all repos — openbox @ 3905872982478e4e0ae05f4ce114a8025a2389ee

openbox fork - make it a bit more like ryudo

merge in r6153-6154 from the 3.4 branch
Dana Jansens danakj@orodu.net
commit

3905872982478e4e0ae05f4ce114a8025a2389ee

parent

edf29cfe733349e3e61de2b4fd9f2a8c1ebec274

M openbox/client_list_menu.copenbox/client_list_menu.c

@@ -159,7 +159,7 @@ it = g_slist_next(it);

} for (; it; it = next, ++i) { next = g_slist_next(it); - menu_free(it->data); + menu_unref(it->data); desktop_menus = g_slist_delete_link(desktop_menus, it); menu_entry_remove(menu_find_entry_id(menu, i)); }
M openbox/menu.copenbox/menu.c

@@ -314,7 +314,7 @@ g_free(script);

} ObMenu* menu_new(const gchar *name, const gchar *title, - gboolean allow_shortcut, gpointer data) + gboolean allow_shortcut_selection, gpointer data) { ObMenu *self;

@@ -322,10 +322,16 @@ self = g_new0(ObMenu, 1);

self->name = g_strdup(name); self->data = data; - self->shortcut = parse_shortcut(title, allow_shortcut, &self->title, - &self->shortcut_position); + self->shortcut = parse_shortcut(title, allow_shortcut_selection, + &self->title, &self->shortcut_position); g_hash_table_replace(menu_hash, self->name, self); + + self->more_menu = g_new0(ObMenu, 1); + self->more_menu->name = "More..."; + self->more_menu->title = "More..."; + self->more_menu->data = data; + self->more_menu->shortcut = g_unichar_tolower(g_utf8_get_char("M")); return self; }

@@ -355,9 +361,10 @@

g_free(self); } -void menu_free(ObMenu *menu) +void menu_unref(ObMenu *menu) { - g_hash_table_remove(menu_hash, menu->name); + if (menu) + g_hash_table_remove(menu_hash, menu->name); } void menu_show(gchar *name, gint x, gint y, gint button, ObClient *client)

@@ -378,7 +385,7 @@ }

menu_frame_hide_all(); - frame = menu_frame_new(self, client); + frame = menu_frame_new(self, 0, client); if (!menu_frame_show_topmenu(frame, x, y, button)) menu_frame_free(frame); else if (frame->entries) {

@@ -396,6 +403,7 @@

g_assert(menu); self = g_new0(ObMenuEntry, 1); + self->ref = 1; self->type = type; self->menu = menu; self->id = id;

@@ -412,9 +420,14 @@

return self; } -void menu_entry_free(ObMenuEntry *self) +void menu_entry_ref(ObMenuEntry *self) { - if (self) { + ++self->ref; +} + +void menu_entry_unref(ObMenuEntry *self) +{ + if (self && --self->ref == 0) { switch (self->type) { case OB_MENU_ENTRY_TYPE_NORMAL: g_free(self->data.normal.label);

@@ -452,15 +465,16 @@ }

#endif while (self->entries) { - menu_entry_free(self->entries->data); + menu_entry_unref(self->entries->data); self->entries = g_list_delete_link(self->entries, self->entries); } + self->more_menu->entries = self->entries; /* keep it in sync */ } void menu_entry_remove(ObMenuEntry *self) { self->menu->entries = g_list_remove(self->menu->entries, self); - menu_entry_free(self); + menu_entry_unref(self); } ObMenuEntry* menu_add_normal(ObMenu *self, gint id, const gchar *label,

@@ -474,6 +488,18 @@

menu_entry_set_label(e, label, allow_shortcut); self->entries = g_list_append(self->entries, e); + self->more_menu->entries = self->entries; /* keep it in sync */ + return e; +} + +ObMenuEntry* menu_get_more(ObMenu *self, guint show_from) +{ + ObMenuEntry *e; + e = menu_entry_new(self, OB_MENU_ENTRY_TYPE_SUBMENU, -1); + /* points to itself */ + e->data.submenu.name = g_strdup(self->name); + e->data.submenu.submenu = self; + e->data.submenu.show_from = show_from; return e; }

@@ -485,6 +511,7 @@ e = menu_entry_new(self, OB_MENU_ENTRY_TYPE_SUBMENU, id);

e->data.submenu.name = g_strdup(submenu); self->entries = g_list_append(self->entries, e); + self->more_menu->entries = self->entries; /* keep it in sync */ return e; }

@@ -497,6 +524,7 @@

menu_entry_set_label(e, label, FALSE); self->entries = g_list_append(self->entries, e); + self->more_menu->entries = self->entries; /* keep it in sync */ return e; }
M openbox/menu.hopenbox/menu.h

@@ -82,6 +82,9 @@ ObMenuPlaceFunc place_func;

/* Pipe-menu parent, we get destroyed when it is destroyed */ ObMenu *pipe_creator; + + /* The menu used as the destination for the "More..." entry for this menu*/ + ObMenu *more_menu; }; typedef enum

@@ -120,6 +123,7 @@

struct _ObSubmenuMenuEntry { gchar *name; ObMenu *submenu; + guint show_from; }; struct _ObSeparatorMenuEntry {

@@ -128,6 +132,8 @@ };

struct _ObMenuEntry { + guint ref; + ObMenuEntryType type; ObMenu *menu;

@@ -143,10 +149,13 @@

void menu_startup(gboolean reconfig); void menu_shutdown(gboolean reconfig); +void menu_entry_ref(ObMenuEntry *self); +void menu_entry_unref(ObMenuEntry *self); + /*! @param allow_shortcut this should be false when the label is coming from outside data like window or desktop titles */ ObMenu* menu_new(const gchar *name, const gchar *title, - gboolean allow_shortcut, gpointer data); + gboolean allow_shortcut_selection, gpointer data); void menu_free(ObMenu *menu); /* Repopulate a pipe-menu by running its command */

@@ -180,5 +189,7 @@ ObMenuEntry* menu_find_entry_id(ObMenu *self, gint id);

/* fills in the submenus, for use when a menu is being shown */ void menu_find_submenus(ObMenu *self); + +ObMenuEntry* menu_get_more(ObMenu *menu, guint show_from); #endif
M openbox/menuframe.copenbox/menuframe.c

@@ -31,6 +31,8 @@ #define PADDING 2

#define SEPARATOR_HEIGHT 3 #define MAX_MENU_WIDTH 400 +#define ITEM_HEIGHT (ob_rr_theme->menu_font_height + 2*PADDING) + #define FRAME_EVENTMASK (ButtonPressMask |ButtonMotionMask | EnterWindowMask |\ LeaveWindowMask) #define ENTRY_EVENTMASK (EnterWindowMask | LeaveWindowMask | \

@@ -69,7 +71,7 @@

g_hash_table_destroy(menu_frame_map); } -ObMenuFrame* menu_frame_new(ObMenu *menu, ObClient *client) +ObMenuFrame* menu_frame_new(ObMenu *menu, guint show_from, ObClient *client) { ObMenuFrame *self; XSetWindowAttributes attr;

@@ -80,11 +82,16 @@ self->menu = menu;

self->selected = NULL; self->client = client; self->direction_right = TRUE; + self->show_from = show_from; attr.event_mask = FRAME_EVENTMASK; self->window = createWindow(RootWindow(ob_display, ob_screen), CWEventMask, &attr); + XSetWindowBorderWidth(ob_display, self->window, ob_rr_theme->mbwidth); + XSetWindowBorder(ob_display, self->window, + RrColorPixel(ob_rr_theme->menu_b_color)); + self->a_title = RrAppearanceCopy(ob_rr_theme->a_menu_title); self->a_items = RrAppearanceCopy(ob_rr_theme->a_menu);

@@ -121,6 +128,8 @@

self = g_new0(ObMenuEntryFrame, 1); self->entry = entry; self->frame = frame; + + menu_entry_ref(entry); attr.event_mask = ENTRY_EVENTMASK; self->window = createWindow(self->frame->window, CWEventMask, &attr);

@@ -176,6 +185,8 @@

static void menu_entry_frame_free(ObMenuEntryFrame *self) { if (self) { + menu_entry_unref(self->entry); + XDestroyWindow(ob_display, self->text); XDestroyWindow(ob_display, self->window); g_hash_table_remove(menu_frame_map, &self->text);

@@ -300,7 +311,7 @@ *x = self->parent->area.x - self->area.width + overlap + bwidth;

*y = self->parent->area.y + self->parent_entry->area.y; if (config_menu_middle) - *y -= (self->area.height - (bwidth * 2) - self->item_h) / 2; + *y -= (self->area.height - (bwidth * 2) - ITEM_HEIGHT) / 2; else *y += overlap; }

@@ -352,7 +363,7 @@ self->a_disabled_selected : self->a_disabled) :

/* enabled */ (self == self->frame->selected ? self->a_selected : self->a_normal)); - th = self->frame->item_h; + th = ITEM_HEIGHT; break; case OB_MENU_ENTRY_TYPE_SEPARATOR: if (self->entry->data.separator.label) {

@@ -422,23 +433,23 @@ case OB_MENU_ENTRY_TYPE_NORMAL:

XMoveResizeWindow(ob_display, self->text, self->frame->text_x, PADDING, self->frame->text_w, - self->frame->item_h - 2*PADDING); + ITEM_HEIGHT - 2*PADDING); text_a->surface.parent = item_a; text_a->surface.parentx = self->frame->text_x; text_a->surface.parenty = PADDING; RrPaint(text_a, self->text, self->frame->text_w, - self->frame->item_h - 2*PADDING); + ITEM_HEIGHT - 2*PADDING); break; case OB_MENU_ENTRY_TYPE_SUBMENU: XMoveResizeWindow(ob_display, self->text, self->frame->text_x, PADDING, - self->frame->text_w - self->frame->item_h, - self->frame->item_h - 2*PADDING); + self->frame->text_w - ITEM_HEIGHT, + ITEM_HEIGHT - 2*PADDING); text_a->surface.parent = item_a; text_a->surface.parentx = self->frame->text_x; text_a->surface.parenty = PADDING; - RrPaint(text_a, self->text, self->frame->text_w - self->frame->item_h, - self->frame->item_h - 2*PADDING); + RrPaint(text_a, self->text, self->frame->text_w - ITEM_HEIGHT, + ITEM_HEIGHT - 2*PADDING); break; case OB_MENU_ENTRY_TYPE_SEPARATOR: if (self->entry->data.separator.label != NULL) {

@@ -480,9 +491,9 @@ self->entry->data.normal.icon_data)

{ XMoveResizeWindow(ob_display, self->icon, PADDING, frame->item_margin.top, - self->frame->item_h - frame->item_margin.top + ITEM_HEIGHT - frame->item_margin.top - frame->item_margin.bottom, - self->frame->item_h - frame->item_margin.top + ITEM_HEIGHT - frame->item_margin.top - frame->item_margin.bottom); self->a_icon->texture[0].data.rgba.width = self->entry->data.normal.icon_width;

@@ -494,9 +505,9 @@ self->a_icon->surface.parent = item_a;

self->a_icon->surface.parentx = PADDING; self->a_icon->surface.parenty = frame->item_margin.top; RrPaint(self->a_icon, self->icon, - self->frame->item_h - frame->item_margin.top + ITEM_HEIGHT - frame->item_margin.top - frame->item_margin.bottom, - self->frame->item_h - frame->item_margin.top + ITEM_HEIGHT - frame->item_margin.top - frame->item_margin.bottom); XMapWindow(ob_display, self->icon); } else if (self->entry->type == OB_MENU_ENTRY_TYPE_NORMAL &&

@@ -506,9 +517,9 @@ RrColor *c;

XMoveResizeWindow(ob_display, self->icon, PADDING, frame->item_margin.top, - self->frame->item_h - frame->item_margin.top + ITEM_HEIGHT - frame->item_margin.top - frame->item_margin.bottom, - self->frame->item_h - frame->item_margin.top + ITEM_HEIGHT - frame->item_margin.top - frame->item_margin.bottom); self->a_mask->texture[0].data.mask.mask = self->entry->data.normal.mask;

@@ -529,9 +540,9 @@ self->a_mask->surface.parent = item_a;

self->a_mask->surface.parentx = PADDING; self->a_mask->surface.parenty = frame->item_margin.top; RrPaint(self->a_mask, self->icon, - self->frame->item_h - frame->item_margin.top + ITEM_HEIGHT - frame->item_margin.top - frame->item_margin.bottom, - self->frame->item_h - frame->item_margin.top + ITEM_HEIGHT - frame->item_margin.top - frame->item_margin.bottom); XMapWindow(ob_display, self->icon); } else

@@ -540,21 +551,20 @@

if (self->entry->type == OB_MENU_ENTRY_TYPE_SUBMENU) { RrAppearance *bullet_a; XMoveResizeWindow(ob_display, self->bullet, - self->frame->text_x + self->frame->text_w - - self->frame->item_h + PADDING, PADDING, - self->frame->item_h - 2*PADDING, - self->frame->item_h - 2*PADDING); + self->frame->text_x + self->frame->text_w - + ITEM_HEIGHT + PADDING, PADDING, + ITEM_HEIGHT - 2*PADDING, + ITEM_HEIGHT - 2*PADDING); bullet_a = (self == self->frame->selected ? self->a_bullet_selected : self->a_bullet_normal); bullet_a->surface.parent = item_a; bullet_a->surface.parentx = - self->frame->text_x + self->frame->text_w - self->frame->item_h - + PADDING; + self->frame->text_x + self->frame->text_w - ITEM_HEIGHT + PADDING; bullet_a->surface.parenty = PADDING; RrPaint(bullet_a, self->bullet, - self->frame->item_h - 2*PADDING, - self->frame->item_h - 2*PADDING); + ITEM_HEIGHT - 2*PADDING, + ITEM_HEIGHT - 2*PADDING); XMapWindow(ob_display, self->bullet); } else XUnmapWindow(ob_display, self->bullet);

@@ -562,6 +572,50 @@

XFlush(ob_display); } +/*! this code is taken from the menu_frame_render. if that changes, this won't + work.. */ +static gint menu_entry_frame_get_height(ObMenuEntryFrame *self, + gboolean first_entry, + gboolean last_entry) +{ + ObMenuEntryType t; + gint h = 0; + + h += 2*PADDING; + + if (self) + t = self->entry->type; + else + /* this is the More... entry, it's NORMAL type */ + t = OB_MENU_ENTRY_TYPE_NORMAL; + + switch (t) { + case OB_MENU_ENTRY_TYPE_NORMAL: + case OB_MENU_ENTRY_TYPE_SUBMENU: + h += ob_rr_theme->menu_font_height; + break; + case OB_MENU_ENTRY_TYPE_SEPARATOR: + if (self->entry->data.separator.label != NULL) { + h += ob_rr_theme->menu_title_height + + (ob_rr_theme->mbwidth - PADDING) * 2; + + /* if the first entry is a labeled separator, then make its border + overlap with the menu's outside border */ + if (first_entry) + h -= ob_rr_theme->mbwidth; + /* if the last entry is a labeled separator, then make its border + overlap with the menu's outside border */ + if (last_entry) + h -= ob_rr_theme->mbwidth; + } else { + h += SEPARATOR_HEIGHT; + } + break; + } + + return h; +} + static void menu_frame_render(ObMenuFrame *self) { gint w = 0, h = 0;

@@ -571,10 +625,6 @@ gboolean has_icon = FALSE;

ObMenu *sub; ObMenuEntryFrame *e; - XSetWindowBorderWidth(ob_display, self->window, ob_rr_theme->mbwidth); - XSetWindowBorder(ob_display, self->window, - RrColorPixel(ob_rr_theme->menu_b_color)); - /* find text dimensions */ STRUT_SET(self->item_margin, 0, 0, 0, 0);

@@ -584,10 +634,10 @@ ObMenuEntryFrame *e = self->entries->data;

gint l, t, r, b; e->a_text_normal->texture[0].data.text.string = ""; - RrMinSize(e->a_text_normal, &tw, &th); + tw = RrMinWidth(e->a_text_normal); tw += 2*PADDING; - th += 2*PADDING; - self->item_h = th; + + th = ITEM_HEIGHT; RrMargins(e->a_normal, &l, &t, &r, &b); STRUT_SET(self->item_margin,

@@ -613,8 +663,7 @@ MAX(self->item_margin.left, l),

MAX(self->item_margin.top, t), MAX(self->item_margin.right, r), MAX(self->item_margin.bottom, b)); - } else - self->item_h = 0; + } /* render the entries */

@@ -655,8 +704,9 @@ e->a_text_selected : e->a_text_normal));

switch (e->entry->type) { case OB_MENU_ENTRY_TYPE_NORMAL: text_a->texture[0].data.text.string = e->entry->data.normal.label; - RrMinSize(text_a, &tw, &th); + tw = RrMinWidth(text_a); tw = MIN(tw, MAX_MENU_WIDTH); + th = ob_rr_theme->menu_font_height; if (e->entry->data.normal.icon_data || e->entry->data.normal.mask)

@@ -665,20 +715,21 @@ break;

case OB_MENU_ENTRY_TYPE_SUBMENU: sub = e->entry->data.submenu.submenu; text_a->texture[0].data.text.string = sub ? sub->title : ""; - RrMinSize(text_a, &tw, &th); + tw = RrMinWidth(text_a); tw = MIN(tw, MAX_MENU_WIDTH); + th = ob_rr_theme->menu_font_height; if (e->entry->data.normal.icon_data || e->entry->data.normal.mask) has_icon = TRUE; - tw += self->item_h - PADDING; + tw += ITEM_HEIGHT - PADDING; break; case OB_MENU_ENTRY_TYPE_SEPARATOR: if (e->entry->data.separator.label != NULL) { e->a_text_title->texture[0].data.text.string = e->entry->data.separator.label; - RrMinSize(e->a_text_title, &tw, &th); + tw = RrMinWidth(text_a); tw = MIN(tw, MAX_MENU_WIDTH); th = ob_rr_theme->menu_title_height + (ob_rr_theme->mbwidth - PADDING) *2;

@@ -709,8 +760,8 @@ self->text_w = w;

if (self->entries) { if (has_icon) { - w += self->item_h + PADDING; - self->text_x += self->item_h + PADDING; + w += ITEM_HEIGHT + PADDING; + self->text_x += ITEM_HEIGHT + PADDING; } }

@@ -737,25 +788,35 @@

static void menu_frame_update(ObMenuFrame *self) { GList *mit, *fit; + Rect *a; + gint h; menu_pipe_execute(self->menu); menu_find_submenus(self->menu); self->selected = NULL; - for (mit = self->menu->entries, fit = self->entries; mit && fit; + /* start at show_from */ + mit = g_list_nth(self->menu->entries, self->show_from); + + /* go through the menu's and frame's entries and connect the frame entries + to the menu entries */ + for (fit = self->entries; mit && fit; mit = g_list_next(mit), fit = g_list_next(fit)) { ObMenuEntryFrame *f = fit->data; f->entry = mit->data; } + /* if there are more menu entries than in the frame, add them */ while (mit) { ObMenuEntryFrame *e = menu_entry_frame_new(mit->data, self); self->entries = g_list_append(self->entries, e); mit = g_list_next(mit); } - + + /* if there are more frame entries than menu entries then get rid of + them */ while (fit) { GList *n = g_list_next(fit); menu_entry_frame_free(fit->data);

@@ -764,6 +825,66 @@ fit = n;

} menu_frame_render(self); + + /* make the menu fit on the screen. at most we call render twice, at least + not like n times or sometime */ + + a = screen_physical_area_monitor(self->monitor); + h = self->area.height; + + if (h > a->height) { + GList *flast, *tmp; + gboolean last_entry = TRUE; + + /* take the height of our More... entry into account */ + h += menu_entry_frame_get_height(NULL, FALSE, TRUE); + + /* start at the end of the entries */ + flast = g_list_last(self->entries); + + /* pull out all the entries from the frame that don't + fit on the screen, leaving at least 1 though */ + while (h > a->height && g_list_previous(flast) != NULL) { + /* update the height, without this entry */ + h -= menu_entry_frame_get_height(flast->data, FALSE, last_entry); + + /* destroy the entry we're not displaying */ + tmp = flast; + flast = g_list_previous(flast); + menu_entry_frame_free(tmp->data); + self->entries = g_list_delete_link(self->entries, tmp); + + menu_frame_render(self); + + /* only the first one that we see is the last entry in the menu */ + last_entry = FALSE; + }; + + { + ObMenuEntry *more_entry; + ObMenuEntryFrame *more_frame; + /* make the More... menu entry frame which will display in this + frame. + if self->menu->more_menu is NULL that means that this is already + More... menu, so just use ourself. + */ + more_entry = menu_get_more((self->menu->more_menu ? + self->menu->more_menu : + self->menu), + /* continue where we left off */ + self->show_from + + g_list_length(self->entries)); + more_frame = menu_entry_frame_new(more_entry, self); + /* make it get deleted when the menu frame goes away */ + menu_entry_unref(more_entry); + + /* add our More... entry to the frame */ + self->entries = g_list_append(self->entries, more_frame); + } + + /* render again */ + menu_frame_render(self); + } } static gboolean menu_frame_is_visible(ObMenuFrame *self)

@@ -1021,6 +1142,7 @@

if (!self->entry->data.submenu.submenu) return; f = menu_frame_new(self->entry->data.submenu.submenu, + self->entry->data.submenu.show_from, self->frame->client); /* pass our direction on to our child */ f->direction_right = self->frame->direction_right;
M openbox/menuframe.hopenbox/menuframe.h

@@ -54,6 +54,9 @@

GList *entries; ObMenuEntryFrame *selected; + /* show entries from the menu starting at this index */ + guint show_from; + /* If the submenus are being drawn to the right or the left */ gboolean direction_right;

@@ -61,10 +64,10 @@ /* On-screen area (including borders!) */

Rect area; Strut item_margin; gint inner_w; /* inside the borders */ - gint title_h; /* height of all title items */ gint item_h; /* height of all normal items */ gint text_x; /* offset at which the text appears in the items */ gint text_w; /* width of the text area in the items */ + gint text_h; /* height of the items */ gint monitor; /* monitor on which to show the menu in xinerama */

@@ -74,6 +77,9 @@ };

struct _ObMenuEntryFrame { + /* if this is true then it doesn't have an entry to point to */ + gboolean more; + struct _ObMenuEntry *entry; ObMenuFrame *frame;

@@ -109,7 +115,9 @@

void menu_frame_startup(gboolean reconfig); void menu_frame_shutdown(gboolean reconfig); -ObMenuFrame* menu_frame_new(struct _ObMenu *menu, struct _ObClient *client); +ObMenuFrame* menu_frame_new(struct _ObMenu *menu, + guint show_from, + struct _ObClient *client); void menu_frame_free(ObMenuFrame *self); void menu_frame_move(ObMenuFrame *self, gint x, gint y);
M render/theme.crender/theme.c

@@ -1204,9 +1204,10 @@ MAX(MAX(theme->padding * 2, ft + fb),

MAX(theme->padding * 2, ut + ub)); */ theme->title_height = theme->label_height + theme->paddingy * 2; - /* this should match the above title_height given the same font size - for both. */ - theme->menu_title_height = theme->menu_title_font_height + + + RrMargins(theme->a_menu_title, &ul, &ut, &ur, &ub); + theme->menu_title_label_height = theme->menu_title_font_height+ut+ub; + theme->menu_title_height = theme->menu_title_label_height + theme->paddingy * 2; } theme->button_size = theme->label_height - 2;
M render/theme.hrender/theme.h

@@ -51,9 +51,10 @@ gint menu_title_font_height;

gint menu_font_height; gint label_height; gint title_height; - gint menu_title_height; gint button_size; gint grip_width; + gint menu_title_label_height; + gint menu_title_height; /* style settings - colors */ RrColor *menu_b_color;