From 60ddf397e389f25f0a038548d9c808c83d815ba7 Mon Sep 17 00:00:00 2001 From: phillbush Date: Sat, 13 Feb 2021 20:36:55 -0300 Subject: [PATCH] add support for mouse scrolling (#26) --- xmenu.1 | 1 - xmenu.c | 93 ++++++++++++++++++++++++++++++++++++++++----------------- xmenu.h | 1 + 3 files changed, 66 insertions(+), 29 deletions(-) diff --git a/xmenu.1 b/xmenu.1 index 82a6ebb..7b14eea 100644 --- a/xmenu.1 +++ b/xmenu.1 @@ -190,7 +190,6 @@ or .BR "\(dqright\(dq" , text is aligned to the left, center, or right of the menu, respectively. By default, text is aligned to the left. - .SH EXAMPLES The following script illustrates the use of .BR xmenu . diff --git a/xmenu.c b/xmenu.c index 8658a9d..afb4301 100644 --- a/xmenu.c +++ b/xmenu.c @@ -1129,17 +1129,37 @@ itemcycle(struct Menu *currmenu, int direction) return item; } +/* check if button is used to scroll */ +static int +isscrollbutton(unsigned int button) +{ + if (button == Button4 || button == Button5) + return 1; + return 0; +} + /* check if button is used to open a item on click */ static int isclickbutton(unsigned int button) { - if (button == Button1) + if (button == Button1 || button == Button2) return 1; if (!rflag && button == Button3) return 1; return 0; } +/* warp pointer to center of selected item */ +static void +warppointer(struct Menu *menu, struct Item *item) +{ + if (menu == NULL || item == NULL) + return; + if (menu->selected) { + XWarpPointer(dpy, None, menu->win, 0, 0, 0, 0, menu->w / 2, item->y + item->h / 2); + } +} + /* append buf into text */ static int append(char *text, char *buf, size_t textsize, size_t buflen) @@ -1240,6 +1260,7 @@ run(struct Menu *currmenu) KeySym ksym; Status status; XEvent ev; + int warped = 0; int action; int len; int i; @@ -1256,38 +1277,50 @@ run(struct Menu *currmenu) action = ACTION_DRAW; break; case MotionNotify: - menu = getmenu(currmenu, ev.xbutton.window); - item = getitem(menu, ev.xbutton.y); - if (menu == NULL || item == NULL || previtem == item) - break; - previtem = item; - select = menu->selected = item; - if (item->submenu != NULL) { - currmenu = item->submenu; - select = NULL; - } else { - currmenu = menu; + if (!warped) { + menu = getmenu(currmenu, ev.xbutton.window); + item = getitem(menu, ev.xbutton.y); + if (menu == NULL || item == NULL || previtem == item) + break; + previtem = item; + select = menu->selected = item; + if (item->submenu != NULL) { + currmenu = item->submenu; + select = NULL; + } else { + currmenu = menu; + } + action = ACTION_CLEAR | ACTION_SELECT | ACTION_MAP | ACTION_DRAW; } - action = ACTION_CLEAR | ACTION_SELECT | ACTION_MAP | ACTION_DRAW; + warped = 0; break; case ButtonRelease: - if (!isclickbutton(ev.xbutton.button)) - break; - menu = getmenu(currmenu, ev.xbutton.window); - item = getitem(menu, ev.xbutton.y); - if (menu == NULL || item == NULL) - break; + if (isscrollbutton(ev.xbutton.button)) { + if (ev.xbutton.button == Button4) + select = itemcycle(currmenu, ITEMPREV); + else + select = itemcycle(currmenu, ITEMNEXT); + action = ACTION_CLEAR | ACTION_SELECT | ACTION_DRAW | ACTION_WARP; + } else if (isclickbutton(ev.xbutton.button)) { + menu = getmenu(currmenu, ev.xbutton.window); + item = getitem(menu, ev.xbutton.y); + if (menu == NULL || item == NULL) + break; enteritem: - if (item->label == NULL) - break; /* ignore separators */ - if (item->submenu != NULL) { - currmenu = item->submenu; - } else { - printf("%s\n", item->output); - return; + if (item->label == NULL) + break; /* ignore separators */ + if (item->submenu != NULL) { + currmenu = item->submenu; + } else { + printf("%s\n", item->output); + return; + } + select = currmenu->list; + action = ACTION_CLEAR | ACTION_SELECT | ACTION_MAP | ACTION_DRAW; + if (ev.xbutton.button == Button2) { + action |= ACTION_WARP; + } } - select = currmenu->list; - action = ACTION_CLEAR | ACTION_SELECT | ACTION_MAP | ACTION_DRAW; break; case ButtonPress: menu = getmenu(currmenu, ev.xbutton.window); @@ -1419,6 +1452,10 @@ append: mapmenu(currmenu); if (action & ACTION_DRAW) drawmenus(currmenu); + if (action & ACTION_WARP) { + warppointer(currmenu, select); + warped = 1; + } } } diff --git a/xmenu.h b/xmenu.h index b5f1556..5e369a2 100644 --- a/xmenu.h +++ b/xmenu.h @@ -6,6 +6,7 @@ #define ACTION_SELECT 1<<1 /* select item */ #define ACTION_MAP 1<<2 /* remap menu windows */ #define ACTION_DRAW 1<<3 /* redraw menu windows */ +#define ACTION_WARP 1<<4 /* warp the pointer */ /* enum for keyboard menu navigation */ enum { ITEMPREV, ITEMNEXT, ITEMFIRST, ITEMLAST };