tests: update for xcb-util >= 0.3.0
[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 <xcb/xcb.h>
8 #include <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 xcb_connection_t *c;
25 static xcb_screen_t *root;
26 static xcb_gcontext_t white, black;
27 static int depth;
28
29 #define WINS 8
30 static struct {
31         xcb_drawable_t w;
32         xcb_drawable_t p;
33         uint16_t width;
34         uint16_t 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         xcb_drawable_t drawable = { root->root };
44         xcb_get_geometry_reply_t *geom;
45         geom = xcb_get_geometry_reply(c, xcb_get_geometry(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, geom->width, geom->height, geom->depth);
55         free(geom);
56 }
57
58 int main()
59 {
60         pthread_t thr;
61         int i;
62
63         uint32_t mask = XCB_GC_FOREGROUND | XCB_GC_GRAPHICS_EXPOSURES;
64         uint32_t values[2];
65         xcb_drawable_t rootwin;
66         int screen_num;
67
68         c = xcb_connect(0, &screen_num);
69         root = xcb_aux_get_screen(c, screen_num);
70         get_depth();
71
72         rootwin = root->root;
73         white = xcb_generate_id(c);
74         black = xcb_generate_id(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         xcb_create_gc(c, white, rootwin, mask, values);
82
83         values[0] = root->black_pixel;
84         xcb_create_gc(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         xcb_copy_area(c, windows[idx].p, windows[idx].w, white, 0, 0, 0, 0,
97                 windows[idx].width, windows[idx].height);
98         /* FIXME: better error detection for broken pipe
99         if(!xcb_sync(c, 0))
100         {
101                 perror("xcb_sync_t failed");
102                 abort();
103         }
104         */
105         xcb_aux_sync(c);
106 }
107
108 void *run(void *param)
109 {
110         int idx = (int)param;
111
112         int xo, yo;
113         double r, theta = 0;
114
115         xcb_point_t line[2];
116
117         windows[idx].w = xcb_generate_id(c);
118         windows[idx].p = xcb_generate_id(c);
119         windows[idx].width = 300;
120         line[0].x = xo = windows[idx].width / 2;
121         windows[idx].height = 300;
122         line[0].y = yo = windows[idx].height / 2;
123         windows[idx].angv = 0.05;
124
125         {
126                 int ws = windows[idx].width * windows[idx].width;
127                 int hs = windows[idx].height * windows[idx].height;
128                 r = sqrt(ws + hs) + 1.0;
129         }
130
131         {
132                 uint32_t mask = XCB_CW_BACK_PIXEL | XCB_CW_EVENT_MASK | XCB_CW_DONT_PROPAGATE;
133                 uint32_t values[3];
134                 xcb_rectangle_t rect = { 0, 0, windows[idx].width, windows[idx].height };
135                 values[0] = root->white_pixel;
136                 values[1] = XCB_EVENT_MASK_BUTTON_RELEASE | XCB_EVENT_MASK_EXPOSURE;
137                 values[2] = XCB_EVENT_MASK_BUTTON_PRESS;
138
139                 xcb_create_window(c, depth, windows[idx].w, root->root,
140                         /* x */ 0, /* y */ 0,
141                         windows[idx].width, windows[idx].height,
142                         /* border */ 0, XCB_WINDOW_CLASS_INPUT_OUTPUT,
143                         /* visual */ root->root_visual,
144                         mask, values);
145
146                 xcb_map_window(c, windows[idx].w);
147
148                 xcb_create_pixmap(c, depth,
149                         windows[idx].p, windows[idx].w,
150                         windows[idx].width, windows[idx].height);
151
152                 xcb_poly_fill_rectangle(c, windows[idx].p, white, 1, &rect);
153         }
154
155         xcb_flush(c);
156
157         while(1)
158         {
159                 line[1].x = xo + r * cos(theta);
160                 line[1].y = yo + r * sin(theta);
161                 xcb_poly_line(c, XCB_COORD_MODE_ORIGIN, windows[idx].p, black,
162                         2, line);
163
164                 line[1].x = xo + r * cos(theta + LAG);
165                 line[1].y = yo + r * sin(theta + LAG);
166                 xcb_poly_line(c, XCB_COORD_MODE_ORIGIN, windows[idx].p, white,
167                         2, line);
168
169                 paint(idx);
170                 theta += windows[idx].angv;
171                 while(theta > 2 * PI)
172                         theta -= 2 * PI;
173                 while(theta < 0)
174                         theta += 2 * PI;
175
176                 usleep(1000000 / FRAME_RATE);
177         }
178
179         return 0;
180 }
181
182 int lookup_window(xcb_window_t w)
183 {
184         int i;
185         for(i = 0; i < WINS; ++i)
186                 if(windows[i].w == w)
187                         return i;
188         return -1;
189 }
190
191 void *event_thread(void *param)
192 {
193         xcb_generic_event_t *e;
194         int idx;
195
196         while(1)
197         {
198                 e = xcb_wait_for_event(c);
199                 if(!formatEvent(e))
200                         return 0;
201                 if(e->response_type == XCB_EXPOSE)
202                 {
203                         xcb_expose_event_t *ee = (xcb_expose_event_t *) e;
204                         idx = lookup_window(ee->window);
205                         if(idx == -1)
206                                 fprintf(stderr, "Expose on unknown window!\n");
207                         else
208                         {
209                                 xcb_copy_area(c, windows[idx].p, windows[idx].w,
210                                         white, ee->x, ee->y, ee->x, ee->y,
211                                         ee->width, ee->height);
212                                 if(ee->count == 0)
213                                         xcb_flush(c);
214                         }
215                 }
216                 else if(e->response_type == XCB_BUTTON_RELEASE)
217                 {
218                         xcb_button_release_event_t *bre = (xcb_button_release_event_t *) e;
219                         idx = lookup_window(bre->event);
220                         if(idx == -1)
221                                 fprintf(stderr, "ButtonRelease on unknown window!\n");
222                         else
223                         {
224                                 if(bre->detail == XCB_BUTTON_INDEX_1)
225                                         windows[idx].angv = -windows[idx].angv;
226                                 else if(bre->detail == XCB_BUTTON_INDEX_4)
227                                         windows[idx].angv += 0.001;
228                                 else if(bre->detail == XCB_BUTTON_INDEX_5)
229                                         windows[idx].angv -= 0.001;
230                         }
231                 }
232                 free(e);
233         }
234 }