diff --git a/synctex-dbus.c b/synctex-dbus.c new file mode 100644 index 0000000..66116a2 --- /dev/null +++ b/synctex-dbus.c @@ -0,0 +1,225 @@ +/* See LICENSE file for license and copyright information */ + +#include "synctex-dbus.h" +#include "synctex.h" +#include "macros.h" +#include "zathura.h" +#include "document.h" +#include +#include +#include +#include + +G_DEFINE_TYPE(ZathuraSynctexDbus, zathura_synctex_dbus, G_TYPE_OBJECT) + +/* template for bus name */ +static const char DBUS_NAME_TEMPLATE[] = "org.pwmt.zathura.PID-%d"; +/* template for object path */ +const char DBUS_OBJPATH[] = "/org/pwmt/zathura/synctex"; + +typedef struct private_s { + zathura_t* zathura; + GDBusNodeInfo* introspection_data; + GDBusConnection* connection; + guint owner_id; + guint registration_id; +} private_t; + +#define GET_PRIVATE(obj) \ + (G_TYPE_INSTANCE_GET_PRIVATE((obj), ZATHURA_TYPE_SYNCTEX_DBUS, \ + private_t)) + +/* Introspection data for the service we are exporting */ +static const char SYNCTEX_DBUS_INTROSPECTION[] = + "\n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + ""; + +static const GDBusInterfaceVTable interface_vtable; + +static bool synctex_dbus_view(ZathuraSynctexDbus* synctex_view, + const char* position); + +static void +finalize(GObject* object) +{ + ZathuraSynctexDbus* synctex_dbus = ZATHURA_SYNCTEX_DBUS(object); + private_t* priv = GET_PRIVATE(synctex_dbus); + + if (priv->connection != NULL && priv->registration_id > 0) { + g_dbus_connection_unregister_object(priv->connection, priv->registration_id); + } + + if (priv->owner_id > 0) { + g_bus_unown_name(priv->owner_id); + } + + if (priv->introspection_data != NULL) { + g_dbus_node_info_unref(priv->introspection_data); + } + + G_OBJECT_CLASS(zathura_synctex_dbus_parent_class)->finalize(object); +} + +static void +zathura_synctex_dbus_class_init(ZathuraSynctexDbusClass* class) +{ + /* initialize methods */ + class->view = synctex_dbus_view; + + /* add private members */ + g_type_class_add_private(class, sizeof(private_t)); + + /* overwrite methods */ + GObjectClass* object_class = G_OBJECT_CLASS(class); + object_class->finalize = finalize; +} + +static void +zathura_synctex_dbus_init(ZathuraSynctexDbus* synctex_dbus) +{ + private_t* priv = GET_PRIVATE(synctex_dbus); + priv->zathura = NULL; + priv->introspection_data = NULL; + priv->connection = NULL; + priv->owner_id = 0; + priv->registration_id = 0; +} + +static void +bus_acquired(GDBusConnection* connection, const gchar* name, void* data) +{ + girara_debug("Bus acquired at '%s'.", name); + + ZathuraSynctexDbus* dbus = data; + private_t* priv = GET_PRIVATE(dbus); + + GError* error = NULL; + priv->registration_id = g_dbus_connection_register_object(connection, + DBUS_OBJPATH, priv->introspection_data->interfaces[0], + &interface_vtable, dbus, NULL, &error); + + if (priv->registration_id == 0) { + girara_warning("Failed to register object on D-Bus connection: %s", + error->message); + g_error_free(error); + return; + } + + priv->connection = connection; +} + +static void +name_acquired(GDBusConnection* UNUSED(connection), const gchar* name, + void* UNUSED(data)) +{ + girara_debug("Acquired '%s' on session bus.", name); +} + +static void +name_lost(GDBusConnection* UNUSED(connection), const gchar* name, + void* UNUSED(data)) +{ + girara_debug("Lost connection or failed to acquire '%s' on session bus.", + name); +} + +ZathuraSynctexDbus* +zathura_synctex_dbus_new(zathura_t* zathura) +{ + GObject* obj = g_object_new(ZATHURA_TYPE_SYNCTEX_DBUS, NULL); + if (obj == NULL) { + return NULL; + } + + ZathuraSynctexDbus* synctex_dbus = ZATHURA_SYNCTEX_DBUS(obj); + private_t* priv = GET_PRIVATE(synctex_dbus); + priv->zathura = zathura; + + GError* error = NULL; + priv->introspection_data = g_dbus_node_info_new_for_xml(SYNCTEX_DBUS_INTROSPECTION, &error); + if (priv->introspection_data == NULL) { + girara_warning("Failed to parse introspection data: %s", error->message); + g_error_free(error); + g_object_unref(obj); + return NULL; + } + + char* well_known_name = g_strdup_printf(DBUS_NAME_TEMPLATE, getpid()); + priv->owner_id = g_bus_own_name(G_BUS_TYPE_SESSION, + well_known_name, G_BUS_NAME_OWNER_FLAGS_NONE, bus_acquired, + name_acquired, name_lost, synctex_dbus, NULL); + g_free(well_known_name); + + return synctex_dbus; +} + +static bool +synctex_dbus_view(ZathuraSynctexDbus* synctex_dbus, const char* position) +{ + private_t* priv = GET_PRIVATE(synctex_dbus); + return synctex_view(priv->zathura, position); +} + +bool +zathura_synctex_dbus_view(ZathuraSynctexDbus* synctex_dbus, const char* position) +{ + g_return_val_if_fail(ZATHURA_IS_SYNCTEX_DBUS(synctex_dbus), false); + g_return_val_if_fail(position != NULL, false); + + return ZATHURA_SYNCTEX_DBUS_GET_CLASS(synctex_dbus)->view(synctex_dbus, + position); +} + +/* D-Bus handler */ + +static void +handle_method_call(GDBusConnection* UNUSED(connection), + const gchar* UNUSED(sender), const gchar* UNUSED(object_path), + const gchar* UNUSED(interface_name), + const gchar* method_name, GVariant* parameters, + GDBusMethodInvocation* invocation, void* data) +{ + ZathuraSynctexDbus* synctex_dbus = data; + + if (g_strcmp0(method_name, "View") == 0) { + gchar* position = NULL; + g_variant_get(parameters, "(s)", &position); + + const bool ret = zathura_synctex_dbus_view(synctex_dbus, position); + g_free(position); + + GVariant* result = g_variant_new("(b)", ret); + g_dbus_method_invocation_return_value(invocation, result); + } +} + +static GVariant* +handle_get_property(GDBusConnection* UNUSED(connection), + const gchar* UNUSED(sender), const gchar* UNUSED(object_path), + const gchar* UNUSED(interface_name), const gchar* property_name, + GError** UNUSED(error), void* data) +{ + ZathuraSynctexDbus* synctex_dbus = data; + private_t* priv = GET_PRIVATE(synctex_dbus); + + if (g_strcmp0(property_name, "filename") == 0) { + return g_variant_new_string(zathura_document_get_path(priv->zathura->document)); + } + + return NULL; +} + +static const GDBusInterfaceVTable interface_vtable = +{ + .method_call = handle_method_call, + .get_property = handle_get_property, + .set_property = NULL +}; + diff --git a/synctex-dbus.h b/synctex-dbus.h new file mode 100644 index 0000000..749bf10 --- /dev/null +++ b/synctex-dbus.h @@ -0,0 +1,49 @@ +/* See LICENSE file for license and copyright information */ + +#ifndef SYNCTEX_DBUS_H +#define SYNCTEX_DBUS_H + +#include +#include +#include +#include "types.h" + +typedef struct zathura_synctex_dbus_class_s ZathuraSynctexDbusClass; + +struct zathura_synctex_dbus_s +{ + GObject parent; +}; + +struct zathura_synctex_dbus_class_s +{ + GObjectClass parent_class; + + bool (*view)(ZathuraSynctexDbus* synctex_dbus, const char* position); +}; + +#define ZATHURA_TYPE_SYNCTEX_DBUS \ + (zathura_synctex_dbus_get_type()) +#define ZATHURA_SYNCTEX_DBUS(obj) \ + (G_TYPE_CHECK_INSTANCE_CAST((obj), ZATHURA_TYPE_SYNCTEX_DBUS, \ + ZathuraSynctexDbus)) +#define ZATHURA_SYNCTEX_DBUS_CLASS(obj) \ + (G_TYPE_CHECK_CLASS_CAST((obj), ZATHURA_TYPE_SYNCTEX_DBUS, \ + ZathuraSynctexDbus)) +#define ZATHURA_IS_SYNCTEX_DBUS(obj) \ + (G_TYPE_CHECK_INSTANCE_TYPE((obj), ZATHURA_TYPE_SYNCTEX_DBUS)) +#define ZATHURA_IS_SYNCTEX_DBUS_CLASS(obj) \ + (G_TYPE_CHECK_CLASS_TYPE((obj), ZATHURA_TYPE_SYNCTEX_DBUS)) +#define ZATHURA_SYNCTEX_DBUS_GET_CLASS(obj) \ + (G_TYPE_INSTANCE_GET_CLASS((obj), ZATHURA_TYPE_SYNCTEX_DBUS, \ + ZathuraSynctexDbusClass)) + +GType zathura_synctex_dbus_get_type(void); + +ZathuraSynctexDbus* zathura_synctex_dbus_new(zathura_t* zathura); + +/* bool zathura_synctex_dbus_view(ZathuraSynctexDbus* synctex_dbus, + const char* position); */ + + +#endif diff --git a/types.h b/types.h index a211e8f..71dce5d 100644 --- a/types.h +++ b/types.h @@ -35,6 +35,11 @@ typedef struct zathura_plugin_manager_s zathura_plugin_manager_t; */ typedef struct zathura_renderer_s ZathuraRenderer; +/** + * Synctex DBus manager + */ +typedef struct zathura_synctex_dbus_s ZathuraSynctexDbus; + /** * Error types */ diff --git a/zathura.c b/zathura.c index 9caa762..d62ec2e 100644 --- a/zathura.c +++ b/zathura.c @@ -34,6 +34,7 @@ #include "page-widget.h" #include "plugin.h" #include "adjustment.h" +#include "synctex-dbus.h" typedef struct zathura_document_info_s { zathura_t* zathura; @@ -804,6 +805,9 @@ document_open(zathura_t* zathura, const char* path, const char* password, position_set(zathura, file_info.position_x, file_info.position_y); } + /* Start D-Bus */ + zathura->synctex.dbus = zathura_synctex_dbus_new(zathura); + return true; error_free: @@ -886,6 +890,12 @@ document_close(zathura_t* zathura, bool keep_monitor) /* stop rendering */ zathura_renderer_stop(zathura->sync.render_thread); + /* stop D-Bus */ + if (zathura->synctex.dbus != NULL) { + g_object_unref(zathura->synctex.dbus); + zathura->synctex.dbus = NULL; + } + /* remove monitor */ if (keep_monitor == false) { if (zathura->file_monitor.monitor != NULL) { diff --git a/zathura.h b/zathura.h index 5f63d01..1eded22 100644 --- a/zathura.h +++ b/zathura.h @@ -89,6 +89,7 @@ struct zathura_s { bool enabled; gchar* editor; + ZathuraSynctexDbus* dbus; } synctex; struct