diff options
-rw-r--r-- | .gitignore | 3 | ||||
-rw-r--r-- | CHECKLIST | 18 | ||||
-rw-r--r-- | HOWTO | 3 | ||||
-rw-r--r-- | INSTALLING | 23 | ||||
-rw-r--r-- | Makefile | 4 | ||||
-rw-r--r-- | README | 13 | ||||
-rw-r--r-- | TODO | 27 | ||||
-rw-r--r-- | examples/configs/sampleconfig | 3 | ||||
-rw-r--r-- | examples/configs/sampleconfig-dev | 3 | ||||
-rwxr-xr-x | examples/scripts/download.sh | 2 | ||||
-rwxr-xr-x | examples/scripts/history.sh | 2 | ||||
-rwxr-xr-x | examples/scripts/load_url_from_bookmarks.sh | 5 | ||||
-rwxr-xr-x | examples/scripts/load_url_from_history.sh | 5 | ||||
-rw-r--r-- | uzbl.c | 523 | ||||
-rw-r--r-- | uzblctrl.c | 63 |
15 files changed, 480 insertions, 217 deletions
@@ -1 +1,2 @@ -uzbl
\ No newline at end of file +uzbl +uzblctrl
\ No newline at end of file @@ -6,19 +6,23 @@ Also testers and interested people can use this list to see what uzbl is about, * commandline switches --uri "http://.." and --config should behave as expected * --help and -? should show help -* config loading: loading of settings, bindings and handlers from config file +* config loading: loading of settings, bindings and all behavior settings (including handlers) from config file * fifo: type this in your shell after starting uzbl: echo 'uri http://www...' > <fifo path here>' where <fifo path> is printed on stdout during program startup. Also "back" , "forward", "refresh" (basically all actions defined in `static Command commands` should behave as expected) + -> temporarily changed to socket io with uzblctrl. see examples in scripts * history logging: the script as defined in sample config should write history entries (date,time, url) into the file defined in the script (by default ./extra/history.sh and /tmp/uzbl.history) * invocations of external commands: you'll see it on stdout everytime uzbl calls an external script/program. the invocations should work and none of the arguments passed should be null/garbage/.. . all should be valid strings and contain things like the pid, fifo file, config file,.. (see README for details). -* XDG_CONFIG_HOME and XDG_CONFIG_DIRS (+ default values) fully supported and working (looks for a config file called 'uzbl'). +* XDG_CONFIG_HOME and XDG_CONFIG_DIRS (+ default values) fully supported and working (looks for a config file called 'uzbl/config'). * --uri can be specified without http:// -- if missing will be prepended. -* Download completely finished +* Downloading of files with handler script * Open in new window partially finished: target _new works, from popup meny does not work yet +* Home command working (home_page variable in config) +* Page Up / Page Down / Up / Down / Left / Right for page navigation work in command mode. +* Open in new window completely finished with --config forwarding between instances +* internal keybinds to change things work (as loaded by config) +* vimlike command and insert modes behave as expected +* always_insert_mode and modkey work too +* status bar can be toggled on and off, if off, some info (mode) will be put in title bar. position of statusbar (top/bottom) also works -TODO: add stuff about internal/external keybinds, mod key, insert mode, status bar, -behavior settings,.... - -TODO: add 'http://' to url if there is no substr '://' @@ -1,3 +0,0 @@ -1) get the latest code from master branch -2) make -3) profit ! diff --git a/INSTALLING b/INSTALLING new file mode 100644 index 0000000..0d10d24 --- /dev/null +++ b/INSTALLING @@ -0,0 +1,23 @@ +* Arch Linux: + pkgbuild @ http://aur.archlinux.org/packages.php?ID=25972 + +* From source: + +$ git clone git://github.com/Dieterbe/uzbl.git +[ $ git checkout master/experimental ] # master == fairly stable. experimental is more bleeding edge +$ cd uzbl +$ make +$ sudo make install + +Dependencies: +libwebkit 1.1.4 or higher +gtk 2 something something +pkgconfig (for Make/gcc) + +Optional: +dmenu, zenity, bash for the sample scripts + +You will have the program in /usr/bin and various sample scripts, a sample config, sample bookmarks file and some documentation in /usr/share/uzbl. You +will probably want to change the scripts to behave more like you want, so copy the scripts to your home dir. If you save your config as +$XDG_CONFIG_HOME/uzbl/config (this expands to ~/.config/uzbl/config on most systems) it will be recognized automatically. You can also pass the path to +the config file with the --config parameter. @@ -1,6 +1,6 @@ CPPFLAGS=$(shell pkg-config --cflags gtk+-2.0 webkit-1.0) -Wall -W LDFLAGS=$(shell pkg-config --libs gtk+-2.0 webkit-1.0) -all: uzbl +all: uzbl uzblctrl test: ./uzbl --uri http://www.uzbl.org @@ -13,12 +13,14 @@ test-config-real: clean: rm -f uzbl + rm -f uzblctrl install: install -d $(DESTDIR)/usr/bin install -d $(DESTDIR)/usr/share/uzbl/docs install -d $(DESTDIR)/usr/share/uzbl/examples install -D -m755 uzbl $(DESTDIR)/usr/bin/uzbl + install -D -m755 uzblctrl $(DESTDIR)/usr/bin/uzblctrl cp -ax examples $(DESTDIR)/usr/share/uzbl/ install -D -m644 CHECKLIST $(DESTDIR)/usr/share/uzbl/docs install -D -m644 README $(DESTDIR)/usr/share/uzbl/docs @@ -105,18 +105,19 @@ $1 uzbl-config-file $2 uzbl-pid $3 uzbl-x-window-id $4 uzbl_fifo-filename +$5 uzbl_socket-filename .. [ script specific ] (optional) The script specific arguments are this: * history: - $5 page url - $6 page title - $7 date of visit (Y-m-d H:i:s localtime) + $6 page url + $7 page title + $8 date of visit (Y-m-d H:i:s localtime) * add bookmark: - $5 page url - $6 page title + $6 page url + $7 page title * download: - $5 url + $6 url KNOWN BUGS - Segfaults when using zoom commands (happens when max zoom already reached?). @@ -1,10 +1,8 @@ ASAP -* do a clean implementation of bindings that need arguments (eg insert_bookmark needs the uri.) - * implement all the ideas from README * get a logo * improve site -* Support for binding keyboard shortcuts in config file. +* when launching new instance, don't just try 'uzbl' and then './uzbl', rather launch a new uzbl in the same way the current uzbl instance was started. (same command, same arguments, except --uri) * where to put proxy config? webkit support? * implement XDG basedir spec (config is done, but not cache/data, which I presume we'll need at some point) * check configured commands if they end on .sh so users don't need to prepend /bin/<shell> @@ -13,8 +11,27 @@ ASAP * implement a vimperator-like link following scheme. but let user pick his favorite characters to construct the "link identifiers" with. * add a keybind to hand the current url to an external scrips, so you can edit it and/or store it in the primary and secondary clipboards * use http://library.gnome.org/devel/glib/stable/glib-Hash-Tables.html#g-hash-table-insert for tracking bindings and wherever we use structs and ugly loops -* char *XDG_CONFIG_HOME_default = "~/.config"; where does ~ get expanded? -* fifo -> socket. so you can do question-response. socket is slightly more complicated so we'll need to create a uzblctrl +* fifo -> socket. so you can do question-response. socket is slightly more complicated so we'll need to create a uzblctrl (half done - commands can't yet send data back) +* select/fork based instead of the pthread stuff -> drops dependency, more lightweight. +* on website, see if we can <pre><?php include('..'); ?></pre> the documentation inside the uzbl project itself, so we need to maintain the stuff on only 1 place +* see if we can use the github bugtracker (anonymous posting allowed?) +* allow user to change bindings for navigation (up,down,left,right, page up, page down etc)and use vim-like defaults +* put on uzbl.org that you can use http://github.com/Dieterbe/uzbl/issues after registering +* make default size configurable, and optional +* on uzbl.org commits overview: add date+time and repository +* how to handle different content types? (text-plain, image/png, application/pdf,... maybe a map of content-type to uzbl/command + xdg already has a spec for this i think + different "opening" modes (open as configured vs ask before opening) + integration with download and new window thingies? +* see if/how we can remove /bin/bash from scripts +* unify internal and external bindings. +* unify command triggering, whether they came in through fifo or keybind +* add to bottom /* vi: set et ts=4: */ +* ideal uri editor: awesome mode like FF, some keyb shortcuts (erase search string, go to end/begin of string,..), history (if you patch dmenu to be in vertical mode and you order correctly, that's it), support copy paste +* get rid of the home page concept. allow user to make keybinds to go to one or more "homepages". a home page is nothing special. +* blinking cursor when not in insert mode is confusing. i suggest dimming it's color if possible +* open in new window -> uzbl: Fatal IO error 11 (Resource temporarily unavailable) on X server :0.0. + SOMEDAY: check if we can make the settings loading less hard coded. eg( keep a list of all settings, and for each one, try to load it) diff --git a/examples/configs/sampleconfig b/examples/configs/sampleconfig index d2991af..4cba098 100644 --- a/examples/configs/sampleconfig +++ b/examples/configs/sampleconfig @@ -14,10 +14,12 @@ history_handler = /bin/bash /usr/share/uzbl/examples/scripts/history.sh download_handler = /bin/bash /usr/share/uzbl/examples/scripts/download.sh fifo_dir = /tmp +socket_dir = /tmp always_insert_mode = 0 modkey = Mod1 show_status = 1 status_top = 0 +home_page = http://www.uzbl.org [bindings] b = back @@ -32,6 +34,7 @@ w = follow_link_new_window + = zoom_in - = zoom_out t = toggle_status +k = exit B = spawn /bin/bash /usr/share/uzbl/examples/scripts/insert_bookmark.sh u = spawn /bin/bash /usr/share/uzbl/examples/scripts/load_url_from_history.sh U = spawn /bin/bash /usr/share/uzbl/examples/scripts/load_url_from_bookmarks.sh diff --git a/examples/configs/sampleconfig-dev b/examples/configs/sampleconfig-dev index 4caa9ff..9413732 100644 --- a/examples/configs/sampleconfig-dev +++ b/examples/configs/sampleconfig-dev @@ -14,10 +14,12 @@ history_handler = /bin/bash ./examples/scripts/history.sh download_handler = /bin/bash ./examples/scripts/download.sh fifo_dir = /tmp +socket_dir = /tmp always_insert_mode = 0 modkey = Mod1 show_status = 1 status_top = 0 +home_page = http://www.uzbl.org [bindings] b = back @@ -32,6 +34,7 @@ w = follow_link_new_window + = zoom_in - = zoom_out t = toggle_status +k = exit B = spawn /bin/bash ./examples/scripts/insert_bookmark.sh u = spawn /bin/bash ./examples/scripts/load_url_from_history.sh U = spawn /bin/bash ./examples/scripts/load_url_from_bookmarks.sh diff --git a/examples/scripts/download.sh b/examples/scripts/download.sh index ff3d8db..41c408e 100755 --- a/examples/scripts/download.sh +++ b/examples/scripts/download.sh @@ -1,2 +1,2 @@ #!/bin/bash -wget $5 +wget $6 diff --git a/examples/scripts/history.sh b/examples/scripts/history.sh index 03c568a..b6671fe 100755 --- a/examples/scripts/history.sh +++ b/examples/scripts/history.sh @@ -1,4 +1,4 @@ #!/bin/bash #TODO: strip 'http://' part # you probably really want this in your $XDG_DATA_HOME (eg $HOME/.local/share/uzbl/history) -echo "$7 $5" >> /tmp/uzbl.history +echo "$8 $6" >> /tmp/uzbl.history diff --git a/examples/scripts/load_url_from_bookmarks.sh b/examples/scripts/load_url_from_bookmarks.sh index ca512eb..2a893bf 100755 --- a/examples/scripts/load_url_from_bookmarks.sh +++ b/examples/scripts/load_url_from_bookmarks.sh @@ -8,5 +8,6 @@ else file=./examples/bookmarks #useful when developing fi -goto=`awk '{print $1}' $file | dmenu` #NOTE: it's the job of the script that inserts bookmarks to make sure there are no dupes. -[ -n "$goto" ] && echo "uri $goto" > $4 +goto=`awk '{print $1}' $file | dmenu -i` #NOTE: it's the job of the script that inserts bookmarks to make sure there are no dupes. +#[ -n "$goto" ] && echo "uri $goto" > $4 +[ -n "$goto" ] && uzblctrl -s $5 -c "uri $goto" diff --git a/examples/scripts/load_url_from_history.sh b/examples/scripts/load_url_from_history.sh index 366aedf..81a220a 100755 --- a/examples/scripts/load_url_from_history.sh +++ b/examples/scripts/load_url_from_history.sh @@ -2,5 +2,6 @@ # you probably really want this in your $XDG_DATA_HOME (eg $HOME/.local/share/uzbl/history) history_file=/tmp/uzbl.history -goto=`awk '{print $3}' $history_file | sort | uniq | dmenu` -[ -n "$goto" ] && echo "uri $goto" > $4 +goto=`awk '{print $3}' $history_file | sort | uniq | dmenu -i` +#[ -n "$goto" ] && echo "uri $goto" > $4 +[ -n "$goto" ] && uzblctrl -s $5 -c "uri $goto" @@ -43,6 +43,12 @@ #include <sys/types.h> #include <unistd.h> #include <stdlib.h> +#include <errno.h> +#include <string.h> +#include <sys/types.h> +#include <fcntl.h> +#include <sys/socket.h> +#include <sys/un.h> /* housekeeping / internal variables */ static GtkWidget* main_window; @@ -50,19 +56,22 @@ static GtkWidget* mainbar; static GtkWidget* mainbar_label; static WebKitWebView* web_view; static gchar* main_title; -static gchar selected_url[500]; +static gchar selected_url[500] = "\0"; static gint load_progress; static Window xwin = 0; -static char fifopath[64]; +static char fifo_path[64]; +static char socket_path[108]; /* state variables (initial values coming from command line arguments but may be changed later) */ static gchar* uri = NULL; static gchar* config_file = NULL; +static gchar config_file_path[500]; static gboolean verbose = FALSE; /* settings from config: group behaviour */ static gchar* history_handler = NULL; -static gchar* fifodir = NULL; +static gchar* fifo_dir = NULL; +static gchar* socket_dir = NULL; static gchar* download_handler = NULL; static gboolean always_insert_mode = FALSE; static gboolean show_status = FALSE; @@ -70,16 +79,18 @@ static gboolean insert_mode = FALSE; static gboolean status_top = FALSE; static gchar* modkey = NULL; static guint modmask = 0; +static gchar* home_page = NULL; -typedef struct { - char *binding; - char *action; - char *param; -} Binding; +/* settings from config: group bindings, key -> action */ +static GHashTable *bindings; -/* settings from config: group bindings_internal */ -static Binding bindings[MAX_BINDINGS]; -static int num_bindings = 0; +/* command list: name -> Command */ +static GHashTable *commands; + +typedef struct { + char *name; + char *param; +} Action; /* commandline arguments (set initial values for the state variables) */ static GOptionEntry entries[] = @@ -90,12 +101,7 @@ static GOptionEntry entries[] = { NULL, 0, 0, 0, NULL, NULL, NULL } }; -/* for internal list of commands */ -typedef struct -{ - const char *command; - void (*func)(WebKitWebView*, const char *); -} Command; +typedef void (*Command)(WebKitWebView*, const char *); /* XDG stuff */ static char *XDG_CONFIG_HOME_default[256]; @@ -107,15 +113,31 @@ update_title (GtkWindow* window); static void load_uri ( WebKitWebView * web_view, const gchar * uri); +static void +new_window_load_uri (const gchar * uri); + +static void +go_home (WebKitWebView *page, const char *param); + +static void +close_uzbl (WebKitWebView *page, const char *param); + static gboolean run_command(const char *command, const char *args); static void spawn(WebKitWebView *web_view, const char *param); +static void +free_action(gpointer action); + +static Action* +new_action(const gchar *name, const gchar *param); + /* --- CALLBACKS --- */ + static gboolean new_window_cb (WebKitWebView *web_view, WebKitWebFrame *frame, WebKitNetworkRequest *request, WebKitWebNavigationAction *navigation_action, WebKitWebPolicyDecision *policy_decision, gpointer user_data) { (void) web_view; @@ -125,36 +147,44 @@ new_window_cb (WebKitWebView *web_view, WebKitWebFrame *frame, WebKitNetworkRequ (void) user_data; const gchar* uri = webkit_network_request_get_uri (request); printf("New window requested -> %s \n", uri); - gboolean result; - GString* to_execute = g_string_new (""); - g_string_printf (to_execute, "uzbl --uri '%s'", uri); - result = g_spawn_command_line_async (to_execute->str, NULL); - if (!result) { - g_string_printf (to_execute, "./uzbl --uri '%s'", uri); - result = g_spawn_command_line_async (to_execute->str, NULL); - } - g_string_free (to_execute, TRUE); + new_window_load_uri(uri); return (FALSE); } +WebKitWebView* +create_web_view_cb (WebKitWebView *web_view, WebKitWebFrame *frame, gpointer user_data) { + (void) web_view; + (void) frame; + (void) user_data; + if (selected_url[0]!=0) { + printf("\nNew web view -> %s\n",selected_url); + new_window_load_uri(selected_url); + } else { + printf("New web view -> %s\n","Nothing to open, exiting"); + } + return (NULL); +} + static gboolean download_cb (WebKitWebView *web_view, GObject *download, gpointer user_data) { (void) web_view; (void) user_data; - const gchar* uri = webkit_download_get_uri ((WebKitDownload*)download); - printf("Download -> %s\n",uri); - run_command(download_handler, uri); + if (download_handler) { + const gchar* uri = webkit_download_get_uri ((WebKitDownload*)download); + printf("Download -> %s\n",uri); + run_command(download_handler, uri); + } return (FALSE); } static void toggle_status_cb (WebKitWebView* page, const char *param) { (void)page; - (void)param; + (void)param; if (show_status) { - gtk_widget_hide(mainbar); + gtk_widget_hide(mainbar); } else { - gtk_widget_show(mainbar); + gtk_widget_show(mainbar); } show_status = !show_status; update_title (GTK_WINDOW (main_window)); @@ -237,22 +267,56 @@ VIEWFUNC(go_forward) /* -- command to callback/function map for things we cannot attach to any signals */ // TODO: reload, home, quit -static Command commands[] = + +static struct {char *name; Command command;} cmdlist[] = { { "back", view_go_back }, { "forward", view_go_forward }, { "reload", view_reload, }, //Buggy + { "refresh", view_reload, }, /* for convenience, will change */ { "stop", view_stop_loading, }, { "zoom_in", view_zoom_in, }, //Can crash (when max zoom reached?). { "zoom_out", view_zoom_out, }, { "uri", load_uri }, { "toggle_status", toggle_status_cb }, - { "spawn", spawn }, -//{ "get uri", &webkit_web_view_get_uri}, + { "spawn", spawn }, + { "home", go_home }, + { "exit", close_uzbl }, }; +static void +commands_hash(void) +{ + unsigned int i; + commands = g_hash_table_new(g_str_hash, g_str_equal); + + for (i = 0; i < LENGTH(cmdlist); i++) + g_hash_table_insert(commands, cmdlist[i].name, cmdlist[i].command); +} + /* -- CORE FUNCTIONS -- */ - + +void +free_action(gpointer act) { + Action *action = (Action*)act; + g_free(action->name); + if (action->param) + g_free(action->param); + g_free(action); +} + +Action* +new_action(const gchar *name, const gchar *param) { + Action *action = g_new(Action, 1); + + action->name = g_strdup(name); + if (param) + action->param = g_strdup(param); + else + action->param = NULL; + + return action; +} static bool file_exists (const char * filename) { @@ -275,14 +339,49 @@ load_uri (WebKitWebView * web_view, const gchar *param) { } } +static void +new_window_load_uri (const gchar * uri) { + GString* to_execute = g_string_new (""); + if (!config_file) { + g_string_printf (to_execute, "uzbl --uri '%s'", uri); + } else { + g_string_printf (to_execute, "uzbl --uri '%s' --config '%s'", uri, config_file); + } + printf("Spawning %s\n",to_execute->str); + if (!g_spawn_command_line_async (to_execute->str, NULL)) { + if (!config_file) { + g_string_printf (to_execute, "./uzbl --uri '%s'", uri); + } else { + g_string_printf (to_execute, "./uzbl --uri '%s' --config '%s'", uri, config_file); + } + printf("Spawning %s\n",to_execute->str); + g_spawn_command_line_async (to_execute->str, NULL); + } + g_string_free (to_execute, TRUE); +} + +static void +go_home (WebKitWebView *page, const char *param) { + (void)param; + + if (home_page) + webkit_web_view_load_uri (page, home_page); +} + +static void +close_uzbl (WebKitWebView *page, const char *param) { + (void)page; + (void)param; + gtk_main_quit (); +} // make sure to put '' around args, so that if there is whitespace we can still keep arguments together. static gboolean run_command(const char *command, const char *args) { - //command <uzbl conf> <uzbl pid> <uzbl win id> <uzbl fifo file> [args] + //command <uzbl conf> <uzbl pid> <uzbl win id> <uzbl fifo file> <uzbl socket file> [args] GString* to_execute = g_string_new (""); gboolean result; - g_string_printf (to_execute, "%s '%s' '%i' '%i' '%s'", command, config_file, (int) getpid() , (int) xwin, fifopath); + g_string_printf (to_execute, "%s '%s' '%i' '%i' '%s' '%s'", command, config_file, (int) getpid() , (int) xwin, fifo_path, socket_path); if(args) { g_string_append_printf (to_execute, " %s", args); } @@ -294,71 +393,142 @@ run_command(const char *command, const char *args) { static void spawn(WebKitWebView *web_view, const char *param) { - (void)web_view; - run_command(param, NULL); + (void)web_view; + run_command(param, NULL); } static void -parse_command(const char *action, const char *param) { - unsigned int i; - int parsed = 0; +parse_command(const char *cmd, const char *param) { + Command c; + + if ((c = g_hash_table_lookup(commands, cmd))) + c(web_view, param); + else + fprintf (stderr, "command \"%s\" not understood. ignoring.\n", cmd); +} - for (i = 0; i < LENGTH (commands); i++) - if (strcmp(action, commands[i].command) == 0) { - commands[i].func(web_view, param); - parsed = 1; - } +static void +parse_line(char *line) { + gchar **parts; - if (!parsed) - fprintf (stderr, "command \"%s\" not understood. ignoring.\n", action); + g_strstrip(line); + + parts = g_strsplit(line, " ", 2); + + if (!parts) + return; + + parse_command(parts[0], parts[1]); + + g_strfreev(parts); } - + static void -*control_fifo() { - if (fifodir) { - sprintf (fifopath, "%s/uzbl_%d", fifodir, (int) xwin); +control_fifo(GIOChannel *fd) { + gchar *ctl_line; + gsize term_pos; + + if(!fd) + return; + + g_io_channel_read_line(fd, &ctl_line, NULL, &term_pos, NULL); + ctl_line[term_pos] ='\0'; + + parse_line(ctl_line); + + g_free(ctl_line); + + return; +} + +static void +create_fifo() { + GIOChannel *chan = NULL; + + if (fifo_dir) { + sprintf (fifo_path, "%s/uzbl_fifo_%d", fifo_dir, (int) xwin); } else { - sprintf (fifopath, "/tmp/uzbl_%d", (int) xwin); + sprintf (fifo_path, "/tmp/uzbl_fifo_%d", (int) xwin); } - - if (mkfifo (fifopath, 0666) == -1) { + printf ("Control fifo opened in %s\n", fifo_path); + if (mkfifo (fifo_path, 0666) == -1) { printf ("Possible error creating fifo\n"); } + + if( (chan = g_io_channel_new_file((gchar *) fifo_path, "r+", NULL)) ) + g_io_add_watch(chan, G_IO_IN|G_IO_HUP, (GIOFunc) control_fifo, chan); + return; +} + +static void +*control_socket() { + if (socket_dir) { + sprintf (socket_path, "%s/uzbl_socket_%d", socket_dir, (int) xwin); + } else { + sprintf (socket_path, "/tmp/uzbl_socket_%d", (int) xwin); + } - printf ("Control fifo opened in %s\n", fifopath); - - while (true) { - FILE *fifo = fopen (fifopath, "r"); - if (!fifo) { - printf ("Could not open %s for reading\n", fifopath); - return NULL; - } - - char buffer[256]; - memset (buffer, 0, sizeof (buffer)); - while (!feof (fifo) && fgets (buffer, sizeof (buffer), fifo)) { - gchar **parts; + int sock, clientsock, len; + unsigned int t; + struct sockaddr_un local, remote; - g_strstrip(buffer); + sock = socket (AF_UNIX, SOCK_STREAM, 0); - parts = g_strsplit(buffer, " ", 2); + local.sun_family = AF_UNIX; + strcpy (local.sun_path, socket_path); + unlink (local.sun_path); - if (!parts) - continue; + len = strlen (local.sun_path) + sizeof (local.sun_family); + bind (sock, (struct sockaddr *) &local, len); + + if (errno == -1) { + printf ("A problem occurred when opening a socket in %s\n", socket_path); + } else { + printf ("Control socket opened in %s\n", socket_path); + } + + listen (sock, 5); + + char buffer[512]; + char temp[128]; + int done, n; + for(;;) { + memset (buffer, 0, sizeof (buffer)); + + t = sizeof (remote); + clientsock = accept (sock, (struct sockaddr *) &remote, &t); + printf ("Connected to client\n"); + + done = 0; + do { + memset (temp, 0, sizeof (temp)); + n = recv (clientsock, temp, 128, 0); + if (n == 0) { + buffer[strlen (buffer)] = '\0'; + done = 1; + } - parse_command(parts[0], parts[1]); + if (!done) + strcat (buffer, temp); + } while (!done); - g_strfreev(parts); + if (strcmp (buffer, "\n") < 0) { + buffer[strlen (buffer) - 1] = '\0'; + } else { + buffer[strlen (buffer)] = '\0'; } + + parse_line (buffer); + close (clientsock); } - + return NULL; } static void setup_threading () { pthread_t control_thread; - pthread_create(&control_thread, NULL, control_fifo, NULL); + pthread_create(&control_thread, NULL, control_socket, NULL); } static void @@ -367,10 +537,10 @@ update_title (GtkWindow* window) { GString* string_short = g_string_new (""); if (!always_insert_mode) g_string_append (string_long, (insert_mode ? "[I] " : "[C] ")); - if (main_title) { - g_string_append (string_long, main_title); - g_string_append (string_short, main_title); - } + if (main_title) { + g_string_append (string_long, main_title); + g_string_append (string_short, main_title); + } g_string_append (string_long, " - Uzbl browser"); g_string_append (string_short, " - Uzbl browser"); if (load_progress < 100) @@ -385,7 +555,7 @@ update_title (GtkWindow* window) { if (show_status) { gtk_window_set_title (window, title_short); - gtk_label_set_text(GTK_LABEL(mainbar_label), title_long); + gtk_label_set_text(GTK_LABEL(mainbar_label), title_long); } else { gtk_window_set_title (window, title_long); } @@ -397,32 +567,28 @@ update_title (GtkWindow* window) { static gboolean key_press_cb (WebKitWebView* page, GdkEventKey* event) { + //TRUE to stop other handlers from being invoked for the event. FALSE to propagate the event further. + (void) page; - int i; - gboolean result=FALSE; //TRUE to stop other handlers from being invoked for the event. FALSE to propagate the event further. - if (event->type != GDK_KEY_PRESS) - return result; + Action *action; + + if (event->type != GDK_KEY_PRESS || event->keyval == GDK_Page_Up || event->keyval == GDK_Page_Down + || event->keyval == GDK_Up || event->keyval == GDK_Down || event->keyval == GDK_Left || event->keyval == GDK_Right) + return FALSE; //TURN OFF/ON INSERT MODE - if (!always_insert_mode && ((insert_mode && (event->keyval == GDK_Escape)) || (!insert_mode && (event->string[0] == 'i')))) { - insert_mode = !insert_mode; + if ((insert_mode && (event->keyval == GDK_Escape)) || (!insert_mode && (event->string[0] == 'i'))) { + insert_mode = !insert_mode || always_insert_mode; update_title (GTK_WINDOW (main_window)); return TRUE; } - for (i = 0; i < num_bindings; i++) { - if (strcmp(event->string, bindings[i].binding) == 0) { - if (!insert_mode || (event->state == modmask)) { - parse_command(bindings[i].action, bindings[i].param); - result = TRUE; - } - } + if ((!insert_mode || (event->state == modmask)) && (action = g_hash_table_lookup(bindings, event->string))) { + parse_command(action->name, action->param); + return TRUE; } - if (!result) - result = (insert_mode ? FALSE : TRUE); - - return result; + return !insert_mode; } static GtkWidget* @@ -441,6 +607,7 @@ create_browser () { g_signal_connect (G_OBJECT (web_view), "key-press-event", G_CALLBACK (key_press_cb), web_view); g_signal_connect (G_OBJECT (web_view), "new-window-policy-decision-requested", G_CALLBACK (new_window_cb), web_view); g_signal_connect (G_OBJECT (web_view), "download-requested", G_CALLBACK (download_cb), web_view); + g_signal_connect (G_OBJECT (web_view), "create-web-view", G_CALLBACK (create_web_view_cb), web_view); return scrolled_window; } @@ -466,47 +633,38 @@ GtkWidget* create_window () { } static void -add_binding (const gchar *key, const gchar *action) { - char **parts = g_strsplit(action, " ", 2); - - printf("add_binding, key '%s', action '%s'", key, action); - - if (!parts) - return; +add_binding (const gchar *key, const gchar *act) { + char **parts = g_strsplit(act, " ", 2); + Action *action; - if (MAX_BINDINGS == num_bindings) { - fprintf(stderr, "Maximum number number bindings reached, ignoring\n"); - return; - } + if (!parts) + return; - bindings[num_bindings].binding = g_strdup(key); - bindings[num_bindings].action = g_strdup(parts[0]); /* parts[0] is always defined */ - bindings[num_bindings].param = (parts[1] ? g_strdup(parts[1]) : NULL); - - num_bindings++; + action = new_action(parts[0], parts[1]); + g_hash_table_insert(bindings, g_strdup(key), action); - g_strfreev(parts); + g_strfreev(parts); } static void settings_init () { GKeyFile* config; gboolean res = FALSE; + char *saveptr; gchar** keys = NULL; - if (! config_file) { + if (!config_file) { const char* XDG_CONFIG_HOME = getenv ("XDG_CONFIG_HOME"); - char conf[256]; if (! XDG_CONFIG_HOME || ! strcmp (XDG_CONFIG_HOME, "")) { XDG_CONFIG_HOME = (char*)XDG_CONFIG_HOME_default; } printf("XDG_CONFIG_HOME: %s\n", XDG_CONFIG_HOME); - strcpy (conf, XDG_CONFIG_HOME); - strcat (conf, "/uzbl/config"); - if (file_exists (conf)) { - printf ("Config file %s found.\n", conf); - config_file = &conf[0]; + strcpy (config_file_path, XDG_CONFIG_HOME); + strcat (config_file_path, "/uzbl/config"); + if (file_exists (config_file_path)) { + printf ("Config file %s found.\n", config_file_path); + config_file = &config_file_path[0]; } else { // Now we check $XDG_CONFIG_DIRS char *XDG_CONFIG_DIRS = getenv ("XDG_CONFIG_DIRS"); @@ -517,15 +675,15 @@ settings_init () { char buffer[512]; strcpy (buffer, XDG_CONFIG_DIRS); - const gchar* dir = strtok (buffer, ":"); - while (dir && ! file_exists (conf)) { - strcpy (conf, dir); - strcat (conf, "/uzbl/config"); - if (file_exists (conf)) { - printf ("Config file %s found.\n", conf); - config_file = &conf[0]; + const gchar* dir = (char *) strtok_r (buffer, ":", &saveptr); + while (dir && ! file_exists (config_file_path)) { + strcpy (config_file_path, dir); + strcat (config_file_path, "/uzbl/config_file_pathig"); + if (file_exists (config_file_path)) { + printf ("Config file %s found.\n", config_file_path); + config_file = &config_file_path[0]; } - dir = strtok (NULL, ":"); + dir = (char * ) strtok_r (NULL, ":", &saveptr); } } } @@ -533,9 +691,9 @@ settings_init () { if (config_file) { config = g_key_file_new (); res = g_key_file_load_from_file (config, config_file, G_KEY_FILE_NONE, NULL); - if(res) { + if(res) { printf ("Config %s loaded\n", config_file); - } else { + } else { fprintf (stderr, "Config %s loading failed\n", config_file); } } else { @@ -543,47 +701,33 @@ settings_init () { } if (res) { - history_handler = g_key_file_get_value (config, "behavior", "history_handler", NULL); - download_handler = g_key_file_get_value (config, "behavior", "download_handler", NULL); + history_handler = g_key_file_get_value (config, "behavior", "history_handler", NULL); + download_handler = g_key_file_get_value (config, "behavior", "download_handler", NULL); always_insert_mode = g_key_file_get_boolean (config, "behavior", "always_insert_mode", NULL); - show_status = g_key_file_get_boolean (config, "behavior", "show_status", NULL); - modkey = g_key_file_get_value (config, "behavior", "modkey", NULL); - status_top = g_key_file_get_boolean (config, "behavior", "status_top", NULL); - if (! fifodir) - fifodir = g_key_file_get_value (config, "behavior", "fifodir", NULL); - keys = g_key_file_get_keys (config, "bindings", NULL, NULL); + show_status = g_key_file_get_boolean (config, "behavior", "show_status", NULL); + modkey = g_key_file_get_value (config, "behavior", "modkey", NULL); + status_top = g_key_file_get_boolean (config, "behavior", "status_top", NULL); + home_page = g_key_file_get_value (config, "behavior", "home_page", NULL); + if (! fifo_dir) + fifo_dir = g_key_file_get_value (config, "behavior", "fifodir", NULL); + if (! socket_dir) + socket_dir = g_key_file_get_value (config, "behavior", "socket_dir", NULL); + keys = g_key_file_get_keys (config, "bindings", NULL, NULL); } - - if (history_handler) { - printf ("History handler: %s\n", history_handler); - } else { - printf ("History handler disabled\n"); - } - - if (download_handler) { - printf ("Download manager: %s\n", download_handler); - } else { - printf ("Download manager disabled\n"); - } - - if (fifodir) { - printf ("Fifo directory: %s\n", fifodir); - } else { - printf ("Fifo directory: /tmp\n"); - } - - printf ("Always insert mode: %s\n", (always_insert_mode ? "TRUE" : "FALSE")); - - printf ("Show status: %s\n", (show_status ? "TRUE" : "FALSE")); - - printf ("Status top: %s\n", (status_top ? "TRUE" : "FALSE")); + + printf ("History handler: %s\n", (history_handler ? history_handler : "disabled")); + printf ("Download manager: %s\n", (download_handler ? download_handler : "disabled")); + printf ("Fifo directory: %s\n", (fifo_dir ? fifo_dir : "/tmp")); + printf ("Socket directory: %s\n", (socket_dir ? socket_dir : "/tmp")); + printf ("Always insert mode: %s\n", (always_insert_mode ? "TRUE" : "FALSE")); + printf ("Show status: %s\n", (show_status ? "TRUE" : "FALSE")); + printf ("Status top: %s\n", (status_top ? "TRUE" : "FALSE")); + printf ("Modkey: %s\n", (modkey ? modkey : "disabled")); + printf ("Home page: %s\n", (home_page ? home_page : "disabled")); + + if (! modkey) + modkey = ""; - if (modkey) { - printf ("Modkey: %s\n", modkey); - } else { - printf ("Modkey disabled\n"); - modkey = ""; - } //POSSIBLE MODKEY VALUES (COMBINATIONS CAN BE USED) gchar* modkeyup = g_utf8_strup (modkey, -1); if (g_strrstr (modkeyup,"SHIFT") != NULL) modmask |= GDK_SHIFT_MASK; //the Shift key. @@ -609,32 +753,36 @@ settings_init () { for (i = 0; keys[i]; i++) { gchar *value = g_key_file_get_string (config, "bindings", keys[i], NULL); - add_binding(g_strstrip(keys[i]), value); - g_free(value); + add_binding(g_strstrip(keys[i]), value); + g_free(value); } - g_strfreev(keys); + g_strfreev(keys); } } int main (int argc, char* argv[]) { - int i; - gtk_init (&argc, &argv); if (!g_thread_supported ()) g_thread_init (NULL); - strcat ((char*)XDG_CONFIG_HOME_default, getenv ("HOME")); - strcat ((char*)XDG_CONFIG_HOME_default, "/.config"); + printf("Uzbl start location: %s\n", argv[0]); + + strcat ((char *) XDG_CONFIG_HOME_default, getenv ("HOME")); + strcat ((char *) XDG_CONFIG_HOME_default, "/.config"); GError *error = NULL; GOptionContext* context = g_option_context_new ("- some stuff here maybe someday"); g_option_context_add_main_entries (context, entries, NULL); g_option_context_add_group (context, gtk_get_option_group (TRUE)); g_option_context_parse (context, &argc, &argv, &error); + /* initialize hash table */ + bindings = g_hash_table_new_full(g_str_hash, g_str_equal, g_free, free_action); settings_init (); + commands_hash (); + if (always_insert_mode) insert_mode = TRUE; @@ -657,20 +805,19 @@ main (int argc, char* argv[]) { printf("pid %i\n", getpid ()); if (!show_status) - gtk_widget_hide(mainbar); + gtk_widget_hide(mainbar); setup_threading (); + create_fifo (); gtk_main (); - for (i = 0; i < num_bindings; i++) { - g_free(bindings[i].binding); - g_free(bindings[i].action); - if (bindings[i].param) - g_free(bindings[i].param); - } - - unlink (fifopath); + unlink (socket_path); + unlink (fifo_path); + g_hash_table_destroy(bindings); + g_hash_table_destroy(commands); return 0; } + +/* vi: set et ts=4: */ diff --git a/uzblctrl.c b/uzblctrl.c new file mode 100644 index 0000000..5415247 --- /dev/null +++ b/uzblctrl.c @@ -0,0 +1,63 @@ +/* Socket code more or less completely copied from here: http://www.ecst.csuchico.edu/~beej/guide/ipc/usock.html */ + +#include <gtk/gtk.h> +#include <gdk/gdkx.h> +#include <gdk/gdkkeysyms.h> +#include <webkit/webkit.h> +#include <pthread.h> +#include <stdio.h> +#include <string.h> +#include <sys/stat.h> +#include <sys/types.h> +#include <unistd.h> +#include <stdlib.h> +#include <errno.h> +#include <string.h> +#include <sys/types.h> +#include <sys/socket.h> +#include <sys/un.h> + +static gchar* sockpath; +static gchar* command; + +static GOptionEntry entries[] = +{ + { "socket", 's', 0, G_OPTION_ARG_STRING, &sockpath, "Socket path of the client uzbl", NULL }, + { "command", 'c', 0, G_OPTION_ARG_STRING, &command, "The uzbl command to execute", NULL }, + { NULL, 0, 0, 0, NULL, NULL, NULL } +}; + +int +main(int argc, char* argv[]) { + GError *error = NULL; + GOptionContext* context = g_option_context_new ("- some stuff here maybe someday"); + g_option_context_add_main_entries (context, entries, NULL); + g_option_context_add_group (context, gtk_get_option_group (TRUE)); + g_option_context_parse (context, &argc, &argv, &error); + + int s, len; + struct sockaddr_un remote; + + if ((s = socket (AF_UNIX, SOCK_STREAM, 0)) == -1) { + perror ("socket"); + exit (1); + } + + remote.sun_family = AF_UNIX; + strcpy (remote.sun_path, (char *) sockpath); + len = strlen (remote.sun_path) + sizeof (remote.sun_family); + + if (connect (s, (struct sockaddr *) &remote, len) == -1) { + perror ("connect"); + exit (1); + } + + if (send (s, command, strlen (command), 0) == -1) { + perror ("send"); + exit (1); + } + + close(s); + + return 0; +} |