xzoom

A simple screen magnifier for X11.
git clone git://r-36.net/xzoom
Log | Files | Refs

commit 29cb8033f8cda420ff86769aa71d42af81b1b540
Author: Christoph Lohmann <20h@r-36.net>
Date:   Fri, 21 Oct 2011 10:29:00 +0200

Initial commit of xzoom 0.3 with 0.4.

Diffstat:
Imakefile | 25+++++++++++++++++++++++++
README | 29+++++++++++++++++++++++++++++
changelog | 178+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
copyright | 22++++++++++++++++++++++
scale.h | 102+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
xzoom.c | 894+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
xzoom.lsm | 18++++++++++++++++++
xzoom.man | 169+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
8 files changed, 1437 insertions(+), 0 deletions(-)

diff --git a/Imakefile b/Imakefile @@ -0,0 +1,25 @@ +#ifndef XCOMM +#define XCOMM # +#endif +XCOMM Imakefile for xzoom +XCOMM Copyright Itai Nahshon 1995, 1996 +XCOMM +XCOMM Valid compile time options: +XCOMM -DFRAME: source area is marked with a rectangular frame. +XCOMM -DXSHM: use X11 shared memory extension. +XCOMM -DTIMER: count time between window updates (just for testing). +XCOMM -DNO_USLEEP: for system that do not have the usleep function +XCOMM -DBCOPY: use bcopy() instead of memmove() + +XCOMM DEFINES = -DFRAME -DXSHM -DTIMER -DNO_USLEEP + +DEFINES = -DFRAME -DXSHM + +LOCAL_LIBRARIES = -lXext -lX11 -lXt + +NAME = xzoom + +BINDIR = /usr/bin +MANPATH = /usr/share/man + +SimpleProgramTarget($(NAME)) diff --git a/README b/README @@ -0,0 +1,29 @@ +This is xzoom 0.3. + +I got a few letters from people who tried xzoom-0.1. +I want to thank all these people for the responses. +Some people have requested to add features. Some +also suggested their own contribution. +I am sory that I could not satisfy all. I will try +to do so in the next releases. + +What's changed since release 0.1: + +Mainly I added command line options. With these +you can start xzoom and focus at any point in the screen +and at any magnification which you want. Look at the +man page for details. + +A second thing that you might have noticed is a memory +leak in 0.1 (funny, I did not get any mail about it). +As I finally found, the leak was due to some X events queing +up and not discarded. Finally I found the documentation +for XSHM in the X11R6 CDROM (disk 2, file +distrib/xc/doc/specs/Xext/mit-shm.ms). The MS macros +came from the BSD cdrom and with that help I could +find the bug and fix it. + +Plese send comments, requests, suggestions to +nahshon@best.com. + +Itai Nahshon diff --git a/changelog b/changelog @@ -0,0 +1,178 @@ +xzoom (0.3-23) unstable; urgency=low + + [ Anibal Avelar ] + * New mantainer + * Fixed the FTBFS bug added the xutils-dev dependency. + (Closes: #485733) + * Bumped to Standards-version 3.8.0. + * Added the Homepage field in the debian/control file. + * Cleaned the debian/copyright file with cosmetic changes. + + [ Piotr O┼╝arowski ] + * debian/watch file added + + -- Anibal Avelar <aavelar@cofradia.org> Sun, 15 Jun 2008 22:27:53 -0400 + +xzoom (0.3-22) unstable; urgency=low + + * Cap menu item. Closes: #438103 + + -- Joey Hess <joeyh@debian.org> Wed, 15 Aug 2007 13:29:53 -0400 + +xzoom (0.3-21) unstable; urgency=low + + * Maintaining this package again. + * Improve description, fix typos. + * Remove debian/pbuild-test directory, seems to be added by accident. + * De-dpatchify (personal preference). + * Clean up rules file. + * Remove various autogenerated files from source package, seems they were + added by accident. + * debhelper v5. + * The Apps/Tools menu is obsolete. Use Applications/Accessibility, + hope that's not too big a stretch. + * Remove CVS dirs from debian patch. + + -- Joey Hess <joeyh@debian.org> Tue, 07 Aug 2007 22:01:43 -0700 + +xzoom (0.3-20) unstable; urgency=low + + * orphan + + -- Junichi Uekawa <dancer@debian.org> Sat, 04 Aug 2007 09:37:51 +0900 + +xzoom (0.3-19) unstable; urgency=low + + * Standards-version: 3.7.2 + * debian/compat: 4 + + -- Junichi Uekawa <dancer@debian.org> Sat, 2 Sep 2006 19:42:17 +0900 + +xzoom (0.3-18) unstable; urgency=low + + * support for X11R7, and install to standard FHS locations. + (Closes: #364168). + * use dpatch. + * quote menu item string. + * Standards-version: 3.6.2 + + -- Junichi Uekawa <dancer@debian.org> Sat, 22 Apr 2006 12:50:12 +0900 + +xzoom (0.3-17) unstable; urgency=low + + * Bug fix: "xzoom: FTBFS: build-depends on removed xlibs-dev" + Changed to x-dev, libxext-dev, libxt-dev (Closes: #346867). + * Bug fix: "'man xzoom' typo: "magniications"", thanks to A + Costa (Closes: #306710). + * add simple test for resulting binary. + + -- Junichi Uekawa <dancer@debian.org> Mon, 9 Jan 2006 13:10:09 +0900 + +xzoom (0.3-16) unstable; urgency=low + + * New maintainer (closes: #202330) + * Standards-version: 3.6.0 + * Modified the package description. + + -- Junichi Uekawa <dancer@debian.org> Sat, 9 Aug 2003 07:38:11 +0900 + +xzoom (0.3-15) unstable; urgency=low + + * orphaned; set maintainer to packages@qa.debian.org + + -- tony mancill <tmancill@debian.org> Mon, 21 Jul 2003 15:46:51 -0700 + +xzoom (0.3-14) unstable; urgency=low + + * updated build-depends for sid (closes: #170185) + + -- tony mancill <tmancill@debian.org> Sat, 23 Nov 2002 16:04:04 -0800 + +xzoom (0.3-13) unstable; urgency=low + + * updated manpage (closes: #93253) + * hacked in WM_DELETE_WINDOW support (closes: #93250) + (you can now use standard window manager methods to close the client) + + -- tony mancill <tmancill@debian.org> Tue, 12 Feb 2002 22:59:09 -0800 + +xzoom (0.3-12) unstable; urgency=low + + * binaries built against xfree 4.x for woody release + + -- tony mancill <tmancill@debian.org> Mon, 26 Nov 2001 20:08:29 -0800 + +xzoom (0.3-11) unstable; urgency=low + + * new maintainer <tmancill@debian.org> (Closes: bug#69658) + + -- tony mancill <tmancill@debian.org> Mon, 28 Aug 2000 17:43:02 -0700 + +xzoom (0.3-10) unstable; urgency=low + + * Build deps. + + -- Joey Hess <joeyh@debian.org> Sat, 4 Dec 1999 18:42:28 -0800 + +xzoom (0.3-9) unstable; urgency=low + + * FHS + + -- Joey Hess <joeyh@debian.org> Sun, 12 Sep 1999 14:27:43 -0700 + +xzoom (0.3-8) unstable; urgency=low + + * Fixed package description: no longer limited to 8bpp. + * Documented the 'g' key in the man page. + + -- Joey Hess <joeyh@debian.org> Wed, 25 Feb 1998 11:09:59 -0800 + +xzoom (0.3-7) unstable; urgency=low + + * Added changes from Markus F.X.J. Oberhumer + <k3040e4@c210.edvz.uni-linz.ac.at>, for greater than 8 bpp support + plus some other features. + + -- Joey Hess <joeyh@debian.org> Thu, 19 Feb 1998 10:59:43 -0800 + +xzoom (0.3-6) unstable; urgency=low + + * Moved binary to /usr/X11R6/bin. + + -- Joey Hess <joeyh@debian.org> Mon, 9 Feb 1998 12:44:08 -0800 + +xzoom (0.3-5) unstable; urgency=low + + * Use debhelper. + + -- Joey Hess <joeyh@debian.org> Sat, 7 Feb 1998 20:48:22 -0800 + +xzoom (0.3-4) unstable; urgency=low + + * libc6. + * Routine update of debian/rules: + Fixed binary-indep target. + + -- Joey Hess <joeyh@debian.org> Mon, 8 Sep 1997 14:08:03 -0400 + +xzoom (0.3-3) unstable; urgency=low + + * Added note to description that it only works at 8bpp. + + -- Joey Hess <joeyh@debian.org> Thu, 5 Jun 1997 19:36:27 -0400 + +xzoom (0.3-2) unstable; urgency=low + + * Fixed man page permissions. (#10275) + * Moved man page to X11R6. + * Updated menu file to menu-1 format. + * Routine update of debian/rules: + Run dpkg-gencontrol after debstd, and delete substvars during clean. + + -- Joey Hess <joeyh@debian.org> Sun, 1 Jun 1997 14:12:42 -0400 + +xzoom (0.3-1) unstable; urgency=low + + * First release. + + -- Joey Hess <joeyh@debian.org> Sat, 8 Mar 1997 15:30:09 -0500 diff --git a/copyright b/copyright @@ -0,0 +1,22 @@ +This package was maintained by tony mancill <tmancill@debian.org>, for a +while, and then picked up by Junichi Uekawa <dancer@debian.org>. Since Sun, 15 Jun 2008 maintained by Anibal Avelar <aavelar@cofradia.org>. + +This package was put together by Joey Hess <joeyh@debian.org>, using +sources from: + ftp://sunsite.unc.edu/pub/linux/libs/X/xzoom-0.3.tgz + +Copyright: 1995-2008 Itai Nahshon + +License: + + This program is distributed with no warranty. + + Source files for this program may be distributed freely. + Modifications to this file are okay as long as: + a. This copyright notice and comment are preserved and + left at the top of the file. + b. The man page is fixed to reflect the change. + c. The author of this change adds his name and change + description to the list of changes below. + Executable files may be distributed with sources, or with + exact location where the source code can be obtained. diff --git a/scale.h b/scale.h @@ -0,0 +1,102 @@ +/* scale image from SRC to DST - parameterized by type T */ + +/* get pixel address of point (x,y) in image t */ +#define getP(t,x,y) \ + (T *) (&ximage[t]->data[(ximage[t]->xoffset+(x))*sizeof(T) + \ + (y)*ximage[t]->bytes_per_line]) + +{ + int i, j, k; + + /* copy scaled lines from SRC to DST */ + j = flipxy ? width[SRC] - 1 : height[SRC] - 1; + do { + T *p1; + T *p2; + int p2step; + T *p1_save; + + /* p1 point to begining of scanline j*magy in DST */ + p1 = getP(DST,0,j*magy); + p1_save = p1; + /* p2 point to begining of scanline j in SRC */ + /* if flipy then line height[SRC]-1-j */ + p2 = getP(SRC,0,flipy ? (height[SRC]-1-j) : j); + + if (flipxy) + { + p2 = getP(SRC,flipy ? j : (width[SRC]-1-j),0); + p2step = ximage[SRC]->bytes_per_line / sizeof(T); + + if (flipx) + { + p2 += p2step * (height[SRC]-1); + p2step = -p2step; + } + + i = height[SRC]; + do { + T c = *p2; p2 += p2step; + k = magx; do *p1++ = c; while (--k > 0); + } while (--i > 0); + } + else if (flipx) + { + p2 += width[SRC]; + i = width[SRC]; + do { + T c = *--p2; + k = magx; do *p1++ = c; while (--k > 0); + } while (--i > 0); + } + else + { + i = width[SRC]; + do { + T c = *p2++; + k = magx; do *p1++ = c; while (--k > 0); + } while (--i > 0); + } + + /* draw vertical grid */ + if (gridy && magx >= 2) + { + p1 = p1_save - 1; + i = magx; + k = flipxy ? height[SRC] : width[SRC]; + do { + p1 += i; + *p1 ^= ~((T)0); + } while (--k > 0); + } + + /* duplicate that line as needed */ + if (magy > 1) + { + /* p1 point to begining of scanline j*magy in DST */ + p1 = p1_save; + /* p2 points to begining of next line */ + p2 = p1; + p2step = ximage[DST]->bytes_per_line / sizeof(T); + + i = width[DST] * sizeof(T); + k = magy - 1; + do { + p2 += p2step; + memcpy(p2, p1, i); + } while (--k > 0); + + /* draw horizontal grid */ + if (gridx && magy >= 2) + { + k = width[DST]; + do { + *p2++ ^= ~((T)0); + } while (--k > 0); + } + } + } while (--j >= 0); +} + +#undef getP + diff --git a/xzoom.c b/xzoom.c @@ -0,0 +1,894 @@ +/* Copyright Itai Nahshon 1995, 1996. + This program is distributed with no warranty. + + Source files for this program may be distributed freely. + Modifications to this file are okay as long as: + a. This copyright notice and comment are preserved and + left at the top of the file. + b. The man page is fixed to reflect the change. + c. The author of this change adds his name and change + description to the list of changes below. + Executable files may be distributed with sources, or with + exact location where the source code can be obtained. + +Changelist: +Author Description +------ ----------- +Itai Nahshon Version 0.1, Nov. 21 1995 +Itai Nahshon Version 0.2, Apr. 17 1996 + include <sys/types.h> + Use memmove() instead of memcopy() + Optional macro to replace call to usleep(). +Markus F.X.J. Oberhumer Version 0.4, Feb. 18 1998 + split into 2 files (scale.h) + added support for 15, 16, 24 and 32 bpp displays + added a grid (press key 'g') + optimized scaling routines + use memcpy() instead of memmove() ;-) + some other minor changes/fixes +tony mancill 2002/02/13 <tmancill@debian.org> + hacked in support for WM_DELETE_WINDOW +*/ + +#include <stdio.h> +#include <string.h> +#include <stdlib.h> +#include <sys/types.h> +#include <sys/signal.h> + +#include <X11/Xlib.h> +#include <X11/Xatom.h> +#include <X11/Xutil.h> + +#ifdef XSHM +#include <sys/ipc.h> +#include <sys/shm.h> +#include <X11/extensions/XShm.h> +#endif + +#include <X11/cursorfont.h> +#include <X11/keysym.h> + +#ifdef TIMER +#include <sys/time.h> +#include <unistd.h> +#endif + +Display *dpy; +Screen *scr; +Window win; +Atom wm_delete_window; +Atom wm_protocols; +Status status; + +GC gc; +#ifdef FRAME +GC framegc; +#endif + +#ifdef TIMER +Font font; +struct timeval old_time; +#endif + +Cursor when_button; +Cursor crosshair; + +char *progname; +int set_title; + +#define SRC 0 /* index for source image */ +#define DST 1 /* index for dest image */ + +#define WIDTH 256 /* default width */ +#define HEIGHT 256 /* default height */ + +#define MAG 2 /* default magnification */ +#define MAGX MAG /* horizontal magnification */ +#define MAGY MAG /* vertical magnification */ + +int xgrab, ygrab; /* where do we take the picture from */ + +int magx = MAGX; +int magy = MAGY; + +int flipxy = False; /* flip x and y */ +int flipx = False; /* flip display about y axis */ +int flipy = False; /* flip display about x axiz */ + +int xzoom_flag = False; /* next mag change only to magx */ +int yzoom_flag = False; /* next mag change only to magy */ + +int gridx = False; +int gridy = False; + +int width[2] = { 0, WIDTH }; +int height[2] = { 0, HEIGHT }; +unsigned depth = 0; + +#ifdef XSHM +XShmSegmentInfo shminfo[2]; /* Segment info. */ +#endif +XImage *ximage[2]; /* Ximage struct. */ + +int created_images = False; + +#define NDELAYS 5 + +int delays[NDELAYS] = { 200000, 100000, 50000, 10000, 0 }; +int delay_index = 0; +int delay = 200000; /* 0.2 second between updates */ + +void +timeout_func(int signum) { + set_title = True; + signum = signum; /* UNUSED */ +} + +#ifdef FRAME +#define DRAW_FRAME() \ + XDrawRectangle(dpy, RootWindowOfScreen(scr), framegc, xgrab, ygrab, width[SRC]-1, height[SRC]-1) +#endif + +void +allocate_images(void) { + int i; + + for(i = 0; i < 2; i++) { + +#ifdef XSHM + ximage[i] = XShmCreateImage(dpy, + DefaultVisualOfScreen(scr), + DefaultDepthOfScreen(scr), + ZPixmap, NULL, &shminfo[i], + width[i], height[i]); + + if(ximage[i] == NULL) { + perror("XShmCreateImage"); + exit(-1); + } + + shminfo[i].shmid = shmget(IPC_PRIVATE, + (unsigned int)(ximage[i]->bytes_per_line * ximage[i]->height), + IPC_CREAT | 0777); + + if(shminfo[i].shmid < 0) { + perror("shmget"); + exit(-1); + } + + shminfo[i].shmaddr = (char *)shmat(shminfo[i].shmid, 0, 0); + + if (shminfo[i].shmaddr == ((char *) -1)) { + perror("shmat"); + exit(-1); + } + +#ifdef DEBUG + fprintf(stderr, "new shared memory segment at 0x%08x size %d\n", + shminfo[i].shmaddr, ximage[i]->bytes_per_line * ximage[i]->height); +#endif + + ximage[i]->data = shminfo[i].shmaddr; + shminfo[i].readOnly = False; + + XShmAttach(dpy, &shminfo[i]); + XSync(dpy, False); + + shmctl(shminfo[i].shmid, IPC_RMID, 0); +#else + char *data; + data = malloc(BitmapUnit(dpy) / 8 * width[i] * height[i]); + + ximage[i] = XCreateImage(dpy, + DefaultVisualOfScreen(scr), + DefaultDepthOfScreen(scr), + ZPixmap, 0, data, + width[i], height[i], 32, 0); + + if(ximage[i] == NULL) { + perror("XCreateImage"); + exit(-1); + } + +#endif /* XSHM */ + } + created_images = True; +} + +void +destroy_images(void) { + int i; + + if (!created_images) + return; + + for(i = 0; i < 2; i++) { +#ifdef XSHM + XShmDetach(dpy, &shminfo[i]); /* ask X11 to detach shared segment */ + shmdt(shminfo[i].shmaddr); /* detach it ourselves */ +#else + free(ximage[i]->data); +#endif + ximage[i]->data = NULL; /* remove refrence to that address */ + XDestroyImage(ximage[i]); /* and destroy image */ + } + + created_images = False; +} + +void +Usage(void) { + fprintf(stderr, "Usage: %s [ args ]\n" + "Command line args:\n" + "-display displayname\n" + "-mag magnification [ magnification ]\n" + "-geometry geometry\n" + "-source geometry\n" + "-x\n" + "-y\n" + "-xy\n\n" + "Window commands:\n" + "+: Zoom in\n" + "-: Zoom out\n" + "x: Flip right and left\n" + "y: Flip top and bottom\n" + "z: Rotate 90 degrees counter-clockwize\n" + "w: Next '+' or '-' only change width scaling\n" + "h: Next '+' or '-' only change height scaling\n" + "d: Change delay between frames\n" + "q: Quit\n" + "Arrow keys: Scroll in direction of arrow\n" + "Mouse button drag: Set top-left corner of viewed area\n", + progname); + exit(1); +} + +/* resize is called with the dest size. + we call it then manification changes or when + actual window size is changed */ +void +resize(int new_width, int new_height) { + + destroy_images(); /* we can get rid of these */ + + /* find new dimensions for source */ + + if(flipxy) { + height[SRC] = (new_width+magx-1) / magx; + width[SRC] = (new_height+magy-1) / magy; + } + else { + width[SRC] = (new_width+magx-1) / magx; + height[SRC] = (new_height+magy-1) / magy; + } + + if(width[SRC] < 1) + width[SRC] = 1; + if(width[SRC] > WidthOfScreen(scr)) + width[SRC] = WidthOfScreen(scr); + + if(height[SRC] < 1) + height[SRC] = 1; + if(height[SRC] > HeightOfScreen(scr)) + height[SRC] = HeightOfScreen(scr); + + /* temporary, the dest image may be larger than the + actual window */ + if(flipxy) { + width[DST] = magx * height[SRC]; + height[DST] = magy * width[SRC]; + } + else { + width[DST] = magx * width[SRC]; + height[DST] = magy * height[SRC]; + } + + allocate_images(); /* allocate new images */ + + /* remember actual window size */ + if(width[DST] > new_width) + width[DST] = new_width; + if(height[DST] > new_height) + height[DST] = new_height; +} + + +void scale8(void) +{ +#define T unsigned char +#include "scale.h" +#undef T +} + + +void scale16(void) +{ +#define T unsigned short +#include "scale.h" +#undef T +} + + +void scale32(void) +{ +#define T unsigned int +#include "scale.h" +#undef T +} + + +int +main(int argc, char **argv) { + XSetWindowAttributes xswa; + XEvent event; + int buttonpressed = False; + int unmapped = True; + int scroll = 1; + char title[80]; + XGCValues gcv; + char *dpyname = NULL; + int source_geom_mask = NoValue, + dest_geom_mask = NoValue, + copy_from_src_mask; + int xpos = 0, ypos = 0; + + atexit(destroy_images); + progname = strrchr(argv[0], '/'); + if(progname) + ++progname; + else + progname = argv[0]; + + /* parse command line options */ + while(--argc > 0) { + ++argv; + + if(argv[0][0] == '=') { + dest_geom_mask = XParseGeometry(argv[0], + &xpos, &ypos, + &width[DST], &height[DST]); + continue; + } + + if(!strcmp(argv[0], "-mag")) { + ++argv; --argc; + + magx = argc > 0 ? atoi(argv[0]) : -1; + + if(magx <= 0) + Usage(); + + + magy = argc > 1 ? atoi(argv[1]) : -1; + + if(magy <= 0) + magy = magx; + else { + ++argv; --argc; + } + + continue; + } + + if(!strcmp(argv[0], "-x")) { + flipx = True; + continue; + } + + if(!strcmp(argv[0], "-y")) { + flipy = True; + continue; + } + + if(!strcmp(argv[0], "-z") || + !strcmp(argv[0], "-xy")) { + flipxy = True; + continue; + } + + if(!strcmp(argv[0], "-source")) { + ++argv; --argc; + + if(argc < 1) + Usage(); + + source_geom_mask = XParseGeometry(argv[0], + &xgrab, &ygrab, + &width[SRC], &height[SRC]); + + continue; + } + + if(!strcmp(argv[0], "-dest") || + !strcmp(argv[0], "-geometry")) { + ++argv; --argc; + + if(argc < 1) + Usage(); + + dest_geom_mask = XParseGeometry(argv[0], + &xpos, &ypos, + &width[DST], &height[DST]); + + continue; + } + + if(!strcmp(argv[0], "-d") || + !strcmp(argv[0], "-display")) { + + ++argv; --argc; + + if(argc < 1) + Usage(); + + dpyname = argv[0]; + continue; + } + + if(!strcmp(argv[0], "-delay")) { + + ++argv; --argc; + + if(argc < 1) + Usage(); + + if(sscanf(argv[0], "%u", &delay) != 1) + Usage(); + + delay *= 1000; + + continue; + } + + Usage(); + } + + if (!(dpy = XOpenDisplay(dpyname))) { + perror("Cannot open display"); + exit(-1); + } + + /* Now, see if we have to calculate width[DST] and height[DST] + from the SRC parameters */ + + copy_from_src_mask = NoValue; + + if(source_geom_mask & WidthValue) { + if(flipxy) { + height[DST] = magy * width[SRC]; + copy_from_src_mask |= HeightValue; + + } + else { + width[DST] = magx * width[SRC]; + copy_from_src_mask |= WidthValue; + } + } + + if(source_geom_mask & HeightValue) { + if(flipxy) { + width[DST] = magx * height[SRC]; + copy_from_src_mask |= WidthValue; + } + else { + height[DST] = magy * height[SRC]; + copy_from_src_mask |= HeightValue; + } + } + + if(copy_from_src_mask & dest_geom_mask) { + fprintf(stderr, "Conflicting dimensions between source and dest geometry\n"); + Usage(); + } + + scr = DefaultScreenOfDisplay(dpy); + + depth = DefaultDepthOfScreen(scr); + if (depth < 8) { + fprintf(stderr, "%s: need at least 8 bits/pixel\n", progname); + exit(1); + } + + if(source_geom_mask & XNegative) + xgrab += WidthOfScreen(scr); + + if(source_geom_mask & YNegative) + ygrab += HeightOfScreen(scr); + + if(dest_geom_mask & XNegative) + xpos += WidthOfScreen(scr); + + if(source_geom_mask & YNegative) + ypos += HeightOfScreen(scr); + + /* printf("=%dx%d+%d+%d\n", width[DST], height[DST], xpos, ypos); */ + + xswa.event_mask = ButtonPressMask|ButtonReleaseMask|ButtonMotionMask; + xswa.event_mask |= StructureNotifyMask; /* resize etc.. */ + xswa.event_mask |= KeyPressMask|KeyReleaseMask; /* commands */ + xswa.background_pixel = BlackPixelOfScreen(scr); + + win = XCreateWindow(dpy, RootWindowOfScreen(scr), + xpos, ypos, width[DST], height[DST], 0, + DefaultDepthOfScreen(scr), InputOutput, + DefaultVisualOfScreen(scr), + CWEventMask | CWBackPixel, &xswa); + + XChangeProperty(dpy, win, XA_WM_ICON_NAME, XA_STRING, 8, + PropModeReplace, + (unsigned char *)progname, strlen(progname)); + + /* + XChangeProperty(dpy, win, XA_WM_NAME, XA_STRING, 8, + PropModeReplace, + (unsigned char *)progname, strlen(progname)); + */ + + + /*** 20020213 + code added by <tmancill@debian.org> to handle + window manager "close" event + ***/ + wm_delete_window = XInternAtom (dpy, "WM_DELETE_WINDOW", False); + wm_protocols = XInternAtom(dpy, "WM_PROTOCOLS", False); + status = XSetWMProtocols(dpy, win, &wm_delete_window, 1); + + set_title = True; + + status = XMapWindow(dpy, win); + + gcv.plane_mask = AllPlanes; + gcv.subwindow_mode = IncludeInferiors; + gcv.function = GXcopy; + gcv.foreground = WhitePixelOfScreen(scr); + gcv.background = BlackPixelOfScreen(scr); + gc = XCreateGC(dpy, RootWindowOfScreen(scr), + GCFunction|GCPlaneMask|GCSubwindowMode|GCForeground|GCBackground, + &gcv); + +#ifdef FRAME + gcv.foreground = AllPlanes; + gcv.plane_mask = WhitePixelOfScreen(scr)^BlackPixelOfScreen(scr); + gcv.subwindow_mode = IncludeInferiors; + gcv.function = GXxor; + framegc = XCreateGC(dpy, RootWindowOfScreen(scr), + GCFunction|GCPlaneMask|GCSubwindowMode|GCForeground, + &gcv); +#endif + +#ifdef TIMER + font = XLoadFont(dpy, "fixed"); +#endif + + resize(width[DST], height[DST]); + +#ifdef FRAME + + { + static char bitmap_data[] = { 0 }; + static XColor col = { 0 }; + Pixmap curs = XCreatePixmapFromBitmapData(dpy, + RootWindowOfScreen(scr), bitmap_data, 1, 1, 0, 0, 1); + + when_button = XCreatePixmapCursor(dpy, curs, curs, &col, &col, 0, 0); + } +#else + when_button = XCreateFontCursor(dpy, XC_ul_angle); +#endif + crosshair = XCreateFontCursor(dpy, XC_crosshair); + + XDefineCursor(dpy, win, crosshair); + + for(;;) { + + /***** + old event loop updated to support WM messages + while(unmapped? + (XWindowEvent(dpy, win, (long)-1, &event), 1): + XCheckWindowEvent(dpy, win, (long)-1, &event)) { + ******/ + + while(XPending(dpy)) { + XNextEvent(dpy, &event); + switch(event.type) { + case ClientMessage: + if ((event.xclient.message_type == wm_protocols) && + (event.xclient.data.l[0] == wm_delete_window)) { + exit(0); + } + break; + case ConfigureNotify: + if(event.xconfigure.width != width[DST] || + event.xconfigure.height != height[DST]) { + + resize(event.xconfigure.width, event.xconfigure.height); + } + break; + case ReparentNotify: + break; /* what do we do with it? */ + + case MapNotify: + unmapped = False; + break; + + case UnmapNotify: + unmapped = True; + break; + + case KeyRelease: + switch(XKeycodeToKeysym(dpy, event.xkey.keycode, 0)) { + case XK_Control_L: + case XK_Control_R: + scroll = 1; + break; + } + break; + + case KeyPress: + switch(XKeycodeToKeysym(dpy, event.xkey.keycode, 0)) { + case XK_Control_L: + case XK_Control_R: + scroll = 10; + break; + + case '+': + case '=': + case XK_KP_Add: + if(!yzoom_flag) ++magx; + if(!xzoom_flag) ++magy; + xzoom_flag = yzoom_flag = False; + resize(width[DST], height[DST]); + set_title = True; + break; + + case '-': + case XK_KP_Subtract: + if(!yzoom_flag) --magx; + if(!xzoom_flag) --magy; + xzoom_flag = yzoom_flag = False; + if(magx < 1) magx = 1; + if(magy < 1) magy = 1; + resize(width[DST], height[DST]); + set_title = True; + break; + + case XK_Left: + case XK_KP_Left: + if(flipxy) + if(flipx) + ygrab += scroll; + else + ygrab -= scroll; + else + if(flipx) + xgrab += scroll; + else + xgrab -= scroll; + break; + + case XK_Right: + case XK_KP_Right: + if(flipxy) + if(flipx) + ygrab -= scroll; + else + ygrab += scroll; + else + if(flipx) + xgrab -= scroll; + else + xgrab += scroll; + break; + + case XK_Up: + case XK_KP_Up: + if(flipxy) + if(flipy) + xgrab -= scroll; + else + xgrab += scroll; + else + if(flipy) + ygrab += scroll; + else + ygrab -= scroll; + break; + + case XK_Down: + case XK_KP_Down: + if(flipxy) + if(flipy) + xgrab += scroll; + else + xgrab -= scroll; + else + if(flipy) + ygrab -= scroll; + else + ygrab += scroll; + break; + + case 'x': + flipx = !flipx; + set_title = True; + break; + + case 'y': + flipy = !flipy; + set_title = True; + break; + + case 'z': + if(flipx^flipy^flipxy) { + flipx = !flipx; + flipy = !flipy; + } + flipxy = !flipxy; + resize(width[DST], height[DST]); + set_title = True; + break; + + case 'w': + xzoom_flag = True; + yzoom_flag = False; + break; + + case 'h': + yzoom_flag = True; + xzoom_flag = False; + break; + + case 'g': + gridx = !gridx; + gridy = !gridy; + break; + + case 'd': + if(++delay_index >= NDELAYS) + delay_index = 0; + delay = delays[delay_index]; + sprintf(title, "delay = %d ms", delay/1000); + XChangeProperty(dpy, win, XA_WM_NAME, XA_STRING, 8, + PropModeReplace, + (unsigned char *)title, strlen(title)); + signal(SIGALRM, timeout_func); + alarm(2); + break; + + case 'q': + exit(0); + break; + } + + break; + + case ButtonPress: +#ifdef FRAME + xgrab = event.xbutton.x_root - width[SRC]/2; + ygrab = event.xbutton.y_root - height[SRC]/2; +#else + xgrab = event.xbutton.x_root; + ygrab = event.xbutton.y_root; +#endif + XDefineCursor(dpy, win, when_button); + buttonpressed = True; + break; + + case ButtonRelease: + /* + xgrab = event.xbutton.x_root - width[SRC]/2; + ygrab = event.xbutton.y_root - height[SRC]/2; + */ + XDefineCursor(dpy, win, crosshair); + buttonpressed = False; + break; + + case MotionNotify: + if(buttonpressed) { +#ifdef FRAME + xgrab = event.xmotion.x_root - width[SRC]/2; + ygrab = event.xmotion.y_root - height[SRC]/2; +#else + xgrab = event.xmotion.x_root; + ygrab = event.xmotion.y_root; +#endif + } + break; + + } + + /* trying XShmGetImage when part of the rect is + not on the screen will fail LOUDLY.. + we have to veryfy this after anything that may + may modified xgrab or ygrab or the size of + the source ximage */ + + if(xgrab < 0) + xgrab = 0; + + if(xgrab > WidthOfScreen(scr)-width[SRC]) + xgrab = WidthOfScreen(scr)-width[SRC]; + + if(ygrab < 0) + ygrab = 0; + + if(ygrab > HeightOfScreen(scr)-height[SRC]) + ygrab = HeightOfScreen(scr)-height[SRC]; + + } + +#ifdef XSHM + XShmGetImage(dpy, RootWindowOfScreen(scr), ximage[SRC], + xgrab, ygrab, AllPlanes); +#else + XGetSubImage(dpy, RootWindowOfScreen(scr), + xgrab, ygrab, width[SRC], height[SRC], AllPlanes, + ZPixmap, ximage[SRC], 0, 0); +#endif +#ifdef FRAME + if(buttonpressed) { /* show the frame */ + DRAW_FRAME(); + XSync(dpy, False); + } +#endif + + if (depth == 8) + scale8(); + else if (depth <= 8*sizeof(short)) + scale16(); + else if (depth <= 8*sizeof(int)) + scale32(); + +#ifdef XSHM + XShmPutImage(dpy, win, gc, ximage[DST], 0, 0, 0, 0, width[DST], height[DST], False); +#else + XPutImage(dpy, win, gc, ximage[DST], 0, 0, 0, 0, width[DST], height[DST]); +#endif + if(set_title) { + if(magx == magy && !flipx && !flipy && !flipxy) + sprintf(title, "%s x%d", progname, magx); + else + sprintf(title, "%s X %s%d%s Y %s%d", + progname, + flipx?"-":"", magx, + flipxy?" <=>":";", + flipy?"-":"", magy); + XChangeProperty(dpy, win, XA_WM_NAME, XA_STRING, 8, + PropModeReplace, + (unsigned char *)title, strlen(title)); + set_title = False; + } +#ifdef TIMER + { + struct timeval current_time; + double DT; + + gettimeofday(&current_time, NULL); + DT = current_time.tv_sec - old_time.tv_sec; + DT += 1e-6*(current_time.tv_usec - old_time.tv_usec); + sprintf(title, "DT=%6.3f", DT); + XDrawString(dpy, win, gc, 20, 20, title, strlen(title)); + old_time = current_time; + } +#endif + XSync(dpy, 0); + +#ifdef NO_USLEEP +#define usleep(_t) \ + { \ + struct timeval timeout; \ + timeout.tv_sec = 0; \ + timeout.tv_usec = _t; \ + select(0, NULL, NULL, NULL, &timeout); \ + } +#endif + + if(!buttonpressed && delay > 0) + usleep(delay); +#ifdef FRAME + if(buttonpressed) /* erase the frame */ + DRAW_FRAME(); +#endif + } +} diff --git a/xzoom.lsm b/xzoom.lsm @@ -0,0 +1,18 @@ +Begin3 +Title: xzoom +Version: 0.3 +Entered-date: May 30 1996 +Description: xzoom can magnify (by integer value) rotate + (by a multiple if 90 degrees) and mirror about + the X or Y axes areas on X11 screen and display + them in it's window. +Keywords: X11 zoom magnify xmag +Author: Itai Nahshon <nahshon@best.com> +Maintained-by: Itai Nahshon <nahshon@best.com> +Primary-site: sunsite.unc.edu + probably in /pub/Linux/X11/xutils/xzoom-0.3.tgz +Platforms: Linux+11. Support only for 8-bit depth. + Tested only in Linux pre-2.0.* with the XSVGA 3.1.2 driver. + Needs the XSHM extension. +Copying-policy: Free +End diff --git a/xzoom.man b/xzoom.man @@ -0,0 +1,169 @@ +.\" xzoom.man +.\" Copyright Itai Nahshon +.\" +.TH XZOOM 1x +.SH NAME +xzoom \- magnify part of the screen, with fast updates +.SH SYNOPSIS +.B xzoom +[ \-display \fIdisplayname\fP ] [ \-mag \fImag\fP [ \fImag\fP ] ] +[ \-x ] [ \-y ] [ \-xy ] +[ \-geometry \fIgeometry\fP ] [ \-source \fIgeometry\fP ] +.SH OPTIONS +.LP +.TP 5 +.B \-display \fIdisplayname\fP \fR|\fP \-d \fIdisplayname\fP +The name of the display to use +(not very useful). +.TP 5 +.B \-mag \fImag\fP [ \fImag\fP ] +What magnification to use. If two number arguments are supplied the +first is used for X magnifications and the second is used for Y magnification. +Magnification should be greater than 0. +.TP 5 +.B \-x +Mirror horizontally. +.TP 5 +.B \-y +Mirror vertically. +.TP 5 +.B \-xy \fR|\fP \-z +Exchange X and Y axes before any magnification is performed. +.TP 5 +.B \-geometry \fIgeometry\fP \fR|\fP =\fIgeometry\fP +Size and position \fBxzoom\fR's window. +.TP 5 +.B \-source \fIgeometry\fP +Size and position the initial source area which is magnified. +The dimensions of this area are multiplied by the magnification to +get the size of \fBxzoom\fR's window. If these dimensions are given +separately (by use of \-geometry ) then an error is reported. +.br +.SH DESCRIPTION +.IR Xzoom +displays in its window a magnified area of the X11 display. +The user can interactively change the zoomed area, the window +size, magnification (optionally different magnification for +X and Y axes) or rotate or mirror the image. +.SH COMMANDS +.LP +Once xzoom has started the user can enter simple commands +using the keyboard. +.LP +.TP 5 +.B q +quit. +.TP 5 +.B \+ +increase magnification value by 1. +.TP 5 +.B \- +decrease magnification value by 1. +.TP 5 +.B w +next \+ or \- command only affect X magnification. +.TP 5 +.B h +next \+ or \- command only affect Y magnification. +.TP 5 +.B x +mirror the display image horizontally. +.TP 5 +.B y +mirror the display image vertically. +.TP 5 +.B z +rotate the displayed image 90 degrees counter-clockwise. +.TP 5 +.B arrow keys +scroll the zoomed area 1 pixel in the direction of the arrow. +if the +.B control +key is pressed the zoomed area will scroll 10 pixels. +.TP 5 +.B d +sets the delay between frame updates. +Built-in delays are 200, 100, 50, 10 and 0 ms. +.TP 5 +.B g +toggle grid on and off. +.TP 5 +.B Mouse buttons +To set the location of the magnified are click the left mouse +button inside xzoom's window and then move it (keep the button +pressed) to the place which you want to see magnified. +.sp 1 +Xzoom allow you to resize it's window at any time. +.sp 1 +When xzoom is iconified it simply waits to get deiconified. +.SH DISPLAYS +Xzoom uses the window's title bar to inform the user about +it's status. Normally the title says something like +.B "xzoom x2" +which means the magnification is 2 both in X and Y axes. +If the image is stretched differently on the X and Y axes +the title will say +.B "xzoom X 2; Y 4." +Negative numbers mean reflection. +If the image is rotated by 90 or 270 degrees the title +will show +.B "<=>" +between the X and Y values. +.sp 1 +When +.B d +is depressed the title will display the new delay value for +approximately 2 seconds and then revert to the default display +of magnification values. +.SH PERFORMANCE +Xzoom is fast enough to display enlarged or mirrored animations +in small windows. On my 486 DX2-66 and Cirrus Logic CL-GD5428 +display card (attached to Vesa local bus) update of a 256x256 +window magnified by 2 (ie, source rect is 128x128) takes +approximately 30 ms. This time varies, off course when +a different size window or different magnification is used. +If we chose 50 ms between updates we can get about 12.5 frames per +second and still let an animation program do it's work. +It is possible to compile xzoom without X shared memory support. +In that case window update may be about 3 times slower (if we +are using a local display, using LAN is a different story). +.SH SEE ALSO +xmag.1x. +.br +I got the motivation for writing xzoom after I saw a similar +WindowsNT program, zoomin working. It started just as a test +for X11 performance. I don't have the fancy menus and scrollbar +like zoomin but I do have all their features (and more) accessible +from the keyboard. +.SH BUGS +.LP 5 +\(dg +The maximum internal built in delay (see command +.B d +above) was set to 200 ms. Xzoom completes the delay before +polling the X event queue for the next command. Larger +delays would feel like poor response to user commands. +.LP 5 +\(dg +For best performance the shared memory extension for X11 is +used. Xzoom will fail if it is compiled to use XSHM and its +display is not on the local host. +.LP 5 +\(dg +Xzoom is given with no warranty. It was tested only under +Linux with Xfree86 release 3.1.2 (X11R6). +.LP 5 +\(dg +Some strange behavior may occur if the requested magnified area +falls beyond the borders of the screen. Example is when you have +magnification of 1 and a window whose width is greater than the +height of the screen and you want 90 degrees rotation. In that +case part of the window will not get updated. +.LP 5 +\(dg +The frame used to mark the zoomed area may corrupt the contents +of other windows if they are modified when the frame is visible. +If you don't like it disable the \-DFRAME option when compiling +xzoom. +.SH AUTHOR +Itai Nahshon