Merge branch 'girara'

Conflicts:
	.gitignore
	LICENSE
	Makefile
	README
	config.def.h
	config.mk
	zathura.1
	zathura.c
This commit is contained in:
Moritz Lipp 2011-09-29 11:41:08 +02:00
commit 2403296c53
31 changed files with 4197 additions and 5569 deletions

7
.gitignore vendored
View file

@ -1,6 +1,9 @@
.depend/
*.o
*.do
config.h
*~
*.rej
*.swp
.depend
zathura
zathura-debug
zathura.pc

View file

@ -1,42 +1,38 @@
# See LICENSE file for license and copyright information
# zathura - user interface
include config.mk
include common.mk
PROJECT = zathura
SOURCE = zathura.c
OBJECTS = ${SOURCE:.c=.o}
DOBJECTS = ${SOURCE:.c=.do}
SOURCE = $(shell find . -iname "*.c")
OBJECTS = $(patsubst %.c, %.o, $(SOURCE))
DOBJECTS = $(patsubst %.c, %.do, $(SOURCE))
ifneq "$(NEEDS_DL)" "0"
LIBS += -ldl
endif
all: options ${PROJECT}
options:
@echo ${PROJECT} build options:
@echo "CFLAGS = ${CFLAGS}"
@echo "LDFLAGS = ${LDFLAGS}"
@echo "LIBS = ${LIBS}"
@echo "DFLAGS = ${DFLAGS}"
@echo "CC = ${CC}"
%.o: %.c
$(ECHO) CC $<
$(QUIET)${CC} -c ${CFLAGS} -o $@ $<
@mkdir -p .depend
$(QUIET)${CC} -c ${CFLAGS} -o $@ $< -MMD -MF .depend/$@.dep
%.do: %.c
$(ECHO) CC $<
$(QUIET)${CC} -c ${CFLAGS} ${DFLAGS} -o $@ $<
@mkdir -p .depend
$(QUIET)${CC} -c ${CFLAGS} ${DFLAGS} -o $@ $< -MMD -MF .depend/$@.dep
${OBJECTS}: config.h config.mk
${DOBJECTS}: config.h config.mk
config.h: config.def.h
@if [ -f $@ ] ; then \
echo "config.h exists, but config.def.h is newer. Please check your" \
"config.h or ${PROJECT} might fail to build." ; \
else \
cp $< $@ ; \
fi
${OBJECTS}: config.mk
${DOBJECTS}: config.mk
${PROJECT}: ${OBJECTS}
$(ECHO) CC -o $@
@ -44,17 +40,20 @@ ${PROJECT}: ${OBJECTS}
clean:
$(QUIET)rm -rf ${PROJECT} ${OBJECTS} ${PROJECT}-${VERSION}.tar.gz \
${DOBJECTS} ${PROJECT}-debug
distclean: clean
$(QUIET)rm -rf config.h
${DOBJECTS} ${PROJECT}-debug .depend ${PROJECT}.pc
${PROJECT}-debug: ${DOBJECTS}
$(ECHO) CC -o ${PROJECT}-debug
$(QUIET)${CC} ${LDFLAGS} -o ${PROJECT}-debug ${DOBJECTS} ${LIBS}
$(ECHO) CC -o $@
$(QUIET)${CC} ${LDFLAGS} -o $@ ${DOBJECTS} ${LIBS}
debug: ${PROJECT}-debug
${PROJECT}.pc: ${PROJECT}.pc.in config.mk
$(QUIET)echo project=${PROJECT} > ${PROJECT}.pc
$(QUIET)echo version=${VERSION} >> ${PROJECT}.pc
$(QUIET)echo includedir=${PREFIX}/include >> ${PROJECT}.pc
$(QUIET)cat ${PROJECT}.pc.in >> ${PROJECT}.pc
valgrind: debug
valgrind --tool=memcheck --leak-check=yes --show-reachable=yes \
./${PROJECT}-debug
@ -64,34 +63,40 @@ gdb: debug
dist: clean
$(QUIET)mkdir -p ${PROJECT}-${VERSION}
$(QUIET)cp -R LICENSE Makefile config.mk config.def.h README \
${PROJECT}.desktop ${PROJECT}rc.5.rst \
${PROJECT}.1 ${SOURCE} ${PROJECT}-${VERSION}
$(QUIET)cp -R LICENSE Makefile config.mk README \
${PROJECT}.1 ${SOURCE} ${PROJECT}.pc.in \
${PROJECT}-${VERSION}
$(QUIET)tar -cf ${PROJECT}-${VERSION}.tar ${PROJECT}-${VERSION}
$(QUIET)gzip ${PROJECT}-${VERSION}.tar
$(QUIET)rm -rf ${PROJECT}-${VERSION}
install: all
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
$(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
$(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)chmod 644 ${DESTDIR}${MANPREFIX}/man1/${PROJECT}.1
$(QUIET)mkdir -p ${DESTDIR}${DESKTOPPREFIX}
$(ECHO) installing desktop file
$(QUIET)install -m 644 ${PROJECT}.desktop ${DESTDIR}${DESKTOPPREFIX}
$(ECHO) installing pkgconfig file
$(QUIET)mkdir -p ${DESTDIR}${PREFIX}/lib/pkgconfig
$(QUIET)cp -f ${PROJECT}.pc ${DESTDIR}${PREFIX}/lib/pkgconfig
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
$(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
-include $(wildcard .depend/*.dep)
.PHONY: all options clean debug valgrind gdb dist install uninstall

25
README
View file

@ -1,28 +1,19 @@
zathura - pdf viewer
zathura - a document viewer
--------------------
zathura is a pdf viewer based on the poppler pdf rendering library
zathura is a highly customizable and functional document viewer based on the
girara user interface library and several document libraries.
Requirements
------------
poppler-glib (>= 0.12.3)
cairo (>= 1.8.8)
gtk2 (>= 2.18.6)
glib2 (>= 2.22.4)
girara
Please note that you need to have a working pkg-config installation
and that the Makefile is only compatible with GNU make.
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.
Configuration
-------------
You can modify some parts of zathura by editing the config.h file
Installation
------------
Customise config.h according to your wishes and run the following
command to build and install zathura:
To build and install zathura:
make install
@ -31,9 +22,3 @@ Uninstall:
To delete zathura from your system, just type:
make uninstall
Use zathura
-----------
Just run:
zathura <file>

97
bookmarks.c Normal file
View file

@ -0,0 +1,97 @@
/* See LICENSE file for license and copyright information */
#include <string.h>
#include "bookmarks.h"
#include "database.h"
#include "document.h"
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* bookmark = g_malloc0(sizeof(zathura_bookmark_t));
bookmark->id = g_strdup(id);
bookmark->page = page;
girara_list_append(zathura->bookmarks.bookmarks, bookmark);
if (zathura->database) {
if (!zathura_db_add_bookmark(zathura->database, zathura->document->file_path, bookmark)) {
girara_warning("Failed to add bookmark to database.");
}
}
return bookmark;
}
bool
zathura_bookmark_remove(zathura_t* zathura, const gchar* id)
{
g_return_val_if_fail(zathura && zathura->document && zathura->bookmarks.bookmarks, false);
g_return_val_if_fail(id, false);
zathura_bookmark_t* bookmark = zathura_bookmark_get(zathura, id);
if (!bookmark) {
return false;
}
if (zathura->database) {
if (!zathura_db_remove_bookmark(zathura->database, zathura->document->file_path, bookmark->id)) {
girara_warning("Failed to remove bookmark from database.");
}
}
girara_list_remove(zathura->bookmarks.bookmarks, bookmark);
return true;
}
zathura_bookmark_t*
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;
}
void
zathura_bookmark_free(zathura_bookmark_t* bookmark)
{
if (!bookmark) {
return;
}
g_free(bookmark->id);
g_free(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(file, false);
girara_list_t* bookmarks = zathura_db_load_bookmarks(zathura->database, file);
if (!bookmarks) {
return false;
}
girara_list_free(zathura->bookmarks.bookmarks);
zathura->bookmarks.bookmarks = bookmarks;
return true;
}

56
bookmarks.h Normal file
View file

@ -0,0 +1,56 @@
/* See LICENSE file for license and copyright information */
#ifndef BOOKMARKS_H
#define BOOKMARKS_H
#include <stdbool.h>
#include "zathura.h"
struct zathura_bookmark_s
{
gchar* id;
unsigned int page;
};
typedef struct zathura_bookmark_s zathura_bookmark_t;
/**
* Create a bookmark and add it to the list of bookmarks.
* @param zathura The zathura instance.
* @param id The bookmark's id.
* @param page The bookmark's page.
* @return the bookmark instance or NULL on failure.
*/
zathura_bookmark_t* zathura_bookmark_add(zathura_t* zathura, const gchar* id, unsigned int page);
/**
* Remove a bookmark from the list of bookmarks.
* @param zathura The zathura instance.
* @param id The bookmark's id.
* @return true on success, false otherwise
*/
bool zathura_bookmark_remove(zathura_t* zathura, const gchar* id);
/**
* Get bookmark from the list of bookmarks.
* @param zathura The zathura instance.
* @param id The bookmark's id.
* @return The bookmark instance if it exists or NULL otherwise.
*/
zathura_bookmark_t* zathura_bookmark_get(zathura_t* zathura, const gchar* id);
/**
* Free a bookmark instance.
* @param bookmark The bookmark instance.
*/
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
*/
bool zathura_bookmarks_load(zathura_t* zathura, const gchar* file);
#endif // BOOKMARKS_H

91
callbacks.c Normal file
View file

@ -0,0 +1,91 @@
/* See LICENSE file for license and copyright information */
#include <girara.h>
#include <stdlib.h>
#include <gtk/gtk.h>
#include "callbacks.h"
#include "zathura.h"
#include "render.h"
#include "document.h"
#include "utils.h"
gboolean
cb_destroy(GtkWidget* UNUSED(widget), gpointer UNUSED(data))
{
return TRUE;
}
void
buffer_changed(girara_session_t* session)
{
g_return_if_fail(session != NULL);
g_return_if_fail(session->global.data != NULL);
zathura_t* zathura = session->global.data;
char* buffer = girara_buffer_get(session);
if (buffer) {
girara_statusbar_item_set_text(session, zathura->ui.statusbar.buffer, buffer);
free(buffer);
} else {
girara_statusbar_item_set_text(session, zathura->ui.statusbar.buffer, "");
}
}
void
cb_view_vadjustment_value_changed(GtkAdjustment *adjustment, gpointer data)
{
zathura_t* zathura = data;
if (!zathura || !zathura->document || !zathura->document->pages || !zathura->ui.page_view) {
return;
}
/* get current adjustment values */
gdouble lower = gtk_adjustment_get_value(adjustment);
gdouble upper = lower + gtk_adjustment_get_page_size(adjustment);
/* 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;
}
double begin = offset->y;
double end = offset->y + page->height;
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 <] */
) {
page->visible = true;
if (page->surface == NULL) {
render_page(zathura->sync.render_thread, page);
}
} else {
page->visible = false;
cairo_surface_destroy(page->surface);
page->surface = NULL;
}
free(offset);
}
}
void
cb_pages_per_row_value_changed(girara_session_t* UNUSED(session), girara_setting_t* setting)
{
int pages_per_row = setting->value.i;
zathura_t* zathura = setting->data;
if (pages_per_row < 1) {
pages_per_row = 1;
}
page_view_set_mode(zathura, pages_per_row);
}

42
callbacks.h Normal file
View file

@ -0,0 +1,42 @@
/* See LICENSE file for license and copyright information */
#ifndef CALLBACKS_H
#define CALLBACKS_H
#include <gtk/gtk.h>
#include <girara.h>
/**
* Quits the current zathura session
*
* @param widget The gtk window of zathura
* @param data NULL
* @return TRUE
*/
gboolean cb_destroy(GtkWidget* widget, gpointer data);
/**
* This function gets called when the buffer of girara changes
*
* @param session The girara session
*/
void buffer_changed(girara_session_t* session);
/**
* This function gets called when the value of the vertical scrollbars
* changes (e.g.: by scrolling, moving to another page)
*
* @param adjustment The vadjustment of the page view
* @param data NULL
*/
void cb_view_vadjustment_value_changed(GtkAdjustment *adjustment, gpointer data);
/**
* This function gets called when the value of the "pages-per-row"
* variable changes
*
* @param session The current girara session
* @param setting The "pages-per-row" setting
*/
void cb_pages_per_row_value_changed(girara_session_t* session, girara_setting_t* setting);
#endif // CALLBACKS_H

169
commands.c Normal file
View file

@ -0,0 +1,169 @@
/* See LICENSE file for license and copyright information */
#include "commands.h"
#include "bookmarks.h"
#include "database.h"
#include "zathura.h"
#include "print.h"
#include "document.h"
bool
cmd_bookmark_create(girara_session_t* UNUSED(session), girara_list_t*
UNUSED(argument_list))
{
return true;
}
bool
cmd_bookmark_delete(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 = girara_list_nth(argument_list, 0);
if (zathura_bookmark_remove(zathura, bookmark)) {
girara_notify(session, GIRARA_INFO, "Removed bookmark: %s", bookmark);
} else {
girara_notify(session, GIRARA_ERROR, "Failed to remove bookmark: %s", bookmark);
}
return true;
}
bool
cmd_bookmark_open(girara_session_t* UNUSED(session), girara_list_t*
UNUSED(argument_list))
{
return true;
}
bool
cmd_close(girara_session_t* session, girara_list_t* UNUSED(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) {
// nothing needs to be done
return true;
}
document_close(zathura);
return true;
}
bool
cmd_info(girara_session_t* UNUSED(session), girara_list_t*
UNUSED(argument_list))
{
return true;
}
bool
cmd_help(girara_session_t* UNUSED(session), girara_list_t*
UNUSED(argument_list))
{
return true;
}
bool
cmd_open(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;
const int argc = girara_list_size(argument_list);
if (argc > 2) {
girara_notify(session, GIRARA_ERROR, "Too many arguments.");
return false;
}
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 {
girara_notify(session, GIRARA_ERROR, "No arguments given.");
return false;
}
return true;
}
bool
cmd_print(girara_session_t* session, girara_list_t* UNUSED(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 open document.");
return false;
}
print((zathura_t*) session->global.data);
return true;
}
bool
cmd_save(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 open document.");
return false;
}
if (girara_list_size(argument_list) == 1) {
document_save(zathura, girara_list_nth(argument_list, 0), false);
}
else {
girara_notify(session, GIRARA_ERROR, "Invalid number of arguments.");
return false;
}
return true;
}
bool
cmd_savef(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 open document.");
return false;
}
if (girara_list_size(argument_list) == 1) {
document_save(zathura, girara_list_nth(argument_list, 0), true);
}
else {
girara_notify(session, GIRARA_ERROR, "Invalid number of arguments.");
return false;
}
return true;
}

100
commands.h Normal file
View file

@ -0,0 +1,100 @@
/* See LICENSE file for license and copyright information */
#ifndef COMMANDS_H
#define COMMANDS_H
#include <stdbool.h>
#include <girara.h>
/**
* Create a bookmark
*
* @param session The used girara session
* @param argument_list List of passed arguments
* @return true if no error occured
*/
bool cmd_bookmark_create(girara_session_t* session, girara_list_t* argument_list);
/**
* Delete a bookmark
*
* @param session The used girara session
* @param argument_list List of passed arguments
* @return true if no error occured
*/
bool cmd_bookmark_delete(girara_session_t* session, girara_list_t* argument_list);
/**
* Open a bookmark
*
* @param session The used girara session
* @param argument_list List of passed arguments
* @return true if no error occured
*/
bool cmd_bookmark_open(girara_session_t* session, girara_list_t* argument_list);
/**
* Close zathura
*
* @param session The used girara session
* @param argument_list List of passed arguments
* @return true if no error occured
*/
bool cmd_close(girara_session_t* session, girara_list_t* argument_list);
/**
* Display document information
*
* @param session The used girara session
* @param argument_list List of passed arguments
* @return true if no error occured
*/
bool cmd_info(girara_session_t* session, girara_list_t* argument_list);
/**
* Display help
*
* @param session The used girara session
* @param argument_list List of passed arguments
* @return true if no error occured
*/
bool cmd_help(girara_session_t* session, girara_list_t* argument_list);
/**
* Opens a document file
*
* @param session The used girara session
* @param argument_list List of passed arguments
* @return true if no error occured
*/
bool cmd_open(girara_session_t* session, girara_list_t* argument_list);
/**
* Print the current file
*
* @param session The used girara session
* @param argument_list List of passed arguments
* @return true if no error occured
*/
bool cmd_print(girara_session_t* session, girara_list_t* argument_list);
/**
* Save the current file
*
* @param session The used girara session
* @param argument_list List of passed arguments
* @return true if no error occured
*/
bool cmd_save(girara_session_t* session, girara_list_t* argument_list);
/**
* Save the current file and overwrite existing files
*
* @param session The used girara session
* @param argument_list List of passed arguments
* @return true if no error occured
*/
bool cmd_savef(girara_session_t* session, girara_list_t* argument_list);
#endif // COMMANDS_H

144
completion.c Normal file
View file

@ -0,0 +1,144 @@
/* See LICENSE file for license and copyright information */
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <unistd.h>
#include <libgen.h>
#include "completion.h"
#include "utils.h"
girara_completion_t*
cc_open(girara_session_t* session, char* input)
{
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);
gchar* path = NULL;
gchar* current_path = NULL;
if (completion == NULL || group == NULL) {
goto error_free;
}
path = girara_fix_path(input);
if (path == NULL) {
goto error_free;
}
/* 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;
#ifdef PATH_MAX
path_max = PATH_MAX;
#else
path_max = pathconf(path,_PC_PATH_MAX);
if (path_max <= 0)
path_max = 4096;
#endif
char cwd[path_max];
getcwd(cwd, path_max);
char* tmp_path = g_strdup_printf("%s/%s", cwd, path);
if (tmp_path == NULL) {
goto error_free;
}
g_free(path);
path = tmp_path;
}
/* Append a slash if the given argument is a directory */
bool is_dir = (path[strlen(path) - 1] == '/') ? true : false;
if ((g_file_test(path, G_FILE_TEST_IS_DIR) == TRUE) && !is_dir) {
char* tmp_path = g_strdup_printf("%s/", path);
if (tmp_path == NULL) {
goto error_free;
}
g_free(path);
path = tmp_path;
is_dir = true;
}
/* get current path */
char* tmp = g_strdup(path);
current_path = is_dir ? g_strdup(tmp) : g_strdup(dirname(tmp));
g_free(tmp);
/* get current file */
gchar* current_file = is_dir ? "" : basename(path);
int current_file_length = strlen(current_file);
/* 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) {
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);
}
g_free(path);
girara_completion_add_group(completion, group);
return completion;
error_free:
if (completion) {
girara_completion_free(completion);
}
if (group) {
girara_completion_group_free(group);
}
g_free(current_path);
g_free(path);
return NULL;
}

18
completion.h Normal file
View file

@ -0,0 +1,18 @@
/* See LICENSE file for license and copyright information */
#ifndef COMPLETION_H
#define COMPLETION_H
#include <girara.h>
/**
* Completion for the open command - Creates a list of accesible directories or
* files
*
* @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_open(girara_session_t* session, char* input);
#endif // COMPLETION_H

150
config.c Normal file
View file

@ -0,0 +1,150 @@
/* See LICENSE file for license and copyright information */
#include "config.h"
#include "commands.h"
#include "completion.h"
#include "callbacks.h"
#include "shortcuts.h"
#include "zathura.h"
void
config_load_default(zathura_t* zathura)
{
if (!zathura || !zathura->ui.session) {
return;
}
int int_value = 0;
char* string_value = NULL;
girara_session_t* gsession = zathura->ui.session;
/* mode settings */
zathura->modes.normal = gsession->modes.normal;
zathura->modes.fullscreen = girara_mode_add(gsession, "fullscreen");
zathura->modes.index = girara_mode_add(gsession, "index");
zathura->modes.insert = girara_mode_add(gsession, "insert");
#define NORMAL zathura->modes.normal
#define INSERT zathura->modes.insert
#define INDEX zathura->modes.index
#define FULLSCREEN zathura->modes.fullscreen
girara_mode_set(gsession, zathura->modes.normal);
/* zathura settings */
int_value = 10;
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);
string_value = "#FFFFFF";
girara_setting_add(gsession, "recolor-dark-color", 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);
/* 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);
/* 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)");
/* add shortcut mappings */
girara_shortcut_mapping_add(gsession, "abort", sc_abort);
girara_shortcut_mapping_add(gsession, "adjust_window", sc_adjust_window);
girara_shortcut_mapping_add(gsession, "change_mode", sc_change_mode);
girara_shortcut_mapping_add(gsession, "follow", sc_follow);
girara_shortcut_mapping_add(gsession, "goto", sc_goto);
girara_shortcut_mapping_add(gsession, "index_navigate", sc_navigate_index);
girara_shortcut_mapping_add(gsession, "navigate", sc_navigate);
girara_shortcut_mapping_add(gsession, "quit", sc_quit);
girara_shortcut_mapping_add(gsession, "recolor", sc_recolor);
girara_shortcut_mapping_add(gsession, "reload", sc_reload);
girara_shortcut_mapping_add(gsession, "rotate", sc_rotate);
girara_shortcut_mapping_add(gsession, "scroll", sc_scroll);
girara_shortcut_mapping_add(gsession, "search", sc_search);
girara_shortcut_mapping_add(gsession, "toggle_fullscreen", sc_toggle_fullscreen);
girara_shortcut_mapping_add(gsession, "toggle_index", sc_toggle_index);
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);
}
void
config_load_file(zathura_t* zathura, char* path)
{
if (zathura == NULL) {
return;
}
girara_config_parse(zathura->ui.session, path);
}

View file

@ -1,368 +0,0 @@
/* settings */
int default_width = 800;
int default_height = 600;
float zoom_step = 10;
float zoom_min = 10;
float zoom_max = 400;
float scroll_step = 40;
float transparency = 0.4;
float smooth_scrolling = 0.0;
int n_completion_items = 15;
/* completion */
static const char FORMAT_COMMAND[] = "<b>%s</b>";
static const char FORMAT_DESCRIPTION[] = "<i>%s</i>";
/* Use XDG directory specification if no config and data directory are given on
* the command line. Uncomment the next line if you just want to use CONFIG_DIR
* and DATA_DIR instead (these will be the default locations if the XDG_*
* environment variables are not set anyway) */
/* #define ZATHURA_NO_XDG */
/* directories and files */
static const char BOOKMARK_FILE[] = "bookmarks";
static const char ZATHURA_RC[] = "zathurarc";
static const char GLOBAL_RC[] = "/etc/zathurarc";
static const char CONFIG_DIR[] = "~/.config/zathura";
static const char DATA_DIR[] = "~/.local/share/zathura";
/* bookmarks */
enum
{
BM_PAGE_ENTRY = 0,
BM_PAGE_OFFSET,
BM_PAGE_SCALE,
BM_MAX,
};
static const char *bm_reserved_names[] =
{
[BM_PAGE_ENTRY] = "page",
[BM_PAGE_OFFSET] = "offset",
[BM_PAGE_SCALE] = "scale",
};
int save_position = 1;
int save_zoom_level = 1;
/* look */
char* font = "monospace normal 9";
char* default_bgcolor = "#000000";
char* default_fgcolor = "#DDDDDD";
char* inputbar_bgcolor = "#141414";
char* inputbar_fgcolor = "#9FBC00";
char* statusbar_bgcolor = "#000000";
char* statusbar_fgcolor = "#FFFFFF";
char* completion_fgcolor = "#DDDDDD";
char* completion_bgcolor = "#232323";
char* completion_g_fgcolor = "#DEDEDE";
char* completion_g_bgcolor = "#FF00FF";
char* completion_hl_fgcolor = "#232323";
char* completion_hl_bgcolor = "#9FBC00";
char* notification_e_bgcolor = "#FF1212";
char* notification_e_fgcolor = "#FFFFFF";
char* notification_w_bgcolor = "#FFF712";
char* notification_w_fgcolor = "#000000";
char* recolor_darkcolor = "#353535";
char* recolor_lightcolor = "#DBDBDB";
char* search_highlight = "#9FBC00";
char* select_text = "#000000";
/* statusbar */
char* default_text = "[No Name]";
/* printing */
char* list_printer_command = "lpstat -v | sed -n '/^.*device for \\(.*\\): .*$/s//\\1/p'";
char* print_command = "lp -d '%s' -P %s %s %s"; /* printer / pages / file */
/* open uri */
char* uri_command = "firefox %s"; /* uri */
/* additional settings */
gboolean show_scrollbars = FALSE;
gboolean scroll_wrap = TRUE;
int adjust_open = ADJUST_BESTFIT;
#define SELECTION_STYLE POPPLER_SELECTION_GLYPH
#define GOTO_MODE GOTO_LABELS /* GOTO_DEFAULT, GOTO_LABELS, GOTO_OFFSET */
/* define additional modes */
#define INSERT (1 << 4)
#define VISUAL (1 << 5)
#define EMACS_CX (1 << 6)
/* mode names */
ModeName mode_names[] = {
/* default mode names */
{"all", ALL, ""},
{"fullscreen", FULLSCREEN, ""},
{"index", INDEX, ""},
{"normal", NORMAL, ""},
/* additional mode names */
{"insert", INSERT, "-- INSERT --"},
{"visual", VISUAL, "-- VISUAL --"}
};
/* shortcuts */
Shortcut shortcuts[] = {
/* mask, key, function, mode, argument */
{GDK_CONTROL_MASK, GDK_c, sc_abort, ALL, {0} },
{0, GDK_a, sc_adjust_window, NORMAL, { ADJUST_BESTFIT } },
{0, GDK_s, sc_adjust_window, NORMAL, { ADJUST_WIDTH } },
{0, GDK_Escape, sc_abort, ALL, {0} },
{0, GDK_BackSpace, sc_change_buffer, ALL, { DELETE_LAST } },
{0, GDK_i, sc_change_mode, NORMAL, { INSERT } },
{0, GDK_v, sc_change_mode, NORMAL, { VISUAL } },
{0, GDK_m, sc_change_mode, NORMAL, { ADD_MARKER } },
{0, GDK_apostrophe, sc_change_mode, NORMAL, { EVAL_MARKER } },
{0, GDK_slash, sc_focus_inputbar, NORMAL, { .data = "/" } },
{GDK_SHIFT_MASK, GDK_slash, sc_focus_inputbar, NORMAL, { .data = "/" } },
{GDK_SHIFT_MASK, GDK_question, sc_focus_inputbar, NORMAL, { .data = "?" } },
{0, GDK_colon, sc_focus_inputbar, NORMAL, { .data = ":" } },
{0, GDK_o, sc_focus_inputbar, NORMAL, { .data = ":open " } },
{0, GDK_O, sc_focus_inputbar, NORMAL, { APPEND_FILEPATH, .data = ":open " } },
{0, GDK_f, sc_follow, NORMAL, {0} },
{0, GDK_J, sc_navigate, NORMAL, { NEXT } },
{0, GDK_K, sc_navigate, NORMAL, { PREVIOUS } },
{GDK_MOD1_MASK, GDK_Right, sc_navigate, NORMAL, { NEXT } },
{GDK_MOD1_MASK, GDK_Left, sc_navigate, NORMAL, { PREVIOUS } },
{0, GDK_Left, sc_navigate, FULLSCREEN, { PREVIOUS } },
{0, GDK_Up, sc_navigate, FULLSCREEN, { PREVIOUS } },
{0, GDK_Down, sc_navigate, FULLSCREEN, { NEXT } },
{0, GDK_Right, sc_navigate, FULLSCREEN, { NEXT } },
{0, GDK_space, sc_navigate, FULLSCREEN, { NEXT } },
{0, GDK_k, sc_navigate_index, INDEX, { UP } },
{0, GDK_j, sc_navigate_index, INDEX, { DOWN } },
{0, GDK_h, sc_navigate_index, INDEX, { COLLAPSE } },
{0, GDK_l, sc_navigate_index, INDEX, { EXPAND } },
{0, GDK_space, sc_navigate_index, INDEX, { SELECT } },
{0, GDK_Return, sc_navigate_index, INDEX, { SELECT } },
{GDK_CONTROL_MASK, GDK_i, sc_recolor, NORMAL, {0} },
{0, GDK_R, sc_reload, NORMAL, {0} },
{0, GDK_r, sc_rotate, NORMAL, {0} },
{0, GDK_n, sc_search, NORMAL, { FORWARD } },
{0, GDK_N, sc_search, NORMAL, { BACKWARD } },
{0, GDK_h, sc_scroll, NORMAL, { LEFT } },
{0, GDK_j, sc_scroll, NORMAL, { DOWN } },
{0, GDK_k, sc_scroll, NORMAL, { UP } },
{0, GDK_l, sc_scroll, NORMAL, { RIGHT } },
{0, GDK_Left, sc_scroll, NORMAL, { LEFT } },
{0, GDK_Up, sc_scroll, NORMAL, { UP } },
{0, GDK_Down, sc_scroll, NORMAL, { DOWN } },
{0, GDK_Right, sc_scroll, NORMAL, { RIGHT } },
{GDK_CONTROL_MASK, GDK_d, sc_scroll, NORMAL, { HALF_DOWN } },
{GDK_CONTROL_MASK, GDK_u, sc_scroll, NORMAL, { HALF_UP } },
{GDK_CONTROL_MASK, GDK_f, sc_scroll, NORMAL, { FULL_DOWN } },
{GDK_CONTROL_MASK, GDK_b, sc_scroll, NORMAL, { FULL_UP } },
{0, GDK_space, sc_scroll, NORMAL, { FULL_DOWN } },
{0, GDK_0, sc_switch_goto_mode, NORMAL, {0} },
{0, GDK_F5, sc_toggle_fullscreen, NORMAL | FULLSCREEN, {0} },
{0, GDK_Tab, sc_toggle_index, NORMAL | INDEX, {0} },
{GDK_CONTROL_MASK, GDK_m, sc_toggle_inputbar, NORMAL, {0} },
{GDK_CONTROL_MASK, GDK_n, sc_toggle_statusbar, NORMAL, {0} },
{GDK_CONTROL_MASK, GDK_q, sc_quit, ALL, {0} },
{0, GDK_plus, sc_zoom, NORMAL | FULLSCREEN, { ZOOM_IN } },
{0, GDK_minus, sc_zoom, NORMAL | FULLSCREEN, { ZOOM_OUT } },
{0, GDK_equal, sc_zoom, NORMAL | FULLSCREEN, { ZOOM_ORIGINAL } },
};
/* inputbar shortcuts */
InputbarShortcut inputbar_shortcuts[] = {
/* mask, key, function, argument */
{0, GDK_Escape, isc_abort, {0} },
{GDK_CONTROL_MASK, GDK_c, isc_abort, {0} },
{0, GDK_Up, isc_command_history, {0} },
{0, GDK_Down, isc_command_history, {0} },
{0, GDK_Tab, isc_completion, { NEXT } },
{GDK_CONTROL_MASK, GDK_Tab, isc_completion, { NEXT_GROUP } },
{0, GDK_ISO_Left_Tab, isc_completion, { PREVIOUS } },
{GDK_CONTROL_MASK, GDK_ISO_Left_Tab, isc_completion, { PREVIOUS_GROUP } },
{0, GDK_BackSpace, isc_string_manipulation, { DELETE_LAST_CHAR } },
{GDK_CONTROL_MASK, GDK_h, isc_string_manipulation, { DELETE_LAST_CHAR } },
{GDK_CONTROL_MASK, GDK_u, isc_string_manipulation, { DELETE_TO_LINE_START } },
{GDK_CONTROL_MASK, GDK_w, isc_string_manipulation, { DELETE_LAST_WORD } },
{GDK_CONTROL_MASK, GDK_f, isc_string_manipulation, { NEXT_CHAR } },
{GDK_CONTROL_MASK, GDK_b, isc_string_manipulation, { PREVIOUS_CHAR } },
};
/* mouse settings */
MouseScrollEvent mouse_scroll_events[] = {
/* direction, function, argument */
{GDK_SCROLL_LEFT, sc_scroll, { LEFT } },
{GDK_SCROLL_UP, sc_scroll, { UP } },
{GDK_SCROLL_DOWN, sc_scroll, { DOWN } },
{GDK_SCROLL_RIGHT, sc_scroll, { RIGHT } },
};
/* commands */
Command commands[] = {
/* command, abbreviation, function, completion, description */
{"blist", 0, cmd_open_bookmark, cc_bookmark, "List and open bookmark" },
{"bmark", "b", cmd_bookmark, 0, "Bookmark current page" },
{"close", "c", cmd_close, 0, "Close current file" },
{"coffset", 0, cmd_correct_offset, 0, "Correct page offset" },
{"delbmark", 0, cmd_delete_bookmark, cc_bookmark, "Delete bookmark" },
{"export", "e", cmd_export, cc_export, "Export images or attached files" },
{"info", "i", cmd_info, 0, "Show information about the document" },
{"map", "m", cmd_map, 0, "Map keybinding to a function" },
{"open", "o", cmd_open, cc_open, "Open a file" },
{"print", "p", cmd_print, cc_print, "Print the document" },
{"quit", "q", cmd_quit, 0, "Quit zathura" },
{"rotate", "r", cmd_rotate, 0, "Rotate the page" },
{"set", "s", cmd_set, cc_set, "Set an option" },
{"write", "w", cmd_save, 0, "Save the document" },
{"write!", "w!", cmd_savef, 0, "Save the document (and force overwriting)" },
};
/* buffer commands */
BufferCommand buffer_commands[] = {
/* regex, function, argument */
{"^gg$", bcmd_goto, { TOP } },
{"^G$", bcmd_goto, { BOTTOM } },
{"^[0-9]+G$", bcmd_goto, {0} },
{"^zI$", bcmd_zoom, { ZOOM_IN } },
{"^zO$", bcmd_zoom, { ZOOM_OUT } },
{"^z0$", bcmd_zoom, { ZOOM_ORIGINAL } },
{"^[0-9]+Z$", bcmd_zoom, { ZOOM_SPECIFIC } },
{"^[0-9]+%$", bcmd_scroll, {0} },
};
/* special commands */
SpecialCommand special_commands[] = {
/* identifier, function, a, argument */
{'/', scmd_search, 1, { DOWN } },
{'?', scmd_search, 1, { UP } },
};
/* settings */
Setting settings[] = {
/* name, variable, type, render, re-init, description */
{"adjust_open", &(adjust_open), 'i', FALSE, FALSE, "Adjust mode"},
{"browser", &(uri_command), 's', FALSE, FALSE, "Command to open URIs"},
{"completion_bgcolor", &(completion_bgcolor), 's', FALSE, TRUE, "Completion background color"},
{"completion_fgcolor", &(completion_fgcolor), 's', FALSE, TRUE, "Completion foreground color"},
{"completion_g_bgcolor", &(completion_g_bgcolor), 's', FALSE, TRUE, "Completion (group) background color"},
{"completion_g_fgcolor", &(completion_g_fgcolor), 's', FALSE, TRUE, "Completion (group) foreground color"},
{"completion_hl_bgcolor", &(completion_hl_bgcolor), 's', FALSE, TRUE, "Completion (highlight) background color"},
{"completion_hl_fgcolor", &(completion_hl_fgcolor), 's', FALSE, TRUE, "Completion (highlight) foreground color"},
{"default_bgcolor", &(default_bgcolor), 's', FALSE, TRUE, "Default background color"},
{"default_fgcolor", &(default_fgcolor), 's', FALSE, TRUE, "Default foreground color"},
{"default_text", &(default_text), 's', FALSE, FALSE, "Default text"},
{"font", &(font), 's', FALSE, TRUE, "The used font" },
{"height", &(default_height), 'i', FALSE, FALSE, "Default window height"},
{"inputbar_bgcolor", &(inputbar_bgcolor), 's', FALSE, TRUE, "Inputbar background color"},
{"inputbar_fgcolor", &(inputbar_fgcolor), 's', FALSE, TRUE, "Inputbar foreground color"},
{"labels", &(Zathura.Global.enable_labelmode), 'b', FALSE, TRUE, "Allow label mode"},
{"list_printer_command", &(list_printer_command), 's', FALSE, FALSE, "Command to list printers"},
{"n_completion_items", &(n_completion_items), 'i', FALSE, FALSE, "Number of completion items"},
{"notification_e_bgcolor", &(notification_e_bgcolor), 's', FALSE, TRUE, "Notification (error) background color"},
{"notification_e_fgcolor", &(notification_e_fgcolor), 's', FALSE, TRUE, "Notification (error) foreground color"},
{"notification_w_bgcolor", &(notification_w_bgcolor), 's', FALSE, TRUE, "Notification (warning) background color"},
{"notification_w_fgcolor", &(notification_w_fgcolor), 's', FALSE, TRUE, "Notification (warning) foreground color"},
{"offset", &(Zathura.PDF.page_offset), 'i', FALSE, FALSE, "Optional page offset" },
{"print_command", &(print_command), 's', FALSE, FALSE, "Command to print"},
{"recolor", &(Zathura.Global.recolor), 'b', TRUE, FALSE, "Invert the image" },
{"recolor_darkcolor", &(recolor_darkcolor), 's', FALSE, TRUE, "Recoloring (dark color)"},
{"recolor_lightcolor", &(recolor_lightcolor), 's', FALSE, TRUE, "Recoloring (light color)"},
{"save_position", &(save_position), 'b', FALSE, FALSE, "Save position in file on quit and restore it on open"},
{"save_zoom_level", &(save_zoom_level), 'b', FALSE, FALSE, "Save zoom level on quit and restore it on open"},
{"scroll_step", &(scroll_step), 'f', FALSE, FALSE, "Scroll step"},
{"scroll_wrap", &(scroll_wrap), 'b', FALSE, FALSE, "Wrap scolling at last page"},
{"scrollbars", &(show_scrollbars), 'b', FALSE, TRUE, "Show scrollbars"},
{"show_statusbar", &(Zathura.Global.show_statusbar), 'b', FALSE, TRUE, "Show statusbar"},
{"show_inputbar", &(Zathura.Global.show_inputbar), 'b', FALSE, TRUE, "Show inputbar"},
{"search_highlight", &(search_highlight), 's', FALSE, TRUE, "Highlighted results"},
{"select_text", &(select_text), 's', FALSE, TRUE, "Rectangle of the selected text"},
{"smooth_scrolling", &(smooth_scrolling), 'f', FALSE, TRUE, "Smooth scrolling"},
{"statusbar_bgcolor", &(statusbar_bgcolor), 's', FALSE, TRUE, "Statusbar background color"},
{"statusbar_fgcolor", &(statusbar_fgcolor), 's', FALSE, TRUE, "Statusbar foreground color"},
{"transparency", &(transparency), 'f', FALSE, FALSE, "Transparency of rectangles"},
{"uri_command", &(uri_command), 's', FALSE, FALSE, "Command for opening URIs"},
{"width", &(default_width), 'i', FALSE, FALSE, "Default window width"},
{"zoom_max", &(zoom_max), 'f', FALSE, FALSE, "Zoom maximum"},
{"zoom_min", &(zoom_min), 'f', FALSE, FALSE, "Zoom minimum"},
{"zoom_step", &(zoom_step), 'f', FALSE, FALSE, "Zoom step"},
};
/* shortcut names */
ShortcutName shortcut_names[] = {
{"abort", sc_abort},
{"adjust_window", sc_adjust_window},
{"change_buffer", sc_change_buffer},
{"change_mode", sc_change_mode},
{"focus_inputbar", sc_focus_inputbar},
{"follow", sc_follow},
{"navigate", sc_navigate},
{"navigate_index", sc_navigate_index},
{"quit", sc_quit},
{"recolor", sc_recolor},
{"reload", sc_reload},
{"rotate", sc_rotate},
{"scroll", sc_scroll},
{"search", sc_search},
{"switch_goto_mode", sc_switch_goto_mode},
{"toggle_fullscreen", sc_toggle_fullscreen},
{"toggle_index", sc_toggle_index},
{"toggle_inputbar", sc_toggle_inputbar},
{"toggle_statusbar", sc_toggle_statusbar},
{"zoom", sc_zoom},
};
/* argument names */
ArgumentName argument_names[] = {
{"add_marker", ADD_MARKER},
{"backward", BACKWARD},
{"bestfit", ADJUST_BESTFIT},
{"collapse", COLLAPSE},
{"delete_last", DELETE_LAST},
{"down", DOWN},
{"eval_marker", EVAL_MARKER},
{"expand", EXPAND},
{"forward", FORWARD},
{"full_down", FULL_DOWN},
{"full_up", FULL_UP},
{"half_down", HALF_DOWN},
{"half_up", HALF_UP},
{"in", ZOOM_IN},
{"insert", INSERT},
{"left", LEFT},
{"next", NEXT},
{"noadjust", ADJUST_NONE},
{"original", ZOOM_ORIGINAL},
{"out", ZOOM_OUT},
{"previous", PREVIOUS},
{"right", RIGHT},
{"select", SELECT},
{"up", UP},
{"visual", VISUAL},
{"width", ADJUST_WIDTH},
};
/* special keys */
GDKKey gdk_keys[] = {
{"<BackSpace>", GDK_BackSpace},
{"<CapsLock>", GDK_Caps_Lock},
{"<Down>", GDK_Down},
{"<Esc>", GDK_Escape},
{"<F10>", GDK_F10},
{"<F11>", GDK_F11},
{"<F12>", GDK_F12},
{"<F1>", GDK_F1},
{"<F2>", GDK_F2},
{"<F3>", GDK_F3},
{"<F4>", GDK_F4},
{"<F5>", GDK_F5},
{"<F6>", GDK_F6},
{"<F7>", GDK_F7},
{"<F8>", GDK_F8},
{"<F9>", GDK_F9},
{"<Left>", GDK_Left},
{"<PageDown>", GDK_Page_Down},
{"<PageUp>", GDK_Page_Up},
{"<Return>", GDK_Return},
{"<Right>", GDK_Right},
{"<Space>", GDK_space},
{"<Super>", GDK_Super_L},
{"<Tab>", GDK_Tab},
{"<Up>", GDK_Up},
};

25
config.h Normal file
View file

@ -0,0 +1,25 @@
/* See LICENSE file for license and copyright information */
#ifndef CONFIG_H
#define CONFIG_H
#define GLOBAL_RC "/etc/zathurarc"
#define ZATHURA_RC "zathurarc"
#include "zathura.h"
/**
* This function loads the default values of the configuration
*
* @param zathura the zathura session
*/
void config_load_default(zathura_t* zathura);
/**
* Loads and evaluates a configuration file
*
* @param path Path to the configuration file
*/
void config_load_file(zathura_t* zathura, char* path);
#endif // CONFIG_H

View file

@ -1,28 +1,37 @@
# See LICENSE file for license and copyright information
# zathura make config
VERSION = 0.0.8.4
VERSION = 0.0.8.1
# paths
PREFIX ?= /usr
MANPREFIX ?= ${PREFIX}/share/man
DESKTOPPREFIX ?= ${PREFIX}/share/applications
# libs
GTK_INC = $(shell pkg-config --cflags gtk+-2.0 poppler-glib)
GTK_LIB = $(shell pkg-config --libs gtk+-2.0 gthread-2.0 poppler-glib)
INCS = -I. -I/usr/include ${GTK_INC}
LIBS = -lc ${GTK_LIB} -lpthread -lm
# set this to 0 if you don't need to link against dl
NEEDS_DL ?= 1
# compiler flags
CFLAGS += -std=c99 -pedantic -Wall $(INCS)
GTK_INC ?= $(shell pkg-config --cflags gtk+-2.0)
GTK_LIB ?= $(shell pkg-config --libs gtk+-2.0 gthread-2.0)
# debug flags
GIRARA_INC ?= $(shell pkg-config --cflags girara-gtk2)
GIRARA_LIB ?= $(shell pkg-config --libs girara-gtk2)
SQLITE_INC ?= $(shell pkg-config --cflags sqlite3)
SQLITE_LIB ?= $(shell pkg-config --libs sqlite3)
INCS = ${GIRARA_INC} ${GTK_INC} $(SQLITE_INC)
LIBS = ${GIRARA_LIB} ${GTK_LIB} $(SQLITE_LIB) -lpthread -lm
# flags
CFLAGS += -std=c99 -pedantic -Wall -Wno-format-zero-length -Wextra $(INCS)
# debug
DFLAGS = -g
# linker flags
LDFLAGS ?=
# ld
LDFLAGS += -rdynamic
# compiler
CC ?= gcc
@ -30,5 +39,5 @@ CC ?= gcc
# strip
SFLAGS ?= -s
# set to something != 0 to enable verbose build output
# set to something != 0 if you want verbose build output
VERBOSE ?= 0

176
database-sqlite.c Normal file
View file

@ -0,0 +1,176 @@
/* See LICENSE file for license and copyright information */
#include <glib.h>
#include <sqlite3.h>
#include <girara.h>
#include "database.h"
struct zathura_database_s
{
sqlite3* session;
};
zathura_database_t*
zathura_db_init(const char* path)
{
zathura_database_t* db = g_malloc0(sizeof(zathura_database_t));
/* create bookmarks database */
static const char SQL_BOOKMARK_INIT[] =
"CREATE TABLE IF NOT EXISTS bookmarks ("
"file TEXT PRIMARY KEY,"
"id TEXT,"
"page INTEGER,"
"UNIQUE(file, id));";
static const char SQL_FILEINFO_INIT[] =
"CREATE TABLE IF NOT EXISTS fileinfo ("
"file TEXT PRIMARY KEY,"
"page INTEGER,"
"offset INTEGER,"
"scale INTEGER);";
if (sqlite3_open(path, &(db->session)) != SQLITE_OK) {
girara_error("Could not open database: %s\n", path);
zathura_db_free(db);
return NULL;
}
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;
}
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;
}
return db;
}
void
zathura_db_free(zathura_database_t* db)
{
if (db == NULL) {
return;
}
sqlite3_close(db->session);
g_free(db);
}
static sqlite3_stmt*
prepare_statement(sqlite3* session, const char* statement)
{
if (session == NULL || statement == NULL) {
return NULL;
}
const char* pz_tail = NULL;
sqlite3_stmt* pp_stmt = NULL;
if (sqlite3_prepare(session, statement, -1, &pp_stmt, &pz_tail) != SQLITE_OK) {
girara_error("Failed to prepare query: %s", statement);
sqlite3_finalize(pp_stmt);
return NULL;
} else if (pz_tail && *pz_tail != '\0') {
girara_error("Unused portion of statement: %s", pz_tail);
sqlite3_finalize(pp_stmt);
return NULL;
}
return pp_stmt;
}
bool
zathura_db_add_bookmark(zathura_database_t* db, const char* file, zathura_bookmark_t* bookmark)
{
g_return_val_if_fail(db && file && bookmark, false);
static const char SQL_BOOKMARK_ADD[] =
"REPLACE INTO bookmarks (file, id, page) VALUES (?, ?, ?);";
sqlite3_stmt* stmt = prepare_statement(db->session, SQL_BOOKMARK_ADD);
if (stmt == NULL) {
return false;
}
if (sqlite3_bind_text(stmt, 1, file, -1, NULL) != SQLITE_OK ||
sqlite3_bind_text(stmt, 2, bookmark->id, -1, NULL) != SQLITE_OK ||
sqlite3_bind_int(stmt, 3, bookmark->page) != SQLITE_OK) {
sqlite3_finalize(stmt);
girara_error("Failed to bind arguments.");
return false;
}
int res = sqlite3_step(stmt);
sqlite3_finalize(stmt);
return res == SQLITE_OK;
}
bool
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 = ?;";
sqlite3_stmt* stmt = prepare_statement(db->session, SQL_BOOKMARK_ADD);
if (stmt == NULL) {
return false;
}
if (sqlite3_bind_text(stmt, 1, file, -1, NULL) != SQLITE_OK ||
sqlite3_bind_text(stmt, 2, id, -1, NULL) != SQLITE_OK) {
sqlite3_finalize(stmt);
girara_error("Failed to bind arguments.");
return false;
}
int res = sqlite3_step(stmt);
sqlite3_finalize(stmt);
return res == SQLITE_OK;
}
girara_list_t*
zathura_db_load_bookmarks(zathura_database_t* db, const char* file)
{
g_return_val_if_fail(db && file, NULL);
static const char SQL_BOOKMARK_SELECT[] =
"SELECT id, page FROM bookmarks WHERE file = ?;";
sqlite3_stmt* stmt = prepare_statement(db->session, SQL_BOOKMARK_SELECT);
if (stmt == NULL) {
return NULL;
}
if (sqlite3_bind_text(stmt, 1, file, -1, NULL) != SQLITE_OK) {
sqlite3_finalize(stmt);
girara_error("Failed to bind arguments.");
return NULL;
}
girara_list_t* result = girara_list_new();
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->page = sqlite3_column_int(stmt, 1);
girara_list_append(result, bookmark);
}
sqlite3_finalize(stmt);
return result;
}

51
database.h Normal file
View file

@ -0,0 +1,51 @@
/* See LICENSE file for license and copyright information */
#ifndef DATABASE_H
#define DATABASE_H
#include <stdbool.h>
#include <girara.h>
#include "zathura.h"
#include "bookmarks.h"
/**
* Initialize database system.
* @param path Path to the database file.
* @return A valid zathura_database_t instance or NULL on failure
*/
zathura_database_t* zathura_db_init(const char* path);
/**
* Free database instance.
* @param 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);
/**
* 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_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);
#endif // DATABASE_H

571
document.c Normal file
View file

@ -0,0 +1,571 @@
/* See LICENSE file for license and copyright information */
#define _BSD_SOURCE
#define _XOPEN_SOURCE 700
// TODO: Implement realpath
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <limits.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <dirent.h>
#include <dlfcn.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <errno.h>
#include "document.h"
#include "utils.h"
#include "zathura.h"
#include "render.h"
#define LENGTH(x) (sizeof(x)/sizeof((x)[0]))
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);
/* read all files in the plugin directory */
DIR* dir = opendir(plugindir);
if (dir == NULL) {
girara_error("could not open plugin directory: %s", plugindir);
continue;
}
int fddir = dirfd(dir);
struct dirent* entry;
while ((entry = readdir(dir)) != NULL) {
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);
continue;
}
/* check if entry is a file */
if (S_ISREG(statbuf.st_mode) == 0) {
girara_info("%s/%s is not a regular file. Skipping.", plugindir, entry->d_name);
continue;
}
void* handle = NULL;
zathura_document_plugin_t* plugin = NULL;
char* path = NULL;
/* get full path */
path = g_build_filename(plugindir, entry->d_name, NULL);
if (path == NULL) {
g_error("failed to allocate memory!");
break;
}
/* load plugin */
handle = dlopen(path, RTLD_NOW);
if (handle == NULL) {
girara_error("could not load plugin %s (%s)", path, dlerror());
g_free(path);
continue;
}
/* resolve symbol */
zathura_plugin_register_service_t register_plugin;
*(void**)(&register_plugin) = dlsym(handle, PLUGIN_REGISTER_FUNCTION);
if (register_plugin == NULL) {
girara_error("could not find '%s' function in plugin %s", PLUGIN_REGISTER_FUNCTION, path);
g_free(path);
dlclose(handle);
continue;
}
plugin = malloc(sizeof(zathura_document_plugin_t));
if (plugin == NULL) {
g_error("failed to allocate memory!");
break;
}
plugin->file_extension = NULL;
plugin->open_function = NULL;
register_plugin(plugin);
bool r = zathura_document_plugin_register(zathura, plugin, handle);
if (r == false) {
girara_error("could not register plugin %s", path);
free(plugin);
dlclose(handle);
}
else {
girara_info("successfully loaded plugin %s", path);
}
g_free(path);
}
if (closedir(dir) == -1) {
girara_error("could not close plugin directory %s", plugindir);
}
} while (girara_list_iterator_next(iter));
girara_list_iterator_free(iter);
}
void
zathura_document_plugins_free(zathura_t* zathura)
{
if (zathura == NULL) {
return;
}
girara_list_iterator_t* iter = girara_list_iterator(zathura->plugins.plugins);
if (iter == NULL) {
return;
}
do {
zathura_document_plugin_t* plugin = (zathura_document_plugin_t*) girara_list_iterator_data(iter);
free(plugin);
} while (girara_list_iterator_next(iter));
girara_list_iterator_free(iter);
}
bool
zathura_document_plugin_register(zathura_t* zathura, zathura_document_plugin_t* new_plugin, void* handle)
{
if( (new_plugin == NULL) || (new_plugin->file_extension == NULL) || (new_plugin->open_function == NULL)
|| (handle == NULL) ) {
girara_error("plugin: could not register\n");
return false;
}
/* search existing plugins */
girara_list_iterator_t* iter = girara_list_iterator(zathura->plugins.plugins);
if (iter) {
do {
zathura_document_plugin_t* plugin = (zathura_document_plugin_t*) girara_list_iterator_data(iter);
if (strcmp(plugin->file_extension, new_plugin->file_extension) == 0) {
girara_error("plugin: already registered for filetype %s\n", plugin->file_extension);
girara_list_iterator_free(iter);
return false;
}
} while (girara_list_iterator_next(iter));
girara_list_iterator_free(iter);
}
girara_list_append(zathura->plugins.plugins, new_plugin);
return true;
}
zathura_document_t*
zathura_document_open(zathura_t* zathura, const char* path, const char* password)
{
if (path == NULL) {
goto error_out;
}
if (file_exists(path) == false) {
girara_error("File does not exist");
goto error_out;
}
const char* file_extension = file_get_extension(path);
if (file_extension == NULL) {
girara_error("Could not determine file type");
goto error_out;
}
/* determine real path */
size_t path_max;
#ifdef PATH_MAX
path_max = PATH_MAX;
#else
path_max = pathconf(path,_PC_PATH_MAX);
if (path_max <= 0)
path_max = 4096;
#endif
char* real_path = NULL;
zathura_document_t* document = NULL;
real_path = malloc(sizeof(char) * path_max);
if (real_path == NULL) {
goto error_out;
}
if (realpath(path, real_path) == NULL) {
goto error_free;
}
document = malloc(sizeof(zathura_document_t));
if (document == NULL) {
goto error_free;
}
document->file_path = real_path;
document->password = password;
document->current_page_number = 0;
document->number_of_pages = 0;
document->scale = 1.0;
document->rotate = 0;
document->data = NULL;
document->pages = NULL;
document->zathura = zathura;
document->functions.document_free = NULL;
document->functions.document_index_generate = NULL;
document->functions.document_save_as = NULL;
document->functions.document_attachments_get = NULL;
document->functions.page_get = NULL;
document->functions.page_free = NULL;
document->functions.page_search_text = NULL;
document->functions.page_links_get = NULL;
document->functions.page_form_fields_get = NULL;
document->functions.page_render = NULL;
girara_list_iterator_t* iter = girara_list_iterator(zathura->plugins.plugins);
if (iter == NULL) {
goto error_free;
}
do {
zathura_document_plugin_t* plugin = (zathura_document_plugin_t*) girara_list_iterator_data(iter);
if (strcmp(file_extension, plugin->file_extension) == 0) {
girara_list_iterator_free(iter);
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;
} else {
girara_error("could not open file\n");
goto error_free;
}
}
}
} while (girara_list_iterator_next(iter));
girara_list_iterator_free(iter);
girara_error("unknown file type\n");
error_free:
free(real_path);
if (document != NULL && document->pages != NULL) {
for (unsigned int page_id = 0; page_id < document->number_of_pages; page_id++) {
zathura_page_free(document->pages[page_id]);
}
free(document->pages);
}
free(document);
error_out:
return NULL;
}
bool
zathura_document_free(zathura_document_t* document)
{
if (document == NULL) {
return false;
}
/* free pages */
for (unsigned int page_id = 0; page_id < document->number_of_pages; page_id++) {
zathura_page_free(document->pages[page_id]);
document->pages[page_id] = NULL;
}
free(document->pages);
/* free document */
if (document->functions.document_free == NULL) {
girara_error("%s not implemented", __FUNCTION__);
if (document->file_path != NULL) {
free(document->file_path);
}
free(document);
return true;
}
bool r = document->functions.document_free(document);
if (document->file_path != NULL) {
free(document->file_path);
}
free(document);
return r;
}
bool
zathura_document_save_as(zathura_document_t* document, const char* path)
{
if (document == NULL || path == NULL) {
return false;
}
if (document->functions.document_save_as == NULL) {
girara_error("%s not implemented", __FUNCTION__);
return false;
}
return document->functions.document_save_as(document, path);
}
girara_tree_node_t*
zathura_document_index_generate(zathura_document_t* document)
{
if (document == NULL) {
return NULL;
}
if (document->functions.document_index_generate == NULL) {
girara_error("%s not implemented", __FUNCTION__);
return NULL;
}
return document->functions.document_index_generate(document);
}
zathura_list_t*
zathura_document_attachments_get(zathura_document_t* document)
{
if (document == NULL) {
return NULL;
}
if (document->functions.document_attachments_get == NULL) {
girara_error("%s not implemented", __FUNCTION__);
return NULL;
}
return document->functions.document_attachments_get(document);
}
bool
zathura_document_attachments_free(zathura_list_t* UNUSED(list))
{
return false;
}
zathura_page_t*
zathura_page_get(zathura_document_t* document, unsigned int page_id)
{
if (document == NULL) {
return NULL;
}
if (document->functions.page_get == NULL) {
girara_error("%s not implemented", __FUNCTION__);
return NULL;
}
zathura_page_t* page = document->functions.page_get(document, page_id);
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->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);
g_static_mutex_init(&(page->lock));
}
return page;
}
bool
zathura_page_free(zathura_page_t* page)
{
if (page == NULL || page->document == NULL) {
return false;
}
if (page->document->functions.page_free == NULL) {
girara_error("%s not implemented", __FUNCTION__);
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)
{
if (page == NULL || page->document == NULL || text == NULL) {
return NULL;
}
if (page->document->functions.page_search_text == NULL) {
girara_error("%s not implemented", __FUNCTION__);
return NULL;
}
return page->document->functions.page_search_text(page, text);
}
zathura_list_t*
zathura_page_links_get(zathura_page_t* page)
{
if (page == NULL || page->document == NULL) {
return NULL;
}
if (page->document->functions.page_links_get == NULL) {
girara_error("%s not implemented", __FUNCTION__);
return NULL;
}
return page->document->functions.page_links_get(page);
}
bool
zathura_page_links_free(zathura_list_t* UNUSED(list))
{
return false;
}
zathura_list_t*
zathura_page_form_fields_get(zathura_page_t* page)
{
if (page == NULL || page->document == NULL) {
return NULL;
}
if (page->document->functions.page_form_fields_get == NULL) {
girara_error("%s not implemented", __FUNCTION__);
return NULL;
}
return page->document->functions.page_form_fields_get(page);
}
bool
zathura_page_form_fields_free(zathura_list_t* UNUSED(list))
{
return false;
}
zathura_image_buffer_t*
zathura_page_render(zathura_page_t* page)
{
if (page == NULL || page->document == NULL) {
return NULL;
}
if (page->document->functions.page_render == NULL) {
girara_error("%s not implemented", __FUNCTION__);
return NULL;
}
return page->document->functions.page_render(page);
}
zathura_index_element_t*
zathura_index_element_new(const char* title)
{
if (title == NULL) {
return NULL;
}
zathura_index_element_t* res = g_malloc0(sizeof(zathura_index_element_t));
if (res == NULL) {
return NULL;
}
res->title = g_strdup(title);
return res;
}
void
zathura_index_element_free(zathura_index_element_t* index)
{
if (index == NULL) {
return;
}
g_free(index->title);
if (index->type == ZATHURA_LINK_EXTERNAL) {
g_free(index->target.uri);
}
g_free(index);
}
zathura_image_buffer_t*
zathura_image_buffer_create(unsigned int width, unsigned int height)
{
zathura_image_buffer_t* image_buffer = malloc(sizeof(zathura_image_buffer_t));
if (image_buffer == NULL) {
return NULL;
}
image_buffer->data = calloc(width * height * 3, sizeof(unsigned char));
if (image_buffer->data == NULL) {
free(image_buffer);
return NULL;
}
image_buffer->width = width;
image_buffer->height = height;
image_buffer->rowstride = width * 3;
return image_buffer;
}
void
zathura_image_buffer_free(zathura_image_buffer_t* image_buffer)
{
if (image_buffer == NULL) {
return;
}
free(image_buffer->data);
free(image_buffer);
}

379
document.h Normal file
View file

@ -0,0 +1,379 @@
/* See LICENSE file for license and copyright information */
#ifndef DOCUMENT_H
#define DOCUMENT_H
#include <gtk/gtk.h>
#include <stdbool.h>
#include <girara-datastructures.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;
typedef bool (*zathura_document_open_t)(zathura_document_t* document);
/**
* Document plugin structure
*/
typedef struct zathura_document_plugin_s
{
char* file_extension; /**> File extension */
zathura_document_open_t open_function; /**> Document open function */
void* handle; /**> DLL handle */
} zathura_document_plugin_t;
/**
* Function prototype that is called to register a document plugin
*
* @param The document plugin
*/
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 */
} zathura_image_buffer_t;
/**
* Creates an image buffer
*
* @param width Width of the image stored in the buffer
* @param height Height of the image stored in the buffer
* @return Image buffer or NULL if an error occured
*/
zathura_image_buffer_t* zathura_image_buffer_create(unsigned int width, unsigned int height);
/**
* Frees the image buffer
*
* @param zathura_image_buffer_t
*/
void zathura_image_buffer_free(zathura_image_buffer_t*);
/**
* Rectangle structure
*/
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 */
} zathura_rectangle_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_type_t;
/**
* Link
*/
typedef struct zathura_link_s
{
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 */
} target;
} zathura_link_t;
/**
* Index element
*/
typedef struct zathura_index_element_s
{
char* title; /**> Title of the element */
zathura_link_type_t type; /**> Type */
union
{
unsigned int page_number; /**> Page number */
char* uri; /**> Uri */
} target;
} zathura_index_element_t;
/**
* Form type
*/
typedef enum zathura_form_type_e
{
ZATHURA_FORM_CHECKBOX, /**> Checkbox */
ZATHURA_FORM_TEXTFIELD /**> Textfield */
} zathura_form_type_t;
/**
* Form element
*/
typedef struct zathura_form_s
{
zathura_rectangle_t position; /**> Position */
zathura_form_type_t type; /**> Type */
} zathura_form_t;
/**
* Page
*/
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 */
};
/**
* Document
*/
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 */
zathura_t* zathura; /** Zathura object */
struct
{
/**
* Frees the document
*/
bool (*document_free)(zathura_document_t* document);
/**
* Generates the document index
*/
girara_tree_node_t* (*document_index_generate)(zathura_document_t* document);
/**
* Save the document
*/
bool (*document_save_as)(zathura_document_t* document, const char* path);
/**
* Get list of attachments
*/
zathura_list_t* (*document_attachments_get)(zathura_document_t* document);
/**
* Gets the page object
*/
zathura_page_t* (*page_get)(zathura_document_t* document, unsigned int page_id);
/**
* Search text
*/
zathura_list_t* (*page_search_text)(zathura_page_t* page, const char* text);
/**
* Get links on a page
*/
zathura_list_t* (*page_links_get)(zathura_page_t* page);
/**
* Get form fields
*/
zathura_list_t* (*page_form_fields_get)(zathura_page_t* page);
/**
* Renders the page
*/
zathura_image_buffer_t* (*page_render)(zathura_page_t* page);
/**
* Free page
*/
bool (*page_free)(zathura_page_t* page);
} functions;
/**
* Document pages
*/
zathura_page_t** pages;
};
/**
* Load all document plugins
*
* @param zathura the zathura session
*/
void zathura_document_plugins_load(zathura_t* zathura);
/**
* Free all document plugins
*
* @param zathura the zathura session
*/
void zathura_document_plugins_free(zathura_t* zathura);
/**
* Register document plugin
*/
bool zathura_document_plugin_register(zathura_t* zathura, zathura_document_plugin_t* new_plugin, void* handle);
/**
* Open the document
*
* @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);
/**
* Free the document
*
* @param document
* @return true if no error occured, otherwise false
*/
bool 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
*/
bool zathura_document_save_as(zathura_document_t* document, const char* path);
/**
* Generate the document index
*
* @param document The document object
* @return Generated index
*/
girara_tree_node_t* zathura_document_index_generate(zathura_document_t* document);
/**
* Get list of attachments
*
* @param document The document object
* @return List of attachments
*/
zathura_list_t* zathura_document_attachments_get(zathura_document_t* document);
/**
* Free document attachments
*
* @param list list of document attachments
* @return
*/
bool zathura_document_attachments_free(zathura_list_t* list);
/**
* Get the page object
*
* @param document The document
* @param page_id Page number
* @return Page object or NULL if an error occured
*/
zathura_page_t* zathura_page_get(zathura_document_t* document, unsigned int page_id);
/**
* Frees the page object
*
* @param page The page object
* @return true if no error occured, otherwise false
*/
bool zathura_page_free(zathura_page_t* page);
/**
* Search page
*
* @param page The page object
* @param text Search item
* @return List of results
*/
zathura_list_t* zathura_page_search_text(zathura_page_t* page, const char* text);
/**
* Get page links
*
* @param page The page object
* @return List of links
*/
zathura_list_t* zathura_page_links_get(zathura_page_t* page);
/**
* Free page links
*
* @param list List of links
* @return true if no error occured, otherwise false
*/
bool zathura_page_links_free(zathura_list_t* list);
/**
* Get list of form fields
*
* @param page The page object
* @return List of form fields
*/
zathura_list_t* zathura_page_form_fields_get(zathura_page_t* page);
/**
* Free list of form fields
*
* @param list List of form fields
* @return true if no error occured, otherwise false
*/
bool zathura_page_form_fields_free(zathura_list_t* list);
/**
* Render page
*
* @param page The page object
* @return Image buffer or NULL if an error occured
*/
zathura_image_buffer_t* zathura_page_render(zathura_page_t* page);
/**
* Create new index element
*
* @param title Title of the index element
* @return Index element
*/
zathura_index_element_t* zathura_index_element_new(const char* title);
/**
* Free index element
*
* @param index The index element
*/
void zathura_index_element_free(zathura_index_element_t* index);
#endif // DOCUMENT_H

82
print.c Normal file
View file

@ -0,0 +1,82 @@
#include "print.h"
#include "document.h"
void
print(zathura_t* zathura)
{
g_return_if_fail(zathura != NULL);
g_return_if_fail(zathura->document != NULL);
GtkPrintOperation* print_operation = gtk_print_operation_new();
/* print operation settings */
if (zathura->print.settings != NULL) {
gtk_print_operation_set_print_settings(print_operation, zathura->print.settings);
}
if (zathura->print.page_setup != NULL) {
gtk_print_operation_set_default_page_setup(print_operation, zathura->print.page_setup);
}
gtk_print_operation_set_allow_async(print_operation, TRUE);
gtk_print_operation_set_n_pages(print_operation, zathura->document->number_of_pages);
gtk_print_operation_set_current_page(print_operation, zathura->document->current_page_number);
/* print operation signals */
g_signal_connect(print_operation, "draw-page", G_CALLBACK(cb_print_draw_page), 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) {
/* 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);
} else if (result == GTK_PRINT_OPERATION_RESULT_ERROR) {
girara_error("Error occured while printing progress");
}
g_object_unref(print_operation);
}
void
cb_print_begin(GtkPrintOperation* UNUSED(print_operation), GtkPrintContext*
UNUSED(context), zathura_t* UNUSED(zathura))
{
}
void
cb_print_draw_page(GtkPrintOperation* UNUSED(print_operation), GtkPrintContext*
context, gint page_number, zathura_t* zathura)
{
cairo_t* cairo = gtk_print_context_get_cairo_context(context);
girara_info("Printing page %d", page_number);
zathura_page_t* page = zathura->document->pages[page_number];
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;
}

26
print.h Normal file
View file

@ -0,0 +1,26 @@
/* See LICENSE file for license and copyright information */
#ifndef PRINT_H
#define PRINT_H
#include "zathura.h"
/**
* Opens a print dialog to print the current file
*
* @param zathura
*/
void print(zathura_t* zathura);
/**
* Callback that is executed for every page that should be printed
*
* @param print_operation Print operation object
* @param context Print context
* @param page_number Current page number
* @param zathura Zathura object
*/
void cb_print_draw_page(GtkPrintOperation* print_operation, GtkPrintContext*
context, gint page_number, zathura_t* zathura);
#endif // PRINT_H

334
render.c Normal file
View file

@ -0,0 +1,334 @@
#include "render.h"
#include "zathura.h"
#include "document.h"
void* render_job(void* data);
bool render(zathura_t* zathura, zathura_page_t* page);
void*
render_job(void* data)
{
render_thread_t* render_thread = (render_thread_t*) data;
while (true) {
g_mutex_lock(render_thread->lock);
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) {
/*
* We've been signaled with g_cond_signal(), but the list
* is still empty. This means that the signal came from
* render_free() and current document is being closed.
* We should unlock the mutex and kill the thread.
*/
g_mutex_unlock(render_thread->lock);
g_thread_exit(0);
}
zathura_page_t* page = (zathura_page_t*) girara_list_nth(render_thread->list, 0);
girara_list_remove(render_thread->list, page);
g_mutex_unlock(render_thread->lock);
if (render(render_thread->zathura, page) != true) {
girara_error("Rendering failed\n");
}
}
return NULL;
}
render_thread_t*
render_init(zathura_t* zathura)
{
render_thread_t* render_thread = malloc(sizeof(render_thread_t));
if (!render_thread) {
goto error_ret;
}
/* init */
render_thread->list = NULL;
render_thread->thread = NULL;
render_thread->cond = NULL;
render_thread->zathura = zathura;
/* setup */
render_thread->list = girara_list_new();
if (!render_thread->list) {
goto error_free;
}
render_thread->cond = g_cond_new();
if (!render_thread->cond) {
goto error_free;
}
render_thread->lock = g_mutex_new();
if (!render_thread->lock) {
goto error_free;
}
render_thread->thread = g_thread_create(render_job, render_thread, TRUE, NULL);
if (!render_thread->thread) {
goto error_free;
}
return render_thread;
error_free:
if (render_thread->list) {
girara_list_free(render_thread->list);
}
if (render_thread->cond) {
g_cond_free(render_thread->cond);
}
if (render_thread->lock) {
g_mutex_free(render_thread->lock);
}
free(render_thread);
error_ret:
return NULL;
}
void
render_free(render_thread_t* render_thread)
{
if (!render_thread) {
return;
}
if (render_thread->list) {
girara_list_free(render_thread->list);
}
if (render_thread->cond) {
g_cond_signal(render_thread->cond);
g_thread_join(render_thread->thread);
g_cond_free(render_thread->cond);
}
if (render_thread->lock) {
g_mutex_free(render_thread->lock);
}
}
bool
render_page(render_thread_t* render_thread, zathura_page_t* page)
{
if (!render_thread || !page || !render_thread->list || page->surface) {
return false;
}
g_mutex_lock(render_thread->lock);
if (!girara_list_contains(render_thread->list, page)) {
girara_list_append(render_thread->list, page);
}
g_cond_signal(render_thread->cond);
g_mutex_unlock(render_thread->lock);
return true;
}
bool
render(zathura_t* zathura, zathura_page_t* page)
{
if (zathura == NULL || page == NULL) {
return false;
}
gdk_threads_enter();
g_static_mutex_lock(&(page->lock));
zathura_image_buffer_t* image_buffer = zathura_page_render(page);
if (image_buffer == NULL) {
g_static_mutex_unlock(&(page->lock));
gdk_threads_leave();
return false;
}
/* create cairo surface */
unsigned int page_width = page->width * zathura->document->scale;
unsigned int page_height = page->height * zathura->document->scale;
cairo_surface_t* surface = cairo_image_surface_create(CAIRO_FORMAT_RGB24, page_width, page_height);
int rowstride = cairo_image_surface_get_stride(surface);
unsigned char* image = cairo_image_surface_get_data(surface);
for (unsigned int y = 0; y < page_height; y++) {
unsigned char* dst = image + y * rowstride;
unsigned char* src = image_buffer->data + y * image_buffer->rowstride;
for (unsigned int x = 0; x < page_width; x++) {
dst[0] = src[2];
dst[1] = src[1];
dst[2] = src[0];
src += 3;
dst += 4;
}
}
/* recolor */
if (zathura->global.recolor) {
/* recolor code based on qimageblitz library flatten() function
(http://sourceforge.net/projects/qimageblitz/) */
int r1 = zathura->ui.colors.recolor_dark_color.red / 257;
int g1 = zathura->ui.colors.recolor_dark_color.green / 257;
int b1 = zathura->ui.colors.recolor_dark_color.blue / 257;
int r2 = zathura->ui.colors.recolor_light_color.red / 257;
int g2 = zathura->ui.colors.recolor_light_color.green / 257;
int b2 = zathura->ui.colors.recolor_light_color.blue / 257;
int min = 0x00;
int max = 0xFF;
int mean = 0x00;
float sr = ((float) r2 - r1) / (max - min);
float sg = ((float) g2 - g1) / (max - min);
float sb = ((float) b2 - b1) / (max - min);
for (unsigned int y = 0; y < page_height; y++) {
unsigned char* data = image + y * rowstride;
for (unsigned int x = 0; x < page_width; x++) {
mean = (data[0] + data[1] + data[2]) / 3;
data[2] = sr * (mean - min) + r1 + 0.5;
data[1] = sg * (mean - min) + g1 + 0.5;
data[0] = sb * (mean - min) + b1 + 0.5;
data += 4;
}
}
}
/* rotate */
unsigned int width = page_width;
unsigned int height = page_height;
if (page->document->rotate == 90 || page->document->rotate == 270) {
width = page_height;
height = page_width;
}
cairo_surface_t* final_surface = cairo_image_surface_create(CAIRO_FORMAT_RGB24, width, height);
cairo_t* cairo = cairo_create(final_surface);
switch(page->document->rotate)
{
case 90:
cairo_translate(cairo, width, 0);
break;
case 180:
cairo_translate(cairo, width, height);
break;
case 270:
cairo_translate(cairo, 0, height);
break;
}
if (page->document->rotate != 0) {
cairo_rotate(cairo, page->document->rotate * G_PI / 180.0);
}
cairo_set_source_surface(cairo, surface, 0, 0);
cairo_set_operator(cairo, CAIRO_OPERATOR_SOURCE);
cairo_paint(cairo);
cairo_destroy(cairo);
cairo_surface_destroy(surface);
/* draw to gtk widget */
page->surface = final_surface;
gtk_widget_set_size_request(page->drawing_area, width, height);
gtk_widget_queue_draw(page->drawing_area);
zathura_image_buffer_free(image_buffer);
g_static_mutex_unlock(&(page->lock));
gdk_threads_leave();
return true;
}
void
render_all(zathura_t* zathura)
{
if (zathura->document == NULL) {
return;
}
/* 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;
}
/* 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;
}

66
render.h Normal file
View file

@ -0,0 +1,66 @@
/* See LICENSE file for license and copyright information */
#ifndef RENDER_H
#define RENDER_H
#include <stdbool.h>
#include <stdlib.h>
#include <girara-datastructures.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 */
};
/**
* This function initializes a render thread
*
* @param Zathura object
* @return The render thread object or NULL if an error occured
*/
render_thread_t* render_init(zathura_t* zathura);
/**
* This function destroys the render thread object
*
* @param render_thread The render thread object
*/
void render_free(render_thread_t* render_thread);
/**
* This function is used to add a page to the render thread list
* that should be rendered.
*
* @param render_thread The render thread object
* @param page The page that should be rendered
* @return true if no error occured
*/
bool render_page(render_thread_t* render_thread, zathura_page_t* page);
/**
* This function is used to unmark all pages as not rendered. This should
* be used if all pages should be rendered again (e.g.: the zoom level or the
* colors have changed)
*
* @param zathura Zathura object
*/
void render_all(zathura_t* zathura);
/**
* Renders page
*
* @param widget Drawing area
* @param event Event
* @param data Optional data
* @return true if no error occured
*/
gboolean page_expose_event(GtkWidget* widget, GdkEventExpose* event, gpointer data);
#endif // RENDER_H

388
shortcuts.c Normal file
View file

@ -0,0 +1,388 @@
/* See LICENSE file for license and copyright information */
#include <girara.h>
#include <gtk/gtk.h>
#include "callbacks.h"
#include "shortcuts.h"
#include "document.h"
#include "zathura.h"
#include "render.h"
#include "utils.h"
bool
sc_abort(girara_session_t* session, girara_argument_t* UNUSED(argument),
unsigned int UNUSED(t))
{
g_return_val_if_fail(session != NULL, false);
girara_mode_set(session, session->modes.normal);
return false;
}
bool
sc_adjust_window(girara_session_t* session, girara_argument_t* UNUSED(argument),
unsigned int UNUSED(t))
{
g_return_val_if_fail(session != NULL, false);
return false;
}
bool
sc_change_mode(girara_session_t* session, girara_argument_t* argument, unsigned
int UNUSED(t))
{
g_return_val_if_fail(session != NULL, false);
girara_mode_set(session, argument->n);
return false;
}
bool
sc_follow(girara_session_t* session, girara_argument_t* UNUSED(argument),
unsigned int UNUSED(t))
{
g_return_val_if_fail(session != NULL, false);
return false;
}
bool
sc_goto(girara_session_t* session, girara_argument_t* argument, 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(zathura->document != NULL, false);
if (argument->n == TOP) {
girara_argument_t arg = { TOP, NULL };
sc_scroll(session, &arg, 0);
return false;
} else {
if (t == 0) {
girara_argument_t arg = { BOTTOM, NULL };
sc_scroll(session, &arg, 0);
return true;
}
page_set(zathura, t - 1);
}
return false;
}
bool
sc_navigate(girara_session_t* session, girara_argument_t* argument, 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);
unsigned int number_of_pages = zathura->document->number_of_pages;
unsigned int new_page = zathura->document->current_page_number;
if (argument->n == NEXT) {
new_page = (new_page + 1) % number_of_pages;
} else if (argument->n == PREVIOUS) {
new_page = (new_page + number_of_pages - 1) % number_of_pages;
}
page_set(zathura, new_page);
return false;
}
bool
sc_recolor(girara_session_t* session, girara_argument_t* UNUSED(argument),
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;
zathura->global.recolor = !zathura->global.recolor;
render_all(zathura);
return false;
}
bool
sc_reload(girara_session_t* session, girara_argument_t* UNUSED(argument),
unsigned int UNUSED(t))
{
g_return_val_if_fail(session != NULL, false);
return false;
}
bool
sc_rotate(girara_session_t* session, girara_argument_t* UNUSED(argument),
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);
/* update rotate value */
zathura->document->rotate = (zathura->document->rotate + 90) % 360;
/* render all pages again */
render_all(zathura);
return false;
}
bool
sc_scroll(girara_session_t* session, girara_argument_t* argument, 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);
if (zathura->document == NULL) {
return false;
}
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;
gdouble new_value;
switch(argument->n)
{
case FULL_UP:
new_value = (value - view_size) < 0 ? 0 : (value - view_size);
break;
case FULL_DOWN:
new_value = (value + view_size) > max ? max : (value + view_size);
break;
case HALF_UP:
new_value = (value - (view_size / 2)) < 0 ? 0 : (value - (view_size / 2));
break;
case HALF_DOWN:
new_value = (value + (view_size / 2)) > max ? max : (value + (view_size / 2));
break;
case LEFT:
case UP:
new_value = (value - scroll_step) < 0 ? 0 : (value - scroll_step);
break;
case RIGHT:
case DOWN:
new_value = (value + scroll_step) > max ? max : (value + scroll_step);
break;
case TOP:
new_value = 0;
break;
case BOTTOM:
new_value = max;
break;
default:
new_value = 0;
}
gtk_adjustment_set_value(adjustment, new_value);
return false;
}
bool
sc_search(girara_session_t* session, girara_argument_t* argument, 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);
return false;
}
bool
sc_navigate_index(girara_session_t* session, girara_argument_t* argument,
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);
return false;
}
bool
sc_toggle_index(girara_session_t* session, girara_argument_t* argument, 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);
girara_tree_node_t* document_index = NULL;
GtkWidget* treeview = NULL;
GtkTreeModel* model = NULL;
GtkCellRenderer* renderer = NULL;
if (zathura->ui.index == NULL) {
/* create new index widget */
zathura->ui.index = gtk_scrolled_window_new(NULL, NULL);
if (zathura->ui.index == NULL) {
goto error_ret;
}
gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(zathura->ui.index),
GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC);
/* create index */
document_index = zathura_document_index_generate(zathura->document);
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));
if (model == NULL) {
goto error_free;
}
treeview = gtk_tree_view_new_with_model(model);
if (treeview == NULL) {
goto error_free;
}
g_object_unref(model);
renderer = gtk_cell_renderer_text_new();
if (renderer == 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_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_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*/
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);
gtk_widget_hide(GTK_WIDGET(zathura->ui.index));
} else {
girara_set_view(session, zathura->ui.index);
gtk_widget_show(GTK_WIDGET(zathura->ui.index));
}
return false;
error_free:
if (zathura->ui.index != NULL) {
g_object_ref_sink(zathura->ui.index);
zathura->ui.index = NULL;
}
if (document_index != NULL) {
girara_node_free(document_index);
}
error_ret:
return false;
}
bool
sc_toggle_fullscreen(girara_session_t* session, girara_argument_t*
UNUSED(argument), unsigned int UNUSED(t))
{
g_return_val_if_fail(session != NULL, false);
static bool fullscreen = false;
if (fullscreen) {
gtk_window_unfullscreen(GTK_WINDOW(session->gtk.window));
} else {
gtk_window_fullscreen(GTK_WINDOW(session->gtk.window));
}
fullscreen = fullscreen ? false : true;
return false;
}
bool
sc_quit(girara_session_t* session, girara_argument_t* UNUSED(argument), 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);
cb_destroy(NULL, NULL);
gtk_main_quit();
return false;
}
bool
sc_zoom(girara_session_t* session, girara_argument_t* argument, 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);
/* retreive zoom step value */
int* value = girara_setting_get(zathura->ui.session, "zoom-step");
if (value == NULL) {
return false;
}
float zoom_step = *value / 100.0f;
if (argument->n == ZOOM_IN) {
zathura->document->scale += zoom_step;
} else if (argument->n == ZOOM_OUT) {
zathura->document->scale -= zoom_step;
} else {
zathura->document->scale = 1.0;
}
render_all(zathura);
return false;
}

168
shortcuts.h Normal file
View file

@ -0,0 +1,168 @@
/* See LICENSE file for license and copyright information */
#ifndef SHORTCUTS_H
#define SHORTCUTS_H
#include <girara.h>
/**
* Abort the current action and return to normal mode
*
* @param session The used girara session
* @param argument The used argument
* @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);
/**
* Adjust the rendered pages to the window
*
* @param session The used girara session
* @param argument The used argument
* @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);
/**
* Change the current mode
*
* @param session The used girara session
* @param argument The used argument
* @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);
/**
* Follow a link
*
* @param session The used girara session
* @param argument The used argument
* @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);
/**
* Go to a specific page or position
*
* @param session The used girara session
* @param argument The used argument
* @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);
/**
* Navigate through the document
*
* @param session The used girara session
* @param argument The used argument
* @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);
/**
* Recolor the pages
*
* @param session The used girara session
* @param argument The used argument
* @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);
/**
* Reload the current document
*
* @param session The used girara session
* @param argument The used argument
* @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);
/**
* Rotate the pages
*
* @param session The used girara session
* @param argument The used argument
* @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);
/**
* Scroll through the pages
*
* @param session The used girara session
* @param argument The used argument
* @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);
/**
* Search through the document for the latest search item
*
* @param session The used girara session
* @param argument The used argument
* @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);
/**
* Navigate through the index of the document
*
* @param session The used girara session
* @param argument The used argument
* @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);
/**
* Show/Hide the index of the document
*
* @param session The used girara session
* @param argument The used argument
* @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);
/**
* Toggle fullscreen mode
*
* @param session The used girara session
* @param argument The used argument
* @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);
/**
* Quit zathura
*
* @param session The used girara session
* @param argument The used argument
* @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);
/**
* Change the zoom level
*
* @param session The used girara session
* @param argument The used argument
* @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);
#endif // SHORTCUTS_H

249
utils.c Normal file
View file

@ -0,0 +1,249 @@
/* See LICENSE file for license and copyright information */
#include <stdlib.h>
#include <stdarg.h>
#include <string.h>
#include <stdio.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/wait.h>
#include "utils.h"
#include "zathura.h"
#include "document.h"
#define BLOCK_SIZE 64
bool
file_exists(const char* path)
{
if (!access(path, F_OK)) {
return true;
} else {
return false;
}
}
const char*
file_get_extension(const char* path)
{
if (!path) {
return NULL;
}
unsigned int i = strlen(path);
for (; i > 0; i--)
{
if (*(path + i) != '.') {
continue;
} else {
break;
}
}
if (!i) {
return NULL;
}
return path + i + 1;
}
bool
file_valid_extension(zathura_t* zathura, const char* path)
{
if (path == NULL) {
return false;
}
const char* file_extension = file_get_extension(path);
if (file_extension == NULL) {
return false;
}
girara_list_iterator_t* iter = girara_list_iterator(zathura->plugins.plugins);
if (iter == NULL) {
return false;
}
do {
zathura_document_plugin_t* plugin = (zathura_document_plugin_t*) girara_list_iterator_data(iter);
if (!strcmp(file_extension, plugin->file_extension)) {
return true;
}
} while (girara_list_iterator_next(iter));
girara_list_iterator_free(iter);
return false;
}
bool
execute_command(char* const argv[], char** output)
{
if (!output) {
return false;
}
int p[2];
if (pipe(p)) {
return -1;
}
pid_t pid = fork();
if (pid == -1) { // failure
return false;
} else if (pid == 0) { // child
dup2(p[1], 1);
close(p[0]);
if (execvp(argv[0], argv) == -1) {
return false;
}
} else { // parent
dup2(p[0], 0);
close(p[1]);
/* read output */
unsigned int bc = BLOCK_SIZE;
unsigned int i = 0;
char* buffer = malloc(sizeof(char) * bc);
*output = NULL;
if (!buffer) {
close(p[0]);
return false;
}
char c;
while (1 == read(p[0], &c, 1)) {
buffer[i++] = c;
if (i == bc) {
bc += BLOCK_SIZE;
char* tmp = realloc(buffer, sizeof(char) * bc);
if (!tmp) {
free(buffer);
close(p[0]);
return false;
}
buffer = tmp;
}
}
char* tmp = realloc(buffer, sizeof(char) * (bc + 1));
if (!tmp) {
free(buffer);
close(p[0]);
return false;
}
buffer = tmp;
buffer[i] = '\0';
*output = buffer;
/* wait for child to terminate */
waitpid(pid, NULL, 0);
close(p[0]);
}
return true;
}
void
document_index_build(GtkTreeModel* UNUSED(model), GtkTreeIter* UNUSED(parent),
girara_tree_node_t* UNUSED(tree))
{
/*girara_list_t* list = girara_node_get_children(tree);*/
/*girara_list_iterator_t* it = girara_list_iterator(list);*/
/*do {*/
/*zathura_index_element_t* index_element = (zathura_index_element_t*) girara_list_iterator_data(it);*/
/*} while ((it = girara_list_iterator_next(it)));*/
}
char*
string_concat(const char* string1, ...)
{
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;
}
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;
}
return offset;
}

82
utils.h Normal file
View file

@ -0,0 +1,82 @@
/* See LICENSE file for license and copyright information */
#ifndef UTILS_H
#define UTILS_H
#include <stdbool.h>
#include <gtk/gtk.h>
#include <girara.h>
#include "document.h"
typedef struct page_offset_s
{
int x;
int y;
} page_offset_t;
/**
* Checks if the given file exists
*
* @param path Path to the file
* @return true if the file exists, otherwise false
*/
bool file_exists(const char* path);
/**
* Returns the file extension of a path
*
* @param path Path to the file
* @return The file extension or NULL
*/
const char* file_get_extension(const char* path);
/**
* This function checks if the file has a valid extension. A extension is
* evaluated as valid if it matches a supported filetype.
*
* @param zathura Zathura object
* @param path The path to the file
* @return true if the extension is valid, otherwise false
*/
bool file_valid_extension(zathura_t* zathura, const char* path);
/**
* Executes a system command and saves its output into output
*
* @param argv The command
* @param output Pointer where the output will be saved
* @return true if no error occured, otherwise false
*/
bool execute_command(char* const argv[], char** output);
/**
* Generates the document index based upon the list retreived from the document
* object.
*
* @param model The tree model
* @param tree_it The Tree iterator
* @param list_it The index list 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
* @return The calculated offset or NULL if an error occured
*/
page_offset_t* page_calculate_offset(zathura_page_t* page);
#endif // UTILS_H

249
zathura.1
View file

@ -1,248 +1,27 @@
.TH ZATHURA 1 zathura\-VERSION
.SH NAME
zathura \- a PDF viewer
zathura \- a document viewer
.SH SYNOPSIS
.B zathura
.RB [-e\ xid]
.RB [-c\ path]
.RB [-d\ path]
.RB [options]
.RB [file]
.RB [password]
.SH DESCRIPTION
zathura is a highly customizable and functional PDF viewer based on the poppler
rendering library and the GTK+ toolkit. zathura provides a minimalistic and
space saving interface, with a focus on keyboard interaction.
If instead of a filename - is specified on the command line, zathura tries to
render a PDF file piped to zathura via stdin.
.SH DESCRIPTION
zathura is a highly customizable and functional document viewer.
.SH OPTIONS
.TP
.B -e xid
.B "-e xid"
Reparents to window specified by xid.
.TP
.B -c path
Path to the config directory (defaults to .config/zathura)
.B "-c path"
Path to the config directory.
.TP
.B -d path
Path to the data directory (defaults to .local/share/zathura)
.SH DEFAULT SETTINGS
.SS Shortcuts
.B "-d path"
Path to the data directory.
.TP
.B J
Go to next page
.TP
.B K
Go to previous page
.TP
.B h
Scroll to the left
.TP
.B k
Scroll upwards
.TP
.B j
Scroll downwards
.TP
.B ^f
Scroll page down
.TP
.B ^b
Scroll page up
.TP
.B ^d
Scroll half a page down
.TP
.B ^u
Scroll half a page up
.TP
.B l
Scroll to the right
.TP
.B /
Search forwards
.TP
.B ?
Search backwards
.TP
.B n
Search last keyword forwards
.TP
.B N
Search last keyword backwards
.TP
.B Tab
Toggle index
.TP
.B o
Open a file
.TP
.B a
Zoom to fit
.TP
.B s
Zoom to width
.TP
.B f
Follow a link on the page
.TP
.B m
Mark current position and save it in register specified by a character
.TP
.B '
Go to saved position specified by the ensuing character
.TP
.B r
Rotate the page
.TP
.B R
Reload the document
.TP
.B O
Change goto mode (L: search labels, D: default, O: manual offset)
.TP
.B ^i
Recolors the page
.TP
.B i
Change to insert mode
.TP
.B v
Change to visual mode
.TP
.B :
Focus inputbar
.TP
.B Backspace
Delete last character in the buffer
.TP
.B F5
Toggle fullscreen mode
.TP
.B ^n
Toggle statusbar visibility
.TP
.B ^m
Toggle inputbar visibility
.TP
.B +
Zoom in
.TP
.B -
Zoom out
.TP
.B =
Zoom to the original size
.TP
.B Esc | ^c
Abort
.TP
.B ^q
Quit the program
.SS Index commands
.TP
.B k
Navigate to one element above the current position
.TP
.B j
Navigate to one element below the current position
.TP
.B h
Collapse current element
.TP
.B l
Expand current element
.TP
.B Space | Return
Select current element
.SS Buffered commands
.TP
.B gg
Go to the first page
.TP
.B GG
Go to the last page
.TP
.B [0-9]+G
Go to the specified page
.TP
.B zI
Zoom in
.TP
.B zO
Zoom out
.TP
.B z0
Zoom to the original size
.TP
.B [0-9]+Z
Zoom to the given level
.TP
.B [0-9]+%
Move to the given position
.SS Commands
.TP
.B blist
List and open bookmark
.TP
.B bmark
Bookmark current page
.TP
.B close
Close current file
.TP
.B coffset
Set page offset
.TP
.B delbmark
Delete given bookmark
.TP
.B export
Export images or attached files
.TP
.B info
Show information about the document
.TP
.B map
Map shortcut functions (map <key> <function> <argument> <mode>)
.TP
.B open
Open a file
.TP
.B print
Print the document
.TP
.B quit
Quit the program
.TP
.B rotate
Rotate the page
.TP
.B set
Set an option (set <id> <value>)
.TP
.B write
Save the document
.SS Inputbar shortcuts
.TP
.B Up
Move up in the command history
.TP
.B Down
Move down in the command history
.TP
.B Tab | Shift + Tab
Tab completion
.TP
.B ^w
Delete last word
.SH CONFIGURATION
The complete configuration including the appearance and shortcuts of the program
are defined in a separate file named config.h. In this file you are able to
change and adjust all the settings of zathura according to your wishes.
In addition you can create a zathurarc file (default path: ~/.config/zathura/zathurarc)
to overwrite settings and keybindings by using the set and map function. For
more information please have a look at \&\fIzathurarc\fR\|(5).
.SH SEE ALSO
\&\fIzathurarc\fR\|(5)
.B "-p path"
Path to the plugin directory.

5352
zathura.c

File diff suppressed because it is too large Load diff

180
zathura.h Normal file
View file

@ -0,0 +1,180 @@
/* See LICENSE file for license and copyright information */
#ifndef ZATHURA_H
#define ZATHURA_H
#include <stdbool.h>
#include <girara.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
enum { NEXT, PREVIOUS, LEFT, RIGHT, UP, DOWN, BOTTOM, TOP, HIDE, HIGHLIGHT,
DELETE_LAST_WORD, DELETE_LAST_CHAR, DEFAULT, ERROR, WARNING, NEXT_GROUP,
PREVIOUS_GROUP, ZOOM_IN, ZOOM_OUT, ZOOM_ORIGINAL, ZOOM_SPECIFIC, FORWARD,
BACKWARD, ADJUST_BESTFIT, ADJUST_WIDTH, ADJUST_NONE, CONTINUOUS, DELETE_LAST,
ADD_MARKER, EVAL_MARKER, EXPAND, COLLAPSE, SELECT, GOTO_DEFAULT, GOTO_LABELS,
GOTO_OFFSET, HALF_UP, HALF_DOWN, FULL_UP, FULL_DOWN, NEXT_CHAR, PREVIOUS_CHAR,
DELETE_TO_LINE_START, APPEND_FILEPATH };
/* forward declaration for types from document.h */
struct zathura_document_s;
struct zathura_page_s;
typedef struct zathura_document_s zathura_document_t;
typedef struct zathura_page_s zathura_page_t;
/* forward declaration for types form database.h */
struct zathura_database_s;
typedef struct zathura_database_s zathura_database_t;
/* forward declaration for types from render.h */
struct render_thread_s;
typedef struct render_thread_s render_thread_t;
typedef struct zathura_s
{
struct
{
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 */
} statusbar;
struct
{
GdkColor recolor_dark_color; /**> Dark color for recoloring */
GdkColor recolor_light_color; /**> Light color for recoloring */
} colors;
GtkWidget *page_view; /**> 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 */
} sync;
struct
{
girara_list_t* plugins; /**> List of plugins */
girara_list_t* path; /**> List of plugin paths */
} plugins;
struct
{
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 */
} print;
struct
{
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 */
} modes;
struct
{
gchar* file; /**> bookmarks file */
girara_list_t* bookmarks; /**> bookmarks */
} bookmarks;
zathura_document_t* document; /**> The current document */
zathura_database_t* database; /**> The database */
} zathura_t;
/**
* Initializes zathura
*
* @param argc Number of arguments
* @param argv Values of arguments
* @return zathura session object or NULL if zathura could not been initialized
*/
zathura_t* zathura_init(int argc, char* argv[]);
/**
* Free zathura session
*
* @param zathura The zathura session
*/
void zathura_free(zathura_t* zathura);
/**
* Opens a file
*
* @param zathura The zathura session
* @param path The path to the file
* @param password The password of the file
*
* @return If no error occured true, otherwise false, is returned.
*/
bool document_open(zathura_t* zathura, const char* path, const char* password);
/**
* Save a open file
*
* @param zathura The zathura session
* @param path The path
* @param overwrite Overwrite existing file
*
* @return If no error occured true, otherwise false, is returned.
*/
bool document_save(zathura_t* zathura, const char* path, bool overwrite);
/**
* Closes the current opened document
*
* @param zathura The zathura session
* @return If no error occured true, otherwise false, is returned.
*/
bool document_close(zathura_t* zathura);
/**
* Opens the page with the given number
*
* @param zathura The zathura session
* @return If no error occured true, otherwise false, is returned.
*/
bool page_set(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);
/**
* Updates the page number in the statusbar. Note that 1 will be added to the
* displayed number
*
* @param zathura The zathura session
*/
void statusbar_page_number_update(zathura_t* zathura);
#endif // ZATHURA_H

9
zathura.pc.in Normal file
View file

@ -0,0 +1,9 @@
INC_PATH=-I${includedir}
Name: ${project}
Description: document viewer
Version: ${version}
URL: http://pwmt.org/projects/zathura
Cflags: ${INC_PATH}
Libs: