f77cf10ae7c19e28abebd7b0aeb80eb132270205
[wmaker-crm.git] / util / wmagnify.c
blobf77cf10ae7c19e28abebd7b0aeb80eb132270205
1 /*
2 * magnify - a X utility for magnifying screen image
4 * 2000/5/21 Alfredo K. Kojima
6 * This program is in the Public Domain.
7 */
8 #include <config.h>
10 #include <X11/Xproto.h>
12 #include <WINGs/WINGs.h>
13 #include <stdlib.h>
14 #include <string.h>
15 #include <stdio.h>
18 * TODO:
19 * - lens that shows where it's magnifying
24 int refreshrate = 200;
26 typedef struct {
27 Drawable d;
28 XRectangle *rects;
29 int rectP;
30 unsigned long lastpixel;
31 unsigned long *buffer;
32 int width, height;
33 int rwidth, rheight; /* size of window in real pixels */
34 int magfactor;
35 int refreshrate;
37 WMWindow *win;
38 WMLabel *label;
39 WMPixmap *pixmap;
41 WMWindow *dlg;
43 WMSlider *speed;
44 WMSlider *magnify;
45 WMButton *okB;
46 WMButton *cancelB;
47 WMButton *newB;
49 int x, y;
50 Bool frozen;
51 Bool firstDraw;
52 Bool markPointerHotspot;
54 WMHandlerID tid;
55 } BufferData;
57 static BufferData *newWindow(int magfactor);
59 int windowCount = 0;
61 int rectBufferSize = 32;
62 Display *dpy, *vdpy;
63 WMScreen *scr;
64 unsigned int black;
65 WMColor *cursorColor1;
66 WMColor *cursorColor2;
69 static BufferData *makeBufferData(WMWindow * win, WMLabel * label, int width, int height, int magfactor)
71 BufferData *data;
73 data = wmalloc(sizeof(BufferData));
75 data->rwidth = width;
76 data->rheight = height;
78 data->refreshrate = refreshrate;
80 data->firstDraw = True;
82 data->magfactor = magfactor;
84 data->rects = wmalloc(sizeof(XRectangle) * rectBufferSize);
85 data->rectP = 0;
87 data->win = win;
88 data->label = label;
90 data->pixmap = WMCreatePixmap(scr, width, height, WMScreenDepth(scr), False);
91 WMSetLabelImage(data->label, data->pixmap);
93 data->d = WMGetPixmapXID(data->pixmap);
95 data->frozen = False;
97 width /= magfactor;
98 height /= magfactor;
99 data->buffer = wmalloc(sizeof(unsigned long) * width * height);
100 data->width = width;
101 data->height = height;
103 return data;
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);
116 data->width = w;
117 data->height = 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)
131 static GC gc = NULL;
132 Bool flush = (x < 0);
134 if (!flush) {
135 if (data->buffer[x + data->width * y] == pixel && !data->firstDraw)
136 return 0;
138 data->buffer[x + data->width * y] = pixel;
140 if (gc == NULL) {
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;
149 data->rectP++;
151 return 0;
153 XSetForeground(dpy, gc, data->lastpixel);
154 XFillRectangles(dpy, data->d, gc, data->rects, data->rectP);
155 data->rectP = 0;
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;
160 data->rectP++;
162 data->lastpixel = pixel;
164 return 1;
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) {
170 return black;
172 return XGetPixel(image, x - xoffs, y - yoffs);
175 static void updateImage(BufferData * data, int rx, int ry)
177 int gx, gy, gw, gh;
178 int x, y;
179 int xoffs, yoffs;
180 int changedPixels = 0;
181 XImage *image;
183 gw = data->width;
184 gh = data->height;
186 gx = rx - gw / 2;
187 gy = ry - gh / 2;
189 xoffs = yoffs = 0;
190 if (gx < 0) {
191 xoffs = abs(gx);
192 gw += gx;
193 gx = 0;
195 if (gx + gw >= WidthOfScreen(DefaultScreenOfDisplay(vdpy))) {
196 gw = WidthOfScreen(DefaultScreenOfDisplay(vdpy)) - gx;
198 if (gy < 0) {
199 yoffs = abs(gy);
200 gh += gy;
201 gy = 0;
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++) {
211 unsigned long pixel;
213 pixel = getpix(image, x, y, xoffs, yoffs);
215 if (drawpoint(data, pixel, x, y))
216 changedPixels++;
219 /* flush the point cache */
220 drawpoint(data, 0, -1, -1);
222 XDestroyImage(image);
224 if (data->markPointerHotspot && !data->frozen) {
225 XRectangle rects[4];
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;
262 Window win;
263 int rx, ry;
264 int bla;
265 unsigned ubla;
267 if (data->frozen) {
268 rx = data->x;
269 ry = data->y;
270 } else {
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 void resizedWindow(void *d, WMNotification * notif)
280 BufferData *data = (BufferData *) d;
281 WMView *view = (WMView *) WMGetNotificationObject(notif);
282 WMSize size;
284 size = WMGetViewSize(view);
286 resizeBufferData(data, size.width, size.height, data->magfactor);
289 void closeWindow(WMWidget * w, void *d)
291 BufferData *data = (BufferData *) d;
293 windowCount--;
294 if (windowCount == 0) {
295 exit(0);
296 } else {
297 WMDeleteTimerHandler(data->tid);
298 WMDestroyWidget(w);
299 wfree(data->buffer);
300 wfree(data->rects);
301 WMReleasePixmap(data->pixmap);
302 wfree(data);
306 static void keyHandler(XEvent * event, void *d)
308 BufferData *data = (BufferData *) d;
309 char buf[32];
310 KeySym ks;
311 WMView *view = WMWidgetView(data->win);
312 WMSize size;
314 size = WMGetViewSize(view);
316 if (XLookupString(&event->xkey, buf, 31, &ks, NULL) > 0) {
317 switch (buf[0]) {
318 case 'n':
319 newWindow(data->magfactor);
320 break;
321 case 'm':
322 data->markPointerHotspot = !data->markPointerHotspot;
323 break;
324 case 'f':
325 case ' ':
326 data->frozen = !data->frozen;
327 if (data->frozen) {
328 data->x = event->xkey.x_root;
329 data->y = event->xkey.y_root;
330 sprintf(buf, "[Magnify %ix]", data->magfactor);
331 } else {
332 sprintf(buf, "Magnify %ix", data->magfactor);
334 WMSetWindowTitle(data->win, buf);
335 break;
336 case '1':
337 case '2':
338 case '3':
339 case '4':
340 case '5':
341 case '6':
342 case '7':
343 case '8':
344 case '9':
345 resizeBufferData(data, size.width, size.height, buf[0] - '0');
346 if (data->frozen) {
347 sprintf(buf, "[Magnify %ix]", data->magfactor);
348 } else {
349 sprintf(buf, "Magnify %ix", data->magfactor);
351 WMSetWindowTitle(data->win, buf);
352 break;
357 static BufferData *newWindow(int magfactor)
359 WMWindow *win;
360 WMLabel *label;
361 BufferData *data;
362 char buf[32];
364 windowCount++;
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);
387 WMMapWidget(win);
389 WMSetWindowCloseAction(win, closeWindow, data);
390 data->tid = WMAddTimerHandler(refreshrate, update, data);
392 return data;
395 int main(int argc, char **argv)
397 int i;
398 char *display = "";
399 char *vdisplay = NULL;
400 int magfactor = 2;
402 WMInitializeApplication("Magnify", &argc, argv);
404 for (i = 1; i < argc; i++) {
405 if (strcmp(argv[i], "-display") == 0) {
406 i++;
407 if (i >= argc)
408 goto help;
409 display = argv[i];
410 } else if (strcmp(argv[i], "-vdisplay") == 0) {
411 i++;
412 if (i >= argc)
413 goto help;
414 vdisplay = argv[i];
415 } else if (strcmp(argv[i], "-m") == 0) {
416 i++;
417 if (i >= argc)
418 goto help;
419 magfactor = atoi(argv[i]);
420 if (magfactor < 1 || magfactor > 32) {
421 printf("%s:invalid magnification factor ``%s''\n", argv[0], argv[i]);
422 exit(1);
424 } else if (strcmp(argv[i], "-r") == 0) {
425 i++;
426 if (i >= argc)
427 goto help;
428 refreshrate = atoi(argv[i]);
429 if (refreshrate < 1) {
430 printf("%s:invalid refresh rate ``%s''\n", argv[0], argv[i]);
431 exit(1);
433 } else if (strcmp(argv[i], "-h") == 0 || strcmp(argv[i], "--help") == 0) {
434 help:
436 printf("Usage: %s [options]\n", argv[0]);
437 puts("Options:");
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)");
441 puts("Keys:");
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"
444 " position");
445 puts(" n create a new window");
446 puts(" m show/hide the pointer hotspot mark");
447 exit(0);
451 dpy = XOpenDisplay(display);
452 if (!dpy) {
453 puts("could not open display");
454 exit(1);
457 if (vdisplay) {
458 vdpy = XOpenDisplay(vdisplay);
459 if (!vdpy) {
460 puts("could not open display to be viewed");
461 exit(1);
463 } else {
464 vdpy = dpy;
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)
471 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);
484 return 0;