dwm-meillo

annotate client.c @ 541:08d3d329270a

using MASTER 600 again, it is definately better, and using urxvtc for the moment (it doesn't flickers on refreshes, but this is not because of Marc Lehmann, it is because of the original rxvt code)
author arg@mig29
date Thu, 26 Oct 2006 12:13:41 +0200
parents 651f2c868b31
children 722cffee3770
rev   line source
arg@532 1 /* (C)opyright MMVI Anselm R. Garbe <garbeam at gmail dot com>
garbeam@5 2 * See LICENSE file for license details.
garbeam@5 3 */
garbeam@76 4 #include "dwm.h"
garbeam@10 5 #include <stdlib.h>
garbeam@5 6 #include <string.h>
garbeam@5 7 #include <X11/Xatom.h>
garbeam@32 8 #include <X11/Xutil.h>
garbeam@5 9
garbeam@76 10 /* static functions */
garbeam@50 11
garbeam@26 12 static void
arg@461 13 detachstack(Client *c) {
arg@446 14 Client **tc;
arg@446 15 for(tc=&stack; *tc && *tc != c; tc=&(*tc)->snext);
arg@446 16 *tc = c->snext;
arg@446 17 }
arg@446 18
arg@446 19 static void
arg@461 20 grabbuttons(Client *c, Bool focused) {
arg@372 21 XUngrabButton(dpy, AnyButton, AnyModifier, c->win);
arg@372 22
arg@452 23 if(focused) {
arg@372 24 XGrabButton(dpy, Button1, MODKEY, c->win, False, BUTTONMASK,
arg@372 25 GrabModeAsync, GrabModeSync, None, None);
arg@372 26 XGrabButton(dpy, Button1, MODKEY | LockMask, c->win, False, BUTTONMASK,
arg@372 27 GrabModeAsync, GrabModeSync, None, None);
arg@372 28 XGrabButton(dpy, Button1, MODKEY | numlockmask, c->win, False, BUTTONMASK,
arg@372 29 GrabModeAsync, GrabModeSync, None, None);
arg@372 30 XGrabButton(dpy, Button1, MODKEY | numlockmask | LockMask, c->win, False, BUTTONMASK,
arg@372 31 GrabModeAsync, GrabModeSync, None, None);
arg@372 32
arg@372 33 XGrabButton(dpy, Button2, MODKEY, c->win, False, BUTTONMASK,
arg@372 34 GrabModeAsync, GrabModeSync, None, None);
arg@372 35 XGrabButton(dpy, Button2, MODKEY | LockMask, c->win, False, BUTTONMASK,
arg@372 36 GrabModeAsync, GrabModeSync, None, None);
arg@372 37 XGrabButton(dpy, Button2, MODKEY | numlockmask, c->win, False, BUTTONMASK,
arg@372 38 GrabModeAsync, GrabModeSync, None, None);
arg@372 39 XGrabButton(dpy, Button2, MODKEY | numlockmask | LockMask, c->win, False, BUTTONMASK,
arg@372 40 GrabModeAsync, GrabModeSync, None, None);
arg@372 41
arg@372 42 XGrabButton(dpy, Button3, MODKEY, c->win, False, BUTTONMASK,
arg@372 43 GrabModeAsync, GrabModeSync, None, None);
arg@372 44 XGrabButton(dpy, Button3, MODKEY | LockMask, c->win, False, BUTTONMASK,
arg@372 45 GrabModeAsync, GrabModeSync, None, None);
arg@372 46 XGrabButton(dpy, Button3, MODKEY | numlockmask, c->win, False, BUTTONMASK,
arg@372 47 GrabModeAsync, GrabModeSync, None, None);
arg@372 48 XGrabButton(dpy, Button3, MODKEY | numlockmask | LockMask, c->win, False, BUTTONMASK,
arg@372 49 GrabModeAsync, GrabModeSync, None, None);
arg@372 50 }
arg@372 51 else
arg@372 52 XGrabButton(dpy, AnyButton, AnyModifier, c->win, False, BUTTONMASK,
arg@372 53 GrabModeAsync, GrabModeSync, None, None);
arg@318 54 }
arg@318 55
garbeam@76 56 static int
arg@461 57 xerrordummy(Display *dsply, XErrorEvent *ee) {
garbeam@76 58 return 0;
garbeam@5 59 }
garbeam@5 60
garbeam@76 61 /* extern functions */
garbeam@20 62
garbeam@20 63 void
arg@461 64 ban(Client *c) {
arg@115 65 XMoveWindow(dpy, c->win, c->x + 2 * sw, c->y);
arg@342 66 XMoveWindow(dpy, c->twin, c->tx + 2 * sw, c->ty);
garbeam@26 67 }
garbeam@26 68
garbeam@26 69 void
arg@491 70 configure(Client *c) {
arg@491 71 XEvent synev;
arg@491 72
arg@491 73 synev.type = ConfigureNotify;
arg@491 74 synev.xconfigure.display = dpy;
arg@491 75 synev.xconfigure.event = c->win;
arg@491 76 synev.xconfigure.window = c->win;
arg@491 77 synev.xconfigure.x = c->x;
arg@491 78 synev.xconfigure.y = c->y;
arg@491 79 synev.xconfigure.width = c->w;
arg@491 80 synev.xconfigure.height = c->h;
arg@491 81 synev.xconfigure.border_width = c->border;
arg@491 82 synev.xconfigure.above = None;
arg@491 83 XSendEvent(dpy, c->win, True, NoEventMask, &synev);
arg@491 84 }
arg@491 85
arg@491 86 void
arg@461 87 focus(Client *c) {
arg@400 88 Client *old;
arg@286 89
arg@464 90 if(!issel || (c && !isvisible(c)))
arg@239 91 return;
arg@319 92 if(!sel)
arg@319 93 sel = c;
arg@319 94 else if(sel != c) {
arg@400 95 old = sel;
arg@319 96 sel = c;
arg@400 97 if(old) {
arg@400 98 grabbuttons(old, False);
arg@400 99 drawtitle(old);
arg@400 100 }
arg@318 101 }
arg@400 102 if(c) {
arg@446 103 detachstack(c);
arg@446 104 c->snext = stack;
arg@446 105 stack = c;
arg@400 106 grabbuttons(c, True);
arg@400 107 drawtitle(c);
arg@400 108 XSetInputFocus(dpy, c->win, RevertToPointerRoot, CurrentTime);
arg@400 109 }
arg@400 110 else
arg@400 111 XSetInputFocus(dpy, root, RevertToPointerRoot, CurrentTime);
garbeam@13 112 }
garbeam@13 113
garbeam@76 114 Client *
arg@461 115 getclient(Window w) {
garbeam@76 116 Client *c;
arg@123 117
garbeam@76 118 for(c = clients; c; c = c->next)
garbeam@76 119 if(c->win == w)
garbeam@76 120 return c;
garbeam@76 121 return NULL;
garbeam@76 122 }
garbeam@76 123
garbeam@76 124 Client *
arg@461 125 getctitle(Window w) {
garbeam@76 126 Client *c;
arg@123 127
garbeam@76 128 for(c = clients; c; c = c->next)
arg@342 129 if(c->twin == w)
garbeam@76 130 return c;
garbeam@76 131 return NULL;
garbeam@76 132 }
garbeam@76 133
garbeam@76 134 void
arg@461 135 gravitate(Client *c, Bool invert) {
garbeam@76 136 int dx = 0, dy = 0;
garbeam@76 137
garbeam@76 138 switch(c->grav) {
arg@127 139 default:
arg@127 140 break;
garbeam@76 141 case StaticGravity:
garbeam@76 142 case NorthWestGravity:
garbeam@76 143 case NorthGravity:
garbeam@76 144 case NorthEastGravity:
garbeam@76 145 dy = c->border;
garbeam@76 146 break;
garbeam@76 147 case EastGravity:
garbeam@76 148 case CenterGravity:
garbeam@76 149 case WestGravity:
arg@115 150 dy = -(c->h / 2) + c->border;
garbeam@76 151 break;
garbeam@76 152 case SouthEastGravity:
garbeam@76 153 case SouthGravity:
garbeam@76 154 case SouthWestGravity:
arg@115 155 dy = -(c->h);
garbeam@76 156 break;
garbeam@76 157 }
garbeam@76 158 switch (c->grav) {
arg@127 159 default:
arg@127 160 break;
garbeam@76 161 case StaticGravity:
garbeam@76 162 case NorthWestGravity:
garbeam@76 163 case WestGravity:
garbeam@76 164 case SouthWestGravity:
garbeam@76 165 dx = c->border;
garbeam@76 166 break;
garbeam@76 167 case NorthGravity:
garbeam@76 168 case CenterGravity:
garbeam@76 169 case SouthGravity:
arg@115 170 dx = -(c->w / 2) + c->border;
garbeam@76 171 break;
garbeam@76 172 case NorthEastGravity:
garbeam@76 173 case EastGravity:
garbeam@76 174 case SouthEastGravity:
arg@115 175 dx = -(c->w + c->border);
garbeam@76 176 break;
garbeam@76 177 }
garbeam@76 178 if(invert) {
garbeam@76 179 dx = -dx;
garbeam@76 180 dy = -dy;
garbeam@76 181 }
arg@115 182 c->x += dx;
arg@115 183 c->y += dy;
garbeam@76 184 }
garbeam@76 185
garbeam@76 186 void
arg@461 187 killclient(Arg *arg) {
garbeam@76 188 if(!sel)
garbeam@76 189 return;
arg@157 190 if(sel->proto & PROTODELWIN)
garbeam@77 191 sendevent(sel->win, wmatom[WMProtocols], wmatom[WMDelete]);
garbeam@76 192 else
garbeam@76 193 XKillClient(dpy, sel->win);
garbeam@76 194 }
garbeam@76 195
garbeam@76 196 void
arg@461 197 manage(Window w, XWindowAttributes *wa) {
arg@431 198 Client *c;
arg@123 199 Window trans;
garbeam@5 200 XSetWindowAttributes twa;
garbeam@5 201
garbeam@5 202 c = emallocz(sizeof(Client));
arg@178 203 c->tags = emallocz(ntags * sizeof(Bool));
garbeam@5 204 c->win = w;
arg@115 205 c->x = c->tx = wa->x;
arg@115 206 c->y = c->ty = wa->y;
arg@115 207 c->w = c->tw = wa->width;
arg@115 208 c->h = wa->height;
arg@115 209 c->th = bh;
arg@164 210 c->border = 0;
arg@454 211 updatesize(c);
arg@502 212 if(c->x + c->w + 2 * BORDERPX > sw)
arg@502 213 c->x = sw - c->w - 2 * BORDERPX;
arg@517 214 if(c->x < sx)
arg@517 215 c->x = sx;
arg@502 216 if(c->y + c->h + 2 * BORDERPX > sh)
arg@517 217 c->y = sh - c->h - 2 * BORDERPX;
arg@163 218 if(c->h != sh && c->y < bh)
arg@314 219 c->y = bh;
garbeam@75 220 c->proto = getproto(c->win);
garbeam@26 221 XSelectInput(dpy, c->win,
arg@127 222 StructureNotifyMask | PropertyChangeMask | EnterWindowMask);
garbeam@53 223 XGetTransientForHint(dpy, c->win, &trans);
garbeam@5 224 twa.override_redirect = 1;
garbeam@5 225 twa.background_pixmap = ParentRelative;
arg@161 226 twa.event_mask = ExposureMask | EnterWindowMask;
arg@342 227 c->twin = XCreateWindow(dpy, root, c->tx, c->ty, c->tw, c->th,
garbeam@20 228 0, DefaultDepth(dpy, screen), CopyFromParent,
garbeam@5 229 DefaultVisual(dpy, screen),
garbeam@5 230 CWOverrideRedirect | CWBackPixmap | CWEventMask, &twa);
arg@372 231 grabbuttons(c, False);
arg@500 232 updatetitle(c);
arg@431 233 settags(c, getclient(trans));
garbeam@80 234 if(!c->isfloat)
arg@163 235 c->isfloat = trans
arg@163 236 || (c->maxw && c->minw &&
arg@164 237 c->maxw == c->minw && c->maxh == c->minh);
arg@500 238 resizetitle(c);
arg@381 239 if(clients)
arg@381 240 clients->prev = c;
arg@381 241 c->next = clients;
arg@446 242 c->snext = stack;
arg@446 243 stack = clients = c;
arg@408 244 ban(c);
arg@270 245 XMapWindow(dpy, c->win);
arg@342 246 XMapWindow(dpy, c->twin);
arg@261 247 if(isvisible(c))
garbeam@51 248 focus(c);
arg@533 249 arrange();
garbeam@94 250 }
garbeam@94 251
garbeam@94 252 void
arg@461 253 resize(Client *c, Bool sizehints, Corner sticky) {
arg@123 254 int bottom = c->y + c->h;
arg@123 255 int right = c->x + c->w;
arg@163 256 XWindowChanges wc;
garbeam@18 257
arg@129 258 if(sizehints) {
garbeam@52 259 if(c->incw)
arg@115 260 c->w -= (c->w - c->basew) % c->incw;
garbeam@52 261 if(c->inch)
arg@115 262 c->h -= (c->h - c->baseh) % c->inch;
arg@129 263 if(c->minw && c->w < c->minw)
arg@129 264 c->w = c->minw;
arg@129 265 if(c->minh && c->h < c->minh)
arg@129 266 c->h = c->minh;
arg@129 267 if(c->maxw && c->w > c->maxw)
arg@129 268 c->w = c->maxw;
arg@129 269 if(c->maxh && c->h > c->maxh)
arg@129 270 c->h = c->maxh;
garbeam@52 271 }
arg@105 272 if(sticky == TopRight || sticky == BotRight)
arg@115 273 c->x = right - c->w;
arg@105 274 if(sticky == BotLeft || sticky == BotRight)
arg@115 275 c->y = bottom - c->h;
arg@465 276 /* offscreen appearance fixes */
arg@517 277 if(c->x + c->w < sx)
arg@517 278 c->x = sx;
arg@465 279 if(c->y + c->h < bh)
arg@465 280 c->y = bh;
arg@465 281 if(c->x > sw)
arg@465 282 c->x = sw - c->w;
arg@465 283 if(c->y > sh)
arg@465 284 c->y = sh - c->h;
garbeam@75 285 resizetitle(c);
arg@163 286 wc.x = c->x;
arg@163 287 wc.y = c->y;
arg@163 288 wc.width = c->w;
arg@163 289 wc.height = c->h;
arg@164 290 if(c->w == sw && c->h == sh)
arg@164 291 wc.border_width = 0;
arg@164 292 else
arg@502 293 wc.border_width = BORDERPX;
arg@452 294 XConfigureWindow(dpy, c->win, CWX | CWY | CWWidth | CWHeight | CWBorderWidth, &wc);
arg@491 295 configure(c);
garbeam@79 296 XSync(dpy, False);
garbeam@18 297 }
garbeam@18 298
garbeam@76 299 void
arg@500 300 resizetitle(Client *c) {
arg@500 301 c->tw = textw(c->name);
arg@500 302 if(c->tw > c->w)
arg@502 303 c->tw = c->w + 2 * BORDERPX;
arg@502 304 c->tx = c->x + c->w - c->tw + 2 * BORDERPX;
arg@500 305 c->ty = c->y;
arg@500 306 if(isvisible(c))
arg@500 307 XMoveResizeWindow(dpy, c->twin, c->tx, c->ty, c->tw, c->th);
arg@500 308 else
arg@500 309 XMoveResizeWindow(dpy, c->twin, c->tx + 2 * sw, c->ty, c->tw, c->th);
arg@500 310 }
arg@500 311
arg@500 312 void
arg@461 313 updatesize(Client *c) {
arg@123 314 long msize;
garbeam@76 315 XSizeHints size;
arg@123 316
garbeam@76 317 if(!XGetWMNormalHints(dpy, c->win, &size, &msize) || !size.flags)
garbeam@76 318 size.flags = PSize;
garbeam@76 319 c->flags = size.flags;
garbeam@76 320 if(c->flags & PBaseSize) {
garbeam@76 321 c->basew = size.base_width;
garbeam@76 322 c->baseh = size.base_height;
garbeam@76 323 }
garbeam@76 324 else
garbeam@76 325 c->basew = c->baseh = 0;
garbeam@76 326 if(c->flags & PResizeInc) {
garbeam@76 327 c->incw = size.width_inc;
garbeam@76 328 c->inch = size.height_inc;
garbeam@76 329 }
garbeam@76 330 else
garbeam@76 331 c->incw = c->inch = 0;
garbeam@76 332 if(c->flags & PMaxSize) {
garbeam@76 333 c->maxw = size.max_width;
garbeam@76 334 c->maxh = size.max_height;
garbeam@76 335 }
garbeam@76 336 else
garbeam@76 337 c->maxw = c->maxh = 0;
garbeam@76 338 if(c->flags & PMinSize) {
garbeam@76 339 c->minw = size.min_width;
garbeam@76 340 c->minh = size.min_height;
garbeam@76 341 }
garbeam@76 342 else
garbeam@76 343 c->minw = c->minh = 0;
garbeam@76 344 if(c->flags & PWinGravity)
garbeam@76 345 c->grav = size.win_gravity;
garbeam@76 346 else
garbeam@76 347 c->grav = NorthWestGravity;
garbeam@76 348 }
garbeam@76 349
garbeam@76 350 void
arg@461 351 updatetitle(Client *c) {
arg@123 352 char **list = NULL;
arg@377 353 int n;
garbeam@76 354 XTextProperty name;
garbeam@76 355
garbeam@76 356 name.nitems = 0;
garbeam@76 357 c->name[0] = 0;
garbeam@77 358 XGetTextProperty(dpy, c->win, &name, netatom[NetWMName]);
garbeam@76 359 if(!name.nitems)
garbeam@76 360 XGetWMName(dpy, c->win, &name);
garbeam@76 361 if(!name.nitems)
garbeam@76 362 return;
garbeam@76 363 if(name.encoding == XA_STRING)
garbeam@76 364 strncpy(c->name, (char *)name.value, sizeof(c->name));
garbeam@76 365 else {
garbeam@76 366 if(XmbTextPropertyToTextList(dpy, &name, &list, &n) >= Success
garbeam@76 367 && n > 0 && *list)
garbeam@76 368 {
garbeam@76 369 strncpy(c->name, *list, sizeof(c->name));
garbeam@76 370 XFreeStringList(list);
garbeam@76 371 }
garbeam@76 372 }
garbeam@76 373 XFree(name.value);
garbeam@10 374 }
garbeam@10 375
garbeam@10 376 void
arg@461 377 unmanage(Client *c) {
arg@450 378 Client *nc;
arg@450 379
arg@472 380 /* The server grab construct avoids race conditions. */
garbeam@10 381 XGrabServer(dpy);
garbeam@75 382 XSetErrorHandler(xerrordummy);
arg@400 383 detach(c);
arg@448 384 detachstack(c);
arg@400 385 if(sel == c) {
arg@450 386 for(nc = stack; nc && !isvisible(nc); nc = nc->snext);
arg@450 387 focus(nc);
arg@400 388 }
garbeam@18 389 XUngrabButton(dpy, AnyButton, AnyModifier, c->win);
arg@342 390 XDestroyWindow(dpy, c->twin);
arg@178 391 free(c->tags);
garbeam@10 392 free(c);
garbeam@79 393 XSync(dpy, False);
garbeam@74 394 XSetErrorHandler(xerror);
garbeam@10 395 XUngrabServer(dpy);
arg@533 396 arrange();
garbeam@10 397 }