aewl

annotate client.c @ 29:8ad86d0a6a53

added gravity stuff
author Anselm R. Garbe <garbeam@wmii.de>
date Wed, 12 Jul 2006 17:17:15 +0200
parents 3dceb132082d
children 2e0fb4130bfb
rev   line source
garbeam@5 1 /*
garbeam@5 2 * (C)opyright MMVI Anselm R. Garbe <garbeam at gmail dot com>
garbeam@5 3 * See LICENSE file for license details.
garbeam@5 4 */
garbeam@5 5
garbeam@27 6 #include <math.h>
garbeam@10 7 #include <stdlib.h>
garbeam@5 8 #include <string.h>
garbeam@5 9 #include <X11/Xatom.h>
garbeam@5 10
garbeam@5 11 #include "util.h"
garbeam@5 12 #include "wm.h"
garbeam@5 13
garbeam@27 14 void
garbeam@28 15 max(void *aux)
garbeam@28 16 {
garbeam@28 17 if(!stack)
garbeam@28 18 return;
garbeam@28 19 stack->x = sx;
garbeam@28 20 stack->y = bh;
garbeam@29 21 stack->w = sw - 2 * stack->border;
garbeam@29 22 stack->h = sh - bh - 2 * stack->border;
garbeam@28 23 resize(stack);
garbeam@29 24 discard_events(EnterWindowMask);
garbeam@28 25 }
garbeam@28 26
garbeam@28 27 void
garbeam@27 28 arrange(void *aux)
garbeam@27 29 {
garbeam@27 30 Client *c;
garbeam@27 31 int n, cols, rows, gw, gh, i, j;
garbeam@27 32 float rt, fd;
garbeam@27 33
garbeam@27 34 if(!clients)
garbeam@27 35 return;
garbeam@27 36 for(n = 0, c = clients; c; c = c->next, n++);
garbeam@27 37 rt = sqrt(n);
garbeam@27 38 if(modff(rt, &fd) < 0.5)
garbeam@27 39 rows = floor(rt);
garbeam@27 40 else
garbeam@27 41 rows = ceil(rt);
garbeam@27 42 if(rows * rows < n)
garbeam@27 43 cols = rows + 1;
garbeam@27 44 else
garbeam@27 45 cols = rows;
garbeam@27 46
garbeam@29 47 gw = (sw - 2 * c->border) / cols;
garbeam@29 48 gh = (sh - bh - 2 * c->border) / rows;
garbeam@27 49
garbeam@27 50 for(i = j = 0, c = clients; c; c = c->next) {
garbeam@27 51 c->x = i * gw;
garbeam@27 52 c->y = j * gh + bh;
garbeam@27 53 c->w = gw;
garbeam@27 54 c->h = gh;
garbeam@27 55 resize(c);
garbeam@27 56 if(++i == cols) {
garbeam@27 57 j++;
garbeam@27 58 i = 0;
garbeam@27 59 }
garbeam@27 60 }
garbeam@29 61 discard_events(EnterWindowMask);
garbeam@27 62 }
garbeam@27 63
garbeam@27 64 void
garbeam@27 65 sel(void *aux)
garbeam@27 66 {
garbeam@27 67 const char *arg = aux;
garbeam@27 68 Client *c = NULL;
garbeam@27 69
garbeam@27 70 if(!arg || !stack)
garbeam@27 71 return;
garbeam@27 72 if(!strncmp(arg, "next", 5))
garbeam@27 73 c = stack->snext ? stack->snext : stack;
garbeam@27 74 else if(!strncmp(arg, "prev", 5))
garbeam@27 75 for(c = stack; c && c->snext; c = c->snext);
garbeam@27 76 if(!c)
garbeam@27 77 c = stack;
garbeam@27 78 raise(c);
garbeam@27 79 focus(c);
garbeam@27 80 }
garbeam@27 81
garbeam@27 82 void
garbeam@27 83 kill(void *aux)
garbeam@27 84 {
garbeam@27 85 Client *c = stack;
garbeam@27 86
garbeam@27 87 if(!c)
garbeam@27 88 return;
garbeam@27 89 if(c->proto & WM_PROTOCOL_DELWIN)
garbeam@27 90 send_message(c->win, wm_atom[WMProtocols], wm_atom[WMDelete]);
garbeam@27 91 else
garbeam@27 92 XKillClient(dpy, c->win);
garbeam@27 93 }
garbeam@27 94
garbeam@26 95 static void
garbeam@26 96 resize_title(Client *c)
garbeam@26 97 {
garbeam@26 98 c->tw = textw(&brush.font, c->name) + bh;
garbeam@26 99 if(c->tw > c->w)
garbeam@26 100 c->tw = c->w + 2;
garbeam@26 101 c->tx = c->x + c->w - c->tw + 2;
garbeam@26 102 c->ty = c->y;
garbeam@26 103 XMoveResizeWindow(dpy, c->title, c->tx, c->ty, c->tw, c->th);
garbeam@26 104 }
garbeam@18 105
garbeam@13 106 void
garbeam@13 107 update_name(Client *c)
garbeam@5 108 {
garbeam@5 109 XTextProperty name;
garbeam@5 110 int n;
garbeam@7 111 char **list = NULL;
garbeam@5 112
garbeam@5 113 name.nitems = 0;
garbeam@5 114 c->name[0] = 0;
garbeam@5 115 XGetTextProperty(dpy, c->win, &name, net_atom[NetWMName]);
garbeam@5 116 if(!name.nitems)
garbeam@5 117 XGetWMName(dpy, c->win, &name);
garbeam@5 118 if(!name.nitems)
garbeam@5 119 return;
garbeam@5 120 if(name.encoding == XA_STRING)
garbeam@5 121 strncpy(c->name, (char *)name.value, sizeof(c->name));
garbeam@5 122 else {
garbeam@5 123 if(XmbTextPropertyToTextList(dpy, &name, &list, &n) >= Success
garbeam@5 124 && n > 0 && *list)
garbeam@5 125 {
garbeam@5 126 strncpy(c->name, *list, sizeof(c->name));
garbeam@5 127 XFreeStringList(list);
garbeam@5 128 }
garbeam@5 129 }
garbeam@5 130 XFree(name.value);
garbeam@26 131 resize_title(c);
garbeam@5 132 }
garbeam@5 133
garbeam@10 134 void
garbeam@20 135 update_size(Client *c)
garbeam@20 136 {
garbeam@20 137 XSizeHints size;
garbeam@20 138 long msize;
garbeam@20 139 if(!XGetWMNormalHints(dpy, c->win, &size, &msize) || !size.flags)
garbeam@20 140 size.flags = PSize;
garbeam@20 141 c->flags = size.flags;
garbeam@21 142 if(c->flags & PBaseSize) {
garbeam@21 143 c->basew = size.base_width;
garbeam@21 144 c->baseh = size.base_height;
garbeam@21 145 }
garbeam@21 146 else
garbeam@21 147 c->basew = c->baseh = 0;
garbeam@21 148 if(c->flags & PResizeInc) {
garbeam@21 149 c->incw = size.width_inc;
garbeam@21 150 c->inch = size.height_inc;
garbeam@21 151 }
garbeam@21 152 else
garbeam@21 153 c->incw = c->inch = 0;
garbeam@21 154 if(c->flags & PMaxSize) {
garbeam@21 155 c->maxw = size.max_width;
garbeam@21 156 c->maxh = size.max_height;
garbeam@21 157 }
garbeam@21 158 else
garbeam@21 159 c->maxw = c->maxh = 0;
garbeam@21 160 if(c->flags & PMinSize) {
garbeam@21 161 c->minw = size.min_width;
garbeam@21 162 c->minh = size.min_height;
garbeam@21 163 }
garbeam@21 164 else
garbeam@21 165 c->minw = c->minh = 0;
garbeam@29 166 if(c->flags & PWinGravity)
garbeam@29 167 c->grav = size.win_gravity;
garbeam@29 168 else
garbeam@29 169 c->grav = NorthWestGravity;
garbeam@20 170 }
garbeam@20 171
garbeam@20 172 void
garbeam@26 173 raise(Client *c)
garbeam@26 174 {
garbeam@26 175 XRaiseWindow(dpy, c->win);
garbeam@26 176 XRaiseWindow(dpy, c->title);
garbeam@26 177 }
garbeam@26 178
garbeam@26 179 void
garbeam@26 180 lower(Client *c)
garbeam@26 181 {
garbeam@26 182 XLowerWindow(dpy, c->title);
garbeam@26 183 XLowerWindow(dpy, c->win);
garbeam@26 184 }
garbeam@26 185
garbeam@26 186 void
garbeam@13 187 focus(Client *c)
garbeam@13 188 {
garbeam@21 189 Client **l, *old;
garbeam@21 190
garbeam@21 191 old = stack;
garbeam@26 192 for(l = &stack; *l && *l != c; l = &(*l)->snext);
garbeam@13 193 eassert(*l == c);
garbeam@13 194 *l = c->snext;
garbeam@13 195 c->snext = stack;
garbeam@13 196 stack = c;
garbeam@21 197 if(old && old != c) {
garbeam@21 198 XMapWindow(dpy, old->title);
garbeam@21 199 draw_client(old);
garbeam@21 200 }
garbeam@21 201 XUnmapWindow(dpy, c->title);
garbeam@27 202 draw_client(c);
garbeam@26 203 XSetInputFocus(dpy, c->win, RevertToPointerRoot, CurrentTime);
garbeam@13 204 XFlush(dpy);
garbeam@13 205 }
garbeam@13 206
garbeam@13 207 void
garbeam@10 208 manage(Window w, XWindowAttributes *wa)
garbeam@5 209 {
garbeam@10 210 Client *c, **l;
garbeam@5 211 XSetWindowAttributes twa;
garbeam@5 212
garbeam@5 213 c = emallocz(sizeof(Client));
garbeam@5 214 c->win = w;
garbeam@22 215 c->tx = c->x = wa->x;
garbeam@22 216 c->ty = c->y = wa->y;
garbeam@26 217 if(c->y < bh)
garbeam@26 218 c->ty = c->y += bh;
garbeam@22 219 c->tw = c->w = wa->width;
garbeam@20 220 c->h = wa->height;
garbeam@26 221 c->th = bh;
garbeam@29 222 c->border = 1;
garbeam@20 223 update_size(c);
garbeam@19 224 XSetWindowBorderWidth(dpy, c->win, 1);
garbeam@22 225 XSetWindowBorder(dpy, c->win, brush.border);
garbeam@26 226 XSelectInput(dpy, c->win,
garbeam@26 227 StructureNotifyMask | PropertyChangeMask | EnterWindowMask);
garbeam@5 228 XGetTransientForHint(dpy, c->win, &c->trans);
garbeam@5 229 twa.override_redirect = 1;
garbeam@5 230 twa.background_pixmap = ParentRelative;
garbeam@23 231 twa.event_mask = ExposureMask;
garbeam@5 232
garbeam@22 233 c->title = XCreateWindow(dpy, root, c->tx, c->ty, c->tw, c->th,
garbeam@20 234 0, DefaultDepth(dpy, screen), CopyFromParent,
garbeam@5 235 DefaultVisual(dpy, screen),
garbeam@5 236 CWOverrideRedirect | CWBackPixmap | CWEventMask, &twa);
garbeam@21 237 update_name(c);
garbeam@5 238
garbeam@10 239 for(l=&clients; *l; l=&(*l)->next);
garbeam@10 240 c->next = *l; /* *l == nil */
garbeam@10 241 *l = c;
garbeam@13 242 c->snext = stack;
garbeam@13 243 stack = c;
garbeam@26 244 XMapRaised(dpy, c->win);
garbeam@26 245 XMapRaised(dpy, c->title);
garbeam@19 246 XGrabButton(dpy, Button1, Mod1Mask, c->win, False, ButtonPressMask,
garbeam@19 247 GrabModeAsync, GrabModeSync, None, None);
garbeam@19 248 XGrabButton(dpy, Button2, Mod1Mask, c->win, False, ButtonPressMask,
garbeam@19 249 GrabModeAsync, GrabModeSync, None, None);
garbeam@19 250 XGrabButton(dpy, Button3, Mod1Mask, c->win, False, ButtonPressMask,
garbeam@18 251 GrabModeAsync, GrabModeSync, None, None);
garbeam@21 252 resize(c);
garbeam@13 253 focus(c);
garbeam@5 254 }
garbeam@9 255
garbeam@18 256 void
garbeam@29 257 gravitate(Client *c, Bool invert)
garbeam@29 258 {
garbeam@29 259 int dx = 0, dy = 0;
garbeam@29 260
garbeam@29 261 switch(c->grav) {
garbeam@29 262 case StaticGravity:
garbeam@29 263 case NorthWestGravity:
garbeam@29 264 case NorthGravity:
garbeam@29 265 case NorthEastGravity:
garbeam@29 266 dy = c->border;
garbeam@29 267 break;
garbeam@29 268 case EastGravity:
garbeam@29 269 case CenterGravity:
garbeam@29 270 case WestGravity:
garbeam@29 271 dy = -(c->h / 2) + c->border;
garbeam@29 272 break;
garbeam@29 273 case SouthEastGravity:
garbeam@29 274 case SouthGravity:
garbeam@29 275 case SouthWestGravity:
garbeam@29 276 dy = -c->h;
garbeam@29 277 break;
garbeam@29 278 default:
garbeam@29 279 break;
garbeam@29 280 }
garbeam@29 281
garbeam@29 282 switch (c->grav) {
garbeam@29 283 case StaticGravity:
garbeam@29 284 case NorthWestGravity:
garbeam@29 285 case WestGravity:
garbeam@29 286 case SouthWestGravity:
garbeam@29 287 dx = c->border;
garbeam@29 288 break;
garbeam@29 289 case NorthGravity:
garbeam@29 290 case CenterGravity:
garbeam@29 291 case SouthGravity:
garbeam@29 292 dx = -(c->w / 2) + c->border;
garbeam@29 293 break;
garbeam@29 294 case NorthEastGravity:
garbeam@29 295 case EastGravity:
garbeam@29 296 case SouthEastGravity:
garbeam@29 297 dx = -(c->w + c->border);
garbeam@29 298 break;
garbeam@29 299 default:
garbeam@29 300 break;
garbeam@29 301 }
garbeam@29 302
garbeam@29 303 if(invert) {
garbeam@29 304 dx = -dx;
garbeam@29 305 dy = -dy;
garbeam@29 306 }
garbeam@29 307 c->x += dx;
garbeam@29 308 c->y += dy;
garbeam@29 309 }
garbeam@29 310
garbeam@29 311 void
garbeam@18 312 resize(Client *c)
garbeam@18 313 {
garbeam@18 314 XConfigureEvent e;
garbeam@18 315
garbeam@26 316 resize_title(c);
garbeam@20 317 XMoveResizeWindow(dpy, c->win, c->x, c->y, c->w, c->h);
garbeam@18 318 e.type = ConfigureNotify;
garbeam@18 319 e.event = c->win;
garbeam@18 320 e.window = c->win;
garbeam@20 321 e.x = c->x;
garbeam@20 322 e.y = c->y;
garbeam@20 323 e.width = c->w;
garbeam@20 324 e.height = c->h;
garbeam@29 325 e.border_width = c->border;
garbeam@18 326 e.above = None;
garbeam@18 327 e.override_redirect = False;
garbeam@18 328 XSendEvent(dpy, c->win, False, StructureNotifyMask, (XEvent *)&e);
garbeam@18 329 XFlush(dpy);
garbeam@18 330 }
garbeam@18 331
garbeam@10 332 static int
garbeam@10 333 dummy_error_handler(Display *dpy, XErrorEvent *error)
garbeam@10 334 {
garbeam@10 335 return 0;
garbeam@10 336 }
garbeam@10 337
garbeam@10 338 void
garbeam@10 339 unmanage(Client *c)
garbeam@10 340 {
garbeam@10 341 Client **l;
garbeam@10 342
garbeam@10 343 XGrabServer(dpy);
garbeam@10 344 XSetErrorHandler(dummy_error_handler);
garbeam@10 345
garbeam@18 346 XUngrabButton(dpy, AnyButton, AnyModifier, c->win);
garbeam@10 347 XDestroyWindow(dpy, c->title);
garbeam@10 348
garbeam@10 349 for(l=&clients; *l && *l != c; l=&(*l)->next);
garbeam@10 350 eassert(*l == c);
garbeam@10 351 *l = c->next;
garbeam@13 352 for(l=&stack; *l && *l != c; l=&(*l)->snext);
garbeam@13 353 eassert(*l == c);
garbeam@13 354 *l = c->snext;
garbeam@10 355 free(c);
garbeam@10 356
garbeam@10 357 XFlush(dpy);
garbeam@10 358 XSetErrorHandler(error_handler);
garbeam@10 359 XUngrabServer(dpy);
garbeam@14 360 if(stack)
garbeam@14 361 focus(stack);
garbeam@10 362 }
garbeam@10 363
garbeam@23 364 Client *
garbeam@23 365 gettitle(Window w)
garbeam@23 366 {
garbeam@23 367 Client *c;
garbeam@23 368 for(c = clients; c; c = c->next)
garbeam@23 369 if(c->title == w)
garbeam@23 370 return c;
garbeam@23 371 return NULL;
garbeam@23 372 }
garbeam@10 373
garbeam@9 374 Client *
garbeam@9 375 getclient(Window w)
garbeam@9 376 {
garbeam@9 377 Client *c;
garbeam@9 378 for(c = clients; c; c = c->next)
garbeam@9 379 if(c->win == w)
garbeam@9 380 return c;
garbeam@9 381 return NULL;
garbeam@9 382 }
garbeam@13 383
garbeam@14 384 void
garbeam@14 385 draw_client(Client *c)
garbeam@14 386 {
garbeam@26 387 if(c == stack) {
garbeam@21 388 draw_bar();
garbeam@26 389 return;
garbeam@26 390 }
garbeam@14 391
garbeam@26 392 brush.x = brush.y = 0;
garbeam@26 393 brush.w = c->tw;
garbeam@26 394 brush.h = c->th;
garbeam@14 395
garbeam@21 396 draw(dpy, &brush, True, c->name);
garbeam@22 397 XCopyArea(dpy, brush.drawable, c->title, brush.gc,
garbeam@22 398 0, 0, c->tw, c->th, 0, 0);
garbeam@21 399 XFlush(dpy);
garbeam@14 400 }