zathura-cb-0.1.5/0000755000175000017500000000000012636351150012223 5ustar mockmockzathura-cb-0.1.5/AUTHORS0000644000175000017500000000025612636351150013276 0ustar mockmockzathura-cb is written by: Moritz Lipp Sebastian Ramacher Other contributors are (in no particular order): Frank Smit zathura-cb-0.1.5/config.mk0000644000175000017500000000330712636351150014024 0ustar mockmock# See LICENSE file for license and copyright information VERSION_MAJOR = 0 VERSION_MINOR = 1 VERSION_REV = 5 VERSION = ${VERSION_MAJOR}.${VERSION_MINOR}.${VERSION_REV} # minimum required zathura version ZATHURA_MIN_VERSION = 0.2.0 ZATHURA_VERSION_CHECK ?= $(shell pkg-config --atleast-version=$(ZATHURA_MIN_VERSION) zathura; echo $$?) ZATHURA_GTK_VERSION ?= $(shell pkg-config --variable=GTK_VERSION zathura) # paths PREFIX ?= /usr LIBDIR ?= ${PREFIX}/lib DESKTOPPREFIX ?= ${PREFIX}/share/applications # libs CAIRO_INC ?= $(shell pkg-config --cflags cairo) CAIRO_LIB ?= $(shell pkg-config --libs cairo) LIBARCHIVE_INC ?= $(shell pkg-config --cflags libarchive) LIBARCHIVE_LIB ?= $(shell pkg-config --libs libarchive) GLIB_INC ?= $(shell pkg-config --cflags glib-2.0 gio-2.0) GLIB_LIB ?= $(shell pkg-config --libs glib-2.0 gio-2.0) GDK_INC ?= $(shell pkg-config --cflags gdk-pixbuf-2.0 gdk-${ZATHURA_GTK_VERSION}.0) GDK_LIB ?= $(shell pkg-config --libs gdk-pixbuf-2.0 gdk-${ZATHURA_GTK_VERSION}.0) GIRARA_INC ?= $(shell pkg-config --cflags girara-gtk${ZATHURA_GTK_VERSION}) GIRARA_LIB ?= $(shell pkg-config --libs girara-gtk${ZATHURA_GTK_VERSION}) ZATHURA_INC ?= $(shell pkg-config --cflags zathura) INCS = ${GIRARA_INC} ${GDK_INC} ${GLIB_INC} ${ZATHURA_INC} ${LIBARCHIVE_INC} LIBS = ${GIRARA_LIB} ${GDK_LIB} ${GLIB_LIB} ${LIBARCHIVE_LIB} # plugindir PLUGINDIR ?= $(shell pkg-config --variable=plugindir zathura) ifeq (,${PLUGINDIR}) PLUGINDIR = ${LIBDIR}/zathura endif # flags CFLAGS += -std=c11 -fPIC -pedantic -Wall -Wno-format-zero-length $(INCS) # debug DFLAGS ?= -g # build with cairo support? WITH_CAIRO ?= 1 # compiler CC ?= gcc LD ?= ld # set to something != 0 if you want verbose build output VERBOSE ?= 0 zathura-cb-0.1.5/zathura-cb.desktop0000644000175000017500000000214312636351150015656 0ustar mockmock[Desktop Entry] Version=1.0 Type=Application Name=Zathura Comment=A minimalistic document viewer Comment[ca]=Un visualitzador de documents minimalista Comment[de]=Ein minimalistischer Dokumenten-Betrachter Comment[el]=Ένας ελαφρύς προβολέας κειμένων Comment[eo]=Malpeza dokumento spektanto Comment[es_CL]=Un visor de documentos minimalista Comment[fr]=Un visionneur de document minimaliste Comment[he]=מציג מסמכים מינימליסטי Comment[id_ID]=Pembaca dokumen minimalis Comment[it]=Un visualizzatore di documenti minimalista Comment[pl]=Minimalistyczna przeglądarka dokumentów Comment[pt_BR]=Um visualizador de documentos minimalista Comment[ru]=Минималистичный просмотрщик документов Comment[tr]=Minimalist bir belge görüntüleyicisi Comment[uk_UA]=Легкий переглядач документів Exec=zathura %U Terminal=false NoDisplay=true Categories=Office;Viewer; MimeType=application/x-cbr;application/x-rar;application/x-cbz;application/zip;application/x-cb7;application/x-7z-compressed;application/x-cbt;application/x-tar; zathura-cb-0.1.5/Makefile0000644000175000017500000000521112636351150013662 0ustar mockmock# See LICENSE file for license and copyright information include config.mk include common.mk PROJECT = zathura-cb PLUGIN = cb SOURCE = $(wildcard *.c) HEADER = $(wildcard *.h) OBJECTS = ${SOURCE:.c=.o} DOBJECTS = ${SOURCE:.c=.do} ifneq "$(WITH_CAIRO)" "0" CPPFLAGS += -DHAVE_CAIRO INCS += $(CAIRO_INC) LIBS += $(CAIRO_LIB) endif CPPFLAGS += "-DVERSION_MAJOR=${VERSION_MAJOR}" CPPFLAGS += "-DVERSION_MINOR=${VERSION_MINOR}" CPPFLAGS += "-DVERSION_REV=${VERSION_REV}" all: options ${PLUGIN}.so zathura-version-check: ifneq ($(ZATHURA_VERSION_CHECK), 0) $(error "The minimum required version of zathura is ${ZATHURA_MIN_VERSION}") endif $(QUIET)touch zathura-version-check options: $(ECHO) ${PLUGIN} build options: $(ECHO) "CFLAGS = ${CFLAGS}" $(ECHO) "LDFLAGS = ${LDFLAGS}" $(ECHO) "DFLAGS = ${DFLAGS}" $(ECHO) "CC = ${CC}" %.o: %.c $(ECHO) CC $< @mkdir -p .depend $(QUIET)${CC} -c ${CPPFLAGS} ${CFLAGS} -o $@ $< -MMD -MF .depend/$@.dep %.do: %.c $(ECHO) CC $< @mkdir -p .depend $(QUIET)${CC} -c ${CPPFLAGS} ${CFLAGS} ${DFLAGS} -o $@ $< -MMD -MF .depend/$@.dep ${OBJECTS}: config.mk zathura-version-check ${DOBJECTS}: config.mk zathura-version-check ${PLUGIN}.so: ${OBJECTS} $(ECHO) LD $@ $(QUIET)${CC} -shared ${LDFLAGS} -o $@ $(OBJECTS) ${LIBS} ${PLUGIN}-debug.so: ${DOBJECTS} $(ECHO) LD $@ $(QUIET)${CC} -shared ${LDFLAGS} -o $@ $(DOBJECTS) ${LIBS} clean: $(QUIET)rm -rf ${OBJECTS} ${DOBJECTS} $(PLUGIN).so $(PLUGIN)-debug.so \ doc .depend ${PROJECT}-${VERSION}.tar.gz zathura-version-check debug: options ${PLUGIN}-debug.so dist: clean $(QUIET)mkdir -p ${PROJECT}-${VERSION} $(QUIET)cp -R LICENSE Makefile config.mk common.mk Doxyfile \ ${HEADER} ${SOURCE} AUTHORS ${PROJECT}.desktop \ ${PROJECT}-${VERSION} $(QUIET)tar -cf ${PROJECT}-${VERSION}.tar ${PROJECT}-${VERSION} $(QUIET)gzip ${PROJECT}-${VERSION}.tar $(QUIET)rm -rf ${PROJECT}-${VERSION} doc: clean $(QUIET)doxygen Doxyfile install: all $(ECHO) installing ${PLUGIN} plugin $(QUIET)mkdir -p ${DESTDIR}${PLUGINDIR} $(QUIET)cp -f ${PLUGIN}.so ${DESTDIR}${PLUGINDIR} $(QUIET)mkdir -m 755 -p ${DESTDIR}${DESKTOPPREFIX} $(ECHO) installing desktop file $(QUIET)install -m 644 ${PROJECT}.desktop ${DESTDIR}${DESKTOPPREFIX} uninstall: $(ECHO) uninstalling ${PLUGIN} plugin $(QUIET)rm -f ${DESTDIR}${PLUGINDIR}/${PLUGIN}.so $(QUIET)rmdir --ignore-fail-on-non-empty ${DESTDIR}${PLUGINDIR} 2> /dev/null $(ECHO) removing desktop file $(QUIET)rm -f ${DESTDIR}${DESKTOPPREFIX}/${PROJECT}.desktop $(QUIET)rmdir --ignore-fail-on-non-empty ${DESTDIR}${DESKTOPPREFIX} 2> /dev/null -include $(wildcard .depend/*.dep) .PHONY: all options clean debug doc dist install uninstall zathura-cb-0.1.5/render.c0000644000175000017500000000577112636351150013660 0ustar mockmock/* See LICENSE file for license and copyright information */ #include #include #include #include #include #include "plugin.h" #include "internal.h" #include "utils.h" #if !defined(HAVE_CAIRO) #error "Cannot render without cairo" #endif static GdkPixbuf* load_pixbuf_from_archive(const char* archive, const char* file); #if HAVE_CAIRO zathura_error_t cb_page_render_cairo(zathura_page_t* page, cb_page_t* cb_page, cairo_t* cairo, bool printing) { if (page == NULL || cb_page == NULL || cairo == NULL) { return ZATHURA_ERROR_INVALID_ARGUMENTS; } zathura_document_t* document = zathura_page_get_document(page); if (document == NULL) { return ZATHURA_ERROR_UNKNOWN; } GdkPixbuf* pixbuf = load_pixbuf_from_archive(zathura_document_get_path(document), cb_page->file); if (pixbuf == NULL) { return ZATHURA_ERROR_UNKNOWN; } gdk_cairo_set_source_pixbuf(cairo, pixbuf, 0, 0); cairo_paint(cairo); g_object_unref(pixbuf); return ZATHURA_ERROR_OK; } #endif static GdkPixbuf* load_pixbuf_from_archive(const char* archive, const char* file) { if (archive == NULL || file == NULL) { return NULL; } struct archive* a = archive_read_new(); if (a == NULL) { return NULL; } archive_read_support_filter_all(a); archive_read_support_format_all(a); int r = archive_read_open_filename(a, archive, LIBARCHIVE_BUFFER_SIZE); if (r != ARCHIVE_OK) { return NULL; } struct archive_entry* entry = NULL; while ((r = archive_read_next_header(a, &entry)) != ARCHIVE_EOF) { if (r < ARCHIVE_WARN) { archive_read_close(a); archive_read_free(a); return NULL; } const char* path = archive_entry_pathname(entry); if (compare_path(path, file) != 0) { continue; } GInputStream* is = g_memory_input_stream_new(); if (is == NULL) { archive_read_close(a); archive_read_free(a); return NULL; } GMemoryInputStream* mis = G_MEMORY_INPUT_STREAM(is); size_t size = 0; const void* buf = NULL; __LA_INT64_T offset = 0; while ((r = archive_read_data_block(a, &buf, &size, &offset)) != ARCHIVE_EOF) { if (r < ARCHIVE_WARN) { archive_read_close(a); archive_read_free(a); g_object_unref(mis); return NULL; } if (size == 0 || buf == NULL) { continue; } void* tmp = g_malloc0(size); if (tmp == NULL) { archive_read_close(a); archive_read_free(a); g_object_unref(mis); return NULL; } memcpy(tmp, buf, size); g_memory_input_stream_add_data(mis, tmp, size, g_free); } GdkPixbuf* pixbuf = gdk_pixbuf_new_from_stream(is, NULL, NULL); if (pixbuf == NULL) { archive_read_close(a); archive_read_free(a); g_object_unref(mis); return NULL; } archive_read_close(a); archive_read_free(a); g_object_unref(mis); return pixbuf; } archive_read_close(a); archive_read_free(a); return NULL; } zathura-cb-0.1.5/page.c0000644000175000017500000000227312636351150013307 0ustar mockmock/* See LICENSE file for license and copyright information */ #include #include #include "plugin.h" #include "internal.h" zathura_error_t cb_page_init(zathura_page_t* page) { if (page == NULL) { return ZATHURA_ERROR_INVALID_ARGUMENTS; } zathura_document_t* document = zathura_page_get_document(page); cb_document_t* cb_document = zathura_document_get_data(document); if (document == NULL || cb_document == NULL) { return ZATHURA_ERROR_UNKNOWN; } cb_document_page_meta_t* meta = girara_list_nth(cb_document->pages, zathura_page_get_index(page)); if (meta == NULL || meta->file == NULL) { return ZATHURA_ERROR_UNKNOWN; } cb_page_t* cb_page = g_malloc0(sizeof(cb_page_t)); if (cb_page == NULL) { return ZATHURA_ERROR_OUT_OF_MEMORY; } cb_page->file = g_strdup(meta->file); zathura_page_set_width(page, meta->width); zathura_page_set_height(page, meta->height); zathura_page_set_data(page, cb_page); return ZATHURA_ERROR_OK; } zathura_error_t cb_page_clear(zathura_page_t* page, cb_page_t* cb_page) { if (cb_page == NULL) { return ZATHURA_ERROR_OK; } g_free(cb_page->file); g_free(cb_page); return ZATHURA_ERROR_OK; } zathura-cb-0.1.5/Doxyfile0000644000175000017500000000116212636351150013731 0ustar mockmock# See LICENSE file for license and copyright information # General information PROJECT_NAME = zathura-cb OUTPUT_DIRECTORY = ./doc/ OUTPUT_LANGUAGE = English TAB_SIZE = 2 EXTRACT_ALL = YES OPTIMIZE_OUTPUT_FOR_C = YES DOXYFILE_ENCODING = UTF-8 TYPEDEF_HIDES_STRUCT = YES # Warning and progress messages QUIET = YES WARNINGS = YES WARN_IF_UNDOCUMENTED = YES # Input files INPUT = FILE_PATTERNS = *.h *.c RECURSIVE = YES # Output files GENERATE_HTML = YES GENERATE_LATEX = NO GENERATE_RTF = NO GENERATE_XML = NO SOURCE_BROWSER = YES zathura-cb-0.1.5/plugin.c0000644000175000017500000000202412636351150013663 0ustar mockmock/* See LICENSE file for license and copyright information */ #include "plugin.h" void register_functions(zathura_plugin_functions_t* functions) { functions->document_open = (zathura_plugin_document_open_t) cb_document_open; functions->document_free = (zathura_plugin_document_free_t) cb_document_free; functions->document_index_generate = (zathura_plugin_document_index_generate_t) cb_document_index_generate; functions->page_init = (zathura_plugin_page_init_t) cb_page_init; functions->page_clear = (zathura_plugin_page_clear_t) cb_page_clear; #ifdef HAVE_CAIRO functions->page_render_cairo = (zathura_plugin_page_render_cairo_t) cb_page_render_cairo; #endif } ZATHURA_PLUGIN_REGISTER( "cb", VERSION_MAJOR, VERSION_MINOR, VERSION_REV, register_functions, ZATHURA_PLUGIN_MIMETYPES({ "application/x-cbr", "application/x-rar", "application/x-cbz", "application/zip", "application/x-cb7", "application/x-7z-compressed", "application/x-cbt", "application/x-tar" }) ) zathura-cb-0.1.5/document.c0000644000175000017500000001324012636351150014205 0ustar mockmock/* See LICENSE file for license and copyright information */ #include #include #include #include #include #include #include #include #include #include "plugin.h" #include "internal.h" #include "utils.h" static int compare_pages(const cb_document_page_meta_t* page1, const cb_document_page_meta_t* page2); static bool read_archive(cb_document_t* cb_document, const char* archive, girara_list_t* supported_extensions); static char* get_extension(const char* path); static void cb_document_page_meta_free(cb_document_page_meta_t* meta); zathura_error_t cb_document_open(zathura_document_t* document) { if (document == NULL) { return ZATHURA_ERROR_INVALID_ARGUMENTS; } cb_document_t* cb_document = g_malloc0(sizeof(cb_document)); /* archive path */ const char* path = zathura_document_get_path(document); /* create list of supported formats */ girara_list_t* supported_extensions = girara_list_new2(g_free); if (supported_extensions == NULL) { goto error_free; } GSList* formats = gdk_pixbuf_get_formats(); for (GSList* list = formats; list != NULL; list = list->next) { GdkPixbufFormat* format = (GdkPixbufFormat*) list->data; char** extensions = gdk_pixbuf_format_get_extensions(format); for (unsigned int i = 0; extensions[i] != NULL; i++) { girara_list_append(supported_extensions, g_strdup(extensions[i])); } g_strfreev(extensions); } g_slist_free(formats); /* create list of supported files (pages) */ cb_document->pages = girara_sorted_list_new2((girara_compare_function_t) compare_pages, (girara_free_function_t) cb_document_page_meta_free); if (cb_document->pages == NULL) { goto error_free; } /* read files recursively */ if (read_archive(cb_document, path, supported_extensions) == false) { goto error_free; } girara_list_free(supported_extensions); /* set document information */ zathura_document_set_number_of_pages(document, girara_list_size(cb_document->pages)); zathura_document_set_data(document, cb_document); return ZATHURA_ERROR_OK; error_free: girara_list_free(supported_extensions); cb_document_free(document, cb_document); return ZATHURA_ERROR_UNKNOWN; } zathura_error_t cb_document_free(zathura_document_t* document, cb_document_t* cb_document) { if (cb_document == NULL) { return ZATHURA_ERROR_INVALID_ARGUMENTS; } /* remove page list */ if (cb_document->pages != NULL) { girara_list_free(cb_document->pages); } g_free(cb_document); return ZATHURA_ERROR_OK; } static void cb_document_page_meta_free(cb_document_page_meta_t* meta) { if (meta == NULL) { return; } if (meta->file != NULL) { g_free(meta->file); } g_free(meta); } static void get_pixbuf_size(GdkPixbufLoader* loader, int width, int height, gpointer data) { cb_document_page_meta_t* meta = (cb_document_page_meta_t*)data; meta->width = width; meta->height = height; gdk_pixbuf_loader_set_size(loader, 0, 0); } static bool read_archive(cb_document_t* cb_document, const char* archive, girara_list_t* supported_extensions) { struct archive* a = archive_read_new(); if (a == NULL) { return false; } archive_read_support_filter_all(a); archive_read_support_format_all(a); int r = archive_read_open_filename(a, archive, (size_t) LIBARCHIVE_BUFFER_SIZE); if (r != ARCHIVE_OK) { archive_read_free(a); return false; } struct archive_entry *entry = NULL; while ((r = archive_read_next_header(a, &entry)) != ARCHIVE_EOF) { if (r < ARCHIVE_WARN) { // let's ignore warnings ... they are non-fatal errors archive_read_close(a); archive_read_free(a); return false; } if (archive_entry_filetype(entry) != AE_IFREG) { // we only care about regular files continue; } const char* path = archive_entry_pathname(entry); char* extension = get_extension(path); if (extension == NULL) { continue; } GIRARA_LIST_FOREACH(supported_extensions, char*, iter, ext) if (g_strcmp0(extension, ext) == 0) { cb_document_page_meta_t* meta = g_malloc0(sizeof(cb_document_page_meta_t)); meta->file = g_strdup(path); GdkPixbufLoader* loader = gdk_pixbuf_loader_new(); g_signal_connect(loader, "size-prepared", G_CALLBACK(get_pixbuf_size), meta); size_t size = 0; const void* buf = NULL; __LA_INT64_T offset = 0; while ((r = archive_read_data_block(a, &buf, &size, &offset)) != ARCHIVE_EOF) { if (r < ARCHIVE_WARN) { break; } if (buf == NULL || size <= 0) { continue; } if (gdk_pixbuf_loader_write(loader, buf, size, NULL) == false) { break; } if (meta->width > 0 && meta->height > 0) { break; } } gdk_pixbuf_loader_close(loader, NULL); g_object_unref(loader); if (meta->width > 0 && meta->height > 0) { girara_list_append(cb_document->pages, meta); } else { cb_document_page_meta_free(meta); } break; } GIRARA_LIST_FOREACH_END(supported_extensions, char*, iter, ext); g_free(extension); } archive_read_close(a); archive_read_free(a); return true; } static int compare_pages(const cb_document_page_meta_t* page1, const cb_document_page_meta_t* page2) { return compare_path(page1->file, page2->file); } static char* get_extension(const char* path) { if (path == NULL) { return NULL; } const char* res = strrchr(path, '.'); if (res == NULL) { return NULL; } return g_ascii_strdown(res + 1, -1); } zathura-cb-0.1.5/utils.h0000644000175000017500000000043712636351150013540 0ustar mockmock/* See LICENSE file for license and copyright information */ #ifndef UTILS_H #define UTILS_H /** * Compares two paths with each other * * @param str1 First path * @param str2 Second path * * @return */ int compare_path(const char* str1, const char* str2); #endif // UTILS_H zathura-cb-0.1.5/plugin.h0000644000175000017500000000341512636351150013675 0ustar mockmock/* See LICENSE file for license and copyright information */ #ifndef CB_H #define CB_H #include #if HAVE_CAIRO #include #endif #include typedef struct cb_document_s cb_document_t; typedef struct cb_page_s cb_page_t; /** * Opens a new document * * @param document The document * @return ZATHURA_ERROR_OK if no error occured */ zathura_error_t cb_document_open(zathura_document_t* document); /** * Frees the document * * @param document The document * @param data Custom data * @return ZATHURA_ERROR_OK if no error occured */ zathura_error_t cb_document_free(zathura_document_t* document, cb_document_t* cb_document); /** * Generates the index of the document * * @param document Zathura document * @param error Set to an error value (see zathura_error_t) if an * error occured * @return Tree node object or NULL if an error occurred (e.g.: the document has * no index) */ girara_tree_node_t* cb_document_index_generate(zathura_document_t* document, cb_document_t* cb_document, zathura_error_t* error); /** * Initializes a page * * @param page The page * @return ZATHURA_ERROR_OK if no error occured */ zathura_error_t cb_page_init(zathura_page_t* page); /** * Clear page * * @param page The page * @param cb_page cb Page * @return ZATHURA_ERROR_OK if no error occured */ zathura_error_t cb_page_clear(zathura_page_t* page, cb_page_t* cb_page); #if HAVE_CAIRO /** * Renders the page to a cairo object * * @param page The page * @param cb_page cb Page * @param cairo Cairo object * @param printing Render for printing * @return ZATHURA_ERROR_OK if no error occured */ zathura_error_t cb_page_render_cairo(zathura_page_t* page, cb_page_t* cb_page, cairo_t* cairo, bool printing); #endif #endif // CB_H zathura-cb-0.1.5/utils.c0000644000175000017500000000052612636351150013532 0ustar mockmock/* See LICENSE file for license and copyright information */ #include #include "utils.h" int compare_path(const char* str1, const char* str2) { char* ustr1 = g_utf8_casefold(str1, -1); char* ustr2 = g_utf8_casefold(str2, -1); int result = g_utf8_collate(ustr1, ustr2); g_free(ustr1); g_free(ustr2); return result; } zathura-cb-0.1.5/common.mk0000644000175000017500000000017612636351150014050 0ustar mockmock# See LICENSE file for license and copyright information ifeq "$(VERBOSE)" "0" ECHO=@echo QUIET=@ else ECHO=@\# QUIET= endif zathura-cb-0.1.5/internal.h0000644000175000017500000000105012636351150014204 0ustar mockmock/* See LICENSE file for license and copyright information */ #ifndef INTERNAL_H #define INTERNAL_H #define LIBARCHIVE_BUFFER_SIZE 8192 struct cb_document_s { girara_list_t* pages; /**< List of metadata structs */ }; struct cb_page_s { char* file; /**< Image associated to the page */ }; /** Image meta-data read during the document initialization */ typedef struct cb_document_page_meta_s { char* file; /**< Image file */ int width; /**< Image width */ int height; /**< Image height */ } cb_document_page_meta_t; #endif // INTERNAL_H zathura-cb-0.1.5/LICENSE0000644000175000017500000000154212636351150013232 0ustar mockmockCopyright (c) 2012-2013 pwmt.org This software is provided 'as-is', without any express or implied warranty. In no event will the authors be held liable for any damages arising from the use of this software. Permission is granted to anyone to use this software for any purpose, including commercial applications, and to alter it and redistribute it freely, subject to the following restrictions: 1. The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation would be appreciated but is not required. 2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software. 3. This notice may not be removed or altered from any source distribution. zathura-cb-0.1.5/index.c0000644000175000017500000000236112636351150013500 0ustar mockmock/* See LICENSE file for license and copyright information */ #include "plugin.h" #include "internal.h" #include girara_tree_node_t* cb_document_index_generate(zathura_document_t* document, cb_document_t* cb_document, zathura_error_t* error) { if (document == NULL || cb_document == NULL) { if (error != NULL) { *error = ZATHURA_ERROR_INVALID_ARGUMENTS; } return NULL; } girara_tree_node_t* root = girara_node_new(zathura_index_element_new("ROOT")); unsigned int page_number = 0; GIRARA_LIST_FOREACH(cb_document->pages, cb_document_page_meta_t*, iter, page) { gchar* markup = g_markup_escape_text(page->file, -1); zathura_index_element_t* index_element = zathura_index_element_new(markup); g_free(markup); if (index_element != NULL) { zathura_rectangle_t rect = { 0, 0, 0, 0 }; zathura_link_target_t target = { ZATHURA_LINK_DESTINATION_XYZ, NULL, page_number, -1, -1, -1, -1, 0 }; index_element->link = zathura_link_new(ZATHURA_LINK_GOTO_DEST, rect, target); girara_node_append_data(root, index_element); } ++page_number; } GIRARA_LIST_FOREACH_END(cb_document->pages, cb_document_page_meta_t*, iter, page); return root; }