/* * Copyright © 2013 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 "overlay-server-protocol.h" struct overlay { struct weston_compositor *compositor; struct wl_global *global; struct wl_resource *resource; struct wl_listener destroy_listener; struct wl_listener surface_destroy_listener; struct weston_surface *surface; struct weston_binding *binding; struct weston_layer layer; struct wl_seat *seat; struct wl_pointer_grab grab; struct weston_output *output; struct wl_surface *saved_focus; struct wl_listener saved_focus_destroy_listener; }; static void handle_surface_destroy(struct wl_listener *listener, void *data) { struct overlay *overlay = container_of(listener, struct overlay, surface_destroy_listener); overlay->surface = NULL; if (overlay->saved_focus) { weston_surface_activate((struct weston_surface *) overlay->saved_focus, (struct weston_seat *) overlay->seat); wl_list_remove(&overlay->saved_focus_destroy_listener.link); } } static void overlay_close(struct overlay *overlay) { overlay_send_done(overlay->resource); wl_pointer_end_grab(overlay->grab.pointer); } static void overlay_grab_focus(struct wl_pointer_grab *grab, struct wl_surface *surface, wl_fixed_t x, wl_fixed_t y) { struct wl_pointer *pointer = grab->pointer; struct overlay *overlay = container_of(grab, struct overlay, grab); if (surface == &overlay->surface->surface) { wl_pointer_set_focus(pointer, surface, x, y); grab->focus = surface; } else { wl_pointer_set_focus(pointer, NULL, wl_fixed_from_int(0), wl_fixed_from_int(0)); grab->focus = NULL; } } static void overlay_grab_motion(struct wl_pointer_grab *grab, uint32_t time, wl_fixed_t sx, wl_fixed_t sy) { struct wl_resource *resource; resource = grab->pointer->focus_resource; if (resource) wl_pointer_send_motion(resource, time, sx, sy); } static void overlay_grab_button(struct wl_pointer_grab *grab, uint32_t time, uint32_t button, uint32_t state_w) { struct wl_resource *resource; struct overlay *overlay = container_of(grab, struct overlay, grab); struct wl_display *display; enum wl_pointer_button_state state = state_w; uint32_t serial; resource = grab->pointer->focus_resource; if (resource) { display = wl_client_get_display(resource->client); serial = wl_display_get_serial(display); wl_pointer_send_button(resource, serial, time, button, state); } else { overlay_close(overlay); } } static const struct wl_pointer_grab_interface overlay_grab_interface = { overlay_grab_focus, overlay_grab_motion, overlay_grab_button, }; static struct weston_output * get_output_for_pointer(struct overlay *overlay) { struct weston_output *output; int x, y; x = wl_fixed_to_int(overlay->seat->pointer->x); y = wl_fixed_to_int(overlay->seat->pointer->y); wl_list_for_each(output, &overlay->compositor->output_list, link) { if (pixman_region32_contains_point(&output->region, x, y, NULL)) return output; } return NULL; } static void handle_saved_focus_destroy(struct wl_listener *listener, void *data) { struct overlay *overlay =container_of(listener, struct overlay, saved_focus_destroy_listener); overlay->saved_focus = NULL; } static void center_on_output(struct overlay *overlay, int32_t width, int32_t height) { struct weston_surface *surface = overlay->surface; struct weston_output *output = overlay->output; surface->geometry.x = output->x + (output->width - width) / 2; surface->geometry.y = output->y + (output->height - height) / 2; surface->geometry.width = width; surface->geometry.height = height; weston_surface_geometry_dirty(surface); } static void overlay_map(struct overlay *overlay, int32_t width, int32_t height) { struct weston_surface *surface = overlay->surface; wl_list_insert(&overlay->layer.surface_list, &surface->layer_link); overlay->saved_focus = overlay->seat->keyboard->focus; if (overlay->saved_focus) { overlay->saved_focus_destroy_listener.notify = handle_saved_focus_destroy; wl_signal_add(&overlay->saved_focus->resource.destroy_signal, &overlay->saved_focus_destroy_listener); } weston_surface_activate(overlay->surface, (struct weston_seat *) overlay->seat); overlay->grab.interface = &overlay_grab_interface; wl_pointer_start_grab(overlay->seat->pointer, &overlay->grab); overlay->output = get_output_for_pointer(overlay); center_on_output(overlay, width, height); weston_surface_update_transform(surface); weston_zoom_run(surface, 0.8, 1.0, NULL, NULL); } static void overlay_configure(struct weston_surface *surface, int32_t sx, int32_t sy, int32_t width, int32_t height) { struct overlay *overlay = surface->private; struct weston_output *output; if (wl_list_empty(&surface->layer_link)) overlay_map(overlay, width, height); else center_on_output(overlay, width, height); } static void overlay_handle_surface(struct wl_client *client, struct wl_resource *resource, struct wl_resource *surface_resource) { struct overlay *overlay = resource->data; overlay->surface = surface_resource->data; overlay->surface_destroy_listener.notify = handle_surface_destroy; wl_signal_add(&surface_resource->destroy_signal, &overlay->surface_destroy_listener); overlay->surface->configure = overlay_configure; overlay->surface->private = overlay; } static void overlay_handle_close(struct wl_client *client, struct wl_resource *resource) { struct overlay *overlay = resource->data; overlay_close(overlay); } static const struct overlay_interface overlay_implementation = { overlay_handle_surface, overlay_handle_close }; static void overlay_binding(struct wl_seat *_seat, uint32_t time, uint32_t key, void *data) { struct overlay *overlay = data; fprintf(stderr, "overlay binding pressed\n"); overlay->seat = _seat; if (overlay->resource) overlay_send_activate(overlay->resource); } static void handle_overlay_destroy(struct wl_resource *resource) { struct overlay *overlay = resource->data; overlay->resource = NULL; free(resource); } static void bind_overlay(struct wl_client *client, void *data, uint32_t version, uint32_t id) { struct overlay *overlay = data; fprintf(stderr, "client %p binds to overlay global\n", client); overlay->resource = wl_client_add_object(client, &overlay_interface, &overlay_implementation, id, overlay); overlay->resource->destroy = handle_overlay_destroy; } static void overlay_destroy(struct wl_listener *listener, void *data) { struct overlay *overlay = container_of(listener, struct overlay, destroy_listener); wl_display_remove_global(overlay->compositor->wl_display, overlay->global); free(overlay); } int module_init(struct weston_compositor *compositor, int *argc, char *argv[], const char *config_file); WL_EXPORT int module_init(struct weston_compositor *compositor, int *argc, char *argv[], const char *config_file) { struct overlay *overlay; int major, minor, micro; weston_version(&major, &minor, µ); if (major != 1 || minor != 0 || micro < 90) { weston_log("overlay plugin requires weston > 1.0.90\n"); return -1; } overlay = malloc(sizeof *overlay); if (overlay == NULL) return -1; overlay->compositor = compositor; overlay->global = wl_display_add_global(compositor->wl_display, &overlay_interface, overlay, bind_overlay); overlay->destroy_listener.notify = overlay_destroy; wl_signal_add(&compositor->destroy_signal, &overlay->destroy_listener); overlay->binding = weston_compositor_add_key_binding(compositor, KEY_SPACE, MODIFIER_SUPER, overlay_binding, overlay); weston_layer_init(&overlay->layer, &compositor->cursor_layer.link); weston_log("overlay initialized\n"); return 0; }