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(¤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 }