c9e37d63c3c21c67663c980b57ca91b9ab41318f
[fw/altos] / src / draw / frame.c
1 /*
2  * Copyright © 2023 Keith Packard <keithp@keithp.com>
3  *
4  * This program is free software; you can redistribute it and/or modify
5  * it under the terms of the GNU General Public License as published by
6  * the Free Software Foundation, either version 2 of the License, or
7  * (at your option) any later version.
8  *
9  * This program is distributed in the hope that it will be useful, but
10  * WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12  * General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License along
15  * with this program; if not, write to the Free Software Foundation, Inc.,
16  * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
17  */
18 #include    <stdio.h>
19 #include    <stdlib.h>
20 #include    <ctype.h>
21 #include    <strings.h>
22 #include    <X11/Xos.h>
23 #include    <X11/Xlib.h>
24 #include    <X11/Xutil.h>
25 #include    <X11/Xatom.h>
26
27 #ifndef DEFAULT_VISUAL
28 #define DEFAULT_VISUAL 0
29 #endif
30
31 #ifndef DEFAULT_ROP
32 #define DEFAULT_ROP "copy"
33 #endif
34
35 #ifndef DEFAULT_WIDTH
36 #define DEFAULT_WIDTH 200
37 #endif
38
39 #ifndef DEFAULT_HEIGHT
40 #define DEFAULT_HEIGHT 200
41 #endif
42
43 #ifndef DEFAULT_FONT
44 #define DEFAULT_FONT 0
45 #endif
46
47 #ifndef DEFAULT_LINE_WIDTH
48 #define DEFAULT_LINE_WIDTH 0
49 #endif
50
51 #ifndef DEFAULT_LINE_STYLE
52 #define DEFAULT_LINE_STYLE NULL
53 #endif
54
55 #ifndef DEFAULT_FILL_STYLE
56 #define DEFAULT_FILL_STYLE NULL
57 #endif
58
59 #ifndef DEFAULT_CAP_STYLE
60 #define DEFAULT_CAP_STYLE NULL
61 #endif
62
63 #ifndef DEFAULT_JOIN_STYLE
64 #define DEFAULT_JOIN_STYLE NULL
65 #endif
66
67 #ifndef DEFAULT_DASHES
68 #define DEFAULT_DASHES  0
69 #define DEFAULT_NUM_DASHES 0
70 #endif
71
72 #ifdef ALL_MOTION
73 #define MOTION  PointerMotionMask
74 #else
75 #define MOTION  ButtonMotionMask
76 #endif
77
78 #ifndef EXTRA_EVENTS
79 #define EXTRA_EVENTS 0
80 #endif
81
82 unsigned long   fg_pixel;
83 unsigned long   bg_pixel;
84 int             default_rop;
85 XFontStruct     *default_font;
86
87 typedef struct _RopNames { char *name; int  rop; } RopNameRec, *RopNamePtr;
88
89 RopNameRec ropNames[] = {
90         { "clear",      GXclear,        }, /* 0 */
91         { "and",                GXand,          }, /* src AND dst */
92         { "andReverse", GXandReverse,   }, /* src AND NOT dst */
93         { "copy",               GXcopy,         }, /* src */
94         { "andInverted",        GXandInverted,  }, /* NOT src AND dst */
95         { "noop",               GXnoop,         }, /* dst */
96         { "xor",                GXxor,          }, /* src XOR dst */
97         { "or",         GXor,           }, /* src OR dst */
98         { "nor",                GXnor,          }, /* NOT src AND NOT dst */
99         { "equiv",      GXequiv,        }, /* NOT src XOR dst */
100         { "invert",     GXinvert,       }, /* NOT dst */
101         { "orReverse",  GXorReverse,    }, /* src OR NOT dst */
102         { "copyInverted",       GXcopyInverted, }, /* NOT src */
103         { "orInverted", GXorInverted,   }, /* NOT src OR dst */
104         { "nand",               GXnand,         }, /* NOT src OR NOT dst */
105         { "set",                GXset,          }, /* 1 */
106 };
107
108 int
109 RopNameToRop (char *name)
110 {
111     int rop;
112
113     for (rop = 0; rop < 16; rop++) {
114         if (!strcmp (name, ropNames[rop].name)) {
115             return ropNames[rop].rop;
116         }
117     }
118     return GXcopy;
119 }
120
121 void
122 Error (char *s, char *a)
123 {
124     fprintf (stderr, s, a);
125     fprintf (stderr, "\n");
126     exit (1);
127 }
128
129 int
130 MatchCapStyle (char *s)
131 {
132     if (!strcmp (s, "round"))
133         return CapRound;
134     if (!strcmp (s, "projecting"))
135         return CapProjecting;
136     if (!strcmp (s, "butt"))
137         return CapButt;
138     if (!strcmp (s, "notlast"))
139         return CapNotLast;
140     Error ("Unknown cap style %s", s);
141     return CapNotLast;
142 }
143
144 int
145 MatchJoinStyle (char *s)
146 {
147     if (!strcmp (s, "round"))
148         return JoinRound;
149     if (!strcmp (s, "miter"))
150         return JoinMiter;
151     if (!strcmp (s, "bevel"))
152         return JoinBevel;
153     Error ("Unknown join style %s", s);
154     return JoinBevel;
155 }
156
157 int
158 MatchFillStyle(char *s)
159 {
160     if (!strcmp (s, "solid"))
161         return FillSolid;
162     if (!strcmp (s, "tiled"))
163         return FillTiled;
164     if (!strcmp (s, "stippled"))
165         return FillStippled;
166     if (!strcmp (s, "opaquestippled"))
167         return FillOpaqueStippled;
168     Error ("Unknown fill style %s", s);
169     return FillSolid;
170 }
171
172 int
173 MatchLineStyle(char *s)
174 {
175     if (!strcmp (s, "solid"))
176         return LineSolid;
177     if (!strcmp (s, "onoff"))
178         return LineOnOffDash;
179     if (!strcmp (s, "double"))
180         return LineDoubleDash;
181     Error ("Unknown line style %s", s);
182     return LineSolid;
183 }
184
185 #ifdef TRACK_POINTER
186 #define PASS_BUTTONS
187 typedef struct _Position {
188     int seen;
189     int start_x, start_y;
190     int cur_x, cur_y;
191     int end_x, end_y;
192 } PositionRec, *PositionPtr;
193
194 PositionRec positions[5];
195
196 void
197 UpdatePositions (state, x, y)
198 {
199     int i;
200
201     state >>= 8;
202     for (i = 0; i < 5; i++)
203     {
204         if (state & (1 << i)) {
205             positions[i].cur_x = x;
206             positions[i].cur_y = y;
207         }
208     }
209 }
210
211 void
212 HandleButtonPress (dpy, win, gc, ev)
213     Display *dpy;
214     Window  win;
215     GC      gc;
216     XEvent  *ev;
217 {
218     XButtonEvent    *bev = (XButtonEvent *) ev;
219
220     Undraw (dpy, win, gc, positions);
221     positions[bev->button - 1].seen = 1;
222     positions[bev->button - 1].start_x = bev->x;
223     positions[bev->button - 1].start_y = bev->y;
224     positions[bev->button - 1].cur_x = bev->x;
225     positions[bev->button - 1].cur_y = bev->y;
226     positions[bev->button - 1].end_x = bev->x;
227     positions[bev->button - 1].end_y = bev->y;
228     UpdatePositions (bev->state, bev->x, bev->y);
229     Draw (dpy, win, gc, positions);
230 }
231
232 void
233 HandleButtonRelease (dpy, win, gc, ev)
234     Display *dpy;
235     Window  win;
236     GC      gc;
237     XEvent  *ev;
238 {
239     XButtonEvent    *bev = (XButtonEvent *) ev;
240
241     Undraw (dpy, win, gc, positions);
242     UpdatePositions (bev->state, bev->x, bev->y);
243     positions[bev->button - 1].end_x = bev->x;
244     positions[bev->button - 1].end_y = bev->y;
245     Draw (dpy, win, gc, positions);
246 }
247
248 void
249 HandleMotionNotify (dpy, win, gc, ev)
250     Display *dpy;
251     Window  win;
252     GC      gc;
253     XEvent  *ev;
254 {
255     XMotionEvent    *mev = (XMotionEvent *) ev;
256
257     Undraw (dpy, win, gc, positions);
258     UpdatePositions (mev->state, mev->x, mev->y);
259     Draw (dpy, win, gc, positions);
260 }
261
262 void
263 DisplayPositions (dpy, win, gc, positions)
264     Display         *dpy;
265     Window          win;
266     GC              gc;
267     PositionRec     positions[5];
268 {
269     static char text[1024];
270     static int  hastext;
271     int         pos;
272     int         i;
273     int         dir, font_ascent, font_descent;
274     XCharStruct overall;
275
276     XTextExtents (default_font , text, strlen(text),
277             &dir, &font_ascent, &font_descent, &overall);
278     if (hastext)
279         XClearArea (dpy, win, 0, 0, overall.width, font_ascent + font_descent, False);
280     pos = 0;
281     for (i = 0; i < 5; i++)
282     {
283         if (positions[i].seen)
284         {
285             if (pos)
286                 text[pos++] = ',';
287             sprintf (text + pos, "%1d: (%4d,%4d),(%4d,%4d)",
288                 i, positions[i].start_x, positions[i].start_y,
289                 positions[i].cur_x, positions[i].cur_y);
290             pos = strlen (text);
291         }
292     }
293     XDrawString (dpy, win, gc, 0, font_ascent, text, pos);
294     hastext = 1;
295 }
296
297 #endif
298
299 void
300 SetToFg (dpy, gc)
301     Display *dpy;
302     GC      gc;
303 {
304     XSetForeground (dpy, gc, fg_pixel);
305     XSetFunction (dpy, gc, default_rop);
306 }
307
308 void
309 SetToBg (dpy, gc)
310     Display *dpy;
311     GC      gc;
312 {
313     XSetForeground (dpy, gc, bg_pixel);
314     XSetFunction (dpy, gc, GXcopy);
315 }
316
317 void
318 Usage (program)
319     char    *program;
320 {
321     int i;
322     fprintf (stderr, "Usage: %s\n", program);
323     fprintf (stderr, "\t-display <display-name>\n");
324     fprintf (stderr, "\t-rop {");
325     for (i = 0; i < 16; i++) {
326         fprintf (stderr, "%s", ropNames[i].name);
327         if (i == 15)
328             fprintf (stderr, "}\n");
329         else if (i % 4 == 3)
330             fprintf (stderr, ",\n\t\t");
331         else
332             fprintf (stderr, ", ");
333     }
334     fprintf (stderr, "\t-fg <fg color name>\n");
335     fprintf (stderr, "\t-bg <bg color name>\n");
336     fprintf (stderr, "\t-fg_pixel <fg pixel value>\n");
337     fprintf (stderr, "\t-bg_pixel <bg pixel value>\n");
338     fprintf (stderr, "\t-fn <font name>\n");
339     fprintf (stderr, "\t-geometry <geometry>\n");
340     fprintf (stderr, "\t-lw <line width>\n");
341     fprintf (stderr, "\t-cap {round, projecting, butt, notlast}\n");
342     fprintf (stderr, "\t-join {round, miter, bevel}\n");
343     fprintf (stderr, "\t-fill {solid, tiled, stippled, opaquestippled}\n");
344     fprintf (stderr, "\t-linestyle {solid, onoff, double}\n");
345     fprintf (stderr, "\t-bitmap <bitmap file name>\n");
346     fprintf (stderr, "\t-dashes [<dash value> ...]\n");
347     exit (1);
348 }
349
350 char    *dpy_name;
351 char    *rop_name;
352 char    *fg;
353 char    *bg;
354 char    *bitmap_file;
355 char    *cap_name = DEFAULT_CAP_STYLE;
356 char    *join_name = DEFAULT_JOIN_STYLE;
357 char    *fill_name = DEFAULT_FILL_STYLE;
358 char    *line_name = DEFAULT_LINE_STYLE;
359 char    *font_name = DEFAULT_FONT;
360 double  line_width = DEFAULT_LINE_WIDTH;
361 char    dashes[256] = { DEFAULT_DASHES };
362 int     ndashes = DEFAULT_NUM_DASHES;
363 VisualID    vid = DEFAULT_VISUAL;
364 unsigned long   planemask = ~0;
365 Colormap    colormap;
366 Visual      *visual;
367 int         depth;
368 Window  root = 0;
369 int         screen;
370
371 void
372 HandleExpose(Display *dpy, Window win, GC gc);
373
374 void
375 HandleKeyPress(Display *dpy, Window win, GC gc, XEvent *ev);
376
377 void
378 HandleKeyRelease(Display *dpy, Window win, GC gc, XEvent *ev);
379
380 int
381 main (argc, argv)
382     int     argc;
383     char    **argv;
384 {
385     Display *dpy;
386     Window  win;
387     GC      gc;
388     char    **init_argv = argv;
389     XSetWindowAttributes    attr;
390     XColor  hard, exact;
391     int     x = 0, y = 0;
392     unsigned int    width = DEFAULT_WIDTH, height = DEFAULT_HEIGHT;
393     int     geometryMask;
394     int     border_width = 1;
395     XSizeHints  sizeHints;
396     XWMHints    wmHints;
397     XClassHint  classHints;
398     XEvent      ev, mev;
399     XGCValues   gcv;
400 #ifdef MATCH_ARGUMENT
401     int         i;
402 #endif
403     int         HasMotion = 0;
404 #ifdef COMPRESS_EXPOSE
405     XEvent      eev;
406     int         HasExpose = 0;
407 #endif
408     int         sync = 0;
409     XTextProperty   wm_name, icon_name;
410     Atom        wm_delete_window;
411     int         has_fg_pixel = 0, has_bg_pixel = 0;
412     int         has_colormap = 0;
413     unsigned long   gc_mask;
414     char        quit_string[10];
415     unsigned long   window_mask;
416
417     if (!rop_name)
418         rop_name = DEFAULT_ROP;
419     wm_name.value = (unsigned char *) argv[0];
420     wm_name.encoding = XA_STRING;
421     wm_name.format = 8;
422     wm_name.nitems = strlen (wm_name.value) + 1;
423     icon_name = wm_name;
424     gc_mask = 0;
425     while (*++argv) {
426         if (!strcmp (*argv, "-display"))
427             dpy_name = *++argv;
428         else if (!strcmp (*argv, "-visual"))
429             vid = strtol(*++argv, NULL, 0);
430         else if (!strcmp (*argv, "-cmap"))
431         {
432             colormap = strtol(*++argv, NULL, 0);
433             has_colormap = 1;
434         }
435         else if (!strcmp (*argv, "-rop"))
436             rop_name = *++argv;
437         else if (!strcmp (*argv, "-fg"))
438             fg = *++argv;
439         else if (!strcmp (*argv, "-bg"))
440             bg = *++argv;
441         else if (!strcmp (*argv, "-fg_pixel"))
442         {
443             fg_pixel = strtol(*++argv, NULL, 0);
444             has_fg_pixel = 1;
445         }
446         else if (!strcmp (*argv, "-bg_pixel"))
447         {
448             bg_pixel = strtol(*++argv, NULL, 0);
449             has_bg_pixel = 1;
450         }
451         else if (!strcmp (*argv, "-fn"))
452             font_name = *++argv;
453         else if (!strcmp (*argv, "-pm"))
454             planemask = strtol(*++argv, NULL, 0);
455         else if (!strcmp (*argv, "-geometry"))
456             geometryMask = XParseGeometry (*++argv, &x, &y, &width, &height);
457         else if (!strcmp (*argv, "-sync"))
458             sync = 1;
459         else if (!strcmp (*argv, "-bw"))
460             border_width = strtol(*++argv, NULL, 0);
461         else if (!strcmp (*argv, "-lw"))
462             line_width = strtod(*++argv, NULL);
463         else if (!strcmp (*argv, "-cap"))
464             cap_name = *++argv;
465         else if (!strcmp (*argv, "-join"))
466             join_name = *++argv;
467         else if (!strcmp (*argv, "-fill"))
468             fill_name = *++argv;
469         else if (!strcmp (*argv, "-linestyle"))
470             line_name = *++argv;
471         else if (!strcmp (*argv, "-bitmap"))
472             bitmap_file = *++argv;
473         else if (!strcmp (*argv, "-dashes"))
474         {
475             argv++;
476             ndashes = 0;
477             while (*argv && isdigit (**argv))
478                 dashes[ndashes++] = atoi(*argv++);
479             argv--;
480         }
481 #ifdef MATCH_ARGUMENT
482         else if (i = MatchArgument (argv))
483             argv += i - 1;
484 #endif
485         else if (!strcmp (*argv, "-root"))
486             root = strtol (*++argv, NULL, 0);
487         else
488             Usage (*init_argv);
489     }
490     sizeHints.flags = 0;
491     wmHints.flags = InputHint;
492     wmHints.input = True;
493     classHints.res_name = init_argv[0];
494     classHints.res_class = init_argv[0];
495     dpy = XOpenDisplay (dpy_name);
496     if (!dpy)
497         Error ("Can't open display", "");
498     if (sync)
499         XSynchronize (dpy, sync);
500     screen = DefaultScreen (dpy);
501     if (!root)
502         root = RootWindow (dpy, screen);
503     window_mask = CWBackPixel|CWBorderPixel|CWEventMask;
504     if (!has_colormap)
505         colormap = DefaultColormap (dpy, screen);
506     else
507     {
508         window_mask |= CWColormap;
509         attr.colormap = colormap;
510     }
511     visual = DefaultVisual (dpy, screen);
512     depth = DefaultDepth (dpy, screen);
513     if (vid)
514     {
515         XVisualInfo vi, *vi_ret;
516         int         n;
517
518         vi.visualid = vid;
519         vi.screen = screen;
520         vi_ret = XGetVisualInfo (dpy, VisualIDMask|VisualScreenMask,
521                                  &vi, &n);
522         if (vi_ret)
523         {
524             visual = vi_ret->visual;
525             if (!has_colormap)
526             {
527                 colormap = XCreateColormap (dpy, root, visual, AllocNone);
528                 window_mask |= CWColormap;
529                 attr.colormap = colormap;
530             }
531             depth = vi_ret->depth;
532         }
533     }
534     if (!has_fg_pixel)
535         fg_pixel = BlackPixel (dpy, screen);
536     if (!has_bg_pixel)
537         bg_pixel = WhitePixel (dpy, screen);
538     if (fg)
539     {
540         if (!XAllocNamedColor (dpy, colormap, fg, &hard, &exact))
541             Error ("Can't allocate fg pixel %s", fg);
542         fg_pixel = hard.pixel;
543     }
544     if (bg)
545     {
546         if (!XAllocNamedColor (dpy, colormap, bg, &hard, &exact))
547             Error ("Can't allocate bg pixel %s", bg);
548         bg_pixel = hard.pixel;
549     }
550     attr.background_pixel = bg_pixel;
551     attr.border_pixel = fg_pixel;
552     attr.event_mask =
553         ExposureMask|KeyPressMask|KeyReleaseMask|ButtonPressMask|ButtonReleaseMask|MOTION|EXTRA_EVENTS;
554 //    attr.override_redirect = True;
555 //    window_mask |= CWOverrideRedirect;
556     wm_delete_window = XInternAtom(dpy, "WM_DELETE_WINDOW", False);
557     win = XCreateWindow (dpy, root, x, y, width, height, border_width,
558                          depth, InputOutput,
559                          visual,
560                          window_mask,
561                          &attr);
562 #ifdef PASS_SETUP
563     Setup (dpy, win);
564 #endif
565     XSetWMProperties (dpy, win,
566                       &wm_name, &icon_name,
567                       init_argv, argc,
568                       &sizeHints, &wmHints, 0);
569     XSetWMProtocols (dpy, win, &wm_delete_window, 1);
570     default_rop =  RopNameToRop (rop_name);
571     if (line_width) 
572     {
573         gcv.line_width = (int) line_width;
574         gc_mask |= GCLineWidth;
575     }
576     if (cap_name)
577     {
578         gcv.cap_style = MatchCapStyle (cap_name);
579         gc_mask |= GCCapStyle;
580     }
581     if (fill_name) {
582         gcv.fill_style = MatchFillStyle (fill_name);
583         gc_mask |= GCFillStyle;
584     }   
585     if (line_name) {
586         gcv.line_style = MatchLineStyle (line_name);
587         gc_mask |= GCLineStyle;
588     }
589     if (join_name) {
590         gcv.join_style = MatchJoinStyle (join_name);
591         gc_mask |= GCJoinStyle;
592     }
593     if (font_name)
594         default_font = XLoadQueryFont (dpy, font_name);
595     if (default_font) {
596         gcv.font = default_font->fid;
597         gc_mask |= GCFont;
598     }
599     gcv.function = default_rop;
600     gcv.foreground = fg_pixel;
601     gcv.background = bg_pixel;
602     gcv.plane_mask = planemask;
603     gc_mask |= GCFunction|GCForeground|GCBackground|GCPlaneMask;
604     if (bitmap_file)
605     {
606         unsigned int    width, height;
607         int             ret;
608         Pixmap          bitmap, pixmap;
609
610         ret = XReadBitmapFile (dpy, win, bitmap_file, &width, &height,
611                                &bitmap, (int *) 0, (int *) 0);
612         switch (ret) {
613         case BitmapOpenFailed:
614             Error ("Can't open bitmap file %s", bitmap_file);
615         case BitmapFileInvalid:
616             Error ("Bitmap file %s invalid", bitmap_file);
617         case BitmapNoMemory:
618             Error ("Out of memory reading bitmap file %s", bitmap_file);
619         case BitmapSuccess:
620             break;
621         }
622         switch (gcv.fill_style) {
623         case FillTiled:
624             pixmap = XCreatePixmap (dpy, win, width, height, DefaultDepth (dpy, screen));
625             gc = XCreateGC (dpy, pixmap, GCForeground|GCBackground, &gcv);
626             XCopyPlane (dpy, bitmap, pixmap, gc, 0, 0, width, height, 0, 0, 1);
627             XFreeGC (dpy, gc);
628             XFreePixmap (dpy, bitmap);
629             gcv.tile = pixmap;
630             gc_mask |= GCTile;
631             break;
632         case FillStippled:
633         case FillOpaqueStippled:
634             gcv.stipple = bitmap;
635             gc_mask |= GCStipple;
636             break;
637         }
638     }
639     gc = XCreateGC (dpy, win, gc_mask, &gcv);
640     if (!default_font)
641         default_font = XQueryFont (dpy, XGContextFromGC(gc));
642     if (ndashes)
643         XSetDashes (dpy, gc, 0, dashes, ndashes);
644     XMapWindow (dpy, win);
645     for (;;) {
646         XNextEvent (dpy, &ev);
647 #ifdef PASS_BUTTONS
648         if (HasMotion && ev.type != MotionNotify) {
649             HasMotion = 0;
650             HandleMotionNotify (dpy, win, gc, &mev);
651         }
652 #endif
653 #ifdef COMPRESS_EXPOSE
654         if (HasExpose && ev.type != Expose) {
655             HasExpose = 0;
656             HandleExpose (dpy, eev.xexpose.window, gc);
657         }
658 #endif
659         switch (ev.type) {
660         case Expose:
661 #ifdef COMPRESS_EXPOSE
662             if (QLength(dpy)) {
663                 eev = ev;
664                 HasExpose = 1;
665             } else if (ev.xexpose.count == 0)
666 #endif
667             
668             HandleExpose (dpy, ev.xexpose.window, gc);
669             break;
670 #ifdef PASS_KEYS
671         case KeyPress:
672             HandleKeyPress (dpy, ev.xkey.window, gc, &ev);
673             break;
674         case KeyRelease:
675             HandleKeyRelease (dpy, ev.xkey.window, gc, &ev);
676             break;
677 #else
678         case KeyPress:
679             if (XLookupString ((XKeyEvent *) &ev, quit_string, sizeof (quit_string), 0, 0) == 1) {
680                 switch (quit_string[0]) {
681                 case 'q':
682                     exit (0);
683                 case 'c':
684                     XClearArea (dpy, ev.xkey.window, 0, 0, 0, 0, True);
685                     break;
686                 }
687             }
688             break;
689 #endif
690 #ifdef PASS_BUTTONS
691         case ButtonPress:
692             HandleButtonPress (dpy, ev.xbutton.window, gc, &ev);
693             break;
694         case ButtonRelease:
695             HandleButtonRelease (dpy, ev.xbutton.window, gc, &ev);
696             break;
697         case MotionNotify:
698             if (QLength(dpy)) {
699                 mev = ev;
700                 HasMotion = 1;
701             } else {
702                 HandleMotionNotify (dpy, ev.xmotion.window, gc, &ev);
703             }
704             break;
705 #endif
706         case ClientMessage:
707             exit (0);
708 #ifdef PASS_OTHER
709         default:
710             HandleOtherEvent (dpy, win, gc, &ev);
711 #endif
712         }
713     }
714 }
715
716 #include <X11/extensions/Xrender.h>
717
718 XRenderColor    renderBlack = { 0, 0, 0, 0xffff };
719 XRenderColor    renderWhite = { 0xffff, 0xffff, 0xffff, 0xffff };
720 XRenderColor    renderRed = { 0xffff, 0, 0, 0xffff };
721 XRenderColor    renderGreen = { 0, 0xffff, 0, 0xffff };
722 XRenderColor    renderBlue = { 0, 0, 0xffff, 0xffff };
723
724 XRenderColor    renderClearRed = { 0x8000, 0, 0, 0x8000 };
725 XRenderColor    renderClearGreen = { 0, 0x8000, 0, 0x8000 };
726 XRenderColor    renderClearBlue = { 0, 0, 0x8000, 0x8000 };
727
728 Picture
729 GetPicture (Display *dpy, Window w)
730 {
731     static Picture p;
732
733     if (!p)
734         p = XRenderCreatePicture (dpy, w, 
735                                   XRenderFindVisualFormat (dpy, visual),
736                                   0, 0);
737     return p;
738 }
739
740 Picture
741 GetSrc (Display *dpy, XRenderColor *color)
742 {
743     static Picture      p;
744     static Pixmap       pix;
745     static XRenderColor lastColor;
746     XRenderPictFormat   *f;
747     XRenderPictureAttributes    attr;
748
749     if (p && !memcmp (color, &lastColor, sizeof (XRenderColor)))
750         return p;
751     if (!p)
752     {
753         f = XRenderFindStandardFormat (dpy, PictStandardARGB32);
754         pix = XCreatePixmap (dpy, RootWindow (dpy, DefaultScreen (dpy)),
755                              1, 1, f->depth);
756         attr.repeat = True;
757         p = XRenderCreatePicture (dpy, pix, f, CPRepeat, &attr);
758         XFreePixmap (dpy, pix);
759     }
760     XRenderFillRectangle (dpy, PictOpSrc, p, color, 0, 0, 1, 1);
761     lastColor = *color;
762     return p;
763 }
764
765 XRenderPictFormat *
766 GetMask (Display *dpy)
767 {
768     return XRenderFindStandardFormat (dpy, PictStandardA8);
769 }