Made makefile more robust
[uzbl-mobile] / uzbl.c
1 // Original code taken from the example webkit-gtk+ application. see notice below.
2 // Modified code is licensed under the GPL 3.  See LICENSE file.
3
4
5 /*
6  * Copyright (C) 2006, 2007 Apple Inc.
7  * Copyright (C) 2007 Alp Toker <alp@atoker.com>
8  *
9  * Redistribution and use in source and binary forms, with or without
10  * modification, are permitted provided that the following conditions
11  * are met:
12  * 1. Redistributions of source code must retain the above copyright
13  *    notice, this list of conditions and the following disclaimer.
14  * 2. Redistributions in binary form must reproduce the above copyright
15  *    notice, this list of conditions and the following disclaimer in the
16  *    documentation and/or other materials provided with the distribution.
17  *
18  * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY
19  * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
20  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
21  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL APPLE COMPUTER, INC. OR
22  * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
23  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
24  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
25  * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
26  * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
27  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
28  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29  */
30
31
32 #define LENGTH(x) (sizeof x / sizeof x[0])
33
34 #include <gtk/gtk.h>
35 #include <gdk/gdkx.h>
36 #include <gdk/gdkkeysyms.h>
37 #include <webkit/webkit.h>
38 #include <pthread.h>
39 #include <stdio.h>
40 #include <string.h>
41 #include <sys/stat.h>
42 #include <sys/types.h>
43 #include <unistd.h>
44 #include <stdlib.h>
45
46 /* housekeeping / internal variables */
47 static GtkWidget* main_window;
48 static GtkWidget* mainbar;
49 static GtkWidget* mainbar_label;
50 static WebKitWebView* web_view;
51 static gchar* main_title;
52 static gchar selected_url[500];
53 static gint load_progress;
54 static Window xwin = 0;
55 static char fifopath[64];
56
57 /* state variables (initial values coming from command line arguments but may be changed later) */
58 static gchar*   uri         = NULL;
59 static gchar*   config_file = NULL;
60 static gboolean verbose     = FALSE;
61
62 /* settings from config: group behaviour */
63 static gchar*   history_handler    = NULL;
64 static gchar*   fifodir            = NULL;
65 static gchar*   download_handler   = NULL;
66 static gboolean always_insert_mode = FALSE;
67 static gboolean show_status        = FALSE;
68 static gboolean insert_mode        = FALSE;
69 static gboolean status_top         = FALSE;
70 static gchar*   modkey             = NULL;
71 static guint    modmask            = 0;
72
73 typedef struct {
74     const char *binding;
75     const char *action;
76 } Binding;
77
78 /* settings from config: group bindings_internal */
79 static Binding internal_bindings[256];
80 static int     num_internal_bindings = 0;
81
82 /* settings from config: group bindings_external */
83 static Binding external_bindings[256];
84 static int     num_external_bindings = 0;
85
86 /* commandline arguments (set initial values for the state variables) */
87 static GOptionEntry entries[] =
88 {
89     { "uri",     'u', 0, G_OPTION_ARG_STRING, &uri,         "Uri to load", NULL },
90     { "verbose", 'v', 0, G_OPTION_ARG_NONE,   &verbose,     "Be verbose",  NULL },
91     { "config",  'c', 0, G_OPTION_ARG_STRING, &config_file, "Config file", NULL },
92     { NULL,      0, 0, 0, NULL, NULL, NULL }
93 };
94
95 /* for internal list of commands */
96 typedef struct
97 {
98     const char *command;
99     void (*func_1_param)(WebKitWebView*);
100     void (*func_2_params)(WebKitWebView*, const gchar *);
101 } Command;
102
103
104 static void
105 update_title (GtkWindow* window);
106
107 static gboolean
108 run_command(const char *command, const char *args);
109
110
111 /* --- CALLBACKS --- */
112 static void
113 go_back_cb (WebKitWebView* page) {
114     (void) page;
115     webkit_web_view_go_back (web_view);
116 }
117
118 static void
119 go_forward_cb (WebKitWebView* page) {
120     (void) page;
121     webkit_web_view_go_forward (web_view);
122 }
123
124 static void
125 toggle_status_cb (WebKitWebView* page) {
126     (void) page;
127     if (show_status) {
128         gtk_widget_hide(mainbar);
129     } else {
130         gtk_widget_show(mainbar);
131     }
132     show_status = !show_status;
133     update_title (GTK_WINDOW (main_window));
134 }
135
136 static void
137 link_hover_cb (WebKitWebView* page, const gchar* title, const gchar* link, gpointer data) {
138     (void) page;
139     (void) title;
140     (void) data;    
141     //ADD HOVER URL TO WINDOW TITLE
142     selected_url[0] = '\0';
143     if (link) {
144         strcpy (selected_url, link);
145     }
146     update_title (GTK_WINDOW (main_window));
147 }
148
149 static void
150 title_change_cb (WebKitWebView* web_view, WebKitWebFrame* web_frame, const gchar* title, gpointer data) {
151     (void) web_view;
152     (void) web_frame;
153     (void) data;
154     if (main_title)
155         g_free (main_title);
156     main_title = g_strdup (title);
157     update_title (GTK_WINDOW (main_window));
158 }
159
160 static void
161 progress_change_cb (WebKitWebView* page, gint progress, gpointer data) {
162     (void) page;
163     (void) data;
164     load_progress = progress;
165     update_title (GTK_WINDOW (main_window));
166 }
167
168 static void
169 load_commit_cb (WebKitWebView* page, WebKitWebFrame* frame, gpointer data) {
170     (void) page;
171     (void) data;
172     strcpy (uri, webkit_web_frame_get_uri (frame));
173 }
174
175 static void
176 destroy_cb (GtkWidget* widget, gpointer data) {
177     (void) widget;
178     (void) data;
179     gtk_main_quit ();
180 }
181
182 static void
183 log_history_cb () {
184    if (history_handler) {
185        time_t rawtime;
186        struct tm * timeinfo;
187        char date [80];
188        time ( &rawtime );
189        timeinfo = localtime ( &rawtime );
190        strftime (date, 80, "%Y-%m-%d %H:%M:%S", timeinfo);
191        GString* args = g_string_new ("");
192        g_string_printf (args, "'%s' '%s' '%s'", uri, "TODO:page title here", date);
193        run_command(history_handler, args->str);
194    }
195 }
196
197 /* -- command to callback/function map for things we cannot attach to any signals */
198 // TODO: reload, home, quit
199 static Command commands[] =
200 {
201     { "back",          &go_back_cb,                    NULL },
202     { "forward",       &go_forward_cb,                 NULL },
203     { "refresh",       &webkit_web_view_reload,        NULL }, //Buggy
204     { "stop",          &webkit_web_view_stop_loading,  NULL },
205     { "zoom_in",       &webkit_web_view_zoom_in,       NULL }, //Can crash (when max zoom reached?).
206     { "zoom_out",      &webkit_web_view_zoom_out,      NULL },
207     { "uri",           NULL, &webkit_web_view_load_uri      },
208     { "toggle_status", &toggle_status_cb,              NULL }
209 //{ "get uri",  &webkit_web_view_get_uri},
210 };
211
212 /* -- CORE FUNCTIONS -- */
213
214 static bool
215 file_exists (const char * filename)
216 {
217     FILE *file = fopen (filename, "r");
218     if (file) {
219         fclose (file);
220         return true;
221     }
222     return false;
223 }
224
225 // make sure to put '' around args, so that if there is whitespace we can still keep arguments together.
226 static gboolean
227 run_command(const char *command, const char *args) {
228    //command <uzbl conf> <uzbl pid> <uzbl win id> <uzbl fifo file> [args]
229     GString* to_execute = g_string_new ("");
230     gboolean result;
231     g_string_printf (to_execute, "%s '%s' '%i' '%i' '%s' %s", command, config_file, (int) getpid() , (int) xwin, "/tmp/uzbl_25165827", args);
232     result = g_spawn_command_line_async (to_execute->str, NULL);
233     printf("Called %s.  Result: %s\n", to_execute->str, (result ? "FALSE" : "TRUE" ));
234     return result;
235 }
236
237 static void
238 parse_command(const char *cmd) {
239     unsigned int i;
240     Command *c = NULL;
241     char buffer[200];
242     strcpy(buffer,cmd);
243     char * command_name  = strtok (buffer, " ");
244     char * command_param = strtok (NULL,  " ,");
245
246     Command *c_tmp = NULL;
247     for (i = 0; i < LENGTH (commands); i++) {
248         c_tmp = &commands[i];
249         if (strncmp (command_name, c_tmp->command, strlen (c_tmp->command)) == 0) {
250             c = c_tmp;
251         }
252     }
253     if (c != NULL) {
254         if (c->func_2_params != NULL) {
255             if (command_param != NULL) {
256                 printf ("command executing: \"%s %s\"\n", command_name, command_param);
257                 c->func_2_params (web_view, command_param);
258             } else {
259                 if (c->func_1_param != NULL) {
260                     printf ("command executing: \"%s\"\n", command_name);
261                     c->func_1_param (web_view);
262                 } else {
263                     fprintf (stderr, "command needs a parameter. \"%s\" is not complete\n", command_name);
264                 }
265             }
266         } else if (c->func_1_param != NULL) {
267             printf ("command executing: \"%s\"\n", command_name);
268             c->func_1_param (web_view);
269         }
270     } else {
271         fprintf (stderr, "command \"%s\" not understood. ignoring.\n", cmd);
272     }
273 }
274  
275 static void
276 *control_fifo() {
277     if (fifodir) {
278         sprintf (fifopath, "%s/uzbl_%d", fifodir, (int) xwin);
279     } else {
280         sprintf (fifopath, "/tmp/uzbl_%d", (int) xwin);
281     }
282  
283     if (mkfifo (fifopath, 0666) == -1) {
284         printf ("Possible error creating fifo\n");
285     }
286  
287     printf ("Control fifo opened in %s\n", fifopath);
288  
289     while (true) {
290         FILE *fifo = fopen (fifopath, "r");
291         if (!fifo) {
292             printf ("Could not open %s for reading\n", fifopath);
293             return NULL;
294         }
295         
296         char buffer[256];
297         memset (buffer, 0, sizeof (buffer));
298         while (!feof (fifo) && fgets (buffer, sizeof (buffer), fifo)) {
299             if (strcmp (buffer, "\n")) {
300                 buffer[strlen (buffer) - 1] = '\0'; // Remove newline
301                 parse_command (buffer);
302             }
303         }
304     }
305     
306     return NULL;
307
308  
309 static void
310 setup_threading () {
311     pthread_t control_thread;
312     pthread_create(&control_thread, NULL, control_fifo, NULL);
313 }
314
315 static void
316 update_title (GtkWindow* window) {
317     GString* string_long = g_string_new ("");
318     GString* string_short = g_string_new ("");
319     if (!always_insert_mode)
320         g_string_append (string_long, (insert_mode ? "[I] " : "[C] "));
321     g_string_append (string_long, main_title);
322     g_string_append (string_short, main_title);
323     g_string_append (string_long, " - Uzbl browser");
324     g_string_append (string_short, " - Uzbl browser");
325     if (load_progress < 100)
326         g_string_append_printf (string_long, " (%d%%)", load_progress);
327
328     if (selected_url[0]!=0) {
329         g_string_append_printf (string_long, " -> (%s)", selected_url);
330     }
331
332     gchar* title_long = g_string_free (string_long, FALSE);
333     gchar* title_short = g_string_free (string_short, FALSE);
334
335     if (show_status) {
336         gtk_window_set_title (window, title_short);
337         gtk_label_set_text(GTK_LABEL(mainbar_label), title_long);
338     } else {
339         gtk_window_set_title (window, title_long);
340     }
341
342     g_free (title_long);
343     g_free (title_short);
344 }
345  
346 static gboolean
347 key_press_cb (WebKitWebView* page, GdkEventKey* event)
348 {
349     (void) page;
350     int i;
351     gboolean result=FALSE; //TRUE to stop other handlers from being invoked for the event. FALSE to propagate the event further.
352     if (event->type != GDK_KEY_PRESS) 
353         return result;
354
355     //TURN OFF/ON INSERT MODE
356     if (!always_insert_mode && ((insert_mode && (event->keyval == GDK_Escape)) || (!insert_mode && (event->string[0] == 'i')))) {
357         insert_mode = !insert_mode;
358         update_title (GTK_WINDOW (main_window));
359         return TRUE;
360     }
361
362     //INTERNAL BINDINGS
363     for (i = 0; i < num_internal_bindings; i++) {
364         if (strcmp(event->string, internal_bindings[i].binding) == 0) {
365             if (!insert_mode || (event->state == modmask)) {
366                 parse_command (internal_bindings[i].action);
367                 result = TRUE;
368             }
369         }       
370     }
371
372     //EXTERNAL BINDINGS
373     for (i = 0; i < num_external_bindings; i++) {
374         if (strcmp(event->string, external_bindings[i].binding) == 0) {
375             if (!insert_mode || (event->state == modmask)) {
376                 run_command(external_bindings[i].action, NULL);
377                 result = TRUE;
378             }
379         }       
380     }
381
382     if (!result)
383         result = (insert_mode ? FALSE : TRUE);      
384
385     return result;
386 }
387
388 static GtkWidget*
389 create_browser () {
390     GtkWidget* scrolled_window = gtk_scrolled_window_new (NULL, NULL);
391     gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (scrolled_window), GTK_POLICY_NEVER, GTK_POLICY_NEVER); //todo: some sort of display of position/total length. like what emacs does
392
393     web_view = WEBKIT_WEB_VIEW (webkit_web_view_new ());
394     gtk_container_add (GTK_CONTAINER (scrolled_window), GTK_WIDGET (web_view));
395
396     g_signal_connect (G_OBJECT (web_view), "title-changed", G_CALLBACK (title_change_cb), web_view);
397     g_signal_connect (G_OBJECT (web_view), "load-progress-changed", G_CALLBACK (progress_change_cb), web_view);
398     g_signal_connect (G_OBJECT (web_view), "load-committed", G_CALLBACK (load_commit_cb), web_view);
399     g_signal_connect (G_OBJECT (web_view), "load-committed", G_CALLBACK (log_history_cb), web_view);
400     g_signal_connect (G_OBJECT (web_view), "hovering-over-link", G_CALLBACK (link_hover_cb), web_view);
401     g_signal_connect (G_OBJECT (web_view), "key-press-event", G_CALLBACK (key_press_cb), web_view);
402
403     return scrolled_window;
404 }
405
406 static GtkWidget*
407 create_mainbar () {
408     mainbar = gtk_hbox_new (FALSE, 0);
409     mainbar_label = gtk_label_new ("");  
410     gtk_misc_set_alignment (GTK_MISC(mainbar_label), 0, 0);
411     gtk_misc_set_padding (GTK_MISC(mainbar_label), 2, 2);
412     gtk_box_pack_start (GTK_BOX (mainbar), mainbar_label, TRUE, TRUE, 0);
413     return mainbar;
414 }
415
416 static
417 GtkWidget* create_window () {
418     GtkWidget* window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
419     gtk_window_set_default_size (GTK_WINDOW (window), 800, 600);
420     gtk_widget_set_name (window, "Uzbl browser");
421     g_signal_connect (G_OBJECT (window), "destroy", G_CALLBACK (destroy_cb), NULL);
422
423     return window;
424 }
425
426 static void
427 add_binding (char *binding, char *action, bool internal) {
428     Binding bind = {binding, action};
429     if (internal) {
430         internal_bindings[num_internal_bindings] = bind;
431         num_internal_bindings ++;
432     } else {
433         external_bindings[num_external_bindings] = bind;
434         num_external_bindings ++;
435     }
436 }
437
438 static void
439 settings_init () {
440     GKeyFile* config;
441     gboolean res  = FALSE;
442     gchar** keysi = NULL;
443     gchar** keyse = NULL;
444
445     if (! config_file) {
446         const char* xdg = getenv ("XDG_CONFIG_HOME");
447         char conf[256];
448         if (xdg) {
449             printf("XDG_CONFIG_DIR: %s\n", xdg);
450             strcpy (conf, xdg);
451             strcat (conf, "/uzbl");
452             if (file_exists (conf)) {
453                 printf ("Config file %s found.\n", conf);
454                 config_file = &conf[0];
455             }
456         }
457     }
458
459     if (config_file) {
460         config = g_key_file_new ();
461         res = g_key_file_load_from_file (config, config_file, G_KEY_FILE_NONE, NULL);
462           if(res) {
463             printf ("Config %s loaded\n", config_file);
464           } else {
465             fprintf (stderr, "Config %s loading failed\n", config_file);
466         }
467     } else {
468         printf ("No configuration.\n");
469     }
470
471     if (res) {
472         history_handler    = g_key_file_get_value   (config, "behavior", "history_handler", NULL);
473         download_handler   = g_key_file_get_value   (config, "behavior", "download_handler", NULL);
474         always_insert_mode = g_key_file_get_boolean (config, "behavior", "always_insert_mode", NULL);
475         show_status        = g_key_file_get_boolean (config, "behavior", "show_status", NULL);
476         modkey             = g_key_file_get_value   (config, "behavior", "modkey", NULL);
477         keysi              = g_key_file_get_keys    (config, "bindings_internal", NULL, NULL);
478         keyse              = g_key_file_get_keys    (config, "bindings_external", NULL, NULL);
479         status_top         = g_key_file_get_boolean (config, "behavior", "status_top", NULL);
480         if (! fifodir)
481             fifodir        = g_key_file_get_value   (config, "behavior", "fifodir", NULL);
482     }
483         
484     if (history_handler) {
485         printf ("History handler: %s\n", history_handler);
486     } else {
487         printf ("History handler disabled\n");
488     }
489
490     if (download_handler) {
491         printf ("Download manager: %s\n", download_handler);
492     } else {
493         printf ("Download manager disabled\n");
494     }
495
496     if (fifodir) {
497         printf ("Fifo directory: %s\n", fifodir);
498     } else {
499         printf ("Fifo directory: /tmp\n");
500     }
501
502     printf ("Always insert mode: %s\n", (always_insert_mode ? "TRUE" : "FALSE"));
503
504     printf ("Show status: %s\n", (show_status ? "TRUE" : "FALSE"));
505
506     printf ("Status top: %s\n", (status_top ? "TRUE" : "FALSE"));
507
508     if (modkey) {
509         printf ("Modkey: %s\n", modkey);
510     } else {
511         printf ("Modkey disabled\n");   
512         modkey = "";
513     }
514     //POSSIBLE MODKEY VALUES (COMBINATIONS CAN BE USED)
515     gchar* modkeyup = g_utf8_strup(modkey, -1);
516     if (g_strrstr(modkeyup,"SHIFT") != NULL)    modmask |= GDK_SHIFT_MASK;    //the Shift key.
517     if (g_strrstr(modkeyup,"LOCK") != NULL)     modmask |= GDK_LOCK_MASK;     //a Lock key (depending on the modifier mapping of the X server this may either be CapsLock or ShiftLock).
518     if (g_strrstr(modkeyup,"CONTROL") != NULL)  modmask |= GDK_CONTROL_MASK;  //the Control key.
519     if (g_strrstr(modkeyup,"MOD1") != NULL)     modmask |= GDK_MOD1_MASK;     //the fourth modifier key (it depends on the modifier mapping of the X server which key is interpreted as this modifier, but normally it is the Alt key).
520     if (g_strrstr(modkeyup,"MOD2") != NULL)     modmask |= GDK_MOD2_MASK;     //the fifth modifier key (it depends on the modifier mapping of the X server which key is interpreted as this modifier).
521     if (g_strrstr(modkeyup,"MOD3") != NULL)     modmask |= GDK_MOD3_MASK;     //the sixth modifier key (it depends on the modifier mapping of the X server which key is interpreted as this modifier).
522     if (g_strrstr(modkeyup,"MOD4") != NULL)     modmask |= GDK_MOD4_MASK;     //the seventh modifier key (it depends on the modifier mapping of the X server which key is interpreted as this modifier).
523     if (g_strrstr(modkeyup,"MOD5") != NULL)     modmask |= GDK_MOD5_MASK;     //the eighth modifier key (it depends on the modifier mapping of the X server which key is interpreted as this modifier).
524     if (g_strrstr(modkeyup,"BUTTON1") != NULL)  modmask |= GDK_BUTTON1_MASK;  //the first mouse button.
525     if (g_strrstr(modkeyup,"BUTTON2") != NULL)  modmask |= GDK_BUTTON2_MASK;  //the second mouse button.
526     if (g_strrstr(modkeyup,"BUTTON3") != NULL)  modmask |= GDK_BUTTON3_MASK;  //the third mouse button.
527     if (g_strrstr(modkeyup,"BUTTON4") != NULL)  modmask |= GDK_BUTTON4_MASK;  //the fourth mouse button.
528     if (g_strrstr(modkeyup,"BUTTON5") != NULL)  modmask |= GDK_BUTTON5_MASK;  //the fifth mouse button.
529     if (g_strrstr(modkeyup,"SUPER") != NULL)    modmask |= GDK_SUPER_MASK;    //the Super modifier. Since 2.10
530     if (g_strrstr(modkeyup,"HYPER") != NULL)    modmask |= GDK_HYPER_MASK;    //the Hyper modifier. Since 2.10
531     if (g_strrstr(modkeyup,"META") != NULL)     modmask |= GDK_META_MASK;     //the Meta modifier. Since 2.10  */
532     free (modkeyup);
533
534     if (keysi) {
535               int i = 0;
536         for (i = 0; keysi[i]; i++) {
537             gchar *binding = g_key_file_get_string (config, "bindings_internal", keysi[i], NULL);
538             printf ("Action: %s, Binding: %s (internal)\n", g_strdup (keysi[i]), binding);
539             add_binding (binding, g_strdup (keysi[i]), true);
540         }
541     }
542     if (keyse) {
543               int i = 0;
544         for (i = 0; keyse[i]; i++) {
545             gchar *binding = g_key_file_get_string (config, "bindings_external", keyse[i], NULL);
546             printf ("Action: %s, Binding: %s (external)\n", g_strdup (keyse[i]), binding);
547             add_binding (binding, g_strdup (keyse[i]), false);
548         }
549     }
550 }
551
552 int
553 main (int argc, char* argv[]) {
554     gtk_init (&argc, &argv);
555     if (!g_thread_supported ())
556         g_thread_init (NULL);
557
558     GError *error = NULL;
559     GOptionContext* context = g_option_context_new ("- some stuff here maybe someday");
560     g_option_context_add_main_entries (context, entries, NULL);
561     g_option_context_add_group (context, gtk_get_option_group (TRUE));
562     g_option_context_parse (context, &argc, &argv, &error);
563
564     settings_init ();
565     if (always_insert_mode)
566         insert_mode = TRUE;
567
568     GtkWidget* vbox = gtk_vbox_new (FALSE, 0);
569     if (status_top)
570         gtk_box_pack_start (GTK_BOX (vbox), create_mainbar (), FALSE, TRUE, 0);
571     gtk_box_pack_start (GTK_BOX (vbox), create_browser (), TRUE, TRUE, 0);
572     if (!status_top)
573         gtk_box_pack_start (GTK_BOX (vbox), create_mainbar (), FALSE, TRUE, 0);
574
575     main_window = create_window ();
576     gtk_container_add (GTK_CONTAINER (main_window), vbox);
577
578     webkit_web_view_load_uri (web_view, uri);
579
580     gtk_widget_grab_focus (GTK_WIDGET (web_view));
581     gtk_widget_show_all (main_window);
582     xwin = GDK_WINDOW_XID (GTK_WIDGET (main_window)->window);
583     printf("window_id %i\n",(int) xwin);
584     printf("pid %i\n", getpid ());
585
586     if (!show_status)
587         gtk_widget_hide(mainbar);
588
589     setup_threading ();
590
591     gtk_main ();
592
593     unlink (fifopath);
594     return 0;
595 }