]> icculus.org git repositories - dana/openbox.git/blob - openbox/apps_menu.c
Show the list of categories in the apps menus as submenus.
[dana/openbox.git] / openbox / apps_menu.c
1 /* -*- indent-tabs-mode: nil; tab-width: 4; c-basic-offset: 4; -*-
2
3    apps_menu.c for the Openbox window manager
4    Copyright (c) 2011        Dana Jansens
5
6    This program is free software; you can redistribute it and/or modify
7    it under the terms of the GNU General Public License as published by
8    the Free Software Foundation; either version 2 of the License, or
9    (at your option) any later version.
10
11    This program is distributed in the hope that it will be useful,
12    but WITHOUT ANY WARRANTY; without even the implied warranty of
13    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14    GNU General Public License for more details.
15
16    See the COPYING file for a copy of the GNU General Public License.
17 */
18
19 #include "openbox.h"
20 #include "menu.h"
21 #include "menuframe.h"
22 #include "screen.h"
23 #include "apps_menu.h"
24 #include "config.h"
25 #include "gettext.h"
26 #include "obt/linkbase.h"
27 #include "obt/link.h"
28 #include "obt/paths.h"
29
30 #include <glib.h>
31
32 #define MENU_NAME "apps-menu"
33
34 typedef struct _ObAppsMenuCategory ObAppsMenuCategory;
35
36 struct _ObAppsMenuCategory {
37     GQuark q;
38     gchar *friendly;
39     ObMenu *m;
40 };
41
42 static ObMenu *apps_menu;
43 static ObtLinkBase *linkbase;
44 static gboolean dirty;
45
46 static ObAppsMenuCategory *categories;
47 /*! An array of pointers to the categories array, sorted by their friendly
48   names. */
49 static ObAppsMenuCategory **sorted_categories;
50 static guint n_categories;
51
52 static void self_destroy(ObMenu *menu, gpointer data)
53 {
54     menu_clear_entries(menu);
55 }
56
57 static gboolean self_update(ObMenuFrame *frame, gpointer data)
58 {
59     ObMenu *menu = frame->menu;
60     ObMenuEntry *e;
61     guint i;
62
63     g_print("UPDATE DIRTY %d\n", dirty);
64
65     if (!dirty) return TRUE;  /* nothing has changed to be updated */
66
67     menu_clear_entries(menu);
68
69     for (i = 0; i < n_categories; ++i) {
70         menu_free(categories[i].m);
71         categories[i].m = NULL;
72     }
73
74
75     for (i = 0; i < n_categories; ++i) {
76         // XXX if not empty
77         ObAppsMenuCategory *cat = sorted_categories[i];
78         const gchar *label = g_quark_to_string(cat->q);
79         if (!cat->m)
80             cat->m = menu_new(label, cat->friendly, FALSE, NULL);
81         e = menu_add_submenu(menu, i, label);
82     }
83 /*
84     menu_add_separator(menu, SEPARATOR, screen_desktop_names[desktop]);
85
86     gchar *title = g_strdup_printf("(%s)", c->icon_title);
87     e = menu_add_normal(menu, desktop, title, NULL, FALSE);
88     g_free(title);
89
90     if (config_menu_show_icons) {
91         e->data.normal.icon = client_icon(c);
92         RrImageRef(e->data.normal.icon);
93         e->data.normal.icon_alpha =
94             c->iconic ? OB_ICONIC_ALPHA : 0xff;
95     }
96
97     e->data.normal.data = link;
98 */
99
100
101     dirty = FALSE;
102     return TRUE; /* always show the menu */
103 }
104
105 static void menu_execute(ObMenuEntry *self, ObMenuFrame *f,
106                          ObClient *c, guint state, gpointer data)
107 {
108 #if 0
109     ObClient *t = self->data.normal.data;
110     if (t) { /* it's set to NULL if its destroyed */
111         gboolean here = state & ShiftMask;
112
113         client_activate(t, TRUE, here, TRUE, TRUE, TRUE);
114         /* if the window is omnipresent then we need to go to its
115            desktop */
116         if (!here && t->desktop == DESKTOP_ALL)
117             screen_set_desktop(self->id, FALSE);
118     }
119 #endif
120 }
121
122 static void linkbase_update(ObtLinkBase *lb, gpointer data)
123 {
124     dirty = TRUE;
125 }
126
127 static int cat_cmp(const void *a, const void *b)
128 {
129     const ObAppsMenuCategory *ca = a, *cb = b;
130     return ca->q - cb->q;
131 }
132
133 static int cat_friendly_cmp(const void *a, const void *b)
134 {
135     ObAppsMenuCategory *const *ca = a, *const *cb = b;
136     return strcmp((*ca)->friendly, (*cb)->friendly);
137 }
138
139 void apps_menu_startup(gboolean reconfig)
140 {
141     if (!reconfig) {
142         ObtPaths *paths;
143         guint i;
144
145         paths = obt_paths_new();
146         /* XXX allow more environments, like GNOME or KDE, to be included */
147         linkbase = obt_linkbase_new(paths, ob_locale_msg,
148                                     OBT_LINK_ENV_OPENBOX);
149         obt_paths_unref(paths);
150         obt_linkbase_set_update_func(linkbase, linkbase_update, NULL);
151
152         dirty = TRUE;
153
154         /* From http://standards.freedesktop.org/menu-spec/latest/apa.html */
155         n_categories = 10;
156         categories = g_new0(ObAppsMenuCategory, n_categories);
157         sorted_categories = g_new(ObAppsMenuCategory*, n_categories);
158
159         categories[0].q = g_quark_from_static_string("AudioVideo");
160         categories[0].friendly = _("Sound & Video");
161         categories[1].q = g_quark_from_static_string("Development");
162         categories[1].friendly = _("Programming");
163         categories[2].q = g_quark_from_static_string("Education");
164         categories[2].friendly = _("Education");
165         categories[3].q = g_quark_from_static_string("Game");
166         categories[3].friendly = _("Games");
167         categories[4].q = g_quark_from_static_string("Graphics");
168         categories[4].friendly = _("Graphics");
169         categories[5].q = g_quark_from_static_string("Network");
170         categories[5].friendly = _("Internet");
171         categories[6].q = g_quark_from_static_string("Office");
172         categories[6].friendly = _("Office");
173         categories[7].q = g_quark_from_static_string("Settings");
174         categories[7].friendly = _("Settings");
175         categories[8].q = g_quark_from_static_string("System");
176         categories[8].friendly = _("System");
177         categories[9].q = g_quark_from_static_string("Utility");
178         categories[9].friendly = _("Utility");
179         /* Sort them by their quark values */
180         qsort(categories, n_categories, sizeof(ObAppsMenuCategory), cat_cmp);
181
182         for (i = 0; i < n_categories; ++i)
183             sorted_categories[i] = &categories[i];
184         qsort(sorted_categories, n_categories, sizeof(void*),
185               cat_friendly_cmp);
186     }
187
188     apps_menu = menu_new(MENU_NAME, _("Applications"), TRUE, NULL);
189     menu_set_update_func(apps_menu, self_update);
190     menu_set_destroy_func(apps_menu, self_destroy);
191     menu_set_execute_func(apps_menu, menu_execute);
192 }
193
194 void apps_menu_shutdown(gboolean reconfig)
195 {
196     if (!reconfig) {
197         guint i;
198
199         obt_linkbase_unref(linkbase);
200         linkbase = NULL;
201
202         for (i = 0; i < n_categories; ++i)
203             if (categories[i].m)
204                 menu_free(categories[i].m);
205         g_free(categories);
206         categories = NULL;
207         g_free(sorted_categories);
208         sorted_categories = NULL;
209     }
210
211     /* freed by the hash table */
212 }