#include "stacking.h"
#include "client.h"
#include "grab.h"
+#include "config.h"
#include "screen.h"
#include "geom.h"
#include "plugin.h"
#include "misc.h"
+#include "parser/parse.h"
GHashTable *menu_hash = NULL;
GList *menu_visible = NULL;
#define ENTRY_EVENTMASK (EnterWindowMask | LeaveWindowMask | \
ButtonPressMask | ButtonReleaseMask)
-static void parse_menu(xmlDocPtr doc, xmlNodePtr node, void *data)
+static void parse_menu(ObParseInst *i, xmlDocPtr doc, xmlNodePtr node,
+ gpointer data)
{
- parse_menu_full(doc, node, data, TRUE);
+ g_message("%s", __FUNCTION__);
+ parse_menu_full(i, doc, node, data, TRUE);
}
-void parse_menu_full(xmlDocPtr doc, xmlNodePtr node, void *data,
- gboolean newmenu)
+void parse_menu_full(ObParseInst *i, xmlDocPtr doc, xmlNodePtr node,
+ gpointer data, gboolean newmenu)
{
- Action *act;
+ ObAction *act;
xmlNodePtr nact;
gchar *id = NULL, *title = NULL, *label = NULL, *plugin;
- ObMenu *menu = NULL, *parent;
+ ObMenu *menu = NULL, *parent = NULL;
if (newmenu == TRUE) {
if (!parse_attr_string("id", node, &id))
if (parse_attr_string("plugin", node, &plugin)) {
PluginMenuCreateData data;
+ data.parse_inst = i;
data.doc = doc;
data.node = node;
data.parent = menu;
- if (plugin_open_reopen(plugin))
- parent = plugin_create(plugin, &data);
+ if (plugin_open_reopen(plugin, i))
+ menu = plugin_create(plugin, &data);
g_free(plugin);
} else
menu = menu_new(title, id, data ? *((ObMenu**)data) : NULL);
- if (data)
+ if (data && menu)
*((ObMenu**)data) = menu;
} else {
menu = (ObMenu *)data;
data.doc = doc;
data.node = node;
data.parent = menu;
- if (plugin_open_reopen(plugin))
+ if (plugin_open_reopen(plugin, i))
parent = plugin_create(plugin, &data);
g_free(plugin);
} else {
parent = menu;
- parse_menu(doc, node, &parent);
+ parse_menu(i, doc, node, &parent);
+ }
+
+ if (parent)
menu_add_entry(menu, menu_entry_new_submenu(parent->label,
parent));
- }
}
else if (!xmlStrcasecmp(node->name, (const xmlChar*) "item")) {
{
GList *it;
+ if (self->destroy) self->destroy(self);
+
for (it = self->entries; it; it = it->next)
menu_entry_free(it->data);
g_list_free(self->entries);
RrAppearanceFree(self->a_item);
RrAppearanceFree(self->a_disabled);
RrAppearanceFree(self->a_hilite);
+ RrAppearanceFree(self->a_submenu);
XDestroyWindow(ob_display, self->item);
-
+ XDestroyWindow(ob_display, self->submenu_pic);
g_free(self);
}
-
-void menu_startup()
+
+void menu_startup(ObParseInst *i)
{
menu_hash = g_hash_table_new_full(g_str_hash, g_str_equal,
(GDestroyNotify)menu_destroy_hash_key,
(GDestroyNotify)menu_destroy_hash_value);
-
- parse_register("menu", parse_menu, NULL);
-
}
void menu_shutdown()
g_hash_table_destroy(menu_hash);
}
+void menu_parse()
+{
+ ObParseInst *i;
+ xmlDocPtr doc;
+ xmlNodePtr node;
+ gchar *p;
+ gboolean loaded = FALSE;
+
+ i = parse_startup();
+
+ if (config_menu_path)
+ if (!(loaded =
+ parse_load(config_menu_path, "openbox_menu", &doc, &node)))
+ g_warning("Failed to load menu from '%s'", config_menu_path);
+ if (!loaded) {
+ p = g_build_filename(g_get_home_dir(), ".openbox", "menu", NULL);
+ if (!(loaded =
+ parse_load(p, "openbox_menu", &doc, &node)))
+ g_warning("Failed to load menu from '%s'", p);
+ g_free(p);
+ }
+ if (!loaded) {
+ p = g_build_filename(RCDIR, "menu", NULL);
+ if (!(loaded =
+ parse_load(p, "openbox_menu", &doc, &node)))
+ g_warning("Failed to load menu from '%s'", p);
+ g_free(p);
+ }
+
+ if (loaded) {
+ parse_register(i, "menu", parse_menu, NULL);
+ parse_tree(i, doc, node->xmlChildrenNode);
+ }
+
+ parse_shutdown(i);
+}
+
static Window createWindow(Window parent, unsigned long mask,
XSetWindowAttributes *attrib)
{
menu_controller_show show, menu_controller_update update,
menu_controller_selected selected,
menu_controller_hide hide,
- menu_controller_mouseover mouseover)
+ menu_controller_mouseover mouseover,
+ menu_controller_destroy destroy)
{
XSetWindowAttributes attrib;
ObMenu *self;
self->invalid = TRUE;
/* default controllers */
+ self->destroy = destroy;
self->show = (show != NULL ? show : menu_show_full);
self->hide = (hide != NULL ? hide : menu_hide);
self->update = (update != NULL ? update : menu_render);
g_hash_table_remove(menu_hash, name);
}
-ObMenuEntry *menu_entry_new_full(char *label, Action *action,
+ObMenuEntry *menu_entry_new_full(char *label, ObAction *action,
ObMenuEntryRenderType render_type,
gpointer submenu)
{
attrib.event_mask = ENTRY_EVENTMASK;
entry->item = createWindow(menu->items, CWEventMask, &attrib);
+ entry->submenu_pic = createWindow(menu->items, CWEventMask, &attrib);
XMapWindow(ob_display, entry->item);
+ XMapWindow(ob_display, entry->submenu_pic);
- entry->a_item = entry->a_disabled = entry->a_hilite = NULL;
+ entry->a_item = entry->a_disabled = entry->a_hilite = entry->a_submenu
+ = NULL;
menu->invalid = TRUE;
g_hash_table_insert(window_map, &entry->item, menu);
+ g_hash_table_insert(window_map, &entry->submenu_pic, menu);
}
void menu_show(char *name, int x, int y, ObClient *client)
{
ObMenu *m;
- if (button > 3) return;
+ /* ignore wheel scrolling */
+ if (button == 4 || button == 5) return;
if (self->action) {
self->action->data.any.c = self->parent->client;
ob_rr_theme->bwidth - ob_rr_theme->menu_overlap;
/* need to get the width. is this bad?*/
- self->parent->update(self->submenu);
+ self->submenu->update(self->submenu);
a = screen_physical_area_monitor(self->parent->xin_area);
- if (self->submenu->size.width + x >= a->x + a->width)
- x = self->parent->location.x - self->submenu->size.width -
- ob_rr_theme->bwidth + ob_rr_theme->menu_overlap;
+ if (self->submenu->size.width + x >= a->x + a->width) {
+ int newparentx = a->x + a->width
+ - self->submenu->size.width
+ - self->parent->size.width
+ - ob_rr_theme->bwidth
+ - ob_rr_theme->menu_overlap;
+
+ x = a->x + a->width - self->submenu->size.width
+ - ob_rr_theme->menu_overlap;
+ XWarpPointer(ob_display, None, None, 0, 0, 0, 0,
+ newparentx - self->parent->location.x, 0);
+
+ menu_show_full(self->parent, newparentx,
+ self->parent->location.y, self->parent->client);
+ }
menu_show_full(self->submenu, x,
self->parent->location.y + self->y,
break;
}
default:
- if (current_menu)
- current_menu->hide(current_menu);
+ ((ObMenu *)menu_visible->data)->hide(menu_visible->data);
+ current_menu = NULL;
}
return;
}