2 * magnify - a X utility for magnifying screen image
4 * 2000/5/21 Alfredo K. Kojima
6 * This program is in the Public Domain.
9 #include <X11/Xproto.h>
11 #include <WINGs/WINGs.h>
18 * - lens that shows where it's magnifying
23 int refreshrate = 200;
29 unsigned long lastpixel;
30 unsigned long *buffer;
32 int rwidth, rheight; /* size of window in real pixels */
51 Bool markPointerHotspot;
56 static BufferData *newWindow(int magfactor);
60 int rectBufferSize = 32;
64 WMColor *cursorColor1;
65 WMColor *cursorColor2;
71 static BufferData *makeBufferData(WMWindow * win, WMLabel * label, int width, int height, int magfactor)
75 data = wmalloc(sizeof(BufferData));
78 data->rheight = height;
80 data->refreshrate = refreshrate;
82 data->firstDraw = True;
84 data->magfactor = magfactor;
86 data->rects = wmalloc(sizeof(XRectangle) * rectBufferSize);
92 data->pixmap = WMCreatePixmap(scr, width, height, WMScreenDepth(scr), False);
93 WMSetLabelImage(data->label, data->pixmap);
95 data->d = WMGetPixmapXID(data->pixmap);
101 data->buffer = wmalloc(sizeof(unsigned long) * width * height);
102 memset(data->buffer, 0, width * height * sizeof(unsigned long));
104 data->height = height;
109 static void resizeBufferData(BufferData * data, int width, int height, int magfactor)
111 int w = width / magfactor;
112 int h = height / magfactor;
114 data->rwidth = width;
115 data->rheight = height;
116 data->firstDraw = True;
117 data->magfactor = magfactor;
118 data->buffer = wrealloc(data->buffer, sizeof(unsigned long) * w * h);
121 memset(data->buffer, 0, w * h * sizeof(unsigned long));
123 WMResizeWidget(data->label, width, height);
125 WMReleasePixmap(data->pixmap);
126 data->pixmap = WMCreatePixmap(scr, width, height, WMScreenDepth(scr), False);
127 WMSetLabelImage(data->label, data->pixmap);
129 data->d = WMGetPixmapXID(data->pixmap);
132 static int drawpoint(BufferData * data, unsigned long pixel, int x, int y)
135 Bool flush = (x < 0);
138 if (data->buffer[x + data->width * y] == pixel && !data->firstDraw)
141 data->buffer[x + data->width * y] = pixel;
144 gc = XCreateGC(dpy, DefaultRootWindow(dpy), 0, NULL);
147 if (!flush && data->lastpixel == pixel && data->rectP < rectBufferSize) {
148 data->rects[data->rectP].x = x * data->magfactor;
149 data->rects[data->rectP].y = y * data->magfactor;
150 data->rects[data->rectP].width = data->magfactor;
151 data->rects[data->rectP].height = data->magfactor;
156 XSetForeground(dpy, gc, data->lastpixel);
157 XFillRectangles(dpy, data->d, gc, data->rects, data->rectP);
159 data->rects[data->rectP].x = x * data->magfactor;
160 data->rects[data->rectP].y = y * data->magfactor;
161 data->rects[data->rectP].width = data->magfactor;
162 data->rects[data->rectP].height = data->magfactor;
165 data->lastpixel = pixel;
170 static inline unsigned long getpix(XImage * image, int x, int y, int xoffs, int yoffs)
172 if (x < xoffs || y < yoffs || x >= xoffs + image->width || y >= yoffs + image->height) {
175 return XGetPixel(image, x - xoffs, y - yoffs);
178 static void updateImage(BufferData * data, int rx, int ry)
183 int changedPixels = 0;
198 if (gx + gw >= WidthOfScreen(DefaultScreenOfDisplay(vdpy))) {
199 gw = WidthOfScreen(DefaultScreenOfDisplay(vdpy)) - gx;
206 if (gy + gh >= HeightOfScreen(DefaultScreenOfDisplay(vdpy))) {
207 gh = HeightOfScreen(DefaultScreenOfDisplay(vdpy)) - gy;
210 image = XGetImage(vdpy, DefaultRootWindow(vdpy), gx, gy, gw, gh, AllPlanes, ZPixmap);
212 for (y = 0; y < data->height; y++) {
213 for (x = 0; x < data->width; x++) {
216 pixel = getpix(image, x, y, xoffs, yoffs);
218 if (drawpoint(data, pixel, x, y))
222 /* flush the point cache */
223 drawpoint(data, 0, -1, -1);
225 XDestroyImage(image);
227 if (data->markPointerHotspot && !data->frozen) {
230 rects[0].x = (data->width / 2 - 3) * data->magfactor;
231 rects[0].y = (data->height / 2) * data->magfactor;
232 rects[0].width = 2 * data->magfactor;
233 rects[0].height = data->magfactor;
235 rects[1].x = (data->width / 2 + 2) * data->magfactor;
236 rects[1].y = (data->height / 2) * data->magfactor;
237 rects[1].width = 2 * data->magfactor;
238 rects[1].height = data->magfactor;
240 XFillRectangles(dpy, data->d, WMColorGC(cursorColor1), rects, 2);
242 rects[2].y = (data->height / 2 - 3) * data->magfactor;
243 rects[2].x = (data->width / 2) * data->magfactor;
244 rects[2].height = 2 * data->magfactor;
245 rects[2].width = data->magfactor;
247 rects[3].y = (data->height / 2 + 2) * data->magfactor;
248 rects[3].x = (data->width / 2) * data->magfactor;
249 rects[3].height = 2 * data->magfactor;
250 rects[3].width = data->magfactor;
252 XFillRectangles(dpy, data->d, WMColorGC(cursorColor2), rects + 2, 2);
255 if (changedPixels > 0) {
256 WMRedisplayWidget(data->label);
259 data->firstDraw = False;
262 static void update(void *d)
264 BufferData *data = (BufferData *) d;
274 XQueryPointer(dpy, DefaultRootWindow(dpy), &win, &win, &rx, &ry, &bla, &bla, &ubla);
276 updateImage(data, rx, ry);
278 data->tid = WMAddTimerHandler(data->refreshrate, update, data);
281 void resizedWindow(void *d, WMNotification * notif)
283 BufferData *data = (BufferData *) d;
284 WMView *view = (WMView *) WMGetNotificationObject(notif);
287 size = WMGetViewSize(view);
289 resizeBufferData(data, size.width, size.height, data->magfactor);
292 void closeWindow(WMWidget * w, void *d)
294 BufferData *data = (BufferData *) d;
297 if (windowCount == 0) {
300 WMDeleteTimerHandler(data->tid);
304 WMReleasePixmap(data->pixmap);
310 static void clickHandler(XEvent * event, void *d)
312 BufferData *data = (BufferData *) d;
314 data->win = WMCreateWindow(scr, "setup");
315 WMSetWindowTitle(data->win, "Magnify Options");
317 data->speed = WMCreateSlider(data->win);
319 data->magnify = WMCreateSlider(data->win);
324 static void keyHandler(XEvent * event, void *d)
326 BufferData *data = (BufferData *) d;
329 WMView *view = WMWidgetView(data->win);
332 size = WMGetViewSize(view);
334 if (XLookupString(&event->xkey, buf, 31, &ks, NULL) > 0) {
337 newWindow(data->magfactor);
340 data->markPointerHotspot = !data->markPointerHotspot;
344 data->frozen = !data->frozen;
346 data->x = event->xkey.x_root;
347 data->y = event->xkey.y_root;
348 sprintf(buf, "[Magnify %ix]", data->magfactor);
350 sprintf(buf, "Magnify %ix", data->magfactor);
352 WMSetWindowTitle(data->win, buf);
363 resizeBufferData(data, size.width, size.height, buf[0] - '0');
365 sprintf(buf, "[Magnify %ix]", data->magfactor);
367 sprintf(buf, "Magnify %ix", data->magfactor);
369 WMSetWindowTitle(data->win, buf);
375 static BufferData *newWindow(int magfactor)
384 win = WMCreateWindow(scr, "magnify");
385 WMResizeWidget(win, 300, 200);
386 sprintf(buf, "Magnify %ix", magfactor);
387 WMSetWindowTitle(win, buf);
388 WMSetViewNotifySizeChanges(WMWidgetView(win), True);
390 label = WMCreateLabel(win);
391 WMResizeWidget(label, 300, 200);
392 WMMoveWidget(label, 0, 0);
393 WMSetLabelRelief(label, WRSunken);
394 WMSetLabelImagePosition(label, WIPImageOnly);
396 data = makeBufferData(win, label, 300, 200, magfactor);
398 WMCreateEventHandler(WMWidgetView(win), KeyReleaseMask, keyHandler, data);
400 WMAddNotificationObserver(resizedWindow, data, WMViewSizeDidChangeNotification, WMWidgetView(win));
402 WMRealizeWidget(win);
404 WMMapSubwidgets(win);
407 WMSetWindowCloseAction(win, closeWindow, data);
408 data->tid = WMAddTimerHandler(refreshrate, update, data);
413 int main(int argc, char **argv)
418 char *vdisplay = NULL;
421 WMButton *radio, *tradio;
423 WMInitializeApplication("Magnify", &argc, argv);
425 for (i = 1; i < argc; i++) {
426 if (strcmp(argv[i], "-display") == 0) {
431 } else if (strcmp(argv[i], "-vdisplay") == 0) {
436 } else if (strcmp(argv[i], "-m") == 0) {
440 magfactor = atoi(argv[i]);
441 if (magfactor < 1 || magfactor > 32) {
442 printf("%s:invalid magnification factor ``%s''\n", argv[0], argv[i]);
445 } else if (strcmp(argv[i], "-r") == 0) {
449 refreshrate = atoi(argv[i]);
450 if (refreshrate < 1) {
451 printf("%s:invalid refresh rate ``%s''\n", argv[0], argv[i]);
454 } else if (strcmp(argv[i], "-h") == 0 || strcmp(argv[i], "--help") == 0) {
457 printf("Syntax: %s [options]\n", argv[0]);
459 puts(" -display <display> display that should be used");
460 puts(" -m <number> change magnification factor (default 2)");
461 puts(" -r <number> change refresh delay, in milliseconds (default 200)");
463 puts(" 1,2,3,4,5,6,7,8,9 change the magnification factor");
464 puts(" <space>, f freeze the 'camera', making it magnify only the current\n"
466 puts(" n create a new window");
467 puts(" m show/hide the pointer hotspot mark");
472 dpy = XOpenDisplay(display);
474 puts("couldnt open display");
479 vdpy = XOpenDisplay(vdisplay);
481 puts("couldnt open display to be viewed");
488 /* calculate how many rectangles we can send in a trip to the server */
489 rectBufferSize = XMaxRequestSize(dpy) - 128;
490 rectBufferSize /= sizeof(XRectangle);
491 if (rectBufferSize < 1)
494 black = BlackPixel(dpy, DefaultScreen(dpy));
496 scr = WMCreateScreen(dpy, 0);
498 cursorColor1 = WMCreateNamedColor(scr, "#ff0000", False);
499 cursorColor2 = WMCreateNamedColor(scr, "#00ff00", False);
501 data = newWindow(magfactor);
503 WMScreenMainLoop(scr);