aboutsummaryrefslogtreecommitdiff
path: root/src/application-service-appstore.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/application-service-appstore.c')
-rw-r--r--src/application-service-appstore.c160
1 files changed, 136 insertions, 24 deletions
diff --git a/src/application-service-appstore.c b/src/application-service-appstore.c
index 4ba2aca..73fc5d1 100644
--- a/src/application-service-appstore.c
+++ b/src/application-service-appstore.c
@@ -32,34 +32,39 @@ with this program. If not, see <http://www.gnu.org/licenses/>.
#include "dbus-properties-client.h"
#include "dbus-shared.h"
#include "notification-approver-client.h"
+#include "generate-id.h"
/* DBus Prototypes */
static gboolean _application_service_server_get_applications (ApplicationServiceAppstore * appstore, GPtrArray ** apps, GError ** error);
#include "application-service-server.h"
-#define NOTIFICATION_ITEM_PROP_ID "Id"
-#define NOTIFICATION_ITEM_PROP_CATEGORY "Category"
-#define NOTIFICATION_ITEM_PROP_STATUS "Status"
-#define NOTIFICATION_ITEM_PROP_ICON_NAME "IconName"
-#define NOTIFICATION_ITEM_PROP_AICON_NAME "AttentionIconName"
-#define NOTIFICATION_ITEM_PROP_ICON_THEME_PATH "IconThemePath"
-#define NOTIFICATION_ITEM_PROP_MENU "Menu"
-#define NOTIFICATION_ITEM_PROP_LABEL "Label"
-#define NOTIFICATION_ITEM_PROP_LABEL_GUIDE "LabelGuide"
+#define NOTIFICATION_ITEM_PROP_ID "Id"
+#define NOTIFICATION_ITEM_PROP_CATEGORY "Category"
+#define NOTIFICATION_ITEM_PROP_STATUS "Status"
+#define NOTIFICATION_ITEM_PROP_ICON_NAME "IconName"
+#define NOTIFICATION_ITEM_PROP_AICON_NAME "AttentionIconName"
+#define NOTIFICATION_ITEM_PROP_ICON_THEME_PATH "IconThemePath"
+#define NOTIFICATION_ITEM_PROP_MENU "Menu"
+#define NOTIFICATION_ITEM_PROP_LABEL "XAyatanaLabel"
+#define NOTIFICATION_ITEM_PROP_LABEL_GUIDE "XAyatanaLabelGuide"
+#define NOTIFICATION_ITEM_PROP_ORDERING_INDEX "XAyatanaOrderingIndex"
#define NOTIFICATION_ITEM_SIG_NEW_ICON "NewIcon"
#define NOTIFICATION_ITEM_SIG_NEW_AICON "NewAttentionIcon"
#define NOTIFICATION_ITEM_SIG_NEW_STATUS "NewStatus"
-#define NOTIFICATION_ITEM_SIG_NEW_LABEL "NewLabel"
+#define NOTIFICATION_ITEM_SIG_NEW_LABEL "XAyatanaNewLabel"
#define NOTIFICATION_ITEM_SIG_NEW_ICON_THEME_PATH "NewIconThemePath"
+#define OVERRIDE_GROUP_NAME "Ordering Index Overrides"
+#define OVERRIDE_FILE_NAME "ordering-override.keyfile"
+
/* Private Stuff */
struct _ApplicationServiceAppstorePrivate {
DBusGConnection * bus;
GList * applications;
GList * approvers;
- AppLruFile * lrufile;
+ GHashTable * ordering_overrides;
};
typedef enum {
@@ -90,6 +95,7 @@ struct _Application {
gchar * label;
gchar * guide;
gboolean currently_free;
+ guint ordering_index;
GList * approved_by;
visible_state_t visible_state;
};
@@ -115,8 +121,10 @@ static void application_service_appstore_init (ApplicationServiceAppstore
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 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);
@@ -189,7 +197,13 @@ application_service_appstore_init (ApplicationServiceAppstore *self)
priv->applications = NULL;
priv->approvers = NULL;
- priv->lrufile = NULL;
+
+ priv->ordering_overrides = g_hash_table_new_full(g_str_hash, g_str_equal, g_free, NULL);
+
+ load_override_file(priv->ordering_overrides, DATADIR "/" OVERRIDE_FILE_NAME);
+ gchar * userfile = g_build_filename(g_get_user_data_dir(), "indicators", "application", OVERRIDE_FILE_NAME, NULL);
+ load_override_file(priv->ordering_overrides, userfile);
+ g_free(userfile);
GError * error = NULL;
priv->bus = dbus_g_bus_get(DBUS_BUS_STARTER, &error);
@@ -232,11 +246,71 @@ application_service_appstore_dispose (GObject *object)
static void
application_service_appstore_finalize (GObject *object)
{
+ ApplicationServiceAppstorePrivate * priv = APPLICATION_SERVICE_APPSTORE(object)->priv;
+
+ if (priv->ordering_overrides != NULL) {
+ g_hash_table_destroy(priv->ordering_overrides);
+ priv->ordering_overrides = NULL;
+ }
G_OBJECT_CLASS (application_service_appstore_parent_class)->finalize (object);
return;
}
+/* Loads the file and adds the override entries to the table
+ of overrides */
+static void
+load_override_file (GHashTable * hash, const gchar * filename)
+{
+ g_return_if_fail(hash != NULL);
+ g_return_if_fail(filename != NULL);
+
+ if (!g_file_test(filename, G_FILE_TEST_EXISTS)) {
+ return;
+ }
+
+ g_debug("Loading overrides from: '%s'", filename);
+
+ GError * error = NULL;
+ GKeyFile * keyfile = g_key_file_new();
+ g_key_file_load_from_file(keyfile, filename, G_KEY_FILE_NONE, &error);
+
+ if (error != NULL) {
+ g_warning("Unable to load keyfile '%s' because: %s", filename, error->message);
+ g_error_free(error);
+ g_key_file_free(keyfile);
+ return;
+ }
+
+ gchar ** keys = g_key_file_get_keys(keyfile, OVERRIDE_GROUP_NAME, NULL, &error);
+ if (error != NULL) {
+ g_warning("Unable to get keys from keyfile '%s' because: %s", filename, error->message);
+ g_error_free(error);
+ g_key_file_free(keyfile);
+ return;
+ }
+
+ gchar * key = keys[0];
+ gint i;
+
+ for (i = 0; (key = keys[i]) != NULL; i++) {
+ GError * valerror = NULL;
+ gint val = g_key_file_get_integer(keyfile, OVERRIDE_GROUP_NAME, key, &valerror);
+
+ if (valerror != NULL) {
+ g_warning("Unable to get key '%s' out of file '%s' because: %s", key, filename, valerror->message);
+ g_error_free(valerror);
+ continue;
+ }
+ g_debug("%s: override '%s' with value '%d'", filename, key, val);
+
+ g_hash_table_insert(hash, g_strdup(key), GINT_TO_POINTER(val));
+ }
+ g_key_file_free(keyfile);
+
+ return;
+}
+
/* Return from getting the properties from the item. We're looking at those
and making sure we have everythign that we need. If we do, then we'll
move on up to sending this onto the indicator. */
@@ -268,7 +342,6 @@ get_all_properties_cb (DBusGProxy * proxy, GHashTable * properties, GError * err
app->status = string_to_status(g_value_get_string(g_hash_table_lookup(properties, NOTIFICATION_ITEM_PROP_STATUS)));
ApplicationServiceAppstorePrivate * priv = app->appstore->priv;
- app_lru_file_touch(priv->lrufile, app->id, app->category);
app->icon = g_value_dup_string(g_hash_table_lookup(properties, NOTIFICATION_ITEM_PROP_ICON_NAME));
@@ -292,6 +365,19 @@ get_all_properties_cb (DBusGProxy * proxy, GHashTable * properties, GError * err
app->icon_theme_path = g_strdup("");
}
+ gpointer ordering_index_over = g_hash_table_lookup(priv->ordering_overrides, app->id);
+ if (ordering_index_over == NULL) {
+ gpointer ordering_index_data = g_hash_table_lookup(properties, NOTIFICATION_ITEM_PROP_ORDERING_INDEX);
+ if (ordering_index_data == NULL || g_value_get_uint(ordering_index_data) == 0) {
+ app->ordering_index = generate_id(string_to_cat(app->category), app->id);
+ } else {
+ app->ordering_index = g_value_get_uint(ordering_index_data);
+ }
+ } else {
+ app->ordering_index = GPOINTER_TO_UINT(ordering_index_over);
+ }
+ g_debug("'%s' ordering index is '%X'", app->id, app->ordering_index);
+
gpointer label_data = g_hash_table_lookup(properties, NOTIFICATION_ITEM_PROP_LABEL);
if (label_data != NULL) {
app->label = g_value_dup_string((GValue *)label_data);
@@ -306,7 +392,7 @@ get_all_properties_cb (DBusGProxy * proxy, GHashTable * properties, GError * err
app->guide = g_strdup("");
}
- priv->applications = g_list_insert_sorted_with_data (priv->applications, app, app_sort_func, priv->lrufile);
+ 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);
@@ -344,6 +430,28 @@ string_to_status(const gchar * status_string)
return retval;
}
+/* Simple translation function -- could be optimized */
+static AppIndicatorCategory
+string_to_cat(const gchar * cat_string)
+{
+ GEnumClass * klass = G_ENUM_CLASS(g_type_class_ref(APP_INDICATOR_TYPE_INDICATOR_CATEGORY));
+ g_return_val_if_fail(klass != NULL, APP_INDICATOR_CATEGORY_OTHER);
+
+ AppIndicatorCategory retval = APP_INDICATOR_CATEGORY_OTHER;
+
+ GEnumValue * val = g_enum_get_value_by_nick(klass, cat_string);
+ if (val == NULL) {
+ g_warning("Unrecognized status '%s' assuming other.", cat_string);
+ } else {
+ retval = (AppIndicatorCategory)val->value;
+ }
+
+ g_type_class_unref(klass);
+
+ return retval;
+}
+
+
/* A small helper function to get the position of an application
in the app list of the applications that are visible. */
static gint
@@ -443,21 +551,22 @@ application_removed_cb (DBusGProxy * proxy, gpointer userdata)
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;
}
/* This function takes two Application structure
- pointers and uses the lrufile to compare them. */
+ pointers and uses their ordering index to compare them. */
static gint
app_sort_func (gconstpointer a, gconstpointer b, gpointer userdata)
{
Application * appa = (Application *)a;
Application * appb = (Application *)b;
- AppLruFile * lrufile = (AppLruFile *)userdata;
-
- return app_lru_file_sort(lrufile, appa->id, appb->id);
+ return (appb->ordering_index/2) - (appa->ordering_index/2);
}
/* Change the status of the application. If we're going passive
@@ -746,6 +855,7 @@ application_service_appstore_application_add (ApplicationServiceAppstore * appst
app->label = NULL;
app->guide = NULL;
app->currently_free = FALSE;
+ app->ordering_index = 0;
app->approved_by = NULL;
app->visible_state = VISIBLE_STATE_HIDDEN;
@@ -867,12 +977,9 @@ application_service_appstore_application_remove (ApplicationServiceAppstore * ap
/* Creates a basic appstore object and attaches the
LRU file object to it. */
ApplicationServiceAppstore *
-application_service_appstore_new (AppLruFile * lrufile)
+application_service_appstore_new (void)
{
- g_return_val_if_fail(IS_APP_LRU_FILE(lrufile), NULL);
ApplicationServiceAppstore * appstore = APPLICATION_SERVICE_APPSTORE(g_object_new(APPLICATION_SERVICE_APPSTORE_TYPE, NULL));
- ApplicationServiceAppstorePrivate * priv = appstore->priv;
- priv->lrufile = lrufile;
return appstore;
}
@@ -979,10 +1086,15 @@ 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) {
+ 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);