view.c (4938B)
1 /* (C)opyright MMVI-MMVII Anselm R. Garbe <garbeam at gmail dot com> 2 * See LICENSE file for license details. 3 */ 4 #include "2wm.h" 5 #include <regex.h> 6 #include <stdio.h> 7 #include <stdlib.h> 8 #include <string.h> 9 #include <sys/types.h> 10 #include <X11/Xutil.h> 11 12 13 typedef struct { regex_t *regex; } RReg; 14 15 /* static */ 16 17 FLOATS 18 19 static RReg *rreg = NULL; 20 static unsigned int reglen = 0; 21 22 static Client * 23 getnext(Client *c) { 24 for(; c && c->view != view; c = c->next); 25 return c; 26 } 27 28 static Client * 29 getprev(Client *c) { 30 for(; c && c->view != view; c = c->prev); 31 return c; 32 } 33 34 static Client * 35 nexttiled(Client *c) { 36 for(c = getnext(c); c && c->isfloat; c = getnext(c->next)); 37 return c; 38 } 39 40 static void 41 pop(Client *c) { 42 detachclient(c); 43 if(clients) 44 clients->prev = c; 45 c->next = clients; 46 clients = c; 47 } 48 49 static void 50 togglemax(Client *c) { 51 XEvent ev; 52 53 if(c->isfixed) 54 return; 55 56 if((c->ismax = !c->ismax)) { 57 c->rx = c->x; c->x = sx; 58 c->ry = c->y; c->y = sy; 59 c->rw = c->w; c->w = sw - 2 * BORDERPX; 60 c->rh = c->h; c->h = sh - 2 * BORDERPX; 61 } 62 else { 63 c->x = c->rx; 64 c->y = c->ry; 65 c->w = c->rw; 66 c->h = c->rh; 67 } 68 resize(c, True); 69 while(XCheckMaskEvent(dpy, EnterWindowMask, &ev)); 70 } 71 72 /* extern */ 73 74 void 75 arrange(void) { 76 unsigned int i, n, mw, mh, tw, th; 77 Client *c; 78 79 for(n = 0, c = nexttiled(clients); c; c = nexttiled(c->next)) 80 n++; 81 /* window geoms */ 82 mh = (n > nmaster) ? sh / nmaster : sh / (n > 0 ? n : 1); 83 mw = (n > nmaster) ? (sw * master) / 1000 : sw; 84 th = (n > nmaster) ? sh / (n - nmaster) : 0; 85 tw = sw - mw; 86 87 for(i = 0, c = clients; c; c = c->next) 88 if(c->view == view) { 89 if(c->isfloat) { 90 resize(c, True); 91 continue; 92 } 93 c->ismax = False; 94 c->x = sx; 95 c->y = sy; 96 if(i < nmaster) { 97 c->y += i * mh; 98 c->w = mw - 2 * BORDERPX; 99 c->h = mh - 2 * BORDERPX; 100 } 101 else { /* tile window */ 102 c->x += mw; 103 c->w = tw - 2 * BORDERPX; 104 if(th > 2 * BORDERPX) { 105 c->y += (i - nmaster) * th; 106 c->h = th - 2 * BORDERPX; 107 } 108 else /* fallback if th <= 2 * BORDERPX */ 109 c->h = sh - 2 * BORDERPX; 110 } 111 resize(c, False); 112 i++; 113 } 114 else 115 XMoveWindow(dpy, c->win, c->x + 2 * sw, c->y); 116 if(!sel || sel->view != view) { 117 for(c = stack; c && c->view != view; c = c->snext); 118 focus(c); 119 } 120 restack(); 121 } 122 123 void 124 attach(Arg *arg) { 125 Client *c; 126 127 for(c = clients; c && c->view == view; c = c->next); 128 if(!c) 129 return; 130 c->view = !c->view; 131 pop(c); 132 focus(c); 133 arrange(); 134 } 135 136 void 137 detach(Arg *arg) { 138 if(!sel) 139 return; 140 sel->view = !sel->view; 141 pop(sel); 142 arrange(); 143 } 144 145 void 146 focusnext(Arg *arg) { 147 Client *c; 148 149 if(!sel) 150 return; 151 if(!(c = getnext(sel->next))) 152 c = getnext(clients); 153 if(c) { 154 focus(c); 155 restack(); 156 } 157 } 158 159 void 160 focusprev(Arg *arg) { 161 Client *c; 162 163 if(!sel) 164 return; 165 if(!(c = getprev(sel->prev))) { 166 for(c = clients; c && c->next; c = c->next); 167 c = getprev(c); 168 } 169 if(c) { 170 focus(c); 171 restack(); 172 } 173 } 174 175 void 176 incnmaster(Arg *arg) { 177 if((nmaster + arg->i < 1) || (sh / (nmaster + arg->i) <= 2 * BORDERPX)) 178 return; 179 nmaster += arg->i; 180 if(sel) 181 arrange(); 182 } 183 184 void 185 initrregs(void) { 186 unsigned int i; 187 regex_t *reg; 188 189 if(rreg) 190 return; 191 for(reglen = 0; floats[reglen]; reglen++); 192 rreg = emallocz(reglen * sizeof(RReg)); 193 for(i = 0; i < reglen; i++) 194 if(floats[i]) { 195 reg = emallocz(sizeof(regex_t)); 196 if(regcomp(reg, floats[i], REG_EXTENDED)) 197 free(reg); 198 else 199 rreg[i].regex = reg; 200 } 201 } 202 203 Bool 204 isfloat(Client *c) { 205 char prop[512]; 206 unsigned int i; 207 regmatch_t tmp; 208 Bool ret = False; 209 XClassHint ch = { 0 }; 210 211 XGetClassHint(dpy, c->win, &ch); 212 snprintf(prop, sizeof prop, "%s:%s:%s", 213 ch.res_class ? ch.res_class : "", 214 ch.res_name ? ch.res_name : "", c->name); 215 for(i = 0; i < reglen; i++) 216 if(rreg[i].regex && !regexec(rreg[i].regex, prop, 1, &tmp, 0)) { 217 ret = True; 218 break; 219 } 220 if(ch.res_class) 221 XFree(ch.res_class); 222 if(ch.res_name) 223 XFree(ch.res_name); 224 return ret; 225 } 226 227 void 228 resizemaster(Arg *arg) { 229 if(arg->i == 0) 230 master = MASTER; 231 else { 232 if(sw * (master + arg->i) / 1000 >= sw - 2 * BORDERPX 233 || sw * (master + arg->i) / 1000 <= 2 * BORDERPX) 234 return; 235 master += arg->i; 236 } 237 arrange(); 238 } 239 240 void 241 restack(void) { 242 Client *c; 243 XEvent ev; 244 245 if(!sel) 246 return; 247 if(sel->isfloat) 248 XRaiseWindow(dpy, sel->win); 249 else 250 XLowerWindow(dpy, sel->win); 251 for(c = nexttiled(clients); c; c = nexttiled(c->next)) { 252 if(c == sel) 253 continue; 254 XLowerWindow(dpy, c->win); 255 } 256 XSync(dpy, False); 257 while(XCheckMaskEvent(dpy, EnterWindowMask, &ev)); 258 } 259 260 void 261 togglefloat(Arg *arg) { 262 if(!sel) 263 return; 264 sel->isfloat = !sel->isfloat; 265 arrange(); 266 } 267 268 void 269 toggleview(Arg *arg) { 270 view = !view; 271 arrange(); 272 } 273 274 void 275 zoom(Arg *arg) { 276 unsigned int n; 277 Client *c; 278 279 if(!sel) 280 return; 281 if(sel->isfloat) { 282 togglemax(sel); 283 return; 284 } 285 for(n = 0, c = nexttiled(clients); c; c = nexttiled(c->next)) 286 n++; 287 288 if((c = sel) == nexttiled(clients)) 289 if(!(c = nexttiled(c->next))) 290 return; 291 pop(c); 292 focus(c); 293 arrange(); 294 }