blob: 0cc3e46ca4e97c59048f220230e28ae481b5087e [file] [log] [blame]
Kristian Høgsbergffd710e2008-12-02 15:15:01 -05001/*
2 * Copyright © 2008 Kristian Høgsberg
3 *
Kristian Høgsberg82f6e8a2008-12-19 13:47:53 -05004 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation; either version 2 of the License, or
7 * (at your option) any later version.
Kristian Høgsbergffd710e2008-12-02 15:15:01 -05008 *
Kristian Høgsberg82f6e8a2008-12-19 13:47:53 -05009 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
13 *
14 * You should have received a copy of the GNU General Public License
15 * along with this program; if not, write to the Free Software Foundation,
16 * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
Kristian Høgsbergffd710e2008-12-02 15:15:01 -050017 */
18
Kristian Høgsberg16eb6752008-10-08 22:51:32 -040019#include <stdio.h>
20#include <string.h>
Ray Strode966aa112008-12-19 14:28:02 -050021#include <stdbool.h>
Kristian Høgsberg16eb6752008-10-08 22:51:32 -040022#include <stdlib.h>
23#include <stdint.h>
Kristian Høgsberg8d7ca6b2008-11-09 00:22:51 -050024#include <stdarg.h>
Ray Strode966aa112008-12-19 14:28:02 -050025#include <termios.h>
Kristian Høgsberg16eb6752008-10-08 22:51:32 -040026#include <i915_drm.h>
27#include <sys/ioctl.h>
28#include <sys/mman.h>
29#include <fcntl.h>
30#include <unistd.h>
Kristian Høgsberg8d7ca6b2008-11-09 00:22:51 -050031#include <signal.h>
Kristian Høgsberg4c9f2c92008-11-21 19:25:44 -050032#include <cairo.h>
Kristian Høgsbergaa5b5be2008-11-21 21:31:54 -050033#include <gdk-pixbuf/gdk-pixbuf.h>
34#include <glib.h>
Kristian Høgsbergfbdbbdc2008-11-28 17:06:06 -050035#include <sys/poll.h>
Kristian Høgsberg8d7ca6b2008-11-09 00:22:51 -050036#include <png.h>
Kristian Høgsberg54879822008-11-23 17:07:32 -050037#include <math.h>
Kristian Høgsbergcddc0ad2008-11-24 00:31:49 -050038#include <linux/input.h>
Ray Strode19ad6a92008-12-19 01:45:41 -050039#include <linux/vt.h>
Kristian Høgsbergbf9541f2008-11-25 12:10:09 -050040#include <xf86drmMode.h>
Kristian Høgsbergfbdbbdc2008-11-28 17:06:06 -050041#include <time.h>
Kristian Høgsbergc492b482008-12-12 12:00:02 -050042#include <fnmatch.h>
43#include <dirent.h>
Kristian Høgsberg16eb6752008-10-08 22:51:32 -040044
Kristian Høgsberg890bc052008-12-30 14:31:33 -050045#define LIBUDEV_I_KNOW_THE_API_IS_SUBJECT_TO_CHANGE
46#include <libudev.h>
47
Kristian Høgsberg16eb6752008-10-08 22:51:32 -040048#include <GL/gl.h>
49#include <eagle.h>
50
Kristian Høgsberg5ee1a602008-12-11 23:18:45 -050051#include "wayland.h"
Kristian Høgsbergfe831a72008-12-21 21:50:23 -050052#include "wayland-protocol.h"
Kristian Høgsberg5ee1a602008-12-11 23:18:45 -050053#include "cairo-util.h"
Kristian Høgsberg82f6e8a2008-12-19 13:47:53 -050054#include "wayland-system-compositor.h"
Kristian Høgsberg5ee1a602008-12-11 23:18:45 -050055
Kristian Høgsberg16eb6752008-10-08 22:51:32 -040056#define ARRAY_LENGTH(a) (sizeof (a) / sizeof (a)[0])
57
Kristian Høgsbergde31d5c2008-12-18 17:55:33 -050058struct wl_visual {
59 struct wl_object base;
60};
61
Kristian Høgsbergee02ca62008-12-21 23:37:12 -050062struct wl_output {
63 struct wl_object base;
64};
65
Kristian Høgsberg82f6e8a2008-12-19 13:47:53 -050066struct wlsc_input_device {
Kristian Høgsberg5ee1a602008-12-11 23:18:45 -050067 struct wl_object base;
68 int32_t x, y;
69 struct egl_compositor *ec;
Kristian Høgsberg29573bc2008-12-11 23:27:27 -050070 struct egl_surface *pointer_surface;
Kristian Høgsbergc492b482008-12-12 12:00:02 -050071 struct wl_list link;
Kristian Høgsberg29573bc2008-12-11 23:27:27 -050072
73 int grab;
74 struct egl_surface *grab_surface;
Kristian Høgsberga7700c82008-12-12 13:48:30 -050075 struct egl_surface *focus_surface;
Kristian Høgsberg5ee1a602008-12-11 23:18:45 -050076};
77
Kristian Høgsberg16eb6752008-10-08 22:51:32 -040078struct egl_compositor {
79 struct wl_compositor base;
Kristian Høgsbergee02ca62008-12-21 23:37:12 -050080 struct wl_output output;
Kristian Høgsbergde31d5c2008-12-18 17:55:33 -050081 struct wl_visual argb_visual, premultiplied_argb_visual, rgb_visual;
82
Kristian Høgsberg16eb6752008-10-08 22:51:32 -040083 EGLDisplay display;
84 EGLSurface surface;
85 EGLContext context;
Kristian Høgsberg2d9cd1e2008-11-03 08:09:34 -050086 EGLConfig config;
Kristian Høgsbergf9212892008-10-11 18:40:23 -040087 struct wl_display *wl_display;
Kristian Høgsberg2c875bd2008-12-19 10:34:02 -050088 int width, height, stride;
Kristian Høgsbergaa5b5be2008-11-21 21:31:54 -050089 struct egl_surface *background;
Kristian Høgsbergfbdbbdc2008-11-28 17:06:06 -050090
Kristian Høgsbergc492b482008-12-12 12:00:02 -050091 struct wl_list input_device_list;
Kristian Høgsberg201a9042008-12-10 00:40:50 -050092 struct wl_list surface_list;
93
Ray Strode966aa112008-12-19 14:28:02 -050094 struct wl_event_source *term_signal_source;
95
96 /* tty handling state */
97 int tty_fd;
Ray Strodee96dcb82008-12-20 02:00:49 -050098 uint32_t vt_active : 1;
Ray Strode966aa112008-12-19 14:28:02 -050099
100 struct termios terminal_attributes;
101 struct wl_event_source *tty_input_source;
Ray Strode19ad6a92008-12-19 01:45:41 -0500102 struct wl_event_source *enter_vt_source;
103 struct wl_event_source *leave_vt_source;
104
Kristian Høgsberg2c875bd2008-12-19 10:34:02 -0500105 /* Modesetting info. */
106 struct drm_mode_modeinfo *mode;
107 uint32_t fb_id;
108 uint32_t crtc_id;
109 uint32_t connector_id;
110
Kristian Høgsberg890bc052008-12-30 14:31:33 -0500111 struct udev *udev;
112
Kristian Høgsbergfbdbbdc2008-11-28 17:06:06 -0500113 /* Repaint state. */
114 struct wl_event_source *timer_source;
115 int repaint_needed;
116 int repaint_on_timeout;
Kristian Høgsbergfbdbbdc2008-11-28 17:06:06 -0500117 struct timespec previous_swap;
118 uint32_t current_frame;
Kristian Høgsberg16eb6752008-10-08 22:51:32 -0400119};
120
Kristian Høgsbergaa5b5be2008-11-21 21:31:54 -0500121struct egl_surface {
Kristian Høgsbergd2412e22008-12-15 20:35:24 -0500122 struct wl_surface base;
123 struct egl_compositor *compositor;
Kristian Høgsbergde31d5c2008-12-18 17:55:33 -0500124 struct wl_visual *visual;
Kristian Høgsberg16eb6752008-10-08 22:51:32 -0400125 GLuint texture;
Kristian Høgsbergf9212892008-10-11 18:40:23 -0400126 struct wl_map map;
Kristian Høgsberg2d9cd1e2008-11-03 08:09:34 -0500127 EGLSurface surface;
Kristian Høgsberg715a0812008-12-10 10:42:04 -0500128 int width, height;
Kristian Høgsberg201a9042008-12-10 00:40:50 -0500129 struct wl_list link;
Kristian Høgsberg16eb6752008-10-08 22:51:32 -0400130};
131
Kristian Høgsberg1e4b86a2008-11-23 23:41:08 -0500132struct screenshooter {
133 struct wl_object base;
134 struct egl_compositor *ec;
135};
136
Kristian Høgsbergd2412e22008-12-15 20:35:24 -0500137struct screenshooter_interface {
138 void (*shoot)(struct wl_client *client, struct screenshooter *shooter);
139};
140
Kristian Høgsberg8d7ca6b2008-11-09 00:22:51 -0500141static void
Kristian Høgsberg1e4b86a2008-11-23 23:41:08 -0500142screenshooter_shoot(struct wl_client *client, struct screenshooter *shooter)
Kristian Høgsberg8d7ca6b2008-11-09 00:22:51 -0500143{
Kristian Høgsberg1e4b86a2008-11-23 23:41:08 -0500144 struct egl_compositor *ec = shooter->ec;
Kristian Høgsberg8d7ca6b2008-11-09 00:22:51 -0500145 GLuint stride;
146 static const char filename[] = "wayland-screenshot.png";
Kristian Høgsberg0ea47102008-12-14 15:53:13 -0500147 GdkPixbuf *pixbuf;
148 GError *error = NULL;
149 void *data;
Kristian Høgsberg8d7ca6b2008-11-09 00:22:51 -0500150
151 data = eglReadBuffer(ec->display, ec->surface, GL_FRONT_LEFT, &stride);
Kristian Høgsberg0ea47102008-12-14 15:53:13 -0500152 pixbuf = gdk_pixbuf_new_from_data(data, GDK_COLORSPACE_RGB, TRUE,
153 8, ec->width, ec->height, stride,
154 NULL, NULL);
155 gdk_pixbuf_save(pixbuf, filename, "png", &error, NULL);
Kristian Høgsberg8d7ca6b2008-11-09 00:22:51 -0500156}
157
Kristian Høgsbergfb6d68d2008-12-21 21:54:51 -0500158static const struct wl_message screenshooter_methods[] = {
Kristian Høgsbergd2412e22008-12-15 20:35:24 -0500159 { "shoot", "", NULL }
Kristian Høgsberg1e4b86a2008-11-23 23:41:08 -0500160};
161
162static const struct wl_interface screenshooter_interface = {
163 "screenshooter", 1,
164 ARRAY_LENGTH(screenshooter_methods),
165 screenshooter_methods,
166};
167
Kristian Høgsbergd2412e22008-12-15 20:35:24 -0500168struct screenshooter_interface screenshooter_implementation = {
169 screenshooter_shoot
170};
171
Kristian Høgsberg1e4b86a2008-11-23 23:41:08 -0500172static struct screenshooter *
173screenshooter_create(struct egl_compositor *ec)
174{
175 struct screenshooter *shooter;
176
177 shooter = malloc(sizeof *shooter);
178 if (shooter == NULL)
179 return NULL;
180
181 shooter->base.interface = &screenshooter_interface;
Kristian Høgsbergd2412e22008-12-15 20:35:24 -0500182 shooter->base.implementation = (void(**)(void)) &screenshooter_implementation;
Kristian Høgsberg1e4b86a2008-11-23 23:41:08 -0500183 shooter->ec = ec;
184
185 return shooter;
186};
187
Kristian Høgsberg54879822008-11-23 17:07:32 -0500188static struct egl_surface *
Kristian Høgsbergde31d5c2008-12-18 17:55:33 -0500189egl_surface_create_from_cairo_surface(struct egl_compositor *ec,
190 cairo_surface_t *surface,
Kristian Høgsberg54879822008-11-23 17:07:32 -0500191 int x, int y, int width, int height)
192{
193 struct egl_surface *es;
194 int stride;
195 void *data;
196
197 stride = cairo_image_surface_get_stride(surface);
198 data = cairo_image_surface_get_data(surface);
199
200 es = malloc(sizeof *es);
201 if (es == NULL)
202 return NULL;
203
204 glGenTextures(1, &es->texture);
205 glBindTexture(GL_TEXTURE_2D, es->texture);
206 glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
Kristian Høgsberg98fed0f2008-12-09 13:35:35 -0500207 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_R, GL_REPEAT);
208 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
209 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
Kristian Høgsberg54879822008-11-23 17:07:32 -0500210 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0,
211 GL_BGRA, GL_UNSIGNED_BYTE, data);
212
Kristian Høgsbergde31d5c2008-12-18 17:55:33 -0500213 es->compositor = ec;
Kristian Høgsberg54879822008-11-23 17:07:32 -0500214 es->map.x = x;
215 es->map.y = y;
216 es->map.width = width;
217 es->map.height = height;
218 es->surface = EGL_NO_SURFACE;
Kristian Høgsbergde31d5c2008-12-18 17:55:33 -0500219 es->visual = &ec->premultiplied_argb_visual;
Kristian Høgsberg54879822008-11-23 17:07:32 -0500220
221 return es;
222}
223
224static void
225egl_surface_destroy(struct egl_surface *es, struct egl_compositor *ec)
226{
227 glDeleteTextures(1, &es->texture);
228 if (es->surface != EGL_NO_SURFACE)
229 eglDestroySurface(ec->display, es->surface);
230 free(es);
231}
232
Kristian Høgsbergef7a9ca2008-10-11 21:21:39 -0400233static void
Kristian Høgsberg4c9f2c92008-11-21 19:25:44 -0500234pointer_path(cairo_t *cr, int x, int y)
235{
236 const int end = 3, tx = 4, ty = 12, dx = 5, dy = 10;
237 const int width = 16, height = 16;
238
239 cairo_move_to(cr, x, y);
240 cairo_line_to(cr, x + tx, y + ty);
241 cairo_line_to(cr, x + dx, y + dy);
242 cairo_line_to(cr, x + width - end, y + height);
243 cairo_line_to(cr, x + width, y + height - end);
244 cairo_line_to(cr, x + dy, y + dx);
245 cairo_line_to(cr, x + ty, y + tx);
246 cairo_close_path(cr);
247}
248
Kristian Høgsbergaa5b5be2008-11-21 21:31:54 -0500249static struct egl_surface *
Kristian Høgsbergde31d5c2008-12-18 17:55:33 -0500250pointer_create(struct egl_compositor *ec, int x, int y, int width, int height)
Kristian Høgsberg4c9f2c92008-11-21 19:25:44 -0500251{
Kristian Høgsberg54879822008-11-23 17:07:32 -0500252 struct egl_surface *es;
Kristian Høgsberg4c9f2c92008-11-21 19:25:44 -0500253 const int hotspot_x = 16, hotspot_y = 16;
Kristian Høgsberg4c9f2c92008-11-21 19:25:44 -0500254 cairo_surface_t *surface;
255 cairo_t *cr;
Kristian Høgsberg4c9f2c92008-11-21 19:25:44 -0500256
257 surface = cairo_image_surface_create(CAIRO_FORMAT_ARGB32,
258 width, height);
259
260 cr = cairo_create(surface);
261 pointer_path(cr, hotspot_x + 5, hotspot_y + 4);
Kristian Høgsberg0ab26242008-12-21 19:33:09 -0500262 cairo_set_line_width(cr, 2);
Kristian Høgsberg4c9f2c92008-11-21 19:25:44 -0500263 cairo_set_source_rgb(cr, 0, 0, 0);
264 cairo_stroke_preserve(cr);
265 cairo_fill(cr);
266 blur_surface(surface, width);
267
268 pointer_path(cr, hotspot_x, hotspot_y);
269 cairo_stroke_preserve(cr);
270 cairo_set_source_rgb(cr, 1, 1, 1);
271 cairo_fill(cr);
272 cairo_destroy(cr);
273
Kristian Høgsbergde31d5c2008-12-18 17:55:33 -0500274 es = egl_surface_create_from_cairo_surface(ec,
275 surface,
Kristian Høgsberg5ee1a602008-12-11 23:18:45 -0500276 x - hotspot_x,
277 y - hotspot_y,
278 width, height);
Kristian Høgsberg54879822008-11-23 17:07:32 -0500279
Kristian Høgsberg4c9f2c92008-11-21 19:25:44 -0500280 cairo_surface_destroy(surface);
281
Kristian Høgsberg54879822008-11-23 17:07:32 -0500282 return es;
Kristian Høgsbergaa5b5be2008-11-21 21:31:54 -0500283}
284
285static struct egl_surface *
Kristian Høgsbergde31d5c2008-12-18 17:55:33 -0500286background_create(struct egl_compositor *ec,
287 const char *filename, int width, int height)
Kristian Høgsbergaa5b5be2008-11-21 21:31:54 -0500288{
289 struct egl_surface *background;
290 GdkPixbuf *pixbuf;
291 GError *error = NULL;
Kristian Høgsbergaa5b5be2008-11-21 21:31:54 -0500292 void *data;
Ray Strode18fd33c2008-12-18 21:05:20 -0500293 GLenum format;
Kristian Høgsbergaa5b5be2008-11-21 21:31:54 -0500294
295 background = malloc(sizeof *background);
296 if (background == NULL)
297 return NULL;
298
299 g_type_init();
300
Kristian Høgsberg0ab26242008-12-21 19:33:09 -0500301 pixbuf = gdk_pixbuf_new_from_file_at_scale(filename,
302 width, height,
303 FALSE, &error);
Kristian Høgsbergaa5b5be2008-11-21 21:31:54 -0500304 if (error != NULL) {
305 free(background);
306 return NULL;
307 }
308
Kristian Høgsbergaa5b5be2008-11-21 21:31:54 -0500309 data = gdk_pixbuf_get_pixels(pixbuf);
310
311 glGenTextures(1, &background->texture);
312 glBindTexture(GL_TEXTURE_2D, background->texture);
313 glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
Kristian Høgsberg98fed0f2008-12-09 13:35:35 -0500314 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_R, GL_REPEAT);
315 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
316 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
Ray Strode18fd33c2008-12-18 21:05:20 -0500317
Kristian Høgsberg0ab26242008-12-21 19:33:09 -0500318 if (gdk_pixbuf_get_has_alpha(pixbuf))
Ray Strode18fd33c2008-12-18 21:05:20 -0500319 format = GL_RGBA;
Kristian Høgsberg0ab26242008-12-21 19:33:09 -0500320 else
Ray Strode18fd33c2008-12-18 21:05:20 -0500321 format = GL_RGB;
Ray Strode18fd33c2008-12-18 21:05:20 -0500322
Kristian Høgsberg2d4219e2008-12-18 21:40:03 -0500323 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, width, height, 0,
Ray Strode18fd33c2008-12-18 21:05:20 -0500324 format, GL_UNSIGNED_BYTE, data);
Kristian Høgsbergaa5b5be2008-11-21 21:31:54 -0500325
Kristian Høgsbergde31d5c2008-12-18 17:55:33 -0500326 background->compositor = ec;
Kristian Høgsbergaa5b5be2008-11-21 21:31:54 -0500327 background->map.x = 0;
328 background->map.y = 0;
329 background->map.width = width;
330 background->map.height = height;
331 background->surface = EGL_NO_SURFACE;
Kristian Høgsbergde31d5c2008-12-18 17:55:33 -0500332 background->visual = &ec->rgb_visual;
Kristian Høgsbergaa5b5be2008-11-21 21:31:54 -0500333
334 return background;
Kristian Høgsberg4c9f2c92008-11-21 19:25:44 -0500335}
336
337static void
Kristian Høgsbergaa5b5be2008-11-21 21:31:54 -0500338draw_surface(struct egl_surface *es)
Kristian Høgsberg4c9f2c92008-11-21 19:25:44 -0500339{
Kristian Høgsbergde31d5c2008-12-18 17:55:33 -0500340 struct egl_compositor *ec = es->compositor;
Kristian Høgsberg4c9f2c92008-11-21 19:25:44 -0500341 GLint vertices[12];
342 GLint tex_coords[12] = { 0, 0, 0, 1, 1, 0, 1, 1 };
343 GLuint indices[4] = { 0, 1, 2, 3 };
344
Kristian Høgsbergaa5b5be2008-11-21 21:31:54 -0500345 vertices[0] = es->map.x;
346 vertices[1] = es->map.y;
Kristian Høgsberg4c9f2c92008-11-21 19:25:44 -0500347 vertices[2] = 0;
348
Kristian Høgsbergaa5b5be2008-11-21 21:31:54 -0500349 vertices[3] = es->map.x;
350 vertices[4] = es->map.y + es->map.height;
Kristian Høgsberg4c9f2c92008-11-21 19:25:44 -0500351 vertices[5] = 0;
352
Kristian Høgsbergaa5b5be2008-11-21 21:31:54 -0500353 vertices[6] = es->map.x + es->map.width;
354 vertices[7] = es->map.y;
Kristian Høgsberg4c9f2c92008-11-21 19:25:44 -0500355 vertices[8] = 0;
356
Kristian Høgsbergaa5b5be2008-11-21 21:31:54 -0500357 vertices[9] = es->map.x + es->map.width;
358 vertices[10] = es->map.y + es->map.height;
Kristian Høgsberg4c9f2c92008-11-21 19:25:44 -0500359 vertices[11] = 0;
360
Kristian Høgsbergde31d5c2008-12-18 17:55:33 -0500361 if (es->visual == &ec->argb_visual) {
362 glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
363 glEnable(GL_BLEND);
364 } else if (es->visual == &ec->premultiplied_argb_visual) {
365 glBlendFunc(GL_ONE, GL_ONE_MINUS_SRC_ALPHA);
366 glEnable(GL_BLEND);
367 } else {
368 glDisable(GL_BLEND);
369 }
370
Kristian Høgsbergaa5b5be2008-11-21 21:31:54 -0500371 glBindTexture(GL_TEXTURE_2D, es->texture);
Kristian Høgsberg4c9f2c92008-11-21 19:25:44 -0500372 glEnable(GL_TEXTURE_2D);
Kristian Høgsberg4c9f2c92008-11-21 19:25:44 -0500373 glEnableClientState(GL_VERTEX_ARRAY);
374 glEnableClientState(GL_TEXTURE_COORD_ARRAY);
375 glVertexPointer(3, GL_INT, 0, vertices);
376 glTexCoordPointer(2, GL_INT, 0, tex_coords);
377 glDrawElements(GL_TRIANGLE_STRIP, 4, GL_UNSIGNED_INT, indices);
378}
379
380static void
Kristian Høgsberg9af92b32008-11-24 01:12:46 -0500381schedule_repaint(struct egl_compositor *ec);
382
383static void
Kristian Høgsberg4a298902008-11-28 18:35:25 -0500384repaint(void *data)
Kristian Høgsbergef7a9ca2008-10-11 21:21:39 -0400385{
386 struct egl_compositor *ec = data;
Kristian Høgsbergaa5b5be2008-11-21 21:31:54 -0500387 struct egl_surface *es;
Kristian Høgsberg82f6e8a2008-12-19 13:47:53 -0500388 struct wlsc_input_device *eid;
Kristian Høgsbergfbdbbdc2008-11-28 17:06:06 -0500389 struct timespec ts;
Kristian Høgsbergfbdbbdc2008-11-28 17:06:06 -0500390 uint32_t msecs;
391
Kristian Høgsbergfbdbbdc2008-11-28 17:06:06 -0500392 if (!ec->repaint_needed) {
393 ec->repaint_on_timeout = 0;
394 return;
395 }
Kristian Høgsbergaa5b5be2008-11-21 21:31:54 -0500396
Kristian Høgsberg5b7f8322008-12-18 12:08:19 -0500397 if (ec->background)
398 draw_surface(ec->background);
399 else
400 glClear(GL_COLOR_BUFFER_BIT);
Kristian Høgsbergef7a9ca2008-10-11 21:21:39 -0400401
Kristian Høgsberg201a9042008-12-10 00:40:50 -0500402 es = container_of(ec->surface_list.next,
403 struct egl_surface, link);
404 while (&es->link != &ec->surface_list) {
Kristian Høgsbergaa5b5be2008-11-21 21:31:54 -0500405 draw_surface(es);
Kristian Høgsberg201a9042008-12-10 00:40:50 -0500406
407 es = container_of(es->link.next,
408 struct egl_surface, link);
Kristian Høgsbergef7a9ca2008-10-11 21:21:39 -0400409 }
Kristian Høgsbergef7a9ca2008-10-11 21:21:39 -0400410
Kristian Høgsbergc492b482008-12-12 12:00:02 -0500411 eid = container_of(ec->input_device_list.next,
Kristian Høgsberg82f6e8a2008-12-19 13:47:53 -0500412 struct wlsc_input_device, link);
Kristian Høgsbergc492b482008-12-12 12:00:02 -0500413 while (&eid->link != &ec->input_device_list) {
414 draw_surface(eid->pointer_surface);
415
416 eid = container_of(eid->link.next,
Kristian Høgsberg82f6e8a2008-12-19 13:47:53 -0500417 struct wlsc_input_device, link);
Kristian Høgsbergc492b482008-12-12 12:00:02 -0500418 }
Kristian Høgsberg4c9f2c92008-11-21 19:25:44 -0500419
Kristian Høgsbergef7a9ca2008-10-11 21:21:39 -0400420 eglSwapBuffers(ec->display, ec->surface);
Kristian Høgsbergfbdbbdc2008-11-28 17:06:06 -0500421 ec->repaint_needed = 0;
Kristian Høgsberg9af92b32008-11-24 01:12:46 -0500422
Kristian Høgsbergfbdbbdc2008-11-28 17:06:06 -0500423 clock_gettime(CLOCK_MONOTONIC, &ts);
424 msecs = ts.tv_sec * 1000 + ts.tv_nsec / (1000 * 1000);
Kristian Høgsbergd2412e22008-12-15 20:35:24 -0500425 wl_display_post_frame(ec->wl_display, &ec->base,
426 ec->current_frame, msecs);
Kristian Høgsbergfbdbbdc2008-11-28 17:06:06 -0500427 ec->current_frame++;
428
Kristian Høgsberg4a298902008-11-28 18:35:25 -0500429 wl_event_source_timer_update(ec->timer_source, 10);
Kristian Høgsbergfbdbbdc2008-11-28 17:06:06 -0500430 ec->repaint_on_timeout = 1;
Kristian Høgsbergef7a9ca2008-10-11 21:21:39 -0400431}
432
Kristian Høgsberg5503bf82008-11-06 10:38:17 -0500433static void
434schedule_repaint(struct egl_compositor *ec)
Kristian Høgsbergef7a9ca2008-10-11 21:21:39 -0400435{
436 struct wl_event_loop *loop;
437
Kristian Høgsbergfbdbbdc2008-11-28 17:06:06 -0500438 ec->repaint_needed = 1;
439 if (!ec->repaint_on_timeout) {
440 loop = wl_display_get_event_loop(ec->wl_display);
Kristian Høgsberg4a298902008-11-28 18:35:25 -0500441 wl_event_loop_add_idle(loop, repaint, ec);
Kristian Høgsbergfbdbbdc2008-11-28 17:06:06 -0500442 }
Kristian Høgsbergef7a9ca2008-10-11 21:21:39 -0400443}
Kristian Høgsberg16eb6752008-10-08 22:51:32 -0400444
Kristian Høgsberg5503bf82008-11-06 10:38:17 -0500445static void
Kristian Høgsbergd2412e22008-12-15 20:35:24 -0500446surface_destroy(struct wl_client *client,
447 struct wl_surface *surface)
Kristian Høgsberg16eb6752008-10-08 22:51:32 -0400448{
Kristian Høgsbergd2412e22008-12-15 20:35:24 -0500449 struct egl_surface *es = (struct egl_surface *) surface;
450 struct egl_compositor *ec = es->compositor;
Kristian Høgsberg2d9cd1e2008-11-03 08:09:34 -0500451
Kristian Høgsberg201a9042008-12-10 00:40:50 -0500452 wl_list_remove(&es->link);
Kristian Høgsbergaa5b5be2008-11-21 21:31:54 -0500453 egl_surface_destroy(es, ec);
Kristian Høgsbergef7a9ca2008-10-11 21:21:39 -0400454
455 schedule_repaint(ec);
Kristian Høgsberg16eb6752008-10-08 22:51:32 -0400456}
457
Kristian Høgsberg5503bf82008-11-06 10:38:17 -0500458static void
Kristian Høgsbergd2412e22008-12-15 20:35:24 -0500459surface_attach(struct wl_client *client,
460 struct wl_surface *surface, uint32_t name,
Kristian Høgsbergde31d5c2008-12-18 17:55:33 -0500461 uint32_t width, uint32_t height, uint32_t stride,
462 struct wl_object *visual)
Kristian Høgsberg16eb6752008-10-08 22:51:32 -0400463{
Kristian Høgsbergd2412e22008-12-15 20:35:24 -0500464 struct egl_surface *es = (struct egl_surface *) surface;
465 struct egl_compositor *ec = es->compositor;
Kristian Høgsberg16eb6752008-10-08 22:51:32 -0400466
Kristian Høgsbergaa5b5be2008-11-21 21:31:54 -0500467 if (es->surface != EGL_NO_SURFACE)
468 eglDestroySurface(ec->display, es->surface);
Kristian Høgsberg16eb6752008-10-08 22:51:32 -0400469
Kristian Høgsberg715a0812008-12-10 10:42:04 -0500470 es->width = width;
471 es->height = height;
Kristian Høgsbergaa5b5be2008-11-21 21:31:54 -0500472 es->surface = eglCreateSurfaceForName(ec->display, ec->config,
Kristian Høgsberg78231c82008-11-08 15:06:01 -0500473 name, width, height, stride, NULL);
Kristian Høgsbergde31d5c2008-12-18 17:55:33 -0500474 if (visual == &ec->argb_visual.base)
475 es->visual = &ec->argb_visual;
476 else if (visual == &ec->premultiplied_argb_visual.base)
477 es->visual = &ec->premultiplied_argb_visual;
Kristian Høgsberge10b8282008-12-18 19:58:44 -0500478 else if (visual == &ec->rgb_visual.base)
479 es->visual = &ec->rgb_visual;
Kristian Høgsbergde31d5c2008-12-18 17:55:33 -0500480 else
481 /* FIXME: Smack client with an exception event */;
Kristian Høgsberg16eb6752008-10-08 22:51:32 -0400482
Kristian Høgsbergaa5b5be2008-11-21 21:31:54 -0500483 glBindTexture(GL_TEXTURE_2D, es->texture);
Kristian Høgsberg16eb6752008-10-08 22:51:32 -0400484 glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
Kristian Høgsberg98fed0f2008-12-09 13:35:35 -0500485 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_R, GL_REPEAT);
486 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
487 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
Kristian Høgsbergaa5b5be2008-11-21 21:31:54 -0500488 eglBindTexImage(ec->display, es->surface, GL_TEXTURE_2D);
Kristian Høgsbergf9212892008-10-11 18:40:23 -0400489}
490
Kristian Høgsberg5503bf82008-11-06 10:38:17 -0500491static void
Kristian Høgsbergd2412e22008-12-15 20:35:24 -0500492surface_map(struct wl_client *client,
493 struct wl_surface *surface,
494 int32_t x, int32_t y, int32_t width, int32_t height)
Kristian Høgsberg16eb6752008-10-08 22:51:32 -0400495{
Kristian Høgsbergd2412e22008-12-15 20:35:24 -0500496 struct egl_surface *es = (struct egl_surface *) surface;
Kristian Høgsberg16eb6752008-10-08 22:51:32 -0400497
Kristian Høgsbergd2412e22008-12-15 20:35:24 -0500498 es->map.x = x;
499 es->map.y = y;
500 es->map.width = width;
501 es->map.height = height;
Kristian Høgsberg16eb6752008-10-08 22:51:32 -0400502}
503
Kristian Høgsberg7f77bd82008-11-07 08:39:37 -0500504static void
Kristian Høgsbergd2412e22008-12-15 20:35:24 -0500505surface_copy(struct wl_client *client,
506 struct wl_surface *surface,
507 int32_t dst_x, int32_t dst_y,
508 uint32_t name, uint32_t stride,
509 int32_t x, int32_t y, int32_t width, int32_t height)
Kristian Høgsberg7f77bd82008-11-07 08:39:37 -0500510{
Kristian Høgsbergd2412e22008-12-15 20:35:24 -0500511 struct egl_surface *es = (struct egl_surface *) surface;
512 struct egl_compositor *ec = es->compositor;
Kristian Høgsberg78231c82008-11-08 15:06:01 -0500513 EGLSurface src;
Kristian Høgsberg78231c82008-11-08 15:06:01 -0500514
515 /* FIXME: glCopyPixels should work, but then we'll have to
516 * call eglMakeCurrent to set up the src and dest surfaces
517 * first. This seems cheaper, but maybe there's a better way
518 * to accomplish this. */
519
520 src = eglCreateSurfaceForName(ec->display, ec->config,
521 name, x + width, y + height, stride, NULL);
522
Kristian Høgsbergaa5b5be2008-11-21 21:31:54 -0500523 eglCopyNativeBuffers(ec->display, es->surface, GL_FRONT_LEFT, dst_x, dst_y,
Kristian Høgsberg78231c82008-11-08 15:06:01 -0500524 src, GL_FRONT_LEFT, x, y, width, height);
Kristian Høgsbergfbdbbdc2008-11-28 17:06:06 -0500525 eglDestroySurface(ec->display, src);
Kristian Høgsberg7f77bd82008-11-07 08:39:37 -0500526}
527
528static void
Kristian Høgsbergd2412e22008-12-15 20:35:24 -0500529surface_damage(struct wl_client *client,
530 struct wl_surface *surface,
531 int32_t x, int32_t y, int32_t width, int32_t height)
Kristian Høgsberg7f77bd82008-11-07 08:39:37 -0500532{
Kristian Høgsbergfbdbbdc2008-11-28 17:06:06 -0500533 /* FIXME: This need to take a damage region, of course. */
534}
535
Kristian Høgsbergd2412e22008-12-15 20:35:24 -0500536const static struct wl_surface_interface surface_interface = {
537 surface_destroy,
538 surface_attach,
539 surface_map,
540 surface_copy,
541 surface_damage
542};
543
544static void
545compositor_create_surface(struct wl_client *client,
546 struct wl_compositor *compositor, uint32_t id)
547{
548 struct egl_compositor *ec = (struct egl_compositor *) compositor;
549 struct egl_surface *es;
550
551 es = malloc(sizeof *es);
552 if (es == NULL)
553 /* FIXME: Send OOM event. */
554 return;
555
556 es->compositor = ec;
557 es->surface = EGL_NO_SURFACE;
558 wl_list_insert(ec->surface_list.prev, &es->link);
559 glGenTextures(1, &es->texture);
560 wl_client_add_surface(client, &es->base,
561 &surface_interface, id);
562}
563
564static void
565compositor_commit(struct wl_client *client,
566 struct wl_compositor *compositor, uint32_t key)
Kristian Høgsbergfbdbbdc2008-11-28 17:06:06 -0500567{
Kristian Høgsberg7f77bd82008-11-07 08:39:37 -0500568 struct egl_compositor *ec = (struct egl_compositor *) compositor;
569
Kristian Høgsberg7f77bd82008-11-07 08:39:37 -0500570 schedule_repaint(ec);
Kristian Høgsbergd2412e22008-12-15 20:35:24 -0500571 wl_client_send_acknowledge(client, compositor, key, ec->current_frame);
Kristian Høgsberg7f77bd82008-11-07 08:39:37 -0500572}
573
Kristian Høgsbergd2412e22008-12-15 20:35:24 -0500574const static struct wl_compositor_interface compositor_interface = {
575 compositor_create_surface,
576 compositor_commit
577};
578
Kristian Høgsberg201a9042008-12-10 00:40:50 -0500579static struct egl_surface *
Kristian Høgsberg7e972a52008-12-21 17:26:00 -0500580pick_surface(struct wlsc_input_device *device, int32_t *sx, int32_t *sy)
Kristian Høgsberg201a9042008-12-10 00:40:50 -0500581{
Kristian Høgsberg5ee1a602008-12-11 23:18:45 -0500582 struct egl_compositor *ec = device->ec;
Kristian Høgsberg201a9042008-12-10 00:40:50 -0500583 struct egl_surface *es;
584
Kristian Høgsbergc492b482008-12-12 12:00:02 -0500585 if (device->grab > 0)
586 return device->grab_surface;
587
Kristian Høgsberg201a9042008-12-10 00:40:50 -0500588 es = container_of(ec->surface_list.prev,
589 struct egl_surface, link);
590 while (&es->link != &ec->surface_list) {
Kristian Høgsberg5ee1a602008-12-11 23:18:45 -0500591 if (es->map.x <= device->x &&
592 device->x < es->map.x + es->map.width &&
593 es->map.y <= device->y &&
594 device->y < es->map.y + es->map.height)
Kristian Høgsberg201a9042008-12-10 00:40:50 -0500595 return es;
596
597 es = container_of(es->link.prev,
598 struct egl_surface, link);
Kristian Høgsberg7e972a52008-12-21 17:26:00 -0500599
600 /* Transform to surface coordinates. */
Kristian Høgsberge3ef3e52008-12-21 19:30:01 -0500601 *sx = (device->x - es->map.x) * es->width / es->map.width;
602 *sy = (device->y - es->map.y) * es->height / es->map.height;
Kristian Høgsberg201a9042008-12-10 00:40:50 -0500603 }
604
605 return NULL;
606}
607
Kristian Høgsberg5ee1a602008-12-11 23:18:45 -0500608void
Kristian Høgsberg82f6e8a2008-12-19 13:47:53 -0500609notify_motion(struct wlsc_input_device *device, int x, int y)
Kristian Høgsberg715a0812008-12-10 10:42:04 -0500610{
Kristian Høgsberg715a0812008-12-10 10:42:04 -0500611 struct egl_surface *es;
Ray Strode90e701d2008-12-18 23:05:43 -0500612 struct egl_compositor *ec = device->ec;
Kristian Høgsberg715a0812008-12-10 10:42:04 -0500613 const int hotspot_x = 16, hotspot_y = 16;
614 int32_t sx, sy;
615
Ray Strodee96dcb82008-12-20 02:00:49 -0500616 if (!ec->vt_active)
617 return;
618
Ray Strode90e701d2008-12-18 23:05:43 -0500619 if (x < 0)
620 x = 0;
621 if (y < 0)
622 y = 0;
623 if (x >= ec->width)
624 x = ec->width - 1;
625 if (y >= ec->height)
626 y = ec->height - 1;
627
Kristian Høgsberge3ef3e52008-12-21 19:30:01 -0500628 device->x = x;
629 device->y = y;
Kristian Høgsberg7e972a52008-12-21 17:26:00 -0500630 es = pick_surface(device, &sx, &sy);
631 if (es)
Kristian Høgsbergd2412e22008-12-15 20:35:24 -0500632 wl_surface_post_event(&es->base, &device->base,
Kristian Høgsberg5a75c902008-12-10 13:16:50 -0500633 WL_INPUT_MOTION, x, y, sx, sy);
Kristian Høgsberg715a0812008-12-10 10:42:04 -0500634
Kristian Høgsberg29573bc2008-12-11 23:27:27 -0500635 device->pointer_surface->map.x = x - hotspot_x;
636 device->pointer_surface->map.y = y - hotspot_y;
Kristian Høgsberg5ee1a602008-12-11 23:18:45 -0500637
638 schedule_repaint(device->ec);
Kristian Høgsberg715a0812008-12-10 10:42:04 -0500639}
640
Kristian Høgsberg5ee1a602008-12-11 23:18:45 -0500641void
Kristian Høgsberg82f6e8a2008-12-19 13:47:53 -0500642notify_button(struct wlsc_input_device *device,
Kristian Høgsberg5ee1a602008-12-11 23:18:45 -0500643 int32_t button, int32_t state)
Kristian Høgsbergeac149a2008-12-10 00:24:18 -0500644{
Kristian Høgsbergeac149a2008-12-10 00:24:18 -0500645 struct egl_surface *es;
Ray Strodee96dcb82008-12-20 02:00:49 -0500646 struct egl_compositor *ec = device->ec;
Kristian Høgsbergc492b482008-12-12 12:00:02 -0500647 int32_t sx, sy;
Kristian Høgsbergeac149a2008-12-10 00:24:18 -0500648
Ray Strodee96dcb82008-12-20 02:00:49 -0500649 if (!ec->vt_active)
650 return;
651
Kristian Høgsberg7e972a52008-12-21 17:26:00 -0500652 es = pick_surface(device, &sx, &sy);
Kristian Høgsberg201a9042008-12-10 00:40:50 -0500653 if (es) {
654 wl_list_remove(&es->link);
Kristian Høgsberg5ee1a602008-12-11 23:18:45 -0500655 wl_list_insert(device->ec->surface_list.prev, &es->link);
Kristian Høgsberg5a75c902008-12-10 13:16:50 -0500656
Kristian Høgsberg29573bc2008-12-11 23:27:27 -0500657 if (state) {
Kristian Høgsberga7700c82008-12-12 13:48:30 -0500658 /* FIXME: We need callbacks when the surfaces
659 * we reference here go away. */
Kristian Høgsberg29573bc2008-12-11 23:27:27 -0500660 device->grab++;
661 device->grab_surface = es;
Kristian Høgsberga7700c82008-12-12 13:48:30 -0500662 device->focus_surface = es;
Kristian Høgsberg29573bc2008-12-11 23:27:27 -0500663 } else {
664 device->grab--;
665 }
666
Kristian Høgsberg5a75c902008-12-10 13:16:50 -0500667 /* FIXME: Swallow click on raise? */
Kristian Høgsbergd2412e22008-12-15 20:35:24 -0500668 wl_surface_post_event(&es->base, &device->base,
Kristian Høgsbergc492b482008-12-12 12:00:02 -0500669 WL_INPUT_BUTTON, button, state,
670 device->x, device->y, sx, sy);
Kristian Høgsbergeac149a2008-12-10 00:24:18 -0500671
Kristian Høgsberg5ee1a602008-12-11 23:18:45 -0500672 schedule_repaint(device->ec);
673 }
Kristian Høgsbergeac149a2008-12-10 00:24:18 -0500674}
675
Kristian Høgsberg5ee1a602008-12-11 23:18:45 -0500676void
Kristian Høgsberg82f6e8a2008-12-19 13:47:53 -0500677notify_key(struct wlsc_input_device *device,
Kristian Høgsberg5ee1a602008-12-11 23:18:45 -0500678 uint32_t key, uint32_t state)
Kristian Høgsbergcddc0ad2008-11-24 00:31:49 -0500679{
Ray Strodee96dcb82008-12-20 02:00:49 -0500680 struct egl_compositor *ec = device->ec;
681
682 if (!ec->vt_active)
683 return;
684
Kristian Høgsberg2c0e56b2008-12-19 13:54:40 -0500685 if (device->focus_surface != NULL)
686 wl_surface_post_event(&device->focus_surface->base,
687 &device->base,
688 WL_INPUT_KEY, key, state);
Kristian Høgsbergcddc0ad2008-11-24 00:31:49 -0500689}
690
Kristian Høgsberg5ee1a602008-12-11 23:18:45 -0500691struct evdev_input_device *
Kristian Høgsberg82f6e8a2008-12-19 13:47:53 -0500692evdev_input_device_create(struct wlsc_input_device *device,
Kristian Høgsberg5ee1a602008-12-11 23:18:45 -0500693 struct wl_display *display, const char *path);
694
Kristian Høgsberg890bc052008-12-30 14:31:33 -0500695static struct wlsc_input_device *
696create_input_device(struct egl_compositor *ec)
Kristian Høgsbergcddc0ad2008-11-24 00:31:49 -0500697{
Kristian Høgsberg82f6e8a2008-12-19 13:47:53 -0500698 struct wlsc_input_device *device;
Kristian Høgsbergcddc0ad2008-11-24 00:31:49 -0500699
Kristian Høgsberg5ee1a602008-12-11 23:18:45 -0500700 device = malloc(sizeof *device);
701 if (device == NULL)
Kristian Høgsberg890bc052008-12-30 14:31:33 -0500702 return NULL;
Kristian Høgsberg5ee1a602008-12-11 23:18:45 -0500703
Kristian Høgsbergc492b482008-12-12 12:00:02 -0500704 memset(device, 0, sizeof *device);
Kristian Høgsbergfe831a72008-12-21 21:50:23 -0500705 device->base.interface = &wl_input_device_interface;
Kristian Høgsbergb3131d92008-12-24 19:30:25 -0500706 device->base.implementation = NULL;
Kristian Høgsberg5ee1a602008-12-11 23:18:45 -0500707 wl_display_add_object(ec->wl_display, &device->base);
Kristian Høgsbergb3131d92008-12-24 19:30:25 -0500708 wl_display_add_global(ec->wl_display, &device->base, NULL);
Kristian Høgsberg5ee1a602008-12-11 23:18:45 -0500709 device->x = 100;
710 device->y = 100;
Kristian Høgsbergfe831a72008-12-21 21:50:23 -0500711 device->pointer_surface =
712 pointer_create(ec, device->x, device->y, 64, 64);
Kristian Høgsberg5ee1a602008-12-11 23:18:45 -0500713 device->ec = ec;
714
Kristian Høgsbergc492b482008-12-12 12:00:02 -0500715 wl_list_insert(ec->input_device_list.prev, &device->link);
Kristian Høgsberg890bc052008-12-30 14:31:33 -0500716
717 return device;
Kristian Høgsberg5ee1a602008-12-11 23:18:45 -0500718}
719
720void
Kristian Høgsberg82f6e8a2008-12-19 13:47:53 -0500721wlsc_device_get_position(struct wlsc_input_device *device, int32_t *x, int32_t *y)
Kristian Høgsberg5ee1a602008-12-11 23:18:45 -0500722{
723 *x = device->x;
724 *y = device->y;
Kristian Høgsbergcddc0ad2008-11-24 00:31:49 -0500725}
726
Kristian Høgsbergbf9541f2008-11-25 12:10:09 -0500727static uint32_t
Kristian Høgsberg2c875bd2008-12-19 10:34:02 -0500728create_frontbuffer(struct egl_compositor *ec)
Kristian Høgsbergbf9541f2008-11-25 12:10:09 -0500729{
730 drmModeConnector *connector;
731 drmModeRes *resources;
732 drmModeEncoder *encoder;
733 struct drm_mode_modeinfo *mode;
734 struct drm_i915_gem_create create;
Kristian Høgsbergbf9541f2008-11-25 12:10:09 -0500735 struct drm_gem_flink flink;
Kristian Høgsberg2c875bd2008-12-19 10:34:02 -0500736 int i, ret, fd;
Kristian Høgsbergbf9541f2008-11-25 12:10:09 -0500737
Kristian Høgsberg2c875bd2008-12-19 10:34:02 -0500738 fd = eglGetDisplayFD(ec->display);
Kristian Høgsbergbf9541f2008-11-25 12:10:09 -0500739 resources = drmModeGetResources(fd);
740 if (!resources) {
741 fprintf(stderr, "drmModeGetResources failed\n");
742 return 0;
743 }
744
745 for (i = 0; i < resources->count_connectors; i++) {
746 connector = drmModeGetConnector(fd, resources->connectors[i]);
747 if (connector == NULL)
748 continue;
749
750 if (connector->connection == DRM_MODE_CONNECTED &&
751 connector->count_modes > 0)
752 break;
753
754 drmModeFreeConnector(connector);
755 }
756
757 if (i == resources->count_connectors) {
758 fprintf(stderr, "No currently active connector found.\n");
759 return -1;
760 }
761
762 mode = &connector->modes[0];
763
764 for (i = 0; i < resources->count_encoders; i++) {
765 encoder = drmModeGetEncoder(fd, resources->encoders[i]);
766
767 if (encoder == NULL)
768 continue;
769
770 if (encoder->encoder_id == connector->encoder_id)
771 break;
772
773 drmModeFreeEncoder(encoder);
774 }
775
776 /* Mode size at 32 bpp */
777 create.size = mode->hdisplay * mode->vdisplay * 4;
778 if (ioctl(fd, DRM_IOCTL_I915_GEM_CREATE, &create) != 0) {
779 fprintf(stderr, "gem create failed: %m\n");
780 return 0;
781 }
782
Kristian Høgsbergbf9541f2008-11-25 12:10:09 -0500783 ret = drmModeAddFB(fd, mode->hdisplay, mode->vdisplay,
Kristian Høgsberg2c875bd2008-12-19 10:34:02 -0500784 32, 32, mode->hdisplay * 4, create.handle, &ec->fb_id);
Kristian Høgsbergbf9541f2008-11-25 12:10:09 -0500785 if (ret) {
786 fprintf(stderr, "failed to add fb: %m\n");
787 return 0;
788 }
789
Kristian Høgsberg2c875bd2008-12-19 10:34:02 -0500790 ret = drmModeSetCrtc(fd, encoder->crtc_id, ec->fb_id, 0, 0,
Kristian Høgsbergbf9541f2008-11-25 12:10:09 -0500791 &connector->connector_id, 1, mode);
792 if (ret) {
793 fprintf(stderr, "failed to set mode: %m\n");
794 return 0;
795 }
796
797 flink.handle = create.handle;
798 if (ioctl(fd, DRM_IOCTL_GEM_FLINK, &flink) != 0) {
799 fprintf(stderr, "gem flink failed: %m\n");
800 return 0;
801 }
802
Kristian Høgsberg2c875bd2008-12-19 10:34:02 -0500803 ec->crtc_id = encoder->crtc_id;
804 ec->connector_id = connector->connector_id;
805 ec->mode = mode;
806 ec->width = mode->hdisplay;
807 ec->height = mode->vdisplay;
808 ec->stride = mode->hdisplay * 4;
Kristian Høgsbergbf9541f2008-11-25 12:10:09 -0500809
810 return flink.name;
811}
812
Kristian Høgsbergde31d5c2008-12-18 17:55:33 -0500813static const struct wl_interface visual_interface = {
814 "visual", 1,
815};
816
817static void
818add_visuals(struct egl_compositor *ec)
819{
820 ec->argb_visual.base.interface = &visual_interface;
821 ec->argb_visual.base.implementation = NULL;
822 wl_display_add_object(ec->wl_display, &ec->argb_visual.base);
Kristian Høgsbergee02ca62008-12-21 23:37:12 -0500823 wl_display_add_global(ec->wl_display, &ec->argb_visual.base, NULL);
Kristian Høgsbergde31d5c2008-12-18 17:55:33 -0500824
825 ec->premultiplied_argb_visual.base.interface = &visual_interface;
826 ec->premultiplied_argb_visual.base.implementation = NULL;
827 wl_display_add_object(ec->wl_display,
828 &ec->premultiplied_argb_visual.base);
829 wl_display_add_global(ec->wl_display,
Kristian Høgsbergee02ca62008-12-21 23:37:12 -0500830 &ec->premultiplied_argb_visual.base, NULL);
Kristian Høgsbergde31d5c2008-12-18 17:55:33 -0500831
832 ec->rgb_visual.base.interface = &visual_interface;
833 ec->rgb_visual.base.implementation = NULL;
834 wl_display_add_object(ec->wl_display, &ec->rgb_visual.base);
Kristian Høgsbergee02ca62008-12-21 23:37:12 -0500835 wl_display_add_global(ec->wl_display, &ec->rgb_visual.base, NULL);
836}
837
838static void
Kristian Høgsberg12ea62e2008-12-22 16:37:07 -0500839post_output_geometry(struct wl_client *client, struct wl_object *global)
Kristian Høgsbergee02ca62008-12-21 23:37:12 -0500840{
841 struct egl_compositor *ec =
842 container_of(global, struct egl_compositor, output.base);
843
844 wl_client_post_event(client, global,
Kristian Høgsberg12ea62e2008-12-22 16:37:07 -0500845 WL_OUTPUT_GEOMETRY, ec->width, ec->height);
Kristian Høgsbergde31d5c2008-12-18 17:55:33 -0500846}
847
Kristian Høgsberg16eb6752008-10-08 22:51:32 -0400848static const char gem_device[] = "/dev/dri/card0";
849
Kristian Høgsbergc492b482008-12-12 12:00:02 -0500850static const char *option_background = "background.jpg";
Kristian Høgsbergc492b482008-12-12 12:00:02 -0500851
852static const GOptionEntry option_entries[] = {
853 { "background", 'b', 0, G_OPTION_ARG_STRING,
854 &option_background, "Background image" },
Kristian Høgsbergd6531262008-12-12 11:06:18 -0500855 { NULL }
856};
857
Ray Strode19ad6a92008-12-19 01:45:41 -0500858static void on_enter_vt(int signal_number, void *data)
859{
860 struct egl_compositor *ec = data;
Kristian Høgsberg2c875bd2008-12-19 10:34:02 -0500861 int ret, fd;
Ray Strode19ad6a92008-12-19 01:45:41 -0500862
Kristian Høgsberg38ccd3a2008-12-19 10:15:35 -0500863 ioctl(ec->tty_fd, VT_RELDISP, VT_ACKACQ);
Ray Strodee96dcb82008-12-20 02:00:49 -0500864 ec->vt_active = TRUE;
Kristian Høgsberg38ccd3a2008-12-19 10:15:35 -0500865
Kristian Høgsberg2c875bd2008-12-19 10:34:02 -0500866 fd = eglGetDisplayFD(ec->display);
867 ret = drmModeSetCrtc(fd, ec->crtc_id, ec->fb_id, 0, 0,
868 &ec->connector_id, 1, ec->mode);
Ray Strode19ad6a92008-12-19 01:45:41 -0500869 if (ret) {
870 fprintf(stderr, "failed to set mode: %m\n");
871 return;
872 }
Ray Strode19ad6a92008-12-19 01:45:41 -0500873}
874
875static void on_leave_vt(int signal_number, void *data)
876{
877 struct egl_compositor *ec = data;
878
879 ioctl (ec->tty_fd, VT_RELDISP, 1);
Ray Strodee96dcb82008-12-20 02:00:49 -0500880 ec->vt_active = FALSE;
Ray Strode19ad6a92008-12-19 01:45:41 -0500881}
882
Ray Strode966aa112008-12-19 14:28:02 -0500883static void
884on_tty_input(int fd, uint32_t mask, void *data)
885{
886 struct egl_compositor *ec = data;
887
888 /* Ignore input to tty. We get keyboard events from evdev
889 */
890 tcflush(ec->tty_fd, TCIFLUSH);
891}
892
893static void on_term_signal(int signal_number, void *data)
894{
895 struct egl_compositor *ec = data;
896
897 if (tcsetattr(ec->tty_fd, TCSANOW, &ec->terminal_attributes) < 0)
898 fprintf(stderr, "could not restore terminal to canonical mode\n");
899
900 exit(0);
901}
902
Kristian Høgsberg0ab26242008-12-21 19:33:09 -0500903static int setup_tty(struct egl_compositor *ec, struct wl_event_loop *loop)
Ray Strode966aa112008-12-19 14:28:02 -0500904{
905 struct termios raw_attributes;
Kristian Høgsberg0ab26242008-12-21 19:33:09 -0500906 struct vt_mode mode = { 0 };
907
908 ec->tty_fd = open("/dev/tty0", O_RDWR | O_NOCTTY);
909 if (ec->tty_fd <= 0) {
910 fprintf(stderr, "failed to open active tty: %m\n");
911 return -1;
912 }
Ray Strode966aa112008-12-19 14:28:02 -0500913
914 if (tcgetattr(ec->tty_fd, &ec->terminal_attributes) < 0) {
915 fprintf(stderr, "could not get terminal attributes: %m\n");
Kristian Høgsberg0ab26242008-12-21 19:33:09 -0500916 return -1;
Ray Strode966aa112008-12-19 14:28:02 -0500917 }
918
Kristian Høgsberg0ab26242008-12-21 19:33:09 -0500919 /* Ignore control characters and disable echo */
Ray Strode966aa112008-12-19 14:28:02 -0500920 raw_attributes = ec->terminal_attributes;
Kristian Høgsberg0ab26242008-12-21 19:33:09 -0500921 cfmakeraw(&raw_attributes);
Ray Strode966aa112008-12-19 14:28:02 -0500922
Kristian Høgsberg0ab26242008-12-21 19:33:09 -0500923 /* Fix up line endings to be normal (cfmakeraw hoses them) */
Ray Strode966aa112008-12-19 14:28:02 -0500924 raw_attributes.c_oflag |= OPOST | OCRNL;
925
926 if (tcsetattr(ec->tty_fd, TCSANOW, &raw_attributes) < 0)
927 fprintf(stderr, "could not put terminal into raw mode: %m\n");
928
Kristian Høgsberg0ab26242008-12-21 19:33:09 -0500929 ec->term_signal_source =
930 wl_event_loop_add_signal(loop, SIGTERM, on_term_signal, ec);
Ray Strode966aa112008-12-19 14:28:02 -0500931
Kristian Høgsberg0ab26242008-12-21 19:33:09 -0500932 ec->tty_input_source =
933 wl_event_loop_add_fd(loop, ec->tty_fd,
934 WL_EVENT_READABLE, on_tty_input, ec);
Ray Strode966aa112008-12-19 14:28:02 -0500935
Kristian Høgsberg0ab26242008-12-21 19:33:09 -0500936 ec->vt_active = TRUE;
Ray Strode19ad6a92008-12-19 01:45:41 -0500937 mode.mode = VT_PROCESS;
938 mode.relsig = SIGUSR1;
939 mode.acqsig = SIGUSR2;
Kristian Høgsberg0ab26242008-12-21 19:33:09 -0500940 if (!ioctl(ec->tty_fd, VT_SETMODE, &mode) < 0) {
Ray Strode19ad6a92008-12-19 01:45:41 -0500941 fprintf(stderr, "failed to take control of vt handling\n");
942 }
943
Kristian Høgsberg0ab26242008-12-21 19:33:09 -0500944 ec->leave_vt_source =
945 wl_event_loop_add_signal(loop, SIGUSR1, on_leave_vt, ec);
946 ec->enter_vt_source =
947 wl_event_loop_add_signal(loop, SIGUSR2, on_enter_vt, ec);
Kristian Høgsbergfe831a72008-12-21 21:50:23 -0500948
949 return 0;
Ray Strode19ad6a92008-12-19 01:45:41 -0500950}
951
Kristian Høgsberg890bc052008-12-30 14:31:33 -0500952static const char *
953get_udev_property(struct udev_device *device, const char *name)
954{
955 struct udev_list_entry *entry;
956
957 udev_list_entry_foreach(entry, udev_device_get_properties_list_entry(device))
958 if (strcmp(udev_list_entry_get_name(entry), name) == 0)
959 return udev_list_entry_get_value(entry);
960
961 return NULL;
962}
963
964static void
965init_libudev(struct egl_compositor *ec)
966{
967 struct udev_enumerate *e;
968 struct udev_list_entry *entry;
969 struct udev_device *device;
970 const char *path, *seat;
971 struct wlsc_input_device *input_device;
972
973 /* FIXME: Newer (version 135+) udev has two new features that
974 * make all this much easier: 1) we can enumerate by a
975 * specific property. This lets us directly iterate through
976 * the devices we care about. 2) We can attach properties to
977 * sysfs nodes without a device file, which lets us configure
978 * which connectors belong to a seat instead of tagging the
979 * overall drm node. I don't want to update my system udev,
980 * so I'm going to stick with this until the new version is in
981 * rawhide. */
982
983 ec->udev = udev_new();
984 if (ec->udev == NULL) {
985 fprintf(stderr, "failed to initialize udev context\n");
986 return;
987 }
988
989 input_device = create_input_device(ec);
990
991 e = udev_enumerate_new(ec->udev);
992 udev_enumerate_scan_devices(e);
993 udev_list_entry_foreach(entry, udev_enumerate_get_list_entry(e)) {
994 path = udev_list_entry_get_name(entry);
995 device = udev_device_new_from_syspath(ec->udev, path);
996
997 /* FIXME: Should the property namespace be CK for console kit? */
998 seat = get_udev_property(device, "WAYLAND_SEAT");
999 if (!seat || strcmp(seat, "1") != 0)
1000 continue;
1001 if (strcmp(udev_device_get_subsystem(device), "input") == 0) {
1002 evdev_input_device_create(input_device, ec->wl_display,
1003 udev_device_get_devnode(device));
1004 continue;
1005 }
1006 }
1007 udev_enumerate_unref(e);
1008}
1009
Kristian Høgsberg122912c2008-12-05 11:13:50 -05001010static struct egl_compositor *
1011egl_compositor_create(struct wl_display *display)
Kristian Høgsberg16eb6752008-10-08 22:51:32 -04001012{
Kristian Høgsberg15d0f8b2008-12-19 12:13:42 -05001013 static const EGLint config_attribs[] = {
1014 EGL_DEPTH_SIZE, 0,
1015 EGL_STENCIL_SIZE, 0,
1016 EGL_CONFIG_CAVEAT, EGL_NONE,
1017 EGL_NONE
1018 };
1019
1020 const static EGLint attribs[] = {
1021 EGL_RENDER_BUFFER, EGL_BACK_BUFFER,
1022 EGL_NONE
1023 };
1024
Kristian Høgsberg443853c2008-11-25 12:12:05 -05001025 EGLint major, minor;
Kristian Høgsberg16eb6752008-10-08 22:51:32 -04001026 struct egl_compositor *ec;
Kristian Høgsberg1e4b86a2008-11-23 23:41:08 -05001027 struct screenshooter *shooter;
Kristian Høgsbergbf9541f2008-11-25 12:10:09 -05001028 uint32_t fb_name;
Kristian Høgsbergfbdbbdc2008-11-28 17:06:06 -05001029 struct wl_event_loop *loop;
Kristian Høgsberg16eb6752008-10-08 22:51:32 -04001030
1031 ec = malloc(sizeof *ec);
1032 if (ec == NULL)
1033 return NULL;
1034
Kristian Høgsbergf9212892008-10-11 18:40:23 -04001035 ec->wl_display = display;
Kristian Høgsberg16eb6752008-10-08 22:51:32 -04001036
Kristian Høgsbergc508d932008-10-13 22:52:42 -04001037 ec->display = eglCreateDisplayNative(gem_device, "i965");
Kristian Høgsberg16eb6752008-10-08 22:51:32 -04001038 if (ec->display == NULL) {
1039 fprintf(stderr, "failed to create display\n");
1040 return NULL;
1041 }
1042
1043 if (!eglInitialize(ec->display, &major, &minor)) {
1044 fprintf(stderr, "failed to initialize display\n");
1045 return NULL;
1046 }
1047
Kristian Høgsberg15d0f8b2008-12-19 12:13:42 -05001048 if (!eglChooseConfig(ec->display, config_attribs, &ec->config, 1, NULL))
Kristian Høgsberg16eb6752008-10-08 22:51:32 -04001049 return NULL;
Kristian Høgsbergbf9541f2008-11-25 12:10:09 -05001050
Kristian Høgsberg2c875bd2008-12-19 10:34:02 -05001051 fb_name = create_frontbuffer(ec);
Kristian Høgsbergbf9541f2008-11-25 12:10:09 -05001052 ec->surface = eglCreateSurfaceForName(ec->display, ec->config,
Kristian Høgsberg2c875bd2008-12-19 10:34:02 -05001053 fb_name, ec->width, ec->height, ec->stride, attribs);
Kristian Høgsberg16eb6752008-10-08 22:51:32 -04001054 if (ec->surface == NULL) {
1055 fprintf(stderr, "failed to create surface\n");
1056 return NULL;
1057 }
1058
Kristian Høgsberg2d9cd1e2008-11-03 08:09:34 -05001059 ec->context = eglCreateContext(ec->display, ec->config, NULL, NULL);
Kristian Høgsberg16eb6752008-10-08 22:51:32 -04001060 if (ec->context == NULL) {
1061 fprintf(stderr, "failed to create context\n");
1062 return NULL;
1063 }
1064
1065 if (!eglMakeCurrent(ec->display, ec->surface, ec->surface, ec->context)) {
1066 fprintf(stderr, "failed to make context current\n");
1067 return NULL;
1068 }
1069
Kristian Høgsberg8d7ca6b2008-11-09 00:22:51 -05001070 glViewport(0, 0, ec->width, ec->height);
Kristian Høgsberg16eb6752008-10-08 22:51:32 -04001071 glMatrixMode(GL_PROJECTION);
1072 glLoadIdentity();
Kristian Høgsberg8d7ca6b2008-11-09 00:22:51 -05001073 glOrtho(0, ec->width, ec->height, 0, 0, 1000.0);
Kristian Høgsberg16eb6752008-10-08 22:51:32 -04001074 glMatrixMode(GL_MODELVIEW);
Kristian Høgsberg5b7f8322008-12-18 12:08:19 -05001075 glClearColor(0, 0, 0.2, 1);
Kristian Høgsbergcddc0ad2008-11-24 00:31:49 -05001076
Kristian Høgsbergd2412e22008-12-15 20:35:24 -05001077 wl_display_set_compositor(display, &ec->base, &compositor_interface);
Kristian Høgsbergee02ca62008-12-21 23:37:12 -05001078
1079 /* FIXME: This needs to be much more expressive... something like randr 1.2. */
1080 ec->output.base.interface = &wl_output_interface;
1081 wl_display_add_object(display, &ec->output.base);
Kristian Høgsberg12ea62e2008-12-22 16:37:07 -05001082 wl_display_add_global(display, &ec->output.base, post_output_geometry);
Kristian Høgsbergee02ca62008-12-21 23:37:12 -05001083
Kristian Høgsbergde31d5c2008-12-18 17:55:33 -05001084 add_visuals(ec);
Kristian Høgsbergd2412e22008-12-15 20:35:24 -05001085
Kristian Høgsbergc492b482008-12-12 12:00:02 -05001086 wl_list_init(&ec->input_device_list);
Kristian Høgsberg890bc052008-12-30 14:31:33 -05001087 init_libudev(ec);
Kristian Høgsberg16eb6752008-10-08 22:51:32 -04001088
Kristian Høgsberg201a9042008-12-10 00:40:50 -05001089 wl_list_init(&ec->surface_list);
Kristian Høgsbergde31d5c2008-12-18 17:55:33 -05001090 ec->background = background_create(ec, option_background,
Kristian Høgsbergd6531262008-12-12 11:06:18 -05001091 ec->width, ec->height);
Kristian Høgsberg4c9f2c92008-11-21 19:25:44 -05001092
Kristian Høgsberg1e4b86a2008-11-23 23:41:08 -05001093 shooter = screenshooter_create(ec);
1094 wl_display_add_object(display, &shooter->base);
Kristian Høgsbergee02ca62008-12-21 23:37:12 -05001095 wl_display_add_global(display, &shooter->base, NULL);
Kristian Høgsberg8d7ca6b2008-11-09 00:22:51 -05001096
Kristian Høgsbergfbdbbdc2008-11-28 17:06:06 -05001097 loop = wl_display_get_event_loop(ec->wl_display);
Ray Strodee96dcb82008-12-20 02:00:49 -05001098
Kristian Høgsberg0ab26242008-12-21 19:33:09 -05001099 setup_tty(ec, loop);
1100
Kristian Høgsberg4a298902008-11-28 18:35:25 -05001101 ec->timer_source = wl_event_loop_add_timer(loop, repaint, ec);
Kristian Høgsbergfbdbbdc2008-11-28 17:06:06 -05001102 ec->repaint_needed = 0;
1103 ec->repaint_on_timeout = 0;
1104
Kristian Høgsbergef7a9ca2008-10-11 21:21:39 -04001105 schedule_repaint(ec);
1106
Kristian Høgsberg122912c2008-12-05 11:13:50 -05001107 return ec;
1108}
1109
1110/* The plan here is to generate a random anonymous socket name and
1111 * advertise that through a service on the session dbus.
1112 */
1113static const char socket_name[] = "\0wayland";
1114
1115int main(int argc, char *argv[])
1116{
1117 struct wl_display *display;
1118 struct egl_compositor *ec;
Kristian Høgsbergd6531262008-12-12 11:06:18 -05001119 GError *error = NULL;
1120 GOptionContext *context;
1121
1122 context = g_option_context_new(NULL);
1123 g_option_context_add_main_entries(context, option_entries, "Wayland");
1124 if (!g_option_context_parse(context, &argc, &argv, &error)) {
1125 fprintf(stderr, "option parsing failed: %s\n", error->message);
1126 exit(EXIT_FAILURE);
1127 }
Kristian Høgsberg122912c2008-12-05 11:13:50 -05001128
1129 display = wl_display_create();
1130
1131 ec = egl_compositor_create(display);
Kristian Høgsberg841883b2008-12-05 11:19:56 -05001132 if (ec == NULL) {
1133 fprintf(stderr, "failed to create compositor\n");
1134 exit(EXIT_FAILURE);
1135 }
1136
Kristian Høgsbergdc0f3552008-12-07 15:22:22 -05001137 if (wl_display_add_socket(display, socket_name, sizeof socket_name)) {
Kristian Høgsberg122912c2008-12-05 11:13:50 -05001138 fprintf(stderr, "failed to add socket: %m\n");
1139 exit(EXIT_FAILURE);
1140 }
1141
1142 wl_display_run(display);
1143
1144 return 0;
Kristian Høgsberg16eb6752008-10-08 22:51:32 -04001145}