dwm-alttab-6.4.diff - sites - public wiki contents of suckless.org
 (HTM) git clone git://git.suckless.org/sites
 (DIR) Log
 (DIR) Files
 (DIR) Refs
       ---
       dwm-alttab-6.4.diff (10136B)
       ---
            1 From 8b1d33db9cbc03bf12df398bb14e62389efc70a3 Mon Sep 17 00:00:00 2001
            2 From: ViliamKovac1223 <viliamkovac1223@gmail.com>
            3 Date: Sun, 9 Oct 2022 16:29:28 -0400
            4 Subject: [PATCH] add alt-tab functionality
            5 
            6 Co-authored-by: Daniel Gerblick <daniel.gerblick@gmail.com>
            7 ---
            8  config.def.h |  11 ++-
            9  dwm.c        | 218 +++++++++++++++++++++++++++++++++++++++++++++++++++
           10  2 files changed, 228 insertions(+), 1 deletion(-)
           11 
           12 diff --git a/config.def.h b/config.def.h
           13 index 061ad66..7a9e3b1 100644
           14 --- a/config.def.h
           15 +++ b/config.def.h
           16 @@ -1,5 +1,13 @@
           17  /* See LICENSE file for copyright and license details. */
           18  
           19 +/* alt-tab configuration */
           20 +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 `*/
           21 +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 */
           22 +static const unsigned int tabPosY                         = 1;        /* tab position on Y axis, 0 = bottom, 1 = center, 2 = top */
           23 +static const unsigned int tabPosX                         = 1;        /* tab position on X axis, 0 = left, 1 = center, 2 = right */
           24 +static const unsigned int maxWTab                         = 600;        /* tab menu width */
           25 +static const unsigned int maxHTab                         = 200;        /* tab menu height */
           26 +
           27  /* appearance */
           28  static const unsigned int borderpx  = 1;        /* border pixel of windows */
           29  static const unsigned int snap      = 32;       /* snap pixel */
           30 @@ -71,7 +79,7 @@ static const Key keys[] = {
           31          { MODKEY,                       XK_h,      setmfact,       {.f = -0.05} },
           32          { MODKEY,                       XK_l,      setmfact,       {.f = +0.05} },
           33          { MODKEY,                       XK_Return, zoom,           {0} },
           34 -        { MODKEY,                       XK_Tab,    view,           {0} },
           35 +        { MODKEY,                       XK_q,           view,           {0} },
           36          { MODKEY|ShiftMask,             XK_c,      killclient,     {0} },
           37          { MODKEY,                       XK_t,      setlayout,      {.v = &layouts[0]} },
           38          { MODKEY,                       XK_f,      setlayout,      {.v = &layouts[1]} },
           39 @@ -84,6 +92,7 @@ static const Key keys[] = {
           40          { MODKEY,                       XK_period, focusmon,       {.i = +1 } },
           41          { MODKEY|ShiftMask,             XK_comma,  tagmon,         {.i = -1 } },
           42          { MODKEY|ShiftMask,             XK_period, tagmon,         {.i = +1 } },
           43 +        { Mod1Mask,                             XK_Tab,    altTabStart,           {0} },
           44          TAGKEYS(                        XK_1,                      0)
           45          TAGKEYS(                        XK_2,                      1)
           46          TAGKEYS(                        XK_3,                      2)
           47 diff --git a/dwm.c b/dwm.c
           48 index e5efb6a..f606311 100644
           49 --- a/dwm.c
           50 +++ b/dwm.c
           51 @@ -40,6 +40,7 @@
           52  #include <X11/extensions/Xinerama.h>
           53  #endif /* XINERAMA */
           54  #include <X11/Xft/Xft.h>
           55 +#include <time.h>
           56  
           57  #include "drw.h"
           58  #include "util.h"
           59 @@ -119,6 +120,11 @@ struct Monitor {
           60          int by;               /* bar geometry */
           61          int mx, my, mw, mh;   /* screen size */
           62          int wx, wy, ww, wh;   /* window area  */
           63 +        int altTabN;                  /* move that many clients forward */
           64 +        int nTabs;                          /* number of active clients in tag */
           65 +        int isAlt;                           /* 1,0 */
           66 +        int maxWTab;
           67 +        int maxHTab;
           68          unsigned int seltags;
           69          unsigned int sellt;
           70          unsigned int tagset[2];
           71 @@ -127,8 +133,10 @@ struct Monitor {
           72          Client *clients;
           73          Client *sel;
           74          Client *stack;
           75 +        Client ** altsnext; /* array of all clients in the tag */
           76          Monitor *next;
           77          Window barwin;
           78 +        Window tabwin;
           79          const Layout *lt[2];
           80  };
           81  
           82 @@ -234,6 +242,9 @@ static int xerror(Display *dpy, XErrorEvent *ee);
           83  static int xerrordummy(Display *dpy, XErrorEvent *ee);
           84  static int xerrorstart(Display *dpy, XErrorEvent *ee);
           85  static void zoom(const Arg *arg);
           86 +void drawTab(int nwins, int first, Monitor *m);
           87 +void altTabStart(const Arg *arg);
           88 +static void altTabEnd();
           89  
           90  /* variables */
           91  static const char broken[] = "broken";
           92 @@ -477,6 +488,7 @@ cleanup(void)
           93          Monitor *m;
           94          size_t i;
           95  
           96 +        altTabEnd();
           97          view(&a);
           98          selmon->lt[selmon->sellt] = &foo;
           99          for (m = mons; m; m = m->next)
          100 @@ -644,6 +656,7 @@ createmon(void)
          101          m->topbar = topbar;
          102          m->lt[0] = &layouts[0];
          103          m->lt[1] = &layouts[1 % LENGTH(layouts)];
          104 +        m->nTabs = 0;
          105          strncpy(m->ltsymbol, layouts[0].symbol, sizeof m->ltsymbol);
          106          return m;
          107  }
          108 @@ -1648,6 +1661,211 @@ spawn(const Arg *arg)
          109          }
          110  }
          111  
          112 +void
          113 +altTab()
          114 +{
          115 +        /* move to next window */
          116 +        if (selmon->sel != NULL && selmon->sel->snext != NULL) {
          117 +                selmon->altTabN++;
          118 +                if (selmon->altTabN >= selmon->nTabs)
          119 +                        selmon->altTabN = 0; /* reset altTabN */
          120 +
          121 +                focus(selmon->altsnext[selmon->altTabN]);
          122 +                restack(selmon);
          123 +        }
          124 +
          125 +        /* redraw tab */
          126 +        XRaiseWindow(dpy, selmon->tabwin);
          127 +        drawTab(selmon->nTabs, 0, selmon);
          128 +}
          129 +
          130 +void
          131 +altTabEnd()
          132 +{
          133 +        if (selmon->isAlt == 0)
          134 +                return;
          135 +
          136 +        /*
          137 +        * move all clients between 1st and choosen position,
          138 +        * one down in stack and put choosen client to the first position 
          139 +        * so they remain in right order for the next time that alt-tab is used
          140 +        */
          141 +        if (selmon->nTabs > 1) {
          142 +                if (selmon->altTabN != 0) { /* if user picked original client do nothing */
          143 +                        Client *buff = selmon->altsnext[selmon->altTabN];
          144 +                        if (selmon->altTabN > 1)
          145 +                                for (int i = selmon->altTabN;i > 0;i--)
          146 +                                        selmon->altsnext[i] = selmon->altsnext[i - 1];
          147 +                        else /* swap them if there are just 2 clients */
          148 +                                selmon->altsnext[selmon->altTabN] = selmon->altsnext[0];
          149 +                        selmon->altsnext[0] = buff;
          150 +                }
          151 +
          152 +                /* restack clients */
          153 +                for (int i = selmon->nTabs - 1;i >= 0;i--) {
          154 +                        focus(selmon->altsnext[i]);
          155 +                        restack(selmon);
          156 +                }
          157 +
          158 +                free(selmon->altsnext); /* free list of clients */
          159 +        }
          160 +
          161 +        /* turn off/destroy the window */
          162 +        selmon->isAlt = 0;
          163 +        selmon->nTabs = 0;
          164 +        XUnmapWindow(dpy, selmon->tabwin);
          165 +        XDestroyWindow(dpy, selmon->tabwin);
          166 +}
          167 +
          168 +void
          169 +drawTab(int nwins, int first, Monitor *m)
          170 +{
          171 +        /* little documentation of functions */
          172 +        /* void drw_rect(Drw *drw, int x, int y, unsigned int w, unsigned int h, int filled, int invert); */
          173 +        /* int drw_text(Drw *drw, int x, int y, unsigned int w, unsigned int h, unsigned int lpad, const char *text, int invert); */
          174 +        /* void drw_map(Drw *drw, Window win, int x, int y, unsigned int w, unsigned int h); */
          175 +
          176 +        Client *c;
          177 +        int h;
          178 +
          179 +        if (first) {
          180 +                Monitor *m = selmon;
          181 +                XSetWindowAttributes wa = {
          182 +                        .override_redirect = True,
          183 +                        .background_pixmap = ParentRelative,
          184 +                        .event_mask = ButtonPressMask|ExposureMask
          185 +                };
          186 +
          187 +                selmon->maxWTab = maxWTab;
          188 +                selmon->maxHTab = maxHTab;
          189 +
          190 +                /* decide position of tabwin */
          191 +                int posX = selmon->mx;
          192 +                int posY = selmon->my;
          193 +                if (tabPosX == 0)
          194 +                        posX += 0;
          195 +                if (tabPosX == 1)
          196 +                        posX += (selmon->mw / 2) - (maxWTab / 2);
          197 +                if (tabPosX == 2)
          198 +                        posX += selmon->mw - maxWTab;
          199 +
          200 +                if (tabPosY == 0)
          201 +                        posY += selmon->mh - maxHTab;
          202 +                if (tabPosY == 1)
          203 +                        posY += (selmon->mh / 2) - (maxHTab / 2);
          204 +                if (tabPosY == 2)
          205 +                        posY += 0;
          206 +
          207 +                h = selmon->maxHTab;
          208 +                /* XCreateWindow(display, parent, x, y, width, height, border_width, depth, class, visual, valuemask, attributes); just reference */
          209 +                m->tabwin = XCreateWindow(dpy, root, posX, posY, selmon->maxWTab, selmon->maxHTab, 2, DefaultDepth(dpy, screen),
          210 +                                                                CopyFromParent, DefaultVisual(dpy, screen),
          211 +                                                                CWOverrideRedirect|CWBackPixmap|CWEventMask, &wa); /* create tabwin */
          212 +
          213 +                XDefineCursor(dpy, m->tabwin, cursor[CurNormal]->cursor);
          214 +                XMapRaised(dpy, m->tabwin);
          215 +
          216 +        }
          217 +
          218 +        h = selmon->maxHTab  / m->nTabs;
          219 +
          220 +        int y = 0;
          221 +        int n = 0;
          222 +        for (int i = 0;i < m->nTabs;i++) { /* draw all clients into tabwin */
          223 +                c = m->altsnext[i];
          224 +                if(!ISVISIBLE(c)) continue;
          225 +                /* if (HIDDEN(c)) continue; uncomment if you're using awesomebar patch */
          226 +
          227 +                n++;
          228 +                drw_setscheme(drw, scheme[(c == m->sel) ? SchemeSel : SchemeNorm]);
          229 +                drw_text(drw, 0, y, selmon->maxWTab, h, 0, c->name, 0);
          230 +                y += h;
          231 +        }
          232 +
          233 +        drw_setscheme(drw, scheme[SchemeNorm]);
          234 +        drw_map(drw, m->tabwin, 0, 0, selmon->maxWTab, selmon->maxHTab);
          235 +}
          236 +
          237 +void
          238 +altTabStart(const Arg *arg)
          239 +{
          240 +        selmon->altsnext = NULL;
          241 +        if (selmon->tabwin)
          242 +                altTabEnd();
          243 +
          244 +        if (selmon->isAlt == 1) {
          245 +                altTabEnd();
          246 +        } else {
          247 +                selmon->isAlt = 1;
          248 +                selmon->altTabN = 0;
          249 +
          250 +                Client *c;
          251 +                Monitor *m = selmon;
          252 +
          253 +                m->nTabs = 0;
          254 +                for(c = m->clients; c; c = c->next) { /* count clients */
          255 +                        if(!ISVISIBLE(c)) continue;
          256 +                        /* if (HIDDEN(c)) continue; uncomment if you're using awesomebar patch */
          257 +
          258 +                        ++m->nTabs;
          259 +                }
          260 +
          261 +                if (m->nTabs > 0) {
          262 +                        m->altsnext = (Client **) malloc(m->nTabs * sizeof(Client *));
          263 +
          264 +                        int listIndex = 0;
          265 +                        for(c = m->stack; c; c = c->snext) { /* add clients to the list */
          266 +                                if(!ISVISIBLE(c)) continue;
          267 +                                /* if (HIDDEN(c)) continue; uncomment if you're using awesomebar patch */
          268 +
          269 +                                m->altsnext[listIndex++] = c;
          270 +                        }
          271 +
          272 +                        drawTab(m->nTabs, 1, m);
          273 +
          274 +                        struct timespec ts = { .tv_sec = 0, .tv_nsec = 1000000 };
          275 +
          276 +                        /* grab keyboard (take all input from keyboard) */
          277 +                        int grabbed = 1;
          278 +                        for (int i = 0;i < 1000;i++) {
          279 +                                if (XGrabKeyboard(dpy, DefaultRootWindow(dpy), True, GrabModeAsync, GrabModeAsync, CurrentTime) == GrabSuccess)
          280 +                                        break;
          281 +                                nanosleep(&ts, NULL);
          282 +                                if (i == 1000 - 1)
          283 +                                        grabbed = 0;
          284 +                        }
          285 +
          286 +                        XEvent event;
          287 +                        altTab();
          288 +                        if (grabbed == 0) {
          289 +                                altTabEnd();
          290 +                        } else {
          291 +                                while (grabbed) {
          292 +                                        XNextEvent(dpy, &event);
          293 +                                        if (event.type == KeyPress || event.type == KeyRelease) {
          294 +                                                if (event.type == KeyRelease && event.xkey.keycode == tabModKey) { /* if super key is released break cycle */
          295 +                                                        break;
          296 +                                                } else if (event.type == KeyPress) {
          297 +                                                        if (event.xkey.keycode == tabCycleKey) {/* if XK_s is pressed move to the next window */
          298 +                                                                altTab();
          299 +                                                        }
          300 +                                                }
          301 +                                        }
          302 +                                }
          303 +
          304 +                                c = selmon->sel;
          305 +                                altTabEnd(); /* end the alt-tab functionality */
          306 +                                /* XUngrabKeyboard(display, time); just a reference */
          307 +                                XUngrabKeyboard(dpy, CurrentTime); /* stop taking all input from keyboard */
          308 +                                focus(c);
          309 +                                restack(selmon);
          310 +                        }
          311 +                } else {
          312 +                        altTabEnd(); /* end the alt-tab functionality */
          313 +                }
          314 +        }
          315 +}
          316 +
          317  void
          318  tag(const Arg *arg)
          319  {
          320 -- 
          321 2.37.3
          322