Change to the linux kernel coding style
[wmaker-crm.git] / util / wmagnify.c
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  */
8
9 #include <X11/Xproto.h>
10
11 #include <WINGs/WINGs.h>
12 #include <stdlib.h>
13 #include <string.h>
14 #include <stdio.h>
15
16 /*
17  * TODO:
18  * - lens that shows where it's magnifying
19  *
20  *
21  */
22
23 int refreshrate = 200;
24
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;
35
36         WMWindow *win;
37         WMLabel *label;
38         WMPixmap *pixmap;
39
40         WMWindow *dlg;
41
42         WMSlider *speed;
43         WMSlider *magnify;
44         WMButton *okB;
45         WMButton *cancelB;
46         WMButton *newB;
47
48         int x, y;
49         Bool frozen;
50         Bool firstDraw;
51         Bool markPointerHotspot;
52
53         WMHandlerID tid;
54 } BufferData;
55
56 static BufferData *newWindow(int magfactor);
57
58 int windowCount = 0;
59
60 int rectBufferSize = 32;
61 Display *dpy, *vdpy;
62 WMScreen *scr;
63 unsigned int black;
64 WMColor *cursorColor1;
65 WMColor *cursorColor2;
66
67 #ifndef __GNUC__
68 #define inline
69 #endif
70
71 static BufferData *makeBufferData(WMWindow * win, WMLabel * label, int width, int height, int magfactor)
72 {
73         BufferData *data;
74
75         data = wmalloc(sizeof(BufferData));
76
77         data->rwidth = width;
78         data->rheight = height;
79
80         data->refreshrate = refreshrate;
81
82         data->firstDraw = True;
83
84         data->magfactor = magfactor;
85
86         data->rects = wmalloc(sizeof(XRectangle) * rectBufferSize);
87         data->rectP = 0;
88
89         data->win = win;
90         data->label = label;
91
92         data->pixmap = WMCreatePixmap(scr, width, height, WMScreenDepth(scr), False);
93         WMSetLabelImage(data->label, data->pixmap);
94
95         data->d = WMGetPixmapXID(data->pixmap);
96
97         data->frozen = False;
98
99         width /= magfactor;
100         height /= magfactor;
101         data->buffer = wmalloc(sizeof(unsigned long) * width * height);
102         memset(data->buffer, 0, width * height * sizeof(unsigned long));
103         data->width = width;
104         data->height = height;
105
106         return data;
107 }
108
109 static void resizeBufferData(BufferData * data, int width, int height, int magfactor)
110 {
111         int w = width / magfactor;
112         int h = height / magfactor;
113
114         data->rwidth = width;
115         data->rheight = height;
116         data->firstDraw = True;
117         data->magfactor = magfactor;
118         data->buffer = wrealloc(data->buffer, sizeof(unsigned long) * w * h);
119         data->width = w;
120         data->height = h;
121         memset(data->buffer, 0, w * h * sizeof(unsigned long));
122
123         WMResizeWidget(data->label, width, height);
124
125         WMReleasePixmap(data->pixmap);
126         data->pixmap = WMCreatePixmap(scr, width, height, WMScreenDepth(scr), False);
127         WMSetLabelImage(data->label, data->pixmap);
128
129         data->d = WMGetPixmapXID(data->pixmap);
130 }
131
132 static int drawpoint(BufferData * data, unsigned long pixel, int x, int y)
133 {
134         static GC gc = NULL;
135         Bool flush = (x < 0);
136
137         if (!flush) {
138                 if (data->buffer[x + data->width * y] == pixel && !data->firstDraw)
139                         return 0;
140
141                 data->buffer[x + data->width * y] = pixel;
142         }
143         if (gc == NULL) {
144                 gc = XCreateGC(dpy, DefaultRootWindow(dpy), 0, NULL);
145         }
146
147         if (!flush && data->lastpixel == pixel && data->rectP < rectBufferSize) {
148                 data->rects[data->rectP].x = x * data->magfactor;
149                 data->rects[data->rectP].y = y * data->magfactor;
150                 data->rects[data->rectP].width = data->magfactor;
151                 data->rects[data->rectP].height = data->magfactor;
152                 data->rectP++;
153
154                 return 0;
155         }
156         XSetForeground(dpy, gc, data->lastpixel);
157         XFillRectangles(dpy, data->d, gc, data->rects, data->rectP);
158         data->rectP = 0;
159         data->rects[data->rectP].x = x * data->magfactor;
160         data->rects[data->rectP].y = y * data->magfactor;
161         data->rects[data->rectP].width = data->magfactor;
162         data->rects[data->rectP].height = data->magfactor;
163         data->rectP++;
164
165         data->lastpixel = pixel;
166
167         return 1;
168 }
169
170 static inline unsigned long getpix(XImage * image, int x, int y, int xoffs, int yoffs)
171 {
172         if (x < xoffs || y < yoffs || x >= xoffs + image->width || y >= yoffs + image->height) {
173                 return black;
174         }
175         return XGetPixel(image, x - xoffs, y - yoffs);
176 }
177
178 static void updateImage(BufferData * data, int rx, int ry)
179 {
180         int gx, gy, gw, gh;
181         int x, y;
182         int xoffs, yoffs;
183         int changedPixels = 0;
184         XImage *image;
185
186         gw = data->width;
187         gh = data->height;
188
189         gx = rx - gw / 2;
190         gy = ry - gh / 2;
191
192         xoffs = yoffs = 0;
193         if (gx < 0) {
194                 xoffs = abs(gx);
195                 gw += gx;
196                 gx = 0;
197         }
198         if (gx + gw >= WidthOfScreen(DefaultScreenOfDisplay(vdpy))) {
199                 gw = WidthOfScreen(DefaultScreenOfDisplay(vdpy)) - gx;
200         }
201         if (gy < 0) {
202                 yoffs = abs(gy);
203                 gh += gy;
204                 gy = 0;
205         }
206         if (gy + gh >= HeightOfScreen(DefaultScreenOfDisplay(vdpy))) {
207                 gh = HeightOfScreen(DefaultScreenOfDisplay(vdpy)) - gy;
208         }
209
210         image = XGetImage(vdpy, DefaultRootWindow(vdpy), gx, gy, gw, gh, AllPlanes, ZPixmap);
211
212         for (y = 0; y < data->height; y++) {
213                 for (x = 0; x < data->width; x++) {
214                         unsigned long pixel;
215
216                         pixel = getpix(image, x, y, xoffs, yoffs);
217
218                         if (drawpoint(data, pixel, x, y))
219                                 changedPixels++;
220                 }
221         }
222         /* flush the point cache */
223         drawpoint(data, 0, -1, -1);
224
225         XDestroyImage(image);
226
227         if (data->markPointerHotspot && !data->frozen) {
228                 XRectangle rects[4];
229
230                 rects[0].x = (data->width / 2 - 3) * data->magfactor;
231                 rects[0].y = (data->height / 2) * data->magfactor;
232                 rects[0].width = 2 * data->magfactor;
233                 rects[0].height = data->magfactor;
234
235                 rects[1].x = (data->width / 2 + 2) * data->magfactor;
236                 rects[1].y = (data->height / 2) * data->magfactor;
237                 rects[1].width = 2 * data->magfactor;
238                 rects[1].height = data->magfactor;
239
240                 XFillRectangles(dpy, data->d, WMColorGC(cursorColor1), rects, 2);
241
242                 rects[2].y = (data->height / 2 - 3) * data->magfactor;
243                 rects[2].x = (data->width / 2) * data->magfactor;
244                 rects[2].height = 2 * data->magfactor;
245                 rects[2].width = data->magfactor;
246
247                 rects[3].y = (data->height / 2 + 2) * data->magfactor;
248                 rects[3].x = (data->width / 2) * data->magfactor;
249                 rects[3].height = 2 * data->magfactor;
250                 rects[3].width = data->magfactor;
251
252                 XFillRectangles(dpy, data->d, WMColorGC(cursorColor2), rects + 2, 2);
253         }
254
255         if (changedPixels > 0) {
256                 WMRedisplayWidget(data->label);
257         }
258
259         data->firstDraw = False;
260 }
261
262 static void update(void *d)
263 {
264         BufferData *data = (BufferData *) d;
265         Window win;
266         int rx, ry;
267         int bla;
268         unsigned ubla;
269
270         if (data->frozen) {
271                 rx = data->x;
272                 ry = data->y;
273         } else {
274                 XQueryPointer(dpy, DefaultRootWindow(dpy), &win, &win, &rx, &ry, &bla, &bla, &ubla);
275         }
276         updateImage(data, rx, ry);
277
278         data->tid = WMAddTimerHandler(data->refreshrate, update, data);
279 }
280
281 void resizedWindow(void *d, WMNotification * notif)
282 {
283         BufferData *data = (BufferData *) d;
284         WMView *view = (WMView *) WMGetNotificationObject(notif);
285         WMSize size;
286
287         size = WMGetViewSize(view);
288
289         resizeBufferData(data, size.width, size.height, data->magfactor);
290 }
291
292 void closeWindow(WMWidget * w, void *d)
293 {
294         BufferData *data = (BufferData *) d;
295
296         windowCount--;
297         if (windowCount == 0) {
298                 exit(0);
299         } else {
300                 WMDeleteTimerHandler(data->tid);
301                 WMDestroyWidget(w);
302                 wfree(data->buffer);
303                 wfree(data->rects);
304                 WMReleasePixmap(data->pixmap);
305                 wfree(data);
306         }
307 }
308
309 #if 0
310 static void clickHandler(XEvent * event, void *d)
311 {
312         BufferData *data = (BufferData *) d;
313
314         data->win = WMCreateWindow(scr, "setup");
315         WMSetWindowTitle(data->win, "Magnify Options");
316
317         data->speed = WMCreateSlider(data->win);
318
319         data->magnify = WMCreateSlider(data->win);
320
321 }
322 #endif
323
324 static void keyHandler(XEvent * event, void *d)
325 {
326         BufferData *data = (BufferData *) d;
327         char buf[32];
328         KeySym ks;
329         WMView *view = WMWidgetView(data->win);
330         WMSize size;
331
332         size = WMGetViewSize(view);
333
334         if (XLookupString(&event->xkey, buf, 31, &ks, NULL) > 0) {
335                 switch (buf[0]) {
336                 case 'n':
337                         newWindow(data->magfactor);
338                         break;
339                 case 'm':
340                         data->markPointerHotspot = !data->markPointerHotspot;
341                         break;
342                 case 'f':
343                 case ' ':
344                         data->frozen = !data->frozen;
345                         if (data->frozen) {
346                                 data->x = event->xkey.x_root;
347                                 data->y = event->xkey.y_root;
348                                 sprintf(buf, "[Magnify %ix]", data->magfactor);
349                         } else {
350                                 sprintf(buf, "Magnify %ix", data->magfactor);
351                         }
352                         WMSetWindowTitle(data->win, buf);
353                         break;
354                 case '1':
355                 case '2':
356                 case '3':
357                 case '4':
358                 case '5':
359                 case '6':
360                 case '7':
361                 case '8':
362                 case '9':
363                         resizeBufferData(data, size.width, size.height, buf[0] - '0');
364                         if (data->frozen) {
365                                 sprintf(buf, "[Magnify %ix]", data->magfactor);
366                         } else {
367                                 sprintf(buf, "Magnify %ix", data->magfactor);
368                         }
369                         WMSetWindowTitle(data->win, buf);
370                         break;
371                 }
372         }
373 }
374
375 static BufferData *newWindow(int magfactor)
376 {
377         WMWindow *win;
378         WMLabel *label;
379         BufferData *data;
380         char buf[32];
381
382         windowCount++;
383
384         win = WMCreateWindow(scr, "magnify");
385         WMResizeWidget(win, 300, 200);
386         sprintf(buf, "Magnify %ix", magfactor);
387         WMSetWindowTitle(win, buf);
388         WMSetViewNotifySizeChanges(WMWidgetView(win), True);
389
390         label = WMCreateLabel(win);
391         WMResizeWidget(label, 300, 200);
392         WMMoveWidget(label, 0, 0);
393         WMSetLabelRelief(label, WRSunken);
394         WMSetLabelImagePosition(label, WIPImageOnly);
395
396         data = makeBufferData(win, label, 300, 200, magfactor);
397
398         WMCreateEventHandler(WMWidgetView(win), KeyReleaseMask, keyHandler, data);
399
400         WMAddNotificationObserver(resizedWindow, data, WMViewSizeDidChangeNotification, WMWidgetView(win));
401
402         WMRealizeWidget(win);
403
404         WMMapSubwidgets(win);
405         WMMapWidget(win);
406
407         WMSetWindowCloseAction(win, closeWindow, data);
408         data->tid = WMAddTimerHandler(refreshrate, update, data);
409
410         return data;
411 }
412
413 int main(int argc, char **argv)
414 {
415         BufferData *data;
416         int i;
417         char *display = "";
418         char *vdisplay = NULL;
419         int magfactor = 2;
420 #if 0
421         WMButton *radio, *tradio;
422 #endif
423         WMInitializeApplication("Magnify", &argc, argv);
424
425         for (i = 1; i < argc; i++) {
426                 if (strcmp(argv[i], "-display") == 0) {
427                         i++;
428                         if (i >= argc)
429                                 goto help;
430                         display = argv[i];
431                 } else if (strcmp(argv[i], "-vdisplay") == 0) {
432                         i++;
433                         if (i >= argc)
434                                 goto help;
435                         vdisplay = argv[i];
436                 } else if (strcmp(argv[i], "-m") == 0) {
437                         i++;
438                         if (i >= argc)
439                                 goto help;
440                         magfactor = atoi(argv[i]);
441                         if (magfactor < 1 || magfactor > 32) {
442                                 printf("%s:invalid magnification factor ``%s''\n", argv[0], argv[i]);
443                                 exit(1);
444                         }
445                 } else if (strcmp(argv[i], "-r") == 0) {
446                         i++;
447                         if (i >= argc)
448                                 goto help;
449                         refreshrate = atoi(argv[i]);
450                         if (refreshrate < 1) {
451                                 printf("%s:invalid refresh rate ``%s''\n", argv[0], argv[i]);
452                                 exit(1);
453                         }
454                 } else if (strcmp(argv[i], "-h") == 0 || strcmp(argv[i], "--help") == 0) {
455  help:
456
457                         printf("Syntax: %s [options]\n", argv[0]);
458                         puts("Options:");
459                         puts("  -display <display>      display that should be used");
460                         puts("  -m <number>             change magnification factor (default 2)");
461                         puts("  -r <number>             change refresh delay, in milliseconds (default 200)");
462                         puts("Keys:");
463                         puts("  1,2,3,4,5,6,7,8,9       change the magnification factor");
464                         puts("  <space>, f              freeze the 'camera', making it magnify only the current\n"
465                              "                  position");
466                         puts("  n                       create a new window");
467                         puts("  m                       show/hide the pointer hotspot mark");
468                         exit(0);
469                 }
470         }
471
472         dpy = XOpenDisplay(display);
473         if (!dpy) {
474                 puts("couldnt open display");
475                 exit(1);
476         }
477
478         if (vdisplay) {
479                 vdpy = XOpenDisplay(vdisplay);
480                 if (!vdpy) {
481                         puts("couldnt open display to be viewed");
482                         exit(1);
483                 }
484         } else {
485                 vdpy = dpy;
486         }
487
488         /* calculate how many rectangles we can send in a trip to the server */
489         rectBufferSize = XMaxRequestSize(dpy) - 128;
490         rectBufferSize /= sizeof(XRectangle);
491         if (rectBufferSize < 1)
492                 rectBufferSize = 1;
493
494         black = BlackPixel(dpy, DefaultScreen(dpy));
495
496         scr = WMCreateScreen(dpy, 0);
497
498         cursorColor1 = WMCreateNamedColor(scr, "#ff0000", False);
499         cursorColor2 = WMCreateNamedColor(scr, "#00ff00", False);
500
501         data = newWindow(magfactor);
502
503         WMScreenMainLoop(scr);
504
505         return 0;
506 }