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