keep only one version of each .desktop file "id" in the linkbase category lists.
authorDana Jansens <danakj@orodu.net>
Wed, 9 Mar 2011 16:08:19 +0000 (11:08 -0500)
committerDana Jansens <danakj@orodu.net>
Sun, 16 Oct 2011 22:54:05 +0000 (18:54 -0400)
obt/linkbase.c
obt/linkbase.h
openbox/apps_menu.c

index 09e729a62d99b9ee95685460aab56f5f36a233f0..dcea092ebea9072ab315f6ec4c0a839e3e9bd0a2 100644 (file)
@@ -54,7 +54,7 @@ struct _ObtLinkBase {
 
     ObtPaths *paths;
     ObtWatch *watch;
-    /*! This holds a GSList of ObtLinkBaseEntrys sorted by priority in
+    /*! This holds a GList of ObtLinkBaseEntrys sorted by priority in
       increasing order (by precedence in decreasing order). */
     GHashTable *base;
     /*! This holds the paths in which we look for links, and the data is an
@@ -80,18 +80,18 @@ static void base_entry_free(ObtLinkBaseEntry *e)
 
 static void base_entry_list_free(gpointer key, gpointer value, gpointer data)
 {
-    GSList *it, *list; (void)key; (void)data;
+    GList *it, *list; (void)key; (void)data;
 
     list = value;
-    for (it = list; it; it = g_slist_next(it))
+    for (it = list; it; it = g_list_next(it))
         base_entry_free(it->data);
-    g_slist_free(list);
+    g_list_free(list);
 }
 
-static GSList* find_base_entry_path(GSList *list, const gchar *full_path)
+static GList* find_base_entry_path(GList *list, const gchar *full_path)
 {
-    GSList *it;
-    for (it = list; it; it = g_slist_next(it)) {
+    GList *it;
+    for (it = list; it; it = g_list_next(it)) {
         ObtLinkBaseEntry *e = it->data;
         if (strcmp(obt_link_source_file(e->link), full_path) == 0)
             break;
@@ -100,10 +100,10 @@ static GSList* find_base_entry_path(GSList *list, const gchar *full_path)
 }
 
 /*! Finds the first entry in the list with a priority number >= @priority. */
-static GSList* find_base_entry_priority(GSList *list, gint priority)
+static GList* find_base_entry_priority(GList *list, gint priority)
 {
-    GSList *it;
-    for (it = list; it; it = g_slist_next(it)) {
+    GList *it;
+    for (it = list; it; it = g_list_next(it)) {
         ObtLinkBaseEntry *e = it->data;
         if (e->priority >= priority)
             break;
@@ -140,6 +140,30 @@ static void category_remove(ObtLinkBase *lb, GQuark cat, ObtLink *link)
         g_hash_table_remove(lb->categories, &cat);
 }
 
+static void category_add_app(ObtLinkBase *lb, ObtLink *link)
+{
+    if (obt_link_type(link) == OBT_LINK_TYPE_APPLICATION) {
+        const GQuark *cats;
+        gulong i, n;
+
+        cats = obt_link_app_categories(link, &n);
+        for (i = 0; i < n; ++i)
+            category_add(lb, cats[i], link);
+    }
+}
+
+static void category_remove_app(ObtLinkBase *lb, ObtLink *link)
+{
+    if (obt_link_type(link) == OBT_LINK_TYPE_APPLICATION) {
+        const GQuark *cats;
+        gulong i, n;
+
+        cats = obt_link_app_categories(link, &n);
+        for (i = 0; i < n; ++i)
+            category_remove(lb, cats[i], link);
+    }
+}
+
 static void category_free(ObtLinkBaseCategory *lc)
 {
     g_slist_free(lc->links);
@@ -154,10 +178,14 @@ static void update(ObtWatch *w, const gchar *base_path,
                    gpointer data)
 {
     ObtLinkBase *self = data;
+    ObtLinkBaseEntry *add = NULL;
+    ObtLinkBaseEntry *remove = NULL;
+    ObtLinkBaseEntry *show, *hide;
+    ObtLink *link;
     gchar *id;
-    GSList *list, *it;
+    GList *list, *it;
+    GList *remove_it = NULL;
     gint *priority;
-    gboolean add = FALSE;
 
     if (!g_str_has_suffix(sub_path, ".desktop"))
         return; /* ignore non-.desktop files */
@@ -168,121 +196,99 @@ static void update(ObtWatch *w, const gchar *base_path,
     switch (type) {
     case OBT_WATCH_SELF_REMOVED:
         break;
-    case OBT_WATCH_REMOVED:
-        it = find_base_entry_path(list, full_path);
-        if (it) {
-            /* it may be false if the link was skipped during the add because
-               it did not want to be displayed */
-
-            ObtLink *link = it->data;
-
-            if (self->update_func)
-                self->update_func(
-                    self, OBT_LINKBASE_REMOVED, link, self->update_data);
-
-            if (obt_link_type(link) == OBT_LINK_TYPE_APPLICATION) {
-                const GQuark *cats;
-                gulong i, n;
-
-                cats = obt_link_app_categories(link, &n);
-                for (i = 0; i < n; ++i)
-                    category_remove(self, cats[i], link);
-            }
-
-            base_entry_free(it->data);
-            list = g_slist_delete_link(list, it);
-
-            if (list) {
-                /* this will free 'id' */
-                g_hash_table_insert(self->base, id, list);
-                id = NULL;
-            }
-            else {
-                /* the value is already freed by deleting it above so we don't
-                   need to free it here. id will still need to be freed tho. */
-                g_hash_table_remove(self->base, id);
-            }
-        }
-        break;
-    case OBT_WATCH_MODIFIED:
-        it = find_base_entry_path(list, full_path);
-        if (it) {
-            /* it may be false if the link was skipped during the add because
-               it did not want to be displayed */
-
-            ObtLink *link = it->data;
-
-            if (self->update_func)
-                self->update_func(
-                    self, OBT_LINKBASE_REMOVED, link, self->update_data);
-
-            if (obt_link_type(link) == OBT_LINK_TYPE_APPLICATION) {
-                const GQuark *cats;
-                gulong i, n;
-
-                cats = obt_link_app_categories(link, &n);
-                for (i = 0; i < n; ++i)
-                    category_remove(self, cats[i], link);
-            }
-
-            base_entry_free(it->data);
-            list = g_slist_delete_link(list, it);
-            /* this will put the modified list into the hash table */
-            add = TRUE;
-        }
-        break;
     case OBT_WATCH_ADDED:
         priority = g_hash_table_lookup(self->path_to_priority, base_path);
-        add = TRUE;
 
-        /* find the first position in the list with a higher priority value */
-        if ((it = find_base_entry_priority(list, *priority))) {
-            const ObtLinkBaseEntry *e = it->data;
+        /* make sure an entry doesn't already exist from the same
+           @base_path */
+        it = find_base_entry_priority(list, *priority);
+        if (it) {
+            ObtLinkBaseEntry *e = it->data;
             if (e->priority == *priority) {
-                /* already exists */
-                add = FALSE;
+                break;
             }
         }
+    case OBT_WATCH_MODIFIED:
+        link = obt_link_from_ddfile(full_path, self->paths,
+                                    self->language, self->country,
+                                    self->modifier);
+        if (link && !obt_link_display(link, self->environments)) {
+            obt_link_unref(link);
+            link = NULL;
+        }
+        if (link) {
+            add = g_slice_new(ObtLinkBaseEntry);
+            add->priority = *priority;
+            add->link = link;
+        }
+
+        if (type != OBT_WATCH_MODIFIED)
+            break;
+    case OBT_WATCH_REMOVED:
+        /* this may be NULL if the link was skipped during the add because
+           it did not want to be displayed */
+        remove_it = find_base_entry_path(list, full_path);
+        remove = remove_it ? remove_it->data : NULL;
         break;
     }
 
+    /* figure out which entry should be shown (which will have highest
+       precedence) */
+    show = hide = NULL;
     if (add) {
-        ObtLink *link;
+        ObtLinkBaseEntry *first = list ? list->data : NULL;
 
-        link = obt_link_from_ddfile(full_path, self->paths,
-                                    self->language, self->country,
-                                    self->modifier);
-        if (link) {
-            if (!obt_link_display(link, self->environments)) {
-                obt_link_unref(link);
-            }
-            else {
-                ObtLinkBaseEntry *e = g_slice_new(ObtLinkBaseEntry);
-                e->priority = *priority;
-                e->link = link;
+        /* a greater priority means a lower precedence, so
+           the new one will replace the current front of the list */
+        if (!first || first->priority >= add->priority) {
+            show = add;
+            hide = first;
+        }
+    }
+    else if (remove) {
+        ObtLinkBaseEntry *first = list ? list->data : NULL;
 
-                if (self->update_func)
-                    self->update_func(
-                        self, OBT_LINKBASE_ADDED, link, self->update_data);
+        if (first == remove) {
+            hide = first;
+            show = list->next ? list->next->data : NULL;
+        }
+    }
 
-                list = g_slist_insert_before(list, it, e);
+    if (hide)
+        category_remove_app(self, hide->link);
+    if (show)
+        category_add_app(self, show->link);
 
-                /* this will free 'id' */
-                g_hash_table_insert(self->base, id, list);
-                id = NULL;
+    if ((remove || add) && self->update_func) {
+        ObtLink *const a = show ? show->link : NULL;
+        ObtLink *const r = hide ? hide->link : NULL;
+        self->update_func(
+            self, r, a, self->update_data);
+    }
 
-                if (obt_link_type(link) == OBT_LINK_TYPE_APPLICATION) {
-                    const GQuark *cats;
-                    gulong i, n;
+    /* do the actual removal/addition to the base list for the @id */
+    if (remove_it) {
+        base_entry_free(remove_it->data);
+        list = g_list_delete_link(list, remove_it);
+    }
+    if (add) {
+        it = find_base_entry_priority(list, *priority);
+        list = g_list_insert_before(list, it, add);
+    }
 
-                    cats = obt_link_app_categories(link, &n);
-                    for (i = 0; i < n; ++i)
-                        category_add(self, cats[i], link);
-                }
-            }
+    if (remove || add) {
+        /* update the list in the hash table */
+        if (list) {
+            /* this will free 'id' */
+            g_hash_table_insert(self->base, id, list);
+            id = NULL;
+        }
+        else {
+            /* the value is already freed by deleting it above so we don't
+               need to free it here. id will still need to be freed tho. */
+            g_hash_table_steal(self->base, id);
         }
     }
-
     g_free(id);
 }
 
index 9d7b1debe5212973a9cfb73a3b2aa338ea84348f..9ed2c032dcdf5063bd34f5050ef81e0dec6f1041 100644 (file)
@@ -29,14 +29,9 @@ struct _ObtLink;
 
 typedef struct _ObtLinkBase ObtLinkBase;
 
-typedef enum {
-    OBT_LINKBASE_ADDED,
-    OBT_LINKBASE_REMOVED,
-} ObtLinkBaseUpdateType;
-
 typedef void (*ObtLinkBaseUpdateFunc)(ObtLinkBase *lb,
-                                      ObtLinkBaseUpdateType type,
-                                      struct _ObtLink *link,
+                                      struct _ObtLink *removed,
+                                      struct _ObtLink *added,
                                       gpointer data);
 
 /*! Create a new database of ObtLinks.
index f2eb36dae4d13eb4642b18a92c3e8105f1fb6b4e..fcbf05435bb3c3ea12270b71c8f37e2745c1254f 100644 (file)
@@ -221,36 +221,41 @@ static gboolean remove_link_from_category(ObtLink *link,
     return rm;
 }
 
-static void linkbase_update(ObtLinkBase *lb, ObtLinkBaseUpdateType type,
-                            ObtLink *link, gpointer data)
+static void linkbase_update(ObtLinkBase *lb, ObtLink *removed,
+                            ObtLink *added, gpointer data)
 {
     const GQuark *cats;
     gulong n_cats, i;
 
-    if (obt_link_type(link) != OBT_LINK_TYPE_APPLICATION)
-        return;  /* not in our menu */
-
     /* For each category in the link, search our list of categories and
        if we are showing that category in the menu, add the link to it (or
        remove the link from it). */
-    cats = obt_link_app_categories(link, &n_cats);
-    for (i = 0; i < n_cats; ++i) {
-        BSEARCH_SETUP();
 
 #define CAT_TO_INT(c) (c.q)
-        BSEARCH_CMP(ObAppsMenuCategory, categories, 0, n_categories,
+    if (removed) {
+        cats = obt_link_app_categories(removed, &n_cats);
+        for (i = 0; i < n_cats; ++i) {
+            BSEARCH_SETUP();
+            BSEARCH_CMP(ObAppsMenuCategory, categories, 0, n_categories,
                     cats[i], CAT_TO_INT);
-#undef  CAT_TO_INT
+            if (BSEARCH_FOUND())
+                remove_link_from_category(removed, &categories[BSEARCH_AT()]);
+        }
+    }
 
-        if (BSEARCH_FOUND()) {
-            if (type == OBT_LINKBASE_ADDED) {
-                add_link_to_category(link, &categories[BSEARCH_AT()]);
+    if (added) {
+        cats = obt_link_app_categories(added, &n_cats);
+        for (i = 0; i < n_cats; ++i) {
+            BSEARCH_SETUP();
+            BSEARCH_CMP(ObAppsMenuCategory, categories, 0, n_categories,
+                        cats[i], CAT_TO_INT);
+            if (BSEARCH_FOUND()) {
+                add_link_to_category(added, &categories[BSEARCH_AT()]);
                 g_ptr_array_sort(categories[i].links, obt_link_cmp_by_name);
             }
-            else
-                remove_link_from_category(link, &categories[BSEARCH_AT()]);
         }
     }
+#undef  CAT_TO_INT
 }
 
 static int cat_cmp(const void *a, const void *b)