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 }