From 7af1c6a9c3a57f3ded34fad3f9f4a30fe377a65e Mon Sep 17 00:00:00 2001 From: Dana Jansens Date: Wed, 25 Jun 2003 18:43:42 +0000 Subject: [PATCH] menus grab the keyboard and pointer, thus making only one menu visible at a time, and making them act like gtk menus and * menus do, where you can click and drag and release to select something as well as click-release to elave it open while you search around the menu --- openbox/event.c | 137 ++++++++++++++++++++++++++++++------------ openbox/menu.c | 37 ++++++++++-- openbox/menu.h | 2 + openbox/menu_render.c | 6 +- 4 files changed, 134 insertions(+), 48 deletions(-) diff --git a/openbox/event.c b/openbox/event.c index 52747d3f..e9e85f0b 100644 --- a/openbox/event.c +++ b/openbox/event.c @@ -41,7 +41,7 @@ static void event_handle_root(XEvent *e); static void event_handle_dock(Dock *s, XEvent *e); static void event_handle_dockapp(DockApp *app, XEvent *e); static void event_handle_client(Client *c, XEvent *e); -static void event_handle_menu(Menu *menu, Client *c, XEvent *e); +static void event_handle_menu(Client *c, XEvent *e); static void fd_event_handle(); #ifdef USE_SM static void ice_watch(IceConn conn, IcePointer data, Bool opening, @@ -501,10 +501,7 @@ static void event_process(XEvent *e) return; /* deal with it in the kernel */ - if (menu) { - event_handle_menu(menu, client, e); - return; - } else if (client) + if (client) event_handle_client(client, e); else if (dockapp) event_handle_dockapp(dockapp, e); @@ -535,6 +532,15 @@ static void event_process(XEvent *e) xerror_set_ignore(FALSE); } + if (menu_visible) + if (e->type == MotionNotify || e->type == ButtonRelease || + e->type == ButtonPress || + e->type == KeyPress || e->type == KeyRelease) { + event_handle_menu(client, e); + + return; /* no dispatch! */ + } + if (moveresize_in_progress) if (e->type == MotionNotify || e->type == ButtonRelease || e->type == ButtonPress || @@ -977,57 +983,110 @@ static void event_handle_client(Client *client, XEvent *e) } } -static void event_handle_menu(Menu *menu, Client *client, XEvent *e) +static void event_handle_menu(Client *client, XEvent *e) { + static MenuEntry *over = NULL; MenuEntry *entry; + Menu *top; + GSList *it; + + top = g_slist_nth_data(menu_visible, 0); g_message("EVENT %d", e->type); switch (e->type) { + case KeyPress: + if (over) { + if (over->parent->mouseover) + over->parent->mouseover(over, FALSE); + else + menu_control_mouseover(over, FALSE); + menu_entry_render(over); + } +/* + if (top->hide) + top->hide(top); + else +*/ + menu_hide(top); + break; case ButtonPress: + if (e->xbutton.button > 3) break; + g_message("BUTTON PRESS"); - if (e->xbutton.button == 3) - menu_hide(menu); - else if (e->xbutton.button == 1) { - entry = menu_find_entry(menu, e->xbutton.window); - if (!entry) - stacking_raise(MENU_AS_WINDOW(menu)); - } break; case ButtonRelease: + if (e->xbutton.button > 3) break; + g_message("BUTTON RELEASED"); - if (!menu->shown) break; - -/* grab_pointer_window(FALSE, None, menu->frame);*/ - - if (e->xbutton.button == 1) { - entry = menu_find_entry(menu, e->xbutton.window); - if (entry) { - int junk; - Window wjunk; - guint ujunk, b, w, h; - XGetGeometry(ob_display, e->xbutton.window, - &wjunk, &junk, &junk, &w, &h, &b, &ujunk); - if (e->xbutton.x >= (signed)-b && - e->xbutton.y >= (signed)-b && - e->xbutton.x < (signed)(w+b) && - e->xbutton.y < (signed)(h+b)) { + + for (it = menu_visible; it; it = g_slist_next(it)) { + Menu *m = it->data; + if (e->xbutton.x_root >= m->location.x - ob_rr_theme->bwidth && + e->xbutton.y_root >= m->location.y - ob_rr_theme->bwidth && + e->xbutton.x_root < m->location.x + m->size.width + + ob_rr_theme->bwidth && + e->xbutton.y_root < m->location.y + m->size.height + + ob_rr_theme->bwidth) { + if ((entry = menu_find_entry_by_pos(it->data, + e->xbutton.x_root - + m->location.x, + e->xbutton.y_root - + m->location.y))) { menu_entry_fire(entry); } + break; } } + if (!it) { + if (over) { + if (over->parent->mouseover) + over->parent->mouseover(over, FALSE); + else + menu_control_mouseover(over, FALSE); + } + menu_entry_render(over); +/* + if (top->hide) + top->hide(top); + else +*/ + menu_hide(top); + } break; - case EnterNotify: - case LeaveNotify: - g_message("enter/leave"); - entry = menu_find_entry(menu, e->xcrossing.window); - if (entry) { - if (menu->mouseover) - menu->mouseover(entry, e->type == EnterNotify); + case MotionNotify: + g_message("motion"); + for (it = menu_visible; it; it = g_slist_next(it)) { + Menu *m = it->data; + if ((entry = menu_find_entry_by_pos(it->data, + e->xmotion.x_root - + m->location.x, + e->xmotion.y_root - + m->location.y))) { + if (over && entry != over) { + if (over->parent->mouseover) + over->parent->mouseover(over, FALSE); + else + menu_control_mouseover(over, FALSE); + menu_entry_render(over); + } + + over = entry; + if (over->parent->mouseover) + over->parent->mouseover(over, TRUE); + else + menu_control_mouseover(over, TRUE); + menu_entry_render(over); + break; + } + } + if (!it && over) { + if (over->parent->mouseover) + over->parent->mouseover(over, FALSE); else - menu_control_mouseover(entry, e->type == EnterNotify); - - menu_entry_render(entry); + menu_control_mouseover(over, FALSE); + menu_entry_render(over); + over = NULL; } break; } diff --git a/openbox/menu.c b/openbox/menu.c index b67b76a6..8f7c8b6c 100644 --- a/openbox/menu.c +++ b/openbox/menu.c @@ -2,12 +2,12 @@ #include "openbox.h" #include "stacking.h" #include "grab.h" -#include "render/theme.h" #include "screen.h" #include "geom.h" #include "plugin.h" GHashTable *menu_hash = NULL; +GSList *menu_visible = NULL; #define FRAME_EVENTMASK (ButtonPressMask |ButtonMotionMask | EnterWindowMask | \ LeaveWindowMask) @@ -310,6 +310,16 @@ void menu_show_full(Menu *self, int x, int y, Client *client) self->client = client; + if (!self->shown) { + GSList *it; + + if (!self->parent) { + grab_pointer(TRUE, None); + grab_keyboard(TRUE); + } + menu_visible = g_slist_append(menu_visible, self); + } + if (self->show) { self->show(self, x, y, client); } else { @@ -326,6 +336,11 @@ void menu_hide(Menu *self) { if (self->parent && self->parent->open_submenu == self) self->parent->open_submenu = NULL; + if (!self->parent) { + grab_keyboard(FALSE); + grab_pointer(FALSE, None); + } + menu_visible = g_slist_remove(menu_visible, self); } } @@ -353,6 +368,18 @@ MenuEntry *menu_find_entry(Menu *menu, Window win) return NULL; } +MenuEntry *menu_find_entry_by_pos(Menu *menu, int x, int y) +{ + if (x < 0 || x >= menu->size.width || y < 0 || y >= menu->size.height) + return NULL; + + y -= menu->title_h + ob_rr_theme->bwidth; + if (y < 0) return NULL; + + g_message ("%d %p", y/menu->item_h, g_list_nth_data(menu->entries, y / menu->item_h)); + return g_list_nth_data(menu->entries, y / menu->item_h); +} + void menu_entry_fire(MenuEntry *self) { Menu *m; @@ -375,12 +402,10 @@ void menu_entry_fire(MenuEntry *self) void menu_control_show(Menu *self, int x, int y, Client *client) { g_assert(!self->invalid); - XMoveWindow(ob_display, self->frame, - MIN(x, screen_physical_size.width - self->size.width), - MIN(y, screen_physical_size.height - self->size.height)); POINT_SET(self->location, MIN(x, screen_physical_size.width - self->size.width), MIN(y, screen_physical_size.height - self->size.height)); + XMoveWindow(ob_display, self->frame, self->location.x, self->location.y); if (!self->shown) { XMapWindow(ob_display, self->frame); @@ -413,9 +438,9 @@ void menu_control_mouseover(MenuEntry *self, gboolean enter) { /* need to get the width. is this bad?*/ menu_render(self->submenu); - if (self->submenu->size.width + x > screen_physical_size.width) + if (self->submenu->size.width + x >= screen_physical_size.width) x = self->parent->location.x - self->submenu->size.width - - ob_rr_theme->bevel; + ob_rr_theme->bwidth; menu_show_full(self->submenu, x, self->parent->location.y + self->y, diff --git a/openbox/menu.h b/openbox/menu.h index 6cb76a5e..ea5d7454 100644 --- a/openbox/menu.h +++ b/openbox/menu.h @@ -16,6 +16,7 @@ typedef void(*menu_controller_mouseover)(struct MenuEntry *self, gboolean enter); extern GHashTable *menu_hash; +extern GSList *menu_visible; typedef struct Menu { ObWindow obwin; @@ -131,6 +132,7 @@ void menu_entry_set_submenu(MenuEntry *entry, Menu *submenu); void menu_add_entry(Menu *menu, MenuEntry *entry); MenuEntry *menu_find_entry(Menu *menu, Window win); +MenuEntry *menu_find_entry_by_pos(Menu *menu, int x, int y); void menu_entry_render(MenuEntry *self); diff --git a/openbox/menu_render.c b/openbox/menu_render.c index 87ffa913..d3b0e016 100644 --- a/openbox/menu_render.c +++ b/openbox/menu_render.c @@ -79,8 +79,8 @@ void menu_render_full(Menu *self) { self->item_h += ob_rr_theme->bevel * 2; items_h = self->item_h * MAX(nitems, 1); - XResizeWindow(ob_display, self->frame, self->size.width, - MAX(self->title_h + items_h + ob_rr_theme->bwidth, 1)); + self->size.height = MAX(self->title_h + items_h + ob_rr_theme->bwidth, 1); + XResizeWindow(ob_display, self->frame, self->size.width,self->size.height); if (self->label) XMoveResizeWindow(ob_display, self->title, -ob_rr_theme->bwidth, -ob_rr_theme->bwidth, @@ -101,7 +101,6 @@ void menu_render_full(Menu *self) { item_y += self->item_h; } - self->size.height = item_y; self->invalid = FALSE; } @@ -134,6 +133,7 @@ void menu_entry_render(MenuEntry *self) self->a_hilite : self->a_item); break; } + g_message ("%s %d", self->label, self->hilite); XMoveResizeWindow(ob_display, self->item, 0, self->y, menu->size.width, menu->item_h); -- 2.39.2