Replace deprecated Automake INCLUDES variable with AM_CPPFLAGS
[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 *run(void *param)
95 {
96         int idx = (int)param;
97
98         int xo, yo;
99         double r, theta = 0;
100
101         xcb_point_t line[2];
102
103         windows[idx].w = xcb_generate_id(c);
104         windows[idx].p = xcb_generate_id(c);
105         windows[idx].width = 300;
106         line[0].x = xo = windows[idx].width / 2;
107         windows[idx].height = 300;
108         line[0].y = yo = windows[idx].height / 2;
109         windows[idx].angv = 0.05;
110
111         {
112                 int ws = windows[idx].width * windows[idx].width;
113                 int hs = windows[idx].height * windows[idx].height;
114                 r = sqrt(ws + hs) + 1.0;
115         }
116
117         {
118                 uint32_t mask = XCB_CW_BACK_PIXEL | XCB_CW_EVENT_MASK | XCB_CW_DONT_PROPAGATE;
119                 uint32_t values[3];
120                 xcb_rectangle_t rect = { 0, 0, windows[idx].width, windows[idx].height };
121                 values[0] = root->white_pixel;
122                 values[1] = XCB_EVENT_MASK_BUTTON_RELEASE | XCB_EVENT_MASK_EXPOSURE;
123                 values[2] = XCB_EVENT_MASK_BUTTON_PRESS;
124
125                 xcb_create_window(c, depth, windows[idx].w, root->root,
126                         /* x */ 0, /* y */ 0,
127                         windows[idx].width, windows[idx].height,
128                         /* border */ 0, XCB_WINDOW_CLASS_INPUT_OUTPUT,
129                         /* visual */ root->root_visual,
130                         mask, values);
131
132                 xcb_map_window(c, windows[idx].w);
133
134                 xcb_create_pixmap(c, depth,
135                         windows[idx].p, windows[idx].w,
136                         windows[idx].width, windows[idx].height);
137
138                 xcb_poly_fill_rectangle(c, windows[idx].p, white, 1, &rect);
139         }
140
141         xcb_flush(c);
142
143         while(1)
144         {
145                 line[1].x = xo + r * cos(theta);
146                 line[1].y = yo + r * sin(theta);
147                 xcb_poly_line(c, XCB_COORD_MODE_ORIGIN, windows[idx].p, black,
148                         2, line);
149
150                 line[1].x = xo + r * cos(theta + LAG);
151                 line[1].y = yo + r * sin(theta + LAG);
152                 xcb_poly_line(c, XCB_COORD_MODE_ORIGIN, windows[idx].p, white,
153                         2, line);
154
155                 xcb_copy_area(c, windows[idx].p, windows[idx].w, white, 0, 0, 0, 0,
156                         windows[idx].width, windows[idx].height);
157                 if(xcb_flush(c) <= 0)
158                         break;
159
160                 theta += windows[idx].angv;
161                 while(theta > 2 * PI)
162                         theta -= 2 * PI;
163                 while(theta < 0)
164                         theta += 2 * PI;
165
166                 usleep(1000000 / FRAME_RATE);
167         }
168
169         return 0;
170 }
171
172 int lookup_window(xcb_window_t w)
173 {
174         int i;
175         for(i = 0; i < WINS; ++i)
176                 if(windows[i].w == w)
177                         return i;
178         return -1;
179 }
180
181 void *event_thread(void *param)
182 {
183         xcb_generic_event_t *e;
184         int idx;
185
186         while(1)
187         {
188                 e = xcb_wait_for_event(c);
189                 if(!formatEvent(e))
190                         return 0;
191                 if(e->response_type == XCB_EXPOSE)
192                 {
193                         xcb_expose_event_t *ee = (xcb_expose_event_t *) e;
194                         idx = lookup_window(ee->window);
195                         if(idx == -1)
196                                 fprintf(stderr, "Expose on unknown window!\n");
197                         else
198                         {
199                                 xcb_copy_area(c, windows[idx].p, windows[idx].w,
200                                         white, ee->x, ee->y, ee->x, ee->y,
201                                         ee->width, ee->height);
202                                 if(ee->count == 0)
203                                         xcb_flush(c);
204                         }
205                 }
206                 else if(e->response_type == XCB_BUTTON_RELEASE)
207                 {
208                         xcb_button_release_event_t *bre = (xcb_button_release_event_t *) e;
209                         idx = lookup_window(bre->event);
210                         if(idx == -1)
211                                 fprintf(stderr, "ButtonRelease on unknown window!\n");
212                         else
213                         {
214                                 if(bre->detail == XCB_BUTTON_INDEX_1)
215                                         windows[idx].angv = -windows[idx].angv;
216                                 else if(bre->detail == XCB_BUTTON_INDEX_4)
217                                         windows[idx].angv += 0.001;
218                                 else if(bre->detail == XCB_BUTTON_INDEX_5)
219                                         windows[idx].angv -= 0.001;
220                         }
221                 }
222                 free(e);
223         }
224 }