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