diff options
author | Ted Gould <ted@gould.cx> | 2010-07-12 09:26:50 -0500 |
---|---|---|
committer | Ted Gould <ted@gould.cx> | 2010-07-12 09:26:50 -0500 |
commit | 7ef183418aaee73864e44d93b32e80962fdea07a (patch) | |
tree | 4bf494ab0e9a5605e97f4066bb4ac9d5fb851462 | |
parent | 1ddd622e7f2ab0142c826459e1a38fec926c4dc6 (diff) | |
parent | 25b69bb08e3e5a3df7037f8ac786422ff53f6425 (diff) | |
download | ayatana-indicator-application-7ef183418aaee73864e44d93b32e80962fdea07a.tar.gz ayatana-indicator-application-7ef183418aaee73864e44d93b32e80962fdea07a.tar.bz2 ayatana-indicator-application-7ef183418aaee73864e44d93b32e80962fdea07a.zip |
Putting in a basic approver API.
-rw-r--r-- | .bzrignore | 3 | ||||
-rw-r--r-- | src/Makefile.am | 1 | ||||
-rw-r--r-- | src/application-service-appstore.c | 103 | ||||
-rw-r--r-- | src/application-service-appstore.h | 11 | ||||
-rw-r--r-- | src/application-service-watcher.c | 14 | ||||
-rw-r--r-- | src/dbus-shared.h | 2 | ||||
-rw-r--r-- | src/notification-approver.xml | 22 | ||||
-rw-r--r-- | src/notification-watcher.xml | 7 | ||||
-rw-r--r-- | tests/Makefile.am | 27 | ||||
-rw-r--r-- | tests/test-approver.c | 170 |
10 files changed, 356 insertions, 4 deletions
@@ -107,3 +107,6 @@ docs/reference/libappindicator-decl.txt.bak docs/reference/libappindicator-decl-list.txt.bak src/AppIndicator-0.1.vapi bindings/mono/policy.appindicator-sharp.dll +src/notification-approver-client.h +src/notification-approver-server.h +tests/test-approver diff --git a/src/Makefile.am b/src/Makefile.am index 787ba2f..68be1c0 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -116,6 +116,7 @@ libappindicator_la_LIBADD = \ DBUS_SPECS = \ dbus-properties.xml \ application-service.xml \ + notification-approver.xml \ notification-item.xml \ notification-watcher.xml diff --git a/src/application-service-appstore.c b/src/application-service-appstore.c index 886fe92..311fcb1 100644 --- a/src/application-service-appstore.c +++ b/src/application-service-appstore.c @@ -31,6 +31,7 @@ with this program. If not, see <http://www.gnu.org/licenses/>. #include "application-service-marshal.h" #include "dbus-properties-client.h" #include "dbus-shared.h" +#include "notification-approver-client.h" /* DBus Prototypes */ static gboolean _application_service_server_get_applications (ApplicationServiceAppstore * appstore, GPtrArray ** apps, GError ** error); @@ -53,9 +54,15 @@ static gboolean _application_service_server_get_applications (ApplicationService struct _ApplicationServiceAppstorePrivate { DBusGConnection * bus; GList * applications; + GList * approvers; AppLruFile * lrufile; }; +typedef struct _Approver Approver; +struct _Approver { + DBusGProxy * proxy; +}; + typedef struct _Application Application; struct _Application { gchar * id; @@ -94,6 +101,9 @@ static void application_service_appstore_dispose (GObject *object); static void application_service_appstore_finalize (GObject *object); static AppIndicatorStatus string_to_status(const gchar * status_string); static void apply_status (Application * app, AppIndicatorStatus status); +static void approver_free (gpointer papprover, gpointer user_data); +static void check_with_new_approver (gpointer papp, gpointer papprove); +static void check_with_old_approver (gpointer papprove, gpointer papp); G_DEFINE_TYPE (ApplicationServiceAppstore, application_service_appstore, G_TYPE_OBJECT); @@ -142,6 +152,7 @@ application_service_appstore_init (ApplicationServiceAppstore *self) ApplicationServiceAppstorePrivate * priv = APPLICATION_SERVICE_APPSTORE_GET_PRIVATE (self); priv->applications = NULL; + priv->approvers = NULL; priv->lrufile = NULL; GError * error = NULL; @@ -172,6 +183,12 @@ application_service_appstore_dispose (GObject *object) ((Application *)priv->applications->data)->dbus_object); } + if (priv->approvers != NULL) { + g_list_foreach(priv->approvers, approver_free, NULL); + g_list_free(priv->approvers); + priv->approvers = NULL; + } + G_OBJECT_CLASS (application_service_appstore_parent_class)->dispose (object); return; } @@ -236,11 +253,23 @@ get_all_properties_cb (DBusGProxy * proxy, GHashTable * properties, GError * err app->icon_path = g_strdup(""); } + /* TODO: Calling approvers, but we're ignoring the results. So, eh. */ + g_list_foreach(priv->approvers, check_with_old_approver, app); + apply_status(app, string_to_status(g_value_get_string(g_hash_table_lookup(properties, NOTIFICATION_ITEM_PROP_STATUS)))); return; } +/* Check the application against an approver */ +static void +check_with_old_approver (gpointer papprove, gpointer papp) +{ + /* Funny the parallels, eh? */ + check_with_new_approver(papp, papprove); + return; +} + /* Simple translation function -- could be optimized */ static AppIndicatorStatus string_to_status(const gchar * status_string) @@ -745,3 +774,77 @@ _application_service_server_get_applications (ApplicationServiceAppstore * appst return TRUE; } +/* Frees the data associated with an approver */ +static void +approver_free (gpointer papprover, gpointer user_data) +{ + Approver * approver = (Approver *)papprover; + g_return_if_fail(approver != NULL); + + if (approver->proxy != NULL) { + g_object_unref(approver->proxy); + approver->proxy = NULL; + } + + g_free(approver); + return; +} + +/* What did the approver tell us? */ +static void +approver_request_cb (DBusGProxy *proxy, gboolean OUT_approved, GError *error, gpointer userdata) +{ + g_debug("Approver responded: %s", OUT_approved ? "approve" : "rejected"); + return; +} + +/* Run the applications through the new approver */ +static void +check_with_new_approver (gpointer papp, gpointer papprove) +{ + Application * app = (Application *)papp; + Approver * approver = (Approver *)papprove; + + org_ayatana_StatusNotifierApprover_approve_item_async(approver->proxy, + app->id, + app->category, + 0, + app->dbus_name, + app->dbus_object, + approver_request_cb, + app); + + return; +} + +/* Adds a new approver to the app store */ +void +application_service_appstore_approver_add (ApplicationServiceAppstore * appstore, const gchar * dbus_name, const gchar * dbus_object) +{ + g_return_if_fail(IS_APPLICATION_SERVICE_APPSTORE(appstore)); + g_return_if_fail(dbus_name != NULL); + g_return_if_fail(dbus_object != NULL); + ApplicationServiceAppstorePrivate * priv = APPLICATION_SERVICE_APPSTORE_GET_PRIVATE (appstore); + + Approver * approver = g_new0(Approver, 1); + + GError * error = NULL; + approver->proxy = dbus_g_proxy_new_for_name_owner(priv->bus, + dbus_name, + dbus_object, + NOTIFICATION_APPROVER_DBUS_IFACE, + &error); + if (error != NULL) { + g_warning("Unable to get approver interface on '%s:%s' : %s", dbus_name, dbus_object, error->message); + g_error_free(error); + g_free(approver); + return; + } + + priv->approvers = g_list_prepend(priv->approvers, approver); + + g_list_foreach(priv->applications, check_with_new_approver, approver); + + return; +} + diff --git a/src/application-service-appstore.h b/src/application-service-appstore.h index 86d989b..e8ba8c1 100644 --- a/src/application-service-appstore.h +++ b/src/application-service-appstore.h @@ -57,11 +57,14 @@ struct _ApplicationServiceAppstore { ApplicationServiceAppstore * application_service_appstore_new (AppLruFile * lrufile); GType application_service_appstore_get_type (void); void application_service_appstore_application_add (ApplicationServiceAppstore * appstore, - const gchar * dbus_name, - const gchar * dbus_object); + const gchar * dbus_name, + const gchar * dbus_object); void application_service_appstore_application_remove (ApplicationServiceAppstore * appstore, - const gchar * dbus_name, - const gchar * dbus_object); + const gchar * dbus_name, + const gchar * dbus_object); +void application_service_appstore_approver_add (ApplicationServiceAppstore * appstore, + const gchar * dbus_name, + const gchar * dbus_object); G_END_DECLS diff --git a/src/application-service-watcher.c b/src/application-service-watcher.c index eff249d..4fe3bc7 100644 --- a/src/application-service-watcher.c +++ b/src/application-service-watcher.c @@ -34,6 +34,7 @@ static gboolean _notification_watcher_server_register_status_notifier_item (Appl static gboolean _notification_watcher_server_registered_status_notifier_items (ApplicationServiceWatcher * appwatcher, GArray ** apps); static gboolean _notification_watcher_server_protocol_version (ApplicationServiceWatcher * appwatcher, char ** version); static gboolean _notification_watcher_server_register_notification_host (ApplicationServiceWatcher * appwatcher, const gchar * host); +static gboolean _notification_watcher_server_register_notification_approver (ApplicationServiceWatcher * appwatcher, const gchar * path, const GArray * categories, DBusGMethodInvocation * method); static gboolean _notification_watcher_server_is_notification_host_registered (ApplicationServiceWatcher * appwatcher, gboolean * haveHost); static void get_name_cb (DBusGProxy * proxy, guint status, GError * error, gpointer data); @@ -249,3 +250,16 @@ get_name_cb (DBusGProxy * proxy, guint status, GError * error, gpointer data) return; } + +static gboolean +_notification_watcher_server_register_notification_approver (ApplicationServiceWatcher * appwatcher, const gchar * path, const GArray * categories, DBusGMethodInvocation * method) +{ + ApplicationServiceWatcherPrivate * priv = APPLICATION_SERVICE_WATCHER_GET_PRIVATE(appwatcher); + + application_service_appstore_approver_add(priv->appstore, + dbus_g_method_get_sender(method), + path); + + dbus_g_method_return(method, G_TYPE_NONE); + return TRUE; +} diff --git a/src/dbus-shared.h b/src/dbus-shared.h index f158b1c..1d8d89c 100644 --- a/src/dbus-shared.h +++ b/src/dbus-shared.h @@ -31,3 +31,5 @@ with this program. If not, see <http://www.gnu.org/licenses/>. #define NOTIFICATION_ITEM_DBUS_IFACE "org.kde.StatusNotifierItem" #define NOTIFICATION_ITEM_DEFAULT_OBJ "/StatusNotifierItem" +#define NOTIFICATION_APPROVER_DBUS_IFACE "org.ayatana.StatusNotifierApprover" + diff --git a/src/notification-approver.xml b/src/notification-approver.xml new file mode 100644 index 0000000..b1e69b9 --- /dev/null +++ b/src/notification-approver.xml @@ -0,0 +1,22 @@ +<?xml version="1.0" encoding="UTF-8"?> +<node name="/"> + <interface name="org.ayatana.StatusNotifierApprover"> + +<!-- Methods --> + <method name="ApproveItem"> + <!-- KSNI ID --> + <arg type="s" name="id" direction="in" /> + <!-- KSNI Category --> + <arg type="s" name="category" direction="in" /> + <!-- Application PID --> + <arg type="u" name="pid" direction="in" /> + <!-- Application DBus Address --> + <arg type="s" name="address" direction="in" /> + <!-- Application DBus Path for KSNI interface --> + <arg type="o" name="path" direction="in" /> + <!-- So, what do you think? --> + <arg type="b" name="approved" direction="out" /> + </method> + + </interface> +</node> diff --git a/src/notification-watcher.xml b/src/notification-watcher.xml index c2324f1..cc7882d 100644 --- a/src/notification-watcher.xml +++ b/src/notification-watcher.xml @@ -22,6 +22,13 @@ <method name="IsNotificationHostRegistered"> <arg type="b" name="hasHost" direction="out" /> </method> + <method name="RegisterNotificationApprover"> + <annotation name="org.freedesktop.DBus.GLib.Async" value="true" /> + <!-- The path where to find the approver interface --> + <arg type="o" name="path" direction="in" /> + <!-- List of categories to approve, none represents all --> + <arg type="as" name="categories" direction="in" /> + </method> <!-- Signals --> <signal name="ServiceRegistered"> diff --git a/tests/Makefile.am b/tests/Makefile.am index 8d356bc..867d4de 100644 --- a/tests/Makefile.am +++ b/tests/Makefile.am @@ -1,5 +1,6 @@ check_PROGRAMS = \ + test-approver \ test-libappindicator \ test-libappindicator-dbus-client \ test-libappindicator-dbus-server \ @@ -99,6 +100,32 @@ test_libappindicator_status_server_LDADD = \ $(top_builddir)/src/libappindicator.la ######################################### +## test-approver +######################################### + +test_approver_SOURCES = \ + test-approver.c + +test_approver_CFLAGS = \ + $(INDICATOR_CFLAGS) \ + -Wall -Werror \ + -I$(top_srcdir)/src \ + -I$(top_builddir)/src + +test_approver_LDADD = \ + $(INDICATOR_LIBS) \ + $(top_builddir)/src/libappindicator.la + +test-approver-tester: test-approver Makefile.am + @echo "#!/bin/bash" > $@ + @echo . $(srcdir)/run-xvfb.sh >> $@ + @echo $(DBUS_RUNNER) --task $(builddir)/test-approver --task-name Approver --task $(top_builddir)/src/indicator-application-service --task-name Service --ignore-return >> $@ + @chmod +x $@ + +TESTS += test-approver-tester + + +######################################### ## test-libappindicator-fallback ######################################### diff --git a/tests/test-approver.c b/tests/test-approver.c new file mode 100644 index 0000000..30beb30 --- /dev/null +++ b/tests/test-approver.c @@ -0,0 +1,170 @@ +#include <glib.h> +#include <glib-object.h> + +#include <dbus/dbus-glib-bindings.h> + +#include "notification-watcher-client.h" +#include "dbus-shared.h" +#include "app-indicator.h" + +#define APPROVER_PATH "/my/approver" + +#define INDICATOR_ID "test-indicator-id" +#define INDICATOR_ICON "test-indicator-icon-name" +#define INDICATOR_CATEGORY APP_INDICATOR_CATEGORY_APPLICATION_STATUS + +#define TEST_APPROVER_TYPE (test_approver_get_type ()) +#define TEST_APPROVER(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), TEST_APPROVER_TYPE, TestApprover)) +#define TEST_APPROVER_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), TEST_APPROVER_TYPE, TestApproverClass)) +#define IS_TEST_APPROVER(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), TEST_APPROVER_TYPE)) +#define IS_TEST_APPROVER_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), TEST_APPROVER_TYPE)) +#define TEST_APPROVER_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), TEST_APPROVER_TYPE, TestApproverClass)) + +typedef struct _TestApprover TestApprover; +typedef struct _TestApproverClass TestApproverClass; + +struct _TestApproverClass { + GObjectClass parent_class; +}; + +struct _TestApprover { + GObject parent; +}; + +GType test_approver_get_type (void); + +static void test_approver_class_init (TestApproverClass *klass); +static void test_approver_init (TestApprover *self); +static gboolean _notification_approver_server_approve_item (TestApprover * ta, const gchar * id, const gchar * category, guint pid, const gchar * address, const gchar * path, gboolean * approved, GError ** error); + +#include "../src/notification-approver-server.h" + +GMainLoop * main_loop = NULL; +DBusGConnection * session_bus = NULL; +DBusGProxy * bus_proxy = NULL; +AppIndicator * app_indicator = NULL; +gboolean passed = FALSE; + +G_DEFINE_TYPE (TestApprover, test_approver, G_TYPE_OBJECT); + +static void +test_approver_class_init (TestApproverClass *klass) +{ + dbus_g_object_type_install_info(TEST_APPROVER_TYPE, + &dbus_glib__notification_approver_server_object_info); + + return; +} + +static void +test_approver_init (TestApprover *self) +{ + dbus_g_connection_register_g_object(session_bus, + APPROVER_PATH, + G_OBJECT(self)); + + return; +} + +static gboolean +_notification_approver_server_approve_item (TestApprover * ta, const gchar * id, const gchar * category, guint pid, const gchar * address, const gchar * path, gboolean * approved, GError ** error) +{ + *approved = TRUE; + g_debug("Asked to approve indicator"); + + if (g_strcmp0(id, INDICATOR_ID) == 0) { + passed = TRUE; + } + + g_main_loop_quit(main_loop); + + return TRUE; +} + +static void +register_cb (DBusGProxy * proxy, GError * error, gpointer user_data) +{ + if (error != NULL) { + g_warning("Unable to register approver: %s", error->message); + g_error_free(error); + g_main_loop_quit(main_loop); + return; + } + + g_debug("Building App Indicator"); + app_indicator = app_indicator_new(INDICATOR_ID, INDICATOR_ICON, INDICATOR_CATEGORY); + + GtkWidget * menu = gtk_menu_new(); + GtkWidget * mi = gtk_image_menu_item_new_from_stock(GTK_STOCK_ABOUT, NULL); + gtk_menu_shell_append(GTK_MENU_SHELL(menu), mi); + + app_indicator_set_menu(app_indicator, GTK_MENU(menu)); + + return; +} + +gint owner_count = 0; +gboolean +check_for_service (gpointer user_data) +{ + g_debug("Checking for Watcher"); + + if (owner_count > 100) { + g_warning("Couldn't find watcher after 100 tries."); + g_main_loop_quit(main_loop); + return FALSE; + } + + owner_count++; + + gboolean has_owner = FALSE; + org_freedesktop_DBus_name_has_owner(bus_proxy, NOTIFICATION_WATCHER_DBUS_ADDR, &has_owner, NULL); + + if (has_owner) { + const char * cats = NULL; + DBusGProxy * proxy = dbus_g_proxy_new_for_name(session_bus, + NOTIFICATION_WATCHER_DBUS_ADDR, + NOTIFICATION_WATCHER_DBUS_OBJ, + NOTIFICATION_WATCHER_DBUS_IFACE); + + g_debug("Registering Approver"); + org_kde_StatusNotifierWatcher_register_notification_approver_async (proxy, APPROVER_PATH, &cats, register_cb, NULL); + + return FALSE; + } + + return TRUE; +} + +int +main (int argc, char ** argv) +{ + GError * error = NULL; + + gtk_init(&argc, &argv); + g_debug("Initing"); + + session_bus = dbus_g_bus_get(DBUS_BUS_SESSION, &error); + if (error != NULL) { + g_warning("Unable to get session bus: %s", error->message); + g_error_free(error); + return -1; + } + + TestApprover * approver = g_object_new(TEST_APPROVER_TYPE, NULL); + + bus_proxy = dbus_g_proxy_new_for_name(session_bus, DBUS_SERVICE_DBUS, DBUS_PATH_DBUS, DBUS_INTERFACE_DBUS); + + g_timeout_add(100, check_for_service, NULL); + + main_loop = g_main_loop_new(NULL, FALSE); + g_main_loop_run(main_loop); + + g_object_unref(approver); + + if (!passed) { + return -1; + } + + return 0; +} |