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
;