aboutsummaryrefslogtreecommitdiffhomepage
path: root/uzbl.c
diff options
context:
space:
mode:
Diffstat (limited to 'uzbl.c')
-rw-r--r--uzbl.c816
1 files changed, 572 insertions, 244 deletions
diff --git a/uzbl.c b/uzbl.c
index 161769b..99ae5a2 100644
--- a/uzbl.c
+++ b/uzbl.c
@@ -40,8 +40,8 @@
#include <sys/stat.h>
#include <sys/types.h>
#include <sys/un.h>
+#include <sys/utsname.h>
#include <webkit/webkit.h>
-#include <pthread.h>
#include <stdio.h>
#include <string.h>
#include <unistd.h>
@@ -54,35 +54,26 @@
#include <libsoup/soup.h>
#include "uzbl.h"
+
+/* status bar format
+ TODO: integrate with the config file
+*/
+char *status_format = "<span background=\"darkgreen\" foreground=\"khaki\"> MODE </span> | Cmd: <span background=\"red\" foreground=\"white\">KEYCMD</span> | <span background=\"darkblue\" foreground=\"white\"> <b>TITLE</b> </span> | LOAD_PROGRESS% <span font_family=\"monospace\">LOAD_PROGRESSBAR</span> | <span foreground=\"darkgreen\">URI</span> | NAME | <span foreground=\"black\" background=\"khaki\"> Uzbl browser </span>";
+
/* housekeeping / internal variables */
-static GtkWidget* main_window;
-static GtkWidget* mainbar;
-static GtkWidget* mainbar_label;
-static GtkScrollbar* scbar_v; // Horizontal and Vertical Scrollbar
-static GtkScrollbar* scbar_h; // (These are still hidden)
-static GtkAdjustment* bar_v; // Information about document length
-static GtkAdjustment* bar_h; // and scrolling position
-static WebKitWebView* web_view;
-static gchar* main_title;
static gchar selected_url[500] = "\0";
-static gint load_progress;
-static Window xwin = 0;
-static char fifo_path[64];
-static char socket_path[108];
static char executable_path[500];
static GString* keycmd;
+static gchar searchtx[500] = "\0";
-/* 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;
+static Uzbl uzbl;
/* settings from config: group behaviour */
static gchar* history_handler = NULL;
static gchar* fifo_dir = NULL;
static gchar* socket_dir = NULL;
static gchar* download_handler = NULL;
+static gchar* cookie_handler = NULL;
static gboolean always_insert_mode = FALSE;
static gboolean show_status = FALSE;
static gboolean insert_mode = FALSE;
@@ -90,7 +81,10 @@ static gboolean status_top = FALSE;
static gchar* modkey = NULL;
static guint modmask = 0;
static guint http_debug = 0;
-static gchar* cookie_handler = NULL;
+
+/* System info */
+static struct utsname unameinfo;
+
/* settings from config: group bindings, key -> action */
static GHashTable* bindings;
@@ -100,9 +94,9 @@ static GHashTable* commands;
/* commandline arguments (set initial values for the state variables) */
static GOptionEntry entries[] =
{
- { "uri", 'u', 0, G_OPTION_ARG_STRING, &uri, "Uri to load", NULL },
- { "verbose", 'v', 0, G_OPTION_ARG_NONE, &verbose, "Be verbose", NULL },
- { "config", 'c', 0, G_OPTION_ARG_STRING, &config_file, "Config file", NULL },
+ { "uri", 'u', 0, G_OPTION_ARG_STRING, &uzbl.state.uri, "Uri to load", "URI" },
+ { "name", 'n', 0, G_OPTION_ARG_STRING, &uzbl.state.instance_name, "Name of the current instance", "NAME" },
+ { "config", 'c', 0, G_OPTION_ARG_STRING, &uzbl.state.config_file, "Config file", "FILE" },
{ NULL, 0, 0, 0, NULL, NULL, NULL }
};
@@ -112,15 +106,21 @@ typedef void (*Command)(WebKitWebView*, const char *);
static char *XDG_CONFIG_HOME_default[256];
static char *XDG_CONFIG_DIRS_default = "/etc/xdg";
-/* libsoup stuff - proxy and friends; networking aptions actually */
-static SoupSession *soup_session;
-static SoupLogger *soup_logger;
-static char *proxy_url = NULL;
-static char *useragent = NULL;
-static gint max_conns;
-static gint max_conns_host;
-static SoupCookieJar *ck;
-static char* current_req = NULL;
+
+/* --- UTILITY FUNCTIONS --- */
+
+char *
+itos(int val) {
+ char tmp[20];
+
+ snprintf(tmp, sizeof(tmp), "%i", val);
+ return g_strdup(tmp);
+}
+
+static char *
+str_replace (const char* search, const char* replace, const char* string) {
+ return g_strjoinv (replace, g_strsplit(string, search, -1));
+}
/* --- CALLBACKS --- */
@@ -180,13 +180,13 @@ scroll (GtkAdjustment* bar, const char *param) {
static void scroll_vert(WebKitWebView* page, const char *param) {
(void) page;
- scroll(bar_v, param);
+ scroll(uzbl.gui.bar_v, param);
}
static void scroll_horz(WebKitWebView* page, const char *param) {
(void) page;
- scroll(bar_h, param);
+ scroll(uzbl.gui.bar_h, param);
}
static void
@@ -195,9 +195,9 @@ toggle_status_cb (WebKitWebView* page, const char *param) {
(void)param;
if (show_status) {
- gtk_widget_hide(mainbar);
+ gtk_widget_hide(uzbl.gui.mainbar);
} else {
- gtk_widget_show(mainbar);
+ gtk_widget_show(uzbl.gui.mainbar);
}
show_status = !show_status;
update_title();
@@ -221,9 +221,9 @@ title_change_cb (WebKitWebView* web_view, WebKitWebFrame* web_frame, const gchar
(void) web_view;
(void) web_frame;
(void) data;
- if (main_title)
- g_free (main_title);
- main_title = g_strdup (title);
+ if (uzbl.gui.main_title)
+ g_free (uzbl.gui.main_title);
+ uzbl.gui.main_title = g_strdup (title);
update_title();
}
@@ -231,7 +231,7 @@ static void
progress_change_cb (WebKitWebView* page, gint progress, gpointer data) {
(void) page;
(void) data;
- load_progress = progress;
+ uzbl.gui.sbar.load_progress = progress;
update_title();
}
@@ -239,9 +239,9 @@ static void
load_commit_cb (WebKitWebView* page, WebKitWebFrame* frame, gpointer data) {
(void) page;
(void) data;
- free (uri);
+ free (uzbl.state.uri);
GString* newuri = g_string_new (webkit_web_frame_get_uri (frame));
- uri = g_string_free (newuri, FALSE);
+ uzbl.state.uri = g_string_free (newuri, FALSE);
}
static void
@@ -267,10 +267,11 @@ log_history_cb () {
}
}
-/* VIEW funcs (little webkit wrappers) */
+/* VIEW funcs (little webkit wrappers) */
#define VIEWFUNC(name) static void view_##name(WebKitWebView *page, const char *param){(void)param; webkit_web_view_##name(page);}
VIEWFUNC(reload)
+VIEWFUNC(reload_bypass_cache)
VIEWFUNC(stop_loading)
VIEWFUNC(zoom_in)
VIEWFUNC(zoom_out)
@@ -283,20 +284,22 @@ VIEWFUNC(go_forward)
static struct {char *name; Command command;} cmdlist[] =
{
- { "back", view_go_back },
- { "forward", view_go_forward },
- { "scroll_vert", scroll_vert },
- { "scroll_horz", scroll_horz },
- { "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 },
- { "exit", close_uzbl },
- { "insert_mode", set_insert_mode }
+ { "back", view_go_back },
+ { "forward", view_go_forward },
+ { "scroll_vert", scroll_vert },
+ { "scroll_horz", scroll_horz },
+ { "reload", view_reload, },
+ { "reload_ign_cache", view_reload_bypass_cache},
+ { "stop", view_stop_loading, },
+ { "zoom_in", view_zoom_in, }, //Can crash (when max zoom reached?).
+ { "zoom_out", view_zoom_out, },
+ { "uri", load_uri },
+ { "script", run_js },
+ { "toggle_status", toggle_status_cb },
+ { "spawn", spawn },
+ { "exit", close_uzbl },
+ { "search", search_text },
+ { "insert_mode", set_insert_mode }
};
static void
@@ -365,6 +368,26 @@ load_uri (WebKitWebView * web_view, const gchar *param) {
}
static void
+run_js (WebKitWebView * web_view, const gchar *param) {
+ if (param)
+ webkit_web_view_execute_script (web_view, param);
+}
+
+static void
+search_text (WebKitWebView *page, const char *param) {
+ if ((param) && (param[0] != '\0')) {
+ strcpy(searchtx, param);
+ }
+ if (searchtx[0] != '\0') {
+ printf ("Searching: %s\n", searchtx);
+ webkit_web_view_unmark_text_matches (page);
+ webkit_web_view_mark_text_matches (page, searchtx, FALSE, 0);
+ webkit_web_view_set_highlight_text_matches (page, TRUE);
+ webkit_web_view_search_text (page, searchtx, FALSE, TRUE, TRUE);
+ }
+}
+
+static void
new_window_load_uri (const gchar * uri) {
GString* to_execute = g_string_new ("");
g_string_append_printf (to_execute, "%s --uri '%s'", executable_path, uri);
@@ -389,14 +412,158 @@ close_uzbl (WebKitWebView *page, const char *param) {
gtk_main_quit ();
}
+/* --Statusbar functions-- */
+static char*
+build_progressbar_ascii(int percent) {
+ int width=10;
+ int i;
+ double l;
+ GString *bar = g_string_new("");
+
+ l = (double)percent*((double)width/100.);
+ l = (int)(l+.5)>=(int)l ? l+.5 : l;
+
+ g_string_append(bar, "[");
+ for(i=0; i<(int)l; i++)
+ g_string_append(bar, "=");
+
+ for(; i<width; i++)
+ g_string_append(bar, "ยท");
+ g_string_append(bar, "]");
+
+ return g_string_free(bar, FALSE);
+}
+
+static void
+setup_scanner() {
+ const GScannerConfig scan_config = {
+ (
+ "\t\r\n"
+ ) /* cset_skip_characters */,
+ (
+ G_CSET_a_2_z
+ "_"
+ G_CSET_A_2_Z
+ ) /* cset_identifier_first */,
+ (
+ G_CSET_a_2_z
+ "_0123456789"
+ G_CSET_A_2_Z
+ G_CSET_LATINS
+ G_CSET_LATINC
+ ) /* cset_identifier_nth */,
+ ( "#\n" ) /* cpair_comment_single */,
+
+ TRUE /* case_sensitive */,
+
+ FALSE /* skip_comment_multi */,
+ FALSE /* skip_comment_single */,
+ FALSE /* scan_comment_multi */,
+ TRUE /* scan_identifier */,
+ TRUE /* scan_identifier_1char */,
+ FALSE /* scan_identifier_NULL */,
+ TRUE /* scan_symbols */,
+ FALSE /* scan_binary */,
+ FALSE /* scan_octal */,
+ FALSE /* scan_float */,
+ FALSE /* scan_hex */,
+ FALSE /* scan_hex_dollar */,
+ FALSE /* scan_string_sq */,
+ FALSE /* scan_string_dq */,
+ TRUE /* numbers_2_int */,
+ FALSE /* int_2_float */,
+ FALSE /* identifier_2_string */,
+ FALSE /* char_2_token */,
+ FALSE /* symbol_2_token */,
+ TRUE /* scope_0_fallback */,
+ FALSE,
+ TRUE
+ };
+
+ uzbl.scan = g_scanner_new(&scan_config);
+ while(symp->symbol_name) {
+ g_scanner_scope_add_symbol(uzbl.scan, 0,
+ symp->symbol_name,
+ GINT_TO_POINTER(symp->symbol_token));
+ symp++;
+ }
+}
+
+static gchar *
+parse_status_template(const char *template) {
+ GTokenType token = G_TOKEN_NONE;
+ GString *ret = g_string_new("");
+ gchar *buf=NULL;
+ int sym;
+
+ if(!template)
+ return NULL;
+
+ g_scanner_input_text(uzbl.scan, template, strlen(template));
+ while(!g_scanner_eof(uzbl.scan) && token != G_TOKEN_LAST) {
+ token = g_scanner_get_next_token(uzbl.scan);
+
+ if(token == G_TOKEN_SYMBOL) {
+ sym = (int)g_scanner_cur_value(uzbl.scan).v_symbol;
+ switch(sym) {
+ case SYM_URI:
+ g_string_append(ret, uzbl.state.uri);
+ break;
+ case SYM_LOADPRGS:
+ g_string_append(ret, itos(uzbl.gui.sbar.load_progress));
+ break;
+ case SYM_LOADPRGSBAR:
+ buf = build_progressbar_ascii(uzbl.gui.sbar.load_progress);
+ g_string_append(ret, buf);
+ g_free(buf);
+ break;
+ case SYM_TITLE:
+ g_string_append(ret,
+ uzbl.gui.main_title?uzbl.gui.main_title:"");
+ break;
+ case SYM_NAME:
+ g_string_append(ret,
+ uzbl.state.instance_name?uzbl.state.instance_name:"" );
+ break;
+ case SYM_KEYCMD:
+ g_string_append(ret,
+ keycmd->str?keycmd->str:"" );
+ break;
+ case SYM_MODE:
+ g_string_append(ret,
+ insert_mode?"[I]":"[C]" );
+ break;
+ default:
+ break;
+ }
+ }
+ else if(token == G_TOKEN_INT) {
+ g_string_append(ret, itos(g_scanner_cur_value(uzbl.scan).v_int));
+ }
+ else if(token == G_TOKEN_IDENTIFIER) {
+ g_string_append(ret, (gchar *)g_scanner_cur_value(uzbl.scan).v_identifier);
+ }
+ else if(token == G_TOKEN_CHAR) {
+ g_string_append_printf(ret, "%c", g_scanner_cur_value(uzbl.scan).v_char);
+ }
+ }
+
+ return g_string_free(ret, FALSE);
+}
+/* --End Statusbar functions-- */
+
+
// make sure to put '' around args, so that if there is whitespace we can still keep arguments together.
static gboolean
run_command_async(const char *command, const char *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' '%s'", command, config_file, (int) getpid() , (int) xwin, fifo_path, socket_path);
- g_string_append_printf (to_execute, " '%s' '%s'", uri, "TODO title here");
+ 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);
+ g_string_append_printf (to_execute, " '%s' '%s'",
+ uzbl.state.uri, "TODO title here");
if(args) {
g_string_append_printf (to_execute, " %s", args);
}
@@ -411,8 +578,8 @@ run_command_sync(const char *command, const char *args, char **stdout) {
//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' '%s'", command, config_file, (int) getpid() , (int) xwin, fifo_path, socket_path);
- g_string_append_printf (to_execute, " '%s' '%s'", uri, "TODO title here");
+ 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);
+ g_string_append_printf (to_execute, " '%s' '%s'", uzbl.state.uri, "TODO title here");
if(args) {
g_string_append_printf (to_execute, " %s", args);
}
@@ -433,7 +600,7 @@ parse_command(const char *cmd, const char *param) {
Command c;
if ((c = g_hash_table_lookup(commands, cmd)))
- c(web_view, param);
+ c(uzbl.gui.web_view, param);
else
fprintf (stderr, "command \"%s\" not understood. ignoring.\n", cmd);
}
@@ -454,132 +621,199 @@ parse_line(char *line) {
g_strfreev(parts);
}
+enum { FIFO, SOCKET};
+void
+build_stream_name(int type) {
+ char *xwin_str;
+ State *s = &uzbl.state;
+
+ xwin_str = itos((int)uzbl.xwin);
+ switch(type) {
+ case FIFO:
+ if (fifo_dir) {
+ sprintf (uzbl.comm.fifo_path, "%s/uzbl_fifo_%s",
+ fifo_dir, s->instance_name ? s->instance_name : xwin_str);
+ } else {
+ sprintf (uzbl.comm.fifo_path, "/tmp/uzbl_fifo_%s",
+ s->instance_name ? s->instance_name : xwin_str);
+ }
+ break;
+
+ case SOCKET:
+ if (socket_dir) {
+ sprintf (uzbl.comm.socket_path, "%s/uzbl_socket_%s",
+ socket_dir, s->instance_name ? s->instance_name : xwin_str);
+ } else {
+ sprintf (uzbl.comm.socket_path, "/tmp/uzbl_socket_%s",
+ s->instance_name ? s->instance_name : xwin_str);
+ }
+ break;
+ default:
+ break;
+ }
+ g_free(xwin_str);
+}
+
static void
-control_fifo(GIOChannel *fd) {
+control_fifo(GIOChannel *gio, GIOCondition condition) {
+ printf("triggered\n");
gchar *ctl_line;
- gsize term_pos;
+ GIOStatus ret;
+ GError *err = NULL;
- if(!fd)
- return;
+ if (condition & G_IO_HUP)
+ g_error ("Fifo: Read end of pipe died!\n");
- g_io_channel_read_line(fd, &ctl_line, NULL, &term_pos, NULL);
- ctl_line[term_pos] ='\0';
+ if(!gio)
+ g_error ("Fifo: GIOChannel broke\n");
- parse_line(ctl_line);
+ ret = g_io_channel_read_line(gio, &ctl_line, NULL, NULL, &err);
+ if (ret == G_IO_STATUS_ERROR)
+ g_error ("Fifo: Error reading: %s\n", err->message);
+ parse_line(ctl_line);
g_free(ctl_line);
-
+ printf("...done\n");
return;
}
static void
create_fifo() {
GIOChannel *chan = NULL;
+ GError *error = NULL;
- if (fifo_dir) {
- sprintf (fifo_path, "%s/uzbl_fifo_%d", fifo_dir, (int) xwin);
- } else {
- sprintf (fifo_path, "/tmp/uzbl_fifo_%d", (int) xwin);
+ build_stream_name(FIFO);
+ if (file_exists(uzbl.comm.fifo_path)) {
+ g_error ("Fifo: Error when creating %s: File exists\n", uzbl.comm.fifo_path);
+ return;
}
- printf ("Control fifo opened in %s\n", fifo_path);
- if (mkfifo (fifo_path, 0666) == -1) {
- printf ("Possible error creating fifo\n");
+ if (mkfifo (uzbl.comm.fifo_path, 0666) == -1) {
+ g_error ("Fifo: Error when creating %s: %s\n", uzbl.comm.fifo_path, strerror(errno));
+ } else {
+ // 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.
+ chan = g_io_channel_new_file((gchar *) uzbl.comm.fifo_path, "r+", &error);
+ if (chan) {
+ if (!g_io_add_watch(chan, G_IO_IN|G_IO_HUP, (GIOFunc) control_fifo, NULL)) {
+ g_error ("Fifo: could not add watch on %s\n", uzbl.comm.fifo_path);
+ } else {
+ printf ("Fifo: created successfully as %s\n", uzbl.comm.fifo_path);
+ }
+ } else {
+ g_error ("Fifo: Error while opening: %s\n", error->message);
+ }
}
-
- 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);
+control_socket(GIOChannel *chan) {
+ struct sockaddr_un remote;
+ char buffer[512], *ctl_line;
+ char temp[128];
+ int sock, clientsock, n, done;
+ unsigned int t;
+
+ sock = g_io_channel_unix_get_fd(chan);
+
+ memset (buffer, 0, sizeof (buffer));
+
+ t = sizeof (remote);
+ clientsock = accept (sock, (struct sockaddr *) &remote, &t);
+
+ done = 0;
+ do {
+ memset (temp, 0, sizeof (temp));
+ n = recv (clientsock, temp, 128, 0);
+ if (n == 0) {
+ buffer[strlen (buffer)] = '\0';
+ done = 1;
+ }
+ if (!done)
+ strcat (buffer, temp);
+ } while (!done);
+
+ if (strcmp (buffer, "\n") < 0) {
+ buffer[strlen (buffer) - 1] = '\0';
} else {
- sprintf (socket_path, "/tmp/uzbl_socket_%d", (int) xwin);
+ buffer[strlen (buffer)] = '\0';
}
-
- int sock, clientsock, len;
- unsigned int t;
- struct sockaddr_un local, remote;
+ close (clientsock);
+ ctl_line = g_strdup(buffer);
+ parse_line (ctl_line);
+
+/*
+ TODO: we should be able to do it with this. but glib errors out with "Invalid argument"
+ GError *error = NULL;
+ gsize len;
+ GIOStatus ret;
+ ret = g_io_channel_read_line(chan, &ctl_line, &len, NULL, &error);
+ if (ret == G_IO_STATUS_ERROR)
+ g_error ("Error reading: %s\n", error->message);
+
+ printf("Got line %s (%u bytes) \n",ctl_line, len);
+ if(ctl_line) {
+ parse_line(ctl_line);
+*/
+
+ g_free(ctl_line);
+ return;
+}
+static void
+create_socket() {
+ GIOChannel *chan = NULL;
+ int sock, len;
+ struct sockaddr_un local;
+
+ build_stream_name(SOCKET);
sock = socket (AF_UNIX, SOCK_STREAM, 0);
local.sun_family = AF_UNIX;
- strcpy (local.sun_path, socket_path);
+ strcpy (local.sun_path, uzbl.comm.socket_path);
unlink (local.sun_path);
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);
+ printf ("Socket: Could not open in %s: %s\n", uzbl.comm.socket_path, strerror(errno));
} 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;
- }
-
- if (!done)
- strcat (buffer, temp);
- } while (!done);
+ printf ("Socket: Opened in %s\n", uzbl.comm.socket_path);
+ listen (sock, 5);
- if (strcmp (buffer, "\n") < 0) {
- buffer[strlen (buffer) - 1] = '\0';
- } else {
- buffer[strlen (buffer)] = '\0';
- }
-
- parse_line (buffer);
- close (clientsock);
+ if( (chan = g_io_channel_unix_new(sock)) )
+ g_io_add_watch(chan, G_IO_IN|G_IO_HUP, (GIOFunc) control_socket, chan);
}
-
- return NULL;
-}
-
-static void
-setup_threading () {
- pthread_t control_thread;
- pthread_create(&control_thread, NULL, control_socket, NULL);
- pthread_detach(control_thread);
}
static void
update_title (void) {
GString* string_long = g_string_new ("");
GString* string_short = g_string_new ("");
+ char* iname = NULL;
+ gchar *statln;
+ int iname_len;
+ State *s = &uzbl.state;
+
+ if(s->instance_name) {
+ iname_len = strlen(s->instance_name)+4;
+ iname = malloc(iname_len);
+ snprintf(iname, iname_len, "<%s> ", s->instance_name);
+
+ g_string_prepend(string_long, iname);
+ g_string_prepend(string_short, iname);
+ free(iname);
+ }
g_string_append_printf(string_long, "%s ", keycmd->str);
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 (uzbl.gui.main_title) {
+ g_string_append (string_long, uzbl.gui.main_title);
+ g_string_append (string_short, uzbl.gui.main_title);
}
g_string_append (string_long, " - Uzbl browser");
g_string_append (string_short, " - Uzbl browser");
- if (load_progress < 100)
- g_string_append_printf (string_long, " (%d%%)", load_progress);
-
if (selected_url[0]!=0) {
g_string_append_printf (string_long, " -> (%s)", selected_url);
}
@@ -588,16 +822,18 @@ update_title (void) {
gchar* title_short = g_string_free (string_short, FALSE);
if (show_status) {
- gtk_window_set_title (GTK_WINDOW(main_window), title_short);
- gtk_label_set_text(GTK_LABEL(mainbar_label), title_long);
+ gtk_window_set_title (GTK_WINDOW(uzbl.gui.main_window), title_short);
+ statln = parse_status_template(status_format);
+ gtk_label_set_markup(GTK_LABEL(uzbl.gui.mainbar_label), statln);
+ g_free(statln);
} else {
- gtk_window_set_title (GTK_WINDOW(main_window), title_long);
+ gtk_window_set_title (GTK_WINDOW(uzbl.gui.main_window), title_long);
}
g_free (title_long);
g_free (title_short);
}
-
+
static gboolean
key_press_cb (WebKitWebView* page, GdkEventKey* event)
{
@@ -617,23 +853,72 @@ key_press_cb (WebKitWebView* page, GdkEventKey* event)
return TRUE;
}
- if (insert_mode && event->state != modmask)
+ if (insert_mode && ((event->state & modmask) != modmask))
return FALSE;
-
if (event->keyval == GDK_Escape) {
g_string_truncate(keycmd, 0);
-
update_title();
+ return TRUE;
+ }
+ //Insert without shift - insert from clipboard; Insert with shift - insert from primary
+ if (event->keyval == GDK_Insert) {
+ gchar * str;
+ if ((event->state & GDK_SHIFT_MASK) == GDK_SHIFT_MASK) {
+ str = gtk_clipboard_wait_for_text (gtk_clipboard_get (GDK_SELECTION_PRIMARY));
+ } else {
+ str = gtk_clipboard_wait_for_text (gtk_clipboard_get (GDK_SELECTION_CLIPBOARD));
+ }
+ if (str) {
+ g_string_append_printf (keycmd, "%s", str);
+ update_title ();
+ free (str);
+ }
return TRUE;
}
- g_string_append(keycmd, event->string);
+ if ((event->keyval == GDK_BackSpace) && (keycmd->len > 0)) {
+ g_string_truncate(keycmd, keycmd->len - 1);
+ update_title();
+ return TRUE;
+ }
+ if ((event->keyval == GDK_Return) || (event->keyval == GDK_KP_Enter)) {
+ GString* short_keys = g_string_new ("");
+ unsigned int i;
+ for (i=0; i<(keycmd->len); i++) {
+ g_string_append_c(short_keys, keycmd->str[i]);
+ g_string_append_c(short_keys, '_');
+
+ //printf("\nTesting string: @%s@\n", short_keys->str);
+ if ((action = g_hash_table_lookup(bindings, short_keys->str))) {
+ GString* parampart = g_string_new (keycmd->str);
+ g_string_erase (parampart, 0, i+1);
+ //printf("\nParameter: @%s@\n", parampart->str);
+ GString* actionname = g_string_new ("");
+ if (action->name)
+ g_string_printf (actionname, action->name, parampart->str);
+ GString* actionparam = g_string_new ("");
+ if (action->param)
+ g_string_printf (actionparam, action->param, parampart->str);
+ parse_command(actionname->str, actionparam->str);
+ g_string_free (actionname, TRUE);
+ g_string_free (actionparam, TRUE);
+ g_string_free (parampart, TRUE);
+ g_string_truncate(keycmd, 0);
+ update_title();
+ }
+
+ g_string_truncate(short_keys, short_keys->len - 1);
+ }
+ g_string_free (short_keys, TRUE);
+ return (!insert_mode);
+ }
+
+ g_string_append(keycmd, event->string);
if ((action = g_hash_table_lookup(bindings, keycmd->str))) {
g_string_truncate(keycmd, 0);
-
parse_command(action->name, action->param);
}
@@ -644,33 +929,38 @@ key_press_cb (WebKitWebView* page, GdkEventKey* event)
static GtkWidget*
create_browser () {
+ GUI *g = &uzbl.gui;
+
GtkWidget* scrolled_window = gtk_scrolled_window_new (NULL, NULL);
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
- web_view = WEBKIT_WEB_VIEW (webkit_web_view_new ());
- gtk_container_add (GTK_CONTAINER (scrolled_window), GTK_WIDGET (web_view));
+ g->web_view = WEBKIT_WEB_VIEW (webkit_web_view_new ());
+ gtk_container_add (GTK_CONTAINER (scrolled_window), GTK_WIDGET (g->web_view));
- g_signal_connect (G_OBJECT (web_view), "title-changed", G_CALLBACK (title_change_cb), web_view);
- g_signal_connect (G_OBJECT (web_view), "load-progress-changed", G_CALLBACK (progress_change_cb), web_view);
- g_signal_connect (G_OBJECT (web_view), "load-committed", G_CALLBACK (load_commit_cb), web_view);
- g_signal_connect (G_OBJECT (web_view), "load-committed", G_CALLBACK (log_history_cb), web_view);
- g_signal_connect (G_OBJECT (web_view), "hovering-over-link", G_CALLBACK (link_hover_cb), web_view);
- 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);
+ g_signal_connect (G_OBJECT (g->web_view), "title-changed", G_CALLBACK (title_change_cb), g->web_view);
+ g_signal_connect (G_OBJECT (g->web_view), "load-progress-changed", G_CALLBACK (progress_change_cb), g->web_view);
+ g_signal_connect (G_OBJECT (g->web_view), "load-committed", G_CALLBACK (load_commit_cb), g->web_view);
+ g_signal_connect (G_OBJECT (g->web_view), "load-committed", G_CALLBACK (log_history_cb), g->web_view);
+ g_signal_connect (G_OBJECT (g->web_view), "hovering-over-link", G_CALLBACK (link_hover_cb), g->web_view);
+ g_signal_connect (G_OBJECT (g->web_view), "key-press-event", G_CALLBACK (key_press_cb), g->web_view);
+ g_signal_connect (G_OBJECT (g->web_view), "new-window-policy-decision-requested", G_CALLBACK (new_window_cb), g->web_view);
+ g_signal_connect (G_OBJECT (g->web_view), "download-requested", G_CALLBACK (download_cb), g->web_view);
+ g_signal_connect (G_OBJECT (g->web_view), "create-web-view", G_CALLBACK (create_web_view_cb), g->web_view);
return scrolled_window;
}
static GtkWidget*
create_mainbar () {
- mainbar = gtk_hbox_new (FALSE, 0);
- mainbar_label = gtk_label_new ("");
- gtk_misc_set_alignment (GTK_MISC(mainbar_label), 0, 0);
- gtk_misc_set_padding (GTK_MISC(mainbar_label), 2, 2);
- gtk_box_pack_start (GTK_BOX (mainbar), mainbar_label, TRUE, TRUE, 0);
- return mainbar;
+ GUI *g = &uzbl.gui;
+
+ g->mainbar = gtk_hbox_new (FALSE, 0);
+ g->mainbar_label = gtk_label_new ("");
+ gtk_label_set_ellipsize(GTK_LABEL(g->mainbar_label), PANGO_ELLIPSIZE_END);
+ gtk_misc_set_alignment (GTK_MISC(g->mainbar_label), 0, 0);
+ gtk_misc_set_padding (GTK_MISC(g->mainbar_label), 2, 2);
+ gtk_box_pack_start (GTK_BOX (g->mainbar), g->mainbar_label, TRUE, TRUE, 0);
+ return g->mainbar;
}
static
@@ -691,6 +981,8 @@ add_binding (const gchar *key, const gchar *act) {
if (!parts)
return;
+ //Debug:
+ printf ("Binding %-10s : %s\n", key, act);
action = new_action(parts[0], parts[1]);
g_hash_table_insert(bindings, g_strdup(key), action);
@@ -703,19 +995,21 @@ settings_init () {
gboolean res = FALSE;
char *saveptr;
gchar** keys = NULL;
+ State *s = &uzbl.state;
+ Network *n = &uzbl.net;
- if (!config_file) {
+ if (!s->config_file) {
const char* XDG_CONFIG_HOME = getenv ("XDG_CONFIG_HOME");
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 (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];
+ strcpy (s->config_file_path, XDG_CONFIG_HOME);
+ strcat (s->config_file_path, "/uzbl/config");
+ if (file_exists (s->config_file_path)) {
+ printf ("Config file %s found.\n", s->config_file_path);
+ s->config_file = &s->config_file_path[0];
} else {
// Now we check $XDG_CONFIG_DIRS
char *XDG_CONFIG_DIRS = getenv ("XDG_CONFIG_DIRS");
@@ -727,25 +1021,25 @@ settings_init () {
char buffer[512];
strcpy (buffer, XDG_CONFIG_DIRS);
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];
+ while (dir && ! file_exists (s->config_file_path)) {
+ strcpy (s->config_file_path, dir);
+ strcat (s->config_file_path, "/uzbl/config_file_pathig");
+ if (file_exists (s->config_file_path)) {
+ printf ("Config file %s found.\n", s->config_file_path);
+ s->config_file = &s->config_file_path[0];
}
dir = (char * ) strtok_r (NULL, ":", &saveptr);
}
}
}
- if (config_file) {
+ if (s->config_file) {
config = g_key_file_new ();
- res = g_key_file_load_from_file (config, config_file, G_KEY_FILE_NONE, NULL);
- if(res) {
- printf ("Config %s loaded\n", config_file);
+ res = g_key_file_load_from_file (config, s->config_file, G_KEY_FILE_NONE, NULL);
+ if (res) {
+ printf ("Config %s loaded\n", s->config_file);
} else {
- fprintf (stderr, "Config %s loading failed\n", config_file);
+ fprintf (stderr, "Config %s loading failed\n", s->config_file);
}
} else {
printf ("No configuration.\n");
@@ -754,6 +1048,7 @@ 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);
+ cookie_handler = g_key_file_get_string (config, "behavior", "cookie_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);
@@ -764,11 +1059,12 @@ settings_init () {
socket_dir = g_key_file_get_value (config, "behavior", "socket_dir", NULL);
keys = g_key_file_get_keys (config, "bindings", NULL, NULL);
}
-
+
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 ("Cookie handler: %s\n", (cookie_handler ? cookie_handler : "disabled"));
+ printf ("Fifo directory: %s\n", (fifo_dir ? fifo_dir : "disabled"));
+ printf ("Socket directory: %s\n", (socket_dir ? socket_dir : "disabled"));
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"));
@@ -810,59 +1106,84 @@ settings_init () {
}
/* networking options */
- proxy_url = g_key_file_get_value (config, "network", "proxy_server", NULL);
- http_debug = g_key_file_get_integer (config, "network", "http_debug", NULL);
- useragent = g_key_file_get_value (config, "network", "user-agent", NULL);
- max_conns = g_key_file_get_integer (config, "network", "max_conns", NULL);
- max_conns_host = g_key_file_get_integer (config, "network", "max_conns_per_host", NULL);
+ if (res) {
+ n->proxy_url = g_key_file_get_value (config, "network", "proxy_server", NULL);
+ http_debug = g_key_file_get_integer (config, "network", "http_debug", NULL);
+ n->useragent = g_key_file_get_value (config, "network", "user-agent", NULL);
+ n->max_conns = g_key_file_get_integer (config, "network", "max_conns", NULL);
+ n->max_conns_host = g_key_file_get_integer (config, "network", "max_conns_per_host", NULL);
+ }
- if(proxy_url){
- g_object_set(G_OBJECT(soup_session), SOUP_SESSION_PROXY_URI, soup_uri_new(proxy_url), NULL);
+ if(n->proxy_url){
+ g_object_set(G_OBJECT(n->soup_session), SOUP_SESSION_PROXY_URI, soup_uri_new(n->proxy_url), NULL);
}
if(!(http_debug <= 3)){
http_debug = 0;
fprintf(stderr, "Wrong http_debug level, ignoring.\n");
} else if (http_debug > 0) {
- soup_logger = soup_logger_new(http_debug, -1);
- soup_session_add_feature(soup_session, SOUP_SESSION_FEATURE(soup_logger));
+ n->soup_logger = soup_logger_new(http_debug, -1);
+ soup_session_add_feature(n->soup_session, SOUP_SESSION_FEATURE(n->soup_logger));
}
- if(useragent){
- g_object_set(G_OBJECT(soup_session), SOUP_SESSION_USER_AGENT, useragent, NULL);
+ if(n->useragent){
+ char* newagent = malloc(1024);
+
+ strcpy(newagent, str_replace("%webkit-major%", itos(WEBKIT_MAJOR_VERSION), n->useragent));
+ strcpy(newagent, str_replace("%webkit-minor%", itos(WEBKIT_MINOR_VERSION), newagent));
+ strcpy(newagent, str_replace("%webkit-micro%", itos(WEBKIT_MICRO_VERSION), newagent));
+
+ if (uname (&unameinfo) == -1) {
+ printf("Error getting uname info. Not replacing system-related user agent variables.\n");
+ } else {
+ strcpy(newagent, str_replace("%sysname%", unameinfo.sysname, newagent));
+ strcpy(newagent, str_replace("%nodename%", unameinfo.nodename, newagent));
+ strcpy(newagent, str_replace("%kernrel%", unameinfo.release, newagent));
+ strcpy(newagent, str_replace("%kernver%", unameinfo.version, newagent));
+ strcpy(newagent, str_replace("%arch-system%", unameinfo.machine, newagent));
+
+ #ifdef _GNU_SOURCE
+ strcpy(newagent, str_replace("%domainname%", unameinfo.domainname, newagent));
+ #endif
+ }
+
+ strcpy(newagent, str_replace("%arch-uzbl%", ARCH, newagent));
+ strcpy(newagent, str_replace("%commit%", COMMIT, newagent));
+
+ n->useragent = malloc(1024);
+ strcpy(n->useragent, newagent);
+ g_object_set(G_OBJECT(n->soup_session), SOUP_SESSION_USER_AGENT, n->useragent, NULL);
}
- if(max_conns >= 1){
- g_object_set(G_OBJECT(soup_session), SOUP_SESSION_MAX_CONNS, max_conns, NULL);
+ if(n->max_conns >= 1){
+ g_object_set(G_OBJECT(n->soup_session), SOUP_SESSION_MAX_CONNS, n->max_conns, NULL);
}
- if(max_conns_host >= 1){
- g_object_set(G_OBJECT(soup_session), SOUP_SESSION_MAX_CONNS_PER_HOST, max_conns_host, NULL);
+ if(n->max_conns_host >= 1){
+ g_object_set(G_OBJECT(n->soup_session), SOUP_SESSION_MAX_CONNS_PER_HOST, n->max_conns_host, NULL);
}
- printf("Proxy configured: %s\n", proxy_url ? proxy_url : "none");
+ printf("Proxy configured: %s\n", n->proxy_url ? n->proxy_url : "none");
printf("HTTP logging level: %d\n", http_debug);
- printf("User-agent: %s\n", useragent? useragent : "default");
- printf("Maximum connections: %d\n", max_conns ? max_conns : 0);
- printf("Maximum connections per host: %d\n", max_conns_host ? max_conns_host: 0);
+ printf("User-agent: %s\n", n->useragent? n->useragent : "default");
+ printf("Maximum connections: %d\n", n->max_conns ? n->max_conns : 0);
+ printf("Maximum connections per host: %d\n", n->max_conns_host ? n->max_conns_host: 0);
+
- /* om nom nom nom */
- cookie_handler = g_key_file_get_string(config, "behavior", "cookie_handler", NULL);
if(cookie_handler){
/* ck = soup_cookie_jar_new(); */
/* soup_session_add_feature(soup_session, SOUP_SESSION_FEATURE(ck)); */
/* g_signal_connect(ck, "changed", G_CALLBACK(cookie_recieved_action), NULL); */
- g_signal_connect(soup_session, "request-queued", G_CALLBACK(handle_cookies), NULL);
- printf("Cookie handler: %s\n", cookie_handler);
+ g_signal_connect(n->soup_session, "request-queued", G_CALLBACK(handle_cookies), NULL);
}
}
-static void handle_cookies (SoupSession *session,
- SoupMessage *msg,
- gpointer user_data){
- soup_message_add_header_handler(msg, "got-headers", "Set-Cookie", G_CALLBACK(save_cookies), NULL);
+static void handle_cookies (SoupSession *session, SoupMessage *msg, gpointer user_data){
+ (void) session;
+ (void) user_data;
+ soup_message_add_header_handler(msg, "got-headers", "Set-Cookie", G_CALLBACK(save_cookies), NULL);
/* ask handler for cookies, if there are any, use
soup_message_headers_replace (msg->request_headers,
@@ -872,19 +1193,19 @@ static void handle_cookies (SoupSession *session,
}
static void
-save_cookies (SoupMessage *msg,
- gpointer user_data){
- GSList *ck;
- char *req, *cookie;
- for (ck = soup_cookies_from_response(msg); ck; ck = ck->next){
- cookie = soup_cookie_to_set_cookie_header(ck->data);
- req = malloc(strlen(cookie) + 10);
- sprintf(req, "PUT \"%s\"", cookie);
- run_command_async(cookie_handler, req);
- free(req);
- free(cookie);
- }
- g_slist_free(ck);
+save_cookies (SoupMessage *msg, gpointer user_data){
+ (void) user_data;
+ GSList *ck;
+ char *req, *cookie;
+ for (ck = soup_cookies_from_response(msg); ck; ck = ck->next){
+ cookie = soup_cookie_to_set_cookie_header(ck->data);
+ req = malloc(strlen(cookie) + 10);
+ sprintf(req, "PUT \"%s\"", cookie);
+ run_command_async(cookie_handler, req);
+ free(req);
+ free(cookie);
+ }
+ g_slist_free(ck);
}
int
@@ -907,7 +1228,7 @@ main (int argc, char* argv[]) {
/* initialize hash table */
bindings = g_hash_table_new_full(g_str_hash, g_str_equal, g_free, free_action);
- soup_session = webkit_get_default_session();
+ uzbl.net.soup_session = webkit_get_default_session();
keycmd = g_string_new("");
settings_init ();
@@ -923,35 +1244,42 @@ main (int argc, char* argv[]) {
if (!status_top)
gtk_box_pack_start (GTK_BOX (vbox), create_mainbar (), FALSE, TRUE, 0);
- main_window = create_window ();
- gtk_container_add (GTK_CONTAINER (main_window), vbox);
+ uzbl.gui.main_window = create_window ();
+ gtk_container_add (GTK_CONTAINER (uzbl.gui.main_window), vbox);
- load_uri (web_view, uri);
+ load_uri (uzbl.gui.web_view, uzbl.state.uri);
- gtk_widget_grab_focus (GTK_WIDGET (web_view));
- gtk_widget_show_all (main_window);
- xwin = GDK_WINDOW_XID (GTK_WIDGET (main_window)->window);
- printf("window_id %i\n",(int) xwin);
+ gtk_widget_grab_focus (GTK_WIDGET (uzbl.gui.web_view));
+ gtk_widget_show_all (uzbl.gui.main_window);
+ uzbl.xwin = GDK_WINDOW_XID (GTK_WIDGET (uzbl.gui.main_window)->window);
+ printf("window_id %i\n",(int) uzbl.xwin);
printf("pid %i\n", getpid ());
+ printf("name: %s\n", uzbl.state.instance_name);
+
+ uzbl.gui.scbar_v = (GtkScrollbar*) gtk_vscrollbar_new (NULL);
+ uzbl.gui.bar_v = gtk_range_get_adjustment((GtkRange*) uzbl.gui.scbar_v);
+ uzbl.gui.scbar_h = (GtkScrollbar*) gtk_hscrollbar_new (NULL);
+ uzbl.gui.bar_h = gtk_range_get_adjustment((GtkRange*) uzbl.gui.scbar_h);
+ gtk_widget_set_scroll_adjustments ((GtkWidget*) uzbl.gui.web_view, uzbl.gui.bar_h, uzbl.gui.bar_v);
- scbar_v = (GtkScrollbar*) gtk_vscrollbar_new (NULL);
- bar_v = gtk_range_get_adjustment((GtkRange*) scbar_v);
- scbar_h = (GtkScrollbar*) gtk_hscrollbar_new (NULL);
- bar_h = gtk_range_get_adjustment((GtkRange*) scbar_h);
- gtk_widget_set_scroll_adjustments ((GtkWidget*) web_view, bar_h, bar_v);
if (!show_status)
- gtk_widget_hide(mainbar);
+ gtk_widget_hide(uzbl.gui.mainbar);
+ setup_scanner();
- setup_threading ();
- create_fifo ();
+ if (fifo_dir)
+ create_fifo ();
+ if (socket_dir)
+ create_socket();
gtk_main ();
g_string_free(keycmd, TRUE);
- unlink (socket_path);
- unlink (fifo_path);
+ if (fifo_dir)
+ unlink (uzbl.comm.fifo_path);
+ if (socket_dir)
+ unlink (uzbl.comm.socket_path);
g_hash_table_destroy(bindings);
g_hash_table_destroy(commands);