Added possibility to run commands from inputbox.
authorDaniel Carl <danielcarl@gmx.de>
Sat, 13 Oct 2012 21:34:40 +0000 (23:34 +0200)
committerDaniel Carl <danielcarl@gmx.de>
Sun, 14 Oct 2012 13:53:55 +0000 (15:53 +0200)
config.mk
src/command.c
src/command.h
src/config.h
src/keybind.c
src/keybind.h
src/main.c
src/main.h

index be2c1ff..f013fa6 100644 (file)
--- 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)
index 4293dba..2dbbb77 100644 (file)
@@ -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;
 }
index 929aba8..f4bd15b 100644 (file)
@@ -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 */
index 0f8511d..e8b12e9 100644 (file)
@@ -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)"
index 884f725..2d02485 100644 (file)
@@ -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 */
index 3758512..1be98de 100644 (file)
@@ -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 */
index 2d8eca6..2116c1f 100644 (file)
@@ -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, WebKitWebFrameframe, 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[])
index 7ce8095..68e913d 100644 (file)
 
 /* 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 */