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
);
103 data
->height
= height
;
108 static void resizeBufferData(BufferData
* data
, int width
, int height
, int magfactor
)
110 int w
= width
/ magfactor
;
111 int h
= height
/ magfactor
;
113 data
->rwidth
= width
;
114 data
->rheight
= height
;
115 data
->firstDraw
= True
;
116 data
->magfactor
= magfactor
;
117 data
->buffer
= wrealloc(data
->buffer
, sizeof(unsigned long) * w
* h
);
120 memset(data
->buffer
, 0, w
* h
* sizeof(unsigned long));
122 WMResizeWidget(data
->label
, width
, height
);
124 WMReleasePixmap(data
->pixmap
);
125 data
->pixmap
= WMCreatePixmap(scr
, width
, height
, WMScreenDepth(scr
), False
);
126 WMSetLabelImage(data
->label
, data
->pixmap
);
128 data
->d
= WMGetPixmapXID(data
->pixmap
);
131 static int drawpoint(BufferData
* data
, unsigned long pixel
, int x
, int y
)
134 Bool flush
= (x
< 0);
137 if (data
->buffer
[x
+ data
->width
* y
] == pixel
&& !data
->firstDraw
)
140 data
->buffer
[x
+ data
->width
* y
] = pixel
;
143 gc
= XCreateGC(dpy
, DefaultRootWindow(dpy
), 0, NULL
);
146 if (!flush
&& data
->lastpixel
== pixel
&& data
->rectP
< rectBufferSize
) {
147 data
->rects
[data
->rectP
].x
= x
* data
->magfactor
;
148 data
->rects
[data
->rectP
].y
= y
* data
->magfactor
;
149 data
->rects
[data
->rectP
].width
= data
->magfactor
;
150 data
->rects
[data
->rectP
].height
= data
->magfactor
;
155 XSetForeground(dpy
, gc
, data
->lastpixel
);
156 XFillRectangles(dpy
, data
->d
, gc
, data
->rects
, data
->rectP
);
158 data
->rects
[data
->rectP
].x
= x
* data
->magfactor
;
159 data
->rects
[data
->rectP
].y
= y
* data
->magfactor
;
160 data
->rects
[data
->rectP
].width
= data
->magfactor
;
161 data
->rects
[data
->rectP
].height
= data
->magfactor
;
164 data
->lastpixel
= pixel
;
169 static inline unsigned long getpix(XImage
* image
, int x
, int y
, int xoffs
, int yoffs
)
171 if (x
< xoffs
|| y
< yoffs
|| x
>= xoffs
+ image
->width
|| y
>= yoffs
+ image
->height
) {
174 return XGetPixel(image
, x
- xoffs
, y
- yoffs
);
177 static void updateImage(BufferData
* data
, int rx
, int ry
)
182 int changedPixels
= 0;
197 if (gx
+ gw
>= WidthOfScreen(DefaultScreenOfDisplay(vdpy
))) {
198 gw
= WidthOfScreen(DefaultScreenOfDisplay(vdpy
)) - gx
;
205 if (gy
+ gh
>= HeightOfScreen(DefaultScreenOfDisplay(vdpy
))) {
206 gh
= HeightOfScreen(DefaultScreenOfDisplay(vdpy
)) - gy
;
209 image
= XGetImage(vdpy
, DefaultRootWindow(vdpy
), gx
, gy
, gw
, gh
, AllPlanes
, ZPixmap
);
211 for (y
= 0; y
< data
->height
; y
++) {
212 for (x
= 0; x
< data
->width
; x
++) {
215 pixel
= getpix(image
, x
, y
, xoffs
, yoffs
);
217 if (drawpoint(data
, pixel
, x
, y
))
221 /* flush the point cache */
222 drawpoint(data
, 0, -1, -1);
224 XDestroyImage(image
);
226 if (data
->markPointerHotspot
&& !data
->frozen
) {
229 rects
[0].x
= (data
->width
/ 2 - 3) * data
->magfactor
;
230 rects
[0].y
= (data
->height
/ 2) * data
->magfactor
;
231 rects
[0].width
= 2 * data
->magfactor
;
232 rects
[0].height
= data
->magfactor
;
234 rects
[1].x
= (data
->width
/ 2 + 2) * data
->magfactor
;
235 rects
[1].y
= (data
->height
/ 2) * data
->magfactor
;
236 rects
[1].width
= 2 * data
->magfactor
;
237 rects
[1].height
= data
->magfactor
;
239 XFillRectangles(dpy
, data
->d
, WMColorGC(cursorColor1
), rects
, 2);
241 rects
[2].y
= (data
->height
/ 2 - 3) * data
->magfactor
;
242 rects
[2].x
= (data
->width
/ 2) * data
->magfactor
;
243 rects
[2].height
= 2 * data
->magfactor
;
244 rects
[2].width
= data
->magfactor
;
246 rects
[3].y
= (data
->height
/ 2 + 2) * data
->magfactor
;
247 rects
[3].x
= (data
->width
/ 2) * data
->magfactor
;
248 rects
[3].height
= 2 * data
->magfactor
;
249 rects
[3].width
= data
->magfactor
;
251 XFillRectangles(dpy
, data
->d
, WMColorGC(cursorColor2
), rects
+ 2, 2);
254 if (changedPixels
> 0) {
255 WMRedisplayWidget(data
->label
);
258 data
->firstDraw
= False
;
261 static void update(void *d
)
263 BufferData
*data
= (BufferData
*) d
;
273 XQueryPointer(dpy
, DefaultRootWindow(dpy
), &win
, &win
, &rx
, &ry
, &bla
, &bla
, &ubla
);
275 updateImage(data
, rx
, ry
);
277 data
->tid
= WMAddTimerHandler(data
->refreshrate
, update
, data
);
280 void resizedWindow(void *d
, WMNotification
* notif
)
282 BufferData
*data
= (BufferData
*) d
;
283 WMView
*view
= (WMView
*) WMGetNotificationObject(notif
);
286 size
= WMGetViewSize(view
);
288 resizeBufferData(data
, size
.width
, size
.height
, data
->magfactor
);
291 void closeWindow(WMWidget
* w
, void *d
)
293 BufferData
*data
= (BufferData
*) d
;
296 if (windowCount
== 0) {
299 WMDeleteTimerHandler(data
->tid
);
303 WMReleasePixmap(data
->pixmap
);
308 static void keyHandler(XEvent
* event
, void *d
)
310 BufferData
*data
= (BufferData
*) d
;
313 WMView
*view
= WMWidgetView(data
->win
);
316 size
= WMGetViewSize(view
);
318 if (XLookupString(&event
->xkey
, buf
, 31, &ks
, NULL
) > 0) {
321 newWindow(data
->magfactor
);
324 data
->markPointerHotspot
= !data
->markPointerHotspot
;
328 data
->frozen
= !data
->frozen
;
330 data
->x
= event
->xkey
.x_root
;
331 data
->y
= event
->xkey
.y_root
;
332 sprintf(buf
, "[Magnify %ix]", data
->magfactor
);
334 sprintf(buf
, "Magnify %ix", data
->magfactor
);
336 WMSetWindowTitle(data
->win
, buf
);
347 resizeBufferData(data
, size
.width
, size
.height
, buf
[0] - '0');
349 sprintf(buf
, "[Magnify %ix]", data
->magfactor
);
351 sprintf(buf
, "Magnify %ix", data
->magfactor
);
353 WMSetWindowTitle(data
->win
, buf
);
359 static BufferData
*newWindow(int magfactor
)
368 win
= WMCreateWindow(scr
, "magnify");
369 WMResizeWidget(win
, 300, 200);
370 sprintf(buf
, "Magnify %ix", magfactor
);
371 WMSetWindowTitle(win
, buf
);
372 WMSetViewNotifySizeChanges(WMWidgetView(win
), True
);
374 label
= WMCreateLabel(win
);
375 WMResizeWidget(label
, 300, 200);
376 WMMoveWidget(label
, 0, 0);
377 WMSetLabelRelief(label
, WRSunken
);
378 WMSetLabelImagePosition(label
, WIPImageOnly
);
380 data
= makeBufferData(win
, label
, 300, 200, magfactor
);
382 WMCreateEventHandler(WMWidgetView(win
), KeyReleaseMask
, keyHandler
, data
);
384 WMAddNotificationObserver(resizedWindow
, data
, WMViewSizeDidChangeNotification
, WMWidgetView(win
));
386 WMRealizeWidget(win
);
388 WMMapSubwidgets(win
);
391 WMSetWindowCloseAction(win
, closeWindow
, data
);
392 data
->tid
= WMAddTimerHandler(refreshrate
, update
, data
);
397 int main(int argc
, char **argv
)
401 char *vdisplay
= NULL
;
404 WMInitializeApplication("Magnify", &argc
, argv
);
406 for (i
= 1; i
< argc
; i
++) {
407 if (strcmp(argv
[i
], "-display") == 0) {
412 } else if (strcmp(argv
[i
], "-vdisplay") == 0) {
417 } else if (strcmp(argv
[i
], "-m") == 0) {
421 magfactor
= atoi(argv
[i
]);
422 if (magfactor
< 1 || magfactor
> 32) {
423 printf("%s:invalid magnification factor ``%s''\n", argv
[0], argv
[i
]);
426 } else if (strcmp(argv
[i
], "-r") == 0) {
430 refreshrate
= atoi(argv
[i
]);
431 if (refreshrate
< 1) {
432 printf("%s:invalid refresh rate ``%s''\n", argv
[0], argv
[i
]);
435 } else if (strcmp(argv
[i
], "-h") == 0 || strcmp(argv
[i
], "--help") == 0) {
438 printf("Usage: %s [options]\n", argv
[0]);
440 puts(" -display <display> display that should be used");
441 puts(" -m <number> change magnification factor (default 2)");
442 puts(" -r <number> change refresh delay, in milliseconds (default 200)");
444 puts(" 1,2,3,4,5,6,7,8,9 change the magnification factor");
445 puts(" <space>, f freeze the 'camera', making it magnify only the current\n"
447 puts(" n create a new window");
448 puts(" m show/hide the pointer hotspot mark");
453 dpy
= XOpenDisplay(display
);
455 puts("could not open display");
460 vdpy
= XOpenDisplay(vdisplay
);
462 puts("could not open display to be viewed");
469 /* calculate how many rectangles we can send in a trip to the server */
470 rectBufferSize
= XMaxRequestSize(dpy
) - 128;
471 rectBufferSize
/= sizeof(XRectangle
);
472 if (rectBufferSize
< 1)
475 black
= BlackPixel(dpy
, DefaultScreen(dpy
));
477 scr
= WMCreateScreen(dpy
, 0);
479 cursorColor1
= WMCreateNamedColor(scr
, "#ff0000", False
);
480 cursorColor2
= WMCreateNamedColor(scr
, "#00ff00", False
);
482 newWindow(magfactor
);
484 WMScreenMainLoop(scr
);