- Made scrolling of text in dialog panel smoother
[wmaker-crm.git] / util / wmagnify.c
blobec736f5aa8dcae00dc2015d6b8714f25886bb7ed
1 /*
2 * magnify - a X utility for magnifying screen image
3 *
4 * 2000/5/21 Alfredo K. Kojima
5 *
6 * This program is in the Public Domain.
7 */
9 #include <X11/Xproto.h>
11 #include <WINGs/WINGs.h>
12 #include <stdlib.h>
13 #include <stdio.h>
16 * TODO:
17 * - lens that shows where it's magnifying
22 int refreshrate = 200;
25 typedef struct {
26 Drawable d;
27 XRectangle *rects;
28 int rectP;
29 unsigned long lastpixel;
30 unsigned long *buffer;
31 int width, height;
32 int rwidth, rheight; /* size of window in real pixels */
33 int magfactor;
34 int refreshrate;
36 WMWindow *win;
37 WMLabel *label;
38 WMPixmap *pixmap;
40 WMWindow *dlg;
42 WMSlider *speed;
43 WMSlider *magnify;
44 WMButton *okB;
45 WMButton *cancelB;
46 WMButton *newB;
48 int x, y;
49 Bool frozen;
50 Bool firstDraw;
51 Bool markPointerHotspot;
53 WMHandlerID tid;
54 } BufferData;
58 static BufferData *newWindow(int magfactor);
61 int windowCount = 0;
63 int rectBufferSize = 32;
64 Display *dpy;
65 WMScreen *scr;
66 unsigned int black;
67 WMColor *cursorColor1;
68 WMColor *cursorColor2;
70 #ifndef __GNUC__
71 #define inline
72 #endif
75 static BufferData*
76 makeBufferData(WMWindow *win, WMLabel *label, int width, int height,
77 int magfactor)
79 BufferData *data;
81 data = wmalloc(sizeof(BufferData));
83 data->rwidth = width;
84 data->rheight = height;
86 data->refreshrate = refreshrate;
88 data->firstDraw = True;
90 data->magfactor = magfactor;
92 data->rects = wmalloc(sizeof(XRectangle)*rectBufferSize);
93 data->rectP = 0;
95 data->win = win;
96 data->label = label;
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;
106 width /= magfactor;
107 height /= magfactor;
108 data->buffer = wmalloc(sizeof(unsigned long)*width*height);
109 memset(data->buffer, 0, width*height*sizeof(unsigned long));
110 data->width = width;
111 data->height = height;
113 return data;
117 static void
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);
128 data->width = w;
129 data->height = 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),
136 False);
137 WMSetLabelImage(data->label, data->pixmap);
139 data->d = WMGetPixmapXID(data->pixmap);
143 static int
144 drawpoint(BufferData *data, unsigned long pixel, int x, int y)
146 static GC gc = NULL;
147 Bool flush = (x < 0);
149 if (!flush) {
150 if (data->buffer[x+data->width*y] == pixel && !data->firstDraw)
151 return 0;
153 data->buffer[x+data->width*y] = pixel;
155 if (gc == NULL) {
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;
164 data->rectP++;
166 return 0;
168 XSetForeground(dpy, gc, data->lastpixel);
169 XFillRectangles(dpy, data->d, gc, data->rects, data->rectP);
170 data->rectP = 0;
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;
175 data->rectP++;
177 data->lastpixel = pixel;
179 return 1;
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) {
188 return black;
190 return XGetPixel(image, x-xoffs, y-yoffs);
194 static void
195 updateImage(BufferData *data, int rx, int ry)
197 int gx, gy, gw, gh;
198 int x, y;
199 int xoffs, yoffs;
200 int changedPixels = 0;
201 XImage *image;
203 gw = data->width;
204 gh = data->height;
206 gx = rx - gw/2;
207 gy = ry - gh/2;
209 xoffs = yoffs = 0;
210 if (gx < 0) {
211 xoffs = abs(gx);
212 gw += gx;
213 gx = 0;
215 if (gx + gw >= WidthOfScreen(DefaultScreenOfDisplay(dpy))) {
216 gw = WidthOfScreen(DefaultScreenOfDisplay(dpy)) - gx;
218 if (gy < 0) {
219 yoffs = abs(gy);
220 gh += gy;
221 gy = 0;
223 if (gy + gh >= HeightOfScreen(DefaultScreenOfDisplay(dpy))) {
224 gh = HeightOfScreen(DefaultScreenOfDisplay(dpy)) - gy;
227 image = XGetImage(dpy, DefaultRootWindow(dpy), gx, gy, gw, gh,
228 AllPlanes, ZPixmap);
231 for (y = 0; y < data->height; y++) {
232 for (x = 0; x < data->width; x++) {
233 unsigned long pixel;
235 pixel = getpix(image, x-xoffs, y-yoffs, xoffs, yoffs);
237 if (drawpoint(data, pixel, x, y))
238 changedPixels++;
241 /* flush the point cache */
242 drawpoint(data, 0, -1, -1);
244 XDestroyImage(image);
246 if (data->markPointerHotspot && !data->frozen) {
247 XRectangle rects[4];
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;
282 static void
283 update(void *d)
285 BufferData *data = (BufferData*)d;
286 Window win;
287 int rx, ry;
288 int bla;
289 unsigned ubla;
292 if (data->frozen) {
293 rx = data->x;
294 ry = data->y;
295 } else {
296 XQueryPointer(dpy, DefaultRootWindow(dpy), &win, &win, &rx, &ry,
297 &bla, &bla, &ubla);
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);
309 WMSize size;
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;
322 windowCount--;
323 if (windowCount == 0) {
324 exit(0);
325 } else {
326 WMDeleteTimerHandler(data->tid);
327 WMDestroyWidget(w);
328 wfree(data->buffer);
329 wfree(data->rects);
330 WMReleasePixmap(data->pixmap);
331 wfree(data);
336 #if 0
337 static void
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);
352 #endif
355 static void
356 keyHandler(XEvent *event, void *d)
358 BufferData *data = (BufferData*)d;
359 char buf[32];
360 KeySym ks;
361 WMView *view = WMWidgetView(data->win);
362 WMSize size;
364 size = WMGetViewSize(view);
366 if (XLookupString(&event->xkey, buf, 31, &ks, NULL) > 0) {
367 switch (buf[0]) {
368 case 'n':
369 newWindow(data->magfactor);
370 break;
371 case 'm':
372 data->markPointerHotspot = !data->markPointerHotspot;
373 break;
374 case 'f':
375 case ' ':
376 data->frozen = !data->frozen;
377 if (data->frozen) {
378 data->x = event->xkey.x_root;
379 data->y = event->xkey.y_root;
380 sprintf(buf, "[Magnify %ix]", data->magfactor);
381 } else {
382 sprintf(buf, "Magnify %ix", data->magfactor);
384 WMSetWindowTitle(data->win, buf);
385 break;
386 case '1':
387 case '2':
388 case '3':
389 case '4':
390 case '5':
391 case '6':
392 case '7':
393 case '8':
394 case '9':
395 resizeBufferData(data, size.width, size.height, buf[0]-'0');
396 if (data->frozen) {
397 sprintf(buf, "[Magnify %ix]", data->magfactor);
398 } else {
399 sprintf(buf, "Magnify %ix", data->magfactor);
401 WMSetWindowTitle(data->win, buf);
402 break;
408 static BufferData*
409 newWindow(int magfactor)
411 WMWindow *win;
412 WMLabel *label;
413 BufferData *data;
414 char buf[32];
416 windowCount++;
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,
433 keyHandler, data);
435 WMAddNotificationObserver(resizedWindow, data,
436 WMViewSizeDidChangeNotification,
437 WMWidgetView(win));
439 WMRealizeWidget(win);
441 WMMapSubwidgets(win);
442 WMMapWidget(win);
444 WMSetWindowCloseAction(win, closeWindow, data);
445 data->tid = WMAddTimerHandler(refreshrate, update, data);
447 return data;
451 int main(int argc, char **argv)
453 BufferData *data;
454 int i;
455 char *display = "";
456 int magfactor = 2;
457 #if 0
458 WMButton *radio, *tradio;
459 #endif
460 WMInitializeApplication("Magnify", &argc, argv);
463 for (i = 1; i < argc; i++) {
464 if (strcmp(argv[i], "-display")==0) {
465 i++;
466 if (i >= argc)
467 goto help;
468 display = argv[i];
469 } else if (strcmp(argv[i], "-m")==0) {
470 i++;
471 if (i >= argc)
472 goto help;
473 magfactor = atoi(argv[i]);
474 if (magfactor < 1 || magfactor > 32) {
475 printf("%s:invalid magnification factor ``%s''\n", argv[0],
476 argv[i]);
477 exit(1);
479 } else if (strcmp(argv[i], "-r")==0) {
480 i++;
481 if (i >= argc)
482 goto help;
483 refreshrate = atoi(argv[i]);
484 if (refreshrate < 1) {
485 printf("%s:invalid refresh rate ``%s''\n", argv[0], argv[i]);
486 exit(1);
488 } else if (strcmp(argv[i], "-h")==0
489 || strcmp(argv[i], "--help")==0) {
490 help:
492 printf("Syntax: %s [options]\n",
493 argv[0]);
494 puts("Options:");
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)");
498 puts("Keys:");
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"
501 " position");
502 puts(" n create a new window");
503 puts(" m show/hide the pointer hotspot mark");
504 exit(0);
508 dpy = XOpenDisplay("");
509 if (!dpy) {
510 puts("couldnt open display");
511 exit(1);
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)
518 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);
531 return 0;