Alopex

Check-in [7bad7d1bf9]

Many hyperlinks are disabled.
Use anonymous login to enable hyperlinks.

Overview
Comment:minor cleanup
Downloads: Tarball | ZIP archive | SQL archive
Timelines: family | ancestors | descendants | both | trunk | master
Files: files | file ages | folders
SHA3-256:7bad7d1bf9e3fb39940ef9a7f5a87279c870c2467a8bf0f801e37ee0a0f955d7
User & Date: jesse@mccluresk9.com 2014-06-16 20:50:48
Context
2014-06-22
22:08
Merge pull request #50 from pfernie/focus_up Initialize Client *b to NULL check-in: e3c8a65315 user: jesse@mccluresk9.com tags: trunk, master
20:24
Support ModX Bind.Mod values besides just Mod4 Allow user to specify Mod1, Mod2, etc. as Bind.Mod values check-in: 42fdaaf0e5 user: patrick.fernie@gmail.com tags: trunk, master
20:18
Initialize Client *b to NULL Issuing a focus up command when at the top of the client list caused a crash due to Client *b not being initialized check-in: db92b46d48 user: patrick.fernie@gmail.com tags: trunk, master
2014-06-16
20:50
minor cleanup check-in: 7bad7d1bf9 user: jesse@mccluresk9.com tags: trunk, master
2014-06-13
23:56
tinkering check-in: d5d62abffb user: jesse@mccluresk9.com tags: trunk, master
Changes

Added share/flats.

















































>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
!! Alopex resource database: theme flats
!! By: Jesse McClure (c) 2014
!! License: CC-BY-SA

flats.Tab.Offset:					0.00 0.00 0.00 2.00 0.0
flats.Tab.Background:			0.08 0.08 0.08 0.00 0.0
flats.Tab.Border:					0.00 0.20 1.00 0.00 0.5
flats.Tab.Text:					0.20 0.40 0.80 1.00 -10
flats.TabFocus.Background:		0.14 0.14 0.14 0.00 0.0
flats.TabFocus.Border:			0.60 0.90 1.00 0.00 0.5
flats.TabFocus.Text:				0.90 0.95 1.00 1.00 -10
flats.TabTop.Background:		0.14 0.14 0.14 0.00 0.0
flats.TabTop.Border:				0.00 0.40 1.00 0.00 0.5
flats.TabTop.Text:				0.35 0.75 1.00 1.00 -10
flats.Status.Offset:				0.00 0.00 0.00 0.00 0.0
flats.Status.Background:		0.14 0.14 0.14 0.00 0.0
flats.Status.Border:				0.60 0.90 1.00 0.00 0.0
flats.Status.Text:				0.80 0.80 0.80 1.00 0.0
flats.Tag.Occupied:				0.60 0.90 1.00 1.00 0.0
flats.Tag.View:					0.90 0.95 1.00 1.00 0.0
flats.Tag.Alt:						0.35 0.75 1.00 1.00 0.0
flats.Tag.Both:					0.60 1.00 0.60 1.00 0.0

!! vim: ft=xdefaults

Changes to src/alopex.c.

2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
#include "alopex.h"

extern int xlib_init(const char *);
extern int xlib_free();
extern int main_loop();

void handler(int sig) {
	if (sig == SIGCHLD) {
		while (waitpid(-1, NULL, WNOHANG) > 0);
	}
}

void die(const char *fmt, ...) {
	fprintf(stderr,"ALOPEX: ");
	va_list arg;
	va_start(arg, fmt);
	vfprintf(stderr, fmt, arg);







|

<







2
3
4
5
6
7
8
9
10

11
12
13
14
15
16
17
#include "alopex.h"

extern int xlib_init(const char *);
extern int xlib_free();
extern int main_loop();

void handler(int sig) {
	if (sig == SIGCHLD)
		while (waitpid(-1, NULL, WNOHANG) > 0);

}

void die(const char *fmt, ...) {
	fprintf(stderr,"ALOPEX: ");
	va_list arg;
	va_start(arg, fmt);
	vfprintf(stderr, fmt, arg);

Changes to src/alopex.h.

59
60
61
62
63
64
65

66
67
68
69
70
71
72
	StatusBackground, StatusBorder, StatusText,
	TagOccupied, TagView, TagAlt, TagBoth,
	ThemeLast
};

enum {
	WM_PROTOCOLS, WM_DELETE_WINDOW, WM_STATE, WM_TAKE_FOCUS,

	NET_SUPPORTED, NET_WM_NAME, NET_WM_STATE,
	NET_WM_STATE_FULLSCREEN, NET_ACTIVE_WINDOW,
	NET_WM_WINDOW_TYPE, NET_WM_TYPE_DIALOG, NET_CLIENT_LIST,
	ATOM_LAST
};

enum { TAG_ICON_TEXT, TAG_TEXT_ICON, TAG_TEXT, TAG_ICON };







>







59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
	StatusBackground, StatusBorder, StatusText,
	TagOccupied, TagView, TagAlt, TagBoth,
	ThemeLast
};

enum {
	WM_PROTOCOLS, WM_DELETE_WINDOW, WM_STATE, WM_TAKE_FOCUS,
	WM_NAME,
	NET_SUPPORTED, NET_WM_NAME, NET_WM_STATE,
	NET_WM_STATE_FULLSCREEN, NET_ACTIVE_WINDOW,
	NET_WM_WINDOW_TYPE, NET_WM_TYPE_DIALOG, NET_CLIENT_LIST,
	ATOM_LAST
};

enum { TAG_ICON_TEXT, TAG_TEXT_ICON, TAG_TEXT, TAG_ICON };

Changes to src/atoms.c.

2
3
4
5
6
7
8

9
10
11
12
13
14
15
..
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46

47
48
49
50
51
52
53
54
55
56
#include "alopex.h"

static inline Atom make_atom(const char *a) {
	return XInternAtom(dpy, a, False);
}

int atoms_init() {

	atom[WM_PROTOCOLS] = make_atom("WM_PROTOCOLS");
	atom[WM_DELETE_WINDOW] = make_atom("WM_DELETE_WINDOW");
	atom[WM_STATE] = make_atom("WM_STATE");
	atom[WM_TAKE_FOCUS] = make_atom("WM_TAKE_FOCUS");
//	atom[NET_SUPPORTED] = make_atom("_NET_SUPPORTED");
	atom[NET_WM_NAME] = make_atom("_NET_WM_NAME");
//	atom[NET_WM_STATE] = make_atom("_NET_WM_STATE");
................................................................................
		return at;
	at = *(Atom *)uc;
	XFree(uc);
	return at;
}

char *get_text(Client *c, int type) {
	char **strs = NULL;
	int n;
	XTextProperty text;
	XGetTextProperty(dpy, c->win, &text, atom[type]);
	if (!text.nitems) return NULL;
	if (text.encoding == XA_STRING) return (char *) text.value;
	else if (XmbTextPropertyToTextList(dpy, &text, &strs, &n)>=Success) {
		char *tmp = strdup(*strs);
		XFreeStringList(strs);

		XFree(text.value);
		return tmp;
	}
}


int send_message(Client *c, int type, int msg) {
	XEvent ev;
	ev.type = ClientMessage;
	ev.xclient.window = c->win;







>







 







|




|

|

>
|
|
<







2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
..
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50

51
52
53
54
55
56
57
#include "alopex.h"

static inline Atom make_atom(const char *a) {
	return XInternAtom(dpy, a, False);
}

int atoms_init() {
	atom[WM_NAME] = XA_WM_NAME;
	atom[WM_PROTOCOLS] = make_atom("WM_PROTOCOLS");
	atom[WM_DELETE_WINDOW] = make_atom("WM_DELETE_WINDOW");
	atom[WM_STATE] = make_atom("WM_STATE");
	atom[WM_TAKE_FOCUS] = make_atom("WM_TAKE_FOCUS");
//	atom[NET_SUPPORTED] = make_atom("_NET_SUPPORTED");
	atom[NET_WM_NAME] = make_atom("_NET_WM_NAME");
//	atom[NET_WM_STATE] = make_atom("_NET_WM_STATE");
................................................................................
		return at;
	at = *(Atom *)uc;
	XFree(uc);
	return at;
}

char *get_text(Client *c, int type) {
	char **strs = NULL, *ret = NULL;
	int n;
	XTextProperty text;
	XGetTextProperty(dpy, c->win, &text, atom[type]);
	if (!text.nitems) return NULL;
	if (text.encoding == XA_STRING) ret = strdup(text.value);
	else if (XmbTextPropertyToTextList(dpy, &text, &strs, &n)>=Success) {
		ret = strdup(*strs);
		XFreeStringList(strs);
	}
	XFree(text.value);
	return ret;

}


int send_message(Client *c, int type, int msg) {
	XEvent ev;
	ev.type = ClientMessage;
	ev.xclient.window = c->win;

Changes to src/tile.c.

86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
			C->w = M->w - M->margin.left - M->margin.right;
			XMoveResizeWindow(dpy, C->win, C->x, C->y, C->w, C->bar->h);
			cairo_set_source_surface(C->bar->ctx, M->bg,
					M->x - C->x, M->y - C->y);
			cairo_paint(C->bar->ctx);
		}
		/* sort floating windows */
		// TODO: needs testing
		for (c = clients ; c; c = c->next) {
			if (!(M->tags & c->tags)) continue;
			else if (c->flags & WIN_FULL_TEST) {
if ( !winmarks[1] || !(winmarks[1]->flags & WIN_FLOAT))
winmarks[1] = c;
				XMoveResizeWindow(dpy, c->win, M->x, M->y, M->w, M->h);
			}
			else if (c->flags & WIN_FLOAT) {
				XMoveResizeWindow(dpy, c->win, c->x, c->y, c->w, c->h);
			}
		}
		if (!M->focus) M->focus = M->container;







<



|
|







86
87
88
89
90
91
92

93
94
95
96
97
98
99
100
101
102
103
104
			C->w = M->w - M->margin.left - M->margin.right;
			XMoveResizeWindow(dpy, C->win, C->x, C->y, C->w, C->bar->h);
			cairo_set_source_surface(C->bar->ctx, M->bg,
					M->x - C->x, M->y - C->y);
			cairo_paint(C->bar->ctx);
		}
		/* sort floating windows */

		for (c = clients ; c; c = c->next) {
			if (!(M->tags & c->tags)) continue;
			else if (c->flags & WIN_FULL_TEST) {
				if ( !winmarks[1] || !(winmarks[1]->flags & WIN_FLOAT))
					winmarks[1] = c;
				XMoveResizeWindow(dpy, c->win, M->x, M->y, M->w, M->h);
			}
			else if (c->flags & WIN_FLOAT) {
				XMoveResizeWindow(dpy, c->win, c->x, c->y, c->w, c->h);
			}
		}
		if (!M->focus) M->focus = M->container;

Changes to src/xlib.c.

24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
...
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
...
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
...
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
...
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
...
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
...
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
...
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
...
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
...
630
631
632
633
634
635
636

637
638
639
640
641
642
643
static int get_size(Client *);

static void buttonpress(XEvent *);
static void configurerequest(XEvent *);
static void enternotify(XEvent *);
static void expose(XEvent *);
static void keypress(XEvent *);
//static void keyrelease(XEvent *);
static void propertynotify(XEvent *);
static void maprequest(XEvent *);
static void unmapnotify(XEvent *);

//static Bool mod_down = False;
static int purgX, purgY;
static void (*handler[LASTEvent]) (XEvent *) = {
	[ButtonPress]       = buttonpress,
	[ConfigureRequest]  = configurerequest,
	[EnterNotify]       = enternotify,
	[Expose]            = expose,
	[KeyPress]          = keypress,
//	[KeyRelease]        = keyrelease,
	[MapRequest]        = maprequest,
	[PropertyNotify]    = propertynotify,
	[UnmapNotify]       = unmapnotify,
};

int free_mons(const char *bg, const char *cont) {
	int i;
................................................................................
		if (minY > mons[i].y) minY = mons[i].y;
		if (maxX < mons[i].x + mons[i].w) maxX = mons[i].x + mons[i].w;
		if (maxY < mons[i].y + mons[i].h) maxY = mons[i].y + mons[i].h;
	}
	/* create monitors and set background */
	cairo_surface_t *src, *dest;
	src = cairo_image_surface_create_from_png(bg);
if (cairo_surface_status(src) != CAIRO_STATUS_SUCCESS) {
	src = cairo_image_surface_create(CAIRO_FORMAT_ARGB32, maxX, maxY);
	cairo_t *blank = cairo_create(src);
	cairo_set_source_rgba(blank, 0, 0, 0, 1);
	cairo_paint(blank);
	cairo_destroy(blank);
}
	int imgw = cairo_image_surface_get_width(src);
	int imgh = cairo_image_surface_get_height(src);
	Pixmap pix = XCreatePixmap(dpy, root, maxX-minX, maxY-minY,
			DefaultDepth(dpy,scr));
	dest = cairo_xlib_surface_create(dpy, pix, DefaultVisual(dpy,scr),
			maxX-minX, maxY-minY);
	cairo_t *ctx, *rctx;
................................................................................
	Monitor *M;
	for (M = mons; M; M = M->next) {
		if (M->x + M->w > purgX) purgX = M->x + M->w + 10;
		if (M->y + M->h > purgY) purgY = M->y + M->h + 10;
	}
	XClearWindow(dpy,root);
	/* BINDING + GRABS */
//XSetWindowAttributes wa;
//wa.event_mask = SELECT_EVENTS;
//XChangeWindowAttributes(dpy,root,CWEventMask,&wa);
	XSelectInput(dpy, root, SELECT_EVENTS);
	unsigned int mod[] = {0, LockMask, Mod2Mask, LockMask|Mod2Mask};
	KeyCode code;
	Key *key;
	XUngrabKey(dpy, AnyKey, AnyModifier, root);
	XSync(dpy,True);
	int i, j;
................................................................................
	for (i = 0; i < conf.nkeys; i++) {
		key = &conf.key[i];
		if ( (code=XKeysymToKeycode(dpy, key->keysym)) ) {
			for (j = 0; j < 4; j++)
				XGrabKey(dpy, code, key->mod|mod[j], root, True, GRABMODE);
		}
	}
//	code = XKeysymToKeycode(dpy, XK_Super_L);
	for (j = 0; j < 4; j++) {
//		XGrabKey(dpy, code, mod[j], root, True, GRABMODE);
		XGrabButton(dpy,1,Mod4Mask|mod[j],root,True,GRABMODE2);
		XGrabButton(dpy,2,Mod4Mask|mod[j],root,True,GRABMODE2);
		XGrabButton(dpy,3,Mod4Mask|mod[j],root,True,GRABMODE2);
	}
	memset(winmarks, 0, 10*sizeof(Client *));
	tile();
	XFlush(dpy);
................................................................................
int get_hints(Client *c) {
	XWMHints *hint;
	if ( !(hint = XGetWMHints(dpy,c->win)) ) return;
	if (hint->flags & XUrgencyHint) c->flags |= WIN_URGENT;
	if (hint->flags & InputHint && !hint->input) c->flags |= WIN_FOCUS;
	if (hint->flags & (IconPixmapHint | IconMaskHint)) get_icon(c);
	XFree(hint);
	// TODO EWMH checks
	return 0;
}

int get_icon(Client *c) {
	// TODO: needs testing
	XWMHints *hint;
	if (!(hint=XGetWMHints(dpy,c->win))) return;
	if (!(hint->flags & (IconPixmapHint | IconMaskHint))) return;
	if (c->icon) { cairo_surface_destroy(c->icon); c->icon = NULL; }
	int w, h, ig, sz = conf.font_size;
	Window wig;
	XGetGeometry(dpy, hint->icon_pixmap, &wig, &ig, &ig, &w, &h, &ig, &ig);
	if (c->icon) cairo_surface_destroy(c->icon);
	cairo_surface_t *icon, *mask = NULL;
	icon = cairo_xlib_surface_create(dpy, hint->icon_pixmap,
			DefaultVisual(dpy,scr), w, h);
	if (hint->flags & IconMaskHint)
	//mask = cairo_xlib_surface_create(dpy, hint->icon_mask,
	//		DefaultVisual(dpy,scr), w, h);
	mask = cairo_xlib_surface_create_for_bitmap(dpy,
			hint->icon_mask, DefaultScreenOfDisplay(dpy), w, h);
	c->icon = cairo_image_surface_create(CAIRO_FORMAT_ARGB32, sz, sz);
	cairo_t *ctx = cairo_create(c->icon);
	cairo_scale(ctx, sz / (double) w, sz / (double) h);
	cairo_set_source_surface(ctx, icon, 0, 0);
	if (mask) cairo_mask_surface(ctx, mask, 0, 0);
................................................................................
}

int get_name(Client *c) {
	static const char *noname = "(no name)";
	Client *p;
	if (c->title && c->title != noname) XFree(c->title);
	if ( !(c->title=get_text(c,NET_WM_NAME)) )
		if ( !(c->title=get_text(c,XA_WM_NAME)) )
			c->title = strdup(noname);
	return 0;
}

int get_size(Client *c) {
	long ret = 0;
	XSizeHints hint;
................................................................................
	}
	XGrabPointer(dpy, root, True, PointerMotionMask | ButtonReleaseMask,
			GRABMODE, None, None, CurrentTime);
	XEvent ee;
	int dx, dy;
	int xx = e->x_root, yy = e->y_root;
	while (True) {
		//XMoveResizeWindow(dpy, c->win, c->x, c->y, c->w, c->h);
		expose(ev);
		XMaskEvent(dpy, PointerMotionMask | ButtonReleaseMask, &ee);
		if (ee.type == ButtonRelease) break;
if (!(c->flags & WIN_FLOAT)) {
	c->flags |= WIN_FLOAT;
	tile();
if (xx < c->x) c->x = xx;
if (xx > c->x + c->w) c->x = xx - c->w;
if (yy < c->y) c->y = yy;
if (yy > c->y + c->h) c->y = yy - c->h;
}
		XMoveResizeWindow(dpy, c->win, c->x, c->y, c->w, c->h);
		dx = ee.xbutton.x_root - xx; xx = ee.xbutton.x_root;
		dy = ee.xbutton.y_root - yy; yy = ee.xbutton.y_root;
		if (b == 1) { c->x += dx; c->y += dy; }
		else if (b == 3) { c->w += dx; c->h += dy; }
	}
	XUngrabPointer(dpy, CurrentTime);
................................................................................
	for (C = m->container; C; C = C->next)
		if (C->top && C->top == c) m->focus = C;
	tile();
}

void expose(XEvent *ev) {
	Monitor *M; Container *C;
//	draw_bars(True);
	for (M = mons; M; M = M->next) {
		for (C = M->container; C; C = C->next){
			cairo_set_source_surface(C->ctx, C->bar->buf, 0, 0);
			cairo_paint(C->ctx);
		}
	}
}

void keypress(XEvent *ev) {
	int i;
	XKeyEvent *e = &ev->xkey;
	KeySym sym = XkbKeycodeToKeysym(dpy, e->keycode, 0, 0);
//	if (sym == XK_Super_L) mod_down = True;
	for (i = 0; i < conf.nkeys; i++) {
		if ( (sym==conf.key[i].keysym) && (conf.key[i].arg) &&
				conf.key[i].mod == ((e->state&~Mod2Mask)&~LockMask) ) {
			command(conf.key[i].arg);
			//mod_down = False;
		}
	}
}

//void keyrelease(XEvent *ev) {
//	XKeyEvent *e = &ev->xkey;
//	KeySym sym = XkbKeycodeToKeysym(dpy, e->keycode, 0, 0);
//	if (sym != XK_Super_L || !mod_down) return;
//	mod_down = False;
//	char str[MAX_LINE];
//	if (input(str)) command(str);
//}

void maprequest(XEvent *ev) {
	XMapRequestEvent *e = &ev->xmaprequest;
	XWindowAttributes wa;
	if (	!XGetWindowAttributes(dpy, e->window, &wa) ||
			wa.override_redirect ) return;
	Client *c;
	if ( (c=wintoclient(e->window)) ) return;
	c = calloc(1, sizeof(Client));
	c->win = e->window;
// check for fullscreen
	get_hints(c);
	get_icon(c);
	get_name(c);
//	get_size(c);
	apply_rules(c);
	if (!c->tags && !(c->tags=m->tags)) {
		Monitor *M;
		int i, tags = 0;
		for (M = mons; M; M = M->next) tags |= M->tags;
//fprintf(stderr,"ADD TAG tags=%X\n",tags);
		for (i = 0; ((1<<i) & tags) && i < 9; i++);
//fprintf(stderr," -- %d\n",i);
		c->tags = m->tags = (1<<i);
	}
	if (XGetTransientForHint(dpy, c->win, &c->parent))
		c->flags |= WIN_TRANS;
	else
		c->parent = e->parent;
	c->x = wa.x; c->y = wa.y; c->w = wa.width; c->h = wa.height;
................................................................................
		case ATTACH_BELOW: push_client(c, m->focus->top->next); break;
	}
	winmarks[0] = winmarks[1];
	winmarks[1] = c;
	purgatory(c->win);
	XMapWindow(dpy, c->win);
	tile();
	//if (c->flags & WIN_FLOAT) XRaiseWindow(dpy, c->win);
}

void propertynotify(XEvent *ev) {
	XPropertyEvent *e = &ev->xproperty;
	Client *c;
	if (e->window == root) {
		char *cmd;
................................................................................
		return;
	}
	if ( !(c=wintoclient(e->window)) ) return;
	if (e->atom == XA_WM_NAME) get_name(c);
	else if (e->atom == XA_WM_HINTS) get_hints(c);
	else if (e->atom == XA_WM_CLASS) apply_rules(c);
	else if (e->atom == XA_WM_NORMAL_HINTS) get_size(c);

	// icon ?
	// netWM
	// XA_TRANSIENT_FOR
	else return;
	tile();
}








<




<







<







 







|
|
|
|
|
|
|







 







<
<
<







 







<

<







 







|




<












<
<







 







|







 







<



|
|
|
|
|
|
|
|







 







<












<




<




<
<
<
<
<
<
<
<
<









<



<





<

<







 







<







 







>







24
25
26
27
28
29
30

31
32
33
34

35
36
37
38
39
40
41

42
43
44
45
46
47
48
..
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
...
296
297
298
299
300
301
302



303
304
305
306
307
308
309
...
310
311
312
313
314
315
316

317

318
319
320
321
322
323
324
...
364
365
366
367
368
369
370
371
372
373
374
375

376
377
378
379
380
381
382
383
384
385
386
387


388
389
390
391
392
393
394
...
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
...
447
448
449
450
451
452
453

454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
...
522
523
524
525
526
527
528

529
530
531
532
533
534
535
536
537
538
539
540

541
542
543
544

545
546
547
548









549
550
551
552
553
554
555
556
557

558
559
560

561
562
563
564
565

566

567
568
569
570
571
572
573
...
581
582
583
584
585
586
587

588
589
590
591
592
593
594
...
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
static int get_size(Client *);

static void buttonpress(XEvent *);
static void configurerequest(XEvent *);
static void enternotify(XEvent *);
static void expose(XEvent *);
static void keypress(XEvent *);

static void propertynotify(XEvent *);
static void maprequest(XEvent *);
static void unmapnotify(XEvent *);


static int purgX, purgY;
static void (*handler[LASTEvent]) (XEvent *) = {
	[ButtonPress]       = buttonpress,
	[ConfigureRequest]  = configurerequest,
	[EnterNotify]       = enternotify,
	[Expose]            = expose,
	[KeyPress]          = keypress,

	[MapRequest]        = maprequest,
	[PropertyNotify]    = propertynotify,
	[UnmapNotify]       = unmapnotify,
};

int free_mons(const char *bg, const char *cont) {
	int i;
................................................................................
		if (minY > mons[i].y) minY = mons[i].y;
		if (maxX < mons[i].x + mons[i].w) maxX = mons[i].x + mons[i].w;
		if (maxY < mons[i].y + mons[i].h) maxY = mons[i].y + mons[i].h;
	}
	/* create monitors and set background */
	cairo_surface_t *src, *dest;
	src = cairo_image_surface_create_from_png(bg);
	if (cairo_surface_status(src) != CAIRO_STATUS_SUCCESS) {
		src = cairo_image_surface_create(CAIRO_FORMAT_ARGB32, maxX, maxY);
		cairo_t *blank = cairo_create(src);
		cairo_set_source_rgba(blank, 0, 0, 0, 1);
		cairo_paint(blank);
		cairo_destroy(blank);
	}
	int imgw = cairo_image_surface_get_width(src);
	int imgh = cairo_image_surface_get_height(src);
	Pixmap pix = XCreatePixmap(dpy, root, maxX-minX, maxY-minY,
			DefaultDepth(dpy,scr));
	dest = cairo_xlib_surface_create(dpy, pix, DefaultVisual(dpy,scr),
			maxX-minX, maxY-minY);
	cairo_t *ctx, *rctx;
................................................................................
	Monitor *M;
	for (M = mons; M; M = M->next) {
		if (M->x + M->w > purgX) purgX = M->x + M->w + 10;
		if (M->y + M->h > purgY) purgY = M->y + M->h + 10;
	}
	XClearWindow(dpy,root);
	/* BINDING + GRABS */



	XSelectInput(dpy, root, SELECT_EVENTS);
	unsigned int mod[] = {0, LockMask, Mod2Mask, LockMask|Mod2Mask};
	KeyCode code;
	Key *key;
	XUngrabKey(dpy, AnyKey, AnyModifier, root);
	XSync(dpy,True);
	int i, j;
................................................................................
	for (i = 0; i < conf.nkeys; i++) {
		key = &conf.key[i];
		if ( (code=XKeysymToKeycode(dpy, key->keysym)) ) {
			for (j = 0; j < 4; j++)
				XGrabKey(dpy, code, key->mod|mod[j], root, True, GRABMODE);
		}
	}

	for (j = 0; j < 4; j++) {

		XGrabButton(dpy,1,Mod4Mask|mod[j],root,True,GRABMODE2);
		XGrabButton(dpy,2,Mod4Mask|mod[j],root,True,GRABMODE2);
		XGrabButton(dpy,3,Mod4Mask|mod[j],root,True,GRABMODE2);
	}
	memset(winmarks, 0, 10*sizeof(Client *));
	tile();
	XFlush(dpy);
................................................................................
int get_hints(Client *c) {
	XWMHints *hint;
	if ( !(hint = XGetWMHints(dpy,c->win)) ) return;
	if (hint->flags & XUrgencyHint) c->flags |= WIN_URGENT;
	if (hint->flags & InputHint && !hint->input) c->flags |= WIN_FOCUS;
	if (hint->flags & (IconPixmapHint | IconMaskHint)) get_icon(c);
	XFree(hint);
	// TODO EWMH checks ??
	return 0;
}

int get_icon(Client *c) {

	XWMHints *hint;
	if (!(hint=XGetWMHints(dpy,c->win))) return;
	if (!(hint->flags & (IconPixmapHint | IconMaskHint))) return;
	if (c->icon) { cairo_surface_destroy(c->icon); c->icon = NULL; }
	int w, h, ig, sz = conf.font_size;
	Window wig;
	XGetGeometry(dpy, hint->icon_pixmap, &wig, &ig, &ig, &w, &h, &ig, &ig);
	if (c->icon) cairo_surface_destroy(c->icon);
	cairo_surface_t *icon, *mask = NULL;
	icon = cairo_xlib_surface_create(dpy, hint->icon_pixmap,
			DefaultVisual(dpy,scr), w, h);
	if (hint->flags & IconMaskHint)


	mask = cairo_xlib_surface_create_for_bitmap(dpy,
			hint->icon_mask, DefaultScreenOfDisplay(dpy), w, h);
	c->icon = cairo_image_surface_create(CAIRO_FORMAT_ARGB32, sz, sz);
	cairo_t *ctx = cairo_create(c->icon);
	cairo_scale(ctx, sz / (double) w, sz / (double) h);
	cairo_set_source_surface(ctx, icon, 0, 0);
	if (mask) cairo_mask_surface(ctx, mask, 0, 0);
................................................................................
}

int get_name(Client *c) {
	static const char *noname = "(no name)";
	Client *p;
	if (c->title && c->title != noname) XFree(c->title);
	if ( !(c->title=get_text(c,NET_WM_NAME)) )
		if ( !(c->title=get_text(c,WM_NAME)) )
			c->title = strdup(noname);
	return 0;
}

int get_size(Client *c) {
	long ret = 0;
	XSizeHints hint;
................................................................................
	}
	XGrabPointer(dpy, root, True, PointerMotionMask | ButtonReleaseMask,
			GRABMODE, None, None, CurrentTime);
	XEvent ee;
	int dx, dy;
	int xx = e->x_root, yy = e->y_root;
	while (True) {

		expose(ev);
		XMaskEvent(dpy, PointerMotionMask | ButtonReleaseMask, &ee);
		if (ee.type == ButtonRelease) break;
		if (!(c->flags & WIN_FLOAT)) {
			c->flags |= WIN_FLOAT;
			tile();
			if (xx < c->x) c->x = xx;
			if (xx > c->x + c->w) c->x = xx - c->w;
			if (yy < c->y) c->y = yy;
			if (yy > c->y + c->h) c->y = yy - c->h;
		}
		XMoveResizeWindow(dpy, c->win, c->x, c->y, c->w, c->h);
		dx = ee.xbutton.x_root - xx; xx = ee.xbutton.x_root;
		dy = ee.xbutton.y_root - yy; yy = ee.xbutton.y_root;
		if (b == 1) { c->x += dx; c->y += dy; }
		else if (b == 3) { c->w += dx; c->h += dy; }
	}
	XUngrabPointer(dpy, CurrentTime);
................................................................................
	for (C = m->container; C; C = C->next)
		if (C->top && C->top == c) m->focus = C;
	tile();
}

void expose(XEvent *ev) {
	Monitor *M; Container *C;

	for (M = mons; M; M = M->next) {
		for (C = M->container; C; C = C->next){
			cairo_set_source_surface(C->ctx, C->bar->buf, 0, 0);
			cairo_paint(C->ctx);
		}
	}
}

void keypress(XEvent *ev) {
	int i;
	XKeyEvent *e = &ev->xkey;
	KeySym sym = XkbKeycodeToKeysym(dpy, e->keycode, 0, 0);

	for (i = 0; i < conf.nkeys; i++) {
		if ( (sym==conf.key[i].keysym) && (conf.key[i].arg) &&
				conf.key[i].mod == ((e->state&~Mod2Mask)&~LockMask) ) {
			command(conf.key[i].arg);

		}
	}
}










void maprequest(XEvent *ev) {
	XMapRequestEvent *e = &ev->xmaprequest;
	XWindowAttributes wa;
	if (	!XGetWindowAttributes(dpy, e->window, &wa) ||
			wa.override_redirect ) return;
	Client *c;
	if ( (c=wintoclient(e->window)) ) return;
	c = calloc(1, sizeof(Client));
	c->win = e->window;

	get_hints(c);
	get_icon(c);
	get_name(c);

	apply_rules(c);
	if (!c->tags && !(c->tags=m->tags)) {
		Monitor *M;
		int i, tags = 0;
		for (M = mons; M; M = M->next) tags |= M->tags;

		for (i = 0; ((1<<i) & tags) && i < 9; i++);

		c->tags = m->tags = (1<<i);
	}
	if (XGetTransientForHint(dpy, c->win, &c->parent))
		c->flags |= WIN_TRANS;
	else
		c->parent = e->parent;
	c->x = wa.x; c->y = wa.y; c->w = wa.width; c->h = wa.height;
................................................................................
		case ATTACH_BELOW: push_client(c, m->focus->top->next); break;
	}
	winmarks[0] = winmarks[1];
	winmarks[1] = c;
	purgatory(c->win);
	XMapWindow(dpy, c->win);
	tile();

}

void propertynotify(XEvent *ev) {
	XPropertyEvent *e = &ev->xproperty;
	Client *c;
	if (e->window == root) {
		char *cmd;
................................................................................
		return;
	}
	if ( !(c=wintoclient(e->window)) ) return;
	if (e->atom == XA_WM_NAME) get_name(c);
	else if (e->atom == XA_WM_HINTS) get_hints(c);
	else if (e->atom == XA_WM_CLASS) apply_rules(c);
	else if (e->atom == XA_WM_NORMAL_HINTS) get_size(c);
	// TODO:
	// icon ?
	// netWM
	// XA_TRANSIENT_FOR
	else return;
	tile();
}