2 * magnify - a X utility for magnifying screen image
4 * 2000/5/21 Alfredo K. Kojima
6 * This program is in the Public Domain.
10 #include <X11/Xproto.h>
12 #include <WINGs/WINGs.h>
19 * - lens that shows where it's magnifying
24 int refreshrate
= 200;
30 unsigned long lastpixel
;
31 unsigned long *buffer
;
33 int rwidth
, rheight
; /* size of window in real pixels */
52 Bool markPointerHotspot
;
57 static BufferData
*newWindow(int magfactor
);
61 int rectBufferSize
= 32;
65 WMColor
*cursorColor1
;
66 WMColor
*cursorColor2
;
69 static BufferData
*makeBufferData(WMWindow
* win
, WMLabel
* label
, int width
, int height
, int magfactor
)
73 data
= wmalloc(sizeof(BufferData
));
76 data
->rheight
= height
;
78 data
->refreshrate
= refreshrate
;
80 data
->firstDraw
= True
;
82 data
->magfactor
= magfactor
;
84 data
->rects
= wmalloc(sizeof(XRectangle
) * rectBufferSize
);
90 data
->pixmap
= WMCreatePixmap(scr
, width
, height
, WMScreenDepth(scr
), False
);
91 WMSetLabelImage(data
->label
, data
->pixmap
);
93 data
->d
= WMGetPixmapXID(data
->pixmap
);
99 data
->buffer
= wmalloc(sizeof(unsigned long) * width
* height
);
101 data
->height
= height
;
106 static void resizeBufferData(BufferData
* data
, int width
, int height
, int magfactor
)
108 int w
= width
/ magfactor
;
109 int h
= height
/ magfactor
;
111 data
->rwidth
= width
;
112 data
->rheight
= height
;
113 data
->firstDraw
= True
;
114 data
->magfactor
= magfactor
;
115 data
->buffer
= wrealloc(data
->buffer
, sizeof(unsigned long) * w
* h
);
118 memset(data
->buffer
, 0, w
* h
* sizeof(unsigned long));
120 WMResizeWidget(data
->label
, width
, height
);
122 WMReleasePixmap(data
->pixmap
);
123 data
->pixmap
= WMCreatePixmap(scr
, width
, height
, WMScreenDepth(scr
), False
);
124 WMSetLabelImage(data
->label
, data
->pixmap
);
126 data
->d
= WMGetPixmapXID(data
->pixmap
);
129 static int drawpoint(BufferData
* data
, unsigned long pixel
, int x
, int y
)
132 Bool flush
= (x
< 0);
135 if (data
->buffer
[x
+ data
->width
* y
] == pixel
&& !data
->firstDraw
)
138 data
->buffer
[x
+ data
->width
* y
] = pixel
;
141 gc
= XCreateGC(dpy
, DefaultRootWindow(dpy
), 0, NULL
);
144 if (!flush
&& data
->lastpixel
== pixel
&& data
->rectP
< rectBufferSize
) {
145 data
->rects
[data
->rectP
].x
= x
* data
->magfactor
;
146 data
->rects
[data
->rectP
].y
= y
* data
->magfactor
;
147 data
->rects
[data
->rectP
].width
= data
->magfactor
;
148 data
->rects
[data
->rectP
].height
= data
->magfactor
;
153 XSetForeground(dpy
, gc
, data
->lastpixel
);
154 XFillRectangles(dpy
, data
->d
, gc
, data
->rects
, data
->rectP
);
156 data
->rects
[data
->rectP
].x
= x
* data
->magfactor
;
157 data
->rects
[data
->rectP
].y
= y
* data
->magfactor
;
158 data
->rects
[data
->rectP
].width
= data
->magfactor
;
159 data
->rects
[data
->rectP
].height
= data
->magfactor
;
162 data
->lastpixel
= pixel
;
167 static inline unsigned long getpix(XImage
* image
, int x
, int y
, int xoffs
, int yoffs
)
169 if (x
< xoffs
|| y
< yoffs
|| x
>= xoffs
+ image
->width
|| y
>= yoffs
+ image
->height
) {
172 return XGetPixel(image
, x
- xoffs
, y
- yoffs
);
175 static void updateImage(BufferData
* data
, int rx
, int ry
)
180 int changedPixels
= 0;
195 if (gx
+ gw
>= WidthOfScreen(DefaultScreenOfDisplay(vdpy
))) {
196 gw
= WidthOfScreen(DefaultScreenOfDisplay(vdpy
)) - gx
;
203 if (gy
+ gh
>= HeightOfScreen(DefaultScreenOfDisplay(vdpy
))) {
204 gh
= HeightOfScreen(DefaultScreenOfDisplay(vdpy
)) - gy
;
207 image
= XGetImage(vdpy
, DefaultRootWindow(vdpy
), gx
, gy
, gw
, gh
, AllPlanes
, ZPixmap
);
209 for (y
= 0; y
< data
->height
; y
++) {
210 for (x
= 0; x
< data
->width
; x
++) {
213 pixel
= getpix(image
, x
, y
, xoffs
, yoffs
);
215 if (drawpoint(data
, pixel
, x
, y
))
219 /* flush the point cache */
220 drawpoint(data
, 0, -1, -1);
222 XDestroyImage(image
);
224 if (data
->markPointerHotspot
&& !data
->frozen
) {
227 rects
[0].x
= (data
->width
/ 2 - 3) * data
->magfactor
;
228 rects
[0].y
= (data
->height
/ 2) * data
->magfactor
;
229 rects
[0].width
= 2 * data
->magfactor
;
230 rects
[0].height
= data
->magfactor
;
232 rects
[1].x
= (data
->width
/ 2 + 2) * data
->magfactor
;
233 rects
[1].y
= (data
->height
/ 2) * data
->magfactor
;
234 rects
[1].width
= 2 * data
->magfactor
;
235 rects
[1].height
= data
->magfactor
;
237 XFillRectangles(dpy
, data
->d
, WMColorGC(cursorColor1
), rects
, 2);
239 rects
[2].y
= (data
->height
/ 2 - 3) * data
->magfactor
;
240 rects
[2].x
= (data
->width
/ 2) * data
->magfactor
;
241 rects
[2].height
= 2 * data
->magfactor
;
242 rects
[2].width
= data
->magfactor
;
244 rects
[3].y
= (data
->height
/ 2 + 2) * data
->magfactor
;
245 rects
[3].x
= (data
->width
/ 2) * data
->magfactor
;
246 rects
[3].height
= 2 * data
->magfactor
;
247 rects
[3].width
= data
->magfactor
;
249 XFillRectangles(dpy
, data
->d
, WMColorGC(cursorColor2
), rects
+ 2, 2);
252 if (changedPixels
> 0) {
253 WMRedisplayWidget(data
->label
);
256 data
->firstDraw
= False
;
259 static void update(void *d
)
261 BufferData
*data
= (BufferData
*) d
;
271 XQueryPointer(dpy
, DefaultRootWindow(dpy
), &win
, &win
, &rx
, &ry
, &bla
, &bla
, &ubla
);
273 updateImage(data
, rx
, ry
);
275 data
->tid
= WMAddTimerHandler(data
->refreshrate
, update
, data
);
278 static void resizedWindow(void *d
, WMNotification
* notif
)
280 BufferData
*data
= (BufferData
*) d
;
281 WMView
*view
= (WMView
*) WMGetNotificationObject(notif
);
284 size
= WMGetViewSize(view
);
286 resizeBufferData(data
, size
.width
, size
.height
, data
->magfactor
);
289 static void closeWindow(WMWidget
* w
, void *d
)
291 BufferData
*data
= (BufferData
*) d
;
294 if (windowCount
== 0) {
295 WMReleaseApplication();
298 WMDeleteTimerHandler(data
->tid
);
302 WMReleasePixmap(data
->pixmap
);
307 static void keyHandler(XEvent
* event
, void *d
)
309 BufferData
*data
= (BufferData
*) d
;
312 WMView
*view
= WMWidgetView(data
->win
);
315 size
= WMGetViewSize(view
);
317 if (XLookupString(&event
->xkey
, buf
, 31, &ks
, NULL
) > 0) {
320 newWindow(data
->magfactor
);
323 data
->markPointerHotspot
= !data
->markPointerHotspot
;
327 data
->frozen
= !data
->frozen
;
329 data
->x
= event
->xkey
.x_root
;
330 data
->y
= event
->xkey
.y_root
;
331 sprintf(buf
, "[Magnify %ix]", data
->magfactor
);
333 sprintf(buf
, "Magnify %ix", data
->magfactor
);
335 WMSetWindowTitle(data
->win
, buf
);
346 resizeBufferData(data
, size
.width
, size
.height
, buf
[0] - '0');
348 sprintf(buf
, "[Magnify %ix]", data
->magfactor
);
350 sprintf(buf
, "Magnify %ix", data
->magfactor
);
352 WMSetWindowTitle(data
->win
, buf
);
358 static BufferData
*newWindow(int magfactor
)
367 win
= WMCreateWindow(scr
, "magnify");
368 WMResizeWidget(win
, 300, 200);
369 sprintf(buf
, "Magnify %ix", magfactor
);
370 WMSetWindowTitle(win
, buf
);
371 WMSetViewNotifySizeChanges(WMWidgetView(win
), True
);
373 label
= WMCreateLabel(win
);
374 WMResizeWidget(label
, 300, 200);
375 WMMoveWidget(label
, 0, 0);
376 WMSetLabelRelief(label
, WRSunken
);
377 WMSetLabelImagePosition(label
, WIPImageOnly
);
379 data
= makeBufferData(win
, label
, 300, 200, magfactor
);
381 WMCreateEventHandler(WMWidgetView(win
), KeyReleaseMask
, keyHandler
, data
);
383 WMAddNotificationObserver(resizedWindow
, data
, WMViewSizeDidChangeNotification
, WMWidgetView(win
));
385 WMRealizeWidget(win
);
387 WMMapSubwidgets(win
);
390 WMSetWindowCloseAction(win
, closeWindow
, data
);
391 data
->tid
= WMAddTimerHandler(refreshrate
, update
, data
);
396 int main(int argc
, char **argv
)
400 char *vdisplay
= NULL
;
403 WMInitializeApplication("Magnify", &argc
, argv
);
405 for (i
= 1; i
< argc
; i
++) {
406 if (strcmp(argv
[i
], "-display") == 0) {
411 } else if (strcmp(argv
[i
], "-vdisplay") == 0) {
416 } else if (strcmp(argv
[i
], "-m") == 0) {
420 magfactor
= atoi(argv
[i
]);
421 if (magfactor
< 1 || magfactor
> 32) {
422 printf("%s:invalid magnification factor ``%s''\n", argv
[0], argv
[i
]);
425 } else if (strcmp(argv
[i
], "-r") == 0) {
429 refreshrate
= atoi(argv
[i
]);
430 if (refreshrate
< 1) {
431 printf("%s:invalid refresh rate ``%s''\n", argv
[0], argv
[i
]);
434 } else if (strcmp(argv
[i
], "-h") == 0 || strcmp(argv
[i
], "--help") == 0) {
437 printf("Usage: %s [options]\n", argv
[0]);
439 puts(" -display <display>\tdisplay where to magnification is shown");
440 puts(" -m <number>\t\tchange magnification factor (default 2)");
441 puts(" -r <number>\t\tchange refresh delay, in milliseconds (default 200)");
442 puts(" -vdisplay <display>\tdisplay from which the magnification is taken");
443 puts(" -h, --help\t\tdisplay this help page");
445 puts(" 1,2,3,4,5,6,7,8,9 change the magnification factor");
446 puts(" <space>, f freeze the 'camera', making it magnify only the current\n"
448 puts(" n create a new window");
449 puts(" m show/hide the pointer hotspot mark");
454 dpy
= XOpenDisplay(display
);
456 puts("could not open display");
461 vdpy
= XOpenDisplay(vdisplay
);
463 puts("could not open display to be viewed");
470 /* calculate how many rectangles we can send in a trip to the server */
471 rectBufferSize
= XMaxRequestSize(dpy
) - 128;
472 rectBufferSize
/= sizeof(XRectangle
);
473 if (rectBufferSize
< 1)
476 black
= BlackPixel(dpy
, DefaultScreen(dpy
));
478 scr
= WMCreateScreen(dpy
, 0);
480 cursorColor1
= WMCreateNamedColor(scr
, "#ff0000", False
);
481 cursorColor2
= WMCreateNamedColor(scr
, "#00ff00", False
);
483 newWindow(magfactor
);
485 WMScreenMainLoop(scr
);