1 /* See LICENSE file for copyright and license details.
3 * This is a port of the popular X11 window manager dwm to Microsoft Windows.
4 * It was originally started by Marc Andre Tanner <mat at brain-dump dot org>
6 * Each child of the root window is called a client. Clients are organized
7 * in a global linked client list, the focus history is remembered through
8 * a global stack list. Each client contains a bit array to indicate the
11 * Keys and tagging rules are organized as arrays and defined in config.h.
13 * To understand everything else, start reading main().
16 #define WIN32_LEAN_AND_MEAN
17 #define _WIN32_WINNT 0x0500
26 #define NAME "dwm-win32" /* Used for window name/class */
29 #define ISVISIBLE(x) ((x)->tags & tagset[seltags])
30 #define ISFOCUSABLE(x) (!(x)->isminimized && ISVISIBLE(x) && IsWindowVisible((x)->hwnd))
31 #define LENGTH(x) (sizeof x / sizeof x[0])
32 #define MAX(a, b) ((a) > (b) ? (a) : (b))
33 #define MIN(a, b) ((a) < (b) ? (a) : (b))
35 #define WIDTH(x) ((x)->w + 2 * (x)->bw)
36 #define HEIGHT(x) ((x)->h + 2 * (x)->bw)
37 #define TAGMASK ((int)((1LL << LENGTH(tags)) - 1))
38 #define TEXTW(x) (textnw(x, strlen(x)))
40 # define debug(format, args...) do { } while(false)
46 enum { CurNormal
, CurResize
, CurMove
, CurLast
}; /* cursor */
47 enum { ColBorder
, ColFG
, ColBG
, ColLast
}; /* color */
48 enum { ClkTagBar
, ClkLtSymbol
, ClkStatusText
, ClkWinTitle
}; /* clicks */
52 unsigned long norm
[ColLast
];
53 unsigned long sel
[ColLast
];
55 } DC
; /* draw context */
70 void (*func
)(const Arg
*arg
);
74 typedef struct Client Client
;
81 int bw
; // XXX: useless?
89 bool isfixed
, isurgent
; // XXX: useless?
97 void (*func
)(const Arg
*);
103 void (*arrange
)(void);
113 /* function declarations */
114 static void applyrules(Client
*c
);
115 static void arrange(void);
116 static void attach(Client
*c
);
117 static void attachstack(Client
*c
);
118 static void cleanup();
119 static void clearurgent(Client
*c
);
120 static void detach(Client
*c
);
121 static void detachstack(Client
*c
);
122 static void die(const char *errstr
, ...);
123 static void drawbar(void);
124 static void drawsquare(bool filled
, bool empty
, bool invert
, unsigned long col
[ColLast
]);
125 static void drawtext(const char *text
, unsigned long col
[ColLast
], bool invert
);
126 void drawborder(Client
*c
, COLORREF color
);
127 void eprint(const char *errstr
, ...);
128 static void focus(Client
*c
);
129 static void focusstack(const Arg
*arg
);
130 static Client
*getclient(HWND hwnd
);
131 LPSTR
getclientclassname(HWND hwnd
);
132 LPSTR
getclienttitle(HWND hwnd
);
133 HWND
getroot(HWND hwnd
);
134 static void grabkeys(HWND hwnd
);
135 static void killclient(const Arg
*arg
);
136 static Client
*manage(HWND hwnd
);
137 static void monocle(void);
138 static Client
*nextchild(Client
*p
, Client
*c
);
139 static Client
*nexttiled(Client
*c
);
140 static void quit(const Arg
*arg
);
141 static void resize(Client
*c
, int x
, int y
, int w
, int h
);
142 static void restack(void);
143 static BOOL CALLBACK
scan(HWND hwnd
, LPARAM lParam
);
144 static void setborder(Client
*c
, bool border
);
145 static void setvisibility(HWND hwnd
, bool visibility
);
146 static void setlayout(const Arg
*arg
);
147 static void setmfact(const Arg
*arg
);
148 static void setup(HINSTANCE hInstance
);
149 static void setupbar(HINSTANCE hInstance
);
150 static void showclientclassname(const Arg
*arg
);
151 static void showhide(Client
*c
);
152 static void spawn(const Arg
*arg
);
153 static void tag(const Arg
*arg
);
154 static int textnw(const char *text
, unsigned int len
);
155 static void tile(void);
156 static void togglebar(const Arg
*arg
);
157 static void toggleborder(const Arg
*arg
);
158 static void toggleexplorer(const Arg
*arg
);
159 static void togglefloating(const Arg
*arg
);
160 static void toggletag(const Arg
*arg
);
161 static void toggleview(const Arg
*arg
);
162 static void unmanage(Client
*c
);
163 static void updatebar(void);
164 static void updategeom(void);
165 static void view(const Arg
*arg
);
166 static void zoom(const Arg
*arg
);
168 /* Shell hook stuff */
170 typedef BOOL (*RegisterShellHookWindowProc
) (HWND
);
171 RegisterShellHookWindowProc RegisterShellHookWindow
;
173 /* XXX: should be in a system header, no? */
177 } SHELLHOOKINFO
, *LPSHELLHOOKINFO
;
180 static HWND dwmhwnd
, barhwnd
;
181 static char stext
[256];
182 static int sx
, sy
, sw
, sh
; /* X display screen geometry x, y, width, height */
183 static int by
, bh
, blw
; /* bar geometry y, height and layout symbol width */
184 static int wx
, wy
, ww
, wh
; /* window area geometry x, y, width, height, bar excluded */
185 static unsigned int seltags
, sellt
;
187 static Client
*clients
= NULL
;
188 static Client
*sel
= NULL
;
189 static Client
*stack
= NULL
;
190 static Layout
*lt
[] = { NULL
, NULL
};
191 static UINT shellhookid
; /* Window Message id */
193 /* configuration, allows nested code to access above variables */
196 /* compile-time check if all tags fit into an unsigned int bit array. */
197 struct NumTags
{ char limitexceeded
[sizeof(unsigned int) * 8 < LENGTH(tags
) ? -1 : 1]; };
199 /* elements of the window whose color should be set to the values in the array below */
200 static int colorwinelements
[] = { COLOR_ACTIVEBORDER
, COLOR_INACTIVEBORDER
};
201 static COLORREF colors
[2][LENGTH(colorwinelements
)] = {
202 { 0, 0 }, /* used to save the values before dwm started */
203 { selbordercolor
, normbordercolor
},
207 /* function implementations */
209 applyrules(Client
*c
) {
214 for(i
= 0; i
< LENGTH(rules
); i
++) {
216 if((!r
->title
|| strstr(getclienttitle(c
->hwnd
), r
->title
))
217 && (!r
->class || strstr(getclientclassname(c
->hwnd
), r
->class))) {
218 c
->isfloating
= r
->isfloating
;
219 c
->tags
|= r
->tags
& TAGMASK
? r
->tags
& TAGMASK
: tagset
[seltags
];
223 c
->tags
= tagset
[seltags
];
230 if(lt
[sellt
]->arrange
)
231 lt
[sellt
]->arrange();
242 attachstack(Client
*c
) {
248 istoolwindowof(Client
*p
, Client
*c
) {
249 debug(" istoolwindowof: %s\n", getclienttitle(p
->hwnd
));
250 debug(" floating: %d\n", c
->isfloating
);
251 debug(" root: %d == %d\n", p
->root
, c
->root
);
252 debug(" threadid: %d == %d\n", p
->threadid
, c
->threadid
);
253 return c
->isfloating
&& (p
->root
== c
->root
|| p
->threadid
== c
->threadid
);
257 buttonpress(unsigned int button
, POINTS
*point
) {
258 unsigned int i
, x
, click
;
262 dc
.hdc
= GetWindowDC(barhwnd
);
266 do { x
+= TEXTW(tags
[i
]); } while(point
->x
>= x
&& ++i
< LENGTH(tags
));
267 if(i
< LENGTH(tags
)) {
271 else if(point
->x
< x
+ blw
)
273 else if(point
->x
> wx
+ ww
- TEXTW(stext
))
274 click
= ClkStatusText
;
278 if (GetKeyState(VK_SHIFT
) < 0)
281 for(i
= 0; i
< LENGTH(buttons
); i
++) {
282 if(click
== buttons
[i
].click
&& buttons
[i
].func
&& buttons
[i
].button
== button
283 && (!buttons
[i
].key
|| GetKeyState(buttons
[i
].key
) < 0)) {
284 buttons
[i
].func(click
== ClkTagBar
&& buttons
[i
].arg
.i
== 0 ? &arg
: &buttons
[i
].arg
);
294 Layout foo
= { "", NULL
};
296 for(i
= 0; i
< LENGTH(keys
); i
++) {
297 UnregisterHotKey(dwmhwnd
, i
);
300 DeregisterShellHookWindow(dwmhwnd
);
307 SetSysColors(LENGTH(colorwinelements
), colorwinelements
, colors
[0]);
309 DestroyWindow(dwmhwnd
);
313 clearurgent(Client
*c
) {
321 for(tc
= &clients
; *tc
&& *tc
!= c
; tc
= &(*tc
)->next
);
326 detachstack(Client
*c
) {
329 for(tc
= &stack
; *tc
&& *tc
!= c
; tc
= &(*tc
)->snext
);
334 die(const char *errstr
, ...) {
337 va_start(ap
, errstr
);
338 vfprintf(stderr
, errstr
, ap
);
346 dc
.hdc
= GetWindowDC(barhwnd
);
351 unsigned int i
, occ
= 0, urg
= 0;
355 for(c
= clients
; c
; c
= c
->next
) {
362 for(i
= 0; i
< LENGTH(tags
); i
++) {
363 dc
.w
= TEXTW(tags
[i
]);
364 col
= tagset
[seltags
] & 1 << i
? dc
.sel
: dc
.norm
;
365 drawtext(tags
[i
], col
, urg
& 1 << i
);
366 drawsquare(sel
&& sel
->tags
& 1 << i
, occ
& 1 << i
, urg
& 1 << i
, col
);
371 drawtext(lt
[sellt
]->symbol
, dc
.norm
, false);
382 drawtext(stext
, dc
.norm
, false);
384 if((dc
.w
= dc
.x
- x
) > bh
) {
387 drawtext(getclienttitle(sel
->hwnd
), dc
.sel
, false);
388 drawsquare(sel
->isfixed
, sel
->isfloating
, false, dc
.sel
);
391 drawtext(NULL
, dc
.norm
, false);
394 ReleaseDC(barhwnd
, dc
.hdc
);
398 drawsquare(bool filled
, bool empty
, bool invert
, COLORREF col
[ColLast
]) {
400 RECT r
= { .left
= dc
.x
+ 1, .top
= dc
.y
+ 1, .right
= dc
.x
+ size
, .bottom
= dc
.y
+ size
};
402 HBRUSH brush
= CreateSolidBrush(col
[invert
? ColBG
: ColFG
]);
403 SelectObject(dc
.hdc
, brush
);
406 FillRect(dc
.hdc
, &r
, brush
);
408 FillRect(dc
.hdc
, &r
, brush
);
414 drawtext(const char *text
, COLORREF col
[ColLast
], bool invert
) {
415 RECT r
= { .left
= dc
.x
, .top
= dc
.y
, .right
= dc
.x
+ dc
.w
, .bottom
= dc
.y
+ dc
.h
};
417 HPEN pen
= CreatePen(PS_SOLID
, borderpx
, selbordercolor
);
418 HBRUSH brush
= CreateSolidBrush(col
[invert
? ColFG
: ColBG
]);
419 SelectObject(dc
.hdc
, pen
);
420 SelectObject(dc
.hdc
, brush
);
421 FillRect(dc
.hdc
, &r
, brush
);
426 SetBkMode(dc
.hdc
, TRANSPARENT
);
427 SetTextColor(dc
.hdc
, col
[invert
? ColBG
: ColFG
]);
429 HFONT font
= (HFONT
)GetStockObject(SYSTEM_FONT
);
430 SelectObject(dc
.hdc
, font
);
432 DrawText(dc
.hdc
, text
, -1, &r
, DT_CENTER
| DT_VCENTER
| DT_SINGLELINE
);
436 eprint(const char *errstr
, ...) {
439 va_start(ap
, errstr
);
440 vfprintf(stderr
, errstr
, ap
);
446 setselected(Client
*c
) {
447 if(!c
|| !ISVISIBLE(c
))
448 for(c
= stack
; c
&& !ISVISIBLE(c
); c
= c
->snext
);
450 drawborder(sel
, normbordercolor
);
456 drawborder(c
, selbordercolor
);
466 SetForegroundWindow(sel
->hwnd
);
470 focusstack(const Arg
*arg
) {
471 Client
*c
= NULL
, *i
;
476 for(c
= sel
->next
; c
&& !ISFOCUSABLE(c
); c
= c
->next
);
478 for(c
= clients
; c
&& !ISFOCUSABLE(c
); c
= c
->next
);
481 for(i
= clients
; i
!= sel
; i
= i
->next
)
485 for(; i
; i
= i
->next
)
496 managechildwindows(Client
*p
) {
498 EnumChildWindows(p
->hwnd
, scan
, 0);
499 /* remove all child windows which were not part
500 * of the enumeration above.
502 for(c
= clients
; c
; ) {
503 if (c
->parent
== p
->hwnd
) {
504 /* XXX: ismanageable isn't that reliable or some
505 * windows change over time which means they
506 * were once reported as manageable but not
507 * this time so we also check if they are
508 * currently visible and if that's the case
509 * we keep them in our client list.
511 if (!c
->isalive
&& !IsWindowVisible(c
->hwnd
)) {
517 /* reset flag for next check */
523 return nextchild(p
, clients
);
527 getclient(HWND hwnd
) {
530 for(c
= clients
; c
; c
= c
->next
)
537 getclientclassname(HWND hwnd
) {
538 static TCHAR buf
[128];
539 GetClassName(hwnd
, buf
, sizeof buf
);
544 getclienttitle(HWND hwnd
) {
545 static TCHAR buf
[128];
546 GetWindowText(hwnd
, buf
, sizeof buf
);
552 HWND parent
, deskwnd
= GetDesktopWindow();
554 while ((parent
= GetWindow(hwnd
, GW_OWNER
)) != NULL
&& deskwnd
!= parent
)
561 grabkeys(HWND hwnd
) {
563 for (i
= 0; i
< LENGTH(keys
); i
++) {
564 RegisterHotKey(hwnd
, i
, keys
[i
].mod
, keys
[i
].key
);
569 ismanageable(HWND hwnd
){
573 HWND parent
= GetParent(hwnd
);
574 HWND owner
= GetWindow(hwnd
, GW_OWNER
);
575 int style
= GetWindowLong(hwnd
, GWL_STYLE
);
576 int exstyle
= GetWindowLong(hwnd
, GWL_EXSTYLE
);
577 bool pok
= (parent
!= 0 && ismanageable(parent
));
578 bool istool
= exstyle
& WS_EX_TOOLWINDOW
;
579 bool isapp
= exstyle
& WS_EX_APPWINDOW
;
581 if (pok
&& !getclient(parent
))
584 debug("ismanageable: %s\n", getclienttitle(hwnd
));
585 debug(" hwnd: %d\n", hwnd
);
586 debug(" window: %d\n", IsWindow(hwnd
));
587 debug(" visible: %d\n", IsWindowVisible(hwnd
));
588 debug(" parent: %d\n", parent
);
589 debug("parentok: %d\n", pok
);
590 debug(" owner: %d\n", owner
);
591 debug(" toolwin: %d\n", istool
);
592 debug(" appwin: %d\n", isapp
);
594 /* XXX: should we do this? */
595 if (GetWindowTextLength(hwnd
) == 0) {
596 debug(" title: NULL\n");
597 debug(" manage: false\n");
601 if (style
& WS_DISABLED
) {
602 debug("disabled: true\n");
603 debug(" manage: false\n");
609 * Forces a top-level window onto the taskbar when
610 * the window is visible.
613 * Creates a tool window; that is, a window intended
614 * to be used as a floating toolbar. A tool window
615 * has a title bar that is shorter than a normal
616 * title bar, and the window title is drawn using
617 * a smaller font. A tool window does not appear in
618 * the taskbar or in the dialog that appears when
619 * the user presses ALT+TAB. If a tool window has
620 * a system menu, its icon is not displayed on the
621 * title bar. However, you can display the system
622 * menu by right-clicking or by typing ALT+SPACE.
625 if ((parent
== 0 && IsWindowVisible(hwnd
)) || pok
) {
626 if ((!istool
&& parent
== 0) || (istool
&& pok
)) {
627 debug(" manage: true\n");
630 if (isapp
&& parent
!= 0) {
631 debug(" manage: true\n");
635 debug(" manage: false\n");
640 killclient(const Arg
*arg
) {
643 PostMessage(sel
->hwnd
, WM_CLOSE
, 0, 0);
649 Client
*c
= getclient(hwnd
);
654 debug(" manage %s\n", getclienttitle(hwnd
));
657 .cbSize
= sizeof(WINDOWINFO
),
660 if (!GetWindowInfo(hwnd
, &wi
))
663 if(!(c
= malloc(sizeof(Client
))))
664 die("fatal: could not malloc() %u bytes\n", sizeof(Client
));
668 c
->threadid
= GetWindowThreadProcessId(hwnd
, NULL
);
669 c
->parent
= GetParent(hwnd
);
670 c
->root
= getroot(hwnd
);
673 static WINDOWPLACEMENT wp
= {
674 .length
= sizeof(WINDOWPLACEMENT
),
675 .showCmd
= SW_RESTORE
,
678 if (IsWindowVisible(c
->hwnd
))
679 SetWindowPlacement(hwnd
, &wp
);
681 /* maybe we could also filter based on
682 * WS_MINIMIZEBOX and WS_MAXIMIZEBOX
684 c
->isfloating
= (wi
.dwStyle
& WS_POPUP
) ||
685 (!(wi
.dwStyle
& WS_MINIMIZEBOX
) && !(wi
.dwStyle
& WS_MAXIMIZEBOX
));
687 debug(" window style: %d\n", wi
.dwStyle
);
688 debug(" minimize: %d\n", wi
.dwStyle
& WS_MINIMIZEBOX
);
689 debug(" maximize: %d\n", wi
.dwStyle
& WS_MAXIMIZEBOX
);
690 debug(" popup: %d\n", wi
.dwStyle
& WS_POPUP
);
691 debug(" isfloating: %d\n", c
->isfloating
);
698 if (c
->isfloating
&& IsWindowVisible(hwnd
)) {
699 debug(" new floating window: x: %d y: %d w: %d h: %d\n", wi
.rcWindow
.left
, wi
.rcWindow
.top
, wi
.rcWindow
.right
- wi
.rcWindow
.left
, wi
.rcWindow
.bottom
- wi
.rcWindow
.top
);
700 resize(c
, wi
.rcWindow
.left
, wi
.rcWindow
.top
, wi
.rcWindow
.right
- wi
.rcWindow
.left
, wi
.rcWindow
.bottom
- wi
.rcWindow
.top
);
712 for(c
= nexttiled(clients
); c
; c
= nexttiled(c
->next
)) {
713 resize(c
, wx
, wy
, ww
- 2 * c
->bw
, wh
- 2 * c
->bw
);
718 nextchild(Client
*p
, Client
*c
) {
719 for(; c
&& c
->parent
!= p
->hwnd
; c
= c
->next
);
724 nexttiled(Client
*c
) {
725 for(; c
&& (c
->isfloating
|| IsIconic(c
->hwnd
) || !ISVISIBLE(c
) || !IsWindowVisible(c
->hwnd
)); c
= c
->next
);
730 quit(const Arg
*arg
) {
731 PostMessage(dwmhwnd
, WM_CLOSE
, 0, 0);
735 resize(Client
*c
, int x
, int y
, int w
, int h
) {
736 if(w
<= 0 && h
<= 0) {
737 setvisibility(c
->hwnd
, false);
744 if(x
+ w
+ 2 * c
->bw
< sx
)
746 if(y
+ h
+ 2 * c
->bw
< sy
)
752 if(c
->x
!= x
|| c
->y
!= y
|| c
->w
!= w
|| c
->h
!= h
) {
757 debug(" resize %d: %s: x: %d y: %d w: %d h: %d\n", c
->hwnd
, getclienttitle(c
->hwnd
), x
, y
, w
, h
);
758 SetWindowPos(c
->hwnd
, HWND_TOP
, c
->x
, c
->y
, c
->w
, c
->h
, SWP_NOACTIVATE
);
767 LRESULT CALLBACK
barhandler(HWND hwnd
, UINT msg
, WPARAM wParam
, LPARAM lParam
)
775 BeginPaint(hwnd
, &ps
);
783 buttonpress(msg
, &MAKEPOINTS(lParam
));
786 return DefWindowProc(hwnd
, msg
, wParam
, lParam
);
792 LRESULT CALLBACK
WndProc(HWND hwnd
, UINT msg
, WPARAM wParam
, LPARAM lParam
)
804 if (wParam
> 0 && wParam
< LENGTH(keys
)) {
805 keys
[wParam
].func(&(keys
[wParam
].arg
));
809 if (msg
== shellhookid
) { /* Handle the shell hook message */
810 Client
*c
= getclient((HWND
)lParam
);
811 switch (wParam
& 0x7fff) {
812 /* The first two events are also trigger if windows
813 * are being hidden or shown because of a tag
814 * switch, therefore we ignore them in this case.
816 case HSHELL_WINDOWCREATED
:
817 debug("window created: %s\n", getclienttitle((HWND
)lParam
));
818 if (!c
&& ismanageable((HWND
)lParam
)) {
819 c
= manage((HWND
)lParam
);
820 managechildwindows(c
);
824 case HSHELL_WINDOWDESTROYED
:
826 debug(" window %s: %s\n", c
->ignore
? "hidden" : "destroyed", getclienttitle(c
->hwnd
));
832 debug(" unmanaged window destroyed\n");
835 case HSHELL_WINDOWACTIVATED
:
836 debug(" window activated: %s || %d\n", c
? getclienttitle(c
->hwnd
) : "unknown", (HWND
)lParam
);
839 managechildwindows(c
);
841 /* check if the previously selected
842 * window got minimized
844 if (t
&& (t
->isminimized
= IsIconic(t
->hwnd
))) {
845 debug(" active window got minimized: %s\n", getclienttitle(t
->hwnd
));
848 /* the newly focused window was minimized */
849 if (sel
->isminimized
) {
850 debug(" newly active window was minimized: %s\n", getclienttitle(sel
->hwnd
));
851 sel
->isminimized
= false;
855 /* Some window don't seem to generate
856 * HSHELL_WINDOWCREATED messages therefore
857 * we check here whether we should manage
860 if (ismanageable((HWND
)lParam
)) {
861 c
= manage((HWND
)lParam
);
862 managechildwindows(c
);
870 return DefWindowProc(hwnd
, msg
, wParam
, lParam
);
877 scan(HWND hwnd
, LPARAM lParam
) {
878 Client
*c
= getclient(hwnd
);
881 else if (ismanageable(hwnd
))
887 drawborder(Client
*c
, COLORREF color
) {
889 HDC hdc
= GetWindowDC(c
->hwnd
);
892 /* this would be another way, but it uses standard sytem colors */
893 RECT area
= { .left
= 0, .top
= 0, .right
= c
->w
, .bottom
= c
->h
};
894 DrawEdge(hdc
, &area
, BDR_RAISEDOUTER
| BDR_SUNKENINNER
, BF_RECT
);
896 HPEN pen
= CreatePen(PS_SOLID
, borderpx
, color
);
897 SelectObject(hdc
, pen
);
898 MoveToEx(hdc
, 0, 0, NULL
);
899 LineTo(hdc
, c
->w
, 0);
900 LineTo(hdc
, c
->w
, c
->h
);
901 LineTo(hdc
, 0, c
->h
);
906 ReleaseDC(c
->hwnd
, hdc
);
911 setborder(Client
*c
, bool border
) {
913 SetWindowLong(c
->hwnd
, GWL_STYLE
, (GetWindowLong(c
->hwnd
, GWL_STYLE
) | (WS_CAPTION
| WS_SIZEBOX
)));
915 /* XXX: ideally i would like to use the standard window border facilities and just modify the
916 * color with SetSysColor but this only seems to work if we leave WS_SIZEBOX enabled which
919 SetWindowLong(c
->hwnd
, GWL_STYLE
, (GetWindowLong(c
->hwnd
, GWL_STYLE
) & ~(WS_CAPTION
| WS_SIZEBOX
)) | WS_BORDER
| WS_THICKFRAME
);
920 SetWindowLong(c
->hwnd
, GWL_EXSTYLE
, (GetWindowLong(c
->hwnd
, GWL_EXSTYLE
) & ~(WS_EX_CLIENTEDGE
| WS_EX_WINDOWEDGE
)));
922 SetWindowPos(c
->hwnd
, 0, 0, 0, 0, 0, SWP_FRAMECHANGED
| SWP_NOACTIVATE
| SWP_NOMOVE
| SWP_NOSIZE
| SWP_NOZORDER
| SWP_NOOWNERZORDER
);
927 setvisibility(HWND hwnd
, bool visibility
) {
928 SetWindowPos(hwnd
, 0, 0, 0, 0, 0, (visibility
? SWP_SHOWWINDOW
: SWP_HIDEWINDOW
) | SWP_NOACTIVATE
| SWP_NOMOVE
| SWP_NOSIZE
| SWP_NOZORDER
);
932 setlayout(const Arg
*arg
) {
933 if(!arg
|| !arg
->v
|| arg
->v
!= lt
[sellt
])
936 lt
[sellt
] = (Layout
*)arg
->v
;
943 /* arg > 1.0 will set mfact absolutly */
945 setmfact(const Arg
*arg
) {
948 if(!arg
|| !lt
[sellt
]->arrange
)
950 f
= arg
->f
< 1.0 ? arg
->f
+ mfact
: arg
->f
- 1.0;
951 if(f
< 0.1 || f
> 0.9)
958 setup(HINSTANCE hInstance
) {
963 lt
[1] = &layouts
[1 % LENGTH(layouts
)];
965 /* init appearance */
967 dc
.norm
[ColBorder
] = normbordercolor
;
968 dc
.norm
[ColBG
] = normbgcolor
;
969 dc
.norm
[ColFG
] = normfgcolor
;
970 dc
.sel
[ColBorder
] = selbordercolor
;
971 dc
.sel
[ColBG
] = selbgcolor
;
972 dc
.sel
[ColFG
] = selfgcolor
;
974 /* save colors so we can restore them in cleanup */
975 for (i
= 0; i
< LENGTH(colorwinelements
); i
++)
976 colors
[0][i
] = GetSysColor(colorwinelements
[i
]);
978 SetSysColors(LENGTH(colorwinelements
), colorwinelements
, colors
[1]);
980 //SystemParametersInfo(SPI_SETBORDER, 1 /* width */, 0, 0);
986 winClass
.cbSize
= sizeof(WNDCLASSEX
);
988 winClass
.lpfnWndProc
= WndProc
;
989 winClass
.cbClsExtra
= 0;
990 winClass
.cbWndExtra
= 0;
991 winClass
.hInstance
= hInstance
;
992 winClass
.hIcon
= NULL
;
993 winClass
.hIconSm
= NULL
;
994 winClass
.hCursor
= NULL
;
995 winClass
.hbrBackground
= NULL
;
996 winClass
.lpszMenuName
= NULL
;
997 winClass
.lpszClassName
= NAME
;
999 if (!RegisterClassEx(&winClass
))
1000 die("Error registering window class");
1002 dwmhwnd
= CreateWindowEx(0, NAME
, NAME
, 0, 0, 0, 0, 0, HWND_MESSAGE
, NULL
, hInstance
, NULL
);
1005 die("Error creating window");
1009 EnumWindows(scan
, 0);
1011 setupbar(hInstance
);
1015 /* Get function pointer for RegisterShellHookWindow */
1016 RegisterShellHookWindow
= (RegisterShellHookWindowProc
)GetProcAddress(GetModuleHandle("USER32.DLL"), "RegisterShellHookWindow");
1017 if (!RegisterShellHookWindow
)
1018 die("Could not find RegisterShellHookWindow");
1019 RegisterShellHookWindow(dwmhwnd
);
1020 /* Grab a dynamic id for the SHELLHOOK message to be used later */
1021 shellhookid
= RegisterWindowMessage("SHELLHOOK");
1025 setupbar(HINSTANCE hInstance
) {
1027 unsigned int i
, w
= 0;
1030 memset(&winClass
, 0, sizeof winClass
);
1033 winClass
.lpfnWndProc
= barhandler
;
1034 winClass
.cbClsExtra
= 0;
1035 winClass
.cbWndExtra
= 0;
1036 winClass
.hInstance
= hInstance
;
1037 winClass
.hIcon
= NULL
;
1038 winClass
.hCursor
= LoadCursor(NULL
, IDC_ARROW
);
1039 winClass
.hbrBackground
= NULL
;
1040 winClass
.lpszMenuName
= NULL
;
1041 winClass
.lpszClassName
= "dwm-bar";
1043 if (!RegisterClass(&winClass
))
1044 die("Error registering window class");
1046 barhwnd
= CreateWindowEx(
1049 NULL
, /* window title */
1050 WS_POPUP
| WS_CLIPCHILDREN
| WS_CLIPSIBLINGS
,
1052 NULL
, /* parent window */
1058 /* calculate width of the largest layout symbol */
1059 dc
.hdc
= GetWindowDC(barhwnd
);
1060 HFONT font
= (HFONT
)GetStockObject(SYSTEM_FONT
);
1061 SelectObject(dc
.hdc
, font
);
1063 for(blw
= i
= 0; LENGTH(layouts
) > 1 && i
< LENGTH(layouts
); i
++) {
1064 w
= TEXTW(layouts
[i
].symbol
);
1068 ReleaseDC(barhwnd
, dc
.hdc
);
1070 PostMessage(barhwnd
, WM_PAINT
, 0, 0);
1075 showclientclassname(const Arg
*arg
) {
1076 MessageBox(NULL
, getclientclassname(GetForegroundWindow()), "Window class", MB_OK
);
1080 showhide(Client
*c
) {
1083 /* XXX: is the order of showing / hidding important? */
1084 if (!ISVISIBLE(c
)) {
1085 if (IsWindowVisible(c
->hwnd
)) {
1087 c
->wasvisible
= true;
1088 setvisibility(c
->hwnd
, false);
1091 if (c
->wasvisible
) {
1092 setvisibility(c
->hwnd
, true);
1099 spawn(const Arg
*arg
) {
1100 ShellExecute(NULL
, NULL
, ((char **)arg
->v
)[0], ((char **)arg
->v
)[1], NULL
, SW_SHOWDEFAULT
);
1104 tag(const Arg
*arg
) {
1107 if(sel
&& arg
->ui
& TAGMASK
) {
1108 sel
->tags
= arg
->ui
& TAGMASK
;
1109 debug("window tagged: %d %s\n", sel
->hwnd
, getclienttitle(sel
->hwnd
));
1110 for (c
= managechildwindows(sel
); c
; c
= nextchild(sel
, c
->next
)) {
1111 debug(" child window which is %s tagged: %s\n", c
->isfloating
? "floating" : "normal", getclienttitle(c
->hwnd
));
1113 c
->tags
= arg
->ui
& TAGMASK
;
1115 debug("window tagged finished\n");
1121 textnw(const char *text
, unsigned int len
) {
1123 GetTextExtentPoint(dc
.hdc
, text
, len
, &size
);
1125 size
.cx
+= textmargin
;
1136 for(n
= 0, c
= nexttiled(clients
); c
; c
= nexttiled(c
->next
), n
++);
1141 c
= nexttiled(clients
);
1143 resize(c
, wx
, wy
, (n
== 1 ? ww
: mw
) - 2 * c
->bw
, wh
- 2 * c
->bw
);
1149 x
= (wx
+ mw
> c
->x
+ c
->w
) ? c
->x
+ c
->w
+ 2 * c
->bw
: wx
+ mw
;
1151 w
= (wx
+ mw
> c
->x
+ c
->w
) ? wx
+ ww
- x
: ww
- mw
;
1156 for(i
= 0, c
= nexttiled(c
->next
); c
; c
= nexttiled(c
->next
), i
++) {
1157 resize(c
, x
, y
, w
- 2 * c
->bw
, /* remainder */ ((i
+ 1 == n
)
1158 ? wy
+ wh
- y
- 2 * c
->bw
: h
- 2 * c
->bw
));
1160 y
= c
->y
+ HEIGHT(c
);
1165 togglebar(const Arg
*arg
) {
1173 toggleborder(const Arg
*arg
) {
1176 setborder(sel
, !sel
->border
);
1180 toggleexplorer(const Arg
*arg
) {
1181 HWND hwnd
= FindWindow("Progman", "Program Manager");
1183 setvisibility(hwnd
, !IsWindowVisible(hwnd
));
1185 hwnd
= FindWindow("Shell_TrayWnd", NULL
);
1187 setvisibility(hwnd
, !IsWindowVisible(hwnd
));
1197 togglefloating(const Arg
*arg
) {
1200 sel
->isfloating
= !sel
->isfloating
|| sel
->isfixed
;
1201 setborder(sel
, sel
->isfloating
);
1203 resize(sel
, sel
->x
, sel
->y
, sel
->w
, sel
->h
);
1208 toggletag(const Arg
*arg
) {
1214 mask
= sel
->tags
^ (arg
->ui
& TAGMASK
);
1222 toggleview(const Arg
*arg
) {
1223 unsigned int mask
= tagset
[seltags
] ^ (arg
->ui
& TAGMASK
);
1226 tagset
[seltags
] = mask
;
1232 unmanage(Client
*c
) {
1233 debug(" unmanage %s\n", getclienttitle(c
->hwnd
));
1235 setvisibility(c
->hwnd
, true);
1248 SetWindowPos(barhwnd
, showbar
? HWND_TOPMOST
: HWND_NOTOPMOST
, 0, by
, ww
, bh
, (showbar
? SWP_SHOWWINDOW
: SWP_HIDEWINDOW
) | SWP_NOACTIVATE
| SWP_NOSENDCHANGING
);
1254 HWND hwnd
= FindWindow("Shell_TrayWnd", NULL
);
1255 /* check if the windows taskbar is visible and adjust
1256 * the workspace accordingly.
1258 if (hwnd
&& IsWindowVisible(hwnd
)) {
1259 SystemParametersInfo(SPI_GETWORKAREA
, 0, &wa
, 0);
1262 sw
= wa
.right
- wa
.left
;
1263 sh
= wa
.bottom
- wa
.top
;
1265 sx
= GetSystemMetrics(SM_XVIRTUALSCREEN
);
1266 sy
= GetSystemMetrics(SM_YVIRTUALSCREEN
);
1267 sw
= GetSystemMetrics(SM_CXVIRTUALSCREEN
);
1268 sh
= GetSystemMetrics(SM_CYVIRTUALSCREEN
);
1271 bh
= 20; /* XXX: fixed value */
1273 /* window area geometry */
1275 wy
= showbar
&& topbar
? sy
+ bh
: sy
;
1277 wh
= showbar
? sh
- bh
: sh
;
1279 by
= showbar
? (topbar
? wy
- bh
: wy
+ wh
) : -bh
;
1280 debug("updategeom: %d x %d\n", ww
, wh
);
1284 view(const Arg
*arg
) {
1285 if((arg
->ui
& TAGMASK
) == tagset
[seltags
])
1287 seltags
^= 1; /* toggle sel tagset */
1288 if(arg
->ui
& TAGMASK
)
1289 tagset
[seltags
] = arg
->ui
& TAGMASK
;
1294 zoom(const Arg
*arg
) {
1297 if(!lt
[sellt
]->arrange
|| lt
[sellt
]->arrange
== monocle
|| (sel
&& sel
->isfloating
))
1299 if(c
== nexttiled(clients
))
1300 if(!c
|| !(c
= nexttiled(c
->next
)))
1308 int WINAPI
WinMain(HINSTANCE hInstance
, HINSTANCE hPrevInstance
, LPSTR lpCmdLine
, int nShowCmd
) {
1313 while (GetMessage(&msg
, NULL
, 0, 0) > 0) {
1314 TranslateMessage(&msg
);
1315 DispatchMessage(&msg
);