shod

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

xmon.c (6647B)


      1 #include "shod.h"
      2 
      3 #include <X11/extensions/Xrandr.h>
      4 
      5 void
      6 moninit(void)
      7 {
      8 	int i;
      9 
     10 	if ((wm.xrandr = XRRQueryExtension(dpy, &wm.xrandrev, &i))) {
     11 		XRRSelectInput(dpy, root, RRScreenChangeNotifyMask);
     12 	}
     13 }
     14 
     15 void
     16 monevent(XEvent *e)
     17 {
     18 	XRRScreenChangeNotifyEvent *ev;
     19 
     20 	ev = (XRRScreenChangeNotifyEvent *)e;
     21 	if (ev->root == root) {
     22 		(void)XRRUpdateConfiguration(e);
     23 		monupdate();
     24 		monupdatearea();
     25 		notifplace();
     26 		dockupdate();
     27 	}
     28 }
     29 
     30 /* delete monitor and set monitor of clients on it to NULL */
     31 void
     32 mondel(struct Monitor *mon)
     33 {
     34 	struct Object *obj;
     35 	struct Container *c;
     36 
     37 	TAILQ_REMOVE(&wm.monq, mon, entry);
     38 	TAILQ_FOREACH(c, &wm.focusq, entry)
     39 		if (c->mon == mon)
     40 			c->mon = NULL;
     41 	TAILQ_FOREACH(obj, &wm.menuq, entry)
     42 		if (((struct Menu *)obj)->mon == mon)
     43 			((struct Menu *)obj)->mon = NULL;
     44 	TAILQ_FOREACH(obj, &wm.splashq, entry)
     45 		if (((struct Splash *)obj)->mon == mon)
     46 			((struct Splash *)obj)->mon = NULL;
     47 	free(mon);
     48 }
     49 
     50 /* get monitor given coordinates */
     51 struct Monitor *
     52 getmon(int x, int y)
     53 {
     54 	struct Monitor *mon;
     55 
     56 	TAILQ_FOREACH(mon, &wm.monq, entry)
     57 		if (x >= mon->mx && x < mon->mx + mon->mw && y >= mon->my && y < mon->my + mon->mh)
     58 			return mon;
     59 	return NULL;
     60 }
     61 
     62 /* update the list of monitors */
     63 void
     64 monupdate(void)
     65 {
     66 	XRRScreenResources *sr;
     67 	XRRCrtcInfo *ci;
     68 	struct MonitorQueue monq;               /* queue of monitors */
     69 	struct Monitor *mon;
     70 	struct Container *c, *focus;
     71 	struct Object *m, *s;
     72 	int delselmon, i;
     73 
     74 	TAILQ_INIT(&monq);
     75 	sr = XRRGetScreenResources(dpy, root);
     76 	for (i = 0, ci = NULL; i < sr->ncrtc; i++) {
     77 		if ((ci = XRRGetCrtcInfo(dpy, sr, sr->crtcs[i])) == NULL)
     78 			continue;
     79 		if (ci->noutput == 0)
     80 			goto next;
     81 
     82 		TAILQ_FOREACH(mon, &wm.monq, entry)
     83 			if (ci->x == mon->mx && ci->y == mon->my &&
     84 			    (int)ci->width == mon->mw && (int)ci->height == mon->mh)
     85 				break;
     86 		if (mon != NULL) {
     87 			TAILQ_REMOVE(&wm.monq, mon, entry);
     88 		} else {
     89 			mon = emalloc(sizeof(*mon));
     90 			*mon = (struct Monitor){
     91 				.mx = ci->x,
     92 				.wx = ci->x,
     93 				.my = ci->y,
     94 				.wy = ci->y,
     95 				.mw = ci->width,
     96 				.ww = ci->width,
     97 				.mh = ci->height,
     98 				.wh = ci->height,
     99 			};
    100 		}
    101 		TAILQ_INSERT_TAIL(&monq, mon, entry);
    102 next:
    103 		XRRFreeCrtcInfo(ci);
    104 	}
    105 	XRRFreeScreenResources(sr);
    106 
    107 	/* delete monitors that do not exist anymore */
    108 	delselmon = 0;
    109 	while ((mon = TAILQ_FIRST(&wm.monq)) != NULL) {
    110 		if (mon == wm.selmon) {
    111 			delselmon = 1;
    112 			wm.selmon = NULL;
    113 		}
    114 		mondel(mon);
    115 	}
    116 	if (delselmon) {
    117 		wm.selmon = TAILQ_FIRST(&monq);
    118 	}
    119 
    120 	/* commit new list of monitor */
    121 	while ((mon = TAILQ_FIRST(&monq)) != NULL) {
    122 		TAILQ_REMOVE(&monq, mon, entry);
    123 		TAILQ_INSERT_TAIL(&wm.monq, mon, entry);
    124 	}
    125 
    126 	/* send containers which do not belong to a monitor to selected desktop */
    127 	focus = NULL;
    128 	TAILQ_FOREACH(c, &wm.focusq, entry) {
    129 		if (!c->isminimized && c->mon == NULL) {
    130 			focus = c;
    131 			c->mon = wm.selmon;
    132 			c->desk = wm.selmon->seldesk;
    133 			containerplace(c, wm.selmon, wm.selmon->seldesk, 0);
    134 			containermoveresize(c, 0);
    135 			ewmhsetwmdesktop(c);
    136 			ewmhsetstate(c);
    137 		}
    138 	}
    139 	TAILQ_FOREACH(m, &wm.menuq, entry)
    140 		if (((struct Menu *)m)->mon == NULL)
    141 			menuplace(wm.selmon, (struct Menu *)m);
    142 	TAILQ_FOREACH(s, &wm.splashq, entry)
    143 		if (((struct Splash *)s)->mon == NULL)
    144 			splashplace(wm.selmon, (struct Splash *)s);
    145 	if (focus != NULL)              /* if a contained changed desktop, focus it */
    146 		tabfocus(focus->selcol->selrow->seltab, 1);
    147 	wm.setclientlist = 1;
    148 }
    149 
    150 /* update window area and dock area of monitor */
    151 void
    152 monupdatearea(void)
    153 {
    154 	struct Monitor *mon;
    155 	struct Bar *bar;
    156 	struct Object *p;
    157 	struct Container *c;
    158 	int t, b, l, r;
    159 
    160 	TAILQ_FOREACH(mon, &wm.monq, entry) {
    161 		mon->wx = mon->mx;
    162 		mon->wy = mon->my;
    163 		mon->ww = mon->mw;
    164 		mon->wh = mon->mh;
    165 		t = b = l = r = 0;
    166 		if (mon == TAILQ_FIRST(&wm.monq) && dock.mapped) {
    167 			switch (config.dockgravity[0]) {
    168 			case 'N':
    169 				t = config.dockwidth;
    170 				break;
    171 			case 'S':
    172 				b = config.dockwidth;
    173 				break;
    174 			case 'W':
    175 				l = config.dockwidth;
    176 				break;
    177 			case 'E':
    178 			default:
    179 				r = config.dockwidth;
    180 				break;
    181 			}
    182 		}
    183 		TAILQ_FOREACH(p, &wm.barq, entry) {
    184 			bar = (struct Bar *)p;
    185 			if (bar->strut[STRUT_TOP] != 0) {
    186 				if (bar->strut[STRUT_TOP] >= mon->my &&
    187 				    bar->strut[STRUT_TOP] < mon->my + mon->mh &&
    188 				    (!bar->ispartial ||
    189 				     (bar->strut[STRUT_TOP_START_X] >= mon->mx &&
    190 				     bar->strut[STRUT_TOP_END_X] <= mon->mx + mon->mw))) {
    191 					t = max(t, bar->strut[STRUT_TOP] - mon->my);
    192 				}
    193 			} else if (bar->strut[STRUT_BOTTOM] != 0) {
    194 				if (DisplayHeight(dpy, screen) - bar->strut[STRUT_BOTTOM] <= mon->my + mon->mh &&
    195 				    DisplayHeight(dpy, screen) - bar->strut[STRUT_BOTTOM] > mon->my &&
    196 				    (!bar->ispartial ||
    197 				     (bar->strut[STRUT_BOTTOM_START_X] >= mon->mx &&
    198 				     bar->strut[STRUT_BOTTOM_END_X] <= mon->mx + mon->mw))) {
    199 					b = max(b, bar->strut[STRUT_BOTTOM] - (DisplayHeight(dpy, screen) - (mon->my + mon->mh)));
    200 				}
    201 			} else if (bar->strut[STRUT_LEFT] != 0) {
    202 				if (bar->strut[STRUT_LEFT] >= mon->mx &&
    203 				    bar->strut[STRUT_LEFT] < mon->mx + mon->mw &&
    204 				    (!bar->ispartial ||
    205 				     (bar->strut[STRUT_LEFT_START_Y] >= mon->my &&
    206 				     bar->strut[STRUT_LEFT_END_Y] <= mon->my + mon->mh))) {
    207 					l = max(l, bar->strut[STRUT_LEFT] - mon->mx);
    208 				}
    209 			} else if (bar->strut[STRUT_RIGHT] != 0) {
    210 				if (DisplayWidth(dpy, screen) - bar->strut[STRUT_RIGHT] <= mon->mx + mon->mw &&
    211 				    DisplayWidth(dpy, screen) - bar->strut[STRUT_RIGHT] > mon->mx &&
    212 				    (!bar->ispartial ||
    213 				     (bar->strut[STRUT_RIGHT_START_Y] >= mon->my &&
    214 				     bar->strut[STRUT_RIGHT_END_Y] <= mon->my + mon->mh))) {
    215 					r = max(r, bar->strut[STRUT_RIGHT] - (DisplayWidth(dpy, screen) - (mon->mx + mon->mw)));
    216 				}
    217 			}
    218 		}
    219 		mon->wy += t;
    220 		mon->wh -= t + b;
    221 		mon->wx += l;
    222 		mon->ww -= l + r;
    223 	}
    224 	TAILQ_FOREACH(c, &wm.focusq, entry) {
    225 		if (c->ismaximized) {
    226 			containercalccols(c);
    227 			containermoveresize(c, 0);
    228 			containerredecorate(c, NULL, NULL, 0);
    229 		}
    230 	}
    231 	wm.setclientlist = 1;
    232 }
    233 
    234 /* if window is bigger than monitor, resize it while maintaining proportion */
    235 void
    236 fitmonitor(struct Monitor *mon, int *x, int *y, int *w, int *h, float factor)
    237 {
    238 	int origw, origh;
    239 	int minw, minh;
    240 
    241 	origw = *w;
    242 	origh = *h;
    243 	minw = min(origw, mon->ww * factor);
    244 	minh = min(origh, mon->wh * factor);
    245 	if (origw * minh > origh * minw) {
    246 		minh = (origh * minw) / origw;
    247 		minw = (origw * minh) / origh;
    248 	} else {
    249 		minw = (origw * minh) / origh;
    250 		minh = (origh * minw) / origw;
    251 	}
    252 	*w = max(wm.minsize, minw);
    253 	*h = max(wm.minsize, minh);
    254 	*x = max(mon->wx, min(mon->wx + mon->ww - *w, *x));
    255 	*y = max(mon->wy, min(mon->wy + mon->wh - *h, *y));
    256 }