From 475e6b6e68020dec0a6cd00988f6134f30a29601 Mon Sep 17 00:00:00 2001 From: Daniel Carl Date: Sat, 13 Oct 2012 23:34:40 +0200 Subject: [PATCH] Added possibility to run commands from inputbox. --- config.mk | 2 +- src/command.c | 8 ++- src/command.h | 2 +- src/config.h | 7 ++- src/keybind.c | 51 ++++++++-------- src/keybind.h | 3 +- src/main.c | 166 ++++++++++++++++++++++++++++++++++++++++++++++++-- src/main.h | 14 ++++- 8 files changed, 214 insertions(+), 39 deletions(-) diff --git a/config.mk b/config.mk index be2c1ff..f013fa6 100644 --- a/config.mk +++ b/config.mk @@ -33,7 +33,7 @@ DFLAGS += -g #----------------end of options---------------------- OBJ = $(patsubst %.c, %.o, $(wildcard src/*.c)) DOBJ = $(patsubst %.c, %.do, $(wildcard src/*.c)) -HEAD = $(wildcard *.h) +HEAD = $(wildcard src/*.h) DEPS = $(OBJ:%.o=%.d) TARGET = $(PROJECT) diff --git a/src/command.c b/src/command.c index 4293dba..2dbbb77 100644 --- a/src/command.c +++ b/src/command.c @@ -3,6 +3,8 @@ static CommandInfo cmd_list[] = { /* command function arg */ + {"normal", vp_set_mode, {VP_MODE_NORMAL, ""}}, + {"input", vp_input, {0, ":"}}, {"quit", vp_close_browser, {0}}, {"source", vp_view_source, {0}}, {"back", vp_navigate, {VP_NAVIG_BACK}}, @@ -34,16 +36,18 @@ void command_init() } } -void command_run(const gchar* name) +gboolean command_run(const gchar* name) { CommandInfo* c = NULL; Arg a; c = g_hash_table_lookup(vp.behave.commands, name); if (!c) { - return; + return FALSE; } a.i = c->arg.i; a.s = g_strdup(c->arg.s); c->function(&a); g_free(a.s); + + return TRUE; } diff --git a/src/command.h b/src/command.h index 929aba8..f4bd15b 100644 --- a/src/command.h +++ b/src/command.h @@ -14,6 +14,6 @@ typedef struct { void command_init(void); -void command_run(const gchar* name); +gboolean command_run(const gchar* name); #endif /* end of include guard: COMMAND_H */ diff --git a/src/config.h b/src/config.h index 0f8511d..e8b12e9 100644 --- a/src/config.h +++ b/src/config.h @@ -6,7 +6,12 @@ #define STATUS_BG_COLOR "#000000" /* background color for status bar */ #define STATUS_FG_COLOR "#ffffff" /* foreground color for status bar */ #define STATUS_BAR_FONT "monospace bold 8" -#define URL_BOX_FONT "monospace 8" + + /* normal error */ +static const char *inputbox_font[] = { "monospace normal 8", "monospace bold 8"}; +static const char *inputbox_fg[] = { "#000000", "#000000" }; +static const char *inputbox_bg[] = { "#ffffff", "#ff0000" }; + #define SETTING_DEFAUL_FONT_SIZE 12 #define SETTING_USER_AGENT PROJECT "/" VERSION " (X11; Linux i686) AppleWebKit/535.22+ Compatible (Safari)" diff --git a/src/keybind.c b/src/keybind.c index 884f725..2d02485 100644 --- a/src/keybind.c +++ b/src/keybind.c @@ -11,7 +11,7 @@ static gboolean keybind_keypress_callback(WebKitWebView* webview, GdkEventKey* e void keybind_init(void) { modkeys = g_string_new(""); - g_signal_connect(G_OBJECT(vp.gui.webview), "key-press-event", G_CALLBACK(keybind_keypress_callback), NULL); + g_signal_connect(G_OBJECT(vp.gui.window), "key-press-event", G_CALLBACK(keybind_keypress_callback), NULL); } void keybind_add(int mode, guint modkey, guint modmask, guint keyval, const gchar* command) @@ -49,38 +49,41 @@ static gboolean keybind_keypress_callback(WebKitWebView* webview, GdkEventKey* e /* check for escape or modkeys or counts */ if ((CLEAN(event->state) & ~irrelevant) == 0) { if (IS_ESCAPE(event)) { - /* TODO add function to main.c to switch the mode */ - /* switch to normal mode */ - vp.state.mode = VP_MODE_NORMAL; - /* remove current modkey and set count back to 0 */ - vp.state.modkey = vp.state.count = 0; - vp_update_statusbar(); - - return TRUE; - } else if (vp.state.modkey == 0 && ((event->keyval >= GDK_1 && event->keyval <= GDK_9) - || (event->keyval == GDK_0 && vp.state.count))) { - /* append the new entered count to previous one */ - vp.state.count = (vp.state.count ? vp.state.count * 10 : 0) + (event->keyval - GDK_0); - vp_update_statusbar(); - - return TRUE; - } else if (strchr(modkeys->str, event->keyval) && vp.state.modkey != event->keyval) { - vp.state.modkey = (gchar)event->keyval; - vp_update_statusbar(); + /* switch to normal mode and clear the input box */ + Arg a = {VP_MODE_NORMAL, ""}; + vp_set_mode(&a); return TRUE; } + /* allow mode keys and counts only in normal mode */ + if (VP_MODE_NORMAL == vp.state.mode) { + if (vp.state.modkey == 0 && ((event->keyval >= GDK_1 && event->keyval <= GDK_9) + || (event->keyval == GDK_0 && vp.state.count))) { + /* append the new entered count to previous one */ + vp.state.count = (vp.state.count ? vp.state.count * 10 : 0) + (event->keyval - GDK_0); + vp_update_statusbar(); + + return TRUE; + } + if (strchr(modkeys->str, event->keyval) && vp.state.modkey != event->keyval) { + vp.state.modkey = (gchar)event->keyval; + vp_update_statusbar(); + + return TRUE; + } + } } + /* TODO move to own function */ /* check for keybinding */ for (tmp = keys; tmp != NULL; tmp = tmp->next) { struct _keybind_key* keybind = (struct _keybind_key*)tmp->data; /* handle key presses */ - if (keybind->modmask == (CLEAN(event->state) & ~irrelevant) - && keybind->modkey == vp.state.modkey - && keybind->keyval == keyval - && keybind->command - ) { + if (keybind->mode == vp.state.mode + && keybind->modmask == (CLEAN(event->state) & ~irrelevant) + && keybind->modkey == vp.state.modkey + && keybind->keyval == keyval + && keybind->command) { command_run(keybind->command); /* if key binding used, remove the modkey */ diff --git a/src/keybind.h b/src/keybind.h index 3758512..1be98de 100644 --- a/src/keybind.h +++ b/src/keybind.h @@ -10,8 +10,7 @@ /* remove unused bits, numlock symbol and buttons from keymask */ #define CLEAN(mask) (mask & (GDK_MODIFIER_MASK) & ~(CLEAN_MOD_NUMLOCK_MASK) & ~(CLEAN_MOD_BUTTON_MASK)) #define IS_ESCAPE(event) (IS_ESCAPE_KEY(CLEAN(event->state), event->keyval)) -#define IS_ESCAPE_KEY(s, k) ((s == 0 && k == GDK_Escape) || \ - (s == GDK_CONTROL_MASK && k == GDK_bracketleft)) +#define IS_ESCAPE_KEY(s, k) ((s == 0 && k == GDK_Escape) || (s == GDK_CONTROL_MASK && k == GDK_c)) struct _keybind_key { int mode; /* mode maks for allowed browser modes */ diff --git a/src/main.c b/src/main.c index 2d8eca6..2116c1f 100644 --- a/src/main.c +++ b/src/main.c @@ -8,18 +8,22 @@ VpCore vp; /* callbacks */ static void vp_webview_load_status_cb(WebKitWebView* view, GParamSpec* pspec, gpointer user_data); -static void vp_webview_load_commited_cb(WebKitWebView *webview, WebKitWebFrame *frame, gpointer user_data); +static void vp_webview_load_commited_cb(WebKitWebView *webview, WebKitWebFrame* frame, gpointer user_data); static void vp_destroy_window_cb(GtkWidget* widget, GtkWidget* window, gpointer user_data); static gboolean vp_frame_scrollbar_policy_changed_cb(void); +static void vp_inputbox_activate_cb(GtkEntry* entry, gpointer user_data); +static gboolean vp_inputbox_keypress_cb(GtkEntry* entry, GdkEventKey* event); +static gboolean vp_inputbox_keyrelease_cb(GtkEntry* entry, GdkEventKey* event); /* functions */ +static gboolean vp_process_input(const char* input); static void vp_print_version(void); static void vp_init(void); static void vp_init_gui(void); +static void vp_set_widget_font(GtkWidget* widget, const gchar* font_definition, const gchar* bg_color, const gchar* fg_color); static void vp_setup_settings(void); static void vp_setup_signals(void); - static void vp_webview_load_status_cb(WebKitWebView* view, GParamSpec* pspec, gpointer user_data) { Gui* gui = &vp.gui; @@ -55,6 +59,68 @@ static gboolean vp_frame_scrollbar_policy_changed_cb(void) return TRUE; } +static void vp_inputbox_activate_cb(GtkEntry *entry, gpointer user_data) +{ + gboolean success = FALSE; + const gchar *text; + guint16 length = gtk_entry_get_text_length(entry); + Gui* gui = &vp.gui; + + if (0 == length) { + return; + } + + gtk_widget_grab_focus(GTK_WIDGET(gui->webview)); + + /* do not free or modify text */ + text = gtk_entry_get_text(entry); + + if (1 < length && ':' == text[0]) { + success = vp_process_input((text + 1)); + if (!success) { + /* print error message */ + gchar* message = g_strdup_printf("Command '%s' not found", (text + 1)); + vp_echo(VP_MSG_ERROR, message); + g_free(message); + + /* switch to normal mode after running command */ + Arg a = {VP_MODE_NORMAL}; + vp_set_mode(&a); + } else { + /* switch to normal mode after running command and clean input */ + Arg a = {VP_MODE_NORMAL, ""}; + vp_set_mode(&a); + } + } +} + +static gboolean vp_inputbox_keypress_cb(GtkEntry *entry, GdkEventKey *event) +{ + return FALSE; +} + +static gboolean vp_inputbox_keyrelease_cb(GtkEntry *entry, GdkEventKey *event) +{ + return FALSE; +} + +static gboolean vp_process_input(const char* input) +{ + gboolean success; + gchar* command = g_strdup(input); + + g_strstrip(command); + size_t length = strlen(command); + if (0 == length) { + return FALSE; + } + + success = command_run(command); + g_free(command); + + return success; +} + gboolean vp_load_uri(const Arg* arg) { char* u; @@ -142,6 +208,55 @@ void vp_view_source(const Arg* arg) webkit_web_view_reload(vp.gui.webview); } +void vp_set_mode(const Arg* arg) +{ + vp.state.mode = arg->i; + vp.state.modkey = vp.state.count = 0; + + switch (arg->i) { + case VP_MODE_NORMAL: + gtk_widget_grab_focus(GTK_WIDGET(vp.gui.webview)); + break; + + case VP_MODE_COMMAND: + gtk_widget_grab_focus(GTK_WIDGET(vp.gui.inputbox)); + break; + + case VP_MODE_INSERT: + gtk_widget_grab_focus(GTK_WIDGET(vp.gui.webview)); + break; + + case VP_MODE_PATH_THROUGH: + gtk_widget_grab_focus(GTK_WIDGET(vp.gui.webview)); + break; + } + + /* echo message if given */ + if (arg->s) { + vp_echo(VP_MSG_NORMAL, arg->s); + } + + vp_update_statusbar(); +} + +void vp_input(const Arg* arg) +{ + gint pos = 0; + + /* reset the colors and fonts to defalts */ + vp_set_widget_font(vp.gui.inputbox, inputbox_font[0], inputbox_bg[0], inputbox_fg[0]); + + /* remove content from input box */ + gtk_entry_set_text(GTK_ENTRY(vp.gui.inputbox), ""); + + /* insert text */ + gtk_editable_insert_text(GTK_EDITABLE(vp.gui.inputbox), arg->s, -1, &pos); + gtk_editable_set_position(GTK_EDITABLE(vp.gui.inputbox), -1); + + Arg a = {VP_MODE_COMMAND}; + vp_set_mode(&a); +} + void vp_update_urlbar(const gchar* uri) { gchar* markup; @@ -182,6 +297,19 @@ void vp_update_statusbar(void) g_free(markup); } +void vp_echo(const MessageType type, const gchar *message) +{ + /* don't print message if the input is focussed */ + if (gtk_widget_is_focus(GTK_WIDGET(vp.gui.inputbox))) { + return; + } + + /* set the collors according to message type */ + vp_set_widget_font(vp.gui.inputbox, inputbox_font[type], inputbox_bg[type], inputbox_fg[type]); + gtk_entry_set_text(GTK_ENTRY(vp.gui.inputbox), message); +} + + static void vp_print_version(void) { fprintf(stderr, "%s/%s (build %s %s)\n", VERSION, PROJECT, __DATE__, __TIME__); @@ -197,6 +325,7 @@ static void vp_init(void) keybind_init(); keybind_add(VP_MODE_NORMAL, GDK_g, 0, GDK_f, "source"); + keybind_add(VP_MODE_NORMAL, 0, 0, GDK_colon, "input"); keybind_add(VP_MODE_NORMAL, 0, 0, GDK_d, "quit"); keybind_add(VP_MODE_NORMAL, 0, GDK_CONTROL_MASK, GDK_o, "back"); keybind_add(VP_MODE_NORMAL, 0, GDK_CONTROL_MASK, GDK_i, "forward"); @@ -253,9 +382,7 @@ static void vp_init_gui(void) gtk_entry_set_inner_border(GTK_ENTRY(gui->inputbox), NULL); g_object_set(gtk_widget_get_settings(gui->inputbox), "gtk-entry-select-on-focus", FALSE, NULL); - PangoFontDescription* font = pango_font_description_from_string(URL_BOX_FONT); - gtk_widget_modify_font(GTK_WIDGET(gui->inputbox), font); - pango_font_description_free(font); + vp_set_widget_font(gui->inputbox, inputbox_font[0], inputbox_bg[0], inputbox_fg[0]); /* Prepare the statusbar */ gui->statusbar.box = GTK_BOX(gtk_hbox_new(FALSE, 0)); @@ -297,6 +424,26 @@ static void vp_init_gui(void) gtk_widget_show_all(gui->window); } +static void vp_set_widget_font(GtkWidget* widget, const gchar* font_definition, const gchar* bg_color, const gchar* fg_color) +{ + GdkColor fg, bg; + PangoFontDescription *font; + + font = pango_font_description_from_string(font_definition); + gtk_widget_modify_font(widget, font); + pango_font_description_free(font); + + if (fg_color) { + gdk_color_parse(fg_color, &fg); + } + if (bg_color) { + gdk_color_parse(bg_color, &bg); + } + + gtk_widget_modify_text(widget, GTK_STATE_NORMAL, fg_color ? &fg : NULL); + gtk_widget_modify_base(widget, GTK_STATE_NORMAL, bg_color ? &bg : NULL); +} + static void vp_setup_settings(void) { WebKitWebSettings *settings = webkit_web_view_get_settings(vp.gui.webview); @@ -319,6 +466,15 @@ static void vp_setup_signals(void) g_signal_connect(G_OBJECT(frame), "scrollbars-policy-changed", G_CALLBACK(vp_frame_scrollbar_policy_changed_cb), NULL); g_signal_connect(G_OBJECT(gui->webview), "notify::load-status", G_CALLBACK(vp_webview_load_status_cb), NULL); g_signal_connect(G_OBJECT(gui->webview), "load-committed", G_CALLBACK(vp_webview_load_commited_cb), NULL); + + g_object_connect( + G_OBJECT(gui->inputbox), + "signal::activate", G_CALLBACK(vp_inputbox_activate_cb), NULL, + "signal::key-press-event", G_CALLBACK(vp_inputbox_keypress_cb), NULL, + "signal::key-release-event", G_CALLBACK(vp_inputbox_keyrelease_cb), NULL, + NULL + ); + } int main(int argc, char* argv[]) diff --git a/src/main.h b/src/main.h index 7ce8095..68e913d 100644 --- a/src/main.h +++ b/src/main.h @@ -26,9 +26,10 @@ /* enums */ typedef enum _vp_mode { - VP_MODE_NORMAL = (1 << 0), - VP_MODE_PATH_THROUGH = (1 << 1), - VP_MODE_INSERT = (1 << 2), + VP_MODE_NORMAL, + VP_MODE_COMMAND, + VP_MODE_PATH_THROUGH, + VP_MODE_INSERT, } Mode; enum { @@ -62,6 +63,10 @@ enum { VP_SCROLL_UNIT_LINE = (1 << 3), VP_SCROLL_UNIT_HALFPAGE = (1 << 4) }; +typedef enum { + VP_MSG_NORMAL, + VP_MSG_ERROR +} MessageType; /* structs */ typedef struct { @@ -123,10 +128,13 @@ extern VpCore vp; /* functions */ void vp_update_statusbar(void); void vp_update_urlbar(const gchar* uri); +void vp_echo(const MessageType type, const gchar *message); gboolean vp_load_uri(const Arg* arg); void vp_navigate(const Arg* arg); void vp_scroll(const Arg* arg); void vp_close_browser(const Arg* arg); void vp_view_source(const Arg* arg); +void vp_set_mode(const Arg* arg); +void vp_input(const Arg* arg); #endif /* end of include guard: MAIN_H */ -- 2.20.1