Change to the linux kernel coding style
[wmaker-crm.git] / util / wmagnify.c
Commit [+]AuthorDateLineData
58b36ec1 kojima2000-05-22 03:09:20 +00001/*
2 * magnify - a X utility for magnifying screen image
6830b057 dan2004-10-12 21:28:27 +00003 *
58b36ec1 kojima2000-05-22 03:09:20 +00004 * 2000/5/21 Alfredo K. Kojima
6830b057 dan2004-10-12 21:28:27 +00005 *
58b36ec1 kojima2000-05-22 03:09:20 +00006 * This program is in the Public Domain.
7 */
8
9#include <X11/Xproto.h>
10
a20aebde dan2001-01-18 19:21:56 +000011#include <WINGs/WINGs.h>
58b36ec1 kojima2000-05-22 03:09:20 +000012#include <stdlib.h>
9aca0d5f dan2004-10-12 01:34:32 +000013#include <string.h>
58b36ec1 kojima2000-05-22 03:09:20 +000014#include <stdio.h>
15
b3dee733 kojima2000-07-15 08:12:33 +000016/*
17 * TODO:
18 * - lens that shows where it's magnifying
6830b057 dan2004-10-12 21:28:27 +000019 *
20 *
b3dee733 kojima2000-07-15 08:12:33 +000021 */
58b36ec1 kojima2000-05-22 03:09:20 +000022
23int refreshrate = 200;
24
58b36ec1 kojima2000-05-22 03:09:20 +000025typedef struct {
688a56e8
CM
Carlos R. Mafra2009-08-20 00:59:40 +020026 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;
58b36ec1 kojima2000-05-22 03:09:20 +000054} BufferData;
55
58b36ec1 kojima2000-05-22 03:09:20 +000056static BufferData *newWindow(int magfactor);
57
58b36ec1 kojima2000-05-22 03:09:20 +000058int windowCount = 0;
59
60int rectBufferSize = 32;
882b9a8e kojima2001-07-23 20:31:32 +000061Display *dpy, *vdpy;
58b36ec1 kojima2000-05-22 03:09:20 +000062WMScreen *scr;
63unsigned int black;
b3dee733 kojima2000-07-15 08:12:33 +000064WMColor *cursorColor1;
65WMColor *cursorColor2;
58b36ec1 kojima2000-05-22 03:09:20 +000066
67#ifndef __GNUC__
68#define inline
69#endif
70
688a56e8 Carlos R. Mafra2009-08-20 00:59:40 +020071static BufferData *makeBufferData(WMWindow * win, WMLabel * label, int width, int height, int magfactor)
58b36ec1 kojima2000-05-22 03:09:20 +000072{
688a56e8 Carlos R. Mafra2009-08-20 00:59:40 +020073 BufferData *data;
6830b057 dan2004-10-12 21:28:27 +000074
688a56e8 Carlos R. Mafra2009-08-20 00:59:40 +020075 data = wmalloc(sizeof(BufferData));
b3dee733 kojima2000-07-15 08:12:33 +000076
688a56e8
CM
Carlos R. Mafra2009-08-20 00:59:40 +020077 data->rwidth = width;
78 data->rheight = height;
6830b057 dan2004-10-12 21:28:27 +000079
688a56e8 Carlos R. Mafra2009-08-20 00:59:40 +020080 data->refreshrate = refreshrate;
6830b057 dan2004-10-12 21:28:27 +000081
688a56e8 Carlos R. Mafra2009-08-20 00:59:40 +020082 data->firstDraw = True;
b3dee733 kojima2000-07-15 08:12:33 +000083
688a56e8 Carlos R. Mafra2009-08-20 00:59:40 +020084 data->magfactor = magfactor;
6830b057 dan2004-10-12 21:28:27 +000085
688a56e8
CM
Carlos R. Mafra2009-08-20 00:59:40 +020086 data->rects = wmalloc(sizeof(XRectangle) * rectBufferSize);
87 data->rectP = 0;
6830b057 dan2004-10-12 21:28:27 +000088
688a56e8
CM
Carlos R. Mafra2009-08-20 00:59:40 +020089 data->win = win;
90 data->label = label;
58b36ec1 kojima2000-05-22 03:09:20 +000091
688a56e8
CM
Carlos R. Mafra2009-08-20 00:59:40 +020092 data->pixmap = WMCreatePixmap(scr, width, height, WMScreenDepth(scr), False);
93 WMSetLabelImage(data->label, data->pixmap);
58b36ec1 kojima2000-05-22 03:09:20 +000094
688a56e8 Carlos R. Mafra2009-08-20 00:59:40 +020095 data->d = WMGetPixmapXID(data->pixmap);
6830b057 dan2004-10-12 21:28:27 +000096
688a56e8 Carlos R. Mafra2009-08-20 00:59:40 +020097 data->frozen = False;
58b36ec1 kojima2000-05-22 03:09:20 +000098
688a56e8
CM
Carlos R. Mafra2009-08-20 00:59:40 +020099 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;
58b36ec1 kojima2000-05-22 03:09:20 +0000105
688a56e8 Carlos R. Mafra2009-08-20 00:59:40 +0200106 return data;
58b36ec1 kojima2000-05-22 03:09:20 +0000107}
108
688a56e8 Carlos R. Mafra2009-08-20 00:59:40 +0200109static void resizeBufferData(BufferData * data, int width, int height, int magfactor)
58b36ec1 kojima2000-05-22 03:09:20 +0000110{
688a56e8
CM
Carlos R. Mafra2009-08-20 00:59:40 +0200111 int w = width / magfactor;
112 int h = height / magfactor;
58b36ec1 kojima2000-05-22 03:09:20 +0000113
688a56e8
CM
Carlos R. Mafra2009-08-20 00:59:40 +0200114 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));
58b36ec1 kojima2000-05-22 03:09:20 +0000122
688a56e8 Carlos R. Mafra2009-08-20 00:59:40 +0200123 WMResizeWidget(data->label, width, height);
58b36ec1 kojima2000-05-22 03:09:20 +0000124
688a56e8
CM
Carlos R. Mafra2009-08-20 00:59:40 +0200125 WMReleasePixmap(data->pixmap);
126 data->pixmap = WMCreatePixmap(scr, width, height, WMScreenDepth(scr), False);
127 WMSetLabelImage(data->label, data->pixmap);
58b36ec1 kojima2000-05-22 03:09:20 +0000128
688a56e8 Carlos R. Mafra2009-08-20 00:59:40 +0200129 data->d = WMGetPixmapXID(data->pixmap);
58b36ec1 kojima2000-05-22 03:09:20 +0000130}
131
688a56e8 Carlos R. Mafra2009-08-20 00:59:40 +0200132static int drawpoint(BufferData * data, unsigned long pixel, int x, int y)
58b36ec1 kojima2000-05-22 03:09:20 +0000133{
688a56e8
CM
Carlos R. Mafra2009-08-20 00:59:40 +0200134 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;
58b36ec1 kojima2000-05-22 03:09:20 +0000168}
169
688a56e8
CM
Carlos R. Mafra2009-08-20 00:59:40 +0200170static 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}
58b36ec1 kojima2000-05-22 03:09:20 +0000177
688a56e8 Carlos R. Mafra2009-08-20 00:59:40 +0200178static void updateImage(BufferData * data, int rx, int ry)
58b36ec1 kojima2000-05-22 03:09:20 +0000179{
688a56e8
CM
Carlos R. Mafra2009-08-20 00:59:40 +0200180 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;
58b36ec1 kojima2000-05-22 03:09:20 +0000260}
261
688a56e8
CM
Carlos R. Mafra2009-08-20 00:59:40 +0200262static 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}
b3dee733 kojima2000-07-15 08:12:33 +0000280
688a56e8 Carlos R. Mafra2009-08-20 00:59:40 +0200281void resizedWindow(void *d, WMNotification * notif)
58b36ec1 kojima2000-05-22 03:09:20 +0000282{
688a56e8
CM
Carlos R. Mafra2009-08-20 00:59:40 +0200283 BufferData *data = (BufferData *) d;
284 WMView *view = (WMView *) WMGetNotificationObject(notif);
285 WMSize size;
58b36ec1 kojima2000-05-22 03:09:20 +0000286
688a56e8 Carlos R. Mafra2009-08-20 00:59:40 +0200287 size = WMGetViewSize(view);
6830b057 dan2004-10-12 21:28:27 +0000288
688a56e8 Carlos R. Mafra2009-08-20 00:59:40 +0200289 resizeBufferData(data, size.width, size.height, data->magfactor);
58b36ec1 kojima2000-05-22 03:09:20 +0000290}
291
688a56e8 Carlos R. Mafra2009-08-20 00:59:40 +0200292void closeWindow(WMWidget * w, void *d)
58b36ec1 kojima2000-05-22 03:09:20 +0000293{
688a56e8
CM
Carlos R. Mafra2009-08-20 00:59:40 +0200294 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 }
58b36ec1 kojima2000-05-22 03:09:20 +0000307}
308
b3dee733 kojima2000-07-15 08:12:33 +0000309#if 0
688a56e8 Carlos R. Mafra2009-08-20 00:59:40 +0200310static void clickHandler(XEvent * event, void *d)
b3dee733 kojima2000-07-15 08:12:33 +0000311{
688a56e8 Carlos R. Mafra2009-08-20 00:59:40 +0200312 BufferData *data = (BufferData *) d;
6830b057 dan2004-10-12 21:28:27 +0000313
688a56e8
CM
Carlos R. Mafra2009-08-20 00:59:40 +0200314 data->win = WMCreateWindow(scr, "setup");
315 WMSetWindowTitle(data->win, "Magnify Options");
6830b057 dan2004-10-12 21:28:27 +0000316
688a56e8 Carlos R. Mafra2009-08-20 00:59:40 +0200317 data->speed = WMCreateSlider(data->win);
6830b057 dan2004-10-12 21:28:27 +0000318
688a56e8 Carlos R. Mafra2009-08-20 00:59:40 +0200319 data->magnify = WMCreateSlider(data->win);
b3dee733 kojima2000-07-15 08:12:33 +0000320
321}
322#endif
323
688a56e8 Carlos R. Mafra2009-08-20 00:59:40 +0200324static void keyHandler(XEvent * event, void *d)
58b36ec1 kojima2000-05-22 03:09:20 +0000325{
688a56e8
CM
Carlos R. Mafra2009-08-20 00:59:40 +0200326 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 }
58b36ec1 kojima2000-05-22 03:09:20 +0000373}
374
688a56e8 Carlos R. Mafra2009-08-20 00:59:40 +0200375static BufferData *newWindow(int magfactor)
58b36ec1 kojima2000-05-22 03:09:20 +0000376{
688a56e8
CM
Carlos R. Mafra2009-08-20 00:59:40 +0200377 WMWindow *win;
378 WMLabel *label;
379 BufferData *data;
380 char buf[32];
58b36ec1 kojima2000-05-22 03:09:20 +0000381
688a56e8 Carlos R. Mafra2009-08-20 00:59:40 +0200382 windowCount++;
6830b057 dan2004-10-12 21:28:27 +0000383
688a56e8
CM
Carlos R. Mafra2009-08-20 00:59:40 +0200384 win = WMCreateWindow(scr, "magnify");
385 WMResizeWidget(win, 300, 200);
386 sprintf(buf, "Magnify %ix", magfactor);
387 WMSetWindowTitle(win, buf);
388 WMSetViewNotifySizeChanges(WMWidgetView(win), True);
58b36ec1 kojima2000-05-22 03:09:20 +0000389
688a56e8
CM
Carlos R. Mafra2009-08-20 00:59:40 +0200390 label = WMCreateLabel(win);
391 WMResizeWidget(label, 300, 200);
392 WMMoveWidget(label, 0, 0);
393 WMSetLabelRelief(label, WRSunken);
394 WMSetLabelImagePosition(label, WIPImageOnly);
6830b057 dan2004-10-12 21:28:27 +0000395
688a56e8 Carlos R. Mafra2009-08-20 00:59:40 +0200396 data = makeBufferData(win, label, 300, 200, magfactor);
58b36ec1 kojima2000-05-22 03:09:20 +0000397
688a56e8 Carlos R. Mafra2009-08-20 00:59:40 +0200398 WMCreateEventHandler(WMWidgetView(win), KeyReleaseMask, keyHandler, data);
6830b057 dan2004-10-12 21:28:27 +0000399
688a56e8 Carlos R. Mafra2009-08-20 00:59:40 +0200400 WMAddNotificationObserver(resizedWindow, data, WMViewSizeDidChangeNotification, WMWidgetView(win));
58b36ec1 kojima2000-05-22 03:09:20 +0000401
688a56e8 Carlos R. Mafra2009-08-20 00:59:40 +0200402 WMRealizeWidget(win);
58b36ec1 kojima2000-05-22 03:09:20 +0000403
688a56e8
CM
Carlos R. Mafra2009-08-20 00:59:40 +0200404 WMMapSubwidgets(win);
405 WMMapWidget(win);
58b36ec1 kojima2000-05-22 03:09:20 +0000406
688a56e8
CM
Carlos R. Mafra2009-08-20 00:59:40 +0200407 WMSetWindowCloseAction(win, closeWindow, data);
408 data->tid = WMAddTimerHandler(refreshrate, update, data);
58b36ec1 kojima2000-05-22 03:09:20 +0000409
688a56e8 Carlos R. Mafra2009-08-20 00:59:40 +0200410 return data;
58b36ec1 kojima2000-05-22 03:09:20 +0000411}
412
58b36ec1 kojima2000-05-22 03:09:20 +0000413int main(int argc, char **argv)
414{
688a56e8
CM
Carlos R. Mafra2009-08-20 00:59:40 +0200415 BufferData *data;
416 int i;
417 char *display = "";
418 char *vdisplay = NULL;
419 int magfactor = 2;
58b36ec1 kojima2000-05-22 03:09:20 +0000420#if 0
688a56e8 Carlos R. Mafra2009-08-20 00:59:40 +0200421 WMButton *radio, *tradio;
58b36ec1 kojima2000-05-22 03:09:20 +0000422#endif
688a56e8
CM
Carlos R. Mafra2009-08-20 00:59:40 +0200423 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;
58b36ec1 kojima2000-05-22 03:09:20 +0000506}