Merge branch 'develop'

This commit is contained in:
Moritz Lipp 2012-02-09 02:09:57 +01:00
commit de0890c215
40 changed files with 4123 additions and 1088 deletions

4
.gitignore vendored
View file

@ -7,3 +7,7 @@
zathura
zathura-debug
zathura.pc
*.info
*.gcno
*.gcda
gcov/

30
Doxyfile Normal file
View file

@ -0,0 +1,30 @@
# See LICENSE file for license and copyright information
# General information
PROJECT_NAME = zathura
OUTPUT_DIRECTORY = ./doc/
OUTPUT_LANGUAGE = English
TAB_SIZE = 2
EXTRACT_ALL = YES
OPTIMIZE_OUTPUT_FOR_C = YES
DOXYFILE_ENCODING = UTF-8
TYPEDEF_HIDES_STRUCT = YES
# Warning and progress messages
QUIET = YES
WARNINGS = YES
WARN_IF_UNDOCUMENTED = YES
# Input files
INPUT =
EXCLUDE = ./tests
FILE_PATTERNS = *.h *.c
RECURSIVE = YES
# Output files
GENERATE_HTML = YES
GENERATE_LATEX = NO
GENERATE_RTF = NO
GENERATE_XML = NO
SOURCE_BROWSER = YES

View file

@ -4,10 +4,21 @@ include config.mk
include common.mk
PROJECT = zathura
SOURCE = $(shell find . -iname "*.c")
SOURCE = $(shell find . -iname "*.c" -a ! -iname "database-*" ! -path "*tests*")
HEADER = $(shell find . -iname "*.h")
OBJECTS = $(patsubst %.c, %.o, $(SOURCE))
DOBJECTS = $(patsubst %.c, %.do, $(SOURCE))
ifeq (${DATABASE}, sqlite)
INCS += $(SQLITE_INC)
LIBS += $(SQLITE_LIB)
SOURCE += database-sqlite.c
else
ifeq (${DATABASE}, plain)
SOURCE += database-plain.c
endif
endif
all: options ${PROJECT}
options:
@ -20,12 +31,15 @@ options:
%.o: %.c
$(ECHO) CC $<
@mkdir -p .depend
$(QUIET)${CC} -c ${CFLAGS} -o $@ $< -MMD -MF .depend/$@.dep
$(QUIET)${CC} -c ${CPPFLAGS} ${CFLAGS} -o $@ $< -MMD -MF .depend/$@.dep
%.do: %.c
$(ECHO) CC $<
@mkdir -p .depend
$(QUIET)${CC} -c ${CFLAGS} ${DFLAGS} -o $@ $< -MMD -MF .depend/$@.dep
$(QUIET)${CC} -c ${CPPFLAGS} ${CFLAGS} ${DFLAGS} -o $@ $< -MMD -MF .depend/$@.dep
# force recompilation of database.o if DATABASE has changed
database.o: database-${DATABASE}.o
${OBJECTS}: config.mk
${DOBJECTS}: config.mk
@ -36,7 +50,8 @@ ${PROJECT}: ${OBJECTS}
clean:
$(QUIET)rm -rf ${PROJECT} ${OBJECTS} ${PROJECT}-${VERSION}.tar.gz \
${DOBJECTS} ${PROJECT}-debug .depend ${PROJECT}.pc
${DOBJECTS} ${PROJECT}-debug .depend ${PROJECT}.pc doc *gcda *gcno $(PROJECT).info gcov
$(QUIET)make -C tests clean
${PROJECT}-debug: ${DOBJECTS}
$(ECHO) CC -o $@
@ -57,26 +72,45 @@ valgrind: debug
gdb: debug
cgdb ${PROJECT}-debug
tests: ${OBJECTS}
$(QUIET)make -C tests
dist: clean
$(QUIET)mkdir -p ${PROJECT}-${VERSION}
$(QUIET)cp -R LICENSE Makefile config.mk README \
${PROJECT}.1 ${SOURCE} ${PROJECT}.pc.in \
$(QUIET)cp -R LICENSE Makefile config.mk common.mk README Doxyfile \
${PROJECT}.1 ${SOURCE} ${HEADER} ${PROJECT}.pc.in tests \
${PROJECT}-${VERSION}
$(QUIET)tar -cf ${PROJECT}-${VERSION}.tar ${PROJECT}-${VERSION}
$(QUIET)gzip ${PROJECT}-${VERSION}.tar
$(QUIET)rm -rf ${PROJECT}-${VERSION}
doc: clean
$(QUIET)doxygen Doxyfile
gcov: clean
$(QUIET)CFLAGS="${CFLAGS}-fprofile-arcs -ftest-coverage" LDFLAGS="${LDFLAGS} -fprofile-arcs" ${MAKE} $(PROJECT)
$(QUIET)${MAKE} -C tests
$(QUIET)lcov --directory . --capture --output-file $(PROJECT).info
$(QUIET)genhtml --output-directory gcov $(PROJECT).info
install: all ${PROJECT}.pc
$(ECHO) installing executable file
$(QUIET)mkdir -p ${DESTDIR}${PREFIX}/bin
$(QUIET)install -m 755 ${PROJECT} ${DESTDIR}${PREFIX}/bin
$(ECHO) installing header file
$(ECHO) installing header files
$(QUIET)mkdir -p ${DESTDIR}${PREFIX}/include/${PROJECT}
$(QUIET)cp -f document.h ${DESTDIR}${PREFIX}/include/${PROJECT}
$(QUIET)cp -f zathura.h ${DESTDIR}${PREFIX}/include/${PROJECT}
$(ECHO) installing manual page
$(ECHO) installing manual pages
$(QUIET)mkdir -p ${DESTDIR}${MANPREFIX}/man1
$(QUIET)sed "s/VERSION/${VERSION}/g" < ${PROJECT}.1 > ${DESTDIR}${MANPREFIX}/man1/${PROJECT}.1
$(QUIET)if which rst2man > /dev/null ; then \
mkdir -p ${DESTDIR}${MANPREFIX}/man5 ; \
rst2man ${PROJECT}rc.5.rst > ${DESTDIR}${MANPREFIX}/man5/${PROJECT}rc.5 ; \
fi
$(QUIET)mkdir -p ${DESTDIR}${DESKTOPPREFIX}
$(ECHO) installing desktop file
$(QUIET)install -m 644 ${PROJECT}.desktop ${DESTDIR}${DESKTOPPREFIX}
$(QUIET)chmod 644 ${DESTDIR}${MANPREFIX}/man1/${PROJECT}.1
$(ECHO) installing pkgconfig file
$(QUIET)mkdir -p ${DESTDIR}${PREFIX}/lib/pkgconfig
@ -85,14 +119,16 @@ install: all ${PROJECT}.pc
uninstall:
$(ECHO) removing executable file
$(QUIET)rm -f ${DESTDIR}${PREFIX}/bin/${PROJECT}
$(ECHO) removing header file
$(QUIET)rm -f ${DESTDIR}${PREFIX}/include/${PROJECT}/document.h
$(QUIET)rm -f ${DESTDIR}${PREFIX}/include/${PROJECT}/zathura.h
$(ECHO) removing manual page
$(ECHO) removing header files
$(QUIET)rm -rf ${DESTDIR}${PREFIX}/include/${PROJECT}
$(ECHO) removing manual pages
$(QUIET)rm -f ${DESTDIR}${MANPREFIX}/man1/${PROJECT}.1
$(QUIET)rm -f ${DESTDIR}${MANPREFIX}/man5/${PROJECT}rc.5
$(ECHO) removing desktop file
$(QUIET)rm -f ${DESTDIR}${DESKTOPPREFIX}/${PROJECT}.desktop
$(ECHO) removing pkgconfig file
$(QUIET)rm -f ${DESTDIR}${PREFIX}/lib/pkgconfig
$(QUIET)rm -f ${DESTDIR}${PREFIX}/lib/pkgconfig/${PROJECT}.pc
-include $(wildcard .depend/*.dep)
.PHONY: all options clean debug valgrind gdb dist install uninstall
.PHONY: all options clean doc debug valgrind gdb dist doc install uninstall tests

11
README
View file

@ -7,9 +7,16 @@ Requirements
------------
gtk2 (>= 2.18.6)
girara
sqlite3
check (for tests)
Please note that you need to have a working pkg-config installation
and that the Makefile is only compatible with GNU make.
Please note that you need to have a working pkg-config installation and that the
Makefile is only compatible with GNU make. If you don't have a working
pkg-config installation please set the GTK_INC, GTK_LIB, GIRARA_INC, GIRARA_LIB,
SQLITE_INC and SQLITE_LIB variables accordingly.
And also note that rst2man from python-docutils is needed to build zathurarc.5.
If it is not installed, zathurarc.5 won't be built.
Installation
------------

View file

@ -5,18 +5,28 @@
#include "database.h"
#include "document.h"
#include <girara/datastructures.h>
#include <girara/utils.h>
static int
bookmark_compare_find(const void* item, const void* data)
{
const zathura_bookmark_t* bookmark = item;
const char* id = data;
return g_strcmp0(bookmark->id, id);
}
zathura_bookmark_t*
zathura_bookmark_add(zathura_t* zathura, const gchar* id, unsigned int page)
{
g_return_val_if_fail(zathura && zathura->document && zathura->bookmarks.bookmarks, NULL);
g_return_val_if_fail(id, NULL);
GIRARA_LIST_FOREACH(zathura->bookmarks.bookmarks, zathura_bookmark_t*, iter, bookmark)
if (strcmp(bookmark->id, id) == 0) {
girara_list_iterator_free(iter);
return NULL;
}
GIRARA_LIST_FOREACH_END(zathura->bookmarks.bookmarks, zathura_bookmark_t*, iter, bookmark)
zathura_bookmark_t* old = girara_list_find(zathura->bookmarks.bookmarks, bookmark_compare_find, id);
if (old != NULL) {
return NULL;
}
zathura_bookmark_t* bookmark = g_malloc0(sizeof(zathura_bookmark_t));
bookmark->id = g_strdup(id);
@ -58,14 +68,7 @@ zathura_bookmark_get(zathura_t* zathura, const gchar* id)
g_return_val_if_fail(zathura && zathura->bookmarks.bookmarks, NULL);
g_return_val_if_fail(id, NULL);
GIRARA_LIST_FOREACH(zathura->bookmarks.bookmarks, zathura_bookmark_t*, iter, bookmark)
if (strcmp(bookmark->id, id) == 0) {
girara_list_iterator_free(iter);
return bookmark;
}
GIRARA_LIST_FOREACH_END(zathura->bookmarks.bookmarks, zathura_bookmark_t*, iter, bookmark)
return NULL;
return girara_list_find(zathura->bookmarks.bookmarks, bookmark_compare_find, id);
}
void
@ -81,8 +84,11 @@ zathura_bookmark_free(zathura_bookmark_t* bookmark)
bool
zathura_bookmarks_load(zathura_t* zathura, const gchar* file) {
g_return_val_if_fail(zathura && zathura->database, false);
g_return_val_if_fail(zathura, false);
g_return_val_if_fail(file, false);
if (zathura->database == NULL) {
return false;
}
girara_list_t* bookmarks = zathura_db_load_bookmarks(zathura->database, file);
if (!bookmarks) {
@ -94,3 +100,18 @@ zathura_bookmarks_load(zathura_t* zathura, const gchar* file) {
return true;
}
int
zathura_bookmarks_compare(zathura_bookmark_t* lhs, zathura_bookmark_t* rhs)
{
if (lhs == NULL && rhs == NULL) {
return 0;
}
if (lhs == NULL) {
return -1;
}
if (rhs == NULL) {
return 1;
}
return g_strcmp0(lhs->id, rhs->id);
}

View file

@ -49,8 +49,16 @@ void zathura_bookmark_free(zathura_bookmark_t* bookmark);
* Load bookmarks for a specific file.
* @param zathura The zathura instance.
* @param file The file.
* @param true on success, false otherwise
* @return true on success, false otherwise
*/
bool zathura_bookmarks_load(zathura_t* zathura, const gchar* file);
/**
* Compare two bookmarks.
* @param lhs a bookmark
* @param rhs a bookmark
* @returns g_strcmp0(lhs->id, rhs->id)
*/
int zathura_bookmarks_compare(zathura_bookmark_t* lhs, zathura_bookmark_t* rhs);
#endif // BOOKMARKS_H

View file

@ -1,23 +1,30 @@
/* See LICENSE file for license and copyright information */
#include <girara.h>
#include <girara/statusbar.h>
#include <girara/session.h>
#include <girara/settings.h>
#include <girara/utils.h>
#include <stdlib.h>
#include <gtk/gtk.h>
#include <string.h>
#include "callbacks.h"
#include "zathura.h"
#include "render.h"
#include "document.h"
#include "utils.h"
#include "shortcuts.h"
#include "page_widget.h"
gboolean
cb_destroy(GtkWidget* UNUSED(widget), gpointer UNUSED(data))
{
gtk_main_quit();
return TRUE;
}
void
buffer_changed(girara_session_t* session)
cb_buffer_changed(girara_session_t* session)
{
g_return_if_fail(session != NULL);
g_return_if_fail(session->global.data != NULL);
@ -35,57 +42,255 @@ buffer_changed(girara_session_t* session)
}
void
cb_view_vadjustment_value_changed(GtkAdjustment *adjustment, gpointer data)
cb_view_vadjustment_value_changed(GtkAdjustment* GIRARA_UNUSED(adjustment), gpointer data)
{
zathura_t* zathura = data;
if (!zathura || !zathura->document || !zathura->document->pages || !zathura->ui.page_view) {
if (!zathura || !zathura->document || !zathura->document->pages || !zathura->ui.page_widget) {
return;
}
/* get current adjustment values */
gdouble lower = gtk_adjustment_get_value(adjustment);
gdouble upper = lower + gtk_adjustment_get_page_size(adjustment);
GtkAdjustment* view_vadjustment = gtk_scrolled_window_get_vadjustment(GTK_SCROLLED_WINDOW(zathura->ui.session->gtk.view));
GtkAdjustment* view_hadjustment = gtk_scrolled_window_get_hadjustment(GTK_SCROLLED_WINDOW(zathura->ui.session->gtk.view));
GdkRectangle view_rect;
/* get current adjustment values */
view_rect.y = gtk_adjustment_get_value(view_vadjustment);
view_rect.height = gtk_adjustment_get_page_size(view_vadjustment);
view_rect.x = gtk_adjustment_get_value(view_hadjustment);
view_rect.width = gtk_adjustment_get_page_size(view_hadjustment);
int page_padding = 1;
girara_setting_get(zathura->ui.session, "page-padding", &page_padding);
GdkRectangle center;
center.x = view_rect.x + (view_rect.width + 1) / 2;
center.y = view_rect.y + (view_rect.height + 1) / 2;
center.height = center.width = 2*page_padding + 1;
bool updated = false;
/* find page that fits */
for (unsigned int page_id = 0; page_id < zathura->document->number_of_pages; page_id++)
{
zathura_page_t* page = zathura->document->pages[page_id];
page_offset_t* offset = page_calculate_offset(page);
if (offset == NULL) {
continue;
}
page_offset_t offset;
page_calculate_offset(page, &offset);
double begin = offset->y;
double end = offset->y + page->height;
GdkRectangle page_rect;
page_rect.x = offset.x;
page_rect.y = offset.y;
page_rect.width = page->width * zathura->document->scale;
page_rect.height = page->height * zathura->document->scale;
if ( ( (begin >= lower) && (end <= upper) ) /* [> page is in viewport <]*/
|| ( (begin <= lower) && (end >= lower) && (end <= upper) ) /* [> end of the page is in viewport <] */
|| ( (begin >= lower) && (end >= upper) && (begin <= upper) ) /* [> begin of the page is in viewport <] */
) {
if (gdk_rectangle_intersect(&view_rect, &page_rect, NULL) == TRUE) {
page->visible = true;
if (page->surface == NULL) {
render_page(zathura->sync.render_thread, page);
if (updated == false && gdk_rectangle_intersect(&center, &page_rect, NULL) == TRUE) {
zathura->document->current_page_number = page_id;
updated = true;
}
} else {
page->visible = false;
cairo_surface_destroy(page->surface);
page->surface = NULL;
}
free(offset);
}
statusbar_page_number_update(zathura);
}
void
cb_pages_per_row_value_changed(girara_session_t* UNUSED(session), girara_setting_t* setting)
cb_pages_per_row_value_changed(girara_session_t* UNUSED(session), const char* UNUSED(name), girara_setting_type_t UNUSED(type), void* value, void* data)
{
int pages_per_row = setting->value.i;
zathura_t* zathura = setting->data;
g_return_if_fail(value != NULL);
int pages_per_row = *(int*) value;
zathura_t* zathura = data;
if (pages_per_row < 1) {
pages_per_row = 1;
}
page_view_set_mode(zathura, pages_per_row);
page_widget_set_mode(zathura, pages_per_row);
}
void
cb_index_row_activated(GtkTreeView* tree_view, GtkTreePath* path,
GtkTreeViewColumn* UNUSED(column), void* data)
{
zathura_t* zathura = data;
if (tree_view == NULL || zathura == NULL || zathura->ui.session == NULL) {
return;
}
GtkTreeModel *model;
GtkTreeIter iter;
g_object_get(tree_view, "model", &model, NULL);
if(gtk_tree_model_get_iter(model, &iter, path))
{
zathura_index_element_t* index_element;
gtk_tree_model_get(model, &iter, 2, &index_element, -1);
if (index_element == NULL) {
return;
}
if (index_element->type == ZATHURA_LINK_TO_PAGE) {
sc_toggle_index(zathura->ui.session, NULL, NULL, 0);
page_set_delayed(zathura, index_element->target.page_number);
} else if (index_element->type == ZATHURA_LINK_EXTERNAL) {
if (girara_xdg_open(index_element->target.uri) == false) {
girara_notify(zathura->ui.session, GIRARA_ERROR, "Failed to run xdg-open.");
}
}
}
g_object_unref(model);
}
bool
cb_sc_follow(GtkEntry* entry, girara_session_t* session)
{
g_return_val_if_fail(session != NULL, FALSE);
g_return_val_if_fail(session->global.data != NULL, FALSE);
zathura_t* zathura = session->global.data;
bool eval = true;
char* input = gtk_editable_get_chars(GTK_EDITABLE(entry), 0, -1);
if (input == NULL || strlen(input) == 0) {
eval = false;
}
int index = 0;
if (eval == true) {
index = atoi(input);
if (index == 0 && g_strcmp0(input, "0") != 0) {
girara_notify(session, GIRARA_WARNING, "Invalid input '%s' given.", input);
eval = false;
}
index = index - 1;
}
/* set pages to draw links */
bool invalid_index = true;
for (unsigned int page_id = 0; page_id < zathura->document->number_of_pages; page_id++) {
zathura_page_t* page = zathura->document->pages[page_id];
if (page == NULL || page->visible == false) {
continue;
}
g_object_set(page->drawing_area, "draw-links", FALSE, NULL);
if (eval == true) {
zathura_link_t* link = zathura_page_widget_link_get(ZATHURA_PAGE(page->drawing_area), index);
if (link != NULL) {
switch (link->type) {
case ZATHURA_LINK_TO_PAGE:
page_set_delayed(zathura, link->target.page_number);
break;
case ZATHURA_LINK_EXTERNAL:
girara_xdg_open(link->target.value);
break;
}
invalid_index = false;
}
}
}
if (eval == true && invalid_index == true) {
girara_notify(session, GIRARA_WARNING, "Invalid index '%s' given.", input);
}
g_free(input);
return (eval == TRUE) ? TRUE : FALSE;
}
void
cb_file_monitor(GFileMonitor* monitor, GFile* file, GFile* UNUSED(other_file), GFileMonitorEvent event, girara_session_t* session)
{
g_return_if_fail(monitor != NULL);
g_return_if_fail(file != NULL);
g_return_if_fail(session != NULL);
if (event != G_FILE_MONITOR_EVENT_CHANGES_DONE_HINT) {
return;
}
sc_reload(session, NULL, NULL, 0);
}
static gboolean
password_dialog(gpointer data)
{
zathura_password_dialog_info_t* dialog = data;
if (dialog != NULL) {
girara_dialog(dialog->zathura->ui.session, "Incorrect password. Enter password:", true, NULL,
(girara_callback_inputbar_activate_t) cb_password_dialog, dialog);
}
return FALSE;
}
bool
cb_password_dialog(GtkEntry* entry, zathura_password_dialog_info_t* dialog)
{
if (entry == NULL || dialog == NULL) {
goto error_ret;
}
if (dialog->path == NULL) {
free(dialog);
goto error_ret;
}
if (dialog->zathura == NULL) {
goto error_free;
}
char* input = gtk_editable_get_chars(GTK_EDITABLE(entry), 0, -1);
/* no or empty password: ask again */
if (input == NULL || strlen(input) == 0) {
if (input != NULL) {
g_free(input);
}
g_idle_add(password_dialog, dialog);
return false;
}
/* try to open document again */
if (document_open(dialog->zathura, dialog->path, input) == false) {
g_idle_add(password_dialog, dialog);
} else {
g_free(dialog->path);
free(dialog);
}
g_free(input);
return true;
error_free:
g_free(dialog->path);
free(dialog);
error_ret:
return false;
}
bool
cb_view_resized(GtkWidget* UNUSED(widget), GtkAllocation* UNUSED(allocation), zathura_t* zathura)
{
if (zathura == NULL || zathura->document == NULL) {
return false;
}
girara_argument_t argument = { zathura->document->adjust_mode, NULL };
sc_adjust_window(zathura->ui.session, &argument, NULL, 0);
return true;
}

View file

@ -4,14 +4,17 @@
#define CALLBACKS_H
#include <gtk/gtk.h>
#include <girara.h>
#include <girara/types.h>
#include <girara/macros.h>
#include "document.h"
/**
* Quits the current zathura session
*
* @param widget The gtk window of zathura
* @param data NULL
* @return TRUE
* @return true if no error occured and the event has been handled
*/
gboolean cb_destroy(GtkWidget* widget, gpointer data);
@ -20,7 +23,7 @@ gboolean cb_destroy(GtkWidget* widget, gpointer data);
*
* @param session The girara session
*/
void buffer_changed(girara_session_t* session);
void cb_buffer_changed(girara_session_t* session);
/**
* This function gets called when the value of the vertical scrollbars
@ -35,8 +38,63 @@ void cb_view_vadjustment_value_changed(GtkAdjustment *adjustment, gpointer data)
* variable changes
*
* @param session The current girara session
* @param setting The "pages-per-row" setting
* @param name The name of the row
* @param type The settings type
* @param value The value
* @param data Custom data
*/
void cb_pages_per_row_value_changed(girara_session_t* session, girara_setting_t* setting);
void cb_pages_per_row_value_changed(girara_session_t* session, const char* name,
girara_setting_type_t type, void* value, void* data);
/**
* Called when an index element is activated (e.g.: double click)
*
* @param tree_view Tree view
* @param path Path
* @param column Column
* @param zathura Zathura session
*/
void cb_index_row_activated(GtkTreeView* tree_view, GtkTreePath* path,
GtkTreeViewColumn* column, void* zathura);
/**
* Called when input has been passed to the sc_follow dialog
*
* @param entry The dialog inputbar
* @param session The girara session
* @return true if no error occured and the event has been handled
*/
bool cb_sc_follow(GtkEntry* entry, girara_session_t* session);
/**
* Emitted when file has been changed
*
* @param monitor The file monitor
* @param file The file
* @param other_file A file or NULL
* @param event The monitor event
* @param session The girara session
*/
void cb_file_monitor(GFileMonitor* monitor, GFile* file, GFile* other_file,
GFileMonitorEvent event, girara_session_t* session);
/**
* Callback to read new password for file that should be opened
*
* @param entry The password entry
* @param dialog The dialog information
* @return true if input has been handled
*/
bool cb_password_dialog(GtkEntry* entry, zathura_password_dialog_info_t* dialog);
/**
* Emitted when the view has been resized
*
* @param widget View
* @param allocation Allocation
* @param zathura Zathura session
* @return true if signal has been handled successfully
*/
bool cb_view_resized(GtkWidget* widget, GtkAllocation* allocation, zathura_t* zathura);
#endif // CALLBACKS_H

View file

@ -1,16 +1,54 @@
/* See LICENSE file for license and copyright information */
#include <string.h>
#include "commands.h"
#include "bookmarks.h"
#include "database.h"
#include "document.h"
#include "zathura.h"
#include "print.h"
#include "document.h"
#include "utils.h"
#include "page_widget.h"
#include <girara/session.h>
#include <girara/datastructures.h>
#include <girara/utils.h>
bool
cmd_bookmark_create(girara_session_t* UNUSED(session), girara_list_t*
UNUSED(argument_list))
cmd_bookmark_create(girara_session_t* session, girara_list_t* argument_list)
{
g_return_val_if_fail(session != NULL, false);
g_return_val_if_fail(session->global.data != NULL, false);
zathura_t* zathura = session->global.data;
if (zathura->document == NULL) {
girara_notify(session, GIRARA_ERROR, "No document opened.");
return false;
}
const unsigned int argc = girara_list_size(argument_list);
if (argc != 1) {
girara_notify(session, GIRARA_ERROR, "Invalid number of arguments given.");
return false;
}
const char* bookmark_name = girara_list_nth(argument_list, 0);
zathura_bookmark_t* bookmark = zathura_bookmark_get(zathura, bookmark_name);
if (bookmark != NULL) {
bookmark->page = zathura->document->current_page_number + 1;
girara_notify(session, GIRARA_INFO, "Bookmark successfuly updated: %s", bookmark_name);
return true;
}
bookmark = zathura_bookmark_add(zathura, bookmark_name, zathura->document->current_page_number + 1);
if (bookmark == NULL) {
girara_notify(session, GIRARA_ERROR, "Could not create bookmark: %s", bookmark_name);
return false;
}
girara_notify(session, GIRARA_INFO, "Bookmark successfuly created: %s", bookmark_name);
return true;
}
@ -42,10 +80,30 @@ cmd_bookmark_delete(girara_session_t* session, girara_list_t* argument_list)
}
bool
cmd_bookmark_open(girara_session_t* UNUSED(session), girara_list_t*
UNUSED(argument_list))
cmd_bookmark_open(girara_session_t* session, girara_list_t* argument_list)
{
return true;
g_return_val_if_fail(session != NULL, false);
g_return_val_if_fail(session->global.data != NULL, false);
zathura_t* zathura = session->global.data;
if (zathura->document == NULL) {
girara_notify(session, GIRARA_ERROR, "No document opened.");
return false;
}
const unsigned int argc = girara_list_size(argument_list);
if (argc != 1) {
girara_notify(session, GIRARA_ERROR, "Invalid number of arguments given.");
return false;
}
const char* bookmark_name = girara_list_nth(argument_list, 0);
zathura_bookmark_t* bookmark = zathura_bookmark_get(zathura, bookmark_name);
if (bookmark == NULL) {
girara_notify(session, GIRARA_ERROR, "No such bookmark: %s", bookmark_name);
return false;
}
return page_set(zathura, bookmark->page - 1);
}
bool
@ -55,7 +113,6 @@ cmd_close(girara_session_t* session, girara_list_t* UNUSED(argument_list))
g_return_val_if_fail(session->global.data != NULL, false);
zathura_t* zathura = session->global.data;
if (zathura->document == NULL) {
// nothing needs to be done
return true;
}
@ -65,10 +122,61 @@ cmd_close(girara_session_t* session, girara_list_t* UNUSED(argument_list))
}
bool
cmd_info(girara_session_t* UNUSED(session), girara_list_t*
UNUSED(argument_list))
cmd_info(girara_session_t* session, girara_list_t* UNUSED(argument_list))
{
return true;
g_return_val_if_fail(session != NULL, false);
g_return_val_if_fail(session->global.data != NULL, false);
zathura_t* zathura = session->global.data;
if (zathura->document == NULL) {
girara_notify(session, GIRARA_ERROR, "No document opened.");
return false;
}
struct meta_field {
char* name;
zathura_document_meta_t field;
};
struct meta_field meta_fields[] = {
{ "Title", ZATHURA_DOCUMENT_TITLE },
{ "Author", ZATHURA_DOCUMENT_AUTHOR },
{ "Subject", ZATHURA_DOCUMENT_SUBJECT },
{ "Keywords", ZATHURA_DOCUMENT_KEYWORDS },
{ "Creator", ZATHURA_DOCUMENT_CREATOR },
{ "Producer", ZATHURA_DOCUMENT_PRODUCER },
{ "Creation date", ZATHURA_DOCUMENT_CREATION_DATE },
{ "Modiciation date", ZATHURA_DOCUMENT_MODIFICATION_DATE }
};
GString* string = g_string_new(NULL);
if (string == NULL) {
return true;
}
for (unsigned int i = 0; i < LENGTH(meta_fields); i++) {
char* tmp = zathura_document_meta_get(zathura->document, meta_fields[i].field, NULL);
if (tmp != NULL) {
char* text = g_strdup_printf("<b>%s:</b> %s\n", meta_fields[i].name, tmp);
if (text == NULL) {
g_free(tmp);
return true;
}
g_string_append(string, text);
g_free(text);
g_free(tmp);
}
}
if (strlen(string->str) > 0) {
g_string_erase(string, strlen(string->str) - 1, 1);
girara_notify(session, GIRARA_INFO, "%s", string->str);
}
g_string_free(string, TRUE);
return false;
}
bool
@ -89,15 +197,13 @@ cmd_open(girara_session_t* session, girara_list_t* argument_list)
if (argc > 2) {
girara_notify(session, GIRARA_ERROR, "Too many arguments.");
return false;
}
else if (argc >= 1) {
} else if (argc >= 1) {
if (zathura->document) {
document_close(zathura);
}
document_open(zathura, girara_list_nth(argument_list, 0), (argc == 2) ? girara_list_nth(argument_list, 1) : NULL);
}
else {
} else {
girara_notify(session, GIRARA_ERROR, "No arguments given.");
return false;
}
@ -136,8 +242,7 @@ cmd_save(girara_session_t* session, girara_list_t* argument_list)
if (girara_list_size(argument_list) == 1) {
document_save(zathura, girara_list_nth(argument_list, 0), false);
}
else {
} else {
girara_notify(session, GIRARA_ERROR, "Invalid number of arguments.");
return false;
}
@ -159,11 +264,82 @@ cmd_savef(girara_session_t* session, girara_list_t* argument_list)
if (girara_list_size(argument_list) == 1) {
document_save(zathura, girara_list_nth(argument_list, 0), true);
}
else {
} else {
girara_notify(session, GIRARA_ERROR, "Invalid number of arguments.");
return false;
}
return true;
}
bool
cmd_search(girara_session_t* session, const char* input, girara_argument_t* argument)
{
g_return_val_if_fail(session != NULL, false);
g_return_val_if_fail(input != NULL, false);
g_return_val_if_fail(argument != NULL, false);
g_return_val_if_fail(session->global.data != NULL, false);
zathura_t* zathura = session->global.data;
if (zathura->document == NULL || strlen(input) == 0) {
return false;
}
bool firsthit = true;
for (unsigned int page_id = 0; page_id < zathura->document->number_of_pages; ++page_id) {
zathura_page_t* page = zathura->document->pages[(page_id + zathura->document->current_page_number) % zathura->document->number_of_pages];
if (page == NULL) {
continue;
}
g_object_set(page->drawing_area, "draw-links", FALSE, NULL);
girara_list_t* result = zathura_page_search_text(page, input, NULL);
if (result == NULL || girara_list_size(result) == 0) {
girara_list_free(result);
g_object_set(page->drawing_area, "search-results", NULL, NULL);
continue;
}
g_object_set(page->drawing_area, "search-results", result, NULL);
if (firsthit == true) {
if (page_id != 0) {
page_set_delayed(zathura, page->number);
}
g_object_set(page->drawing_area, "search-current", 0, NULL);
firsthit = false;
}
}
return true;
}
bool
cmd_export(girara_session_t* session, girara_list_t* argument_list)
{
g_return_val_if_fail(session != NULL, false);
g_return_val_if_fail(session->global.data != NULL, false);
zathura_t* zathura = session->global.data;
if (zathura->document == NULL) {
girara_notify(session, GIRARA_ERROR, "No document opened.");
return false;
}
const unsigned int argc = girara_list_size(argument_list);
if (argc != 2) {
girara_notify(session, GIRARA_ERROR, "Invalid number of arguments given.");
return false;
}
const char* attachment_name = girara_list_nth(argument_list, 0);
const char* file_name = girara_list_nth(argument_list, 1);
char* file_name2 = girara_fix_path(file_name);
if (!zathura_document_attachment_save(zathura->document, attachment_name, file_name)) {
girara_notify(session, GIRARA_ERROR, "Couldn't write attachment '%s' to '%s'.", attachment_name, file_name);
} else {
girara_notify(session, GIRARA_INFO, "Wrote attachment '%s' to '%s'.", attachment_name, file_name2);
}
g_free(file_name2);
return true;
}

View file

@ -4,7 +4,7 @@
#define COMMANDS_H
#include <stdbool.h>
#include <girara.h>
#include <girara/types.h>
/**
* Create a bookmark
@ -96,5 +96,23 @@ bool cmd_save(girara_session_t* session, girara_list_t* argument_list);
*/
bool cmd_savef(girara_session_t* session, girara_list_t* argument_list);
/**
* Search the current file
*
* @param session The used girara session
* @param input The current input
* @param argument Passed argument
* @return true if no error occured
*/
bool cmd_search(girara_session_t* session, const char* input, girara_argument_t* argument);
/**
* Save attachment to a file
*
* @param session The used girara session
* @param argument_list List of passed arguments
* @return true if no error occured
*/
bool cmd_export(girara_session_t* session, girara_list_t* argument_list);
#endif // COMMANDS_H

View file

@ -6,11 +6,82 @@
#include <unistd.h>
#include <libgen.h>
#include "bookmarks.h"
#include "completion.h"
#include "utils.h"
#include <girara/session.h>
#include <girara/completion.h>
#include <girara/utils.h>
#include <girara/datastructures.h>
static int
compare_case_insensitive(const char* str1, const char* str2)
{
char* ustr1 = g_utf8_casefold(str1, -1);
char* ustr2 = g_utf8_casefold(str2, -1);
int res = g_utf8_collate(ustr1, ustr2);
g_free(ustr1);
g_free(ustr2);
return res;
}
static girara_list_t*
list_files(zathura_t* zathura, const char* current_path, const char* current_file, int current_file_length, bool is_dir)
{
/* read directory */
GDir* dir = g_dir_open(current_path, 0, NULL);
if (dir == NULL) {
return NULL;
}
girara_list_t* res = girara_sorted_list_new2((girara_compare_function_t)compare_case_insensitive,
(girara_free_function_t)g_free);
/* read files */
char* name = NULL;
while ((name = (char*) g_dir_read_name(dir)) != NULL) {
char* e_name = g_filename_display_name(name);
if (e_name == NULL) {
goto error_free;
}
int e_length = strlen(e_name);
if ((current_file_length > e_length) || strncmp(current_file, e_name,
current_file_length)) {
g_free(e_name);
continue;
}
char* full_path = g_strdup_printf("%s%s%s", current_path, is_dir ? "" : "/", e_name);
if (full_path == NULL) {
g_free(e_name);
goto error_free;
}
if (g_file_test(full_path, G_FILE_TEST_IS_DIR) == true) {
char* tmp_path = full_path;
full_path = g_strdup_printf("%s/", full_path);
g_free(tmp_path);
girara_list_append(res, full_path);
} else if (file_valid_extension(zathura, full_path) == true) {
girara_list_append(res, full_path);
} else {
g_free(full_path);
}
g_free(e_name);
}
g_dir_close(dir);
return res;
error_free:
girara_list_free(res);
return NULL;
}
girara_completion_t*
cc_open(girara_session_t* session, char* input)
cc_open(girara_session_t* session, const char* input)
{
g_return_val_if_fail(session != NULL, NULL);
g_return_val_if_fail(session->global.data != NULL, NULL);
@ -34,7 +105,7 @@ cc_open(girara_session_t* session, char* input)
/* If the path does not begin with a slash we update the path with the current
* working directory */
if (strlen(path) == 0 || path[0] != '/') {
size_t path_max;
long path_max;
#ifdef PATH_MAX
path_max = PATH_MAX;
#else
@ -44,7 +115,9 @@ cc_open(girara_session_t* session, char* input)
#endif
char cwd[path_max];
getcwd(cwd, path_max);
if (getcwd(cwd, path_max) == NULL) {
goto error_free;
}
char* tmp_path = g_strdup_printf("%s/%s", cwd, path);
if (tmp_path == NULL) {
@ -79,50 +152,19 @@ cc_open(girara_session_t* session, char* input)
/* read directory */
if (g_file_test(current_path, G_FILE_TEST_IS_DIR) == TRUE) {
GDir* dir = g_dir_open(current_path, 0, NULL);
if (dir == NULL) {
girara_list_t* names = list_files(zathura, current_path, current_file, current_file_length, is_dir);
if (!names) {
goto error_free;
}
/* read files */
char* name = NULL;
while ((name = (char*) g_dir_read_name(dir)) != NULL) {
char* e_name = g_filename_display_name(name);
int e_length = strlen(e_name);
if (e_name == NULL) {
goto error_free;
}
if ((current_file_length > e_length) || strncmp(current_file, e_name,
current_file_length)) {
g_free(e_name);
continue;
}
char* full_path = g_strdup_printf("%s%s%s", current_path, is_dir ? "" : "/", e_name);
if (full_path == NULL) {
g_free(e_name);
goto error_free;
}
if (g_file_test(full_path, G_FILE_TEST_IS_DIR) == true) {
char* tmp_path = full_path;
full_path = g_strdup_printf("%s/", full_path);
g_free(tmp_path);
girara_completion_group_add_element(group, full_path, NULL);
} else if (file_valid_extension(zathura, full_path) == true) {
girara_completion_group_add_element(group, full_path, NULL);
}
g_free(full_path);
g_free(e_name);
}
g_dir_close(dir);
GIRARA_LIST_FOREACH(names, const char*, iter, file)
girara_completion_group_add_element(group, file, NULL);
GIRARA_LIST_FOREACH_END(names, const char*, iter, file);
girara_list_free(names);
}
g_free(path);
g_free(current_path);
girara_completion_add_group(completion, group);
@ -142,3 +184,94 @@ error_free:
return NULL;
}
girara_completion_t*
cc_bookmarks(girara_session_t* session, const char* input)
{
if (input == NULL) {
return NULL;
}
g_return_val_if_fail(session != NULL, NULL);
g_return_val_if_fail(session->global.data != NULL, NULL);
zathura_t* zathura = session->global.data;
girara_completion_t* completion = girara_completion_init();
girara_completion_group_t* group = girara_completion_group_create(session, NULL);
if (completion == NULL || group == NULL) {
goto error_free;
}
const size_t input_length = strlen(input);
GIRARA_LIST_FOREACH(zathura->bookmarks.bookmarks, zathura_bookmark_t*, iter, bookmark)
if (input_length <= strlen(bookmark->id) && !strncmp(input, bookmark->id, input_length)) {
gchar* paged = g_strdup_printf("Page %d", bookmark->page);
girara_completion_group_add_element(group, bookmark->id, paged);
g_free(paged);
}
GIRARA_LIST_FOREACH_END(zathura->bookmarks.bookmarks, zathura_bookmark_t*, iter, bookmark);
girara_completion_add_group(completion, group);
return completion;
error_free:
if (completion) {
girara_completion_free(completion);
}
if (group) {
girara_completion_group_free(group);
}
return NULL;
}
girara_completion_t*
cc_export(girara_session_t* session, const char* input)
{
if (input == NULL) {
return NULL;
}
g_return_val_if_fail(session != NULL, NULL);
g_return_val_if_fail(session->global.data != NULL, NULL);
zathura_t* zathura = session->global.data;
girara_completion_t* completion = girara_completion_init();
girara_completion_group_t* group = girara_completion_group_create(session, NULL);
if (completion == NULL || group == NULL) {
goto error_free;
}
const size_t input_length = strlen(input);
girara_list_t* attachments = zathura_document_attachments_get(zathura->document, NULL);
if (attachments == NULL) {
goto error_free;
}
GIRARA_LIST_FOREACH(attachments, const char*, iter, attachment)
if (input_length <= strlen(attachment) && !strncmp(input, attachment, input_length)) {
girara_completion_group_add_element(group, attachment, NULL);
}
GIRARA_LIST_FOREACH_END(zathura->bookmarks.bookmarks, zathura_bookmark_t*, iter, bookmark);
girara_completion_add_group(completion, group);
girara_list_free(attachments);
return completion;
error_free:
if (completion) {
girara_completion_free(completion);
}
if (group) {
girara_completion_group_free(group);
}
return NULL;
}

View file

@ -3,7 +3,7 @@
#ifndef COMPLETION_H
#define COMPLETION_H
#include <girara.h>
#include <girara/types.h>
/**
* Completion for the open command - Creates a list of accesible directories or
@ -13,6 +13,25 @@
* @param input The current input
* @return The completion object or NULL if an error occured
*/
girara_completion_t* cc_open(girara_session_t* session, char* input);
girara_completion_t* cc_open(girara_session_t* session, const char* input);
/**
* Completion for the bmarks command - Creates a list of bookmarks
*
* @param session The used girara session
* @param input The current input
* @return The completion object or NULL if an error occured
*/
girara_completion_t* cc_bookmarks(girara_session_t* session, const char* input);
/**
* Completion for the export command - Creates a list of attachments
*
* @param session the girara session
* @param input the current input
* @return completion object, NULL on error
*/
girara_completion_t* cc_export(girara_session_t* session, const char* input);
#endif // COMPLETION_H

218
config.c
View file

@ -7,15 +7,23 @@
#include "shortcuts.h"
#include "zathura.h"
#include <girara/settings.h>
#include <girara/session.h>
#include <girara/shortcuts.h>
#include <girara/config.h>
#include <girara/commands.h>
void
config_load_default(zathura_t* zathura)
{
if (!zathura || !zathura->ui.session) {
if (zathura == NULL || zathura->ui.session == NULL) {
return;
}
int int_value = 0;
float float_value = 0;
char* string_value = NULL;
bool bool_value = false;
girara_session_t* gsession = zathura->ui.session;
/* mode settings */
@ -33,90 +41,126 @@ config_load_default(zathura_t* zathura)
/* zathura settings */
int_value = 10;
girara_setting_add(gsession, "zoom-step", &int_value, INT, false, "Zoom step", NULL, NULL);
girara_setting_add(gsession, "zoom-step", &int_value, INT, false, "Zoom step", NULL, NULL);
int_value = 1;
girara_setting_add(gsession, "page-padding", &int_value, INT, true, "Padding between pages", NULL, NULL);
int_value = 2;
girara_setting_add(gsession, "pages-per-row", &int_value, INT, false, "Number of pages per row", cb_pages_per_row_value_changed, zathura);
girara_setting_add(gsession, "page-padding", &int_value, INT, true, "Padding between pages", NULL, NULL);
int_value = 1;
girara_setting_add(gsession, "pages-per-row", &int_value, INT, false, "Number of pages per row", cb_pages_per_row_value_changed, zathura);
float_value = 40;
girara_setting_add(gsession, "scroll-step", &float_value, FLOAT, false, "Scroll step", NULL, NULL);
string_value = "#FFFFFF";
girara_setting_add(gsession, "recolor-dark-color", string_value, STRING, false, "Recoloring (dark color)", NULL, NULL);
girara_setting_add(gsession, "recolor-darkcolor", string_value, STRING, false, "Recoloring (dark color)", NULL, NULL);
string_value = "#000000";
girara_setting_add(gsession, "recolor-light-color", string_value, STRING, false, "Recoloring (light color)", NULL, NULL);
girara_setting_add(gsession, "recolor-lightcolor", string_value, STRING, false, "Recoloring (light color)", NULL, NULL);
string_value = "#9FBC00";
girara_setting_add(gsession, "highlight-color", string_value, STRING, false, "Color for highlighting", NULL, NULL);
float_value = 0.5;
girara_setting_add(gsession, "highlight-transparency", &float_value, FLOAT, false, "Transparency for highlighting", NULL, NULL);
bool_value = true;
girara_setting_add(gsession, "render-loading", &bool_value, BOOLEAN, false, "Render 'Loading ...'", NULL, NULL);
int_value = ADJUST_BESTFIT;
girara_setting_add(gsession, "adjust-open", &int_value, INT, false, "Adjust to when opening file", NULL, NULL);
/* define default shortcuts */
girara_shortcut_add(gsession, GDK_CONTROL_MASK, GDK_c, NULL, sc_abort, 0, 0, NULL);
girara_shortcut_add(gsession, 0, GDK_Escape, NULL, sc_abort, 0, 0, NULL);
girara_shortcut_add(gsession, 0, GDK_a, NULL, sc_adjust_window, NORMAL, ADJUST_BESTFIT, NULL);
girara_shortcut_add(gsession, 0, GDK_s, NULL, sc_adjust_window, NORMAL, ADJUST_WIDTH, NULL);
girara_shortcut_add(gsession, 0, GDK_i, NULL, sc_change_mode, NORMAL, INSERT, NULL);
girara_shortcut_add(gsession, 0, GDK_m, NULL, sc_change_mode, NORMAL, ADD_MARKER, NULL);
girara_shortcut_add(gsession, 0, GDK_apostrophe, NULL, sc_change_mode, NORMAL, EVAL_MARKER, NULL);
girara_shortcut_add(gsession, 0, GDK_slash, NULL, girara_sc_focus_inputbar, NORMAL, 0, &("/"));
girara_shortcut_add(gsession, GDK_SHIFT_MASK, GDK_slash, NULL, girara_sc_focus_inputbar, NORMAL, 0, &("/"));
girara_shortcut_add(gsession, 0, GDK_question, NULL, girara_sc_focus_inputbar, NORMAL, 0, &("?"));
girara_shortcut_add(gsession, 0, GDK_colon, NULL, girara_sc_focus_inputbar, NORMAL, 0, &(":"));
girara_shortcut_add(gsession, 0, GDK_o, NULL, girara_sc_focus_inputbar, NORMAL, 0, &(":open "));
girara_shortcut_add(gsession, 0, GDK_O, NULL, girara_sc_focus_inputbar, NORMAL, APPEND_FILEPATH, &(":open "));
girara_shortcut_add(gsession, 0, GDK_f, NULL, sc_follow, NORMAL, 0, NULL);
girara_shortcut_add(gsession, 0, 0, "gg", sc_goto, NORMAL | FULLSCREEN, TOP, NULL);
girara_shortcut_add(gsession, 0, 0, "G", sc_goto, NORMAL | FULLSCREEN, BOTTOM, NULL);
girara_shortcut_add(gsession, 0, GDK_J, NULL, sc_navigate, NORMAL, NEXT, NULL);
girara_shortcut_add(gsession, 0, GDK_K, NULL, sc_navigate, NORMAL, PREVIOUS, NULL);
girara_shortcut_add(gsession, GDK_MOD1_MASK, GDK_Right, NULL, sc_navigate, NORMAL, NEXT, NULL);
girara_shortcut_add(gsession, GDK_MOD1_MASK, GDK_Left, NULL, sc_navigate, NORMAL, PREVIOUS, NULL);
girara_shortcut_add(gsession, 0, GDK_Left, NULL, sc_navigate, FULLSCREEN, PREVIOUS, NULL);
girara_shortcut_add(gsession, 0, GDK_Up, NULL, sc_navigate, FULLSCREEN, PREVIOUS, NULL);
girara_shortcut_add(gsession, 0, GDK_Down, NULL, sc_navigate, FULLSCREEN, NEXT, NULL);
girara_shortcut_add(gsession, 0, GDK_Right, NULL, sc_navigate, FULLSCREEN, NEXT, NULL);
girara_shortcut_add(gsession, 0, GDK_k, NULL, sc_navigate_index, INDEX, UP, NULL);
girara_shortcut_add(gsession, 0, GDK_j, NULL, sc_navigate_index, INDEX, DOWN, NULL);
girara_shortcut_add(gsession, 0, GDK_h, NULL, sc_navigate_index, INDEX, COLLAPSE, NULL);
girara_shortcut_add(gsession, 0, GDK_l, NULL, sc_navigate_index, INDEX, EXPAND, NULL);
girara_shortcut_add(gsession, 0, GDK_space, NULL, sc_navigate_index, INDEX, SELECT, NULL);
girara_shortcut_add(gsession, 0, GDK_Return, NULL, sc_navigate_index, INDEX, SELECT, NULL);
girara_shortcut_add(gsession, GDK_CONTROL_MASK, GDK_i, NULL, sc_recolor, NORMAL, 0, NULL);
girara_shortcut_add(gsession, 0, GDK_R, NULL, sc_reload, NORMAL, 0, NULL);
girara_shortcut_add(gsession, 0, GDK_r, NULL, sc_rotate, NORMAL, 0, NULL);
girara_shortcut_add(gsession, 0, GDK_h, NULL, sc_scroll, NORMAL, LEFT, NULL);
girara_shortcut_add(gsession, 0, GDK_j, NULL, sc_scroll, NORMAL, DOWN, NULL);
girara_shortcut_add(gsession, 0, GDK_k, NULL, sc_scroll, NORMAL, UP, NULL);
girara_shortcut_add(gsession, 0, GDK_l, NULL, sc_scroll, NORMAL, RIGHT, NULL);
girara_shortcut_add(gsession, 0, GDK_Left, NULL, sc_scroll, NORMAL, LEFT, NULL);
girara_shortcut_add(gsession, 0, GDK_Up, NULL, sc_scroll, NORMAL, UP, NULL);
girara_shortcut_add(gsession, 0, GDK_Down, NULL, sc_scroll, NORMAL, DOWN, NULL);
girara_shortcut_add(gsession, 0, GDK_Right, NULL, sc_scroll, NORMAL, RIGHT, NULL);
girara_shortcut_add(gsession, GDK_CONTROL_MASK, GDK_d, NULL, sc_scroll, NORMAL, HALF_DOWN, NULL);
girara_shortcut_add(gsession, GDK_CONTROL_MASK, GDK_u, NULL, sc_scroll, NORMAL, HALF_UP, NULL);
girara_shortcut_add(gsession, GDK_CONTROL_MASK, GDK_f, NULL, sc_scroll, NORMAL, FULL_DOWN, NULL);
girara_shortcut_add(gsession, GDK_CONTROL_MASK, GDK_b, NULL, sc_scroll, NORMAL, FULL_UP, NULL);
girara_shortcut_add(gsession, 0, GDK_space, NULL, sc_scroll, NORMAL, FULL_DOWN, NULL);
girara_shortcut_add(gsession, GDK_SHIFT_MASK, GDK_space, NULL, sc_scroll, NORMAL, FULL_UP, NULL);
girara_shortcut_add(gsession, 0, GDK_n, NULL, sc_search, NORMAL, FORWARD, NULL);
girara_shortcut_add(gsession, 0, GDK_N, NULL, sc_search, NORMAL, BACKWARD, NULL);
girara_shortcut_add(gsession, 0, GDK_Tab, NULL, sc_toggle_index, NORMAL | INDEX, 0, NULL);
girara_shortcut_add(gsession, GDK_CONTROL_MASK, GDK_m, NULL, girara_sc_toggle_inputbar, NORMAL, 0, NULL);
girara_shortcut_add(gsession, 0, GDK_F5, NULL, sc_toggle_fullscreen, NORMAL | FULLSCREEN, 0, NULL);
girara_shortcut_add(gsession, GDK_CONTROL_MASK, GDK_n, NULL, girara_sc_toggle_statusbar, NORMAL, 0, NULL);
girara_shortcut_add(gsession, 0, GDK_q, NULL, sc_quit, NORMAL, 0, NULL);
girara_shortcut_add(gsession, 0, GDK_plus, NULL, sc_zoom, NORMAL | FULLSCREEN, ZOOM_IN, NULL);
girara_shortcut_add(gsession, 0, GDK_minus, NULL, sc_zoom, NORMAL | FULLSCREEN, ZOOM_OUT, NULL);
girara_shortcut_add(gsession, 0, GDK_equal, NULL, sc_zoom, NORMAL | FULLSCREEN, ZOOM_ORIGINAL, NULL);
girara_shortcut_add(gsession, 0, 0, "zI", sc_zoom, NORMAL | FULLSCREEN, ZOOM_IN, NULL);
girara_shortcut_add(gsession, 0, 0, "zO", sc_zoom, NORMAL | FULLSCREEN, ZOOM_OUT, NULL);
girara_shortcut_add(gsession, 0, 0, "z0", sc_zoom, NORMAL | FULLSCREEN, ZOOM_ORIGINAL, NULL);
girara_shortcut_add(gsession, GDK_CONTROL_MASK, GDK_c, NULL, sc_abort, 0, 0, NULL);
girara_shortcut_add(gsession, 0, GDK_Escape, NULL, sc_abort, 0, 0, NULL);
girara_shortcut_add(gsession, 0, GDK_a, NULL, sc_adjust_window, NORMAL, ADJUST_BESTFIT, NULL);
girara_shortcut_add(gsession, 0, GDK_s, NULL, sc_adjust_window, NORMAL, ADJUST_WIDTH, NULL);
girara_shortcut_add(gsession, 0, GDK_i, NULL, sc_change_mode, NORMAL, INSERT, NULL);
girara_shortcut_add(gsession, 0, GDK_m, NULL, sc_change_mode, NORMAL, ADD_MARKER, NULL);
girara_shortcut_add(gsession, 0, GDK_apostrophe, NULL, sc_change_mode, NORMAL, EVAL_MARKER, NULL);
girara_shortcut_add(gsession, 0, GDK_slash, NULL, girara_sc_focus_inputbar, NORMAL, 0, &("/"));
girara_shortcut_add(gsession, GDK_SHIFT_MASK, GDK_slash, NULL, girara_sc_focus_inputbar, NORMAL, 0, &("/"));
girara_shortcut_add(gsession, 0, GDK_question, NULL, girara_sc_focus_inputbar, NORMAL, 0, &("?"));
girara_shortcut_add(gsession, 0, GDK_colon, NULL, girara_sc_focus_inputbar, NORMAL, 0, &(":"));
girara_shortcut_add(gsession, 0, GDK_o, NULL, girara_sc_focus_inputbar, NORMAL, 0, &(":open "));
girara_shortcut_add(gsession, 0, GDK_O, NULL, girara_sc_focus_inputbar, NORMAL, APPEND_FILEPATH, &(":open "));
girara_shortcut_add(gsession, 0, GDK_f, NULL, sc_follow, NORMAL, 0, NULL);
girara_shortcut_add(gsession, 0, 0, "gg", sc_goto, NORMAL, TOP, NULL);
girara_shortcut_add(gsession, 0, 0, "gg", sc_goto, FULLSCREEN, TOP, NULL);
girara_shortcut_add(gsession, 0, 0, "G", sc_goto, NORMAL, BOTTOM, NULL);
girara_shortcut_add(gsession, 0, 0, "G", sc_goto, FULLSCREEN, BOTTOM, NULL);
girara_shortcut_add(gsession, 0, GDK_J, NULL, sc_navigate, NORMAL, NEXT, NULL);
girara_shortcut_add(gsession, 0, GDK_K, NULL, sc_navigate, NORMAL, PREVIOUS, NULL);
girara_shortcut_add(gsession, GDK_MOD1_MASK, GDK_Right, NULL, sc_navigate, NORMAL, NEXT, NULL);
girara_shortcut_add(gsession, GDK_MOD1_MASK, GDK_Left, NULL, sc_navigate, NORMAL, PREVIOUS, NULL);
girara_shortcut_add(gsession, 0, GDK_Left, NULL, sc_navigate, FULLSCREEN, PREVIOUS, NULL);
girara_shortcut_add(gsession, 0, GDK_Up, NULL, sc_navigate, FULLSCREEN, PREVIOUS, NULL);
girara_shortcut_add(gsession, 0, GDK_Down, NULL, sc_navigate, FULLSCREEN, NEXT, NULL);
girara_shortcut_add(gsession, 0, GDK_Right, NULL, sc_navigate, FULLSCREEN, NEXT, NULL);
girara_shortcut_add(gsession, 0, GDK_k, NULL, sc_navigate_index, INDEX, UP, NULL);
girara_shortcut_add(gsession, 0, GDK_j, NULL, sc_navigate_index, INDEX, DOWN, NULL);
girara_shortcut_add(gsession, 0, GDK_h, NULL, sc_navigate_index, INDEX, COLLAPSE, NULL);
girara_shortcut_add(gsession, 0, GDK_l, NULL, sc_navigate_index, INDEX, EXPAND, NULL);
girara_shortcut_add(gsession, 0, GDK_space, NULL, sc_navigate_index, INDEX, SELECT, NULL);
girara_shortcut_add(gsession, 0, GDK_Return, NULL, sc_navigate_index, INDEX, SELECT, NULL);
girara_shortcut_add(gsession, GDK_CONTROL_MASK, GDK_i, NULL, sc_recolor, NORMAL, 0, NULL);
girara_shortcut_add(gsession, 0, GDK_R, NULL, sc_reload, NORMAL, 0, NULL);
girara_shortcut_add(gsession, 0, GDK_r, NULL, sc_rotate, NORMAL, 0, NULL);
girara_shortcut_add(gsession, 0, GDK_h, NULL, sc_scroll, NORMAL, LEFT, NULL);
girara_shortcut_add(gsession, 0, GDK_j, NULL, sc_scroll, NORMAL, DOWN, NULL);
girara_shortcut_add(gsession, 0, GDK_k, NULL, sc_scroll, NORMAL, UP, NULL);
girara_shortcut_add(gsession, 0, GDK_l, NULL, sc_scroll, NORMAL, RIGHT, NULL);
girara_shortcut_add(gsession, 0, GDK_Left, NULL, sc_scroll, NORMAL, LEFT, NULL);
girara_shortcut_add(gsession, 0, GDK_Up, NULL, sc_scroll, NORMAL, UP, NULL);
girara_shortcut_add(gsession, 0, GDK_Down, NULL, sc_scroll, NORMAL, DOWN, NULL);
girara_shortcut_add(gsession, 0, GDK_Right, NULL, sc_scroll, NORMAL, RIGHT, NULL);
girara_shortcut_add(gsession, GDK_CONTROL_MASK, GDK_d, NULL, sc_scroll, NORMAL, HALF_DOWN, NULL);
girara_shortcut_add(gsession, GDK_CONTROL_MASK, GDK_u, NULL, sc_scroll, NORMAL, HALF_UP, NULL);
girara_shortcut_add(gsession, GDK_CONTROL_MASK, GDK_f, NULL, sc_scroll, NORMAL, FULL_DOWN, NULL);
girara_shortcut_add(gsession, GDK_CONTROL_MASK, GDK_b, NULL, sc_scroll, NORMAL, FULL_UP, NULL);
girara_shortcut_add(gsession, 0, GDK_space, NULL, sc_scroll, NORMAL, FULL_DOWN, NULL);
girara_shortcut_add(gsession, GDK_SHIFT_MASK, GDK_space, NULL, sc_scroll, NORMAL, FULL_UP, NULL);
girara_shortcut_add(gsession, 0, GDK_n, NULL, sc_search, NORMAL, FORWARD, NULL);
girara_shortcut_add(gsession, 0, GDK_N, NULL, sc_search, NORMAL, BACKWARD, NULL);
girara_shortcut_add(gsession, 0, GDK_Tab, NULL, sc_toggle_index, NORMAL, 0, NULL);
girara_shortcut_add(gsession, 0, GDK_Tab, NULL, sc_toggle_index, INDEX, 0, NULL);
girara_shortcut_add(gsession, GDK_CONTROL_MASK, GDK_m, NULL, girara_sc_toggle_inputbar, NORMAL, 0, NULL);
girara_shortcut_add(gsession, 0, GDK_F5, NULL, sc_toggle_fullscreen, NORMAL, 0, NULL);
girara_shortcut_add(gsession, 0, GDK_F5, NULL, sc_toggle_fullscreen, FULLSCREEN, 0, NULL);
girara_shortcut_add(gsession, GDK_CONTROL_MASK, GDK_n, NULL, girara_sc_toggle_statusbar, NORMAL, 0, NULL);
girara_shortcut_add(gsession, 0, GDK_q, NULL, sc_quit, NORMAL, 0, NULL);
girara_shortcut_add(gsession, 0, GDK_plus, NULL, sc_zoom, NORMAL, ZOOM_IN, NULL);
girara_shortcut_add(gsession, 0, GDK_plus, NULL, sc_zoom, FULLSCREEN, ZOOM_IN, NULL);
girara_shortcut_add(gsession, 0, GDK_minus, NULL, sc_zoom, NORMAL, ZOOM_OUT, NULL);
girara_shortcut_add(gsession, 0, GDK_minus, NULL, sc_zoom, FULLSCREEN, ZOOM_OUT, NULL);
girara_shortcut_add(gsession, 0, GDK_equal, NULL, sc_zoom, NORMAL, ZOOM_ORIGINAL, NULL);
girara_shortcut_add(gsession, 0, GDK_equal, NULL, sc_zoom, FULLSCREEN, ZOOM_ORIGINAL, NULL);
girara_shortcut_add(gsession, 0, 0, "zI", sc_zoom, NORMAL, ZOOM_IN, NULL);
girara_shortcut_add(gsession, 0, 0, "zI", sc_zoom, FULLSCREEN, ZOOM_IN, NULL);
girara_shortcut_add(gsession, 0, 0, "zO", sc_zoom, NORMAL, ZOOM_OUT, NULL);
girara_shortcut_add(gsession, 0, 0, "zO", sc_zoom, FULLSCREEN, ZOOM_OUT, NULL);
girara_shortcut_add(gsession, 0, 0, "z0", sc_zoom, NORMAL, ZOOM_ORIGINAL, NULL);
girara_shortcut_add(gsession, 0, 0, "z0", sc_zoom, FULLSCREEN, ZOOM_ORIGINAL, NULL);
girara_shortcut_add(gsession, 0, GDK_equal, NULL, sc_zoom, NORMAL, ZOOM_SPECIFIC, NULL);
girara_shortcut_add(gsession, 0, GDK_equal, NULL, sc_zoom, FULLSCREEN, ZOOM_SPECIFIC, NULL);
/* mouse events */
girara_mouse_event_add(gsession, 0, 0, sc_mouse_scroll, NORMAL, GIRARA_EVENT_SCROLL, 0, NULL);
girara_mouse_event_add(gsession, 0, 0, sc_mouse_scroll, FULLSCREEN, GIRARA_EVENT_SCROLL, 0, NULL);
girara_mouse_event_add(gsession, GDK_CONTROL_MASK, 0, sc_mouse_zoom, NORMAL, GIRARA_EVENT_SCROLL, 0, NULL);
girara_mouse_event_add(gsession, GDK_CONTROL_MASK, 0, sc_mouse_zoom, FULLSCREEN, GIRARA_EVENT_SCROLL, 0, NULL);
girara_mouse_event_add(gsession, 0, GIRARA_MOUSE_BUTTON2, sc_mouse_scroll, NORMAL, GIRARA_EVENT_BUTTON_PRESS, 0, NULL);
girara_mouse_event_add(gsession, GDK_BUTTON2_MASK, GIRARA_MOUSE_BUTTON2, sc_mouse_scroll, NORMAL, GIRARA_EVENT_BUTTON_RELEASE, 0, NULL);
girara_mouse_event_add(gsession, GDK_BUTTON2_MASK, 0, sc_mouse_scroll, NORMAL, GIRARA_EVENT_MOTION_NOTIFY, 0, NULL);
/* define default inputbar commands */
girara_inputbar_command_add(gsession, "bmark", NULL, cmd_bookmark_create, NULL, "Add a bookmark");
girara_inputbar_command_add(gsession, "bdelete", NULL, cmd_bookmark_delete, NULL, "Delete a bookmark");
girara_inputbar_command_add(gsession, "blist", NULL, cmd_bookmark_open, NULL, "List all bookmarks");
girara_inputbar_command_add(gsession, "close", NULL, cmd_close, NULL, "Close current file");
girara_inputbar_command_add(gsession, "info", NULL, cmd_info, NULL, "Show file information");
girara_inputbar_command_add(gsession, "help", NULL, cmd_help, NULL, "Show help");
girara_inputbar_command_add(gsession, "open", "o", cmd_open, cc_open, "Open document");
girara_inputbar_command_add(gsession, "print", NULL, cmd_print, NULL, "Print document");
girara_inputbar_command_add(gsession, "write", NULL, cmd_save, NULL, "Save document");
girara_inputbar_command_add(gsession, "write!", NULL, cmd_savef, NULL, "Save document (and force overwriting)");
girara_inputbar_command_add(gsession, "bmark", NULL, cmd_bookmark_create, NULL, "Add a bookmark");
girara_inputbar_command_add(gsession, "bdelete", NULL, cmd_bookmark_delete, cc_bookmarks, "Delete a bookmark");
girara_inputbar_command_add(gsession, "blist", NULL, cmd_bookmark_open, cc_bookmarks, "List all bookmarks");
girara_inputbar_command_add(gsession, "close", NULL, cmd_close, NULL, "Close current file");
girara_inputbar_command_add(gsession, "info", NULL, cmd_info, NULL, "Show file information");
girara_inputbar_command_add(gsession, "help", NULL, cmd_help, NULL, "Show help");
girara_inputbar_command_add(gsession, "open", "o", cmd_open, cc_open, "Open document");
girara_inputbar_command_add(gsession, "print", NULL, cmd_print, NULL, "Print document");
girara_inputbar_command_add(gsession, "write", NULL, cmd_save, NULL, "Save document");
girara_inputbar_command_add(gsession, "write!", NULL, cmd_savef, NULL, "Save document (and force overwriting)");
girara_inputbar_command_add(gsession, "export", NULL, cmd_export, cc_export, "Save attachments");
girara_special_command_add(gsession, '/', cmd_search, true, FORWARD, NULL);
girara_special_command_add(gsession, '?', cmd_search, true, BACKWARD, NULL);
/* add shortcut mappings */
girara_shortcut_mapping_add(gsession, "abort", sc_abort);
@ -137,6 +181,26 @@ config_load_default(zathura_t* zathura)
girara_shortcut_mapping_add(gsession, "toggle_inputbar", girara_sc_toggle_inputbar);
girara_shortcut_mapping_add(gsession, "toggle_statusbar", girara_sc_toggle_statusbar);
girara_shortcut_mapping_add(gsession, "zoom", sc_zoom);
/* add argument mappings */
girara_argument_mapping_add(gsession, "bottom", BOTTOM);
girara_argument_mapping_add(gsession, "default", DEFAULT);
girara_argument_mapping_add(gsession, "down", DOWN);
girara_argument_mapping_add(gsession, "full-down", FULL_DOWN);
girara_argument_mapping_add(gsession, "full-up", FULL_UP);
girara_argument_mapping_add(gsession, "half-down", HALF_DOWN);
girara_argument_mapping_add(gsession, "half-up", HALF_UP);
girara_argument_mapping_add(gsession, "in", ZOOM_IN);
girara_argument_mapping_add(gsession, "left", LEFT);
girara_argument_mapping_add(gsession, "next", NEXT);
girara_argument_mapping_add(gsession, "out", ZOOM_OUT);
girara_argument_mapping_add(gsession, "previous", PREVIOUS);
girara_argument_mapping_add(gsession, "right", RIGHT);
girara_argument_mapping_add(gsession, "specific", ZOOM_SPECIFIC);
girara_argument_mapping_add(gsession, "top", TOP);
girara_argument_mapping_add(gsession, "up", UP);
girara_argument_mapping_add(gsession, "best-fit", ADJUST_BESTFIT);
girara_argument_mapping_add(gsession, "width", ADJUST_WIDTH);
}
void

View file

@ -11,13 +11,14 @@
/**
* This function loads the default values of the configuration
*
* @param zathura the zathura session
* @param zathura The zathura session
*/
void config_load_default(zathura_t* zathura);
/**
* Loads and evaluates a configuration file
*
* @param zathura The zathura session
* @param path Path to the configuration file
*/
void config_load_file(zathura_t* zathura, char* path);

View file

@ -6,6 +6,9 @@ VERSION = 0.0.8.1
# paths
PREFIX ?= /usr
MANPREFIX ?= ${PREFIX}/share/man
DESKTOPPREFIX ?= ${PREFIX}/share/applications
# list of : seperated values
PLUGINDIR ?= ${PREFIX}/lib/zathura
# libs
@ -19,13 +22,15 @@ GIRARA_LIB ?= $(shell pkg-config --libs girara-gtk2)
SQLITE_INC ?= $(shell pkg-config --cflags sqlite3)
SQLITE_LIB ?= $(shell pkg-config --libs sqlite3)
#set it to an empty value if you don't need to link against ld for dlopen and friends
DL_LIB ?= -ldl
INCS = ${GIRARA_INC} ${GTK_INC} $(SQLITE_INC)
LIBS = ${GIRARA_LIB} ${GTK_LIB} $(SQLITE_LIB) $(DL_LIB) -lpthread -lm
INCS = ${GIRARA_INC} ${GTK_INC}
LIBS = ${GIRARA_LIB} ${GTK_LIB} $(DL_LIB) -lpthread -lm
# flags
CFLAGS += -std=c99 -pedantic -Wall -Wno-format-zero-length -Wextra $(INCS)
CPPFLAGS += -DZATHURA_PLUGINDIR=\"${PLUGINDIR}\"
# debug
DFLAGS ?= -g
@ -41,3 +46,7 @@ SFLAGS ?= -s
# set to something != 0 if you want verbose build output
VERBOSE ?= 0
# database
# possible values are sqlite and plain
DATABASE ?= plain

403
database-plain.c Normal file
View file

@ -0,0 +1,403 @@
/* See LICENSE file for license and copyright information */
#define _POSIX_SOURCE
#include <glib.h>
#include <stdlib.h>
#include <string.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <girara/utils.h>
#include <girara/datastructures.h>
#include "database.h"
#define BOOKMARKS "bookmarks"
#define HISTORY "history"
#define KEY_PAGE "page"
#define KEY_OFFSET "offset"
#define KEY_SCALE "scale"
#define KEY_ROTATE "rotate"
#define file_lock_set(fd, cmd) \
{ \
struct flock lock = { .l_type = cmd, .l_start = 0, .l_whence = SEEK_SET, .l_len = 0}; \
fcntl(fd, F_SETLK, lock); \
}
/* forward declaration */
static bool zathura_db_check_file(const char* path);
static GKeyFile* zathura_db_read_key_file_from_file(const char* path);
static void zathura_db_write_key_file_to_file(const char* file, GKeyFile* key_file);
static void cb_zathura_db_watch_file(GFileMonitor* monitor, GFile* file, GFile*
other_file, GFileMonitorEvent event, zathura_database_t* database);
struct zathura_database_s
{
char* bookmark_path;
GKeyFile* bookmarks;
GFileMonitor* bookmark_monitor;
char* history_path;
GKeyFile* history;
GFileMonitor* history_monitor;
};
zathura_database_t*
zathura_db_init(const char* dir)
{
if (dir == NULL) {
goto error_ret;
}
zathura_database_t* db = calloc(1, sizeof(zathura_database_t));
if (db == NULL) {
goto error_ret;
}
/* bookmarks */
db->bookmark_path = g_build_filename(dir, BOOKMARKS, NULL);
if (db->bookmark_path == NULL ||
zathura_db_check_file(db->bookmark_path) == false) {
goto error_free;
}
GFile* bookmark_file = g_file_new_for_path(db->bookmark_path);
if (bookmark_file != NULL) {
db->bookmark_monitor = g_file_monitor(bookmark_file, G_FILE_MONITOR_NONE, NULL, NULL);
} else {
goto error_free;
}
g_object_unref(bookmark_file);
g_signal_connect(
G_OBJECT(db->bookmark_monitor),
"changed",
G_CALLBACK(cb_zathura_db_watch_file),
db
);
db->bookmarks = zathura_db_read_key_file_from_file(db->bookmark_path);
if (db->bookmarks == NULL) {
goto error_free;
}
/* history */
db->history_path = g_build_filename(dir, HISTORY, NULL);
if (db->history_path == NULL ||
zathura_db_check_file(db->history_path) == false) {
goto error_free;
}
GFile* history_file = g_file_new_for_path(db->history_path);
if (history_file != NULL) {
db->history_monitor = g_file_monitor(history_file, G_FILE_MONITOR_NONE, NULL, NULL);
} else {
goto error_free;
}
g_object_unref(history_file);
g_signal_connect(
G_OBJECT(db->history_monitor),
"changed",
G_CALLBACK(cb_zathura_db_watch_file),
db
);
db->history = zathura_db_read_key_file_from_file(db->history_path);
if (db->history == NULL) {
goto error_free;
}
return db;
error_free:
zathura_db_free(db);
error_ret:
return NULL;
}
void
zathura_db_free(zathura_database_t* db)
{
if (db == NULL) {
return;
}
/* bookmarks */
g_free(db->bookmark_path);
if (db->bookmark_monitor != NULL) {
g_object_unref(db->bookmark_monitor);
}
if (db->bookmarks != NULL) {
g_key_file_free(db->bookmarks);
}
/* history */
g_free(db->history_path);
if (db->history_monitor != NULL) {
g_object_unref(db->history_monitor);
}
/* database */
free(db);
}
bool
zathura_db_add_bookmark(zathura_database_t* db, const char* file,
zathura_bookmark_t* bookmark)
{
if (db == NULL || db->bookmarks == NULL || db->bookmark_path == NULL || file
== NULL || bookmark == NULL || bookmark->id == NULL) {
return false;
}
g_key_file_set_integer(db->bookmarks, file, bookmark->id, bookmark->page);
zathura_db_write_key_file_to_file(db->bookmark_path, db->bookmarks);
return true;
}
bool
zathura_db_remove_bookmark(zathura_database_t* db, const char* file, const char*
id)
{
if (db == NULL || db->bookmarks == NULL || db->bookmark_path == NULL || file
== NULL || id == NULL) {
return false;
}
if (g_key_file_has_group(db->bookmarks, file) == TRUE) {
g_key_file_remove_group(db->bookmarks, file, NULL);
zathura_db_write_key_file_to_file(db->bookmark_path, db->bookmarks);
return true;
}
return false;
}
girara_list_t*
zathura_db_load_bookmarks(zathura_database_t* db, const char* file)
{
if (db == NULL || db->bookmarks == NULL || file == NULL) {
return NULL;
}
if (g_key_file_has_group(db->bookmarks, file) == FALSE) {
return NULL;
}
girara_list_t* result = girara_sorted_list_new2((girara_compare_function_t) zathura_bookmarks_compare,
(girara_free_function_t) zathura_bookmark_free);
if (result == NULL) {
return NULL;
}
girara_list_set_free_function(result, (girara_free_function_t) zathura_bookmark_free);
gsize length;
char** keys = g_key_file_get_keys(db->bookmarks, file, &length, NULL);
if (keys == NULL) {
girara_list_free(result);
return NULL;
}
for (gsize i = 0; i < length; i++) {
zathura_bookmark_t* bookmark = g_malloc0(sizeof(zathura_bookmark_t));
bookmark->id = g_strdup(keys[i]);
bookmark->page = g_key_file_get_integer(db->bookmarks, file, keys[i], NULL);
girara_list_append(result, bookmark);
}
return result;
}
bool
zathura_db_set_fileinfo(zathura_database_t* db, const char* file, unsigned int
page, int offset, double scale, int rotation)
{
if (db == NULL || db->history == NULL || file == NULL) {
return false;
}
char* tmp = g_strdup_printf("%f", scale);
if (tmp == NULL) {
return false;
}
g_key_file_set_integer(db->history, file, KEY_PAGE, page);
g_key_file_set_integer(db->history, file, KEY_OFFSET, offset);
g_key_file_set_string (db->history, file, KEY_SCALE, tmp);
g_key_file_set_integer(db->history, file, KEY_ROTATE, rotation);
g_free(tmp);
zathura_db_write_key_file_to_file(db->history_path, db->history);
return true;
}
bool
zathura_db_get_fileinfo(zathura_database_t* db, const char* file, unsigned int*
page, int* offset, double* scale, int* rotation)
{
if (db == NULL || db->history == NULL || file == NULL || page == NULL ||
offset == NULL || scale == NULL || rotation == NULL) {
return false;
}
if (g_key_file_has_group(db->history, file) == FALSE) {
return false;
}
*page = g_key_file_get_integer(db->history, file, KEY_PAGE, NULL);
*offset = g_key_file_get_integer(db->history, file, KEY_OFFSET, NULL);
*scale = strtod(g_key_file_get_string(db->history, file, KEY_SCALE, NULL), NULL);
*rotation = g_key_file_get_integer(db->history, file, KEY_ROTATE, NULL);
return true;
}
static bool
zathura_db_check_file(const char* path)
{
if (path == NULL) {
return false;
}
if (g_file_test(path, G_FILE_TEST_EXISTS) == false) {
FILE* file = fopen(path, "w");
if (file != NULL) {
fclose(file);
} else {
return false;
}
} else if (g_file_test(path, G_FILE_TEST_IS_REGULAR) == false) {
return false;
}
return true;
}
static GKeyFile*
zathura_db_read_key_file_from_file(const char* path)
{
if (path == NULL) {
return NULL;
}
/* open file */
FILE* file = fopen(path, "r");
if (file == NULL) {
return NULL;
}
GKeyFile* key_file = g_key_file_new();
if (key_file == NULL) {
fclose(file);
return NULL;
}
/* read config file */
file_lock_set(fileno(file), F_WRLCK);
char* content = girara_file_read2(file);
file_lock_set(fileno(file), F_UNLCK);
fclose(file);
if (content == NULL) {
g_key_file_free(key_file);
return NULL;
}
/* parse config file */
size_t contentlen = strlen(content);
if (contentlen == 0) {
static const char dummy_content[] = "# nothing";
static const size_t dummy_len = sizeof(dummy_content) - 1;
free(content);
content = malloc(sizeof(char) * (dummy_len + 1));
content = memcpy(content, dummy_content, dummy_len + 1);
contentlen = dummy_len;
}
GError* error = NULL;
if (g_key_file_load_from_data(key_file, content, contentlen,
G_KEY_FILE_KEEP_COMMENTS | G_KEY_FILE_KEEP_TRANSLATIONS, &error) ==
FALSE) {
if (error->code != 1) /* ignore empty file */ {
free(content);
g_key_file_free(key_file);
g_error_free(error);
return NULL;
}
g_error_free(error);
}
free(content);
return key_file;
}
static void
zathura_db_write_key_file_to_file(const char* file, GKeyFile* key_file)
{
if (file == NULL || key_file == NULL) {
return;
}
gchar* content = g_key_file_to_data(key_file, NULL, NULL);
if (content == NULL) {
return;
}
/* open file */
int fd = open(file, O_RDWR);
if (fd == -1) {
g_free(content);
return;
}
file_lock_set(fd, F_WRLCK);
if (write(fd, content, strlen(content)) == 0) {
girara_error("Failed to write to %s", file);
}
file_lock_set(fd, F_UNLCK);
close(fd);
g_free(content);
}
static void
cb_zathura_db_watch_file(GFileMonitor* UNUSED(monitor), GFile* file, GFile* UNUSED(other_file),
GFileMonitorEvent event, zathura_database_t* database)
{
if (event != G_FILE_MONITOR_EVENT_CHANGES_DONE_HINT || database == NULL) {
return;
}
char* path = g_file_get_path(file);
if (path == NULL) {
return;
}
if (database->bookmark_path && strcmp(database->bookmark_path, path) == 0) {
database->bookmarks = zathura_db_read_key_file_from_file(database->bookmark_path);
} else if (database->history_path && strcmp(database->history_path, path) == 0) {
database->history = zathura_db_read_key_file_from_file(database->history_path);
}
}

View file

@ -2,18 +2,30 @@
#include <glib.h>
#include <sqlite3.h>
#include <girara.h>
#include <girara/utils.h>
#include <girara/datastructures.h>
#include "database.h"
#define DATABASE "bookmarks.sqlite"
struct zathura_database_s
{
sqlite3* session;
};
zathura_database_t*
zathura_db_init(const char* path)
zathura_db_init(const char* dir)
{
if (dir == NULL) {
return NULL;
}
char* path = g_build_filename(dir, DATABASE, NULL);
if (path == NULL) {
return NULL;
}
zathura_database_t* db = g_malloc0(sizeof(zathura_database_t));
/* create bookmarks database */
@ -29,27 +41,32 @@ zathura_db_init(const char* path)
"file TEXT PRIMARY KEY,"
"page INTEGER,"
"offset INTEGER,"
"scale FLOAT);";
"scale FLOAT,"
"rotation INTEGER);";
if (sqlite3_open(path, &(db->session)) != SQLITE_OK) {
girara_error("Could not open database: %s\n", path);
zathura_db_free(db);
return NULL;
goto error_free;
}
if (sqlite3_exec(db->session, SQL_BOOKMARK_INIT, NULL, 0, NULL) != SQLITE_OK) {
girara_error("Failed to initialize database: %s\n", path);
zathura_db_free(db);
return NULL;
goto error_free;
}
if (sqlite3_exec(db->session, SQL_FILEINFO_INIT, NULL, 0, NULL) != SQLITE_OK) {
girara_error("Failed to initialize database: %s\n", path);
zathura_db_free(db);
return NULL;
goto error_free;
}
return db;
error_free:
zathura_db_free(db);
g_free(path);
return NULL;
}
void
@ -59,7 +76,10 @@ zathura_db_free(zathura_database_t* db)
return;
}
sqlite3_close(db->session);
if (db->session != NULL) {
sqlite3_close(db->session);
}
g_free(db);
}
@ -73,7 +93,7 @@ prepare_statement(sqlite3* session, const char* statement)
const char* pz_tail = NULL;
sqlite3_stmt* pp_stmt = NULL;
if (sqlite3_prepare(session, statement, -1, &pp_stmt, &pz_tail) != SQLITE_OK) {
if (sqlite3_prepare_v2(session, statement, -1, &pp_stmt, &pz_tail) != SQLITE_OK) {
girara_error("Failed to prepare query: %s", statement);
sqlite3_finalize(pp_stmt);
return NULL;
@ -87,7 +107,8 @@ prepare_statement(sqlite3* session, const char* statement)
}
bool
zathura_db_add_bookmark(zathura_database_t* db, const char* file, zathura_bookmark_t* bookmark)
zathura_db_add_bookmark(zathura_database_t* db, const char* file,
zathura_bookmark_t* bookmark)
{
g_return_val_if_fail(db && file && bookmark, false);
@ -109,16 +130,17 @@ zathura_db_add_bookmark(zathura_database_t* db, const char* file, zathura_bookma
int res = sqlite3_step(stmt);
sqlite3_finalize(stmt);
return res == SQLITE_OK;
return res == SQLITE_DONE;
}
bool
zathura_db_remove_bookmark(zathura_database_t* db, const char* file, const char* id)
zathura_db_remove_bookmark(zathura_database_t* db, const char* file, const char*
id)
{
g_return_val_if_fail(db && file && id, false);
static const char SQL_BOOKMARK_ADD[] =
"DELETE FROM bookmarks WHERE file = ? && id = ?;";
"DELETE FROM bookmarks WHERE file = ? AND id = ?;";
sqlite3_stmt* stmt = prepare_statement(db->session, SQL_BOOKMARK_ADD);
if (stmt == NULL) {
@ -134,7 +156,7 @@ zathura_db_remove_bookmark(zathura_database_t* db, const char* file, const char*
int res = sqlite3_step(stmt);
sqlite3_finalize(stmt);
return res == SQLITE_OK;
return res == SQLITE_DONE;
}
girara_list_t*
@ -156,16 +178,17 @@ zathura_db_load_bookmarks(zathura_database_t* db, const char* file)
return NULL;
}
girara_list_t* result = girara_list_new();
girara_list_t* result = girara_sorted_list_new2((girara_compare_function_t) zathura_bookmarks_compare,
(girara_free_function_t) zathura_bookmark_free);
if (result == NULL) {
sqlite3_finalize(stmt);
return NULL;
}
girara_list_set_free_function(result, (girara_free_function_t) zathura_bookmark_free);
while (sqlite3_step(stmt) == SQLITE_ROW) {
zathura_bookmark_t* bookmark = g_malloc0(sizeof(zathura_bookmark_t));
bookmark->id = g_strdup((const char*) sqlite3_column_text(stmt, 0));
bookmark->id = g_strdup((const char*) sqlite3_column_text(stmt, 0));
bookmark->page = sqlite3_column_int(stmt, 1);
girara_list_append(result, bookmark);
@ -175,12 +198,13 @@ zathura_db_load_bookmarks(zathura_database_t* db, const char* file)
}
bool
zathura_db_set_fileinfo(zathura_database_t* db, const char* file, unsigned int page, int offset, float scale)
zathura_db_set_fileinfo(zathura_database_t* db, const char* file, unsigned int
page, int offset, double scale, int rotation)
{
g_return_val_if_fail(db && file, false);
static const char SQL_FILEINFO_SET[] =
"REPLACE INTO fileinfo (file, page, offset, scale) VALUES (?, ?, ?);";
"REPLACE INTO fileinfo (file, page, offset, scale, rotation) VALUES (?, ?, ?, ?, ?);";
sqlite3_stmt* stmt = prepare_statement(db->session, SQL_FILEINFO_SET);
if (stmt == NULL) {
@ -190,7 +214,8 @@ zathura_db_set_fileinfo(zathura_database_t* db, const char* file, unsigned int p
if (sqlite3_bind_text(stmt, 1, file, -1, NULL) != SQLITE_OK ||
sqlite3_bind_int(stmt, 2, page) != SQLITE_OK ||
sqlite3_bind_int(stmt, 3, offset) != SQLITE_OK ||
sqlite3_bind_double(stmt, 4, scale) != SQLITE_OK) {
sqlite3_bind_double(stmt, 4, scale) != SQLITE_OK ||
sqlite3_bind_int(stmt, 5, rotation) != SQLITE_OK) {
sqlite3_finalize(stmt);
girara_error("Failed to bind arguments.");
return false;
@ -198,16 +223,17 @@ zathura_db_set_fileinfo(zathura_database_t* db, const char* file, unsigned int p
int res = sqlite3_step(stmt);
sqlite3_finalize(stmt);
return res == SQLITE_OK;
return res == SQLITE_DONE;
}
bool
zathura_db_get_fileinfo(zathura_database_t* db, const char* file, unsigned int* page, int* offset, float* scale)
zathura_db_get_fileinfo(zathura_database_t* db, const char* file, unsigned int*
page, int* offset, double* scale, int* rotation)
{
g_return_val_if_fail(db && file && page && offset && scale, false);
g_return_val_if_fail(db && file && page && offset && scale && rotation, false);
static const char SQL_FILEINFO_GET[] =
"SELECT page, offset, scale FROM fileinfo WHERE file = ?;";
"SELECT page, offset, scale, rotation FROM fileinfo WHERE file = ?;";
sqlite3_stmt* stmt = prepare_statement(db->session, SQL_FILEINFO_GET);
if (stmt == NULL) {
@ -229,6 +255,8 @@ zathura_db_get_fileinfo(zathura_database_t* db, const char* file, unsigned int*
*page = sqlite3_column_int(stmt, 0);
*offset = sqlite3_column_int(stmt, 1);
*scale = sqlite3_column_double(stmt, 2);
*rotation = sqlite3_column_int(stmt, 3);
sqlite3_finalize(stmt);
return true;
}

View file

@ -4,69 +4,83 @@
#define DATABASE_H
#include <stdbool.h>
#include <girara.h>
#include <girara/types.h>
#include "zathura.h"
#include "bookmarks.h"
/**
* Initialize database system.
* @param path Path to the database file.
*
* @param dir Path to the directory where the database file should be located.
* @return A valid zathura_database_t instance or NULL on failure
*/
zathura_database_t* zathura_db_init(const char* path);
zathura_database_t* zathura_db_init(const char* dir);
/**
* Free database instance.
* @param The database instance to free.
*
* @param db The database instance to free.
*/
void zathura_db_free(zathura_database_t* db);
/**
* Add or update bookmark in the database.
*
* @param db The database instance
* @param file The file to which the bookmark belongs to.
* @param bookmark The bookmark instance.
* @return true on success, false otherwise
*/
bool zathura_db_add_bookmark(zathura_database_t* db, const char* file, zathura_bookmark_t* bookmark);
bool zathura_db_add_bookmark(zathura_database_t* db, const char* file,
zathura_bookmark_t* bookmark);
/**
* Add or update bookmark in the database.
*
* @param db The database instance
* @param file The file to which the bookmark belongs to.
* @param bookmark The bookmark instance.
* @param id The id of the bookmark
* @return true on success, false otherwise
*/
bool zathura_db_remove_bookmark(zathura_database_t* db, const char* file, const char* id);
bool zathura_db_remove_bookmark(zathura_database_t* db, const char* file, const
char* id);
/**
* Loads all bookmarks from the database belonging to a specific file.
*
* @param db The database instance.
* @param file The file for which the bookmarks should be loaded.
* @return List of zathura_bookmark_t* or NULL on failure.
*/
girara_list_t* zathura_db_load_bookmarks(zathura_database_t* db, const char* file);
girara_list_t* zathura_db_load_bookmarks(zathura_database_t* db, const char*
file);
/**
* Set file info (last site, ...) in the database.
*
* @param db The database instance
* @param file The file to which the file info belongs to.
* @param page The last page.
* @param offset The last offset.
* @param scale The last scale.
* @param rotation The last rotation.
* @return true on success, false otherwise.
*/
bool zathura_db_set_fileinfo(zathura_database_t* db, const char* file, unsigned int page, int offset, float scale);
bool zathura_db_set_fileinfo(zathura_database_t* db, const char* file, unsigned
int page, int offset, double scale, int rotation);
/* Get file info (last site, ...) from the database.
*
* @param db The database instance
* @param file The file to which the file info belongs to.
* @param page The last page.
* @param offset The last offset.
* @param scale The last scale.
* @param rotation The rotation.
* @return true on success, false otherwise.
*/
bool zathura_db_get_fileinfo(zathura_database_t* db, const char* file, unsigned int* page, int* offset, float* scale);
bool zathura_db_get_fileinfo(zathura_database_t* db, const char* file, unsigned
int* page, int* offset, double* scale, int* rotation);
#endif // DATABASE_H

View file

@ -6,6 +6,7 @@
#include <stdlib.h>
#include <stdio.h>
#include <unistd.h>
#include <string.h>
#include <limits.h>
#include <sys/types.h>
@ -15,36 +16,46 @@
#include <sys/stat.h>
#include <fcntl.h>
#include <errno.h>
#include <glib.h>
#include "document.h"
#include "utils.h"
#include "zathura.h"
#include "render.h"
#include "database.h"
#include "page_widget.h"
#define LENGTH(x) (sizeof(x)/sizeof((x)[0]))
#include <girara/datastructures.h>
#include <girara/utils.h>
#include <girara/statusbar.h>
#include <girara/session.h>
#include <girara/settings.h>
/**
* Register document plugin
*/
static bool zathura_document_plugin_register(zathura_t* zathura, zathura_document_plugin_t* new_plugin);
void
zathura_document_plugins_load(zathura_t* zathura)
{
girara_list_iterator_t* iter = girara_list_iterator(zathura->plugins.path);
if (iter == NULL) {
return;
}
do
{
char* plugindir = girara_list_iterator_data(iter);
GIRARA_LIST_FOREACH(zathura->plugins.path, char*, iter, plugindir)
/* TODO: rewrite with GDir */
/* read all files in the plugin directory */
DIR* dir = opendir(plugindir);
if (dir == NULL) {
girara_error("could not open plugin directory: %s", plugindir);
girara_list_iterator_next(iter);
continue;
}
int fddir = dirfd(dir);
struct dirent* entry;
while ((entry = readdir(dir)) != NULL) {
if (strcmp(entry->d_name, ".") == 0 || strcmp(entry->d_name, "..") == 0) {
continue;
}
struct stat statbuf;
if (fstatat(fddir, entry->d_name, &statbuf, 0) != 0) {
girara_error("failed to fstatat %s/%s; errno is %d.", plugindir, entry->d_name, errno);
@ -87,27 +98,18 @@ zathura_document_plugins_load(zathura_t* zathura)
continue;
}
plugin = malloc(sizeof(zathura_document_plugin_t));
if (plugin == NULL) {
g_error("failed to allocate memory!");
break;
}
plugin->open_function = NULL;
plugin->content_types = girara_list_new();
girara_list_set_free_function(plugin->content_types, g_free);
plugin = g_malloc0(sizeof(zathura_document_plugin_t));
plugin->content_types = girara_list_new2(g_free);
plugin->handle = handle;
register_plugin(plugin);
bool r = zathura_document_plugin_register(zathura, plugin, handle);
bool r = zathura_document_plugin_register(zathura, plugin);
if (r == false) {
girara_error("could not register plugin %s", path);
free(plugin);
dlclose(handle);
}
else {
zathura_document_plugin_free(plugin);
} else {
girara_info("successfully loaded plugin %s", path);
}
@ -117,8 +119,7 @@ zathura_document_plugins_load(zathura_t* zathura)
if (closedir(dir) == -1) {
girara_error("could not close plugin directory %s", plugindir);
}
} while (girara_list_iterator_next(iter));
girara_list_iterator_free(iter);
GIRARA_LIST_FOREACH_END(zathura->plugins.path, char*, iter, plugindir);
}
void
@ -128,15 +129,15 @@ zathura_document_plugin_free(zathura_document_plugin_t* plugin)
return;
}
dlclose(plugin->handle);
girara_list_free(plugin->content_types);
free(plugin);
g_free(plugin);
}
bool
zathura_document_plugin_register(zathura_t* zathura, zathura_document_plugin_t* new_plugin, void* handle)
static bool
zathura_document_plugin_register(zathura_t* zathura, zathura_document_plugin_t* new_plugin)
{
if( (new_plugin == NULL) || (new_plugin->content_types == NULL) || (new_plugin->open_function == NULL)
|| (handle == NULL) ) {
if (new_plugin == NULL || new_plugin->content_types == NULL || new_plugin->open_function == NULL) {
girara_error("plugin: could not register\n");
return false;
}
@ -145,9 +146,10 @@ zathura_document_plugin_register(zathura_t* zathura, zathura_document_plugin_t*
GIRARA_LIST_FOREACH(new_plugin->content_types, gchar*, iter, type)
if (!zathura_type_plugin_mapping_new(zathura, type, new_plugin)) {
girara_error("plugin: already registered for filetype %s\n", type);
} else {
atleastone = true;
}
atleastone = true;
GIRARA_LIST_FOREACH_END(new_plugin->content_types, gchar*, iter, type)
GIRARA_LIST_FOREACH_END(new_plugin->content_types, gchar*, iter, type);
if (atleastone) {
girara_list_append(zathura->plugins.plugins, new_plugin);
@ -155,6 +157,47 @@ zathura_document_plugin_register(zathura_t* zathura, zathura_document_plugin_t*
return atleastone;
}
static const gchar*
guess_type(const char* path)
{
gboolean uncertain;
const gchar* content_type = g_content_type_guess(path, NULL, 0, &uncertain);
if (content_type == NULL) {
return NULL;
}
FILE* f = fopen(path, "r");
if (f == NULL) {
return NULL;
}
const int fd = fileno(f);
guchar* content = NULL;
size_t length = 0u;
while (uncertain == TRUE) {
g_free((void*)content_type);
content_type = NULL;
content = g_realloc(content, length + BUFSIZ);
const ssize_t r = read(fd, content + length, BUFSIZ);
if (r == -1) {
break;
}
length += r;
content_type = g_content_type_guess(NULL, content, length, &uncertain);
}
fclose(f);
if (uncertain == TRUE) {
g_free((void*)content_type);
content_type = NULL;
}
g_free(content);
return content_type;
}
zathura_document_t*
zathura_document_open(zathura_t* zathura, const char* path, const char* password)
{
@ -163,18 +206,20 @@ zathura_document_open(zathura_t* zathura, const char* path, const char* password
}
if (file_exists(path) == false) {
girara_error("File does not exist");
girara_error("File '%s' does not exist", path);
return NULL;
}
const gchar* content_type = g_content_type_guess(path, NULL, 0, NULL);
const gchar* content_type = guess_type(path);
if (content_type == NULL) {
girara_error("Could not determine file type");
girara_error("Could not determine file type.");
return NULL;
}
char* file_uri = NULL;
/* determine real path */
size_t path_max;
long path_max;
#ifdef PATH_MAX
path_max = PATH_MAX;
#else
@ -204,52 +249,118 @@ zathura_document_open(zathura_t* zathura, const char* path, const char* password
plugin = mapping->plugin;
break;
}
GIRARA_LIST_FOREACH_END(zathura->plugins.type_plugin_mapping, zathura_type_plugin_mapping_t*, iter, mapping)
GIRARA_LIST_FOREACH_END(zathura->plugins.type_plugin_mapping, zathura_type_plugin_mapping_t*, iter, mapping);
g_free((void*)content_type);
if (plugin == NULL) {
girara_error("unknown file type\n");
free(real_path);
goto error_free;
}
document = g_malloc0(sizeof(zathura_document_t));
if (document == NULL) {
goto error_free;
}
document->file_path = real_path;
document->password = password;
document->scale = 1.0;
document->zathura = zathura;
if (plugin->open_function != NULL) {
if (plugin->open_function(document) == true) {
/* update statusbar */
girara_statusbar_item_set_text(zathura->ui.session, zathura->ui.statusbar.file, real_path);
/* read all pages */
document->pages = calloc(document->number_of_pages, sizeof(zathura_page_t*));
if (document->pages == NULL) {
goto error_free;
}
for (unsigned int page_id = 0; page_id < document->number_of_pages; page_id++) {
zathura_page_t* page = zathura_page_get(document, page_id);
if (page == NULL) {
goto error_free;
}
document->pages[page_id] = page;
}
return document;
}
/* open document */
if (plugin->open_function == NULL) {
girara_error("plugin has no open function\n");
goto error_free;
}
girara_error("could not open file\n");
zathura_plugin_error_t error = plugin->open_function(document);
if (error != ZATHURA_PLUGIN_ERROR_OK) {
if (error == ZATHURA_PLUGIN_ERROR_INVALID_PASSWORD) {
zathura_password_dialog_info_t* password_dialog_info = malloc(sizeof(zathura_password_dialog_info_t));
if (password_dialog_info != NULL) {
password_dialog_info->path = g_strdup(path);
password_dialog_info->zathura = zathura;
if (path != NULL) {
girara_dialog(zathura->ui.session, "Enter password:", true, NULL,
(girara_callback_inputbar_activate_t) cb_password_dialog, password_dialog_info);
goto error_free;
} else {
free(password_dialog_info);
}
}
goto error_free;
}
girara_error("could not open document\n");
goto error_free;
}
/* read history file */
int offset = 0;
zathura_db_get_fileinfo(zathura->database, document->file_path,
&document->current_page_number, &offset, &document->scale, &document->rotate);
/* check for valid scale value */
if (document->scale <= FLT_EPSILON) {
girara_warning("document info: '%s' has non positive scale", document->file_path);
document->scale = 1;
}
/* check current page number */
if (document->current_page_number > document->number_of_pages) {
girara_warning("document info: '%s' has an invalid page number", document->file_path);
document->current_page_number = 0;
}
/* update statusbar */
girara_statusbar_item_set_text(zathura->ui.session, zathura->ui.statusbar.file, real_path);
/* read all pages */
document->pages = calloc(document->number_of_pages, sizeof(zathura_page_t*));
if (document->pages == NULL) {
goto error_free;
}
for (unsigned int page_id = 0; page_id < document->number_of_pages; page_id++) {
zathura_page_t* page = zathura_page_get(document, page_id, NULL);
if (page == NULL) {
goto error_free;
}
document->pages[page_id] = page;
}
/* install file monitor */
file_uri = g_filename_to_uri(real_path, NULL, NULL);
if (file_uri == NULL) {
goto error_free;
}
document->file_monitor.file = g_file_new_for_uri(file_uri);
if (document->file_monitor.file == NULL) {
goto error_free;
}
document->file_monitor.monitor = g_file_monitor_file(document->file_monitor.file, G_FILE_MONITOR_NONE, NULL, NULL);
if (document->file_monitor.monitor == NULL) {
goto error_free;
}
g_signal_connect(G_OBJECT(document->file_monitor.monitor), "changed", G_CALLBACK(cb_file_monitor), zathura->ui.session);
/* apply open adjustment */
int adjust_open = ADJUST_BESTFIT;
girara_setting_get(zathura->ui.session, "adjust-open", &adjust_open);
g_free(file_uri);
return document;
error_free:
if (file_uri != NULL) {
g_free(file_uri);
}
free(real_path);
if (document != NULL && document->pages != NULL) {
@ -264,7 +375,7 @@ error_free:
return NULL;
}
bool
zathura_plugin_error_t
zathura_document_free(zathura_document_t* document)
{
if (document == NULL) {
@ -280,19 +391,13 @@ zathura_document_free(zathura_document_t* document)
free(document->pages);
/* free document */
bool r = true;
if (document->functions.document_free == NULL) {
girara_error("%s not implemented", __FUNCTION__);
if (document->file_path != NULL) {
free(document->file_path);
}
g_free(document);
return true;
} else {
r = document->functions.document_free(document);
}
bool r = document->functions.document_free(document);
if (document->file_path != NULL) {
free(document->file_path);
}
@ -302,7 +407,7 @@ zathura_document_free(zathura_document_t* document)
return r;
}
bool
zathura_plugin_error_t
zathura_document_save_as(zathura_document_t* document, const char* path)
{
if (document == NULL || path == NULL) {
@ -318,7 +423,7 @@ zathura_document_save_as(zathura_document_t* document, const char* path)
}
girara_tree_node_t*
zathura_document_index_generate(zathura_document_t* document)
zathura_document_index_generate(zathura_document_t* document, zathura_plugin_error_t* error)
{
if (document == NULL) {
return NULL;
@ -329,11 +434,11 @@ zathura_document_index_generate(zathura_document_t* document)
return NULL;
}
return document->functions.document_index_generate(document);
return document->functions.document_index_generate(document, error);
}
zathura_list_t*
zathura_document_attachments_get(zathura_document_t* document)
girara_list_t*
zathura_document_attachments_get(zathura_document_t* document, zathura_plugin_error_t* error)
{
if (document == NULL) {
return NULL;
@ -344,17 +449,45 @@ zathura_document_attachments_get(zathura_document_t* document)
return NULL;
}
return document->functions.document_attachments_get(document);
return document->functions.document_attachments_get(document, error);
}
bool
zathura_document_attachments_free(zathura_list_t* UNUSED(list))
zathura_plugin_error_t
zathura_document_attachment_save(zathura_document_t* document, const char* attachment, const char* file)
{
return false;
if (document == NULL) {
return ZATHURA_PLUGIN_ERROR_INVALID_ARGUMENTS;
}
if (document->functions.document_attachment_save == NULL) {
return ZATHURA_PLUGIN_ERROR_NOT_IMPLEMENTED;
}
return document->functions.document_attachment_save(document, attachment, file);
}
char*
zathura_document_meta_get(zathura_document_t* document, zathura_document_meta_t meta, zathura_plugin_error_t* error)
{
if (document == NULL) {
if (error != NULL) {
*error = ZATHURA_PLUGIN_ERROR_NOT_IMPLEMENTED;
}
return NULL;
}
if (document->functions.document_meta_get == NULL) {
if (error != NULL) {
*error = ZATHURA_PLUGIN_ERROR_NOT_IMPLEMENTED;
}
return NULL;
}
return document->functions.document_meta_get(document, meta, error);
}
zathura_page_t*
zathura_page_get(zathura_document_t* document, unsigned int page_id)
zathura_page_get(zathura_document_t* document, unsigned int page_id, zathura_plugin_error_t* error)
{
if (document == NULL) {
return NULL;
@ -365,27 +498,25 @@ zathura_page_get(zathura_document_t* document, unsigned int page_id)
return NULL;
}
zathura_page_t* page = document->functions.page_get(document, page_id);
zathura_page_t* page = document->functions.page_get(document, page_id, error);
if (page != NULL) {
page->number = page_id;
page->visible = false;
page->event_box = gtk_event_box_new();
page->drawing_area = gtk_drawing_area_new();
page->surface = NULL;
page->drawing_area = zathura_page_widget_new(page);
page->document = document;
g_signal_connect(page->drawing_area, "expose-event", G_CALLBACK(page_expose_event), page);
gtk_widget_set_size_request(page->drawing_area, page->width * document->scale, page->height * document->scale);
gtk_container_add(GTK_CONTAINER(page->event_box), page->drawing_area);
unsigned int page_height = 0;
unsigned int page_width = 0;
page_calc_height_width(page, &page_height, &page_width, true);
g_static_mutex_init(&(page->lock));
gtk_widget_set_size_request(page->drawing_area, page_width, page_height);
}
return page;
}
bool
zathura_plugin_error_t
zathura_page_free(zathura_page_t* page)
{
if (page == NULL || page->document == NULL) {
@ -397,13 +528,11 @@ zathura_page_free(zathura_page_t* page)
return false;
}
g_static_mutex_free(&(page->lock));
return page->document->functions.page_free(page);
}
zathura_list_t*
zathura_page_search_text(zathura_page_t* page, const char* text)
girara_list_t*
zathura_page_search_text(zathura_page_t* page, const char* text, zathura_plugin_error_t* error)
{
if (page == NULL || page->document == NULL || text == NULL) {
return NULL;
@ -414,11 +543,11 @@ zathura_page_search_text(zathura_page_t* page, const char* text)
return NULL;
}
return page->document->functions.page_search_text(page, text);
return page->document->functions.page_search_text(page, text, error);
}
zathura_list_t*
zathura_page_links_get(zathura_page_t* page)
girara_list_t*
zathura_page_links_get(zathura_page_t* page, zathura_plugin_error_t* error)
{
if (page == NULL || page->document == NULL) {
return NULL;
@ -429,17 +558,17 @@ zathura_page_links_get(zathura_page_t* page)
return NULL;
}
return page->document->functions.page_links_get(page);
return page->document->functions.page_links_get(page, error);
}
bool
zathura_page_links_free(zathura_list_t* UNUSED(list))
zathura_plugin_error_t
zathura_page_links_free(girara_list_t* UNUSED(list))
{
return false;
}
zathura_list_t*
zathura_page_form_fields_get(zathura_page_t* page)
girara_list_t*
zathura_page_form_fields_get(zathura_page_t* page, zathura_plugin_error_t* error)
{
if (page == NULL || page->document == NULL) {
return NULL;
@ -450,28 +579,78 @@ zathura_page_form_fields_get(zathura_page_t* page)
return NULL;
}
return page->document->functions.page_form_fields_get(page);
return page->document->functions.page_form_fields_get(page, error);
}
bool
zathura_page_form_fields_free(zathura_list_t* UNUSED(list))
zathura_plugin_error_t
zathura_page_form_fields_free(girara_list_t* UNUSED(list))
{
return false;
}
bool
zathura_page_render(zathura_page_t* page, cairo_t* cairo)
girara_list_t*
zathura_page_images_get(zathura_page_t* page, zathura_plugin_error_t* error)
{
if (page == NULL || page->document == NULL) {
return NULL;
}
if (page->document->functions.page_images_get == NULL) {
girara_error("%s not implemented", __FUNCTION__);
return false;
}
return page->document->functions.page_images_get(page, error);
}
zathura_plugin_error_t
zathura_page_image_save(zathura_page_t* page, zathura_image_t* image, const char* file)
{
if (page == NULL || page->document == NULL || image == NULL || file == NULL) {
return false;
}
if (page->document->functions.page_image_save == NULL) {
girara_error("%s not implemented", __FUNCTION__);
return false;
}
return page->document->functions.page_image_save(page, image, file);
}
char* zathura_page_get_text(zathura_page_t* page, zathura_rectangle_t rectangle, zathura_plugin_error_t* error)
{
if (page == NULL || page->document == NULL) {
if (error) {
*error = ZATHURA_PLUGIN_ERROR_INVALID_ARGUMENTS;
}
return NULL;
}
if (page->document->functions.page_get_text == NULL) {
girara_error("%s not implemented", __FUNCTION__);
if (error) {
*error = ZATHURA_PLUGIN_ERROR_NOT_IMPLEMENTED;
}
return NULL;
}
return page->document->functions.page_get_text(page, rectangle, error);
}
zathura_plugin_error_t
zathura_page_render(zathura_page_t* page, cairo_t* cairo, bool printing)
{
if (page == NULL || page->document == NULL || cairo == NULL) {
return NULL;
return ZATHURA_PLUGIN_ERROR_INVALID_ARGUMENTS;
}
if (page->document->functions.page_render_cairo == NULL) {
girara_error("%s not implemented", __FUNCTION__);
return NULL;
return ZATHURA_PLUGIN_ERROR_NOT_IMPLEMENTED;
}
return page->document->functions.page_render_cairo(page, cairo);
return page->document->functions.page_render_cairo(page, cairo, printing);
}
zathura_index_element_t*
@ -483,10 +662,6 @@ zathura_index_element_new(const char* title)
zathura_index_element_t* res = g_malloc0(sizeof(zathura_index_element_t));
if (res == NULL) {
return NULL;
}
res->title = g_strdup(title);
return res;
@ -552,7 +727,7 @@ zathura_type_plugin_mapping_new(zathura_t* zathura, const gchar* type, zathura_d
girara_list_iterator_free(iter);
return false;
}
GIRARA_LIST_FOREACH_END(zathura->plugins.type_plugin_mapping, zathura_type_plugin_mapping_t*, iter, mapping)
GIRARA_LIST_FOREACH_END(zathura->plugins.type_plugin_mapping, zathura_type_plugin_mapping_t*, iter, mapping);
zathura_type_plugin_mapping_t* mapping = g_malloc(sizeof(zathura_type_plugin_mapping_t));
mapping->type = g_strdup(type);
@ -571,3 +746,16 @@ zathura_type_plugin_mapping_free(zathura_type_plugin_mapping_t* mapping)
g_free((void*)mapping->type);
g_free(mapping);
}
void
zathura_link_free(zathura_link_t* link)
{
if (link == NULL) {
return;
}
if (link->type == ZATHURA_LINK_EXTERNAL) {
g_free(link->target.value);
}
g_free(link);
}

View file

@ -7,32 +7,72 @@
#include <gtk/gtk.h>
#include <stdbool.h>
#include <girara-datastructures.h>
#include <girara/types.h>
#include "zathura.h"
#define PLUGIN_REGISTER_FUNCTION "plugin_register"
typedef struct zathura_list_s zathura_list_t;
// typedef struct zathura_document_s zathura_document_t;
/**
* Error types for plugins
*/
typedef enum zathura_plugin_error_e
{
ZATHURA_PLUGIN_ERROR_OK, /**< No error occured */
ZATHURA_PLUGIN_ERROR_UNKNOWN, /**< An unknown error occured */
ZATHURA_PLUGIN_ERROR_OUT_OF_MEMORY, /**< Out of memory */
ZATHURA_PLUGIN_ERROR_NOT_IMPLEMENTED, /**< The called function has not been implemented */
ZATHURA_PLUGIN_ERROR_INVALID_ARGUMENTS, /**< Invalid arguments have been passed */
ZATHURA_PLUGIN_ERROR_INVALID_PASSWORD /**< The provided password is invalid */
} zathura_plugin_error_t;
typedef bool (*zathura_document_open_t)(zathura_document_t* document);
/**
* Document open function
*
* @param document The document
* @return true if no error occured otherwise false
*/
typedef zathura_plugin_error_t (*zathura_document_open_t)(zathura_document_t* document);
/**
* Document plugin structure
*/
typedef struct zathura_document_plugin_s
{
girara_list_t* content_types; /**> List of supported content types */
zathura_document_open_t open_function; /**> Document open function */
void* handle; /**> DLL handle */
girara_list_t* content_types; /**< List of supported content types */
zathura_document_open_t open_function; /**< Document open function */
void* handle; /**< DLL handle */
} zathura_document_plugin_t;
/**
* Plugin mapping
*/
typedef struct zathura_type_plugin_mapping_s
{
const gchar* type;
zathura_document_plugin_t* plugin;
const gchar* type; /**< Plugin type */
zathura_document_plugin_t* plugin; /**< Mapped plugin */
} zathura_type_plugin_mapping_t;
/**
* Meta data entries
*/
typedef enum zathura_document_meta_e
{
ZATHURA_DOCUMENT_TITLE, /**< Title of the document */
ZATHURA_DOCUMENT_AUTHOR, /**< Author of the document */
ZATHURA_DOCUMENT_SUBJECT, /**< Subject of the document */
ZATHURA_DOCUMENT_KEYWORDS, /**< Keywords of the document */
ZATHURA_DOCUMENT_CREATOR, /**< Creator of the document */
ZATHURA_DOCUMENT_PRODUCER, /**< Producer of the document */
ZATHURA_DOCUMENT_CREATION_DATE, /**< Creation data */
ZATHURA_DOCUMENT_MODIFICATION_DATE /**< Modification data */
} zathura_document_meta_t;
typedef struct zathura_password_dialog_info_s
{
char* path; /**< Path to the file */
zathura_t* zathura; /**< Zathura session */
} zathura_password_dialog_info_t;
/**
* Function prototype that is called to register a document plugin
*
@ -40,24 +80,15 @@ typedef struct zathura_type_plugin_mapping_s
*/
typedef void (*zathura_plugin_register_service_t)(zathura_document_plugin_t*);
/**
* Structure for a list
*/
struct zathura_list_s
{
void* data; /**> Data value */
struct zathura_list_s* next; /**> Next element in the list */
};
/**
* Image buffer
*/
typedef struct zathura_image_buffer_s
{
unsigned char* data; /**> Image buffer data */
unsigned int height; /**> Height of the image */
unsigned int width; /**> Width of the image */
unsigned int rowstride; /**> Rowstride of the image */
unsigned char* data; /**< Image buffer data */
unsigned int height; /**< Height of the image */
unsigned int width; /**< Width of the image */
unsigned int rowstride; /**< Rowstride of the image */
} zathura_image_buffer_t;
/**
@ -72,28 +103,39 @@ zathura_image_buffer_t* zathura_image_buffer_create(unsigned int width, unsigned
/**
* Frees the image buffer
*
* @param zathura_image_buffer_t
* @param buffer The image buffer
*/
void zathura_image_buffer_free(zathura_image_buffer_t*);
void zathura_image_buffer_free(zathura_image_buffer_t* buffer);
/**
* Rectangle structure
* Rectangle structure.
* The coordinate system has its origin in the left upper corner. The x axes
* goes to the right, the y access goes down.
*/
typedef struct zathura_rectangle_s
{
double x1; /**> X coordinate of point 1 */
double y1; /**> Y coordinate of point 1 */
double x2; /**> X coordinate of point 2 */
double y2; /**> Y coordinate of point 2 */
double x1; /**< X coordinate of point 1 */
double y1; /**< Y coordinate of point 1 */
double x2; /**< X coordinate of point 2 */
double y2; /**< Y coordinate of point 2 */
} zathura_rectangle_t;
/**
* Image structure
*/
typedef struct zathura_image_s
{
zathura_rectangle_t position; /**< Coordinates of the image */
void* data; /**< Custom data of the plugin */
} zathura_image_t;
/**
* Possible link types
*/
typedef enum zathura_link_type_e
{
ZATHURA_LINK_TO_PAGE, /**> Links to a page */
ZATHURA_LINK_EXTERNAL, /**> Links to an external source */
ZATHURA_LINK_TO_PAGE, /**< Links to a page */
ZATHURA_LINK_EXTERNAL, /**< Links to an external source */
} zathura_link_type_t;
/**
@ -101,12 +143,12 @@ typedef enum zathura_link_type_e
*/
typedef struct zathura_link_s
{
zathura_rectangle_t position; /**> Position of the link */
zathura_link_type_t type; /**> Link type */
zathura_rectangle_t position; /**< Position of the link */
zathura_link_type_t type; /**< Link type */
union
{
unsigned int page_number; /**> Page number */
char* value; /**> Value */
unsigned int page_number; /**< Page number */
char* value; /**< Value */
} target;
} zathura_link_t;
@ -115,12 +157,12 @@ typedef struct zathura_link_s
*/
typedef struct zathura_index_element_s
{
char* title; /**> Title of the element */
zathura_link_type_t type; /**> Type */
char* title; /**< Title of the element */
zathura_link_type_t type; /**< Type */
union
{
unsigned int page_number; /**> Page number */
char* uri; /**> Uri */
unsigned int page_number; /**< Page number */
char* uri; /**< Uri */
} target;
} zathura_index_element_t;
@ -129,8 +171,8 @@ typedef struct zathura_index_element_s
*/
typedef enum zathura_form_type_e
{
ZATHURA_FORM_CHECKBOX, /**> Checkbox */
ZATHURA_FORM_TEXTFIELD /**> Textfield */
ZATHURA_FORM_CHECKBOX, /**< Checkbox */
ZATHURA_FORM_TEXTFIELD /**< Textfield */
} zathura_form_type_t;
/**
@ -138,8 +180,8 @@ typedef enum zathura_form_type_e
*/
typedef struct zathura_form_s
{
zathura_rectangle_t position; /**> Position */
zathura_form_type_t type; /**> Type */
zathura_rectangle_t position; /**< Position */
zathura_form_type_t type; /**< Type */
} zathura_form_t;
/**
@ -147,16 +189,13 @@ typedef struct zathura_form_s
*/
struct zathura_page_s
{
double height; /**> Page height */
double width; /**> Page width */
unsigned int number; /**> Page number */
zathura_document_t* document; /**> Document */
void* data; /**> Custom data */
bool visible; /**> Page is visible */
GtkWidget* event_box; /**> Widget wrapper for mouse events */
GtkWidget* drawing_area; /**> Drawing area */
GStaticMutex lock; /**> Lock */
cairo_surface_t* surface; /** Cairo surface */
double height; /**< Page height */
double width; /**< Page width */
unsigned int number; /**< Page number */
zathura_document_t* document; /**< Document */
void* data; /**< Custom data */
bool visible; /**< Page is visible */
GtkWidget* drawing_area; /**< Drawing area */
};
/**
@ -164,77 +203,111 @@ struct zathura_page_s
*/
struct zathura_document_s
{
char* file_path; /**> File path of the document */
const char* password; /**> Password of the document */
unsigned int current_page_number; /**> Current page number */
unsigned int number_of_pages; /**> Number of pages */
double scale; /**> Scale value */
int rotate; /**> Rotation */
void* data; /**> Custom data */
char* file_path; /**< File path of the document */
const char* password; /**< Password of the document */
unsigned int current_page_number; /**< Current page number */
unsigned int number_of_pages; /**< Number of pages */
double scale; /**< Scale value */
int rotate; /**< Rotation */
void* data; /**< Custom data */
zathura_t* zathura; /** Zathura object */
int adjust_mode; /**< Adjust mode (best-fit, width) */
struct
{
/**
* Frees the document
*/
bool (*document_free)(zathura_document_t* document);
zathura_plugin_error_t (*document_free)(zathura_document_t* document);
/**
* Generates the document index
*/
girara_tree_node_t* (*document_index_generate)(zathura_document_t* document);
girara_tree_node_t* (*document_index_generate)(zathura_document_t* document, zathura_plugin_error_t* error);
/**
* Save the document
*/
bool (*document_save_as)(zathura_document_t* document, const char* path);
zathura_plugin_error_t (*document_save_as)(zathura_document_t* document, const char* path);
/**
* Get list of attachments
*/
zathura_list_t* (*document_attachments_get)(zathura_document_t* document);
girara_list_t* (*document_attachments_get)(zathura_document_t* document, zathura_plugin_error_t* error);
/**
* Save attachment to a file
*/
zathura_plugin_error_t (*document_attachment_save)(zathura_document_t* document, const char* attachment, const char* file);
/**
* Get document information
*/
char* (*document_meta_get)(zathura_document_t* document, zathura_document_meta_t info, zathura_plugin_error_t* error);
/**
* Gets the page object
*/
zathura_page_t* (*page_get)(zathura_document_t* document, unsigned int page_id);
zathura_page_t* (*page_get)(zathura_document_t* document, unsigned int page_id, zathura_plugin_error_t* error);
/**
* Search text
*/
zathura_list_t* (*page_search_text)(zathura_page_t* page, const char* text);
girara_list_t* (*page_search_text)(zathura_page_t* page, const char* text, zathura_plugin_error_t* error);
/**
* Get links on a page
*/
zathura_list_t* (*page_links_get)(zathura_page_t* page);
girara_list_t* (*page_links_get)(zathura_page_t* page, zathura_plugin_error_t* error);
/**
* Get form fields
*/
zathura_list_t* (*page_form_fields_get)(zathura_page_t* page);
girara_list_t* (*page_form_fields_get)(zathura_page_t* page, zathura_plugin_error_t* error);
/**
* Get list of images
*/
girara_list_t* (*page_images_get)(zathura_page_t* page, zathura_plugin_error_t* error);
/**
* Save image to a file
*/
zathura_plugin_error_t (*page_image_save)(zathura_page_t* page, zathura_image_t* image, const char* file);
/**
* Get text for selection
*/
char* (*page_get_text)(zathura_page_t* page, zathura_rectangle_t rectangle, zathura_plugin_error_t* error);
/**
* Renders the page
*/
zathura_image_buffer_t* (*page_render)(zathura_page_t* page);
zathura_image_buffer_t* (*page_render)(zathura_page_t* page, zathura_plugin_error_t* error);
/**
* Renders the page
*/
bool (*page_render_cairo)(zathura_page_t* page, cairo_t* cairo);
zathura_plugin_error_t (*page_render_cairo)(zathura_page_t* page, cairo_t* cairo, bool printing);
/**
* Free page
*/
bool (*page_free)(zathura_page_t* page);
zathura_plugin_error_t (*page_free)(zathura_page_t* page);
} functions;
/**
* Document pages
*/
zathura_page_t** pages;
/**
* File monitor
*/
struct {
GFileMonitor* monitor; /**< File monitor */
GFile* file; /**< File for file monitor */
} file_monitor;
};
/**
@ -251,128 +324,189 @@ void zathura_document_plugins_load(zathura_t* zathura);
*/
void zathura_document_plugin_free(zathura_document_plugin_t* plugin);
/**
* Register document plugin
*/
bool zathura_document_plugin_register(zathura_t* zathura, zathura_document_plugin_t* new_plugin, void* handle);
/**
* Open the document
*
* @param zathura Zathura object
* @param path Path to the document
* @param password Password of the document or NULL
* @return The document object
*/
zathura_document_t* zathura_document_open(zathura_t* zathura, const char* path, const char* password);
zathura_document_t* zathura_document_open(zathura_t* zathura, const char* path,
const char* password);
/**
* Free the document
*
* @param document
* @return true if no error occured, otherwise false
* @return ZATHURA_PLUGIN_ERROR_OK when no error occured, otherwise see
* zathura_plugin_error_t
*/
bool zathura_document_free(zathura_document_t* document);
zathura_plugin_error_t zathura_document_free(zathura_document_t* document);
/**
* Save the document
*
* @param document The document object
* @param path Path for the saved file
* @return true if no error occured, otherwise false
* @return ZATHURA_PLUGIN_ERROR_OK when no error occured, otherwise see
* zathura_plugin_error_t
*/
bool zathura_document_save_as(zathura_document_t* document, const char* path);
zathura_plugin_error_t zathura_document_save_as(zathura_document_t* document, const char* path);
/**
* Generate the document index
*
* @param document The document object
* @param error Set to an error value (see \ref zathura_plugin_error_t) if an
* error occured
* @return Generated index
*/
girara_tree_node_t* zathura_document_index_generate(zathura_document_t* document);
girara_tree_node_t* zathura_document_index_generate(zathura_document_t* document, zathura_plugin_error_t* error);
/**
* Get list of attachments
*
* @param document The document object
* @param error Set to an error value (see \ref zathura_plugin_error_t) if an
* error occured
* @return List of attachments
*/
zathura_list_t* zathura_document_attachments_get(zathura_document_t* document);
girara_list_t* zathura_document_attachments_get(zathura_document_t* document, zathura_plugin_error_t* error);
/**
* Free document attachments
* Save document attachment
*
* @param list list of document attachments
* @return
* @param document The document objects
* @param attachment name of the attachment
* @param file the target filename
* @return ZATHURA_PLUGIN_ERROR_OK when no error occured, otherwise see
* zathura_plugin_error_t
*/
bool zathura_document_attachments_free(zathura_list_t* list);
zathura_plugin_error_t zathura_document_attachment_save(zathura_document_t* document, const char* attachment, const char* file);
/**
* Returns a string of the requested information
*
* @param document The zathura document
* @param meta The information field
* @param error Set to an error value (see \ref zathura_plugin_error_t) if an
* error occured
* @return String or NULL if information could not be retreived
*/
char* zathura_document_meta_get(zathura_document_t* document, zathura_document_meta_t meta, zathura_plugin_error_t* error);
/**
* Get the page object
*
* @param document The document
* @param page_id Page number
* @param error Set to an error value (see \ref zathura_plugin_error_t) if an
* error occured
* @return Page object or NULL if an error occured
*/
zathura_page_t* zathura_page_get(zathura_document_t* document, unsigned int page_id);
zathura_page_t* zathura_page_get(zathura_document_t* document, unsigned int page_id, zathura_plugin_error_t* error);
/**
* Frees the page object
*
* @param page The page object
* @return true if no error occured, otherwise false
* @return ZATHURA_PLUGIN_ERROR_OK when no error occured, otherwise see
* zathura_plugin_error_t
*/
bool zathura_page_free(zathura_page_t* page);
zathura_plugin_error_t zathura_page_free(zathura_page_t* page);
/**
* Search page
*
* @param page The page object
* @param text Search item
* @param error Set to an error value (see \ref zathura_plugin_error_t) if an
* error occured
* @return List of results
*/
zathura_list_t* zathura_page_search_text(zathura_page_t* page, const char* text);
girara_list_t* zathura_page_search_text(zathura_page_t* page, const char* text, zathura_plugin_error_t* error);
/**
* Get page links
*
* @param page The page object
* @param error Set to an error value (see \ref zathura_plugin_error_t) if an
* error occured
* @return List of links
*/
zathura_list_t* zathura_page_links_get(zathura_page_t* page);
girara_list_t* zathura_page_links_get(zathura_page_t* page, zathura_plugin_error_t* error);
/**
* Free page links
*
* @param list List of links
* @return true if no error occured, otherwise false
* @return ZATHURA_PLUGIN_ERROR_OK when no error occured, otherwise see
* zathura_plugin_error_t
*/
bool zathura_page_links_free(zathura_list_t* list);
zathura_plugin_error_t zathura_page_links_free(girara_list_t* list);
/**
* Get list of form fields
*
* @param page The page object
* @param error Set to an error value (see \ref zathura_plugin_error_t) if an
* error occured
* @return List of form fields
*/
zathura_list_t* zathura_page_form_fields_get(zathura_page_t* page);
girara_list_t* zathura_page_form_fields_get(zathura_page_t* page, zathura_plugin_error_t* error);
/**
* Free list of form fields
*
* @param list List of form fields
* @return true if no error occured, otherwise false
* @return ZATHURA_PLUGIN_ERROR_OK when no error occured, otherwise see
* zathura_plugin_error_t
*/
bool zathura_page_form_fields_free(zathura_list_t* list);
zathura_plugin_error_t zathura_page_form_fields_free(girara_list_t* list);
/**
* Get list of images
*
* @param page Page
* @param error Set to an error value (see \ref zathura_plugin_error_t) if an
* error occured
* @return List of images or NULL if an error occured
*/
girara_list_t* zathura_page_images_get(zathura_page_t* page, zathura_plugin_error_t* error);
/**
* Save image
*
* @param page Page
* @param image The image
* @param file Path to the file
* @return ZATHURA_PLUGIN_ERROR_OK when no error occured, otherwise see
* zathura_plugin_error_t
*/
zathura_plugin_error_t zathura_page_image_save(zathura_page_t* page, zathura_image_t* image, const char* file);
/**
* Get text for selection
* @param page Page
* @param rectangle Selection
* @error Set to an error value (see \ref zathura_plugin_error_t) if an error
* occured
* @return The selected text (needs to be deallocated with g_free)
*/
char* zathura_page_get_text(zathura_page_t* page, zathura_rectangle_t rectangle, zathura_plugin_error_t* error);
/**
* Render page
*
* @param page The page object
* @param cairo Cairo object
* @return True if no error occured, otherwise false
* @param printing render for printing
* @return ZATHURA_PLUGIN_ERROR_OK when no error occured, otherwise see
* zathura_plugin_error_t
*/
bool zathura_page_render(zathura_page_t* page, cairo_t* cairo);
zathura_plugin_error_t zathura_page_render(zathura_page_t* page, cairo_t* cairo, bool printing);
/**
* Create new index element
@ -389,6 +523,13 @@ zathura_index_element_t* zathura_index_element_new(const char* title);
*/
void zathura_index_element_free(zathura_index_element_t* index);
/**
* Free link
*
* @param link The link
*/
void zathura_link_free(zathura_link_t* link);
/**
* Add type -> plugin mapping
* @param zathura zathura instance

29
main.c Normal file
View file

@ -0,0 +1,29 @@
/* See LICENSE file for license and copyright information */
#include <stdio.h>
#include <glib/gstdio.h>
#include "zathura.h"
/* main function */
int main(int argc, char* argv[])
{
g_thread_init(NULL);
gdk_threads_init();
gtk_init(&argc, &argv);
zathura_t* zathura = zathura_init(argc, argv);
if (zathura == NULL) {
fprintf(stderr, "error: could not initialize zathura\n");
return -1;
}
gdk_threads_enter();
gtk_main();
gdk_threads_leave();
zathura_free(zathura);
return 0;
}

535
page_widget.c Normal file
View file

@ -0,0 +1,535 @@
/* See LICENSE file for license and copyright information */
#include <girara/utils.h>
#include <girara/settings.h>
#include <girara/datastructures.h>
#include "page_widget.h"
#include "render.h"
#include "utils.h"
#include "shortcuts.h"
G_DEFINE_TYPE(ZathuraPage, zathura_page_widget, GTK_TYPE_DRAWING_AREA)
typedef struct zathura_page_widget_private_s {
zathura_page_t* page;
zathura_t* zathura;
cairo_surface_t* surface; /** Cairo surface */
GStaticMutex lock; /**< Lock */
girara_list_t* links; /**< List of links on the page */
bool links_got; /**< True if we already tried to retrieve the list of links */
bool draw_links; /**< True if links should be drawn */
unsigned int link_offset; /**< Offset to the links */
unsigned int number_of_links; /**< Offset to the links */
girara_list_t* search_results; /** A list if there are search results that should be drawn */
int search_current; /** The index of the current search result */
zathura_rectangle_t selection; /** Region selected with the mouse */
} zathura_page_widget_private_t;
#define ZATHURA_PAGE_GET_PRIVATE(obj) \
(G_TYPE_INSTANCE_GET_PRIVATE ((obj), ZATHURA_TYPE_PAGE, zathura_page_widget_private_t))
static gboolean zathura_page_widget_expose(GtkWidget* widget, GdkEventExpose* event);
static void zathura_page_widget_finalize(GObject* object);
static void zathura_page_widget_set_property(GObject* object, guint prop_id, const GValue* value, GParamSpec* pspec);
static void zathura_page_widget_get_property(GObject* object, guint prop_id, GValue* value, GParamSpec* pspec);
static void zathura_page_widget_size_allocate(GtkWidget* widget, GdkRectangle* allocation);
static void redraw_rect(ZathuraPage* widget, zathura_rectangle_t* rectangle);
static void redraw_all_rects(ZathuraPage* widget, girara_list_t* rectangles);
static gboolean cb_zathura_page_widget_button_press_event(GtkWidget* widget, GdkEventButton* button);
static gboolean cb_zathura_page_widget_button_release_event(GtkWidget* widget, GdkEventButton* button);
static gboolean cb_zathura_page_widget_motion_notify(GtkWidget* widget, GdkEventMotion* event);
enum properties_e
{
PROP_0,
PROP_PAGE,
PROP_DRAW_LINKS,
PROP_LINKS_OFFSET,
PROP_LINKS_NUMBER,
PROP_SEARCH_RESULT,
PROP_SEARCH_RESULTS,
PROP_SEARCH_RESULTS_LENGTH,
PROP_SEARCH_RESULTS_CURRENT
};
static void
zathura_page_widget_class_init(ZathuraPageClass* class)
{
/* add private members */
g_type_class_add_private(class, sizeof(zathura_page_widget_private_t));
/* overwrite methods */
GtkWidgetClass* widget_class = GTK_WIDGET_CLASS(class);
widget_class->expose_event = zathura_page_widget_expose;
widget_class->size_allocate = zathura_page_widget_size_allocate;
widget_class->button_press_event = cb_zathura_page_widget_button_press_event;
widget_class->button_release_event = cb_zathura_page_widget_button_release_event;
widget_class->motion_notify_event = cb_zathura_page_widget_motion_notify;
GObjectClass* object_class = G_OBJECT_CLASS(class);
object_class->finalize = zathura_page_widget_finalize;
object_class->set_property = zathura_page_widget_set_property;
object_class->get_property = zathura_page_widget_get_property;
/* add properties */
g_object_class_install_property(object_class, PROP_PAGE,
g_param_spec_pointer("page", "page", "the page to draw", G_PARAM_WRITABLE | G_PARAM_CONSTRUCT_ONLY));
g_object_class_install_property(object_class, PROP_DRAW_LINKS,
g_param_spec_boolean("draw-links", "draw-links", "Set to true if links should be drawn", FALSE, G_PARAM_WRITABLE));
g_object_class_install_property(object_class, PROP_LINKS_OFFSET,
g_param_spec_int("offset-links", "offset-links", "Offset for the link numbers", 0, INT_MAX, 0, G_PARAM_WRITABLE));
g_object_class_install_property(object_class, PROP_LINKS_NUMBER,
g_param_spec_int("number-of-links", "number-of-links", "Number of links", 0, INT_MAX, 0, G_PARAM_READABLE));
g_object_class_install_property(object_class, PROP_SEARCH_RESULTS,
g_param_spec_pointer("search-results", "search-results", "Set to the list of search results", G_PARAM_WRITABLE | G_PARAM_READABLE));
g_object_class_install_property(object_class, PROP_SEARCH_RESULTS_CURRENT,
g_param_spec_int("search-current", "search-current", "The current search result", -1, INT_MAX, 0, G_PARAM_WRITABLE | G_PARAM_READABLE));
g_object_class_install_property(object_class, PROP_SEARCH_RESULTS_LENGTH,
g_param_spec_int("search-length", "search-length", "The number of search results", -1, INT_MAX, 0, G_PARAM_READABLE));
}
static void
zathura_page_widget_init(ZathuraPage* widget)
{
zathura_page_widget_private_t* priv = ZATHURA_PAGE_GET_PRIVATE(widget);
priv->page = NULL;
priv->surface = NULL;
priv->links = NULL;
priv->links_got = false;
priv->link_offset = 0;
priv->search_results = NULL;
priv->search_current = INT_MAX;
priv->selection.x1 = -1;
g_static_mutex_init(&(priv->lock));
/* we want mouse events */
gtk_widget_add_events(GTK_WIDGET(widget),
GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK | GDK_POINTER_MOTION_MASK);
}
GtkWidget*
zathura_page_widget_new(zathura_page_t* page)
{
g_return_val_if_fail(page != NULL, NULL);
return g_object_new(ZATHURA_TYPE_PAGE, "page", page, NULL);
}
static void
zathura_page_widget_finalize(GObject* object)
{
ZathuraPage* widget = ZATHURA_PAGE(object);
zathura_page_widget_private_t* priv = ZATHURA_PAGE_GET_PRIVATE(widget);
if (priv->surface) {
cairo_surface_destroy(priv->surface);
}
g_static_mutex_free(&(priv->lock));
girara_list_free(priv->links);
G_OBJECT_CLASS(zathura_page_widget_parent_class)->finalize(object);
}
static void
zathura_page_widget_set_property(GObject* object, guint prop_id, const GValue* value, GParamSpec* pspec)
{
ZathuraPage* pageview = ZATHURA_PAGE(object);
zathura_page_widget_private_t* priv = ZATHURA_PAGE_GET_PRIVATE(pageview);
switch (prop_id) {
case PROP_PAGE:
priv->page = g_value_get_pointer(value);
priv->zathura = priv->page->document->zathura;
break;
case PROP_DRAW_LINKS:
priv->draw_links = g_value_get_boolean(value);
/* get links */
if (priv->draw_links == true && priv->links_got == false) {
priv->links = zathura_page_links_get(priv->page, NULL);
priv->links_got = true;
priv->number_of_links = (priv->links == NULL) ? 0 : girara_list_size(priv->links);
}
if (priv->links_got == true && priv->links != NULL) {
GIRARA_LIST_FOREACH(priv->links, zathura_link_t*, iter, link)
zathura_rectangle_t rectangle = recalc_rectangle(priv->page, link->position);
redraw_rect(pageview, &rectangle);
GIRARA_LIST_FOREACH_END(priv->links, zathura_link_t*, iter, link);
}
break;
case PROP_LINKS_OFFSET:
priv->link_offset = g_value_get_int(value);
break;
case PROP_SEARCH_RESULTS:
if (priv->search_results != NULL) {
redraw_all_rects(pageview, priv->search_results);
girara_list_free(priv->search_results);
}
priv->search_results = g_value_get_pointer(value);
if (priv->search_results != NULL) {
priv->draw_links = false;
redraw_all_rects(pageview, priv->search_results);
}
priv->search_current = -1;
break;
case PROP_SEARCH_RESULTS_CURRENT: {
g_return_if_fail(priv->search_results != NULL);
if (priv->search_current >= 0 && priv->search_current < (signed) girara_list_size(priv->search_results)) {
zathura_rectangle_t* rect = girara_list_nth(priv->search_results, priv->search_current);
zathura_rectangle_t rectangle = recalc_rectangle(priv->page, *rect);
redraw_rect(pageview, &rectangle);
}
int val = g_value_get_int(value);
if (val < 0) {
priv->search_current = girara_list_size(priv->search_results);
} else {
priv->search_current = val;
zathura_rectangle_t* rect = girara_list_nth(priv->search_results, priv->search_current);
zathura_rectangle_t rectangle = recalc_rectangle(priv->page, *rect);
redraw_rect(pageview, &rectangle);
}
break;
}
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec);
}
}
static void
zathura_page_widget_get_property(GObject* object, guint prop_id, GValue* value, GParamSpec* pspec)
{
ZathuraPage* pageview = ZATHURA_PAGE(object);
zathura_page_widget_private_t* priv = ZATHURA_PAGE_GET_PRIVATE(pageview);
switch (prop_id) {
case PROP_LINKS_NUMBER:
g_value_set_int(value, priv->number_of_links);
break;
case PROP_SEARCH_RESULTS_LENGTH:
g_value_set_int(value, priv->search_results == NULL ? 0 : girara_list_size(priv->search_results));
break;
case PROP_SEARCH_RESULTS_CURRENT:
g_value_set_int(value, priv->search_results == NULL ? -1 : priv->search_current);
break;
case PROP_SEARCH_RESULTS:
g_value_set_pointer(value, priv->search_results);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec);
}
}
static gboolean
zathura_page_widget_expose(GtkWidget* widget, GdkEventExpose* event)
{
cairo_t* cairo = gdk_cairo_create(widget->window);
if (cairo == NULL) {
girara_error("Could not retreive cairo object");
return FALSE;
}
/* set clip region */
cairo_rectangle(cairo, event->area.x, event->area.y, event->area.width, event->area.height);
cairo_clip(cairo);
zathura_page_widget_private_t* priv = ZATHURA_PAGE_GET_PRIVATE(widget);
g_static_mutex_lock(&(priv->lock));
if (priv->surface != NULL) {
cairo_save(cairo);
unsigned int page_height = widget->allocation.height;
unsigned int page_width = widget->allocation.width;
switch (priv->page->document->rotate) {
case 90:
cairo_translate(cairo, page_width, 0);
break;
case 180:
cairo_translate(cairo, page_width, page_height);
break;
case 270:
cairo_translate(cairo, 0, page_height);
break;
}
if (priv->page->document->rotate != 0) {
cairo_rotate(cairo, priv->page->document->rotate * G_PI / 180.0);
}
cairo_set_source_surface(cairo, priv->surface, 0, 0);
cairo_paint(cairo);
cairo_restore(cairo);
/* draw rectangles */
char* font = NULL;
girara_setting_get(priv->zathura->ui.session, "font", &font);
float transparency = 0.5;
girara_setting_get(priv->zathura->ui.session, "highlight-transparency", &transparency);
if (font != NULL) {
cairo_select_font_face(cairo, font, CAIRO_FONT_SLANT_NORMAL, CAIRO_FONT_WEIGHT_BOLD);
}
g_free(font);
/* draw links */
if (priv->draw_links == true && priv->number_of_links != 0) {
unsigned int link_counter = 0;
GIRARA_LIST_FOREACH(priv->links, zathura_link_t*, iter, link)
zathura_rectangle_t rectangle = recalc_rectangle(priv->page, link->position);
/* draw position */
GdkColor color = priv->zathura->ui.colors.highlight_color;
cairo_set_source_rgba(cairo, color.red, color.green, color.blue, transparency);
cairo_rectangle(cairo, rectangle.x1, rectangle.y1,
(rectangle.x2 - rectangle.x1), (rectangle.y2 - rectangle.y1));
cairo_fill(cairo);
/* draw text */
cairo_set_source_rgba(cairo, 0, 0, 0, 1);
cairo_set_font_size(cairo, 10);
cairo_move_to(cairo, rectangle.x1 + 1, rectangle.y2 - 1);
char* link_number = g_strdup_printf("%i", priv->link_offset + ++link_counter);
cairo_show_text(cairo, link_number);
g_free(link_number);
GIRARA_LIST_FOREACH_END(priv->links, zathura_link_t*, iter, link);
}
/* draw search results */
if (priv->search_results != NULL) {
int idx = 0;
GIRARA_LIST_FOREACH(priv->search_results, zathura_rectangle_t*, iter, rect)
zathura_rectangle_t rectangle = recalc_rectangle(priv->page, *rect);
/* draw position */
GdkColor color = priv->zathura->ui.colors.highlight_color;
if (idx == priv->search_current) {
cairo_set_source_rgba(cairo, 0, color.green, color.blue, transparency);
} else {
cairo_set_source_rgba(cairo, color.red, color.green, color.blue, transparency);
}
cairo_rectangle(cairo, rectangle.x1, rectangle.y1,
(rectangle.x2 - rectangle.x1), (rectangle.y2 - rectangle.y1));
cairo_fill(cairo);
++idx;
GIRARA_LIST_FOREACH_END(priv->search_results, zathura_rectangle_t*, iter, rect);
}
/* draw selection */
if (priv->selection.y2 != -1 && priv->selection.x2 != -1) {
GdkColor color = priv->zathura->ui.colors.highlight_color;
cairo_set_source_rgba(cairo, color.red, color.green, color.blue, transparency);
cairo_rectangle(cairo, priv->selection.x1, priv->selection.y1,
(priv->selection.x2 - priv->selection.x1), (priv->selection.y2 - priv->selection.y1));
cairo_fill(cairo);
}
} else {
/* set background color */
cairo_set_source_rgb(cairo, 255, 255, 255);
cairo_rectangle(cairo, 0, 0, widget->allocation.width, widget->allocation.height);
cairo_fill(cairo);
bool render_loading = true;
girara_setting_get(priv->zathura->ui.session, "render-loading", &render_loading);
/* write text */
if (render_loading == true) {
cairo_set_source_rgb(cairo, 0, 0, 0);
const char* text = "Loading...";
cairo_select_font_face(cairo, "Sans", CAIRO_FONT_SLANT_NORMAL, CAIRO_FONT_WEIGHT_NORMAL);
cairo_set_font_size(cairo, 16.0);
cairo_text_extents_t extents;
cairo_text_extents(cairo, text, &extents);
double x = widget->allocation.width * 0.5 - (extents.width * 0.5 + extents.x_bearing);
double y = widget->allocation.height * 0.5 - (extents.height * 0.5 + extents.y_bearing);
cairo_move_to(cairo, x, y);
cairo_show_text(cairo, text);
}
/* render real page */
render_page(priv->zathura->sync.render_thread, priv->page);
}
cairo_destroy(cairo);
g_static_mutex_unlock(&(priv->lock));
return FALSE;
}
static void
zathura_page_widget_redraw_canvas(ZathuraPage* pageview)
{
GtkWidget* widget = GTK_WIDGET(pageview);
gtk_widget_queue_draw(widget);
}
void
zathura_page_widget_update_surface(ZathuraPage* widget, cairo_surface_t* surface)
{
zathura_page_widget_private_t* priv = ZATHURA_PAGE_GET_PRIVATE(widget);
g_static_mutex_lock(&(priv->lock));
if (priv->surface != NULL) {
cairo_surface_destroy(priv->surface);
}
priv->surface = surface;
g_static_mutex_unlock(&(priv->lock));
/* force a redraw here */
zathura_page_widget_redraw_canvas(widget);
}
static void
zathura_page_widget_size_allocate(GtkWidget* widget, GdkRectangle* allocation)
{
GTK_WIDGET_CLASS(zathura_page_widget_parent_class)->size_allocate(widget, allocation);
zathura_page_widget_update_surface(ZATHURA_PAGE(widget), NULL);
}
static void
redraw_rect(ZathuraPage* widget, zathura_rectangle_t* rectangle)
{
/* cause the rect to be drawn */
GdkRectangle grect;
grect.x = rectangle->x1;
grect.y = rectangle->y1;
grect.width = rectangle->x2 - rectangle->x1;
grect.height = rectangle->y2 - rectangle->y1;
gdk_window_invalidate_rect(GTK_WIDGET(widget)->window, &grect, TRUE);
}
static void
redraw_all_rects(ZathuraPage* widget, girara_list_t* rectangles)
{
zathura_page_widget_private_t* priv = ZATHURA_PAGE_GET_PRIVATE(widget);
GIRARA_LIST_FOREACH(rectangles, zathura_rectangle_t*, iter, rect)
zathura_rectangle_t rectangle = recalc_rectangle(priv->page, *rect);
redraw_rect(widget, &rectangle);
GIRARA_LIST_FOREACH_END(rectangles, zathura_recantgle_t*, iter, rect);
}
zathura_link_t*
zathura_page_widget_link_get(ZathuraPage* widget, unsigned int index)
{
g_return_val_if_fail(widget != NULL, NULL);
zathura_page_widget_private_t* priv = ZATHURA_PAGE_GET_PRIVATE(widget);
g_return_val_if_fail(priv != NULL, NULL);
if (priv->links != NULL && index >= priv->link_offset &&
girara_list_size(priv->links) >= index - priv->link_offset) {
return girara_list_nth(priv->links, index - priv->link_offset);
} else {
return NULL;
}
}
static gboolean
cb_zathura_page_widget_button_press_event(GtkWidget* widget, GdkEventButton* button)
{
g_return_val_if_fail(widget != NULL, false);
g_return_val_if_fail(button != NULL, false);
if (button->button != 1) {
return false;
}
zathura_page_widget_private_t* priv = ZATHURA_PAGE_GET_PRIVATE(widget);
if (button->type == GDK_BUTTON_PRESS) {
/* start the selection */
priv->selection.x1 = button->x;
priv->selection.y1 = button->y;
priv->selection.x2 = -1;
priv->selection.y2 = -1;
} else if (button->type == GDK_2BUTTON_PRESS || button->type == GDK_3BUTTON_PRESS) {
/* abort the selection */
priv->selection.x1 = -1;
priv->selection.y1 = -1;
priv->selection.x2 = -1;
priv->selection.y2 = -1;
}
return false;
}
static gboolean
cb_zathura_page_widget_button_release_event(GtkWidget* widget, GdkEventButton* button)
{
g_return_val_if_fail(widget != NULL, false);
g_return_val_if_fail(button != NULL, false);
if (button->type != GDK_BUTTON_RELEASE || button->button != 1) {
return false;
}
zathura_page_widget_private_t* priv = ZATHURA_PAGE_GET_PRIVATE(widget);
if (priv->selection.y2 == -1 && priv->selection.x2 == -1 ) {
/* simple single click */
/* get links */
if (priv->links_got == false) {
priv->links = zathura_page_links_get(priv->page, NULL);
priv->links_got = true;
priv->number_of_links = (priv->links == NULL) ? 0 : girara_list_size(priv->links);
}
if (priv->links != NULL && priv->number_of_links > 0) {
GIRARA_LIST_FOREACH(priv->links, zathura_link_t*, iter, link)
zathura_rectangle_t rect = recalc_rectangle(priv->page, link->position);
if (rect.x1 <= button->x && rect.x2 >= button->x
&& rect.y1 <= button->y && rect.y2 >= button->y) {
switch (link->type) {
case ZATHURA_LINK_TO_PAGE:
page_set_delayed(priv->page->document->zathura, link->target.page_number);
return false;
case ZATHURA_LINK_EXTERNAL:
girara_xdg_open(link->target.value);
return false;
}
}
GIRARA_LIST_FOREACH_END(priv->links, zathura_link_t*, iter, link);
}
} else {
redraw_rect(ZATHURA_PAGE(widget), &priv->selection);
zathura_rectangle_t tmp = priv->selection;
tmp.x1 /= priv->page->document->scale;
tmp.x2 /= priv->page->document->scale;
tmp.y1 /= priv->page->document->scale;
tmp.y2 /= priv->page->document->scale;
char* text = zathura_page_get_text(priv->page, tmp, NULL);
if (text != NULL) {
gtk_clipboard_set_text(gtk_clipboard_get(GDK_SELECTION_PRIMARY), text, -1);
g_free(text);
}
}
priv->selection.x1 = -1;
priv->selection.y1 = -1;
priv->selection.x2 = -1;
priv->selection.y2 = -1;
return false;
}
static gboolean
cb_zathura_page_widget_motion_notify(GtkWidget* widget, GdkEventMotion* event)
{
g_return_val_if_fail(widget != NULL, false);
g_return_val_if_fail(event != NULL, false);
if ((event->state & GDK_BUTTON1_MASK) == 0) {
return false;
}
zathura_page_widget_private_t* priv = ZATHURA_PAGE_GET_PRIVATE(widget);
zathura_rectangle_t tmp = priv->selection;
if (event->x < priv->selection.x1) {
tmp.x1 = event->x;
} else {
tmp.x2 = event->x;
}
if (event->y < priv->selection.y1) {
tmp.y1 = event->y;
} else {
tmp.y2 = event->y;
}
redraw_rect(ZATHURA_PAGE(widget), &priv->selection);
redraw_rect(ZATHURA_PAGE(widget), &tmp);
priv->selection = tmp;
return false;
}

81
page_widget.h Normal file
View file

@ -0,0 +1,81 @@
/* See LICENSE file for license and copyright information */
#ifndef PAGE_WIDGET_H
#define PAGE_WIDGET_H
#include <gtk/gtk.h>
#include "document.h"
/**
* The page view widget. The widget handles all the rendering on its own. It
* only has to be resized. The widget also manages and handles all the
* rectangles for highlighting.
*
* Before the properties contain the correct values, 'draw-links' has to be set
* to TRUE at least one time.
* */
typedef struct zathura_page_widget_s ZathuraPage;
typedef struct zathura_page_widget_class_s ZathuraPageClass;
struct zathura_page_widget_s {
GtkDrawingArea parent;
};
struct zathura_page_widget_class_s {
GtkDrawingAreaClass parent_class;
};
#define ZATHURA_TYPE_PAGE \
(zathura_page_widget_get_type ())
#define ZATHURA_PAGE(obj) \
(G_TYPE_CHECK_INSTANCE_CAST ((obj), ZATHURA_TYPE_PAGE, ZathuraPage))
#define ZATHURA_PAGE_CLASS(obj) \
(G_TYPE_CHECK_CLASS_CAST ((obj), ZATHURA_PAGE, ZathuraPageClass))
#define ZATHURA_IS_PAGE(obj) \
(G_TYPE_CHECK_INSTANCE_TYPE ((obj), ZATHURA_PAGE))
#define ZATHURA_IS_PAGE_WDIGET_CLASS(obj) \
(G_TYPE_CHECK_CLASS_TYPE ((obj), ZATHURA_TYPE_PAGE))
#define ZATHURA_PAGE_GET_CLASS \
(G_TYPE_INSTANCE_GET_CLASS ((obj), ZATHURA_TYPE_PAGE, ZathuraPageclass))
/**
* Returns the type of the page view widget.
* @return the type
*/
GType zathura_page_widget_get_type(void);
/**
* Create a page view widget.
* @param page the page to be displayed
* @return a page view widget
*/
GtkWidget* zathura_page_widget_new(zathura_page_t* page);
/**
* Update the widget's surface. This should only be called from the render
* thread.
* @param widget the widget
* @param surface the new surface
*/
void zathura_page_widget_update_surface(ZathuraPage* widget, cairo_surface_t* surface);
/**
* Draw a rectangle to mark links or search results
* @param widget the widget
* @param rectangle the rectangle
* @param linkid the link id if it's a link, -1 otherwise
*/
void zathura_page_widget_draw_rectangle(ZathuraPage* widget, zathura_rectangle_t* rectangle, int linkid);
/**
* Clear all rectangles.
* @param widget the widget
*/
void zathura_page_widget_clear_rectangles(ZathuraPage* widget);
/**
* Returns the zathura link object at the given index
*
* @param widget the widget
* @param index Index of the link
* @return Link object or NULL if an error occured
*/
zathura_link_t* zathura_page_widget_link_get(ZathuraPage* widget, unsigned int index);
#endif

70
print.c
View file

@ -1,5 +1,11 @@
/* See LICENSE file for license and copyright information */
#include "print.h"
#include "document.h"
#include "render.h"
#include <girara/utils.h>
#include <girara/statusbar.h>
void
print(zathura_t* zathura)
@ -24,15 +30,23 @@ print(zathura_t* zathura)
/* print operation signals */
g_signal_connect(print_operation, "draw-page", G_CALLBACK(cb_print_draw_page), zathura);
g_signal_connect(print_operation, "end-print", G_CALLBACK(cb_print_end), zathura);
/* print */
GtkPrintOperationResult result = gtk_print_operation_run(print_operation,
GTK_PRINT_OPERATION_ACTION_PRINT_DIALOG, NULL, NULL);
if (result == GTK_PRINT_OPERATION_RESULT_APPLY) {
if (zathura->print.settings != NULL) {
g_object_unref(zathura->print.settings);
}
if (zathura->print.page_setup != NULL) {
g_object_unref(zathura->print.page_setup);
}
/* save previous settings */
zathura->print.settings = gtk_print_operation_get_print_settings(print_operation);
zathura->print.page_setup = gtk_print_operation_get_default_page_setup(print_operation);
zathura->print.settings = g_object_ref(gtk_print_operation_get_print_settings(print_operation));
zathura->print.page_setup = g_object_ref(gtk_print_operation_get_default_page_setup(print_operation));
} else if (result == GTK_PRINT_OPERATION_RESULT_ERROR) {
girara_error("Error occured while printing progress");
}
@ -41,43 +55,39 @@ print(zathura_t* zathura)
}
void
cb_print_begin(GtkPrintOperation* UNUSED(print_operation), GtkPrintContext*
UNUSED(context), zathura_t* UNUSED(zathura))
cb_print_end(GtkPrintOperation* UNUSED(print_operation), GtkPrintContext*
UNUSED(context), zathura_t* zathura)
{
if (zathura == NULL || zathura->ui.session == NULL || zathura->document == NULL
|| zathura->document->file_path == NULL) {
return;
}
girara_statusbar_item_set_text(zathura->ui.session,
zathura->ui.statusbar.file, zathura->document->file_path);
}
void
cb_print_draw_page(GtkPrintOperation* UNUSED(print_operation), GtkPrintContext*
context, gint page_number, zathura_t* zathura)
{
/* TODO: Implement with cairo */
/*cairo_t* cairo = gtk_print_context_get_cairo_context(context);*/
if (context == NULL || zathura == NULL || zathura->document->pages == NULL ||
zathura->ui.session == NULL || zathura->ui.statusbar.file == NULL) {
return;
}
/*girara_info("Printing page %d", page_number);*/
/* update statusbar */
char* tmp = g_strdup_printf("Printing %d...", page_number);
girara_statusbar_item_set_text(zathura->ui.session,
zathura->ui.statusbar.file, tmp);
g_free(tmp);
/*zathura_page_t* page = zathura->document->pages[page_number];*/
/* render page */
cairo_t* cairo = gtk_print_context_get_cairo_context(context);
zathura_page_t* page = zathura->document->pages[page_number];
if (cairo == NULL || page == NULL) {
return;
}
/*double requested_with = gtk_print_context_get_width(context);*/
/*double tmp_scale = zathura->document->scale;*/
/*zathura->document->scale = requested_with / page->width;*/
/*g_static_mutex_lock(&(page->lock));*/
/*zathura_image_buffer_t* image_buffer = zathura_page_render(page);*/
/*g_static_mutex_unlock(&(page->lock));*/
/*for (unsigned int y = 0; y < image_buffer->height; y++) {*/
/*unsigned char* src = image_buffer->data + y * image_buffer->rowstride;*/
/*for (unsigned int x = 0; x < image_buffer->width; x++) {*/
/*if (src[0] != 255 && src[1] != 255 && src[2] != 255) {*/
/*cairo_set_source_rgb(cairo, src[0], src[1], src[2]);*/
/*cairo_rectangle(cairo, x, y, 1, 1);*/
/*cairo_fill(cairo);*/
/*}*/
/*src += 3;*/
/*}*/
/*}*/
/*zathura->document->scale = tmp_scale;*/
zathura_page_render(page, cairo, true);
}

10
print.h
View file

@ -23,4 +23,14 @@ void print(zathura_t* zathura);
void cb_print_draw_page(GtkPrintOperation* print_operation, GtkPrintContext*
context, gint page_number, zathura_t* zathura);
/**
* Emitted after all pages have been rendered
*
* @param print_operation Print operation
* @param context Print context
* @param zathura Zathura object
*/
void cb_print_end(GtkPrintOperation* print_operation, GtkPrintContext* context,
zathura_t* zathura);
#endif // PRINT_H

136
render.c
View file

@ -1,6 +1,16 @@
/* See LICENSE file for license and copyright information */
#include <math.h>
#include <girara/datastructures.h>
#include <girara/utils.h>
#include <girara/session.h>
#include <girara/settings.h>
#include "render.h"
#include "zathura.h"
#include "document.h"
#include "page_widget.h"
#include "utils.h"
void* render_job(void* data);
bool render(zathura_t* zathura, zathura_page_t* page);
@ -13,11 +23,11 @@ render_job(void* data)
while (true) {
g_mutex_lock(render_thread->lock);
if (girara_list_size(render_thread->list) <= 0) {
if (girara_list_size(render_thread->list) == 0) {
g_cond_wait(render_thread->cond, render_thread->lock);
}
if (girara_list_size(render_thread->list) <= 0) {
if (girara_list_size(render_thread->list) == 0) {
/*
* We've been signaled with g_cond_signal(), but the list
* is still empty. This means that the signal came from
@ -43,16 +53,9 @@ render_job(void* data)
render_thread_t*
render_init(zathura_t* zathura)
{
render_thread_t* render_thread = malloc(sizeof(render_thread_t));
if (!render_thread) {
goto error_ret;
}
render_thread_t* render_thread = g_malloc0(sizeof(render_thread_t));
/* init */
render_thread->list = NULL;
render_thread->thread = NULL;
render_thread->cond = NULL;
render_thread->zathura = zathura;
/* setup */
@ -96,9 +99,7 @@ error_free:
g_mutex_free(render_thread->lock);
}
free(render_thread);
error_ret:
g_free(render_thread);
return NULL;
}
@ -128,7 +129,7 @@ render_free(render_thread_t* render_thread)
bool
render_page(render_thread_t* render_thread, zathura_page_t* page)
{
if (!render_thread || !page || !render_thread->list || page->surface) {
if (!render_thread || !page || !render_thread->list) {
return false;
}
@ -150,24 +151,15 @@ render(zathura_t* zathura, zathura_page_t* page)
}
gdk_threads_enter();
g_static_mutex_lock(&(page->lock));
/* create cairo surface */
unsigned int page_width = 0;
unsigned int page_height = 0;
if (page->document->rotate == 0 || page->document->rotate == 180) {
page_width = page->width * zathura->document->scale;
page_height = page->height * zathura->document->scale;
} else {
page_width = page->height * zathura->document->scale;
page_height = page->width * zathura->document->scale;
}
page_calc_height_width(page, &page_height, &page_width, false);
cairo_surface_t* surface = cairo_image_surface_create(CAIRO_FORMAT_RGB24, page_width, page_height);
if (surface == NULL) {
g_static_mutex_unlock(&(page->lock));
gdk_threads_leave();
return false;
}
@ -176,7 +168,6 @@ render(zathura_t* zathura, zathura_page_t* page)
if (cairo == NULL) {
cairo_surface_destroy(surface);
g_static_mutex_unlock(&(page->lock));
gdk_threads_leave();
return false;
}
@ -188,26 +179,13 @@ render(zathura_t* zathura, zathura_page_t* page)
cairo_restore(cairo);
cairo_save(cairo);
switch(page->document->rotate) {
case 90:
cairo_translate(cairo, page_width, 0);
break;
case 180:
cairo_translate(cairo, page_width, page_height);
break;
case 270:
cairo_translate(cairo, 0, page_height);
break;
if (fabs(zathura->document->scale - 1.0f) > FLT_EPSILON) {
cairo_scale(cairo, zathura->document->scale, zathura->document->scale);
}
if (page->document->rotate != 0) {
cairo_rotate(cairo, page->document->rotate * G_PI / 180.0);
}
if (zathura_page_render(page, cairo) == false) {
if (zathura_page_render(page, cairo, false) != ZATHURA_PLUGIN_ERROR_OK) {
cairo_destroy(cairo);
cairo_surface_destroy(surface);
g_static_mutex_unlock(&(page->lock));
gdk_threads_leave();
return false;
}
@ -215,7 +193,7 @@ render(zathura_t* zathura, zathura_page_t* page)
cairo_restore(cairo);
cairo_destroy(cairo);
int rowstride = cairo_image_surface_get_stride(surface);
const int rowstride = cairo_image_surface_get_stride(surface);
unsigned char* image = cairo_image_surface_get_data(surface);
/* recolor */
@ -251,12 +229,9 @@ render(zathura_t* zathura, zathura_page_t* page)
}
}
/* draw to gtk widget */
page->surface = surface;
gtk_widget_set_size_request(page->drawing_area, page_width, page_height);
gtk_widget_queue_draw(page->drawing_area);
/* update the widget */
zathura_page_widget_update_surface(ZATHURA_PAGE(page->drawing_area), surface);
g_static_mutex_unlock(&(page->lock));
gdk_threads_leave();
return true;
@ -271,66 +246,11 @@ render_all(zathura_t* zathura)
/* unmark all pages */
for (unsigned int page_id = 0; page_id < zathura->document->number_of_pages; page_id++) {
cairo_surface_destroy(zathura->document->pages[page_id]->surface);
zathura->document->pages[page_id]->surface = NULL;
}
zathura_page_t* page = zathura->document->pages[page_id];
unsigned int page_height = 0, page_width = 0;
page_calc_height_width(page, &page_height, &page_width, true);
/* redraw current page */
GtkAdjustment* view_vadjustment = gtk_scrolled_window_get_vadjustment(GTK_SCROLLED_WINDOW(zathura->ui.session->gtk.view));
cb_view_vadjustment_value_changed(view_vadjustment, zathura);
}
gboolean
page_expose_event(GtkWidget* UNUSED(widget), GdkEventExpose* UNUSED(event),
gpointer data)
{
zathura_page_t* page = data;
if (page == NULL) {
return FALSE;
}
g_static_mutex_lock(&(page->lock));
cairo_t* cairo = gdk_cairo_create(page->drawing_area->window);
if (cairo == NULL) {
girara_error("Could not retreive cairo object");
g_static_mutex_unlock(&(page->lock));
return FALSE;
}
if (page->surface != NULL) {
cairo_set_source_surface(cairo, page->surface, 0, 0);
cairo_paint(cairo);
} else {
/* set background color */
cairo_set_source_rgb(cairo, 255, 255, 255);
cairo_rectangle(cairo, 0, 0, page->width * page->document->scale, page->height * page->document->scale);
cairo_fill(cairo);
/* write text */
cairo_set_source_rgb(cairo, 0, 0, 0);
const char* text = "Loading...";
cairo_select_font_face(cairo, "Sans", CAIRO_FONT_SLANT_NORMAL, CAIRO_FONT_WEIGHT_NORMAL);
cairo_set_font_size(cairo, 16.0);
cairo_text_extents_t extents;
cairo_text_extents(cairo, text, &extents);
double x = (page->width * page->document->scale) / 2 - (extents.width / 2 + extents.x_bearing);
double y = (page->height * page->document->scale) / 2 - (extents.height / 2 + extents.y_bearing);
cairo_move_to(cairo, x, y);
cairo_show_text(cairo, text);
/* render real page */
render_page(page->document->zathura->sync.render_thread, page);
/* update statusbar */
}
cairo_destroy(cairo);
page->document->current_page_number = page->number;
statusbar_page_number_update(page->document->zathura);
g_static_mutex_unlock(&(page->lock));
return TRUE;
gtk_widget_set_size_request(page->drawing_area, page_width, page_height);
gtk_widget_queue_resize(page->drawing_area);
}
}

View file

@ -5,24 +5,24 @@
#include <stdbool.h>
#include <stdlib.h>
#include <girara-datastructures.h>
#include <girara/types.h>
#include "zathura.h"
#include "callbacks.h"
struct render_thread_s
{
girara_list_t* list; /**> The list of pages */
GThread* thread; /**> The thread object */
GMutex* lock; /**> Lock */
GCond* cond; /**> Condition */
zathura_t* zathura; /**> Zathura object */
girara_list_t* list; /**< The list of pages */
GThread* thread; /**< The thread object */
GMutex* lock; /**< Lock */
GCond* cond; /**< Condition */
zathura_t* zathura; /**< Zathura object */
};
/**
* This function initializes a render thread
*
* @param Zathura object
* @param zathura object
* @return The render thread object or NULL if an error occured
*/
render_thread_t* render_init(zathura_t* zathura);

View file

@ -1,6 +1,10 @@
/* See LICENSE file for license and copyright information */
#include <girara.h>
#include <girara/session.h>
#include <girara/settings.h>
#include <girara/datastructures.h>
#include <girara/shortcuts.h>
#include <girara/utils.h>
#include <gtk/gtk.h>
#include "callbacks.h"
@ -9,30 +13,97 @@
#include "zathura.h"
#include "render.h"
#include "utils.h"
#include "page_widget.h"
bool
sc_abort(girara_session_t* session, girara_argument_t* UNUSED(argument),
unsigned int UNUSED(t))
girara_event_t* UNUSED(event), unsigned int UNUSED(t))
{
g_return_val_if_fail(session != NULL, false);
g_return_val_if_fail(session->global.data != NULL, false);
zathura_t* zathura = session->global.data;
if (zathura->document != NULL) {
for (unsigned int page_id = 0; page_id < zathura->document->number_of_pages; ++page_id) {
zathura_page_t* page = zathura->document->pages[page_id];
if (page == NULL) {
continue;
}
g_object_set(page->drawing_area, "draw-links", FALSE, NULL);
}
}
girara_mode_set(session, session->modes.normal);
girara_sc_abort(session, NULL, NULL, 0);
return false;
}
bool
sc_adjust_window(girara_session_t* session, girara_argument_t* UNUSED(argument),
unsigned int UNUSED(t))
sc_adjust_window(girara_session_t* session, girara_argument_t* argument,
girara_event_t* UNUSED(event), unsigned int UNUSED(t))
{
g_return_val_if_fail(session != NULL, false);
g_return_val_if_fail(session->global.data != NULL, false);
zathura_t* zathura = session->global.data;
g_return_val_if_fail(argument != NULL, false);
unsigned int pages_per_row = 1;
girara_setting_get(session, "pages-per-row", &pages_per_row);
if (zathura->ui.page_widget == NULL || zathura->document == NULL) {
goto error_ret;
}
zathura->document->adjust_mode = argument->n;
/* get window size */
GtkAllocation allocation;
gtk_widget_get_allocation(session->gtk.view, &allocation);
gint width = allocation.width;
gint height = allocation.height;
/* calculate total width and max-height */
double total_width = 0;
double max_height = 0;
for (unsigned int page_id = 0; page_id < pages_per_row; page_id++) {
if (page_id == zathura->document->number_of_pages) {
break;
}
zathura_page_t* page = zathura->document->pages[page_id];
if (page == NULL) {
goto error_ret;
}
if (page->height > max_height) {
max_height = page->height;
}
total_width += page->width;
}
if (argument->n == ADJUST_WIDTH) {
zathura->document->scale = width / total_width;
} else if (argument->n == ADJUST_BESTFIT) {
zathura->document->scale = height / max_height;
} else {
goto error_ret;
}
/* re-render all pages */
render_all(zathura);
error_ret:
return false;
}
bool
sc_change_mode(girara_session_t* session, girara_argument_t* argument, unsigned
int UNUSED(t))
sc_change_mode(girara_session_t* session, girara_argument_t* argument,
girara_event_t* UNUSED(event), unsigned int UNUSED(t))
{
g_return_val_if_fail(session != NULL, false);
@ -43,15 +114,51 @@ sc_change_mode(girara_session_t* session, girara_argument_t* argument, unsigned
bool
sc_follow(girara_session_t* session, girara_argument_t* UNUSED(argument),
unsigned int UNUSED(t))
girara_event_t* UNUSED(event), unsigned int UNUSED(t))
{
g_return_val_if_fail(session != NULL, false);
g_return_val_if_fail(session->global.data != NULL, false);
zathura_t* zathura = session->global.data;
if (zathura->document == NULL) {
return false;
}
/* set pages to draw links */
bool show_links = false;
unsigned int page_offset = 0;
for (unsigned int page_id = 0; page_id < zathura->document->number_of_pages; page_id++) {
zathura_page_t* page = zathura->document->pages[page_id];
if (page == NULL) {
continue;
}
g_object_set(page->drawing_area, "search-results", NULL, NULL);
if (page->visible == true) {
g_object_set(page->drawing_area, "draw-links", TRUE, NULL);
int number_of_links = 0;
g_object_get(page->drawing_area, "number-of-links", &number_of_links, NULL);
if (number_of_links != 0) {
show_links = true;
}
g_object_set(page->drawing_area, "offset-links", page_offset, NULL);
page_offset += number_of_links;
} else {
g_object_set(page->drawing_area, "draw-links", FALSE, NULL);
}
}
/* ask for input */
if (show_links == true) {
girara_dialog(zathura->ui.session, "Follow link:", FALSE, NULL, (girara_callback_inputbar_activate_t) cb_sc_follow, NULL);
}
return false;
}
bool
sc_goto(girara_session_t* session, girara_argument_t* argument, unsigned int t)
sc_goto(girara_session_t* session, girara_argument_t* argument, girara_event_t* UNUSED(event), unsigned int t)
{
g_return_val_if_fail(session != NULL, false);
g_return_val_if_fail(session->global.data != NULL, false);
@ -60,27 +167,113 @@ sc_goto(girara_session_t* session, girara_argument_t* argument, unsigned int t)
g_return_val_if_fail(zathura->document != NULL, false);
if (argument->n == TOP) {
girara_argument_t arg = { TOP, NULL };
sc_scroll(session, &arg, 0);
return false;
page_set(zathura, 0);
} else {
if (t == 0) {
girara_argument_t arg = { BOTTOM, NULL };
sc_scroll(session, &arg, 0);
return true;
page_set(zathura, zathura->document->number_of_pages - 1);
} else {
page_set(zathura, t - 1);
}
page_set(zathura, t - 1);
}
return false;
}
bool
sc_navigate(girara_session_t* session, girara_argument_t* argument, unsigned int
UNUSED(t))
sc_mouse_scroll(girara_session_t* session, girara_argument_t* argument, girara_event_t* event, unsigned int t)
{
g_return_val_if_fail(session != NULL, false);
g_return_val_if_fail(session->global.data != NULL, false);
zathura_t* zathura = session->global.data;
g_return_val_if_fail(argument != NULL, false);
g_return_val_if_fail(event != NULL, false);
static int x = 0;
static int y = 0;
if (zathura->document == NULL) {
return false;
}
/* scroll event */
if (event->type == GIRARA_EVENT_SCROLL) {
switch (event->direction) {
case GIRARA_SCROLL_UP:
argument->n = UP;
break;
case GIRARA_SCROLL_DOWN:
argument->n = DOWN;
break;
case GIRARA_SCROLL_LEFT:
argument->n = LEFT;
break;
case GIRARA_SCROLL_RIGHT:
argument->n = RIGHT;
break;
}
return sc_scroll(session, argument, NULL, t);
} else if (event->type == GIRARA_EVENT_BUTTON_PRESS) {
x = event->x;
y = event->y;
} else if (event->type == GIRARA_EVENT_BUTTON_RELEASE) {
x = 0;
y = 0;
} else if (event->type == GIRARA_EVENT_MOTION_NOTIFY) {
GtkAdjustment* x_adj =
gtk_scrolled_window_get_hadjustment(GTK_SCROLLED_WINDOW(session->gtk.view));
GtkAdjustment* y_adj =
gtk_scrolled_window_get_vadjustment(GTK_SCROLLED_WINDOW(session->gtk.view));
if (x_adj == NULL || y_adj == NULL) {
return false;
}
set_adjustment(x_adj, gtk_adjustment_get_value(x_adj) - (event->x - x));
set_adjustment(y_adj, gtk_adjustment_get_value(y_adj) - (event->y - y));
x = event->x;
y = event->y;
}
return false;
}
bool
sc_mouse_zoom(girara_session_t* session, girara_argument_t* argument, girara_event_t* event, unsigned int t)
{
g_return_val_if_fail(session != NULL, false);
g_return_val_if_fail(session->global.data != NULL, false);
zathura_t* zathura = session->global.data;
g_return_val_if_fail(argument != NULL, false);
g_return_val_if_fail(event != NULL, false);
if (zathura->document == NULL) {
return false;
}
/* scroll event */
if (event->type == GIRARA_EVENT_SCROLL) {
switch (event->direction) {
case GIRARA_SCROLL_UP:
argument->n = ZOOM_IN;
break;
case GIRARA_SCROLL_DOWN:
argument->n = ZOOM_OUT;
break;
default:
return false;
}
return sc_zoom(session, argument, NULL, t);
}
return false;
}
bool
sc_navigate(girara_session_t* session, girara_argument_t* argument,
girara_event_t* UNUSED(event), unsigned int t)
{
g_return_val_if_fail(session != NULL, false);
g_return_val_if_fail(session->global.data != NULL, false);
@ -91,10 +284,11 @@ sc_navigate(girara_session_t* session, girara_argument_t* argument, unsigned int
unsigned int number_of_pages = zathura->document->number_of_pages;
unsigned int new_page = zathura->document->current_page_number;
t = (t == 0) ? 1 : t;
if (argument->n == NEXT) {
new_page = (new_page + 1) % number_of_pages;
new_page = (new_page + t) % number_of_pages;
} else if (argument->n == PREVIOUS) {
new_page = (new_page + number_of_pages - 1) % number_of_pages;
new_page = (new_page + number_of_pages - t) % number_of_pages;
}
page_set(zathura, new_page);
@ -104,7 +298,7 @@ sc_navigate(girara_session_t* session, girara_argument_t* argument, unsigned int
bool
sc_recolor(girara_session_t* session, girara_argument_t* UNUSED(argument),
unsigned int UNUSED(t))
girara_event_t* UNUSED(event), unsigned int UNUSED(t))
{
g_return_val_if_fail(session != NULL, false);
g_return_val_if_fail(session->global.data != NULL, false);
@ -118,34 +312,58 @@ sc_recolor(girara_session_t* session, girara_argument_t* UNUSED(argument),
bool
sc_reload(girara_session_t* session, girara_argument_t* UNUSED(argument),
unsigned int UNUSED(t))
girara_event_t* UNUSED(event), unsigned int UNUSED(t))
{
g_return_val_if_fail(session != NULL, false);
g_return_val_if_fail(session->global.data != NULL, false);
zathura_t* zathura = session->global.data;
if (zathura->document == NULL || zathura->document->file_path == NULL) {
return false;
}
/* save current document path and password */
char* path = g_strdup(zathura->document->file_path);
char* password = zathura->document->password ? g_strdup(zathura->document->password) : NULL;
/* close current document */
document_close(zathura);
/* reopen document */
document_open(zathura, path, password);
/* clean up */
g_free(path);
g_free(password);
return false;
}
bool
sc_rotate(girara_session_t* session, girara_argument_t* UNUSED(argument),
unsigned int UNUSED(t))
girara_event_t* UNUSED(event), unsigned int UNUSED(t))
{
g_return_val_if_fail(session != NULL, false);
g_return_val_if_fail(session->global.data != NULL, false);
zathura_t* zathura = session->global.data;
g_return_val_if_fail(zathura->document != NULL, false);
unsigned int page_number = zathura->document->current_page_number;
/* update rotate value */
zathura->document->rotate = (zathura->document->rotate + 90) % 360;
/* render all pages again */
render_all(zathura);
page_set_delayed(zathura, page_number);
return false;
}
bool
sc_scroll(girara_session_t* session, girara_argument_t* argument, unsigned int
UNUSED(t))
sc_scroll(girara_session_t* session, girara_argument_t* argument,
girara_event_t* UNUSED(event), unsigned int UNUSED(t))
{
g_return_val_if_fail(session != NULL, false);
g_return_val_if_fail(session->global.data != NULL, false);
@ -156,38 +374,39 @@ sc_scroll(girara_session_t* session, girara_argument_t* argument, unsigned int
}
GtkAdjustment* adjustment = NULL;
if ( (argument->n == LEFT) || (argument->n == RIGHT) )
adjustment = gtk_scrolled_window_get_hadjustment(GTK_SCROLLED_WINDOW(zathura->ui.session->gtk.view));
else
adjustment = gtk_scrolled_window_get_vadjustment(GTK_SCROLLED_WINDOW(zathura->ui.session->gtk.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;
gdouble scroll_step = 40;
if ( (argument->n == LEFT) || (argument->n == RIGHT) ) {
adjustment = gtk_scrolled_window_get_hadjustment(GTK_SCROLLED_WINDOW(session->gtk.view));
} else {
adjustment = gtk_scrolled_window_get_vadjustment(GTK_SCROLLED_WINDOW(session->gtk.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;
float scroll_step = 40;
girara_setting_get(session, "scroll-step", &scroll_step);
gdouble new_value;
switch(argument->n)
{
switch(argument->n) {
case FULL_UP:
new_value = (value - view_size) < 0 ? 0 : (value - view_size);
new_value = value - view_size;
break;
case FULL_DOWN:
new_value = (value + view_size) > max ? max : (value + view_size);
new_value = value + view_size;
break;
case HALF_UP:
new_value = (value - (view_size / 2)) < 0 ? 0 : (value - (view_size / 2));
new_value = value - (view_size / 2);
break;
case HALF_DOWN:
new_value = (value + (view_size / 2)) > max ? max : (value + (view_size / 2));
new_value = value + (view_size / 2);
break;
case LEFT:
case UP:
new_value = (value - scroll_step) < 0 ? 0 : (value - scroll_step);
new_value = value - scroll_step;
break;
case RIGHT:
case DOWN:
new_value = (value + scroll_step) > max ? max : (value + scroll_step);
new_value = value + scroll_step;
break;
case TOP:
new_value = 0;
@ -196,17 +415,17 @@ sc_scroll(girara_session_t* session, girara_argument_t* argument, unsigned int
new_value = max;
break;
default:
new_value = 0;
new_value = value;
}
gtk_adjustment_set_value(adjustment, new_value);
set_adjustment(adjustment, new_value);
return false;
}
bool
sc_search(girara_session_t* session, girara_argument_t* argument, unsigned int
UNUSED(t))
sc_search(girara_session_t* session, girara_argument_t* argument,
girara_event_t* UNUSED(event), unsigned int UNUSED(t))
{
g_return_val_if_fail(session != NULL, false);
g_return_val_if_fail(session->global.data != NULL, false);
@ -214,12 +433,79 @@ sc_search(girara_session_t* session, girara_argument_t* argument, unsigned int
g_return_val_if_fail(argument != NULL, false);
g_return_val_if_fail(zathura->document != NULL, false);
const int num_pages = zathura->document->number_of_pages;
const int cur_page = zathura->document->current_page_number;
int diff = argument->n == FORWARD ? 1 : -1;
zathura_page_t* target_page = NULL;
int target_idx = 0;
for (int page_id = 0; page_id < num_pages; ++page_id) {
int tmp = cur_page + diff * page_id;
zathura_page_t* page = zathura->document->pages[(tmp + num_pages) % num_pages];
if (page == NULL) {
continue;
}
int num_search_results = 0, current = -1;
g_object_get(page->drawing_area, "search-current", &current,
"search-length", &num_search_results, NULL);
if (num_search_results == 0 || current == -1) {
continue;
}
if (diff == 1 && current < num_search_results - 1) {
/* the next result is on the same page */
target_page = page;
target_idx = current + 1;
// g_object_set(page->drawing_area, "search-current", current + 1, NULL);
} else if (diff == -1 && current >= 1) {
// g_object_set(page->drawing_area, "search-current", current - 1, NULL);
target_page = page;
target_idx = current - 1;
} else {
/* the next result is on a different page */
g_object_set(page->drawing_area, "search-current", -1, NULL);
for (int npage_id = 1; page_id < num_pages; ++npage_id) {
int ntmp = cur_page + diff * (page_id + npage_id);
zathura_page_t* npage = zathura->document->pages[(ntmp + 2*num_pages) % num_pages];
g_object_get(npage->drawing_area, "search-length", &num_search_results, NULL);
if (num_search_results != 0) {
target_page = npage;
target_idx = diff == 1 ? 0 : num_search_results - 1;
break;
}
}
}
break;
}
if (target_page != NULL) {
girara_list_t* results = NULL;
g_object_set(target_page->drawing_area, "search-current", target_idx, NULL);
g_object_get(target_page->drawing_area, "search-results", &results, NULL);
zathura_rectangle_t* rect = girara_list_nth(results, target_idx);
zathura_rectangle_t rectangle = recalc_rectangle(target_page, *rect);
page_offset_t offset;
page_calculate_offset(target_page, &offset);
GtkAdjustment* view_vadjustment = gtk_scrolled_window_get_vadjustment(GTK_SCROLLED_WINDOW(zathura->ui.session->gtk.view));
GtkAdjustment* view_hadjustment = gtk_scrolled_window_get_hadjustment(GTK_SCROLLED_WINDOW(zathura->ui.session->gtk.view));
int x = offset.x - gtk_adjustment_get_page_size(view_hadjustment) / 2 + rectangle.x1;
int y = offset.y - gtk_adjustment_get_page_size(view_vadjustment) / 2 + rectangle.y1;
set_adjustment(view_hadjustment, x);
set_adjustment(view_vadjustment, y);
}
return false;
}
bool
sc_navigate_index(girara_session_t* session, girara_argument_t* argument,
unsigned int UNUSED(t))
girara_event_t* UNUSED(event), unsigned int UNUSED(t))
{
g_return_val_if_fail(session != NULL, false);
g_return_val_if_fail(session->global.data != NULL, false);
@ -227,23 +513,95 @@ sc_navigate_index(girara_session_t* session, girara_argument_t* argument,
g_return_val_if_fail(argument != NULL, false);
g_return_val_if_fail(zathura->document != NULL, false);
if(zathura->ui.index == NULL) {
return false;
}
GtkTreeView *tree_view = gtk_container_get_children(GTK_CONTAINER(zathura->ui.index))->data;
GtkTreePath *path;
gtk_tree_view_get_cursor(tree_view, &path, NULL);
if (path == NULL) {
return false;
}
GtkTreeModel *model = gtk_tree_view_get_model(tree_view);
GtkTreeIter iter;
GtkTreeIter child_iter;
gboolean is_valid_path = TRUE;
switch(argument->n) {
case UP:
if(gtk_tree_path_prev(path) == FALSE) {
is_valid_path = gtk_tree_path_up(path);
} else { /* row above */
while(gtk_tree_view_row_expanded(tree_view, path)) {
gtk_tree_model_get_iter(model, &iter, path);
/* select last child */
gtk_tree_model_iter_nth_child(model, &child_iter, &iter,
gtk_tree_model_iter_n_children(model, &iter)-1);
gtk_tree_path_free(path);
path = gtk_tree_model_get_path(model, &child_iter);
}
}
break;
case COLLAPSE:
if(!gtk_tree_view_collapse_row(tree_view, path)
&& gtk_tree_path_get_depth(path) > 1) {
gtk_tree_path_up(path);
gtk_tree_view_collapse_row(tree_view, path);
}
break;
case DOWN:
if(gtk_tree_view_row_expanded(tree_view, path)) {
gtk_tree_path_down(path);
} else {
do {
gtk_tree_model_get_iter(model, &iter, path);
if (gtk_tree_model_iter_next(model, &iter)) {
path = gtk_tree_model_get_path(model, &iter);
break;
}
} while((is_valid_path = (gtk_tree_path_get_depth(path) > 1))
&& gtk_tree_path_up(path));
}
break;
case EXPAND:
if(gtk_tree_view_expand_row(tree_view, path, FALSE)) {
gtk_tree_path_down(path);
}
break;
case SELECT:
cb_index_row_activated(tree_view, path, NULL, zathura);
return false;
}
if (is_valid_path) {
gtk_tree_view_set_cursor(tree_view, path, NULL, FALSE);
}
gtk_tree_path_free(path);
return false;
}
bool
sc_toggle_index(girara_session_t* session, girara_argument_t* argument, unsigned
int UNUSED(t))
sc_toggle_index(girara_session_t* session, girara_argument_t* UNUSED(argument),
girara_event_t* UNUSED(event), unsigned int UNUSED(t))
{
g_return_val_if_fail(session != NULL, false);
g_return_val_if_fail(session->global.data != NULL, false);
zathura_t* zathura = session->global.data;
g_return_val_if_fail(argument != NULL, false);
g_return_val_if_fail(zathura->document != NULL, false);
if (zathura->document == NULL) {
return false;
}
girara_tree_node_t* document_index = NULL;
GtkWidget* treeview = NULL;
GtkTreeModel* model = NULL;
GtkCellRenderer* renderer = NULL;
GtkCellRenderer* renderer2 = NULL;
if (zathura->ui.index == NULL) {
/* create new index widget */
@ -257,13 +615,13 @@ sc_toggle_index(girara_session_t* session, girara_argument_t* argument, unsigned
GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC);
/* create index */
document_index = zathura_document_index_generate(zathura->document);
document_index = zathura_document_index_generate(zathura->document, NULL);
if (document_index == NULL) {
// TODO: Error message
goto error_free;
}
model = GTK_TREE_MODEL(gtk_tree_store_new(2, G_TYPE_STRING, G_TYPE_POINTER));
model = GTK_TREE_MODEL(gtk_tree_store_new(3, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_POINTER));
if (model == NULL) {
goto error_free;
}
@ -280,27 +638,37 @@ sc_toggle_index(girara_session_t* session, girara_argument_t* argument, unsigned
goto error_free;
}
renderer2 = gtk_cell_renderer_text_new();
if (renderer2 == NULL) {
goto error_free;
}
document_index_build(model, NULL, document_index);
girara_node_free(document_index);
/* setup widget */
gtk_tree_view_insert_column_with_attributes(GTK_TREE_VIEW (treeview), 0, "Title", renderer, "markup", 0, NULL);
gtk_tree_view_insert_column_with_attributes(GTK_TREE_VIEW (treeview), 1, "Target", renderer2, "text", 1, NULL);
gtk_tree_view_set_headers_visible(GTK_TREE_VIEW(treeview), FALSE);
g_object_set(G_OBJECT(renderer), "ellipsize", PANGO_ELLIPSIZE_END, NULL);
g_object_set(G_OBJECT(gtk_tree_view_get_column(GTK_TREE_VIEW(treeview), 0)), "expand", TRUE, NULL);
gtk_tree_view_column_set_alignment(gtk_tree_view_get_column(GTK_TREE_VIEW(treeview), 1), 1.0f);
gtk_tree_view_set_cursor(GTK_TREE_VIEW(treeview), gtk_tree_path_new_first(), NULL, FALSE);
/*g_signal_connect(G_OBJECT(treeview), "row-activated", G_CALLBACK(cb_index_row_activated), NULL); TODO*/
g_signal_connect(G_OBJECT(treeview), "row-activated", G_CALLBACK(cb_index_row_activated), zathura);
gtk_container_add(GTK_CONTAINER(zathura->ui.index), treeview);
gtk_widget_show(treeview);
}
if (gtk_widget_get_visible(GTK_WIDGET(zathura->ui.index))) {
girara_set_view(session, zathura->ui.page_view);
girara_set_view(session, zathura->ui.page_widget_alignment);
gtk_widget_hide(GTK_WIDGET(zathura->ui.index));
girara_mode_set(zathura->ui.session, zathura->modes.normal);
} else {
girara_set_view(session, zathura->ui.index);
gtk_widget_show(GTK_WIDGET(zathura->ui.index));
girara_mode_set(zathura->ui.session, zathura->modes.index);
}
return false;
@ -323,15 +691,49 @@ error_ret:
bool
sc_toggle_fullscreen(girara_session_t* session, girara_argument_t*
UNUSED(argument), unsigned int UNUSED(t))
UNUSED(argument), girara_event_t* UNUSED(event), unsigned int UNUSED(t))
{
g_return_val_if_fail(session != NULL, false);
g_return_val_if_fail(session->global.data != NULL, false);
zathura_t* zathura = session->global.data;
static bool fullscreen = false;
static bool fullscreen = false;
static int pages_per_row = 1;
static double zoom = 1.0;
if (fullscreen) {
if (fullscreen == true) {
/* reset pages per row */
girara_setting_set(session, "pages-per-row", &pages_per_row);
/* show status bar */
gtk_widget_show(GTK_WIDGET(session->gtk.statusbar));
/* set full screen */
gtk_window_unfullscreen(GTK_WINDOW(session->gtk.window));
/* reset scale */
zathura->document->scale = zoom;
render_all(zathura);
} else {
/* backup pages per row */
girara_setting_get(session, "pages-per-row", &pages_per_row);
/* set single view */
int int_value = 1;
girara_setting_set(session, "pages-per-row", &int_value);
/* back up zoom */
zoom = zathura->document->scale;
/* adjust window */
girara_argument_t argument = { ADJUST_BESTFIT, NULL };
sc_adjust_window(session, &argument, NULL, 0);
/* hide status and inputbar */
gtk_widget_hide(GTK_WIDGET(session->gtk.inputbar));
gtk_widget_hide(GTK_WIDGET(session->gtk.statusbar));
/* set full screen */
gtk_window_fullscreen(GTK_WINDOW(session->gtk.window));
}
@ -341,24 +743,22 @@ sc_toggle_fullscreen(girara_session_t* session, girara_argument_t*
}
bool
sc_quit(girara_session_t* session, girara_argument_t* UNUSED(argument), unsigned
int UNUSED(t))
sc_quit(girara_session_t* session, girara_argument_t* UNUSED(argument),
girara_event_t* UNUSED(event), unsigned int UNUSED(t))
{
g_return_val_if_fail(session != NULL, false);
girara_argument_t arg = { GIRARA_HIDE, NULL };
girara_isc_completion(session, &arg, 0);
girara_isc_completion(session, &arg, NULL, 0);
cb_destroy(NULL, NULL);
gtk_main_quit();
return false;
}
bool
sc_zoom(girara_session_t* session, girara_argument_t* argument, unsigned int
UNUSED(t))
sc_zoom(girara_session_t* session, girara_argument_t* argument, girara_event_t*
UNUSED(event), unsigned int t)
{
g_return_val_if_fail(session != NULL, false);
g_return_val_if_fail(session->global.data != NULL, false);
@ -366,23 +766,43 @@ sc_zoom(girara_session_t* session, girara_argument_t* argument, unsigned int
g_return_val_if_fail(argument != NULL, false);
g_return_val_if_fail(zathura->document != NULL, false);
zathura->document->adjust_mode = ADJUST_NONE;
/* retreive zoom step value */
int* value = girara_setting_get(zathura->ui.session, "zoom-step");
if (value == NULL) {
return false;
}
int value = 1;
girara_setting_get(zathura->ui.session, "zoom-step", &value);
float zoom_step = *value / 100.0f;
float zoom_step = value / 100.0f;
float oldzoom = zathura->document->scale;
/* specify new zoom value */
if (argument->n == ZOOM_IN) {
zathura->document->scale += zoom_step;
} else if (argument->n == ZOOM_OUT) {
zathura->document->scale -= zoom_step;
} else if (argument->n == ZOOM_SPECIFIC) {
zathura->document->scale = t / 100.0f;
} else {
zathura->document->scale = 1.0;
}
/* zoom limitations */
if (zathura->document->scale < 0.1f) {
zathura->document->scale = 0.1f;
} else if (zathura->document->scale > 10.0f) {
zathura->document->scale = 10.0f;
}
/* keep position */
GtkAdjustment* view_vadjustment = gtk_scrolled_window_get_vadjustment(GTK_SCROLLED_WINDOW(zathura->ui.session->gtk.view));
GtkAdjustment* view_hadjustment = gtk_scrolled_window_get_hadjustment(GTK_SCROLLED_WINDOW(zathura->ui.session->gtk.view));
gdouble valx = gtk_adjustment_get_value(view_hadjustment) / oldzoom * zathura->document->scale;
gdouble valy = gtk_adjustment_get_value(view_vadjustment) / oldzoom * zathura->document->scale;
set_adjustment(view_hadjustment, valx);
set_adjustment(view_vadjustment, valy);
render_all(zathura);
return false;
}

View file

@ -3,166 +3,204 @@
#ifndef SHORTCUTS_H
#define SHORTCUTS_H
#include <girara.h>
#include <girara/types.h>
/**
* Abort the current action and return to normal mode
*
* @param session The used girara session
* @param argument The used argument
* @param event Girara event
* @param t Number of executions
* @return true if no error occured otherwise false
*/
bool sc_abort(girara_session_t* session, girara_argument_t* argument, unsigned int t);
bool sc_abort(girara_session_t* session, girara_argument_t* argument, girara_event_t* event, unsigned int t);
/**
* Adjust the rendered pages to the window
*
* @param session The used girara session
* @param argument The used argument
* @param event Girara event
* @param t Number of executions
* @return true if no error occured otherwise false
*/
bool sc_adjust_window(girara_session_t* session, girara_argument_t* argument, unsigned int t);
bool sc_adjust_window(girara_session_t* session, girara_argument_t* argument, girara_event_t* event, unsigned int t);
/**
* Change the current mode
*
* @param session The used girara session
* @param argument The used argument
* @param event Girara event
* @param t Number of executions
* @return true if no error occured otherwise false
*/
bool sc_change_mode(girara_session_t* session, girara_argument_t* argument, unsigned int t);
bool sc_change_mode(girara_session_t* session, girara_argument_t* argument, girara_event_t* event, unsigned int t);
/**
* Follow a link
*
* @param session The used girara session
* @param argument The used argument
* @param event Girara event
* @param t Number of executions
* @return true if no error occured otherwise false
*/
bool sc_follow(girara_session_t* session, girara_argument_t* argument, unsigned int t);
bool sc_follow(girara_session_t* session, girara_argument_t* argument, girara_event_t* event, unsigned int t);
/**
* Go to a specific page or position
*
* @param session The used girara session
* @param argument The used argument
* @param event Girara event
* @param t Number of executions
* @return true if no error occured otherwise false
*/
bool sc_goto(girara_session_t* session, girara_argument_t* argument, unsigned int t);
bool sc_goto(girara_session_t* session, girara_argument_t* argument, girara_event_t* event, unsigned int t);
/**
* Handle mouse events
*
* @param session The used girara session
* @param argument The used argument
* @param event Girara event
* @param t Number of executions
* @return true if no error occured otherwise false
*/
bool sc_mouse_scroll(girara_session_t* session, girara_argument_t* argument, girara_event_t* event, unsigned int t);
/**
* Handle mouse zoom events
*
* @param session The used girara session
* @param argument The used argument
* @param event Girara event
* @param t Number of executions
* @return true if no error occured otherwise false
*/
bool sc_mouse_zoom(girara_session_t* session, girara_argument_t* argument, girara_event_t* event, unsigned int t);
/**
* Navigate through the document
*
* @param session The used girara session
* @param argument The used argument
* @param event Girara event
* @param t Number of executions
* @return true if no error occured otherwise false
*/
bool sc_navigate(girara_session_t* session, girara_argument_t* argument, unsigned int t);
bool sc_navigate(girara_session_t* session, girara_argument_t* argument, girara_event_t* event, unsigned int t);
/**
* Recolor the pages
*
* @param session The used girara session
* @param argument The used argument
* @param event Girara event
* @param t Number of executions
* @return true if no error occured otherwise false
*/
bool sc_recolor(girara_session_t* session, girara_argument_t* argument, unsigned int t);
bool sc_recolor(girara_session_t* session, girara_argument_t* argument, girara_event_t* event, unsigned int t);
/**
* Reload the current document
*
* @param session The used girara session
* @param argument The used argument
* @param event Girara event
* @param t Number of executions
* @return true if no error occured otherwise false
*/
bool sc_reload(girara_session_t* session, girara_argument_t* argument, unsigned int t);
bool sc_reload(girara_session_t* session, girara_argument_t* argument, girara_event_t* event, unsigned int t);
/**
* Rotate the pages
*
* @param session The used girara session
* @param argument The used argument
* @param event Girara event
* @param t Number of executions
* @return true if no error occured otherwise false
*/
bool sc_rotate(girara_session_t* session, girara_argument_t* argument, unsigned int t);
bool sc_rotate(girara_session_t* session, girara_argument_t* argument, girara_event_t* event, unsigned int t);
/**
* Scroll through the pages
*
* @param session The used girara session
* @param argument The used argument
* @param event Girara event
* @param t Number of executions
* @return true if no error occured otherwise false
*/
bool sc_scroll(girara_session_t* session, girara_argument_t* argument, unsigned int t);
bool sc_scroll(girara_session_t* session, girara_argument_t* argument, girara_event_t* event, unsigned int t);
/**
* Search through the document for the latest search item
*
* @param session The used girara session
* @param argument The used argument
* @param event Girara event
* @param t Number of executions
* @return true if no error occured otherwise false
*/
bool sc_search(girara_session_t* session, girara_argument_t* argument, unsigned int t);
bool sc_search(girara_session_t* session, girara_argument_t* argument, girara_event_t* event, unsigned int t);
/**
* Navigate through the index of the document
*
* @param session The used girara session
* @param argument The used argument
* @param event Girara event
* @param t Number of executions
* @return true if no error occured otherwise false
*/
bool sc_navigate_index(girara_session_t* session, girara_argument_t* argument, unsigned int t);
bool sc_navigate_index(girara_session_t* session, girara_argument_t* argument, girara_event_t* event, unsigned int t);
/**
* Show/Hide the index of the document
*
* @param session The used girara session
* @param argument The used argument
* @param event Girara event
* @param t Number of executions
* @return true if no error occured otherwise false
*/
bool sc_toggle_index(girara_session_t* session, girara_argument_t* argument, unsigned int t);
bool sc_toggle_index(girara_session_t* session, girara_argument_t* argument, girara_event_t* event, unsigned int t);
/**
* Toggle fullscreen mode
*
* @param session The used girara session
* @param argument The used argument
* @param event Girara event
* @param t Number of executions
* @return true if no error occured otherwise false
*/
bool sc_toggle_fullscreen(girara_session_t* session, girara_argument_t* argument, unsigned int t);
bool sc_toggle_fullscreen(girara_session_t* session, girara_argument_t* argument, girara_event_t* event, unsigned int t);
/**
* Quit zathura
*
* @param session The used girara session
* @param argument The used argument
* @param event Girara event
* @param t Number of executions
* @return true if no error occured otherwise false
*/
bool sc_quit(girara_session_t* session, girara_argument_t* argument, unsigned int t);
bool sc_quit(girara_session_t* session, girara_argument_t* argument, girara_event_t* event, unsigned int t);
/**
* Change the zoom level
*
* @param session The used girara session
* @param argument The used argument
* @param event Girara event
* @param t Number of executions
* @return true if no error occured otherwise false
*/
bool sc_zoom(girara_session_t* session, girara_argument_t* argument, unsigned int t);
bool sc_zoom(girara_session_t* session, girara_argument_t* argument, girara_event_t* event, unsigned int t);
#endif // SHORTCUTS_H

1
tests/.gitignore vendored Normal file
View file

@ -0,0 +1 @@
tests

53
tests/Makefile Normal file
View file

@ -0,0 +1,53 @@
# See LICENSE file for license and copyright information
include ../config.mk
include ../common.mk
include config.mk
PROJECT = tests
SOURCE = tests.c $(wildcard test_*.c)
OBJECTS = ${SOURCE:.c=.o}
ZSOURCE = $(shell find ../ -iname "*.c" -a ! -iname "database-*" ! -iname "main.c" ! -path "*tests*")
ZOBJECTS = ${ZSOURCE:.c=.o}
ifeq (${DATABASE}, sqlite)
INCS += $(SQLITE_INC)
LIBS += $(SQLITE_LIB)
ZSOURCE += ../database-sqlite.c
else
ifeq (${DATABASE}, plain)
ZSOURCE += ../database-plain.c
endif
endif
all: ${PROJECT} run
run: ${PROJECT}
$(QUIET)./${PROJECT}
options:
@echo ${PROJECT} build options:
@echo "CFLAGS = ${CFLAGS}"
@echo "LDFLAGS = ${LDFLAGS}"
@echo "DFLAGS = ${DFLAGS}"
@echo "CC = ${CC}"
%.o: %.c
$(ECHO) CC $<
@mkdir -p .depend
$(QUIET)${CC} -c -I.. ${CPPFLAGS} ${CFLAGS} -o $@ $< -MMD -MF .depend/$@.dep
${PROJECT}: options ${OBJECTS}
$(QUIET)make -C ..
$(ECHO) CC -o $@
$(QUIET)${CC} ${SFLAGS} ${LDFLAGS} -o $@ ${OBJECTS} ${ZOBJECTS} ${LIBS}
${OBJECTS}: ../config.mk
clean:
$(QUIET)rm -rf ${OBJECTS} ${PROJECT}
.PHONY: all options clean debug
-include $(wildcard .depend/*.dep)

9
tests/config.mk Normal file
View file

@ -0,0 +1,9 @@
# See LICENSE file for license and copyright information
CHECK_INC ?= $(shell pkg-config --cflags check)
CHECK_LIB ?= $(shell pkg-config --libs check)
LIBS += ${CHECK_LIB}
CFLAGS += -fprofile-arcs -ftest-coverage
LDFLAGS += -fprofile-arcs

44
tests/test_utils.c Normal file
View file

@ -0,0 +1,44 @@
/* See LICENSE file for license and copyright information */
#include <check.h>
#include "../utils.h"
START_TEST(test_file_exists_null) {
fail_unless(file_exists(NULL) == false);
} END_TEST
START_TEST(test_file_get_extension_null) {
fail_unless(file_get_extension(NULL) == NULL);
} END_TEST
START_TEST(test_file_get_extension_none) {
const char* path = "test";
fail_unless(file_get_extension(path) == NULL);
} END_TEST
START_TEST(test_file_get_extension_single) {
const char* path = "test.pdf";
const char* extension = file_get_extension(path);
fail_unless(strcmp(extension, "pdf") == 0);
} END_TEST
Suite* suite_utils()
{
TCase* tcase = NULL;
Suite* suite = suite_create("Utils");
/* file exists */
tcase = tcase_create("file_exists");
tcase_add_test(tcase, test_file_exists_null);
suite_add_tcase(suite, tcase);
/* file exists */
tcase = tcase_create("file_get_extension");
tcase_add_test(tcase, test_file_get_extension_null);
tcase_add_test(tcase, test_file_get_extension_none);
tcase_add_test(tcase, test_file_get_extension_single);
suite_add_tcase(suite, tcase);
return suite;
}

22
tests/tests.c Normal file
View file

@ -0,0 +1,22 @@
/* See LICENSE file for license and copyright information */
#include <check.h>
#include <girara/macros.h>
#define UNUSED(x) GIRARA_UNUSED(x)
Suite* suite_utils();
int main(int UNUSED(argc), char *UNUSED(argv[]))
{
Suite* suite = NULL;
SRunner* suite_runner = NULL;
/* test utils */
suite = suite_utils();
suite_runner = srunner_create(suite);
srunner_run_all(suite_runner, CK_NORMAL);
srunner_free(suite_runner);
return 0;
}

205
utils.c
View file

@ -7,11 +7,14 @@
#include <unistd.h>
#include <sys/types.h>
#include <sys/wait.h>
#include "math.h"
#include "utils.h"
#include "zathura.h"
#include "document.h"
#include <girara/datastructures.h>
#define BLOCK_SIZE 64
bool
@ -66,9 +69,9 @@ file_valid_extension(zathura_t* zathura, const char* path)
result = true;
break;
}
GIRARA_LIST_FOREACH_END(zathura->plugins.type_plugin_mapping, zathura_type_plugin_mapping_t*, iter, mapping)
GIRARA_LIST_FOREACH_END(zathura->plugins.type_plugin_mapping, zathura_type_plugin_mapping_t*, iter, mapping);
g_free(content_type);
g_free((void*)content_type);
return result;
}
@ -149,96 +152,130 @@ execute_command(char* const argv[], char** output)
}
void
document_index_build(GtkTreeModel* UNUSED(model), GtkTreeIter* UNUSED(parent),
girara_tree_node_t* UNUSED(tree))
document_index_build(GtkTreeModel* model, GtkTreeIter* parent,
girara_tree_node_t* tree)
{
/*girara_list_t* list = girara_node_get_children(tree);*/
/*girara_list_iterator_t* it = girara_list_iterator(list);*/
girara_list_t* list = girara_node_get_children(tree);
GIRARA_LIST_FOREACH(list, girara_tree_node_t*, iter, node)
zathura_index_element_t* index_element = (zathura_index_element_t*)girara_node_get_data(node);
/*do {*/
/*zathura_index_element_t* index_element = (zathura_index_element_t*) girara_list_iterator_data(it);*/
/*} while ((it = girara_list_iterator_next(it)));*/
gchar* description = NULL;
if (index_element->type == ZATHURA_LINK_TO_PAGE) {
description = g_strdup_printf("Page %d", index_element->target.page_number);
} else {
description = g_strdup(index_element->target.uri);
}
GtkTreeIter tree_iter;
gtk_tree_store_append(GTK_TREE_STORE(model), &tree_iter, parent);
gtk_tree_store_set(GTK_TREE_STORE(model), &tree_iter, 0, index_element->title, 1, description, 2, index_element, -1);
g_object_weak_ref(G_OBJECT(model), (GWeakNotify) zathura_index_element_free, index_element);
g_free(description);
if (girara_node_get_num_children(node) > 0) {
document_index_build(model, &tree_iter, node);
}
GIRARA_LIST_FOREACH_END(list, gchar*, iter, name);
}
char*
string_concat(const char* string1, ...)
void
page_calculate_offset(zathura_page_t* page, page_offset_t* offset)
{
if(!string1) {
return NULL;
}
va_list args;
char* s;
int l = strlen(string1) + 1;
/* calculate length */
va_start(args, string1);
s = va_arg(args, char*);
while(s) {
l += strlen(s);
s = va_arg(args, char*);
}
va_end(args);
/* prepare */
char* c = malloc(sizeof(char) * l);
char* p = c;
/* copy */
char* d = p;
char* x = (char*) string1;
do {
*d++ = *x;
} while (*x++ != '\0');
p = d - 1;
va_start(args, string1);
s = va_arg(args, char*);
while(s) {
d = p;
x = s;
do {
*d++ = *x;
} while (*x++ != '\0');
p = d - 1;
s = va_arg(args, char*);
}
va_end(args);
return c;
}
page_offset_t*
page_calculate_offset(zathura_page_t* page)
{
if (page == NULL || page->document == NULL || page->document->zathura == NULL) {
return NULL;
}
page_offset_t* offset = malloc(sizeof(page_offset_t));
if (offset == NULL) {
return NULL;
}
g_return_if_fail(page != NULL && page->document != NULL && page->document->zathura != NULL && offset != NULL);
zathura_document_t* document = page->document;
zathura_t* zathura = document->zathura;
if (gtk_widget_translate_coordinates(page->event_box, zathura->ui.page_view, 0, 0, &(offset->x), &(offset->y)) == false) {
free(offset);
return NULL;
g_return_if_fail(gtk_widget_translate_coordinates(page->drawing_area,
zathura->ui.page_widget, 0, 0, &(offset->x), &(offset->y)) == true);
}
zathura_rectangle_t rotate_rectangle(zathura_rectangle_t rectangle, unsigned int degree, int height, int width)
{
zathura_rectangle_t tmp;
switch (degree) {
case 90:
tmp.x1 = height - rectangle.y2;
tmp.x2 = height - rectangle.y1;
tmp.y1 = rectangle.x1;
tmp.y2 = rectangle.x2;
break;
case 180:
tmp.x1 = width - rectangle.x2;
tmp.x2 = width - rectangle.x1;
tmp.y1 = height - rectangle.y2;
tmp.y2 = height - rectangle.y1;
break;
case 270:
tmp.x1 = rectangle.y1;
tmp.x2 = rectangle.y2;
tmp.y1 = width - rectangle.x2;
tmp.y2 = width - rectangle.x1;
break;
default:
tmp.x1 = rectangle.x1;
tmp.x2 = rectangle.x2;
tmp.y1 = rectangle.y1;
tmp.y2 = rectangle.y2;
}
return offset;
return tmp;
}
zathura_rectangle_t
recalc_rectangle(zathura_page_t* page, zathura_rectangle_t rectangle)
{
if (page == NULL || page->document == NULL) {
return rectangle;
}
zathura_rectangle_t tmp;
switch (page->document->rotate) {
case 90:
tmp.x1 = (page->height - rectangle.y2) * page->document->scale;
tmp.x2 = (page->height - rectangle.y1) * page->document->scale;
tmp.y1 = rectangle.x1 * page->document->scale;
tmp.y2 = rectangle.x2 * page->document->scale;
break;
case 180:
tmp.x1 = (page->width - rectangle.x2) * page->document->scale;
tmp.x2 = (page->width - rectangle.x1) * page->document->scale;
tmp.y1 = (page->height - rectangle.y2) * page->document->scale;
tmp.y2 = (page->height - rectangle.y1) * page->document->scale;
break;
case 270:
tmp.x1 = rectangle.y1 * page->document->scale;
tmp.x2 = rectangle.y2 * page->document->scale;
tmp.y1 = (page->width - rectangle.x2) * page->document->scale;
tmp.y2 = (page->width - rectangle.x1) * page->document->scale;
break;
default:
tmp.x1 = rectangle.x1 * page->document->scale;
tmp.x2 = rectangle.x2 * page->document->scale;
tmp.y1 = rectangle.y1 * page->document->scale;
tmp.y2 = rectangle.y2 * page->document->scale;
}
return tmp;
}
void
set_adjustment(GtkAdjustment* adjustment, gdouble value)
{
gtk_adjustment_set_value(adjustment, MAX(adjustment->lower, MIN(adjustment->upper - adjustment->page_size, value)));
}
void
page_calc_height_width(zathura_page_t* page, unsigned int* page_height, unsigned int* page_width, bool rotate)
{
g_return_if_fail(page != NULL && page_height != NULL && page_width != NULL);
if (rotate && page->document->rotate % 180) {
*page_width = ceil(page->height * page->document->scale);
*page_height = ceil(page->width * page->document->scale);
} else {
*page_width = ceil(page->width * page->document->scale);
*page_height = ceil(page->height * page->document->scale);
}
}

60
utils.h
View file

@ -5,10 +5,12 @@
#include <stdbool.h>
#include <gtk/gtk.h>
#include <girara.h>
#include <girara/types.h>
#include "document.h"
#define LENGTH(x) (sizeof(x)/sizeof((x)[0]))
typedef struct page_offset_s
{
int x;
@ -55,28 +57,58 @@ bool execute_command(char* const argv[], char** output);
* object.
*
* @param model The tree model
* @param tree_it The Tree iterator
* @param list_it The index list iterator
* @param parent The tree iterator parent
* @param tree The Tree iterator
*/
void document_index_build(GtkTreeModel* model, GtkTreeIter* parent, girara_tree_node_t* tree);
/**
* This function is used to concatenate multiple strings. Argument list has to
* be ended with NULL. Returned string has to be freed with free().
*
* @param string1 First string
* @param ... Additional strings
* @return Concatenated string or NULL if an error occured
*/
char* string_concat(const char* string1, ...);
/**
* Calculates the offset of the page to the top of the viewing area as
* well as to the left side of it. The result has to be freed.
*
* @param page The Page
* @param offset Applied offset
* @return The calculated offset or NULL if an error occured
*/
page_offset_t* page_calculate_offset(zathura_page_t* page);
void page_calculate_offset(zathura_page_t* page, page_offset_t* offset);
/**
* Rotate a rectangle by 0, 90, 180 or 270 degree
* @param rect the rectangle to rotate
* @param degree rotation degree
* @param height the height of the enclosing rectangle
* @param width the width of the enclosing rectangle
* @return the rotated rectangle
*/
zathura_rectangle_t rotate_rectangle(zathura_rectangle_t rectangle, unsigned int degree, int height, int width);
/**
* Calculates the new coordinates based on the rotation and scale level of the
* document for the given rectangle
*
* @param page Page where the rectangle should be
* @param rectangle The rectangle
* @return New rectangle
*/
zathura_rectangle_t recalc_rectangle(zathura_page_t* page, zathura_rectangle_t rectangle);
/**
* Set adjustment of a GtkAdjustment respecting its limits.
* @param adjust the GtkAdkustment instance
* @param value the new adjustment
*/
void set_adjustment(GtkAdjustment* adjust, gdouble value);
/**
* Calculate the page size according to the corrent scaling and rotation if
* desired.
* @param page the page
* @param page_height the resulting page height
* @param page_width the resultung page width
* @param rotate honor page's rotation
*/
void
page_calc_height_width(zathura_page_t* page, unsigned int* page_height, unsigned int* page_width, bool rotate);
#endif // UTILS_H

373
zathura.c
View file

@ -1,8 +1,18 @@
/* See LICENSE file for license and copyright information */
#include <stdlib.h>
#define _BSD_SOURCE
#define _XOPEN_SOURCE 700
#include <girara.h>
#include <stdlib.h>
#include <unistd.h>
#include <math.h>
#include <girara/datastructures.h>
#include <girara/utils.h>
#include <girara/session.h>
#include <girara/statusbar.h>
#include <girara/settings.h>
#include <glib/gstdio.h>
#include "bookmarks.h"
#include "callbacks.h"
@ -21,7 +31,7 @@ typedef struct zathura_document_info_s
const char* password;
} zathura_document_info_t;
gboolean document_info_open(gpointer data);
static gboolean document_info_open(gpointer data);
/* function implementation */
zathura_t*
@ -30,12 +40,14 @@ zathura_init(int argc, char* argv[])
/* parse command line options */
GdkNativeWindow embed = 0;
gchar* config_dir = NULL, *data_dir = NULL, *plugin_path = NULL;
bool forkback = false;
GOptionEntry entries[] =
{
{ "reparent", 'e', 0, G_OPTION_ARG_INT, &embed, "Reparents to window specified by xid", "xid" },
{ "config-dir", 'c', 0, G_OPTION_ARG_FILENAME, &config_dir, "Path to the config directory", "path" },
{ "data-dir", 'd', 0, G_OPTION_ARG_FILENAME, &data_dir, "Path to the data directory", "path" },
{ "plugins-dir", 'p', 0, G_OPTION_ARG_STRING, &plugin_path, "Path to the directories containing plugins", "path" },
{ "fork", '\0', 0, G_OPTION_ARG_NONE, &forkback, "Fork into the background" , NULL },
{ NULL, '\0', 0, 0, NULL, NULL, NULL }
};
@ -48,26 +60,31 @@ zathura_init(int argc, char* argv[])
printf("Error parsing command line arguments: %s\n", error->message);
g_option_context_free(context);
g_error_free(error);
goto error_free;
return NULL;
}
g_option_context_free(context);
zathura_t* zathura = malloc(sizeof(zathura_t));
/* Fork into the background if the user really wants to ... */
if (forkback == true)
{
int pid = fork();
if (pid > 0) { /* parent */
exit(0);
} else if (pid < 0) { /* error */
printf("Error: couldn't fork.");
}
if (zathura == NULL) {
return NULL;
setsid();
}
/* general */
zathura->document = NULL;
zathura_t* zathura = g_malloc0(sizeof(zathura_t));
/* plugins */
zathura->plugins.plugins = girara_list_new();
girara_list_set_free_function(zathura->plugins.plugins, zathura_document_plugin_free);
zathura->plugins.path = girara_list_new();
girara_list_set_free_function(zathura->plugins.path, g_free);
zathura->plugins.type_plugin_mapping = girara_list_new();
girara_list_set_free_function(zathura->plugins.type_plugin_mapping, zathura_type_plugin_mapping_free);
zathura->plugins.plugins = girara_list_new2(
(girara_free_function_t)zathura_document_plugin_free);
zathura->plugins.path = girara_list_new2(g_free);
zathura->plugins.type_plugin_mapping = girara_list_new2(
(girara_free_function_t)zathura_type_plugin_mapping_free);
if (config_dir) {
zathura->config.config_dir = g_strdup(config_dir);
@ -85,16 +102,20 @@ zathura_init(int argc, char* argv[])
g_free(path);
}
/* create zathura (config/data) directory */
g_mkdir_with_parents(zathura->config.config_dir, 0771);
g_mkdir_with_parents(zathura->config.data_dir, 0771);
if (plugin_path) {
gchar** paths = g_strsplit(plugin_path, ":", 0);
for (unsigned int i = 0; paths[i] != '\0'; ++i) {
girara_list_append(zathura->plugins.path, g_strdup(paths[i]));
}
g_strfreev(paths);
girara_list_t* paths = girara_split_path_array(plugin_path);
girara_list_merge(zathura->plugins.path, paths);
girara_list_free(paths);
} else {
/* XXX: this shouldn't be hard coded! */
girara_list_append(zathura->plugins.path, g_strdup("/usr/local/lib/zathura"));
girara_list_append(zathura->plugins.path, g_strdup("/usr/lib/zathura"));
#ifdef ZATHURA_PLUGINDIR
girara_list_t* paths = girara_split_path_array(ZATHURA_PLUGINDIR);
girara_list_merge(zathura->plugins.path, paths);
girara_list_free(paths);
#endif
}
/* UI */
@ -106,7 +127,7 @@ zathura_init(int argc, char* argv[])
zathura->ui.statusbar.file = NULL;
zathura->ui.statusbar.buffer = NULL;
zathura->ui.statusbar.page_number = NULL;
zathura->ui.page_view = NULL;
zathura->ui.page_widget = NULL;
zathura->ui.index = NULL;
/* print settings */
@ -123,35 +144,54 @@ zathura_init(int argc, char* argv[])
config_load_default(zathura);
/* load global configuration files */
girara_list_t* config_dirs = girara_split_path_array(girara_get_xdg_path(XDG_CONFIG_DIRS));
ssize_t size = girara_list_size(config_dirs) - 1;
for (; size >= 0; --size) {
const char* dir = girara_list_nth(config_dirs, size);
char* file = g_build_filename(dir, ZATHURA_RC, NULL);
config_load_file(zathura, file);
g_free(file);
}
girara_list_free(config_dirs);
config_load_file(zathura, GLOBAL_RC);
/* load local configuration files */
char* configuration_file = g_build_filename(zathura->config.config_dir, ZATHURA_RC, NULL);
config_load_file(zathura, configuration_file);
free(configuration_file);
g_free(configuration_file);
/* initialize girara */
zathura->ui.session->gtk.embed = embed;
if (girara_session_init(zathura->ui.session) == false) {
if (girara_session_init(zathura->ui.session, "zathura") == false) {
goto error_out;
}
/* girara events */
zathura->ui.session->events.buffer_changed = buffer_changed;
zathura->ui.session->events.buffer_changed = cb_buffer_changed;
/* page view */
zathura->ui.page_view = gtk_table_new(0, 0, TRUE);
if (!zathura->ui.page_view) {
zathura->ui.page_widget = gtk_table_new(0, 0, TRUE);
if (!zathura->ui.page_widget) {
goto error_free;
}
g_signal_connect(G_OBJECT(zathura->ui.session->gtk.view), "size-allocate", G_CALLBACK(cb_view_resized), zathura);
/* callbacks */
GtkAdjustment* view_vadjustment = gtk_scrolled_window_get_vadjustment(GTK_SCROLLED_WINDOW(zathura->ui.session->gtk.view));
g_signal_connect(G_OBJECT(view_vadjustment), "value-changed", G_CALLBACK(cb_view_vadjustment_value_changed), zathura);
GtkAdjustment* view_hadjustment = gtk_scrolled_window_get_hadjustment(GTK_SCROLLED_WINDOW(zathura->ui.session->gtk.view));
g_signal_connect(G_OBJECT(view_hadjustment), "value-changed", G_CALLBACK(cb_view_vadjustment_value_changed), zathura);
gtk_widget_show(zathura->ui.page_view);
/* page view alignment */
zathura->ui.page_widget_alignment = gtk_alignment_new(0.5, 0.5, 0, 0);
if (!zathura->ui.page_widget_alignment) {
goto error_free;
}
gtk_container_add(GTK_CONTAINER(zathura->ui.page_widget_alignment), zathura->ui.page_widget);
gtk_widget_show(zathura->ui.page_widget);
/* statusbar */
zathura->ui.statusbar.file = girara_statusbar_item_add(zathura->ui.session, TRUE, TRUE, TRUE, NULL);
@ -175,64 +215,69 @@ zathura_init(int argc, char* argv[])
g_signal_connect(G_OBJECT(zathura->ui.session->gtk.window), "destroy", G_CALLBACK(cb_destroy), NULL);
/* save page padding */
int* page_padding = girara_setting_get(zathura->ui.session, "page-padding");
zathura->global.page_padding = (page_padding) ? *page_padding : 1;
zathura->global.page_padding = 1;
girara_setting_get(zathura->ui.session, "page-padding", &zathura->global.page_padding);
gtk_table_set_row_spacings(GTK_TABLE(zathura->ui.page_view), zathura->global.page_padding);
gtk_table_set_col_spacings(GTK_TABLE(zathura->ui.page_view), zathura->global.page_padding);
gtk_table_set_row_spacings(GTK_TABLE(zathura->ui.page_widget), zathura->global.page_padding);
gtk_table_set_col_spacings(GTK_TABLE(zathura->ui.page_widget), zathura->global.page_padding);
/* parse colors */
char* string_value = girara_setting_get(zathura->ui.session, "recolor-dark-color");
char* string_value = NULL;
girara_setting_get(zathura->ui.session, "recolor-darkcolor", &string_value);
if (string_value != NULL) {
gdk_color_parse(string_value, &(zathura->ui.colors.recolor_dark_color));
free(string_value);
g_free(string_value);
}
string_value = girara_setting_get(zathura->ui.session, "recolor-light-color");
string_value = NULL;
girara_setting_get(zathura->ui.session, "recolor-lightcolor", &string_value);
if (string_value != NULL) {
gdk_color_parse(string_value, &(zathura->ui.colors.recolor_light_color));
free(string_value);
g_free(string_value);
}
string_value = NULL;
girara_setting_get(zathura->ui.session, "highlight-color", &string_value);
if (string_value != NULL) {
gdk_color_parse(string_value, &(zathura->ui.colors.highlight_color));
g_free(string_value);
}
/* database */
char* database_path = g_build_filename(zathura->config.data_dir, "bookmarks.sqlite", NULL);
zathura->database = zathura_db_init(database_path);
zathura->database = zathura_db_init(zathura->config.data_dir);
if (zathura->database == NULL) {
girara_error("Unable to inizialize database. Bookmarks won't be available.");
girara_error("Unable to initialize database. Bookmarks won't be available.");
}
g_free(database_path);
/* bookmarks */
zathura->bookmarks.bookmarks = girara_list_new();
girara_list_set_free_function(zathura->bookmarks.bookmarks, (girara_free_function_t) zathura_bookmark_free);
zathura->bookmarks.bookmarks = girara_sorted_list_new2((girara_compare_function_t) zathura_bookmarks_compare,
(girara_free_function_t) zathura_bookmark_free);
/* open document if passed */
if (argc > 1) {
zathura_document_info_t* document_info = malloc(sizeof(zathura_document_info_t));
zathura_document_info_t* document_info = g_malloc0(sizeof(zathura_document_info_t));
if (document_info != NULL) {
document_info->zathura = zathura;
document_info->path = argv[1];
document_info->password = (argc >= 2) ? argv[2] : NULL;
g_idle_add(document_info_open, document_info);
}
document_info->zathura = zathura;
document_info->path = argv[1];
document_info->password = (argc >= 2) ? argv[2] : NULL;
g_idle_add(document_info_open, document_info);
}
return zathura;
error_free:
if (zathura->ui.page_view) {
g_object_unref(zathura->ui.page_view);
if (zathura->ui.page_widget) {
g_object_unref(zathura->ui.page_widget);
}
girara_session_destroy(zathura->ui.session);
girara_list_free(zathura->bookmarks.bookmarks);
zathura_db_free(zathura->database);
if (zathura->ui.page_widget_alignment) {
g_object_unref(zathura->ui.page_widget_alignment);
}
error_out:
free(zathura);
zathura_free(zathura);
return NULL;
}
@ -244,11 +289,17 @@ zathura_free(zathura_t* zathura)
return;
}
document_close(zathura);
if (zathura->ui.session != NULL) {
girara_session_destroy(zathura->ui.session);
}
document_close(zathura);
/* stdin support */
if (zathura->stdin_support.file != NULL) {
g_unlink(zathura->stdin_support.file);
g_free(zathura->stdin_support.file);
}
/* bookmarks */
girara_list_free(zathura->bookmarks.bookmarks);
@ -272,22 +323,91 @@ zathura_free(zathura_t* zathura)
/* free config variables */
g_free(zathura->config.config_dir);
g_free(zathura->config.data_dir);
g_free(zathura);
}
gboolean
static gchar*
prepare_document_open_from_stdin(zathura_t* zathura)
{
g_return_val_if_fail(zathura, NULL);
GError* error = NULL;
gchar* file = NULL;
gint handle = g_file_open_tmp("zathura.stdin.XXXXXX", &file, &error);
if (handle == -1)
{
if (error != NULL) {
girara_error("Can not create temporary file: %s", error->message);
g_error_free(error);
}
return NULL;
}
// read from stdin and dump to temporary file
int stdinfno = fileno(stdin);
if (stdinfno == -1)
{
girara_error("Can not read from stdin.");
close(handle);
g_unlink(file);
g_free(file);
return NULL;
}
char buffer[BUFSIZ];
ssize_t count = 0;
while ((count = read(stdinfno, buffer, BUFSIZ)) > 0)
{
if (write(handle, buffer, count) != count)
{
girara_error("Can not write to temporary file: %s", file);
close(handle);
g_unlink(file);
g_free(file);
return NULL;
}
}
close(handle);
if (count != 0)
{
girara_error("Can not read from stdin.");
g_unlink(file);
g_free(file);
return NULL;
}
return file;
}
static gboolean
document_info_open(gpointer data)
{
zathura_document_info_t* document_info = data;
g_return_val_if_fail(document_info != NULL, FALSE);
if (document_info->zathura == NULL || document_info->path == NULL) {
free(document_info);
return FALSE;
if (document_info->zathura != NULL && document_info->path != NULL) {
char* file = NULL;
if (g_strcmp0(document_info->path, "-") == 0) {
file = prepare_document_open_from_stdin(document_info->zathura);
if (file == NULL) {
girara_notify(document_info->zathura->ui.session, GIRARA_ERROR,
"Could not read file from stdin and write it to a temporary file.");
} else {
document_info->zathura->stdin_support.file = g_strdup(file);
}
} else {
file = g_strdup(document_info->path);
}
if (file != NULL) {
document_open(document_info->zathura, file, document_info->password);
g_free(file);
}
}
document_open(document_info->zathura, document_info->path, document_info->password);
free(document_info);
g_free(document_info);
return FALSE;
}
@ -307,12 +427,11 @@ document_open(zathura_t* zathura, const char* path, const char* password)
zathura->document = document;
/* view mode */
int* value = girara_setting_get(zathura->ui.session, "pages-per-row");
int pages_per_row = (value) ? *value : 1;
free(value);
page_view_set_mode(zathura, pages_per_row);
int pages_per_row = 1;
girara_setting_get(zathura->ui.session, "pages-per-row", &pages_per_row);
page_widget_set_mode(zathura, pages_per_row);
girara_set_view(zathura->ui.session, zathura->ui.page_view);
girara_set_view(zathura->ui.session, zathura->ui.page_widget_alignment);
/* threads */
zathura->sync.render_thread = render_init(zathura);
@ -324,7 +443,7 @@ document_open(zathura_t* zathura, const char* path, const char* password)
/* create blank pages */
for (unsigned int page_id = 0; page_id < document->number_of_pages; page_id++) {
zathura_page_t* page = document->pages[page_id];
gtk_widget_realize(page->event_box);
gtk_widget_realize(page->drawing_area);
}
/* bookmarks */
@ -332,6 +451,9 @@ document_open(zathura_t* zathura, const char* path, const char* password)
girara_warning("Failed to load bookmarks for %s.\n", zathura->document->file_path);
}
page_set_delayed(zathura, document->current_page_number - 1);
cb_view_vadjustment_value_changed(NULL, zathura);
return true;
error_free:
@ -353,9 +475,8 @@ document_save(zathura_t* zathura, const char* path, bool overwrite)
gchar* file_path = girara_fix_path(path);
if (!overwrite && g_file_test(file_path, G_FILE_TEST_EXISTS))
{
gchar* message = g_strdup_printf("File already exists: %s. Use :write! to overwrite it.", file_path);
girara_error(message);
g_free(message);
girara_error("File already exists: %s. Use :write! to overwrite it.", file_path);
g_free(file_path);
return false;
}
@ -381,23 +502,65 @@ document_close(zathura_t* zathura)
return false;
}
/* store last seen page */
zathura_db_set_fileinfo(zathura->database, zathura->document->file_path, zathura->document->current_page_number,
/* zathura->document->offset TODO */ 0, zathura->document->scale,
zathura->document->rotate);
render_free(zathura->sync.render_thread);
zathura->sync.render_thread = NULL;
gtk_container_foreach(GTK_CONTAINER(zathura->ui.page_view), remove_page_from_table, (gpointer)1);
gtk_container_foreach(GTK_CONTAINER(zathura->ui.page_widget), remove_page_from_table, (gpointer)1);
zathura_document_free(zathura->document);
zathura->document = NULL;
gtk_widget_hide_all(zathura->ui.page_view);
gtk_widget_hide(zathura->ui.page_widget);
statusbar_page_number_update(zathura);
if (zathura->ui.session != NULL && zathura->ui.statusbar.file != NULL) {
girara_statusbar_item_set_text(zathura->ui.session, zathura->ui.statusbar.file, "[No name]");
}
return true;
}
typedef struct page_set_delayed_s
{
zathura_t* zathura;
unsigned int page;
} page_set_delayed_t;
static gboolean
page_set_delayed_impl(gpointer data)
{
page_set_delayed_t* p = data;
page_set(p->zathura, p->page);
g_free(p);
return FALSE;
}
bool
page_set_delayed(zathura_t* zathura, unsigned int page_id)
{
if (zathura == NULL || zathura->document == NULL || zathura->document->pages == NULL ||
page_id >= zathura->document->number_of_pages) {
return false;
}
page_set_delayed_t* p = g_malloc(sizeof(page_set_delayed_t));
p->zathura = zathura;
p->page = page_id;
g_idle_add(page_set_delayed_impl, p);
return true;
}
bool
page_set(zathura_t* zathura, unsigned int page_id)
{
if (!zathura->document || !zathura->document->pages) {
if (zathura == NULL || zathura->document == NULL || zathura->document->pages == NULL) {
goto error_out;
}
@ -412,19 +575,13 @@ page_set(zathura_t* zathura, unsigned int page_id)
goto error_out;
}
page_offset_t* offset = page_calculate_offset(page);
if (offset == NULL) {
goto error_out;
}
page_offset_t offset;
page_calculate_offset(page, &offset);
GtkAdjustment* view_vadjustment = gtk_scrolled_window_get_vadjustment(GTK_SCROLLED_WINDOW(zathura->ui.session->gtk.view));
GtkAdjustment* view_hadjustment = gtk_scrolled_window_get_hadjustment(GTK_SCROLLED_WINDOW(zathura->ui.session->gtk.view));
gtk_adjustment_set_value(view_hadjustment, offset->x);
gtk_adjustment_set_value(view_vadjustment, offset->y);
/* update page number */
zathura->document->current_page_number = page_id;
statusbar_page_number_update(zathura);
set_adjustment(view_hadjustment, offset.x);
set_adjustment(view_vadjustment, offset.y);
return true;
@ -440,13 +597,17 @@ statusbar_page_number_update(zathura_t* zathura)
return;
}
char* page_number_text = g_strdup_printf("[%d/%d]", zathura->document->current_page_number + 1, zathura->document->number_of_pages);
girara_statusbar_item_set_text(zathura->ui.session, zathura->ui.statusbar.page_number, page_number_text);
g_free(page_number_text);
if (zathura->document != NULL) {
char* page_number_text = g_strdup_printf("[%d/%d]", zathura->document->current_page_number + 1, zathura->document->number_of_pages);
girara_statusbar_item_set_text(zathura->ui.session, zathura->ui.statusbar.page_number, page_number_text);
g_free(page_number_text);
} else {
girara_statusbar_item_set_text(zathura->ui.session, zathura->ui.statusbar.page_number, "");
}
}
void
page_view_set_mode(zathura_t* zathura, unsigned int pages_per_row)
page_widget_set_mode(zathura_t* zathura, unsigned int pages_per_row)
{
/* show at least one page */
if (pages_per_row == 0) {
@ -457,37 +618,15 @@ page_view_set_mode(zathura_t* zathura, unsigned int pages_per_row)
return;
}
gtk_container_foreach(GTK_CONTAINER(zathura->ui.page_view), remove_page_from_table, (gpointer)0);
gtk_container_foreach(GTK_CONTAINER(zathura->ui.page_widget), remove_page_from_table, (gpointer)0);
gtk_table_resize(GTK_TABLE(zathura->ui.page_view), zathura->document->number_of_pages / pages_per_row + 1, pages_per_row);
gtk_table_resize(GTK_TABLE(zathura->ui.page_widget), ceil(zathura->document->number_of_pages / pages_per_row), pages_per_row);
for (unsigned int i = 0; i < zathura->document->number_of_pages; i++)
{
int x = i % pages_per_row;
int y = i / pages_per_row;
gtk_table_attach(GTK_TABLE(zathura->ui.page_view), zathura->document->pages[i]->event_box, x, x + 1, y, y + 1, GTK_EXPAND, GTK_EXPAND, 0, 0);
gtk_table_attach(GTK_TABLE(zathura->ui.page_widget), zathura->document->pages[i]->drawing_area, x, x + 1, y, y + 1, GTK_SHRINK, GTK_SHRINK, 0, 0);
}
gtk_widget_show_all(zathura->ui.page_view);
}
/* main function */
int main(int argc, char* argv[])
{
g_thread_init(NULL);
gdk_threads_init();
gtk_init(&argc, &argv);
zathura_t* zathura = zathura_init(argc, argv);
if (zathura == NULL) {
printf("error: coult not initialize zathura\n");
return -1;
}
gdk_threads_enter();
gtk_main();
gdk_threads_leave();
zathura_free(zathura);
return 0;
gtk_widget_show_all(zathura->ui.page_widget);
}

View file

@ -2,9 +2,9 @@
Version=1.0
Type=Application
Name=Zathura
Comment=A minimalistic PDF viewer
Comment[de]=Ein minimalistischer PDF-Betrachter
Comment=A minimalistic document viewer
Comment[de]=Ein minimalistischer Dokumenten-Betrachter
Exec=zathura %f
Terminal=false
Categories=Office;Viewer;
MimeType=application/pdf;
MimeType=application/pdf;application/postscript;image/vnd.djvu;

View file

@ -4,16 +4,11 @@
#define ZATHURA_H
#include <stdbool.h>
#include <girara.h>
#include <girara/types.h>
#include <girara/macros.h>
#include <gtk/gtk.h>
#ifdef UNUSED
#elif defined(__GNUC__)
# define UNUSED(x) UNUSED_ ## x __attribute__((unused))
#elif defined(__LCINT__)
# define UNUSED(x) /*@unused@*/ x
#else
# define UNUSED(x) x
#endif
#define UNUSED(x) GIRARA_UNUSED(x)
enum { NEXT, PREVIOUS, LEFT, RIGHT, UP, DOWN, BOTTOM, TOP, HIDE, HIGHLIGHT,
DELETE_LAST_WORD, DELETE_LAST_CHAR, DEFAULT, ERROR, WARNING, NEXT_GROUP,
@ -41,71 +36,78 @@ typedef struct zathura_s
{
struct
{
girara_session_t* session; /**> girara interface session */
girara_session_t* session; /**< girara interface session */
struct
{
girara_statusbar_item_t* buffer; /**> buffer statusbar entry */
girara_statusbar_item_t* file; /**> file statusbar entry */
girara_statusbar_item_t* page_number; /**> page number statusbar entry */
girara_statusbar_item_t* buffer; /**< buffer statusbar entry */
girara_statusbar_item_t* file; /**< file statusbar entry */
girara_statusbar_item_t* page_number; /**< page number statusbar entry */
} statusbar;
struct
{
GdkColor recolor_dark_color; /**> Dark color for recoloring */
GdkColor recolor_light_color; /**> Light color for recoloring */
GdkColor recolor_dark_color; /**< Dark color for recoloring */
GdkColor recolor_light_color; /**< Light color for recoloring */
GdkColor highlight_color; /**< Color for highlighting */
} colors;
GtkWidget *page_view; /**> Widget that contains all rendered pages */
GtkWidget *index; /**> Widget to show the index of the document */
GtkWidget *page_widget_alignment;
GtkWidget *page_widget; /**< Widget that contains all rendered pages */
GtkWidget *index; /**< Widget to show the index of the document */
} ui;
struct
{
render_thread_t* render_thread; /**> The thread responsible for rendering the pages */
render_thread_t* render_thread; /**< The thread responsible for rendering the pages */
} sync;
struct
{
girara_list_t* plugins; /**> List of plugins */
girara_list_t* path; /**> List of plugin paths */
girara_list_t* type_plugin_mapping; /**> List of type -> plugin mappings */
girara_list_t* plugins; /**< List of plugins */
girara_list_t* path; /**< List of plugin paths */
girara_list_t* type_plugin_mapping; /**< List of type -> plugin mappings */
} plugins;
struct
{
gchar* config_dir; /**> Path to the configuration directory */
gchar* data_dir; /**> Path to the data directory */
gchar* config_dir; /**< Path to the configuration directory */
gchar* data_dir; /**< Path to the data directory */
} config;
struct
{
GtkPrintSettings* settings; /**> Print settings */
GtkPageSetup* page_setup; /**> Saved page setup */
GtkPrintSettings* settings; /**< Print settings */
GtkPageSetup* page_setup; /**< Saved page setup */
} print;
struct
{
unsigned int page_padding; /**> Padding between the pages */
bool recolor; /**> Recoloring mode switch */
unsigned int page_padding; /**< Padding between the pages */
bool recolor; /**< Recoloring mode switch */
} global;
struct
{
girara_mode_t normal; /**> Normal mode */
girara_mode_t fullscreen; /**> Fullscreen mode */
girara_mode_t index; /**> Index mode */
girara_mode_t insert; /**> Insert mode */
girara_mode_t normal; /**< Normal mode */
girara_mode_t fullscreen; /**< Fullscreen mode */
girara_mode_t index; /**< Index mode */
girara_mode_t insert; /**< Insert mode */
} modes;
struct
{
gchar* file; /**> bookmarks file */
girara_list_t* bookmarks; /**> bookmarks */
gchar* file; /**< bookmarks file */
girara_list_t* bookmarks; /**< bookmarks */
} bookmarks;
zathura_document_t* document; /**> The current document */
zathura_database_t* database; /**> The database */
struct
{
gchar* file;
} stdin_support;
zathura_document_t* document; /**< The current document */
zathura_database_t* database; /**< The database */
} zathura_t;
/**
@ -158,17 +160,27 @@ bool document_close(zathura_t* zathura);
* Opens the page with the given number
*
* @param zathura The zathura session
* @param page_id The id of the page that should be set
* @return If no error occured true, otherwise false, is returned.
*/
bool page_set(zathura_t* zathura, unsigned int page_id);
/**
* Opens the page with the given number (delayed)
*
* @param zathura The zathura session
* @param page_id The id of the page that should be set
* @return If no error occured true, otherwise false, is returned.
*/
bool page_set_delayed(zathura_t* zathura, unsigned int page_id);
/**
* Builds the box structure to show the rendered pages
*
* @param zathura The zathura session
* @param pages_per_row Number of shown pages per row
*/
void page_view_set_mode(zathura_t* zathura, unsigned int pages_per_row);
void page_widget_set_mode(zathura_t* zathura, unsigned int pages_per_row);
/**
* Updates the page number in the statusbar. Note that 1 will be added to the

View file

@ -6,188 +6,268 @@
zathura configuration file
--------------------------
:Author: Sebastian Ramacher <s.ramacher@gmx.at>
:Date: 19.8.2010
:Author: pwmt.org
:Date: 02.02.2012
:Manual section: 5
SYNOPOSIS
=========
/etc/zathurarc, ~/.config/zathura/zathurarc
/etc/zathurarc, $XDG_CONFIG_HOME/zathura/zathurarc
DESCRIPTION
===========
The zathurarc contains various options controlling the behavior of zathura. One
can use the ``set`` and ``map`` commands:
The zathurarc file is a simple plain text file that can be populated with
various commands to change the behaviour and the look of zathura which we are
going to describe in the following subsections. Each line (besides empty lines
and comments (which start with a prepended #)) is evaluated on its own, so it is
not possible to write multiple commands in one single line.
* ``set`` [id] [value]
* ``map`` [key] [function] [argument] [mode]
The following commands can be used:
They behave the same as the ``set`` and ``map`` commands in zathura. Any line
not starting with ``set`` or ``map`` will be ignored.
set - Changing the options
--------------------------
set
---
In addition to the build-in :set command zathura offers more options to be
changed and makes those changes permanent. To overwrite an option you just have
to add a line structured like the following:
[id] and the corresponding [value] can be one of
::
set <option> <new value>
* adjust_open [bestfit|width|noadjust] - adjust mode.
The option field has to be replaced with the name of the option that should be
changed and the new value field has to be replaced with the new value the option
should get. The type of the value can be one of the following:
- bestfit: adjust to best fit
- width: adjust to width
- noadjust: don't adjust
* INT - An integer number
* FLOAT - A floating point number
* STRING - A character string
* BOOL - A boolean value (“true” for true, “false” for false)
* browser,
uri_command [string] - command to open external URIs.
The string has to include a ``%s`` which will be replaced with the URI.
In addition we advice you to check the List of options to get a more detailed
view of the options that can be changed and which values they should be set to.
* completion_bgcolor,
completion_fgcolor,
completion_g_bgcolor,
completion_g_fgcolor,
completion_hl_bgcolor,
completion_hl_fgcolor,
default_bgcolor,
default_fgcolor,
inputbar_bgcolor,
inputbar_fgcolor,
notification_e_bgcolor,
notification_e_fgcolor,
notification_w_bgcolor,
notification_w_fgcolor,
recolor_darkcolor,
recoler_lightcolor,
statusbar_bgcolor,
statusbar_fgcolor,
search_highlight,
select_text [color] -
colors settings.
The color can be given as hex triplet (#rrggbb) or any color
string understood by GTK+ (e.g. red, green, blue, black, ...).
The following example should give some deeper insight of how the set command can
be used:
* default_text [string] - text displayed in the statusbar if no file is opened.
::
set option1 5
set option2 2.0
set option3 hello
set option4 hello\ world
set option5 "hello world"
* font [string] - the used font.
Possible options are:
* height,
width [int] - default height and width of the zathura window.
page-padding
^^^^^^^^^^^^
The page padding defines the gap in pixels between each rendered page and can
not be changed during runtime.
* labels [bool] - allow label mode.
* Value-type: Integer
* Default value: 1
* list_printer_command [string] - command to list all available printers.
pages-per-row
^^^^^^^^^^^^^
Defines the number of pages that are rendered next to each other in a row.
* n_completion_items [int] - number of completion items to display.
* Value-type: Integer
* Default value: 1
* offset - page offset.
recolor-dark-color
^^^^^^^^^^^^^^^^^^
Defines the color value that is used to represent dark colors in recoloring mode
* print_command [string] - command to print the file.
The string has to include
``%s`` four times. The first occurence of ``%s`` will be replaced with the
printer, the second with additional options given on the command line, the
third with the pages to print and the fourth with the filename.
* Value-type: String
* Default value: #FFFFFF
* recolor [bool] - invert the image.
recolor-light-color
^^^^^^^^^^^^^^^^^^^
Defines the color value that is used to represent light colors in recoloring mode
* save_position, save_zoom_level [bool] - save current page and zoom level in
bookmarks file.
* Value-type: String
* Default value: #000000
* scroll_step [float] - scroll step.
zoom-step
^^^^^^^^^
Defines the amount of percent that is zoomed in or out on each comand.
* scroll_wrap [bool] - wrap scrolling at the end and beginning of the document.
* Value-type: Integer
* Default value: 10
* scrollbars,
show_statusbar,
show_inputbar [bool] -
show statusbar, inputbar and scrollbars.
map - Mapping a shortcut
------------------------
It is possible to map or remap new key bindings to shortcut functions which
allows a high level of customization. The *:map* command can also be used in
the *zathurarc* file to make those changes permanent::
* smooth_scrolling [float] - smooth scrolling.
map [mode] <binding> <shortcut function> <argument>
* transparency [float] - transparency of rectangles.
Mode
^^^^
The *map* command expects several arguments where only the *binding* as well as
the *shortcut-function* argument is required. Since zathura uses several odes it
is possible to map bindings only for a specific mode by passing the *mode*
argument which can take one of the following values:
* zoom_max,
zoom_min,
zoom_step [float] - maximal and minimal zoom level and zoom step.
map
---
[key] can be a single character, ``<C-?>`` for ``Ctrl + ?`` like shortcuts,
where ``?`` stands for some key (e.g. ``<C-q>``). Also it can be ``<S-?>`` for
uppercase shortcuts or one of
``<BackSpace>, <CapsLock>, <Down>, <Esc>, <F[1-12]>, <Left>, <PageDown>,
<PageUp>, <Return>, <Right>, <Space>, <Super>, <Tab>, <Up>``.
[function] and the corresponding [argument] can be one of
* abort - clear command line and buffer.
* adjust_window
* change_buffer [delete_last]: change buffer.
- delete_last: delete last character
* change_mode [mode] - change mode.
For the possible modes see the list of modes below.
* focus_inputbar - focus the inputbar.
* follow - follow a URI.
* navigate [next|previous|left|right] - navigate the document.
* navigate_index [up|down|expand|collapse|select] - nagivate the index.
* quit - quit zathura.
* recolor - toogle recolor setting.
* reload - reload the file.
* rotate - rotate by 90 degrees clockwise.
* scroll [up|down|half_up|half_down|full_up|full_down|left|right] - scroll.
* search [string] - search for the specified string.
* switch_goto_mode - toogle goto mode.
* toggle_fullscreen - toogle fullscreen mode.
* toggle_index - toogle index mode.
* toggle_inputbar - toogle inputbar display setting.
* toogle_statusbar - toogle statusbar display setting.
* zoom [in|out|float] - zoom in, out or to a specific zooming level.
[mode] can be one of
* all
* fullscreen
* index
* normal
* insert
* normal (default)
* visual
* insert
* index
If [mode] is omitted, all will be used.
The brackets around the value are mandatory.
Single key binding
^^^^^^^^^^^^^^^^^^
The (possible) second argument defines the used key binding that should be
mapped to the shortcut function and is structured like the following. On the one
hand it is possible to just assign single letters, numbers or signs to it::
map a shortcut_function
map b shortcut_function
map c shortcut_function
map 1 shortcut_function
map 2 shortcut_function
map 3 shortcut_function
map ! shortcut_function
map ? shortcut_function
Using modifiers
^^^^^^^^^^^^^^^
It is also possible to use modifiers like the *Control* or *Alt* button on the
keyboard. It is possible to use the following modifiers:
* A - *Alt*
* C - *Control*
* S - *Shift*
Now it is required to define the *binding* with the following structure::
map <A-a> shortcut_function
map <C-a> shortcut_function
Special keys
^^^^^^^^^^^^
zathura allows it also to assign keys like the space bar or the tab button which
also have to be written in between angle brackets. The following special keys
are currently available:
========== =================
Identifier Description
========== =================
BackSpace *Back space*
CapsLock *Caps lock*
Esc *Escape*
Down *Arrow down*
Up *Arrow up*
Left *Arrow left*
Right *A7row right*
F1 *F1*
F2 *F2*
F3 *F3*
F4 *F4*
F5 *F5*
F6 *F6*
F7 *F7*
F8 *F8*
F9 *F9*
F10 *F10*
F11 *F11*
F12 *F12*
PageDown *Page Down*
PageUp *Page Up*
Return *Return*
Space *Space*
Super *Windows button*
Tab *Tab*
========== =================
Of course it is possible to combine those special keys with a modifier. The
usage of those keys should be explained by the following examples::
map <Space> shortcut_function
map <C-Space> shortcut_function
Mouse buttons
^^^^^^^^^^^^^
It is also possible to map mouse buttons to shortcuts by using the following
special keys:
========== ================
Identifier Description
========== ================
Button1 *Mouse button 1*
Button2 *Mouse button 2*
Button3 *Mouse button 3*
Button4 *Mouse button 4*
Button5 *Mouse button 5*
========== ================
They can also be combined with modifiers::
map <Button1> shortcut_function
map <C-Button1> shortcut_function
Buffer commands
^^^^^^^^^^^^^^^
If a mapping does not match one of the previous definition but is still a valid
mapping it will be mapped as a buffer command::
map abc quit
map test quit
Shortcut functions
^^^^^^^^^^^^^^^^^^
The following shortcut functions can be mapped:
================= ====================================
Function Description
================= ====================================
abort *Switch back to normal mode*
adjust *Adjust page width*
change_mode *Change current mode*
focus_inputbar *Focus inputbar*
follow *Follow a link*
goto *Go to a certain page*
index_navigate *Navigate through the index*
naviate *Navigate to the next/previous page*
quit *Quit zathura*
recolor *Recolor the pages*
reload *Reload the document*
rotate *Rotate the page*
scroll *Scroll*
search *Search next/previous item*
toggle_fullscreen *Toggle fullscreen*
toggle_index *Show or hide index*
toggle_inputbar *Show or hide inputbar*
toggle_statusbar *Show or hide statusbar*
zoom *Zoom in or out*
================= ====================================
Pass arguments
^^^^^^^^^^^^^^
Some shortcut function require or have optional arguments which influence the
behaviour of them. Those can be passed as the last argument::
map <C-i> zoom in
map <C-o> zoom out
unmap - Removing a shortcut
---------------------------
In addition to mapping or remaping custom key bindings it is possible to remove
existing ones by using the *:unmap* command. The command is used in the
following way (the explanation of the parameters is described in the *map*
section of this document::
unmap [mode] <binding>
EXAMPLE
=======
::
# zathurarc
# colors
set statusbar_bgcolor #00FF00
set statusbar_fgcolor red
# settings
set height 1024
set width 768
set adjust_open width
# key bindings
map <PageUp> navigate previous
map <PageDown> navigate next
map + zoom in
map - zoom out
map <C-q> quit
SEE ALSO
========