shod

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

xdock.c (10042B)


      1 #include "shod.h"
      2 
      3 /* decorate dock */
      4 void
      5 dockdecorate(void)
      6 {
      7 	if (dock.pw != dock.w || dock.ph != dock.h || dock.pix == None)
      8 		pixmapnew(&dock.pix, dock.win, dock.w, dock.h);
      9 	dock.pw = dock.w;
     10 	dock.ph = dock.h;
     11 	drawdock(dock.pix, dock.w, dock.h);
     12 	drawcommit(dock.pix, dock.win);
     13 }
     14 
     15 /* configure dockapp window */
     16 void
     17 dockappconfigure(struct Dockapp *dapp, unsigned int valuemask, XWindowChanges *wc)
     18 {
     19 	if (dapp == NULL)
     20 		return;
     21 	if (valuemask & CWWidth)
     22 		dapp->w = wc->width;
     23 	if (valuemask & CWHeight)
     24 		dapp->h = wc->height;
     25 	switch (config.dockgravity[0]) {
     26 	case 'N':
     27 	case 'S':
     28 		if (dapp->state & SHRUNK)
     29 			dapp->slotsize = dapp->w;
     30 		else
     31 			dapp->slotsize = (dapp->w / config.dockspace + (dapp->w % config.dockspace ? 1 : 0)) * config.dockspace;
     32 		dapp->h = min(config.dockwidth, dapp->h);
     33 		break;
     34 	case 'W':
     35 	case 'E':
     36 	default:
     37 		if (dapp->state & SHRUNK)
     38 			dapp->slotsize = dapp->h;
     39 		else
     40 			dapp->slotsize = (dapp->h / config.dockspace + (dapp->h % config.dockspace ? 1 : 0)) * config.dockspace;
     41 		dapp->w = min(config.dockwidth, dapp->w);
     42 		break;
     43 	}
     44 }
     45 
     46 static void
     47 dockappinsert(struct Dockapp *dapp)
     48 {
     49 	struct Object *prev;
     50 
     51 	if (dapp->dockpos == 0) {
     52 		TAILQ_INSERT_TAIL(&dock.dappq, (struct Object *)dapp, entry);
     53 	} else {
     54 		TAILQ_FOREACH_REVERSE(prev, &dock.dappq, Queue, entry)
     55 			if (((struct Dockapp *)prev)->dockpos <= dapp->dockpos)
     56 				break;
     57 		if (prev != NULL) {
     58 			TAILQ_INSERT_AFTER(&dock.dappq, prev, (struct Object *)dapp, entry);
     59 		} else {
     60 			TAILQ_INSERT_HEAD(&dock.dappq, (struct Object *)dapp, entry);
     61 		}
     62 	}
     63 	dockappconfigure(
     64 		dapp,
     65 		CWWidth | CWHeight,
     66 		&(XWindowChanges){
     67 			.width = dapp->w,
     68 			.height = dapp->h,
     69 		}
     70 	);
     71 }
     72 
     73 /* create dockapp */
     74 static void
     75 dockappnew(Window win, int w, int h, int dockpos, int state, int ignoreunmap)
     76 {
     77 	struct Dockapp *dapp;
     78 
     79 	dapp = emalloc(sizeof(*dapp));
     80 	*dapp = (struct Dockapp){
     81 		.obj.type = TYPE_DOCKAPP,
     82 		.obj.win = win,
     83 		.x = 0,
     84 		.y = 0,
     85 		.w = w,
     86 		.h = h,
     87 		.ignoreunmap = ignoreunmap,
     88 		.dockpos = dockpos,
     89 		.state = state,
     90 	};
     91 	dockappinsert(dapp);
     92 }
     93 
     94 /* compute dockapp position given its width or height */
     95 static int
     96 dockapppos(int pos)
     97 {
     98 	return max(0, config.dockwidth / 2 - pos / 2);
     99 }
    100 
    101 /* update dock position; create it, if necessary */
    102 static void
    103 dockupdateresizeable(void)
    104 {
    105 	struct Monitor *mon;
    106 	struct Object *p;
    107 	struct Dockapp *dapp;
    108 	int size;
    109 
    110 	mon = TAILQ_FIRST(&wm.monq);
    111 	size = 0;
    112 	TAILQ_FOREACH(p, &dock.dappq, entry) {
    113 		dapp = (struct Dockapp *)p;
    114 		switch (config.dockgravity[0]) {
    115 		case 'N':
    116 			if (dapp->state & RESIZED)
    117 				dapp->h = config.dockwidth;
    118 			dapp->x = DOCKBORDER + size + max(0, (dapp->slotsize - dapp->w) / 2);
    119 			dapp->y = DOCKBORDER + dockapppos(dapp->h);
    120 			break;
    121 		case 'S':
    122 			if (dapp->state & RESIZED)
    123 				dapp->h = config.dockwidth;
    124 			dapp->x = DOCKBORDER + size + max(0, (dapp->slotsize - dapp->w) / 2);
    125 			dapp->y = DOCKBORDER + dockapppos(dapp->h);
    126 			break;
    127 		case 'W':
    128 			if (dapp->state & RESIZED)
    129 				dapp->w = config.dockwidth;
    130 			dapp->x = DOCKBORDER + dockapppos(dapp->w);
    131 			dapp->y = DOCKBORDER + size + max(0, (dapp->slotsize - dapp->h) / 2);
    132 			break;
    133 		case 'E':
    134 		default:
    135 			if (dapp->state & RESIZED)
    136 				dapp->w = config.dockwidth;
    137 			dapp->x = DOCKBORDER + dockapppos(dapp->w);
    138 			dapp->y = DOCKBORDER + size + max(0, (dapp->slotsize - dapp->h) / 2);
    139 			break;
    140 		}
    141 		size += dapp->slotsize;
    142 	}
    143 	if (size == 0) {
    144 		XUnmapWindow(dpy, dock.win);
    145 		dock.mapped = 0;
    146 		return;
    147 	}
    148 	dock.mapped = 1;
    149 	size += DOCKBORDER * 2;
    150 	switch (config.dockgravity[0]) {
    151 	case 'N':
    152 		dock.h = config.dockwidth;
    153 		dock.x = mon->mx;
    154 		dock.y = mon->my;
    155 		break;
    156 	case 'S':
    157 		dock.h = config.dockwidth;
    158 		dock.x = mon->mx;
    159 		dock.y = mon->my + mon->mh - config.dockwidth;
    160 		break;
    161 	case 'W':
    162 		dock.w = config.dockwidth;
    163 		dock.x = mon->mx;
    164 		dock.y = mon->my;
    165 		break;
    166 	case 'E':
    167 	default:
    168 		dock.w = config.dockwidth;
    169 		dock.x = mon->mx + mon->mw - config.dockwidth;
    170 		dock.h = min(size, mon->mh);
    171 		dock.y = mon->my + mon->mh / 2 - size / 2;
    172 		break;
    173 	}
    174 	if (config.dockgravity[0] == 'N' || config.dockgravity[0] == 'S') {
    175 		switch (config.dockgravity[1]) {
    176 		case 'F':
    177 			dock.x = mon->mx;
    178 			dock.w = mon->mw;
    179 			break;
    180 		case 'W':
    181 			dock.w = min(size, mon->mw);
    182 			dock.x = mon->mx;
    183 			break;
    184 		case 'E':
    185 			dock.w = min(size, mon->mw);
    186 			dock.x = mon->mx + mon->mw - size;
    187 			break;
    188 		default:
    189 			dock.w = min(size, mon->mw);
    190 			dock.x = mon->mx + mon->mw / 2 - size / 2;
    191 			break;
    192 		}
    193 	} else if (config.dockgravity[0] != '\0') {
    194 		switch (config.dockgravity[1]) {
    195 		case 'F':
    196 			dock.h = mon->mh;
    197 			dock.y = mon->my;
    198 			break;
    199 		case 'N':
    200 			dock.h = min(size, mon->mh);
    201 			dock.y = mon->my;
    202 			break;
    203 		case 'S':
    204 			dock.h = min(size, mon->mh);
    205 			dock.y = mon->my + mon->mh - size;
    206 			break;
    207 		default:
    208 			dock.h = min(size, mon->mh);
    209 			dock.y = mon->my + mon->mh / 2 - size / 2;
    210 			break;
    211 		}
    212 	}
    213 	TAILQ_FOREACH(p, &dock.dappq, entry) {
    214 		dapp = (struct Dockapp *)p;
    215 		XMoveResizeWindow(dpy, dapp->obj.win, dapp->x, dapp->y, dapp->w, dapp->h);
    216 		winnotify(dapp->obj.win, dock.x + dapp->x, dock.y + dapp->y, dapp->w, dapp->h);
    217 	}
    218 }
    219 
    220 /* update dock position; create it, if necessary */
    221 static void
    222 dockupdatefull(void)
    223 {
    224 	struct Object *p;
    225 	struct Monitor *mon;
    226 	struct Dockapp *dapp;
    227 	int part, nextend, size;
    228 	int i, n;
    229 
    230 	mon = TAILQ_FIRST(&wm.monq);
    231 	if (TAILQ_FIRST(&dock.dappq) == NULL) {
    232 		XUnmapWindow(dpy, dock.win);
    233 		dock.mapped = 0;
    234 		return;
    235 	}
    236 	dock.mapped = 1;
    237 	switch (config.dockgravity[0]) {
    238 	case 'N':
    239 		dock.x = mon->mx;
    240 		dock.y = mon->my;
    241 		dock.w = mon->mw;
    242 		dock.h = config.dockwidth;
    243 		part = dock.w;
    244 		break;
    245 	case 'S':
    246 		dock.x = mon->mx;
    247 		dock.y = mon->my + mon->mh - config.dockwidth;
    248 		dock.w = mon->mw;
    249 		dock.h = config.dockwidth;
    250 		part = dock.w;
    251 		break;
    252 	case 'W':
    253 		dock.x = mon->mx;
    254 		dock.y = mon->my;
    255 		dock.w = config.dockwidth;
    256 		dock.h = mon->mh;
    257 		part = dock.h;
    258 		break;
    259 	case 'E':
    260 	default:
    261 		dock.x = mon->mx + mon->mw - config.dockwidth;
    262 		dock.y = mon->my;
    263 		dock.w = config.dockwidth;
    264 		dock.h = mon->mh;
    265 		part = dock.h;
    266 		break;
    267 	}
    268 	nextend = 0;
    269 	size = 0;
    270 	TAILQ_FOREACH(p, &dock.dappq, entry) {
    271 		dapp = (struct Dockapp *)p;
    272 		if (dapp->state & EXTEND) {
    273 			nextend++;
    274 		} else {
    275 			size += dapp->slotsize;
    276 		}
    277 	}
    278 	part = max(part - size, 1);
    279 	if (nextend > 0)
    280 		part /= nextend;
    281 	i = 0;
    282 	size = 0;
    283 	TAILQ_FOREACH(p, &dock.dappq, entry) {
    284 		dapp = (struct Dockapp *)p;
    285 		switch (config.dockgravity[0]) {
    286 		case 'N':
    287 			if (dapp->state & RESIZED)
    288 				dapp->h = config.dockwidth - DOCKBORDER;
    289 			if (dapp->state & EXTEND) {
    290 				dapp->w = max(1, (i + 1) * part - i * part);
    291 				n = dapp->w;
    292 			} else {
    293 				n = dapp->slotsize;
    294 			}
    295 			dapp->x = size + max(0, (n - dapp->w) / 2);
    296 			dapp->y = DOCKBORDER + dockapppos(dapp->h);
    297 			break;
    298 		case 'S':
    299 			if (dapp->state & RESIZED)
    300 				dapp->h = config.dockwidth - DOCKBORDER;
    301 			if (dapp->state & EXTEND) {
    302 				dapp->w = max(1, (i + 1) * part - i * part);
    303 				n = dapp->w;
    304 			} else {
    305 				n = dapp->slotsize;
    306 			}
    307 			dapp->x = size + max(0, (n - dapp->w) / 2);
    308 			dapp->y = DOCKBORDER + dockapppos(dapp->h);
    309 			break;
    310 		case 'W':
    311 			if (dapp->state & RESIZED)
    312 				dapp->w = config.dockwidth - DOCKBORDER;
    313 			if (dapp->state & EXTEND) {
    314 				dapp->h = max(1, (i + 1) * part - i * part);
    315 				n = dapp->h;
    316 			} else {
    317 				n = dapp->slotsize;
    318 			}
    319 			dapp->x = DOCKBORDER + dockapppos(dapp->w);
    320 			dapp->y = size + max(0, (n - dapp->h) / 2);
    321 			break;
    322 		case 'E':
    323 		default:
    324 			if (dapp->state & RESIZED)
    325 				dapp->w = config.dockwidth - DOCKBORDER;
    326 			if (dapp->state & EXTEND) {
    327 				dapp->h = max(1, (i + 1) * part - i * part);
    328 				n = dapp->h;
    329 			} else {
    330 				n = dapp->slotsize;
    331 			}
    332 			dapp->x = DOCKBORDER + dockapppos(dapp->w);
    333 			dapp->y = size + max(0, (n - dapp->h) / 2);
    334 			break;
    335 		}
    336 		XMoveResizeWindow(dpy, dapp->obj.win, dapp->x, dapp->y, dapp->w, dapp->h);
    337 		winnotify(dapp->obj.win, dock.x + dapp->x, dock.y + dapp->y, dapp->w, dapp->h);
    338 		size += n;
    339 	}
    340 }
    341 
    342 /* update dock position; create it, if necessary */
    343 void
    344 dockupdate(void)
    345 {
    346 	Window wins[2];
    347 
    348 	if (TAILQ_EMPTY(&dock.dappq)) {
    349 		XUnmapWindow(dpy, dock.win);
    350 		return;
    351 	}
    352 	if (config.dockgravity[0] != '\0' && (config.dockgravity[1] == 'F' || config.dockgravity[1] == 'f')) {
    353 		dockupdatefull();
    354 	} else {
    355 		dockupdateresizeable();
    356 	}
    357 	dockdecorate();
    358 	wins[0] = wm.layers[LAYER_DOCK].frame;
    359 	wins[1] = dock.win;
    360 	XMoveResizeWindow(dpy, dock.win, dock.x, dock.y, dock.w, dock.h);
    361 	XRestackWindows(dpy, wins, 2);
    362 	XMapWindow(dpy, dock.win);
    363 	XMapSubwindows(dpy, dock.win);
    364 }
    365 
    366 /* map dockapp window */
    367 void
    368 managedockapp(struct Tab *tab, struct Monitor *mon, int desk, Window win, Window leader, XRectangle rect, int state, int ignoreunmap)
    369 {
    370 	(void)tab;
    371 	(void)mon;
    372 	(void)desk;
    373 	(void)leader;
    374 	XReparentWindow(dpy, win, dock.win, 0, 0);
    375 	dockappnew(win, rect.width, rect.height, rect.x, state, ignoreunmap);
    376 	dockupdate();
    377 	monupdatearea();
    378 }
    379 
    380 /* delete dockapp */
    381 int
    382 unmanagedockapp(struct Object *obj, int ignoreunmap)
    383 {
    384 	struct Dockapp *dapp;
    385 
    386 	dapp = (struct Dockapp *)obj;
    387 	if (ignoreunmap && dapp->ignoreunmap) {
    388 		dapp->ignoreunmap--;
    389 		return 0;
    390 	}
    391 	TAILQ_REMOVE(&dock.dappq, (struct Object *)dapp, entry);
    392 	XReparentWindow(dpy, dapp->obj.win, root, 0, 0);
    393 	free(dapp);
    394 	dockupdate();
    395 	monupdatearea();
    396 	return 0;
    397 }
    398 
    399 void
    400 dockreset(void)
    401 {
    402 	struct Queue dappq;
    403 	struct Object *obj;
    404 	struct Dockapp *dapp;
    405 	Window win, dummyw;
    406 	struct Tab *dummyt;
    407 	XRectangle rect;
    408 	int state, desk;
    409 
    410 	if (TAILQ_EMPTY(&dock.dappq)) {
    411 		XUnmapWindow(dpy, dock.win);
    412 		return;
    413 	}
    414 	TAILQ_INIT(&dappq);
    415 	while ((obj = TAILQ_FIRST(&dock.dappq)) != NULL) {
    416 		TAILQ_REMOVE(&dock.dappq, obj, entry);
    417 		TAILQ_INSERT_TAIL(&dappq, obj, entry);
    418 	}
    419 	while ((obj = TAILQ_FIRST(&dappq)) != NULL) {
    420 		TAILQ_REMOVE(&dappq, obj, entry);
    421 		win = obj->win;
    422 		dapp = (struct Dockapp *)obj;
    423 		if (getwintype(&win, &dummyw, &dummyt, &state, &rect, &desk) == TYPE_DOCKAPP) {
    424 			if (rect.x > 0) {
    425 				dapp->dockpos = rect.x;
    426 			}
    427 			if (state != 0) {
    428 				dapp->state = state;
    429 			}
    430 		}
    431 		dockappinsert(dapp);
    432 	}
    433 	dockupdate();
    434 }