1 /*
2  * This file is part of YAD.
3  *
4  * YAD is free software; you can redistribute it and/or modify
5  * it under the terms of the GNU General Public License as published by
6  * the Free Software Foundation; either version 3 of the License, or
7  * (at your option) any later version.
8  *
9  * YAD is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12  * GNU General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License
15  * along with YAD. If not, see <http://www.gnu.org/licenses/>.
16  *
17  * Copyright (C) 2008-2019, Victor Ananjevsky <ananasik@gmail.com>
18  */
19 
20 #include <sys/types.h>
21 #include <sys/stat.h>
22 #include <fcntl.h>
23 #include <locale.h>
24 #include <stdlib.h>
25 #include <signal.h>
26 #include <stdio.h>
27 #include <unistd.h>
28 
29 #ifndef G_OS_WIN32
30 # include <sys/shm.h>
31 # include <gdk/gdkx.h>
32 #endif
33 
34 #include "yad.h"
35 
36 YadOptions options;
37 GtkIconTheme *yad_icon_theme;
38 
39 #ifndef STANDALONE
40 GSettings *settings;
41 #endif
42 
43 GdkPixbuf *big_fallback_image = NULL;
44 GdkPixbuf *small_fallback_image = NULL;
45 
46 static GtkWidget *dialog = NULL;
47 static GtkWidget *text = NULL;
48 
49 static gint ret = YAD_RESPONSE_ESC;
50 
51 static gboolean is_x11 = FALSE;
52 
53 YadNTabs *tabs;
54 
55 #ifndef G_OS_WIN32
56 static void
sa_usr1(gint sig)57 sa_usr1 (gint sig)
58 {
59   if (options.plug != -1)
60     yad_print_result ();
61   else
62     yad_exit (options.data.def_resp);
63 }
64 
65 static void
sa_usr2(gint sig)66 sa_usr2 (gint sig)
67 {
68   if (options.plug != -1)
69     gtk_main_quit ();
70   else
71     yad_exit (YAD_RESPONSE_CANCEL);
72 }
73 #endif
74 
75 static gboolean
keys_cb(GtkWidget * w,GdkEventKey * ev,gpointer d)76 keys_cb (GtkWidget *w, GdkEventKey *ev, gpointer d)
77 {
78   if (options.plug != -1)
79     return FALSE;
80 
81   switch (ev->keyval)
82     {
83     case GDK_KEY_Escape:
84       if (options.data.escape_ok)
85           yad_exit (options.data.def_resp);
86       else if (!options.data.no_escape)
87          yad_exit (YAD_RESPONSE_ESC);
88       return TRUE;
89     case GDK_KEY_Return:
90     case GDK_KEY_KP_Enter:
91       if (ev->state & GDK_CONTROL_MASK)
92         {
93           yad_exit (options.data.def_resp);
94           return TRUE;
95         }
96      }
97    return FALSE;
98 }
99 
100 static void
btn_cb(GtkWidget * b,gchar * cmd)101 btn_cb (GtkWidget *b, gchar *cmd)
102 {
103   if (cmd)
104     run_command_async (cmd);
105   else
106     {
107       gint resp = GPOINTER_TO_INT (g_object_get_data (G_OBJECT (b), "resp"));
108       yad_exit (resp);
109     }
110 }
111 
112 static gboolean
timeout_cb(gpointer data)113 timeout_cb (gpointer data)
114 {
115   static guint count = 1;
116   GtkWidget *w = (GtkWidget *) data;
117 
118   if (options.data.timeout < count)
119     {
120       yad_exit (YAD_RESPONSE_TIMEOUT);
121       return FALSE;
122     }
123 
124   if (w)
125     {
126       gdouble percent = ((gdouble) options.data.timeout - count) / (gdouble) options.data.timeout;
127       gtk_progress_bar_set_fraction (GTK_PROGRESS_BAR (w), percent);
128 #ifndef STANDALONE
129       if (g_settings_get_boolean (settings, "show-remain"))
130 #else
131       if (SHOW_REMAIN)
132 #endif
133         {
134           gchar *lbl = g_strdup_printf (_("%d sec"), options.data.timeout - count);
135           gtk_progress_bar_set_text (GTK_PROGRESS_BAR (w), lbl);
136           g_free (lbl);
137         }
138     }
139 
140   count++;
141 
142   return TRUE;
143 }
144 
145 static gboolean
unfocus_cb(GtkWidget * w,GdkEventFocus * ev,gpointer d)146 unfocus_cb (GtkWidget *w, GdkEventFocus *ev, gpointer d)
147 {
148   if (options.data.close_on_unfocus)
149     gtk_main_quit ();
150   return FALSE;
151 }
152 
153 void
yad_exit(gint id)154 yad_exit (gint id)
155 {
156   if ((options.mode == YAD_MODE_FILE) && !(id & 1))
157     {
158       /* show custom confirmation dialog */
159       if (!file_confirm_overwrite (dialog))
160         return;
161     }
162 
163   ret = id;
164   gtk_main_quit ();
165 }
166 
167 static GtkWidget *
create_layout(GtkWidget * dlg)168 create_layout (GtkWidget *dlg)
169 {
170   GtkWidget *image, *mw, *imw, *layout, *exp, *box;
171 
172   layout = image = mw = exp = NULL;
173 
174   /* create image */
175   if (options.data.dialog_image)
176     {
177       GdkPixbuf *pb = NULL;
178 
179       pb = get_pixbuf (options.data.dialog_image, YAD_BIG_ICON, FALSE);
180       image = gtk_image_new_from_pixbuf (pb);
181       if (pb)
182         g_object_unref (pb);
183 
184       gtk_widget_set_name (image, "yad-dialog-image");
185       gtk_widget_set_halign (image, GTK_ALIGN_CENTER);
186       gtk_widget_set_valign (image, GTK_ALIGN_START);
187     }
188 
189   /* create text label */
190   if (options.data.dialog_text)
191     {
192       /* for dnd's tooltip we don't need text label */
193       if (options.mode != YAD_MODE_DND || !options.dnd_data.tooltip)
194         {
195           gchar *buf = g_strcompress (options.data.dialog_text);
196 
197           text = gtk_label_new (NULL);
198           if (!options.data.no_markup)
199             gtk_label_set_markup (GTK_LABEL (text), buf);
200           else
201             gtk_label_set_text (GTK_LABEL (text), buf);
202           g_free (buf);
203 
204           gtk_widget_set_name (text, "yad-dialog-label");
205           gtk_label_set_line_wrap (GTK_LABEL (text), TRUE);
206           gtk_label_set_selectable (GTK_LABEL (text), options.data.selectable_labels);
207           gtk_label_set_justify (GTK_LABEL (text), options.data.text_align);
208           gtk_widget_set_state_flags (text, GTK_STATE_NORMAL, FALSE);
209           gtk_label_set_xalign (GTK_LABEL (text), options.data.text_align);
210           gtk_widget_set_can_focus (text, FALSE);
211         }
212     }
213 
214   /* create main widget */
215   switch (options.mode)
216     {
217     case YAD_MODE_APP:
218       mw = app_create_widget (dlg);
219       break;
220     case YAD_MODE_CALENDAR:
221       mw = calendar_create_widget (dlg);
222       break;
223     case YAD_MODE_COLOR:
224       mw = color_create_widget (dlg);
225       break;
226     case YAD_MODE_ENTRY:
227       mw = entry_create_widget (dlg);
228       break;
229     case YAD_MODE_FILE:
230       mw = file_create_widget (dlg);
231       break;
232     case YAD_MODE_FONT:
233       mw = font_create_widget (dlg);
234       break;
235     case YAD_MODE_FORM:
236       mw = form_create_widget (dlg);
237       break;
238 #ifdef HAVE_HTML
239     case YAD_MODE_HTML:
240       mw = html_create_widget (dlg);
241       break;
242 #endif
243     case YAD_MODE_ICONS:
244       mw = icons_create_widget (dlg);
245       break;
246     case YAD_MODE_LIST:
247       mw = list_create_widget (dlg);
248       break;
249     case YAD_MODE_NOTEBOOK:
250       if (options.plug == -1)
251         mw = notebook_create_widget (dlg);
252       break;
253     case YAD_MODE_PANED:
254       if (options.plug == -1)
255         mw = paned_create_widget (dlg);
256       break;
257     case YAD_MODE_PICTURE:
258       mw = picture_create_widget (dlg);
259       break;
260     case YAD_MODE_PROGRESS:
261       mw = progress_create_widget (dlg);
262       break;
263     case YAD_MODE_SCALE:
264       mw = scale_create_widget (dlg);
265       break;
266     case YAD_MODE_TEXTINFO:
267       mw = text_create_widget (dlg);
268       break;
269     default: ;
270     }
271 
272   /* add expander */
273   imw = NULL;
274   if (mw && options.data.expander)
275     {
276       exp = gtk_expander_new_with_mnemonic (options.data.expander);
277       gtk_expander_set_expanded (GTK_EXPANDER (exp), FALSE);
278       if (mw)
279         {
280           gtk_container_add (GTK_CONTAINER (exp), mw);
281           imw = exp;
282         }
283     }
284   else
285     imw = mw;
286 
287   /* create layout */
288   layout = gtk_box_new (GTK_ORIENTATION_VERTICAL, 5);
289   box = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 5);
290 
291   if (image)
292     gtk_box_pack_start (GTK_BOX (box), image, FALSE, FALSE, 2);
293   if (text)
294     gtk_box_pack_start (GTK_BOX (box), text, TRUE, TRUE, 2);
295 
296   gtk_box_pack_start (GTK_BOX (layout), box, FALSE, FALSE, 0);
297   if (imw)
298     gtk_box_pack_start (GTK_BOX (layout), imw, TRUE, TRUE, 0);
299 
300   if (options.mode == YAD_MODE_DND)
301     dnd_init (layout);
302 
303   return layout;
304 }
305 
306 static void
realize_cb(GtkWidget * dlg,gpointer d)307 realize_cb (GtkWidget *dlg, gpointer d)
308 {
309   gint cw, ch;
310   /* get current window size for gtk_window_resize */
311   gtk_window_get_size (GTK_WINDOW (dlg), &cw, &ch);
312   if (options.data.width == -1)
313     options.data.width = cw;
314   if (options.data.height == -1)
315     options.data.height = ch;
316 
317   gtk_window_resize (GTK_WINDOW (dlg), options.data.width, options.data.height);
318   gtk_window_set_resizable (GTK_WINDOW (dlg), !options.data.fixed);
319 
320   if (options.data.use_posx || options.data.use_posy)
321     {
322       gint ww, wh, sw, sh;
323       gtk_window_get_size (GTK_WINDOW (dlg), &ww, &wh);
324       gdk_window_get_geometry (gdk_get_default_root_window (), NULL, NULL, &sw, &sh);
325       /* place window to specified coordinates */
326       if (!options.data.use_posx)
327         gtk_window_get_position (GTK_WINDOW (dlg), &options.data.posx, NULL);
328       if (!options.data.use_posy)
329         gtk_window_get_position (GTK_WINDOW (dlg), NULL, &options.data.posy);
330       if (options.data.posx < 0)
331         options.data.posx = sw - ww + options.data.posx;
332       if (options.data.posy < 0)
333         options.data.posy = sh - wh + options.data.posy;
334       gtk_window_move (GTK_WINDOW (dlg), options.data.posx, options.data.posy);
335     }
336 }
337 
338 static GtkWidget *
create_dialog(void)339 create_dialog (void)
340 {
341   GtkWidget *dlg, *vbox, *layout;
342 
343   /* create dialog window */
344   dlg = gtk_window_new (GTK_WINDOW_TOPLEVEL);
345   if (options.data.splash)
346     gtk_window_set_type_hint (GTK_WINDOW (dlg), GDK_WINDOW_TYPE_HINT_SPLASHSCREEN);
347   gtk_window_set_title (GTK_WINDOW (dlg), options.data.dialog_title);
348   gtk_widget_set_name (dlg, "yad-dialog-window");
349 
350   g_signal_connect (G_OBJECT (dlg), "delete-event", G_CALLBACK (gtk_main_quit), NULL);
351   g_signal_connect (G_OBJECT (dlg), "key-press-event", G_CALLBACK (keys_cb), NULL);
352   g_signal_connect (G_OBJECT (dlg), "focus-out-event", G_CALLBACK (unfocus_cb), NULL);
353 
354   /* set window icon */
355   if (options.data.window_icon)
356     {
357       if (g_file_test (options.data.window_icon, G_FILE_TEST_EXISTS))
358         gtk_window_set_icon_from_file (GTK_WINDOW (dlg), options.data.window_icon, NULL);
359       else
360         gtk_window_set_icon_name (GTK_WINDOW (dlg), options.data.window_icon);
361     }
362 
363   /* set window borders */
364   if (options.data.borders < 0)
365     options.data.borders = 2;
366   gtk_container_set_border_width (GTK_CONTAINER (dlg), (guint) options.data.borders);
367 
368   /* set window size and position */
369   if (!options.data.maximized && !options.data.fullscreen)
370     {
371       if (options.data.center)
372         gtk_window_set_position (GTK_WINDOW (dlg), GTK_WIN_POS_CENTER_ALWAYS);
373       else if (options.data.mouse)
374         gtk_window_set_position (GTK_WINDOW (dlg), GTK_WIN_POS_MOUSE);
375     }
376 
377   /* set window behavior */
378   if (options.data.sticky)
379     gtk_window_stick (GTK_WINDOW (dlg));
380   gtk_window_set_keep_above (GTK_WINDOW (dlg), options.data.ontop);
381   gtk_window_set_decorated (GTK_WINDOW (dlg), !options.data.undecorated);
382   gtk_window_set_skip_taskbar_hint (GTK_WINDOW (dlg), options.data.skip_taskbar);
383   gtk_window_set_skip_pager_hint (GTK_WINDOW (dlg), options.data.skip_taskbar);
384   gtk_window_set_accept_focus (GTK_WINDOW (dlg), options.data.focus);
385 
386   /* create box */
387   vbox = gtk_box_new (GTK_ORIENTATION_VERTICAL, 2);
388   gtk_container_add (GTK_CONTAINER (dlg), vbox);
389 
390   layout = create_layout (dlg);
391 
392   /* create timeout indicator widget */
393   if (options.data.timeout)
394     {
395       GtkWidget *cbox = NULL, *topb = NULL;
396 
397       if (G_LIKELY (options.data.to_indicator) && strcasecmp (options.data.to_indicator, "none") != 0)
398         {
399           topb = gtk_progress_bar_new ();
400           gtk_progress_bar_set_fraction (GTK_PROGRESS_BAR (topb), 1.0);
401           gtk_widget_set_name (topb, "yad-timeout-indicator");
402         }
403 
404       /* add timeout indicator */
405       if (topb)
406         {
407           if (strcasecmp (options.data.to_indicator, "top") == 0)
408             {
409               gtk_orientable_set_orientation (GTK_ORIENTABLE (topb), GTK_ORIENTATION_HORIZONTAL);
410               cbox = gtk_box_new (GTK_ORIENTATION_VERTICAL, 0);
411               gtk_box_pack_start (GTK_BOX (cbox), topb, FALSE, FALSE, 2);
412               gtk_box_pack_end (GTK_BOX (cbox), layout, TRUE, TRUE, 0);
413             }
414           else if (strcasecmp (options.data.to_indicator, "bottom") == 0)
415             {
416               gtk_orientable_set_orientation (GTK_ORIENTABLE (topb), GTK_ORIENTATION_HORIZONTAL);
417               cbox = gtk_box_new (GTK_ORIENTATION_VERTICAL, 0);
418               gtk_box_pack_start (GTK_BOX (cbox), layout, TRUE, TRUE, 0);
419               gtk_box_pack_end (GTK_BOX (cbox), topb, FALSE, FALSE, 2);
420             }
421           else if (strcasecmp (options.data.to_indicator, "left") == 0)
422             {
423               gtk_orientable_set_orientation (GTK_ORIENTABLE (topb), GTK_ORIENTATION_VERTICAL);
424               gtk_progress_bar_set_inverted (GTK_PROGRESS_BAR (topb), TRUE);
425               cbox = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 0);
426               gtk_box_pack_start (GTK_BOX (cbox), topb, FALSE, FALSE, 2);
427               gtk_box_pack_end (GTK_BOX (cbox), layout, TRUE, TRUE, 0);
428             }
429           else if (strcasecmp (options.data.to_indicator, "right") == 0)
430             {
431               gtk_orientable_set_orientation (GTK_ORIENTABLE (topb), GTK_ORIENTATION_VERTICAL);
432               gtk_progress_bar_set_inverted (GTK_PROGRESS_BAR (topb), TRUE);
433               cbox = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 0);
434               gtk_box_pack_start (GTK_BOX (cbox), layout, TRUE, TRUE, 0);
435               gtk_box_pack_end (GTK_BOX (cbox), topb, FALSE, FALSE, 2);
436             }
437 
438 #ifndef STANDALONE
439           if (g_settings_get_boolean (settings, "show-remain"))
440 #else
441           if (SHOW_REMAIN)
442 #endif
443             {
444               gchar *lbl = g_strdup_printf (_("%d sec"), options.data.timeout);
445               gtk_progress_bar_set_show_text (GTK_PROGRESS_BAR (topb), TRUE);
446               gtk_progress_bar_set_text (GTK_PROGRESS_BAR (topb), lbl);
447               g_free (lbl);
448             }
449         }
450       else
451         {
452           cbox = gtk_box_new (GTK_ORIENTATION_VERTICAL, 0);
453           gtk_box_pack_start (GTK_BOX (cbox), layout, TRUE, TRUE, 0);
454         }
455 
456       if (cbox)
457         gtk_box_pack_start (GTK_BOX (vbox), cbox, TRUE, TRUE, 0);
458 
459       /* set timeout handler */
460       g_timeout_add_seconds (1, timeout_cb, topb);
461     }
462   else
463     gtk_box_pack_start (GTK_BOX (vbox), layout, TRUE, TRUE, 0);
464 
465 #ifdef HAVE_HTML
466   /* enable no-buttons mode if --browser is specified and sets no custom buttons */
467   if (options.mode == YAD_MODE_HTML && options.html_data.browser && !options.data.buttons)
468     options.data.no_buttons = TRUE;
469 #endif
470 
471   if (!options.data.no_buttons)
472     {
473       GtkWidget *btn;
474       /* create buttons container */
475       GtkWidget *bbox = gtk_button_box_new (GTK_ORIENTATION_HORIZONTAL);
476       gtk_box_set_homogeneous (GTK_BOX (bbox), TRUE);
477       gtk_container_set_border_width (GTK_CONTAINER (bbox), 2);
478       gtk_box_set_spacing (GTK_BOX (bbox), 5);
479       gtk_button_box_set_layout (GTK_BUTTON_BOX (bbox), options.data.buttons_layout);
480 
481       /* add buttons */
482       if (options.data.buttons)
483         {
484           GSList *tmp = options.data.buttons;
485           do
486             {
487               YadButton *b = (YadButton *) tmp->data;
488 
489               btn = gtk_button_new ();
490               gtk_container_add (GTK_CONTAINER (btn), get_label (b->name, 2, btn));
491               g_object_set_data (G_OBJECT (btn), "resp", GINT_TO_POINTER (b->response));
492               g_signal_connect (G_OBJECT (btn), "clicked", G_CALLBACK (btn_cb), b->cmd);
493               gtk_box_pack_start (GTK_BOX (bbox), btn, TRUE, TRUE, 0);
494 
495               tmp = tmp->next;
496             }
497           while (tmp != NULL);
498         }
499       else
500         {
501           if (options.mode == YAD_MODE_PROGRESS || options.mode == YAD_MODE_DND || options.mode == YAD_MODE_PICTURE)
502             {
503               /* add close button */
504               btn = gtk_button_new ();
505               gtk_container_add (GTK_CONTAINER (btn), get_label ("yad-close", 2, btn));
506               g_object_set_data (G_OBJECT (btn), "resp", GINT_TO_POINTER (YAD_RESPONSE_OK));
507               g_signal_connect (G_OBJECT (btn), "clicked", G_CALLBACK (btn_cb), NULL);
508               gtk_box_pack_start (GTK_BOX (bbox), btn, TRUE, TRUE, 0);
509 
510             }
511           else
512             {
513               /* add cancel button */
514               btn = gtk_button_new ();
515               gtk_container_add (GTK_CONTAINER (btn), get_label ("yad-cancel", 2, btn));
516               g_object_set_data (G_OBJECT (btn), "resp", GINT_TO_POINTER (YAD_RESPONSE_CANCEL));
517               g_signal_connect (G_OBJECT (btn), "clicked", G_CALLBACK (btn_cb), NULL);
518               gtk_box_pack_start (GTK_BOX (bbox), btn, TRUE, TRUE, 0);
519 
520               /*add ok button */
521               btn = gtk_button_new ();
522               gtk_container_add (GTK_CONTAINER (btn), get_label ("yad-ok", 2, btn));
523               g_object_set_data (G_OBJECT (btn), "resp", GINT_TO_POINTER (YAD_RESPONSE_OK));
524               g_signal_connect (G_OBJECT (btn), "clicked", G_CALLBACK (btn_cb), NULL);
525               gtk_box_pack_start (GTK_BOX (bbox), btn, TRUE, TRUE, 0);
526             }
527         }
528       /* add buttons box to main window */
529       gtk_box_pack_start (GTK_BOX (vbox), bbox, FALSE, FALSE, 0);
530     }
531 
532   /* show widgets */
533   gtk_widget_show_all (vbox);
534 
535   /* parse geometry or move window, if given. must be after showing widget */
536   if (!options.data.maximized && !options.data.fullscreen)
537     {
538       parse_geometry ();
539       g_signal_connect (G_OBJECT (dlg), "realize", G_CALLBACK (realize_cb), NULL);
540       gtk_widget_show_all (dlg);
541     }
542   else
543     {
544       gtk_widget_show (dlg);
545       /* set maximized or fixed size after showing widget */
546       if (options.data.maximized)
547         gtk_window_maximize (GTK_WINDOW (dlg));
548       else if (options.data.fullscreen)
549         gtk_window_fullscreen (GTK_WINDOW (dlg));
550     }
551 
552   /* print xid */
553   if (is_x11 && options.print_xid)
554     {
555       FILE *xf;
556 
557       if (options.xid_file)
558         xf = fopen (options.xid_file, "w");
559       else
560         xf = stderr;
561 
562       if (xf)
563         {
564           fprintf (xf, "0x%lX\n", GDK_WINDOW_XID (gtk_widget_get_window (dlg)));
565 
566           if (options.xid_file)
567             fclose (xf);
568           else
569             fflush (xf);
570         }
571     }
572 
573   return dlg;
574 }
575 
576 static void
create_plug(void)577 create_plug (void)
578 {
579   GtkWidget *win, *box;
580 
581   tabs = get_tabs (options.plug, FALSE);
582   while (!tabs)
583     {
584       usleep (1000);
585       tabs = get_tabs (options.plug, FALSE);
586     }
587 
588   while (!tabs[0].xid)
589     usleep (1000);
590 
591   win = gtk_plug_new (0);
592   /* set window borders */
593   if (options.data.borders == -1)
594     options.data.borders = (gint) gtk_container_get_border_width (GTK_CONTAINER (win));
595   gtk_container_set_border_width (GTK_CONTAINER (win), (guint) options.data.borders);
596 
597   box = create_layout (win);
598   if (box)
599     gtk_container_add (GTK_CONTAINER (win), box);
600 
601   gtk_widget_show_all (win);
602 
603   /* add plug data */
604   /* notebook/paned will count non-zero xids */
605   tabs[options.tabnum].pid = getpid ();
606   tabs[options.tabnum].xid = gtk_plug_get_id (GTK_PLUG (win));
607   shmdt (tabs);
608 }
609 
610 void
yad_print_result(void)611 yad_print_result (void)
612 {
613   switch (options.mode)
614     {
615     case YAD_MODE_APP:
616       app_print_result ();
617       break;
618     case YAD_MODE_CALENDAR:
619       calendar_print_result ();
620       break;
621     case YAD_MODE_COLOR:
622       color_print_result ();
623       break;
624     case YAD_MODE_ENTRY:
625       entry_print_result ();
626       break;
627     case YAD_MODE_FILE:
628       file_print_result ();
629       break;
630     case YAD_MODE_FONT:
631       font_print_result ();
632       break;
633     case YAD_MODE_FORM:
634       form_print_result ();
635       break;
636     case YAD_MODE_LIST:
637       list_print_result ();
638       break;
639     case YAD_MODE_NOTEBOOK:
640       notebook_print_result ();
641       break;
642     case YAD_MODE_PANED:
643       paned_print_result ();
644       break;
645     case YAD_MODE_SCALE:
646       scale_print_result ();
647       break;
648     case YAD_MODE_TEXTINFO:
649       text_print_result ();
650       break;
651     default:;
652     }
653 }
654 
655 gint
main(gint argc,gchar ** argv)656 main (gint argc, gchar ** argv)
657 {
658   GOptionContext *ctx;
659   GError *err = NULL;
660   gint w, h;
661   gchar *str;
662 
663   setlocale (LC_ALL, "");
664 
665 #ifdef ENABLE_NLS
666   bindtextdomain (GETTEXT_PACKAGE, LOCALEDIR);
667   bind_textdomain_codeset (GETTEXT_PACKAGE, "UTF-8");
668   textdomain (GETTEXT_PACKAGE);
669 #endif
670 
671   gtk_init (&argc, &argv);
672   g_set_application_name ("YAD");
673 
674 #ifndef STANDALONE
675   settings = g_settings_new ("yad.settings");
676 #endif
677 
678   yad_icon_theme = gtk_icon_theme_get_default ();
679 
680   yad_options_init ();
681 
682   ctx = yad_create_context ();
683   /* parse YAD_OPTIONS */
684   if (g_getenv ("YAD_OPTIONS"))
685     {
686       gchar *cmd, **args = NULL;
687       gint cnt;
688 
689       cmd = g_strdup_printf ("yad %s", g_getenv ("YAD_OPTIONS"));
690 
691       if (g_shell_parse_argv (cmd, &cnt, &args, &err))
692         {
693           g_option_context_parse (ctx, &cnt, &args, &err);
694           if (err)
695             {
696               g_printerr (_("Unable to parse YAD_OPTIONS: %s\n"), err->message);
697               g_error_free (err);
698               err = NULL;
699             }
700         }
701       else
702         {
703           g_printerr (_("Unable to parse YAD_OPTIONS: %s\n"), err->message);
704           g_error_free (err);
705           err = NULL;
706         }
707 
708       g_free (cmd);
709     }
710   /* parse command line */
711   g_option_context_parse (ctx, &argc, &argv, &err);
712   if (err)
713     {
714       g_printerr (_("Unable to parse command line: %s\n"), err->message);
715       return -1;
716     }
717   yad_set_mode ();
718 
719   /* check for current GDK backend */
720 #ifdef GDK_WINDOWING_X11
721   if (GDK_IS_X11_DISPLAY (gdk_display_get_default ()))
722     is_x11 = TRUE;
723 #endif
724 
725   /* parse custom gtkrc */
726   if (options.gtkrc_file)
727     {
728       GtkCssProvider *css = gtk_css_provider_new ();
729       gtk_css_provider_load_from_path (css, options.gtkrc_file, NULL);
730       gtk_style_context_add_provider_for_screen (gdk_screen_get_default (), GTK_STYLE_PROVIDER (css),
731                                                  GTK_STYLE_PROVIDER_PRIORITY_USER);
732       g_object_unref (css);
733     }
734 
735   /* set default icons and icon theme */
736   if (options.data.icon_theme)
737     gtk_icon_theme_set_custom_theme (yad_icon_theme, options.data.icon_theme);
738   gtk_icon_size_lookup (GTK_ICON_SIZE_DIALOG, &w, &h);
739   big_fallback_image = gtk_icon_theme_load_icon (yad_icon_theme, "yad", MIN (w, h), GTK_ICON_LOOKUP_GENERIC_FALLBACK, NULL);
740   gtk_icon_size_lookup (GTK_ICON_SIZE_MENU, &w, &h);
741   small_fallback_image = gtk_icon_theme_load_icon (yad_icon_theme, "yad", MIN (w, h), GTK_ICON_LOOKUP_GENERIC_FALLBACK, NULL);
742 
743   /* correct separators */
744   str = g_strcompress (options.common_data.separator);
745   options.common_data.separator = str;
746   str = g_strcompress (options.common_data.item_separator);
747   options.common_data.item_separator = str;
748 
749   /* loads an extra arguments, if specified */
750   if (options.rest_file)
751     {
752       GIOChannel *ioc;
753       gchar *buf;
754       guint len, line = 0;
755 
756       g_strfreev (options.extra_data);
757       options.extra_data = NULL;
758 
759       ioc = g_io_channel_new_file (options.rest_file, "r", NULL);
760       while (TRUE)
761         {
762           gint status = g_io_channel_read_line (ioc, &buf, NULL, NULL, NULL);
763 
764           if (status != G_IO_STATUS_NORMAL)
765             break;
766 
767           /* remove \n at the end of string */
768           len = strlen (buf);
769           if (buf[len - 1] == '\n')
770             buf[len - 1] = '\0';
771 
772           /* add line to arguments array */
773           options.extra_data = g_realloc (options.extra_data, (line + 2) * sizeof (gchar *));
774           options.extra_data[line] = g_strcompress (buf);
775           options.extra_data[line + 1] = NULL;
776 
777           g_free (buf);
778           line++;
779         }
780       g_io_channel_shutdown (ioc, FALSE, NULL);
781     }
782 
783 #ifndef G_OS_WIN32
784   /* add YAD_PID variable */
785   str = g_strdup_printf ("%d", getpid ());
786   g_setenv ("YAD_PID", str, TRUE);
787   /* set signal handlers */
788   signal (SIGUSR1, sa_usr1);
789   signal (SIGUSR2, sa_usr2);
790 #endif
791 
792   if (!is_x11 && options.plug != -1)
793     {
794       options.plug = -1;
795       if (options.debug)
796         g_printerr (_("WARNING: --plug mode not supported outside X11\n"));
797     }
798 
799   /* plug mode */
800   if (options.plug != -1)
801     {
802       create_plug ();
803       gtk_main ();
804       shmdt (tabs);
805       return ret;
806     }
807 
808   if (!is_x11)
809     {
810       if (options.mode == YAD_MODE_NOTEBOOK || options.mode == YAD_MODE_PANED
811 #ifdef HAVE_TRAY
812           || options.mode == YAD_MODE_NOTIFICATION
813 #endif
814          )
815         {
816           g_printerr (_("WARNING: This mode not supported outside X11\n"));
817           return 1;
818         }
819     }
820 
821   switch (options.mode)
822     {
823     case YAD_MODE_ABOUT:
824       ret = yad_about ();
825       break;
826 
827     case YAD_MODE_VERSION:
828       g_print ("%s (GTK+ %d.%d.%d)\n", VERSION, gtk_major_version, gtk_minor_version, gtk_micro_version);
829       break;
830 
831 #ifdef HAVE_SPELL
832     case YAD_MODE_LANGS:
833       show_langs ();
834       break;
835 #endif
836 
837 #ifdef HAVE_SOURCEVIEW
838     case YAD_MODE_THEMES:
839       show_themes ();
840       break;
841 #endif
842 
843 #ifdef HAVE_TRAY
844     case YAD_MODE_NOTIFICATION:
845       ret = yad_notification_run ();
846       break;
847 #endif
848 
849     case YAD_MODE_PRINT:
850       ret = yad_print_run ();
851       break;
852 
853     default:
854       dialog = create_dialog ();
855 
856       if (is_x11)
857         {
858           /* add YAD_XID variable */
859           str = g_strdup_printf ("0x%lX", GDK_WINDOW_XID (gtk_widget_get_window (dialog)));
860           g_setenv ("YAD_XID", str, TRUE);
861         }
862 
863       /* make some specific init actions */
864       if (options.mode == YAD_MODE_NOTEBOOK)
865         notebook_swallow_childs ();
866       else if (options.mode == YAD_MODE_PANED)
867         paned_swallow_childs ();
868       else if (options.mode == YAD_MODE_PICTURE)
869         {
870           if (options.picture_data.size == YAD_PICTURE_FIT)
871             picture_fit_to_window ();
872         }
873 
874       if (text && options.data.selectable_labels)
875         gtk_label_select_region (GTK_LABEL (text), 0, 0);
876 
877       /* run main loop */
878       gtk_main ();
879 
880       /* print results */
881       if (ret != YAD_RESPONSE_TIMEOUT && ret != YAD_RESPONSE_ESC)
882         {
883           if (options.data.always_print)
884             yad_print_result ();
885           else
886             {
887               /* standard OK button pressed */
888               if (ret == YAD_RESPONSE_OK && options.data.buttons == NULL)
889                 yad_print_result ();
890               /* custom even button pressed */
891               else if (!(ret & 1))
892                 yad_print_result ();
893             }
894         }
895 #ifndef G_OS_WIN32
896       if (options.mode == YAD_MODE_NOTEBOOK)
897         notebook_close_childs ();
898       else if (options.mode == YAD_MODE_PANED)
899         paned_close_childs ();
900       /* autokill option for progress dialog */
901       if (!options.kill_parent)
902         {
903           if (options.mode == YAD_MODE_PROGRESS && options.progress_data.autokill && ret != YAD_RESPONSE_OK)
904             kill (getppid (), SIGHUP);
905         }
906 #endif
907     }
908 
909 #ifndef G_OS_WIN32
910   /* NSIG defined in signal.h */
911   if (options.kill_parent > 0 && options.kill_parent < NSIG)
912     kill (getppid (), options.kill_parent);
913 #endif
914 
915   return ret;
916 }
917