Add README for the adventurous, allow evdev override from getenv().
[profile/ivi/wayland.git] / flower.c
1 #include <stdint.h>
2 #include <stdio.h>
3 #include <stdlib.h>
4 #include <string.h>
5 #include <i915_drm.h>
6 #include <sys/ioctl.h>
7 #include <sys/poll.h>
8 #include <sys/timerfd.h>
9 #include <time.h>
10 #include <fcntl.h>
11 #include <unistd.h>
12 #include <math.h>
13 #include <time.h>
14 #include <cairo.h>
15
16 #include "wayland-client.h"
17
18 static const char gem_device[] = "/dev/dri/card0";
19 static const char socket_name[] = "\0wayland";
20
21 static uint32_t name_cairo_surface(int fd, cairo_surface_t *surface)
22 {
23         struct drm_i915_gem_create create;
24         struct drm_gem_flink flink;
25         struct drm_i915_gem_pwrite pwrite;
26         int32_t width, height, stride;
27         void *data;
28
29         width = cairo_image_surface_get_width(surface);
30         height = cairo_image_surface_get_height(surface);
31         stride = cairo_image_surface_get_stride(surface);
32         data = cairo_image_surface_get_data(surface);
33
34         memset(&create, 0, sizeof(create));
35         create.size = height * stride;
36
37         if (ioctl(fd, DRM_IOCTL_I915_GEM_CREATE, &create) != 0) {
38                 fprintf(stderr, "gem create failed: %m\n");
39                 return 0;
40         }
41
42         pwrite.handle = create.handle;
43         pwrite.offset = 0;
44         pwrite.size = height * stride;
45         pwrite.data_ptr = (uint64_t) (uintptr_t) data;
46         if (ioctl(fd, DRM_IOCTL_I915_GEM_PWRITE, &pwrite) < 0) {
47                 fprintf(stderr, "gem pwrite failed: %m\n");
48                 return 0;
49         }
50
51         flink.handle = create.handle;
52         if (ioctl(fd, DRM_IOCTL_GEM_FLINK, &flink) != 0) {
53                 fprintf(stderr, "gem flink failed: %m\n");
54                 return 0;
55         }
56
57 #if 0
58         /* We need to hold on to the handle until the server has received
59          * the attach request... we probably need a confirmation event.
60          * I guess the breadcrumb idea will suffice. */
61         struct drm_gem_close close;
62         close.handle = create.handle;
63         if (ioctl(fd, DRM_IOCTL_GEM_CLOSE, &close) < 0) {
64                 fprintf(stderr, "gem close failed: %m\n");
65                 return 0;
66         }
67 #endif
68
69         return flink.name;
70 }
71
72 static void
73 set_random_color(cairo_t *cr)
74 {
75         cairo_set_source_rgba(cr,
76                               0.5 + (random() % 50) / 49.0,
77                               0.5 + (random() % 50) / 49.0,
78                               0.5 + (random() % 50) / 49.0,
79                               0.5 + (random() % 100) / 99.0);
80 }
81
82
83 static void *
84 draw_stuff(int width, int height)
85 {
86         const int petal_count = 3 + random() % 5;
87         const double r1 = 60 + random() % 35;
88         const double r2 = 20 + random() % 40;
89         const double u = (10 + random() % 90) / 100.0;
90         const double v = (random() % 90) / 100.0;
91
92         cairo_surface_t *surface;
93         cairo_t *cr;
94         int i;
95         double t, dt = 2 * M_PI / (petal_count * 2);
96         double x1, y1, x2, y2, x3, y3;
97
98         surface = cairo_image_surface_create(CAIRO_FORMAT_RGB24,
99                                              width, height);
100
101         cr = cairo_create(surface);
102         cairo_translate(cr, width / 2, height / 2);
103         cairo_move_to(cr, cos(t) * r1, sin(t) * r1);
104         for (t = 0, i = 0; i < petal_count; i++, t += dt * 2) {
105                 x1 = cos(t) * r1;
106                 y1 = sin(t) * r1;
107                 x2 = cos(t + dt) * r2;
108                 y2 = sin(t + dt) * r2;
109                 x3 = cos(t + 2 * dt) * r1;
110                 y3 = sin(t + 2 * dt) * r1;
111
112                 cairo_curve_to(cr,
113                                x1 - y1 * u, y1 + x1 * u,
114                                x2 + y2 * v, y2 - x2 * v,
115                                x2, y2);                        
116
117                 cairo_curve_to(cr,
118                                x2 - y2 * v, y2 + x2 * v,
119                                x3 + y3 * u, y3 - x3 * u,
120                                x3, y3);
121         }
122
123         cairo_close_path(cr);
124         set_random_color(cr);
125         cairo_fill_preserve(cr);
126         set_random_color(cr);
127         cairo_stroke(cr);
128
129         cairo_destroy(cr);
130
131         return surface;
132 }
133
134 static int
135 connection_update(struct wl_connection *connection,
136                   uint32_t mask, void *data)
137 {
138         struct pollfd *p = data;
139
140         p->events = 0;
141         if (mask & WL_CONNECTION_READABLE)
142                 p->events |= POLLIN;
143         if (mask & WL_CONNECTION_WRITABLE)
144                 p->events |= POLLOUT;
145
146         return 0;
147 }
148
149 int main(int argc, char *argv[])
150 {
151         struct wl_display *display;
152         struct wl_surface *surface;
153         const int x = 512, y = 384, width = 200, height = 200;
154         int fd, i, ret;
155         uint32_t name, mask;
156         cairo_surface_t *s;
157         struct pollfd p[2];
158         struct timespec ts;
159         struct itimerspec its;
160         uint64_t expires;
161
162         fd = open(gem_device, O_RDWR);
163         if (fd < 0) {
164                 fprintf(stderr, "drm open failed: %m\n");
165                 return -1;
166         }
167
168         display = wl_display_create(socket_name,
169                                     connection_update, &p[0]);
170         if (display == NULL) {
171                 fprintf(stderr, "failed to create display: %m\n");
172                 return -1;
173         }
174         p[0].fd = wl_display_get_fd(display);
175
176         surface = wl_display_create_surface(display);
177
178         p[1].fd = timerfd_create(CLOCK_MONOTONIC, 0);
179         if (p[1].fd < 0) {
180                 fprintf(stderr, "could not create timerfd\n: %m");
181                 return -1;
182         }
183
184         p[1].events = POLLIN;
185         clock_gettime(CLOCK_MONOTONIC, &ts);
186         its.it_value = ts;
187         its.it_interval.tv_sec = 0;
188         its.it_interval.tv_nsec = 20 * 1000000;
189         if (timerfd_settime(p[1].fd, TFD_TIMER_ABSTIME, &its, NULL) < 0) {
190                 fprintf(stderr, "could not set timerfd\n: %m");
191                 return -1;
192         }
193
194         srandom(ts.tv_nsec);
195
196         s = draw_stuff(width, height);
197         name = name_cairo_surface(fd, s);
198
199         wl_surface_attach(surface, name, width, height,
200                           cairo_image_surface_get_stride(s));
201
202         i = ts.tv_nsec;
203         while (ret = poll(p, 2, -1), ret >= 0) {
204                 if (p[1].revents & POLLIN) {
205                         read(p[1].fd, &expires, sizeof expires);
206                         wl_surface_map(surface, 
207                                        x + cos(i / 31.0) * 400 - width / 2,
208                                        y + sin(i / 27.0) * 300 - height / 2,
209                                        width, height);
210                         i++;
211                         continue;
212                 }
213
214                 mask = 0;
215                 if (p[0].revents & POLLIN)
216                         mask |= WL_CONNECTION_READABLE;
217                 if (p[0].revents & POLLOUT)
218                         mask |= WL_CONNECTION_WRITABLE;
219                 if (mask)
220                         wl_display_iterate(display, mask);
221         }
222
223         return 0;
224 }