diff --git a/src/compositor.c b/src/compositor.c index 7b1b0f4d..02358b25 100644 --- a/src/compositor.c +++ b/src/compositor.c @@ -227,7 +227,7 @@ weston_surface_set_color(struct weston_surface *surface, surface->shader = &surface->compositor->solid_shader; } -static void +WL_EXPORT void weston_surface_update_transform(struct weston_surface *surface) { struct weston_matrix *matrix = &surface->transform.matrix; diff --git a/src/compositor.h b/src/compositor.h index 53126651..580800db 100644 --- a/src/compositor.h +++ b/src/compositor.h @@ -250,6 +250,9 @@ struct weston_surface { struct wl_listener buffer_destroy_listener; }; +void +weston_surface_update_transform(struct weston_surface *surface); + void weston_device_repick(struct wl_input_device *device, uint32_t time); diff --git a/src/shell.c b/src/shell.c index 92196994..49b0b109 100644 --- a/src/shell.c +++ b/src/shell.c @@ -29,6 +29,7 @@ #include #include #include +#include #include #include "compositor.h" @@ -93,6 +94,10 @@ struct shell_surface { enum shell_surface_type type; int32_t saved_x, saved_y; + struct { + struct weston_transform transform; + } rotation; + struct { struct wl_grab grab; uint32_t time; @@ -110,6 +115,15 @@ struct weston_move_grab { int32_t dx, dy; }; +struct rotate_grab { + struct wl_grab grab; + struct shell_surface *surface; + struct { + int32_t x; + int32_t y; + } center; +}; + static void shell_configuration(struct wl_shell *shell) { @@ -621,6 +635,9 @@ shell_get_shell_surface(struct wl_client *client, /* init link so its safe to always remove it in destroy_shell_surface */ wl_list_init(&shsurf->link); + /* empty when not in use */ + wl_list_init(&shsurf->rotation.transform.link); + shsurf->type = SHELL_SURFACE_NONE; wl_client_add_resource(client, &shsurf->resource); @@ -946,6 +963,118 @@ terminate_binding(struct wl_input_device *device, uint32_t time, wl_display_terminate(compositor->wl_display); } +static void +rotate_grab_motion(struct wl_grab *grab, + uint32_t time, int32_t x, int32_t y) +{ + struct rotate_grab *rotate = + container_of(grab, struct rotate_grab, grab); + struct wl_input_device *device = grab->input_device; + struct shell_surface *surface = rotate->surface; + GLfloat dx, dy; + GLfloat r; + + dx = device->x - rotate->center.x; + dy = device->y - rotate->center.y; + r = sqrtf(dx * dx + dy * dy); + + wl_list_remove(&surface->rotation.transform.link); + surface->surface->transform.dirty = 1; + + if (r > 20.0f) { + struct weston_matrix roto; + struct weston_matrix *matrix = + &surface->rotation.transform.matrix; + + weston_matrix_init(&roto); + roto.d[0] = dx / r; + roto.d[4] = -dy / r; + roto.d[1] = -roto.d[4]; + roto.d[5] = roto.d[0]; + + weston_matrix_init(matrix); + weston_matrix_translate(matrix, -rotate->center.x, + -rotate->center.y, 0.0f); + weston_matrix_multiply(matrix, &roto); + weston_matrix_translate(matrix, rotate->center.x, + rotate->center.y, 0.0f); + + wl_list_insert(surface->surface->transform.list.prev, + &surface->rotation.transform.link); + } else { + wl_list_init(&surface->rotation.transform.link); + } + + weston_compositor_damage_all(surface->surface->compositor); +} + +static void +rotate_grab_button(struct wl_grab *grab, + uint32_t time, int32_t button, int32_t state) +{ + struct rotate_grab *rotate = + container_of(grab, struct rotate_grab, grab); + struct wl_input_device *device = grab->input_device; + + if (device->button_count == 0 && state == 0) { + wl_input_device_end_grab(device, time); + free(rotate); + } +} + +static const struct wl_grab_interface rotate_grab_interface = { + noop_grab_focus, + rotate_grab_motion, + rotate_grab_button, +}; + +static void +rotate_binding(struct wl_input_device *device, uint32_t time, + uint32_t key, uint32_t button, uint32_t state, void *data) +{ + struct weston_surface *base_surface = + (struct weston_surface *) device->pointer_focus; + struct shell_surface *surface; + struct rotate_grab *rotate; + struct weston_vector center = { { 0.0f, 0.0f, 0.0f, 1.0f } }; + + if (base_surface == NULL) + return; + + surface = get_shell_surface(base_surface); + if (!surface) + return; + + switch (surface->type) { + case SHELL_SURFACE_PANEL: + case SHELL_SURFACE_BACKGROUND: + case SHELL_SURFACE_FULLSCREEN: + case SHELL_SURFACE_SCREENSAVER: + return; + default: + break; + } + + center.f[0] = 0.5f * surface->surface->width; + center.f[1] = 0.5f * surface->surface->height; + weston_surface_update_transform(surface->surface); + weston_matrix_transform(&surface->surface->transform.matrix, ¢er); + if (fabsf(center.f[3]) < 1e-6) + return; + + rotate = malloc(sizeof *rotate); + if (!rotate) + return; + + rotate->grab.interface = &rotate_grab_interface; + rotate->surface = surface; + rotate->center.x = center.f[0] / center.f[3]; + rotate->center.y = center.f[1] / center.f[3]; + + wl_input_device_start_grab(device, &rotate->grab, time); + wl_input_device_set_pointer_focus(device, NULL, time, 0, 0, 0, 0); +} + static void activate(struct weston_shell *base, struct weston_surface *es, struct weston_input_device *device, uint32_t time) @@ -1474,6 +1603,9 @@ shell_init(struct weston_compositor *ec) terminate_binding, ec); weston_compositor_add_binding(ec, 0, BTN_LEFT, 0, click_to_activate_binding, ec); + weston_compositor_add_binding(ec, 0, BTN_LEFT, + MODIFIER_SUPER | MODIFIER_ALT, + rotate_binding, NULL); ec->shell = &shell->shell;