summaryrefslogtreecommitdiff
path: root/applets/notification_area/libstatus-notifier-watcher
diff options
context:
space:
mode:
Diffstat (limited to 'applets/notification_area/libstatus-notifier-watcher')
-rw-r--r--applets/notification_area/libstatus-notifier-watcher/Makefile.am45
-rw-r--r--applets/notification_area/libstatus-notifier-watcher/README2
-rw-r--r--applets/notification_area/libstatus-notifier-watcher/gf-sn-watcher-v0.c395
-rw-r--r--applets/notification_area/libstatus-notifier-watcher/gf-sn-watcher-v0.h33
-rw-r--r--applets/notification_area/libstatus-notifier-watcher/gf-status-notifier-watcher.c64
-rw-r--r--applets/notification_area/libstatus-notifier-watcher/gf-status-notifier-watcher.h33
-rw-r--r--applets/notification_area/libstatus-notifier-watcher/org.kde.StatusNotifierWatcher.xml42
7 files changed, 614 insertions, 0 deletions
diff --git a/applets/notification_area/libstatus-notifier-watcher/Makefile.am b/applets/notification_area/libstatus-notifier-watcher/Makefile.am
new file mode 100644
index 00000000..eb06ce83
--- /dev/null
+++ b/applets/notification_area/libstatus-notifier-watcher/Makefile.am
@@ -0,0 +1,45 @@
+NULL =
+
+noinst_LTLIBRARIES = \
+ libstatus-notifier-watcher.la \
+ $(NULL)
+
+AM_CPPFLAGS = \
+ $(NOTIFICATION_AREA_CFLAGS) \
+ -DG_LOG_DOMAIN=\"status-notifier-watcher\" \
+ $(DISABLE_DEPRECATED_CFLAGS)
+
+AM_CFLAGS = $(WARN_CFLAGS)
+
+libstatus_notifier_watcher_la_SOURCES = \
+ gf-sn-watcher-v0.c \
+ gf-sn-watcher-v0.h \
+ gf-status-notifier-watcher.c \
+ gf-status-notifier-watcher.h \
+ $(BUILT_SOURCES) \
+ $(NULL)
+
+libstatus_notifier_watcher_la_LIBADD = \
+ $(NOTIFICATION_AREA_LIBS) \
+ $(NULL)
+
+gf-sn-watcher-v0-gen.h:
+gf-sn-watcher-v0-gen.c: org.kde.StatusNotifierWatcher.xml
+ $(AM_V_GEN) $(GDBUS_CODEGEN) --c-namespace Gf \
+ --generate-c-code gf-sn-watcher-v0-gen \
+ $(srcdir)/org.kde.StatusNotifierWatcher.xml
+
+BUILT_SOURCES = \
+ gf-sn-watcher-v0-gen.c \
+ gf-sn-watcher-v0-gen.h \
+ $(NULL)
+
+EXTRA_DIST = \
+ org.kde.StatusNotifierWatcher.xml \
+ $(NULL)
+
+CLEANFILES = \
+ $(BUILT_SOURCES) \
+ $(NULL)
+
+-include $(top_srcdir)/git.mk
diff --git a/applets/notification_area/libstatus-notifier-watcher/README b/applets/notification_area/libstatus-notifier-watcher/README
new file mode 100644
index 00000000..706b2a82
--- /dev/null
+++ b/applets/notification_area/libstatus-notifier-watcher/README
@@ -0,0 +1,2 @@
+Borrowed from gnome-flashback:
+https://git.gnome.org/browse/gnome-flashback/tree/gnome-flashback/libstatus-notifier-watcher
diff --git a/applets/notification_area/libstatus-notifier-watcher/gf-sn-watcher-v0.c b/applets/notification_area/libstatus-notifier-watcher/gf-sn-watcher-v0.c
new file mode 100644
index 00000000..8e82c10f
--- /dev/null
+++ b/applets/notification_area/libstatus-notifier-watcher/gf-sn-watcher-v0.c
@@ -0,0 +1,395 @@
+/*
+ * Copyright (C) 2016 Alberts Muktupāvels
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "config.h"
+
+#include "gf-sn-watcher-v0.h"
+
+struct _GfSnWatcherV0
+{
+ GfSnWatcherV0GenSkeleton parent;
+
+ guint bus_name_id;
+
+ GSList *hosts;
+ GSList *items;
+};
+
+typedef enum
+{
+ GF_WATCH_TYPE_HOST,
+ GF_WATCH_TYPE_ITEM
+} GfWatchType;
+
+typedef struct
+{
+ GfSnWatcherV0 *v0;
+ GfWatchType type;
+
+ gchar *service;
+ gchar *bus_name;
+ gchar *object_path;
+ guint watch_id;
+} GfWatch;
+
+static void gf_sn_watcher_v0_gen_init (GfSnWatcherV0GenIface *iface);
+
+G_DEFINE_TYPE_WITH_CODE (GfSnWatcherV0, gf_sn_watcher_v0, GF_TYPE_SN_WATCHER_V0_GEN_SKELETON,
+ G_IMPLEMENT_INTERFACE (GF_TYPE_SN_WATCHER_V0_GEN, gf_sn_watcher_v0_gen_init))
+
+static void
+update_registered_items (GfSnWatcherV0 *v0)
+{
+ GVariantBuilder builder;
+ GSList *l;
+ GVariant *variant;
+ const gchar **items;
+
+ g_variant_builder_init (&builder, G_VARIANT_TYPE ("as"));
+
+ for (l = v0->items; l != NULL; l = g_slist_next (l))
+ {
+ GfWatch *watch;
+ gchar *item;
+
+ watch = (GfWatch *) l->data;
+
+ item = g_strdup_printf ("%s%s", watch->bus_name, watch->object_path);
+ g_variant_builder_add (&builder, "s", item);
+ g_free (item);
+ }
+
+ variant = g_variant_builder_end (&builder);
+ items = g_variant_get_strv (variant, NULL);
+
+ gf_sn_watcher_v0_gen_set_registered_items (GF_SN_WATCHER_V0_GEN (v0), items);
+ g_variant_unref (variant);
+}
+
+static void
+gf_watch_free (gpointer data)
+{
+ GfWatch *watch;
+
+ watch = (GfWatch *) data;
+
+ if (watch->watch_id > 0)
+ g_bus_unwatch_name (watch->watch_id);
+
+ g_free (watch->service);
+ g_free (watch->bus_name);
+ g_free (watch->object_path);
+
+ g_free (watch);
+}
+
+static void
+name_vanished_cb (GDBusConnection *connection,
+ const char *name,
+ gpointer user_data)
+{
+ GfWatch *watch;
+ GfSnWatcherV0 *v0;
+ GfSnWatcherV0Gen *gen;
+
+ watch = (GfWatch *) user_data;
+ v0 = watch->v0;
+ gen = GF_SN_WATCHER_V0_GEN (v0);
+
+ if (watch->type == GF_WATCH_TYPE_HOST)
+ {
+ v0->hosts = g_slist_remove (v0->hosts, watch);
+
+ if (v0->hosts == NULL)
+ {
+ gf_sn_watcher_v0_gen_set_is_host_registered (gen, FALSE);
+ gf_sn_watcher_v0_gen_emit_host_registered (gen);
+ }
+ }
+ else if (watch->type == GF_WATCH_TYPE_ITEM)
+ {
+ gchar *tmp;
+
+ v0->items = g_slist_remove (v0->items, watch);
+
+ update_registered_items (v0);
+
+ tmp = g_strdup_printf ("%s%s", watch->bus_name, watch->object_path);
+ gf_sn_watcher_v0_gen_emit_item_unregistered (gen, tmp);
+ g_free (tmp);
+ }
+ else
+ {
+ g_assert_not_reached ();
+ }
+
+ gf_watch_free (watch);
+}
+
+static GfWatch *
+gf_watch_new (GfSnWatcherV0 *v0,
+ GfWatchType type,
+ const gchar *service,
+ const gchar *bus_name,
+ const gchar *object_path)
+{
+ GfWatch *watch;
+
+ watch = g_new0 (GfWatch, 1);
+
+ watch->v0 = v0;
+ watch->type = type;
+
+ watch->service = g_strdup (service);
+ watch->bus_name = g_strdup (bus_name);
+ watch->object_path = g_strdup (object_path);
+ watch->watch_id = g_bus_watch_name (G_BUS_TYPE_SESSION, bus_name,
+ G_BUS_NAME_WATCHER_FLAGS_NONE, NULL,
+ name_vanished_cb, watch, NULL);
+
+ return watch;
+}
+
+static GfWatch *
+gf_watch_find (GSList *list,
+ const gchar *bus_name,
+ const gchar *object_path)
+{
+ GSList *l;
+
+ for (l = list; l != NULL; l = g_slist_next (l))
+ {
+ GfWatch *watch;
+
+ watch = (GfWatch *) l->data;
+
+ if (g_strcmp0 (watch->bus_name, bus_name) == 0 &&
+ g_strcmp0 (watch->object_path, object_path) == 0)
+ {
+ return watch;
+ }
+ }
+
+ return NULL;
+}
+
+static gboolean
+gf_sn_watcher_v0_handle_register_host (GfSnWatcherV0Gen *object,
+ GDBusMethodInvocation *invocation,
+ const gchar *service)
+{
+ GfSnWatcherV0 *v0;
+ const gchar *bus_name;
+ const gchar *object_path;
+ GfWatch *watch;
+
+ v0 = GF_SN_WATCHER_V0 (object);
+
+ if (*service == '/')
+ {
+ bus_name = g_dbus_method_invocation_get_sender (invocation);
+ object_path = service;
+ }
+ else
+ {
+ bus_name = service;
+ object_path = "/StatusNotifierHost";
+ }
+
+ if (g_dbus_is_name (bus_name) == FALSE)
+ {
+ g_dbus_method_invocation_return_error (invocation, G_DBUS_ERROR,
+ G_DBUS_ERROR_INVALID_ARGS,
+ "D-Bus bus name '%s' is not valid",
+ bus_name);
+
+ return TRUE;
+ }
+
+ watch = gf_watch_find (v0->hosts, bus_name, object_path);
+
+ if (watch != NULL)
+ {
+ g_dbus_method_invocation_return_error (invocation, G_DBUS_ERROR,
+ G_DBUS_ERROR_INVALID_ARGS,
+ "Status Notifier Host with bus name '%s' and object path '%s' is already registered",
+ bus_name, object_path);
+
+ return TRUE;
+ }
+
+ watch = gf_watch_new (v0, GF_WATCH_TYPE_HOST, service, bus_name, object_path);
+ v0->hosts = g_slist_prepend (v0->hosts, watch);
+
+ if (!gf_sn_watcher_v0_gen_get_is_host_registered (object))
+ {
+ gf_sn_watcher_v0_gen_set_is_host_registered (object, TRUE);
+ gf_sn_watcher_v0_gen_emit_host_registered (object);
+ }
+
+ gf_sn_watcher_v0_gen_complete_register_host (object, invocation);
+
+ return TRUE;
+}
+
+static gboolean
+gf_sn_watcher_v0_handle_register_item (GfSnWatcherV0Gen *object,
+ GDBusMethodInvocation *invocation,
+ const gchar *service)
+{
+ GfSnWatcherV0 *v0;
+ const gchar *bus_name;
+ const gchar *object_path;
+ GfWatch *watch;
+ gchar *tmp;
+
+ v0 = GF_SN_WATCHER_V0 (object);
+
+ if (*service == '/')
+ {
+ bus_name = g_dbus_method_invocation_get_sender (invocation);
+ object_path = service;
+ }
+ else
+ {
+ bus_name = service;
+ object_path = "/StatusNotifierItem";
+ }
+
+ if (g_dbus_is_name (bus_name) == FALSE)
+ {
+ g_dbus_method_invocation_return_error (invocation, G_DBUS_ERROR,
+ G_DBUS_ERROR_INVALID_ARGS,
+ "D-Bus bus name '%s' is not valid",
+ bus_name);
+
+ return TRUE;
+ }
+
+ watch = gf_watch_find (v0->items, bus_name, object_path);
+
+ if (watch != NULL)
+ {
+ g_dbus_method_invocation_return_error (invocation, G_DBUS_ERROR,
+ G_DBUS_ERROR_INVALID_ARGS,
+ "Status Notifier Item with bus name '%s' and object path '%s' is already registered",
+ bus_name, object_path);
+
+ return TRUE;
+ }
+
+ watch = gf_watch_new (v0, GF_WATCH_TYPE_ITEM, service, bus_name, object_path);
+ v0->items = g_slist_prepend (v0->items, watch);
+
+ update_registered_items (v0);
+
+ tmp = g_strdup_printf ("%s%s", bus_name, object_path);
+ gf_sn_watcher_v0_gen_emit_item_registered (object, tmp);
+ g_free (tmp);
+
+ gf_sn_watcher_v0_gen_complete_register_item (object, invocation);
+
+ return TRUE;
+}
+
+static void
+gf_sn_watcher_v0_gen_init (GfSnWatcherV0GenIface *iface)
+{
+ iface->handle_register_host = gf_sn_watcher_v0_handle_register_host;
+ iface->handle_register_item = gf_sn_watcher_v0_handle_register_item;
+}
+
+static void
+bus_acquired_cb (GDBusConnection *connection,
+ const gchar *name,
+ gpointer user_data)
+{
+ GfSnWatcherV0 *v0;
+ GDBusInterfaceSkeleton *skeleton;
+ GError *error;
+
+ v0 = GF_SN_WATCHER_V0 (user_data);
+ skeleton = G_DBUS_INTERFACE_SKELETON (v0);
+
+ error = NULL;
+ g_dbus_interface_skeleton_export (skeleton, connection,
+ "/StatusNotifierWatcher", &error);
+
+ if (error != NULL)
+ {
+ g_warning ("%s", error->message);
+ g_error_free (error);
+ return;
+ }
+}
+
+static void
+gf_sn_watcher_v0_dispose (GObject *object)
+{
+ GfSnWatcherV0 *v0;
+
+ v0 = GF_SN_WATCHER_V0 (object);
+
+ if (v0->bus_name_id > 0)
+ {
+ g_bus_unown_name (v0->bus_name_id);
+ v0->bus_name_id = 0;
+ }
+
+ if (v0->hosts != NULL)
+ {
+ g_slist_free_full (v0->hosts, gf_watch_free);
+ v0->hosts = NULL;
+ }
+
+ if (v0->items != NULL)
+ {
+ g_slist_free_full (v0->items, gf_watch_free);
+ v0->items = NULL;
+ }
+
+ G_OBJECT_CLASS (gf_sn_watcher_v0_parent_class)->dispose (object);
+}
+
+static void
+gf_sn_watcher_v0_class_init (GfSnWatcherV0Class *v0_class)
+{
+ GObjectClass *object_class;
+
+ object_class = G_OBJECT_CLASS (v0_class);
+
+ object_class->dispose = gf_sn_watcher_v0_dispose;
+}
+
+static void
+gf_sn_watcher_v0_init (GfSnWatcherV0 *v0)
+{
+ GBusNameOwnerFlags flags;
+
+ flags = G_BUS_NAME_OWNER_FLAGS_ALLOW_REPLACEMENT |
+ G_BUS_NAME_OWNER_FLAGS_REPLACE;
+
+ v0->bus_name_id = g_bus_own_name (G_BUS_TYPE_SESSION,
+ "org.kde.StatusNotifierWatcher", flags,
+ bus_acquired_cb, NULL, NULL, v0, NULL);
+}
+
+GfSnWatcherV0 *
+gf_sn_watcher_v0_new (void)
+{
+ return g_object_new (GF_TYPE_SN_WATCHER_V0, NULL);
+}
diff --git a/applets/notification_area/libstatus-notifier-watcher/gf-sn-watcher-v0.h b/applets/notification_area/libstatus-notifier-watcher/gf-sn-watcher-v0.h
new file mode 100644
index 00000000..73bf6d04
--- /dev/null
+++ b/applets/notification_area/libstatus-notifier-watcher/gf-sn-watcher-v0.h
@@ -0,0 +1,33 @@
+/*
+ * Copyright (C) 2016 Alberts Muktupāvels
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef GF_SN_WATCHER_V0_H
+#define GF_SN_WATCHER_V0_H
+
+#include "gf-sn-watcher-v0-gen.h"
+
+G_BEGIN_DECLS
+
+#define GF_TYPE_SN_WATCHER_V0 gf_sn_watcher_v0_get_type ()
+G_DECLARE_FINAL_TYPE (GfSnWatcherV0, gf_sn_watcher_v0,
+ GF, SN_WATCHER_V0, GfSnWatcherV0GenSkeleton)
+
+GfSnWatcherV0 *gf_sn_watcher_v0_new (void);
+
+G_END_DECLS
+
+#endif
diff --git a/applets/notification_area/libstatus-notifier-watcher/gf-status-notifier-watcher.c b/applets/notification_area/libstatus-notifier-watcher/gf-status-notifier-watcher.c
new file mode 100644
index 00000000..e8b2c654
--- /dev/null
+++ b/applets/notification_area/libstatus-notifier-watcher/gf-status-notifier-watcher.c
@@ -0,0 +1,64 @@
+/*
+ * Copyright (C) 2016 Alberts Muktupāvels
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "config.h"
+
+#include "gf-sn-watcher-v0.h"
+#include "gf-status-notifier-watcher.h"
+
+struct _GfStatusNotifierWatcher
+{
+ GObject parent;
+
+ GfSnWatcherV0 *v0;
+};
+
+G_DEFINE_TYPE (GfStatusNotifierWatcher, gf_status_notifier_watcher, G_TYPE_OBJECT)
+
+static void
+gf_status_notifier_watcher_dispose (GObject *object)
+{
+ GfStatusNotifierWatcher *watcher;
+
+ watcher = GF_STATUS_NOTIFIER_WATCHER (object);
+
+ g_clear_object (&watcher->v0);
+
+ G_OBJECT_CLASS (gf_status_notifier_watcher_parent_class)->dispose (object);
+}
+
+static void
+gf_status_notifier_watcher_class_init (GfStatusNotifierWatcherClass *watcher_class)
+{
+ GObjectClass *object_class;
+
+ object_class = G_OBJECT_CLASS (watcher_class);
+
+ object_class->dispose = gf_status_notifier_watcher_dispose;
+}
+
+static void
+gf_status_notifier_watcher_init (GfStatusNotifierWatcher *watcher)
+{
+ watcher->v0 = gf_sn_watcher_v0_new ();
+}
+
+GfStatusNotifierWatcher *
+gf_status_notifier_watcher_new (void)
+{
+ return g_object_new (GF_TYPE_STATUS_NOTIFIER_WATCHER, NULL);
+}
diff --git a/applets/notification_area/libstatus-notifier-watcher/gf-status-notifier-watcher.h b/applets/notification_area/libstatus-notifier-watcher/gf-status-notifier-watcher.h
new file mode 100644
index 00000000..fd871a42
--- /dev/null
+++ b/applets/notification_area/libstatus-notifier-watcher/gf-status-notifier-watcher.h
@@ -0,0 +1,33 @@
+/*
+ * Copyright (C) 2016 Alberts Muktupāvels
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef GF_STATUS_NOTIFIER_WATCHER_H
+#define GF_STATUS_NOTIFIER_WATCHER_H
+
+#include <glib-object.h>
+
+G_BEGIN_DECLS
+
+#define GF_TYPE_STATUS_NOTIFIER_WATCHER gf_status_notifier_watcher_get_type ()
+G_DECLARE_FINAL_TYPE (GfStatusNotifierWatcher, gf_status_notifier_watcher,
+ GF, STATUS_NOTIFIER_WATCHER, GObject)
+
+GfStatusNotifierWatcher *gf_status_notifier_watcher_new (void);
+
+G_END_DECLS
+
+#endif
diff --git a/applets/notification_area/libstatus-notifier-watcher/org.kde.StatusNotifierWatcher.xml b/applets/notification_area/libstatus-notifier-watcher/org.kde.StatusNotifierWatcher.xml
new file mode 100644
index 00000000..30d3f774
--- /dev/null
+++ b/applets/notification_area/libstatus-notifier-watcher/org.kde.StatusNotifierWatcher.xml
@@ -0,0 +1,42 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<!DOCTYPE node PUBLIC "-//freedesktop//DTD D-BUS Object Introspection 1.0//EN"
+"http://www.freedesktop.org/standards/dbus/1.0/introspect.dtd">
+<node>
+ <interface name="org.kde.StatusNotifierWatcher">
+ <annotation name="org.gtk.GDBus.C.Name" value="SnWatcherV0Gen" />
+
+ <method name="RegisterStatusNotifierItem">
+ <annotation name="org.gtk.GDBus.C.Name" value="RegisterItem" />
+ <arg type="s" direction="in" name="service" />
+ </method>
+
+ <method name="RegisterStatusNotifierHost">
+ <annotation name="org.gtk.GDBus.C.Name" value="RegisterHost" />
+ <arg type="s" direction="in" name="service" />
+ </method>
+
+ <property name="RegisteredStatusNotifierItems" type="as" access="read">
+ <annotation name="org.gtk.GDBus.C.Name" value="RegisteredItems" />
+ </property>
+
+ <property name="IsStatusNotifierHostRegistered" type="b" access="read">
+ <annotation name="org.gtk.GDBus.C.Name" value="IsHostRegistered" />
+ </property>
+
+ <property name="ProtocolVersion" type="i" access="read" />
+
+ <signal name="StatusNotifierItemRegistered">
+ <annotation name="org.gtk.GDBus.C.Name" value="ItemRegistered" />
+ <arg type="s" direction="out" name="service" />
+ </signal>
+
+ <signal name="StatusNotifierItemUnregistered">
+ <annotation name="org.gtk.GDBus.C.Name" value="ItemUnregistered" />
+ <arg type="s" direction="out" name="service" />
+ </signal>
+
+ <signal name="StatusNotifierHostRegistered">
+ <annotation name="org.gtk.GDBus.C.Name" value="HostRegistered" />
+ </signal>
+ </interface>
+</node>