blob: 4f10cb9913f5e74c7f0125773f217b5955ef2003 [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[] = {
Kristian Høgsberg73f4e762008-12-08 14:07:33 -0500215 { "shoot", screenshooter_shoot, "", NULL }
Kristian Høgsberg1e4b86a2008-11-23 23:41:08 -0500216};
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);
Kristian Høgsberg98fed0f2008-12-09 13:35:35 -0500257 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_R, GL_REPEAT);
258 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
259 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
Kristian Høgsberg54879822008-11-23 17:07:32 -0500260 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);
Kristian Høgsberg98fed0f2008-12-09 13:35:35 -0500357 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_R, GL_REPEAT);
358 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
359 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
Kristian Høgsbergaa5b5be2008-11-21 21:31:54 -0500360 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);
Kristian Høgsberg98fed0f2008-12-09 13:35:35 -0500658 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_R, GL_REPEAT);
659 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
660 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
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
Kristian Høgsbergeac149a2008-12-10 00:24:18 -0500734notify_pointer_button(struct wl_compositor *compositor,
735 struct wl_object *source,
736 int32_t button, int32_t state)
737{
738 struct egl_compositor *ec = (struct egl_compositor *) compositor;
739 struct egl_surface *es;
740 struct wl_surface_iterator *iterator;
741 struct wl_surface *surface, *target;
742 const int hotspot_x = 16, hotspot_y = 16;
743 int x, y;
744
745 x = ec->pointer->map.x + hotspot_x;
746 y = ec->pointer->map.y + hotspot_y;
747
748 target = NULL;
749 iterator = wl_surface_iterator_create(ec->wl_display, 0);
750 while (wl_surface_iterator_next(iterator, &surface)) {
751 es = wl_surface_get_data(surface);
752 if (es == NULL)
753 continue;
754
755 if (es->map.x <= x && x < es->map.x + es->map.width &&
756 es->map.y <= y && y < es->map.y + es->map.height)
757 target = surface;
758 }
759 wl_surface_iterator_destroy(iterator);
760
761 if (target)
762 wl_display_raise_surface(ec->wl_display, target);
763}
764
765static void
Kristian Høgsbergcddc0ad2008-11-24 00:31:49 -0500766notify_key(struct wl_compositor *compositor,
767 struct wl_object *source, uint32_t key, uint32_t state)
768{
769 struct egl_compositor *ec = (struct egl_compositor *) compositor;
770
Kristian Høgsberg9af92b32008-11-24 01:12:46 -0500771 if (key == KEY_ESC && state == 1) {
772 if (ec->overlay_target == ec->height)
773 ec->overlay_target -= 200;
774 else
775 ec->overlay_target += 200;
Kristian Høgsbergcddc0ad2008-11-24 00:31:49 -0500776 schedule_repaint(ec);
Kristian Høgsberg9af92b32008-11-24 01:12:46 -0500777 }
Kristian Høgsbergcddc0ad2008-11-24 00:31:49 -0500778}
779
Kristian Høgsberg5503bf82008-11-06 10:38:17 -0500780static const struct wl_compositor_interface interface = {
Kristian Høgsberg16eb6752008-10-08 22:51:32 -0400781 notify_surface_create,
782 notify_surface_destroy,
783 notify_surface_attach,
Kristian Høgsberg7f77bd82008-11-07 08:39:37 -0500784 notify_surface_map,
785 notify_surface_copy,
Kristian Høgsberg4c9f2c92008-11-21 19:25:44 -0500786 notify_surface_damage,
Kristian Høgsbergfbdbbdc2008-11-28 17:06:06 -0500787 notify_commit,
Kristian Høgsbergcddc0ad2008-11-24 00:31:49 -0500788 notify_pointer_motion,
Kristian Høgsbergeac149a2008-12-10 00:24:18 -0500789 notify_pointer_button,
Kristian Høgsbergcddc0ad2008-11-24 00:31:49 -0500790 notify_key
Kristian Høgsberg16eb6752008-10-08 22:51:32 -0400791};
792
Kristian Høgsbergcddc0ad2008-11-24 00:31:49 -0500793static const char pointer_device_file[] =
794 "/dev/input/by-id/usb-Apple__Inc._Apple_Internal_Keyboard_._Trackpad-event-mouse";
795static const char keyboard_device_file[] =
796 "/dev/input/by-id/usb-Apple__Inc._Apple_Internal_Keyboard_._Trackpad-event-kbd";
797
798static void
799create_input_devices(struct wl_display *display)
800{
801 struct wl_object *obj;
802 const char *path;
803
804 path = getenv("WAYLAND_POINTER");
805 if (path == NULL)
806 path = pointer_device_file;
807
808 obj = wl_input_device_create(display, path);
809 if (obj != NULL)
810 wl_display_add_object(display, obj);
811
812 path = getenv("WAYLAND_KEYBOARD");
813 if (path == NULL)
814 path = keyboard_device_file;
815
816 obj = wl_input_device_create(display, path);
817 if (obj != NULL)
818 wl_display_add_object(display, obj);
819}
820
Kristian Høgsbergbf9541f2008-11-25 12:10:09 -0500821static uint32_t
822create_frontbuffer(int fd, int *width, int *height, int *stride)
823{
824 drmModeConnector *connector;
825 drmModeRes *resources;
826 drmModeEncoder *encoder;
827 struct drm_mode_modeinfo *mode;
828 struct drm_i915_gem_create create;
829 struct drm_i915_gem_pin pin;
830 struct drm_gem_flink flink;
831 unsigned int fb_id;
832 int i, ret;
833
834 resources = drmModeGetResources(fd);
835 if (!resources) {
836 fprintf(stderr, "drmModeGetResources failed\n");
837 return 0;
838 }
839
840 for (i = 0; i < resources->count_connectors; i++) {
841 connector = drmModeGetConnector(fd, resources->connectors[i]);
842 if (connector == NULL)
843 continue;
844
845 if (connector->connection == DRM_MODE_CONNECTED &&
846 connector->count_modes > 0)
847 break;
848
849 drmModeFreeConnector(connector);
850 }
851
852 if (i == resources->count_connectors) {
853 fprintf(stderr, "No currently active connector found.\n");
854 return -1;
855 }
856
857 mode = &connector->modes[0];
858
859 for (i = 0; i < resources->count_encoders; i++) {
860 encoder = drmModeGetEncoder(fd, resources->encoders[i]);
861
862 if (encoder == NULL)
863 continue;
864
865 if (encoder->encoder_id == connector->encoder_id)
866 break;
867
868 drmModeFreeEncoder(encoder);
869 }
870
871 /* Mode size at 32 bpp */
872 create.size = mode->hdisplay * mode->vdisplay * 4;
873 if (ioctl(fd, DRM_IOCTL_I915_GEM_CREATE, &create) != 0) {
874 fprintf(stderr, "gem create failed: %m\n");
875 return 0;
876 }
877
878 pin.handle = create.handle;
879 pin.alignment = 4096;
880 if (ioctl(fd, DRM_IOCTL_I915_GEM_PIN, &pin)) {
881 fprintf(stderr, "failed to pin buffer: %m\n");
882 return 0;
883 }
884
885 ret = drmModeAddFB(fd, mode->hdisplay, mode->vdisplay,
886 32, 32, mode->hdisplay * 4, create.handle, &fb_id);
887 if (ret) {
888 fprintf(stderr, "failed to add fb: %m\n");
889 return 0;
890 }
891
892 ret = drmModeSetCrtc(fd, encoder->crtc_id, fb_id, 0, 0,
893 &connector->connector_id, 1, mode);
894 if (ret) {
895 fprintf(stderr, "failed to set mode: %m\n");
896 return 0;
897 }
898
899 flink.handle = create.handle;
900 if (ioctl(fd, DRM_IOCTL_GEM_FLINK, &flink) != 0) {
901 fprintf(stderr, "gem flink failed: %m\n");
902 return 0;
903 }
904
905 *width = mode->hdisplay;
906 *height = mode->vdisplay;
907 *stride = mode->hdisplay * 4;
908
909 return flink.name;
910}
911
Kristian Høgsberg443853c2008-11-25 12:12:05 -0500912static int
913pick_config(struct egl_compositor *ec)
914{
915 EGLConfig configs[100];
916 EGLint value, count;
917 int i;
918
919 if (!eglGetConfigs(ec->display, configs, ARRAY_LENGTH(configs), &count)) {
920 fprintf(stderr, "failed to get configs\n");
921 return -1;
922 }
923
924 ec->config = EGL_NO_CONFIG;
925 for (i = 0; i < count; i++) {
926 eglGetConfigAttrib(ec->display,
927 configs[i],
928 EGL_DEPTH_SIZE,
929 &value);
930 if (value > 0) {
931 fprintf(stderr, "config %d has depth size %d\n", i, value);
932 continue;
933 }
934
935 eglGetConfigAttrib(ec->display,
936 configs[i],
937 EGL_STENCIL_SIZE,
938 &value);
939 if (value > 0) {
940 fprintf(stderr, "config %d has stencil size %d\n", i, value);
941 continue;
942 }
943
944 eglGetConfigAttrib(ec->display,
945 configs[i],
946 EGL_CONFIG_CAVEAT,
947 &value);
948 if (value != EGL_NONE) {
949 fprintf(stderr, "config %d has caveat %d\n", i, value);
950 continue;
951 }
952
953 ec->config = configs[i];
954 break;
955 }
956
957 if (ec->config == EGL_NO_CONFIG) {
958 fprintf(stderr, "found no config without depth or stencil buffers\n");
959 return -1;
960 }
961
962 return 0;
963}
Kristian Høgsbergbf9541f2008-11-25 12:10:09 -0500964
Kristian Høgsberg16eb6752008-10-08 22:51:32 -0400965static const char gem_device[] = "/dev/dri/card0";
966
Kristian Høgsberg122912c2008-12-05 11:13:50 -0500967static struct egl_compositor *
968egl_compositor_create(struct wl_display *display)
Kristian Høgsberg16eb6752008-10-08 22:51:32 -0400969{
Kristian Høgsberg443853c2008-11-25 12:12:05 -0500970 EGLint major, minor;
Kristian Høgsberg16eb6752008-10-08 22:51:32 -0400971 struct egl_compositor *ec;
Kristian Høgsbergaa5b5be2008-11-21 21:31:54 -0500972 const char *filename;
Kristian Høgsberg1e4b86a2008-11-23 23:41:08 -0500973 struct screenshooter *shooter;
Kristian Høgsbergbf9541f2008-11-25 12:10:09 -0500974 uint32_t fb_name;
975 int stride;
Kristian Høgsbergfbdbbdc2008-11-28 17:06:06 -0500976 struct wl_event_loop *loop;
Kristian Høgsbergbf9541f2008-11-25 12:10:09 -0500977 const static EGLint attribs[] =
978 { EGL_RENDER_BUFFER, EGL_BACK_BUFFER, EGL_NONE };
Kristian Høgsberg16eb6752008-10-08 22:51:32 -0400979
980 ec = malloc(sizeof *ec);
981 if (ec == NULL)
982 return NULL;
983
984 ec->base.interface = &interface;
Kristian Høgsbergf9212892008-10-11 18:40:23 -0400985 ec->wl_display = display;
Kristian Høgsberg16eb6752008-10-08 22:51:32 -0400986
Kristian Høgsbergc508d932008-10-13 22:52:42 -0400987 ec->display = eglCreateDisplayNative(gem_device, "i965");
Kristian Høgsberg16eb6752008-10-08 22:51:32 -0400988 if (ec->display == NULL) {
989 fprintf(stderr, "failed to create display\n");
990 return NULL;
991 }
992
993 if (!eglInitialize(ec->display, &major, &minor)) {
994 fprintf(stderr, "failed to initialize display\n");
995 return NULL;
996 }
997
Kristian Høgsberg443853c2008-11-25 12:12:05 -0500998 if (pick_config(ec))
Kristian Høgsberg16eb6752008-10-08 22:51:32 -0400999 return NULL;
Kristian Høgsbergbf9541f2008-11-25 12:10:09 -05001000
Kristian Høgsbergbf9541f2008-11-25 12:10:09 -05001001 fb_name = create_frontbuffer(eglGetDisplayFD(ec->display),
1002 &ec->width, &ec->height, &stride);
1003 ec->surface = eglCreateSurfaceForName(ec->display, ec->config,
1004 fb_name, ec->width, ec->height, stride, attribs);
Kristian Høgsberg16eb6752008-10-08 22:51:32 -04001005 if (ec->surface == NULL) {
1006 fprintf(stderr, "failed to create surface\n");
1007 return NULL;
1008 }
1009
Kristian Høgsberg2d9cd1e2008-11-03 08:09:34 -05001010 ec->context = eglCreateContext(ec->display, ec->config, NULL, NULL);
Kristian Høgsberg16eb6752008-10-08 22:51:32 -04001011 if (ec->context == NULL) {
1012 fprintf(stderr, "failed to create context\n");
1013 return NULL;
1014 }
1015
1016 if (!eglMakeCurrent(ec->display, ec->surface, ec->surface, ec->context)) {
1017 fprintf(stderr, "failed to make context current\n");
1018 return NULL;
1019 }
1020
Kristian Høgsberg8d7ca6b2008-11-09 00:22:51 -05001021 glViewport(0, 0, ec->width, ec->height);
Kristian Høgsberg16eb6752008-10-08 22:51:32 -04001022 glMatrixMode(GL_PROJECTION);
1023 glLoadIdentity();
Kristian Høgsberg8d7ca6b2008-11-09 00:22:51 -05001024 glOrtho(0, ec->width, ec->height, 0, 0, 1000.0);
Kristian Høgsberg16eb6752008-10-08 22:51:32 -04001025 glMatrixMode(GL_MODELVIEW);
Kristian Høgsbergcddc0ad2008-11-24 00:31:49 -05001026
1027 create_input_devices(display);
Kristian Høgsberg16eb6752008-10-08 22:51:32 -04001028
Kristian Høgsbergaa5b5be2008-11-21 21:31:54 -05001029 filename = getenv("WAYLAND_BACKGROUND");
1030 if (filename == NULL)
1031 filename = "background.jpg";
1032 ec->background = background_create(filename, 1280, 800);
Kristian Høgsberg4c9f2c92008-11-21 19:25:44 -05001033 ec->pointer = pointer_create(100, 100, 64, 64);
Kristian Høgsberg9af92b32008-11-24 01:12:46 -05001034 ec->overlay = overlay_create(0, ec->height, ec->width, 200);
Kristian Høgsberg9f88b182008-12-08 13:52:08 -05001035 ec->overlay_y = ec->height;
Kristian Høgsberg9af92b32008-11-24 01:12:46 -05001036 ec->overlay_target = ec->height;
1037 ec->overlay_previous = ec->height;
Kristian Høgsberg4c9f2c92008-11-21 19:25:44 -05001038
Kristian Høgsberg16eb6752008-10-08 22:51:32 -04001039 ec->gem_fd = open(gem_device, O_RDWR);
1040 if (ec->gem_fd < 0) {
1041 fprintf(stderr, "failed to open drm device\n");
1042 return NULL;
1043 }
1044
Kristian Høgsberg1e4b86a2008-11-23 23:41:08 -05001045 shooter = screenshooter_create(ec);
1046 wl_display_add_object(display, &shooter->base);
1047 wl_display_add_global(display, &shooter->base);
Kristian Høgsberg8d7ca6b2008-11-09 00:22:51 -05001048
Kristian Høgsbergfbdbbdc2008-11-28 17:06:06 -05001049 loop = wl_display_get_event_loop(ec->wl_display);
Kristian Høgsberg4a298902008-11-28 18:35:25 -05001050 ec->timer_source = wl_event_loop_add_timer(loop, repaint, ec);
Kristian Høgsbergfbdbbdc2008-11-28 17:06:06 -05001051 ec->repaint_needed = 0;
1052 ec->repaint_on_timeout = 0;
1053
Kristian Høgsbergef7a9ca2008-10-11 21:21:39 -04001054 schedule_repaint(ec);
1055
Kristian Høgsberg122912c2008-12-05 11:13:50 -05001056 return ec;
1057}
1058
1059/* The plan here is to generate a random anonymous socket name and
1060 * advertise that through a service on the session dbus.
1061 */
1062static const char socket_name[] = "\0wayland";
1063
1064int main(int argc, char *argv[])
1065{
1066 struct wl_display *display;
1067 struct egl_compositor *ec;
1068
1069 display = wl_display_create();
1070
1071 ec = egl_compositor_create(display);
Kristian Høgsberg841883b2008-12-05 11:19:56 -05001072 if (ec == NULL) {
1073 fprintf(stderr, "failed to create compositor\n");
1074 exit(EXIT_FAILURE);
1075 }
1076
Kristian Høgsberg122912c2008-12-05 11:13:50 -05001077 wl_display_set_compositor(display, &ec->base);
1078
Kristian Høgsbergdc0f3552008-12-07 15:22:22 -05001079 if (wl_display_add_socket(display, socket_name, sizeof socket_name)) {
Kristian Høgsberg122912c2008-12-05 11:13:50 -05001080 fprintf(stderr, "failed to add socket: %m\n");
1081 exit(EXIT_FAILURE);
1082 }
1083
1084 wl_display_run(display);
1085
1086 return 0;
Kristian Høgsberg16eb6752008-10-08 22:51:32 -04001087}