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
));
80 m
= menu_new("client menu", "client", NULL
);
81 a
= action_from_string("iconify");
82 menu_add_entry(m
, menu_entry_new("iconify", a
));
83 a
= action_from_string("toggleshade");
84 menu_add_entry(m
, menu_entry_new("(un)shade", a
));
85 a
= action_from_string("togglemaximizefull");
86 menu_add_entry(m
, menu_entry_new("(un)maximize", a
));
87 a
= action_from_string("close");
88 menu_add_entry(m
, menu_entry_new("close", a
));
93 g_hash_table_destroy(menu_hash
);
94 g_hash_table_destroy(menu_map
);
97 static Window
createWindow(Window parent
, unsigned long mask
,
98 XSetWindowAttributes
*attrib
)
100 return XCreateWindow(ob_display
, parent
, 0, 0, 1, 1, 0,
101 render_depth
, InputOutput
, render_visual
,
106 Menu
*menu_new_full(char *label
, char *name
, Menu
*parent
,
107 menu_controller_show show
, menu_controller_update update
)
109 XSetWindowAttributes attrib
;
112 self
= g_new0(Menu
, 1);
113 self
->label
= g_strdup(label
);
114 self
->name
= g_strdup(name
);
115 self
->parent
= parent
;
117 self
->entries
= NULL
;
119 self
->invalid
= FALSE
;
120 /* default controllers? */
124 self
->update
= update
;
125 self
->mouseover
= NULL
;
126 self
->selected
= NULL
;
128 attrib
.override_redirect
= TRUE
;
129 attrib
.event_mask
= FRAME_EVENTMASK
;
130 self
->frame
= createWindow(ob_root
, CWOverrideRedirect
|CWEventMask
, &attrib
);
131 attrib
.event_mask
= TITLE_EVENTMASK
;
132 self
->title
= createWindow(self
->frame
, CWEventMask
, &attrib
);
133 self
->items
= createWindow(self
->frame
, 0, &attrib
);
135 XSetWindowBorderWidth(ob_display
, self
->frame
, theme_bwidth
);
136 XSetWindowBorderWidth(ob_display
, self
->title
, theme_bwidth
);
137 XSetWindowBorder(ob_display
, self
->frame
, theme_b_color
->pixel
);
138 XSetWindowBorder(ob_display
, self
->title
, theme_b_color
->pixel
);
140 XMapWindow(ob_display
, self
->title
);
141 XMapWindow(ob_display
, self
->items
);
143 self
->a_title
= appearance_copy(theme_a_menu_title
);
144 self
->a_items
= appearance_copy(theme_a_menu
);
146 g_hash_table_insert(menu_map
, &self
->frame
, self
);
147 g_hash_table_insert(menu_map
, &self
->title
, self
);
148 g_hash_table_insert(menu_map
, &self
->items
, self
);
149 g_hash_table_insert(menu_hash
, g_strdup(name
), self
);
153 void menu_free(char *name
)
155 g_hash_table_remove(menu_hash
, name
);
158 MenuEntry
*menu_entry_new_full(char *label
, Action
*action
,
159 MenuEntryRenderType render_type
,
162 MenuEntry
*menu_entry
= g_new0(MenuEntry
, 1);
164 menu_entry
->label
= g_strdup(label
);
165 menu_entry
->render_type
= render_type
;
166 menu_entry
->action
= action
;
168 menu_entry
->hilite
= FALSE
;
169 menu_entry
->enabled
= TRUE
;
171 menu_entry
->submenu
= submenu
;
176 void menu_entry_set_submenu(MenuEntry
*entry
, Menu
*submenu
)
178 g_assert(entry
!= NULL
);
180 entry
->submenu
= submenu
;
182 if(entry
->parent
!= NULL
)
183 entry
->parent
->invalid
= TRUE
;
186 void menu_add_entry(Menu
*menu
, MenuEntry
*entry
)
188 XSetWindowAttributes attrib
;
190 g_assert(menu
!= NULL
&& entry
!= NULL
&& entry
->item
== None
);
192 menu
->entries
= g_list_append(menu
->entries
, entry
);
193 entry
->parent
= menu
;
195 attrib
.event_mask
= ENTRY_EVENTMASK
;
196 entry
->item
= createWindow(menu
->items
, CWEventMask
, &attrib
);
197 XMapWindow(ob_display
, entry
->item
);
198 entry
->a_item
= appearance_copy(theme_a_menu_item
);
199 entry
->a_disabled
= appearance_copy(theme_a_menu_disabled
);
200 entry
->a_hilite
= appearance_copy(theme_a_menu_hilite
);
202 menu
->invalid
= TRUE
;
204 g_hash_table_insert(menu_map
, &entry
->item
, menu
);
207 void menu_show(char *name
, int x
, int y
, Client
*client
)
211 self
= g_hash_table_lookup(menu_hash
, name
);
213 g_warning("Attempted to show menu '%s' but it does not exist.",
226 self
->client
= client
;
229 self
->show(self
, x
, y
, client
);
231 menu_control_show(self
, x
, y
, client
);
235 void menu_hide(Menu
*self
) {
237 XUnmapWindow(ob_display
, self
->frame
);
242 MenuEntry
*menu_find_entry(Menu
*menu
, Window win
)
246 for (it
= menu
->entries
; it
; it
= it
->next
) {
247 MenuEntry
*entry
= it
->data
;
248 if (entry
->item
== win
)
254 void menu_entry_render(MenuEntry
*self
)
256 Menu
*menu
= self
->parent
;
259 a
= !self
->enabled
? self
->a_disabled
:
260 (self
->hilite
&& self
->action
? self
->a_hilite
: self
->a_item
);
262 RECT_SET(a
->area
, 0, 0, menu
->width
,
264 RECT_SET(a
->texture
[0].position
, menu
->bullet_w
,
265 0, menu
->width
- 2 * menu
->bullet_w
,
268 XMoveResizeWindow(ob_display
, self
->item
, 0, self
->y
,
269 menu
->width
, menu
->item_h
);
270 a
->surface
.data
.planar
.parent
= menu
->a_items
;
271 a
->surface
.data
.planar
.parentx
= 0;
272 a
->surface
.data
.planar
.parenty
= self
->y
;
274 paint(self
->item
, a
);
277 void menu_entry_fire(MenuEntry
*self
)
282 self
->action
->data
.any
.c
= self
->parent
->client
;
283 self
->action
->func(&self
->action
->data
);
285 /* hide the whole thing */
287 while (m
->parent
) m
= m
->parent
;
293 Default menu controller action for showing.
296 void menu_control_show(Menu
*self
, int x
, int y
, Client
*client
) {
297 XMoveWindow(ob_display
, self
->frame
, x
, y
);
300 stacking_raise_internal(self
->frame
);
301 XMapWindow(ob_display
, self
->frame
);