fixed garbled graph colours on systems using less then 24 bit colour depth
[monky] / cairo.c
1 /* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2
3 /* Small example demonstrating emulating knockout-groups as in PDF-1.4
4  * using cairo_set_operator().
5  *
6  * Owen Taylor,
7
8  * v0.1  30 November  2002
9  * v0.2   1 December  2002 - typo fixes from Keith Packard
10  * v0.3  17 April     2003 - Tracking changes in Xr, (Removal of Xr{Push,Pop}Group)
11  * v0.4  29 September 2003 - Use cairo_rectangle rather than private rect_path
12  *                           Use cairo_arc for oval_path
13  * Keeping log of changes in ChangeLog/CVS now. (2003-11-19) Carl Worth
14  */
15 #include "conky.h"
16 #include <X11/Xlib.h>
17 #include <X11/Xutil.h>
18 #include <cairo.h>
19 #include <cairo-xlib.h>
20 #include <math.h>
21 #include <stdio.h>
22
23 /* Fill the given area with checks in the standard style
24  * for showing compositing effects.
25  */
26 static void fill_checks(cairo_t * cr, int x, int y, int width, int height)
27 {
28         cairo_surface_t *check;
29         cairo_pattern_t *check_pattern;
30
31         cairo_save(cr);
32
33 #define CHECK_SIZE 32
34
35         check =
36             cairo_surface_create_similar(cairo_current_target_surface(cr),
37                                          CAIRO_FORMAT_RGB24,
38                                          2 * CHECK_SIZE, 2 * CHECK_SIZE);
39         cairo_surface_set_repeat(check, 1);
40
41         /* Draw the check */
42         {
43                 cairo_save(cr);
44
45                 cairo_set_target_surface(cr, check);
46
47                 cairo_set_operator(cr, CAIRO_OPERATOR_SRC);
48
49                 cairo_set_rgb_color(cr, 0.4, 0.4, 0.4);
50
51                 cairo_rectangle(cr, 0, 0, 2 * CHECK_SIZE, 2 * CHECK_SIZE);
52                 cairo_fill(cr);
53
54                 cairo_set_rgb_color(cr, 0.7, 0.7, 0.7);
55
56                 cairo_rectangle(cr, x, y, CHECK_SIZE, CHECK_SIZE);
57                 cairo_fill(cr);
58                 cairo_rectangle(cr, x + CHECK_SIZE, y + CHECK_SIZE,
59                                 CHECK_SIZE, CHECK_SIZE);
60                 cairo_fill(cr);
61
62                 cairo_restore(cr);
63         }
64
65         /* Fill the whole surface with the check */
66
67         check_pattern = cairo_pattern_create_for_surface(check);
68         cairo_set_pattern(cr, check_pattern);
69         cairo_rectangle(cr, 0, 0, width, height);
70         cairo_fill(cr);
71
72         cairo_pattern_destroy(check_pattern);
73         cairo_surface_destroy(check);
74
75         cairo_restore(cr);
76 }
77
78 static void draw_pee(cairo_t * cr, double xc, double yc)
79 {
80         cairo_set_rgb_color(cr, 0, 0, 0);
81         cairo_show_text(cr, "Conky");
82 }
83
84 static void draw(cairo_t * cr, int width, int height)
85 {
86         cairo_surface_t *overlay;
87
88         /* Fill the background */
89         double xc = width / 2.;
90         double yc = height / 2.;
91
92         overlay =
93             cairo_surface_create_similar(cairo_current_target_surface(cr),
94                                          CAIRO_FORMAT_ARGB32, width,
95                                          height);
96         if (overlay == NULL)
97                 return;
98
99         fill_checks(cr, 0, 0, width, height);
100
101         cairo_save(cr);
102         cairo_set_target_surface(cr, overlay);
103
104         cairo_set_alpha(cr, 0.5);
105         cairo_set_operator(cr, CAIRO_OPERATOR_OVER);
106         draw_pee(cr, xc, yc);
107
108         cairo_restore(cr);
109
110         cairo_show_surface(cr, overlay, width, height);
111
112         cairo_surface_destroy(overlay);
113 }
114
115 int do_it(void)
116 {
117         Display *dpy;
118         int screen;
119         Window w;
120         Pixmap pixmap;
121         char *title = "cairo: Knockout Groups";
122         unsigned int quit_keycode;
123         int needs_redraw;
124         GC gc;
125         XWMHints *wmhints;
126         XSizeHints *normalhints;
127         XClassHint *classhint;
128
129         int width = 400;
130         int height = 400;
131
132         dpy = XOpenDisplay(NULL);
133         screen = DefaultScreen(dpy);
134
135         w = XCreateSimpleWindow(dpy, RootWindow(dpy, screen),
136                                 0, 0, width, height, 0,
137                                 BlackPixel(dpy, screen), WhitePixel(dpy,
138                                                                     screen));
139
140         normalhints = XAllocSizeHints();
141         normalhints->flags = 0;
142         normalhints->x = 0;
143         normalhints->y = 0;
144         normalhints->width = width;
145         normalhints->height = height;
146
147         classhint = XAllocClassHint();
148         classhint->res_name = "cairo-knockout";
149         classhint->res_class = "Cairo-knockout";
150
151         wmhints = XAllocWMHints();
152         wmhints->flags = InputHint;
153         wmhints->input = True;
154
155         XmbSetWMProperties(dpy, w, title, "cairo-knockout", 0, 0,
156                            normalhints, wmhints, classhint);
157         XFree(wmhints);
158         XFree(classhint);
159         XFree(normalhints);
160
161         pixmap =
162             XCreatePixmap(dpy, w, width, height,
163                           DefaultDepth(dpy, screen));
164         gc = XCreateGC(dpy, pixmap, 0, NULL);
165
166         quit_keycode = XKeysymToKeycode(dpy, XStringToKeysym("Q"));
167
168         XSelectInput(dpy, w,
169                      ExposureMask | StructureNotifyMask | ButtonPressMask |
170                      KeyPressMask);
171         XMapWindow(dpy, w);
172
173         needs_redraw = 1;
174
175         while (1) {
176                 XEvent xev;
177
178                 /* Only do the redraw if there are no events pending.  This
179                  * avoids us getting behind doing several redraws for several
180                  * consecutive resize events for example.
181                  */
182                 if (!XPending(dpy) && needs_redraw) {
183                         cairo_t *cr = cairo_create();
184
185                         cairo_set_target_drawable(cr, dpy, pixmap);
186
187                         draw(cr, width, height);
188
189                         cairo_destroy(cr);
190
191                         XCopyArea(dpy, pixmap, w, gc,
192                                   0, 0, width, height, 0, 0);
193
194                         needs_redraw = 0;
195                 }
196
197                 XNextEvent(dpy, &xev);
198
199                 switch (xev.xany.type) {
200                 case ButtonPress:
201                         /* A click on the canvas ends the program */
202                         goto DONE;
203                 case KeyPress:
204                         if (xev.xkey.keycode == quit_keycode)
205                                 goto DONE;
206                         break;
207                 case ConfigureNotify:
208                         /* Note new size and create new pixmap. */
209                         width = xev.xconfigure.width;
210                         height = xev.xconfigure.height;
211                         XFreePixmap(dpy, pixmap);
212                         pixmap =
213                             XCreatePixmap(dpy, w, width, height,
214                                           DefaultDepth(dpy, screen));
215                         needs_redraw = 1;
216                         break;
217                 case Expose:
218                         XCopyArea(dpy, pixmap, w, gc,
219                                   xev.xexpose.x, xev.xexpose.y,
220                                   xev.xexpose.width, xev.xexpose.height,
221                                   xev.xexpose.x, xev.xexpose.y);
222                         break;
223                 }
224         }
225       DONE:
226
227         XFreeGC(dpy, gc);
228         XCloseDisplay(dpy);
229
230         return 0;
231 }