Merge in Jan (jouz) stuff properly
[uzbl-mobile] / uzbl.c
1 /* -*- c-basic-offset: 4; */
2 // Original code taken from the example webkit-gtk+ application. see notice below.
3 // Modified code is licensed under the GPL 3.  See LICENSE file.
4
5
6 /*
7  * Copyright (C) 2006, 2007 Apple Inc.
8  * Copyright (C) 2007 Alp Toker <alp@atoker.com>
9  *
10  * Redistribution and use in source and binary forms, with or without
11  * modification, are permitted provided that the following conditions
12  * are met:
13  * 1. Redistributions of source code must retain the above copyright
14  *    notice, this list of conditions and the following disclaimer.
15  * 2. Redistributions in binary form must reproduce the above copyright
16  *    notice, this list of conditions and the following disclaimer in the
17  *    documentation and/or other materials provided with the distribution.
18  *
19  * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY
20  * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
22  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL APPLE COMPUTER, INC. OR
23  * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
24  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
25  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
26  * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
27  * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
28  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
29  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
30  */
31
32
33 #define LENGTH(x) (sizeof x / sizeof x[0])
34 #define MAX_BINDINGS 256
35
36 #include <gtk/gtk.h>
37 #include <gdk/gdkx.h>
38 #include <gdk/gdkkeysyms.h>
39 #include <sys/socket.h>
40 #include <sys/stat.h>
41 #include <sys/types.h>
42 #include <sys/un.h>
43 #include <sys/utsname.h>
44 #include <webkit/webkit.h>
45 #include <stdio.h>
46 #include <string.h>
47 #include <unistd.h>
48 #include <stdlib.h>
49 #include <errno.h>
50 #include <string.h>
51 #include <fcntl.h>
52 #include <sys/socket.h>
53 #include <sys/un.h>
54 #include <libsoup/soup.h>
55 #include "uzbl.h"
56
57
58 /* status bar format
59    TODO: integrate with the config file
60 */
61 char *status_format =  "<span background=\"darkgreen\" foreground=\"khaki\"> MODE </span> | Cmd: <span background=\"red\" foreground=\"white\">KEYCMD</span> | <span background=\"darkblue\" foreground=\"white\">  <b>TITLE</b>  </span> | LOAD_PROGRESS% <span font_family=\"monospace\">LOAD_PROGRESSBAR</span> | <span foreground=\"darkgreen\">URI</span> | NAME | <span foreground=\"black\" background=\"khaki\"> Uzbl browser </span>";
62
63 /* housekeeping / internal variables */
64 static gchar          selected_url[500] = "\0";
65 static char           executable_path[500];
66 static GString*       keycmd;
67 static gchar          searchtx[500] = "\0";
68
69 static Uzbl uzbl;
70
71 /* settings from config: group behaviour */
72 static gchar*   history_handler    = NULL;
73 static gchar*   fifo_dir           = NULL;
74 static gchar*   socket_dir         = NULL;
75 static gchar*   download_handler   = NULL;
76 static gboolean always_insert_mode = FALSE;
77 static gboolean show_status        = FALSE;
78 static gboolean insert_mode        = FALSE;
79 static gboolean status_top         = FALSE;
80 static gchar*   modkey             = NULL;
81 static guint    modmask            = 0;
82 static guint    http_debug         = 0;
83
84 /* System info */
85 static struct utsname unameinfo;
86
87 /* settings from config: group bindings, key -> action */
88 static GHashTable* bindings;
89
90 /* command list: name -> Command  */
91 static GHashTable* commands;
92
93 /* commandline arguments (set initial values for the state variables) */
94 static GOptionEntry entries[] =
95 {
96     { "uri",     'u', 0, G_OPTION_ARG_STRING, &uzbl.state.uri,           "Uri to load", "URI" },
97     { "name",    'n', 0, G_OPTION_ARG_STRING, &uzbl.state.instance_name, "Name of the current instance", "NAME" },
98     { "config",  'c', 0, G_OPTION_ARG_STRING, &uzbl.state.config_file,   "Config file", "FILE" },
99     { NULL,      0, 0, 0, NULL, NULL, NULL }
100 };
101
102 typedef void (*Command)(WebKitWebView*, const char *);
103
104 /* XDG stuff */
105 static char *XDG_CONFIG_HOME_default[256];
106 static char *XDG_CONFIG_DIRS_default = "/etc/xdg";
107
108
109 /* --- UTILITY FUNCTIONS --- */
110
111 char *
112 itos(int val) {
113     char tmp[20];
114
115     snprintf(tmp, sizeof(tmp), "%i", val);
116     return g_strdup(tmp);
117 }
118
119 static char *
120 str_replace (const char* search, const char* replace, const char* string) {
121     return g_strjoinv (replace, g_strsplit(string, search, -1));
122 }
123
124 /* --- CALLBACKS --- */
125
126 static gboolean
127 new_window_cb (WebKitWebView *web_view, WebKitWebFrame *frame, WebKitNetworkRequest *request, WebKitWebNavigationAction *navigation_action, WebKitWebPolicyDecision *policy_decision, gpointer user_data) {
128     (void) web_view;
129     (void) frame;
130     (void) navigation_action;
131     (void) policy_decision;
132     (void) user_data;
133     const gchar* uri = webkit_network_request_get_uri (request);
134     printf("New window requested -> %s \n", uri);
135     new_window_load_uri(uri);
136     return (FALSE);
137 }
138
139 WebKitWebView*
140 create_web_view_cb (WebKitWebView  *web_view, WebKitWebFrame *frame, gpointer user_data) {
141     (void) web_view;
142     (void) frame;
143     (void) user_data;
144     if (selected_url[0]!=0) {
145         printf("\nNew web view -> %s\n",selected_url);
146         new_window_load_uri(selected_url);
147     } else {
148         printf("New web view -> %s\n","Nothing to open, exiting");
149     }
150     return (NULL);
151 }
152
153 static gboolean
154 download_cb (WebKitWebView *web_view, GObject *download, gpointer user_data) {
155     (void) web_view;
156     (void) user_data;
157     if (download_handler) {
158         const gchar* uri = webkit_download_get_uri ((WebKitDownload*)download);
159         printf("Download -> %s\n",uri);
160         run_command(download_handler, uri);
161     }
162     return (FALSE);
163 }
164
165 /* scroll a bar in a given direction */
166 static void
167 scroll (GtkAdjustment* bar, const char *param) {
168     gdouble amount;
169     gchar *end;
170
171     amount = g_ascii_strtod(param, &end);
172
173     if (*end)
174         fprintf(stderr, "found something after double: %s\n", end);
175
176     gtk_adjustment_set_value (bar, gtk_adjustment_get_value(bar)+amount);
177 }
178
179 static void scroll_vert(WebKitWebView* page, const char *param) {
180     (void) page;
181
182     scroll(uzbl.gui.bar_v, param);
183 }
184
185 static void scroll_horz(WebKitWebView* page, const char *param) {
186     (void) page;
187
188     scroll(uzbl.gui.bar_h, param);
189 }
190
191 static void
192 toggle_status_cb (WebKitWebView* page, const char *param) {
193     (void)page;
194     (void)param;
195
196     if (show_status) {
197         gtk_widget_hide(uzbl.gui.mainbar);
198     } else {
199         gtk_widget_show(uzbl.gui.mainbar);
200     }
201     show_status = !show_status;
202     update_title();
203 }
204
205 static void
206 link_hover_cb (WebKitWebView* page, const gchar* title, const gchar* link, gpointer data) {
207     (void) page;
208     (void) title;
209     (void) data;    
210     //ADD HOVER URL TO WINDOW TITLE
211     selected_url[0] = '\0';
212     if (link) {
213         strcpy (selected_url, link);
214     }
215     update_title();
216 }
217
218 static void
219 title_change_cb (WebKitWebView* web_view, WebKitWebFrame* web_frame, const gchar* title, gpointer data) {
220     (void) web_view;
221     (void) web_frame;
222     (void) data;
223     if (uzbl.gui.main_title)
224         g_free (uzbl.gui.main_title);
225     uzbl.gui.main_title = g_strdup (title);
226     update_title();
227 }
228
229 static void
230 progress_change_cb (WebKitWebView* page, gint progress, gpointer data) {
231     (void) page;
232     (void) data;
233     uzbl.gui.sbar.load_progress = progress;
234     update_title();
235 }
236
237 static void
238 load_commit_cb (WebKitWebView* page, WebKitWebFrame* frame, gpointer data) {
239     (void) page;
240     (void) data;
241     free (uzbl.state.uri);
242     GString* newuri = g_string_new (webkit_web_frame_get_uri (frame));
243     uzbl.state.uri = g_string_free (newuri, FALSE);
244 }
245
246 static void
247 destroy_cb (GtkWidget* widget, gpointer data) {
248     (void) widget;
249     (void) data;
250     gtk_main_quit ();
251 }
252
253 static void
254 log_history_cb () {
255    if (history_handler) {
256        time_t rawtime;
257        struct tm * timeinfo;
258        char date [80];
259        time ( &rawtime );
260        timeinfo = localtime ( &rawtime );
261        strftime (date, 80, "%Y-%m-%d %H:%M:%S", timeinfo);
262        GString* args = g_string_new ("");
263        g_string_printf (args, "'%s'", date);
264        run_command(history_handler, args->str);
265        g_string_free (args, TRUE);
266    }
267 }
268
269
270 /* VIEW funcs (little webkit wrappers) */
271 #define VIEWFUNC(name) static void view_##name(WebKitWebView *page, const char *param){(void)param; webkit_web_view_##name(page);}
272 VIEWFUNC(reload)
273 VIEWFUNC(reload_bypass_cache)
274 VIEWFUNC(stop_loading)
275 VIEWFUNC(zoom_in)
276 VIEWFUNC(zoom_out)
277 VIEWFUNC(go_back)
278 VIEWFUNC(go_forward)
279 #undef VIEWFUNC
280
281 /* -- command to callback/function map for things we cannot attach to any signals */
282 // TODO: reload
283
284 static struct {char *name; Command command;} cmdlist[] =
285 {
286     { "back",             view_go_back            },
287     { "forward",          view_go_forward         },
288     { "scroll_vert",      scroll_vert             },
289     { "scroll_horz",      scroll_horz             },
290     { "reload",           view_reload,            }, 
291     { "reload_ign_cache", view_reload_bypass_cache},
292     { "stop",             view_stop_loading,      },
293     { "zoom_in",          view_zoom_in,           }, //Can crash (when max zoom reached?).
294     { "zoom_out",         view_zoom_out,          },
295     { "uri",              load_uri                },
296     { "script",           run_js                  },
297     { "toggle_status",    toggle_status_cb        },
298     { "spawn",            spawn                   },
299     { "exit",             close_uzbl              },
300     { "search",           search_text             },
301     { "insert_mode",      set_insert_mode         }
302 };
303
304 static void
305 commands_hash(void)
306 {
307     unsigned int i;
308     commands = g_hash_table_new(g_str_hash, g_str_equal);
309
310     for (i = 0; i < LENGTH(cmdlist); i++)
311         g_hash_table_insert(commands, cmdlist[i].name, cmdlist[i].command);
312 }
313
314 /* -- CORE FUNCTIONS -- */
315
316 void
317 free_action(gpointer act) {
318     Action *action = (Action*)act;
319     g_free(action->name);
320     if (action->param)
321         g_free(action->param);
322     g_free(action);
323 }
324
325 Action*
326 new_action(const gchar *name, const gchar *param) {
327     Action *action = g_new(Action, 1);
328
329     action->name = g_strdup(name);
330     if (param)
331         action->param = g_strdup(param);
332     else
333         action->param = NULL;
334
335     return action;
336 }
337
338 static bool
339 file_exists (const char * filename) {
340     FILE *file = fopen (filename, "r");
341     if (file) {
342         fclose (file);
343         return true;
344     }
345     return false;
346 }
347
348 void
349 set_insert_mode(WebKitWebView *page, const gchar *param) {
350     (void)page;
351     (void)param;
352
353     insert_mode = TRUE;
354     update_title();
355 }
356
357 static void
358 load_uri (WebKitWebView * web_view, const gchar *param) {
359     if (param) {
360         GString* newuri = g_string_new (param);
361         if (g_strrstr (param, "://") == NULL)
362             g_string_prepend (newuri, "http://"); 
363         webkit_web_view_load_uri (web_view, newuri->str);
364         g_string_free (newuri, TRUE);
365     }
366 }
367
368 static void
369 run_js (WebKitWebView * web_view, const gchar *param) {
370     if (param)
371         webkit_web_view_execute_script (web_view, param);
372 }
373
374 static void
375 search_text (WebKitWebView *page, const char *param) {
376     if ((param) && (param[0] != '\0')) {
377         strcpy(searchtx, param);
378     }
379     if (searchtx[0] != '\0') {
380         printf ("Searching: %s\n", searchtx);
381         webkit_web_view_unmark_text_matches (page);
382         webkit_web_view_mark_text_matches (page, searchtx, FALSE, 0);
383         webkit_web_view_set_highlight_text_matches (page, TRUE);
384         webkit_web_view_search_text (page, searchtx, FALSE, TRUE, TRUE);
385     }
386 }
387
388 static void
389 new_window_load_uri (const gchar * uri) {
390     GString* to_execute = g_string_new ("");
391     g_string_append_printf (to_execute, "%s --uri '%s'", executable_path, uri);
392     int i;
393     for (i = 0; entries[i].long_name != NULL; i++) {
394         if ((entries[i].arg == G_OPTION_ARG_STRING) && (strcmp(entries[i].long_name,"uri")!=0)) {
395             gchar** str = (gchar**)entries[i].arg_data;
396             if (*str!=NULL) {
397                 g_string_append_printf (to_execute, " --%s '%s'", entries[i].long_name, *str);
398             }
399         }
400     }
401     printf("\n%s\n", to_execute->str);
402     g_spawn_command_line_async (to_execute->str, NULL);
403     g_string_free (to_execute, TRUE);
404 }
405
406 static void
407 close_uzbl (WebKitWebView *page, const char *param) {
408     (void)page;
409     (void)param;
410     gtk_main_quit ();
411 }
412
413 /* --Statusbar functions-- */
414 static char*
415 build_progressbar_ascii(int percent) {
416    int width=10;
417    int i;
418    double l;
419    GString *bar = g_string_new("");
420
421    l = (double)percent*((double)width/100.);
422    l = (int)(l+.5)>=(int)l ? l+.5 : l;
423
424    g_string_append(bar, "[");
425    for(i=0; i<(int)l; i++)
426        g_string_append(bar, "=");
427           
428    for(; i<width; i++)
429        g_string_append(bar, "·");
430    g_string_append(bar, "]");
431
432    return g_string_free(bar, FALSE);
433 }
434
435 static void
436 setup_scanner() {
437      const GScannerConfig scan_config = {
438              (
439               "\t\r\n"
440              )            /* cset_skip_characters */,
441              (
442               G_CSET_a_2_z
443               "_"
444               G_CSET_A_2_Z
445              )            /* cset_identifier_first */,
446              (
447               G_CSET_a_2_z
448               "_0123456789"
449               G_CSET_A_2_Z
450               G_CSET_LATINS
451               G_CSET_LATINC
452              )            /* cset_identifier_nth */,
453              ( "#\n" )    /* cpair_comment_single */,
454
455              TRUE         /* case_sensitive */,
456
457              FALSE        /* skip_comment_multi */,
458              FALSE        /* skip_comment_single */,
459              FALSE        /* scan_comment_multi */,
460              TRUE         /* scan_identifier */,
461              TRUE         /* scan_identifier_1char */,
462              FALSE        /* scan_identifier_NULL */,
463              TRUE         /* scan_symbols */,
464              FALSE        /* scan_binary */,
465              FALSE        /* scan_octal */,
466              FALSE        /* scan_float */,
467              FALSE        /* scan_hex */,
468              FALSE        /* scan_hex_dollar */,
469              FALSE        /* scan_string_sq */,
470              FALSE        /* scan_string_dq */,
471              TRUE         /* numbers_2_int */,
472              FALSE        /* int_2_float */,
473              FALSE        /* identifier_2_string */,
474              FALSE        /* char_2_token */,
475              FALSE        /* symbol_2_token */,
476              TRUE         /* scope_0_fallback */,
477              FALSE,
478              TRUE
479      };
480
481      uzbl.scan = g_scanner_new(&scan_config);
482      while(symp->symbol_name) {
483          g_scanner_scope_add_symbol(uzbl.scan, 0,
484                          symp->symbol_name,
485                          GINT_TO_POINTER(symp->symbol_token));
486          symp++;
487      }
488 }
489
490 static gchar *
491 parse_status_template(const char *template) {
492      GTokenType token = G_TOKEN_NONE;
493      GString *ret = g_string_new("");
494      gchar *buf=NULL;
495      int sym;
496
497      if(!template)
498          return NULL;
499
500      g_scanner_input_text(uzbl.scan, template, strlen(template));
501      while(!g_scanner_eof(uzbl.scan) && token != G_TOKEN_LAST) {
502          token = g_scanner_get_next_token(uzbl.scan);
503
504          if(token == G_TOKEN_SYMBOL) {
505              sym = (int)g_scanner_cur_value(uzbl.scan).v_symbol;
506              switch(sym) {
507                  case SYM_URI:
508                      g_string_append(ret, uzbl.state.uri);
509                      break;
510                  case SYM_LOADPRGS:
511                      g_string_append(ret, itos(uzbl.gui.sbar.load_progress));
512                      break;
513                  case SYM_LOADPRGSBAR:
514                      buf = build_progressbar_ascii(uzbl.gui.sbar.load_progress);
515                      g_string_append(ret, buf);
516                      g_free(buf);
517                      break;
518                  case SYM_TITLE:
519                      g_string_append(ret,
520                          uzbl.gui.main_title?uzbl.gui.main_title:"");
521                      break;
522                  case SYM_NAME:
523                      g_string_append(ret, 
524                          uzbl.state.instance_name?uzbl.state.instance_name:"" );
525                      break;
526                  case SYM_KEYCMD:
527                      g_string_append(ret, 
528                          keycmd->str?keycmd->str:"" );
529                      break;
530                  case SYM_MODE:
531                      g_string_append(ret, 
532                          insert_mode?"[I]":"[C]" );
533                      break;
534                  default:
535                      break;
536              }
537          }
538          else if(token == G_TOKEN_INT) {
539              g_string_append(ret, itos(g_scanner_cur_value(uzbl.scan).v_int));
540          }
541          else if(token == G_TOKEN_IDENTIFIER) {
542              g_string_append(ret, (gchar *)g_scanner_cur_value(uzbl.scan).v_identifier);
543          }
544          else if(token == G_TOKEN_CHAR) {
545              g_string_append_printf(ret, "%c", g_scanner_cur_value(uzbl.scan).v_char);
546          }
547      }
548
549      return g_string_free(ret, FALSE);
550 }
551 /* --End Statusbar functions-- */
552
553
554 // make sure to put '' around args, so that if there is whitespace we can still keep arguments together.
555 static gboolean
556 run_command(const char *command, const char *args) {
557    //command <uzbl conf> <uzbl pid> <uzbl win id> <uzbl fifo file> <uzbl socket file> [args]
558     GString* to_execute = g_string_new ("");
559     gboolean result;
560     g_string_printf (to_execute, "%s '%s' '%i' '%i' '%s' '%s'", 
561                     command, uzbl.state.config_file, (int) getpid() ,
562                     (int) uzbl.xwin, uzbl.comm.fifo_path, uzbl.comm.socket_path);
563     g_string_append_printf (to_execute, " '%s' '%s'", 
564                     uzbl.state.uri, "TODO title here");
565     if(args) {
566         g_string_append_printf (to_execute, " %s", args);
567     }
568     result = g_spawn_command_line_async (to_execute->str, NULL);
569     printf("Called %s.  Result: %s\n", to_execute->str, (result ? "TRUE" : "FALSE" ));
570     g_string_free (to_execute, TRUE);
571     return result;
572 }
573
574 static void
575 spawn(WebKitWebView *web_view, const char *param) {
576     (void)web_view;
577     run_command(param, NULL);
578 }
579
580 static void
581 parse_command(const char *cmd, const char *param) {
582     Command c;
583
584     if ((c = g_hash_table_lookup(commands, cmd)))
585         c(uzbl.gui.web_view, param);
586     else
587         fprintf (stderr, "command \"%s\" not understood. ignoring.\n", cmd);
588 }
589
590 static void
591 parse_line(char *line) {
592     gchar **parts;
593
594     g_strstrip(line);
595
596     parts = g_strsplit(line, " ", 2);
597
598     if (!parts)
599         return;
600
601     parse_command(parts[0], parts[1]);
602
603     g_strfreev(parts);
604 }
605
606 enum { FIFO, SOCKET};
607 void
608 build_stream_name(int type) {
609     char *xwin_str;
610     State *s = &uzbl.state;
611
612     xwin_str = itos((int)uzbl.xwin);
613     switch(type) {
614         case FIFO:
615             if (fifo_dir) {
616                 sprintf (uzbl.comm.fifo_path, "%s/uzbl_fifo_%s", 
617                                 fifo_dir, s->instance_name ? s->instance_name : xwin_str);
618             } else {
619                 sprintf (uzbl.comm.fifo_path, "/tmp/uzbl_fifo_%s",
620                                 s->instance_name ? s->instance_name : xwin_str);
621             }
622             break;
623
624         case SOCKET:
625             if (socket_dir) {
626                 sprintf (uzbl.comm.socket_path, "%s/uzbl_socket_%s",
627                                 socket_dir, s->instance_name ? s->instance_name : xwin_str);
628             } else {
629                 sprintf (uzbl.comm.socket_path, "/tmp/uzbl_socket_%s",
630                                 s->instance_name ? s->instance_name : xwin_str);
631             }
632             break;
633         default:
634             break;
635     }
636     g_free(xwin_str);
637 }
638
639 static void
640 control_fifo(GIOChannel *gio, GIOCondition condition) {
641     printf("triggered\n");
642     gchar *ctl_line;
643     GIOStatus ret;
644     GError *err = NULL;
645
646     if (condition & G_IO_HUP)
647         g_error ("Fifo: Read end of pipe died!\n");
648
649     if(!gio)
650        g_error ("Fifo: GIOChannel broke\n");
651
652     ret = g_io_channel_read_line(gio, &ctl_line, NULL, NULL, &err);
653     if (ret == G_IO_STATUS_ERROR)
654         g_error ("Fifo: Error reading: %s\n", err->message);
655
656     parse_line(ctl_line);
657     g_free(ctl_line);
658     printf("...done\n");
659     return;
660 }
661
662 static void
663 create_fifo() {
664     GIOChannel *chan = NULL;
665     GError *error = NULL;
666
667     build_stream_name(FIFO);
668     if (file_exists(uzbl.comm.fifo_path)) {
669         g_error ("Fifo: Error when creating %s: File exists\n", uzbl.comm.fifo_path);
670         return;
671     }
672     if (mkfifo (uzbl.comm.fifo_path, 0666) == -1) {
673         g_error ("Fifo: Error when creating %s: %s\n", uzbl.comm.fifo_path, strerror(errno));
674     } else {
675         // we don't really need to write to the file, but if we open the file as 'r' we will block here, waiting for a writer to open the file.
676         chan = g_io_channel_new_file((gchar *) uzbl.comm.fifo_path, "r+", &error);
677         if (chan) {
678             if (!g_io_add_watch(chan, G_IO_IN|G_IO_HUP, (GIOFunc) control_fifo, NULL)) {
679                 g_error ("Fifo: could not add watch on %s\n", uzbl.comm.fifo_path);
680             } else { 
681                 printf ("Fifo: created successfully as %s\n", uzbl.comm.fifo_path);
682             }
683         } else {
684             g_error ("Fifo: Error while opening: %s\n", error->message);
685         }
686     }
687     return;
688 }
689
690 static void
691 control_socket(GIOChannel *chan) {
692     struct sockaddr_un remote;
693     char buffer[512], *ctl_line;
694     char temp[128];
695     int sock, clientsock, n, done;
696     unsigned int t;
697
698     sock = g_io_channel_unix_get_fd(chan);
699
700     memset (buffer, 0, sizeof (buffer));
701
702     t          = sizeof (remote);
703     clientsock = accept (sock, (struct sockaddr *) &remote, &t);
704
705     done = 0;
706     do {
707         memset (temp, 0, sizeof (temp));
708         n = recv (clientsock, temp, 128, 0);
709         if (n == 0) {
710             buffer[strlen (buffer)] = '\0';
711             done = 1;
712         }
713         if (!done)
714             strcat (buffer, temp);
715     } while (!done);
716
717     if (strcmp (buffer, "\n") < 0) {
718         buffer[strlen (buffer) - 1] = '\0';
719     } else {
720         buffer[strlen (buffer)] = '\0';
721     }
722     close (clientsock);
723     ctl_line = g_strdup(buffer);
724     parse_line (ctl_line);
725
726 /*
727    TODO: we should be able to do it with this.  but glib errors out with "Invalid argument"
728     GError *error = NULL;
729     gsize len;
730     GIOStatus ret;
731     ret = g_io_channel_read_line(chan, &ctl_line, &len, NULL, &error);
732     if (ret == G_IO_STATUS_ERROR)
733         g_error ("Error reading: %s\n", error->message);
734
735     printf("Got line %s (%u bytes) \n",ctl_line, len);
736     if(ctl_line) {
737        parse_line(ctl_line);
738 */
739
740     g_free(ctl_line);
741     return;
742
743
744 static void
745 create_socket() {
746     GIOChannel *chan = NULL;
747     int sock, len;
748     struct sockaddr_un local;
749
750     build_stream_name(SOCKET);
751     sock = socket (AF_UNIX, SOCK_STREAM, 0);
752
753     local.sun_family = AF_UNIX;
754     strcpy (local.sun_path, uzbl.comm.socket_path);
755     unlink (local.sun_path);
756
757     len = strlen (local.sun_path) + sizeof (local.sun_family);
758     bind (sock, (struct sockaddr *) &local, len);
759
760     if (errno == -1) {
761         printf ("Socket: Could not open in %s: %s\n", uzbl.comm.socket_path, strerror(errno));
762     } else {
763         printf ("Socket: Opened in %s\n", uzbl.comm.socket_path);
764         listen (sock, 5);
765
766         if( (chan = g_io_channel_unix_new(sock)) )
767             g_io_add_watch(chan, G_IO_IN|G_IO_HUP, (GIOFunc) control_socket, chan);
768     }
769 }
770
771 static void
772 update_title (void) {
773     GString* string_long = g_string_new ("");
774     GString* string_short = g_string_new ("");
775     char* iname = NULL;
776     gchar *statln;
777     int iname_len;
778     State *s = &uzbl.state;
779
780     if(s->instance_name) {
781             iname_len = strlen(s->instance_name)+4;
782             iname = malloc(iname_len);
783             snprintf(iname, iname_len, "<%s> ", s->instance_name);
784             
785             g_string_prepend(string_long, iname);
786             g_string_prepend(string_short, iname);
787             free(iname);
788     }
789
790     g_string_append_printf(string_long, "%s ", keycmd->str);
791     if (!always_insert_mode)
792         g_string_append (string_long, (insert_mode ? "[I] " : "[C] "));
793     if (uzbl.gui.main_title) {
794         g_string_append (string_long, uzbl.gui.main_title);
795         g_string_append (string_short, uzbl.gui.main_title);
796     }
797     g_string_append (string_long, " - Uzbl browser");
798     g_string_append (string_short, " - Uzbl browser");
799     if (selected_url[0]!=0) {
800         g_string_append_printf (string_long, " -> (%s)", selected_url);
801     }
802
803     gchar* title_long = g_string_free (string_long, FALSE);
804     gchar* title_short = g_string_free (string_short, FALSE);
805
806     if (show_status) {
807         gtk_window_set_title (GTK_WINDOW(uzbl.gui.main_window), title_short);
808         statln = parse_status_template(status_format);
809         gtk_label_set_markup(GTK_LABEL(uzbl.gui.mainbar_label), statln);
810         g_free(statln);
811     } else {
812         gtk_window_set_title (GTK_WINDOW(uzbl.gui.main_window), title_long);
813     }
814
815     g_free (title_long);
816     g_free (title_short);
817 }
818
819 static gboolean
820 key_press_cb (WebKitWebView* page, GdkEventKey* event)
821 {
822     //TRUE to stop other handlers from being invoked for the event. FALSE to propagate the event further.
823
824     (void) page;
825     Action *action;
826
827     if (event->type != GDK_KEY_PRESS || event->keyval == GDK_Page_Up || event->keyval == GDK_Page_Down
828         || event->keyval == GDK_Up || event->keyval == GDK_Down || event->keyval == GDK_Left || event->keyval == GDK_Right)
829         return FALSE;
830
831     /* turn off insert mode (if always_insert_mode is not used) */
832     if (insert_mode && (event->keyval == GDK_Escape)) {
833         insert_mode = always_insert_mode;
834         update_title();
835         return TRUE;
836     }
837
838     if (insert_mode && ((event->state & modmask) != modmask))
839         return FALSE;
840
841     if (event->keyval == GDK_Escape) {
842         g_string_truncate(keycmd, 0);
843         update_title();
844         return TRUE;
845     }
846
847     //Insert without shift - insert from clipboard; Insert with shift - insert from primary
848     if (event->keyval == GDK_Insert) {
849         gchar * str;
850         if ((event->state & GDK_SHIFT_MASK) == GDK_SHIFT_MASK) {
851             str = gtk_clipboard_wait_for_text (gtk_clipboard_get (GDK_SELECTION_PRIMARY));
852         } else {
853             str = gtk_clipboard_wait_for_text (gtk_clipboard_get (GDK_SELECTION_CLIPBOARD)); 
854         }
855         if (str) {
856             g_string_append_printf (keycmd, "%s",  str);
857             update_title ();
858             free (str);
859         }
860         return TRUE;
861     }
862
863     if ((event->keyval == GDK_BackSpace) && (keycmd->len > 0)) {
864         g_string_truncate(keycmd, keycmd->len - 1);
865         update_title();
866         return TRUE;
867     }
868
869     if ((event->keyval == GDK_Return) || (event->keyval == GDK_KP_Enter)) {
870         GString* short_keys = g_string_new ("");
871         unsigned int i;
872         for (i=0; i<(keycmd->len); i++) {
873             g_string_append_c(short_keys, keycmd->str[i]);
874             g_string_append_c(short_keys, '_');
875             
876             //printf("\nTesting string: @%s@\n", short_keys->str);
877             if ((action = g_hash_table_lookup(bindings, short_keys->str))) {
878                 GString* parampart = g_string_new (keycmd->str);
879                 g_string_erase (parampart, 0, i+1);
880                 //printf("\nParameter: @%s@\n", parampart->str);
881                 GString* actionname = g_string_new ("");
882                 if (action->name)
883                     g_string_printf (actionname, action->name, parampart->str);
884                 GString* actionparam = g_string_new ("");
885                 if (action->param)
886                     g_string_printf (actionparam, action->param, parampart->str);
887                 parse_command(actionname->str, actionparam->str);
888                 g_string_free (actionname, TRUE);
889                 g_string_free (actionparam, TRUE);
890                 g_string_free (parampart, TRUE);
891                 g_string_truncate(keycmd, 0);
892                 update_title();
893             }          
894
895             g_string_truncate(short_keys, short_keys->len - 1);
896         }
897         g_string_free (short_keys, TRUE);
898         return (!insert_mode);
899     }
900
901     g_string_append(keycmd, event->string);
902     if ((action = g_hash_table_lookup(bindings, keycmd->str))) {
903         g_string_truncate(keycmd, 0);
904         parse_command(action->name, action->param);
905     }
906
907     update_title();
908
909     return TRUE;
910 }
911
912 static GtkWidget*
913 create_browser () {
914     GUI *g = &uzbl.gui;
915
916     GtkWidget* scrolled_window = gtk_scrolled_window_new (NULL, NULL);
917     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
918
919     g->web_view = WEBKIT_WEB_VIEW (webkit_web_view_new ());
920     gtk_container_add (GTK_CONTAINER (scrolled_window), GTK_WIDGET (g->web_view));
921
922     g_signal_connect (G_OBJECT (g->web_view), "title-changed", G_CALLBACK (title_change_cb), g->web_view);
923     g_signal_connect (G_OBJECT (g->web_view), "load-progress-changed", G_CALLBACK (progress_change_cb), g->web_view);
924     g_signal_connect (G_OBJECT (g->web_view), "load-committed", G_CALLBACK (load_commit_cb), g->web_view);
925     g_signal_connect (G_OBJECT (g->web_view), "load-committed", G_CALLBACK (log_history_cb), g->web_view);
926     g_signal_connect (G_OBJECT (g->web_view), "hovering-over-link", G_CALLBACK (link_hover_cb), g->web_view);
927     g_signal_connect (G_OBJECT (g->web_view), "key-press-event", G_CALLBACK (key_press_cb), g->web_view);
928     g_signal_connect (G_OBJECT (g->web_view), "new-window-policy-decision-requested", G_CALLBACK (new_window_cb), g->web_view); 
929     g_signal_connect (G_OBJECT (g->web_view), "download-requested", G_CALLBACK (download_cb), g->web_view); 
930     g_signal_connect (G_OBJECT (g->web_view), "create-web-view", G_CALLBACK (create_web_view_cb), g->web_view);  
931
932     return scrolled_window;
933 }
934
935 static GtkWidget*
936 create_mainbar () {
937     GUI *g = &uzbl.gui;
938
939     g->mainbar = gtk_hbox_new (FALSE, 0);
940     g->mainbar_label = gtk_label_new ("");  
941     gtk_label_set_ellipsize(GTK_LABEL(g->mainbar_label), PANGO_ELLIPSIZE_END);
942     gtk_misc_set_alignment (GTK_MISC(g->mainbar_label), 0, 0);
943     gtk_misc_set_padding (GTK_MISC(g->mainbar_label), 2, 2);
944     gtk_box_pack_start (GTK_BOX (g->mainbar), g->mainbar_label, TRUE, TRUE, 0);
945     return g->mainbar;
946 }
947
948 static
949 GtkWidget* create_window () {
950     GtkWidget* window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
951     gtk_window_set_default_size (GTK_WINDOW (window), 800, 600);
952     gtk_widget_set_name (window, "Uzbl browser");
953     g_signal_connect (G_OBJECT (window), "destroy", G_CALLBACK (destroy_cb), NULL);
954
955     return window;
956 }
957
958 static void
959 add_binding (const gchar *key, const gchar *act) {
960     char **parts = g_strsplit(act, " ", 2);
961     Action *action;
962
963     if (!parts)
964         return;
965
966     //Debug:
967     printf ("Binding %-10s : %s\n", key, act);
968     action = new_action(parts[0], parts[1]);
969     g_hash_table_insert(bindings, g_strdup(key), action);
970
971     g_strfreev(parts);
972 }
973
974 static void
975 settings_init () {
976     GKeyFile* config;
977     gboolean res  = FALSE;
978     char *saveptr;
979     gchar** keys = NULL;
980     State *s = &uzbl.state;
981     Network *n = &uzbl.net;
982
983     if (!s->config_file) {
984         const char* XDG_CONFIG_HOME = getenv ("XDG_CONFIG_HOME");
985         if (! XDG_CONFIG_HOME || ! strcmp (XDG_CONFIG_HOME, "")) {
986           XDG_CONFIG_HOME = (char*)XDG_CONFIG_HOME_default;
987         }
988         printf("XDG_CONFIG_HOME: %s\n", XDG_CONFIG_HOME);
989     
990         strcpy (s->config_file_path, XDG_CONFIG_HOME);
991         strcat (s->config_file_path, "/uzbl/config");
992         if (file_exists (s->config_file_path)) {
993           printf ("Config file %s found.\n", s->config_file_path);
994           s->config_file = &s->config_file_path[0];
995         } else {
996             // Now we check $XDG_CONFIG_DIRS
997             char *XDG_CONFIG_DIRS = getenv ("XDG_CONFIG_DIRS");
998             if (! XDG_CONFIG_DIRS || ! strcmp (XDG_CONFIG_DIRS, ""))
999                 XDG_CONFIG_DIRS = XDG_CONFIG_DIRS_default;
1000
1001             printf("XDG_CONFIG_DIRS: %s\n", XDG_CONFIG_DIRS);
1002
1003             char buffer[512];
1004             strcpy (buffer, XDG_CONFIG_DIRS);
1005             const gchar* dir = (char *) strtok_r (buffer, ":", &saveptr);
1006             while (dir && ! file_exists (s->config_file_path)) {
1007                 strcpy (s->config_file_path, dir);
1008                 strcat (s->config_file_path, "/uzbl/config_file_pathig");
1009                 if (file_exists (s->config_file_path)) {
1010                     printf ("Config file %s found.\n", s->config_file_path);
1011                     s->config_file = &s->config_file_path[0];
1012                 }
1013                 dir = (char * ) strtok_r (NULL, ":", &saveptr);
1014             }
1015         }
1016     }
1017
1018     if (s->config_file) {
1019         config = g_key_file_new ();
1020         res = g_key_file_load_from_file (config, s->config_file, G_KEY_FILE_NONE, NULL);
1021           if (res) {
1022             printf ("Config %s loaded\n", s->config_file);
1023           } else {
1024             fprintf (stderr, "Config %s loading failed\n", s->config_file);
1025         }
1026     } else {
1027         printf ("No configuration.\n");
1028     }
1029
1030     if (res) {
1031         history_handler    = g_key_file_get_value   (config, "behavior", "history_handler",    NULL);
1032         download_handler   = g_key_file_get_value   (config, "behavior", "download_handler",   NULL);
1033         always_insert_mode = g_key_file_get_boolean (config, "behavior", "always_insert_mode", NULL);
1034         show_status        = g_key_file_get_boolean (config, "behavior", "show_status",        NULL);
1035         modkey             = g_key_file_get_value   (config, "behavior", "modkey",             NULL);
1036         status_top         = g_key_file_get_boolean (config, "behavior", "status_top",         NULL);
1037         if (! fifo_dir)
1038             fifo_dir        = g_key_file_get_value  (config, "behavior", "fifo_dir",           NULL);
1039         if (! socket_dir)
1040             socket_dir     = g_key_file_get_value   (config, "behavior", "socket_dir",         NULL);
1041         keys               = g_key_file_get_keys    (config, "bindings", NULL,                 NULL);
1042     }
1043
1044     printf ("History handler: %s\n",    (history_handler    ? history_handler  : "disabled"));
1045     printf ("Download manager: %s\n",   (download_handler   ? download_handler : "disabled"));
1046     printf ("Fifo directory: %s\n",     (fifo_dir           ? fifo_dir         : "disabled"));
1047     printf ("Socket directory: %s\n",   (socket_dir         ? socket_dir       : "disabled"));
1048     printf ("Always insert mode: %s\n", (always_insert_mode ? "TRUE"           : "FALSE"));
1049     printf ("Show status: %s\n",        (show_status        ? "TRUE"           : "FALSE"));
1050     printf ("Status top: %s\n",         (status_top         ? "TRUE"           : "FALSE"));
1051     printf ("Modkey: %s\n",             (modkey             ? modkey           : "disabled"));
1052
1053     if (! modkey)
1054         modkey = "";
1055
1056     //POSSIBLE MODKEY VALUES (COMBINATIONS CAN BE USED)
1057     gchar* modkeyup = g_utf8_strup (modkey, -1);
1058     if (g_strrstr (modkeyup,"SHIFT") != NULL)    modmask |= GDK_SHIFT_MASK;    //the Shift key.
1059     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).
1060     if (g_strrstr (modkeyup,"CONTROL") != NULL)  modmask |= GDK_CONTROL_MASK;  //the Control key.
1061     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).
1062     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).
1063     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).
1064     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).
1065     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).
1066     if (g_strrstr (modkeyup,"BUTTON1") != NULL)  modmask |= GDK_BUTTON1_MASK;  //the first mouse button.
1067     if (g_strrstr (modkeyup,"BUTTON2") != NULL)  modmask |= GDK_BUTTON2_MASK;  //the second mouse button.
1068     if (g_strrstr (modkeyup,"BUTTON3") != NULL)  modmask |= GDK_BUTTON3_MASK;  //the third mouse button.
1069     if (g_strrstr (modkeyup,"BUTTON4") != NULL)  modmask |= GDK_BUTTON4_MASK;  //the fourth mouse button.
1070     if (g_strrstr (modkeyup,"BUTTON5") != NULL)  modmask |= GDK_BUTTON5_MASK;  //the fifth mouse button.
1071     if (g_strrstr (modkeyup,"SUPER") != NULL)    modmask |= GDK_SUPER_MASK;    //the Super modifier. Since 2.10
1072     if (g_strrstr (modkeyup,"HYPER") != NULL)    modmask |= GDK_HYPER_MASK;    //the Hyper modifier. Since 2.10
1073     if (g_strrstr (modkeyup,"META") != NULL)     modmask |= GDK_META_MASK;     //the Meta modifier. Since 2.10  */
1074     free (modkeyup);
1075
1076     if (keys) {
1077         int i;
1078         for (i = 0; keys[i]; i++) {
1079             gchar *value = g_key_file_get_string (config, "bindings", keys[i], NULL);
1080             
1081             add_binding(g_strstrip(keys[i]), value);
1082             g_free(value);
1083         }
1084
1085         g_strfreev(keys);
1086     }
1087
1088     /* networking options */
1089     if (res) {
1090         n->proxy_url      = g_key_file_get_value   (config, "network", "proxy_server",       NULL);
1091         http_debug     = g_key_file_get_integer (config, "network", "http_debug",         NULL);
1092         n->useragent      = g_key_file_get_value   (config, "network", "user-agent",         NULL);
1093         n->max_conns      = g_key_file_get_integer (config, "network", "max_conns",          NULL);
1094         n->max_conns_host = g_key_file_get_integer (config, "network", "max_conns_per_host", NULL);
1095     }
1096
1097     if(n->proxy_url){
1098         g_object_set(G_OBJECT(n->soup_session), SOUP_SESSION_PROXY_URI, soup_uri_new(n->proxy_url), NULL);
1099     }
1100         
1101     if(!(http_debug <= 3)){
1102         http_debug = 0;
1103         fprintf(stderr, "Wrong http_debug level, ignoring.\n");
1104     } else if (http_debug > 0) {
1105         n->soup_logger = soup_logger_new(http_debug, -1);
1106         soup_session_add_feature(n->soup_session, SOUP_SESSION_FEATURE(n->soup_logger));
1107     }
1108         
1109     if(n->useragent){
1110         char* newagent  = malloc(1024);
1111
1112         strcpy(newagent, str_replace("%webkit-major%", itos(WEBKIT_MAJOR_VERSION), n->useragent));
1113         strcpy(newagent, str_replace("%webkit-minor%", itos(WEBKIT_MINOR_VERSION), newagent));
1114         strcpy(newagent, str_replace("%webkit-micro%", itos(WEBKIT_MICRO_VERSION), newagent));
1115
1116         if (uname (&unameinfo) == -1) {
1117             printf("Error getting uname info. Not replacing system-related user agent variables.\n");
1118         } else {
1119             strcpy(newagent, str_replace("%sysname%",     unameinfo.sysname, newagent));
1120             strcpy(newagent, str_replace("%nodename%",    unameinfo.nodename, newagent));
1121             strcpy(newagent, str_replace("%kernrel%",     unameinfo.release, newagent));
1122             strcpy(newagent, str_replace("%kernver%",     unameinfo.version, newagent));
1123             strcpy(newagent, str_replace("%arch-system%", unameinfo.machine, newagent));
1124
1125             #ifdef _GNU_SOURCE
1126                 strcpy(newagent, str_replace("%domainname%", unameinfo.domainname, newagent));
1127             #endif
1128         }
1129
1130         strcpy(newagent, str_replace("%arch-uzbl%",    ARCH,                       newagent));
1131         strcpy(newagent, str_replace("%commit%",       COMMIT,                     newagent));
1132
1133         n->useragent = malloc(1024);
1134         strcpy(n->useragent, newagent);
1135         g_object_set(G_OBJECT(n->soup_session), SOUP_SESSION_USER_AGENT, n->useragent, NULL);
1136     }
1137
1138     if(n->max_conns >= 1){
1139         g_object_set(G_OBJECT(n->soup_session), SOUP_SESSION_MAX_CONNS, n->max_conns, NULL);
1140     }
1141
1142     if(n->max_conns_host >= 1){
1143         g_object_set(G_OBJECT(n->soup_session), SOUP_SESSION_MAX_CONNS_PER_HOST, n->max_conns_host, NULL);
1144     }
1145
1146     printf("Proxy configured: %s\n", n->proxy_url ? n->proxy_url : "none");
1147     printf("HTTP logging level: %d\n", http_debug);
1148     printf("User-agent: %s\n", n->useragent? n->useragent : "default");
1149     printf("Maximum connections: %d\n", n->max_conns ? n->max_conns : 0);
1150     printf("Maximum connections per host: %d\n", n->max_conns_host ? n->max_conns_host: 0);
1151                 
1152 }
1153
1154 int
1155 main (int argc, char* argv[]) {
1156     gtk_init (&argc, &argv);
1157     if (!g_thread_supported ())
1158         g_thread_init (NULL);
1159
1160     printf("Uzbl start location: %s\n", argv[0]);
1161     strcpy(executable_path,argv[0]);
1162
1163     strcat ((char *) XDG_CONFIG_HOME_default, getenv ("HOME"));
1164     strcat ((char *) XDG_CONFIG_HOME_default, "/.config");
1165
1166     GError *error = NULL;
1167     GOptionContext* context = g_option_context_new ("- some stuff here maybe someday");
1168     g_option_context_add_main_entries (context, entries, NULL);
1169     g_option_context_add_group (context, gtk_get_option_group (TRUE));
1170     g_option_context_parse (context, &argc, &argv, &error);
1171     /* initialize hash table */
1172     bindings = g_hash_table_new_full(g_str_hash, g_str_equal, g_free, free_action);
1173         
1174         uzbl.net.soup_session = webkit_get_default_session();
1175     keycmd = g_string_new("");
1176
1177     settings_init ();
1178     commands_hash ();
1179
1180     if (always_insert_mode)
1181         insert_mode = TRUE;
1182
1183     GtkWidget* vbox = gtk_vbox_new (FALSE, 0);
1184     if (status_top)
1185         gtk_box_pack_start (GTK_BOX (vbox), create_mainbar (), FALSE, TRUE, 0);
1186     gtk_box_pack_start (GTK_BOX (vbox), create_browser (), TRUE, TRUE, 0);
1187     if (!status_top)
1188         gtk_box_pack_start (GTK_BOX (vbox), create_mainbar (), FALSE, TRUE, 0);
1189
1190     uzbl.gui.main_window = create_window ();
1191     gtk_container_add (GTK_CONTAINER (uzbl.gui.main_window), vbox);
1192
1193     load_uri (uzbl.gui.web_view, uzbl.state.uri);
1194
1195     gtk_widget_grab_focus (GTK_WIDGET (uzbl.gui.web_view));
1196     gtk_widget_show_all (uzbl.gui.main_window);
1197     uzbl.xwin = GDK_WINDOW_XID (GTK_WIDGET (uzbl.gui.main_window)->window);
1198     printf("window_id %i\n",(int) uzbl.xwin);
1199     printf("pid %i\n", getpid ());
1200     printf("name: %s\n", uzbl.state.instance_name);
1201
1202     uzbl.gui.scbar_v = (GtkScrollbar*) gtk_vscrollbar_new (NULL);
1203     uzbl.gui.bar_v = gtk_range_get_adjustment((GtkRange*) uzbl.gui.scbar_v);
1204     uzbl.gui.scbar_h = (GtkScrollbar*) gtk_hscrollbar_new (NULL);
1205     uzbl.gui.bar_h = gtk_range_get_adjustment((GtkRange*) uzbl.gui.scbar_h);
1206     gtk_widget_set_scroll_adjustments ((GtkWidget*) uzbl.gui.web_view, uzbl.gui.bar_h, uzbl.gui.bar_v);
1207
1208
1209     if (!show_status)
1210         gtk_widget_hide(uzbl.gui.mainbar);
1211     setup_scanner();
1212
1213     if (fifo_dir)
1214         create_fifo ();
1215     if (socket_dir)
1216         create_socket();
1217
1218     gtk_main ();
1219
1220     g_string_free(keycmd, TRUE);
1221
1222     if (fifo_dir)
1223         unlink (uzbl.comm.fifo_path);
1224     if (socket_dir)
1225         unlink (uzbl.comm.socket_path);
1226
1227     g_hash_table_destroy(bindings);
1228     g_hash_table_destroy(commands);
1229     return 0;
1230 }
1231
1232 /* vi: set et ts=4: */