From 0eeb457bea2f93983e556d07028c2cfdb49b898c Mon Sep 17 00:00:00 2001 From: Moritz Lipp Date: Tue, 11 Aug 2009 23:18:50 +0200 Subject: [PATCH] Initial commit --- Makefile | 28 ++++ README | 34 +++++ config.h | 31 ++++ zathura.c | 435 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 528 insertions(+) create mode 100644 Makefile create mode 100644 README create mode 100644 config.h create mode 100644 zathura.c diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..b95cc67 --- /dev/null +++ b/Makefile @@ -0,0 +1,28 @@ +LIBS = gtk+-2.0 poppler poppler-glib +FLAGS = `pkg-config --cflags --libs $(LIBS)` +SOURCE = zathura.c +TARGET = zathura + +all: $(TARGET) + +$(TARGET): zathura.c config.h + gcc $(FLAGS) -Wall -o $(TARGET) $(SOURCE) + +clean: + rm -f $(TARGET) + +debug: $(TARGET) + gcc $(FLAGS) -Wall -o $(TARGET) $(SOURCE) -g + +valgrind: debug $(TARGET) + valgrind --tool=memcheck --leak-check=yes --show-reachable=yes ./${TARGET} + +install: all + @echo installing executeable to /usr/bin + @mkdir -p /usr/bin + @cp -f ${TARGET} /usr/bin + @chmod 755 /usr/bin/${TARGET} + +uninstall: + @echo removing executeable from /usr/bin + @rm -f /usr/bin/${TARGET} diff --git a/README b/README new file mode 100644 index 0000000..794abdb --- /dev/null +++ b/README @@ -0,0 +1,34 @@ +zathura - pdf viewer +-------------------- +zathura is an pdf viewer based on the poppler pdf rendering library + +Requirements +------------ +poppler (0.10.7-2) +poppler-glib (0.10.7-1) +gtk2 (2.16.5-1) + +Configuration +------------- +You can modify some parts of zathura by editing the config.h file + +Installation +------------ +Customise config.h according to your wishes and run the following +command to build and install zathura: + + make install + +Uninstall: +---------- +To delete zathura from your system, just type: + + make uninstall + +Use zathura +----------- +Just run: + + zathura + + diff --git a/config.h b/config.h new file mode 100644 index 0000000..3d91ce7 --- /dev/null +++ b/config.h @@ -0,0 +1,31 @@ +static const float zoom_step = 0.1; +static const float scroll_step = 40; + +static const char font[] = "monospace normal 9"; +static const char default_bgcolor[] = "#141414"; +static const char default_fgcolor[] = "#CCCCCC"; + +static const char inputbar_bgcolor[] = "#141414"; +static const char inputbar_fgcolor[] = "#9FBC00"; +static const char inputbar_wn_fgcolor[] = "#CCCCCC"; +static const char inputbar_wn_bgcolor[] = "#B82121"; + +static const char completion_fgcolor[] = "#CCCCCC"; +static const char completion_bgcolor[] = "#232323"; +static const char completion_hl_fgcolor[] = "#232323"; +static const char completion_hl_bgcolor[] = "#9FBC00"; + +Shortcut shortcuts[] = { + // mask, key, function, argument + {0, GDK_colon, sc_focus_inputbar, { .data = ":" } }, + {0, GDK_o, sc_focus_inputbar, { .data = ":open " } }, + {GDK_CONTROL_MASK, GDK_q, sc_quit, {0} }, +}; + +Command commands[] = { + // command, function + {"o", cmd_open}, + {"open", cmd_open}, + {"q", cmd_quit}, + {"quit", cmd_quit}, +}; diff --git a/zathura.c b/zathura.c new file mode 100644 index 0000000..3ac502a --- /dev/null +++ b/zathura.c @@ -0,0 +1,435 @@ +#include +#include + +#include +#include + +/* macros */ +#define LENGTH(x) sizeof(x)/sizeof((x)[0]) + +/* enums */ +enum { NEXT, PREVIOUS, HIDE, WARNING, DEFAULT }; + +struct +{ + GtkWindow *window; + GtkBox *box; + GtkScrolledWindow *view; + GtkEntry *inputbar; + + struct + { + GdkColor default_fg; + GdkColor default_bg; + GdkColor inputbar_fg; + GdkColor inputbar_bg; + GdkColor inputbar_wn_fg; + GdkColor inputbar_wn_bg; + GdkColor completion_fg; + GdkColor completion_bg; + GdkColor completion_hl_fg; + GdkColor completion_hl_bg; + PangoFontDescription *font; + } Settings; +} Zathura; + +typedef struct +{ + int n; + void *data; +} Argument; + +typedef struct +{ + int mask; + int key; + void (*function)(Argument*); + Argument argument; +} Shortcut; + +typedef struct +{ + char *command; + void (*function)(int, char**); +} Command; + +/* function declarations */ +void init(); +void update_title(); +void update_status(int, char*); + +gboolean complete(Argument*); + +/* shortcut declarations */ +void sc_focus_inputbar(Argument*); +void sc_quit(Argument*); + +/* command declarations */ +void cmd_open(int, char**); +void cmd_quit(int, char**); + +/* callbacks declarations */ +void cb_destroy(GtkWidget*, gpointer); +void cb_inputbar_activate(GtkEntry*, gpointer); +void cb_inputbar_button_pressed(GtkWidget*, GdkEventButton*, 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); + +/* configuration */ +#include "config.h" + +/* function implementations */ +void +init() +{ + /* 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(inputbar_wn_fgcolor, &(Zathura.Settings.inputbar_wn_fg)); + gdk_color_parse(inputbar_wn_bgcolor, &(Zathura.Settings.inputbar_wn_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)); + Zathura.Settings.font = pango_font_description_from_string(font); + + /* variables */ + Zathura.window = GTK_WINDOW(gtk_window_new(GTK_WINDOW_TOPLEVEL)); + Zathura.box = GTK_BOX(gtk_vbox_new(FALSE, 0)); + Zathura.view = GTK_SCROLLED_WINDOW(gtk_scrolled_window_new(NULL, NULL)); + Zathura.inputbar = GTK_ENTRY(gtk_entry_new()); + + /* window */ + gtk_window_set_title(Zathura.window, "title"); + g_signal_connect(G_OBJECT(Zathura.window), "destroy", G_CALLBACK(cb_destroy), NULL); + + /* box */ + gtk_box_set_spacing(Zathura.box, 0); + gtk_container_add(GTK_CONTAINER(Zathura.window), GTK_WIDGET(Zathura.box)); + + /* view */ + g_signal_connect(G_OBJECT(Zathura.view), "key-press-event", G_CALLBACK(cb_view_key_pressed), NULL); + + #ifdef 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 + + /* 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); + + /* packing */ + gtk_box_pack_start(Zathura.box, GTK_WIDGET(Zathura.view), TRUE, TRUE, 0); + gtk_box_pack_end(Zathura.box, 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 +update_title() +{ + +} + +void +update_status(int level, char* text) +{ + if(level == WARNING) + { + gtk_widget_modify_text(GTK_WIDGET(Zathura.inputbar), GTK_STATE_NORMAL, &(Zathura.Settings.inputbar_wn_fg)); + gtk_widget_modify_base(GTK_WIDGET(Zathura.inputbar), GTK_STATE_NORMAL, &(Zathura.Settings.inputbar_wn_bg)); + } + else if(level == DEFAULT) + { + 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_entry_set_text(Zathura.inputbar, text); +} + +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.box, 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) +{ + gtk_entry_set_text(Zathura.inputbar, argument->data); + 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_editable_set_position(GTK_EDITABLE(Zathura.inputbar), -1); +} + +void +sc_quit(Argument *argument) +{ + cb_destroy(NULL, NULL); +} + +/* command implementations */ +void +cmd_open(int argc, char** argv) +{ + +} + +void +cmd_quit(int argc, char** argv) +{ + cb_destroy(NULL, NULL); +} + +/* callback implementations */ +void +cb_destroy(GtkWidget *widget, gpointer data) +{ + gtk_main_quit(); +} + +gboolean +cb_view_key_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 == 0)) + { + shortcuts[i].function(&(shortcuts[i].argument)); + return TRUE; + } + } + return FALSE; +} + +void +cb_inputbar_activate(GtkEntry* entry, 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; + + argument.n = HIDE; + complete(&argument); + + if(length < 1) + return; + + // special command + if(*tokens[0] == '/') + return; + + // other + for(i = 0; i < LENGTH(commands); i++) + { + if(g_strcmp0(command, commands[i].command) == 0) + { + commands[i].function(length - 1, tokens + 1); + success = TRUE; + break; + } + } + + if(!success) + update_status(WARNING, "Not a valid command"); + else + update_status(DEFAULT, ""); + + 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_editable_set_position(GTK_EDITABLE(Zathura.inputbar), -1); + gtk_widget_grab_focus(GTK_WIDGET(Zathura.inputbar)); + } +} + +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(DEFAULT, ""); + 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); + } + + return FALSE; +} + +gboolean +cb_inputbar_key_released(GtkEntry *entry, GdkEventKey *event, gpointer data) +{ + int length = gtk_entry_get_text_length(entry); + Argument argument; + + if(!length) + { + argument.n = HIDE; + complete(&argument); + } + + return FALSE; +} + +/* main function */ +int +main(int argc, char* argv[]) +{ + gtk_init(&argc, &argv); + + init(); + + gtk_widget_show_all(GTK_WIDGET(Zathura.window)); + gtk_main(); + + return 0; +} +