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) {
297 WMDeleteTimerHandler(data
->tid
);
301 WMReleasePixmap(data
->pixmap
);
306 static void keyHandler(XEvent
* event
, void *d
)
308 BufferData
*data
= (BufferData
*) d
;
311 WMView
*view
= WMWidgetView(data
->win
);
314 size
= WMGetViewSize(view
);
316 if (XLookupString(&event
->xkey
, buf
, 31, &ks
, NULL
) > 0) {
319 newWindow(data
->magfactor
);
322 data
->markPointerHotspot
= !data
->markPointerHotspot
;
326 data
->frozen
= !data
->frozen
;
328 data
->x
= event
->xkey
.x_root
;
329 data
->y
= event
->xkey
.y_root
;
330 sprintf(buf
, "[Magnify %ix]", data
->magfactor
);
332 sprintf(buf
, "Magnify %ix", data
->magfactor
);
334 WMSetWindowTitle(data
->win
, buf
);
345 resizeBufferData(data
, size
.width
, size
.height
, buf
[0] - '0');
347 sprintf(buf
, "[Magnify %ix]", data
->magfactor
);
349 sprintf(buf
, "Magnify %ix", data
->magfactor
);
351 WMSetWindowTitle(data
->win
, buf
);
357 static BufferData
*newWindow(int magfactor
)
366 win
= WMCreateWindow(scr
, "magnify");
367 WMResizeWidget(win
, 300, 200);
368 sprintf(buf
, "Magnify %ix", magfactor
);
369 WMSetWindowTitle(win
, buf
);
370 WMSetViewNotifySizeChanges(WMWidgetView(win
), True
);
372 label
= WMCreateLabel(win
);
373 WMResizeWidget(label
, 300, 200);
374 WMMoveWidget(label
, 0, 0);
375 WMSetLabelRelief(label
, WRSunken
);
376 WMSetLabelImagePosition(label
, WIPImageOnly
);
378 data
= makeBufferData(win
, label
, 300, 200, magfactor
);
380 WMCreateEventHandler(WMWidgetView(win
), KeyReleaseMask
, keyHandler
, data
);
382 WMAddNotificationObserver(resizedWindow
, data
, WMViewSizeDidChangeNotification
, WMWidgetView(win
));
384 WMRealizeWidget(win
);
386 WMMapSubwidgets(win
);
389 WMSetWindowCloseAction(win
, closeWindow
, data
);
390 data
->tid
= WMAddTimerHandler(refreshrate
, update
, data
);
395 int main(int argc
, char **argv
)
399 char *vdisplay
= NULL
;
402 WMInitializeApplication("Magnify", &argc
, argv
);
404 for (i
= 1; i
< argc
; i
++) {
405 if (strcmp(argv
[i
], "-display") == 0) {
410 } else if (strcmp(argv
[i
], "-vdisplay") == 0) {
415 } else if (strcmp(argv
[i
], "-m") == 0) {
419 magfactor
= atoi(argv
[i
]);
420 if (magfactor
< 1 || magfactor
> 32) {
421 printf("%s:invalid magnification factor ``%s''\n", argv
[0], argv
[i
]);
424 } else if (strcmp(argv
[i
], "-r") == 0) {
428 refreshrate
= atoi(argv
[i
]);
429 if (refreshrate
< 1) {
430 printf("%s:invalid refresh rate ``%s''\n", argv
[0], argv
[i
]);
433 } else if (strcmp(argv
[i
], "-h") == 0 || strcmp(argv
[i
], "--help") == 0) {
436 printf("Usage: %s [options]\n", argv
[0]);
438 puts(" -display <display> display that should be used");
439 puts(" -m <number> change magnification factor (default 2)");
440 puts(" -r <number> change refresh delay, in milliseconds (default 200)");
442 puts(" 1,2,3,4,5,6,7,8,9 change the magnification factor");
443 puts(" <space>, f freeze the 'camera', making it magnify only the current\n"
445 puts(" n create a new window");
446 puts(" m show/hide the pointer hotspot mark");
451 dpy
= XOpenDisplay(display
);
453 puts("could not open display");
458 vdpy
= XOpenDisplay(vdisplay
);
460 puts("could not open display to be viewed");
467 /* calculate how many rectangles we can send in a trip to the server */
468 rectBufferSize
= XMaxRequestSize(dpy
) - 128;
469 rectBufferSize
/= sizeof(XRectangle
);
470 if (rectBufferSize
< 1)
473 black
= BlackPixel(dpy
, DefaultScreen(dpy
));
475 scr
= WMCreateScreen(dpy
, 0);
477 cursorColor1
= WMCreateNamedColor(scr
, "#ff0000", False
);
478 cursorColor2
= WMCreateNamedColor(scr
, "#00ff00", False
);
480 newWindow(magfactor
);
482 WMScreenMainLoop(scr
);