58 enum { ColBorder, ColFG, ColBG, ColLast }; /* color */ |
58 enum { ColBorder, ColFG, ColBG, ColLast }; /* color */ |
59 enum { NetSupported, NetWMName, NetLast }; /* EWMH atoms */ |
59 enum { NetSupported, NetWMName, NetLast }; /* EWMH atoms */ |
60 enum { WMProtocols, WMDelete, WMName, WMState, WMLast };/* default atoms */ |
60 enum { WMProtocols, WMDelete, WMName, WMState, WMLast };/* default atoms */ |
61 |
61 |
62 /* typedefs */ |
62 /* typedefs */ |
63 typedef struct View View; |
|
64 typedef struct Client Client; |
63 typedef struct Client Client; |
65 struct Client { |
64 struct Client { |
66 char name[256]; |
65 char name[256]; |
67 int x, y, w, h; |
66 int x, y, w, h; |
68 int basew, baseh, incw, inch, maxw, maxh, minw, minh; |
67 int basew, baseh, incw, inch, maxw, maxh, minw, minh; |
128 void checkotherwm(void); |
119 void checkotherwm(void); |
129 void cleanup(void); |
120 void cleanup(void); |
130 void configure(Client *c); |
121 void configure(Client *c); |
131 void configurenotify(XEvent *e); |
122 void configurenotify(XEvent *e); |
132 void configurerequest(XEvent *e); |
123 void configurerequest(XEvent *e); |
133 Bool conflicts(Client *c, unsigned int tidx); |
|
134 void destroynotify(XEvent *e); |
124 void destroynotify(XEvent *e); |
135 void detach(Client *c); |
125 void detach(Client *c); |
136 void detachstack(Client *c); |
126 void detachstack(Client *c); |
137 void drawbar(View *v); |
127 void drawbar(void); |
138 void drawsquare(Bool filled, Bool empty, Bool invert, unsigned long col[ColLast]); |
128 void drawsquare(Bool filled, Bool empty, Bool invert, unsigned long col[ColLast]); |
139 void drawtext(const char *text, unsigned long col[ColLast], Bool invert); |
129 void drawtext(const char *text, unsigned long col[ColLast], Bool invert); |
140 void *emallocz(unsigned int size); |
130 void *emallocz(unsigned int size); |
141 void enternotify(XEvent *e); |
131 void enternotify(XEvent *e); |
142 void eprint(const char *errstr, ...); |
132 void eprint(const char *errstr, ...); |
143 void expose(XEvent *e); |
133 void expose(XEvent *e); |
144 unsigned int firstag(View *v); |
134 void floating(void); /* default floating layout */ |
145 void floating(View *v); /* default floating layout */ |
|
146 void focus(Client *c); |
135 void focus(Client *c); |
147 void focusin(XEvent *e); |
136 void focusin(XEvent *e); |
148 void focusnext(const char *arg); |
137 void focusnext(const char *arg); |
149 void focusprev(const char *arg); |
138 void focusprev(const char *arg); |
150 Client *getclient(Window w); |
139 Client *getclient(Window w); |
151 unsigned long getcolor(const char *colstr); |
140 unsigned long getcolor(const char *colstr); |
152 View *getview(Client *c); |
|
153 View *getviewbar(Window barwin); |
|
154 long getstate(Window w); |
141 long getstate(Window w); |
155 Bool gettextprop(Window w, Atom atom, char *text, unsigned int size); |
142 Bool gettextprop(Window w, Atom atom, char *text, unsigned int size); |
156 void grabbuttons(Client *c, Bool focused); |
143 void grabbuttons(Client *c, Bool focused); |
157 void grabkeys(void); |
144 void grabkeys(void); |
158 unsigned int idxoftag(const char *t); |
145 unsigned int idxoftag(const char *t); |
164 void keypress(XEvent *e); |
151 void keypress(XEvent *e); |
165 void killclient(const char *arg); |
152 void killclient(const char *arg); |
166 void manage(Window w, XWindowAttributes *wa); |
153 void manage(Window w, XWindowAttributes *wa); |
167 void mappingnotify(XEvent *e); |
154 void mappingnotify(XEvent *e); |
168 void maprequest(XEvent *e); |
155 void maprequest(XEvent *e); |
169 View *viewat(void); |
|
170 void movemouse(Client *c); |
156 void movemouse(Client *c); |
171 Client *nexttiled(Client *c, View *v); |
157 Client *nexttiled(Client *c); |
172 void propertynotify(XEvent *e); |
158 void propertynotify(XEvent *e); |
173 void quit(const char *arg); |
159 void quit(const char *arg); |
174 void reapply(const char *arg); |
160 void reapply(const char *arg); |
175 void resize(Client *c, int x, int y, int w, int h, Bool sizehints); |
161 void resize(Client *c, int x, int y, int w, int h, Bool sizehints); |
176 void resizemouse(Client *c); |
162 void resizemouse(Client *c); |
177 void restack(View *v); |
163 void restack(void); |
178 void run(void); |
164 void run(void); |
179 void scan(void); |
165 void scan(void); |
180 void setclientstate(Client *c, long state); |
166 void setclientstate(Client *c, long state); |
181 void setlayout(const char *arg); |
167 void setlayout(const char *arg); |
182 void setmwfact(const char *arg); |
168 void setmwfact(const char *arg); |
183 void setup(void); |
169 void setup(void); |
184 void spawn(const char *arg); |
170 void spawn(const char *arg); |
185 void tag(const char *arg); |
171 void tag(const char *arg); |
186 unsigned int textnw(const char *text, unsigned int len); |
172 unsigned int textnw(const char *text, unsigned int len); |
187 unsigned int textw(const char *text); |
173 unsigned int textw(const char *text); |
188 void tile(View *v); |
174 void tile(void); |
189 void togglebar(const char *arg); |
175 void togglebar(const char *arg); |
190 void togglefloating(const char *arg); |
176 void togglefloating(const char *arg); |
191 void toggletag(const char *arg); |
177 void toggletag(const char *arg); |
192 void toggleview(const char *arg); |
178 void toggleview(const char *arg); |
193 void unban(Client *c); |
179 void unban(Client *c); |
194 void unmanage(Client *c); |
180 void unmanage(Client *c); |
195 void unmapnotify(XEvent *e); |
181 void unmapnotify(XEvent *e); |
196 void updatebarpos(View *v); |
182 void updatebarpos(void); |
197 void updatesizehints(Client *c); |
183 void updatesizehints(Client *c); |
198 void updatetitle(Client *c); |
184 void updatetitle(Client *c); |
199 void updatewmhints(Client *c); |
185 void updatewmhints(Client *c); |
200 void view(const char *arg); |
186 void view(const char *arg); |
201 void viewprevtag(const char *arg); /* views previous selected tags */ |
187 void viewprevtag(const char *arg); /* views previous selected tags */ |
205 void zoom(const char *arg); |
191 void zoom(const char *arg); |
206 void selectview(const char *arg); |
192 void selectview(const char *arg); |
207 |
193 |
208 /* variables */ |
194 /* variables */ |
209 char stext[256], buf[256]; |
195 char stext[256], buf[256]; |
210 int nviews = 1; |
196 double mwfact; |
211 int screen; |
197 int screen, sx, sy, sw, sh, wax, way, waw, wah, xscreens; |
212 int (*xerrorxlib)(Display *, XErrorEvent *); |
198 int (*xerrorxlib)(Display *, XErrorEvent *); |
213 unsigned int bh, bpos; |
199 unsigned int bh, bpos; |
214 unsigned int blw = 0; |
200 unsigned int blw = 0; |
215 unsigned int numlockmask = 0; |
201 unsigned int numlockmask = 0; |
216 void (*handler[LASTEvent]) (XEvent *) = { |
202 void (*handler[LASTEvent]) (XEvent *) = { |
436 } |
419 } |
437 |
420 |
438 void |
421 void |
439 configurenotify(XEvent *e) { |
422 configurenotify(XEvent *e) { |
440 XConfigureEvent *ev = &e->xconfigure; |
423 XConfigureEvent *ev = &e->xconfigure; |
441 View *v = selview; |
424 |
442 |
425 if(ev->window == root && (ev->width != sw || ev->height != sh)) { |
443 if(ev->window == root && (ev->width != v->w || ev->height != v->h)) { |
426 /* TODO -- use Xinerama dimensions here ? */ |
444 /* TODO -- update Xinerama dimensions here */ |
427 sw = ev->width; |
445 v->w = ev->width; |
428 sh = ev->height; |
446 v->h = ev->height; |
|
447 XFreePixmap(dpy, dc.drawable); |
429 XFreePixmap(dpy, dc.drawable); |
448 dc.drawable = XCreatePixmap(dpy, root, DisplayWidth(root, screen), bh, DefaultDepth(dpy, screen)); |
430 dc.drawable = XCreatePixmap(dpy, root, DisplayWidth(root, screen), bh, DefaultDepth(dpy, screen)); |
449 XResizeWindow(dpy, v->barwin, v->w, bh); |
431 XResizeWindow(dpy, barwin, sw, bh); |
450 updatebarpos(selview); |
432 updatebarpos(); |
451 arrange(); |
433 arrange(); |
452 } |
434 } |
453 } |
435 } |
454 |
436 |
455 void |
437 void |
456 configurerequest(XEvent *e) { |
438 configurerequest(XEvent *e) { |
457 Client *c; |
439 Client *c; |
458 XConfigureRequestEvent *ev = &e->xconfigurerequest; |
440 XConfigureRequestEvent *ev = &e->xconfigurerequest; |
459 XWindowChanges wc; |
441 XWindowChanges wc; |
460 |
442 |
|
443 /* TODO -- consider Xinerama if necessary when centering */ |
461 if((c = getclient(ev->window))) { |
444 if((c = getclient(ev->window))) { |
462 View *v = getview(c); |
|
463 if(ev->value_mask & CWBorderWidth) |
445 if(ev->value_mask & CWBorderWidth) |
464 c->border = ev->border_width; |
446 c->border = ev->border_width; |
465 if(c->isfixed || c->isfloating || (floating == v->layout->arrange)) { |
447 if(c->isfixed || c->isfloating || (floating == lt->arrange)) { |
466 if(ev->value_mask & CWX) |
448 if(ev->value_mask & CWX) |
467 c->x = v->x + ev->x; |
449 c->x = sx + ev->x; |
468 if(ev->value_mask & CWY) |
450 if(ev->value_mask & CWY) |
469 c->y = v->y + ev->y; |
451 c->y = sy + ev->y; |
470 if(ev->value_mask & CWWidth) |
452 if(ev->value_mask & CWWidth) |
471 c->w = ev->width; |
453 c->w = ev->width; |
472 if(ev->value_mask & CWHeight) |
454 if(ev->value_mask & CWHeight) |
473 c->h = ev->height; |
455 c->h = ev->height; |
474 if((c->x - v->x + c->w) > v->w && c->isfloating) |
456 if((c->x - sx + c->w) > sw && c->isfloating) |
475 c->x = v->x + (v->w / 2 - c->w / 2); /* center in x direction */ |
457 c->x = sx + (sw / 2 - c->w / 2); /* center in x direction */ |
476 if((c->y - v->y + c->h) > v->h && c->isfloating) |
458 if((c->y - sy + c->h) > sh && c->isfloating) |
477 c->y = v->y + (v->h / 2 - c->h / 2); /* center in y direction */ |
459 c->y = sy + (sh / 2 - c->h / 2); /* center in y direction */ |
478 if((ev->value_mask & (CWX|CWY)) |
460 if((ev->value_mask & (CWX|CWY)) |
479 && !(ev->value_mask & (CWWidth|CWHeight))) |
461 && !(ev->value_mask & (CWWidth|CWHeight))) |
480 configure(c); |
462 configure(c); |
481 if(isvisible(c)) |
463 if(isvisible(c)) |
482 XMoveResizeWindow(dpy, c->win, c->x, c->y, c->w, c->h); |
464 XMoveResizeWindow(dpy, c->win, c->x, c->y, c->w, c->h); |
555 drawsquare(c && c->tags[i], isoccupied(i), isurgent(i), dc.norm); |
535 drawsquare(c && c->tags[i], isoccupied(i), isurgent(i), dc.norm); |
556 } |
536 } |
557 dc.x += dc.w; |
537 dc.x += dc.w; |
558 } |
538 } |
559 dc.w = blw; |
539 dc.w = blw; |
560 drawtext(v->layout->symbol, dc.norm, False); |
540 drawtext(lt->symbol, dc.norm, False); |
561 x = dc.x + dc.w; |
541 x = dc.x + dc.w; |
562 if(v == selview) { |
542 dc.w = textw(stext); |
563 dc.w = textw(stext); |
543 dc.x = sw - dc.w; |
564 dc.x = v->w - dc.w; |
544 if(dc.x < x) { |
565 if(dc.x < x) { |
545 dc.x = x; |
566 dc.x = x; |
546 dc.w = sw - x; |
567 dc.w = v->w - x; |
547 } |
568 } |
548 drawtext(stext, dc.norm, False); |
569 drawtext(stext, dc.norm, False); |
|
570 } |
|
571 else |
|
572 dc.x = v->w; |
|
573 if((dc.w = dc.x - x) > bh) { |
549 if((dc.w = dc.x - x) > bh) { |
574 dc.x = x; |
550 dc.x = x; |
575 if(c) { |
551 if(c) { |
576 drawtext(c->name, dc.sel, False); |
552 drawtext(c->name, dc.sel, False); |
577 drawsquare(False, c->isfloating, False, dc.sel); |
553 drawsquare(False, c->isfloating, False, dc.sel); |
578 } |
554 } |
579 else |
555 else |
580 drawtext(NULL, dc.norm, False); |
556 drawtext(NULL, dc.norm, False); |
581 } |
557 } |
582 XCopyArea(dpy, dc.drawable, v->barwin, dc.gc, 0, 0, v->w, bh, 0, 0); |
558 XCopyArea(dpy, dc.drawable, barwin, dc.gc, 0, 0, sw, bh, 0, 0); |
583 XSync(dpy, False); |
559 XSync(dpy, False); |
584 } |
560 } |
585 |
561 |
586 void |
562 void |
587 drawsquare(Bool filled, Bool empty, Bool invert, unsigned long col[ColLast]) { |
563 drawsquare(Bool filled, Bool empty, Bool invert, unsigned long col[ColLast]) { |
675 exit(EXIT_FAILURE); |
651 exit(EXIT_FAILURE); |
676 } |
652 } |
677 |
653 |
678 void |
654 void |
679 expose(XEvent *e) { |
655 expose(XEvent *e) { |
680 View *v; |
|
681 XExposeEvent *ev = &e->xexpose; |
656 XExposeEvent *ev = &e->xexpose; |
682 |
657 |
683 if(ev->count == 0 && ((v = getviewbar(ev->window)))) |
658 if(ev->count == 0 && (ev->window == barwin)) |
684 drawbar(v); |
659 drawbar(); |
685 } |
660 } |
686 |
661 |
687 unsigned int |
662 void |
688 firstag(View *v) { |
663 floating(void) { /* default floating layout */ |
689 unsigned int i; |
|
690 |
|
691 for(i = 0; i < LENGTH(tags); i++) |
|
692 if(vtags[i] == v->id) |
|
693 return i; |
|
694 return 0; /* safe fallback */ |
|
695 } |
|
696 |
|
697 void |
|
698 floating(View *v) { /* default floating layout */ |
|
699 Client *c; |
664 Client *c; |
700 |
665 |
701 domwfact = dozoom = False; |
666 domwfact = dozoom = False; |
702 for(c = clients; c; c = c->next) |
667 for(c = clients; c; c = c->next) |
703 if(isvisible(c)) |
668 if(isvisible(c)) |
704 resize(c, c->x, c->y, c->w, c->h, True); |
669 resize(c, c->x, c->y, c->w, c->h, True); |
705 } |
670 } |
706 |
671 |
707 void |
672 void |
708 focus(Client *c) { |
673 focus(Client *c) { |
709 View *v = selview; |
|
710 |
|
711 if(c) |
|
712 selview = getview(c); |
|
713 if(selview != v) |
|
714 drawbar(v); |
|
715 if(!c || (c && !isvisible(c))) |
674 if(!c || (c && !isvisible(c))) |
716 /* TODO: isvisible might take getview(c) as constraint? */ |
675 for(c = stack; c && !isvisible(c); c = c->snext); |
717 for(c = stack; c && (!isvisible(c) || getview(c) != selview); c = c->snext); |
|
718 if(sel && sel != c) { |
676 if(sel && sel != c) { |
719 grabbuttons(sel, False); |
677 grabbuttons(sel, False); |
720 XSetWindowBorder(dpy, sel->win, dc.norm[ColBorder]); |
678 XSetWindowBorder(dpy, sel->win, dc.norm[ColBorder]); |
721 } |
679 } |
722 if(c) { |
680 if(c) { |
1055 } |
992 } |
1056 |
993 |
1057 void |
994 void |
1058 manage(Window w, XWindowAttributes *wa) { |
995 manage(Window w, XWindowAttributes *wa) { |
1059 Client *c, *t = NULL; |
996 Client *c, *t = NULL; |
1060 View *v; |
|
1061 Status rettrans; |
997 Status rettrans; |
1062 Window trans; |
998 Window trans; |
1063 XWindowChanges wc; |
999 XWindowChanges wc; |
1064 |
1000 |
1065 c = emallocz(sizeof(Client)); |
1001 c = emallocz(sizeof(Client)); |
1066 c->tags = emallocz(TAGSZ); |
1002 c->tags = emallocz(TAGSZ); |
1067 c->win = w; |
1003 c->win = w; |
1068 |
1004 |
1069 applyrules(c); |
1005 applyrules(c); |
1070 |
1006 |
1071 v = getview(c); |
1007 c->x = wa->x + sx; |
1072 |
1008 c->y = wa->y + sy; |
1073 c->x = wa->x + v->x; |
|
1074 c->y = wa->y + v->y; |
|
1075 c->w = wa->width; |
1009 c->w = wa->width; |
1076 c->h = wa->height; |
1010 c->h = wa->height; |
1077 c->oldborder = wa->border_width; |
1011 c->oldborder = wa->border_width; |
1078 |
1012 |
1079 if(c->w == v->w && c->h == v->h) { |
1013 if(c->w == sw && c->h == sh) { |
1080 c->x = v->x; |
1014 c->x = sx; |
1081 c->y = v->y; |
1015 c->y = sy; |
1082 c->border = wa->border_width; |
1016 c->border = wa->border_width; |
1083 } |
1017 } |
1084 else { |
1018 else { |
1085 if(c->x + c->w + 2 * c->border > v->wax + v->waw) |
1019 if(c->x + c->w + 2 * c->border > wax + waw) |
1086 c->x = v->wax + v->waw - c->w - 2 * c->border; |
1020 c->x = wax + waw - c->w - 2 * c->border; |
1087 if(c->y + c->h + 2 * c->border > v->way + v->wah) |
1021 if(c->y + c->h + 2 * c->border > way + wah) |
1088 c->y = v->way + v->wah - c->h - 2 * c->border; |
1022 c->y = way + wah - c->h - 2 * c->border; |
1089 if(c->x < v->wax) |
1023 if(c->x < wax) |
1090 c->x = v->wax; |
1024 c->x = wax; |
1091 if(c->y < v->way) |
1025 if(c->y < way) |
1092 c->y = v->way; |
1026 c->y = way; |
1093 c->border = BORDERPX; |
1027 c->border = BORDERPX; |
1094 } |
1028 } |
1095 wc.border_width = c->border; |
1029 wc.border_width = c->border; |
1096 XConfigureWindow(dpy, w, CWBorderWidth, &wc); |
1030 XConfigureWindow(dpy, w, CWBorderWidth, &wc); |
1097 XSetWindowBorder(dpy, w, dc.norm[ColBorder]); |
1031 XSetWindowBorder(dpy, w, dc.norm[ColBorder]); |
1139 |
1073 |
1140 void |
1074 void |
1141 movemouse(Client *c) { |
1075 movemouse(Client *c) { |
1142 int x1, y1, ocx, ocy, di, nx, ny; |
1076 int x1, y1, ocx, ocy, di, nx, ny; |
1143 unsigned int dui; |
1077 unsigned int dui; |
1144 View *v; |
|
1145 Window dummy; |
1078 Window dummy; |
1146 XEvent ev; |
1079 XEvent ev; |
1147 |
1080 |
1148 ocx = nx = c->x; |
1081 ocx = nx = c->x; |
1149 ocy = ny = c->y; |
1082 ocy = ny = c->y; |
1150 v = getview(c); |
|
1151 if(XGrabPointer(dpy, root, False, MOUSEMASK, GrabModeAsync, GrabModeAsync, |
1083 if(XGrabPointer(dpy, root, False, MOUSEMASK, GrabModeAsync, GrabModeAsync, |
1152 None, cursor[CurMove], CurrentTime) != GrabSuccess) |
1084 None, cursor[CurMove], CurrentTime) != GrabSuccess) |
1153 return; |
1085 return; |
1154 XQueryPointer(dpy, root, &dummy, &dummy, &x1, &y1, &di, &di, &dui); |
1086 XQueryPointer(dpy, root, &dummy, &dummy, &x1, &y1, &di, &di, &dui); |
1155 for(;;) { |
1087 for(;;) { |
1165 break; |
1097 break; |
1166 case MotionNotify: |
1098 case MotionNotify: |
1167 XSync(dpy, False); |
1099 XSync(dpy, False); |
1168 nx = ocx + (ev.xmotion.x - x1); |
1100 nx = ocx + (ev.xmotion.x - x1); |
1169 ny = ocy + (ev.xmotion.y - y1); |
1101 ny = ocy + (ev.xmotion.y - y1); |
1170 if(abs(v->wax - nx) < SNAP) |
1102 if(abs(wax - nx) < SNAP) |
1171 nx = v->wax; |
1103 nx = wax; |
1172 else if(abs((v->wax + v->waw) - (nx + c->w + 2 * c->border)) < SNAP) |
1104 else if(abs((wax + waw) - (nx + c->w + 2 * c->border)) < SNAP) |
1173 nx = v->wax + v->waw - c->w - 2 * c->border; |
1105 nx = wax + waw - c->w - 2 * c->border; |
1174 if(abs(v->way - ny) < SNAP) |
1106 if(abs(way - ny) < SNAP) |
1175 ny = v->way; |
1107 ny = way; |
1176 else if(abs((v->way + v->wah) - (ny + c->h + 2 * c->border)) < SNAP) |
1108 else if(abs((way + wah) - (ny + c->h + 2 * c->border)) < SNAP) |
1177 ny = v->way + v->wah - c->h - 2 * c->border; |
1109 ny = way + wah - c->h - 2 * c->border; |
1178 if(!c->isfloating && (v->layout->arrange != floating) && (abs(nx - c->x) > SNAP || abs(ny - c->y) > SNAP)) |
1110 if(!c->isfloating && (lt->arrange != floating) && (abs(nx - c->x) > SNAP || abs(ny - c->y) > SNAP)) |
1179 togglefloating(NULL); |
1111 togglefloating(NULL); |
1180 if((v->layout->arrange == floating) || c->isfloating) |
1112 if((lt->arrange == floating) || c->isfloating) |
1181 resize(c, nx, ny, c->w, c->h, False); |
1113 resize(c, nx, ny, c->w, c->h, False); |
1182 break; |
1114 break; |
1183 } |
1115 } |
1184 } |
1116 } |
1185 } |
1117 } |
1186 |
1118 |
1187 Client * |
1119 Client * |
1188 nexttiled(Client *c, View *v) { |
1120 nexttiled(Client *c) { |
1189 for(; c && (c->isfloating || getview(c) != v || !isvisible(c)); c = c->next); |
1121 for(; c && (c->isfloating || !isvisible(c)); c = c->next); |
1190 return c; |
1122 return c; |
1191 } |
1123 } |
1192 |
1124 |
1193 void |
1125 void |
1194 propertynotify(XEvent *e) { |
1126 propertynotify(XEvent *e) { |
1308 |
1238 |
1309 void |
1239 void |
1310 resizemouse(Client *c) { |
1240 resizemouse(Client *c) { |
1311 int ocx, ocy; |
1241 int ocx, ocy; |
1312 int nw, nh; |
1242 int nw, nh; |
1313 View *v; |
|
1314 XEvent ev; |
1243 XEvent ev; |
1315 |
1244 |
1316 ocx = c->x; |
1245 ocx = c->x; |
1317 ocy = c->y; |
1246 ocy = c->y; |
1318 v = getview(c); |
|
1319 if(XGrabPointer(dpy, root, False, MOUSEMASK, GrabModeAsync, GrabModeAsync, |
1247 if(XGrabPointer(dpy, root, False, MOUSEMASK, GrabModeAsync, GrabModeAsync, |
1320 None, cursor[CurResize], CurrentTime) != GrabSuccess) |
1248 None, cursor[CurResize], CurrentTime) != GrabSuccess) |
1321 return; |
1249 return; |
1322 XWarpPointer(dpy, None, c->win, 0, 0, 0, 0, c->w + c->border - 1, c->h + c->border - 1); |
1250 XWarpPointer(dpy, None, c->win, 0, 0, 0, 0, c->w + c->border - 1, c->h + c->border - 1); |
1323 for(;;) { |
1251 for(;;) { |
1338 XSync(dpy, False); |
1266 XSync(dpy, False); |
1339 if((nw = ev.xmotion.x - ocx - 2 * c->border + 1) <= 0) |
1267 if((nw = ev.xmotion.x - ocx - 2 * c->border + 1) <= 0) |
1340 nw = 1; |
1268 nw = 1; |
1341 if((nh = ev.xmotion.y - ocy - 2 * c->border + 1) <= 0) |
1269 if((nh = ev.xmotion.y - ocy - 2 * c->border + 1) <= 0) |
1342 nh = 1; |
1270 nh = 1; |
1343 if(!c->isfloating && (v->layout->arrange != floating) && (abs(nw - c->w) > SNAP || abs(nh - c->h) > SNAP)) |
1271 if(!c->isfloating && (lt->arrange != floating) && (abs(nw - c->w) > SNAP || abs(nh - c->h) > SNAP)) |
1344 togglefloating(NULL); |
1272 togglefloating(NULL); |
1345 if((v->layout->arrange == floating) || c->isfloating) |
1273 if((lt->arrange == floating) || c->isfloating) |
1346 resize(c, c->x, c->y, nw, nh, True); |
1274 resize(c, c->x, c->y, nw, nh, True); |
1347 break; |
1275 break; |
1348 } |
1276 } |
1349 } |
1277 } |
1350 } |
1278 } |
1351 |
1279 |
1352 void |
1280 void |
1353 restack(View *v) { |
1281 restack(void) { |
1354 Client *c; |
1282 Client *c; |
1355 XEvent ev; |
1283 XEvent ev; |
1356 XWindowChanges wc; |
1284 XWindowChanges wc; |
1357 |
1285 |
1358 drawbar(v); |
1286 drawbar(); |
1359 if(!sel) |
1287 if(!sel) |
1360 return; |
1288 return; |
1361 if(sel->isfloating || (v->layout->arrange == floating)) |
1289 if(sel->isfloating || (lt->arrange == floating)) |
1362 XRaiseWindow(dpy, sel->win); |
1290 XRaiseWindow(dpy, sel->win); |
1363 if(v->layout->arrange != floating) { |
1291 if(lt->arrange != floating) { |
1364 wc.stack_mode = Below; |
1292 wc.stack_mode = Below; |
1365 wc.sibling = v->barwin; |
1293 wc.sibling = barwin; |
1366 if(!sel->isfloating) { |
1294 if(!sel->isfloating) { |
1367 XConfigureWindow(dpy, sel->win, CWSibling|CWStackMode, &wc); |
1295 XConfigureWindow(dpy, sel->win, CWSibling|CWStackMode, &wc); |
1368 wc.sibling = sel->win; |
1296 wc.sibling = sel->win; |
1369 } |
1297 } |
1370 for(c = nexttiled(clients, v); c; c = nexttiled(c->next, v)) { |
1298 for(c = nexttiled(clients); c; c = nexttiled(c->next)) { |
1371 if(c == sel) |
1299 if(c == sel) |
1372 continue; |
1300 continue; |
1373 XConfigureWindow(dpy, c->win, CWSibling|CWStackMode, &wc); |
1301 XConfigureWindow(dpy, c->win, CWSibling|CWStackMode, &wc); |
1374 wc.sibling = c->win; |
1302 wc.sibling = c->win; |
1375 } |
1303 } |
1474 } |
1402 } |
1475 |
1403 |
1476 void |
1404 void |
1477 setlayout(const char *arg) { |
1405 setlayout(const char *arg) { |
1478 unsigned int i; |
1406 unsigned int i; |
1479 View *v = selview; |
|
1480 |
1407 |
1481 if(!arg) { |
1408 if(!arg) { |
1482 v->layout++; |
1409 lt++; |
1483 if(v->layout == &layouts[LENGTH(layouts)]) |
1410 if(lt == &layouts[LENGTH(layouts)]) |
1484 v->layout = &layouts[0]; |
1411 lt = &layouts[0]; |
1485 } |
1412 } |
1486 else { |
1413 else { |
1487 for(i = 0; i < LENGTH(layouts); i++) |
1414 for(i = 0; i < LENGTH(layouts); i++) |
1488 if(!strcmp(arg, layouts[i].symbol)) |
1415 if(arg == layouts[i].symbol) |
1489 break; |
1416 break; |
1490 if(i == LENGTH(layouts)) |
1417 if(i == LENGTH(layouts)) |
1491 return; |
1418 return; |
1492 v->layout = &layouts[i]; |
1419 lt = &layouts[i]; |
1493 } |
1420 } |
1494 if(sel) |
1421 if(sel) |
1495 arrange(); |
1422 arrange(); |
1496 else |
1423 else |
1497 drawbar(selview); |
1424 drawbar(); |
1498 } |
1425 } |
1499 |
1426 |
1500 void |
1427 void |
1501 setmwfact(const char *arg) { |
1428 setmwfact(const char *arg) { |
1502 double delta; |
1429 double delta; |
1503 View *v = selview; |
|
1504 |
1430 |
1505 if(!domwfact) |
1431 if(!domwfact) |
1506 return; |
1432 return; |
1507 /* arg handling, manipulate mwfact */ |
1433 /* arg handling, manipulate mwfact */ |
1508 if(arg == NULL) |
1434 if(arg == NULL) |
1509 v->mwfact = MWFACT; |
1435 mwfact = MWFACT; |
1510 else if(sscanf(arg, "%lf", &delta) == 1) { |
1436 else if(sscanf(arg, "%lf", &delta) == 1) { |
1511 if(arg[0] == '+' || arg[0] == '-') |
1437 if(arg[0] == '+' || arg[0] == '-') |
1512 v->mwfact += delta; |
1438 mwfact += delta; |
1513 else |
1439 else |
1514 v->mwfact = delta; |
1440 mwfact = delta; |
1515 if(v->mwfact < 0.1) |
1441 if(mwfact < 0.1) |
1516 v->mwfact = 0.1; |
1442 mwfact = 0.1; |
1517 else if(v->mwfact > 0.9) |
1443 else if(mwfact > 0.9) |
1518 v->mwfact = 0.9; |
1444 mwfact = 0.9; |
1519 } |
1445 } |
1520 arrange(); |
1446 arrange(); |
1521 } |
1447 } |
1522 |
1448 |
1523 void |
1449 void |
1524 setup(void) { |
1450 setup(void) { |
1525 unsigned int i, j; |
1451 unsigned int i; |
1526 View *v; |
|
1527 XSetWindowAttributes wa; |
1452 XSetWindowAttributes wa; |
1528 XineramaScreenInfo *info = NULL; |
1453 |
|
1454 /* init screen */ |
|
1455 screen = DefaultScreen(dpy); |
|
1456 root = RootWindow(dpy, screen); |
|
1457 sx = 0; |
|
1458 sy = 0; |
|
1459 sw = DisplayWidth(dpy, screen); |
|
1460 sh = DisplayHeight(dpy, screen); |
1529 |
1461 |
1530 /* init atoms */ |
1462 /* init atoms */ |
1531 wmatom[WMProtocols] = XInternAtom(dpy, "WM_PROTOCOLS", False); |
1463 wmatom[WMProtocols] = XInternAtom(dpy, "WM_PROTOCOLS", False); |
1532 wmatom[WMDelete] = XInternAtom(dpy, "WM_DELETE_WINDOW", False); |
1464 wmatom[WMDelete] = XInternAtom(dpy, "WM_DELETE_WINDOW", False); |
1533 wmatom[WMName] = XInternAtom(dpy, "WM_NAME", False); |
1465 wmatom[WMName] = XInternAtom(dpy, "WM_NAME", False); |
1538 /* init cursors */ |
1470 /* init cursors */ |
1539 wa.cursor = cursor[CurNormal] = XCreateFontCursor(dpy, XC_left_ptr); |
1471 wa.cursor = cursor[CurNormal] = XCreateFontCursor(dpy, XC_left_ptr); |
1540 cursor[CurResize] = XCreateFontCursor(dpy, XC_sizing); |
1472 cursor[CurResize] = XCreateFontCursor(dpy, XC_sizing); |
1541 cursor[CurMove] = XCreateFontCursor(dpy, XC_fleur); |
1473 cursor[CurMove] = XCreateFontCursor(dpy, XC_fleur); |
1542 |
1474 |
|
1475 #ifdef XINERAMA |
1543 if(XineramaIsActive(dpy)) |
1476 if(XineramaIsActive(dpy)) |
1544 info = XineramaQueryScreens(dpy, &nviews); |
1477 info = XineramaQueryScreens(dpy, &xscreens); |
1545 |
|
1546 #if defined(AIM_XINERAMA) |
|
1547 nviews = 2; /* aim Xinerama */ |
|
1548 #endif |
1478 #endif |
1549 views = emallocz(nviews * sizeof(View)); |
|
1550 |
|
1551 screen = DefaultScreen(dpy); |
|
1552 root = RootWindow(dpy, screen); |
|
1553 |
1479 |
1554 /* init appearance */ |
1480 /* init appearance */ |
1555 dc.norm[ColBorder] = getcolor(NORMBORDERCOLOR); |
1481 dc.norm[ColBorder] = getcolor(NORMBORDERCOLOR); |
1556 dc.norm[ColBG] = getcolor(NORMBGCOLOR); |
1482 dc.norm[ColBG] = getcolor(NORMBGCOLOR); |
1557 dc.norm[ColFG] = getcolor(NORMFGCOLOR); |
1483 dc.norm[ColFG] = getcolor(NORMFGCOLOR); |
1564 dc.gc = XCreateGC(dpy, root, 0, 0); |
1490 dc.gc = XCreateGC(dpy, root, 0, 0); |
1565 XSetLineAttributes(dpy, dc.gc, 1, LineSolid, CapButt, JoinMiter); |
1491 XSetLineAttributes(dpy, dc.gc, 1, LineSolid, CapButt, JoinMiter); |
1566 if(!dc.font.set) |
1492 if(!dc.font.set) |
1567 XSetFont(dpy, dc.gc, dc.font.xfont->fid); |
1493 XSetFont(dpy, dc.gc, dc.font.xfont->fid); |
1568 |
1494 |
|
1495 /* init tags */ |
|
1496 seltags = emallocz(TAGSZ); |
|
1497 prevtags = emallocz(TAGSZ); |
|
1498 seltags[0] = prevtags[0] = True; |
|
1499 |
|
1500 /* init layouts */ |
|
1501 mwfact = MWFACT; |
|
1502 lt = &layouts[0]; |
|
1503 |
|
1504 /* TODO: Xinerama hints ? */ |
|
1505 /* init bar */ |
1569 for(blw = i = 0; i < LENGTH(layouts); i++) { |
1506 for(blw = i = 0; i < LENGTH(layouts); i++) { |
1570 i = textw(layouts[i].symbol); |
1507 i = textw(layouts[i].symbol); |
1571 if(i > blw) |
1508 if(i > blw) |
1572 blw = i; |
1509 blw = i; |
1573 } |
1510 } |
1574 |
1511 |
1575 seltags = emallocz(TAGSZ); |
1512 bpos = BARPOS; |
1576 prevtags = emallocz(TAGSZ); |
1513 wa.override_redirect = 1; |
1577 |
1514 wa.background_pixmap = ParentRelative; |
1578 /* check, if vtags need assistance, because there is only 1 view */ |
1515 wa.event_mask = ButtonPressMask|ExposureMask; |
1579 if(nviews == 1) |
1516 |
1580 for(i = 0; i < LENGTH(tags); i++) |
1517 barwin = XCreateWindow(dpy, root, sx, sy, sw, bh, 0, DefaultDepth(dpy, screen), |
1581 vtags[i] = 0; |
1518 CopyFromParent, DefaultVisual(dpy, screen), |
1582 |
|
1583 for(i = 0; i < nviews; i++) { |
|
1584 /* init geometry */ |
|
1585 v = &views[i]; |
|
1586 v->id = i; |
|
1587 |
|
1588 /* select first tag of view */ |
|
1589 j = firstag(v); |
|
1590 seltags[j] = prevtags[j] = True; |
|
1591 |
|
1592 if(info) { |
|
1593 |
|
1594 #if defined(AIM_XINERAMA) |
|
1595 v->w = DisplayWidth(dpy, screen) / 2; |
|
1596 v->x = (i == 0) ? 0 : v->w; |
|
1597 v->y = 0; |
|
1598 v->h = DisplayHeight(dpy, screen); |
|
1599 #else |
|
1600 v->x = info[i].x_org; |
|
1601 v->y = info[i].y_org; |
|
1602 v->w = info[i].width; |
|
1603 v->h = info[i].height; |
|
1604 #endif |
|
1605 } |
|
1606 else { |
|
1607 v->x = 0; |
|
1608 v->y = 0; |
|
1609 v->w = DisplayWidth(dpy, screen); |
|
1610 v->h = DisplayHeight(dpy, screen); |
|
1611 } |
|
1612 |
|
1613 /* init layouts */ |
|
1614 v->mwfact = MWFACT; |
|
1615 v->layout = &layouts[0]; |
|
1616 |
|
1617 // TODO: bpos per screen? |
|
1618 bpos = BARPOS; |
|
1619 wa.override_redirect = 1; |
|
1620 wa.background_pixmap = ParentRelative; |
|
1621 wa.event_mask = ButtonPressMask|ExposureMask; |
|
1622 |
|
1623 /* init bars */ |
|
1624 v->barwin = XCreateWindow(dpy, root, v->x, v->y, v->w, bh, 0, |
|
1625 DefaultDepth(dpy, screen), CopyFromParent, DefaultVisual(dpy, screen), |
|
1626 CWOverrideRedirect|CWBackPixmap|CWEventMask, &wa); |
1519 CWOverrideRedirect|CWBackPixmap|CWEventMask, &wa); |
1627 XDefineCursor(dpy, v->barwin, cursor[CurNormal]); |
1520 XDefineCursor(dpy, barwin, cursor[CurNormal]); |
1628 updatebarpos(v); |
1521 updatebarpos(); |
1629 XMapRaised(dpy, v->barwin); |
1522 XMapRaised(dpy, barwin); |
1630 strcpy(stext, "dwm-"VERSION); |
1523 strcpy(stext, "dwm-"VERSION); |
1631 |
1524 drawbar(); |
1632 /* EWMH support per view */ |
1525 |
1633 XChangeProperty(dpy, root, netatom[NetSupported], XA_ATOM, 32, |
1526 /* EWMH support per view */ |
1634 PropModeReplace, (unsigned char *) netatom, NetLast); |
1527 XChangeProperty(dpy, root, netatom[NetSupported], XA_ATOM, 32, |
1635 |
1528 PropModeReplace, (unsigned char *) netatom, NetLast); |
1636 /* select for events */ |
1529 |
1637 wa.event_mask = SubstructureRedirectMask|SubstructureNotifyMask |
1530 /* select for events */ |
1638 |EnterWindowMask|LeaveWindowMask|StructureNotifyMask; |
1531 wa.event_mask = SubstructureRedirectMask|SubstructureNotifyMask |
1639 XChangeWindowAttributes(dpy, root, CWEventMask|CWCursor, &wa); |
1532 |EnterWindowMask|LeaveWindowMask|StructureNotifyMask; |
1640 XSelectInput(dpy, root, wa.event_mask); |
1533 XChangeWindowAttributes(dpy, root, CWEventMask|CWCursor, &wa); |
1641 |
1534 XSelectInput(dpy, root, wa.event_mask); |
1642 drawbar(v); |
1535 |
1643 } |
|
1644 if(info) |
|
1645 XFree(info); |
|
1646 |
|
1647 selview = viewat(); |
|
1648 |
1536 |
1649 /* grab keys */ |
1537 /* grab keys */ |
1650 grabkeys(); |
1538 grabkeys(); |
1651 } |
1539 } |
1652 |
1540 |
1703 textw(const char *text) { |
1589 textw(const char *text) { |
1704 return textnw(text, strlen(text)) + dc.font.height; |
1590 return textnw(text, strlen(text)) + dc.font.height; |
1705 } |
1591 } |
1706 |
1592 |
1707 void |
1593 void |
1708 tile(View *v) { |
1594 tile(void) { |
1709 unsigned int i, n, nx, ny, nw, nh, mw, th; |
1595 unsigned int i, n, nx, ny, nw, nh, mw, th; |
1710 Client *c, *mc; |
1596 Client *c, *mc; |
1711 |
1597 |
1712 domwfact = dozoom = True; |
1598 domwfact = dozoom = True; |
1713 nx = v->wax; |
1599 nx = wax; |
1714 ny = v->way; |
1600 ny = way; |
1715 nw = 0; |
1601 nw = 0; |
1716 for(n = 0, c = nexttiled(clients, v); c; c = nexttiled(c->next, v)) |
1602 for(n = 0, c = nexttiled(clients); c; c = nexttiled(c->next)) |
1717 n++; |
1603 n++; |
1718 |
1604 |
1719 /* window geoms */ |
1605 /* window geoms */ |
1720 mw = (n == 1) ? v->waw : v->mwfact * v->waw; |
1606 mw = (n == 1) ? waw : mwfact * waw; |
1721 th = (n > 1) ? v->wah / (n - 1) : 0; |
1607 th = (n > 1) ? wah / (n - 1) : 0; |
1722 if(n > 1 && th < bh) |
1608 if(n > 1 && th < bh) |
1723 th = v->wah; |
1609 th = wah; |
1724 |
1610 |
1725 for(i = 0, c = mc = nexttiled(clients, v); c; c = nexttiled(c->next, v)) { |
1611 for(i = 0, c = mc = nexttiled(clients); c; c = nexttiled(c->next)) { |
1726 if(i == 0) { /* master */ |
1612 if(i == 0) { /* master */ |
1727 nw = mw - 2 * c->border; |
1613 nw = mw - 2 * c->border; |
1728 nh = v->wah - 2 * c->border; |
1614 nh = wah - 2 * c->border; |
1729 } |
1615 } |
1730 else { /* tile window */ |
1616 else { /* tile window */ |
1731 if(i == 1) { |
1617 if(i == 1) { |
1732 ny = v->way; |
1618 ny = way; |
1733 nx += mc->w + 2 * mc->border; |
1619 nx += mc->w + 2 * mc->border; |
1734 nw = v->waw - mw - 2 * c->border; |
1620 nw = waw - mw - 2 * c->border; |
1735 } |
1621 } |
1736 if(i + 1 == n) /* remainder */ |
1622 if(i + 1 == n) /* remainder */ |
1737 nh = (v->way + v->wah) - ny - 2 * c->border; |
1623 nh = (way + wah) - ny - 2 * c->border; |
1738 else |
1624 else |
1739 nh = th - 2 * c->border; |
1625 nh = th - 2 * c->border; |
1740 } |
1626 } |
1741 resize(c, nx, ny, nw, nh, RESIZEHINTS); |
1627 resize(c, nx, ny, nw, nh, RESIZEHINTS); |
1742 if((RESIZEHINTS) && ((c->h < bh) || (c->h > nh) || (c->w < bh) || (c->w > nw))) |
1628 if((RESIZEHINTS) && ((c->h < bh) || (c->h > nh) || (c->w < bh) || (c->w > nw))) |
1743 /* client doesn't accept size constraints */ |
1629 /* client doesn't accept size constraints */ |
1744 resize(c, nx, ny, nw, nh, False); |
1630 resize(c, nx, ny, nw, nh, False); |
1745 if(n > 1 && th != v->wah) |
1631 if(n > 1 && th != wah) |
1746 ny = c->y + c->h + 2 * c->border; |
1632 ny = c->y + c->h + 2 * c->border; |
1747 i++; |
1633 i++; |
1748 } |
1634 } |
1749 } |
1635 } |
1750 |
1636 |
1928 c->isurgent = (wmh->flags & XUrgencyHint) ? True : False; |
1814 c->isurgent = (wmh->flags & XUrgencyHint) ? True : False; |
1929 XFree(wmh); |
1815 XFree(wmh); |
1930 } |
1816 } |
1931 } |
1817 } |
1932 |
1818 |
|
1819 |
1933 void |
1820 void |
1934 view(const char *arg) { |
1821 view(const char *arg) { |
1935 unsigned int i, j; |
1822 unsigned int i; |
1936 Bool tmp[LENGTH(tags)]; |
1823 |
1937 |
1824 for(i = 0; i < LENGTH(tags); i++) |
1938 memcpy(tmp, seltags, TAGSZ); |
1825 tmp[i] = (NULL == arg); |
1939 if(arg == NULL) { |
1826 tmp[idxoftag(arg)] = True; |
1940 for(i = 0; i < LENGTH(tags); i++) |
1827 |
1941 tmp[i] = (vtags[i] == selview->id); |
|
1942 } |
|
1943 else { |
|
1944 i = idxoftag(arg); |
|
1945 for(j = 0; j < LENGTH(tags); j++) |
|
1946 if(selview->id == vtags[i]) { |
|
1947 /* view tag of selview */ |
|
1948 if(selview->id == vtags[j]) |
|
1949 tmp[j] = False; |
|
1950 } |
|
1951 else { |
|
1952 /* only touch the view the focus should go */ |
|
1953 if(vtags[j] == vtags[i]) |
|
1954 tmp[j] = False; |
|
1955 } |
|
1956 selview = &views[vtags[i]]; |
|
1957 tmp[i] = True; |
|
1958 } |
|
1959 if(memcmp(seltags, tmp, TAGSZ) != 0) { |
1828 if(memcmp(seltags, tmp, TAGSZ) != 0) { |
1960 memcpy(prevtags, seltags, TAGSZ); |
1829 memcpy(prevtags, seltags, TAGSZ); |
1961 memcpy(seltags, tmp, TAGSZ); |
1830 memcpy(seltags, tmp, TAGSZ); |
1962 arrange(); |
1831 arrange(); |
1963 } |
1832 } |
1964 } |
1833 } |
1965 |
1834 |
1966 View * |
|
1967 viewat() { |
|
1968 int i, x, y; |
|
1969 Window win; |
|
1970 unsigned int mask; |
|
1971 |
|
1972 XQueryPointer(dpy, root, &win, &win, &x, &y, &i, &i, &mask); |
|
1973 for(i = 0; i < nviews; i++) { |
|
1974 if((x >= views[i].x && x < views[i].x + views[i].w) |
|
1975 && (y >= views[i].y && y < views[i].y + views[i].h)) |
|
1976 return &views[i]; |
|
1977 } |
|
1978 return NULL; |
|
1979 } |
|
1980 |
|
1981 void |
1835 void |
1982 viewprevtag(const char *arg) { |
1836 viewprevtag(const char *arg) { |
1983 static Bool tmp[LENGTH(tags)]; |
|
1984 |
1837 |
1985 memcpy(tmp, seltags, TAGSZ); |
1838 memcpy(tmp, seltags, TAGSZ); |
1986 memcpy(seltags, prevtags, TAGSZ); |
1839 memcpy(seltags, prevtags, TAGSZ); |
1987 memcpy(prevtags, tmp, TAGSZ); |
1840 memcpy(prevtags, tmp, TAGSZ); |
1988 arrange(); |
1841 arrange(); |