menu: recursive findMenu so sub-sub-menus respond to mouse
The previous implementation only checked one level of cascades — scr->root_menu and scr->root_menu->cascades[i]. Sub-sub-menus (cascade->cascade->...) were never checked, so hovering over a sub-sub-menu's entries did not return the menu, and selectEntry therefore could not open the next-level cascade or react to clicks. Replace with a recursive walk over each top-level menu's full cascade tree. Pick the deepest mapped menu that contains the pointer (deeper cascades render on top in the scene graph and should win the hit-test). X11 sidesteps this with XQueryPointer + XFindContext, which finds any menu window via the X server's hit-test regardless of nesting.
This commit is contained in:
parent
31576e4b25
commit
3fb9f3925f
94
src/menu.c
94
src/menu.c
|
|
@ -1109,73 +1109,49 @@ static void selectEntry(WMenu * menu, int entry_no)
|
|||
}
|
||||
}
|
||||
|
||||
/* Recursively walk a menu and all of its descendants checking whether
|
||||
* the pointer is over the entries area. Updates *deepest_p to the
|
||||
* deepest mapped menu under (x,y) so that sub-sub-menus (cascade-of-
|
||||
* cascade-...) are reachable.
|
||||
*/
|
||||
static void findMenuWalk(WMenu *m, int x, int y,
|
||||
WMenu **deepest_p, int *dx_p, int *dy_p)
|
||||
{
|
||||
if (!m) return;
|
||||
if (m->flags.mapped &&
|
||||
x >= m->frame_x && x < m->frame_x + MENUW(m) &&
|
||||
y >= m->frame_y && y < m->frame_y + MENUH(m)) {
|
||||
*deepest_p = m;
|
||||
*dx_p = x - m->frame_x;
|
||||
*dy_p = y - m->frame_y - m->frame->top_width;
|
||||
}
|
||||
if (m->brother)
|
||||
findMenuWalk(m->brother, x, y, deepest_p, dx_p, dy_p);
|
||||
for (int i = 0; i < m->cascade_no; i++)
|
||||
findMenuWalk(m->cascades[i], x, y, deepest_p, dx_p, dy_p);
|
||||
}
|
||||
|
||||
static WMenu *findMenu(WScreen * scr, int *x_ret, int *y_ret)
|
||||
{
|
||||
WMenu *menu;
|
||||
int x, y;
|
||||
WMenu *deepest = NULL;
|
||||
int dx = 0, dy = 0;
|
||||
|
||||
wm_backend->pointer_get_position(&x, &y);
|
||||
|
||||
/* Helper: check if (x,y) is inside a mapped menu */
|
||||
#define CHECK_MENU(m) do { \
|
||||
if ((m) && (m)->flags.mapped && \
|
||||
x >= (m)->frame_x && x < (m)->frame_x + MENUW(m) && \
|
||||
y >= (m)->frame_y && y < (m)->frame_y + MENUH(m)) { \
|
||||
*x_ret = x - (m)->frame_x; \
|
||||
*y_ret = y - (m)->frame_y - (m)->frame->top_width; \
|
||||
return (m); \
|
||||
} \
|
||||
} while(0)
|
||||
findMenuWalk(scr->root_menu, x, y, &deepest, &dx, &dy);
|
||||
findMenuWalk(scr->switch_menu, x, y, &deepest, &dx, &dy);
|
||||
findMenuWalk(scr->window_menu, x, y, &deepest, &dx, &dy);
|
||||
findMenuWalk(scr->dock ? scr->dock->menu : NULL,
|
||||
x, y, &deepest, &dx, &dy);
|
||||
findMenuWalk(scr->clip_menu, x, y, &deepest, &dx, &dy);
|
||||
findMenuWalk(scr->dock_pos_menu, x, y, &deepest, &dx, &dy);
|
||||
|
||||
/* Check root menu, its brother, and cascades */
|
||||
menu = scr->root_menu;
|
||||
if (menu) {
|
||||
CHECK_MENU(menu);
|
||||
CHECK_MENU(menu->brother);
|
||||
for (int i = 0; i < menu->cascade_no; i++) {
|
||||
CHECK_MENU(menu->cascades[i]);
|
||||
if (menu->cascades[i])
|
||||
CHECK_MENU(menu->cascades[i]->brother);
|
||||
}
|
||||
if (deepest) {
|
||||
*x_ret = dx;
|
||||
*y_ret = dy;
|
||||
return deepest;
|
||||
}
|
||||
|
||||
/* Check switch menu */
|
||||
menu = scr->switch_menu;
|
||||
CHECK_MENU(menu);
|
||||
if (menu) CHECK_MENU(menu->brother);
|
||||
|
||||
/* Check window menu */
|
||||
menu = scr->window_menu;
|
||||
if (menu) {
|
||||
CHECK_MENU(menu);
|
||||
CHECK_MENU(menu->brother);
|
||||
for (int i = 0; i < menu->cascade_no; i++) {
|
||||
CHECK_MENU(menu->cascades[i]);
|
||||
if (menu->cascades[i])
|
||||
CHECK_MENU(menu->cascades[i]->brother);
|
||||
}
|
||||
}
|
||||
|
||||
/* Check dock menu */
|
||||
menu = scr->dock ? scr->dock->menu : NULL;
|
||||
if (menu) {
|
||||
CHECK_MENU(menu);
|
||||
for (int i = 0; i < menu->cascade_no; i++)
|
||||
CHECK_MENU(menu->cascades[i]);
|
||||
}
|
||||
|
||||
/* Check clip menu */
|
||||
menu = scr->clip_menu;
|
||||
if (menu) {
|
||||
CHECK_MENU(menu);
|
||||
for (int i = 0; i < menu->cascade_no; i++)
|
||||
CHECK_MENU(menu->cascades[i]);
|
||||
}
|
||||
|
||||
/* Check dock position menu */
|
||||
CHECK_MENU(scr->dock_pos_menu);
|
||||
|
||||
#undef CHECK_MENU
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
|
|
|||
Loading…
Reference in New Issue