21 | 21 |
*/
|
22 | 22 |
#include <errno.h>
|
23 | 23 |
#include <locale.h>
|
|
24 |
#include <signal.h>
|
24 | 25 |
#include <stdarg.h>
|
25 | |
#include <signal.h>
|
26 | 26 |
#include <stdio.h>
|
27 | 27 |
#include <stdlib.h>
|
28 | 28 |
#include <string.h>
|
|
38 | 38 |
#ifdef XINERAMA
|
39 | 39 |
#include <X11/extensions/Xinerama.h>
|
40 | 40 |
#endif /* XINERAMA */
|
|
41 |
#include <X11/Xft/Xft.h>
|
|
42 |
|
|
43 |
#include "drw.h"
|
|
44 |
#include "util.h"
|
41 | 45 |
|
42 | 46 |
/* macros */
|
43 | 47 |
#define BUTTONMASK (ButtonPressMask|ButtonReleaseMask)
|
|
46 | 50 |
* MAX(0, MIN((y)+(h),(m)->wy+(m)->wh) - MAX((y),(m)->wy)))
|
47 | 51 |
#define ISVISIBLE(C) ((C->tags & C->mon->tagset[C->mon->seltags]))
|
48 | 52 |
#define LENGTH(X) (sizeof X / sizeof X[0])
|
49 | |
#define MAX(A, B) ((A) > (B) ? (A) : (B))
|
50 | |
#define MIN(A, B) ((A) < (B) ? (A) : (B))
|
51 | 53 |
#define MOUSEMASK (BUTTONMASK|PointerMotionMask)
|
52 | 54 |
#define WIDTH(X) ((X)->w + 2 * (X)->bw)
|
53 | 55 |
#define HEIGHT(X) ((X)->h + 2 * (X)->bw)
|
54 | 56 |
#define TAGMASK ((1 << LENGTH(tags)) - 1)
|
55 | |
#define TEXTW(X) (textnw(X, strlen(X)) + dc.font.height)
|
|
57 |
#define TEXTW(X) (drw_text(drw, 0, 0, 0, 0, (X), 0) + drw->fonts[0]->h)
|
56 | 58 |
|
57 | 59 |
/* enums */
|
58 | |
enum { CurNormal, CurResize, CurMove, CurLast }; /* cursor */
|
59 | |
enum { ColBorder, ColFG, ColBG, ColLast }; /* color */
|
|
60 |
enum { CurNormal, CurResize, CurMove, CurLast }; /* cursor */
|
|
61 |
enum { SchemeNorm, SchemeSel, SchemeLast }; /* color schemes */
|
60 | 62 |
enum { NetSupported, NetWMName, NetWMState,
|
61 | 63 |
NetWMFullscreen, NetActiveWindow, NetWMWindowType,
|
62 | |
NetWMWindowTypeDialog, NetLast }; /* EWMH atoms */
|
|
64 |
NetWMWindowTypeDialog, NetClientList, NetLast }; /* EWMH atoms */
|
63 | 65 |
enum { WMProtocols, WMDelete, WMState, WMTakeFocus, WMLast }; /* default atoms */
|
64 | 66 |
enum { ClkTagBar, ClkLtSymbol, ClkStatusText, ClkWinTitle,
|
65 | |
ClkClientWin, ClkRootWin, ClkLast }; /* clicks */
|
|
67 |
ClkClientWin, ClkRootWin, ClkLast }; /* clicks */
|
66 | 68 |
|
67 | 69 |
typedef union {
|
68 | 70 |
int i;
|
|
89 | 91 |
int basew, baseh, incw, inch, maxw, maxh, minw, minh;
|
90 | 92 |
int bw, oldbw;
|
91 | 93 |
unsigned int tags;
|
92 | |
Bool isfixed, isfloating, isurgent, neverfocus, oldstate, isfullscreen;
|
|
94 |
int isfixed, isfloating, isurgent, neverfocus, oldstate, isfullscreen;
|
93 | 95 |
Client *next;
|
94 | 96 |
Client *snext;
|
95 | 97 |
Monitor *mon;
|
96 | 98 |
Window win;
|
97 | 99 |
};
|
98 | |
|
99 | |
typedef struct {
|
100 | |
int x, y, w, h;
|
101 | |
unsigned long norm[ColLast];
|
102 | |
unsigned long sel[ColLast];
|
103 | |
Drawable drawable;
|
104 | |
GC gc;
|
105 | |
struct {
|
106 | |
int ascent;
|
107 | |
int descent;
|
108 | |
int height;
|
109 | |
XFontSet set;
|
110 | |
XFontStruct *xfont;
|
111 | |
} font;
|
112 | |
} DC; /* draw context */
|
113 | 100 |
|
114 | 101 |
typedef struct {
|
115 | 102 |
unsigned int mod;
|
|
134 | 121 |
unsigned int seltags;
|
135 | 122 |
unsigned int sellt;
|
136 | 123 |
unsigned int tagset[2];
|
137 | |
Bool showbar;
|
138 | |
Bool topbar;
|
|
124 |
int showbar;
|
|
125 |
int topbar;
|
139 | 126 |
Client *clients;
|
140 | 127 |
Client *sel;
|
141 | 128 |
Client *stack;
|
|
149 | 136 |
const char *instance;
|
150 | 137 |
const char *title;
|
151 | 138 |
unsigned int tags;
|
152 | |
Bool isfloating;
|
|
139 |
int isfloating;
|
153 | 140 |
int monitor;
|
154 | 141 |
} Rule;
|
155 | 142 |
|
156 | 143 |
/* function declarations */
|
157 | 144 |
static void applyrules(Client *c);
|
158 | |
static Bool applysizehints(Client *c, int *x, int *y, int *w, int *h, Bool interact);
|
|
145 |
static int applysizehints(Client *c, int *x, int *y, int *w, int *h, int interact);
|
159 | 146 |
static void arrange(Monitor *m);
|
160 | 147 |
static void arrangemon(Monitor *m);
|
161 | 148 |
static void attach(Client *c);
|
|
173 | 160 |
static void destroynotify(XEvent *e);
|
174 | 161 |
static void detach(Client *c);
|
175 | 162 |
static void detachstack(Client *c);
|
176 | |
static void die(const char *errstr, ...);
|
177 | 163 |
static Monitor *dirtomon(int dir);
|
178 | 164 |
static void drawbar(Monitor *m);
|
179 | 165 |
static void drawbars(void);
|
180 | |
static void drawsquare(Bool filled, Bool empty, Bool invert, unsigned long col[ColLast]);
|
181 | |
static void drawtext(const char *text, unsigned long col[ColLast], Bool invert);
|
182 | 166 |
static void enternotify(XEvent *e);
|
183 | 167 |
static void expose(XEvent *e);
|
184 | 168 |
static void focus(Client *c);
|
185 | 169 |
static void focusin(XEvent *e);
|
186 | 170 |
static void focusmon(const Arg *arg);
|
187 | 171 |
static void focusstack(const Arg *arg);
|
188 | |
static unsigned long getcolor(const char *colstr);
|
189 | |
static Bool getrootptr(int *x, int *y);
|
|
172 |
static int getrootptr(int *x, int *y);
|
190 | 173 |
static long getstate(Window w);
|
191 | |
static Bool gettextprop(Window w, Atom atom, char *text, unsigned int size);
|
192 | |
static void grabbuttons(Client *c, Bool focused);
|
|
174 |
static int gettextprop(Window w, Atom atom, char *text, unsigned int size);
|
|
175 |
static void grabbuttons(Client *c, int focused);
|
193 | 176 |
static void grabkeys(void);
|
194 | 177 |
static void incnmaster(const Arg *arg);
|
195 | |
static void initfont(const char *fontstr);
|
196 | 178 |
static void keypress(XEvent *e);
|
197 | 179 |
static void killclient(const Arg *arg);
|
198 | 180 |
static void manage(Window w, XWindowAttributes *wa);
|
|
206 | 188 |
static void propertynotify(XEvent *e);
|
207 | 189 |
static void quit(const Arg *arg);
|
208 | 190 |
static Monitor *recttomon(int x, int y, int w, int h);
|
209 | |
static void resize(Client *c, int x, int y, int w, int h, Bool interact);
|
|
191 |
static void resize(Client *c, int x, int y, int w, int h, int interact);
|
210 | 192 |
static void resizeclient(Client *c, int x, int y, int w, int h);
|
211 | 193 |
static void resizemouse(const Arg *arg);
|
212 | 194 |
static void restack(Monitor *m);
|
213 | 195 |
static void run(void);
|
214 | 196 |
static void scan(void);
|
215 | |
static Bool sendevent(Client *c, Atom proto);
|
|
197 |
static int sendevent(Client *c, Atom proto);
|
216 | 198 |
static void sendmon(Client *c, Monitor *m);
|
217 | 199 |
static void setclientstate(Client *c, long state);
|
218 | 200 |
static void setfocus(Client *c);
|
219 | |
static void setfullscreen(Client *c, Bool fullscreen);
|
|
201 |
static void setfullscreen(Client *c, int fullscreen);
|
220 | 202 |
static void setlayout(const Arg *arg);
|
221 | 203 |
static void setmfact(const Arg *arg);
|
222 | 204 |
static void setup(void);
|
|
225 | 207 |
static void spawn(const Arg *arg);
|
226 | 208 |
static void tag(const Arg *arg);
|
227 | 209 |
static void tagmon(const Arg *arg);
|
228 | |
static int textnw(const char *text, unsigned int len);
|
229 | 210 |
static void tile(Monitor *);
|
230 | 211 |
static void togglebar(const Arg *arg);
|
231 | 212 |
static void togglefloating(const Arg *arg);
|
232 | 213 |
static void toggletag(const Arg *arg);
|
233 | 214 |
static void toggleview(const Arg *arg);
|
234 | |
static void unfocus(Client *c, Bool setfocus);
|
235 | |
static void unmanage(Client *c, Bool destroyed);
|
|
215 |
static void unfocus(Client *c, int setfocus);
|
|
216 |
static void unmanage(Client *c, int destroyed);
|
236 | 217 |
static void unmapnotify(XEvent *e);
|
237 | |
static Bool updategeom(void);
|
|
218 |
static int updategeom(void);
|
238 | 219 |
static void updatebarpos(Monitor *m);
|
239 | 220 |
static void updatebars(void);
|
|
221 |
static void updateclientlist(void);
|
240 | 222 |
static void updatenumlockmask(void);
|
241 | 223 |
static void updatesizehints(Client *c);
|
242 | 224 |
static void updatestatus(void);
|
|
276 | 258 |
[UnmapNotify] = unmapnotify
|
277 | 259 |
};
|
278 | 260 |
static Atom wmatom[WMLast], netatom[NetLast];
|
279 | |
static Bool running = True;
|
280 | |
static Cursor cursor[CurLast];
|
|
261 |
static int running = 1;
|
|
262 |
static Cur *cursor[CurLast];
|
|
263 |
static ClrScheme scheme[SchemeLast];
|
281 | 264 |
static Display *dpy;
|
282 | |
static DC dc;
|
283 | |
static Monitor *mons = NULL, *selmon = NULL;
|
|
265 |
static Drw *drw;
|
|
266 |
static Monitor *mons, *selmon;
|
284 | 267 |
static Window root;
|
285 | 268 |
|
286 | 269 |
/* configuration, allows nested code to access above variables */
|
|
291 | 274 |
|
292 | 275 |
/* function implementations */
|
293 | 276 |
void
|
294 | |
applyrules(Client *c) {
|
|
277 |
applyrules(Client *c)
|
|
278 |
{
|
295 | 279 |
const char *class, *instance;
|
296 | 280 |
unsigned int i;
|
297 | 281 |
const Rule *r;
|
|
299 | 283 |
XClassHint ch = { NULL, NULL };
|
300 | 284 |
|
301 | 285 |
/* rule matching */
|
302 | |
c->isfloating = c->tags = 0;
|
|
286 |
c->isfloating = 0;
|
|
287 |
c->tags = 0;
|
303 | 288 |
XGetClassHint(dpy, c->win, &ch);
|
304 | 289 |
class = ch.res_class ? ch.res_class : broken;
|
305 | 290 |
instance = ch.res_name ? ch.res_name : broken;
|
306 | 291 |
|
307 | |
for(i = 0; i < LENGTH(rules); i++) {
|
|
292 |
for (i = 0; i < LENGTH(rules); i++) {
|
308 | 293 |
r = &rules[i];
|
309 | |
if((!r->title || strstr(c->name, r->title))
|
|
294 |
if ((!r->title || strstr(c->name, r->title))
|
310 | 295 |
&& (!r->class || strstr(class, r->class))
|
311 | 296 |
&& (!r->instance || strstr(instance, r->instance)))
|
312 | 297 |
{
|
313 | 298 |
c->isfloating = r->isfloating;
|
314 | 299 |
c->tags |= r->tags;
|
315 | |
for(m = mons; m && m->num != r->monitor; m = m->next);
|
316 | |
if(m)
|
|
300 |
for (m = mons; m && m->num != r->monitor; m = m->next);
|
|
301 |
if (m)
|
317 | 302 |
c->mon = m;
|
318 | 303 |
}
|
319 | 304 |
}
|
320 | |
if(ch.res_class)
|
|
305 |
if (ch.res_class)
|
321 | 306 |
XFree(ch.res_class);
|
322 | |
if(ch.res_name)
|
|
307 |
if (ch.res_name)
|
323 | 308 |
XFree(ch.res_name);
|
324 | 309 |
c->tags = c->tags & TAGMASK ? c->tags & TAGMASK : c->mon->tagset[c->mon->seltags];
|
325 | 310 |
}
|
326 | 311 |
|
327 | |
Bool
|
328 | |
applysizehints(Client *c, int *x, int *y, int *w, int *h, Bool interact) {
|
329 | |
Bool baseismin;
|
|
312 |
int
|
|
313 |
applysizehints(Client *c, int *x, int *y, int *w, int *h, int interact)
|
|
314 |
{
|
|
315 |
int baseismin;
|
330 | 316 |
Monitor *m = c->mon;
|
331 | 317 |
|
332 | 318 |
/* set minimum possible */
|
333 | 319 |
*w = MAX(1, *w);
|
334 | 320 |
*h = MAX(1, *h);
|
335 | |
if(interact) {
|
336 | |
if(*x > sw)
|
|
321 |
if (interact) {
|
|
322 |
if (*x > sw)
|
337 | 323 |
*x = sw - WIDTH(c);
|
338 | |
if(*y > sh)
|
|
324 |
if (*y > sh)
|
339 | 325 |
*y = sh - HEIGHT(c);
|
340 | |
if(*x + *w + 2 * c->bw < 0)
|
|
326 |
if (*x + *w + 2 * c->bw < 0)
|
341 | 327 |
*x = 0;
|
342 | |
if(*y + *h + 2 * c->bw < 0)
|
|
328 |
if (*y + *h + 2 * c->bw < 0)
|
343 | 329 |
*y = 0;
|
344 | |
}
|
345 | |
else {
|
346 | |
if(*x >= m->wx + m->ww)
|
|
330 |
} else {
|
|
331 |
if (*x >= m->wx + m->ww)
|
347 | 332 |
*x = m->wx + m->ww - WIDTH(c);
|
348 | |
if(*y >= m->wy + m->wh)
|
|
333 |
if (*y >= m->wy + m->wh)
|
349 | 334 |
*y = m->wy + m->wh - HEIGHT(c);
|
350 | |
if(*x + *w + 2 * c->bw <= m->wx)
|
|
335 |
if (*x + *w + 2 * c->bw <= m->wx)
|
351 | 336 |
*x = m->wx;
|
352 | |
if(*y + *h + 2 * c->bw <= m->wy)
|
|
337 |
if (*y + *h + 2 * c->bw <= m->wy)
|
353 | 338 |
*y = m->wy;
|
354 | 339 |
}
|
355 | |
if(*h < bh)
|
|
340 |
if (*h < bh)
|
356 | 341 |
*h = bh;
|
357 | |
if(*w < bh)
|
|
342 |
if (*w < bh)
|
358 | 343 |
*w = bh;
|
359 | |
if(resizehints || c->isfloating || !c->mon->lt[c->mon->sellt]->arrange) {
|
|
344 |
if (resizehints || c->isfloating || !c->mon->lt[c->mon->sellt]->arrange) {
|
360 | 345 |
/* see last two sentences in ICCCM 4.1.2.3 */
|
361 | 346 |
baseismin = c->basew == c->minw && c->baseh == c->minh;
|
362 | |
if(!baseismin) { /* temporarily remove base dimensions */
|
|
347 |
if (!baseismin) { /* temporarily remove base dimensions */
|
363 | 348 |
*w -= c->basew;
|
364 | 349 |
*h -= c->baseh;
|
365 | 350 |
}
|
366 | 351 |
/* adjust for aspect limits */
|
367 | |
if(c->mina > 0 && c->maxa > 0) {
|
368 | |
if(c->maxa < (float)*w / *h)
|
|
352 |
if (c->mina > 0 && c->maxa > 0) {
|
|
353 |
if (c->maxa < (float)*w / *h)
|
369 | 354 |
*w = *h * c->maxa + 0.5;
|
370 | |
else if(c->mina < (float)*h / *w)
|
|
355 |
else if (c->mina < (float)*h / *w)
|
371 | 356 |
*h = *w * c->mina + 0.5;
|
372 | 357 |
}
|
373 | |
if(baseismin) { /* increment calculation requires this */
|
|
358 |
if (baseismin) { /* increment calculation requires this */
|
374 | 359 |
*w -= c->basew;
|
375 | 360 |
*h -= c->baseh;
|
376 | 361 |
}
|
377 | 362 |
/* adjust for increment value */
|
378 | |
if(c->incw)
|
|
363 |
if (c->incw)
|
379 | 364 |
*w -= *w % c->incw;
|
380 | |
if(c->inch)
|
|
365 |
if (c->inch)
|
381 | 366 |
*h -= *h % c->inch;
|
382 | 367 |
/* restore base dimensions */
|
383 | 368 |
*w = MAX(*w + c->basew, c->minw);
|
384 | 369 |
*h = MAX(*h + c->baseh, c->minh);
|
385 | |
if(c->maxw)
|
|
370 |
if (c->maxw)
|
386 | 371 |
*w = MIN(*w, c->maxw);
|
387 | |
if(c->maxh)
|
|
372 |
if (c->maxh)
|
388 | 373 |
*h = MIN(*h, c->maxh);
|
389 | 374 |
}
|
390 | 375 |
return *x != c->x || *y != c->y || *w != c->w || *h != c->h;
|
391 | 376 |
}
|
392 | 377 |
|
393 | 378 |
void
|
394 | |
arrange(Monitor *m) {
|
395 | |
if(m)
|
|
379 |
arrange(Monitor *m)
|
|
380 |
{
|
|
381 |
if (m)
|
396 | 382 |
showhide(m->stack);
|
397 | |
else for(m = mons; m; m = m->next)
|
|
383 |
else for (m = mons; m; m = m->next)
|
398 | 384 |
showhide(m->stack);
|
399 | |
if(m)
|
|
385 |
if (m) {
|
400 | 386 |
arrangemon(m);
|
401 | |
else for(m = mons; m; m = m->next)
|
|
387 |
restack(m);
|
|
388 |
} else for (m = mons; m; m = m->next)
|
402 | 389 |
arrangemon(m);
|
403 | 390 |
}
|
404 | 391 |
|
405 | 392 |
void
|
406 | |
arrangemon(Monitor *m) {
|
|
393 |
arrangemon(Monitor *m)
|
|
394 |
{
|
407 | 395 |
strncpy(m->ltsymbol, m->lt[m->sellt]->symbol, sizeof m->ltsymbol);
|
408 | |
if(m->lt[m->sellt]->arrange)
|
|
396 |
if (m->lt[m->sellt]->arrange)
|
409 | 397 |
m->lt[m->sellt]->arrange(m);
|
410 | |
restack(m);
|
411 | |
}
|
412 | |
|
413 | |
void
|
414 | |
attach(Client *c) {
|
|
398 |
}
|
|
399 |
|
|
400 |
void
|
|
401 |
attach(Client *c)
|
|
402 |
{
|
415 | 403 |
c->next = c->mon->clients;
|
416 | 404 |
c->mon->clients = c;
|
417 | 405 |
}
|
418 | 406 |
|
419 | 407 |
void
|
420 | |
attachstack(Client *c) {
|
|
408 |
attachstack(Client *c)
|
|
409 |
{
|
421 | 410 |
c->snext = c->mon->stack;
|
422 | 411 |
c->mon->stack = c;
|
423 | 412 |
}
|
424 | 413 |
|
425 | 414 |
void
|
426 | |
buttonpress(XEvent *e) {
|
|
415 |
buttonpress(XEvent *e)
|
|
416 |
{
|
427 | 417 |
unsigned int i, x, click;
|
428 | 418 |
Arg arg = {0};
|
429 | 419 |
Client *c;
|
|
432 | 422 |
|
433 | 423 |
click = ClkRootWin;
|
434 | 424 |
/* focus monitor if necessary */
|
435 | |
if((m = wintomon(ev->window)) && m != selmon) {
|
436 | |
unfocus(selmon->sel, True);
|
|
425 |
if ((m = wintomon(ev->window)) && m != selmon) {
|
|
426 |
unfocus(selmon->sel, 1);
|
437 | 427 |
selmon = m;
|
438 | 428 |
focus(NULL);
|
439 | 429 |
}
|
440 | |
if(ev->window == selmon->barwin) {
|
|
430 |
if (ev->window == selmon->barwin) {
|
441 | 431 |
i = x = 0;
|
442 | 432 |
do
|
443 | 433 |
x += TEXTW(tags[i]);
|
444 | |
while(ev->x >= x && ++i < LENGTH(tags));
|
445 | |
if(i < LENGTH(tags)) {
|
|
434 |
while (ev->x >= x && ++i < LENGTH(tags));
|
|
435 |
if (i < LENGTH(tags)) {
|
446 | 436 |
click = ClkTagBar;
|
447 | 437 |
arg.ui = 1 << i;
|
448 | |
}
|
449 | |
else if(ev->x < x + blw)
|
|
438 |
} else if (ev->x < x + blw)
|
450 | 439 |
click = ClkLtSymbol;
|
451 | |
else if(ev->x > selmon->ww - TEXTW(stext))
|
|
440 |
else if (ev->x > selmon->ww - TEXTW(stext))
|
452 | 441 |
click = ClkStatusText;
|
453 | 442 |
else
|
454 | 443 |
click = ClkWinTitle;
|
455 | |
}
|
456 | |
else if((c = wintoclient(ev->window))) {
|
|
444 |
} else if ((c = wintoclient(ev->window))) {
|
457 | 445 |
focus(c);
|
458 | 446 |
click = ClkClientWin;
|
459 | 447 |
}
|
460 | |
for(i = 0; i < LENGTH(buttons); i++)
|
461 | |
if(click == buttons[i].click && buttons[i].func && buttons[i].button == ev->button
|
|
448 |
for (i = 0; i < LENGTH(buttons); i++)
|
|
449 |
if (click == buttons[i].click && buttons[i].func && buttons[i].button == ev->button
|
462 | 450 |
&& CLEANMASK(buttons[i].mask) == CLEANMASK(ev->state))
|
463 | 451 |
buttons[i].func(click == ClkTagBar && buttons[i].arg.i == 0 ? &arg : &buttons[i].arg);
|
464 | 452 |
}
|
465 | 453 |
|
466 | 454 |
void
|
467 | |
checkotherwm(void) {
|
|
455 |
checkotherwm(void)
|
|
456 |
{
|
468 | 457 |
xerrorxlib = XSetErrorHandler(xerrorstart);
|
469 | 458 |
/* this causes an error if some other window manager is running */
|
470 | 459 |
XSelectInput(dpy, DefaultRootWindow(dpy), SubstructureRedirectMask);
|
|
474 | 463 |
}
|
475 | 464 |
|
476 | 465 |
void
|
477 | |
cleanup(void) {
|
|
466 |
cleanup(void)
|
|
467 |
{
|
478 | 468 |
Arg a = {.ui = ~0};
|
479 | 469 |
Layout foo = { "", NULL };
|
480 | 470 |
Monitor *m;
|
|
471 |
size_t i;
|
481 | 472 |
|
482 | 473 |
view(&a);
|
483 | 474 |
selmon->lt[selmon->sellt] = &foo;
|
484 | |
for(m = mons; m; m = m->next)
|
485 | |
while(m->stack)
|
486 | |
unmanage(m->stack, False);
|
487 | |
if(dc.font.set)
|
488 | |
XFreeFontSet(dpy, dc.font.set);
|
489 | |
else
|
490 | |
XFreeFont(dpy, dc.font.xfont);
|
|
475 |
for (m = mons; m; m = m->next)
|
|
476 |
while (m->stack)
|
|
477 |
unmanage(m->stack, 0);
|
491 | 478 |
XUngrabKey(dpy, AnyKey, AnyModifier, root);
|
492 | |
XFreePixmap(dpy, dc.drawable);
|
493 | |
XFreeGC(dpy, dc.gc);
|
494 | |
XFreeCursor(dpy, cursor[CurNormal]);
|
495 | |
XFreeCursor(dpy, cursor[CurResize]);
|
496 | |
XFreeCursor(dpy, cursor[CurMove]);
|
497 | |
while(mons)
|
|
479 |
while (mons)
|
498 | 480 |
cleanupmon(mons);
|
|
481 |
for (i = 0; i < CurLast; i++)
|
|
482 |
drw_cur_free(drw, cursor[i]);
|
|
483 |
for (i = 0; i < SchemeLast; i++) {
|
|
484 |
drw_clr_free(scheme[i].border);
|
|
485 |
drw_clr_free(scheme[i].bg);
|
|
486 |
drw_clr_free(scheme[i].fg);
|
|
487 |
}
|
|
488 |
drw_free(drw);
|
499 | 489 |
XSync(dpy, False);
|
500 | 490 |
XSetInputFocus(dpy, PointerRoot, RevertToPointerRoot, CurrentTime);
|
501 | |
}
|
502 | |
|
503 | |
void
|
504 | |
cleanupmon(Monitor *mon) {
|
|
491 |
XDeleteProperty(dpy, root, netatom[NetActiveWindow]);
|
|
492 |
}
|
|
493 |
|
|
494 |
void
|
|
495 |
cleanupmon(Monitor *mon)
|
|
496 |
{
|
505 | 497 |
Monitor *m;
|
506 | 498 |
|
507 | |
if(mon == mons)
|
|
499 |
if (mon == mons)
|
508 | 500 |
mons = mons->next;
|
509 | 501 |
else {
|
510 | |
for(m = mons; m && m->next != mon; m = m->next);
|
|
502 |
for (m = mons; m && m->next != mon; m = m->next);
|
511 | 503 |
m->next = mon->next;
|
512 | 504 |
}
|
513 | 505 |
XUnmapWindow(dpy, mon->barwin);
|
|
516 | 508 |
}
|
517 | 509 |
|
518 | 510 |
void
|
519 | |
clearurgent(Client *c) {
|
|
511 |
clearurgent(Client *c)
|
|
512 |
{
|
520 | 513 |
XWMHints *wmh;
|
521 | 514 |
|
522 | |
c->isurgent = False;
|
523 | |
if(!(wmh = XGetWMHints(dpy, c->win)))
|
|
515 |
c->isurgent = 0;
|
|
516 |
if (!(wmh = XGetWMHints(dpy, c->win)))
|
524 | 517 |
return;
|
525 | 518 |
wmh->flags &= ~XUrgencyHint;
|
526 | 519 |
XSetWMHints(dpy, c->win, wmh);
|
|
528 | 521 |
}
|
529 | 522 |
|
530 | 523 |
void
|
531 | |
clientmessage(XEvent *e) {
|
|
524 |
clientmessage(XEvent *e)
|
|
525 |
{
|
532 | 526 |
XClientMessageEvent *cme = &e->xclient;
|
533 | 527 |
Client *c = wintoclient(cme->window);
|
534 | 528 |
|
535 | |
if(!c)
|
536 | |
return;
|
537 | |
if(cme->message_type == netatom[NetWMState]) {
|
538 | |
if(cme->data.l[1] == netatom[NetWMFullscreen] || cme->data.l[2] == netatom[NetWMFullscreen])
|
|
529 |
if (!c)
|
|
530 |
return;
|
|
531 |
if (cme->message_type == netatom[NetWMState]) {
|
|
532 |
if (cme->data.l[1] == netatom[NetWMFullscreen] || cme->data.l[2] == netatom[NetWMFullscreen])
|
539 | 533 |
setfullscreen(c, (cme->data.l[0] == 1 /* _NET_WM_STATE_ADD */
|
540 | 534 |
|| (cme->data.l[0] == 2 /* _NET_WM_STATE_TOGGLE */ && !c->isfullscreen)));
|
541 | |
}
|
542 | |
else if(cme->message_type == netatom[NetActiveWindow]) {
|
543 | |
if(!ISVISIBLE(c)) {
|
|
535 |
} else if (cme->message_type == netatom[NetActiveWindow]) {
|
|
536 |
if (!ISVISIBLE(c)) {
|
544 | 537 |
c->mon->seltags ^= 1;
|
545 | 538 |
c->mon->tagset[c->mon->seltags] = c->tags;
|
546 | 539 |
}
|
|
549 | 542 |
}
|
550 | 543 |
|
551 | 544 |
void
|
552 | |
configure(Client *c) {
|
|
545 |
configure(Client *c)
|
|
546 |
{
|
553 | 547 |
XConfigureEvent ce;
|
554 | 548 |
|
555 | 549 |
ce.type = ConfigureNotify;
|
|
567 | 561 |
}
|
568 | 562 |
|
569 | 563 |
void
|
570 | |
configurenotify(XEvent *e) {
|
|
564 |
configurenotify(XEvent *e)
|
|
565 |
{
|
571 | 566 |
Monitor *m;
|
572 | 567 |
XConfigureEvent *ev = &e->xconfigure;
|
573 | |
Bool dirty;
|
574 | |
|
575 | |
if(ev->window == root) {
|
576 | |
dirty = (sw != ev->width);
|
|
568 |
int dirty;
|
|
569 |
|
|
570 |
/* TODO: updategeom handling sucks, needs to be simplified */
|
|
571 |
if (ev->window == root) {
|
|
572 |
dirty = (sw != ev->width || sh != ev->height);
|
577 | 573 |
sw = ev->width;
|
578 | 574 |
sh = ev->height;
|
579 | |
if(updategeom() || dirty) {
|
580 | |
if(dc.drawable != 0)
|
581 | |
XFreePixmap(dpy, dc.drawable);
|
582 | |
dc.drawable = XCreatePixmap(dpy, root, sw, bh, DefaultDepth(dpy, screen));
|
|
575 |
if (updategeom() || dirty) {
|
|
576 |
drw_resize(drw, sw, bh);
|
583 | 577 |
updatebars();
|
584 | |
for(m = mons; m; m = m->next)
|
|
578 |
for (m = mons; m; m = m->next)
|
585 | 579 |
XMoveResizeWindow(dpy, m->barwin, m->wx, m->by, m->ww, bh);
|
586 | 580 |
focus(NULL);
|
587 | 581 |
arrange(NULL);
|
|
590 | 584 |
}
|
591 | 585 |
|
592 | 586 |
void
|
593 | |
configurerequest(XEvent *e) {
|
|
587 |
configurerequest(XEvent *e)
|
|
588 |
{
|
594 | 589 |
Client *c;
|
595 | 590 |
Monitor *m;
|
596 | 591 |
XConfigureRequestEvent *ev = &e->xconfigurerequest;
|
597 | 592 |
XWindowChanges wc;
|
598 | 593 |
|
599 | |
if((c = wintoclient(ev->window))) {
|
600 | |
if(ev->value_mask & CWBorderWidth)
|
|
594 |
if ((c = wintoclient(ev->window))) {
|
|
595 |
if (ev->value_mask & CWBorderWidth)
|
601 | 596 |
c->bw = ev->border_width;
|
602 | |
else if(c->isfloating || !selmon->lt[selmon->sellt]->arrange) {
|
|
597 |
else if (c->isfloating || !selmon->lt[selmon->sellt]->arrange) {
|
603 | 598 |
m = c->mon;
|
604 | |
if(ev->value_mask & CWX) {
|
|
599 |
if (ev->value_mask & CWX) {
|
605 | 600 |
c->oldx = c->x;
|
606 | 601 |
c->x = m->mx + ev->x;
|
607 | 602 |
}
|
608 | |
if(ev->value_mask & CWY) {
|
|
603 |
if (ev->value_mask & CWY) {
|
609 | 604 |
c->oldy = c->y;
|
610 | 605 |
c->y = m->my + ev->y;
|
611 | 606 |
}
|
612 | |
if(ev->value_mask & CWWidth) {
|
|
607 |
if (ev->value_mask & CWWidth) {
|
613 | 608 |
c->oldw = c->w;
|
614 | 609 |
c->w = ev->width;
|
615 | 610 |
}
|
616 | |
if(ev->value_mask & CWHeight) {
|
|
611 |
if (ev->value_mask & CWHeight) {
|
617 | 612 |
c->oldh = c->h;
|
618 | 613 |
c->h = ev->height;
|
619 | 614 |
}
|
620 | |
if((c->x + c->w) > m->mx + m->mw && c->isfloating)
|
|
615 |
if ((c->x + c->w) > m->mx + m->mw && c->isfloating)
|
621 | 616 |
c->x = m->mx + (m->mw / 2 - WIDTH(c) / 2); /* center in x direction */
|
622 | |
if((c->y + c->h) > m->my + m->mh && c->isfloating)
|
|
617 |
if ((c->y + c->h) > m->my + m->mh && c->isfloating)
|
623 | 618 |
c->y = m->my + (m->mh / 2 - HEIGHT(c) / 2); /* center in y direction */
|
624 | |
if((ev->value_mask & (CWX|CWY)) && !(ev->value_mask & (CWWidth|CWHeight)))
|
|
619 |
if ((ev->value_mask & (CWX|CWY)) && !(ev->value_mask & (CWWidth|CWHeight)))
|
625 | 620 |
configure(c);
|
626 | |
if(ISVISIBLE(c))
|
|
621 |
if (ISVISIBLE(c))
|
627 | 622 |
XMoveResizeWindow(dpy, c->win, c->x, c->y, c->w, c->h);
|
628 | |
}
|
629 | |
else
|
|
623 |
} else
|
630 | 624 |
configure(c);
|
631 | |
}
|
632 | |
else {
|
|
625 |
} else {
|
633 | 626 |
wc.x = ev->x;
|
634 | 627 |
wc.y = ev->y;
|
635 | 628 |
wc.width = ev->width;
|
|
643 | 636 |
}
|
644 | 637 |
|
645 | 638 |
Monitor *
|
646 | |
createmon(void) {
|
|
639 |
createmon(void)
|
|
640 |
{
|
647 | 641 |
Monitor *m;
|
648 | 642 |
|
649 | |
if(!(m = (Monitor *)calloc(1, sizeof(Monitor))))
|
650 | |
die("fatal: could not malloc() %u bytes\n", sizeof(Monitor));
|
|
643 |
m = ecalloc(1, sizeof(Monitor));
|
651 | 644 |
m->tagset[0] = m->tagset[1] = 1;
|
652 | 645 |
m->mfact = mfact;
|
653 | 646 |
m->nmaster = nmaster;
|
|
660 | 653 |
}
|
661 | 654 |
|
662 | 655 |
void
|
663 | |
destroynotify(XEvent *e) {
|
|
656 |
destroynotify(XEvent *e)
|
|
657 |
{
|
664 | 658 |
Client *c;
|
665 | 659 |
XDestroyWindowEvent *ev = &e->xdestroywindow;
|
666 | 660 |
|
667 | |
if((c = wintoclient(ev->window)))
|
668 | |
unmanage(c, True);
|
669 | |
}
|
670 | |
|
671 | |
void
|
672 | |
detach(Client *c) {
|
|
661 |
if ((c = wintoclient(ev->window)))
|
|
662 |
unmanage(c, 1);
|
|
663 |
}
|
|
664 |
|
|
665 |
void
|
|
666 |
detach(Client *c)
|
|
667 |
{
|
673 | 668 |
Client **tc;
|
674 | 669 |
|
675 | |
for(tc = &c->mon->clients; *tc && *tc != c; tc = &(*tc)->next);
|
|
670 |
for (tc = &c->mon->clients; *tc && *tc != c; tc = &(*tc)->next);
|
676 | 671 |
*tc = c->next;
|
677 | 672 |
}
|
678 | 673 |
|
679 | 674 |
void
|
680 | |
detachstack(Client *c) {
|
|
675 |
detachstack(Client *c)
|
|
676 |
{
|
681 | 677 |
Client **tc, *t;
|
682 | 678 |
|
683 | |
for(tc = &c->mon->stack; *tc && *tc != c; tc = &(*tc)->snext);
|
|
679 |
for (tc = &c->mon->stack; *tc && *tc != c; tc = &(*tc)->snext);
|
684 | 680 |
*tc = c->snext;
|
685 | 681 |
|
686 | |
if(c == c->mon->sel) {
|
687 | |
for(t = c->mon->stack; t && !ISVISIBLE(t); t = t->snext);
|
|
682 |
if (c == c->mon->sel) {
|
|
683 |
for (t = c->mon->stack; t && !ISVISIBLE(t); t = t->snext);
|
688 | 684 |
c->mon->sel = t;
|
689 | 685 |
}
|
690 | 686 |
}
|
691 | 687 |
|
692 | |
void
|
693 | |
die(const char *errstr, ...) {
|
694 | |
va_list ap;
|
695 | |
|
696 | |
va_start(ap, errstr);
|
697 | |
vfprintf(stderr, errstr, ap);
|
698 | |
va_end(ap);
|
699 | |
exit(EXIT_FAILURE);
|
700 | |
}
|
701 | |
|
702 | 688 |
Monitor *
|
703 | |
dirtomon(int dir) {
|
|
689 |
dirtomon(int dir)
|
|
690 |
{
|
704 | 691 |
Monitor *m = NULL;
|
705 | 692 |
|
706 | |
if(dir > 0) {
|
707 | |
if(!(m = selmon->next))
|
|
693 |
if (dir > 0) {
|
|
694 |
if (!(m = selmon->next))
|
708 | 695 |
m = mons;
|
709 | |
}
|
710 | |
else if(selmon == mons)
|
711 | |
for(m = mons; m->next; m = m->next);
|
|
696 |
} else if (selmon == mons)
|
|
697 |
for (m = mons; m->next; m = m->next);
|
712 | 698 |
else
|
713 | |
for(m = mons; m->next != selmon; m = m->next);
|
|
699 |
for (m = mons; m->next != selmon; m = m->next);
|
714 | 700 |
return m;
|
715 | 701 |
}
|
716 | 702 |
|
717 | 703 |
void
|
718 | |
drawbar(Monitor *m) {
|
719 | |
int x;
|
|
704 |
drawbar(Monitor *m)
|
|
705 |
{
|
|
706 |
int x, xx, w, dx;
|
720 | 707 |
unsigned int i, occ = 0, urg = 0;
|
721 | |
unsigned long *col;
|
722 | 708 |
Client *c;
|
723 | 709 |
|
724 | |
for(c = m->clients; c; c = c->next) {
|
|
710 |
dx = (drw->fonts[0]->ascent + drw->fonts[0]->descent + 2) / 4;
|
|
711 |
|
|
712 |
for (c = m->clients; c; c = c->next) {
|
725 | 713 |
occ |= c->tags;
|
726 | |
if(c->isurgent)
|
|
714 |
if (c->isurgent)
|
727 | 715 |
urg |= c->tags;
|
728 | 716 |
}
|
729 | |
dc.x = 0;
|
730 | |
for(i = 0; i < LENGTH(tags); i++) {
|
731 | |
dc.w = TEXTW(tags[i]);
|
732 | |
col = m->tagset[m->seltags] & 1 << i ? dc.sel : dc.norm;
|
733 | |
drawtext(tags[i], col, urg & 1 << i);
|
734 | |
drawsquare(m == selmon && selmon->sel && selmon->sel->tags & 1 << i,
|
735 | |
occ & 1 << i, urg & 1 << i, col);
|
736 | |
dc.x += dc.w;
|
737 | |
}
|
738 | |
dc.w = blw = TEXTW(m->ltsymbol);
|
739 | |
drawtext(m->ltsymbol, dc.norm, False);
|
740 | |
dc.x += dc.w;
|
741 | |
x = dc.x;
|
742 | |
if(m == selmon) { /* status is only drawn on selected monitor */
|
743 | |
dc.w = TEXTW(stext);
|
744 | |
dc.x = m->ww - dc.w;
|
745 | |
if(dc.x < x) {
|
746 | |
dc.x = x;
|
747 | |
dc.w = m->ww - x;
|
|
717 |
x = 0;
|
|
718 |
for (i = 0; i < LENGTH(tags); i++) {
|
|
719 |
w = TEXTW(tags[i]);
|
|
720 |
drw_setscheme(drw, m->tagset[m->seltags] & 1 << i ? &scheme[SchemeSel] : &scheme[SchemeNorm]);
|
|
721 |
drw_text(drw, x, 0, w, bh, tags[i], urg & 1 << i);
|
|
722 |
drw_rect(drw, x + 1, 1, dx, dx, m == selmon && selmon->sel && selmon->sel->tags & 1 << i,
|
|
723 |
occ & 1 << i, urg & 1 << i);
|
|
724 |
x += w;
|
|
725 |
}
|
|
726 |
w = blw = TEXTW(m->ltsymbol);
|
|
727 |
drw_setscheme(drw, &scheme[SchemeNorm]);
|
|
728 |
drw_text(drw, x, 0, w, bh, m->ltsymbol, 0);
|
|
729 |
x += w;
|
|
730 |
xx = x;
|
|
731 |
if (m == selmon) { /* status is only drawn on selected monitor */
|
|
732 |
w = TEXTW(stext);
|
|
733 |
x = m->ww - w;
|
|
734 |
if (x < xx) {
|
|
735 |
x = xx;
|
|
736 |
w = m->ww - xx;
|
748 | 737 |
}
|
749 | |
drawtext(stext, dc.norm, False);
|
750 | |
}
|
751 | |
else
|
752 | |
dc.x = m->ww;
|
753 | |
if((dc.w = dc.x - x) > bh) {
|
754 | |
dc.x = x;
|
755 | |
if(m->sel) {
|
756 | |
col = m == selmon ? dc.sel : dc.norm;
|
757 | |
drawtext(m->sel->name, col, False);
|
758 | |
drawsquare(m->sel->isfixed, m->sel->isfloating, False, col);
|
|
738 |
drw_text(drw, x, 0, w, bh, stext, 0);
|
|
739 |
} else
|
|
740 |
x = m->ww;
|
|
741 |
if ((w = x - xx) > bh) {
|
|
742 |
x = xx;
|
|
743 |
if (m->sel) {
|
|
744 |
drw_setscheme(drw, m == selmon ? &scheme[SchemeSel] : &scheme[SchemeNorm]);
|
|
745 |
drw_text(drw, x, 0, w, bh, m->sel->name, 0);
|
|
746 |
drw_rect(drw, x + 1, 1, dx, dx, m->sel->isfixed, m->sel->isfloating, 0);
|
|
747 |
} else {
|
|
748 |
drw_setscheme(drw, &scheme[SchemeNorm]);
|
|
749 |
drw_rect(drw, x, 0, w, bh, 1, 0, 1);
|
759 | 750 |
}
|
760 | |
else
|
761 | |
drawtext(NULL, dc.norm, False);
|
762 | |
}
|
763 | |
XCopyArea(dpy, dc.drawable, m->barwin, dc.gc, 0, 0, m->ww, bh, 0, 0);
|
764 | |
XSync(dpy, False);
|
765 | |
}
|
766 | |
|
767 | |
void
|
768 | |
drawbars(void) {
|
|
751 |
}
|
|
752 |
drw_map(drw, m->barwin, 0, 0, m->ww, bh);
|
|
753 |
}
|
|
754 |
|
|
755 |
void
|
|
756 |
drawbars(void)
|
|
757 |
{
|
769 | 758 |
Monitor *m;
|
770 | 759 |
|
771 | |
for(m = mons; m; m = m->next)
|
|
760 |
for (m = mons; m; m = m->next)
|
772 | 761 |
drawbar(m);
|
773 | 762 |
}
|
774 | 763 |
|
775 | 764 |
void
|
776 | |
drawsquare(Bool filled, Bool empty, Bool invert, unsigned long col[ColLast]) {
|
777 | |
int x;
|
778 | |
|
779 | |
XSetForeground(dpy, dc.gc, col[invert ? ColBG : ColFG]);
|
780 | |
x = (dc.font.ascent + dc.font.descent + 2) / 4;
|
781 | |
if(filled)
|
782 | |
XFillRectangle(dpy, dc.drawable, dc.gc, dc.x+1, dc.y+1, x+1, x+1);
|
783 | |
else if(empty)
|
784 | |
XDrawRectangle(dpy, dc.drawable, dc.gc, dc.x+1, dc.y+1, x, x);
|
785 | |
}
|
786 | |
|
787 | |
void
|
788 | |
drawtext(const char *text, unsigned long col[ColLast], Bool invert) {
|
789 | |
char buf[256];
|
790 | |
int i, x, y, h, len, olen;
|
791 | |
|
792 | |
XSetForeground(dpy, dc.gc, col[invert ? ColFG : ColBG]);
|
793 | |
XFillRectangle(dpy, dc.drawable, dc.gc, dc.x, dc.y, dc.w, dc.h);
|
794 | |
if(!text)
|
795 | |
return;
|
796 | |
olen = strlen(text);
|
797 | |
h = dc.font.ascent + dc.font.descent;
|
798 | |
y = dc.y + (dc.h / 2) - (h / 2) + dc.font.ascent;
|
799 | |
x = dc.x + (h / 2);
|
800 | |
/* shorten text if necessary */
|
801 | |
for(len = MIN(olen, sizeof buf); len && textnw(text, len) > dc.w - h; len--);
|
802 | |
if(!len)
|
803 | |
return;
|
804 | |
memcpy(buf, text, len);
|
805 | |
if(len < olen)
|
806 | |
for(i = len; i && i > len - 3; buf[--i] = '.');
|
807 | |
XSetForeground(dpy, dc.gc, col[invert ? ColBG : ColFG]);
|
808 | |
if(dc.font.set)
|
809 | |
XmbDrawString(dpy, dc.drawable, dc.font.set, dc.gc, x, y, buf, len);
|
810 | |
else
|
811 | |
XDrawString(dpy, dc.drawable, dc.gc, x, y, buf, len);
|
812 | |
}
|
813 | |
|
814 | |
void
|
815 | |
enternotify(XEvent *e) {
|
|
765 |
enternotify(XEvent *e)
|
|
766 |
{
|
816 | 767 |
Client *c;
|
817 | 768 |
Monitor *m;
|
818 | 769 |
XCrossingEvent *ev = &e->xcrossing;
|
819 | 770 |
|
820 | |
if((ev->mode != NotifyNormal || ev->detail == NotifyInferior) && ev->window != root)
|
|
771 |
if ((ev->mode != NotifyNormal || ev->detail == NotifyInferior) && ev->window != root)
|
821 | 772 |
return;
|
822 | 773 |
c = wintoclient(ev->window);
|
823 | 774 |
m = c ? c->mon : wintomon(ev->window);
|
824 | |
if(m != selmon) {
|
825 | |
unfocus(selmon->sel, True);
|
|
775 |
if (m != selmon) {
|
|
776 |
unfocus(selmon->sel, 1);
|
826 | 777 |
selmon = m;
|
827 | |
}
|
828 | |
else if(!c || c == selmon->sel)
|
|
778 |
} else if (!c || c == selmon->sel)
|
829 | 779 |
return;
|
830 | 780 |
focus(c);
|
831 | 781 |
}
|
832 | 782 |
|
833 | 783 |
void
|
834 | |
expose(XEvent *e) {
|
|
784 |
expose(XEvent *e)
|
|
785 |
{
|
835 | 786 |
Monitor *m;
|
836 | 787 |
XExposeEvent *ev = &e->xexpose;
|
837 | 788 |
|
838 | |
if(ev->count == 0 && (m = wintomon(ev->window)))
|
|
789 |
if (ev->count == 0 && (m = wintomon(ev->window)))
|
839 | 790 |
drawbar(m);
|
840 | 791 |
}
|
841 | 792 |
|
842 | 793 |
void
|
843 | |
focus(Client *c) {
|
844 | |
if(!c || !ISVISIBLE(c))
|
845 | |
for(c = selmon->stack; c && !ISVISIBLE(c); c = c->snext);
|
846 | |
/* was if(selmon->sel) */
|
847 | |
if(selmon->sel && selmon->sel != c)
|
848 | |
unfocus(selmon->sel, False);
|
849 | |
if(c) {
|
850 | |
if(c->mon != selmon)
|
|
794 |
focus(Client *c)
|
|
795 |
{
|
|
796 |
if (!c || !ISVISIBLE(c))
|
|
797 |
for (c = selmon->stack; c && !ISVISIBLE(c); c = c->snext);
|
|
798 |
/* was if (selmon->sel) */
|
|
799 |
if (selmon->sel && selmon->sel != c)
|
|
800 |
unfocus(selmon->sel, 0);
|
|
801 |
if (c) {
|
|
802 |
if (c->mon != selmon)
|
851 | 803 |
selmon = c->mon;
|
852 | |
if(c->isurgent)
|
|
804 |
if (c->isurgent)
|
853 | 805 |
clearurgent(c);
|
854 | 806 |
detachstack(c);
|
855 | 807 |
attachstack(c);
|
856 | |
grabbuttons(c, True);
|
857 | |
XSetWindowBorder(dpy, c->win, dc.sel[ColBorder]);
|
|
808 |
grabbuttons(c, 1);
|
|
809 |
XSetWindowBorder(dpy, c->win, scheme[SchemeSel].border->pix);
|
858 | 810 |
setfocus(c);
|
859 | |
}
|
860 | |
else
|
|
811 |
} else {
|
861 | 812 |
XSetInputFocus(dpy, root, RevertToPointerRoot, CurrentTime);
|
|
813 |
XDeleteProperty(dpy, root, netatom[NetActiveWindow]);
|
|
814 |
}
|
862 | 815 |
selmon->sel = c;
|
863 | 816 |
drawbars();
|
864 | 817 |
}
|
865 | 818 |
|
866 | |
void
|
867 | |
focusin(XEvent *e) { /* there are some broken focus acquiring clients */
|
|
819 |
/* there are some broken focus acquiring clients */
|
|
820 |
void
|
|
821 |
focusin(XEvent *e)
|
|
822 |
{
|
868 | 823 |
XFocusChangeEvent *ev = &e->xfocus;
|
869 | 824 |
|
870 | |
if(selmon->sel && ev->window != selmon->sel->win)
|
|
825 |
if (selmon->sel && ev->window != selmon->sel->win)
|
871 | 826 |
setfocus(selmon->sel);
|
872 | 827 |
}
|
873 | 828 |
|
874 | 829 |
void
|
875 | |
focusmon(const Arg *arg) {
|
|
830 |
focusmon(const Arg *arg)
|
|
831 |
{
|
876 | 832 |
Monitor *m;
|
877 | 833 |
|
878 | |
if(!mons->next)
|
879 | |
return;
|
880 | |
if((m = dirtomon(arg->i)) == selmon)
|
881 | |
return;
|
882 | |
unfocus(selmon->sel, True);
|
|
834 |
if (!mons->next)
|
|
835 |
return;
|
|
836 |
if ((m = dirtomon(arg->i)) == selmon)
|
|
837 |
return;
|
|
838 |
unfocus(selmon->sel, 0); /* s/1/0/ fixes input focus issues
|
|
839 |
in gedit and anjuta */
|
883 | 840 |
selmon = m;
|
884 | 841 |
focus(NULL);
|
885 | 842 |
}
|
886 | 843 |
|
887 | 844 |
void
|
888 | |
focusstack(const Arg *arg) {
|
|
845 |
focusstack(const Arg *arg)
|
|
846 |
{
|
889 | 847 |
Client *c = NULL, *i;
|
890 | 848 |
|
891 | |
if(!selmon->sel)
|
892 | |
return;
|
893 | |
if(arg->i > 0) {
|
894 | |
for(c = selmon->sel->next; c && !ISVISIBLE(c); c = c->next);
|
895 | |
if(!c)
|
896 | |
for(c = selmon->clients; c && !ISVISIBLE(c); c = c->next);
|
897 | |
}
|
898 | |
else {
|
899 | |
for(i = selmon->clients; i != selmon->sel; i = i->next)
|
900 | |
if(ISVISIBLE(i))
|
|
849 |
if (!selmon->sel)
|
|
850 |
return;
|
|
851 |
if (arg->i > 0) {
|
|
852 |
for (c = selmon->sel->next; c && !ISVISIBLE(c); c = c->next);
|
|
853 |
if (!c)
|
|
854 |
for (c = selmon->clients; c && !ISVISIBLE(c); c = c->next);
|
|
855 |
} else {
|
|
856 |
for (i = selmon->clients; i != selmon->sel; i = i->next)
|
|
857 |
if (ISVISIBLE(i))
|
901 | 858 |
c = i;
|
902 | |
if(!c)
|
903 | |
for(; i; i = i->next)
|
904 | |
if(ISVISIBLE(i))
|
|
859 |
if (!c)
|
|
860 |
for (; i; i = i->next)
|
|
861 |
if (ISVISIBLE(i))
|
905 | 862 |
c = i;
|
906 | 863 |
}
|
907 | |
if(c) {
|
|
864 |
if (c) {
|
908 | 865 |
focus(c);
|
909 | 866 |
restack(selmon);
|
910 | 867 |
}
|
911 | 868 |
}
|
912 | 869 |
|
913 | 870 |
Atom
|
914 | |
getatomprop(Client *c, Atom prop) {
|
|
871 |
getatomprop(Client *c, Atom prop)
|
|
872 |
{
|
915 | 873 |
int di;
|
916 | 874 |
unsigned long dl;
|
917 | 875 |
unsigned char *p = NULL;
|
918 | 876 |
Atom da, atom = None;
|
919 | 877 |
|
920 | |
if(XGetWindowProperty(dpy, c->win, prop, 0L, sizeof atom, False, XA_ATOM,
|
|
878 |
if (XGetWindowProperty(dpy, c->win, prop, 0L, sizeof atom, False, XA_ATOM,
|
921 | 879 |
&da, &di, &dl, &dl, &p) == Success && p) {
|
922 | 880 |
atom = *(Atom *)p;
|
923 | 881 |
XFree(p);
|
|
925 | 883 |
return atom;
|
926 | 884 |
}
|
927 | 885 |
|
928 | |
unsigned long
|
929 | |
getcolor(const char *colstr) {
|
930 | |
Colormap cmap = DefaultColormap(dpy, screen);
|
931 | |
XColor color;
|
932 | |
|
933 | |
if(!XAllocNamedColor(dpy, cmap, colstr, &color, &color))
|
934 | |
die("error, cannot allocate color '%s'\n", colstr);
|
935 | |
return color.pixel;
|
936 | |
}
|
937 | |
|
938 | |
Bool
|
939 | |
getrootptr(int *x, int *y) {
|
|
886 |
int
|
|
887 |
getrootptr(int *x, int *y)
|
|
888 |
{
|
940 | 889 |
int di;
|
941 | 890 |
unsigned int dui;
|
942 | 891 |
Window dummy;
|
|
945 | 894 |
}
|
946 | 895 |
|
947 | 896 |
long
|
948 | |
getstate(Window w) {
|
|
897 |
getstate(Window w)
|
|
898 |
{
|
949 | 899 |
int format;
|
950 | 900 |
long result = -1;
|
951 | 901 |
unsigned char *p = NULL;
|
952 | 902 |
unsigned long n, extra;
|
953 | 903 |
Atom real;
|
954 | 904 |
|
955 | |
if(XGetWindowProperty(dpy, w, wmatom[WMState], 0L, 2L, False, wmatom[WMState],
|
|
905 |
if (XGetWindowProperty(dpy, w, wmatom[WMState], 0L, 2L, False, wmatom[WMState],
|
956 | 906 |
&real, &format, &n, &extra, (unsigned char **)&p) != Success)
|
957 | 907 |
return -1;
|
958 | |
if(n != 0)
|
|
908 |
if (n != 0)
|
959 | 909 |
result = *p;
|
960 | 910 |
XFree(p);
|
961 | 911 |
return result;
|
962 | 912 |
}
|
963 | 913 |
|
964 | |
Bool
|
965 | |
gettextprop(Window w, Atom atom, char *text, unsigned int size) {
|
|
914 |
int
|
|
915 |
gettextprop(Window w, Atom atom, char *text, unsigned int size)
|
|
916 |
{
|
966 | 917 |
char **list = NULL;
|
967 | 918 |
int n;
|
968 | 919 |
XTextProperty name;
|
969 | 920 |
|
970 | |
if(!text || size == 0)
|
971 | |
return False;
|
|
921 |
if (!text || size == 0)
|
|
922 |
return 0;
|
972 | 923 |
text[0] = '\0';
|
973 | 924 |
XGetTextProperty(dpy, w, &name, atom);
|
974 | |
if(!name.nitems)
|
975 | |
return False;
|
976 | |
if(name.encoding == XA_STRING)
|
|
925 |
if (!name.nitems)
|
|
926 |
return 0;
|
|
927 |
if (name.encoding == XA_STRING)
|
977 | 928 |
strncpy(text, (char *)name.value, size - 1);
|
978 | 929 |
else {
|
979 | |
if(XmbTextPropertyToTextList(dpy, &name, &list, &n) >= Success && n > 0 && *list) {
|
|
930 |
if (XmbTextPropertyToTextList(dpy, &name, &list, &n) >= Success && n > 0 && *list) {
|
980 | 931 |
strncpy(text, *list, size - 1);
|
981 | 932 |
XFreeStringList(list);
|
982 | 933 |
}
|
983 | 934 |
}
|
984 | 935 |
text[size - 1] = '\0';
|
985 | 936 |
XFree(name.value);
|
986 | |
return True;
|
987 | |
}
|
988 | |
|
989 | |
void
|
990 | |
grabbuttons(Client *c, Bool focused) {
|
|
937 |
return 1;
|
|
938 |
}
|
|
939 |
|
|
940 |
void
|
|
941 |
grabbuttons(Client *c, int focused)
|
|
942 |
{
|
991 | 943 |
updatenumlockmask();
|
992 | 944 |
{
|
993 | 945 |
unsigned int i, j;
|
994 | 946 |
unsigned int modifiers[] = { 0, LockMask, numlockmask, numlockmask|LockMask };
|
995 | 947 |
XUngrabButton(dpy, AnyButton, AnyModifier, c->win);
|
996 | |
if(focused) {
|
997 | |
for(i = 0; i < LENGTH(buttons); i++)
|
998 | |
if(buttons[i].click == ClkClientWin)
|
999 | |
for(j = 0; j < LENGTH(modifiers); j++)
|
|
948 |
if (focused) {
|
|
949 |
for (i = 0; i < LENGTH(buttons); i++)
|
|
950 |
if (buttons[i].click == ClkClientWin)
|
|
951 |
for (j = 0; j < LENGTH(modifiers); j++)
|
1000 | 952 |
XGrabButton(dpy, buttons[i].button,
|
1001 | 953 |
buttons[i].mask | modifiers[j],
|
1002 | 954 |
c->win, False, BUTTONMASK,
|
1003 | 955 |
GrabModeAsync, GrabModeSync, None, None);
|
1004 | |
}
|
1005 | |
else
|
|
956 |
} else
|
1006 | 957 |
XGrabButton(dpy, AnyButton, AnyModifier, c->win, False,
|
1007 | 958 |
BUTTONMASK, GrabModeAsync, GrabModeSync, None, None);
|
1008 | 959 |
}
|
1009 | 960 |
}
|
1010 | 961 |
|
1011 | 962 |
void
|
1012 | |
grabkeys(void) {
|
|
963 |
grabkeys(void)
|
|
964 |
{
|
1013 | 965 |
updatenumlockmask();
|
1014 | 966 |
{
|
1015 | 967 |
unsigned int i, j;
|
|
1017 | 969 |
KeyCode code;
|
1018 | 970 |
|
1019 | 971 |
XUngrabKey(dpy, AnyKey, AnyModifier, root);
|
1020 | |
for(i = 0; i < LENGTH(keys); i++)
|
1021 | |
if((code = XKeysymToKeycode(dpy, keys[i].keysym)))
|
1022 | |
for(j = 0; j < LENGTH(modifiers); j++)
|
|
972 |
for (i = 0; i < LENGTH(keys); i++)
|
|
973 |
if ((code = XKeysymToKeycode(dpy, keys[i].keysym)))
|
|
974 |
for (j = 0; j < LENGTH(modifiers); j++)
|
1023 | 975 |
XGrabKey(dpy, code, keys[i].mod | modifiers[j], root,
|
1024 | 976 |
True, GrabModeAsync, GrabModeAsync);
|
1025 | 977 |
}
|
1026 | 978 |
}
|
1027 | 979 |
|
1028 | 980 |
void
|
1029 | |
incnmaster(const Arg *arg) {
|
|
981 |
incnmaster(const Arg *arg)
|
|
982 |
{
|
1030 | 983 |
selmon->nmaster = MAX(selmon->nmaster + arg->i, 0);
|
1031 | 984 |
arrange(selmon);
|
1032 | 985 |
}
|
1033 | 986 |
|
1034 | |
void
|
1035 | |
initfont(const char *fontstr) {
|
1036 | |
char *def, **missing;
|
1037 | |
int n;
|
1038 | |
|
1039 | |
dc.font.set = XCreateFontSet(dpy, fontstr, &missing, &n, &def);
|
1040 | |
if(missing) {
|
1041 | |
while(n--)
|
1042 | |
fprintf(stderr, "dwm: missing fontset: %s\n", missing[n]);
|
1043 | |
XFreeStringList(missing);
|
1044 | |
}
|
1045 | |
if(dc.font.set) {
|
1046 | |
XFontStruct **xfonts;
|
1047 | |
char **font_names;
|
1048 | |
|
1049 | |
dc.font.ascent = dc.font.descent = 0;
|
1050 | |
XExtentsOfFontSet(dc.font.set);
|
1051 | |
n = XFontsOfFontSet(dc.font.set, &xfonts, &font_names);
|
1052 | |
while(n--) {
|
1053 | |
dc.font.ascent = MAX(dc.font.ascent, (*xfonts)->ascent);
|
1054 | |
dc.font.descent = MAX(dc.font.descent,(*xfonts)->descent);
|
1055 | |
xfonts++;
|
1056 | |
}
|
1057 | |
}
|
1058 | |
else {
|
1059 | |
if(!(dc.font.xfont = XLoadQueryFont(dpy, fontstr))
|
1060 | |
&& !(dc.font.xfont = XLoadQueryFont(dpy, "fixed")))
|
1061 | |
die("error, cannot load font: '%s'\n", fontstr);
|
1062 | |
dc.font.ascent = dc.font.xfont->ascent;
|
1063 | |
dc.font.descent = dc.font.xfont->descent;
|
1064 | |
}
|
1065 | |
dc.font.height = dc.font.ascent + dc.font.descent;
|
1066 | |
}
|
1067 | |
|
1068 | 987 |
#ifdef XINERAMA
|
1069 | |
static Bool
|
1070 | |
isuniquegeom(XineramaScreenInfo *unique, size_t n, XineramaScreenInfo *info) {
|
1071 | |
while(n--)
|
1072 | |
if(unique[n].x_org == info->x_org && unique[n].y_org == info->y_org
|
|
988 |
static int
|
|
989 |
isuniquegeom(XineramaScreenInfo *unique, size_t n, XineramaScreenInfo *info)
|
|
990 |
{
|
|
991 |
while (n--)
|
|
992 |
if (unique[n].x_org == info->x_org && unique[n].y_org == info->y_org
|
1073 | 993 |
&& unique[n].width == info->width && unique[n].height == info->height)
|
1074 | |
return False;
|
1075 | |
return True;
|
|
994 |
return 0;
|
|
995 |
return 1;
|
1076 | 996 |
}
|
1077 | 997 |
#endif /* XINERAMA */
|
1078 | 998 |
|
1079 | 999 |
void
|
1080 | |
keypress(XEvent *e) {
|
|
1000 |
keypress(XEvent *e)
|
|
1001 |
{
|
1081 | 1002 |
unsigned int i;
|
1082 | 1003 |
KeySym keysym;
|
1083 | 1004 |
XKeyEvent *ev;
|
1084 | 1005 |
|
1085 | 1006 |
ev = &e->xkey;
|
1086 | 1007 |
keysym = XKeycodeToKeysym(dpy, (KeyCode)ev->keycode, 0);
|
1087 | |
for(i = 0; i < LENGTH(keys); i++)
|
1088 | |
if(keysym == keys[i].keysym
|
|
1008 |
for (i = 0; i < LENGTH(keys); i++)
|
|
1009 |
if (keysym == keys[i].keysym
|
1089 | 1010 |
&& CLEANMASK(keys[i].mod) == CLEANMASK(ev->state)
|
1090 | 1011 |
&& keys[i].func)
|
1091 | 1012 |
keys[i].func(&(keys[i].arg));
|
1092 | 1013 |
}
|
1093 | 1014 |
|
1094 | 1015 |
void
|
1095 | |
killclient(const Arg *arg) {
|
1096 | |
if(!selmon->sel)
|
1097 | |
return;
|
1098 | |
if(!sendevent(selmon->sel, wmatom[WMDelete])) {
|
|
1016 |
killclient(const Arg *arg)
|
|
1017 |
{
|
|
1018 |
if (!selmon->sel)
|
|
1019 |
return;
|
|
1020 |
if (!sendevent(selmon->sel, wmatom[WMDelete])) {
|
1099 | 1021 |
XGrabServer(dpy);
|
1100 | 1022 |
XSetErrorHandler(xerrordummy);
|
1101 | 1023 |
XSetCloseDownMode(dpy, DestroyAll);
|
|
1107 | 1029 |
}
|
1108 | 1030 |
|
1109 | 1031 |
void
|
1110 | |
manage(Window w, XWindowAttributes *wa) {
|
|
1032 |
manage(Window w, XWindowAttributes *wa)
|
|
1033 |
{
|
1111 | 1034 |
Client *c, *t = NULL;
|
1112 | 1035 |
Window trans = None;
|
1113 | 1036 |
XWindowChanges wc;
|
1114 | 1037 |
|
1115 | |
if(!(c = calloc(1, sizeof(Client))))
|
1116 | |
die("fatal: could not malloc() %u bytes\n", sizeof(Client));
|
|
1038 |
c = ecalloc(1, sizeof(Client));
|
1117 | 1039 |
c->win = w;
|
1118 | 1040 |
updatetitle(c);
|
1119 | |
if(XGetTransientForHint(dpy, w, &trans) && (t = wintoclient(trans))) {
|
|
1041 |
if (XGetTransientForHint(dpy, w, &trans) && (t = wintoclient(trans))) {
|
1120 | 1042 |
c->mon = t->mon;
|
1121 | 1043 |
c->tags = t->tags;
|
1122 | |
}
|
1123 | |
else {
|
|
1044 |
} else {
|
1124 | 1045 |
c->mon = selmon;
|
1125 | 1046 |
applyrules(c);
|
1126 | 1047 |
}
|
|
1131 | 1052 |
c->h = c->oldh = wa->height;
|
1132 | 1053 |
c->oldbw = wa->border_width;
|
1133 | 1054 |
|
1134 | |
if(c->x + WIDTH(c) > c->mon->mx + c->mon->mw)
|
|
1055 |
if (c->x + WIDTH(c) > c->mon->mx + c->mon->mw)
|
1135 | 1056 |
c->x = c->mon->mx + c->mon->mw - WIDTH(c);
|
1136 | |
if(c->y + HEIGHT(c) > c->mon->my + c->mon->mh)
|
|
1057 |
if (c->y + HEIGHT(c) > c->mon->my + c->mon->mh)
|
1137 | 1058 |
c->y = c->mon->my + c->mon->mh - HEIGHT(c);
|
1138 | 1059 |
c->x = MAX(c->x, c->mon->mx);
|
1139 | 1060 |
/* only fix client y-offset, if the client center might cover the bar */
|
|
1143 | 1064 |
|
1144 | 1065 |
wc.border_width = c->bw;
|
1145 | 1066 |
XConfigureWindow(dpy, w, CWBorderWidth, &wc);
|
1146 | |
XSetWindowBorder(dpy, w, dc.norm[ColBorder]);
|
|
1067 |
XSetWindowBorder(dpy, w, scheme[SchemeNorm].border->pix);
|
1147 | 1068 |
configure(c); /* propagates border_width, if size doesn't change */
|
1148 | 1069 |
updatewindowtype(c);
|
1149 | 1070 |
updatesizehints(c);
|
1150 | 1071 |
updatewmhints(c);
|
1151 | 1072 |
XSelectInput(dpy, w, EnterWindowMask|FocusChangeMask|PropertyChangeMask|StructureNotifyMask);
|
1152 | |
grabbuttons(c, False);
|
1153 | |
if(!c->isfloating)
|
|
1073 |
grabbuttons(c, 0);
|
|
1074 |
if (!c->isfloating)
|
1154 | 1075 |
c->isfloating = c->oldstate = trans != None || c->isfixed;
|
1155 | |
if(c->isfloating)
|
|
1076 |
if (c->isfloating)
|
1156 | 1077 |
XRaiseWindow(dpy, c->win);
|
1157 | 1078 |
attach(c);
|
1158 | 1079 |
attachstack(c);
|
|
1080 |
XChangeProperty(dpy, root, netatom[NetClientList], XA_WINDOW, 32, PropModeAppend,
|
|
1081 |
(unsigned char *) &(c->win), 1);
|
1159 | 1082 |
XMoveResizeWindow(dpy, c->win, c->x + 2 * sw, c->y, c->w, c->h); /* some windows require this */
|
1160 | 1083 |
setclientstate(c, NormalState);
|
1161 | 1084 |
if (c->mon == selmon)
|
1162 | |
unfocus(selmon->sel, False);
|
|
1085 |
unfocus(selmon->sel, 0);
|
1163 | 1086 |
c->mon->sel = c;
|
1164 | 1087 |
arrange(c->mon);
|
1165 | 1088 |
XMapWindow(dpy, c->win);
|
|
1167 | 1090 |
}
|
1168 | 1091 |
|
1169 | 1092 |
void
|
1170 | |
mappingnotify(XEvent *e) {
|
|
1093 |
mappingnotify(XEvent *e)
|
|
1094 |
{
|
1171 | 1095 |
XMappingEvent *ev = &e->xmapping;
|
1172 | 1096 |
|
1173 | 1097 |
XRefreshKeyboardMapping(ev);
|
1174 | |
if(ev->request == MappingKeyboard)
|
|
1098 |
if (ev->request == MappingKeyboard)
|
1175 | 1099 |
grabkeys();
|
1176 | 1100 |
}
|
1177 | 1101 |
|
1178 | 1102 |
void
|
1179 | |
maprequest(XEvent *e) {
|
|
1103 |
maprequest(XEvent *e)
|
|
1104 |
{
|
1180 | 1105 |
static XWindowAttributes wa;
|
1181 | 1106 |
XMapRequestEvent *ev = &e->xmaprequest;
|
1182 | 1107 |
|
1183 | |
if(!XGetWindowAttributes(dpy, ev->window, &wa))
|
1184 | |
return;
|
1185 | |
if(wa.override_redirect)
|
1186 | |
return;
|
1187 | |
if(!wintoclient(ev->window))
|
|
1108 |
if (!XGetWindowAttributes(dpy, ev->window, &wa))
|
|
1109 |
return;
|
|
1110 |
if (wa.override_redirect)
|
|
1111 |
return;
|
|
1112 |
if (!wintoclient(ev->window))
|
1188 | 1113 |
manage(ev->window, &wa);
|
1189 | 1114 |
}
|
1190 | 1115 |
|
1191 | 1116 |
void
|
1192 | |
monocle(Monitor *m) {
|
|
1117 |
monocle(Monitor *m)
|
|
1118 |
{
|
1193 | 1119 |
unsigned int n = 0;
|
1194 | 1120 |
Client *c;
|
1195 | 1121 |
|
1196 | |
for(c = m->clients; c; c = c->next)
|
1197 | |
if(ISVISIBLE(c))
|
|
1122 |
for (c = m->clients; c; c = c->next)
|
|
1123 |
if (ISVISIBLE(c))
|
1198 | 1124 |
n++;
|
1199 | |
if(n > 0) /* override layout symbol */
|
|
1125 |
if (n > 0) /* override layout symbol */
|
1200 | 1126 |
snprintf(m->ltsymbol, sizeof m->ltsymbol, "[%d]", n);
|
1201 | |
for(c = nexttiled(m->clients); c; c = nexttiled(c->next))
|
1202 | |
resize(c, m->wx, m->wy, m->ww - 2 * c->bw, m->wh - 2 * c->bw, False);
|
1203 | |
}
|
1204 | |
|
1205 | |
void
|
1206 | |
motionnotify(XEvent *e) {
|
|
1127 |
for (c = nexttiled(m->clients); c; c = nexttiled(c->next))
|
|
1128 |
resize(c, m->wx, m->wy, m->ww - 2 * c->bw, m->wh - 2 * c->bw, 0);
|
|
1129 |
}
|
|
1130 |
|
|
1131 |
void
|
|
1132 |
motionnotify(XEvent *e)
|
|
1133 |
{
|
1207 | 1134 |
static Monitor *mon = NULL;
|
1208 | 1135 |
Monitor *m;
|
1209 | 1136 |
XMotionEvent *ev = &e->xmotion;
|
1210 | 1137 |
|
1211 | |
if(ev->window != root)
|
1212 | |
return;
|
1213 | |
if((m = recttomon(ev->x_root, ev->y_root, 1, 1)) != mon && mon) {
|
|
1138 |
if (ev->window != root)
|
|
1139 |
return;
|
|
1140 |
if ((m = recttomon(ev->x_root, ev->y_root, 1, 1)) != mon && mon) {
|
|
1141 |
unfocus(selmon->sel, 1);
|
1214 | 1142 |
selmon = m;
|
1215 | 1143 |
focus(NULL);
|
1216 | 1144 |
}
|
|
1218 | 1146 |
}
|
1219 | 1147 |
|
1220 | 1148 |
void
|
1221 | |
movemouse(const Arg *arg) {
|
|
1149 |
movemouse(const Arg *arg)
|
|
1150 |
{
|
1222 | 1151 |
int x, y, ocx, ocy, nx, ny;
|
1223 | 1152 |
Client *c;
|
1224 | 1153 |
Monitor *m;
|
1225 | 1154 |
XEvent ev;
|
1226 | |
|
1227 | |
if(!(c = selmon->sel))
|
|
1155 |
Time lasttime = 0;
|
|
1156 |
|
|
1157 |
if (!(c = selmon->sel))
|
|
1158 |
return;
|
|
1159 |
if (c->isfullscreen) /* no support moving fullscreen windows by mouse */
|
1228 | 1160 |
return;
|
1229 | 1161 |
restack(selmon);
|
1230 | 1162 |
ocx = c->x;
|
1231 | 1163 |
ocy = c->y;
|
1232 | |
if(XGrabPointer(dpy, root, False, MOUSEMASK, GrabModeAsync, GrabModeAsync,
|
1233 | |
None, cursor[CurMove], CurrentTime) != GrabSuccess)
|
1234 | |
return;
|
1235 | |
if(!getrootptr(&x, &y))
|
|
1164 |
if (XGrabPointer(dpy, root, False, MOUSEMASK, GrabModeAsync, GrabModeAsync,
|
|
1165 |
None, cursor[CurMove]->cursor, CurrentTime) != GrabSuccess)
|
|
1166 |
return;
|
|
1167 |
if (!getrootptr(&x, &y))
|
1236 | 1168 |
return;
|
1237 | 1169 |
do {
|
1238 | 1170 |
XMaskEvent(dpy, MOUSEMASK|ExposureMask|SubstructureRedirectMask, &ev);
|
|
1243 | 1175 |
handler[ev.type](&ev);
|
1244 | 1176 |
break;
|
1245 | 1177 |
case MotionNotify:
|
|
1178 |
if ((ev.xmotion.time - lasttime) <= (1000 / 60))
|
|
1179 |
continue;
|
|
1180 |
lasttime = ev.xmotion.time;
|
|
1181 |
|
1246 | 1182 |
nx = ocx + (ev.xmotion.x - x);
|
1247 | 1183 |
ny = ocy + (ev.xmotion.y - y);
|
1248 | |
if(nx >= selmon->wx && nx <= selmon->wx + selmon->ww
|
|
1184 |
if (nx >= selmon->wx && nx <= selmon->wx + selmon->ww
|
1249 | 1185 |
&& ny >= selmon->wy && ny <= selmon->wy + selmon->wh) {
|
1250 | |
if(abs(selmon->wx - nx) < snap)
|
|
1186 |
if (abs(selmon->wx - nx) < snap)
|
1251 | 1187 |
nx = selmon->wx;
|
1252 | |
else if(abs((selmon->wx + selmon->ww) - (nx + WIDTH(c))) < snap)
|
|
1188 |
else if (abs((selmon->wx + selmon->ww) - (nx + WIDTH(c))) < snap)
|
1253 | 1189 |
nx = selmon->wx + selmon->ww - WIDTH(c);
|
1254 | |
if(abs(selmon->wy - ny) < snap)
|
|
1190 |
if (abs(selmon->wy - ny) < snap)
|
1255 | 1191 |
ny = selmon->wy;
|
1256 | |
else if(abs((selmon->wy + selmon->wh) - (ny + HEIGHT(c))) < snap)
|
|
1192 |
else if (abs((selmon->wy + selmon->wh) - (ny + HEIGHT(c))) < snap)
|
1257 | 1193 |
ny = selmon->wy + selmon->wh - HEIGHT(c);
|
1258 | |
if(!c->isfloating && selmon->lt[selmon->sellt]->arrange
|
|
1194 |
if (!c->isfloating && selmon->lt[selmon->sellt]->arrange
|
1259 | 1195 |
&& (abs(nx - c->x) > snap || abs(ny - c->y) > snap))
|
1260 | 1196 |
togglefloating(NULL);
|
1261 | 1197 |
}
|
1262 | |
if(!selmon->lt[selmon->sellt]->arrange || c->isfloating)
|
1263 | |
resize(c, nx, ny, c->w, c->h, True);
|
|
1198 |
if (!selmon->lt[selmon->sellt]->arrange || c->isfloating)
|
|
1199 |
resize(c, nx, ny, c->w, c->h, 1);
|
1264 | 1200 |
break;
|
1265 | 1201 |
}
|
1266 | |
} while(ev.type != ButtonRelease);
|
|
1202 |
} while (ev.type != ButtonRelease);
|
1267 | 1203 |
XUngrabPointer(dpy, CurrentTime);
|
1268 | |
if((m = recttomon(c->x, c->y, c->w, c->h)) != selmon) {
|
|
1204 |
if ((m = recttomon(c->x, c->y, c->w, c->h)) != selmon) {
|
1269 | 1205 |
sendmon(c, m);
|
1270 | 1206 |
selmon = m;
|
1271 | 1207 |
focus(NULL);
|
|
1273 | 1209 |
}
|
1274 | 1210 |
|
1275 | 1211 |
Client *
|
1276 | |
nexttiled(Client *c) {
|
1277 | |
for(; c && (c->isfloating || !ISVISIBLE(c)); c = c->next);
|
|
1212 |
nexttiled(Client *c)
|
|
1213 |
{
|
|
1214 |
for (; c && (c->isfloating || !ISVISIBLE(c)); c = c->next);
|
1278 | 1215 |
return c;
|
1279 | 1216 |
}
|
1280 | 1217 |
|
1281 | 1218 |
void
|
1282 | |
pop(Client *c) {
|
|
1219 |
pop(Client *c)
|
|
1220 |
{
|
1283 | 1221 |
detach(c);
|
1284 | 1222 |
attach(c);
|
1285 | 1223 |
focus(c);
|
|
1287 | 1225 |
}
|
1288 | 1226 |
|
1289 | 1227 |
void
|
1290 | |
propertynotify(XEvent *e) {
|
|
1228 |
propertynotify(XEvent *e)
|
|
1229 |
{
|
1291 | 1230 |
Client *c;
|
1292 | 1231 |
Window trans;
|
1293 | 1232 |
XPropertyEvent *ev = &e->xproperty;
|
1294 | 1233 |
|
1295 | |
if((ev->window == root) && (ev->atom == XA_WM_NAME))
|
|
1234 |
if ((ev->window == root) && (ev->atom == XA_WM_NAME))
|
1296 | 1235 |
updatestatus();
|
1297 | |
else if(ev->state == PropertyDelete)
|
|
1236 |
else if (ev->state == PropertyDelete)
|
1298 | 1237 |
return; /* ignore */
|
1299 | |
else if((c = wintoclient(ev->window))) {
|
|
1238 |
else if ((c = wintoclient(ev->window))) {
|
1300 | 1239 |
switch(ev->atom) {
|
1301 | 1240 |
default: break;
|
1302 | 1241 |
case XA_WM_TRANSIENT_FOR:
|
1303 | |
if(!c->isfloating && (XGetTransientForHint(dpy, c->win, &trans)) &&
|
|
1242 |
if (!c->isfloating && (XGetTransientForHint(dpy, c->win, &trans)) &&
|
1304 | 1243 |
(c->isfloating = (wintoclient(trans)) != NULL))
|
1305 | 1244 |
arrange(c->mon);
|
1306 | 1245 |
break;
|
|
1312 | 1251 |
drawbars();
|
1313 | 1252 |
break;
|
1314 | 1253 |
}
|
1315 | |
if(ev->atom == XA_WM_NAME || ev->atom == netatom[NetWMName]) {
|
|
1254 |
if (ev->atom == XA_WM_NAME || ev->atom == netatom[NetWMName]) {
|
1316 | 1255 |
updatetitle(c);
|
1317 | |
if(c == c->mon->sel)
|
|
1256 |
if (c == c->mon->sel)
|
1318 | 1257 |
drawbar(c->mon);
|
1319 | 1258 |
}
|
1320 | |
if(ev->atom == netatom[NetWMWindowType])
|
|
1259 |
if (ev->atom == netatom[NetWMWindowType])
|
1321 | 1260 |
updatewindowtype(c);
|
1322 | 1261 |
}
|
1323 | 1262 |
}
|
1324 | 1263 |
|
1325 | 1264 |
void
|
1326 | |
quit(const Arg *arg) {
|
1327 | |
running = False;
|
|
1265 |
quit(const Arg *arg)
|
|
1266 |
{
|
|
1267 |
running = 0;
|
1328 | 1268 |
}
|
1329 | 1269 |
|
1330 | 1270 |
Monitor *
|
1331 | |
recttomon(int x, int y, int w, int h) {
|
|
1271 |
recttomon(int x, int y, int w, int h)
|
|
1272 |
{
|
1332 | 1273 |
Monitor *m, *r = selmon;
|
1333 | 1274 |
int a, area = 0;
|
1334 | 1275 |
|
1335 | |
for(m = mons; m; m = m->next)
|
1336 | |
if((a = INTERSECT(x, y, w, h, m)) > area) {
|
|
1276 |
for (m = mons; m; m = m->next)
|
|
1277 |
if ((a = INTERSECT(x, y, w, h, m)) > area) {
|
1337 | 1278 |
area = a;
|
1338 | 1279 |
r = m;
|
1339 | 1280 |
}
|
|
1341 | 1282 |
}
|
1342 | 1283 |
|
1343 | 1284 |
void
|
1344 | |
resize(Client *c, int x, int y, int w, int h, Bool interact) {
|
1345 | |
if(applysizehints(c, &x, &y, &w, &h, interact))
|
|
1285 |
resize(Client *c, int x, int y, int w, int h, int interact)
|
|
1286 |
{
|
|
1287 |
if (applysizehints(c, &x, &y, &w, &h, interact))
|
1346 | 1288 |
resizeclient(c, x, y, w, h);
|
1347 | 1289 |
}
|
1348 | 1290 |
|
1349 | 1291 |
void
|
1350 | |
resizeclient(Client *c, int x, int y, int w, int h) {
|
|
1292 |
resizeclient(Client *c, int x, int y, int w, int h)
|
|
1293 |
{
|
1351 | 1294 |
XWindowChanges wc;
|
1352 | 1295 |
|
1353 | 1296 |
c->oldx = c->x; c->x = wc.x = x;
|
|
1361 | 1304 |
}
|
1362 | 1305 |
|
1363 | 1306 |
void
|
1364 | |
resizemouse(const Arg *arg) {
|
1365 | |
int ocx, ocy;
|
1366 | |
int nw, nh;
|
|
1307 |
resizemouse(const Arg *arg)
|
|
1308 |
{
|
|
1309 |
int ocx, ocy, nw, nh;
|
1367 | 1310 |
Client *c;
|
1368 | 1311 |
Monitor *m;
|
1369 | 1312 |
XEvent ev;
|
1370 | |
|
1371 | |
if(!(c = selmon->sel))
|
|
1313 |
Time lasttime = 0;
|
|
1314 |
|
|
1315 |
if (!(c = selmon->sel))
|
|
1316 |
return;
|
|
1317 |
if (c->isfullscreen) /* no support resizing fullscreen windows by mouse */
|
1372 | 1318 |
return;
|
1373 | 1319 |
restack(selmon);
|
1374 | 1320 |
ocx = c->x;
|
1375 | 1321 |
ocy = c->y;
|
1376 | |
if(XGrabPointer(dpy, root, False, MOUSEMASK, GrabModeAsync, GrabModeAsync,
|
1377 | |
None, cursor[CurResize], CurrentTime) != GrabSuccess)
|
|
1322 |
if (XGrabPointer(dpy, root, False, MOUSEMASK, GrabModeAsync, GrabModeAsync,
|
|
1323 |
None, cursor[CurResize]->cursor, CurrentTime) != GrabSuccess)
|
1378 | 1324 |
return;
|
1379 | 1325 |
XWarpPointer(dpy, None, c->win, 0, 0, 0, 0, c->w + c->bw - 1, c->h + c->bw - 1);
|
1380 | 1326 |
do {
|
|
1386 | 1332 |
handler[ev.type](&ev);
|
1387 | 1333 |
break;
|
1388 | 1334 |
case MotionNotify:
|
|
1335 |
if ((ev.xmotion.time - lasttime) <= (1000 / 60))
|
|
1336 |
continue;
|
|
1337 |
lasttime = ev.xmotion.time;
|
|
1338 |
|
1389 | 1339 |
nw = MAX(ev.xmotion.x - ocx - 2 * c->bw + 1, 1);
|
1390 | 1340 |
nh = MAX(ev.xmotion.y - ocy - 2 * c->bw + 1, 1);
|
1391 | |
if(c->mon->wx + nw >= selmon->wx && c->mon->wx + nw <= selmon->wx + selmon->ww
|
|
1341 |
if (c->mon->wx + nw >= selmon->wx && c->mon->wx + nw <= selmon->wx + selmon->ww
|
1392 | 1342 |
&& c->mon->wy + nh >= selmon->wy && c->mon->wy + nh <= selmon->wy + selmon->wh)
|
1393 | 1343 |
{
|
1394 | |
if(!c->isfloating && selmon->lt[selmon->sellt]->arrange
|
|
1344 |
if (!c->isfloating && selmon->lt[selmon->sellt]->arrange
|
1395 | 1345 |
&& (abs(nw - c->w) > snap || abs(nh - c->h) > snap))
|
1396 | 1346 |
togglefloating(NULL);
|
1397 | 1347 |
}
|
1398 | |
if(!selmon->lt[selmon->sellt]->arrange || c->isfloating)
|
1399 | |
resize(c, c->x, c->y, nw, nh, True);
|
|
1348 |
if (!selmon->lt[selmon->sellt]->arrange || c->isfloating)
|
|
1349 |
resize(c, c->x, c->y, nw, nh, 1);
|
1400 | 1350 |
break;
|
1401 | 1351 |
}
|
1402 | |
} while(ev.type != ButtonRelease);
|
|
1352 |
} while (ev.type != ButtonRelease);
|
1403 | 1353 |
XWarpPointer(dpy, None, c->win, 0, 0, 0, 0, c->w + c->bw - 1, c->h + c->bw - 1);
|
1404 | 1354 |
XUngrabPointer(dpy, CurrentTime);
|
1405 | |
while(XCheckMaskEvent(dpy, EnterWindowMask, &ev));
|
1406 | |
if((m = recttomon(c->x, c->y, c->w, c->h)) != selmon) {
|
|
1355 |
while (XCheckMaskEvent(dpy, EnterWindowMask, &ev));
|
|
1356 |
if ((m = recttomon(c->x, c->y, c->w, c->h)) != selmon) {
|
1407 | 1357 |
sendmon(c, m);
|
1408 | 1358 |
selmon = m;
|
1409 | 1359 |
focus(NULL);
|
|
1411 | 1361 |
}
|
1412 | 1362 |
|
1413 | 1363 |
void
|
1414 | |
restack(Monitor *m) {
|
|
1364 |
restack(Monitor *m)
|
|
1365 |
{
|
1415 | 1366 |
Client *c;
|
1416 | 1367 |
XEvent ev;
|
1417 | 1368 |
XWindowChanges wc;
|
1418 | 1369 |
|
1419 | 1370 |
drawbar(m);
|
1420 | |
if(!m->sel)
|
1421 | |
return;
|
1422 | |
if(m->sel->isfloating || !m->lt[m->sellt]->arrange)
|
|
1371 |
if (!m->sel)
|
|
1372 |
return;
|
|
1373 |
if (m->sel->isfloating || !m->lt[m->sellt]->arrange)
|
1423 | 1374 |
XRaiseWindow(dpy, m->sel->win);
|
1424 | |
if(m->lt[m->sellt]->arrange) {
|
|
1375 |
if (m->lt[m->sellt]->arrange) {
|
1425 | 1376 |
wc.stack_mode = Below;
|
1426 | 1377 |
wc.sibling = m->barwin;
|
1427 | |
for(c = m->stack; c; c = c->snext)
|
1428 | |
if(!c->isfloating && ISVISIBLE(c)) {
|
|
1378 |
for (c = m->stack; c; c = c->snext)
|
|
1379 |
if (!c->isfloating && ISVISIBLE(c)) {
|
1429 | 1380 |
XConfigureWindow(dpy, c->win, CWSibling|CWStackMode, &wc);
|
1430 | 1381 |
wc.sibling = c->win;
|
1431 | 1382 |
}
|
1432 | 1383 |
}
|
1433 | 1384 |
XSync(dpy, False);
|
1434 | |
while(XCheckMaskEvent(dpy, EnterWindowMask, &ev));
|
1435 | |
}
|
1436 | |
|
1437 | |
void
|
1438 | |
run(void) {
|
|
1385 |
while (XCheckMaskEvent(dpy, EnterWindowMask, &ev));
|
|
1386 |
}
|
|
1387 |
|
|
1388 |
void
|
|
1389 |
run(void)
|
|
1390 |
{
|
1439 | 1391 |
XEvent ev;
|
1440 | 1392 |
/* main event loop */
|
1441 | 1393 |
XSync(dpy, False);
|
1442 | |
while(running && !XNextEvent(dpy, &ev))
|
1443 | |
if(handler[ev.type])
|
|
1394 |
while (running && !XNextEvent(dpy, &ev))
|
|
1395 |
if (handler[ev.type])
|
1444 | 1396 |
handler[ev.type](&ev); /* call handler */
|
1445 | 1397 |
}
|
1446 | 1398 |
|
1447 | 1399 |
void
|
1448 | |
scan(void) {
|
|
1400 |
scan(void)
|
|
1401 |
{
|
1449 | 1402 |
unsigned int i, num;
|
1450 | 1403 |
Window d1, d2, *wins = NULL;
|
1451 | 1404 |
XWindowAttributes wa;
|
1452 | 1405 |
|
1453 | |
if(XQueryTree(dpy, root, &d1, &d2, &wins, &num)) {
|
1454 | |
for(i = 0; i < num; i++) {
|
1455 | |
if(!XGetWindowAttributes(dpy, wins[i], &wa)
|
|
1406 |
if (XQueryTree(dpy, root, &d1, &d2, &wins, &num)) {
|
|
1407 |
for (i = 0; i < num; i++) {
|
|
1408 |
if (!XGetWindowAttributes(dpy, wins[i], &wa)
|
1456 | 1409 |
|| wa.override_redirect || XGetTransientForHint(dpy, wins[i], &d1))
|
1457 | 1410 |
continue;
|
1458 | |
if(wa.map_state == IsViewable || getstate(wins[i]) == IconicState)
|
|
1411 |
if (wa.map_state == IsViewable || getstate(wins[i]) == IconicState)
|
1459 | 1412 |
manage(wins[i], &wa);
|
1460 | 1413 |
}
|
1461 | |
for(i = 0; i < num; i++) { /* now the transients */
|
1462 | |
if(!XGetWindowAttributes(dpy, wins[i], &wa))
|
|
1414 |
for (i = 0; i < num; i++) { /* now the transients */
|
|
1415 |
if (!XGetWindowAttributes(dpy, wins[i], &wa))
|
1463 | 1416 |
continue;
|
1464 | |
if(XGetTransientForHint(dpy, wins[i], &d1)
|
|
1417 |
if (XGetTransientForHint(dpy, wins[i], &d1)
|
1465 | 1418 |
&& (wa.map_state == IsViewable || getstate(wins[i]) == IconicState))
|
1466 | 1419 |
manage(wins[i], &wa);
|
1467 | 1420 |
}
|
1468 | |
if(wins)
|
|
1421 |
if (wins)
|
1469 | 1422 |
XFree(wins);
|
1470 | 1423 |
}
|
1471 | 1424 |
}
|
1472 | 1425 |
|
1473 | 1426 |
void
|
1474 | |
sendmon(Client *c, Monitor *m) {
|
1475 | |
if(c->mon == m)
|
1476 | |
return;
|
1477 | |
unfocus(c, True);
|
|
1427 |
sendmon(Client *c, Monitor *m)
|
|
1428 |
{
|
|
1429 |
if (c->mon == m)
|
|
1430 |
return;
|
|
1431 |
unfocus(c, 1);
|
1478 | 1432 |
detach(c);
|
1479 | 1433 |
detachstack(c);
|
1480 | 1434 |
c->mon = m;
|
|
1486 | 1440 |
}
|
1487 | 1441 |
|
1488 | 1442 |
void
|
1489 | |
setclientstate(Client *c, long state) {
|
|
1443 |
setclientstate(Client *c, long state)
|
|
1444 |
{
|
1490 | 1445 |
long data[] = { state, None };
|
1491 | 1446 |
|
1492 | 1447 |
XChangeProperty(dpy, c->win, wmatom[WMState], wmatom[WMState], 32,
|
1493 | 1448 |
PropModeReplace, (unsigned char *)data, 2);
|
1494 | 1449 |
}
|
1495 | 1450 |
|
1496 | |
Bool
|
1497 | |
sendevent(Client *c, Atom proto) {
|
|
1451 |
int
|
|
1452 |
sendevent(Client *c, Atom proto)
|
|
1453 |
{
|
1498 | 1454 |
int n;
|
1499 | 1455 |
Atom *protocols;
|
1500 | |
Bool exists = False;
|
|
1456 |
int exists = 0;
|
1501 | 1457 |
XEvent ev;
|
1502 | 1458 |
|
1503 | |
if(XGetWMProtocols(dpy, c->win, &protocols, &n)) {
|
1504 | |
while(!exists && n--)
|
|
1459 |
if (XGetWMProtocols(dpy, c->win, &protocols, &n)) {
|
|
1460 |
while (!exists && n--)
|
1505 | 1461 |
exists = protocols[n] == proto;
|
1506 | 1462 |
XFree(protocols);
|
1507 | 1463 |
}
|
1508 | |
if(exists) {
|
|
1464 |
if (exists) {
|
1509 | 1465 |
ev.type = ClientMessage;
|
1510 | 1466 |
ev.xclient.window = c->win;
|
1511 | 1467 |
ev.xclient.message_type = wmatom[WMProtocols];
|
|
1518 | 1474 |
}
|
1519 | 1475 |
|
1520 | 1476 |
void
|
1521 | |
setfocus(Client *c) {
|
1522 | |
if(!c->neverfocus)
|
|
1477 |
setfocus(Client *c)
|
|
1478 |
{
|
|
1479 |
if (!c->neverfocus) {
|
1523 | 1480 |
XSetInputFocus(dpy, c->win, RevertToPointerRoot, CurrentTime);
|
|
1481 |
XChangeProperty(dpy, root, netatom[NetActiveWindow],
|
|
1482 |
XA_WINDOW, 32, PropModeReplace,
|
|
1483 |
(unsigned char *) &(c->win), 1);
|
|
1484 |
}
|
1524 | 1485 |
sendevent(c, wmatom[WMTakeFocus]);
|
1525 | 1486 |
}
|
1526 | 1487 |
|
1527 | 1488 |
void
|
1528 | |
setfullscreen(Client *c, Bool fullscreen) {
|
1529 | |
if(fullscreen) {
|
|
1489 |
setfullscreen(Client *c, int fullscreen)
|
|
1490 |
{
|
|
1491 |
if (fullscreen && !c->isfullscreen) {
|
1530 | 1492 |
XChangeProperty(dpy, c->win, netatom[NetWMState], XA_ATOM, 32,
|
1531 | 1493 |
PropModeReplace, (unsigned char*)&netatom[NetWMFullscreen], 1);
|
1532 | |
c->isfullscreen = True;
|
|
1494 |
c->isfullscreen = 1;
|
1533 | 1495 |
c->oldstate = c->isfloating;
|
1534 | 1496 |
c->oldbw = c->bw;
|
1535 | 1497 |
c->bw = 0;
|
1536 | |
c->isfloating = True;
|
|
1498 |
c->isfloating = 1;
|
1537 | 1499 |
resizeclient(c, c->mon->mx, c->mon->my, c->mon->mw, c->mon->mh);
|
1538 | 1500 |
XRaiseWindow(dpy, c->win);
|
1539 | |
}
|
1540 | |
else {
|
|
1501 |
} else if (!fullscreen && c->isfullscreen){
|
1541 | 1502 |
XChangeProperty(dpy, c->win, netatom[NetWMState], XA_ATOM, 32,
|
1542 | 1503 |
PropModeReplace, (unsigned char*)0, 0);
|
1543 | |
c->isfullscreen = False;
|
|
1504 |
c->isfullscreen = 0;
|
1544 | 1505 |
c->isfloating = c->oldstate;
|
1545 | 1506 |
c->bw = c->oldbw;
|
1546 | 1507 |
c->x = c->oldx;
|
|
1553 | 1514 |
}
|
1554 | 1515 |
|
1555 | 1516 |
void
|
1556 | |
setlayout(const Arg *arg) {
|
1557 | |
if(!arg || !arg->v || arg->v != selmon->lt[selmon->sellt])
|
|
1517 |
setlayout(const Arg *arg)
|
|
1518 |
{
|
|
1519 |
if (!arg || !arg->v || arg->v != selmon->lt[selmon->sellt])
|
1558 | 1520 |
selmon->sellt ^= 1;
|
1559 | |
if(arg && arg->v)
|
|
1521 |
if (arg && arg->v)
|
1560 | 1522 |
selmon->lt[selmon->sellt] = (Layout *)arg->v;
|
1561 | 1523 |
strncpy(selmon->ltsymbol, selmon->lt[selmon->sellt]->symbol, sizeof selmon->ltsymbol);
|
1562 | |
if(selmon->sel)
|
|
1524 |
if (selmon->sel)
|
1563 | 1525 |
arrange(selmon);
|
1564 | 1526 |
else
|
1565 | 1527 |
drawbar(selmon);
|
|
1567 | 1529 |
|
1568 | 1530 |
/* arg > 1.0 will set mfact absolutly */
|
1569 | 1531 |
void
|
1570 | |
setmfact(const Arg *arg) {
|
|
1532 |
setmfact(const Arg *arg)
|
|
1533 |
{
|
1571 | 1534 |
float f;
|
1572 | 1535 |
|
1573 | |
if(!arg || !selmon->lt[selmon->sellt]->arrange)
|
|
1536 |
if (!arg || !selmon->lt[selmon->sellt]->arrange)
|
1574 | 1537 |
return;
|
1575 | 1538 |
f = arg->f < 1.0 ? arg->f + selmon->mfact : arg->f - 1.0;
|
1576 | |
if(f < 0.1 || f > 0.9)
|
|
1539 |
if (f < 0.1 || f > 0.9)
|
1577 | 1540 |
return;
|
1578 | 1541 |
selmon->mfact = f;
|
1579 | 1542 |
arrange(selmon);
|
1580 | 1543 |
}
|
1581 | 1544 |
|
1582 | 1545 |
void
|
1583 | |
setup(void) {
|
|
1546 |
setup(void)
|
|
1547 |
{
|
1584 | 1548 |
XSetWindowAttributes wa;
|
1585 | 1549 |
|
1586 | 1550 |
/* clean up any zombies immediately */
|
|
1588 | 1552 |
|
1589 | 1553 |
/* init screen */
|
1590 | 1554 |
screen = DefaultScreen(dpy);
|
1591 | |
root = RootWindow(dpy, screen);
|
1592 | |
initfont(font);
|
1593 | 1555 |
sw = DisplayWidth(dpy, screen);
|
1594 | 1556 |
sh = DisplayHeight(dpy, screen);
|
1595 | |
bh = dc.h = dc.font.height + 2;
|
|
1557 |
root = RootWindow(dpy, screen);
|
|
1558 |
drw = drw_create(dpy, screen, root, sw, sh);
|
|
1559 |
drw_load_fonts(drw, fonts, LENGTH(fonts));
|
|
1560 |
if (!drw->fontcount)
|
|
1561 |
die("no fonts could be loaded.\n");
|
|
1562 |
bh = drw->fonts[0]->h + 2;
|
1596 | 1563 |
updategeom();
|
1597 | 1564 |
/* init atoms */
|
1598 | 1565 |
wmatom[WMProtocols] = XInternAtom(dpy, "WM_PROTOCOLS", False);
|
|
1606 | 1573 |
netatom[NetWMFullscreen] = XInternAtom(dpy, "_NET_WM_STATE_FULLSCREEN", False);
|
1607 | 1574 |
netatom[NetWMWindowType] = XInternAtom(dpy, "_NET_WM_WINDOW_TYPE", False);
|
1608 | 1575 |
netatom[NetWMWindowTypeDialog] = XInternAtom(dpy, "_NET_WM_WINDOW_TYPE_DIALOG", False);
|
|
1576 |
netatom[NetClientList] = XInternAtom(dpy, "_NET_CLIENT_LIST", False);
|
1609 | 1577 |
/* init cursors */
|
1610 | |
cursor[CurNormal] = XCreateFontCursor(dpy, XC_left_ptr);
|
1611 | |
cursor[CurResize] = XCreateFontCursor(dpy, XC_sizing);
|
1612 | |
cursor[CurMove] = XCreateFontCursor(dpy, XC_fleur);
|
|
1578 |
cursor[CurNormal] = drw_cur_create(drw, XC_left_ptr);
|
|
1579 |
cursor[CurResize] = drw_cur_create(drw, XC_sizing);
|
|
1580 |
cursor[CurMove] = drw_cur_create(drw, XC_fleur);
|
1613 | 1581 |
/* init appearance */
|
1614 | |
dc.norm[ColBorder] = getcolor(normbordercolor);
|
1615 | |
dc.norm[ColBG] = getcolor(normbgcolor);
|
1616 | |
dc.norm[ColFG] = getcolor(normfgcolor);
|
1617 | |
dc.sel[ColBorder] = getcolor(selbordercolor);
|
1618 | |
dc.sel[ColBG] = getcolor(selbgcolor);
|
1619 | |
dc.sel[ColFG] = getcolor(selfgcolor);
|
1620 | |
dc.drawable = XCreatePixmap(dpy, root, DisplayWidth(dpy, screen), bh, DefaultDepth(dpy, screen));
|
1621 | |
dc.gc = XCreateGC(dpy, root, 0, NULL);
|
1622 | |
XSetLineAttributes(dpy, dc.gc, 1, LineSolid, CapButt, JoinMiter);
|
1623 | |
if(!dc.font.set)
|
1624 | |
XSetFont(dpy, dc.gc, dc.font.xfont->fid);
|
|
1582 |
scheme[SchemeNorm].border = drw_clr_create(drw, normbordercolor);
|
|
1583 |
scheme[SchemeNorm].bg = drw_clr_create(drw, normbgcolor);
|
|
1584 |
scheme[SchemeNorm].fg = drw_clr_create(drw, normfgcolor);
|
|
1585 |
scheme[SchemeSel].border = drw_clr_create(drw, selbordercolor);
|
|
1586 |
scheme[SchemeSel].bg = drw_clr_create(drw, selbgcolor);
|
|
1587 |
scheme[SchemeSel].fg = drw_clr_create(drw, selfgcolor);
|
1625 | 1588 |
/* init bars */
|
1626 | 1589 |
updatebars();
|
1627 | 1590 |
updatestatus();
|
1628 | 1591 |
/* EWMH support per view */
|
1629 | 1592 |
XChangeProperty(dpy, root, netatom[NetSupported], XA_ATOM, 32,
|
1630 | 1593 |
PropModeReplace, (unsigned char *) netatom, NetLast);
|
|
1594 |
XDeleteProperty(dpy, root, netatom[NetClientList]);
|
1631 | 1595 |
/* select for events */
|
1632 | |
wa.cursor = cursor[CurNormal];
|
|
1596 |
wa.cursor = cursor[CurNormal]->cursor;
|
1633 | 1597 |
wa.event_mask = SubstructureRedirectMask|SubstructureNotifyMask|ButtonPressMask|PointerMotionMask
|
1634 | 1598 |
|EnterWindowMask|LeaveWindowMask|StructureNotifyMask|PropertyChangeMask;
|
1635 | 1599 |
XChangeWindowAttributes(dpy, root, CWEventMask|CWCursor, &wa);
|
1636 | 1600 |
XSelectInput(dpy, root, wa.event_mask);
|
1637 | 1601 |
grabkeys();
|
1638 | |
}
|
1639 | |
|
1640 | |
void
|
1641 | |
showhide(Client *c) {
|
1642 | |
if(!c)
|
1643 | |
return;
|
1644 | |
if(ISVISIBLE(c)) { /* show clients top down */
|
|
1602 |
focus(NULL);
|
|
1603 |
}
|
|
1604 |
|
|
1605 |
void
|
|
1606 |
showhide(Client *c)
|
|
1607 |
{
|
|
1608 |
if (!c)
|
|
1609 |
return;
|
|
1610 |
if (ISVISIBLE(c)) {
|
|
1611 |
/* show clients top down */
|
1645 | 1612 |
XMoveWindow(dpy, c->win, c->x, c->y);
|
1646 | |
if((!c->mon->lt[c->mon->sellt]->arrange || c->isfloating) && !c->isfullscreen)
|
1647 | |
resize(c, c->x, c->y, c->w, c->h, False);
|
|
1613 |
if ((!c->mon->lt[c->mon->sellt]->arrange || c->isfloating) && !c->isfullscreen)
|
|
1614 |
resize(c, c->x, c->y, c->w, c->h, 0);
|
1648 | 1615 |
showhide(c->snext);
|
1649 | |
}
|
1650 | |
else { /* hide clients bottom up */
|
|
1616 |
} else {
|
|
1617 |
/* hide clients bottom up */
|
1651 | 1618 |
showhide(c->snext);
|
1652 | 1619 |
XMoveWindow(dpy, c->win, WIDTH(c) * -2, c->y);
|
1653 | 1620 |
}
|
1654 | 1621 |
}
|
1655 | 1622 |
|
1656 | 1623 |
void
|
1657 | |
sigchld(int unused) {
|
1658 | |
if(signal(SIGCHLD, sigchld) == SIG_ERR)
|
1659 | |
die("Can't install SIGCHLD handler");
|
1660 | |
while(0 < waitpid(-1, NULL, WNOHANG));
|
1661 | |
}
|
1662 | |
|
1663 | |
void
|
1664 | |
spawn(const Arg *arg) {
|
1665 | |
if(fork() == 0) {
|
1666 | |
if(dpy)
|
|
1624 |
sigchld(int unused)
|
|
1625 |
{
|
|
1626 |
if (signal(SIGCHLD, sigchld) == SIG_ERR)
|
|
1627 |
die("can't install SIGCHLD handler:");
|
|
1628 |
while (0 < waitpid(-1, NULL, WNOHANG));
|
|
1629 |
}
|
|
1630 |
|
|
1631 |
void
|
|
1632 |
spawn(const Arg *arg)
|
|
1633 |
{
|
|
1634 |
if (arg->v == dmenucmd)
|
|
1635 |
dmenumon[0] = '0' + selmon->num;
|
|
1636 |
if (fork() == 0) {
|
|
1637 |
if (dpy)
|
1667 | 1638 |
close(ConnectionNumber(dpy));
|
1668 | 1639 |
setsid();
|
1669 | 1640 |
execvp(((char **)arg->v)[0], (char **)arg->v);
|
|
1674 | 1645 |
}
|
1675 | 1646 |
|
1676 | 1647 |
void
|
1677 | |
tag(const Arg *arg) {
|
1678 | |
if(selmon->sel && arg->ui & TAGMASK) {
|
|
1648 |
tag(const Arg *arg)
|
|
1649 |
{
|
|
1650 |
if (selmon->sel && arg->ui & TAGMASK) {
|
1679 | 1651 |
selmon->sel->tags = arg->ui & TAGMASK;
|
1680 | 1652 |
focus(NULL);
|
1681 | 1653 |
arrange(selmon);
|
|
1683 | 1655 |
}
|
1684 | 1656 |
|
1685 | 1657 |
void
|
1686 | |
tagmon(const Arg *arg) {
|
1687 | |
if(!selmon->sel || !mons->next)
|
|
1658 |
tagmon(const Arg *arg)
|
|
1659 |
{
|
|
1660 |
if (!selmon->sel || !mons->next)
|
1688 | 1661 |
return;
|
1689 | 1662 |
sendmon(selmon->sel, dirtomon(arg->i));
|
1690 | 1663 |
}
|
1691 | 1664 |
|
1692 | |
int
|
1693 | |
textnw(const char *text, unsigned int len) {
|
1694 | |
XRectangle r;
|
1695 | |
|
1696 | |
if(dc.font.set) {
|
1697 | |
XmbTextExtents(dc.font.set, text, len, NULL, &r);
|
1698 | |
return r.width;
|
1699 | |
}
|
1700 | |
return XTextWidth(dc.font.xfont, text, len);
|
1701 | |
}
|
1702 | |
|
1703 | |
void
|
1704 | |
tile(Monitor *m) {
|
|
1665 |
void
|
|
1666 |
tile(Monitor *m)
|
|
1667 |
{
|
1705 | 1668 |
unsigned int i, n, h, mw, my, ty;
|
1706 | 1669 |
Client *c;
|
1707 | 1670 |
|
1708 | |
for(n = 0, c = nexttiled(m->clients); c; c = nexttiled(c->next), n++);
|
1709 | |
if(n == 0)
|
1710 | |
return;
|
1711 | |
|
1712 | |
if(n > m->nmaster)
|
|
1671 |
for (n = 0, c = nexttiled(m->clients); c; c = nexttiled(c->next), n++);
|
|
1672 |
if (n == 0)
|
|
1673 |
return;
|
|
1674 |
|
|
1675 |
if (n > m->nmaster)
|
1713 | 1676 |
mw = m->nmaster ? m->ww * m->mfact : 0;
|
1714 | 1677 |
else
|
1715 | 1678 |
mw = m->ww;
|
1716 | |
for(i = my = ty = 0, c = nexttiled(m->clients); c; c = nexttiled(c->next), i++)
|
1717 | |
if(i < m->nmaster) {
|
|
1679 |
for (i = my = ty = 0, c = nexttiled(m->clients); c; c = nexttiled(c->next), i++)
|
|
1680 |
if (i < m->nmaster) {
|
1718 | 1681 |
h = (m->wh - my) / (MIN(n, m->nmaster) - i);
|
1719 | |
resize(c, m->wx, m->wy + my, mw - (2*c->bw), h - (2*c->bw), False);
|
|
1682 |
resize(c, m->wx, m->wy + my, mw - (2*c->bw), h - (2*c->bw), 0);
|
1720 | 1683 |
my += HEIGHT(c);
|
1721 | |
}
|
1722 | |
else {
|
|
1684 |
} else {
|
1723 | 1685 |
h = (m->wh - ty) / (n - i);
|
1724 | |
resize(c, m->wx + mw, m->wy + ty, m->ww - mw - (2*c->bw), h - (2*c->bw), False);
|
|
1686 |
resize(c, m->wx + mw, m->wy + ty, m->ww - mw - (2*c->bw), h - (2*c->bw), 0);
|
1725 | 1687 |
ty += HEIGHT(c);
|
1726 | 1688 |
}
|
1727 | 1689 |
}
|
1728 | 1690 |
|
1729 | 1691 |
void
|
1730 | |
togglebar(const Arg *arg) {
|
|
1692 |
togglebar(const Arg *arg)
|
|
1693 |
{
|
1731 | 1694 |
selmon->showbar = !selmon->showbar;
|
1732 | 1695 |
updatebarpos(selmon);
|
1733 | 1696 |
XMoveResizeWindow(dpy, selmon->barwin, selmon->wx, selmon->by, selmon->ww, bh);
|
|
1735 | 1698 |
}
|
1736 | 1699 |
|
1737 | 1700 |
void
|
1738 | |
togglefloating(const Arg *arg) {
|
1739 | |
if(!selmon->sel)
|
|
1701 |
togglefloating(const Arg *arg)
|
|
1702 |
{
|
|
1703 |
if (!selmon->sel)
|
|
1704 |
return;
|
|
1705 |
if (selmon->sel->isfullscreen) /* no support for fullscreen windows */
|
1740 | 1706 |
return;
|
1741 | 1707 |
selmon->sel->isfloating = !selmon->sel->isfloating || selmon->sel->isfixed;
|
1742 | |
if(selmon->sel->isfloating)
|
|
1708 |
if (selmon->sel->isfloating)
|
1743 | 1709 |
resize(selmon->sel, selmon->sel->x, selmon->sel->y,
|
1744 | |
selmon->sel->w, selmon->sel->h, False);
|
|
1710 |
selmon->sel->w, selmon->sel->h, 0);
|
1745 | 1711 |
arrange(selmon);
|
1746 | 1712 |
}
|
1747 | 1713 |
|
1748 | 1714 |
void
|
1749 | |
toggletag(const Arg *arg) {
|
|
1715 |
toggletag(const Arg *arg)
|
|
1716 |
{
|
1750 | 1717 |
unsigned int newtags;
|
1751 | 1718 |
|
1752 | |
if(!selmon->sel)
|
|
1719 |
if (!selmon->sel)
|
1753 | 1720 |
return;
|
1754 | 1721 |
newtags = selmon->sel->tags ^ (arg->ui & TAGMASK);
|
1755 | |
if(newtags) {
|
|
1722 |
if (newtags) {
|
1756 | 1723 |
selmon->sel->tags = newtags;
|
1757 | 1724 |
focus(NULL);
|
1758 | 1725 |
arrange(selmon);
|
|
1760 | 1727 |
}
|
1761 | 1728 |
|
1762 | 1729 |
void
|
1763 | |
toggleview(const Arg *arg) {
|
|
1730 |
toggleview(const Arg *arg)
|
|
1731 |
{
|
1764 | 1732 |
unsigned int newtagset = selmon->tagset[selmon->seltags] ^ (arg->ui & TAGMASK);
|
1765 | 1733 |
|
1766 | |
if(newtagset) {
|
|
1734 |
if (newtagset) {
|
1767 | 1735 |
selmon->tagset[selmon->seltags] = newtagset;
|
1768 | 1736 |
focus(NULL);
|
1769 | 1737 |
arrange(selmon);
|
|
1771 | 1739 |
}
|
1772 | 1740 |
|
1773 | 1741 |
void
|
1774 | |
unfocus(Client *c, Bool setfocus) {
|
1775 | |
if(!c)
|
1776 | |
return;
|
1777 | |
grabbuttons(c, False);
|
1778 | |
XSetWindowBorder(dpy, c->win, dc.norm[ColBorder]);
|
1779 | |
if(setfocus)
|
|
1742 |
unfocus(Client *c, int setfocus)
|
|
1743 |
{
|
|
1744 |
if (!c)
|
|
1745 |
return;
|
|
1746 |
grabbuttons(c, 0);
|
|
1747 |
XSetWindowBorder(dpy, c->win, scheme[SchemeNorm].border->pix);
|
|
1748 |
if (setfocus) {
|
1780 | 1749 |
XSetInputFocus(dpy, root, RevertToPointerRoot, CurrentTime);
|
1781 | |
}
|
1782 | |
|
1783 | |
void
|
1784 | |
unmanage(Client *c, Bool destroyed) {
|
|
1750 |
XDeleteProperty(dpy, root, netatom[NetActiveWindow]);
|
|
1751 |
}
|
|
1752 |
}
|
|
1753 |
|
|
1754 |
void
|
|
1755 |
unmanage(Client *c, int destroyed)
|
|
1756 |
{
|
1785 | 1757 |
Monitor *m = c->mon;
|
1786 | 1758 |
XWindowChanges wc;
|
1787 | 1759 |
|
1788 | 1760 |
/* The server grab construct avoids race conditions. */
|
1789 | 1761 |
detach(c);
|
1790 | 1762 |
detachstack(c);
|
1791 | |
if(!destroyed) {
|
|
1763 |
if (!destroyed) {
|
1792 | 1764 |
wc.border_width = c->oldbw;
|
1793 | 1765 |
XGrabServer(dpy);
|
1794 | 1766 |
XSetErrorHandler(xerrordummy);
|
|
1801 | 1773 |
}
|
1802 | 1774 |
free(c);
|
1803 | 1775 |
focus(NULL);
|
|
1776 |
updateclientlist();
|
1804 | 1777 |
arrange(m);
|
1805 | 1778 |
}
|
1806 | 1779 |
|
1807 | 1780 |
void
|
1808 | |
unmapnotify(XEvent *e) {
|
|
1781 |
unmapnotify(XEvent *e)
|
|
1782 |
{
|
1809 | 1783 |
Client *c;
|
1810 | 1784 |
XUnmapEvent *ev = &e->xunmap;
|
1811 | 1785 |
|
1812 | |
if((c = wintoclient(ev->window))) {
|
1813 | |
if(ev->send_event)
|
|
1786 |
if ((c = wintoclient(ev->window))) {
|
|
1787 |
if (ev->send_event)
|
1814 | 1788 |
setclientstate(c, WithdrawnState);
|
1815 | 1789 |
else
|
1816 | |
unmanage(c, False);
|
1817 | |
}
|
1818 | |
}
|
1819 | |
|
1820 | |
void
|
1821 | |
updatebars(void) {
|
|
1790 |
unmanage(c, 0);
|
|
1791 |
}
|
|
1792 |
}
|
|
1793 |
|
|
1794 |
void
|
|
1795 |
updatebars(void)
|
|
1796 |
{
|
1822 | 1797 |
Monitor *m;
|
1823 | 1798 |
XSetWindowAttributes wa = {
|
1824 | 1799 |
.override_redirect = True,
|
1825 | 1800 |
.background_pixmap = ParentRelative,
|
1826 | 1801 |
.event_mask = ButtonPressMask|ExposureMask
|
1827 | 1802 |
};
|
1828 | |
for(m = mons; m; m = m->next) {
|
|
1803 |
for (m = mons; m; m = m->next) {
|
|
1804 |
if (m->barwin)
|
|
1805 |
continue;
|
1829 | 1806 |
m->barwin = XCreateWindow(dpy, root, m->wx, m->by, m->ww, bh, 0, DefaultDepth(dpy, screen),
|
1830 | 1807 |
CopyFromParent, DefaultVisual(dpy, screen),
|
1831 | 1808 |
CWOverrideRedirect|CWBackPixmap|CWEventMask, &wa);
|
1832 | |
XDefineCursor(dpy, m->barwin, cursor[CurNormal]);
|
|
1809 |
XDefineCursor(dpy, m->barwin, cursor[CurNormal]->cursor);
|
1833 | 1810 |
XMapRaised(dpy, m->barwin);
|
1834 | 1811 |
}
|
1835 | 1812 |
}
|
1836 | 1813 |
|
1837 | 1814 |
void
|
1838 | |
updatebarpos(Monitor *m) {
|
|
1815 |
updatebarpos(Monitor *m)
|
|
1816 |
{
|
1839 | 1817 |
m->wy = m->my;
|
1840 | 1818 |
m->wh = m->mh;
|
1841 | |
if(m->showbar) {
|
|
1819 |
if (m->showbar) {
|
1842 | 1820 |
m->wh -= bh;
|
1843 | 1821 |
m->by = m->topbar ? m->wy : m->wy + m->wh;
|
1844 | 1822 |
m->wy = m->topbar ? m->wy + bh : m->wy;
|
1845 | |
}
|
1846 | |
else
|
|
1823 |
} else
|
1847 | 1824 |
m->by = -bh;
|
1848 | 1825 |
}
|
1849 | 1826 |
|
1850 | |
Bool
|
1851 | |
updategeom(void) {
|
1852 | |
Bool dirty = False;
|
|
1827 |
void
|
|
1828 |
updateclientlist()
|
|
1829 |
{
|
|
1830 |
Client *c;
|
|
1831 |
Monitor *m;
|
|
1832 |
|
|
1833 |
XDeleteProperty(dpy, root, netatom[NetClientList]);
|
|
1834 |
for (m = mons; m; m = m->next)
|
|
1835 |
for (c = m->clients; c; c = c->next)
|
|
1836 |
XChangeProperty(dpy, root, netatom[NetClientList],
|
|
1837 |
XA_WINDOW, 32, PropModeAppend,
|
|
1838 |
(unsigned char *) &(c->win), 1);
|
|
1839 |
}
|
|
1840 |
|
|
1841 |
int
|
|
1842 |
updategeom(void)
|
|
1843 |
{
|
|
1844 |
int dirty = 0;
|
1853 | 1845 |
|
1854 | 1846 |
#ifdef XINERAMA
|
1855 | |
if(XineramaIsActive(dpy)) {
|
|
1847 |
if (XineramaIsActive(dpy)) {
|
1856 | 1848 |
int i, j, n, nn;
|
1857 | 1849 |
Client *c;
|
1858 | 1850 |
Monitor *m;
|
1859 | 1851 |
XineramaScreenInfo *info = XineramaQueryScreens(dpy, &nn);
|
1860 | 1852 |
XineramaScreenInfo *unique = NULL;
|
1861 | 1853 |
|
1862 | |
for(n = 0, m = mons; m; m = m->next, n++);
|
|
1854 |
for (n = 0, m = mons; m; m = m->next, n++);
|
1863 | 1855 |
/* only consider unique geometries as separate screens */
|
1864 | |
if(!(unique = (XineramaScreenInfo *)malloc(sizeof(XineramaScreenInfo) * nn)))
|
1865 | |
die("fatal: could not malloc() %u bytes\n", sizeof(XineramaScreenInfo) * nn);
|
1866 | |
for(i = 0, j = 0; i < nn; i++)
|
1867 | |
if(isuniquegeom(unique, j, &info[i]))
|
|
1856 |
unique = ecalloc(nn, sizeof(XineramaScreenInfo));
|
|
1857 |
for (i = 0, j = 0; i < nn; i++)
|
|
1858 |
if (isuniquegeom(unique, j, &info[i]))
|
1868 | 1859 |
memcpy(&unique[j++], &info[i], sizeof(XineramaScreenInfo));
|
1869 | 1860 |
XFree(info);
|
1870 | 1861 |
nn = j;
|
1871 | |
if(n <= nn) {
|
1872 | |
for(i = 0; i < (nn - n); i++) { /* new monitors available */
|
1873 | |
for(m = mons; m && m->next; m = m->next);
|
1874 | |
if(m)
|
|
1862 |
if (n <= nn) {
|
|
1863 |
for (i = 0; i < (nn - n); i++) { /* new monitors available */
|
|
1864 |
for (m = mons; m && m->next; m = m->next);
|
|
1865 |
if (m)
|
1875 | 1866 |
m->next = createmon();
|
1876 | 1867 |
else
|
1877 | 1868 |
mons = createmon();
|
1878 | 1869 |
}
|
1879 | |
for(i = 0, m = mons; i < nn && m; m = m->next, i++)
|
1880 | |
if(i >= n
|
|
1870 |
for (i = 0, m = mons; i < nn && m; m = m->next, i++)
|
|
1871 |
if (i >= n
|
1881 | 1872 |
|| (unique[i].x_org != m->mx || unique[i].y_org != m->my
|
1882 | 1873 |
|| unique[i].width != m->mw || unique[i].height != m->mh))
|
1883 | 1874 |
{
|
1884 | |
dirty = True;
|
|
1875 |
dirty = 1;
|
1885 | 1876 |
m->num = i;
|
1886 | 1877 |
m->mx = m->wx = unique[i].x_org;
|
1887 | 1878 |
m->my = m->wy = unique[i].y_org;
|
|
1889 | 1880 |
m->mh = m->wh = unique[i].height;
|
1890 | 1881 |
updatebarpos(m);
|
1891 | 1882 |
}
|
1892 | |
}
|
1893 | |
else { /* less monitors available nn < n */
|
1894 | |
for(i = nn; i < n; i++) {
|
1895 | |
for(m = mons; m && m->next; m = m->next);
|
1896 | |
while(m->clients) {
|
1897 | |
dirty = True;
|
|
1883 |
} else {
|
|
1884 |
/* less monitors available nn < n */
|
|
1885 |
for (i = nn; i < n; i++) {
|
|
1886 |
for (m = mons; m && m->next; m = m->next);
|
|
1887 |
while (m->clients) {
|
|
1888 |
dirty = 1;
|
1898 | 1889 |
c = m->clients;
|
1899 | 1890 |
m->clients = c->next;
|
1900 | 1891 |
detachstack(c);
|
|
1902 | 1893 |
attach(c);
|
1903 | 1894 |
attachstack(c);
|
1904 | 1895 |
}
|
1905 | |
if(m == selmon)
|
|
1896 |
if (m == selmon)
|
1906 | 1897 |
selmon = mons;
|
1907 | 1898 |
cleanupmon(m);
|
1908 | 1899 |
}
|
1909 | 1900 |
}
|
1910 | 1901 |
free(unique);
|
1911 | |
}
|
1912 | |
else
|
|
1902 |
} else
|
1913 | 1903 |
#endif /* XINERAMA */
|
1914 | 1904 |
/* default monitor setup */
|
1915 | 1905 |
{
|
1916 | |
if(!mons)
|
|
1906 |
if (!mons)
|
1917 | 1907 |
mons = createmon();
|
1918 | |
if(mons->mw != sw || mons->mh != sh) {
|
1919 | |
dirty = True;
|
|
1908 |
if (mons->mw != sw || mons->mh != sh) {
|
|
1909 |
dirty = 1;
|
1920 | 1910 |
mons->mw = mons->ww = sw;
|
1921 | 1911 |
mons->mh = mons->wh = sh;
|
1922 | 1912 |
updatebarpos(mons);
|
1923 | 1913 |
}
|
1924 | 1914 |
}
|
1925 | |
if(dirty) {
|
|
1915 |
if (dirty) {
|
1926 | 1916 |
selmon = mons;
|
1927 | 1917 |
selmon = wintomon(root);
|
1928 | 1918 |
}
|
|
1930 | 1920 |
}
|
1931 | 1921 |
|
1932 | 1922 |
void
|
1933 | |
updatenumlockmask(void) {
|
|
1923 |
updatenumlockmask(void)
|
|
1924 |
{
|
1934 | 1925 |
unsigned int i, j;
|
1935 | 1926 |
XModifierKeymap *modmap;
|
1936 | 1927 |
|
1937 | 1928 |
numlockmask = 0;
|
1938 | 1929 |
modmap = XGetModifierMapping(dpy);
|
1939 | |
for(i = 0; i < 8; i++)
|
1940 | |
for(j = 0; j < modmap->max_keypermod; j++)
|
1941 | |
if(modmap->modifiermap[i * modmap->max_keypermod + j]
|
|
1930 |
for (i = 0; i < 8; i++)
|
|
1931 |
for (j = 0; j < modmap->max_keypermod; j++)
|
|
1932 |
if (modmap->modifiermap[i * modmap->max_keypermod + j]
|
1942 | 1933 |
== XKeysymToKeycode(dpy, XK_Num_Lock))
|
1943 | 1934 |
numlockmask = (1 << i);
|
1944 | 1935 |
XFreeModifiermap(modmap);
|
1945 | 1936 |
}
|
1946 | 1937 |
|
1947 | 1938 |
void
|
1948 | |
updatesizehints(Client *c) {
|
|
1939 |
updatesizehints(Client *c)
|
|
1940 |
{
|
1949 | 1941 |
long msize;
|
1950 | 1942 |
XSizeHints size;
|
1951 | 1943 |
|
1952 | |
if(!XGetWMNormalHints(dpy, c->win, &size, &msize))
|
|
1944 |
if (!XGetWMNormalHints(dpy, c->win, &size, &msize))
|
1953 | 1945 |
/* size is uninitialized, ensure that size.flags aren't used */
|
1954 | 1946 |
size.flags = PSize;
|
1955 | |
if(size.flags & PBaseSize) {
|
|
1947 |
if (size.flags & PBaseSize) {
|
1956 | 1948 |
c->basew = size.base_width;
|
1957 | 1949 |
c->baseh = size.base_height;
|
1958 | |
}
|
1959 | |
else if(size.flags & PMinSize) {
|
|
1950 |
} else if (size.flags & PMinSize) {
|
1960 | 1951 |
c->basew = size.min_width;
|
1961 | 1952 |
c->baseh = size.min_height;
|
1962 | |
}
|
1963 | |
else
|
|
1953 |
} else
|
1964 | 1954 |
c->basew = c->baseh = 0;
|
1965 | |
if(size.flags & PResizeInc) {
|
|
1955 |
if (size.flags & PResizeInc) {
|
1966 | 1956 |
c->incw = size.width_inc;
|
1967 | 1957 |
c->inch = size.height_inc;
|
1968 | |
}
|
1969 | |
else
|
|
1958 |
} else
|
1970 | 1959 |
c->incw = c->inch = 0;
|
1971 | |
if(size.flags & PMaxSize) {
|
|
1960 |
if (size.flags & PMaxSize) {
|
1972 | 1961 |
c->maxw = size.max_width;
|
1973 | 1962 |
c->maxh = size.max_height;
|
1974 | |
}
|
1975 | |
else
|
|
1963 |
} else
|
1976 | 1964 |
c->maxw = c->maxh = 0;
|
1977 | |
if(size.flags & PMinSize) {
|
|
1965 |
if (size.flags & PMinSize) {
|
1978 | 1966 |
c->minw = size.min_width;
|
1979 | 1967 |
c->minh = size.min_height;
|
1980 | |
}
|
1981 | |
else if(size.flags & PBaseSize) {
|
|
1968 |
} else if (size.flags & PBaseSize) {
|
1982 | 1969 |
c->minw = size.base_width;
|
1983 | 1970 |
c->minh = size.base_height;
|
1984 | |
}
|
1985 | |
else
|
|
1971 |
} else
|
1986 | 1972 |
c->minw = c->minh = 0;
|
1987 | |
if(size.flags & PAspect) {
|
|
1973 |
if (size.flags & PAspect) {
|
1988 | 1974 |
c->mina = (float)size.min_aspect.y / size.min_aspect.x;
|
1989 | 1975 |
c->maxa = (float)size.max_aspect.x / size.max_aspect.y;
|
1990 | |
}
|
1991 | |
else
|
|
1976 |
} else
|
1992 | 1977 |
c->maxa = c->mina = 0.0;
|
1993 | 1978 |
c->isfixed = (c->maxw && c->minw && c->maxh && c->minh
|
1994 | 1979 |
&& c->maxw == c->minw && c->maxh == c->minh);
|
1995 | 1980 |
}
|
1996 | 1981 |
|
1997 | 1982 |
void
|
1998 | |
updatetitle(Client *c) {
|
1999 | |
if(!gettextprop(c->win, netatom[NetWMName], c->name, sizeof c->name))
|
|
1983 |
updatetitle(Client *c)
|
|
1984 |
{
|
|
1985 |
if (!gettextprop(c->win, netatom[NetWMName], c->name, sizeof c->name))
|
2000 | 1986 |
gettextprop(c->win, XA_WM_NAME, c->name, sizeof c->name);
|
2001 | |
if(c->name[0] == '\0') /* hack to mark broken clients */
|
|
1987 |
if (c->name[0] == '\0') /* hack to mark broken clients */
|
2002 | 1988 |
strcpy(c->name, broken);
|
2003 | 1989 |
}
|
2004 | 1990 |
|
2005 | 1991 |
void
|
2006 | |
updatestatus(void) {
|
2007 | |
if(!gettextprop(root, XA_WM_NAME, stext, sizeof(stext)))
|
|
1992 |
updatestatus(void)
|
|
1993 |
{
|
|
1994 |
if (!gettextprop(root, XA_WM_NAME, stext, sizeof(stext)))
|
2008 | 1995 |
strcpy(stext, "dwm-"VERSION);
|
2009 | 1996 |
drawbar(selmon);
|
2010 | 1997 |
}
|
2011 | 1998 |
|
2012 | 1999 |
void
|
2013 | |
updatewindowtype(Client *c) {
|
|
2000 |
updatewindowtype(Client *c)
|
|
2001 |
{
|
2014 | 2002 |
Atom state = getatomprop(c, netatom[NetWMState]);
|
2015 | 2003 |
Atom wtype = getatomprop(c, netatom[NetWMWindowType]);
|
2016 | 2004 |
|
2017 | |
if(state == netatom[NetWMFullscreen])
|
2018 | |
setfullscreen(c, True);
|
2019 | |
|
2020 | |
if(wtype == netatom[NetWMWindowTypeDialog])
|
2021 | |
c->isfloating = True;
|
2022 | |
}
|
2023 | |
|
2024 | |
void
|
2025 | |
updatewmhints(Client *c) {
|
|
2005 |
if (state == netatom[NetWMFullscreen])
|
|
2006 |
setfullscreen(c, 1);
|
|
2007 |
if (wtype == netatom[NetWMWindowTypeDialog])
|
|
2008 |
c->isfloating = 1;
|
|
2009 |
}
|
|
2010 |
|
|
2011 |
void
|
|
2012 |
updatewmhints(Client *c)
|
|
2013 |
{
|
2026 | 2014 |
XWMHints *wmh;
|
2027 | 2015 |
|
2028 | |
if((wmh = XGetWMHints(dpy, c->win))) {
|
2029 | |
if(c == selmon->sel && wmh->flags & XUrgencyHint) {
|
|
2016 |
if ((wmh = XGetWMHints(dpy, c->win))) {
|
|
2017 |
if (c == selmon->sel && wmh->flags & XUrgencyHint) {
|
2030 | 2018 |
wmh->flags &= ~XUrgencyHint;
|
2031 | 2019 |
XSetWMHints(dpy, c->win, wmh);
|
2032 | |
}
|
2033 | |
else
|
2034 | |
c->isurgent = (wmh->flags & XUrgencyHint) ? True : False;
|
2035 | |
if(wmh->flags & InputHint)
|
|
2020 |
} else
|
|
2021 |
c->isurgent = (wmh->flags & XUrgencyHint) ? 1 : 0;
|
|
2022 |
if (wmh->flags & InputHint)
|
2036 | 2023 |
c->neverfocus = !wmh->input;
|
2037 | 2024 |
else
|
2038 | |
c->neverfocus = False;
|
|
2025 |
c->neverfocus = 0;
|
2039 | 2026 |
XFree(wmh);
|
2040 | 2027 |
}
|
2041 | 2028 |
}
|
2042 | 2029 |
|
2043 | 2030 |
void
|
2044 | |
view(const Arg *arg) {
|
2045 | |
if((arg->ui & TAGMASK) == selmon->tagset[selmon->seltags])
|
|
2031 |
view(const Arg *arg)
|
|
2032 |
{
|
|
2033 |
if ((arg->ui & TAGMASK) == selmon->tagset[selmon->seltags])
|
2046 | 2034 |
return;
|
2047 | 2035 |
selmon->seltags ^= 1; /* toggle sel tagset */
|
2048 | |
if(arg->ui & TAGMASK)
|
|
2036 |
if (arg->ui & TAGMASK)
|
2049 | 2037 |
selmon->tagset[selmon->seltags] = arg->ui & TAGMASK;
|
2050 | 2038 |
focus(NULL);
|
2051 | 2039 |
arrange(selmon);
|
2052 | 2040 |
}
|
2053 | 2041 |
|
2054 | 2042 |
Client *
|
2055 | |
wintoclient(Window w) {
|
|
2043 |
wintoclient(Window w)
|
|
2044 |
{
|
2056 | 2045 |
Client *c;
|
2057 | 2046 |
Monitor *m;
|
2058 | 2047 |
|
2059 | |
for(m = mons; m; m = m->next)
|
2060 | |
for(c = m->clients; c; c = c->next)
|
2061 | |
if(c->win == w)
|
|
2048 |
for (m = mons; m; m = m->next)
|
|
2049 |
for (c = m->clients; c; c = c->next)
|
|
2050 |
if (c->win == w)
|
2062 | 2051 |
return c;
|
2063 | 2052 |
return NULL;
|
2064 | 2053 |
}
|
2065 | 2054 |
|
2066 | 2055 |
Monitor *
|
2067 | |
wintomon(Window w) {
|
|
2056 |
wintomon(Window w)
|
|
2057 |
{
|
2068 | 2058 |
int x, y;
|
2069 | 2059 |
Client *c;
|
2070 | 2060 |
Monitor *m;
|
2071 | 2061 |
|
2072 | |
if(w == root && getrootptr(&x, &y))
|
|
2062 |
if (w == root && getrootptr(&x, &y))
|
2073 | 2063 |
return recttomon(x, y, 1, 1);
|
2074 | |
for(m = mons; m; m = m->next)
|
2075 | |
if(w == m->barwin)
|
|
2064 |
for (m = mons; m; m = m->next)
|
|
2065 |
if (w == m->barwin)
|
2076 | 2066 |
return m;
|
2077 | |
if((c = wintoclient(w)))
|
|
2067 |
if ((c = wintoclient(w)))
|
2078 | 2068 |
return c->mon;
|
2079 | 2069 |
return selmon;
|
2080 | 2070 |
}
|
|
2083 | 2073 |
* ignored (especially on UnmapNotify's). Other types of errors call Xlibs
|
2084 | 2074 |
* default error handler, which may call exit. */
|
2085 | 2075 |
int
|
2086 | |
xerror(Display *dpy, XErrorEvent *ee) {
|
2087 | |
if(ee->error_code == BadWindow
|
|
2076 |
xerror(Display *dpy, XErrorEvent *ee)
|
|
2077 |
{
|
|
2078 |
if (ee->error_code == BadWindow
|
2088 | 2079 |
|| (ee->request_code == X_SetInputFocus && ee->error_code == BadMatch)
|
2089 | 2080 |
|| (ee->request_code == X_PolyText8 && ee->error_code == BadDrawable)
|
2090 | 2081 |
|| (ee->request_code == X_PolyFillRectangle && ee->error_code == BadDrawable)
|
|
2100 | 2091 |
}
|
2101 | 2092 |
|
2102 | 2093 |
int
|
2103 | |
xerrordummy(Display *dpy, XErrorEvent *ee) {
|
|
2094 |
xerrordummy(Display *dpy, XErrorEvent *ee)
|
|
2095 |
{
|
2104 | 2096 |
return 0;
|
2105 | 2097 |
}
|
2106 | 2098 |
|
2107 | 2099 |
/* Startup Error handler to check if another window manager
|
2108 | 2100 |
* is already running. */
|
2109 | 2101 |
int
|
2110 | |
xerrorstart(Display *dpy, XErrorEvent *ee) {
|
|
2102 |
xerrorstart(Display *dpy, XErrorEvent *ee)
|
|
2103 |
{
|
2111 | 2104 |
die("dwm: another window manager is already running\n");
|
2112 | 2105 |
return -1;
|
2113 | 2106 |
}
|
2114 | 2107 |
|
2115 | 2108 |
void
|
2116 | |
zoom(const Arg *arg) {
|
|
2109 |
zoom(const Arg *arg)
|
|
2110 |
{
|
2117 | 2111 |
Client *c = selmon->sel;
|
2118 | 2112 |
|
2119 | |
if(!selmon->lt[selmon->sellt]->arrange
|
|
2113 |
if (!selmon->lt[selmon->sellt]->arrange
|
2120 | 2114 |
|| (selmon->sel && selmon->sel->isfloating))
|
2121 | 2115 |
return;
|
2122 | |
if(c == nexttiled(selmon->clients))
|
2123 | |
if(!c || !(c = nexttiled(c->next)))
|
|
2116 |
if (c == nexttiled(selmon->clients))
|
|
2117 |
if (!c || !(c = nexttiled(c->next)))
|
2124 | 2118 |
return;
|
2125 | 2119 |
pop(c);
|
2126 | 2120 |
}
|
2127 | 2121 |
|
2128 | 2122 |
int
|
2129 | |
main(int argc, char *argv[]) {
|
2130 | |
if(argc == 2 && !strcmp("-v", argv[1]))
|
2131 | |
die("dwm-"VERSION", © 2006-2011 dwm engineers, see LICENSE for details\n");
|
2132 | |
else if(argc != 1)
|
|
2123 |
main(int argc, char *argv[])
|
|
2124 |
{
|
|
2125 |
if (argc == 2 && !strcmp("-v", argv[1]))
|
|
2126 |
die("dwm-"VERSION "\n");
|
|
2127 |
else if (argc != 1)
|
2133 | 2128 |
die("usage: dwm [-v]\n");
|
2134 | |
if(!setlocale(LC_CTYPE, "") || !XSupportsLocale())
|
|
2129 |
if (!setlocale(LC_CTYPE, "") || !XSupportsLocale())
|
2135 | 2130 |
fputs("warning: no locale support\n", stderr);
|
2136 | |
if(!(dpy = XOpenDisplay(NULL)))
|
|
2131 |
if (!(dpy = XOpenDisplay(NULL)))
|
2137 | 2132 |
die("dwm: cannot open display\n");
|
2138 | 2133 |
checkotherwm();
|
2139 | 2134 |
setup();
|