shod

mouse-based window manager that can tile windows inside floating containers
Log | Files | Refs | README | LICENSE

xhints.c (8586B)


      1 #include "shod.h"
      2 
      3 /* get window name */
      4 static char *
      5 getwinname(Window win)
      6 {
      7 	XTextProperty tprop;
      8 	char **list = NULL;
      9 	char *name = NULL;
     10 	unsigned char *p = NULL;
     11 	unsigned long size, dl;
     12 	int di;
     13 	Atom da;
     14 
     15 	if (XGetWindowProperty(dpy, win, atoms[_NET_WM_NAME], 0L, NAMEMAXLEN, False, atoms[UTF8_STRING],
     16 	                       &da, &di, &size, &dl, &p) == Success && p) {
     17 		name = estrndup((char *)p, NAMEMAXLEN);
     18 		XFree(p);
     19 	} else if (XGetWMName(dpy, win, &tprop) &&
     20 	           XmbTextPropertyToTextList(dpy, &tprop, &list, &di) == Success &&
     21 	           di > 0 && list && *list) {
     22 		name = estrndup(*list, NAMEMAXLEN);
     23 		XFreeStringList(list);
     24 		XFree(tprop.value);
     25 	}
     26 	return name;
     27 }
     28 
     29 /* check if given geometry is obscured by containers above it */
     30 static int
     31 isobscured(struct Container *c, struct Monitor *mon, int desk, int x, int y, int w, int h)
     32 {
     33 	x = max(x, mon->wx);
     34 	y = max(y, mon->wy);
     35 	w = min(x + w, mon->wx + mon->ww) - x;
     36 	h = min(y + h, mon->wy + mon->wh) - y;
     37 	if (config.disablehidden || c == NULL)
     38 		return 0;
     39 	if (w <= 0 || h <= 0)
     40 		return 1;
     41 	while ((c = TAILQ_PREV(c, ContainerQueue, raiseentry)) != NULL) {
     42 		if (ISDUMMY(c) || !containerisvisible(c, mon, desk))
     43 			continue;
     44 		return isobscured(c, mon, desk, x, y, w, c->y - y) &&
     45 		       isobscured(c, mon, desk, x, y, c->x - x, h) &&
     46 		       isobscured(c, mon, desk, x, c->y + c->h, w, y + h - (c->y + c->h)) &&
     47 		       isobscured(c, mon, desk, c->x + c->w, y, x + w - (c->x + c->w), h);
     48 	}
     49 	return 0;
     50 }
     51 
     52 /* set desktop for a given window */
     53 void
     54 ewmhsetdesktop(Window win, long d)
     55 {
     56 	XChangeProperty(dpy, win, atoms[_NET_WM_DESKTOP], XA_CARDINAL, 32, PropModeReplace, (unsigned char *)&d, 1);
     57 }
     58 
     59 /* initialize ewmh hints */
     60 void
     61 ewmhinit(const char *wmname)
     62 {
     63 	/* set window and property that indicates that the wm is ewmh compliant */
     64 	XChangeProperty(dpy, wm.checkwin, atoms[_NET_SUPPORTING_WM_CHECK], XA_WINDOW, 32, PropModeReplace, (unsigned char *)&wm.checkwin, 1);
     65 	XChangeProperty(dpy, wm.checkwin, atoms[_NET_WM_NAME], atoms[UTF8_STRING], 8, PropModeReplace, (unsigned char *)wmname, strlen(wmname));
     66 	XChangeProperty(dpy, root, atoms[_NET_SUPPORTING_WM_CHECK], XA_WINDOW, 32, PropModeReplace, (unsigned char *)&wm.checkwin, 1);
     67 
     68 	/* set properties that the window manager supports */
     69 	XChangeProperty(dpy, root, atoms[_NET_SUPPORTED], XA_ATOM, 32, PropModeReplace, (unsigned char *)atoms, NATOMS);
     70 	XDeleteProperty(dpy, root, atoms[_NET_CLIENT_LIST]);
     71 
     72 	/* set number of desktops */
     73 	XChangeProperty(dpy, root, atoms[_NET_NUMBER_OF_DESKTOPS], XA_CARDINAL, 32, PropModeReplace, (unsigned char *)&config.ndesktops, 1);
     74 }
     75 
     76 /* set current desktop hint */
     77 void
     78 ewmhsetcurrentdesktop(unsigned long n)
     79 {
     80 	XChangeProperty(dpy, root, atoms[_NET_CURRENT_DESKTOP], XA_CARDINAL, 32, PropModeReplace, (unsigned char *)&n, 1);
     81 }
     82 
     83 /* set showing desktop hint */
     84 void
     85 ewmhsetshowingdesktop(int n)
     86 {
     87 	XChangeProperty(dpy, root, atoms[_NET_SHOWING_DESKTOP], XA_CARDINAL, 32, PropModeReplace, (unsigned char *)&n, 1);
     88 }
     89 
     90 /* set stacking list of clients hint */
     91 void
     92 ewmhsetclients(void)
     93 {
     94 	Window *wins = NULL;
     95 	Window *cnts = NULL;
     96 	struct Container *c;
     97 	struct Column *col;
     98 	struct Row *row;
     99 	struct Object *p;
    100 	struct Tab *t;
    101 	int prevobscured, i, j = 0;
    102 
    103 	if (wm.nclients < 1) {
    104 		XChangeProperty(dpy, root, atoms[_NET_CLIENT_LIST], XA_WINDOW, 32, PropModeReplace, NULL, 0);
    105 		XChangeProperty(dpy, root, atoms[_NET_CLIENT_LIST_STACKING], XA_WINDOW, 32, PropModeReplace, NULL, 0);
    106 		XChangeProperty(dpy, root, atoms[_SHOD_CONTAINER_LIST], XA_WINDOW, 32, PropModeReplace, NULL, 0);
    107 		return;
    108 	}
    109 	wins = ecalloc(wm.nclients, sizeof *wins);
    110 	cnts = ecalloc(wm.nclients, sizeof *cnts);
    111 	i = wm.nclients;
    112 	TAILQ_FOREACH(c, &wm.stackq, raiseentry) {
    113 		if (ISDUMMY(c))
    114 			continue;
    115 		cnts[j++] = c->selcol->selrow->seltab->obj.win;
    116 		prevobscured = c->isobscured;
    117 		if (!config.disablehidden)
    118 			c->isobscured = isobscured(c, c->mon, c->desk, c->x, c->y, c->w, c->h);
    119 		TAILQ_FOREACH(col, &c->colq, entry) {
    120 			if (col->selrow->seltab != NULL)
    121 				wins[--i] = col->selrow->seltab->obj.win;
    122 			TAILQ_FOREACH(p, &col->selrow->tabq, entry) {
    123 				t = (struct Tab *)p;
    124 				if (t != col->selrow->seltab) {
    125 					wins[--i] = t->obj.win;
    126 				}
    127 			}
    128 			TAILQ_FOREACH(row, &col->rowq, entry) {
    129 				if (row == col->selrow)
    130 					continue;
    131 				if (row->seltab != NULL)
    132 					wins[--i] = row->seltab->obj.win;
    133 				TAILQ_FOREACH(p, &row->tabq, entry) {
    134 					t = (struct Tab *)p;
    135 					if (t != row->seltab) {
    136 						wins[--i] = t->obj.win;
    137 					}
    138 				}
    139 			}
    140 		}
    141 		if (prevobscured != c->isobscured) {
    142 			ewmhsetstate(c);
    143 		}
    144 	}
    145 	XChangeProperty(dpy, root, atoms[_NET_CLIENT_LIST], XA_WINDOW, 32, PropModeReplace, (unsigned char *)wins, wm.nclients-i);
    146 	XChangeProperty(dpy, root, atoms[_NET_CLIENT_LIST_STACKING], XA_WINDOW, 32, PropModeReplace, (unsigned char *)wins+i, wm.nclients-i);
    147 	XChangeProperty(dpy, root, atoms[_SHOD_CONTAINER_LIST], XA_WINDOW, 32, PropModeReplace, (unsigned char *)cnts, j);
    148 	free(wins);
    149 	free(cnts);
    150 }
    151 
    152 /* set active window hint */
    153 void
    154 ewmhsetactivewindow(Window w)
    155 {
    156 	XChangeProperty(dpy, root, atoms[_NET_ACTIVE_WINDOW], XA_WINDOW, 32, PropModeReplace, (unsigned char *)&w, 1);
    157 }
    158 
    159 /* set desktop for all windows in a container */
    160 void
    161 ewmhsetwmdesktop(struct Container *c)
    162 {
    163 	struct Object *t;
    164 	unsigned long n;
    165 
    166 	n = (c->issticky || c->isminimized) ? 0xFFFFFFFF : (unsigned long)c->desk;
    167 	TAB_FOREACH_BEGIN(c, t){
    168 		ewmhsetdesktop(t->win, n);
    169 	}TAB_FOREACH_END
    170 }
    171 
    172 /* set frames of window */
    173 void
    174 ewmhsetframeextents(Window win, int b, int t)
    175 {
    176 	unsigned long data[4];
    177 
    178 	data[0] = data[1] = data[3] = b;
    179 	data[2] = b + t;
    180 	XChangeProperty(dpy, win, atoms[_NET_FRAME_EXTENTS], XA_CARDINAL, 32, PropModeReplace, (unsigned char *)data, 4);
    181 }
    182 
    183 /* set state of windows */
    184 void
    185 ewmhsetstate(struct Container *c)
    186 {
    187 	struct Object *t;
    188 	Atom data[9];
    189 	int n = 0;
    190 
    191 	if (c == NULL)
    192 		return;
    193 	if (c == wm.focused)
    194 		data[n++] = atoms[_NET_WM_STATE_FOCUSED];
    195 	if (c->isfullscreen)
    196 		data[n++] = atoms[_NET_WM_STATE_FULLSCREEN];
    197 	if (c->issticky)
    198 		data[n++] = atoms[_NET_WM_STATE_STICKY];
    199 	if (c->isshaded)
    200 		data[n++] = atoms[_NET_WM_STATE_SHADED];
    201 	if (c->isminimized || c->isobscured)
    202 		data[n++] = atoms[_NET_WM_STATE_HIDDEN];
    203 	if (c->ismaximized) {
    204 		data[n++] = atoms[_NET_WM_STATE_MAXIMIZED_VERT];
    205 		data[n++] = atoms[_NET_WM_STATE_MAXIMIZED_HORZ];
    206 	}
    207 	if (c->abovebelow > 0)
    208 		data[n++] = atoms[_NET_WM_STATE_ABOVE];
    209 	else if (c->abovebelow < 0)
    210 		data[n++] = atoms[_NET_WM_STATE_BELOW];
    211 	TAB_FOREACH_BEGIN(c, t){
    212 		XChangeProperty(dpy, t->win, atoms[_NET_WM_STATE], XA_ATOM, 32, PropModeReplace, (unsigned char *)data, n);
    213 	}TAB_FOREACH_END
    214 }
    215 
    216 /* set icccm wmstate */
    217 void
    218 icccmwmstate(Window win, int state)
    219 {
    220 	long data[2];
    221 
    222 	data[0] = state;
    223 	data[1] = None;
    224 	XChangeProperty(dpy, win, atoms[WM_STATE], atoms[WM_STATE], 32, PropModeReplace, (unsigned char *)&data, 2);
    225 }
    226 
    227 /* delete window state property */
    228 void
    229 icccmdeletestate(Window win)
    230 {
    231 	XDeleteProperty(dpy, win, atoms[WM_STATE]);
    232 }
    233 
    234 /* set group of windows in client */
    235 void
    236 shodgrouptab(struct Container *c)
    237 {
    238 	struct Object *t;
    239 
    240 	TAB_FOREACH_BEGIN(c, t){
    241 		XChangeProperty(dpy, t->win, atoms[_SHOD_GROUP_TAB], XA_WINDOW, 32, PropModeReplace, (unsigned char *)&row->seltab->obj.win, 1);
    242 	}TAB_FOREACH_END
    243 }
    244 
    245 /* set group of windows in client */
    246 void
    247 shodgroupcontainer(struct Container *c)
    248 {
    249 	struct Object *t;
    250 
    251 	TAB_FOREACH_BEGIN(c, t){
    252 		XChangeProperty(dpy, t->win, atoms[_SHOD_GROUP_CONTAINER], XA_WINDOW, 32, PropModeReplace, (unsigned char *)&c->selcol->selrow->seltab->obj.win, 1);
    253 	}TAB_FOREACH_END
    254 }
    255 
    256 /* update tab title */
    257 void
    258 winupdatetitle(Window win, char **name)
    259 {
    260 	free(*name);
    261 	*name = getwinname(win);
    262 }
    263 
    264 /* notify window of configuration changing */
    265 void
    266 winnotify(Window win, int x, int y, int w, int h)
    267 {
    268 	XConfigureEvent ce;
    269 
    270 	ce.type = ConfigureNotify;
    271 	ce.display = dpy;
    272 	ce.x = x;
    273 	ce.y = y;
    274 	ce.width = w;
    275 	ce.height = h;
    276 	ce.border_width = 0;
    277 	ce.above = None;
    278 	ce.override_redirect = False;
    279 	ce.event = win;
    280 	ce.window = win;
    281 	XSendEvent(dpy, win, False, StructureNotifyMask, (XEvent *)&ce);
    282 }
    283 
    284 /* send a WM_DELETE message to client */
    285 void
    286 winclose(Window win)
    287 {
    288 	XEvent ev;
    289 
    290 	ev.type = ClientMessage;
    291 	ev.xclient.window = win;
    292 	ev.xclient.message_type = atoms[WM_PROTOCOLS];
    293 	ev.xclient.format = 32;
    294 	ev.xclient.data.l[0] = atoms[WM_DELETE_WINDOW];
    295 	ev.xclient.data.l[1] = CurrentTime;
    296 
    297 	/*
    298 	 * communicate with the given Client, kindly telling it to
    299 	 * close itself and terminate any associated processes using
    300 	 * the WM_DELETE_WINDOW protocol
    301 	 */
    302 	XSendEvent(dpy, win, False, NoEventMask, &ev);
    303 }