aboutsummaryrefslogtreecommitdiff
path: root/libindicate
diff options
context:
space:
mode:
Diffstat (limited to 'libindicate')
-rw-r--r--libindicate/Makefile.am44
-rw-r--r--libindicate/interests.h5
-rw-r--r--libindicate/listener.c145
-rw-r--r--libindicate/listener.h5
-rw-r--r--libindicate/server.c13
5 files changed, 195 insertions, 17 deletions
diff --git a/libindicate/Makefile.am b/libindicate/Makefile.am
index c1900a6..3ad6247 100644
--- a/libindicate/Makefile.am
+++ b/libindicate/Makefile.am
@@ -1,3 +1,6 @@
+MARSHAL_PREFIX = indicate_marshal
+MARSHAL_FILE = indicate-marshal
+ENUM_FILE = indicate-enum-types
INCLUDES= \
-DG_LOG_DOMAIN=\"libindicate\"
@@ -14,7 +17,9 @@ BUILT_SOURCES = \
dbus-listener-server.h \
dbus-listener-client.h \
listener-marshal.c \
- listener-marshal.h
+ listener-marshal.h \
+ $(ENUM_FILE).h \
+ $(ENUM_FILE).c
lib_LTLIBRARIES = \
libindicate.la
@@ -26,7 +31,8 @@ indicate_headers = \
indicator-message.h \
listener.h \
server.h \
- interests.h
+ interests.h \
+ $(ENUM_FILE).h
libindicateinclude_HEADERS = \
$(indicate_headers)
@@ -37,6 +43,7 @@ libindicate_la_SOURCES = \
dbus-indicate-client.h \
dbus-listener-server.h \
dbus-listener-client.h \
+ indicate-enum-types.c \
server.c \
listener.c \
listener-marshal.c \
@@ -97,6 +104,39 @@ listener-marshal.c: $(srcdir)/listener-marshal.list
pkgconfig_DATA = indicate.pc
pkgconfigdir = $(libdir)/pkgconfig
+$(ENUM_FILE).h: s-enum-types-h
+ @true
+s-enum-types-h: $(indicate_headers) Makefile
+ ( cd $(srcdir) && glib-mkenums \
+ --fhead "#ifndef _INDICATE_ENUM_TYPES_H_\n#define _INDICATE_ENUM_TYPES_H_\n\n#include <glib-object.h>\n\nG_BEGIN_DECLS\n" \
+ --fprod "/* enumerations from \"@filename@\" */\n" \
+ --vhead "GType @enum_name@_get_type(void);\n#define INDICATE_TYPE_@ENUMSHORT@ (@enum_name@_get_type())\n" \
+ --ftail "G_END_DECLS\n\n#endif /* _INDICATE_ENUM_TYPES_H_ */" \
+ interests.h ) > tmp-$(ENUM_FILE).h \
+ && (cmp -s tmp-$(ENUM_FILE).h $(ENUM_FILE).h || cp tmp-$(ENUM_FILE).h $(ENUM_FILE).h ) \
+ && rm -f tmp-$(ENUM_FILE).h \
+ && echo timestamp > $(@F)
+
+$(ENUM_FILE).c: s-enum-types-c
+ @true
+s-enum-types-c: $(indicate_headers) Makefile
+ ( cd $(srcdir) && glib-mkenums \
+ --fhead "#include \"interests.h\"\n#include <glib-object.h>" \
+ --fprod "\n/* enumerations from \"@filename@\" */" \
+ --vhead "GType\n@enum_name@_get_type (void)\n{\n static GType etype = 0;\n if (etype == 0) {\n static const G@Type@Value values[] = {" \
+ --vprod " { @VALUENAME@, \"@VALUENAME@\", \"@valuenick@\" }," \
+ --vtail " { 0, NULL, NULL }\n };\n etype = g_@type@_register_static (\"@EnumName@\", values);\n }\n return etype;\n}\n" \
+ interests.h ) > tmp-$(ENUM_FILE).c \
+ && (cmp -s tmp-$(ENUM_FILE).c $(ENUM_FILE).c || cp tmp-$(ENUM_FILE).c $(ENUM_FILE).c ) \
+ && rm -f tmp-$(ENUM_FILE).c \
+ && echo timestamp > $(@F)
+
+CLEANFILES = \
+ $(ENUM_FILE).c \
+ $(ENUM_FILE).h \
+ s-enum-types-c \
+ s-enum-types-h
+
if USE_GIR
gobjectintrospection_gir_DATA = \
diff --git a/libindicate/interests.h b/libindicate/interests.h
index 70c52d9..1c6215a 100644
--- a/libindicate/interests.h
+++ b/libindicate/interests.h
@@ -34,8 +34,7 @@ License version 3 and version 2.1 along with this program. If not, see
G_BEGIN_DECLS
-typedef enum _IndicateInterests IndicateInterests;
-enum _IndicateInterests {
+typedef enum {
INDICATE_INTEREST_NONE, /**< We're of no interest */
INDICATE_INTEREST_SERVER_DISPLAY, /**< Displays the server's existance to the user */
INDICATE_INTEREST_SERVER_SIGNAL, /**< Will send signals to the server to be displayed */
@@ -43,7 +42,7 @@ enum _IndicateInterests {
INDICATE_INTEREST_INDICATOR_SIGNAL, /**< Will return signals based on individual indicators being responded to */
INDICATE_INTEREST_INDICATOR_COUNT, /**< Only displays a count of the indicators */
INDICATE_INTEREST_LAST /**< Makes merges and counting easier */
-};
+} IndicateInterests;
G_END_DECLS
diff --git a/libindicate/listener.c b/libindicate/listener.c
index 3cc84b6..bd3639d 100644
--- a/libindicate/listener.c
+++ b/libindicate/listener.c
@@ -27,6 +27,9 @@ License version 3 and version 2.1 along with this program. If not, see
<http://www.gnu.org/licenses/>
*/
+#include <libxml/parser.h>
+#include <libxml/tree.h>
+
#include "listener.h"
#include "listener-marshal.h"
#include <dbus/dbus-glib-bindings.h>
@@ -89,6 +92,7 @@ typedef struct {
gchar * type;
IndicateListener * listener;
GHashTable * indicators;
+ guint introspect_level;
IndicateListenerServer server;
} proxy_t;
@@ -129,6 +133,7 @@ static void proxy_indicator_modified (DBusGProxy * proxy, guint id, const gchar
static void proxy_get_indicator_list (DBusGProxy * proxy, GArray * indicators, GError * error, gpointer data);
static void proxy_get_indicator_type (DBusGProxy * proxy, gchar * type, GError * error, gpointer data);
static void proxy_indicators_free (gpointer data);
+static void introspect_this (DBusGProxy * proxy, char * OUT_data, GError * error, gpointer data);
/* DBus interface */
gboolean _indicate_listener_get_indicator_servers (IndicateListener * listener, GList * servers);
@@ -154,35 +159,35 @@ indicate_listener_class_init (IndicateListenerClass * class)
G_STRUCT_OFFSET (IndicateListenerClass, indicator_added),
NULL, NULL,
_indicate_listener_marshal_VOID__POINTER_POINTER_STRING,
- G_TYPE_NONE, 3, G_TYPE_POINTER, G_TYPE_POINTER, G_TYPE_STRING);
+ G_TYPE_NONE, 3, INDICATE_TYPE_LISTENER_SERVER, INDICATE_TYPE_LISTENER_INDICATOR, G_TYPE_STRING);
signals[INDICATOR_REMOVED] = g_signal_new(INDICATE_LISTENER_SIGNAL_INDICATOR_REMOVED,
G_TYPE_FROM_CLASS (class),
G_SIGNAL_RUN_LAST,
G_STRUCT_OFFSET (IndicateListenerClass, indicator_removed),
NULL, NULL,
_indicate_listener_marshal_VOID__POINTER_POINTER_STRING,
- G_TYPE_NONE, 3, G_TYPE_POINTER, G_TYPE_POINTER, G_TYPE_STRING);
+ G_TYPE_NONE, 3, INDICATE_TYPE_LISTENER_SERVER, INDICATE_TYPE_LISTENER_INDICATOR, G_TYPE_STRING);
signals[INDICATOR_MODIFIED] = g_signal_new(INDICATE_LISTENER_SIGNAL_INDICATOR_MODIFIED,
G_TYPE_FROM_CLASS (class),
G_SIGNAL_RUN_LAST,
G_STRUCT_OFFSET (IndicateListenerClass, indicator_modified),
NULL, NULL,
_indicate_listener_marshal_VOID__POINTER_POINTER_STRING_STRING,
- G_TYPE_NONE, 4, G_TYPE_POINTER, G_TYPE_POINTER, G_TYPE_STRING, G_TYPE_STRING);
+ G_TYPE_NONE, 4, INDICATE_TYPE_LISTENER_SERVER, INDICATE_TYPE_LISTENER_INDICATOR, G_TYPE_STRING, G_TYPE_STRING);
signals[SERVER_ADDED] = g_signal_new(INDICATE_LISTENER_SIGNAL_SERVER_ADDED,
G_TYPE_FROM_CLASS (class),
G_SIGNAL_RUN_LAST,
G_STRUCT_OFFSET (IndicateListenerClass, server_added),
NULL, NULL,
_indicate_listener_marshal_VOID__POINTER_STRING,
- G_TYPE_NONE, 2, G_TYPE_POINTER, G_TYPE_STRING);
+ G_TYPE_NONE, 2, INDICATE_TYPE_LISTENER_SERVER, G_TYPE_STRING);
signals[SERVER_REMOVED] = g_signal_new(INDICATE_LISTENER_SIGNAL_SERVER_REMOVED,
G_TYPE_FROM_CLASS (class),
G_SIGNAL_RUN_LAST,
G_STRUCT_OFFSET (IndicateListenerClass, server_removed),
NULL, NULL,
_indicate_listener_marshal_VOID__POINTER_STRING,
- G_TYPE_NONE, 2, G_TYPE_POINTER, G_TYPE_STRING);
+ G_TYPE_NONE, 2, INDICATE_TYPE_LISTENER_SERVER, G_TYPE_STRING);
dbus_g_object_register_marshaller(_indicate_listener_marshal_VOID__UINT_STRING,
G_TYPE_NONE,
@@ -499,13 +504,9 @@ todo_idle (gpointer data)
priv->proxies_possible = g_list_prepend(priv->proxies_possible, proxyt);
- /* I think that we need to have this as there is a race
- * condition here. If someone comes on the bus and we get
- * that message, but before we set up the handler for the ServerShow
- * signal it gets sent, we wouldn't get it. So then we would
- * miss an indicator server coming on the bus. I'd like to not
- * generate a warning in every app with DBus though. */
- indicate_listener_server_get_type(listener, &proxyt->server, get_type_cb, proxyt);
+ /* Look through the introspection data to see if this
+ is already a server */
+ introspect_this (NULL, NULL, NULL, proxyt);
return TRUE;
}
@@ -1002,6 +1003,10 @@ interest_cb (DBusGProxy *proxy, GError *error, gpointer userdata)
void
indicate_listener_server_show_interest (IndicateListener * listener, IndicateListenerServer * server, IndicateInterests interest)
{
+ if (!(interest > INDICATE_INTEREST_NONE && interest < INDICATE_INTEREST_LAST)) {
+ return;
+ }
+
if (!server->interests[interest]) {
org_freedesktop_indicator_show_interest_async (server->proxy, interest_to_string(interest), interest_cb, server);
server->interests[interest] = TRUE;
@@ -1025,3 +1030,119 @@ indicate_listener_server_check_interest (IndicateListener * listener, IndicateLi
return server->interests[interest];
}
+GType
+indicate_listener_server_get_gtype (void)
+{
+ static GType our_type = 0;
+
+ if (our_type == 0)
+ our_type = g_pointer_type_register_static ("IndicateListenerServer");
+
+ return our_type;
+}
+
+GType
+indicate_listener_indicator_get_gtype (void)
+{
+ static GType our_type = 0;
+
+ if (our_type == 0)
+ our_type = g_pointer_type_register_static ("IndicateListenerIndicator");
+
+ return our_type;
+}
+
+static const gchar * _introspector_path[] = {"", "org", "freedesktop", "indicate", NULL};
+static const gchar * _introspector_fullpath[] = {"/", "/org", "/org/freedesktop", "/org/freedesktop/indicate", NULL};
+static const gchar * _introspector_interface = "org.freedesktop.indicator";
+
+static void
+introspect_this (DBusGProxy * proxy, char * OUT_data, GError * error, gpointer data)
+{
+ /* g_debug("Introspect this:\n%s", OUT_data); */
+ proxy_t * server = (proxy_t *)data;
+ if (proxy != NULL) {
+ g_object_unref(proxy);
+ }
+ if (error != NULL) {
+ /* We probably couldn't introspect that far up. That's
+ life, it happens. Or there's a timeout, that happens
+ too, I guess some apps are too busy for us. */
+ /* g_debug("Introspection error on %s object %s: %s", server->name, _introspector_fullpath[server->introspect_level], error->message); */
+ return;
+ }
+
+ if (OUT_data != NULL) {
+ xmlDocPtr xmldoc;
+ /* Parse the XML */
+ xmldoc = xmlReadMemory(OUT_data, g_utf8_strlen(OUT_data, 16*1024), "introspection.xml", NULL, 0);
+
+ /* Check for root being "node" */
+ xmlNodePtr root = xmlDocGetRootElement(xmldoc);
+ if (g_strcmp0(root->name, "node") != 0) {
+ xmlFreeDoc(xmldoc);
+ g_warning("Introspection data from %s is not valid: %s", server->name, OUT_data);
+ return;
+ }
+
+ server->introspect_level += 1;
+ const gchar * nodename = NULL;
+ const gchar * nameval = NULL;
+ if (_introspector_path[server->introspect_level] == NULL) {
+ /* We're looking for our interface */
+ nodename = "interface";
+ nameval = _introspector_interface;
+ } else {
+ /* We're looking for our next node */
+ nodename = "node";
+ nameval = _introspector_path[server->introspect_level];
+ }
+
+ gboolean found = FALSE;
+ xmlNodePtr children;
+ for (children = root->children; children != NULL; children = children->next) {
+ gchar * xmlnameval = NULL;
+ if (g_strcmp0(children->name, nodename) == 0) {
+ xmlAttrPtr attrib;
+ for (attrib = children->properties; attrib != NULL; attrib = attrib->next) {
+ if (g_strcmp0(attrib->name, "name") == 0) {
+ if (attrib->children != NULL) {
+ xmlnameval = attrib->children->content;
+ }
+ break;
+ }
+ }
+
+ if (!g_strcmp0(nameval, xmlnameval)) {
+ found = TRUE;
+ break;
+ }
+ }
+ }
+
+ xmlFreeDoc(xmldoc);
+
+ if (!found) {
+ /* Ah, nothing we're interested in */
+ return;
+ }
+
+ if (_introspector_path[server->introspect_level] == NULL) {
+ /* If we've found the interface at the end of the tree, whoo! hoo! */
+ /* Now we know it's safe to get the type on it */
+ indicate_listener_server_get_type(server->listener, &server->server, get_type_cb, server);
+ return;
+ }
+ } else {
+ server->introspect_level = 0;
+ }
+
+ DBusGProxy * newproxy = dbus_g_proxy_new_for_name(server->connection,
+ server->name,
+ _introspector_fullpath[server->introspect_level],
+ DBUS_INTERFACE_INTROSPECTABLE);
+
+ org_freedesktop_DBus_Introspectable_introspect_async(newproxy, introspect_this, server);
+
+ return;
+}
diff --git a/libindicate/listener.h b/libindicate/listener.h
index 0fdaa9b..5bfd298 100644
--- a/libindicate/listener.h
+++ b/libindicate/listener.h
@@ -59,7 +59,12 @@ G_BEGIN_DECLS
#define INDICATE_LISTENER_INDICATOR_ID(indicator) (indicate_listener_indicator_get_id(indicator))
typedef struct _IndicateListenerServer IndicateListenerServer;
+#define INDICATE_TYPE_LISTENER_SERVER (indicate_listener_server_get_gtype ())
+GType indicate_listener_server_get_gtype (void) G_GNUC_CONST;
+
typedef struct _IndicateListenerIndicator IndicateListenerIndicator;
+#define INDICATE_TYPE_LISTENER_INDICATOR (indicate_listener_indicator_get_gtype ())
+GType indicate_listener_indicator_get_gtype (void) G_GNUC_CONST;
typedef struct _IndicateListener IndicateListener;
struct _IndicateListener {
diff --git a/libindicate/server.c b/libindicate/server.c
index e3d071c..d42fe61 100644
--- a/libindicate/server.c
+++ b/libindicate/server.c
@@ -1207,6 +1207,19 @@ _indicate_server_remove_interest (IndicateServer * server, gchar * interest, DBu
return FALSE;
}
+gboolean
+indicate_server_check_interest (IndicateServer * server, IndicateInterests interest)
+{
+ IndicateServerClass * class = INDICATE_SERVER_GET_CLASS(server);
+
+ if (class != NULL && class->check_interest != NULL) {
+ return class->check_interest (server, interest);
+ }
+
+ g_warning("check_interest function not implemented in this server class: %s", G_OBJECT_TYPE_NAME(server));
+ return FALSE;
+}
+
/* Signal emission functions for sub-classes of the server */
void
indicate_server_emit_indicator_added (IndicateServer *server, guint id, const gchar *type)