Commit fb088e1f authored by Moritz Lipp's avatar Moritz Lipp
Browse files

Merge branch 'feature/sphinx' into develop

parents 66bdac61 224d8e92
......@@ -13,9 +13,12 @@ zathura.pc
......@@ -99,7 +99,6 @@ clean:
${PROJECT}-debug \
.depend \
${PROJECT}.pc \
doc \
version.h \
version.h.tmp \
dbus-interface-definitions.c \
......@@ -111,6 +110,7 @@ ifneq "$(wildcard ${RSTTOMAN})" ""
$(QUIET)$(MAKE) -C tests clean
$(QUIET)$(MAKE) -C po clean
$(QUIET)$(MAKE) -C doc clean
$(ECHO) CC -o $@
......@@ -142,12 +142,26 @@ dist: clean build-manpages
$(QUIET)mkdir -p ${PROJECT}-${VERSION}
$(QUIET)mkdir -p ${PROJECT}-${VERSION}/tests
$(QUIET)mkdir -p ${PROJECT}-${VERSION}/po
$(QUIET)mkdir -p ${PROJECT}-${VERSION}/doc
${PROJECT}.1.rst ${PROJECT}rc.5.rst ${OSOURCE} ${HEADER} ${PROJECT} \
${PROJECT}.desktop \
${PROJECT}.1 ${PROJECT}rc.5 \
$(QUIET)cp -r data ${PROJECT}-${VERSION}
$(QUIET)cp -r \
doc/Makefile \
doc/Doxyfile \
doc/ \
doc/ \
doc/*.rst \
doc/requirements.txt \
doc/api \
doc/configuration \
doc/installation \
doc/man \
doc/usage \
$(QUIET)cp tests/Makefile tests/ tests/*.c \
$(QUIET)cp po/Makefile po/*.po ${PROJECT}-${VERSION}/po
......@@ -156,7 +170,7 @@ dist: clean build-manpages
$(QUIET)doxygen Doxyfile
$(QUIET)make -C doc
gcov: clean
$(QUIET)CFLAGS="${CFLAGS} -fprofile-arcs -ftest-coverage" LDFLAGS="${LDFLAGS} -fprofile-arcs" ${MAKE} $(PROJECT)
......@@ -170,29 +184,17 @@ po:
$(QUIET)${MAKE} -C po update-po
ifneq "$(wildcard ${RSTTOMAN})" ""
%.1 %.5:
$(QUIET)sed "s/VERSION/${VERSION}/g" < $@.rst > $@.tmp
$(QUIET)${RSTTOMAN} $@.tmp > $@.out.tmp
$(QUIET)mv $@.out.tmp $@
$(QUIET)rm $@.tmp
${PROJECT}.1: ${PROJECT}.1.rst
${PROJECT}rc.5: ${PROJECT}rc.5.rst
build-manpages: ${PROJECT}.1 ${PROJECT}rc.5
$(QUIET)${MAKE} -C doc man
install-manpages: build-manpages
$(ECHO) installing manual pages
$(QUIET)mkdir -m 755 -p ${DESTDIR}${MANPREFIX}/man1 ${DESTDIR}${MANPREFIX}/man5
ifneq "$(wildcard ${PROJECT}.1)" ""
$(QUIET)install -m 644 ${PROJECT}.1 ${DESTDIR}${MANPREFIX}/man1
ifneq "$(wildcard ./doc/_build/man/${PROJECT}.1)" ""
$(QUIET)install -m 644 ./doc/_build/man/${PROJECT}.1 ${DESTDIR}${MANPREFIX}/man1
ifneq "$(wildcard ${PROJECT}rc.5)" ""
$(QUIET)install -m 644 ${PROJECT}rc.5 ${DESTDIR}${MANPREFIX}/man5
ifneq "$(wildcard ./doc/_build/man/${PROJECT}rc.5)" ""
$(QUIET)install -m 644 ./doc/_build/man/${PROJECT}rc.5 ${DESTDIR}${MANPREFIX}/man5
install-headers: ${PROJECT}.pc
......@@ -31,6 +31,9 @@ WITH_MAGIC=0.
If you pass these flags as a command line argument to make, you have to ensure
to pass the same flags when executing the install target.
If you want to build zathuras documentation, please install all python
dependencies from the ./doc/requirements.txt file.
To build and install zathura:
......@@ -48,9 +48,6 @@ PLUGINDIR ?= ${LIBDIR}/zathura
# locale directory
LOCALEDIR ?= ${PREFIX}/share/locale
# rst2man
RSTTOMAN ?= /usr/bin/rst2man
# libs
GTK_INC ?= $(shell pkg-config --cflags gtk+-3.0)
GTK_LIB ?= $(shell pkg-config --libs gtk+-3.0)
......@@ -2,7 +2,7 @@
# General information
PROJECT_NAME = zathura
OUTPUT_DIRECTORY = ./_build/doxygen/
......@@ -16,15 +16,15 @@ WARNINGS = YES
# Input files
EXCLUDE = ./tests
INPUT = ../
EXCLUDE = ./tests ./doc
# Output files
# See LICENSE file for license and copyright information
include ../
include ../
ifeq ($(shell which $(SPHINX_BIN) >/dev/null 2>&1; echo $$?), 1)
$(error The '$(SPHINX_BIN)' command was not found.)
all: html man
html: doxygen
man: doxygen
doxygen: init
.PHONY: clean html man
API and Development
This guide should give a short introduction in the way zathura's plugin
system works and how you can write your own plugin and let zathura use
zathura's plugin system is quite simple. At startup zathura searches
through a specified directory for shared objects and tries to load them
as plugins. Each plugin has to register itself by a name, its version, a
special function as well as its supported mimetypes to zathura. After
the registration of the plugin zathura will automatically use it to open
files with the previous defined mimetypes. That's it.
.. toctree::
:maxdepth: 2
Example - A minimalistic PDF plugin
In this section we are going to develop a simplified version of the
`zathura-pdf-poppler <../zathura-pdf-poppler>`_ plugin. For the sake of
simplicity we are not discussing the build process of the plugin because
we would recommend you to adapt our Makefiles from existing plugins. In
addition we avoid most of the error handling that should be implemented.
In order to use the following described functions and macros you have to
include the *plugin-api.h* header file:
#include <zathura/plugin-api.h>
This automatically loads other header files for the
*zathura\_document\_t*, *zathura\_page\_t* as well as all the other
types that are necessary automatically.
Register the plugin
As previously described each plugin has to register itself to zathura so
that it can be used properly. Therefore we have introduced a macro
called *ZATHURA\_PLUGIN\_REGISTER* which expects several parameters:
- Plugin name *The name of the plugin*
- Major version *The plugins major version*
- Minor version *The plugins minor version*
- Revision *The plugins revision*
- Open function *The open function*
- Mimetypes *A character array of supported mime types*
In our case we are going to register our plugin "my plugin" with its
version 1.0.1, the register function *register\_functions* and the list
of supported mimetypes.
0, 1, 0,
This macro will automatically generate among others a function called
*plugin\_register* which is used to register the plugin to zathura when
it has been loaded.
Register the plugin functions
In our macro we have defined that the function *register\_functions* is
used to install our functions which will implement a certain
functionality in the struct:
register_functions(zathura_plugin_functions_t* functions)
functions->document_open = plugin_document_open;
functions->document_free = plugin_document_free;
functions->page_init = plugin_page_init;
functions->page_clear = plugin_page_clear;
functions->page_render_cairo = plugin_page_render_cairo;
We are now going to give a short overview about the used functions in
the above code snippet. For a complete documentation you should checkout
the documentation of `zathura\_document\_functions\_t <../../doxygen>`_.
A document instance consists out of a *zathura\_document\_t* document
object that contains information about the document itself and a defined
number of *zathura\_page\_t* page objects. There are several functions
defined for those two types and they have to be implemented by the
plugin. For our simple plugin which will only be capable of rendering a
page we will need one function that is capable of opening the PDF
document and setting up all necessary objects for further usage and one
function which will clean up all the allocated objects afterwards. In
addition we need two of those functions for page objects as well and one
function that will actually implement the rendering process.
Open and closing a document
The first thing we have to do when opening a document is to initialize
all necessary objects and values that we are going to need for the
future use of the plugin. Therefore we have to implement our
*pdf\_document\_open* function:
plugin_document_open(zathura_document_t* document)
/* get path and password */
const char* path = zathura_document_get_path(document);
const char* password = zathura_document_get_password(document);
/* create document data */
char* uri = g_filename_to_uri(path, NULL, NULL);
PopplerDocument* poppler_document = poppler_document_new_from_file(uri, password, NULL);
if (poppler_document == NULL) {
/* save poppler document for further usage */
zathura_document_set_data(document, poppler_document);
/* get number of pages */
unsigned int number_of_pages = poppler_document_get_n_pages(poppler_document);
zathura_document_set_number_of_pages(document, number_of_pages);
To open the document we retrieve the *path* and the optional *password*
of the document to create an instance of *PopplerDocument* which
represents a document in the poppler library. If this fails for any
reason (e.g.: the path does not exist, the user provided the incorrect
password) we tell zathura that this function failed for an unknown
reason. If we are lucky we continue and save the created
*poppler\_document* object in the custom data field of the document so
that we can access it later on. After that we determine the number of
pages that the document contains so that zathura can initialize every
single page.
Since we have allocated the *poppler\_document* object we have to make
sure that its resources will be freed when it is no longer needed. This
happens in our *pdf\_document\_free* function:
plugin_document_free(zathura_document_t* document, PopplerDocument* poppler_document)
Page initialization
Each page has to be initialized so that zathura knows about its
dimension. In addition this stage is used to store additional data in
the page that will be used for further use with it. Therefore we are
implementing *pdf\_page\_init* which will save the width and the height
of the page in the given structure:
plugin_page_init(zathura_page_t* page)
unsigned int page_index = zathura_page_get_index(page);
zathura_document_t* document = zathura_page_get_document(page);
PopplerDocument* poppler_document = zathura_document_get_data(document);
/* create poppler page */
PopplerPage* poppler_page = poppler_document_get_page(poppler_document, page_index);
zathura_page_set_data(page, poppler_page);
/* get page dimensions */
double width, height;
poppler_page_get_size(poppler_page, &width, &height);
zathura_page_set_width(page, width);
zathura_page_set_height(page, height);
And we have to make sure that all requested resources are freed in the
plugin_page_clear(zathura_page_t* page, PopplerPage* poppler_page)
Render a page
After we have setup the document and the page objects we are ready to
implement the render function which finally will be able to draw our
page on a widget so that it can be viewed with zathura. This function
has two additional parameters to the already known *zathura\_page\_t*
object: One of them is a *cairo\_t* object which will be used to render
the page, the other one is a flag called *printing* which determines if
the rendered page should be rendered for the print process of zathura.
For instance if this flag is set to true you should not render any
rectangles around links in the document because they are totally
worthless on paper:
pdf_page_render_cairo(zathura_page_t* page, cairo_t* cairo, bool printing)
if (printing == false) {
poppler_page_render(poppler_page, cairo);
} else {
poppler_page_render_for_printing(poppler_page, cairo);
In this case the *pdf\_page\_render\_cairo* function is very simplistic
since all the work is done by the *poppler* library. In your case you
might have to do some magic here to draw the page to the cairo object.
Make sure to check out the source code of our plugins.
Installation of the plugin
As we suggested earlier the easiest way to build and install the plugin
is to duplicate the *Makefile* (as long with its ** and
** files of one of our plugins. It already contains all
necessary targets for building, installing and debugging the plugin.
Otherwise you could build the above plugin with the following command:
$ gcc -std=c99 -shared -fPIC -pedantic -Wall `pkg-config --cflags --libs poppler-glib zathura` \
-o pdf.c
After that you have to copy the ** file into the directory where
zathura looks for plugins (this is by default: */usr/lib/zathura*).
Plugin system
zathura's plugin system is quite simple. At startup zathura searches
through a specified directory for shared objects and tries to load them
as plugins. Each plugin has to register itself by a name, its version, a
special function as well as its supported mimetypes to zathura. After
the registration of the plugin zathura will automatically use it to open
files with the previous defined mimetypes. That's it.
Each plugin has to implement a basic set of functionality so that it can
be used in a meaningful way with zathura. For instance it would not make
any sense if the plugin was not able to render any page at all. On the
contrary the export of images out of the document might not be
considered as that important.
We have predefined a certain set of functionality that a plugin can have
and that can be used by zathura if it has been implemented by the
plugin. When a plugin is loaded, zathura calls a certain function that
the plugin **must implemented** in order to work correctly. This
function gets a data structure which has to be filled with function
pointers by the plugin, which are then used by the main application.
.. toctree::
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
# See LICENSE file for license and copyright information
import sphinx_rtd_theme
# -- General configuration ------------------------------------------------
extensions = [
source_suffix = '.rst'
master_doc = 'index'
templates_path = ['_templates']
exclude_patterns = ['_build']
pygments_style = 'sphinx'
# -- Project configuration ------------------------------------------------
project = 'zathura'
copyright = '2014,'
version = '0.2.7'
release = '0.2.7'
# -- Options for HTML output ----------------------------------------------
html_theme = 'sphinx_rtd_theme'
html_theme_path = [sphinx_rtd_theme.get_html_theme_path()]
html_static_path = ['_static']
htmlhelp_basename = 'zathuradoc'
# -- Options for manual page output ---------------------------------------
man_pages = [
('man/zathura.1', 'zathura', 'a document viewer', [''], 1),
('man/zathurarc.5', 'zathurarc', 'a document viewer', [''], 5)
# -- Options for breathe ---------------------------------------
breathe_projects = { "zathura": "_build/doxygen/xml" }
breathe_default_project = "zathura"
breathe_build_directory = "_build"
breathe_projects_source = {
"zathura": "../"
breathe_domain_by_extension = {
"h" : "c",
"c" : "c"
# See LICENSE file for license and copyright information
SPHINX_BIN = sphinx-build
DOXYGEN_BIN = doxygen
.. toctree::
:maxdepth: 1
The customization of zathura is be managed via a configuration file
called *zathurarc*. By default zathura will evaluate the following
- */etc/zathurarc*
- *$XDG\_CONFIG\_HOME/zathura/zathurarc* (default:
The *zathurarc* file is a simple plain text file that can be populated
with various commands to change the behaviour and the look of zathura
which we are going to describe in the following subsections. Each line
(besides empty lines and comments (which start with a prepended *#*) is
evaluated on its own, so it is not possible to write multiple commands
in one single line.
map - Mapping a shortcut
It is possible to map or remap new key bindings to shortcut functions
which allows a high level of customization. The *:map* command can also
be used in the *zathurarc* file to make those changes permanent:
map [mode] <binding> <shortcut function> <argument>
The *map* command expects several arguments where only the *binding* as
well as the *shortcut-function* argument is required. Since zathura uses
several modes it is possible to map bindings only for a specific mode by
passing the *mode* argument which can take one of the following values:
- normal (default)
- visual
- insert
- fullscreen
- index
The brackets around the value are mandatory.
Single key binding
The (possible) second argument defines the used key binding that should
be mapped to the shortcut function and is structured like the following.
On the one hand it is possible to just assign single letters, numbers or
signs to it:
map a shortcut_function
map b shortcut_function
map c shortcut_function
map 1 shortcut_function
map 2 shortcut_function
map 3 shortcut_function
map ! shortcut_function
map ? shortcut_function
Using modifiers
It is also possible to use modifiers like the *Control* or *Alt* button
on the keyboard. It is possible to use the following modifiers:
- A - *Alt*
- C - *Control*
- S - *Shift*
Now it is required to define the *binding* with the following structure:
map <A-a> shortcut_function
map <C-a> shortcut_function
Special keys
zathura allows it also to assign keys like the space bar or the tab
button which also have to be written in between angle brackets. The
following special keys are currently available:
| Identifier | Description |
| BackSpace | *Back space* |
| CapsLock | *Caps lock* |