5e78d03548ac6367e037ee9498de9d7009f301d9
[framework/graphics/cairo.git] / doc / tutorial / src / include / cairo-tutorial-xlib.h
1 /* cairo-tutorial-xlib.h - a tutorial framework for cairo with xlib
2  *
3  * Copyright © 2005, Keith Packard
4  *
5  * This program is free software; you can redistribute it and/or modify
6  * it under the terms of the GNU General Public License version 2 as
7  * published by the Free Software Foundation.
8  *
9  * This program is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12  * GNU General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License
15  * along with this program; if not, write to the Free Software Foundation,
16  * Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA.
17  */
18
19 #include    <stdio.h>
20 #include    <stdlib.h>
21 #include    <ctype.h>
22 #include    <strings.h>
23 #include    <X11/Xos.h>
24 #include    <X11/Xlib.h>
25 #include    <X11/Xutil.h>
26 #include    <X11/Xatom.h>
27 #include    <cairo.h>
28 #include    <cairo-xlib.h>
29
30 #ifndef WIDTH
31 #define WIDTH 400
32 #endif
33
34 #ifndef HEIGHT
35 #define HEIGHT 400
36 #endif
37
38 #ifndef DEFAULT_VISUAL
39 #define DEFAULT_VISUAL 0
40 #endif
41
42 static void
43 Usage (char *program)
44 {
45     fprintf (stderr, "Usage: %s\n", program);
46     fprintf (stderr, "\t-display <display-name>\n");
47     fprintf (stderr, "\t-geometry <geometry>\n");
48     exit (1);
49 }
50
51 char        *dpy_name;
52 VisualID    vid = DEFAULT_VISUAL;
53 Colormap    colormap;
54 Visual      *visual;
55 int         depth;
56 unsigned int width = WIDTH, height = HEIGHT;
57 Window      win;
58 Pixmap      pix;
59 GC          gc;
60
61 static void
62 draw (cairo_t *cr, int width, int height);
63
64 static void
65 draw_to_pixmap (Display *dpy, Pixmap pix)
66 {
67     cairo_surface_t *surface;
68     cairo_t *cr;
69
70     surface = cairo_xlib_surface_create (dpy, pix, visual,
71                                          width, height);
72     cr = cairo_create (surface);
73
74     draw (cr, width, height);
75
76     cairo_destroy (cr);
77     cairo_surface_destroy (surface);
78 }
79
80 static void
81 handle_configure (Display *dpy, XConfigureEvent *cev)
82 {
83     width = cev->width;
84     height = cev->height;
85
86     XFreePixmap(dpy, pix);
87     pix = XCreatePixmap(dpy, win, width, height, depth);
88     XFillRectangle(dpy, pix, gc, 0, 0, width, height);
89     draw_to_pixmap (dpy, pix);
90 }
91
92 static void
93 handle_expose (Display *dpy, XExposeEvent *eev)
94 {
95     XCopyArea (dpy, pix, win, gc,
96                eev->x, eev->y,
97                eev->width, eev->height,
98                eev->x, eev->y);
99 }
100
101 int
102 main (argc, argv)
103     int     argc;
104     char    **argv;
105 {
106     Display *dpy;
107     Window  root = 0;
108     char    **init_argv = argv;
109     XSetWindowAttributes    attr;
110     int     scr;
111     int     x = 0, y = 0;
112     int     geometryMask;
113     int     border_width = 1;
114     XSizeHints  sizeHints;
115     XWMHints    wmHints;
116     XClassHint  classHints;
117     XEvent      ev;
118     XEvent      eev;
119     int         HasExpose = 0;
120     int         sync = 0;
121     XTextProperty   wm_name, icon_name;
122     Atom        wm_delete_window;
123     unsigned long   gc_mask;
124     XGCValues       gcv;
125     char        quit_string[10];
126     unsigned long   window_mask;
127     int         has_colormap = 0;
128
129     wm_name.value = (unsigned char *) argv[0];
130     wm_name.encoding = XA_STRING;
131     wm_name.format = 8;
132     wm_name.nitems = strlen (argv[0]) + 1;
133     icon_name = wm_name;
134     gc_mask = 0;
135     while (*++argv) {
136         if (!strcmp (*argv, "-display"))
137             dpy_name = *++argv;
138         else if (!strcmp (*argv, "-visual"))
139             vid = strtol(*++argv, NULL, 0);
140         else if (!strcmp (*argv, "-geometry"))
141             geometryMask = XParseGeometry (*++argv, &x, &y, &width, &height);
142         else if (!strcmp (*argv, "-sync"))
143             sync = 1;
144         else if (!strcmp (*argv, "-bw"))
145             border_width = strtol(*++argv, NULL, 0);
146         else if (!strcmp (*argv, "-root"))
147             root = strtol (*++argv, NULL, 0);
148         else
149             Usage (*init_argv);
150     }
151     sizeHints.flags = 0;
152     wmHints.flags = InputHint;
153     wmHints.input = True;
154     classHints.res_name = init_argv[0];
155     classHints.res_class = init_argv[0];
156     dpy = XOpenDisplay (dpy_name);
157     if (!dpy) {
158         fprintf (stderr, "Error: failed to open display: %s\n",
159                  XDisplayName (dpy_name));
160         exit (1);
161     }
162     if (sync)
163         XSynchronize (dpy, sync);
164     scr = DefaultScreen (dpy);
165     if (!root)
166         root = RootWindow (dpy, scr);
167     window_mask = CWBackPixel|CWBorderPixel|CWEventMask;
168     if (!has_colormap)
169         colormap = DefaultColormap (dpy, scr);
170     else
171     {
172         window_mask |= CWColormap;
173         attr.colormap = colormap;
174     }
175     visual = DefaultVisual (dpy, scr);
176     depth = DefaultDepth (dpy, scr);
177     if (vid)
178     {
179         XVisualInfo vi, *vi_ret;
180         int         n;
181
182         vi.visualid = vid;
183         vi.screen = scr;
184         vi_ret = XGetVisualInfo (dpy, VisualIDMask|VisualScreenMask,
185                                  &vi, &n);
186         if (vi_ret)
187         {
188             visual = vi_ret->visual;
189             if (!has_colormap)
190             {
191                 colormap = XCreateColormap (dpy, root, visual, AllocNone);
192                 window_mask |= CWColormap;
193                 attr.colormap = colormap;
194             }
195             depth = vi_ret->depth;
196         }
197     }
198     attr.background_pixel = WhitePixel (dpy, scr);
199     attr.border_pixel = 0;
200     attr.event_mask = ExposureMask|KeyPressMask|KeyReleaseMask|StructureNotifyMask;
201     wm_delete_window = XInternAtom(dpy, "WM_DELETE_WINDOW", False);
202     win = XCreateWindow (dpy, root, x, y, width, height, border_width,
203                          depth, InputOutput,
204                          visual,
205                          window_mask,
206                          &attr);
207     pix = XCreatePixmap (dpy, win, width, height, depth);
208     gcv.foreground = WhitePixel (dpy, scr);
209     gc = XCreateGC (dpy, pix, GCForeground, &gcv);
210     XFillRectangle(dpy, pix, gc, 0, 0, width, height);
211     draw_to_pixmap (dpy, pix);
212     XSetWMProperties (dpy, win,
213                       &wm_name, &icon_name,
214                       init_argv, argc,
215                       &sizeHints, &wmHints, 0);
216     XSetWMProtocols (dpy, win, &wm_delete_window, 1);
217     XMapWindow (dpy, win);
218     for (;;) {
219         XNextEvent (dpy, &ev);
220         if (HasExpose && ev.type != Expose) {
221             HasExpose = 0;
222             handle_expose (dpy, &eev.xexpose);
223         }
224         switch (ev.type) {
225         case ConfigureNotify:
226             handle_configure (dpy, &ev.xconfigure);
227             break;
228         case Expose:
229             if (QLength(dpy)) {
230                 eev = ev;
231                 HasExpose = 1;
232             } else if (ev.xexpose.count == 0) {
233                 handle_expose (dpy, &ev.xexpose);
234             }
235             break;
236         case KeyPress:
237             if (XLookupString ((XKeyEvent *) &ev, quit_string, sizeof (quit_string), 0, 0) == 1) {
238                 switch (quit_string[0]) {
239                 case 'q':
240                     exit (0);
241                 case 'c':
242                     XClearArea (dpy, ev.xkey.window, 0, 0, 0, 0, True);
243                     break;
244                 }
245             }
246             break;
247         case ClientMessage:
248             exit (0);
249         }
250     }
251 }