45 #include <X11/extensions/Xinerama.h> |
45 #include <X11/extensions/Xinerama.h> |
46 #endif /* XINERAMA */ |
46 #endif /* XINERAMA */ |
47 |
47 |
48 /* macros */ |
48 /* macros */ |
49 #define BUTTONMASK (ButtonPressMask|ButtonReleaseMask) |
49 #define BUTTONMASK (ButtonPressMask|ButtonReleaseMask) |
50 #define CLEANMASK(mask) (mask & ~(numlockmask|LockMask)) |
50 #define CLEANMASK(mask) (mask & ~(numlockmask|LockMask) & (ShiftMask|ControlMask|Mod1Mask|Mod2Mask|Mod3Mask|Mod4Mask|Mod5Mask)) |
51 #define INRECT(X,Y,RX,RY,RW,RH) ((X) >= (RX) && (X) < (RX) + (RW) && (Y) >= (RY) && (Y) < (RY) + (RH)) |
51 #define INTERSECT(x,y,w,h,m) (MAX(0, MIN((x)+(w),(m)->wx+(m)->ww) - MAX((x),(m)->wx)) \ |
|
52 * MAX(0, MIN((y)+(h),(m)->wy+(m)->wh) - MAX((y),(m)->wy))) |
52 #define ISVISIBLE(C) ((C->tags & C->mon->tagset[C->mon->seltags])) |
53 #define ISVISIBLE(C) ((C->tags & C->mon->tagset[C->mon->seltags])) |
53 #define LENGTH(X) (sizeof X / sizeof X[0]) |
54 #define LENGTH(X) (sizeof X / sizeof X[0]) |
54 #ifndef MAX |
55 #ifndef MAX |
55 #define MAX(A, B) ((A) > (B) ? (A) : (B)) |
56 #define MAX(A, B) ((A) > (B) ? (A) : (B)) |
56 #endif |
57 #endif |
66 |
67 |
67 /* enums */ |
68 /* enums */ |
68 enum { CurNormal, CurResize, CurMove, CurLast }; /* cursor */ |
69 enum { CurNormal, CurResize, CurMove, CurLast }; /* cursor */ |
69 enum { ColBorder, ColFG, ColBG, ColLast }; /* color */ |
70 enum { ColBorder, ColFG, ColBG, ColLast }; /* color */ |
70 enum { NetSupported, NetWMName, NetWMState, |
71 enum { NetSupported, NetWMName, NetWMState, |
71 NetWMFullscreen, NetLast }; /* EWMH atoms */ |
72 NetWMFullscreen, NetActiveWindow, NetWMWindowType, |
72 enum { WMProtocols, WMDelete, WMState, WMLast }; /* default atoms */ |
73 NetWMWindowTypeDialog, NetLast }; /* EWMH atoms */ |
|
74 enum { WMProtocols, WMDelete, WMState, WMTakeFocus, WMLast }; /* default atoms */ |
73 enum { ClkTagBar, ClkLtSymbol, ClkStatusText, ClkWinTitle, |
75 enum { ClkTagBar, ClkLtSymbol, ClkStatusText, ClkWinTitle, |
74 ClkClientWin, ClkRootWin, ClkLast }; /* clicks */ |
76 ClkClientWin, ClkRootWin, ClkLast }; /* clicks */ |
75 |
77 |
76 typedef union { |
78 typedef union { |
77 int i; |
79 int i; |
96 int x, y, w, h; |
98 int x, y, w, h; |
97 int oldx, oldy, oldw, oldh; |
99 int oldx, oldy, oldw, oldh; |
98 int basew, baseh, incw, inch, maxw, maxh, minw, minh; |
100 int basew, baseh, incw, inch, maxw, maxh, minw, minh; |
99 int bw, oldbw; |
101 int bw, oldbw; |
100 unsigned int tags; |
102 unsigned int tags; |
101 Bool isfixed, isfloating, isurgent, oldstate; |
103 Bool isfixed, isfloating, isurgent, neverfocus, oldstate, isfullscreen; |
102 Client *next; |
104 Client *next; |
103 Client *snext; |
105 Client *snext; |
104 Monitor *mon; |
106 Monitor *mon; |
105 Window win; |
107 Window win; |
106 }; |
108 }; |
183 static Bool getrootptr(int *x, int *y); |
206 static Bool getrootptr(int *x, int *y); |
184 static long getstate(Window w); |
207 static long getstate(Window w); |
185 static Bool gettextprop(Window w, Atom atom, char *text, unsigned int size); |
208 static Bool gettextprop(Window w, Atom atom, char *text, unsigned int size); |
186 static void grabbuttons(Client *c, Bool focused); |
209 static void grabbuttons(Client *c, Bool focused); |
187 static void grabkeys(void); |
210 static void grabkeys(void); |
|
211 static void incnmaster(const Arg *arg); |
188 static void initfont(const char *fontstr); |
212 static void initfont(const char *fontstr); |
189 static Bool isprotodel(Client *c); |
|
190 static void keypress(XEvent *e); |
213 static void keypress(XEvent *e); |
191 static void killclient(const Arg *arg); |
214 static void killclient(const Arg *arg); |
192 static void manage(Window w, XWindowAttributes *wa); |
215 static void manage(Window w, XWindowAttributes *wa); |
193 static void mappingnotify(XEvent *e); |
216 static void mappingnotify(XEvent *e); |
194 static void maprequest(XEvent *e); |
217 static void maprequest(XEvent *e); |
195 static void monocle(Monitor *m); |
218 static void monocle(Monitor *m); |
|
219 static void motionnotify(XEvent *e); |
196 static void movemouse(const Arg *arg); |
220 static void movemouse(const Arg *arg); |
197 static Client *nexttiled(Client *c); |
221 static Client *nexttiled(Client *c); |
198 static Monitor *ptrtomon(int x, int y); |
222 static void pop(Client *); |
199 static void propertynotify(XEvent *e); |
223 static void propertynotify(XEvent *e); |
200 static void quit(const Arg *arg); |
224 static void quit(const Arg *arg); |
|
225 static Monitor *recttomon(int x, int y, int w, int h); |
201 static void resize(Client *c, int x, int y, int w, int h, Bool interact); |
226 static void resize(Client *c, int x, int y, int w, int h, Bool interact); |
202 static void resizeclient(Client *c, int x, int y, int w, int h); |
227 static void resizeclient(Client *c, int x, int y, int w, int h); |
203 static void resizemouse(const Arg *arg); |
228 static void resizemouse(const Arg *arg); |
204 static void restack(Monitor *m); |
229 static void restack(Monitor *m); |
205 static void run(void); |
230 static void run(void); |
206 static void scan(void); |
231 static void scan(void); |
|
232 static Bool sendevent(Client *c, Atom proto); |
207 static void sendmon(Client *c, Monitor *m); |
233 static void sendmon(Client *c, Monitor *m); |
208 static void setclientstate(Client *c, long state); |
234 static void setclientstate(Client *c, long state); |
|
235 static void setfocus(Client *c); |
|
236 static void setfullscreen(Client *c, Bool fullscreen); |
209 static void setlayout(const Arg *arg); |
237 static void setlayout(const Arg *arg); |
210 static void setmfact(const Arg *arg); |
238 static void setmfact(const Arg *arg); |
211 static void setup(void); |
239 static void setup(void); |
212 static void showhide(Client *c); |
240 static void showhide(Client *c); |
213 static void sigchld(int unused); |
241 static void sigchld(int unused); |
227 static void updatebarpos(Monitor *m); |
255 static void updatebarpos(Monitor *m); |
228 static void updatebars(void); |
256 static void updatebars(void); |
229 static void updatenumlockmask(void); |
257 static void updatenumlockmask(void); |
230 static void updatesizehints(Client *c); |
258 static void updatesizehints(Client *c); |
231 static void updatestatus(void); |
259 static void updatestatus(void); |
|
260 static void updatewindowtype(Client *c); |
232 static void updatetitle(Client *c); |
261 static void updatetitle(Client *c); |
233 static void updatewmhints(Client *c); |
262 static void updatewmhints(Client *c); |
234 static void view(const Arg *arg); |
263 static void view(const Arg *arg); |
235 static Client *wintoclient(Window w); |
264 static Client *wintoclient(Window w); |
236 static Monitor *wintomon(Window w); |
265 static Monitor *wintomon(Window w); |
257 [Expose] = expose, |
286 [Expose] = expose, |
258 [FocusIn] = focusin, |
287 [FocusIn] = focusin, |
259 [KeyPress] = keypress, |
288 [KeyPress] = keypress, |
260 [MappingNotify] = mappingnotify, |
289 [MappingNotify] = mappingnotify, |
261 [MapRequest] = maprequest, |
290 [MapRequest] = maprequest, |
|
291 [MotionNotify] = motionnotify, |
262 [PropertyNotify] = propertynotify, |
292 [PropertyNotify] = propertynotify, |
263 [UnmapNotify] = unmapnotify |
293 [UnmapNotify] = unmapnotify |
264 }; |
294 }; |
265 static Atom wmatom[WMLast], netatom[NetLast]; |
295 static Atom wmatom[WMLast], netatom[NetLast]; |
266 static Bool running = True; |
296 static Bool running = True; |
311 applyrules(Client *c) { |
341 applyrules(Client *c) { |
312 const char *class, *instance; |
342 const char *class, *instance; |
313 unsigned int i; |
343 unsigned int i; |
314 const Rule *r; |
344 const Rule *r; |
315 Monitor *m; |
345 Monitor *m; |
316 XClassHint ch = { 0 }; |
346 XClassHint ch = { NULL, NULL }; |
317 |
347 |
318 /* rule matching */ |
348 /* rule matching */ |
319 c->isfloating = c->tags = 0; |
349 c->isfloating = c->tags = 0; |
320 if(XGetClassHint(dpy, c->win, &ch)) { |
350 XGetClassHint(dpy, c->win, &ch); |
321 class = ch.res_class ? ch.res_class : broken; |
351 class = ch.res_class ? ch.res_class : broken; |
322 instance = ch.res_name ? ch.res_name : broken; |
352 instance = ch.res_name ? ch.res_name : broken; |
323 for(i = 0; i < LENGTH(rules); i++) { |
353 |
324 r = &rules[i]; |
354 for(i = 0; i < LENGTH(rules); i++) { |
325 if((!r->title || strstr(c->name, r->title)) |
355 r = &rules[i]; |
326 && (!r->class || strstr(class, r->class)) |
356 if((!r->title || strstr(c->name, r->title)) |
327 && (!r->instance || strstr(instance, r->instance))) |
357 && (!r->class || strstr(class, r->class)) |
328 { |
358 && (!r->instance || strstr(instance, r->instance))) |
329 c->isfloating = r->isfloating; |
359 { |
330 c->tags |= r->tags; |
360 c->isfloating = r->isfloating; |
331 for(m = mons; m && m->num != r->monitor; m = m->next); |
361 c->tags |= r->tags; |
332 if(m) |
362 for(m = mons; m && m->num != r->monitor; m = m->next); |
333 c->mon = m; |
363 if(m) |
334 } |
364 c->mon = m; |
335 } |
365 } |
336 if(ch.res_class) |
366 } |
337 XFree(ch.res_class); |
367 if(ch.res_class) |
338 if(ch.res_name) |
368 XFree(ch.res_class); |
339 XFree(ch.res_name); |
369 if(ch.res_name) |
340 } |
370 XFree(ch.res_name); |
341 c->tags = c->tags & TAGMASK ? c->tags & TAGMASK : c->mon->tagset[c->mon->seltags]; |
371 c->tags = c->tags & TAGMASK ? c->tags & TAGMASK : c->mon->tagset[c->mon->seltags]; |
342 } |
372 } |
343 |
373 |
344 Bool |
374 Bool |
345 applysizehints(Client *c, int *x, int *y, int *w, int *h, Bool interact) { |
375 applysizehints(Client *c, int *x, int *y, int *w, int *h, Bool interact) { |
358 *x = 0; |
388 *x = 0; |
359 if(*y + *h + 2 * c->bw < 0) |
389 if(*y + *h + 2 * c->bw < 0) |
360 *y = 0; |
390 *y = 0; |
361 } |
391 } |
362 else { |
392 else { |
363 if(*x > m->mx + m->mw) |
393 if(*x >= m->wx + m->ww) |
364 *x = m->mx + m->mw - WIDTH(c); |
394 *x = m->wx + m->ww - WIDTH(c); |
365 if(*y > m->my + m->mh) |
395 if(*y >= m->wy + m->wh) |
366 *y = m->my + m->mh - HEIGHT(c); |
396 *y = m->wy + m->wh - HEIGHT(c); |
367 if(*x + *w + 2 * c->bw < m->mx) |
397 if(*x + *w + 2 * c->bw <= m->wx) |
368 *x = m->mx; |
398 *x = m->wx; |
369 if(*y + *h + 2 * c->bw < m->my) |
399 if(*y + *h + 2 * c->bw <= m->wy) |
370 *y = m->my; |
400 *y = m->wy; |
371 } |
401 } |
372 if(*h < bh) |
402 if(*h < bh) |
373 *h = bh; |
403 *h = bh; |
374 if(*w < bh) |
404 if(*w < bh) |
375 *w = bh; |
405 *w = bh; |
376 if(resizehints || c->isfloating) { |
406 if(resizehints || c->isfloating || !c->mon->lt[c->mon->sellt]->arrange) { |
377 /* see last two sentences in ICCCM 4.1.2.3 */ |
407 /* see last two sentences in ICCCM 4.1.2.3 */ |
378 baseismin = c->basew == c->minw && c->baseh == c->minh; |
408 baseismin = c->basew == c->minw && c->baseh == c->minh; |
379 if(!baseismin) { /* temporarily remove base dimensions */ |
409 if(!baseismin) { /* temporarily remove base dimensions */ |
380 *w -= c->basew; |
410 *w -= c->basew; |
381 *h -= c->baseh; |
411 *h -= c->baseh; |
540 XSetWMHints(dpy, c->win, wmh); |
569 XSetWMHints(dpy, c->win, wmh); |
541 XFree(wmh); |
570 XFree(wmh); |
542 } |
571 } |
543 |
572 |
544 void |
573 void |
|
574 clientmessage(XEvent *e) { |
|
575 XClientMessageEvent *cme = &e->xclient; |
|
576 Client *c = wintoclient(cme->window); |
|
577 |
|
578 if(!c) |
|
579 return; |
|
580 if(cme->message_type == netatom[NetWMState]) { |
|
581 if(cme->data.l[1] == netatom[NetWMFullscreen] || cme->data.l[2] == netatom[NetWMFullscreen]) |
|
582 setfullscreen(c, (cme->data.l[0] == 1 /* _NET_WM_STATE_ADD */ |
|
583 || (cme->data.l[0] == 2 /* _NET_WM_STATE_TOGGLE */ && !c->isfullscreen))); |
|
584 } |
|
585 else if(cme->message_type == netatom[NetActiveWindow]) { |
|
586 if(!ISVISIBLE(c)) { |
|
587 c->mon->seltags ^= 1; |
|
588 c->mon->tagset[c->mon->seltags] = c->tags; |
|
589 } |
|
590 pop(c); |
|
591 } |
|
592 } |
|
593 |
|
594 void |
545 configure(Client *c) { |
595 configure(Client *c) { |
546 XConfigureEvent ce; |
596 XConfigureEvent ce; |
547 |
597 |
548 ce.type = ConfigureNotify; |
598 ce.type = ConfigureNotify; |
549 ce.display = dpy; |
599 ce.display = dpy; |
561 |
611 |
562 void |
612 void |
563 configurenotify(XEvent *e) { |
613 configurenotify(XEvent *e) { |
564 Monitor *m; |
614 Monitor *m; |
565 XConfigureEvent *ev = &e->xconfigure; |
615 XConfigureEvent *ev = &e->xconfigure; |
|
616 Bool dirty; |
566 |
617 |
567 if(ev->window == root) { |
618 if(ev->window == root) { |
|
619 dirty = (sw != ev->width); |
568 sw = ev->width; |
620 sw = ev->width; |
569 sh = ev->height; |
621 sh = ev->height; |
570 if(updategeom()) { |
622 if(updategeom() || dirty) { |
571 if(dc.drawable != 0) |
623 if(dc.drawable != 0) |
572 XFreePixmap(dpy, dc.drawable); |
624 XFreePixmap(dpy, dc.drawable); |
573 dc.drawable = XCreatePixmap(dpy, root, sw, bh, DefaultDepth(dpy, screen)); |
625 dc.drawable = XCreatePixmap(dpy, root, sw, bh, DefaultDepth(dpy, screen)); |
574 XftDrawChange(dc.xftdrawable, dc.drawable); |
626 XftDrawChange(dc.xftdrawable, dc.drawable); |
575 updatebars(); |
627 updatebars(); |
576 for(m = mons; m; m = m->next) |
628 for(m = mons; m; m = m->next) |
577 XMoveResizeWindow(dpy, m->barwin, m->wx, m->by, m->ww, bh); |
629 XMoveResizeWindow(dpy, m->barwin, m->wx, m->by, m->ww, bh); |
|
630 focus(NULL); |
578 arrange(NULL); |
631 arrange(NULL); |
579 } |
632 } |
580 } |
633 } |
581 } |
634 } |
582 |
635 |
590 if((c = wintoclient(ev->window))) { |
643 if((c = wintoclient(ev->window))) { |
591 if(ev->value_mask & CWBorderWidth) |
644 if(ev->value_mask & CWBorderWidth) |
592 c->bw = ev->border_width; |
645 c->bw = ev->border_width; |
593 else if(c->isfloating || !selmon->lt[selmon->sellt]->arrange) { |
646 else if(c->isfloating || !selmon->lt[selmon->sellt]->arrange) { |
594 m = c->mon; |
647 m = c->mon; |
595 if(ev->value_mask & CWX) |
648 if(ev->value_mask & CWX) { |
|
649 c->oldx = c->x; |
596 c->x = m->mx + ev->x; |
650 c->x = m->mx + ev->x; |
597 if(ev->value_mask & CWY) |
651 } |
|
652 if(ev->value_mask & CWY) { |
|
653 c->oldy = c->y; |
598 c->y = m->my + ev->y; |
654 c->y = m->my + ev->y; |
599 if(ev->value_mask & CWWidth) |
655 } |
|
656 if(ev->value_mask & CWWidth) { |
|
657 c->oldw = c->w; |
600 c->w = ev->width; |
658 c->w = ev->width; |
601 if(ev->value_mask & CWHeight) |
659 } |
|
660 if(ev->value_mask & CWHeight) { |
|
661 c->oldh = c->h; |
602 c->h = ev->height; |
662 c->h = ev->height; |
|
663 } |
603 if((c->x + c->w) > m->mx + m->mw && c->isfloating) |
664 if((c->x + c->w) > m->mx + m->mw && c->isfloating) |
604 c->x = m->mx + (m->mw / 2 - c->w / 2); /* center in x direction */ |
665 c->x = m->mx + (m->mw / 2 - WIDTH(c) / 2); /* center in x direction */ |
605 if((c->y + c->h) > m->my + m->mh && c->isfloating) |
666 if((c->y + c->h) > m->my + m->mh && c->isfloating) |
606 c->y = m->my + (m->mh / 2 - c->h / 2); /* center in y direction */ |
667 c->y = m->my + (m->mh / 2 - HEIGHT(c) / 2); /* center in y direction */ |
607 if((ev->value_mask & (CWX|CWY)) && !(ev->value_mask & (CWWidth|CWHeight))) |
668 if((ev->value_mask & (CWX|CWY)) && !(ev->value_mask & (CWWidth|CWHeight))) |
608 configure(c); |
669 configure(c); |
609 if(ISVISIBLE(c)) |
670 if(ISVISIBLE(c)) |
610 XMoveResizeWindow(dpy, c->win, c->x, c->y, c->w, c->h); |
671 XMoveResizeWindow(dpy, c->win, c->x, c->y, c->w, c->h); |
611 } |
672 } |
632 |
693 |
633 if(!(m = (Monitor *)calloc(1, sizeof(Monitor)))) |
694 if(!(m = (Monitor *)calloc(1, sizeof(Monitor)))) |
634 die("fatal: could not malloc() %u bytes\n", sizeof(Monitor)); |
695 die("fatal: could not malloc() %u bytes\n", sizeof(Monitor)); |
635 m->tagset[0] = m->tagset[1] = 1; |
696 m->tagset[0] = m->tagset[1] = 1; |
636 m->mfact = mfact; |
697 m->mfact = mfact; |
|
698 m->nmaster = nmaster; |
637 m->showbar = showbar; |
699 m->showbar = showbar; |
638 m->topbar = topbar; |
700 m->topbar = topbar; |
639 m->lt[0] = &layouts[0]; |
701 m->lt[0] = &layouts[0]; |
640 m->lt[1] = &layouts[1 % LENGTH(layouts)]; |
702 m->lt[1] = &layouts[1 % LENGTH(layouts)]; |
641 strncpy(m->ltsymbol, layouts[0].symbol, sizeof m->ltsymbol); |
703 strncpy(m->ltsymbol, layouts[0].symbol, sizeof m->ltsymbol); |
767 } |
827 } |
768 |
828 |
769 void |
829 void |
770 drawsquare(Bool filled, Bool empty, Bool invert, unsigned long col[ColLast]) { |
830 drawsquare(Bool filled, Bool empty, Bool invert, unsigned long col[ColLast]) { |
771 int x; |
831 int x; |
772 XGCValues gcv; |
832 |
773 XRectangle r = { dc.x, dc.y, dc.w, dc.h }; |
833 XSetForeground(dpy, dc.gc, col[invert ? ColBG : ColFG]); |
774 |
|
775 gcv.foreground = col[invert ? ColBG : ColFG]; |
|
776 XChangeGC(dpy, dc.gc, GCForeground, &gcv); |
|
777 x = (dc.font.ascent + dc.font.descent + 2) / 4; |
834 x = (dc.font.ascent + dc.font.descent + 2) / 4; |
778 r.x = dc.x + 1; |
835 if(filled) |
779 r.y = dc.y + 1; |
836 XFillRectangle(dpy, dc.drawable, dc.gc, dc.x+1, dc.y+1, x+1, x+1); |
780 if(filled) { |
837 else if(empty) |
781 r.width = r.height = x + 1; |
838 XDrawRectangle(dpy, dc.drawable, dc.gc, dc.x+1, dc.y+1, x, x); |
782 XFillRectangles(dpy, dc.drawable, dc.gc, &r, 1); |
|
783 } |
|
784 else if(empty) { |
|
785 r.width = r.height = x; |
|
786 XDrawRectangles(dpy, dc.drawable, dc.gc, &r, 1); |
|
787 } |
|
788 } |
839 } |
789 |
840 |
790 void |
841 void |
791 drawtext(const char *text, unsigned long col[ColLast], Bool invert, Bool markup) { |
842 drawtext(const char *text, unsigned long col[ColLast], Bool invert, Bool markup) { |
792 char buf[256]; |
843 char buf[256]; |
793 int i, x, y, h, len, olen; |
844 int i, x, y, h, len, olen; |
794 XRectangle r = { dc.x, dc.y, dc.w, dc.h }; |
|
795 |
845 |
796 XSetForeground(dpy, dc.gc, col[invert ? ColFG : ColBG]); |
846 XSetForeground(dpy, dc.gc, col[invert ? ColFG : ColBG]); |
797 XFillRectangles(dpy, dc.drawable, dc.gc, &r, 1); |
847 XFillRectangle(dpy, dc.drawable, dc.gc, dc.x, dc.y, dc.w, dc.h); |
798 if(!text) |
848 if(!text) |
799 return; |
849 return; |
800 olen = strlen(text); |
850 olen = strlen(text); |
801 h = dc.font.ascent + dc.font.descent; |
851 h = dc.font.ascent + dc.font.descent; |
802 //y = dc.y + (dc.h / 2) - (h / 2) + dc.font.ascent; |
852 //y = dc.y + (dc.h / 2) - (h / 2) + dc.font.ascent; |
816 pango_xft_render_layout(dc.xftdrawable, (col==dc.norm?dc.xftnorm:dc.xftsel)+(invert?ColBG:ColFG), dc.plo, x * PANGO_SCALE, y * PANGO_SCALE); |
866 pango_xft_render_layout(dc.xftdrawable, (col==dc.norm?dc.xftnorm:dc.xftsel)+(invert?ColBG:ColFG), dc.plo, x * PANGO_SCALE, y * PANGO_SCALE); |
817 } |
867 } |
818 |
868 |
819 void |
869 void |
820 enternotify(XEvent *e) { |
870 enternotify(XEvent *e) { |
|
871 Client *c; |
821 Monitor *m; |
872 Monitor *m; |
822 XCrossingEvent *ev = &e->xcrossing; |
873 XCrossingEvent *ev = &e->xcrossing; |
823 |
874 |
824 if((ev->mode != NotifyNormal || ev->detail == NotifyInferior) && ev->window != root) |
875 if((ev->mode != NotifyNormal || ev->detail == NotifyInferior) && ev->window != root) |
825 return; |
876 return; |
826 if((m = wintomon(ev->window)) && m != selmon) { |
877 c = wintoclient(ev->window); |
|
878 m = c ? c->mon : wintomon(ev->window); |
|
879 if(m != selmon) { |
827 unfocus(selmon->sel, True); |
880 unfocus(selmon->sel, True); |
828 selmon = m; |
881 selmon = m; |
829 } |
882 } |
830 focus((wintoclient(ev->window))); |
883 else if(!c || c == selmon->sel) |
|
884 return; |
|
885 focus(c); |
831 } |
886 } |
832 |
887 |
833 void |
888 void |
834 expose(XEvent *e) { |
889 expose(XEvent *e) { |
835 Monitor *m; |
890 Monitor *m; |
1000 unsigned int i, j; |
1070 unsigned int i, j; |
1001 unsigned int modifiers[] = { 0, LockMask, numlockmask, numlockmask|LockMask }; |
1071 unsigned int modifiers[] = { 0, LockMask, numlockmask, numlockmask|LockMask }; |
1002 KeyCode code; |
1072 KeyCode code; |
1003 |
1073 |
1004 XUngrabKey(dpy, AnyKey, AnyModifier, root); |
1074 XUngrabKey(dpy, AnyKey, AnyModifier, root); |
1005 for(i = 0; i < LENGTH(keys); i++) { |
1075 for(i = 0; i < LENGTH(keys); i++) |
1006 if((code = XKeysymToKeycode(dpy, keys[i].keysym))) |
1076 if((code = XKeysymToKeycode(dpy, keys[i].keysym))) |
1007 for(j = 0; j < LENGTH(modifiers); j++) |
1077 for(j = 0; j < LENGTH(modifiers); j++) |
1008 XGrabKey(dpy, code, keys[i].mod | modifiers[j], root, |
1078 XGrabKey(dpy, code, keys[i].mod | modifiers[j], root, |
1009 True, GrabModeAsync, GrabModeAsync); |
1079 True, GrabModeAsync, GrabModeAsync); |
1010 } |
1080 } |
1011 } |
1081 } |
|
1082 |
|
1083 void |
|
1084 incnmaster(const Arg *arg) { |
|
1085 selmon->nmaster = MAX(selmon->nmaster + arg->i, 0); |
|
1086 arrange(selmon); |
1012 } |
1087 } |
1013 |
1088 |
1014 void |
1089 void |
1015 initfont(const char *fontstr) { |
1090 initfont(const char *fontstr) { |
1016 PangoFontMetrics *metrics; |
1091 PangoFontMetrics *metrics; |
1069 keys[i].func(&(keys[i].arg)); |
1130 keys[i].func(&(keys[i].arg)); |
1070 } |
1131 } |
1071 |
1132 |
1072 void |
1133 void |
1073 killclient(const Arg *arg) { |
1134 killclient(const Arg *arg) { |
1074 XEvent ev; |
|
1075 |
|
1076 if(!selmon->sel) |
1135 if(!selmon->sel) |
1077 return; |
1136 return; |
1078 if(isprotodel(selmon->sel)) { |
1137 if(!sendevent(selmon->sel, wmatom[WMDelete])) { |
1079 ev.type = ClientMessage; |
|
1080 ev.xclient.window = selmon->sel->win; |
|
1081 ev.xclient.message_type = wmatom[WMProtocols]; |
|
1082 ev.xclient.format = 32; |
|
1083 ev.xclient.data.l[0] = wmatom[WMDelete]; |
|
1084 ev.xclient.data.l[1] = CurrentTime; |
|
1085 XSendEvent(dpy, selmon->sel->win, False, NoEventMask, &ev); |
|
1086 } |
|
1087 else { |
|
1088 XGrabServer(dpy); |
1138 XGrabServer(dpy); |
1089 XSetErrorHandler(xerrordummy); |
1139 XSetErrorHandler(xerrordummy); |
1090 XSetCloseDownMode(dpy, DestroyAll); |
1140 XSetCloseDownMode(dpy, DestroyAll); |
1091 XKillClient(dpy, selmon->sel->win); |
1141 XKillClient(dpy, selmon->sel->win); |
1092 XSync(dpy, False); |
1142 XSync(dpy, False); |
1112 else { |
1162 else { |
1113 c->mon = selmon; |
1163 c->mon = selmon; |
1114 applyrules(c); |
1164 applyrules(c); |
1115 } |
1165 } |
1116 /* geometry */ |
1166 /* geometry */ |
1117 c->x = c->oldx = wa->x + c->mon->wx; |
1167 c->x = c->oldx = wa->x; |
1118 c->y = c->oldy = wa->y + c->mon->wy; |
1168 c->y = c->oldy = wa->y; |
1119 c->w = c->oldw = wa->width; |
1169 c->w = c->oldw = wa->width; |
1120 c->h = c->oldh = wa->height; |
1170 c->h = c->oldh = wa->height; |
1121 c->oldbw = wa->border_width; |
1171 c->oldbw = wa->border_width; |
1122 if(c->w == c->mon->mw && c->h == c->mon->mh) { |
1172 |
1123 c->isfloating = True; |
1173 if(c->x + WIDTH(c) > c->mon->mx + c->mon->mw) |
1124 c->x = c->mon->mx; |
1174 c->x = c->mon->mx + c->mon->mw - WIDTH(c); |
1125 c->y = c->mon->my; |
1175 if(c->y + HEIGHT(c) > c->mon->my + c->mon->mh) |
1126 c->bw = 0; |
1176 c->y = c->mon->my + c->mon->mh - HEIGHT(c); |
1127 } |
1177 c->x = MAX(c->x, c->mon->mx); |
1128 else { |
1178 /* only fix client y-offset, if the client center might cover the bar */ |
1129 if(c->x + WIDTH(c) > c->mon->mx + c->mon->mw) |
1179 c->y = MAX(c->y, ((c->mon->by == c->mon->my) && (c->x + (c->w / 2) >= c->mon->wx) |
1130 c->x = c->mon->mx + c->mon->mw - WIDTH(c); |
1180 && (c->x + (c->w / 2) < c->mon->wx + c->mon->ww)) ? bh : c->mon->my); |
1131 if(c->y + HEIGHT(c) > c->mon->my + c->mon->mh) |
1181 c->bw = borderpx; |
1132 c->y = c->mon->my + c->mon->mh - HEIGHT(c); |
1182 |
1133 c->x = MAX(c->x, c->mon->mx); |
|
1134 /* only fix client y-offset, if the client center might cover the bar */ |
|
1135 c->y = MAX(c->y, ((c->mon->by == 0) && (c->x + (c->w / 2) >= c->mon->wx) |
|
1136 && (c->x + (c->w / 2) < c->mon->wx + c->mon->ww)) ? bh : c->mon->my); |
|
1137 c->bw = borderpx; |
|
1138 } |
|
1139 wc.border_width = c->bw; |
1183 wc.border_width = c->bw; |
1140 XConfigureWindow(dpy, w, CWBorderWidth, &wc); |
1184 XConfigureWindow(dpy, w, CWBorderWidth, &wc); |
1141 XSetWindowBorder(dpy, w, dc.norm[ColBorder]); |
1185 XSetWindowBorder(dpy, w, dc.norm[ColBorder]); |
1142 configure(c); /* propagates border_width, if size doesn't change */ |
1186 configure(c); /* propagates border_width, if size doesn't change */ |
|
1187 updatewindowtype(c); |
1143 updatesizehints(c); |
1188 updatesizehints(c); |
|
1189 updatewmhints(c); |
1144 XSelectInput(dpy, w, EnterWindowMask|FocusChangeMask|PropertyChangeMask|StructureNotifyMask); |
1190 XSelectInput(dpy, w, EnterWindowMask|FocusChangeMask|PropertyChangeMask|StructureNotifyMask); |
1145 grabbuttons(c, False); |
1191 grabbuttons(c, False); |
1146 if(!c->isfloating) |
1192 if(!c->isfloating) |
1147 c->isfloating = c->oldstate = trans != None || c->isfixed; |
1193 c->isfloating = c->oldstate = trans != None || c->isfixed; |
1148 if(c->isfloating) |
1194 if(c->isfloating) |
1149 XRaiseWindow(dpy, c->win); |
1195 XRaiseWindow(dpy, c->win); |
1150 attach(c); |
1196 attach(c); |
1151 attachstack(c); |
1197 attachstack(c); |
1152 XMoveResizeWindow(dpy, c->win, c->x + 2 * sw, c->y, c->w, c->h); /* some windows require this */ |
1198 XMoveResizeWindow(dpy, c->win, c->x + 2 * sw, c->y, c->w, c->h); /* some windows require this */ |
|
1199 setclientstate(c, NormalState); |
|
1200 if (c->mon == selmon) |
|
1201 unfocus(selmon->sel, False); |
|
1202 c->mon->sel = c; |
|
1203 arrange(c->mon); |
1153 XMapWindow(dpy, c->win); |
1204 XMapWindow(dpy, c->win); |
1154 setclientstate(c, NormalState); |
1205 focus(NULL); |
1155 arrange(c->mon); |
|
1156 } |
1206 } |
1157 |
1207 |
1158 void |
1208 void |
1159 mappingnotify(XEvent *e) { |
1209 mappingnotify(XEvent *e) { |
1160 XMappingEvent *ev = &e->xmapping; |
1210 XMappingEvent *ev = &e->xmapping; |
1190 for(c = nexttiled(m->clients); c; c = nexttiled(c->next)) |
1240 for(c = nexttiled(m->clients); c; c = nexttiled(c->next)) |
1191 resize(c, m->wx, m->wy, m->ww - 2 * c->bw, m->wh - 2 * c->bw, False); |
1241 resize(c, m->wx, m->wy, m->ww - 2 * c->bw, m->wh - 2 * c->bw, False); |
1192 } |
1242 } |
1193 |
1243 |
1194 void |
1244 void |
|
1245 motionnotify(XEvent *e) { |
|
1246 static Monitor *mon = NULL; |
|
1247 Monitor *m; |
|
1248 XMotionEvent *ev = &e->xmotion; |
|
1249 |
|
1250 if(ev->window != root) |
|
1251 return; |
|
1252 if((m = recttomon(ev->x_root, ev->y_root, 1, 1)) != mon && mon) { |
|
1253 selmon = m; |
|
1254 focus(NULL); |
|
1255 } |
|
1256 mon = m; |
|
1257 } |
|
1258 |
|
1259 void |
1195 movemouse(const Arg *arg) { |
1260 movemouse(const Arg *arg) { |
1196 int x, y, ocx, ocy, nx, ny; |
1261 int x, y, ocx, ocy, nx, ny; |
1197 Client *c; |
1262 Client *c; |
1198 Monitor *m; |
1263 Monitor *m; |
1199 XEvent ev; |
1264 XEvent ev; |
1208 return; |
1273 return; |
1209 if(!getrootptr(&x, &y)) |
1274 if(!getrootptr(&x, &y)) |
1210 return; |
1275 return; |
1211 do { |
1276 do { |
1212 XMaskEvent(dpy, MOUSEMASK|ExposureMask|SubstructureRedirectMask, &ev); |
1277 XMaskEvent(dpy, MOUSEMASK|ExposureMask|SubstructureRedirectMask, &ev); |
1213 switch (ev.type) { |
1278 switch(ev.type) { |
1214 case ConfigureRequest: |
1279 case ConfigureRequest: |
1215 case Expose: |
1280 case Expose: |
1216 case MapRequest: |
1281 case MapRequest: |
1217 handler[ev.type](&ev); |
1282 handler[ev.type](&ev); |
1218 break; |
1283 break; |
1219 case MotionNotify: |
1284 case MotionNotify: |
1220 nx = ocx + (ev.xmotion.x - x); |
1285 nx = ocx + (ev.xmotion.x - x); |
1221 ny = ocy + (ev.xmotion.y - y); |
1286 ny = ocy + (ev.xmotion.y - y); |
1222 if(snap && nx >= selmon->wx && nx <= selmon->wx + selmon->ww |
1287 if(nx >= selmon->wx && nx <= selmon->wx + selmon->ww |
1223 && ny >= selmon->wy && ny <= selmon->wy + selmon->wh) { |
1288 && ny >= selmon->wy && ny <= selmon->wy + selmon->wh) { |
1224 if(abs(selmon->wx - nx) < snap) |
1289 if(abs(selmon->wx - nx) < snap) |
1225 nx = selmon->wx; |
1290 nx = selmon->wx; |
1226 else if(abs((selmon->wx + selmon->ww) - (nx + WIDTH(c))) < snap) |
1291 else if(abs((selmon->wx + selmon->ww) - (nx + WIDTH(c))) < snap) |
1227 nx = selmon->wx + selmon->ww - WIDTH(c); |
1292 nx = selmon->wx + selmon->ww - WIDTH(c); |
1291 if(ev->atom == XA_WM_NAME || ev->atom == netatom[NetWMName]) { |
1354 if(ev->atom == XA_WM_NAME || ev->atom == netatom[NetWMName]) { |
1292 updatetitle(c); |
1355 updatetitle(c); |
1293 if(c == c->mon->sel) |
1356 if(c == c->mon->sel) |
1294 drawbar(c->mon); |
1357 drawbar(c->mon); |
1295 } |
1358 } |
1296 } |
1359 if(ev->atom == netatom[NetWMWindowType]) |
1297 } |
1360 updatewindowtype(c); |
1298 |
|
1299 void |
|
1300 clientmessage(XEvent *e) { |
|
1301 XClientMessageEvent *cme = &e->xclient; |
|
1302 Client *c; |
|
1303 |
|
1304 if((c = wintoclient(cme->window)) |
|
1305 && (cme->message_type == netatom[NetWMState] && cme->data.l[1] == netatom[NetWMFullscreen])) |
|
1306 { |
|
1307 if(cme->data.l[0]) { |
|
1308 XChangeProperty(dpy, cme->window, netatom[NetWMState], XA_ATOM, 32, |
|
1309 PropModeReplace, (unsigned char*)&netatom[NetWMFullscreen], 1); |
|
1310 c->oldstate = c->isfloating; |
|
1311 c->oldbw = c->bw; |
|
1312 c->bw = 0; |
|
1313 c->isfloating = True; |
|
1314 resizeclient(c, c->mon->mx, c->mon->my, c->mon->mw, c->mon->mh); |
|
1315 XRaiseWindow(dpy, c->win); |
|
1316 } |
|
1317 else { |
|
1318 XChangeProperty(dpy, cme->window, netatom[NetWMState], XA_ATOM, 32, |
|
1319 PropModeReplace, (unsigned char*)0, 0); |
|
1320 c->isfloating = c->oldstate; |
|
1321 c->bw = c->oldbw; |
|
1322 c->x = c->oldx; |
|
1323 c->y = c->oldy; |
|
1324 c->w = c->oldw; |
|
1325 c->h = c->oldh; |
|
1326 resizeclient(c, c->x, c->y, c->w, c->h); |
|
1327 arrange(c->mon); |
|
1328 } |
|
1329 } |
1361 } |
1330 } |
1362 } |
1331 |
1363 |
1332 void |
1364 void |
1333 quit(const Arg *arg) { |
1365 quit(const Arg *arg) { |
1334 running = False; |
1366 running = False; |
|
1367 } |
|
1368 |
|
1369 Monitor * |
|
1370 recttomon(int x, int y, int w, int h) { |
|
1371 Monitor *m, *r = selmon; |
|
1372 int a, area = 0; |
|
1373 |
|
1374 for(m = mons; m; m = m->next) |
|
1375 if((a = INTERSECT(x, y, w, h, m)) > area) { |
|
1376 area = a; |
|
1377 r = m; |
|
1378 } |
|
1379 return r; |
1335 } |
1380 } |
1336 |
1381 |
1337 void |
1382 void |
1338 resize(Client *c, int x, int y, int w, int h, Bool interact) { |
1383 resize(Client *c, int x, int y, int w, int h, Bool interact) { |
1339 if(applysizehints(c, &x, &y, &w, &h, interact)) |
1384 if(applysizehints(c, &x, &y, &w, &h, interact)) |
1380 handler[ev.type](&ev); |
1425 handler[ev.type](&ev); |
1381 break; |
1426 break; |
1382 case MotionNotify: |
1427 case MotionNotify: |
1383 nw = MAX(ev.xmotion.x - ocx - 2 * c->bw + 1, 1); |
1428 nw = MAX(ev.xmotion.x - ocx - 2 * c->bw + 1, 1); |
1384 nh = MAX(ev.xmotion.y - ocy - 2 * c->bw + 1, 1); |
1429 nh = MAX(ev.xmotion.y - ocy - 2 * c->bw + 1, 1); |
1385 if(snap && nw >= selmon->wx && nw <= selmon->wx + selmon->ww |
1430 if(c->mon->wx + nw >= selmon->wx && c->mon->wx + nw <= selmon->wx + selmon->ww |
1386 && nh >= selmon->wy && nh <= selmon->wy + selmon->wh) |
1431 && c->mon->wy + nh >= selmon->wy && c->mon->wy + nh <= selmon->wy + selmon->wh) |
1387 { |
1432 { |
1388 if(!c->isfloating && selmon->lt[selmon->sellt]->arrange |
1433 if(!c->isfloating && selmon->lt[selmon->sellt]->arrange |
1389 && (abs(nw - c->w) > snap || abs(nh - c->h) > snap)) |
1434 && (abs(nw - c->w) > snap || abs(nh - c->h) > snap)) |
1390 togglefloating(NULL); |
1435 togglefloating(NULL); |
1391 } |
1436 } |
1395 } |
1440 } |
1396 } while(ev.type != ButtonRelease); |
1441 } while(ev.type != ButtonRelease); |
1397 XWarpPointer(dpy, None, c->win, 0, 0, 0, 0, c->w + c->bw - 1, c->h + c->bw - 1); |
1442 XWarpPointer(dpy, None, c->win, 0, 0, 0, 0, c->w + c->bw - 1, c->h + c->bw - 1); |
1398 XUngrabPointer(dpy, CurrentTime); |
1443 XUngrabPointer(dpy, CurrentTime); |
1399 while(XCheckMaskEvent(dpy, EnterWindowMask, &ev)); |
1444 while(XCheckMaskEvent(dpy, EnterWindowMask, &ev)); |
1400 if((m = ptrtomon(c->x + c->w / 2, c->y + c->h / 2)) != selmon) { |
1445 if((m = recttomon(c->x, c->y, c->w, c->h)) != selmon) { |
1401 sendmon(c, m); |
1446 sendmon(c, m); |
1402 selmon = m; |
1447 selmon = m; |
1403 focus(NULL); |
1448 focus(NULL); |
1404 } |
1449 } |
1405 } |
1450 } |
1484 setclientstate(Client *c, long state) { |
1528 setclientstate(Client *c, long state) { |
1485 long data[] = { state, None }; |
1529 long data[] = { state, None }; |
1486 |
1530 |
1487 XChangeProperty(dpy, c->win, wmatom[WMState], wmatom[WMState], 32, |
1531 XChangeProperty(dpy, c->win, wmatom[WMState], wmatom[WMState], 32, |
1488 PropModeReplace, (unsigned char *)data, 2); |
1532 PropModeReplace, (unsigned char *)data, 2); |
|
1533 } |
|
1534 |
|
1535 Bool |
|
1536 sendevent(Client *c, Atom proto) { |
|
1537 int n; |
|
1538 Atom *protocols; |
|
1539 Bool exists = False; |
|
1540 XEvent ev; |
|
1541 |
|
1542 if(XGetWMProtocols(dpy, c->win, &protocols, &n)) { |
|
1543 while(!exists && n--) |
|
1544 exists = protocols[n] == proto; |
|
1545 XFree(protocols); |
|
1546 } |
|
1547 if(exists) { |
|
1548 ev.type = ClientMessage; |
|
1549 ev.xclient.window = c->win; |
|
1550 ev.xclient.message_type = wmatom[WMProtocols]; |
|
1551 ev.xclient.format = 32; |
|
1552 ev.xclient.data.l[0] = proto; |
|
1553 ev.xclient.data.l[1] = CurrentTime; |
|
1554 XSendEvent(dpy, c->win, False, NoEventMask, &ev); |
|
1555 } |
|
1556 return exists; |
|
1557 } |
|
1558 |
|
1559 void |
|
1560 setfocus(Client *c) { |
|
1561 if(!c->neverfocus) |
|
1562 XSetInputFocus(dpy, c->win, RevertToPointerRoot, CurrentTime); |
|
1563 sendevent(c, wmatom[WMTakeFocus]); |
|
1564 } |
|
1565 |
|
1566 void |
|
1567 setfullscreen(Client *c, Bool fullscreen) { |
|
1568 if(fullscreen) { |
|
1569 XChangeProperty(dpy, c->win, netatom[NetWMState], XA_ATOM, 32, |
|
1570 PropModeReplace, (unsigned char*)&netatom[NetWMFullscreen], 1); |
|
1571 c->isfullscreen = True; |
|
1572 c->oldstate = c->isfloating; |
|
1573 c->oldbw = c->bw; |
|
1574 c->bw = 0; |
|
1575 c->isfloating = True; |
|
1576 resizeclient(c, c->mon->mx, c->mon->my, c->mon->mw, c->mon->mh); |
|
1577 XRaiseWindow(dpy, c->win); |
|
1578 } |
|
1579 else { |
|
1580 XChangeProperty(dpy, c->win, netatom[NetWMState], XA_ATOM, 32, |
|
1581 PropModeReplace, (unsigned char*)0, 0); |
|
1582 c->isfullscreen = False; |
|
1583 c->isfloating = c->oldstate; |
|
1584 c->bw = c->oldbw; |
|
1585 c->x = c->oldx; |
|
1586 c->y = c->oldy; |
|
1587 c->w = c->oldw; |
|
1588 c->h = c->oldh; |
|
1589 resizeclient(c, c->x, c->y, c->w, c->h); |
|
1590 arrange(c->mon); |
|
1591 } |
1489 } |
1592 } |
1490 |
1593 |
1491 void |
1594 void |
1492 setlayout(const Arg *arg) { |
1595 setlayout(const Arg *arg) { |
1493 if(!arg || !arg->v || arg->v != selmon->lt[selmon->sellt]) |
1596 if(!arg || !arg->v || arg->v != selmon->lt[selmon->sellt]) |
1532 updategeom(); |
1635 updategeom(); |
1533 /* init atoms */ |
1636 /* init atoms */ |
1534 wmatom[WMProtocols] = XInternAtom(dpy, "WM_PROTOCOLS", False); |
1637 wmatom[WMProtocols] = XInternAtom(dpy, "WM_PROTOCOLS", False); |
1535 wmatom[WMDelete] = XInternAtom(dpy, "WM_DELETE_WINDOW", False); |
1638 wmatom[WMDelete] = XInternAtom(dpy, "WM_DELETE_WINDOW", False); |
1536 wmatom[WMState] = XInternAtom(dpy, "WM_STATE", False); |
1639 wmatom[WMState] = XInternAtom(dpy, "WM_STATE", False); |
|
1640 wmatom[WMTakeFocus] = XInternAtom(dpy, "WM_TAKE_FOCUS", False); |
|
1641 netatom[NetActiveWindow] = XInternAtom(dpy, "_NET_ACTIVE_WINDOW", False); |
1537 netatom[NetSupported] = XInternAtom(dpy, "_NET_SUPPORTED", False); |
1642 netatom[NetSupported] = XInternAtom(dpy, "_NET_SUPPORTED", False); |
1538 netatom[NetWMName] = XInternAtom(dpy, "_NET_WM_NAME", False); |
1643 netatom[NetWMName] = XInternAtom(dpy, "_NET_WM_NAME", False); |
1539 netatom[NetWMState] = XInternAtom(dpy, "_NET_WM_STATE", False); |
1644 netatom[NetWMState] = XInternAtom(dpy, "_NET_WM_STATE", False); |
1540 netatom[NetWMFullscreen] = XInternAtom(dpy, "_NET_WM_STATE_FULLSCREEN", False); |
1645 netatom[NetWMFullscreen] = XInternAtom(dpy, "_NET_WM_STATE_FULLSCREEN", False); |
|
1646 netatom[NetWMWindowType] = XInternAtom(dpy, "_NET_WM_WINDOW_TYPE", False); |
|
1647 netatom[NetWMWindowTypeDialog] = XInternAtom(dpy, "_NET_WM_WINDOW_TYPE_DIALOG", False); |
1541 /* init cursors */ |
1648 /* init cursors */ |
1542 cursor[CurNormal] = XCreateFontCursor(dpy, XC_left_ptr); |
1649 cursor[CurNormal] = XCreateFontCursor(dpy, XC_left_ptr); |
1543 cursor[CurResize] = XCreateFontCursor(dpy, XC_sizing); |
1650 cursor[CurResize] = XCreateFontCursor(dpy, XC_sizing); |
1544 cursor[CurMove] = XCreateFontCursor(dpy, XC_fleur); |
1651 cursor[CurMove] = XCreateFontCursor(dpy, XC_fleur); |
1545 /* init appearance */ |
1652 /* init appearance */ |
1560 /* EWMH support per view */ |
1667 /* EWMH support per view */ |
1561 XChangeProperty(dpy, root, netatom[NetSupported], XA_ATOM, 32, |
1668 XChangeProperty(dpy, root, netatom[NetSupported], XA_ATOM, 32, |
1562 PropModeReplace, (unsigned char *) netatom, NetLast); |
1669 PropModeReplace, (unsigned char *) netatom, NetLast); |
1563 /* select for events */ |
1670 /* select for events */ |
1564 wa.cursor = cursor[CurNormal]; |
1671 wa.cursor = cursor[CurNormal]; |
1565 wa.event_mask = SubstructureRedirectMask|SubstructureNotifyMask|ButtonPressMask |
1672 wa.event_mask = SubstructureRedirectMask|SubstructureNotifyMask|ButtonPressMask|PointerMotionMask |
1566 |EnterWindowMask|LeaveWindowMask|StructureNotifyMask |
1673 |EnterWindowMask|LeaveWindowMask|StructureNotifyMask|PropertyChangeMask; |
1567 |PropertyChangeMask; |
|
1568 XChangeWindowAttributes(dpy, root, CWEventMask|CWCursor, &wa); |
1674 XChangeWindowAttributes(dpy, root, CWEventMask|CWCursor, &wa); |
1569 XSelectInput(dpy, root, wa.event_mask); |
1675 XSelectInput(dpy, root, wa.event_mask); |
1570 grabkeys(); |
1676 grabkeys(); |
1571 } |
1677 } |
1572 |
1678 |
1574 showhide(Client *c) { |
1680 showhide(Client *c) { |
1575 if(!c) |
1681 if(!c) |
1576 return; |
1682 return; |
1577 if(ISVISIBLE(c)) { /* show clients top down */ |
1683 if(ISVISIBLE(c)) { /* show clients top down */ |
1578 XMoveWindow(dpy, c->win, c->x, c->y); |
1684 XMoveWindow(dpy, c->win, c->x, c->y); |
1579 if(!c->mon->lt[c->mon->sellt]->arrange || c->isfloating) |
1685 if((!c->mon->lt[c->mon->sellt]->arrange || c->isfloating) && !c->isfullscreen) |
1580 resize(c, c->x, c->y, c->w, c->h, False); |
1686 resize(c, c->x, c->y, c->w, c->h, False); |
1581 showhide(c->snext); |
1687 showhide(c->snext); |
1582 } |
1688 } |
1583 else { /* hide clients bottom up */ |
1689 else { /* hide clients bottom up */ |
1584 showhide(c->snext); |
1690 showhide(c->snext); |
1585 XMoveWindow(dpy, c->win, c->x + 2 * sw, c->y); |
1691 XMoveWindow(dpy, c->win, WIDTH(c) * -2, c->y); |
1586 } |
1692 } |
1587 } |
1693 } |
1588 |
1694 |
1589 void |
1695 void |
1590 sigchld(int unused) { |
1696 sigchld(int unused) { |
1636 return r.width / PANGO_SCALE; |
1743 return r.width / PANGO_SCALE; |
1637 } |
1744 } |
1638 |
1745 |
1639 void |
1746 void |
1640 tile(Monitor *m) { |
1747 tile(Monitor *m) { |
1641 int x, y, h, w, mw; |
1748 unsigned int i, n, h, mw, my, ty; |
1642 unsigned int i, n; |
|
1643 Client *c; |
1749 Client *c; |
1644 |
1750 |
1645 for(n = 0, c = nexttiled(m->clients); c; c = nexttiled(c->next), n++); |
1751 for(n = 0, c = nexttiled(m->clients); c; c = nexttiled(c->next), n++); |
1646 if(n == 0) |
1752 if(n == 0) |
1647 return; |
1753 return; |
1648 /* master */ |
1754 |
1649 c = nexttiled(m->clients); |
1755 if(n > m->nmaster) |
1650 mw = m->mfact * m->ww; |
1756 mw = m->nmaster ? m->ww * m->mfact : 0; |
1651 resize(c, m->wx, m->wy, (n == 1 ? m->ww : mw) - 2 * c->bw, m->wh - 2 * c->bw, False); |
1757 else |
1652 if(--n == 0) |
1758 mw = m->ww; |
1653 return; |
1759 for(i = my = ty = 0, c = nexttiled(m->clients); c; c = nexttiled(c->next), i++) |
1654 /* tile stack */ |
1760 if(i < m->nmaster) { |
1655 x = (m->wx + mw > c->x + c->w) ? c->x + c->w + 2 * c->bw : m->wx + mw; |
1761 h = (m->wh - my) / (MIN(n, m->nmaster) - i); |
1656 y = m->wy; |
1762 resize(c, m->wx, m->wy + my, mw - (2*c->bw), h - (2*c->bw), False); |
1657 w = (m->wx + mw > c->x + c->w) ? m->wx + m->ww - x : m->ww - mw; |
1763 my += HEIGHT(c); |
1658 h = m->wh / n; |
1764 } |
1659 if(h < bh) |
1765 else { |
1660 h = m->wh; |
1766 h = (m->wh - ty) / (n - i); |
1661 for(i = 0, c = nexttiled(c->next); c; c = nexttiled(c->next), i++) { |
1767 resize(c, m->wx + mw, m->wy + ty, m->ww - mw - (2*c->bw), h - (2*c->bw), False); |
1662 resize(c, x, y, w - 2 * c->bw, /* remainder */ ((i + 1 == n) |
1768 ty += HEIGHT(c); |
1663 ? m->wy + m->wh - y - 2 * c->bw : h - 2 * c->bw), False); |
1769 } |
1664 if(h != m->wh) |
|
1665 y = c->y + HEIGHT(c); |
|
1666 } |
|
1667 } |
1770 } |
1668 |
1771 |
1669 void |
1772 void |
1670 togglebar(const Arg *arg) { |
1773 togglebar(const Arg *arg) { |
1671 selmon->showbar = selmon->showbars[selmon->curtag] = !selmon->showbar; |
1774 selmon->showbar = selmon->showbars[selmon->curtag] = !selmon->showbar; |
1760 void |
1865 void |
1761 unmapnotify(XEvent *e) { |
1866 unmapnotify(XEvent *e) { |
1762 Client *c; |
1867 Client *c; |
1763 XUnmapEvent *ev = &e->xunmap; |
1868 XUnmapEvent *ev = &e->xunmap; |
1764 |
1869 |
1765 if((c = wintoclient(ev->window))) |
1870 if((c = wintoclient(ev->window))) { |
1766 unmanage(c, False); |
1871 if(ev->send_event) |
|
1872 setclientstate(c, WithdrawnState); |
|
1873 else |
|
1874 unmanage(c, False); |
|
1875 } |
1767 } |
1876 } |
1768 |
1877 |
1769 void |
1878 void |
1770 updatebars(void) { |
1879 updatebars(void) { |
1771 Monitor *m; |
1880 Monitor *m; |
1772 XSetWindowAttributes wa; |
1881 XSetWindowAttributes wa = { |
1773 |
1882 .override_redirect = True, |
1774 wa.override_redirect = True; |
1883 .background_pixmap = ParentRelative, |
1775 wa.background_pixmap = ParentRelative; |
1884 .event_mask = ButtonPressMask|ExposureMask |
1776 wa.event_mask = ButtonPressMask|ExposureMask; |
1885 }; |
1777 for(m = mons; m; m = m->next) { |
1886 for(m = mons; m; m = m->next) { |
1778 m->barwin = XCreateWindow(dpy, root, m->wx, m->by, m->ww, bh, 0, DefaultDepth(dpy, screen), |
1887 m->barwin = XCreateWindow(dpy, root, m->wx, m->by, m->ww, bh, 0, DefaultDepth(dpy, screen), |
1779 CopyFromParent, DefaultVisual(dpy, screen), |
1888 CopyFromParent, DefaultVisual(dpy, screen), |
1780 CWOverrideRedirect|CWBackPixmap|CWEventMask, &wa); |
1889 CWOverrideRedirect|CWBackPixmap|CWEventMask, &wa); |
1781 XDefineCursor(dpy, m->barwin, cursor[CurNormal]); |
1890 XDefineCursor(dpy, m->barwin, cursor[CurNormal]); |
1957 strcpy(stext, "dwm-"VERSION); |
2066 strcpy(stext, "dwm-"VERSION); |
1958 drawbar(selmon); |
2067 drawbar(selmon); |
1959 } |
2068 } |
1960 |
2069 |
1961 void |
2070 void |
|
2071 updatewindowtype(Client *c) { |
|
2072 Atom state = getatomprop(c, netatom[NetWMState]); |
|
2073 Atom wtype = getatomprop(c, netatom[NetWMWindowType]); |
|
2074 |
|
2075 if(state == netatom[NetWMFullscreen]) |
|
2076 setfullscreen(c, True); |
|
2077 |
|
2078 if(wtype == netatom[NetWMWindowTypeDialog]) |
|
2079 c->isfloating = True; |
|
2080 } |
|
2081 |
|
2082 void |
1962 updatewmhints(Client *c) { |
2083 updatewmhints(Client *c) { |
1963 XWMHints *wmh; |
2084 XWMHints *wmh; |
1964 |
2085 |
1965 if((wmh = XGetWMHints(dpy, c->win))) { |
2086 if((wmh = XGetWMHints(dpy, c->win))) { |
1966 if(c == selmon->sel && wmh->flags & XUrgencyHint) { |
2087 if(c == selmon->sel && wmh->flags & XUrgencyHint) { |
1967 wmh->flags &= ~XUrgencyHint; |
2088 wmh->flags &= ~XUrgencyHint; |
1968 XSetWMHints(dpy, c->win, wmh); |
2089 XSetWMHints(dpy, c->win, wmh); |
1969 } |
2090 } |
1970 else |
2091 else |
1971 c->isurgent = (wmh->flags & XUrgencyHint) ? True : False; |
2092 c->isurgent = (wmh->flags & XUrgencyHint) ? True : False; |
|
2093 if(wmh->flags & InputHint) |
|
2094 c->neverfocus = !wmh->input; |
|
2095 else |
|
2096 c->neverfocus = False; |
1972 XFree(wmh); |
2097 XFree(wmh); |
1973 } |
2098 } |
1974 } |
2099 } |
1975 |
2100 |
1976 void |
2101 void |
2065 void |
2191 void |
2066 zoom(const Arg *arg) { |
2192 zoom(const Arg *arg) { |
2067 Client *c = selmon->sel; |
2193 Client *c = selmon->sel; |
2068 |
2194 |
2069 if(!selmon->lt[selmon->sellt]->arrange |
2195 if(!selmon->lt[selmon->sellt]->arrange |
2070 || selmon->lt[selmon->sellt]->arrange == monocle |
|
2071 || (selmon->sel && selmon->sel->isfloating)) |
2196 || (selmon->sel && selmon->sel->isfloating)) |
2072 return; |
2197 return; |
2073 if(c == nexttiled(selmon->clients)) |
2198 if(c == nexttiled(selmon->clients)) |
2074 if(!c || !(c = nexttiled(c->next))) |
2199 if(!c || !(c = nexttiled(c->next))) |
2075 return; |
2200 return; |
2076 detach(c); |
2201 pop(c); |
2077 attach(c); |
|
2078 focus(c); |
|
2079 arrange(c->mon); |
|
2080 } |
2202 } |
2081 |
2203 |
2082 int |
2204 int |
2083 main(int argc, char *argv[]) { |
2205 main(int argc, char *argv[]) { |
2084 if(argc == 2 && !strcmp("-v", argv[1])) |
2206 if(argc == 2 && !strcmp("-v", argv[1])) |
2085 die("dwm-"VERSION", © 2006-2010 dwm engineers, see LICENSE for details\n"); |
2207 die("dwm-"VERSION", © 2006-2011 dwm engineers, see LICENSE for details\n"); |
2086 else if(argc != 1) |
2208 else if(argc != 1) |
2087 die("usage: dwm [-v]\n"); |
2209 die("usage: dwm [-v]\n"); |
2088 if(!setlocale(LC_CTYPE, "") || !XSupportsLocale()) |
2210 if(!setlocale(LC_CTYPE, "") || !XSupportsLocale()) |
2089 fputs("warning: no locale support\n", stderr); |
2211 fputs("warning: no locale support\n", stderr); |
2090 if(!(dpy = XOpenDisplay(NULL))) |
2212 if(!(dpy = XOpenDisplay(NULL))) |