commit e79be7617b0bb040138bb79184d3b7e0142a2db0
parent 5a48a8a830b1f2086901ecf8056f6525525b5d90
Author: Lucas de Sena <lucas@seninha.org>
Date: Mon, 16 Jan 2023 21:24:09 -0300
add shodc cycle
Diffstat:
M | shod.1 | | | 58 | +++++++++++++++++++++++++++++++++------------------------- |
M | shod.c | | | 7 | ++----- |
M | shodc.c | | | 33 | +++++++++++++++++++++++++++++++++ |
M | xevents.c | | | 41 | +++++++++++++---------------------------- |
M | xutil.c | | | 1 | + |
M | xutil.h | | | 1 | + |
6 files changed, 83 insertions(+), 58 deletions(-)
diff --git a/shod.1 b/shod.1
@@ -7,7 +7,7 @@
.Nd mouse-focused window manager
.Sh SYNOPSIS
.Nm shod
-.Op Fl cdhst
+.Op Fl cdhs
.Op Fl m Ar keysym
.Op Ar file
.Pp
@@ -15,6 +15,11 @@
.Cm close
.Op Ar win_id
.Nm shodc
+.Cm cycle
+.Op Fl s
+.Op Fl a Ar altkey
+.Op Fl t Ar tabkey
+.Nm shodc
.Cm desk
.Nm shodc
.Cm focus
@@ -119,9 +124,6 @@ or
on most systems).
.It Fl s
Use sloppy focus rather than click-to-focus.
-.It Fl t
-Disable container cycling (aka
-.Dq "alt-tab" No ).
.El
.Pp
.Nm shodc
@@ -140,6 +142,33 @@ The
.Cm close
operation closes a window whose ID is provided as argument.
If no argument is provided, close the active window.
+.Ss Cycle containers
+The
+.Cm cycle
+operation cycles through the open containers on the current desktop.
+This cycling is generally called
+.Qq "Alt-Tab"
+and is initiated by pressing a key (usually
+.Qq "Tab" )
+while a modifier key (usually
+.Qq "Alt_L" )
+is pressed.
+If the
+.Qq "Shift"
+modifier is also pressed, the cycling is performed in the opposite direction.
+.Pp The options are as follows.
+.Bl -tag -width Ds
+.It Fl a Ar altkey
+Use the key
+.Ar altkey
+as Alt.
+.It Fl s
+Initiate the cycling in the opposite direction.
+.It Fl t Ar tabkey
+Use the key
+.Ar tabkey
+as Tab.
+.El
.Ss List desktops
The
.Cm desks
@@ -491,27 +520,6 @@ or undoes this state.
Each title bar has a right button.
Clicking on the right title-bar button with the first mouse button
closes the focused client or its top dialog.
-.Pp
-Containers can be cycled using the key provided by the
-.Fl m
-option
-.No ( Cm Alt_L
-by default) followed by the
-.Cm Tab
-key.
-The
-.Cm Tab
-key can be further modified by
-.Cm Shift
-to cycle in the oposite direction.
-This mechanism is usually called
-.Dq "alt-tab"
-because of the key combination that usually triggers it.
-This mechanism can be turned off by invoking
-.Nm shod
-with the
-.Fl t
-command-line option.
.Ss Dialog
Windows that are transient for another managed windows (called its leader)
are mapped in the center of the leader.
diff --git a/shod.c b/shod.c
@@ -35,7 +35,7 @@ struct Dock dock;
static void
usage(void)
{
- (void)fprintf(stderr, "usage: shod [-cdhst] [-m modifier] [file]\n");
+ (void)fprintf(stderr, "usage: shod [-cdhs] [-m modifier] [file]\n");
exit(1);
}
@@ -119,7 +119,7 @@ getoptions(int argc, char *argv[])
{
int c;
- while ((c = getopt(argc, argv, "cdhm:st")) != -1) {
+ while ((c = getopt(argc, argv, "cdhm:s")) != -1) {
switch (c) {
case 'c':
config.honorconfig = 1;
@@ -137,9 +137,6 @@ getoptions(int argc, char *argv[])
case 's':
config.sloppyfocus = 1;
break;
- case 't':
- config.disablealttab = 1;
- break;
default:
usage();
break;
diff --git a/shodc.c b/shodc.c
@@ -589,6 +589,37 @@ state(int argc, char *argv[])
clientmsg(win, atoms[_NET_WM_STATE], action, state1, state2, DIRECT_ACTION, 0);
}
+/* cycle containers */
+static void
+cycle(int argc, char *argv[])
+{
+ KeyCode alt, tab;
+ KeySym ksym;
+ int c, shift;
+
+ alt = XKeysymToKeycode(dpy, XK_Alt_L);
+ tab = XKeysymToKeycode(dpy, XK_Tab);
+ shift = 0;
+ while ((c = getopt(argc, argv, "a:st:")) != -1) {
+ switch (c) {
+ case 'a':
+ if ((ksym = XStringToKeysym(optarg)) == NoSymbol)
+ errx(1, "%s: unknown key", optarg);
+ alt = XKeysymToKeycode(dpy, ksym);
+ break;
+ case 's':
+ shift = 1;
+ break;
+ case 't':
+ if ((ksym = XStringToKeysym(optarg)) == NoSymbol)
+ errx(1, "%s: unknown key", optarg);
+ tab = XKeysymToKeycode(dpy, ksym);
+ break;
+ }
+ }
+ clientmsg(None, atoms[_SHOD_CYCLE], alt, tab, shift, 0, 0);
+}
+
/* shodc: remote controller for shod */
int
main(int argc, char *argv[])
@@ -615,6 +646,8 @@ main(int argc, char *argv[])
sendto(argc - 1, argv + 1);
else if (strcmp(argv[1], "state") == 0)
state(argc - 1, argv + 1);
+ else if (strcmp(argv[1], "cycle") == 0)
+ cycle(argc - 1, argv + 1);
else
usage();
diff --git a/xevents.c b/xevents.c
@@ -699,52 +699,48 @@ manage(Window win, XRectangle rect, int ignoreunmap)
/* perform container switching (aka alt-tab) */
static void
-alttab(XEvent *e)
+alttab(KeyCode alt, KeyCode tab, int shift)
{
struct Container *c, *prevfocused;
XEvent ev;
- int raised;
prevfocused = wm.focused;
if ((c = TAILQ_FIRST(&wm.focusq)) == NULL)
return;
- ev = *e;
- raised = 0;
if (XGrabKeyboard(dpy, root, True, GrabModeAsync, GrabModeAsync, CurrentTime) != GrabSuccess)
goto done;
if (XGrabPointer(dpy, root, False, 0, GrabModeAsync, GrabModeAsync, None, None, CurrentTime) != GrabSuccess)
goto done;
- do {
+ containerbacktoplace(c, 0);
+ c = containerraisetemp(c, shift);
+ while (!XMaskEvent(dpy, ALTTABMASK, &ev)) {
switch (ev.type) {
case Expose:
if (ev.xexpose.count == 0)
copypixmap(ev.xexpose.window);
break;
case KeyPress:
- if (ev.xkey.keycode == config.tabkeycode && isvalidstate(ev.xkey.state)) {
- containerbacktoplace(c, raised);
+ if (ev.xkey.keycode == tab && isvalidstate(ev.xkey.state)) {
+ containerbacktoplace(c, 1);
c = containerraisetemp(c, isshiftstate(ev.xkey.state));
- raised = 1;
} else if (!isvalidstate(ev.xkey.state)) {
goto done;
}
break;
case KeyRelease:
- if (ev.xkey.keycode == config.altkeycode || !isvalidstate(ev.xkey.state))
+ if (ev.xkey.keycode == config.altkeycode || ev.xkey.keycode == alt || !isvalidstate(ev.xkey.state))
goto done;
break;
}
- } while (!XMaskEvent(dpy, ALTTABMASK, &ev));
+ }
done:
XUngrabKeyboard(dpy, CurrentTime);
XUngrabPointer(dpy, CurrentTime);
if (c == NULL)
return;
- if (raised) {
- containerbacktoplace(c, raised);
- wm.focused = prevfocused;
- tabfocus(c->selcol->selrow->seltab, 0);
- }
+ containerbacktoplace(c, 1);
+ wm.focused = prevfocused;
+ tabfocus(c->selcol->selrow->seltab, 0);
}
/* detach tab from window with mouse */
@@ -1395,6 +1391,8 @@ xeventclientmessage(XEvent *e)
}
if (ev->message_type == atoms[_NET_CURRENT_DESKTOP]) {
deskfocus(wm.selmon, ev->data.l[0]);
+ } else if (ev->message_type == atoms[_SHOD_CYCLE]) {
+ alttab(ev->data.l[0], ev->data.l[1], ev->data.l[2]);
} else if (ev->message_type == atoms[_NET_SHOWING_DESKTOP]) {
if (ev->data.l[0]) {
deskshow(1);
@@ -1663,9 +1661,6 @@ xeventkeypress(XEvent *e)
XKeyPressedEvent *ev;
ev = &e->xkey;
- if (!config.disablealttab && ev->keycode == config.tabkeycode) {
- alttab(e);
- }
if (ev->window == wm.wmcheckwin) {
e->xkey.window = root;
XSendEvent(dpy, root, False, KeyPressMask, e);
@@ -1832,20 +1827,10 @@ setmod(void)
warnx("could not get keycode from keysym");
return;
}
- if ((config.tabkeycode = XKeysymToKeycode(dpy, config.tabkeysym)) == 0) {
- warnx("could not get keycode from keysym");
- return;
- }
if ((config.modifier = XkbKeysymToModifiers(dpy, config.altkeysym)) == 0) {
warnx("could not get modifier from keysym");
return;
}
- if (config.disablealttab)
- return;
- XUngrabKey(dpy, config.tabkeycode, config.modifier, root);
- XUngrabKey(dpy, config.tabkeycode, config.modifier | config.shift, root);
- XGrabKey(dpy, config.tabkeycode, config.modifier, root, False, GrabModeAsync, GrabModeAsync);
- XGrabKey(dpy, config.tabkeycode, config.modifier | config.shift, root, False, GrabModeAsync, GrabModeAsync);
}
void (*xevents[LASTEvent])(XEvent *) = {
diff --git a/xutil.c b/xutil.c
@@ -55,6 +55,7 @@ static char *atomnames[ATOM_LAST] = {
[_NET_FRAME_EXTENTS] = "_NET_FRAME_EXTENTS",
[_NET_WM_FULL_PLACEMENT] = "_NET_WM_FULL_PLACEMENT",
[_MOTIF_WM_HINTS] = "_MOTIF_WM_HINTS",
+ [_SHOD_CYCLE] = "_SHOD_CYCLE",
[_SHOD_GROUP_TAB] = "_SHOD_GROUP_TAB",
[_SHOD_GROUP_CONTAINER] = "_SHOD_GROUP_CONTAINER",
[_SHOD_CONTAINER_LIST] = "_SHOD_CONTAINER_LIST",
diff --git a/xutil.h b/xutil.h
@@ -66,6 +66,7 @@ enum {
_MOTIF_WM_HINTS,
/* shod atoms */
+ _SHOD_CYCLE,
_SHOD_GROUP_TAB,
_SHOD_GROUP_CONTAINER,
_SHOD_CONTAINER_LIST,