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 }