swm

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

monitor.c (5097B)


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