Commit 5fcbd977 authored by Alberts Muktupāvels's avatar Alberts Muktupāvels
Browse files

status-notifier-watcher: initial version

parent 87c21ba9
......@@ -118,7 +118,6 @@ UPOWER_GLIB_REQUIRED=0.99.0
PKG_CHECK_MODULES([GNOME_FLASHBACK], [
gtk+-3.0 >= $GTK_REQUIRED
$LIBSTATUS_NOTIFIER_PKG
])
PKG_CHECK_MODULES([AUDIO_DEVICE_SELECTION], [
......@@ -238,6 +237,11 @@ PKG_CHECK_MODULES([SOUND_APPLET], [
$LIBSTATUS_NOTIFIER_PKG
])
PKG_CHECK_MODULES([STATUS_NOTIFIER_WATCHER], [
glib-2.0 >= $GLIB_REQUIRED
gio-unix-2.0 >= $GLIB_REQUIRED
])
PKG_CHECK_MODULES([WORKAROUNDS], [
glib-2.0 >= $GLIB_REQUIRED
gtk+-3.0 >= $GTK_REQUIRED
......@@ -305,6 +309,7 @@ AC_CONFIG_FILES([
gnome-flashback/libshell/Makefile
gnome-flashback/libsound-applet/Makefile
gnome-flashback/libsound-applet/gvc/Makefile
gnome-flashback/libstatus-notifier-watcher/Makefile
gnome-flashback/libworkarounds/Makefile
po/Makefile.in
......
......@@ -102,7 +102,7 @@
<description>If set to true, then GNOME Flashback application will be used to show a sound applet. This is the same sound applet that used to be a part of GNOME Control Center.</description>
</key>
<key name="watcher" type="b">
<key name="status-notifier-watcher" type="b">
<default>true</default>
<summary>Status Notifier Watcher</summary>
<description>If set to true, then GNOME Flashback application will be used as Status Notifier Watcher.</description>
......
......@@ -19,6 +19,7 @@ SUBDIRS = \
libscreenshot \
libshell \
libsound-applet \
libstatus-notifier-watcher \
libworkarounds \
$(NULL)
......@@ -67,6 +68,7 @@ gnome_flashback_LDADD = \
$(top_builddir)/gnome-flashback/libscreenshot/libscreenshot.la \
$(top_builddir)/gnome-flashback/libshell/libshell.la \
$(top_builddir)/gnome-flashback/libsound-applet/libsound-applet.la \
$(top_builddir)/gnome-flashback/libstatus-notifier-watcher/libstatus-notifier-watcher.la \
$(top_builddir)/gnome-flashback/libworkarounds/libworkarounds.la \
$(NULL)
......
......@@ -38,44 +38,38 @@
#include "libscreenshot/gf-screenshot.h"
#include "libshell/flashback-shell.h"
#include "libsound-applet/gf-sound-applet.h"
#include "libstatus-notifier-watcher/gf-status-notifier-watcher.h"
#include "libworkarounds/gf-workarounds.h"
#ifdef WITH_LIBSTATUS_NOTIFIER
#include <libstatus-notifier/sn.h>
#endif
struct _GfApplication
{
GObject parent;
gint bus_name;
GSettings *settings;
GtkStyleProvider *provider;
GsdAutomountManager *automount;
FlashbackDisplayConfig *config;
FlashbackIdleMonitor *idle_monitor;
FlashbackPolkit *polkit;
FlashbackShell *shell;
GfAudioDeviceSelection *audio_device_selection;
GfBluetoothApplet *bluetooth;
GfDesktopBackground *background;
GfEndSessionDialog *dialog;
GfInputSettings *input_settings;
GfInputSources *input_sources;
GfNotifications *notifications;
GfPowerApplet *power;
GfScreencast *screencast;
GfScreensaver *screensaver;
GfScreenshot *screenshot;
GfSoundApplet *sound;
GfWorkarounds *workarounds;
#ifdef WITH_LIBSTATUS_NOTIFIER
SnWatcher *watcher;
#endif
GObject parent;
gint bus_name;
GSettings *settings;
GtkStyleProvider *provider;
GsdAutomountManager *automount;
FlashbackDisplayConfig *config;
FlashbackIdleMonitor *idle_monitor;
FlashbackPolkit *polkit;
FlashbackShell *shell;
GfAudioDeviceSelection *audio_device_selection;
GfBluetoothApplet *bluetooth;
GfDesktopBackground *background;
GfEndSessionDialog *dialog;
GfInputSettings *input_settings;
GfInputSources *input_sources;
GfNotifications *notifications;
GfPowerApplet *power;
GfScreencast *screencast;
GfScreensaver *screensaver;
GfScreenshot *screenshot;
GfSoundApplet *sound;
GfStatusNotifierWatcher *status_notifier_watcher;
GfWorkarounds *workarounds;
};
G_DEFINE_TYPE (GfApplication, gf_application, G_TYPE_OBJECT)
......@@ -170,25 +164,11 @@ settings_changed (GSettings *settings,
SETTING_CHANGED (screensaver, "screensaver", gf_screensaver_new)
SETTING_CHANGED (screenshot, "screenshot", gf_screenshot_new)
SETTING_CHANGED (sound, "sound-applet", gf_sound_applet_new)
SETTING_CHANGED (status_notifier_watcher, "status-notifier-watcher", gf_status_notifier_watcher_new)
SETTING_CHANGED (workarounds, "workarounds", gf_workarounds_new)
#undef SETTING_CHANGED
#ifdef WITH_LIBSTATUS_NOTIFIER
if (key == NULL || g_strcmp0 (key, "watcher") == 0)
{
if (g_settings_get_boolean (settings, "watcher"))
{
if (application->watcher == NULL)
application->watcher = sn_watcher_new (SN_WATCHER_FLAGS_NONE);
}
else
{
g_clear_object (&application->watcher);
}
}
#endif
if (application->input_settings)
gf_input_settings_set_display_config (application->input_settings,
application->config);
......@@ -230,12 +210,9 @@ gf_application_dispose (GObject *object)
g_clear_object (&application->screenshot);
g_clear_object (&application->screensaver);
g_clear_object (&application->sound);
g_clear_object (&application->status_notifier_watcher);
g_clear_object (&application->workarounds);
#ifdef WITH_LIBSTATUS_NOTIFIER
g_clear_object (&application->watcher);
#endif
G_OBJECT_CLASS (gf_application_parent_class)->dispose (object);
}
......
NULL =
noinst_LTLIBRARIES = \
libstatus-notifier-watcher.la \
$(NULL)
libstatus_notifier_watcher_la_CPPFLAGS = \
-DG_LOG_DOMAIN=\"gf-status-notifier-watcher\" \
-DG_LOG_USE_STRUCTURED=1 \
-I$(top_builddir)/gnome-flashback/libstatus-notifier-watcher \
$(NULL)
libstatus_notifier_watcher_la_CFLAGS = \
$(STATUS_NOTIFIER_WATCHER_CFLAGS) \
$(WARN_CFLAGS) \
$(AM_CFLAGS) \
$(NULL)
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_LDFLAGS = \
$(WARN_LDFLAGS) \
$(AM_LDFLAGS) \
$(NULL)
libstatus_notifier_watcher_la_LIBADD = \
$(STATUS_NOTIFIER_WATCHER_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
/*
* 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)
{
g_assert (gf_sn_watcher_v0_gen_get_is_host_registered (gen) == FALSE);
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)
{
v0->items = g_slist_remove (v0->items, watch);
update_registered_items (v0);
gf_sn_watcher_v0_gen_emit_item_unregistered (gen, watch->service);
}
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))
{
g_assert (v0->hosts != NULL);
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;
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);
gf_sn_watcher_v0_gen_emit_item_registered (object, service);
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);
}