Undo XDG string-escaping when generating menu-entries.
[wmaker-crm.git] / util / wmagnify.c
blob4b41115cf8ed21c71a0b0b23ba2bf619c2982579
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 static 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 static void closeWindow(WMWidget * w, void *d)
291 BufferData *data = (BufferData *) d;
293 windowCount--;
294 if (windowCount == 0) {
295 WMReleaseApplication();
296 exit(0);
297 } else {
298 WMDeleteTimerHandler(data->tid);
299 WMDestroyWidget(w);
300 wfree(data->buffer);
301 wfree(data->rects);
302 WMReleasePixmap(data->pixmap);
303 wfree(data);
307 static void keyHandler(XEvent * event, void *d)
309 BufferData *data = (BufferData *) d;
310 char buf[32];
311 KeySym ks;
312 WMView *view = WMWidgetView(data->win);
313 WMSize size;
315 size = WMGetViewSize(view);
317 if (XLookupString(&event->xkey, buf, 31, &ks, NULL) > 0) {
318 switch (buf[0]) {
319 case 'n':
320 newWindow(data->magfactor);
321 break;
322 case 'm':
323 data->markPointerHotspot = !data->markPointerHotspot;
324 break;
325 case 'f':
326 case ' ':
327 data->frozen = !data->frozen;
328 if (data->frozen) {
329 data->x = event->xkey.x_root;
330 data->y = event->xkey.y_root;
331 sprintf(buf, "[Magnify %ix]", data->magfactor);
332 } else {
333 sprintf(buf, "Magnify %ix", data->magfactor);
335 WMSetWindowTitle(data->win, buf);
336 break;
337 case '1':
338 case '2':
339 case '3':
340 case '4':
341 case '5':
342 case '6':
343 case '7':
344 case '8':
345 case '9':
346 resizeBufferData(data, size.width, size.height, buf[0] - '0');
347 if (data->frozen) {
348 sprintf(buf, "[Magnify %ix]", data->magfactor);
349 } else {
350 sprintf(buf, "Magnify %ix", data->magfactor);
352 WMSetWindowTitle(data->win, buf);
353 break;
358 static BufferData *newWindow(int magfactor)
360 WMWindow *win;
361 WMLabel *label;
362 BufferData *data;
363 char buf[32];
365 windowCount++;
367 win = WMCreateWindow(scr, "magnify");
368 WMResizeWidget(win, 300, 200);
369 sprintf(buf, "Magnify %ix", magfactor);
370 WMSetWindowTitle(win, buf);
371 WMSetViewNotifySizeChanges(WMWidgetView(win), True);
373 label = WMCreateLabel(win);
374 WMResizeWidget(label, 300, 200);
375 WMMoveWidget(label, 0, 0);
376 WMSetLabelRelief(label, WRSunken);
377 WMSetLabelImagePosition(label, WIPImageOnly);
379 data = makeBufferData(win, label, 300, 200, magfactor);
381 WMCreateEventHandler(WMWidgetView(win), KeyReleaseMask, keyHandler, data);
383 WMAddNotificationObserver(resizedWindow, data, WMViewSizeDidChangeNotification, WMWidgetView(win));
385 WMRealizeWidget(win);
387 WMMapSubwidgets(win);
388 WMMapWidget(win);
390 WMSetWindowCloseAction(win, closeWindow, data);
391 data->tid = WMAddTimerHandler(refreshrate, update, data);
393 return data;
396 int main(int argc, char **argv)
398 int i;
399 char *display = "";
400 char *vdisplay = NULL;
401 int magfactor = 2;
403 WMInitializeApplication("Magnify", &argc, argv);
405 for (i = 1; i < argc; i++) {
406 if (strcmp(argv[i], "-display") == 0) {
407 i++;
408 if (i >= argc)
409 goto help;
410 display = argv[i];
411 } else if (strcmp(argv[i], "-vdisplay") == 0) {
412 i++;
413 if (i >= argc)
414 goto help;
415 vdisplay = argv[i];
416 } else if (strcmp(argv[i], "-m") == 0) {
417 i++;
418 if (i >= argc)
419 goto help;
420 magfactor = atoi(argv[i]);
421 if (magfactor < 1 || magfactor > 32) {
422 printf("%s:invalid magnification factor ``%s''\n", argv[0], argv[i]);
423 exit(1);
425 } else if (strcmp(argv[i], "-r") == 0) {
426 i++;
427 if (i >= argc)
428 goto help;
429 refreshrate = atoi(argv[i]);
430 if (refreshrate < 1) {
431 printf("%s:invalid refresh rate ``%s''\n", argv[0], argv[i]);
432 exit(1);
434 } else if (strcmp(argv[i], "-h") == 0 || strcmp(argv[i], "--help") == 0) {
435 help:
437 printf("Usage: %s [options]\n", argv[0]);
438 puts("Options:");
439 puts(" -display <display>\tdisplay where to magnification is shown");
440 puts(" -m <number>\t\tchange magnification factor (default 2)");
441 puts(" -r <number>\t\tchange refresh delay, in milliseconds (default 200)");
442 puts(" -vdisplay <display>\tdisplay from which the magnification is taken");
443 puts(" -h, --help\t\tdisplay this help page");
444 puts("Keys:");
445 puts(" 1,2,3,4,5,6,7,8,9 change the magnification factor");
446 puts(" <space>, f freeze the 'camera', making it magnify only the current\n"
447 " position");
448 puts(" n create a new window");
449 puts(" m show/hide the pointer hotspot mark");
450 exit(0);
454 dpy = XOpenDisplay(display);
455 if (!dpy) {
456 puts("could not open display");
457 exit(1);
460 if (vdisplay) {
461 vdpy = XOpenDisplay(vdisplay);
462 if (!vdpy) {
463 puts("could not open display to be viewed");
464 exit(1);
466 } else {
467 vdpy = dpy;
470 /* calculate how many rectangles we can send in a trip to the server */
471 rectBufferSize = XMaxRequestSize(dpy) - 128;
472 rectBufferSize /= sizeof(XRectangle);
473 if (rectBufferSize < 1)
474 rectBufferSize = 1;
476 black = BlackPixel(dpy, DefaultScreen(dpy));
478 scr = WMCreateScreen(dpy, 0);
480 cursorColor1 = WMCreateNamedColor(scr, "#ff0000", False);
481 cursorColor2 = WMCreateNamedColor(scr, "#00ff00", False);
483 newWindow(magfactor);
485 WMScreenMainLoop(scr);
487 return 0;