]> Dogcows Code - chaz/openbox/blobdiff - openbox/menuframe.c
fix for using freed memory to exec stuff
[chaz/openbox] / openbox / menuframe.c
index 29b9b638f51ead4d001c3b1401c4f7fef740be43..725b1a18b732047284a392a1e436cab57a8dbc90 100644 (file)
@@ -16,6 +16,9 @@
 
 GList *menu_frame_visible;
 
+static ObMenuEntryFrame* menu_entry_frame_new(ObMenuEntry *entry,
+                                              ObMenuFrame *frame);
+static void menu_entry_frame_free(ObMenuEntryFrame *self);
 static void menu_frame_render(ObMenuFrame *self);
 static void menu_frame_update(ObMenuFrame *self);
 
@@ -37,6 +40,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 +55,21 @@ 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) {
+        while (self->entries) {
+            menu_entry_frame_free(self->entries->data);
+            self->entries = g_list_delete_link(self->entries, self->entries);
+        }
+
+        stacking_remove(MENU_AS_WINDOW(self));
+
         XDestroyWindow(ob_display, self->items);
         XDestroyWindow(ob_display, self->title);
         XDestroyWindow(ob_display, self->window);
@@ -68,7 +81,8 @@ void menu_frame_free(ObMenuFrame *self)
     }
 }
 
-ObMenuEntryFrame* menu_entry_frame_new(ObMenuEntry *entry, ObMenuFrame *frame)
+static ObMenuEntryFrame* menu_entry_frame_new(ObMenuEntry *entry,
+                                              ObMenuFrame *frame)
 {
     ObMenuEntryFrame *self;
     XSetWindowAttributes attr;
@@ -105,7 +119,7 @@ ObMenuEntryFrame* menu_entry_frame_new(ObMenuEntry *entry, ObMenuFrame *frame)
     return self;
 }
 
-void menu_entry_frame_free(ObMenuEntryFrame *self)
+static void menu_entry_frame_free(ObMenuEntryFrame *self)
 {
     if (self) {
         XDestroyWindow(ob_display, self->icon);
@@ -129,7 +143,6 @@ void menu_entry_frame_free(ObMenuEntryFrame *self)
 
 void menu_frame_move(ObMenuFrame *self, gint x, gint y)
 {
-    /* XXX screen constraints */
     RECT_SET_POINT(self->area, x, y);
     XMoveWindow(ob_display, self->window, self->area.x, self->area.y);
 }
@@ -165,8 +178,10 @@ static void menu_entry_frame_render(ObMenuEntryFrame *self)
 {
     RrAppearance *item_a, *text_a;
     gint th; /* temp */
+    ObMenu *sub;
 
-    item_a = (!self->entry->enabled ?
+    item_a = ((self->entry->type == OB_MENU_ENTRY_TYPE_NORMAL &&
+               !self->entry->data.normal.enabled) ?
               self->a_disabled :
               (self == self->frame->selected ?
                self->a_selected :
@@ -188,7 +203,8 @@ static void menu_entry_frame_render(ObMenuEntryFrame *self)
     item_a->surface.parenty = self->area.y;
     RrPaint(item_a, self->window, self->area.width, self->area.height);
 
-    text_a = (!self->entry->enabled ?
+    text_a = ((self->entry->type == OB_MENU_ENTRY_TYPE_NORMAL &&
+               !self->entry->data.normal.enabled) ?
               self->a_text_disabled :
               (self == self->frame->selected ?
                self->a_text_selected :
@@ -198,8 +214,8 @@ static void menu_entry_frame_render(ObMenuEntryFrame *self)
         text_a->texture[0].data.text.string = self->entry->data.normal.label;
         break;
     case OB_MENU_ENTRY_TYPE_SUBMENU:
-        text_a->texture[0].data.text.string =
-            self->entry->data.submenu.submenu->title;
+        sub = self->entry->data.submenu.submenu;
+        text_a->texture[0].data.text.string = sub ? sub->title : "";
         break;
     case OB_MENU_ENTRY_TYPE_SEPARATOR:
         break;
@@ -222,11 +238,17 @@ static void menu_entry_frame_render(ObMenuEntryFrame *self)
         break;
     }
 
-    /* XXX draw icons */
-    if (0) {
+    if (self->entry->type == OB_MENU_ENTRY_TYPE_NORMAL &&
+        self->entry->data.normal.icon_data)
+    {
         XMoveResizeWindow(ob_display, self->icon, 0, 0,
                           self->frame->item_h, self->frame->item_h);
-        /* XXX set the RGBA surface stuff */
+        self->a_icon->texture[0].data.rgba.width =
+            self->entry->data.normal.icon_width;
+        self->a_icon->texture[0].data.rgba.height =
+            self->entry->data.normal.icon_height;
+        self->a_icon->texture[0].data.rgba.data =
+            self->entry->data.normal.icon_data;
         self->a_icon->surface.parent = item_a;
         self->a_icon->surface.parentx = 0;
         self->a_icon->surface.parenty = 0;
@@ -258,12 +280,13 @@ static void menu_frame_render(ObMenuFrame *self)
     gint tw, th; /* temps */
     GList *it;
     gboolean has_icon = FALSE, has_bullet = FALSE;
+    ObMenu *sub;
 
     XSetWindowBorderWidth(ob_display, self->window, ob_rr_theme->bwidth);
     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);
 
@@ -294,7 +317,8 @@ static void menu_frame_render(ObMenuFrame *self)
         RECT_SET_POINT(e->area, 0, allitems_h);
         XMoveWindow(ob_display, e->window, 0, e->area.y);
 
-        text_a = (!e->entry->enabled ?
+        text_a = ((e->entry->type == OB_MENU_ENTRY_TYPE_NORMAL &&
+                   !e->entry->data.normal.enabled) ?
                   e->a_text_disabled :
                   (e == self->selected ?
                    e->a_text_selected :
@@ -304,11 +328,12 @@ static void menu_frame_render(ObMenuFrame *self)
             text_a->texture[0].data.text.string = e->entry->data.normal.label;
             RrMinsize(text_a, &tw, &th);
 
-            /* XXX has_icon = TRUE; */
+            if (e->entry->data.normal.icon_data)
+                has_icon = TRUE;
             break;
         case OB_MENU_ENTRY_TYPE_SUBMENU:
-            text_a->texture[0].data.text.string =
-                e->entry->data.submenu.submenu->title;
+            sub = e->entry->data.submenu.submenu;
+            text_a->texture[0].data.text.string = sub ? sub->title : "";
             RrMinsize(text_a, &tw, &th);
 
             has_bullet = TRUE;
@@ -336,15 +361,17 @@ static void menu_frame_render(ObMenuFrame *self)
     }
 
     if (!w) w = 10;
-    if (!allitems_h) allitems_h = 3;
-    if (!h) h = 3;
+    if (!allitems_h) {
+        allitems_h = 3;
+        h += 3;
+    }
 
     XResizeWindow(ob_display, self->window, w, h);
     XResizeWindow(ob_display, self->items, w, allitems_h);
 
     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,
@@ -368,6 +395,8 @@ static void menu_frame_update(ObMenuFrame *self)
 {
     GList *mit, *fit;
 
+    menu_find_submenus(self->menu);
+
     self->selected = NULL;
 
     for (mit = self->menu->entries, fit = self->entries; mit && fit;
@@ -411,6 +440,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 +474,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 +531,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 +540,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);
 
@@ -513,28 +557,42 @@ void menu_entry_frame_show_submenu(ObMenuEntryFrame *self)
 {
     ObMenuFrame *f;
 
+    if (!self->entry->data.submenu.submenu) return;
+
     f = menu_frame_new(self->entry->data.submenu.submenu,
                        self->frame->client);
     menu_frame_move(f,
                     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);
 }
 
-void menu_entry_frame_execute(ObMenuEntryFrame *self)
+void menu_entry_frame_execute(ObMenuEntryFrame *self, gboolean hide)
 {
     if (self->entry->type == OB_MENU_ENTRY_TYPE_NORMAL) {
-        GSList *it;
-
-        for (it = self->entry->data.normal.actions; it;
-             it = g_slist_next(it))
-        {
-            ObAction *act = it->data;
-            act->data.any.c = self->frame->client;
-            act->func(&act->data);
-        }
+        /* grab all this shizzle, cuz when the menu gets hidden, 'self'
+           gets freed */
+        ObMenuEntry *entry = self->entry;
+        ObMenuExecuteFunc func = self->frame->menu->execute_func;
+        gpointer data = self->frame->menu->data;
+        GSList *acts = self->entry->data.normal.actions;
+
+        /* release grabs before executing the shit */
         menu_frame_hide_all();
+
+        if (func)
+            func(entry, data);
+        else {
+            GSList *it;
+
+            for (it = acts; it; it = g_slist_next(it))
+            {
+                ObAction *act = it->data;
+                act->data.any.c = self->frame->client;
+                act->func(&act->data);
+            }
+        }
     }
 }
This page took 0.027234 seconds and 4 git commands to generate.