Mercurial > hg > index.fcgi > dwm > dwm-3.6.1-10pba
diff client.c @ 0:7024076fa948
initial add
author | paulo@localhost |
---|---|
date | Sun, 22 Mar 2009 23:26:35 -0700 |
parents | |
children | a54de16f8277 |
line diff
1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/client.c Sun Mar 22 23:26:35 2009 -0700 1.3 @@ -0,0 +1,517 @@ 1.4 +/* (C)opyright MMVI-MMVII Anselm R. Garbe <garbeam at gmail dot com> 1.5 + * See LICENSE file for license details. 1.6 + */ 1.7 +#include "dwm.h" 1.8 +#include <stdio.h> 1.9 +#include <stdlib.h> 1.10 +#include <string.h> 1.11 +#include <X11/Xatom.h> 1.12 +#include <X11/Xutil.h> 1.13 + 1.14 +/* static */ 1.15 + 1.16 +static void 1.17 +attachstack(Client *c) { 1.18 + c->snext = stack; 1.19 + stack = c; 1.20 +} 1.21 + 1.22 +static void 1.23 +detachstack(Client *c) { 1.24 + Client **tc; 1.25 + 1.26 + for(tc=&stack; *tc && *tc != c; tc=&(*tc)->snext); 1.27 + *tc = c->snext; 1.28 +} 1.29 + 1.30 +static void 1.31 +grabbuttons(Client *c, Bool focused) { 1.32 + XUngrabButton(dpy, AnyButton, AnyModifier, c->win); 1.33 + 1.34 + if(focused) { 1.35 + XGrabButton(dpy, Button1, MODKEY, c->win, False, BUTTONMASK, 1.36 + GrabModeAsync, GrabModeSync, None, None); 1.37 + XGrabButton(dpy, Button1, MODKEY | LockMask, c->win, False, BUTTONMASK, 1.38 + GrabModeAsync, GrabModeSync, None, None); 1.39 + XGrabButton(dpy, Button1, MODKEY | numlockmask, c->win, False, BUTTONMASK, 1.40 + GrabModeAsync, GrabModeSync, None, None); 1.41 + XGrabButton(dpy, Button1, MODKEY | numlockmask | LockMask, c->win, False, BUTTONMASK, 1.42 + GrabModeAsync, GrabModeSync, None, None); 1.43 + 1.44 + XGrabButton(dpy, Button2, MODKEY, c->win, False, BUTTONMASK, 1.45 + GrabModeAsync, GrabModeSync, None, None); 1.46 + XGrabButton(dpy, Button2, MODKEY | LockMask, c->win, False, BUTTONMASK, 1.47 + GrabModeAsync, GrabModeSync, None, None); 1.48 + XGrabButton(dpy, Button2, MODKEY | numlockmask, c->win, False, BUTTONMASK, 1.49 + GrabModeAsync, GrabModeSync, None, None); 1.50 + XGrabButton(dpy, Button2, MODKEY | numlockmask | LockMask, c->win, False, BUTTONMASK, 1.51 + GrabModeAsync, GrabModeSync, None, None); 1.52 + 1.53 + XGrabButton(dpy, Button3, MODKEY, c->win, False, BUTTONMASK, 1.54 + GrabModeAsync, GrabModeSync, None, None); 1.55 + XGrabButton(dpy, Button3, MODKEY | LockMask, c->win, False, BUTTONMASK, 1.56 + GrabModeAsync, GrabModeSync, None, None); 1.57 + XGrabButton(dpy, Button3, MODKEY | numlockmask, c->win, False, BUTTONMASK, 1.58 + GrabModeAsync, GrabModeSync, None, None); 1.59 + XGrabButton(dpy, Button3, MODKEY | numlockmask | LockMask, c->win, False, BUTTONMASK, 1.60 + GrabModeAsync, GrabModeSync, None, None); 1.61 + } 1.62 + else 1.63 + XGrabButton(dpy, AnyButton, AnyModifier, c->win, False, BUTTONMASK, 1.64 + GrabModeAsync, GrabModeSync, None, None); 1.65 +} 1.66 + 1.67 +static Bool 1.68 +isprotodel(Client *c) { 1.69 + int i, n; 1.70 + Atom *protocols; 1.71 + Bool ret = False; 1.72 + 1.73 + if(XGetWMProtocols(dpy, c->win, &protocols, &n)) { 1.74 + for(i = 0; !ret && i < n; i++) 1.75 + if(protocols[i] == wmatom[WMDelete]) 1.76 + ret = True; 1.77 + XFree(protocols); 1.78 + } 1.79 + return ret; 1.80 +} 1.81 + 1.82 +static void 1.83 +setclientstate(Client *c, long state) { 1.84 + long data[] = {state, None}; 1.85 + 1.86 + XChangeProperty(dpy, c->win, wmatom[WMState], wmatom[WMState], 32, 1.87 + PropModeReplace, (unsigned char *)data, 2); 1.88 +} 1.89 + 1.90 +static void 1.91 +togglemax(Client *c) { 1.92 + XEvent ev; 1.93 + 1.94 + if(c->isfixed) 1.95 + return; 1.96 + if((c->ismax = !c->ismax)) { 1.97 + c->rx = c->x; 1.98 + c->ry = c->y; 1.99 + c->rw = c->w; 1.100 + c->rh = c->h; 1.101 + resize(c, wax, way, waw - 2 * BORDERPX, wah - 2 * BORDERPX, True); 1.102 + } 1.103 + else 1.104 + resize(c, c->rx, c->ry, c->rw, c->rh, True); 1.105 + while(XCheckMaskEvent(dpy, EnterWindowMask, &ev)); 1.106 +} 1.107 + 1.108 +static int 1.109 +xerrordummy(Display *dsply, XErrorEvent *ee) { 1.110 + return 0; 1.111 +} 1.112 + 1.113 +/* extern */ 1.114 + 1.115 +void 1.116 +attach(Client *c) { 1.117 + if(clients) 1.118 + clients->prev = c; 1.119 + c->next = clients; 1.120 + clients = c; 1.121 +} 1.122 + 1.123 +void 1.124 +configure(Client *c) { 1.125 + XConfigureEvent ce; 1.126 + 1.127 + ce.type = ConfigureNotify; 1.128 + ce.display = dpy; 1.129 + ce.event = c->win; 1.130 + ce.window = c->win; 1.131 + ce.x = c->x; 1.132 + ce.y = c->y; 1.133 + ce.width = c->w; 1.134 + ce.height = c->h; 1.135 + ce.border_width = c->border; 1.136 + ce.above = None; 1.137 + ce.override_redirect = False; 1.138 + XSendEvent(dpy, c->win, False, StructureNotifyMask, (XEvent *)&ce); 1.139 +} 1.140 + 1.141 +void 1.142 +detach(Client *c) { 1.143 + if(c->prev) 1.144 + c->prev->next = c->next; 1.145 + if(c->next) 1.146 + c->next->prev = c->prev; 1.147 + if(c == clients) 1.148 + clients = c->next; 1.149 + c->next = c->prev = NULL; 1.150 +} 1.151 + 1.152 +void 1.153 +focus(Client *c) { 1.154 + if(c && !isvisible(c)) 1.155 + return; 1.156 + if(sel && sel != c) { 1.157 + grabbuttons(sel, False); 1.158 + XSetWindowBorder(dpy, sel->win, dc.norm[ColBorder]); 1.159 + } 1.160 + if(c) { 1.161 + detachstack(c); 1.162 + attachstack(c); 1.163 + grabbuttons(c, True); 1.164 + } 1.165 + sel = c; 1.166 + drawstatus(); 1.167 + if(!selscreen) 1.168 + return; 1.169 + if(c) { 1.170 + XSetWindowBorder(dpy, c->win, dc.sel[ColBorder]); 1.171 + XSetInputFocus(dpy, c->win, RevertToPointerRoot, CurrentTime); 1.172 + } 1.173 + else 1.174 + XSetInputFocus(dpy, root, RevertToPointerRoot, CurrentTime); 1.175 +} 1.176 + 1.177 +void 1.178 +killclient(Arg *arg) { 1.179 + if(!sel) 1.180 + return; 1.181 + if(isprotodel(sel)) 1.182 + sendevent(sel->win, wmatom[WMProtocols], wmatom[WMDelete]); 1.183 + else 1.184 + XKillClient(dpy, sel->win); 1.185 +} 1.186 + 1.187 +void 1.188 +manage(Window w, XWindowAttributes *wa) { 1.189 + Client *c, *t; 1.190 + Window trans; 1.191 + XWindowChanges wc; 1.192 + 1.193 + c = emallocz(sizeof(Client)); 1.194 + c->tags = emallocz(ntags * sizeof(Bool)); 1.195 + c->win = w; 1.196 + c->x = wa->x; 1.197 + c->y = wa->y; 1.198 + c->w = wa->width; 1.199 + c->h = wa->height; 1.200 + if(c->w == sw && c->h == sh) { 1.201 + c->border = 0; 1.202 + c->x = sx; 1.203 + c->y = sy; 1.204 + } 1.205 + else { 1.206 + c->border = BORDERPX; 1.207 + if(c->x > wax + waw && c-> w < waw) 1.208 + c->x = wax + waw - c->w - 2 * c->border; 1.209 + if(c->y > way + wah && c-> h < wah) 1.210 + c->y = way + wah - c->h - 2 * c->border; 1.211 + if(c->x < wax && c->w < waw) 1.212 + c->x = wax; 1.213 + if(c->y < way && c->h < wah) 1.214 + c->y = way; 1.215 + } 1.216 + XSelectInput(dpy, w, 1.217 + StructureNotifyMask | PropertyChangeMask | EnterWindowMask); 1.218 + XGetTransientForHint(dpy, w, &trans); 1.219 + grabbuttons(c, False); 1.220 + wc.border_width = c->border; 1.221 + XConfigureWindow(dpy, w, CWBorderWidth, &wc); 1.222 + XSetWindowBorder(dpy, w, dc.norm[ColBorder]); 1.223 + configure(c); /* propagates border_width, if size doesn't change */ 1.224 + updatetitle(c); 1.225 + for(t = clients; t && t->win != trans; t = t->next); 1.226 + settags(c, t); 1.227 + if(!c->isversatile) 1.228 + c->isversatile = (t != NULL) || c->isfixed; 1.229 + attach(c); 1.230 + attachstack(c); 1.231 + c->isbanned = True; 1.232 + XMoveWindow(dpy, w, c->x + 2 * sw, c->y); 1.233 + XMapWindow(dpy, w); 1.234 + setclientstate(c, NormalState); 1.235 + if(isvisible(c)) 1.236 + focus(c); 1.237 + updatesizehints(c); 1.238 + lt->arrange(); 1.239 +} 1.240 + 1.241 +void 1.242 +resize(Client *c, int x, int y, int w, int h, Bool sizehints) { 1.243 + float actual, dx, dy, max, min; 1.244 + XWindowChanges wc; 1.245 + 1.246 + if(w <= 0 || h <= 0) 1.247 + return; 1.248 + if(sizehints) { 1.249 + if(c->minw && w < c->minw) 1.250 + w = c->minw; 1.251 + if(c->minh && h < c->minh) 1.252 + h = c->minh; 1.253 + if(c->maxw && w > c->maxw) 1.254 + w = c->maxw; 1.255 + if(c->maxh && h > c->maxh) 1.256 + h = c->maxh; 1.257 + /* inspired by algorithm from fluxbox */ 1.258 + if(c->minay > 0 && c->maxay && (h - c->baseh) > 0) { 1.259 + dx = (float)(w - c->basew); 1.260 + dy = (float)(h - c->baseh); 1.261 + min = (float)(c->minax) / (float)(c->minay); 1.262 + max = (float)(c->maxax) / (float)(c->maxay); 1.263 + actual = dx / dy; 1.264 + if(max > 0 && min > 0 && actual > 0) { 1.265 + if(actual < min) { 1.266 + dy = (dx * min + dy) / (min * min + 1); 1.267 + dx = dy * min; 1.268 + w = (int)dx + c->basew; 1.269 + h = (int)dy + c->baseh; 1.270 + } 1.271 + else if(actual > max) { 1.272 + dy = (dx * min + dy) / (max * max + 1); 1.273 + dx = dy * min; 1.274 + w = (int)dx + c->basew; 1.275 + h = (int)dy + c->baseh; 1.276 + } 1.277 + } 1.278 + } 1.279 + if(c->incw) 1.280 + w -= (w - c->basew) % c->incw; 1.281 + if(c->inch) 1.282 + h -= (h - c->baseh) % c->inch; 1.283 + } 1.284 + if(w == sw && h == sh) 1.285 + c->border = 0; 1.286 + else 1.287 + c->border = BORDERPX; 1.288 + /* offscreen appearance fixes */ 1.289 + if(x > sw) 1.290 + x = sw - w - 2 * c->border; 1.291 + if(y > sh) 1.292 + y = sh - h - 2 * c->border; 1.293 + if(x + w + 2 * c->border < sx) 1.294 + x = sx; 1.295 + if(y + h + 2 * c->border < sy) 1.296 + y = sy; 1.297 + /* if(c->x != x || c->y != y || c->w != w || c->h != h) { */ 1.298 + c->x = wc.x = x; 1.299 + c->y = wc.y = y; 1.300 + c->w = wc.width = w; 1.301 + c->h = wc.height = h; 1.302 + wc.border_width = c->border; 1.303 + XConfigureWindow(dpy, c->win, CWX | CWY | CWWidth | CWHeight | CWBorderWidth, &wc); 1.304 + configure(c); 1.305 + XSync(dpy, False); 1.306 + /* } */ 1.307 +} 1.308 + 1.309 +void 1.310 +toggleversatile(Arg *arg) { 1.311 + if(!sel || lt->arrange == versatile) 1.312 + return; 1.313 + sel->isversatile = !sel->isversatile; 1.314 + lt->arrange(); 1.315 +} 1.316 + 1.317 +void 1.318 +updatesizehints(Client *c) { 1.319 + long msize; 1.320 + XSizeHints size; 1.321 + 1.322 + if(!XGetWMNormalHints(dpy, c->win, &size, &msize) || !size.flags) 1.323 + size.flags = PSize; 1.324 + c->flags = size.flags; 1.325 + if(c->flags & PBaseSize) { 1.326 + c->basew = size.base_width; 1.327 + c->baseh = size.base_height; 1.328 + } 1.329 + else 1.330 + c->basew = c->baseh = 0; 1.331 + if(c->flags & PResizeInc) { 1.332 + c->incw = size.width_inc; 1.333 + c->inch = size.height_inc; 1.334 + } 1.335 + else 1.336 + c->incw = c->inch = 0; 1.337 + if(c->flags & PMaxSize) { 1.338 + c->maxw = size.max_width; 1.339 + c->maxh = size.max_height; 1.340 + } 1.341 + else 1.342 + c->maxw = c->maxh = 0; 1.343 + if(c->flags & PMinSize) { 1.344 + c->minw = size.min_width; 1.345 + c->minh = size.min_height; 1.346 + } 1.347 + else 1.348 + c->minw = c->minh = 0; 1.349 + if(c->flags & PAspect) { 1.350 + c->minax = size.min_aspect.x; 1.351 + c->minay = size.min_aspect.y; 1.352 + c->maxax = size.max_aspect.x; 1.353 + c->maxay = size.max_aspect.y; 1.354 + } 1.355 + else 1.356 + c->minax = c->minay = c->maxax = c->maxay = 0; 1.357 + c->isfixed = (c->maxw && c->minw && c->maxh && c->minh 1.358 + && c->maxw == c->minw && c->maxh == c->minh); 1.359 +} 1.360 + 1.361 +void 1.362 +updatetitle(Client *c) { 1.363 + char **list = NULL; 1.364 + int n; 1.365 + XTextProperty name; 1.366 + 1.367 + name.nitems = 0; 1.368 + c->name[0] = 0; 1.369 + XGetTextProperty(dpy, c->win, &name, netatom[NetWMName]); 1.370 + if(!name.nitems) 1.371 + XGetWMName(dpy, c->win, &name); 1.372 + if(!name.nitems) 1.373 + return; 1.374 + if(name.encoding == XA_STRING) 1.375 + strncpy(c->name, (char *)name.value, sizeof c->name); 1.376 + else { 1.377 + if(XmbTextPropertyToTextList(dpy, &name, &list, &n) >= Success 1.378 + && n > 0 && *list) 1.379 + { 1.380 + strncpy(c->name, *list, sizeof c->name); 1.381 + XFreeStringList(list); 1.382 + } 1.383 + } 1.384 + XFree(name.value); 1.385 +} 1.386 + 1.387 +void 1.388 +unmanage(Client *c) { 1.389 + Client *nc; 1.390 + 1.391 + /* The server grab construct avoids race conditions. */ 1.392 + XGrabServer(dpy); 1.393 + XSetErrorHandler(xerrordummy); 1.394 + detach(c); 1.395 + detachstack(c); 1.396 + if(sel == c) { 1.397 + for(nc = stack; nc && !isvisible(nc); nc = nc->snext); 1.398 + focus(nc); 1.399 + } 1.400 + XUngrabButton(dpy, AnyButton, AnyModifier, c->win); 1.401 + setclientstate(c, WithdrawnState); 1.402 + free(c->tags); 1.403 + free(c); 1.404 + XSync(dpy, False); 1.405 + XSetErrorHandler(xerror); 1.406 + XUngrabServer(dpy); 1.407 + lt->arrange(); 1.408 +} 1.409 + 1.410 +void 1.411 +zoom(Arg *arg) { 1.412 + unsigned int n; 1.413 + Client *c; 1.414 + 1.415 + if(!sel) 1.416 + return; 1.417 + if(sel->isversatile || (lt->arrange == versatile)) { 1.418 + togglemax(sel); 1.419 + return; 1.420 + } 1.421 + for(n = 0, c = nexttiled(clients); c; c = nexttiled(c->next)) 1.422 + n++; 1.423 + if((c = sel) == nexttiled(clients)) 1.424 + if(!(c = nexttiled(c->next))) 1.425 + return; 1.426 + detach(c); 1.427 + attach(c); 1.428 + focus(c); 1.429 + lt->arrange(); 1.430 +} 1.431 + 1.432 +Client * 1.433 +prevtiled(Client *c) { 1.434 + for(; c && (c->isversatile || !isvisible(c)); c = c->prev); 1.435 + return c; 1.436 +} 1.437 + 1.438 +void 1.439 +pushup(Arg *arg) { 1.440 + Client *c; 1.441 + 1.442 + if(!sel || sel->isversatile) 1.443 + return; 1.444 + if((c = prevtiled(sel->prev))) { 1.445 + /* attach before c */ 1.446 + detach(sel); 1.447 + sel->next = c; 1.448 + sel->prev = c->prev; 1.449 + c->prev = sel; 1.450 + if(sel->prev) 1.451 + sel->prev->next = sel; 1.452 + else 1.453 + clients = sel; 1.454 + } else { 1.455 + /* move to the end */ 1.456 + for(c = sel; c->next; c = c->next); 1.457 + detach(sel); 1.458 + sel->prev = c; 1.459 + c->next = sel; 1.460 + } 1.461 + focus(sel); 1.462 + lt->arrange(); 1.463 +} 1.464 + 1.465 +void 1.466 +pushdown(Arg *arg) { 1.467 + Client *c; 1.468 + 1.469 + if(!sel || sel->isversatile) 1.470 + return; 1.471 + if((c = nexttiled(sel->next))) { 1.472 + /* attach after c */ 1.473 + detach(sel); 1.474 + sel->prev = c; 1.475 + sel->next = c->next; 1.476 + c->next = sel; 1.477 + if(sel->next) 1.478 + sel->next->prev = sel; 1.479 + } else { 1.480 + /* move to the front */ 1.481 + detach(sel); 1.482 + attach(sel); 1.483 + } 1.484 + focus(sel); 1.485 + lt->arrange(); 1.486 +} 1.487 + 1.488 +void 1.489 +moveresize(Arg *arg) { 1.490 + int x, y, w, h, nx, ny, nw, nh, ox, oy, ow, oh; 1.491 + char xAbs, yAbs, wAbs, hAbs; 1.492 + int mx, my, dx, dy, nmx, nmy; 1.493 + unsigned int dui; 1.494 + Window dummy; 1.495 + 1.496 + if (lt->arrange != versatile) 1.497 + if (!sel || !sel->isversatile || !arg) 1.498 + return; 1.499 + if(sscanf(arg->cmd, "%d%c %d%c %d%c %d%c", &x, &xAbs, &y, &yAbs, &w, &wAbs, &h, &hAbs) != 8) 1.500 + return; 1.501 + nx = xAbs == 'X' ? x : sel->x + x; 1.502 + ny = yAbs == 'Y' ? y : sel->y + y; 1.503 + nw = wAbs == 'W' ? w : sel->w + w; 1.504 + nh = hAbs == 'H' ? h : sel->h + h; 1.505 + 1.506 + ox = sel->x; 1.507 + oy = sel->y; 1.508 + ow = sel->w; 1.509 + oh = sel->h; 1.510 + 1.511 + Bool xqp = XQueryPointer(dpy, root, &dummy, &dummy, &mx, &my, &dx, &dy, &dui); 1.512 + resize(sel, nx, ny, nw, nh, True); 1.513 + if (xqp && ox <= mx && (ox + ow) >= mx && oy <= my && (oy + oh) >= my) 1.514 + { 1.515 + nmx = mx-ox+sel->w-ow-1 < 0 ? 0 : mx-ox+sel->w-ow-1; 1.516 + nmy = my-oy+sel->h-oh-1 < 0 ? 0 : my-oy+sel->h-oh-1; 1.517 + XWarpPointer(dpy, None, sel->win, 0, 0, 0, 0, nmx, nmy); 1.518 + } 1.519 +} 1.520 +