mirror of
https://git.pwmt.org/pwmt/zathura.git
synced 2024-12-25 21:16:01 +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
|
||||
===================
|
||||
|
||||
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::
|
||||
:maxdepth: 1
|
||||
|
||||
plugin-development
|
||||
:maxdepth: 2
|
||||
:hidden:
|
||||
|
||||
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