swm

sigma window manager
git clone git://wolog.xyz/swm
Log | Files | Refs | README | LICENSE

monitor.c (5287B)


      1 /*
      2  * Copyright (C) Raymond Cole <rc@wolog.xyz>
      3  *
      4  * Licensed under the GNU General Public License; either version 3 of
      5  * the License, or (at your option) any later version.  See the LICENSE
      6  * file for details.
      7  *
      8  * Portions of the code originally belong to dwm as developed by Anselm
      9  * R. Garbe et al.  See LICENSE-dwm for the copyright and license details
     10  * of those portions.
     11  */
     12 #include <stdlib.h>
     13 #include <X11/Xlib.h>
     14 #ifdef XINERAMA
     15 #include <X11/extensions/Xinerama.h>
     16 #endif
     17 
     18 #include "swm.h"
     19 #include "util.h"
     20 
     21 static Monitor *createmon(void);
     22 static void cleanupmon(Monitor *mon);
     23 static void showhide(Client *c);
     24 static void restack(Monitor *m);
     25 
     26 void
     27 wsload(Monitor *m)
     28 {
     29 	Workspace *w = m->workspaces + m->selws;
     30 
     31 	m->lyt = w->lyt;
     32 	w->lyt = NULL;
     33 	m->tagset = w->tagset;
     34 	updatelytdesc(m);
     35 }
     36 
     37 void
     38 wssync(Monitor *m)
     39 {
     40 	Workspace *w = m->workspaces + m->selws;
     41 
     42 	w->lyt = m->lyt;
     43 	w->tagset = m->tagset;
     44 }
     45 
     46 Monitor *
     47 createmon(void)
     48 {
     49 	Monitor *m;
     50 	unsigned i;
     51 
     52 	if (!(m = malloc(sizeof(*m)))) {
     53 		warn("malloc:");
     54 		return NULL;
     55 	}
     56 	m->nogaps = NOGAPS;
     57 	m->showbar = SHOWBAR;
     58 	m->gapih = gapih;
     59 	m->gapiv = gapiv;
     60 	m->gapoh = gapoh;
     61 	m->gapov = gapov;
     62 	m->clients = m->stack = m->sel = NULL;
     63 	m->next = NULL;
     64 	m->pending = 0;
     65 	for (i = 0; i < LENGTH(tags); ++i) {
     66 		m->workspaces[i].lyt = lytparse(defaultlayout);
     67 		m->workspaces[i].tagset = 1 << i;
     68 	}
     69 	m->selws = m->altws = 0;
     70 	wsload(m);
     71 	pdrawbar(m);
     72 	return m;
     73 }
     74 
     75 void
     76 cleanupmon(Monitor *mon)
     77 {
     78 	Monitor *m;
     79 	int i;
     80 
     81 	if (mon == mons) {
     82 		mons = mons->next;
     83 	} else {
     84 		for (m = mons; m && m->next != mon; m = m->next)
     85 			;
     86 		m->next = mon->next;
     87 	}
     88 	wssync(mon);
     89 	for (i = 0; i < LENGTH(tags); ++i)
     90 		lytfree(mon->workspaces[i].lyt);
     91 	XUnmapWindow(dpy, mon->barwin);
     92 	XDestroyWindow(dpy, mon->barwin);
     93 	free(mon);
     94 }
     95 
     96 #ifdef XINERAMA
     97 static int
     98 isuniquegeom(XineramaScreenInfo *unique, size_t n, XineramaScreenInfo *info)
     99 {
    100 	while (n--)
    101 		if (unique[n].x_org == info->x_org
    102 		 && unique[n].y_org == info->y_org
    103 		 && unique[n].width == info->width
    104 		 && unique[n].height == info->height)
    105 			return 0;
    106 	return 1;
    107 }
    108 #endif /* XINERAMA */
    109 
    110 int
    111 updategeom(void)
    112 {
    113 	int dirty = 0;
    114 
    115 #ifdef XINERAMA
    116 	if (XineramaIsActive(dpy)) {
    117 		XineramaScreenInfo *info;
    118 		Monitor *m, **pm;
    119 		int i, n, nn;
    120 		Client *c;
    121 
    122 		/* only consider unique geometries as separate screens */
    123 		info = XineramaQueryScreens(dpy, &n);
    124 		nn = 0;
    125 		for (i = 0; i < n; ++i)
    126 			if (isuniquegeom(info, nn, info + i))
    127 				info[nn++] = info[i];
    128 		for (n = 0, pm = &mons; n < nn && *pm; ++n, pm = &(*pm)->next)
    129 			;
    130 		if (n < nn) {
    131 			/* new monitors */
    132 			for (i = n; i < nn; ++i) {
    133 				if (!(*pm = createmon()))
    134 					break;
    135 				pm = &(*pm)->next;
    136 			}
    137 			if (i < nn) {
    138 				warn("cannot handle some new screens");
    139 				nn = i;
    140 			}
    141 		} else if (n > nn) {
    142 			/* removed monitors */
    143 			while (*pm) {
    144 				while ((c = (*pm)->clients)) {
    145 					dirty = 1;
    146 					sendtomon(c, mons);
    147 				}
    148 				if (*pm == selmon)
    149 					focusmon(mons);
    150 				cleanupmon(*pm);
    151 			}
    152 		}
    153 		for (m = mons, i = 0; m; m = m->next, ++i) {
    154 			if (i >= n
    155 			|| info[i].x_org != m->x || info[i].width != m->w
    156 			|| info[i].y_org != m->y || info[i].height != m->h) {
    157 				dirty = 1;
    158 				m->num = i;
    159 				m->x = info[i].x_org;
    160 				m->y = info[i].y_org;
    161 				m->w = info[i].width;
    162 				m->h = info[i].height;
    163 			}
    164 		}
    165 		XFree(info);
    166 	} else
    167 #endif /* XINERAMA */
    168 	{
    169 		/* default monitor setup */
    170 		if (!mons) {
    171 			if (!(mons = createmon())) {
    172 				warn("cannot handle default screen");
    173 				return -1;
    174 			}
    175 			dirty = 1;
    176 			mons->x = mons->y = 0;
    177 			mons->w = sw;
    178 			mons->h = sh;
    179 		} else if (mons->w != sw || mons->h != sh) {
    180 			dirty = 1;
    181 			mons->w = sw;
    182 			mons->h = sh;
    183 		}
    184 	}
    185 	if (dirty)
    186 		focusmon(mons);
    187 	return dirty;
    188 }
    189 
    190 void
    191 cleanupgeom(void)
    192 {
    193 	while (mons)
    194 		cleanupmon(mons);
    195 }
    196 
    197 Monitor *
    198 nextmon(Monitor *m)
    199 {
    200 	return m->next ? m->next : mons;
    201 }
    202 
    203 Monitor *
    204 prevmon(Monitor *m)
    205 {
    206 	Monitor *n = m == mons ? NULL : m;
    207 
    208 	for (m = mons; m->next != n; m = m->next)
    209 		;
    210 	return m;
    211 }
    212 
    213 Monitor *
    214 pttomon(int x, int y)
    215 {
    216 	Monitor *m = selmon;
    217 
    218 	do {
    219 		if (x >= m->x && x < m->x + m->w
    220 		 && y >= m->y && y < m->y + m->h)
    221 			return m;
    222 		m = m->next ? m->next : mons;
    223 	} while (m != selmon);
    224 	return NULL;
    225 }
    226 
    227 void
    228 focusmon(Monitor *m)
    229 {
    230 	if (selmon) {
    231 		focus(NULL);
    232 		pdrawbar(selmon);
    233 	}
    234 	selmon = m;
    235 	if (selmon) {
    236 		pdrawbar(selmon);
    237 		focus(selmon->stack);
    238 	}
    239 }
    240 
    241 void
    242 showhide(Client *c)
    243 {
    244 	for (; c; c = c->snext) {
    245 		if (c->ishidden == !ISVISIBLE(c))
    246 			continue;
    247 		if (c->ishidden) {
    248 			configure(c, 0);
    249 		} else {
    250 			showhide(c->snext);
    251 			configure(c, 0);
    252 			return;
    253 		}
    254 	}
    255 }
    256 
    257 void
    258 restack(Monitor *m)
    259 {
    260 	XWindowChanges fwc, twc;
    261 	XWindowChanges *wc = NULL;
    262 	Client *c;
    263 
    264 	fwc.stack_mode = twc.stack_mode = Below;
    265 	fwc.sibling = None;
    266 	twc.sibling = m->barwin;
    267 	for (c = m->stack; c; c = c->snext) {
    268 		if (c->ishidden)
    269 			continue;
    270 		if (!c->isfullscreen && m->lyt && !c->isfloating) {
    271 			wc = &twc;
    272 		} else if (fwc.sibling != None) {
    273 			wc = &fwc;
    274 		} else {
    275 			XRaiseWindow(dpy, c->win);
    276 			fwc.sibling = c->win;
    277 			continue;
    278 		}
    279 		XConfigureWindow(dpy, c->win, CWSibling|CWStackMode, wc);
    280 		wc->sibling = c->win;
    281 	}
    282 }
    283 
    284 void
    285 arrange(Monitor *m)
    286 {
    287 	XEvent ev;
    288 
    289 	showhide(m->stack);
    290 	restack(m);
    291 	lyttile(m);
    292 	XSync(dpy, False);
    293 	while (XCheckMaskEvent(dpy, EnterWindowMask, &ev))
    294 		;
    295 }