Re: [wiki] [sites] add alt-tab functionality patch for dwm || ViliamKovac1223

From: Tom Schwindl <schwindl_AT_posteo.de>
Date: Sat, 9 Jul 2022 14:47:48 +0000

Hi Viliam,

> + /* See LICENSE file for copyright and license details. */
> +
> ++/* alt-tab configuration */
> ++static const unsigned int tabModKey = 0x40; /* if this key is hold the alt-tab functionality stays acitve. This key must be the same as key that is used to active functin altTabStart `*/
> ++static const unsigned int tabCycleKey = 0x17; /* if this key is hit the alt-tab program moves one position forward in clients stack. This key must be the same as key that is used to active functin altTabStart */
> ++static const unsigned int tabPosY = 1; /* tab position on Y axis, 0 = bottom, 1 = center, 2 = top */
> ++static const unsigned int tabPosX = 1; /* tab position on X axis, 0 = left, 1 = center, 2 = right */
> ++static const unsigned int maxWTab = 600; /* tab menu width */
> ++static const unsigned int maxHTab = 200; /* tab menu height */

Some typos and a trailing \` character in here. Nothing too bad.

> +_AT_@ -234,6 +242,9 @@ static int xerror(Display *dpy, XErrorEvent *ee);
> + static int xerrordummy(Display *dpy, XErrorEvent *ee);
> + static int xerrorstart(Display *dpy, XErrorEvent *ee);
> + static void zoom(const Arg *arg);
> ++void drawTab(int nwins, int first, Monitor *m);
> ++void altTabStart(const Arg *arg);
> ++static void altTabEnd();

The prototype for altTab() is missing.
Is there a reason drawTab() and altTabStart() aren't declared static?

Also, please do not use the legacy way of declaring functions without arguments
as `f()`, use `f(void)` instead.

> + /* variables */
> + static const char broken[] = "broken";
> +_AT_@ -477,6 +488,7 @@ cleanup(void)
> + Monitor *m;
> + size_t i;
> +
> ++ altTabEnd();
> + view(&a);
> + selmon->lt[selmon->sellt] = &foo;
> + for (m = mons; m; m = m->next)
> +_AT_@ -644,6 +656,7 @@ createmon(void)
> + m->topbar = topbar;
> + m->lt[0] = &layouts[0];
> + m->lt[1] = &layouts[1 % LENGTH(layouts)];
> ++ m->nTabs = 0;
> + strncpy(m->ltsymbol, layouts[0].symbol, sizeof m->ltsymbol);
> + return m;
> + }
> +_AT_@ -1659,6 +1672,211 @@ spawn(const Arg *arg)
> + }
> + }
> +
> ++void
> ++altTab()
> ++{
> ++ /* move to next window */
> ++ if (selmon->sel != NULL && selmon->sel->snext != NULL) {
> ++ selmon->altTabN++;
> ++ if (selmon->altTabN >= selmon->nTabs)
> ++ selmon->altTabN = 0; /* reset altTabN */
> ++
> ++ focus(selmon->altsnext[selmon->altTabN]);
> ++ restack(selmon);
> ++ }
> ++
> ++ /* redraw tab */
> ++ XRaiseWindow(dpy, selmon->tabwin);
> ++ drawTab(selmon->nTabs, 0, selmon);
> ++}
> ++
> ++void
> ++altTabEnd()
> ++{
> ++ if (selmon->isAlt == 0)
> ++ return;
> ++
> ++ /*
> ++ * move all clients between 1st and choosen position,
> ++ * one down in stack and put choosen client to the first position
> ++ * so they remain in right order for the next time that alt-tab is used
> ++ */

It should be "chosen" instead of "choosen" and I'm unsure if this comment is necessary.

> ++ if (selmon->nTabs > 1) {
> ++ if (selmon->altTabN != 0) { /* if user picked original client do nothing */
> ++ Client *buff = selmon->altsnext[selmon->altTabN];
> ++ if (selmon->altTabN > 1)
> ++ for (int i = selmon->altTabN;i > 0;i--)
> ++ selmon->altsnext[i] = selmon->altsnext[i - 1];
> ++ else /* swap them if there are just 2 clients */
> ++ selmon->altsnext[selmon->altTabN] = selmon->altsnext[0];
> ++ selmon->altsnext[0] = buff;
> ++ }
> ++
> ++ /* restack clients */
> ++ for (int i = selmon->nTabs - 1;i >= 0;i--) {
> ++ focus(selmon->altsnext[i]);
> ++ restack(selmon);
> ++ }
> ++
> ++ free(selmon->altsnext); /* free list of clients */
> ++ }
> ++
> ++ /* turn off/destroy the window */
> ++ selmon->isAlt = 0;
> ++ selmon->nTabs = 0;
> ++ XUnmapWindow(dpy, selmon->tabwin);
> ++ XDestroyWindow(dpy, selmon->tabwin);
> ++}
> ++
> ++void
> ++drawTab(int nwins, int first, Monitor *m)
> ++{
> ++ /* little documentation of functions */
> ++ /* void drw_rect(Drw *drw, int x, int y, unsigned int w, unsigned int h, int filled, int invert); */
> ++ /* int drw_text(Drw *drw, int x, int y, unsigned int w, unsigned int h, unsigned int lpad, const char *text, int invert); */
> ++ /* void drw_map(Drw *drw, Window win, int x, int y, unsigned int w, unsigned int h); */

What is this comment supposed to document? I don't see a reason to leave it here.

> ++ Client *c;
> ++ int h;
> ++
> ++ if (first) {
> ++ Monitor *m = selmon;
> ++ XSetWindowAttributes wa = {
> ++ .override_redirect = True,
> ++ .background_pixmap = ParentRelative,
> ++ .event_mask = ButtonPressMask|ExposureMask
> ++ };
> ++
> ++ selmon->maxWTab = maxWTab;
> ++ selmon->maxHTab = maxHTab;
> ++
> ++ /* decide position of tabwin */
> ++ int posX = 0;
> ++ int posY = 0;
> ++ if (tabPosX == 0)
> ++ posX = 0;
> ++ if (tabPosX == 1)
> ++ posX = (selmon->mw / 2) - (maxWTab / 2);
> ++ if (tabPosX == 2)
> ++ posX = selmon->mw - maxWTab;
> ++
> ++ if (tabPosY == 0)
> ++ posY = selmon->mh - maxHTab;
> ++ if (tabPosY == 1)
> ++ posY = (selmon->mh / 2) - (maxHTab / 2);
> ++ if (tabPosY == 2)
> ++ posY = 0;

`else if` is more appropriate than `if` in this case.

> ++
> ++ h = selmon->maxHTab;
> ++ /* XCreateWindow(display, parent, x, y, width, height, border_width, depth, class, visual, valuemask, attributes); just reference */

Use the manpage of XCreateWindow(3) as a reference, not a comment in the code.

> ++ m->tabwin = XCreateWindow(dpy, root, posX, posY, selmon->maxWTab, selmon->maxHTab, 2, DefaultDepth(dpy, screen),
> ++ CopyFromParent, DefaultVisual(dpy, screen),
> ++ CWOverrideRedirect|CWBackPixmap|CWEventMask, &wa); /* create tabwin */
> ++
> ++ XDefineCursor(dpy, m->tabwin, cursor[CurNormal]->cursor);
> ++ XMapRaised(dpy, m->tabwin);
> ++
> ++ }
> ++
> ++ h = selmon->maxHTab / m->nTabs;
> ++
> ++ int y = 0;
> ++ int n = 0;
> ++ for (int i = 0;i < m->nTabs;i++) { /* draw all clients into tabwin */
> ++ c = m->altsnext[i];
> ++ if(!ISVISIBLE(c)) continue;
> ++ /* if (HIDDEN(c)) continue; uncomment if you're using awesomebar patch */
> ++
> ++ n++;
> ++ drw_setscheme(drw, scheme[(c == m->sel) ? SchemeSel : SchemeNorm]);
> ++ drw_text(drw, 0, y, selmon->maxWTab, h, 0, c->name, 0);
> ++ y += h;
> ++ }
> ++
> ++ drw_setscheme(drw, scheme[SchemeNorm]);
> ++ drw_map(drw, m->tabwin, 0, 0, selmon->maxWTab, selmon->maxHTab);
> ++}

> ++void
> ++altTabStart(const Arg *arg)
> ++{
> ++ selmon->altsnext = NULL;
> ++ if (selmon->tabwin)
> ++ altTabEnd();
> ++
> ++ if (selmon->isAlt == 1) {
> ++ altTabEnd();
> ++ } else {
> ++ selmon->isAlt = 1;
> ++ selmon->altTabN = 0;
> ++
> ++ Client *c;
> ++ Monitor *m = selmon;
> ++
> ++ m->nTabs = 0;
> ++ for(c = m->clients; c; c = c->next) { /* count clients */
> ++ if(!ISVISIBLE(c)) continue;
> ++ /* if (HIDDEN(c)) continue; uncomment if you're using awesomebar patch */
> ++
> ++ ++m->nTabs;
> ++ }
> ++
> ++ if (m->nTabs > 0) {
> ++ m->altsnext = (Client **) malloc(m->nTabs * sizeof(Client *));
> ++
> ++ int listIndex = 0;
> ++ for(c = m->stack; c; c = c->snext) { /* add clients to the list */
> ++ if(!ISVISIBLE(c)) continue;
> ++ /* if (HIDDEN(c)) continue; uncomment if you're using awesomebar patch */
> ++
> ++ m->altsnext[listIndex++] = c;
> ++ }
> ++
> ++ drawTab(m->nTabs, 1, m);
> ++
> ++ struct timespec ts = { .tv_sec = 0, .tv_nsec = 1000000 };
> ++
> ++ /* grab keyboard (take all input from keyboard) */

This comment is unnecessary, too. The code shows what's going on.

> ++ int grabbed = 1;
> ++ for (int i = 0;i < 1000;i++) {
> ++ if (XGrabKeyboard(dpy, DefaultRootWindow(dpy), True, GrabModeAsync, GrabModeAsync, CurrentTime) == GrabSuccess)
> ++ break;
> ++ nanosleep(&ts, NULL);
> ++ if (i == 1000 - 1)
> ++ grabbed = 0;
> ++ }
> ++
> ++ XEvent event;
> ++ altTab();
> ++ if (grabbed == 0) {
> ++ altTabEnd();
> ++ } else {
> ++ while (grabbed) {
> ++ XNextEvent(dpy, &event);
> ++ if (event.type == KeyPress || event.type == KeyRelease) {
> ++ if (event.type == KeyRelease && event.xkey.keycode == tabModKey) { /* if super key is released break cycle */
> ++ break;
> ++ } else if (event.type == KeyPress) {
> ++ if (event.xkey.keycode == tabCycleKey) {/* if XK_s is pressed move to the next window */
> ++ altTab();
> ++ }
> ++ }
> ++ }
> ++ }
> ++
> ++ c = selmon->sel;
> ++ altTabEnd(); /* end the alt-tab functionality */
> ++ /* XUngrabKeyboard(display, time); just a reference */

As stated above, those "reference" comments should be removed.

> ++ XUngrabKeyboard(dpy, CurrentTime); /* stop taking all input from keyboard */
> ++ focus(c);
> ++ restack(selmon);
> ++ }
> ++ } else {
> ++ altTabEnd(); /* end the alt-tab functionality */

Another redundant comment^^

> diff --git a/dwm.suckless.org/patches/alt-tab/get-xkey.c b/dwm.suckless.org/patches/alt-tab/get-xkey.c
> new file mode 100644
> index 00000000..76b80f8d
> --- /dev/null
> +++ b/dwm.suckless.org/patches/alt-tab/get-xkey.c
> _AT_@ -0,0 +1,30 @@
> +#include <stdio.h>
> +#include <stdlib.h>
> +#include <X11/Xlib.h>
> +
> +int main(void) {
> + Display *dpy;
> + Window win;
> + XEvent e;
> + int s;
> +
> + dpy = XOpenDisplay(NULL);
> + if (dpy == NULL) {
> + fprintf(stderr, "Cannot open display
> ");
> + exit(1);
> + }
> +
> + s = DefaultScreen(dpy);
> + win = XCreateSimpleWindow(dpy, RootWindow(dpy, s), 10, 10, 100, 100, 0, 0, 0);
> + XSelectInput(dpy, win, ExposureMask | KeyPressMask);
> + XMapWindow(dpy, win);
> +
> + while (1) {
> + XNextEvent(dpy, &e);
> + if (e.type == KeyPress)
> + printf("0x%x
> ",e.xkey.keycode);
> + }
> +
> + XCloseDisplay(dpy);
> + return 0;
> +}

This is unnecessary and should be dropped, we can use xev(1) to obtain a keycode.

> +Fake Internet money
> +-------------------
> +If you like my work and want to support me by some fake internet money, here is my monero address
> +
> +85EVKkDnQMYZxmJ7Fj5dG6Lw9V3vZRxAjft3btaB2FhzTCGoGocbRTAS857tgZvy1QD5cShxxp98S6y3utG3nqMTVARnW8P

I'm unsure if this is okay.

Additionally, the style guide states that initial declarations
in `for` loops shouldn't be used.

-- 
Best Regards,
Tom Schwindl
Received on Sat Jul 09 2022 - 16:47:48 CEST

This archive was generated by hypermail 2.3.0 : Sat Jul 09 2022 - 17:00:40 CEST