further enhancements to the cmd parser, added sampleconfig-pipe
[uzbl-00z.git] / uzbl.c
blobccb2203b18454723810cd823caa0ce03d8c37712
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 { "status_format", (void *)&uzbl.behave.status_format },
67 { "show_status", (void *)&uzbl.behave.show_status },
68 { "insert_mode", (void *)&uzbl.behave.insert_mode },
69 { NULL, NULL }
70 }, *n2v_p = var_name_to_ptr;
72 /* construct a hash from the var_name_to_ptr array for quick access */
73 static void
74 make_var_to_name_hash() {
75 uzbl.comm.proto_var = g_hash_table_new(g_str_hash, g_str_equal);
76 while(n2v_p->name) {
77 g_hash_table_insert(uzbl.comm.proto_var, n2v_p->name, n2v_p->ptr);
78 n2v_p++;
82 /* commandline arguments (set initial values for the state variables) */
83 static GOptionEntry entries[] =
85 { "uri", 'u', 0, G_OPTION_ARG_STRING, &uzbl.state.uri, "Uri to load", "URI" },
86 { "name", 'n', 0, G_OPTION_ARG_STRING, &uzbl.state.instance_name, "Name of the current instance", "NAME" },
87 { "config", 'c', 0, G_OPTION_ARG_STRING, &uzbl.state.config_file, "Config file", "FILE" },
88 { NULL, 0, 0, 0, NULL, NULL, NULL }
91 typedef void (*Command)(WebKitWebView*, const char *);
93 /* XDG stuff */
94 static char *XDG_CONFIG_HOME_default[256];
95 static char *XDG_CONFIG_DIRS_default = "/etc/xdg";
98 /* --- UTILITY FUNCTIONS --- */
100 char *
101 itos(int val) {
102 char tmp[20];
104 snprintf(tmp, sizeof(tmp), "%i", val);
105 return g_strdup(tmp);
108 static char *
109 str_replace (const char* search, const char* replace, const char* string) {
110 return g_strjoinv (replace, g_strsplit(string, search, -1));
113 static sigfunc*
114 setup_signal(int signr, sigfunc *shandler) {
115 struct sigaction nh, oh;
117 nh.sa_handler = shandler;
118 sigemptyset(&nh.sa_mask);
119 nh.sa_flags = 0;
121 if(sigaction(signr, &nh, &oh) < 0)
122 return SIG_ERR;
124 return NULL;
127 static void
128 clean_up(void) {
129 if (uzbl.behave.fifo_dir)
130 unlink (uzbl.comm.fifo_path);
131 if (uzbl.behave.socket_dir)
132 unlink (uzbl.comm.socket_path);
134 g_string_free(uzbl.state.keycmd, TRUE);
135 g_hash_table_destroy(uzbl.bindings);
136 g_hash_table_destroy(uzbl.behave.commands);
140 /* --- SIGNAL HANDLER --- */
142 static void
143 catch_sigterm(int s) {
144 (void) s;
145 clean_up();
148 /* --- CALLBACKS --- */
150 static gboolean
151 new_window_cb (WebKitWebView *web_view, WebKitWebFrame *frame, WebKitNetworkRequest *request, WebKitWebNavigationAction *navigation_action, WebKitWebPolicyDecision *policy_decision, gpointer user_data) {
152 (void) web_view;
153 (void) frame;
154 (void) navigation_action;
155 (void) policy_decision;
156 (void) user_data;
157 const gchar* uri = webkit_network_request_get_uri (request);
158 printf("New window requested -> %s \n", uri);
159 new_window_load_uri(uri);
160 return (FALSE);
163 WebKitWebView*
164 create_web_view_cb (WebKitWebView *web_view, WebKitWebFrame *frame, gpointer user_data) {
165 (void) web_view;
166 (void) frame;
167 (void) user_data;
168 if (uzbl.state.selected_url[0]!=0) {
169 printf("\nNew web view -> %s\n",uzbl.state.selected_url);
170 new_window_load_uri(uzbl.state.selected_url);
171 } else {
172 printf("New web view -> %s\n","Nothing to open, exiting");
174 return (NULL);
177 static gboolean
178 download_cb (WebKitWebView *web_view, GObject *download, gpointer user_data) {
179 (void) web_view;
180 (void) user_data;
181 if (uzbl.behave.download_handler) {
182 const gchar* uri = webkit_download_get_uri ((WebKitDownload*)download);
183 printf("Download -> %s\n",uri);
184 run_command_async(uzbl.behave.download_handler, uri);
186 return (FALSE);
189 /* scroll a bar in a given direction */
190 static void
191 scroll (GtkAdjustment* bar, const char *param) {
192 gdouble amount;
193 gchar *end;
195 amount = g_ascii_strtod(param, &end);
197 if (*end)
198 fprintf(stderr, "found something after double: %s\n", end);
200 gtk_adjustment_set_value (bar, gtk_adjustment_get_value(bar)+amount);
203 static void scroll_vert(WebKitWebView* page, const char *param) {
204 (void) page;
206 scroll(uzbl.gui.bar_v, param);
209 static void scroll_horz(WebKitWebView* page, const char *param) {
210 (void) page;
212 scroll(uzbl.gui.bar_h, param);
215 static void
216 cmd_set_status() {
217 if (!uzbl.behave.show_status) {
218 gtk_widget_hide(uzbl.gui.mainbar);
219 } else {
220 gtk_widget_show(uzbl.gui.mainbar);
222 update_title();
225 static void
226 toggle_status_cb (WebKitWebView* page, const char *param) {
227 (void)page;
228 (void)param;
230 if (uzbl.behave.show_status) {
231 gtk_widget_hide(uzbl.gui.mainbar);
232 } else {
233 gtk_widget_show(uzbl.gui.mainbar);
235 uzbl.behave.show_status = !uzbl.behave.show_status;
236 update_title();
239 static void
240 link_hover_cb (WebKitWebView* page, const gchar* title, const gchar* link, gpointer data) {
241 (void) page;
242 (void) title;
243 (void) data;
244 //ADD HOVER URL TO WINDOW TITLE
245 uzbl.state.selected_url[0] = '\0';
246 if (link) {
247 strcpy (uzbl.state.selected_url, link);
249 update_title();
252 static void
253 title_change_cb (WebKitWebView* web_view, WebKitWebFrame* web_frame, const gchar* title, gpointer data) {
254 (void) web_view;
255 (void) web_frame;
256 (void) data;
257 if (uzbl.gui.main_title)
258 g_free (uzbl.gui.main_title);
259 uzbl.gui.main_title = g_strdup (title);
260 update_title();
263 static void
264 progress_change_cb (WebKitWebView* page, gint progress, gpointer data) {
265 (void) page;
266 (void) data;
267 uzbl.gui.sbar.load_progress = progress;
268 update_title();
271 static void
272 load_commit_cb (WebKitWebView* page, WebKitWebFrame* frame, gpointer data) {
273 (void) page;
274 (void) data;
275 free (uzbl.state.uri);
276 GString* newuri = g_string_new (webkit_web_frame_get_uri (frame));
277 uzbl.state.uri = g_string_free (newuri, FALSE);
280 static void
281 destroy_cb (GtkWidget* widget, gpointer data) {
282 (void) widget;
283 (void) data;
284 gtk_main_quit ();
287 static void
288 log_history_cb () {
289 if (uzbl.behave.history_handler) {
290 time_t rawtime;
291 struct tm * timeinfo;
292 char date [80];
293 time ( &rawtime );
294 timeinfo = localtime ( &rawtime );
295 strftime (date, 80, "%Y-%m-%d %H:%M:%S", timeinfo);
296 GString* args = g_string_new ("");
297 g_string_printf (args, "'%s'", date);
298 run_command_async(uzbl.behave.history_handler, args->str);
299 g_string_free (args, TRUE);
304 /* VIEW funcs (little webkit wrappers) */
305 #define VIEWFUNC(name) static void view_##name(WebKitWebView *page, const char *param){(void)param; webkit_web_view_##name(page);}
306 VIEWFUNC(reload)
307 VIEWFUNC(reload_bypass_cache)
308 VIEWFUNC(stop_loading)
309 VIEWFUNC(zoom_in)
310 VIEWFUNC(zoom_out)
311 VIEWFUNC(go_back)
312 VIEWFUNC(go_forward)
313 #undef VIEWFUNC
315 /* -- command to callback/function map for things we cannot attach to any signals */
316 // TODO: reload
318 static struct {char *name; Command command;} cmdlist[] =
320 { "back", view_go_back },
321 { "forward", view_go_forward },
322 { "scroll_vert", scroll_vert },
323 { "scroll_horz", scroll_horz },
324 { "reload", view_reload, },
325 { "reload_ign_cache", view_reload_bypass_cache},
326 { "stop", view_stop_loading, },
327 { "zoom_in", view_zoom_in, }, //Can crash (when max zoom reached?).
328 { "zoom_out", view_zoom_out, },
329 { "uri", load_uri },
330 { "script", run_js },
331 { "toggle_status", toggle_status_cb },
332 { "spawn", spawn },
333 { "exit", close_uzbl },
334 { "search", search_text },
335 { "insert_mode", set_insert_mode }
338 static void
339 commands_hash(void)
341 unsigned int i;
342 uzbl.behave.commands = g_hash_table_new(g_str_hash, g_str_equal);
344 for (i = 0; i < LENGTH(cmdlist); i++)
345 g_hash_table_insert(uzbl.behave.commands, cmdlist[i].name, cmdlist[i].command);
348 /* -- CORE FUNCTIONS -- */
350 void
351 free_action(gpointer act) {
352 Action *action = (Action*)act;
353 g_free(action->name);
354 if (action->param)
355 g_free(action->param);
356 g_free(action);
359 Action*
360 new_action(const gchar *name, const gchar *param) {
361 Action *action = g_new(Action, 1);
363 action->name = g_strdup(name);
364 if (param)
365 action->param = g_strdup(param);
366 else
367 action->param = NULL;
369 return action;
372 static bool
373 file_exists (const char * filename) {
374 FILE *file = fopen (filename, "r");
375 if (file) {
376 fclose (file);
377 return true;
379 return false;
382 void
383 set_insert_mode(WebKitWebView *page, const gchar *param) {
384 (void)page;
385 (void)param;
387 uzbl.behave.insert_mode = TRUE;
388 update_title();
391 static void
392 load_uri (WebKitWebView * web_view, const gchar *param) {
393 if (param) {
394 GString* newuri = g_string_new (param);
395 if (g_strrstr (param, "://") == NULL)
396 g_string_prepend (newuri, "http://");
397 /* if we do handle cookies, ask our handler for them */
398 webkit_web_view_load_uri (web_view, newuri->str);
399 g_string_free (newuri, TRUE);
403 static void
404 run_js (WebKitWebView * web_view, const gchar *param) {
405 if (param)
406 webkit_web_view_execute_script (web_view, param);
409 static void
410 search_text (WebKitWebView *page, const char *param) {
411 if ((param) && (param[0] != '\0')) {
412 strcpy(uzbl.state.searchtx, param);
414 if (uzbl.state.searchtx[0] != '\0') {
415 printf ("Searching: %s\n", uzbl.state.searchtx);
416 webkit_web_view_unmark_text_matches (page);
417 webkit_web_view_mark_text_matches (page, uzbl.state.searchtx, FALSE, 0);
418 webkit_web_view_set_highlight_text_matches (page, TRUE);
419 webkit_web_view_search_text (page, uzbl.state.searchtx, FALSE, TRUE, TRUE);
423 static void
424 new_window_load_uri (const gchar * uri) {
425 GString* to_execute = g_string_new ("");
426 g_string_append_printf (to_execute, "%s --uri '%s'", uzbl.state.executable_path, uri);
427 int i;
428 for (i = 0; entries[i].long_name != NULL; i++) {
429 if ((entries[i].arg == G_OPTION_ARG_STRING) && (strcmp(entries[i].long_name,"uri")!=0)) {
430 gchar** str = (gchar**)entries[i].arg_data;
431 if (*str!=NULL) {
432 g_string_append_printf (to_execute, " --%s '%s'", entries[i].long_name, *str);
436 printf("\n%s\n", to_execute->str);
437 g_spawn_command_line_async (to_execute->str, NULL);
438 g_string_free (to_execute, TRUE);
441 static void
442 close_uzbl (WebKitWebView *page, const char *param) {
443 (void)page;
444 (void)param;
445 gtk_main_quit ();
448 /* --Statusbar functions-- */
449 static char*
450 build_progressbar_ascii(int percent) {
451 int width=10;
452 int i;
453 double l;
454 GString *bar = g_string_new("");
456 l = (double)percent*((double)width/100.);
457 l = (int)(l+.5)>=(int)l ? l+.5 : l;
459 g_string_append(bar, "[");
460 for(i=0; i<(int)l; i++)
461 g_string_append(bar, "=");
463 for(; i<width; i++)
464 g_string_append(bar, "·");
465 g_string_append(bar, "]");
467 return g_string_free(bar, FALSE);
470 static void
471 setup_scanner() {
472 const GScannerConfig scan_config = {
474 "\t\r\n"
475 ) /* cset_skip_characters */,
477 G_CSET_a_2_z
478 "_#"
479 G_CSET_A_2_Z
480 ) /* cset_identifier_first */,
482 G_CSET_a_2_z
483 "_0123456789"
484 G_CSET_A_2_Z
485 G_CSET_LATINS
486 G_CSET_LATINC
487 ) /* cset_identifier_nth */,
488 ( "" ) /* cpair_comment_single */,
490 TRUE /* case_sensitive */,
492 FALSE /* skip_comment_multi */,
493 FALSE /* skip_comment_single */,
494 FALSE /* scan_comment_multi */,
495 TRUE /* scan_identifier */,
496 TRUE /* scan_identifier_1char */,
497 FALSE /* scan_identifier_NULL */,
498 TRUE /* scan_symbols */,
499 FALSE /* scan_binary */,
500 FALSE /* scan_octal */,
501 FALSE /* scan_float */,
502 FALSE /* scan_hex */,
503 FALSE /* scan_hex_dollar */,
504 FALSE /* scan_string_sq */,
505 FALSE /* scan_string_dq */,
506 TRUE /* numbers_2_int */,
507 FALSE /* int_2_float */,
508 FALSE /* identifier_2_string */,
509 FALSE /* char_2_token */,
510 FALSE /* symbol_2_token */,
511 TRUE /* scope_0_fallback */,
512 FALSE,
513 TRUE
516 uzbl.scan = g_scanner_new(&scan_config);
517 while(symp->symbol_name) {
518 g_scanner_scope_add_symbol(uzbl.scan, 0,
519 symp->symbol_name,
520 GINT_TO_POINTER(symp->symbol_token));
521 symp++;
525 static gchar *
526 parse_status_template(const char *template) {
527 GTokenType token = G_TOKEN_NONE;
528 GString *ret = g_string_new("");
529 gchar *buf=NULL;
530 int sym;
532 if(!template)
533 return NULL;
535 g_scanner_input_text(uzbl.scan, template, strlen(template));
536 while(!g_scanner_eof(uzbl.scan) && token != G_TOKEN_LAST) {
537 token = g_scanner_get_next_token(uzbl.scan);
539 if(token == G_TOKEN_SYMBOL) {
540 sym = (int)g_scanner_cur_value(uzbl.scan).v_symbol;
541 switch(sym) {
542 case SYM_URI:
543 g_string_append(ret,
544 uzbl.state.uri?
545 g_markup_printf_escaped("%s", uzbl.state.uri):"");
546 break;
547 case SYM_LOADPRGS:
548 g_string_append(ret, itos(uzbl.gui.sbar.load_progress));
549 break;
550 case SYM_LOADPRGSBAR:
551 buf = build_progressbar_ascii(uzbl.gui.sbar.load_progress);
552 g_string_append(ret, buf);
553 g_free(buf);
554 break;
555 case SYM_TITLE:
556 g_string_append(ret,
557 uzbl.gui.main_title?
558 g_markup_printf_escaped("%s", uzbl.gui.main_title):"");
559 break;
560 case SYM_NAME:
561 g_string_append(ret,
562 uzbl.state.instance_name?uzbl.state.instance_name:itos(uzbl.xwin));
563 break;
564 case SYM_KEYCMD:
565 g_string_append(ret,
566 uzbl.state.keycmd->str ?
567 g_markup_printf_escaped("%s", uzbl.state.keycmd->str):"");
568 break;
569 case SYM_MODE:
570 g_string_append(ret,
571 uzbl.behave.insert_mode?"[I]":"[C]");
572 break;
573 default:
574 break;
577 else if(token == G_TOKEN_INT) {
578 g_string_append(ret, itos(g_scanner_cur_value(uzbl.scan).v_int));
580 else if(token == G_TOKEN_IDENTIFIER) {
581 g_string_append(ret, (gchar *)g_scanner_cur_value(uzbl.scan).v_identifier);
583 else if(token == G_TOKEN_CHAR) {
584 g_string_append_c(ret, (gchar)g_scanner_cur_value(uzbl.scan).v_char);
588 return g_string_free(ret, FALSE);
590 /* --End Statusbar functions-- */
593 // make sure to put '' around args, so that if there is whitespace we can still keep arguments together.
594 static gboolean
595 run_command_async(const char *command, const char *args) {
596 //command <uzbl conf> <uzbl pid> <uzbl win id> <uzbl fifo file> <uzbl socket file> [args]
597 GString* to_execute = g_string_new ("");
598 gboolean result;
599 g_string_printf (to_execute, "%s '%s' '%i' '%i' '%s' '%s'",
600 command, uzbl.state.config_file, (int) getpid() ,
601 (int) uzbl.xwin, uzbl.comm.fifo_path, uzbl.comm.socket_path);
602 g_string_append_printf (to_execute, " '%s' '%s'",
603 uzbl.state.uri, "TODO title here");
604 if(args) {
605 g_string_append_printf (to_execute, " %s", args);
607 result = g_spawn_command_line_async (to_execute->str, NULL);
608 printf("Called %s. Result: %s\n", to_execute->str, (result ? "TRUE" : "FALSE" ));
609 g_string_free (to_execute, TRUE);
610 return result;
613 static gboolean
614 run_command_sync(const char *command, const char *args, char **stdout) {
615 //command <uzbl conf> <uzbl pid> <uzbl win id> <uzbl fifo file> <uzbl socket file> [args]
616 GString* to_execute = g_string_new ("");
617 gboolean result;
618 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);
619 g_string_append_printf (to_execute, " '%s' '%s'", uzbl.state.uri, "TODO title here");
620 if(args) {
621 g_string_append_printf (to_execute, " %s", args);
623 result = g_spawn_command_line_sync (to_execute->str, stdout, NULL, NULL, NULL);
624 printf("Called %s. Result: %s\n", to_execute->str, (result ? "TRUE" : "FALSE" ));
625 g_string_free (to_execute, TRUE);
626 return result;
629 static void
630 spawn(WebKitWebView *web_view, const char *param) {
631 (void)web_view;
632 run_command_async(param, NULL);
635 static void
636 parse_command(const char *cmd, const char *param) {
637 Command c;
639 if ((c = g_hash_table_lookup(uzbl.behave.commands, cmd)))
640 c(uzbl.gui.web_view, param);
641 else
642 fprintf (stderr, "command \"%s\" not understood. ignoring.\n", cmd);
645 static void
646 parse_line(char *line) {
647 gchar **parts;
649 g_strstrip(line);
651 parts = g_strsplit(line, " ", 2);
653 if (!parts)
654 return;
656 parse_command(parts[0], parts[1]);
658 g_strfreev(parts);
661 void
662 build_stream_name(int type) {
663 char *xwin_str;
664 State *s = &uzbl.state;
665 Behaviour *b = &uzbl.behave;
667 xwin_str = itos((int)uzbl.xwin);
668 switch(type) {
669 case FIFO:
670 if (b->fifo_dir) {
671 sprintf (uzbl.comm.fifo_path, "%s/uzbl_fifo_%s",
672 b->fifo_dir,
673 s->instance_name ? s->instance_name : xwin_str);
674 } else {
675 sprintf (uzbl.comm.fifo_path, "/tmp/uzbl_fifo_%s",
676 s->instance_name ? s->instance_name : xwin_str);
678 break;
680 case SOCKET:
681 if (b->socket_dir) {
682 sprintf (uzbl.comm.socket_path, "%s/uzbl_socket_%s",
683 b->socket_dir,
684 s->instance_name ? s->instance_name : xwin_str);
685 } else {
686 sprintf (uzbl.comm.socket_path, "/tmp/uzbl_socket_%s",
687 s->instance_name ? s->instance_name : xwin_str);
689 break;
690 default:
691 break;
693 g_free(xwin_str);
696 static void
697 control_fifo(GIOChannel *gio, GIOCondition condition) {
698 printf("triggered\n");
699 gchar *ctl_line;
700 GIOStatus ret;
701 GError *err = NULL;
703 if (condition & G_IO_HUP)
704 g_error ("Fifo: Read end of pipe died!\n");
706 if(!gio)
707 g_error ("Fifo: GIOChannel broke\n");
709 ret = g_io_channel_read_line(gio, &ctl_line, NULL, NULL, &err);
710 if (ret == G_IO_STATUS_ERROR)
711 g_error ("Fifo: Error reading: %s\n", err->message);
713 parse_line(ctl_line);
714 g_free(ctl_line);
715 printf("...done\n");
716 return;
719 static void
720 create_fifo() {
721 GIOChannel *chan = NULL;
722 GError *error = NULL;
724 build_stream_name(FIFO);
725 if (file_exists(uzbl.comm.fifo_path)) {
726 g_error ("Fifo: Error when creating %s: File exists\n", uzbl.comm.fifo_path);
727 return;
729 if (mkfifo (uzbl.comm.fifo_path, 0666) == -1) {
730 g_error ("Fifo: Error when creating %s: %s\n", uzbl.comm.fifo_path, strerror(errno));
731 } else {
732 // 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.
733 chan = g_io_channel_new_file((gchar *) uzbl.comm.fifo_path, "r+", &error);
734 if (chan) {
735 if (!g_io_add_watch(chan, G_IO_IN|G_IO_HUP, (GIOFunc) control_fifo, NULL)) {
736 g_error ("Fifo: could not add watch on %s\n", uzbl.comm.fifo_path);
737 } else {
738 printf ("Fifo: created successfully as %s\n", uzbl.comm.fifo_path);
740 } else {
741 g_error ("Fifo: Error while opening: %s\n", error->message);
744 return;
747 static gboolean
748 get_var_value(gchar *name) {
749 void **p = NULL;
751 if( (p = g_hash_table_lookup(uzbl.comm.proto_var, name)) ) {
752 if(!strcmp(name, "name")) {
753 printf("VAR: %s VALUE: %s\n", name, (char *)*p);
754 } else {
755 printf("VAR: %s VALUE: %d\n", name, (int)*p);
758 return TRUE;
761 static gboolean
762 set_var_value(gchar *name, gchar *val) {
763 void **p = NULL;
764 char *endp = NULL;
766 if( (p = g_hash_table_lookup(uzbl.comm.proto_var, name)) ) {
767 if(!strcmp(name, "status_format")) {
768 free(*p);
769 *p = g_strdup(val);
770 update_title();
772 /* variables that take int values */
773 else {
774 *p = (int)strtoul(val, &endp, 10);
776 if(!strcmp(name, "show_status")) {
777 cmd_set_status();
781 return TRUE;
784 static void
785 setup_regex() {
786 GError *err=NULL;
788 uzbl.comm.get_regex = g_regex_new("^GET\\s+([^ \\n]+)$", 0, 0, &err);
789 uzbl.comm.set_regex = g_regex_new("^SET\\s+([^ ]+)\\s*=\\s*([^\\n].*)$", 0, 0, &err);
790 uzbl.comm.bind_regex = g_regex_new("^BIND\\s+(.*[^ ])\\s*=\\s*([a-z][^\\n].+)$", 0, 0, &err);
793 static gboolean
794 control_stdin(GIOChannel *gio, GIOCondition condition) {
795 gchar *ctl_line = NULL;
796 gsize ctl_line_len = 0;
797 GIOStatus ret;
798 GError *err = NULL;
799 gchar **tokens;
801 if (condition & G_IO_HUP) {
802 ret = g_io_channel_shutdown (gio, FALSE, &err);
803 return FALSE;
806 ret = g_io_channel_read_line(gio, &ctl_line, &ctl_line_len, NULL, &err);
807 if ( (ret == G_IO_STATUS_ERROR) || (ret == G_IO_STATUS_EOF) )
808 return FALSE;
810 /* SET command */
811 if(ctl_line[0] == 'S') {
812 tokens = g_regex_split(uzbl.comm.set_regex, ctl_line, 0);
813 if(tokens[0][0] == 0) {
814 set_var_value(tokens[1], tokens[2]);
815 g_strfreev(tokens);
817 else
818 printf("Error in command: %s\n", tokens[0]);
820 /* GET command */
821 else if(ctl_line[0] == 'G') {
822 tokens = g_regex_split(uzbl.comm.get_regex, ctl_line, 0);
823 if(tokens[0][0] == 0) {
824 get_var_value(tokens[1]);
825 g_strfreev(tokens);
827 else
828 printf("Error in command: %s\n", tokens[0]);
830 /* BIND command */
831 else if(ctl_line[0] == 'B') {
832 tokens = g_regex_split(uzbl.comm.bind_regex, ctl_line, 0);
833 if(tokens[0][0] == 0) {
834 add_binding(tokens[1], tokens[2]);
835 g_strfreev(tokens);
837 else
838 printf("Error in command: %s\n", tokens[0]);
840 else
841 printf("Command not understood (%s)\n", ctl_line);
843 g_free(ctl_line);
845 return TRUE;
848 static void
849 create_stdin () {
850 GIOChannel *chan = NULL;
851 GError *error = NULL;
853 chan = g_io_channel_unix_new(fileno(stdin));
854 if (chan) {
855 if (!g_io_add_watch(chan, G_IO_IN|G_IO_HUP, (GIOFunc) control_stdin, NULL)) {
856 g_error ("Stdin: could not add watch\n");
857 } else {
858 printf ("Stdin: watch added successfully\n");
860 } else {
861 g_error ("Stdin: Error while opening: %s\n", error->message);
865 static void
866 control_socket(GIOChannel *chan) {
867 struct sockaddr_un remote;
868 char buffer[512], *ctl_line;
869 char temp[128];
870 int sock, clientsock, n, done;
871 unsigned int t;
873 sock = g_io_channel_unix_get_fd(chan);
875 memset (buffer, 0, sizeof (buffer));
877 t = sizeof (remote);
878 clientsock = accept (sock, (struct sockaddr *) &remote, &t);
880 done = 0;
881 do {
882 memset (temp, 0, sizeof (temp));
883 n = recv (clientsock, temp, 128, 0);
884 if (n == 0) {
885 buffer[strlen (buffer)] = '\0';
886 done = 1;
888 if (!done)
889 strcat (buffer, temp);
890 } while (!done);
892 if (strcmp (buffer, "\n") < 0) {
893 buffer[strlen (buffer) - 1] = '\0';
894 } else {
895 buffer[strlen (buffer)] = '\0';
897 close (clientsock);
898 ctl_line = g_strdup(buffer);
899 parse_line (ctl_line);
902 TODO: we should be able to do it with this. but glib errors out with "Invalid argument"
903 GError *error = NULL;
904 gsize len;
905 GIOStatus ret;
906 ret = g_io_channel_read_line(chan, &ctl_line, &len, NULL, &error);
907 if (ret == G_IO_STATUS_ERROR)
908 g_error ("Error reading: %s\n", error->message);
910 printf("Got line %s (%u bytes) \n",ctl_line, len);
911 if(ctl_line) {
912 parse_line(ctl_line);
915 g_free(ctl_line);
916 return;
919 static void
920 create_socket() {
921 GIOChannel *chan = NULL;
922 int sock, len;
923 struct sockaddr_un local;
925 build_stream_name(SOCKET);
926 sock = socket (AF_UNIX, SOCK_STREAM, 0);
928 local.sun_family = AF_UNIX;
929 strcpy (local.sun_path, uzbl.comm.socket_path);
930 unlink (local.sun_path);
932 len = strlen (local.sun_path) + sizeof (local.sun_family);
933 bind (sock, (struct sockaddr *) &local, len);
935 if (errno == -1) {
936 printf ("Socket: Could not open in %s: %s\n", uzbl.comm.socket_path, strerror(errno));
937 } else {
938 printf ("Socket: Opened in %s\n", uzbl.comm.socket_path);
939 listen (sock, 5);
941 if( (chan = g_io_channel_unix_new(sock)) )
942 g_io_add_watch(chan, G_IO_IN|G_IO_HUP, (GIOFunc) control_socket, chan);
946 static void
947 update_title (void) {
948 GString* string_long = g_string_new ("");
949 GString* string_short = g_string_new ("");
950 char* iname = NULL;
951 gchar *statln;
952 int iname_len;
953 State *s = &uzbl.state;
954 Behaviour *b = &uzbl.behave;
956 if(s->instance_name) {
957 iname_len = strlen(s->instance_name)+4;
958 iname = malloc(iname_len);
959 snprintf(iname, iname_len, "<%s> ", s->instance_name);
961 g_string_prepend(string_long, iname);
962 g_string_prepend(string_short, iname);
963 free(iname);
966 g_string_append_printf(string_long, "%s ", s->keycmd->str);
967 if (!b->always_insert_mode)
968 g_string_append (string_long, (b->insert_mode ? "[I] " : "[C] "));
969 if (uzbl.gui.main_title) {
970 g_string_append (string_long, uzbl.gui.main_title);
971 g_string_append (string_short, uzbl.gui.main_title);
973 g_string_append (string_long, " - Uzbl browser");
974 g_string_append (string_short, " - Uzbl browser");
975 if (s->selected_url[0]!=0) {
976 g_string_append_printf (string_long, " -> (%s)", s->selected_url);
979 gchar* title_long = g_string_free (string_long, FALSE);
980 gchar* title_short = g_string_free (string_short, FALSE);
982 if (b->show_status) {
983 gtk_window_set_title (GTK_WINDOW(uzbl.gui.main_window), title_short);
984 // TODO: we should probably not do this every time we want to update the title..?
985 statln = parse_status_template(uzbl.behave.status_format);
986 gtk_label_set_markup(GTK_LABEL(uzbl.gui.mainbar_label), statln);
987 if (b->status_background) {
988 GdkColor color;
989 gdk_color_parse (b->status_background, &color);
990 //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)
991 gtk_widget_modify_bg (uzbl.gui.main_window, GTK_STATE_NORMAL, &color);
993 g_free(statln);
994 } else {
995 gtk_window_set_title (GTK_WINDOW(uzbl.gui.main_window), title_long);
998 g_free (title_long);
999 g_free (title_short);
1002 static gboolean
1003 key_press_cb (WebKitWebView* page, GdkEventKey* event)
1005 //TRUE to stop other handlers from being invoked for the event. FALSE to propagate the event further.
1007 (void) page;
1008 Action *action;
1010 if (event->type != GDK_KEY_PRESS || event->keyval == GDK_Page_Up || event->keyval == GDK_Page_Down
1011 || event->keyval == GDK_Up || event->keyval == GDK_Down || event->keyval == GDK_Left || event->keyval == GDK_Right)
1012 return FALSE;
1014 /* turn off insert mode (if always_insert_mode is not used) */
1015 if (uzbl.behave.insert_mode && (event->keyval == GDK_Escape)) {
1016 uzbl.behave.insert_mode = uzbl.behave.always_insert_mode;
1017 update_title();
1018 return TRUE;
1021 if (uzbl.behave.insert_mode && ((event->state & uzbl.behave.modmask) != uzbl.behave.modmask))
1022 return FALSE;
1024 if (event->keyval == GDK_Escape) {
1025 g_string_truncate(uzbl.state.keycmd, 0);
1026 update_title();
1027 return TRUE;
1030 //Insert without shift - insert from clipboard; Insert with shift - insert from primary
1031 if (event->keyval == GDK_Insert) {
1032 gchar * str;
1033 if ((event->state & GDK_SHIFT_MASK) == GDK_SHIFT_MASK) {
1034 str = gtk_clipboard_wait_for_text (gtk_clipboard_get (GDK_SELECTION_PRIMARY));
1035 } else {
1036 str = gtk_clipboard_wait_for_text (gtk_clipboard_get (GDK_SELECTION_CLIPBOARD));
1038 if (str) {
1039 g_string_append_printf (uzbl.state.keycmd, "%s", str);
1040 update_title ();
1041 free (str);
1043 return TRUE;
1046 if ((event->keyval == GDK_BackSpace) && (uzbl.state.keycmd->len > 0)) {
1047 g_string_truncate(uzbl.state.keycmd, uzbl.state.keycmd->len - 1);
1048 update_title();
1049 return TRUE;
1052 if ((event->keyval == GDK_Return) || (event->keyval == GDK_KP_Enter)) {
1053 GString* short_keys = g_string_new ("");
1054 unsigned int i;
1055 for (i=0; i<(uzbl.state.keycmd->len); i++) {
1056 g_string_append_c(short_keys, uzbl.state.keycmd->str[i]);
1057 g_string_append_c(short_keys, '_');
1059 //printf("\nTesting string: @%s@\n", short_keys->str);
1060 if ((action = g_hash_table_lookup(uzbl.bindings, short_keys->str))) {
1061 GString* parampart = g_string_new (uzbl.state.keycmd->str);
1062 g_string_erase (parampart, 0, i+1);
1063 //printf("\nParameter: @%s@\n", parampart->str);
1064 GString* actionname = g_string_new ("");
1065 if (action->name)
1066 g_string_printf (actionname, action->name, parampart->str);
1067 GString* actionparam = g_string_new ("");
1068 if (action->param)
1069 g_string_printf (actionparam, action->param, parampart->str);
1070 parse_command(actionname->str, actionparam->str);
1071 g_string_free (actionname, TRUE);
1072 g_string_free (actionparam, TRUE);
1073 g_string_free (parampart, TRUE);
1074 g_string_truncate(uzbl.state.keycmd, 0);
1075 update_title();
1078 g_string_truncate(short_keys, short_keys->len - 1);
1080 g_string_free (short_keys, TRUE);
1081 return (!uzbl.behave.insert_mode);
1084 g_string_append(uzbl.state.keycmd, event->string);
1085 if ((action = g_hash_table_lookup(uzbl.bindings, uzbl.state.keycmd->str))) {
1086 g_string_truncate(uzbl.state.keycmd, 0);
1087 parse_command(action->name, action->param);
1090 update_title();
1092 return TRUE;
1095 static GtkWidget*
1096 create_browser () {
1097 GUI *g = &uzbl.gui;
1099 GtkWidget* scrolled_window = gtk_scrolled_window_new (NULL, NULL);
1100 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
1102 g->web_view = WEBKIT_WEB_VIEW (webkit_web_view_new ());
1103 gtk_container_add (GTK_CONTAINER (scrolled_window), GTK_WIDGET (g->web_view));
1105 g_signal_connect (G_OBJECT (g->web_view), "title-changed", G_CALLBACK (title_change_cb), g->web_view);
1106 g_signal_connect (G_OBJECT (g->web_view), "load-progress-changed", G_CALLBACK (progress_change_cb), g->web_view);
1107 g_signal_connect (G_OBJECT (g->web_view), "load-committed", G_CALLBACK (load_commit_cb), g->web_view);
1108 g_signal_connect (G_OBJECT (g->web_view), "load-committed", G_CALLBACK (log_history_cb), g->web_view);
1109 g_signal_connect (G_OBJECT (g->web_view), "hovering-over-link", G_CALLBACK (link_hover_cb), g->web_view);
1110 g_signal_connect (G_OBJECT (g->web_view), "key-press-event", G_CALLBACK (key_press_cb), g->web_view);
1111 g_signal_connect (G_OBJECT (g->web_view), "new-window-policy-decision-requested", G_CALLBACK (new_window_cb), g->web_view);
1112 g_signal_connect (G_OBJECT (g->web_view), "download-requested", G_CALLBACK (download_cb), g->web_view);
1113 g_signal_connect (G_OBJECT (g->web_view), "create-web-view", G_CALLBACK (create_web_view_cb), g->web_view);
1115 return scrolled_window;
1118 static GtkWidget*
1119 create_mainbar () {
1120 GUI *g = &uzbl.gui;
1122 g->mainbar = gtk_hbox_new (FALSE, 0);
1123 g->mainbar_label = gtk_label_new ("");
1124 gtk_label_set_selectable((GtkLabel *)g->mainbar_label, TRUE);
1125 gtk_label_set_ellipsize(GTK_LABEL(g->mainbar_label), PANGO_ELLIPSIZE_END);
1126 gtk_misc_set_alignment (GTK_MISC(g->mainbar_label), 0, 0);
1127 gtk_misc_set_padding (GTK_MISC(g->mainbar_label), 2, 2);
1128 gtk_box_pack_start (GTK_BOX (g->mainbar), g->mainbar_label, TRUE, TRUE, 0);
1129 return g->mainbar;
1132 static
1133 GtkWidget* create_window () {
1134 GtkWidget* window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
1135 gtk_window_set_default_size (GTK_WINDOW (window), 800, 600);
1136 gtk_widget_set_name (window, "Uzbl browser");
1137 g_signal_connect (G_OBJECT (window), "destroy", G_CALLBACK (destroy_cb), NULL);
1139 return window;
1142 static void
1143 add_binding (const gchar *key, const gchar *act) {
1144 char **parts = g_strsplit(act, " ", 2);
1145 Action *action;
1147 if (!parts)
1148 return;
1150 //Debug:
1151 printf ("Binding %-10s : %s\n", key, act);
1152 action = new_action(parts[0], parts[1]);
1153 g_hash_table_insert(uzbl.bindings, g_strdup(key), action);
1155 g_strfreev(parts);
1158 static void
1159 settings_init () {
1160 GKeyFile* config = NULL;
1161 gboolean res = FALSE;
1162 char *saveptr;
1163 gchar** keys = NULL;
1164 State *s = &uzbl.state;
1165 Network *n = &uzbl.net;
1166 Behaviour *b = &uzbl.behave;
1168 if (!s->config_file) {
1169 const char* XDG_CONFIG_HOME = getenv ("XDG_CONFIG_HOME");
1170 if (! XDG_CONFIG_HOME || ! strcmp (XDG_CONFIG_HOME, "")) {
1171 XDG_CONFIG_HOME = (char*)XDG_CONFIG_HOME_default;
1173 printf("XDG_CONFIG_HOME: %s\n", XDG_CONFIG_HOME);
1175 strcpy (s->config_file_path, XDG_CONFIG_HOME);
1176 strcat (s->config_file_path, "/uzbl/config");
1177 if (file_exists (s->config_file_path)) {
1178 printf ("Config file %s found.\n", s->config_file_path);
1179 s->config_file = &s->config_file_path[0];
1180 } else {
1181 // Now we check $XDG_CONFIG_DIRS
1182 char *XDG_CONFIG_DIRS = getenv ("XDG_CONFIG_DIRS");
1183 if (! XDG_CONFIG_DIRS || ! strcmp (XDG_CONFIG_DIRS, ""))
1184 XDG_CONFIG_DIRS = XDG_CONFIG_DIRS_default;
1186 printf("XDG_CONFIG_DIRS: %s\n", XDG_CONFIG_DIRS);
1188 char buffer[512];
1189 strcpy (buffer, XDG_CONFIG_DIRS);
1190 const gchar* dir = (char *) strtok_r (buffer, ":", &saveptr);
1191 while (dir && ! file_exists (s->config_file_path)) {
1192 strcpy (s->config_file_path, dir);
1193 strcat (s->config_file_path, "/uzbl/config_file_pathig");
1194 if (file_exists (s->config_file_path)) {
1195 printf ("Config file %s found.\n", s->config_file_path);
1196 s->config_file = &s->config_file_path[0];
1198 dir = (char * ) strtok_r (NULL, ":", &saveptr);
1203 if (s->config_file) {
1204 config = g_key_file_new ();
1205 res = g_key_file_load_from_file (config, s->config_file, G_KEY_FILE_NONE, NULL);
1206 if (res) {
1207 printf ("Config %s loaded\n", s->config_file);
1208 } else {
1209 fprintf (stderr, "Config %s loading failed\n", s->config_file);
1211 } else {
1212 printf ("No configuration.\n");
1215 if (res) {
1216 b->history_handler = g_key_file_get_value (config, "behavior", "history_handler", NULL);
1217 b->download_handler = g_key_file_get_value (config, "behavior", "download_handler", NULL);
1218 b->cookie_handler = g_key_file_get_string (config, "behavior", "cookie_handler", NULL);
1219 b->always_insert_mode = g_key_file_get_boolean (config, "behavior", "always_insert_mode", NULL);
1220 b->show_status = g_key_file_get_boolean (config, "behavior", "show_status", NULL);
1221 b->modkey = g_key_file_get_value (config, "behavior", "modkey", NULL);
1222 b->status_top = g_key_file_get_boolean (config, "behavior", "status_top", NULL);
1223 b->status_format = g_key_file_get_string (config, "behavior", "status_format", NULL);
1224 b->status_background = g_key_file_get_string (config, "behavior", "status_background", NULL);
1225 if (! b->fifo_dir)
1226 b->fifo_dir = g_key_file_get_value (config, "behavior", "fifo_dir", NULL);
1227 if (! b->socket_dir)
1228 b->socket_dir = g_key_file_get_value (config, "behavior", "socket_dir", NULL);
1229 keys = g_key_file_get_keys (config, "bindings", NULL, NULL);
1232 printf ("History handler: %s\n", (b->history_handler ? b->history_handler : "disabled"));
1233 printf ("Download manager: %s\n", (b->download_handler ? b->download_handler : "disabled"));
1234 printf ("Cookie handler: %s\n", (b->cookie_handler ? b->cookie_handler : "disabled"));
1235 printf ("Fifo directory: %s\n", (b->fifo_dir ? b->fifo_dir : "disabled"));
1236 printf ("Socket directory: %s\n", (b->socket_dir ? b->socket_dir : "disabled"));
1237 printf ("Always insert mode: %s\n", (b->always_insert_mode ? "TRUE" : "FALSE"));
1238 printf ("Show status: %s\n", (b->show_status ? "TRUE" : "FALSE"));
1239 printf ("Status top: %s\n", (b->status_top ? "TRUE" : "FALSE"));
1240 printf ("Modkey: %s\n", (b->modkey ? b->modkey : "disabled"));
1241 printf ("Status format: %s\n", (b->status_format ? b->status_format : "none"));
1243 if (!b->modkey)
1244 b->modkey = "";
1246 //POSSIBLE MODKEY VALUES (COMBINATIONS CAN BE USED)
1247 gchar* modkeyup = g_utf8_strup (b->modkey, -1);
1248 if (g_strrstr (modkeyup,"SHIFT") != NULL) b->modmask |= GDK_SHIFT_MASK; //the Shift key.
1249 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).
1250 if (g_strrstr (modkeyup,"CONTROL") != NULL) b->modmask |= GDK_CONTROL_MASK; //the Control key.
1251 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).
1252 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).
1253 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).
1254 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).
1255 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).
1256 if (g_strrstr (modkeyup,"BUTTON1") != NULL) b->modmask |= GDK_BUTTON1_MASK; //the first mouse button.
1257 if (g_strrstr (modkeyup,"BUTTON2") != NULL) b->modmask |= GDK_BUTTON2_MASK; //the second mouse button.
1258 if (g_strrstr (modkeyup,"BUTTON3") != NULL) b->modmask |= GDK_BUTTON3_MASK; //the third mouse button.
1259 if (g_strrstr (modkeyup,"BUTTON4") != NULL) b->modmask |= GDK_BUTTON4_MASK; //the fourth mouse button.
1260 if (g_strrstr (modkeyup,"BUTTON5") != NULL) b->modmask |= GDK_BUTTON5_MASK; //the fifth mouse button.
1261 if (g_strrstr (modkeyup,"SUPER") != NULL) b->modmask |= GDK_SUPER_MASK; //the Super modifier. Since 2.10
1262 if (g_strrstr (modkeyup,"HYPER") != NULL) b->modmask |= GDK_HYPER_MASK; //the Hyper modifier. Since 2.10
1263 if (g_strrstr (modkeyup,"META") != NULL) b->modmask |= GDK_META_MASK; //the Meta modifier. Since 2.10 */
1264 free (modkeyup);
1266 if (keys) {
1267 int i;
1268 for (i = 0; keys[i]; i++) {
1269 gchar *value = g_key_file_get_string (config, "bindings", keys[i], NULL);
1271 add_binding(g_strstrip(keys[i]), value);
1272 g_free(value);
1275 g_strfreev(keys);
1278 /* networking options */
1279 if (res) {
1280 n->proxy_url = g_key_file_get_value (config, "network", "proxy_server", NULL);
1281 b->http_debug = g_key_file_get_integer (config, "network", "http_debug", NULL);
1282 n->useragent = g_key_file_get_value (config, "network", "user-agent", NULL);
1283 n->max_conns = g_key_file_get_integer (config, "network", "max_conns", NULL);
1284 n->max_conns_host = g_key_file_get_integer (config, "network", "max_conns_per_host", NULL);
1287 if(n->proxy_url){
1288 g_object_set(G_OBJECT(n->soup_session), SOUP_SESSION_PROXY_URI, soup_uri_new(n->proxy_url), NULL);
1291 if(!(b->http_debug <= 3)){
1292 b->http_debug = 0;
1293 fprintf(stderr, "Wrong http_debug level, ignoring.\n");
1294 } else if (b->http_debug > 0) {
1295 n->soup_logger = soup_logger_new(b->http_debug, -1);
1296 soup_session_add_feature(n->soup_session, SOUP_SESSION_FEATURE(n->soup_logger));
1299 if(n->useragent){
1300 char* newagent = malloc(1024);
1302 strcpy(newagent, str_replace("%webkit-major%", itos(WEBKIT_MAJOR_VERSION), n->useragent));
1303 strcpy(newagent, str_replace("%webkit-minor%", itos(WEBKIT_MINOR_VERSION), newagent));
1304 strcpy(newagent, str_replace("%webkit-micro%", itos(WEBKIT_MICRO_VERSION), newagent));
1306 if (uname (&s->unameinfo) == -1) {
1307 printf("Error getting uname info. Not replacing system-related user agent variables.\n");
1308 } else {
1309 strcpy(newagent, str_replace("%sysname%", s->unameinfo.sysname, newagent));
1310 strcpy(newagent, str_replace("%nodename%", s->unameinfo.nodename, newagent));
1311 strcpy(newagent, str_replace("%kernrel%", s->unameinfo.release, newagent));
1312 strcpy(newagent, str_replace("%kernver%", s->unameinfo.version, newagent));
1313 strcpy(newagent, str_replace("%arch-system%", s->unameinfo.machine, newagent));
1315 #ifdef _GNU_SOURCE
1316 strcpy(newagent, str_replace("%domainname%", s->unameinfo.domainname, newagent));
1317 #endif
1320 strcpy(newagent, str_replace("%arch-uzbl%", ARCH, newagent));
1321 strcpy(newagent, str_replace("%commit%", COMMIT, newagent));
1323 n->useragent = malloc(1024);
1324 strcpy(n->useragent, newagent);
1325 g_object_set(G_OBJECT(n->soup_session), SOUP_SESSION_USER_AGENT, n->useragent, NULL);
1328 if(n->max_conns >= 1){
1329 g_object_set(G_OBJECT(n->soup_session), SOUP_SESSION_MAX_CONNS, n->max_conns, NULL);
1332 if(n->max_conns_host >= 1){
1333 g_object_set(G_OBJECT(n->soup_session), SOUP_SESSION_MAX_CONNS_PER_HOST, n->max_conns_host, NULL);
1336 printf("Proxy configured: %s\n", n->proxy_url ? n->proxy_url : "none");
1337 printf("HTTP logging level: %d\n", b->http_debug);
1338 printf("User-agent: %s\n", n->useragent? n->useragent : "default");
1339 printf("Maximum connections: %d\n", n->max_conns ? n->max_conns : 0);
1340 printf("Maximum connections per host: %d\n", n->max_conns_host ? n->max_conns_host: 0);
1344 if(b->cookie_handler){
1345 /* ck = soup_cookie_jar_new(); */
1346 /* soup_session_add_feature(soup_session, SOUP_SESSION_FEATURE(ck)); */
1347 /* g_signal_connect(ck, "changed", G_CALLBACK(cookie_recieved_action), NULL); */
1348 g_signal_connect(n->soup_session, "request-queued", G_CALLBACK(handle_cookies), NULL);
1353 static void handle_cookies (SoupSession *session, SoupMessage *msg, gpointer user_data){
1354 (void) session;
1355 (void) user_data;
1356 gchar * stdout = NULL;
1357 soup_message_add_header_handler(msg, "got-headers", "Set-Cookie", G_CALLBACK(save_cookies), NULL);
1358 GString* args = g_string_new ("");
1359 SoupURI * soup_uri = soup_message_get_uri(msg);
1360 g_string_printf (args, "GET %s %s", soup_uri->host, soup_uri->path);
1361 run_command_sync(uzbl.behave.cookie_handler, args->str, &stdout);
1362 if(stdout) {
1363 soup_message_headers_replace (msg->request_headers, "Cookie", stdout);
1365 g_string_free(args, TRUE);
1368 static void
1369 save_cookies (SoupMessage *msg, gpointer user_data){
1370 (void) user_data;
1371 GSList *ck;
1372 char *cookie;
1373 for (ck = soup_cookies_from_response(msg); ck; ck = ck->next){
1374 cookie = soup_cookie_to_set_cookie_header(ck->data);
1375 GString* args = g_string_new ("");
1376 SoupURI * soup_uri = soup_message_get_uri(msg);
1377 g_string_printf (args, "PUT %s %s \"%s\"", soup_uri->host, soup_uri->path, cookie);
1378 run_command_async(uzbl.behave.cookie_handler, args->str);
1379 g_string_free(args, TRUE);
1380 free(cookie);
1382 g_slist_free(ck);
1386 main (int argc, char* argv[]) {
1387 gtk_init (&argc, &argv);
1388 if (!g_thread_supported ())
1389 g_thread_init (NULL);
1391 printf("Uzbl start location: %s\n", argv[0]);
1392 strcpy(uzbl.state.executable_path,argv[0]);
1394 strcat ((char *) XDG_CONFIG_HOME_default, getenv ("HOME"));
1395 strcat ((char *) XDG_CONFIG_HOME_default, "/.config");
1397 GError *error = NULL;
1398 GOptionContext* context = g_option_context_new ("- some stuff here maybe someday");
1399 g_option_context_add_main_entries (context, entries, NULL);
1400 g_option_context_add_group (context, gtk_get_option_group (TRUE));
1401 g_option_context_parse (context, &argc, &argv, &error);
1402 /* initialize hash table */
1403 uzbl.bindings = g_hash_table_new_full(g_str_hash, g_str_equal, g_free, free_action);
1405 uzbl.net.soup_session = webkit_get_default_session();
1406 uzbl.state.keycmd = g_string_new("");
1408 settings_init ();
1409 commands_hash ();
1411 if (uzbl.behave.always_insert_mode)
1412 uzbl.behave.insert_mode = TRUE;
1414 GtkWidget* vbox = gtk_vbox_new (FALSE, 0);
1415 if (uzbl.behave.status_top)
1416 gtk_box_pack_start (GTK_BOX (vbox), create_mainbar (), FALSE, TRUE, 0);
1417 gtk_box_pack_start (GTK_BOX (vbox), create_browser (), TRUE, TRUE, 0);
1418 if (!uzbl.behave.status_top)
1419 gtk_box_pack_start (GTK_BOX (vbox), create_mainbar (), FALSE, TRUE, 0);
1421 uzbl.gui.main_window = create_window ();
1422 gtk_container_add (GTK_CONTAINER (uzbl.gui.main_window), vbox);
1424 load_uri (uzbl.gui.web_view, uzbl.state.uri);
1426 gtk_widget_grab_focus (GTK_WIDGET (uzbl.gui.web_view));
1427 gtk_widget_show_all (uzbl.gui.main_window);
1428 uzbl.xwin = GDK_WINDOW_XID (GTK_WIDGET (uzbl.gui.main_window)->window);
1429 printf("window_id %i\n",(int) uzbl.xwin);
1430 printf("pid %i\n", getpid ());
1431 printf("name: %s\n", uzbl.state.instance_name);
1433 uzbl.gui.scbar_v = (GtkScrollbar*) gtk_vscrollbar_new (NULL);
1434 uzbl.gui.bar_v = gtk_range_get_adjustment((GtkRange*) uzbl.gui.scbar_v);
1435 uzbl.gui.scbar_h = (GtkScrollbar*) gtk_hscrollbar_new (NULL);
1436 uzbl.gui.bar_h = gtk_range_get_adjustment((GtkRange*) uzbl.gui.scbar_h);
1437 gtk_widget_set_scroll_adjustments ((GtkWidget*) uzbl.gui.web_view, uzbl.gui.bar_h, uzbl.gui.bar_v);
1440 if(setup_signal(SIGTERM, catch_sigterm) == SIG_ERR)
1441 fprintf(stderr, "uzbl: error hooking SIGTERM\n");
1444 setup_regex();
1445 setup_scanner();
1447 if (!uzbl.behave.status_format)
1448 uzbl.behave.status_format = STATUS_DEFAULT;
1449 if (!uzbl.behave.show_status)
1450 gtk_widget_hide(uzbl.gui.mainbar);
1451 else
1452 update_title();
1455 make_var_to_name_hash();
1456 create_stdin();
1457 if (uzbl.behave.fifo_dir)
1458 create_fifo ();
1459 if (uzbl.behave.socket_dir)
1460 create_socket ();
1462 gtk_main ();
1463 clean_up();
1465 return EXIT_SUCCESS;
1468 /* vi: set et ts=4: */