blob: 0067488ccca1e3c4839102e74264bbffa522c3bf [file] [log] [blame]
Kristian Høgsberg61017b12008-11-02 18:51:48 -05001#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 <fcntl.h>
9#include <unistd.h>
10#include <math.h>
11#include <time.h>
12#include <cairo.h>
13
14#include "wayland-client.h"
15
16static const char gem_device[] = "/dev/dri/card0";
17static const char socket_name[] = "\0wayland";
18
Kristian Høgsberg61017b12008-11-02 18:51:48 -050019static uint32_t name_cairo_surface(int fd, cairo_surface_t *surface)
20{
21 struct drm_i915_gem_create create;
22 struct drm_gem_flink flink;
23 struct drm_i915_gem_pwrite pwrite;
24 int32_t width, height, stride;
25 void *data;
26
27 width = cairo_image_surface_get_width(surface);
28 height = cairo_image_surface_get_height(surface);
29 stride = cairo_image_surface_get_stride(surface);
30 data = cairo_image_surface_get_data(surface);
31
Kristian Høgsberg61017b12008-11-02 18:51:48 -050032 memset(&create, 0, sizeof(create));
33 create.size = height * stride;
34
35 if (ioctl(fd, DRM_IOCTL_I915_GEM_CREATE, &create) != 0) {
36 fprintf(stderr, "gem create failed: %m\n");
37 return 0;
38 }
39
40 pwrite.handle = create.handle;
41 pwrite.offset = 0;
42 pwrite.size = height * stride;
43 pwrite.data_ptr = (uint64_t) (uintptr_t) data;
44 if (ioctl(fd, DRM_IOCTL_I915_GEM_PWRITE, &pwrite) < 0) {
45 fprintf(stderr, "gem pwrite failed: %m\n");
46 return 0;
47 }
48
49 flink.handle = create.handle;
50 if (ioctl(fd, DRM_IOCTL_GEM_FLINK, &flink) != 0) {
51 fprintf(stderr, "gem flink failed: %m\n");
52 return 0;
53 }
54
55#if 0
56 /* We need to hold on to the handle until the server has received
57 * the attach request... we probably need a confirmation event.
58 * I guess the breadcrumb idea will suffice. */
59 struct drm_gem_close close;
60 close.handle = create.handle;
61 if (ioctl(fd, DRM_IOCTL_GEM_CLOSE, &close) < 0) {
62 fprintf(stderr, "gem close failed: %m\n");
63 return 0;
64 }
65#endif
66
67 return flink.name;
68}
69
70struct window {
71 struct wl_surface *surface;
72 int x, y, width, height, stride;
73 int drag_x, drag_y, last_x, last_y;
74 int state;
75 uint32_t name;
76 int fd;
Kristian Høgsberg35370f82008-11-03 11:42:01 -050077 int need_redraw;
Kristian Høgsberg61017b12008-11-02 18:51:48 -050078};
79
80static void *
81draw_window(struct window *window)
82{
83 cairo_surface_t *surface;
84 cairo_t *cr;
Kristian Høgsbergca1d1f62008-11-03 06:59:52 -050085 int border = 2, radius = 5;
86 int margin = (border + 1) / 2;
87 cairo_text_extents_t extents;
88 const static char title[] = "Wayland First Post";
Kristian Høgsberg61017b12008-11-02 18:51:48 -050089
90 surface = cairo_image_surface_create(CAIRO_FORMAT_RGB24,
91 window->width,
92 window->height);
93
94 cr = cairo_create(surface);
95 cairo_set_line_width (cr, border);
Kristian Høgsbergca1d1f62008-11-03 06:59:52 -050096 cairo_move_to(cr, margin, margin + radius);
97 cairo_arc(cr, margin + radius, margin + radius, radius,
98 M_PI, 3 * M_PI / 2);
99 cairo_line_to(cr, window->width - radius - margin, margin);
100 cairo_arc(cr, window->width - margin - radius, margin + radius, radius,
101 3 * M_PI / 2, 2 * M_PI);
102 cairo_line_to(cr, window->width - margin,
103 window->height - margin);
104 cairo_line_to(cr, margin, window->height - margin);
Kristian Høgsberg61017b12008-11-02 18:51:48 -0500105 cairo_close_path(cr);
Kristian Høgsbergca1d1f62008-11-03 06:59:52 -0500106 cairo_set_source_rgba(cr, 0.2, 0.2, 0.2, 0.9);
Kristian Høgsberg61017b12008-11-02 18:51:48 -0500107 cairo_fill_preserve(cr);
108 cairo_set_source_rgba(cr, 0, 0, 0, 1);
Kristian Høgsbergca1d1f62008-11-03 06:59:52 -0500109 cairo_set_font_size(cr, 14);
110 cairo_text_extents(cr, title, &extents);
111 cairo_move_to(cr, margin, margin + radius + extents.height + 10);
112 cairo_line_to(cr, margin + window->width, margin + radius + extents.height + 10);
Kristian Høgsberg61017b12008-11-02 18:51:48 -0500113 cairo_stroke(cr);
Kristian Høgsbergca1d1f62008-11-03 06:59:52 -0500114
115 cairo_move_to(cr, (window->width - extents.width) / 2, 10 - extents.y_bearing);
116 cairo_show_text(cr, title);
117
Kristian Høgsberg61017b12008-11-02 18:51:48 -0500118 cairo_destroy(cr);
119
120 window->stride = cairo_image_surface_get_stride(surface);
121
122 window->name = name_cairo_surface(window->fd, surface);
123 cairo_surface_destroy(surface);
124
125 wl_surface_attach(window->surface, window->name,
126 window->width, window->height, window->stride);
127
128 wl_surface_map(window->surface,
129 window->x, window->y,
130 window->width, window->height);
131
132 return surface;
133}
134
135static int
136connection_update(struct wl_connection *connection,
137 uint32_t mask, void *data)
138{
139 struct pollfd *p = data;
140
141 p->events = 0;
142 if (mask & WL_CONNECTION_READABLE)
143 p->events |= POLLIN;
144 if (mask & WL_CONNECTION_WRITABLE)
145 p->events |= POLLOUT;
146
147 return 0;
148}
149
150enum window_state {
151 WINDOW_STABLE,
152 WINDOW_MOVING,
153 WINDOW_RESIZING_UPPER_LEFT,
154 WINDOW_RESIZING_UPPER_RIGHT,
155 WINDOW_RESIZING_LOWER_LEFT,
156 WINDOW_RESIZING_LOWER_RIGHT
157};
158
159enum location {
160 LOCATION_INTERIOR,
161 LOCATION_UPPER_LEFT,
162 LOCATION_UPPER_RIGHT,
163 LOCATION_LOWER_LEFT,
164 LOCATION_LOWER_RIGHT,
165 LOCATION_OUTSIDE
166};
167
168void event_handler(struct wl_display *display,
169 uint32_t opcode,
170 uint32_t arg1, uint32_t arg2, void *data)
171{
172 struct window *window = data;
173 int location, border = 4;
174 int grip_size = 16;
175
176 if (opcode == 0) {
177 window->last_x = arg1;
178 window->last_y = arg2;
179 switch (window->state) {
180 case WINDOW_MOVING:
181 window->x = window->drag_x + arg1;
182 window->y = window->drag_y + arg2;
183 wl_surface_map(window->surface, window->x, window->y,
184 window->width, window->height);
185 break;
186 case WINDOW_RESIZING_LOWER_RIGHT:
187 window->width = window->drag_x + arg1;
188 window->height = window->drag_y + arg2;
Kristian Høgsberg35370f82008-11-03 11:42:01 -0500189 window->need_redraw = 1;
Kristian Høgsberg61017b12008-11-02 18:51:48 -0500190 break;
191 }
192 }
193
194 if (window->x + border <= window->last_x &&
195 window->last_x < window->x + window->width - border &&
196 window->y + border <= window->last_y &&
197 window->last_y < window->y + window->height - border) {
198 location = LOCATION_INTERIOR;
199 } else if (window->x + window->width - grip_size <= window->last_x &&
200 window->last_x < window->x + window->width &&
201 window->y + window->height - grip_size <= window->last_y &&
202 window->last_y < window->y + window->height) {
203 location = LOCATION_LOWER_RIGHT;
204 } else {
205 location = LOCATION_OUTSIDE;
206 }
207
208 if (opcode == 1 && arg1 == 0 && arg2 == 1) {
209 switch (location) {
210 case LOCATION_INTERIOR:
211 window->drag_x = window->x - window->last_x;
212 window->drag_y = window->y - window->last_y;
213 window->state = WINDOW_MOVING;
214 break;
215 case LOCATION_LOWER_RIGHT:
216 window->drag_x = window->width - window->last_x;
217 window->drag_y = window->height - window->last_y;
218 window->state = WINDOW_RESIZING_LOWER_RIGHT;
219 break;
220 default:
221 window->state = WINDOW_STABLE;
222 break;
223 }
224 } else if (opcode == 1 && arg1 == 0 && arg2 == 0) {
225 window->state = WINDOW_STABLE;
226 }
227}
228
229int main(int argc, char *argv[])
230{
231 struct wl_display *display;
232 int fd, ret;
233 uint32_t mask;
234 cairo_surface_t *s;
235 struct pollfd p[1];
236 struct window window;
237
238 fd = open(gem_device, O_RDWR);
239 if (fd < 0) {
240 fprintf(stderr, "drm open failed: %m\n");
241 return -1;
242 }
243
244 display = wl_display_create(socket_name,
245 connection_update, &p[0]);
246 if (display == NULL) {
247 fprintf(stderr, "failed to create display: %m\n");
248 return -1;
249 }
250 p[0].fd = wl_display_get_fd(display);
251
252 window.surface = wl_display_create_surface(display);
253 window.x = 200;
254 window.y = 200;
255 window.width = 350;
256 window.height = 200;
257 window.state = WINDOW_STABLE;
258 window.fd = fd;
259
260 s = draw_window(&window);
261
262 wl_display_set_event_handler(display, event_handler, &window);
263
264 while (ret = poll(p, 1, -1), ret >= 0) {
265 mask = 0;
266 if (p[0].revents & POLLIN)
267 mask |= WL_CONNECTION_READABLE;
268 if (p[0].revents & POLLOUT)
269 mask |= WL_CONNECTION_WRITABLE;
270 if (mask)
271 wl_display_iterate(display, mask);
Kristian Høgsberg35370f82008-11-03 11:42:01 -0500272 if (window.need_redraw) {
273 draw_window(&window);
274 window.need_redraw = 0;
275 }
Kristian Høgsberg61017b12008-11-02 18:51:48 -0500276 }
277
278 return 0;
279}