X-Git-Url: https://git.dogcows.com/gitweb?a=blobdiff_plain;f=openbox%2Fmenuframe.c;h=f359c9852ee091b0c14e2793de5584fbc427b124;hb=939fbcfd31e07a6e0f1cdbfcef9b04f63e6af700;hp=f8c0b0556505badca1190041aaf2951274233175;hpb=e6c82786ff65e7681c980c8adebe082656c16438;p=chaz%2Fopenbox diff --git a/openbox/menuframe.c b/openbox/menuframe.c index f8c0b055..f359c985 100644 --- a/openbox/menuframe.c +++ b/openbox/menuframe.c @@ -2,7 +2,7 @@ menuframe.c for the Openbox window manager Copyright (c) 2006 Mikael Magnusson - Copyright (c) 2003 Ben Jansens + Copyright (c) 2003-2007 Dana Jansens This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -33,7 +33,6 @@ #define FRAME_EVENTMASK (ButtonPressMask |ButtonMotionMask | EnterWindowMask |\ LeaveWindowMask) -#define TITLE_EVENTMASK (ButtonPressMask | ButtonMotionMask) #define ENTRY_EVENTMASK (EnterWindowMask | LeaveWindowMask | \ ButtonPressMask | ButtonReleaseMask) @@ -54,6 +53,22 @@ static Window createWindow(Window parent, gulong mask, RrVisual(ob_rr_inst), mask, attrib); } +GHashTable *menu_frame_map; + +void menu_frame_startup(gboolean reconfig) +{ + if (reconfig) return; + + menu_frame_map = g_hash_table_new(g_int_hash, g_int_equal); +} + +void menu_frame_shutdown(gboolean reconfig) +{ + if (reconfig) return; + + g_hash_table_destroy(menu_frame_map); +} + ObMenuFrame* menu_frame_new(ObMenu *menu, ObClient *client) { ObMenuFrame *self; @@ -63,18 +78,12 @@ 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; self->direction_right = TRUE; attr.event_mask = FRAME_EVENTMASK; self->window = createWindow(RootWindow(ob_display, ob_screen), CWEventMask, &attr); - attr.event_mask = TITLE_EVENTMASK; - self->title = createWindow(self->window, CWEventMask, &attr); - self->items = createWindow(self->window, 0, NULL); - - XMapWindow(ob_display, self->items); self->a_title = RrAppearanceCopy(ob_rr_theme->a_menu_title); self->a_items = RrAppearanceCopy(ob_rr_theme->a_menu); @@ -94,8 +103,6 @@ void menu_frame_free(ObMenuFrame *self) stacking_remove(MENU_AS_WINDOW(self)); - XDestroyWindow(ob_display, self->items); - XDestroyWindow(ob_display, self->title); XDestroyWindow(ob_display, self->window); RrAppearanceFree(self->a_items); @@ -116,11 +123,17 @@ static ObMenuEntryFrame* menu_entry_frame_new(ObMenuEntry *entry, self->frame = frame; attr.event_mask = ENTRY_EVENTMASK; - self->window = createWindow(self->frame->items, CWEventMask, &attr); + self->window = createWindow(self->frame->window, CWEventMask, &attr); self->text = createWindow(self->window, 0, NULL); - if (entry->type != OB_MENU_ENTRY_TYPE_SEPARATOR) { + g_hash_table_insert(menu_frame_map, &self->window, self); + g_hash_table_insert(menu_frame_map, &self->text, self); + if (entry->type == OB_MENU_ENTRY_TYPE_NORMAL) { self->icon = createWindow(self->window, 0, NULL); + g_hash_table_insert(menu_frame_map, &self->icon, self); + } + if (entry->type == OB_MENU_ENTRY_TYPE_SUBMENU) { self->bullet = createWindow(self->window, 0, NULL); + g_hash_table_insert(menu_frame_map, &self->bullet, self); } XMapWindow(ob_display, self->window); @@ -150,6 +163,8 @@ static ObMenuEntryFrame* menu_entry_frame_new(ObMenuEntry *entry, RrAppearanceCopy(ob_rr_theme->a_menu_text_disabled); self->a_text_selected = RrAppearanceCopy(ob_rr_theme->a_menu_text_selected); + self->a_text_title = + RrAppearanceCopy(ob_rr_theme->a_menu_text_title); return self; } @@ -159,9 +174,15 @@ static void menu_entry_frame_free(ObMenuEntryFrame *self) if (self) { XDestroyWindow(ob_display, self->text); XDestroyWindow(ob_display, self->window); - if (self->entry->type != OB_MENU_ENTRY_TYPE_SEPARATOR) { + g_hash_table_insert(menu_frame_map, &self->text, self); + g_hash_table_insert(menu_frame_map, &self->window, self); + if (self->entry->type == OB_MENU_ENTRY_TYPE_NORMAL) { XDestroyWindow(ob_display, self->icon); + g_hash_table_insert(menu_frame_map, &self->icon, self); + } + if (self->entry->type == OB_MENU_ENTRY_TYPE_SUBMENU) { XDestroyWindow(ob_display, self->bullet); + g_hash_table_insert(menu_frame_map, &self->bullet, self); } RrAppearanceFree(self->a_normal); @@ -174,6 +195,7 @@ static void menu_entry_frame_free(ObMenuEntryFrame *self) RrAppearanceFree(self->a_text_normal); RrAppearanceFree(self->a_text_disabled); RrAppearanceFree(self->a_text_selected); + RrAppearanceFree(self->a_text_title); RrAppearanceFree(self->a_bullet_normal); RrAppearanceFree(self->a_bullet_selected); @@ -193,13 +215,8 @@ void menu_frame_place_topmenu(ObMenuFrame *self, gint x, gint y) x = self->client->frame->area.x + self->client->frame->size.left; y = self->client->frame->area.y + self->client->frame->size.top; } else { - if (config_menu_middle) { - x -= self->area.width / 2; - y -= self->title_h*3/4; - } else { - x -= ob_rr_theme->mbwidth; - y -= ob_rr_theme->mbwidth; - } + if (config_menu_middle) + y -= self->area.height / 2; } menu_frame_move(self, x, y); } @@ -210,19 +227,19 @@ void menu_frame_place_submenu(ObMenuFrame *self) gint overlap; gint bwidth; - overlap = (config_menu_middle ? 0 : ob_rr_theme->menu_overlap); + overlap = ob_rr_theme->menu_overlap; bwidth = ob_rr_theme->mbwidth; - if (self->direction_right) x = self->parent->area.x + self->parent->area.width - overlap - bwidth; else x = self->parent->area.x - self->area.width + overlap + bwidth; - y = self->parent->area.y + self->parent->title_h + - self->parent_entry->area.y + overlap; + y = self->parent->area.y + self->parent_entry->area.y; if (config_menu_middle) - y = y - self->area.height/2 + self->item_h/2; + y -= (self->area.height - (bwidth * 2) - self->item_h) / 2; + else + y += overlap; menu_frame_move(self, x, y); } @@ -262,19 +279,25 @@ static void menu_entry_frame_render(ObMenuEntryFrame *self) ObMenu *sub; ObMenuFrame *frame = self->frame; - 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 : - self->a_normal)); switch (self->entry->type) { case OB_MENU_ENTRY_TYPE_NORMAL: case OB_MENU_ENTRY_TYPE_SUBMENU: + 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 : + self->a_normal)); th = self->frame->item_h; break; case OB_MENU_ENTRY_TYPE_SEPARATOR: - th = SEPARATOR_HEIGHT + 2*PADDING; + if (self->entry->data.separator.label) { + item_a = self->frame->a_title; + th = ob_rr_theme->menu_title_height; + } else { + item_a = self->a_normal; + th = SEPARATOR_HEIGHT + 2*PADDING; + } break; default: g_assert_not_reached(); @@ -287,21 +310,27 @@ 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->type == OB_MENU_ENTRY_TYPE_NORMAL && - !self->entry->data.normal.enabled) ? - self->a_text_disabled : - (self == self->frame->selected ? - self->a_text_selected : - self->a_text_normal)); switch (self->entry->type) { case OB_MENU_ENTRY_TYPE_NORMAL: + text_a = (!self->entry->data.normal.enabled ? + self->a_text_disabled : + (self == self->frame->selected ? + self->a_text_selected : + self->a_text_normal)); text_a->texture[0].data.text.string = self->entry->data.normal.label; break; case OB_MENU_ENTRY_TYPE_SUBMENU: + text_a = (self == self->frame->selected ? + self->a_text_selected : + self->a_text_normal); sub = self->entry->data.submenu.submenu; text_a->texture[0].data.text.string = sub ? sub->title : ""; break; case OB_MENU_ENTRY_TYPE_SEPARATOR: + if (self->entry->data.separator.label != NULL) + text_a = self->a_text_title; + else + text_a = self->a_text_normal; break; } @@ -329,24 +358,41 @@ static void menu_entry_frame_render(ObMenuEntryFrame *self) self->frame->item_h - 2*PADDING); break; case OB_MENU_ENTRY_TYPE_SEPARATOR: - XMoveResizeWindow(ob_display, self->text, PADDING, PADDING, - self->area.width - 2*PADDING, SEPARATOR_HEIGHT); - self->a_separator->surface.parent = item_a; - self->a_separator->surface.parentx = PADDING; - self->a_separator->surface.parenty = PADDING; - self->a_separator->texture[0].data.lineart.color = - text_a->texture[0].data.text.color; - self->a_separator->texture[0].data.lineart.x1 = 2*PADDING; - self->a_separator->texture[0].data.lineart.y1 = SEPARATOR_HEIGHT / 2; - self->a_separator->texture[0].data.lineart.x2 = - self->area.width - 4*PADDING; - self->a_separator->texture[0].data.lineart.y2 = SEPARATOR_HEIGHT / 2; - RrPaint(self->a_separator, self->text, - self->area.width - 2*PADDING, SEPARATOR_HEIGHT); + if (self->entry->data.separator.label != NULL) { + /* labeled separator */ + XMoveResizeWindow(ob_display, self->text, + ob_rr_theme->paddingx, ob_rr_theme->paddingy, + self->area.width - 2*ob_rr_theme->paddingx, + ob_rr_theme->menu_title_height - + 2*ob_rr_theme->paddingy); + text_a->surface.parent = item_a; + text_a->surface.parentx = ob_rr_theme->paddingx; + text_a->surface.parenty = ob_rr_theme->paddingy; + RrPaint(text_a, self->text, + self->area.width - 2*ob_rr_theme->paddingx, + ob_rr_theme->menu_title_height - + 2*ob_rr_theme->paddingy); + } else { + /* unlabeled separaator */ + XMoveResizeWindow(ob_display, self->text, PADDING, PADDING, + self->area.width - 2*PADDING, SEPARATOR_HEIGHT); + self->a_separator->surface.parent = item_a; + self->a_separator->surface.parentx = PADDING; + self->a_separator->surface.parenty = PADDING; + self->a_separator->texture[0].data.lineart.color = + text_a->texture[0].data.text.color; + self->a_separator->texture[0].data.lineart.x1 = 2*PADDING; + self->a_separator->texture[0].data.lineart.y1 = SEPARATOR_HEIGHT/2; + self->a_separator->texture[0].data.lineart.x2 = + self->area.width - 4*PADDING; + self->a_separator->texture[0].data.lineart.y2 = SEPARATOR_HEIGHT/2; + RrPaint(self->a_separator, self->text, + self->area.width - 2*PADDING, SEPARATOR_HEIGHT); + } break; } - if (self->entry->type != OB_MENU_ENTRY_TYPE_SEPARATOR && + if (self->entry->type == OB_MENU_ENTRY_TYPE_NORMAL && self->entry->data.normal.icon_data) { XMoveResizeWindow(ob_display, self->icon, @@ -370,7 +416,7 @@ static void menu_entry_frame_render(ObMenuEntryFrame *self) self->frame->item_h - frame->item_margin.top - frame->item_margin.bottom); XMapWindow(ob_display, self->icon); - } else if (self->entry->type != OB_MENU_ENTRY_TYPE_SEPARATOR && + } else if (self->entry->type == OB_MENU_ENTRY_TYPE_NORMAL && self->entry->data.normal.mask) { RrColor *c; @@ -432,34 +478,17 @@ static void menu_entry_frame_render(ObMenuEntryFrame *self) static void menu_frame_render(ObMenuFrame *self) { gint w = 0, h = 0; - gint allitems_h = 0; gint tw, th; /* temps */ GList *it; 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)); - if (!self->parent && self->show_title) { - XMoveWindow(ob_display, self->title, - -ob_rr_theme->mbwidth, h - ob_rr_theme->mbwidth); - - self->a_title->texture[0].data.text.string = self->menu->title; - RrMinsize(self->a_title, &tw, &th); - tw = MIN(tw, MAX_MENU_WIDTH) + ob_rr_theme->paddingx * 2; - w = MAX(w, tw); - - th = ob_rr_theme->menu_title_height; - h += (self->title_h = th + ob_rr_theme->mbwidth); - - XSetWindowBorderWidth(ob_display, self->title, ob_rr_theme->mbwidth); - XSetWindowBorder(ob_display, self->title, - RrColorPixel(ob_rr_theme->menu_b_color)); - } - - XMoveWindow(ob_display, self->items, 0, h); + /* find text dimensions */ STRUT_SET(self->item_margin, 0, 0, 0, 0); @@ -494,12 +523,32 @@ static void menu_frame_render(ObMenuFrame *self) } else self->item_h = 0; + /* render the entries */ + for (it = self->entries; it; it = g_list_next(it)) { RrAppearance *text_a; - ObMenuEntryFrame *e = it->data; + e = it->data; + + /* if the first entry is a labeled separator, then make its border + overlap with the menu's outside border */ + if (it == self->entries && + e->entry->type == OB_MENU_ENTRY_TYPE_SEPARATOR && + e->entry->data.separator.label) + { + h -= ob_rr_theme->mbwidth; + } + + if (e->entry->type == OB_MENU_ENTRY_TYPE_SEPARATOR && + e->entry->data.separator.label) + { + e->border = ob_rr_theme->mbwidth; + } - RECT_SET_POINT(e->area, 0, allitems_h); - XMoveWindow(ob_display, e->window, 0, e->area.y); + RECT_SET_POINT(e->area, 0, h+e->border); + XMoveWindow(ob_display, e->window, e->area.x-e->border, e->area.y-e->border); + XSetWindowBorderWidth(ob_display, e->window, e->border); + XSetWindowBorder(ob_display, e->window, + RrColorPixel(ob_rr_theme->menu_b_color)); text_a = ((e->entry->type == OB_MENU_ENTRY_TYPE_NORMAL && !e->entry->data.normal.enabled) ? @@ -530,15 +579,33 @@ static void menu_frame_render(ObMenuFrame *self) tw += self->item_h - PADDING; break; case OB_MENU_ENTRY_TYPE_SEPARATOR: - tw = 0; - th = SEPARATOR_HEIGHT; + 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 = MIN(tw, MAX_MENU_WIDTH); + th = ob_rr_theme->menu_title_height + + (ob_rr_theme->mbwidth - PADDING) *2; + } else { + tw = 0; + th = SEPARATOR_HEIGHT; + } break; } tw += 2*PADDING; th += 2*PADDING; w = MAX(w, tw); h += th; - allitems_h += th; + } + + /* if the last entry is a labeled separator, then make its border + overlap with the menu's outside border */ + it = g_list_last(self->entries); + e = it ? it->data : NULL; + if (e && e->entry->type == OB_MENU_ENTRY_TYPE_SEPARATOR && + e->entry->data.separator.label) + { + h -= ob_rr_theme->mbwidth; } self->text_x = PADDING; @@ -552,26 +619,13 @@ static void menu_frame_render(ObMenuFrame *self) } if (!w) w = 10; - if (!allitems_h) { - allitems_h = 3; - h += 3; - } + if (!h) 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->show_title) { - XResizeWindow(ob_display, self->title, - w, self->title_h - ob_rr_theme->mbwidth); - RrPaint(self->a_title, self->title, - w, self->title_h - ob_rr_theme->mbwidth); - XMapWindow(ob_display, self->title); - } else - XUnmapWindow(ob_display, self->title); - - RrPaint(self->a_items, self->items, w, allitems_h); + RrPaint(self->a_items, self->window, w, h); for (it = self->entries; it; it = g_list_next(it)) menu_entry_frame_render(it->data); @@ -627,10 +681,10 @@ static gboolean menu_frame_show(ObMenuFrame *self) if (menu_frame_visible == NULL) { /* no menus shown yet */ - if (!grab_pointer(TRUE, OB_CURSOR_NONE)) + if (!grab_pointer(TRUE, OB_CURSOR_POINTER)) return FALSE; if (!grab_keyboard(TRUE)) { - grab_pointer(FALSE, OB_CURSOR_NONE); + grab_pointer(FALSE, OB_CURSOR_POINTER); return FALSE; } } @@ -685,12 +739,11 @@ gboolean menu_frame_show_topmenu(ObMenuFrame *self, gint x, gint y) gboolean menu_frame_show_submenu(ObMenuFrame *self, ObMenuFrame *parent, ObMenuEntryFrame *parent_entry) { + ObMenuEntryFrame *e; gint dx, dy; if (menu_frame_is_visible(self)) return TRUE; - if (!menu_frame_show(self)) - return FALSE; self->monitor = parent->monitor; self->parent = parent; @@ -701,6 +754,9 @@ gboolean menu_frame_show_submenu(ObMenuFrame *self, ObMenuFrame *parent, menu_frame_hide(parent->child); parent->child = self; + if (!menu_frame_show(self)) + return FALSE; + menu_frame_place_submenu(self); menu_frame_move_on_screen(self, &dx, &dy); @@ -727,6 +783,10 @@ gboolean menu_frame_show_submenu(ObMenuFrame *self, ObMenuFrame *parent, XMapWindow(ob_display, self->window); + if (screen_pointer_pos(&dx, &dy) && (e = menu_entry_frame_under(dx, dy)) && + e->frame == self) + ++e->ignore_enters; + return TRUE; } @@ -806,7 +866,7 @@ ObMenuEntryFrame* menu_entry_frame_under(gint x, gint y) if ((frame = menu_frame_under(x, y))) { x -= ob_rr_theme->mbwidth + frame->area.x; - y -= frame->title_h + ob_rr_theme->mbwidth + frame->area.y; + y -= ob_rr_theme->mbwidth + frame->area.y; for (it = frame->entries; it; it = g_list_next(it)) { ObMenuEntryFrame *e = it->data; @@ -858,7 +918,7 @@ void menu_frame_select(ObMenuFrame *self, ObMenuEntryFrame *entry) ob_main_loop_timeout_add(ob_main_loop, config_submenu_show_delay * 1000, menu_entry_frame_submenu_timeout, - self->selected, + self->selected, g_direct_equal, NULL); } else { menu_entry_frame_show_submenu(self->selected);