Initial revision
[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
27                 fill_checks (cairo_t *cr,
28                              int x,     int y,
29                              int width, int height)
30 {
31         cairo_surface_t *check;
32         cairo_pattern_t *check_pattern;
33     
34         cairo_save (cr);
35
36 #define CHECK_SIZE 32
37
38     check = cairo_surface_create_similar (cairo_current_target_surface (cr),
39                                           CAIRO_FORMAT_RGB24,
40                                           2 * CHECK_SIZE, 2 * CHECK_SIZE);
41     cairo_surface_set_repeat (check, 1);
42
43     /* Draw the check */
44     {
45             cairo_save (cr);
46
47             cairo_set_target_surface (cr, check);
48
49             cairo_set_operator (cr, CAIRO_OPERATOR_SRC);
50
51             cairo_set_rgb_color (cr, 0.4, 0.4, 0.4);
52
53             cairo_rectangle (cr, 0, 0, 2 * CHECK_SIZE, 2 * CHECK_SIZE);
54             cairo_fill (cr);
55
56             cairo_set_rgb_color (cr, 0.7, 0.7, 0.7);
57
58             cairo_rectangle (cr, x, y, CHECK_SIZE, CHECK_SIZE);
59             cairo_fill (cr);
60             cairo_rectangle (cr, x + CHECK_SIZE, y + CHECK_SIZE, CHECK_SIZE, CHECK_SIZE);
61             cairo_fill (cr);
62
63             cairo_restore (cr);
64     }
65
66     /* Fill the whole surface with the check */
67
68     check_pattern = cairo_pattern_create_for_surface (check);
69     cairo_set_pattern (cr, check_pattern);
70     cairo_rectangle (cr, 0, 0, width, height);
71     cairo_fill (cr);
72
73     cairo_pattern_destroy (check_pattern);
74     cairo_surface_destroy (check);
75
76     cairo_restore (cr);
77 }
78
79 static void draw_pee (cairo_t *cr, double xc, double yc)
80 {
81         cairo_set_rgb_color (cr, 0, 0, 0);
82         cairo_show_text (cr, "Conky");
83 }
84
85 static void
86                 draw (cairo_t *cr,
87                       int      width,
88                       int      height)
89 {
90         cairo_surface_t *overlay;
91
92         /* Fill the background */
93         double xc = width / 2.;
94         double yc = height / 2.;
95
96         overlay = cairo_surface_create_similar (cairo_current_target_surface (cr),
97                         CAIRO_FORMAT_ARGB32,
98                         width, height);
99         if (overlay == NULL)
100                 return;
101
102         fill_checks (cr, 0, 0, width, height);
103
104         cairo_save (cr);
105         cairo_set_target_surface (cr, overlay);
106
107         cairo_set_alpha (cr, 0.5);
108         cairo_set_operator (cr, CAIRO_OPERATOR_OVER);
109         draw_pee (cr, xc, yc);
110
111         cairo_restore (cr);
112
113         cairo_show_surface (cr, overlay, width, height);
114
115         cairo_surface_destroy (overlay);
116 }
117
118 int
119                 do_it (void)
120 {
121         Display *dpy;
122         int screen;
123         Window w;
124         Pixmap pixmap;
125         char *title = "cairo: Knockout Groups";
126         unsigned int quit_keycode;
127         int needs_redraw;
128         GC gc;
129         XWMHints *wmhints;
130         XSizeHints *normalhints;
131         XClassHint *classhint;
132   
133         int width = 400;
134         int height = 400;
135   
136         dpy = XOpenDisplay (NULL);
137         screen = DefaultScreen (dpy);
138
139         w = XCreateSimpleWindow (dpy, RootWindow (dpy, screen),
140                                  0, 0, width, height, 0,
141                                  BlackPixel (dpy, screen), WhitePixel (dpy, screen));
142
143         normalhints = XAllocSizeHints ();
144         normalhints->flags = 0;
145         normalhints->x = 0;
146         normalhints->y = 0;
147         normalhints->width = width;
148         normalhints->height = height;
149
150         classhint = XAllocClassHint ();
151         classhint->res_name = "cairo-knockout";
152         classhint->res_class = "Cairo-knockout";
153     
154         wmhints = XAllocWMHints ();
155         wmhints->flags = InputHint;
156         wmhints->input = True;
157     
158         XmbSetWMProperties (dpy, w, title, "cairo-knockout", 0, 0, 
159                             normalhints, wmhints, classhint);
160         XFree (wmhints);
161         XFree (classhint);
162         XFree (normalhints);
163
164         pixmap = XCreatePixmap (dpy, w, width, height, DefaultDepth (dpy, screen));
165         gc = XCreateGC (dpy, pixmap, 0, NULL);
166
167         quit_keycode = XKeysymToKeycode(dpy, XStringToKeysym("Q"));
168
169         XSelectInput (dpy, w, ExposureMask | StructureNotifyMask | ButtonPressMask | KeyPressMask);
170         XMapWindow (dpy, w);
171   
172         needs_redraw = 1;
173
174         while (1) {
175                 XEvent xev;
176
177       /* Only do the redraw if there are no events pending.  This
178                 * avoids us getting behind doing several redraws for several
179                 * consecutive resize events for example.
180       */
181                 if (!XPending (dpy) && needs_redraw) {
182                         cairo_t *cr = cairo_create ();
183
184                         cairo_set_target_drawable (cr, dpy, pixmap);
185
186                         draw (cr, width, height);
187
188                         cairo_destroy (cr);
189
190                         XCopyArea (dpy, pixmap, w, gc,
191                                    0, 0,
192                                    width, height,
193                                    0, 0);
194
195                         needs_redraw = 0;
196                 }
197       
198                 XNextEvent (dpy, &xev);
199
200                 switch (xev.xany.type) {
201                         case ButtonPress:
202                                 /* A click on the canvas ends the program */
203                                 goto DONE;
204                         case KeyPress:
205                                 if (xev.xkey.keycode == quit_keycode)
206                                         goto DONE;
207                                 break;
208                         case ConfigureNotify:
209                                 /* Note new size and create new pixmap. */
210                                 width = xev.xconfigure.width;
211                                 height = xev.xconfigure.height;
212                                 XFreePixmap (dpy, pixmap);
213                                 pixmap = XCreatePixmap (dpy, w, width, height, DefaultDepth (dpy, screen));
214                                 needs_redraw = 1;
215                                 break;
216                         case Expose:
217                                 XCopyArea (dpy, pixmap, w, gc,
218                                            xev.xexpose.x, xev.xexpose.y,
219                                            xev.xexpose.width, xev.xexpose.height,
220                                            xev.xexpose.x, xev.xexpose.y);
221                                 break;
222                 }
223         }
224   DONE:
225
226                   XFreeGC (dpy, gc);
227   XCloseDisplay (dpy);
228
229   return 0;
230 }