diff --git a/Makefile b/Makefile index b039fef..81a5e87 100644 --- a/Makefile +++ b/Makefile @@ -6,7 +6,7 @@ include common.mk PROJECT = zathura OSOURCE = $(wildcard *.c) HEADER = $(wildcard *.h) -HEADERINST = version.h zathura.h document.h macros.h page.h types.h +HEADERINST = version.h zathura.h document.h macros.h page.h types.h plugin-api.h ifneq (${WITH_SQLITE},0) INCS += $(SQLITE_INC) diff --git a/commands.c b/commands.c index 4876c21..80192bd 100644 --- a/commands.c +++ b/commands.c @@ -302,7 +302,7 @@ cmd_search(girara_session_t* session, const char* input, girara_argument_t* argu } bool firsthit = true; - zathura_plugin_error_t error = ZATHURA_PLUGIN_ERROR_OK; + zathura_error_t error = ZATHURA_ERROR_OK; for (unsigned int page_id = 0; page_id < zathura->document->number_of_pages; ++page_id) { zathura_page_t* page = zathura->document->pages[(page_id + zathura->document->current_page_number) % zathura->document->number_of_pages]; @@ -318,7 +318,7 @@ cmd_search(girara_session_t* session, const char* input, girara_argument_t* argu girara_list_free(result); g_object_set(page_widget, "search-results", NULL, NULL); - if (error == ZATHURA_PLUGIN_ERROR_NOT_IMPLEMENTED) { + if (error == ZATHURA_ERROR_NOT_IMPLEMENTED) { break; } else { continue; diff --git a/document.c b/document.c index 303062e..510ae71 100644 --- a/document.c +++ b/document.c @@ -8,11 +8,16 @@ #include #include #include -#include #include #include #include +#include +#include +#include +#include +#include + #include "document.h" #include "utils.h" #include "zathura.h" @@ -20,237 +25,12 @@ #include "database.h" #include "page.h" #include "page-widget.h" - -#include -#include -#include -#include -#include +#include "plugin.h" /** Read a most GT_MAX_READ bytes before falling back to file. */ static const size_t GT_MAX_READ = 1 << 16; -/** - * Register document plugin - */ -static bool zathura_document_plugin_register(zathura_t* zathura, zathura_document_plugin_t* new_plugin); - -void -zathura_document_plugins_load(zathura_t* zathura) -{ - GIRARA_LIST_FOREACH(zathura->plugins.path, char*, iter, plugindir) - /* read all files in the plugin directory */ - GDir* dir = g_dir_open(plugindir, 0, NULL); - if (dir == NULL) { - girara_error("could not open plugin directory: %s", plugindir); - girara_list_iterator_next(iter); - continue; - } - - char* name = NULL; - while ((name = (char*) g_dir_read_name(dir)) != NULL) { - char* path = g_build_filename(plugindir, name, NULL); - if (g_file_test(path, G_FILE_TEST_IS_REGULAR) == 0) { - girara_info("%s is not a regular file. Skipping.", path); - g_free(path); - continue; - } - - void* handle = NULL; - zathura_document_plugin_t* plugin = NULL; - - /* load plugin */ - handle = dlopen(path, RTLD_NOW); - if (handle == NULL) { - girara_error("could not load plugin %s (%s)", path, dlerror()); - g_free(path); - continue; - } - - /* resolve symbols and check API and ABI version*/ - zathura_plugin_api_version_t api_version; - *(void**)(&api_version) = dlsym(handle, PLUGIN_API_VERSION_FUNCTION); - if (api_version != NULL) { - if (api_version() != ZATHURA_API_VERSION) { - girara_error("plugin %s has been built againt zathura with a different API version (plugin: %d, zathura: %d)", - path, api_version(), ZATHURA_API_VERSION); - g_free(path); - dlclose(handle); - continue; - } - } else { -#if ZATHURA_API_VERSION == 1 - girara_warning("could not find '%s' function in plugin %s ... loading anyway", PLUGIN_API_VERSION_FUNCTION, path); -#else - girara_error("could not find '%s' function in plugin %s", PLUGIN_API_VERSION_FUNCTION, path); - g_free(path); - dlclose(handle); - continue; -#endif - } - - zathura_plugin_abi_version_t abi_version; - *(void**)(&abi_version) = dlsym(handle, PLUGIN_ABI_VERSION_FUNCTION); - if (abi_version != NULL) { - if (abi_version() != ZATHURA_ABI_VERSION) { - girara_error("plugin %s has been built againt zathura with a different ABI version (plugin: %d, zathura: %d)", - path, abi_version(), ZATHURA_ABI_VERSION); - g_free(path); - dlclose(handle); - continue; - } - } else { -#if ZATHURA_API_VERSION == 1 - girara_warning("could not find '%s' function in plugin %s ... loading anyway", PLUGIN_ABI_VERSION_FUNCTION, path); -#else - girara_error("could not find '%s' function in plugin %s", PLUGIN_ABI_VERSION_FUNCTION, path); - g_free(path); - dlclose(handle); - continue; -#endif - } - - zathura_plugin_register_service_t register_plugin; - *(void**)(®ister_plugin) = dlsym(handle, PLUGIN_REGISTER_FUNCTION); - - if (register_plugin == NULL) { - girara_error("could not find '%s' function in plugin %s", PLUGIN_REGISTER_FUNCTION, path); - g_free(path); - dlclose(handle); - continue; - } - - plugin = g_malloc0(sizeof(zathura_document_plugin_t)); - plugin->content_types = girara_list_new2(g_free); - plugin->handle = handle; - - register_plugin(plugin); - - bool r = zathura_document_plugin_register(zathura, plugin); - - if (r == false) { - girara_error("could not register plugin %s", path); - zathura_document_plugin_free(plugin); - } else { - girara_info("successfully loaded plugin %s", path); - } - - g_free(path); - } - g_dir_close(dir); - GIRARA_LIST_FOREACH_END(zathura->plugins.path, char*, iter, plugindir); -} - -void -zathura_document_plugin_free(zathura_document_plugin_t* plugin) -{ - if (plugin == NULL) { - return; - } - - dlclose(plugin->handle); - girara_list_free(plugin->content_types); - g_free(plugin); -} - -static bool -zathura_document_plugin_register(zathura_t* zathura, zathura_document_plugin_t* new_plugin) -{ - if (new_plugin == NULL || new_plugin->content_types == NULL || new_plugin->open_function == NULL) { - girara_error("plugin: could not register\n"); - return false; - } - - bool atleastone = false; - GIRARA_LIST_FOREACH(new_plugin->content_types, gchar*, iter, type) - if (!zathura_type_plugin_mapping_new(zathura, type, new_plugin)) { - girara_error("plugin: already registered for filetype %s\n", type); - } else { - atleastone = true; - } - GIRARA_LIST_FOREACH_END(new_plugin->content_types, gchar*, iter, type); - - if (atleastone) { - girara_list_append(zathura->plugins.plugins, new_plugin); - } - return atleastone; -} - -static const gchar* -guess_type(const char* path) -{ - gboolean uncertain; - const gchar* content_type = g_content_type_guess(path, NULL, 0, &uncertain); - if (content_type == NULL) { - return NULL; - } - - if (uncertain == FALSE) { - return content_type; - } - - girara_debug("g_content_type is uncertain, guess: %s\n", content_type); - - FILE* f = fopen(path, "rb"); - if (f == NULL) { - return NULL; - } - - const int fd = fileno(f); - guchar* content = NULL; - size_t length = 0u; - while (uncertain == TRUE && length < GT_MAX_READ) { - g_free((void*)content_type); - content_type = NULL; - - content = g_realloc(content, length + BUFSIZ); - const ssize_t r = read(fd, content + length, BUFSIZ); - if (r == -1) { - break; - } - - length += r; - content_type = g_content_type_guess(NULL, content, length, &uncertain); - girara_debug("new guess: %s uncertain: %d, read: %zu\n", content_type, uncertain, length); - } - - fclose(f); - g_free(content); - if (uncertain == FALSE) { - return content_type; - } - - g_free((void*)content_type); - content_type = NULL; - - girara_debug("falling back to file"); - - GString* command = g_string_new("file -b --mime-type "); - char* tmp = g_shell_quote(path); - - g_string_append(command, tmp); - g_free(tmp); - - GError* error = NULL; - char* out = NULL; - int ret = 0; - g_spawn_command_line_sync(command->str, &out, NULL, &ret, &error); - g_string_free(command, TRUE); - if (error != NULL) { - girara_warning("failed to execute command: %s", error->message); - g_error_free(error); - g_free(out); - return NULL; - } - if (WEXITSTATUS(ret) != 0) { - girara_warning("file failed with error code: %d", WEXITSTATUS(ret)); - g_free(out); - return NULL; - } - - g_strdelimit(out, "\n\r", '\0'); - return out; -} +static const gchar* guess_type(const char* path); zathura_document_t* zathura_document_open(zathura_t* zathura, const char* path, const char* password) @@ -295,7 +75,7 @@ zathura_document_open(zathura_t* zathura, const char* path, const char* password return NULL; } - zathura_document_plugin_t* plugin = NULL; + zathura_plugin_t* plugin = NULL; GIRARA_LIST_FOREACH(zathura->plugins.type_plugin_mapping, zathura_type_plugin_mapping_t*, iter, mapping) if (g_content_type_equals(content_type, mapping->type)) { plugin = mapping->plugin; @@ -311,20 +91,21 @@ zathura_document_open(zathura_t* zathura, const char* path, const char* password document = g_malloc0(sizeof(zathura_document_t)); - document->file_path = real_path; - document->password = password; - document->scale = 1.0; - document->zathura = zathura; + document->file_path = real_path; + document->password = password; + document->scale = 1.0; + document->zathura = zathura; + document->plugin = plugin; /* open document */ - if (plugin->open_function == NULL) { + if (plugin->functions.document_open == NULL) { girara_error("plugin has no open function\n"); goto error_free; } - zathura_plugin_error_t error = plugin->open_function(document); - if (error != ZATHURA_PLUGIN_ERROR_OK) { - if (error == ZATHURA_PLUGIN_ERROR_INVALID_PASSWORD) { + zathura_error_t error = plugin->functions.document_open(document); + if (error != ZATHURA_ERROR_OK) { + if (error == ZATHURA_ERROR_INVALID_PASSWORD) { zathura_password_dialog_info_t* password_dialog_info = malloc(sizeof(zathura_password_dialog_info_t)); if (password_dialog_info != NULL) { password_dialog_info->path = g_strdup(path); @@ -419,11 +200,12 @@ error_free: return NULL; } -zathura_plugin_error_t +zathura_error_t zathura_document_free(zathura_document_t* document) { - if (document == NULL || document->zathura == NULL || document->zathura->ui.session == NULL) { - return ZATHURA_PLUGIN_ERROR_INVALID_ARGUMENTS; + if (document == NULL || document->plugin == NULL || document->zathura == NULL + || document->zathura->ui.session == NULL) { + return ZATHURA_ERROR_INVALID_ARGUMENTS; } /* free pages */ @@ -435,13 +217,13 @@ zathura_document_free(zathura_document_t* document) free(document->pages); /* free document */ - zathura_plugin_error_t error = ZATHURA_PLUGIN_ERROR_OK; - if (document->functions.document_free == NULL) { + zathura_error_t error = ZATHURA_ERROR_OK; + if (document->plugin->functions.document_free == NULL) { girara_notify(document->zathura->ui.session, GIRARA_WARNING, _("%s not implemented"), __FUNCTION__); girara_error("%s not implemented", __FUNCTION__); - error = ZATHURA_PLUGIN_ERROR_NOT_IMPLEMENTED; + error = ZATHURA_ERROR_NOT_IMPLEMENTED; } else { - error = document->functions.document_free(document); + error = document->plugin->functions.document_free(document); } if (document->file_path != NULL) { @@ -453,194 +235,180 @@ zathura_document_free(zathura_document_t* document) return error; } -zathura_plugin_error_t +zathura_error_t zathura_document_save_as(zathura_document_t* document, const char* path) { - if (document == NULL || path == NULL || document->zathura == NULL || document->zathura->ui.session == NULL) { - return ZATHURA_PLUGIN_ERROR_UNKNOWN; + if (document == NULL || document->plugin == NULL || path == NULL || + document->zathura == NULL || document->zathura->ui.session == NULL) { + return ZATHURA_ERROR_UNKNOWN; } - if (document->functions.document_save_as == NULL) { + if (document->plugin->functions.document_save_as == NULL) { girara_notify(document->zathura->ui.session, GIRARA_WARNING, _("%s not implemented"), __FUNCTION__); girara_error("%s not implemented", __FUNCTION__); - return ZATHURA_PLUGIN_ERROR_NOT_IMPLEMENTED; + return ZATHURA_ERROR_NOT_IMPLEMENTED; } - return document->functions.document_save_as(document, path); + return document->plugin->functions.document_save_as(document, path); } girara_tree_node_t* -zathura_document_index_generate(zathura_document_t* document, zathura_plugin_error_t* error) +zathura_document_index_generate(zathura_document_t* document, zathura_error_t* error) { - if (document == NULL || document->zathura == NULL || document->zathura->ui.session == NULL) { + if (document == NULL || document->plugin == NULL || document->zathura == NULL + || document->zathura->ui.session == NULL) { if (error != NULL) { - *error = ZATHURA_PLUGIN_ERROR_INVALID_ARGUMENTS; + *error = ZATHURA_ERROR_INVALID_ARGUMENTS; } return NULL; } - if (document->functions.document_index_generate == NULL) { + if (document->plugin->functions.document_index_generate == NULL) { girara_notify(document->zathura->ui.session, GIRARA_WARNING, _("%s not implemented"), __FUNCTION__); girara_error("%s not implemented", __FUNCTION__); if (error != NULL) { - *error = ZATHURA_PLUGIN_ERROR_NOT_IMPLEMENTED; + *error = ZATHURA_ERROR_NOT_IMPLEMENTED; } return NULL; } - return document->functions.document_index_generate(document, error); + return document->plugin->functions.document_index_generate(document, error); } girara_list_t* -zathura_document_attachments_get(zathura_document_t* document, zathura_plugin_error_t* error) +zathura_document_attachments_get(zathura_document_t* document, zathura_error_t* error) { - if (document == NULL || document->zathura == NULL || document->zathura->ui.session == NULL) { + if (document == NULL || document->plugin == NULL || document->zathura == NULL + || document->zathura->ui.session == NULL) { if (error != NULL) { - *error = ZATHURA_PLUGIN_ERROR_INVALID_ARGUMENTS; + *error = ZATHURA_ERROR_INVALID_ARGUMENTS; } return NULL; } - if (document->functions.document_attachments_get == NULL) { + if (document->plugin->functions.document_attachments_get == NULL) { girara_notify(document->zathura->ui.session, GIRARA_WARNING, _("%s not implemented"), __FUNCTION__); girara_error("%s not implemented", __FUNCTION__); if (error != NULL) { - *error = ZATHURA_PLUGIN_ERROR_NOT_IMPLEMENTED; + *error = ZATHURA_ERROR_NOT_IMPLEMENTED; } return NULL; } - return document->functions.document_attachments_get(document, error); + return document->plugin->functions.document_attachments_get(document, error); } -zathura_plugin_error_t +zathura_error_t zathura_document_attachment_save(zathura_document_t* document, const char* attachment, const char* file) { - if (document == NULL || document->zathura == NULL || document->zathura->ui.session == NULL) { - return ZATHURA_PLUGIN_ERROR_INVALID_ARGUMENTS; + if (document == NULL || document->plugin == NULL || document->zathura == NULL + || document->zathura->ui.session == NULL) { + return ZATHURA_ERROR_INVALID_ARGUMENTS; } - if (document->functions.document_attachment_save == NULL) { + if (document->plugin->functions.document_attachment_save == NULL) { girara_notify(document->zathura->ui.session, GIRARA_WARNING, _("%s not implemented"), __FUNCTION__); girara_error("%s not implemented", __FUNCTION__); - return ZATHURA_PLUGIN_ERROR_NOT_IMPLEMENTED; + return ZATHURA_ERROR_NOT_IMPLEMENTED; } - return document->functions.document_attachment_save(document, attachment, file); + return document->plugin->functions.document_attachment_save(document, attachment, file); } char* -zathura_document_meta_get(zathura_document_t* document, zathura_document_meta_t meta, zathura_plugin_error_t* error) +zathura_document_meta_get(zathura_document_t* document, zathura_document_meta_t meta, zathura_error_t* error) { - if (document == NULL || document->zathura == NULL || document->zathura->ui.session == NULL) { + if (document == NULL || document->plugin == NULL || document->zathura == NULL || document->zathura->ui.session == NULL) { if (error != NULL) { - *error = ZATHURA_PLUGIN_ERROR_INVALID_ARGUMENTS; + *error = ZATHURA_ERROR_INVALID_ARGUMENTS; } return NULL; } - if (document->functions.document_meta_get == NULL) { + if (document->plugin->functions.document_meta_get == NULL) { if (error != NULL) { - *error = ZATHURA_PLUGIN_ERROR_NOT_IMPLEMENTED; + *error = ZATHURA_ERROR_NOT_IMPLEMENTED; } girara_notify(document->zathura->ui.session, GIRARA_WARNING, _("%s not implemented"), __FUNCTION__); girara_error("%s not implemented", __FUNCTION__); return NULL; } - return document->functions.document_meta_get(document, meta, error); + return document->plugin->functions.document_meta_get(document, meta, error); } -zathura_index_element_t* -zathura_index_element_new(const char* title) +static const gchar* +guess_type(const char* path) { - if (title == NULL) { + gboolean uncertain; + const gchar* content_type = g_content_type_guess(path, NULL, 0, &uncertain); + if (content_type == NULL) { return NULL; } - zathura_index_element_t* res = g_malloc0(sizeof(zathura_index_element_t)); - - res->title = g_strdup(title); - - return res; -} - -void -zathura_index_element_free(zathura_index_element_t* index) -{ - if (index == NULL) { - return; + if (uncertain == FALSE) { + return content_type; } - g_free(index->title); + girara_debug("g_content_type is uncertain, guess: %s\n", content_type); - if (index->type == ZATHURA_LINK_EXTERNAL) { - g_free(index->target.uri); - } - - g_free(index); -} - -zathura_image_buffer_t* -zathura_image_buffer_create(unsigned int width, unsigned int height) -{ - zathura_image_buffer_t* image_buffer = malloc(sizeof(zathura_image_buffer_t)); - - if (image_buffer == NULL) { + FILE* f = fopen(path, "rb"); + if (f == NULL) { return NULL; } - image_buffer->data = calloc(width * height * 3, sizeof(unsigned char)); + const int fd = fileno(f); + guchar* content = NULL; + size_t length = 0u; + while (uncertain == TRUE && length < GT_MAX_READ) { + g_free((void*)content_type); + content_type = NULL; - if (image_buffer->data == NULL) { - free(image_buffer); - return NULL; - } - - image_buffer->width = width; - image_buffer->height = height; - image_buffer->rowstride = width * 3; - - return image_buffer; -} - -void -zathura_image_buffer_free(zathura_image_buffer_t* image_buffer) -{ - if (image_buffer == NULL) { - return; - } - - free(image_buffer->data); - free(image_buffer); -} - -bool -zathura_type_plugin_mapping_new(zathura_t* zathura, const gchar* type, zathura_document_plugin_t* plugin) -{ - g_return_val_if_fail(zathura && type && plugin, false); - - GIRARA_LIST_FOREACH(zathura->plugins.type_plugin_mapping, zathura_type_plugin_mapping_t*, iter, mapping) - if (g_content_type_equals(type, mapping->type)) { - girara_list_iterator_free(iter); - return false; + content = g_realloc(content, length + BUFSIZ); + const ssize_t r = read(fd, content + length, BUFSIZ); + if (r == -1) { + break; } - GIRARA_LIST_FOREACH_END(zathura->plugins.type_plugin_mapping, zathura_type_plugin_mapping_t*, iter, mapping); - zathura_type_plugin_mapping_t* mapping = g_malloc(sizeof(zathura_type_plugin_mapping_t)); - mapping->type = g_strdup(type); - mapping->plugin = plugin; - girara_list_append(zathura->plugins.type_plugin_mapping, mapping); - return true; -} - -void -zathura_type_plugin_mapping_free(zathura_type_plugin_mapping_t* mapping) -{ - if (mapping == NULL) { - return; + length += r; + content_type = g_content_type_guess(NULL, content, length, &uncertain); + girara_debug("new guess: %s uncertain: %d, read: %zu\n", content_type, uncertain, length); } - g_free((void*)mapping->type); - g_free(mapping); + fclose(f); + g_free(content); + if (uncertain == FALSE) { + return content_type; + } + + g_free((void*)content_type); + content_type = NULL; + + girara_debug("falling back to file"); + + GString* command = g_string_new("file -b --mime-type "); + char* tmp = g_shell_quote(path); + + g_string_append(command, tmp); + g_free(tmp); + + GError* error = NULL; + char* out = NULL; + int ret = 0; + g_spawn_command_line_sync(command->str, &out, NULL, &ret, &error); + g_string_free(command, TRUE); + if (error != NULL) { + girara_warning("failed to execute command: %s", error->message); + g_error_free(error); + g_free(out); + return NULL; + } + if (WEXITSTATUS(ret) != 0) { + girara_warning("file failed with error code: %d", WEXITSTATUS(ret)); + g_free(out); + return NULL; + } + + g_strdelimit(out, "\n\r", '\0'); + return out; } diff --git a/document.h b/document.h index 73d5081..adcf80c 100644 --- a/document.h +++ b/document.h @@ -6,87 +6,11 @@ #include #include #include - #include + #include "zathura.h" -#include "version.h" #include "types.h" -#define PLUGIN_REGISTER_FUNCTION "plugin_register" -#define PLUGIN_API_VERSION_FUNCTION "plugin_api_version" -#define PLUGIN_ABI_VERSION_FUNCTION "plugin_abi_version" - -/** - * Register a plugin. - * - * @param plugin_name the name of the plugin - * @param major the plugin's major version - * @param minor the plugin's minor version - * @param rev the plugin's revision - * @param plugin_open_function the plugin's open function - * @param mimetypes a char array of mime types supported by the plugin - */ -#define PLUGIN_REGISTER(plugin_name, major, minor, rev, plugin_open_function, mimetypes) \ - unsigned int plugin_version_major() { return major; } \ - unsigned int plugin_version_minor() { return minor; } \ - unsigned int plugin_version_revision() { return rev; } \ - unsigned int plugin_api_version() { return ZATHURA_API_VERSION; } \ - unsigned int plugin_abi_version() { return ZATHURA_ABI_VERSION; } \ - \ - void plugin_register(zathura_document_plugin_t* plugin) \ - { \ - if (plugin == NULL) { \ - return; \ - } \ - plugin->open_function = (plugin_open_function); \ - static const char* mime_types[] = mimetypes; \ - for (size_t s = 0; s != sizeof(mime_types) / sizeof(const char*); ++s) { \ - girara_list_append(plugin->content_types, g_content_type_from_mime_type(mime_types[s])); \ - } \ - } \ - -#define PLUGIN_MIMETYPES(...) __VA_ARGS__ - -/** - * Error types for plugins - */ -typedef enum zathura_plugin_error_e -{ - ZATHURA_PLUGIN_ERROR_OK, /**< No error occured */ - ZATHURA_PLUGIN_ERROR_UNKNOWN, /**< An unknown error occured */ - ZATHURA_PLUGIN_ERROR_OUT_OF_MEMORY, /**< Out of memory */ - ZATHURA_PLUGIN_ERROR_NOT_IMPLEMENTED, /**< The called function has not been implemented */ - ZATHURA_PLUGIN_ERROR_INVALID_ARGUMENTS, /**< Invalid arguments have been passed */ - ZATHURA_PLUGIN_ERROR_INVALID_PASSWORD /**< The provided password is invalid */ -} zathura_plugin_error_t; - -/** - * Document open function - * - * @param document The document - * @return true if no error occured otherwise false - */ -typedef zathura_plugin_error_t (*zathura_document_open_t)(zathura_document_t* document); - -/** - * Document plugin structure - */ -typedef struct zathura_document_plugin_s -{ - girara_list_t* content_types; /**< List of supported content types */ - zathura_document_open_t open_function; /**< Document open function */ - void* handle; /**< DLL handle */ -} zathura_document_plugin_t; - -/** - * Plugin mapping - */ -typedef struct zathura_type_plugin_mapping_s -{ - const gchar* type; /**< Plugin type */ - zathura_document_plugin_t* plugin; /**< Mapped plugin */ -} zathura_type_plugin_mapping_t; - /** * Meta data entries */ @@ -108,28 +32,6 @@ typedef struct zathura_password_dialog_info_s zathura_t* zathura; /**< Zathura session */ } zathura_password_dialog_info_t; -/** - * Function prototype that is called to register a document plugin - * - * @param The document plugin - */ -typedef void (*zathura_plugin_register_service_t)(zathura_document_plugin_t*); - -/** - * Function prototype that is called to get the plugin's API version. - * - * @return plugin's API version - */ -typedef unsigned int (*zathura_plugin_api_version_t)(); - -/** - * Function prototype that is called to get the ABI version the plugin is built - * against. - * - * @return plugin's ABI version - */ -typedef unsigned int (*zathura_plugin_abi_version_t)(); - /** * Document */ @@ -146,109 +48,17 @@ struct zathura_document_s int adjust_mode; /**< Adjust mode (best-fit, width) */ unsigned int page_offset; /**< Page offset */ - struct - { - /** - * Frees the document - */ - zathura_plugin_error_t (*document_free)(zathura_document_t* document); - - /** - * Generates the document index - */ - girara_tree_node_t* (*document_index_generate)(zathura_document_t* document, zathura_plugin_error_t* error); - - /** - * Save the document - */ - zathura_plugin_error_t (*document_save_as)(zathura_document_t* document, const char* path); - - /** - * Get list of attachments - */ - girara_list_t* (*document_attachments_get)(zathura_document_t* document, zathura_plugin_error_t* error); - - /** - * Save attachment to a file - */ - zathura_plugin_error_t (*document_attachment_save)(zathura_document_t* document, const char* attachment, const char* file); - - /** - * Get document information - */ - char* (*document_meta_get)(zathura_document_t* document, zathura_document_meta_t info, zathura_plugin_error_t* error); - - /** - * Gets the page object - */ - zathura_plugin_error_t (*page_init)(zathura_page_t* page); - - /** - * Free page - */ - zathura_plugin_error_t (*page_clear)(zathura_page_t* page); - - /** - * Search text - */ - girara_list_t* (*page_search_text)(zathura_page_t* page, const char* text, zathura_plugin_error_t* error); - - /** - * Get links on a page - */ - girara_list_t* (*page_links_get)(zathura_page_t* page, zathura_plugin_error_t* error); - - /** - * Get form fields - */ - girara_list_t* (*page_form_fields_get)(zathura_page_t* page, zathura_plugin_error_t* error); - - /** - * Get list of images - */ - girara_list_t* (*page_images_get)(zathura_page_t* page, zathura_plugin_error_t* error); - - /** - * Get the image - */ - cairo_surface_t* (*page_image_get_cairo)(zathura_page_t* page, zathura_image_t* image, zathura_plugin_error_t* error); - - /** - * Get text for selection - */ - char* (*page_get_text)(zathura_page_t* page, zathura_rectangle_t rectangle, zathura_plugin_error_t* error); - - /** - * Renders the page - */ - zathura_image_buffer_t* (*page_render)(zathura_page_t* page, zathura_plugin_error_t* error); - - /** - * Renders the page - */ - zathura_plugin_error_t (*page_render_cairo)(zathura_page_t* page, cairo_t* cairo, bool printing); - } functions; - /** * Document pages */ zathura_page_t** pages; + + /** + * Used plugin + */ + zathura_plugin_t* plugin; }; -/** - * Load all document plugins - * - * @param zathura the zathura session - */ -void zathura_document_plugins_load(zathura_t* zathura); - -/** - * Free a document plugin - * - * @param plugin The plugin - */ -void zathura_document_plugin_free(zathura_document_plugin_t* plugin); - /** * Open the document * @@ -264,41 +74,41 @@ zathura_document_t* zathura_document_open(zathura_t* zathura, const char* path, * Free the document * * @param document - * @return ZATHURA_PLUGIN_ERROR_OK when no error occured, otherwise see - * zathura_plugin_error_t + * @return ZATHURA_ERROR_OK when no error occured, otherwise see + * zathura_error_t */ -zathura_plugin_error_t zathura_document_free(zathura_document_t* document); +zathura_error_t zathura_document_free(zathura_document_t* document); /** * Save the document * * @param document The document object * @param path Path for the saved file - * @return ZATHURA_PLUGIN_ERROR_OK when no error occured, otherwise see - * zathura_plugin_error_t + * @return ZATHURA_ERROR_OK when no error occured, otherwise see + * zathura_error_t */ -zathura_plugin_error_t zathura_document_save_as(zathura_document_t* document, const char* path); +zathura_error_t zathura_document_save_as(zathura_document_t* document, const char* path); /** * Generate the document index * * @param document The document object - * @param error Set to an error value (see \ref zathura_plugin_error_t) if an + * @param error Set to an error value (see \ref zathura_error_t) if an * error occured * @return Generated index */ -girara_tree_node_t* zathura_document_index_generate(zathura_document_t* document, zathura_plugin_error_t* error); +girara_tree_node_t* zathura_document_index_generate(zathura_document_t* document, zathura_error_t* error); /** * Get list of attachments * * @param document The document object - * @param error Set to an error value (see \ref zathura_plugin_error_t) if an + * @param error Set to an error value (see \ref zathura_error_t) if an * error occured * @return List of attachments */ -girara_list_t* zathura_document_attachments_get(zathura_document_t* document, zathura_plugin_error_t* error); +girara_list_t* zathura_document_attachments_get(zathura_document_t* document, zathura_error_t* error); /** * Save document attachment @@ -306,36 +116,20 @@ girara_list_t* zathura_document_attachments_get(zathura_document_t* document, za * @param document The document objects * @param attachment name of the attachment * @param file the target filename - * @return ZATHURA_PLUGIN_ERROR_OK when no error occured, otherwise see - * zathura_plugin_error_t + * @return ZATHURA_ERROR_OK when no error occured, otherwise see + * zathura_error_t */ -zathura_plugin_error_t zathura_document_attachment_save(zathura_document_t* document, const char* attachment, const char* file); +zathura_error_t zathura_document_attachment_save(zathura_document_t* document, const char* attachment, const char* file); /** * Returns a string of the requested information * * @param document The zathura document * @param meta The information field - * @param error Set to an error value (see \ref zathura_plugin_error_t) if an + * @param error Set to an error value (see \ref zathura_error_t) if an * error occured * @return String or NULL if information could not be retreived */ -char* zathura_document_meta_get(zathura_document_t* document, zathura_document_meta_t meta, zathura_plugin_error_t* error); - -/** - * Add type -> plugin mapping - * @param zathura zathura instance - * @param type content type - * @param plugin plugin instance - * @return true on success, false if another plugin is already registered for - * that type - */ -bool zathura_type_plugin_mapping_new(zathura_t* zathura, const gchar* type, zathura_document_plugin_t* plugin); - -/** - * Free type -> plugin mapping - * @param mapping To be freed - */ -void zathura_type_plugin_mapping_free(zathura_type_plugin_mapping_t* mapping); +char* zathura_document_meta_get(zathura_document_t* document, zathura_document_meta_t meta, zathura_error_t* error); #endif // DOCUMENT_H diff --git a/page.c b/page.c index 7db963e..6f9de95 100644 --- a/page.c +++ b/page.c @@ -7,6 +7,7 @@ #include "document.h" #include "page.h" #include "page-widget.h" +#include "plugin.h" #include "utils.h" struct zathura_page_s { @@ -20,11 +21,12 @@ struct zathura_page_s { }; zathura_page_t* -zathura_page_new(zathura_document_t* document, unsigned int index, zathura_plugin_error_t* error) +zathura_page_new(zathura_document_t* document, unsigned int index, zathura_error_t* error) { - if (document == NULL || document->zathura == NULL || document->zathura->ui.session == NULL) { + if (document == NULL || document->plugin == NULL || document->zathura == NULL + || document->zathura->ui.session == NULL) { if (error != NULL) { - *error = ZATHURA_PLUGIN_ERROR_INVALID_ARGUMENTS; + *error = ZATHURA_ERROR_INVALID_ARGUMENTS; } goto error_ret; } @@ -39,23 +41,23 @@ zathura_page_new(zathura_document_t* document, unsigned int index, zathura_plugi if (page->widget == NULL) { if (error != NULL) { - *error = ZATHURA_PLUGIN_ERROR_UNKNOWN; + *error = ZATHURA_ERROR_UNKNOWN; } goto error_free; } /* init plugin */ - if (document->functions.page_init == NULL) { + if (document->plugin->functions.page_init == NULL) { if (error != NULL) { girara_notify(page->document->zathura->ui.session, GIRARA_WARNING, _("%s not implemented"), __FUNCTION__); girara_error("%s not implemented", __FUNCTION__); - *error = ZATHURA_PLUGIN_ERROR_NOT_IMPLEMENTED; + *error = ZATHURA_ERROR_NOT_IMPLEMENTED; } goto error_ret; } - zathura_plugin_error_t ret = document->functions.page_init(page); - if (ret != ZATHURA_PLUGIN_ERROR_OK) { + zathura_error_t ret = document->plugin->functions.page_init(page); + if (ret != ZATHURA_ERROR_OK) { if (error != NULL) { *error = ret; } @@ -82,25 +84,26 @@ error_ret: return NULL; } -zathura_plugin_error_t +zathura_error_t zathura_page_free(zathura_page_t* page) { if (page == NULL) { - return ZATHURA_PLUGIN_ERROR_INVALID_ARGUMENTS; + return ZATHURA_ERROR_INVALID_ARGUMENTS; } - if (page->document == NULL || page->document->zathura == NULL || page->document->zathura->ui.session == NULL) { + if (page->document == NULL || page->document->plugin == NULL || + page->document->zathura == NULL || page->document->zathura->ui.session == NULL) { g_free(page); - return ZATHURA_PLUGIN_ERROR_INVALID_ARGUMENTS; + return ZATHURA_ERROR_INVALID_ARGUMENTS; } - if (page->document->functions.page_clear == NULL) { + if (page->document->plugin->functions.page_clear == NULL) { girara_notify(page->document->zathura->ui.session, GIRARA_WARNING, _("%s not implemented"), __FUNCTION__); girara_error("%s not implemented", __FUNCTION__); - return ZATHURA_PLUGIN_ERROR_NOT_IMPLEMENTED; + return ZATHURA_ERROR_NOT_IMPLEMENTED; } - zathura_plugin_error_t error = page->document->functions.page_clear(page); + zathura_error_t error = page->document->plugin->functions.page_clear(page); g_free(page); @@ -218,168 +221,170 @@ zathura_page_set_data(zathura_page_t* page, void* data) } girara_list_t* -zathura_page_search_text(zathura_page_t* page, const char* text, zathura_plugin_error_t* error) +zathura_page_search_text(zathura_page_t* page, const char* text, zathura_error_t* error) { - if (page == NULL || page->document == NULL || text == NULL || + if (page == NULL || page->document == NULL || page->document->plugin == NULL || text == NULL || page->document->zathura == NULL || page->document->zathura->ui.session == NULL) { if (error != NULL) { - *error = ZATHURA_PLUGIN_ERROR_INVALID_ARGUMENTS; + *error = ZATHURA_ERROR_INVALID_ARGUMENTS; } return NULL; } - if (page->document->functions.page_search_text == NULL) { + if (page->document->plugin->functions.page_search_text == NULL) { girara_notify(page->document->zathura->ui.session, GIRARA_WARNING, _("%s not implemented"), __FUNCTION__); girara_error("%s not implemented", __FUNCTION__); if (error != NULL) { - *error = ZATHURA_PLUGIN_ERROR_NOT_IMPLEMENTED; + *error = ZATHURA_ERROR_NOT_IMPLEMENTED; } return NULL; } - return page->document->functions.page_search_text(page, text, error); + return page->document->plugin->functions.page_search_text(page, text, error); } girara_list_t* -zathura_page_links_get(zathura_page_t* page, zathura_plugin_error_t* error) +zathura_page_links_get(zathura_page_t* page, zathura_error_t* error) { - if (page == NULL || page->document == NULL || page->document->zathura == NULL + if (page == NULL || page->document == NULL || page->document->plugin == NULL || page->document->zathura == NULL || page->document->zathura->ui.session == NULL) { if (error != NULL) { - *error = ZATHURA_PLUGIN_ERROR_INVALID_ARGUMENTS; + *error = ZATHURA_ERROR_INVALID_ARGUMENTS; } return NULL; } - if (page->document->functions.page_links_get == NULL) { + if (page->document->plugin->functions.page_links_get == NULL) { girara_notify(page->document->zathura->ui.session, GIRARA_WARNING, _("%s not implemented"), __FUNCTION__); girara_error("%s not implemented", __FUNCTION__); if (error != NULL) { - *error = ZATHURA_PLUGIN_ERROR_NOT_IMPLEMENTED; + *error = ZATHURA_ERROR_NOT_IMPLEMENTED; } return NULL; } - return page->document->functions.page_links_get(page, error); + return page->document->plugin->functions.page_links_get(page, error); } -zathura_plugin_error_t +zathura_error_t zathura_page_links_free(girara_list_t* UNUSED(list)) { return false; } girara_list_t* -zathura_page_form_fields_get(zathura_page_t* page, zathura_plugin_error_t* error) +zathura_page_form_fields_get(zathura_page_t* page, zathura_error_t* error) { - if (page == NULL || page->document == NULL || page->document->zathura == NULL + if (page == NULL || page->document == NULL || page->document->plugin == NULL || page->document->zathura == NULL || page->document->zathura->ui.session == NULL) { if (error != NULL) { - *error = ZATHURA_PLUGIN_ERROR_INVALID_ARGUMENTS; + *error = ZATHURA_ERROR_INVALID_ARGUMENTS; } return NULL; } - if (page->document->functions.page_form_fields_get == NULL) { + if (page->document->plugin->functions.page_form_fields_get == NULL) { girara_notify(page->document->zathura->ui.session, GIRARA_WARNING, _("%s not implemented"), __FUNCTION__); girara_error("%s not implemented", __FUNCTION__); if (error != NULL) { - *error = ZATHURA_PLUGIN_ERROR_NOT_IMPLEMENTED; + *error = ZATHURA_ERROR_NOT_IMPLEMENTED; } return NULL; } - return page->document->functions.page_form_fields_get(page, error); + return page->document->plugin->functions.page_form_fields_get(page, error); } -zathura_plugin_error_t +zathura_error_t zathura_page_form_fields_free(girara_list_t* UNUSED(list)) { - return ZATHURA_PLUGIN_ERROR_NOT_IMPLEMENTED; + return ZATHURA_ERROR_NOT_IMPLEMENTED; } girara_list_t* -zathura_page_images_get(zathura_page_t* page, zathura_plugin_error_t* error) +zathura_page_images_get(zathura_page_t* page, zathura_error_t* error) { - if (page == NULL || page->document == NULL || page->document->zathura == NULL + if (page == NULL || page->document == NULL || page->document->plugin == NULL || page->document->zathura == NULL || page->document->zathura->ui.session == NULL) { if (error != NULL) { - *error = ZATHURA_PLUGIN_ERROR_INVALID_ARGUMENTS; + *error = ZATHURA_ERROR_INVALID_ARGUMENTS; } return NULL; } - if (page->document->functions.page_images_get == NULL) { + if (page->document->plugin->functions.page_images_get == NULL) { girara_notify(page->document->zathura->ui.session, GIRARA_WARNING, _("%s not implemented"), __FUNCTION__); girara_error("%s not implemented", __FUNCTION__); if (error != NULL) { - *error = ZATHURA_PLUGIN_ERROR_NOT_IMPLEMENTED; + *error = ZATHURA_ERROR_NOT_IMPLEMENTED; } return NULL; } - return page->document->functions.page_images_get(page, error); + return page->document->plugin->functions.page_images_get(page, error); } cairo_surface_t* -zathura_page_image_get_cairo(zathura_page_t* page, zathura_image_t* image, zathura_plugin_error_t* error) +zathura_page_image_get_cairo(zathura_page_t* page, zathura_image_t* image, zathura_error_t* error) { - if (page == NULL || page->document == NULL || image == NULL || + if (page == NULL || page->document == NULL || page->document->plugin == NULL || image == NULL || page->document->zathura == NULL || page->document->zathura->ui.session == NULL) { if (error != NULL) { - *error = ZATHURA_PLUGIN_ERROR_INVALID_ARGUMENTS; + *error = ZATHURA_ERROR_INVALID_ARGUMENTS; } return NULL; } - if (page->document->functions.page_image_get_cairo == NULL) { + if (page->document->plugin->functions.page_image_get_cairo == NULL) { girara_notify(page->document->zathura->ui.session, GIRARA_WARNING, _("%s not implemented"), __FUNCTION__); girara_error("%s not implemented", __FUNCTION__); if (error != NULL) { - *error = ZATHURA_PLUGIN_ERROR_NOT_IMPLEMENTED; + *error = ZATHURA_ERROR_NOT_IMPLEMENTED; } return NULL; } - return page->document->functions.page_image_get_cairo(page, image, error); + return page->document->plugin->functions.page_image_get_cairo(page, image, error); } -char* zathura_page_get_text(zathura_page_t* page, zathura_rectangle_t rectangle, zathura_plugin_error_t* error) +char* zathura_page_get_text(zathura_page_t* page, zathura_rectangle_t rectangle, zathura_error_t* error) { - if (page == NULL || page->document == NULL || page->document->zathura == NULL || page->document->zathura->ui.session == NULL) { + if (page == NULL || page->document == NULL || page->document->plugin == NULL + || page->document->zathura == NULL || page->document->zathura->ui.session + == NULL) { if (error) { - *error = ZATHURA_PLUGIN_ERROR_INVALID_ARGUMENTS; + *error = ZATHURA_ERROR_INVALID_ARGUMENTS; } return NULL; } - if (page->document->functions.page_get_text == NULL) { + if (page->document->plugin->functions.page_get_text == NULL) { girara_notify(page->document->zathura->ui.session, GIRARA_WARNING, _("%s not implemented"), __FUNCTION__); girara_error("%s not implemented", __FUNCTION__); if (error) { - *error = ZATHURA_PLUGIN_ERROR_NOT_IMPLEMENTED; + *error = ZATHURA_ERROR_NOT_IMPLEMENTED; } return NULL; } - return page->document->functions.page_get_text(page, rectangle, error); + return page->document->plugin->functions.page_get_text(page, rectangle, error); } -zathura_plugin_error_t +zathura_error_t zathura_page_render(zathura_page_t* page, cairo_t* cairo, bool printing) { - if (page == NULL || page->document == NULL || cairo == NULL || + if (page == NULL || page->document->plugin == NULL || page->document == NULL || cairo == NULL || page->document->zathura == NULL || page->document->zathura->ui.session == NULL) { - return ZATHURA_PLUGIN_ERROR_INVALID_ARGUMENTS; + return ZATHURA_ERROR_INVALID_ARGUMENTS; } - if (page->document->functions.page_render_cairo == NULL) { + if (page->document->plugin->functions.page_render_cairo == NULL) { girara_notify(page->document->zathura->ui.session, GIRARA_WARNING, _("%s not implemented"), __FUNCTION__); girara_error("%s not implemented", __FUNCTION__); - return ZATHURA_PLUGIN_ERROR_NOT_IMPLEMENTED; + return ZATHURA_ERROR_NOT_IMPLEMENTED; } - return page->document->functions.page_render_cairo(page, cairo, printing); + return page->document->plugin->functions.page_render_cairo(page, cairo, printing); } diff --git a/page.h b/page.h index 09e9932..e4cd103 100644 --- a/page.h +++ b/page.h @@ -16,16 +16,16 @@ * @return Page object or NULL if an error occured */ zathura_page_t* zathura_page_new(zathura_document_t* document, unsigned int - index, zathura_plugin_error_t* error); + index, zathura_error_t* error); /** * Frees the page object * * @param page The page object - * @return ZATHURA_PLUGIN_ERROR_OK when no error occured, otherwise see - * zathura_plugin_error_t + * @return ZATHURA_ERROR_OK when no error occured, otherwise see + * zathura_error_t */ -zathura_plugin_error_t zathura_page_free(zathura_page_t* page); +zathura_error_t zathura_page_free(zathura_page_t* page); /** * Returns the associated document @@ -125,80 +125,80 @@ void zathura_page_set_data(zathura_page_t* page, void* data); * * @param page The page object * @param text Search item - * @param error Set to an error value (see \ref zathura_plugin_error_t) if an + * @param error Set to an error value (see \ref zathura_error_t) if an * error occured * @return List of results */ -girara_list_t* zathura_page_search_text(zathura_page_t* page, const char* text, zathura_plugin_error_t* error); +girara_list_t* zathura_page_search_text(zathura_page_t* page, const char* text, zathura_error_t* error); /** * Get page links * * @param page The page object - * @param error Set to an error value (see \ref zathura_plugin_error_t) if an + * @param error Set to an error value (see \ref zathura_error_t) if an * error occured * @return List of links */ -girara_list_t* zathura_page_links_get(zathura_page_t* page, zathura_plugin_error_t* error); +girara_list_t* zathura_page_links_get(zathura_page_t* page, zathura_error_t* error); /** * Free page links * * @param list List of links - * @return ZATHURA_PLUGIN_ERROR_OK when no error occured, otherwise see - * zathura_plugin_error_t + * @return ZATHURA_ERROR_OK when no error occured, otherwise see + * zathura_error_t */ -zathura_plugin_error_t zathura_page_links_free(girara_list_t* list); +zathura_error_t zathura_page_links_free(girara_list_t* list); /** * Get list of form fields * * @param page The page object - * @param error Set to an error value (see \ref zathura_plugin_error_t) if an + * @param error Set to an error value (see \ref zathura_error_t) if an * error occured * @return List of form fields */ -girara_list_t* zathura_page_form_fields_get(zathura_page_t* page, zathura_plugin_error_t* error); +girara_list_t* zathura_page_form_fields_get(zathura_page_t* page, zathura_error_t* error); /** * Free list of form fields * * @param list List of form fields - * @return ZATHURA_PLUGIN_ERROR_OK when no error occured, otherwise see - * zathura_plugin_error_t + * @return ZATHURA_ERROR_OK when no error occured, otherwise see + * zathura_error_t */ -zathura_plugin_error_t zathura_page_form_fields_free(girara_list_t* list); +zathura_error_t zathura_page_form_fields_free(girara_list_t* list); /** * Get list of images * * @param page Page - * @param error Set to an error value (see \ref zathura_plugin_error_t) if an + * @param error Set to an error value (see \ref zathura_error_t) if an * error occured * @return List of images or NULL if an error occured */ -girara_list_t* zathura_page_images_get(zathura_page_t* page, zathura_plugin_error_t* error); +girara_list_t* zathura_page_images_get(zathura_page_t* page, zathura_error_t* error); /** * Get image * * @param page Page * @param image Image identifier - * @param error Set to an error value (see \ref zathura_plugin_error_t) if an + * @param error Set to an error value (see \ref zathura_error_t) if an * error occured * @return The cairo image surface or NULL if an error occured */ -cairo_surface_t* zathura_page_image_get_cairo(zathura_page_t* page, zathura_image_t* image, zathura_plugin_error_t* error); +cairo_surface_t* zathura_page_image_get_cairo(zathura_page_t* page, zathura_image_t* image, zathura_error_t* error); /** * Get text for selection * @param page Page * @param rectangle Selection - * @param error Set to an error value (see \ref zathura_plugin_error_t) if an error + * @param error Set to an error value (see \ref zathura_error_t) if an error * occured * @return The selected text (needs to be deallocated with g_free) */ -char* zathura_page_get_text(zathura_page_t* page, zathura_rectangle_t rectangle, zathura_plugin_error_t* error); +char* zathura_page_get_text(zathura_page_t* page, zathura_rectangle_t rectangle, zathura_error_t* error); /** * Render page @@ -206,9 +206,9 @@ char* zathura_page_get_text(zathura_page_t* page, zathura_rectangle_t rectangle, * @param page The page object * @param cairo Cairo object * @param printing render for printing - * @return ZATHURA_PLUGIN_ERROR_OK when no error occured, otherwise see - * zathura_plugin_error_t + * @return ZATHURA_ERROR_OK when no error occured, otherwise see + * zathura_error_t */ -zathura_plugin_error_t zathura_page_render(zathura_page_t* page, cairo_t* cairo, bool printing); +zathura_error_t zathura_page_render(zathura_page_t* page, cairo_t* cairo, bool printing); #endif // PAGE_H diff --git a/plugin-api.h b/plugin-api.h new file mode 100644 index 0000000..ea34ad2 --- /dev/null +++ b/plugin-api.h @@ -0,0 +1,153 @@ +/* See LICENSE file for license and copyright information */ + +#ifndef PLUGIN_API_H +#define PLUGIN_API_H + +#include "page.h" +#include "document.h" +#include "version.h" + +typedef struct zathura_document_functions_s zathura_document_functions_t; + +/** + * Functions register function + * + * @param functions The functions struct + */ +typedef void (*zathura_plugin_register_function_t)(zathura_document_functions_t* functions); + +/** + * Sets the functions register function of the plugin + * + * @param plugin The plugin + */ +void zathura_plugin_set_register_functions_function(zathura_plugin_t* plugin, zathura_plugin_register_function_t register_function); + +/** + * Sets the functions register function of the plugin + * + * @param plugin The plugin + */ +void zathura_plugin_add_mimetype(zathura_plugin_t* plugin, const char* mime_type); + +/** + * Register a plugin. + * + * @param plugin_name the name of the plugin + * @param major the plugin's major version + * @param minor the plugin's minor version + * @param rev the plugin's revision + * @param register_functions function to register the plugin's document functions + * @param mimetypes a char array of mime types supported by the plugin + */ +#define PLUGIN_REGISTER(plugin_name, major, minor, rev, register_functions, mimetypes) \ + unsigned int plugin_version_major() { return major; } \ + unsigned int plugin_version_minor() { return minor; } \ + unsigned int plugin_version_revision() { return rev; } \ + unsigned int plugin_api_version() { return ZATHURA_API_VERSION; } \ + unsigned int plugin_abi_version() { return ZATHURA_ABI_VERSION; } \ + \ + void plugin_register(zathura_plugin_t* plugin) \ + { \ + if (plugin == NULL) { \ + return; \ + } \ + zathura_plugin_set_register_functions_function(plugin, register_functions); \ + static const char* mime_types[] = mimetypes; \ + for (size_t s = 0; s != sizeof(mime_types) / sizeof(const char*); ++s) { \ + zathura_plugin_add_mimetype(plugin, mime_types[s]); \ + } \ + } \ + +#define PLUGIN_MIMETYPES(...) __VA_ARGS__ + +struct zathura_document_functions_s +{ + /** + * Opens a document + */ + zathura_error_t (*document_open)(zathura_document_t* document); + + /** + * Frees the document + */ + zathura_error_t (*document_free)(zathura_document_t* document); + + /** + * Generates the document index + */ + girara_tree_node_t* (*document_index_generate)(zathura_document_t* document, zathura_error_t* error); + + /** + * Save the document + */ + zathura_error_t (*document_save_as)(zathura_document_t* document, const char* path); + + /** + * Get list of attachments + */ + girara_list_t* (*document_attachments_get)(zathura_document_t* document, zathura_error_t* error); + + /** + * Save attachment to a file + */ + zathura_error_t (*document_attachment_save)(zathura_document_t* document, const char* attachment, const char* file); + + /** + * Get document information + */ + char* (*document_meta_get)(zathura_document_t* document, zathura_document_meta_t info, zathura_error_t* error); + + /** + * Gets the page object + */ + zathura_error_t (*page_init)(zathura_page_t* page); + + /** + * Free page + */ + zathura_error_t (*page_clear)(zathura_page_t* page); + + /** + * Search text + */ + girara_list_t* (*page_search_text)(zathura_page_t* page, const char* text, zathura_error_t* error); + + /** + * Get links on a page + */ + girara_list_t* (*page_links_get)(zathura_page_t* page, zathura_error_t* error); + + /** + * Get form fields + */ + girara_list_t* (*page_form_fields_get)(zathura_page_t* page, zathura_error_t* error); + + /** + * Get list of images + */ + girara_list_t* (*page_images_get)(zathura_page_t* page, zathura_error_t* error); + + /** + * Get the image + */ + cairo_surface_t* (*page_image_get_cairo)(zathura_page_t* page, zathura_image_t* image, zathura_error_t* error); + + /** + * Get text for selection + */ + char* (*page_get_text)(zathura_page_t* page, zathura_rectangle_t rectangle, zathura_error_t* error); + + /** + * Renders the page + */ + zathura_image_buffer_t* (*page_render)(zathura_page_t* page, zathura_error_t* error); + + /** + * Renders the page + */ + zathura_error_t (*page_render_cairo)(zathura_page_t* page, cairo_t* cairo, bool printing); +}; + + +#endif // PLUGIN_API_H diff --git a/plugin.c b/plugin.c new file mode 100644 index 0000000..e26438c --- /dev/null +++ b/plugin.c @@ -0,0 +1,219 @@ +/* See LICENSE file for license and copyright information */ + +#include "plugin.h" + +#include +#include +#include + +#include +#include +#include +#include +#include + +/** + * Register document plugin + */ +static bool zathura_document_plugin_register(zathura_t* zathura, zathura_plugin_t* new_plugin); + +void +zathura_document_plugins_load(zathura_t* zathura) +{ + GIRARA_LIST_FOREACH(zathura->plugins.path, char*, iter, plugindir) + /* read all files in the plugin directory */ + GDir* dir = g_dir_open(plugindir, 0, NULL); + if (dir == NULL) { + girara_error("could not open plugin directory: %s", plugindir); + girara_list_iterator_next(iter); + continue; + } + + char* name = NULL; + while ((name = (char*) g_dir_read_name(dir)) != NULL) { + char* path = g_build_filename(plugindir, name, NULL); + if (g_file_test(path, G_FILE_TEST_IS_REGULAR) == 0) { + girara_info("%s is not a regular file. Skipping.", path); + g_free(path); + continue; + } + + void* handle = NULL; + zathura_plugin_t* plugin = NULL; + + /* load plugin */ + handle = dlopen(path, RTLD_NOW); + if (handle == NULL) { + girara_error("could not load plugin %s (%s)", path, dlerror()); + g_free(path); + continue; + } + + /* resolve symbols and check API and ABI version*/ + zathura_plugin_api_version_t api_version; + *(void**)(&api_version) = dlsym(handle, PLUGIN_API_VERSION_FUNCTION); + if (api_version != NULL) { + if (api_version() != ZATHURA_API_VERSION) { + girara_error("plugin %s has been built againt zathura with a different API version (plugin: %d, zathura: %d)", + path, api_version(), ZATHURA_API_VERSION); + g_free(path); + dlclose(handle); + continue; + } + } else { +#if ZATHURA_API_VERSION == 1 + girara_warning("could not find '%s' function in plugin %s ... loading anyway", PLUGIN_API_VERSION_FUNCTION, path); +#else + girara_error("could not find '%s' function in plugin %s", PLUGIN_API_VERSION_FUNCTION, path); + g_free(path); + dlclose(handle); + continue; +#endif + } + + zathura_plugin_abi_version_t abi_version; + *(void**)(&abi_version) = dlsym(handle, PLUGIN_ABI_VERSION_FUNCTION); + if (abi_version != NULL) { + if (abi_version() != ZATHURA_ABI_VERSION) { + girara_error("plugin %s has been built againt zathura with a different ABI version (plugin: %d, zathura: %d)", + path, abi_version(), ZATHURA_ABI_VERSION); + g_free(path); + dlclose(handle); + continue; + } + } else { +#if ZATHURA_API_VERSION == 1 + girara_warning("could not find '%s' function in plugin %s ... loading anyway", PLUGIN_ABI_VERSION_FUNCTION, path); +#else + girara_error("could not find '%s' function in plugin %s", PLUGIN_ABI_VERSION_FUNCTION, path); + g_free(path); + dlclose(handle); + continue; +#endif + } + + zathura_plugin_register_service_t register_plugin; + *(void**)(®ister_plugin) = dlsym(handle, PLUGIN_REGISTER_FUNCTION); + + if (register_plugin == NULL) { + girara_error("could not find '%s' function in plugin %s", PLUGIN_REGISTER_FUNCTION, path); + g_free(path); + dlclose(handle); + continue; + } + + plugin = g_malloc0(sizeof(zathura_plugin_t)); + plugin->content_types = girara_list_new2(g_free); + plugin->handle = handle; + + register_plugin(plugin); + + /* register functions */ + if (plugin->register_function == NULL) { + girara_error("plugin has no document functions register function"); + g_free(path); + dlclose(handle); + continue; + } + + plugin->register_function(&(plugin->functions)); + + bool r = zathura_document_plugin_register(zathura, plugin); + + if (r == false) { + girara_error("could not register plugin %s", path); + zathura_document_plugin_free(plugin); + } else { + girara_info("successfully loaded plugin %s", path); + } + + g_free(path); + } + g_dir_close(dir); + GIRARA_LIST_FOREACH_END(zathura->plugins.path, char*, iter, plugindir); +} + +void +zathura_document_plugin_free(zathura_plugin_t* plugin) +{ + if (plugin == NULL) { + return; + } + + dlclose(plugin->handle); + girara_list_free(plugin->content_types); + g_free(plugin); +} + +static bool +zathura_document_plugin_register(zathura_t* zathura, zathura_plugin_t* new_plugin) +{ + if (new_plugin == NULL || new_plugin->content_types == NULL || new_plugin->register_function == NULL) { + girara_error("plugin: could not register\n"); + return false; + } + + bool atleastone = false; + GIRARA_LIST_FOREACH(new_plugin->content_types, gchar*, iter, type) + if (!zathura_type_plugin_mapping_new(zathura, type, new_plugin)) { + girara_error("plugin: already registered for filetype %s\n", type); + } else { + atleastone = true; + } + GIRARA_LIST_FOREACH_END(new_plugin->content_types, gchar*, iter, type); + + if (atleastone) { + girara_list_append(zathura->plugins.plugins, new_plugin); + } + return atleastone; +} + +bool +zathura_type_plugin_mapping_new(zathura_t* zathura, const gchar* type, zathura_plugin_t* plugin) +{ + g_return_val_if_fail(zathura && type && plugin, false); + + GIRARA_LIST_FOREACH(zathura->plugins.type_plugin_mapping, zathura_type_plugin_mapping_t*, iter, mapping) + if (g_content_type_equals(type, mapping->type)) { + girara_list_iterator_free(iter); + return false; + } + GIRARA_LIST_FOREACH_END(zathura->plugins.type_plugin_mapping, zathura_type_plugin_mapping_t*, iter, mapping); + + zathura_type_plugin_mapping_t* mapping = g_malloc(sizeof(zathura_type_plugin_mapping_t)); + mapping->type = g_strdup(type); + mapping->plugin = plugin; + girara_list_append(zathura->plugins.type_plugin_mapping, mapping); + return true; +} + +void +zathura_type_plugin_mapping_free(zathura_type_plugin_mapping_t* mapping) +{ + if (mapping == NULL) { + return; + } + + g_free((void*)mapping->type); + g_free(mapping); +} + +void +zathura_plugin_set_register_functions_function(zathura_plugin_t* plugin, zathura_plugin_register_function_t register_function) +{ + if (plugin == NULL || register_function == NULL) { + return; + } + + plugin->register_function = register_function; +} + +void +zathura_plugin_add_mimetype(zathura_plugin_t* plugin, const char* mime_type) +{ + if (plugin == NULL || mime_type == NULL) { + return; + } + + girara_list_append(plugin->content_types, g_content_type_from_mime_type(mime_type)); +} diff --git a/plugin.h b/plugin.h new file mode 100644 index 0000000..b3751c1 --- /dev/null +++ b/plugin.h @@ -0,0 +1,89 @@ +/* See LICENSE file for license and copyright information */ + +#ifndef PLUGIN_H +#define PLUGIN_H + +#include + +#include "types.h" +#include "plugin-api.h" +#include "version.h" +#include "zathura.h" + +#define PLUGIN_REGISTER_FUNCTION "plugin_register" +#define PLUGIN_API_VERSION_FUNCTION "plugin_api_version" +#define PLUGIN_ABI_VERSION_FUNCTION "plugin_abi_version" + +/** + * Plugin mapping + */ +typedef struct zathura_type_plugin_mapping_s +{ + const gchar* type; /**< Plugin type */ + zathura_plugin_t* plugin; /**< Mapped plugin */ +} zathura_type_plugin_mapping_t; + +/** + * Document plugin structure + */ +struct zathura_plugin_s +{ + girara_list_t* content_types; /**< List of supported content types */ + zathura_plugin_register_function_t register_function; /**< Document open function */ + zathura_document_functions_t functions; /**< Document functions */ + void* handle; /**< DLL handle */ +}; + +/** + * Function prototype that is called to register a document plugin + * + * @param The document plugin + */ +typedef void (*zathura_plugin_register_service_t)(zathura_plugin_t*); + +/** + * Function prototype that is called to get the plugin's API version. + * + * @return plugin's API version + */ +typedef unsigned int (*zathura_plugin_api_version_t)(); + +/** + * Function prototype that is called to get the ABI version the plugin is built + * against. + * + * @return plugin's ABI version + */ +typedef unsigned int (*zathura_plugin_abi_version_t)(); + +/** + * Load all document plugins + * + * @param zathura the zathura session + */ +void zathura_document_plugins_load(zathura_t* zathura); + +/** + * Free a document plugin + * + * @param plugin The plugin + */ +void zathura_document_plugin_free(zathura_plugin_t* plugin); + +/** + * Add type -> plugin mapping + * @param zathura zathura instance + * @param type content type + * @param plugin plugin instance + * @return true on success, false if another plugin is already registered for + * that type + */ +bool zathura_type_plugin_mapping_new(zathura_t* zathura, const gchar* type, zathura_plugin_t* plugin); + +/** + * Free type -> plugin mapping + * @param mapping To be freed + */ +void zathura_type_plugin_mapping_free(zathura_type_plugin_mapping_t* mapping); + +#endif // PLUGIN_H diff --git a/render.c b/render.c index cea04a1..7b18b86 100644 --- a/render.c +++ b/render.c @@ -115,7 +115,7 @@ render(zathura_t* zathura, zathura_page_t* page) cairo_scale(cairo, zathura->document->scale, zathura->document->scale); } - if (zathura_page_render(page, cairo, false) != ZATHURA_PLUGIN_ERROR_OK) { + if (zathura_page_render(page, cairo, false) != ZATHURA_ERROR_OK) { cairo_destroy(cairo); cairo_surface_destroy(surface); return false; diff --git a/types.c b/types.c index 84938ef..ae12131 100644 --- a/types.c +++ b/types.c @@ -1,5 +1,7 @@ /* See LICENSE file for license and copyright information */ +#include + #include "types.h" zathura_link_t* @@ -78,3 +80,68 @@ zathura_link_get_target(zathura_link_t* link) return link->target; } + +zathura_index_element_t* +zathura_index_element_new(const char* title) +{ + if (title == NULL) { + return NULL; + } + + zathura_index_element_t* res = g_malloc0(sizeof(zathura_index_element_t)); + + res->title = g_strdup(title); + + return res; +} + +void +zathura_index_element_free(zathura_index_element_t* index) +{ + if (index == NULL) { + return; + } + + g_free(index->title); + + if (index->type == ZATHURA_LINK_EXTERNAL) { + g_free(index->target.uri); + } + + g_free(index); +} + +zathura_image_buffer_t* +zathura_image_buffer_create(unsigned int width, unsigned int height) +{ + zathura_image_buffer_t* image_buffer = malloc(sizeof(zathura_image_buffer_t)); + + if (image_buffer == NULL) { + return NULL; + } + + image_buffer->data = calloc(width * height * 3, sizeof(unsigned char)); + + if (image_buffer->data == NULL) { + free(image_buffer); + return NULL; + } + + image_buffer->width = width; + image_buffer->height = height; + image_buffer->rowstride = width * 3; + + return image_buffer; +} + +void +zathura_image_buffer_free(zathura_image_buffer_t* image_buffer) +{ + if (image_buffer == NULL) { + return; + } + + free(image_buffer->data); + free(image_buffer); +} + diff --git a/types.h b/types.h index 6717c56..13bf164 100644 --- a/types.h +++ b/types.h @@ -5,6 +5,24 @@ #include "zathura.h" +/** + * Plugin + */ +typedef struct zathura_plugin_s zathura_plugin_t; + +/** + * Error types + */ +typedef enum zathura_plugin_error_e +{ + ZATHURA_ERROR_OK, /**< No error occured */ + ZATHURA_ERROR_UNKNOWN, /**< An unknown error occured */ + ZATHURA_ERROR_OUT_OF_MEMORY, /**< Out of memory */ + ZATHURA_ERROR_NOT_IMPLEMENTED, /**< The called function has not been implemented */ + ZATHURA_ERROR_INVALID_ARGUMENTS, /**< Invalid arguments have been passed */ + ZATHURA_ERROR_INVALID_PASSWORD /**< The provided password is invalid */ +} zathura_error_t; + /** * Image buffer */ @@ -133,7 +151,7 @@ void zathura_index_element_free(zathura_index_element_t* index); * @param type Type of the link * @param position Position of the link * @param target Target - * @return New zathura link + * @return New zathura link */ zathura_link_t* zathura_link_new(zathura_link_type_t type, zathura_rectangle_t position, zathura_link_target_t target); @@ -149,14 +167,14 @@ void zathura_link_free(zathura_link_t* link); * Returns the type of the link * * @param link The link - * @return The target type of the link + * @return The target type of the link */ zathura_link_type_t zathura_link_get_type(zathura_link_t* link); /** * Returns the position of the link * - * @param link The link + * @param link The link * @return The position of the link */ zathura_rectangle_t zathura_link_get_position(zathura_link_t* link); diff --git a/utils.c b/utils.c index 5387f27..d1842d2 100644 --- a/utils.c +++ b/utils.c @@ -13,6 +13,7 @@ #include "zathura.h" #include "document.h" #include "page.h" +#include "plugin.h" #include diff --git a/zathura.c b/zathura.c index d838091..fe6fc37 100644 --- a/zathura.c +++ b/zathura.c @@ -29,6 +29,7 @@ #include "render.h" #include "page.h" #include "page-widget.h" +#include "plugin.h" typedef struct zathura_document_info_s { @@ -550,10 +551,10 @@ document_save(zathura_t* zathura, const char* path, bool overwrite) return false; } - zathura_plugin_error_t error = zathura_document_save_as(zathura->document, file_path); + zathura_error_t error = zathura_document_save_as(zathura->document, file_path); g_free(file_path); - return (error == ZATHURA_PLUGIN_ERROR_OK) ? true : false; + return (error == ZATHURA_ERROR_OK) ? true : false; } static void