4 #include "render/theme.h"
6 static GHashTable
*menu_hash
= NULL
;
7 GHashTable
*menu_map
= NULL
;
9 #define TITLE_EVENTMASK (ButtonPressMask | ButtonMotionMask)
10 #define ENTRY_EVENTMASK (EnterWindowMask | LeaveWindowMask | \
11 ButtonPressMask | ButtonReleaseMask)
13 void menu_destroy_hash_key(gpointer data
)
18 void menu_destroy_hash_value(Menu
*self
)
22 for (it
= self
->entries
; it
; it
= it
->next
)
23 menu_entry_free(it
->data
);
24 g_list_free(self
->entries
);
29 g_hash_table_remove(menu_map
, &self
->title
);
30 g_hash_table_remove(menu_map
, &self
->frame
);
31 g_hash_table_remove(menu_map
, &self
->items
);
33 appearance_free(self
->a_title
);
34 XDestroyWindow(ob_display
, self
->title
);
35 XDestroyWindow(ob_display
, self
->frame
);
36 XDestroyWindow(ob_display
, self
->items
);
41 void menu_entry_free(MenuEntry
*self
)
44 action_free(self
->action
);
46 g_hash_table_remove(menu_map
, &self
->item
);
48 appearance_free(self
->a_item
);
49 appearance_free(self
->a_disabled
);
50 appearance_free(self
->a_hilite
);
51 XDestroyWindow(ob_display
, self
->item
);
60 menu_hash
= g_hash_table_new_full(g_str_hash
, g_str_equal
,
61 menu_destroy_hash_key
,
62 (GDestroyNotify
)menu_destroy_hash_value
);
63 menu_map
= g_hash_table_new(g_int_hash
, g_int_equal
);
65 m
= menu_new("sex menu", "root", NULL
);
66 menu_add_entry(m
, menu_entry_new("foo shit etc bleh",
67 action_from_string("restart")));
68 menu_add_entry(m
, menu_entry_new("more shit",
69 action_from_string("restart")));
70 menu_add_entry(m
, menu_entry_new("",
71 action_from_string("restart")));
72 menu_add_entry(m
, menu_entry_new("and yet more",
73 action_from_string("restart")));
78 g_hash_table_destroy(menu_hash
);
79 g_hash_table_destroy(menu_map
);
82 static Window
createWindow(Window parent
, unsigned long mask
,
83 XSetWindowAttributes
*attrib
)
85 return XCreateWindow(ob_display
, parent
, 0, 0, 1, 1, 0,
86 render_depth
, InputOutput
, render_visual
,
91 Menu
*menu_new(char *label
, char *name
, Menu
*parent
)
93 XSetWindowAttributes attrib
;
96 self
= g_new0(Menu
, 1);
97 self
->label
= g_strdup(label
);
98 self
->name
= g_strdup(name
);
99 self
->parent
= parent
;
101 self
->entries
= NULL
;
103 self
->invalid
= FALSE
;
104 /* default controllers? */
106 attrib
.override_redirect
= TRUE
;
107 self
->frame
= createWindow(ob_root
, CWOverrideRedirect
, &attrib
);
108 attrib
.event_mask
= TITLE_EVENTMASK
;
109 self
->title
= createWindow(self
->frame
, CWEventMask
, &attrib
);
110 self
->items
= createWindow(self
->frame
, 0, &attrib
);
112 XSetWindowBorderWidth(ob_display
, self
->frame
, theme_bwidth
);
113 XSetWindowBorderWidth(ob_display
, self
->title
, theme_bwidth
);
114 XSetWindowBorder(ob_display
, self
->frame
, theme_b_color
->pixel
);
115 XSetWindowBorder(ob_display
, self
->title
, theme_b_color
->pixel
);
117 XMapWindow(ob_display
, self
->title
);
118 XMapWindow(ob_display
, self
->items
);
120 self
->a_title
= appearance_copy(theme_a_menu_title
);
121 self
->a_items
= appearance_copy(theme_a_menu
);
123 g_hash_table_insert(menu_map
, &self
->frame
, self
);
124 g_hash_table_insert(menu_map
, &self
->title
, self
);
125 g_hash_table_insert(menu_map
, &self
->items
, self
);
126 g_hash_table_insert(menu_hash
, g_strdup(name
), self
);
130 void menu_free(char *name
)
132 g_hash_table_remove(menu_hash
, name
);
135 MenuEntry
*menu_entry_new_full(char *label
, Action
*action
,
136 MenuEntryRenderType render_type
,
139 MenuEntry
*menu_entry
= g_new0(MenuEntry
, 1);
141 menu_entry
->label
= g_strdup(label
);
142 menu_entry
->render_type
= render_type
;
143 menu_entry
->action
= action
;
145 menu_entry
->hilite
= FALSE
;
146 menu_entry
->enabled
= TRUE
;
148 menu_entry
->submenu
= submenu
;
153 void menu_entry_set_submenu(MenuEntry
*entry
, Menu
*submenu
)
155 g_assert(entry
!= NULL
);
157 entry
->submenu
= submenu
;
159 if(entry
->parent
!= NULL
)
160 entry
->parent
->invalid
= TRUE
;
163 void menu_add_entry(Menu
*menu
, MenuEntry
*entry
)
165 XSetWindowAttributes attrib
;
167 g_assert(menu
!= NULL
&& entry
!= NULL
&& entry
->item
== None
);
169 menu
->entries
= g_list_append(menu
->entries
, entry
);
170 entry
->parent
= menu
;
172 attrib
.event_mask
= ENTRY_EVENTMASK
;
173 entry
->item
= createWindow(menu
->items
, CWEventMask
, &attrib
);
174 XMapWindow(ob_display
, entry
->item
);
175 entry
->a_item
= appearance_copy(theme_a_menu_item
);
176 entry
->a_disabled
= appearance_copy(theme_a_menu_disabled
);
177 entry
->a_hilite
= appearance_copy(theme_a_menu_hilite
);
179 menu
->invalid
= TRUE
;
181 g_hash_table_insert(menu_map
, &entry
->item
, menu
);
184 void menu_show(char *name
, int x
, int y
, Client
*client
)
189 int nitems
= 0; /* each item, only one is used */
192 self
= g_hash_table_lookup(menu_hash
, name
);
194 g_warning("Attempted to show menu '%s' but it does not exist.",
202 /* set texture data and size them mofos out */
203 self
->a_title
->texture
[0].data
.text
.string
= self
->label
;
204 appearance_minsize(self
->a_title
, &self
->title_min_w
, &self
->title_h
);
205 self
->title_min_w
+= theme_bevel
* 2;
206 self
->title_h
+= theme_bevel
* 2;
207 self
->width
= MAX(self
->width
, self
->title_min_w
);
209 for (it
= self
->entries
; it
; it
= it
->next
) {
210 MenuEntry
*e
= it
->data
;
213 e
->a_item
->texture
[0].data
.text
.string
= e
->label
;
214 appearance_minsize(e
->a_item
, &e
->min_w
, &self
->item_h
);
215 self
->width
= MAX(self
->width
, e
->min_w
);
217 e
->a_disabled
->texture
[0].data
.text
.string
= e
->label
;
218 appearance_minsize(e
->a_disabled
, &e
->min_w
, &h
);
219 self
->item_h
= MAX(self
->item_h
, h
);
220 self
->width
= MAX(self
->width
, e
->min_w
);
222 e
->a_hilite
->texture
[0].data
.text
.string
= e
->label
;
223 appearance_minsize(e
->a_hilite
, &e
->min_w
, &h
);
224 self
->item_h
= MAX(self
->item_h
, h
);
225 self
->width
= MAX(self
->width
, e
->min_w
);
227 e
->min_w
+= theme_bevel
* 2;
230 self
->bullet_w
= self
->item_h
+ theme_bevel
;
231 self
->width
+= 2 * self
->bullet_w
;
232 self
->item_h
+= theme_bevel
* 2;
233 items_h
= self
->item_h
* nitems
;
235 RECT_SET(self
->a_title
->area
, 0, 0, self
->width
, self
->title_h
);
236 RECT_SET(self
->a_title
->texture
[0].position
, 0, 0, self
->width
,
238 RECT_SET(self
->a_items
->area
, 0, 0, self
->width
, items_h
);
240 XMoveResizeWindow(ob_display
, self
->frame
, x
, y
, self
->width
,
241 self
->title_h
+ items_h
);
242 XMoveResizeWindow(ob_display
, self
->title
, -theme_bwidth
, -theme_bwidth
,
243 self
->width
, self
->title_h
);
244 XMoveResizeWindow(ob_display
, self
->items
, 0, self
->title_h
+ theme_bwidth
,
245 self
->width
, items_h
);
247 paint(self
->title
, self
->a_title
);
248 paint(self
->items
, self
->a_items
);
251 for (it
= self
->entries
; it
; it
= it
->next
) {
252 ((MenuEntry
*)it
->data
)->y
= item_y
;
253 menu_entry_render(it
->data
);
254 item_y
+= self
->item_h
;
257 stacking_raise_internal(self
->frame
);
258 XMapWindow(ob_display
, self
->frame
);
261 MenuEntry
*menu_find_entry(Menu
*menu
, Window win
)
265 for (it
= menu
->entries
; it
; it
= it
->next
) {
266 MenuEntry
*entry
= it
->data
;
267 if (entry
->item
== win
)
273 void menu_entry_render(MenuEntry
*self
)
275 Menu
*menu
= self
->parent
;
278 a
= !self
->enabled
? self
->a_disabled
:
279 (self
->hilite
? self
->a_hilite
: self
->a_item
);
281 RECT_SET(a
->area
, 0, 0, menu
->width
,
283 RECT_SET(a
->texture
[0].position
, menu
->bullet_w
,
284 0, menu
->width
- 2 * menu
->bullet_w
,
287 XMoveResizeWindow(ob_display
, self
->item
, 0, self
->y
,
288 menu
->width
, menu
->item_h
);
289 a
->surface
.data
.planar
.parent
= menu
->a_items
;
290 a
->surface
.data
.planar
.parentx
= 0;
291 a
->surface
.data
.planar
.parenty
= self
->y
;
293 paint(self
->item
, a
);