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