From 1b6a2b47534d0f64c6531f919ed8eb7481ec27fa Mon Sep 17 00:00:00 2001 From: Sebastian Ramacher Date: Tue, 24 Dec 2013 01:05:40 +0100 Subject: [PATCH] Initial D-Bus client implementation Signed-off-by: Sebastian Ramacher --- main.c | 41 +++++++++++++++-------- synctex-dbus.c | 89 ++++++++++++++++++++++++++++++++++++++++++++++++++ synctex-dbus.h | 8 +++++ 3 files changed, 125 insertions(+), 13 deletions(-) diff --git a/main.c b/main.c index 7f3ac59..a0982ab 100644 --- a/main.c +++ b/main.c @@ -10,6 +10,7 @@ #include "zathura.h" #include "utils.h" +#include "synctex-dbus.h" /* main function */ int @@ -43,6 +44,7 @@ main(int argc, char* argv[]) gchar* loglevel = NULL; gchar* password = NULL; gchar* synctex_editor = NULL; + gchar* synctex_fwd = NULL; bool forkback = false; bool print_version = false; bool synctex = false; @@ -55,17 +57,18 @@ main(int argc, char* argv[]) #endif GOptionEntry entries[] = { - { "reparent", 'e', 0, G_OPTION_ARG_INT, &embed, _("Reparents to window specified by xid"), "xid" }, - { "config-dir", 'c', 0, G_OPTION_ARG_FILENAME, &config_dir, _("Path to the config directory"), "path" }, - { "data-dir", 'd', 0, G_OPTION_ARG_FILENAME, &data_dir, _("Path to the data directory"), "path" }, - { "plugins-dir", 'p', 0, G_OPTION_ARG_STRING, &plugin_path, _("Path to the directories containing plugins"), "path" }, - { "fork", '\0',0, G_OPTION_ARG_NONE, &forkback, _("Fork into the background"), NULL }, - { "password", 'w', 0, G_OPTION_ARG_STRING, &password, _("Document password"), "password" }, - { "page", 'P', 0, G_OPTION_ARG_INT, &page_number, _("Page number to go to"), "number" }, - { "debug", 'l', 0, G_OPTION_ARG_STRING, &loglevel, _("Log level (debug, info, warning, error)"), "level" }, - { "version", 'v', 0, G_OPTION_ARG_NONE, &print_version, _("Print version information"), NULL }, - { "synctex", 's', 0, G_OPTION_ARG_NONE, &synctex, _("Enable synctex support"), NULL }, - { "synctex-editor-command", 'x', 0, G_OPTION_ARG_STRING, &synctex_editor, _("Synctex editor (forwarded to the synctex command)"), "cmd" }, + { "reparent", 'e', 0, G_OPTION_ARG_INT, &embed, _("Reparents to window specified by xid"), "xid" }, + { "config-dir", 'c', 0, G_OPTION_ARG_FILENAME, &config_dir, _("Path to the config directory"), "path" }, + { "data-dir", 'd', 0, G_OPTION_ARG_FILENAME, &data_dir, _("Path to the data directory"), "path" }, + { "plugins-dir", 'p', 0, G_OPTION_ARG_STRING, &plugin_path, _("Path to the directories containing plugins"), "path" }, + { "fork", '\0', 0, G_OPTION_ARG_NONE, &forkback, _("Fork into the background"), NULL }, + { "password", 'w', 0, G_OPTION_ARG_STRING, &password, _("Document password"), "password" }, + { "page", 'P', 0, G_OPTION_ARG_INT, &page_number, _("Page number to go to"), "number" }, + { "debug", 'l', 0, G_OPTION_ARG_STRING, &loglevel, _("Log level (debug, info, warning, error)"), "level" }, + { "version", 'v', 0, G_OPTION_ARG_NONE, &print_version, _("Print version information"), NULL }, + { "synctex", 's', 0, G_OPTION_ARG_NONE, &synctex, _("Enable synctex support"), NULL }, + { "synctex-editor-command", 'x', 0, G_OPTION_ARG_STRING, &synctex_editor, _("Synctex editor (forwarded to the synctex command)"), "cmd" }, + { "synctex-forward", '\0', 0, G_OPTION_ARG_STRING, &synctex_fwd, _("Synctex forward ..."), "position" }, { NULL, '\0', 0, 0, NULL, NULL, NULL } }; @@ -82,11 +85,23 @@ main(int argc, char* argv[]) } g_option_context_free(context); + if (synctex_fwd != NULL) { + if (argc != 2) { + girara_error(_("Too many arguments or missing filename while running with --syntex-forward")); + return -1; + } + + if (synctex_forward_position(argv[1], synctex_fwd) == true) { + return 0; + } + } + + /* Fork into the background if the user really wants to ... */ if (forkback == true) { - int pid = fork(); + const int pid = fork(); if (pid > 0) { /* parent */ - exit(0); + return 0; } else if (pid < 0) { /* error */ girara_error("Couldn't fork."); } diff --git a/synctex-dbus.c b/synctex-dbus.c index 66116a2..a9f2926 100644 --- a/synctex-dbus.c +++ b/synctex-dbus.c @@ -223,3 +223,92 @@ static const GDBusInterfaceVTable interface_vtable = .set_property = NULL }; +static const unsigned int TIMEOUT = 3000; + +bool +synctex_forward_position(const char* filename, const char* position) +{ + if (filename == NULL || position == NULL) { + return false; + } + + GError* error = NULL; + GDBusConnection* connection = g_bus_get_sync(G_BUS_TYPE_SESSION, + NULL, &error); + /* GDBusProxy* proxy = g_dbus_proxy_new_for_bus_sync(G_BUS_TYPE_SESSION, + G_DBUS_PROXY_FLAGS_NONE, NULL, "org.freedesktop.DBus", + "/org/freedesktop/DBus", "org.freedesktop.DBus", NULL, &error); */ + if (connection == NULL) { + girara_error("Could not create proxy for 'org.freedesktop.DBus': %s", + error->message); + g_error_free(error); + return false; + } + + GVariant* vnames = g_dbus_connection_call_sync(connection, + "org.freedesktop.DBus", "/org/freedesktop/DBus", "org.freedesktop.DBus", + "ListNames", NULL, G_VARIANT_TYPE("(as)"), G_DBUS_CALL_FLAGS_NONE, + TIMEOUT, NULL, &error); + if (vnames == NULL) { + girara_error("Could not list available names: %s", error->message); + g_error_free(error); + // g_object_unref(proxy); + g_object_unref(connection); + return false; + } + + GVariantIter* iter = NULL; + g_variant_get(vnames, "(as)", &iter); + + gchar* name = NULL; + bool found_one = false; + while (g_variant_iter_loop(iter, "s", &name) == TRUE) { + if (g_str_has_prefix(name, "org.pwmt.zathura.PID") == FALSE) { + continue; + } + girara_debug("Found name: %s", name); + + GVariant* vfilename = g_dbus_connection_call_sync(connection, + name, DBUS_OBJPATH, "org.freedesktop.DBus.Properties", + "Get", g_variant_new("(ss)", "org.pwmt.zathura.Synctex", "filename"), + G_VARIANT_TYPE("(v)"), G_DBUS_CALL_FLAGS_NONE, + TIMEOUT, NULL, &error); + if (vfilename == NULL) { + girara_error("Failed to query 'filename' property from '%s': %s", + name, error->message); + g_error_free(error); + continue; + } + + GVariant* tmp = NULL; + g_variant_get(vfilename, "(v)", &tmp); + gchar* remote_filename = g_variant_dup_string(tmp, NULL); + girara_debug("Filename from '%s': %s", name, remote_filename); + g_variant_unref(tmp); + g_variant_unref(vfilename); + + if (g_strcmp0(filename, remote_filename) != 0) { + g_free(remote_filename); + continue; + } + + g_free(remote_filename); + found_one = true; + + GVariant* ret = g_dbus_connection_call_sync(connection, + name, DBUS_OBJPATH, "org.pwmt.zathura.Synctex", "View", + g_variant_new("(s)", position), G_VARIANT_TYPE("(b)"), + G_DBUS_CALL_FLAGS_NONE, TIMEOUT, NULL, &error); + if (ret == NULL) { + girara_error("Failed to run View on '%s': %s", name, error->message); + g_error_free(error); + } else { + g_variant_unref(ret); + } + } + g_variant_iter_free(iter); + g_variant_unref(vnames); + + return found_one; +} + diff --git a/synctex-dbus.h b/synctex-dbus.h index 749bf10..1cb2501 100644 --- a/synctex-dbus.h +++ b/synctex-dbus.h @@ -45,5 +45,13 @@ ZathuraSynctexDbus* zathura_synctex_dbus_new(zathura_t* zathura); /* bool zathura_synctex_dbus_view(ZathuraSynctexDbus* synctex_dbus, const char* position); */ +/** + * Forward synctex position to zathura instance having the right file open. + * @param filename filename + * @param position synctex position + * @returns true if a instance was found that has the given filename open, false + * otherwise + */ +bool synctex_forward_position(const char* filename, const char* position); #endif