update for beta release
[framework/uifw/e17.git] / src / bin / e_alert_main.c
1 #include <stdio.h>
2 #include <stdlib.h>
3 #include <stdarg.h>
4 #include <string.h>
5 #include <sys/types.h>
6 #include <unistd.h>
7 #include <signal.h>
8 #include <limits.h>
9 #include <Eina.h>
10 #include <Ecore.h>
11 #include <Ecore_Ipc.h>
12 #include <xcb/xcb.h>
13 #include <xcb/shape.h>
14
15 #define WINDOW_WIDTH 320
16 #define WINDOW_HEIGHT 240
17
18 /* local function prototypes */
19 static int _e_alert_connect(void);
20 static void _e_alert_create(void);
21 static void _e_alert_display(void);
22 static void _e_alert_button_move_resize(xcb_window_t btn, int x, int y, int w, int h);
23 static void _e_alert_window_raise(xcb_window_t win);
24 static void _e_alert_sync(void);
25 static void _e_alert_shutdown(void);
26 static void _e_alert_run(void);
27 static void _e_alert_draw(void);
28 static int _e_alert_handle_key_press(xcb_generic_event_t *event);
29 static int _e_alert_handle_button_press(xcb_generic_event_t *event);
30 static xcb_char2b_t *_e_alert_build_string(const char *str);
31 static void _e_alert_draw_outline(void);
32 static void _e_alert_draw_title_outline(void);
33 static void _e_alert_draw_title(void);
34 static void _e_alert_draw_text(void);
35 static void _e_alert_draw_button_outlines(void);
36 static void _e_alert_draw_button_text(void);
37
38 /* local variables */
39 static xcb_connection_t *conn = NULL;
40 static xcb_screen_t *screen = NULL;
41 static xcb_window_t win = 0, comp_win = 0;
42 static xcb_window_t btn1 = 0;
43 static xcb_window_t btn2 = 0;
44 static xcb_font_t font = 0;
45 static xcb_gcontext_t gc = 0;
46 static int sw = 0, sh = 0;
47 static int fa = 0, fh = 0, fw = 0;
48 static const char *title = NULL, *str1 = NULL, *str2 = NULL;
49 static int ret = 0, sig = 0;
50 static pid_t pid;
51
52 int
53 main(int argc, char **argv)
54 {
55    int i = 0;
56
57    for (i = 1; i < argc; i++)
58      {
59         if ((!strcmp(argv[i], "-h")) ||
60             (!strcmp(argv[i], "-help")) ||
61             (!strcmp(argv[i], "--help")))
62           {
63              printf("This is an internal tool for Enlightenment.\n"
64                     "do not use it.\n");
65              exit(0);
66           }
67         else if ((i == 1))
68           sig = atoi(argv[i]); // signal
69         else if ((i == 2))
70           pid = atoi(argv[i]); // E's pid
71         else if ((i == 3))
72           comp_win = atoi(argv[i]); // Composite Alert Window
73      }
74
75    if (!ecore_init()) return EXIT_FAILURE;
76    ecore_app_args_set(argc, (const char **)argv);
77
78    if (!_e_alert_connect())
79      {
80         printf("FAILED TO INIT ALERT SYSTEM!!!\n");
81         ecore_shutdown();
82         return EXIT_FAILURE;
83      }
84
85    title = "Enlightenment Error";
86    str1 = "(F1) Recover";
87    str2 = "(F2) Exit";
88
89    _e_alert_create();
90    _e_alert_display();
91    _e_alert_run();
92    _e_alert_shutdown();
93
94    ecore_shutdown();
95
96    /* ret == 1 => restart e => exit code 1 */
97    /* ret == 2 => exit e => any code will do that */
98    return ret;
99 }
100
101 /* local functions */
102 static int
103 _e_alert_connect(void)
104 {
105    conn = xcb_connect(NULL, NULL);
106    if ((!conn) || (xcb_connection_has_error(conn)))
107      {
108         printf("E_Alert_Main: Error Trying to Connect!!\n");
109         return 0;
110      }
111
112    /* grab default screen */
113    screen = xcb_setup_roots_iterator(xcb_get_setup(conn)).data;
114    sw = screen->width_in_pixels;
115    sh = screen->height_in_pixels;
116
117    return 1;
118 }
119
120 static void 
121 _e_alert_create(void) 
122 {
123    uint32_t mask, mask_list[4];
124    int wx = 0, wy = 0;
125
126    wx = ((sw - WINDOW_WIDTH) / 2);
127    wy = ((sh - WINDOW_HEIGHT) / 2);
128
129    font = xcb_generate_id(conn);
130    xcb_open_font(conn, font, strlen("fixed"), "fixed");
131
132    /* create main window */
133    mask = (XCB_CW_BACK_PIXEL | XCB_CW_BORDER_PIXEL | 
134            XCB_CW_OVERRIDE_REDIRECT | XCB_CW_EVENT_MASK);
135    mask_list[0] = screen->white_pixel;
136    mask_list[1] = screen->black_pixel;
137    mask_list[2] = 1;
138    mask_list[3] = (XCB_EVENT_MASK_KEY_PRESS | XCB_EVENT_MASK_KEY_RELEASE | 
139                    XCB_EVENT_MASK_EXPOSURE);
140
141    win = xcb_generate_id(conn);
142    xcb_create_window(conn, XCB_COPY_FROM_PARENT, win, screen->root, 
143                      wx, wy, WINDOW_WIDTH, WINDOW_HEIGHT, 0, 
144                      XCB_WINDOW_CLASS_INPUT_OUTPUT, 
145                      XCB_COPY_FROM_PARENT, mask, mask_list);
146
147    /* create button 1 */
148    mask_list[3] = (XCB_EVENT_MASK_BUTTON_PRESS | 
149                    XCB_EVENT_MASK_BUTTON_RELEASE | XCB_EVENT_MASK_EXPOSURE);
150
151    btn1 = xcb_generate_id(conn);
152    xcb_create_window(conn, XCB_COPY_FROM_PARENT, btn1, win, 
153                      -100, -100, 1, 1, 0, 
154                      XCB_WINDOW_CLASS_INPUT_OUTPUT, 
155                      XCB_COPY_FROM_PARENT, mask, mask_list);
156    xcb_map_window(conn, btn1);
157
158    /* create button 2 */
159    btn2 = xcb_generate_id(conn);
160    xcb_create_window(conn, XCB_COPY_FROM_PARENT, btn2, win, 
161                      -100, -100, 1, 1, 0, 
162                      XCB_WINDOW_CLASS_INPUT_OUTPUT, 
163                      XCB_COPY_FROM_PARENT, mask, mask_list);
164    xcb_map_window(conn, btn2);
165
166    /* create drawing gc */
167    mask = (XCB_GC_FOREGROUND | XCB_GC_BACKGROUND | XCB_GC_FONT);
168    mask_list[0] = screen->black_pixel;
169    mask_list[1] = screen->white_pixel;
170    mask_list[2] = font;
171
172    gc = xcb_generate_id(conn);
173    xcb_create_gc(conn, gc, win, mask, mask_list);
174 }
175
176 static void 
177 _e_alert_display(void) 
178 {
179    xcb_char2b_t *str = NULL;
180    xcb_query_text_extents_cookie_t cookie;
181    xcb_query_text_extents_reply_t *reply;
182    int x = 0, w = 0;
183
184    str = _e_alert_build_string(title);
185
186    cookie = 
187      xcb_query_text_extents_unchecked(conn, font, strlen(title), str);
188    reply = xcb_query_text_extents_reply(conn, cookie, NULL);
189    if (reply) 
190      {
191         fa = reply->font_ascent;
192         fh = (fa + reply->font_descent);
193         fw = reply->overall_width;
194         free(reply);
195      }
196    free(str);
197
198    /* move buttons */
199    x = 20;
200    w = (WINDOW_WIDTH / 2) - 40;
201    _e_alert_button_move_resize(btn1, x, WINDOW_HEIGHT - 20 - (fh + 20), 
202                                w, (fh + 20));
203
204    x = ((WINDOW_WIDTH / 2) + 20);
205    _e_alert_button_move_resize(btn2, x, WINDOW_HEIGHT - 20 - (fh + 20), 
206                                w, (fh + 20));
207
208    if (comp_win)
209      {
210         xcb_rectangle_t rect;
211         int wx = 0, wy = 0;
212
213         wx = ((sw - WINDOW_WIDTH) / 2);
214         wy = ((sh - WINDOW_HEIGHT) / 2);
215
216         rect.x = wx;
217         rect.y = wy;
218         rect.width = WINDOW_WIDTH;
219         rect.height = WINDOW_HEIGHT;
220
221         xcb_shape_rectangles(conn, XCB_SHAPE_SO_SET, 
222                              XCB_SHAPE_SK_INPUT, XCB_CLIP_ORDERING_UNSORTED, 
223                              comp_win, 0, 0, 1, &rect);
224
225         xcb_reparent_window(conn, win, comp_win, wx, wy);
226      }
227
228    /* map and raise main window */
229    xcb_map_window(conn, win);
230    _e_alert_window_raise(win);
231
232    /* grab pointer & keyboard */
233    xcb_grab_pointer_unchecked(conn, 0, win, 
234                               (XCB_EVENT_MASK_BUTTON_PRESS | 
235                                   XCB_EVENT_MASK_BUTTON_RELEASE), 
236                               XCB_GRAB_MODE_ASYNC, XCB_GRAB_MODE_ASYNC, 
237                               XCB_NONE, XCB_NONE, XCB_CURRENT_TIME);
238    xcb_grab_keyboard_unchecked(conn, 0, win, XCB_CURRENT_TIME, 
239                                XCB_GRAB_MODE_ASYNC, XCB_GRAB_MODE_ASYNC);
240    xcb_set_input_focus(conn, XCB_INPUT_FOCUS_POINTER_ROOT, 
241                        win, XCB_CURRENT_TIME);
242
243    /* flush screen */
244    xcb_flush(conn);
245
246    /* sync */
247    _e_alert_sync();
248 }
249
250 static void 
251 _e_alert_button_move_resize(xcb_window_t btn, int x, int y, int w, int h) 
252 {
253    uint32_t list[4], mask;
254
255    if (!btn) return;
256
257    mask = (XCB_CONFIG_WINDOW_X | XCB_CONFIG_WINDOW_Y | 
258            XCB_CONFIG_WINDOW_WIDTH | XCB_CONFIG_WINDOW_HEIGHT);
259    list[0] = x;
260    list[1] = y;
261    list[2] = w;
262    list[3] = h;
263
264    xcb_configure_window(conn, btn, mask, (const uint32_t *)&list);
265 }
266
267 static void
268 _e_alert_window_raise(xcb_window_t window)
269 {
270    uint32_t list[] = { XCB_STACK_MODE_ABOVE };
271
272    if (!window) return;
273    xcb_configure_window(conn, window, XCB_CONFIG_WINDOW_STACK_MODE, list);
274 }
275
276 static void 
277 _e_alert_sync(void) 
278 {
279    free(xcb_get_input_focus_reply(conn, 
280                                   xcb_get_input_focus(conn), NULL));
281 }
282
283 static void 
284 _e_alert_shutdown(void) 
285 {
286    if (!xcb_connection_has_error(conn)) 
287      {
288         xcb_close_font(conn, font);
289         xcb_destroy_window(conn, btn1);
290         xcb_destroy_window(conn, btn2);
291         xcb_destroy_window(conn, win);
292         if (comp_win) xcb_destroy_window(conn, comp_win);
293         xcb_free_gc(conn, gc);
294         xcb_disconnect(conn);
295      }
296 }
297
298 static void 
299 _e_alert_run(void) 
300 {
301    xcb_generic_event_t *event = NULL;
302
303    xcb_flush(conn);
304    while ((event = xcb_wait_for_event(conn))) 
305      {
306         switch (event->response_type & ~0x80) 
307           {
308            case XCB_BUTTON_PRESS:
309              ret = _e_alert_handle_button_press(event);
310              break;
311            case XCB_KEY_PRESS: 
312              ret = _e_alert_handle_key_press(event);
313              break;
314            case XCB_EXPOSE: 
315                {
316                   xcb_expose_event_t *ev;
317
318                   ev = (xcb_expose_event_t *)event;
319                   if (ev->window != win) break;
320
321                   _e_alert_draw();
322                   _e_alert_sync();
323
324                   break;
325                }
326            default:
327              break;
328           }
329         free(event);
330         if (ret > 0) return;
331      }
332 }
333
334 static void 
335 _e_alert_draw(void) 
336 {
337    _e_alert_draw_outline();
338    _e_alert_draw_title_outline();
339    _e_alert_draw_title();
340    _e_alert_draw_text();
341    _e_alert_draw_button_outlines();
342    _e_alert_draw_button_text();
343
344    xcb_flush(conn);
345 }
346
347 static int 
348 _e_alert_handle_key_press(xcb_generic_event_t *event) 
349 {
350    xcb_key_press_event_t *ev;
351
352    ev = (xcb_key_press_event_t *)event;
353    if (ev->detail == 67) // F1
354      return 1;
355    else if (ev->detail == 68) // F2
356      return 2;
357    else
358      return 0;
359 }
360
361 static int 
362 _e_alert_handle_button_press(xcb_generic_event_t *event) 
363 {
364    xcb_button_press_event_t *ev;
365
366    ev = (xcb_button_press_event_t *)event;
367    if (ev->child == btn1) 
368      return 1;
369    else if (ev->child == btn2)
370      return 2;
371    else
372      return 0;
373 }
374
375 static xcb_char2b_t *
376 _e_alert_build_string(const char *str)
377 {
378    unsigned int i = 0;
379    xcb_char2b_t *r = NULL;
380
381    if (!(r = malloc(strlen(str) * sizeof(xcb_char2b_t))))
382      return NULL;
383
384    for (i = 0; i < strlen(str); i++)
385      {
386         r[i].byte1 = 0;
387         r[i].byte2 = str[i];
388      }
389
390    return r;
391 }
392
393 static void 
394 _e_alert_draw_outline(void) 
395 {
396    xcb_rectangle_t rect;
397
398    /* draw outline */
399    rect.x = 0;
400    rect.y = 0;
401    rect.width = (WINDOW_WIDTH - 1);
402    rect.height = (WINDOW_HEIGHT - 1);
403    xcb_poly_rectangle(conn, win, gc, 1, &rect);
404 }
405
406 static void 
407 _e_alert_draw_title_outline(void) 
408 {
409    xcb_rectangle_t rect;
410
411    /* draw title box */
412    rect.x = 2;
413    rect.y = 2;
414    rect.width = (WINDOW_WIDTH - 4 - 1);
415    rect.height = (fh + 4 + 2);
416    xcb_poly_rectangle(conn, win, gc, 1, &rect);
417 }
418
419 static void 
420 _e_alert_draw_title(void) 
421 {
422    xcb_void_cookie_t cookie;
423    int x = 0, y = 0;
424
425    /* draw title */
426    x = (2 + 2 + ((WINDOW_WIDTH - 4 - 4 - fw) / 2));
427    y = (2 + 2 + fh);
428
429    cookie = 
430      xcb_image_text_8(conn, strlen(title), win, gc, x, y, title);
431 }
432
433 struct {
434   int signal;
435   const char *name;
436 } signal_name[5] = {
437   { SIGSEGV, "SEGV" },
438   { SIGILL, "SIGILL" },
439   { SIGFPE, "SIGFPE" },
440   { SIGBUS, "SIGBUS" },
441   { SIGABRT, "SIGABRT" }
442 };
443
444 static void
445 _e_alert_draw_text(void)
446 {
447    xcb_void_cookie_t cookie;
448    char warn[1024], msg[PATH_MAX], line[1024];
449    unsigned int i = 0, j = 0, k = 0;
450
451    snprintf(msg, sizeof(msg),
452             "This is not meant to happen and is likely a sign of \n"
453             "a bug in Enlightenment or the libraries it relies \n"
454             "on. You can gdb attach to this process (%d) now \n"
455             "to try debug it or you could exit, or just hit \n"
456             "restart to try and get your desktop back the way \n"
457             "it was.\n"
458             "\n"
459             "Please compile everything with -g in your CFLAGS.", pid);
460
461    strcpy(warn, "");
462
463    for (i = 0; i < sizeof(signal_name) / sizeof(signal_name[0]); ++i)
464      if (signal_name[i].signal == sig)
465        snprintf(warn, sizeof(warn),
466                 "This is very bad. Enlightenment %s'd.",
467                 signal_name[i].name);
468
469    /* draw text */
470    k = (fh + 12);
471    cookie =
472      xcb_image_text_8(conn, strlen(warn), win, gc,
473                       4, (k + fa), warn);
474    k += (2 * (fh + 2));
475    while (msg[i])
476      {
477         line[j++] = msg[i++];
478         if (line[j - 1] == '\n')
479           {
480              line[j - 1] = 0;
481              j = 0;
482              cookie =
483                xcb_image_text_8(conn, strlen(line), win, gc,
484                                 4, (k + fa), line);
485              k += (fh + 2);
486           }
487      }
488 }
489
490 static void
491 _e_alert_draw_button_outlines(void)
492 {
493    xcb_rectangle_t rect;
494
495    rect.x = 0;
496    rect.y = 0;
497    rect.width = (WINDOW_WIDTH / 2) - 40 - 1;
498    rect.height = (fh + 20) - 1;
499
500    /* draw button outlines */
501    xcb_poly_rectangle(conn, btn1, gc, 1, &rect);
502    xcb_poly_rectangle(conn, btn2, gc, 1, &rect);
503 }
504
505 static void
506 _e_alert_draw_button_text(void)
507 {
508    xcb_void_cookie_t dcookie;
509    xcb_char2b_t *str = NULL;
510    xcb_query_text_extents_cookie_t cookie;
511    xcb_query_text_extents_reply_t *reply;
512    int x = 0, w = 0, bw = 0;
513
514    bw = (WINDOW_WIDTH / 2) - 40 - 1;
515
516    /* draw button1 text */
517    str = _e_alert_build_string(str1);
518
519    cookie =
520      xcb_query_text_extents_unchecked(conn, font, strlen(str1), str);
521    reply = xcb_query_text_extents_reply(conn, cookie, NULL);
522    if (reply)
523      {
524         w = reply->overall_width;
525         free(reply);
526      }
527    free(str);
528
529    x = (5 + ((bw - w) / 2));
530
531    dcookie =
532      xcb_image_text_8(conn, strlen(str1), btn1, gc, x, (10 + fa), str1);
533
534    /* draw button2 text */
535    str = _e_alert_build_string(str2);
536
537    cookie =
538      xcb_query_text_extents_unchecked(conn, font, strlen(str2), str);
539    reply = xcb_query_text_extents_reply(conn, cookie, NULL);
540    if (reply)
541      {
542         w = reply->overall_width;
543         free(reply);
544      }
545    free(str);
546
547    x = (5 + ((bw - w) / 2));
548
549    dcookie =
550      xcb_image_text_8(conn, strlen(str2), btn2, gc, x, (10 + fa), str2);
551 }