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
);
309 static void keyHandler(XEvent
* event
, void *d
)
311 BufferData
*data
= (BufferData
*) d
;
314 WMView
*view
= WMWidgetView(data
->win
);
317 size
= WMGetViewSize(view
);
319 if (XLookupString(&event
->xkey
, buf
, 31, &ks
, NULL
) > 0) {
322 newWindow(data
->magfactor
);
325 data
->markPointerHotspot
= !data
->markPointerHotspot
;
329 data
->frozen
= !data
->frozen
;
331 data
->x
= event
->xkey
.x_root
;
332 data
->y
= event
->xkey
.y_root
;
333 sprintf(buf
, "[Magnify %ix]", data
->magfactor
);
335 sprintf(buf
, "Magnify %ix", data
->magfactor
);
337 WMSetWindowTitle(data
->win
, buf
);
348 resizeBufferData(data
, size
.width
, size
.height
, buf
[0] - '0');
350 sprintf(buf
, "[Magnify %ix]", data
->magfactor
);
352 sprintf(buf
, "Magnify %ix", data
->magfactor
);
354 WMSetWindowTitle(data
->win
, buf
);
360 static BufferData
*newWindow(int magfactor
)
369 win
= WMCreateWindow(scr
, "magnify");
370 WMResizeWidget(win
, 300, 200);
371 sprintf(buf
, "Magnify %ix", magfactor
);
372 WMSetWindowTitle(win
, buf
);
373 WMSetViewNotifySizeChanges(WMWidgetView(win
), True
);
375 label
= WMCreateLabel(win
);
376 WMResizeWidget(label
, 300, 200);
377 WMMoveWidget(label
, 0, 0);
378 WMSetLabelRelief(label
, WRSunken
);
379 WMSetLabelImagePosition(label
, WIPImageOnly
);
381 data
= makeBufferData(win
, label
, 300, 200, magfactor
);
383 WMCreateEventHandler(WMWidgetView(win
), KeyReleaseMask
, keyHandler
, data
);
385 WMAddNotificationObserver(resizedWindow
, data
, WMViewSizeDidChangeNotification
, WMWidgetView(win
));
387 WMRealizeWidget(win
);
389 WMMapSubwidgets(win
);
392 WMSetWindowCloseAction(win
, closeWindow
, data
);
393 data
->tid
= WMAddTimerHandler(refreshrate
, update
, data
);
398 int main(int argc
, char **argv
)
403 char *vdisplay
= NULL
;
406 WMInitializeApplication("Magnify", &argc
, argv
);
408 for (i
= 1; i
< argc
; i
++) {
409 if (strcmp(argv
[i
], "-display") == 0) {
414 } else if (strcmp(argv
[i
], "-vdisplay") == 0) {
419 } else if (strcmp(argv
[i
], "-m") == 0) {
423 magfactor
= atoi(argv
[i
]);
424 if (magfactor
< 1 || magfactor
> 32) {
425 printf("%s:invalid magnification factor ``%s''\n", argv
[0], argv
[i
]);
428 } else if (strcmp(argv
[i
], "-r") == 0) {
432 refreshrate
= atoi(argv
[i
]);
433 if (refreshrate
< 1) {
434 printf("%s:invalid refresh rate ``%s''\n", argv
[0], argv
[i
]);
437 } else if (strcmp(argv
[i
], "-h") == 0 || strcmp(argv
[i
], "--help") == 0) {
440 printf("Usage: %s [options]\n", argv
[0]);
442 puts(" -display <display> display that should be used");
443 puts(" -m <number> change magnification factor (default 2)");
444 puts(" -r <number> change refresh delay, in milliseconds (default 200)");
446 puts(" 1,2,3,4,5,6,7,8,9 change the magnification factor");
447 puts(" <space>, f freeze the 'camera', making it magnify only the current\n"
449 puts(" n create a new window");
450 puts(" m show/hide the pointer hotspot mark");
455 dpy
= XOpenDisplay(display
);
457 puts("could not open display");
462 vdpy
= XOpenDisplay(vdisplay
);
464 puts("could not open display to be viewed");
471 /* calculate how many rectangles we can send in a trip to the server */
472 rectBufferSize
= XMaxRequestSize(dpy
) - 128;
473 rectBufferSize
/= sizeof(XRectangle
);
474 if (rectBufferSize
< 1)
477 black
= BlackPixel(dpy
, DefaultScreen(dpy
));
479 scr
= WMCreateScreen(dpy
, 0);
481 cursorColor1
= WMCreateNamedColor(scr
, "#ff0000", False
);
482 cursorColor2
= WMCreateNamedColor(scr
, "#00ff00", False
);
484 data
= newWindow(magfactor
);
486 WMScreenMainLoop(scr
);