aboutsummaryrefslogtreecommitdiffstats
path: root/src/core
diff options
context:
space:
mode:
Diffstat (limited to 'src/core')
-rw-r--r--src/core/dwm.c4535
-rw-r--r--src/core/dwm.h176
2 files changed, 2413 insertions, 2298 deletions
diff --git a/src/core/dwm.c b/src/core/dwm.c
index d3782cb..e16bc2f 100644
--- a/src/core/dwm.c
+++ b/src/core/dwm.c
@@ -56,12 +56,12 @@
56/* macros */ 56/* macros */
57#define BUTTONMASK (ButtonPressMask | ButtonReleaseMask) 57#define BUTTONMASK (ButtonPressMask | ButtonReleaseMask)
58#define CLEANMASK(mask) \ 58#define CLEANMASK(mask) \
59 (mask & ~(numlockmask | LockMask) & \ 59 (mask & ~(numlockmask | LockMask) & \
60 (ShiftMask | ControlMask | Mod1Mask | Mod2Mask | Mod3Mask | Mod4Mask | \ 60 (ShiftMask | ControlMask | Mod1Mask | Mod2Mask | Mod3Mask | \
61 Mod5Mask)) 61 Mod4Mask | Mod5Mask))
62#define INTERSECT(x, y, w, h, m) \ 62#define INTERSECT(x, y, w, h, m) \
63 (MAX(0, MIN((x) + (w), (m)->wx + (m)->ww) - MAX((x), (m)->wx)) * \ 63 (MAX(0, MIN((x) + (w), (m)->wx + (m)->ww) - MAX((x), (m)->wx)) * \
64 MAX(0, MIN((y) + (h), (m)->wy + (m)->wh) - MAX((y), (m)->wy))) 64 MAX(0, MIN((y) + (h), (m)->wy + (m)->wh) - MAX((y), (m)->wy)))
65#define ISVISIBLE(C) ((C->tags & C->mon->tagset[C->mon->seltags])) 65#define ISVISIBLE(C) ((C->tags & C->mon->tagset[C->mon->seltags]))
66#define LENGTH(X) (sizeof X / sizeof X[0]) 66#define LENGTH(X) (sizeof X / sizeof X[0])
67#define MOUSEMASK (BUTTONMASK | PointerMotionMask) 67#define MOUSEMASK (BUTTONMASK | PointerMotionMask)
@@ -88,514 +88,551 @@
88 88
89/* compile-time check if all tags fit into an unsigned int bit array. */ 89/* compile-time check if all tags fit into an unsigned int bit array. */
90struct NumTags { 90struct NumTags {
91 char limitexceeded[LENGTH(tags) > 31 ? -1 : 1]; 91 char limitexceeded[LENGTH(tags) > 31 ? -1 : 1];
92}; 92};
93 93
94/* function implementations */ 94/* function implementations */
95void applyrules(Client *c) { 95void applyrules(Client *c)
96 const char *class, *instance; 96{
97 unsigned int i; 97 const char *class, *instance;
98 const Rule *r; 98 unsigned int i;
99 Monitor *m; 99 const Rule *r;
100 XClassHint ch = {NULL, NULL}; 100 Monitor *m;
101 101 XClassHint ch = {NULL, NULL};
102 /* rule matching */ 102
103 c->isfloating = 0; 103 /* rule matching */
104 c->tags = 0; 104 c->isfloating = 0;
105 XGetClassHint(dpy, c->win, &ch); 105 c->tags = 0;
106 class = ch.res_class ? ch.res_class : broken; 106 XGetClassHint(dpy, c->win, &ch);
107 instance = ch.res_name ? ch.res_name : broken; 107 class = ch.res_class ? ch.res_class : broken;
108 108 instance = ch.res_name ? ch.res_name : broken;
109 for (i = 0; i < LENGTH(rules); i++) { 109
110 r = &rules[i]; 110 for (i = 0; i < LENGTH(rules); i++) {
111 if ((!r->title || strstr(c->name, r->title)) && 111 r = &rules[i];
112 (!r->class || strstr(class, r->class)) && 112 if ((!r->title || strstr(c->name, r->title)) &&
113 (!r->instance || strstr(instance, r->instance))) { 113 (!r->class || strstr(class, r->class)) &&
114 c->isterminal = r->isterminal; 114 (!r->instance || strstr(instance, r->instance))) {
115 c->noswallow = r->noswallow; 115 c->isterminal = r->isterminal;
116 c->isfloating = r->isfloating; 116 c->noswallow = r->noswallow;
117 c->tags |= r->tags; 117 c->isfloating = r->isfloating;
118 for (m = mons; m && m->num != r->monitor; m = m->next) 118 c->tags |= r->tags;
119 ; 119 for (m = mons; m && m->num != r->monitor; m = m->next)
120 if (m) 120 ;
121 c->mon = m; 121 if (m)
122 } 122 c->mon = m;
123 } 123 }
124 if (ch.res_class) 124 }
125 XFree(ch.res_class); 125 if (ch.res_class)
126 if (ch.res_name) 126 XFree(ch.res_class);
127 XFree(ch.res_name); 127 if (ch.res_name)
128 c->tags = 128 XFree(ch.res_name);
129 c->tags & TAGMASK ? c->tags & TAGMASK : c->mon->tagset[c->mon->seltags]; 129 c->tags = c->tags & TAGMASK ? c->tags & TAGMASK
130} 130 : c->mon->tagset[c->mon->seltags];
131 131}
132int applysizehints(Client *c, int *x, int *y, int *w, int *h, int interact) { 132
133 int baseismin; 133int applysizehints(Client *c, int *x, int *y, int *w, int *h, int interact)
134 Monitor *m = c->mon; 134{
135 135 int baseismin;
136 /* set minimum possible */ 136 Monitor *m = c->mon;
137 *w = MAX(1, *w); 137
138 *h = MAX(1, *h); 138 /* set minimum possible */
139 if (interact) { 139 *w = MAX(1, *w);
140 if (*x > sw) 140 *h = MAX(1, *h);
141 *x = sw - WIDTH(c); 141 if (interact) {
142 if (*y > sh) 142 if (*x > sw)
143 *y = sh - HEIGHT(c); 143 *x = sw - WIDTH(c);
144 if (*x + *w + 2 * c->bw < 0) 144 if (*y > sh)
145 *x = 0; 145 *y = sh - HEIGHT(c);
146 if (*y + *h + 2 * c->bw < 0) 146 if (*x + *w + 2 * c->bw < 0)
147 *y = 0; 147 *x = 0;
148 } else { 148 if (*y + *h + 2 * c->bw < 0)
149 if (*x >= m->wx + m->ww) 149 *y = 0;
150 *x = m->wx + m->ww - WIDTH(c); 150 } else {
151 if (*y >= m->wy + m->wh) 151 if (*x >= m->wx + m->ww)
152 *y = m->wy + m->wh - HEIGHT(c); 152 *x = m->wx + m->ww - WIDTH(c);
153 if (*x + *w + 2 * c->bw <= m->wx) 153 if (*y >= m->wy + m->wh)
154 *x = m->wx; 154 *y = m->wy + m->wh - HEIGHT(c);
155 if (*y + *h + 2 * c->bw <= m->wy) 155 if (*x + *w + 2 * c->bw <= m->wx)
156 *y = m->wy; 156 *x = m->wx;
157 } 157 if (*y + *h + 2 * c->bw <= m->wy)
158 if (*h < bh) 158 *y = m->wy;
159 *h = bh; 159 }
160 if (*w < bh) 160 if (*h < bh)
161 *w = bh; 161 *h = bh;
162 if (resizehints || c->isfloating || !c->mon->lt[c->mon->sellt]->arrange) { 162 if (*w < bh)
163 if (!c->hintsvalid) 163 *w = bh;
164 updatesizehints(c); 164 if (resizehints || c->isfloating ||
165 /* see last two sentences in ICCCM 4.1.2.3 */ 165 !c->mon->lt[c->mon->sellt]->arrange) {
166 baseismin = c->basew == c->minw && c->baseh == c->minh; 166 if (!c->hintsvalid)
167 if (!baseismin) { /* temporarily remove base dimensions */ 167 updatesizehints(c);
168 *w -= c->basew; 168 /* see last two sentences in ICCCM 4.1.2.3 */
169 *h -= c->baseh; 169 baseismin = c->basew == c->minw && c->baseh == c->minh;
170 } 170 if (!baseismin) { /* temporarily remove base dimensions */
171 /* adjust for aspect limits */ 171 *w -= c->basew;
172 if (c->mina > 0 && c->maxa > 0) { 172 *h -= c->baseh;
173 if (c->maxa < (float)*w / *h) 173 }
174 *w = *h * c->maxa + 0.5; 174 /* adjust for aspect limits */
175 else if (c->mina < (float)*h / *w) 175 if (c->mina > 0 && c->maxa > 0) {
176 *h = *w * c->mina + 0.5; 176 if (c->maxa < (float)*w / *h)
177 } 177 *w = *h * c->maxa + 0.5;
178 if (baseismin) { /* increment calculation requires this */ 178 else if (c->mina < (float)*h / *w)
179 *w -= c->basew; 179 *h = *w * c->mina + 0.5;
180 *h -= c->baseh; 180 }
181 } 181 if (baseismin) { /* increment calculation requires this */
182 /* adjust for increment value */ 182 *w -= c->basew;
183 if (c->incw) 183 *h -= c->baseh;
184 *w -= *w % c->incw; 184 }
185 if (c->inch) 185 /* adjust for increment value */
186 *h -= *h % c->inch; 186 if (c->incw)
187 /* restore base dimensions */ 187 *w -= *w % c->incw;
188 *w = MAX(*w + c->basew, c->minw); 188 if (c->inch)
189 *h = MAX(*h + c->baseh, c->minh); 189 *h -= *h % c->inch;
190 if (c->maxw) 190 /* restore base dimensions */
191 *w = MIN(*w, c->maxw); 191 *w = MAX(*w + c->basew, c->minw);
192 if (c->maxh) 192 *h = MAX(*h + c->baseh, c->minh);
193 *h = MIN(*h, c->maxh); 193 if (c->maxw)
194 } 194 *w = MIN(*w, c->maxw);
195 return *x != c->x || *y != c->y || *w != c->w || *h != c->h; 195 if (c->maxh)
196} 196 *h = MIN(*h, c->maxh);
197 197 }
198void arrange(Monitor *m) { 198 return *x != c->x || *y != c->y || *w != c->w || *h != c->h;
199 if (m) 199}
200 showhide(m->stack); 200
201 else 201void arrange(Monitor *m)
202 for (m = mons; m; m = m->next) 202{
203 showhide(m->stack); 203 if (m)
204 if (m) { 204 showhide(m->stack);
205 arrangemon(m); 205 else
206 restack(m); 206 for (m = mons; m; m = m->next)
207 } else 207 showhide(m->stack);
208 for (m = mons; m; m = m->next) 208 if (m) {
209 arrangemon(m); 209 arrangemon(m);
210} 210 restack(m);
211 211 } else
212void arrangemon(Monitor *m) { 212 for (m = mons; m; m = m->next)
213 strncpy(m->ltsymbol, m->lt[m->sellt]->symbol, sizeof m->ltsymbol); 213 arrangemon(m);
214 if (m->lt[m->sellt]->arrange) 214}
215 m->lt[m->sellt]->arrange(m); 215
216} 216void arrangemon(Monitor *m)
217 217{
218void attach(Client *c) { 218 strncpy(m->ltsymbol, m->lt[m->sellt]->symbol, sizeof m->ltsymbol);
219 c->next = c->mon->clients; 219 if (m->lt[m->sellt]->arrange)
220 c->mon->clients = c; 220 m->lt[m->sellt]->arrange(m);
221} 221}
222 222
223void attachstack(Client *c) { 223void attach(Client *c)
224 c->snext = c->mon->stack; 224{
225 c->mon->stack = c; 225 c->next = c->mon->clients;
226} 226 c->mon->clients = c;
227 227}
228void swallow(Client *p, Client *c) { 228
229 229void attachstack(Client *c)
230 if (c->noswallow || c->isterminal) 230{
231 return; 231 c->snext = c->mon->stack;
232 if (c->noswallow && !swallowfloating && c->isfloating) 232 c->mon->stack = c;
233 return; 233}
234 234
235 detach(c); 235void swallow(Client *p, Client *c)
236 detachstack(c); 236{
237 237
238 setclientstate(c, WithdrawnState); 238 if (c->noswallow || c->isterminal)
239 XUnmapWindow(dpy, p->win); 239 return;
240 240 if (c->noswallow && !swallowfloating && c->isfloating)
241 p->swallowing = c; 241 return;
242 c->mon = p->mon; 242
243 243 detach(c);
244 Window w = p->win; 244 detachstack(c);
245 p->win = c->win; 245
246 c->win = w; 246 setclientstate(c, WithdrawnState);
247 updatetitle(p); 247 XUnmapWindow(dpy, p->win);
248 XMoveResizeWindow(dpy, p->win, p->x, p->y, p->w, p->h); 248
249 arrange(p->mon); 249 p->swallowing = c;
250 configure(p); 250 c->mon = p->mon;
251 updateclientlist(); 251
252} 252 Window w = p->win;
253 253 p->win = c->win;
254void unswallow(Client *c) { 254 c->win = w;
255 c->win = c->swallowing->win; 255 updatetitle(p);
256 256 XMoveResizeWindow(dpy, p->win, p->x, p->y, p->w, p->h);
257 free(c->swallowing); 257 arrange(p->mon);
258 c->swallowing = NULL; 258 configure(p);
259 259 updateclientlist();
260 /* unfullscreen the client */ 260}
261 setfullscreen(c, 0); 261
262 updatetitle(c); 262void unswallow(Client *c)
263 arrange(c->mon); 263{
264 XMapWindow(dpy, c->win); 264 c->win = c->swallowing->win;
265 XMoveResizeWindow(dpy, c->win, c->x, c->y, c->w, c->h); 265
266 setclientstate(c, NormalState); 266 free(c->swallowing);
267 focus(NULL); 267 c->swallowing = NULL;
268 arrange(c->mon); 268
269} 269 /* unfullscreen the client */
270 270 setfullscreen(c, 0);
271void buttonpress(XEvent *e) { 271 updatetitle(c);
272 unsigned int i, x, click; 272 arrange(c->mon);
273 Arg arg = {0}; 273 XMapWindow(dpy, c->win);
274 Client *c; 274 XMoveResizeWindow(dpy, c->win, c->x, c->y, c->w, c->h);
275 Monitor *m; 275 setclientstate(c, NormalState);
276 XButtonPressedEvent *ev = &e->xbutton; 276 focus(NULL);
277 277 arrange(c->mon);
278 click = ClkRootWin; 278}
279 /* focus monitor if necessary */ 279
280 if ((m = wintomon(ev->window)) && m != selmon) { 280void buttonpress(XEvent *e)
281 unfocus(selmon->sel, 1); 281{
282 selmon = m; 282 unsigned int i, x, click;
283 focus(NULL); 283 Arg arg = {0};
284 } 284 Client *c;
285 if (ev->window == selmon->barwin) { 285 Monitor *m;
286 i = x = 0; 286 XButtonPressedEvent *ev = &e->xbutton;
287 unsigned int occ = 0; 287
288 for (c = m->clients; c; c = c->next) 288 click = ClkRootWin;
289 occ |= c->tags; 289 /* focus monitor if necessary */
290 do { 290 if ((m = wintomon(ev->window)) && m != selmon) {
291 /* Do not reserve space for vacant tags */ 291 unfocus(selmon->sel, 1);
292 if (!(occ & 1 << i || m->tagset[m->seltags] & 1 << i)) 292 selmon = m;
293 continue; 293 focus(NULL);
294 x += TEXTW(tags[i]); 294 }
295 } while (ev->x >= x && ++i < LENGTH(tags)); 295 if (ev->window == selmon->barwin) {
296 if (i < LENGTH(tags)) { 296 i = x = 0;
297 click = ClkTagBar; 297 unsigned int occ = 0;
298 arg.ui = 1 << i; 298 for (c = m->clients; c; c = c->next)
299 } else if (ev->x < x + TEXTW(selmon->ltsymbol)) 299 occ |= c->tags;
300 click = ClkLtSymbol; 300 do {
301 else if (ev->x > selmon->ww - (int)TEXTW(stext) - getsystraywidth()) 301 /* Do not reserve space for vacant tags */
302 click = ClkStatusText; 302 if (!(occ & 1 << i || m->tagset[m->seltags] & 1 << i))
303 else 303 continue;
304 click = ClkWinTitle; 304 x += TEXTW(tags[i]);
305 } else if ((c = wintoclient(ev->window))) { 305 } while (ev->x >= x && ++i < LENGTH(tags));
306 focus(c); 306 if (i < LENGTH(tags)) {
307 restack(selmon); 307 click = ClkTagBar;
308 XAllowEvents(dpy, ReplayPointer, CurrentTime); 308 arg.ui = 1 << i;
309 click = ClkClientWin; 309 } else if (ev->x < x + TEXTW(selmon->ltsymbol))
310 } 310 click = ClkLtSymbol;
311 for (i = 0; i < LENGTH(buttons); i++) 311 else if (ev->x >
312 if (click == buttons[i].click && buttons[i].func && 312 selmon->ww - (int)TEXTW(stext) - getsystraywidth())
313 buttons[i].button == ev->button && 313 click = ClkStatusText;
314 CLEANMASK(buttons[i].mask) == CLEANMASK(ev->state)) 314 else
315 buttons[i].func( 315 click = ClkWinTitle;
316 click == ClkTagBar && buttons[i].arg.i == 0 ? &arg : &buttons[i].arg); 316 } else if ((c = wintoclient(ev->window))) {
317} 317 focus(c);
318 318 restack(selmon);
319void checkotherwm(void) { 319 XAllowEvents(dpy, ReplayPointer, CurrentTime);
320 xerrorxlib = XSetErrorHandler(xerrorstart); 320 click = ClkClientWin;
321 /* this causes an error if some other window manager is running */ 321 }
322 XSelectInput(dpy, DefaultRootWindow(dpy), SubstructureRedirectMask); 322 for (i = 0; i < LENGTH(buttons); i++)
323 XSync(dpy, False); 323 if (click == buttons[i].click && buttons[i].func &&
324 XSetErrorHandler(xerror); 324 buttons[i].button == ev->button &&
325 XSync(dpy, False); 325 CLEANMASK(buttons[i].mask) == CLEANMASK(ev->state))
326} 326 buttons[i].func(click == ClkTagBar &&
327 327 buttons[i].arg.i == 0
328void cleanup(void) { 328 ? &arg
329 Arg a = {.ui = ~0}; 329 : &buttons[i].arg);
330 Layout foo = {"", NULL}; 330}
331 Monitor *m; 331
332 size_t i; 332void checkotherwm(void)
333 333{
334 view(&a); 334 xerrorxlib = XSetErrorHandler(xerrorstart);
335 selmon->lt[selmon->sellt] = &foo; 335 /* this causes an error if some other window manager is running */
336 for (m = mons; m; m = m->next) 336 XSelectInput(dpy, DefaultRootWindow(dpy), SubstructureRedirectMask);
337 while (m->stack) 337 XSync(dpy, False);
338 unmanage(m->stack, 0); 338 XSetErrorHandler(xerror);
339 XUngrabKey(dpy, AnyKey, AnyModifier, root); 339 XSync(dpy, False);
340 while (mons) 340}
341 cleanupmon(mons); 341
342 342void cleanup(void)
343 if (showsystray) { 343{
344 XUnmapWindow(dpy, systray->win); 344 Arg a = {.ui = ~0};
345 XDestroyWindow(dpy, systray->win); 345 Layout foo = {"", NULL};
346 free(systray); 346 Monitor *m;
347 } 347 size_t i;
348 348
349 for (i = 0; i < CurLast; i++) 349 view(&a);
350 drw_cur_free(drw, cursor[i]); 350 selmon->lt[selmon->sellt] = &foo;
351 for (i = 0; i < LENGTH(colors); i++) 351 for (m = mons; m; m = m->next)
352 free(scheme[i]); 352 while (m->stack)
353 free(scheme); 353 unmanage(m->stack, 0);
354 XDestroyWindow(dpy, wmcheckwin); 354 XUngrabKey(dpy, AnyKey, AnyModifier, root);
355 drw_free(drw); 355 while (mons)
356 XSync(dpy, False); 356 cleanupmon(mons);
357 XSetInputFocus(dpy, PointerRoot, RevertToPointerRoot, CurrentTime); 357
358 XDeleteProperty(dpy, root, netatom[NetActiveWindow]); 358 if (showsystray) {
359} 359 XUnmapWindow(dpy, systray->win);
360 360 XDestroyWindow(dpy, systray->win);
361void cleanupmon(Monitor *mon) { 361 free(systray);
362 Monitor *m; 362 }
363 363
364 if (mon == mons) 364 for (i = 0; i < CurLast; i++)
365 mons = mons->next; 365 drw_cur_free(drw, cursor[i]);
366 else { 366 for (i = 0; i < LENGTH(colors); i++)
367 for (m = mons; m && m->next != mon; m = m->next) 367 free(scheme[i]);
368 ; 368 free(scheme);
369 m->next = mon->next; 369 XDestroyWindow(dpy, wmcheckwin);
370 } 370 drw_free(drw);
371 XUnmapWindow(dpy, mon->barwin); 371 XSync(dpy, False);
372 XDestroyWindow(dpy, mon->barwin); 372 XSetInputFocus(dpy, PointerRoot, RevertToPointerRoot, CurrentTime);
373 free(mon); 373 XDeleteProperty(dpy, root, netatom[NetActiveWindow]);
374} 374}
375 375
376void clientmessage(XEvent *e) { 376void cleanupmon(Monitor *mon)
377 XWindowAttributes wa; 377{
378 XSetWindowAttributes swa; 378 Monitor *m;
379 XClientMessageEvent *cme = &e->xclient; 379
380 Client *c = wintoclient(cme->window); 380 if (mon == mons)
381 381 mons = mons->next;
382 if (showsystray && cme->window == systray->win && 382 else {
383 cme->message_type == netatom[NetSystemTrayOP]) { 383 for (m = mons; m && m->next != mon; m = m->next)
384 /* add systray icons */ 384 ;
385 if (cme->data.l[1] == SYSTEM_TRAY_REQUEST_DOCK) { 385 m->next = mon->next;
386 if (!(c = (Client *)calloc(1, sizeof(Client)))) 386 }
387 die("fatal: could not malloc() %u bytes\n", sizeof(Client)); 387 XUnmapWindow(dpy, mon->barwin);
388 if (!(c->win = cme->data.l[2])) { 388 XDestroyWindow(dpy, mon->barwin);
389 free(c); 389 free(mon);
390 return; 390}
391 } 391
392 c->mon = selmon; 392void clientmessage(XEvent *e)
393 c->next = systray->icons; 393{
394 systray->icons = c; 394 XWindowAttributes wa;
395 if (!XGetWindowAttributes(dpy, c->win, &wa)) { 395 XSetWindowAttributes swa;
396 /* use sane defaults */ 396 XClientMessageEvent *cme = &e->xclient;
397 wa.width = bh; 397 Client *c = wintoclient(cme->window);
398 wa.height = bh; 398
399 wa.border_width = 0; 399 if (showsystray && cme->window == systray->win &&
400 } 400 cme->message_type == netatom[NetSystemTrayOP]) {
401 c->x = c->oldx = c->y = c->oldy = 0; 401 /* add systray icons */
402 c->w = c->oldw = wa.width; 402 if (cme->data.l[1] == SYSTEM_TRAY_REQUEST_DOCK) {
403 c->h = c->oldh = wa.height; 403 if (!(c = (Client *)calloc(1, sizeof(Client))))
404 c->oldbw = wa.border_width; 404 die("fatal: could not malloc() %u bytes\n",
405 c->bw = 0; 405 sizeof(Client));
406 c->isfloating = True; 406 if (!(c->win = cme->data.l[2])) {
407 /* reuse tags field as mapped status */ 407 free(c);
408 c->tags = 1; 408 return;
409 updatesizehints(c); 409 }
410 updatesystrayicongeom(c, wa.width, wa.height); 410 c->mon = selmon;
411 XAddToSaveSet(dpy, c->win); 411 c->next = systray->icons;
412 XSelectInput(dpy, c->win, 412 systray->icons = c;
413 StructureNotifyMask | PropertyChangeMask | 413 if (!XGetWindowAttributes(dpy, c->win, &wa)) {
414 ResizeRedirectMask); 414 /* use sane defaults */
415 XReparentWindow(dpy, c->win, systray->win, 0, 0); 415 wa.width = bh;
416 /* use parents background color */ 416 wa.height = bh;
417 swa.background_pixel = scheme[SchemeNorm][ColBg].pixel; 417 wa.border_width = 0;
418 XChangeWindowAttributes(dpy, c->win, CWBackPixel, &swa); 418 }
419 sendevent(c->win, netatom[Xembed], StructureNotifyMask, CurrentTime, 419 c->x = c->oldx = c->y = c->oldy = 0;
420 XEMBED_EMBEDDED_NOTIFY, 0, systray->win, 420 c->w = c->oldw = wa.width;
421 XEMBED_EMBEDDED_VERSION); 421 c->h = c->oldh = wa.height;
422 /* FIXME not sure if I have to send these events, too */ 422 c->oldbw = wa.border_width;
423 sendevent(c->win, netatom[Xembed], StructureNotifyMask, CurrentTime, 423 c->bw = 0;
424 XEMBED_FOCUS_IN, 0, systray->win, XEMBED_EMBEDDED_VERSION); 424 c->isfloating = True;
425 sendevent(c->win, netatom[Xembed], StructureNotifyMask, CurrentTime, 425 /* reuse tags field as mapped status */
426 XEMBED_WINDOW_ACTIVATE, 0, systray->win, 426 c->tags = 1;
427 XEMBED_EMBEDDED_VERSION); 427 updatesizehints(c);
428 sendevent(c->win, netatom[Xembed], StructureNotifyMask, CurrentTime, 428 updatesystrayicongeom(c, wa.width, wa.height);
429 XEMBED_MODALITY_ON, 0, systray->win, XEMBED_EMBEDDED_VERSION); 429 XAddToSaveSet(dpy, c->win);
430 XSync(dpy, False); 430 XSelectInput(dpy, c->win,
431 resizebarwin(selmon); 431 StructureNotifyMask | PropertyChangeMask |
432 updatesystray(); 432 ResizeRedirectMask);
433 setclientstate(c, NormalState); 433 XReparentWindow(dpy, c->win, systray->win, 0, 0);
434 } 434 /* use parents background color */
435 return; 435 swa.background_pixel = scheme[SchemeNorm][ColBg].pixel;
436 } 436 XChangeWindowAttributes(dpy, c->win, CWBackPixel, &swa);
437 437 sendevent(c->win, netatom[Xembed], StructureNotifyMask,
438 if (!c) 438 CurrentTime, XEMBED_EMBEDDED_NOTIFY, 0,
439 return; 439 systray->win, XEMBED_EMBEDDED_VERSION);
440 if (cme->message_type == netatom[NetWMState]) { 440 /* FIXME not sure if I have to send these events, too */
441 if (cme->data.l[1] == netatom[NetWMFullscreen] || 441 sendevent(c->win, netatom[Xembed], StructureNotifyMask,
442 cme->data.l[2] == netatom[NetWMFullscreen]) 442 CurrentTime, XEMBED_FOCUS_IN, 0, systray->win,
443 setfullscreen(c, (cme->data.l[0] == 1 /* _NET_WM_STATE_ADD */ 443 XEMBED_EMBEDDED_VERSION);
444 || (cme->data.l[0] == 2 /* _NET_WM_STATE_TOGGLE */ 444 sendevent(c->win, netatom[Xembed], StructureNotifyMask,
445 && !c->isfullscreen))); 445 CurrentTime, XEMBED_WINDOW_ACTIVATE, 0,
446 } else if (cme->message_type == netatom[NetActiveWindow]) { 446 systray->win, XEMBED_EMBEDDED_VERSION);
447 if (c != selmon->sel && !c->isurgent) 447 sendevent(c->win, netatom[Xembed], StructureNotifyMask,
448 seturgent(c, 1); 448 CurrentTime, XEMBED_MODALITY_ON, 0,
449 } 449 systray->win, XEMBED_EMBEDDED_VERSION);
450} 450 XSync(dpy, False);
451 451 resizebarwin(selmon);
452void configure(Client *c) { 452 updatesystray();
453 XConfigureEvent ce; 453 setclientstate(c, NormalState);
454 454 }
455 ce.type = ConfigureNotify; 455 return;
456 ce.display = dpy; 456 }
457 ce.event = c->win; 457
458 ce.window = c->win; 458 if (!c)
459 ce.x = c->x; 459 return;
460 ce.y = c->y; 460 if (cme->message_type == netatom[NetWMState]) {
461 ce.width = c->w; 461 if (cme->data.l[1] == netatom[NetWMFullscreen] ||
462 ce.height = c->h; 462 cme->data.l[2] == netatom[NetWMFullscreen])
463 ce.border_width = c->bw; 463 setfullscreen(
464 ce.above = None; 464 c,
465 ce.override_redirect = False; 465 (cme->data.l[0] == 1 /* _NET_WM_STATE_ADD */
466 XSendEvent(dpy, c->win, False, StructureNotifyMask, (XEvent *)&ce); 466 || (cme->data.l[0] == 2 /* _NET_WM_STATE_TOGGLE */
467} 467 && !c->isfullscreen)));
468 468 } else if (cme->message_type == netatom[NetActiveWindow]) {
469void configurenotify(XEvent *e) { 469 if (c != selmon->sel && !c->isurgent)
470 Monitor *m; 470 seturgent(c, 1);
471 Client *c; 471 }
472 XConfigureEvent *ev = &e->xconfigure; 472}
473 int dirty; 473
474 474void configure(Client *c)
475 /* TODO: updategeom handling sucks, needs to be simplified */ 475{
476 if (ev->window == root) { 476 XConfigureEvent ce;
477 dirty = (sw != ev->width || sh != ev->height); 477
478 sw = ev->width; 478 ce.type = ConfigureNotify;
479 sh = ev->height; 479 ce.display = dpy;
480 if (updategeom() || dirty) { 480 ce.event = c->win;
481 drw_resize(drw, sw, bh); 481 ce.window = c->win;
482 updatebars(); 482 ce.x = c->x;
483 for (m = mons; m; m = m->next) { 483 ce.y = c->y;
484 for (c = m->clients; c; c = c->next) 484 ce.width = c->w;
485 if (c->isfullscreen) 485 ce.height = c->h;
486 resizeclient(c, m->mx, m->my, m->mw, m->mh); 486 ce.border_width = c->bw;
487 resizebarwin(m); 487 ce.above = None;
488 } 488 ce.override_redirect = False;
489 focus(NULL); 489 XSendEvent(dpy, c->win, False, StructureNotifyMask, (XEvent *)&ce);
490 arrange(NULL); 490}
491 } 491
492 } 492void configurenotify(XEvent *e)
493} 493{
494 494 Monitor *m;
495void configurerequest(XEvent *e) { 495 Client *c;
496 Client *c; 496 XConfigureEvent *ev = &e->xconfigure;
497 Monitor *m; 497 int dirty;
498 XConfigureRequestEvent *ev = &e->xconfigurerequest; 498
499 XWindowChanges wc; 499 /* TODO: updategeom handling sucks, needs to be simplified */
500 500 if (ev->window == root) {
501 if ((c = wintoclient(ev->window))) { 501 dirty = (sw != ev->width || sh != ev->height);
502 if (ev->value_mask & CWBorderWidth) 502 sw = ev->width;
503 c->bw = ev->border_width; 503 sh = ev->height;
504 else if (c->isfloating || !selmon->lt[selmon->sellt]->arrange) { 504 if (updategeom() || dirty) {
505 m = c->mon; 505 drw_resize(drw, sw, bh);
506 if (ev->value_mask & CWX) { 506 updatebars();
507 c->oldx = c->x; 507 for (m = mons; m; m = m->next) {
508 c->x = m->mx + ev->x; 508 for (c = m->clients; c; c = c->next)
509 } 509 if (c->isfullscreen)
510 if (ev->value_mask & CWY) { 510 resizeclient(c, m->mx, m->my,
511 c->oldy = c->y; 511 m->mw, m->mh);
512 c->y = m->my + ev->y; 512 resizebarwin(m);
513 } 513 }
514 if (ev->value_mask & CWWidth) { 514 focus(NULL);
515 c->oldw = c->w; 515 arrange(NULL);
516 c->w = ev->width; 516 }
517 } 517 }
518 if (ev->value_mask & CWHeight) { 518}
519 c->oldh = c->h; 519
520 c->h = ev->height; 520void configurerequest(XEvent *e)
521 } 521{
522 if ((c->x + c->w) > m->mx + m->mw && c->isfloating) 522 Client *c;
523 c->x = m->mx + (m->mw / 2 - WIDTH(c) / 2); /* center in x direction */ 523 Monitor *m;
524 if ((c->y + c->h) > m->my + m->mh && c->isfloating) 524 XConfigureRequestEvent *ev = &e->xconfigurerequest;
525 c->y = m->my + (m->mh / 2 - HEIGHT(c) / 2); /* center in y direction */ 525 XWindowChanges wc;
526 if ((ev->value_mask & (CWX | CWY)) && 526
527 !(ev->value_mask & (CWWidth | CWHeight))) 527 if ((c = wintoclient(ev->window))) {
528 configure(c); 528 if (ev->value_mask & CWBorderWidth)
529 if (ISVISIBLE(c)) 529 c->bw = ev->border_width;
530 XMoveResizeWindow(dpy, c->win, c->x, c->y, c->w, c->h); 530 else if (c->isfloating || !selmon->lt[selmon->sellt]->arrange) {
531 } else 531 m = c->mon;
532 configure(c); 532 if (ev->value_mask & CWX) {
533 } else { 533 c->oldx = c->x;
534 wc.x = ev->x; 534 c->x = m->mx + ev->x;
535 wc.y = ev->y; 535 }
536 wc.width = ev->width; 536 if (ev->value_mask & CWY) {
537 wc.height = ev->height; 537 c->oldy = c->y;
538 wc.border_width = ev->border_width; 538 c->y = m->my + ev->y;
539 wc.sibling = ev->above; 539 }
540 wc.stack_mode = ev->detail; 540 if (ev->value_mask & CWWidth) {
541 XConfigureWindow(dpy, ev->window, ev->value_mask, &wc); 541 c->oldw = c->w;
542 } 542 c->w = ev->width;
543 XSync(dpy, False); 543 }
544} 544 if (ev->value_mask & CWHeight) {
545 545 c->oldh = c->h;
546Monitor *createmon(void) { 546 c->h = ev->height;
547 Monitor *m; 547 }
548 548 if ((c->x + c->w) > m->mx + m->mw && c->isfloating)
549 m = ecalloc(1, sizeof(Monitor)); 549 c->x =
550 m->tagset[0] = m->tagset[1] = 1; 550 m->mx +
551 m->mfact = mfact; 551 (m->mw / 2 -
552 m->nmaster = nmaster; 552 WIDTH(c) / 2); /* center in x direction */
553 m->showbar = showbar; 553 if ((c->y + c->h) > m->my + m->mh && c->isfloating)
554 m->topbar = topbar; 554 c->y =
555 m->gappih = gappih; 555 m->my +
556 m->gappiv = gappiv; 556 (m->mh / 2 -
557 m->gappoh = gappoh; 557 HEIGHT(c) / 2); /* center in y direction */
558 m->gappov = gappov; 558 if ((ev->value_mask & (CWX | CWY)) &&
559 m->lt[0] = &layouts[0]; 559 !(ev->value_mask & (CWWidth | CWHeight)))
560 m->lt[1] = &layouts[1 % LENGTH(layouts)]; 560 configure(c);
561 strncpy(m->ltsymbol, layouts[0].symbol, sizeof m->ltsymbol); 561 if (ISVISIBLE(c))
562 return m; 562 XMoveResizeWindow(dpy, c->win, c->x, c->y, c->w,
563} 563 c->h);
564 564 } else
565void destroynotify(XEvent *e) { 565 configure(c);
566 Client *c; 566 } else {
567 XDestroyWindowEvent *ev = &e->xdestroywindow; 567 wc.x = ev->x;
568 568 wc.y = ev->y;
569 if ((c = wintoclient(ev->window))) 569 wc.width = ev->width;
570 unmanage(c, 1); 570 wc.height = ev->height;
571 else if ((c = wintosystrayicon(ev->window))) { 571 wc.border_width = ev->border_width;
572 removesystrayicon(c); 572 wc.sibling = ev->above;
573 resizebarwin(selmon); 573 wc.stack_mode = ev->detail;
574 updatesystray(); 574 XConfigureWindow(dpy, ev->window, ev->value_mask, &wc);
575 } else if ((c = swallowingclient(ev->window))) 575 }
576 unmanage(c->swallowing, 1); 576 XSync(dpy, False);
577} 577}
578 578
579void detach(Client *c) { 579Monitor *createmon(void)
580 Client **tc; 580{
581 581 Monitor *m;
582 for (tc = &c->mon->clients; *tc && *tc != c; tc = &(*tc)->next) 582
583 ; 583 m = ecalloc(1, sizeof(Monitor));
584 *tc = c->next; 584 m->tagset[0] = m->tagset[1] = 1;
585} 585 m->mfact = mfact;
586 586 m->nmaster = nmaster;
587void detachstack(Client *c) { 587 m->showbar = showbar;
588 Client **tc, *t; 588 m->topbar = topbar;
589 589 m->gappih = gappih;
590 for (tc = &c->mon->stack; *tc && *tc != c; tc = &(*tc)->snext) 590 m->gappiv = gappiv;
591 ; 591 m->gappoh = gappoh;
592 *tc = c->snext; 592 m->gappov = gappov;
593 593 m->lt[0] = &layouts[0];
594 if (c == c->mon->sel) { 594 m->lt[1] = &layouts[1 % LENGTH(layouts)];
595 for (t = c->mon->stack; t && !ISVISIBLE(t); t = t->snext) 595 strncpy(m->ltsymbol, layouts[0].symbol, sizeof m->ltsymbol);
596 ; 596 return m;
597 c->mon->sel = t; 597}
598 } 598
599void destroynotify(XEvent *e)
600{
601 Client *c;
602 XDestroyWindowEvent *ev = &e->xdestroywindow;
603
604 if ((c = wintoclient(ev->window)))
605 unmanage(c, 1);
606 else if ((c = wintosystrayicon(ev->window))) {
607 removesystrayicon(c);
608 resizebarwin(selmon);
609 updatesystray();
610 } else if ((c = swallowingclient(ev->window)))
611 unmanage(c->swallowing, 1);
612}
613
614void detach(Client *c)
615{
616 Client **tc;
617
618 for (tc = &c->mon->clients; *tc && *tc != c; tc = &(*tc)->next)
619 ;
620 *tc = c->next;
621}
622
623void detachstack(Client *c)
624{
625 Client **tc, *t;
626
627 for (tc = &c->mon->stack; *tc && *tc != c; tc = &(*tc)->snext)
628 ;
629 *tc = c->snext;
630
631 if (c == c->mon->sel) {
632 for (t = c->mon->stack; t && !ISVISIBLE(t); t = t->snext)
633 ;
634 c->mon->sel = t;
635 }
599} 636}
600 637
601// Monitor *dirtomon(int dir) { 638// Monitor *dirtomon(int dir) {
@@ -613,131 +650,143 @@ void detachstack(Client *c) {
613// return m; 650// return m;
614// } 651// }
615 652
616void drawbar(Monitor *m) { 653void drawbar(Monitor *m)
617 int x, w, tw = 0, stw = 0; 654{
618 int boxs = drw->fonts->h / 9; 655 int x, w, tw = 0, stw = 0;
619 int boxw = drw->fonts->h / 6 + 2; 656 int boxs = drw->fonts->h / 9;
620 unsigned int i, occ = 0, urg = 0; 657 int boxw = drw->fonts->h / 6 + 2;
621 Client *c; 658 unsigned int i, occ = 0, urg = 0;
622 659 Client *c;
623 if (!m->showbar) 660
624 return; 661 if (!m->showbar)
625 662 return;
626 if (showsystray && m == systraytomon(m) && !systrayonleft) 663
627 stw = getsystraywidth(); 664 if (showsystray && m == systraytomon(m) && !systrayonleft)
628 665 stw = getsystraywidth();
629 /* draw status first so it can be overdrawn by tags later */ 666
630 if (m == selmon) { /* status is only drawn on selected monitor */ 667 /* draw status first so it can be overdrawn by tags later */
631 drw_setscheme(drw, scheme[SchemeNorm]); 668 if (m == selmon) { /* status is only drawn on selected monitor */
632 tw = TEXTW(stext) - lrpad / 2 + 2; /* 2px extra right padding */ 669 drw_setscheme(drw, scheme[SchemeNorm]);
633 drw_text(drw, m->ww - tw - stw, 0, tw, bh, lrpad / 2 - 2, stext, 0); 670 tw = TEXTW(stext) - lrpad / 2 + 2; /* 2px extra right padding */
634 } 671 drw_text(drw, m->ww - tw - stw, 0, tw, bh, lrpad / 2 - 2, stext,
635 672 0);
636 resizebarwin(m); 673 }
637 for (c = m->clients; c; c = c->next) { 674
638 occ |= c->tags; 675 resizebarwin(m);
639 if (c->isurgent) 676 for (c = m->clients; c; c = c->next) {
640 urg |= c->tags; 677 occ |= c->tags;
641 } 678 if (c->isurgent)
642 x = 0; 679 urg |= c->tags;
643 for (i = 0; i < LENGTH(tags); i++) { 680 }
644 /* Do not draw vacant tags */ 681 x = 0;
645 if (!(occ & 1 << i || m->tagset[m->seltags] & 1 << i)) 682 for (i = 0; i < LENGTH(tags); i++) {
646 continue; 683 /* Do not draw vacant tags */
647 w = TEXTW(tags[i]); 684 if (!(occ & 1 << i || m->tagset[m->seltags] & 1 << i))
648 drw_setscheme( 685 continue;
649 drw, scheme[m->tagset[m->seltags] & 1 << i ? SchemeSel : SchemeNorm]); 686 w = TEXTW(tags[i]);
650 drw_text(drw, x, 0, w, bh, lrpad / 2, tags[i], urg & 1 << i); 687 drw_setscheme(
651 if (occ & 1 << i) 688 drw, scheme[m->tagset[m->seltags] & 1 << i ? SchemeSel
652 drw_rect(drw, x + boxs, boxs, boxw, boxw, 689 : SchemeNorm]);
653 m == selmon && selmon->sel && selmon->sel->tags & 1 << i, 690 drw_text(drw, x, 0, w, bh, lrpad / 2, tags[i], urg & 1 << i);
654 urg & 1 << i); 691 if (occ & 1 << i)
655 x += w; 692 drw_rect(drw, x + boxs, boxs, boxw, boxw,
656 } 693 m == selmon && selmon->sel &&
657 w = TEXTW(m->ltsymbol); 694 selmon->sel->tags & 1 << i,
658 drw_setscheme(drw, scheme[SchemeNorm]); 695 urg & 1 << i);
659 x = drw_text(drw, x, 0, w, bh, lrpad / 2, m->ltsymbol, 0); 696 x += w;
660 697 }
661 if ((w = m->ww - tw - stw - x) > bh) { 698 w = TEXTW(m->ltsymbol);
662 if (m->sel) { 699 drw_setscheme(drw, scheme[SchemeNorm]);
663 drw_setscheme(drw, scheme[m == selmon ? SchemeSel : SchemeNorm]); 700 x = drw_text(drw, x, 0, w, bh, lrpad / 2, m->ltsymbol, 0);
664 drw_text(drw, x, 0, w, bh, lrpad / 2, m->sel->name, 0); 701
665 if (m->sel->isfloating) 702 if ((w = m->ww - tw - stw - x) > bh) {
666 drw_rect(drw, x + boxs, boxs, boxw, boxw, m->sel->isfixed, 0); 703 if (m->sel) {
667 } else { 704 drw_setscheme(
668 drw_setscheme(drw, scheme[SchemeNorm]); 705 drw, scheme[m == selmon ? SchemeSel : SchemeNorm]);
669 drw_rect(drw, x, 0, w, bh, 1, 1); 706 drw_text(drw, x, 0, w, bh, lrpad / 2, m->sel->name, 0);
670 } 707 if (m->sel->isfloating)
671 } 708 drw_rect(drw, x + boxs, boxs, boxw, boxw,
672 drw_map(drw, m->barwin, 0, 0, m->ww - stw, bh); 709 m->sel->isfixed, 0);
673} 710 } else {
674 711 drw_setscheme(drw, scheme[SchemeNorm]);
675void drawbars(void) { 712 drw_rect(drw, x, 0, w, bh, 1, 1);
676 Monitor *m; 713 }
677 714 }
678 for (m = mons; m; m = m->next) 715 drw_map(drw, m->barwin, 0, 0, m->ww - stw, bh);
679 drawbar(m); 716}
680} 717
681 718void drawbars(void)
682void enternotify(XEvent *e) { 719{
683 Client *c; 720 Monitor *m;
684 Monitor *m; 721
685 XCrossingEvent *ev = &e->xcrossing; 722 for (m = mons; m; m = m->next)
686 723 drawbar(m);
687 if ((ev->mode != NotifyNormal || ev->detail == NotifyInferior) && 724}
688 ev->window != root) 725
689 return; 726void enternotify(XEvent *e)
690 c = wintoclient(ev->window); 727{
691 m = c ? c->mon : wintomon(ev->window); 728 Client *c;
692 if (m != selmon) { 729 Monitor *m;
693 unfocus(selmon->sel, 1); 730 XCrossingEvent *ev = &e->xcrossing;
694 selmon = m; 731
695 } else if (!c || c == selmon->sel) 732 if ((ev->mode != NotifyNormal || ev->detail == NotifyInferior) &&
696 return; 733 ev->window != root)
697 focus(c); 734 return;
698} 735 c = wintoclient(ev->window);
699 736 m = c ? c->mon : wintomon(ev->window);
700void expose(XEvent *e) { 737 if (m != selmon) {
701 Monitor *m; 738 unfocus(selmon->sel, 1);
702 XExposeEvent *ev = &e->xexpose; 739 selmon = m;
703 740 } else if (!c || c == selmon->sel)
704 if (ev->count == 0 && (m = wintomon(ev->window))) { 741 return;
705 drawbar(m); 742 focus(c);
706 if (m == selmon) 743}
707 updatesystray(); 744
708 } 745void expose(XEvent *e)
709} 746{
710 747 Monitor *m;
711void focus(Client *c) { 748 XExposeEvent *ev = &e->xexpose;
712 if (!c || !ISVISIBLE(c)) 749
713 for (c = selmon->stack; c && !ISVISIBLE(c); c = c->snext) 750 if (ev->count == 0 && (m = wintomon(ev->window))) {
714 ; 751 drawbar(m);
715 if (selmon->sel && selmon->sel != c) 752 if (m == selmon)
716 unfocus(selmon->sel, 0); 753 updatesystray();
717 if (c) { 754 }
718 if (c->mon != selmon) 755}
719 selmon = c->mon; 756
720 if (c->isurgent) 757void focus(Client *c)
721 seturgent(c, 0); 758{
722 detachstack(c); 759 if (!c || !ISVISIBLE(c))
723 attachstack(c); 760 for (c = selmon->stack; c && !ISVISIBLE(c); c = c->snext)
724 grabbuttons(c, 1); 761 ;
725 XSetWindowBorder(dpy, c->win, scheme[SchemeSel][ColBorder].pixel); 762 if (selmon->sel && selmon->sel != c)
726 setfocus(c); 763 unfocus(selmon->sel, 0);
727 } else { 764 if (c) {
728 XSetInputFocus(dpy, root, RevertToPointerRoot, CurrentTime); 765 if (c->mon != selmon)
729 XDeleteProperty(dpy, root, netatom[NetActiveWindow]); 766 selmon = c->mon;
730 } 767 if (c->isurgent)
731 selmon->sel = c; 768 seturgent(c, 0);
732 drawbars(); 769 detachstack(c);
770 attachstack(c);
771 grabbuttons(c, 1);
772 XSetWindowBorder(dpy, c->win,
773 scheme[SchemeSel][ColBorder].pixel);
774 setfocus(c);
775 } else {
776 XSetInputFocus(dpy, root, RevertToPointerRoot, CurrentTime);
777 XDeleteProperty(dpy, root, netatom[NetActiveWindow]);
778 }
779 selmon->sel = c;
780 drawbars();
733} 781}
734 782
735/* there are some broken focus acquiring clients needing extra handling */ 783/* there are some broken focus acquiring clients needing extra handling */
736void focusin(XEvent *e) { 784void focusin(XEvent *e)
737 XFocusChangeEvent *ev = &e->xfocus; 785{
786 XFocusChangeEvent *ev = &e->xfocus;
738 787
739 if (selmon->sel && ev->window != selmon->sel->win) 788 if (selmon->sel && ev->window != selmon->sel->win)
740 setfocus(selmon->sel); 789 setfocus(selmon->sel);
741} 790}
742 791
743// void focusmon(const Arg *arg) { 792// void focusmon(const Arg *arg) {
@@ -778,127 +827,143 @@ void focusin(XEvent *e) {
778// } 827// }
779// } 828// }
780 829
781Atom getatomprop(Client *c, Atom prop) { 830Atom getatomprop(Client *c, Atom prop)
782 int di; 831{
783 unsigned long dl; 832 int di;
784 unsigned char *p = NULL; 833 unsigned long dl;
785 Atom da, atom = None; 834 unsigned char *p = NULL;
786 835 Atom da, atom = None;
787 /* FIXME getatomprop should return the number of items and a pointer to 836
788 * the stored data instead of this workaround */ 837 /* FIXME getatomprop should return the number of items and a pointer to
789 Atom req = XA_ATOM; 838 * the stored data instead of this workaround */
790 if (prop == xatom[XembedInfo]) 839 Atom req = XA_ATOM;
791 req = xatom[XembedInfo]; 840 if (prop == xatom[XembedInfo])
792 841 req = xatom[XembedInfo];
793 if (XGetWindowProperty(dpy, c->win, prop, 0L, sizeof atom, False, req, &da, 842
794 &di, &dl, &dl, &p) == Success && 843 if (XGetWindowProperty(dpy, c->win, prop, 0L, sizeof atom, False, req,
795 p) { 844 &da, &di, &dl, &dl, &p) == Success &&
796 atom = *(Atom *)p; 845 p) {
797 if (da == xatom[XembedInfo] && dl == 2) 846 atom = *(Atom *)p;
798 atom = ((Atom *)p)[1]; 847 if (da == xatom[XembedInfo] && dl == 2)
799 XFree(p); 848 atom = ((Atom *)p)[1];
800 } 849 XFree(p);
801 return atom; 850 }
802} 851 return atom;
803 852}
804unsigned int getsystraywidth() { 853
805 unsigned int w = 0; 854unsigned int getsystraywidth()
806 Client *i; 855{
807 if (showsystray) 856 unsigned int w = 0;
808 for (i = systray->icons; i; w += i->w + systrayspacing, i = i->next) 857 Client *i;
809 ; 858 if (showsystray)
810 return w ? w + systrayspacing : 1; 859 for (i = systray->icons; i;
811} 860 w += i->w + systrayspacing, i = i->next)
812 861 ;
813int getrootptr(int *x, int *y) { 862 return w ? w + systrayspacing : 1;
814 int di; 863}
815 unsigned int dui; 864
816 Window dummy; 865int getrootptr(int *x, int *y)
817 866{
818 return XQueryPointer(dpy, root, &dummy, &dummy, x, y, &di, &di, &dui); 867 int di;
819} 868 unsigned int dui;
820 869 Window dummy;
821long getstate(Window w) { 870
822 int format; 871 return XQueryPointer(dpy, root, &dummy, &dummy, x, y, &di, &di, &dui);
823 long result = -1; 872}
824 unsigned char *p = NULL; 873
825 unsigned long n, extra; 874long getstate(Window w)
826 Atom real; 875{
827 876 int format;
828 if (XGetWindowProperty(dpy, w, wmatom[WMState], 0L, 2L, False, 877 long result = -1;
829 wmatom[WMState], &real, &format, &n, &extra, 878 unsigned char *p = NULL;
830 (unsigned char **)&p) != Success) 879 unsigned long n, extra;
831 return -1; 880 Atom real;
832 if (n != 0) 881
833 result = *p; 882 if (XGetWindowProperty(dpy, w, wmatom[WMState], 0L, 2L, False,
834 XFree(p); 883 wmatom[WMState], &real, &format, &n, &extra,
835 return result; 884 (unsigned char **)&p) != Success)
836} 885 return -1;
837 886 if (n != 0)
838int gettextprop(Window w, Atom atom, char *text, unsigned int size) { 887 result = *p;
839 char **list = NULL; 888 XFree(p);
840 int n; 889 return result;
841 XTextProperty name; 890}
842 891
843 if (!text || size == 0) 892int gettextprop(Window w, Atom atom, char *text, unsigned int size)
844 return 0; 893{
845 text[0] = '\0'; 894 char **list = NULL;
846 if (!XGetTextProperty(dpy, w, &name, atom) || !name.nitems) 895 int n;
847 return 0; 896 XTextProperty name;
848 if (name.encoding == XA_STRING) { 897
849 strncpy(text, (char *)name.value, size - 1); 898 if (!text || size == 0)
850 } else if (XmbTextPropertyToTextList(dpy, &name, &list, &n) >= Success && 899 return 0;
851 n > 0 && *list) { 900 text[0] = '\0';
852 strncpy(text, *list, size - 1); 901 if (!XGetTextProperty(dpy, w, &name, atom) || !name.nitems)
853 XFreeStringList(list); 902 return 0;
854 } 903 if (name.encoding == XA_STRING) {
855 text[size - 1] = '\0'; 904 strncpy(text, (char *)name.value, size - 1);
856 XFree(name.value); 905 } else if (XmbTextPropertyToTextList(dpy, &name, &list, &n) >=
857 return 1; 906 Success &&
858} 907 n > 0 && *list) {
859 908 strncpy(text, *list, size - 1);
860void grabbuttons(Client *c, int focused) { 909 XFreeStringList(list);
861 updatenumlockmask(); 910 }
862 { 911 text[size - 1] = '\0';
863 unsigned int i, j; 912 XFree(name.value);
864 unsigned int modifiers[] = {0, LockMask, numlockmask, 913 return 1;
865 numlockmask | LockMask}; 914}
866 XUngrabButton(dpy, AnyButton, AnyModifier, c->win); 915
867 if (!focused) 916void grabbuttons(Client *c, int focused)
868 XGrabButton(dpy, AnyButton, AnyModifier, c->win, False, BUTTONMASK, 917{
869 GrabModeSync, GrabModeSync, None, None); 918 updatenumlockmask();
870 for (i = 0; i < LENGTH(buttons); i++) 919 {
871 if (buttons[i].click == ClkClientWin) 920 unsigned int i, j;
872 for (j = 0; j < LENGTH(modifiers); j++) 921 unsigned int modifiers[] = {0, LockMask, numlockmask,
873 XGrabButton(dpy, buttons[i].button, buttons[i].mask | modifiers[j], 922 numlockmask | LockMask};
874 c->win, False, BUTTONMASK, GrabModeAsync, GrabModeSync, 923 XUngrabButton(dpy, AnyButton, AnyModifier, c->win);
875 None, None); 924 if (!focused)
876 } 925 XGrabButton(dpy, AnyButton, AnyModifier, c->win, False,
877} 926 BUTTONMASK, GrabModeSync, GrabModeSync,
878 927 None, None);
879void grabkeys(void) { 928 for (i = 0; i < LENGTH(buttons); i++)
880 updatenumlockmask(); 929 if (buttons[i].click == ClkClientWin)
881 { 930 for (j = 0; j < LENGTH(modifiers); j++)
882 unsigned int i, j, k; 931 XGrabButton(dpy, buttons[i].button,
883 unsigned int modifiers[] = {0, LockMask, numlockmask, 932 buttons[i].mask |
884 numlockmask | LockMask}; 933 modifiers[j],
885 int start, end, skip; 934 c->win, False, BUTTONMASK,
886 KeySym *syms; 935 GrabModeAsync, GrabModeSync,
887 936 None, None);
888 XUngrabKey(dpy, AnyKey, AnyModifier, root); 937 }
889 XDisplayKeycodes(dpy, &start, &end); 938}
890 syms = XGetKeyboardMapping(dpy, start, end - start + 1, &skip); 939
891 if (!syms) 940void grabkeys(void)
892 return; 941{
893 for (k = start; k <= end; k++) 942 updatenumlockmask();
894 for (i = 0; i < LENGTH(keys); i++) 943 {
895 /* skip modifier codes, we do that ourselves */ 944 unsigned int i, j, k;
896 if (keys[i].keysym == syms[(k - start) * skip]) 945 unsigned int modifiers[] = {0, LockMask, numlockmask,
897 for (j = 0; j < LENGTH(modifiers); j++) 946 numlockmask | LockMask};
898 XGrabKey(dpy, k, keys[i].mod | modifiers[j], root, True, 947 int start, end, skip;
899 GrabModeAsync, GrabModeAsync); 948 KeySym *syms;
900 XFree(syms); 949
901 } 950 XUngrabKey(dpy, AnyKey, AnyModifier, root);
951 XDisplayKeycodes(dpy, &start, &end);
952 syms = XGetKeyboardMapping(dpy, start, end - start + 1, &skip);
953 if (!syms)
954 return;
955 for (k = start; k <= end; k++)
956 for (i = 0; i < LENGTH(keys); i++)
957 /* skip modifier codes, we do that ourselves */
958 if (keys[i].keysym == syms[(k - start) * skip])
959 for (j = 0; j < LENGTH(modifiers); j++)
960 XGrabKey(
961 dpy, k,
962 keys[i].mod | modifiers[j],
963 root, True, GrabModeAsync,
964 GrabModeAsync);
965 XFree(syms);
966 }
902} 967}
903 968
904// void incnmaster(const Arg *arg) { 969// void incnmaster(const Arg *arg) {
@@ -908,133 +973,143 @@ void grabkeys(void) {
908 973
909#ifdef XINERAMA 974#ifdef XINERAMA
910static int isuniquegeom(XineramaScreenInfo *unique, size_t n, 975static int isuniquegeom(XineramaScreenInfo *unique, size_t n,
911 XineramaScreenInfo *info) { 976 XineramaScreenInfo *info)
912 while (n--) 977{
913 if (unique[n].x_org == info->x_org && unique[n].y_org == info->y_org && 978 while (n--)
914 unique[n].width == info->width && unique[n].height == info->height) 979 if (unique[n].x_org == info->x_org &&
915 return 0; 980 unique[n].y_org == info->y_org &&
916 return 1; 981 unique[n].width == info->width &&
982 unique[n].height == info->height)
983 return 0;
984 return 1;
917} 985}
918#endif /* XINERAMA */ 986#endif /* XINERAMA */
919 987
920void keypress(XEvent *e) { 988void keypress(XEvent *e)
921 unsigned int i; 989{
922 KeySym keysym; 990 unsigned int i;
923 XKeyEvent *ev; 991 KeySym keysym;
924 992 XKeyEvent *ev;
925 ev = &e->xkey; 993
926 keysym = XKeycodeToKeysym(dpy, (KeyCode)ev->keycode, 0); 994 ev = &e->xkey;
927 for (i = 0; i < LENGTH(keys); i++) 995 keysym = XKeycodeToKeysym(dpy, (KeyCode)ev->keycode, 0);
928 if (keysym == keys[i].keysym && 996 for (i = 0; i < LENGTH(keys); i++)
929 CLEANMASK(keys[i].mod) == CLEANMASK(ev->state) && keys[i].func) 997 if (keysym == keys[i].keysym &&
930 keys[i].func(&(keys[i].arg)); 998 CLEANMASK(keys[i].mod) == CLEANMASK(ev->state) &&
931} 999 keys[i].func)
932 1000 keys[i].func(&(keys[i].arg));
933void killclient(const Arg *arg) { 1001}
934 if (!selmon->sel) 1002
935 return; 1003void killclient(const Arg *arg)
936 1004{
937 if (!sendevent(selmon->sel->win, wmatom[WMDelete], NoEventMask, 1005 if (!selmon->sel)
938 wmatom[WMDelete], CurrentTime, 0, 0, 0)) { 1006 return;
939 XGrabServer(dpy); 1007
940 XSetErrorHandler(xerrordummy); 1008 if (!sendevent(selmon->sel->win, wmatom[WMDelete], NoEventMask,
941 XSetCloseDownMode(dpy, DestroyAll); 1009 wmatom[WMDelete], CurrentTime, 0, 0, 0)) {
942 XKillClient(dpy, selmon->sel->win); 1010 XGrabServer(dpy);
943 XSync(dpy, False); 1011 XSetErrorHandler(xerrordummy);
944 XSetErrorHandler(xerror); 1012 XSetCloseDownMode(dpy, DestroyAll);
945 XUngrabServer(dpy); 1013 XKillClient(dpy, selmon->sel->win);
946 } 1014 XSync(dpy, False);
947} 1015 XSetErrorHandler(xerror);
948 1016 XUngrabServer(dpy);
949void manage(Window w, XWindowAttributes *wa) { 1017 }
950 Client *c, *t = NULL, *term = NULL; 1018}
951 Window trans = None; 1019
952 XWindowChanges wc; 1020void manage(Window w, XWindowAttributes *wa)
953 1021{
954 c = ecalloc(1, sizeof(Client)); 1022 Client *c, *t = NULL, *term = NULL;
955 c->win = w; 1023 Window trans = None;
956 c->pid = winpid(w); 1024 XWindowChanges wc;
957 /* geometry */ 1025
958 c->x = c->oldx = wa->x; 1026 c = ecalloc(1, sizeof(Client));
959 c->y = c->oldy = wa->y; 1027 c->win = w;
960 c->w = c->oldw = wa->width; 1028 c->pid = winpid(w);
961 c->h = c->oldh = wa->height; 1029 /* geometry */
962 c->oldbw = wa->border_width; 1030 c->x = c->oldx = wa->x;
963 1031 c->y = c->oldy = wa->y;
964 updatetitle(c); 1032 c->w = c->oldw = wa->width;
965 if (XGetTransientForHint(dpy, w, &trans) && (t = wintoclient(trans))) { 1033 c->h = c->oldh = wa->height;
966 c->mon = t->mon; 1034 c->oldbw = wa->border_width;
967 c->tags = t->tags; 1035
968 } else { 1036 updatetitle(c);
969 c->mon = selmon; 1037 if (XGetTransientForHint(dpy, w, &trans) && (t = wintoclient(trans))) {
970 applyrules(c); 1038 c->mon = t->mon;
971 term = termforwin(c); 1039 c->tags = t->tags;
972 } 1040 } else {
973 1041 c->mon = selmon;
974 if (c->x + WIDTH(c) > c->mon->wx + c->mon->ww) 1042 applyrules(c);
975 c->x = c->mon->wx + c->mon->ww - WIDTH(c); 1043 term = termforwin(c);
976 if (c->y + HEIGHT(c) > c->mon->wy + c->mon->wh) 1044 }
977 c->y = c->mon->wy + c->mon->wh - HEIGHT(c); 1045
978 c->x = MAX(c->x, c->mon->wx); 1046 if (c->x + WIDTH(c) > c->mon->wx + c->mon->ww)
979 c->y = MAX(c->y, c->mon->wy); 1047 c->x = c->mon->wx + c->mon->ww - WIDTH(c);
980 c->bw = borderpx; 1048 if (c->y + HEIGHT(c) > c->mon->wy + c->mon->wh)
981 1049 c->y = c->mon->wy + c->mon->wh - HEIGHT(c);
982 wc.border_width = c->bw; 1050 c->x = MAX(c->x, c->mon->wx);
983 XConfigureWindow(dpy, w, CWBorderWidth, &wc); 1051 c->y = MAX(c->y, c->mon->wy);
984 XSetWindowBorder(dpy, w, scheme[SchemeNorm][ColBorder].pixel); 1052 c->bw = borderpx;
985 configure(c); /* propagates border_width, if size doesn't change */ 1053
986 updatewindowtype(c); 1054 wc.border_width = c->bw;
987 updatesizehints(c); 1055 XConfigureWindow(dpy, w, CWBorderWidth, &wc);
988 updatewmhints(c); 1056 XSetWindowBorder(dpy, w, scheme[SchemeNorm][ColBorder].pixel);
989 XSelectInput(dpy, w, 1057 configure(c); /* propagates border_width, if size doesn't change */
990 EnterWindowMask | FocusChangeMask | PropertyChangeMask | 1058 updatewindowtype(c);
991 StructureNotifyMask); 1059 updatesizehints(c);
992 grabbuttons(c, 0); 1060 updatewmhints(c);
993 if (!c->isfloating) 1061 XSelectInput(dpy, w,
994 c->isfloating = c->oldstate = trans != None || c->isfixed; 1062 EnterWindowMask | FocusChangeMask | PropertyChangeMask |
995 if (c->isfloating) 1063 StructureNotifyMask);
996 XRaiseWindow(dpy, c->win); 1064 grabbuttons(c, 0);
997 attach(c); 1065 if (!c->isfloating)
998 attachstack(c); 1066 c->isfloating = c->oldstate = trans != None || c->isfixed;
999 XChangeProperty(dpy, root, netatom[NetClientList], XA_WINDOW, 32, 1067 if (c->isfloating)
1000 PropModeAppend, (unsigned char *)&(c->win), 1); 1068 XRaiseWindow(dpy, c->win);
1001 XMoveResizeWindow(dpy, c->win, c->x + 2 * sw, c->y, c->w, 1069 attach(c);
1002 c->h); /* some windows require this */ 1070 attachstack(c);
1003 setclientstate(c, NormalState); 1071 XChangeProperty(dpy, root, netatom[NetClientList], XA_WINDOW, 32,
1004 if (c->mon == selmon) 1072 PropModeAppend, (unsigned char *)&(c->win), 1);
1005 unfocus(selmon->sel, 0); 1073 XMoveResizeWindow(dpy, c->win, c->x + 2 * sw, c->y, c->w,
1006 c->mon->sel = c; 1074 c->h); /* some windows require this */
1007 arrange(c->mon); 1075 setclientstate(c, NormalState);
1008 XMapWindow(dpy, c->win); 1076 if (c->mon == selmon)
1009 if (term) 1077 unfocus(selmon->sel, 0);
1010 swallow(term, c); 1078 c->mon->sel = c;
1011 focus(NULL); 1079 arrange(c->mon);
1012} 1080 XMapWindow(dpy, c->win);
1013 1081 if (term)
1014void mappingnotify(XEvent *e) { 1082 swallow(term, c);
1015 XMappingEvent *ev = &e->xmapping; 1083 focus(NULL);
1016 1084}
1017 XRefreshKeyboardMapping(ev); 1085
1018 if (ev->request == MappingKeyboard) 1086void mappingnotify(XEvent *e)
1019 grabkeys(); 1087{
1020} 1088 XMappingEvent *ev = &e->xmapping;
1021 1089
1022void maprequest(XEvent *e) { 1090 XRefreshKeyboardMapping(ev);
1023 static XWindowAttributes wa; 1091 if (ev->request == MappingKeyboard)
1024 XMapRequestEvent *ev = &e->xmaprequest; 1092 grabkeys();
1025 1093}
1026 Client *i; 1094
1027 if ((i = wintosystrayicon(ev->window))) { 1095void maprequest(XEvent *e)
1028 sendevent(i->win, netatom[Xembed], StructureNotifyMask, CurrentTime, 1096{
1029 XEMBED_WINDOW_ACTIVATE, 0, systray->win, XEMBED_EMBEDDED_VERSION); 1097 static XWindowAttributes wa;
1030 resizebarwin(selmon); 1098 XMapRequestEvent *ev = &e->xmaprequest;
1031 updatesystray(); 1099
1032 } 1100 Client *i;
1033 1101 if ((i = wintosystrayicon(ev->window))) {
1034 if (!XGetWindowAttributes(dpy, ev->window, &wa) || wa.override_redirect) 1102 sendevent(i->win, netatom[Xembed], StructureNotifyMask,
1035 return; 1103 CurrentTime, XEMBED_WINDOW_ACTIVATE, 0, systray->win,
1036 if (!wintoclient(ev->window)) 1104 XEMBED_EMBEDDED_VERSION);
1037 manage(ev->window, &wa); 1105 resizebarwin(selmon);
1106 updatesystray();
1107 }
1108
1109 if (!XGetWindowAttributes(dpy, ev->window, &wa) || wa.override_redirect)
1110 return;
1111 if (!wintoclient(ev->window))
1112 manage(ev->window, &wa);
1038} 1113}
1039 1114
1040// void monocle(Monitor *m) { 1115// void monocle(Monitor *m) {
@@ -1050,1402 +1125,1442 @@ void maprequest(XEvent *e) {
1050// resize(c, m->wx, m->wy, m->ww - 2 * c->bw, m->wh - 2 * c->bw, 0); 1125// resize(c, m->wx, m->wy, m->ww - 2 * c->bw, m->wh - 2 * c->bw, 0);
1051// } 1126// }
1052 1127
1053void motionnotify(XEvent *e) { 1128void motionnotify(XEvent *e)
1054 static Monitor *mon = NULL; 1129{
1055 Monitor *m; 1130 static Monitor *mon = NULL;
1056 XMotionEvent *ev = &e->xmotion; 1131 Monitor *m;
1057 1132 XMotionEvent *ev = &e->xmotion;
1058 if (ev->window != root) 1133
1059 return; 1134 if (ev->window != root)
1060 if ((m = recttomon(ev->x_root, ev->y_root, 1, 1)) != mon && mon) { 1135 return;
1061 unfocus(selmon->sel, 1); 1136 if ((m = recttomon(ev->x_root, ev->y_root, 1, 1)) != mon && mon) {
1062 selmon = m; 1137 unfocus(selmon->sel, 1);
1063 focus(NULL); 1138 selmon = m;
1064 } 1139 focus(NULL);
1065 mon = m; 1140 }
1066} 1141 mon = m;
1067 1142}
1068void movemouse(const Arg *arg) { 1143
1069 int x, y, ocx, ocy, nx, ny; 1144void movemouse(const Arg *arg)
1070 Client *c; 1145{
1071 Monitor *m; 1146 int x, y, ocx, ocy, nx, ny;
1072 XEvent ev; 1147 Client *c;
1073 Time lasttime = 0; 1148 Monitor *m;
1074 1149 XEvent ev;
1075 if (!(c = selmon->sel)) 1150 Time lasttime = 0;
1076 return; 1151
1077 if (c->isfullscreen) /* no support moving fullscreen windows by mouse */ 1152 if (!(c = selmon->sel))
1078 return; 1153 return;
1079 restack(selmon); 1154 if (c->isfullscreen) /* no support moving fullscreen windows by mouse */
1080 ocx = c->x; 1155 return;
1081 ocy = c->y; 1156 restack(selmon);
1082 if (XGrabPointer(dpy, root, False, MOUSEMASK, GrabModeAsync, GrabModeAsync, 1157 ocx = c->x;
1083 None, cursor[CurMove]->cursor, CurrentTime) != GrabSuccess) 1158 ocy = c->y;
1084 return; 1159 if (XGrabPointer(dpy, root, False, MOUSEMASK, GrabModeAsync,
1085 if (!getrootptr(&x, &y)) 1160 GrabModeAsync, None, cursor[CurMove]->cursor,
1086 return; 1161 CurrentTime) != GrabSuccess)
1087 do { 1162 return;
1088 XMaskEvent(dpy, MOUSEMASK | ExposureMask | SubstructureRedirectMask, &ev); 1163 if (!getrootptr(&x, &y))
1089 switch (ev.type) { 1164 return;
1090 case ConfigureRequest: 1165 do {
1091 case Expose: 1166 XMaskEvent(dpy,
1092 case MapRequest: 1167 MOUSEMASK | ExposureMask | SubstructureRedirectMask,
1093 handler[ev.type](&ev); 1168 &ev);
1094 break; 1169 switch (ev.type) {
1095 case MotionNotify: 1170 case ConfigureRequest:
1096 if ((ev.xmotion.time - lasttime) <= (1000 / 60)) 1171 case Expose:
1097 continue; 1172 case MapRequest:
1098 lasttime = ev.xmotion.time; 1173 handler[ev.type](&ev);
1099 1174 break;
1100 nx = ocx + (ev.xmotion.x - x); 1175 case MotionNotify:
1101 ny = ocy + (ev.xmotion.y - y); 1176 if ((ev.xmotion.time - lasttime) <= (1000 / 60))
1102 if (abs(selmon->wx - nx) < snap) 1177 continue;
1103 nx = selmon->wx; 1178 lasttime = ev.xmotion.time;
1104 else if (abs((selmon->wx + selmon->ww) - (nx + WIDTH(c))) < snap) 1179
1105 nx = selmon->wx + selmon->ww - WIDTH(c); 1180 nx = ocx + (ev.xmotion.x - x);
1106 if (abs(selmon->wy - ny) < snap) 1181 ny = ocy + (ev.xmotion.y - y);
1107 ny = selmon->wy; 1182 if (abs(selmon->wx - nx) < snap)
1108 else if (abs((selmon->wy + selmon->wh) - (ny + HEIGHT(c))) < snap) 1183 nx = selmon->wx;
1109 ny = selmon->wy + selmon->wh - HEIGHT(c); 1184 else if (abs((selmon->wx + selmon->ww) -
1110 if (!c->isfloating && selmon->lt[selmon->sellt]->arrange && 1185 (nx + WIDTH(c))) < snap)
1111 (abs(nx - c->x) > snap || abs(ny - c->y) > snap)) 1186 nx = selmon->wx + selmon->ww - WIDTH(c);
1112 togglefloating(NULL); 1187 if (abs(selmon->wy - ny) < snap)
1113 if (!selmon->lt[selmon->sellt]->arrange || c->isfloating) 1188 ny = selmon->wy;
1114 resize(c, nx, ny, c->w, c->h, 1); 1189 else if (abs((selmon->wy + selmon->wh) -
1115 break; 1190 (ny + HEIGHT(c))) < snap)
1116 } 1191 ny = selmon->wy + selmon->wh - HEIGHT(c);
1117 } while (ev.type != ButtonRelease); 1192 if (!c->isfloating &&
1118 XUngrabPointer(dpy, CurrentTime); 1193 selmon->lt[selmon->sellt]->arrange &&
1119 if ((m = recttomon(c->x, c->y, c->w, c->h)) != selmon) { 1194 (abs(nx - c->x) > snap || abs(ny - c->y) > snap))
1120 sendmon(c, m); 1195 togglefloating(NULL);
1121 selmon = m; 1196 if (!selmon->lt[selmon->sellt]->arrange ||
1122 focus(NULL); 1197 c->isfloating)
1123 } 1198 resize(c, nx, ny, c->w, c->h, 1);
1124} 1199 break;
1125 1200 }
1126Client *nexttiled(Client *c) { 1201 } while (ev.type != ButtonRelease);
1127 for (; c && (c->isfloating || !ISVISIBLE(c)); c = c->next) 1202 XUngrabPointer(dpy, CurrentTime);
1128 ; 1203 if ((m = recttomon(c->x, c->y, c->w, c->h)) != selmon) {
1129 return c; 1204 sendmon(c, m);
1130} 1205 selmon = m;
1131 1206 focus(NULL);
1132void pop(Client *c) { 1207 }
1133 detach(c); 1208}
1134 attach(c); 1209
1135 focus(c); 1210Client *nexttiled(Client *c)
1136 arrange(c->mon); 1211{
1137} 1212 for (; c && (c->isfloating || !ISVISIBLE(c)); c = c->next)
1138 1213 ;
1139void propertynotify(XEvent *e) { 1214 return c;
1140 Client *c; 1215}
1141 Window trans; 1216
1142 XPropertyEvent *ev = &e->xproperty; 1217void pop(Client *c)
1143 1218{
1144 if ((c = wintosystrayicon(ev->window))) { 1219 detach(c);
1145 if (ev->atom == XA_WM_NORMAL_HINTS) { 1220 attach(c);
1146 updatesizehints(c); 1221 focus(c);
1147 updatesystrayicongeom(c, c->w, c->h); 1222 arrange(c->mon);
1148 } else 1223}
1149 updatesystrayiconstate(c, ev); 1224
1150 resizebarwin(selmon); 1225void propertynotify(XEvent *e)
1151 updatesystray(); 1226{
1152 } 1227 Client *c;
1153 1228 Window trans;
1154 if ((ev->window == root) && (ev->atom == XA_WM_NAME)) 1229 XPropertyEvent *ev = &e->xproperty;
1155 updatestatus(); 1230
1156 else if (ev->state == PropertyDelete) 1231 if ((c = wintosystrayicon(ev->window))) {
1157 return; /* ignore */ 1232 if (ev->atom == XA_WM_NORMAL_HINTS) {
1158 else if ((c = wintoclient(ev->window))) { 1233 updatesizehints(c);
1159 switch (ev->atom) { 1234 updatesystrayicongeom(c, c->w, c->h);
1160 default: 1235 } else
1161 break; 1236 updatesystrayiconstate(c, ev);
1162 case XA_WM_TRANSIENT_FOR: 1237 resizebarwin(selmon);
1163 if (!c->isfloating && (XGetTransientForHint(dpy, c->win, &trans)) && 1238 updatesystray();
1164 (c->isfloating = (wintoclient(trans)) != NULL)) 1239 }
1165 arrange(c->mon); 1240
1166 break; 1241 if ((ev->window == root) && (ev->atom == XA_WM_NAME))
1167 case XA_WM_NORMAL_HINTS: 1242 updatestatus();
1168 c->hintsvalid = 0; 1243 else if (ev->state == PropertyDelete)
1169 break; 1244 return; /* ignore */
1170 case XA_WM_HINTS: 1245 else if ((c = wintoclient(ev->window))) {
1171 updatewmhints(c); 1246 switch (ev->atom) {
1172 drawbars(); 1247 default:
1173 break; 1248 break;
1174 } 1249 case XA_WM_TRANSIENT_FOR:
1175 if (ev->atom == XA_WM_NAME || ev->atom == netatom[NetWMName]) { 1250 if (!c->isfloating &&
1176 updatetitle(c); 1251 (XGetTransientForHint(dpy, c->win, &trans)) &&
1177 if (c == c->mon->sel) 1252 (c->isfloating = (wintoclient(trans)) != NULL))
1178 drawbar(c->mon); 1253 arrange(c->mon);
1179 } 1254 break;
1180 if (ev->atom == netatom[NetWMWindowType]) 1255 case XA_WM_NORMAL_HINTS:
1181 updatewindowtype(c); 1256 c->hintsvalid = 0;
1182 } 1257 break;
1258 case XA_WM_HINTS:
1259 updatewmhints(c);
1260 drawbars();
1261 break;
1262 }
1263 if (ev->atom == XA_WM_NAME || ev->atom == netatom[NetWMName]) {
1264 updatetitle(c);
1265 if (c == c->mon->sel)
1266 drawbar(c->mon);
1267 }
1268 if (ev->atom == netatom[NetWMWindowType])
1269 updatewindowtype(c);
1270 }
1183} 1271}
1184 1272
1185void quit(const Arg *arg) { running = 0; } 1273void quit(const Arg *arg) { running = 0; }
1186 1274
1187Monitor *recttomon(int x, int y, int w, int h) { 1275Monitor *recttomon(int x, int y, int w, int h)
1188 Monitor *m, *r = selmon; 1276{
1189 int a, area = 0; 1277 Monitor *m, *r = selmon;
1190 1278 int a, area = 0;
1191 for (m = mons; m; m = m->next) 1279
1192 if ((a = INTERSECT(x, y, w, h, m)) > area) { 1280 for (m = mons; m; m = m->next)
1193 area = a; 1281 if ((a = INTERSECT(x, y, w, h, m)) > area) {
1194 r = m; 1282 area = a;
1195 } 1283 r = m;
1196 return r; 1284 }
1197} 1285 return r;
1198 1286}
1199void removesystrayicon(Client *i) { 1287
1200 Client **ii; 1288void removesystrayicon(Client *i)
1201 1289{
1202 if (!showsystray || !i) 1290 Client **ii;
1203 return; 1291
1204 for (ii = &systray->icons; *ii && *ii != i; ii = &(*ii)->next) 1292 if (!showsystray || !i)
1205 ; 1293 return;
1206 if (ii) 1294 for (ii = &systray->icons; *ii && *ii != i; ii = &(*ii)->next)
1207 *ii = i->next; 1295 ;
1208 free(i); 1296 if (ii)
1209} 1297 *ii = i->next;
1210 1298 free(i);
1211void resize(Client *c, int x, int y, int w, int h, int interact) { 1299}
1212 if (applysizehints(c, &x, &y, &w, &h, interact)) 1300
1213 resizeclient(c, x, y, w, h); 1301void resize(Client *c, int x, int y, int w, int h, int interact)
1214} 1302{
1215 1303 if (applysizehints(c, &x, &y, &w, &h, interact))
1216void resizebarwin(Monitor *m) { 1304 resizeclient(c, x, y, w, h);
1217 unsigned int w = m->ww; 1305}
1218 if (showsystray && m == systraytomon(m) && !systrayonleft) 1306
1219 w -= getsystraywidth(); 1307void resizebarwin(Monitor *m)
1220 XMoveResizeWindow(dpy, m->barwin, m->wx, m->by, w, bh); 1308{
1221} 1309 unsigned int w = m->ww;
1222 1310 if (showsystray && m == systraytomon(m) && !systrayonleft)
1223void resizeclient(Client *c, int x, int y, int w, int h) { 1311 w -= getsystraywidth();
1224 XWindowChanges wc; 1312 XMoveResizeWindow(dpy, m->barwin, m->wx, m->by, w, bh);
1225 1313}
1226 c->oldx = c->x; 1314
1227 c->x = wc.x = x; 1315void resizeclient(Client *c, int x, int y, int w, int h)
1228 c->oldy = c->y; 1316{
1229 c->y = wc.y = y; 1317 XWindowChanges wc;
1230 c->oldw = c->w; 1318
1231 c->w = wc.width = w; 1319 c->oldx = c->x;
1232 c->oldh = c->h; 1320 c->x = wc.x = x;
1233 c->h = wc.height = h; 1321 c->oldy = c->y;
1234 wc.border_width = c->bw; 1322 c->y = wc.y = y;
1235 XConfigureWindow(dpy, c->win, CWX | CWY | CWWidth | CWHeight | CWBorderWidth, 1323 c->oldw = c->w;
1236 &wc); 1324 c->w = wc.width = w;
1237 configure(c); 1325 c->oldh = c->h;
1238 XSync(dpy, False); 1326 c->h = wc.height = h;
1239} 1327 wc.border_width = c->bw;
1240 1328 XConfigureWindow(dpy, c->win,
1241void resizerequest(XEvent *e) { 1329 CWX | CWY | CWWidth | CWHeight | CWBorderWidth, &wc);
1242 XResizeRequestEvent *ev = &e->xresizerequest; 1330 configure(c);
1243 Client *i; 1331 XSync(dpy, False);
1244 1332}
1245 if ((i = wintosystrayicon(ev->window))) { 1333
1246 updatesystrayicongeom(i, ev->width, ev->height); 1334void resizerequest(XEvent *e)
1247 resizebarwin(selmon); 1335{
1248 updatesystray(); 1336 XResizeRequestEvent *ev = &e->xresizerequest;
1249 } 1337 Client *i;
1250} 1338
1251 1339 if ((i = wintosystrayicon(ev->window))) {
1252void resizemouse(const Arg *arg) { 1340 updatesystrayicongeom(i, ev->width, ev->height);
1253 int ocx, ocy, nw, nh; 1341 resizebarwin(selmon);
1254 Client *c; 1342 updatesystray();
1255 Monitor *m; 1343 }
1256 XEvent ev; 1344}
1257 Time lasttime = 0; 1345
1258 1346void resizemouse(const Arg *arg)
1259 if (!(c = selmon->sel)) 1347{
1260 return; 1348 int ocx, ocy, nw, nh;
1261 if (c->isfullscreen) /* no support resizing fullscreen windows by mouse */ 1349 Client *c;
1262 return; 1350 Monitor *m;
1263 restack(selmon); 1351 XEvent ev;
1264 ocx = c->x; 1352 Time lasttime = 0;
1265 ocy = c->y; 1353
1266 if (XGrabPointer(dpy, root, False, MOUSEMASK, GrabModeAsync, GrabModeAsync, 1354 if (!(c = selmon->sel))
1267 None, cursor[CurResize]->cursor, CurrentTime) != GrabSuccess) 1355 return;
1268 return; 1356 if (c->isfullscreen) /* no support resizing fullscreen windows by mouse
1269 XWarpPointer(dpy, None, c->win, 0, 0, 0, 0, c->w + c->bw - 1, 1357 */
1270 c->h + c->bw - 1); 1358 return;
1271 do { 1359 restack(selmon);
1272 XMaskEvent(dpy, MOUSEMASK | ExposureMask | SubstructureRedirectMask, &ev); 1360 ocx = c->x;
1273 switch (ev.type) { 1361 ocy = c->y;
1274 case ConfigureRequest: 1362 if (XGrabPointer(dpy, root, False, MOUSEMASK, GrabModeAsync,
1275 case Expose: 1363 GrabModeAsync, None, cursor[CurResize]->cursor,
1276 case MapRequest: 1364 CurrentTime) != GrabSuccess)
1277 handler[ev.type](&ev); 1365 return;
1278 break; 1366 XWarpPointer(dpy, None, c->win, 0, 0, 0, 0, c->w + c->bw - 1,
1279 case MotionNotify: 1367 c->h + c->bw - 1);
1280 if ((ev.xmotion.time - lasttime) <= (1000 / 60)) 1368 do {
1281 continue; 1369 XMaskEvent(dpy,
1282 lasttime = ev.xmotion.time; 1370 MOUSEMASK | ExposureMask | SubstructureRedirectMask,
1283 1371 &ev);
1284 nw = MAX(ev.xmotion.x - ocx - 2 * c->bw + 1, 1); 1372 switch (ev.type) {
1285 nh = MAX(ev.xmotion.y - ocy - 2 * c->bw + 1, 1); 1373 case ConfigureRequest:
1286 if (c->mon->wx + nw >= selmon->wx && 1374 case Expose:
1287 c->mon->wx + nw <= selmon->wx + selmon->ww && 1375 case MapRequest:
1288 c->mon->wy + nh >= selmon->wy && 1376 handler[ev.type](&ev);
1289 c->mon->wy + nh <= selmon->wy + selmon->wh) { 1377 break;
1290 if (!c->isfloating && selmon->lt[selmon->sellt]->arrange && 1378 case MotionNotify:
1291 (abs(nw - c->w) > snap || abs(nh - c->h) > snap)) 1379 if ((ev.xmotion.time - lasttime) <= (1000 / 60))
1292 togglefloating(NULL); 1380 continue;
1293 } 1381 lasttime = ev.xmotion.time;
1294 if (!selmon->lt[selmon->sellt]->arrange || c->isfloating) 1382
1295 resize(c, c->x, c->y, nw, nh, 1); 1383 nw = MAX(ev.xmotion.x - ocx - 2 * c->bw + 1, 1);
1296 break; 1384 nh = MAX(ev.xmotion.y - ocy - 2 * c->bw + 1, 1);
1297 } 1385 if (c->mon->wx + nw >= selmon->wx &&
1298 } while (ev.type != ButtonRelease); 1386 c->mon->wx + nw <= selmon->wx + selmon->ww &&
1299 XWarpPointer(dpy, None, c->win, 0, 0, 0, 0, c->w + c->bw - 1, 1387 c->mon->wy + nh >= selmon->wy &&
1300 c->h + c->bw - 1); 1388 c->mon->wy + nh <= selmon->wy + selmon->wh) {
1301 XUngrabPointer(dpy, CurrentTime); 1389 if (!c->isfloating &&
1302 while (XCheckMaskEvent(dpy, EnterWindowMask, &ev)) 1390 selmon->lt[selmon->sellt]->arrange &&
1303 ; 1391 (abs(nw - c->w) > snap ||
1304 if ((m = recttomon(c->x, c->y, c->w, c->h)) != selmon) { 1392 abs(nh - c->h) > snap))
1305 sendmon(c, m); 1393 togglefloating(NULL);
1306 selmon = m; 1394 }
1307 focus(NULL); 1395 if (!selmon->lt[selmon->sellt]->arrange ||
1308 } 1396 c->isfloating)
1309} 1397 resize(c, c->x, c->y, nw, nh, 1);
1310 1398 break;
1311void restack(Monitor *m) { 1399 }
1312 Client *c; 1400 } while (ev.type != ButtonRelease);
1313 XEvent ev; 1401 XWarpPointer(dpy, None, c->win, 0, 0, 0, 0, c->w + c->bw - 1,
1314 XWindowChanges wc; 1402 c->h + c->bw - 1);
1315 1403 XUngrabPointer(dpy, CurrentTime);
1316 drawbar(m); 1404 while (XCheckMaskEvent(dpy, EnterWindowMask, &ev))
1317 if (!m->sel) 1405 ;
1318 return; 1406 if ((m = recttomon(c->x, c->y, c->w, c->h)) != selmon) {
1319 if (m->sel->isfloating || !m->lt[m->sellt]->arrange) 1407 sendmon(c, m);
1320 XRaiseWindow(dpy, m->sel->win); 1408 selmon = m;
1321 if (m->lt[m->sellt]->arrange) { 1409 focus(NULL);
1322 wc.stack_mode = Below; 1410 }
1323 wc.sibling = m->barwin; 1411}
1324 for (c = m->stack; c; c = c->snext) 1412
1325 if (!c->isfloating && ISVISIBLE(c)) { 1413void restack(Monitor *m)
1326 XConfigureWindow(dpy, c->win, CWSibling | CWStackMode, &wc); 1414{
1327 wc.sibling = c->win; 1415 Client *c;
1328 } 1416 XEvent ev;
1329 } 1417 XWindowChanges wc;
1330 XSync(dpy, False); 1418
1331 while (XCheckMaskEvent(dpy, EnterWindowMask, &ev)) 1419 drawbar(m);
1332 ; 1420 if (!m->sel)
1333} 1421 return;
1334 1422 if (m->sel->isfloating || !m->lt[m->sellt]->arrange)
1335void run(void) { 1423 XRaiseWindow(dpy, m->sel->win);
1336 XEvent ev; 1424 if (m->lt[m->sellt]->arrange) {
1337 /* main event loop */ 1425 wc.stack_mode = Below;
1338 XSync(dpy, False); 1426 wc.sibling = m->barwin;
1339 while (running && !XNextEvent(dpy, &ev)) 1427 for (c = m->stack; c; c = c->snext)
1340 if (handler[ev.type]) 1428 if (!c->isfloating && ISVISIBLE(c)) {
1341 handler[ev.type](&ev); /* call handler */ 1429 XConfigureWindow(dpy, c->win,
1342} 1430 CWSibling | CWStackMode, &wc);
1343 1431 wc.sibling = c->win;
1344void scan(void) { 1432 }
1345 unsigned int i, num; 1433 }
1346 Window d1, d2, *wins = NULL; 1434 XSync(dpy, False);
1347 XWindowAttributes wa; 1435 while (XCheckMaskEvent(dpy, EnterWindowMask, &ev))
1348 1436 ;
1349 if (XQueryTree(dpy, root, &d1, &d2, &wins, &num)) { 1437}
1350 for (i = 0; i < num; i++) { 1438
1351 if (!XGetWindowAttributes(dpy, wins[i], &wa) || wa.override_redirect || 1439void run(void)
1352 XGetTransientForHint(dpy, wins[i], &d1)) 1440{
1353 continue; 1441 XEvent ev;
1354 if (wa.map_state == IsViewable || getstate(wins[i]) == IconicState) 1442 /* main event loop */
1355 manage(wins[i], &wa); 1443 XSync(dpy, False);
1356 } 1444 while (running && !XNextEvent(dpy, &ev))
1357 for (i = 0; i < num; i++) { /* now the transients */ 1445 if (handler[ev.type])
1358 if (!XGetWindowAttributes(dpy, wins[i], &wa)) 1446 handler[ev.type](&ev); /* call handler */
1359 continue; 1447}
1360 if (XGetTransientForHint(dpy, wins[i], &d1) && 1448
1361 (wa.map_state == IsViewable || getstate(wins[i]) == IconicState)) 1449void scan(void)
1362 manage(wins[i], &wa); 1450{
1363 } 1451 unsigned int i, num;
1364 if (wins) 1452 Window d1, d2, *wins = NULL;
1365 XFree(wins); 1453 XWindowAttributes wa;
1366 } 1454
1367} 1455 if (XQueryTree(dpy, root, &d1, &d2, &wins, &num)) {
1368 1456 for (i = 0; i < num; i++) {
1369void sendmon(Client *c, Monitor *m) { 1457 if (!XGetWindowAttributes(dpy, wins[i], &wa) ||
1370 if (c->mon == m) 1458 wa.override_redirect ||
1371 return; 1459 XGetTransientForHint(dpy, wins[i], &d1))
1372 unfocus(c, 1); 1460 continue;
1373 detach(c); 1461 if (wa.map_state == IsViewable ||
1374 detachstack(c); 1462 getstate(wins[i]) == IconicState)
1375 c->mon = m; 1463 manage(wins[i], &wa);
1376 c->tags = m->tagset[m->seltags]; /* assign tags of target monitor */ 1464 }
1377 attach(c); 1465 for (i = 0; i < num; i++) { /* now the transients */
1378 attachstack(c); 1466 if (!XGetWindowAttributes(dpy, wins[i], &wa))
1379 focus(NULL); 1467 continue;
1380 arrange(NULL); 1468 if (XGetTransientForHint(dpy, wins[i], &d1) &&
1381} 1469 (wa.map_state == IsViewable ||
1382 1470 getstate(wins[i]) == IconicState))
1383void setclientstate(Client *c, long state) { 1471 manage(wins[i], &wa);
1384 long data[] = {state, None}; 1472 }
1385 1473 if (wins)
1386 XChangeProperty(dpy, c->win, wmatom[WMState], wmatom[WMState], 32, 1474 XFree(wins);
1387 PropModeReplace, (unsigned char *)data, 2); 1475 }
1476}
1477
1478void sendmon(Client *c, Monitor *m)
1479{
1480 if (c->mon == m)
1481 return;
1482 unfocus(c, 1);
1483 detach(c);
1484 detachstack(c);
1485 c->mon = m;
1486 c->tags = m->tagset[m->seltags]; /* assign tags of target monitor */
1487 attach(c);
1488 attachstack(c);
1489 focus(NULL);
1490 arrange(NULL);
1491}
1492
1493void setclientstate(Client *c, long state)
1494{
1495 long data[] = {state, None};
1496
1497 XChangeProperty(dpy, c->win, wmatom[WMState], wmatom[WMState], 32,
1498 PropModeReplace, (unsigned char *)data, 2);
1388} 1499}
1389 1500
1390int sendevent(Window w, Atom proto, int mask, long d0, long d1, long d2, 1501int sendevent(Window w, Atom proto, int mask, long d0, long d1, long d2,
1391 long d3, long d4) { 1502 long d3, long d4)
1392 int n; 1503{
1393 Atom *protocols, mt; 1504 int n;
1394 int exists = 0; 1505 Atom *protocols, mt;
1395 XEvent ev; 1506 int exists = 0;
1396 1507 XEvent ev;
1397 if (proto == wmatom[WMTakeFocus] || proto == wmatom[WMDelete]) { 1508
1398 mt = wmatom[WMProtocols]; 1509 if (proto == wmatom[WMTakeFocus] || proto == wmatom[WMDelete]) {
1399 if (XGetWMProtocols(dpy, w, &protocols, &n)) { 1510 mt = wmatom[WMProtocols];
1400 while (!exists && n--) 1511 if (XGetWMProtocols(dpy, w, &protocols, &n)) {
1401 exists = protocols[n] == proto; 1512 while (!exists && n--)
1402 XFree(protocols); 1513 exists = protocols[n] == proto;
1403 } 1514 XFree(protocols);
1404 } else { 1515 }
1405 exists = True; 1516 } else {
1406 mt = proto; 1517 exists = True;
1407 } 1518 mt = proto;
1408 1519 }
1409 if (exists) { 1520
1410 ev.type = ClientMessage; 1521 if (exists) {
1411 ev.xclient.window = w; 1522 ev.type = ClientMessage;
1412 ev.xclient.message_type = mt; 1523 ev.xclient.window = w;
1413 ev.xclient.format = 32; 1524 ev.xclient.message_type = mt;
1414 ev.xclient.data.l[0] = d0; 1525 ev.xclient.format = 32;
1415 ev.xclient.data.l[1] = d1; 1526 ev.xclient.data.l[0] = d0;
1416 ev.xclient.data.l[2] = d2; 1527 ev.xclient.data.l[1] = d1;
1417 ev.xclient.data.l[3] = d3; 1528 ev.xclient.data.l[2] = d2;
1418 ev.xclient.data.l[4] = d4; 1529 ev.xclient.data.l[3] = d3;
1419 XSendEvent(dpy, w, False, mask, &ev); 1530 ev.xclient.data.l[4] = d4;
1420 } 1531 XSendEvent(dpy, w, False, mask, &ev);
1421 return exists; 1532 }
1422} 1533 return exists;
1423 1534}
1424void setfocus(Client *c) { 1535
1425 if (!c->neverfocus) { 1536void setfocus(Client *c)
1426 XSetInputFocus(dpy, c->win, RevertToPointerRoot, CurrentTime); 1537{
1427 XChangeProperty(dpy, root, netatom[NetActiveWindow], XA_WINDOW, 32, 1538 if (!c->neverfocus) {
1428 PropModeReplace, (unsigned char *)&(c->win), 1); 1539 XSetInputFocus(dpy, c->win, RevertToPointerRoot, CurrentTime);
1429 } 1540 XChangeProperty(dpy, root, netatom[NetActiveWindow], XA_WINDOW,
1430 sendevent(c->win, wmatom[WMTakeFocus], NoEventMask, wmatom[WMTakeFocus], 1541 32, PropModeReplace, (unsigned char *)&(c->win),
1431 CurrentTime, 0, 0, 0); 1542 1);
1432} 1543 }
1433 1544 sendevent(c->win, wmatom[WMTakeFocus], NoEventMask, wmatom[WMTakeFocus],
1434void setfullscreen(Client *c, int fullscreen) { 1545 CurrentTime, 0, 0, 0);
1435 if (fullscreen && !c->isfullscreen) { 1546}
1436 XChangeProperty(dpy, c->win, netatom[NetWMState], XA_ATOM, 32, 1547
1437 PropModeReplace, (unsigned char *)&netatom[NetWMFullscreen], 1548void setfullscreen(Client *c, int fullscreen)
1438 1); 1549{
1439 c->isfullscreen = 1; 1550 if (fullscreen && !c->isfullscreen) {
1440 c->oldstate = c->isfloating; 1551 XChangeProperty(dpy, c->win, netatom[NetWMState], XA_ATOM, 32,
1441 c->oldbw = c->bw; 1552 PropModeReplace,
1442 c->bw = 0; 1553 (unsigned char *)&netatom[NetWMFullscreen], 1);
1443 c->isfloating = 1; 1554 c->isfullscreen = 1;
1444 resizeclient(c, c->mon->mx, c->mon->my, c->mon->mw, c->mon->mh); 1555 c->oldstate = c->isfloating;
1445 XRaiseWindow(dpy, c->win); 1556 c->oldbw = c->bw;
1446 } else if (!fullscreen && c->isfullscreen) { 1557 c->bw = 0;
1447 XChangeProperty(dpy, c->win, netatom[NetWMState], XA_ATOM, 32, 1558 c->isfloating = 1;
1448 PropModeReplace, (unsigned char *)0, 0); 1559 resizeclient(c, c->mon->mx, c->mon->my, c->mon->mw, c->mon->mh);
1449 c->isfullscreen = 0; 1560 XRaiseWindow(dpy, c->win);
1450 c->isfloating = c->oldstate; 1561 } else if (!fullscreen && c->isfullscreen) {
1451 c->bw = c->oldbw; 1562 XChangeProperty(dpy, c->win, netatom[NetWMState], XA_ATOM, 32,
1452 c->x = c->oldx; 1563 PropModeReplace, (unsigned char *)0, 0);
1453 c->y = c->oldy; 1564 c->isfullscreen = 0;
1454 c->w = c->oldw; 1565 c->isfloating = c->oldstate;
1455 c->h = c->oldh; 1566 c->bw = c->oldbw;
1456 resizeclient(c, c->x, c->y, c->w, c->h); 1567 c->x = c->oldx;
1457 arrange(c->mon); 1568 c->y = c->oldy;
1458 } 1569 c->w = c->oldw;
1459} 1570 c->h = c->oldh;
1460 1571 resizeclient(c, c->x, c->y, c->w, c->h);
1461// void setgaps(int oh, int ov, int ih, int iv) { 1572 arrange(c->mon);
1462// if (oh < 0) 1573 }
1463// oh = 0; 1574}
1464// if (ov < 0) 1575
1465// ov = 0; 1576void setlayout(const Arg *arg)
1466// if (ih < 0) 1577{
1467// ih = 0; 1578 if (!arg || !arg->v || arg->v != selmon->lt[selmon->sellt])
1468// if (iv < 0) 1579 selmon->sellt ^= 1;
1469// iv = 0; 1580 if (arg && arg->v)
1470// 1581 selmon->lt[selmon->sellt] = (Layout *)arg->v;
1471// selmon->gappoh = oh; 1582 strncpy(selmon->ltsymbol, selmon->lt[selmon->sellt]->symbol,
1472// selmon->gappov = ov; 1583 sizeof selmon->ltsymbol);
1473// selmon->gappih = ih; 1584 if (selmon->sel)
1474// selmon->gappiv = iv; 1585 arrange(selmon);
1475// arrange(selmon); 1586 else
1476// } 1587 drawbar(selmon);
1477 1588}
1478// void togglegaps(const Arg *arg) { 1589
1479// enablegaps = !enablegaps; 1590void setup(void)
1480// arrange(selmon); 1591{
1481// } 1592 int i;
1482 1593 XSetWindowAttributes wa;
1483// void defaultgaps(const Arg *arg) { setgaps(gappoh, gappov, gappih, gappiv); } 1594 Atom utf8string;
1484// 1595 struct sigaction sa;
1485// void incrgaps(const Arg *arg) { 1596
1486// setgaps(selmon->gappoh + arg->i, selmon->gappov + arg->i, 1597 /* do not transform children into zombies when they terminate */
1487// selmon->gappih + arg->i, selmon->gappiv + arg->i); 1598 sigemptyset(&sa.sa_mask);
1488// } 1599 sa.sa_flags = SA_NOCLDSTOP | SA_NOCLDWAIT | SA_RESTART;
1489// 1600 sa.sa_handler = SIG_IGN;
1490// void incrigaps(const Arg *arg) { 1601 sigaction(SIGCHLD, &sa, NULL);
1491// setgaps(selmon->gappoh, selmon->gappov, selmon->gappih + arg->i, 1602
1492// selmon->gappiv + arg->i); 1603 /* clean up any zombies (inherited from .xinitrc etc) immediately */
1493// } 1604 while (waitpid(-1, NULL, WNOHANG) > 0)
1494// 1605 ;
1495// void incrogaps(const Arg *arg) { 1606
1496// setgaps(selmon->gappoh + arg->i, selmon->gappov + arg->i, selmon->gappih, 1607 /* init screen */
1497// selmon->gappiv); 1608 screen = DefaultScreen(dpy);
1498// } 1609 sw = DisplayWidth(dpy, screen);
1499 1610 sh = DisplayHeight(dpy, screen);
1500// void incrohgaps(const Arg *arg) { 1611 root = RootWindow(dpy, screen);
1501// setgaps(selmon->gappoh + arg->i, selmon->gappov, selmon->gappih, 1612 drw = drw_create(dpy, screen, root, sw, sh);
1502// selmon->gappiv); 1613 if (!drw_fontset_create(drw, fonts, LENGTH(fonts)))
1503// } 1614 die("no fonts could be loaded.");
1504// 1615 lrpad = drw->fonts->h;
1505// void incrovgaps(const Arg *arg) { 1616 bh = drw->fonts->h + 2;
1506// setgaps(selmon->gappoh, selmon->gappov + arg->i, selmon->gappih, 1617 updategeom();
1507// selmon->gappiv); 1618 /* init atoms */
1508// } 1619 utf8string = XInternAtom(dpy, "UTF8_STRING", False);
1509// 1620 wmatom[WMProtocols] = XInternAtom(dpy, "WM_PROTOCOLS", False);
1510// void incrihgaps(const Arg *arg) { 1621 wmatom[WMDelete] = XInternAtom(dpy, "WM_DELETE_WINDOW", False);
1511// setgaps(selmon->gappoh, selmon->gappov, selmon->gappih + arg->i, 1622 wmatom[WMState] = XInternAtom(dpy, "WM_STATE", False);
1512// selmon->gappiv); 1623 wmatom[WMTakeFocus] = XInternAtom(dpy, "WM_TAKE_FOCUS", False);
1513// } 1624 netatom[NetActiveWindow] =
1514// 1625 XInternAtom(dpy, "_NET_ACTIVE_WINDOW", False);
1515// void incrivgaps(const Arg *arg) { 1626 netatom[NetSupported] = XInternAtom(dpy, "_NET_SUPPORTED", False);
1516// setgaps(selmon->gappoh, selmon->gappov, selmon->gappih, 1627 netatom[NetSystemTray] = XInternAtom(dpy, "_NET_SYSTEM_TRAY_S0", False);
1517// selmon->gappiv + arg->i); 1628 netatom[NetSystemTrayOP] =
1518// } 1629 XInternAtom(dpy, "_NET_SYSTEM_TRAY_OPCODE", False);
1519 1630 netatom[NetSystemTrayOrientation] =
1520void setlayout(const Arg *arg) { 1631 XInternAtom(dpy, "_NET_SYSTEM_TRAY_ORIENTATION", False);
1521 if (!arg || !arg->v || arg->v != selmon->lt[selmon->sellt]) 1632 netatom[NetSystemTrayOrientationHorz] =
1522 selmon->sellt ^= 1; 1633 XInternAtom(dpy, "_NET_SYSTEM_TRAY_ORIENTATION_HORZ", False);
1523 if (arg && arg->v) 1634 netatom[NetWMName] = XInternAtom(dpy, "_NET_WM_NAME", False);
1524 selmon->lt[selmon->sellt] = (Layout *)arg->v; 1635 netatom[NetWMState] = XInternAtom(dpy, "_NET_WM_STATE", False);
1525 strncpy(selmon->ltsymbol, selmon->lt[selmon->sellt]->symbol, 1636 netatom[NetWMCheck] =
1526 sizeof selmon->ltsymbol); 1637 XInternAtom(dpy, "_NET_SUPPORTING_WM_CHECK", False);
1527 if (selmon->sel) 1638 netatom[NetWMFullscreen] =
1528 arrange(selmon); 1639 XInternAtom(dpy, "_NET_WM_STATE_FULLSCREEN", False);
1529 else 1640 netatom[NetWMWindowType] =
1530 drawbar(selmon); 1641 XInternAtom(dpy, "_NET_WM_WINDOW_TYPE", False);
1531} 1642 netatom[NetWMWindowTypeDialog] =
1532 1643 XInternAtom(dpy, "_NET_WM_WINDOW_TYPE_DIALOG", False);
1533// /* arg > 1.0 will set mfact absolutely */ 1644 netatom[NetClientList] = XInternAtom(dpy, "_NET_CLIENT_LIST", False);
1534// void setmfact(const Arg *arg) { 1645 xatom[Manager] = XInternAtom(dpy, "MANAGER", False);
1535// float f; 1646 xatom[Xembed] = XInternAtom(dpy, "_XEMBED", False);
1536// 1647 xatom[XembedInfo] = XInternAtom(dpy, "_XEMBED_INFO", False);
1537// if (!arg || !selmon->lt[selmon->sellt]->arrange) 1648 /* init cursors */
1538// return; 1649 cursor[CurNormal] = drw_cur_create(drw, XC_left_ptr);
1539// f = arg->f < 1.0 ? arg->f + selmon->mfact : arg->f - 1.0; 1650 cursor[CurResize] = drw_cur_create(drw, XC_sizing);
1540// if (f < 0.05 || f > 0.95) 1651 cursor[CurMove] = drw_cur_create(drw, XC_fleur);
1541// return; 1652 /* init appearance */
1542// selmon->mfact = f; 1653 scheme = ecalloc(LENGTH(colors), sizeof(Clr *));
1543// arrange(selmon); 1654 for (i = 0; i < LENGTH(colors); i++)
1544// } 1655 scheme[i] = drw_scm_create(drw, colors[i], 3);
1545 1656 /* init system tray */
1546void setup(void) { 1657 updatesystray();
1547 int i; 1658 /* init bars */
1548 XSetWindowAttributes wa; 1659 updatebars();
1549 Atom utf8string; 1660 updatestatus();
1550 struct sigaction sa; 1661 /* supporting window for NetWMCheck */
1551 1662 wmcheckwin = XCreateSimpleWindow(dpy, root, 0, 0, 1, 1, 0, 0, 0);
1552 /* do not transform children into zombies when they terminate */ 1663 XChangeProperty(dpy, wmcheckwin, netatom[NetWMCheck], XA_WINDOW, 32,
1553 sigemptyset(&sa.sa_mask); 1664 PropModeReplace, (unsigned char *)&wmcheckwin, 1);
1554 sa.sa_flags = SA_NOCLDSTOP | SA_NOCLDWAIT | SA_RESTART; 1665 XChangeProperty(dpy, wmcheckwin, netatom[NetWMName], utf8string, 8,
1555 sa.sa_handler = SIG_IGN; 1666 PropModeReplace, (unsigned char *)"dwm", 3);
1556 sigaction(SIGCHLD, &sa, NULL); 1667 XChangeProperty(dpy, root, netatom[NetWMCheck], XA_WINDOW, 32,
1557 1668 PropModeReplace, (unsigned char *)&wmcheckwin, 1);
1558 /* clean up any zombies (inherited from .xinitrc etc) immediately */ 1669 /* EWMH support per view */
1559 while (waitpid(-1, NULL, WNOHANG) > 0) 1670 XChangeProperty(dpy, root, netatom[NetSupported], XA_ATOM, 32,
1560 ; 1671 PropModeReplace, (unsigned char *)netatom, NetLast);
1561 1672 XDeleteProperty(dpy, root, netatom[NetClientList]);
1562 /* init screen */ 1673 /* select events */
1563 screen = DefaultScreen(dpy); 1674 wa.cursor = cursor[CurNormal]->cursor;
1564 sw = DisplayWidth(dpy, screen); 1675 wa.event_mask = SubstructureRedirectMask | SubstructureNotifyMask |
1565 sh = DisplayHeight(dpy, screen); 1676 ButtonPressMask | PointerMotionMask | EnterWindowMask |
1566 root = RootWindow(dpy, screen); 1677 LeaveWindowMask | StructureNotifyMask |
1567 drw = drw_create(dpy, screen, root, sw, sh); 1678 PropertyChangeMask;
1568 if (!drw_fontset_create(drw, fonts, LENGTH(fonts))) 1679 XChangeWindowAttributes(dpy, root, CWEventMask | CWCursor, &wa);
1569 die("no fonts could be loaded."); 1680 XSelectInput(dpy, root, wa.event_mask);
1570 lrpad = drw->fonts->h; 1681 grabkeys();
1571 bh = drw->fonts->h + 2; 1682 focus(NULL);
1572 updategeom(); 1683}
1573 /* init atoms */ 1684
1574 utf8string = XInternAtom(dpy, "UTF8_STRING", False); 1685void seturgent(Client *c, int urg)
1575 wmatom[WMProtocols] = XInternAtom(dpy, "WM_PROTOCOLS", False); 1686{
1576 wmatom[WMDelete] = XInternAtom(dpy, "WM_DELETE_WINDOW", False); 1687 XWMHints *wmh;
1577 wmatom[WMState] = XInternAtom(dpy, "WM_STATE", False); 1688
1578 wmatom[WMTakeFocus] = XInternAtom(dpy, "WM_TAKE_FOCUS", False); 1689 c->isurgent = urg;
1579 netatom[NetActiveWindow] = XInternAtom(dpy, "_NET_ACTIVE_WINDOW", False); 1690 if (!(wmh = XGetWMHints(dpy, c->win)))
1580 netatom[NetSupported] = XInternAtom(dpy, "_NET_SUPPORTED", False); 1691 return;
1581 netatom[NetSystemTray] = XInternAtom(dpy, "_NET_SYSTEM_TRAY_S0", False); 1692 wmh->flags =
1582 netatom[NetSystemTrayOP] = XInternAtom(dpy, "_NET_SYSTEM_TRAY_OPCODE", False); 1693 urg ? (wmh->flags | XUrgencyHint) : (wmh->flags & ~XUrgencyHint);
1583 netatom[NetSystemTrayOrientation] = 1694 XSetWMHints(dpy, c->win, wmh);
1584 XInternAtom(dpy, "_NET_SYSTEM_TRAY_ORIENTATION", False); 1695 XFree(wmh);
1585 netatom[NetSystemTrayOrientationHorz] = 1696}
1586 XInternAtom(dpy, "_NET_SYSTEM_TRAY_ORIENTATION_HORZ", False); 1697
1587 netatom[NetWMName] = XInternAtom(dpy, "_NET_WM_NAME", False); 1698void showhide(Client *c)
1588 netatom[NetWMState] = XInternAtom(dpy, "_NET_WM_STATE", False); 1699{
1589 netatom[NetWMCheck] = XInternAtom(dpy, "_NET_SUPPORTING_WM_CHECK", False); 1700 if (!c)
1590 netatom[NetWMFullscreen] = 1701 return;
1591 XInternAtom(dpy, "_NET_WM_STATE_FULLSCREEN", False); 1702 if (ISVISIBLE(c)) {
1592 netatom[NetWMWindowType] = XInternAtom(dpy, "_NET_WM_WINDOW_TYPE", False); 1703 /* show clients top down */
1593 netatom[NetWMWindowTypeDialog] = 1704 XMoveWindow(dpy, c->win, c->x, c->y);
1594 XInternAtom(dpy, "_NET_WM_WINDOW_TYPE_DIALOG", False); 1705 if ((!c->mon->lt[c->mon->sellt]->arrange || c->isfloating) &&
1595 netatom[NetClientList] = XInternAtom(dpy, "_NET_CLIENT_LIST", False); 1706 !c->isfullscreen)
1596 xatom[Manager] = XInternAtom(dpy, "MANAGER", False); 1707 resize(c, c->x, c->y, c->w, c->h, 0);
1597 xatom[Xembed] = XInternAtom(dpy, "_XEMBED", False); 1708 showhide(c->snext);
1598 xatom[XembedInfo] = XInternAtom(dpy, "_XEMBED_INFO", False); 1709 } else {
1599 /* init cursors */ 1710 /* hide clients bottom up */
1600 cursor[CurNormal] = drw_cur_create(drw, XC_left_ptr); 1711 showhide(c->snext);
1601 cursor[CurResize] = drw_cur_create(drw, XC_sizing); 1712 XMoveWindow(dpy, c->win, WIDTH(c) * -2, c->y);
1602 cursor[CurMove] = drw_cur_create(drw, XC_fleur); 1713 }
1603 /* init appearance */ 1714}
1604 scheme = ecalloc(LENGTH(colors), sizeof(Clr *)); 1715
1605 for (i = 0; i < LENGTH(colors); i++) 1716void spawn(const Arg *arg)
1606 scheme[i] = drw_scm_create(drw, colors[i], 3); 1717{
1607 /* init system tray */ 1718 struct sigaction sa;
1608 updatesystray(); 1719
1609 /* init bars */ 1720 if (arg->v == dmenucmd)
1610 updatebars(); 1721 dmenumon[0] = '0' + selmon->num;
1611 updatestatus(); 1722 if (fork() == 0) {
1612 /* supporting window for NetWMCheck */ 1723 if (dpy)
1613 wmcheckwin = XCreateSimpleWindow(dpy, root, 0, 0, 1, 1, 0, 0, 0); 1724 close(ConnectionNumber(dpy));
1614 XChangeProperty(dpy, wmcheckwin, netatom[NetWMCheck], XA_WINDOW, 32, 1725 setsid();
1615 PropModeReplace, (unsigned char *)&wmcheckwin, 1); 1726
1616 XChangeProperty(dpy, wmcheckwin, netatom[NetWMName], utf8string, 8, 1727 sigemptyset(&sa.sa_mask);
1617 PropModeReplace, (unsigned char *)"dwm", 3); 1728 sa.sa_flags = 0;
1618 XChangeProperty(dpy, root, netatom[NetWMCheck], XA_WINDOW, 32, 1729 sa.sa_handler = SIG_DFL;
1619 PropModeReplace, (unsigned char *)&wmcheckwin, 1); 1730 sigaction(SIGCHLD, &sa, NULL);
1620 /* EWMH support per view */ 1731
1621 XChangeProperty(dpy, root, netatom[NetSupported], XA_ATOM, 32, 1732 execvp(((char **)arg->v)[0], (char **)arg->v);
1622 PropModeReplace, (unsigned char *)netatom, NetLast); 1733 die("dwm: execvp '%s' failed:", ((char **)arg->v)[0]);
1623 XDeleteProperty(dpy, root, netatom[NetClientList]); 1734 }
1624 /* select events */ 1735}
1625 wa.cursor = cursor[CurNormal]->cursor; 1736
1626 wa.event_mask = SubstructureRedirectMask | SubstructureNotifyMask | 1737void tag(const Arg *arg)
1627 ButtonPressMask | PointerMotionMask | EnterWindowMask | 1738{
1628 LeaveWindowMask | StructureNotifyMask | PropertyChangeMask; 1739 if (selmon->sel && arg->ui & TAGMASK) {
1629 XChangeWindowAttributes(dpy, root, CWEventMask | CWCursor, &wa); 1740 selmon->sel->tags = arg->ui & TAGMASK;
1630 XSelectInput(dpy, root, wa.event_mask); 1741 focus(NULL);
1631 grabkeys(); 1742 arrange(selmon);
1632 focus(NULL); 1743 }
1633} 1744}
1634 1745
1635void seturgent(Client *c, int urg) { 1746void tile(Monitor *m)
1636 XWMHints *wmh; 1747{
1637 1748 unsigned int i, n, h, r, oe = enablegaps, ie = enablegaps, mw, my, ty;
1638 c->isurgent = urg; 1749 Client *c;
1639 if (!(wmh = XGetWMHints(dpy, c->win))) 1750
1640 return; 1751 for (n = 0, c = nexttiled(m->clients); c; c = nexttiled(c->next), n++)
1641 wmh->flags = urg ? (wmh->flags | XUrgencyHint) : (wmh->flags & ~XUrgencyHint); 1752 ;
1642 XSetWMHints(dpy, c->win, wmh); 1753 if (n == 0)
1643 XFree(wmh); 1754 return;
1644} 1755 if (smartgaps == n) {
1645 1756 oe = 0; // outer gaps disabled
1646void showhide(Client *c) { 1757 }
1647 if (!c) 1758
1648 return; 1759 if (n > m->nmaster)
1649 if (ISVISIBLE(c)) { 1760 mw = m->nmaster ? (m->ww + m->gappiv * ie) * m->mfact : 0;
1650 /* show clients top down */ 1761 else
1651 XMoveWindow(dpy, c->win, c->x, c->y); 1762 mw = m->ww - 2 * m->gappov * oe + m->gappiv * ie;
1652 if ((!c->mon->lt[c->mon->sellt]->arrange || c->isfloating) && 1763 for (i = 0, my = ty = m->gappoh * oe, c = nexttiled(m->clients); c;
1653 !c->isfullscreen) 1764 c = nexttiled(c->next), i++)
1654 resize(c, c->x, c->y, c->w, c->h, 0); 1765 if (i < m->nmaster) {
1655 showhide(c->snext); 1766 r = MIN(n, m->nmaster) - i;
1656 } else { 1767 h = (m->wh - my - m->gappoh * oe -
1657 /* hide clients bottom up */ 1768 m->gappih * ie * (r - 1)) /
1658 showhide(c->snext); 1769 r;
1659 XMoveWindow(dpy, c->win, WIDTH(c) * -2, c->y); 1770 resize(c, m->wx + m->gappov * oe, m->wy + my,
1660 } 1771 mw - (2 * c->bw) - m->gappiv * ie,
1661} 1772 h - (2 * c->bw), 0);
1662 1773 my += HEIGHT(c) + m->gappih * ie;
1663void spawn(const Arg *arg) { 1774
1664 struct sigaction sa; 1775 if (my + HEIGHT(c) < m->wh)
1665 1776 my += HEIGHT(c);
1666 if (arg->v == dmenucmd) 1777 } else {
1667 dmenumon[0] = '0' + selmon->num; 1778 r = n - i;
1668 if (fork() == 0) { 1779 h = (m->wh - ty - m->gappoh * oe -
1669 if (dpy) 1780 m->gappih * ie * (r - 1)) /
1670 close(ConnectionNumber(dpy)); 1781 r;
1671 setsid(); 1782 resize(c, m->wx + mw + m->gappov * oe, m->wy + ty,
1672 1783 m->ww - mw - (2 * c->bw) - 2 * m->gappov * oe,
1673 sigemptyset(&sa.sa_mask); 1784 h - (2 * c->bw), 0);
1674 sa.sa_flags = 0; 1785 ty += HEIGHT(c) + m->gappih * ie;
1675 sa.sa_handler = SIG_DFL; 1786 }
1676 sigaction(SIGCHLD, &sa, NULL); 1787}
1677 1788
1678 execvp(((char **)arg->v)[0], (char **)arg->v); 1789void togglebar(const Arg *arg)
1679 die("dwm: execvp '%s' failed:", ((char **)arg->v)[0]); 1790{
1680 } 1791 selmon->showbar = !selmon->showbar;
1681} 1792 updatebarpos(selmon);
1682 1793 resizebarwin(selmon);
1683void tag(const Arg *arg) { 1794 if (showsystray) {
1684 if (selmon->sel && arg->ui & TAGMASK) { 1795 XWindowChanges wc;
1685 selmon->sel->tags = arg->ui & TAGMASK; 1796 if (!selmon->showbar)
1686 focus(NULL); 1797 wc.y = -bh;
1687 arrange(selmon); 1798 else if (selmon->showbar) {
1688 } 1799 wc.y = 0;
1689} 1800 if (!selmon->topbar)
1690 1801 wc.y = selmon->mh - bh;
1691// void tagmon(const Arg *arg) { 1802 }
1692// if (!selmon->sel || !mons->next) 1803 XConfigureWindow(dpy, systray->win, CWY, &wc);
1693// return; 1804 }
1694// sendmon(selmon->sel, dirtomon(arg->i)); 1805 arrange(selmon);
1695// } 1806}
1696 1807
1697void tile(Monitor *m) { 1808void togglefloating(const Arg *arg)
1698 unsigned int i, n, h, r, oe = enablegaps, ie = enablegaps, mw, my, ty; 1809{
1699 Client *c; 1810 if (!selmon->sel)
1700 1811 return;
1701 for (n = 0, c = nexttiled(m->clients); c; c = nexttiled(c->next), n++) 1812 if (selmon->sel->isfullscreen) /* no support for fullscreen windows */
1702 ; 1813 return;
1703 if (n == 0) 1814 selmon->sel->isfloating =
1704 return; 1815 !selmon->sel->isfloating || selmon->sel->isfixed;
1705 if (smartgaps == n) { 1816 if (selmon->sel->isfloating)
1706 oe = 0; // outer gaps disabled 1817 resize(selmon->sel, selmon->sel->x, selmon->sel->y,
1707 } 1818 selmon->sel->w, selmon->sel->h, 0);
1708 1819 arrange(selmon);
1709 if (n > m->nmaster) 1820}
1710 mw = m->nmaster ? (m->ww + m->gappiv * ie) * m->mfact : 0; 1821
1711 else 1822void togglefullscr(const Arg *arg)
1712 mw = m->ww - 2 * m->gappov * oe + m->gappiv * ie; 1823{
1713 for (i = 0, my = ty = m->gappoh * oe, c = nexttiled(m->clients); c; 1824 if (selmon->sel)
1714 c = nexttiled(c->next), i++) 1825 setfullscreen(selmon->sel, !selmon->sel->isfullscreen);
1715 if (i < m->nmaster) { 1826}
1716 r = MIN(n, m->nmaster) - i; 1827
1717 h = (m->wh - my - m->gappoh * oe - m->gappih * ie * (r - 1)) / r; 1828void toggletag(const Arg *arg)
1718 resize(c, m->wx + m->gappov * oe, m->wy + my, 1829{
1719 mw - (2 * c->bw) - m->gappiv * ie, h - (2 * c->bw), 0); 1830 unsigned int newtags;
1720 my += HEIGHT(c) + m->gappih * ie; 1831
1721 1832 if (!selmon->sel)
1722 if (my + HEIGHT(c) < m->wh) 1833 return;
1723 my += HEIGHT(c); 1834 newtags = selmon->sel->tags ^ (arg->ui & TAGMASK);
1724 } else { 1835 if (newtags) {
1725 r = n - i; 1836 selmon->sel->tags = newtags;
1726 h = (m->wh - ty - m->gappoh * oe - m->gappih * ie * (r - 1)) / r; 1837 focus(NULL);
1727 resize(c, m->wx + mw + m->gappov * oe, m->wy + ty, 1838 arrange(selmon);
1728 m->ww - mw - (2 * c->bw) - 2 * m->gappov * oe, h - (2 * c->bw), 0); 1839 }
1729 ty += HEIGHT(c) + m->gappih * ie; 1840}
1730 } 1841
1731} 1842void toggleview(const Arg *arg)
1732 1843{
1733void togglebar(const Arg *arg) { 1844 unsigned int newtagset =
1734 selmon->showbar = !selmon->showbar; 1845 selmon->tagset[selmon->seltags] ^ (arg->ui & TAGMASK);
1735 updatebarpos(selmon); 1846
1736 resizebarwin(selmon); 1847 if (newtagset) {
1737 if (showsystray) { 1848 selmon->tagset[selmon->seltags] = newtagset;
1738 XWindowChanges wc; 1849 focus(NULL);
1739 if (!selmon->showbar) 1850 arrange(selmon);
1740 wc.y = -bh; 1851 }
1741 else if (selmon->showbar) { 1852}
1742 wc.y = 0; 1853
1743 if (!selmon->topbar) 1854void unfocus(Client *c, int setfocus)
1744 wc.y = selmon->mh - bh; 1855{
1745 } 1856 if (!c)
1746 XConfigureWindow(dpy, systray->win, CWY, &wc); 1857 return;
1747 } 1858 grabbuttons(c, 0);
1748 arrange(selmon); 1859 XSetWindowBorder(dpy, c->win, scheme[SchemeNorm][ColBorder].pixel);
1749} 1860 if (setfocus) {
1750 1861 XSetInputFocus(dpy, root, RevertToPointerRoot, CurrentTime);
1751void togglefloating(const Arg *arg) { 1862 XDeleteProperty(dpy, root, netatom[NetActiveWindow]);
1752 if (!selmon->sel) 1863 }
1753 return; 1864}
1754 if (selmon->sel->isfullscreen) /* no support for fullscreen windows */ 1865
1755 return; 1866void unmanage(Client *c, int destroyed)
1756 selmon->sel->isfloating = !selmon->sel->isfloating || selmon->sel->isfixed; 1867{
1757 if (selmon->sel->isfloating) 1868 Monitor *m = c->mon;
1758 resize(selmon->sel, selmon->sel->x, selmon->sel->y, selmon->sel->w, 1869 XWindowChanges wc;
1759 selmon->sel->h, 0); 1870
1760 arrange(selmon); 1871 if (c->swallowing) {
1761} 1872 unswallow(c);
1762 1873 return;
1763void togglefullscr(const Arg *arg) { 1874 }
1764 if (selmon->sel) 1875
1765 setfullscreen(selmon->sel, !selmon->sel->isfullscreen); 1876 Client *s = swallowingclient(c->win);
1766} 1877 if (s) {
1767 1878 free(s->swallowing);
1768void toggletag(const Arg *arg) { 1879 s->swallowing = NULL;
1769 unsigned int newtags; 1880 arrange(m);
1770 1881 focus(NULL);
1771 if (!selmon->sel) 1882 return;
1772 return; 1883 }
1773 newtags = selmon->sel->tags ^ (arg->ui & TAGMASK); 1884
1774 if (newtags) { 1885 detach(c);
1775 selmon->sel->tags = newtags; 1886 detachstack(c);
1776 focus(NULL); 1887 if (!destroyed) {
1777 arrange(selmon); 1888 wc.border_width = c->oldbw;
1778 } 1889 XGrabServer(dpy); /* avoid race conditions */
1779} 1890 XSetErrorHandler(xerrordummy);
1780 1891 XSelectInput(dpy, c->win, NoEventMask);
1781void toggleview(const Arg *arg) { 1892 XConfigureWindow(dpy, c->win, CWBorderWidth,
1782 unsigned int newtagset = 1893 &wc); /* restore border */
1783 selmon->tagset[selmon->seltags] ^ (arg->ui & TAGMASK); 1894 XUngrabButton(dpy, AnyButton, AnyModifier, c->win);
1784 1895 setclientstate(c, WithdrawnState);
1785 if (newtagset) { 1896 XSync(dpy, False);
1786 selmon->tagset[selmon->seltags] = newtagset; 1897 XSetErrorHandler(xerror);
1787 focus(NULL); 1898 XUngrabServer(dpy);
1788 arrange(selmon); 1899 }
1789 } 1900 free(c);
1790} 1901
1791 1902 if (!s) {
1792void unfocus(Client *c, int setfocus) { 1903 arrange(m);
1793 if (!c) 1904 focus(NULL);
1794 return; 1905 updateclientlist();
1795 grabbuttons(c, 0); 1906 }
1796 XSetWindowBorder(dpy, c->win, scheme[SchemeNorm][ColBorder].pixel); 1907}
1797 if (setfocus) { 1908
1798 XSetInputFocus(dpy, root, RevertToPointerRoot, CurrentTime); 1909void unmapnotify(XEvent *e)
1799 XDeleteProperty(dpy, root, netatom[NetActiveWindow]); 1910{
1800 } 1911 Client *c;
1801} 1912 XUnmapEvent *ev = &e->xunmap;
1802 1913
1803void unmanage(Client *c, int destroyed) { 1914 if ((c = wintoclient(ev->window))) {
1804 Monitor *m = c->mon; 1915 if (ev->send_event)
1805 XWindowChanges wc; 1916 setclientstate(c, WithdrawnState);
1806 1917 else
1807 if (c->swallowing) { 1918 unmanage(c, 0);
1808 unswallow(c); 1919 } else if ((c = wintosystrayicon(ev->window))) {
1809 return; 1920 /* KLUDGE! sometimes icons occasionally unmap their windows, but
1810 } 1921 * do _not_ destroy them. We map those windows back */
1811 1922 XMapRaised(dpy, c->win);
1812 Client *s = swallowingclient(c->win); 1923 updatesystray();
1813 if (s) { 1924 }
1814 free(s->swallowing); 1925}
1815 s->swallowing = NULL; 1926
1816 arrange(m); 1927void updatebars(void)
1817 focus(NULL); 1928{
1818 return; 1929 unsigned int w;
1819 } 1930 Monitor *m;
1820 1931 XSetWindowAttributes wa = {.override_redirect = True,
1821 detach(c); 1932 .background_pixmap = ParentRelative,
1822 detachstack(c); 1933 .event_mask =
1823 if (!destroyed) { 1934 ButtonPressMask | ExposureMask};
1824 wc.border_width = c->oldbw; 1935 XClassHint ch = {"dwm", "dwm"};
1825 XGrabServer(dpy); /* avoid race conditions */ 1936 for (m = mons; m; m = m->next) {
1826 XSetErrorHandler(xerrordummy); 1937 if (m->barwin)
1827 XSelectInput(dpy, c->win, NoEventMask); 1938 continue;
1828 XConfigureWindow(dpy, c->win, CWBorderWidth, &wc); /* restore border */ 1939 w = m->ww;
1829 XUngrabButton(dpy, AnyButton, AnyModifier, c->win); 1940 if (showsystray && m == systraytomon(m))
1830 setclientstate(c, WithdrawnState); 1941 w -= getsystraywidth();
1831 XSync(dpy, False); 1942 m->barwin = XCreateWindow(
1832 XSetErrorHandler(xerror); 1943 dpy, root, m->wx, m->by, w, bh, 0,
1833 XUngrabServer(dpy); 1944 DefaultDepth(dpy, screen), CopyFromParent,
1834 } 1945 DefaultVisual(dpy, screen),
1835 free(c); 1946 CWOverrideRedirect | CWBackPixmap | CWEventMask, &wa);
1836 1947 XDefineCursor(dpy, m->barwin, cursor[CurNormal]->cursor);
1837 if (!s) { 1948 if (showsystray && m == systraytomon(m))
1838 arrange(m); 1949 XMapRaised(dpy, systray->win);
1839 focus(NULL); 1950 XMapRaised(dpy, m->barwin);
1840 updateclientlist(); 1951 XSetClassHint(dpy, m->barwin, &ch);
1841 } 1952 }
1842} 1953}
1843 1954
1844void unmapnotify(XEvent *e) { 1955void updatebarpos(Monitor *m)
1845 Client *c; 1956{
1846 XUnmapEvent *ev = &e->xunmap; 1957 m->wy = m->my;
1847 1958 m->wh = m->mh;
1848 if ((c = wintoclient(ev->window))) { 1959 if (m->showbar) {
1849 if (ev->send_event) 1960 m->wh -= bh;
1850 setclientstate(c, WithdrawnState); 1961 m->by = m->topbar ? m->wy : m->wy + m->wh;
1851 else 1962 m->wy = m->topbar ? m->wy + bh : m->wy;
1852 unmanage(c, 0); 1963 } else
1853 } else if ((c = wintosystrayicon(ev->window))) { 1964 m->by = -bh;
1854 /* KLUDGE! sometimes icons occasionally unmap their windows, but do 1965}
1855 * _not_ destroy them. We map those windows back */ 1966
1856 XMapRaised(dpy, c->win); 1967void updateclientlist()
1857 updatesystray(); 1968{
1858 } 1969 Client *c;
1859} 1970 Monitor *m;
1860 1971
1861void updatebars(void) { 1972 XDeleteProperty(dpy, root, netatom[NetClientList]);
1862 unsigned int w; 1973 for (m = mons; m; m = m->next)
1863 Monitor *m; 1974 for (c = m->clients; c; c = c->next)
1864 XSetWindowAttributes wa = {.override_redirect = True, 1975 XChangeProperty(dpy, root, netatom[NetClientList],
1865 .background_pixmap = ParentRelative, 1976 XA_WINDOW, 32, PropModeAppend,
1866 .event_mask = ButtonPressMask | ExposureMask}; 1977 (unsigned char *)&(c->win), 1);
1867 XClassHint ch = {"dwm", "dwm"}; 1978}
1868 for (m = mons; m; m = m->next) { 1979
1869 if (m->barwin) 1980int updategeom(void)
1870 continue; 1981{
1871 w = m->ww; 1982 int dirty = 0;
1872 if (showsystray && m == systraytomon(m))
1873 w -= getsystraywidth();
1874 m->barwin = XCreateWindow(
1875 dpy, root, m->wx, m->by, w, bh, 0, DefaultDepth(dpy, screen),
1876 CopyFromParent, DefaultVisual(dpy, screen),
1877 CWOverrideRedirect | CWBackPixmap | CWEventMask, &wa);
1878 XDefineCursor(dpy, m->barwin, cursor[CurNormal]->cursor);
1879 if (showsystray && m == systraytomon(m))
1880 XMapRaised(dpy, systray->win);
1881 XMapRaised(dpy, m->barwin);
1882 XSetClassHint(dpy, m->barwin, &ch);
1883 }
1884}
1885
1886void updatebarpos(Monitor *m) {
1887 m->wy = m->my;
1888 m->wh = m->mh;
1889 if (m->showbar) {
1890 m->wh -= bh;
1891 m->by = m->topbar ? m->wy : m->wy + m->wh;
1892 m->wy = m->topbar ? m->wy + bh : m->wy;
1893 } else
1894 m->by = -bh;
1895}
1896
1897void updateclientlist() {
1898 Client *c;
1899 Monitor *m;
1900
1901 XDeleteProperty(dpy, root, netatom[NetClientList]);
1902 for (m = mons; m; m = m->next)
1903 for (c = m->clients; c; c = c->next)
1904 XChangeProperty(dpy, root, netatom[NetClientList], XA_WINDOW, 32,
1905 PropModeAppend, (unsigned char *)&(c->win), 1);
1906}
1907
1908int updategeom(void) {
1909 int dirty = 0;
1910 1983
1911#ifdef XINERAMA 1984#ifdef XINERAMA
1912 if (XineramaIsActive(dpy)) { 1985 if (XineramaIsActive(dpy)) {
1913 int i, j, n, nn; 1986 int i, j, n, nn;
1914 Client *c; 1987 Client *c;
1915 Monitor *m; 1988 Monitor *m;
1916 XineramaScreenInfo *info = XineramaQueryScreens(dpy, &nn); 1989 XineramaScreenInfo *info = XineramaQueryScreens(dpy, &nn);
1917 XineramaScreenInfo *unique = NULL; 1990 XineramaScreenInfo *unique = NULL;
1918 1991
1919 for (n = 0, m = mons; m; m = m->next, n++) 1992 for (n = 0, m = mons; m; m = m->next, n++)
1920 ; 1993 ;
1921 /* only consider unique geometries as separate screens */ 1994 /* only consider unique geometries as separate screens */
1922 unique = ecalloc(nn, sizeof(XineramaScreenInfo)); 1995 unique = ecalloc(nn, sizeof(XineramaScreenInfo));
1923 for (i = 0, j = 0; i < nn; i++) 1996 for (i = 0, j = 0; i < nn; i++)
1924 if (isuniquegeom(unique, j, &info[i])) 1997 if (isuniquegeom(unique, j, &info[i]))
1925 memcpy(&unique[j++], &info[i], sizeof(XineramaScreenInfo)); 1998 memcpy(&unique[j++], &info[i],
1926 XFree(info); 1999 sizeof(XineramaScreenInfo));
1927 nn = j; 2000 XFree(info);
1928 2001 nn = j;
1929 /* new monitors if nn > n */ 2002
1930 for (i = n; i < nn; i++) { 2003 /* new monitors if nn > n */
1931 for (m = mons; m && m->next; m = m->next) 2004 for (i = n; i < nn; i++) {
1932 ; 2005 for (m = mons; m && m->next; m = m->next)
1933 if (m) 2006 ;
1934 m->next = createmon(); 2007 if (m)
1935 else 2008 m->next = createmon();
1936 mons = createmon(); 2009 else
1937 } 2010 mons = createmon();
1938 for (i = 0, m = mons; i < nn && m; m = m->next, i++) 2011 }
1939 if (i >= n || unique[i].x_org != m->mx || unique[i].y_org != m->my || 2012 for (i = 0, m = mons; i < nn && m; m = m->next, i++)
1940 unique[i].width != m->mw || unique[i].height != m->mh) { 2013 if (i >= n || unique[i].x_org != m->mx ||
1941 dirty = 1; 2014 unique[i].y_org != m->my ||
1942 m->num = i; 2015 unique[i].width != m->mw ||
1943 m->mx = m->wx = unique[i].x_org; 2016 unique[i].height != m->mh) {
1944 m->my = m->wy = unique[i].y_org; 2017 dirty = 1;
1945 m->mw = m->ww = unique[i].width; 2018 m->num = i;
1946 m->mh = m->wh = unique[i].height; 2019 m->mx = m->wx = unique[i].x_org;
1947 updatebarpos(m); 2020 m->my = m->wy = unique[i].y_org;
1948 } 2021 m->mw = m->ww = unique[i].width;
1949 /* removed monitors if n > nn */ 2022 m->mh = m->wh = unique[i].height;
1950 for (i = nn; i < n; i++) { 2023 updatebarpos(m);
1951 for (m = mons; m && m->next; m = m->next) 2024 }
1952 ; 2025 /* removed monitors if n > nn */
1953 while ((c = m->clients)) { 2026 for (i = nn; i < n; i++) {
1954 dirty = 1; 2027 for (m = mons; m && m->next; m = m->next)
1955 m->clients = c->next; 2028 ;
1956 detachstack(c); 2029 while ((c = m->clients)) {
1957 c->mon = mons; 2030 dirty = 1;
1958 attach(c); 2031 m->clients = c->next;
1959 attachstack(c); 2032 detachstack(c);
1960 } 2033 c->mon = mons;
1961 if (m == selmon) 2034 attach(c);
1962 selmon = mons; 2035 attachstack(c);
1963 cleanupmon(m); 2036 }
1964 } 2037 if (m == selmon)
1965 free(unique); 2038 selmon = mons;
1966 } else 2039 cleanupmon(m);
1967#endif /* XINERAMA */ 2040 }
1968 { /* default monitor setup */ 2041 free(unique);
1969 if (!mons) 2042 } else
1970 mons = createmon(); 2043#endif /* XINERAMA */
1971 if (mons->mw != sw || mons->mh != sh) { 2044 { /* default monitor setup */
1972 dirty = 1; 2045 if (!mons)
1973 mons->mw = mons->ww = sw; 2046 mons = createmon();
1974 mons->mh = mons->wh = sh; 2047 if (mons->mw != sw || mons->mh != sh) {
1975 updatebarpos(mons); 2048 dirty = 1;
1976 } 2049 mons->mw = mons->ww = sw;
1977 } 2050 mons->mh = mons->wh = sh;
1978 if (dirty) { 2051 updatebarpos(mons);
1979 selmon = mons; 2052 }
1980 selmon = wintomon(root); 2053 }
1981 } 2054 if (dirty) {
1982 return dirty; 2055 selmon = mons;
1983} 2056 selmon = wintomon(root);
1984 2057 }
1985void updatenumlockmask(void) { 2058 return dirty;
1986 unsigned int i, j; 2059}
1987 XModifierKeymap *modmap; 2060
1988 2061void updatenumlockmask(void)
1989 numlockmask = 0; 2062{
1990 modmap = XGetModifierMapping(dpy); 2063 unsigned int i, j;
1991 for (i = 0; i < 8; i++) 2064 XModifierKeymap *modmap;
1992 for (j = 0; j < modmap->max_keypermod; j++) 2065
1993 if (modmap->modifiermap[i * modmap->max_keypermod + j] == 2066 numlockmask = 0;
1994 XKeysymToKeycode(dpy, XK_Num_Lock)) 2067 modmap = XGetModifierMapping(dpy);
1995 numlockmask = (1 << i); 2068 for (i = 0; i < 8; i++)
1996 XFreeModifiermap(modmap); 2069 for (j = 0; j < modmap->max_keypermod; j++)
1997} 2070 if (modmap
1998 2071 ->modifiermap[i * modmap->max_keypermod + j] ==
1999void updatesizehints(Client *c) { 2072 XKeysymToKeycode(dpy, XK_Num_Lock))
2000 long msize; 2073 numlockmask = (1 << i);
2001 XSizeHints size; 2074 XFreeModifiermap(modmap);
2002 2075}
2003 if (!XGetWMNormalHints(dpy, c->win, &size, &msize)) 2076
2004 /* size is uninitialized, ensure that size.flags aren't used */ 2077void updatesizehints(Client *c)
2005 size.flags = PSize; 2078{
2006 if (size.flags & PBaseSize) { 2079 long msize;
2007 c->basew = size.base_width; 2080 XSizeHints size;
2008 c->baseh = size.base_height; 2081
2009 } else if (size.flags & PMinSize) { 2082 if (!XGetWMNormalHints(dpy, c->win, &size, &msize))
2010 c->basew = size.min_width; 2083 /* size is uninitialized, ensure that size.flags aren't used */
2011 c->baseh = size.min_height; 2084 size.flags = PSize;
2012 } else 2085 if (size.flags & PBaseSize) {
2013 c->basew = c->baseh = 0; 2086 c->basew = size.base_width;
2014 if (size.flags & PResizeInc) { 2087 c->baseh = size.base_height;
2015 c->incw = size.width_inc; 2088 } else if (size.flags & PMinSize) {
2016 c->inch = size.height_inc; 2089 c->basew = size.min_width;
2017 } else 2090 c->baseh = size.min_height;
2018 c->incw = c->inch = 0; 2091 } else
2019 if (size.flags & PMaxSize) { 2092 c->basew = c->baseh = 0;
2020 c->maxw = size.max_width; 2093 if (size.flags & PResizeInc) {
2021 c->maxh = size.max_height; 2094 c->incw = size.width_inc;
2022 } else 2095 c->inch = size.height_inc;
2023 c->maxw = c->maxh = 0; 2096 } else
2024 if (size.flags & PMinSize) { 2097 c->incw = c->inch = 0;
2025 c->minw = size.min_width; 2098 if (size.flags & PMaxSize) {
2026 c->minh = size.min_height; 2099 c->maxw = size.max_width;
2027 } else if (size.flags & PBaseSize) { 2100 c->maxh = size.max_height;
2028 c->minw = size.base_width; 2101 } else
2029 c->minh = size.base_height; 2102 c->maxw = c->maxh = 0;
2030 } else 2103 if (size.flags & PMinSize) {
2031 c->minw = c->minh = 0; 2104 c->minw = size.min_width;
2032 if (size.flags & PAspect) { 2105 c->minh = size.min_height;
2033 c->mina = (float)size.min_aspect.y / size.min_aspect.x; 2106 } else if (size.flags & PBaseSize) {
2034 c->maxa = (float)size.max_aspect.x / size.max_aspect.y; 2107 c->minw = size.base_width;
2035 } else 2108 c->minh = size.base_height;
2036 c->maxa = c->mina = 0.0; 2109 } else
2037 c->isfixed = (c->maxw && c->maxh && c->maxw == c->minw && c->maxh == c->minh); 2110 c->minw = c->minh = 0;
2038 c->hintsvalid = 1; 2111 if (size.flags & PAspect) {
2039} 2112 c->mina = (float)size.min_aspect.y / size.min_aspect.x;
2040 2113 c->maxa = (float)size.max_aspect.x / size.max_aspect.y;
2041void updatestatus(void) { 2114 } else
2042 if (!gettextprop(root, XA_WM_NAME, stext, sizeof(stext))) 2115 c->maxa = c->mina = 0.0;
2043 strcpy(stext, "dwm-" VERSION); 2116 c->isfixed =
2044 drawbar(selmon); 2117 (c->maxw && c->maxh && c->maxw == c->minw && c->maxh == c->minh);
2045 updatesystray(); 2118 c->hintsvalid = 1;
2046} 2119}
2047 2120
2048void updatesystrayicongeom(Client *i, int w, int h) { 2121void updatestatus(void)
2049 if (i) { 2122{
2050 i->h = bh; 2123 if (!gettextprop(root, XA_WM_NAME, stext, sizeof(stext)))
2051 if (w == h) 2124 strcpy(stext, "dwm-" VERSION);
2052 i->w = bh; 2125 drawbar(selmon);
2053 else if (h == bh) 2126 updatesystray();
2054 i->w = w; 2127}
2055 else 2128
2056 i->w = (int)((float)bh * ((float)w / (float)h)); 2129void updatesystrayicongeom(Client *i, int w, int h)
2057 applysizehints(i, &(i->x), &(i->y), &(i->w), &(i->h), False); 2130{
2058 /* force icons into the systray dimensions if they don't want to */ 2131 if (i) {
2059 if (i->h > bh) { 2132 i->h = bh;
2060 if (i->w == i->h) 2133 if (w == h)
2061 i->w = bh; 2134 i->w = bh;
2062 else 2135 else if (h == bh)
2063 i->w = (int)((float)bh * ((float)i->w / (float)i->h)); 2136 i->w = w;
2064 i->h = bh; 2137 else
2065 } 2138 i->w = (int)((float)bh * ((float)w / (float)h));
2066 } 2139 applysizehints(i, &(i->x), &(i->y), &(i->w), &(i->h), False);
2067} 2140 /* force icons into the systray dimensions if they don't want to
2068 2141 */
2069void updatesystrayiconstate(Client *i, XPropertyEvent *ev) { 2142 if (i->h > bh) {
2070 long flags; 2143 if (i->w == i->h)
2071 int code = 0; 2144 i->w = bh;
2072 2145 else
2073 if (!showsystray || !i || ev->atom != xatom[XembedInfo] || 2146 i->w = (int)((float)bh *
2074 !(flags = getatomprop(i, xatom[XembedInfo]))) 2147 ((float)i->w / (float)i->h));
2075 return; 2148 i->h = bh;
2076 2149 }
2077 if (flags & XEMBED_MAPPED && !i->tags) { 2150 }
2078 i->tags = 1; 2151}
2079 code = XEMBED_WINDOW_ACTIVATE; 2152
2080 XMapRaised(dpy, i->win); 2153void updatesystrayiconstate(Client *i, XPropertyEvent *ev)
2081 setclientstate(i, NormalState); 2154{
2082 } else if (!(flags & XEMBED_MAPPED) && i->tags) { 2155 long flags;
2083 i->tags = 0; 2156 int code = 0;
2084 code = XEMBED_WINDOW_DEACTIVATE; 2157
2085 XUnmapWindow(dpy, i->win); 2158 if (!showsystray || !i || ev->atom != xatom[XembedInfo] ||
2086 setclientstate(i, WithdrawnState); 2159 !(flags = getatomprop(i, xatom[XembedInfo])))
2087 } else 2160 return;
2088 return; 2161
2089 sendevent(i->win, xatom[Xembed], StructureNotifyMask, CurrentTime, code, 0, 2162 if (flags & XEMBED_MAPPED && !i->tags) {
2090 systray->win, XEMBED_EMBEDDED_VERSION); 2163 i->tags = 1;
2091} 2164 code = XEMBED_WINDOW_ACTIVATE;
2092 2165 XMapRaised(dpy, i->win);
2093void updatesystray(void) { 2166 setclientstate(i, NormalState);
2094 XSetWindowAttributes wa; 2167 } else if (!(flags & XEMBED_MAPPED) && i->tags) {
2095 XWindowChanges wc; 2168 i->tags = 0;
2096 Client *i; 2169 code = XEMBED_WINDOW_DEACTIVATE;
2097 Monitor *m = systraytomon(NULL); 2170 XUnmapWindow(dpy, i->win);
2098 unsigned int x = m->mx + m->mw; 2171 setclientstate(i, WithdrawnState);
2099 unsigned int sw = TEXTW(stext) - lrpad + systrayspacing; 2172 } else
2100 unsigned int w = 1; 2173 return;
2101 2174 sendevent(i->win, xatom[Xembed], StructureNotifyMask, CurrentTime, code,
2102 if (!showsystray) 2175 0, systray->win, XEMBED_EMBEDDED_VERSION);
2103 return; 2176}
2104 if (systrayonleft) 2177
2105 x -= sw + lrpad / 2; 2178void updatesystray(void)
2106 if (!systray) { 2179{
2107 /* init systray */ 2180 XSetWindowAttributes wa;
2108 if (!(systray = (Systray *)calloc(1, sizeof(Systray)))) 2181 XWindowChanges wc;
2109 die("fatal: could not malloc() %u bytes\n", sizeof(Systray)); 2182 Client *i;
2110 systray->win = XCreateSimpleWindow(dpy, root, x, m->by, w, bh, 0, 0, 2183 Monitor *m = systraytomon(NULL);
2111 scheme[SchemeSel][ColBg].pixel); 2184 unsigned int x = m->mx + m->mw;
2112 wa.event_mask = ButtonPressMask | ExposureMask; 2185 unsigned int sw = TEXTW(stext) - lrpad + systrayspacing;
2113 wa.override_redirect = True; 2186 unsigned int w = 1;
2114 wa.background_pixel = scheme[SchemeNorm][ColBg].pixel; 2187
2115 XSelectInput(dpy, systray->win, SubstructureNotifyMask); 2188 if (!showsystray)
2116 XChangeProperty(dpy, systray->win, netatom[NetSystemTrayOrientation], 2189 return;
2117 XA_CARDINAL, 32, PropModeReplace, 2190 if (systrayonleft)
2118 (unsigned char *)&netatom[NetSystemTrayOrientationHorz], 1); 2191 x -= sw + lrpad / 2;
2119 XChangeWindowAttributes( 2192 if (!systray) {
2120 dpy, systray->win, CWEventMask | CWOverrideRedirect | CWBackPixel, &wa); 2193 /* init systray */
2121 XMapRaised(dpy, systray->win); 2194 if (!(systray = (Systray *)calloc(1, sizeof(Systray))))
2122 XSetSelectionOwner(dpy, netatom[NetSystemTray], systray->win, CurrentTime); 2195 die("fatal: could not malloc() %u bytes\n",
2123 if (XGetSelectionOwner(dpy, netatom[NetSystemTray]) == systray->win) { 2196 sizeof(Systray));
2124 sendevent(root, xatom[Manager], StructureNotifyMask, CurrentTime, 2197 systray->win =
2125 netatom[NetSystemTray], systray->win, 0, 0); 2198 XCreateSimpleWindow(dpy, root, x, m->by, w, bh, 0, 0,
2126 XSync(dpy, False); 2199 scheme[SchemeSel][ColBg].pixel);
2127 } else { 2200 wa.event_mask = ButtonPressMask | ExposureMask;
2128 fprintf(stderr, "dwm: unable to obtain system tray.\n"); 2201 wa.override_redirect = True;
2129 free(systray); 2202 wa.background_pixel = scheme[SchemeNorm][ColBg].pixel;
2130 systray = NULL; 2203 XSelectInput(dpy, systray->win, SubstructureNotifyMask);
2131 return; 2204 XChangeProperty(
2132 } 2205 dpy, systray->win, netatom[NetSystemTrayOrientation],
2133 } 2206 XA_CARDINAL, 32, PropModeReplace,
2134 for (w = 0, i = systray->icons; i; i = i->next) { 2207 (unsigned char *)&netatom[NetSystemTrayOrientationHorz], 1);
2135 /* make sure the background color stays the same */ 2208 XChangeWindowAttributes(
2136 wa.background_pixel = scheme[SchemeNorm][ColBg].pixel; 2209 dpy, systray->win,
2137 XChangeWindowAttributes(dpy, i->win, CWBackPixel, &wa); 2210 CWEventMask | CWOverrideRedirect | CWBackPixel, &wa);
2138 XMapRaised(dpy, i->win); 2211 XMapRaised(dpy, systray->win);
2139 w += systrayspacing; 2212 XSetSelectionOwner(dpy, netatom[NetSystemTray], systray->win,
2140 i->x = w; 2213 CurrentTime);
2141 XMoveResizeWindow(dpy, i->win, i->x, 0, i->w, i->h); 2214 if (XGetSelectionOwner(dpy, netatom[NetSystemTray]) ==
2142 w += i->w; 2215 systray->win) {
2143 if (i->mon != m) 2216 sendevent(root, xatom[Manager], StructureNotifyMask,
2144 i->mon = m; 2217 CurrentTime, netatom[NetSystemTray],
2145 } 2218 systray->win, 0, 0);
2146 w = w ? w + systrayspacing : 1; 2219 XSync(dpy, False);
2147 x -= w; 2220 } else {
2148 XMoveResizeWindow(dpy, systray->win, x, m->by, w, bh); 2221 fprintf(stderr, "dwm: unable to obtain system tray.\n");
2149 wc.x = x; 2222 free(systray);
2150 wc.y = m->by; 2223 systray = NULL;
2151 wc.width = w; 2224 return;
2152 wc.height = bh; 2225 }
2153 wc.stack_mode = Above; 2226 }
2154 wc.sibling = m->barwin; 2227 for (w = 0, i = systray->icons; i; i = i->next) {
2155 XConfigureWindow(dpy, systray->win, 2228 /* make sure the background color stays the same */
2156 CWX | CWY | CWWidth | CWHeight | CWSibling | CWStackMode, 2229 wa.background_pixel = scheme[SchemeNorm][ColBg].pixel;
2157 &wc); 2230 XChangeWindowAttributes(dpy, i->win, CWBackPixel, &wa);
2158 XMapWindow(dpy, systray->win); 2231 XMapRaised(dpy, i->win);
2159 XMapSubwindows(dpy, systray->win); 2232 w += systrayspacing;
2160 /* redraw background */ 2233 i->x = w;
2161 XSetForeground(dpy, drw->gc, scheme[SchemeNorm][ColBg].pixel); 2234 XMoveResizeWindow(dpy, i->win, i->x, 0, i->w, i->h);
2162 XFillRectangle(dpy, systray->win, drw->gc, 0, 0, w, bh); 2235 w += i->w;
2163 XSync(dpy, False); 2236 if (i->mon != m)
2164} 2237 i->mon = m;
2165 2238 }
2166void updatetitle(Client *c) { 2239 w = w ? w + systrayspacing : 1;
2167 if (!gettextprop(c->win, netatom[NetWMName], c->name, sizeof c->name)) 2240 x -= w;
2168 gettextprop(c->win, XA_WM_NAME, c->name, sizeof c->name); 2241 XMoveResizeWindow(dpy, systray->win, x, m->by, w, bh);
2169 if (c->name[0] == '\0') /* hack to mark broken clients */ 2242 wc.x = x;
2170 strcpy(c->name, broken); 2243 wc.y = m->by;
2171} 2244 wc.width = w;
2172 2245 wc.height = bh;
2173void updatewindowtype(Client *c) { 2246 wc.stack_mode = Above;
2174 Atom state = getatomprop(c, netatom[NetWMState]); 2247 wc.sibling = m->barwin;
2175 Atom wtype = getatomprop(c, netatom[NetWMWindowType]); 2248 XConfigureWindow(
2176 2249 dpy, systray->win,
2177 if (state == netatom[NetWMFullscreen]) 2250 CWX | CWY | CWWidth | CWHeight | CWSibling | CWStackMode, &wc);
2178 setfullscreen(c, 1); 2251 XMapWindow(dpy, systray->win);
2179 if (wtype == netatom[NetWMWindowTypeDialog]) 2252 XMapSubwindows(dpy, systray->win);
2180 c->isfloating = 1; 2253 /* redraw background */
2181} 2254 XSetForeground(dpy, drw->gc, scheme[SchemeNorm][ColBg].pixel);
2182 2255 XFillRectangle(dpy, systray->win, drw->gc, 0, 0, w, bh);
2183void updatewmhints(Client *c) { 2256 XSync(dpy, False);
2184 XWMHints *wmh; 2257}
2185 2258
2186 if ((wmh = XGetWMHints(dpy, c->win))) { 2259void updatetitle(Client *c)
2187 if (c == selmon->sel && wmh->flags & XUrgencyHint) { 2260{
2188 wmh->flags &= ~XUrgencyHint; 2261 if (!gettextprop(c->win, netatom[NetWMName], c->name, sizeof c->name))
2189 XSetWMHints(dpy, c->win, wmh); 2262 gettextprop(c->win, XA_WM_NAME, c->name, sizeof c->name);
2190 } else 2263 if (c->name[0] == '\0') /* hack to mark broken clients */
2191 c->isurgent = (wmh->flags & XUrgencyHint) ? 1 : 0; 2264 strcpy(c->name, broken);
2192 if (wmh->flags & InputHint) 2265}
2193 c->neverfocus = !wmh->input; 2266
2194 else 2267void updatewindowtype(Client *c)
2195 c->neverfocus = 0; 2268{
2196 XFree(wmh); 2269 Atom state = getatomprop(c, netatom[NetWMState]);
2197 } 2270 Atom wtype = getatomprop(c, netatom[NetWMWindowType]);
2198} 2271
2199 2272 if (state == netatom[NetWMFullscreen])
2200void view(const Arg *arg) { 2273 setfullscreen(c, 1);
2201 if ((arg->ui & TAGMASK) == selmon->tagset[selmon->seltags]) 2274 if (wtype == netatom[NetWMWindowTypeDialog])
2202 return; 2275 c->isfloating = 1;
2203 selmon->seltags ^= 1; /* toggle sel tagset */ 2276}
2204 if (arg->ui & TAGMASK) 2277
2205 selmon->tagset[selmon->seltags] = arg->ui & TAGMASK; 2278void updatewmhints(Client *c)
2206 focus(NULL); 2279{
2207 arrange(selmon); 2280 XWMHints *wmh;
2208} 2281
2209 2282 if ((wmh = XGetWMHints(dpy, c->win))) {
2210pid_t winpid(Window w) { 2283 if (c == selmon->sel && wmh->flags & XUrgencyHint) {
2211 2284 wmh->flags &= ~XUrgencyHint;
2212 pid_t result = 0; 2285 XSetWMHints(dpy, c->win, wmh);
2286 } else
2287 c->isurgent = (wmh->flags & XUrgencyHint) ? 1 : 0;
2288 if (wmh->flags & InputHint)
2289 c->neverfocus = !wmh->input;
2290 else
2291 c->neverfocus = 0;
2292 XFree(wmh);
2293 }
2294}
2295
2296void view(const Arg *arg)
2297{
2298 if ((arg->ui & TAGMASK) == selmon->tagset[selmon->seltags])
2299 return;
2300 selmon->seltags ^= 1; /* toggle sel tagset */
2301 if (arg->ui & TAGMASK)
2302 selmon->tagset[selmon->seltags] = arg->ui & TAGMASK;
2303 focus(NULL);
2304 arrange(selmon);
2305}
2306
2307pid_t winpid(Window w)
2308{
2309
2310 pid_t result = 0;
2213 2311
2214#ifdef __linux__ 2312#ifdef __linux__
2215 xcb_res_client_id_spec_t spec = {0}; 2313 xcb_res_client_id_spec_t spec = {0};
2216 spec.client = w; 2314 spec.client = w;
2217 spec.mask = XCB_RES_CLIENT_ID_MASK_LOCAL_CLIENT_PID; 2315 spec.mask = XCB_RES_CLIENT_ID_MASK_LOCAL_CLIENT_PID;
2218 2316
2219 xcb_generic_error_t *e = NULL; 2317 xcb_generic_error_t *e = NULL;
2220 xcb_res_query_client_ids_cookie_t c = 2318 xcb_res_query_client_ids_cookie_t c =
2221 xcb_res_query_client_ids(xcon, 1, &spec); 2319 xcb_res_query_client_ids(xcon, 1, &spec);
2222 xcb_res_query_client_ids_reply_t *r = 2320 xcb_res_query_client_ids_reply_t *r =
2223 xcb_res_query_client_ids_reply(xcon, c, &e); 2321 xcb_res_query_client_ids_reply(xcon, c, &e);
2224 2322
2225 if (!r) 2323 if (!r)
2226 return (pid_t)0; 2324 return (pid_t)0;
2227 2325
2228 xcb_res_client_id_value_iterator_t i = 2326 xcb_res_client_id_value_iterator_t i =
2229 xcb_res_query_client_ids_ids_iterator(r); 2327 xcb_res_query_client_ids_ids_iterator(r);
2230 for (; i.rem; xcb_res_client_id_value_next(&i)) { 2328 for (; i.rem; xcb_res_client_id_value_next(&i)) {
2231 spec = i.data->spec; 2329 spec = i.data->spec;
2232 if (spec.mask & XCB_RES_CLIENT_ID_MASK_LOCAL_CLIENT_PID) { 2330 if (spec.mask & XCB_RES_CLIENT_ID_MASK_LOCAL_CLIENT_PID) {
2233 uint32_t *t = xcb_res_client_id_value_value(i.data); 2331 uint32_t *t = xcb_res_client_id_value_value(i.data);
2234 result = *t; 2332 result = *t;
2235 break; 2333 break;
2236 } 2334 }
2237 } 2335 }
2238 2336
2239 free(r); 2337 free(r);
2240 2338
2241 if (result == (pid_t)-1) 2339 if (result == (pid_t)-1)
2242 result = 0; 2340 result = 0;
2243 2341
2244#endif /* __linux__ */ 2342#endif /* __linux__ */
2245 2343
2246#ifdef __OpenBSD__ 2344#ifdef __OpenBSD__
2247 Atom type; 2345 Atom type;
2248 int format; 2346 int format;
2249 unsigned long len, bytes; 2347 unsigned long len, bytes;
2250 unsigned char *prop; 2348 unsigned char *prop;
2251 pid_t ret; 2349 pid_t ret;
2252 2350
2253 if (XGetWindowProperty(dpy, w, XInternAtom(dpy, "_NET_WM_PID", 0), 0, 1, 2351 if (XGetWindowProperty(dpy, w, XInternAtom(dpy, "_NET_WM_PID", 0), 0, 1,
2254 False, AnyPropertyType, &type, &format, &len, &bytes, 2352 False, AnyPropertyType, &type, &format, &len,
2255 &prop) != Success || 2353 &bytes, &prop) != Success ||
2256 !prop) 2354 !prop)
2257 return 0; 2355 return 0;
2258 2356
2259 ret = *(pid_t *)prop; 2357 ret = *(pid_t *)prop;
2260 XFree(prop); 2358 XFree(prop);
2261 result = ret; 2359 result = ret;
2262 2360
2263#endif /* __OpenBSD__ */ 2361#endif /* __OpenBSD__ */
2264 return result; 2362 return result;
2265} 2363}
2266 2364
2267pid_t getparentprocess(pid_t p) { 2365pid_t getparentprocess(pid_t p)
2268 unsigned int v = 0; 2366{
2367 unsigned int v = 0;
2269 2368
2270#ifdef __linux__ 2369#ifdef __linux__
2271 FILE *f; 2370 FILE *f;
2272 char buf[256]; 2371 char buf[256];
2273 snprintf(buf, sizeof(buf) - 1, "/proc/%u/stat", (unsigned)p); 2372 snprintf(buf, sizeof(buf) - 1, "/proc/%u/stat", (unsigned)p);
2274 2373
2275 if (!(f = fopen(buf, "r"))) 2374 if (!(f = fopen(buf, "r")))
2276 return 0; 2375 return 0;
2277 2376
2278 fscanf(f, "%*u %*s %*c %u", &v); 2377 fscanf(f, "%*u %*s %*c %u", &v);
2279 fclose(f); 2378 fclose(f);
2280#endif /* __linux__ */ 2379#endif /* __linux__ */
2281 2380
2282#ifdef __OpenBSD__ 2381#ifdef __OpenBSD__
2283 int n; 2382 int n;
2284 kvm_t *kd; 2383 kvm_t *kd;
2285 struct kinfo_proc *kp; 2384 struct kinfo_proc *kp;
2286 2385
2287 kd = kvm_openfiles(NULL, NULL, NULL, KVM_NO_FILES, NULL); 2386 kd = kvm_openfiles(NULL, NULL, NULL, KVM_NO_FILES, NULL);
2288 if (!kd) 2387 if (!kd)
2289 return 0; 2388 return 0;
2290 2389
2291 kp = kvm_getprocs(kd, KERN_PROC_PID, p, sizeof(*kp), &n); 2390 kp = kvm_getprocs(kd, KERN_PROC_PID, p, sizeof(*kp), &n);
2292 v = kp->p_ppid; 2391 v = kp->p_ppid;
2293#endif /* __OpenBSD__ */ 2392#endif /* __OpenBSD__ */
2294 2393
2295 return (pid_t)v; 2394 return (pid_t)v;
2296} 2395}
2297 2396
2298int isdescprocess(pid_t p, pid_t c) { 2397int isdescprocess(pid_t p, pid_t c)
2299 while (p != c && c != 0) 2398{
2300 c = getparentprocess(c); 2399 while (p != c && c != 0)
2400 c = getparentprocess(c);
2301 2401
2302 return (int)c; 2402 return (int)c;
2303} 2403}
2304 2404
2305Client *termforwin(const Client *w) { 2405Client *termforwin(const Client *w)
2306 Client *c; 2406{
2307 Monitor *m; 2407 Client *c;
2408 Monitor *m;
2308 2409
2309 if (!w->pid || w->isterminal) 2410 if (!w->pid || w->isterminal)
2310 return NULL; 2411 return NULL;
2311 2412
2312 for (m = mons; m; m = m->next) { 2413 for (m = mons; m; m = m->next) {
2313 for (c = m->clients; c; c = c->next) { 2414 for (c = m->clients; c; c = c->next) {
2314 if (c->isterminal && !c->swallowing && c->pid && 2415 if (c->isterminal && !c->swallowing && c->pid &&
2315 isdescprocess(c->pid, w->pid)) 2416 isdescprocess(c->pid, w->pid))
2316 return c; 2417 return c;
2317 } 2418 }
2318 } 2419 }
2319 2420
2320 return NULL; 2421 return NULL;
2321} 2422}
2322 2423
2323Client *swallowingclient(Window w) { 2424Client *swallowingclient(Window w)
2324 Client *c; 2425{
2325 Monitor *m; 2426 Client *c;
2427 Monitor *m;
2326 2428
2327 for (m = mons; m; m = m->next) { 2429 for (m = mons; m; m = m->next) {
2328 for (c = m->clients; c; c = c->next) { 2430 for (c = m->clients; c; c = c->next) {
2329 if (c->swallowing && c->swallowing->win == w) 2431 if (c->swallowing && c->swallowing->win == w)
2330 return c; 2432 return c;
2331 } 2433 }
2332 } 2434 }
2333 2435
2334 return NULL; 2436 return NULL;
2335} 2437}
2336 2438
2337Client *wintoclient(Window w) { 2439Client *wintoclient(Window w)
2338 Client *c; 2440{
2339 Monitor *m; 2441 Client *c;
2442 Monitor *m;
2340 2443
2341 for (m = mons; m; m = m->next) 2444 for (m = mons; m; m = m->next)
2342 for (c = m->clients; c; c = c->next) 2445 for (c = m->clients; c; c = c->next)
2343 if (c->win == w) 2446 if (c->win == w)
2344 return c; 2447 return c;
2345 return NULL; 2448 return NULL;
2346} 2449}
2347 2450
2348Client *wintosystrayicon(Window w) { 2451Client *wintosystrayicon(Window w)
2349 Client *i = NULL; 2452{
2453 Client *i = NULL;
2350 2454
2351 if (!showsystray || !w) 2455 if (!showsystray || !w)
2352 return i; 2456 return i;
2353 for (i = systray->icons; i && i->win != w; i = i->next) 2457 for (i = systray->icons; i && i->win != w; i = i->next)
2354 ; 2458 ;
2355 return i; 2459 return i;
2356} 2460}
2357 2461
2358Monitor *wintomon(Window w) { 2462Monitor *wintomon(Window w)
2359 int x, y; 2463{
2360 Client *c; 2464 int x, y;
2361 Monitor *m; 2465 Client *c;
2466 Monitor *m;
2362 2467
2363 if (w == root && getrootptr(&x, &y)) 2468 if (w == root && getrootptr(&x, &y))
2364 return recttomon(x, y, 1, 1); 2469 return recttomon(x, y, 1, 1);
2365 for (m = mons; m; m = m->next) 2470 for (m = mons; m; m = m->next)
2366 if (w == m->barwin) 2471 if (w == m->barwin)
2367 return m; 2472 return m;
2368 if ((c = wintoclient(w))) 2473 if ((c = wintoclient(w)))
2369 return c->mon; 2474 return c->mon;
2370 return selmon; 2475 return selmon;
2371} 2476}
2372 2477
2373/* There's no way to check accesses to destroyed windows, thus those cases are 2478/* There's no way to check accesses to destroyed windows, thus those cases are
2374 * ignored (especially on UnmapNotify's). Other types of errors call Xlibs 2479 * ignored (especially on UnmapNotify's). Other types of errors call Xlibs
2375 * default error handler, which may call exit. */ 2480 * default error handler, which may call exit. */
2376int xerror(Display *dpy, XErrorEvent *ee) { 2481int xerror(Display *dpy, XErrorEvent *ee)
2377 if (ee->error_code == BadWindow || 2482{
2378 (ee->request_code == X_SetInputFocus && ee->error_code == BadMatch) || 2483 if (ee->error_code == BadWindow ||
2379 (ee->request_code == X_PolyText8 && ee->error_code == BadDrawable) || 2484 (ee->request_code == X_SetInputFocus &&
2380 (ee->request_code == X_PolyFillRectangle && 2485 ee->error_code == BadMatch) ||
2381 ee->error_code == BadDrawable) || 2486 (ee->request_code == X_PolyText8 &&
2382 (ee->request_code == X_PolySegment && ee->error_code == BadDrawable) || 2487 ee->error_code == BadDrawable) ||
2383 (ee->request_code == X_ConfigureWindow && ee->error_code == BadMatch) || 2488 (ee->request_code == X_PolyFillRectangle &&
2384 (ee->request_code == X_GrabButton && ee->error_code == BadAccess) || 2489 ee->error_code == BadDrawable) ||
2385 (ee->request_code == X_GrabKey && ee->error_code == BadAccess) || 2490 (ee->request_code == X_PolySegment &&
2386 (ee->request_code == X_CopyArea && ee->error_code == BadDrawable)) 2491 ee->error_code == BadDrawable) ||
2387 return 0; 2492 (ee->request_code == X_ConfigureWindow &&
2388 fprintf(stderr, "dwm: fatal error: request code=%d, error code=%d\n", 2493 ee->error_code == BadMatch) ||
2389 ee->request_code, ee->error_code); 2494 (ee->request_code == X_GrabButton && ee->error_code == BadAccess) ||
2390 return xerrorxlib(dpy, ee); /* may call exit */ 2495 (ee->request_code == X_GrabKey && ee->error_code == BadAccess) ||
2496 (ee->request_code == X_CopyArea && ee->error_code == BadDrawable))
2497 return 0;
2498 fprintf(stderr, "dwm: fatal error: request code=%d, error code=%d\n",
2499 ee->request_code, ee->error_code);
2500 return xerrorxlib(dpy, ee); /* may call exit */
2391} 2501}
2392 2502
2393int xerrordummy(Display *dpy, XErrorEvent *ee) { return 0; } 2503int xerrordummy(Display *dpy, XErrorEvent *ee) { return 0; }
2394 2504
2395/* Startup Error handler to check if another window manager 2505/* Startup Error handler to check if another window manager
2396 * is already running. */ 2506 * is already running. */
2397int xerrorstart(Display *dpy, XErrorEvent *ee) { 2507int xerrorstart(Display *dpy, XErrorEvent *ee)
2398 die("dwm: another window manager is already running"); 2508{
2399 return -1; 2509 die("dwm: another window manager is already running");
2400} 2510 return -1;
2401 2511}
2402Monitor *systraytomon(Monitor *m) { 2512
2403 Monitor *t; 2513Monitor *systraytomon(Monitor *m)
2404 int i, n; 2514{
2405 if (!systraypinning) { 2515 Monitor *t;
2406 if (!m) 2516 int i, n;
2407 return selmon; 2517 if (!systraypinning) {
2408 return m == selmon ? m : NULL; 2518 if (!m)
2409 } 2519 return selmon;
2410 for (n = 1, t = mons; t && t->next; n++, t = t->next) 2520 return m == selmon ? m : NULL;
2411 ; 2521 }
2412 for (i = 1, t = mons; t && t->next && i < systraypinning; i++, t = t->next) 2522 for (n = 1, t = mons; t && t->next; n++, t = t->next)
2413 ; 2523 ;
2414 if (systraypinningfailfirst && n < systraypinning) 2524 for (i = 1, t = mons; t && t->next && i < systraypinning;
2415 return mons; 2525 i++, t = t->next)
2416 return t; 2526 ;
2417} 2527 if (systraypinningfailfirst && n < systraypinning)
2418 2528 return mons;
2419void zoom(const Arg *arg) { 2529 return t;
2420 Client *c = selmon->sel; 2530}
2421 2531
2422 if (!selmon->lt[selmon->sellt]->arrange || !c || c->isfloating) 2532void zoom(const Arg *arg)
2423 return; 2533{
2424 if (c == nexttiled(selmon->clients) && !(c = nexttiled(c->next))) 2534 Client *c = selmon->sel;
2425 return; 2535
2426 pop(c); 2536 if (!selmon->lt[selmon->sellt]->arrange || !c || c->isfloating)
2427} 2537 return;
2428 2538 if (c == nexttiled(selmon->clients) && !(c = nexttiled(c->next)))
2429int main(int argc, char *argv[]) { 2539 return;
2430 if (argc == 2 && !strcmp("-v", argv[1])) 2540 pop(c);
2431 die("dwm-" VERSION); 2541}
2432 else if (argc != 1) 2542
2433 die("usage: dwm [-v]"); 2543int main(int argc, char *argv[])
2434 if (!setlocale(LC_CTYPE, "") || !XSupportsLocale()) 2544{
2435 fputs("warning: no locale support\n", stderr); 2545 if (argc == 2 && !strcmp("-v", argv[1]))
2436 if (!(dpy = XOpenDisplay(NULL))) 2546 die("dwm-" VERSION);
2437 die("dwm: cannot open display"); 2547 else if (argc != 1)
2438 if (!(xcon = XGetXCBConnection(dpy))) 2548 die("usage: dwm [-v]");
2439 die("dwm: cannot get xcb connection\n"); 2549 if (!setlocale(LC_CTYPE, "") || !XSupportsLocale())
2440 checkotherwm(); 2550 fputs("warning: no locale support\n", stderr);
2441 setup(); 2551 if (!(dpy = XOpenDisplay(NULL)))
2552 die("dwm: cannot open display");
2553 if (!(xcon = XGetXCBConnection(dpy)))
2554 die("dwm: cannot get xcb connection\n");
2555 checkotherwm();
2556 setup();
2442#ifdef __OpenBSD__ 2557#ifdef __OpenBSD__
2443 if (pledge("stdio rpath proc exec ps", NULL) == -1) 2558 if (pledge("stdio rpath proc exec ps", NULL) == -1)
2444 die("pledge"); 2559 die("pledge");
2445#endif /* __OpenBSD__ */ 2560#endif /* __OpenBSD__ */
2446 scan(); 2561 scan();
2447 run(); 2562 run();
2448 cleanup(); 2563 cleanup();
2449 XCloseDisplay(dpy); 2564 XCloseDisplay(dpy);
2450 return EXIT_SUCCESS; 2565 return EXIT_SUCCESS;
2451} 2566}
diff --git a/src/core/dwm.h b/src/core/dwm.h
index 68eaf93..090448a 100644
--- a/src/core/dwm.h
+++ b/src/core/dwm.h
@@ -2,126 +2,126 @@
2enum { CurNormal, CurResize, CurMove, CurLast }; /* cursor */ 2enum { CurNormal, CurResize, CurMove, CurLast }; /* cursor */
3enum { SchemeNorm, SchemeSel }; /* color schemes */ 3enum { SchemeNorm, SchemeSel }; /* color schemes */
4enum { 4enum {
5 NetSupported, 5 NetSupported,
6 NetWMName, 6 NetWMName,
7 NetWMState, 7 NetWMState,
8 NetWMCheck, 8 NetWMCheck,
9 NetSystemTray, 9 NetSystemTray,
10 NetSystemTrayOP, 10 NetSystemTrayOP,
11 NetSystemTrayOrientation, 11 NetSystemTrayOrientation,
12 NetSystemTrayOrientationHorz, 12 NetSystemTrayOrientationHorz,
13 NetWMFullscreen, 13 NetWMFullscreen,
14 NetActiveWindow, 14 NetActiveWindow,
15 NetWMWindowType, 15 NetWMWindowType,
16 NetWMWindowTypeDialog, 16 NetWMWindowTypeDialog,
17 NetClientList, 17 NetClientList,
18 NetLast 18 NetLast
19}; /* EWMH atoms */ 19}; /* EWMH atoms */
20enum { Manager, Xembed, XembedInfo, XLast }; /* Xembed atoms */ 20enum { Manager, Xembed, XembedInfo, XLast }; /* Xembed atoms */
21enum { 21enum {
22 WMProtocols, 22 WMProtocols,
23 WMDelete, 23 WMDelete,
24 WMState, 24 WMState,
25 WMTakeFocus, 25 WMTakeFocus,
26 WMLast 26 WMLast
27}; /* default atoms */ 27}; /* default atoms */
28enum { 28enum {
29 ClkTagBar, 29 ClkTagBar,
30 ClkLtSymbol, 30 ClkLtSymbol,
31 ClkStatusText, 31 ClkStatusText,
32 ClkWinTitle, 32 ClkWinTitle,
33 ClkClientWin, 33 ClkClientWin,
34 ClkRootWin, 34 ClkRootWin,
35 ClkLast 35 ClkLast
36}; /* clicks */ 36}; /* clicks */
37 37
38typedef union { 38typedef union {
39 int i; 39 int i;
40 unsigned int ui; 40 unsigned int ui;
41 float f; 41 float f;
42 const void *v; 42 const void *v;
43} Arg; 43} Arg;
44 44
45typedef struct { 45typedef struct {
46 unsigned int click; 46 unsigned int click;
47 unsigned int mask; 47 unsigned int mask;
48 unsigned int button; 48 unsigned int button;
49 void (*func)(const Arg *arg); 49 void (*func)(const Arg *arg);
50 const Arg arg; 50 const Arg arg;
51} Button; 51} Button;
52 52
53typedef struct Monitor Monitor; 53typedef struct Monitor Monitor;
54typedef struct Client Client; 54typedef struct Client Client;
55struct Client { 55struct Client {
56 char name[256]; 56 char name[256];
57 float mina, maxa; 57 float mina, maxa;
58 int x, y, w, h; 58 int x, y, w, h;
59 int oldx, oldy, oldw, oldh; 59 int oldx, oldy, oldw, oldh;
60 int basew, baseh, incw, inch, maxw, maxh, minw, minh, hintsvalid; 60 int basew, baseh, incw, inch, maxw, maxh, minw, minh, hintsvalid;
61 int bw, oldbw; 61 int bw, oldbw;
62 unsigned int tags; 62 unsigned int tags;
63 int isfixed, isfloating, isurgent, neverfocus, oldstate, isfullscreen, 63 int isfixed, isfloating, isurgent, neverfocus, oldstate, isfullscreen,
64 isterminal, noswallow; 64 isterminal, noswallow;
65 pid_t pid; 65 pid_t pid;
66 Client *next; 66 Client *next;
67 Client *snext; 67 Client *snext;
68 Client *swallowing; 68 Client *swallowing;
69 Monitor *mon; 69 Monitor *mon;
70 Window win; 70 Window win;
71}; 71};
72 72
73typedef struct { 73typedef struct {
74 unsigned int mod; 74 unsigned int mod;
75 KeySym keysym; 75 KeySym keysym;
76 void (*func)(const Arg *); 76 void (*func)(const Arg *);
77 const Arg arg; 77 const Arg arg;
78} Key; 78} Key;
79 79
80typedef struct { 80typedef struct {
81 const char *symbol; 81 const char *symbol;
82 void (*arrange)(Monitor *); 82 void (*arrange)(Monitor *);
83} Layout; 83} Layout;
84 84
85struct Monitor { 85struct Monitor {
86 char ltsymbol[16]; 86 char ltsymbol[16];
87 float mfact; 87 float mfact;
88 int nmaster; 88 int nmaster;
89 int num; 89 int num;
90 int by; /* bar geometry */ 90 int by; /* bar geometry */
91 int mx, my, mw, mh; /* screen size */ 91 int mx, my, mw, mh; /* screen size */
92 int wx, wy, ww, wh; /* window area */ 92 int wx, wy, ww, wh; /* window area */
93 int gappih; /* horizontal gap between windows */ 93 int gappih; /* horizontal gap between windows */
94 int gappiv; /* vertical gap between windows */ 94 int gappiv; /* vertical gap between windows */
95 int gappoh; /* horizontal outer gaps */ 95 int gappoh; /* horizontal outer gaps */
96 int gappov; /* vertical outer gaps */ 96 int gappov; /* vertical outer gaps */
97 unsigned int seltags; 97 unsigned int seltags;
98 unsigned int sellt; 98 unsigned int sellt;
99 unsigned int tagset[2]; 99 unsigned int tagset[2];
100 int showbar; 100 int showbar;
101 int topbar; 101 int topbar;
102 Client *clients; 102 Client *clients;
103 Client *sel; 103 Client *sel;
104 Client *stack; 104 Client *stack;
105 Monitor *next; 105 Monitor *next;
106 Window barwin; 106 Window barwin;
107 const Layout *lt[2]; 107 const Layout *lt[2];
108}; 108};
109 109
110typedef struct { 110typedef struct {
111 const char *class; 111 const char *class;
112 const char *instance; 112 const char *instance;
113 const char *title; 113 const char *title;
114 unsigned int tags; 114 unsigned int tags;
115 int isfloating; 115 int isfloating;
116 int isterminal; 116 int isterminal;
117 int noswallow; 117 int noswallow;
118 int monitor; 118 int monitor;
119} Rule; 119} Rule;
120 120
121typedef struct Systray Systray; 121typedef struct Systray Systray;
122struct Systray { 122struct Systray {
123 Window win; 123 Window win;
124 Client *icons; 124 Client *icons;
125}; 125};
126 126
127/* function declarations */ 127/* function declarations */