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