-
Notifications
You must be signed in to change notification settings - Fork 0
/
dwm_personal.diff
802 lines (776 loc) · 36.6 KB
/
dwm_personal.diff
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
diff -up -N /gnu/store/qf41ki0f1508412bpnyvnj7sbli8zfyq-dwm-6.4-checkout/config.def.h /home/tadhg/src/dwm/config.def.h
--- /gnu/store/qf41ki0f1508412bpnyvnj7sbli8zfyq-dwm-6.4-checkout/config.def.h 1969-12-31 19:00:01.000000000 -0500
+++ /home/tadhg/src/dwm/config.def.h 2024-10-30 17:52:50.282956460 -0400
@@ -1,12 +1,13 @@
/* See LICENSE file for copyright and license details. */
-
+#include <X11/XF86keysym.h>
/* appearance */
static const unsigned int borderpx = 1; /* border pixel of windows */
static const unsigned int snap = 32; /* snap pixel */
-static const int showbar = 1; /* 0 means no bar */
+// showbar=2 means it starts in the state like you are holding down the mod key, so showing but will go away when you do anything
+static const int showbar = 2; /* 0 means no bar */
static const int topbar = 1; /* 0 means bottom bar */
-static const char font[] = "monospace 10";
-static const char dmenufont[] = "monospace:size=10";
+static const char font[] = "monospace 16";
+static const char dmenufont[] = "monospace:size=16";
static const char col_gray1[] = "#222222";
static const char col_gray2[] = "#444444";
static const char col_gray3[] = "#bbbbbb";
@@ -19,27 +20,79 @@ static const char *colors[][3] = {
};
/* tagging */
-static const char *tags[] = { "1", "2", "3", "4", "5", "6", "7", "8", "9" };
-
+// these are intended to be the dozonal characters I define with my custom font.
+// without the custom font they are the unicode characters for "Ideographic Telegraph Symbol For Hour X" where X goes from 0 to 11.
+// so in theory a font that supports this range would display reasonable graphics for the tags.
+static const char *tags[] = { "\u3358", "\u3359", "\u335a", "\u335b", "\u335c", "\u335d", "\u335e", "\u335f", "\u3360", "\u3361", "\u3362", "\u3363" };
+
+// rules to apply to new windows, can force them to start on a particular tag or to be floating or a monitor etc.
+// currently if a program is launched while the auto-start programs are still being opened it breaks the sequence
+// putting all the windows to the wrong spots, we could use rules to fix that but it would mean that if we, say,
+// opened emacs at any point like to view a file it would always open on tag 3 if we specified it here.
+// so I think the current system where the auto-start specifies the tag and this is used only to fix issues with splash screen
+// that is the best bet.
+// also use `guix shell xprop -- xprop` then click on a window to print the details,
static const Rule rules[] = {
/* xprop(1):
* WM_CLASS(STRING) = instance, class
* WM_NAME(STRING) = title
*/
/* class instance title tags mask isfloating monitor */
- { "Gimp", NULL, NULL, 0, 1, -1 },
- { "Firefox", NULL, NULL, 1 << 8, 0, -1 },
+ // force discord to open on tag 1 since it has the annoying splash screen
+ { "discord", "discord", NULL, 1 << 1, 0, -1 },
};
/* layout(s) */
static const float mfact = 0.55; /* factor of master area size [0.05..0.95] */
static const int nmaster = 1; /* number of clients in master area */
static const int resizehints = 1; /* 1 means respect size hints in tiled resizals */
-static const int lockfullscreen = 1; /* 1 will force focus on the fullscreen window */
+static const int lockfullscreen = 0; /* 1 will force focus on the fullscreen window */
+
+/* w/h ratio */
+static const float MIN_ASPECT_RATIO_TO_TILE_HORIZONTALLY = 1.0;
+void mytile(Monitor *m){
+ unsigned int x = m->wx;
+ unsigned int y = m->wy;
+ unsigned int w = m->ww;
+ unsigned int h = m->wh;
+ float mfact = m->mfact;
+ Client *c = nexttiled(m->clients);
+ if(c==NULL){
+ return;
+ }
+ while(1){ // broken by nextc==NULL in the middle of the loop
+ Client *nextc = nexttiled(c->next);
+ if(nextc == NULL || (c->mina != 0 && c->maxa != 0)){
+ // last one to tile or desired aspect ratio, use up all the available space
+ resize(c, x,y,w,h,0);
+ } else if(w > h*MIN_ASPECT_RATIO_TO_TILE_HORIZONTALLY){
+ // tile horizontally
+ resize(c, x,y, w*mfact, h, 0);
+ } else {
+ // tile vertically
+ resize(c, x,y, w, h*mfact, 0);
+ }
+ if(nextc == NULL){
+ return;
+ }
+ // because of aspect ratio and border widths just check whether there is more space vertically or horizontally to tile next elements.
+ // TODO: casting these to ints fixes the issue if one ends up negative but is it the correct way to handle this?
+ if((int)(w - c->w) > (int)(h - c->h)){
+ // more space to the side
+ w -= c->w;
+ x += c->w;
+ } else {
+ // more space below
+ h -= c->h;
+ y += c->h;
+ }
+ c = nextc;
+ }
+}
static const Layout layouts[] = {
/* symbol arrange function */
- { "[]=", tile }, /* first entry is default */
+ { "[]=", mytile }, /* first entry is default */
{ "><>", NULL }, /* no layout function means floating behavior */
{ "[M]", monocle },
{ "TTT", bstack },
@@ -47,89 +100,148 @@ static const Layout layouts[] = {
};
/* key definitions */
-#define MODKEY Mod1Mask
+#define MODKEY Mod4Mask
#define TAGKEYS(KEY,TAG) \
{ MODKEY, KEY, view, {.ui = 1 << TAG} }, \
{ MODKEY|ControlMask, KEY, toggleview, {.ui = 1 << TAG} }, \
{ MODKEY|ShiftMask, KEY, tag, {.ui = 1 << TAG} }, \
{ MODKEY|ControlMask|ShiftMask, KEY, toggletag, {.ui = 1 << TAG} },
-#define HOLDKEY 0xffe9 // 0 - disable; 0xffe9 - Mod1Mask; 0xffeb - Mod4Mask
+#define HOLDKEY 0xffeb // 0 - disable; 0xffe9 - Mod1Mask; 0xffeb - Mod4Mask
/* helper for spawning shell commands in the pre dwm-5.0 fashion */
#define SHCMD(cmd) { .v = (const char*[]){ "/bin/sh", "-c", cmd, NULL } }
/* commands */
-static const char *dmenucmd[] = { "dmenu_run", "-fn", dmenufont, "-nb", col_gray1, "-nf", col_gray3, "-sb", col_cyan, "-sf", col_gray4, NULL };
-static const char *termcmd[] = { "st", NULL };
-static const char *termcmd2[] = { "xterm", NULL };
-static const char *browsercmd[] = {"librewolf", NULL};
-static const char *keepassxccmd[] = {"keepassxc", NULL};
+static const char *dmenucmd[] = { "dmenuwithbangs", "-fn", dmenufont, "-nb", col_gray1, "-nf", col_gray3, "-sb", col_cyan, "-sf", col_gray4, NULL };
+static const char *termcmd[] = { "alacritty", NULL };
+static const char *chatclientcmd[] = { "dino", NULL };
+static const char *discord[] = {"discord", NULL};
+static const char *fbmessengerbrave[] = {"brave", "--app=https://www.messenger.com/", NULL};
+static const char *browsercmd[] = {"brave", NULL};
+static const char *emailclientcmd[] = {"icedove", NULL};
static const char *emacscmd[] = {"emacs", NULL};
Autostarttag autostarttaglist[] = {
- {.cmd = browsercmd, .tags = 1 << 0 },
- {.cmd = keepassxccmd, .tags = 1 << 4 },
- {.cmd = emacscmd, .tags = 1 << 7 },
- {.cmd = termcmd2, .tags = 1 << 8 },
+ { .tags=1<< 2, .cmd=browsercmd },
+ { .tags=1<< 3, .cmd=emacscmd },
+ { .tags=1<< 5, .cmd=emailclientcmd },
+ { .tags=1<< 1, .cmd=discord },
+ { .tags=1<< 1, .cmd=fbmessengerbrave },
+ { .tags=1<< 1, .cmd=chatclientcmd },
+
+
{.cmd = NULL, .tags = 0 },
};
+
static const Key keys[] = {
/* modifier key function argument */
- { MODKEY, XK_p, spawn, {.v = dmenucmd } },
- { MODKEY|ShiftMask, XK_Return, spawn, {.v = termcmd } },
- { MODKEY, XK_b, togglebar, {0} },
- { MODKEY, XK_j, focusstack, {.i = +1 } },
- { MODKEY, XK_k, focusstack, {.i = -1 } },
- { MODKEY, XK_i, incnmaster, {.i = +1 } },
- { MODKEY, XK_d, incnmaster, {.i = -1 } },
+ // win+space opens dmenu for quicklook like behaviour
+ { MODKEY, XK_space, spawn, {.v = dmenucmd } },
+ // win+shift+space opens terminal
+ { MODKEY|ShiftMask, XK_space, spawn, {.v = termcmd } },
+ // TODO: probably remove this, win+play_pause speaks the selected text
+ { MODKEY, XF86XK_AudioPlay, spawn, SHCMD("xclip -o | festival --tts") },
+ // brightness keys, shift+win goes to extreme value, win goes to major value and without modifier keys goes to typical value
+ // TODO: implement deltas into brctl and add bindings here instead of always absolute.
+ // every now and then the brightness keys stop working so map the function keys too as a backup
+ { MODKEY|ShiftMask, XF86XK_MonBrightnessDown, spawn, SHCMD("brctl 0") },
+ { MODKEY|ShiftMask, XK_F7, spawn, SHCMD("brctl 0") },
+ { MODKEY, XF86XK_MonBrightnessDown, spawn, SHCMD("brctl 1") },
+ { MODKEY, XK_F7, spawn, SHCMD("brctl 1") },
+ { 0, XF86XK_MonBrightnessDown, spawn, SHCMD("brctl 5") },
+ { 0, XK_F7, spawn, SHCMD("brctl 5") },
+ { 0, XF86XK_MonBrightnessUp, spawn, SHCMD("brctl 10") },
+ { 0, XK_F8, spawn, SHCMD("brctl 10") },
+ { MODKEY, XF86XK_MonBrightnessUp, spawn, SHCMD("brctl 20") },
+ { MODKEY, XK_F8, spawn, SHCMD("brctl 20") },
+ { MODKEY|ShiftMask, XF86XK_MonBrightnessUp, spawn, SHCMD("brctl 40") },
+ { MODKEY|ShiftMask, XK_F8, spawn, SHCMD("brctl 40") },
+ // mute button: without modkey unconditional unmute, with modkey unconditional mute
+ { 0, XF86XK_AudioMute, spawn, SHCMD("amixer set Master mute") },
+ { MODKEY, XF86XK_AudioMute, spawn, SHCMD("amixer set Master unmute") },
+ // volume down: (without modkey decreases volume by 5%, with modkey sets volume to 0
+ { 0, XF86XK_AudioLowerVolume, spawn, SHCMD("amixer set Master 5%-") },
+ { MODKEY, XF86XK_AudioLowerVolume, spawn, SHCMD("amixer set Master 0%") },
+ // volume up: withoutt modkey increases 5%, with modkey increases 5% with pactl so it can go above 100%
+ { 0, XF86XK_AudioRaiseVolume, spawn, SHCMD("amixer set Master 5%+") },
+ { MODKEY, XF86XK_AudioRaiseVolume, spawn, SHCMD("pactl set-sink-volume 0 +5%") },
+ // don't allow toggling the bar to always be showing because I don't typically want that.
+ /*{ MODKEY, XK_b, togglebar, {0} },*/
+ // use layouts instead of being able to increment nmaster
+ /*{ MODKEY, XK_i, incnmaster, {.i = +1 } },*/
+ /*{ MODKEY, XK_d, incnmaster, {.i = -1 } },*/
+ // h and l change the size of the main window when there are more than 1 window open in the tag.
{ MODKEY, XK_h, setmfact, {.f = -0.05} },
{ MODKEY, XK_l, setmfact, {.f = +0.05} },
+ // return key (enter) sets the selected window as the main one (moves to left larger space) only noticable with 3 windows open on a tag.
{ MODKEY, XK_Return, zoom, {0} },
- { MODKEY, XK_Tab, view, {0} },
- { MODKEY|ShiftMask, XK_c, killclient, {0} },
- { MODKEY, XK_t, setlayout, {.v = &layouts[0]} },
- { MODKEY, XK_f, setlayout, {.v = &layouts[1]} },
- { MODKEY, XK_m, setlayout, {.v = &layouts[2]} },
- { MODKEY, XK_u, setlayout, {.v = &layouts[3]} },
- { MODKEY, XK_o, setlayout, {.v = &layouts[4]} },
- { MODKEY, XK_space, setlayout, {0} },
- { MODKEY|ShiftMask, XK_space, togglefloating, {0} },
- { MODKEY|ShiftMask, XK_f, togglefullscr, {0} },
- { MODKEY, XK_0, view, {.ui = ~0 } },
- { MODKEY|ShiftMask, XK_0, tag, {.ui = ~0 } },
+ // win+tab will toggle between recently used tags
+ { MODKEY, XK_Tab, view, {0} },
+ // backspace kills the selected window, if no windows are open in any tag this will also close dwm (which is one of my personal edits to the code)
+ { MODKEY, XK_BackSpace, killclient, {0} },
+ // force quit dwm and all windows.
+ { MODKEY|ShiftMask|ControlMask, XK_BackSpace, quit, {0} },
+ // clicking on tile symbol in menu bar switches between the only layouts I care about.
+ /* { MODKEY, XK_t, setlayout, {.v = &layouts[0]} },*/
+ /* { MODKEY, XK_f, setlayout, {.v = &layouts[1]} },*/
+ /* { MODKEY, XK_m, setlayout, {.v = &layouts[2]} },*/
+ /* { MODKEY, XK_u, setlayout, {.v = &layouts[3]} },*/
+ /* { MODKEY, XK_o, setlayout, {.v = &layouts[4]} },*/
+ /*{ MODKEY, XK_space, setlayout, {0} },*/
+ { MODKEY|ShiftMask|ControlMask, XK_f, togglefloating, {0} },
+ { MODKEY, XK_f, togglefullscr, {0} },
+ // comma and period change focus between monitors, shift+win+comma moves the window to another monitor etc.
{ MODKEY, XK_comma, focusmon, {.i = -1 } },
{ MODKEY, XK_period, focusmon, {.i = +1 } },
{ MODKEY|ShiftMask, XK_comma, tagmon, {.i = -1 } },
{ MODKEY|ShiftMask, XK_period, tagmon, {.i = +1 } },
- TAGKEYS( XK_1, 0)
- TAGKEYS( XK_2, 1)
- TAGKEYS( XK_3, 2)
- TAGKEYS( XK_4, 3)
- TAGKEYS( XK_5, 4)
- TAGKEYS( XK_6, 5)
- TAGKEYS( XK_7, 6)
- TAGKEYS( XK_8, 7)
- TAGKEYS( XK_9, 8)
- { MODKEY|ShiftMask, XK_q, quit, {0} },
+ // tagkeys, starting from grave for 0, 1 to 9 then 0=>10 and minus=>11.
+ TAGKEYS( XK_grave, 0)
+ TAGKEYS( XK_1, 1)
+ TAGKEYS( XK_2, 2)
+ TAGKEYS( XK_3, 3)
+ TAGKEYS( XK_4, 4)
+ TAGKEYS( XK_5, 5)
+ TAGKEYS( XK_6, 6)
+ TAGKEYS( XK_7, 7)
+ TAGKEYS( XK_8, 8)
+ TAGKEYS( XK_9, 9)
+ TAGKEYS( XK_0, 10)
+ TAGKEYS( XK_minus, 11)
+ // use equal key as 'all tags', so win+equal shows all windows and win+shift+equal sets a window to be visible on all tags
+ { MODKEY, XK_equal, view, {.ui = ~0 } },
+ { MODKEY|ShiftMask, XK_equal, tag, {.ui = ~0 } },
+ // pressing the win key with any other modifiers should show the bar,
+ // in theory this could be handled as a special case in the code to ignore modifiers if the key is HOLDKEY but this works too.
{ 0, HOLDKEY, holdbar, {0} },
+ { ShiftMask, HOLDKEY, holdbar, {0} },
+ { ControlMask, HOLDKEY, holdbar, {0} },
+ { ShiftMask|ControlMask, HOLDKEY, holdbar, {0} },
+ { Mod1Mask, HOLDKEY, holdbar, {0} },
+ { Mod1Mask|ShiftMask, HOLDKEY, holdbar, {0} },
+ { Mod1Mask|ControlMask, HOLDKEY, holdbar, {0} },
+ { Mod1Mask|ShiftMask|ControlMask,HOLDKEY, holdbar, {0} },
};
/* button definitions */
/* click can be ClkTagBar, ClkLtSymbol, ClkStatusText, ClkWinTitle, ClkClientWin, or ClkRootWin */
+/* note all are set to use MODKEY because the bar will only show up when the mod key is held */
static const Button buttons[] = {
/* click event mask button function argument */
- { ClkLtSymbol, 0, Button1, setlayout, {0} },
- { ClkLtSymbol, 0, Button3, setlayout, {.v = &layouts[2]} },
- { ClkWinTitle, 0, Button2, zoom, {0} },
- { ClkStatusText, 0, Button2, spawn, {.v = termcmd } },
- { ClkClientWin, MODKEY, Button1, movemouse, {0} },
- { ClkClientWin, MODKEY, Button2, togglefloating, {0} },
- { ClkClientWin, MODKEY, Button3, resizemouse, {0} },
- { ClkTagBar, 0, Button1, view, {0} },
- { ClkTagBar, 0, Button3, toggleview, {0} },
- { ClkTagBar, MODKEY, Button1, tag, {0} },
- { ClkTagBar, MODKEY, Button3, toggletag, {0} },
+ // clicking on layout symbol switches to tiling, rightclick switches to list mode
+ { ClkLtSymbol, MODKEY, Button1, setlayout, {.v = &layouts[0]} },
+ { ClkLtSymbol, MODKEY, Button3, setlayout, {.v = &layouts[3]} },
+ { ClkWinTitle, MODKEY, Button2, zoom, {0} },
+ { ClkStatusText, MODKEY, Button1, toggledoz, {0} },
+ { ClkStatusText, MODKEY, Button2, spawn, {.v = termcmd } },
+ { ClkClientWin, MODKEY|ShiftMask, Button1, movemouse, {0} },
+ { ClkClientWin, MODKEY|ShiftMask, Button2, togglefloating, {0} },
+ { ClkClientWin, MODKEY|ShiftMask, Button3, resizemouse, {0} },
+ { ClkTagBar, MODKEY, Button1, view, {0} },
+ { ClkTagBar, MODKEY, Button3, toggleview, {0} },
+ { ClkTagBar, MODKEY|ShiftMask, Button1, tag, {0} },
+ { ClkTagBar, MODKEY|ShiftMask, Button3, toggletag, {0} },
};
diff -up -N /gnu/store/qf41ki0f1508412bpnyvnj7sbli8zfyq-dwm-6.4-checkout/config.mk /home/tadhg/src/dwm/config.mk
--- /gnu/store/qf41ki0f1508412bpnyvnj7sbli8zfyq-dwm-6.4-checkout/config.mk 1969-12-31 19:00:01.000000000 -0500
+++ /home/tadhg/src/dwm/config.mk 2024-04-23 14:56:32.801882541 -0400
@@ -36,4 +36,4 @@ LDFLAGS = ${LIBS}
#LDFLAGS = ${LIBS}
# compiler and linker
-CC = cc
+CC = gcc
diff -up -N /gnu/store/qf41ki0f1508412bpnyvnj7sbli8zfyq-dwm-6.4-checkout/dwm.c /home/tadhg/src/dwm/dwm.c
--- /gnu/store/qf41ki0f1508412bpnyvnj7sbli8zfyq-dwm-6.4-checkout/dwm.c 1969-12-31 19:00:01.000000000 -0500
+++ /home/tadhg/src/dwm/dwm.c 2024-05-28 08:46:18.893203766 -0400
@@ -27,6 +27,7 @@
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
+#include <time.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/wait.h>
@@ -44,6 +45,7 @@
#include "drw.h"
#include "util.h"
+#include "status.h"
/* macros */
#define BUTTONMASK (ButtonPressMask|ButtonReleaseMask)
@@ -69,6 +71,10 @@ enum { WMProtocols, WMDelete, WMState, W
enum { ClkTagBar, ClkLtSymbol, ClkStatusText, ClkWinTitle,
ClkClientWin, ClkRootWin, ClkLast }; /* clicks */
+struct timespec current_time;
+struct timespec next_update;
+int usedoz = 1;
+
typedef union {
int i;
unsigned int ui;
@@ -223,6 +229,7 @@ static void tag(const Arg *arg);
static void tagmon(const Arg *arg);
static void tile(Monitor *m);
static void togglebar(const Arg *arg);
+static void toggledoz(const Arg *arg);
static void holdbar(const Arg *arg);
static void togglefloating(const Arg *arg);
static void togglefullscr(const Arg *arg);
@@ -508,9 +515,15 @@ buttonpress(XEvent *e)
}
if (ev->window == selmon->barwin) {
i = x = 0;
- do
+ unsigned int occ = 0;
+ for(c = m->clients; c; c=c->next)
+ occ |= c->tags == TAGMASK ? 0 : c->tags;
+ do {
+ /* Do not reserve space for vacant tags */
+ if (!(occ & 1 << i || m->tagset[m->seltags] & 1 << i))
+ continue;
x += TEXTW(tags[i]);
- while (ev->x >= x && ++i < LENGTH(tags));
+ } while (ev->x >= x && ++i < LENGTH(tags));
if (i < LENGTH(tags)) {
click = ClkTagBar;
arg.ui = 1 << i;
@@ -802,19 +815,18 @@ drawbar(Monitor *m)
}
for (c = m->clients; c; c = c->next) {
- occ |= c->tags;
+ occ |= c->tags == TAGMASK ? 0 : c->tags;
if (c->isurgent)
urg |= c->tags;
}
x = 0;
for (i = 0; i < LENGTH(tags); i++) {
+ /* Do not draw vacant tags */
+ if(!(occ & 1 << i || m->tagset[m->seltags] & 1 << i))
+ continue;
w = TEXTW(tags[i]);
drw_setscheme(drw, scheme[m->tagset[m->seltags] & 1 << i ? SchemeSel : SchemeNorm]);
drw_text(drw, x, 0, w, bh, lrpad / 2, tags[i], urg & 1 << i, False);
- if (occ & 1 << i)
- drw_rect(drw, x + boxs, boxs, boxw, boxw,
- m == selmon && selmon->sel && selmon->sel->tags & 1 << i,
- urg & 1 << i);
x += w;
}
w = TEXTW(m->ltsymbol);
@@ -1089,11 +1101,25 @@ keypress(XEvent *e)
keys[i].func(&(keys[i].arg));
}
+int are_any_clients_running(){
+ for(Monitor* m = mons; m; m = m->next){
+ if(m->clients){
+ return 1;
+ }
+ }
+ return 0;
+}
void
killclient(const Arg *arg)
{
- if (!selmon->sel)
- return;
+ if (!selmon->sel){
+ // if there aren't any clients running on any monitor on any tag then the keybinding to close the current window instead closes dwm
+ // this workflow gives me more reason to go close all the windows which can complain that they have unsaved data.
+ if(!are_any_clients_running()){
+ quit(arg);
+ }
+ return;
+ }
if (!sendevent(selmon->sel, wmatom[WMDelete])) {
XGrabServer(dpy);
XSetErrorHandler(xerrordummy);
@@ -1459,14 +1485,70 @@ restack(Monitor *m)
XSync(dpy, False);
while (XCheckMaskEvent(dpy, EnterWindowMask, &ev));
}
+/**
+ returns 1 when XNextEvent should be called, in theory it can return 0 to abort dwm but
+ the only case where we can detect something going wrong happens for expected system interrupts so
+ we just continue on that case.
+
+ If the selected monitor does not have the status bar showing this returns immidiately to wait on an event,
+ otherwise it loops until XPending or 'select' suggests there is an X event to handle.
+
+ So as long as the bar is showing and there aren't X events to handle it will get the current time,
+ measure the time delta until the next clock update, and wait that amount of time such that an X event can interrupt it.
+ This means the clock is updated as infrequently as possible while still functioning seemlessly.
+
+ In order to work properly this does rely on updatestatus() to update the variable next_update to be in the future,
+ if that wasn't the case it would continuously redraw the statusbar
+
+*/
+int
+update_time(int x11_fd)
+{
+ struct timeval delta;
+ // if we are not showing the bar or there are pending events just go handle the next event
+ if(!selmon->showbar) return 1;
+ while(!XPending(dpy)){
+ clock_gettime(CLOCK_REALTIME, ¤t_time);
+ delta.tv_sec = next_update.tv_sec - current_time.tv_sec;
+ delta.tv_usec = (next_update.tv_nsec - current_time.tv_nsec)/1000 + 1;
+ if(delta.tv_usec < 0){
+ delta.tv_sec-=1;
+ delta.tv_usec+=1e6;
+ }
+ if(delta.tv_sec < 0){
+ updatestatus(); // if we've already passed the update time (like if handling an event took a while or we had the bar hidden)
+ continue;
+ }
+ // at this point we have a valid (positive) delta to wait on the select.
+ // Create a File Description Set containing x11_fd based on:
+ // https://stackoverflow.com/a/8592969/5827215
+ fd_set in_fds;
+ FD_ZERO(&in_fds);
+ FD_SET(x11_fd, &in_fds);
+
+ int num_ready_fds = select(x11_fd + 1, &in_fds, NULL, NULL, &delta);
+ if (num_ready_fds > 0){
+ return 1; // means there is data ready
+ } else if(num_ready_fds == 0){
+ clock_gettime(CLOCK_REALTIME, ¤t_time);
+ updatestatus(); // means timer expired, redraw clock and set a new timer
+ continue;
+ } else{
+ continue; // usually system interrupt or something non vital, go recheck XPending.
+ // if something has gone wrong with the select we will assume it will cause bigger issues for X and get caught there.
+ }
+ }
+ return 1;// if the loop broke it means XPending returned 1 while we were updating the clock
+}
void
run(void)
{
XEvent ev;
+ int x11_fd = ConnectionNumber(dpy);
/* main event loop */
XSync(dpy, False);
- while (running && !XNextEvent(dpy, &ev)){
+ while (running && update_time(x11_fd) && !XNextEvent(dpy, &ev)){
if (!(autostartcomplete || autostarttags))
autostarttagsspawner();
if (handler[ev.type])
@@ -1666,6 +1748,7 @@ setup(void)
scheme[i] = drw_scm_create(drw, colors[i], 3);
/* init bars */
updatebars();
+ clock_gettime(CLOCK_REALTIME, ¤t_time);
updatestatus();
/* supporting window for NetWMCheck */
wmcheckwin = XCreateSimpleWindow(dpy, root, 0, 0, 1, 1, 0, 0, 0);
@@ -1696,6 +1779,13 @@ seturgent(Client *c, int urg)
XWMHints *wmh;
c->isurgent = urg;
+ // if we are setting an urgent flag get the bar to be visible as if we started pressing the windows key.
+ // this is the non intrusive notification.
+ // See also updatewmhints
+ if (urg){
+ Arg a = {0}; //dummy so we have an argument
+ holdbar(&a);
+ }
if (!(wmh = XGetWMHints(dpy, c->win)))
return;
wmh->flags = urg ? (wmh->flags | XUrgencyHint) : (wmh->flags & ~XUrgencyHint);
@@ -1824,6 +1914,13 @@ togglebar(const Arg *arg)
}
void
+toggledoz(const Arg *arg)
+{
+ usedoz = !usedoz;
+ updatestatus();
+}
+
+void
togglefloating(const Arg *arg)
{
if (!selmon->sel)
@@ -2135,9 +2232,19 @@ updatesizehints(Client *c)
void
updatestatus(void)
{
- if (!gettextprop(root, XA_WM_NAME, stext, sizeof(stext)))
- strcpy(stext, "dwm-"VERSION);
- drawbar(selmon);
+ if (!gettextprop(root, XA_WM_NAME, stext, sizeof(stext))){
+ if(usedoz){
+ updatestatus_dozonal(stext, ¤t_time, &next_update);
+ } else {
+ updatestatus_regular(stext, ¤t_time, &next_update);
+ }
+ } else {
+ // if the status is set from the XA_WM_NAME variable then the code for updating the clock should probably be avoided entirely
+ // but it is easier to just set the time for the next update very far in the future.
+ // and rely on the un-setting of that variable to call this function (which it does) and therefore update the next_update time normally.
+ next_update.tv_sec = current_time.tv_sec + 10000;
+ }
+ drawbar(selmon);
}
void
@@ -2145,7 +2252,8 @@ updatetitle(Client *c)
{
if (!gettextprop(c->win, netatom[NetWMName], c->name, sizeof c->name))
gettextprop(c->win, XA_WM_NAME, c->name, sizeof c->name);
- if (c->name[0] == '\0') /* hack to mark broken clients */
+ // windows with emojis in their title seem to crash dwm, for now just display broken everywhere so I can actually have a usable workflow.
+ if (1)//(c->name[0] == '\0') /* hack to mark broken clients */
strcpy(c->name, broken);
}
@@ -2165,19 +2273,27 @@ void
updatewmhints(Client *c)
{
XWMHints *wmh;
-
+ int has_urgent = 0;
if ((wmh = XGetWMHints(dpy, c->win))) {
if (c == selmon->sel && wmh->flags & XUrgencyHint) {
wmh->flags &= ~XUrgencyHint;
XSetWMHints(dpy, c->win, wmh);
- } else
+ } else {
c->isurgent = (wmh->flags & XUrgencyHint) ? 1 : 0;
+ has_urgent = has_urgent | c->isurgent;
+ }
if (wmh->flags & InputHint)
c->neverfocus = !wmh->input;
else
c->neverfocus = 0;
XFree(wmh);
}
+ if(has_urgent){
+ // gives non intrusive notification when we have an urgent flag,
+ // see also seturgent
+ Arg a = {0};
+ holdbar(&a);
+ }
}
void
@@ -2340,6 +2456,11 @@ bstack(Monitor *m) {
w = (m->ww - mx) / (MIN(n, m->nmaster) - i);
resize(c, m->wx + mx, m->wy, w - (2 * c->bw), mh - (2 * c->bw), 0);
mx += WIDTH(c);
+ if(m->nmaster == 1 && HEIGHT(c) != mh){
+ // one main window that had an aspect ratio that allows more space
+ mh = HEIGHT(c);
+ ty = m->wy + mh;
+ }
} else {
h = m->wh - mh;
resize(c, tx, ty, tw - (2 * c->bw), h - (2 * c->bw), 0);
Common subdirectories: /gnu/store/qf41ki0f1508412bpnyvnj7sbli8zfyq-dwm-6.4-checkout/.git and /home/tadhg/src/dwm/.git
diff -up -N /gnu/store/qf41ki0f1508412bpnyvnj7sbli8zfyq-dwm-6.4-checkout/Makefile /home/tadhg/src/dwm/Makefile
--- /gnu/store/qf41ki0f1508412bpnyvnj7sbli8zfyq-dwm-6.4-checkout/Makefile 1969-12-31 19:00:01.000000000 -0500
+++ /home/tadhg/src/dwm/Makefile 2024-04-23 17:10:33.274202418 -0400
@@ -3,7 +3,7 @@
include config.mk
-SRC = drw.c dwm.c util.c
+SRC = drw.c dwm.c util.c status.c
OBJ = ${SRC:.c=.o}
all: options dwm
Common subdirectories: /gnu/store/qf41ki0f1508412bpnyvnj7sbli8zfyq-dwm-6.4-checkout/patches and /home/tadhg/src/dwm/patches
diff -up -N /gnu/store/qf41ki0f1508412bpnyvnj7sbli8zfyq-dwm-6.4-checkout/status.c /home/tadhg/src/dwm/status.c
--- /gnu/store/qf41ki0f1508412bpnyvnj7sbli8zfyq-dwm-6.4-checkout/status.c 1969-12-31 19:00:00.000000000 -0500
+++ /home/tadhg/src/dwm/status.c 2024-05-09 20:35:41.885339819 -0400
@@ -0,0 +1,168 @@
+#include <time.h>
+#include <string.h>
+#include <stdio.h>
+#include <stdarg.h>
+#include <math.h>
+#include "status.h"
+#include "util.h"
+
+// stolen from slstatus/util.c
+int
+pscanf(const char *path, const char *fmt, ...)
+{
+ FILE *fp;
+ va_list ap;
+ int n;
+
+ if (!(fp = fopen(path, "r"))) {
+ perror(path);
+ return -1;
+ }
+ va_start(ap, fmt);
+ n = vfscanf(fp, fmt, ap);
+ va_end(ap);
+ fclose(fp);
+
+ return (n == EOF) ? -1 : n;
+}
+
+
+#define CHARGE_NOW "/sys/class/power_supply/BAT1/charge_now"
+#define CHARGE_FULL "/sys/class/power_supply/BAT1/charge_full"
+#define CURRENT_DRAW "/sys/class/power_supply/BAT1/current_now"
+#define BAT_STATUS "/sys/class/power_supply/BAT1/status"
+
+struct battery_info {
+ double perc; // number from 0 to 1 for percentage filled
+ double hours_left; // number of hours left, negative if discharging and positive if charging
+};
+#define NAN_IF_NOT_ONE(X) if(X != 1){info.perc=NAN;info.hours_left=NAN;return info;}
+/** returns number of hours until complete,
+ negative when discharging positive when charging,
+ returns NAN on error */
+struct battery_info get_battery_status(void){
+ static double full = 0.0;
+ double charge, current;
+ char state[13];
+ struct battery_info info;
+ NAN_IF_NOT_ONE(pscanf(BAT_STATUS, "%12[a-zA-Z ]", state));
+ if(strncmp(state, "Not charging", 10) == 0 || strcmp(state, "Full") == 0){
+ info.perc = 1.0;
+ info.hours_left = 0.0;
+ return info;
+ }
+ NAN_IF_NOT_ONE(pscanf(CURRENT_DRAW, "%lf", ¤t));
+ NAN_IF_NOT_ONE(pscanf(CHARGE_NOW, "%lf", &charge));
+ if(full == 0.0){
+ NAN_IF_NOT_ONE(pscanf(CHARGE_FULL, "%lf", &full));
+ }
+ info.perc = charge/full;
+ if (!strcmp(state, "Discharging")){
+ // discharging so negate charge to be negative
+ info.hours_left = -charge / current;
+ } else if (!strcmp(state, "Charging")){
+ // full - charge_now will give positive value of how much we still need to charge.
+ info.hours_left = (full - charge)/current;
+ } else {
+ // if status isn't Charging, Discharging, or Full then I have no idea what is going on.
+ info.hours_left = NAN;
+ }
+ return info;
+}
+
+// dozonal characters specified by my own custom font
+// they are put in the range for "Ideographic Telegraph Symbol For Hour X" so theoretically some fonts that implement those won't be totally wrong.
+static const char *DOZ[] ={"\u3358", // 0
+ "\u3359", // 1
+ "\u335a", // 2
+ "\u335b", // 3
+ "\u335c", // 4
+ "\u335d", // 5
+ "\u335e", // 6
+ "\u335f", // 7
+ "\u3360", // 8
+ "\u3361", // 9
+ "\u3362", //10
+ "\u3363", //11
+ // 12 shouldn't be used in typical usage but full battery and leap seconds can hit this case.
+ // although for leap seconds I think it would end up being the 3rd digit that overflows given
+ // how the code below is structured.
+ "\u3364"};
+
+// used for seasons in the date system, this ordering seems the most natural to me for the quarters of the year roughly
+// matching seasons but if I wanted to use this system to save files I'd want to figure out symbols that have strictly
+// increasing unicode values for sorting.
+static const char *SUITS[] = {
+ "\u2666", // diamond
+ "\u2665", // heart
+ "\u2663", // club
+ "\u2660" // spade
+};
+/**
+ updates stext to show: (battery percentage, time until battery full/empty, date, time)
+ where the date uses my silly 4*13*7 + 1 system and the rest uses dozonal.
+ The battery "percentage" is really just twelves, the percentage symbol is kind of misleading but since the battery fraction
+ is the only thing that uses the percentage symbol it makes it clearer what it represents.
+ */
+void updatestatus_dozonal(char* stext, struct timespec *current_time, struct timespec *next_update){
+ struct tm *val = localtime(¤t_time->tv_sec);
+ int digAB = val->tm_hour*6 + val->tm_min/10;
+ int secs_left = (val->tm_min%10)*60 + val->tm_sec; // note due to leap seconds tm_sec can go up to 61
+
+ int digC = secs_left/50;
+ // ((seconds left%50 to nsec) + nanoseconds) / (50s to nsec) = fraction of dig3. multiplying by 144 gives it in terms of dig5.
+ long digDE = (((long)((secs_left%50) * 1e9) + current_time->tv_nsec) * 144 / 50e9);
+
+ int season = val->tm_yday/91;
+ if(season>3){season = 3;} // when yday is 364 or 365 we still want season to be the 4th one (0 indexed is 3)
+ int day_of_season = val->tm_yday - season*91;
+ char week = 'a'+(day_of_season/7); // will go to n0 for last day of year and n1 for leap year.
+ char day = '0'+val->tm_yday%7;
+
+ struct battery_info info = get_battery_status();
+
+ char charge_sign = info.hours_left == 0 ? '/' : info.hours_left > 0 ? '+' : '-';
+ int charge_digA = isnan(info.perc) ? 0 : (int)(info.perc*12.0);
+ int remaining_A, remaining_B, remaining_C;
+ if(isnan(info.hours_left)){
+ charge_sign = '?';
+ remaining_A = 0;
+ remaining_B = 0;
+ remaining_C = 0;
+ } else if(fabs(info.hours_left) >= 24.0){
+ remaining_A = 12;
+ remaining_B = 12;
+ remaining_C = 12;
+ } else{
+ int left = (int)(fabs(info.hours_left) * 72.0);
+ remaining_A = left/144;
+ remaining_B = (left/12)%12;
+ remaining_C = left%12;
+ }
+
+ sprintf(stext, "%s%% %c.%s%s%s %d%s%c%c.%s%s%s%s%s", DOZ[charge_digA], charge_sign, DOZ[remaining_A], DOZ[remaining_B], DOZ[remaining_C], val->tm_year+1900, SUITS[season], week, day, DOZ[digAB/12], DOZ[digAB%12], DOZ[digC], DOZ[digDE/12], DOZ[digDE%12]);
+
+ // and calculate the time that will next result in an update, next dig45
+ long ns_next = (digDE+1)*50e9/144 - (secs_left%50) * 1e9;
+ next_update->tv_sec = (ns_next < 1e9) ? current_time->tv_sec : current_time->tv_sec+1;
+ next_update->tv_nsec= (ns_next < 1e9) ? ns_next : ns_next-1e9;
+}
+/** updates stext to display same info as dozonal function above but using more typical numbering */
+void updatestatus_regular(char* stext, struct timespec *current_time, struct timespec *next_update){
+ struct tm *val = localtime(¤t_time->tv_sec);
+ struct battery_info info = get_battery_status();
+ int perc = (int)(info.perc*100.0);
+ int hours = (int)(info.hours_left);
+ int mins = (int)((info.hours_left - hours)*60);
+
+ if(info.hours_left != info.hours_left){
+ perc = -1;
+ hours = 888;
+ mins = 0;
+ } else if(mins < 0){
+ mins = -mins; // allow hours to display with negative but get minutes to be positive always.
+ }
+ sprintf(stext, " %2d%% %+dh %dm, %4d-%02d-%02d %2d:%02d:%02d",perc,hours,mins, val->tm_year+1900, val->tm_mon+1, val->tm_mday, val->tm_hour, val->tm_min, val->tm_sec);
+ next_update->tv_sec = current_time->tv_sec + 1;
+ next_update->tv_nsec = 0;
+}
diff -up -N /gnu/store/qf41ki0f1508412bpnyvnj7sbli8zfyq-dwm-6.4-checkout/status.h /home/tadhg/src/dwm/status.h
--- /gnu/store/qf41ki0f1508412bpnyvnj7sbli8zfyq-dwm-6.4-checkout/status.h 1969-12-31 19:00:00.000000000 -0500
+++ /home/tadhg/src/dwm/status.h 2024-04-23 17:22:37.540978117 -0400
@@ -0,0 +1,5 @@
+
+void updatestatus_dozonal(char* stext, struct timespec *current_time, struct timespec *next_update);
+
+void updatestatus_regular(char* stext, struct timespec *current_time, struct timespec *next_update);
+