fixed redraw problem when frame title changes
[wmaker-crm.git] / util / wmagnify.c
blob770e868f109306403ce1aa61e2d2411097e81ba6
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 */
9 #include <X11/Xproto.h>
11 #include <WINGs.h>
12 #include <stdlib.h>
13 #include <stdio.h>
16 int refreshrate = 200;
19 typedef struct {
20 Drawable d;
21 XRectangle *rects;
22 int rectP;
23 unsigned long lastpixel;
24 unsigned long *buffer;
25 int width, height;
26 int magfactor;
28 WMWindow *win;
29 WMLabel *label;
30 WMPixmap *pixmap;
32 int x, y;
33 Bool frozen;
35 WMHandlerID tid;
36 } BufferData;
40 static BufferData *newWindow(int magfactor);
43 int windowCount = 0;
45 int rectBufferSize = 32;
46 Display *dpy;
47 WMScreen *scr;
48 unsigned int black;
50 #ifndef __GNUC__
51 #define inline
52 #endif
55 static BufferData*
56 makeBufferData(WMWindow *win, WMLabel *label, int width, int height,
57 int magfactor)
59 BufferData *data;
61 data = wmalloc(sizeof(BufferData));
63 data->magfactor = magfactor;
65 data->rects = wmalloc(sizeof(XRectangle)*rectBufferSize);
66 data->rectP = 0;
68 data->win = win;
69 data->label = label;
71 data->pixmap = WMCreatePixmap(scr, width, height,
72 WMScreenDepth(scr), False);
73 WMSetLabelImage(data->label, data->pixmap);
75 data->d = WMGetPixmapXID(data->pixmap);
77 data->frozen = False;
79 width /= magfactor;
80 height /= magfactor;
81 data->buffer = wmalloc(sizeof(unsigned long)*width*height);
82 memset(data->buffer, 0, width*height*sizeof(unsigned long));
83 data->width = width;
84 data->height = height;
86 return data;
90 static void
91 resizeBufferData(BufferData *data, int width, int height, int magfactor)
93 int w = width/magfactor;
94 int h = height/magfactor;
96 data->magfactor = magfactor;
97 data->buffer = wrealloc(data->buffer, sizeof(unsigned long)*w*h);
98 data->width = w;
99 data->height = h;
100 memset(data->buffer, 0, w*h*sizeof(unsigned long));
102 WMResizeWidget(data->label, width, height);
104 WMReleasePixmap(data->pixmap);
105 data->pixmap = WMCreatePixmap(scr, width, height, WMScreenDepth(scr),
106 False);
107 WMSetLabelImage(data->label, data->pixmap);
109 data->d = WMGetPixmapXID(data->pixmap);
113 static int
114 drawpoint(BufferData *data, unsigned long pixel, int x, int y)
116 static GC gc = NULL;
118 if (data->buffer[x+data->width*y] == pixel)
119 return 0;
121 data->buffer[x+data->width*y] = pixel;
123 if (gc == NULL) {
124 gc = XCreateGC(dpy, DefaultRootWindow(dpy), 0, NULL);
127 if (data->lastpixel == pixel && data->rectP < rectBufferSize) {
128 data->rects[data->rectP].x = x*data->magfactor;
129 data->rects[data->rectP].y = y*data->magfactor;
130 data->rects[data->rectP].width = data->magfactor;
131 data->rects[data->rectP].height = data->magfactor;
132 data->rectP++;
134 return 0;
136 XSetForeground(dpy, gc, data->lastpixel);
137 XFillRectangles(dpy, data->d, gc, data->rects, data->rectP);
138 data->rectP = 0;
139 data->rects[data->rectP].x = x*data->magfactor;
140 data->rects[data->rectP].y = y*data->magfactor;
141 data->rects[data->rectP].width = data->magfactor;
142 data->rects[data->rectP].height = data->magfactor;
143 data->rectP++;
145 data->lastpixel = pixel;
147 return 1;
151 static inline unsigned long
152 getpix(XImage *image, int x, int y, int xoffs, int yoffs)
154 if (x < xoffs || y < yoffs
155 || x >= xoffs + image->width || y >= yoffs + image->height) {
156 return black;
158 return XGetPixel(image, x-xoffs, y-yoffs);
162 static void
163 updateImage(BufferData *data, int rx, int ry)
165 int gx, gy, gw, gh;
166 int x, y;
167 int xoffs, yoffs;
168 int changedPixels = 0;
169 XImage *image;
171 gw = data->width;
172 gh = data->height;
174 gx = rx - gw/2;
175 gy = ry - gh/2;
177 xoffs = yoffs = 0;
178 if (gx < 0) {
179 xoffs = abs(gx);
180 gw += gx;
181 gx = 0;
183 if (gx + gw >= WidthOfScreen(DefaultScreenOfDisplay(dpy))) {
184 gw = WidthOfScreen(DefaultScreenOfDisplay(dpy)) - gx;
186 if (gy < 0) {
187 yoffs = abs(gy);
188 gh += gy;
189 gy = 0;
191 if (gy + gh >= HeightOfScreen(DefaultScreenOfDisplay(dpy))) {
192 gh = HeightOfScreen(DefaultScreenOfDisplay(dpy)) - gy;
195 image = XGetImage(dpy, DefaultRootWindow(dpy), gx, gy, gw, gh,
196 AllPlanes, ZPixmap);
199 for (y = 0; y < data->height; y++) {
200 for (x = 0; x < data->width; x++) {
201 unsigned long pixel;
203 pixel = getpix(image, x-xoffs, y-yoffs, xoffs, yoffs);
205 if (drawpoint(data, pixel, x, y))
206 changedPixels++;
210 XDestroyImage(image);
212 if (changedPixels > 0) {
213 WMRedisplayWidget(data->label);
218 static void
219 update(void *d)
221 BufferData *data = (BufferData*)d;
222 Window win;
223 int rx, ry;
224 int bla;
225 unsigned ubla;
228 if (data->frozen) {
229 rx = data->x;
230 ry = data->y;
231 } else {
232 XQueryPointer(dpy, DefaultRootWindow(dpy), &win, &win, &rx, &ry,
233 &bla, &bla, &ubla);
235 updateImage(data, rx, ry);
237 data->tid = WMAddTimerHandler(refreshrate, update, data);
240 void resizedWindow(void *d, WMNotification *notif)
242 BufferData *data = (BufferData*)d;
243 WMView *view = (WMView*)WMGetNotificationObject(notif);
244 WMSize size;
246 size = WMGetViewSize(view);
248 resizeBufferData(data, size.width, size.height, data->magfactor);
253 void closeWindow(WMWidget *w, void *d)
255 BufferData *data = (BufferData*)d;
257 windowCount--;
258 if (windowCount == 0) {
259 exit(0);
260 } else {
261 WMDeleteTimerHandler(data->tid);
262 WMDestroyWidget(w);
263 free(data->buffer);
264 free(data->rects);
265 WMReleasePixmap(data->pixmap);
266 free(data);
271 static void
272 keyHandler(XEvent *event, void *d)
274 BufferData *data = (BufferData*)d;
275 char buf[32];
276 KeySym ks;
277 WMView *view = WMWidgetView(data->win);
278 WMSize size;
280 size = WMGetViewSize(view);
282 if (XLookupString(&event->xkey, buf, 31, &ks, NULL) > 0) {
283 switch (buf[0]) {
284 case 'n':
285 newWindow(data->magfactor);
286 break;
287 case 'f':
288 case ' ':
289 data->frozen = !data->frozen;
290 if (data->frozen) {
291 data->x = event->xkey.x_root;
292 data->y = event->xkey.y_root;
293 sprintf(buf, "[Magnify %ix]", data->magfactor);
294 } else {
295 sprintf(buf, "Magnify %ix", data->magfactor);
297 WMSetWindowTitle(data->win, buf);
298 break;
299 case '1':
300 case '2':
301 case '3':
302 case '4':
303 case '5':
304 case '6':
305 case '7':
306 case '8':
307 case '9':
308 resizeBufferData(data, size.width, size.height, buf[0]-'0');
309 if (data->frozen) {
310 sprintf(buf, "[Magnify %ix]", data->magfactor);
311 } else {
312 sprintf(buf, "Magnify %ix", data->magfactor);
314 WMSetWindowTitle(data->win, buf);
315 break;
321 static BufferData*
322 newWindow(int magfactor)
324 WMWindow *win;
325 WMLabel *label;
326 BufferData *data;
327 char buf[32];
329 windowCount++;
331 win = WMCreateWindow(scr, "magnify");
332 WMResizeWidget(win, 300, 200);
333 sprintf(buf, "Magnify %ix", magfactor);
334 WMSetWindowTitle(win, buf);
335 WMSetViewNotifySizeChanges(WMWidgetView(win), True);
337 label = WMCreateLabel(win);
338 WMResizeWidget(label, 300, 200);
339 WMMoveWidget(label, 0, 0);
340 WMSetLabelRelief(label, WRSunken);
341 WMSetLabelImagePosition(label, WIPImageOnly);
343 data = makeBufferData(win, label, 300, 200, magfactor);
345 WMCreateEventHandler(WMWidgetView(win), KeyReleaseMask,
346 keyHandler, data);
348 WMAddNotificationObserver(resizedWindow, data,
349 WMViewSizeDidChangeNotification,
350 WMWidgetView(win));
352 WMRealizeWidget(win);
354 WMMapSubwidgets(win);
355 WMMapWidget(win);
357 WMSetWindowCloseAction(win, closeWindow, data);
358 data->tid = WMAddTimerHandler(refreshrate, update, data);
360 return data;
364 int main(int argc, char **argv)
366 BufferData *data;
367 int i;
368 char *display = "";
369 int magfactor = 2;
370 #if 0
371 WMButton *radio, *tradio;
372 #endif
373 WMInitializeApplication("Magnify", &argc, argv);
376 for (i = 1; i < argc; i++) {
377 if (strcmp(argv[i], "-display")==0) {
378 i++;
379 if (i >= argc)
380 goto help;
381 display = argv[i];
382 } else if (strcmp(argv[i], "-m")==0) {
383 i++;
384 if (i >= argc)
385 goto help;
386 magfactor = atoi(argv[i]);
387 if (magfactor < 1 || magfactor > 32) {
388 printf("%s:invalid magnification factor ``%s''\n", argv[0],
389 argv[i]);
390 exit(1);
392 } else if (strcmp(argv[i], "-r")==0) {
393 i++;
394 if (i >= argc)
395 goto help;
396 refreshrate = atoi(argv[i]);
397 if (refreshrate < 1) {
398 printf("%s:invalid refresh rate ``%s''\n", argv[0], argv[i]);
399 exit(1);
401 } else if (strcmp(argv[i], "-h")==0
402 || strcmp(argv[i], "--help")==0) {
403 help:
404 printf("Syntax: %s [-display <display>] [-m <number>] [-r <number>]\n",
405 argv[0]);
406 puts("-display <display> display that should be used");
407 puts("-m <number> change magnification factor (default 2)");
408 puts("-r <number> change refresh delay, in milliseconds (default 200)");
409 exit(0);
413 dpy = XOpenDisplay("");
414 if (!dpy) {
415 puts("couldnt open display");
416 exit(1);
419 /* calculate how many rectangles we can send in a trip to the server */
420 rectBufferSize = XMaxRequestSize(dpy) - 128;
421 rectBufferSize /= sizeof(XRectangle);
422 if (rectBufferSize < 1)
423 rectBufferSize = 1;
425 black = BlackPixel(dpy, DefaultScreen(dpy));
427 scr = WMCreateScreen(dpy, 0);
429 data = newWindow(magfactor);
431 WMScreenMainLoop(scr);
433 return 0;