blob: dddd98ac738e4d878fed7501f3a4784090dc7fb8 [file] [log] [blame]
Kristian Høgsbergffd710e2008-12-02 15:15:01 -05001/*
2 * Copyright © 2008 Kristian Høgsberg
3 *
4 * Permission to use, copy, modify, distribute, and sell this software and its
5 * documentation for any purpose is hereby granted without fee, provided that
6 * the above copyright notice appear in all copies and that both that copyright
7 * notice and this permission notice appear in supporting documentation, and
8 * that the name of the copyright holders not be used in advertising or
9 * publicity pertaining to distribution of the software without specific,
10 * written prior permission. The copyright holders make no representations
11 * about the suitability of this software for any purpose. It is provided "as
12 * is" without express or implied warranty.
13 *
14 * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
15 * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
16 * EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY SPECIAL, INDIRECT OR
17 * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
18 * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
19 * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
20 * OF THIS SOFTWARE.
21 */
22
Kristian Høgsberg16eb6752008-10-08 22:51:32 -040023#include <stdio.h>
24#include <string.h>
25#include <stdlib.h>
26#include <stdint.h>
Kristian Høgsberg8d7ca6b2008-11-09 00:22:51 -050027#include <stdarg.h>
Kristian Høgsberg16eb6752008-10-08 22:51:32 -040028#include <i915_drm.h>
29#include <sys/ioctl.h>
30#include <sys/mman.h>
31#include <fcntl.h>
32#include <unistd.h>
Kristian Høgsberg8d7ca6b2008-11-09 00:22:51 -050033#include <signal.h>
Kristian Høgsberg4c9f2c92008-11-21 19:25:44 -050034#include <cairo.h>
Kristian Høgsbergaa5b5be2008-11-21 21:31:54 -050035#include <gdk-pixbuf/gdk-pixbuf.h>
36#include <glib.h>
Kristian Høgsbergfbdbbdc2008-11-28 17:06:06 -050037#include <sys/poll.h>
Kristian Høgsberg8d7ca6b2008-11-09 00:22:51 -050038#include <png.h>
Kristian Høgsberg54879822008-11-23 17:07:32 -050039#include <math.h>
Kristian Høgsbergcddc0ad2008-11-24 00:31:49 -050040#include <linux/input.h>
Kristian Høgsbergbf9541f2008-11-25 12:10:09 -050041#include <xf86drmMode.h>
Kristian Høgsbergfbdbbdc2008-11-28 17:06:06 -050042#include <time.h>
Kristian Høgsberg16eb6752008-10-08 22:51:32 -040043
44#include "wayland.h"
Kristian Høgsberg4c9f2c92008-11-21 19:25:44 -050045#include "cairo-util.h"
Kristian Høgsberg16eb6752008-10-08 22:51:32 -040046
47#include <GL/gl.h>
48#include <eagle.h>
49
50#define ARRAY_LENGTH(a) (sizeof (a) / sizeof (a)[0])
51
52struct egl_compositor {
53 struct wl_compositor base;
54 EGLDisplay display;
55 EGLSurface surface;
56 EGLContext context;
Kristian Høgsberg2d9cd1e2008-11-03 08:09:34 -050057 EGLConfig config;
Kristian Høgsbergf9212892008-10-11 18:40:23 -040058 struct wl_display *wl_display;
Kristian Høgsberg16eb6752008-10-08 22:51:32 -040059 int gem_fd;
Kristian Høgsberg8d7ca6b2008-11-09 00:22:51 -050060 int width, height;
Kristian Høgsbergaa5b5be2008-11-21 21:31:54 -050061 struct egl_surface *pointer;
62 struct egl_surface *background;
Kristian Høgsberg54879822008-11-23 17:07:32 -050063 struct egl_surface *overlay;
Kristian Høgsberg5c1e6ec2008-11-25 13:51:36 -050064 double overlay_y, overlay_target, overlay_previous;
Kristian Høgsbergfbdbbdc2008-11-28 17:06:06 -050065
66 /* Repaint state. */
67 struct wl_event_source *timer_source;
68 int repaint_needed;
69 int repaint_on_timeout;
Kristian Høgsbergfbdbbdc2008-11-28 17:06:06 -050070 struct timespec previous_swap;
71 uint32_t current_frame;
Kristian Høgsberg16eb6752008-10-08 22:51:32 -040072};
73
Kristian Høgsbergaa5b5be2008-11-21 21:31:54 -050074struct egl_surface {
Kristian Høgsberg16eb6752008-10-08 22:51:32 -040075 GLuint texture;
Kristian Høgsbergf9212892008-10-11 18:40:23 -040076 struct wl_map map;
Kristian Høgsberg2d9cd1e2008-11-03 08:09:34 -050077 EGLSurface surface;
Kristian Høgsberg16eb6752008-10-08 22:51:32 -040078};
79
Kristian Høgsberg8d7ca6b2008-11-09 00:22:51 -050080static void
81die(const char *msg, ...)
82{
83 va_list ap;
84
85 va_start (ap, msg);
86 vfprintf(stderr, msg, ap);
87 va_end (ap);
88
89 exit(EXIT_FAILURE);
90}
91
92static void
93stdio_write_func (png_structp png, png_bytep data, png_size_t size)
94{
95 FILE *fp;
96 size_t ret;
97
98 fp = png_get_io_ptr (png);
99 while (size) {
100 ret = fwrite (data, 1, size, fp);
101 size -= ret;
102 data += ret;
103 if (size && ferror (fp))
104 die("write: %m\n");
105 }
106}
107
108static void
109png_simple_output_flush_fn (png_structp png_ptr)
110{
111}
112
113static void
114png_simple_error_callback (png_structp png,
115 png_const_charp error_msg)
116{
117 die("png error: %s\n", error_msg);
118}
119
120static void
121png_simple_warning_callback (png_structp png,
122 png_const_charp error_msg)
123{
124 fprintf(stderr, "png warning: %s\n", error_msg);
125}
126
127static void
128convert_pixels(png_structp png, png_row_infop row_info, png_bytep data)
129{
130 unsigned int i;
131
132 for (i = 0; i < row_info->rowbytes; i += 4) {
133 uint8_t *b = &data[i];
134 uint32_t pixel;
135
136 memcpy (&pixel, b, sizeof (uint32_t));
137 b[0] = (pixel & 0xff0000) >> 16;
138 b[1] = (pixel & 0x00ff00) >> 8;
139 b[2] = (pixel & 0x0000ff) >> 0;
140 b[3] = 0;
141 }
142}
143
Kristian Høgsberg1e4b86a2008-11-23 23:41:08 -0500144struct screenshooter {
145 struct wl_object base;
146 struct egl_compositor *ec;
147};
148
Kristian Høgsberg8d7ca6b2008-11-09 00:22:51 -0500149static void
Kristian Høgsberg1e4b86a2008-11-23 23:41:08 -0500150screenshooter_shoot(struct wl_client *client, struct screenshooter *shooter)
Kristian Høgsberg8d7ca6b2008-11-09 00:22:51 -0500151{
Kristian Høgsberg1e4b86a2008-11-23 23:41:08 -0500152 struct egl_compositor *ec = shooter->ec;
Kristian Høgsberg8d7ca6b2008-11-09 00:22:51 -0500153 png_struct *png;
154 png_info *info;
155 png_byte **volatile rows = NULL;
156 png_color_16 white;
157 int depth, i;
158 FILE *fp;
159 uint8_t *data;
160 GLuint stride;
161 static const char filename[] = "wayland-screenshot.png";
162
163 data = eglReadBuffer(ec->display, ec->surface, GL_FRONT_LEFT, &stride);
164 if (data == NULL)
165 die("eglReadBuffer failed\n");
166 rows = malloc(ec->height * sizeof rows[0]);
167 if (rows == NULL)
168 die("malloc failed\n");
169
170 for (i = 0; i < ec->height; i++)
171 rows[i] = (png_byte *) data + i * stride;
172
173 png = png_create_write_struct(PNG_LIBPNG_VER_STRING, NULL,
174 png_simple_error_callback,
175 png_simple_warning_callback);
176 if (png == NULL)
177 die("png_create_write_struct failed\n");
178
179 info = png_create_info_struct(png);
180 if (info == NULL)
181 die("png_create_info_struct failed\n");
182
183 fp = fopen(filename, "w");
184 if (fp == NULL)
185 die("fopen failed: %m\n");
186
187 png_set_write_fn(png, fp, stdio_write_func, png_simple_output_flush_fn);
188
189 depth = 8;
190 png_set_IHDR(png, info,
191 ec->width,
192 ec->height, depth,
193 PNG_COLOR_TYPE_RGB,
194 PNG_INTERLACE_NONE,
195 PNG_COMPRESSION_TYPE_DEFAULT,
196 PNG_FILTER_TYPE_DEFAULT);
197
198 white.gray = (1 << depth) - 1;
199 white.red = white.blue = white.green = white.gray;
200 png_set_bKGD(png, info, &white);
201 png_write_info (png, info);
202 png_set_write_user_transform_fn(png, convert_pixels);
203
204 png_set_filler(png, 0, PNG_FILLER_AFTER);
205 png_write_image(png, rows);
206 png_write_end(png, info);
207
208 png_destroy_write_struct(&png, &info);
209 fclose(fp);
210 free(rows);
211 free(data);
212}
213
Kristian Høgsberg1e4b86a2008-11-23 23:41:08 -0500214static const struct wl_method screenshooter_methods[] = {
215 { "shoot", screenshooter_shoot, 0, NULL }
216};
217
218static const struct wl_interface screenshooter_interface = {
219 "screenshooter", 1,
220 ARRAY_LENGTH(screenshooter_methods),
221 screenshooter_methods,
222};
223
224static struct screenshooter *
225screenshooter_create(struct egl_compositor *ec)
226{
227 struct screenshooter *shooter;
228
229 shooter = malloc(sizeof *shooter);
230 if (shooter == NULL)
231 return NULL;
232
233 shooter->base.interface = &screenshooter_interface;
234 shooter->ec = ec;
235
236 return shooter;
237};
238
Kristian Høgsberg54879822008-11-23 17:07:32 -0500239static struct egl_surface *
240egl_surface_create_from_cairo_surface(cairo_surface_t *surface,
241 int x, int y, int width, int height)
242{
243 struct egl_surface *es;
244 int stride;
245 void *data;
246
247 stride = cairo_image_surface_get_stride(surface);
248 data = cairo_image_surface_get_data(surface);
249
250 es = malloc(sizeof *es);
251 if (es == NULL)
252 return NULL;
253
254 glGenTextures(1, &es->texture);
255 glBindTexture(GL_TEXTURE_2D, es->texture);
256 glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
257 glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_R, GL_REPEAT);
258 glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
259 glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
260 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0,
261 GL_BGRA, GL_UNSIGNED_BYTE, data);
262
263 es->map.x = x;
264 es->map.y = y;
265 es->map.width = width;
266 es->map.height = height;
267 es->surface = EGL_NO_SURFACE;
268
269 return es;
270}
271
272static void
273egl_surface_destroy(struct egl_surface *es, struct egl_compositor *ec)
274{
275 glDeleteTextures(1, &es->texture);
276 if (es->surface != EGL_NO_SURFACE)
277 eglDestroySurface(ec->display, es->surface);
278 free(es);
279}
280
Kristian Høgsbergef7a9ca2008-10-11 21:21:39 -0400281static void
Kristian Høgsberg4c9f2c92008-11-21 19:25:44 -0500282pointer_path(cairo_t *cr, int x, int y)
283{
284 const int end = 3, tx = 4, ty = 12, dx = 5, dy = 10;
285 const int width = 16, height = 16;
286
287 cairo_move_to(cr, x, y);
288 cairo_line_to(cr, x + tx, y + ty);
289 cairo_line_to(cr, x + dx, y + dy);
290 cairo_line_to(cr, x + width - end, y + height);
291 cairo_line_to(cr, x + width, y + height - end);
292 cairo_line_to(cr, x + dy, y + dx);
293 cairo_line_to(cr, x + ty, y + tx);
294 cairo_close_path(cr);
295}
296
Kristian Høgsbergaa5b5be2008-11-21 21:31:54 -0500297static struct egl_surface *
Kristian Høgsberg4c9f2c92008-11-21 19:25:44 -0500298pointer_create(int x, int y, int width, int height)
299{
Kristian Høgsberg54879822008-11-23 17:07:32 -0500300 struct egl_surface *es;
Kristian Høgsberg4c9f2c92008-11-21 19:25:44 -0500301 const int hotspot_x = 16, hotspot_y = 16;
Kristian Høgsberg4c9f2c92008-11-21 19:25:44 -0500302 cairo_surface_t *surface;
303 cairo_t *cr;
Kristian Høgsberg4c9f2c92008-11-21 19:25:44 -0500304
305 surface = cairo_image_surface_create(CAIRO_FORMAT_ARGB32,
306 width, height);
307
308 cr = cairo_create(surface);
309 pointer_path(cr, hotspot_x + 5, hotspot_y + 4);
310 cairo_set_line_width (cr, 2);
311 cairo_set_source_rgb(cr, 0, 0, 0);
312 cairo_stroke_preserve(cr);
313 cairo_fill(cr);
314 blur_surface(surface, width);
315
316 pointer_path(cr, hotspot_x, hotspot_y);
317 cairo_stroke_preserve(cr);
318 cairo_set_source_rgb(cr, 1, 1, 1);
319 cairo_fill(cr);
320 cairo_destroy(cr);
321
Kristian Høgsberg54879822008-11-23 17:07:32 -0500322 es = egl_surface_create_from_cairo_surface(surface, x, y, width, height);
323
Kristian Høgsberg4c9f2c92008-11-21 19:25:44 -0500324 cairo_surface_destroy(surface);
325
Kristian Høgsberg54879822008-11-23 17:07:32 -0500326 return es;
Kristian Høgsbergaa5b5be2008-11-21 21:31:54 -0500327}
328
329static struct egl_surface *
330background_create(const char *filename, int width, int height)
331{
332 struct egl_surface *background;
333 GdkPixbuf *pixbuf;
334 GError *error = NULL;
335 int pixbuf_width, pixbuf_height;
336 void *data;
337
338 background = malloc(sizeof *background);
339 if (background == NULL)
340 return NULL;
341
342 g_type_init();
343
344 pixbuf = gdk_pixbuf_new_from_file(filename, &error);
345 if (error != NULL) {
346 free(background);
347 return NULL;
348 }
349
350 pixbuf_width = gdk_pixbuf_get_width(pixbuf);
351 pixbuf_height = gdk_pixbuf_get_height(pixbuf);
352 data = gdk_pixbuf_get_pixels(pixbuf);
353
354 glGenTextures(1, &background->texture);
355 glBindTexture(GL_TEXTURE_2D, background->texture);
356 glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
357 glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_R, GL_REPEAT);
358 glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
359 glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
360 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, pixbuf_width, pixbuf_height, 0,
361 GL_BGR, GL_UNSIGNED_BYTE, data);
362
363 background->map.x = 0;
364 background->map.y = 0;
365 background->map.width = width;
366 background->map.height = height;
367 background->surface = EGL_NO_SURFACE;
368
369 return background;
Kristian Høgsberg4c9f2c92008-11-21 19:25:44 -0500370}
371
372static void
Kristian Høgsberg54879822008-11-23 17:07:32 -0500373rounded_rect(cairo_t *cr, int x0, int y0, int x1, int y1, int radius)
374{
375 cairo_move_to(cr, x0, y0 + radius);
376 cairo_arc(cr, x0 + radius, y0 + radius, radius, M_PI, 3 * M_PI / 2);
377 cairo_line_to(cr, x1 - radius, y0);
378 cairo_arc(cr, x1 - radius, y0 + radius, radius, 3 * M_PI / 2, 2 * M_PI);
379 cairo_line_to(cr, x1, y1 - radius);
380 cairo_arc(cr, x1 - radius, y1 - radius, radius, 0, M_PI / 2);
381 cairo_line_to(cr, x0 + radius, y1);
382 cairo_arc(cr, x0 + radius, y1 - radius, radius, M_PI / 2, M_PI);
383 cairo_close_path(cr);
384}
385
386static void
387draw_button(cairo_t *cr, int x, int y, int width, int height, const char *text)
388{
389 cairo_pattern_t *gradient;
390 cairo_text_extents_t extents;
391 double bright = 0.15, dim = 0.02;
392 int radius = 10;
393
394 cairo_set_operator(cr, CAIRO_OPERATOR_OVER);
395 cairo_set_line_width (cr, 2);
396 rounded_rect(cr, x, y, x + width, y + height, radius);
397 cairo_set_source_rgb(cr, dim, dim, dim);
398 cairo_stroke(cr);
399 rounded_rect(cr, x + 2, y + 2, x + width, y + height, radius);
400 cairo_set_source_rgb(cr, 0.1, 0.1, 0.1);
401 cairo_stroke(cr);
402
403 rounded_rect(cr, x + 1, y + 1, x + width - 1, y + height - 1, radius - 1);
404 cairo_set_source_rgb(cr, bright, bright, bright);
405 cairo_stroke(cr);
406 rounded_rect(cr, x + 3, y + 3, x + width - 1, y + height - 1, radius - 1);
407 cairo_set_source_rgb(cr, dim, dim, dim);
408 cairo_stroke(cr);
409
410 rounded_rect(cr, x + 1, y + 1, x + width - 1, y + height - 1, radius - 1);
411 gradient = cairo_pattern_create_linear (0, y, 0, y + height);
412 cairo_pattern_add_color_stop_rgb(gradient, 0, 0.15, 0.15, 0.15);
413 cairo_pattern_add_color_stop_rgb(gradient, 0.5, 0.08, 0.08, 0.08);
414 cairo_pattern_add_color_stop_rgb(gradient, 0.5, 0.07, 0.07, 0.07);
415 cairo_pattern_add_color_stop_rgb(gradient, 1, 0.1, 0.1, 0.1);
416 cairo_set_source(cr, gradient);
417 cairo_fill(cr);
418
419 cairo_set_font_size(cr, 16);
420 cairo_text_extents(cr, text, &extents);
421 cairo_move_to(cr, x + (width - extents.width) / 2, y + (height - extents.height) / 2 - extents.y_bearing);
422 cairo_set_line_cap (cr, CAIRO_LINE_CAP_ROUND);
423 cairo_set_line_join (cr, CAIRO_LINE_JOIN_ROUND);
424 cairo_set_line_width (cr, 4);
425 cairo_text_path(cr, text);
426 cairo_set_source_rgb(cr, 0.0, 0.0, 0.0);
427 cairo_stroke_preserve(cr);
428 cairo_set_source_rgb(cr, 1, 1, 1);
429 cairo_fill(cr);
430}
431
432static struct egl_surface *
433overlay_create(int x, int y, int width, int height)
434{
435 struct egl_surface *es;
436 cairo_surface_t *surface;
437 cairo_t *cr;
438 int total_width, button_x, button_y;
439 const int button_width = 150;
440 const int button_height = 40;
441 const int spacing = 50;
442
443 surface = cairo_image_surface_create(CAIRO_FORMAT_ARGB32,
444 width, height);
445
446 cr = cairo_create(surface);
Kristian Høgsberg1e4b86a2008-11-23 23:41:08 -0500447 cairo_set_source_rgba(cr, 0.1, 0.1, 0.1, 0.8);
Kristian Høgsberg54879822008-11-23 17:07:32 -0500448 cairo_set_operator(cr, CAIRO_OPERATOR_SOURCE);
449 cairo_paint(cr);
450
451 total_width = button_width * 2 + spacing;
452 button_x = (width - total_width) / 2;
453 button_y = height - button_height - 20;
454 draw_button(cr, button_x, button_y, button_width, button_height, "Previous");
455 button_x += button_width + spacing;
456 draw_button(cr, button_x, button_y, button_width, button_height, "Next");
457
458 cairo_destroy(cr);
459
460 es = egl_surface_create_from_cairo_surface(surface, x, y, width, height);
461
462 cairo_surface_destroy(surface);
463
464 return es;
465}
466
467static void
Kristian Høgsbergaa5b5be2008-11-21 21:31:54 -0500468draw_surface(struct egl_surface *es)
Kristian Høgsberg4c9f2c92008-11-21 19:25:44 -0500469{
470 GLint vertices[12];
471 GLint tex_coords[12] = { 0, 0, 0, 1, 1, 0, 1, 1 };
472 GLuint indices[4] = { 0, 1, 2, 3 };
473
Kristian Høgsbergaa5b5be2008-11-21 21:31:54 -0500474 vertices[0] = es->map.x;
475 vertices[1] = es->map.y;
Kristian Høgsberg4c9f2c92008-11-21 19:25:44 -0500476 vertices[2] = 0;
477
Kristian Høgsbergaa5b5be2008-11-21 21:31:54 -0500478 vertices[3] = es->map.x;
479 vertices[4] = es->map.y + es->map.height;
Kristian Høgsberg4c9f2c92008-11-21 19:25:44 -0500480 vertices[5] = 0;
481
Kristian Høgsbergaa5b5be2008-11-21 21:31:54 -0500482 vertices[6] = es->map.x + es->map.width;
483 vertices[7] = es->map.y;
Kristian Høgsberg4c9f2c92008-11-21 19:25:44 -0500484 vertices[8] = 0;
485
Kristian Høgsbergaa5b5be2008-11-21 21:31:54 -0500486 vertices[9] = es->map.x + es->map.width;
487 vertices[10] = es->map.y + es->map.height;
Kristian Høgsberg4c9f2c92008-11-21 19:25:44 -0500488 vertices[11] = 0;
489
Kristian Høgsbergaa5b5be2008-11-21 21:31:54 -0500490 glBindTexture(GL_TEXTURE_2D, es->texture);
Kristian Høgsberg4c9f2c92008-11-21 19:25:44 -0500491 glEnable(GL_TEXTURE_2D);
492 glEnable(GL_BLEND);
493 /* Assume pre-multiplied alpha for now, this probably
494 * needs to be a wayland visual type of thing. */
495 glBlendFunc(GL_ONE, GL_ONE_MINUS_SRC_ALPHA);
496
497 glEnableClientState(GL_VERTEX_ARRAY);
498 glEnableClientState(GL_TEXTURE_COORD_ARRAY);
499 glVertexPointer(3, GL_INT, 0, vertices);
500 glTexCoordPointer(2, GL_INT, 0, tex_coords);
501 glDrawElements(GL_TRIANGLE_STRIP, 4, GL_UNSIGNED_INT, indices);
502}
503
504static void
Kristian Høgsberg9af92b32008-11-24 01:12:46 -0500505schedule_repaint(struct egl_compositor *ec);
506
507static void
Kristian Høgsberg5c1e6ec2008-11-25 13:51:36 -0500508animate_overlay(struct egl_compositor *ec)
509{
510 double force, y;
511 int32_t top, bottom;
Kristian Høgsbergffb74062008-11-25 18:10:39 -0500512#if 1
513 double bounce = 0.0;
514 double friction = 1.0;
515 double spring = 0.2;
516#else
517 double bounce = 0.2;
518 double friction = 0.04;
519 double spring = 0.09;
520#endif
Kristian Høgsberg5c1e6ec2008-11-25 13:51:36 -0500521
522 y = ec->overlay_y;
Kristian Høgsbergffb74062008-11-25 18:10:39 -0500523 force = (ec->overlay_target - ec->overlay_y) * spring +
524 (ec->overlay_previous - y) * friction;
Kristian Høgsberg5c1e6ec2008-11-25 13:51:36 -0500525
526 ec->overlay_y = y + (y - ec->overlay_previous) + force;
527 ec->overlay_previous = y;
528
529 top = ec->height - ec->overlay->map.height;
530 bottom = ec->height;
531 if (ec->overlay_y >= bottom) {
532 ec->overlay_y = bottom;
533 ec->overlay_previous = bottom;
534 }
535
536 if (ec->overlay_y <= top) {
Kristian Høgsbergffb74062008-11-25 18:10:39 -0500537 ec->overlay_y = top + bounce * (top - ec->overlay_y);
538 ec->overlay_previous =
539 top + bounce * (top - ec->overlay_previous);
Kristian Høgsberg5c1e6ec2008-11-25 13:51:36 -0500540 }
541
542 ec->overlay->map.y = ec->overlay_y + 0.5;
Kristian Høgsbergffb74062008-11-25 18:10:39 -0500543
Kristian Høgsberg73c30582008-11-25 22:45:46 -0500544 if (fabs(y - ec->overlay_target) > 0.2 ||
545 fabs(ec->overlay_y - ec->overlay_target) > 0.2)
Kristian Høgsberg5c1e6ec2008-11-25 13:51:36 -0500546 schedule_repaint(ec);
547}
548
549static void
Kristian Høgsberg4a298902008-11-28 18:35:25 -0500550repaint(void *data)
Kristian Høgsbergef7a9ca2008-10-11 21:21:39 -0400551{
552 struct egl_compositor *ec = data;
553 struct wl_surface_iterator *iterator;
554 struct wl_surface *surface;
Kristian Høgsbergaa5b5be2008-11-21 21:31:54 -0500555 struct egl_surface *es;
Kristian Høgsbergfbdbbdc2008-11-28 17:06:06 -0500556 struct timespec ts;
Kristian Høgsbergfbdbbdc2008-11-28 17:06:06 -0500557 uint32_t msecs;
558
Kristian Høgsbergfbdbbdc2008-11-28 17:06:06 -0500559 if (!ec->repaint_needed) {
560 ec->repaint_on_timeout = 0;
561 return;
562 }
Kristian Høgsbergaa5b5be2008-11-21 21:31:54 -0500563
564 draw_surface(ec->background);
Kristian Høgsbergef7a9ca2008-10-11 21:21:39 -0400565
566 iterator = wl_surface_iterator_create(ec->wl_display, 0);
567 while (wl_surface_iterator_next(iterator, &surface)) {
Kristian Høgsbergaa5b5be2008-11-21 21:31:54 -0500568 es = wl_surface_get_data(surface);
569 if (es == NULL)
Kristian Høgsbergef7a9ca2008-10-11 21:21:39 -0400570 continue;
571
Kristian Høgsbergaa5b5be2008-11-21 21:31:54 -0500572 draw_surface(es);
Kristian Høgsbergef7a9ca2008-10-11 21:21:39 -0400573 }
574 wl_surface_iterator_destroy(iterator);
575
Kristian Høgsberg54879822008-11-23 17:07:32 -0500576 draw_surface(ec->overlay);
577
Kristian Høgsbergaa5b5be2008-11-21 21:31:54 -0500578 draw_surface(ec->pointer);
Kristian Høgsberg4c9f2c92008-11-21 19:25:44 -0500579
Kristian Høgsbergef7a9ca2008-10-11 21:21:39 -0400580 eglSwapBuffers(ec->display, ec->surface);
Kristian Høgsbergfbdbbdc2008-11-28 17:06:06 -0500581 ec->repaint_needed = 0;
Kristian Høgsberg9af92b32008-11-24 01:12:46 -0500582
Kristian Høgsbergfbdbbdc2008-11-28 17:06:06 -0500583 clock_gettime(CLOCK_MONOTONIC, &ts);
584 msecs = ts.tv_sec * 1000 + ts.tv_nsec / (1000 * 1000);
585 wl_display_post_frame(ec->wl_display, ec->current_frame, msecs);
586 ec->current_frame++;
587
Kristian Høgsberg4a298902008-11-28 18:35:25 -0500588 wl_event_source_timer_update(ec->timer_source, 10);
Kristian Høgsbergfbdbbdc2008-11-28 17:06:06 -0500589 ec->repaint_on_timeout = 1;
Kristian Høgsberg44f36e32008-11-26 12:57:31 -0500590
Kristian Høgsberg5c1e6ec2008-11-25 13:51:36 -0500591 animate_overlay(ec);
Kristian Høgsbergef7a9ca2008-10-11 21:21:39 -0400592}
593
Kristian Høgsberg5503bf82008-11-06 10:38:17 -0500594static void
595schedule_repaint(struct egl_compositor *ec)
Kristian Høgsbergef7a9ca2008-10-11 21:21:39 -0400596{
597 struct wl_event_loop *loop;
598
Kristian Høgsbergfbdbbdc2008-11-28 17:06:06 -0500599 ec->repaint_needed = 1;
600 if (!ec->repaint_on_timeout) {
601 loop = wl_display_get_event_loop(ec->wl_display);
Kristian Høgsberg4a298902008-11-28 18:35:25 -0500602 wl_event_loop_add_idle(loop, repaint, ec);
Kristian Høgsbergfbdbbdc2008-11-28 17:06:06 -0500603 }
Kristian Høgsbergef7a9ca2008-10-11 21:21:39 -0400604}
605
Kristian Høgsberg5503bf82008-11-06 10:38:17 -0500606static void
607notify_surface_create(struct wl_compositor *compositor,
608 struct wl_surface *surface)
Kristian Høgsberg16eb6752008-10-08 22:51:32 -0400609{
Kristian Høgsbergaa5b5be2008-11-21 21:31:54 -0500610 struct egl_surface *es;
Kristian Høgsberg16eb6752008-10-08 22:51:32 -0400611
Kristian Høgsbergaa5b5be2008-11-21 21:31:54 -0500612 es = malloc(sizeof *es);
613 if (es == NULL)
Kristian Høgsberg16eb6752008-10-08 22:51:32 -0400614 return;
615
Kristian Høgsbergaa5b5be2008-11-21 21:31:54 -0500616 es->surface = EGL_NO_SURFACE;
617 wl_surface_set_data(surface, es);
Kristian Høgsberg16eb6752008-10-08 22:51:32 -0400618
Kristian Høgsbergaa5b5be2008-11-21 21:31:54 -0500619 glGenTextures(1, &es->texture);
Kristian Høgsberg16eb6752008-10-08 22:51:32 -0400620}
621
Kristian Høgsberg5503bf82008-11-06 10:38:17 -0500622static void
623notify_surface_destroy(struct wl_compositor *compositor,
624 struct wl_surface *surface)
Kristian Høgsberg16eb6752008-10-08 22:51:32 -0400625{
626 struct egl_compositor *ec = (struct egl_compositor *) compositor;
Kristian Høgsbergaa5b5be2008-11-21 21:31:54 -0500627 struct egl_surface *es;
Kristian Høgsberg16eb6752008-10-08 22:51:32 -0400628
Kristian Høgsbergaa5b5be2008-11-21 21:31:54 -0500629 es = wl_surface_get_data(surface);
630 if (es == NULL)
Kristian Høgsberg16eb6752008-10-08 22:51:32 -0400631 return;
Kristian Høgsberg2d9cd1e2008-11-03 08:09:34 -0500632
Kristian Høgsbergaa5b5be2008-11-21 21:31:54 -0500633 egl_surface_destroy(es, ec);
Kristian Høgsbergef7a9ca2008-10-11 21:21:39 -0400634
635 schedule_repaint(ec);
Kristian Høgsberg16eb6752008-10-08 22:51:32 -0400636}
637
Kristian Høgsberg5503bf82008-11-06 10:38:17 -0500638static void
639notify_surface_attach(struct wl_compositor *compositor,
640 struct wl_surface *surface, uint32_t name,
641 uint32_t width, uint32_t height, uint32_t stride)
Kristian Høgsberg16eb6752008-10-08 22:51:32 -0400642{
643 struct egl_compositor *ec = (struct egl_compositor *) compositor;
Kristian Høgsbergaa5b5be2008-11-21 21:31:54 -0500644 struct egl_surface *es;
Kristian Høgsberg16eb6752008-10-08 22:51:32 -0400645
Kristian Høgsbergaa5b5be2008-11-21 21:31:54 -0500646 es = wl_surface_get_data(surface);
647 if (es == NULL)
Kristian Høgsberg16eb6752008-10-08 22:51:32 -0400648 return;
649
Kristian Høgsbergaa5b5be2008-11-21 21:31:54 -0500650 if (es->surface != EGL_NO_SURFACE)
651 eglDestroySurface(ec->display, es->surface);
Kristian Høgsberg16eb6752008-10-08 22:51:32 -0400652
Kristian Høgsbergaa5b5be2008-11-21 21:31:54 -0500653 es->surface = eglCreateSurfaceForName(ec->display, ec->config,
Kristian Høgsberg78231c82008-11-08 15:06:01 -0500654 name, width, height, stride, NULL);
Kristian Høgsberg16eb6752008-10-08 22:51:32 -0400655
Kristian Høgsbergaa5b5be2008-11-21 21:31:54 -0500656 glBindTexture(GL_TEXTURE_2D, es->texture);
Kristian Høgsberg16eb6752008-10-08 22:51:32 -0400657 glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
658 glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_R, GL_REPEAT);
659 glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
660 glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
Kristian Høgsbergaa5b5be2008-11-21 21:31:54 -0500661 eglBindTexImage(ec->display, es->surface, GL_TEXTURE_2D);
Kristian Høgsbergf9212892008-10-11 18:40:23 -0400662}
663
Kristian Høgsberg5503bf82008-11-06 10:38:17 -0500664static void
665notify_surface_map(struct wl_compositor *compositor,
666 struct wl_surface *surface, struct wl_map *map)
Kristian Høgsberg16eb6752008-10-08 22:51:32 -0400667{
Kristian Høgsbergaa5b5be2008-11-21 21:31:54 -0500668 struct egl_surface *es;
Kristian Høgsberg16eb6752008-10-08 22:51:32 -0400669
Kristian Høgsbergaa5b5be2008-11-21 21:31:54 -0500670 es = wl_surface_get_data(surface);
671 if (es == NULL)
Kristian Høgsberg16eb6752008-10-08 22:51:32 -0400672 return;
673
Kristian Høgsbergaa5b5be2008-11-21 21:31:54 -0500674 es->map = *map;
Kristian Høgsberg16eb6752008-10-08 22:51:32 -0400675}
676
Kristian Høgsberg7f77bd82008-11-07 08:39:37 -0500677static void
678notify_surface_copy(struct wl_compositor *compositor,
679 struct wl_surface *surface,
680 int32_t dst_x, int32_t dst_y,
681 uint32_t name, uint32_t stride,
682 int32_t x, int32_t y, int32_t width, int32_t height)
683{
Kristian Høgsberg78231c82008-11-08 15:06:01 -0500684 struct egl_compositor *ec = (struct egl_compositor *) compositor;
685 EGLSurface src;
Kristian Høgsbergaa5b5be2008-11-21 21:31:54 -0500686 struct egl_surface *es;
Kristian Høgsberg78231c82008-11-08 15:06:01 -0500687
Kristian Høgsbergaa5b5be2008-11-21 21:31:54 -0500688 es = wl_surface_get_data(surface);
Kristian Høgsberg78231c82008-11-08 15:06:01 -0500689
690 /* FIXME: glCopyPixels should work, but then we'll have to
691 * call eglMakeCurrent to set up the src and dest surfaces
692 * first. This seems cheaper, but maybe there's a better way
693 * to accomplish this. */
694
695 src = eglCreateSurfaceForName(ec->display, ec->config,
696 name, x + width, y + height, stride, NULL);
697
Kristian Høgsbergaa5b5be2008-11-21 21:31:54 -0500698 eglCopyNativeBuffers(ec->display, es->surface, GL_FRONT_LEFT, dst_x, dst_y,
Kristian Høgsberg78231c82008-11-08 15:06:01 -0500699 src, GL_FRONT_LEFT, x, y, width, height);
Kristian Høgsbergfbdbbdc2008-11-28 17:06:06 -0500700 eglDestroySurface(ec->display, src);
Kristian Høgsberg7f77bd82008-11-07 08:39:37 -0500701}
702
703static void
704notify_surface_damage(struct wl_compositor *compositor,
Kristian Høgsberg78231c82008-11-08 15:06:01 -0500705 struct wl_surface *surface,
706 int32_t x, int32_t y, int32_t width, int32_t height)
Kristian Høgsberg7f77bd82008-11-07 08:39:37 -0500707{
Kristian Høgsbergfbdbbdc2008-11-28 17:06:06 -0500708 /* FIXME: This need to take a damage region, of course. */
709}
710
711static uint32_t
712notify_commit(struct wl_compositor *compositor)
713{
Kristian Høgsberg7f77bd82008-11-07 08:39:37 -0500714 struct egl_compositor *ec = (struct egl_compositor *) compositor;
715
Kristian Høgsberg7f77bd82008-11-07 08:39:37 -0500716 schedule_repaint(ec);
Kristian Høgsbergfbdbbdc2008-11-28 17:06:06 -0500717
718 return ec->current_frame;
Kristian Høgsberg7f77bd82008-11-07 08:39:37 -0500719}
720
Kristian Høgsberg4c9f2c92008-11-21 19:25:44 -0500721static void
722notify_pointer_motion(struct wl_compositor *compositor,
723 struct wl_object *source, int x, int y)
724{
725 struct egl_compositor *ec = (struct egl_compositor *) compositor;
Kristian Høgsberg961a04c2008-11-25 22:38:56 -0500726 const int hotspot_x = 16, hotspot_y = 16;
Kristian Høgsberg4c9f2c92008-11-21 19:25:44 -0500727
Kristian Høgsberg961a04c2008-11-25 22:38:56 -0500728 ec->pointer->map.x = x - hotspot_x;
729 ec->pointer->map.y = y - hotspot_y;
Kristian Høgsberg4c9f2c92008-11-21 19:25:44 -0500730 schedule_repaint(ec);
731}
732
Kristian Høgsbergcddc0ad2008-11-24 00:31:49 -0500733static void
734notify_key(struct wl_compositor *compositor,
735 struct wl_object *source, uint32_t key, uint32_t state)
736{
737 struct egl_compositor *ec = (struct egl_compositor *) compositor;
738
Kristian Høgsberg9af92b32008-11-24 01:12:46 -0500739 if (key == KEY_ESC && state == 1) {
740 if (ec->overlay_target == ec->height)
741 ec->overlay_target -= 200;
742 else
743 ec->overlay_target += 200;
Kristian Høgsbergcddc0ad2008-11-24 00:31:49 -0500744 schedule_repaint(ec);
Kristian Høgsberg9af92b32008-11-24 01:12:46 -0500745 }
Kristian Høgsbergcddc0ad2008-11-24 00:31:49 -0500746}
747
Kristian Høgsberg5503bf82008-11-06 10:38:17 -0500748static const struct wl_compositor_interface interface = {
Kristian Høgsberg16eb6752008-10-08 22:51:32 -0400749 notify_surface_create,
750 notify_surface_destroy,
751 notify_surface_attach,
Kristian Høgsberg7f77bd82008-11-07 08:39:37 -0500752 notify_surface_map,
753 notify_surface_copy,
Kristian Høgsberg4c9f2c92008-11-21 19:25:44 -0500754 notify_surface_damage,
Kristian Høgsbergfbdbbdc2008-11-28 17:06:06 -0500755 notify_commit,
Kristian Høgsbergcddc0ad2008-11-24 00:31:49 -0500756 notify_pointer_motion,
757 notify_key
Kristian Høgsberg16eb6752008-10-08 22:51:32 -0400758};
759
Kristian Høgsbergcddc0ad2008-11-24 00:31:49 -0500760static const char pointer_device_file[] =
761 "/dev/input/by-id/usb-Apple__Inc._Apple_Internal_Keyboard_._Trackpad-event-mouse";
762static const char keyboard_device_file[] =
763 "/dev/input/by-id/usb-Apple__Inc._Apple_Internal_Keyboard_._Trackpad-event-kbd";
764
765static void
766create_input_devices(struct wl_display *display)
767{
768 struct wl_object *obj;
769 const char *path;
770
771 path = getenv("WAYLAND_POINTER");
772 if (path == NULL)
773 path = pointer_device_file;
774
775 obj = wl_input_device_create(display, path);
776 if (obj != NULL)
777 wl_display_add_object(display, obj);
778
779 path = getenv("WAYLAND_KEYBOARD");
780 if (path == NULL)
781 path = keyboard_device_file;
782
783 obj = wl_input_device_create(display, path);
784 if (obj != NULL)
785 wl_display_add_object(display, obj);
786}
787
Kristian Høgsbergbf9541f2008-11-25 12:10:09 -0500788static uint32_t
789create_frontbuffer(int fd, int *width, int *height, int *stride)
790{
791 drmModeConnector *connector;
792 drmModeRes *resources;
793 drmModeEncoder *encoder;
794 struct drm_mode_modeinfo *mode;
795 struct drm_i915_gem_create create;
796 struct drm_i915_gem_pin pin;
797 struct drm_gem_flink flink;
798 unsigned int fb_id;
799 int i, ret;
800
801 resources = drmModeGetResources(fd);
802 if (!resources) {
803 fprintf(stderr, "drmModeGetResources failed\n");
804 return 0;
805 }
806
807 for (i = 0; i < resources->count_connectors; i++) {
808 connector = drmModeGetConnector(fd, resources->connectors[i]);
809 if (connector == NULL)
810 continue;
811
812 if (connector->connection == DRM_MODE_CONNECTED &&
813 connector->count_modes > 0)
814 break;
815
816 drmModeFreeConnector(connector);
817 }
818
819 if (i == resources->count_connectors) {
820 fprintf(stderr, "No currently active connector found.\n");
821 return -1;
822 }
823
824 mode = &connector->modes[0];
825
826 for (i = 0; i < resources->count_encoders; i++) {
827 encoder = drmModeGetEncoder(fd, resources->encoders[i]);
828
829 if (encoder == NULL)
830 continue;
831
832 if (encoder->encoder_id == connector->encoder_id)
833 break;
834
835 drmModeFreeEncoder(encoder);
836 }
837
838 /* Mode size at 32 bpp */
839 create.size = mode->hdisplay * mode->vdisplay * 4;
840 if (ioctl(fd, DRM_IOCTL_I915_GEM_CREATE, &create) != 0) {
841 fprintf(stderr, "gem create failed: %m\n");
842 return 0;
843 }
844
845 pin.handle = create.handle;
846 pin.alignment = 4096;
847 if (ioctl(fd, DRM_IOCTL_I915_GEM_PIN, &pin)) {
848 fprintf(stderr, "failed to pin buffer: %m\n");
849 return 0;
850 }
851
852 ret = drmModeAddFB(fd, mode->hdisplay, mode->vdisplay,
853 32, 32, mode->hdisplay * 4, create.handle, &fb_id);
854 if (ret) {
855 fprintf(stderr, "failed to add fb: %m\n");
856 return 0;
857 }
858
859 ret = drmModeSetCrtc(fd, encoder->crtc_id, fb_id, 0, 0,
860 &connector->connector_id, 1, mode);
861 if (ret) {
862 fprintf(stderr, "failed to set mode: %m\n");
863 return 0;
864 }
865
866 flink.handle = create.handle;
867 if (ioctl(fd, DRM_IOCTL_GEM_FLINK, &flink) != 0) {
868 fprintf(stderr, "gem flink failed: %m\n");
869 return 0;
870 }
871
872 *width = mode->hdisplay;
873 *height = mode->vdisplay;
874 *stride = mode->hdisplay * 4;
875
876 return flink.name;
877}
878
Kristian Høgsberg443853c2008-11-25 12:12:05 -0500879static int
880pick_config(struct egl_compositor *ec)
881{
882 EGLConfig configs[100];
883 EGLint value, count;
884 int i;
885
886 if (!eglGetConfigs(ec->display, configs, ARRAY_LENGTH(configs), &count)) {
887 fprintf(stderr, "failed to get configs\n");
888 return -1;
889 }
890
891 ec->config = EGL_NO_CONFIG;
892 for (i = 0; i < count; i++) {
893 eglGetConfigAttrib(ec->display,
894 configs[i],
895 EGL_DEPTH_SIZE,
896 &value);
897 if (value > 0) {
898 fprintf(stderr, "config %d has depth size %d\n", i, value);
899 continue;
900 }
901
902 eglGetConfigAttrib(ec->display,
903 configs[i],
904 EGL_STENCIL_SIZE,
905 &value);
906 if (value > 0) {
907 fprintf(stderr, "config %d has stencil size %d\n", i, value);
908 continue;
909 }
910
911 eglGetConfigAttrib(ec->display,
912 configs[i],
913 EGL_CONFIG_CAVEAT,
914 &value);
915 if (value != EGL_NONE) {
916 fprintf(stderr, "config %d has caveat %d\n", i, value);
917 continue;
918 }
919
920 ec->config = configs[i];
921 break;
922 }
923
924 if (ec->config == EGL_NO_CONFIG) {
925 fprintf(stderr, "found no config without depth or stencil buffers\n");
926 return -1;
927 }
928
929 return 0;
930}
Kristian Høgsbergbf9541f2008-11-25 12:10:09 -0500931
Kristian Høgsberg16eb6752008-10-08 22:51:32 -0400932static const char gem_device[] = "/dev/dri/card0";
933
Kristian Høgsberg122912c2008-12-05 11:13:50 -0500934static struct egl_compositor *
935egl_compositor_create(struct wl_display *display)
Kristian Høgsberg16eb6752008-10-08 22:51:32 -0400936{
Kristian Høgsberg443853c2008-11-25 12:12:05 -0500937 EGLint major, minor;
Kristian Høgsberg16eb6752008-10-08 22:51:32 -0400938 struct egl_compositor *ec;
Kristian Høgsbergaa5b5be2008-11-21 21:31:54 -0500939 const char *filename;
Kristian Høgsberg1e4b86a2008-11-23 23:41:08 -0500940 struct screenshooter *shooter;
Kristian Høgsbergbf9541f2008-11-25 12:10:09 -0500941 uint32_t fb_name;
942 int stride;
Kristian Høgsbergfbdbbdc2008-11-28 17:06:06 -0500943 struct wl_event_loop *loop;
Kristian Høgsbergbf9541f2008-11-25 12:10:09 -0500944 const static EGLint attribs[] =
945 { EGL_RENDER_BUFFER, EGL_BACK_BUFFER, EGL_NONE };
Kristian Høgsberg16eb6752008-10-08 22:51:32 -0400946
947 ec = malloc(sizeof *ec);
948 if (ec == NULL)
949 return NULL;
950
951 ec->base.interface = &interface;
Kristian Høgsbergf9212892008-10-11 18:40:23 -0400952 ec->wl_display = display;
Kristian Høgsberg16eb6752008-10-08 22:51:32 -0400953
Kristian Høgsbergc508d932008-10-13 22:52:42 -0400954 ec->display = eglCreateDisplayNative(gem_device, "i965");
Kristian Høgsberg16eb6752008-10-08 22:51:32 -0400955 if (ec->display == NULL) {
956 fprintf(stderr, "failed to create display\n");
957 return NULL;
958 }
959
960 if (!eglInitialize(ec->display, &major, &minor)) {
961 fprintf(stderr, "failed to initialize display\n");
962 return NULL;
963 }
964
Kristian Høgsberg443853c2008-11-25 12:12:05 -0500965 if (pick_config(ec))
Kristian Høgsberg16eb6752008-10-08 22:51:32 -0400966 return NULL;
Kristian Høgsbergbf9541f2008-11-25 12:10:09 -0500967
Kristian Høgsbergbf9541f2008-11-25 12:10:09 -0500968 fb_name = create_frontbuffer(eglGetDisplayFD(ec->display),
969 &ec->width, &ec->height, &stride);
970 ec->surface = eglCreateSurfaceForName(ec->display, ec->config,
971 fb_name, ec->width, ec->height, stride, attribs);
Kristian Høgsberg16eb6752008-10-08 22:51:32 -0400972 if (ec->surface == NULL) {
973 fprintf(stderr, "failed to create surface\n");
974 return NULL;
975 }
976
Kristian Høgsberg2d9cd1e2008-11-03 08:09:34 -0500977 ec->context = eglCreateContext(ec->display, ec->config, NULL, NULL);
Kristian Høgsberg16eb6752008-10-08 22:51:32 -0400978 if (ec->context == NULL) {
979 fprintf(stderr, "failed to create context\n");
980 return NULL;
981 }
982
983 if (!eglMakeCurrent(ec->display, ec->surface, ec->surface, ec->context)) {
984 fprintf(stderr, "failed to make context current\n");
985 return NULL;
986 }
987
Kristian Høgsberg8d7ca6b2008-11-09 00:22:51 -0500988 glViewport(0, 0, ec->width, ec->height);
Kristian Høgsberg16eb6752008-10-08 22:51:32 -0400989 glMatrixMode(GL_PROJECTION);
990 glLoadIdentity();
Kristian Høgsberg8d7ca6b2008-11-09 00:22:51 -0500991 glOrtho(0, ec->width, ec->height, 0, 0, 1000.0);
Kristian Høgsberg16eb6752008-10-08 22:51:32 -0400992 glMatrixMode(GL_MODELVIEW);
Kristian Høgsbergcddc0ad2008-11-24 00:31:49 -0500993
994 create_input_devices(display);
Kristian Høgsberg16eb6752008-10-08 22:51:32 -0400995
Kristian Høgsbergaa5b5be2008-11-21 21:31:54 -0500996 filename = getenv("WAYLAND_BACKGROUND");
997 if (filename == NULL)
998 filename = "background.jpg";
999 ec->background = background_create(filename, 1280, 800);
Kristian Høgsberg4c9f2c92008-11-21 19:25:44 -05001000 ec->pointer = pointer_create(100, 100, 64, 64);
Kristian Høgsberg9af92b32008-11-24 01:12:46 -05001001 ec->overlay = overlay_create(0, ec->height, ec->width, 200);
1002 ec->overlay_target = ec->height;
1003 ec->overlay_previous = ec->height;
Kristian Høgsberg4c9f2c92008-11-21 19:25:44 -05001004
Kristian Høgsberg16eb6752008-10-08 22:51:32 -04001005 ec->gem_fd = open(gem_device, O_RDWR);
1006 if (ec->gem_fd < 0) {
1007 fprintf(stderr, "failed to open drm device\n");
1008 return NULL;
1009 }
1010
Kristian Høgsberg1e4b86a2008-11-23 23:41:08 -05001011 shooter = screenshooter_create(ec);
1012 wl_display_add_object(display, &shooter->base);
1013 wl_display_add_global(display, &shooter->base);
Kristian Høgsberg8d7ca6b2008-11-09 00:22:51 -05001014
Kristian Høgsbergfbdbbdc2008-11-28 17:06:06 -05001015 loop = wl_display_get_event_loop(ec->wl_display);
Kristian Høgsberg4a298902008-11-28 18:35:25 -05001016 ec->timer_source = wl_event_loop_add_timer(loop, repaint, ec);
Kristian Høgsbergfbdbbdc2008-11-28 17:06:06 -05001017 ec->repaint_needed = 0;
1018 ec->repaint_on_timeout = 0;
1019
Kristian Høgsbergef7a9ca2008-10-11 21:21:39 -04001020 schedule_repaint(ec);
1021
Kristian Høgsberg122912c2008-12-05 11:13:50 -05001022 return ec;
1023}
1024
1025/* The plan here is to generate a random anonymous socket name and
1026 * advertise that through a service on the session dbus.
1027 */
1028static const char socket_name[] = "\0wayland";
1029
1030int main(int argc, char *argv[])
1031{
1032 struct wl_display *display;
1033 struct egl_compositor *ec;
1034
1035 display = wl_display_create();
1036
1037 ec = egl_compositor_create(display);
1038
1039 wl_display_set_compositor(display, &ec->base);
1040
1041 if (wl_display_add_socket(display, socket_name)) {
1042 fprintf(stderr, "failed to add socket: %m\n");
1043 exit(EXIT_FAILURE);
1044 }
1045
1046 wl_display_run(display);
1047
1048 return 0;
Kristian Høgsberg16eb6752008-10-08 22:51:32 -04001049}