about summary refs log tree commit diff stats
path: root/client.c
blob: 1e693f71d15c4a44b44f38af383982a4c69f822b (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
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
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
/*
 * (C)opyright MMVI Anselm R. Garbe <garbeam at gmail dot com>
 * See LICENSE file for license details.
 */

#include <string.h>
#include <X11/Xatom.h>

#include "util.h"
#include "wm.h"

static void
update_client_name(Client *c)
{
	XTextProperty name;
	int n;
	char **list = NULL;

	name.nitems = 0;
	c->name[0] = 0;
	XGetTextProperty(dpy, c->win, &name, net_atom[NetWMName]);
	if(!name.nitems)
		XGetWMName(dpy, c->win, &name);
	if(!name.nitems)
		return;
	if(name.encoding == XA_STRING)
		strncpy(c->name, (char *)name.value, sizeof(c->name));
	else {
		if(XmbTextPropertyToTextList(dpy, &name, &list, &n) >= Success
				&& n > 0 && *list)
		{
			strncpy(c->name, *list, sizeof(c->name));
			XFreeStringList(list);
		}
	}
	XFree(name.value);
}

Client *
create_client(Window w, XWindowAttributes *wa)
{
	Client *c;
	XSetWindowAttributes twa;
	long msize;

	c = emallocz(sizeof(Client));
	c->win = w;
	c->r[RFloat].x = wa->x;
	c->r[RFloat].y = wa->y;
	c->r[RFloat].width = wa->width;
	c->r[RFloat].height = wa->height;
	c->border = wa->border_width;
	XSetWindowBorderWidth(dpy, c->win, 0);
	c->proto = win_proto(c->win);
	XGetTransientForHint(dpy, c->win, &c->trans);
	if(!XGetWMNormalHints(dpy, c->win, &c->size, &msize) || !c->size.flags)
		c->size.flags = PSize;
	c->fixedsize =
		(c->size.flags & PMinSize && c->size.flags & PMaxSize
		 && c->size.min_width == c->size.max_width
		 && c->size.min_height == c->size.max_height);
	XAddToSaveSet(dpy, c->win);
	update_client_name(c);
	twa.override_redirect = 1;
	twa.background_pixmap = ParentRelative;
	twa.event_mask = ExposureMask;

	c->title = XCreateWindow(dpy, root, c->r[RFloat].x, c->r[RFloat].y,
			c->r[RFloat].width, barrect.height, 0,
			DefaultDepth(dpy, screen), CopyFromParent,
			DefaultVisual(dpy, screen),
			CWOverrideRedirect | CWBackPixmap | CWEventMask, &twa);
	XFlush(dpy);

#if 0
	for(t=&client, i=0; *t; t=&(*t)->next, i++);
	c->next = *t; /* *t == nil */
	*t = c;
#endif
	return c;
}

void
manage(Client *c)
{
	XMapRaised(dpy, c->win);
	XSetInputFocus(dpy, c->win, RevertToPointerRoot, CurrentTime);
	XFlush(dpy);
}
span class="p">; if(th > 2 * c->border) { ny += (i - nmaster) * th; nh = th - 2 * c->border; if (i == n - 1) nh += remainder; } else /* fallback if th <= 2 * c->border */ nh = wah - 2 * c->border; } resize(c, nx, ny, nw, nh, False); i++; } else { c->isbanned = True; XMoveWindow(dpy, c->win, c->x + 2 * sw, c->y); } if(!sel || !isvisible(sel)) focustopvisible(); restack(); } LAYOUTS /* extern */ void floating(void) { Client *c; for(c = clients; c; c = c->next) { if(isvisible(c)) { if(c->isbanned) XMoveWindow(dpy, c->win, c->x, c->y); c->isbanned = False; resize(c, c->x, c->y, c->w, c->h, True); } else { c->isbanned = True; XMoveWindow(dpy, c->win, c->x + 2 * sw, c->y); } } if(!sel || !isvisible(sel)) focustopvisible(); restack(); } void focusclient(const char *arg) { Client *c; if(!sel || !arg) return; if(atoi(arg) < 0) { for(c = sel->prev; c && !isvisible(c); c = c->prev); if(!c) { for(c = clients; c && c->next; c = c->next); for(; c && !isvisible(c); c = c->prev); } } else { for(c = sel->next; c && !isvisible(c); c = c->next); if(!c) for(c = clients; c && !isvisible(c); c = c->next); } if(c) { focus(c); restack(); } } void incmasterw(const char *arg) { int i; if(lt->arrange != tile) return; if(!arg) masterw = MASTERWIDTH; else { i = atoi(arg); if(waw * (masterw + i) / 1000 >= waw - 2 * BORDERPX || waw * (masterw + i) / 1000 <= 2 * BORDERPX) return; masterw += i; } lt->arrange(); } void incnmaster(const char *arg) { int i; if(!arg) nmaster = NMASTER; else { i = atoi(arg); if((lt->arrange != tile) || (nmaster + i < 1) || (wah / (nmaster + i) <= 2 * BORDERPX)) return; nmaster += i; } if(sel) lt->arrange(); else drawstatus(); } void initlayouts(void) { unsigned int i, w; lt = &layout[0]; nlayouts = sizeof layout / sizeof layout[0]; for(blw = i = 0; i < nlayouts; i++) { w = textw(layout[i].symbol); if(w > blw) blw = w; } } Client * nexttiled(Client *c) { for(; c && (c->isfloating || !isvisible(c)); c = c->next); return c; } void restack(void) { Client *c; XEvent ev; drawstatus(); if(!sel) return; if(sel->isfloating || lt->arrange == floating) XRaiseWindow(dpy, sel->win); if(lt->arrange != floating) { if(!sel->isfloating) XLowerWindow(dpy, sel->win); for(c = nexttiled(clients); c; c = nexttiled(c->next)) { if(c == sel) continue; XLowerWindow(dpy, c->win); } } XSync(dpy, False); while(XCheckMaskEvent(dpy, EnterWindowMask, &ev)); } void setlayout(const char *arg) { int i; if(!arg) { for(i = 0; i < nlayouts && lt != &layout[i]; i++); if(i == nlayouts - 1) lt = &layout[0]; else lt = &layout[++i]; } else { i = atoi(arg); if(i < 0 || i >= nlayouts) return; lt = &layout[i]; } if(sel) lt->arrange(); else drawstatus(); } void togglebar(const char *arg) { bpos = (bpos == BarOff) ? BARPOS : BarOff; updatebarpos(); lt->arrange(); } void togglemax(const char *arg) { XEvent ev; if(!sel || (lt->arrange != floating && !sel->isfloating) || sel->isfixed) return; if((sel->ismax = !sel->ismax)) { sel->rx = sel->x; sel->ry = sel->y; sel->rw = sel->w; sel->rh = sel->h; resize(sel, wax, way, waw - 2 * BORDERPX, wah - 2 * BORDERPX, True); } else resize(sel, sel->rx, sel->ry, sel->rw, sel->rh, True); drawstatus(); while(XCheckMaskEvent(dpy, EnterWindowMask, &ev)); } void zoom(const char *arg) { Client *c; if(!sel || lt->arrange != tile || sel->isfloating) return; if((c = sel) == nexttiled(clients)) if(!(c = nexttiled(c->next))) return; detach(c); attach(c); focus(c); lt->arrange(); }