Deprecate XCBSync, move to XCBAuxSync.
[free-sw/xcb/demo] / hypnomoire.c
1 /*
2  * Copyright (C) 2001-2002 Bart Massey and Jamey Sharp.
3  * All Rights Reserved.  See the file COPYING in this directory
4  * for licensing information.
5  */
6
7 #include <X11/XCB/xcb.h>
8 #include <X11/XCB/xcb_aux.h>
9 #include "reply_formats.h"
10 #include <math.h>
11 #include <stdlib.h> /* for free(3) */
12 #include <unistd.h> /* for usleep(3) */
13 #include <stdio.h>
14 #include <pthread.h>
15
16 #define LAG 0.3 /* lag angle for the follow line */
17
18 /* If I've done my math right, Linux maxes out at 100 fps on Intel (1000 fps
19  * on Alpha) due to the granularity of the kernel timer. */
20 #define FRAME_RATE 10.0 /* frames per second */
21
22 #define PI 3.14159265
23
24 static XCBConnection *c;
25 static XCBSCREEN *root;
26 static XCBGCONTEXT white, black;
27 static int depth;
28
29 #define WINS 8
30 static struct {
31         XCBDRAWABLE w;
32         XCBDRAWABLE p;
33         CARD16 width;
34         CARD16 height;
35         float angv;
36 } windows[WINS];
37
38 void *run(void *param);
39 void *event_thread(void *param);
40
41 static void get_depth()
42 {
43         XCBDRAWABLE drawable = { root->root };
44         XCBGetGeometryRep *geom;
45         geom = XCBGetGeometryReply(c, XCBGetGeometry(c, drawable), 0);
46         if(!geom)
47         {
48                 perror("GetGeometry(root) failed");
49                 abort();
50         }
51
52         depth = geom->depth;
53         fprintf(stderr, "Root 0x%x: %dx%dx%d\n",
54                 root->root.xid, geom->width, geom->height, geom->depth);
55         free(geom);
56 }
57
58 int main()
59 {
60         pthread_t thr;
61         int i;
62
63         CARD32 mask = XCBGCForeground | XCBGCGraphicsExposures;
64         CARD32 values[2];
65         XCBDRAWABLE rootwin;
66         int screen_num;
67
68         c = XCBConnect(0, &screen_num);
69         root = XCBAuxGetScreen(c, screen_num);
70         get_depth();
71
72         rootwin.window = root->root;
73         white = XCBGCONTEXTNew(c);
74         black = XCBGCONTEXTNew(c);
75
76         pthread_create(&thr, 0, event_thread, 0);
77
78         values[1] = 0; /* no graphics exposures */
79
80         values[0] = root->white_pixel;
81         XCBCreateGC(c, white, rootwin, mask, values);
82
83         values[0] = root->black_pixel;
84         XCBCreateGC(c, black, rootwin, mask, values);
85
86         for(i = 1; i < WINS; ++i)
87                 pthread_create(&thr, 0, run, (void*)i);
88         run((void*)0);
89
90         exit(0);
91         /*NOTREACHED*/
92 }
93
94 void paint(int idx)
95 {
96         XCBCopyArea(c, windows[idx].p, windows[idx].w, white, 0, 0, 0, 0,
97                 windows[idx].width, windows[idx].height);
98         /* TODO: better error detection for broken pipe */
99         if(!XCBSync(c, 0))
100         {
101                 perror("XCBSync failed");
102                 abort();
103         }
104 }
105
106 void *run(void *param)
107 {
108         int idx = (int)param;
109
110         int xo, yo;
111         double r, theta = 0;
112
113         XCBPOINT line[2];
114
115         windows[idx].w.window = XCBWINDOWNew(c);
116         windows[idx].p.pixmap = XCBPIXMAPNew(c);
117         windows[idx].width = 300;
118         line[0].x = xo = windows[idx].width / 2;
119         windows[idx].height = 300;
120         line[0].y = yo = windows[idx].height / 2;
121         windows[idx].angv = 0.05;
122
123         {
124                 int ws = windows[idx].width * windows[idx].width;
125                 int hs = windows[idx].height * windows[idx].height;
126                 r = sqrt(ws + hs) + 1.0;
127         }
128
129         {
130                 CARD32 mask = XCBCWBackPixel | XCBCWEventMask | XCBCWDontPropagate;
131                 CARD32 values[3];
132                 XCBRECTANGLE rect = { 0, 0, windows[idx].width, windows[idx].height };
133                 values[0] = root->white_pixel;
134                 values[1] = XCBEventMaskButtonRelease | XCBEventMaskExposure;
135                 values[2] = XCBEventMaskButtonPress;
136
137                 XCBCreateWindow(c, depth, windows[idx].w.window, root->root,
138                         /* x */ 0, /* y */ 0,
139                         windows[idx].width, windows[idx].height,
140                         /* border */ 0, XCBWindowClassInputOutput,
141                         /* visual */ root->root_visual,
142                         mask, values);
143
144                 XCBMapWindow(c, windows[idx].w.window);
145
146                 XCBCreatePixmap(c, depth,
147                         windows[idx].p.pixmap, windows[idx].w,
148                         windows[idx].width, windows[idx].height);
149
150                 XCBPolyFillRectangle(c, windows[idx].p, white, 1, &rect);
151         }
152
153         XCBFlush(c);
154
155         while(1)
156         {
157                 line[1].x = xo + r * cos(theta);
158                 line[1].y = yo + r * sin(theta);
159                 XCBPolyLine(c, XCBCoordModeOrigin, windows[idx].p, black,
160                         2, line);
161
162                 line[1].x = xo + r * cos(theta + LAG);
163                 line[1].y = yo + r * sin(theta + LAG);
164                 XCBPolyLine(c, XCBCoordModeOrigin, windows[idx].p, white,
165                         2, line);
166
167                 paint(idx);
168                 theta += windows[idx].angv;
169                 while(theta > 2 * PI)
170                         theta -= 2 * PI;
171                 while(theta < 0)
172                         theta += 2 * PI;
173
174                 usleep(1000000 / FRAME_RATE);
175         }
176
177         return 0;
178 }
179
180 int lookup_window(XCBWINDOW w)
181 {
182         int i;
183         for(i = 0; i < WINS; ++i)
184                 if(windows[i].w.window.xid == w.xid)
185                         return i;
186         return -1;
187 }
188
189 void *event_thread(void *param)
190 {
191         XCBGenericEvent *e;
192         int idx;
193
194         while(1)
195         {
196                 e = XCBWaitForEvent(c);
197                 if(!formatEvent(e))
198                         return 0;
199                 if(e->response_type == XCBExpose)
200                 {
201                         XCBExposeEvent *ee = (XCBExposeEvent *) e;
202                         idx = lookup_window(ee->window);
203                         if(idx == -1)
204                                 fprintf(stderr, "Expose on unknown window!\n");
205                         else
206                         {
207                                 XCBCopyArea(c, windows[idx].p, windows[idx].w,
208                                         white, ee->x, ee->y, ee->x, ee->y,
209                                         ee->width, ee->height);
210                                 if(ee->count == 0)
211                                         XCBFlush(c);
212                         }
213                 }
214                 else if(e->response_type == XCBButtonRelease)
215                 {
216                         XCBButtonReleaseEvent *bre = (XCBButtonReleaseEvent *) e;
217                         idx = lookup_window(bre->event);
218                         if(idx == -1)
219                                 fprintf(stderr, "ButtonRelease on unknown window!\n");
220                         else
221                         {
222                                 if(bre->detail.id == XCBButton1)
223                                         windows[idx].angv = -windows[idx].angv;
224                                 else if(bre->detail.id == XCBButton4)
225                                         windows[idx].angv += 0.001;
226                                 else if(bre->detail.id == XCBButton5)
227                                         windows[idx].angv -= 0.001;
228                         }
229                 }
230                 free(e);
231         }
232 }