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>
17 * - lens that shows where it's magnifying
22 int refreshrate
= 200;
29 unsigned long lastpixel
;
30 unsigned long *buffer
;
32 int rwidth
, rheight
; /* size of window in real pixels */
51 Bool markPointerHotspot
;
58 static BufferData
*newWindow(int magfactor
);
63 int rectBufferSize
= 32;
67 WMColor
*cursorColor1
;
68 WMColor
*cursorColor2
;
76 makeBufferData(WMWindow
*win
, WMLabel
*label
, int width
, int height
,
81 data
= wmalloc(sizeof(BufferData
));
84 data
->rheight
= height
;
86 data
->refreshrate
= refreshrate
;
88 data
->firstDraw
= True
;
90 data
->magfactor
= magfactor
;
92 data
->rects
= wmalloc(sizeof(XRectangle
)*rectBufferSize
);
98 data
->pixmap
= WMCreatePixmap(scr
, width
, height
,
99 WMScreenDepth(scr
), False
);
100 WMSetLabelImage(data
->label
, data
->pixmap
);
102 data
->d
= WMGetPixmapXID(data
->pixmap
);
104 data
->frozen
= False
;
108 data
->buffer
= wmalloc(sizeof(unsigned long)*width
*height
);
109 memset(data
->buffer
, 0, width
*height
*sizeof(unsigned long));
111 data
->height
= height
;
118 resizeBufferData(BufferData
*data
, int width
, int height
, int magfactor
)
120 int w
= width
/magfactor
;
121 int h
= height
/magfactor
;
123 data
->rwidth
= width
;
124 data
->rheight
= height
;
125 data
->firstDraw
= True
;
126 data
->magfactor
= magfactor
;
127 data
->buffer
= wrealloc(data
->buffer
, sizeof(unsigned long)*w
*h
);
130 memset(data
->buffer
, 0, w
*h
*sizeof(unsigned long));
132 WMResizeWidget(data
->label
, width
, height
);
134 WMReleasePixmap(data
->pixmap
);
135 data
->pixmap
= WMCreatePixmap(scr
, width
, height
, WMScreenDepth(scr
),
137 WMSetLabelImage(data
->label
, data
->pixmap
);
139 data
->d
= WMGetPixmapXID(data
->pixmap
);
144 drawpoint(BufferData
*data
, unsigned long pixel
, int x
, int y
)
147 Bool flush
= (x
< 0);
150 if (data
->buffer
[x
+data
->width
*y
] == pixel
&& !data
->firstDraw
)
153 data
->buffer
[x
+data
->width
*y
] = pixel
;
156 gc
= XCreateGC(dpy
, DefaultRootWindow(dpy
), 0, NULL
);
159 if (!flush
&& data
->lastpixel
== pixel
&& data
->rectP
< rectBufferSize
) {
160 data
->rects
[data
->rectP
].x
= x
*data
->magfactor
;
161 data
->rects
[data
->rectP
].y
= y
*data
->magfactor
;
162 data
->rects
[data
->rectP
].width
= data
->magfactor
;
163 data
->rects
[data
->rectP
].height
= data
->magfactor
;
168 XSetForeground(dpy
, gc
, data
->lastpixel
);
169 XFillRectangles(dpy
, data
->d
, gc
, data
->rects
, data
->rectP
);
171 data
->rects
[data
->rectP
].x
= x
*data
->magfactor
;
172 data
->rects
[data
->rectP
].y
= y
*data
->magfactor
;
173 data
->rects
[data
->rectP
].width
= data
->magfactor
;
174 data
->rects
[data
->rectP
].height
= data
->magfactor
;
177 data
->lastpixel
= pixel
;
183 static inline unsigned long
184 getpix(XImage
*image
, int x
, int y
, int xoffs
, int yoffs
)
186 if (x
< xoffs
|| y
< yoffs
187 || x
>= xoffs
+ image
->width
|| y
>= yoffs
+ image
->height
) {
190 return XGetPixel(image
, x
-xoffs
, y
-yoffs
);
195 updateImage(BufferData
*data
, int rx
, int ry
)
200 int changedPixels
= 0;
215 if (gx
+ gw
>= WidthOfScreen(DefaultScreenOfDisplay(dpy
))) {
216 gw
= WidthOfScreen(DefaultScreenOfDisplay(dpy
)) - gx
;
223 if (gy
+ gh
>= HeightOfScreen(DefaultScreenOfDisplay(dpy
))) {
224 gh
= HeightOfScreen(DefaultScreenOfDisplay(dpy
)) - gy
;
227 image
= XGetImage(dpy
, DefaultRootWindow(dpy
), gx
, gy
, gw
, gh
,
231 for (y
= 0; y
< data
->height
; y
++) {
232 for (x
= 0; x
< data
->width
; x
++) {
235 pixel
= getpix(image
, x
-xoffs
, y
-yoffs
, xoffs
, yoffs
);
237 if (drawpoint(data
, pixel
, x
, y
))
241 /* flush the point cache */
242 drawpoint(data
, 0, -1, -1);
244 XDestroyImage(image
);
246 if (data
->markPointerHotspot
&& !data
->frozen
) {
249 rects
[0].x
= (data
->width
/2 - 3)*data
->magfactor
;
250 rects
[0].y
= (data
->height
/2)*data
->magfactor
;
251 rects
[0].width
= 2*data
->magfactor
;
252 rects
[0].height
= data
->magfactor
;
254 rects
[1].x
= (data
->width
/2 + 2)*data
->magfactor
;
255 rects
[1].y
= (data
->height
/2)*data
->magfactor
;
256 rects
[1].width
= 2*data
->magfactor
;
257 rects
[1].height
= data
->magfactor
;
259 XFillRectangles(dpy
, data
->d
, WMColorGC(cursorColor1
), rects
, 2);
261 rects
[2].y
= (data
->height
/2 - 3)*data
->magfactor
;
262 rects
[2].x
= (data
->width
/2)*data
->magfactor
;
263 rects
[2].height
= 2*data
->magfactor
;
264 rects
[2].width
= data
->magfactor
;
266 rects
[3].y
= (data
->height
/2 + 2)*data
->magfactor
;
267 rects
[3].x
= (data
->width
/2)*data
->magfactor
;
268 rects
[3].height
= 2*data
->magfactor
;
269 rects
[3].width
= data
->magfactor
;
271 XFillRectangles(dpy
, data
->d
, WMColorGC(cursorColor2
), rects
+ 2, 2);
274 if (changedPixels
> 0) {
275 WMRedisplayWidget(data
->label
);
278 data
->firstDraw
= False
;
285 BufferData
*data
= (BufferData
*)d
;
296 XQueryPointer(dpy
, DefaultRootWindow(dpy
), &win
, &win
, &rx
, &ry
,
299 updateImage(data
, rx
, ry
);
301 data
->tid
= WMAddTimerHandler(data
->refreshrate
, update
, data
);
305 void resizedWindow(void *d
, WMNotification
*notif
)
307 BufferData
*data
= (BufferData
*)d
;
308 WMView
*view
= (WMView
*)WMGetNotificationObject(notif
);
311 size
= WMGetViewSize(view
);
313 resizeBufferData(data
, size
.width
, size
.height
, data
->magfactor
);
318 void closeWindow(WMWidget
*w
, void *d
)
320 BufferData
*data
= (BufferData
*)d
;
323 if (windowCount
== 0) {
326 WMDeleteTimerHandler(data
->tid
);
330 WMReleasePixmap(data
->pixmap
);
338 clickHandler(XEvent
*event
, void *d
)
340 BufferData
*data
= (BufferData
*)d
;
342 data
->win
= WMCreateWindow(scr
, "setup");
343 WMSetWindowTitle(data
->win
, "Magnify Options");
345 data
->speed
= WMCreateSlider(data
->win
);
347 data
->magnify
= WMCreateSlider(data
->win
);
356 keyHandler(XEvent
*event
, void *d
)
358 BufferData
*data
= (BufferData
*)d
;
361 WMView
*view
= WMWidgetView(data
->win
);
364 size
= WMGetViewSize(view
);
366 if (XLookupString(&event
->xkey
, buf
, 31, &ks
, NULL
) > 0) {
369 newWindow(data
->magfactor
);
372 data
->markPointerHotspot
= !data
->markPointerHotspot
;
376 data
->frozen
= !data
->frozen
;
378 data
->x
= event
->xkey
.x_root
;
379 data
->y
= event
->xkey
.y_root
;
380 sprintf(buf
, "[Magnify %ix]", data
->magfactor
);
382 sprintf(buf
, "Magnify %ix", data
->magfactor
);
384 WMSetWindowTitle(data
->win
, buf
);
395 resizeBufferData(data
, size
.width
, size
.height
, buf
[0]-'0');
397 sprintf(buf
, "[Magnify %ix]", data
->magfactor
);
399 sprintf(buf
, "Magnify %ix", data
->magfactor
);
401 WMSetWindowTitle(data
->win
, buf
);
409 newWindow(int magfactor
)
418 win
= WMCreateWindow(scr
, "magnify");
419 WMResizeWidget(win
, 300, 200);
420 sprintf(buf
, "Magnify %ix", magfactor
);
421 WMSetWindowTitle(win
, buf
);
422 WMSetViewNotifySizeChanges(WMWidgetView(win
), True
);
424 label
= WMCreateLabel(win
);
425 WMResizeWidget(label
, 300, 200);
426 WMMoveWidget(label
, 0, 0);
427 WMSetLabelRelief(label
, WRSunken
);
428 WMSetLabelImagePosition(label
, WIPImageOnly
);
430 data
= makeBufferData(win
, label
, 300, 200, magfactor
);
432 WMCreateEventHandler(WMWidgetView(win
), KeyReleaseMask
,
435 WMAddNotificationObserver(resizedWindow
, data
,
436 WMViewSizeDidChangeNotification
,
439 WMRealizeWidget(win
);
441 WMMapSubwidgets(win
);
444 WMSetWindowCloseAction(win
, closeWindow
, data
);
445 data
->tid
= WMAddTimerHandler(refreshrate
, update
, data
);
451 int main(int argc
, char **argv
)
458 WMButton
*radio
, *tradio
;
460 WMInitializeApplication("Magnify", &argc
, argv
);
463 for (i
= 1; i
< argc
; i
++) {
464 if (strcmp(argv
[i
], "-display")==0) {
469 } else if (strcmp(argv
[i
], "-m")==0) {
473 magfactor
= atoi(argv
[i
]);
474 if (magfactor
< 1 || magfactor
> 32) {
475 printf("%s:invalid magnification factor ``%s''\n", argv
[0],
479 } else if (strcmp(argv
[i
], "-r")==0) {
483 refreshrate
= atoi(argv
[i
]);
484 if (refreshrate
< 1) {
485 printf("%s:invalid refresh rate ``%s''\n", argv
[0], argv
[i
]);
488 } else if (strcmp(argv
[i
], "-h")==0
489 || strcmp(argv
[i
], "--help")==0) {
492 printf("Syntax: %s [options]\n",
495 puts(" -display <display> display that should be used");
496 puts(" -m <number> change magnification factor (default 2)");
497 puts(" -r <number> change refresh delay, in milliseconds (default 200)");
499 puts(" 1,2,3,4,5,6,7,8,9 change the magnification factor");
500 puts(" <space>, f freeze the 'camera', making it magnify only the current\n"
502 puts(" n create a new window");
503 puts(" m show/hide the pointer hotspot mark");
508 dpy
= XOpenDisplay("");
510 puts("couldnt open display");
514 /* calculate how many rectangles we can send in a trip to the server */
515 rectBufferSize
= XMaxRequestSize(dpy
) - 128;
516 rectBufferSize
/= sizeof(XRectangle
);
517 if (rectBufferSize
< 1)
520 black
= BlackPixel(dpy
, DefaultScreen(dpy
));
522 scr
= WMCreateScreen(dpy
, 0);
524 cursorColor1
= WMCreateNamedColor(scr
, "#ff0000", False
);
525 cursorColor2
= WMCreateNamedColor(scr
, "#00ff00", False
);
527 data
= newWindow(magfactor
);
529 WMScreenMainLoop(scr
);