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;
30 unsigned long lastpixel
;
31 unsigned long *buffer
;
33 int rwidth
, rheight
; /* size of window in real pixels */
52 Bool markPointerHotspot
;
59 static BufferData
*newWindow(int magfactor
);
64 int rectBufferSize
= 32;
68 WMColor
*cursorColor1
;
69 WMColor
*cursorColor2
;
77 makeBufferData(WMWindow
*win
, WMLabel
*label
, int width
, int height
,
82 data
= wmalloc(sizeof(BufferData
));
85 data
->rheight
= height
;
87 data
->refreshrate
= refreshrate
;
89 data
->firstDraw
= True
;
91 data
->magfactor
= magfactor
;
93 data
->rects
= wmalloc(sizeof(XRectangle
)*rectBufferSize
);
99 data
->pixmap
= WMCreatePixmap(scr
, width
, height
,
100 WMScreenDepth(scr
), False
);
101 WMSetLabelImage(data
->label
, data
->pixmap
);
103 data
->d
= WMGetPixmapXID(data
->pixmap
);
105 data
->frozen
= False
;
109 data
->buffer
= wmalloc(sizeof(unsigned long)*width
*height
);
110 memset(data
->buffer
, 0, width
*height
*sizeof(unsigned long));
112 data
->height
= height
;
119 resizeBufferData(BufferData
*data
, int width
, int height
, int magfactor
)
121 int w
= width
/magfactor
;
122 int h
= height
/magfactor
;
124 data
->rwidth
= width
;
125 data
->rheight
= height
;
126 data
->firstDraw
= True
;
127 data
->magfactor
= magfactor
;
128 data
->buffer
= wrealloc(data
->buffer
, sizeof(unsigned long)*w
*h
);
131 memset(data
->buffer
, 0, w
*h
*sizeof(unsigned long));
133 WMResizeWidget(data
->label
, width
, height
);
135 WMReleasePixmap(data
->pixmap
);
136 data
->pixmap
= WMCreatePixmap(scr
, width
, height
, WMScreenDepth(scr
),
138 WMSetLabelImage(data
->label
, data
->pixmap
);
140 data
->d
= WMGetPixmapXID(data
->pixmap
);
145 drawpoint(BufferData
*data
, unsigned long pixel
, int x
, int y
)
148 Bool flush
= (x
< 0);
151 if (data
->buffer
[x
+data
->width
*y
] == pixel
&& !data
->firstDraw
)
154 data
->buffer
[x
+data
->width
*y
] = pixel
;
157 gc
= XCreateGC(dpy
, DefaultRootWindow(dpy
), 0, NULL
);
160 if (!flush
&& data
->lastpixel
== pixel
&& data
->rectP
< rectBufferSize
) {
161 data
->rects
[data
->rectP
].x
= x
*data
->magfactor
;
162 data
->rects
[data
->rectP
].y
= y
*data
->magfactor
;
163 data
->rects
[data
->rectP
].width
= data
->magfactor
;
164 data
->rects
[data
->rectP
].height
= data
->magfactor
;
169 XSetForeground(dpy
, gc
, data
->lastpixel
);
170 XFillRectangles(dpy
, data
->d
, gc
, data
->rects
, data
->rectP
);
172 data
->rects
[data
->rectP
].x
= x
*data
->magfactor
;
173 data
->rects
[data
->rectP
].y
= y
*data
->magfactor
;
174 data
->rects
[data
->rectP
].width
= data
->magfactor
;
175 data
->rects
[data
->rectP
].height
= data
->magfactor
;
178 data
->lastpixel
= pixel
;
184 static inline unsigned long
185 getpix(XImage
*image
, int x
, int y
, int xoffs
, int yoffs
)
187 if (x
< xoffs
|| y
< yoffs
188 || x
>= xoffs
+ image
->width
|| y
>= yoffs
+ image
->height
) {
191 return XGetPixel(image
, x
-xoffs
, y
-yoffs
);
196 updateImage(BufferData
*data
, int rx
, int ry
)
201 int changedPixels
= 0;
216 if (gx
+ gw
>= WidthOfScreen(DefaultScreenOfDisplay(vdpy
))) {
217 gw
= WidthOfScreen(DefaultScreenOfDisplay(vdpy
)) - gx
;
224 if (gy
+ gh
>= HeightOfScreen(DefaultScreenOfDisplay(vdpy
))) {
225 gh
= HeightOfScreen(DefaultScreenOfDisplay(vdpy
)) - gy
;
228 image
= XGetImage(vdpy
, DefaultRootWindow(vdpy
), gx
, gy
, gw
, gh
,
232 for (y
= 0; y
< data
->height
; y
++) {
233 for (x
= 0; x
< data
->width
; x
++) {
236 pixel
= getpix(image
, x
, y
, xoffs
, yoffs
);
238 if (drawpoint(data
, pixel
, x
, y
))
242 /* flush the point cache */
243 drawpoint(data
, 0, -1, -1);
245 XDestroyImage(image
);
247 if (data
->markPointerHotspot
&& !data
->frozen
) {
250 rects
[0].x
= (data
->width
/2 - 3)*data
->magfactor
;
251 rects
[0].y
= (data
->height
/2)*data
->magfactor
;
252 rects
[0].width
= 2*data
->magfactor
;
253 rects
[0].height
= data
->magfactor
;
255 rects
[1].x
= (data
->width
/2 + 2)*data
->magfactor
;
256 rects
[1].y
= (data
->height
/2)*data
->magfactor
;
257 rects
[1].width
= 2*data
->magfactor
;
258 rects
[1].height
= data
->magfactor
;
260 XFillRectangles(dpy
, data
->d
, WMColorGC(cursorColor1
), rects
, 2);
262 rects
[2].y
= (data
->height
/2 - 3)*data
->magfactor
;
263 rects
[2].x
= (data
->width
/2)*data
->magfactor
;
264 rects
[2].height
= 2*data
->magfactor
;
265 rects
[2].width
= data
->magfactor
;
267 rects
[3].y
= (data
->height
/2 + 2)*data
->magfactor
;
268 rects
[3].x
= (data
->width
/2)*data
->magfactor
;
269 rects
[3].height
= 2*data
->magfactor
;
270 rects
[3].width
= data
->magfactor
;
272 XFillRectangles(dpy
, data
->d
, WMColorGC(cursorColor2
), rects
+ 2, 2);
275 if (changedPixels
> 0) {
276 WMRedisplayWidget(data
->label
);
279 data
->firstDraw
= False
;
286 BufferData
*data
= (BufferData
*)d
;
297 XQueryPointer(dpy
, DefaultRootWindow(dpy
), &win
, &win
, &rx
, &ry
,
300 updateImage(data
, rx
, ry
);
302 data
->tid
= WMAddTimerHandler(data
->refreshrate
, update
, data
);
306 void resizedWindow(void *d
, WMNotification
*notif
)
308 BufferData
*data
= (BufferData
*)d
;
309 WMView
*view
= (WMView
*)WMGetNotificationObject(notif
);
312 size
= WMGetViewSize(view
);
314 resizeBufferData(data
, size
.width
, size
.height
, data
->magfactor
);
319 void closeWindow(WMWidget
*w
, void *d
)
321 BufferData
*data
= (BufferData
*)d
;
324 if (windowCount
== 0) {
327 WMDeleteTimerHandler(data
->tid
);
331 WMReleasePixmap(data
->pixmap
);
339 clickHandler(XEvent
*event
, void *d
)
341 BufferData
*data
= (BufferData
*)d
;
343 data
->win
= WMCreateWindow(scr
, "setup");
344 WMSetWindowTitle(data
->win
, "Magnify Options");
346 data
->speed
= WMCreateSlider(data
->win
);
348 data
->magnify
= WMCreateSlider(data
->win
);
357 keyHandler(XEvent
*event
, void *d
)
359 BufferData
*data
= (BufferData
*)d
;
362 WMView
*view
= WMWidgetView(data
->win
);
365 size
= WMGetViewSize(view
);
367 if (XLookupString(&event
->xkey
, buf
, 31, &ks
, NULL
) > 0) {
370 newWindow(data
->magfactor
);
373 data
->markPointerHotspot
= !data
->markPointerHotspot
;
377 data
->frozen
= !data
->frozen
;
379 data
->x
= event
->xkey
.x_root
;
380 data
->y
= event
->xkey
.y_root
;
381 sprintf(buf
, "[Magnify %ix]", data
->magfactor
);
383 sprintf(buf
, "Magnify %ix", data
->magfactor
);
385 WMSetWindowTitle(data
->win
, buf
);
396 resizeBufferData(data
, size
.width
, size
.height
, buf
[0]-'0');
398 sprintf(buf
, "[Magnify %ix]", data
->magfactor
);
400 sprintf(buf
, "Magnify %ix", data
->magfactor
);
402 WMSetWindowTitle(data
->win
, buf
);
410 newWindow(int magfactor
)
419 win
= WMCreateWindow(scr
, "magnify");
420 WMResizeWidget(win
, 300, 200);
421 sprintf(buf
, "Magnify %ix", magfactor
);
422 WMSetWindowTitle(win
, buf
);
423 WMSetViewNotifySizeChanges(WMWidgetView(win
), True
);
425 label
= WMCreateLabel(win
);
426 WMResizeWidget(label
, 300, 200);
427 WMMoveWidget(label
, 0, 0);
428 WMSetLabelRelief(label
, WRSunken
);
429 WMSetLabelImagePosition(label
, WIPImageOnly
);
431 data
= makeBufferData(win
, label
, 300, 200, magfactor
);
433 WMCreateEventHandler(WMWidgetView(win
), KeyReleaseMask
,
436 WMAddNotificationObserver(resizedWindow
, data
,
437 WMViewSizeDidChangeNotification
,
440 WMRealizeWidget(win
);
442 WMMapSubwidgets(win
);
445 WMSetWindowCloseAction(win
, closeWindow
, data
);
446 data
->tid
= WMAddTimerHandler(refreshrate
, update
, data
);
452 int main(int argc
, char **argv
)
457 char *vdisplay
= NULL
;
460 WMButton
*radio
, *tradio
;
462 WMInitializeApplication("Magnify", &argc
, argv
);
465 for (i
= 1; i
< argc
; i
++) {
466 if (strcmp(argv
[i
], "-display")==0) {
471 } else if (strcmp(argv
[i
], "-vdisplay")==0) {
476 } else if (strcmp(argv
[i
], "-m")==0) {
480 magfactor
= atoi(argv
[i
]);
481 if (magfactor
< 1 || magfactor
> 32) {
482 printf("%s:invalid magnification factor ``%s''\n", argv
[0],
486 } else if (strcmp(argv
[i
], "-r")==0) {
490 refreshrate
= atoi(argv
[i
]);
491 if (refreshrate
< 1) {
492 printf("%s:invalid refresh rate ``%s''\n", argv
[0], argv
[i
]);
495 } else if (strcmp(argv
[i
], "-h")==0
496 || strcmp(argv
[i
], "--help")==0) {
499 printf("Syntax: %s [options]\n",
502 puts(" -display <display> display that should be used");
503 puts(" -m <number> change magnification factor (default 2)");
504 puts(" -r <number> change refresh delay, in milliseconds (default 200)");
506 puts(" 1,2,3,4,5,6,7,8,9 change the magnification factor");
507 puts(" <space>, f freeze the 'camera', making it magnify only the current\n"
509 puts(" n create a new window");
510 puts(" m show/hide the pointer hotspot mark");
515 dpy
= XOpenDisplay(display
);
517 puts("couldnt open display");
522 vdpy
= XOpenDisplay(vdisplay
);
524 puts("couldnt open display to be viewed");
531 /* calculate how many rectangles we can send in a trip to the server */
532 rectBufferSize
= XMaxRequestSize(dpy
) - 128;
533 rectBufferSize
/= sizeof(XRectangle
);
534 if (rectBufferSize
< 1)
537 black
= BlackPixel(dpy
, DefaultScreen(dpy
));
539 scr
= WMCreateScreen(dpy
, 0);
541 cursorColor1
= WMCreateNamedColor(scr
, "#ff0000", False
);
542 cursorColor2
= WMCreateNamedColor(scr
, "#00ff00", False
);
544 data
= newWindow(magfactor
);
546 WMScreenMainLoop(scr
);