From 12b628a8aa3b7df67487f426fcb2fe2a32e2def5 Mon Sep 17 00:00:00 2001 From: Daniel Carl Date: Wed, 19 Sep 2012 01:20:32 +0200 Subject: [PATCH] Start of project. --- Makefile | 45 ++++++++++ config.mk | 45 ++++++++++ src/callback.c | 31 +++++++ src/callback.h | 9 ++ src/command.c | 89 +++++++++++++++++++ src/command.h | 23 +++++ src/config.h | 11 +++ src/keybind.c | 100 +++++++++++++++++++++ src/keybind.h | 27 ++++++ src/main.c | 232 +++++++++++++++++++++++++++++++++++++++++++++++++ src/main.h | 102 ++++++++++++++++++++++ 11 files changed, 714 insertions(+) create mode 100644 Makefile create mode 100644 config.mk create mode 100644 src/callback.c create mode 100644 src/callback.h create mode 100644 src/command.c create mode 100644 src/command.h create mode 100644 src/config.h create mode 100644 src/keybind.c create mode 100644 src/keybind.h create mode 100644 src/main.c create mode 100644 src/main.h diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..1ea23d6 --- /dev/null +++ b/Makefile @@ -0,0 +1,45 @@ +include config.mk + +all: $(TARGET) + +-include $(DEPS) + +options: + @echo "$(PROJECT) build options:" + @echo "LIBS = $(LIBS)" + @echo "CC = $(CC)" + @echo "CFLAGS = $(CFLAGS)" + @echo "CPPFLAGS = $(CPPFLAGS)" + @echo "LDFLAGS = $(LDFLAGS)" + +all: $(TARGET) + +$(TARGET): $(OBJ) + @echo "$(CC) $@" + @$(CC) $(OBJ) -o $(TARGET) $(LDFLAGS) + +%.o: %.c $(HEAD) + @echo "${CC} $<" + @$(CC) -c -o $@ $< $(CPPFLAGS) $(CFLAGS) + +debug: $(DTARGET) + +$(DTARGET): $(DOBJ) + @echo "$(CC) $@" + @$(CC) $(DFLAGS) $(DOBJ) -o $(DTARGET) $(LDFLAGS) + +%.do: %.c $(HEAD) + @echo "${CC} $<" + @$(CC) -c -o $@ $< $(CPPFLAGS) $(DFLAGS) + +clean: + $(RM) $(OBJ) $(DOBJ) $(TARGET) $(DTARGET) + +dist: distclean + @echo "Creating tarball." + @git archive --format tar -o $(DIST_FILE) HEAD + +distclean: + $(RM) $(DIST_FILE) + +.PHONY: clean debug all install uninstall options dist diff --git a/config.mk b/config.mk new file mode 100644 index 0000000..d0a5fb0 --- /dev/null +++ b/config.mk @@ -0,0 +1,45 @@ +#----------------user/install options---------------- +VERSION = 0.1.0 + +PROJECT = vimprobable +PREFIX ?= /usr/local +BINDIR ?= $(PREFIX)/bin/ +MANDIR ?= $(PREFIX)/share/man/ + +#----------------compile options--------------------- +LIBS = gtk+-2.0 webkit-1.0 + +CFLAGS += $(shell pkg-config --cflags $(LIBS)) +CFLAGS += -Wall +CFLAGS += -pipe +CFLAGS += -ansi +CFLAGS += -std=c99 +CFLAGS += -pedantic +CFLAGS += -Wmissing-declarations +CFLAGS += -Wmissing-parameter-type +#CFLAGS += -Wstrict-prototypes + +LDFLAGS += $(shell pkg-config --libs $(LIBS)) -lX11 -lXext + +CPPFLAGS += -DPROJECT=\"$(PROJECT)\" +CPPFLAGS += -DVERSION=\"${VERSION}\" + +#----------------developer options------------------- +DFLAGS += $(CFLAGS) +DFLAGS += -DDEBUG +DFLAGS += -ggdb +DFLAGS += -g + +#----------------end of options---------------------- +OBJ = $(patsubst %.c, %.o, $(wildcard src/*.c)) +DOBJ = $(patsubst %.c, %.do, $(wildcard src/*.c)) +HEAD = $(wildcard *.h) +DEPS = $(OBJ:%.o=%.d) + +TARGET = $(PROJECT) +DTARGET = $(TARGET)_dbg +DIST_FILE = $(PROJECT)_$(VERSION).tar.gz + +FMOD = 0644 + +MFLAGS = --no-print-directory diff --git a/src/callback.c b/src/callback.c new file mode 100644 index 0000000..9f2b099 --- /dev/null +++ b/src/callback.c @@ -0,0 +1,31 @@ +#include "main.h" +#include "callback.h" +#include "config.h" + +void webview_load_status_cb(WebKitWebView* view, GParamSpec* pspec) +{ + Gui* gui = &vp.gui; + const char* uri = webkit_web_view_get_uri(gui->webview); + + switch (webkit_web_view_get_load_status(gui->webview)) { + case WEBKIT_LOAD_COMMITTED: + vp_update_urlbar(uri); + break; + + case WEBKIT_LOAD_FINISHED: + break; + + default: + break; + } +} + +void destroy_window_cb(GtkWidget* widget, GtkWidget* window) +{ + vp_close_browser(0); +} + +gboolean dummy_cb(void) +{ + return TRUE; +} diff --git a/src/callback.h b/src/callback.h new file mode 100644 index 0000000..d2839ae --- /dev/null +++ b/src/callback.h @@ -0,0 +1,9 @@ +#ifndef CALLBACKS_H +#define CALLBACKS_H + +/* callbacks */ +void webview_load_status_cb(WebKitWebView* view, GParamSpec* pspec); +void destroy_window_cb(GtkWidget* widget, GtkWidget* window); +gboolean dummy_cb(void); + +#endif /* end of include guard: CALLBACKS_H */ diff --git a/src/command.c b/src/command.c new file mode 100644 index 0000000..55e0255 --- /dev/null +++ b/src/command.c @@ -0,0 +1,89 @@ +#include "command.h" + +static CommandInfo cmd_list[] = { + /* command function */ + {"quit", quit}, + {"source", view_source}, +}; + +static void command_sharg_append(GArray* a, const gchar* str); + + +void command_init() +{ + guint i; + vp.behave.commands = g_hash_table_new(g_str_hash, g_str_equal); + + for (i = 0; i < LENGTH(cmd_list); i++) { + g_hash_table_insert(vp.behave.commands, (gpointer)cmd_list[i].name, &cmd_list[i]); + } +} + +void command_parse_line(const gchar* line, GString* result) +{ + gchar* string = g_strdup(line); + + /* strip trailing newline, and any other whitespace from left */ + g_strstrip(string); + + if (strcmp(string, "")) { + /* ignore comment lines */ + if ((string[0] != '#')) { + GArray* a = g_array_new(TRUE, FALSE, sizeof(gchar*)); + const CommandInfo* c = command_parse_parts(string, a); + if (c) { + command_run_command(c, a, result); + } + g_array_free(a, TRUE); + } + } + + g_free(string); +} + +/* static? */ +const CommandInfo* command_parse_parts(const gchar* line, GArray* a) +{ + CommandInfo* c = NULL; + + /* split the line into the command and its parameters */ + gchar **tokens = g_strsplit(line, " ", 2); + + /* look up the command */ + c = g_hash_table_lookup(vp.behave.commands, tokens[0]); + if (!c) { + g_strfreev(tokens); + return NULL; + } + + gchar* p = g_strdup(tokens[1]); + command_sharg_append(a, p); + + g_strfreev(tokens); + g_free(p); + + return c; +} + +void command_run_command(const CommandInfo* c, GArray* a, GString* result) +{ + c->function(a, result); +} + +static void command_sharg_append(GArray* a, const gchar* str) +{ + const gchar* s = (str ? str : ""); + g_array_append_val(a, s); +} + +void quit(GArray* argv, GString* result) +{ + vp_close_browser(); +} + +void view_source(GArray* argv, GString* result) +{ + gboolean mode = webkit_web_view_get_view_source_mode(vp.gui.webview); + webkit_web_view_set_view_source_mode(vp.gui.webview, !mode); + webkit_web_view_reload(vp.gui.webview); +} diff --git a/src/command.h b/src/command.h new file mode 100644 index 0000000..36acfc7 --- /dev/null +++ b/src/command.h @@ -0,0 +1,23 @@ +#ifndef COMMAND_H +#define COMMAND_H + +#include "main.h" +#include + +typedef void (*Command)(GArray *argv, GString *result); + +typedef struct { + const gchar* name; + Command function; +} CommandInfo; + + +void command_init(void); +void command_parse_line(const gchar* line, GString* result); +const CommandInfo* command_parse_parts(const gchar* line, GArray* a); +void command_run_command(const CommandInfo* c, GArray* a, GString* result); + +void quit(GArray* argv, GString* result); +void view_source(GArray* argv, GString* result); + +#endif /* end of include guard: COMMAND_H */ diff --git a/src/config.h b/src/config.h new file mode 100644 index 0000000..42e6b51 --- /dev/null +++ b/src/config.h @@ -0,0 +1,11 @@ +#ifndef CONFIG_H +#define CONFIG_H + +#define START_PAGE "http://sourceforge.net/apps/trac/vimprobable" + +#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" + +#endif /* end of include guard: CONFIG_H */ diff --git a/src/keybind.c b/src/keybind.c new file mode 100644 index 0000000..a79cb5f --- /dev/null +++ b/src/keybind.c @@ -0,0 +1,100 @@ +#include "main.h" +#include "keybind.h" +#include "command.h" + +static GSList* keys = NULL; +static GString* modkeys = NULL; + +static gboolean keybind_keypress_callback(WebKitWebView* webview, GdkEventKey* event); + + +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); +} + +void keybind_add(int mode, guint modkey, guint modmask, guint keyval, const gchar* command) +{ + struct _keybind_key* keybind = g_new0(struct _keybind_key, 1); + + keybind->mode = mode; + keybind->modkey = modkey; + keybind->modmask = modmask; + keybind->keyval = keyval; + keybind->command = g_strdup(command); + + keys = g_slist_append(keys, keybind); + + /* save the modkey also in the modkey string */ + if (modkey) { + g_string_append_c(modkeys, modkey); + } +} + +static gboolean keybind_keypress_callback(WebKitWebView* webview, GdkEventKey* event) +{ + GSList* tmp; + GdkModifierType irrelevant; + guint keyval; + static GdkKeymap *keymap; + + keymap = gdk_keymap_get_default(); + + /* Get a mask of modifiers that shouldn't be considered for this event. + * E.g.: It shouldn't matter whether ';' is shifted or not. */ + gdk_keymap_translate_keyboard_state(keymap, event->hardware_keycode, + event->state, event->group, &keyval, NULL, NULL, &irrelevant); + + /* 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 = 0; + 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(); + + return TRUE; + } + } + /* check for keybinding */ + for (tmp = keys; tmp != NULL; tmp = tmp->next) { + struct _keybind_key* keybind = (struct _keybind_key*)tmp->data; + + if (gdk_keyval_to_lower(event->keyval) == keybind->keyval + && (event->state & keybind->modmask) == keybind->modmask + && keybind->modkey == vp.state.modkey + && keybind->command + ) { + GArray* a = g_array_new(TRUE, FALSE, sizeof(gchar*)); + const CommandInfo* c = command_parse_parts(keybind->command, a); + if (c) { + command_run_command(c, a, NULL); + } + g_array_free(a, TRUE); + + /* if key binding used, remove the modkey */ + vp.state.modkey = 0; + vp_update_statusbar(); + + return TRUE; + } + } + + return FALSE; +} diff --git a/src/keybind.h b/src/keybind.h new file mode 100644 index 0000000..3758512 --- /dev/null +++ b/src/keybind.h @@ -0,0 +1,27 @@ +#ifndef KEYBIND_H +#define KEYBIND_H + +#include + +/* the CLEAN_MOD_*_MASK defines have all the bits set that will be stripped from the modifier bit field */ +#define CLEAN_MOD_NUMLOCK_MASK (GDK_MOD2_MASK) +#define CLEAN_MOD_BUTTON_MASK (GDK_BUTTON1_MASK|GDK_BUTTON2_MASK|GDK_BUTTON3_MASK|GDK_BUTTON4_MASK|GDK_BUTTON5_MASK) + +/* 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)) + +struct _keybind_key { + int mode; /* mode maks for allowed browser modes */ + guint modkey; + guint modmask; /* modemask for the kayval */ + guint keyval; + gchar* command; /* command to run */ +}; + +void keybind_init(void); +void keybind_add(int mode, guint modkey, guint modmask, guint keyval, const gchar* command); + +#endif /* end of include guard: KEYBIND_H */ diff --git a/src/main.c b/src/main.c new file mode 100644 index 0000000..1f27c48 --- /dev/null +++ b/src/main.c @@ -0,0 +1,232 @@ +#include "config.h" +#include "main.h" +#include "command.h" +#include "callback.h" +#include "keybind.h" + +/* variables */ +VpCore vp; + +/* functions */ +static void vp_print_version(void); +static void vp_init(void); +static void vp_init_gui(void); +static void vp_setup_signals(void); + + +gboolean vp_load_uri(const Arg* arg) +{ + char* u; + const char* uri = arg->c; + + if (strcmp(uri, "") == 0) { + return FALSE; + } + u = g_strrstr(uri, "://") ? g_strdup(uri) : g_strdup_printf("http://%s", uri); + + /* Load a web page into the browser instance */ + webkit_web_view_load_uri(vp.gui.webview, u); + g_free(u); + + /* change state to normal mode */ + vp.state.mode = VP_MODE_NORMAL; + vp_update_statusbar(); + + return TRUE; +} + +gboolean vp_navigate(const Arg *arg) +{ + if (arg->i <= NAVIG_FORWARD) { + /* TODO allow to set a count for the navigation */ + webkit_web_view_go_back_or_forward( + vp.gui.webview, (arg->i == NAVIG_BACK ? -1 : 1) + ); + } else if (arg->i == NAVIG_RELOAD) { + webkit_web_view_reload(vp.gui.webview); + } else if (arg->i == NAVIG_RELOAD_FORCE) { + webkit_web_view_reload_bypass_cache(vp.gui.webview); + } else { + webkit_web_view_stop_loading(vp.gui.webview); + } + + return TRUE; +} + +void vp_close_browser() +{ + if (vp.behave.commands) { + g_hash_table_destroy(vp.behave.commands); + vp.behave.commands = NULL; + } + gtk_main_quit(); +} + +void vp_update_urlbar(const gchar* uri) +{ + gchar* markup; + + markup = g_markup_printf_escaped("%s", STATUS_BAR_FONT, uri); + gtk_label_set_markup(GTK_LABEL(vp.gui.statusbar.left), markup); + g_free(markup); +} + +void vp_update_statusbar(void) +{ + GString* status = g_string_new(""); + gchar* markup; + + /* TODO show modekeys count */ + /* at the moment we have only one modkey available */ + /* http://current_uri.tld 34% */ + g_string_append_printf(status, "%.0d", vp.state.count); + if (vp.state.modkey) { + g_string_append_c(status, vp.state.modkey); + } + g_string_append_printf(status, " %.0d%%", 46); + markup = g_markup_printf_escaped("%s", STATUS_BAR_FONT, status->str); + gtk_label_set_markup(GTK_LABEL(vp.gui.statusbar.right), markup); + g_free(markup); +} + +static void vp_print_version(void) +{ + fprintf(stderr, "%s/%s (build %s %s)\n", VERSION, PROJECT, __DATE__, __TIME__); +} + +static void vp_init(void) +{ + /* initialize the gui elements and event callbacks */ + vp_init_gui(); + /* initialize the commands hash map */ + command_init(); + /* initialize the keybindings */ + keybind_init(); + + /*command_parse_line("quit", NULL);*/ + keybind_add(VP_MODE_NORMAL, GDK_g, 0, GDK_f, "source"); + keybind_add(VP_MODE_NORMAL, 0, 0, GDK_d, "quit"); +} + +static void vp_init_gui(void) +{ + Gui* gui = &vp.gui; + GdkColor bg, fg; + + GdkGeometry hints = {10, 10}; + gui->window = gtk_window_new(GTK_WINDOW_TOPLEVEL); + gtk_window_set_wmclass(GTK_WINDOW(gui->window), PROJECT, PROJECT); + gtk_window_set_default_size(GTK_WINDOW(gui->window), 640, 480); + gtk_window_set_title(GTK_WINDOW(gui->window), PROJECT); + gtk_window_set_geometry_hints(GTK_WINDOW(gui->window), NULL, &hints, GDK_HINT_MIN_SIZE); + + /* Create a browser instance */ + gui->webview = WEBKIT_WEB_VIEW(webkit_web_view_new()); + + /* Create a scrollable area */ + gui->viewport = gtk_scrolled_window_new(NULL, NULL); + gtk_scrolled_window_set_policy( + GTK_SCROLLED_WINDOW(gui->viewport), + GTK_POLICY_NEVER, GTK_POLICY_NEVER + ); + + gui->box = GTK_BOX(gtk_vbox_new(FALSE, 0)); + + /* Prepare the imputbox */ + gui->inputbox = gtk_entry_new(); + 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); + + /* Prepare the statusbar */ + gui->statusbar.box = GTK_BOX(gtk_hbox_new(FALSE, 0)); + gui->statusbar.left = gtk_label_new(NULL); + gui->statusbar.right = gtk_label_new(NULL); + + /* Prepare the event box */ + gui->eventbox = gtk_event_box_new(); + gdk_color_parse(STATUS_BG_COLOR, &bg); + gdk_color_parse(STATUS_FG_COLOR, &fg); + gtk_widget_modify_bg(gui->eventbox, GTK_STATE_NORMAL, &bg); + gtk_widget_modify_fg(gui->eventbox, GTK_STATE_NORMAL, &fg); + + vp_setup_signals(); + + /* Put all part together */ + gtk_container_add(GTK_CONTAINER(gui->viewport), GTK_WIDGET(gui->webview)); + gtk_container_add(GTK_CONTAINER(gui->eventbox), GTK_WIDGET(gui->statusbar.box)); + gtk_container_add(GTK_CONTAINER(gui->window), GTK_WIDGET(gui->box)); + gtk_misc_set_alignment(GTK_MISC(gui->statusbar.left), 0.0, 0.0); + gtk_misc_set_alignment(GTK_MISC(gui->statusbar.right), 1.0, 0.0); + gtk_box_pack_start(gui->statusbar.box, gui->statusbar.left, TRUE, TRUE, 2); + gtk_box_pack_start(gui->statusbar.box, gui->statusbar.right, FALSE, FALSE, 2); + gtk_widget_modify_bg(GTK_WIDGET(gui->statusbar.left), GTK_STATE_NORMAL, &bg); + gtk_widget_modify_fg(GTK_WIDGET(gui->statusbar.left), GTK_STATE_NORMAL, &fg); + gtk_widget_modify_bg(GTK_WIDGET(gui->statusbar.right), GTK_STATE_NORMAL, &bg); + gtk_widget_modify_fg(GTK_WIDGET(gui->statusbar.right), GTK_STATE_NORMAL, &fg); + + gtk_box_pack_start(gui->box, gui->viewport, TRUE, TRUE, 0); + gtk_box_pack_start(gui->box, gui->eventbox, FALSE, FALSE, 0); + gtk_entry_set_has_frame(GTK_ENTRY(gui->inputbox), FALSE); + gtk_box_pack_end(gui->box, gui->inputbox, FALSE, FALSE, 0); + + /* Make sure that when the browser area becomes visible, it will get mouse + * and keyboard events */ + gtk_widget_grab_focus(GTK_WIDGET(gui->webview)); + + /* Make sure the main window and all its contents are visible */ + gtk_widget_show_all(gui->window); +} + +static void vp_setup_signals(void) +{ + Gui* gui = &vp.gui; + WebKitWebFrame *frame = webkit_web_view_get_main_frame(gui->webview); + + /* Set up callbacks so that if either the main window or the browser + * instance is closed, the program will exit */ + g_signal_connect(gui->window, "destroy", G_CALLBACK(destroy_window_cb), NULL); + g_signal_connect(G_OBJECT(frame), "scrollbars-policy-changed", G_CALLBACK(dummy_cb), NULL); + g_signal_connect(G_OBJECT(gui->webview), "notify::load-status", G_CALLBACK(webview_load_status_cb), NULL); +} + +int main(int argc, char* argv[]) +{ + static gboolean ver = false; + static GError* err; + static GOptionEntry opts[] = { + { "version", 'v', 0, G_OPTION_ARG_NONE, &ver, "print version", NULL }, + { NULL } + }; + /* Initialize GTK+ */ + if (!gtk_init_with_args(&argc, &argv, "[]", opts, NULL, &err)) { + g_printerr("can't init gtk: %s\n", err->message); + g_error_free(err); + + return EXIT_FAILURE; + } + + if (ver) { + vp_print_version(); + return EXIT_SUCCESS; + } + vp_init(); + + /* command line argument: URL */ + Arg arg; + if (argc > 1) { + arg.c = g_strdup(argv[argc - 1]); + } else { + arg.c = g_strdup(START_PAGE); + } + vp_load_uri(&arg); + g_free(arg.c); + + /* Run the main GTK+ event loop */ + gtk_main(); + + return EXIT_SUCCESS; +} diff --git a/src/main.h b/src/main.h new file mode 100644 index 0000000..67cc893 --- /dev/null +++ b/src/main.h @@ -0,0 +1,102 @@ +#ifndef MAIN_H +#define MAIN_H + +#include +#include +#include + +#define LENGTH(x) (sizeof x / sizeof x[0]) + +#ifdef DEBUG +#define PRINT_DEBUG(...) do { \ + fprintf(stderr, "\n\033[31;1mDEBUG:\033[0m %s:%d:%s()\t", __FILE__, __LINE__, __func__); \ + fprintf(stderr, __VA_ARGS__);\ + fprintf(stderr, "\n"); \ +} while(0); +#define TIMER_START GTimer *__timer; do {__timer = g_timer_new(); g_timer_start(__timer);} while(0) +#define TIMER_END do {gulong __debug_micro = 0; gdouble __debug_elapsed = g_timer_elapsed(__timer, &__debug_micro);\ + PRINT_DEBUG("\033[33mtimer:\033[0m elapsed: %f, micro: %lu", __debug_elapsed, __debug_micro);\ + g_timer_destroy(__timer); \ +} while(0) +#else +#define PRINT_DEBUG(message, ...) +#define TIMER_START +#define TIMER_END +#endif + +/* enums */ +typedef enum _vp_mode { + VP_MODE_NORMAL = (1 << 0), + VP_MODE_PATH_THROUGH = (1 << 1), + VP_MODE_INSERT = (1 << 2), +} Mode; + +enum { + NAVIG_BACK, + NAVIG_FORWARD, + NAVIG_RELOAD, + NAVIG_RELOAD_FORCE, + NAVIG_STOP_LOADING +}; + +/* structs */ +typedef struct { + gint i; + char* c; +} Arg; + +/* statusbar */ +typedef struct { + GtkBox* box; + GtkWidget* left; + GtkWidget* right; +} StatusBar; + +/* gui */ +typedef struct { + GtkWidget* window; + WebKitWebView* webview; + GtkWidget* viewport; + GtkBox* box; + GtkWidget* eventbox; + GtkWidget* inputbox; + StatusBar statusbar; +} Gui; + +/* state */ +typedef struct { + Mode mode; + gchar modkey; + int count; +} State; + +/* behaviour */ +typedef struct { + /* command list: (key)name -> (value)Command */ + GHashTable* commands; +} Behaviour; + +/* core struct */ +typedef struct { + Gui gui; + State state; + Behaviour behave; +#if 0 + Network net; + Ssl ssl; + Communication comm; + Info info; +#endif +} VpCore; + +/* main object */ +extern VpCore vp; + +/* functions */ +void vp_update_statusbar(void); +void vp_update_urlbar(const gchar* uri); +gboolean vp_load_uri(const Arg* arg); +gboolean vp_navigate(const Arg* arg); +void vp_close_browser(); + +#endif /* end of include guard: MAIN_H */ -- 2.20.1