From 97960d7d24246dcb8499f0f313fcbe846e01e32d Mon Sep 17 00:00:00 2001 From: phillbush Date: Sun, 9 May 2021 17:24:11 -0300 Subject: [PATCH] revert -r remotion; fix mouse control --- pmenu.1 | 41 +++++++- pmenu.c | 285 +++++++++++++++++++++++++++++++++++--------------------- 2 files changed, 220 insertions(+), 106 deletions(-) diff --git a/pmenu.1 b/pmenu.1 index 8c4a125..3596da5 100644 --- a/pmenu.1 +++ b/pmenu.1 @@ -3,7 +3,11 @@ pmenu \- pie menu utility for X .SH SYNOPSIS .B pmenu -.RB [ \-tw ] +.RB [ \-ptw ] +.RB [ \-m +.IR modifier ] +.RB [ \-r +.IR button ] .SH DESCRIPTION .B pmenu is a pie menu for X, @@ -14,6 +18,41 @@ The pie menu contains one slice for each item. .PP The options are as follows: .TP +.BI "\-m " modifier +Use the button click specified by the +.B \-r +option with the given modifier number to spawn the pie menu. +For example, if calling pmenu with the +.B -r 3 -m 4 +options, +the pie menu will be displayed when clicking any window with the right mouse button +and the Mod4 modifier (usually the Super key). +this option only makes sense when +.B \-r +is used. +.TP +.B \-p +When +.B \-r +is used, pass the click to the root window, +for the window manage to use it, for example. +This option only makes sense when +.B \-r +is used. +.TP +.B \-r +When this option is used, +.B pmenu +listens to button presses on the root window, +and shows the pie menu when the button (a number between 1 and 3) is pressed on the root window. +This option makes +.B menu +run continuously, +so it should be run in background on a X startup file (like +.BR "~/.xinitrc" , +.BR "~/.xprofile" , +etc). +.TP .B \-t Draw a triangle on the border of slices that spawn a submenu. .TP diff --git a/pmenu.c b/pmenu.c index dfdcfe6..54d13c7 100644 --- a/pmenu.c +++ b/pmenu.c @@ -33,8 +33,12 @@ static struct Monitor mon; static struct Pie pie; /* flags */ +static int rflag = 0; /* wheter to run in root mode */ +static int pflag = 0; /* whether to pass click to root window */ static int tflag = 0; /* whether to draw triangle for submenus */ static int wflag = 0; /* whether to disable pointer warping */ +static unsigned int button; /* button to trigger pmenu in root mode */ +static unsigned int modifier; /* modifier to trigger pmenu */ #include "config.h" @@ -42,7 +46,7 @@ static int wflag = 0; /* whether to disable pointer warping */ static void usage(void) { - (void)fprintf(stderr, "usage: pmenu [-w]\n"); + (void)fprintf(stderr, "usage: pmenu [-ptw] [-m modifier] [-r button]\n"); exit(1); } @@ -83,8 +87,46 @@ getoptions(int *argc, char ***argv) { int ch; - while ((ch = getopt(*argc, *argv, "tw")) != -1) { + while ((ch = getopt(*argc, *argv, "m:pr:tw")) != -1) { switch (ch) { + case 'm': + switch (*optarg) { + default: + case '1': + modifier = Mod1Mask; + break; + case '2': + modifier = Mod2Mask; + break; + case '3': + modifier = Mod3Mask; + break; + case '4': + modifier = Mod4Mask; + break; + case '5': + modifier = Mod5Mask; + break; + } + break; + case 'p': + pflag = 1; + break; + case 'r': + rflag = 1; + switch (*optarg) { + case '1': + button = Button1; + break; + case '2': + button = Button2; + break; + default: + case '3': + button = Button3; + break; + } + break; case 't': tflag = 1; break; @@ -1140,118 +1182,147 @@ run(struct Menu *rootmenu) struct Slice *slice = NULL; KeySym ksym; XEvent ev; - - getmonitor(); - prevmenu = NULL; - currmenu = rootmenu; - grabpointer(); - grabkeyboard(); - placemenu(currmenu); - prevmenu = mapmenu(currmenu, prevmenu); - while (!XNextEvent(dpy, &ev)) { - switch (ev.type) { - case Expose: - if (ev.xexpose.count == 0) + int mapped = 0; + + if (!rflag) { + getmonitor(); + prevmenu = NULL; + currmenu = rootmenu; + grabpointer(); + grabkeyboard(); + placemenu(currmenu); + prevmenu = mapmenu(currmenu, prevmenu); + XWarpPointer(dpy, None, currmenu->win, 0, 0, 0, 0, pie.radius, pie.radius); + } + do { + while (!XNextEvent(dpy, &ev)) { + if (rflag && !mapped && ev.type == ButtonPress) { + if (ev.xbutton.state == modifier || ev.xbutton.subwindow == None) { + if (pflag && ev.xbutton.state == 0) + XAllowEvents(dpy, ReplayPointer, CurrentTime); + mapped = 1; + getmonitor(); + prevmenu = NULL; + currmenu = rootmenu; + grabpointer(); + grabkeyboard(); + placemenu(currmenu); + prevmenu = mapmenu(currmenu, prevmenu); + XWarpPointer(dpy, None, currmenu->win, 0, 0, 0, 0, pie.radius, pie.radius); + } else { + XAllowEvents(dpy, ReplayPointer, CurrentTime); + } + continue; + } + switch (ev.type) { + case Expose: + if (ev.xexpose.count == 0) + copymenu(currmenu); + break; + case EnterNotify: + menu = getmenu(currmenu, ev.xcrossing.window); + if (menu == NULL) + break; + prevmenu = mapmenu(currmenu, prevmenu); copymenu(currmenu); - break; - case EnterNotify: - menu = getmenu(currmenu, ev.xcrossing.window); - if (menu == NULL) break; - prevmenu = mapmenu(currmenu, prevmenu); - copymenu(currmenu); - break; - case LeaveNotify: - menu = getmenu(currmenu, ev.xcrossing.window); - if (menu == NULL) + case LeaveNotify: + menu = getmenu(currmenu, ev.xcrossing.window); + if (menu == NULL) + break; + if (menu != rootmenu && menu == currmenu) { + currmenu = currmenu->parent; + prevmenu = mapmenu(currmenu, prevmenu); + } + currmenu->selected = NULL; + copymenu(currmenu); break; - if (menu != rootmenu && menu == currmenu) { - currmenu = currmenu->parent; + case MotionNotify: + menu = getmenu(currmenu, ev.xbutton.window); + slice = getslice(menu, ev.xbutton.x, ev.xbutton.y); + if (menu == NULL) + break; + else if (slice == NULL) + menu->selected = NULL; + else + menu->selected = slice; + copymenu(currmenu); + break; + case ButtonRelease: + if (ev.xbutton.button != Button1 && ev.xbutton.button != Button3) + break; + menu = getmenu(currmenu, ev.xbutton.window); + slice = getslice(menu, ev.xbutton.x, ev.xbutton.y); + if (menu == NULL || slice == NULL) + break; + selectslice: + if (slice->submenu) { + currmenu = slice->submenu; + } else { + printf("%s\n", slice->output); + fflush(stdout); + goto done; + } prevmenu = mapmenu(currmenu, prevmenu); - } - currmenu->selected = NULL; - copymenu(currmenu); - break; - case MotionNotify: - menu = getmenu(currmenu, ev.xbutton.window); - slice = getslice(menu, ev.xbutton.x, ev.xbutton.y); - if (menu == NULL) + currmenu->selected = NULL; + copymenu(currmenu); + if (!wflag) + XWarpPointer(dpy, None, currmenu->win, 0, 0, 0, 0, pie.radius, pie.radius); break; - else if (slice == NULL) - menu->selected = NULL; - else - menu->selected = slice; - copymenu(currmenu); - break; - case ButtonRelease: - menu = getmenu(currmenu, ev.xbutton.window); - slice = getslice(menu, ev.xbutton.x, ev.xbutton.y); - if (menu == NULL || slice == NULL) + case ButtonPress: + if (ev.xbutton.button != Button1 && ev.xbutton.button != Button3) + break; + menu = getmenu(currmenu, ev.xbutton.window); + slice = getslice(menu, ev.xbutton.x, ev.xbutton.y); + if (menu == NULL || slice == NULL) + goto done; break; -selectslice: - if (slice->submenu) { - currmenu = slice->submenu; - } else { - printf("%s\n", slice->output); - fflush(stdout); - goto done; - } - prevmenu = mapmenu(currmenu, prevmenu); - currmenu->selected = NULL; - copymenu(currmenu); - if (!wflag) - XWarpPointer(dpy, None, currmenu->win, 0, 0, 0, 0, pie.radius, pie.radius); - break; - case ButtonPress: - menu = getmenu(currmenu, ev.xbutton.window); - slice = getslice(menu, ev.xbutton.x, ev.xbutton.y); - if (menu == NULL || slice == NULL) - goto done; - break; - case KeyPress: - ksym = XkbKeycodeToKeysym(dpy, ev.xkey.keycode, 0, 0); - - /* esc closes pmenu when current menu is the root menu */ - if (ksym == XK_Escape && currmenu->parent == NULL) - goto done; - - /* Shift-Tab = ISO_Left_Tab */ - if (ksym == XK_Tab && (ev.xkey.state & ShiftMask)) - ksym = XK_ISO_Left_Tab; - - /* cycle through menu */ - slice = NULL; - if (ksym == XK_Tab) { - slice = slicecycle(currmenu, 1); - } else if (ksym == XK_ISO_Left_Tab) { - slice = slicecycle(currmenu, 0); - } else if ((ksym == XK_Return) && - currmenu->selected != NULL) { - slice = currmenu->selected; - goto selectslice; - } else if ((ksym == XK_Escape) && - currmenu->parent != NULL) { - slice = currmenu->parent->selected; - currmenu = currmenu->parent; - prevmenu = mapmenu(currmenu, prevmenu); - } else + case KeyPress: + ksym = XkbKeycodeToKeysym(dpy, ev.xkey.keycode, 0, 0); + + /* esc closes pmenu when current menu is the root menu */ + if (ksym == XK_Escape && currmenu->parent == NULL) + goto done; + + /* Shift-Tab = ISO_Left_Tab */ + if (ksym == XK_Tab && (ev.xkey.state & ShiftMask)) + ksym = XK_ISO_Left_Tab; + + /* cycle through menu */ + slice = NULL; + if (ksym == XK_Tab) { + slice = slicecycle(currmenu, 1); + } else if (ksym == XK_ISO_Left_Tab) { + slice = slicecycle(currmenu, 0); + } else if ((ksym == XK_Return) && + currmenu->selected != NULL) { + slice = currmenu->selected; + goto selectslice; + } else if ((ksym == XK_Escape) && + currmenu->parent != NULL) { + slice = currmenu->parent->selected; + currmenu = currmenu->parent; + prevmenu = mapmenu(currmenu, prevmenu); + } else + break; + currmenu->selected = slice; + copymenu(currmenu); break; - currmenu->selected = slice; - copymenu(currmenu); - break; - case ConfigureNotify: - menu = getmenu(currmenu, ev.xconfigure.window); - if (menu == NULL) + case ConfigureNotify: + menu = getmenu(currmenu, ev.xconfigure.window); + if (menu == NULL) + break; + menu->x = ev.xconfigure.x; + menu->y = ev.xconfigure.y; break; - menu->x = ev.xconfigure.x; - menu->y = ev.xconfigure.y; - break; + } } - } -done: - unmapmenu(currmenu); - ungrab(); - XFlush(dpy); + done: + mapped = 0; + unmapmenu(currmenu); + ungrab(); + XFlush(dpy); + } while (rflag); } /* recursivelly free pixmaps and destroy windows */ @@ -1343,6 +1414,10 @@ main(int argc, char *argv[]) initdc(); initpie(); + /* if running in root mode, get button presses from root window */ + if (rflag) + XGrabButton(dpy, button, AnyModifier, rootwin, False, ButtonPressMask, GrabModeSync, GrabModeSync, None, None); + /* generate menus and set them up */ rootmenu = parsestdin(); if (rootmenu == NULL)