+ g_free(self->label);
+ g_free(self->name);
+
+ g_hash_table_remove(window_map, &self->title);
+ g_hash_table_remove(window_map, &self->frame);
+ g_hash_table_remove(window_map, &self->items);
+
+ stacking_remove(self);
+
+ appearance_free(self->a_title);
+ XDestroyWindow(ob_display, self->title);
+ XDestroyWindow(ob_display, self->frame);
+ XDestroyWindow(ob_display, self->items);
+
+ g_free(self);
+}
+
+void menu_entry_free(MenuEntry *self)
+{
+ g_free(self->label);
+ action_free(self->action);
+
+ g_hash_table_remove(window_map, &self->item);
+
+ appearance_free(self->a_item);
+ appearance_free(self->a_disabled);
+ appearance_free(self->a_hilite);
+ XDestroyWindow(ob_display, self->item);
+
+ g_free(self);
+}
+
+void menu_startup()
+{
+ Menu *m;
+ Menu *s;
+ Menu *t;
+ Action *a;
+
+ menu_hash = g_hash_table_new_full(g_str_hash, g_str_equal,
+ menu_destroy_hash_key,
+ (GDestroyNotify)menu_destroy_hash_value);
+
+ m = menu_new("sex menu", "root", NULL);
+
+ a = action_from_string("execute");
+ a->data.execute.path = g_strdup("xterm");
+ menu_add_entry(m, menu_entry_new("xterm", a));
+ a = action_from_string("restart");
+ menu_add_entry(m, menu_entry_new("restart", a));
+ menu_add_entry(m, menu_entry_new_separator("--"));
+ a = action_from_string("exit");
+ menu_add_entry(m, menu_entry_new("exit", a));
+
+ /*
+ s = menu_new("subsex menu", "submenu", m);
+ a = action_from_string("execute");
+ a->data.execute.path = g_strdup("xclock");
+ menu_add_entry(s, menu_entry_new("xclock", a));
+
+ menu_add_entry(m, menu_entry_new_submenu("subz", s));
+
+ s = menu_new("empty", "chub", m);
+ menu_add_entry(m, menu_entry_new_submenu("empty", s));
+
+ s = menu_new("", "s-club", m);
+ menu_add_entry(m, menu_entry_new_submenu("empty", s));
+
+ s = menu_new(NULL, "h-club", m);
+ menu_add_entry(m, menu_entry_new_submenu("empty", s));
+
+ s = menu_new(NULL, "g-club", m);
+
+ a = action_from_string("execute");
+ a->data.execute.path = g_strdup("xterm");
+ menu_add_entry(s, menu_entry_new("xterm", a));
+ a = action_from_string("restart");
+ menu_add_entry(s, menu_entry_new("restart", a));
+ menu_add_entry(s, menu_entry_new_separator("--"));
+ a = action_from_string("exit");
+ menu_add_entry(s, menu_entry_new("exit", a));
+
+ menu_add_entry(m, menu_entry_new_submenu("long", s));
+ */
+}
+
+void menu_shutdown()
+{
+ g_hash_table_destroy(menu_hash);
+}
+
+static Window createWindow(Window parent, unsigned long mask,
+ XSetWindowAttributes *attrib)
+{
+ return XCreateWindow(ob_display, parent, 0, 0, 1, 1, 0,
+ render_depth, InputOutput, render_visual,
+ mask, attrib);
+
+}
+
+Menu *menu_new_full(char *label, char *name, Menu *parent,
+ menu_controller_show show, menu_controller_update update)
+{
+ XSetWindowAttributes attrib;
+ Menu *self;
+
+ self = g_new0(Menu, 1);
+ self->obwin.type = Window_Menu;
+ self->label = g_strdup(label);
+ self->name = g_strdup(name);
+ self->parent = parent;
+ self->open_submenu = NULL;
+
+ self->entries = NULL;
+ self->shown = FALSE;
+ self->invalid = TRUE;
+
+ /* default controllers */
+ self->show = show;
+ self->hide = NULL;
+ self->update = update;
+ self->mouseover = NULL;
+ self->selected = NULL;
+
+ self->plugin = NULL;
+ self->plugin_data = NULL;
+
+ attrib.override_redirect = TRUE;
+ attrib.event_mask = FRAME_EVENTMASK;
+ self->frame = createWindow(ob_root, CWOverrideRedirect|CWEventMask, &attrib);
+ attrib.event_mask = TITLE_EVENTMASK;
+ self->title = createWindow(self->frame, CWEventMask, &attrib);
+ self->items = createWindow(self->frame, 0, &attrib);
+
+ XSetWindowBorderWidth(ob_display, self->frame, theme_bwidth);
+ XSetWindowBackground(ob_display, self->frame, theme_b_color->pixel);
+ XSetWindowBorderWidth(ob_display, self->title, theme_bwidth);
+ XSetWindowBorder(ob_display, self->frame, theme_b_color->pixel);
+ XSetWindowBorder(ob_display, self->title, theme_b_color->pixel);
+
+ XMapWindow(ob_display, self->title);
+ XMapWindow(ob_display, self->items);
+
+ self->a_title = appearance_copy(theme_a_menu_title);
+ self->a_items = appearance_copy(theme_a_menu);
+
+ g_hash_table_insert(window_map, &self->frame, self);
+ g_hash_table_insert(window_map, &self->title, self);
+ g_hash_table_insert(window_map, &self->items, self);
+ g_hash_table_insert(menu_hash, g_strdup(name), self);
+
+ stacking_add(MENU_AS_WINDOW(self));
+ stacking_raise(MENU_AS_WINDOW(self));
+
+ return self;
+}
+
+void menu_free(char *name)
+{
+ g_hash_table_remove(menu_hash, name);