From c64309f5a4bcbc62d4ab5810735be97e7abcf335 Mon Sep 17 00:00:00 2001 From: Jason Conti Date: Fri, 13 May 2011 14:10:30 -0400 Subject: Importing dbus-spy and notification dbus objects to watch dbus for org.freedesktop.Notification.Notify messages (from test project). --- src/dbus-spy.c | 166 +++++++++++++++++++++++++++++++++++++++++++++++++++++ src/dbus-spy.h | 53 +++++++++++++++++ src/notification.c | 132 ++++++++++++++++++++++++++++++++++++++++++ src/notification.h | 62 ++++++++++++++++++++ 4 files changed, 413 insertions(+) create mode 100644 src/dbus-spy.c create mode 100644 src/dbus-spy.h create mode 100644 src/notification.c create mode 100644 src/notification.h diff --git a/src/dbus-spy.c b/src/dbus-spy.c new file mode 100644 index 0000000..af3e492 --- /dev/null +++ b/src/dbus-spy.c @@ -0,0 +1,166 @@ +/* + * dbus-spy.c - A gobject subclass to watch dbus for org.freedesktop.Notification.Notify messages. + */ + +#include "dbus-spy.h" + +enum { + MESSAGE_RECEIVED, + LAST_SIGNAL +}; + +static guint signals[LAST_SIGNAL]; + +static void dbus_spy_class_init(DBusSpyClass *klass); +static void dbus_spy_init(DBusSpy *self); +static void dbus_spy_dispose(GObject *object); + +static void add_filter(DBusSpy *self); + +static void bus_get_cb(GObject *source_object, GAsyncResult *res, gpointer user_data); + +static GDBusMessage *message_filter(GDBusConnection *connection, GDBusMessage *message, + gboolean incoming, gpointer user_data); + +#define MATCH_STRING "type='method_call',interface='org.freedesktop.Notifications',member='Notify'" + +G_DEFINE_TYPE (DBusSpy, dbus_spy, G_TYPE_OBJECT); + +static void +dbus_spy_class_init(DBusSpyClass *klass) +{ + GObjectClass *object_class = G_OBJECT_CLASS(klass); + + g_type_class_add_private(klass, sizeof(DBusSpyPrivate)); + + object_class->dispose = dbus_spy_dispose; + + signals[MESSAGE_RECEIVED] = + g_signal_new("message-received", + G_TYPE_FROM_CLASS(klass), + G_SIGNAL_RUN_LAST, + G_STRUCT_OFFSET(DBusSpyClass, message_received), + NULL, NULL, + g_cclosure_marshal_VOID__OBJECT, + G_TYPE_NONE, + 1, NOTIFICATION_TYPE); +} + +static void +bus_get_cb(GObject *source_object, GAsyncResult *res, gpointer user_data) +{ + GError *error = NULL; + + GDBusConnection *connection = g_bus_get_finish(res, &error); + + if(error != NULL) { + g_warning("Could not get a connection to the dbus session bus: %s\n", error->message); + g_error_free(error); + return; + } + + DBusSpy *self = DBUS_SPY(user_data); + g_return_if_fail(self != NULL); + + if(self->priv->connection_cancel != NULL) { + g_object_unref(self->priv->connection_cancel); + self->priv->connection_cancel = NULL; + } + + self->priv->connection = connection; + + add_filter(self); +} + +static void +add_filter(DBusSpy *self) +{ + GDBusMessage *message; + GVariant *body; + GError *error = NULL; + + message = g_dbus_message_new_method_call("org.freedesktop.DBus", "/org/freedesktop/DBus", + "org.freedesktop.DBus", "AddMatch"); + + body = g_variant_new_parsed("(%s,)", MATCH_STRING); + + g_dbus_message_set_body(message, body); + + g_dbus_connection_send_message(self->priv->connection, + message, + G_DBUS_SEND_MESSAGE_FLAGS_NONE, + NULL, + &error); + if(error != NULL) { + g_warning("Failed to send AddMatch message: %s\n", error->message); + g_error_free(error); + return; + } + + g_dbus_connection_add_filter(self->priv->connection, message_filter, self, NULL); +} + +static GDBusMessage* +message_filter(GDBusConnection *connection, GDBusMessage *message, gboolean incoming, gpointer user_data) +{ + if(!incoming) return message; + + GDBusMessageType type = g_dbus_message_get_message_type(message); + const gchar *interface = g_dbus_message_get_interface(message); + const gchar *member = g_dbus_message_get_member(message); + + if((type == G_DBUS_MESSAGE_TYPE_METHOD_CALL) + && (g_strcmp0(interface, "org.freedesktop.Notifications") == 0) + && (g_strcmp0(member, "Notify") == 0)) + { + DBusSpy *spy = DBUS_SPY(user_data); + Notification *note = notification_new_from_dbus_message(message); + g_signal_emit(spy, signals[MESSAGE_RECEIVED], 0, note); + g_object_unref(note); + g_object_unref(message); + message = NULL; + } + + return message; +} + +static void +dbus_spy_init(DBusSpy *self) +{ + self->priv = DBUS_SPY_GET_PRIVATE(self); + + self->priv->connection = NULL; + self->priv->connection_cancel = g_cancellable_new(); + + g_bus_get(G_BUS_TYPE_SESSION, + self->priv->connection_cancel, + bus_get_cb, + self); +} + +static void +dbus_spy_dispose(GObject *object) +{ + DBusSpy *self = DBUS_SPY(object); + + if(self->priv->connection_cancel != NULL) { + g_cancellable_cancel(self->priv->connection_cancel); + g_object_unref(self->priv->connection_cancel); + self->priv->connection_cancel = NULL; + } + + if(self->priv->connection != NULL) { + g_dbus_connection_close(self->priv->connection, NULL, NULL, NULL); + g_object_unref(self->priv->connection); + self->priv->connection = NULL; + } + + G_OBJECT_CLASS(dbus_spy_parent_class)->dispose(object); +} + +DBusSpy* +dbus_spy_new(void) +{ + return DBUS_SPY(g_object_new(DBUS_SPY_TYPE, NULL)); +} + diff --git a/src/dbus-spy.h b/src/dbus-spy.h new file mode 100644 index 0000000..1f9f79e --- /dev/null +++ b/src/dbus-spy.h @@ -0,0 +1,53 @@ +/* + * dbus-spy.h - A gobject subclass to watch dbus for org.freedesktop.Notification.Notify messages. + */ + +#ifndef __DBUS_SPY_H__ +#define __DBUS_SPY_H__ + +#include +#include +#include + +#include "notification.h" + +G_BEGIN_DECLS + +#define DBUS_SPY_TYPE (dbus_spy_get_type ()) +#define DBUS_SPY(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), DBUS_SPY_TYPE, DBusSpy)) +#define DBUS_SPY_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), DBUS_SPY_TYPE, DBusSpyClass)) +#define IS_DBUS_SPY(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), DBUS_SPY_TYPE)) +#define IS_DBUS_SPY_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), DBUS_SPY_TYPE)) + +typedef struct _DBusSpy DBusSpy; +typedef struct _DBusSpyClass DBusSpyClass; +typedef struct _DBusSpyPrivate DBusSpyPrivate; + +struct _DBusSpy +{ + GObject parent; + DBusSpyPrivate *priv; +}; + +struct _DBusSpyClass +{ + GObjectClass parent_class; + + void (* message_received) (DBusSpy *spy, + Notification *note); +}; + +struct _DBusSpyPrivate { + GDBusConnection *connection; + GCancellable *connection_cancel; +}; + +#define DBUS_SPY_GET_PRIVATE(o) \ + (G_TYPE_INSTANCE_GET_PRIVATE ((o), DBUS_SPY_TYPE, DBusSpyPrivate)) + +GType dbus_spy_get_type(void); +DBusSpy* dbus_spy_new(void); + +G_END_DECLS + +#endif /* __DBUS_SPY_H__ */ diff --git a/src/notification.c b/src/notification.c new file mode 100644 index 0000000..9b0a3c9 --- /dev/null +++ b/src/notification.c @@ -0,0 +1,132 @@ +/* + * notification.c - A gobject subclass to represent a org.freedesktop.Notification.Notify message. + */ + +#include "notification.h" + +#define COLUMN_APP_NAME 0 +#define COLUMN_REPLACES_ID 1 +#define COLUMN_APP_ICON 2 +#define COLUMN_SUMMARY 3 +#define COLUMN_BODY 4 +#define COLUMN_ACTIONS 5 +#define COLUMN_HINTS 6 +#define COLUMN_EXPIRE_TIMEOUT 7 + +#define COLUMN_COUNT 8 + +static void notification_class_init(NotificationClass *klass); +static void notification_init(Notification *self); +static void notification_dispose(GObject *object); + +G_DEFINE_TYPE (Notification, notification, G_TYPE_OBJECT); + +static void +notification_class_init(NotificationClass *klass) +{ + GObjectClass *object_class = G_OBJECT_CLASS(klass); + + g_type_class_add_private(klass, sizeof(NotificationPrivate)); + + object_class->dispose = notification_dispose; +} + +static void +notification_init(Notification *self) +{ + self->priv = NOTIFICATION_GET_PRIVATE(self); + + self->priv->app_name = NULL; + self->priv->replaces_id = 0; + self->priv->app_icon = NULL; + self->priv->summary = NULL; + self->priv->body = NULL; + self->priv->expire_timeout = 0; +} + +static void +notification_dispose(GObject *object) +{ + Notification *self = NOTIFICATION(object); + + if(self->priv->app_name != NULL) { + g_free(self->priv->app_name); + self->priv->app_name = NULL; + } + + if(self->priv->app_icon != NULL) { + g_free(self->priv->app_icon); + self->priv->app_icon = NULL; + } + + if(self->priv->summary != NULL) { + g_free(self->priv->summary); + self->priv->summary = NULL; + } + + if(self->priv->body != NULL) { + g_free(self->priv->body); + self->priv->body = NULL; + } + + G_OBJECT_CLASS(notification_parent_class)->dispose(object); +} + +Notification* +notification_new(void) +{ + return NOTIFICATION(g_object_new(NOTIFICATION_TYPE, NULL)); +} + +Notification* +notification_new_from_dbus_message(GDBusMessage *message) +{ + Notification *self = notification_new(); + + GVariant *body = g_dbus_message_get_body(message); + GVariant *child = NULL; + g_assert(g_variant_is_of_type(body, G_VARIANT_TYPE_TUPLE)); + g_assert(g_variant_n_children(body) == COLUMN_COUNT); + + /* app_name */ + child = g_variant_get_child_value(body, COLUMN_APP_NAME); + g_assert(g_variant_is_of_type(child, G_VARIANT_TYPE_STRING)); + self->priv->app_name = g_variant_dup_string(child, + &(self->priv->app_name_length)); + + /* replaces_id */ + child = g_variant_get_child_value(body, COLUMN_REPLACES_ID); + g_assert(g_variant_is_of_type(child, G_VARIANT_TYPE_UINT32)); + self->priv->replaces_id = g_variant_get_uint32(child); + + /* app_icon */ + child = g_variant_get_child_value(body, COLUMN_APP_ICON); + g_assert(g_variant_is_of_type(child, G_VARIANT_TYPE_STRING)); + self->priv->app_icon = g_variant_dup_string(child, + &(self->priv->app_icon_length)); + + /* summary */ + child = g_variant_get_child_value(body, COLUMN_SUMMARY); + g_assert(g_variant_is_of_type(child, G_VARIANT_TYPE_STRING)); + self->priv->summary = g_variant_dup_string(child, + &(self->priv->summary_length)); + + /* body */ + child = g_variant_get_child_value(body, COLUMN_BODY); + g_assert(g_variant_is_of_type(child, G_VARIANT_TYPE_STRING)); + self->priv->body = g_variant_dup_string(child, + &(self->priv->body_length)); + + child = NULL; + + return self; +} + +void +notification_print(Notification *self) +{ + g_print("app_name = %s\n", self->priv->app_name); + g_print("app_icon = %s\n", self->priv->app_icon); + g_print("summary = %s\n", self->priv->summary); + g_print("body = %s\n", self->priv->body); +} diff --git a/src/notification.h b/src/notification.h new file mode 100644 index 0000000..d31a76d --- /dev/null +++ b/src/notification.h @@ -0,0 +1,62 @@ +/* + * notification.h - A gobject subclass to represent a org.freedesktop.Notification.Notify message. + */ + +#ifndef __NOTIFICATION_H__ +#define __NOTIFICATION_H__ + +#include +#include +#include + +G_BEGIN_DECLS + +#define NOTIFICATION_TYPE (notification_get_type ()) +#define NOTIFICATION(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), NOTIFICATION_TYPE, Notification)) +#define NOTIFICATION_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), NOTIFICATION_TYPE, NotificationClass)) +#define IS_NOTIFICATION(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), NOTIFICATION_TYPE)) +#define IS_NOTIFICATION_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), NOTIFICATION_TYPE)) + +typedef struct _Notification Notification; +typedef struct _NotificationClass NotificationClass; +typedef struct _NotificationPrivate NotificationPrivate; + +struct _Notification +{ + GObject parent; + NotificationPrivate *priv; +}; + +struct _NotificationClass +{ + GObjectClass parent_class; +}; + +struct _NotificationPrivate { + gchar *app_name; + gsize app_name_length; + guint32 replaces_id; + gchar *app_icon; + gsize app_icon_length; + gchar *summary; + gsize summary_length; + gchar *body; + gsize body_length; + gint expire_timeout; +}; + +#define NOTIFICATION_GET_PRIVATE(o) \ + (G_TYPE_INSTANCE_GET_PRIVATE ((o), NOTIFICATION_TYPE, NotificationPrivate)) + +GType notification_get_type(void); +Notification *notification_new(void); +Notification *notification_new_from_dbus_message(GDBusMessage *); +gchar *notification_get_app_name(Notification *); +gchar *notification_get_app_icon(Notification *); +gchar *notification_get_summary(Notification *); +gchar *notification_get_body(Notification *); +void notification_print(Notification *); + +G_END_DECLS + +#endif /* __NOTIFICATION_H__ */ -- cgit v1.2.3