diff --git a/clients/Makefile.am b/clients/Makefile.am index 37135f28..86a3359d 100644 --- a/clients/Makefile.am +++ b/clients/Makefile.am @@ -7,21 +7,17 @@ noinst_PROGRAMS = \ $(poppler_programs) \ dnd \ smoke \ - resizor + resizor \ + simple-client noinst_LTLIBRARIES = libtoytoolkit.la -INCLUDES = \ - -I$(top_srcdir)/wayland \ - -I$(top_builddir)/wayland \ - $(CLIENT_CFLAGS) - -LDADD = libtoytoolkit.la \ - $(top_builddir)/wayland/libwayland-client.la \ - $(CLIENT_LIBS) -lrt -lm - AM_CFLAGS = $(GCC_CFLAGS) -AM_CPPFLAGS = -DDATADIR='"$(datadir)"' +AM_CPPFLAGS = \ + -DDATADIR='"$(datadir)"' \ + -I$(top_srcdir)/wayland \ + -I$(top_builddir)/wayland \ + $(CLIENT_CFLAGS) libtoytoolkit_la_SOURCES = \ window.c \ @@ -31,14 +27,38 @@ libtoytoolkit_la_SOURCES = \ cairo-util.c \ cairo-util.h -flower_SOURCES = flower.c -smoke_SOURCES = smoke.c +toolkit_libs = \ + libtoytoolkit.la \ + $(top_builddir)/wayland/libwayland-client.la \ + $(CLIENT_LIBS) -lrt -lm + gears_SOURCES = gears.c +gears_LDADD = $(toolkit_libs) + +flower_SOURCES = flower.c +flower_LDADD = $(toolkit_libs) + screenshot_SOURCES = screenshot.c screenshooter-protocol.c +screenshot_LDADD = $(toolkit_libs) + terminal_SOURCES = terminal.c +terminal_LDADD = $(toolkit_libs) -lutil + image_SOURCES = image.c +image_LDADD = $(toolkit_libs) + dnd_SOURCES = dnd.c +dnd_LDADD = $(toolkit_libs) + +smoke_SOURCES = smoke.c +smoke_LDADD = $(toolkit_libs) + resizor_SOURCES = resizor.c +resizor_LDADD = $(toolkit_libs) + +simple_client_SOURCES = simple-client.c +simple_client_LDADD = \ + $(top_builddir)/wayland/libwayland-client.la -lm $(GLES2_LIBS) BUILT_SOURCES = \ screenshooter-client-protocol.h \ @@ -48,11 +68,9 @@ CLEANFILES = $(BUILT_SOURCES) include $(top_srcdir)/wayland/scanner.mk -terminal_LDADD = $(LDADD) -lutil - if HAVE_POPPLER poppler_programs = view view_SOURCES = view.c -view_LDADD = $(LDADD) $(POPPLER_LIBS) -view_CPPFLAGS = $(POPPLER_CFLAGS) +view_LDADD = $(toolkit_libs) $(POPPLER_LIBS) +view_CPPFLAGS = $(AM_CPPFLAGS) $(POPPLER_CFLAGS) endif diff --git a/clients/dnd.c b/clients/dnd.c index feea3369..3b54dec5 100644 --- a/clients/dnd.c +++ b/clients/dnd.c @@ -171,21 +171,20 @@ dnd_draw(struct dnd *dnd) { struct rectangle allocation; cairo_t *cr; - cairo_surface_t *wsurface, *surface; + cairo_surface_t *surface; int i; window_draw(dnd->window); - window_get_child_allocation(dnd->window, &allocation); - - wsurface = window_get_surface(dnd->window); - surface = cairo_surface_create_similar(wsurface, - CAIRO_CONTENT_COLOR_ALPHA, - allocation.width, - allocation.height); - cairo_surface_destroy(wsurface); - + surface = window_get_surface(dnd->window); cr = cairo_create(surface); + window_get_child_allocation(dnd->window, &allocation); + cairo_rectangle(cr, allocation.x, allocation.y, + allocation.width, allocation.height); + cairo_clip(cr); + cairo_push_group(cr); + + cairo_translate(cr, allocation.x, allocation.y); cairo_set_operator(cr, CAIRO_OPERATOR_SOURCE); cairo_set_source_rgba(cr, 0, 0, 0, 0.8); cairo_paint(cr); @@ -199,9 +198,9 @@ dnd_draw(struct dnd *dnd) cairo_paint(cr); } + cairo_pop_group_to_source(cr); + cairo_paint(cr); cairo_destroy(cr); - - window_copy_surface(dnd->window, &allocation, surface); cairo_surface_destroy(surface); window_flush(dnd->window); } @@ -487,14 +486,21 @@ static const struct wl_drag_offer_listener drag_offer_listener = { }; static void -drag_offer_handler(struct wl_drag_offer *offer, struct display *display) +global_handler(struct display *display, + const char *interface, uint32_t id, uint32_t version) { + struct wl_drag_offer *offer; struct dnd_offer *dnd_offer; + if (strcmp(interface, "drag_offer") != 0) + return; + + offer = wl_drag_offer_create(display_get_display(display), id); + dnd_offer = malloc(sizeof *dnd_offer); if (dnd_offer == NULL) return; - + dnd_offer->refcount = 1; wl_drag_offer_add_listener(offer, &drag_offer_listener, dnd_offer); @@ -681,7 +687,7 @@ main(int argc, char *argv[]) return -1; } - display_set_drag_offer_handler(d, drag_offer_handler); + display_set_global_handler(d, global_handler); dnd = dnd_create (d); diff --git a/clients/gears.c b/clients/gears.c index b8e6cca0..f2eae9c9 100644 --- a/clients/gears.c +++ b/clients/gears.c @@ -212,7 +212,7 @@ allocate_buffer(struct gears *gears) window_draw(gears->window); gears->surface[gears->current] = window_get_surface(gears->window); -#ifdef HAVE_CAIRO_GL +#ifdef HAVE_CAIRO_EGL image = display_get_image_for_drm_surface(gears->display, gears->surface[gears->current]); #else /* XXX: hack to make Wayland compile, even if this example doesn't run */ diff --git a/clients/image.c b/clients/image.c index 61d8b25f..891bd8a7 100644 --- a/clients/image.c +++ b/clients/image.c @@ -140,7 +140,7 @@ image_draw(struct image *image) struct rectangle allocation; GdkPixbuf *pb; cairo_t *cr; - cairo_surface_t *wsurface, *surface; + cairo_surface_t *surface; window_draw(image->window); @@ -153,14 +153,15 @@ image_draw(struct image *image) if (pb == NULL) return; - wsurface = window_get_surface(image->window); - surface = cairo_surface_create_similar(wsurface, - CAIRO_CONTENT_COLOR_ALPHA, - allocation.width, - allocation.height); - - cairo_surface_destroy(wsurface); + surface = window_get_surface(image->window); cr = cairo_create(surface); + window_get_child_allocation(image->window, &allocation); + cairo_rectangle(cr, allocation.x, allocation.y, + allocation.width, allocation.height); + cairo_clip(cr); + cairo_push_group(cr); + cairo_translate(cr, allocation.x, allocation.y); + cairo_set_operator(cr, CAIRO_OPERATOR_SOURCE); cairo_set_source_rgba(cr, 0, 0, 0, 1); cairo_paint(cr); @@ -169,11 +170,13 @@ image_draw(struct image *image) allocation.width, allocation.height); cairo_set_operator(cr, CAIRO_OPERATOR_OVER); cairo_paint(cr); - cairo_destroy(cr); g_object_unref(pb); - window_copy_surface(image->window, &allocation, surface); + cairo_pop_group_to_source(cr); + cairo_paint(cr); + cairo_destroy(cr); + window_flush(image->window); cairo_surface_destroy(surface); } diff --git a/clients/resizor.c b/clients/resizor.c index cd9bfdc5..46d9cbf7 100644 --- a/clients/resizor.c +++ b/clients/resizor.c @@ -128,8 +128,8 @@ keyboard_focus_handler(struct window *window, } static void -key_handler(struct window *window, uint32_t key, uint32_t sym, - uint32_t state, uint32_t modifiers, void *data) +key_handler(struct window *window, struct input *input, uint32_t time, + uint32_t key, uint32_t sym, uint32_t state, void *data) { struct resizor *resizor = data; diff --git a/clients/simple-client.c b/clients/simple-client.c new file mode 100644 index 00000000..3a9b4a12 --- /dev/null +++ b/clients/simple-client.c @@ -0,0 +1,393 @@ +/* + * Copyright © 2011 Benjamin Franzke + * + * Permission to use, copy, modify, distribute, and sell this software and its + * documentation for any purpose is hereby granted without fee, provided that + * the above copyright notice appear in all copies and that both that copyright + * notice and this permission notice appear in supporting documentation, and + * that the name of the copyright holders not be used in advertising or + * publicity pertaining to distribution of the software without specific, + * written prior permission. The copyright holders make no representations + * about the suitability of this software for any purpose. It is provided "as + * is" without express or implied warranty. + * + * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, + * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO + * EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY SPECIAL, INDIRECT OR + * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, + * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE + * OF THIS SOFTWARE. + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#include +#include + +#define GL_GLEXT_PROTOTYPES +#define EGL_EGLEXT_PROTOTYPES +#include +#include +#include +#include + +struct display { + struct wl_display *display; + struct { + struct wl_compositor *compositor; + struct wl_drm *drm; + } interface; + struct { + EGLDisplay dpy; + EGLContext ctx; + } egl; + struct { + int fd; + const char *device_name; + bool authenticated; + } drm; + uint32_t mask; +}; + +struct window { + struct display *display; + struct { + int width, height; + } geometry; + struct { + GLuint fbo; + GLuint color_rbo; + + GLuint program; + GLuint rotation_uniform; + + GLuint pos; + GLuint col; + } gl; + struct { + struct wl_buffer *buffer; + struct wl_surface *surface; + EGLImageKHR image; + } drm_surface; +}; + +static const char *vert_shader_text = + "uniform mat4 rotation;\n" + "attribute vec4 pos;\n" + "attribute vec4 color;\n" + "varying vec4 v_color;\n" + "void main() {\n" + " gl_Position = rotation * pos;\n" + " v_color = color;\n" + "}\n"; + +static const char *frag_shader_text = + "precision mediump float;\n" + "varying vec4 v_color;\n" + "void main() {\n" + " gl_FragColor = v_color;\n" + "}\n"; + +static void +init_egl(struct display *display) +{ + static const EGLint context_attribs[] = { + EGL_CONTEXT_CLIENT_VERSION, 2, + EGL_NONE + }; + + EGLint major, minor; + EGLBoolean ret; + + display->egl.dpy = eglGetDRMDisplayMESA(display->drm.fd); + assert(display->egl.dpy); + + ret = eglInitialize(display->egl.dpy, &major, &minor); + assert(ret == EGL_TRUE); + ret = eglBindAPI(EGL_OPENGL_ES_API); + assert(ret == EGL_TRUE); + + display->egl.ctx = eglCreateContext(display->egl.dpy, NULL, + EGL_NO_CONTEXT, context_attribs); + assert(display->egl.ctx); + ret = eglMakeCurrent(display->egl.dpy, NULL, NULL, display->egl.ctx); + assert(ret == EGL_TRUE); +} + +static GLuint +create_shader(struct window *window, const char *source, GLenum shader_type) +{ + GLuint shader; + GLint status; + + shader = glCreateShader(shader_type); + assert(shader != 0); + + glShaderSource(shader, 1, (const char **) &source, NULL); + glCompileShader(shader); + + glGetShaderiv(shader, GL_COMPILE_STATUS, &status); + if (!status) { + char log[1000]; + GLsizei len; + glGetShaderInfoLog(shader, 1000, &len, log); + fprintf(stderr, "Error: compiling %s: %*s\n", + shader_type == GL_VERTEX_SHADER ? "vertex" : "fragment", + len, log); + exit(1); + } + + return shader; +} + +static void +init_gl(struct window *window) +{ + GLfloat ar; + GLuint frag, vert; + GLint status; + + glGenFramebuffers(1, &window->gl.fbo); + glBindFramebuffer(GL_FRAMEBUFFER, window->gl.fbo); + + glGenRenderbuffers(1, &window->gl.color_rbo); + + glViewport(0, 0, window->geometry.width, window->geometry.height); + ar = (GLfloat)window->geometry.width / (GLfloat)window->geometry.height; + + frag = create_shader(window, frag_shader_text, GL_FRAGMENT_SHADER); + vert = create_shader(window, vert_shader_text, GL_VERTEX_SHADER); + + window->gl.program = glCreateProgram(); + glAttachShader(window->gl.program, frag); + glAttachShader(window->gl.program, vert); + glLinkProgram(window->gl.program); + + glGetProgramiv(window->gl.program, GL_LINK_STATUS, &status); + if (!status) { + char log[1000]; + GLsizei len; + glGetProgramInfoLog(window->gl.program, 1000, &len, log); + fprintf(stderr, "Error: linking:\n%*s\n", len, log); + exit(1); + } + + glUseProgram(window->gl.program); + + window->gl.pos = 0; + window->gl.pos = 1; + + glBindAttribLocation(window->gl.program, window->gl.pos, "pos"); + glBindAttribLocation(window->gl.program, window->gl.col, "color"); + glLinkProgram(window->gl.program); + + window->gl.rotation_uniform = + glGetUniformLocation(window->gl.program, "rotation"); +} + +static void +create_surface(struct window *window) +{ + struct display *display = window->display; + struct wl_visual *visual; + EGLint name, stride; + EGLint image_attribs[] = { + EGL_WIDTH, 0, + EGL_HEIGHT, 0, + EGL_DRM_BUFFER_FORMAT_MESA, EGL_DRM_BUFFER_FORMAT_ARGB32_MESA, + EGL_DRM_BUFFER_USE_MESA, EGL_DRM_BUFFER_USE_SCANOUT_MESA, + EGL_NONE + }; + + window->drm_surface.surface = + wl_compositor_create_surface(display->interface.compositor); + + image_attribs[1] = window->geometry.width; + image_attribs[3] = window->geometry.height; + + window->drm_surface.image = eglCreateDRMImageMESA(display->egl.dpy, + image_attribs); + eglExportDRMImageMESA(display->egl.dpy, window->drm_surface.image, + &name, NULL, &stride); + visual = wl_display_get_premultiplied_argb_visual(display->display); + + window->drm_surface.buffer = + wl_drm_create_buffer(display->interface.drm, name, + window->geometry.width, + window->geometry.height, + stride, visual); + + wl_surface_attach(window->drm_surface.surface, + window->drm_surface.buffer, 0, 0); + wl_surface_map_toplevel(window->drm_surface.surface); + + glBindRenderbuffer(GL_RENDERBUFFER, window->gl.color_rbo); + glEGLImageTargetRenderbufferStorageOES(GL_RENDERBUFFER, + window->drm_surface.image); + + glFramebufferRenderbuffer(GL_FRAMEBUFFER, + GL_COLOR_ATTACHMENT0, + GL_RENDERBUFFER, + window->gl.color_rbo); + + assert(glCheckFramebufferStatus(GL_FRAMEBUFFER) == + GL_FRAMEBUFFER_COMPLETE); +} + +static void +redraw(void *data, uint32_t time) +{ + struct window *window = data; + static const GLfloat verts[3][2] = { + { -0.5, -0.5 }, + { 0.5, -0.5 }, + { 0, 0.5 } + }; + static const GLfloat colors[3][3] = { + { 1, 0, 0 }, + { 0, 1, 0 }, + { 0, 0, 1 } + }; + GLfloat angle; + GLfloat rotation[4][4] = { + { 1, 0, 0, 0 }, + { 0, 1, 0, 0 }, + { 0, 0, 1, 0 }, + { 0, 0, 0, 1 } + }; + static const int32_t speed_div = 5; + static uint32_t start_time = 0; + + if (start_time == 0) + start_time = time; + + angle = ((time-start_time) / speed_div) % 360 * M_PI / 180.0; + rotation[0][0] = cos(angle); + rotation[0][2] = sin(angle); + rotation[2][0] = -sin(angle); + rotation[2][2] = cos(angle); + + glUniformMatrix4fv(window->gl.rotation_uniform, 1, GL_FALSE, + (GLfloat *) rotation); + + glClearColor(0.0, 0.0, 0.0, 0.5); + glClear(GL_COLOR_BUFFER_BIT); + + glVertexAttribPointer(window->gl.pos, 2, GL_FLOAT, GL_FALSE, 0, verts); + glVertexAttribPointer(window->gl.col, 3, GL_FLOAT, GL_FALSE, 0, colors); + glEnableVertexAttribArray(window->gl.pos); + glEnableVertexAttribArray(window->gl.col); + + glDrawArrays(GL_TRIANGLES, 0, 3); + + glDisableVertexAttribArray(window->gl.pos); + glDisableVertexAttribArray(window->gl.col); + + glFlush(); + + wl_surface_damage(window->drm_surface.surface, 0, 0, + window->geometry.width, window->geometry.height); + + wl_display_frame_callback(window->display->display, redraw, window); +} + +static void +drm_handle_device(void *data, struct wl_drm *drm, const char *device) +{ + struct display *d = data; + + d->drm.device_name = strdup(device); +} + +static void +drm_handle_authenticated(void *data, struct wl_drm *drm) +{ + struct display *d = data; + + d->drm.authenticated = true; +} + +static const struct wl_drm_listener drm_listener = { + drm_handle_device, + drm_handle_authenticated +}; + +static void +display_handle_global(struct wl_display *display, uint32_t id, + const char *interface, uint32_t version, void *data) +{ + struct display *d = data; + + if (strcmp(interface, "compositor") == 0) { + d->interface.compositor = wl_compositor_create(display, id); + } else if (strcmp(interface, "drm") == 0) { + d->interface.drm = wl_drm_create(display, id); + wl_drm_add_listener(d->interface.drm, &drm_listener, d); + } +} + +static int +event_mask_update(uint32_t mask, void *data) +{ + struct display *d = data; + + d->mask = mask; + + return 0; +} + +int +main(int argc, char **argv) +{ + struct display display = { 0 }; + struct window window = { 0 }; + drm_magic_t magic; + int ret; + + memset(&display, 0, sizeof display); + memset(&window, 0, sizeof window); + + window.display = &display; + window.geometry.width = 250; + window.geometry.height = 250; + + display.display = wl_display_connect(NULL); + assert(display.display); + + wl_display_add_global_listener(display.display, + display_handle_global, &display); + /* process connection events */ + wl_display_iterate(display.display, WL_DISPLAY_READABLE); + + display.drm.fd = open(display.drm.device_name, O_RDWR); + assert(display.drm.fd >= 0); + + ret = drmGetMagic(display.drm.fd, &magic); + assert(ret == 0); + wl_drm_authenticate(display.interface.drm, magic); + wl_display_iterate(display.display, WL_DISPLAY_WRITABLE); + while (!display.drm.authenticated) + wl_display_iterate(display.display, WL_DISPLAY_READABLE); + + init_egl(&display); + init_gl(&window); + create_surface(&window); + + wl_display_frame_callback(display.display, redraw, &window); + + wl_display_get_fd(display.display, event_mask_update, &display); + while (true) + wl_display_iterate(display.display, display.mask); + + return 0; +} diff --git a/clients/terminal.c b/clients/terminal.c index 7316dcde..055a5f6e 100644 --- a/clients/terminal.c +++ b/clients/terminal.c @@ -273,9 +273,9 @@ function_key_response(char escape, int num, uint32_t modifiers, int mod_num = 0; int len; - if (modifiers & WINDOW_MODIFIER_SHIFT) mod_num |= 1; - if (modifiers & WINDOW_MODIFIER_ALT) mod_num |= 2; - if (modifiers & WINDOW_MODIFIER_CONTROL) mod_num |= 4; + if (modifiers & XKB_COMMON_SHIFT_MASK) mod_num |= 1; + if (modifiers & XKB_COMMON_MOD1_MASK) mod_num |= 2; + if (modifiers & XKB_COMMON_CONTROL_MASK) mod_num |= 4; if (mod_num != 0) len = snprintf(response, MAX_RESPONSE, "\e[%d;%d%c", @@ -390,6 +390,14 @@ struct terminal { struct terminal_color color_table[256]; cairo_font_extents_t extents; cairo_scaled_font_t *font_normal, *font_bold; + + uint32_t tag; + struct wl_selection *selection; + struct wl_selection_offer *selection_offer; + uint32_t selection_offer_has_text; + int32_t dragging, selection_active; + int selection_start_x, selection_start_y; + int selection_end_x, selection_end_y; }; /* Create default tab stops, every 8 characters */ @@ -487,16 +495,62 @@ union decoded_attr { uint32_t key; }; +static int +terminal_compare_position(struct terminal *terminal, + int x, int y, int32_t ref_row, int32_t ref_col) +{ + struct rectangle allocation; + int top_margin, side_margin, col, row, ref_x; + + window_get_child_allocation(terminal->window, &allocation); + side_margin = allocation.x + (allocation.width - terminal->width * terminal->extents.max_x_advance) / 2; + top_margin = allocation.y + (allocation.height - terminal->height * terminal->extents.height) / 2; + + col = (x - side_margin) / terminal->extents.max_x_advance; + row = (y - top_margin) / terminal->extents.height; + + ref_x = side_margin + ref_col * terminal->extents.max_x_advance + + terminal->extents.max_x_advance / 2; + + if (row < ref_row) + return -1; + if (row == ref_row) { + if (col < ref_col) + return -1; + if (col == ref_col && x < ref_x) + return -1; + } + + return 1; +} + static void terminal_decode_attr(struct terminal *terminal, int row, int col, union decoded_attr *decoded) { struct attr attr; int foreground, background, tmp; + int inverse = 0, start_cmp, end_cmp; + + start_cmp = + terminal_compare_position(terminal, + terminal->selection_start_x, + terminal->selection_start_y, + row, col); + end_cmp = + terminal_compare_position(terminal, + terminal->selection_end_x, + terminal->selection_end_y, + row, col); + if (start_cmp < 0 && end_cmp > 0) + inverse = 1; + else if (end_cmp < 0 && start_cmp > 0) + inverse = 1; /* get the attributes for this character cell */ attr = terminal_get_attr_row(terminal, row)[col]; if ((attr.a & ATTRMASK_INVERSE) || + inverse || ((terminal->mode & MODE_SHOW_CURSOR) && terminal->focused && terminal->row == row && terminal->column == col)) { @@ -830,7 +884,6 @@ terminal_draw_contents(struct terminal *terminal) { struct rectangle allocation; cairo_t *cr; - cairo_font_extents_t extents; int top_margin, side_margin; int row, col; union utf8_char *p_row; @@ -839,23 +892,29 @@ terminal_draw_contents(struct terminal *terminal) cairo_surface_t *surface; double d; struct glyph_run run; + cairo_font_extents_t extents; + surface = window_get_surface(terminal->window); window_get_child_allocation(terminal->window, &allocation); - - surface = display_create_surface(terminal->display, &allocation); cr = cairo_create(surface); + cairo_rectangle(cr, allocation.x, allocation.y, + allocation.width, allocation.height); + cairo_clip(cr); + cairo_push_group(cr); + cairo_set_operator(cr, CAIRO_OPERATOR_SOURCE); terminal_set_color(terminal, cr, terminal->color_scheme->border); cairo_paint(cr); cairo_set_scaled_font(cr, terminal->font_normal); - cairo_font_extents(cr, &extents); + extents = terminal->extents; side_margin = (allocation.width - terminal->width * extents.max_x_advance) / 2; top_margin = (allocation.height - terminal->height * extents.height) / 2; cairo_set_line_width(cr, 1.0); - + cairo_translate(cr, allocation.x + side_margin, + allocation.y + top_margin); /* paint the background */ for (row = 0; row < terminal->height; row++) { for (col = 0; col < terminal->width; col++) { @@ -866,8 +925,8 @@ terminal_draw_contents(struct terminal *terminal) continue; terminal_set_color(terminal, cr, attr.attr.bg); - cairo_move_to(cr, side_margin + (col * extents.max_x_advance), - top_margin + (row * extents.height)); + cairo_move_to(cr, col * extents.max_x_advance, + row * extents.height); cairo_rel_line_to(cr, extents.max_x_advance, 0); cairo_rel_line_to(cr, 0, extents.height); cairo_rel_line_to(cr, -extents.max_x_advance, 0); @@ -888,8 +947,8 @@ terminal_draw_contents(struct terminal *terminal) glyph_run_flush(&run, attr); - text_x = side_margin + col * extents.max_x_advance; - text_y = top_margin + extents.ascent + row * extents.height; + text_x = col * extents.max_x_advance; + text_y = extents.ascent + row * extents.height; if (attr.attr.a & ATTRMASK_UNDERLINE) { terminal_set_color(terminal, cr, attr.attr.fg); cairo_move_to(cr, text_x, (double)text_y + 1.5); @@ -908,8 +967,8 @@ terminal_draw_contents(struct terminal *terminal) d = 0.5; cairo_set_line_width(cr, 1); - cairo_move_to(cr, side_margin + terminal->column * extents.max_x_advance + d, - top_margin + terminal->row * extents.height + d); + cairo_move_to(cr, terminal->column * extents.max_x_advance + d, + terminal->row * extents.height + d); cairo_rel_line_to(cr, extents.max_x_advance - 2 * d, 0); cairo_rel_line_to(cr, 0, extents.height - 2 * d); cairo_rel_line_to(cr, -extents.max_x_advance + 2 * d, 0); @@ -918,10 +977,9 @@ terminal_draw_contents(struct terminal *terminal) cairo_stroke(cr); } + cairo_pop_group_to_source(cr); + cairo_paint(cr); cairo_destroy(cr); - - window_copy_surface(terminal->window, &allocation, surface); - cairo_surface_destroy(surface); } @@ -1936,13 +1994,102 @@ terminal_data(struct terminal *terminal, const char *data, size_t length) } static void -key_handler(struct window *window, uint32_t key, uint32_t sym, - uint32_t state, uint32_t modifiers, void *data) +selection_listener_send(void *data, struct wl_selection *selection, + const char *mime_type, int fd) +{ + static const char msg[] = "selection data"; + + fprintf(stderr, "selection send, fd is %d\n", fd); + write(fd, msg, sizeof msg - 1); + close(fd); +} + +static void +selection_listener_cancelled(void *data, struct wl_selection *selection) +{ + fprintf(stderr, "selection cancelled\n"); + wl_selection_destroy(selection); +} + +static const struct wl_selection_listener selection_listener = { + selection_listener_send, + selection_listener_cancelled +}; + +static gboolean +selection_io_func(GIOChannel *source, GIOCondition condition, gpointer data) +{ + struct terminal *terminal = data; + char buffer[256]; + unsigned int len; + int fd; + + fd = g_io_channel_unix_get_fd(source); + len = read(fd, buffer, sizeof buffer); + fprintf(stderr, "read %d bytes: %.*s\n", len, len, buffer); + + write(terminal->master, buffer, len); + + close(fd); + g_source_remove(terminal->tag); + + g_io_channel_unref(source); + + return TRUE; +} + +static int +handle_bound_key(struct terminal *terminal, + struct input *input, uint32_t sym, uint32_t time) +{ + struct wl_shell *shell; + GIOChannel *channel; + int fd; + + switch (sym) { + case XK_C: + shell = display_get_shell(terminal->display); + terminal->selection = wl_shell_create_selection(shell); + wl_selection_add_listener(terminal->selection, + &selection_listener, terminal); + wl_selection_offer(terminal->selection, "text/plain"); + wl_selection_activate(terminal->selection, + input_get_input_device(input), time); + + return 1; + case XK_V: + if (input_offers_mime_type(input, "text/plain")) { + fd = input_receive_mime_type(input, "text/plain"); + channel = g_io_channel_unix_new(fd); + terminal->tag = g_io_add_watch(channel, G_IO_IN, + selection_io_func, + terminal); + } + + return 1; + case XK_X: + /* cut selection; terminal doesn't do cut */ + return 0; + default: + return 0; + } +} + +static void +key_handler(struct window *window, struct input *input, uint32_t time, + uint32_t key, uint32_t sym, uint32_t state, void *data) { struct terminal *terminal = data; char ch[MAX_RESPONSE]; + uint32_t modifiers; int len = 0; + modifiers = input_get_modifiers(input); + if ((modifiers & XKB_COMMON_CONTROL_MASK) && + (modifiers & XKB_COMMON_SHIFT_MASK) && + state && handle_bound_key(terminal, input, sym, 0)) + return; + switch (sym) { case XK_F11: if (!state) @@ -2034,7 +2181,7 @@ key_handler(struct window *window, uint32_t key, uint32_t sym, len = apply_key_map(terminal->key_mode, sym, modifiers, ch); if (len != 0) break; - if (modifiers & WINDOW_MODIFIER_CONTROL) { + if (modifiers & XKB_COMMON_CONTROL_MASK) { if (sym >= '3' && sym <= '7') sym = (sym & 0x1f) + 8; @@ -2045,10 +2192,10 @@ key_handler(struct window *window, uint32_t key, uint32_t sym, else if (sym == '/') sym = 0x1F; else if (sym == '8' || sym == '?') sym = 0x7F; } else if ((terminal->mode & MODE_ALT_SENDS_ESC) && - (modifiers & WINDOW_MODIFIER_ALT)) + (modifiers & XKB_COMMON_MOD1_MASK)) { ch[len++] = 0x1b; - } else if (modifiers & WINDOW_MODIFIER_ALT) { + } else if (modifiers & XKB_COMMON_MOD1_MASK) { sym = sym | 0x80; } @@ -2071,6 +2218,50 @@ keyboard_focus_handler(struct window *window, window_schedule_redraw(terminal->window); } +static void +button_handler(struct window *window, + struct input *input, uint32_t time, + int button, int state, void *data) +{ + struct terminal *terminal = data; + + switch (button) { + case 272: + if (state) { + terminal->dragging = 1; + terminal->selection_active = 0; + input_get_position(input, + &terminal->selection_start_x, + &terminal->selection_start_y); + terminal->selection_end_x = terminal->selection_start_x; + terminal->selection_end_y = terminal->selection_start_y; + window_schedule_redraw(window); + } else { + terminal->dragging = 0; + } + break; + } +} + +static int +motion_handler(struct window *window, + struct input *input, uint32_t time, + int32_t x, int32_t y, + int32_t sx, int32_t sy, void *data) +{ + struct terminal *terminal = data; + + if (terminal->dragging) { + terminal->selection_active = 1; + input_get_position(input, + &terminal->selection_end_x, + &terminal->selection_end_y); + window_schedule_redraw(window); + } + + return POINTER_IBEAM; +} + static struct terminal * terminal_create(struct display *display, int fullscreen) { @@ -2105,6 +2296,8 @@ terminal_create(struct display *display, int fullscreen) window_set_key_handler(terminal->window, key_handler); window_set_keyboard_focus_handler(terminal->window, keyboard_focus_handler); + window_set_button_handler(terminal->window, button_handler); + window_set_motion_handler(terminal->window, motion_handler); surface = cairo_image_surface_create(CAIRO_FORMAT_ARGB32, 0, 0); cr = cairo_create(surface); diff --git a/clients/view.c b/clients/view.c index 5b81c456..db94dcaf 100644 --- a/clients/view.c +++ b/clients/view.c @@ -110,8 +110,8 @@ redraw_handler(struct window *window, void *data) } static void -key_handler(struct window *window, uint32_t key, uint32_t unicode, - uint32_t state, uint32_t modifiers, void *data) +key_handler(struct window *window, struct input *input, uint32_t time, + uint32_t key, uint32_t unicode, uint32_t state, void *data) { struct view *view = data; diff --git a/clients/window.c b/clients/window.c index 98bc53af..8a567bd7 100644 --- a/clients/window.c +++ b/clients/window.c @@ -43,7 +43,7 @@ #include #include -#ifdef HAVE_CAIRO_GL +#ifdef HAVE_CAIRO_EGL #include #endif @@ -79,7 +79,7 @@ struct display { struct xkb_desc *xkb; cairo_surface_t **pointer_surfaces; - display_drag_offer_handler_t drag_offer_handler; + display_global_handler_t global_handler; }; struct window { @@ -118,6 +118,7 @@ struct input { struct wl_input_device *input_device; struct window *pointer_focus; struct window *keyboard_focus; + struct selection_offer *offer; uint32_t current_pointer_image; uint32_t modifiers; int32_t x, y, sx, sy; @@ -181,7 +182,7 @@ struct surface_data { #define MULT(_d,c,a,t) \ do { t = c * a + 0x7f; _d = ((t >> 8) + t) >> 8; } while (0) -#ifdef HAVE_CAIRO_GL +#ifdef HAVE_CAIRO_EGL struct drm_surface_data { struct surface_data data; @@ -469,7 +470,7 @@ cairo_surface_t * display_create_surface(struct display *display, struct rectangle *rectangle) { -#ifdef HAVE_CAIRO_GL +#ifdef HAVE_CAIRO_EGL if (display->drm) { return display_create_drm_surface(display, rectangle); } @@ -482,7 +483,7 @@ display_create_surface_from_file(struct display *display, const char *filename, struct rectangle *rectangle) { -#ifdef HAVE_CAIRO_GL +#ifdef HAVE_CAIRO_EGL if (display->drm) { return display_create_drm_surface_from_file(display, filename, rectangle); } @@ -536,7 +537,7 @@ display_get_pointer_surface(struct display *display, int pointer, cairo_surface_t *surface; surface = display->pointer_surfaces[pointer]; -#if HAVE_CAIRO_GL +#if HAVE_CAIRO_EGL *width = cairo_gl_surface_get_width(surface); *height = cairo_gl_surface_get_height(surface); #else @@ -630,7 +631,7 @@ window_create_surface(struct window *window) cairo_surface_t *surface; switch (window->buffer_type) { -#ifdef HAVE_CAIRO_GL +#ifdef HAVE_CAIRO_EGL case WINDOW_BUFFER_TYPE_DRM: surface = display_create_surface(window->display, &window->allocation); @@ -910,7 +911,7 @@ window_handle_key(void *data, struct wl_input_device *input_device, return; level = 0; - if (input->modifiers & WINDOW_MODIFIER_SHIFT && + if (input->modifiers & XKB_COMMON_SHIFT_MASK && XkbKeyGroupWidth(d->xkb, code, 0) > 1) level = 1; @@ -922,8 +923,8 @@ window_handle_key(void *data, struct wl_input_device *input_device, input->modifiers &= ~d->xkb->map->modmap[code]; if (window->key_handler) - (*window->key_handler)(window, key, sym, state, - input->modifiers, window->user_data); + (*window->key_handler)(window, input, time, key, sym, state, + window->user_data); } static void @@ -940,6 +941,11 @@ window_handle_pointer_focus(void *data, input->pointer_focus = wl_surface_get_user_data(surface); window = input->pointer_focus; + input->x = x; + input->y = y; + input->sx = sx; + input->sy = sy; + pointer = POINTER_LEFT_PTR; if (window->motion_handler) pointer = (*window->motion_handler)(window, @@ -1014,6 +1020,12 @@ input_get_input_device(struct input *input) return input->input_device; } +uint32_t +input_get_modifiers(struct input *input) +{ + return input->modifiers; +} + struct wl_drag * window_create_drag(struct window *window) { @@ -1090,30 +1102,6 @@ window_set_child_size(struct window *window, int32_t width, int32_t height) } } -void -window_copy_image(struct window *window, - struct rectangle *rectangle, EGLImageKHR image) -{ - /* set image as read buffer, copy pixels or something... */ -} - -void -window_copy_surface(struct window *window, - struct rectangle *rectangle, - cairo_surface_t *surface) -{ - cairo_t *cr; - - cr = cairo_create (window->cairo_surface); - - cairo_set_source_surface (cr, - surface, - rectangle->x, rectangle->y); - - cairo_paint (cr); - cairo_destroy (cr); -} - static gboolean idle_redraw(void *data) { @@ -1324,12 +1312,122 @@ display_add_input(struct display *d, uint32_t id) wl_input_device_set_user_data(input->input_device, input); } +struct selection_offer { + struct display *display; + struct wl_selection_offer *offer; + struct wl_array types; + struct input *input; +}; + +int +input_offers_mime_type(struct input *input, const char *type) +{ + struct selection_offer *offer = input->offer; + char **p, **end; + + if (offer == NULL) + return 0; + + end = offer->types.data + offer->types.size; + for (p = offer->types.data; p < end; p++) + if (strcmp(*p, type) == 0) + return 1; + + return 0; +} + +int +input_receive_mime_type(struct input *input, const char *type) +{ + struct selection_offer *offer = input->offer; + int p[2]; + + pipe(p); + /* FIXME: A number of things can go wrong here: the object may + * not be the current selection offer any more (which could + * still work, but the source may have gone away or just + * destroyed its wl_selection) or the offer may not have the + * requested type after all (programmer/client error, + * typically) */ + wl_selection_offer_receive(offer->offer, type, p[1]); + close(p[1]); + + return p[0]; +} + +static void +selection_offer_offer(void *data, + struct wl_selection_offer *selection_offer, + const char *type) +{ + struct selection_offer *offer = data; + + char **p; + + p = wl_array_add(&offer->types, sizeof *p); + if (p) + *p = strdup(type); +}; + +static void +selection_offer_keyboard_focus(void *data, + struct wl_selection_offer *selection_offer, + struct wl_input_device *input_device) +{ + struct selection_offer *offer = data; + struct input *input; + char **p, **end; + + if (input_device == NULL) { + printf("selection offer retracted %p\n", selection_offer); + input = offer->input; + input->offer = NULL; + wl_selection_offer_destroy(selection_offer); + wl_array_release(&offer->types); + free(offer); + return; + } + + input = wl_input_device_get_user_data(input_device); + printf("new selection offer %p:", selection_offer); + + offer->input = input; + input->offer = offer; + end = offer->types.data + offer->types.size; + for (p = offer->types.data; p < end; p++) + printf(" %s", *p); + + printf("\n"); +} + +struct wl_selection_offer_listener selection_offer_listener = { + selection_offer_offer, + selection_offer_keyboard_focus +}; + +static void +add_selection_offer(struct display *d, uint32_t id) +{ + struct selection_offer *offer; + + offer = malloc(sizeof *offer); + if (offer == NULL) + return; + + offer->offer = wl_selection_offer_create(d->display, id); + offer->display = d; + wl_array_init(&offer->types); + offer->input = NULL; + + wl_selection_offer_add_listener(offer->offer, + &selection_offer_listener, offer); +} + static void display_handle_global(struct wl_display *display, uint32_t id, const char *interface, uint32_t version, void *data) { struct display *d = data; - struct wl_drag_offer *offer; if (strcmp(interface, "compositor") == 0) { d->compositor = wl_compositor_create(display, id); @@ -1346,11 +1444,10 @@ display_handle_global(struct wl_display *display, uint32_t id, wl_drm_add_listener(d->drm, &drm_listener, d); } else if (strcmp(interface, "shm") == 0) { d->shm = wl_shm_create(display, id); - } else if (strcmp(interface, "drag_offer") == 0) { - if (d->drag_offer_handler) { - offer = wl_drag_offer_create(display, id); - d->drag_offer_handler(offer, d); - } + } else if (strcmp(interface, "selection_offer") == 0) { + add_selection_offer(d, id); + } else if (d->global_handler) { + d->global_handler(d, interface, id, version); } } @@ -1452,7 +1549,7 @@ init_drm(struct display *d) return -1; } -#ifdef HAVE_CAIRO_GL +#ifdef HAVE_CAIRO_EGL d->device = cairo_egl_device_create(d->dpy, d->ctx); if (d->device == NULL) { fprintf(stderr, "failed to get cairo drm device\n"); @@ -1545,6 +1642,12 @@ display_get_egl_display(struct display *d) return d->dpy; } +struct wl_shell * +display_get_shell(struct display *display) +{ + return display->shell; +} + void display_run(struct display *d) { @@ -1552,8 +1655,8 @@ display_run(struct display *d) } void -display_set_drag_offer_handler(struct display *display, - display_drag_offer_handler_t handler) +display_set_global_handler(struct display *display, + display_global_handler_t handler) { - display->drag_offer_handler = handler; + display->global_handler = handler; } diff --git a/clients/window.h b/clients/window.h index 36ca196f..7d70a78d 100644 --- a/clients/window.h +++ b/clients/window.h @@ -23,6 +23,7 @@ #ifndef _WINDOW_H_ #define _WINDOW_H_ +#include #include #include @@ -47,11 +48,14 @@ display_get_display(struct display *display); struct wl_compositor * display_get_compositor(struct display *display); +struct wl_shell * +display_get_shell(struct display *display); + #ifdef EGL_NO_DISPLAY EGLDisplay display_get_egl_display(struct display *d); -#ifdef HAVE_CAIRO_GL +#ifdef HAVE_CAIRO_EGL EGLImageKHR display_get_image_for_drm_surface(struct display *display, cairo_surface_t *surface); @@ -82,14 +86,6 @@ display_flush_cairo_device(struct display *display); void display_run(struct display *d); -enum { - WINDOW_MODIFIER_SHIFT = 0x01, - WINDOW_MODIFIER_LOCK = 0x02, - WINDOW_MODIFIER_CONTROL = 0x04, - WINDOW_MODIFIER_ALT = 0x08, - WINDOW_MODIFIER_MOD2 = 0x10, -}; - enum pointer_type { POINTER_BOTTOM_LEFT, POINTER_BOTTOM_RIGHT, @@ -110,8 +106,9 @@ typedef void (*window_resize_handler_t)(struct window *window, void *data); typedef void (*window_redraw_handler_t)(struct window *window, void *data); typedef void (*window_frame_handler_t)(struct window *window, uint32_t frame, uint32_t timestamp, void *data); -typedef void (*window_key_handler_t)(struct window *window, uint32_t key, uint32_t unicode, - uint32_t state, uint32_t modifiers, void *data); +typedef void (*window_key_handler_t)(struct window *window, struct input *input, + uint32_t time, uint32_t key, uint32_t unicode, + uint32_t state, void *data); typedef void (*window_keyboard_focus_handler_t)(struct window *window, struct input *device, void *data); @@ -124,8 +121,10 @@ typedef int (*window_motion_handler_t)(struct window *window, int32_t x, int32_t y, int32_t sx, int32_t sy, void *data); -typedef void (*display_drag_offer_handler_t)(struct wl_drag_offer *offer, - struct display *display); +typedef void (*display_global_handler_t)(struct display *display, + const char *interface, + uint32_t id, + uint32_t version); struct window * window_create(struct display *display, const char *title, @@ -143,10 +142,6 @@ window_get_child_allocation(struct window *window, void window_set_child_size(struct window *window, int32_t width, int32_t height); void -window_copy_image(struct window *window, - struct rectangle *rectangle, - void *image); -void window_schedule_redraw(struct window *window); void @@ -156,11 +151,6 @@ window_damage(struct window *window, int32_t x, int32_t y, cairo_surface_t * window_get_surface(struct window *window); -void -window_copy_surface(struct window *window, - struct rectangle *rectangle, - cairo_surface_t *surface); - void window_flush(struct window *window); @@ -228,8 +218,8 @@ const char * window_get_title(struct window *window); void -display_set_drag_offer_handler(struct display *display, - display_drag_offer_handler_t handler); +display_set_global_handler(struct display *display, + display_global_handler_t handler); struct wl_drag * window_create_drag(struct window *window); @@ -241,7 +231,16 @@ window_activate_drag(struct wl_drag *drag, struct window *window, void input_get_position(struct input *input, int32_t *x, int32_t *y); +uint32_t +input_get_modifiers(struct input *input); + struct wl_input_device * input_get_input_device(struct input *input); +int +input_offers_mime_type(struct input *input, const char *type); +int +input_receive_mime_type(struct input *input, const char *type); + + #endif diff --git a/compositor/70-wayland.rules b/compositor/70-wayland.rules index 49442dee..1b7ca661 100644 --- a/compositor/70-wayland.rules +++ b/compositor/70-wayland.rules @@ -2,5 +2,6 @@ KERNEL=="event*", ENV{ID_INPUT_KEYBOARD}=="1", ENV{WAYLAND_SEAT}="1" KERNEL=="event*", ENV{ID_INPUT_MOUSE}=="1", ENV{WAYLAND_SEAT}="1" KERNEL=="event*", ENV{ID_INPUT_TOUCHPAD}=="1", ENV{WAYLAND_SEAT}="1" KERNEL=="event*", ENV{ID_INPUT_TOUCHSCREEN}=="1", ENV{WAYLAND_SEAT}="1" +KERNEL=="event*", ENV{ID_INPUT_TABLET}=="1", ENV{WAYLAND_SEAT}="1" KERNEL=="card0", ENV{WAYLAND_SEAT}="1" diff --git a/compositor/Makefile.am b/compositor/Makefile.am index 0b28cade..89ea4434 100644 --- a/compositor/Makefile.am +++ b/compositor/Makefile.am @@ -13,17 +13,33 @@ compositor_LDADD = \ $(top_builddir)/wayland/libwayland-client.la \ $(COMPOSITOR_LIBS) +if ENABLE_DRM_COMPOSITOR +drm_compositor_sources = compositor-drm.c tty.c evdev.c +drm_sources = drm.c +endif + +if ENABLE_X11_COMPOSITOR +x11_compositor_sources = compositor-x11.c +drm_sources = drm.c +endif + +if ENABLE_WAYLAND_COMPOSITOR +wayland_compositor_sources = compositor-wayland.c +drm_sources = drm.c +endif + compositor_SOURCES = \ compositor.c \ compositor.h \ - compositor-drm.c \ - compositor-x11.c \ - compositor-wayland.c \ + shell.c \ screenshooter.c \ screenshooter-protocol.c \ screenshooter-server-protocol.h \ - drm.c \ - shm.c + shm.c \ + $(drm_compositor_sources) \ + $(x11_compositor_sources) \ + $(wayland_compositor_sources) \ + $(drm_sources) udevrulesddir = $(sysconfdir)/udev/rules.d diff --git a/compositor/compositor-drm.c b/compositor/compositor-drm.c index de15bfed..6df6b34c 100644 --- a/compositor/compositor-drm.c +++ b/compositor/compositor-drm.c @@ -22,11 +22,6 @@ #include #include -#include -#include -#include -#include - #define GL_GLEXT_PROTOTYPES #define EGL_EGLEXT_PROTOTYPES #include @@ -42,14 +37,7 @@ struct drm_compositor { struct udev *udev; struct wl_event_source *drm_source; - /* tty handling state */ - int tty_fd; - uint32_t vt_active : 1; - - struct termios terminal_attributes; - struct wl_event_source *tty_input_source; - struct wl_event_source *enter_vt_source; - struct wl_event_source *leave_vt_source; + struct tty *tty; }; struct drm_output { @@ -64,199 +52,6 @@ struct drm_output { uint32_t current; }; -struct drm_input { - struct wlsc_input_device base; -}; - -struct evdev_input_device { - struct drm_input *master; - struct wl_event_source *source; - int tool, new_x, new_y; - int base_x, base_y; - int fd; -}; - -static void evdev_input_device_data(int fd, uint32_t mask, void *data) -{ - struct drm_compositor *c; - struct evdev_input_device *device = data; - struct input_event ev[8], *e, *end; - int len, value, dx, dy, absolute_event; - int x, y; - uint32_t time; - - c = (struct drm_compositor *) - device->master->base.input_device.compositor; - if (!c->vt_active) - return; - - dx = 0; - dy = 0; - absolute_event = 0; - x = device->master->base.input_device.x; - y = device->master->base.input_device.y; - - len = read(fd, &ev, sizeof ev); - if (len < 0 || len % sizeof e[0] != 0) { - /* FIXME: handle error... reopen device? */; - return; - } - - e = ev; - end = (void *) ev + len; - for (e = ev; e < end; e++) { - /* Get the signed value, earlier kernels had this as unsigned */ - value = e->value; - time = e->time.tv_sec * 1000 + e->time.tv_usec / 1000; - - switch (e->type) { - case EV_REL: - switch (e->code) { - case REL_X: - dx += value; - break; - - case REL_Y: - dy += value; - break; - } - break; - - case EV_ABS: - absolute_event = 1; - switch (e->code) { - case ABS_X: - if (device->new_x) { - device->base_x = x - value; - device->new_x = 0; - } - x = device->base_x + value; - break; - case ABS_Y: - if (device->new_y) { - device->base_y = y - value; - device->new_y = 0; - } - y = device->base_y + value; - break; - } - break; - - case EV_KEY: - if (value == 2) - break; - - switch (e->code) { - case BTN_TOUCH: - case BTN_TOOL_PEN: - case BTN_TOOL_RUBBER: - case BTN_TOOL_BRUSH: - case BTN_TOOL_PENCIL: - case BTN_TOOL_AIRBRUSH: - case BTN_TOOL_FINGER: - case BTN_TOOL_MOUSE: - case BTN_TOOL_LENS: - if (device->tool == 0 && value) { - device->new_x = 1; - device->new_y = 1; - } - device->tool = value ? e->code : 0; - break; - - case BTN_LEFT: - case BTN_RIGHT: - case BTN_MIDDLE: - case BTN_SIDE: - case BTN_EXTRA: - case BTN_FORWARD: - case BTN_BACK: - case BTN_TASK: - notify_button(&device->master->base.input_device, - time, e->code, value); - break; - - default: - notify_key(&device->master->base.input_device, - time, e->code, value); - break; - } - } - } - - if (dx != 0 || dy != 0) - notify_motion(&device->master->base.input_device, - time, x + dx, y + dy); - if (absolute_event && device->tool) - notify_motion(&device->master->base.input_device, time, x, y); -} - -static struct evdev_input_device * -evdev_input_device_create(struct drm_input *master, - struct wl_display *display, const char *path) -{ - struct evdev_input_device *device; - struct wl_event_loop *loop; - - device = malloc(sizeof *device); - if (device == NULL) - return NULL; - - device->tool = 1; - device->new_x = 1; - device->new_y = 1; - device->master = master; - - device->fd = open(path, O_RDONLY); - if (device->fd < 0) { - free(device); - fprintf(stderr, "couldn't create pointer for %s: %m\n", path); - return NULL; - } - - loop = wl_display_get_event_loop(display); - device->source = wl_event_loop_add_fd(loop, device->fd, - WL_EVENT_READABLE, - evdev_input_device_data, device); - if (device->source == NULL) { - close(device->fd); - free(device); - return NULL; - } - - return device; -} - -static void -drm_input_create(struct drm_compositor *c) -{ - struct drm_input *input; - struct udev_enumerate *e; - struct udev_list_entry *entry; - struct udev_device *device; - const char *path; - - input = malloc(sizeof *input); - if (input == NULL) - return; - - memset(input, 0, sizeof *input); - wlsc_input_device_init(&input->base, &c->base); - - e = udev_enumerate_new(c->udev); - udev_enumerate_add_match_subsystem(e, "input"); - udev_enumerate_add_match_property(e, "WAYLAND_SEAT", "1"); - udev_enumerate_scan_devices(e); - udev_list_entry_foreach(entry, udev_enumerate_get_list_entry(e)) { - path = udev_list_entry_get_name(entry); - device = udev_device_new_from_syspath(c->udev, path); - evdev_input_device_create(input, c->base.wl_display, - udev_device_get_devnode(device)); - } - udev_enumerate_unref(e); - - c->base.input_device = &input->base.input_device; -} - static void drm_compositor_present(struct wlsc_compositor *ec) { @@ -498,118 +293,6 @@ create_outputs(struct drm_compositor *ec, int option_connector) return 0; } -static void on_enter_vt(int signal_number, void *data) -{ - struct drm_compositor *ec = data; - struct drm_output *output; - int ret; - - ret = drmSetMaster(ec->base.drm.fd); - if (ret) { - fprintf(stderr, "failed to set drm master\n"); - kill(0, SIGTERM); - return; - } - - fprintf(stderr, "enter vt\n"); - - ioctl(ec->tty_fd, VT_RELDISP, VT_ACKACQ); - ret = ioctl(ec->tty_fd, KDSETMODE, KD_GRAPHICS); - if (ret) - fprintf(stderr, "failed to set KD_GRAPHICS mode on console: %m\n"); - ec->vt_active = 1; - - wl_list_for_each(output, &ec->base.output_list, base.link) { - ret = drmModeSetCrtc(ec->base.drm.fd, output->crtc_id, - output->fb_id[output->current ^ 1], 0, 0, - &output->connector_id, 1, &output->mode); - if (ret) - fprintf(stderr, - "failed to set mode for connector %d: %m\n", - output->connector_id); - } -} - -static void on_leave_vt(int signal_number, void *data) -{ - struct drm_compositor *ec = data; - int ret; - - ret = drmDropMaster(ec->base.drm.fd); - if (ret) { - fprintf(stderr, "failed to drop drm master\n"); - kill(0, SIGTERM); - return; - } - - ioctl (ec->tty_fd, VT_RELDISP, 1); - ret = ioctl(ec->tty_fd, KDSETMODE, KD_TEXT); - if (ret) - fprintf(stderr, "failed to set KD_TEXT mode on console: %m\n"); - ec->vt_active = 0; -} - -static void -on_tty_input(int fd, uint32_t mask, void *data) -{ - struct drm_compositor *ec = data; - - /* Ignore input to tty. We get keyboard events from evdev - */ - tcflush(ec->tty_fd, TCIFLUSH); -} - -static int setup_tty(struct drm_compositor *ec, struct wl_event_loop *loop) -{ - struct termios raw_attributes; - struct vt_mode mode = { 0 }; - int ret; - - ec->tty_fd = open("/dev/tty0", O_RDWR | O_NOCTTY); - if (ec->tty_fd <= 0) { - fprintf(stderr, "failed to open active tty: %m\n"); - return -1; - } - - if (tcgetattr(ec->tty_fd, &ec->terminal_attributes) < 0) { - fprintf(stderr, "could not get terminal attributes: %m\n"); - return -1; - } - - /* Ignore control characters and disable echo */ - raw_attributes = ec->terminal_attributes; - cfmakeraw(&raw_attributes); - - /* Fix up line endings to be normal (cfmakeraw hoses them) */ - raw_attributes.c_oflag |= OPOST | OCRNL; - - if (tcsetattr(ec->tty_fd, TCSANOW, &raw_attributes) < 0) - fprintf(stderr, "could not put terminal into raw mode: %m\n"); - - ec->tty_input_source = - wl_event_loop_add_fd(loop, ec->tty_fd, - WL_EVENT_READABLE, on_tty_input, ec); - - ret = ioctl(ec->tty_fd, KDSETMODE, KD_GRAPHICS); - if (ret) - fprintf(stderr, "failed to set KD_GRAPHICS mode on tty: %m\n"); - - ec->vt_active = 1; - mode.mode = VT_PROCESS; - mode.relsig = SIGUSR1; - mode.acqsig = SIGUSR2; - if (!ioctl(ec->tty_fd, VT_SETMODE, &mode) < 0) { - fprintf(stderr, "failed to take control of vt handling\n"); - } - - ec->leave_vt_source = - wl_event_loop_add_signal(loop, SIGUSR1, on_leave_vt, ec); - ec->enter_vt_source = - wl_event_loop_add_signal(loop, SIGUSR2, on_enter_vt, ec); - - return 0; -} - static int drm_authenticate(struct wlsc_compositor *c, uint32_t id) { @@ -623,11 +306,9 @@ drm_destroy(struct wlsc_compositor *ec) { struct drm_compositor *d = (struct drm_compositor *) ec; - if (tcsetattr(d->tty_fd, TCSANOW, &d->terminal_attributes) < 0) - fprintf(stderr, - "could not restore terminal to canonical mode\n"); + tty_destroy(d->tty); - free(ec); + free(d); } struct wlsc_compositor * @@ -673,7 +354,13 @@ drm_compositor_create(struct wl_display *display, int connector) fprintf(stderr, "failed to initialize egl\n"); return NULL; } - + + ec->base.destroy = drm_destroy; + ec->base.authenticate = drm_authenticate; + ec->base.present = drm_compositor_present; + ec->base.create_buffer = wlsc_drm_buffer_create; + ec->base.focus = 1; + /* Can't init base class until we have a current egl context */ if (wlsc_compositor_init(&ec->base, display) < 0) return NULL; @@ -683,17 +370,13 @@ drm_compositor_create(struct wl_display *display, int connector) return NULL; } - drm_input_create(ec); + evdev_input_add_devices(&ec->base, ec->udev); loop = wl_display_get_event_loop(ec->base.wl_display); ec->drm_source = wl_event_loop_add_fd(loop, ec->base.drm.fd, WL_EVENT_READABLE, on_drm_input, ec); - setup_tty(ec, loop); - ec->base.destroy = drm_destroy; - ec->base.authenticate = drm_authenticate; - ec->base.present = drm_compositor_present; - ec->base.focus = 1; + ec->tty = tty_create(&ec->base); return &ec->base; } diff --git a/compositor/compositor-wayland.c b/compositor/compositor-wayland.c index a7a7874f..8a40137d 100644 --- a/compositor/compositor-wayland.c +++ b/compositor/compositor-wayland.c @@ -278,9 +278,7 @@ wayland_compositor_create_output(struct wayland_compositor *c, static struct wl_buffer * create_invisible_pointer(struct wayland_compositor *c) { - struct wlsc_drm_buffer *wlsc_buffer; struct wl_buffer *buffer; - int name, stride; struct wl_visual *visual; GLuint texture; const int width = 1, height = 1; @@ -294,18 +292,8 @@ create_invisible_pointer(struct wayland_compositor *c) glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); visual = wl_display_get_premultiplied_argb_visual(c->parent.display); - wlsc_buffer = wlsc_drm_buffer_create(&c->base, width, height, visual); + buffer = c->base.create_buffer(&c->base, width, height, visual, data); - glEGLImageTargetTexture2DOES(GL_TEXTURE_2D, wlsc_buffer->image); - glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, width, height, - GL_RGBA, GL_UNSIGNED_BYTE, data); - - eglExportDRMImageMESA(c->base.display, wlsc_buffer->image, - &name, NULL, &stride); - - buffer = wl_drm_create_buffer(c->parent.drm, name, - width, height, - stride, visual); return buffer; } @@ -542,6 +530,11 @@ wayland_compositor_create(struct wl_display *display, int width, int height) if (wayland_compositor_init_egl(c) < 0) return NULL; + c->base.destroy = wayland_destroy; + c->base.authenticate = wayland_authenticate; + c->base.present = wayland_compositor_present; + c->base.create_buffer = wlsc_drm_buffer_create; + /* Can't init base class until we have a current egl context */ if (wlsc_compositor_init(&c->base, display) < 0) return NULL; @@ -561,9 +554,5 @@ wayland_compositor_create(struct wl_display *display, int width, int height) if (c->parent.wl_source == NULL) return NULL; - c->base.destroy = wayland_destroy; - c->base.authenticate = wayland_authenticate; - c->base.present = wayland_compositor_present; - return &c->base; } diff --git a/compositor/compositor-x11.c b/compositor/compositor-x11.c index 722bd944..7e7c8ca1 100644 --- a/compositor/compositor-x11.c +++ b/compositor/compositor-x11.c @@ -676,6 +676,11 @@ x11_compositor_create(struct wl_display *display, int width, int height) if (x11_compositor_init_egl(c) < 0) return NULL; + c->base.destroy = x11_destroy; + c->base.authenticate = x11_authenticate; + c->base.present = x11_compositor_present; + c->base.create_buffer = wlsc_drm_buffer_create; + /* Can't init base class until we have a current egl context */ if (wlsc_compositor_init(&c->base, display) < 0) return NULL; @@ -693,9 +698,5 @@ x11_compositor_create(struct wl_display *display, int width, int height) WL_EVENT_READABLE, x11_compositor_handle_event, c); - c->base.destroy = x11_destroy; - c->base.authenticate = x11_authenticate; - c->base.present = x11_compositor_present; - return &c->base; } diff --git a/compositor/compositor.c b/compositor/compositor.c index 1e6f2efe..72a3878c 100644 --- a/compositor/compositor.c +++ b/compositor/compositor.c @@ -18,6 +18,8 @@ #define _GNU_SOURCE +#include "config.h" + #include #include #include @@ -30,7 +32,7 @@ #include #include -#include "wayland-server-protocol.h" +#include "wayland-server.h" #include "compositor.h" /* The plan here is to generate a random anonymous socket name and @@ -119,7 +121,6 @@ wlsc_matrix_transform(struct wlsc_matrix *matrix, struct wlsc_vector *v) static struct wlsc_surface * wlsc_surface_create(struct wlsc_compositor *compositor, - struct wl_visual *visual, int32_t x, int32_t y, int32_t width, int32_t height) { struct wlsc_surface *surface; @@ -140,7 +141,7 @@ wlsc_surface_create(struct wlsc_compositor *compositor, glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); surface->compositor = compositor; - surface->visual = visual; + surface->visual = NULL; surface->x = x; surface->y = y; surface->width = width; @@ -156,7 +157,7 @@ wlsc_surface_create(struct wlsc_compositor *compositor, return surface; } -static uint32_t +uint32_t get_time(void) { struct timeval tv; @@ -188,33 +189,76 @@ destroy_surface(struct wl_resource *resource, struct wl_client *client) wlsc_compositor_schedule_repaint(compositor); } -static int -texture_from_png(const char *filename, int width, int height) +static struct wl_buffer * +create_buffer_from_png(struct wlsc_compositor *ec, + const char *filename, int width, int height) { GdkPixbuf *pixbuf; GError *error = NULL; - void *data; - GLenum format; + int stride, i, n_channels; + unsigned char *pixels, *end, *argb_pixels, *s, *d; + struct wl_buffer *buffer; pixbuf = gdk_pixbuf_new_from_file_at_scale(filename, width, height, FALSE, &error); if (error != NULL) - return -1; + return NULL; - data = gdk_pixbuf_get_pixels(pixbuf); + stride = gdk_pixbuf_get_rowstride(pixbuf); + pixels = gdk_pixbuf_get_pixels(pixbuf); + n_channels = gdk_pixbuf_get_n_channels(pixbuf); - if (gdk_pixbuf_get_has_alpha(pixbuf)) - format = GL_RGBA; - else - format = GL_RGB; + argb_pixels = malloc (height * width * 4); + if (argb_pixels == NULL) { + gdk_pixbuf_unref(pixbuf); + return NULL; + } - glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, width, height, - format, GL_UNSIGNED_BYTE, data); + if (n_channels == 4) { + for (i = 0; i < height; i++) { + s = pixels + i * stride; + end = s + width * 4; + d = argb_pixels + i * width * 4; + while (s < end) { + unsigned int t; + +#define MULT(_d,c,a,t) \ + do { t = c * a + 0x7f; _d = ((t >> 8) + t) >> 8; } while (0) + + MULT(d[0], s[2], s[3], t); + MULT(d[1], s[1], s[3], t); + MULT(d[2], s[0], s[3], t); + d[3] = s[3]; + s += 4; + d += 4; + } + } + } else if (n_channels == 3) { + for (i = 0; i < height; i++) { + s = pixels + i * stride; + end = s + width * 3; + d = argb_pixels + i * width * 4; + while (s < end) { + d[0] = s[2]; + d[1] = s[1]; + d[2] = s[0]; + d[3] = 0xff; + s += 3; + d += 4; + } + } + } gdk_pixbuf_unref(pixbuf); - return 0; + buffer = ec->create_buffer(ec, width, height, + &ec->compositor.premultiplied_argb_visual, + argb_pixels); + + free(argb_pixels); + + return buffer; } static const struct { @@ -238,25 +282,15 @@ static void create_pointer_images(struct wlsc_compositor *ec) { int i, count; - GLuint texture; const int width = 32, height = 32; - glGenTextures(1, &texture); - glBindTexture(GL_TEXTURE_2D, texture); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); - count = ARRAY_LENGTH(pointer_images); ec->pointer_buffers = malloc(count * sizeof *ec->pointer_buffers); for (i = 0; i < count; i++) { ec->pointer_buffers[i] = - wlsc_drm_buffer_create(ec, width, height, - &ec->compositor.argb_visual); - glEGLImageTargetTexture2DOES(GL_TEXTURE_2D, - ec->pointer_buffers[i]->image); - texture_from_png(pointer_images[i].filename, width, height); + create_buffer_from_png(ec, + pointer_images[i].filename, + width, height); } } @@ -264,37 +298,22 @@ static struct wlsc_surface * background_create(struct wlsc_output *output, const char *filename) { struct wlsc_surface *background; - GdkPixbuf *pixbuf; - GError *error = NULL; - void *data; - GLenum format; + struct wl_buffer *buffer; background = wlsc_surface_create(output->compositor, - &output->compositor->compositor.rgb_visual, output->x, output->y, output->width, output->height); if (background == NULL) return NULL; - pixbuf = gdk_pixbuf_new_from_file_at_scale(filename, - output->width, - output->height, - FALSE, &error); - if (error != NULL) { + buffer = create_buffer_from_png(output->compositor, + filename, + output->width, output->height); + if (buffer == NULL) { free(background); return NULL; } - - data = gdk_pixbuf_get_pixels(pixbuf); - - if (gdk_pixbuf_get_has_alpha(pixbuf)) - format = GL_RGBA; - else - format = GL_RGB; - - glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, - output->width, output->height, 0, - format, GL_UNSIGNED_BYTE, data); + buffer->attach(buffer, &background->surface); return background; } @@ -340,7 +359,7 @@ wlsc_surface_raise(struct wlsc_surface *surface) wl_list_insert(&compositor->surface_list, &surface->link); } -static void +void wlsc_surface_update_matrix(struct wlsc_surface *es) { wlsc_matrix_init(&es->matrix); @@ -492,7 +511,7 @@ wlsc_input_device_attach(struct wlsc_input_device *device, } -static void +void wlsc_input_device_set_pointer_image(struct wlsc_input_device *device, enum wlsc_pointer_type type) { @@ -500,253 +519,11 @@ wlsc_input_device_set_pointer_image(struct wlsc_input_device *device, (struct wlsc_compositor *) device->input_device.compositor; wlsc_input_device_attach(device, - &compositor->pointer_buffers[type]->buffer, + compositor->pointer_buffers[type], pointer_images[type].hotspot_x, pointer_images[type].hotspot_y); } -struct wlsc_move_grab { - struct wl_grab grab; - int32_t dx, dy; -}; - -static void -move_grab_motion(struct wl_grab *grab, - uint32_t time, int32_t x, int32_t y) -{ - struct wlsc_move_grab *move = (struct wlsc_move_grab *) grab; - struct wlsc_surface *es = - (struct wlsc_surface *) grab->input_device->pointer_focus; - - es->x = x + move->dx; - es->y = y + move->dy; - wlsc_surface_update_matrix(es); -} - -static void -move_grab_button(struct wl_grab *grab, - uint32_t time, int32_t button, int32_t state) -{ -} - -static void -move_grab_end(struct wl_grab *grab, uint32_t time) -{ - free(grab); -} - -static const struct wl_grab_interface move_grab_interface = { - move_grab_motion, - move_grab_button, - move_grab_end -}; - -static void -shell_move(struct wl_client *client, struct wl_shell *shell, - struct wl_surface *surface, - struct wl_input_device *device, uint32_t time) -{ - struct wlsc_input_device *wd = (struct wlsc_input_device *) device; - struct wlsc_surface *es = (struct wlsc_surface *) surface; - struct wlsc_move_grab *move; - - move = malloc(sizeof *move); - if (!move) { - wl_client_post_no_memory(client); - return; - } - - move->grab.interface = &move_grab_interface; - move->dx = es->x - wd->input_device.grab_x; - move->dy = es->y - wd->input_device.grab_y; - - if (wl_input_device_update_grab(&wd->input_device, - &move->grab, surface, time) < 0) - return; - - wlsc_input_device_set_pointer_image(wd, WLSC_POINTER_DRAGGING); -} - -struct wlsc_resize_grab { - struct wl_grab grab; - uint32_t edges; - int32_t dx, dy, width, height; -}; - -static void -resize_grab_motion(struct wl_grab *grab, - uint32_t time, int32_t x, int32_t y) -{ - struct wlsc_resize_grab *resize = (struct wlsc_resize_grab *) grab; - struct wl_input_device *device = grab->input_device; - struct wlsc_compositor *ec = - (struct wlsc_compositor *) device->compositor; - struct wl_surface *surface = device->pointer_focus; - int32_t width, height; - - if (resize->edges & WL_GRAB_RESIZE_LEFT) { - width = device->grab_x - x + resize->width; - } else if (resize->edges & WL_GRAB_RESIZE_RIGHT) { - width = x - device->grab_x + resize->width; - } else { - width = resize->width; - } - - if (resize->edges & WL_GRAB_RESIZE_TOP) { - height = device->grab_y - y + resize->height; - } else if (resize->edges & WL_GRAB_RESIZE_BOTTOM) { - height = y - device->grab_y + resize->height; - } else { - height = resize->height; - } - - wl_client_post_event(surface->client, &ec->shell.object, - WL_SHELL_CONFIGURE, time, resize->edges, - surface, width, height); -} - -static void -resize_grab_button(struct wl_grab *grab, - uint32_t time, int32_t button, int32_t state) -{ -} - -static void -resize_grab_end(struct wl_grab *grab, uint32_t time) -{ - free(grab); -} - -static const struct wl_grab_interface resize_grab_interface = { - resize_grab_motion, - resize_grab_button, - resize_grab_end -}; - -static void -shell_resize(struct wl_client *client, struct wl_shell *shell, - struct wl_surface *surface, - struct wl_input_device *device, uint32_t time, uint32_t edges) -{ - struct wlsc_input_device *wd = (struct wlsc_input_device *) device; - struct wlsc_resize_grab *resize; - enum wlsc_pointer_type pointer = WLSC_POINTER_LEFT_PTR; - struct wlsc_surface *es = (struct wlsc_surface *) surface; - - resize = malloc(sizeof *resize); - if (!resize) { - wl_client_post_no_memory(client); - return; - } - - resize->grab.interface = &resize_grab_interface; - resize->edges = edges; - resize->dx = es->x - wd->input_device.grab_x; - resize->dy = es->y - wd->input_device.grab_y; - resize->width = es->width; - resize->height = es->height; - - if (edges == 0 || edges > 15 || - (edges & 3) == 3 || (edges & 12) == 12) - return; - - switch (edges) { - case WL_GRAB_RESIZE_TOP: - pointer = WLSC_POINTER_TOP; - break; - case WL_GRAB_RESIZE_BOTTOM: - pointer = WLSC_POINTER_BOTTOM; - break; - case WL_GRAB_RESIZE_LEFT: - pointer = WLSC_POINTER_LEFT; - break; - case WL_GRAB_RESIZE_TOP_LEFT: - pointer = WLSC_POINTER_TOP_LEFT; - break; - case WL_GRAB_RESIZE_BOTTOM_LEFT: - pointer = WLSC_POINTER_BOTTOM_LEFT; - break; - case WL_GRAB_RESIZE_RIGHT: - pointer = WLSC_POINTER_RIGHT; - break; - case WL_GRAB_RESIZE_TOP_RIGHT: - pointer = WLSC_POINTER_TOP_RIGHT; - break; - case WL_GRAB_RESIZE_BOTTOM_RIGHT: - pointer = WLSC_POINTER_BOTTOM_RIGHT; - break; - } - - if (wl_input_device_update_grab(&wd->input_device, - &resize->grab, surface, time) < 0) - return; - - wlsc_input_device_set_pointer_image(wd, pointer); -} - -static void -wl_drag_set_pointer_focus(struct wl_drag *drag, - struct wl_surface *surface, uint32_t time, - int32_t x, int32_t y, int32_t sx, int32_t sy); - -static void -destroy_drag(struct wl_resource *resource, struct wl_client *client) -{ - struct wl_drag *drag = - container_of(resource, struct wl_drag, resource); - - wl_list_remove(&drag->drag_focus_listener.link); - if (drag->grab.input_device) - wl_input_device_end_grab(drag->grab.input_device, get_time()); - - free(drag); -} - -const static struct wl_drag_interface drag_interface; - -static void -drag_handle_surface_destroy(struct wl_listener *listener, - struct wl_surface *surface, uint32_t time) -{ - struct wl_drag *drag = - container_of(listener, struct wl_drag, drag_focus_listener); - - if (drag->drag_focus == surface) - wl_drag_set_pointer_focus(drag, NULL, time, 0, 0, 0, 0); -} - -static void -shell_create_drag(struct wl_client *client, - struct wl_shell *shell, uint32_t id) -{ - struct wl_drag *drag; - - drag = malloc(sizeof *drag); - if (drag == NULL) { - wl_client_post_no_memory(client); - return; - } - - memset(drag, 0, sizeof *drag); - drag->resource.object.id = id; - drag->resource.object.interface = &wl_drag_interface; - drag->resource.object.implementation = - (void (**)(void)) &drag_interface; - - drag->resource.destroy = destroy_drag; - - drag->drag_focus_listener.func = drag_handle_surface_destroy; - wl_list_init(&drag->drag_focus_listener.link); - - wl_client_add_resource(client, &drag->resource); -} - -const static struct wl_shell_interface shell_interface = { - shell_move, - shell_resize, - shell_create_drag -}; - static void compositor_create_surface(struct wl_client *client, struct wl_compositor *compositor, uint32_t id) @@ -754,7 +531,7 @@ compositor_create_surface(struct wl_client *client, struct wlsc_compositor *ec = (struct wlsc_compositor *) compositor; struct wlsc_surface *surface; - surface = wlsc_surface_create(ec, NULL, 0, 0, 0, 0); + surface = wlsc_surface_create(ec, 0, 0, 0, 0); if (surface == NULL) { wl_client_post_no_memory(client); return; @@ -786,7 +563,7 @@ wlsc_surface_transform(struct wlsc_surface *surface, *sy = v.f[1] * surface->height; } -static struct wlsc_surface * +struct wlsc_surface * pick_surface(struct wl_input_device *device, int32_t *sx, int32_t *sy) { struct wlsc_compositor *ec = @@ -905,6 +682,10 @@ notify_button(struct wl_input_device *device, if (state && device->grab == NULL) { wlsc_surface_raise(surface); + if (wd->selection) + wlsc_selection_set_focus(wd->selection, + &surface->surface, time); + wl_input_device_start_grab(device, &device->motion_grab, button, time); @@ -990,202 +771,6 @@ notify_key(struct wl_input_device *device, WL_INPUT_DEVICE_KEY, time, key, state); } -static void -wl_drag_set_pointer_focus(struct wl_drag *drag, - struct wl_surface *surface, uint32_t time, - int32_t x, int32_t y, int32_t sx, int32_t sy) -{ - char **p, **end; - - if (drag->drag_focus == surface) - return; - - if (drag->drag_focus && - (!surface || drag->drag_focus->client != surface->client)) - wl_client_post_event(drag->drag_focus->client, - &drag->drag_offer.object, - WL_DRAG_OFFER_POINTER_FOCUS, - time, NULL, 0, 0, 0, 0); - - if (surface && - (!drag->drag_focus || - drag->drag_focus->client != surface->client)) { - wl_client_post_global(surface->client, - &drag->drag_offer.object); - - end = drag->types.data + drag->types.size; - for (p = drag->types.data; p < end; p++) - wl_client_post_event(surface->client, - &drag->drag_offer.object, - WL_DRAG_OFFER_OFFER, *p); - } - - if (surface) { - wl_client_post_event(surface->client, - &drag->drag_offer.object, - WL_DRAG_OFFER_POINTER_FOCUS, - time, surface, - x, y, sx, sy); - - } - - drag->drag_focus = surface; - drag->pointer_focus_time = time; - drag->target = NULL; - - wl_list_remove(&drag->drag_focus_listener.link); - if (surface) - wl_list_insert(surface->destroy_listener_list.prev, - &drag->drag_focus_listener.link); -} - -static void -drag_offer_accept(struct wl_client *client, - struct wl_drag_offer *offer, uint32_t time, const char *type) -{ - struct wl_drag *drag = container_of(offer, struct wl_drag, drag_offer); - char **p, **end; - - /* If the client responds to drag pointer_focus or motion - * events after the pointer has left the surface, we just - * discard the accept requests. The drag source just won't - * get the corresponding 'target' events and eventually the - * next surface/root will start sending events. */ - if (time < drag->pointer_focus_time) - return; - - drag->target = client; - drag->type = NULL; - end = drag->types.data + drag->types.size; - for (p = drag->types.data; p < end; p++) - if (type && strcmp(*p, type) == 0) - drag->type = *p; - - wl_client_post_event(drag->source->client, &drag->resource.object, - WL_DRAG_TARGET, drag->type); -} - -static void -drag_offer_receive(struct wl_client *client, - struct wl_drag_offer *offer, int fd) -{ - struct wl_drag *drag = container_of(offer, struct wl_drag, drag_offer); - - wl_client_post_event(drag->source->client, &drag->resource.object, - WL_DRAG_FINISH, fd); - close(fd); -} - -static void -drag_offer_reject(struct wl_client *client, struct wl_drag_offer *offer) -{ - struct wl_drag *drag = container_of(offer, struct wl_drag, drag_offer); - - wl_client_post_event(drag->source->client, &drag->resource.object, - WL_DRAG_REJECT); -} - -static const struct wl_drag_offer_interface drag_offer_interface = { - drag_offer_accept, - drag_offer_receive, - drag_offer_reject -}; - -static void -drag_offer(struct wl_client *client, struct wl_drag *drag, const char *type) -{ - char **p; - - p = wl_array_add(&drag->types, sizeof *p); - if (p) - *p = strdup(type); - if (!p || !*p) - wl_client_post_no_memory(client); -} - -static void -drag_grab_motion(struct wl_grab *grab, - uint32_t time, int32_t x, int32_t y) -{ - struct wl_drag *drag = container_of(grab, struct wl_drag, grab); - struct wlsc_surface *es; - int32_t sx, sy; - - es = pick_surface(grab->input_device, &sx, &sy); - wl_drag_set_pointer_focus(drag, &es->surface, time, x, y, sx, sy); - if (es) - wl_client_post_event(es->surface.client, - &drag->drag_offer.object, - WL_DRAG_OFFER_MOTION, - time, x, y, sx, sy); -} - -static void -drag_grab_button(struct wl_grab *grab, - uint32_t time, int32_t button, int32_t state) -{ -} - -static void -drag_grab_end(struct wl_grab *grab, uint32_t time) -{ - struct wl_drag *drag = container_of(grab, struct wl_drag, grab); - - if (drag->target) - wl_client_post_event(drag->target, - &drag->drag_offer.object, - WL_DRAG_OFFER_DROP); - - wl_drag_set_pointer_focus(drag, NULL, time, 0, 0, 0, 0); -} - -static const struct wl_grab_interface drag_grab_interface = { - drag_grab_motion, - drag_grab_button, - drag_grab_end -}; - -static void -drag_activate(struct wl_client *client, - struct wl_drag *drag, - struct wl_surface *surface, - struct wl_input_device *device, uint32_t time) -{ - struct wl_display *display = wl_client_get_display (client); - struct wlsc_surface *target; - int32_t sx, sy; - - if (wl_input_device_update_grab(device, - &drag->grab, surface, time) < 0) - return; - - drag->grab.interface = &drag_grab_interface; - - drag->source = surface; - - drag->drag_offer.object.interface = &wl_drag_offer_interface; - drag->drag_offer.object.implementation = - (void (**)(void)) &drag_offer_interface; - - wl_display_add_object(display, &drag->drag_offer.object); - - target = pick_surface(device, &sx, &sy); - wl_drag_set_pointer_focus(drag, &target->surface, time, - device->x, device->y, sx, sy); -} - -static void -drag_destroy(struct wl_client *client, struct wl_drag *drag) -{ - wl_resource_destroy(&drag->resource, client); -} - -static const struct wl_drag_interface drag_interface = { - drag_offer, - drag_activate, - drag_destroy, -}; - static void input_device_attach(struct wl_client *client, struct wl_input_device *device_base, @@ -1228,7 +813,7 @@ wlsc_input_device_init(struct wlsc_input_device *device, wl_display_add_object(ec->wl_display, &device->input_device.object); wl_display_add_global(ec->wl_display, &device->input_device.object, NULL); - device->sprite = wlsc_surface_create(ec, &ec->compositor.argb_visual, + device->sprite = wlsc_surface_create(ec, device->input_device.x, device->input_device.y, 32, 32); device->hotspot_x = 16; @@ -1383,6 +968,7 @@ int wlsc_compositor_init(struct wlsc_compositor *ec, struct wl_display *display) { struct wl_event_loop *loop; + const char *extensions; ec->wl_display = display; @@ -1390,11 +976,7 @@ wlsc_compositor_init(struct wlsc_compositor *ec, struct wl_display *display) wlsc_shm_init(ec); - ec->shell.object.interface = &wl_shell_interface; - ec->shell.object.implementation = (void (**)(void)) &shell_interface; - wl_display_add_object(display, &ec->shell.object); - if (wl_display_add_global(display, &ec->shell.object, NULL)) - return -1; + wlsc_shell_init(ec); wl_list_init(&ec->surface_list); wl_list_init(&ec->input_device_list); @@ -1404,6 +986,13 @@ wlsc_compositor_init(struct wlsc_compositor *ec, struct wl_display *display) screenshooter_create(ec); + extensions = (const char *) glGetString(GL_EXTENSIONS); + if (!strstr(extensions, "GL_EXT_texture_format_BGRA8888")) { + fprintf(stderr, + "GL_EXT_texture_format_BGRA8888 not available\n"); + return -1; + } + glGenFramebuffers(1, &ec->fbo); glBindFramebuffer(GL_FRAMEBUFFER, ec->fbo); glActiveTexture(GL_TEXTURE0); @@ -1449,12 +1038,22 @@ int main(int argc, char *argv[]) display = wl_display_create(); + ec = NULL; + +#if BUILD_WAYLAND_COMPOSITOR if (getenv("WAYLAND_DISPLAY")) ec = wayland_compositor_create(display, width, height); - else if (getenv("DISPLAY")) +#endif + +#if BUILD_X11_COMPOSITOR + if (ec == NULL && getenv("DISPLAY")) ec = x11_compositor_create(display, width, height); - else +#endif + +#if BUILD_DRM_COMPOSITOR + if (ec == NULL) ec = drm_compositor_create(display, option_connector); +#endif if (ec == NULL) { fprintf(stderr, "failed to create compositor\n"); diff --git a/compositor/compositor.h b/compositor/compositor.h index 99035c71..ac826ed8 100644 --- a/compositor/compositor.h +++ b/compositor/compositor.h @@ -19,7 +19,6 @@ #ifndef _WAYLAND_SYSTEM_COMPOSITOR_H_ #define _WAYLAND_SYSTEM_COMPOSITOR_H_ -#include #include #include #include @@ -70,6 +69,7 @@ struct wlsc_input_device { int32_t hotspot_x, hotspot_y; struct wl_list link; uint32_t modifier_state; + struct wl_selection *selection; }; struct wlsc_drm { @@ -78,21 +78,10 @@ struct wlsc_drm { char *filename; }; -struct wlsc_drm_buffer { - struct wl_buffer buffer; - EGLImageKHR image; -}; - struct wlsc_shm { struct wl_object object; }; -struct wlsc_shm_buffer { - struct wl_buffer buffer; - int32_t stride; - void *data; -}; - struct wlsc_compositor { struct wl_compositor compositor; @@ -102,7 +91,7 @@ struct wlsc_compositor { EGLContext context; GLuint fbo, vbo; GLuint proj_uniform, tex_uniform; - struct wlsc_drm_buffer **pointer_buffers; + struct wl_buffer **pointer_buffers; struct wl_display *wl_display; /* We implement the shell interface. */ @@ -126,6 +115,10 @@ struct wlsc_compositor { void (*destroy)(struct wlsc_compositor *ec); int (*authenticate)(struct wlsc_compositor *c, uint32_t id); void (*present)(struct wlsc_compositor *c); + struct wl_buffer *(*create_buffer)(struct wlsc_compositor *c, + int32_t width, int32_t height, + struct wl_visual *visual, + const void *data); }; #define MODIFIER_CTRL (1 << 8) @@ -149,6 +142,9 @@ struct wlsc_surface { int mapped; }; +void +wlsc_surface_update_matrix(struct wlsc_surface *es); + void notify_motion(struct wl_input_device *device, uint32_t time, int x, int y); @@ -164,9 +160,23 @@ wlsc_compositor_finish_frame(struct wlsc_compositor *compositor, int msecs); void wlsc_compositor_schedule_repaint(struct wlsc_compositor *compositor); -struct wlsc_drm_buffer * +void +wlsc_input_device_set_pointer_image(struct wlsc_input_device *device, + enum wlsc_pointer_type type); +struct wlsc_surface * +pick_surface(struct wl_input_device *device, int32_t *sx, int32_t *sy); + +void +wlsc_selection_set_focus(struct wl_selection *selection, + struct wl_surface *surface, uint32_t time); + +uint32_t +get_time(void); + +struct wl_buffer * wlsc_drm_buffer_create(struct wlsc_compositor *ec, - int width, int height, struct wl_visual *visual); + int width, int height, + struct wl_visual *visual, const void *data); int wlsc_compositor_init(struct wlsc_compositor *ec, struct wl_display *display); @@ -182,6 +192,19 @@ wlsc_drm_init(struct wlsc_compositor *ec, int fd, const char *filename); int wlsc_shm_init(struct wlsc_compositor *ec); +int +wlsc_shell_init(struct wlsc_compositor *ec); + +void +shell_move(struct wl_client *client, struct wl_shell *shell, + struct wl_surface *surface, + struct wl_input_device *device, uint32_t time); + +void +shell_resize(struct wl_client *client, struct wl_shell *shell, + struct wl_surface *surface, + struct wl_input_device *device, uint32_t time, uint32_t edges); + struct wl_buffer * wl_buffer_create_drm(struct wlsc_compositor *compositor, struct wl_visual *visual); @@ -195,6 +218,15 @@ drm_compositor_create(struct wl_display *display, int connector); struct wlsc_compositor * wayland_compositor_create(struct wl_display *display, int width, int height); +void +evdev_input_add_devices(struct wlsc_compositor *c, struct udev *udev); + +struct tty * +tty_create(struct wlsc_compositor *compositor); + +void +tty_destroy(struct tty *tty); + void screenshooter_create(struct wlsc_compositor *ec); diff --git a/compositor/drm.c b/compositor/drm.c index 0c3b1296..9e25d339 100644 --- a/compositor/drm.c +++ b/compositor/drm.c @@ -22,6 +22,11 @@ #include "compositor.h" +struct wlsc_drm_buffer { + struct wl_buffer buffer; + EGLImageKHR image; +}; + static void drm_authenticate(struct wl_client *client, struct wl_drm *drm_base, uint32_t id) @@ -197,12 +202,13 @@ wlsc_drm_init(struct wlsc_compositor *ec, int fd, const char *filename) return 0; } -struct wlsc_drm_buffer * -wlsc_drm_buffer_create(struct wlsc_compositor *ec, - int width, int height, struct wl_visual *visual) +struct wl_buffer * +wlsc_drm_buffer_create(struct wlsc_compositor *ec, int width, int height, + struct wl_visual *visual, const void *data) { struct wlsc_drm_buffer *buffer; EGLImageKHR image; + GLuint texture; EGLint image_attribs[] = { EGL_WIDTH, 0, @@ -222,5 +228,19 @@ wlsc_drm_buffer_create(struct wlsc_compositor *ec, buffer = wlsc_drm_buffer_create_for_image(ec, image, width, height, visual); - return buffer; + glGenTextures(1, &texture); + glBindTexture(GL_TEXTURE_2D, texture); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); + + glEGLImageTargetTexture2DOES(GL_TEXTURE_2D, buffer->image); + + glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, width, height, + GL_BGRA_EXT, GL_UNSIGNED_BYTE, data); + + glDeleteTextures(1, &texture); + + return &buffer->buffer; } diff --git a/compositor/evdev.c b/compositor/evdev.c new file mode 100644 index 00000000..6ff7b699 --- /dev/null +++ b/compositor/evdev.c @@ -0,0 +1,239 @@ +/* + * Copyright © 2010 Intel Corporation + * + * Permission to use, copy, modify, distribute, and sell this software and + * its documentation for any purpose is hereby granted without fee, provided + * that the above copyright notice appear in all copies and that both that + * copyright notice and this permission notice appear in supporting + * documentation, and that the name of the copyright holders not be used in + * advertising or publicity pertaining to distribution of the software + * without specific, written prior permission. The copyright holders make + * no representations about the suitability of this software for any + * purpose. It is provided "as is" without express or implied warranty. + * + * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS + * SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS, IN NO EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY + * SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER + * RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF + * CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN + * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include +#include +#include +#include +#include +#include + +#include "compositor.h" + +struct evdev_input { + struct wlsc_input_device base; +}; + +struct evdev_input_device { + struct evdev_input *master; + struct wl_event_source *source; + int tool, new_x, new_y; + int base_x, base_y; + int fd; + int min_x, max_x, min_y, max_y; +}; + +static void evdev_input_device_data(int fd, uint32_t mask, void *data) +{ + struct wlsc_compositor *ec; + struct evdev_input_device *device = data; + struct input_event ev[8], *e, *end; + int len, value, dx, dy, absolute_event; + int x, y; + uint32_t time; + + /* FIXME: Obviously we need to not hardcode these here, but + * instead get the values from the output it's associated with. */ + const int screen_width = 1024, screen_height = 600; + + ec = (struct wlsc_compositor *) + device->master->base.input_device.compositor; + if (!ec->focus) + return; + + dx = 0; + dy = 0; + absolute_event = 0; + x = device->master->base.input_device.x; + y = device->master->base.input_device.y; + + len = read(fd, &ev, sizeof ev); + if (len < 0 || len % sizeof e[0] != 0) { + /* FIXME: handle error... reopen device? */; + return; + } + + e = ev; + end = (void *) ev + len; + for (e = ev; e < end; e++) { + /* Get the signed value, earlier kernels had this as unsigned */ + value = e->value; + time = e->time.tv_sec * 1000 + e->time.tv_usec / 1000; + + switch (e->type) { + case EV_REL: + switch (e->code) { + case REL_X: + dx += value; + break; + + case REL_Y: + dy += value; + break; + } + break; + + case EV_ABS: + switch (e->code) { + case ABS_X: + absolute_event = device->tool; + x = (value - device->min_x) * screen_width / + (device->max_x - device->min_x); + break; + case ABS_Y: + absolute_event = device->tool; + y = (value - device->min_y) * screen_height / + (device->max_y - device->min_y); + break; + } + break; + + case EV_KEY: + if (value == 2) + break; + + switch (e->code) { + case BTN_TOUCH: + case BTN_TOOL_PEN: + case BTN_TOOL_RUBBER: + case BTN_TOOL_BRUSH: + case BTN_TOOL_PENCIL: + case BTN_TOOL_AIRBRUSH: + case BTN_TOOL_FINGER: + case BTN_TOOL_MOUSE: + case BTN_TOOL_LENS: + device->tool = value ? e->code : 0; + break; + + case BTN_LEFT: + case BTN_RIGHT: + case BTN_MIDDLE: + case BTN_SIDE: + case BTN_EXTRA: + case BTN_FORWARD: + case BTN_BACK: + case BTN_TASK: + notify_button(&device->master->base.input_device, + time, e->code, value); + break; + + default: + notify_key(&device->master->base.input_device, + time, e->code, value); + break; + } + } + } + + if (dx != 0 || dy != 0) + notify_motion(&device->master->base.input_device, + time, x + dx, y + dy); + if (absolute_event) + notify_motion(&device->master->base.input_device, time, x, y); +} + +#define TEST_BIT(b, i) (b[(i) / 32] & (1 << (i & 31))) + +static struct evdev_input_device * +evdev_input_device_create(struct evdev_input *master, + struct wl_display *display, const char *path) +{ + struct evdev_input_device *device; + struct wl_event_loop *loop; + struct input_absinfo absinfo; + uint32_t ev_bits[EV_MAX]; + uint32_t key_bits[KEY_MAX]; + + device = malloc(sizeof *device); + if (device == NULL) + return NULL; + + device->tool = 1; + device->new_x = 1; + device->new_y = 1; + device->master = master; + + device->fd = open(path, O_RDONLY); + if (device->fd < 0) { + free(device); + fprintf(stderr, "couldn't create pointer for %s: %m\n", path); + return NULL; + } + + ioctl(device->fd, EVIOCGBIT(0, EV_MAX), ev_bits); + if (TEST_BIT(ev_bits, EV_ABS)) { + ioctl(device->fd, EVIOCGBIT(EV_ABS, EV_MAX), key_bits); + if (TEST_BIT(key_bits, ABS_X)) { + ioctl(device->fd, EVIOCGABS(ABS_X), &absinfo); + device->min_x = absinfo.minimum; + device->max_x = absinfo.maximum; + } + if (TEST_BIT(key_bits, ABS_Y)) { + ioctl(device->fd, EVIOCGABS(ABS_Y), &absinfo); + device->min_y = absinfo.minimum; + device->max_y = absinfo.maximum; + } + } + + loop = wl_display_get_event_loop(display); + device->source = wl_event_loop_add_fd(loop, device->fd, + WL_EVENT_READABLE, + evdev_input_device_data, device); + if (device->source == NULL) { + close(device->fd); + free(device); + return NULL; + } + + return device; +} + +void +evdev_input_add_devices(struct wlsc_compositor *c, struct udev *udev) +{ + struct evdev_input *input; + struct udev_enumerate *e; + struct udev_list_entry *entry; + struct udev_device *device; + const char *path; + + input = malloc(sizeof *input); + if (input == NULL) + return; + + memset(input, 0, sizeof *input); + wlsc_input_device_init(&input->base, c); + + e = udev_enumerate_new(udev); + udev_enumerate_add_match_subsystem(e, "input"); + udev_enumerate_add_match_property(e, "WAYLAND_SEAT", "1"); + udev_enumerate_scan_devices(e); + udev_list_entry_foreach(entry, udev_enumerate_get_list_entry(e)) { + path = udev_list_entry_get_name(entry); + device = udev_device_new_from_syspath(udev, path); + evdev_input_device_create(input, c->wl_display, + udev_device_get_devnode(device)); + } + udev_enumerate_unref(e); + + c->input_device = &input->base.input_device; +} diff --git a/compositor/shell.c b/compositor/shell.c new file mode 100644 index 00000000..d50a3d69 --- /dev/null +++ b/compositor/shell.c @@ -0,0 +1,640 @@ +/* + * Copyright © 2010 Intel Corporation + * + * Permission to use, copy, modify, distribute, and sell this software and + * its documentation for any purpose is hereby granted without fee, provided + * that the above copyright notice appear in all copies and that both that + * copyright notice and this permission notice appear in supporting + * documentation, and that the name of the copyright holders not be used in + * advertising or publicity pertaining to distribution of the software + * without specific, written prior permission. The copyright holders make + * no representations about the suitability of this software for any + * purpose. It is provided "as is" without express or implied warranty. + * + * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS + * SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS, IN NO EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY + * SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER + * RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF + * CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN + * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include +#include +#include + +#include "wayland-server.h" +#include "compositor.h" + +struct wlsc_move_grab { + struct wl_grab grab; + int32_t dx, dy; +}; + +static void +move_grab_motion(struct wl_grab *grab, + uint32_t time, int32_t x, int32_t y) +{ + struct wlsc_move_grab *move = (struct wlsc_move_grab *) grab; + struct wlsc_surface *es = + (struct wlsc_surface *) grab->input_device->pointer_focus; + + es->x = x + move->dx; + es->y = y + move->dy; + wlsc_surface_update_matrix(es); +} + +static void +move_grab_button(struct wl_grab *grab, + uint32_t time, int32_t button, int32_t state) +{ +} + +static void +move_grab_end(struct wl_grab *grab, uint32_t time) +{ + free(grab); +} + +static const struct wl_grab_interface move_grab_interface = { + move_grab_motion, + move_grab_button, + move_grab_end +}; + +void +shell_move(struct wl_client *client, struct wl_shell *shell, + struct wl_surface *surface, + struct wl_input_device *device, uint32_t time) +{ + struct wlsc_input_device *wd = (struct wlsc_input_device *) device; + struct wlsc_surface *es = (struct wlsc_surface *) surface; + struct wlsc_move_grab *move; + + move = malloc(sizeof *move); + if (!move) { + wl_client_post_no_memory(client); + return; + } + + move->grab.interface = &move_grab_interface; + move->dx = es->x - wd->input_device.grab_x; + move->dy = es->y - wd->input_device.grab_y; + + if (wl_input_device_update_grab(&wd->input_device, + &move->grab, surface, time) < 0) + return; + + wlsc_input_device_set_pointer_image(wd, WLSC_POINTER_DRAGGING); +} + +struct wlsc_resize_grab { + struct wl_grab grab; + uint32_t edges; + int32_t dx, dy, width, height; +}; + +static void +resize_grab_motion(struct wl_grab *grab, + uint32_t time, int32_t x, int32_t y) +{ + struct wlsc_resize_grab *resize = (struct wlsc_resize_grab *) grab; + struct wl_input_device *device = grab->input_device; + struct wlsc_compositor *ec = + (struct wlsc_compositor *) device->compositor; + struct wl_surface *surface = device->pointer_focus; + int32_t width, height; + + if (resize->edges & WL_GRAB_RESIZE_LEFT) { + width = device->grab_x - x + resize->width; + } else if (resize->edges & WL_GRAB_RESIZE_RIGHT) { + width = x - device->grab_x + resize->width; + } else { + width = resize->width; + } + + if (resize->edges & WL_GRAB_RESIZE_TOP) { + height = device->grab_y - y + resize->height; + } else if (resize->edges & WL_GRAB_RESIZE_BOTTOM) { + height = y - device->grab_y + resize->height; + } else { + height = resize->height; + } + + wl_client_post_event(surface->client, &ec->shell.object, + WL_SHELL_CONFIGURE, time, resize->edges, + surface, width, height); +} + +static void +resize_grab_button(struct wl_grab *grab, + uint32_t time, int32_t button, int32_t state) +{ +} + +static void +resize_grab_end(struct wl_grab *grab, uint32_t time) +{ + free(grab); +} + +static const struct wl_grab_interface resize_grab_interface = { + resize_grab_motion, + resize_grab_button, + resize_grab_end +}; + +void +shell_resize(struct wl_client *client, struct wl_shell *shell, + struct wl_surface *surface, + struct wl_input_device *device, uint32_t time, uint32_t edges) +{ + struct wlsc_input_device *wd = (struct wlsc_input_device *) device; + struct wlsc_resize_grab *resize; + enum wlsc_pointer_type pointer = WLSC_POINTER_LEFT_PTR; + struct wlsc_surface *es = (struct wlsc_surface *) surface; + + resize = malloc(sizeof *resize); + if (!resize) { + wl_client_post_no_memory(client); + return; + } + + resize->grab.interface = &resize_grab_interface; + resize->edges = edges; + resize->dx = es->x - wd->input_device.grab_x; + resize->dy = es->y - wd->input_device.grab_y; + resize->width = es->width; + resize->height = es->height; + + if (edges == 0 || edges > 15 || + (edges & 3) == 3 || (edges & 12) == 12) + return; + + switch (edges) { + case WL_GRAB_RESIZE_TOP: + pointer = WLSC_POINTER_TOP; + break; + case WL_GRAB_RESIZE_BOTTOM: + pointer = WLSC_POINTER_BOTTOM; + break; + case WL_GRAB_RESIZE_LEFT: + pointer = WLSC_POINTER_LEFT; + break; + case WL_GRAB_RESIZE_TOP_LEFT: + pointer = WLSC_POINTER_TOP_LEFT; + break; + case WL_GRAB_RESIZE_BOTTOM_LEFT: + pointer = WLSC_POINTER_BOTTOM_LEFT; + break; + case WL_GRAB_RESIZE_RIGHT: + pointer = WLSC_POINTER_RIGHT; + break; + case WL_GRAB_RESIZE_TOP_RIGHT: + pointer = WLSC_POINTER_TOP_RIGHT; + break; + case WL_GRAB_RESIZE_BOTTOM_RIGHT: + pointer = WLSC_POINTER_BOTTOM_RIGHT; + break; + } + + if (wl_input_device_update_grab(&wd->input_device, + &resize->grab, surface, time) < 0) + return; + + wlsc_input_device_set_pointer_image(wd, pointer); +} + +static void +destroy_drag(struct wl_resource *resource, struct wl_client *client) +{ + struct wl_drag *drag = + container_of(resource, struct wl_drag, resource); + + wl_list_remove(&drag->drag_focus_listener.link); + if (drag->grab.input_device) + wl_input_device_end_grab(drag->grab.input_device, get_time()); + + free(drag); +} + + +static void +wl_drag_set_pointer_focus(struct wl_drag *drag, + struct wl_surface *surface, uint32_t time, + int32_t x, int32_t y, int32_t sx, int32_t sy) +{ + char **p, **end; + + if (drag->drag_focus == surface) + return; + + if (drag->drag_focus && + (!surface || drag->drag_focus->client != surface->client)) + wl_client_post_event(drag->drag_focus->client, + &drag->drag_offer.object, + WL_DRAG_OFFER_POINTER_FOCUS, + time, NULL, 0, 0, 0, 0); + + if (surface && + (!drag->drag_focus || + drag->drag_focus->client != surface->client)) { + wl_client_post_global(surface->client, + &drag->drag_offer.object); + + end = drag->types.data + drag->types.size; + for (p = drag->types.data; p < end; p++) + wl_client_post_event(surface->client, + &drag->drag_offer.object, + WL_DRAG_OFFER_OFFER, *p); + } + + if (surface) { + wl_client_post_event(surface->client, + &drag->drag_offer.object, + WL_DRAG_OFFER_POINTER_FOCUS, + time, surface, + x, y, sx, sy); + + } + + drag->drag_focus = surface; + drag->pointer_focus_time = time; + drag->target = NULL; + + wl_list_remove(&drag->drag_focus_listener.link); + if (surface) + wl_list_insert(surface->destroy_listener_list.prev, + &drag->drag_focus_listener.link); +} + +static void +drag_offer_accept(struct wl_client *client, + struct wl_drag_offer *offer, uint32_t time, const char *type) +{ + struct wl_drag *drag = container_of(offer, struct wl_drag, drag_offer); + char **p, **end; + + /* If the client responds to drag pointer_focus or motion + * events after the pointer has left the surface, we just + * discard the accept requests. The drag source just won't + * get the corresponding 'target' events and eventually the + * next surface/root will start sending events. */ + if (time < drag->pointer_focus_time) + return; + + drag->target = client; + drag->type = NULL; + end = drag->types.data + drag->types.size; + for (p = drag->types.data; p < end; p++) + if (type && strcmp(*p, type) == 0) + drag->type = *p; + + wl_client_post_event(drag->source->client, &drag->resource.object, + WL_DRAG_TARGET, drag->type); +} + +static void +drag_offer_receive(struct wl_client *client, + struct wl_drag_offer *offer, int fd) +{ + struct wl_drag *drag = container_of(offer, struct wl_drag, drag_offer); + + wl_client_post_event(drag->source->client, &drag->resource.object, + WL_DRAG_FINISH, fd); + close(fd); +} + +static void +drag_offer_reject(struct wl_client *client, struct wl_drag_offer *offer) +{ + struct wl_drag *drag = container_of(offer, struct wl_drag, drag_offer); + + wl_client_post_event(drag->source->client, &drag->resource.object, + WL_DRAG_REJECT); +} + +static const struct wl_drag_offer_interface drag_offer_interface = { + drag_offer_accept, + drag_offer_receive, + drag_offer_reject +}; + +static void +drag_offer(struct wl_client *client, struct wl_drag *drag, const char *type) +{ + char **p; + + p = wl_array_add(&drag->types, sizeof *p); + if (p) + *p = strdup(type); + if (!p || !*p) + wl_client_post_no_memory(client); +} + +static void +drag_grab_motion(struct wl_grab *grab, + uint32_t time, int32_t x, int32_t y) +{ + struct wl_drag *drag = container_of(grab, struct wl_drag, grab); + struct wlsc_surface *es; + int32_t sx, sy; + + es = pick_surface(grab->input_device, &sx, &sy); + wl_drag_set_pointer_focus(drag, &es->surface, time, x, y, sx, sy); + if (es) + wl_client_post_event(es->surface.client, + &drag->drag_offer.object, + WL_DRAG_OFFER_MOTION, + time, x, y, sx, sy); +} + +static void +drag_grab_button(struct wl_grab *grab, + uint32_t time, int32_t button, int32_t state) +{ +} + +static void +drag_grab_end(struct wl_grab *grab, uint32_t time) +{ + struct wl_drag *drag = container_of(grab, struct wl_drag, grab); + + if (drag->target) + wl_client_post_event(drag->target, + &drag->drag_offer.object, + WL_DRAG_OFFER_DROP); + + wl_drag_set_pointer_focus(drag, NULL, time, 0, 0, 0, 0); +} + +static const struct wl_grab_interface drag_grab_interface = { + drag_grab_motion, + drag_grab_button, + drag_grab_end +}; + +static void +drag_activate(struct wl_client *client, + struct wl_drag *drag, + struct wl_surface *surface, + struct wl_input_device *device, uint32_t time) +{ + struct wl_display *display = wl_client_get_display (client); + struct wlsc_surface *target; + int32_t sx, sy; + + if (wl_input_device_update_grab(device, + &drag->grab, surface, time) < 0) + return; + + drag->grab.interface = &drag_grab_interface; + + drag->source = surface; + + drag->drag_offer.object.interface = &wl_drag_offer_interface; + drag->drag_offer.object.implementation = + (void (**)(void)) &drag_offer_interface; + + wl_display_add_object(display, &drag->drag_offer.object); + + target = pick_surface(device, &sx, &sy); + wl_drag_set_pointer_focus(drag, &target->surface, time, + device->x, device->y, sx, sy); +} + +static void +drag_destroy(struct wl_client *client, struct wl_drag *drag) +{ + wl_resource_destroy(&drag->resource, client); +} + +static const struct wl_drag_interface drag_interface = { + drag_offer, + drag_activate, + drag_destroy, +}; + +static void +drag_handle_surface_destroy(struct wl_listener *listener, + struct wl_surface *surface, uint32_t time) +{ + struct wl_drag *drag = + container_of(listener, struct wl_drag, drag_focus_listener); + + if (drag->drag_focus == surface) + wl_drag_set_pointer_focus(drag, NULL, time, 0, 0, 0, 0); +} + +static void +shell_create_drag(struct wl_client *client, + struct wl_shell *shell, uint32_t id) +{ + struct wl_drag *drag; + + drag = malloc(sizeof *drag); + if (drag == NULL) { + wl_client_post_no_memory(client); + return; + } + + memset(drag, 0, sizeof *drag); + drag->resource.object.id = id; + drag->resource.object.interface = &wl_drag_interface; + drag->resource.object.implementation = + (void (**)(void)) &drag_interface; + + drag->resource.destroy = destroy_drag; + + drag->drag_focus_listener.func = drag_handle_surface_destroy; + wl_list_init(&drag->drag_focus_listener.link); + + wl_client_add_resource(client, &drag->resource); +} + +void +wlsc_selection_set_focus(struct wl_selection *selection, + struct wl_surface *surface, uint32_t time) +{ + char **p, **end; + + if (selection->selection_focus == surface) + return; + + if (selection->selection_focus != NULL) + wl_client_post_event(selection->selection_focus->client, + &selection->selection_offer.object, + WL_SELECTION_OFFER_KEYBOARD_FOCUS, + NULL); + + if (surface) { + wl_client_post_global(surface->client, + &selection->selection_offer.object); + + end = selection->types.data + selection->types.size; + for (p = selection->types.data; p < end; p++) + wl_client_post_event(surface->client, + &selection->selection_offer.object, + WL_SELECTION_OFFER_OFFER, *p); + + wl_list_remove(&selection->selection_focus_listener.link); + wl_list_insert(surface->destroy_listener_list.prev, + &selection->selection_focus_listener.link); + + wl_client_post_event(surface->client, + &selection->selection_offer.object, + WL_SELECTION_OFFER_KEYBOARD_FOCUS, + selection->input_device); + } + + selection->selection_focus = surface; + + wl_list_remove(&selection->selection_focus_listener.link); + if (surface) + wl_list_insert(surface->destroy_listener_list.prev, + &selection->selection_focus_listener.link); +} + +static void +selection_offer_receive(struct wl_client *client, + struct wl_selection_offer *offer, + const char *mime_type, int fd) +{ + struct wl_selection *selection = + container_of(offer, struct wl_selection, selection_offer); + + wl_client_post_event(selection->client, + &selection->resource.object, + WL_SELECTION_SEND, mime_type, fd); + close(fd); +} + +static const struct wl_selection_offer_interface selection_offer_interface = { + selection_offer_receive +}; + +static void +selection_offer(struct wl_client *client, + struct wl_selection *selection, const char *type) +{ + char **p; + + p = wl_array_add(&selection->types, sizeof *p); + if (p) + *p = strdup(type); + if (!p || !*p) + wl_client_post_no_memory(client); +} + +static void +selection_activate(struct wl_client *client, + struct wl_selection *selection, + struct wl_input_device *device, uint32_t time) +{ + struct wlsc_input_device *wd = (struct wlsc_input_device *) device; + struct wl_display *display = wl_client_get_display (client); + + selection->input_device = device; + + selection->selection_offer.object.interface = + &wl_selection_offer_interface; + selection->selection_offer.object.implementation = + (void (**)(void)) &selection_offer_interface; + + wl_display_add_object(display, &selection->selection_offer.object); + + if (wd->selection) { + wl_client_post_event(wd->selection->client, + &wd->selection->resource.object, + WL_SELECTION_CANCELLED); + } + wd->selection = selection; + + wlsc_selection_set_focus(selection, device->keyboard_focus, time); +} + +static void +selection_destroy(struct wl_client *client, struct wl_selection *selection) +{ + wl_resource_destroy(&selection->resource, client); +} + +static const struct wl_selection_interface selection_interface = { + selection_offer, + selection_activate, + selection_destroy +}; + +static void +destroy_selection(struct wl_resource *resource, struct wl_client *client) +{ + struct wl_selection *selection = + container_of(resource, struct wl_selection, resource); + struct wlsc_input_device *wd = + (struct wlsc_input_device *) selection->input_device; + + if (wd && wd->selection == selection) { + wd->selection = NULL; + wlsc_selection_set_focus(selection, NULL, get_time()); + } + + wl_list_remove(&selection->selection_focus_listener.link); + free(selection); +} + +static void +selection_handle_surface_destroy(struct wl_listener *listener, + struct wl_surface *surface, uint32_t time) +{ +} + +static void +shell_create_selection(struct wl_client *client, + struct wl_shell *shell, uint32_t id) +{ + struct wl_selection *selection; + + selection = malloc(sizeof *selection); + if (selection == NULL) { + wl_client_post_no_memory(client); + return; + } + + memset(selection, 0, sizeof *selection); + selection->resource.object.id = id; + selection->resource.object.interface = &wl_selection_interface; + selection->resource.object.implementation = + (void (**)(void)) &selection_interface; + + selection->client = client; + selection->resource.destroy = destroy_selection; + selection->selection_focus = NULL; + + selection->selection_focus_listener.func = + selection_handle_surface_destroy; + wl_list_init(&selection->selection_focus_listener.link); + + wl_client_add_resource(client, &selection->resource); +} + +const static struct wl_shell_interface shell_interface = { + shell_move, + shell_resize, + shell_create_drag, + shell_create_selection +}; + +int +wlsc_shell_init(struct wlsc_compositor *ec) +{ + struct wl_shell *shell = &ec->shell; + + shell->object.interface = &wl_shell_interface; + shell->object.implementation = (void (**)(void)) &shell_interface; + wl_display_add_object(ec->wl_display, &shell->object); + if (wl_display_add_global(ec->wl_display, &shell->object, NULL)) + return -1; + + return 0; +} diff --git a/compositor/shm.c b/compositor/shm.c index 52585f82..6b96a5b6 100644 --- a/compositor/shm.c +++ b/compositor/shm.c @@ -24,6 +24,12 @@ #include "compositor.h" +struct wlsc_shm_buffer { + struct wl_buffer buffer; + int32_t stride; + void *data; +}; + static void destroy_buffer(struct wl_resource *resource, struct wl_client *client) { @@ -57,8 +63,7 @@ shm_buffer_attach(struct wl_buffer *buffer_base, struct wl_surface *surface) * overwrite it.*/ glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 0, 0, 0, GL_BGRA_EXT, GL_UNSIGNED_BYTE, NULL); - - glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, + glTexImage2D(GL_TEXTURE_2D, 0, GL_BGRA_EXT, buffer->buffer.width, buffer->buffer.height, 0, GL_BGRA_EXT, GL_UNSIGNED_BYTE, buffer->data); es->visual = buffer->buffer.visual; diff --git a/compositor/tty.c b/compositor/tty.c new file mode 100644 index 00000000..70c319da --- /dev/null +++ b/compositor/tty.c @@ -0,0 +1,163 @@ +/* + * Copyright © 2010 Intel Corporation + * + * Permission to use, copy, modify, distribute, and sell this software and + * its documentation for any purpose is hereby granted without fee, provided + * that the above copyright notice appear in all copies and that both that + * copyright notice and this permission notice appear in supporting + * documentation, and that the name of the copyright holders not be used in + * advertising or publicity pertaining to distribution of the software + * without specific, written prior permission. The copyright holders make + * no representations about the suitability of this software for any + * purpose. It is provided "as is" without express or implied warranty. + * + * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS + * SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS, IN NO EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY + * SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER + * RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF + * CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN + * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "compositor.h" + +struct tty { + struct wlsc_compositor *compositor; + int fd; + struct termios terminal_attributes; + + struct wl_event_source *input_source; + struct wl_event_source *enter_vt_source; + struct wl_event_source *leave_vt_source; +}; + +static void on_enter_vt(int signal_number, void *data) +{ + struct tty *tty = data; + int ret; + + fprintf(stderr, "enter vt\n"); + + ioctl(tty->fd, VT_RELDISP, VT_ACKACQ); + ret = ioctl(tty->fd, KDSETMODE, KD_GRAPHICS); + if (ret) + fprintf(stderr, "failed to set KD_GRAPHICS mode on console: %m\n"); + tty->compositor->focus = 1; +} + +static void on_leave_vt(int signal_number, void *data) +{ + struct tty *tty = data; + int ret; + + ioctl (tty->fd, VT_RELDISP, 1); + ret = ioctl(tty->fd, KDSETMODE, KD_TEXT); + if (ret) + fprintf(stderr, + "failed to set KD_TEXT mode on console: %m\n"); + + tty->compositor->focus = 0; +} + +static void +on_tty_input(int fd, uint32_t mask, void *data) +{ + struct tty *tty = data; + + /* Ignore input to tty. We get keyboard events from evdev + */ + tcflush(tty->fd, TCIFLUSH); +} + +struct tty * +tty_create(struct wlsc_compositor *compositor) +{ + struct termios raw_attributes; + struct vt_mode mode = { 0 }; + int ret; + struct tty *tty; + struct wl_event_loop *loop; + + tty = malloc(sizeof *tty); + if (tty == NULL) + return NULL; + + memset(tty, 0, sizeof *tty); + tty->compositor = compositor; + tty->fd = open("/dev/tty0", O_RDWR | O_NOCTTY); + if (tty->fd <= 0) { + fprintf(stderr, "failed to open active tty: %m\n"); + return NULL; + } + + if (tcgetattr(tty->fd, &tty->terminal_attributes) < 0) { + fprintf(stderr, "could not get terminal attributes: %m\n"); + return NULL; + } + + /* Ignore control characters and disable echo */ + raw_attributes = tty->terminal_attributes; + cfmakeraw(&raw_attributes); + + /* Fix up line endings to be normal (cfmakeraw hoses them) */ + raw_attributes.c_oflag |= OPOST | OCRNL; + + if (tcsetattr(tty->fd, TCSANOW, &raw_attributes) < 0) + fprintf(stderr, "could not put terminal into raw mode: %m\n"); + + loop = wl_display_get_event_loop(compositor->wl_display); + tty->input_source = + wl_event_loop_add_fd(loop, tty->fd, + WL_EVENT_READABLE, on_tty_input, tty); + + ret = ioctl(tty->fd, KDSETMODE, KD_GRAPHICS); + if (ret) { + fprintf(stderr, "failed to set KD_GRAPHICS mode on tty: %m\n"); + return NULL; + } + + tty->compositor->focus = 1; + mode.mode = VT_PROCESS; + mode.relsig = SIGUSR1; + mode.acqsig = SIGUSR2; + if (!ioctl(tty->fd, VT_SETMODE, &mode) < 0) { + fprintf(stderr, "failed to take control of vt handling\n"); + return NULL; + } + + tty->leave_vt_source = + wl_event_loop_add_signal(loop, SIGUSR1, on_leave_vt, tty); + tty->enter_vt_source = + wl_event_loop_add_signal(loop, SIGUSR2, on_enter_vt, tty); + + return tty; +} + +void +tty_destroy(struct tty *tty) +{ + int ret; + + ret = ioctl(tty->fd, KDSETMODE, KD_TEXT); + if (ret) + fprintf(stderr, + "failed to set KD_GRAPHICS mode on tty: %m\n"); + + if (tcsetattr(tty->fd, TCSANOW, &tty->terminal_attributes) < 0) + fprintf(stderr, + "could not restore terminal to canonical mode\n"); + + free(tty); +} diff --git a/configure.ac b/configure.ac index 31654a6d..bcc1e834 100644 --- a/configure.ac +++ b/configure.ac @@ -24,15 +24,41 @@ PKG_CHECK_MODULES(FFI, [libffi]) PKG_CHECK_MODULES(COMPOSITOR, [egl glesv2 gdk-pixbuf-2.0 libudev >= 136 libdrm >= 2.4.17] xcb-dri2 xcb-xfixes) +PKG_CHECK_MODULES(GLES2, [egl glesv2 libdrm]) PKG_CHECK_MODULES(CLIENT, [egl gl cairo gdk-pixbuf-2.0 glib-2.0 gobject-2.0 xkbcommon libdrm]) PKG_CHECK_MODULES(POPPLER, [poppler-glib gdk-2.0], [have_poppler=yes], [have_poppler=no]) AM_CONDITIONAL(HAVE_POPPLER, test "x$have_poppler" = "xyes") -PKG_CHECK_MODULES(CAIRO_GL, [cairo-gl], - [have_cairo_gl=yes], [have_cairo_gl=no]) -AS_IF([test "x$have_cairo_gl" = "xyes"], - [AC_DEFINE([HAVE_CAIRO_GL], [1], [Have cairo-gl])]) + +AC_ARG_ENABLE(x11-compositor, [ --enable-x11-compositor],, + enable_x11_compositor=yes) +AM_CONDITIONAL(ENABLE_X11_COMPOSITOR, test x$enable_x11_compositor == xyes) +if test x$enable_x11_compositor == xyes; then + AC_DEFINE([BUILD_X11_COMPOSITOR], [1], [Build the X11 compositor]) +fi + + +AC_ARG_ENABLE(drm-compositor, [ --enable-drm-compositor]) +AM_CONDITIONAL(ENABLE_DRM_COMPOSITOR, test x$enable_drm_compositor == xyes) +if test x$enable_drm_compositor == xyes; then + AC_DEFINE([BUILD_DRM_COMPOSITOR], [1], [Build the DRM compositor]) +fi + + +AC_ARG_ENABLE(wayland-compositor, [ --enable-wayland-compositor]) +AM_CONDITIONAL(ENABLE_WAYLAND_COMPOSITOR, + test x$enable_wayland_compositor == xyes) +if test x$enable_wayland_compositor == xyes; then + AC_DEFINE([BUILD_WAYLAND_COMPOSITOR], [1], + [Build the Wayland (nested) compositor]) +fi + + +PKG_CHECK_MODULES(CAIRO_EGL, [cairo-egl], + [have_cairo_egl=yes], [have_cairo_egl=no]) +AS_IF([test "x$have_cairo_egl" = "xyes"], + [AC_DEFINE([HAVE_CAIRO_EGL], [1], [Have cairo-egl])]) if test $CC = gcc; then GCC_CFLAGS="-Wall -g -Wstrict-prototypes -Wmissing-prototypes -fvisibility=hidden" diff --git a/protocol/wayland.xml b/protocol/wayland.xml index 8799a64e..75ccb5bd 100644 --- a/protocol/wayland.xml +++ b/protocol/wayland.xml @@ -164,6 +164,10 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +