blob: 72681f15ba9b764ea59d856c6a3c5bec1b79a6b4 [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øgsberg9af92b32008-11-24 01:12:46 -050039 int32_t overlay_target, overlay_previous;
Kristian Høgsberg16eb6752008-10-08 22:51:32 -040040};
41
Kristian Høgsbergaa5b5be2008-11-21 21:31:54 -050042struct egl_surface {
Kristian Høgsberg16eb6752008-10-08 22:51:32 -040043 GLuint texture;
Kristian Høgsbergf9212892008-10-11 18:40:23 -040044 struct wl_map map;
Kristian Høgsberg2d9cd1e2008-11-03 08:09:34 -050045 EGLSurface surface;
Kristian Høgsberg16eb6752008-10-08 22:51:32 -040046};
47
Kristian Høgsberg8d7ca6b2008-11-09 00:22:51 -050048static void
49die(const char *msg, ...)
50{
51 va_list ap;
52
53 va_start (ap, msg);
54 vfprintf(stderr, msg, ap);
55 va_end (ap);
56
57 exit(EXIT_FAILURE);
58}
59
60static void
61stdio_write_func (png_structp png, png_bytep data, png_size_t size)
62{
63 FILE *fp;
64 size_t ret;
65
66 fp = png_get_io_ptr (png);
67 while (size) {
68 ret = fwrite (data, 1, size, fp);
69 size -= ret;
70 data += ret;
71 if (size && ferror (fp))
72 die("write: %m\n");
73 }
74}
75
76static void
77png_simple_output_flush_fn (png_structp png_ptr)
78{
79}
80
81static void
82png_simple_error_callback (png_structp png,
83 png_const_charp error_msg)
84{
85 die("png error: %s\n", error_msg);
86}
87
88static void
89png_simple_warning_callback (png_structp png,
90 png_const_charp error_msg)
91{
92 fprintf(stderr, "png warning: %s\n", error_msg);
93}
94
95static void
96convert_pixels(png_structp png, png_row_infop row_info, png_bytep data)
97{
98 unsigned int i;
99
100 for (i = 0; i < row_info->rowbytes; i += 4) {
101 uint8_t *b = &data[i];
102 uint32_t pixel;
103
104 memcpy (&pixel, b, sizeof (uint32_t));
105 b[0] = (pixel & 0xff0000) >> 16;
106 b[1] = (pixel & 0x00ff00) >> 8;
107 b[2] = (pixel & 0x0000ff) >> 0;
108 b[3] = 0;
109 }
110}
111
Kristian Høgsberg1e4b86a2008-11-23 23:41:08 -0500112struct screenshooter {
113 struct wl_object base;
114 struct egl_compositor *ec;
115};
116
Kristian Høgsberg8d7ca6b2008-11-09 00:22:51 -0500117static void
Kristian Høgsberg1e4b86a2008-11-23 23:41:08 -0500118screenshooter_shoot(struct wl_client *client, struct screenshooter *shooter)
Kristian Høgsberg8d7ca6b2008-11-09 00:22:51 -0500119{
Kristian Høgsberg1e4b86a2008-11-23 23:41:08 -0500120 struct egl_compositor *ec = shooter->ec;
Kristian Høgsberg8d7ca6b2008-11-09 00:22:51 -0500121 png_struct *png;
122 png_info *info;
123 png_byte **volatile rows = NULL;
124 png_color_16 white;
125 int depth, i;
126 FILE *fp;
127 uint8_t *data;
128 GLuint stride;
129 static const char filename[] = "wayland-screenshot.png";
130
131 data = eglReadBuffer(ec->display, ec->surface, GL_FRONT_LEFT, &stride);
132 if (data == NULL)
133 die("eglReadBuffer failed\n");
134 rows = malloc(ec->height * sizeof rows[0]);
135 if (rows == NULL)
136 die("malloc failed\n");
137
138 for (i = 0; i < ec->height; i++)
139 rows[i] = (png_byte *) data + i * stride;
140
141 png = png_create_write_struct(PNG_LIBPNG_VER_STRING, NULL,
142 png_simple_error_callback,
143 png_simple_warning_callback);
144 if (png == NULL)
145 die("png_create_write_struct failed\n");
146
147 info = png_create_info_struct(png);
148 if (info == NULL)
149 die("png_create_info_struct failed\n");
150
151 fp = fopen(filename, "w");
152 if (fp == NULL)
153 die("fopen failed: %m\n");
154
155 png_set_write_fn(png, fp, stdio_write_func, png_simple_output_flush_fn);
156
157 depth = 8;
158 png_set_IHDR(png, info,
159 ec->width,
160 ec->height, depth,
161 PNG_COLOR_TYPE_RGB,
162 PNG_INTERLACE_NONE,
163 PNG_COMPRESSION_TYPE_DEFAULT,
164 PNG_FILTER_TYPE_DEFAULT);
165
166 white.gray = (1 << depth) - 1;
167 white.red = white.blue = white.green = white.gray;
168 png_set_bKGD(png, info, &white);
169 png_write_info (png, info);
170 png_set_write_user_transform_fn(png, convert_pixels);
171
172 png_set_filler(png, 0, PNG_FILLER_AFTER);
173 png_write_image(png, rows);
174 png_write_end(png, info);
175
176 png_destroy_write_struct(&png, &info);
177 fclose(fp);
178 free(rows);
179 free(data);
180}
181
Kristian Høgsberg1e4b86a2008-11-23 23:41:08 -0500182static const struct wl_method screenshooter_methods[] = {
183 { "shoot", screenshooter_shoot, 0, NULL }
184};
185
186static const struct wl_interface screenshooter_interface = {
187 "screenshooter", 1,
188 ARRAY_LENGTH(screenshooter_methods),
189 screenshooter_methods,
190};
191
192static struct screenshooter *
193screenshooter_create(struct egl_compositor *ec)
194{
195 struct screenshooter *shooter;
196
197 shooter = malloc(sizeof *shooter);
198 if (shooter == NULL)
199 return NULL;
200
201 shooter->base.interface = &screenshooter_interface;
202 shooter->ec = ec;
203
204 return shooter;
205};
206
Kristian Høgsberg54879822008-11-23 17:07:32 -0500207static struct egl_surface *
208egl_surface_create_from_cairo_surface(cairo_surface_t *surface,
209 int x, int y, int width, int height)
210{
211 struct egl_surface *es;
212 int stride;
213 void *data;
214
215 stride = cairo_image_surface_get_stride(surface);
216 data = cairo_image_surface_get_data(surface);
217
218 es = malloc(sizeof *es);
219 if (es == NULL)
220 return NULL;
221
222 glGenTextures(1, &es->texture);
223 glBindTexture(GL_TEXTURE_2D, es->texture);
224 glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
225 glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_R, GL_REPEAT);
226 glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
227 glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
228 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0,
229 GL_BGRA, GL_UNSIGNED_BYTE, data);
230
231 es->map.x = x;
232 es->map.y = y;
233 es->map.width = width;
234 es->map.height = height;
235 es->surface = EGL_NO_SURFACE;
236
237 return es;
238}
239
240static void
241egl_surface_destroy(struct egl_surface *es, struct egl_compositor *ec)
242{
243 glDeleteTextures(1, &es->texture);
244 if (es->surface != EGL_NO_SURFACE)
245 eglDestroySurface(ec->display, es->surface);
246 free(es);
247}
248
Kristian Høgsbergef7a9ca2008-10-11 21:21:39 -0400249static void
Kristian Høgsberg4c9f2c92008-11-21 19:25:44 -0500250pointer_path(cairo_t *cr, int x, int y)
251{
252 const int end = 3, tx = 4, ty = 12, dx = 5, dy = 10;
253 const int width = 16, height = 16;
254
255 cairo_move_to(cr, x, y);
256 cairo_line_to(cr, x + tx, y + ty);
257 cairo_line_to(cr, x + dx, y + dy);
258 cairo_line_to(cr, x + width - end, y + height);
259 cairo_line_to(cr, x + width, y + height - end);
260 cairo_line_to(cr, x + dy, y + dx);
261 cairo_line_to(cr, x + ty, y + tx);
262 cairo_close_path(cr);
263}
264
Kristian Høgsbergaa5b5be2008-11-21 21:31:54 -0500265static struct egl_surface *
Kristian Høgsberg4c9f2c92008-11-21 19:25:44 -0500266pointer_create(int x, int y, int width, int height)
267{
Kristian Høgsberg54879822008-11-23 17:07:32 -0500268 struct egl_surface *es;
Kristian Høgsberg4c9f2c92008-11-21 19:25:44 -0500269 const int hotspot_x = 16, hotspot_y = 16;
Kristian Høgsberg4c9f2c92008-11-21 19:25:44 -0500270 cairo_surface_t *surface;
271 cairo_t *cr;
Kristian Høgsberg4c9f2c92008-11-21 19:25:44 -0500272
273 surface = cairo_image_surface_create(CAIRO_FORMAT_ARGB32,
274 width, height);
275
276 cr = cairo_create(surface);
277 pointer_path(cr, hotspot_x + 5, hotspot_y + 4);
278 cairo_set_line_width (cr, 2);
279 cairo_set_source_rgb(cr, 0, 0, 0);
280 cairo_stroke_preserve(cr);
281 cairo_fill(cr);
282 blur_surface(surface, width);
283
284 pointer_path(cr, hotspot_x, hotspot_y);
285 cairo_stroke_preserve(cr);
286 cairo_set_source_rgb(cr, 1, 1, 1);
287 cairo_fill(cr);
288 cairo_destroy(cr);
289
Kristian Høgsberg54879822008-11-23 17:07:32 -0500290 es = egl_surface_create_from_cairo_surface(surface, x, y, width, height);
291
Kristian Høgsberg4c9f2c92008-11-21 19:25:44 -0500292 cairo_surface_destroy(surface);
293
Kristian Høgsberg54879822008-11-23 17:07:32 -0500294 return es;
Kristian Høgsbergaa5b5be2008-11-21 21:31:54 -0500295}
296
297static struct egl_surface *
298background_create(const char *filename, int width, int height)
299{
300 struct egl_surface *background;
301 GdkPixbuf *pixbuf;
302 GError *error = NULL;
303 int pixbuf_width, pixbuf_height;
304 void *data;
305
306 background = malloc(sizeof *background);
307 if (background == NULL)
308 return NULL;
309
310 g_type_init();
311
312 pixbuf = gdk_pixbuf_new_from_file(filename, &error);
313 if (error != NULL) {
314 free(background);
315 return NULL;
316 }
317
318 pixbuf_width = gdk_pixbuf_get_width(pixbuf);
319 pixbuf_height = gdk_pixbuf_get_height(pixbuf);
320 data = gdk_pixbuf_get_pixels(pixbuf);
321
322 glGenTextures(1, &background->texture);
323 glBindTexture(GL_TEXTURE_2D, background->texture);
324 glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
325 glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_R, GL_REPEAT);
326 glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
327 glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
328 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, pixbuf_width, pixbuf_height, 0,
329 GL_BGR, GL_UNSIGNED_BYTE, data);
330
331 background->map.x = 0;
332 background->map.y = 0;
333 background->map.width = width;
334 background->map.height = height;
335 background->surface = EGL_NO_SURFACE;
336
337 return background;
Kristian Høgsberg4c9f2c92008-11-21 19:25:44 -0500338}
339
340static void
Kristian Høgsberg54879822008-11-23 17:07:32 -0500341rounded_rect(cairo_t *cr, int x0, int y0, int x1, int y1, int radius)
342{
343 cairo_move_to(cr, x0, y0 + radius);
344 cairo_arc(cr, x0 + radius, y0 + radius, radius, M_PI, 3 * M_PI / 2);
345 cairo_line_to(cr, x1 - radius, y0);
346 cairo_arc(cr, x1 - radius, y0 + radius, radius, 3 * M_PI / 2, 2 * M_PI);
347 cairo_line_to(cr, x1, y1 - radius);
348 cairo_arc(cr, x1 - radius, y1 - radius, radius, 0, M_PI / 2);
349 cairo_line_to(cr, x0 + radius, y1);
350 cairo_arc(cr, x0 + radius, y1 - radius, radius, M_PI / 2, M_PI);
351 cairo_close_path(cr);
352}
353
354static void
355draw_button(cairo_t *cr, int x, int y, int width, int height, const char *text)
356{
357 cairo_pattern_t *gradient;
358 cairo_text_extents_t extents;
359 double bright = 0.15, dim = 0.02;
360 int radius = 10;
361
362 cairo_set_operator(cr, CAIRO_OPERATOR_OVER);
363 cairo_set_line_width (cr, 2);
364 rounded_rect(cr, x, y, x + width, y + height, radius);
365 cairo_set_source_rgb(cr, dim, dim, dim);
366 cairo_stroke(cr);
367 rounded_rect(cr, x + 2, y + 2, x + width, y + height, radius);
368 cairo_set_source_rgb(cr, 0.1, 0.1, 0.1);
369 cairo_stroke(cr);
370
371 rounded_rect(cr, x + 1, y + 1, x + width - 1, y + height - 1, radius - 1);
372 cairo_set_source_rgb(cr, bright, bright, bright);
373 cairo_stroke(cr);
374 rounded_rect(cr, x + 3, y + 3, x + width - 1, y + height - 1, radius - 1);
375 cairo_set_source_rgb(cr, dim, dim, dim);
376 cairo_stroke(cr);
377
378 rounded_rect(cr, x + 1, y + 1, x + width - 1, y + height - 1, radius - 1);
379 gradient = cairo_pattern_create_linear (0, y, 0, y + height);
380 cairo_pattern_add_color_stop_rgb(gradient, 0, 0.15, 0.15, 0.15);
381 cairo_pattern_add_color_stop_rgb(gradient, 0.5, 0.08, 0.08, 0.08);
382 cairo_pattern_add_color_stop_rgb(gradient, 0.5, 0.07, 0.07, 0.07);
383 cairo_pattern_add_color_stop_rgb(gradient, 1, 0.1, 0.1, 0.1);
384 cairo_set_source(cr, gradient);
385 cairo_fill(cr);
386
387 cairo_set_font_size(cr, 16);
388 cairo_text_extents(cr, text, &extents);
389 cairo_move_to(cr, x + (width - extents.width) / 2, y + (height - extents.height) / 2 - extents.y_bearing);
390 cairo_set_line_cap (cr, CAIRO_LINE_CAP_ROUND);
391 cairo_set_line_join (cr, CAIRO_LINE_JOIN_ROUND);
392 cairo_set_line_width (cr, 4);
393 cairo_text_path(cr, text);
394 cairo_set_source_rgb(cr, 0.0, 0.0, 0.0);
395 cairo_stroke_preserve(cr);
396 cairo_set_source_rgb(cr, 1, 1, 1);
397 cairo_fill(cr);
398}
399
400static struct egl_surface *
401overlay_create(int x, int y, int width, int height)
402{
403 struct egl_surface *es;
404 cairo_surface_t *surface;
405 cairo_t *cr;
406 int total_width, button_x, button_y;
407 const int button_width = 150;
408 const int button_height = 40;
409 const int spacing = 50;
410
411 surface = cairo_image_surface_create(CAIRO_FORMAT_ARGB32,
412 width, height);
413
414 cr = cairo_create(surface);
Kristian Høgsberg1e4b86a2008-11-23 23:41:08 -0500415 cairo_set_source_rgba(cr, 0.1, 0.1, 0.1, 0.8);
Kristian Høgsberg54879822008-11-23 17:07:32 -0500416 cairo_set_operator(cr, CAIRO_OPERATOR_SOURCE);
417 cairo_paint(cr);
418
419 total_width = button_width * 2 + spacing;
420 button_x = (width - total_width) / 2;
421 button_y = height - button_height - 20;
422 draw_button(cr, button_x, button_y, button_width, button_height, "Previous");
423 button_x += button_width + spacing;
424 draw_button(cr, button_x, button_y, button_width, button_height, "Next");
425
426 cairo_destroy(cr);
427
428 es = egl_surface_create_from_cairo_surface(surface, x, y, width, height);
429
430 cairo_surface_destroy(surface);
431
432 return es;
433}
434
435static void
Kristian Høgsbergaa5b5be2008-11-21 21:31:54 -0500436draw_surface(struct egl_surface *es)
Kristian Høgsberg4c9f2c92008-11-21 19:25:44 -0500437{
438 GLint vertices[12];
439 GLint tex_coords[12] = { 0, 0, 0, 1, 1, 0, 1, 1 };
440 GLuint indices[4] = { 0, 1, 2, 3 };
441
Kristian Høgsbergaa5b5be2008-11-21 21:31:54 -0500442 vertices[0] = es->map.x;
443 vertices[1] = es->map.y;
Kristian Høgsberg4c9f2c92008-11-21 19:25:44 -0500444 vertices[2] = 0;
445
Kristian Høgsbergaa5b5be2008-11-21 21:31:54 -0500446 vertices[3] = es->map.x;
447 vertices[4] = es->map.y + es->map.height;
Kristian Høgsberg4c9f2c92008-11-21 19:25:44 -0500448 vertices[5] = 0;
449
Kristian Høgsbergaa5b5be2008-11-21 21:31:54 -0500450 vertices[6] = es->map.x + es->map.width;
451 vertices[7] = es->map.y;
Kristian Høgsberg4c9f2c92008-11-21 19:25:44 -0500452 vertices[8] = 0;
453
Kristian Høgsbergaa5b5be2008-11-21 21:31:54 -0500454 vertices[9] = es->map.x + es->map.width;
455 vertices[10] = es->map.y + es->map.height;
Kristian Høgsberg4c9f2c92008-11-21 19:25:44 -0500456 vertices[11] = 0;
457
Kristian Høgsbergaa5b5be2008-11-21 21:31:54 -0500458 glBindTexture(GL_TEXTURE_2D, es->texture);
Kristian Høgsberg4c9f2c92008-11-21 19:25:44 -0500459 glEnable(GL_TEXTURE_2D);
460 glEnable(GL_BLEND);
461 /* Assume pre-multiplied alpha for now, this probably
462 * needs to be a wayland visual type of thing. */
463 glBlendFunc(GL_ONE, GL_ONE_MINUS_SRC_ALPHA);
464
465 glEnableClientState(GL_VERTEX_ARRAY);
466 glEnableClientState(GL_TEXTURE_COORD_ARRAY);
467 glVertexPointer(3, GL_INT, 0, vertices);
468 glTexCoordPointer(2, GL_INT, 0, tex_coords);
469 glDrawElements(GL_TRIANGLE_STRIP, 4, GL_UNSIGNED_INT, indices);
470}
471
472static void
Kristian Høgsberg9af92b32008-11-24 01:12:46 -0500473schedule_repaint(struct egl_compositor *ec);
474
475static void
Kristian Høgsbergef7a9ca2008-10-11 21:21:39 -0400476repaint(void *data)
477{
478 struct egl_compositor *ec = data;
479 struct wl_surface_iterator *iterator;
480 struct wl_surface *surface;
Kristian Høgsbergaa5b5be2008-11-21 21:31:54 -0500481 struct egl_surface *es;
Kristian Høgsberg9af92b32008-11-24 01:12:46 -0500482 double force;
483 int32_t y;
Kristian Høgsbergaa5b5be2008-11-21 21:31:54 -0500484
485 draw_surface(ec->background);
Kristian Høgsbergef7a9ca2008-10-11 21:21:39 -0400486
487 iterator = wl_surface_iterator_create(ec->wl_display, 0);
488 while (wl_surface_iterator_next(iterator, &surface)) {
Kristian Høgsbergaa5b5be2008-11-21 21:31:54 -0500489 es = wl_surface_get_data(surface);
490 if (es == NULL)
Kristian Høgsbergef7a9ca2008-10-11 21:21:39 -0400491 continue;
492
Kristian Høgsbergaa5b5be2008-11-21 21:31:54 -0500493 draw_surface(es);
Kristian Høgsbergef7a9ca2008-10-11 21:21:39 -0400494 }
495 wl_surface_iterator_destroy(iterator);
496
Kristian Høgsberg54879822008-11-23 17:07:32 -0500497 draw_surface(ec->overlay);
498
Kristian Høgsbergaa5b5be2008-11-21 21:31:54 -0500499 draw_surface(ec->pointer);
Kristian Høgsberg4c9f2c92008-11-21 19:25:44 -0500500
Kristian Høgsbergef7a9ca2008-10-11 21:21:39 -0400501 eglSwapBuffers(ec->display, ec->surface);
Kristian Høgsberg9af92b32008-11-24 01:12:46 -0500502
503 y = ec->overlay->map.y;
504 force = (ec->overlay_target - ec->overlay->map.y) / 25.0 +
505 (ec->overlay_previous - y) / 25.0;
506
507 ec->overlay->map.y = y + (y - ec->overlay_previous) + force;
508 ec->overlay_previous = y;
509
510 if (ec->overlay->map.y >= 800) {
511 ec->overlay->map.y = 800;
512 ec->overlay_previous = 800;
513 }
514
515 if (ec->overlay->map.y <= 600) {
516 ec->overlay->map.y = 600;
517 ec->overlay_previous = 600;
518 }
519
520 if (ec->overlay->map.y != y)
521 schedule_repaint(ec);
Kristian Høgsbergef7a9ca2008-10-11 21:21:39 -0400522}
523
Kristian Høgsberg5503bf82008-11-06 10:38:17 -0500524static void
525schedule_repaint(struct egl_compositor *ec)
Kristian Høgsbergef7a9ca2008-10-11 21:21:39 -0400526{
527 struct wl_event_loop *loop;
528
529 loop = wl_display_get_event_loop(ec->wl_display);
530 wl_event_loop_add_idle(loop, repaint, ec);
531}
532
Kristian Høgsberg5503bf82008-11-06 10:38:17 -0500533static void
534notify_surface_create(struct wl_compositor *compositor,
535 struct wl_surface *surface)
Kristian Høgsberg16eb6752008-10-08 22:51:32 -0400536{
Kristian Høgsbergaa5b5be2008-11-21 21:31:54 -0500537 struct egl_surface *es;
Kristian Høgsberg16eb6752008-10-08 22:51:32 -0400538
Kristian Høgsbergaa5b5be2008-11-21 21:31:54 -0500539 es = malloc(sizeof *es);
540 if (es == NULL)
Kristian Høgsberg16eb6752008-10-08 22:51:32 -0400541 return;
542
Kristian Høgsbergaa5b5be2008-11-21 21:31:54 -0500543 es->surface = EGL_NO_SURFACE;
544 wl_surface_set_data(surface, es);
Kristian Høgsberg16eb6752008-10-08 22:51:32 -0400545
Kristian Høgsbergaa5b5be2008-11-21 21:31:54 -0500546 glGenTextures(1, &es->texture);
Kristian Høgsberg16eb6752008-10-08 22:51:32 -0400547}
548
Kristian Høgsberg5503bf82008-11-06 10:38:17 -0500549static void
550notify_surface_destroy(struct wl_compositor *compositor,
551 struct wl_surface *surface)
Kristian Høgsberg16eb6752008-10-08 22:51:32 -0400552{
553 struct egl_compositor *ec = (struct egl_compositor *) compositor;
Kristian Høgsbergaa5b5be2008-11-21 21:31:54 -0500554 struct egl_surface *es;
Kristian Høgsberg16eb6752008-10-08 22:51:32 -0400555
Kristian Høgsbergaa5b5be2008-11-21 21:31:54 -0500556 es = wl_surface_get_data(surface);
557 if (es == NULL)
Kristian Høgsberg16eb6752008-10-08 22:51:32 -0400558 return;
Kristian Høgsberg2d9cd1e2008-11-03 08:09:34 -0500559
Kristian Høgsbergaa5b5be2008-11-21 21:31:54 -0500560 egl_surface_destroy(es, ec);
Kristian Høgsbergef7a9ca2008-10-11 21:21:39 -0400561
562 schedule_repaint(ec);
Kristian Høgsberg16eb6752008-10-08 22:51:32 -0400563}
564
Kristian Høgsberg5503bf82008-11-06 10:38:17 -0500565static void
566notify_surface_attach(struct wl_compositor *compositor,
567 struct wl_surface *surface, uint32_t name,
568 uint32_t width, uint32_t height, uint32_t stride)
Kristian Høgsberg16eb6752008-10-08 22:51:32 -0400569{
570 struct egl_compositor *ec = (struct egl_compositor *) compositor;
Kristian Høgsbergaa5b5be2008-11-21 21:31:54 -0500571 struct egl_surface *es;
Kristian Høgsberg16eb6752008-10-08 22:51:32 -0400572
Kristian Høgsbergaa5b5be2008-11-21 21:31:54 -0500573 es = wl_surface_get_data(surface);
574 if (es == NULL)
Kristian Høgsberg16eb6752008-10-08 22:51:32 -0400575 return;
576
Kristian Høgsbergaa5b5be2008-11-21 21:31:54 -0500577 if (es->surface != EGL_NO_SURFACE)
578 eglDestroySurface(ec->display, es->surface);
Kristian Høgsberg16eb6752008-10-08 22:51:32 -0400579
Kristian Høgsberg56f3c712008-11-05 07:55:45 -0500580 /* FIXME: We need to use a single buffer config without depth
581 * or stencil buffers here to keep egl from creating auxillary
582 * buffers for the pixmap here. */
Kristian Høgsbergaa5b5be2008-11-21 21:31:54 -0500583 es->surface = eglCreateSurfaceForName(ec->display, ec->config,
Kristian Høgsberg78231c82008-11-08 15:06:01 -0500584 name, width, height, stride, NULL);
Kristian Høgsberg16eb6752008-10-08 22:51:32 -0400585
Kristian Høgsbergaa5b5be2008-11-21 21:31:54 -0500586 glBindTexture(GL_TEXTURE_2D, es->texture);
Kristian Høgsberg16eb6752008-10-08 22:51:32 -0400587 glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
588 glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_R, GL_REPEAT);
589 glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
590 glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
Kristian Høgsbergaa5b5be2008-11-21 21:31:54 -0500591 eglBindTexImage(ec->display, es->surface, GL_TEXTURE_2D);
Kristian Høgsberg16eb6752008-10-08 22:51:32 -0400592
Kristian Høgsbergef7a9ca2008-10-11 21:21:39 -0400593 schedule_repaint(ec);
Kristian Høgsbergf9212892008-10-11 18:40:23 -0400594}
595
Kristian Høgsberg5503bf82008-11-06 10:38:17 -0500596static void
597notify_surface_map(struct wl_compositor *compositor,
598 struct wl_surface *surface, struct wl_map *map)
Kristian Høgsberg16eb6752008-10-08 22:51:32 -0400599{
600 struct egl_compositor *ec = (struct egl_compositor *) compositor;
Kristian Høgsbergaa5b5be2008-11-21 21:31:54 -0500601 struct egl_surface *es;
Kristian Høgsberg16eb6752008-10-08 22:51:32 -0400602
Kristian Høgsbergaa5b5be2008-11-21 21:31:54 -0500603 es = wl_surface_get_data(surface);
604 if (es == NULL)
Kristian Høgsberg16eb6752008-10-08 22:51:32 -0400605 return;
606
Kristian Høgsbergaa5b5be2008-11-21 21:31:54 -0500607 es->map = *map;
Kristian Høgsberg5ebb3172008-10-11 19:21:35 -0400608
Kristian Høgsbergef7a9ca2008-10-11 21:21:39 -0400609 schedule_repaint(ec);
Kristian Høgsberg16eb6752008-10-08 22:51:32 -0400610}
611
Kristian Høgsberg7f77bd82008-11-07 08:39:37 -0500612static void
613notify_surface_copy(struct wl_compositor *compositor,
614 struct wl_surface *surface,
615 int32_t dst_x, int32_t dst_y,
616 uint32_t name, uint32_t stride,
617 int32_t x, int32_t y, int32_t width, int32_t height)
618{
Kristian Høgsberg78231c82008-11-08 15:06:01 -0500619 struct egl_compositor *ec = (struct egl_compositor *) compositor;
620 EGLSurface src;
Kristian Høgsbergaa5b5be2008-11-21 21:31:54 -0500621 struct egl_surface *es;
Kristian Høgsberg78231c82008-11-08 15:06:01 -0500622
Kristian Høgsbergaa5b5be2008-11-21 21:31:54 -0500623 es = wl_surface_get_data(surface);
Kristian Høgsberg78231c82008-11-08 15:06:01 -0500624
625 /* FIXME: glCopyPixels should work, but then we'll have to
626 * call eglMakeCurrent to set up the src and dest surfaces
627 * first. This seems cheaper, but maybe there's a better way
628 * to accomplish this. */
629
630 src = eglCreateSurfaceForName(ec->display, ec->config,
631 name, x + width, y + height, stride, NULL);
632
Kristian Høgsbergaa5b5be2008-11-21 21:31:54 -0500633 eglCopyNativeBuffers(ec->display, es->surface, GL_FRONT_LEFT, dst_x, dst_y,
Kristian Høgsberg78231c82008-11-08 15:06:01 -0500634 src, GL_FRONT_LEFT, x, y, width, height);
635 schedule_repaint(ec);
Kristian Høgsberg7f77bd82008-11-07 08:39:37 -0500636}
637
638static void
639notify_surface_damage(struct wl_compositor *compositor,
Kristian Høgsberg78231c82008-11-08 15:06:01 -0500640 struct wl_surface *surface,
641 int32_t x, int32_t y, int32_t width, int32_t height)
Kristian Høgsberg7f77bd82008-11-07 08:39:37 -0500642{
643 struct egl_compositor *ec = (struct egl_compositor *) compositor;
644
645 /* FIXME: This need to take a damage region, of course. */
646 schedule_repaint(ec);
647}
648
Kristian Høgsberg4c9f2c92008-11-21 19:25:44 -0500649static void
650notify_pointer_motion(struct wl_compositor *compositor,
651 struct wl_object *source, int x, int y)
652{
653 struct egl_compositor *ec = (struct egl_compositor *) compositor;
654
655 ec->pointer->map.x = x;
656 ec->pointer->map.y = y;
657 schedule_repaint(ec);
658}
659
Kristian Høgsbergcddc0ad2008-11-24 00:31:49 -0500660static void
661notify_key(struct wl_compositor *compositor,
662 struct wl_object *source, uint32_t key, uint32_t state)
663{
664 struct egl_compositor *ec = (struct egl_compositor *) compositor;
665
Kristian Høgsberg9af92b32008-11-24 01:12:46 -0500666 if (key == KEY_ESC && state == 1) {
667 if (ec->overlay_target == ec->height)
668 ec->overlay_target -= 200;
669 else
670 ec->overlay_target += 200;
Kristian Høgsbergcddc0ad2008-11-24 00:31:49 -0500671 schedule_repaint(ec);
Kristian Høgsberg9af92b32008-11-24 01:12:46 -0500672 }
Kristian Høgsbergcddc0ad2008-11-24 00:31:49 -0500673}
674
Kristian Høgsberg5503bf82008-11-06 10:38:17 -0500675static const struct wl_compositor_interface interface = {
Kristian Høgsberg16eb6752008-10-08 22:51:32 -0400676 notify_surface_create,
677 notify_surface_destroy,
678 notify_surface_attach,
Kristian Høgsberg7f77bd82008-11-07 08:39:37 -0500679 notify_surface_map,
680 notify_surface_copy,
Kristian Høgsberg4c9f2c92008-11-21 19:25:44 -0500681 notify_surface_damage,
Kristian Høgsbergcddc0ad2008-11-24 00:31:49 -0500682 notify_pointer_motion,
683 notify_key
Kristian Høgsberg16eb6752008-10-08 22:51:32 -0400684};
685
Kristian Høgsbergcddc0ad2008-11-24 00:31:49 -0500686static const char pointer_device_file[] =
687 "/dev/input/by-id/usb-Apple__Inc._Apple_Internal_Keyboard_._Trackpad-event-mouse";
688static const char keyboard_device_file[] =
689 "/dev/input/by-id/usb-Apple__Inc._Apple_Internal_Keyboard_._Trackpad-event-kbd";
690
691static void
692create_input_devices(struct wl_display *display)
693{
694 struct wl_object *obj;
695 const char *path;
696
697 path = getenv("WAYLAND_POINTER");
698 if (path == NULL)
699 path = pointer_device_file;
700
701 obj = wl_input_device_create(display, path);
702 if (obj != NULL)
703 wl_display_add_object(display, obj);
704
705 path = getenv("WAYLAND_KEYBOARD");
706 if (path == NULL)
707 path = keyboard_device_file;
708
709 obj = wl_input_device_create(display, path);
710 if (obj != NULL)
711 wl_display_add_object(display, obj);
712}
713
Kristian Høgsberg16eb6752008-10-08 22:51:32 -0400714static const char gem_device[] = "/dev/dri/card0";
715
Kristian Høgsbergb7a01922008-11-08 15:39:41 -0500716WL_EXPORT struct wl_compositor *
Kristian Høgsbergf9212892008-10-11 18:40:23 -0400717wl_compositor_create(struct wl_display *display)
Kristian Høgsberg16eb6752008-10-08 22:51:32 -0400718{
719 EGLConfig configs[64];
720 EGLint major, minor, count;
721 struct egl_compositor *ec;
Kristian Høgsbergaa5b5be2008-11-21 21:31:54 -0500722 const char *filename;
Kristian Høgsberg1e4b86a2008-11-23 23:41:08 -0500723 struct screenshooter *shooter;
Kristian Høgsberg16eb6752008-10-08 22:51:32 -0400724
725 ec = malloc(sizeof *ec);
726 if (ec == NULL)
727 return NULL;
728
Kristian Høgsberg8d7ca6b2008-11-09 00:22:51 -0500729 ec->width = 1280;
730 ec->height = 800;
731
Kristian Høgsberg16eb6752008-10-08 22:51:32 -0400732 ec->base.interface = &interface;
Kristian Høgsbergf9212892008-10-11 18:40:23 -0400733 ec->wl_display = display;
Kristian Høgsberg16eb6752008-10-08 22:51:32 -0400734
Kristian Høgsbergc508d932008-10-13 22:52:42 -0400735 ec->display = eglCreateDisplayNative(gem_device, "i965");
Kristian Høgsberg16eb6752008-10-08 22:51:32 -0400736 if (ec->display == NULL) {
737 fprintf(stderr, "failed to create display\n");
738 return NULL;
739 }
740
741 if (!eglInitialize(ec->display, &major, &minor)) {
742 fprintf(stderr, "failed to initialize display\n");
743 return NULL;
744 }
745
746 if (!eglGetConfigs(ec->display, configs, ARRAY_LENGTH(configs), &count)) {
747 fprintf(stderr, "failed to get configs\n");
748 return NULL;
749 }
750
Kristian Høgsberg2d9cd1e2008-11-03 08:09:34 -0500751 ec->config = configs[24];
752 ec->surface = eglCreateSurfaceNative(ec->display, ec->config,
Kristian Høgsberg8d7ca6b2008-11-09 00:22:51 -0500753 0, 0, ec->width, ec->height);
Kristian Høgsberg16eb6752008-10-08 22:51:32 -0400754 if (ec->surface == NULL) {
755 fprintf(stderr, "failed to create surface\n");
756 return NULL;
757 }
758
Kristian Høgsberg2d9cd1e2008-11-03 08:09:34 -0500759 ec->context = eglCreateContext(ec->display, ec->config, NULL, NULL);
Kristian Høgsberg16eb6752008-10-08 22:51:32 -0400760 if (ec->context == NULL) {
761 fprintf(stderr, "failed to create context\n");
762 return NULL;
763 }
764
765 if (!eglMakeCurrent(ec->display, ec->surface, ec->surface, ec->context)) {
766 fprintf(stderr, "failed to make context current\n");
767 return NULL;
768 }
769
Kristian Høgsberg8d7ca6b2008-11-09 00:22:51 -0500770 glViewport(0, 0, ec->width, ec->height);
Kristian Høgsberg16eb6752008-10-08 22:51:32 -0400771 glMatrixMode(GL_PROJECTION);
772 glLoadIdentity();
Kristian Høgsberg8d7ca6b2008-11-09 00:22:51 -0500773 glOrtho(0, ec->width, ec->height, 0, 0, 1000.0);
Kristian Høgsberg16eb6752008-10-08 22:51:32 -0400774 glMatrixMode(GL_MODELVIEW);
Kristian Høgsbergcddc0ad2008-11-24 00:31:49 -0500775
776 create_input_devices(display);
Kristian Høgsberg16eb6752008-10-08 22:51:32 -0400777
Kristian Høgsbergaa5b5be2008-11-21 21:31:54 -0500778 filename = getenv("WAYLAND_BACKGROUND");
779 if (filename == NULL)
780 filename = "background.jpg";
781 ec->background = background_create(filename, 1280, 800);
Kristian Høgsberg4c9f2c92008-11-21 19:25:44 -0500782 ec->pointer = pointer_create(100, 100, 64, 64);
Kristian Høgsberg9af92b32008-11-24 01:12:46 -0500783 ec->overlay = overlay_create(0, ec->height, ec->width, 200);
784 ec->overlay_target = ec->height;
785 ec->overlay_previous = ec->height;
Kristian Høgsberg4c9f2c92008-11-21 19:25:44 -0500786
Kristian Høgsberg16eb6752008-10-08 22:51:32 -0400787 ec->gem_fd = open(gem_device, O_RDWR);
788 if (ec->gem_fd < 0) {
789 fprintf(stderr, "failed to open drm device\n");
790 return NULL;
791 }
792
Kristian Høgsberg1e4b86a2008-11-23 23:41:08 -0500793 shooter = screenshooter_create(ec);
794 wl_display_add_object(display, &shooter->base);
795 wl_display_add_global(display, &shooter->base);
Kristian Høgsberg8d7ca6b2008-11-09 00:22:51 -0500796
Kristian Høgsbergef7a9ca2008-10-11 21:21:39 -0400797 schedule_repaint(ec);
798
Kristian Høgsberg16eb6752008-10-08 22:51:32 -0400799 return &ec->base;
800}