mirror of
https://git.pwmt.org/pwmt/zathura.git
synced 2024-12-26 09:06:02 +01:00
Add plugin development documentation
This commit is contained in:
parent
6ee14a8fc8
commit
7651bc3d77
3 changed files with 285 additions and 3 deletions
|
@ -1,9 +1,20 @@
|
||||||
API and Development
|
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
|
||||||
|
it.
|
||||||
|
|
||||||
|
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::
|
.. toctree::
|
||||||
:maxdepth: 1
|
:maxdepth: 2
|
||||||
|
:hidden:
|
||||||
plugin-development
|
|
||||||
|
|
||||||
|
plugin
|
||||||
|
|
||||||
|
|
245
doc/api/plugin-development.rst
Normal file
245
doc/api/plugin-development.rst
Normal file
|
@ -0,0 +1,245 @@
|
||||||
|
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.
|
||||||
|
|
||||||
|
Prerequisites
|
||||||
|
~~~~~~~~~~~~~
|
||||||
|
|
||||||
|
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.
|
||||||
|
|
||||||
|
::
|
||||||
|
|
||||||
|
ZATHURA_PLUGIN_REGISTER(
|
||||||
|
"plugin-tutorial",
|
||||||
|
0, 1, 0,
|
||||||
|
register_functions,
|
||||||
|
ZATHURA_PLUGIN_MIMETYPES({
|
||||||
|
"application/pdf"
|
||||||
|
})
|
||||||
|
)
|
||||||
|
|
||||||
|
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:
|
||||||
|
|
||||||
|
::
|
||||||
|
|
||||||
|
void
|
||||||
|
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:
|
||||||
|
|
||||||
|
::
|
||||||
|
|
||||||
|
zathura_error_t
|
||||||
|
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);
|
||||||
|
g_free(uri);
|
||||||
|
|
||||||
|
if (poppler_document == NULL) {
|
||||||
|
return ZATHURA_ERROR_UNKNOWN;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 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);
|
||||||
|
|
||||||
|
return ZATHURA_ERROR_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
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:
|
||||||
|
|
||||||
|
::
|
||||||
|
|
||||||
|
zathura_error_t
|
||||||
|
plugin_document_free(zathura_document_t* document, PopplerDocument* poppler_document)
|
||||||
|
{
|
||||||
|
g_object_unref(poppler_document);
|
||||||
|
|
||||||
|
return ZATHURA_ERROR_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
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:
|
||||||
|
|
||||||
|
::
|
||||||
|
|
||||||
|
zathura_error_t
|
||||||
|
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);
|
||||||
|
|
||||||
|
return ZATHURA_ERROR_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
And we have to make sure that all requested resources are freed in the
|
||||||
|
end:
|
||||||
|
|
||||||
|
::
|
||||||
|
|
||||||
|
zathura_error_t
|
||||||
|
plugin_page_clear(zathura_page_t* page, PopplerPage* poppler_page)
|
||||||
|
{
|
||||||
|
g_object_unref(poppler_page);
|
||||||
|
|
||||||
|
return ZATHURA_ERROR_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
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:
|
||||||
|
|
||||||
|
::
|
||||||
|
|
||||||
|
zathura_error_t
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
|
||||||
|
return ZATHURA_ERROR_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
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 *common.mk* and
|
||||||
|
*config.mk* 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.so pdf.c
|
||||||
|
|
||||||
|
After that you have to copy the *pdf.so* file into the directory where
|
||||||
|
zathura looks for plugins (this is by default: */usr/lib/zathura*).
|
26
doc/api/plugin.rst
Normal file
26
doc/api/plugin.rst
Normal file
|
@ -0,0 +1,26 @@
|
||||||
|
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::
|
||||||
|
|
||||||
|
plugin-development
|
Loading…
Reference in a new issue