From: Dana Jansens Date: Wed, 9 Mar 2011 16:08:19 +0000 (-0500) Subject: keep only one version of each .desktop file "id" in the linkbase category lists. X-Git-Url: http://git.openbox.org/?a=commitdiff_plain;h=62e04a10249a56504a908b88838c976ea547bf15;p=dana%2Fopenbox.git keep only one version of each .desktop file "id" in the linkbase category lists. --- diff --git a/obt/linkbase.c b/obt/linkbase.c index 09e729a6..dcea092e 100644 --- a/obt/linkbase.c +++ b/obt/linkbase.c @@ -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); } diff --git a/obt/linkbase.h b/obt/linkbase.h index 9d7b1deb..9ed2c032 100644 --- a/obt/linkbase.h +++ b/obt/linkbase.h @@ -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. diff --git a/openbox/apps_menu.c b/openbox/apps_menu.c index f2eb36da..fcbf0543 100644 --- a/openbox/apps_menu.c +++ b/openbox/apps_menu.c @@ -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)