xzoom.c - xzoom - A simple screen magnifier for X11.
 (HTM) git clone git://r-36.net/xzoom
 (DIR) Log
 (DIR) Files
 (DIR) Refs
       ---
       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(&current_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 }