todo updates
[uzbl-00z.git] / uzbl.c
blob5a1203b04c446db26a66c0e8fc5032186571d275
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.
6 /*
7 * Copyright (C) 2006, 2007 Apple Inc.
8 * Copyright (C) 2007 Alp Toker <alp@atoker.com>
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.
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.
33 #define LENGTH(x) (sizeof x / sizeof x[0])
34 #define MAX_BINDINGS 256
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 <signal.h>
56 #include "uzbl.h"
59 static Uzbl uzbl;
61 /* define names and pointers to all config specific variables */
62 const struct {
63 char *name;
64 void **ptr;
65 } var_name_to_ptr[] = {
66 // Already working commands
67 { "uri", (void *)&uzbl.state.uri },
68 { "status_format", (void *)&uzbl.behave.status_format },
69 { "status_background", (void *)&uzbl.behave.status_background },
70 { "status_message", (void *)&uzbl.gui.sbar.msg },
71 { "show_status", (void *)&uzbl.behave.show_status },
72 { "insert_mode", (void *)&uzbl.behave.insert_mode },
73 { "proxy_url", (void *)&uzbl.net.proxy_url },
74 // TODO: write cmd handlers for the following
75 { "useragent", (void *)&uzbl.net.useragent },
76 { "max_conns", (void *)&uzbl.net.max_conns },
77 { "max_conns_host", (void *)&uzbl.net.max_conns_host },
78 { "http_debug", (void *)&uzbl.behave.http_debug },
79 { NULL, NULL }
80 }, *n2v_p = var_name_to_ptr;
82 /* construct a hash from the var_name_to_ptr array for quick access */
83 static void
84 make_var_to_name_hash() {
85 uzbl.comm.proto_var = g_hash_table_new(g_str_hash, g_str_equal);
86 while(n2v_p->name) {
87 g_hash_table_insert(uzbl.comm.proto_var, n2v_p->name, n2v_p->ptr);
88 n2v_p++;
92 /* commandline arguments (set initial values for the state variables) */
93 static GOptionEntry entries[] =
95 { "uri", 'u', 0, G_OPTION_ARG_STRING, &uzbl.state.uri, "Uri to load", "URI" },
96 { "name", 'n', 0, G_OPTION_ARG_STRING, &uzbl.state.instance_name, "Name of the current instance", "NAME" },
97 { "config", 'c', 0, G_OPTION_ARG_STRING, &uzbl.state.config_file, "Config file", "FILE" },
98 { NULL, 0, 0, 0, NULL, NULL, NULL }
101 typedef void (*Command)(WebKitWebView*, const char *);
103 /* XDG stuff */
104 static char *XDG_CONFIG_HOME_default[256];
105 static char *XDG_CONFIG_DIRS_default = "/etc/xdg";
108 /* --- UTILITY FUNCTIONS --- */
110 char *
111 itos(int val) {
112 char tmp[20];
114 snprintf(tmp, sizeof(tmp), "%i", val);
115 return g_strdup(tmp);
118 static char *
119 str_replace (const char* search, const char* replace, const char* string) {
120 return g_strjoinv (replace, g_strsplit(string, search, -1));
123 static sigfunc*
124 setup_signal(int signr, sigfunc *shandler) {
125 struct sigaction nh, oh;
127 nh.sa_handler = shandler;
128 sigemptyset(&nh.sa_mask);
129 nh.sa_flags = 0;
131 if(sigaction(signr, &nh, &oh) < 0)
132 return SIG_ERR;
134 return NULL;
137 static void
138 clean_up(void) {
139 if (uzbl.behave.fifo_dir)
140 unlink (uzbl.comm.fifo_path);
141 if (uzbl.behave.socket_dir)
142 unlink (uzbl.comm.socket_path);
144 g_string_free(uzbl.state.keycmd, TRUE);
145 g_hash_table_destroy(uzbl.bindings);
146 g_hash_table_destroy(uzbl.behave.commands);
150 /* --- SIGNAL HANDLER --- */
152 static void
153 catch_sigterm(int s) {
154 (void) s;
155 clean_up();
158 /* --- CALLBACKS --- */
160 static gboolean
161 new_window_cb (WebKitWebView *web_view, WebKitWebFrame *frame, WebKitNetworkRequest *request, WebKitWebNavigationAction *navigation_action, WebKitWebPolicyDecision *policy_decision, gpointer user_data) {
162 (void) web_view;
163 (void) frame;
164 (void) navigation_action;
165 (void) policy_decision;
166 (void) user_data;
167 const gchar* uri = webkit_network_request_get_uri (request);
168 printf("New window requested -> %s \n", uri);
169 new_window_load_uri(uri);
170 return (FALSE);
173 WebKitWebView*
174 create_web_view_cb (WebKitWebView *web_view, WebKitWebFrame *frame, gpointer user_data) {
175 (void) web_view;
176 (void) frame;
177 (void) user_data;
178 if (uzbl.state.selected_url[0]!=0) {
179 printf("\nNew web view -> %s\n",uzbl.state.selected_url);
180 new_window_load_uri(uzbl.state.selected_url);
181 } else {
182 printf("New web view -> %s\n","Nothing to open, exiting");
184 return (NULL);
187 static gboolean
188 download_cb (WebKitWebView *web_view, GObject *download, gpointer user_data) {
189 (void) web_view;
190 (void) user_data;
191 if (uzbl.behave.download_handler) {
192 const gchar* uri = webkit_download_get_uri ((WebKitDownload*)download);
193 printf("Download -> %s\n",uri);
194 run_command_async(uzbl.behave.download_handler, uri);
196 return (FALSE);
199 /* scroll a bar in a given direction */
200 static void
201 scroll (GtkAdjustment* bar, const char *param) {
202 gdouble amount;
203 gchar *end;
205 amount = g_ascii_strtod(param, &end);
207 if (*end)
208 fprintf(stderr, "found something after double: %s\n", end);
210 gtk_adjustment_set_value (bar, gtk_adjustment_get_value(bar)+amount);
213 static void scroll_vert(WebKitWebView* page, const char *param) {
214 (void) page;
216 scroll(uzbl.gui.bar_v, param);
219 static void scroll_horz(WebKitWebView* page, const char *param) {
220 (void) page;
222 scroll(uzbl.gui.bar_h, param);
225 static void
226 cmd_set_status() {
227 if (!uzbl.behave.show_status) {
228 gtk_widget_hide(uzbl.gui.mainbar);
229 } else {
230 gtk_widget_show(uzbl.gui.mainbar);
232 update_title();
235 static void
236 toggle_status_cb (WebKitWebView* page, const char *param) {
237 (void)page;
238 (void)param;
240 if (uzbl.behave.show_status) {
241 gtk_widget_hide(uzbl.gui.mainbar);
242 } else {
243 gtk_widget_show(uzbl.gui.mainbar);
245 uzbl.behave.show_status = !uzbl.behave.show_status;
246 update_title();
249 static void
250 link_hover_cb (WebKitWebView* page, const gchar* title, const gchar* link, gpointer data) {
251 (void) page;
252 (void) title;
253 (void) data;
254 //ADD HOVER URL TO WINDOW TITLE
255 uzbl.state.selected_url[0] = '\0';
256 if (link) {
257 strcpy (uzbl.state.selected_url, link);
259 update_title();
262 static void
263 title_change_cb (WebKitWebView* web_view, WebKitWebFrame* web_frame, const gchar* title, gpointer data) {
264 (void) web_view;
265 (void) web_frame;
266 (void) data;
267 if (uzbl.gui.main_title)
268 g_free (uzbl.gui.main_title);
269 uzbl.gui.main_title = g_strdup (title);
270 update_title();
273 static void
274 progress_change_cb (WebKitWebView* page, gint progress, gpointer data) {
275 (void) page;
276 (void) data;
277 uzbl.gui.sbar.load_progress = progress;
278 update_title();
281 static void
282 load_commit_cb (WebKitWebView* page, WebKitWebFrame* frame, gpointer data) {
283 (void) page;
284 (void) data;
285 free (uzbl.state.uri);
286 GString* newuri = g_string_new (webkit_web_frame_get_uri (frame));
287 uzbl.state.uri = g_string_free (newuri, FALSE);
290 static void
291 destroy_cb (GtkWidget* widget, gpointer data) {
292 (void) widget;
293 (void) data;
294 gtk_main_quit ();
297 static void
298 log_history_cb () {
299 if (uzbl.behave.history_handler) {
300 time_t rawtime;
301 struct tm * timeinfo;
302 char date [80];
303 time ( &rawtime );
304 timeinfo = localtime ( &rawtime );
305 strftime (date, 80, "%Y-%m-%d %H:%M:%S", timeinfo);
306 GString* args = g_string_new ("");
307 g_string_printf (args, "'%s'", date);
308 run_command_async(uzbl.behave.history_handler, args->str);
309 g_string_free (args, TRUE);
314 /* VIEW funcs (little webkit wrappers) */
315 #define VIEWFUNC(name) static void view_##name(WebKitWebView *page, const char *param){(void)param; webkit_web_view_##name(page);}
316 VIEWFUNC(reload)
317 VIEWFUNC(reload_bypass_cache)
318 VIEWFUNC(stop_loading)
319 VIEWFUNC(zoom_in)
320 VIEWFUNC(zoom_out)
321 VIEWFUNC(go_back)
322 VIEWFUNC(go_forward)
323 #undef VIEWFUNC
325 /* -- command to callback/function map for things we cannot attach to any signals */
326 // TODO: reload
328 static struct {char *name; Command command;} cmdlist[] =
330 { "back", view_go_back },
331 { "forward", view_go_forward },
332 { "scroll_vert", scroll_vert },
333 { "scroll_horz", scroll_horz },
334 { "reload", view_reload, },
335 { "reload_ign_cache", view_reload_bypass_cache},
336 { "stop", view_stop_loading, },
337 { "zoom_in", view_zoom_in, }, //Can crash (when max zoom reached?).
338 { "zoom_out", view_zoom_out, },
339 { "uri", load_uri },
340 { "script", run_js },
341 { "toggle_status", toggle_status_cb },
342 { "spawn", spawn },
343 { "exit", close_uzbl },
344 { "search", search_text },
345 { "insert_mode", set_insert_mode }
348 static void
349 commands_hash(void)
351 unsigned int i;
352 uzbl.behave.commands = g_hash_table_new(g_str_hash, g_str_equal);
354 for (i = 0; i < LENGTH(cmdlist); i++)
355 g_hash_table_insert(uzbl.behave.commands, cmdlist[i].name, cmdlist[i].command);
358 /* -- CORE FUNCTIONS -- */
360 void
361 free_action(gpointer act) {
362 Action *action = (Action*)act;
363 g_free(action->name);
364 if (action->param)
365 g_free(action->param);
366 g_free(action);
369 Action*
370 new_action(const gchar *name, const gchar *param) {
371 Action *action = g_new(Action, 1);
373 action->name = g_strdup(name);
374 if (param)
375 action->param = g_strdup(param);
376 else
377 action->param = NULL;
379 return action;
382 static bool
383 file_exists (const char * filename) {
384 FILE *file = fopen (filename, "r");
385 if (file) {
386 fclose (file);
387 return true;
389 return false;
392 void
393 set_insert_mode(WebKitWebView *page, const gchar *param) {
394 (void)page;
395 (void)param;
397 uzbl.behave.insert_mode = TRUE;
398 update_title();
401 static void
402 load_uri (WebKitWebView * web_view, const gchar *param) {
403 if (param) {
404 GString* newuri = g_string_new (param);
405 if (g_strrstr (param, "://") == NULL)
406 g_string_prepend (newuri, "http://");
407 /* if we do handle cookies, ask our handler for them */
408 webkit_web_view_load_uri (web_view, newuri->str);
409 g_string_free (newuri, TRUE);
413 static void
414 run_js (WebKitWebView * web_view, const gchar *param) {
415 if (param)
416 webkit_web_view_execute_script (web_view, param);
419 static void
420 search_text (WebKitWebView *page, const char *param) {
421 if ((param) && (param[0] != '\0')) {
422 strcpy(uzbl.state.searchtx, param);
424 if (uzbl.state.searchtx[0] != '\0') {
425 printf ("Searching: %s\n", uzbl.state.searchtx);
426 webkit_web_view_unmark_text_matches (page);
427 webkit_web_view_mark_text_matches (page, uzbl.state.searchtx, FALSE, 0);
428 webkit_web_view_set_highlight_text_matches (page, TRUE);
429 webkit_web_view_search_text (page, uzbl.state.searchtx, FALSE, TRUE, TRUE);
433 static void
434 new_window_load_uri (const gchar * uri) {
435 GString* to_execute = g_string_new ("");
436 g_string_append_printf (to_execute, "%s --uri '%s'", uzbl.state.executable_path, uri);
437 int i;
438 for (i = 0; entries[i].long_name != NULL; i++) {
439 if ((entries[i].arg == G_OPTION_ARG_STRING) && (strcmp(entries[i].long_name,"uri")!=0)) {
440 gchar** str = (gchar**)entries[i].arg_data;
441 if (*str!=NULL) {
442 g_string_append_printf (to_execute, " --%s '%s'", entries[i].long_name, *str);
446 printf("\n%s\n", to_execute->str);
447 g_spawn_command_line_async (to_execute->str, NULL);
448 g_string_free (to_execute, TRUE);
451 static void
452 close_uzbl (WebKitWebView *page, const char *param) {
453 (void)page;
454 (void)param;
455 gtk_main_quit ();
458 /* --Statusbar functions-- */
459 static char*
460 build_progressbar_ascii(int percent) {
461 int width=10;
462 int i;
463 double l;
464 GString *bar = g_string_new("");
466 l = (double)percent*((double)width/100.);
467 l = (int)(l+.5)>=(int)l ? l+.5 : l;
469 g_string_append(bar, "[");
470 for(i=0; i<(int)l; i++)
471 g_string_append(bar, "=");
473 for(; i<width; i++)
474 g_string_append(bar, "·");
475 g_string_append(bar, "]");
477 return g_string_free(bar, FALSE);
480 static void
481 setup_scanner() {
482 const GScannerConfig scan_config = {
484 "\t\r\n"
485 ) /* cset_skip_characters */,
487 G_CSET_a_2_z
488 "_#"
489 G_CSET_A_2_Z
490 ) /* cset_identifier_first */,
492 G_CSET_a_2_z
493 "_0123456789"
494 G_CSET_A_2_Z
495 G_CSET_LATINS
496 G_CSET_LATINC
497 ) /* cset_identifier_nth */,
498 ( "" ) /* cpair_comment_single */,
500 TRUE /* case_sensitive */,
502 FALSE /* skip_comment_multi */,
503 FALSE /* skip_comment_single */,
504 FALSE /* scan_comment_multi */,
505 TRUE /* scan_identifier */,
506 TRUE /* scan_identifier_1char */,
507 FALSE /* scan_identifier_NULL */,
508 TRUE /* scan_symbols */,
509 FALSE /* scan_binary */,
510 FALSE /* scan_octal */,
511 FALSE /* scan_float */,
512 FALSE /* scan_hex */,
513 FALSE /* scan_hex_dollar */,
514 FALSE /* scan_string_sq */,
515 FALSE /* scan_string_dq */,
516 TRUE /* numbers_2_int */,
517 FALSE /* int_2_float */,
518 FALSE /* identifier_2_string */,
519 FALSE /* char_2_token */,
520 FALSE /* symbol_2_token */,
521 TRUE /* scope_0_fallback */,
522 FALSE,
523 TRUE
526 uzbl.scan = g_scanner_new(&scan_config);
527 while(symp->symbol_name) {
528 g_scanner_scope_add_symbol(uzbl.scan, 0,
529 symp->symbol_name,
530 GINT_TO_POINTER(symp->symbol_token));
531 symp++;
535 static gchar *
536 parse_status_template(const char *template) {
537 GTokenType token = G_TOKEN_NONE;
538 GString *ret = g_string_new("");
539 gchar *buf=NULL;
540 int sym;
542 if(!template)
543 return NULL;
545 g_scanner_input_text(uzbl.scan, template, strlen(template));
546 while(!g_scanner_eof(uzbl.scan) && token != G_TOKEN_LAST) {
547 token = g_scanner_get_next_token(uzbl.scan);
549 if(token == G_TOKEN_SYMBOL) {
550 sym = (int)g_scanner_cur_value(uzbl.scan).v_symbol;
551 switch(sym) {
552 case SYM_URI:
553 g_string_append(ret,
554 uzbl.state.uri?
555 g_markup_printf_escaped("%s", uzbl.state.uri):"");
556 break;
557 case SYM_LOADPRGS:
558 g_string_append(ret, itos(uzbl.gui.sbar.load_progress));
559 break;
560 case SYM_LOADPRGSBAR:
561 buf = build_progressbar_ascii(uzbl.gui.sbar.load_progress);
562 g_string_append(ret, buf);
563 g_free(buf);
564 break;
565 case SYM_TITLE:
566 g_string_append(ret,
567 uzbl.gui.main_title?
568 g_markup_printf_escaped("%s", uzbl.gui.main_title):"");
569 break;
570 case SYM_NAME:
571 g_string_append(ret,
572 uzbl.state.instance_name?uzbl.state.instance_name:itos(uzbl.xwin));
573 break;
574 case SYM_KEYCMD:
575 g_string_append(ret,
576 uzbl.state.keycmd->str ?
577 g_markup_printf_escaped("%s", uzbl.state.keycmd->str):"");
578 break;
579 case SYM_MODE:
580 g_string_append(ret,
581 uzbl.behave.insert_mode?"[I]":"[C]");
582 break;
583 case SYM_MSG:
584 g_string_append(ret,
585 uzbl.gui.sbar.msg?uzbl.gui.sbar.msg:"");
586 break;
587 default:
588 break;
591 else if(token == G_TOKEN_INT) {
592 g_string_append(ret, itos(g_scanner_cur_value(uzbl.scan).v_int));
594 else if(token == G_TOKEN_IDENTIFIER) {
595 g_string_append(ret, (gchar *)g_scanner_cur_value(uzbl.scan).v_identifier);
597 else if(token == G_TOKEN_CHAR) {
598 g_string_append_c(ret, (gchar)g_scanner_cur_value(uzbl.scan).v_char);
602 return g_string_free(ret, FALSE);
604 /* --End Statusbar functions-- */
607 // make sure to put '' around args, so that if there is whitespace we can still keep arguments together.
608 static gboolean
609 run_command_async(const char *command, const char *args) {
610 //command <uzbl conf> <uzbl pid> <uzbl win id> <uzbl fifo file> <uzbl socket file> [args]
611 GString* to_execute = g_string_new ("");
612 gboolean result;
613 g_string_printf (to_execute, "%s '%s' '%i' '%i' '%s' '%s'",
614 command, uzbl.state.config_file, (int) getpid() ,
615 (int) uzbl.xwin, uzbl.comm.fifo_path, uzbl.comm.socket_path);
616 g_string_append_printf (to_execute, " '%s' '%s'",
617 uzbl.state.uri, "TODO title here");
618 if(args) {
619 g_string_append_printf (to_execute, " %s", args);
621 result = g_spawn_command_line_async (to_execute->str, NULL);
622 printf("Called %s. Result: %s\n", to_execute->str, (result ? "TRUE" : "FALSE" ));
623 g_string_free (to_execute, TRUE);
624 return result;
627 static gboolean
628 run_command_sync(const char *command, const char *args, char **stdout) {
629 //command <uzbl conf> <uzbl pid> <uzbl win id> <uzbl fifo file> <uzbl socket file> [args]
630 GString* to_execute = g_string_new ("");
631 gboolean result;
632 g_string_printf (to_execute, "%s '%s' '%i' '%i' '%s' '%s'", command, uzbl.state.config_file, (int) getpid() , (int) uzbl.xwin, uzbl.comm.fifo_path, uzbl.comm.socket_path);
633 g_string_append_printf (to_execute, " '%s' '%s'", uzbl.state.uri, "TODO title here");
634 if(args) {
635 g_string_append_printf (to_execute, " %s", args);
637 result = g_spawn_command_line_sync (to_execute->str, stdout, NULL, NULL, NULL);
638 printf("Called %s. Result: %s\n", to_execute->str, (result ? "TRUE" : "FALSE" ));
639 g_string_free (to_execute, TRUE);
640 return result;
643 static void
644 spawn(WebKitWebView *web_view, const char *param) {
645 (void)web_view;
646 run_command_async(param, NULL);
649 static void
650 parse_command(const char *cmd, const char *param) {
651 Command c;
653 if ((c = g_hash_table_lookup(uzbl.behave.commands, cmd)))
654 c(uzbl.gui.web_view, param);
655 else
656 fprintf (stderr, "command \"%s\" not understood. ignoring.\n", cmd);
659 /* command parser */
660 static void
661 setup_regex() {
662 GError *err=NULL;
664 uzbl.comm.get_regex = g_regex_new("^[Gg][a-zA-Z]*\\s+([^ \\n]+)$",
665 G_REGEX_OPTIMIZE, 0, &err);
666 uzbl.comm.set_regex = g_regex_new("^[Ss][a-zA-Z]*\\s+([^ ]+)\\s*=\\s*([^\\n].*)$",
667 G_REGEX_OPTIMIZE, 0, &err);
668 uzbl.comm.bind_regex = g_regex_new("^[Bb][a-zA-Z]*\\s+?(.*[^ ])\\s*?=\\s*([a-z][^\\n].+)$",
669 G_REGEX_UNGREEDY|G_REGEX_OPTIMIZE, 0, &err);
672 static gboolean
673 get_var_value(gchar *name) {
674 void **p = NULL;
676 if( (p = g_hash_table_lookup(uzbl.comm.proto_var, name)) ) {
677 if(!strcmp(name, "status_format")) {
678 printf("VAR: %s VALUE: %s\n", name, (char *)*p);
679 } else {
680 printf("VAR: %s VALUE: %d\n", name, (int)*p);
683 return TRUE;
686 static void
687 set_proxy_url() {
688 SoupURI *suri;
690 if(*uzbl.net.proxy_url == ' '
691 || uzbl.net.proxy_url == NULL) {
692 soup_session_remove_feature_by_type(uzbl.net.soup_session,
693 (GType) SOUP_SESSION_PROXY_URI);
695 else {
696 suri = soup_uri_new(uzbl.net.proxy_url);
697 g_object_set(G_OBJECT(uzbl.net.soup_session),
698 SOUP_SESSION_PROXY_URI,
699 suri, NULL);
700 soup_uri_free(suri);
702 return;
705 static gboolean
706 var_is(const char *x, const char *y) {
707 gboolean ret = FALSE;
709 if(!strcmp(x, y))
710 ret = TRUE;
712 return ret;
715 static gboolean
716 set_var_value(gchar *name, gchar *val) {
717 void **p = NULL;
718 char *endp = NULL;
720 if( (p = g_hash_table_lookup(uzbl.comm.proto_var, name)) ) {
721 if(var_is("status_message", name)
722 || var_is("status_background", name)
723 || var_is("status_format", name)) {
724 if(*p)
725 free(*p);
726 *p = g_strdup(val);
727 update_title();
729 else if(var_is("uri", name)) {
730 if(*p)
731 free(*p);
732 *p = g_strdup(val);
733 load_uri(uzbl.gui.web_view, (const gchar*)*p);
735 else if(var_is("proxy_url", name)) {
736 if(*p)
737 free(*p);
738 *p = g_strdup(val);
739 set_proxy_url();
741 /* variables that take int values */
742 else {
743 *p = (int)strtoul(val, &endp, 10);
745 if(var_is("show_status", name)) {
746 cmd_set_status();
750 return TRUE;
754 static void
755 parse_cmd_line(char *ctl_line) {
756 gchar **tokens;
758 /* SET command */
759 if(ctl_line[0] == 's' || ctl_line[0] == 'S') {
760 tokens = g_regex_split(uzbl.comm.set_regex, ctl_line, 0);
761 if(tokens[0][0] == 0) {
762 set_var_value(tokens[1], tokens[2]);
763 g_strfreev(tokens);
765 else
766 printf("Error in command: %s\n", tokens[0]);
768 /* GET command */
769 else if(ctl_line[0] == 'g' || ctl_line[0] == 'G') {
770 tokens = g_regex_split(uzbl.comm.get_regex, ctl_line, 0);
771 if(tokens[0][0] == 0) {
772 get_var_value(tokens[1]);
773 g_strfreev(tokens);
775 else
776 printf("Error in command: %s\n", tokens[0]);
778 /* BIND command */
779 else if(ctl_line[0] == 'b' || ctl_line[0] == 'B') {
780 tokens = g_regex_split(uzbl.comm.bind_regex, ctl_line, 0);
781 if(tokens[0][0] == 0) {
782 add_binding(tokens[1], tokens[2]);
783 g_strfreev(tokens);
785 else
786 printf("Error in command: %s\n", tokens[0]);
788 /* Comments */
789 else if( (ctl_line[0] == '#')
790 || (ctl_line[0] == ' ')
791 || (ctl_line[0] == '\n'))
792 ; /* ignore these lines */
793 else
794 printf("Command not understood (%s)\n", ctl_line);
796 return;
800 void
801 build_stream_name(int type) {
802 char *xwin_str;
803 State *s = &uzbl.state;
804 Behaviour *b = &uzbl.behave;
806 xwin_str = itos((int)uzbl.xwin);
807 switch(type) {
808 case FIFO:
809 if (b->fifo_dir) {
810 sprintf (uzbl.comm.fifo_path, "%s/uzbl_fifo_%s",
811 b->fifo_dir,
812 s->instance_name ? s->instance_name : xwin_str);
813 } else {
814 sprintf (uzbl.comm.fifo_path, "/tmp/uzbl_fifo_%s",
815 s->instance_name ? s->instance_name : xwin_str);
817 break;
819 case SOCKET:
820 if (b->socket_dir) {
821 sprintf (uzbl.comm.socket_path, "%s/uzbl_socket_%s",
822 b->socket_dir,
823 s->instance_name ? s->instance_name : xwin_str);
824 } else {
825 sprintf (uzbl.comm.socket_path, "/tmp/uzbl_socket_%s",
826 s->instance_name ? s->instance_name : xwin_str);
828 break;
829 default:
830 break;
832 g_free(xwin_str);
835 static void
836 control_fifo(GIOChannel *gio, GIOCondition condition) {
837 printf("triggered\n");
838 gchar *ctl_line;
839 GIOStatus ret;
840 GError *err = NULL;
842 if (condition & G_IO_HUP)
843 g_error ("Fifo: Read end of pipe died!\n");
845 if(!gio)
846 g_error ("Fifo: GIOChannel broke\n");
848 ret = g_io_channel_read_line(gio, &ctl_line, NULL, NULL, &err);
849 if (ret == G_IO_STATUS_ERROR)
850 g_error ("Fifo: Error reading: %s\n", err->message);
852 parse_cmd_line(ctl_line);
853 g_free(ctl_line);
855 return;
858 static void
859 create_fifo() {
860 GIOChannel *chan = NULL;
861 GError *error = NULL;
863 build_stream_name(FIFO);
864 if (file_exists(uzbl.comm.fifo_path)) {
865 g_error ("Fifo: Error when creating %s: File exists\n", uzbl.comm.fifo_path);
866 return;
868 if (mkfifo (uzbl.comm.fifo_path, 0666) == -1) {
869 g_error ("Fifo: Error when creating %s: %s\n", uzbl.comm.fifo_path, strerror(errno));
870 } else {
871 // 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.
872 chan = g_io_channel_new_file((gchar *) uzbl.comm.fifo_path, "r+", &error);
873 if (chan) {
874 if (!g_io_add_watch(chan, G_IO_IN|G_IO_HUP, (GIOFunc) control_fifo, NULL)) {
875 g_error ("Fifo: could not add watch on %s\n", uzbl.comm.fifo_path);
876 } else {
877 printf ("Fifo: created successfully as %s\n", uzbl.comm.fifo_path);
879 } else {
880 g_error ("Fifo: Error while opening: %s\n", error->message);
883 return;
887 static gboolean
888 control_stdin(GIOChannel *gio, GIOCondition condition) {
889 gchar *ctl_line = NULL;
890 gsize ctl_line_len = 0;
891 GIOStatus ret;
892 GError *err = NULL;
894 if (condition & G_IO_HUP) {
895 ret = g_io_channel_shutdown (gio, FALSE, &err);
896 return FALSE;
899 ret = g_io_channel_read_line(gio, &ctl_line, &ctl_line_len, NULL, &err);
900 if ( (ret == G_IO_STATUS_ERROR) || (ret == G_IO_STATUS_EOF) )
901 return FALSE;
903 parse_cmd_line(ctl_line);
904 g_free(ctl_line);
906 return TRUE;
909 static void
910 create_stdin () {
911 GIOChannel *chan = NULL;
912 GError *error = NULL;
914 chan = g_io_channel_unix_new(fileno(stdin));
915 if (chan) {
916 if (!g_io_add_watch(chan, G_IO_IN|G_IO_HUP, (GIOFunc) control_stdin, NULL)) {
917 g_error ("Stdin: could not add watch\n");
918 } else {
919 printf ("Stdin: watch added successfully\n");
921 } else {
922 g_error ("Stdin: Error while opening: %s\n", error->message);
926 static void
927 control_socket(GIOChannel *chan) {
928 struct sockaddr_un remote;
929 char buffer[512], *ctl_line;
930 char temp[128];
931 int sock, clientsock, n, done;
932 unsigned int t;
934 sock = g_io_channel_unix_get_fd(chan);
936 memset (buffer, 0, sizeof (buffer));
938 t = sizeof (remote);
939 clientsock = accept (sock, (struct sockaddr *) &remote, &t);
941 done = 0;
942 do {
943 memset (temp, 0, sizeof (temp));
944 n = recv (clientsock, temp, 128, 0);
945 if (n == 0) {
946 buffer[strlen (buffer)] = '\0';
947 done = 1;
949 if (!done)
950 strcat (buffer, temp);
951 } while (!done);
953 if (strcmp (buffer, "\n") < 0) {
954 buffer[strlen (buffer) - 1] = '\0';
955 } else {
956 buffer[strlen (buffer)] = '\0';
958 close (clientsock);
959 ctl_line = g_strdup(buffer);
960 parse_cmd_line (ctl_line);
963 TODO: we should be able to do it with this. but glib errors out with "Invalid argument"
964 GError *error = NULL;
965 gsize len;
966 GIOStatus ret;
967 ret = g_io_channel_read_line(chan, &ctl_line, &len, NULL, &error);
968 if (ret == G_IO_STATUS_ERROR)
969 g_error ("Error reading: %s\n", error->message);
971 printf("Got line %s (%u bytes) \n",ctl_line, len);
972 if(ctl_line) {
973 parse_line(ctl_line);
976 g_free(ctl_line);
977 return;
980 static void
981 create_socket() {
982 GIOChannel *chan = NULL;
983 int sock, len;
984 struct sockaddr_un local;
986 build_stream_name(SOCKET);
987 sock = socket (AF_UNIX, SOCK_STREAM, 0);
989 local.sun_family = AF_UNIX;
990 strcpy (local.sun_path, uzbl.comm.socket_path);
991 unlink (local.sun_path);
993 len = strlen (local.sun_path) + sizeof (local.sun_family);
994 bind (sock, (struct sockaddr *) &local, len);
996 if (errno == -1) {
997 printf ("Socket: Could not open in %s: %s\n", uzbl.comm.socket_path, strerror(errno));
998 } else {
999 printf ("Socket: Opened in %s\n", uzbl.comm.socket_path);
1000 listen (sock, 5);
1002 if( (chan = g_io_channel_unix_new(sock)) )
1003 g_io_add_watch(chan, G_IO_IN|G_IO_HUP, (GIOFunc) control_socket, chan);
1007 static void
1008 update_title (void) {
1009 GString* string_long = g_string_new ("");
1010 GString* string_short = g_string_new ("");
1011 char* iname = NULL;
1012 gchar *statln;
1013 int iname_len;
1014 State *s = &uzbl.state;
1015 Behaviour *b = &uzbl.behave;
1017 if(s->instance_name) {
1018 iname_len = strlen(s->instance_name)+4;
1019 iname = malloc(iname_len);
1020 snprintf(iname, iname_len, "<%s> ", s->instance_name);
1022 g_string_prepend(string_long, iname);
1023 g_string_prepend(string_short, iname);
1024 free(iname);
1027 g_string_append_printf(string_long, "%s ", s->keycmd->str);
1028 if (!b->always_insert_mode)
1029 g_string_append (string_long, (b->insert_mode ? "[I] " : "[C] "));
1030 if (uzbl.gui.main_title) {
1031 g_string_append (string_long, uzbl.gui.main_title);
1032 g_string_append (string_short, uzbl.gui.main_title);
1034 g_string_append (string_long, " - Uzbl browser");
1035 g_string_append (string_short, " - Uzbl browser");
1036 if (s->selected_url[0]!=0) {
1037 g_string_append_printf (string_long, " -> (%s)", s->selected_url);
1040 gchar* title_long = g_string_free (string_long, FALSE);
1041 gchar* title_short = g_string_free (string_short, FALSE);
1043 if (b->show_status) {
1044 gtk_window_set_title (GTK_WINDOW(uzbl.gui.main_window), title_short);
1045 // TODO: we should probably not do this every time we want to update the title..?
1046 statln = parse_status_template(uzbl.behave.status_format);
1047 gtk_label_set_markup(GTK_LABEL(uzbl.gui.mainbar_label), statln);
1048 if (b->status_background) {
1049 GdkColor color;
1050 gdk_color_parse (b->status_background, &color);
1051 //labels and hboxes do not draw their own background. applying this on the window is ok as we the statusbar is the only affected widget. (if not, we could also use GtkEventBox)
1052 gtk_widget_modify_bg (uzbl.gui.main_window, GTK_STATE_NORMAL, &color);
1054 g_free(statln);
1055 } else {
1056 gtk_window_set_title (GTK_WINDOW(uzbl.gui.main_window), title_long);
1059 g_free (title_long);
1060 g_free (title_short);
1063 static gboolean
1064 key_press_cb (WebKitWebView* page, GdkEventKey* event)
1066 //TRUE to stop other handlers from being invoked for the event. FALSE to propagate the event further.
1068 (void) page;
1069 Action *action;
1071 if (event->type != GDK_KEY_PRESS || event->keyval == GDK_Page_Up || event->keyval == GDK_Page_Down
1072 || event->keyval == GDK_Up || event->keyval == GDK_Down || event->keyval == GDK_Left || event->keyval == GDK_Right)
1073 return FALSE;
1075 /* turn off insert mode (if always_insert_mode is not used) */
1076 if (uzbl.behave.insert_mode && (event->keyval == GDK_Escape)) {
1077 uzbl.behave.insert_mode = uzbl.behave.always_insert_mode;
1078 update_title();
1079 return TRUE;
1082 if (uzbl.behave.insert_mode && ((event->state & uzbl.behave.modmask) != uzbl.behave.modmask))
1083 return FALSE;
1085 if (event->keyval == GDK_Escape) {
1086 g_string_truncate(uzbl.state.keycmd, 0);
1087 update_title();
1088 return TRUE;
1091 //Insert without shift - insert from clipboard; Insert with shift - insert from primary
1092 if (event->keyval == GDK_Insert) {
1093 gchar * str;
1094 if ((event->state & GDK_SHIFT_MASK) == GDK_SHIFT_MASK) {
1095 str = gtk_clipboard_wait_for_text (gtk_clipboard_get (GDK_SELECTION_PRIMARY));
1096 } else {
1097 str = gtk_clipboard_wait_for_text (gtk_clipboard_get (GDK_SELECTION_CLIPBOARD));
1099 if (str) {
1100 g_string_append_printf (uzbl.state.keycmd, "%s", str);
1101 update_title ();
1102 free (str);
1104 return TRUE;
1107 if ((event->keyval == GDK_BackSpace) && (uzbl.state.keycmd->len > 0)) {
1108 g_string_truncate(uzbl.state.keycmd, uzbl.state.keycmd->len - 1);
1109 update_title();
1110 return TRUE;
1113 if ((event->keyval == GDK_Return) || (event->keyval == GDK_KP_Enter)) {
1114 GString* short_keys = g_string_new ("");
1115 unsigned int i;
1116 for (i=0; i<(uzbl.state.keycmd->len); i++) {
1117 g_string_append_c(short_keys, uzbl.state.keycmd->str[i]);
1118 g_string_append_c(short_keys, '_');
1120 //printf("\nTesting string: @%s@\n", short_keys->str);
1121 if ((action = g_hash_table_lookup(uzbl.bindings, short_keys->str))) {
1122 GString* parampart = g_string_new (uzbl.state.keycmd->str);
1123 g_string_erase (parampart, 0, i+1);
1124 //printf("\nParameter: @%s@\n", parampart->str);
1125 GString* actionname = g_string_new ("");
1126 if (action->name)
1127 g_string_printf (actionname, action->name, parampart->str);
1128 GString* actionparam = g_string_new ("");
1129 if (action->param)
1130 g_string_printf (actionparam, action->param, parampart->str);
1131 parse_command(actionname->str, actionparam->str);
1132 g_string_free (actionname, TRUE);
1133 g_string_free (actionparam, TRUE);
1134 g_string_free (parampart, TRUE);
1135 g_string_truncate(uzbl.state.keycmd, 0);
1136 update_title();
1139 g_string_truncate(short_keys, short_keys->len - 1);
1141 g_string_free (short_keys, TRUE);
1142 return (!uzbl.behave.insert_mode);
1145 g_string_append(uzbl.state.keycmd, event->string);
1146 if ((action = g_hash_table_lookup(uzbl.bindings, uzbl.state.keycmd->str))) {
1147 g_string_truncate(uzbl.state.keycmd, 0);
1148 parse_command(action->name, action->param);
1151 update_title();
1153 return TRUE;
1156 static GtkWidget*
1157 create_browser () {
1158 GUI *g = &uzbl.gui;
1160 GtkWidget* scrolled_window = gtk_scrolled_window_new (NULL, NULL);
1161 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
1163 g->web_view = WEBKIT_WEB_VIEW (webkit_web_view_new ());
1164 gtk_container_add (GTK_CONTAINER (scrolled_window), GTK_WIDGET (g->web_view));
1166 g_signal_connect (G_OBJECT (g->web_view), "title-changed", G_CALLBACK (title_change_cb), g->web_view);
1167 g_signal_connect (G_OBJECT (g->web_view), "load-progress-changed", G_CALLBACK (progress_change_cb), g->web_view);
1168 g_signal_connect (G_OBJECT (g->web_view), "load-committed", G_CALLBACK (load_commit_cb), g->web_view);
1169 g_signal_connect (G_OBJECT (g->web_view), "load-committed", G_CALLBACK (log_history_cb), g->web_view);
1170 g_signal_connect (G_OBJECT (g->web_view), "hovering-over-link", G_CALLBACK (link_hover_cb), g->web_view);
1171 g_signal_connect (G_OBJECT (g->web_view), "key-press-event", G_CALLBACK (key_press_cb), g->web_view);
1172 g_signal_connect (G_OBJECT (g->web_view), "new-window-policy-decision-requested", G_CALLBACK (new_window_cb), g->web_view);
1173 g_signal_connect (G_OBJECT (g->web_view), "download-requested", G_CALLBACK (download_cb), g->web_view);
1174 g_signal_connect (G_OBJECT (g->web_view), "create-web-view", G_CALLBACK (create_web_view_cb), g->web_view);
1176 return scrolled_window;
1179 static GtkWidget*
1180 create_mainbar () {
1181 GUI *g = &uzbl.gui;
1183 g->mainbar = gtk_hbox_new (FALSE, 0);
1184 g->mainbar_label = gtk_label_new ("");
1185 gtk_label_set_selectable((GtkLabel *)g->mainbar_label, TRUE);
1186 gtk_label_set_ellipsize(GTK_LABEL(g->mainbar_label), PANGO_ELLIPSIZE_END);
1187 gtk_misc_set_alignment (GTK_MISC(g->mainbar_label), 0, 0);
1188 gtk_misc_set_padding (GTK_MISC(g->mainbar_label), 2, 2);
1189 gtk_box_pack_start (GTK_BOX (g->mainbar), g->mainbar_label, TRUE, TRUE, 0);
1190 return g->mainbar;
1193 static
1194 GtkWidget* create_window () {
1195 GtkWidget* window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
1196 gtk_window_set_default_size (GTK_WINDOW (window), 800, 600);
1197 gtk_widget_set_name (window, "Uzbl browser");
1198 g_signal_connect (G_OBJECT (window), "destroy", G_CALLBACK (destroy_cb), NULL);
1200 return window;
1203 static void
1204 add_binding (const gchar *key, const gchar *act) {
1205 char **parts = g_strsplit(act, " ", 2);
1206 Action *action;
1208 if (!parts)
1209 return;
1211 //Debug:
1212 printf ("Binding %-10s : %s\n", key, act);
1213 action = new_action(parts[0], parts[1]);
1215 if(g_hash_table_lookup(uzbl.bindings, key))
1216 g_hash_table_remove(uzbl.bindings, key);
1217 g_hash_table_insert(uzbl.bindings, g_strdup(key), action);
1219 g_strfreev(parts);
1222 static void
1223 settings_init () {
1224 GKeyFile* config = NULL;
1225 gboolean res = FALSE;
1226 char *saveptr;
1227 gchar** keys = NULL;
1228 State *s = &uzbl.state;
1229 Network *n = &uzbl.net;
1230 Behaviour *b = &uzbl.behave;
1232 if (!s->config_file) {
1233 const char* XDG_CONFIG_HOME = getenv ("XDG_CONFIG_HOME");
1234 if (! XDG_CONFIG_HOME || ! strcmp (XDG_CONFIG_HOME, "")) {
1235 XDG_CONFIG_HOME = (char*)XDG_CONFIG_HOME_default;
1237 printf("XDG_CONFIG_HOME: %s\n", XDG_CONFIG_HOME);
1239 strcpy (s->config_file_path, XDG_CONFIG_HOME);
1240 strcat (s->config_file_path, "/uzbl/config");
1241 if (file_exists (s->config_file_path)) {
1242 printf ("Config file %s found.\n", s->config_file_path);
1243 s->config_file = &s->config_file_path[0];
1244 } else {
1245 // Now we check $XDG_CONFIG_DIRS
1246 char *XDG_CONFIG_DIRS = getenv ("XDG_CONFIG_DIRS");
1247 if (! XDG_CONFIG_DIRS || ! strcmp (XDG_CONFIG_DIRS, ""))
1248 XDG_CONFIG_DIRS = XDG_CONFIG_DIRS_default;
1250 printf("XDG_CONFIG_DIRS: %s\n", XDG_CONFIG_DIRS);
1252 char buffer[512];
1253 strcpy (buffer, XDG_CONFIG_DIRS);
1254 const gchar* dir = (char *) strtok_r (buffer, ":", &saveptr);
1255 while (dir && ! file_exists (s->config_file_path)) {
1256 strcpy (s->config_file_path, dir);
1257 strcat (s->config_file_path, "/uzbl/config_file_pathig");
1258 if (file_exists (s->config_file_path)) {
1259 printf ("Config file %s found.\n", s->config_file_path);
1260 s->config_file = &s->config_file_path[0];
1262 dir = (char * ) strtok_r (NULL, ":", &saveptr);
1267 if (s->config_file) {
1268 config = g_key_file_new ();
1269 res = g_key_file_load_from_file (config, s->config_file, G_KEY_FILE_NONE, NULL);
1270 if (res) {
1271 printf ("Config %s loaded\n", s->config_file);
1272 } else {
1273 fprintf (stderr, "Config %s loading failed\n", s->config_file);
1275 } else {
1276 printf ("No configuration.\n");
1279 if (res) {
1280 b->history_handler = g_key_file_get_value (config, "behavior", "history_handler", NULL);
1281 b->download_handler = g_key_file_get_value (config, "behavior", "download_handler", NULL);
1282 b->cookie_handler = g_key_file_get_string (config, "behavior", "cookie_handler", NULL);
1283 b->always_insert_mode = g_key_file_get_boolean (config, "behavior", "always_insert_mode", NULL);
1284 b->show_status = g_key_file_get_boolean (config, "behavior", "show_status", NULL);
1285 b->modkey = g_key_file_get_value (config, "behavior", "modkey", NULL);
1286 b->status_top = g_key_file_get_boolean (config, "behavior", "status_top", NULL);
1287 b->status_format = g_key_file_get_string (config, "behavior", "status_format", NULL);
1288 b->status_background = g_key_file_get_string (config, "behavior", "status_background", NULL);
1289 if (! b->fifo_dir)
1290 b->fifo_dir = g_key_file_get_value (config, "behavior", "fifo_dir", NULL);
1291 if (! b->socket_dir)
1292 b->socket_dir = g_key_file_get_value (config, "behavior", "socket_dir", NULL);
1293 keys = g_key_file_get_keys (config, "bindings", NULL, NULL);
1296 printf ("History handler: %s\n", (b->history_handler ? b->history_handler : "disabled"));
1297 printf ("Download manager: %s\n", (b->download_handler ? b->download_handler : "disabled"));
1298 printf ("Cookie handler: %s\n", (b->cookie_handler ? b->cookie_handler : "disabled"));
1299 printf ("Fifo directory: %s\n", (b->fifo_dir ? b->fifo_dir : "disabled"));
1300 printf ("Socket directory: %s\n", (b->socket_dir ? b->socket_dir : "disabled"));
1301 printf ("Always insert mode: %s\n", (b->always_insert_mode ? "TRUE" : "FALSE"));
1302 printf ("Show status: %s\n", (b->show_status ? "TRUE" : "FALSE"));
1303 printf ("Status top: %s\n", (b->status_top ? "TRUE" : "FALSE"));
1304 printf ("Modkey: %s\n", (b->modkey ? b->modkey : "disabled"));
1305 printf ("Status format: %s\n", (b->status_format ? b->status_format : "none"));
1307 if (!b->modkey)
1308 b->modkey = "";
1310 //POSSIBLE MODKEY VALUES (COMBINATIONS CAN BE USED)
1311 gchar* modkeyup = g_utf8_strup (b->modkey, -1);
1312 if (g_strrstr (modkeyup,"SHIFT") != NULL) b->modmask |= GDK_SHIFT_MASK; //the Shift key.
1313 if (g_strrstr (modkeyup,"LOCK") != NULL) b->modmask |= GDK_LOCK_MASK; //a Lock key (depending on the modifier mapping of the X server this may either be CapsLock or ShiftLock).
1314 if (g_strrstr (modkeyup,"CONTROL") != NULL) b->modmask |= GDK_CONTROL_MASK; //the Control key.
1315 if (g_strrstr (modkeyup,"MOD1") != NULL) b->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).
1316 if (g_strrstr (modkeyup,"MOD2") != NULL) b->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).
1317 if (g_strrstr (modkeyup,"MOD3") != NULL) b->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).
1318 if (g_strrstr (modkeyup,"MOD4") != NULL) b->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).
1319 if (g_strrstr (modkeyup,"MOD5") != NULL) b->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).
1320 if (g_strrstr (modkeyup,"BUTTON1") != NULL) b->modmask |= GDK_BUTTON1_MASK; //the first mouse button.
1321 if (g_strrstr (modkeyup,"BUTTON2") != NULL) b->modmask |= GDK_BUTTON2_MASK; //the second mouse button.
1322 if (g_strrstr (modkeyup,"BUTTON3") != NULL) b->modmask |= GDK_BUTTON3_MASK; //the third mouse button.
1323 if (g_strrstr (modkeyup,"BUTTON4") != NULL) b->modmask |= GDK_BUTTON4_MASK; //the fourth mouse button.
1324 if (g_strrstr (modkeyup,"BUTTON5") != NULL) b->modmask |= GDK_BUTTON5_MASK; //the fifth mouse button.
1325 if (g_strrstr (modkeyup,"SUPER") != NULL) b->modmask |= GDK_SUPER_MASK; //the Super modifier. Since 2.10
1326 if (g_strrstr (modkeyup,"HYPER") != NULL) b->modmask |= GDK_HYPER_MASK; //the Hyper modifier. Since 2.10
1327 if (g_strrstr (modkeyup,"META") != NULL) b->modmask |= GDK_META_MASK; //the Meta modifier. Since 2.10 */
1328 free (modkeyup);
1330 if (keys) {
1331 int i;
1332 for (i = 0; keys[i]; i++) {
1333 gchar *value = g_key_file_get_string (config, "bindings", keys[i], NULL);
1335 add_binding(g_strstrip(keys[i]), value);
1336 g_free(value);
1339 g_strfreev(keys);
1342 /* networking options */
1343 if (res) {
1344 b->http_debug = g_key_file_get_integer (config, "network", "http_debug", NULL);
1345 n->useragent = g_key_file_get_value (config, "network", "user-agent", NULL);
1346 n->max_conns = g_key_file_get_integer (config, "network", "max_conns", NULL);
1347 n->max_conns_host = g_key_file_get_integer (config, "network", "max_conns_per_host", NULL);
1351 if(!(b->http_debug <= 3)){
1352 b->http_debug = 0;
1353 fprintf(stderr, "Wrong http_debug level, ignoring.\n");
1354 } else if (b->http_debug > 0) {
1355 n->soup_logger = soup_logger_new(b->http_debug, -1);
1356 soup_session_add_feature(n->soup_session, SOUP_SESSION_FEATURE(n->soup_logger));
1359 if(n->useragent){
1360 char* newagent = malloc(1024);
1362 strcpy(newagent, str_replace("%webkit-major%", itos(WEBKIT_MAJOR_VERSION), n->useragent));
1363 strcpy(newagent, str_replace("%webkit-minor%", itos(WEBKIT_MINOR_VERSION), newagent));
1364 strcpy(newagent, str_replace("%webkit-micro%", itos(WEBKIT_MICRO_VERSION), newagent));
1366 if (uname (&s->unameinfo) == -1) {
1367 printf("Error getting uname info. Not replacing system-related user agent variables.\n");
1368 } else {
1369 strcpy(newagent, str_replace("%sysname%", s->unameinfo.sysname, newagent));
1370 strcpy(newagent, str_replace("%nodename%", s->unameinfo.nodename, newagent));
1371 strcpy(newagent, str_replace("%kernrel%", s->unameinfo.release, newagent));
1372 strcpy(newagent, str_replace("%kernver%", s->unameinfo.version, newagent));
1373 strcpy(newagent, str_replace("%arch-system%", s->unameinfo.machine, newagent));
1375 #ifdef _GNU_SOURCE
1376 strcpy(newagent, str_replace("%domainname%", s->unameinfo.domainname, newagent));
1377 #endif
1380 strcpy(newagent, str_replace("%arch-uzbl%", ARCH, newagent));
1381 strcpy(newagent, str_replace("%commit%", COMMIT, newagent));
1383 n->useragent = malloc(1024);
1384 strcpy(n->useragent, newagent);
1385 g_object_set(G_OBJECT(n->soup_session), SOUP_SESSION_USER_AGENT, n->useragent, NULL);
1388 if(n->max_conns >= 1){
1389 g_object_set(G_OBJECT(n->soup_session), SOUP_SESSION_MAX_CONNS, n->max_conns, NULL);
1392 if(n->max_conns_host >= 1){
1393 g_object_set(G_OBJECT(n->soup_session), SOUP_SESSION_MAX_CONNS_PER_HOST, n->max_conns_host, NULL);
1396 printf("Proxy configured: %s\n", n->proxy_url ? n->proxy_url : "none");
1397 printf("HTTP logging level: %d\n", b->http_debug);
1398 printf("User-agent: %s\n", n->useragent? n->useragent : "default");
1399 printf("Maximum connections: %d\n", n->max_conns ? n->max_conns : 0);
1400 printf("Maximum connections per host: %d\n", n->max_conns_host ? n->max_conns_host: 0);
1404 if(b->cookie_handler){
1405 /* ck = soup_cookie_jar_new(); */
1406 /* soup_session_add_feature(soup_session, SOUP_SESSION_FEATURE(ck)); */
1407 /* g_signal_connect(ck, "changed", G_CALLBACK(cookie_recieved_action), NULL); */
1408 g_signal_connect(n->soup_session, "request-queued", G_CALLBACK(handle_cookies), NULL);
1413 static void handle_cookies (SoupSession *session, SoupMessage *msg, gpointer user_data){
1414 (void) session;
1415 (void) user_data;
1416 gchar * stdout = NULL;
1417 soup_message_add_header_handler(msg, "got-headers", "Set-Cookie", G_CALLBACK(save_cookies), NULL);
1418 GString* args = g_string_new ("");
1419 SoupURI * soup_uri = soup_message_get_uri(msg);
1420 g_string_printf (args, "GET %s %s", soup_uri->host, soup_uri->path);
1421 run_command_sync(uzbl.behave.cookie_handler, args->str, &stdout);
1422 if(stdout) {
1423 soup_message_headers_replace (msg->request_headers, "Cookie", stdout);
1425 g_string_free(args, TRUE);
1428 static void
1429 save_cookies (SoupMessage *msg, gpointer user_data){
1430 (void) user_data;
1431 GSList *ck;
1432 char *cookie;
1433 for (ck = soup_cookies_from_response(msg); ck; ck = ck->next){
1434 cookie = soup_cookie_to_set_cookie_header(ck->data);
1435 GString* args = g_string_new ("");
1436 SoupURI * soup_uri = soup_message_get_uri(msg);
1437 g_string_printf (args, "PUT %s %s \"%s\"", soup_uri->host, soup_uri->path, cookie);
1438 run_command_async(uzbl.behave.cookie_handler, args->str);
1439 g_string_free(args, TRUE);
1440 free(cookie);
1442 g_slist_free(ck);
1446 main (int argc, char* argv[]) {
1447 gtk_init (&argc, &argv);
1448 if (!g_thread_supported ())
1449 g_thread_init (NULL);
1451 printf("Uzbl start location: %s\n", argv[0]);
1452 strcpy(uzbl.state.executable_path,argv[0]);
1454 strcat ((char *) XDG_CONFIG_HOME_default, getenv ("HOME"));
1455 strcat ((char *) XDG_CONFIG_HOME_default, "/.config");
1457 GError *error = NULL;
1458 GOptionContext* context = g_option_context_new ("- some stuff here maybe someday");
1459 g_option_context_add_main_entries (context, entries, NULL);
1460 g_option_context_add_group (context, gtk_get_option_group (TRUE));
1461 g_option_context_parse (context, &argc, &argv, &error);
1462 /* initialize hash table */
1463 uzbl.bindings = g_hash_table_new_full(g_str_hash, g_str_equal, g_free, free_action);
1465 uzbl.net.soup_session = webkit_get_default_session();
1466 uzbl.state.keycmd = g_string_new("");
1468 settings_init ();
1469 commands_hash ();
1471 if (uzbl.behave.always_insert_mode)
1472 uzbl.behave.insert_mode = TRUE;
1474 GtkWidget* vbox = gtk_vbox_new (FALSE, 0);
1475 if (uzbl.behave.status_top)
1476 gtk_box_pack_start (GTK_BOX (vbox), create_mainbar (), FALSE, TRUE, 0);
1477 gtk_box_pack_start (GTK_BOX (vbox), create_browser (), TRUE, TRUE, 0);
1478 if (!uzbl.behave.status_top)
1479 gtk_box_pack_start (GTK_BOX (vbox), create_mainbar (), FALSE, TRUE, 0);
1481 uzbl.gui.main_window = create_window ();
1482 gtk_container_add (GTK_CONTAINER (uzbl.gui.main_window), vbox);
1484 load_uri (uzbl.gui.web_view, uzbl.state.uri);
1486 gtk_widget_grab_focus (GTK_WIDGET (uzbl.gui.web_view));
1487 gtk_widget_show_all (uzbl.gui.main_window);
1488 uzbl.xwin = GDK_WINDOW_XID (GTK_WIDGET (uzbl.gui.main_window)->window);
1489 printf("window_id %i\n",(int) uzbl.xwin);
1490 printf("pid %i\n", getpid ());
1491 printf("name: %s\n", uzbl.state.instance_name);
1493 uzbl.gui.scbar_v = (GtkScrollbar*) gtk_vscrollbar_new (NULL);
1494 uzbl.gui.bar_v = gtk_range_get_adjustment((GtkRange*) uzbl.gui.scbar_v);
1495 uzbl.gui.scbar_h = (GtkScrollbar*) gtk_hscrollbar_new (NULL);
1496 uzbl.gui.bar_h = gtk_range_get_adjustment((GtkRange*) uzbl.gui.scbar_h);
1497 gtk_widget_set_scroll_adjustments ((GtkWidget*) uzbl.gui.web_view, uzbl.gui.bar_h, uzbl.gui.bar_v);
1500 if(setup_signal(SIGTERM, catch_sigterm) == SIG_ERR)
1501 fprintf(stderr, "uzbl: error hooking SIGTERM\n");
1504 setup_regex();
1505 setup_scanner();
1507 if (!uzbl.behave.status_format)
1508 uzbl.behave.status_format = g_strdup(STATUS_DEFAULT);
1509 if (!uzbl.behave.show_status)
1510 gtk_widget_hide(uzbl.gui.mainbar);
1511 else
1512 update_title();
1515 make_var_to_name_hash();
1516 create_stdin();
1517 if (uzbl.behave.fifo_dir)
1518 create_fifo ();
1519 if (uzbl.behave.socket_dir)
1520 create_socket ();
1522 gtk_main ();
1523 clean_up();
1525 return EXIT_SUCCESS;
1528 /* vi: set et ts=4: */