-
Notifications
You must be signed in to change notification settings - Fork 23
/
dwm.c
7210 lines (6878 loc) · 319 KB
/
dwm.c
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
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
/* See LICENSE file for copyright and license details.
*
* dynamic window manager is designed like any other X client as well. It is
* driven through handling X events. In contrast to other X clients, a window
* manager selects for SubstructureRedirectMask on the root window, to receive
* events about window (dis-)appearance. Only one X connection at a time is
* allowed to select for this event mask.
*
* The event handlers of dwm are organized in an array which is accessed
* whenever a new event has been fetched. This allows event dispatching
* in O(1) time.
*
* Each child of the root window is called a client, except windows which have
* set the override_redirect flag. Clients are organized in a linked client
* list on each monitor, the focus history is remembered through a stack list
* on each monitor. Each client contains a bit array to indicate the tags of a
* client.
*
* Keys and tagging rules are organized as arrays and defined in config.h.
*
* Some general concepts and terminology:
*
* X
* The X Window System (X11, or simply X) is a windowing system for bitmap displays and is
* common on Unix-like operating systems. This provides the basic framework for a GUI
* environment and it handles the drawing and moving of windows as well as the interaction
* with a mouse and keyboard.
*
* Xlib
* An X Window System protocol client library written in C containing functions for
* interacting with an X server.
*
* Window
* A window is the graphical representation of a program. This is what you see and interact
* with when using your computer.
*
* Window Manager
* A window manager is a program that is responsible for controlling the placement and
* appearance of windows within a windowing system. It can be part of a desktop environment
* or be used on its own.
*
* Desktop Environment
* A desktop environment bundles together a variety of components to provide common graphical
* user interface elements such as icons, toolbars, wallpapers, and desktop widgets.
* Additionally, most desktop environments include a set of integrated applications and
* utilities.
*
* Typically desktop environments provide their own window manager and come with a built-in
* compositor for handling transparency and special effects when moving or switching between
* windows.
*
* Screen
* This can refer to a physical display, but in the context of dwm this can also refer to the
* visible screen space that is covered by the root window. This spans all physical monitors.
*
* Monitor
* In the context of dwm the Monitor represents the drawable area of the screen and holds
* properties such as the size and position of the screen as well as per-monitor settings
* such as the selected layout, the position of the bar as well as a list of the clients
* that are assigned to the given monitor.
*
* Client
* In the context of dwm the Client represents a window that is managed by the window
* manager. The client holds a series of properties such as the size and position of the
* window, various size restrictions, miscellaneous flags indicating state as well as
* references to other clients within the same workspace.
*
* A set of clients is represented in form of a linked list, which means that one client has
* a reference to the next, and so on.
*
* Layout
* In the context of dwm a Layout controls how clients are arranged (tiled) respective to
* other visible clients.
*
* Most layouts have a larger "master" area where the main window(s) of interest reside and
* one or more "stack" areas where the remaining windows are placed.
*
* Floating clients stay on top of tiled clients and remain in their floating position
* regardless of how other clients are tiled.
*
* Workspace
* In the context of window managers in general a workspace is what holds (or owns) a window
* or a set of windows. Conceptually dwm has one workspace per monitor and controls what
* clients are shown on that workspace through the use of tags. Each workspace can have a
* different layout.
*
* That dwm has workspaces generally goes unsaid due to the workspace being embedded into the
* monitor making it transparent to the user. If in doubt then note how the Monitor struct
* holds information that is unrelated to the screen space it occupies, as in it is used for
* more than one thing.
*
* For the sake of consistency we will be referring to the monitor rather than the workspace
* for all upcoming text.
*
* Tags
* In the context of dwm the visibility of clients are handled through the use of tags. In
* dwm the number of tags is user defined but limited to be between 1 and 32 tags. The number
* of tags will be the same on all monitors, but are controlled separately from monitor to
* monitor.
*
* Multiple tags can can be viewed at the same time on a monitor, and a client can be shown
* on multiple tags.
*
* The famous pertag patch for dwm enables a separate layout (and other options) to be set on
* a per tag basis. It works by keeping a record of what layout etc. is used on each
* individual tag. When you switch to another tag the settings for that tag is copied across
* to the Monitor. This creates a form of hybrid between workspaces and tags while taking
* away from the purity and concept behind tags.
*
* View
* In the context of dwm a view is the presentation of clients on a per-monitor basis.
*
* Bar
* The bar in dwm shows what tags are being viewed, what layout is used, the name of the
* selected client (if any) and a plain text status that will default to "dwm-<version>".
*
* EWMH
* The Extended Window Manager Hints is an X Window System standard for communication between
* window managers and the windows they manage. These standards formulate protocols for the
* mediation of access to shared X resources. Communication occurs via X properties and
* client messages. The EWMH is a comprehensive set of protocols to implement a desktop
* environment.
*
* dwm only supports a handful of EWMH properties and client messages out of the box.
*
* The event loop
* In X everything is event driven. What this means is that when you click on a window then
* that will generate an event that is propagated back to the window manager via the X server.
*
* The window manager tells the X server what types of events it is interested in receiving
* as well as what form of button or key presses the window manager is listening for.
*
* When a window wants to go into fullscreen then it sends a client message event indicating
* its desire to go into fullscreen. When you move a mouse cursor over a window then the
* window manager will receive a notification that the mouse cursor crossed over from one
* window to another. When a new window is created the window manager will receive an event
* to that effect, the same goes when a window is closed.
*
* When you hit the keybinding to focus on the next client then that will result in a key
* press event because the window manager told the X server that it was interested in getting
* such an event when the user hit MOD+k. When handling that event the window manager works
* out that it is associated with the focusstack function and calls that accordingly. When
* that action is complete it falls back to looking for new events to process.
*
* Once dwm hits the run function every action or operation that the window manager does
* after that is reacting to events received by the X server.
*
* To understand everything else, start reading main() as that is what sets everything up before
* entering the event loop.
*
* @see https://www.cl.cam.ac.uk/~mgk25/ucs/icccm.pdf
*
* Below is a high level call stack for dwm:
*
* main
* ├── checkotherwm
* ├── die
* ├── setup
* │ ├── ecalloc
* │ │ └── die
* │ ├── updategeom
* │ │ ├── ecalloc
* │ │ │ └── die
* │ │ ├── createmon
* │ │ │ └── ecalloc
* │ │ │ └── die
* │ │ ├── wintomon
* │ │ │ ├── wintoclient
* │ │ │ ├── rectomon
* │ │ │ └── getrootptr
* │ │ ├── updatebarpos
* │ │ └── isuniquegeom
* │ ├── drw_create
* │ │ └── ecalloc
* │ ├── drw_scm_create
* │ │ ├── drw_clr_create
* │ │ │ └── die
* │ │ └── ecalloc
* │ ├── drw_cur_create
* │ │ └── ecalloc
* │ ├── grabkeys
* │ │ └── updatenumlockmask
* │ ├── updatebars
* │ ├── focus
* │ └── drw_fontset_create
* │ └── xfont_create
* │ └── ecalloc
* ├── scan
* │ └── getstate
* ├── run
* │ ├── propertynotify
* │ │ ├── wintoclient
* │ │ ├── updatewmhints
* │ │ ├── updatetitle
* │ │ │ └── gettextprop
* │ │ ├── updatestatus
* │ │ │ ├── gettextprop
* │ │ │ └── drawbar
* │ │ ├── updatewindowtype
* │ │ │ └── getatomprop
* │ │ ├── drawbar
* │ │ ├── drawbars
* │ │ │ └── drawbar
* │ │ └── arrange
* │ ├── unmapnotify
* │ │ ├── wintoclient
* │ │ ├── unmanage
* │ │ │ ├── updateclientlist
* │ │ │ ├── setclientstate
* │ │ │ ├── focus
* │ │ │ ├── detachstack
* │ │ │ ├── detach
* │ │ │ └── arrange
* │ │ └── setclientstate
* │ ├── enternotify
* │ │ ├── wintoclient
* │ │ ├── wintomon
* │ │ │ ├── wintoclient
* │ │ │ └── recttomon
* │ │ ├── unfocus
* │ │ └── focus
* │ ├── destroynotify
* │ │ ├── wintoclient
* │ │ └── unmanage
* │ │ ├── updateclientlist
* │ │ ├── setclientstate
* │ │ ├── focus
* │ │ ├── detachstack
* │ │ ├── detach
* │ │ └── arrange
* │ ├── maprequest
* │ │ ├── manage
* │ │ │ ├── ecalloc
* │ │ │ │ └── die
* │ │ │ ├── wintoclient
* │ │ │ ├── updatewmhints
* │ │ │ ├── updatesizehints
* │ │ │ ├── grabbuttons
* │ │ │ │ └── updatenumlockmask
* │ │ │ ├── unfocus
* │ │ │ ├── setclientstate
* │ │ │ ├── updatetitle
* │ │ │ │ └── gettextprop
* │ │ │ ├── updatewindowtype
* │ │ │ │ └── getatomprop
* │ │ │ ├── focus
* │ │ │ ├── configure
* │ │ │ ├── attachstack
* │ │ │ ├── attach
* │ │ │ ├── arrange
* │ │ │ └── applyrules
* │ │ └── wintoclient
* │ ├── clientmessage
* │ │ ├── wintoclient
* │ │ ├── seturgent
* │ │ └── setfullscreen
* │ │ ├── resizeclient
* │ │ └── arrange
* │ ├── configurerequest
* │ │ ├── wintoclient
* │ │ └── configure
* │ ├── buttonpress
* │ │ ├── wintoclient
* │ │ ├── wintomon
* │ │ │ ├── wintoclient
* │ │ │ └── recttomon
* │ │ ├── unfocus
* │ │ ├── spawn
* │ │ │ └── die
* │ │ ├── togglefloating
* │ │ │ ├── resize
* │ │ │ └── arrange
* │ │ ├── resizemouse
* │ │ │ ├── sendmon
* │ │ │ │ ├── unfocus
* │ │ │ │ ├── focus
* │ │ │ │ ├── detachstack
* │ │ │ │ ├── detach
* │ │ │ │ ├── attachstack
* │ │ │ │ ├── attach
* │ │ │ │ └── arrange
* │ │ │ ├── resize
* │ │ │ ├── recttomon
* │ │ │ ├── maprequest
* │ │ │ ├── focus
* │ │ │ ├── expose
* │ │ │ ├── restack
* │ │ │ │ └── drawbar
* │ │ │ ├── configurerequest
* │ │ │ └── togglefloating
* │ │ │ └── arrange
* │ │ ├── movemouse
* │ │ │ ├── sendmon
* │ │ │ │ ├── unfocus
* │ │ │ │ ├── focus
* │ │ │ │ ├── detachstack
* │ │ │ │ ├── detach
* │ │ │ │ ├── attachstack
* │ │ │ │ ├── attach
* │ │ │ │ └── arrange
* │ │ │ ├── resize
* │ │ │ ├── recttomon
* │ │ │ ├── maprequest
* │ │ │ ├── getrootptr
* │ │ │ ├── focus
* │ │ │ ├── expose
* │ │ │ ├── restack
* │ │ │ │ └── drawbar
* │ │ │ ├── configurerequest
* │ │ │ └── togglefloating
* │ │ │ └── arrange
* │ │ ├── view
* │ │ │ ├── focus
* │ │ │ └── arrange
* │ │ ├── toggleview
* │ │ │ ├── focus
* │ │ │ └── arrange
* │ │ ├── toggletag
* │ │ │ ├── focus
* │ │ │ └── arrange
* │ │ ├── tag
* │ │ │ ├── focus
* │ │ │ └── arrange
* │ │ ├── focus
* │ │ ├── setlayout
* │ │ │ └── drawbar
* │ │ ├── restack
* │ │ │ └── drawbar
* │ │ └── drw_fontset_getwidth
* │ │ └── drw_text
* │ │ ├── die
* │ │ ├── drw_font_getexts
* │ │ └── xfont_free
* │ ├── configurenotify
* │ │ ├── updategeom
* │ │ │ ├── ecalloc
* │ │ │ │ └── die
* │ │ │ ├── createmon
* │ │ │ │ └── ecalloc
* │ │ │ │ └── die
* │ │ │ ├── wintomon
* │ │ │ │ ├── wintoclient
* │ │ │ │ ├── rectomon
* │ │ │ │ └── getrootptr
* │ │ │ ├── updatebarpos
* │ │ │ ├── isuniquegeom
* │ │ │ ├── detachstack
* │ │ │ ├── cleanupmon
* │ │ │ ├── attachstack
* │ │ │ └── attach
* │ │ ├── drw_resize
* │ │ ├── updatebars
* │ │ ├── resizeclient
* │ │ ├── focus
* │ │ └── arrange
* │ ├── keypress
* │ │ ├── focusmon
* │ │ │ ├── unfocus
* │ │ │ ├── focus
* │ │ │ └── dirtomon
* │ │ ├── spawn
* │ │ │ └── die
* │ │ ├── togglefloating
* │ │ │ ├── resize
* │ │ │ └── arrange
* │ │ ├── quit
* │ │ ├── zoom
* │ │ │ ├── nexttiled
* │ │ │ └── pop
* │ │ │ ├── focus
* │ │ │ ├── detach
* │ │ │ ├── attach
* │ │ │ └── arrange
* │ │ ├── killclient
* │ │ │ └── sendevent
* │ │ ├── view
* │ │ │ ├── focus
* │ │ │ └── arrange
* │ │ ├── toggleview
* │ │ │ ├── focus
* │ │ │ └── arrange
* │ │ ├── toggletag
* │ │ │ ├── focus
* │ │ │ └── arrange
* │ │ ├── tag
* │ │ │ ├── focus
* │ │ │ └── arrange
* │ │ ├── focusstack
* │ │ │ ├── focus
* │ │ │ └── restack
* │ │ │ └── drawbar
* │ │ ├── setlayout
* │ │ │ ├── drawbar
* │ │ │ └── arrange
* │ │ ├── tagmon
* │ │ │ ├── sendmon
* │ │ │ │ ├── unfocus
* │ │ │ │ ├── focus
* │ │ │ │ ├── detachstack
* │ │ │ │ ├── detach
* │ │ │ │ ├── attachstack
* │ │ │ │ ├── attach
* │ │ │ │ └── arrange
* │ │ │ └── dirtomon
* │ │ ├── togglebar
* │ │ │ └── arrange
* │ │ ├── setmfact
* │ │ │ └── arrange
* │ │ └── incnmaster
* │ │ └── arrange
* │ ├── focusin
* │ │ └── setfocus
* │ │ └── sendevent
* │ ├── expose
* │ │ ├── wintomon
* │ │ │ ├── wintoclient
* │ │ │ └── recttomon
* │ │ └── drawbar
* │ ├── motionnotify
* │ │ ├── recttomon
* │ │ └── focus
* │ ├── scan
* │ │ └── manage
* │ │ └── ecalloc
* │ │ └── die
* │ ├── mappingnotify
* │ │ └── grabkeys
* │ │ └── updatenumlockmask
* │ ├── setup
* │ │ └── updatestatus
* │ │ ├── gettextprop
* │ │ └── drawbar
* │ └── updatewindowtype
* │ └── setfullscreen
* │ ├── resizeclient
* │ └── arrange
* └── cleanup
* ├── unmanage
* │ └── updateclientlist
* ├── view
* │ ├── focus
* │ └── arrange
* ├── cleanupmon
* ├── drw_cur_free
* └── drw_free
* └── drw_fontset_free
* ├── drw_fontset_free
* └── xfont_free
*
* The above skips details for commonly called functions like drawbar, resize, arrange, focus and
* unfocus.
*/
#include <errno.h>
#include <locale.h>
#include <signal.h>
#include <stdarg.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <X11/cursorfont.h>
#include <X11/keysym.h>
#include <X11/Xatom.h>
#include <X11/Xlib.h>
#include <X11/Xproto.h>
#include <X11/Xutil.h>
#ifdef XINERAMA
#include <X11/extensions/Xinerama.h>
#endif /* XINERAMA */
#include <X11/Xft/Xft.h>
#include "drw.h"
#include "util.h"
/* macros */
/* The BUTTONMASK macro is used as part of the MOUSEMASK macro and it is directly used in the
* grabbuttons function. It indicates that we are interested in receiving events both when a mouse
* button is pressed and when it is released. */
#define BUTTONMASK (ButtonPressMask|ButtonReleaseMask)
/* The CLEANMASK macro removes Num Lock mask and Lock mask from a given bit mask.
* Refer to the numlockmask variable comment for more details on the Num Lock mask.
* The CLEANMASK macro is used in the keypress and buttonpress functions. */
#define CLEANMASK(mask) (mask & ~(numlockmask|LockMask) & (ShiftMask|ControlMask|Mod1Mask|Mod2Mask|Mod3Mask|Mod4Mask|Mod5Mask))
/* Calculates how much a monitor's window area intersects with a given size and position.
* See the writeup in the recttomon function for more information on this. */
#define INTERSECT(x,y,w,h,m) (MAX(0, MIN((x)+(w),(m)->wx+(m)->ww) - MAX((x),(m)->wx)) \
* MAX(0, MIN((y)+(h),(m)->wy+(m)->wh) - MAX((y),(m)->wy)))
/* This macro returns true if any of the given client's tags is on any of the tags currently being
* viewed on the monitor. */
#define ISVISIBLE(C) ((C->tags & C->mon->tagset[C->mon->seltags]))
/* The MOUSEMASK macro is used in the movemouse and resizemouse user functions and it indicates
* that we are interested in receiving events when the mouse cursor moves in addition to when the
* button is released. */
#define MOUSEMASK (BUTTONMASK|PointerMotionMask)
/* The actual width of a client window includes the border and this macro helps calculate that. */
#define WIDTH(X) ((X)->w + 2 * (X)->bw)
/* The actual height of a client window includes the border and this macro helps calculate that. */
#define HEIGHT(X) ((X)->h + 2 * (X)->bw)
/* The TAGMASK macro gives a binary value that represents a valid bitmask according to how many
* tags are defined.
*
* As an example dwm by default comes with nine tags and the bitmask is a 32 bit integer. In this
* case the TAGMASK macro would return a binary value like this:
*
* 00000000000000000000000111111111
*
* but if the configuration was changed so that there are icons defined for four tags then the
* TAGMASK macro would return a binary value like this:
*
* 00000000000000000000000000001111
*
* The TAGMASK is used in various places to restrict and to validate bitmask values used in the
* context of what tags are viewed by the monitor and what tags are assigned to a client.
*/
#define TAGMASK ((1 << LENGTH(tags)) - 1)
/* The TEXTW macro returns the width of a given text string plus the left and right padding.
*
* Due to that not all fonts have every glyph and we have a primary font and fallback fonts this
* macro calls drw_fontset_getwidth which does the exact same thing as when text is drawn, just
* that it returns how far the cursor has moved rather than actually drawing the text. */
#define TEXTW(X) (drw_fontset_getwidth(drw, (X)) + lrpad)
/* Enumerators (enums) are user defined data types in C. They are mainly used to assign names to
* integral constants to make a program easier to read and maintain.
*
* As an example the below cursor enum would result in CurNormal having a value of 0, CurResize
* having a value of 1 and CurMove having a value of 2. Often an additional constant is added to
* an enum representing the last of the given type, e.g. CurLast having a value of 3.
*
* The last value is commonly used when needing to looping through the various options / constants.
* It is possible to specify the value of each constant, but this is not used here.
*/
enum { CurNormal, CurResize, CurMove, CurLast }; /* cursor */
/* If you need to add your own colour schemes then this is where you would add them. */
enum { SchemeNorm, SchemeSel }; /* color schemes */
/* This represents the various extended window manager hint atoms that dwm supports. */
enum { NetSupported, NetWMName, NetWMState, NetWMCheck,
NetWMFullscreen, NetActiveWindow, NetWMWindowType,
NetWMWindowTypeDialog, NetClientList, NetLast }; /* EWMH atoms */
/* This represents various window manager hint atoms that dwm supports. */
enum { WMProtocols, WMDelete, WMState, WMTakeFocus, WMLast }; /* default atoms */
/* This represents the various click options that can be used when defining mouse button press
* bindings in the buttons array in the configuration file. */
enum { ClkTagBar, ClkLtSymbol, ClkStatusText, ClkWinTitle,
ClkClientWin, ClkRootWin, ClkLast }; /* clicks */
/* In C, a struct(ure) can be thought of as a user defined data type. They define how much space
* is needed to allocate memory to hold values for each of the variables inside the structure.
*
* While arrays allow for variables that can hold several data types of the same kind to be
* defined, a structure allows for data items of different kinds to be defined.
*
* A union is conceptually similar to structures, with the difference being that of memory
* allocation. In a structure each variable (also referred to as a member) has allocated space
* whereas in a union all the variables share the same memory. The Arg type that are passed to
* user functions is a union which means that the argument can be an integer, an unsigned integer,
* a float value or a pointer, but the argument can only hold a single value.
*/
typedef union {
int i;
unsigned int ui;
float f;
const void *v;
} Arg;
/* The definition of a button, used in the configuration file when setting up mouse button
* bindings.
*
* static Button buttons[] = {
* // click event mask button function argument
* { ClkLtSymbol, 0, Button1, setlayout, {0} },
* { ClkLtSymbol, 0, Button3, setlayout, {.v = &layouts[2]} },
* ...
* };
*/
typedef struct {
unsigned int click;
unsigned int mask;
unsigned int button;
void (*func)(const Arg *arg);
const Arg arg;
} Button;
/* Here we are declaring that we are going to have a struct called Monitor without going into
* details of what exactly this struct looks like. This is because the Client struct refers to
* the current monitor, while the monitor is going to have a list of clients. We define these
* structs alphabetically thus the Client is defined before the Monitor. */
typedef struct Monitor Monitor;
typedef struct Client Client;
/* The Client struct represents a window that is managed by the window manager. */
struct Client {
/* The name holds the window title. */
char name[256];
/* The mina and maxa represents the minimum and maximum aspect ratios as per size hints. */
float mina, maxa;
/* The client x, y coordinates and size (width, height). */
int x, y, w, h;
/* These variables represent the client's previous size and position and they are maintained
* in the resizeclient function. In practice in a stock dwm they are only used when a
* fullscreen window exits fullscreen. */
int oldx, oldy, oldw, oldh;
/* These variables are all in relation to size hints.
* basew - base width
* baseh - base height
* incw - width increment
* inch - height increment
* minw - minimum width
* minh - minimum height
* maxw - maximum width
* maxh - maximum height
* hintsvalid - flag indicating whether size hints need to be refreshed
*/
int basew, baseh, incw, inch, maxw, maxh, minw, minh, hintsvalid;
/* Border width (bw) and old border width. The old border width is set in the manage
* function and is used in the unmanage function in the event that the window was not
* destroyed. The setfullscreen function also relies on this variable. See comment in the
* unmanage function. */
int bw, oldbw;
/* This represents the tags the client is shown on. This is a bitmask where each bit
* represents whether the client is shown on that tag.
*
* As an example consider the hexadecimal value of 0x51 (decimal 81) which has a binary
* value of:
* 001010001 - bitmask
* 987654321 - tags
*
* This would mean that the client is shown on tags 1, 5 and 7.
*/
unsigned int tags;
/* Various status flags.
* isfixed - means that the client is fixed in size due to minimum and maximum size
* hints being the same value
* isfloating - indicates whether the client is floating or not
* isurgent - indicates whether the client is urgent or not
* neverfocus - some windows do not want the window manager to give them input focus as
* they are mere passive windows that do not handle any input, the
* neverfocus indicates that the client should never receive input focus
* as indicated by the window manager hints for the window
* (see updatewmhints and setfocus functions)
* oldstate - represents the previous state in the event that the client goes into
* fullscreen, the variable is only used to indicate whether the client
* was floating or not
* isfullscreen - indicates whether the window is in fullscreen
*/
int isfixed, isfloating, isurgent, neverfocus, oldstate, isfullscreen;
/* The next client in the client list, which is a linked list. The client list controls the
* order in which clients are tiled. */
Client *next;
/* The next client in the stacking order list, which is also a linked list. The stacking
* order indicates which window is on top of others as well as the order in which clients
* had focus. */
Client *snext;
/* The monitor this client belongs to. */
Monitor *mon;
/* The managed window that this client represents. */
Window win;
};
/* The definition of a key, used in the configuration file when setting up key bindings.
*
* static Key keys[] = {
* // modifier key function argument
* { MODKEY, XK_d, incnmaster, {.i = -1 } },
* { MODKEY, XK_h, setmfact, {.f = -0.05} },
* ...
* };
*/
typedef struct {
unsigned int mod;
KeySym keysym;
void (*func)(const Arg *);
const Arg arg;
} Key;
/* The definition of a layout, used in the configuration file when setting up layouts.
*
* static const Layout layouts[] = {
* // symbol arrange function
* { "[]=", tile }, // first entry is default
* { "><>", NULL }, // no layout function means floating behavior
* { "[M]", monocle },
* };
*/
typedef struct {
const char *symbol;
void (*arrange)(Monitor *);
} Layout;
/* This represents individual monitors (screens) if Xinerama is used, or a single monitor
* representing the entire screen space if Xinerama is not enabled. */
struct Monitor {
/* This holds the layout symbol text, typically as defined in the layouts array. This is
* used when drawing the layout symbol on the bar. The reason why this is defined for the
* monitor rather than simply using the layout symbol as defined in the layouts array is
* that some layouts, like the monocle layout for example, may alter the layout symbol
* depending on how many clients are present. */
char ltsymbol[16];
/* The master / stack factor which controls how big a proportion of the window tiling area
* is reserved for the master area compared to the stack area. The default value is
* configured in the configuration file and the value is adjusted via the setmfact function.
* The value has a range from 0.05 to 0.95. */
float mfact;
/* This represents the number of clients that are to be tiled in the master area. This has
* no upper limit but cannot be less than 0. The default value is configured in the
* configuration file and the value is adjusted via the incnmaster function. */
int nmaster;
/* This represents the monitor number, or the monitor index if you wish. */
int num;
/* The by variable defines the bar windows position on the y axis and this is set in the
* updatebarpos function. */
int by; /* bar geometry */
/* These variables represents the position and dimensions of the monitor.
* mx - monitor position on the x-axis
* my - monitor position on the y-axis
* mw - the monitor's width
* mh - the monitor's height
*/
int mx, my, mw, mh; /* screen size */
/* These variables represents the position and dimensions of the window area, as in the part
* of the monitor where windows are tiled. This is the space of the monitor excluding the
* bar window. These are set in the updatebarpos function.
* wx - window area position on the x-axis
* wy - window area position on the y-axis
* ww - the window area's width
* wh - the window area's height
*/
int wx, wy, ww, wh; /* window area */
/* The seltags variable is either 0 or 1 and represents the currently selected tagset.
*
* This allows for a clever mechanism where one can easily flip between the current and
* previous tagset by simply flipping the value of seltags:
*
* selmon->seltags ^= 1;
*
* For this reason when referring to the selected tags for a monitor you will often find
* these kind of patterns:
*
* m->tagset[m->seltags]
* selmon->tagset[selmon->seltags]
* c->mon->tagset[c->mon->seltags]
*
* In principle this could just have been defined as two variables for the monitor.
*
* m->tags
* m->prevtags
*
* which would make the above patterns slightly easier to read, i.e.
*
* m->tags
* selmon->tags
* c->mon->tags
*
* The benefit of using this mechanism, however, is that we save on a single line of code
* in the view function when the argument is 0 and we toggle back to the previous view.
*/
unsigned int seltags;
/* The sellt variable is either 0 or 1 and represents the currently selected layout. This
* follows the same mechanism as seltags above giving patterns such a:
*
* m->lt[m->sellt]
* selmon->lt[selmon->sellt]
* c->mon->lt[c->mon->sellt]
*/
unsigned int sellt;
/* This array holds the previously and currently viewed tags for the monitor, the index of
* which is indicated by the seltags variable. */
unsigned int tagset[2];
/* Internal flag indicating whether the bar is shown or not. */
int showbar;
/* Internal flag indicating whether the bar is shown at the top or at the bottom. */
int topbar;
/* The client list. This represents the start of a linked list of clients which determines
* the order in which clients are tiled. */
Client *clients;
/* This represents the monitor's selected client. */
Client *sel;
/* The stacking order list. This represents the order in which client windows are stacked on
* top of each other, as well as the order in which clients had last focus. */
Client *stack;
/* Monitors are also managed as a linked list with the mons variable referring to the first
* monitor. The next variable on the monitor refers to the next monitor in the list. */
Monitor *next;
/* This is the bar window which is used to draw the bar. Each monitor has their own bar. */
Window barwin;
/* This array holds the previous and current layout for the monitor, the index of which is
* indicated by the sellt variable. */
const Layout *lt[2];
};
/* The definition of a rule, used in the configuration file when setting up client rules.
*
* 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 },
* };
*
* See the applyrules function for how the rules are applied.
*/
typedef struct {
const char *class;
const char *instance;
const char *title;
unsigned int tags;
int isfloating;
int monitor;
} Rule;
/* Function declarations. All functions are declared for visibility and overview reasons. The
* declarations as well as the functions themselves are sorted alphabetically so that they should
* be easier to find and maintain. */
static void applyrules(Client *c);
static int applysizehints(Client *c, int *x, int *y, int *w, int *h, int interact);
static void arrange(Monitor *m);
static void arrangemon(Monitor *m);
static void attach(Client *c);
static void attachstack(Client *c);
static void buttonpress(XEvent *e);
static void checkotherwm(void);
static void cleanup(void);
static void cleanupmon(Monitor *mon);
static void clientmessage(XEvent *e);
static void configure(Client *c);
static void configurenotify(XEvent *e);
static void configurerequest(XEvent *e);
static Monitor *createmon(void);
static void destroynotify(XEvent *e);
static void detach(Client *c);
static void detachstack(Client *c);
static Monitor *dirtomon(int dir);
static void drawbar(Monitor *m);
static void drawbars(void);
static void enternotify(XEvent *e);
static void expose(XEvent *e);
static void focus(Client *c);
static void focusin(XEvent *e);
static void focusmon(const Arg *arg);
static void focusstack(const Arg *arg);
static Atom getatomprop(Client *c, Atom prop);
static int getrootptr(int *x, int *y);
static long getstate(Window w);
static int gettextprop(Window w, Atom atom, char *text, unsigned int size);
static void grabbuttons(Client *c, int focused);
static void grabkeys(void);
static void incnmaster(const Arg *arg);
static void keypress(XEvent *e);
static void killclient(const Arg *arg);
static void manage(Window w, XWindowAttributes *wa);
static void mappingnotify(XEvent *e);
static void maprequest(XEvent *e);
static void monocle(Monitor *m);
static void motionnotify(XEvent *e);
static void movemouse(const Arg *arg);
static Client *nexttiled(Client *c);
static void pop(Client *c);
static void propertynotify(XEvent *e);
static void quit(const Arg *arg);
static Monitor *recttomon(int x, int y, int w, int h);
static void resize(Client *c, int x, int y, int w, int h, int interact);
static void resizeclient(Client *c, int x, int y, int w, int h);
static void resizemouse(const Arg *arg);
static void restack(Monitor *m);
static void run(void);
static void scan(void);
static int sendevent(Client *c, Atom proto);
static void sendmon(Client *c, Monitor *m);
static void setclientstate(Client *c, long state);
static void setfocus(Client *c);
static void setfullscreen(Client *c, int fullscreen);
static void setlayout(const Arg *arg);
static void setmfact(const Arg *arg);
static void setup(void);
static void seturgent(Client *c, int urg);
static void showhide(Client *c);
static void spawn(const Arg *arg);
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 togglefloating(const Arg *arg);
static void toggletag(const Arg *arg);
static void toggleview(const Arg *arg);
static void unfocus(Client *c, int setfocus);
static void unmanage(Client *c, int destroyed);
static void unmapnotify(XEvent *e);
static void updatebarpos(Monitor *m);
static void updatebars(void);
static void updateclientlist(void);
static int updategeom(void);
static void updatenumlockmask(void);
static void updatesizehints(Client *c);
static void updatestatus(void);
static void updatetitle(Client *c);
static void updatewindowtype(Client *c);
static void updatewmhints(Client *c);
static void view(const Arg *arg);
static Client *wintoclient(Window w);
static Monitor *wintomon(Window w);
static int xerror(Display *dpy, XErrorEvent *ee);
static int xerrordummy(Display *dpy, XErrorEvent *ee);
static int xerrorstart(Display *dpy, XErrorEvent *ee);
static void zoom(const Arg *arg);
/* variables */
/* This is used as a fallback text for windows that do not have a windwow title / name set */
static const char broken[] = "broken";
/* This array of characters holds the status text */
static char stext[256];
/* This holds the default screen value, used when creating windows and handling the display etc. */
static int screen;
static int sw, sh; /* X display screen geometry width, height */
static int bh; /* bar height */
static int lrpad; /* sum of left and right padding for text */
/* This is the reference we store the X error handler in and it is used in the xerror function for
* any errors that are not simply ignored. Search the code for xerrorxlib to see how this set and
* used. */
static int (*xerrorxlib)(Display *, XErrorEvent *);
/* The static global numlockmask variable that holds the modifier that is related to the
* Num Lock key.
*
* This is set in the updatenumlockmask function based on the presence of the Num Lock key in the
* modifier map. This is then later used to subscribe to KeyPress and ButtonPress events involving
* the Num Lock keys in the grabkeys and grabbuttons functions.
*
* Additionally the variable is used in the CLEANMASK macro which omits the Num Lock and Caps Lock
* modifiers from a given modifier mask. This macro is then used in both the buttonpress and
* keypress functions to ignore Num Lock and Caps Lock when looking for matching keypress or button
* press combinations.
*/
static unsigned int numlockmask = 0;
/* This is what maps event types to the functions that handles those event types.
*
* This is primarily used in the run function which handles the event loop, but it is also used
* in the movemouse and resizemouse functions that temporarily hooks into the event loop for a few
* select event types while client windows are being moved or resized.
*/
static void (*handler[LASTEvent]) (XEvent *) = {
[ButtonPress] = buttonpress,
[ClientMessage] = clientmessage,
[ConfigureRequest] = configurerequest,
[ConfigureNotify] = configurenotify,
[DestroyNotify] = destroynotify,
[EnterNotify] = enternotify,
[Expose] = expose,
[FocusIn] = focusin,
[KeyPress] = keypress,
[MappingNotify] = mappingnotify,
[MapRequest] = maprequest,
[MotionNotify] = motionnotify,
[PropertyNotify] = propertynotify,
[UnmapNotify] = unmapnotify
};
/* This initialises the wmatom and netatom arrays which holds X atom references */
static Atom wmatom[WMLast], netatom[NetLast];
/* The global running variable indicates whether the window manager is running. When set to 0 then
* the window manager will exit out of the event loop in the run function and make dwm exit the
* process gracefully. */
static int running = 1;
/* This holds the various mouse cursor types used by the window manager. */
static Cur *cursor[CurLast];
/* This holds a reference to the array of colour schemes. */
static Clr **scheme;
/* This holds a reference to the display that we have opened. */
static Display *dpy;
/* This holds a reference to the drawable that we have created. Refer to the struct definition in
* the drw.h file. */
static Drw *drw;
/* Two references to hold the first and the selected monitor. */
static Monitor *mons, *selmon;
/* Two window references, one for the root window and one for the supporting window. More on the
* latter in the setup function. */
static Window root, wmcheckwin;
/* Configuration, allows nested code to access above variables */
#include "config.h"
/* Compile-time check if all tags fit into an unsigned int bit array. This causes a compilation
* error if the user has added more than 31 entries in the tags array. This NumTags struct does
* not actually cost anything because the compiler is free to discard it as it is not used by
* anything. */
struct NumTags { char limitexceeded[LENGTH(tags) > 31 ? -1 : 1]; };
/* Function implementations. Functions are ordered alphabetically and function names always
* start on a new line to make them easier to find. */
/* This function applies client rules for a client window.
*
* Example rules from the default configuration:
*