annotate client.c @ 3:faa4cb9d7bd6

add TASKBAR and CLICK_TO_FOCUS
author paulo@localhost
date Thu, 23 Apr 2009 02:43:13 -0700
parents
children a54de16f8277
rev   line source
paulo@0 1 /* (C)opyright MMVI-MMVII Anselm R. Garbe <garbeam at gmail dot com>
paulo@0 2 * See LICENSE file for license details.
paulo@0 3 */
paulo@0 4 #include "dwm.h"
paulo@0 5 #include <stdio.h>
paulo@0 6 #include <stdlib.h>
paulo@0 7 #include <string.h>
paulo@0 8 #include <X11/Xatom.h>
paulo@0 9 #include <X11/Xutil.h>
paulo@0 10
paulo@0 11 /* static */
paulo@0 12
paulo@0 13 static void
paulo@0 14 attachstack(Client *c) {
paulo@0 15 c->snext = stack;
paulo@0 16 stack = c;
paulo@0 17 }
paulo@0 18
paulo@0 19 static void
paulo@0 20 detachstack(Client *c) {
paulo@0 21 Client **tc;
paulo@0 22
paulo@0 23 for(tc=&stack; *tc && *tc != c; tc=&(*tc)->snext);
paulo@0 24 *tc = c->snext;
paulo@0 25 }
paulo@0 26
paulo@0 27 static void
paulo@0 28 grabbuttons(Client *c, Bool focused) {
paulo@0 29 XUngrabButton(dpy, AnyButton, AnyModifier, c->win);
paulo@0 30
paulo@0 31 if(focused) {
paulo@0 32 XGrabButton(dpy, Button1, MODKEY, c->win, False, BUTTONMASK,
paulo@0 33 GrabModeAsync, GrabModeSync, None, None);
paulo@0 34 XGrabButton(dpy, Button1, MODKEY | LockMask, c->win, False, BUTTONMASK,
paulo@0 35 GrabModeAsync, GrabModeSync, None, None);
paulo@0 36 XGrabButton(dpy, Button1, MODKEY | numlockmask, c->win, False, BUTTONMASK,
paulo@0 37 GrabModeAsync, GrabModeSync, None, None);
paulo@0 38 XGrabButton(dpy, Button1, MODKEY | numlockmask | LockMask, c->win, False, BUTTONMASK,
paulo@0 39 GrabModeAsync, GrabModeSync, None, None);
paulo@0 40
paulo@0 41 XGrabButton(dpy, Button2, MODKEY, c->win, False, BUTTONMASK,
paulo@0 42 GrabModeAsync, GrabModeSync, None, None);
paulo@0 43 XGrabButton(dpy, Button2, MODKEY | LockMask, c->win, False, BUTTONMASK,
paulo@0 44 GrabModeAsync, GrabModeSync, None, None);
paulo@0 45 XGrabButton(dpy, Button2, MODKEY | numlockmask, c->win, False, BUTTONMASK,
paulo@0 46 GrabModeAsync, GrabModeSync, None, None);
paulo@0 47 XGrabButton(dpy, Button2, MODKEY | numlockmask | LockMask, c->win, False, BUTTONMASK,
paulo@0 48 GrabModeAsync, GrabModeSync, None, None);
paulo@0 49
paulo@0 50 XGrabButton(dpy, Button3, MODKEY, c->win, False, BUTTONMASK,
paulo@0 51 GrabModeAsync, GrabModeSync, None, None);
paulo@0 52 XGrabButton(dpy, Button3, MODKEY | LockMask, c->win, False, BUTTONMASK,
paulo@0 53 GrabModeAsync, GrabModeSync, None, None);
paulo@0 54 XGrabButton(dpy, Button3, MODKEY | numlockmask, c->win, False, BUTTONMASK,
paulo@0 55 GrabModeAsync, GrabModeSync, None, None);
paulo@0 56 XGrabButton(dpy, Button3, MODKEY | numlockmask | LockMask, c->win, False, BUTTONMASK,
paulo@0 57 GrabModeAsync, GrabModeSync, None, None);
paulo@0 58 }
paulo@0 59 else
paulo@0 60 XGrabButton(dpy, AnyButton, AnyModifier, c->win, False, BUTTONMASK,
paulo@0 61 GrabModeAsync, GrabModeSync, None, None);
paulo@0 62 }
paulo@0 63
paulo@0 64 static Bool
paulo@0 65 isprotodel(Client *c) {
paulo@0 66 int i, n;
paulo@0 67 Atom *protocols;
paulo@0 68 Bool ret = False;
paulo@0 69
paulo@0 70 if(XGetWMProtocols(dpy, c->win, &protocols, &n)) {
paulo@0 71 for(i = 0; !ret && i < n; i++)
paulo@0 72 if(protocols[i] == wmatom[WMDelete])
paulo@0 73 ret = True;
paulo@0 74 XFree(protocols);
paulo@0 75 }
paulo@0 76 return ret;
paulo@0 77 }
paulo@0 78
paulo@0 79 static void
paulo@0 80 setclientstate(Client *c, long state) {
paulo@0 81 long data[] = {state, None};
paulo@0 82
paulo@0 83 XChangeProperty(dpy, c->win, wmatom[WMState], wmatom[WMState], 32,
paulo@0 84 PropModeReplace, (unsigned char *)data, 2);
paulo@0 85 }
paulo@0 86
paulo@0 87 static void
paulo@0 88 togglemax(Client *c) {
paulo@0 89 XEvent ev;
paulo@0 90
paulo@0 91 if(c->isfixed)
paulo@0 92 return;
paulo@0 93 if((c->ismax = !c->ismax)) {
paulo@0 94 c->rx = c->x;
paulo@0 95 c->ry = c->y;
paulo@0 96 c->rw = c->w;
paulo@0 97 c->rh = c->h;
paulo@0 98 resize(c, wax, way, waw - 2 * BORDERPX, wah - 2 * BORDERPX, True);
paulo@0 99 }
paulo@0 100 else
paulo@0 101 resize(c, c->rx, c->ry, c->rw, c->rh, True);
paulo@0 102 while(XCheckMaskEvent(dpy, EnterWindowMask, &ev));
paulo@0 103 }
paulo@0 104
paulo@0 105 static int
paulo@0 106 xerrordummy(Display *dsply, XErrorEvent *ee) {
paulo@0 107 return 0;
paulo@0 108 }
paulo@0 109
paulo@0 110 /* extern */
paulo@0 111
paulo@0 112 void
paulo@0 113 attach(Client *c) {
paulo@0 114 if(clients)
paulo@0 115 clients->prev = c;
paulo@0 116 c->next = clients;
paulo@0 117 clients = c;
paulo@0 118 }
paulo@0 119
paulo@0 120 void
paulo@0 121 configure(Client *c) {
paulo@0 122 XConfigureEvent ce;
paulo@0 123
paulo@0 124 ce.type = ConfigureNotify;
paulo@0 125 ce.display = dpy;
paulo@0 126 ce.event = c->win;
paulo@0 127 ce.window = c->win;
paulo@0 128 ce.x = c->x;
paulo@0 129 ce.y = c->y;
paulo@0 130 ce.width = c->w;
paulo@0 131 ce.height = c->h;
paulo@0 132 ce.border_width = c->border;
paulo@0 133 ce.above = None;
paulo@0 134 ce.override_redirect = False;
paulo@0 135 XSendEvent(dpy, c->win, False, StructureNotifyMask, (XEvent *)&ce);
paulo@0 136 }
paulo@0 137
paulo@0 138 void
paulo@0 139 detach(Client *c) {
paulo@0 140 if(c->prev)
paulo@0 141 c->prev->next = c->next;
paulo@0 142 if(c->next)
paulo@0 143 c->next->prev = c->prev;
paulo@0 144 if(c == clients)
paulo@0 145 clients = c->next;
paulo@0 146 c->next = c->prev = NULL;
paulo@0 147 }
paulo@0 148
paulo@0 149 void
paulo@0 150 focus(Client *c) {
paulo@0 151 if(c && !isvisible(c))
paulo@0 152 return;
paulo@0 153 if(sel && sel != c) {
paulo@0 154 grabbuttons(sel, False);
paulo@0 155 XSetWindowBorder(dpy, sel->win, dc.norm[ColBorder]);
paulo@0 156 }
paulo@0 157 if(c) {
paulo@0 158 detachstack(c);
paulo@0 159 attachstack(c);
paulo@0 160 grabbuttons(c, True);
paulo@0 161 }
paulo@0 162 sel = c;
paulo@0 163 drawstatus();
paulo@0 164 if(!selscreen)
paulo@0 165 return;
paulo@0 166 if(c) {
paulo@0 167 XSetWindowBorder(dpy, c->win, dc.sel[ColBorder]);
paulo@0 168 XSetInputFocus(dpy, c->win, RevertToPointerRoot, CurrentTime);
paulo@0 169 }
paulo@0 170 else
paulo@0 171 XSetInputFocus(dpy, root, RevertToPointerRoot, CurrentTime);
paulo@0 172 }
paulo@0 173
paulo@0 174 void
paulo@0 175 killclient(Arg *arg) {
paulo@0 176 if(!sel)
paulo@0 177 return;
paulo@0 178 if(isprotodel(sel))
paulo@0 179 sendevent(sel->win, wmatom[WMProtocols], wmatom[WMDelete]);
paulo@0 180 else
paulo@0 181 XKillClient(dpy, sel->win);
paulo@0 182 }
paulo@0 183
paulo@0 184 void
paulo@0 185 manage(Window w, XWindowAttributes *wa) {
paulo@0 186 Client *c, *t;
paulo@0 187 Window trans;
paulo@0 188 XWindowChanges wc;
paulo@0 189
paulo@0 190 c = emallocz(sizeof(Client));
paulo@0 191 c->tags = emallocz(ntags * sizeof(Bool));
paulo@0 192 c->win = w;
paulo@0 193 c->x = wa->x;
paulo@0 194 c->y = wa->y;
paulo@0 195 c->w = wa->width;
paulo@0 196 c->h = wa->height;
paulo@0 197 if(c->w == sw && c->h == sh) {
paulo@0 198 c->border = 0;
paulo@0 199 c->x = sx;
paulo@0 200 c->y = sy;
paulo@0 201 }
paulo@0 202 else {
paulo@0 203 c->border = BORDERPX;
paulo@0 204 if(c->x > wax + waw && c-> w < waw)
paulo@0 205 c->x = wax + waw - c->w - 2 * c->border;
paulo@0 206 if(c->y > way + wah && c-> h < wah)
paulo@0 207 c->y = way + wah - c->h - 2 * c->border;
paulo@0 208 if(c->x < wax && c->w < waw)
paulo@0 209 c->x = wax;
paulo@0 210 if(c->y < way && c->h < wah)
paulo@0 211 c->y = way;
paulo@0 212 }
paulo@0 213 XSelectInput(dpy, w,
paulo@0 214 StructureNotifyMask | PropertyChangeMask | EnterWindowMask);
paulo@0 215 XGetTransientForHint(dpy, w, &trans);
paulo@0 216 grabbuttons(c, False);
paulo@0 217 wc.border_width = c->border;
paulo@0 218 XConfigureWindow(dpy, w, CWBorderWidth, &wc);
paulo@0 219 XSetWindowBorder(dpy, w, dc.norm[ColBorder]);
paulo@0 220 configure(c); /* propagates border_width, if size doesn't change */
paulo@0 221 updatetitle(c);
paulo@0 222 for(t = clients; t && t->win != trans; t = t->next);
paulo@0 223 settags(c, t);
paulo@0 224 if(!c->isversatile)
paulo@0 225 c->isversatile = (t != NULL) || c->isfixed;
paulo@0 226 attach(c);
paulo@0 227 attachstack(c);
paulo@0 228 c->isbanned = True;
paulo@0 229 XMoveWindow(dpy, w, c->x + 2 * sw, c->y);
paulo@0 230 XMapWindow(dpy, w);
paulo@0 231 setclientstate(c, NormalState);
paulo@0 232 if(isvisible(c))
paulo@0 233 focus(c);
paulo@0 234 updatesizehints(c);
paulo@0 235 lt->arrange();
paulo@0 236 }
paulo@0 237
paulo@0 238 void
paulo@0 239 resize(Client *c, int x, int y, int w, int h, Bool sizehints) {
paulo@0 240 float actual, dx, dy, max, min;
paulo@0 241 XWindowChanges wc;
paulo@0 242
paulo@0 243 if(w <= 0 || h <= 0)
paulo@0 244 return;
paulo@0 245 if(sizehints) {
paulo@0 246 if(c->minw && w < c->minw)
paulo@0 247 w = c->minw;
paulo@0 248 if(c->minh && h < c->minh)
paulo@0 249 h = c->minh;
paulo@0 250 if(c->maxw && w > c->maxw)
paulo@0 251 w = c->maxw;
paulo@0 252 if(c->maxh && h > c->maxh)
paulo@0 253 h = c->maxh;
paulo@0 254 /* inspired by algorithm from fluxbox */
paulo@0 255 if(c->minay > 0 && c->maxay && (h - c->baseh) > 0) {
paulo@0 256 dx = (float)(w - c->basew);
paulo@0 257 dy = (float)(h - c->baseh);
paulo@0 258 min = (float)(c->minax) / (float)(c->minay);
paulo@0 259 max = (float)(c->maxax) / (float)(c->maxay);
paulo@0 260 actual = dx / dy;
paulo@0 261 if(max > 0 && min > 0 && actual > 0) {
paulo@0 262 if(actual < min) {
paulo@0 263 dy = (dx * min + dy) / (min * min + 1);
paulo@0 264 dx = dy * min;
paulo@0 265 w = (int)dx + c->basew;
paulo@0 266 h = (int)dy + c->baseh;
paulo@0 267 }
paulo@0 268 else if(actual > max) {
paulo@0 269 dy = (dx * min + dy) / (max * max + 1);
paulo@0 270 dx = dy * min;
paulo@0 271 w = (int)dx + c->basew;
paulo@0 272 h = (int)dy + c->baseh;
paulo@0 273 }
paulo@0 274 }
paulo@0 275 }
paulo@0 276 if(c->incw)
paulo@0 277 w -= (w - c->basew) % c->incw;
paulo@0 278 if(c->inch)
paulo@0 279 h -= (h - c->baseh) % c->inch;
paulo@0 280 }
paulo@0 281 if(w == sw && h == sh)
paulo@0 282 c->border = 0;
paulo@0 283 else
paulo@0 284 c->border = BORDERPX;
paulo@0 285 /* offscreen appearance fixes */
paulo@0 286 if(x > sw)
paulo@0 287 x = sw - w - 2 * c->border;
paulo@0 288 if(y > sh)
paulo@0 289 y = sh - h - 2 * c->border;
paulo@0 290 if(x + w + 2 * c->border < sx)
paulo@0 291 x = sx;
paulo@0 292 if(y + h + 2 * c->border < sy)
paulo@0 293 y = sy;
paulo@0 294 /* if(c->x != x || c->y != y || c->w != w || c->h != h) { */
paulo@0 295 c->x = wc.x = x;
paulo@0 296 c->y = wc.y = y;
paulo@0 297 c->w = wc.width = w;
paulo@0 298 c->h = wc.height = h;
paulo@0 299 wc.border_width = c->border;
paulo@0 300 XConfigureWindow(dpy, c->win, CWX | CWY | CWWidth | CWHeight | CWBorderWidth, &wc);
paulo@0 301 configure(c);
paulo@0 302 XSync(dpy, False);
paulo@0 303 /* } */
paulo@0 304 }
paulo@0 305
paulo@0 306 void
paulo@0 307 toggleversatile(Arg *arg) {
paulo@0 308 if(!sel || lt->arrange == versatile)
paulo@0 309 return;
paulo@0 310 sel->isversatile = !sel->isversatile;
paulo@0 311 lt->arrange();
paulo@0 312 }
paulo@0 313
paulo@0 314 void
paulo@0 315 updatesizehints(Client *c) {
paulo@0 316 long msize;
paulo@0 317 XSizeHints size;
paulo@0 318
paulo@0 319 if(!XGetWMNormalHints(dpy, c->win, &size, &msize) || !size.flags)
paulo@0 320 size.flags = PSize;
paulo@0 321 c->flags = size.flags;
paulo@0 322 if(c->flags & PBaseSize) {
paulo@0 323 c->basew = size.base_width;
paulo@0 324 c->baseh = size.base_height;
paulo@0 325 }
paulo@0 326 else
paulo@0 327 c->basew = c->baseh = 0;
paulo@0 328 if(c->flags & PResizeInc) {
paulo@0 329 c->incw = size.width_inc;
paulo@0 330 c->inch = size.height_inc;
paulo@0 331 }
paulo@0 332 else
paulo@0 333 c->incw = c->inch = 0;
paulo@0 334 if(c->flags & PMaxSize) {
paulo@0 335 c->maxw = size.max_width;
paulo@0 336 c->maxh = size.max_height;
paulo@0 337 }
paulo@0 338 else
paulo@0 339 c->maxw = c->maxh = 0;
paulo@0 340 if(c->flags & PMinSize) {
paulo@0 341 c->minw = size.min_width;
paulo@0 342 c->minh = size.min_height;
paulo@0 343 }
paulo@0 344 else
paulo@0 345 c->minw = c->minh = 0;
paulo@0 346 if(c->flags & PAspect) {
paulo@0 347 c->minax = size.min_aspect.x;
paulo@0 348 c->minay = size.min_aspect.y;
paulo@0 349 c->maxax = size.max_aspect.x;
paulo@0 350 c->maxay = size.max_aspect.y;
paulo@0 351 }
paulo@0 352 else
paulo@0 353 c->minax = c->minay = c->maxax = c->maxay = 0;
paulo@0 354 c->isfixed = (c->maxw && c->minw && c->maxh && c->minh
paulo@0 355 && c->maxw == c->minw && c->maxh == c->minh);
paulo@0 356 }
paulo@0 357
paulo@0 358 void
paulo@0 359 updatetitle(Client *c) {
paulo@0 360 char **list = NULL;
paulo@0 361 int n;
paulo@0 362 XTextProperty name;
paulo@0 363
paulo@0 364 name.nitems = 0;
paulo@0 365 c->name[0] = 0;
paulo@0 366 XGetTextProperty(dpy, c->win, &name, netatom[NetWMName]);
paulo@0 367 if(!name.nitems)
paulo@0 368 XGetWMName(dpy, c->win, &name);
paulo@0 369 if(!name.nitems)
paulo@0 370 return;
paulo@0 371 if(name.encoding == XA_STRING)
paulo@0 372 strncpy(c->name, (char *)name.value, sizeof c->name);
paulo@0 373 else {
paulo@0 374 if(XmbTextPropertyToTextList(dpy, &name, &list, &n) >= Success
paulo@0 375 && n > 0 && *list)
paulo@0 376 {
paulo@0 377 strncpy(c->name, *list, sizeof c->name);
paulo@0 378 XFreeStringList(list);
paulo@0 379 }
paulo@0 380 }
paulo@0 381 XFree(name.value);
paulo@0 382 }
paulo@0 383
paulo@0 384 void
paulo@0 385 unmanage(Client *c) {
paulo@0 386 Client *nc;
paulo@0 387
paulo@0 388 /* The server grab construct avoids race conditions. */
paulo@0 389 XGrabServer(dpy);
paulo@0 390 XSetErrorHandler(xerrordummy);
paulo@0 391 detach(c);
paulo@0 392 detachstack(c);
paulo@0 393 if(sel == c) {
paulo@0 394 for(nc = stack; nc && !isvisible(nc); nc = nc->snext);
paulo@0 395 focus(nc);
paulo@0 396 }
paulo@0 397 XUngrabButton(dpy, AnyButton, AnyModifier, c->win);
paulo@0 398 setclientstate(c, WithdrawnState);
paulo@0 399 free(c->tags);
paulo@0 400 free(c);
paulo@0 401 XSync(dpy, False);
paulo@0 402 XSetErrorHandler(xerror);
paulo@0 403 XUngrabServer(dpy);
paulo@0 404 lt->arrange();
paulo@0 405 }
paulo@0 406
paulo@0 407 void
paulo@0 408 zoom(Arg *arg) {
paulo@0 409 unsigned int n;
paulo@0 410 Client *c;
paulo@0 411
paulo@0 412 if(!sel)
paulo@0 413 return;
paulo@0 414 if(sel->isversatile || (lt->arrange == versatile)) {
paulo@0 415 togglemax(sel);
paulo@0 416 return;
paulo@0 417 }
paulo@0 418 for(n = 0, c = nexttiled(clients); c; c = nexttiled(c->next))
paulo@0 419 n++;
paulo@0 420 if((c = sel) == nexttiled(clients))
paulo@0 421 if(!(c = nexttiled(c->next)))
paulo@0 422 return;
paulo@0 423 detach(c);
paulo@0 424 attach(c);
paulo@0 425 focus(c);
paulo@0 426 lt->arrange();
paulo@0 427 }
paulo@0 428
paulo@0 429 Client *
paulo@0 430 prevtiled(Client *c) {
paulo@0 431 for(; c && (c->isversatile || !isvisible(c)); c = c->prev);
paulo@0 432 return c;
paulo@0 433 }
paulo@0 434
paulo@0 435 void
paulo@0 436 pushup(Arg *arg) {
paulo@0 437 Client *c;
paulo@0 438
paulo@0 439 if(!sel || sel->isversatile)
paulo@0 440 return;
paulo@0 441 if((c = prevtiled(sel->prev))) {
paulo@0 442 /* attach before c */
paulo@0 443 detach(sel);
paulo@0 444 sel->next = c;
paulo@0 445 sel->prev = c->prev;
paulo@0 446 c->prev = sel;
paulo@0 447 if(sel->prev)
paulo@0 448 sel->prev->next = sel;
paulo@0 449 else
paulo@0 450 clients = sel;
paulo@0 451 } else {
paulo@0 452 /* move to the end */
paulo@0 453 for(c = sel; c->next; c = c->next);
paulo@0 454 detach(sel);
paulo@0 455 sel->prev = c;
paulo@0 456 c->next = sel;
paulo@0 457 }
paulo@0 458 focus(sel);
paulo@0 459 lt->arrange();
paulo@0 460 }
paulo@0 461
paulo@0 462 void
paulo@0 463 pushdown(Arg *arg) {
paulo@0 464 Client *c;
paulo@0 465
paulo@0 466 if(!sel || sel->isversatile)
paulo@0 467 return;
paulo@0 468 if((c = nexttiled(sel->next))) {
paulo@0 469 /* attach after c */
paulo@0 470 detach(sel);
paulo@0 471 sel->prev = c;
paulo@0 472 sel->next = c->next;
paulo@0 473 c->next = sel;
paulo@0 474 if(sel->next)
paulo@0 475 sel->next->prev = sel;
paulo@0 476 } else {
paulo@0 477 /* move to the front */
paulo@0 478 detach(sel);
paulo@0 479 attach(sel);
paulo@0 480 }
paulo@0 481 focus(sel);
paulo@0 482 lt->arrange();
paulo@0 483 }
paulo@0 484
paulo@0 485 void
paulo@0 486 moveresize(Arg *arg) {
paulo@0 487 int x, y, w, h, nx, ny, nw, nh, ox, oy, ow, oh;
paulo@0 488 char xAbs, yAbs, wAbs, hAbs;
paulo@0 489 int mx, my, dx, dy, nmx, nmy;
paulo@0 490 unsigned int dui;
paulo@0 491 Window dummy;
paulo@0 492
paulo@0 493 if (lt->arrange != versatile)
paulo@0 494 if (!sel || !sel->isversatile || !arg)
paulo@0 495 return;
paulo@0 496 if(sscanf(arg->cmd, "%d%c %d%c %d%c %d%c", &x, &xAbs, &y, &yAbs, &w, &wAbs, &h, &hAbs) != 8)
paulo@0 497 return;
paulo@0 498 nx = xAbs == 'X' ? x : sel->x + x;
paulo@0 499 ny = yAbs == 'Y' ? y : sel->y + y;
paulo@0 500 nw = wAbs == 'W' ? w : sel->w + w;
paulo@0 501 nh = hAbs == 'H' ? h : sel->h + h;
paulo@0 502
paulo@0 503 ox = sel->x;
paulo@0 504 oy = sel->y;
paulo@0 505 ow = sel->w;
paulo@0 506 oh = sel->h;
paulo@0 507
paulo@0 508 Bool xqp = XQueryPointer(dpy, root, &dummy, &dummy, &mx, &my, &dx, &dy, &dui);
paulo@0 509 resize(sel, nx, ny, nw, nh, True);
paulo@0 510 if (xqp && ox <= mx && (ox + ow) >= mx && oy <= my && (oy + oh) >= my)
paulo@0 511 {
paulo@0 512 nmx = mx-ox+sel->w-ow-1 < 0 ? 0 : mx-ox+sel->w-ow-1;
paulo@0 513 nmy = my-oy+sel->h-oh-1 < 0 ? 0 : my-oy+sel->h-oh-1;
paulo@0 514 XWarpPointer(dpy, None, sel->win, 0, 0, 0, 0, nmx, nmy);
paulo@0 515 }
paulo@0 516 }
paulo@0 517