5 #include "render/theme.h"
7 static GHashTable *menu_hash = NULL;
8 GHashTable *menu_map = NULL;
10 #define FRAME_EVENTMASK (ButtonMotionMask | EnterWindowMask | LeaveWindowMask)
11 #define TITLE_EVENTMASK (ButtonPressMask | ButtonMotionMask)
12 #define ENTRY_EVENTMASK (EnterWindowMask | LeaveWindowMask | \
13 ButtonPressMask | ButtonReleaseMask)
15 void menu_destroy_hash_key(gpointer data)
20 void menu_destroy_hash_value(Menu *self)
24 for (it = self->entries; it; it = it->next)
25 menu_entry_free(it->data);
26 g_list_free(self->entries);
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);
35 appearance_free(self->a_title);
36 XDestroyWindow(ob_display, self->title);
37 XDestroyWindow(ob_display, self->frame);
38 XDestroyWindow(ob_display, self->items);
43 void menu_entry_free(MenuEntry *self)
46 action_free(self->action);
48 g_hash_table_remove(menu_map, &self->item);
50 appearance_free(self->a_item);
51 appearance_free(self->a_disabled);
52 appearance_free(self->a_hilite);
53 XDestroyWindow(ob_display, self->item);
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);
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));
81 g_hash_table_destroy(menu_hash);
82 g_hash_table_destroy(menu_map);
85 static Window createWindow(Window parent, unsigned long mask,
86 XSetWindowAttributes *attrib)
88 return XCreateWindow(ob_display, parent, 0, 0, 1, 1, 0,
89 render_depth, InputOutput, render_visual,
94 Menu *menu_new(char *label, char *name, Menu *parent)
96 XSetWindowAttributes attrib;
99 self = g_new0(Menu, 1);
100 self->label = g_strdup(label);
101 self->name = g_strdup(name);
102 self->parent = parent;
104 self->entries = NULL;
106 self->invalid = FALSE;
107 /* default controllers? */
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);
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);
121 XMapWindow(ob_display, self->title);
122 XMapWindow(ob_display, self->items);
124 self->a_title = appearance_copy(theme_a_menu_title);
125 self->a_items = appearance_copy(theme_a_menu);
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);
134 void menu_free(char *name)
136 g_hash_table_remove(menu_hash, name);
139 MenuEntry *menu_entry_new_full(char *label, Action *action,
140 MenuEntryRenderType render_type,
143 MenuEntry *menu_entry = g_new0(MenuEntry, 1);
145 menu_entry->label = g_strdup(label);
146 menu_entry->render_type = render_type;
147 menu_entry->action = action;
149 menu_entry->hilite = FALSE;
150 menu_entry->enabled = TRUE;
152 menu_entry->submenu = submenu;
157 void menu_entry_set_submenu(MenuEntry *entry, Menu *submenu)
159 g_assert(entry != NULL);
161 entry->submenu = submenu;
163 if(entry->parent != NULL)
164 entry->parent->invalid = TRUE;
167 void menu_add_entry(Menu *menu, MenuEntry *entry)
169 XSetWindowAttributes attrib;
171 g_assert(menu != NULL && entry != NULL && entry->item == None);
173 menu->entries = g_list_append(menu->entries, entry);
174 entry->parent = menu;
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);
183 menu->invalid = TRUE;
185 g_hash_table_insert(menu_map, &entry->item, menu);
188 void menu_show(char *name, int x, int y, Client *client)
192 self = g_hash_table_lookup(menu_hash, name);
194 g_warning("Attempted to show menu '%s' but it does not exist.",
203 XMoveWindow(ob_display, self->frame, x, y);
205 self->client = client;
208 stacking_raise_internal(self->frame);
209 XMapWindow(ob_display, self->frame);
210 /* grab_pointer_window(TRUE, None, self->frame);*/
215 void menu_hide(Menu *self) {
217 XUnmapWindow(ob_display, self->frame);
222 MenuEntry *menu_find_entry(Menu *menu, Window win)
226 for (it = menu->entries; it; it = it->next) {
227 MenuEntry *entry = it->data;
228 if (entry->item == win)
234 void menu_entry_render(MenuEntry *self)
236 Menu *menu = self->parent;
239 a = !self->enabled ? self->a_disabled :
240 (self->hilite && self->action ? self->a_hilite : self->a_item);
242 RECT_SET(a->area, 0, 0, menu->width,
244 RECT_SET(a->texture[0].position, menu->bullet_w,
245 0, menu->width - 2 * menu->bullet_w,
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;
254 paint(self->item, a);
257 void menu_entry_fire(MenuEntry *self)
262 self->action->data.any.c = self->parent->client;
263 self->action->func(&self->action->data);
265 /* hide the whole thing */
267 while (m->parent) m = m->parent;