altos: Fill in more of the draw code
[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 int
375 main (argc, argv)
376     int     argc;
377     char    **argv;
378 {
379     Display *dpy;
380     Window  win;
381     GC      gc;
382     char    **init_argv = argv;
383     XSetWindowAttributes    attr;
384     XColor  hard, exact;
385     int     x = 0, y = 0;
386     unsigned int    width = DEFAULT_WIDTH, height = DEFAULT_HEIGHT;
387     int     geometryMask;
388     int     border_width = 1;
389     XSizeHints  sizeHints;
390     XWMHints    wmHints;
391     XClassHint  classHints;
392     XEvent      ev, mev;
393     XGCValues   gcv;
394 #ifdef MATCH_ARGUMENT
395     int         i;
396 #endif
397     int         HasMotion = 0;
398 #ifdef COMPRESS_EXPOSE
399     XEvent      eev;
400     int         HasExpose = 0;
401 #endif
402     int         sync = 0;
403     XTextProperty   wm_name, icon_name;
404     Atom        wm_delete_window;
405     int         has_fg_pixel = 0, has_bg_pixel = 0;
406     int         has_colormap = 0;
407     unsigned long   gc_mask;
408     char        quit_string[10];
409     unsigned long   window_mask;
410
411     if (!rop_name)
412         rop_name = DEFAULT_ROP;
413     wm_name.value = (unsigned char *) argv[0];
414     wm_name.encoding = XA_STRING;
415     wm_name.format = 8;
416     wm_name.nitems = strlen (wm_name.value) + 1;
417     icon_name = wm_name;
418     gc_mask = 0;
419     while (*++argv) {
420         if (!strcmp (*argv, "-display"))
421             dpy_name = *++argv;
422         else if (!strcmp (*argv, "-visual"))
423             vid = strtol(*++argv, NULL, 0);
424         else if (!strcmp (*argv, "-cmap"))
425         {
426             colormap = strtol(*++argv, NULL, 0);
427             has_colormap = 1;
428         }
429         else if (!strcmp (*argv, "-rop"))
430             rop_name = *++argv;
431         else if (!strcmp (*argv, "-fg"))
432             fg = *++argv;
433         else if (!strcmp (*argv, "-bg"))
434             bg = *++argv;
435         else if (!strcmp (*argv, "-fg_pixel"))
436         {
437             fg_pixel = strtol(*++argv, NULL, 0);
438             has_fg_pixel = 1;
439         }
440         else if (!strcmp (*argv, "-bg_pixel"))
441         {
442             bg_pixel = strtol(*++argv, NULL, 0);
443             has_bg_pixel = 1;
444         }
445         else if (!strcmp (*argv, "-fn"))
446             font_name = *++argv;
447         else if (!strcmp (*argv, "-pm"))
448             planemask = strtol(*++argv, NULL, 0);
449         else if (!strcmp (*argv, "-geometry"))
450             geometryMask = XParseGeometry (*++argv, &x, &y, &width, &height);
451         else if (!strcmp (*argv, "-sync"))
452             sync = 1;
453         else if (!strcmp (*argv, "-bw"))
454             border_width = strtol(*++argv, NULL, 0);
455         else if (!strcmp (*argv, "-lw"))
456             line_width = strtod(*++argv, NULL);
457         else if (!strcmp (*argv, "-cap"))
458             cap_name = *++argv;
459         else if (!strcmp (*argv, "-join"))
460             join_name = *++argv;
461         else if (!strcmp (*argv, "-fill"))
462             fill_name = *++argv;
463         else if (!strcmp (*argv, "-linestyle"))
464             line_name = *++argv;
465         else if (!strcmp (*argv, "-bitmap"))
466             bitmap_file = *++argv;
467         else if (!strcmp (*argv, "-dashes"))
468         {
469             argv++;
470             ndashes = 0;
471             while (*argv && isdigit (**argv))
472                 dashes[ndashes++] = atoi(*argv++);
473             argv--;
474         }
475 #ifdef MATCH_ARGUMENT
476         else if (i = MatchArgument (argv))
477             argv += i - 1;
478 #endif
479         else if (!strcmp (*argv, "-root"))
480             root = strtol (*++argv, NULL, 0);
481         else
482             Usage (*init_argv);
483     }
484     sizeHints.flags = 0;
485     wmHints.flags = InputHint;
486     wmHints.input = True;
487     classHints.res_name = init_argv[0];
488     classHints.res_class = init_argv[0];
489     dpy = XOpenDisplay (dpy_name);
490     if (!dpy)
491         Error ("Can't open display", "");
492     if (sync)
493         XSynchronize (dpy, sync);
494     screen = DefaultScreen (dpy);
495     if (!root)
496         root = RootWindow (dpy, screen);
497     window_mask = CWBackPixel|CWBorderPixel|CWEventMask;
498     if (!has_colormap)
499         colormap = DefaultColormap (dpy, screen);
500     else
501     {
502         window_mask |= CWColormap;
503         attr.colormap = colormap;
504     }
505     visual = DefaultVisual (dpy, screen);
506     depth = DefaultDepth (dpy, screen);
507     if (vid)
508     {
509         XVisualInfo vi, *vi_ret;
510         int         n;
511
512         vi.visualid = vid;
513         vi.screen = screen;
514         vi_ret = XGetVisualInfo (dpy, VisualIDMask|VisualScreenMask,
515                                  &vi, &n);
516         if (vi_ret)
517         {
518             visual = vi_ret->visual;
519             if (!has_colormap)
520             {
521                 colormap = XCreateColormap (dpy, root, visual, AllocNone);
522                 window_mask |= CWColormap;
523                 attr.colormap = colormap;
524             }
525             depth = vi_ret->depth;
526         }
527     }
528     if (!has_fg_pixel)
529         fg_pixel = BlackPixel (dpy, screen);
530     if (!has_bg_pixel)
531         bg_pixel = WhitePixel (dpy, screen);
532     if (fg)
533     {
534         if (!XAllocNamedColor (dpy, colormap, fg, &hard, &exact))
535             Error ("Can't allocate fg pixel %s", fg);
536         fg_pixel = hard.pixel;
537     }
538     if (bg)
539     {
540         if (!XAllocNamedColor (dpy, colormap, bg, &hard, &exact))
541             Error ("Can't allocate bg pixel %s", bg);
542         bg_pixel = hard.pixel;
543     }
544     attr.background_pixel = bg_pixel;
545     attr.border_pixel = fg_pixel;
546     attr.event_mask =
547         ExposureMask|KeyPressMask|KeyReleaseMask|ButtonPressMask|ButtonReleaseMask|MOTION|EXTRA_EVENTS;
548 //    attr.override_redirect = True;
549 //    window_mask |= CWOverrideRedirect;
550     wm_delete_window = XInternAtom(dpy, "WM_DELETE_WINDOW", False);
551     win = XCreateWindow (dpy, root, x, y, width, height, border_width,
552                          depth, InputOutput,
553                          visual,
554                          window_mask,
555                          &attr);
556 #ifdef PASS_SETUP
557     Setup (dpy, win);
558 #endif
559     XSetWMProperties (dpy, win,
560                       &wm_name, &icon_name,
561                       init_argv, argc,
562                       &sizeHints, &wmHints, 0);
563     XSetWMProtocols (dpy, win, &wm_delete_window, 1);
564     default_rop =  RopNameToRop (rop_name);
565     if (line_width) 
566     {
567         gcv.line_width = (int) line_width;
568         gc_mask |= GCLineWidth;
569     }
570     if (cap_name)
571     {
572         gcv.cap_style = MatchCapStyle (cap_name);
573         gc_mask |= GCCapStyle;
574     }
575     if (fill_name) {
576         gcv.fill_style = MatchFillStyle (fill_name);
577         gc_mask |= GCFillStyle;
578     }   
579     if (line_name) {
580         gcv.line_style = MatchLineStyle (line_name);
581         gc_mask |= GCLineStyle;
582     }
583     if (join_name) {
584         gcv.join_style = MatchJoinStyle (join_name);
585         gc_mask |= GCJoinStyle;
586     }
587     if (font_name)
588         default_font = XLoadQueryFont (dpy, font_name);
589     if (default_font) {
590         gcv.font = default_font->fid;
591         gc_mask |= GCFont;
592     }
593     gcv.function = default_rop;
594     gcv.foreground = fg_pixel;
595     gcv.background = bg_pixel;
596     gcv.plane_mask = planemask;
597     gc_mask |= GCFunction|GCForeground|GCBackground|GCPlaneMask;
598     if (bitmap_file)
599     {
600         unsigned int    width, height;
601         int             ret;
602         Pixmap          bitmap, pixmap;
603
604         ret = XReadBitmapFile (dpy, win, bitmap_file, &width, &height,
605                                &bitmap, (int *) 0, (int *) 0);
606         switch (ret) {
607         case BitmapOpenFailed:
608             Error ("Can't open bitmap file %s", bitmap_file);
609         case BitmapFileInvalid:
610             Error ("Bitmap file %s invalid", bitmap_file);
611         case BitmapNoMemory:
612             Error ("Out of memory reading bitmap file %s", bitmap_file);
613         case BitmapSuccess:
614             break;
615         }
616         switch (gcv.fill_style) {
617         case FillTiled:
618             pixmap = XCreatePixmap (dpy, win, width, height, DefaultDepth (dpy, screen));
619             gc = XCreateGC (dpy, pixmap, GCForeground|GCBackground, &gcv);
620             XCopyPlane (dpy, bitmap, pixmap, gc, 0, 0, width, height, 0, 0, 1);
621             XFreeGC (dpy, gc);
622             XFreePixmap (dpy, bitmap);
623             gcv.tile = pixmap;
624             gc_mask |= GCTile;
625             break;
626         case FillStippled:
627         case FillOpaqueStippled:
628             gcv.stipple = bitmap;
629             gc_mask |= GCStipple;
630             break;
631         }
632     }
633     gc = XCreateGC (dpy, win, gc_mask, &gcv);
634     if (!default_font)
635         default_font = XQueryFont (dpy, XGContextFromGC(gc));
636     if (ndashes)
637         XSetDashes (dpy, gc, 0, dashes, ndashes);
638     XMapWindow (dpy, win);
639     for (;;) {
640         XNextEvent (dpy, &ev);
641 #ifdef PASS_BUTTONS
642         if (HasMotion && ev.type != MotionNotify) {
643             HasMotion = 0;
644             HandleMotionNotify (dpy, win, gc, &mev);
645         }
646 #endif
647 #ifdef COMPRESS_EXPOSE
648         if (HasExpose && ev.type != Expose) {
649             HasExpose = 0;
650             HandleExpose (dpy, eev.xexpose.window, gc);
651         }
652 #endif
653         switch (ev.type) {
654         case Expose:
655 #ifdef COMPRESS_EXPOSE
656             if (QLength(dpy)) {
657                 eev = ev;
658                 HasExpose = 1;
659             } else if (ev.xexpose.count == 0)
660 #endif
661             
662             HandleExpose (dpy, ev.xexpose.window, gc);
663             break;
664 #ifdef PASS_KEYS
665         case KeyPress:
666             HandleKeyPress (dpy, ev.xkey.window, gc, &ev);
667             break;
668         case KeyRelease:
669             HandleKeyRelease (dpy, ev.xkey.window, gc, &ev);
670             break;
671 #else
672         case KeyPress:
673             if (XLookupString ((XKeyEvent *) &ev, quit_string, sizeof (quit_string), 0, 0) == 1) {
674                 switch (quit_string[0]) {
675                 case 'q':
676                     exit (0);
677                 case 'c':
678                     XClearArea (dpy, ev.xkey.window, 0, 0, 0, 0, True);
679                     break;
680                 }
681             }
682             break;
683 #endif
684 #ifdef PASS_BUTTONS
685         case ButtonPress:
686             HandleButtonPress (dpy, ev.xbutton.window, gc, &ev);
687             break;
688         case ButtonRelease:
689             HandleButtonRelease (dpy, ev.xbutton.window, gc, &ev);
690             break;
691         case MotionNotify:
692             if (QLength(dpy)) {
693                 mev = ev;
694                 HasMotion = 1;
695             } else {
696                 HandleMotionNotify (dpy, ev.xmotion.window, gc, &ev);
697             }
698             break;
699 #endif
700         case ClientMessage:
701             exit (0);
702 #ifdef PASS_OTHER
703         default:
704             HandleOtherEvent (dpy, win, gc, &ev);
705 #endif
706         }
707     }
708 }
709
710 #include <X11/extensions/Xrender.h>
711
712 XRenderColor    renderBlack = { 0, 0, 0, 0xffff };
713 XRenderColor    renderWhite = { 0xffff, 0xffff, 0xffff, 0xffff };
714 XRenderColor    renderRed = { 0xffff, 0, 0, 0xffff };
715 XRenderColor    renderGreen = { 0, 0xffff, 0, 0xffff };
716 XRenderColor    renderBlue = { 0, 0, 0xffff, 0xffff };
717
718 XRenderColor    renderClearRed = { 0x8000, 0, 0, 0x8000 };
719 XRenderColor    renderClearGreen = { 0, 0x8000, 0, 0x8000 };
720 XRenderColor    renderClearBlue = { 0, 0, 0x8000, 0x8000 };
721
722 Picture
723 GetPicture (Display *dpy, Window w)
724 {
725     static Picture p;
726
727     if (!p)
728         p = XRenderCreatePicture (dpy, w, 
729                                   XRenderFindVisualFormat (dpy, visual),
730                                   0, 0);
731     return p;
732 }
733
734 Picture
735 GetSrc (Display *dpy, XRenderColor *color)
736 {
737     static Picture      p;
738     static Pixmap       pix;
739     static XRenderColor lastColor;
740     XRenderPictFormat   *f;
741     XRenderPictureAttributes    attr;
742
743     if (p && !memcmp (color, &lastColor, sizeof (XRenderColor)))
744         return p;
745     if (!p)
746     {
747         f = XRenderFindStandardFormat (dpy, PictStandardARGB32);
748         pix = XCreatePixmap (dpy, RootWindow (dpy, DefaultScreen (dpy)),
749                              1, 1, f->depth);
750         attr.repeat = True;
751         p = XRenderCreatePicture (dpy, pix, f, CPRepeat, &attr);
752         XFreePixmap (dpy, pix);
753     }
754     XRenderFillRectangle (dpy, PictOpSrc, p, color, 0, 0, 1, 1);
755     lastColor = *color;
756     return p;
757 }
758
759 XRenderPictFormat *
760 GetMask (Display *dpy)
761 {
762     return XRenderFindStandardFormat (dpy, PictStandardA8);
763 }