blob: d24ab003ee18b2fdbc8fb80f5f8fa9d43f89fb8f [file] [log] [blame]
Kristian Høgsberg16eb6752008-10-08 22:51:32 -04001#include <stdio.h>
2#include <string.h>
3#include <stdlib.h>
4#include <stdint.h>
Kristian Høgsberg8d7ca6b2008-11-09 00:22:51 -05005#include <stdarg.h>
Kristian Høgsberg16eb6752008-10-08 22:51:32 -04006#include <i915_drm.h>
7#include <sys/ioctl.h>
8#include <sys/mman.h>
9#include <fcntl.h>
10#include <unistd.h>
Kristian Høgsberg8d7ca6b2008-11-09 00:22:51 -050011#include <signal.h>
Kristian Høgsberg4c9f2c92008-11-21 19:25:44 -050012#include <cairo.h>
Kristian Høgsbergaa5b5be2008-11-21 21:31:54 -050013#include <gdk-pixbuf/gdk-pixbuf.h>
14#include <glib.h>
Kristian Høgsberg8d7ca6b2008-11-09 00:22:51 -050015#include <png.h>
Kristian Høgsberg54879822008-11-23 17:07:32 -050016#include <math.h>
Kristian Høgsbergcddc0ad2008-11-24 00:31:49 -050017#include <linux/input.h>
Kristian Høgsberg16eb6752008-10-08 22:51:32 -040018
19#include "wayland.h"
Kristian Høgsberg4c9f2c92008-11-21 19:25:44 -050020#include "cairo-util.h"
Kristian Høgsberg16eb6752008-10-08 22:51:32 -040021
22#include <GL/gl.h>
23#include <eagle.h>
24
25#define ARRAY_LENGTH(a) (sizeof (a) / sizeof (a)[0])
26
27struct egl_compositor {
28 struct wl_compositor base;
29 EGLDisplay display;
30 EGLSurface surface;
31 EGLContext context;
Kristian Høgsberg2d9cd1e2008-11-03 08:09:34 -050032 EGLConfig config;
Kristian Høgsbergf9212892008-10-11 18:40:23 -040033 struct wl_display *wl_display;
Kristian Høgsberg16eb6752008-10-08 22:51:32 -040034 int gem_fd;
Kristian Høgsberg8d7ca6b2008-11-09 00:22:51 -050035 int width, height;
Kristian Høgsbergaa5b5be2008-11-21 21:31:54 -050036 struct egl_surface *pointer;
37 struct egl_surface *background;
Kristian Høgsberg54879822008-11-23 17:07:32 -050038 struct egl_surface *overlay;
Kristian Høgsberg16eb6752008-10-08 22:51:32 -040039};
40
Kristian Høgsbergaa5b5be2008-11-21 21:31:54 -050041struct egl_surface {
Kristian Høgsberg16eb6752008-10-08 22:51:32 -040042 GLuint texture;
Kristian Høgsbergf9212892008-10-11 18:40:23 -040043 struct wl_map map;
Kristian Høgsberg2d9cd1e2008-11-03 08:09:34 -050044 EGLSurface surface;
Kristian Høgsberg16eb6752008-10-08 22:51:32 -040045};
46
Kristian Høgsberg8d7ca6b2008-11-09 00:22:51 -050047static void
48die(const char *msg, ...)
49{
50 va_list ap;
51
52 va_start (ap, msg);
53 vfprintf(stderr, msg, ap);
54 va_end (ap);
55
56 exit(EXIT_FAILURE);
57}
58
59static void
60stdio_write_func (png_structp png, png_bytep data, png_size_t size)
61{
62 FILE *fp;
63 size_t ret;
64
65 fp = png_get_io_ptr (png);
66 while (size) {
67 ret = fwrite (data, 1, size, fp);
68 size -= ret;
69 data += ret;
70 if (size && ferror (fp))
71 die("write: %m\n");
72 }
73}
74
75static void
76png_simple_output_flush_fn (png_structp png_ptr)
77{
78}
79
80static void
81png_simple_error_callback (png_structp png,
82 png_const_charp error_msg)
83{
84 die("png error: %s\n", error_msg);
85}
86
87static void
88png_simple_warning_callback (png_structp png,
89 png_const_charp error_msg)
90{
91 fprintf(stderr, "png warning: %s\n", error_msg);
92}
93
94static void
95convert_pixels(png_structp png, png_row_infop row_info, png_bytep data)
96{
97 unsigned int i;
98
99 for (i = 0; i < row_info->rowbytes; i += 4) {
100 uint8_t *b = &data[i];
101 uint32_t pixel;
102
103 memcpy (&pixel, b, sizeof (uint32_t));
104 b[0] = (pixel & 0xff0000) >> 16;
105 b[1] = (pixel & 0x00ff00) >> 8;
106 b[2] = (pixel & 0x0000ff) >> 0;
107 b[3] = 0;
108 }
109}
110
Kristian Høgsberg1e4b86a2008-11-23 23:41:08 -0500111struct screenshooter {
112 struct wl_object base;
113 struct egl_compositor *ec;
114};
115
Kristian Høgsberg8d7ca6b2008-11-09 00:22:51 -0500116static void
Kristian Høgsberg1e4b86a2008-11-23 23:41:08 -0500117screenshooter_shoot(struct wl_client *client, struct screenshooter *shooter)
Kristian Høgsberg8d7ca6b2008-11-09 00:22:51 -0500118{
Kristian Høgsberg1e4b86a2008-11-23 23:41:08 -0500119 struct egl_compositor *ec = shooter->ec;
Kristian Høgsberg8d7ca6b2008-11-09 00:22:51 -0500120 png_struct *png;
121 png_info *info;
122 png_byte **volatile rows = NULL;
123 png_color_16 white;
124 int depth, i;
125 FILE *fp;
126 uint8_t *data;
127 GLuint stride;
128 static const char filename[] = "wayland-screenshot.png";
129
130 data = eglReadBuffer(ec->display, ec->surface, GL_FRONT_LEFT, &stride);
131 if (data == NULL)
132 die("eglReadBuffer failed\n");
133 rows = malloc(ec->height * sizeof rows[0]);
134 if (rows == NULL)
135 die("malloc failed\n");
136
137 for (i = 0; i < ec->height; i++)
138 rows[i] = (png_byte *) data + i * stride;
139
140 png = png_create_write_struct(PNG_LIBPNG_VER_STRING, NULL,
141 png_simple_error_callback,
142 png_simple_warning_callback);
143 if (png == NULL)
144 die("png_create_write_struct failed\n");
145
146 info = png_create_info_struct(png);
147 if (info == NULL)
148 die("png_create_info_struct failed\n");
149
150 fp = fopen(filename, "w");
151 if (fp == NULL)
152 die("fopen failed: %m\n");
153
154 png_set_write_fn(png, fp, stdio_write_func, png_simple_output_flush_fn);
155
156 depth = 8;
157 png_set_IHDR(png, info,
158 ec->width,
159 ec->height, depth,
160 PNG_COLOR_TYPE_RGB,
161 PNG_INTERLACE_NONE,
162 PNG_COMPRESSION_TYPE_DEFAULT,
163 PNG_FILTER_TYPE_DEFAULT);
164
165 white.gray = (1 << depth) - 1;
166 white.red = white.blue = white.green = white.gray;
167 png_set_bKGD(png, info, &white);
168 png_write_info (png, info);
169 png_set_write_user_transform_fn(png, convert_pixels);
170
171 png_set_filler(png, 0, PNG_FILLER_AFTER);
172 png_write_image(png, rows);
173 png_write_end(png, info);
174
175 png_destroy_write_struct(&png, &info);
176 fclose(fp);
177 free(rows);
178 free(data);
179}
180
Kristian Høgsberg1e4b86a2008-11-23 23:41:08 -0500181static const struct wl_method screenshooter_methods[] = {
182 { "shoot", screenshooter_shoot, 0, NULL }
183};
184
185static const struct wl_interface screenshooter_interface = {
186 "screenshooter", 1,
187 ARRAY_LENGTH(screenshooter_methods),
188 screenshooter_methods,
189};
190
191static struct screenshooter *
192screenshooter_create(struct egl_compositor *ec)
193{
194 struct screenshooter *shooter;
195
196 shooter = malloc(sizeof *shooter);
197 if (shooter == NULL)
198 return NULL;
199
200 shooter->base.interface = &screenshooter_interface;
201 shooter->ec = ec;
202
203 return shooter;
204};
205
Kristian Høgsberg54879822008-11-23 17:07:32 -0500206static struct egl_surface *
207egl_surface_create_from_cairo_surface(cairo_surface_t *surface,
208 int x, int y, int width, int height)
209{
210 struct egl_surface *es;
211 int stride;
212 void *data;
213
214 stride = cairo_image_surface_get_stride(surface);
215 data = cairo_image_surface_get_data(surface);
216
217 es = malloc(sizeof *es);
218 if (es == NULL)
219 return NULL;
220
221 glGenTextures(1, &es->texture);
222 glBindTexture(GL_TEXTURE_2D, es->texture);
223 glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
224 glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_R, GL_REPEAT);
225 glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
226 glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
227 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0,
228 GL_BGRA, GL_UNSIGNED_BYTE, data);
229
230 es->map.x = x;
231 es->map.y = y;
232 es->map.width = width;
233 es->map.height = height;
234 es->surface = EGL_NO_SURFACE;
235
236 return es;
237}
238
239static void
240egl_surface_destroy(struct egl_surface *es, struct egl_compositor *ec)
241{
242 glDeleteTextures(1, &es->texture);
243 if (es->surface != EGL_NO_SURFACE)
244 eglDestroySurface(ec->display, es->surface);
245 free(es);
246}
247
Kristian Høgsbergef7a9ca2008-10-11 21:21:39 -0400248static void
Kristian Høgsberg4c9f2c92008-11-21 19:25:44 -0500249pointer_path(cairo_t *cr, int x, int y)
250{
251 const int end = 3, tx = 4, ty = 12, dx = 5, dy = 10;
252 const int width = 16, height = 16;
253
254 cairo_move_to(cr, x, y);
255 cairo_line_to(cr, x + tx, y + ty);
256 cairo_line_to(cr, x + dx, y + dy);
257 cairo_line_to(cr, x + width - end, y + height);
258 cairo_line_to(cr, x + width, y + height - end);
259 cairo_line_to(cr, x + dy, y + dx);
260 cairo_line_to(cr, x + ty, y + tx);
261 cairo_close_path(cr);
262}
263
Kristian Høgsbergaa5b5be2008-11-21 21:31:54 -0500264static struct egl_surface *
Kristian Høgsberg4c9f2c92008-11-21 19:25:44 -0500265pointer_create(int x, int y, int width, int height)
266{
Kristian Høgsberg54879822008-11-23 17:07:32 -0500267 struct egl_surface *es;
Kristian Høgsberg4c9f2c92008-11-21 19:25:44 -0500268 const int hotspot_x = 16, hotspot_y = 16;
Kristian Høgsberg4c9f2c92008-11-21 19:25:44 -0500269 cairo_surface_t *surface;
270 cairo_t *cr;
Kristian Høgsberg4c9f2c92008-11-21 19:25:44 -0500271
272 surface = cairo_image_surface_create(CAIRO_FORMAT_ARGB32,
273 width, height);
274
275 cr = cairo_create(surface);
276 pointer_path(cr, hotspot_x + 5, hotspot_y + 4);
277 cairo_set_line_width (cr, 2);
278 cairo_set_source_rgb(cr, 0, 0, 0);
279 cairo_stroke_preserve(cr);
280 cairo_fill(cr);
281 blur_surface(surface, width);
282
283 pointer_path(cr, hotspot_x, hotspot_y);
284 cairo_stroke_preserve(cr);
285 cairo_set_source_rgb(cr, 1, 1, 1);
286 cairo_fill(cr);
287 cairo_destroy(cr);
288
Kristian Høgsberg54879822008-11-23 17:07:32 -0500289 es = egl_surface_create_from_cairo_surface(surface, x, y, width, height);
290
Kristian Høgsberg4c9f2c92008-11-21 19:25:44 -0500291 cairo_surface_destroy(surface);
292
Kristian Høgsberg54879822008-11-23 17:07:32 -0500293 return es;
Kristian Høgsbergaa5b5be2008-11-21 21:31:54 -0500294}
295
296static struct egl_surface *
297background_create(const char *filename, int width, int height)
298{
299 struct egl_surface *background;
300 GdkPixbuf *pixbuf;
301 GError *error = NULL;
302 int pixbuf_width, pixbuf_height;
303 void *data;
304
305 background = malloc(sizeof *background);
306 if (background == NULL)
307 return NULL;
308
309 g_type_init();
310
311 pixbuf = gdk_pixbuf_new_from_file(filename, &error);
312 if (error != NULL) {
313 free(background);
314 return NULL;
315 }
316
317 pixbuf_width = gdk_pixbuf_get_width(pixbuf);
318 pixbuf_height = gdk_pixbuf_get_height(pixbuf);
319 data = gdk_pixbuf_get_pixels(pixbuf);
320
321 glGenTextures(1, &background->texture);
322 glBindTexture(GL_TEXTURE_2D, background->texture);
323 glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
324 glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_R, GL_REPEAT);
325 glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
326 glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
327 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, pixbuf_width, pixbuf_height, 0,
328 GL_BGR, GL_UNSIGNED_BYTE, data);
329
330 background->map.x = 0;
331 background->map.y = 0;
332 background->map.width = width;
333 background->map.height = height;
334 background->surface = EGL_NO_SURFACE;
335
336 return background;
Kristian Høgsberg4c9f2c92008-11-21 19:25:44 -0500337}
338
339static void
Kristian Høgsberg54879822008-11-23 17:07:32 -0500340rounded_rect(cairo_t *cr, int x0, int y0, int x1, int y1, int radius)
341{
342 cairo_move_to(cr, x0, y0 + radius);
343 cairo_arc(cr, x0 + radius, y0 + radius, radius, M_PI, 3 * M_PI / 2);
344 cairo_line_to(cr, x1 - radius, y0);
345 cairo_arc(cr, x1 - radius, y0 + radius, radius, 3 * M_PI / 2, 2 * M_PI);
346 cairo_line_to(cr, x1, y1 - radius);
347 cairo_arc(cr, x1 - radius, y1 - radius, radius, 0, M_PI / 2);
348 cairo_line_to(cr, x0 + radius, y1);
349 cairo_arc(cr, x0 + radius, y1 - radius, radius, M_PI / 2, M_PI);
350 cairo_close_path(cr);
351}
352
353static void
354draw_button(cairo_t *cr, int x, int y, int width, int height, const char *text)
355{
356 cairo_pattern_t *gradient;
357 cairo_text_extents_t extents;
358 double bright = 0.15, dim = 0.02;
359 int radius = 10;
360
361 cairo_set_operator(cr, CAIRO_OPERATOR_OVER);
362 cairo_set_line_width (cr, 2);
363 rounded_rect(cr, x, y, x + width, y + height, radius);
364 cairo_set_source_rgb(cr, dim, dim, dim);
365 cairo_stroke(cr);
366 rounded_rect(cr, x + 2, y + 2, x + width, y + height, radius);
367 cairo_set_source_rgb(cr, 0.1, 0.1, 0.1);
368 cairo_stroke(cr);
369
370 rounded_rect(cr, x + 1, y + 1, x + width - 1, y + height - 1, radius - 1);
371 cairo_set_source_rgb(cr, bright, bright, bright);
372 cairo_stroke(cr);
373 rounded_rect(cr, x + 3, y + 3, x + width - 1, y + height - 1, radius - 1);
374 cairo_set_source_rgb(cr, dim, dim, dim);
375 cairo_stroke(cr);
376
377 rounded_rect(cr, x + 1, y + 1, x + width - 1, y + height - 1, radius - 1);
378 gradient = cairo_pattern_create_linear (0, y, 0, y + height);
379 cairo_pattern_add_color_stop_rgb(gradient, 0, 0.15, 0.15, 0.15);
380 cairo_pattern_add_color_stop_rgb(gradient, 0.5, 0.08, 0.08, 0.08);
381 cairo_pattern_add_color_stop_rgb(gradient, 0.5, 0.07, 0.07, 0.07);
382 cairo_pattern_add_color_stop_rgb(gradient, 1, 0.1, 0.1, 0.1);
383 cairo_set_source(cr, gradient);
384 cairo_fill(cr);
385
386 cairo_set_font_size(cr, 16);
387 cairo_text_extents(cr, text, &extents);
388 cairo_move_to(cr, x + (width - extents.width) / 2, y + (height - extents.height) / 2 - extents.y_bearing);
389 cairo_set_line_cap (cr, CAIRO_LINE_CAP_ROUND);
390 cairo_set_line_join (cr, CAIRO_LINE_JOIN_ROUND);
391 cairo_set_line_width (cr, 4);
392 cairo_text_path(cr, text);
393 cairo_set_source_rgb(cr, 0.0, 0.0, 0.0);
394 cairo_stroke_preserve(cr);
395 cairo_set_source_rgb(cr, 1, 1, 1);
396 cairo_fill(cr);
397}
398
399static struct egl_surface *
400overlay_create(int x, int y, int width, int height)
401{
402 struct egl_surface *es;
403 cairo_surface_t *surface;
404 cairo_t *cr;
405 int total_width, button_x, button_y;
406 const int button_width = 150;
407 const int button_height = 40;
408 const int spacing = 50;
409
410 surface = cairo_image_surface_create(CAIRO_FORMAT_ARGB32,
411 width, height);
412
413 cr = cairo_create(surface);
Kristian Høgsberg1e4b86a2008-11-23 23:41:08 -0500414 cairo_set_source_rgba(cr, 0.1, 0.1, 0.1, 0.8);
Kristian Høgsberg54879822008-11-23 17:07:32 -0500415 cairo_set_operator(cr, CAIRO_OPERATOR_SOURCE);
416 cairo_paint(cr);
417
418 total_width = button_width * 2 + spacing;
419 button_x = (width - total_width) / 2;
420 button_y = height - button_height - 20;
421 draw_button(cr, button_x, button_y, button_width, button_height, "Previous");
422 button_x += button_width + spacing;
423 draw_button(cr, button_x, button_y, button_width, button_height, "Next");
424
425 cairo_destroy(cr);
426
427 es = egl_surface_create_from_cairo_surface(surface, x, y, width, height);
428
429 cairo_surface_destroy(surface);
430
431 return es;
432}
433
434static void
Kristian Høgsbergaa5b5be2008-11-21 21:31:54 -0500435draw_surface(struct egl_surface *es)
Kristian Høgsberg4c9f2c92008-11-21 19:25:44 -0500436{
437 GLint vertices[12];
438 GLint tex_coords[12] = { 0, 0, 0, 1, 1, 0, 1, 1 };
439 GLuint indices[4] = { 0, 1, 2, 3 };
440
Kristian Høgsbergaa5b5be2008-11-21 21:31:54 -0500441 vertices[0] = es->map.x;
442 vertices[1] = es->map.y;
Kristian Høgsberg4c9f2c92008-11-21 19:25:44 -0500443 vertices[2] = 0;
444
Kristian Høgsbergaa5b5be2008-11-21 21:31:54 -0500445 vertices[3] = es->map.x;
446 vertices[4] = es->map.y + es->map.height;
Kristian Høgsberg4c9f2c92008-11-21 19:25:44 -0500447 vertices[5] = 0;
448
Kristian Høgsbergaa5b5be2008-11-21 21:31:54 -0500449 vertices[6] = es->map.x + es->map.width;
450 vertices[7] = es->map.y;
Kristian Høgsberg4c9f2c92008-11-21 19:25:44 -0500451 vertices[8] = 0;
452
Kristian Høgsbergaa5b5be2008-11-21 21:31:54 -0500453 vertices[9] = es->map.x + es->map.width;
454 vertices[10] = es->map.y + es->map.height;
Kristian Høgsberg4c9f2c92008-11-21 19:25:44 -0500455 vertices[11] = 0;
456
Kristian Høgsbergaa5b5be2008-11-21 21:31:54 -0500457 glBindTexture(GL_TEXTURE_2D, es->texture);
Kristian Høgsberg4c9f2c92008-11-21 19:25:44 -0500458 glEnable(GL_TEXTURE_2D);
459 glEnable(GL_BLEND);
460 /* Assume pre-multiplied alpha for now, this probably
461 * needs to be a wayland visual type of thing. */
462 glBlendFunc(GL_ONE, GL_ONE_MINUS_SRC_ALPHA);
463
464 glEnableClientState(GL_VERTEX_ARRAY);
465 glEnableClientState(GL_TEXTURE_COORD_ARRAY);
466 glVertexPointer(3, GL_INT, 0, vertices);
467 glTexCoordPointer(2, GL_INT, 0, tex_coords);
468 glDrawElements(GL_TRIANGLE_STRIP, 4, GL_UNSIGNED_INT, indices);
469}
470
471static void
Kristian Høgsbergef7a9ca2008-10-11 21:21:39 -0400472repaint(void *data)
473{
474 struct egl_compositor *ec = data;
475 struct wl_surface_iterator *iterator;
476 struct wl_surface *surface;
Kristian Høgsbergaa5b5be2008-11-21 21:31:54 -0500477 struct egl_surface *es;
478
479 draw_surface(ec->background);
Kristian Høgsbergef7a9ca2008-10-11 21:21:39 -0400480
481 iterator = wl_surface_iterator_create(ec->wl_display, 0);
482 while (wl_surface_iterator_next(iterator, &surface)) {
Kristian Høgsbergaa5b5be2008-11-21 21:31:54 -0500483 es = wl_surface_get_data(surface);
484 if (es == NULL)
Kristian Høgsbergef7a9ca2008-10-11 21:21:39 -0400485 continue;
486
Kristian Høgsbergaa5b5be2008-11-21 21:31:54 -0500487 draw_surface(es);
Kristian Høgsbergef7a9ca2008-10-11 21:21:39 -0400488 }
489 wl_surface_iterator_destroy(iterator);
490
Kristian Høgsberg54879822008-11-23 17:07:32 -0500491 draw_surface(ec->overlay);
492
Kristian Høgsbergaa5b5be2008-11-21 21:31:54 -0500493 draw_surface(ec->pointer);
Kristian Høgsberg4c9f2c92008-11-21 19:25:44 -0500494
Kristian Høgsbergef7a9ca2008-10-11 21:21:39 -0400495 eglSwapBuffers(ec->display, ec->surface);
496}
497
Kristian Høgsberg5503bf82008-11-06 10:38:17 -0500498static void
499schedule_repaint(struct egl_compositor *ec)
Kristian Høgsbergef7a9ca2008-10-11 21:21:39 -0400500{
501 struct wl_event_loop *loop;
502
503 loop = wl_display_get_event_loop(ec->wl_display);
504 wl_event_loop_add_idle(loop, repaint, ec);
505}
506
Kristian Høgsberg5503bf82008-11-06 10:38:17 -0500507static void
508notify_surface_create(struct wl_compositor *compositor,
509 struct wl_surface *surface)
Kristian Høgsberg16eb6752008-10-08 22:51:32 -0400510{
Kristian Høgsbergaa5b5be2008-11-21 21:31:54 -0500511 struct egl_surface *es;
Kristian Høgsberg16eb6752008-10-08 22:51:32 -0400512
Kristian Høgsbergaa5b5be2008-11-21 21:31:54 -0500513 es = malloc(sizeof *es);
514 if (es == NULL)
Kristian Høgsberg16eb6752008-10-08 22:51:32 -0400515 return;
516
Kristian Høgsbergaa5b5be2008-11-21 21:31:54 -0500517 es->surface = EGL_NO_SURFACE;
518 wl_surface_set_data(surface, es);
Kristian Høgsberg16eb6752008-10-08 22:51:32 -0400519
Kristian Høgsbergaa5b5be2008-11-21 21:31:54 -0500520 glGenTextures(1, &es->texture);
Kristian Høgsberg16eb6752008-10-08 22:51:32 -0400521}
522
Kristian Høgsberg5503bf82008-11-06 10:38:17 -0500523static void
524notify_surface_destroy(struct wl_compositor *compositor,
525 struct wl_surface *surface)
Kristian Høgsberg16eb6752008-10-08 22:51:32 -0400526{
527 struct egl_compositor *ec = (struct egl_compositor *) compositor;
Kristian Høgsbergaa5b5be2008-11-21 21:31:54 -0500528 struct egl_surface *es;
Kristian Høgsberg16eb6752008-10-08 22:51:32 -0400529
Kristian Høgsbergaa5b5be2008-11-21 21:31:54 -0500530 es = wl_surface_get_data(surface);
531 if (es == NULL)
Kristian Høgsberg16eb6752008-10-08 22:51:32 -0400532 return;
Kristian Høgsberg2d9cd1e2008-11-03 08:09:34 -0500533
Kristian Høgsbergaa5b5be2008-11-21 21:31:54 -0500534 egl_surface_destroy(es, ec);
Kristian Høgsbergef7a9ca2008-10-11 21:21:39 -0400535
536 schedule_repaint(ec);
Kristian Høgsberg16eb6752008-10-08 22:51:32 -0400537}
538
Kristian Høgsberg5503bf82008-11-06 10:38:17 -0500539static void
540notify_surface_attach(struct wl_compositor *compositor,
541 struct wl_surface *surface, uint32_t name,
542 uint32_t width, uint32_t height, uint32_t stride)
Kristian Høgsberg16eb6752008-10-08 22:51:32 -0400543{
544 struct egl_compositor *ec = (struct egl_compositor *) compositor;
Kristian Høgsbergaa5b5be2008-11-21 21:31:54 -0500545 struct egl_surface *es;
Kristian Høgsberg16eb6752008-10-08 22:51:32 -0400546
Kristian Høgsbergaa5b5be2008-11-21 21:31:54 -0500547 es = wl_surface_get_data(surface);
548 if (es == NULL)
Kristian Høgsberg16eb6752008-10-08 22:51:32 -0400549 return;
550
Kristian Høgsbergaa5b5be2008-11-21 21:31:54 -0500551 if (es->surface != EGL_NO_SURFACE)
552 eglDestroySurface(ec->display, es->surface);
Kristian Høgsberg16eb6752008-10-08 22:51:32 -0400553
Kristian Høgsberg56f3c712008-11-05 07:55:45 -0500554 /* FIXME: We need to use a single buffer config without depth
555 * or stencil buffers here to keep egl from creating auxillary
556 * buffers for the pixmap here. */
Kristian Høgsbergaa5b5be2008-11-21 21:31:54 -0500557 es->surface = eglCreateSurfaceForName(ec->display, ec->config,
Kristian Høgsberg78231c82008-11-08 15:06:01 -0500558 name, width, height, stride, NULL);
Kristian Høgsberg16eb6752008-10-08 22:51:32 -0400559
Kristian Høgsbergaa5b5be2008-11-21 21:31:54 -0500560 glBindTexture(GL_TEXTURE_2D, es->texture);
Kristian Høgsberg16eb6752008-10-08 22:51:32 -0400561 glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
562 glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_R, GL_REPEAT);
563 glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
564 glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
Kristian Høgsbergaa5b5be2008-11-21 21:31:54 -0500565 eglBindTexImage(ec->display, es->surface, GL_TEXTURE_2D);
Kristian Høgsberg16eb6752008-10-08 22:51:32 -0400566
Kristian Høgsbergef7a9ca2008-10-11 21:21:39 -0400567 schedule_repaint(ec);
Kristian Høgsbergf9212892008-10-11 18:40:23 -0400568}
569
Kristian Høgsberg5503bf82008-11-06 10:38:17 -0500570static void
571notify_surface_map(struct wl_compositor *compositor,
572 struct wl_surface *surface, struct wl_map *map)
Kristian Høgsberg16eb6752008-10-08 22:51:32 -0400573{
574 struct egl_compositor *ec = (struct egl_compositor *) compositor;
Kristian Høgsbergaa5b5be2008-11-21 21:31:54 -0500575 struct egl_surface *es;
Kristian Høgsberg16eb6752008-10-08 22:51:32 -0400576
Kristian Høgsbergaa5b5be2008-11-21 21:31:54 -0500577 es = wl_surface_get_data(surface);
578 if (es == NULL)
Kristian Høgsberg16eb6752008-10-08 22:51:32 -0400579 return;
580
Kristian Høgsbergaa5b5be2008-11-21 21:31:54 -0500581 es->map = *map;
Kristian Høgsberg5ebb3172008-10-11 19:21:35 -0400582
Kristian Høgsbergef7a9ca2008-10-11 21:21:39 -0400583 schedule_repaint(ec);
Kristian Høgsberg16eb6752008-10-08 22:51:32 -0400584}
585
Kristian Høgsberg7f77bd82008-11-07 08:39:37 -0500586static void
587notify_surface_copy(struct wl_compositor *compositor,
588 struct wl_surface *surface,
589 int32_t dst_x, int32_t dst_y,
590 uint32_t name, uint32_t stride,
591 int32_t x, int32_t y, int32_t width, int32_t height)
592{
Kristian Høgsberg78231c82008-11-08 15:06:01 -0500593 struct egl_compositor *ec = (struct egl_compositor *) compositor;
594 EGLSurface src;
Kristian Høgsbergaa5b5be2008-11-21 21:31:54 -0500595 struct egl_surface *es;
Kristian Høgsberg78231c82008-11-08 15:06:01 -0500596
Kristian Høgsbergaa5b5be2008-11-21 21:31:54 -0500597 es = wl_surface_get_data(surface);
Kristian Høgsberg78231c82008-11-08 15:06:01 -0500598
599 /* FIXME: glCopyPixels should work, but then we'll have to
600 * call eglMakeCurrent to set up the src and dest surfaces
601 * first. This seems cheaper, but maybe there's a better way
602 * to accomplish this. */
603
604 src = eglCreateSurfaceForName(ec->display, ec->config,
605 name, x + width, y + height, stride, NULL);
606
Kristian Høgsbergaa5b5be2008-11-21 21:31:54 -0500607 eglCopyNativeBuffers(ec->display, es->surface, GL_FRONT_LEFT, dst_x, dst_y,
Kristian Høgsberg78231c82008-11-08 15:06:01 -0500608 src, GL_FRONT_LEFT, x, y, width, height);
609 schedule_repaint(ec);
Kristian Høgsberg7f77bd82008-11-07 08:39:37 -0500610}
611
612static void
613notify_surface_damage(struct wl_compositor *compositor,
Kristian Høgsberg78231c82008-11-08 15:06:01 -0500614 struct wl_surface *surface,
615 int32_t x, int32_t y, int32_t width, int32_t height)
Kristian Høgsberg7f77bd82008-11-07 08:39:37 -0500616{
617 struct egl_compositor *ec = (struct egl_compositor *) compositor;
618
619 /* FIXME: This need to take a damage region, of course. */
620 schedule_repaint(ec);
621}
622
Kristian Høgsberg4c9f2c92008-11-21 19:25:44 -0500623static void
624notify_pointer_motion(struct wl_compositor *compositor,
625 struct wl_object *source, int x, int y)
626{
627 struct egl_compositor *ec = (struct egl_compositor *) compositor;
628
629 ec->pointer->map.x = x;
630 ec->pointer->map.y = y;
631 schedule_repaint(ec);
632}
633
Kristian Høgsbergcddc0ad2008-11-24 00:31:49 -0500634static void
635notify_key(struct wl_compositor *compositor,
636 struct wl_object *source, uint32_t key, uint32_t state)
637{
638 struct egl_compositor *ec = (struct egl_compositor *) compositor;
639
640 if (key == KEY_ESC)
641 schedule_repaint(ec);
642}
643
Kristian Høgsberg5503bf82008-11-06 10:38:17 -0500644static const struct wl_compositor_interface interface = {
Kristian Høgsberg16eb6752008-10-08 22:51:32 -0400645 notify_surface_create,
646 notify_surface_destroy,
647 notify_surface_attach,
Kristian Høgsberg7f77bd82008-11-07 08:39:37 -0500648 notify_surface_map,
649 notify_surface_copy,
Kristian Høgsberg4c9f2c92008-11-21 19:25:44 -0500650 notify_surface_damage,
Kristian Høgsbergcddc0ad2008-11-24 00:31:49 -0500651 notify_pointer_motion,
652 notify_key
Kristian Høgsberg16eb6752008-10-08 22:51:32 -0400653};
654
Kristian Høgsbergcddc0ad2008-11-24 00:31:49 -0500655static const char pointer_device_file[] =
656 "/dev/input/by-id/usb-Apple__Inc._Apple_Internal_Keyboard_._Trackpad-event-mouse";
657static const char keyboard_device_file[] =
658 "/dev/input/by-id/usb-Apple__Inc._Apple_Internal_Keyboard_._Trackpad-event-kbd";
659
660static void
661create_input_devices(struct wl_display *display)
662{
663 struct wl_object *obj;
664 const char *path;
665
666 path = getenv("WAYLAND_POINTER");
667 if (path == NULL)
668 path = pointer_device_file;
669
670 obj = wl_input_device_create(display, path);
671 if (obj != NULL)
672 wl_display_add_object(display, obj);
673
674 path = getenv("WAYLAND_KEYBOARD");
675 if (path == NULL)
676 path = keyboard_device_file;
677
678 obj = wl_input_device_create(display, path);
679 if (obj != NULL)
680 wl_display_add_object(display, obj);
681}
682
Kristian Høgsberg16eb6752008-10-08 22:51:32 -0400683static const char gem_device[] = "/dev/dri/card0";
684
Kristian Høgsbergb7a01922008-11-08 15:39:41 -0500685WL_EXPORT struct wl_compositor *
Kristian Høgsbergf9212892008-10-11 18:40:23 -0400686wl_compositor_create(struct wl_display *display)
Kristian Høgsberg16eb6752008-10-08 22:51:32 -0400687{
688 EGLConfig configs[64];
689 EGLint major, minor, count;
690 struct egl_compositor *ec;
Kristian Høgsbergaa5b5be2008-11-21 21:31:54 -0500691 const char *filename;
Kristian Høgsberg1e4b86a2008-11-23 23:41:08 -0500692 struct screenshooter *shooter;
Kristian Høgsberg16eb6752008-10-08 22:51:32 -0400693
694 ec = malloc(sizeof *ec);
695 if (ec == NULL)
696 return NULL;
697
Kristian Høgsberg8d7ca6b2008-11-09 00:22:51 -0500698 ec->width = 1280;
699 ec->height = 800;
700
Kristian Høgsberg16eb6752008-10-08 22:51:32 -0400701 ec->base.interface = &interface;
Kristian Høgsbergf9212892008-10-11 18:40:23 -0400702 ec->wl_display = display;
Kristian Høgsberg16eb6752008-10-08 22:51:32 -0400703
Kristian Høgsbergc508d932008-10-13 22:52:42 -0400704 ec->display = eglCreateDisplayNative(gem_device, "i965");
Kristian Høgsberg16eb6752008-10-08 22:51:32 -0400705 if (ec->display == NULL) {
706 fprintf(stderr, "failed to create display\n");
707 return NULL;
708 }
709
710 if (!eglInitialize(ec->display, &major, &minor)) {
711 fprintf(stderr, "failed to initialize display\n");
712 return NULL;
713 }
714
715 if (!eglGetConfigs(ec->display, configs, ARRAY_LENGTH(configs), &count)) {
716 fprintf(stderr, "failed to get configs\n");
717 return NULL;
718 }
719
Kristian Høgsberg2d9cd1e2008-11-03 08:09:34 -0500720 ec->config = configs[24];
721 ec->surface = eglCreateSurfaceNative(ec->display, ec->config,
Kristian Høgsberg8d7ca6b2008-11-09 00:22:51 -0500722 0, 0, ec->width, ec->height);
Kristian Høgsberg16eb6752008-10-08 22:51:32 -0400723 if (ec->surface == NULL) {
724 fprintf(stderr, "failed to create surface\n");
725 return NULL;
726 }
727
Kristian Høgsberg2d9cd1e2008-11-03 08:09:34 -0500728 ec->context = eglCreateContext(ec->display, ec->config, NULL, NULL);
Kristian Høgsberg16eb6752008-10-08 22:51:32 -0400729 if (ec->context == NULL) {
730 fprintf(stderr, "failed to create context\n");
731 return NULL;
732 }
733
734 if (!eglMakeCurrent(ec->display, ec->surface, ec->surface, ec->context)) {
735 fprintf(stderr, "failed to make context current\n");
736 return NULL;
737 }
738
Kristian Høgsberg8d7ca6b2008-11-09 00:22:51 -0500739 glViewport(0, 0, ec->width, ec->height);
Kristian Høgsberg16eb6752008-10-08 22:51:32 -0400740 glMatrixMode(GL_PROJECTION);
741 glLoadIdentity();
Kristian Høgsberg8d7ca6b2008-11-09 00:22:51 -0500742 glOrtho(0, ec->width, ec->height, 0, 0, 1000.0);
Kristian Høgsberg16eb6752008-10-08 22:51:32 -0400743 glMatrixMode(GL_MODELVIEW);
Kristian Høgsbergcddc0ad2008-11-24 00:31:49 -0500744
745 create_input_devices(display);
Kristian Høgsberg16eb6752008-10-08 22:51:32 -0400746
Kristian Høgsbergaa5b5be2008-11-21 21:31:54 -0500747 filename = getenv("WAYLAND_BACKGROUND");
748 if (filename == NULL)
749 filename = "background.jpg";
750 ec->background = background_create(filename, 1280, 800);
Kristian Høgsberg4c9f2c92008-11-21 19:25:44 -0500751 ec->pointer = pointer_create(100, 100, 64, 64);
Kristian Høgsberg54879822008-11-23 17:07:32 -0500752 ec->overlay = overlay_create(0, ec->height - 200, ec->width, 200);
Kristian Høgsberg4c9f2c92008-11-21 19:25:44 -0500753
Kristian Høgsberg16eb6752008-10-08 22:51:32 -0400754 ec->gem_fd = open(gem_device, O_RDWR);
755 if (ec->gem_fd < 0) {
756 fprintf(stderr, "failed to open drm device\n");
757 return NULL;
758 }
759
Kristian Høgsberg1e4b86a2008-11-23 23:41:08 -0500760 shooter = screenshooter_create(ec);
761 wl_display_add_object(display, &shooter->base);
762 wl_display_add_global(display, &shooter->base);
Kristian Høgsberg8d7ca6b2008-11-09 00:22:51 -0500763
Kristian Høgsbergef7a9ca2008-10-11 21:21:39 -0400764 schedule_repaint(ec);
765
Kristian Høgsberg16eb6752008-10-08 22:51:32 -0400766 return &ec->base;
767}