aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorTed Gould <ted@gould.cx>2010-08-19 09:48:16 -0500
committerTed Gould <ted@gould.cx>2010-08-19 09:48:16 -0500
commite930a47a4fd7d139ef9de26eae025037d4a9c608 (patch)
treee2b7d7032b8742c86b6350e02abba48577f94ae4
parentfbb932301868675cfad681c6701d46c0b741865e (diff)
parent72c93f2c3aea90bc18a694a723915f33701a021b (diff)
downloadayatana-indicator-application-e930a47a4fd7d139ef9de26eae025037d4a9c608.tar.gz
ayatana-indicator-application-e930a47a4fd7d139ef9de26eae025037d4a9c608.tar.bz2
ayatana-indicator-application-e930a47a4fd7d139ef9de26eae025037d4a9c608.zip
Changing the state machine to have approvers actually aprove things.
-rw-r--r--src/application-service-appstore.c224
1 files changed, 159 insertions, 65 deletions
diff --git a/src/application-service-appstore.c b/src/application-service-appstore.c
index 9764798..6df1b49 100644
--- a/src/application-service-appstore.c
+++ b/src/application-service-appstore.c
@@ -67,9 +67,15 @@ struct _ApplicationServiceAppstorePrivate {
GHashTable * ordering_overrides;
};
+typedef enum {
+ VISIBLE_STATE_HIDDEN,
+ VISIBLE_STATE_SHOWN
+} visible_state_t;
+
typedef struct _Approver Approver;
struct _Approver {
DBusGProxy * proxy;
+ gboolean destroy_by_proxy;
};
typedef struct _Application Application;
@@ -91,6 +97,8 @@ struct _Application {
gchar * guide;
gboolean currently_free;
guint ordering_index;
+ GList * approved_by;
+ visible_state_t visible_state;
};
#define APPLICATION_SERVICE_APPSTORE_GET_PRIVATE(o) \
@@ -113,10 +121,11 @@ static void application_service_appstore_class_init (ApplicationServiceAppstoreC
static void application_service_appstore_init (ApplicationServiceAppstore *self);
static void application_service_appstore_dispose (GObject *object);
static void application_service_appstore_finalize (GObject *object);
+static gint app_sort_func (gconstpointer a, gconstpointer b, gpointer userdata);
static void load_override_file (GHashTable * hash, const gchar * filename);
static AppIndicatorStatus string_to_status(const gchar * status_string);
+static void apply_status (Application * app);
static AppIndicatorCategory string_to_cat(const gchar * cat_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);
@@ -226,7 +235,7 @@ application_service_appstore_dispose (GObject *object)
}
if (priv->approvers != NULL) {
- g_list_foreach(priv->approvers, approver_free, NULL);
+ g_list_foreach(priv->approvers, approver_free, object);
g_list_free(priv->approvers);
priv->approvers = NULL;
}
@@ -312,6 +321,7 @@ get_all_properties_cb (DBusGProxy * proxy, GHashTable * properties, GError * err
{
if (error != NULL) {
g_warning("Unable to get properties: %s", error->message);
+ /* TODO: We need to free all the application data here */
return;
}
@@ -331,6 +341,8 @@ get_all_properties_cb (DBusGProxy * proxy, GHashTable * properties, GError * err
app->id = g_value_dup_string(g_hash_table_lookup(properties, NOTIFICATION_ITEM_PROP_ID));
app->category = g_value_dup_string(g_hash_table_lookup(properties, NOTIFICATION_ITEM_PROP_CATEGORY));
+ app->status = string_to_status(g_value_get_string(g_hash_table_lookup(properties, NOTIFICATION_ITEM_PROP_STATUS)));
+
ApplicationServiceAppstorePrivate * priv = app->appstore->priv;
app->icon = g_value_dup_string(g_hash_table_lookup(properties, NOTIFICATION_ITEM_PROP_ICON_NAME));
@@ -382,10 +394,10 @@ get_all_properties_cb (DBusGProxy * proxy, GHashTable * properties, GError * err
app->guide = g_strdup("");
}
- /* TODO: Calling approvers, but we're ignoring the results. So, eh. */
+ priv->applications = g_list_insert_sorted_with_data (priv->applications, app, app_sort_func, NULL);
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))));
+ apply_status(app);
return;
}
@@ -443,18 +455,34 @@ string_to_cat(const gchar * cat_string)
/* A small helper function to get the position of an application
- in the app list. */
+ in the app list of the applications that are visible. */
static gint
get_position (Application * app) {
ApplicationServiceAppstore * appstore = app->appstore;
ApplicationServiceAppstorePrivate * priv = appstore->priv;
- GList * applistitem = g_list_find(priv->applications, app);
- if (applistitem == NULL) {
- return -1;
+ GList * lapp;
+ gint count;
+
+ /* Go through the list and try to find ours */
+ for (lapp = priv->applications, count = 0; lapp != NULL; lapp = g_list_next(lapp), count++) {
+ if (lapp->data == app) {
+ break;
+ }
+
+ /* If the selected app isn't visible let's not
+ count it's position */
+ Application * thisapp = (Application *)(lapp->data);
+ if (thisapp->visible_state == VISIBLE_STATE_HIDDEN) {
+ count--;
+ }
}
- return g_list_position(priv->applications, applistitem);
+ if (lapp == NULL) {
+ return -1;
+ }
+
+ return count;
}
/* A simple global function for dealing with freeing the information
@@ -506,6 +534,9 @@ application_free (Application * app)
if (app->guide != NULL) {
g_free(app->guide);
}
+ if (app->approved_by != NULL) {
+ g_list_free(app->approved_by);
+ }
g_free(app);
return;
@@ -519,35 +550,17 @@ application_removed_cb (DBusGProxy * proxy, gpointer userdata)
Application * app = (Application *)userdata;
/* Remove from the panel */
- apply_status(app, APP_INDICATOR_STATUS_PASSIVE);
+ app->status = APP_INDICATOR_STATUS_PASSIVE;
+ apply_status(app);
+
+ /* Remove from the application list */
+ app->appstore->priv->applications = g_list_remove(app->appstore->priv->applications, app);
/* Destroy the data */
application_free(app);
return;
}
-static gboolean
-can_add_application (GList *applications, Application *app)
-{
- if (applications)
- {
- GList *l = NULL;
-
- for (l = applications; l != NULL; l = g_list_next (l))
- {
- Application *tmp_app = (Application *)l->data;
-
- if (g_strcmp0 (tmp_app->dbus_name, app->dbus_name) == 0 &&
- g_strcmp0 (tmp_app->dbus_object, app->dbus_object) == 0)
- {
- return FALSE;
- }
- }
- }
-
- return TRUE;
-}
-
/* This function takes two Application structure
pointers and uses their ordering index to compare them. */
static gint
@@ -562,49 +575,53 @@ app_sort_func (gconstpointer a, gconstpointer b, gpointer userdata)
it removes it from the panel. If we're coming online, then
it add it to the panel. Otherwise it changes the icon. */
static void
-apply_status (Application * app, AppIndicatorStatus status)
+apply_status (Application * app)
{
- if (app->status == status) {
- return;
- }
- g_debug("Changing app status to: %d", status);
-
ApplicationServiceAppstore * appstore = app->appstore;
ApplicationServiceAppstorePrivate * priv = appstore->priv;
+ /* g_debug("Applying status. Status: %d Approved by: %d Approvers: %d Visible: %d", app->status, g_list_length(app->approved_by), g_list_length(priv->approvers), app->visible_state); */
+
+ visible_state_t goal_state = VISIBLE_STATE_HIDDEN;
+
+ if (app->status != APP_INDICATOR_STATUS_PASSIVE &&
+ g_list_length(app->approved_by) >= g_list_length(priv->approvers)) {
+ goal_state = VISIBLE_STATE_SHOWN;
+ }
+
+ /* Nothing needs to change, we're good */
+ if (app->visible_state == goal_state) {
+ return;
+ }
+
/* This means we're going off line */
- if (status == APP_INDICATOR_STATUS_PASSIVE) {
+ if (goal_state == VISIBLE_STATE_HIDDEN) {
gint position = get_position(app);
if (position == -1) return;
g_signal_emit(G_OBJECT(appstore),
signals[APPLICATION_REMOVED], 0,
position, TRUE);
- priv->applications = g_list_remove(priv->applications, app);
} else {
/* Figure out which icon we should be using */
gchar * newicon = app->icon;
- if (status == APP_INDICATOR_STATUS_ATTENTION && app->aicon != NULL && app->aicon[0] != '\0') {
+ if (app->status == APP_INDICATOR_STATUS_ATTENTION && app->aicon != NULL && app->aicon[0] != '\0') {
newicon = app->aicon;
}
/* Determine whether we're already shown or not */
- if (app->status == APP_INDICATOR_STATUS_PASSIVE) {
- if (can_add_application (priv->applications, app)) {
- /* Put on panel */
- priv->applications = g_list_insert_sorted_with_data (priv->applications, app, app_sort_func, NULL);
-
- g_signal_emit(G_OBJECT(app->appstore),
- signals[APPLICATION_ADDED], 0,
- newicon,
- g_list_index(priv->applications, app), /* Position */
- app->dbus_name,
- app->menu,
- app->icon_theme_path,
- app->label,
- app->guide,
- TRUE);
- }
+ if (app->visible_state == VISIBLE_STATE_HIDDEN) {
+ /* Put on panel */
+ g_signal_emit(G_OBJECT(app->appstore),
+ signals[APPLICATION_ADDED], 0,
+ newicon,
+ g_list_index(priv->applications, app), /* Position */
+ app->dbus_name,
+ app->menu,
+ app->icon_theme_path,
+ app->label,
+ app->guide,
+ TRUE);
} else {
/* Icon update */
gint position = get_position(app);
@@ -616,7 +633,7 @@ apply_status (Application * app, AppIndicatorStatus status)
}
}
- app->status = status;
+ app->visible_state = goal_state;
return;
}
@@ -646,7 +663,7 @@ new_icon_cb (DBusGProxy * proxy, GValue value, GError * error, gpointer userdata
if (app->icon != NULL) g_free(app->icon);
app->icon = g_strdup(newicon);
- if (app->status == APP_INDICATOR_STATUS_ACTIVE) {
+ if (app->visible_state == VISIBLE_STATE_SHOWN && app->status == APP_INDICATOR_STATUS_ACTIVE) {
gint position = get_position(app);
if (position == -1) return;
@@ -684,7 +701,7 @@ new_aicon_cb (DBusGProxy * proxy, GValue value, GError * error, gpointer userdat
if (app->aicon != NULL) g_free(app->aicon);
app->aicon = g_strdup(newicon);
- if (app->status == APP_INDICATOR_STATUS_ATTENTION) {
+ if (app->visible_state == VISIBLE_STATE_SHOWN && app->status == APP_INDICATOR_STATUS_ATTENTION) {
gint position = get_position(app);
if (position == -1) return;
@@ -738,7 +755,8 @@ new_status (DBusGProxy * proxy, const gchar * status, gpointer data)
Application * app = (Application *)data;
if (!app->validated) return;
- apply_status(app, string_to_status(status));
+ app->status = string_to_status(status);
+ apply_status(app);
return;
}
@@ -756,7 +774,7 @@ new_icon_theme_path (DBusGProxy * proxy, const gchar * icon_theme_path, gpointer
if (app->icon_theme_path != NULL) g_free(app->icon_theme_path);
app->icon_theme_path = g_strdup(icon_theme_path);
- if (app->status == APP_INDICATOR_STATUS_ACTIVE) {
+ if (app->visible_state != VISIBLE_STATE_HIDDEN) {
gint position = get_position(app);
if (position == -1) return;
@@ -842,6 +860,8 @@ application_service_appstore_application_add (ApplicationServiceAppstore * appst
app->guide = NULL;
app->currently_free = FALSE;
app->ordering_index = 0;
+ app->approved_by = NULL;
+ app->visible_state = VISIBLE_STATE_HIDDEN;
/* Get the DBus proxy for the NotificationItem interface */
GError * error = NULL;
@@ -935,7 +955,7 @@ application_service_appstore_application_add (ApplicationServiceAppstore * appst
}
/* Removes an application. Currently only works for the apps
- that are shown. /TODO Need to fix that. */
+ that are shown. */
void
application_service_appstore_application_remove (ApplicationServiceAppstore * appstore, const gchar * dbus_name, const gchar * dbus_object)
{
@@ -979,6 +999,10 @@ _application_service_server_get_applications (ApplicationServiceAppstore * appst
for (listpntr = priv->applications; listpntr != NULL; listpntr = g_list_next(listpntr)) {
Application * app = (Application *)listpntr->data;
+ if (app->visible_state == VISIBLE_STATE_HIDDEN) {
+ continue;
+ }
+
GValueArray * values = g_value_array_new(5);
GValue value = {0};
@@ -1031,15 +1055,32 @@ _application_service_server_get_applications (ApplicationServiceAppstore * appst
return TRUE;
}
+/* Removes and approver from our list of approvers and
+ then sees if that changes our status. Most likely this
+ could make us visible if this approver rejected us. */
+static void
+remove_approver (gpointer papp, gpointer pproxy)
+{
+ Application * app = (Application *)papp;
+ app->approved_by = g_list_remove(app->approved_by, pproxy);
+ apply_status(app);
+ return;
+}
+
/* 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);
+
+ ApplicationServiceAppstore * appstore = APPLICATION_SERVICE_APPSTORE(user_data);
+ g_list_foreach(appstore->priv->applications, remove_approver, approver->proxy);
if (approver->proxy != NULL) {
- g_object_unref(approver->proxy);
+ if (!approver->destroy_by_proxy) {
+ g_object_unref(approver->proxy);
+ }
approver->proxy = NULL;
}
@@ -1051,7 +1092,21 @@ approver_free (gpointer papprover, gpointer user_data)
static void
approver_request_cb (DBusGProxy *proxy, gboolean OUT_approved, GError *error, gpointer userdata)
{
- g_debug("Approver responded: %s", OUT_approved ? "approve" : "rejected");
+ if (error == NULL) {
+ g_debug("Approver responded: %s", OUT_approved ? "approve" : "rejected");
+ } else {
+ g_debug("Approver responded error: %s", error->message);
+ }
+
+ Application * app = (Application *)userdata;
+
+ if (OUT_approved || error != NULL) {
+ app->approved_by = g_list_prepend(app->approved_by, proxy);
+ } else {
+ app->approved_by = g_list_remove(app->approved_by, proxy);
+ }
+
+ apply_status(app);
return;
}
@@ -1074,6 +1129,42 @@ check_with_new_approver (gpointer papp, gpointer papprove)
return;
}
+/* Look through all the approvers and find the one with a given
+ proxy. */
+static gint
+approver_find_by_proxy (gconstpointer papprover, gconstpointer pproxy)
+{
+ Approver * approver = (Approver *)papprover;
+
+ if (approver->proxy == pproxy) {
+ return 0;
+ }
+
+ return -1;
+}
+
+/* Tracks when a proxy gets destroyed so that we know that the
+ approver has dropped off the bus. */
+static void
+approver_destroyed (gpointer pproxy, gpointer pappstore)
+{
+ ApplicationServiceAppstore * appstore = APPLICATION_SERVICE_APPSTORE(pappstore);
+
+ GList * lapprover = g_list_find_custom(appstore->priv->approvers, pproxy, approver_find_by_proxy);
+ if (lapprover == NULL) {
+ g_warning("Approver proxy died, but we don't seem to have that approver.");
+ return;
+ }
+
+ Approver * approver = (Approver *)lapprover->data;
+ approver->destroy_by_proxy = TRUE;
+
+ appstore->priv->approvers = g_list_remove(appstore->priv->approvers, approver);
+ approver_free(approver, appstore);
+
+ 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)
@@ -1084,6 +1175,7 @@ application_service_appstore_approver_add (ApplicationServiceAppstore * appstore
ApplicationServiceAppstorePrivate * priv = APPLICATION_SERVICE_APPSTORE_GET_PRIVATE (appstore);
Approver * approver = g_new0(Approver, 1);
+ approver->destroy_by_proxy = FALSE;
GError * error = NULL;
approver->proxy = dbus_g_proxy_new_for_name_owner(priv->bus,
@@ -1098,6 +1190,8 @@ application_service_appstore_approver_add (ApplicationServiceAppstore * appstore
return;
}
+ g_signal_connect(G_OBJECT(approver->proxy), "destroy", G_CALLBACK(approver_destroyed), appstore);
+
priv->approvers = g_list_prepend(priv->approvers, approver);
g_list_foreach(priv->applications, check_with_new_approver, approver);