change the menu plugin interface, no need for the create/destroy functions any more.
authorDana Jansens <danakj@orodu.net>
Thu, 28 Aug 2003 05:44:13 +0000 (05:44 +0000)
committerDana Jansens <danakj@orodu.net>
Thu, 28 Aug 2003 05:44:13 +0000 (05:44 +0000)
redo the client-menu plugin to work with the new menu api

13 files changed:
Makefile.am
data/menu
openbox/client.c
openbox/event.c
openbox/menu.c
openbox/menu.h
openbox/menuframe.c
openbox/menuframe.h
openbox/openbox.c
openbox/plugin.c
openbox/plugin.h
plugins/interface.h
plugins/menu/client_menu.c

index 4726907..c056e25 100644 (file)
@@ -26,10 +26,10 @@ bin_PROGRAMS = \
        tools/kdetrayproxy/kdetrayproxy
 
 plugin_LTLIBRARIES = \
-       plugins/placement/placement.la
+       plugins/placement/placement.la \
+       plugins/menu/client_menu.la
 #      plugins/menu/timed_menu.la \
 #      plugins/menu/fifo_menu.la \
-#      plugins/menu/client_menu.la \
 #      plugins/menu/include_menu.la \
 #      plugins/menu/client_list_menu.la
 
index ce2ccb4..1a31f06 100644 (file)
--- a/data/menu
+++ b/data/menu
@@ -28,8 +28,8 @@
 </menu>
 
 <menu id="root-menu" label="Openbox 3">
-  <menu id="apps-menu">
-  <menu id="games-menu">
+  <menu id="apps-menu" />
+  <menu id="games-menu" />
   <separator />
   <item label="Restart">
     <action name="restart" />
index ab7c804..f17e972 100644 (file)
@@ -17,7 +17,7 @@
 #include "openbox.h"
 #include "group.h"
 #include "config.h"
-#include "menu.h"
+#include "menuframe.h"
 #include "keyboard.h"
 #include "mouse.h"
 #include "render/render.h"
@@ -406,7 +406,9 @@ void client_unmanage(ObClient *self)
     if (moveresize_client == self)
         moveresize_end(TRUE);
 
-    /* XXX close any windows that are attached to this window */
+    /* menus can be associated with a client, so close any that are since
+       we are disappearing now */
+    menu_frame_hide_all_client(self);
     
     if (focus_client == self) {
         XEvent e;
index 6480855..fc45060 100644 (file)
@@ -1183,8 +1183,8 @@ static void event_handle_menu(XEvent *ev)
         if ((f = menu_frame_under(ev->xmotion.x_root,
                                   ev->xmotion.y_root))) {
             menu_frame_move_on_screen(f);
-            if (e = menu_entry_frame_under(ev->xmotion.x_root,
-                                           ev->xmotion.y_root))
+            if ((e = menu_entry_frame_under(ev->xmotion.x_root,
+                                            ev->xmotion.y_root)))
                 menu_frame_select(f, e);
         }
         break;
index 7e8685f..3e38c0f 100644 (file)
@@ -44,11 +44,11 @@ static void parse_menu_item(ObParseInst *i, xmlDocPtr doc, xmlNodePtr node,
     if (state->menus) {
         if (parse_attr_string("label", node, &label)) {
             GSList *acts = NULL;
-            
+
             for (node = node->xmlChildrenNode; node; node = node->next)
                 if (!xmlStrcasecmp(node->name, (const xmlChar*) "action"))
                     acts = g_slist_append(acts, action_parse(doc, node));
-            menu_add_normal(state->menus->data, label, acts);
+            menu_add_normal(state->menus->data, 0, label, acts);
             g_free(label);
         }
     }
@@ -59,9 +59,9 @@ static void parse_menu_separator(ObParseInst *i,
                                  gpointer data)
 {
     ObMenuParseState *state = data;
-    
+
     if (state->menus)
-        menu_add_separator(state->menus->data);
+        menu_add_separator(state->menus->data, 0);
 }
 
 static void parse_menu(ObParseInst *i, xmlDocPtr doc, xmlNodePtr node,
@@ -85,7 +85,7 @@ static void parse_menu(ObParseInst *i, xmlDocPtr doc, xmlNodePtr node,
     }
 
     if (state->menus)
-        menu_add_submenu(state->menus->data, name);
+        menu_add_submenu(state->menus->data, 0, name);
 
 parse_menu_fail:
     g_free(name);
@@ -95,6 +95,7 @@ parse_menu_fail:
 
 void menu_destroy_hash_value(ObMenu *self)
 {
+    /* XXX make sure its not visible */
     menu_clear_entries_internal(self);
     g_free(self->name);
     g_free(self->title);
@@ -110,6 +111,7 @@ void menu_shutdown()
 {
     menu_frame_hide_all();
     g_hash_table_destroy(menu_hash);
+    menu_hash = NULL;
 }
 
 void menu_parse()
@@ -170,6 +172,14 @@ gboolean menu_new(gchar *name, gchar *title, gpointer data)
     return TRUE;
 }
 
+void menu_free(gchar *name)
+{
+    ObMenu *self;
+    
+    if (!(self = menu_from_name(name))) return;
+    g_hash_table_remove(menu_hash, self->name);
+}
+
 void menu_show(gchar *name, gint x, gint y, ObClient *client)
 {
     ObMenu *self;
@@ -177,14 +187,12 @@ void menu_show(gchar *name, gint x, gint y, ObClient *client)
 
     if (!(self = menu_from_name(name))) return;
 
-    /* XXX update entries */
-
     frame = menu_frame_new(self, client);
     menu_frame_move(frame, x, y);
     menu_frame_show(frame, NULL);
 }
 
-static ObMenuEntry* menu_entry_new(ObMenu *menu, ObMenuEntryType type)
+static ObMenuEntry* menu_entry_new(ObMenu *menu, ObMenuEntryType type, gint id)
 {
     ObMenuEntry *self;
 
@@ -193,6 +201,7 @@ static ObMenuEntry* menu_entry_new(ObMenu *menu, ObMenuEntryType type)
     self = g_new0(ObMenuEntry, 1);
     self->type = type;
     self->menu = menu;
+    self->id = id;
     self->enabled = TRUE;
     return self;
 }
@@ -238,21 +247,21 @@ static void menu_clear_entries_internal(ObMenu *self)
     }
 }
 
-void menu_add_normal(gchar *name, gchar *label, GSList *actions)
+void menu_add_normal(gchar *name, gint id, gchar *label, GSList *actions)
 {
     ObMenu *self;
     ObMenuEntry *e;
 
     if (!(self = menu_from_name(name))) return;
 
-    e = menu_entry_new(self, OB_MENU_ENTRY_TYPE_NORMAL);
+    e = menu_entry_new(self, OB_MENU_ENTRY_TYPE_NORMAL, id);
     e->data.normal.label = g_strdup(label);
     e->data.normal.actions = actions;
 
     self->entries = g_list_append(self->entries, e);
 }
 
-void menu_add_submenu(gchar *name, gchar *submenu)
+void menu_add_submenu(gchar *name, gint id, gchar *submenu)
 {
     ObMenu *self, *sub;
     ObMenuEntry *e;
@@ -260,20 +269,44 @@ void menu_add_submenu(gchar *name, gchar *submenu)
     if (!(self = menu_from_name(name))) return;
     if (!(sub = menu_from_name(submenu))) return;
 
-    e = menu_entry_new(self, OB_MENU_ENTRY_TYPE_SUBMENU);
+    e = menu_entry_new(self, OB_MENU_ENTRY_TYPE_SUBMENU, id);
     e->data.submenu.submenu = sub;
 
     self->entries = g_list_append(self->entries, e);
 }
 
-void menu_add_separator(gchar *name)
+void menu_add_separator(gchar *name, gint id)
 {
     ObMenu *self;
     ObMenuEntry *e;
 
     if (!(self = menu_from_name(name))) return;
 
-    e = menu_entry_new(self, OB_MENU_ENTRY_TYPE_SEPARATOR);
+    e = menu_entry_new(self, OB_MENU_ENTRY_TYPE_SEPARATOR, id);
 
     self->entries = g_list_append(self->entries, e);
 }
+
+void menu_set_update_func(gchar *name, ObMenuUpdateFunc func)
+{
+    ObMenu *self;
+
+    if (!(self = menu_from_name(name))) return;
+    self->update_func = func;
+}
+
+ObMenuEntry* menu_find_entry_id(ObMenu *self, gint id)
+{
+    ObMenuEntry *ret = NULL;
+    GList *it;
+
+    for (it = self->entries; it; it = g_list_next(it)) {
+        ObMenuEntry *e = it->data;
+
+        if (e->id == id) {
+            ret = e;
+            break;
+        }
+    }
+    return ret;
+}
index cfbb52d..66390e7 100644 (file)
@@ -17,9 +17,9 @@ typedef struct _ObNormalMenuEntry ObNormalMenuEntry;
 typedef struct _ObSubmenuMenuEntry ObSubmenuMenuEntry;
 typedef struct _ObSeparatorMenuEntry ObSeparatorMenuEntry;
 
-extern GList *menu_visible;
-
+typedef void (*ObMenuUpdateFunc)(struct _ObMenuFrame *frame, gpointer data);
 
+extern GList *menu_visible;
 
 struct _ObMenu
 {
@@ -33,6 +33,8 @@ struct _ObMenu
 
     /* plugin data */
     gpointer data;
+
+    ObMenuUpdateFunc update_func;
 };
 
 typedef enum
@@ -62,6 +64,8 @@ struct _ObMenuEntry
     ObMenuEntryType type;
     ObMenu *menu;
 
+    gint id;
+
     /* state */
     gboolean enabled;
 
@@ -78,13 +82,18 @@ void menu_shutdown();
 void menu_parse();
 
 gboolean menu_new(gchar *name, gchar *title, gpointer data);
+void menu_free(gchar *name);
+
+void menu_set_update_func(gchar *name, ObMenuUpdateFunc func);
 
 void menu_show(gchar *name, gint x, gint y, struct _ObClient *client);
 
 /* functions for building menus */
 void menu_clear_entries(gchar *name);
-void menu_add_normal(gchar *name, gchar *label, GSList *actions);
-void menu_add_submenu(gchar *name, gchar *submenu);
-void menu_add_separator(gchar *name);
+void menu_add_normal(gchar *name, gint id, gchar *label, GSList *actions);
+void menu_add_submenu(gchar *name, gint id, gchar *submenu);
+void menu_add_separator(gchar *name, gint id);
+
+ObMenuEntry* menu_find_entry_id(ObMenu *self, gint id);
 
 #endif
index 29b9b63..daecd6c 100644 (file)
@@ -37,6 +37,7 @@ ObMenuFrame* menu_frame_new(ObMenu *menu, ObClient *client)
     self->type = Window_Menu;
     self->menu = menu;
     self->selected = NULL;
+    self->show_title = TRUE;
     self->client = client;
 
     attr.event_mask = FRAME_EVENTMASK;
@@ -51,12 +52,16 @@ ObMenuFrame* menu_frame_new(ObMenu *menu, ObClient *client)
     self->a_title = RrAppearanceCopy(ob_rr_theme->a_menu_title);
     self->a_items = RrAppearanceCopy(ob_rr_theme->a_menu);
 
+    stacking_add(MENU_AS_WINDOW(self));
+
     return self;
 }
 
 void menu_frame_free(ObMenuFrame *self)
 {
     if (self) {
+        stacking_remove(MENU_AS_WINDOW(self));
+
         XDestroyWindow(ob_display, self->items);
         XDestroyWindow(ob_display, self->title);
         XDestroyWindow(ob_display, self->window);
@@ -263,7 +268,7 @@ static void menu_frame_render(ObMenuFrame *self)
     XSetWindowBorder(ob_display, self->window,
                      RrColorPixel(ob_rr_theme->b_color));
 
-    if (!self->parent && self->menu->title) {
+    if (!self->parent && self->show_title) {
         XMoveWindow(ob_display, self->title, 
                     -ob_rr_theme->bwidth, h - ob_rr_theme->bwidth);
 
@@ -344,7 +349,7 @@ static void menu_frame_render(ObMenuFrame *self)
 
     self->inner_w = w;
 
-    if (!self->parent && self->title) {
+    if (!self->parent && self->show_title) {
         XResizeWindow(ob_display, self->title,
                       w, self->title_h - ob_rr_theme->bwidth);
         RrPaint(self->a_title, self->title,
@@ -411,6 +416,8 @@ void menu_frame_show(ObMenuFrame *self, ObMenuFrame *parent)
     if (!g_list_find(menu_frame_visible, self)) {
         menu_frame_visible = g_list_prepend(menu_frame_visible, self);
 
+        if (self->menu->update_func)
+            self->menu->update_func(self, self->menu->data);
         menu_frame_update(self);
     }
 
@@ -443,10 +450,22 @@ void menu_frame_hide(ObMenuFrame *self)
 
 void menu_frame_hide_all()
 {
-    while (menu_frame_visible)
-        menu_frame_hide(menu_frame_visible->data);
+    GList *it = g_list_last(menu_frame_visible);
+    if (it) 
+        menu_frame_hide(it->data);
+}
+
+void menu_frame_hide_all_client(ObClient *client)
+{
+    GList *it = g_list_last(menu_frame_visible);
+    if (it) {
+        ObMenuFrame *f = it->data;
+        if (f->client == client)
+            menu_frame_hide(f);
+    }
 }
 
+
 ObMenuFrame* menu_frame_under(gint x, gint y)
 {
     ObMenuFrame *ret = NULL;
@@ -488,6 +507,7 @@ ObMenuEntryFrame* menu_entry_frame_under(gint x, gint y)
 void menu_frame_select(ObMenuFrame *self, ObMenuEntryFrame *entry)
 {
     ObMenuEntryFrame *old = self->selected;
+    ObMenuFrame *oldchild = self->child;
 
     if (old == entry) return;
 
@@ -496,11 +516,11 @@ void menu_frame_select(ObMenuFrame *self, ObMenuEntryFrame *entry)
     else
         self->selected = NULL;
 
-    if (old) {
+    if (old)
         menu_entry_frame_render(old);
-        if (old->entry->type == OB_MENU_ENTRY_TYPE_SUBMENU)
-            menu_frame_hide(self->child);
-    }
+    if (oldchild)
+        menu_frame_hide(oldchild);
+
     if (self->selected) {
         menu_entry_frame_render(self->selected);
 
@@ -519,7 +539,7 @@ void menu_entry_frame_show_submenu(ObMenuEntryFrame *self)
                     self->frame->area.x + self->frame->area.width
                     - ob_rr_theme->menu_overlap,
                     self->frame->area.y + self->frame->title_h +
-                    self->area.y);
+                    self->area.y + ob_rr_theme->menu_overlap);
     menu_frame_show(f, self->frame);
 }
 
@@ -528,6 +548,9 @@ void menu_entry_frame_execute(ObMenuEntryFrame *self)
     if (self->entry->type == OB_MENU_ENTRY_TYPE_NORMAL) {
         GSList *it;
 
+        /* release grabs before executing the shit */
+        menu_frame_hide_all();
+
         for (it = self->entry->data.normal.actions; it;
              it = g_slist_next(it))
         {
@@ -535,6 +558,5 @@ void menu_entry_frame_execute(ObMenuEntryFrame *self)
             act->data.any.c = self->frame->client;
             act->func(&act->data);
         }
-        menu_frame_hide_all();
     }
 }
index f739144..8cfc837 100644 (file)
@@ -31,6 +31,12 @@ struct _ObMenuFrame
     ObMenuFrame *parent;
     ObMenuFrame *child;
 
+    GList *entries;
+    ObMenuEntryFrame *selected;
+
+    /* If a titlebar is displayed for the menu or not (for top-level menus) */
+    gboolean show_title;
+
     /* On-screen area (including borders!) */
     Rect area;
     gint inner_w; /* inside the borders */
@@ -39,9 +45,6 @@ struct _ObMenuFrame
     gint text_x;  /* offset at which the text appears in the items */
     gint text_w;  /* width of the text area in the items */
 
-    GList *entries;
-    ObMenuEntryFrame *selected;
-
     Window title;
     Window items;
 
@@ -82,6 +85,7 @@ void menu_frame_show(ObMenuFrame *self, ObMenuFrame *parent);
 void menu_frame_hide(ObMenuFrame *self);
 
 void menu_frame_hide_all();
+void menu_frame_hide_all_client(struct _ObClient *client);
 
 void menu_frame_select(ObMenuFrame *self, ObMenuEntryFrame *entry);
 
index 6656304..165d722 100644 (file)
@@ -266,8 +266,8 @@ int main(int argc, char **argv)
         dock_remove_all();
        client_unmanage_all();
 
-        menu_shutdown(); /* destroy menus before unloading plugins */
         plugin_shutdown(); /* calls all the plugins' shutdown functions */
+        menu_shutdown();
         mouse_shutdown();
         keyboard_shutdown();
         dock_shutdown();
index 411eb6f..b8d9be4 100644 (file)
@@ -11,8 +11,6 @@ typedef struct {
     PluginSetupConfig config;
     PluginStartup startup;
     PluginShutdown shutdown;
-    PluginCreate create;
-    PluginDestroy destroy;
 } Plugin;
 
 static gpointer load_sym(GModule *module, char *name, char *symbol,
@@ -58,9 +56,6 @@ static Plugin *plugin_new(char *name)
                                         FALSE);
     p->shutdown = (PluginShutdown)load_sym(p->module, name, "plugin_shutdown",
                                           FALSE);
-    p->create = (PluginCreate)load_sym(p->module, name, "plugin_create", TRUE);
-    p->destroy = (PluginDestroy)load_sym(p->module, name, "plugin_destroy",
-                                        TRUE);
 
     if (p->config == NULL || p->startup == NULL || p->shutdown == NULL) {
         g_module_close(p->module);
@@ -174,41 +169,3 @@ void plugin_loadall(ObParseInst *i)
         g_io_channel_unref(io);
     }
 }
-
-void *plugin_create(char *name, void *data)
-{
-    Plugin *p = (Plugin *)g_datalist_get_data(&plugins, name);
-
-    if (p == NULL) {
-       g_warning("Unable to find plugin for create: %s", name);
-       return NULL;
-    }
-
-    if (p->create == NULL || p->destroy == NULL) {
-       g_critical("Unsupported create/destroy: %s", name);
-       return NULL;
-    }
-
-    return p->create(data);
-}
-
-void plugin_destroy(char *name, void *data)
-{
-    Plugin *p = (Plugin *)g_datalist_get_data(&plugins, name);
-
-    if (p == NULL) {
-       g_critical("Unable to find plugin for destroy: %s", name);
-       /* really shouldn't happen, but attempt to free something anyway? */
-       g_free(data);
-       return;
-    }
-
-    if (p->destroy == NULL || p->create == NULL) {
-       g_critical("Unsupported create/destroy: %s", name);
-       /* really, really shouldn't happen, but attempt to free anyway? */
-       g_free(data);
-       return;
-    }
-
-    p->destroy(data);
-}
index 6d14c64..7ef004b 100644 (file)
@@ -15,9 +15,4 @@ gboolean plugin_open(char *name, struct _ObParseInst *i);
 gboolean plugin_open_reopen(char *name, struct _ObParseInst *i);
 void plugin_close(char *name);
 
-/* call plugin's generic constructor */
-void *plugin_create(char *name, void *data);
-/* free memory allocated by plugin_create() */
-void plugin_destroy(char *name, void *object);
-
 #endif
index 52b46f3..83eb97a 100644 (file)
@@ -12,10 +12,4 @@ typedef void (*PluginStartup)(void);
 /* plugin_shutdown() */
 typedef void (*PluginShutdown)(void);
 
-/* plugin_create() - for menu plugins only */
-typedef void *(*PluginCreate)(/* TODO */);
-
-/* plugin_destroy() - for menu plugins only */
-typedef void (*PluginDestroy)(void *);
-
 #endif
index 816de3e..d60f545 100644 (file)
 #include "kernel/debug.h"
 #include "kernel/menu.h"
+#include "kernel/menuframe.h"
 #include "kernel/screen.h"
 #include "kernel/client.h"
 #include "kernel/openbox.h"
 #include "kernel/frame.h"
-
-#include "render/theme.h"
+#include "gettext.h"
 
 #include <glib.h>
 
-static char *PLUGIN_NAME = "client_menu";
+#define CLIENT_MENU_NAME  "client-menu"
+#define SEND_TO_MENU_NAME "client-send-to-menu"
+#define LAYER_MENU_NAME   "client-layer-menu"
+
+enum {
+    LAYER_TOP,
+    LAYER_NORMAL,
+    LAYER_BOTTOM
+};
+
+enum {
+    CLIENT_SEND_TO,
+    CLIENT_LAYER,
+    CLIENT_ICONIFY,
+    CLIENT_MAXIMIZE,
+    CLIENT_RAISE,
+    CLIENT_LOWER,
+    CLIENT_SHADE,
+    CLIENT_DECORATE,
+    CLIENT_MOVE,
+    CLIENT_RESIZE,
+    CLIENT_CLOSE
+};
+
+void plugin_setup_config() { }
+
+static void client_update(ObMenuFrame *frame, gpointer data)
+{
+    ObMenu *menu = frame->menu;
+    ObMenuEntry *e;
+
+    frame->show_title = FALSE;
+
+    if (!frame->client) {
+        GList *it;
+
+        for (it = menu->entries; it; it = g_list_next(it)) {
+            ObMenuEntry *e = it->data;
+            e->enabled = FALSE;
+        }
+        return;
+    }
+
+    e = menu_find_entry_id(menu, CLIENT_ICONIFY);
+    e->enabled = frame->client->functions & OB_CLIENT_FUNC_ICONIFY;
+
+    e = menu_find_entry_id(menu, CLIENT_MAXIMIZE);
+    e->enabled = frame->client->functions & OB_CLIENT_FUNC_MAXIMIZE;
 
-static ObMenu *send_to_menu;
-static ObMenu *layer_menu;
+    e = menu_find_entry_id(menu, CLIENT_SHADE);
+    e->enabled = frame->client->functions & OB_CLIENT_FUNC_SHADE;
 
-typedef struct {
-    gint foo;
-} Client_Menu_Data;
+    e = menu_find_entry_id(menu, CLIENT_MOVE);
+    e->enabled = frame->client->functions & OB_CLIENT_FUNC_MOVE;
 
-#define CLIENT_MENU(m) ((ObMenu *)m)
-#define CLIENT_MENU_DATA(m) ((Client_Menu_Data *)((ObMenu *)m)->plugin_data)
+    e = menu_find_entry_id(menu, CLIENT_RESIZE);
+    e->enabled = frame->client->functions & OB_CLIENT_FUNC_RESIZE;
 
-void client_menu_clean_up(ObMenu *m) {
+    e = menu_find_entry_id(menu, CLIENT_CLOSE);
+    e->enabled = frame->client->functions & OB_CLIENT_FUNC_CLOSE;
 }
 
-void client_send_to_update(ObMenu *self)
+static void send_to_update(ObMenuFrame *frame, gpointer data)
 {
-    guint i = 0;
-    GList *it = self->entries;
-    
-    /* check if we have to update. lame */
-    while (it != NULL) {
-        if (i == screen_desktop) {
-            if (((ObMenuEntry *)it->data)->enabled)
-                break;
+    ObMenu *menu = frame->menu;
+    guint i;
+    GSList *acts;
+    ObAction *act;
+
+    menu_clear_entries(SEND_TO_MENU_NAME);
+
+    if (!frame->client)
+        return;
+
+    for (i = 0; i <= screen_num_desktops; ++i) {
+        gchar *name;
+        guint desk;
+
+        if (i >= screen_num_desktops) {
+            desk = DESKTOP_ALL;
+            name = _("All desktops");
         } else {
-            if (!((ObMenuEntry *)it->data)->enabled)
-                break;
+            desk = i;
+            name = screen_desktop_names[i];
         }
-        if (i >= screen_num_desktops)
-            break;
-        if (strcmp(screen_desktop_names[i],
-                   ((ObMenuEntry *)it->data)->label) != 0)
-            break;
-        ++i;
-        it = it->next;
-    }
 
-    if (it != NULL || i != screen_num_desktops) {
-        menu_clear(self);
-        ob_debug("update\n");
-        for (i = 0; i < screen_num_desktops; ++i) {
-            ObMenuEntry *e;
-            ObAction *a = action_from_string("sendtodesktop");
-            a->data.sendto.desk = i;
-            a->data.sendto.follow = FALSE;
-            e = menu_entry_new(screen_desktop_names[i], a);
-            if (i == screen_desktop)
-                e->enabled = FALSE;
-            menu_add_entry(self, e);
+        act = action_from_string("SendToDesktop");
+        act->data.sendto.desk = desk;
+        act->data.sendto.follow = FALSE;
+        acts = g_slist_prepend(NULL, act);
+        menu_add_normal(SEND_TO_MENU_NAME, desk, name, acts);
+
+        if (frame->client->desktop == desk) {
+            ObMenuEntry *e = menu_find_entry_id(menu, desk);
+            g_assert(e);
+            e->enabled = FALSE;
         }
-        
-        menu_render(self);
     }
 }
 
-void client_menu_show(ObMenu *self, int x, int y, ObClient *client)
+void plugin_startup()
 {
-    guint i;
-    gint newy, newx;
-    Rect *a = NULL;
-
-    g_assert(!self->invalid);
-    g_assert(client);
-    
-    for (i = 0; i < screen_num_monitors; ++i) {
-        a = screen_physical_area_monitor(i);
-        if (RECT_CONTAINS(*a, x, y))
-            break;
-    }
-    g_assert(a != NULL);
-    self->xin_area = i;
-
-    newx = MAX(x, client->area.x);
-    newy = MAX(y, client->area.y);
-    POINT_SET(self->location,
-             MIN(newx, client->area.x + client->area.width - self->size.width),
-             MIN(newy, client->area.y + client->area.height -
-                  self->size.height));
-    
-    XMoveWindow(ob_display, self->frame, self->location.x, self->location.y);
-
-    if (!self->shown) {
-       XMapWindow(ob_display, self->frame);
-        stacking_raise(MENU_AS_WINDOW(self));
-       self->shown = TRUE;
-    } else if (self->shown && self->open_submenu) {
-       menu_hide(self->open_submenu);
-    }
-}
+    GSList *acts;
 
-void plugin_setup_config() { }
+    menu_new(LAYER_MENU_NAME, _("Layer"), NULL);
 
-void plugin_shutdown() { }
+    acts = g_slist_prepend(NULL, action_from_string("SendToTopLayer"));
+    menu_add_normal(LAYER_MENU_NAME, LAYER_TOP, _("Always on top"), acts);
 
-void plugin_destroy (ObMenu *m)
-{
-}
+    acts = g_slist_prepend(NULL, action_from_string("SendToNormalLayer"));
+    menu_add_normal(LAYER_MENU_NAME, LAYER_NORMAL, _("Normal"), acts);
 
-void *plugin_create() /* TODO: need config */
-{
-    ObMenu *m = menu_new_full(NULL, "client-menu", NULL,
-                            client_menu_show, NULL, NULL, NULL, NULL, NULL);
-    m->plugin = PLUGIN_NAME;
-    menu_add_entry(m, menu_entry_new_submenu("Send To Workspace",
-                                             send_to_menu));
-    send_to_menu->parent = m;
-
-    menu_add_entry(m, menu_entry_new("Iconify",
-                                     action_from_string("iconify")));
-    menu_add_entry(m, menu_entry_new("Raise",
-                                     action_from_string("raise")));
-    menu_add_entry(m, menu_entry_new("Lower",
-                                     action_from_string("lower")));
-    menu_add_entry(m, menu_entry_new("Close",
-                                     action_from_string("close")));
-    menu_add_entry(m, menu_entry_new("Shade",
-                                     action_from_string("toggleshade")));
-    menu_add_entry(m, menu_entry_new("Omnipresent",
-                                     action_from_string("toggleomnipresent")));
-    menu_add_entry(m, menu_entry_new("Decorations",
-                                     action_from_string("toggledecorations")));
-    menu_add_entry(m, menu_entry_new_submenu("Layers",
-                                             layer_menu));
-    layer_menu->parent = m;
-
-    /* send to desktop
-       iconify
-       raise
-       lower
-       close
-       kill
-       shade
-       omnipresent
-       decorations
-    */
-    return (void *)m;
+    acts = g_slist_prepend(NULL, action_from_string("SendToBottomLayer"));
+    menu_add_normal(LAYER_MENU_NAME, LAYER_BOTTOM, _("Always on bottom"),acts);
+
+
+    menu_new(SEND_TO_MENU_NAME, _("Send to desktop"), NULL);
+    menu_set_update_func(SEND_TO_MENU_NAME, send_to_update);
+
+    menu_new(CLIENT_MENU_NAME, _("Client menu"), NULL);
+    menu_set_update_func(CLIENT_MENU_NAME, client_update);
+
+    menu_add_submenu(CLIENT_MENU_NAME, CLIENT_SEND_TO, SEND_TO_MENU_NAME);
+
+    menu_add_submenu(CLIENT_MENU_NAME, CLIENT_LAYER, LAYER_MENU_NAME);
+
+    acts = g_slist_prepend(NULL, action_from_string("Iconify"));
+    menu_add_normal(CLIENT_MENU_NAME, CLIENT_ICONIFY, _("Iconify"), acts);
+
+    acts = g_slist_prepend(NULL, action_from_string("Maximize"));
+    menu_add_normal(CLIENT_MENU_NAME, CLIENT_MAXIMIZE, _("Maximize"), acts);
+
+    acts = g_slist_prepend(NULL, action_from_string("Raise"));
+    menu_add_normal(CLIENT_MENU_NAME, CLIENT_RAISE, _("Raise to top"), acts);
+
+    acts = g_slist_prepend(NULL, action_from_string("Lower"));
+    menu_add_normal(CLIENT_MENU_NAME, CLIENT_LOWER, _("Lower to bottom"),acts);
+
+    acts = g_slist_prepend(NULL, action_from_string("ToggleShade"));
+    menu_add_normal(CLIENT_MENU_NAME, CLIENT_SHADE, _("(Un)Shade"), acts);
+
+    acts = g_slist_prepend(NULL, action_from_string("ToggleDecorations"));
+    menu_add_normal(CLIENT_MENU_NAME, CLIENT_DECORATE, _("Decorate"), acts);
+
+    menu_add_separator(CLIENT_MENU_NAME, -1);
+
+    acts = g_slist_prepend(NULL, action_from_string("KeyboardMove"));
+    menu_add_normal(CLIENT_MENU_NAME, CLIENT_MOVE, _("Move"), acts);
+
+    acts = g_slist_prepend(NULL, action_from_string("KeyboardResize"));
+    menu_add_normal(CLIENT_MENU_NAME, CLIENT_RESIZE, _("Resize"), acts);
+
+    menu_add_separator(CLIENT_MENU_NAME, -1);
+
+    acts = g_slist_prepend(NULL, action_from_string("Close"));
+    menu_add_normal(CLIENT_MENU_NAME, CLIENT_CLOSE, _("Close"), acts);
 }
 
-void plugin_startup()
+void plugin_shutdown()
 {
-    ObMenu *t;
-    /* create a Send To Workspace ObMenu */
-    send_to_menu = menu_new_full(NULL, "send-to-workspace",
-                                 NULL, NULL, client_send_to_update,
-                                 NULL, NULL, NULL,
-                                 NULL);
-    
-    layer_menu = menu_new(NULL, "layer", NULL);
-    menu_add_entry(layer_menu, menu_entry_new("Top Layer",
-                                     action_from_string("sendtotoplayer")));
-    menu_add_entry(layer_menu, menu_entry_new("Normal Layer",
-                                     action_from_string("sendtonormallayer")));
-    menu_add_entry(layer_menu, menu_entry_new("Bottom Layer",
-                                     action_from_string("sendtobottomlayer")));
-                          
-    t = (ObMenu *)plugin_create("client_menu");
+    menu_free(LAYER_MENU_NAME);
+    menu_free(SEND_TO_MENU_NAME);
+    menu_free(CLIENT_MENU_NAME);
 }
-