aewl

annotate client.c @ 74:5370ef170cc9

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