dwm-meillo

annotate client.c @ 384:126e78129f1d

configurenotify remembers max geom now, and restores this if necessary, however it accepts to touch the max size on configurerequest, this shouldn't break fillscreen apps (tested with mplayer)
author Anselm R. Garbe <arg@10kloc.org>
date Tue, 29 Aug 2006 17:31:55 +0200
parents 83576f5f0a90
children 052657ff2e7b
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@76 5 #include "dwm.h"
garbeam@10 6 #include <stdlib.h>
garbeam@5 7 #include <string.h>
garbeam@5 8 #include <X11/Xatom.h>
garbeam@32 9 #include <X11/Xutil.h>
garbeam@5 10
garbeam@76 11 /* static functions */
garbeam@50 12
garbeam@26 13 static void
arg@372 14 grabbuttons(Client *c, Bool focus)
arg@318 15 {
arg@372 16 XUngrabButton(dpy, AnyButton, AnyModifier, c->win);
arg@372 17
arg@372 18 if(focus) {
arg@372 19 XGrabButton(dpy, Button1, MODKEY, c->win, False, BUTTONMASK,
arg@372 20 GrabModeAsync, GrabModeSync, None, None);
arg@372 21 XGrabButton(dpy, Button1, MODKEY | LockMask, c->win, False, BUTTONMASK,
arg@372 22 GrabModeAsync, GrabModeSync, None, None);
arg@372 23 XGrabButton(dpy, Button1, MODKEY | numlockmask, c->win, False, BUTTONMASK,
arg@372 24 GrabModeAsync, GrabModeSync, None, None);
arg@372 25 XGrabButton(dpy, Button1, MODKEY | numlockmask | LockMask, c->win, False, BUTTONMASK,
arg@372 26 GrabModeAsync, GrabModeSync, None, None);
arg@372 27
arg@372 28 XGrabButton(dpy, Button2, MODKEY, c->win, False, BUTTONMASK,
arg@372 29 GrabModeAsync, GrabModeSync, None, None);
arg@372 30 XGrabButton(dpy, Button2, MODKEY | LockMask, c->win, False, BUTTONMASK,
arg@372 31 GrabModeAsync, GrabModeSync, None, None);
arg@372 32 XGrabButton(dpy, Button2, MODKEY | numlockmask, c->win, False, BUTTONMASK,
arg@372 33 GrabModeAsync, GrabModeSync, None, None);
arg@372 34 XGrabButton(dpy, Button2, MODKEY | numlockmask | LockMask, c->win, False, BUTTONMASK,
arg@372 35 GrabModeAsync, GrabModeSync, None, None);
arg@372 36
arg@372 37 XGrabButton(dpy, Button3, MODKEY, c->win, False, BUTTONMASK,
arg@372 38 GrabModeAsync, GrabModeSync, None, None);
arg@372 39 XGrabButton(dpy, Button3, MODKEY | LockMask, c->win, False, BUTTONMASK,
arg@372 40 GrabModeAsync, GrabModeSync, None, None);
arg@372 41 XGrabButton(dpy, Button3, MODKEY | numlockmask, c->win, False, BUTTONMASK,
arg@372 42 GrabModeAsync, GrabModeSync, None, None);
arg@372 43 XGrabButton(dpy, Button3, MODKEY | numlockmask | LockMask, c->win, False, BUTTONMASK,
arg@372 44 GrabModeAsync, GrabModeSync, None, None);
arg@372 45 }
arg@372 46 else
arg@372 47 XGrabButton(dpy, AnyButton, AnyModifier, c->win, False, BUTTONMASK,
arg@372 48 GrabModeAsync, GrabModeSync, None, None);
arg@372 49
arg@318 50 }
arg@318 51
arg@318 52 static void
garbeam@75 53 resizetitle(Client *c)
garbeam@26 54 {
arg@342 55 c->tw = textw(c->name);
arg@115 56 if(c->tw > c->w)
arg@115 57 c->tw = c->w + 2;
arg@115 58 c->tx = c->x + c->w - c->tw + 2;
arg@115 59 c->ty = c->y;
arg@261 60 if(isvisible(c))
arg@342 61 XMoveResizeWindow(dpy, c->twin, c->tx, c->ty, c->tw, c->th);
arg@106 62 else
arg@342 63 XMoveResizeWindow(dpy, c->twin, c->tx + 2 * sw, c->ty, c->tw, c->th);
arg@106 64
garbeam@26 65 }
garbeam@18 66
garbeam@76 67 static int
garbeam@76 68 xerrordummy(Display *dsply, XErrorEvent *ee)
garbeam@5 69 {
garbeam@76 70 return 0;
garbeam@5 71 }
garbeam@5 72
garbeam@76 73 /* extern functions */
garbeam@20 74
garbeam@20 75 void
garbeam@76 76 ban(Client *c)
garbeam@26 77 {
arg@115 78 XMoveWindow(dpy, c->win, c->x + 2 * sw, c->y);
arg@342 79 XMoveWindow(dpy, c->twin, c->tx + 2 * sw, c->ty);
garbeam@26 80 }
garbeam@26 81
garbeam@26 82 void
garbeam@13 83 focus(Client *c)
garbeam@13 84 {
arg@286 85 Client *old = sel;
arg@286 86
arg@319 87 if(!issel)
arg@239 88 return;
arg@319 89 if(!sel)
arg@319 90 sel = c;
arg@319 91 else if(sel != c) {
arg@319 92 if(sel->ismax)
arg@319 93 togglemax(NULL);
arg@319 94 sel = c;
arg@372 95 grabbuttons(old, False);
garbeam@74 96 drawtitle(old);
arg@318 97 }
arg@372 98 grabbuttons(c, True);
garbeam@74 99 drawtitle(c);
garbeam@26 100 XSetInputFocus(dpy, c->win, RevertToPointerRoot, CurrentTime);
garbeam@13 101 }
garbeam@13 102
garbeam@76 103 Client *
garbeam@76 104 getclient(Window w)
garbeam@76 105 {
garbeam@76 106 Client *c;
arg@123 107
garbeam@76 108 for(c = clients; c; c = c->next)
garbeam@76 109 if(c->win == w)
garbeam@76 110 return c;
garbeam@76 111 return NULL;
garbeam@76 112 }
garbeam@76 113
garbeam@76 114 Client *
garbeam@76 115 getctitle(Window w)
garbeam@76 116 {
garbeam@76 117 Client *c;
arg@123 118
garbeam@76 119 for(c = clients; c; c = c->next)
arg@342 120 if(c->twin == w)
garbeam@76 121 return c;
garbeam@76 122 return NULL;
garbeam@76 123 }
garbeam@76 124
garbeam@76 125 void
garbeam@76 126 gravitate(Client *c, Bool invert)
garbeam@76 127 {
garbeam@76 128 int dx = 0, dy = 0;
garbeam@76 129
garbeam@76 130 switch(c->grav) {
arg@127 131 default:
arg@127 132 break;
garbeam@76 133 case StaticGravity:
garbeam@76 134 case NorthWestGravity:
garbeam@76 135 case NorthGravity:
garbeam@76 136 case NorthEastGravity:
garbeam@76 137 dy = c->border;
garbeam@76 138 break;
garbeam@76 139 case EastGravity:
garbeam@76 140 case CenterGravity:
garbeam@76 141 case WestGravity:
arg@115 142 dy = -(c->h / 2) + c->border;
garbeam@76 143 break;
garbeam@76 144 case SouthEastGravity:
garbeam@76 145 case SouthGravity:
garbeam@76 146 case SouthWestGravity:
arg@115 147 dy = -(c->h);
garbeam@76 148 break;
garbeam@76 149 }
garbeam@76 150
garbeam@76 151 switch (c->grav) {
arg@127 152 default:
arg@127 153 break;
garbeam@76 154 case StaticGravity:
garbeam@76 155 case NorthWestGravity:
garbeam@76 156 case WestGravity:
garbeam@76 157 case SouthWestGravity:
garbeam@76 158 dx = c->border;
garbeam@76 159 break;
garbeam@76 160 case NorthGravity:
garbeam@76 161 case CenterGravity:
garbeam@76 162 case SouthGravity:
arg@115 163 dx = -(c->w / 2) + c->border;
garbeam@76 164 break;
garbeam@76 165 case NorthEastGravity:
garbeam@76 166 case EastGravity:
garbeam@76 167 case SouthEastGravity:
arg@115 168 dx = -(c->w + c->border);
garbeam@76 169 break;
garbeam@76 170 }
garbeam@76 171
garbeam@76 172 if(invert) {
garbeam@76 173 dx = -dx;
garbeam@76 174 dy = -dy;
garbeam@76 175 }
arg@115 176 c->x += dx;
arg@115 177 c->y += dy;
garbeam@76 178 }
garbeam@76 179
garbeam@76 180 void
garbeam@76 181 killclient(Arg *arg)
garbeam@76 182 {
garbeam@76 183 if(!sel)
garbeam@76 184 return;
arg@157 185 if(sel->proto & PROTODELWIN)
garbeam@77 186 sendevent(sel->win, wmatom[WMProtocols], wmatom[WMDelete]);
garbeam@76 187 else
garbeam@76 188 XKillClient(dpy, sel->win);
garbeam@76 189 }
garbeam@76 190
garbeam@76 191 void
garbeam@10 192 manage(Window w, XWindowAttributes *wa)
garbeam@5 193 {
arg@320 194 unsigned int i;
arg@306 195 Client *c, *tc;
arg@123 196 Window trans;
garbeam@5 197 XSetWindowAttributes twa;
garbeam@5 198
garbeam@5 199 c = emallocz(sizeof(Client));
arg@178 200 c->tags = emallocz(ntags * sizeof(Bool));
garbeam@5 201 c->win = w;
arg@115 202 c->x = c->tx = wa->x;
arg@115 203 c->y = c->ty = wa->y;
arg@115 204 c->w = c->tw = wa->width;
arg@115 205 c->h = wa->height;
arg@115 206 c->th = bh;
arg@100 207
arg@164 208 c->border = 0;
arg@163 209 setsize(c);
arg@163 210
arg@315 211 if(c->x + c->w + 2 > sw)
arg@314 212 c->x = sw - c->w - 2;
arg@314 213 if(c->x < 0)
arg@314 214 c->x = 0;
arg@315 215 if(c->y + c->h + 2 > sh)
arg@314 216 c->y = sh - c->h - 2;
arg@163 217 if(c->h != sh && c->y < bh)
arg@314 218 c->y = bh;
arg@104 219
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;
garbeam@5 227
arg@342 228 c->twin = XCreateWindow(dpy, root, c->tx, c->ty, c->tw, c->th,
garbeam@20 229 0, DefaultDepth(dpy, screen), CopyFromParent,
garbeam@5 230 DefaultVisual(dpy, screen),
garbeam@5 231 CWOverrideRedirect | CWBackPixmap | CWEventMask, &twa);
garbeam@31 232
arg@372 233 grabbuttons(c, False);
arg@320 234 if((tc = getclient(trans))) /* inherit tags */
arg@320 235 for(i = 0; i < ntags; i++)
arg@320 236 c->tags[i] = tc->tags[i];
arg@320 237 else
arg@320 238 settags(c);
garbeam@80 239 if(!c->isfloat)
arg@163 240 c->isfloat = trans
arg@163 241 || (c->maxw && c->minw &&
arg@164 242 c->maxw == c->minw && c->maxh == c->minh);
arg@378 243
arg@381 244 if(clients)
arg@381 245 clients->prev = c;
arg@381 246 c->next = clients;
arg@381 247 clients = c;
arg@378 248
garbeam@95 249 settitle(c);
arg@283 250 if(isvisible(c))
arg@283 251 sel = c;
arg@283 252 arrange(NULL);
arg@270 253 XMapWindow(dpy, c->win);
arg@342 254 XMapWindow(dpy, c->twin);
arg@261 255 if(isvisible(c))
garbeam@51 256 focus(c);
garbeam@94 257 }
garbeam@94 258
garbeam@94 259 void
arg@129 260 resize(Client *c, Bool sizehints, Corner sticky)
garbeam@18 261 {
arg@123 262 int bottom = c->y + c->h;
arg@123 263 int right = c->x + c->w;
arg@163 264 XWindowChanges wc;
garbeam@18 265
arg@129 266 if(sizehints) {
garbeam@52 267 if(c->incw)
arg@115 268 c->w -= (c->w - c->basew) % c->incw;
garbeam@52 269 if(c->inch)
arg@115 270 c->h -= (c->h - c->baseh) % c->inch;
arg@129 271 if(c->minw && c->w < c->minw)
arg@129 272 c->w = c->minw;
arg@129 273 if(c->minh && c->h < c->minh)
arg@129 274 c->h = c->minh;
arg@129 275 if(c->maxw && c->w > c->maxw)
arg@129 276 c->w = c->maxw;
arg@129 277 if(c->maxh && c->h > c->maxh)
arg@129 278 c->h = c->maxh;
garbeam@52 279 }
arg@105 280 if(sticky == TopRight || sticky == BotRight)
arg@115 281 c->x = right - c->w;
arg@105 282 if(sticky == BotLeft || sticky == BotRight)
arg@115 283 c->y = bottom - c->h;
arg@106 284
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@164 293 wc.border_width = 1;
arg@164 294 XConfigureWindow(dpy, c->win, CWX|CWY|CWWidth|CWHeight|CWBorderWidth, &wc);
garbeam@79 295 XSync(dpy, False);
garbeam@18 296 }
garbeam@18 297
garbeam@76 298 void
garbeam@76 299 setsize(Client *c)
garbeam@10 300 {
arg@123 301 long msize;
garbeam@76 302 XSizeHints size;
arg@123 303
garbeam@76 304 if(!XGetWMNormalHints(dpy, c->win, &size, &msize) || !size.flags)
garbeam@76 305 size.flags = PSize;
garbeam@76 306 c->flags = size.flags;
garbeam@76 307 if(c->flags & PBaseSize) {
garbeam@76 308 c->basew = size.base_width;
garbeam@76 309 c->baseh = size.base_height;
garbeam@76 310 }
garbeam@76 311 else
garbeam@76 312 c->basew = c->baseh = 0;
garbeam@76 313 if(c->flags & PResizeInc) {
garbeam@76 314 c->incw = size.width_inc;
garbeam@76 315 c->inch = size.height_inc;
garbeam@76 316 }
garbeam@76 317 else
garbeam@76 318 c->incw = c->inch = 0;
garbeam@76 319 if(c->flags & PMaxSize) {
garbeam@76 320 c->maxw = size.max_width;
garbeam@76 321 c->maxh = size.max_height;
garbeam@76 322 }
garbeam@76 323 else
garbeam@76 324 c->maxw = c->maxh = 0;
garbeam@76 325 if(c->flags & PMinSize) {
garbeam@76 326 c->minw = size.min_width;
garbeam@76 327 c->minh = size.min_height;
garbeam@76 328 }
garbeam@76 329 else
garbeam@76 330 c->minw = c->minh = 0;
garbeam@76 331 if(c->flags & PWinGravity)
garbeam@76 332 c->grav = size.win_gravity;
garbeam@76 333 else
garbeam@76 334 c->grav = NorthWestGravity;
garbeam@76 335 }
garbeam@76 336
garbeam@76 337 void
garbeam@76 338 settitle(Client *c)
garbeam@76 339 {
arg@123 340 char **list = NULL;
arg@377 341 int n;
garbeam@76 342 XTextProperty name;
garbeam@76 343
garbeam@76 344 name.nitems = 0;
garbeam@76 345 c->name[0] = 0;
garbeam@77 346 XGetTextProperty(dpy, c->win, &name, netatom[NetWMName]);
garbeam@76 347 if(!name.nitems)
garbeam@76 348 XGetWMName(dpy, c->win, &name);
garbeam@76 349 if(!name.nitems)
garbeam@76 350 return;
garbeam@76 351 if(name.encoding == XA_STRING)
garbeam@76 352 strncpy(c->name, (char *)name.value, sizeof(c->name));
garbeam@76 353 else {
garbeam@76 354 if(XmbTextPropertyToTextList(dpy, &name, &list, &n) >= Success
garbeam@76 355 && n > 0 && *list)
garbeam@76 356 {
garbeam@76 357 strncpy(c->name, *list, sizeof(c->name));
garbeam@76 358 XFreeStringList(list);
garbeam@76 359 }
garbeam@76 360 }
garbeam@76 361 XFree(name.value);
garbeam@76 362 resizetitle(c);
garbeam@10 363 }
garbeam@10 364
garbeam@10 365 void
arg@124 366 togglemax(Arg *arg)
arg@124 367 {
arg@124 368 int ox, oy, ow, oh;
arg@124 369 XEvent ev;
arg@124 370
arg@124 371 if(!sel)
arg@124 372 return;
arg@124 373
arg@124 374 if((sel->ismax = !sel->ismax)) {
arg@124 375 ox = sel->x;
arg@124 376 oy = sel->y;
arg@124 377 ow = sel->w;
arg@124 378 oh = sel->h;
arg@124 379 sel->x = sx;
arg@124 380 sel->y = sy + bh;
arg@164 381 sel->w = sw - 2;
arg@164 382 sel->h = sh - 2 - bh;
arg@124 383
arg@270 384 restack();
arg@247 385 resize(sel, arrange == dofloat, TopLeft);
arg@124 386
arg@124 387 sel->x = ox;
arg@124 388 sel->y = oy;
arg@124 389 sel->w = ow;
arg@124 390 sel->h = oh;
arg@124 391 }
arg@124 392 else
arg@124 393 resize(sel, False, TopLeft);
arg@124 394 while(XCheckMaskEvent(dpy, EnterWindowMask, &ev));
arg@124 395 }
arg@124 396
arg@124 397 void
garbeam@10 398 unmanage(Client *c)
garbeam@10 399 {
arg@372 400 Client *tc;
arg@372 401 Window trans;
garbeam@10 402 XGrabServer(dpy);
garbeam@75 403 XSetErrorHandler(xerrordummy);
garbeam@10 404
arg@372 405 XGetTransientForHint(dpy, c->win, &trans);
arg@372 406
garbeam@18 407 XUngrabButton(dpy, AnyButton, AnyModifier, c->win);
arg@342 408 XDestroyWindow(dpy, c->twin);
garbeam@10 409
arg@378 410 detach(c);
arg@372 411 if(sel == c) {
arg@372 412 if(trans && (tc = getclient(trans)) && isvisible(tc))
arg@372 413 sel = tc;
arg@372 414 else
arg@372 415 sel = getnext(clients);
arg@372 416 }
arg@178 417 free(c->tags);
garbeam@10 418 free(c);
garbeam@10 419
garbeam@79 420 XSync(dpy, False);
garbeam@74 421 XSetErrorHandler(xerror);
garbeam@10 422 XUngrabServer(dpy);
garbeam@50 423 if(sel)
garbeam@50 424 focus(sel);
arg@270 425 arrange(NULL);
garbeam@10 426 }