From cf3a457887245a1edccee36efeb59bbdee2e9f0b Mon Sep 17 00:00:00 2001 From: Moritz Lipp 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[] = "%s"; +static const char FORMAT_DESCRIPTION[] = "%s"; + +/* 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..5ab080d 100644 --- a/zathura.c +++ b/zathura.c @@ -1,9 +1,8 @@ +/* See LICENSE file for license and copyright information */ + +#include #include #include -#include - -#include -#include #include #include @@ -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*)q + 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( - "Title: ", title ? title : "", "\n", - "Author: ", author ? author : "", "\n", - "Subject: ", subject ? subject : "", "\n", - "Keywords: ", keywords ? keywords : "", "\n", - "Creator: ", creator ? creator : "", "\n", - "Producer: ", 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("%s: %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(®ex, buffer_commands[i].regex, REG_EXTENDED); + status = regexec(®ex, Zathura.Global.buffer->str, (size_t) 0, NULL, 0); + regfree(®ex); + + 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; } -