xzoom.c (20211B)
1 /* Copyright Itai Nahshon 1995, 1996. 2 This program is distributed with no warranty. 3 4 Source files for this program may be distributed freely. 5 Modifications to this file are okay as long as: 6 a. This copyright notice and comment are preserved and 7 left at the top of the file. 8 b. The man page is fixed to reflect the change. 9 c. The author of this change adds his name and change 10 description to the list of changes below. 11 Executable files may be distributed with sources, or with 12 exact location where the source code can be obtained. 13 14 Changelist: 15 Author Description 16 ------ ----------- 17 Itai Nahshon Version 0.1, Nov. 21 1995 18 Itai Nahshon Version 0.2, Apr. 17 1996 19 include <sys/types.h> 20 Use memmove() instead of memcopy() 21 Optional macro to replace call to usleep(). 22 Markus F.X.J. Oberhumer Version 0.4, Feb. 18 1998 23 split into 2 files (scale.h) 24 added support for 15, 16, 24 and 32 bpp displays 25 added a grid (press key 'g') 26 optimized scaling routines 27 use memcpy() instead of memmove() ;-) 28 some other minor changes/fixes 29 tony mancill 2002/02/13 <tmancill@debian.org> 30 hacked in support for WM_DELETE_WINDOW 31 */ 32 33 #include <stdio.h> 34 #include <string.h> 35 #include <stdlib.h> 36 #include <sys/types.h> 37 #include <sys/signal.h> 38 39 #include <X11/Xlib.h> 40 #include <X11/Xatom.h> 41 #include <X11/Xutil.h> 42 43 #ifdef XSHM 44 #include <sys/ipc.h> 45 #include <sys/shm.h> 46 #include <X11/extensions/XShm.h> 47 #endif 48 49 #include <X11/cursorfont.h> 50 #include <X11/keysym.h> 51 52 #ifdef TIMER 53 #include <sys/time.h> 54 #include <unistd.h> 55 #endif 56 57 Display *dpy; 58 Screen *scr; 59 Window win; 60 Atom wm_delete_window; 61 Atom wm_protocols; 62 Atom wm_dock; 63 Atom wm_windowtype; 64 Status status; 65 66 GC gc; 67 #ifdef FRAME 68 GC framegc; 69 #endif 70 71 #ifdef TIMER 72 Font font; 73 struct timeval old_time; 74 #endif 75 76 Cursor when_button; 77 Cursor crosshair; 78 79 char *progname; 80 int set_title; 81 82 #define SRC 0 /* index for source image */ 83 #define DST 1 /* index for dest image */ 84 85 #define WIDTH 256 /* default width */ 86 #define HEIGHT 256 /* default height */ 87 88 #define MAG 2 /* default magnification */ 89 #define MAGX MAG /* horizontal magnification */ 90 #define MAGY MAG /* vertical magnification */ 91 92 int xgrab, ygrab; /* where do we take the picture from */ 93 94 int magx = MAGX; 95 int magy = MAGY; 96 97 int flipxy = False; /* flip x and y */ 98 int flipx = False; /* flip display about y axis */ 99 int flipy = False; /* flip display about x axiz */ 100 101 int xzoom_flag = False; /* next mag change only to magx */ 102 int yzoom_flag = False; /* next mag change only to magy */ 103 104 int gridx = False; 105 int gridy = False; 106 107 int width[2] = { 0, WIDTH }; 108 int height[2] = { 0, HEIGHT }; 109 unsigned depth = 0; 110 111 #ifdef XSHM 112 XShmSegmentInfo shminfo[2]; /* Segment info. */ 113 #endif 114 XImage *ximage[2]; /* Ximage struct. */ 115 116 int created_images = False; 117 118 #define NDELAYS 5 119 120 int delays[NDELAYS] = { 200000, 100000, 50000, 10000, 0 }; 121 int delay_index = 0; 122 int delay = 200000; /* 0.2 second between updates */ 123 124 void 125 timeout_func(int signum) { 126 set_title = True; 127 signum = signum; /* UNUSED */ 128 } 129 130 void 131 allocate_images(void) { 132 int i; 133 134 for(i = 0; i < 2; i++) { 135 136 #ifdef XSHM 137 ximage[i] = XShmCreateImage(dpy, 138 DefaultVisualOfScreen(scr), 139 DefaultDepthOfScreen(scr), 140 ZPixmap, NULL, &shminfo[i], 141 width[i], height[i]); 142 143 if(ximage[i] == NULL) { 144 perror("XShmCreateImage"); 145 exit(-1); 146 } 147 148 shminfo[i].shmid = shmget(IPC_PRIVATE, 149 (unsigned int)(ximage[i]->bytes_per_line * ximage[i]->height), 150 IPC_CREAT | 0777); 151 152 if(shminfo[i].shmid < 0) { 153 perror("shmget"); 154 exit(-1); 155 } 156 157 shminfo[i].shmaddr = (char *)shmat(shminfo[i].shmid, 0, 0); 158 159 if (shminfo[i].shmaddr == ((char *) -1)) { 160 perror("shmat"); 161 exit(-1); 162 } 163 164 #ifdef DEBUG 165 fprintf(stderr, "new shared memory segment at 0x%08x size %d\n", 166 shminfo[i].shmaddr, ximage[i]->bytes_per_line * ximage[i]->height); 167 #endif 168 169 ximage[i]->data = shminfo[i].shmaddr; 170 shminfo[i].readOnly = False; 171 172 XShmAttach(dpy, &shminfo[i]); 173 XSync(dpy, False); 174 175 shmctl(shminfo[i].shmid, IPC_RMID, 0); 176 #else 177 char *data; 178 data = malloc(BitmapUnit(dpy) / 8 * width[i] * height[i]); 179 180 ximage[i] = XCreateImage(dpy, 181 DefaultVisualOfScreen(scr), 182 DefaultDepthOfScreen(scr), 183 ZPixmap, 0, data, 184 width[i], height[i], 32, 0); 185 186 if(ximage[i] == NULL) { 187 perror("XCreateImage"); 188 exit(-1); 189 } 190 191 #endif /* XSHM */ 192 } 193 created_images = True; 194 } 195 196 void 197 destroy_images(void) { 198 int i; 199 200 if (!created_images) 201 return; 202 203 for(i = 0; i < 2; i++) { 204 #ifdef XSHM 205 XShmDetach(dpy, &shminfo[i]); /* ask X11 to detach shared segment */ 206 shmdt(shminfo[i].shmaddr); /* detach it ourselves */ 207 #else 208 free(ximage[i]->data); 209 #endif 210 ximage[i]->data = NULL; /* remove refrence to that address */ 211 XDestroyImage(ximage[i]); /* and destroy image */ 212 } 213 214 created_images = False; 215 } 216 217 void 218 Usage(void) { 219 fprintf(stderr, "Usage: %s [ args ]\n" 220 "Command line args:\n" 221 "-display displayname\n" 222 "-mag magnification [ magnification ]\n" 223 "-geometry geometry\n" 224 "-source geometry\n" 225 "-dock\n" 226 "-x\n" 227 "-y\n" 228 "-xy\n\n" 229 "Window commands:\n" 230 "+: Zoom in\n" 231 "-: Zoom out\n" 232 "x: Flip right and left\n" 233 "y: Flip top and bottom\n" 234 "z: Rotate 90 degrees counter-clockwize\n" 235 "w: Next '+' or '-' only change width scaling\n" 236 "h: Next '+' or '-' only change height scaling\n" 237 "d: Change delay between frames\n" 238 "q: Quit\n" 239 "Arrow keys: Scroll in direction of arrow\n" 240 "Mouse button drag: Set top-left corner of viewed area\n", 241 progname); 242 exit(1); 243 } 244 245 /* resize is called with the dest size. 246 we call it then manification changes or when 247 actual window size is changed */ 248 void 249 resize(int new_width, int new_height) { 250 251 destroy_images(); /* we can get rid of these */ 252 253 /* find new dimensions for source */ 254 255 if(flipxy) { 256 height[SRC] = (new_width+magx-1) / magx; 257 width[SRC] = (new_height+magy-1) / magy; 258 } 259 else { 260 width[SRC] = (new_width+magx-1) / magx; 261 height[SRC] = (new_height+magy-1) / magy; 262 } 263 264 if(width[SRC] < 1) 265 width[SRC] = 1; 266 if(width[SRC] > WidthOfScreen(scr)) 267 width[SRC] = WidthOfScreen(scr); 268 269 if(height[SRC] < 1) 270 height[SRC] = 1; 271 if(height[SRC] > HeightOfScreen(scr)) 272 height[SRC] = HeightOfScreen(scr); 273 274 /* temporary, the dest image may be larger than the 275 actual window */ 276 if(flipxy) { 277 width[DST] = magx * height[SRC]; 278 height[DST] = magy * width[SRC]; 279 } 280 else { 281 width[DST] = magx * width[SRC]; 282 height[DST] = magy * height[SRC]; 283 } 284 285 allocate_images(); /* allocate new images */ 286 287 /* remember actual window size */ 288 if(width[DST] > new_width) 289 width[DST] = new_width; 290 if(height[DST] > new_height) 291 height[DST] = new_height; 292 } 293 294 295 void scale8(void) 296 { 297 #define T unsigned char 298 #include "scale.h" 299 #undef T 300 } 301 302 303 void scale16(void) 304 { 305 #define T unsigned short 306 #include "scale.h" 307 #undef T 308 } 309 310 311 void scale32(void) 312 { 313 #define T unsigned int 314 #include "scale.h" 315 #undef T 316 } 317 318 319 void xzoom(int buttonpressed) 320 { 321 char title[80]; 322 323 #ifdef XSHM 324 XShmGetImage(dpy, RootWindowOfScreen(scr), ximage[SRC], 325 xgrab, ygrab, AllPlanes); 326 #else 327 XGetSubImage(dpy, RootWindowOfScreen(scr), 328 xgrab, ygrab, width[SRC], height[SRC], AllPlanes, 329 ZPixmap, ximage[SRC], 0, 0); 330 #endif 331 #ifdef FRAME 332 if(buttonpressed) { /* show the frame */ 333 XDrawRectangle(dpy, RootWindowOfScreen(scr), framegc, xgrab, ygrab, width[SRC]-1, height[SRC]-1); 334 XSync(dpy, False); 335 } 336 #endif 337 338 if (depth == 8) 339 scale8(); 340 else if (depth <= 8*sizeof(short)) 341 scale16(); 342 else if (depth <= 8*sizeof(int)) 343 scale32(); 344 345 #ifdef XSHM 346 XShmPutImage(dpy, win, gc, ximage[DST], 0, 0, 0, 0, width[DST], height[DST], False); 347 #else 348 XPutImage(dpy, win, gc, ximage[DST], 0, 0, 0, 0, width[DST], height[DST]); 349 #endif 350 if(set_title) { 351 if(magx == magy && !flipx && !flipy && !flipxy) 352 sprintf(title, "%s x%d", progname, magx); 353 else 354 sprintf(title, "%s X %s%d%s Y %s%d", 355 progname, 356 flipx?"-":"", magx, 357 flipxy?" <=>":";", 358 flipy?"-":"", magy); 359 XChangeProperty(dpy, win, XA_WM_NAME, XA_STRING, 8, 360 PropModeReplace, 361 (unsigned char *)title, strlen(title)); 362 set_title = False; 363 } 364 #ifdef TIMER 365 { 366 struct timeval current_time; 367 double DT; 368 369 gettimeofday(¤t_time, NULL); 370 DT = current_time.tv_sec - old_time.tv_sec; 371 DT += 1e-6*(current_time.tv_usec - old_time.tv_usec); 372 sprintf(title, "DT=%6.3f", DT); 373 XDrawString(dpy, win, gc, 20, 20, title, strlen(title)); 374 old_time = current_time; 375 } 376 #endif 377 XSync(dpy, 0); 378 } 379 380 int 381 main(int argc, char **argv) { 382 XSetWindowAttributes xswa; 383 XEvent event; 384 XTextProperty str; 385 XSizeHints *sizeh = NULL; 386 XClassHint *ch; 387 int buttonpressed = False; 388 int visible = False; 389 int scroll = 1; 390 char title[80]; 391 XGCValues gcv; 392 char *dpyname = NULL; 393 int source_geom_mask = NoValue, 394 dest_geom_mask = NoValue, 395 copy_from_src_mask; 396 int xpos = 0, ypos = 0; 397 int isdock = 0; 398 399 atexit(destroy_images); 400 progname = strrchr(argv[0], '/'); 401 if(progname) 402 ++progname; 403 else 404 progname = argv[0]; 405 406 /* parse command line options */ 407 while(--argc > 0) { 408 ++argv; 409 410 if(argv[0][0] == '=') { 411 dest_geom_mask = XParseGeometry(argv[0], 412 &xpos, &ypos, 413 &width[DST], &height[DST]); 414 continue; 415 } 416 417 if(!strcmp(argv[0], "-mag")) { 418 ++argv; --argc; 419 420 magx = argc > 0 ? atoi(argv[0]) : -1; 421 422 if(magx <= 0) 423 Usage(); 424 425 426 magy = argc > 1 ? atoi(argv[1]) : -1; 427 428 if(magy <= 0) 429 magy = magx; 430 else { 431 ++argv; --argc; 432 } 433 434 continue; 435 } 436 437 if(!strcmp(argv[0], "-x")) { 438 flipx = True; 439 continue; 440 } 441 442 if(!strcmp(argv[0], "-y")) { 443 flipy = True; 444 continue; 445 } 446 447 if(!strcmp(argv[0], "-z") || 448 !strcmp(argv[0], "-xy")) { 449 flipxy = True; 450 continue; 451 } 452 453 if(!strcmp(argv[0], "-source")) { 454 ++argv; --argc; 455 456 if(argc < 1) 457 Usage(); 458 459 source_geom_mask = XParseGeometry(argv[0], 460 &xgrab, &ygrab, 461 &width[SRC], &height[SRC]); 462 463 continue; 464 } 465 466 if(!strcmp(argv[0], "-dest") || 467 !strcmp(argv[0], "-geometry")) { 468 ++argv; --argc; 469 470 if(argc < 1) 471 Usage(); 472 473 dest_geom_mask = XParseGeometry(argv[0], 474 &xpos, &ypos, 475 &width[DST], &height[DST]); 476 477 continue; 478 } 479 480 if(!strcmp(argv[0], "-d") || 481 !strcmp(argv[0], "-display")) { 482 483 ++argv; --argc; 484 485 if(argc < 1) 486 Usage(); 487 488 dpyname = argv[0]; 489 continue; 490 } 491 492 if(!strcmp(argv[0], "-delay")) { 493 494 ++argv; --argc; 495 496 if(argc < 1) 497 Usage(); 498 499 if(sscanf(argv[0], "%u", &delay) != 1) 500 Usage(); 501 502 delay *= 1000; 503 504 continue; 505 } 506 507 if(!strcmp(argv[0], "-dock")) { 508 509 isdock = 1; 510 511 continue; 512 } 513 514 Usage(); 515 } 516 517 if (!(dpy = XOpenDisplay(dpyname))) { 518 perror("Cannot open display"); 519 exit(-1); 520 } 521 522 /* Now, see if we have to calculate width[DST] and height[DST] 523 from the SRC parameters */ 524 525 copy_from_src_mask = NoValue; 526 527 if(source_geom_mask & WidthValue) { 528 if(flipxy) { 529 height[DST] = magy * width[SRC]; 530 copy_from_src_mask |= HeightValue; 531 532 } 533 else { 534 width[DST] = magx * width[SRC]; 535 copy_from_src_mask |= WidthValue; 536 } 537 } 538 539 if(source_geom_mask & HeightValue) { 540 if(flipxy) { 541 width[DST] = magx * height[SRC]; 542 copy_from_src_mask |= WidthValue; 543 } 544 else { 545 height[DST] = magy * height[SRC]; 546 copy_from_src_mask |= HeightValue; 547 } 548 } 549 550 if(copy_from_src_mask & dest_geom_mask) { 551 fprintf(stderr, "Conflicting dimensions between source and dest geometry\n"); 552 Usage(); 553 } 554 555 scr = DefaultScreenOfDisplay(dpy); 556 557 depth = DefaultDepthOfScreen(scr); 558 if (depth < 8) { 559 fprintf(stderr, "%s: need at least 8 bits/pixel\n", progname); 560 exit(1); 561 } 562 563 if(source_geom_mask & XNegative) 564 xgrab += WidthOfScreen(scr); 565 566 if(source_geom_mask & YNegative) 567 ygrab += HeightOfScreen(scr); 568 569 if(dest_geom_mask & XNegative) 570 xpos += WidthOfScreen(scr); 571 572 if(dest_geom_mask & YNegative) 573 ypos += HeightOfScreen(scr); 574 575 printf("=%dx%d+%d+%d\n", width[DST], height[DST], xpos, ypos); 576 577 xswa.event_mask = ButtonPressMask|ButtonReleaseMask|ButtonMotionMask; 578 xswa.event_mask |= StructureNotifyMask; /* resize etc.. */ 579 xswa.event_mask |= KeyPressMask|KeyReleaseMask; /* commands */ 580 xswa.event_mask |= VisibilityChangeMask; 581 582 xswa.background_pixel = BlackPixelOfScreen(scr); 583 584 win = XCreateWindow(dpy, RootWindowOfScreen(scr), 585 xpos, ypos, width[DST], height[DST], 0, 586 DefaultDepthOfScreen(scr), InputOutput, 587 DefaultVisualOfScreen(scr), 588 CWEventMask | CWBackPixel, &xswa); 589 590 XChangeProperty(dpy, win, XA_WM_ICON_NAME, XA_STRING, 8, 591 PropModeReplace, 592 (unsigned char *)progname, strlen(progname)); 593 594 if(!isdock) { 595 sizeh = XAllocSizeHints(); 596 sizeh->flags = PMaxSize | PMinSize; 597 sizeh->min_width = sizeh->max_width = width[DST]; 598 sizeh->min_height = sizeh->max_height = height[DST]; 599 } 600 XStringListToTextProperty(&progname, 1, &str); 601 ch = XAllocClassHint(); 602 ch->res_class = progname; 603 ch->res_name = progname; 604 605 XSetWMProperties(dpy, win, &str, &str, NULL, 0, sizeh, NULL, ch); 606 607 if(isdock) { 608 wm_windowtype = XInternAtom(dpy, "_NET_WM_WINDOW_TYPE", False); 609 wm_dock = XInternAtom(dpy, "_NET_WM_WINDOW_TYPE_DOCK", False); 610 611 XChangeProperty(dpy, win, wm_windowtype, XA_ATOM, 32, 612 PropModeReplace, (unsigned char *)&wm_dock, 613 1); 614 } 615 616 /* 617 XChangeProperty(dpy, win, XA_WM_NAME, XA_STRING, 8, 618 PropModeReplace, 619 (unsigned char *)progname, strlen(progname)); 620 */ 621 622 623 /*** 20020213 624 code added by <tmancill@debian.org> to handle 625 window manager "close" event 626 ***/ 627 wm_delete_window = XInternAtom (dpy, "WM_DELETE_WINDOW", False); 628 wm_protocols = XInternAtom(dpy, "WM_PROTOCOLS", False); 629 status = XSetWMProtocols(dpy, win, &wm_delete_window, 1); 630 631 set_title = True; 632 633 status = XMapWindow(dpy, win); 634 635 gcv.plane_mask = AllPlanes; 636 gcv.subwindow_mode = IncludeInferiors; 637 gcv.function = GXcopy; 638 gcv.foreground = WhitePixelOfScreen(scr); 639 gcv.background = BlackPixelOfScreen(scr); 640 gc = XCreateGC(dpy, RootWindowOfScreen(scr), 641 GCFunction|GCPlaneMask|GCSubwindowMode|GCForeground|GCBackground, 642 &gcv); 643 644 #ifdef FRAME 645 gcv.foreground = AllPlanes; 646 gcv.plane_mask = WhitePixelOfScreen(scr)^BlackPixelOfScreen(scr); 647 gcv.subwindow_mode = IncludeInferiors; 648 gcv.function = GXxor; 649 framegc = XCreateGC(dpy, RootWindowOfScreen(scr), 650 GCFunction|GCPlaneMask|GCSubwindowMode|GCForeground, 651 &gcv); 652 #endif 653 654 #ifdef TIMER 655 font = XLoadFont(dpy, "fixed"); 656 #endif 657 658 resize(width[DST], height[DST]); 659 660 #ifdef FRAME 661 662 { 663 static char bitmap_data[] = { 0 }; 664 static XColor col = { 0 }; 665 Pixmap curs = XCreatePixmapFromBitmapData(dpy, 666 RootWindowOfScreen(scr), bitmap_data, 1, 1, 0, 0, 1); 667 668 when_button = XCreatePixmapCursor(dpy, curs, curs, &col, &col, 0, 0); 669 } 670 #else 671 when_button = XCreateFontCursor(dpy, XC_ul_angle); 672 #endif 673 crosshair = XCreateFontCursor(dpy, XC_crosshair); 674 675 XDefineCursor(dpy, win, crosshair); 676 677 for(;;) { 678 679 /***** 680 old event loop updated to support WM messages 681 while(unmapped? 682 (XWindowEvent(dpy, win, (long)-1, &event), 1): 683 XCheckWindowEvent(dpy, win, (long)-1, &event)) { 684 ******/ 685 686 while(XPending(dpy)) { 687 XNextEvent(dpy, &event); 688 switch(event.type) { 689 case ClientMessage: 690 if ((event.xclient.message_type == wm_protocols) && 691 (event.xclient.data.l[0] == wm_delete_window)) { 692 exit(0); 693 } 694 break; 695 case ConfigureNotify: 696 if(event.xconfigure.width != width[DST] || 697 event.xconfigure.height != height[DST]) { 698 699 resize(event.xconfigure.width, event.xconfigure.height); 700 } 701 break; 702 case ReparentNotify: 703 break; /* what do we do with it? */ 704 705 case VisibilityNotify: 706 /* VisibilityUnobscured, VisibilityPartiallyObscured, or VisibilityFullyObscured */ 707 visible = (event.xvisibility.state!=VisibilityFullyObscured); 708 break; 709 710 case KeyRelease: 711 switch(XKeycodeToKeysym(dpy, event.xkey.keycode, 0)) { 712 case XK_Control_L: 713 case XK_Control_R: 714 scroll = 1; 715 break; 716 } 717 break; 718 719 case KeyPress: 720 switch(XKeycodeToKeysym(dpy, event.xkey.keycode, 0)) { 721 case XK_Control_L: 722 case XK_Control_R: 723 scroll = 10; 724 break; 725 726 case '+': 727 case '=': 728 case XK_KP_Add: 729 if(!yzoom_flag) ++magx; 730 if(!xzoom_flag) ++magy; 731 xzoom_flag = yzoom_flag = False; 732 resize(width[DST], height[DST]); 733 set_title = True; 734 break; 735 736 case '-': 737 case XK_KP_Subtract: 738 if(!yzoom_flag) --magx; 739 if(!xzoom_flag) --magy; 740 xzoom_flag = yzoom_flag = False; 741 if(magx < 1) magx = 1; 742 if(magy < 1) magy = 1; 743 resize(width[DST], height[DST]); 744 set_title = True; 745 break; 746 747 case XK_Left: 748 case XK_KP_Left: 749 if(flipxy) 750 if(flipx) 751 ygrab += scroll; 752 else 753 ygrab -= scroll; 754 else 755 if(flipx) 756 xgrab += scroll; 757 else 758 xgrab -= scroll; 759 break; 760 761 case XK_Right: 762 case XK_KP_Right: 763 if(flipxy) 764 if(flipx) 765 ygrab -= scroll; 766 else 767 ygrab += scroll; 768 else 769 if(flipx) 770 xgrab -= scroll; 771 else 772 xgrab += scroll; 773 break; 774 775 case XK_Up: 776 case XK_KP_Up: 777 if(flipxy) 778 if(flipy) 779 xgrab -= scroll; 780 else 781 xgrab += scroll; 782 else 783 if(flipy) 784 ygrab += scroll; 785 else 786 ygrab -= scroll; 787 break; 788 789 case XK_Down: 790 case XK_KP_Down: 791 if(flipxy) 792 if(flipy) 793 xgrab += scroll; 794 else 795 xgrab -= scroll; 796 else 797 if(flipy) 798 ygrab -= scroll; 799 else 800 ygrab += scroll; 801 break; 802 803 case 'x': 804 flipx = !flipx; 805 set_title = True; 806 break; 807 808 case 'y': 809 flipy = !flipy; 810 set_title = True; 811 break; 812 813 case 'z': 814 if(flipx^flipy^flipxy) { 815 flipx = !flipx; 816 flipy = !flipy; 817 } 818 flipxy = !flipxy; 819 resize(width[DST], height[DST]); 820 set_title = True; 821 break; 822 823 case 'w': 824 xzoom_flag = True; 825 yzoom_flag = False; 826 break; 827 828 case 'h': 829 yzoom_flag = True; 830 xzoom_flag = False; 831 break; 832 833 case 'g': 834 gridx = !gridx; 835 gridy = !gridy; 836 break; 837 838 case 'd': 839 if(++delay_index >= NDELAYS) 840 delay_index = 0; 841 delay = delays[delay_index]; 842 sprintf(title, "delay = %d ms", delay/1000); 843 XChangeProperty(dpy, win, XA_WM_NAME, XA_STRING, 8, 844 PropModeReplace, 845 (unsigned char *)title, strlen(title)); 846 signal(SIGALRM, timeout_func); 847 alarm(2); 848 break; 849 850 case 'q': 851 exit(0); 852 break; 853 } 854 855 break; 856 857 case ButtonPress: 858 #ifdef FRAME 859 xgrab = event.xbutton.x_root - width[SRC]/2; 860 ygrab = event.xbutton.y_root - height[SRC]/2; 861 #else 862 xgrab = event.xbutton.x_root; 863 ygrab = event.xbutton.y_root; 864 #endif 865 XDefineCursor(dpy, win, when_button); 866 buttonpressed = True; 867 break; 868 869 case ButtonRelease: 870 /* 871 xgrab = event.xbutton.x_root - width[SRC]/2; 872 ygrab = event.xbutton.y_root - height[SRC]/2; 873 */ 874 XDefineCursor(dpy, win, crosshair); 875 buttonpressed = False; 876 break; 877 878 case MotionNotify: 879 if(buttonpressed) { 880 #ifdef FRAME 881 xgrab = event.xmotion.x_root - width[SRC]/2; 882 ygrab = event.xmotion.y_root - height[SRC]/2; 883 #else 884 xgrab = event.xmotion.x_root; 885 ygrab = event.xmotion.y_root; 886 #endif 887 } 888 break; 889 890 } 891 892 /* trying XShmGetImage when part of the rect is 893 not on the screen will fail LOUDLY.. 894 we have to veryfy this after anything that may 895 may modified xgrab or ygrab or the size of 896 the source ximage */ 897 898 if(xgrab < 0) 899 xgrab = 0; 900 901 if(xgrab > WidthOfScreen(scr)-width[SRC]) 902 xgrab = WidthOfScreen(scr)-width[SRC]; 903 904 if(ygrab < 0) 905 ygrab = 0; 906 907 if(ygrab > HeightOfScreen(scr)-height[SRC]) 908 ygrab = HeightOfScreen(scr)-height[SRC]; 909 910 } 911 912 if(visible) 913 xzoom(buttonpressed); 914 915 #ifdef NO_USLEEP 916 #define usleep(_t) \ 917 { \ 918 struct timeval timeout; \ 919 timeout.tv_sec = 0; \ 920 timeout.tv_usec = _t; \ 921 select(0, NULL, NULL, NULL, &timeout); \ 922 } 923 #endif 924 925 if(!buttonpressed && delay > 0) 926 usleep(delay); 927 #ifdef FRAME 928 if(buttonpressed) { 929 XDrawRectangle(dpy, RootWindowOfScreen(scr), 930 framegc, xgrab, ygrab, width[SRC]-1, 931 height[SRC]-1); 932 } 933 #endif 934 } 935 }