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
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;
}
/*! 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;
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);
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 */
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);
}
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)