From 216a204c7acc2c939a15a3753c453b5a95c5b9d3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kristian=20H=C3=B8gsberg?= Date: Mon, 11 Apr 2011 14:15:50 -0400 Subject: [PATCH] meego compositor fun --- clients/Makefile.am | 15 ++- clients/meego-app-switcher.c | 187 +++++++++++++++++++++++++++++ compositor/Makefile.am | 8 +- compositor/compositor.c | 224 +++++++++++++++++++++++++++++------ compositor/compositor.h | 50 +++++++- compositor/meego-tablet-shell.c | 250 +++++++++++++++++++++++++++++++++++++++ compositor/meego-tablet-shell.h | 29 +++++ protocol/meego-tablet.xml | 9 ++ 8 files changed, 728 insertions(+), 44 deletions(-) create mode 100644 clients/meego-app-switcher.c create mode 100644 compositor/meego-tablet-shell.c create mode 100644 compositor/meego-tablet-shell.h create mode 100644 protocol/meego-tablet.xml diff --git a/clients/Makefile.am b/clients/Makefile.am index ee61efd..f5e26c5 100644 --- a/clients/Makefile.am +++ b/clients/Makefile.am @@ -9,7 +9,9 @@ noinst_PROGRAMS = \ smoke \ resizor \ simple-client \ - eventdemo + eventdemo \ + meego-app-switcher + noinst_LIBRARIES = libtoytoolkit.a @@ -62,9 +64,18 @@ simple_client_LDADD = $(SIMPLE_CLIENT_LIBS) -lm eventdemo_SOURCES = eventdemo.c eventdemo_LDADD = $(toolkit_libs) +meego_app_switcher_SOURCES = \ + meego-app-switcher.c \ + meego-tablet-protocol.c \ + meego-tablet-client-protocol.h + +meego_app_switcher_LDADD = $(toolkit_libs) + BUILT_SOURCES = \ screenshooter-client-protocol.h \ - screenshooter-protocol.c + screenshooter-protocol.c \ + meego-tablet-protocol.c \ + meego-tablet-client-protocol.h CLEANFILES = $(BUILT_SOURCES) diff --git a/clients/meego-app-switcher.c b/clients/meego-app-switcher.c new file mode 100644 index 0000000..d5fcc14 --- /dev/null +++ b/clients/meego-app-switcher.c @@ -0,0 +1,187 @@ +/* + * 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 "wayland-util.h" +#include "wayland-client.h" +#include "wayland-glib.h" + +#include "window.h" +#include "meego-tablet-client-protocol.h" + +#include + +static struct wl_app_switcher *app_switcher; + +struct switcher { + struct display *display; + struct window *window; + struct window *menu; + int32_t width, height; +}; + +static void +rounded_rect(cairo_t *cr, int x0, int y0, int x1, int y1, int radius) +{ + cairo_move_to(cr, x0, y0 + radius); + cairo_arc(cr, x0 + radius, y0 + radius, radius, M_PI, 3 * M_PI / 2); + cairo_line_to(cr, x1 - radius, y0); + cairo_arc(cr, x1 - radius, y0 + radius, radius, 3 * M_PI / 2, 2 * M_PI); + cairo_line_to(cr, x1, y1 - radius); + cairo_arc(cr, x1 - radius, y1 - radius, radius, 0, M_PI / 2); + cairo_line_to(cr, x0 + radius, y1); + cairo_arc(cr, x0 + radius, y1 - radius, radius, M_PI / 2, M_PI); + cairo_close_path(cr); +} + +static void +switcher_draw(struct switcher *switcher) +{ + cairo_surface_t *surface; + cairo_t *cr; + struct rectangle allocation; + struct wl_surface *ws; + int r = 5; + + window_draw(switcher->window); + + window_get_child_allocation(switcher->window, &allocation); + + surface = window_get_surface(switcher->window); + + cr = cairo_create(surface); + cairo_set_operator(cr, CAIRO_OPERATOR_SOURCE); + cairo_rectangle(cr, + allocation.x, + allocation.y, + allocation.width, + allocation.height); + cairo_set_source_rgba(cr, 0, 0, 0, 0.0); + cairo_fill(cr); + + rounded_rect(cr, r, r, allocation.width - r, allocation.height - r, r); + cairo_set_operator(cr, CAIRO_OPERATOR_SOURCE); + cairo_set_source_rgba(cr, 1.0, 1.0, 0.0, 1.0); + cairo_fill(cr); + cairo_destroy(cr); + + cairo_surface_destroy(surface); + + window_flush(switcher->window); + + /* FIXME: Should we do app_swithcer.create_surface instead and + * then just surface.map_toplevel()? */ + ws = window_get_wl_surface(switcher->window); + wl_app_switcher_map_switcher(app_switcher, ws); +} + +static void +key_handler(struct window *window, struct input *input, uint32_t time, + uint32_t key, uint32_t sym, uint32_t state, void *data) +{ + if (state == 0) + return; + + switch (sym) { + case XK_Escape: + exit(0); + break; + default: + break; + } +} + +static void +redraw_handler(struct window *window, void *data) +{ + struct switcher *switcher = data; + + switcher_draw(switcher); +} + +static struct switcher * +switcher_create(struct display *display) +{ + struct switcher *switcher; + + switcher = malloc(sizeof *switcher); + if (switcher == NULL) + return switcher; + memset(switcher, 0, sizeof *switcher); + + switcher->window = window_create(display, 200, 200); + window_set_title(switcher->window, "Switcher"); + switcher->display = display; + + window_set_key_handler(switcher->window, key_handler); + window_set_user_data(switcher->window, switcher); + window_set_redraw_handler(switcher->window, redraw_handler); + window_set_decoration(switcher->window, 0); + + switcher->width = 200; + switcher->height = 200; + + window_set_child_size(switcher->window, + switcher->width, switcher->height); + + switcher_draw(switcher); + + return switcher; +} + +static void +global_handler(struct display *display, + const char *interface, uint32_t id, uint32_t version) +{ + if (strcmp(interface, "app_switcher") != 0) + return; + + app_switcher = + wl_app_switcher_create(display_get_display(display), id); + + fprintf(stderr, "got app switcher, id %d, proxy %p\n", + id, app_switcher); +} + +int +main(int argc, char *argv[]) +{ + struct display *d; + + d = display_create(&argc, &argv, NULL, global_handler); + if (d == NULL) { + fprintf(stderr, "failed to create display: %m\n"); + return -1; + } + + switcher_create (d); + + display_run(d); + + return 0; +} diff --git a/compositor/Makefile.am b/compositor/Makefile.am index e90830a..4ff4952 100644 --- a/compositor/Makefile.am +++ b/compositor/Makefile.am @@ -31,6 +31,10 @@ compositor_SOURCES = \ screenshooter-protocol.c \ screenshooter-server-protocol.h \ shm.c \ + meego-tablet-shell.c \ + meego-tablet-shell.h \ + meego-tablet-protocol.c \ + meego-tablet-server-protocol.h \ $(drm_compositor_sources) \ $(x11_compositor_sources) \ $(wayland_compositor_sources) @@ -42,7 +46,9 @@ dist_udevrulesd_DATA = \ BUILT_SOURCES = \ screenshooter-server-protocol.h \ - screenshooter-protocol.c + screenshooter-protocol.c \ + meego-tablet-protocol.c \ + meego-tablet-server-protocol.h CLEANFILES = $(BUILT_SOURCES) diff --git a/compositor/compositor.c b/compositor/compositor.c index f2c0a05..6d103dd 100644 --- a/compositor/compositor.c +++ b/compositor/compositor.c @@ -35,6 +35,7 @@ #include "wayland-server.h" #include "compositor.h" +#include "meego-tablet-shell.h" struct wlsc_switcher { struct wlsc_compositor *compositor; @@ -126,6 +127,46 @@ wlsc_matrix_transform(struct wlsc_matrix *matrix, struct wlsc_vector *v) *v = t; } +void +wlsc_tweener_init(struct wlsc_tweener *tweener, double value) +{ + tweener->k = 3.0; + tweener->current = value; + tweener->target = value; + tweener->previous = value; +} + +void +wlsc_tweener_update(struct wlsc_tweener *tweener, uint32_t msec) +{ + double force, current; + + current = tweener->current; + force = tweener->k * (tweener->target - current) / 10.0 + + (tweener->previous - current); + + tweener->current = + current + (current - tweener->previous) + force; + tweener->previous = current; + + if (tweener->current >= 1.0) { + tweener->current = 1.0; + tweener->previous = 1.0; + } + + if (tweener->current <= 0.0) { + tweener->current = 0.0; + tweener->previous = 0.0; + } +} + +int +wlsc_tweener_done(struct wlsc_tweener *tweener) +{ + return fabs(tweener->previous - tweener->target) < 0.001 && + fabs(tweener->current - tweener->target) < 0.001; +} + static struct wlsc_surface * wlsc_surface_create(struct wlsc_compositor *compositor, int32_t x, int32_t y, int32_t width, int32_t height) @@ -479,11 +520,52 @@ wlsc_surface_update_matrix(struct wlsc_surface *es) } void -wlsc_compositor_finish_frame(struct wlsc_compositor *compositor, int msecs) +wlsc_compositor_damage_all(struct wlsc_compositor *compositor) +{ + struct wlsc_output *output; + + wl_list_for_each(output, &compositor->output_list, link) + pixman_region32_union_rect(&compositor->damage_region, + &compositor->damage_region, + output->x, output->y, + output->width, output->height); + wlsc_compositor_schedule_repaint(compositor); +} + +void +wlsc_compositor_finish_frame(struct wlsc_compositor *compositor, + uint32_t msecs) { wl_display_post_frame(compositor->wl_display, msecs); wl_event_source_timer_update(compositor->timer_source, 5); compositor->repaint_on_timeout = 1; + + app_switcher_update(compositor->meego_tablet_shell, msecs); + + wlsc_tweener_update(&compositor->tint, msecs); + if (!wlsc_tweener_done(&compositor->tint)) + wlsc_compositor_damage_all(compositor); +} + +static void +tint_output(struct wlsc_output *output, + GLfloat tint, pixman_region32_t *region) +{ + struct wlsc_compositor *compositor = output->compositor; + struct wlsc_surface surface; + GLfloat color[4] = { 0.0, 0.0, 0.0, tint }; + + surface.compositor = compositor; + surface.x = output->x; + surface.y = output->y; + surface.width = output->width; + surface.height = output->height; + surface.visual = &compositor->compositor.premultiplied_argb_visual; + glUseProgram(compositor->solid_shader.program); + glUniformMatrix4fv(compositor->solid_shader.proj_uniform, + 1, GL_FALSE, output->matrix.d); + glUniform4fv(compositor->solid_shader.color_uniform, 1, color); + wlsc_surface_draw(&surface, output, region); } static void @@ -498,8 +580,10 @@ wlsc_output_repaint(struct wlsc_output *output) glViewport(0, 0, output->width, output->height); - glUniformMatrix4fv(ec->proj_uniform, 1, GL_FALSE, output->matrix.d); - glUniform1i(ec->tex_uniform, 0); + glUseProgram(ec->texture_shader.program); + glUniformMatrix4fv(ec->texture_shader.proj_uniform, + 1, GL_FALSE, output->matrix.d); + glUniform1i(ec->texture_shader.tex_uniform, 0); pixman_region32_init(&new_damage); pixman_region32_init(&total_damage); @@ -555,8 +639,12 @@ wlsc_output_repaint(struct wlsc_output *output) } } - if (ec->switcher) - wlsc_surface_draw(ec->switcher->current, + if (ec->tint.current > 0.001) + tint_output(output, ec->tint.current, &total_damage); + + glUseProgram(ec->texture_shader.program); + if (ec->overlay_surface) + wlsc_surface_draw(ec->overlay_surface, output, &total_damage); if (ec->focus) @@ -593,6 +681,13 @@ wlsc_compositor_schedule_repaint(struct wlsc_compositor *compositor) compositor->repaint_on_timeout = 1; } +void +wlsc_compositor_set_tint(struct wlsc_compositor *compositor, float tint) +{ + compositor->tint.target = tint; + wlsc_compositor_damage_all(compositor); +} + static void surface_destroy(struct wl_client *client, struct wl_surface *surface) @@ -933,7 +1028,7 @@ notify_motion(struct wl_input_device *device, uint32_t time, int x, int y) wlsc_surface_damage(wd->sprite); } -static void +void wlsc_surface_activate(struct wlsc_surface *surface, struct wlsc_input_device *device, uint32_t time) { @@ -1015,6 +1110,7 @@ wlsc_switcher_next(struct wlsc_switcher *switcher) if (l == &switcher->compositor->surface_list) l = switcher->compositor->surface_list.next; switcher->current = container_of(l, struct wlsc_surface, link); + switcher->compositor->overlay_surface = switcher->current; wl_list_remove(&switcher->listener.link); wl_list_insert(switcher->current->surface.destroy_listener_list.prev, &switcher->listener.link); @@ -1040,6 +1136,7 @@ wlsc_switcher_create(struct wlsc_compositor *compositor) switcher->compositor = compositor; switcher->current = container_of(compositor->surface_list.next, struct wlsc_surface, link); + switcher->compositor->overlay_surface = switcher->current; switcher->listener.func = switcher_handle_surface_destroy; wl_list_init(&switcher->listener.link); @@ -1329,7 +1426,7 @@ static const char vertex_shader[] = " v_texcoord = texcoord;\n" "}\n"; -static const char fragment_shader[] = +static const char texture_fragment_shader[] = "precision mediump float;\n" "varying vec2 v_texcoord;\n" "uniform sampler2D tex;\n" @@ -1338,53 +1435,103 @@ static const char fragment_shader[] = " gl_FragColor = texture2D(tex, v_texcoord)\n;" "}\n"; +static const char solid_fragment_shader[] = + "precision mediump float;\n" + "varying vec2 v_texcoord;\n" + "uniform vec4 color;\n" + "void main()\n" + "{\n" + " gl_FragColor = color\n;" + "}\n"; + static int -init_shaders(struct wlsc_compositor *ec) +compile_shader(GLenum type, const char *source) { - GLuint v, f, program; - const char *p; + GLuint s; char msg[512]; GLint status; - p = vertex_shader; - v = glCreateShader(GL_VERTEX_SHADER); - glShaderSource(v, 1, &p, NULL); - glCompileShader(v); - glGetShaderiv(v, GL_COMPILE_STATUS, &status); + s = glCreateShader(type); + glShaderSource(s, 1, &source, NULL); + glCompileShader(s); + glGetShaderiv(s, GL_COMPILE_STATUS, &status); if (!status) { - glGetShaderInfoLog(v, sizeof msg, NULL, msg); - fprintf(stderr, "vertex shader info: %s\n", msg); - return -1; + glGetShaderInfoLog(s, sizeof msg, NULL, msg); + fprintf(stderr, "shader info: %s\n", msg); + return GL_NONE; } - p = fragment_shader; - f = glCreateShader(GL_FRAGMENT_SHADER); - glShaderSource(f, 1, &p, NULL); - glCompileShader(f); - glGetShaderiv(f, GL_COMPILE_STATUS, &status); + return s; +} + +static int +wlsc_shader_init(struct wlsc_shader *shader, + const char *vertex_source, const char *fragment_source) +{ + char msg[512]; + GLint status; + + shader->vertex_shader = + compile_shader(GL_VERTEX_SHADER, vertex_source); + shader->fragment_shader = + compile_shader(GL_FRAGMENT_SHADER, fragment_source); + + shader->program = glCreateProgram(); + glAttachShader(shader->program, shader->vertex_shader); + glAttachShader(shader->program, shader->fragment_shader); + glBindAttribLocation(shader->program, 0, "position"); + glBindAttribLocation(shader->program, 1, "texcoord"); + + glLinkProgram(shader->program); + glGetProgramiv(shader->program, GL_LINK_STATUS, &status); if (!status) { - glGetShaderInfoLog(f, sizeof msg, NULL, msg); - fprintf(stderr, "fragment shader info: %s\n", msg); + glGetProgramInfoLog(shader->program, sizeof msg, NULL, msg); + fprintf(stderr, "link info: %s\n", msg); return -1; } - program = glCreateProgram(); - glAttachShader(program, v); - glAttachShader(program, f); - glBindAttribLocation(program, 0, "position"); - glBindAttribLocation(program, 1, "texcoord"); + shader->proj_uniform = glGetUniformLocation(shader->program, "proj"); + shader->tex_uniform = glGetUniformLocation(shader->program, "tex"); + + return 0; +} + +static void +init_solid_shader(struct wlsc_shader *shader, + GLuint vertex_shader, const char *fragment_source) +{ + GLint status; + char msg[512]; + + shader->vertex_shader = vertex_shader; + shader->fragment_shader = + compile_shader(GL_FRAGMENT_SHADER, fragment_source); + + shader->program = glCreateProgram(); + glAttachShader(shader->program, shader->vertex_shader); + glAttachShader(shader->program, shader->fragment_shader); + glBindAttribLocation(shader->program, 0, "position"); + glBindAttribLocation(shader->program, 1, "texcoord"); - glLinkProgram(program); - glGetProgramiv(program, GL_LINK_STATUS, &status); + glLinkProgram(shader->program); + glGetProgramiv(shader->program, GL_LINK_STATUS, &status); if (!status) { - glGetProgramInfoLog(program, sizeof msg, NULL, msg); + glGetProgramInfoLog(shader->program, sizeof msg, NULL, msg); fprintf(stderr, "link info: %s\n", msg); - return -1; } - glUseProgram(program); - ec->proj_uniform = glGetUniformLocation(program, "proj"); - ec->tex_uniform = glGetUniformLocation(program, "tex"); + shader->proj_uniform = glGetUniformLocation(shader->program, "proj"); + shader->color_uniform = glGetUniformLocation(shader->program, "color"); +} + +static int +init_shaders(struct wlsc_compositor *ec) +{ + wlsc_shader_init(&ec->texture_shader, + vertex_shader, texture_fragment_shader); + init_solid_shader(&ec->solid_shader, + ec->texture_shader.vertex_shader, + solid_fragment_shader); return 0; } @@ -1468,6 +1615,7 @@ wlsc_compositor_init(struct wlsc_compositor *ec, struct wl_display *display) wl_list_init(&ec->input_device_list); wl_list_init(&ec->output_list); wl_list_init(&ec->binding_list); + ec->tint.k = 0.2; wlsc_compositor_add_binding(ec, KEY_BACKSPACE, MODIFIER_CTRL | MODIFIER_ALT, @@ -1565,6 +1713,8 @@ int main(int argc, char *argv[]) wl_event_loop_add_signal(loop, SIGTERM, on_term_signal, ec); wl_event_loop_add_signal(loop, SIGINT, on_term_signal, ec); + ec->meego_tablet_shell = meego_tablet_shell_create(ec); + wl_display_run(display); eglUnbindWaylandDisplayWL(ec->display, display); diff --git a/compositor/compositor.h b/compositor/compositor.h index 865e527..4fac6d6 100644 --- a/compositor/compositor.h +++ b/compositor/compositor.h @@ -79,6 +79,23 @@ struct wlsc_shm { struct wl_object object; }; +struct meego_tablet_shell; + +struct wlsc_tweener { + double k; + double current; + double target; + double previous; +}; + +struct wlsc_shader { + GLuint program; + GLuint vertex_shader, fragment_shader; + GLuint proj_uniform; + GLuint tex_uniform; + GLuint color_uniform; +}; + struct wlsc_compositor { struct wl_compositor compositor; @@ -87,10 +104,11 @@ struct wlsc_compositor { EGLContext context; EGLConfig config; GLuint fbo; - GLuint proj_uniform, tex_uniform; + struct wlsc_shader texture_shader; + struct wlsc_shader solid_shader; + struct wl_buffer **pointer_buffers; struct wl_display *wl_display; - /* We implement the shell interface. */ struct wl_shell shell; @@ -101,6 +119,8 @@ struct wlsc_compositor { struct wl_list input_device_list; struct wl_list surface_list; struct wl_list binding_list; + struct wlsc_surface *overlay_surface; + struct wlsc_tweener tint; /* Repaint state. */ struct wl_event_source *timer_source; @@ -113,6 +133,8 @@ struct wlsc_compositor { struct wlsc_switcher *switcher; uint32_t focus; + struct meego_tablet_shell *meego_tablet_shell; + void (*destroy)(struct wlsc_compositor *ec); int (*authenticate)(struct wlsc_compositor *c, uint32_t id); void (*present)(struct wlsc_compositor *c); @@ -138,7 +160,9 @@ enum wlsc_surface_map_type { WLSC_SURFACE_MAP_UNMAPPED, WLSC_SURFACE_MAP_TOPLEVEL, WLSC_SURFACE_MAP_TRANSIENT, - WLSC_SURFACE_MAP_FULLSCREEN + WLSC_SURFACE_MAP_FULLSCREEN, + + WLSC_SURFACE_MAP_SWITCHER }; struct wlsc_surface { @@ -157,6 +181,15 @@ struct wlsc_surface { }; void +app_switcher_update(struct meego_tablet_shell *shell, uint32_t msecs); +void +wlsc_tweener_init(struct wlsc_tweener *tweener, double value); +void +wlsc_tweener_update(struct wlsc_tweener *tweener, uint32_t msec); +int +wlsc_tweener_done(struct wlsc_tweener *tweener); + +void wlsc_surface_update_matrix(struct wlsc_surface *es); void @@ -181,9 +214,18 @@ notify_keyboard_focus(struct wl_input_device *device, struct wl_array *keys); void -wlsc_compositor_finish_frame(struct wlsc_compositor *compositor, int msecs); +wlsc_compositor_finish_frame(struct wlsc_compositor *compositor, + uint32_t msecs); void wlsc_compositor_schedule_repaint(struct wlsc_compositor *compositor); +void +wlsc_compositor_set_tint(struct wlsc_compositor *compositor, float tint); +void +wlsc_compositor_damage_all(struct wlsc_compositor *compositor); + +void +wlsc_surface_activate(struct wlsc_surface *surface, + struct wlsc_input_device *device, uint32_t time); struct wlsc_binding; typedef void (*wlsc_binding_handler_t)(struct wlsc_input_device *device, diff --git a/compositor/meego-tablet-shell.c b/compositor/meego-tablet-shell.c new file mode 100644 index 0000000..1daeaf8 --- /dev/null +++ b/compositor/meego-tablet-shell.c @@ -0,0 +1,250 @@ +/* + * Copyright © 2011 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 "compositor.h" +#include "meego-tablet-server-protocol.h" +#include "meego-tablet-shell.h" + +/* FIXME: We need a way to generate a different prefix. */ +struct wl_app_switcher { + struct wl_object object; + struct wlsc_surface *surface; + pid_t pid; + struct wl_listener listener; + struct wlsc_input_device *device; + struct wlsc_tweener scale; + int width, height; +}; + +struct meego_tablet_shell { + struct wl_app_switcher app_switcher; + struct wl_event_source *sigchld_source; +}; + +static void +sigchld_handler(int signal_number, void *data) +{ + struct meego_tablet_shell *shell = data; + int status; + + wait(&status); + shell->app_switcher.pid = -1; +} + +void +app_switcher_update(struct meego_tablet_shell *shell, uint32_t msecs) +{ + struct wl_app_switcher *app_switcher = &shell->app_switcher; + struct wlsc_surface *es = app_switcher->surface; + struct wlsc_output *output; + float scale; + + if (!app_switcher->surface) + return; + + output = container_of(es->compositor->output_list.next, + struct wlsc_output, link); + + scale = app_switcher->scale.current + 1.0; + wlsc_tweener_update(&app_switcher->scale, msecs); + if (!wlsc_tweener_done(&app_switcher->scale)) + wlsc_surface_damage(app_switcher->surface); + + es->width = scale * app_switcher->width; + es->height = scale * app_switcher->height; + es->x = (output->width - es->width) / 2; + es->y = (output->height - es->height) / 2; + wlsc_surface_update_matrix(es); + wlsc_surface_damage(es); + wlsc_compositor_damage_all(es->compositor); +} + +static void +switcher_map_switcher(struct wl_client *client, + struct wl_app_switcher *app_switcher, + struct wl_surface *surface) +{ + struct wlsc_surface *es = (struct wlsc_surface *) surface; + struct meego_tablet_shell *shell = + container_of(app_switcher, + struct meego_tablet_shell, app_switcher); + + switch (es->map_type) { + default: + /* FIXME: The window.c clients always map as toplevel + * first... so just override that. */ + wlsc_tweener_init(&app_switcher->scale, 1.0); + app_switcher->scale.k = 0.8; + app_switcher->scale.target = 0.0; + app_switcher->surface = es; + app_switcher->width = es->width; + app_switcher->height = es->height; + app_switcher_update(shell, 0); + es->map_type = WLSC_SURFACE_MAP_SWITCHER; + + wl_list_insert(surface->destroy_listener_list.prev, + &app_switcher->listener.link); + + wlsc_surface_activate(es, app_switcher->device, get_time()); + wlsc_compositor_set_tint(es->compositor, 0.5); + es->compositor->overlay_surface = es; + break; + + case WLSC_SURFACE_MAP_SWITCHER: + break; + } + +} + +static const struct wl_app_switcher_interface app_switcher_interface = { + switcher_map_switcher +}; + +static void +launch_switcher(struct wlsc_compositor *compositor) +{ + struct meego_tablet_shell *shell = compositor->meego_tablet_shell; + char s[32]; + int sv[2], flags; + struct wl_client *client; + + if (socketpair(AF_UNIX, SOCK_STREAM | SOCK_CLOEXEC, 0, sv) < 0) { + fprintf(stderr, "socketpair failed\n"); + return; + } + + /* SOCK_CLOEXEC closes both ends, so we need to unset the flag + * on the client fd. */ + flags = fcntl(sv[1], F_GETFD); + if (flags != -1) + fcntl(sv[1], F_SETFD, flags & ~FD_CLOEXEC); + + shell->app_switcher.pid = fork(); + switch (shell->app_switcher.pid) { + case 0: + snprintf(s, sizeof s, "%d", sv[1]); + setenv("WAYLAND_SOCKET", s, 1); + setenv("EGL_PLATFORM", "wayland", 1); +#if 1 + if (execl("./clients/meego-app-switcher", + "./clients/meego-app-switcher", NULL) < 0) + fprintf(stderr, "exec failed: %m\n"); +#else + if (execl("/usr/bin/meego-qml-launcher", + "/usr/bin/meego-qml-launcher", + "-platform", "wayland", + "--app", "meego-app-calculator", + "--width", "600", "--height", "480" + "--opengl", NULL) < 0) + fprintf(stderr, "exec failed: %m\n"); +#endif + exit(0); + + default: + close(sv[1]); + client = wl_client_create(compositor->wl_display, sv[0]); + + /* FIXME: If this is just a global, anybody who knows + * the global name can access it. We need the + * subscribtion mechanism where we send back an ack + * that an object of a certain type and version has + * been bound to a client id. Can't do that because + * the client needs to allocate the id... */ + wl_client_post_global(client, &shell->app_switcher.object); + break; + + case -1: + fprintf(stderr, "failed to fork\n"); + break; + } +} + +static void +app_switcher_binding(struct wlsc_input_device *device, + uint32_t time, uint32_t key, uint32_t state, void *data) +{ + struct wlsc_compositor *compositor = data; + struct meego_tablet_shell *shell = compositor->meego_tablet_shell; + + if (shell->app_switcher.surface || !state) + return; + if (shell->app_switcher.pid != -1) + fprintf(stderr, "lingering switcher child...\n"); + + shell->app_switcher.device = device; + launch_switcher(compositor); +} + +static void +handle_surface_destroy(struct wl_listener *listener, + struct wl_surface *surface, uint32_t time) +{ + struct wl_app_switcher *switcher = + container_of(listener, struct wl_app_switcher, listener); + struct wlsc_surface *es = (struct wlsc_surface *) surface; + + switcher->surface = NULL; + es->compositor->overlay_surface = NULL; + wlsc_compositor_set_tint(es->compositor, 0.0); +} + +struct meego_tablet_shell * +meego_tablet_shell_create(struct wlsc_compositor *compositor) +{ + struct meego_tablet_shell *shell; + struct wl_event_loop *loop; + + shell = malloc(sizeof *shell); + if (shell == NULL) + return NULL; + + shell->app_switcher.surface = NULL; + shell->app_switcher.pid = -1; + + shell->app_switcher.object.interface = &wl_app_switcher_interface; + shell->app_switcher.object.implementation = + (void (**)(void)) &app_switcher_interface; + wl_display_add_object(compositor->wl_display, + &shell->app_switcher.object); + + loop = wl_display_get_event_loop(compositor->wl_display); + shell->sigchld_source = + wl_event_loop_add_signal(loop, SIGCHLD, + sigchld_handler, shell); + + shell->app_switcher.listener.func = handle_surface_destroy; + wl_list_init(&shell->app_switcher.listener.link); + + wlsc_compositor_add_binding(compositor, KEY_GRAVE, MODIFIER_ALT, + app_switcher_binding, compositor); + + return shell; +} diff --git a/compositor/meego-tablet-shell.h b/compositor/meego-tablet-shell.h new file mode 100644 index 0000000..96be25b --- /dev/null +++ b/compositor/meego-tablet-shell.h @@ -0,0 +1,29 @@ +/* + * Copyright © 2011 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. + */ + +#ifndef MEEGO_TABLET_SHELL_H +#define MEEGO_TABLET_SHELL_H + +struct meego_tablet_shell * +meego_tablet_shell_create(struct wlsc_compositor *compositor); + +#endif /* MEEGO_TABLET_SHELL_H */ diff --git a/protocol/meego-tablet.xml b/protocol/meego-tablet.xml new file mode 100644 index 0000000..25540d8 --- /dev/null +++ b/protocol/meego-tablet.xml @@ -0,0 +1,9 @@ + + + + + + + + + -- 1.7.4.1