Fix typo in lissajoux: s/availaible/available/g.
[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%lx: %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         if(!XCBSync(c, 0))
99         {
100                 perror("XCBSync failed");
101                 abort();
102         }
103 }
104
105 void *run(void *param)
106 {
107         int idx = (int)param;
108
109         int xo, yo;
110         double r, theta = 0;
111
112         XCBPOINT line[2];
113
114         windows[idx].w.window = XCBWINDOWNew(c);
115         windows[idx].p.pixmap = XCBPIXMAPNew(c);
116         windows[idx].width = 300;
117         line[0].x = xo = windows[idx].width / 2;
118         windows[idx].height = 300;
119         line[0].y = yo = windows[idx].height / 2;
120         windows[idx].angv = 0.05;
121
122         {
123                 int ws = windows[idx].width * windows[idx].width;
124                 int hs = windows[idx].height * windows[idx].height;
125                 r = sqrt(ws + hs) + 1.0;
126         }
127
128         {
129                 CARD32 mask = XCBCWBackPixel | XCBCWEventMask | XCBCWDontPropagate;
130                 CARD32 values[3];
131                 XCBRECTANGLE rect = { 0, 0, windows[idx].width, windows[idx].height };
132                 values[0] = root->white_pixel;
133                 values[1] = XCBEventMaskButtonRelease | XCBEventMaskExposure;
134                 values[2] = XCBEventMaskButtonPress;
135
136                 XCBCreateWindow(c, depth, windows[idx].w.window, root->root,
137                         /* x */ 0, /* y */ 0,
138                         windows[idx].width, windows[idx].height,
139                         /* border */ 0, XCBWindowClassInputOutput,
140                         /* visual */ root->root_visual,
141                         mask, values);
142
143                 XCBMapWindow(c, windows[idx].w.window);
144
145                 XCBCreatePixmap(c, depth,
146                         windows[idx].p.pixmap, windows[idx].w,
147                         windows[idx].width, windows[idx].height);
148
149                 XCBPolyFillRectangle(c, windows[idx].p, white, 1, &rect);
150         }
151
152         XCBSync(c, 0);
153
154         while(1)
155         {
156                 line[1].x = xo + r * cos(theta);
157                 line[1].y = yo + r * sin(theta);
158                 XCBPolyLine(c, XCBCoordModeOrigin, windows[idx].p, black,
159                         2, line);
160
161                 line[1].x = xo + r * cos(theta + LAG);
162                 line[1].y = yo + r * sin(theta + LAG);
163                 XCBPolyLine(c, XCBCoordModeOrigin, windows[idx].p, white,
164                         2, line);
165
166                 paint(idx);
167                 theta += windows[idx].angv;
168                 while(theta > 2 * PI)
169                         theta -= 2 * PI;
170                 while(theta < 0)
171                         theta += 2 * PI;
172
173                 usleep(1000000 / FRAME_RATE);
174         }
175 }
176
177 int lookup_window(XCBWINDOW w)
178 {
179         int i;
180         for(i = 0; i < WINS; ++i)
181                 if(windows[i].w.window.xid == w.xid)
182                         return i;
183         return -1;
184 }
185
186 void *event_thread(void *param)
187 {
188         XCBGenericEvent *e;
189         int idx;
190
191         while(1)
192         {
193                 e = XCBWaitForEvent(c);
194                 if(!formatEvent(e))
195                         return 0;
196                 if(e->response_type == XCBExpose)
197                 {
198                         XCBExposeEvent *ee = (XCBExposeEvent *) e;
199                         idx = lookup_window(ee->window);
200                         if(idx == -1)
201                                 fprintf(stderr, "Expose on unknown window!\n");
202                         else
203                         {
204                                 XCBCopyArea(c, windows[idx].p, windows[idx].w,
205                                         white, ee->x, ee->y, ee->x, ee->y,
206                                         ee->width, ee->height);
207                                 if(ee->count == 0)
208                                         XCBFlush(c);
209                         }
210                 }
211                 else if(e->response_type == XCBButtonRelease)
212                 {
213                         XCBButtonReleaseEvent *bre = (XCBButtonReleaseEvent *) e;
214                         idx = lookup_window(bre->event);
215                         if(idx == -1)
216                                 fprintf(stderr, "ButtonRelease on unknown window!\n");
217                         else
218                         {
219                                 if(bre->detail.id == XCBButton1)
220                                         windows[idx].angv = -windows[idx].angv;
221                                 else if(bre->detail.id == XCBButton4)
222                                         windows[idx].angv += 0.001;
223                                 else if(bre->detail.id == XCBButton5)
224                                         windows[idx].angv -= 0.001;
225                         }
226                 }
227                 free(e);
228         }
229 }