]> Dogcows Code - chaz/openbox/blob - openbox/menu.c
Render menus only when they are invalid.
[chaz/openbox] / openbox / menu.c
1 #include "menu.h"
2 #include "openbox.h"
3 #include "stacking.h"
4 #include "grab.h"
5 #include "render/theme.h"
6
7 static GHashTable *menu_hash = NULL;
8 GHashTable *menu_map = NULL;
9
10 #define FRAME_EVENTMASK (ButtonMotionMask | EnterWindowMask | LeaveWindowMask)
11 #define TITLE_EVENTMASK (ButtonPressMask | ButtonMotionMask)
12 #define ENTRY_EVENTMASK (EnterWindowMask | LeaveWindowMask | \
13 ButtonPressMask | ButtonReleaseMask)
14
15 void menu_destroy_hash_key(gpointer data)
16 {
17 g_free(data);
18 }
19
20 void menu_destroy_hash_value(Menu *self)
21 {
22 GList *it;
23
24 for (it = self->entries; it; it = it->next)
25 menu_entry_free(it->data);
26 g_list_free(self->entries);
27
28 g_free(self->label);
29 g_free(self->name);
30
31 g_hash_table_remove(menu_map, &self->title);
32 g_hash_table_remove(menu_map, &self->frame);
33 g_hash_table_remove(menu_map, &self->items);
34
35 appearance_free(self->a_title);
36 XDestroyWindow(ob_display, self->title);
37 XDestroyWindow(ob_display, self->frame);
38 XDestroyWindow(ob_display, self->items);
39
40 g_free(self);
41 }
42
43 void menu_entry_free(MenuEntry *self)
44 {
45 g_free(self->label);
46 action_free(self->action);
47
48 g_hash_table_remove(menu_map, &self->item);
49
50 appearance_free(self->a_item);
51 appearance_free(self->a_disabled);
52 appearance_free(self->a_hilite);
53 XDestroyWindow(ob_display, self->item);
54
55 g_free(self);
56 }
57
58 void menu_startup()
59 {
60 Menu *m;
61 Action *a;
62
63 menu_hash = g_hash_table_new_full(g_str_hash, g_str_equal,
64 menu_destroy_hash_key,
65 (GDestroyNotify)menu_destroy_hash_value);
66 menu_map = g_hash_table_new(g_int_hash, g_int_equal);
67
68 m = menu_new("sex menu", "root", NULL);
69 a = action_from_string("execute");
70 a->data.execute.path = g_strdup("xterm");
71 menu_add_entry(m, menu_entry_new("xterm", a));
72 a = action_from_string("restart");
73 menu_add_entry(m, menu_entry_new("restart", a));
74 menu_add_entry(m, menu_entry_new("--", NULL));
75 a = action_from_string("exit");
76 menu_add_entry(m, menu_entry_new("exit", a));
77 }
78
79 void menu_shutdown()
80 {
81 g_hash_table_destroy(menu_hash);
82 g_hash_table_destroy(menu_map);
83 }
84
85 static Window createWindow(Window parent, unsigned long mask,
86 XSetWindowAttributes *attrib)
87 {
88 return XCreateWindow(ob_display, parent, 0, 0, 1, 1, 0,
89 render_depth, InputOutput, render_visual,
90 mask, attrib);
91
92 }
93
94 Menu *menu_new(char *label, char *name, Menu *parent)
95 {
96 XSetWindowAttributes attrib;
97 Menu *self;
98
99 self = g_new0(Menu, 1);
100 self->label = g_strdup(label);
101 self->name = g_strdup(name);
102 self->parent = parent;
103
104 self->entries = NULL;
105 self->shown = FALSE;
106 self->invalid = FALSE;
107 /* default controllers? */
108
109 attrib.override_redirect = TRUE;
110 attrib.event_mask = FRAME_EVENTMASK;
111 self->frame = createWindow(ob_root, CWOverrideRedirect|CWEventMask, &attrib);
112 attrib.event_mask = TITLE_EVENTMASK;
113 self->title = createWindow(self->frame, CWEventMask, &attrib);
114 self->items = createWindow(self->frame, 0, &attrib);
115
116 XSetWindowBorderWidth(ob_display, self->frame, theme_bwidth);
117 XSetWindowBorderWidth(ob_display, self->title, theme_bwidth);
118 XSetWindowBorder(ob_display, self->frame, theme_b_color->pixel);
119 XSetWindowBorder(ob_display, self->title, theme_b_color->pixel);
120
121 XMapWindow(ob_display, self->title);
122 XMapWindow(ob_display, self->items);
123
124 self->a_title = appearance_copy(theme_a_menu_title);
125 self->a_items = appearance_copy(theme_a_menu);
126
127 g_hash_table_insert(menu_map, &self->frame, self);
128 g_hash_table_insert(menu_map, &self->title, self);
129 g_hash_table_insert(menu_map, &self->items, self);
130 g_hash_table_insert(menu_hash, g_strdup(name), self);
131 return self;
132 }
133
134 void menu_free(char *name)
135 {
136 g_hash_table_remove(menu_hash, name);
137 }
138
139 MenuEntry *menu_entry_new_full(char *label, Action *action,
140 MenuEntryRenderType render_type,
141 gpointer submenu)
142 {
143 MenuEntry *menu_entry = g_new0(MenuEntry, 1);
144
145 menu_entry->label = g_strdup(label);
146 menu_entry->render_type = render_type;
147 menu_entry->action = action;
148
149 menu_entry->hilite = FALSE;
150 menu_entry->enabled = TRUE;
151
152 menu_entry->submenu = submenu;
153
154 return menu_entry;
155 }
156
157 void menu_entry_set_submenu(MenuEntry *entry, Menu *submenu)
158 {
159 g_assert(entry != NULL);
160
161 entry->submenu = submenu;
162
163 if(entry->parent != NULL)
164 entry->parent->invalid = TRUE;
165 }
166
167 void menu_add_entry(Menu *menu, MenuEntry *entry)
168 {
169 XSetWindowAttributes attrib;
170
171 g_assert(menu != NULL && entry != NULL && entry->item == None);
172
173 menu->entries = g_list_append(menu->entries, entry);
174 entry->parent = menu;
175
176 attrib.event_mask = ENTRY_EVENTMASK;
177 entry->item = createWindow(menu->items, CWEventMask, &attrib);
178 XMapWindow(ob_display, entry->item);
179 entry->a_item = appearance_copy(theme_a_menu_item);
180 entry->a_disabled = appearance_copy(theme_a_menu_disabled);
181 entry->a_hilite = appearance_copy(theme_a_menu_hilite);
182
183 menu->invalid = TRUE;
184
185 g_hash_table_insert(menu_map, &entry->item, menu);
186 }
187
188 void menu_show(char *name, int x, int y, Client *client)
189 {
190 Menu *self;
191
192 self = g_hash_table_lookup(menu_hash, name);
193 if (!self) {
194 g_warning("Attempted to show menu '%s' but it does not exist.",
195 name);
196 return;
197 }
198
199 if(self->invalid) {
200 menu_render(self);
201 }
202
203 XMoveWindow(ob_display, self->frame, x, y);
204
205 self->client = client;
206
207 if (!self->shown) {
208 stacking_raise_internal(self->frame);
209 XMapWindow(ob_display, self->frame);
210 /* grab_pointer_window(TRUE, None, self->frame);*/
211 self->shown = TRUE;
212 }
213 }
214
215 void menu_hide(Menu *self) {
216 if (self->shown) {
217 XUnmapWindow(ob_display, self->frame);
218 self->shown = FALSE;
219 }
220 }
221
222 MenuEntry *menu_find_entry(Menu *menu, Window win)
223 {
224 GList *it;
225
226 for (it = menu->entries; it; it = it->next) {
227 MenuEntry *entry = it->data;
228 if (entry->item == win)
229 return entry;
230 }
231 return NULL;
232 }
233
234 void menu_entry_render(MenuEntry *self)
235 {
236 Menu *menu = self->parent;
237 Appearance *a;
238
239 a = !self->enabled ? self->a_disabled :
240 (self->hilite && self->action ? self->a_hilite : self->a_item);
241
242 RECT_SET(a->area, 0, 0, menu->width,
243 menu->item_h);
244 RECT_SET(a->texture[0].position, menu->bullet_w,
245 0, menu->width - 2 * menu->bullet_w,
246 menu->item_h);
247
248 XMoveResizeWindow(ob_display, self->item, 0, self->y,
249 menu->width, menu->item_h);
250 a->surface.data.planar.parent = menu->a_items;
251 a->surface.data.planar.parentx = 0;
252 a->surface.data.planar.parenty = self->y;
253
254 paint(self->item, a);
255 }
256
257 void menu_entry_fire(MenuEntry *self)
258 {
259 Menu *m;
260
261 if (self->action) {
262 self->action->data.any.c = self->parent->client;
263 self->action->func(&self->action->data);
264
265 /* hide the whole thing */
266 m = self->parent;
267 while (m->parent) m = m->parent;
268 menu_hide(m);
269 }
270 }
This page took 0.056652 seconds and 5 git commands to generate.