annotate keynav.c @ 0:ab8a496afb67

initial hg commit of my version of keynav
author paulo@thepaulopc
date Tue, 08 Sep 2009 22:45:57 -0700
parents
children 0d5dc7c29c78
rev   line source
paulo@0 1 /*
paulo@0 2 * Visual user-directed binary search for something to point your mouse at.
paulo@0 3 */
paulo@0 4
paulo@0 5 #include "config.h"
paulo@0 6
paulo@0 7 #include <stdio.h>
paulo@0 8 #include <stdlib.h>
paulo@0 9 #include <string.h>
paulo@0 10
paulo@0 11 #include <X11/Xlib.h>
paulo@0 12 #include <X11/Xresource.h>
paulo@0 13 #include <X11/Xutil.h>
paulo@0 14 #include <X11/extensions/shape.h>
paulo@0 15 #include <X11/extensions/XTest.h>
paulo@0 16
paulo@0 17 Display *dpy;
paulo@0 18 Window root;
paulo@0 19 XWindowAttributes attr;
paulo@0 20 int drag = 0;
paulo@0 21 int allmoves = 0;
paulo@0 22 int allhits = 0;
paulo@0 23 int allclicks = 0;
paulo@0 24 int ninegrid_default = 0;
paulo@0 25 int ninegrid_n_switch = 0;
paulo@0 26 int ninegrid = 0;
paulo@0 27
paulo@0 28 struct /* undo stack */
paulo@0 29 {
paulo@0 30 int x[N_UNDO];
paulo@0 31 int y[N_UNDO];
paulo@0 32 int w[N_UNDO];
paulo@0 33 int h[N_UNDO];
paulo@0 34 int ninegrid[N_UNDO];
paulo@0 35 } u;
paulo@0 36
paulo@0 37 void toggleninegrid() {
paulo@0 38 if (ninegrid)
paulo@0 39 ninegrid = 0;
paulo@0 40 else
paulo@0 41 ninegrid = 1;
paulo@0 42 }
paulo@0 43
paulo@0 44 void stats(int hits, int moves) {
paulo@0 45 allhits += hits;
paulo@0 46 allmoves += moves;
paulo@0 47 allclicks++;
paulo@0 48 printf("hits=%d, moves=%d \n", hits, moves);
paulo@0 49 printf("total hits=%d, total moves=%d, total clicks=%d, avg. hit/click=%.2f, avg. moves/click=%.2f \n", allhits, allmoves, allclicks, (float)allhits/(float)allclicks, (float)allmoves/(float)allclicks);
paulo@0 50 fflush(stdout); fflush(stderr); // force buffers to write out
paulo@0 51 }
paulo@0 52
paulo@0 53 void grab(char *keyname, int mods) {
paulo@0 54 int key;
paulo@0 55
paulo@0 56 key = XKeysymToKeycode(dpy, XStringToKeysym(keyname));
paulo@0 57 XGrabKey(dpy, key, mods, root, False,
paulo@0 58 GrabModeAsync, GrabModeAsync);
paulo@0 59 XGrabKey(dpy, key, mods | CAPSLOCKMASK, root, False,
paulo@0 60 GrabModeAsync, GrabModeAsync);
paulo@0 61 XGrabKey(dpy, key, mods | NUMLOCKMASK, root, False,
paulo@0 62 GrabModeAsync, GrabModeAsync);
paulo@0 63 XGrabKey(dpy, key, mods | CAPSLOCKMASK | NUMLOCKMASK, root, False,
paulo@0 64 GrabModeAsync, GrabModeAsync);
paulo@0 65 }
paulo@0 66
paulo@0 67 void ungrab(char *keyname, int mod) {
paulo@0 68 int key;
paulo@0 69
paulo@0 70 key = XKeysymToKeycode(dpy, XStringToKeysym(keyname));
paulo@0 71 XUngrabKey(dpy, key, mod, root);
paulo@0 72 XUngrabKey(dpy, key, mod | CAPSLOCKMASK, root);
paulo@0 73 XUngrabKey(dpy, key, mod | NUMLOCKMASK, root);
paulo@0 74 XUngrabKey(dpy, key, mod | CAPSLOCKMASK | NUMLOCKMASK, root);
paulo@0 75 }
paulo@0 76
paulo@0 77 void buttondown(int i) {
paulo@0 78 XTestFakeButtonEvent(dpy, i, True, 50);
paulo@0 79 }
paulo@0 80
paulo@0 81 void buttonup(int i) {
paulo@0 82 XTestFakeButtonEvent(dpy, i, False, 50);
paulo@0 83 }
paulo@0 84
paulo@0 85 void warppointer(int x, int y, int w, int h) {
paulo@0 86 XWarpPointer(dpy, None, root, 0, 0, 0, 0, x + w/2, y + h/2);
paulo@0 87 }
paulo@0 88
paulo@0 89 /* operations for undo */
paulo@0 90 void undo_stack_push(int x, int y, int w, int h) {
paulo@0 91 int i;
paulo@0 92
paulo@0 93 if (x >= 0 && y >= 0 && w > 0 && h > 0) {
paulo@0 94 fprintf(stderr,"undo_stack_push success: @(%d,%d) #(%d,%d)\n", x, y, w, h);
paulo@0 95 for (i=N_UNDO-1; i>0; i--) {
paulo@0 96 u.x[i] = u.x[i-1];
paulo@0 97 u.y[i] = u.y[i-1];
paulo@0 98 u.w[i] = u.w[i-1];
paulo@0 99 u.h[i] = u.h[i-1];
paulo@0 100 u.ninegrid[i] = u.ninegrid[i-1];
paulo@0 101 }
paulo@0 102 u.x[0] = x;
paulo@0 103 u.y[0] = y;
paulo@0 104 u.w[0] = w;
paulo@0 105 u.h[0] = h;
paulo@0 106 u.ninegrid[0] = ninegrid;
paulo@0 107 }
paulo@0 108 }
paulo@0 109
paulo@0 110 int undo_stack_pop(int *x, int *y, int *w, int *h, int *ninegrid) {
paulo@0 111 int i;
paulo@0 112 int ret = 0;
paulo@0 113
paulo@0 114 int rx = u.x[0];
paulo@0 115 int ry = u.y[0];
paulo@0 116 int rw = u.w[0];
paulo@0 117 int rh = u.h[0];
paulo@0 118 int rninegrid = u.ninegrid[0];
paulo@0 119
paulo@0 120 if (rx >= 0 && ry >= 0 && rw > 0 && rh > 0) {
paulo@0 121 fprintf(stderr,"undo_stack_pop success: @(%d,%d) #(%d,%d)\n", *x, *y, *w, *h);
paulo@0 122 ret = 1; // return success
paulo@0 123 for (i=0; i<N_UNDO-1; i++) {
paulo@0 124 u.x[i] = u.x[i+1];
paulo@0 125 u.y[i] = u.y[i+1];
paulo@0 126 u.w[i] = u.w[i+1];
paulo@0 127 u.h[i] = u.h[i+1];
paulo@0 128 u.ninegrid[i] = u.ninegrid[i+1];
paulo@0 129 }
paulo@0 130 u.x[N_UNDO-1] = -1;
paulo@0 131 u.y[N_UNDO-1] = -1;
paulo@0 132 u.w[N_UNDO-1] = -1;
paulo@0 133 u.h[N_UNDO-1] = -1;
paulo@0 134 u.ninegrid[N_UNDO-1] = -1;
paulo@0 135 *x = rx;
paulo@0 136 *y = ry;
paulo@0 137 *w = rw;
paulo@0 138 *h = rh;
paulo@0 139 *ninegrid = rninegrid;
paulo@0 140 }
paulo@0 141 return ret;
paulo@0 142 }
paulo@0 143
paulo@0 144 void undo_stack_reset() {
paulo@0 145 int i;
paulo@0 146
paulo@0 147 for (i=0; i<N_UNDO; i++) {
paulo@0 148 u.x[i] = -1;
paulo@0 149 u.y[i] = -1;
paulo@0 150 u.w[i] = -1;
paulo@0 151 u.h[i] = -1;
paulo@0 152 }
paulo@0 153 }
paulo@0 154 /* =-=-=-=-=-= */
paulo@0 155
paulo@0 156 int chk_keysym(int keysym, char *str) {
paulo@0 157 int ret = 0;
paulo@0 158
paulo@0 159 if (XStringToKeysym(str) == keysym)
paulo@0 160 ret = 1;
paulo@0 161
paulo@0 162 return ret;
paulo@0 163 }
paulo@0 164
paulo@0 165 GC creategc(Window win) {
paulo@0 166 GC gc;
paulo@0 167 XGCValues values;
paulo@0 168
paulo@0 169 gc = XCreateGC(dpy, win, 0, &values);
paulo@0 170 XSetForeground(dpy, gc, BlackPixel(dpy, 0));
paulo@0 171 XSetBackground(dpy, gc, WhitePixel(dpy, 0));
paulo@0 172 XSetLineAttributes(dpy, gc, LINEWIDTH, LineSolid, CapButt, JoinBevel);
paulo@0 173 XSetFillStyle(dpy, gc, FillSolid);
paulo@0 174
paulo@0 175 return gc;
paulo@0 176 }
paulo@0 177
paulo@0 178 void drawquadrants(Window win, int w, int h) {
paulo@0 179 GC gc;
paulo@0 180 XRectangle clip[20];
paulo@0 181 int idx = 0;
paulo@0 182 Colormap colormap;
paulo@0 183 XColor color;
paulo@0 184
paulo@0 185 gc = creategc(win);
paulo@0 186 colormap = DefaultColormap(dpy, 0);
paulo@0 187
paulo@0 188 if (drag)
paulo@0 189 XAllocNamedColor(dpy, colormap, DRAG_COLOR, &color, &color);
paulo@0 190 else
paulo@0 191 XAllocNamedColor(dpy, colormap, NORM_COLOR, &color, &color);
paulo@0 192
paulo@0 193 /*left*/ clip[idx].x = 0; clip[idx].y = 0; clip[idx].width = BORDER; clip[idx].height = h;
paulo@0 194 idx++;
paulo@0 195 /*right*/ clip[idx].x = w-BORDER; clip[idx].y = 0; clip[idx].width = BORDER; clip[idx].height = h;
paulo@0 196 idx++;
paulo@0 197 /*top*/ clip[idx].x = 0; clip[idx].y = 0; clip[idx].width = w; clip[idx].height = BORDER;
paulo@0 198 idx++;
paulo@0 199 /*bottom*/ clip[idx].x = 0; clip[idx].y = h-BORDER; clip[idx].width = w; clip[idx].height = BORDER;
paulo@0 200 idx++;
paulo@0 201
paulo@0 202 if (ninegrid) {
paulo@0 203 /*1st horiz*/
paulo@0 204 clip[idx].x = 0; clip[idx].y = h/3 - BORDER/2;
paulo@0 205 clip[idx].width = w; clip[idx].height = BORDER;
paulo@0 206 idx++;
paulo@0 207 /*2nd horiz*/
paulo@0 208 clip[idx].x = 0; clip[idx].y = h*2/3 - BORDER/2;
paulo@0 209 clip[idx].width = w; clip[idx].height = BORDER;
paulo@0 210 idx++;
paulo@0 211 /*1st vert*/
paulo@0 212 clip[idx].x = w/3 - BORDER/2; clip[idx].y = 0;
paulo@0 213 clip[idx].width = BORDER; clip[idx].height = h;
paulo@0 214 idx++;
paulo@0 215 /*2nd vert*/
paulo@0 216 clip[idx].x = w*2/3 - BORDER/2; clip[idx].y = 0;
paulo@0 217 clip[idx].width = BORDER; clip[idx].height = h;
paulo@0 218 idx++;
paulo@0 219 } else {
paulo@0 220 /*horiz*/
paulo@0 221 clip[idx].x = 0; clip[idx].y = h/2 - BORDER/2;
paulo@0 222 clip[idx].width = w; clip[idx].height = BORDER;
paulo@0 223 idx++;
paulo@0 224 /*vert*/
paulo@0 225 clip[idx].x = w/2 - BORDER/2; clip[idx].y = 0;
paulo@0 226 clip[idx].width = BORDER; clip[idx].height = h;
paulo@0 227 idx++;
paulo@0 228 }
paulo@0 229
paulo@0 230 XShapeCombineRectangles(dpy, win, ShapeBounding, 0, 0, clip, idx, ShapeSet, 0);
paulo@0 231
paulo@0 232 XFillRectangle(dpy, win, gc, 0, 0, w, h);
paulo@0 233
paulo@0 234 XSetForeground(dpy, gc, color.pixel);
paulo@0 235 XDrawLine(dpy, win, gc, BORDER - PEN, BORDER - PEN, w - PEN, BORDER - PEN); //top line
paulo@0 236 XDrawLine(dpy, win, gc, BORDER - PEN, h - PEN, w - PEN, h - PEN); //bottom line
paulo@0 237 XDrawLine(dpy, win, gc, BORDER - PEN, BORDER - PEN, BORDER - PEN, h - PEN); //left line
paulo@0 238 XDrawLine(dpy, win, gc, w - PEN, BORDER - PEN, w - PEN, h - PEN); //left line
paulo@0 239
paulo@0 240 if (ninegrid) {
paulo@0 241 XDrawLine(dpy, win, gc, w/3, 0, w/3, h); // 1st vert line
paulo@0 242 XDrawLine(dpy, win, gc, w*2/3, 0, w*2/3, h); // 2nd vert line
paulo@0 243 XDrawLine(dpy, win, gc, 0, h/3, w, h/3); // 1st horiz line
paulo@0 244 XDrawLine(dpy, win, gc, 0, h*2/3, w, h*2/3); // 2nd horiz line
paulo@0 245 } else {
paulo@0 246 XDrawLine(dpy, win, gc, w/2, 0, w/2, h); // vert line
paulo@0 247 XDrawLine(dpy, win, gc, 0, h/2, w, h/2); // horiz line
paulo@0 248 }
paulo@0 249
paulo@0 250 XFlush(dpy);
paulo@0 251 }
paulo@0 252
paulo@0 253 int handlekey(int keysym, int mod, int *moves, int *x, int *y, int *w, int *h) {
paulo@0 254 int ret = 1;
paulo@0 255 int ox = *x;
paulo@0 256 int oy = *y;
paulo@0 257 int ow = *w;
paulo@0 258 int oh = *h;;
paulo@0 259
paulo@0 260 if (mod & SHIFTMASK || mod & SHIFTMASK & NUMLOCKMASK || mod & SHIFTMASK & CAPSLOCKMASK || mod & SHIFTMASK & CAPSLOCKMASK & NUMLOCKMASK) {
paulo@0 261 if (chk_keysym(keysym, KEY_CENTER))
paulo@0 262 toggleninegrid();
paulo@0 263 if (chk_keysym(keysym, KEY_LEFT) || chk_keysym(keysym, KEY_UPLEFT) || chk_keysym(keysym, KEY_DOWNLEFT)) {
paulo@0 264 if (*x > 0) *x -= *w; // shift left
paulo@0 265 }
paulo@0 266 if (chk_keysym(keysym, KEY_DOWN) || chk_keysym(keysym, KEY_DOWNLEFT) || chk_keysym(keysym, KEY_DOWNRIGHT)) {
paulo@0 267 if ((*y + *h) < attr.height) *y += *h; // shift down
paulo@0 268 }
paulo@0 269 if (chk_keysym(keysym, KEY_UP) || chk_keysym(keysym, KEY_UPLEFT) || chk_keysym(keysym, KEY_UPRIGHT)) {
paulo@0 270 if (*y > 0) *y -= *h; // shift up
paulo@0 271 }
paulo@0 272 if (chk_keysym(keysym, KEY_RIGHT) || chk_keysym(keysym, KEY_UPRIGHT) || chk_keysym(keysym, KEY_DOWNRIGHT)) {
paulo@0 273 if ((*x + *w) < attr.width) *x += *w; // shift right
paulo@0 274 }
paulo@0 275 } else {
paulo@0 276 if (ninegrid) {
paulo@0 277 if (chk_keysym(keysym, KEY_UPLEFT)) {
paulo@0 278 *w /= 3; *h /= 3; // split upper left
paulo@0 279 } else if (chk_keysym(keysym, KEY_UP)) {
paulo@0 280 *w /= 3; *h /= 3; // split up
paulo@0 281 *x += *w;
paulo@0 282 } else if (chk_keysym(keysym, KEY_UPRIGHT)) {
paulo@0 283 *w /= 3; *h /= 3; // split upper right
paulo@0 284 *x += *w * 2;
paulo@0 285 } else if (chk_keysym(keysym, KEY_LEFT)) {
paulo@0 286 *w /= 3; *h /= 3; // split left
paulo@0 287 *y += *h;
paulo@0 288 } else if (chk_keysym(keysym, KEY_CENTER)) {
paulo@0 289 *w /= 3; *h /= 3; // split center
paulo@0 290 *x += *w; *y += *h;
paulo@0 291 } else if (chk_keysym(keysym, KEY_RIGHT)) {
paulo@0 292 *w /= 3; *h /= 3; // split right
paulo@0 293 *x += *w * 2; *y += *h;
paulo@0 294 } else if (chk_keysym(keysym, KEY_DOWNLEFT)) {
paulo@0 295 *w /= 3; *h /= 3; // split bottom left
paulo@0 296 *y += *h * 2;
paulo@0 297 } else if (chk_keysym(keysym, KEY_DOWN)) {
paulo@0 298 *w /= 3; *h /= 3; // split down
paulo@0 299 *x += *w; *y += *h * 2;
paulo@0 300 } else if (chk_keysym(keysym, KEY_DOWNRIGHT)) {
paulo@0 301 *w /= 3; *h /= 3; // split bottom right
paulo@0 302 *x += *w * 2; *y += *h * 2;
paulo@0 303 }
paulo@0 304 } else {
paulo@0 305 if (chk_keysym(keysym, KEY_LEFT) || chk_keysym(keysym, KEY_UPLEFT) || chk_keysym(keysym, KEY_DOWNLEFT)) {
paulo@0 306 *w /= 2; // split left
paulo@0 307 }
paulo@0 308 if (chk_keysym(keysym, KEY_DOWN) || chk_keysym(keysym, KEY_DOWNLEFT) || chk_keysym(keysym, KEY_DOWNRIGHT)) {
paulo@0 309 *h /= 2; // split down
paulo@0 310 *y += *h;
paulo@0 311 }
paulo@0 312 if (chk_keysym(keysym, KEY_UP) || chk_keysym(keysym, KEY_UPLEFT) || chk_keysym(keysym, KEY_UPRIGHT)) {
paulo@0 313 *h /= 2; // split up
paulo@0 314 }
paulo@0 315 if (chk_keysym(keysym, KEY_RIGHT) || chk_keysym(keysym, KEY_UPRIGHT) || chk_keysym(keysym, KEY_DOWNRIGHT)) {
paulo@0 316 *w /= 2; // split right
paulo@0 317 *x += *w;
paulo@0 318 }
paulo@0 319 }
paulo@0 320 }
paulo@0 321
paulo@0 322 if (ox != *x || oy != *y || ow != *w || oh != *h) {
paulo@0 323 undo_stack_push(ox, oy, ow, oh);
paulo@0 324 *moves += 1;
paulo@0 325 }
paulo@0 326 else if (chk_keysym(keysym, KEY_UNDO)) {
paulo@0 327 int i, j;
paulo@0 328
paulo@0 329 if (mod & SHIFTMASK) j = 0;
paulo@0 330 else j = SHIFT_N_UNDO-1;
paulo@0 331
paulo@0 332 for (i=j; i<SHIFT_N_UNDO; i++) {
paulo@0 333 undo_stack_pop(x, y, w, h, &ninegrid);
paulo@0 334 *moves -= 1;
paulo@0 335 }
paulo@0 336 ret = 2;
paulo@0 337 }
paulo@0 338
paulo@0 339 if (*w < 1 || *h < 1) {
paulo@0 340 fprintf(stderr,"OOPS. Area too small. Giving up :(\n");
paulo@0 341 return 0;
paulo@0 342 }
paulo@0 343
paulo@0 344 if (drag && !(mod & WARPMASK) || !drag && (mod & WARPMASK))
paulo@0 345 warppointer(*x, *y, *w, *h);
paulo@0 346
paulo@0 347 fprintf(stderr,"Box: @(%d,%d) #(%d,%d)\n", *x, *y, *w, *h);
paulo@0 348
paulo@0 349 return ret;
paulo@0 350 }
paulo@0 351
paulo@0 352 void startmousekey(int from_undo) {
paulo@0 353 int keysym;
paulo@0 354 int done = 0;
paulo@0 355 int x,y,w,h;
paulo@0 356 int warp = 0;
paulo@0 357 int click = 0;
paulo@0 358 int k, hits, moves;
paulo@0 359 int mod;
paulo@0 360
paulo@0 361 Window zone;
paulo@0 362
paulo@0 363 // disable trigger keygrab
paulo@0 364 ungrab(KEY_TRIGGER, TRIGGERMASK);
paulo@0 365 ungrab(KEY_UNDO, TRIGGERMASK);
paulo@0 366
paulo@0 367 // grab keyboard
paulo@0 368 XGrabKeyboard(dpy, root, False, GrabModeAsync, GrabModeAsync, CurrentTime);
paulo@0 369
paulo@0 370 // init stuff
paulo@0 371 hits = moves = 0;
paulo@0 372 if (from_undo && undo_stack_pop(&x, &y, &w, &h, &ninegrid));
paulo@0 373 /* null -- only check for undo_stack_pop success */
paulo@0 374 else {
paulo@0 375 undo_stack_reset();
paulo@0 376 if (ninegrid_default)
paulo@0 377 ninegrid = 1;
paulo@0 378 x = y = 0;
paulo@0 379 w = attr.width;
paulo@0 380 h = attr.height;
paulo@0 381 }
paulo@0 382
paulo@0 383 zone = XCreateSimpleWindow(dpy, root, x, y, w, h, 1, BlackPixel(dpy, 0), WhitePixel(dpy, 0));
paulo@0 384
paulo@0 385 { /* Tell the window manager not to manage us */
paulo@0 386 unsigned long valuemask;
paulo@0 387 XSetWindowAttributes winattr;
paulo@0 388 winattr.override_redirect = 1;
paulo@0 389 XChangeWindowAttributes(dpy, zone, CWOverrideRedirect, &winattr);
paulo@0 390 }
paulo@0 391
paulo@0 392 drawquadrants(zone, w, h);
paulo@0 393 XMapWindow(dpy, zone);
paulo@0 394 drawquadrants(zone, w, h);
paulo@0 395
paulo@0 396 fprintf(stderr,"Starting quadrants...\n");
paulo@0 397 while (!done) {
paulo@0 398 XEvent e;
paulo@0 399 XNextEvent(dpy, &e);
paulo@0 400 if (e.type == KeyPress) {
paulo@0 401 keysym = XKeycodeToKeysym(dpy, e.xkey.keycode, 0);
paulo@0 402 mod = e.xkey.state;
paulo@0 403 if (chk_keysym(keysym, KEY_Q_CLICK)) {
paulo@0 404 done++;
paulo@0 405 click = 1;
paulo@0 406 } else if (chk_keysym(keysym, KEY_Q_RCLICK)) {
paulo@0 407 done++;
paulo@0 408 click = 3;
paulo@0 409 } else if (chk_keysym(keysym, KEY_QW_CLICK)) {
paulo@0 410 done++;
paulo@0 411 warp = 1;
paulo@0 412 click = 1;
paulo@0 413 } else if (chk_keysym(keysym, KEY_Q_MCLICK)) {
paulo@0 414 done++;
paulo@0 415 click = 2;
paulo@0 416 } else if (chk_keysym(keysym, KEY_QW_RCLICK)) {
paulo@0 417 done++;
paulo@0 418 warp = 1;
paulo@0 419 click = 3;
paulo@0 420 } else if (chk_keysym(keysym, KEY_HIDE)) {
paulo@0 421 done++;
paulo@0 422 warp = 1;
paulo@0 423 x = w; y = h;
paulo@0 424 } else if (chk_keysym(keysym, KEY_ESCAPE)) {
paulo@0 425 warp = 0;
paulo@0 426 done++;
paulo@0 427 } else if (!drag && chk_keysym(keysym, KEY_ONE)) {
paulo@0 428 buttondown(1);
paulo@0 429 buttonup(1);
paulo@0 430 } else if (!drag && chk_keysym(keysym, KEY_TWO)) {
paulo@0 431 buttondown(2);
paulo@0 432 buttonup(2);
paulo@0 433 } else if (!drag && chk_keysym(keysym, KEY_THREE)) {
paulo@0 434 buttondown(3);
paulo@0 435 buttonup(3);
paulo@0 436 } else {
paulo@0 437 if (k = handlekey(keysym, mod, &moves, &x, &y, &w, &h)) {
paulo@0 438 if (ninegrid_default && ninegrid_n_switch && k < 2 && moves >= ninegrid_n_switch)
paulo@0 439 ninegrid = 0;
paulo@0 440 hits++;
paulo@0 441 XMoveResizeWindow(dpy, zone, x, y, w, h);
paulo@0 442 drawquadrants(zone, w, h);
paulo@0 443 } else
paulo@0 444 done++;
paulo@0 445 }
paulo@0 446 }
paulo@0 447 }
paulo@0 448
paulo@0 449 // end mouse key
paulo@0 450 XUngrabKeyboard(dpy, CurrentTime);
paulo@0 451 XDestroyWindow(dpy, zone);
paulo@0 452 undo_stack_push(x, y, w, h);
paulo@0 453
paulo@0 454 if (warp)
paulo@0 455 warppointer(x, y, w, h);
paulo@0 456 if (click == 1) {
paulo@0 457 if (!drag)
paulo@0 458 buttondown(1);
paulo@0 459 if (mod & DRAGMASK && !drag)
paulo@0 460 drag = 1;
paulo@0 461 else if (mod & DRAGMASK) {
paulo@0 462 buttonup(1);
paulo@0 463 buttondown(1);
paulo@0 464 } else {
paulo@0 465 buttonup(1);
paulo@0 466 drag = 0;
paulo@0 467 }
paulo@0 468 } else if (click) {
paulo@0 469 buttondown(click);
paulo@0 470 buttonup(click);
paulo@0 471 }
paulo@0 472
paulo@0 473 if (click) stats(hits, moves);
paulo@0 474
paulo@0 475 // loop back if in drag mode
paulo@0 476 if (drag) {
paulo@0 477 usleep(50);
paulo@0 478 startmousekey(0);
paulo@0 479 }
paulo@0 480
paulo@0 481 // re-enable trigger keygrabs
paulo@0 482 grab(KEY_TRIGGER, TRIGGERMASK);
paulo@0 483 grab(KEY_UNDO, TRIGGERMASK);
paulo@0 484 }
paulo@0 485
paulo@0 486 int main(int argc, char **argv) {
paulo@0 487 char *pcDisplay;
paulo@0 488
paulo@0 489 if ((dpy = XOpenDisplay(pcDisplay = getenv("DISPLAY"))) == NULL) {
paulo@0 490 fprintf(stderr,"Error: Can't open display: %s", pcDisplay);
paulo@0 491 exit(1);
paulo@0 492 }
paulo@0 493 fprintf(stderr,"Display: %s\n", pcDisplay);
paulo@0 494
paulo@0 495 // parse options
paulo@0 496 if (argc > 1)
paulo@0 497 if (argv[1][0] && argv[1][0] == '-')
paulo@0 498 if (argv[1][1] && argv[1][1] == 'n') {
paulo@0 499 ninegrid_default = 1;
paulo@0 500 fprintf(stderr,"nine-grid default mode \n");
paulo@0 501 if (argv[2]) {
paulo@0 502 ninegrid_n_switch = atoi(argv[2]);
paulo@0 503 fprintf(stderr,"nine-grid autoswitch num: %d \n", ninegrid_n_switch);
paulo@0 504 }
paulo@0 505 }
paulo@0 506
paulo@0 507 root = XDefaultRootWindow(dpy);
paulo@0 508 XGetWindowAttributes(dpy, root, &attr);
paulo@0 509
paulo@0 510 // these are the trigger keygrabs
paulo@0 511 grab(KEY_TRIGGER, TRIGGERMASK);
paulo@0 512 grab(KEY_UNDO, TRIGGERMASK);
paulo@0 513
paulo@0 514 while (1) {
paulo@0 515 XEvent e;
paulo@0 516 XNextEvent(dpy, &e);
paulo@0 517 if (e.type == KeyPress)
paulo@0 518 if (chk_keysym(XKeycodeToKeysym(dpy, e.xkey.keycode, 0), KEY_UNDO))
paulo@0 519 startmousekey(1);
paulo@0 520 else
paulo@0 521 startmousekey(0);
paulo@0 522 }
paulo@0 523 }