From 1278a9e9dd820547f2d672dbff439d38fff989e5 Mon Sep 17 00:00:00 2001
From: neldoreth <mail@pwmt.org>
Date: Sat, 26 Dec 2009 14:30:50 +0100
Subject: [PATCH] Updated interface from zjui project

The whole project files have been replaced by the first version
of zjui, a side project for the user interface. Additionally there
has been an update of the Makefile and the configuration.

Mentionable features:
  * Buffered commands
  * Statusbar
  * Advanced completion
  * Notification system
  * Modes and mode-depending shortcuts
---
 LICENSE      |   19 +-
 Makefile     |   83 +-
 config.def.h |   72 ++
 config.h     |  100 ---
 config.mk    |   25 +
 zathura.c    | 2249 ++++++++++++++++++--------------------------------
 6 files changed, 981 insertions(+), 1567 deletions(-)
 create mode 100644 config.def.h
 delete mode 100644 config.h
 create mode 100644 config.mk

diff --git a/LICENSE b/LICENSE
index 8f3c571..05b00df 100644
--- a/LICENSE
+++ b/LICENSE
@@ -1,4 +1,4 @@
-Copyright (c) 2009 ML, JY
+Copyright (c) 2009 ML, JY - pwmt.org
 
 This software is provided 'as-is', without any express or implied
 warranty. In no event will the authors be held liable for any damages
@@ -8,14 +8,13 @@ Permission is granted to anyone to use this software for any purpose,
 including commercial applications, and to alter it and redistribute it
 freely, subject to the following restrictions:
 
-    1. The origin of this software must not be misrepresented; you must not
-    claim that you wrote the original software. If you use this software
-    in a product, an acknowledgment in the product documentation would be
-    appreciated but is not required.
+   1. The origin of this software must not be misrepresented; you must not
+   claim that you wrote the original software. If you use this software
+   in a product, an acknowledgment in the product documentation would be
+   appreciated but is not required.
 
-    2. Altered source versions must be plainly marked as such, and must not be
-    misrepresented as being the original software.
-
-    3. This notice may not be removed or altered from any source
-    distribution.
+   2. Altered source versions must be plainly marked as such, and must not be
+   misrepresented as being the original software.
 
+   3. This notice may not be removed or altered from any source
+   distribution.
diff --git a/Makefile b/Makefile
index 2e1068d..7e39f32 100644
--- a/Makefile
+++ b/Makefile
@@ -1,28 +1,77 @@
-LIBS   = gtk+-2.0 poppler poppler-glib
-FLAGS  = `pkg-config --cflags --libs $(LIBS)`
-SOURCE = zathura.c
-TARGET = zathura
+# See LICENSE file for license and copyright information
+# zathura - user interface
 
-all: $(TARGET)
+include config.mk
 
-$(TARGET): zathura.c config.h
-	gcc $(FLAGS) -Wall -o $(TARGET) $(SOURCE) 
+PROJECT  = zathura
+SOURCE   = zathura.c
+OBJECTS  = ${SOURCE:.c=.o}
+DOBJECTS = ${SOURCE:.c=.do}
+
+all: options ${PROJECT}
+
+options:
+	@echo ${PROJECT} buld options:
+	@echo "CFLAGS  = ${CFLAGS}"
+	@echo "LDFLAGS = ${LDFLAGS}"
+	@echo "DFLAGS  = ${DFLAGS}"
+	@echo "CC      = ${CC}"
+
+%.o: %.c
+	@echo CC $<
+	@${CC} -c ${CFLAGS} -o $@ $<
+
+%.do: %.c
+	@echo CC $<
+	@${CC} -c ${CFLAGS} ${DFLAGS} -o $@ $<
+
+${OBJECTS}:  config.h config.mk
+${DOBJECTS}: config.h config.mk
+
+config.h:
+	@cp config.def.h $@
+
+${PROJECT}: ${OBJECTS}
+	@echo CC -o $@
+	@${CC} -o $@ ${OBJECTS} ${LDFLAGS}
 
 clean:
-	rm -f $(TARGET)
+	@rm -rf ${PROJECT} ${OBJECTS} ${PROJECT}-${VERSION}.tar.gz \
+		${DOBJECTS} ${PROJECT}-debug
 
-debug: 
-	gcc $(FLAGS) -Wall -o $(TARGET) $(SOURCE) -g
+${PROJECT}-debug: ${DOBJECTS}
+	@echo CC -o ${PROJECT}-debug
+	@${CC} -o ${PROJECT}-debug ${DOBJECTS} ${LDFLAGS}
+
+debug: ${PROJECT}-debug
 
 valgrind: debug
-	valgrind --tool=memcheck --leak-check=yes --show-reachable=yes ./${TARGET}
+	valgrind --tool=memcheck --leak-check=yes --show-reachable=yes \
+		./${PROJECT}-debug
+
+gdb: debug
+	cgdb ${PROJECT}-debug
+
+dist: clean
+	@mkdir -p ${PROJECT}-${VERSION}
+	@cp -R LICENSE Makefile config.mk config.def.h README \
+			${PROJECT}.1 ${SOURCE} ${PROJECT}-${VERSION}
+	@tar -cf ${PROJECT}-${VERSION}.tar ${PROJECT}-${VERSION}
+	@gzip ${PROJECT}-${VERSION}.tar
+	@rm -rf ${PROJECT}-${VERSION}
 
 install: all
-	@echo installing executeable to /usr/bin
-	@mkdir -p /usr/bin
-	@cp -f ${TARGET} /usr/bin
-	@chmod 755 /usr/bin/${TARGET}
+	@echo installing executeable file
+	@mkdir -p ${PREFIX}/bin
+	@cp -f ${PROJECT} ${PREFIX}/bin
+	@chmod 755 ${PROJECT} ${PREFIX}/bin/${PROJECT}
+	@echo installing manual page
+	@mkdir -p ${MANPREFIX}/man1
+	@sed "s/VERSION/${VERSION}/g" < ${PROJECT}.1 > ${MANPREFIX}/man1/${PROJECT}.1
+	@chmod 644 ${MANPREFIX}/man1/${PROJECT}.1
 
 uninstall:
-	@echo removing executeable from /usr/bin
-	@rm -f /usr/bin/${TARGET}
+	@echo removing executeable file
+	@rm -f ${MANPREFIX}/bin/${PROJECT}
+	@echo removing manual page
+	@rm -f ${MANPREFIX}/man1/${PROJECT}.1
diff --git a/config.def.h b/config.def.h
new file mode 100644
index 0000000..86e6a62
--- /dev/null
+++ b/config.def.h
@@ -0,0 +1,72 @@
+/* settings */
+static const int DEFAULT_WIDTH  = 800;
+static const int DEFAULT_HEIGHT = 600;
+
+/* completion */
+static const char FORMAT_COMMAND[]     = "<b>%s</b>";
+static const char FORMAT_DESCRIPTION[] = "<i>%s</i>";
+
+/* look */
+static const char font[]                   = "monospace normal 9";
+static const char default_bgcolor[]        = "#000000";
+static const char default_fgcolor[]        = "#DDDDDD";
+static const char inputbar_bgcolor[]       = "#141414";
+static const char inputbar_fgcolor[]       = "#9FBC00";
+static const char statusbar_bgcolor[]      = "#000000";
+static const char statusbar_fgcolor[]      = "#FFFFFF";
+static const char completion_fgcolor[]     = "#DDDDDD";
+static const char completion_bgcolor[]     = "#232323";
+static const char completion_g_fgcolor[]   = "#DEDEDE";
+static const char completion_g_bgcolor[]   = "#FF00FF";
+static const char completion_hl_fgcolor[]  = "#232323";
+static const char completion_hl_bgcolor[]  = "#9FBC00";
+static const char notification_e_bgcolor[] = "#FF1212";
+static const char notification_e_fgcolor[] = "#FFFFFF";
+static const char notification_w_bgcolor[] = "#FFF712";
+static const char notification_w_fgcolor[] = "#000000";
+
+/* shortcuts */
+Shortcut shortcuts[] = {
+  /* mask,             key,               function,             mode,     argument */
+  {0,                  GDK_i,             sc_change_mode,       NORMAL,   { INSERT } },
+  {0,                  GDK_v,             sc_change_mode,       NORMAL,   { VISUAL } },
+  {GDK_CONTROL_MASK,   GDK_q,             sc_quit,              -1,       {0} },
+  {GDK_SHIFT_MASK,     GDK_slash,         sc_focus_inputbar,    -1,       { .data = "/" } },
+  {GDK_SHIFT_MASK,     GDK_question,      sc_focus_inputbar,    -1,       { .data = "?" } },
+  {0,                  GDK_colon,         sc_focus_inputbar,    -1,       { .data = ":" } },
+  {0,                  GDK_Escape,        sc_abort,             -1,       {0} },
+};
+
+/* inputbar shortcuts */
+InputbarShortcut inputbar_shortcuts[] = {
+  /* mask,             key,               function,                  argument */
+  {0,                  GDK_Escape,        isc_abort,                 {0} },
+  {0,                  GDK_Up,            isc_command_history,       {0} },
+  {0,                  GDK_Down,          isc_command_history,       {0} },
+  {0,                  GDK_Tab,           isc_completion,            { NEXT } },
+  {GDK_CONTROL_MASK,   GDK_Tab,           isc_completion,            { NEXT_GROUP } },
+  {0,                  GDK_ISO_Left_Tab,  isc_completion,            { PREVIOUS } },
+  {GDK_CONTROL_MASK,   GDK_ISO_Left_Tab,  isc_completion,            { PREVIOUS_GROUP } },
+  {GDK_CONTROL_MASK,   GDK_w,             isc_string_manipulation,   { DELETE_LAST_WORD } },
+};
+
+/* commands */
+Command commands[] = {
+  /* command,   abbreviation,   function,   completion,   description  */
+  {"open",      "o",            cmd_quit,   cc_open,      "Open a file" },
+  {"quit",      "q",            cmd_quit,   0,            "Quit zjui" },
+};
+
+/* buffer commands */
+BufferCommand buffer_commands[] = {
+  /* regex,        function,      argument */
+  {"^gg$",         bcmd_goto,     { TOP } },
+  {"^[0-9]+G$",    bcmd_goto,     {0} },
+};
+
+/* special commands */
+SpecialCommand special_commands[] = {
+  /* identifier,   function,      a,   argument */
+  {'/',            scmd_search,   1,   { DOWN } },
+  {'?',            scmd_search,   1,   { UP } },
+};
diff --git a/config.h b/config.h
deleted file mode 100644
index 8cdd785..0000000
--- a/config.h
+++ /dev/null
@@ -1,100 +0,0 @@
-/* settings */
-static const float  ZOOM_STEP         = 0.1;
-static const float  SCROLL_STEP       = 40;
-static const float  HL_TRANSPARENCY   = 0.4;
-static const int    SHOW_NOTIFICATION = 5;
-static const int    DEFAULT_WIDTH     = 800;
-static const int    DEFAULT_HEIGHT    = 600;
-static const int    MIN_INDEX_WIDTH   = 200;
-static const char   BROWSER[]         = "firefox %s";
-static const char  *PRINTER[]         = { "PRINTER_1",
-                                          "PRINTER_2",
-                                          "PRINTER_3"
-                                        };
-
-/* look */
-static const char font[]                  = "monospace normal 9";
-static const char default_bgcolor[]       = "#000000";
-static const char default_fgcolor[]       = "#DDDDDD";
-
-static const char notification_fgcolor[]         = "#0F0F0F";
-static const char notification_bgcolor[]         = "#F9F9F9";
-static const char notification_warning_fgcolor[] = "DDDDDDC";
-static const char notification_warning_bgcolor[] = "#D0C54D";
-static const char notification_error_fgcolor[]   = "#FFFFFF";
-static const char notification_error_bgcolor[]   = "#BC2800";
-
-static const char inputbar_bgcolor[]      = "#141414";
-static const char inputbar_fgcolor[]      = "#9FBC00";
-
-static const char completion_fgcolor[]    = "#DDDDDD";
-static const char completion_bgcolor[]    = "#232323";
-static const char completion_hl_fgcolor[] = "#232323";
-static const char completion_hl_bgcolor[] = "#9FBC00";
-
-static const char search_highlight[] = "#9FBC00";
-
-/* additional settings */
-#define SHOW_SCROLLBARS    0
-#define INCREMENTAL_SEARCH 0
-
-/* shortcuts */
-Shortcut shortcuts[] = {
-  // mask,               key,           function,            argument
-  {GDK_CONTROL_MASK,     GDK_f,         sc_navigate,         { NEXT } },
-  {GDK_CONTROL_MASK,     GDK_b,         sc_navigate,         { PREVIOUS } },
-  {GDK_CONTROL_MASK,     GDK_plus,      sc_zoom,             { ZOOM_IN } },
-  {GDK_CONTROL_MASK,     GDK_minus,     sc_zoom,             { ZOOM_OUT } },
-  {GDK_CONTROL_MASK,     GDK_0,         sc_zoom,             { ZOOM_ORIGINAL } },
-  {GDK_CONTROL_MASK,     GDK_r,         sc_rotate,           { RIGHT } },
-  {GDK_CONTROL_MASK,     GDK_e,         sc_rotate,           { LEFT } },
-  {GDK_CONTROL_MASK,     GDK_p,         sc_focus_inputbar,   { .data = ":print all" } },
-  {GDK_CONTROL_MASK,     GDK_q,         sc_quit,             {0} },
-  {GDK_CONTROL_MASK,     GDK_i,         sc_toggle_index,     {0} },
-  {GDK_CONTROL_MASK,     GDK_m,         sc_toggle_inputbar,  {0} },
-  {0,                    GDK_n,         sc_search,           { FORWARD } },
-  {0,                    GDK_N,         sc_search,           { BACKWARD } },
-  {0,                    GDK_h,         sc_scroll,           { LEFT } },
-  {0,                    GDK_j,         sc_scroll,           { UP } },
-  {0,                    GDK_k,         sc_scroll,           { DOWN } },
-  {0,                    GDK_l,         sc_scroll,           { RIGHT } },
-  {0,                    GDK_Page_Up,   sc_scroll,           { TOP } },
-  {0,                    GDK_Page_Down, sc_scroll,           { BOTTOM } },
-  {0,                    GDK_i,         sc_adjust_window,    { ADJUST_BESTFIT } },
-  {0,                    GDK_u,         sc_adjust_window,    { ADJUST_WIDTH } },
-  {0,                    GDK_colon,     sc_focus_inputbar,   { .data = ":" } },
-  {0,                    GDK_o,         sc_focus_inputbar,   { .data = ":open " } },
-  {0,                    GDK_r,         sc_focus_inputbar,   { .data = ":rotate " } },
-  {0,                    GDK_z,         sc_focus_inputbar,   { .data = ":zoom " } },
-  {0,                    GDK_g,         sc_focus_inputbar,   { .data = ":goto " } },
-  {0,                    GDK_slash,     sc_focus_inputbar,   { .data = "/" } },
-  {0,                    GDK_Up,        sc_focus_inputbar,   {0} },
-  {0,                    GDK_Down,      sc_focus_inputbar,   {0} },
-};
-
-/* commands */
-Command commands[] = {
-  // command,         function
-  {"export",          cmd_export},
-  {"e",               cmd_export},
-  {"form",            cmd_form},
-  {"f",               cmd_form},
-  {"goto",            cmd_goto},
-  {"g",               cmd_goto},
-  {"info",            cmd_info},
-  {"i",               cmd_info},
-  {"links",           cmd_links},
-  {"l",               cmd_links},
-  {"open",            cmd_open},
-  {"o",               cmd_open},
-  {"print",           cmd_print},
-  {"p",               cmd_print},
-  {"rotate",          cmd_rotate},
-  {"r",               cmd_rotate},
-  {"save",            cmd_save},
-  {"s",               cmd_save},
-  {"quit",            cmd_quit},
-  {"q",               cmd_quit},
-  {"zoom",            cmd_zoom},
-  {"z",               cmd_zoom},
-};
diff --git a/config.mk b/config.mk
new file mode 100644
index 0000000..c8d83b1
--- /dev/null
+++ b/config.mk
@@ -0,0 +1,25 @@
+# See LICENSE file for license and copyright information
+# zathura make config
+
+VERSION = 0.0.1
+
+# paths
+PREFIX = /usr
+MANPREFIX = ${PREFIX}/share/man
+
+# libs
+GTK_INC = $(shell pkg-config --cflags gtk+-2.0)
+GTK_LIB = $(shell pkg-config --libs gtk+-2.0)
+
+INCS = -I. -I/usr/include ${GTK_INC}
+LIBS = -L/usr/lib -lc ${GTK_LIB}
+
+# flags
+CFLAGS = -std=c99 -pedantic -Wall $(INCS)
+LDFLAGS = ${LIBS}
+
+# debug
+DFLAGS = -g
+
+# compiler
+CC = gcc
diff --git a/zathura.c b/zathura.c
index 17a1a35..0d87a0e 100644
--- a/zathura.c
+++ b/zathura.c
@@ -1,9 +1,8 @@
+/* See LICENSE file for license and copyright information */
+
+#include <regex.h>
 #include <stdlib.h>
 #include <string.h>
-#include <unistd.h>
-
-#include <poppler/glib/poppler.h>
-#include <cairo.h>
 
 #include <gtk/gtk.h>
 #include <gdk/gdkkeysyms.h>
@@ -12,56 +11,90 @@
 #define LENGTH(x) sizeof(x)/sizeof((x)[0])
 
 /* enums */
-enum { UP, DOWN, LEFT, RIGHT, ZOOM_IN, ZOOM_OUT, ZOOM_ORIGINAL, 
-       NEXT, PREVIOUS, HIDE, ERROR, WARNING, DEFAULT, TOP, BOTTOM, 
-       ADJUST_BESTFIT, ADJUST_WIDTH, FORWARD, BACKWARD };
+enum { NEXT, PREVIOUS, LEFT, RIGHT, UP, DOWN,
+       BOTTOM, TOP, HIDE, NORMAL, HIGHLIGHT,
+       INSERT, VISUAL, DELETE_LAST_WORD, DEFAULT,
+       ERROR, WARNING, NEXT_GROUP, PREVIOUS_GROUP };
 
+/* zathura */
 struct
 {
-  GtkWindow         *window;
-  GtkBox            *vbox;
-  GtkBox            *hbox;
-  GtkScrolledWindow *view;
-  GtkWidget         *drawing_area;
-  GtkBox            *notification;
-  GtkEntry          *inputbar;
-  GList             *history;
-  GtkWidget         *index;
+  struct
+  {
+    GtkWindow         *window;
+    GtkBox            *box;
+    GtkScrolledWindow *view;
+    GtkWidget         *statusbar;
+    GtkBox            *statusbar_entries;
+    GtkEntry          *inputbar;
+  } UI;
 
   struct
   {
-    GdkColor              default_fg;
-    GdkColor              default_bg;
-    GdkColor              inputbar_fg;
-    GdkColor              inputbar_bg;
-    GdkColor              notification_fg;
-    GdkColor              notification_bg;
-    GdkColor              notification_wn_fg;
-    GdkColor              notification_wn_bg;
-    GdkColor              notification_er_fg;
-    GdkColor              notification_er_bg;
-    GdkColor              completion_fg;
-    GdkColor              completion_bg;
-    GdkColor              completion_hl_fg;
-    GdkColor              completion_hl_bg;
-    GdkColor              search_highlight;
+    GdkColor default_fg;
+    GdkColor default_bg;
+    GdkColor inputbar_fg;
+    GdkColor inputbar_bg;
+    GdkColor statusbar_fg;
+    GdkColor statusbar_bg;
+    GdkColor completion_fg;
+    GdkColor completion_bg;
+    GdkColor completion_g_bg;
+    GdkColor completion_g_fg;
+    GdkColor completion_hl_fg;
+    GdkColor completion_hl_bg;
+    GdkColor notification_e_fg;
+    GdkColor notification_e_bg;
+    GdkColor notification_w_fg;
+    GdkColor notification_w_bg;
     PangoFontDescription *font;
-  } Settings;
+  } Style;
 
   struct
   {
-    PopplerDocument *document;
-    PopplerPage     *page;
-    char            *file;
-    cairo_surface_t *surface;
-    int              page_number;
-    int              number_of_pages;
-    double           scale;
-    int              rotate;
-  } PDF;
+    GString *buffer;
+    GList   *history;
+    int      mode;
+    GtkLabel *status_text;
+    GtkLabel *status_buffer;
+    GtkLabel *status_state;
+  } Global;
 
 } Zathura;
 
+/* typedefs */
+struct CElement
+{
+  char            *value;
+  char            *description;
+  struct CElement *next;
+};
+
+typedef struct CElement CompletionElement;
+
+struct CGroup
+{
+  char              *value;
+  CompletionElement *elements;
+  struct CGroup     *next;
+};
+
+typedef struct CGroup CompletionGroup;
+
+typedef struct
+{
+  CompletionGroup* groups;
+} Completion;
+
+typedef struct
+{
+  char*      command;
+  char*      description;
+  int        command_id;
+  gboolean   is_group;
+  GtkWidget* row;
+} CompletionRow;
+
 typedef struct
 {
   int   n;
@@ -73,1563 +106,899 @@ typedef struct
   int mask;
   int key;
   void (*function)(Argument*);
+  int mode;
   Argument argument;
 } Shortcut;
 
 typedef struct
 {
-  char *command;
+  int mask;
+  int key;
+  void (*function)(Argument*);
+  Argument argument;
+} InputbarShortcut;
+
+typedef struct
+{
+  char* command;
+  char* abbr;
   void (*function)(int, char**);
+  Completion* (*completion)(char*);
+  char* description;
 } Command;
 
+typedef struct
+{
+  char* regex;
+  void (*function)(char*, Argument*);
+  Argument argument;
+} BufferCommand;
+
+typedef struct
+{
+  char identifier;
+  void (*function)(char*, Argument*);
+  int always;
+  Argument argument;
+} SpecialCommand;
+
 /* function declarations */
-void init();
-void build_index(GtkTreeModel*, GtkTreeIter*, PopplerIndexIter*);
-void history(int);
-void update_title();
-void update_status();
-void set_page(int);
-void draw();
-void highlight_result(PopplerRectangle*);
-void open_link(char*);
-void save_images(int, char*);
-void save_attachments(char*);
-
-gboolean complete(Argument*);
-gboolean delete_widget(gpointer);
-
-GtkWidget* notify(int, char*);
-GtkWidget* update_notification(GtkWidget*, int, char*);
-
-PopplerRectangle* recalcRectangle(PopplerRectangle*);
+void init_zathura();
+void change_mode(int);
+void notify(int, char*);
+void update_status(char*, char*);
+void setCompletionRowColor(GtkBox*, int, int);
+GtkEventBox* createCompletionRow(GtkBox*, char*, char*, gboolean);
 
 /* shortcut declarations */
+void sc_abort(Argument*);
+void sc_change_mode(Argument*);
 void sc_focus_inputbar(Argument*);
-void sc_scroll(Argument*);
-void sc_navigate(Argument*);
-void sc_zoom(Argument*);
-void sc_adjust_window(Argument*);
-void sc_rotate(Argument*);
-void sc_search(Argument*);
-void sc_toggle_index(Argument*);
-void sc_toggle_inputbar(Argument*);
 void sc_quit(Argument*);
 
+/* inputbar shortcut declarations */
+void isc_abort(Argument*);
+void isc_command_history(Argument*);
+void isc_completion(Argument*);
+void isc_string_manipulation(Argument*);
+
 /* command declarations */
-void cmd_export(int, char**);
-void cmd_form(int, char**);
-void cmd_goto(int, char**);
-void cmd_info(int, char**);
-void cmd_links(int, char**);
-void cmd_open(int, char**);
-void cmd_print(int, char**);
-void cmd_rotate(int, char**);
-void cmd_save(int, char**);
 void cmd_quit(int, char**);
-void cmd_zoom(int, char**);
 
-/* callbacks declarations */
-void cb_draw(GtkWidget*, gpointer);
-void cb_destroy(GtkWidget*, gpointer);
-void cb_inputbar_activate(GtkEntry*, gpointer);
-void cb_inputbar_button_pressed(GtkWidget*, GdkEventButton*, gpointer);
-void cb_drawing_area_button_pressed(GtkWidget*, GdkEventButton*, gpointer);
-void cb_index_selection_changed(GtkTreeSelection*, GtkWidget*);
+/* completion commands */
+Completion* cc_open(char*);
 
-gboolean cb_label_open_link(GtkLabel*, gchar*, gpointer);
-gboolean cb_inputbar_key_pressed(GtkEntry*,  GdkEventKey*, gpointer);
-gboolean cb_inputbar_key_released(GtkEntry*, GdkEventKey*, gpointer);
-gboolean cb_view_key_pressed(GtkWidget*,     GdkEventKey*, gpointer);
+/* buffer command declarations */
+void bcmd_goto(char*, Argument*);
+
+/* special command delcarations */
+void scmd_search(char*, Argument*);
+
+/* callback declarations */
+gboolean cb_destroy(GtkWidget*, gpointer);
+gboolean cb_view_kb_pressed(GtkWidget*, GdkEventKey*, gpointer);
+gboolean cb_inputbar_kb_pressed(GtkWidget*, GdkEventKey*, gpointer);
+gboolean cb_inputbar_activate(GtkEntry*, gpointer);
 
 /* configuration */
 #include "config.h"
 
-/* function implementations */ 
+/* function implementation */
 void
-init()
+init_zathura()
 {
-  /* settings */
-  gdk_color_parse(default_fgcolor,              &(Zathura.Settings.default_fg));
-  gdk_color_parse(default_bgcolor,              &(Zathura.Settings.default_bg));
-  gdk_color_parse(inputbar_fgcolor,             &(Zathura.Settings.inputbar_fg));
-  gdk_color_parse(inputbar_bgcolor,             &(Zathura.Settings.inputbar_bg));
-  gdk_color_parse(notification_fgcolor,         &(Zathura.Settings.notification_fg));
-  gdk_color_parse(notification_bgcolor,         &(Zathura.Settings.notification_bg));
-  gdk_color_parse(notification_warning_fgcolor, &(Zathura.Settings.notification_wn_fg));
-  gdk_color_parse(notification_warning_bgcolor, &(Zathura.Settings.notification_wn_bg));
-  gdk_color_parse(notification_error_fgcolor,   &(Zathura.Settings.notification_er_fg));
-  gdk_color_parse(notification_error_bgcolor,   &(Zathura.Settings.notification_er_bg));
-  gdk_color_parse(completion_fgcolor,           &(Zathura.Settings.completion_fg));
-  gdk_color_parse(completion_bgcolor,           &(Zathura.Settings.completion_bg));
-  gdk_color_parse(completion_hl_fgcolor,        &(Zathura.Settings.completion_hl_fg));
-  gdk_color_parse(completion_hl_bgcolor,        &(Zathura.Settings.completion_hl_bg));
-  gdk_color_parse(search_highlight,             &(Zathura.Settings.search_highlight));
-  Zathura.Settings.font = pango_font_description_from_string(font);
+  /* look */
+  gdk_color_parse(default_fgcolor,        &(Zathura.Style.default_fg));
+  gdk_color_parse(default_bgcolor,        &(Zathura.Style.default_bg));
+  gdk_color_parse(inputbar_fgcolor,       &(Zathura.Style.inputbar_fg));
+  gdk_color_parse(inputbar_bgcolor,       &(Zathura.Style.inputbar_bg));
+  gdk_color_parse(statusbar_fgcolor,      &(Zathura.Style.statusbar_fg));
+  gdk_color_parse(statusbar_bgcolor,      &(Zathura.Style.statusbar_bg));
+  gdk_color_parse(completion_fgcolor,     &(Zathura.Style.completion_fg));
+  gdk_color_parse(completion_bgcolor,     &(Zathura.Style.completion_bg));
+  gdk_color_parse(completion_g_fgcolor,   &(Zathura.Style.completion_g_fg));
+  gdk_color_parse(completion_g_fgcolor,   &(Zathura.Style.completion_g_fg));
+  gdk_color_parse(completion_hl_fgcolor,  &(Zathura.Style.completion_hl_fg));
+  gdk_color_parse(completion_hl_bgcolor,  &(Zathura.Style.completion_hl_bg));
+  gdk_color_parse(notification_e_fgcolor, &(Zathura.Style.notification_e_fg));
+  gdk_color_parse(notification_e_bgcolor, &(Zathura.Style.notification_e_bg));
+  gdk_color_parse(notification_w_fgcolor, &(Zathura.Style.notification_w_fg));
+  gdk_color_parse(notification_w_bgcolor, &(Zathura.Style.notification_w_bg));
+  Zathura.Style.font = pango_font_description_from_string(font);
 
-  /* variables */
-  Zathura.window       = GTK_WINDOW(gtk_window_new(GTK_WINDOW_TOPLEVEL));
-  Zathura.vbox         = GTK_BOX(gtk_vbox_new(FALSE, 0));
-  Zathura.hbox         = GTK_BOX(gtk_hbox_new(FALSE, 0));
-  Zathura.view         = GTK_SCROLLED_WINDOW(gtk_scrolled_window_new(NULL, NULL));
-  Zathura.drawing_area = gtk_drawing_area_new();
-  Zathura.notification = GTK_BOX(gtk_vbox_new(FALSE, 0));
-  Zathura.inputbar     = GTK_ENTRY(gtk_entry_new());
-  Zathura.PDF.scale    = 1.0;
-  Zathura.PDF.rotate   = 0;
+  /* other */
+  Zathura.Global.mode = NORMAL;
+
+  /* UI */
+  Zathura.UI.window            = GTK_WINDOW(gtk_window_new(GTK_WINDOW_TOPLEVEL));
+  Zathura.UI.box               = GTK_BOX(gtk_vbox_new(FALSE, 0));
+  Zathura.UI.view              = GTK_SCROLLED_WINDOW(gtk_scrolled_window_new(NULL, NULL));
+  Zathura.UI.statusbar         = gtk_event_box_new();
+  Zathura.UI.statusbar_entries = GTK_BOX(gtk_hbox_new(FALSE, 0));
+  Zathura.UI.inputbar          = GTK_ENTRY(gtk_entry_new());
 
   /* window */
-  gtk_window_set_title(Zathura.window, "zathura");
-  gtk_window_set_default_size(Zathura.window, DEFAULT_WIDTH, DEFAULT_HEIGHT);
-  g_signal_connect(G_OBJECT(Zathura.window), "destroy", G_CALLBACK(cb_destroy), NULL);
+  gtk_window_set_title(Zathura.UI.window, "zathura");
+  GdkGeometry hints = { 1, 1 };
+  gtk_window_set_geometry_hints(Zathura.UI.window, NULL, &hints, GDK_HINT_MIN_SIZE);
+  gtk_window_set_default_size(Zathura.UI.window, DEFAULT_WIDTH, DEFAULT_HEIGHT);
+  g_signal_connect(G_OBJECT(Zathura.UI.window), "destroy", G_CALLBACK(cb_destroy), NULL);
+
+  /* box */
+  gtk_box_set_spacing(Zathura.UI.box, 0);
+  gtk_container_add(GTK_CONTAINER(Zathura.UI.window), GTK_WIDGET(Zathura.UI.box));
 
-  /* vbox */
-  gtk_box_set_spacing(Zathura.vbox, 0);
-  gtk_container_add(GTK_CONTAINER(Zathura.window), GTK_WIDGET(Zathura.vbox));
-  
-  /* hbox */
-  gtk_box_set_spacing(Zathura.hbox, 1);
-  gtk_container_add(GTK_CONTAINER(Zathura.hbox), GTK_WIDGET(Zathura.view));
-  
   /* view */
-  gtk_scrolled_window_add_with_viewport(GTK_SCROLLED_WINDOW(Zathura.view), 
-    Zathura.drawing_area);
-  gtk_viewport_set_shadow_type((GtkViewport*) gtk_bin_get_child(GTK_BIN(Zathura.view)), GTK_SHADOW_NONE);
-  g_signal_connect(G_OBJECT(Zathura.view), "key-press-event", G_CALLBACK(cb_view_key_pressed), NULL);
-  
-  #if SHOW_SCROLLBARS
-    gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(Zathura.view), GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC);
-  #else
-    gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(Zathura.view), GTK_POLICY_NEVER, GTK_POLICY_NEVER);
-  #endif
+  g_signal_connect(G_OBJECT(Zathura.UI.view), "key-press-event", G_CALLBACK(cb_view_kb_pressed), NULL);
 
-  /* drawing area */
-  g_signal_connect(G_OBJECT(Zathura.drawing_area), "expose-event",       G_CALLBACK(cb_draw), NULL);
-  g_signal_connect(G_OBJECT(Zathura.drawing_area), "button-press-event", G_CALLBACK(cb_drawing_area_button_pressed), NULL);
-  gtk_widget_set_events(Zathura.drawing_area, GDK_BUTTON_PRESS_MASK);
-  gtk_widget_modify_bg(GTK_WIDGET(Zathura.drawing_area), GTK_STATE_NORMAL, &(Zathura.Settings.default_bg));
+  /* statusbar */
+  gtk_widget_modify_bg(GTK_WIDGET(Zathura.UI.statusbar), GTK_STATE_NORMAL, &(Zathura.Style.statusbar_bg));
+
+  Zathura.Global.status_text   = GTK_LABEL(gtk_label_new(NULL));
+  Zathura.Global.status_state  = GTK_LABEL(gtk_label_new(NULL));
+  Zathura.Global.status_buffer = GTK_LABEL(gtk_label_new(NULL));
+
+  gtk_widget_modify_fg(GTK_WIDGET(Zathura.Global.status_text),  GTK_STATE_NORMAL, &(Zathura.Style.statusbar_fg));
+  gtk_widget_modify_fg(GTK_WIDGET(Zathura.Global.status_state), GTK_STATE_NORMAL, &(Zathura.Style.statusbar_fg));
+  gtk_widget_modify_fg(GTK_WIDGET(Zathura.Global.status_buffer), GTK_STATE_NORMAL, &(Zathura.Style.statusbar_fg));
+
+  gtk_widget_modify_font(GTK_WIDGET(Zathura.Global.status_text),  Zathura.Style.font);
+  gtk_widget_modify_font(GTK_WIDGET(Zathura.Global.status_state), Zathura.Style.font);
+  gtk_widget_modify_font(GTK_WIDGET(Zathura.Global.status_buffer), Zathura.Style.font);
+
+  gtk_misc_set_alignment(GTK_MISC(Zathura.Global.status_text),  0.0, 0.0);
+  gtk_misc_set_alignment(GTK_MISC(Zathura.Global.status_state), 1.0, 0.0);
+  gtk_misc_set_alignment(GTK_MISC(Zathura.Global.status_buffer), 1.0, 0.0);
+
+  gtk_misc_set_padding(GTK_MISC(Zathura.Global.status_text),  2.0, 4.0);
+  gtk_misc_set_padding(GTK_MISC(Zathura.Global.status_state), 2.0, 4.0);
+  gtk_misc_set_padding(GTK_MISC(Zathura.Global.status_buffer), 2.0, 4.0);
+
+  gtk_label_set_use_markup(Zathura.Global.status_text,  TRUE);
+  gtk_label_set_use_markup(Zathura.Global.status_state, TRUE);
+  gtk_label_set_use_markup(Zathura.Global.status_buffer, TRUE);
+
+  gtk_box_pack_start(Zathura.UI.statusbar_entries, GTK_WIDGET(Zathura.Global.status_text),  TRUE,  TRUE,  2);
+  gtk_box_pack_start(Zathura.UI.statusbar_entries, GTK_WIDGET(Zathura.Global.status_buffer), FALSE, FALSE, 2);
+  gtk_box_pack_start(Zathura.UI.statusbar_entries, GTK_WIDGET(Zathura.Global.status_state), FALSE, FALSE, 2);
+
+  gtk_container_add(GTK_CONTAINER(Zathura.UI.statusbar), GTK_WIDGET(Zathura.UI.statusbar_entries));
 
   /* inputbar */
-  gtk_entry_set_inner_border(Zathura.inputbar, NULL);
-  gtk_entry_set_has_frame(Zathura.inputbar, FALSE);
-  gtk_entry_set_editable(Zathura.inputbar,TRUE);
-  g_signal_connect(G_OBJECT(Zathura.inputbar), "activate",           G_CALLBACK(cb_inputbar_activate),       NULL);
-  g_signal_connect(G_OBJECT(Zathura.inputbar), "button-press-event", G_CALLBACK(cb_inputbar_button_pressed), NULL);
-  g_signal_connect(G_OBJECT(Zathura.inputbar), "key-press-event",    G_CALLBACK(cb_inputbar_key_pressed),    NULL);
-  g_signal_connect(G_OBJECT(Zathura.inputbar), "key-release-event",  G_CALLBACK(cb_inputbar_key_released),   NULL);
+  gtk_entry_set_inner_border(Zathura.UI.inputbar, NULL);
+  gtk_entry_set_has_frame(   Zathura.UI.inputbar, FALSE);
+  gtk_editable_set_editable( GTK_EDITABLE(Zathura.UI.inputbar), TRUE);
+
+  gtk_widget_modify_base(GTK_WIDGET(Zathura.UI.inputbar), GTK_STATE_NORMAL, &(Zathura.Style.inputbar_bg));
+  gtk_widget_modify_text(GTK_WIDGET(Zathura.UI.inputbar), GTK_STATE_NORMAL, &(Zathura.Style.inputbar_fg));
+  gtk_widget_modify_font(GTK_WIDGET(Zathura.UI.inputbar),                     Zathura.Style.font);
+
+  g_signal_connect(G_OBJECT(Zathura.UI.inputbar), "key-press-event", G_CALLBACK(cb_inputbar_kb_pressed), NULL);
+  g_signal_connect(G_OBJECT(Zathura.UI.inputbar), "activate",        G_CALLBACK(cb_inputbar_activate),   NULL);
 
   /* packing */
-  gtk_box_pack_start(Zathura.vbox, GTK_WIDGET(Zathura.hbox),         TRUE,  TRUE,  0);
-  gtk_box_pack_start(Zathura.vbox, GTK_WIDGET(Zathura.notification), FALSE, FALSE, 0);
-  gtk_box_pack_end(Zathura.vbox,   GTK_WIDGET(Zathura.inputbar),     FALSE, FALSE, 0);
-
-  /* visuals */
-  gtk_widget_modify_base(GTK_WIDGET(Zathura.inputbar), GTK_STATE_NORMAL, &(Zathura.Settings.inputbar_bg));
-  gtk_widget_modify_text(GTK_WIDGET(Zathura.inputbar), GTK_STATE_NORMAL, &(Zathura.Settings.inputbar_fg));
-  gtk_widget_modify_font(GTK_WIDGET(Zathura.inputbar), Zathura.Settings.font);
-}
-
-void build_index(GtkTreeModel* model, GtkTreeIter* parent, PopplerIndexIter* index_iter)
-{
-  do
-  {
-    GtkTreeIter       tree_iter;
-    PopplerIndexIter *child;
-    PopplerAction    *action;
-    gboolean          expand;
-    gchar            *markup;
-
-    action = poppler_index_iter_get_action(index_iter);
-    expand = poppler_index_iter_is_open(index_iter);
-
-    if(!action)
-      continue;
-
-    markup = g_markup_escape_text(action->any.title, -1);
-    
-    gtk_tree_store_append(GTK_TREE_STORE(model), &tree_iter, parent);
-    gtk_tree_store_set(GTK_TREE_STORE(model), &tree_iter, 0, markup,
-      1, action, -1);
-    g_object_weak_ref(G_OBJECT(model), (GWeakNotify) poppler_action_free, action);
-    g_free(markup);
-
-    child = poppler_index_iter_get_child(index_iter);
-    if(child)
-      build_index(model, &tree_iter, child);
-    poppler_index_iter_free(child);
-  }
-  while(poppler_index_iter_next(index_iter));
+  gtk_box_pack_start(Zathura.UI.box, GTK_WIDGET(Zathura.UI.view),      TRUE,  TRUE,  0);
+  gtk_box_pack_start(Zathura.UI.box, GTK_WIDGET(Zathura.UI.statusbar), FALSE, FALSE, 0);
+  gtk_box_pack_end(  Zathura.UI.box, GTK_WIDGET(Zathura.UI.inputbar),  FALSE, FALSE, 0);
 }
 
 void
-history(int direction)
+change_mode(int mode)
 {
-  static int current = 0;
-  int length = g_list_length(Zathura.history);
+  char* mode_text;
 
-  if(length > 0)
+  switch(mode)
   {
-    if(direction == NEXT)
-      current = (length + current + 1) % length;
+    case INSERT:
+      mode_text = "-- INSERT --";
+      gtk_editable_set_editable( GTK_EDITABLE(Zathura.UI.inputbar), FALSE);
+      break;
+    case VISUAL:
+      mode_text = "-- VISUAL --";
+      gtk_editable_set_editable( GTK_EDITABLE(Zathura.UI.inputbar), FALSE);
+      break;
+    default:
+      mode_text = "";
+      mode      = NORMAL;
+      gtk_editable_set_editable( GTK_EDITABLE(Zathura.UI.inputbar), TRUE);
+      break;
+  }
+
+  Zathura.Global.mode = mode;
+  notify(DEFAULT, mode_text);
+}
+
+void notify(int level, char* message)
+{
+  switch(level)
+  {
+    case ERROR:
+      gtk_widget_modify_base(GTK_WIDGET(Zathura.UI.inputbar), GTK_STATE_NORMAL, &(Zathura.Style.notification_e_bg));
+      gtk_widget_modify_text(GTK_WIDGET(Zathura.UI.inputbar), GTK_STATE_NORMAL, &(Zathura.Style.notification_e_fg));
+      break;
+    case WARNING:
+      gtk_widget_modify_base(GTK_WIDGET(Zathura.UI.inputbar), GTK_STATE_NORMAL, &(Zathura.Style.notification_w_bg));
+      gtk_widget_modify_text(GTK_WIDGET(Zathura.UI.inputbar), GTK_STATE_NORMAL, &(Zathura.Style.notification_w_fg));
+      break;
+    default:
+      gtk_widget_modify_base(GTK_WIDGET(Zathura.UI.inputbar), GTK_STATE_NORMAL, &(Zathura.Style.inputbar_bg));
+      gtk_widget_modify_text(GTK_WIDGET(Zathura.UI.inputbar), GTK_STATE_NORMAL, &(Zathura.Style.inputbar_fg));
+      break;
+  }
+ 
+  if(message)
+    gtk_entry_set_text(Zathura.UI.inputbar, message);
+}
+
+void
+update_status(char* text, char* state)
+{
+  /* update text */
+  if(text)
+    gtk_label_set_markup((GtkLabel*) Zathura.Global.status_text, text);
+
+  /* update state */
+  if(state)
+    gtk_label_set_markup((GtkLabel*) Zathura.Global.status_state, state);
+}
+
+GtkEventBox*
+createCompletionRow(GtkBox* results, char* command, char* description, gboolean group)
+{
+  GtkBox      *col = GTK_BOX(gtk_hbox_new(FALSE, 0));
+  GtkEventBox *row = GTK_EVENT_BOX(gtk_event_box_new());
+
+  GtkLabel *show_command     = GTK_LABEL(gtk_label_new(NULL));
+  GtkLabel *show_description = GTK_LABEL(gtk_label_new(NULL));
+
+  gtk_misc_set_alignment(GTK_MISC(show_command),     0.0, 0.0);
+  gtk_misc_set_alignment(GTK_MISC(show_description), 0.0, 0.0);
+
+  if(group)
+  {
+    gtk_misc_set_padding(GTK_MISC(show_command),     2.0, 4.0);
+    gtk_misc_set_padding(GTK_MISC(show_description), 2.0, 4.0);
+  }
+  else
+  {
+    gtk_misc_set_padding(GTK_MISC(show_command),     1.0, 1.0);
+    gtk_misc_set_padding(GTK_MISC(show_description), 1.0, 1.0);
+  }
+
+  gtk_label_set_use_markup(show_command,     TRUE),
+  gtk_label_set_use_markup(show_description, TRUE),
+
+  gtk_label_set_markup(show_command,     g_markup_printf_escaped(FORMAT_COMMAND,     command ? command : ""));
+  gtk_label_set_markup(show_description, g_markup_printf_escaped(FORMAT_DESCRIPTION, description ? description : ""));
+
+  if(group)
+  {
+    gtk_widget_modify_fg(GTK_WIDGET(show_command),     GTK_STATE_NORMAL, &(Zathura.Style.completion_g_fg));
+    gtk_widget_modify_fg(GTK_WIDGET(show_description), GTK_STATE_NORMAL, &(Zathura.Style.completion_g_fg));
+    gtk_widget_modify_bg(GTK_WIDGET(row),              GTK_STATE_NORMAL, &(Zathura.Style.completion_g_bg));
+  }
+  else
+  {
+    gtk_widget_modify_fg(GTK_WIDGET(show_command),     GTK_STATE_NORMAL, &(Zathura.Style.completion_fg));
+    gtk_widget_modify_fg(GTK_WIDGET(show_description), GTK_STATE_NORMAL, &(Zathura.Style.completion_fg));
+    gtk_widget_modify_bg(GTK_WIDGET(row),              GTK_STATE_NORMAL, &(Zathura.Style.completion_bg));
+  }
+
+  gtk_widget_modify_font(GTK_WIDGET(show_command),     Zathura.Style.font);
+  gtk_widget_modify_font(GTK_WIDGET(show_description), Zathura.Style.font);
+
+  gtk_box_pack_start(GTK_BOX(col), GTK_WIDGET(show_command),     TRUE,  TRUE,  2);
+  gtk_box_pack_start(GTK_BOX(col), GTK_WIDGET(show_description), FALSE, FALSE, 2);
+
+  gtk_container_add(GTK_CONTAINER(row), GTK_WIDGET(col));
+
+  gtk_box_pack_start(results, GTK_WIDGET(row), FALSE, FALSE, 0);
+
+  return row;
+}
+
+void
+setCompletionRowColor(GtkBox* results, int mode, int id)
+{
+  GtkEventBox *row   = (GtkEventBox*) g_list_nth_data(gtk_container_get_children(GTK_CONTAINER(results)), id);
+ 
+  if(row)
+  {
+    GtkBox      *col   = (GtkBox*)      g_list_nth_data(gtk_container_get_children(GTK_CONTAINER(row)), 0);
+    GtkLabel    *cmd   = (GtkLabel*)    g_list_nth_data(gtk_container_get_children(GTK_CONTAINER(col)), 0);
+    GtkLabel    *cdesc = (GtkLabel*)    g_list_nth_data(gtk_container_get_children(GTK_CONTAINER(col)), 1);
+
+    if(mode == NORMAL)
+    {
+      gtk_widget_modify_fg(GTK_WIDGET(cmd),   GTK_STATE_NORMAL, &(Zathura.Style.completion_fg));
+      gtk_widget_modify_fg(GTK_WIDGET(cdesc), GTK_STATE_NORMAL, &(Zathura.Style.completion_fg));
+      gtk_widget_modify_bg(GTK_WIDGET(row),   GTK_STATE_NORMAL, &(Zathura.Style.completion_bg));
+    }
     else
-      current = (length + current - 1) % length;
-
-    char* command = (char*) g_list_nth_data(Zathura.history, current);
-    gtk_widget_grab_focus(GTK_WIDGET(Zathura.inputbar));
-    gtk_entry_set_text(Zathura.inputbar, command);
-    gtk_editable_set_position(GTK_EDITABLE(Zathura.inputbar), -1);
+    {
+      gtk_widget_modify_fg(GTK_WIDGET(cmd),   GTK_STATE_NORMAL, &(Zathura.Style.completion_hl_fg));
+      gtk_widget_modify_fg(GTK_WIDGET(cdesc), GTK_STATE_NORMAL, &(Zathura.Style.completion_hl_fg));
+      gtk_widget_modify_bg(GTK_WIDGET(row),   GTK_STATE_NORMAL, &(Zathura.Style.completion_hl_bg));
+    }
   }
 }
 
+/* shortcut implementation */
+void
+sc_abort(Argument* argument)
+{
+  /* Clear buffer */
+  if(Zathura.Global.buffer)
+  {
+    g_string_free(Zathura.Global.buffer, TRUE);
+    Zathura.Global.buffer = NULL;
+    gtk_label_set_markup((GtkLabel*) Zathura.Global.status_buffer, "");
+  }
+
+  /* Set back to normal mode */
+  change_mode(NORMAL);
+}
+
 void
-update_title()
+sc_change_mode(Argument* argument)
 {
-  if(Zathura.PDF.file != NULL)
-    gtk_window_set_title(GTK_WINDOW(Zathura.window), Zathura.PDF.file);
-  else
-    gtk_window_set_title(GTK_WINDOW(Zathura.window), "zathura");
-}
-
-GtkWidget*
-notify(int level, char* text)
-{
-  GtkEventBox *view = GTK_EVENT_BOX(gtk_event_box_new());
- 
-  update_notification(GTK_WIDGET(view), level, text);
-
-  gtk_container_add(GTK_CONTAINER(Zathura.notification), GTK_WIDGET(view));
-  
-  gtk_widget_show_all(GTK_WIDGET(Zathura.window));
-  g_timeout_add_seconds(SHOW_NOTIFICATION, delete_widget, GTK_WIDGET(GTK_WIDGET(view)));
-
-  return GTK_WIDGET(view);
-}
-
-GtkWidget*
-update_notification(GtkWidget* view, int level, char* text)
-{
-  GtkLabel *message = GTK_LABEL(gtk_label_new(""));
-  gtk_label_set_markup(message, text);
-  g_signal_connect(G_OBJECT(message), "activate-link", G_CALLBACK(cb_label_open_link), NULL);
-
-  gtk_misc_set_alignment(GTK_MISC(message), 0, 0);
-  gtk_widget_modify_font(GTK_WIDGET(message), Zathura.Settings.font);
-
-  if(level == WARNING)
-  {
-    gtk_widget_modify_fg(GTK_WIDGET(message), GTK_STATE_NORMAL, &(Zathura.Settings.notification_wn_fg));
-    gtk_widget_modify_bg(GTK_WIDGET(view),    GTK_STATE_NORMAL, &(Zathura.Settings.notification_wn_bg));
-  }
-  else if(level == ERROR)
-  {
-    gtk_widget_modify_fg(GTK_WIDGET(message), GTK_STATE_NORMAL, &(Zathura.Settings.notification_er_fg));
-    gtk_widget_modify_bg(GTK_WIDGET(view),    GTK_STATE_NORMAL, &(Zathura.Settings.notification_er_bg));
-  }
-  else
-  {
-    gtk_widget_modify_fg(GTK_WIDGET(message), GTK_STATE_NORMAL, &(Zathura.Settings.notification_fg));
-    gtk_widget_modify_bg(GTK_WIDGET(view),    GTK_STATE_NORMAL, &(Zathura.Settings.notification_bg));
-  }
-
-  if(gtk_bin_get_child(GTK_BIN(view)))
-    gtk_container_remove(GTK_CONTAINER(view), gtk_bin_get_child(GTK_BIN(view)));
-
-  gtk_container_add(GTK_CONTAINER(view), GTK_WIDGET(message));
-
-  return GTK_WIDGET(view);
-}
-
-PopplerRectangle*
-recalcRectangle(PopplerRectangle* rectangle)
-{
-  double page_width, page_height;
-  double x1 = rectangle->x1;
-  double x2 = rectangle->x2;
-  double y1 = rectangle->y1;
-  double y2 = rectangle->y2;
-
-  poppler_page_get_size(Zathura.PDF.page, &page_width, &page_height);
-  
-  switch(Zathura.PDF.rotate)
-  {
-    case 90:
-      rectangle->x1 = (page_height - y2) * Zathura.PDF.scale;
-      rectangle->y1 = x1 * Zathura.PDF.scale;
-      rectangle->x2 = (page_height - y1) * Zathura.PDF.scale;
-      rectangle->y2 = x2 * Zathura.PDF.scale;
-      break;
-    case 180:
-      rectangle->x1 = (page_width  - x2) * Zathura.PDF.scale;
-      rectangle->y1 = (page_height - y2) * Zathura.PDF.scale;
-      rectangle->x2 = (page_width  - x1) * Zathura.PDF.scale;
-      rectangle->y2 = (page_height - y1) * Zathura.PDF.scale;
-      break;
-    case 270:
-      rectangle->x1 = y1 * Zathura.PDF.scale;
-      rectangle->y1 = (page_width  - x2) * Zathura.PDF.scale;
-      rectangle->x2 = y2 * Zathura.PDF.scale;
-      rectangle->y2 = (page_width  - x1) * Zathura.PDF.scale;
-      break;
-    default:
-      rectangle->x1 = x1 * Zathura.PDF.scale;
-      rectangle->y1 = y1 * Zathura.PDF.scale;
-      rectangle->x2 = x2 * Zathura.PDF.scale;
-      rectangle->y2 = y2 * Zathura.PDF.scale;
-  }
-
-  return rectangle;
-}
-
-void
-update_status()
-{
-  char* text = "";
-
-  if(Zathura.PDF.document && Zathura.PDF.page)
-    text = g_strdup_printf("[%i/%i] %s", Zathura.PDF.page_number + 1, Zathura.PDF.number_of_pages, Zathura.PDF.file);
-
-  gtk_entry_set_text(Zathura.inputbar, text);
-}
-
-void set_page(int page_number)
-{
-  if(page_number > Zathura.PDF.number_of_pages) 
-  {
-    notify(WARNING, "Could not open page");
-    return;
-  }
-  
-  Zathura.PDF.page_number = page_number;
-  Zathura.PDF.page = poppler_document_get_page(Zathura.PDF.document, page_number);
-}
-
-void
-draw()
-{
-  if(!Zathura.PDF.document || !Zathura.PDF.page)
-    return;
-
-  double page_width, page_height;
-  double width, height;
-
-  if(Zathura.PDF.surface)
-    cairo_surface_destroy(Zathura.PDF.surface);
-  Zathura.PDF.surface = NULL;
-
-  poppler_page_get_size(Zathura.PDF.page, &page_width, &page_height);
- 
-  if(Zathura.PDF.rotate == 0 || Zathura.PDF.rotate == 180)
-  {
-    width  = page_width  * Zathura.PDF.scale;
-    height = page_height * Zathura.PDF.scale;
-  }
-  else
-  {
-    width  = page_height * Zathura.PDF.scale;
-    height = page_width  * Zathura.PDF.scale;
-  }
-
-  cairo_t *cairo;
-  Zathura.PDF.surface = cairo_image_surface_create(CAIRO_FORMAT_RGB24, width, height);
-  cairo = cairo_create(Zathura.PDF.surface);
-
-  cairo_save(cairo);
-  cairo_set_source_rgb(cairo, 1, 1, 1);
-  cairo_rectangle(cairo, 0, 0, width, height);
-  cairo_fill(cairo);
-  cairo_restore(cairo);
-  cairo_save(cairo);
-
-  switch(Zathura.PDF.rotate)
-  {
-    case 90:
-      cairo_translate(cairo, width, 0);
-      break;
-    case 180:
-      cairo_translate(cairo, width, height);
-      break;
-    case 270:
-      cairo_translate(cairo, 0, height);
-      break;
-    default:
-      cairo_translate(cairo, 0, 0);
-  }
-
-  if(Zathura.PDF.scale != 1.0)
-    cairo_scale(cairo, Zathura.PDF.scale, Zathura.PDF.scale);
-
-  if(Zathura.PDF.rotate != 0)
-    cairo_rotate(cairo, Zathura.PDF.rotate * G_PI / 180.0);
-
-  poppler_page_render(Zathura.PDF.page, cairo);
-
-  cairo_restore(cairo);
-  cairo_destroy(cairo);
-
-  gtk_widget_set_size_request(Zathura.drawing_area, width, height);
-  gtk_widget_queue_draw(Zathura.drawing_area);
+  if(argument)
+    change_mode(argument->n);
 }
 
 void 
-highlight_result(PopplerRectangle* rectangle)
-{
-  cairo_t *cairo = cairo_create(Zathura.PDF.surface);
-  cairo_set_source_rgba(cairo, Zathura.Settings.search_highlight.red, Zathura.Settings.search_highlight.green, 
-      Zathura.Settings.search_highlight.blue, HL_TRANSPARENCY);
-
-  rectangle = recalcRectangle(rectangle);
- 
-  cairo_rectangle(cairo, rectangle->x1, rectangle->y1, (rectangle->x2 - rectangle->x1), (rectangle->y2 - rectangle->y1));
-  cairo_fill(cairo);
-}
-
-void
-open_link(char* link)
-{
-  char* start_browser = g_strdup_printf(BROWSER, link);
-  system(start_browser);
-}
-
-void
-save_images(int page, char* directory)
-{
-  GList           *image_list;
-  GList           *images;
-  cairo_surface_t *image;
-  PopplerPage     *document_page;
-
-  document_page = poppler_document_get_page(Zathura.PDF.document, page);
-  image_list = poppler_page_get_image_mapping(document_page);
-
-  for(images = image_list; images; images = g_list_next(images))
-  {
-    PopplerImageMapping *image_mapping;
-    PopplerRectangle     image_field;
-    gint                 image_id;
-    char*                file;
-    char*                filename;
-
-    image_mapping = (PopplerImageMapping*) images->data;
-    image_field   = image_mapping->area;
-    image_id      = image_mapping->image_id;
- 
-    image     = poppler_page_get_image(document_page, image_id);
-    filename  = g_strdup_printf("p%i_i%i.png", page + 1, image_id);
-
-    if(directory[0] == '~')
-    {
-      file = malloc(((int) strlen(filename) + (int) strlen(directory) 
-        + (int) strlen(getenv("HOME")) - 1) * sizeof(char));
-      file = g_strdup_printf("%s%s%s", getenv("HOME"), directory + 1, filename);
-    }
-    else
-      file = g_strdup_printf("%s%s", directory, filename);
-
-    cairo_surface_write_to_png(image, file);
-
-    g_free(file);
-  }
-}
-
-void
-save_attachments(char* directory)
-{
-  GList *attachment_list;
-  GList *attachments;
-  char  *file;
-
-  attachment_list = poppler_document_get_attachments(Zathura.PDF.document);
-
-  for(attachments = attachment_list; attachments; attachments = g_list_next(attachments))
-  {
-    PopplerAttachment *attachment = (PopplerAttachment*) attachments->data;
-    
-    if(directory[0] == '~')
-    {
-      file = malloc(((int) strlen(attachment->name) + (int) strlen(directory) 
-        + (int) strlen(getenv("HOME")) - 1) * sizeof(char));
-      file = g_strdup_printf("%s%s%s", getenv("HOME"), directory + 1, attachment->name);
-    }
-    else
-      file = g_strdup_printf("%s%s", directory, attachment->name);
-    
-    poppler_attachment_save(attachment, file, NULL);
-
-    g_free(file);
-  }
-}
-
-gboolean
-delete_widget(gpointer data)
-{
-  gtk_widget_destroy(GTK_WIDGET(data));
-
-  return FALSE;
-}
-
-gboolean
-complete(Argument* argument)
-{
-  static GtkBox     *results;
-  static GtkWidget **result_rows;
-  static char      **command_names;
-  static int         n = 0;
-  static int         current = -1; 
-
-  char *command = (char*) gtk_entry_get_text(Zathura.inputbar);
-  int   command_length  = strlen(command);
-  int   length = 0;
-  int   i = 0;
-
-  if( (command_length == 0 || command[0] != ':') && argument->n != HIDE )
-    return TRUE;
-
-  if(argument->n != HIDE && n > 0 && results && current != -1 && !strcmp(&command[1], command_names[current]) )
-  {
-    GtkEventBox *current_box   = (GtkEventBox*) g_list_nth_data(gtk_container_get_children(GTK_CONTAINER(results)),     current);
-    GtkLabel    *current_label = (GtkLabel*)    g_list_nth_data(gtk_container_get_children(GTK_CONTAINER(current_box)), 0);
-   
-    gtk_widget_modify_fg(GTK_WIDGET(current_label), GTK_STATE_NORMAL, &(Zathura.Settings.completion_fg));
-    gtk_widget_modify_bg(GTK_WIDGET(current_box),   GTK_STATE_NORMAL, &(Zathura.Settings.completion_bg));
-
-    if(argument->n == NEXT)
-      current = (current + n + 1) % n;
-    else if (argument->n == PREVIOUS)
-      current = (current + n - 1) % n;
-
-    current_box   = (GtkEventBox*) g_list_nth_data(gtk_container_get_children(GTK_CONTAINER(results)),     current);
-    current_label = (GtkLabel*)    g_list_nth_data(gtk_container_get_children(GTK_CONTAINER(current_box)), 0);
-
-    gtk_widget_modify_fg(GTK_WIDGET(current_label), GTK_STATE_NORMAL, &(Zathura.Settings.completion_hl_fg));
-    gtk_widget_modify_bg(GTK_WIDGET(current_box),   GTK_STATE_NORMAL, &(Zathura.Settings.completion_hl_bg));
-
-    char* temp_string = g_strconcat(":", command_names[current], NULL);
-    gtk_entry_set_text(GTK_ENTRY(Zathura.inputbar), temp_string);
-    gtk_editable_set_position(GTK_EDITABLE(Zathura.inputbar), -1);
-    g_free(temp_string);
-  }
-  else
-  {
-    if(results != NULL)
-      gtk_widget_destroy(GTK_WIDGET(results));
- 
-    free(result_rows);
-    free(command_names);
-
-    n             = 0;
-    current       = -1;
-    results       = NULL;
-    result_rows   = NULL;
-    command_names = NULL;
-
-    if(argument->n == HIDE)
-      return TRUE;
-  }
-
-  if(!results)
-  {
-    results       = GTK_BOX(gtk_vbox_new(FALSE, 0));
-    result_rows   = malloc(LENGTH(commands) * sizeof(GtkWidget*));
-    command_names = malloc(LENGTH(commands) * sizeof(char*));
-
-    for(i = 0; i < LENGTH(commands); i++)
-    {
-      length = strlen(commands[i].command);
-      
-      if( (command_length - 1 <= length) && !strncmp(&command[1], commands[i].command, command_length - 1) )
-      {
-        GtkLabel *show_command = GTK_LABEL(gtk_label_new(commands[i].command));
-        GtkEventBox *event_box = GTK_EVENT_BOX(gtk_event_box_new());
-
-        gtk_misc_set_alignment(GTK_MISC(show_command), 0, 0);
-        gtk_widget_modify_fg(  GTK_WIDGET(show_command), GTK_STATE_NORMAL, &(Zathura.Settings.completion_fg));
-        gtk_widget_modify_bg(  GTK_WIDGET(event_box),    GTK_STATE_NORMAL, &(Zathura.Settings.completion_bg));
-        gtk_widget_modify_font(GTK_WIDGET(show_command), Zathura.Settings.font);
-
-        gtk_container_add(GTK_CONTAINER(event_box), GTK_WIDGET(show_command));
-        gtk_box_pack_start(results, GTK_WIDGET(event_box), FALSE, FALSE, 0);
-        
-        command_names[n] = commands[i].command;
-        result_rows[n++] = GTK_WIDGET(event_box);
-      }
-    }
-
-    command_names = realloc(command_names, n * sizeof(char*));
-    result_rows   = realloc(result_rows,   n * sizeof(GtkWidget*));
-    
-    gtk_box_pack_start(Zathura.vbox, GTK_WIDGET(results), FALSE, FALSE, 0);
-    gtk_widget_show_all(GTK_WIDGET(Zathura.window));
-
-    current = (argument->n == NEXT) ? 0 : (n - 1);
-  }
-
-  if(current != -1 && n > 0)
-  {
-    GtkEventBox *current_box   = (GtkEventBox*) g_list_nth_data(gtk_container_get_children(GTK_CONTAINER(results)),     current);
-    GtkLabel    *current_label = (GtkLabel*)    g_list_nth_data(gtk_container_get_children(GTK_CONTAINER(current_box)), 0);
-   
-    gtk_widget_modify_fg(GTK_WIDGET(current_label), GTK_STATE_NORMAL, &(Zathura.Settings.completion_hl_fg));
-    gtk_widget_modify_bg(GTK_WIDGET(current_box),   GTK_STATE_NORMAL, &(Zathura.Settings.completion_hl_bg));
-
-    char* temp_string = g_strconcat(":", command_names[current], NULL);
-    gtk_entry_set_text(GTK_ENTRY(Zathura.inputbar), temp_string);
-    gtk_editable_set_position(GTK_EDITABLE(Zathura.inputbar), -1);
-    g_free(temp_string); 
-  }
-
-  return TRUE;
-}
-
-/* shortcut implementations */
-void
-sc_focus_inputbar(Argument *argument)
+sc_focus_inputbar(Argument* argument)
 {
-  if(argument->data)
-    gtk_entry_set_text(Zathura.inputbar, argument->data);
-  else
-    history(PREVIOUS);
-
-  gtk_widget_modify_text(GTK_WIDGET(Zathura.inputbar), GTK_STATE_NORMAL, &(Zathura.Settings.inputbar_fg));
-  gtk_widget_modify_base(GTK_WIDGET(Zathura.inputbar), GTK_STATE_NORMAL, &(Zathura.Settings.inputbar_bg));
- 
   if(argument->data)
   {
-    gtk_widget_grab_focus(GTK_WIDGET(Zathura.inputbar));
-    gtk_editable_set_position(GTK_EDITABLE(Zathura.inputbar), -1);
+    notify(DEFAULT, argument->data);
+    gtk_widget_grab_focus(GTK_WIDGET(Zathura.UI.inputbar));
+    gtk_editable_set_position(GTK_EDITABLE(Zathura.UI.inputbar), -1);
   }
 }
 
 void
-sc_scroll(Argument *argument)
-{
-  GtkAdjustment* adjustment;
-
-  if( (argument->n == LEFT) || (argument->n == RIGHT) )
-    adjustment = gtk_scrolled_window_get_hadjustment(Zathura.view);
-  else
-    adjustment = gtk_scrolled_window_get_vadjustment(Zathura.view);
-
-  gdouble view_size  = gtk_adjustment_get_page_size(adjustment);
-  gdouble value      = gtk_adjustment_get_value(adjustment);
-  gdouble max        = gtk_adjustment_get_upper(adjustment) - view_size;
-
-  int number_of_pages = poppler_document_get_n_pages(Zathura.PDF.document);
-  int new_page = Zathura.PDF.page_number;
-
-  int next_page = abs( (new_page + number_of_pages + 1) % number_of_pages);
-  int previous_page = abs( (new_page + number_of_pages - 1) % number_of_pages);
-
-  switch(argument->n) 
-  {
-    case TOP:
-      if ((value == 0 && previous_page >= 0)) 
-      {
-        set_page(previous_page);
-        gtk_adjustment_set_value(adjustment, max);
-        draw();
-        update_status();
-      } 
-      else 
-      {
-        gtk_adjustment_set_value(adjustment, 0);
-      }
-      break;
-    case BOTTOM:
-      if ((value >= max && next_page <= Zathura.PDF.number_of_pages)) 
-      {
-        set_page(next_page);
-        gtk_adjustment_set_value(adjustment, 0);
-        draw();
-        update_status();
-      } 
-      else 
-      {
-        gtk_adjustment_set_value(adjustment, max);
-      }
-      break;
-    case LEFT:
-      gtk_adjustment_set_value(adjustment, (value - SCROLL_STEP) < 0 ? 0 : (value - SCROLL_STEP));
-      break;
-    case DOWN:
-      if ((value - SCROLL_STEP) < 0 && previous_page >= 0) 
-      {
-        set_page(previous_page);
-        gtk_adjustment_set_value(adjustment, max);
-        draw();
-        update_status();
-      } 
-      else 
-      {
-        gtk_adjustment_set_value(adjustment, value - SCROLL_STEP);
-      }
-      break;
-    case RIGHT:
-      gtk_adjustment_set_value(adjustment, (value + SCROLL_STEP) > max ? max : (value + SCROLL_STEP));
-      break;
-    case UP:
-      if ((value + SCROLL_STEP) > max && next_page <= Zathura.PDF.number_of_pages) 
-      {
-        set_page(next_page);
-        gtk_adjustment_set_value(adjustment, 0);
-        draw();
-        update_status();
-      } 
-      else 
-      {
-        gtk_adjustment_set_value(adjustment, value + SCROLL_STEP);
-      }
-      break;
-  }
-
-}
-
-void
-sc_navigate(Argument *argument)
-{
-  int number_of_pages = poppler_document_get_n_pages(Zathura.PDF.document);
-  int new_page = Zathura.PDF.page_number;
-
-  if(argument->n == NEXT)
-    new_page = abs( (new_page + number_of_pages + 1) % number_of_pages);
-  else if(argument->n == PREVIOUS)
-    new_page = abs( (new_page + number_of_pages - 1) % number_of_pages);
-
-  set_page(new_page);
-  GtkAdjustment* adjustment;
-  adjustment = gtk_scrolled_window_get_vadjustment(Zathura.view);
-  gtk_adjustment_set_value(adjustment, 0);
-
-  draw();
-
-  update_status();
-}
-
-void
-sc_zoom(Argument *argument)
-{
-  if(argument->n == ZOOM_IN)
-    Zathura.PDF.scale += ZOOM_STEP;
-  else if(argument->n == ZOOM_OUT)
-    Zathura.PDF.scale -= ZOOM_STEP;
-  else if(argument->n == ZOOM_ORIGINAL)
-    Zathura.PDF.scale = 1.0;
-
-  draw();
-}
-
-void
-sc_adjust_window(Argument *argument)
-{
-  GtkAdjustment* adjustment;
-  double view_size;
-  double page_width;
-  double page_height;
-
-  if(argument->n == ADJUST_WIDTH)
-    adjustment = gtk_scrolled_window_get_vadjustment(Zathura.view);
-  else
-    adjustment = gtk_scrolled_window_get_hadjustment(Zathura.view);
-
-  view_size  = gtk_adjustment_get_page_size(adjustment);
-  poppler_page_get_size(Zathura.PDF.page, &page_width, &page_height);
-
-  // If document is on its side, then width is height and vice versa.
-  if ((Zathura.PDF.rotate == 90) || (Zathura.PDF.rotate == 270)) 
-  {
-    double swap = page_width;
-    page_width  = page_height;
-    page_height = swap;
-  }
-
-  if(argument->n == ADJUST_WIDTH)
-    Zathura.PDF.scale = view_size / page_height;
-  else
-    Zathura.PDF.scale = view_size / page_width;
-
-  draw();
-}
-
-void
-sc_rotate(Argument *argument)
-{
-  if(argument->n == LEFT)
-    Zathura.PDF.rotate = (270 + Zathura.PDF.rotate) % 360;
-  else if(argument->n == RIGHT)
-    Zathura.PDF.rotate = (450 + Zathura.PDF.rotate) % 360;
-
-  draw();
-}
-
-void
-sc_search(Argument *argument)
-{
-  static char* search_item;
-  static int direction;
-  int page_counter;
-  GList* results;
-  GList* list;
-
-  if(argument->data)
-    search_item = g_strdup((char*) argument->data);
-
-  if(!Zathura.PDF.document || !Zathura.PDF.page || !search_item)
-    return;
-
-  /* search document */
-  GtkWidget* search_status = notify(DEFAULT, "Searching...");
-  
-  if(argument->n)
-    direction = (argument->n == BACKWARD) ? -1 : 1;
-
-  for(page_counter = 1; page_counter <= Zathura.PDF.number_of_pages; page_counter++)
-  {
-    int next_page = (Zathura.PDF.number_of_pages + Zathura.PDF.page_number + 
-        page_counter * direction) % Zathura.PDF.number_of_pages;
-    set_page(next_page);
-    
-    results = poppler_page_find_text(Zathura.PDF.page, search_item);
-    if(results)
-      break;
-  }
-
-  /* draw results */
-  if(results)
-  {
-    double page_width, page_height;
-    poppler_page_get_size(Zathura.PDF.page, &page_width, &page_height);
-    draw();
-    
-    update_notification(GTK_WIDGET(search_status), DEFAULT, g_strdup_printf("%s found on page %i for %i time(s)", 
-      search_item, Zathura.PDF.page_number, g_list_length(results)));
-    
-    for(list = results; list && list->data; list = g_list_next(list))
-    {
-      PopplerRectangle* result = (PopplerRectangle*) list->data;
-      result->y1 = page_height - result->y1;
-      result->y2 = page_height - result->y2;
-      highlight_result(result);
-    }
-
-    if(argument->n == FORWARD || argument->n == BACKWARD)
-      update_status();
-  }
-  else
-    update_notification(search_status, DEFAULT, g_strdup_printf("No match for %s", search_item));
-}
-
-void
-sc_toggle_inputbar(Argument *argument)
-{
-  if(GTK_WIDGET_VISIBLE(GTK_WIDGET(Zathura.inputbar)))
-    gtk_widget_hide(GTK_WIDGET(Zathura.inputbar));
-  else
-    gtk_widget_show(GTK_WIDGET(Zathura.inputbar));
-
-  cb_draw(Zathura.drawing_area, NULL);
-}
-
-void 
-sc_toggle_index(Argument* argument)
-{
-  if(!Zathura.PDF.document)
-    return;
-
-  GtkWidget        *treeview;
-  GtkTreeModel     *model;
-  PopplerIndexIter *index_iter;
-  GtkCellRenderer  *renderer;
-  GtkTreeSelection *selection;
-
-  if(!Zathura.index)
-  {
-    Zathura.index = gtk_scrolled_window_new(NULL, NULL);
-    gtk_widget_set_size_request(GTK_WIDGET(Zathura.index), MIN_INDEX_WIDTH, -1);
-    gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(Zathura.index),
-      GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC);
-    gtk_box_pack_start(Zathura.hbox, GTK_WIDGET(Zathura.index), TRUE, TRUE, 0);
-    gtk_box_reorder_child(Zathura.hbox, GTK_WIDGET(Zathura.index), 0);
-
-    index_iter = poppler_index_iter_new(Zathura.PDF.document);
-
-    if(index_iter)
-    {
-      model = GTK_TREE_MODEL(gtk_tree_store_new(2, G_TYPE_STRING, G_TYPE_POINTER));
-      build_index(model, NULL, index_iter);
-      poppler_index_iter_free(index_iter);
-      treeview = gtk_tree_view_new_with_model(model);
-      g_object_unref(model);
-   
-      renderer = gtk_cell_renderer_text_new();
-      gtk_tree_view_insert_column_with_attributes(GTK_TREE_VIEW(treeview), 0, "Title", renderer,
-        "markup", 0, NULL);
-      gtk_tree_view_set_headers_visible(GTK_TREE_VIEW(treeview), FALSE);
-
-      selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(treeview));
-      g_signal_connect(G_OBJECT(selection), "changed", G_CALLBACK(cb_index_selection_changed),
-        NULL);
-
-      gtk_container_add(GTK_CONTAINER(Zathura.index), treeview);    
-      gtk_widget_show(GTK_WIDGET(treeview));
-    }
-    else
-      notify(WARNING, "This document does not contain any index");
-  }
-
-  if(GTK_WIDGET_VISIBLE(GTK_WIDGET(Zathura.index)))
-    gtk_widget_hide(GTK_WIDGET(Zathura.index));
-  else
-    gtk_widget_show(GTK_WIDGET(Zathura.index));
-}
-
-void
-sc_quit(Argument *argument)
+sc_quit(Argument* argument)
 {
   cb_destroy(NULL, NULL);
 }
 
-/* command implementations */
+/* inputbar shortcut declarations */
 void
-cmd_open(int argc, char** argv)
+isc_abort(Argument* argument)
 {
-  if(argc == 0 || (int) strlen(argv[0]) == 0)
-    return;
+  Argument arg = { HIDE };
+  isc_completion(&arg);
 
-  char* file = realpath(argv[0], NULL);
-  
-  if(argv[0][0] == '~')
-  {
-    file = realloc(file, ((int) strlen(argv[0]) + (int) strlen(getenv("HOME")) - 1) * sizeof(char));
-    file = g_strdup_printf("%s%s", getenv("HOME"), argv[0] + 1);
-  }
-
-  if(!g_file_test(file, G_FILE_TEST_IS_REGULAR))
-  {
-    notify(ERROR, "File does not exist");
-    return;
-  }
-
-  Zathura.PDF.document = poppler_document_new_from_file(g_strdup_printf("file://%s", file), 
-      (argc == 2) ? argv[1] : NULL, NULL);
-  
-  if(!Zathura.PDF.document)
-  {
-    notify(WARNING, "Can not open file");
-    return;
-  }
-
-  if(Zathura.index != NULL)
-    gtk_widget_destroy(Zathura.index);
-  Zathura.index = NULL;
-
-  Zathura.PDF.number_of_pages = poppler_document_get_n_pages(Zathura.PDF.document);
-  Zathura.PDF.file = file;
-  
-  set_page(0);
-  draw();  
- 
-  update_status();
-  update_title();
+  notify(DEFAULT, "");
+  gtk_widget_grab_focus(GTK_WIDGET(Zathura.UI.view));
 }
 
 void
-cmd_print(int argc, char** argv)
+isc_command_history(Argument* argument)
 {
-  if(argc == 0 || !Zathura.PDF.document)
-    return;
+  static int current = 0;
+  int        length  = g_list_length(Zathura.Global.history);
 
-  char* print_command;
-  char* sites;
-  char* printer;
-
-  if(strcmp(argv[0], "all") == 0)
-    sites = g_strdup_printf("%i", Zathura.PDF.number_of_pages);
-  else
-    sites = argv[0];
-
-  if(argc == 2)
+  if(length > 0)
   {
-    if(atoi(argv[1]) != 0 && atoi(argv[1]) <= (sizeof(PRINTER) / sizeof(char*)))
-      printer = (char*) PRINTER[atoi(argv[1]) - 1];
+    if(argument->n == NEXT)
+      current = (length + current + 1) % length;
     else
-      printer = argv[1];
-  }
-  else
-    printer = (char*) PRINTER[0];
+      current = (length + current - 1) % length;
 
-  print_command = g_strdup_printf("lp -d '%s' -P %s %s", printer, sites, Zathura.PDF.file);
-  system(print_command);
+    gchar* command = (gchar*) g_list_nth_data(Zathura.Global.history, current);
+    notify(DEFAULT, command);
+    gtk_widget_grab_focus(GTK_WIDGET(Zathura.UI.inputbar));
+    gtk_editable_set_position(GTK_EDITABLE(Zathura.UI.inputbar), -1);
+  }
 }
 
-void
-cmd_export(int argc, char** argv)
+void 
+isc_completion(Argument* argument)
 {
-  if(argc == 0 || !Zathura.PDF.document)
-    return;
+  gchar *input      = gtk_editable_get_chars(GTK_EDITABLE(Zathura.UI.inputbar), 1, -1);
+  gchar  identifier = gtk_editable_get_chars(GTK_EDITABLE(Zathura.UI.inputbar), 0,  1)[0];
+  int    length     = strlen(input);
  
-  if(argc < 2)
-  {
-    notify(WARNING, "No export path specified");
+  if(!length && !identifier)
     return;
-  }
-  
-  /* export images */
-  if(strcmp(argv[0], "images") == 0)
+
+  /* get current information*/
+  char* first_space = strstr(input, " ");
+  char* current_command;
+  char* current_parameter;
+  int   current_command_length;
+  int   current_parameter_length;
+
+  if(!first_space)
   {
-    int page_counter;
-   
-    if(argc == 3)
-    {
-      int page_number = atoi(argv[2]) - 1;
+    current_command          = input;
+    current_command_length   = length;
+    current_parameter        = NULL;
+    current_parameter_length = 0;
+  }
+  else
+  {
+    int offset               = abs(input - first_space);
+    current_command          = g_strndup(input, offset);
+    current_command_length   = strlen(current_command);
+    current_parameter        = input + offset + 1;
+    current_parameter_length = strlen(current_parameter);
+  }
 
-      if(page_number < 0 || page_number > Zathura.PDF.number_of_pages)
-        notify(WARNING, "Page does not exist");
-      else
-        save_images(page_number, argv[1]);
+  /* if the identifier does not match the command sign and
+   * the completion should not be hidden, leave this function */
+  if((identifier != ':') && (argument->n != HIDE))
+    return;
 
+  /* static elements */
+  static GtkBox        *results = NULL;
+  static CompletionRow *rows    = NULL;
+
+  static int current_item = 0;
+  static int n_items      = 0;
+
+  static char *previous_command   = NULL;
+  static char *previous_parameter = NULL;
+  static int   previous_id        = 0;
+  static int   previous_length    = 0;
+
+  static gboolean command_mode = TRUE;
+
+  /* delete old list iff
+   *   the completion should be hidden
+   *   the current command differs from the previous one
+   *   the current parameter differs from the previous one
+   */
+  if( (argument->n == HIDE) ||
+      (current_parameter && previous_parameter && strcmp(current_parameter, previous_parameter)) ||
+      (current_command && previous_command && strcmp(current_command, previous_command)) ||
+      (previous_length != length)
+    )
+  {
+    if(results)
+      gtk_widget_destroy(GTK_WIDGET(results));
+
+    results = NULL;
+
+    if(rows)
+      free(rows);
+
+    rows         = NULL;
+    current_item = 0;
+    n_items      = 0;
+    command_mode = TRUE;
+
+    if(argument->n == HIDE)
       return;
-    }
-    
-    for(page_counter = 0; page_counter < Zathura.PDF.number_of_pages; page_counter++)
+  }
+
+  /* create new list iff
+   *  there is no current list
+   *  the current command differs from the previous one
+   *  the current parameter differs from the previous one
+   */
+  if( (!results) )
+  {
+    results = GTK_BOX(gtk_vbox_new(FALSE, 0));
+
+    /* create list based on parameters iff
+     *  there is a current parameter given
+     *  there is an old list with commands
+     *  the current command does not differ from the previous one
+     *  the current command has an completion function
+     */
+    if( (previous_command) && (current_parameter) && !strcmp(current_command, previous_command) )
     {
-      save_images(page_counter, argv[1]);
-    }
-  }
+      if(previous_id < 0 || !commands[previous_id].completion)
+        return;
 
-  /* export attachments */
-  else if(strcmp(argv[0], "attachments") == 0)
-  {
-    if(!poppler_document_has_attachments(Zathura.PDF.document))
-      notify(WARNING, "PDF file has no attachments");
-    else
-      save_attachments(argv[1]);
-  }
-  else
-  {
-    notify(DEFAULT, "export [images|attachments]");
-    return;
-  }
-}
+      Completion *result = commands[previous_id].completion(current_parameter);
 
-void
-cmd_form(int argc, char** argv)
-{
-  if(argc == 0 || !Zathura.PDF.document || !Zathura.PDF.page)
-    return;
+      if(!result && result->groups)
+        return;
 
-  if(strcmp(argv[0], "show") == 0)
-  {
-    double page_width, page_height;
-    int form_id = 0;
-    GList* form_mapping = g_list_reverse(poppler_page_get_form_field_mapping(Zathura.PDF.page));
-    GList* forms;
+      command_mode = FALSE;
+      CompletionGroup* group;
+      CompletionElement* element;
 
-    poppler_page_get_size(Zathura.PDF.page, &page_width, &page_height);
+      rows = malloc(sizeof(CompletionRow));
 
-    for(forms = form_mapping; forms; forms = g_list_next(forms))
-    {
-      /* draw rectangle */
-      PopplerFormFieldMapping *form = (PopplerFormFieldMapping*) forms->data;
-      PopplerRectangle *form_rectangle = &form->area;
-
-      if(!poppler_form_field_is_read_only(form->field))
+      for(group = result->groups; group != NULL; group = group->next)
       {
-        form_rectangle->y1 = page_height - form_rectangle->y1;
-        form_rectangle->y2 = page_height - form_rectangle->y2;
+        int group_elements = 0;
 
-        highlight_result(form_rectangle);
+        for(element = group->elements; element != NULL; element = element->next)
+        {
+          if( (element->value) &&
+              (current_parameter_length <= strlen(element->value)) && !strncmp(current_parameter, element->value, current_parameter_length)
+            )
+          {
+            rows = realloc(rows, (n_items + 1) * sizeof(CompletionRow));
+            rows[n_items].command     = element->value;
+            rows[n_items].description = element->description;
+            rows[n_items].command_id  = previous_id;
+            rows[n_items].is_group    = FALSE;
+            rows[n_items++].row       = GTK_WIDGET(createCompletionRow(results, element->value, element->description, FALSE));
+            group_elements++;
+          }
+        }
 
-        /* draw text */
-        cairo_t *cairo = cairo_create(Zathura.PDF.surface);
-        cairo_select_font_face(cairo, font, CAIRO_FONT_SLANT_NORMAL, CAIRO_FONT_WEIGHT_BOLD);
-        cairo_set_font_size(cairo, 10);
-        cairo_move_to(cairo, form_rectangle->x1 + 1, form_rectangle->y1 - 1);
-        cairo_show_text(cairo, g_strdup_printf("%i", form_id));
+        if(group->value && group_elements > 0)
+        {
+          rows = realloc(rows, (n_items + 1) * sizeof(CompletionRow));
+          rows[n_items].command     = group->value;
+          rows[n_items].description = NULL;
+          rows[n_items].command_id  = -1;
+          rows[n_items].is_group    = TRUE;
+          rows[n_items].row       = GTK_WIDGET(createCompletionRow(results, group->value, NULL, TRUE));
+
+          /* Swap group element with first element of the list */
+          CompletionRow temp = rows[n_items - group_elements];
+          gtk_box_reorder_child(results, rows[n_items].row, n_items - group_elements);
+          rows[n_items - group_elements] = rows[n_items];
+          rows[n_items] = temp;
+
+          n_items++;
+        }
+      }
+
+      /* clean up */
+      group = result->groups;
+
+      while(group)
+      {
+        element = group->elements;
+        while(element)
+        {
+          CompletionElement* ne = element->next;
+          free(element);
+          element = ne;
+        }
+
+        CompletionGroup *ng = group->next;
+        free(group);
+        group = ng;
       }
-  
-      form_id++;
     }
-    
-    gtk_widget_queue_draw(Zathura.drawing_area);
-    poppler_page_free_form_field_mapping(form_mapping);
-  }
-  else if(strcmp(argv[0], "set") == 0)
-  {
-    if(argc <= 2)
-      return;
-
-    GList* form_mapping    = g_list_reverse(poppler_page_get_form_field_mapping(Zathura.PDF.page));
-    int    form_id         = atoi(argv[1]);
-    
-    PopplerFormFieldMapping *form = (PopplerFormFieldMapping*) g_list_nth_data(form_mapping, form_id);
-    PopplerFormFieldType type     = poppler_form_field_get_field_type(form->field);
-
-    if(type == POPPLER_FORM_FIELD_TEXT)
-    {
-      char *text = "";
-      int i;
-
-      for(i = 2; i < argc; i++)
-        text = g_strdup_printf("%s %s", text, argv[i]);
-      
-      poppler_form_field_text_set_text(form->field, text);
-    }
-    else if(type == POPPLER_FORM_FIELD_BUTTON)
-    {
-      if(argv[2][0] == '0')
-        poppler_form_field_button_set_state(form->field, FALSE);
-      else
-        poppler_form_field_button_set_state(form->field, TRUE);
-    }
-  
-   draw();
-  }
-}
-
-void
-cmd_goto(int argc, char** argv)
-{
-  if(argc == 0)
-    return;
-
-  int page = atoi(argv[0]);;
-  set_page(page - 1);
-  
-  Argument argument;
-  argument.n = TOP;
-  sc_scroll(&argument);
-  
-  draw();
-
-  update_status();
-}
-
-void
-cmd_info(int argc, char** argv)
-{
-  if(!Zathura.PDF.document)
-    return;
-
-  gchar *info;
-  gchar *title,   *author;
-  gchar *subject, *keywords;
-  gchar *creator, *producer;
-  GTime  creation_date, modification_date;
-
-  g_object_get(Zathura.PDF.document,
-      "title",         &title,
-      "author",        &author,
-      "subject",       &subject,
-      "keywords",      &keywords,
-      "creator",       &creator,
-      "producer",      &producer,
-      "creation-date", &creation_date,
-      "mod-date",      &modification_date,
-      NULL);
-
-  info = g_strconcat(
-      "<b>Title:</b> ",    title    ? title    : "", "\n", 
-      "<b>Author:</b> ",   author   ? author   : "", "\n",
-      "<b>Subject:</b> ",  subject  ? subject  : "", "\n",
-      "<b>Keywords:</b> ", keywords ? keywords : "", "\n",
-      "<b>Creator:</b> ",  creator  ? creator  : "", "\n",
-      "<b>Producer:</b> ", producer ? producer : "",
-      NULL);
-
-  notify(DEFAULT, info);
-}
-
-void
-cmd_links(int argc, char** argv)
-{
-  if(!Zathura.PDF.document && !Zathura.PDF.page)
-    return;
-
-  GList *link_list;
-  GList *links;
-  int    number_of_links = 0;
-
-  link_list       = poppler_page_get_link_mapping(Zathura.PDF.page);
-
-  for(links = link_list; links; links = g_list_next(links))
-  {
-    PopplerLinkMapping *link_mapping;
-    PopplerAction      *action;
-    
-    link_mapping = (PopplerLinkMapping*) links->data;
-    action       = poppler_action_copy(link_mapping->action);
-    
-    if(action->type == POPPLER_ACTION_URI)
-    {
-      char* link_name = poppler_page_get_text(Zathura.PDF.page, POPPLER_SELECTION_WORD, &link_mapping->area);
-      notify(DEFAULT, g_strdup_printf("<b><a href=\"%s\">%s</a>:</b> %s", action->uri.uri, link_name, action->uri.uri));
-      number_of_links++;
-    }
-  }
-  
-  if(number_of_links > 0)
-    notify(DEFAULT, g_strdup_printf("%d links found", number_of_links));
-  else
-    notify(WARNING, "No links found");
-
-
-  poppler_page_free_link_mapping(link_list);
-}
-
-void
-cmd_rotate(int argc, char** argv)
-{
-  Argument argument;
-  
-  if(argc == 0)
-    argument.n = RIGHT;
-  else 
-  {
-    if(!strncmp(argv[0], "left", strlen(argv[0]) - 1))
-      argument.n = LEFT;
+    /* create list based on commands */
     else
-      argument.n = RIGHT;
+    {
+      int i = 0;
+      command_mode = TRUE;
+
+      rows = malloc(LENGTH(commands) * sizeof(CompletionRow));
+
+      for(i = 0; i < LENGTH(commands); i++)
+      {
+        int abbr_length = strlen(commands[i].abbr);
+        int cmd_length  = strlen(commands[i].command);
+
+        /* add command to list iff
+         *  the current command would match the command
+         *  the current command would match the abbreviation
+         */
+        if( ((current_command_length <= cmd_length)  && !strncmp(current_command, commands[i].command, current_command_length)) ||
+            ((current_command_length <= abbr_length) && !strncmp(current_command, commands[i].abbr,    current_command_length))
+          )
+        {
+          rows[n_items].command     = commands[i].command;
+          rows[n_items].description = commands[i].description;
+          rows[n_items].command_id  = i;
+          rows[n_items].is_group    = FALSE;
+          rows[n_items++].row       = GTK_WIDGET(createCompletionRow(results, commands[i].command, commands[i].description, FALSE));
+        }
+      }
+
+      rows = realloc(rows, n_items * sizeof(CompletionRow));
+    }
+
+    gtk_box_pack_start(Zathura.UI.box, GTK_WIDGET(results), FALSE, FALSE, 0);
+    gtk_widget_show_all(GTK_WIDGET(Zathura.UI.window));
+
+    current_item = (argument->n == NEXT) ? -1 : 0;
   }
 
-  sc_rotate(&argument);
+  /* update coloring iff
+   *  there is a list with items
+   */
+  if( (results) && (n_items > 0) )
+  {
+    setCompletionRowColor(results, NORMAL, current_item);
+    char* temp;
+    int i = 0, next_group = 0;
+
+    for(i = 0; i < n_items; i++)
+    {
+      if(argument->n == NEXT || argument->n == NEXT_GROUP)
+        current_item = (current_item + n_items + 1) % n_items;
+      else if(argument->n == PREVIOUS || argument->n == PREVIOUS_GROUP)
+        current_item = (current_item + n_items - 1) % n_items;
+
+      if(rows[current_item].is_group)
+      {
+        if(!command_mode && (argument->n == NEXT_GROUP || argument->n == PREVIOUS_GROUP))
+          next_group = 1;
+        continue;
+      }
+      else
+      {
+        if(!command_mode && (next_group == 0) && (argument->n == NEXT_GROUP || argument->n == PREVIOUS_GROUP))
+          continue;
+        break;
+      }
+    }
+
+    setCompletionRowColor(results, HIGHLIGHT, current_item);
+
+    if(command_mode)
+    {
+      char* cp = (current_parameter) ? g_strconcat(" ", current_parameter, NULL) : 0;
+      temp = g_strconcat(":", rows[current_item].command, cp, NULL);
+    }
+    else
+    {
+      temp = g_strconcat(":", previous_command, " ", rows[current_item].command, NULL);
+    }
+
+    gtk_entry_set_text(Zathura.UI.inputbar, temp);
+    gtk_editable_set_position(GTK_EDITABLE(Zathura.UI.inputbar), -1);
+    g_free(temp);
+
+    previous_command   = (command_mode) ? rows[current_item].command : current_command;
+    previous_parameter = (command_mode) ? current_parameter : rows[current_item].command;
+    previous_length    = strlen(previous_command) + ((command_mode) ? (length - current_command_length) : (strlen(previous_parameter) + 1));
+    previous_id        = rows[current_item].command_id;
+  }
 }
 
 void
-cmd_save(int argc, char** argv)
+isc_string_manipulation(Argument* argument)
 {
-  if(argc == 0 || !Zathura.PDF.document)
-    return;
+  if(argument->n == DELETE_LAST_WORD)
+  {
+    gchar *input  = gtk_editable_get_chars(GTK_EDITABLE(Zathura.UI.inputbar), 0, -1);
+    int    length = strlen(input);
+    int    i      = 0;
 
-  poppler_document_save(Zathura.PDF.document, g_strdup_printf("file://%s", argv[0]), NULL);
-}
-
-void
-cmd_zoom(int argc, char** argv)
-{
-  if(argc == 0)
-    return;
-
-  int zoom = atoi(argv[0]);
-  if(zoom < 1 || zoom >= 1000)
-    return;
-
-  Zathura.PDF.scale = (float) zoom / 100;
-  draw();
+    for(i = length; i > 0; i--)
+    {
+      if( (input[i] == ' ') ||
+          (input[i] == '/') )
+      {
+        if(i == (length - 1))
+          continue;
+
+        i = (input[i] == ' ') ? (i - 1) : i;
+        break;
+      }
+    }
+
+    notify(DEFAULT, g_strndup(input, i + 1));
+    gtk_editable_set_position(GTK_EDITABLE(Zathura.UI.inputbar), -1);
+  }
 }
 
+/* command implementation */
 void
 cmd_quit(int argc, char** argv)
 {
   cb_destroy(NULL, NULL);
 }
 
-/* callback implementations */
-void
-cb_draw(GtkWidget *widget, gpointer data)
+/* completion command implementation */
+Completion* cc_open(char* input)
 {
-  gdk_window_clear(widget->window);
-  cairo_t *cairo = gdk_cairo_create(widget->window);
+  Completion *completion = malloc(sizeof(Completion));
+  CompletionGroup* group = malloc(sizeof(CompletionGroup));
+  CompletionElement *el1 = malloc(sizeof(CompletionElement));
+  CompletionElement *el2 = malloc(sizeof(CompletionElement));
+  CompletionElement *el3 = malloc(sizeof(CompletionElement));
+  CompletionElement *el4 = malloc(sizeof(CompletionElement));
+  CompletionElement *el5 = malloc(sizeof(CompletionElement));
+  CompletionElement *el6 = malloc(sizeof(CompletionElement));
+  CompletionGroup* g2 = malloc(sizeof(CompletionGroup));
 
-  /* Center the PDF if it is smaller than the window. */
-  double page_width, page_height, width, height;
-  poppler_page_get_size(Zathura.PDF.page, &page_width, &page_height);
+  el1->value = "Word 1";
+  el1->description = NULL;
+  el1->next = (CompletionElement*) el2;
+  el2->value = "Word 2";
+  el2->description = NULL;
+  el2->next = (CompletionElement*) el3;
+  el3->value = "Word 3";
+  el3->description = NULL;
+  el3->next = NULL;
 
-  if(Zathura.PDF.rotate == 0 || Zathura.PDF.rotate == 180)
-  {
-    width  = page_width  * Zathura.PDF.scale;
-    height = page_height * Zathura.PDF.scale;
-  }
-  else
-  {
-    width  = page_height * Zathura.PDF.scale;
-    height = page_width  * Zathura.PDF.scale;
-  }
+  el4->value = "Word 4";
+  el4->description = NULL;
+  el4->next = (CompletionElement*) el5;
+  el5->value = "Word 5";
+  el5->description = NULL;
+  el5->next = (CompletionElement*) el6;
+  el6->value = "Word 6";
+  el6->description = NULL;
+  el6->next = NULL;
 
-  int window_x, window_y;
-  gdk_drawable_get_size(widget->window, &window_x, &window_y);
+  group->value = "Group 1";
+  group->elements = el1;
+  group->next = g2;
 
-  int offset_x, offset_y;
+  g2->value = "Group 2";
+  g2->elements = el4;
+  g2->next = NULL;
 
-  if (window_x > width)
-    offset_x = (window_x - width) / 2;
-  else
-    offset_x = 0;
+  completion->groups = group;
 
-  if (window_y > height)
-    offset_y = (window_y - height) / 2;
-  else
-    offset_y = 0;
-
-  cairo_set_source_surface(cairo, Zathura.PDF.surface, offset_x, offset_y);
-  cairo_paint(cairo);
-  cairo_destroy(cairo);
+  return completion;
 }
 
-void
-cb_destroy(GtkWidget *widget, gpointer data)
+/* buffer command implementation */
+void 
+bcmd_goto(char* buffer, Argument* argument)
 {
-  pango_font_description_free(Zathura.Settings.font);
+
+}
+
+/* special command implementation */
+void
+scmd_search(char* input, Argument* argument)
+{
+
+}
+
+/* callback implementation */
+gboolean
+cb_destroy(GtkWidget* widget, gpointer data)
+{
+  pango_font_description_free(Zathura.Style.font);
   gtk_main_quit();
+
+  return TRUE;
 }
 
 gboolean
-cb_view_key_pressed(GtkWidget *widget, GdkEventKey *event, gpointer data)
+cb_view_kb_pressed(GtkWidget *widget, GdkEventKey *event, gpointer data)
 {
   int i;
   for(i = 0; i < LENGTH(shortcuts); i++)
   {
     if (event->keyval == shortcuts[i].key && 
-      (((event->state & shortcuts[i].mask) == shortcuts[i].mask) || shortcuts[i].mask == 0))
+      (((event->state & shortcuts[i].mask) == shortcuts[i].mask) || shortcuts[i].mask == 0)
+      && (Zathura.Global.mode == shortcuts[i].mode || shortcuts[i].mode == -1))
     {
       shortcuts[i].function(&(shortcuts[i].argument));
       return TRUE;
     }
   }
+
+  /* append only numbers and characters to buffer */
+  if( (event->keyval >= 0x30) && (event->keyval <= 0x7A))
+  {
+    if(!Zathura.Global.buffer)
+      Zathura.Global.buffer = g_string_new("");
+
+    Zathura.Global.buffer = g_string_append_c(Zathura.Global.buffer, event->keyval);
+    gtk_label_set_markup((GtkLabel*) Zathura.Global.status_buffer, Zathura.Global.buffer->str);
+  }
+
+  /* search buffer commands */
+  if(Zathura.Global.buffer)
+  {
+    for(i = 0; i < LENGTH(buffer_commands); i++)
+    {
+      regex_t regex;
+      int     status;
+
+      regcomp(&regex, buffer_commands[i].regex, REG_EXTENDED);
+      status = regexec(&regex, Zathura.Global.buffer->str, (size_t) 0, NULL, 0);
+      regfree(&regex);
+
+      if(status == 0)
+      {
+        buffer_commands[i].function(Zathura.Global.buffer->str, &(buffer_commands[i].argument));
+        g_string_free(Zathura.Global.buffer, TRUE);
+        Zathura.Global.buffer = NULL;
+        gtk_label_set_markup((GtkLabel*) Zathura.Global.status_buffer, "");
+
+        return TRUE;
+      }
+    }
+  }
+
   return FALSE;
 }
 
-void
-cb_inputbar_activate(GtkEntry* entry, gpointer data)
+gboolean
+cb_inputbar_kb_pressed(GtkWidget *widget, GdkEventKey *event, gpointer data)
 {
-  gchar **tokens   = g_strsplit(gtk_entry_get_text(entry), " ", gtk_entry_get_text_length(entry));
-  gchar  *command  = tokens[0] + 1;
-  int     length   = g_strv_length(tokens);
-  int          i   = 0;
-  gboolean success = FALSE;
-  Argument argument;
+  int i;
 
-  argument.n = HIDE;
-  complete(&argument);
-
-  if(length < 1)
-    return;
-
-  // special command
-  if(*tokens[0] == '/')
+  /* inputbar shortcuts */
+  for(i = 0; i < LENGTH(inputbar_shortcuts); i++)
   {
-    Argument argument;
-    argument.data = (char*) gtk_entry_get_text(entry) + 1;
-    sc_search(&argument);
-    g_strfreev(tokens);
-    update_status();
-    gtk_widget_grab_focus(GTK_WIDGET(Zathura.view));
-    return;
+    if(event->keyval == inputbar_shortcuts[i].key &&
+      (((event->state & inputbar_shortcuts[i].mask) == inputbar_shortcuts[i].mask)
+       || inputbar_shortcuts[i].mask == 0))
+    {
+      inputbar_shortcuts[i].function(&(inputbar_shortcuts[i].argument));
+      return TRUE;
+    }
   }
 
-  // other
+  /* special commands */
+  char identifier = gtk_editable_get_chars(GTK_EDITABLE(Zathura.UI.inputbar), 0, 1)[0];
+  for(i = 0; i < LENGTH(special_commands); i++)
+  {
+    if((identifier == special_commands[i].identifier) &&
+       (special_commands[i].always == 1))
+    {
+      gchar *input  = gtk_editable_get_chars(GTK_EDITABLE(Zathura.UI.inputbar), 1, -1);
+      special_commands[i].function(input, &(special_commands[i].argument));
+      return FALSE;
+    }
+  }
+
+  return FALSE;
+}
+
+gboolean
+cb_inputbar_activate(GtkEntry* entry, gpointer data)
+{
+  gchar  *input   = gtk_editable_get_chars(GTK_EDITABLE(entry), 1, -1);
+  gchar **tokens  = g_strsplit(input, " ", -1);
+  gchar  *command = tokens[0];
+  int     length  = g_strv_length(tokens);
+  int          i  = 0;
+
+  /* no input */
+  if(length < 1)
+  {
+    isc_abort(NULL);
+    return FALSE;
+  }
+
+  /* special commands */
+  char identifier = gtk_editable_get_chars(GTK_EDITABLE(entry), 0, 1)[0];
+  for(i = 0; i < LENGTH(special_commands); i++)
+  {
+    if(identifier == special_commands[i].identifier)
+    {
+      special_commands[i].function(input, &(special_commands[i].argument));
+      isc_abort(NULL);
+      return TRUE;
+    }
+  }
+
+  /* search commands */
   for(i = 0; i < LENGTH(commands); i++)
   {
-    if(g_strcmp0(command, commands[i].command) == 0)
+    if((g_strcmp0(command, commands[i].command) == 0) ||
+       (g_strcmp0(command, commands[i].abbr)    == 0))
     {
       commands[i].function(length - 1, tokens + 1);
-      success = TRUE;
       break;
     }
   }
 
-  if(!success)
-    notify(ERROR, g_strdup_printf("\"%s\" is not a valid command", command));
+  /* append input to the command history */
+  Zathura.Global.history = g_list_append(Zathura.Global.history, g_strdup(gtk_entry_get_text(entry)));
 
-  Zathura.history = g_list_append(Zathura.history, (char*) g_strdup(gtk_entry_get_text(entry)));
+  isc_abort(NULL);
 
-  update_status();
-  g_strfreev(tokens);
-  gtk_widget_grab_focus(GTK_WIDGET(Zathura.view));
-}
-
-void 
-cb_inputbar_button_pressed(GtkWidget* widget, GdkEventButton* event, gpointer data)
-{
-  if(event->type == GDK_BUTTON_PRESS)
-  {
-    gtk_widget_modify_text(GTK_WIDGET(Zathura.inputbar), GTK_STATE_NORMAL, &(Zathura.Settings.inputbar_fg));
-    gtk_widget_modify_base(GTK_WIDGET(Zathura.inputbar), GTK_STATE_NORMAL, &(Zathura.Settings.inputbar_bg));
-    gtk_widget_grab_focus(GTK_WIDGET(Zathura.inputbar));
-    gtk_entry_set_text(Zathura.inputbar, "");
-    gtk_editable_set_position(GTK_EDITABLE(Zathura.inputbar), -1);
-  }
-}
-
-void 
-cb_drawing_area_button_pressed(GtkWidget* widget, GdkEventButton* event, gpointer data)
-{
-  if(!Zathura.PDF.document && !Zathura.PDF.page)
-    return;
-
-  // left click
-  if(event->button == 1)
-  {
-    // check for links
-    GList *link_list = poppler_page_get_link_mapping(Zathura.PDF.page);
-    GList *links;
-    int number_of_links = g_list_length(link_list);
-
-    if(number_of_links <= 0)
-      return;
-
-    for(links = link_list; links; links = g_list_next(links))
-    {
-      PopplerLinkMapping *link_mapping = (PopplerLinkMapping*) links->data;
-      PopplerAction      *action       = poppler_action_copy(link_mapping->action);
-
-      double page_width, page_height;
-      poppler_page_get_size(Zathura.PDF.page, &page_width, &page_height);
-      PopplerRectangle* link_rectangle = &link_mapping->area;
-
-      if(Zathura.PDF.rotate == 0 || Zathura.PDF.rotate == 180)
-        event->y = page_height - event->y;
-      else if(Zathura.PDF.rotate == 90 || Zathura.PDF.rotate == 270)
-        event->x = page_height - event->x;
-        
-      link_rectangle = recalcRectangle(link_rectangle);
-      
-      // check if click is in url area
-      if( (link_rectangle->x1 <= event->x)
-       && (link_rectangle->x2 >= event->x)
-       && (link_rectangle->y1 <= event->y)
-       && (link_rectangle->y2 >= event->y))
-      {
-        if(action->type == POPPLER_ACTION_URI)
-          open_link(action->uri.uri);
-        else if(action->type == POPPLER_ACTION_GOTO_DEST)
-        {
-          PopplerDest* destination = action->goto_dest.dest;
-
-          if(destination->type == POPPLER_DEST_NAMED)
-          {            
-            destination = poppler_document_find_dest(Zathura.PDF.document, destination->named_dest);
-            
-            if(destination)
-            {  
-              set_page(destination->page_num - 1);
-              draw();
-              update_status();
-            }
-          }
-        }
-      }
-    }
-    
-    poppler_page_free_link_mapping(link_list);
-  }
-}
-
-void 
-cb_index_selection_changed(GtkTreeSelection* treeselection, GtkWidget* action_view)
-{
-  GtkTreeModel *model;
-  GtkTreeIter   iter;
-
-  if(gtk_tree_selection_get_selected(treeselection, &model, &iter))
-  {
-    PopplerAction* action;
-    PopplerDest*   destination;
-
-    gtk_tree_model_get(model, &iter, 1, &action, -1);
-    
-    if(action->type == POPPLER_ACTION_GOTO_DEST)
-    {
-      destination = action->goto_dest.dest;
-
-      if(destination->type == POPPLER_DEST_NAMED)
-      {
-        destination = poppler_document_find_dest(Zathura.PDF.document, destination->named_dest);
-
-        if(destination)
-        {
-          set_page(destination->page_num - 1);
-          draw();
-          update_status();
-        }
-      }
-    }
-  }
-}
-
-gboolean
-cb_label_open_link(GtkLabel* label, gchar* link, gpointer data)
-{
-  open_link(link);
   return TRUE;
 }
 
-gboolean
-cb_inputbar_key_pressed(GtkEntry* entry, GdkEventKey *event, gpointer data)
-{
-  Argument argument;
-
-  switch(event->keyval)
-  {
-    case GDK_Escape:
-      gtk_widget_grab_focus(GTK_WIDGET(Zathura.view));
-      update_status();
-      argument.n = HIDE;
-      return complete(&argument);
-    case GDK_Tab:
-      argument.n = NEXT;
-      return complete(&argument);
-    case GDK_ISO_Left_Tab:
-      argument.n = PREVIOUS;
-      return complete(&argument);
-    case GDK_Up:
-      history(PREVIOUS);
-      return TRUE;
-    case GDK_Down:
-      history(NEXT);
-      return TRUE;
-  }
-  
-  return FALSE;
-}
-
-gboolean
-cb_inputbar_key_released(GtkEntry *entry, GdkEventKey *event, gpointer data)
-{
-  int  length = gtk_entry_get_text_length(entry);
-  
-  #if INCREMENTAL_SEARCH
-  char*  text = (char*) gtk_entry_get_text(entry);
-  #endif
-  
-  Argument argument;
-
-  if(!length)
-  {
-    argument.n = HIDE;
-    complete(&argument);
-  }
-
-  #if INCREMENTAL_SEARCH
-  else if(length > 1 && text[0] == '/')
-  {
-    Argument argument;
-    argument.data = (char*) text + 1;
-    sc_search(&argument);
-    gtk_widget_grab_focus(GTK_WIDGET(Zathura.inputbar));
-    gtk_editable_set_position(GTK_EDITABLE(Zathura.inputbar), -1);
-  }
-  #endif
-
-  return FALSE;
-}
-
 /* main function */
-int
-main(int argc, char* argv[])
+int main(int argc, char* argv[])
 {
   gtk_init(&argc, &argv);
 
-  init();
-  
-  if(argc >= 2)
-    cmd_open(2, &argv[1]);
-
-  gtk_widget_show_all(GTK_WIDGET(Zathura.window));
- 
-  Argument arg;
-  arg.n = ADJUST_WIDTH;
-  sc_adjust_window(&arg);
+  init_zathura();
+  update_status("Text", "State");
 
+  gtk_widget_show_all(GTK_WIDGET(Zathura.UI.window));
   gtk_main();
 
   return 0;
 }
-