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 }