40 #include <X11/extensions/Xinerama.h> |
40 #include <X11/extensions/Xinerama.h> |
41 #endif /* XINERAMA */ |
41 #endif /* XINERAMA */ |
42 |
42 |
43 /* macros */ |
43 /* macros */ |
44 #define BUTTONMASK (ButtonPressMask|ButtonReleaseMask) |
44 #define BUTTONMASK (ButtonPressMask|ButtonReleaseMask) |
45 #define CLEANMASK(mask) (mask & ~(numlockmask|LockMask)) |
45 #define CLEANMASK(mask) (mask & ~(numlockmask|LockMask) & (ShiftMask|ControlMask|Mod1Mask|Mod2Mask|Mod3Mask|Mod4Mask|Mod5Mask)) |
46 #define INRECT(X,Y,RX,RY,RW,RH) ((X) >= (RX) && (X) < (RX) + (RW) && (Y) >= (RY) && (Y) < (RY) + (RH)) |
46 #define INTERSECT(x,y,w,h,m) (MAX(0, MIN((x)+(w),(m)->wx+(m)->ww) - MAX((x),(m)->wx)) \ |
|
47 * MAX(0, MIN((y)+(h),(m)->wy+(m)->wh) - MAX((y),(m)->wy))) |
47 #define ISVISIBLE(C) ((C->tags & C->mon->tagset[C->mon->seltags])) |
48 #define ISVISIBLE(C) ((C->tags & C->mon->tagset[C->mon->seltags])) |
48 #define LENGTH(X) (sizeof X / sizeof X[0]) |
49 #define LENGTH(X) (sizeof X / sizeof X[0]) |
49 #define MAX(A, B) ((A) > (B) ? (A) : (B)) |
50 #define MAX(A, B) ((A) > (B) ? (A) : (B)) |
50 #define MIN(A, B) ((A) < (B) ? (A) : (B)) |
51 #define MIN(A, B) ((A) < (B) ? (A) : (B)) |
51 #define MOUSEMASK (BUTTONMASK|PointerMotionMask) |
52 #define MOUSEMASK (BUTTONMASK|PointerMotionMask) |
56 |
57 |
57 /* enums */ |
58 /* enums */ |
58 enum { CurNormal, CurResize, CurMove, CurLast }; /* cursor */ |
59 enum { CurNormal, CurResize, CurMove, CurLast }; /* cursor */ |
59 enum { ColBorder, ColFG, ColBG, ColLast }; /* color */ |
60 enum { ColBorder, ColFG, ColBG, ColLast }; /* color */ |
60 enum { NetSupported, NetWMName, NetWMState, |
61 enum { NetSupported, NetWMName, NetWMState, |
61 NetWMFullscreen, NetLast }; /* EWMH atoms */ |
62 NetWMFullscreen, NetActiveWindow, NetWMWindowType, |
62 enum { WMProtocols, WMDelete, WMState, WMLast }; /* default atoms */ |
63 NetWMWindowTypeDialog, NetLast }; /* EWMH atoms */ |
|
64 enum { WMProtocols, WMDelete, WMState, WMTakeFocus, WMLast }; /* default atoms */ |
63 enum { ClkTagBar, ClkLtSymbol, ClkStatusText, ClkWinTitle, |
65 enum { ClkTagBar, ClkLtSymbol, ClkStatusText, ClkWinTitle, |
64 ClkClientWin, ClkRootWin, ClkLast }; /* clicks */ |
66 ClkClientWin, ClkRootWin, ClkLast }; /* clicks */ |
65 |
67 |
66 typedef union { |
68 typedef union { |
67 int i; |
69 int i; |
86 int x, y, w, h; |
88 int x, y, w, h; |
87 int oldx, oldy, oldw, oldh; |
89 int oldx, oldy, oldw, oldh; |
88 int basew, baseh, incw, inch, maxw, maxh, minw, minh; |
90 int basew, baseh, incw, inch, maxw, maxh, minw, minh; |
89 int bw, oldbw; |
91 int bw, oldbw; |
90 unsigned int tags; |
92 unsigned int tags; |
91 Bool isfixed, isfloating, isurgent, oldstate; |
93 Bool isfixed, isfloating, isurgent, neverfocus, oldstate, isfullscreen; |
92 Client *next; |
94 Client *next; |
93 Client *snext; |
95 Client *snext; |
94 Monitor *mon; |
96 Monitor *mon; |
95 Window win; |
97 Window win; |
96 }; |
98 }; |
187 static Bool getrootptr(int *x, int *y); |
190 static Bool getrootptr(int *x, int *y); |
188 static long getstate(Window w); |
191 static long getstate(Window w); |
189 static Bool gettextprop(Window w, Atom atom, char *text, unsigned int size); |
192 static Bool gettextprop(Window w, Atom atom, char *text, unsigned int size); |
190 static void grabbuttons(Client *c, Bool focused); |
193 static void grabbuttons(Client *c, Bool focused); |
191 static void grabkeys(void); |
194 static void grabkeys(void); |
|
195 static void incnmaster(const Arg *arg); |
192 static void initfont(const char *fontstr); |
196 static void initfont(const char *fontstr); |
193 static Bool isprotodel(Client *c); |
|
194 static void keypress(XEvent *e); |
197 static void keypress(XEvent *e); |
195 static void killclient(const Arg *arg); |
198 static void killclient(const Arg *arg); |
196 static void manage(Window w, XWindowAttributes *wa); |
199 static void manage(Window w, XWindowAttributes *wa); |
197 static void mappingnotify(XEvent *e); |
200 static void mappingnotify(XEvent *e); |
198 static void maprequest(XEvent *e); |
201 static void maprequest(XEvent *e); |
199 static void monocle(Monitor *m); |
202 static void monocle(Monitor *m); |
|
203 static void motionnotify(XEvent *e); |
200 static void movemouse(const Arg *arg); |
204 static void movemouse(const Arg *arg); |
201 static Client *nexttiled(Client *c); |
205 static Client *nexttiled(Client *c); |
202 static Monitor *ptrtomon(int x, int y); |
206 static void pop(Client *); |
203 static void propertynotify(XEvent *e); |
207 static void propertynotify(XEvent *e); |
204 static void quit(const Arg *arg); |
208 static void quit(const Arg *arg); |
|
209 static Monitor *recttomon(int x, int y, int w, int h); |
205 static void resize(Client *c, int x, int y, int w, int h, Bool interact); |
210 static void resize(Client *c, int x, int y, int w, int h, Bool interact); |
206 static void resizeclient(Client *c, int x, int y, int w, int h); |
211 static void resizeclient(Client *c, int x, int y, int w, int h); |
207 static void resizemouse(const Arg *arg); |
212 static void resizemouse(const Arg *arg); |
208 static void restack(Monitor *m); |
213 static void restack(Monitor *m); |
209 static void run(void); |
214 static void run(void); |
210 static void scan(void); |
215 static void scan(void); |
|
216 static Bool sendevent(Client *c, Atom proto); |
211 static void sendmon(Client *c, Monitor *m); |
217 static void sendmon(Client *c, Monitor *m); |
212 static void setclientstate(Client *c, long state); |
218 static void setclientstate(Client *c, long state); |
|
219 static void setfocus(Client *c); |
|
220 static void setfullscreen(Client *c, Bool fullscreen); |
213 static void setlayout(const Arg *arg); |
221 static void setlayout(const Arg *arg); |
214 static void setmfact(const Arg *arg); |
222 static void setmfact(const Arg *arg); |
215 static void setup(void); |
223 static void setup(void); |
216 static void showhide(Client *c); |
224 static void showhide(Client *c); |
217 static void sigchld(int unused); |
225 static void sigchld(int unused); |
231 static void updatebarpos(Monitor *m); |
239 static void updatebarpos(Monitor *m); |
232 static void updatebars(void); |
240 static void updatebars(void); |
233 static void updatenumlockmask(void); |
241 static void updatenumlockmask(void); |
234 static void updatesizehints(Client *c); |
242 static void updatesizehints(Client *c); |
235 static void updatestatus(void); |
243 static void updatestatus(void); |
|
244 static void updatewindowtype(Client *c); |
236 static void updatetitle(Client *c); |
245 static void updatetitle(Client *c); |
237 static void updatewmhints(Client *c); |
246 static void updatewmhints(Client *c); |
238 static void view(const Arg *arg); |
247 static void view(const Arg *arg); |
239 static Client *wintoclient(Window w); |
248 static Client *wintoclient(Window w); |
240 static Monitor *wintomon(Window w); |
249 static Monitor *wintomon(Window w); |
261 [Expose] = expose, |
270 [Expose] = expose, |
262 [FocusIn] = focusin, |
271 [FocusIn] = focusin, |
263 [KeyPress] = keypress, |
272 [KeyPress] = keypress, |
264 [MappingNotify] = mappingnotify, |
273 [MappingNotify] = mappingnotify, |
265 [MapRequest] = maprequest, |
274 [MapRequest] = maprequest, |
|
275 [MotionNotify] = motionnotify, |
266 [PropertyNotify] = propertynotify, |
276 [PropertyNotify] = propertynotify, |
267 [UnmapNotify] = unmapnotify |
277 [UnmapNotify] = unmapnotify |
268 }; |
278 }; |
269 static Atom wmatom[WMLast], netatom[NetLast]; |
279 static Atom wmatom[WMLast], netatom[NetLast]; |
270 static Bool running = True; |
280 static Bool running = True; |
285 applyrules(Client *c) { |
295 applyrules(Client *c) { |
286 const char *class, *instance; |
296 const char *class, *instance; |
287 unsigned int i; |
297 unsigned int i; |
288 const Rule *r; |
298 const Rule *r; |
289 Monitor *m; |
299 Monitor *m; |
290 XClassHint ch = { 0 }; |
300 XClassHint ch = { NULL, NULL }; |
291 |
301 |
292 /* rule matching */ |
302 /* rule matching */ |
293 c->isfloating = c->tags = 0; |
303 c->isfloating = c->tags = 0; |
294 if(XGetClassHint(dpy, c->win, &ch)) { |
304 XGetClassHint(dpy, c->win, &ch); |
295 class = ch.res_class ? ch.res_class : broken; |
305 class = ch.res_class ? ch.res_class : broken; |
296 instance = ch.res_name ? ch.res_name : broken; |
306 instance = ch.res_name ? ch.res_name : broken; |
297 for(i = 0; i < LENGTH(rules); i++) { |
307 |
298 r = &rules[i]; |
308 for(i = 0; i < LENGTH(rules); i++) { |
299 if((!r->title || strstr(c->name, r->title)) |
309 r = &rules[i]; |
300 && (!r->class || strstr(class, r->class)) |
310 if((!r->title || strstr(c->name, r->title)) |
301 && (!r->instance || strstr(instance, r->instance))) |
311 && (!r->class || strstr(class, r->class)) |
302 { |
312 && (!r->instance || strstr(instance, r->instance))) |
303 c->isfloating = r->isfloating; |
313 { |
304 c->tags |= r->tags; |
314 c->isfloating = r->isfloating; |
305 for(m = mons; m && m->num != r->monitor; m = m->next); |
315 c->tags |= r->tags; |
306 if(m) |
316 for(m = mons; m && m->num != r->monitor; m = m->next); |
307 c->mon = m; |
317 if(m) |
308 } |
318 c->mon = m; |
309 } |
319 } |
310 if(ch.res_class) |
320 } |
311 XFree(ch.res_class); |
321 if(ch.res_class) |
312 if(ch.res_name) |
322 XFree(ch.res_class); |
313 XFree(ch.res_name); |
323 if(ch.res_name) |
314 } |
324 XFree(ch.res_name); |
315 c->tags = c->tags & TAGMASK ? c->tags & TAGMASK : c->mon->tagset[c->mon->seltags]; |
325 c->tags = c->tags & TAGMASK ? c->tags & TAGMASK : c->mon->tagset[c->mon->seltags]; |
316 } |
326 } |
317 |
327 |
318 Bool |
328 Bool |
319 applysizehints(Client *c, int *x, int *y, int *w, int *h, Bool interact) { |
329 applysizehints(Client *c, int *x, int *y, int *w, int *h, Bool interact) { |
332 *x = 0; |
342 *x = 0; |
333 if(*y + *h + 2 * c->bw < 0) |
343 if(*y + *h + 2 * c->bw < 0) |
334 *y = 0; |
344 *y = 0; |
335 } |
345 } |
336 else { |
346 else { |
337 if(*x > m->mx + m->mw) |
347 if(*x >= m->wx + m->ww) |
338 *x = m->mx + m->mw - WIDTH(c); |
348 *x = m->wx + m->ww - WIDTH(c); |
339 if(*y > m->my + m->mh) |
349 if(*y >= m->wy + m->wh) |
340 *y = m->my + m->mh - HEIGHT(c); |
350 *y = m->wy + m->wh - HEIGHT(c); |
341 if(*x + *w + 2 * c->bw < m->mx) |
351 if(*x + *w + 2 * c->bw <= m->wx) |
342 *x = m->mx; |
352 *x = m->wx; |
343 if(*y + *h + 2 * c->bw < m->my) |
353 if(*y + *h + 2 * c->bw <= m->wy) |
344 *y = m->my; |
354 *y = m->wy; |
345 } |
355 } |
346 if(*h < bh) |
356 if(*h < bh) |
347 *h = bh; |
357 *h = bh; |
348 if(*w < bh) |
358 if(*w < bh) |
349 *w = bh; |
359 *w = bh; |
350 if(resizehints || c->isfloating) { |
360 if(resizehints || c->isfloating || !c->mon->lt[c->mon->sellt]->arrange) { |
351 /* see last two sentences in ICCCM 4.1.2.3 */ |
361 /* see last two sentences in ICCCM 4.1.2.3 */ |
352 baseismin = c->basew == c->minw && c->baseh == c->minh; |
362 baseismin = c->basew == c->minw && c->baseh == c->minh; |
353 if(!baseismin) { /* temporarily remove base dimensions */ |
363 if(!baseismin) { /* temporarily remove base dimensions */ |
354 *w -= c->basew; |
364 *w -= c->basew; |
355 *h -= c->baseh; |
365 *h -= c->baseh; |
518 XSetWMHints(dpy, c->win, wmh); |
527 XSetWMHints(dpy, c->win, wmh); |
519 XFree(wmh); |
528 XFree(wmh); |
520 } |
529 } |
521 |
530 |
522 void |
531 void |
|
532 clientmessage(XEvent *e) { |
|
533 XClientMessageEvent *cme = &e->xclient; |
|
534 Client *c = wintoclient(cme->window); |
|
535 |
|
536 if(!c) |
|
537 return; |
|
538 if(cme->message_type == netatom[NetWMState]) { |
|
539 if(cme->data.l[1] == netatom[NetWMFullscreen] || cme->data.l[2] == netatom[NetWMFullscreen]) |
|
540 setfullscreen(c, (cme->data.l[0] == 1 /* _NET_WM_STATE_ADD */ |
|
541 || (cme->data.l[0] == 2 /* _NET_WM_STATE_TOGGLE */ && !c->isfullscreen))); |
|
542 } |
|
543 else if(cme->message_type == netatom[NetActiveWindow]) { |
|
544 if(!ISVISIBLE(c)) { |
|
545 c->mon->seltags ^= 1; |
|
546 c->mon->tagset[c->mon->seltags] = c->tags; |
|
547 } |
|
548 pop(c); |
|
549 } |
|
550 } |
|
551 |
|
552 void |
523 configure(Client *c) { |
553 configure(Client *c) { |
524 XConfigureEvent ce; |
554 XConfigureEvent ce; |
525 |
555 |
526 ce.type = ConfigureNotify; |
556 ce.type = ConfigureNotify; |
527 ce.display = dpy; |
557 ce.display = dpy; |
539 |
569 |
540 void |
570 void |
541 configurenotify(XEvent *e) { |
571 configurenotify(XEvent *e) { |
542 Monitor *m; |
572 Monitor *m; |
543 XConfigureEvent *ev = &e->xconfigure; |
573 XConfigureEvent *ev = &e->xconfigure; |
|
574 Bool dirty; |
544 |
575 |
545 if(ev->window == root) { |
576 if(ev->window == root) { |
|
577 dirty = (sw != ev->width); |
546 sw = ev->width; |
578 sw = ev->width; |
547 sh = ev->height; |
579 sh = ev->height; |
548 if(updategeom()) { |
580 if(updategeom() || dirty) { |
549 if(dc.drawable != 0) |
581 if(dc.drawable != 0) |
550 XFreePixmap(dpy, dc.drawable); |
582 XFreePixmap(dpy, dc.drawable); |
551 dc.drawable = XCreatePixmap(dpy, root, sw, bh, DefaultDepth(dpy, screen)); |
583 dc.drawable = XCreatePixmap(dpy, root, sw, bh, DefaultDepth(dpy, screen)); |
552 updatebars(); |
584 updatebars(); |
553 for(m = mons; m; m = m->next) |
585 for(m = mons; m; m = m->next) |
554 XMoveResizeWindow(dpy, m->barwin, m->wx, m->by, m->ww, bh); |
586 XMoveResizeWindow(dpy, m->barwin, m->wx, m->by, m->ww, bh); |
|
587 focus(NULL); |
555 arrange(NULL); |
588 arrange(NULL); |
556 } |
589 } |
557 } |
590 } |
558 } |
591 } |
559 |
592 |
567 if((c = wintoclient(ev->window))) { |
600 if((c = wintoclient(ev->window))) { |
568 if(ev->value_mask & CWBorderWidth) |
601 if(ev->value_mask & CWBorderWidth) |
569 c->bw = ev->border_width; |
602 c->bw = ev->border_width; |
570 else if(c->isfloating || !selmon->lt[selmon->sellt]->arrange) { |
603 else if(c->isfloating || !selmon->lt[selmon->sellt]->arrange) { |
571 m = c->mon; |
604 m = c->mon; |
572 if(ev->value_mask & CWX) |
605 if(ev->value_mask & CWX) { |
|
606 c->oldx = c->x; |
573 c->x = m->mx + ev->x; |
607 c->x = m->mx + ev->x; |
574 if(ev->value_mask & CWY) |
608 } |
|
609 if(ev->value_mask & CWY) { |
|
610 c->oldy = c->y; |
575 c->y = m->my + ev->y; |
611 c->y = m->my + ev->y; |
576 if(ev->value_mask & CWWidth) |
612 } |
|
613 if(ev->value_mask & CWWidth) { |
|
614 c->oldw = c->w; |
577 c->w = ev->width; |
615 c->w = ev->width; |
578 if(ev->value_mask & CWHeight) |
616 } |
|
617 if(ev->value_mask & CWHeight) { |
|
618 c->oldh = c->h; |
579 c->h = ev->height; |
619 c->h = ev->height; |
|
620 } |
580 if((c->x + c->w) > m->mx + m->mw && c->isfloating) |
621 if((c->x + c->w) > m->mx + m->mw && c->isfloating) |
581 c->x = m->mx + (m->mw / 2 - c->w / 2); /* center in x direction */ |
622 c->x = m->mx + (m->mw / 2 - WIDTH(c) / 2); /* center in x direction */ |
582 if((c->y + c->h) > m->my + m->mh && c->isfloating) |
623 if((c->y + c->h) > m->my + m->mh && c->isfloating) |
583 c->y = m->my + (m->mh / 2 - c->h / 2); /* center in y direction */ |
624 c->y = m->my + (m->mh / 2 - HEIGHT(c) / 2); /* center in y direction */ |
584 if((ev->value_mask & (CWX|CWY)) && !(ev->value_mask & (CWWidth|CWHeight))) |
625 if((ev->value_mask & (CWX|CWY)) && !(ev->value_mask & (CWWidth|CWHeight))) |
585 configure(c); |
626 configure(c); |
586 if(ISVISIBLE(c)) |
627 if(ISVISIBLE(c)) |
587 XMoveResizeWindow(dpy, c->win, c->x, c->y, c->w, c->h); |
628 XMoveResizeWindow(dpy, c->win, c->x, c->y, c->w, c->h); |
588 } |
629 } |
608 |
649 |
609 if(!(m = (Monitor *)calloc(1, sizeof(Monitor)))) |
650 if(!(m = (Monitor *)calloc(1, sizeof(Monitor)))) |
610 die("fatal: could not malloc() %u bytes\n", sizeof(Monitor)); |
651 die("fatal: could not malloc() %u bytes\n", sizeof(Monitor)); |
611 m->tagset[0] = m->tagset[1] = 1; |
652 m->tagset[0] = m->tagset[1] = 1; |
612 m->mfact = mfact; |
653 m->mfact = mfact; |
|
654 m->nmaster = nmaster; |
613 m->showbar = showbar; |
655 m->showbar = showbar; |
614 m->topbar = topbar; |
656 m->topbar = topbar; |
615 m->lt[0] = &layouts[0]; |
657 m->lt[0] = &layouts[0]; |
616 m->lt[1] = &layouts[1 % LENGTH(layouts)]; |
658 m->lt[1] = &layouts[1 % LENGTH(layouts)]; |
617 strncpy(m->ltsymbol, layouts[0].symbol, sizeof m->ltsymbol); |
659 strncpy(m->ltsymbol, layouts[0].symbol, sizeof m->ltsymbol); |
734 } |
774 } |
735 |
775 |
736 void |
776 void |
737 drawsquare(Bool filled, Bool empty, Bool invert, unsigned long col[ColLast]) { |
777 drawsquare(Bool filled, Bool empty, Bool invert, unsigned long col[ColLast]) { |
738 int x; |
778 int x; |
739 XGCValues gcv; |
779 |
740 XRectangle r = { dc.x, dc.y, dc.w, dc.h }; |
780 XSetForeground(dpy, dc.gc, col[invert ? ColBG : ColFG]); |
741 |
|
742 gcv.foreground = col[invert ? ColBG : ColFG]; |
|
743 XChangeGC(dpy, dc.gc, GCForeground, &gcv); |
|
744 x = (dc.font.ascent + dc.font.descent + 2) / 4; |
781 x = (dc.font.ascent + dc.font.descent + 2) / 4; |
745 r.x = dc.x + 1; |
782 if(filled) |
746 r.y = dc.y + 1; |
783 XFillRectangle(dpy, dc.drawable, dc.gc, dc.x+1, dc.y+1, x+1, x+1); |
747 if(filled) { |
784 else if(empty) |
748 r.width = r.height = x + 1; |
785 XDrawRectangle(dpy, dc.drawable, dc.gc, dc.x+1, dc.y+1, x, x); |
749 XFillRectangles(dpy, dc.drawable, dc.gc, &r, 1); |
|
750 } |
|
751 else if(empty) { |
|
752 r.width = r.height = x; |
|
753 XDrawRectangles(dpy, dc.drawable, dc.gc, &r, 1); |
|
754 } |
|
755 } |
786 } |
756 |
787 |
757 void |
788 void |
758 drawtext(const char *text, unsigned long col[ColLast], Bool invert) { |
789 drawtext(const char *text, unsigned long col[ColLast], Bool invert) { |
759 char buf[256]; |
790 char buf[256]; |
760 int i, x, y, h, len, olen; |
791 int i, x, y, h, len, olen; |
761 XRectangle r = { dc.x, dc.y, dc.w, dc.h }; |
|
762 |
792 |
763 XSetForeground(dpy, dc.gc, col[invert ? ColFG : ColBG]); |
793 XSetForeground(dpy, dc.gc, col[invert ? ColFG : ColBG]); |
764 XFillRectangles(dpy, dc.drawable, dc.gc, &r, 1); |
794 XFillRectangle(dpy, dc.drawable, dc.gc, dc.x, dc.y, dc.w, dc.h); |
765 if(!text) |
795 if(!text) |
766 return; |
796 return; |
767 olen = strlen(text); |
797 olen = strlen(text); |
768 h = dc.font.ascent + dc.font.descent; |
798 h = dc.font.ascent + dc.font.descent; |
769 y = dc.y + (dc.h / 2) - (h / 2) + dc.font.ascent; |
799 y = dc.y + (dc.h / 2) - (h / 2) + dc.font.ascent; |
782 XDrawString(dpy, dc.drawable, dc.gc, x, y, buf, len); |
812 XDrawString(dpy, dc.drawable, dc.gc, x, y, buf, len); |
783 } |
813 } |
784 |
814 |
785 void |
815 void |
786 enternotify(XEvent *e) { |
816 enternotify(XEvent *e) { |
|
817 Client *c; |
787 Monitor *m; |
818 Monitor *m; |
788 XCrossingEvent *ev = &e->xcrossing; |
819 XCrossingEvent *ev = &e->xcrossing; |
789 |
820 |
790 if((ev->mode != NotifyNormal || ev->detail == NotifyInferior) && ev->window != root) |
821 if((ev->mode != NotifyNormal || ev->detail == NotifyInferior) && ev->window != root) |
791 return; |
822 return; |
792 if((m = wintomon(ev->window)) && m != selmon) { |
823 c = wintoclient(ev->window); |
|
824 m = c ? c->mon : wintomon(ev->window); |
|
825 if(m != selmon) { |
793 unfocus(selmon->sel, True); |
826 unfocus(selmon->sel, True); |
794 selmon = m; |
827 selmon = m; |
795 } |
828 } |
796 focus((wintoclient(ev->window))); |
829 else if(!c || c == selmon->sel) |
|
830 return; |
|
831 focus(c); |
797 } |
832 } |
798 |
833 |
799 void |
834 void |
800 expose(XEvent *e) { |
835 expose(XEvent *e) { |
801 Monitor *m; |
836 Monitor *m; |
966 unsigned int i, j; |
1016 unsigned int i, j; |
967 unsigned int modifiers[] = { 0, LockMask, numlockmask, numlockmask|LockMask }; |
1017 unsigned int modifiers[] = { 0, LockMask, numlockmask, numlockmask|LockMask }; |
968 KeyCode code; |
1018 KeyCode code; |
969 |
1019 |
970 XUngrabKey(dpy, AnyKey, AnyModifier, root); |
1020 XUngrabKey(dpy, AnyKey, AnyModifier, root); |
971 for(i = 0; i < LENGTH(keys); i++) { |
1021 for(i = 0; i < LENGTH(keys); i++) |
972 if((code = XKeysymToKeycode(dpy, keys[i].keysym))) |
1022 if((code = XKeysymToKeycode(dpy, keys[i].keysym))) |
973 for(j = 0; j < LENGTH(modifiers); j++) |
1023 for(j = 0; j < LENGTH(modifiers); j++) |
974 XGrabKey(dpy, code, keys[i].mod | modifiers[j], root, |
1024 XGrabKey(dpy, code, keys[i].mod | modifiers[j], root, |
975 True, GrabModeAsync, GrabModeAsync); |
1025 True, GrabModeAsync, GrabModeAsync); |
976 } |
1026 } |
977 } |
1027 } |
|
1028 |
|
1029 void |
|
1030 incnmaster(const Arg *arg) { |
|
1031 selmon->nmaster = MAX(selmon->nmaster + arg->i, 0); |
|
1032 arrange(selmon); |
978 } |
1033 } |
979 |
1034 |
980 void |
1035 void |
981 initfont(const char *fontstr) { |
1036 initfont(const char *fontstr) { |
982 char *def, **missing; |
1037 char *def, **missing; |
983 int n; |
1038 int n; |
984 |
1039 |
985 missing = NULL; |
|
986 dc.font.set = XCreateFontSet(dpy, fontstr, &missing, &n, &def); |
1040 dc.font.set = XCreateFontSet(dpy, fontstr, &missing, &n, &def); |
987 if(missing) { |
1041 if(missing) { |
988 while(n--) |
1042 while(n--) |
989 fprintf(stderr, "dwm: missing fontset: %s\n", missing[n]); |
1043 fprintf(stderr, "dwm: missing fontset: %s\n", missing[n]); |
990 XFreeStringList(missing); |
1044 XFreeStringList(missing); |
1052 keys[i].func(&(keys[i].arg)); |
1092 keys[i].func(&(keys[i].arg)); |
1053 } |
1093 } |
1054 |
1094 |
1055 void |
1095 void |
1056 killclient(const Arg *arg) { |
1096 killclient(const Arg *arg) { |
1057 XEvent ev; |
|
1058 |
|
1059 if(!selmon->sel) |
1097 if(!selmon->sel) |
1060 return; |
1098 return; |
1061 if(isprotodel(selmon->sel)) { |
1099 if(!sendevent(selmon->sel, wmatom[WMDelete])) { |
1062 ev.type = ClientMessage; |
|
1063 ev.xclient.window = selmon->sel->win; |
|
1064 ev.xclient.message_type = wmatom[WMProtocols]; |
|
1065 ev.xclient.format = 32; |
|
1066 ev.xclient.data.l[0] = wmatom[WMDelete]; |
|
1067 ev.xclient.data.l[1] = CurrentTime; |
|
1068 XSendEvent(dpy, selmon->sel->win, False, NoEventMask, &ev); |
|
1069 } |
|
1070 else { |
|
1071 XGrabServer(dpy); |
1100 XGrabServer(dpy); |
1072 XSetErrorHandler(xerrordummy); |
1101 XSetErrorHandler(xerrordummy); |
1073 XSetCloseDownMode(dpy, DestroyAll); |
1102 XSetCloseDownMode(dpy, DestroyAll); |
1074 XKillClient(dpy, selmon->sel->win); |
1103 XKillClient(dpy, selmon->sel->win); |
1075 XSync(dpy, False); |
1104 XSync(dpy, False); |
1095 else { |
1124 else { |
1096 c->mon = selmon; |
1125 c->mon = selmon; |
1097 applyrules(c); |
1126 applyrules(c); |
1098 } |
1127 } |
1099 /* geometry */ |
1128 /* geometry */ |
1100 c->x = c->oldx = wa->x + c->mon->wx; |
1129 c->x = c->oldx = wa->x; |
1101 c->y = c->oldy = wa->y + c->mon->wy; |
1130 c->y = c->oldy = wa->y; |
1102 c->w = c->oldw = wa->width; |
1131 c->w = c->oldw = wa->width; |
1103 c->h = c->oldh = wa->height; |
1132 c->h = c->oldh = wa->height; |
1104 c->oldbw = wa->border_width; |
1133 c->oldbw = wa->border_width; |
1105 if(c->w == c->mon->mw && c->h == c->mon->mh) { |
1134 |
1106 c->isfloating = True; |
1135 if(c->x + WIDTH(c) > c->mon->mx + c->mon->mw) |
1107 c->x = c->mon->mx; |
1136 c->x = c->mon->mx + c->mon->mw - WIDTH(c); |
1108 c->y = c->mon->my; |
1137 if(c->y + HEIGHT(c) > c->mon->my + c->mon->mh) |
1109 c->bw = 0; |
1138 c->y = c->mon->my + c->mon->mh - HEIGHT(c); |
1110 } |
1139 c->x = MAX(c->x, c->mon->mx); |
1111 else { |
1140 /* only fix client y-offset, if the client center might cover the bar */ |
1112 if(c->x + WIDTH(c) > c->mon->mx + c->mon->mw) |
1141 c->y = MAX(c->y, ((c->mon->by == c->mon->my) && (c->x + (c->w / 2) >= c->mon->wx) |
1113 c->x = c->mon->mx + c->mon->mw - WIDTH(c); |
1142 && (c->x + (c->w / 2) < c->mon->wx + c->mon->ww)) ? bh : c->mon->my); |
1114 if(c->y + HEIGHT(c) > c->mon->my + c->mon->mh) |
1143 c->bw = borderpx; |
1115 c->y = c->mon->my + c->mon->mh - HEIGHT(c); |
1144 |
1116 c->x = MAX(c->x, c->mon->mx); |
|
1117 /* only fix client y-offset, if the client center might cover the bar */ |
|
1118 c->y = MAX(c->y, ((c->mon->by == 0) && (c->x + (c->w / 2) >= c->mon->wx) |
|
1119 && (c->x + (c->w / 2) < c->mon->wx + c->mon->ww)) ? bh : c->mon->my); |
|
1120 c->bw = borderpx; |
|
1121 } |
|
1122 wc.border_width = c->bw; |
1145 wc.border_width = c->bw; |
1123 XConfigureWindow(dpy, w, CWBorderWidth, &wc); |
1146 XConfigureWindow(dpy, w, CWBorderWidth, &wc); |
1124 XSetWindowBorder(dpy, w, dc.norm[ColBorder]); |
1147 XSetWindowBorder(dpy, w, dc.norm[ColBorder]); |
1125 configure(c); /* propagates border_width, if size doesn't change */ |
1148 configure(c); /* propagates border_width, if size doesn't change */ |
|
1149 updatewindowtype(c); |
1126 updatesizehints(c); |
1150 updatesizehints(c); |
|
1151 updatewmhints(c); |
1127 XSelectInput(dpy, w, EnterWindowMask|FocusChangeMask|PropertyChangeMask|StructureNotifyMask); |
1152 XSelectInput(dpy, w, EnterWindowMask|FocusChangeMask|PropertyChangeMask|StructureNotifyMask); |
1128 grabbuttons(c, False); |
1153 grabbuttons(c, False); |
1129 if(!c->isfloating) |
1154 if(!c->isfloating) |
1130 c->isfloating = c->oldstate = trans != None || c->isfixed; |
1155 c->isfloating = c->oldstate = trans != None || c->isfixed; |
1131 if(c->isfloating) |
1156 if(c->isfloating) |
1132 XRaiseWindow(dpy, c->win); |
1157 XRaiseWindow(dpy, c->win); |
1133 attach(c); |
1158 attach(c); |
1134 attachstack(c); |
1159 attachstack(c); |
1135 XMoveResizeWindow(dpy, c->win, c->x + 2 * sw, c->y, c->w, c->h); /* some windows require this */ |
1160 XMoveResizeWindow(dpy, c->win, c->x + 2 * sw, c->y, c->w, c->h); /* some windows require this */ |
|
1161 setclientstate(c, NormalState); |
|
1162 if (c->mon == selmon) |
|
1163 unfocus(selmon->sel, False); |
|
1164 c->mon->sel = c; |
|
1165 arrange(c->mon); |
1136 XMapWindow(dpy, c->win); |
1166 XMapWindow(dpy, c->win); |
1137 setclientstate(c, NormalState); |
1167 focus(NULL); |
1138 arrange(c->mon); |
|
1139 } |
1168 } |
1140 |
1169 |
1141 void |
1170 void |
1142 mappingnotify(XEvent *e) { |
1171 mappingnotify(XEvent *e) { |
1143 XMappingEvent *ev = &e->xmapping; |
1172 XMappingEvent *ev = &e->xmapping; |
1173 for(c = nexttiled(m->clients); c; c = nexttiled(c->next)) |
1202 for(c = nexttiled(m->clients); c; c = nexttiled(c->next)) |
1174 resize(c, m->wx, m->wy, m->ww - 2 * c->bw, m->wh - 2 * c->bw, False); |
1203 resize(c, m->wx, m->wy, m->ww - 2 * c->bw, m->wh - 2 * c->bw, False); |
1175 } |
1204 } |
1176 |
1205 |
1177 void |
1206 void |
|
1207 motionnotify(XEvent *e) { |
|
1208 static Monitor *mon = NULL; |
|
1209 Monitor *m; |
|
1210 XMotionEvent *ev = &e->xmotion; |
|
1211 |
|
1212 if(ev->window != root) |
|
1213 return; |
|
1214 if((m = recttomon(ev->x_root, ev->y_root, 1, 1)) != mon && mon) { |
|
1215 selmon = m; |
|
1216 focus(NULL); |
|
1217 } |
|
1218 mon = m; |
|
1219 } |
|
1220 |
|
1221 void |
1178 movemouse(const Arg *arg) { |
1222 movemouse(const Arg *arg) { |
1179 int x, y, ocx, ocy, nx, ny; |
1223 int x, y, ocx, ocy, nx, ny; |
1180 Client *c; |
1224 Client *c; |
1181 Monitor *m; |
1225 Monitor *m; |
1182 XEvent ev; |
1226 XEvent ev; |
1191 return; |
1235 return; |
1192 if(!getrootptr(&x, &y)) |
1236 if(!getrootptr(&x, &y)) |
1193 return; |
1237 return; |
1194 do { |
1238 do { |
1195 XMaskEvent(dpy, MOUSEMASK|ExposureMask|SubstructureRedirectMask, &ev); |
1239 XMaskEvent(dpy, MOUSEMASK|ExposureMask|SubstructureRedirectMask, &ev); |
1196 switch (ev.type) { |
1240 switch(ev.type) { |
1197 case ConfigureRequest: |
1241 case ConfigureRequest: |
1198 case Expose: |
1242 case Expose: |
1199 case MapRequest: |
1243 case MapRequest: |
1200 handler[ev.type](&ev); |
1244 handler[ev.type](&ev); |
1201 break; |
1245 break; |
1202 case MotionNotify: |
1246 case MotionNotify: |
1203 nx = ocx + (ev.xmotion.x - x); |
1247 nx = ocx + (ev.xmotion.x - x); |
1204 ny = ocy + (ev.xmotion.y - y); |
1248 ny = ocy + (ev.xmotion.y - y); |
1205 if(snap && nx >= selmon->wx && nx <= selmon->wx + selmon->ww |
1249 if(nx >= selmon->wx && nx <= selmon->wx + selmon->ww |
1206 && ny >= selmon->wy && ny <= selmon->wy + selmon->wh) { |
1250 && ny >= selmon->wy && ny <= selmon->wy + selmon->wh) { |
1207 if(abs(selmon->wx - nx) < snap) |
1251 if(abs(selmon->wx - nx) < snap) |
1208 nx = selmon->wx; |
1252 nx = selmon->wx; |
1209 else if(abs((selmon->wx + selmon->ww) - (nx + WIDTH(c))) < snap) |
1253 else if(abs((selmon->wx + selmon->ww) - (nx + WIDTH(c))) < snap) |
1210 nx = selmon->wx + selmon->ww - WIDTH(c); |
1254 nx = selmon->wx + selmon->ww - WIDTH(c); |
1274 if(ev->atom == XA_WM_NAME || ev->atom == netatom[NetWMName]) { |
1316 if(ev->atom == XA_WM_NAME || ev->atom == netatom[NetWMName]) { |
1275 updatetitle(c); |
1317 updatetitle(c); |
1276 if(c == c->mon->sel) |
1318 if(c == c->mon->sel) |
1277 drawbar(c->mon); |
1319 drawbar(c->mon); |
1278 } |
1320 } |
1279 } |
1321 if(ev->atom == netatom[NetWMWindowType]) |
1280 } |
1322 updatewindowtype(c); |
1281 |
|
1282 void |
|
1283 clientmessage(XEvent *e) { |
|
1284 XClientMessageEvent *cme = &e->xclient; |
|
1285 Client *c; |
|
1286 |
|
1287 if((c = wintoclient(cme->window)) |
|
1288 && (cme->message_type == netatom[NetWMState] && cme->data.l[1] == netatom[NetWMFullscreen])) |
|
1289 { |
|
1290 if(cme->data.l[0]) { |
|
1291 XChangeProperty(dpy, cme->window, netatom[NetWMState], XA_ATOM, 32, |
|
1292 PropModeReplace, (unsigned char*)&netatom[NetWMFullscreen], 1); |
|
1293 c->oldstate = c->isfloating; |
|
1294 c->oldbw = c->bw; |
|
1295 c->bw = 0; |
|
1296 c->isfloating = True; |
|
1297 resizeclient(c, c->mon->mx, c->mon->my, c->mon->mw, c->mon->mh); |
|
1298 XRaiseWindow(dpy, c->win); |
|
1299 } |
|
1300 else { |
|
1301 XChangeProperty(dpy, cme->window, netatom[NetWMState], XA_ATOM, 32, |
|
1302 PropModeReplace, (unsigned char*)0, 0); |
|
1303 c->isfloating = c->oldstate; |
|
1304 c->bw = c->oldbw; |
|
1305 c->x = c->oldx; |
|
1306 c->y = c->oldy; |
|
1307 c->w = c->oldw; |
|
1308 c->h = c->oldh; |
|
1309 resizeclient(c, c->x, c->y, c->w, c->h); |
|
1310 arrange(c->mon); |
|
1311 } |
|
1312 } |
1323 } |
1313 } |
1324 } |
1314 |
1325 |
1315 void |
1326 void |
1316 quit(const Arg *arg) { |
1327 quit(const Arg *arg) { |
1317 running = False; |
1328 running = False; |
|
1329 } |
|
1330 |
|
1331 Monitor * |
|
1332 recttomon(int x, int y, int w, int h) { |
|
1333 Monitor *m, *r = selmon; |
|
1334 int a, area = 0; |
|
1335 |
|
1336 for(m = mons; m; m = m->next) |
|
1337 if((a = INTERSECT(x, y, w, h, m)) > area) { |
|
1338 area = a; |
|
1339 r = m; |
|
1340 } |
|
1341 return r; |
1318 } |
1342 } |
1319 |
1343 |
1320 void |
1344 void |
1321 resize(Client *c, int x, int y, int w, int h, Bool interact) { |
1345 resize(Client *c, int x, int y, int w, int h, Bool interact) { |
1322 if(applysizehints(c, &x, &y, &w, &h, interact)) |
1346 if(applysizehints(c, &x, &y, &w, &h, interact)) |
1363 handler[ev.type](&ev); |
1387 handler[ev.type](&ev); |
1364 break; |
1388 break; |
1365 case MotionNotify: |
1389 case MotionNotify: |
1366 nw = MAX(ev.xmotion.x - ocx - 2 * c->bw + 1, 1); |
1390 nw = MAX(ev.xmotion.x - ocx - 2 * c->bw + 1, 1); |
1367 nh = MAX(ev.xmotion.y - ocy - 2 * c->bw + 1, 1); |
1391 nh = MAX(ev.xmotion.y - ocy - 2 * c->bw + 1, 1); |
1368 if(snap && nw >= selmon->wx && nw <= selmon->wx + selmon->ww |
1392 if(c->mon->wx + nw >= selmon->wx && c->mon->wx + nw <= selmon->wx + selmon->ww |
1369 && nh >= selmon->wy && nh <= selmon->wy + selmon->wh) |
1393 && c->mon->wy + nh >= selmon->wy && c->mon->wy + nh <= selmon->wy + selmon->wh) |
1370 { |
1394 { |
1371 if(!c->isfloating && selmon->lt[selmon->sellt]->arrange |
1395 if(!c->isfloating && selmon->lt[selmon->sellt]->arrange |
1372 && (abs(nw - c->w) > snap || abs(nh - c->h) > snap)) |
1396 && (abs(nw - c->w) > snap || abs(nh - c->h) > snap)) |
1373 togglefloating(NULL); |
1397 togglefloating(NULL); |
1374 } |
1398 } |
1378 } |
1402 } |
1379 } while(ev.type != ButtonRelease); |
1403 } while(ev.type != ButtonRelease); |
1380 XWarpPointer(dpy, None, c->win, 0, 0, 0, 0, c->w + c->bw - 1, c->h + c->bw - 1); |
1404 XWarpPointer(dpy, None, c->win, 0, 0, 0, 0, c->w + c->bw - 1, c->h + c->bw - 1); |
1381 XUngrabPointer(dpy, CurrentTime); |
1405 XUngrabPointer(dpy, CurrentTime); |
1382 while(XCheckMaskEvent(dpy, EnterWindowMask, &ev)); |
1406 while(XCheckMaskEvent(dpy, EnterWindowMask, &ev)); |
1383 if((m = ptrtomon(c->x + c->w / 2, c->y + c->h / 2)) != selmon) { |
1407 if((m = recttomon(c->x, c->y, c->w, c->h)) != selmon) { |
1384 sendmon(c, m); |
1408 sendmon(c, m); |
1385 selmon = m; |
1409 selmon = m; |
1386 focus(NULL); |
1410 focus(NULL); |
1387 } |
1411 } |
1388 } |
1412 } |
1467 setclientstate(Client *c, long state) { |
1490 setclientstate(Client *c, long state) { |
1468 long data[] = { state, None }; |
1491 long data[] = { state, None }; |
1469 |
1492 |
1470 XChangeProperty(dpy, c->win, wmatom[WMState], wmatom[WMState], 32, |
1493 XChangeProperty(dpy, c->win, wmatom[WMState], wmatom[WMState], 32, |
1471 PropModeReplace, (unsigned char *)data, 2); |
1494 PropModeReplace, (unsigned char *)data, 2); |
|
1495 } |
|
1496 |
|
1497 Bool |
|
1498 sendevent(Client *c, Atom proto) { |
|
1499 int n; |
|
1500 Atom *protocols; |
|
1501 Bool exists = False; |
|
1502 XEvent ev; |
|
1503 |
|
1504 if(XGetWMProtocols(dpy, c->win, &protocols, &n)) { |
|
1505 while(!exists && n--) |
|
1506 exists = protocols[n] == proto; |
|
1507 XFree(protocols); |
|
1508 } |
|
1509 if(exists) { |
|
1510 ev.type = ClientMessage; |
|
1511 ev.xclient.window = c->win; |
|
1512 ev.xclient.message_type = wmatom[WMProtocols]; |
|
1513 ev.xclient.format = 32; |
|
1514 ev.xclient.data.l[0] = proto; |
|
1515 ev.xclient.data.l[1] = CurrentTime; |
|
1516 XSendEvent(dpy, c->win, False, NoEventMask, &ev); |
|
1517 } |
|
1518 return exists; |
|
1519 } |
|
1520 |
|
1521 void |
|
1522 setfocus(Client *c) { |
|
1523 if(!c->neverfocus) |
|
1524 XSetInputFocus(dpy, c->win, RevertToPointerRoot, CurrentTime); |
|
1525 sendevent(c, wmatom[WMTakeFocus]); |
|
1526 } |
|
1527 |
|
1528 void |
|
1529 setfullscreen(Client *c, Bool fullscreen) { |
|
1530 if(fullscreen) { |
|
1531 XChangeProperty(dpy, c->win, netatom[NetWMState], XA_ATOM, 32, |
|
1532 PropModeReplace, (unsigned char*)&netatom[NetWMFullscreen], 1); |
|
1533 c->isfullscreen = True; |
|
1534 c->oldstate = c->isfloating; |
|
1535 c->oldbw = c->bw; |
|
1536 c->bw = 0; |
|
1537 c->isfloating = True; |
|
1538 resizeclient(c, c->mon->mx, c->mon->my, c->mon->mw, c->mon->mh); |
|
1539 XRaiseWindow(dpy, c->win); |
|
1540 } |
|
1541 else { |
|
1542 XChangeProperty(dpy, c->win, netatom[NetWMState], XA_ATOM, 32, |
|
1543 PropModeReplace, (unsigned char*)0, 0); |
|
1544 c->isfullscreen = False; |
|
1545 c->isfloating = c->oldstate; |
|
1546 c->bw = c->oldbw; |
|
1547 c->x = c->oldx; |
|
1548 c->y = c->oldy; |
|
1549 c->w = c->oldw; |
|
1550 c->h = c->oldh; |
|
1551 resizeclient(c, c->x, c->y, c->w, c->h); |
|
1552 arrange(c->mon); |
|
1553 } |
1472 } |
1554 } |
1473 |
1555 |
1474 void |
1556 void |
1475 setlayout(const Arg *arg) { |
1557 setlayout(const Arg *arg) { |
1476 if(!arg || !arg->v || arg->v != selmon->lt[selmon->sellt]) |
1558 if(!arg || !arg->v || arg->v != selmon->lt[selmon->sellt]) |
1515 updategeom(); |
1597 updategeom(); |
1516 /* init atoms */ |
1598 /* init atoms */ |
1517 wmatom[WMProtocols] = XInternAtom(dpy, "WM_PROTOCOLS", False); |
1599 wmatom[WMProtocols] = XInternAtom(dpy, "WM_PROTOCOLS", False); |
1518 wmatom[WMDelete] = XInternAtom(dpy, "WM_DELETE_WINDOW", False); |
1600 wmatom[WMDelete] = XInternAtom(dpy, "WM_DELETE_WINDOW", False); |
1519 wmatom[WMState] = XInternAtom(dpy, "WM_STATE", False); |
1601 wmatom[WMState] = XInternAtom(dpy, "WM_STATE", False); |
|
1602 wmatom[WMTakeFocus] = XInternAtom(dpy, "WM_TAKE_FOCUS", False); |
|
1603 netatom[NetActiveWindow] = XInternAtom(dpy, "_NET_ACTIVE_WINDOW", False); |
1520 netatom[NetSupported] = XInternAtom(dpy, "_NET_SUPPORTED", False); |
1604 netatom[NetSupported] = XInternAtom(dpy, "_NET_SUPPORTED", False); |
1521 netatom[NetWMName] = XInternAtom(dpy, "_NET_WM_NAME", False); |
1605 netatom[NetWMName] = XInternAtom(dpy, "_NET_WM_NAME", False); |
1522 netatom[NetWMState] = XInternAtom(dpy, "_NET_WM_STATE", False); |
1606 netatom[NetWMState] = XInternAtom(dpy, "_NET_WM_STATE", False); |
1523 netatom[NetWMFullscreen] = XInternAtom(dpy, "_NET_WM_STATE_FULLSCREEN", False); |
1607 netatom[NetWMFullscreen] = XInternAtom(dpy, "_NET_WM_STATE_FULLSCREEN", False); |
|
1608 netatom[NetWMWindowType] = XInternAtom(dpy, "_NET_WM_WINDOW_TYPE", False); |
|
1609 netatom[NetWMWindowTypeDialog] = XInternAtom(dpy, "_NET_WM_WINDOW_TYPE_DIALOG", False); |
1524 /* init cursors */ |
1610 /* init cursors */ |
1525 cursor[CurNormal] = XCreateFontCursor(dpy, XC_left_ptr); |
1611 cursor[CurNormal] = XCreateFontCursor(dpy, XC_left_ptr); |
1526 cursor[CurResize] = XCreateFontCursor(dpy, XC_sizing); |
1612 cursor[CurResize] = XCreateFontCursor(dpy, XC_sizing); |
1527 cursor[CurMove] = XCreateFontCursor(dpy, XC_fleur); |
1613 cursor[CurMove] = XCreateFontCursor(dpy, XC_fleur); |
1528 /* init appearance */ |
1614 /* init appearance */ |
1543 /* EWMH support per view */ |
1629 /* EWMH support per view */ |
1544 XChangeProperty(dpy, root, netatom[NetSupported], XA_ATOM, 32, |
1630 XChangeProperty(dpy, root, netatom[NetSupported], XA_ATOM, 32, |
1545 PropModeReplace, (unsigned char *) netatom, NetLast); |
1631 PropModeReplace, (unsigned char *) netatom, NetLast); |
1546 /* select for events */ |
1632 /* select for events */ |
1547 wa.cursor = cursor[CurNormal]; |
1633 wa.cursor = cursor[CurNormal]; |
1548 wa.event_mask = SubstructureRedirectMask|SubstructureNotifyMask|ButtonPressMask |
1634 wa.event_mask = SubstructureRedirectMask|SubstructureNotifyMask|ButtonPressMask|PointerMotionMask |
1549 |EnterWindowMask|LeaveWindowMask|StructureNotifyMask |
1635 |EnterWindowMask|LeaveWindowMask|StructureNotifyMask|PropertyChangeMask; |
1550 |PropertyChangeMask; |
|
1551 XChangeWindowAttributes(dpy, root, CWEventMask|CWCursor, &wa); |
1636 XChangeWindowAttributes(dpy, root, CWEventMask|CWCursor, &wa); |
1552 XSelectInput(dpy, root, wa.event_mask); |
1637 XSelectInput(dpy, root, wa.event_mask); |
1553 grabkeys(); |
1638 grabkeys(); |
1554 } |
1639 } |
1555 |
1640 |
1557 showhide(Client *c) { |
1642 showhide(Client *c) { |
1558 if(!c) |
1643 if(!c) |
1559 return; |
1644 return; |
1560 if(ISVISIBLE(c)) { /* show clients top down */ |
1645 if(ISVISIBLE(c)) { /* show clients top down */ |
1561 XMoveWindow(dpy, c->win, c->x, c->y); |
1646 XMoveWindow(dpy, c->win, c->x, c->y); |
1562 if(!c->mon->lt[c->mon->sellt]->arrange || c->isfloating) |
1647 if((!c->mon->lt[c->mon->sellt]->arrange || c->isfloating) && !c->isfullscreen) |
1563 resize(c, c->x, c->y, c->w, c->h, False); |
1648 resize(c, c->x, c->y, c->w, c->h, False); |
1564 showhide(c->snext); |
1649 showhide(c->snext); |
1565 } |
1650 } |
1566 else { /* hide clients bottom up */ |
1651 else { /* hide clients bottom up */ |
1567 showhide(c->snext); |
1652 showhide(c->snext); |
1568 XMoveWindow(dpy, c->win, c->x + 2 * sw, c->y); |
1653 XMoveWindow(dpy, c->win, WIDTH(c) * -2, c->y); |
1569 } |
1654 } |
1570 } |
1655 } |
1571 |
1656 |
1572 void |
1657 void |
1573 sigchld(int unused) { |
1658 sigchld(int unused) { |
1615 return XTextWidth(dc.font.xfont, text, len); |
1701 return XTextWidth(dc.font.xfont, text, len); |
1616 } |
1702 } |
1617 |
1703 |
1618 void |
1704 void |
1619 tile(Monitor *m) { |
1705 tile(Monitor *m) { |
1620 int x, y, h, w, mw; |
1706 unsigned int i, n, h, mw, my, ty; |
1621 unsigned int i, n; |
|
1622 Client *c; |
1707 Client *c; |
1623 |
1708 |
1624 for(n = 0, c = nexttiled(m->clients); c; c = nexttiled(c->next), n++); |
1709 for(n = 0, c = nexttiled(m->clients); c; c = nexttiled(c->next), n++); |
1625 if(n == 0) |
1710 if(n == 0) |
1626 return; |
1711 return; |
1627 /* master */ |
1712 |
1628 c = nexttiled(m->clients); |
1713 if(n > m->nmaster) |
1629 mw = m->mfact * m->ww; |
1714 mw = m->nmaster ? m->ww * m->mfact : 0; |
1630 resize(c, m->wx, m->wy, (n == 1 ? m->ww : mw) - 2 * c->bw, m->wh - 2 * c->bw, False); |
1715 else |
1631 if(--n == 0) |
1716 mw = m->ww; |
1632 return; |
1717 for(i = my = ty = 0, c = nexttiled(m->clients); c; c = nexttiled(c->next), i++) |
1633 /* tile stack */ |
1718 if(i < m->nmaster) { |
1634 x = (m->wx + mw > c->x + c->w) ? c->x + c->w + 2 * c->bw : m->wx + mw; |
1719 h = (m->wh - my) / (MIN(n, m->nmaster) - i); |
1635 y = m->wy; |
1720 resize(c, m->wx, m->wy + my, mw - (2*c->bw), h - (2*c->bw), False); |
1636 w = (m->wx + mw > c->x + c->w) ? m->wx + m->ww - x : m->ww - mw; |
1721 my += HEIGHT(c); |
1637 h = m->wh / n; |
1722 } |
1638 if(h < bh) |
1723 else { |
1639 h = m->wh; |
1724 h = (m->wh - ty) / (n - i); |
1640 for(i = 0, c = nexttiled(c->next); c; c = nexttiled(c->next), i++) { |
1725 resize(c, m->wx + mw, m->wy + ty, m->ww - mw - (2*c->bw), h - (2*c->bw), False); |
1641 resize(c, x, y, w - 2 * c->bw, /* remainder */ ((i + 1 == n) |
1726 ty += HEIGHT(c); |
1642 ? m->wy + m->wh - y - 2 * c->bw : h - 2 * c->bw), False); |
1727 } |
1643 if(h != m->wh) |
|
1644 y = c->y + HEIGHT(c); |
|
1645 } |
|
1646 } |
1728 } |
1647 |
1729 |
1648 void |
1730 void |
1649 togglebar(const Arg *arg) { |
1731 togglebar(const Arg *arg) { |
1650 selmon->showbar = !selmon->showbar; |
1732 selmon->showbar = !selmon->showbar; |
1724 void |
1808 void |
1725 unmapnotify(XEvent *e) { |
1809 unmapnotify(XEvent *e) { |
1726 Client *c; |
1810 Client *c; |
1727 XUnmapEvent *ev = &e->xunmap; |
1811 XUnmapEvent *ev = &e->xunmap; |
1728 |
1812 |
1729 if((c = wintoclient(ev->window))) |
1813 if((c = wintoclient(ev->window))) { |
1730 unmanage(c, False); |
1814 if(ev->send_event) |
|
1815 setclientstate(c, WithdrawnState); |
|
1816 else |
|
1817 unmanage(c, False); |
|
1818 } |
1731 } |
1819 } |
1732 |
1820 |
1733 void |
1821 void |
1734 updatebars(void) { |
1822 updatebars(void) { |
1735 Monitor *m; |
1823 Monitor *m; |
1736 XSetWindowAttributes wa; |
1824 XSetWindowAttributes wa = { |
1737 |
1825 .override_redirect = True, |
1738 wa.override_redirect = True; |
1826 .background_pixmap = ParentRelative, |
1739 wa.background_pixmap = ParentRelative; |
1827 .event_mask = ButtonPressMask|ExposureMask |
1740 wa.event_mask = ButtonPressMask|ExposureMask; |
1828 }; |
1741 for(m = mons; m; m = m->next) { |
1829 for(m = mons; m; m = m->next) { |
1742 m->barwin = XCreateWindow(dpy, root, m->wx, m->by, m->ww, bh, 0, DefaultDepth(dpy, screen), |
1830 m->barwin = XCreateWindow(dpy, root, m->wx, m->by, m->ww, bh, 0, DefaultDepth(dpy, screen), |
1743 CopyFromParent, DefaultVisual(dpy, screen), |
1831 CopyFromParent, DefaultVisual(dpy, screen), |
1744 CWOverrideRedirect|CWBackPixmap|CWEventMask, &wa); |
1832 CWOverrideRedirect|CWBackPixmap|CWEventMask, &wa); |
1745 XDefineCursor(dpy, m->barwin, cursor[CurNormal]); |
1833 XDefineCursor(dpy, m->barwin, cursor[CurNormal]); |
1921 strcpy(stext, "dwm-"VERSION); |
2009 strcpy(stext, "dwm-"VERSION); |
1922 drawbar(selmon); |
2010 drawbar(selmon); |
1923 } |
2011 } |
1924 |
2012 |
1925 void |
2013 void |
|
2014 updatewindowtype(Client *c) { |
|
2015 Atom state = getatomprop(c, netatom[NetWMState]); |
|
2016 Atom wtype = getatomprop(c, netatom[NetWMWindowType]); |
|
2017 |
|
2018 if(state == netatom[NetWMFullscreen]) |
|
2019 setfullscreen(c, True); |
|
2020 |
|
2021 if(wtype == netatom[NetWMWindowTypeDialog]) |
|
2022 c->isfloating = True; |
|
2023 } |
|
2024 |
|
2025 void |
1926 updatewmhints(Client *c) { |
2026 updatewmhints(Client *c) { |
1927 XWMHints *wmh; |
2027 XWMHints *wmh; |
1928 |
2028 |
1929 if((wmh = XGetWMHints(dpy, c->win))) { |
2029 if((wmh = XGetWMHints(dpy, c->win))) { |
1930 if(c == selmon->sel && wmh->flags & XUrgencyHint) { |
2030 if(c == selmon->sel && wmh->flags & XUrgencyHint) { |
1931 wmh->flags &= ~XUrgencyHint; |
2031 wmh->flags &= ~XUrgencyHint; |
1932 XSetWMHints(dpy, c->win, wmh); |
2032 XSetWMHints(dpy, c->win, wmh); |
1933 } |
2033 } |
1934 else |
2034 else |
1935 c->isurgent = (wmh->flags & XUrgencyHint) ? True : False; |
2035 c->isurgent = (wmh->flags & XUrgencyHint) ? True : False; |
|
2036 if(wmh->flags & InputHint) |
|
2037 c->neverfocus = !wmh->input; |
|
2038 else |
|
2039 c->neverfocus = False; |
1936 XFree(wmh); |
2040 XFree(wmh); |
1937 } |
2041 } |
1938 } |
2042 } |
1939 |
2043 |
1940 void |
2044 void |
2011 void |
2116 void |
2012 zoom(const Arg *arg) { |
2117 zoom(const Arg *arg) { |
2013 Client *c = selmon->sel; |
2118 Client *c = selmon->sel; |
2014 |
2119 |
2015 if(!selmon->lt[selmon->sellt]->arrange |
2120 if(!selmon->lt[selmon->sellt]->arrange |
2016 || selmon->lt[selmon->sellt]->arrange == monocle |
|
2017 || (selmon->sel && selmon->sel->isfloating)) |
2121 || (selmon->sel && selmon->sel->isfloating)) |
2018 return; |
2122 return; |
2019 if(c == nexttiled(selmon->clients)) |
2123 if(c == nexttiled(selmon->clients)) |
2020 if(!c || !(c = nexttiled(c->next))) |
2124 if(!c || !(c = nexttiled(c->next))) |
2021 return; |
2125 return; |
2022 detach(c); |
2126 pop(c); |
2023 attach(c); |
|
2024 focus(c); |
|
2025 arrange(c->mon); |
|
2026 } |
2127 } |
2027 |
2128 |
2028 int |
2129 int |
2029 main(int argc, char *argv[]) { |
2130 main(int argc, char *argv[]) { |
2030 if(argc == 2 && !strcmp("-v", argv[1])) |
2131 if(argc == 2 && !strcmp("-v", argv[1])) |
2031 die("dwm-"VERSION", © 2006-2010 dwm engineers, see LICENSE for details\n"); |
2132 die("dwm-"VERSION", © 2006-2011 dwm engineers, see LICENSE for details\n"); |
2032 else if(argc != 1) |
2133 else if(argc != 1) |
2033 die("usage: dwm [-v]\n"); |
2134 die("usage: dwm [-v]\n"); |
2034 if(!setlocale(LC_CTYPE, "") || !XSupportsLocale()) |
2135 if(!setlocale(LC_CTYPE, "") || !XSupportsLocale()) |
2035 fputs("warning: no locale support\n", stderr); |
2136 fputs("warning: no locale support\n", stderr); |
2036 if(!(dpy = XOpenDisplay(NULL))) |
2137 if(!(dpy = XOpenDisplay(NULL))) |