fixed crash bug with alt-tab + run-dialog (or internal windows in general)
[wmaker-crm.git] / util / wmagnify.c
blob4046b3805c62afa2a9de2ab471c2c715053caeed
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 */
9 #include <X11/Xproto.h>
11 #include <WINGs/WINGs.h>
12 #include <stdlib.h>
13 #include <string.h>
14 #include <stdio.h>
17 * TODO:
18 * - lens that shows where it's magnifying
23 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;
59 static BufferData *newWindow(int magfactor);
62 int windowCount = 0;
64 int rectBufferSize = 32;
65 Display *dpy, *vdpy;
66 WMScreen *scr;
67 unsigned int black;
68 WMColor *cursorColor1;
69 WMColor *cursorColor2;
71 #ifndef __GNUC__
72 #define inline
73 #endif
76 static BufferData*
77 makeBufferData(WMWindow *win, WMLabel *label, int width, int height,
78 int magfactor)
80 BufferData *data;
82 data = wmalloc(sizeof(BufferData));
84 data->rwidth = width;
85 data->rheight = height;
87 data->refreshrate = refreshrate;
89 data->firstDraw = True;
91 data->magfactor = magfactor;
93 data->rects = wmalloc(sizeof(XRectangle)*rectBufferSize);
94 data->rectP = 0;
96 data->win = win;
97 data->label = label;
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;
107 width /= magfactor;
108 height /= magfactor;
109 data->buffer = wmalloc(sizeof(unsigned long)*width*height);
110 memset(data->buffer, 0, width*height*sizeof(unsigned long));
111 data->width = width;
112 data->height = height;
114 return data;
118 static void
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);
129 data->width = w;
130 data->height = 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),
137 False);
138 WMSetLabelImage(data->label, data->pixmap);
140 data->d = WMGetPixmapXID(data->pixmap);
144 static int
145 drawpoint(BufferData *data, unsigned long pixel, int x, int y)
147 static GC gc = NULL;
148 Bool flush = (x < 0);
150 if (!flush) {
151 if (data->buffer[x+data->width*y] == pixel && !data->firstDraw)
152 return 0;
154 data->buffer[x+data->width*y] = pixel;
156 if (gc == NULL) {
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;
165 data->rectP++;
167 return 0;
169 XSetForeground(dpy, gc, data->lastpixel);
170 XFillRectangles(dpy, data->d, gc, data->rects, data->rectP);
171 data->rectP = 0;
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;
176 data->rectP++;
178 data->lastpixel = pixel;
180 return 1;
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) {
189 return black;
191 return XGetPixel(image, x-xoffs, y-yoffs);
195 static void
196 updateImage(BufferData *data, int rx, int ry)
198 int gx, gy, gw, gh;
199 int x, y;
200 int xoffs, yoffs;
201 int changedPixels = 0;
202 XImage *image;
204 gw = data->width;
205 gh = data->height;
207 gx = rx - gw/2;
208 gy = ry - gh/2;
210 xoffs = yoffs = 0;
211 if (gx < 0) {
212 xoffs = abs(gx);
213 gw += gx;
214 gx = 0;
216 if (gx + gw >= WidthOfScreen(DefaultScreenOfDisplay(vdpy))) {
217 gw = WidthOfScreen(DefaultScreenOfDisplay(vdpy)) - gx;
219 if (gy < 0) {
220 yoffs = abs(gy);
221 gh += gy;
222 gy = 0;
224 if (gy + gh >= HeightOfScreen(DefaultScreenOfDisplay(vdpy))) {
225 gh = HeightOfScreen(DefaultScreenOfDisplay(vdpy)) - gy;
228 image = XGetImage(vdpy, DefaultRootWindow(vdpy), gx, gy, gw, gh,
229 AllPlanes, ZPixmap);
232 for (y = 0; y < data->height; y++) {
233 for (x = 0; x < data->width; x++) {
234 unsigned long pixel;
236 pixel = getpix(image, x, y, xoffs, yoffs);
238 if (drawpoint(data, pixel, x, y))
239 changedPixels++;
242 /* flush the point cache */
243 drawpoint(data, 0, -1, -1);
245 XDestroyImage(image);
247 if (data->markPointerHotspot && !data->frozen) {
248 XRectangle rects[4];
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;
283 static void
284 update(void *d)
286 BufferData *data = (BufferData*)d;
287 Window win;
288 int rx, ry;
289 int bla;
290 unsigned ubla;
293 if (data->frozen) {
294 rx = data->x;
295 ry = data->y;
296 } else {
297 XQueryPointer(dpy, DefaultRootWindow(dpy), &win, &win, &rx, &ry,
298 &bla, &bla, &ubla);
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);
310 WMSize size;
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;
323 windowCount--;
324 if (windowCount == 0) {
325 exit(0);
326 } else {
327 WMDeleteTimerHandler(data->tid);
328 WMDestroyWidget(w);
329 wfree(data->buffer);
330 wfree(data->rects);
331 WMReleasePixmap(data->pixmap);
332 wfree(data);
337 #if 0
338 static void
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);
353 #endif
356 static void
357 keyHandler(XEvent *event, void *d)
359 BufferData *data = (BufferData*)d;
360 char buf[32];
361 KeySym ks;
362 WMView *view = WMWidgetView(data->win);
363 WMSize size;
365 size = WMGetViewSize(view);
367 if (XLookupString(&event->xkey, buf, 31, &ks, NULL) > 0) {
368 switch (buf[0]) {
369 case 'n':
370 newWindow(data->magfactor);
371 break;
372 case 'm':
373 data->markPointerHotspot = !data->markPointerHotspot;
374 break;
375 case 'f':
376 case ' ':
377 data->frozen = !data->frozen;
378 if (data->frozen) {
379 data->x = event->xkey.x_root;
380 data->y = event->xkey.y_root;
381 sprintf(buf, "[Magnify %ix]", data->magfactor);
382 } else {
383 sprintf(buf, "Magnify %ix", data->magfactor);
385 WMSetWindowTitle(data->win, buf);
386 break;
387 case '1':
388 case '2':
389 case '3':
390 case '4':
391 case '5':
392 case '6':
393 case '7':
394 case '8':
395 case '9':
396 resizeBufferData(data, size.width, size.height, buf[0]-'0');
397 if (data->frozen) {
398 sprintf(buf, "[Magnify %ix]", data->magfactor);
399 } else {
400 sprintf(buf, "Magnify %ix", data->magfactor);
402 WMSetWindowTitle(data->win, buf);
403 break;
409 static BufferData*
410 newWindow(int magfactor)
412 WMWindow *win;
413 WMLabel *label;
414 BufferData *data;
415 char buf[32];
417 windowCount++;
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,
434 keyHandler, data);
436 WMAddNotificationObserver(resizedWindow, data,
437 WMViewSizeDidChangeNotification,
438 WMWidgetView(win));
440 WMRealizeWidget(win);
442 WMMapSubwidgets(win);
443 WMMapWidget(win);
445 WMSetWindowCloseAction(win, closeWindow, data);
446 data->tid = WMAddTimerHandler(refreshrate, update, data);
448 return data;
452 int main(int argc, char **argv)
454 BufferData *data;
455 int i;
456 char *display = "";
457 char *vdisplay = NULL;
458 int magfactor = 2;
459 #if 0
460 WMButton *radio, *tradio;
461 #endif
462 WMInitializeApplication("Magnify", &argc, argv);
465 for (i = 1; i < argc; i++) {
466 if (strcmp(argv[i], "-display")==0) {
467 i++;
468 if (i >= argc)
469 goto help;
470 display = argv[i];
471 } else if (strcmp(argv[i], "-vdisplay")==0) {
472 i++;
473 if (i >= argc)
474 goto help;
475 vdisplay = argv[i];
476 } else if (strcmp(argv[i], "-m")==0) {
477 i++;
478 if (i >= argc)
479 goto help;
480 magfactor = atoi(argv[i]);
481 if (magfactor < 1 || magfactor > 32) {
482 printf("%s:invalid magnification factor ``%s''\n", argv[0],
483 argv[i]);
484 exit(1);
486 } else if (strcmp(argv[i], "-r")==0) {
487 i++;
488 if (i >= argc)
489 goto help;
490 refreshrate = atoi(argv[i]);
491 if (refreshrate < 1) {
492 printf("%s:invalid refresh rate ``%s''\n", argv[0], argv[i]);
493 exit(1);
495 } else if (strcmp(argv[i], "-h")==0
496 || strcmp(argv[i], "--help")==0) {
497 help:
499 printf("Syntax: %s [options]\n",
500 argv[0]);
501 puts("Options:");
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)");
505 puts("Keys:");
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"
508 " position");
509 puts(" n create a new window");
510 puts(" m show/hide the pointer hotspot mark");
511 exit(0);
515 dpy = XOpenDisplay(display);
516 if (!dpy) {
517 puts("couldnt open display");
518 exit(1);
521 if (vdisplay) {
522 vdpy = XOpenDisplay(vdisplay);
523 if (!vdpy) {
524 puts("couldnt open display to be viewed");
525 exit(1);
527 } else {
528 vdpy = dpy;
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)
535 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);
548 return 0;