144 long getstate(Window w); |
160 long getstate(Window w); |
145 Bool gettextprop(Window w, Atom atom, char *text, unsigned int size); |
161 Bool gettextprop(Window w, Atom atom, char *text, unsigned int size); |
146 void grabbuttons(Client *c, Bool focused); |
162 void grabbuttons(Client *c, Bool focused); |
147 void grabkeys(void); |
163 void grabkeys(void); |
148 unsigned int idxoftag(const char *tag); |
164 unsigned int idxoftag(const char *tag); |
149 void initfont(const char *fontstr); |
165 void initfont(Monitor*, const char *fontstr); |
150 Bool isoccupied(unsigned int t); |
166 Bool isoccupied(Monitor *m, unsigned int t); |
151 Bool isprotodel(Client *c); |
167 Bool isprotodel(Client *c); |
152 Bool isvisible(Client *c); |
168 Bool isvisible(Client *c, Monitor *m); |
153 void keypress(XEvent *e); |
169 void keypress(XEvent *e); |
154 void killclient(const char *arg); |
170 void killclient(const char *arg); |
155 void leavenotify(XEvent *e); |
171 void leavenotify(XEvent *e); |
156 void manage(Window w, XWindowAttributes *wa); |
172 void manage(Window w, XWindowAttributes *wa); |
157 void mappingnotify(XEvent *e); |
173 void mappingnotify(XEvent *e); |
158 void maprequest(XEvent *e); |
174 void maprequest(XEvent *e); |
159 void maximize(const char *arg); |
175 void maximize(const char *arg); |
160 void movemouse(Client *c); |
176 void movemouse(Client *c); |
161 Client *nexttiled(Client *c); |
177 Client *nexttiled(Client *c, Monitor *m); |
162 void propertynotify(XEvent *e); |
178 void propertynotify(XEvent *e); |
163 void quit(const char *arg); |
179 void quit(const char *arg); |
164 void reapply(const char *arg); |
180 void reapply(const char *arg); |
165 void resize(Client *c, int x, int y, int w, int h, Bool sizehints); |
181 void resize(Client *c, int x, int y, int w, int h, Bool sizehints); |
166 void resizemouse(Client *c); |
182 void resizemouse(Client *c); |
171 void setlayout(const char *arg); |
187 void setlayout(const char *arg); |
172 void setmwfact(const char *arg); |
188 void setmwfact(const char *arg); |
173 void setup(void); |
189 void setup(void); |
174 void spawn(const char *arg); |
190 void spawn(const char *arg); |
175 void tag(const char *arg); |
191 void tag(const char *arg); |
176 unsigned int textnw(const char *text, unsigned int len); |
192 unsigned int textnw(Monitor*, const char *text, unsigned int len); |
177 unsigned int textw(const char *text); |
193 unsigned int textw(Monitor*, const char *text); |
178 void tile(void); |
194 void tile(void); |
179 void togglebar(const char *arg); |
195 void togglebar(const char *arg); |
180 void togglefloating(const char *arg); |
196 void togglefloating(const char *arg); |
181 void toggletag(const char *arg); |
197 void toggletag(const char *arg); |
182 void toggleview(const char *arg); |
198 void toggleview(const char *arg); |
183 void unban(Client *c); |
199 void unban(Client *c); |
184 void unmanage(Client *c); |
200 void unmanage(Client *c); |
185 void unmapnotify(XEvent *e); |
201 void unmapnotify(XEvent *e); |
186 void updatebarpos(void); |
202 void updatebarpos(Monitor *s); |
187 void updatesizehints(Client *c); |
203 void updatesizehints(Client *c); |
188 void updatetitle(Client *c); |
204 void updatetitle(Client *c); |
189 void view(const char *arg); |
205 void view(const char *arg); |
190 void viewprevtag(const char *arg); /* views previous selected tags */ |
206 void viewprevtag(const char *arg); /* views previous selected tags */ |
191 int xerror(Display *dpy, XErrorEvent *ee); |
207 int xerror(Display *dpy, XErrorEvent *ee); |
192 int xerrordummy(Display *dsply, XErrorEvent *ee); |
208 int xerrordummy(Display *dsply, XErrorEvent *ee); |
193 int xerrorstart(Display *dsply, XErrorEvent *ee); |
209 int xerrorstart(Display *dsply, XErrorEvent *ee); |
194 void zoom(const char *arg); |
210 void zoom(const char *arg); |
|
211 int monitorat(int, int); |
|
212 void movetomonitor(const char *arg); |
|
213 void selectmonitor(const char *arg); |
195 |
214 |
196 /* variables */ |
215 /* variables */ |
197 char stext[256]; |
216 char stext[256]; |
198 double mwfact; |
217 int mcount, screen; |
199 int screen, sx, sy, sw, sh, wax, way, waw, wah; |
218 //double mwfact; |
|
219 //int screen, sx, sy, sw, sh, wax, way, waw, wah; |
200 int (*xerrorxlib)(Display *, XErrorEvent *); |
220 int (*xerrorxlib)(Display *, XErrorEvent *); |
201 unsigned int bh, bpos; |
221 unsigned int bh, bpos; |
202 unsigned int blw = 0; |
222 unsigned int blw = 0; |
203 unsigned int numlockmask = 0; |
223 unsigned int numlockmask = 0; |
204 void (*handler[LASTEvent]) (XEvent *) = { |
224 void (*handler[LASTEvent]) (XEvent *) = { |
219 Atom wmatom[WMLast], netatom[NetLast]; |
239 Atom wmatom[WMLast], netatom[NetLast]; |
220 Bool domwfact = True; |
240 Bool domwfact = True; |
221 Bool dozoom = True; |
241 Bool dozoom = True; |
222 Bool otherwm, readin; |
242 Bool otherwm, readin; |
223 Bool running = True; |
243 Bool running = True; |
224 Bool selscreen = True; |
244 //Bool selscreen = True; |
225 Client *clients = NULL; |
245 Client *clients = NULL; |
226 Client *sel = NULL; |
246 Client *sel = NULL; |
227 Client *stack = NULL; |
247 Client *stack = NULL; |
228 Cursor cursor[CurLast]; |
248 Cursor cursor[CurLast]; |
229 Display *dpy; |
249 Display *dpy; |
230 DC dc = {0}; |
250 DC dc = {0}; |
231 Layout *layout = NULL; |
251 Window root; |
232 Window barwin, root; |
252 //Layout *layout = NULL; |
|
253 //Window barwin, root; |
233 Regs *regs = NULL; |
254 Regs *regs = NULL; |
|
255 Monitor *monitors; |
|
256 int selmonitor = 0; |
234 |
257 |
235 /* configuration, allows nested code to access above variables */ |
258 /* configuration, allows nested code to access above variables */ |
236 #include "config.h" |
259 #include "config.h" |
237 |
260 |
238 Bool prevtags[LENGTH(tags)]; |
261 //Bool prevtags[LENGTH(tags)]; |
239 |
262 |
240 /* function implementations */ |
263 /* function implementations */ |
241 void |
264 void |
242 applyrules(Client *c) { |
265 applyrules(Client *c) { |
243 static char buf[512]; |
266 static char buf[512]; |
244 unsigned int i, j; |
267 unsigned int i, j; |
245 regmatch_t tmp; |
268 regmatch_t tmp; |
246 Bool matched = False; |
269 Bool matched_tag = False; |
|
270 Bool matched_monitor = False; |
247 XClassHint ch = { 0 }; |
271 XClassHint ch = { 0 }; |
248 |
272 |
249 /* rule matching */ |
273 /* rule matching */ |
250 XGetClassHint(dpy, c->win, &ch); |
274 XGetClassHint(dpy, c->win, &ch); |
251 snprintf(buf, sizeof buf, "%s:%s:%s", |
275 snprintf(buf, sizeof buf, "%s:%s:%s", |
252 ch.res_class ? ch.res_class : "", |
276 ch.res_class ? ch.res_class : "", |
253 ch.res_name ? ch.res_name : "", c->name); |
277 ch.res_name ? ch.res_name : "", c->name); |
254 for(i = 0; i < LENGTH(rules); i++) |
278 for(i = 0; i < LENGTH(rules); i++) |
255 if(regs[i].propregex && !regexec(regs[i].propregex, buf, 1, &tmp, 0)) { |
279 if(regs[i].propregex && !regexec(regs[i].propregex, buf, 1, &tmp, 0)) { |
|
280 if (rules[i].monitor >= 0 && rules[i].monitor < mcount) { |
|
281 matched_monitor = True; |
|
282 c->monitor = rules[i].monitor; |
|
283 } |
|
284 |
256 c->isfloating = rules[i].isfloating; |
285 c->isfloating = rules[i].isfloating; |
257 for(j = 0; regs[i].tagregex && j < LENGTH(tags); j++) { |
286 for(j = 0; regs[i].tagregex && j < LENGTH(tags); j++) { |
258 if(!regexec(regs[i].tagregex, tags[j], 1, &tmp, 0)) { |
287 if(!regexec(regs[i].tagregex, tags[j], 1, &tmp, 0)) { |
259 matched = True; |
288 matched_tag = True; |
260 c->tags[j] = True; |
289 c->tags[j] = True; |
261 } |
290 } |
262 } |
291 } |
263 } |
292 } |
264 if(ch.res_class) |
293 if(ch.res_class) |
265 XFree(ch.res_class); |
294 XFree(ch.res_class); |
266 if(ch.res_name) |
295 if(ch.res_name) |
267 XFree(ch.res_name); |
296 XFree(ch.res_name); |
268 if(!matched) |
297 if(!matched_tag) |
269 memcpy(c->tags, seltags, sizeof seltags); |
298 memcpy(c->tags, monitors[monitorat(-1, -1)].seltags, sizeof seltags); |
|
299 if (!matched_monitor) |
|
300 c->monitor = monitorat(-1, -1); |
270 } |
301 } |
271 |
302 |
272 void |
303 void |
273 arrange(void) { |
304 arrange(void) { |
274 Client *c; |
305 Client *c; |
275 |
306 |
276 for(c = clients; c; c = c->next) |
307 for(c = clients; c; c = c->next) |
277 if(isvisible(c)) |
308 if(isvisible(c, &monitors[c->monitor])) |
278 unban(c); |
309 unban(c); |
279 else |
310 else |
280 ban(c); |
311 ban(c); |
281 layout->arrange(); |
312 |
|
313 monitors[selmonitor].layout->arrange(); |
282 focus(NULL); |
314 focus(NULL); |
283 restack(); |
315 restack(); |
284 } |
316 } |
285 |
317 |
286 void |
318 void |
377 XSync(dpy, False); |
411 XSync(dpy, False); |
378 } |
412 } |
379 |
413 |
380 void |
414 void |
381 cleanup(void) { |
415 cleanup(void) { |
|
416 unsigned int i; |
382 close(STDIN_FILENO); |
417 close(STDIN_FILENO); |
383 while(stack) { |
418 while(stack) { |
384 unban(stack); |
419 unban(stack); |
385 unmanage(stack); |
420 unmanage(stack); |
386 } |
421 } |
387 if(dc.font.set) |
422 for(i = 0; i < mcount; i++) { |
388 XFreeFontSet(dpy, dc.font.set); |
423 Monitor *m = &monitors[i]; |
389 else |
424 if(m->dc.font.set) |
390 XFreeFont(dpy, dc.font.xfont); |
425 XFreeFontSet(dpy, m->dc.font.set); |
391 XUngrabKey(dpy, AnyKey, AnyModifier, root); |
426 else |
392 XFreePixmap(dpy, dc.drawable); |
427 XFreeFont(dpy, m->dc.font.xfont); |
393 XFreeGC(dpy, dc.gc); |
428 XUngrabKey(dpy, AnyKey, AnyModifier, root); |
394 XDestroyWindow(dpy, barwin); |
429 XFreePixmap(dpy, m->dc.drawable); |
395 XFreeCursor(dpy, cursor[CurNormal]); |
430 XFreeGC(dpy, m->dc.gc); |
396 XFreeCursor(dpy, cursor[CurResize]); |
431 XDestroyWindow(dpy, m->barwin); |
397 XFreeCursor(dpy, cursor[CurMove]); |
432 XFreeCursor(dpy, cursor[CurNormal]); |
398 XSetInputFocus(dpy, PointerRoot, RevertToPointerRoot, CurrentTime); |
433 XFreeCursor(dpy, cursor[CurResize]); |
399 XSync(dpy, False); |
434 XFreeCursor(dpy, cursor[CurMove]); |
|
435 XSetInputFocus(dpy, PointerRoot, RevertToPointerRoot, CurrentTime); |
|
436 XSync(dpy, False); |
|
437 } |
400 } |
438 } |
401 |
439 |
402 void |
440 void |
403 compileregs(void) { |
441 compileregs(void) { |
404 unsigned int i; |
442 unsigned int i; |
463 Client *c; |
502 Client *c; |
464 XConfigureRequestEvent *ev = &e->xconfigurerequest; |
503 XConfigureRequestEvent *ev = &e->xconfigurerequest; |
465 XWindowChanges wc; |
504 XWindowChanges wc; |
466 |
505 |
467 if((c = getclient(ev->window))) { |
506 if((c = getclient(ev->window))) { |
|
507 Monitor *m = &monitors[c->monitor]; |
468 if(ev->value_mask & CWBorderWidth) |
508 if(ev->value_mask & CWBorderWidth) |
469 c->border = ev->border_width; |
509 c->border = ev->border_width; |
470 if(c->isfixed || c->isfloating || (floating == layout->arrange)) { |
510 if(c->isfixed || c->isfloating || (floating == m->layout->arrange)) { |
471 if(ev->value_mask & CWX) |
511 if(ev->value_mask & CWX) |
472 c->x = ev->x; |
512 c->x = m->sx+ev->x; |
473 if(ev->value_mask & CWY) |
513 if(ev->value_mask & CWY) |
474 c->y = ev->y; |
514 c->y = m->sy+ev->y; |
475 if(ev->value_mask & CWWidth) |
515 if(ev->value_mask & CWWidth) |
476 c->w = ev->width; |
516 c->w = ev->width; |
477 if(ev->value_mask & CWHeight) |
517 if(ev->value_mask & CWHeight) |
478 c->h = ev->height; |
518 c->h = ev->height; |
479 if((c->x + c->w) > sw && c->isfloating) |
519 if((c->x - m->sx + c->w) > m->sw && c->isfloating) |
480 c->x = sw / 2 - c->w / 2; /* center in x direction */ |
520 c->x = m->sx + (m->sw / 2 - c->w / 2); /* center in x direction */ |
481 if((c->y + c->h) > sh && c->isfloating) |
521 if((c->y - m->sy + c->h) > m->sh && c->isfloating) |
482 c->y = sh / 2 - c->h / 2; /* center in y direction */ |
522 c->y = m->sy + (m->sh / 2 - c->h / 2); /* center in y direction */ |
483 if((ev->value_mask & (CWX | CWY)) |
523 if((ev->value_mask & (CWX | CWY)) |
484 && !(ev->value_mask & (CWWidth | CWHeight))) |
524 && !(ev->value_mask & (CWWidth | CWHeight))) |
485 configure(c); |
525 configure(c); |
486 if(isvisible(c)) |
526 if(isvisible(c, &monitors[monitorat(-1,-1)])) |
487 XMoveResizeWindow(dpy, c->win, c->x, c->y, c->w, c->h); |
527 XMoveResizeWindow(dpy, c->win, c->x, c->y, c->w, c->h); |
488 } |
528 } |
489 else |
529 else |
490 configure(c); |
530 configure(c); |
491 } |
531 } |
530 *tc = c->snext; |
570 *tc = c->snext; |
531 } |
571 } |
532 |
572 |
533 void |
573 void |
534 drawbar(void) { |
574 drawbar(void) { |
535 int i, x; |
575 int i, x, s; |
536 |
576 |
537 dc.x = dc.y = 0; |
577 for(s = 0; s < mcount; ++s) { |
538 for(i = 0; i < LENGTH(tags); i++) { |
578 Monitor *m = &monitors[s]; |
539 dc.w = textw(tags[i]); |
579 m->dc.x = 0; |
540 if(seltags[i]) { |
580 for(i = 0; i < LENGTH(tags); i++) { |
541 drawtext(tags[i], dc.sel); |
581 m->dc.w = textw(m, tags[i]); |
542 drawsquare(sel && sel->tags[i], isoccupied(i), dc.sel); |
582 if(m->seltags[i]) { |
543 } |
583 drawtext(m, tags[i], m->dc.sel); |
544 else { |
584 drawsquare(m, sel && sel->tags[i] && sel->monitor == m->id, isoccupied(m, i), m->dc.sel); |
545 drawtext(tags[i], dc.norm); |
585 } |
546 drawsquare(sel && sel->tags[i], isoccupied(i), dc.norm); |
586 else { |
547 } |
587 drawtext(m, tags[i], m->dc.norm); |
548 dc.x += dc.w; |
588 drawsquare(m, sel && sel->tags[i] && sel->monitor == m->id, isoccupied(m, i), m->dc.norm); |
549 } |
589 } |
550 dc.w = blw; |
590 m->dc.x += m->dc.w; |
551 drawtext(layout->symbol, dc.norm); |
591 } |
552 x = dc.x + dc.w; |
592 m->dc.w = blw; |
553 dc.w = textw(stext); |
593 drawtext(m, m->layout->symbol, m->dc.norm); |
554 dc.x = sw - dc.w; |
594 x = m->dc.x + m->dc.w; |
555 if(dc.x < x) { |
595 m->dc.w = textw(m, stext); |
556 dc.x = x; |
596 m->dc.x = m->sw - m->dc.w; |
557 dc.w = sw - x; |
597 if(m->dc.x < x) { |
558 } |
598 m->dc.x = x; |
559 drawtext(stext, dc.norm); |
599 m->dc.w = m->sw - x; |
560 if((dc.w = dc.x - x) > bh) { |
600 } |
561 dc.x = x; |
601 drawtext(m, stext, m->dc.norm); |
562 if(sel) { |
602 if((m->dc.w = m->dc.x - x) > bh) { |
563 drawtext(sel->name, dc.sel); |
603 m->dc.x = x; |
564 drawsquare(False, sel->isfloating, dc.sel); |
604 if(sel && sel->monitor == m->id) { |
565 } |
605 drawtext(m, sel->name, m->dc.sel); |
566 else |
606 drawsquare(m, False, sel->isfloating, m->dc.sel); |
567 drawtext(NULL, dc.norm); |
607 } |
568 } |
608 else |
569 XCopyArea(dpy, dc.drawable, barwin, dc.gc, 0, 0, sw, bh, 0, 0); |
609 drawtext(m, NULL, m->dc.norm); |
570 XSync(dpy, False); |
610 } |
571 } |
611 XCopyArea(dpy, m->dc.drawable, m->barwin, m->dc.gc, 0, 0, m->sw, bh, 0, 0); |
572 |
612 XSync(dpy, False); |
573 void |
613 } |
574 drawsquare(Bool filled, Bool empty, unsigned long col[ColLast]) { |
614 } |
|
615 |
|
616 void |
|
617 drawsquare(Monitor *m, Bool filled, Bool empty, unsigned long col[ColLast]) { |
575 int x; |
618 int x; |
576 XGCValues gcv; |
619 XGCValues gcv; |
577 XRectangle r = { dc.x, dc.y, dc.w, dc.h }; |
620 XRectangle r = { m->dc.x, m->dc.y, m->dc.w, m->dc.h }; |
578 |
621 |
579 gcv.foreground = col[ColFG]; |
622 gcv.foreground = col[ColFG]; |
580 XChangeGC(dpy, dc.gc, GCForeground, &gcv); |
623 XChangeGC(dpy, m->dc.gc, GCForeground, &gcv); |
581 x = (dc.font.ascent + dc.font.descent + 2) / 4; |
624 x = (m->dc.font.ascent + m->dc.font.descent + 2) / 4; |
582 r.x = dc.x + 1; |
625 r.x = m->dc.x + 1; |
583 r.y = dc.y + 1; |
626 r.y = m->dc.y + 1; |
584 if(filled) { |
627 if(filled) { |
585 r.width = r.height = x + 1; |
628 r.width = r.height = x + 1; |
586 XFillRectangles(dpy, dc.drawable, dc.gc, &r, 1); |
629 XFillRectangles(dpy, m->dc.drawable, m->dc.gc, &r, 1); |
587 } |
630 } |
588 else if(empty) { |
631 else if(empty) { |
589 r.width = r.height = x; |
632 r.width = r.height = x; |
590 XDrawRectangles(dpy, dc.drawable, dc.gc, &r, 1); |
633 XDrawRectangles(dpy, m->dc.drawable, m->dc.gc, &r, 1); |
591 } |
634 } |
592 } |
635 } |
593 |
636 |
594 void |
637 void |
595 drawtext(const char *text, unsigned long col[ColLast]) { |
638 drawtext(Monitor *m, const char *text, unsigned long col[ColLast]) { |
596 int x, y, w, h; |
639 int x, y, w, h; |
597 static char buf[256]; |
640 static char buf[256]; |
598 unsigned int len, olen; |
641 unsigned int len, olen; |
599 XRectangle r = { dc.x, dc.y, dc.w, dc.h }; |
642 XRectangle r = { m->dc.x, m->dc.y, m->dc.w, m->dc.h }; |
600 |
643 |
601 XSetForeground(dpy, dc.gc, col[ColBG]); |
644 XSetForeground(dpy, m->dc.gc, col[ColBG]); |
602 XFillRectangles(dpy, dc.drawable, dc.gc, &r, 1); |
645 XFillRectangles(dpy, m->dc.drawable, m->dc.gc, &r, 1); |
603 if(!text) |
646 if(!text) |
604 return; |
647 return; |
605 w = 0; |
648 w = 0; |
606 olen = len = strlen(text); |
649 olen = len = strlen(text); |
607 if(len >= sizeof buf) |
650 if(len >= sizeof buf) |
608 len = sizeof buf - 1; |
651 len = sizeof buf - 1; |
609 memcpy(buf, text, len); |
652 memcpy(buf, text, len); |
610 buf[len] = 0; |
653 buf[len] = 0; |
611 h = dc.font.ascent + dc.font.descent; |
654 h = m->dc.font.ascent + m->dc.font.descent; |
612 y = dc.y + (dc.h / 2) - (h / 2) + dc.font.ascent; |
655 y = m->dc.y + (m->dc.h / 2) - (h / 2) + m->dc.font.ascent; |
613 x = dc.x + (h / 2); |
656 x = m->dc.x + (h / 2); |
614 /* shorten text if necessary */ |
657 /* shorten text if necessary */ |
615 while(len && (w = textnw(buf, len)) > dc.w - h) |
658 while(len && (w = textnw(m, buf, len)) > m->dc.w - h) |
616 buf[--len] = 0; |
659 buf[--len] = 0; |
617 if(len < olen) { |
660 if(len < olen) { |
618 if(len > 1) |
661 if(len > 1) |
619 buf[len - 1] = '.'; |
662 buf[len - 1] = '.'; |
620 if(len > 2) |
663 if(len > 2) |
621 buf[len - 2] = '.'; |
664 buf[len - 2] = '.'; |
622 if(len > 3) |
665 if(len > 3) |
623 buf[len - 3] = '.'; |
666 buf[len - 3] = '.'; |
624 } |
667 } |
625 if(w > dc.w) |
668 if(w > m->dc.w) |
626 return; /* too long */ |
669 return; /* too long */ |
627 XSetForeground(dpy, dc.gc, col[ColFG]); |
670 XSetForeground(dpy, m->dc.gc, col[ColFG]); |
628 if(dc.font.set) |
671 if(m->dc.font.set) |
629 XmbDrawString(dpy, dc.drawable, dc.font.set, dc.gc, x, y, buf, len); |
672 XmbDrawString(dpy, m->dc.drawable, m->dc.font.set, m->dc.gc, x, y, buf, len); |
630 else |
673 else |
631 XDrawString(dpy, dc.drawable, dc.gc, x, y, buf, len); |
674 XDrawString(dpy, m->dc.drawable, m->dc.gc, x, y, buf, len); |
632 } |
675 } |
633 |
676 |
634 void * |
677 void * |
635 emallocz(unsigned int size) { |
678 emallocz(unsigned int size) { |
636 void *res = calloc(1, size); |
679 void *res = calloc(1, size); |
668 void |
711 void |
669 expose(XEvent *e) { |
712 expose(XEvent *e) { |
670 XExposeEvent *ev = &e->xexpose; |
713 XExposeEvent *ev = &e->xexpose; |
671 |
714 |
672 if(ev->count == 0) { |
715 if(ev->count == 0) { |
673 if(ev->window == barwin) |
716 if(ev->window == monitors[selmonitor].barwin) |
674 drawbar(); |
717 drawbar(); |
675 } |
718 } |
676 } |
719 } |
677 |
720 |
678 void |
721 void |
679 floating(void) { /* default floating layout */ |
722 floating(void) { /* default floating layout */ |
680 Client *c; |
723 Client *c; |
681 |
724 |
682 domwfact = dozoom = False; |
725 domwfact = dozoom = False; |
683 for(c = clients; c; c = c->next) |
726 for(c = clients; c; c = c->next) |
684 if(isvisible(c)) |
727 if(isvisible(c, &monitors[selmonitor])) |
685 resize(c, c->x, c->y, c->w, c->h, True); |
728 resize(c, c->x, c->y, c->w, c->h, True); |
686 } |
729 } |
687 |
730 |
688 void |
731 void |
689 focus(Client *c) { |
732 focus(Client *c) { |
690 if((!c && selscreen) || (c && !isvisible(c))) |
733 Monitor *m = &monitors[monitorat(-1, -1)]; |
691 for(c = stack; c && !isvisible(c); c = c->snext); |
734 if(!c || (c && !isvisible(c, m))) |
|
735 for(c = stack; c && !isvisible(c, m); c = c->snext); |
692 if(sel && sel != c) { |
736 if(sel && sel != c) { |
693 grabbuttons(sel, False); |
737 grabbuttons(sel, False); |
694 XSetWindowBorder(dpy, sel->win, dc.norm[ColBorder]); |
738 XSetWindowBorder(dpy, sel->win, monitors[sel->monitor].dc.norm[ColBorder]); |
695 } |
739 } |
696 if(c) { |
740 if(c) { |
697 detachstack(c); |
741 detachstack(c); |
698 attachstack(c); |
742 attachstack(c); |
699 grabbuttons(c, True); |
743 grabbuttons(c, True); |
700 } |
744 } |
701 sel = c; |
745 sel = c; |
702 drawbar(); |
746 drawbar(); |
703 if(!selscreen) |
|
704 return; |
|
705 if(c) { |
747 if(c) { |
706 XSetWindowBorder(dpy, c->win, dc.sel[ColBorder]); |
748 XSetWindowBorder(dpy, c->win, monitors[c->monitor].dc.sel[ColBorder]); |
707 XSetInputFocus(dpy, c->win, RevertToPointerRoot, CurrentTime); |
749 XSetInputFocus(dpy, c->win, RevertToPointerRoot, CurrentTime); |
708 } |
750 selmonitor = monitorat(c->x, c->y); |
709 else |
751 } |
|
752 else { |
710 XSetInputFocus(dpy, root, RevertToPointerRoot, CurrentTime); |
753 XSetInputFocus(dpy, root, RevertToPointerRoot, CurrentTime); |
|
754 selmonitor = monitorat(-1, -1); |
|
755 } |
711 } |
756 } |
712 |
757 |
713 void |
758 void |
714 focusin(XEvent *e) { /* there are some broken focus acquiring clients */ |
759 focusin(XEvent *e) { /* there are some broken focus acquiring clients */ |
715 XFocusChangeEvent *ev = &e->xfocus; |
760 XFocusChangeEvent *ev = &e->xfocus; |
875 for(i = 0; (i < LENGTH(tags)) && (tags[i] != tag); i++); |
922 for(i = 0; (i < LENGTH(tags)) && (tags[i] != tag); i++); |
876 return (i < LENGTH(tags)) ? i : 0; |
923 return (i < LENGTH(tags)) ? i : 0; |
877 } |
924 } |
878 |
925 |
879 void |
926 void |
880 initfont(const char *fontstr) { |
927 initfont(Monitor *m, const char *fontstr) { |
881 char *def, **missing; |
928 char *def, **missing; |
882 int i, n; |
929 int i, n; |
883 |
930 |
884 missing = NULL; |
931 missing = NULL; |
885 if(dc.font.set) |
932 if(m->dc.font.set) |
886 XFreeFontSet(dpy, dc.font.set); |
933 XFreeFontSet(dpy, m->dc.font.set); |
887 dc.font.set = XCreateFontSet(dpy, fontstr, &missing, &n, &def); |
934 m->dc.font.set = XCreateFontSet(dpy, fontstr, &missing, &n, &def); |
888 if(missing) { |
935 if(missing) { |
889 while(n--) |
936 while(n--) |
890 fprintf(stderr, "dwm: missing fontset: %s\n", missing[n]); |
937 fprintf(stderr, "dwm: missing fontset: %s\n", missing[n]); |
891 XFreeStringList(missing); |
938 XFreeStringList(missing); |
892 } |
939 } |
893 if(dc.font.set) { |
940 if(m->dc.font.set) { |
894 XFontSetExtents *font_extents; |
941 XFontSetExtents *font_extents; |
895 XFontStruct **xfonts; |
942 XFontStruct **xfonts; |
896 char **font_names; |
943 char **font_names; |
897 dc.font.ascent = dc.font.descent = 0; |
944 m->dc.font.ascent = m->dc.font.descent = 0; |
898 font_extents = XExtentsOfFontSet(dc.font.set); |
945 font_extents = XExtentsOfFontSet(m->dc.font.set); |
899 n = XFontsOfFontSet(dc.font.set, &xfonts, &font_names); |
946 n = XFontsOfFontSet(m->dc.font.set, &xfonts, &font_names); |
900 for(i = 0, dc.font.ascent = 0, dc.font.descent = 0; i < n; i++) { |
947 for(i = 0, m->dc.font.ascent = 0, m->dc.font.descent = 0; i < n; i++) { |
901 if(dc.font.ascent < (*xfonts)->ascent) |
948 if(m->dc.font.ascent < (*xfonts)->ascent) |
902 dc.font.ascent = (*xfonts)->ascent; |
949 m->dc.font.ascent = (*xfonts)->ascent; |
903 if(dc.font.descent < (*xfonts)->descent) |
950 if(m->dc.font.descent < (*xfonts)->descent) |
904 dc.font.descent = (*xfonts)->descent; |
951 m->dc.font.descent = (*xfonts)->descent; |
905 xfonts++; |
952 xfonts++; |
906 } |
953 } |
907 } |
954 } |
908 else { |
955 else { |
909 if(dc.font.xfont) |
956 if(m->dc.font.xfont) |
910 XFreeFont(dpy, dc.font.xfont); |
957 XFreeFont(dpy, m->dc.font.xfont); |
911 dc.font.xfont = NULL; |
958 m->dc.font.xfont = NULL; |
912 if(!(dc.font.xfont = XLoadQueryFont(dpy, fontstr)) |
959 if(!(m->dc.font.xfont = XLoadQueryFont(dpy, fontstr)) |
913 && !(dc.font.xfont = XLoadQueryFont(dpy, "fixed"))) |
960 && !(m->dc.font.xfont = XLoadQueryFont(dpy, "fixed"))) |
914 eprint("error, cannot load font: '%s'\n", fontstr); |
961 eprint("error, cannot load font: '%s'\n", fontstr); |
915 dc.font.ascent = dc.font.xfont->ascent; |
962 m->dc.font.ascent = m->dc.font.xfont->ascent; |
916 dc.font.descent = dc.font.xfont->descent; |
963 m->dc.font.descent = m->dc.font.xfont->descent; |
917 } |
964 } |
918 dc.font.height = dc.font.ascent + dc.font.descent; |
965 m->dc.font.height = m->dc.font.ascent + m->dc.font.descent; |
919 } |
966 } |
920 |
967 |
921 Bool |
968 Bool |
922 isoccupied(unsigned int t) { |
969 isoccupied(Monitor *m, unsigned int t) { |
923 Client *c; |
970 Client *c; |
924 |
971 |
925 for(c = clients; c; c = c->next) |
972 for(c = clients; c; c = c->next) |
926 if(c->tags[t]) |
973 if(c->tags[t] && c->monitor == m->id) |
927 return True; |
974 return True; |
928 return False; |
975 return False; |
929 } |
976 } |
930 |
977 |
931 Bool |
978 Bool |
1007 XWindowChanges wc; |
1054 XWindowChanges wc; |
1008 |
1055 |
1009 c = emallocz(sizeof(Client)); |
1056 c = emallocz(sizeof(Client)); |
1010 c->tags = emallocz(sizeof seltags); |
1057 c->tags = emallocz(sizeof seltags); |
1011 c->win = w; |
1058 c->win = w; |
1012 c->x = wa->x; |
1059 |
1013 c->y = wa->y; |
1060 applyrules(c); |
|
1061 Monitor *m = &monitors[c->monitor]; |
|
1062 |
|
1063 c->x = wa->x+m->sx; |
|
1064 c->y = wa->y+m->sy; |
1014 c->w = wa->width; |
1065 c->w = wa->width; |
1015 c->h = wa->height; |
1066 c->h = wa->height; |
1016 c->oldborder = wa->border_width; |
1067 c->oldborder = wa->border_width; |
1017 if(c->w == sw && c->h == sh) { |
1068 |
1018 c->x = sx; |
1069 if (monitorat(c->x, c->y) != c->monitor) { |
1019 c->y = sy; |
1070 c->x = m->sx; |
|
1071 c->y = m->sy; |
|
1072 } |
|
1073 |
|
1074 if(c->w == m->sw && c->h == m->sh) { |
|
1075 c->x = m->sx; |
|
1076 c->y = m->sy; |
1020 c->border = wa->border_width; |
1077 c->border = wa->border_width; |
1021 } |
1078 } |
1022 else { |
1079 else { |
1023 if(c->x + c->w + 2 * c->border > wax + waw) |
1080 if(c->x + c->w + 2 * c->border > m->wax + m->waw) |
1024 c->x = wax + waw - c->w - 2 * c->border; |
1081 c->x = m->wax + m->waw - c->w - 2 * c->border; |
1025 if(c->y + c->h + 2 * c->border > way + wah) |
1082 if(c->y + c->h + 2 * c->border > m->way + m->wah) |
1026 c->y = way + wah - c->h - 2 * c->border; |
1083 c->y = m->way + m->wah - c->h - 2 * c->border; |
1027 if(c->x < wax) |
1084 if(c->x < m->wax) |
1028 c->x = wax; |
1085 c->x = m->wax; |
1029 if(c->y < way) |
1086 if(c->y < m->way) |
1030 c->y = way; |
1087 c->y = m->way; |
1031 c->border = BORDERPX; |
1088 c->border = BORDERPX; |
1032 } |
1089 } |
1033 wc.border_width = c->border; |
1090 wc.border_width = c->border; |
1034 XConfigureWindow(dpy, w, CWBorderWidth, &wc); |
1091 XConfigureWindow(dpy, w, CWBorderWidth, &wc); |
1035 XSetWindowBorder(dpy, w, dc.norm[ColBorder]); |
1092 XSetWindowBorder(dpy, w, m->dc.norm[ColBorder]); |
1036 configure(c); /* propagates border_width, if size doesn't change */ |
1093 configure(c); /* propagates border_width, if size doesn't change */ |
1037 updatesizehints(c); |
1094 updatesizehints(c); |
1038 XSelectInput(dpy, w, EnterWindowMask | FocusChangeMask | PropertyChangeMask | StructureNotifyMask); |
1095 XSelectInput(dpy, w, EnterWindowMask | FocusChangeMask | PropertyChangeMask | StructureNotifyMask); |
1039 grabbuttons(c, False); |
1096 grabbuttons(c, False); |
1040 updatetitle(c); |
1097 updatetitle(c); |
1041 if((rettrans = XGetTransientForHint(dpy, w, &trans) == Success)) |
1098 if((rettrans = XGetTransientForHint(dpy, w, &trans) == Success)) |
1042 for(t = clients; t && t->win != trans; t = t->next); |
1099 for(t = clients; t && t->win != trans; t = t->next); |
1043 if(t) |
1100 if(t) |
1044 memcpy(c->tags, t->tags, sizeof seltags); |
1101 memcpy(c->tags, t->tags, sizeof seltags); |
1045 applyrules(c); |
|
1046 if(!c->isfloating) |
1102 if(!c->isfloating) |
1047 c->isfloating = (rettrans == Success) || c->isfixed; |
1103 c->isfloating = (rettrans == Success) || c->isfixed; |
1048 attach(c); |
1104 attach(c); |
1049 attachstack(c); |
1105 attachstack(c); |
1050 XMoveResizeWindow(dpy, c->win, c->x, c->y, c->w, c->h); /* some windows require this */ |
1106 XMoveResizeWindow(dpy, c->win, c->x, c->y, c->w, c->h); /* some windows require this */ |
1109 break; |
1167 break; |
1110 case MotionNotify: |
1168 case MotionNotify: |
1111 XSync(dpy, False); |
1169 XSync(dpy, False); |
1112 nx = ocx + (ev.xmotion.x - x1); |
1170 nx = ocx + (ev.xmotion.x - x1); |
1113 ny = ocy + (ev.xmotion.y - y1); |
1171 ny = ocy + (ev.xmotion.y - y1); |
1114 if(abs(wax + nx) < SNAP) |
1172 Monitor *m = &monitors[monitorat(nx, ny)]; |
1115 nx = wax; |
1173 if(abs(m->wax - nx) < SNAP) |
1116 else if(abs((wax + waw) - (nx + c->w + 2 * c->border)) < SNAP) |
1174 nx = m->wax; |
1117 nx = wax + waw - c->w - 2 * c->border; |
1175 else if(abs((m->wax + m->waw) - (nx + c->w + 2 * c->border)) < SNAP) |
1118 if(abs(way - ny) < SNAP) |
1176 nx = m->wax + m->waw - c->w - 2 * c->border; |
1119 ny = way; |
1177 if(abs(m->way - ny) < SNAP) |
1120 else if(abs((way + wah) - (ny + c->h + 2 * c->border)) < SNAP) |
1178 ny = m->way; |
1121 ny = way + wah - c->h - 2 * c->border; |
1179 else if(abs((m->way + m->wah) - (ny + c->h + 2 * c->border)) < SNAP) |
|
1180 ny = m->way + m->wah - c->h - 2 * c->border; |
1122 resize(c, nx, ny, c->w, c->h, False); |
1181 resize(c, nx, ny, c->w, c->h, False); |
|
1182 memcpy(c->tags, monitors[monitorat(nx, ny)].seltags, sizeof seltags); |
1123 break; |
1183 break; |
1124 } |
1184 } |
1125 } |
1185 } |
1126 } |
1186 } |
1127 |
1187 |
1128 Client * |
1188 Client * |
1129 nexttiled(Client *c) { |
1189 nexttiled(Client *c, Monitor *m) { |
1130 for(; c && (c->isfloating || !isvisible(c)); c = c->next); |
1190 for(; c && (c->isfloating || !isvisible(c, m)); c = c->next); |
1131 return c; |
1191 return c; |
1132 } |
1192 } |
1133 |
1193 |
1134 void |
1194 void |
1135 propertynotify(XEvent *e) { |
1195 propertynotify(XEvent *e) { |
1282 void |
1346 void |
1283 restack(void) { |
1347 restack(void) { |
1284 Client *c; |
1348 Client *c; |
1285 XEvent ev; |
1349 XEvent ev; |
1286 XWindowChanges wc; |
1350 XWindowChanges wc; |
|
1351 int s; |
1287 |
1352 |
1288 drawbar(); |
1353 drawbar(); |
1289 if(!sel) |
1354 if(!sel) |
1290 return; |
1355 return; |
1291 if(sel->isfloating || (layout->arrange == floating)) |
1356 if(sel->isfloating || (monitors[selmonitor].layout->arrange == floating)) |
1292 XRaiseWindow(dpy, sel->win); |
1357 XRaiseWindow(dpy, sel->win); |
1293 if(layout->arrange != floating) { |
1358 if(monitors[selmonitor].layout->arrange != floating) { |
1294 wc.stack_mode = Below; |
1359 wc.stack_mode = Below; |
1295 wc.sibling = barwin; |
1360 wc.sibling = monitors[selmonitor].barwin; |
1296 if(!sel->isfloating) { |
1361 if(!sel->isfloating) { |
1297 XConfigureWindow(dpy, sel->win, CWSibling | CWStackMode, &wc); |
1362 XConfigureWindow(dpy, sel->win, CWSibling | CWStackMode, &wc); |
1298 wc.sibling = sel->win; |
1363 wc.sibling = sel->win; |
1299 } |
1364 } |
1300 for(c = nexttiled(clients); c; c = nexttiled(c->next)) { |
1365 for(s = 0; s < mcount; s++) { |
1301 if(c == sel) |
1366 for(c = nexttiled(clients, &monitors[s]); c; c = nexttiled(c->next, &monitors[s])) { |
1302 continue; |
1367 if(c == sel) |
1303 XConfigureWindow(dpy, c->win, CWSibling | CWStackMode, &wc); |
1368 continue; |
1304 wc.sibling = c->win; |
1369 XConfigureWindow(dpy, c->win, CWSibling | CWStackMode, &wc); |
|
1370 wc.sibling = c->win; |
|
1371 } |
1305 } |
1372 } |
1306 } |
1373 } |
1307 XSync(dpy, False); |
1374 XSync(dpy, False); |
1308 while(XCheckMaskEvent(dpy, EnterWindowMask, &ev)); |
1375 while(XCheckMaskEvent(dpy, EnterWindowMask, &ev)); |
1309 } |
1376 } |
1427 |
1496 |
1428 void |
1497 void |
1429 setmwfact(const char *arg) { |
1498 setmwfact(const char *arg) { |
1430 double delta; |
1499 double delta; |
1431 |
1500 |
|
1501 Monitor *m = &monitors[monitorat(-1, -1)]; |
|
1502 |
1432 if(!domwfact) |
1503 if(!domwfact) |
1433 return; |
1504 return; |
1434 /* arg handling, manipulate mwfact */ |
1505 /* arg handling, manipulate mwfact */ |
1435 if(arg == NULL) |
1506 if(arg == NULL) |
1436 mwfact = MWFACT; |
1507 m->mwfact = MWFACT; |
1437 else if(sscanf(arg, "%lf", &delta) == 1) { |
1508 else if(sscanf(arg, "%lf", &delta) == 1) { |
1438 if(arg[0] == '+' || arg[0] == '-') |
1509 if(arg[0] == '+' || arg[0] == '-') |
1439 mwfact += delta; |
1510 m->mwfact += delta; |
1440 else |
1511 else |
1441 mwfact = delta; |
1512 m->mwfact = delta; |
1442 if(mwfact < 0.1) |
1513 if(m->mwfact < 0.1) |
1443 mwfact = 0.1; |
1514 m->mwfact = 0.1; |
1444 else if(mwfact > 0.9) |
1515 else if(m->mwfact > 0.9) |
1445 mwfact = 0.9; |
1516 m->mwfact = 0.9; |
1446 } |
1517 } |
1447 arrange(); |
1518 arrange(); |
1448 } |
1519 } |
1449 |
1520 |
1450 void |
1521 void |
1451 setup(void) { |
1522 setup(void) { |
1452 int d; |
1523 unsigned int i, j, k; |
1453 unsigned int i, j, mask; |
|
1454 Window w; |
|
1455 XModifierKeymap *modmap; |
1524 XModifierKeymap *modmap; |
1456 XSetWindowAttributes wa; |
1525 XSetWindowAttributes wa; |
|
1526 int s = 1; |
|
1527 GC g; |
|
1528 XineramaScreenInfo *info = NULL; |
1457 |
1529 |
1458 /* init atoms */ |
1530 /* init atoms */ |
1459 wmatom[WMProtocols] = XInternAtom(dpy, "WM_PROTOCOLS", False); |
1531 wmatom[WMProtocols] = XInternAtom(dpy, "WM_PROTOCOLS", False); |
1460 wmatom[WMDelete] = XInternAtom(dpy, "WM_DELETE_WINDOW", False); |
1532 wmatom[WMDelete] = XInternAtom(dpy, "WM_DELETE_WINDOW", False); |
1461 wmatom[WMName] = XInternAtom(dpy, "WM_NAME", False); |
1533 wmatom[WMName] = XInternAtom(dpy, "WM_NAME", False); |
1494 |
1562 |
1495 /* grab keys */ |
1563 /* grab keys */ |
1496 grabkeys(); |
1564 grabkeys(); |
1497 |
1565 |
1498 /* init tags */ |
1566 /* init tags */ |
1499 memcpy(prevtags, seltags, sizeof seltags); |
|
1500 compileregs(); |
1567 compileregs(); |
1501 |
1568 |
1502 /* init appearance */ |
1569 if (XineramaIsActive(dpy)) { |
1503 dc.norm[ColBorder] = getcolor(NORMBORDERCOLOR); |
1570 info = XineramaQueryScreens(dpy, &s); |
1504 dc.norm[ColBG] = getcolor(NORMBGCOLOR); |
1571 } |
1505 dc.norm[ColFG] = getcolor(NORMFGCOLOR); |
1572 |
1506 dc.sel[ColBorder] = getcolor(SELBORDERCOLOR); |
1573 monitors = emallocz(s*sizeof(Monitor)); |
1507 dc.sel[ColBG] = getcolor(SELBGCOLOR); |
1574 mcount = s; |
1508 dc.sel[ColFG] = getcolor(SELFGCOLOR); |
1575 |
1509 initfont(FONT); |
1576 for(i = 0; i < s; i++) { |
1510 dc.h = bh = dc.font.height + 2; |
1577 /* init geometry */ |
1511 |
1578 if (mcount != 1) { |
1512 /* init layouts */ |
1579 monitors[i].sx = info[i].x_org; |
1513 mwfact = MWFACT; |
1580 monitors[i].sy = info[i].y_org; |
1514 layout = &layouts[0]; |
1581 monitors[i].sw = info[i].width; |
1515 for(blw = i = 0; i < LENGTH(layouts); i++) { |
1582 monitors[i].sh = info[i].height; |
1516 j = textw(layouts[i].symbol); |
1583 } |
1517 if(j > blw) |
1584 else { |
1518 blw = j; |
1585 monitors[i].sx = 0; |
1519 } |
1586 monitors[i].sy = 0; |
1520 |
1587 monitors[i].sw = DisplayWidth(dpy, screen); |
1521 /* init bar */ |
1588 monitors[i].sh = DisplayHeight(dpy, screen); |
1522 bpos = BARPOS; |
1589 } |
1523 wa.override_redirect = 1; |
1590 |
1524 wa.background_pixmap = ParentRelative; |
1591 monitors[i].id = i; |
1525 wa.event_mask = ButtonPressMask | ExposureMask; |
1592 monitors[i].seltags = emallocz(LENGTH(tags)*sizeof(char*)); |
1526 barwin = XCreateWindow(dpy, root, sx, sy, sw, bh, 0, |
1593 monitors[i].prevtags = emallocz(LENGTH(tags)*sizeof(char*)); |
1527 DefaultDepth(dpy, screen), CopyFromParent, DefaultVisual(dpy, screen), |
1594 |
1528 CWOverrideRedirect | CWBackPixmap | CWEventMask, &wa); |
1595 memcpy(monitors[i].seltags, seltags, sizeof seltags); |
1529 XDefineCursor(dpy, barwin, cursor[CurNormal]); |
1596 memcpy(monitors[i].prevtags, seltags, sizeof seltags); |
1530 updatebarpos(); |
1597 |
1531 XMapRaised(dpy, barwin); |
1598 /* init appearance */ |
1532 strcpy(stext, "dwm-"VERSION); |
1599 monitors[i].dc.norm[ColBorder] = getcolor(NORMBORDERCOLOR); |
1533 dc.drawable = XCreatePixmap(dpy, root, sw, bh, DefaultDepth(dpy, screen)); |
1600 monitors[i].dc.norm[ColBG] = getcolor(NORMBGCOLOR); |
1534 dc.gc = XCreateGC(dpy, root, 0, 0); |
1601 monitors[i].dc.norm[ColFG] = getcolor(NORMFGCOLOR); |
1535 XSetLineAttributes(dpy, dc.gc, 1, LineSolid, CapButt, JoinMiter); |
1602 monitors[i].dc.sel[ColBorder] = getcolor(SELBORDERCOLOR); |
1536 if(!dc.font.set) |
1603 monitors[i].dc.sel[ColBG] = getcolor(SELBGCOLOR); |
1537 XSetFont(dpy, dc.gc, dc.font.xfont->fid); |
1604 monitors[i].dc.sel[ColFG] = getcolor(SELFGCOLOR); |
1538 |
1605 initfont(&(monitors[i]), FONT); |
1539 /* multihead support */ |
1606 monitors[i].dc.h = bh = monitors[i].dc.font.height + 2; |
1540 selscreen = XQueryPointer(dpy, root, &w, &w, &d, &d, &d, &d, &mask); |
1607 |
1541 |
1608 /* init layouts */ |
|
1609 monitors[i].mwfact = MWFACT; |
|
1610 monitors[i].layout = &layouts[0]; |
|
1611 for(blw = k = 0; k < LENGTH(layouts); k++) { |
|
1612 j = textw(&monitors[i], layouts[k].symbol); |
|
1613 if(j > blw) |
|
1614 blw = j; |
|
1615 } |
|
1616 |
|
1617 bpos = BARPOS; |
|
1618 wa.override_redirect = 1; |
|
1619 wa.background_pixmap = ParentRelative; |
|
1620 wa.event_mask = ButtonPressMask | ExposureMask; |
|
1621 |
|
1622 /* init bars */ |
|
1623 monitors[i].barwin = XCreateWindow(dpy, root, monitors[i].sx, monitors[i].sy, monitors[i].sw, bh, 0, |
|
1624 DefaultDepth(dpy, screen), CopyFromParent, DefaultVisual(dpy, screen), |
|
1625 CWOverrideRedirect | CWBackPixmap | CWEventMask, &wa); |
|
1626 XDefineCursor(dpy, monitors[i].barwin, cursor[CurNormal]); |
|
1627 updatebarpos(&monitors[i]); |
|
1628 XMapRaised(dpy, monitors[i].barwin); |
|
1629 strcpy(stext, "dwm-"VERSION); |
|
1630 monitors[i].dc.drawable = XCreatePixmap(dpy, root, monitors[i].sw, bh, DefaultDepth(dpy, screen)); |
|
1631 g = XCreateGC(dpy, root, 0, 0); |
|
1632 monitors[i].dc.gc = XCreateGC(dpy, root, 0, 0); |
|
1633 XSetLineAttributes(dpy, monitors[i].dc.gc, 1, LineSolid, CapButt, JoinMiter); |
|
1634 if(!monitors[i].dc.font.set) |
|
1635 XSetFont(dpy, monitors[i].dc.gc, monitors[i].dc.font.xfont->fid); |
|
1636 } |
1542 } |
1637 } |
1543 |
1638 |
1544 void |
1639 void |
1545 spawn(const char *arg) { |
1640 spawn(const char *arg) { |
1546 static char *shell = NULL; |
1641 static char *shell = NULL; |
1576 sel->tags[idxoftag(arg)] = True; |
1671 sel->tags[idxoftag(arg)] = True; |
1577 arrange(); |
1672 arrange(); |
1578 } |
1673 } |
1579 |
1674 |
1580 unsigned int |
1675 unsigned int |
1581 textnw(const char *text, unsigned int len) { |
1676 textnw(Monitor *m, const char *text, unsigned int len) { |
1582 XRectangle r; |
1677 XRectangle r; |
1583 |
1678 |
1584 if(dc.font.set) { |
1679 if(m->dc.font.set) { |
1585 XmbTextExtents(dc.font.set, text, len, NULL, &r); |
1680 XmbTextExtents(m->dc.font.set, text, len, NULL, &r); |
1586 return r.width; |
1681 return r.width; |
1587 } |
1682 } |
1588 return XTextWidth(dc.font.xfont, text, len); |
1683 return XTextWidth(m->dc.font.xfont, text, len); |
1589 } |
1684 } |
1590 |
1685 |
1591 unsigned int |
1686 unsigned int |
1592 textw(const char *text) { |
1687 textw(Monitor *m, const char *text) { |
1593 return textnw(text, strlen(text)) + dc.font.height; |
1688 return textnw(m, text, strlen(text)) + m->dc.font.height; |
1594 } |
1689 } |
1595 |
1690 |
1596 void |
1691 void |
1597 tile(void) { |
1692 tile(void) { |
1598 unsigned int i, n, nx, ny, nw, nh, mw, th; |
1693 unsigned int i, n, nx, ny, nw, nh, mw, th; |
|
1694 int s; |
1599 Client *c, *mc; |
1695 Client *c, *mc; |
1600 |
1696 |
1601 domwfact = dozoom = True; |
1697 domwfact = dozoom = True; |
1602 for(n = 0, c = nexttiled(clients); c; c = nexttiled(c->next)) |
1698 |
1603 n++; |
|
1604 |
|
1605 /* window geoms */ |
|
1606 mw = (n == 1) ? waw : mwfact * waw; |
|
1607 th = (n > 1) ? wah / (n - 1) : 0; |
|
1608 if(n > 1 && th < bh) |
|
1609 th = wah; |
|
1610 |
|
1611 nx = wax; |
|
1612 ny = way; |
|
1613 nw = 0; /* gcc stupidity requires this */ |
1699 nw = 0; /* gcc stupidity requires this */ |
1614 for(i = 0, c = mc = nexttiled(clients); c; c = nexttiled(c->next), i++) { |
1700 |
1615 if(i == 0) { /* master */ |
1701 for (s = 0; s < mcount; s++) { |
1616 nw = mw - 2 * c->border; |
1702 Monitor *m = &monitors[s]; |
1617 nh = wah - 2 * c->border; |
1703 |
1618 } |
1704 for(n = 0, c = nexttiled(clients, m); c; c = nexttiled(c->next, m)) |
1619 else { /* tile window */ |
1705 n++; |
1620 if(i == 1) { |
1706 |
1621 ny = way; |
1707 for(i = 0, c = mc = nexttiled(clients, m); c; c = nexttiled(c->next, m)) { |
1622 nx += mc->w + 2 * mc->border; |
1708 /* window geoms */ |
1623 nw = waw - nx - 2 * c->border; |
1709 mw = (n == 1) ? m->waw : m->mwfact * m->waw; |
|
1710 th = (n > 1) ? m->wah / (n - 1) : 0; |
|
1711 if(n > 1 && th < bh) |
|
1712 th = m->wah; |
|
1713 if(i == 0) { /* master */ |
|
1714 nx = m->wax; |
|
1715 ny = m->way; |
|
1716 nw = mw - 2 * c->border; |
|
1717 nh = m->wah - 2 * c->border; |
1624 } |
1718 } |
1625 if(i + 1 == n) /* remainder */ |
1719 else { /* tile window */ |
1626 nh = (way + wah) - ny - 2 * c->border; |
1720 if(i == 1) { |
1627 else |
1721 ny = m->way; |
1628 nh = th - 2 * c->border; |
1722 nx += mc->w + 2 * mc->border; |
1629 } |
1723 nw = m->waw - mw - 2 * c->border; |
1630 resize(c, nx, ny, nw, nh, RESIZEHINTS); |
1724 } |
1631 if((RESIZEHINTS) && ((c->h < bh) || (c->h > nh) || (c->w < bh) || (c->w > nw))) |
1725 if(i + 1 == n) /* remainder */ |
1632 /* client doesn't accept size constraints */ |
1726 nh = (m->way + m->wah) - ny - 2 * c->border; |
1633 resize(c, nx, ny, nw, nh, False); |
1727 else |
1634 if(n > 1 && th != wah) |
1728 nh = th - 2 * c->border; |
1635 ny = c->y + c->h + 2 * c->border; |
1729 } |
1636 } |
1730 resize(c, nx, ny, nw, nh, RESIZEHINTS); |
1637 } |
1731 if((RESIZEHINTS) && ((c->h < bh) || (c->h > nh) || (c->w < bh) || (c->w > nw))) |
1638 |
1732 /* client doesn't accept size constraints */ |
|
1733 resize(c, nx, ny, nw, nh, False); |
|
1734 if(n > 1 && th != m->wah) |
|
1735 ny = c->y + c->h + 2 * c->border; |
|
1736 |
|
1737 i++; |
|
1738 } |
|
1739 } |
|
1740 } |
1639 void |
1741 void |
1640 togglebar(const char *arg) { |
1742 togglebar(const char *arg) { |
1641 if(bpos == BarOff) |
1743 if(bpos == BarOff) |
1642 bpos = (BARPOS == BarOff) ? BarTop : BARPOS; |
1744 bpos = (BARPOS == BarOff) ? BarTop : BARPOS; |
1643 else |
1745 else |
1644 bpos = BarOff; |
1746 bpos = BarOff; |
1645 updatebarpos(); |
1747 updatebarpos(&monitors[monitorat(-1,-1)]); |
1646 arrange(); |
1748 arrange(); |
1647 } |
1749 } |
1648 |
1750 |
1649 void |
1751 void |
1650 togglefloating(const char *arg) { |
1752 togglefloating(const char *arg) { |
1840 |
1944 |
1841 void |
1945 void |
1842 view(const char *arg) { |
1946 view(const char *arg) { |
1843 unsigned int i; |
1947 unsigned int i; |
1844 |
1948 |
1845 memcpy(prevtags, seltags, sizeof seltags); |
1949 Monitor *m = &monitors[monitorat(-1, -1)]; |
|
1950 |
|
1951 memcpy(m->prevtags, seltags, sizeof seltags); |
1846 for(i = 0; i < LENGTH(tags); i++) |
1952 for(i = 0; i < LENGTH(tags); i++) |
1847 seltags[i] = (NULL == arg); |
1953 m->seltags[i] = (NULL == arg); |
1848 seltags[idxoftag(arg)] = True; |
1954 m->seltags[idxoftag(arg)] = True; |
1849 arrange(); |
1955 arrange(); |
1850 } |
1956 } |
1851 |
1957 |
1852 void |
1958 void |
1853 viewprevtag(const char *arg) { |
1959 viewprevtag(const char *arg) { |
1854 static Bool tmp[LENGTH(tags)]; |
1960 static Bool tmp[LENGTH(tags)]; |
1855 |
1961 |
1856 memcpy(tmp, seltags, sizeof seltags); |
1962 Monitor *m = &monitors[monitorat(-1, -1)]; |
1857 memcpy(seltags, prevtags, sizeof seltags); |
1963 |
1858 memcpy(prevtags, tmp, sizeof seltags); |
1964 memcpy(tmp, m->seltags, sizeof seltags); |
|
1965 memcpy(m->seltags, m->prevtags, sizeof seltags); |
|
1966 memcpy(m->prevtags, tmp, sizeof seltags); |
1859 arrange(); |
1967 arrange(); |
1860 } |
1968 } |
1861 |
1969 |
1862 void |
1970 void |
1863 zoom(const char *arg) { |
1971 zoom(const char *arg) { |
1864 Client *c; |
1972 Client *c; |
1865 |
1973 |
1866 if(!sel || !dozoom || sel->isfloating) |
1974 if(!sel || !dozoom || sel->isfloating) |
1867 return; |
1975 return; |
1868 if((c = sel) == nexttiled(clients)) |
1976 if((c = sel) == nexttiled(clients, &monitors[c->monitor])) |
1869 if(!(c = nexttiled(c->next))) |
1977 if(!(c = nexttiled(c->next, &monitors[c->monitor]))) |
1870 return; |
1978 return; |
1871 detach(c); |
1979 detach(c); |
1872 attach(c); |
1980 attach(c); |
1873 focus(c); |
1981 focus(c); |
1874 arrange(); |
1982 arrange(); |
1875 } |
1983 } |
|
1984 |
|
1985 int |
|
1986 monitorat(int x, int y) { |
|
1987 int i; |
|
1988 |
|
1989 if(!XineramaIsActive(dpy)) |
|
1990 return 0; |
|
1991 |
|
1992 if (x < 0 || y < 0) { |
|
1993 Window win; |
|
1994 unsigned int mask; |
|
1995 XQueryPointer(dpy, root, &win, &win, &x, &y, &i, &i, &mask); |
|
1996 } |
|
1997 |
|
1998 for(i = 0; i < mcount; i++) |
|
1999 if((x < 0 || (x >= monitors[i].sx && x < monitors[i].sx + monitors[i].sw)) |
|
2000 && (y < 0 || (y >= monitors[i].sy && y < monitors[i].sy + monitors[i].sh))) |
|
2001 { |
|
2002 return i; |
|
2003 } |
|
2004 return 0; |
|
2005 } |
|
2006 |
|
2007 void |
|
2008 movetomonitor(const char *arg) { |
|
2009 if (sel) { |
|
2010 sel->monitor = arg ? atoi(arg) : (sel->monitor+1) % mcount; |
|
2011 |
|
2012 memcpy(sel->tags, monitors[sel->monitor].seltags, sizeof seltags); |
|
2013 resize(sel, monitors[sel->monitor].wax, monitors[sel->monitor].way, sel->w, sel->h, True); |
|
2014 arrange(); |
|
2015 } |
|
2016 } |
|
2017 |
|
2018 void |
|
2019 selectmonitor(const char *arg) { |
|
2020 Monitor *m = &monitors[arg ? atoi(arg) : (monitorat(-1, -1)+1) % mcount]; |
|
2021 |
|
2022 XWarpPointer(dpy, None, root, 0, 0, 0, 0, m->wax+m->waw/2, m->way+m->wah/2); |
|
2023 focus(NULL); |
|
2024 } |
|
2025 |
1876 |
2026 |
1877 int |
2027 int |
1878 main(int argc, char *argv[]) { |
2028 main(int argc, char *argv[]) { |
1879 if(argc == 2 && !strcmp("-v", argv[1])) |
2029 if(argc == 2 && !strcmp("-v", argv[1])) |
1880 eprint("dwm-"VERSION", © 2006-2007 Anselm R. Garbe, Sander van Dijk, " |
2030 eprint("dwm-"VERSION", © 2006-2007 Anselm R. Garbe, Sander van Dijk, " |