]> Dogcows Code - chaz/openbox/blob - openbox/menu.c
start of showing/rendering menus. woot!
[chaz/openbox] / openbox / menu.c
1 #include "menu.h"
2 #include "openbox.h"
3 #include "render/theme.h"
4
5 GHashTable *menu_hash = NULL;
6
7 #define ENTRY_EVENTMASK (EnterWindowMask | LeaveWindowMask | \
8 ButtonPressMask | ButtonReleaseMask)
9
10 void menu_destroy_hash_key(gpointer data)
11 {
12 g_free(data);
13 }
14
15 void menu_free_entries(Menu *menu)
16 {
17 GList *it;
18
19 for (it = menu->entries; it; it = it->next)
20 menu_entry_free((MenuEntry *)it->data);
21
22 g_list_free(menu->entries);
23 }
24
25 void menu_destroy_hash_value(gpointer data)
26 {
27 Menu *del_menu = (Menu *)data;
28 MenuRenderData *rd = del_menu->render_data;
29
30 menu_free_entries(del_menu);
31
32 g_free(del_menu->label);
33 g_free(del_menu->name);
34
35 appearance_free(rd->a_title);
36 XDestroyWindow(ob_display, rd->title);
37 XDestroyWindow(ob_display, rd->frame);
38 }
39
40 void menu_entry_free(MenuEntry *entry)
41 {
42 g_free(entry->label);
43 g_free(entry->render_data);
44 action_free(entry->action);
45 }
46
47 void menu_startup()
48 {
49 Menu *m;
50
51 menu_hash = g_hash_table_new_full(g_str_hash, g_str_equal,
52 menu_destroy_hash_key,
53 menu_destroy_hash_value);
54 m = menu_new("sex menu", "root", NULL);
55 menu_add_entry(m, menu_entry_new("foo shit etc bleh",
56 action_from_string("restart")));
57 menu_add_entry(m, menu_entry_new("more shit",
58 action_from_string("restart")));
59 menu_add_entry(m, menu_entry_new("",
60 action_from_string("restart")));
61 menu_add_entry(m, menu_entry_new("and yet more",
62 action_from_string("restart")));
63 }
64
65 void menu_shutdown()
66 {
67 g_hash_table_destroy(menu_hash);
68 }
69
70 static Window createWindow(Window parent, unsigned long mask,
71 XSetWindowAttributes *attrib)
72 {
73 return XCreateWindow(ob_display, parent, 0, 0, 1, 1, 0,
74 render_depth, InputOutput, render_visual,
75 mask, attrib);
76
77 }
78
79 Menu *menu_new(char *label, char *name, Menu *parent)
80 {
81 XSetWindowAttributes attrib;
82 Menu *self;
83 MenuRenderData *data;
84
85 self = g_new0(Menu, 1);
86 self->label = g_strdup(label);
87 self->name = g_strdup(name);
88 self->parent = parent;
89
90 self->entries = NULL;
91 self->shown = FALSE;
92 self->invalid = FALSE;
93 /* default controllers? */
94
95 data = g_new(MenuRenderData, 1);
96
97 attrib.override_redirect = TRUE;
98 data->frame = createWindow(ob_root, CWOverrideRedirect, &attrib);
99 data->title = createWindow(data->frame, 0, &attrib);
100 data->items = createWindow(data->frame, 0, &attrib);
101
102 XSetWindowBorderWidth(ob_display, data->frame, theme_bwidth);
103 XSetWindowBorderWidth(ob_display, data->title, theme_bwidth);
104 XSetWindowBorder(ob_display, data->frame, theme_b_color->pixel);
105 XSetWindowBorder(ob_display, data->title, theme_b_color->pixel);
106
107 XMapWindow(ob_display, data->title);
108 XMapWindow(ob_display, data->items);
109
110 data->a_title = appearance_copy(theme_a_menu_title);
111 data->a_items = appearance_copy(theme_a_menu);
112
113 self->render_data = data;
114
115 g_hash_table_insert(menu_hash, g_strdup(name), self);
116 return self;
117 }
118
119 void menu_free(char *name)
120 {
121 g_hash_table_remove(menu_hash, name);
122 }
123
124 MenuEntry *menu_entry_new_full(char *label, Action *action,
125 MenuEntryRenderType render_type,
126 gpointer submenu)
127 {
128 MenuEntry *menu_entry = g_new(MenuEntry, 1);
129
130 menu_entry->label = g_strdup(label);
131 menu_entry->render_type = render_type;
132 menu_entry->action = action;
133
134 menu_entry->render_data = NULL;
135 menu_entry->submenu = submenu;
136
137 return menu_entry;
138 }
139
140 void menu_entry_set_submenu(MenuEntry *entry, Menu *submenu)
141 {
142 g_assert(entry != NULL);
143
144 entry->submenu = submenu;
145
146 if(entry->parent != NULL)
147 entry->parent->invalid = TRUE;
148 }
149
150 void menu_add_entry(Menu *menu, MenuEntry *entry)
151 {
152 MenuEntryRenderData *data;
153 XSetWindowAttributes attrib;
154
155 g_assert(menu != NULL && entry != NULL && entry->render_data == NULL);
156
157 menu->entries = g_list_append(menu->entries, entry);
158 entry->parent = menu;
159
160 data = g_new(MenuEntryRenderData, 1);
161 data->item = createWindow(((MenuRenderData*)menu->render_data)->items,
162 0, &attrib);
163 XMapWindow(ob_display, data->item);
164 data->a_item = appearance_copy(theme_a_menu_item);
165
166 entry->render_data = data;
167
168 menu->invalid = TRUE;
169 }
170
171 void menu_show(char *name, int x, int y, Client *client)
172 {
173 Menu *self;
174 MenuRenderData *data;
175 GList *it;
176 int w = 1;
177 int items_h;
178 int item_h = 0, nitems = 0; /* each item, only one is used */
179 int item_y;
180 int bullet_w;
181
182 self = g_hash_table_lookup(menu_hash, name);
183 if (!self) {
184 g_warning("Attempted to show menu '%s' but it does not exist.",
185 name);
186 return;
187 }
188
189 data = self->render_data;
190
191 /* set texture data and size them mofos out */
192 data->a_title->texture[0].data.text.string = self->label;
193 appearance_minsize(data->a_title, &data->title_min_w, &data->title_h);
194 data->title_min_w += theme_bevel * 2;
195 data->title_h += theme_bevel * 2;
196 w = MAX(w, data->title_min_w);
197
198 for (it = self->entries; it; it = it->next) {
199 MenuEntryRenderData *r = ((MenuEntry*)it->data)->render_data;
200
201 r->a_item->texture[0].data.text.string = ((MenuEntry*)it->data)->label;
202 appearance_minsize(r->a_item, &r->min_w, &item_h);
203 r->min_w += theme_bevel * 2;
204 item_h += theme_bevel * 2;
205 w = MAX(w, r->min_w);
206 ++nitems;
207 }
208 bullet_w = item_h + theme_bevel;
209 w += 2 * bullet_w;
210 items_h = item_h * nitems;
211
212 /* size appearances */
213 RECT_SET(data->a_title->area, 0, 0, w, data->title_h);
214 RECT_SET(data->a_title->texture[0].position, 0, 0, w, data->title_h);
215 RECT_SET(data->a_items->area, 0, 0, w, items_h);
216 for (it = self->entries; it; it = it->next) {
217 MenuEntryRenderData *r = ((MenuEntry*)it->data)->render_data;
218 RECT_SET(r->a_item->area, 0, 0, w, item_h);
219 RECT_SET(r->a_item->texture[0].position, bullet_w, 0,
220 w - 2 * bullet_w, item_h);
221 }
222
223 /* size windows and paint the suckers */
224 XMoveResizeWindow(ob_display, data->frame, x, y, w,
225 data->title_h + items_h);
226 XMoveResizeWindow(ob_display, data->title, -theme_bwidth, -theme_bwidth,
227 w, data->title_h);
228 paint(data->title, data->a_title);
229 XMoveResizeWindow(ob_display, data->items, 0, data->title_h + theme_bwidth,
230 w, items_h);
231 paint(data->items, data->a_items);
232 for (item_y = 0, it = self->entries; it; item_y += item_h, it = it->next) {
233 MenuEntryRenderData *r = ((MenuEntry*)it->data)->render_data;
234 XMoveResizeWindow(ob_display, r->item, 0, item_y, w, item_h);
235 r->a_item->surface.data.planar.parent = data->a_items;
236 r->a_item->surface.data.planar.parentx = 0;
237 r->a_item->surface.data.planar.parenty = item_y;
238 paint(r->item, r->a_item);
239 }
240
241
242 XMapWindow(ob_display, data->frame);
243 }
This page took 0.051055 seconds and 5 git commands to generate.