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