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 }