blob: daca339181722d352619154334c43c6e11ac6b74 [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>
21#include <stdlib.h>
22#include <stdint.h>
Kristian Høgsberg8d7ca6b2008-11-09 00:22:51 -050023#include <stdarg.h>
Ray Strode966aa112008-12-19 14:28:02 -050024#include <termios.h>
Kristian Høgsberg16eb6752008-10-08 22:51:32 -040025#include <sys/ioctl.h>
Kristian Høgsberg16eb6752008-10-08 22:51:32 -040026#include <fcntl.h>
27#include <unistd.h>
Kristian Høgsberg4c9f2c92008-11-21 19:25:44 -050028#include <cairo.h>
Kristian Høgsbergaa5b5be2008-11-21 21:31:54 -050029#include <gdk-pixbuf/gdk-pixbuf.h>
Kristian Høgsberg54879822008-11-23 17:07:32 -050030#include <math.h>
Kristian Høgsbergcddc0ad2008-11-24 00:31:49 -050031#include <linux/input.h>
Ray Strode19ad6a92008-12-19 01:45:41 -050032#include <linux/vt.h>
Kristian Høgsbergbf9541f2008-11-25 12:10:09 -050033#include <xf86drmMode.h>
Kristian Høgsbergfbdbbdc2008-11-28 17:06:06 -050034#include <time.h>
Kristian Høgsberg16eb6752008-10-08 22:51:32 -040035
Kristian Høgsberg890bc052008-12-30 14:31:33 -050036#define LIBUDEV_I_KNOW_THE_API_IS_SUBJECT_TO_CHANGE
37#include <libudev.h>
38
Kristian Høgsberg16eb6752008-10-08 22:51:32 -040039#include <GL/gl.h>
40#include <eagle.h>
41
Kristian Høgsberg5ee1a602008-12-11 23:18:45 -050042#include "wayland.h"
Kristian Høgsbergfe831a72008-12-21 21:50:23 -050043#include "wayland-protocol.h"
Kristian Høgsberg5ee1a602008-12-11 23:18:45 -050044#include "cairo-util.h"
Kristian Høgsberg82f6e8a2008-12-19 13:47:53 -050045#include "wayland-system-compositor.h"
Kristian Høgsberg5ee1a602008-12-11 23:18:45 -050046
Kristian Høgsberg16eb6752008-10-08 22:51:32 -040047#define ARRAY_LENGTH(a) (sizeof (a) / sizeof (a)[0])
48
Kristian Høgsberg5c8c3282009-02-09 15:17:46 -050049struct wlsc_matrix {
50 GLdouble d[16];
51};
52
Kristian Høgsbergde31d5c2008-12-18 17:55:33 -050053struct wl_visual {
54 struct wl_object base;
55};
56
Kristian Høgsberg4fa48732009-03-10 23:17:00 -040057struct wlsc_surface;
58
59struct wlsc_listener {
60 struct wl_list link;
61 void (*func)(struct wlsc_listener *listener,
62 struct wlsc_surface *surface);
63};
64
Kristian Høgsberg81ce09a2008-12-31 16:18:42 -050065struct wlsc_output {
Kristian Høgsbergee02ca62008-12-21 23:37:12 -050066 struct wl_object base;
Kristian Høgsberg81ce09a2008-12-31 16:18:42 -050067 struct wl_list link;
Kristian Høgsberg1a208d52009-02-10 14:20:26 -050068 struct wlsc_compositor *compositor;
Kristian Høgsberg8e438622009-01-26 23:07:00 -050069 struct wlsc_surface *background;
Kristian Høgsberg81ce09a2008-12-31 16:18:42 -050070 EGLSurface surface;
Kristian Høgsbergb22382b2009-03-10 23:40:35 -040071 int32_t x, y, width, height;
Kristian Høgsberg81ce09a2008-12-31 16:18:42 -050072
Kristian Høgsberg41a10682009-02-15 22:37:03 -050073 drmModeModeInfo *mode;
Kristian Høgsberg81ce09a2008-12-31 16:18:42 -050074 uint32_t fb_id;
75 uint32_t crtc_id;
76 uint32_t connector_id;
Kristian Høgsbergee02ca62008-12-21 23:37:12 -050077};
78
Kristian Høgsberg82f6e8a2008-12-19 13:47:53 -050079struct wlsc_input_device {
Kristian Høgsberg5ee1a602008-12-11 23:18:45 -050080 struct wl_object base;
81 int32_t x, y;
Kristian Høgsberg8e438622009-01-26 23:07:00 -050082 struct wlsc_compositor *ec;
Kristian Høgsberg0555d8e2009-02-22 19:19:47 -050083 struct wlsc_surface *sprite;
Kristian Høgsbergc492b482008-12-12 12:00:02 -050084 struct wl_list link;
Kristian Høgsberg29573bc2008-12-11 23:27:27 -050085
86 int grab;
Kristian Høgsberg8e438622009-01-26 23:07:00 -050087 struct wlsc_surface *grab_surface;
Kristian Høgsbergdb6c2f32009-02-22 21:51:24 -050088 struct wlsc_surface *pointer_focus;
89 struct wlsc_surface *keyboard_focus;
Kristian Høgsberg3c38fa02009-02-23 22:30:29 -050090 struct wl_array keys;
Kristian Høgsberg4fa48732009-03-10 23:17:00 -040091
92 struct wlsc_listener listener;
Kristian Høgsberg5ee1a602008-12-11 23:18:45 -050093};
94
Kristian Høgsberg8e438622009-01-26 23:07:00 -050095struct wlsc_compositor {
Kristian Høgsberg16eb6752008-10-08 22:51:32 -040096 struct wl_compositor base;
Kristian Høgsbergde31d5c2008-12-18 17:55:33 -050097 struct wl_visual argb_visual, premultiplied_argb_visual, rgb_visual;
98
Kristian Høgsberg16eb6752008-10-08 22:51:32 -040099 EGLDisplay display;
Kristian Høgsberg16eb6752008-10-08 22:51:32 -0400100 EGLContext context;
Kristian Høgsberg2d9cd1e2008-11-03 08:09:34 -0500101 EGLConfig config;
Kristian Høgsbergf9212892008-10-11 18:40:23 -0400102 struct wl_display *wl_display;
Kristian Høgsbergfbdbbdc2008-11-28 17:06:06 -0500103
Kristian Høgsberg81ce09a2008-12-31 16:18:42 -0500104 struct wl_list output_list;
Kristian Høgsbergc492b482008-12-12 12:00:02 -0500105 struct wl_list input_device_list;
Kristian Høgsberg201a9042008-12-10 00:40:50 -0500106 struct wl_list surface_list;
107
Kristian Høgsberg4fa48732009-03-10 23:17:00 -0400108 struct wl_list surface_destroy_listener_list;
109
Ray Strode966aa112008-12-19 14:28:02 -0500110 struct wl_event_source *term_signal_source;
111
112 /* tty handling state */
113 int tty_fd;
Ray Strodee96dcb82008-12-20 02:00:49 -0500114 uint32_t vt_active : 1;
Ray Strode966aa112008-12-19 14:28:02 -0500115
116 struct termios terminal_attributes;
117 struct wl_event_source *tty_input_source;
Ray Strode19ad6a92008-12-19 01:45:41 -0500118 struct wl_event_source *enter_vt_source;
119 struct wl_event_source *leave_vt_source;
120
Kristian Høgsberg890bc052008-12-30 14:31:33 -0500121 struct udev *udev;
122
Kristian Høgsbergfbdbbdc2008-11-28 17:06:06 -0500123 /* Repaint state. */
124 struct wl_event_source *timer_source;
125 int repaint_needed;
126 int repaint_on_timeout;
Kristian Høgsbergfbdbbdc2008-11-28 17:06:06 -0500127 struct timespec previous_swap;
128 uint32_t current_frame;
Kristian Høgsberg5c8c3282009-02-09 15:17:46 -0500129
130 uint32_t meta_state;
Kristian Høgsberg1a208d52009-02-10 14:20:26 -0500131 struct wl_list animate_list;
Kristian Høgsberg8da19ac2009-03-17 16:12:51 -0400132
133 struct wlsc_session *primary;
134 struct wl_list session_list;
Kristian Høgsberg16eb6752008-10-08 22:51:32 -0400135};
136
Kristian Høgsberg5c8c3282009-02-09 15:17:46 -0500137#define META_DOWN 256
138
Kristian Høgsberg8da19ac2009-03-17 16:12:51 -0400139struct wlsc_vector {
140 GLdouble x, y, z;
141};
142
Kristian Høgsberg1a208d52009-02-10 14:20:26 -0500143struct wlsc_animate {
144 struct wl_list link;
145 void (*animate)(struct wlsc_animate *animate,
146 struct wlsc_compositor *compositor,
147 uint32_t frame, uint32_t msecs);
148};
149
Kristian Høgsberg8da19ac2009-03-17 16:12:51 -0400150struct wlsc_session {
151 struct wlsc_surface *surface;
152 struct wlsc_vector target, current, previous;
153 GLdouble target_angle, current_angle, previous_angle;
154 struct wlsc_animate animate;
155 struct wl_list link;
156 struct wlsc_listener listener;
Kristian Høgsberg1a208d52009-02-10 14:20:26 -0500157};
158
Kristian Høgsberg8e438622009-01-26 23:07:00 -0500159struct wlsc_surface {
Kristian Høgsbergd2412e22008-12-15 20:35:24 -0500160 struct wl_surface base;
Kristian Høgsberg8e438622009-01-26 23:07:00 -0500161 struct wlsc_compositor *compositor;
Kristian Høgsbergde31d5c2008-12-18 17:55:33 -0500162 struct wl_visual *visual;
Kristian Høgsberg16eb6752008-10-08 22:51:32 -0400163 GLuint texture;
Kristian Høgsbergf9212892008-10-11 18:40:23 -0400164 struct wl_map map;
Kristian Høgsberg2d9cd1e2008-11-03 08:09:34 -0500165 EGLSurface surface;
Kristian Høgsberg715a0812008-12-10 10:42:04 -0500166 int width, height;
Kristian Høgsberg201a9042008-12-10 00:40:50 -0500167 struct wl_list link;
Kristian Høgsberg5c8c3282009-02-09 15:17:46 -0500168 struct wlsc_matrix matrix;
Kristian Høgsberg1a208d52009-02-10 14:20:26 -0500169
Kristian Høgsberg8da19ac2009-03-17 16:12:51 -0400170 /* FIXME: This should be it's own object at some point. */
171 struct wlsc_session session;
Kristian Høgsberg16eb6752008-10-08 22:51:32 -0400172};
173
Kristian Høgsberg81ce09a2008-12-31 16:18:42 -0500174static const char *option_background = "background.jpg";
175
176static const GOptionEntry option_entries[] = {
177 { "background", 'b', 0, G_OPTION_ARG_STRING,
178 &option_background, "Background image" },
179 { NULL }
180};
181
Kristian Høgsberg1e4b86a2008-11-23 23:41:08 -0500182struct screenshooter {
183 struct wl_object base;
Kristian Høgsberg8e438622009-01-26 23:07:00 -0500184 struct wlsc_compositor *ec;
Kristian Høgsberg1e4b86a2008-11-23 23:41:08 -0500185};
186
Kristian Høgsbergd2412e22008-12-15 20:35:24 -0500187struct screenshooter_interface {
188 void (*shoot)(struct wl_client *client, struct screenshooter *shooter);
189};
190
Kristian Høgsberg8d7ca6b2008-11-09 00:22:51 -0500191static void
Kristian Høgsberg1e4b86a2008-11-23 23:41:08 -0500192screenshooter_shoot(struct wl_client *client, struct screenshooter *shooter)
Kristian Høgsberg8d7ca6b2008-11-09 00:22:51 -0500193{
Kristian Høgsberg8e438622009-01-26 23:07:00 -0500194 struct wlsc_compositor *ec = shooter->ec;
Kristian Høgsberg81ce09a2008-12-31 16:18:42 -0500195 struct wlsc_output *output;
Kristian Høgsberg81ce09a2008-12-31 16:18:42 -0500196 char buffer[256];
Kristian Høgsbergc0b44322009-01-26 22:54:40 -0500197 GdkPixbuf *pixbuf, *normal;
Kristian Høgsberg0ea47102008-12-14 15:53:13 -0500198 GError *error = NULL;
Kristian Høgsberg1a208d52009-02-10 14:20:26 -0500199 unsigned char *data;
200 int i, j;
Kristian Høgsberg8d7ca6b2008-11-09 00:22:51 -0500201
Kristian Høgsberg81ce09a2008-12-31 16:18:42 -0500202 i = 0;
203 output = container_of(ec->output_list.next, struct wlsc_output, link);
204 while (&output->link != &ec->output_list) {
205 snprintf(buffer, sizeof buffer, "wayland-screenshot-%d.png", i++);
Kristian Høgsbergc0b44322009-01-26 22:54:40 -0500206 data = malloc(output->width * output->height * 4);
207 if (data == NULL) {
208 fprintf(stderr, "couldn't allocate image buffer\n");
209 continue;
210 }
211
212 glReadBuffer(GL_FRONT);
213 glPixelStorei(GL_PACK_ALIGNMENT, 1);
214 glReadPixels(0, 0, output->width, output->height,
215 GL_RGBA, GL_UNSIGNED_BYTE, data);
216
Kristian Høgsberg1a208d52009-02-10 14:20:26 -0500217 /* FIXME: We should just use a RGB visual for the frontbuffer. */
218 for (j = 3; j < output->width * output->height * 4; j += 4)
219 data[j] = 0xff;
220
Kristian Høgsberg81ce09a2008-12-31 16:18:42 -0500221 pixbuf = gdk_pixbuf_new_from_data(data, GDK_COLORSPACE_RGB, TRUE,
Kristian Høgsbergc0b44322009-01-26 22:54:40 -0500222 8, output->width, output->height, output->width * 4,
Kristian Høgsberg81ce09a2008-12-31 16:18:42 -0500223 NULL, NULL);
Kristian Høgsbergc0b44322009-01-26 22:54:40 -0500224 normal = gdk_pixbuf_flip(pixbuf, FALSE);
225 gdk_pixbuf_save(normal, buffer, "png", &error, NULL);
226 gdk_pixbuf_unref(normal);
227 gdk_pixbuf_unref(pixbuf);
228 free(data);
Kristian Høgsberg81ce09a2008-12-31 16:18:42 -0500229
230 output = container_of(output->link.next,
231 struct wlsc_output, link);
232 }
Kristian Høgsberg8d7ca6b2008-11-09 00:22:51 -0500233}
234
Kristian Høgsbergfb6d68d2008-12-21 21:54:51 -0500235static const struct wl_message screenshooter_methods[] = {
Kristian Høgsbergd2412e22008-12-15 20:35:24 -0500236 { "shoot", "", NULL }
Kristian Høgsberg1e4b86a2008-11-23 23:41:08 -0500237};
238
239static const struct wl_interface screenshooter_interface = {
240 "screenshooter", 1,
241 ARRAY_LENGTH(screenshooter_methods),
242 screenshooter_methods,
243};
244
Kristian Høgsbergd2412e22008-12-15 20:35:24 -0500245struct screenshooter_interface screenshooter_implementation = {
246 screenshooter_shoot
247};
248
Kristian Høgsberg1e4b86a2008-11-23 23:41:08 -0500249static struct screenshooter *
Kristian Høgsberg8e438622009-01-26 23:07:00 -0500250screenshooter_create(struct wlsc_compositor *ec)
Kristian Høgsberg1e4b86a2008-11-23 23:41:08 -0500251{
252 struct screenshooter *shooter;
253
254 shooter = malloc(sizeof *shooter);
255 if (shooter == NULL)
256 return NULL;
257
258 shooter->base.interface = &screenshooter_interface;
Kristian Høgsbergd2412e22008-12-15 20:35:24 -0500259 shooter->base.implementation = (void(**)(void)) &screenshooter_implementation;
Kristian Høgsberg1e4b86a2008-11-23 23:41:08 -0500260 shooter->ec = ec;
261
262 return shooter;
263};
Kristian Høgsberg5c8c3282009-02-09 15:17:46 -0500264
265static void
266wlsc_matrix_init(struct wlsc_matrix *matrix)
267{
268 static const struct wlsc_matrix identity = {
269 { 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1 }
270 };
271
272 memcpy(matrix, &identity, sizeof identity);
273}
274
275static void
276wlsc_matrix_multiply(struct wlsc_matrix *m, const struct wlsc_matrix *n)
277{
278 struct wlsc_matrix tmp;
279 const GLdouble *row, *column;
280 div_t d;
281 int i, j;
282
283 for (i = 0; i < 16; i++) {
284 tmp.d[i] = 0;
285 d = div(i, 4);
286 row = m->d + d.quot * 4;
287 column = n->d + d.rem;
288 for (j = 0; j < 4; j++)
289 tmp.d[i] += row[j] * column[j * 4];
290 }
291 memcpy(m, &tmp, sizeof tmp);
292}
293
294static void
295wlsc_matrix_translate(struct wlsc_matrix *matrix, GLdouble x, GLdouble y, GLdouble z)
296{
297 struct wlsc_matrix translate = {
298 { 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, x, y, z, 1 }
299 };
300
301 wlsc_matrix_multiply(matrix, &translate);
302}
303
304static void
305wlsc_matrix_scale(struct wlsc_matrix *matrix, GLdouble x, GLdouble y, GLdouble z)
306{
307 struct wlsc_matrix scale = {
308 { x, 0, 0, 0, 0, y, 0, 0, 0, 0, z, 0, 0, 0, 0, 1 }
309 };
310
311 wlsc_matrix_multiply(matrix, &scale);
312}
313
314static void
315wlsc_matrix_rotate(struct wlsc_matrix *matrix,
316 GLdouble angle, GLdouble x, GLdouble y, GLdouble z)
317{
318 GLdouble c = cos(angle);
319 GLdouble s = sin(angle);
320 struct wlsc_matrix rotate = {
321 { x * x * (1 - c) + c, y * x * (1 - c) + z * s, x * z * (1 - c) - y * s, 0,
322 x * y * (1 - c) - z * s, y * y * (1 - c) + c, y * z * (1 - c) - x * s, 0,
323 x * z * (1 - c) + y * x, y * z * (1 - c) - x * s, z * z * (1 - c) + c, 0,
324 0, 0, 0, 1 }
325 };
326
327 wlsc_matrix_multiply(matrix, &rotate);
328}
329
330static void
Kristian Høgsberg1a208d52009-02-10 14:20:26 -0500331wlsc_surface_init(struct wlsc_surface *surface,
332 struct wlsc_compositor *compositor, struct wl_visual *visual,
333 int32_t x, int32_t y, int32_t width, int32_t height)
334{
335 glGenTextures(1, &surface->texture);
336 surface->compositor = compositor;
337 surface->map.x = x;
338 surface->map.y = y;
339 surface->map.width = width;
340 surface->map.height = height;
341 surface->surface = EGL_NO_SURFACE;
342 surface->visual = visual;
Kristian Høgsberg8da19ac2009-03-17 16:12:51 -0400343 wlsc_matrix_init(&surface->matrix);
Kristian Høgsberg5c8c3282009-02-09 15:17:46 -0500344}
Kristian Høgsberg1e4b86a2008-11-23 23:41:08 -0500345
Kristian Høgsberg8e438622009-01-26 23:07:00 -0500346static struct wlsc_surface *
347wlsc_surface_create_from_cairo_surface(struct wlsc_compositor *ec,
Kristian Høgsbergde31d5c2008-12-18 17:55:33 -0500348 cairo_surface_t *surface,
Kristian Høgsberg54879822008-11-23 17:07:32 -0500349 int x, int y, int width, int height)
350{
Kristian Høgsberg8e438622009-01-26 23:07:00 -0500351 struct wlsc_surface *es;
Kristian Høgsberg54879822008-11-23 17:07:32 -0500352 int stride;
353 void *data;
354
355 stride = cairo_image_surface_get_stride(surface);
356 data = cairo_image_surface_get_data(surface);
357
358 es = malloc(sizeof *es);
359 if (es == NULL)
360 return NULL;
361
Kristian Høgsberg1a208d52009-02-10 14:20:26 -0500362 wlsc_surface_init(es, ec, &ec->premultiplied_argb_visual,
363 x, y, width, height);
Kristian Høgsberg54879822008-11-23 17:07:32 -0500364 glBindTexture(GL_TEXTURE_2D, es->texture);
365 glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
Kristian Høgsberg98fed0f2008-12-09 13:35:35 -0500366 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_R, GL_REPEAT);
367 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
368 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
Kristian Høgsberg54879822008-11-23 17:07:32 -0500369 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0,
370 GL_BGRA, GL_UNSIGNED_BYTE, data);
371
Kristian Høgsberg54879822008-11-23 17:07:32 -0500372 return es;
373}
374
375static void
Kristian Høgsberg4fa48732009-03-10 23:17:00 -0400376wlsc_surface_destroy(struct wlsc_surface *surface,
377 struct wlsc_compositor *compositor)
Kristian Høgsberg54879822008-11-23 17:07:32 -0500378{
Kristian Høgsberg8da19ac2009-03-17 16:12:51 -0400379 struct wlsc_listener *l, *next;
Kristian Høgsberg4fa48732009-03-10 23:17:00 -0400380
381 l = container_of(compositor->surface_destroy_listener_list.next,
382 struct wlsc_listener, link);
383 while (&l->link != &compositor->surface_destroy_listener_list) {
Kristian Høgsberg8da19ac2009-03-17 16:12:51 -0400384 next = container_of(l->link.next, struct wlsc_listener, link);
Kristian Høgsberg4fa48732009-03-10 23:17:00 -0400385 l->func(l, surface);
Kristian Høgsberg8da19ac2009-03-17 16:12:51 -0400386 l = next;
Kristian Høgsberg4fa48732009-03-10 23:17:00 -0400387 }
388
389 wl_list_remove(&surface->link);
Kristian Høgsberg4fa48732009-03-10 23:17:00 -0400390
391 glDeleteTextures(1, &surface->texture);
392 if (surface->surface != EGL_NO_SURFACE)
393 eglDestroySurface(compositor->display, surface->surface);
394 free(surface);
Kristian Høgsberg54879822008-11-23 17:07:32 -0500395}
396
Kristian Høgsbergef7a9ca2008-10-11 21:21:39 -0400397static void
Kristian Høgsberg4c9f2c92008-11-21 19:25:44 -0500398pointer_path(cairo_t *cr, int x, int y)
399{
400 const int end = 3, tx = 4, ty = 12, dx = 5, dy = 10;
401 const int width = 16, height = 16;
402
403 cairo_move_to(cr, x, y);
404 cairo_line_to(cr, x + tx, y + ty);
405 cairo_line_to(cr, x + dx, y + dy);
406 cairo_line_to(cr, x + width - end, y + height);
407 cairo_line_to(cr, x + width, y + height - end);
408 cairo_line_to(cr, x + dy, y + dx);
409 cairo_line_to(cr, x + ty, y + tx);
410 cairo_close_path(cr);
411}
412
Kristian Høgsberg8e438622009-01-26 23:07:00 -0500413static struct wlsc_surface *
414pointer_create(struct wlsc_compositor *ec, int x, int y, int width, int height)
Kristian Høgsberg4c9f2c92008-11-21 19:25:44 -0500415{
Kristian Høgsberg8e438622009-01-26 23:07:00 -0500416 struct wlsc_surface *es;
Kristian Høgsberg4c9f2c92008-11-21 19:25:44 -0500417 const int hotspot_x = 16, hotspot_y = 16;
Kristian Høgsberg4c9f2c92008-11-21 19:25:44 -0500418 cairo_surface_t *surface;
419 cairo_t *cr;
Kristian Høgsberg4c9f2c92008-11-21 19:25:44 -0500420
421 surface = cairo_image_surface_create(CAIRO_FORMAT_ARGB32,
422 width, height);
423
424 cr = cairo_create(surface);
425 pointer_path(cr, hotspot_x + 5, hotspot_y + 4);
Kristian Høgsberg0ab26242008-12-21 19:33:09 -0500426 cairo_set_line_width(cr, 2);
Kristian Høgsberg4c9f2c92008-11-21 19:25:44 -0500427 cairo_set_source_rgb(cr, 0, 0, 0);
428 cairo_stroke_preserve(cr);
429 cairo_fill(cr);
430 blur_surface(surface, width);
431
432 pointer_path(cr, hotspot_x, hotspot_y);
433 cairo_stroke_preserve(cr);
434 cairo_set_source_rgb(cr, 1, 1, 1);
435 cairo_fill(cr);
436 cairo_destroy(cr);
437
Kristian Høgsberg8e438622009-01-26 23:07:00 -0500438 es = wlsc_surface_create_from_cairo_surface(ec,
Kristian Høgsbergde31d5c2008-12-18 17:55:33 -0500439 surface,
Kristian Høgsberg5ee1a602008-12-11 23:18:45 -0500440 x - hotspot_x,
441 y - hotspot_y,
442 width, height);
Kristian Høgsberg54879822008-11-23 17:07:32 -0500443
Kristian Høgsberg4c9f2c92008-11-21 19:25:44 -0500444 cairo_surface_destroy(surface);
445
Kristian Høgsberg54879822008-11-23 17:07:32 -0500446 return es;
Kristian Høgsbergaa5b5be2008-11-21 21:31:54 -0500447}
448
Kristian Høgsberg8e438622009-01-26 23:07:00 -0500449static struct wlsc_surface *
Kristian Høgsberg81ce09a2008-12-31 16:18:42 -0500450background_create(struct wlsc_output *output, const char *filename)
Kristian Høgsbergaa5b5be2008-11-21 21:31:54 -0500451{
Kristian Høgsberg8e438622009-01-26 23:07:00 -0500452 struct wlsc_surface *background;
Kristian Høgsbergaa5b5be2008-11-21 21:31:54 -0500453 GdkPixbuf *pixbuf;
454 GError *error = NULL;
Kristian Høgsbergaa5b5be2008-11-21 21:31:54 -0500455 void *data;
Ray Strode18fd33c2008-12-18 21:05:20 -0500456 GLenum format;
Kristian Høgsbergaa5b5be2008-11-21 21:31:54 -0500457
458 background = malloc(sizeof *background);
459 if (background == NULL)
460 return NULL;
461
462 g_type_init();
463
Kristian Høgsberg0ab26242008-12-21 19:33:09 -0500464 pixbuf = gdk_pixbuf_new_from_file_at_scale(filename,
Kristian Høgsberg81ce09a2008-12-31 16:18:42 -0500465 output->width,
466 output->height,
Kristian Høgsberg0ab26242008-12-21 19:33:09 -0500467 FALSE, &error);
Kristian Høgsbergaa5b5be2008-11-21 21:31:54 -0500468 if (error != NULL) {
469 free(background);
470 return NULL;
471 }
472
Kristian Høgsbergaa5b5be2008-11-21 21:31:54 -0500473 data = gdk_pixbuf_get_pixels(pixbuf);
474
Kristian Høgsberg1a208d52009-02-10 14:20:26 -0500475 wlsc_surface_init(background, output->compositor,
476 &output->compositor->rgb_visual,
477 output->x, output->y, output->width, output->height);
478
Kristian Høgsbergaa5b5be2008-11-21 21:31:54 -0500479 glBindTexture(GL_TEXTURE_2D, background->texture);
480 glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
Kristian Høgsberg98fed0f2008-12-09 13:35:35 -0500481 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_R, GL_REPEAT);
Kristian Høgsbergfdec2362001-01-01 22:23:51 -0500482 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
483 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
Ray Strode18fd33c2008-12-18 21:05:20 -0500484
Kristian Høgsberg0ab26242008-12-21 19:33:09 -0500485 if (gdk_pixbuf_get_has_alpha(pixbuf))
Ray Strode18fd33c2008-12-18 21:05:20 -0500486 format = GL_RGBA;
Kristian Høgsberg0ab26242008-12-21 19:33:09 -0500487 else
Ray Strode18fd33c2008-12-18 21:05:20 -0500488 format = GL_RGB;
Ray Strode18fd33c2008-12-18 21:05:20 -0500489
Kristian Høgsberg81ce09a2008-12-31 16:18:42 -0500490 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB,
491 output->width, output->height, 0,
Ray Strode18fd33c2008-12-18 21:05:20 -0500492 format, GL_UNSIGNED_BYTE, data);
Kristian Høgsbergaa5b5be2008-11-21 21:31:54 -0500493
Kristian Høgsbergaa5b5be2008-11-21 21:31:54 -0500494 return background;
Kristian Høgsberg4c9f2c92008-11-21 19:25:44 -0500495}
496
497static void
Kristian Høgsberg5c8c3282009-02-09 15:17:46 -0500498wlsc_surface_draw(struct wlsc_surface *es)
Kristian Høgsberg4c9f2c92008-11-21 19:25:44 -0500499{
Kristian Høgsberg8e438622009-01-26 23:07:00 -0500500 struct wlsc_compositor *ec = es->compositor;
Kristian Høgsberg4c9f2c92008-11-21 19:25:44 -0500501 GLint vertices[12];
502 GLint tex_coords[12] = { 0, 0, 0, 1, 1, 0, 1, 1 };
503 GLuint indices[4] = { 0, 1, 2, 3 };
504
Kristian Høgsbergaa5b5be2008-11-21 21:31:54 -0500505 vertices[0] = es->map.x;
506 vertices[1] = es->map.y;
Kristian Høgsberg4c9f2c92008-11-21 19:25:44 -0500507 vertices[2] = 0;
508
Kristian Høgsbergaa5b5be2008-11-21 21:31:54 -0500509 vertices[3] = es->map.x;
510 vertices[4] = es->map.y + es->map.height;
Kristian Høgsberg4c9f2c92008-11-21 19:25:44 -0500511 vertices[5] = 0;
512
Kristian Høgsbergaa5b5be2008-11-21 21:31:54 -0500513 vertices[6] = es->map.x + es->map.width;
514 vertices[7] = es->map.y;
Kristian Høgsberg4c9f2c92008-11-21 19:25:44 -0500515 vertices[8] = 0;
516
Kristian Høgsbergaa5b5be2008-11-21 21:31:54 -0500517 vertices[9] = es->map.x + es->map.width;
518 vertices[10] = es->map.y + es->map.height;
Kristian Høgsberg4c9f2c92008-11-21 19:25:44 -0500519 vertices[11] = 0;
520
Kristian Høgsbergde31d5c2008-12-18 17:55:33 -0500521 if (es->visual == &ec->argb_visual) {
522 glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
523 glEnable(GL_BLEND);
524 } else if (es->visual == &ec->premultiplied_argb_visual) {
525 glBlendFunc(GL_ONE, GL_ONE_MINUS_SRC_ALPHA);
526 glEnable(GL_BLEND);
527 } else {
528 glDisable(GL_BLEND);
529 }
530
Kristian Høgsberg5c8c3282009-02-09 15:17:46 -0500531 glPushMatrix();
532 glMultMatrixd(es->matrix.d);
Kristian Høgsbergaa5b5be2008-11-21 21:31:54 -0500533 glBindTexture(GL_TEXTURE_2D, es->texture);
Kristian Høgsberg4c9f2c92008-11-21 19:25:44 -0500534 glEnable(GL_TEXTURE_2D);
Kristian Høgsberg4c9f2c92008-11-21 19:25:44 -0500535 glEnableClientState(GL_VERTEX_ARRAY);
536 glEnableClientState(GL_TEXTURE_COORD_ARRAY);
537 glVertexPointer(3, GL_INT, 0, vertices);
538 glTexCoordPointer(2, GL_INT, 0, tex_coords);
539 glDrawElements(GL_TRIANGLE_STRIP, 4, GL_UNSIGNED_INT, indices);
Kristian Høgsberg5c8c3282009-02-09 15:17:46 -0500540 glPopMatrix();
Kristian Høgsberg4c9f2c92008-11-21 19:25:44 -0500541}
542
543static void
Kristian Høgsberg8da19ac2009-03-17 16:12:51 -0400544wlsc_surface_raise(struct wlsc_surface *surface)
545{
546 struct wlsc_compositor *compositor = surface->compositor;
547
548 wl_list_remove(&surface->link);
549 wl_list_insert(compositor->surface_list.prev, &surface->link);
550}
551
552static void
553wlsc_surface_lower(struct wlsc_surface *surface)
554{
555 struct wlsc_compositor *compositor = surface->compositor;
556
557 wl_list_remove(&surface->link);
558 wl_list_insert(&compositor->surface_list, &surface->link);
559}
560
561static void
Kristian Høgsberg1a208d52009-02-10 14:20:26 -0500562wlsc_vector_add(struct wlsc_vector *v1, struct wlsc_vector *v2)
563{
564 v1->x += v2->x;
565 v1->y += v2->y;
566 v1->z += v2->z;
567}
568
569static void
570wlsc_vector_subtract(struct wlsc_vector *v1, struct wlsc_vector *v2)
571{
572 v1->x -= v2->x;
573 v1->y -= v2->y;
574 v1->z -= v2->z;
575}
576
577static void
578wlsc_vector_scalar(struct wlsc_vector *v1, GLdouble s)
579{
580 v1->x *= s;
581 v1->y *= s;
582 v1->z *= s;
583}
584
585static void
Kristian Høgsberg81ce09a2008-12-31 16:18:42 -0500586repaint_output(struct wlsc_output *output)
Kristian Høgsbergef7a9ca2008-10-11 21:21:39 -0400587{
Kristian Høgsberg1a208d52009-02-10 14:20:26 -0500588 struct wlsc_compositor *ec = output->compositor;
Kristian Høgsberg8e438622009-01-26 23:07:00 -0500589 struct wlsc_surface *es;
Kristian Høgsberg82f6e8a2008-12-19 13:47:53 -0500590 struct wlsc_input_device *eid;
Kristian Høgsbergfdec2362001-01-01 22:23:51 -0500591 double s = 3000;
Kristian Høgsbergfbdbbdc2008-11-28 17:06:06 -0500592
Kristian Høgsberg81ce09a2008-12-31 16:18:42 -0500593 if (!eglMakeCurrent(ec->display, output->surface, output->surface, ec->context)) {
594 fprintf(stderr, "failed to make context current\n");
Kristian Høgsbergfbdbbdc2008-11-28 17:06:06 -0500595 return;
596 }
Kristian Høgsbergaa5b5be2008-11-21 21:31:54 -0500597
Kristian Høgsberg81ce09a2008-12-31 16:18:42 -0500598 glViewport(0, 0, output->width, output->height);
599 glMatrixMode(GL_PROJECTION);
600 glLoadIdentity();
Kristian Høgsberg5c8c3282009-02-09 15:17:46 -0500601 glFrustum(-output->width / s, output->width / s,
602 output->height / s, -output->height / s, 1, 2 * s);
Kristian Høgsberg81ce09a2008-12-31 16:18:42 -0500603 glMatrixMode(GL_MODELVIEW);
Kristian Høgsbergfdec2362001-01-01 22:23:51 -0500604 glLoadIdentity();
Kristian Høgsberg8da19ac2009-03-17 16:12:51 -0400605 glClearColor(0, 0, 0, 1);
Kristian Høgsberg81ce09a2008-12-31 16:18:42 -0500606
Kristian Høgsberg5c8c3282009-02-09 15:17:46 -0500607 glTranslatef(-output->width / 2, -output->height / 2, -s / 2);
Kristian Høgsbergfdec2362001-01-01 22:23:51 -0500608
Kristian Høgsberg81ce09a2008-12-31 16:18:42 -0500609 if (output->background)
Kristian Høgsberg5c8c3282009-02-09 15:17:46 -0500610 wlsc_surface_draw(output->background);
Kristian Høgsberg5b7f8322008-12-18 12:08:19 -0500611 else
612 glClear(GL_COLOR_BUFFER_BIT);
Kristian Høgsbergef7a9ca2008-10-11 21:21:39 -0400613
Kristian Høgsberg201a9042008-12-10 00:40:50 -0500614 es = container_of(ec->surface_list.next,
Kristian Høgsberg8e438622009-01-26 23:07:00 -0500615 struct wlsc_surface, link);
Kristian Høgsberg201a9042008-12-10 00:40:50 -0500616 while (&es->link != &ec->surface_list) {
Kristian Høgsberg5c8c3282009-02-09 15:17:46 -0500617 wlsc_surface_draw(es);
Kristian Høgsberg201a9042008-12-10 00:40:50 -0500618 es = container_of(es->link.next,
Kristian Høgsberg8e438622009-01-26 23:07:00 -0500619 struct wlsc_surface, link);
Kristian Høgsbergef7a9ca2008-10-11 21:21:39 -0400620 }
Kristian Høgsbergef7a9ca2008-10-11 21:21:39 -0400621
Kristian Høgsbergc492b482008-12-12 12:00:02 -0500622 eid = container_of(ec->input_device_list.next,
Kristian Høgsberg82f6e8a2008-12-19 13:47:53 -0500623 struct wlsc_input_device, link);
Kristian Høgsbergc492b482008-12-12 12:00:02 -0500624 while (&eid->link != &ec->input_device_list) {
Kristian Høgsberg0555d8e2009-02-22 19:19:47 -0500625 wlsc_surface_draw(eid->sprite);
Kristian Høgsbergc492b482008-12-12 12:00:02 -0500626
627 eid = container_of(eid->link.next,
Kristian Høgsberg82f6e8a2008-12-19 13:47:53 -0500628 struct wlsc_input_device, link);
Kristian Høgsbergc492b482008-12-12 12:00:02 -0500629 }
Kristian Høgsberg4c9f2c92008-11-21 19:25:44 -0500630
Kristian Høgsberg81ce09a2008-12-31 16:18:42 -0500631 eglSwapBuffers(ec->display, output->surface);
632}
633
634static void
635repaint(void *data)
636{
Kristian Høgsberg8e438622009-01-26 23:07:00 -0500637 struct wlsc_compositor *ec = data;
Kristian Høgsberg81ce09a2008-12-31 16:18:42 -0500638 struct wlsc_output *output;
Kristian Høgsberg1a208d52009-02-10 14:20:26 -0500639 struct wlsc_animate *animate, *next;
Kristian Høgsberg81ce09a2008-12-31 16:18:42 -0500640 struct timespec ts;
641 uint32_t msecs;
642
643 if (!ec->repaint_needed) {
644 ec->repaint_on_timeout = 0;
645 return;
646 }
647
648 output = container_of(ec->output_list.next, struct wlsc_output, link);
649 while (&output->link != &ec->output_list) {
650 repaint_output(output);
651 output = container_of(output->link.next,
652 struct wlsc_output, link);
653 }
654
Kristian Høgsbergfbdbbdc2008-11-28 17:06:06 -0500655 ec->repaint_needed = 0;
Kristian Høgsberg9af92b32008-11-24 01:12:46 -0500656
Kristian Høgsbergfbdbbdc2008-11-28 17:06:06 -0500657 clock_gettime(CLOCK_MONOTONIC, &ts);
658 msecs = ts.tv_sec * 1000 + ts.tv_nsec / (1000 * 1000);
Kristian Høgsbergd2412e22008-12-15 20:35:24 -0500659 wl_display_post_frame(ec->wl_display, &ec->base,
660 ec->current_frame, msecs);
Kristian Høgsbergfbdbbdc2008-11-28 17:06:06 -0500661
Kristian Høgsberg4a298902008-11-28 18:35:25 -0500662 wl_event_source_timer_update(ec->timer_source, 10);
Kristian Høgsbergfbdbbdc2008-11-28 17:06:06 -0500663 ec->repaint_on_timeout = 1;
Kristian Høgsberg1a208d52009-02-10 14:20:26 -0500664
665 animate = container_of(ec->animate_list.next, struct wlsc_animate, link);
666 while (&animate->link != &ec->animate_list) {
667 next = container_of(animate->link.next,
668 struct wlsc_animate, link);
669 animate->animate(animate, ec, ec->current_frame, msecs);
670 animate = next;
671 }
672
673 ec->current_frame++;
Kristian Høgsbergef7a9ca2008-10-11 21:21:39 -0400674}
675
Kristian Høgsberg5503bf82008-11-06 10:38:17 -0500676static void
Kristian Høgsberg8da19ac2009-03-17 16:12:51 -0400677wlsc_compositor_schedule_repaint(struct wlsc_compositor *compositor)
Kristian Høgsbergef7a9ca2008-10-11 21:21:39 -0400678{
679 struct wl_event_loop *loop;
680
Kristian Høgsberg8da19ac2009-03-17 16:12:51 -0400681 compositor->repaint_needed = 1;
682 if (!compositor->repaint_on_timeout) {
683 loop = wl_display_get_event_loop(compositor->wl_display);
684 wl_event_loop_add_idle(loop, repaint, compositor);
Kristian Høgsbergfbdbbdc2008-11-28 17:06:06 -0500685 }
Kristian Høgsbergef7a9ca2008-10-11 21:21:39 -0400686}
Kristian Høgsberg5c8c3282009-02-09 15:17:46 -0500687
Kristian Høgsberg5503bf82008-11-06 10:38:17 -0500688static void
Kristian Høgsbergd2412e22008-12-15 20:35:24 -0500689surface_destroy(struct wl_client *client,
690 struct wl_surface *surface)
Kristian Høgsberg16eb6752008-10-08 22:51:32 -0400691{
Kristian Høgsberg8e438622009-01-26 23:07:00 -0500692 struct wlsc_surface *es = (struct wlsc_surface *) surface;
693 struct wlsc_compositor *ec = es->compositor;
Kristian Høgsberg2d9cd1e2008-11-03 08:09:34 -0500694
Kristian Høgsberg8e438622009-01-26 23:07:00 -0500695 wlsc_surface_destroy(es, ec);
Kristian Høgsbergef7a9ca2008-10-11 21:21:39 -0400696
Kristian Høgsberg8da19ac2009-03-17 16:12:51 -0400697 wlsc_compositor_schedule_repaint(ec);
Kristian Høgsberg16eb6752008-10-08 22:51:32 -0400698}
699
Kristian Høgsberg5503bf82008-11-06 10:38:17 -0500700static void
Kristian Høgsbergd2412e22008-12-15 20:35:24 -0500701surface_attach(struct wl_client *client,
702 struct wl_surface *surface, uint32_t name,
Kristian Høgsbergde31d5c2008-12-18 17:55:33 -0500703 uint32_t width, uint32_t height, uint32_t stride,
704 struct wl_object *visual)
Kristian Høgsberg16eb6752008-10-08 22:51:32 -0400705{
Kristian Høgsberg8e438622009-01-26 23:07:00 -0500706 struct wlsc_surface *es = (struct wlsc_surface *) surface;
707 struct wlsc_compositor *ec = es->compositor;
Kristian Høgsberg16eb6752008-10-08 22:51:32 -0400708
Kristian Høgsbergaa5b5be2008-11-21 21:31:54 -0500709 if (es->surface != EGL_NO_SURFACE)
710 eglDestroySurface(ec->display, es->surface);
Kristian Høgsberg16eb6752008-10-08 22:51:32 -0400711
Kristian Høgsberg715a0812008-12-10 10:42:04 -0500712 es->width = width;
713 es->height = height;
Kristian Høgsbergaa5b5be2008-11-21 21:31:54 -0500714 es->surface = eglCreateSurfaceForName(ec->display, ec->config,
Kristian Høgsberg78231c82008-11-08 15:06:01 -0500715 name, width, height, stride, NULL);
Kristian Høgsbergde31d5c2008-12-18 17:55:33 -0500716 if (visual == &ec->argb_visual.base)
717 es->visual = &ec->argb_visual;
718 else if (visual == &ec->premultiplied_argb_visual.base)
719 es->visual = &ec->premultiplied_argb_visual;
Kristian Høgsberge10b8282008-12-18 19:58:44 -0500720 else if (visual == &ec->rgb_visual.base)
721 es->visual = &ec->rgb_visual;
Kristian Høgsbergde31d5c2008-12-18 17:55:33 -0500722 else
723 /* FIXME: Smack client with an exception event */;
Kristian Høgsberg16eb6752008-10-08 22:51:32 -0400724
Kristian Høgsbergaa5b5be2008-11-21 21:31:54 -0500725 glBindTexture(GL_TEXTURE_2D, es->texture);
Kristian Høgsberg16eb6752008-10-08 22:51:32 -0400726 glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
Kristian Høgsberg98fed0f2008-12-09 13:35:35 -0500727 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_R, GL_REPEAT);
728 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
729 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
Kristian Høgsbergaa5b5be2008-11-21 21:31:54 -0500730 eglBindTexImage(ec->display, es->surface, GL_TEXTURE_2D);
Kristian Høgsbergf9212892008-10-11 18:40:23 -0400731}
732
Kristian Høgsberg5503bf82008-11-06 10:38:17 -0500733static void
Kristian Høgsberg8da19ac2009-03-17 16:12:51 -0400734wlsc_session_update_matrix(struct wlsc_session *session);
735
736static void
Kristian Høgsbergd2412e22008-12-15 20:35:24 -0500737surface_map(struct wl_client *client,
738 struct wl_surface *surface,
739 int32_t x, int32_t y, int32_t width, int32_t height)
Kristian Høgsberg16eb6752008-10-08 22:51:32 -0400740{
Kristian Høgsberg8e438622009-01-26 23:07:00 -0500741 struct wlsc_surface *es = (struct wlsc_surface *) surface;
Kristian Høgsberg16eb6752008-10-08 22:51:32 -0400742
Kristian Høgsbergd2412e22008-12-15 20:35:24 -0500743 es->map.x = x;
744 es->map.y = y;
745 es->map.width = width;
746 es->map.height = height;
Kristian Høgsberg8da19ac2009-03-17 16:12:51 -0400747
748 wlsc_session_update_matrix(&es->session);
Kristian Høgsberg16eb6752008-10-08 22:51:32 -0400749}
750
Kristian Høgsberg7f77bd82008-11-07 08:39:37 -0500751static void
Kristian Høgsbergd2412e22008-12-15 20:35:24 -0500752surface_copy(struct wl_client *client,
753 struct wl_surface *surface,
754 int32_t dst_x, int32_t dst_y,
755 uint32_t name, uint32_t stride,
756 int32_t x, int32_t y, int32_t width, int32_t height)
Kristian Høgsberg7f77bd82008-11-07 08:39:37 -0500757{
Kristian Høgsberg8e438622009-01-26 23:07:00 -0500758 struct wlsc_surface *es = (struct wlsc_surface *) surface;
759 struct wlsc_compositor *ec = es->compositor;
Kristian Høgsberg78231c82008-11-08 15:06:01 -0500760 EGLSurface src;
Kristian Høgsberg78231c82008-11-08 15:06:01 -0500761
762 /* FIXME: glCopyPixels should work, but then we'll have to
763 * call eglMakeCurrent to set up the src and dest surfaces
764 * first. This seems cheaper, but maybe there's a better way
765 * to accomplish this. */
766
767 src = eglCreateSurfaceForName(ec->display, ec->config,
768 name, x + width, y + height, stride, NULL);
769
Kristian Høgsbergaa5b5be2008-11-21 21:31:54 -0500770 eglCopyNativeBuffers(ec->display, es->surface, GL_FRONT_LEFT, dst_x, dst_y,
Kristian Høgsberg78231c82008-11-08 15:06:01 -0500771 src, GL_FRONT_LEFT, x, y, width, height);
Kristian Høgsbergfbdbbdc2008-11-28 17:06:06 -0500772 eglDestroySurface(ec->display, src);
Kristian Høgsberg7f77bd82008-11-07 08:39:37 -0500773}
774
775static void
Kristian Høgsbergd2412e22008-12-15 20:35:24 -0500776surface_damage(struct wl_client *client,
777 struct wl_surface *surface,
778 int32_t x, int32_t y, int32_t width, int32_t height)
Kristian Høgsberg7f77bd82008-11-07 08:39:37 -0500779{
Kristian Høgsbergfbdbbdc2008-11-28 17:06:06 -0500780 /* FIXME: This need to take a damage region, of course. */
781}
782
Kristian Høgsbergd2412e22008-12-15 20:35:24 -0500783const static struct wl_surface_interface surface_interface = {
784 surface_destroy,
785 surface_attach,
786 surface_map,
787 surface_copy,
788 surface_damage
789};
790
791static void
Kristian Høgsberg8da19ac2009-03-17 16:12:51 -0400792wlsc_session_update_matrix(struct wlsc_session *session)
Kristian Høgsberg1a208d52009-02-10 14:20:26 -0500793{
Kristian Høgsberg8da19ac2009-03-17 16:12:51 -0400794 GLdouble tx, ty;
795 struct wlsc_surface *s = session->surface;
796
797 tx = s->map.x + s->map.width / 2;
798 ty = s->map.y + s->map.height / 2;
799
800 wlsc_matrix_init(&s->matrix);
801 wlsc_matrix_translate(&s->matrix, -tx, -ty, 0);
802 wlsc_matrix_rotate(&s->matrix, session->current_angle, 0, 1, 0);
803 wlsc_matrix_translate(&s->matrix, tx + session->current.x,
804 ty + session->current.y, session->current.z);
805}
806
807static void
808wl_session_animate(struct wlsc_animate *animate,
809 struct wlsc_compositor *compositor,
810 uint32_t frame, uint32_t msecs)
811{
812 struct wlsc_session *session;
Kristian Høgsberg1a208d52009-02-10 14:20:26 -0500813 struct wlsc_surface *s;
814 double angle_force, angle;
815 struct wlsc_vector force, tmp;
Kristian Høgsberg8da19ac2009-03-17 16:12:51 -0400816 double step = 0.2;
817 double friction = 1.5;
Kristian Høgsberg1a208d52009-02-10 14:20:26 -0500818 double spring = 0.2;
819
Kristian Høgsberg8da19ac2009-03-17 16:12:51 -0400820 session = container_of(animate, struct wlsc_session, animate);
821 s = session->surface;
Kristian Høgsberg1a208d52009-02-10 14:20:26 -0500822
Kristian Høgsberg8da19ac2009-03-17 16:12:51 -0400823 angle = session->current_angle;
824 angle_force = (session->target_angle - angle) * spring +
825 (session->previous_angle - angle) * friction;
Kristian Høgsberg1a208d52009-02-10 14:20:26 -0500826
Kristian Høgsberg8da19ac2009-03-17 16:12:51 -0400827 session->current_angle =
828 angle + (angle - session->previous_angle) + angle_force * step;
829 session->previous_angle = angle;
Kristian Høgsberg1a208d52009-02-10 14:20:26 -0500830
Kristian Høgsberg8da19ac2009-03-17 16:12:51 -0400831 force = session->target;
832 wlsc_vector_subtract(&force, &session->current);
Kristian Høgsberg1a208d52009-02-10 14:20:26 -0500833 wlsc_vector_scalar(&force, spring);
Kristian Høgsberg8da19ac2009-03-17 16:12:51 -0400834 tmp = session->previous;
835 wlsc_vector_subtract(&tmp, &session->current);
Kristian Høgsberg1a208d52009-02-10 14:20:26 -0500836 wlsc_vector_scalar(&tmp, friction);
837 wlsc_vector_add(&force, &tmp);
838
839 wlsc_vector_scalar(&force, step);
Kristian Høgsberg8da19ac2009-03-17 16:12:51 -0400840 wlsc_vector_add(&force, &session->current);
841 wlsc_vector_subtract(&force, &session->previous);
842 session->previous = session->current;
843 wlsc_vector_add(&session->current, &force);
Kristian Høgsberg1a208d52009-02-10 14:20:26 -0500844
Kristian Høgsberg8da19ac2009-03-17 16:12:51 -0400845 wlsc_session_update_matrix(session);
Kristian Høgsberg1a208d52009-02-10 14:20:26 -0500846
Kristian Høgsberg8da19ac2009-03-17 16:12:51 -0400847 tmp = session->current;
848 wlsc_vector_subtract(&tmp, &session->target);
Kristian Høgsbergbb8cd932009-02-10 19:48:47 -0500849 if (tmp.x * tmp.x + tmp.y * tmp.y + tmp.z * tmp.z > 0.001) {
Kristian Høgsberg8da19ac2009-03-17 16:12:51 -0400850 wlsc_compositor_schedule_repaint(compositor);
Kristian Høgsbergbb8cd932009-02-10 19:48:47 -0500851 } else {
Kristian Høgsberg8da19ac2009-03-17 16:12:51 -0400852 wl_list_remove(&session->animate.link);
853 wl_list_init(&session->animate.link);
Kristian Høgsbergbb8cd932009-02-10 19:48:47 -0500854 }
Kristian Høgsberg1a208d52009-02-10 14:20:26 -0500855}
856
857static void
Kristian Høgsberg8da19ac2009-03-17 16:12:51 -0400858wlsc_session_activate(struct wlsc_compositor *compositor, struct wlsc_session *session)
859{
860 struct wlsc_session *s;
861 int i;
862
863 compositor->primary = session;
864 if (wl_list_empty(&compositor->session_list))
865 return;
866
867 session->target.x = 0;
868 session->target.y = 0;
869 session->target.z = -600;
870 session->target_angle = 0;
871 wl_list_remove(&session->animate.link);
872 wl_list_insert(compositor->animate_list.prev, &session->animate.link);
873
874 i = 0;
875 s = container_of(session->link.prev,
876 struct wlsc_session, link);
877 while (&s->link != &compositor->session_list) {
878 s->target.x = -1000 - 500 * i;
879 s->target.y = 0;
880 s->target.z = -2500;
881 s->target_angle = M_PI / 4;
882 wl_list_remove(&s->animate.link);
883 wl_list_insert(compositor->animate_list.prev, &s->animate.link);
884 wlsc_surface_lower(s->surface);
885
886 s = container_of(s->link.prev,
887 struct wlsc_session, link);
888 i++;
889 }
890
891 i = 0;
892 s = container_of(session->link.next,
893 struct wlsc_session, link);
894 while (&s->link != &compositor->session_list) {
895 s->target.x = 1000 + 500 * i;
896 s->target.y = 0;
897 s->target.z = -2500;
898 s->target_angle = -M_PI / 4;
899 wl_list_remove(&s->animate.link);
900 wl_list_insert(compositor->animate_list.prev, &s->animate.link);
901 wlsc_surface_lower(s->surface);
902
903 s = container_of(s->link.next,
904 struct wlsc_session, link);
905 i++;
906 }
907
908 wlsc_compositor_schedule_repaint(compositor);
909}
910
911static void
912wlsc_session_handle_surface_destroy(struct wlsc_listener *listener,
913 struct wlsc_surface *surface)
914{
915 struct wlsc_session *session =
916 container_of(listener, struct wlsc_session, listener);
917 struct wlsc_compositor *compositor;
918 struct wlsc_session *primary;
919
920 if (session->surface != surface)
921 return;
922
923 compositor = session->surface->compositor;
924 if (compositor->primary == session) {
925 printf("destroy session %p [%p, %p]\n", session, session->link.prev, session->link.next);
926 if (session->link.next != &compositor->session_list)
927 primary = container_of(session->link.next,
928 struct wlsc_session, link);
929 else if (session->link.prev != &compositor->session_list)
930 primary = container_of(session->link.prev,
931 struct wlsc_session, link);
932 else
933 primary = NULL;
934 }
935
936 wl_list_remove(&session->animate.link);
937 wl_list_remove(&session->link);
938 wl_list_remove(&session->listener.link);
939
940 if (compositor->primary == session) {
941 printf("activating session %p\n", primary);
942 wlsc_session_activate(compositor, primary);
943 }
944}
945
946static void
947wlsc_session_init(struct wlsc_session *session, struct wlsc_surface *surface)
948{
949 struct wlsc_compositor *c = surface->compositor;
950
951 session->animate.animate = wl_session_animate;
952 wl_list_init(&session->animate.link);
953 wl_list_insert(c->session_list.prev, &session->link);
954
955 session->surface = surface;
956 session->current.x = 0;
957 session->current.y = 0;
958 session->current.z = 0;
959 session->current_angle = 0;
960 session->target.x = 0;
961 session->target.y = 0;
962 session->target.z = 0;
963 session->target_angle = 0;
964 session->previous_angle = 0;
965
966 wlsc_session_update_matrix(session);
967
968 session->listener.func = wlsc_session_handle_surface_destroy;
969 wl_list_insert(c->surface_destroy_listener_list.prev,
970 &session->listener.link);
971
972 printf("added session %p [%p, %p]\n", session, session->link.prev, session->link.next);
973 printf(" - prev [%p]\n", session->link.prev->prev);
974}
975
976static void
Kristian Høgsbergd2412e22008-12-15 20:35:24 -0500977compositor_create_surface(struct wl_client *client,
978 struct wl_compositor *compositor, uint32_t id)
979{
Kristian Høgsberg8e438622009-01-26 23:07:00 -0500980 struct wlsc_compositor *ec = (struct wlsc_compositor *) compositor;
Kristian Høgsberg8da19ac2009-03-17 16:12:51 -0400981 struct wlsc_surface *surface;
Kristian Høgsbergd2412e22008-12-15 20:35:24 -0500982
Kristian Høgsberg8da19ac2009-03-17 16:12:51 -0400983 surface = malloc(sizeof *surface);
984 if (surface == NULL)
Kristian Høgsbergd2412e22008-12-15 20:35:24 -0500985 /* FIXME: Send OOM event. */
986 return;
987
Kristian Høgsberg8da19ac2009-03-17 16:12:51 -0400988 wlsc_surface_init(surface, ec, NULL, 0, 0, 0, 0);
Kristian Høgsberg5c8c3282009-02-09 15:17:46 -0500989
Kristian Høgsberg8da19ac2009-03-17 16:12:51 -0400990 wl_list_insert(ec->surface_list.prev, &surface->link);
991 wl_client_add_surface(client, &surface->base,
Kristian Høgsbergd2412e22008-12-15 20:35:24 -0500992 &surface_interface, id);
Kristian Høgsberg8da19ac2009-03-17 16:12:51 -0400993
994 wlsc_session_init(&surface->session, surface);
995 wlsc_session_activate(ec, &surface->session);
Kristian Høgsbergd2412e22008-12-15 20:35:24 -0500996}
997
998static void
999compositor_commit(struct wl_client *client,
1000 struct wl_compositor *compositor, uint32_t key)
Kristian Høgsbergfbdbbdc2008-11-28 17:06:06 -05001001{
Kristian Høgsberg8e438622009-01-26 23:07:00 -05001002 struct wlsc_compositor *ec = (struct wlsc_compositor *) compositor;
Kristian Høgsberg7f77bd82008-11-07 08:39:37 -05001003
Kristian Høgsberg8da19ac2009-03-17 16:12:51 -04001004 wlsc_compositor_schedule_repaint(ec);
Kristian Høgsbergd2412e22008-12-15 20:35:24 -05001005 wl_client_send_acknowledge(client, compositor, key, ec->current_frame);
Kristian Høgsberg7f77bd82008-11-07 08:39:37 -05001006}
1007
Kristian Høgsbergd2412e22008-12-15 20:35:24 -05001008const static struct wl_compositor_interface compositor_interface = {
1009 compositor_create_surface,
1010 compositor_commit
1011};
1012
Kristian Høgsberg7b6907f2009-02-14 17:47:55 -05001013static void
1014wlsc_surface_transform(struct wlsc_surface *surface,
1015 int32_t x, int32_t y, int32_t *sx, int32_t *sy)
1016{
1017 /* Transform to surface coordinates. */
1018 *sx = (x - surface->map.x) * surface->width / surface->map.width;
1019 *sy = (y - surface->map.y) * surface->height / surface->map.height;
1020}
1021
Kristian Høgsbergdb6c2f32009-02-22 21:51:24 -05001022static void
1023wlsc_input_device_set_keyboard_focus(struct wlsc_input_device *device,
1024 struct wlsc_surface *surface)
1025{
1026 if (device->keyboard_focus == surface)
1027 return;
1028
1029 if (device->keyboard_focus &&
1030 (!surface || device->keyboard_focus->base.client != surface->base.client))
1031 wl_surface_post_event(&device->keyboard_focus->base,
1032 &device->base,
Kristian Høgsberg786ca0d2009-03-06 21:25:21 -05001033 WL_INPUT_KEYBOARD_FOCUS, NULL, &device->keys);
Kristian Høgsbergdb6c2f32009-02-22 21:51:24 -05001034
Kristian Høgsbergdb6c2f32009-02-22 21:51:24 -05001035 if (surface)
1036 wl_surface_post_event(&surface->base,
1037 &device->base,
Kristian Høgsberg3c38fa02009-02-23 22:30:29 -05001038 WL_INPUT_KEYBOARD_FOCUS,
1039 &surface->base, &device->keys);
Kristian Høgsbergdb6c2f32009-02-22 21:51:24 -05001040
1041 device->keyboard_focus = surface;
1042}
1043
1044static void
1045wlsc_input_device_set_pointer_focus(struct wlsc_input_device *device,
1046 struct wlsc_surface *surface)
1047{
1048 if (device->pointer_focus == surface)
1049 return;
1050
1051 if (device->pointer_focus &&
1052 (!surface || device->pointer_focus->base.client != surface->base.client))
1053 wl_surface_post_event(&device->pointer_focus->base,
1054 &device->base,
1055 WL_INPUT_POINTER_FOCUS, NULL);
1056 if (surface)
1057 wl_surface_post_event(&surface->base,
1058 &device->base,
1059 WL_INPUT_POINTER_FOCUS, &surface->base);
1060
1061 device->pointer_focus = surface;
1062}
1063
Kristian Høgsberg8e438622009-01-26 23:07:00 -05001064static struct wlsc_surface *
Kristian Høgsberg7e972a52008-12-21 17:26:00 -05001065pick_surface(struct wlsc_input_device *device, int32_t *sx, int32_t *sy)
Kristian Høgsberg201a9042008-12-10 00:40:50 -05001066{
Kristian Høgsberg8e438622009-01-26 23:07:00 -05001067 struct wlsc_compositor *ec = device->ec;
1068 struct wlsc_surface *es;
Kristian Høgsberg201a9042008-12-10 00:40:50 -05001069
Kristian Høgsberg7b6907f2009-02-14 17:47:55 -05001070 if (device->grab > 0) {
1071 wlsc_surface_transform(device->grab_surface,
1072 device->x, device->y, sx, sy);
Kristian Høgsbergc492b482008-12-12 12:00:02 -05001073 return device->grab_surface;
Kristian Høgsberg7b6907f2009-02-14 17:47:55 -05001074 }
Kristian Høgsbergc492b482008-12-12 12:00:02 -05001075
Kristian Høgsberg201a9042008-12-10 00:40:50 -05001076 es = container_of(ec->surface_list.prev,
Kristian Høgsberg8e438622009-01-26 23:07:00 -05001077 struct wlsc_surface, link);
Kristian Høgsberg201a9042008-12-10 00:40:50 -05001078 while (&es->link != &ec->surface_list) {
Kristian Høgsberg5ee1a602008-12-11 23:18:45 -05001079 if (es->map.x <= device->x &&
1080 device->x < es->map.x + es->map.width &&
1081 es->map.y <= device->y &&
Kristian Høgsberg6c9c8f82009-02-10 18:29:24 -05001082 device->y < es->map.y + es->map.height) {
Kristian Høgsberg7b6907f2009-02-14 17:47:55 -05001083 wlsc_surface_transform(es, device->x, device->y, sx, sy);
Kristian Høgsberg201a9042008-12-10 00:40:50 -05001084 return es;
Kristian Høgsberg6c9c8f82009-02-10 18:29:24 -05001085 }
Kristian Høgsberg201a9042008-12-10 00:40:50 -05001086
1087 es = container_of(es->link.prev,
Kristian Høgsberg8e438622009-01-26 23:07:00 -05001088 struct wlsc_surface, link);
Kristian Høgsberg7e972a52008-12-21 17:26:00 -05001089
Kristian Høgsberg201a9042008-12-10 00:40:50 -05001090 }
1091
1092 return NULL;
1093}
1094
Kristian Høgsberg5ee1a602008-12-11 23:18:45 -05001095void
Kristian Høgsberg82f6e8a2008-12-19 13:47:53 -05001096notify_motion(struct wlsc_input_device *device, int x, int y)
Kristian Høgsberg715a0812008-12-10 10:42:04 -05001097{
Kristian Høgsberg8e438622009-01-26 23:07:00 -05001098 struct wlsc_surface *es;
1099 struct wlsc_compositor *ec = device->ec;
Kristian Høgsberg81ce09a2008-12-31 16:18:42 -05001100 struct wlsc_output *output;
Kristian Høgsberg715a0812008-12-10 10:42:04 -05001101 const int hotspot_x = 16, hotspot_y = 16;
1102 int32_t sx, sy;
1103
Ray Strodee96dcb82008-12-20 02:00:49 -05001104 if (!ec->vt_active)
1105 return;
1106
Kristian Høgsberg81ce09a2008-12-31 16:18:42 -05001107 /* FIXME: We need some multi head love here. */
1108 output = container_of(ec->output_list.next, struct wlsc_output, link);
1109 if (x < output->x)
Ray Strode90e701d2008-12-18 23:05:43 -05001110 x = 0;
Kristian Høgsberg81ce09a2008-12-31 16:18:42 -05001111 if (y < output->y)
Ray Strode90e701d2008-12-18 23:05:43 -05001112 y = 0;
Kristian Høgsberg81ce09a2008-12-31 16:18:42 -05001113 if (x >= output->x + output->width)
1114 x = output->x + output->width - 1;
1115 if (y >= output->y + output->height)
1116 y = output->y + output->height - 1;
Ray Strode90e701d2008-12-18 23:05:43 -05001117
Kristian Høgsberge3ef3e52008-12-21 19:30:01 -05001118 device->x = x;
1119 device->y = y;
Kristian Høgsberg7e972a52008-12-21 17:26:00 -05001120 es = pick_surface(device, &sx, &sy);
Kristian Høgsbergdb6c2f32009-02-22 21:51:24 -05001121
1122 wlsc_input_device_set_pointer_focus(device, es);
1123
Kristian Høgsberg7e972a52008-12-21 17:26:00 -05001124 if (es)
Kristian Høgsbergd2412e22008-12-15 20:35:24 -05001125 wl_surface_post_event(&es->base, &device->base,
Kristian Høgsberg5a75c902008-12-10 13:16:50 -05001126 WL_INPUT_MOTION, x, y, sx, sy);
Kristian Høgsberg715a0812008-12-10 10:42:04 -05001127
Kristian Høgsberg0555d8e2009-02-22 19:19:47 -05001128 device->sprite->map.x = x - hotspot_x;
1129 device->sprite->map.y = y - hotspot_y;
Kristian Høgsberg5ee1a602008-12-11 23:18:45 -05001130
Kristian Høgsberg8da19ac2009-03-17 16:12:51 -04001131 wlsc_compositor_schedule_repaint(device->ec);
Kristian Høgsberg715a0812008-12-10 10:42:04 -05001132}
1133
Kristian Høgsberg5ee1a602008-12-11 23:18:45 -05001134void
Kristian Høgsberg82f6e8a2008-12-19 13:47:53 -05001135notify_button(struct wlsc_input_device *device,
Kristian Høgsberg5ee1a602008-12-11 23:18:45 -05001136 int32_t button, int32_t state)
Kristian Høgsbergeac149a2008-12-10 00:24:18 -05001137{
Kristian Høgsberg8da19ac2009-03-17 16:12:51 -04001138 struct wlsc_surface *surface;
1139 struct wlsc_compositor *compositor = device->ec;
Kristian Høgsbergc492b482008-12-12 12:00:02 -05001140 int32_t sx, sy;
Kristian Høgsbergeac149a2008-12-10 00:24:18 -05001141
Kristian Høgsberg8da19ac2009-03-17 16:12:51 -04001142 if (!compositor->vt_active)
Ray Strodee96dcb82008-12-20 02:00:49 -05001143 return;
1144
Kristian Høgsberg8da19ac2009-03-17 16:12:51 -04001145 surface = pick_surface(device, &sx, &sy);
1146 if (surface) {
1147 wlsc_surface_raise(surface);
Kristian Høgsberg5a75c902008-12-10 13:16:50 -05001148
Kristian Høgsberg29573bc2008-12-11 23:27:27 -05001149 if (state) {
1150 device->grab++;
Kristian Høgsberg8da19ac2009-03-17 16:12:51 -04001151 device->grab_surface = surface;
1152 wlsc_input_device_set_keyboard_focus(device,
1153 surface);
Kristian Høgsberg29573bc2008-12-11 23:27:27 -05001154 } else {
1155 device->grab--;
1156 }
1157
Kristian Høgsberg5a75c902008-12-10 13:16:50 -05001158 /* FIXME: Swallow click on raise? */
Kristian Høgsberg8da19ac2009-03-17 16:12:51 -04001159 wl_surface_post_event(&surface->base, &device->base,
Kristian Høgsbergc492b482008-12-12 12:00:02 -05001160 WL_INPUT_BUTTON, button, state,
1161 device->x, device->y, sx, sy);
Kristian Høgsbergeac149a2008-12-10 00:24:18 -05001162
Kristian Høgsberg8da19ac2009-03-17 16:12:51 -04001163 wlsc_compositor_schedule_repaint(compositor);
Kristian Høgsberg5ee1a602008-12-11 23:18:45 -05001164 }
Kristian Høgsbergeac149a2008-12-10 00:24:18 -05001165}
1166
Kristian Høgsbergab909ae2001-01-01 22:24:24 -05001167static void on_term_signal(int signal_number, void *data);
1168
Kristian Høgsberg5ee1a602008-12-11 23:18:45 -05001169void
Kristian Høgsberg82f6e8a2008-12-19 13:47:53 -05001170notify_key(struct wlsc_input_device *device,
Kristian Høgsberg5ee1a602008-12-11 23:18:45 -05001171 uint32_t key, uint32_t state)
Kristian Høgsbergcddc0ad2008-11-24 00:31:49 -05001172{
Kristian Høgsberg8da19ac2009-03-17 16:12:51 -04001173 struct wlsc_compositor *compositor = device->ec;
1174 struct wlsc_session *s;
Kristian Høgsberg3c38fa02009-02-23 22:30:29 -05001175 uint32_t *k, *end;
1176
Kristian Høgsberg8da19ac2009-03-17 16:12:51 -04001177 if (!compositor->vt_active)
Kristian Høgsberg3c38fa02009-02-23 22:30:29 -05001178 return;
Ray Strodee96dcb82008-12-20 02:00:49 -05001179
Kristian Høgsberg8da19ac2009-03-17 16:12:51 -04001180 switch (key | compositor->meta_state) {
Kristian Høgsberg5c8c3282009-02-09 15:17:46 -05001181 case KEY_EJECTCD | META_DOWN:
Kristian Høgsberg8da19ac2009-03-17 16:12:51 -04001182 on_term_signal(SIGTERM, compositor);
Kristian Høgsberg5c8c3282009-02-09 15:17:46 -05001183 return;
1184
Kristian Høgsberg8da19ac2009-03-17 16:12:51 -04001185 case KEY_LEFT | META_DOWN:
1186 if (!compositor->primary || !state)
1187 break;
1188 s = container_of(compositor->primary->link.prev,
1189 struct wlsc_session, link);
1190 if (&s->link != &compositor->session_list) {
1191 wlsc_session_activate(compositor, s);
1192 if (device->grab == 0)
1193 wlsc_input_device_set_keyboard_focus(device, s->surface);
1194 }
1195 return;
1196
1197
1198 case KEY_RIGHT | META_DOWN:
1199 if (!compositor->primary || !state)
1200 break;
1201 s = container_of(compositor->primary->link.next,
1202 struct wlsc_session, link);
1203 if (&s->link != &compositor->session_list) {
1204 wlsc_session_activate(compositor, s);
1205 if (device->grab == 0)
1206 wlsc_input_device_set_keyboard_focus(device, s->surface);
1207
1208 }
Kristian Høgsberg5c8c3282009-02-09 15:17:46 -05001209 return;
1210
1211 case KEY_LEFTMETA:
1212 case KEY_RIGHTMETA:
Kristian Høgsberg5c8c3282009-02-09 15:17:46 -05001213 case KEY_LEFTMETA | META_DOWN:
1214 case KEY_RIGHTMETA | META_DOWN:
Kristian Høgsberg8da19ac2009-03-17 16:12:51 -04001215 compositor->meta_state = state ? META_DOWN : 0;
1216
1217 if (state == 0 && compositor->primary) {
1218 s = compositor->primary;
1219 s->target.z = 0;
1220 wl_list_remove(&s->animate.link);
1221 wl_list_insert(compositor->animate_list.prev, &s->animate.link);
1222 wlsc_compositor_schedule_repaint(compositor);
Kristian Høgsberg1a208d52009-02-10 14:20:26 -05001223 }
Kristian Høgsberg8da19ac2009-03-17 16:12:51 -04001224
Kristian Høgsberg5c8c3282009-02-09 15:17:46 -05001225 return;
1226 }
Kristian Høgsbergab909ae2001-01-01 22:24:24 -05001227
Kristian Høgsberg3c38fa02009-02-23 22:30:29 -05001228 end = device->keys.data + device->keys.size;
1229 for (k = device->keys.data; k < end; k++) {
1230 if (*k == key)
1231 *k = *--end;
1232 }
1233 device->keys.size = (void *) end - device->keys.data;
1234 if (state) {
1235 k = wl_array_add(&device->keys, sizeof *k);
1236 *k = key;
1237 }
Ray Strodee96dcb82008-12-20 02:00:49 -05001238
Kristian Høgsbergdb6c2f32009-02-22 21:51:24 -05001239 if (device->keyboard_focus != NULL)
1240 wl_surface_post_event(&device->keyboard_focus->base,
Kristian Høgsberg2c0e56b2008-12-19 13:54:40 -05001241 &device->base,
1242 WL_INPUT_KEY, key, state);
Kristian Høgsbergcddc0ad2008-11-24 00:31:49 -05001243}
1244
Kristian Høgsberg5ee1a602008-12-11 23:18:45 -05001245struct evdev_input_device *
Kristian Høgsberg82f6e8a2008-12-19 13:47:53 -05001246evdev_input_device_create(struct wlsc_input_device *device,
Kristian Høgsberg5ee1a602008-12-11 23:18:45 -05001247 struct wl_display *display, const char *path);
1248
Kristian Høgsberg4fa48732009-03-10 23:17:00 -04001249static void
1250handle_surface_destroy(struct wlsc_listener *listener,
1251 struct wlsc_surface *surface)
1252{
1253 struct wlsc_input_device *device =
1254 container_of(listener, struct wlsc_input_device, listener);
1255
1256 if (device->grab_surface == surface) {
1257 device->grab_surface = NULL;
1258 device->grab = 0;
1259 }
1260 if (device->keyboard_focus == surface)
1261 device->keyboard_focus = NULL;
1262 if (device->pointer_focus == surface)
1263 device->pointer_focus = NULL;
1264}
1265
Kristian Høgsberg890bc052008-12-30 14:31:33 -05001266static struct wlsc_input_device *
Kristian Høgsberg8e438622009-01-26 23:07:00 -05001267create_input_device(struct wlsc_compositor *ec)
Kristian Høgsbergcddc0ad2008-11-24 00:31:49 -05001268{
Kristian Høgsberg82f6e8a2008-12-19 13:47:53 -05001269 struct wlsc_input_device *device;
Kristian Høgsbergcddc0ad2008-11-24 00:31:49 -05001270
Kristian Høgsberg5ee1a602008-12-11 23:18:45 -05001271 device = malloc(sizeof *device);
1272 if (device == NULL)
Kristian Høgsberg890bc052008-12-30 14:31:33 -05001273 return NULL;
Kristian Høgsberg5ee1a602008-12-11 23:18:45 -05001274
Kristian Høgsbergc492b482008-12-12 12:00:02 -05001275 memset(device, 0, sizeof *device);
Kristian Høgsbergfe831a72008-12-21 21:50:23 -05001276 device->base.interface = &wl_input_device_interface;
Kristian Høgsbergb3131d92008-12-24 19:30:25 -05001277 device->base.implementation = NULL;
Kristian Høgsberg5ee1a602008-12-11 23:18:45 -05001278 wl_display_add_object(ec->wl_display, &device->base);
Kristian Høgsbergb3131d92008-12-24 19:30:25 -05001279 wl_display_add_global(ec->wl_display, &device->base, NULL);
Kristian Høgsberg5ee1a602008-12-11 23:18:45 -05001280 device->x = 100;
1281 device->y = 100;
Kristian Høgsberg5ee1a602008-12-11 23:18:45 -05001282 device->ec = ec;
1283
Kristian Høgsberg4fa48732009-03-10 23:17:00 -04001284 device->listener.func = handle_surface_destroy;
1285 wl_list_insert(ec->surface_destroy_listener_list.prev,
1286 &device->listener.link);
Kristian Høgsbergc492b482008-12-12 12:00:02 -05001287 wl_list_insert(ec->input_device_list.prev, &device->link);
Kristian Høgsberg890bc052008-12-30 14:31:33 -05001288
1289 return device;
Kristian Høgsberg5ee1a602008-12-11 23:18:45 -05001290}
1291
1292void
Kristian Høgsberg82f6e8a2008-12-19 13:47:53 -05001293wlsc_device_get_position(struct wlsc_input_device *device, int32_t *x, int32_t *y)
Kristian Høgsberg5ee1a602008-12-11 23:18:45 -05001294{
1295 *x = device->x;
1296 *y = device->y;
Kristian Høgsbergcddc0ad2008-11-24 00:31:49 -05001297}
1298
Kristian Høgsberg81ce09a2008-12-31 16:18:42 -05001299static void
1300post_output_geometry(struct wl_client *client, struct wl_object *global)
Kristian Høgsbergbf9541f2008-11-25 12:10:09 -05001301{
Kristian Høgsberg81ce09a2008-12-31 16:18:42 -05001302 struct wlsc_output *output =
1303 container_of(global, struct wlsc_output, base);
1304
1305 wl_client_post_event(client, global,
1306 WL_OUTPUT_GEOMETRY,
1307 output->width, output->height);
1308}
1309
Kristian Høgsberg81ce09a2008-12-31 16:18:42 -05001310static int
Kristian Høgsberg8e438622009-01-26 23:07:00 -05001311init_egl(struct wlsc_compositor *ec, struct udev_device *device)
Kristian Høgsberg81ce09a2008-12-31 16:18:42 -05001312{
1313 static const EGLint config_attribs[] = {
Kristian Høgsberg8e438622009-01-26 23:07:00 -05001314 EGL_DEPTH_SIZE, 0,
1315 EGL_STENCIL_SIZE, 0,
1316 EGL_CONFIG_CAVEAT, EGL_NONE,
1317 EGL_RED_SIZE, 8,
Kristian Høgsberg81ce09a2008-12-31 16:18:42 -05001318 EGL_NONE
1319 };
1320
Kristian Høgsberg81ce09a2008-12-31 16:18:42 -05001321 EGLint major, minor;
1322
Kristian Høgsbergaa68fe32009-01-15 12:50:21 -05001323 ec->display = eglCreateDisplayNative(device);
Kristian Høgsberg81ce09a2008-12-31 16:18:42 -05001324 if (ec->display == NULL) {
1325 fprintf(stderr, "failed to create display\n");
1326 return -1;
1327 }
1328
1329 if (!eglInitialize(ec->display, &major, &minor)) {
1330 fprintf(stderr, "failed to initialize display\n");
1331 return -1;
1332 }
1333
1334 if (!eglChooseConfig(ec->display, config_attribs, &ec->config, 1, NULL))
1335 return -1;
1336
1337 ec->context = eglCreateContext(ec->display, ec->config, NULL, NULL);
1338 if (ec->context == NULL) {
1339 fprintf(stderr, "failed to create context\n");
1340 return -1;
1341 }
1342 return 0;
1343}
1344
1345static int
Kristian Høgsberg8e438622009-01-26 23:07:00 -05001346create_output(struct wlsc_compositor *ec, struct udev_device *device)
Kristian Høgsberg81ce09a2008-12-31 16:18:42 -05001347{
1348 const static EGLint surface_attribs[] = {
1349 EGL_RENDER_BUFFER, EGL_BACK_BUFFER,
1350 EGL_NONE
1351 };
1352
Kristian Høgsbergbf9541f2008-11-25 12:10:09 -05001353 drmModeConnector *connector;
1354 drmModeRes *resources;
1355 drmModeEncoder *encoder;
Kristian Høgsberg41a10682009-02-15 22:37:03 -05001356 drmModeModeInfo *mode;
Kristian Høgsberg81ce09a2008-12-31 16:18:42 -05001357 struct wlsc_output *output;
Kristian Høgsbergb22382b2009-03-10 23:40:35 -04001358 uint32_t name, handle, stride;
Kristian Høgsberg2c875bd2008-12-19 10:34:02 -05001359 int i, ret, fd;
Kristian Høgsbergbf9541f2008-11-25 12:10:09 -05001360
Kristian Høgsberg81ce09a2008-12-31 16:18:42 -05001361 if (ec->display == NULL && init_egl(ec, device) < 0) {
1362 fprintf(stderr, "failed to initialize egl\n");
1363 return -1;
1364 }
1365
1366 output = malloc(sizeof *output);
1367 if (output == NULL)
1368 return -1;
1369
Kristian Høgsberg2c875bd2008-12-19 10:34:02 -05001370 fd = eglGetDisplayFD(ec->display);
Kristian Høgsbergbf9541f2008-11-25 12:10:09 -05001371 resources = drmModeGetResources(fd);
1372 if (!resources) {
1373 fprintf(stderr, "drmModeGetResources failed\n");
Kristian Høgsberg81ce09a2008-12-31 16:18:42 -05001374 return -1;
Kristian Høgsbergbf9541f2008-11-25 12:10:09 -05001375 }
1376
1377 for (i = 0; i < resources->count_connectors; i++) {
1378 connector = drmModeGetConnector(fd, resources->connectors[i]);
1379 if (connector == NULL)
1380 continue;
1381
1382 if (connector->connection == DRM_MODE_CONNECTED &&
1383 connector->count_modes > 0)
1384 break;
1385
1386 drmModeFreeConnector(connector);
1387 }
1388
1389 if (i == resources->count_connectors) {
1390 fprintf(stderr, "No currently active connector found.\n");
1391 return -1;
1392 }
1393
1394 mode = &connector->modes[0];
1395
1396 for (i = 0; i < resources->count_encoders; i++) {
1397 encoder = drmModeGetEncoder(fd, resources->encoders[i]);
1398
1399 if (encoder == NULL)
1400 continue;
1401
1402 if (encoder->encoder_id == connector->encoder_id)
1403 break;
1404
1405 drmModeFreeEncoder(encoder);
1406 }
1407
Kristian Høgsbergb22382b2009-03-10 23:40:35 -04001408 output->compositor = ec;
1409 output->crtc_id = encoder->crtc_id;
1410 output->connector_id = connector->connector_id;
1411 output->mode = mode;
1412 output->x = 0;
1413 output->y = 0;
1414 output->width = mode->hdisplay;
1415 output->height = mode->vdisplay;
1416
1417 output->surface = eglCreateSurfaceForName(ec->display,
1418 ec->config,
1419 0,
1420 output->width,
1421 output->height,
1422 0, surface_attribs);
1423 if (output->surface == NULL) {
1424 fprintf(stderr, "failed to create surface\n");
Kristian Høgsberg81ce09a2008-12-31 16:18:42 -05001425 return -1;
Kristian Høgsbergbf9541f2008-11-25 12:10:09 -05001426 }
1427
Kristian Høgsbergb22382b2009-03-10 23:40:35 -04001428 eglGetNativeBuffer(output->surface,
1429 GL_FRONT_LEFT, &name, &handle, &stride);
1430 ret = drmModeAddFB(fd, output->width, output->height,
1431 32, 32, stride, handle, &output->fb_id);
Kristian Høgsbergbf9541f2008-11-25 12:10:09 -05001432 if (ret) {
1433 fprintf(stderr, "failed to add fb: %m\n");
Kristian Høgsberg81ce09a2008-12-31 16:18:42 -05001434 return -1;
Kristian Høgsbergbf9541f2008-11-25 12:10:09 -05001435 }
1436
Kristian Høgsberg81ce09a2008-12-31 16:18:42 -05001437 ret = drmModeSetCrtc(fd, encoder->crtc_id, output->fb_id, 0, 0,
Kristian Høgsbergbf9541f2008-11-25 12:10:09 -05001438 &connector->connector_id, 1, mode);
1439 if (ret) {
1440 fprintf(stderr, "failed to set mode: %m\n");
Kristian Høgsberg81ce09a2008-12-31 16:18:42 -05001441 return -1;
Kristian Høgsbergbf9541f2008-11-25 12:10:09 -05001442 }
1443
Kristian Høgsberg81ce09a2008-12-31 16:18:42 -05001444 output->base.interface = &wl_output_interface;
1445 wl_display_add_object(ec->wl_display, &output->base);
1446 wl_display_add_global(ec->wl_display, &output->base, post_output_geometry);
1447 wl_list_insert(ec->output_list.prev, &output->link);
1448
1449 if (!eglMakeCurrent(ec->display, output->surface, output->surface, ec->context)) {
1450 fprintf(stderr, "failed to make context current\n");
1451 return -1;
1452 }
1453
1454 output->background = background_create(output, option_background);
1455
1456 return 0;
Kristian Høgsbergbf9541f2008-11-25 12:10:09 -05001457}
1458
Kristian Høgsbergde31d5c2008-12-18 17:55:33 -05001459static const struct wl_interface visual_interface = {
1460 "visual", 1,
1461};
1462
1463static void
Kristian Høgsberg8e438622009-01-26 23:07:00 -05001464add_visuals(struct wlsc_compositor *ec)
Kristian Høgsbergde31d5c2008-12-18 17:55:33 -05001465{
1466 ec->argb_visual.base.interface = &visual_interface;
1467 ec->argb_visual.base.implementation = NULL;
1468 wl_display_add_object(ec->wl_display, &ec->argb_visual.base);
Kristian Høgsbergee02ca62008-12-21 23:37:12 -05001469 wl_display_add_global(ec->wl_display, &ec->argb_visual.base, NULL);
Kristian Høgsbergde31d5c2008-12-18 17:55:33 -05001470
1471 ec->premultiplied_argb_visual.base.interface = &visual_interface;
1472 ec->premultiplied_argb_visual.base.implementation = NULL;
1473 wl_display_add_object(ec->wl_display,
1474 &ec->premultiplied_argb_visual.base);
1475 wl_display_add_global(ec->wl_display,
Kristian Høgsbergee02ca62008-12-21 23:37:12 -05001476 &ec->premultiplied_argb_visual.base, NULL);
Kristian Høgsbergde31d5c2008-12-18 17:55:33 -05001477
1478 ec->rgb_visual.base.interface = &visual_interface;
1479 ec->rgb_visual.base.implementation = NULL;
1480 wl_display_add_object(ec->wl_display, &ec->rgb_visual.base);
Kristian Høgsbergee02ca62008-12-21 23:37:12 -05001481 wl_display_add_global(ec->wl_display, &ec->rgb_visual.base, NULL);
1482}
1483
Ray Strode19ad6a92008-12-19 01:45:41 -05001484static void on_enter_vt(int signal_number, void *data)
1485{
Kristian Høgsberg8e438622009-01-26 23:07:00 -05001486 struct wlsc_compositor *ec = data;
Kristian Høgsberg81ce09a2008-12-31 16:18:42 -05001487 struct wlsc_output *output;
Kristian Høgsberg2c875bd2008-12-19 10:34:02 -05001488 int ret, fd;
Ray Strode19ad6a92008-12-19 01:45:41 -05001489
Kristian Høgsberg38ccd3a2008-12-19 10:15:35 -05001490 ioctl(ec->tty_fd, VT_RELDISP, VT_ACKACQ);
Ray Strodee96dcb82008-12-20 02:00:49 -05001491 ec->vt_active = TRUE;
Kristian Høgsberg38ccd3a2008-12-19 10:15:35 -05001492
Kristian Høgsberg2c875bd2008-12-19 10:34:02 -05001493 fd = eglGetDisplayFD(ec->display);
Kristian Høgsberg81ce09a2008-12-31 16:18:42 -05001494 output = container_of(ec->output_list.next, struct wlsc_output, link);
1495 while (&output->link != &ec->output_list) {
1496 ret = drmModeSetCrtc(fd, output->crtc_id, output->fb_id, 0, 0,
1497 &output->connector_id, 1, output->mode);
1498 if (ret)
1499 fprintf(stderr, "failed to set mode for connector %d: %m\n",
1500 output->connector_id);
1501
1502 output = container_of(output->link.next,
1503 struct wlsc_output, link);
Ray Strode19ad6a92008-12-19 01:45:41 -05001504 }
Ray Strode19ad6a92008-12-19 01:45:41 -05001505}
1506
1507static void on_leave_vt(int signal_number, void *data)
1508{
Kristian Høgsberg8e438622009-01-26 23:07:00 -05001509 struct wlsc_compositor *ec = data;
Ray Strode19ad6a92008-12-19 01:45:41 -05001510
1511 ioctl (ec->tty_fd, VT_RELDISP, 1);
Ray Strodee96dcb82008-12-20 02:00:49 -05001512 ec->vt_active = FALSE;
Ray Strode19ad6a92008-12-19 01:45:41 -05001513}
1514
Ray Strode966aa112008-12-19 14:28:02 -05001515static void
1516on_tty_input(int fd, uint32_t mask, void *data)
1517{
Kristian Høgsberg8e438622009-01-26 23:07:00 -05001518 struct wlsc_compositor *ec = data;
Ray Strode966aa112008-12-19 14:28:02 -05001519
1520 /* Ignore input to tty. We get keyboard events from evdev
1521 */
1522 tcflush(ec->tty_fd, TCIFLUSH);
1523}
1524
1525static void on_term_signal(int signal_number, void *data)
1526{
Kristian Høgsberg8e438622009-01-26 23:07:00 -05001527 struct wlsc_compositor *ec = data;
Ray Strode966aa112008-12-19 14:28:02 -05001528
1529 if (tcsetattr(ec->tty_fd, TCSANOW, &ec->terminal_attributes) < 0)
1530 fprintf(stderr, "could not restore terminal to canonical mode\n");
1531
1532 exit(0);
1533}
1534
Kristian Høgsberg8e438622009-01-26 23:07:00 -05001535static int setup_tty(struct wlsc_compositor *ec, struct wl_event_loop *loop)
Ray Strode966aa112008-12-19 14:28:02 -05001536{
1537 struct termios raw_attributes;
Kristian Høgsberg0ab26242008-12-21 19:33:09 -05001538 struct vt_mode mode = { 0 };
1539
1540 ec->tty_fd = open("/dev/tty0", O_RDWR | O_NOCTTY);
1541 if (ec->tty_fd <= 0) {
1542 fprintf(stderr, "failed to open active tty: %m\n");
1543 return -1;
1544 }
Ray Strode966aa112008-12-19 14:28:02 -05001545
1546 if (tcgetattr(ec->tty_fd, &ec->terminal_attributes) < 0) {
1547 fprintf(stderr, "could not get terminal attributes: %m\n");
Kristian Høgsberg0ab26242008-12-21 19:33:09 -05001548 return -1;
Ray Strode966aa112008-12-19 14:28:02 -05001549 }
1550
Kristian Høgsberg0ab26242008-12-21 19:33:09 -05001551 /* Ignore control characters and disable echo */
Ray Strode966aa112008-12-19 14:28:02 -05001552 raw_attributes = ec->terminal_attributes;
Kristian Høgsberg0ab26242008-12-21 19:33:09 -05001553 cfmakeraw(&raw_attributes);
Ray Strode966aa112008-12-19 14:28:02 -05001554
Kristian Høgsberg0ab26242008-12-21 19:33:09 -05001555 /* Fix up line endings to be normal (cfmakeraw hoses them) */
Ray Strode966aa112008-12-19 14:28:02 -05001556 raw_attributes.c_oflag |= OPOST | OCRNL;
1557
1558 if (tcsetattr(ec->tty_fd, TCSANOW, &raw_attributes) < 0)
1559 fprintf(stderr, "could not put terminal into raw mode: %m\n");
1560
Kristian Høgsberg0ab26242008-12-21 19:33:09 -05001561 ec->term_signal_source =
1562 wl_event_loop_add_signal(loop, SIGTERM, on_term_signal, ec);
Ray Strode966aa112008-12-19 14:28:02 -05001563
Kristian Høgsberg0ab26242008-12-21 19:33:09 -05001564 ec->tty_input_source =
1565 wl_event_loop_add_fd(loop, ec->tty_fd,
1566 WL_EVENT_READABLE, on_tty_input, ec);
Ray Strode966aa112008-12-19 14:28:02 -05001567
Kristian Høgsberg0ab26242008-12-21 19:33:09 -05001568 ec->vt_active = TRUE;
Ray Strode19ad6a92008-12-19 01:45:41 -05001569 mode.mode = VT_PROCESS;
1570 mode.relsig = SIGUSR1;
1571 mode.acqsig = SIGUSR2;
Kristian Høgsberg0ab26242008-12-21 19:33:09 -05001572 if (!ioctl(ec->tty_fd, VT_SETMODE, &mode) < 0) {
Ray Strode19ad6a92008-12-19 01:45:41 -05001573 fprintf(stderr, "failed to take control of vt handling\n");
1574 }
1575
Kristian Høgsberg0ab26242008-12-21 19:33:09 -05001576 ec->leave_vt_source =
1577 wl_event_loop_add_signal(loop, SIGUSR1, on_leave_vt, ec);
1578 ec->enter_vt_source =
1579 wl_event_loop_add_signal(loop, SIGUSR2, on_enter_vt, ec);
Kristian Høgsbergfe831a72008-12-21 21:50:23 -05001580
1581 return 0;
Ray Strode19ad6a92008-12-19 01:45:41 -05001582}
1583
Kristian Høgsberg81ce09a2008-12-31 16:18:42 -05001584static int
Kristian Høgsberg8e438622009-01-26 23:07:00 -05001585init_libudev(struct wlsc_compositor *ec)
Kristian Høgsberg890bc052008-12-30 14:31:33 -05001586{
1587 struct udev_enumerate *e;
1588 struct udev_list_entry *entry;
1589 struct udev_device *device;
Kristian Høgsbergf13eb142009-01-26 21:38:14 -05001590 const char *path;
Kristian Høgsberg890bc052008-12-30 14:31:33 -05001591 struct wlsc_input_device *input_device;
1592
Kristian Høgsberg890bc052008-12-30 14:31:33 -05001593 ec->udev = udev_new();
1594 if (ec->udev == NULL) {
1595 fprintf(stderr, "failed to initialize udev context\n");
Kristian Høgsberg81ce09a2008-12-31 16:18:42 -05001596 return -1;
Kristian Høgsberg890bc052008-12-30 14:31:33 -05001597 }
1598
1599 input_device = create_input_device(ec);
1600
1601 e = udev_enumerate_new(ec->udev);
Kristian Høgsbergf13eb142009-01-26 21:38:14 -05001602 udev_enumerate_add_match_subsystem(e, "input");
1603 udev_enumerate_add_match_property(e, "WAYLAND_SEAT", "1");
Kristian Høgsberg890bc052008-12-30 14:31:33 -05001604 udev_enumerate_scan_devices(e);
1605 udev_list_entry_foreach(entry, udev_enumerate_get_list_entry(e)) {
1606 path = udev_list_entry_get_name(entry);
1607 device = udev_device_new_from_syspath(ec->udev, path);
Kristian Høgsbergf13eb142009-01-26 21:38:14 -05001608 evdev_input_device_create(input_device, ec->wl_display,
1609 udev_device_get_devnode(device));
1610 }
1611 udev_enumerate_unref(e);
Kristian Høgsberg890bc052008-12-30 14:31:33 -05001612
Kristian Høgsbergf13eb142009-01-26 21:38:14 -05001613 e = udev_enumerate_new(ec->udev);
1614 udev_enumerate_add_match_subsystem(e, "drm");
1615 udev_enumerate_add_match_property(e, "WAYLAND_SEAT", "1");
1616 udev_enumerate_scan_devices(e);
1617 udev_list_entry_foreach(entry, udev_enumerate_get_list_entry(e)) {
1618 path = udev_list_entry_get_name(entry);
1619 device = udev_device_new_from_syspath(ec->udev, path);
1620 if (create_output(ec, device) < 0) {
1621 fprintf(stderr, "failed to create output for %s\n", path);
1622 return -1;
Kristian Høgsberg890bc052008-12-30 14:31:33 -05001623 }
1624 }
1625 udev_enumerate_unref(e);
Kristian Høgsberg81ce09a2008-12-31 16:18:42 -05001626
1627 /* Create the pointer surface now that we have a current EGL context. */
Kristian Høgsberg0555d8e2009-02-22 19:19:47 -05001628 input_device->sprite =
Kristian Høgsberg81ce09a2008-12-31 16:18:42 -05001629 pointer_create(ec, input_device->x, input_device->y, 64, 64);
1630
1631 return 0;
Kristian Høgsberg890bc052008-12-30 14:31:33 -05001632}
1633
Kristian Høgsberg8e438622009-01-26 23:07:00 -05001634static struct wlsc_compositor *
1635wlsc_compositor_create(struct wl_display *display)
Kristian Høgsberg16eb6752008-10-08 22:51:32 -04001636{
Kristian Høgsberg8e438622009-01-26 23:07:00 -05001637 struct wlsc_compositor *ec;
Kristian Høgsberg1e4b86a2008-11-23 23:41:08 -05001638 struct screenshooter *shooter;
Kristian Høgsbergfbdbbdc2008-11-28 17:06:06 -05001639 struct wl_event_loop *loop;
Kristian Høgsberg16eb6752008-10-08 22:51:32 -04001640
1641 ec = malloc(sizeof *ec);
1642 if (ec == NULL)
1643 return NULL;
1644
Kristian Høgsberg81ce09a2008-12-31 16:18:42 -05001645 memset(ec, 0, sizeof *ec);
Kristian Høgsbergf9212892008-10-11 18:40:23 -04001646 ec->wl_display = display;
Kristian Høgsberg16eb6752008-10-08 22:51:32 -04001647
Kristian Høgsbergd2412e22008-12-15 20:35:24 -05001648 wl_display_set_compositor(display, &ec->base, &compositor_interface);
Kristian Høgsbergee02ca62008-12-21 23:37:12 -05001649
Kristian Høgsbergde31d5c2008-12-18 17:55:33 -05001650 add_visuals(ec);
Kristian Høgsbergd2412e22008-12-15 20:35:24 -05001651
Kristian Høgsberg201a9042008-12-10 00:40:50 -05001652 wl_list_init(&ec->surface_list);
Kristian Høgsberg81ce09a2008-12-31 16:18:42 -05001653 wl_list_init(&ec->input_device_list);
1654 wl_list_init(&ec->output_list);
Kristian Høgsberg4fa48732009-03-10 23:17:00 -04001655 wl_list_init(&ec->surface_destroy_listener_list);
Kristian Høgsberg81ce09a2008-12-31 16:18:42 -05001656 if (init_libudev(ec) < 0) {
1657 fprintf(stderr, "failed to initialize devices\n");
1658 return NULL;
1659 }
Kristian Høgsberg4c9f2c92008-11-21 19:25:44 -05001660
Kristian Høgsberg1e4b86a2008-11-23 23:41:08 -05001661 shooter = screenshooter_create(ec);
1662 wl_display_add_object(display, &shooter->base);
Kristian Høgsbergee02ca62008-12-21 23:37:12 -05001663 wl_display_add_global(display, &shooter->base, NULL);
Kristian Høgsberg8d7ca6b2008-11-09 00:22:51 -05001664
Kristian Høgsbergfbdbbdc2008-11-28 17:06:06 -05001665 loop = wl_display_get_event_loop(ec->wl_display);
Ray Strodee96dcb82008-12-20 02:00:49 -05001666
Kristian Høgsberg0ab26242008-12-21 19:33:09 -05001667 setup_tty(ec, loop);
1668
Kristian Høgsberg4a298902008-11-28 18:35:25 -05001669 ec->timer_source = wl_event_loop_add_timer(loop, repaint, ec);
Kristian Høgsberg8da19ac2009-03-17 16:12:51 -04001670 wlsc_compositor_schedule_repaint(ec);
Kristian Høgsbergef7a9ca2008-10-11 21:21:39 -04001671
Kristian Høgsberg1a208d52009-02-10 14:20:26 -05001672 wl_list_init(&ec->animate_list);
Kristian Høgsberg8da19ac2009-03-17 16:12:51 -04001673 wl_list_init(&ec->session_list);
Kristian Høgsberg1a208d52009-02-10 14:20:26 -05001674
Kristian Høgsberg122912c2008-12-05 11:13:50 -05001675 return ec;
1676}
1677
1678/* The plan here is to generate a random anonymous socket name and
1679 * advertise that through a service on the session dbus.
1680 */
1681static const char socket_name[] = "\0wayland";
1682
1683int main(int argc, char *argv[])
1684{
1685 struct wl_display *display;
Kristian Høgsberg8e438622009-01-26 23:07:00 -05001686 struct wlsc_compositor *ec;
Kristian Høgsbergd6531262008-12-12 11:06:18 -05001687 GError *error = NULL;
1688 GOptionContext *context;
1689
1690 context = g_option_context_new(NULL);
1691 g_option_context_add_main_entries(context, option_entries, "Wayland");
1692 if (!g_option_context_parse(context, &argc, &argv, &error)) {
1693 fprintf(stderr, "option parsing failed: %s\n", error->message);
1694 exit(EXIT_FAILURE);
1695 }
Kristian Høgsberg122912c2008-12-05 11:13:50 -05001696
1697 display = wl_display_create();
1698
Kristian Høgsberg8e438622009-01-26 23:07:00 -05001699 ec = wlsc_compositor_create(display);
Kristian Høgsberg841883b2008-12-05 11:19:56 -05001700 if (ec == NULL) {
1701 fprintf(stderr, "failed to create compositor\n");
1702 exit(EXIT_FAILURE);
1703 }
1704
Kristian Høgsbergdc0f3552008-12-07 15:22:22 -05001705 if (wl_display_add_socket(display, socket_name, sizeof socket_name)) {
Kristian Høgsberg122912c2008-12-05 11:13:50 -05001706 fprintf(stderr, "failed to add socket: %m\n");
1707 exit(EXIT_FAILURE);
1708 }
1709
1710 wl_display_run(display);
1711
1712 return 0;
Kristian Høgsberg16eb6752008-10-08 22:51:32 -04001713}