Commit 4b559e58 authored by Sebastian Ramacher's avatar Sebastian Ramacher
Browse files

Implement support to use both database backends.

parent 925c9973
...@@ -4,17 +4,14 @@ include config.mk ...@@ -4,17 +4,14 @@ include config.mk
include common.mk include common.mk
PROJECT = zathura PROJECT = zathura
OSOURCE = $(shell find . -maxdepth 1 -iname "*.c" -a ! -iname "database-*") OSOURCE = $(shell find . -maxdepth 1 -iname "*.c" -a ! -iname "database-sqlite.c")
HEADER = $(shell find . -maxdepth 1 -iname "*.h") HEADER = $(shell find . -maxdepth 1 -iname "*.h")
ifeq (${DATABASE}, sqlite) ifneq (${WITH_SQLITE},0)
INCS += $(SQLITE_INC) INCS += $(SQLITE_INC)
LIBS += $(SQLITE_LIB) LIBS += $(SQLITE_LIB)
SOURCE = $(OSOURCE) database-sqlite.c SOURCE = $(OSOURCE) database-sqlite.c
else CPPFLAGS += -DWITH_SQLITE
ifeq (${DATABASE}, plain)
SOURCE = $(OSOURCE) database-plain.c
endif
endif endif
OBJECTS = $(patsubst %.c, %.o, $(SOURCE)) OBJECTS = $(patsubst %.c, %.o, $(SOURCE))
...@@ -45,9 +42,6 @@ version.h: version.h.in config.mk ...@@ -45,9 +42,6 @@ version.h: version.h.in config.mk
@mkdir -p .depend @mkdir -p .depend
$(QUIET)${CC} -c ${CPPFLAGS} ${CFLAGS} ${DFLAGS} -o $@ $< -MMD -MF .depend/$@.dep $(QUIET)${CC} -c ${CPPFLAGS} ${CFLAGS} ${DFLAGS} -o $@ $< -MMD -MF .depend/$@.dep
# force recompilation of database.o if DATABASE has changed
database.o: database-${DATABASE}.o
${OBJECTS}: config.mk version.h ${OBJECTS}: config.mk version.h
${DOBJECTS}: config.mk version.h ${DOBJECTS}: config.mk version.h
...@@ -91,7 +85,7 @@ dist: clean ...@@ -91,7 +85,7 @@ dist: clean
$(QUIET)mkdir -p ${PROJECT}-${VERSION}/tests $(QUIET)mkdir -p ${PROJECT}-${VERSION}/tests
$(QUIET)cp LICENSE Makefile config.mk common.mk README AUTHORS Doxyfile \ $(QUIET)cp LICENSE Makefile config.mk common.mk README AUTHORS Doxyfile \
${PROJECT}.1.rst ${PROJECT}rc.5.rst ${OSOURCE} ${HEADER} ${PROJECT}.pc.in \ ${PROJECT}.1.rst ${PROJECT}rc.5.rst ${OSOURCE} ${HEADER} ${PROJECT}.pc.in \
${PROJECT}.desktop version.h.in database-*.c \ ${PROJECT}.desktop version.h.in database-sqlite.c \
${PROJECT}-${VERSION} ${PROJECT}-${VERSION}
$(QUIET)cp tests/Makefile tests/config.mk tests/*.c \ $(QUIET)cp tests/Makefile tests/config.mk tests/*.c \
${PROJECT}-${VERSION}/tests ${PROJECT}-${VERSION}/tests
......
...@@ -47,7 +47,6 @@ config_load_default(zathura_t* zathura) ...@@ -47,7 +47,6 @@ config_load_default(zathura_t* zathura)
int int_value = 0; int int_value = 0;
float float_value = 0; float float_value = 0;
char* string_value = NULL;
bool bool_value = false; bool bool_value = false;
girara_session_t* gsession = zathura->ui.session; girara_session_t* gsession = zathura->ui.session;
...@@ -65,18 +64,19 @@ config_load_default(zathura_t* zathura) ...@@ -65,18 +64,19 @@ config_load_default(zathura_t* zathura)
girara_mode_set(gsession, zathura->modes.normal); girara_mode_set(gsession, zathura->modes.normal);
/* zathura settings */ /* zathura settings */
girara_setting_add(gsession, "database", "plain", STRING, true, "Database backend", NULL, NULL);
int_value = 10; int_value = 10;
girara_setting_add(gsession, "zoom-step", &int_value, INT, false, "Zoom step", NULL, NULL); girara_setting_add(gsession, "zoom-step", &int_value, INT, false, "Zoom step", NULL, NULL);
int_value = 1; int_value = 1;
girara_setting_add(gsession, "page-padding", &int_value, INT, true, "Padding between pages", NULL, NULL); girara_setting_add(gsession, "page-padding", &int_value, INT, true, "Padding between pages", NULL, NULL);
int_value = 1; int_value = 1;
girara_setting_add(gsession, "pages-per-row", &int_value, INT, false, "Number of pages per row", cb_pages_per_row_value_changed, NULL); girara_setting_add(gsession, "pages-per-row", &int_value, INT, false, "Number of pages per row", cb_pages_per_row_value_changed, NULL);
float_value = 40; float_value = 40;
girara_setting_add(gsession, "scroll-step", &float_value, FLOAT, false, "Scroll step", NULL, NULL); girara_setting_add(gsession, "scroll-step", &float_value, FLOAT, false, "Scroll step", NULL, NULL);
int_value = 10; int_value = 10;
girara_setting_add(gsession, "zoom-min", &int_value, INT, false, "Zoom minimum", NULL, NULL); girara_setting_add(gsession, "zoom-min", &int_value, INT, false, "Zoom minimum", NULL, NULL);
int_value = 1000; int_value = 1000;
girara_setting_add(gsession, "zoom-max", &int_value, INT, false, "Zoom maximum", NULL, NULL); girara_setting_add(gsession, "zoom-max", &int_value, INT, false, "Zoom maximum", NULL, NULL);
girara_setting_add(gsession, "recolor-darkcolor", NULL, STRING, false, "Recoloring (dark color)", cb_color_change, NULL); girara_setting_add(gsession, "recolor-darkcolor", NULL, STRING, false, "Recoloring (dark color)", cb_color_change, NULL);
girara_setting_set(gsession, "recolor-darkcolor", "#FFFFFF"); girara_setting_set(gsession, "recolor-darkcolor", "#FFFFFF");
...@@ -91,8 +91,7 @@ config_load_default(zathura_t* zathura) ...@@ -91,8 +91,7 @@ config_load_default(zathura_t* zathura)
girara_setting_add(gsession, "highlight-transparency", &float_value, FLOAT, false, "Transparency for highlighting", NULL, NULL); girara_setting_add(gsession, "highlight-transparency", &float_value, FLOAT, false, "Transparency for highlighting", NULL, NULL);
bool_value = true; bool_value = true;
girara_setting_add(gsession, "render-loading", &bool_value, BOOLEAN, false, "Render 'Loading ...'", NULL, NULL); girara_setting_add(gsession, "render-loading", &bool_value, BOOLEAN, false, "Render 'Loading ...'", NULL, NULL);
string_value = "best-fit"; girara_setting_add(gsession, "adjust-open", "best-fit", STRING, false, "Adjust to when opening file", NULL, NULL);
girara_setting_add(gsession, "adjust-open", string_value, STRING, false, "Adjust to when opening file", NULL, NULL);
bool_value = false; bool_value = false;
girara_setting_add(gsession, "show-hidden", &bool_value, BOOLEAN, false, "Show hidden files and directories", NULL, NULL); girara_setting_add(gsession, "show-hidden", &bool_value, BOOLEAN, false, "Show hidden files and directories", NULL, NULL);
......
...@@ -10,6 +10,10 @@ VERSION = ${ZATHURA_VERSION_MAJOR}.${ZATHURA_VERSION_MINOR}.${ZATHURA_VERSION_RE ...@@ -10,6 +10,10 @@ VERSION = ${ZATHURA_VERSION_MAJOR}.${ZATHURA_VERSION_MINOR}.${ZATHURA_VERSION_RE
# the GTK version to use # the GTK version to use
ZATHURA_GTK_VERSION ?= 2 ZATHURA_GTK_VERSION ?= 2
# database
# build with sqlite support
WITH_SQLITE ?= 1
# paths # paths
PREFIX ?= /usr PREFIX ?= /usr
MANPREFIX ?= ${PREFIX}/share/man MANPREFIX ?= ${PREFIX}/share/man
...@@ -26,8 +30,10 @@ GTK_LIB ?= $(shell pkg-config --libs gtk+-${ZATHURA_GTK_VERSION}.0 gthread-2.0) ...@@ -26,8 +30,10 @@ GTK_LIB ?= $(shell pkg-config --libs gtk+-${ZATHURA_GTK_VERSION}.0 gthread-2.0)
GIRARA_INC ?= $(shell pkg-config --cflags girara-gtk${ZATHURA_GTK_VERSION}) GIRARA_INC ?= $(shell pkg-config --cflags girara-gtk${ZATHURA_GTK_VERSION})
GIRARA_LIB ?= $(shell pkg-config --libs girara-gtk${ZATHURA_GTK_VERSION}) GIRARA_LIB ?= $(shell pkg-config --libs girara-gtk${ZATHURA_GTK_VERSION})
ifneq (${WITH_SQLITE},0)
SQLITE_INC ?= $(shell pkg-config --cflags sqlite3) SQLITE_INC ?= $(shell pkg-config --cflags sqlite3)
SQLITE_LIB ?= $(shell pkg-config --libs sqlite3) SQLITE_LIB ?= $(shell pkg-config --libs sqlite3)
endif
#set it to an empty value if you don't need to link against ld for dlopen and friends #set it to an empty value if you don't need to link against ld for dlopen and friends
DL_LIB ?= -ldl DL_LIB ?= -ldl
...@@ -54,6 +60,3 @@ SFLAGS ?= -s ...@@ -54,6 +60,3 @@ SFLAGS ?= -s
# set to something != 0 if you want verbose build output # set to something != 0 if you want verbose build output
VERBOSE ?= 0 VERBOSE ?= 0
# database
# possible values are sqlite and plain
DATABASE ?= plain
...@@ -11,7 +11,7 @@ ...@@ -11,7 +11,7 @@
#include <girara/utils.h> #include <girara/utils.h>
#include <girara/datastructures.h> #include <girara/datastructures.h>
#include "database.h" #include "database-plain.h"
#define BOOKMARKS "bookmarks" #define BOOKMARKS "bookmarks"
#define HISTORY "history" #define HISTORY "history"
...@@ -27,6 +27,24 @@ ...@@ -27,6 +27,24 @@
fcntl(fd, F_SETLK, lock); \ fcntl(fd, F_SETLK, lock); \
} }
static void zathura_database_interface_init(ZathuraDatabaseInterface* iface);
G_DEFINE_TYPE_WITH_CODE(ZathuraPlainDatabase, zathura_plaindatabase, G_TYPE_OBJECT,
G_IMPLEMENT_INTERFACE(ZATHURA_TYPE_DATABASE, zathura_database_interface_init))
static void plain_finalize(GObject* object);
static bool plain_add_bookmark(zathura_database_t* db, const char* file,
zathura_bookmark_t* bookmark);
static bool plain_remove_bookmark(zathura_database_t* db, const char* file, const
char* id);
static girara_list_t* plain_load_bookmarks(zathura_database_t* db, const char*
file);
static bool plain_set_fileinfo(zathura_database_t* db, const char* file, unsigned
int page, int offset, double scale, int rotation);
static bool plain_get_fileinfo(zathura_database_t* db, const char* file, unsigned
int* page, int* offset, double* scale, int* rotation);
static void plain_set_property(GObject* object, guint prop_id, const GValue* value, GParamSpec* pspec);
/* forward declaration */ /* forward declaration */
static bool zathura_db_check_file(const char* path); static bool zathura_db_check_file(const char* path);
static GKeyFile* zathura_db_read_key_file_from_file(const char* path); static GKeyFile* zathura_db_read_key_file_from_file(const char* path);
...@@ -34,8 +52,7 @@ static void zathura_db_write_key_file_to_file(const char* file, GKeyFile* key_fi ...@@ -34,8 +52,7 @@ static void zathura_db_write_key_file_to_file(const char* file, GKeyFile* key_fi
static void cb_zathura_db_watch_file(GFileMonitor* monitor, GFile* file, GFile* static void cb_zathura_db_watch_file(GFileMonitor* monitor, GFile* file, GFile*
other_file, GFileMonitorEvent event, zathura_database_t* database); other_file, GFileMonitorEvent event, zathura_database_t* database);
struct zathura_database_s typedef struct zathura_plaindatabase_private_s {
{
char* bookmark_path; char* bookmark_path;
GKeyFile* bookmarks; GKeyFile* bookmarks;
GFileMonitor* bookmark_monitor; GFileMonitor* bookmark_monitor;
...@@ -43,143 +60,232 @@ struct zathura_database_s ...@@ -43,143 +60,232 @@ struct zathura_database_s
char* history_path; char* history_path;
GKeyFile* history; GKeyFile* history;
GFileMonitor* history_monitor; GFileMonitor* history_monitor;
} zathura_plaindatabase_private_t;
#define ZATHURA_PLAINDATABASE_GET_PRIVATE(obj) \
(G_TYPE_INSTANCE_GET_PRIVATE ((obj), ZATHURA_TYPE_PLAINDATABASE, zathura_plaindatabase_private_t))
enum
{
PROP_0,
PROP_PATH
}; };
static void
zathura_database_interface_init(ZathuraDatabaseInterface* iface)
{
/* initialize interface */
iface->add_bookmark = plain_add_bookmark;
iface->remove_bookmark = plain_remove_bookmark;
iface->load_bookmarks = plain_load_bookmarks;
iface->set_fileinfo = plain_set_fileinfo;
iface->get_fileinfo = plain_get_fileinfo;
}
static void
zathura_plaindatabase_class_init(ZathuraPlainDatabaseClass* class)
{
/* add private members */
g_type_class_add_private(class, sizeof(zathura_plaindatabase_private_t));
/* override methods */
GObjectClass* object_class = G_OBJECT_CLASS(class);
object_class->finalize = plain_finalize;
object_class->set_property = plain_set_property;
g_object_class_install_property(object_class, PROP_PATH,
g_param_spec_string("path", "path", "path to directory where the bookmarks and history are locates",
NULL, G_PARAM_WRITABLE | G_PARAM_CONSTRUCT_ONLY));
}
static void
zathura_plaindatabase_init(ZathuraPlainDatabase* db)
{
zathura_plaindatabase_private_t* priv = ZATHURA_PLAINDATABASE_GET_PRIVATE(db);
priv->bookmark_path = NULL;
priv->bookmark_monitor = NULL;
priv->bookmarks = NULL;
priv->history_path = NULL;
priv->history_monitor = NULL;
priv->history = NULL;
}
zathura_database_t* zathura_database_t*
zathura_db_init(const char* dir) zathura_plaindatabase_new(const char* path)
{ {
if (dir == NULL) { g_return_val_if_fail(path != NULL && strlen(path) != 0, NULL);
goto error_ret;
}
zathura_database_t* db = calloc(1, sizeof(zathura_database_t)); zathura_database_t* db = g_object_new(ZATHURA_TYPE_PLAINDATABASE, "path", path, NULL);
if (db == NULL) { zathura_plaindatabase_private_t* priv = ZATHURA_PLAINDATABASE_GET_PRIVATE(db);
goto error_ret; if (priv->bookmark_path == NULL) {
g_object_unref(db);
return NULL;
} }
return db;
}
static void
plain_db_init(ZathuraPlainDatabase* db, const char* dir)
{
zathura_plaindatabase_private_t* priv = ZATHURA_PLAINDATABASE_GET_PRIVATE(db);
/* bookmarks */ /* bookmarks */
db->bookmark_path = g_build_filename(dir, BOOKMARKS, NULL); priv->bookmark_path = g_build_filename(dir, BOOKMARKS, NULL);
if (db->bookmark_path == NULL || if (zathura_db_check_file(priv->bookmark_path) == false) {
zathura_db_check_file(db->bookmark_path) == false) {
goto error_free; goto error_free;
} }
GFile* bookmark_file = g_file_new_for_path(db->bookmark_path); GFile* bookmark_file = g_file_new_for_path(priv->bookmark_path);
if (bookmark_file != NULL) { if (bookmark_file != NULL) {
db->bookmark_monitor = g_file_monitor(bookmark_file, G_FILE_MONITOR_NONE, NULL, NULL); priv->bookmark_monitor = g_file_monitor(bookmark_file, G_FILE_MONITOR_NONE, NULL, NULL);
} else { } else {
goto error_free; goto error_free;
} }
g_object_unref(bookmark_file); g_object_unref(bookmark_file);
g_signal_connect( g_signal_connect(
G_OBJECT(db->bookmark_monitor), G_OBJECT(priv->bookmark_monitor),
"changed", "changed",
G_CALLBACK(cb_zathura_db_watch_file), G_CALLBACK(cb_zathura_db_watch_file),
db db
); );
db->bookmarks = zathura_db_read_key_file_from_file(db->bookmark_path); priv->bookmarks = zathura_db_read_key_file_from_file(priv->bookmark_path);
if (db->bookmarks == NULL) { if (priv->bookmarks == NULL) {
goto error_free; goto error_free;
} }
/* history */ /* history */
db->history_path = g_build_filename(dir, HISTORY, NULL); priv->history_path = g_build_filename(dir, HISTORY, NULL);
if (db->history_path == NULL || if (zathura_db_check_file(priv->history_path) == false) {
zathura_db_check_file(db->history_path) == false) {
goto error_free; goto error_free;
} }
GFile* history_file = g_file_new_for_path(db->history_path); GFile* history_file = g_file_new_for_path(priv->history_path);
if (history_file != NULL) { if (history_file != NULL) {
db->history_monitor = g_file_monitor(history_file, G_FILE_MONITOR_NONE, NULL, NULL); priv->history_monitor = g_file_monitor(history_file, G_FILE_MONITOR_NONE, NULL, NULL);
} else { } else {
goto error_free; goto error_free;
} }
g_object_unref(history_file); g_object_unref(history_file);
g_signal_connect( g_signal_connect(
G_OBJECT(db->history_monitor), G_OBJECT(priv->history_monitor),
"changed", "changed",
G_CALLBACK(cb_zathura_db_watch_file), G_CALLBACK(cb_zathura_db_watch_file),
db db
); );
db->history = zathura_db_read_key_file_from_file(db->history_path); priv->history = zathura_db_read_key_file_from_file(priv->history_path);
if (db->history == NULL) { if (priv->history == NULL) {
goto error_free; goto error_free;
} }
return db;
error_free: error_free:
zathura_db_free(db); /* bookmarks */
g_free(priv->bookmark_path);
priv->bookmark_path = NULL;
if (priv->bookmark_monitor != NULL) {
g_object_unref(priv->bookmark_monitor);
priv->bookmark_monitor = NULL;
}
if (priv->bookmarks != NULL) {
g_key_file_free(priv->bookmarks);
priv->bookmarks = NULL;
}
/* history */
g_free(priv->history_path);
priv->history_path = NULL;
error_ret: if (priv->history_monitor != NULL) {
g_object_unref(priv->history_monitor);
priv->history_monitor = NULL;
}
return NULL; if (priv->history != NULL) {
g_key_file_free(priv->history);
priv->history = NULL;
}
} }
void static void
zathura_db_free(zathura_database_t* db) plain_set_property(GObject* object, guint prop_id, const GValue* value, GParamSpec* pspec)
{ {
if (db == NULL) { ZathuraPlainDatabase* db = ZATHURA_PLAINDATABASE(object);
return;
switch (prop_id) {
case PROP_PATH:
plain_db_init(db, g_value_get_string(value));
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec);
} }
}
static void
plain_finalize(GObject* object)
{
ZathuraPlainDatabase* db = ZATHURA_PLAINDATABASE(object);
zathura_plaindatabase_private_t* priv = ZATHURA_PLAINDATABASE_GET_PRIVATE(db);
/* bookmarks */ /* bookmarks */
g_free(db->bookmark_path); g_free(priv->bookmark_path);
if (db->bookmark_monitor != NULL) { if (priv->bookmark_monitor != NULL) {
g_object_unref(db->bookmark_monitor); g_object_unref(priv->bookmark_monitor);
} }
if (db->bookmarks != NULL) { if (priv->bookmarks != NULL) {
g_key_file_free(db->bookmarks); g_key_file_free(priv->bookmarks);
} }
/* history */ /* history */
g_free(db->history_path); g_free(priv->history_path);
if (db->history_monitor != NULL) { if (priv->history_monitor != NULL) {
g_object_unref(db->history_monitor); g_object_unref(priv->history_monitor);
} }
/* database */ if (priv->history != NULL) {
free(db); g_key_file_free(priv->history);
}
G_OBJECT_CLASS(zathura_plaindatabase_parent_class)->finalize(object);
} }
bool static bool
zathura_db_add_bookmark(zathura_database_t* db, const char* file, plain_add_bookmark(zathura_database_t* db, const char* file,
zathura_bookmark_t* bookmark) zathura_bookmark_t* bookmark)
{ {
if (db == NULL || db->bookmarks == NULL || db->bookmark_path == NULL || file zathura_plaindatabase_private_t* priv = ZATHURA_PLAINDATABASE_GET_PRIVATE(db);
== NULL || bookmark == NULL || bookmark->id == NULL) { if (priv->bookmarks == NULL || priv->bookmark_path == NULL ||
bookmark->id == NULL) {
return false; return false;
} }
g_key_file_set_integer(db->bookmarks, file, bookmark->id, bookmark->page); g_key_file_set_integer(priv->bookmarks, file, bookmark->id, bookmark->page);
zathura_db_write_key_file_to_file(db->bookmark_path, db->bookmarks); zathura_db_write_key_file_to_file(priv->bookmark_path, priv->bookmarks);
return true; return true;
} }
bool static bool
zathura_db_remove_bookmark(zathura_database_t* db, const char* file, const char* plain_remove_bookmark(zathura_database_t* db, const char* file, const char*
id) GIRARA_UNUSED(id))
{ {
if (db == NULL || db->bookmarks == NULL || db->bookmark_path == NULL || file zathura_plaindatabase_private_t* priv = ZATHURA_PLAINDATABASE_GET_PRIVATE(db);
== NULL || id == NULL) { if (priv->bookmarks == NULL || priv->bookmark_path == NULL) {
return false; return false;
} }
if (g_key_file_has_group(db->bookmarks, file) == TRUE) { if (g_key_file_has_group(priv->bookmarks, file) == TRUE) {
g_key_file_remove_group(db->bookmarks, file, NULL); g_key_file_remove_group(priv->bookmarks, file, NULL);
zathura_db_write_key_file_to_file(db->bookmark_path, db->bookmarks); zathura_db_write_key_file_to_file(priv->bookmark_path, priv->bookmarks);
return true; return true;
} }
...@@ -187,27 +293,23 @@ zathura_db_remove_bookmark(zathura_database_t* db, const char* file, const char* ...@@ -187,27 +293,23 @@ zathura_db_remove_bookmark(zathura_database_t* db, const char* file, const char*
return false; return false;
} }
girara_list_t* static girara_list_t*
zathura_db_load_bookmarks(zathura_database_t* db, const char* file) plain_load_bookmarks(zathura_database_t* db, const char* file)
{ {
if (db == NULL || db->bookmarks == NULL || file == NULL) { zathura_plaindatabase_private_t* priv = ZATHURA_PLAINDATABASE_GET_PRIVATE(db);
if (priv->bookmarks == NULL) {
return NULL; return NULL;
} }
if (g_key_file_has_group(db->bookmarks, file) == FALSE) { if (g_key_file_has_group(priv->bookmarks, file) == FALSE) {
return NULL; return NULL;
} }
girara_list_t* result = girara_sorted_list_new2((girara_compare_function_t) zathura_bookmarks_compare, girara_list_t* result = girara_sorted_list_new2((girara_compare_function_t) zathura_bookmarks_compare,
(girara_free_function_t) zathura_bookmark_free); (girara_free_function_t) zathura_bookmark_free);
if (result == NULL) {
return NULL;
}
girara_list_set_free_function(result, (girara_free_function_t) zathura_bookmark_free);
gsize length; gsize length;
char** keys = g_key_file_get_keys(db->bookmarks, file, &length, NULL); char** keys = g_key_file_get_keys(priv->bookmarks, file, &length, NULL);
if (keys == NULL) { if (keys == NULL) {
girara_list_free(result); girara_list_free(result);
return NULL; return NULL;
...@@ -217,7 +319,7 @@ zathura_db_load_bookmarks(zathura_database_t* db, const char* file) ...@@ -217,7 +319,7 @@ zathura_db_load_bookmarks(zathura_database_t* db, const char* file)
zathura_bookmark_t* bookmark = g_malloc0(sizeof(zathura_bookmark_t)); zathura_bookmark_t* bookmark = g_malloc0(sizeof(zathura_bookmark_t));
bookmark->id = g_strdup(keys[i]); bookmark->id = g_strdup(keys[i]);
bookmark->page = g_key_file_get_integer(db->bookmarks, file, keys[i], NULL);