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_control_show(Menu
*self
, int x
, int y
, Client
*client
);
17 void menu_destroy_hash_key(gpointer data
)
22 void menu_destroy_hash_value(Menu
*self
)
26 for (it
= self
->entries
; it
; it
= it
->next
)
27 menu_entry_free(it
->data
);
28 g_list_free(self
->entries
);
33 g_hash_table_remove(menu_map
, &self
->title
);
34 g_hash_table_remove(menu_map
, &self
->frame
);
35 g_hash_table_remove(menu_map
, &self
->items
);
37 appearance_free(self
->a_title
);
38 XDestroyWindow(ob_display
, self
->title
);
39 XDestroyWindow(ob_display
, self
->frame
);
40 XDestroyWindow(ob_display
, self
->items
);
45 void menu_entry_free(MenuEntry
*self
)
48 action_free(self
->action
);
50 g_hash_table_remove(menu_map
, &self
->item
);
52 appearance_free(self
->a_item
);
53 appearance_free(self
->a_disabled
);
54 appearance_free(self
->a_hilite
);
55 XDestroyWindow(ob_display
, self
->item
);
65 menu_hash
= g_hash_table_new_full(g_str_hash
, g_str_equal
,
66 menu_destroy_hash_key
,
67 (GDestroyNotify
)menu_destroy_hash_value
);
68 menu_map
= g_hash_table_new(g_int_hash
, g_int_equal
);
70 m
= menu_new("sex menu", "root", NULL
);
71 a
= action_from_string("execute");
72 a
->data
.execute
.path
= g_strdup("xterm");
73 menu_add_entry(m
, menu_entry_new("xterm", a
));
74 a
= action_from_string("restart");
75 menu_add_entry(m
, menu_entry_new("restart", a
));
76 menu_add_entry(m
, menu_entry_new("--", NULL
));
77 a
= action_from_string("exit");
78 menu_add_entry(m
, menu_entry_new("exit", a
));
83 g_hash_table_destroy(menu_hash
);
84 g_hash_table_destroy(menu_map
);
87 static Window
createWindow(Window parent
, unsigned long mask
,
88 XSetWindowAttributes
*attrib
)
90 return XCreateWindow(ob_display
, parent
, 0, 0, 1, 1, 0,
91 render_depth
, InputOutput
, render_visual
,
96 Menu
*menu_new_full(char *label
, char *name
, Menu
*parent
,
97 menu_controller_show show
, menu_controller_update update
)
99 XSetWindowAttributes attrib
;
102 self
= g_new0(Menu
, 1);
103 self
->label
= g_strdup(label
);
104 self
->name
= g_strdup(name
);
105 self
->parent
= parent
;
107 self
->entries
= NULL
;
109 self
->invalid
= FALSE
;
110 /* default controllers? */
114 self
->update
= update
;
115 self
->mouseover
= NULL
;
116 self
->selected
= NULL
;
118 attrib
.override_redirect
= TRUE
;
119 attrib
.event_mask
= FRAME_EVENTMASK
;
120 self
->frame
= createWindow(ob_root
, CWOverrideRedirect
|CWEventMask
, &attrib
);
121 attrib
.event_mask
= TITLE_EVENTMASK
;
122 self
->title
= createWindow(self
->frame
, CWEventMask
, &attrib
);
123 self
->items
= createWindow(self
->frame
, 0, &attrib
);
125 XSetWindowBorderWidth(ob_display
, self
->frame
, theme_bwidth
);
126 XSetWindowBorderWidth(ob_display
, self
->title
, theme_bwidth
);
127 XSetWindowBorder(ob_display
, self
->frame
, theme_b_color
->pixel
);
128 XSetWindowBorder(ob_display
, self
->title
, theme_b_color
->pixel
);
130 XMapWindow(ob_display
, self
->title
);
131 XMapWindow(ob_display
, self
->items
);
133 self
->a_title
= appearance_copy(theme_a_menu_title
);
134 self
->a_items
= appearance_copy(theme_a_menu
);
136 g_hash_table_insert(menu_map
, &self
->frame
, self
);
137 g_hash_table_insert(menu_map
, &self
->title
, self
);
138 g_hash_table_insert(menu_map
, &self
->items
, self
);
139 g_hash_table_insert(menu_hash
, g_strdup(name
), self
);
143 void menu_free(char *name
)
145 g_hash_table_remove(menu_hash
, name
);
148 MenuEntry
*menu_entry_new_full(char *label
, Action
*action
,
149 MenuEntryRenderType render_type
,
152 MenuEntry
*menu_entry
= g_new0(MenuEntry
, 1);
154 menu_entry
->label
= g_strdup(label
);
155 menu_entry
->render_type
= render_type
;
156 menu_entry
->action
= action
;
158 menu_entry
->hilite
= FALSE
;
159 menu_entry
->enabled
= TRUE
;
161 menu_entry
->submenu
= submenu
;
166 void menu_entry_set_submenu(MenuEntry
*entry
, Menu
*submenu
)
168 g_assert(entry
!= NULL
);
170 entry
->submenu
= submenu
;
172 if(entry
->parent
!= NULL
)
173 entry
->parent
->invalid
= TRUE
;
176 void menu_add_entry(Menu
*menu
, MenuEntry
*entry
)
178 XSetWindowAttributes attrib
;
180 g_assert(menu
!= NULL
&& entry
!= NULL
&& entry
->item
== None
);
182 menu
->entries
= g_list_append(menu
->entries
, entry
);
183 entry
->parent
= menu
;
185 attrib
.event_mask
= ENTRY_EVENTMASK
;
186 entry
->item
= createWindow(menu
->items
, CWEventMask
, &attrib
);
187 XMapWindow(ob_display
, entry
->item
);
188 entry
->a_item
= appearance_copy(theme_a_menu_item
);
189 entry
->a_disabled
= appearance_copy(theme_a_menu_disabled
);
190 entry
->a_hilite
= appearance_copy(theme_a_menu_hilite
);
192 menu
->invalid
= TRUE
;
194 g_hash_table_insert(menu_map
, &entry
->item
, menu
);
197 void menu_show(char *name
, int x
, int y
, Client
*client
)
201 self
= g_hash_table_lookup(menu_hash
, name
);
203 g_warning("Attempted to show menu '%s' but it does not exist.",
216 self
->client
= client
;
219 self
->show(self
, x
, y
, client
);
221 menu_control_show(self
, x
, y
, client
);
225 void menu_hide(Menu
*self
) {
227 XUnmapWindow(ob_display
, self
->frame
);
232 MenuEntry
*menu_find_entry(Menu
*menu
, Window win
)
236 for (it
= menu
->entries
; it
; it
= it
->next
) {
237 MenuEntry
*entry
= it
->data
;
238 if (entry
->item
== win
)
244 void menu_entry_render(MenuEntry
*self
)
246 Menu
*menu
= self
->parent
;
249 a
= !self
->enabled
? self
->a_disabled
:
250 (self
->hilite
&& self
->action
? self
->a_hilite
: self
->a_item
);
252 RECT_SET(a
->area
, 0, 0, menu
->width
,
254 RECT_SET(a
->texture
[0].position
, menu
->bullet_w
,
255 0, menu
->width
- 2 * menu
->bullet_w
,
258 XMoveResizeWindow(ob_display
, self
->item
, 0, self
->y
,
259 menu
->width
, menu
->item_h
);
260 a
->surface
.data
.planar
.parent
= menu
->a_items
;
261 a
->surface
.data
.planar
.parentx
= 0;
262 a
->surface
.data
.planar
.parenty
= self
->y
;
264 paint(self
->item
, a
);
267 void menu_entry_fire(MenuEntry
*self
)
272 self
->action
->data
.any
.c
= self
->parent
->client
;
273 self
->action
->func(&self
->action
->data
);
275 /* hide the whole thing */
277 while (m
->parent
) m
= m
->parent
;
283 Default menu controller action for showing.
286 void menu_control_show(Menu
*self
, int x
, int y
, Client
*client
) {
287 XMoveWindow(ob_display
, self
->frame
, x
, y
);
290 stacking_raise_internal(self
->frame
);
291 XMapWindow(ob_display
, self
->frame
);