- data = self->render_data;
-
- /* set texture data and size them mofos out */
- data->a_title->texture[0].data.text.string = self->label;
- appearance_minsize(data->a_title, &data->title_min_w, &data->title_h);
- data->title_min_w += theme_bevel * 2;
- data->title_h += theme_bevel * 2;
- w = MAX(w, data->title_min_w);
-
- for (it = self->entries; it; it = it->next) {
- MenuEntryRenderData *r = ((MenuEntry*)it->data)->render_data;
-
- r->a_item->texture[0].data.text.string = ((MenuEntry*)it->data)->label;
- appearance_minsize(r->a_item, &r->min_w, &item_h);
- r->min_w += theme_bevel * 2;
- item_h += theme_bevel * 2;
- w = MAX(w, r->min_w);
- ++nitems;
- }
- bullet_w = item_h + theme_bevel;
- w += 2 * bullet_w;
- items_h = item_h * nitems;
-
- /* size appearances */
- RECT_SET(data->a_title->area, 0, 0, w, data->title_h);
- RECT_SET(data->a_title->texture[0].position, 0, 0, w, data->title_h);
- RECT_SET(data->a_items->area, 0, 0, w, items_h);
- for (it = self->entries; it; it = it->next) {
- MenuEntryRenderData *r = ((MenuEntry*)it->data)->render_data;
- RECT_SET(r->a_item->area, 0, 0, w, item_h);
- RECT_SET(r->a_item->texture[0].position, bullet_w, 0,
- w - 2 * bullet_w, item_h);
- }
-
- /* size windows and paint the suckers */
- XMoveResizeWindow(ob_display, data->frame, x, y, w,
- data->title_h + items_h);
- XMoveResizeWindow(ob_display, data->title, -theme_bwidth, -theme_bwidth,
- w, data->title_h);
- paint(data->title, data->a_title);
- XMoveResizeWindow(ob_display, data->items, 0, data->title_h + theme_bwidth,
- w, items_h);
- paint(data->items, data->a_items);
- for (item_y = 0, it = self->entries; it; item_y += item_h, it = it->next) {
- MenuEntryRenderData *r = ((MenuEntry*)it->data)->render_data;
- XMoveResizeWindow(ob_display, r->item, 0, item_y, w, item_h);
- r->a_item->surface.data.planar.parent = data->a_items;
- r->a_item->surface.data.planar.parentx = 0;
- r->a_item->surface.data.planar.parenty = item_y;
- paint(r->item, r->a_item);
- }
-
-
- XMapWindow(ob_display, data->frame);
+void menu_show_all_shortcuts(ObMenu *self, gboolean show)
+{
+ self->show_all_shortcuts = show;
+}
+
+static int sort_func(const void *a, const void *b) {
+ const ObMenuEntry *e[2] = {*(ObMenuEntry**)a, *(ObMenuEntry**)b};
+ const gchar *k[2];
+ gint i;
+
+ for (i = 0; i < 2; ++i) {
+ if (e[i]->type == OB_MENU_ENTRY_TYPE_NORMAL)
+ k[i] = e[i]->data.normal.collate_key;
+ else {
+ g_assert(e[i]->type == OB_MENU_ENTRY_TYPE_SUBMENU);
+ if (e[i]->data.submenu.submenu)
+ k[i] = e[i]->data.submenu.submenu->collate_key;
+ else
+ return -1; /* arbitrary really.. the submenu doesn't exist. */
+ }
+ }
+ return strcmp(k[0], k[1]);
+}
+
+/*!
+ @param start The first entry in the range to sort.
+ @param end The last entry in the range to sort.
+*/
+static void sort_range(ObMenu *self, GList *start, GList *end, guint len)
+{
+ ObMenuEntry **ar;
+ GList *it;
+ guint i;
+ if (!len) return;
+
+ ar = g_slice_alloc(sizeof(ObMenuEntry*) * len);
+ for (i = 0, it = start; it != g_list_next(end); ++i, it = g_list_next(it))
+ ar[i] = it->data;
+ qsort(ar, len, sizeof(ObMenuEntry*), sort_func);
+ for (i = 0, it = start; it != g_list_next(end); ++i, it = g_list_next(it))
+ it->data = ar[i];
+ g_slice_free1(sizeof(ObMenuEntry*) * len, ar);
+}
+
+void menu_sort_entries(ObMenu *self)
+{
+ GList *it, *start, *end, *last;
+ guint len;
+
+ /* need the submenus to know their labels for sorting */
+ menu_find_submenus(self);
+
+ start = self->entries;
+ len = 0;
+ for (it = self->entries; it; it = g_list_next(it)) {
+ ObMenuEntry *e = it->data;
+ if (e->type == OB_MENU_ENTRY_TYPE_SEPARATOR) {
+ end = g_list_previous(it);
+ sort_range(self, start, end, len);
+
+ it = g_list_next(it); /* skip over the separator */
+ start = it;
+ len = 0;
+ }
+ else
+ len += 1;
+ last = it;
+ }
+ sort_range(self, start, last, len);