From: Ning Tang <ning.t...@intel.com> Enable dragging launchers. Use the drag and drop mechanism, the launcher's icon is provided as cursor image. Currently ignore all drop events.
Signed-off-by: Ning Tang <tecto...@gmail.com> --- clients/tablet-shell.c | 234 ++++++++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 223 insertions(+), 11 deletions(-) diff --git a/clients/tablet-shell.c b/clients/tablet-shell.c index 515d198..eaaa8d7 100644 --- a/clients/tablet-shell.c +++ b/clients/tablet-shell.c @@ -27,6 +27,7 @@ #include <unistd.h> #include <sys/wait.h> +#include <wayland-cursor.h> #include "window.h" #include "../shared/cairo-util.h" #include "../shared/config-parser.h" @@ -82,6 +83,17 @@ struct launcher { int focused, pressed; char *path; struct wl_list link; + + cairo_surface_t *opaque; + cairo_surface_t *translucent; + int dragging; + int hotspot_x, hotspot_y; + uint32_t click_time; + int index; + + const char *mime_type; + struct wl_surface *drag_surface; + struct wl_data_source *data_source; }; static char *key_lockscreen_icon; @@ -91,6 +103,8 @@ static char *key_launcher_icon; static char *key_launcher_path; static void launcher_section_done(void *data); static void layout_section_done(void *data); +/* launcher drag */ +struct launcher *gl_launcher_drag = NULL; static int launcher_size; static int key_layout_rows; static int key_layout_columns; @@ -194,6 +208,37 @@ homescreen_draw(struct widget *widget, void *data) } static void +data_source_target(void *data, + struct wl_data_source *source, const char *mime_type) +{ + struct launcher *launcher = data; + cairo_surface_t *surface; + struct wl_buffer *buffer; + struct display *display = + window_get_display(launcher->layout->homescreen->window); + struct wl_cursor_image *pointer = + display_get_pointer_image(display, CURSOR_DRAGGING); + + launcher->mime_type = mime_type; + if (mime_type) + surface = launcher->opaque; + else + surface = launcher->translucent; + + buffer = display_get_buffer_for_surface(display, surface); + wl_surface_attach(launcher->drag_surface, buffer, 0, 0); + wl_surface_damage(launcher->drag_surface, 0, 0, + launcher_size + 2 * pointer->width, + launcher_size + 2 * pointer->height); +} + +static const struct wl_data_source_listener data_source_listener = { + data_source_target, + NULL, + NULL, +}; + +static void lockscreen_draw(struct widget *widget, void *data) { struct lockscreen *lockscreen = data; @@ -242,6 +287,156 @@ lockscreen_button_handler(struct widget *widget, } } +static cairo_surface_t * +create_drag_cursor(struct launcher *launcher, + int32_t x, int32_t y, double opacity) +{ + cairo_surface_t *surface; + struct wl_cursor_image *pointer; + struct rectangle rectangle; + cairo_pattern_t *pattern; + cairo_t *cr; + struct display *display; + struct rectangle allocation; + + widget_get_allocation(launcher->widget, &allocation); + display = window_get_display(launcher->layout->homescreen->window); + pointer = display_get_pointer_image(display, CURSOR_DRAGGING); + + rectangle.width = launcher_size + 2 * pointer->width; + rectangle.height = launcher_size + 2 * pointer->height; + + surface = display_create_surface(display, NULL, &rectangle, + SURFACE_SHM); + + cr = cairo_create(surface); + cairo_translate(cr, pointer->width, pointer->height); + + cairo_set_operator(cr, CAIRO_OPERATOR_SOURCE); + cairo_set_source_rgba(cr, 0, 0, 0, 0); + cairo_paint(cr); + + cairo_set_operator(cr, CAIRO_OPERATOR_OVER); + cairo_set_source_surface(cr, launcher->icon,0, 0); + pattern = cairo_pattern_create_rgba(0, 0, 0, opacity); + cairo_mask(cr, pattern); + cairo_pattern_destroy(pattern); + + /* FIXME: more cairo-gl brokeness */ + surface_flush_device(surface); + cairo_destroy(cr); + + launcher->hotspot_x = pointer->width + x - allocation.x; + launcher->hotspot_y = pointer->height + y - allocation.y; + + return surface; +} + +static int +launcher_motion_handler(struct widget *widget, struct input *input, + uint32_t time, float x, float y, void *data) +{ + struct launcher *launcher = data; + struct display *display; + struct rectangle allocation; + struct wl_compositor *compositor; + struct wl_buffer *buffer; + struct wl_cursor_image *pointer; + uint32_t serial; + + widget_get_allocation(widget, &allocation); + widget_set_tooltip(widget, basename(launcher->path), + x, allocation.y + allocation.height); + + if (!launcher->dragging && launcher->pressed == 1 && + time - launcher->click_time > 600) + { + widget_destroy_tooltip(widget); + // draging mode + launcher->focused = 0; + if (gl_launcher_drag) + free(gl_launcher_drag); + gl_launcher_drag = launcher; + display = + window_get_display(launcher->layout->homescreen->window); + compositor = display_get_compositor(display); + serial = display_get_serial(display); + launcher->drag_surface = + wl_compositor_create_surface(compositor); + + input_ungrab(input); + + launcher->data_source = display_create_data_source(display); + wl_data_source_add_listener(launcher->data_source, + &data_source_listener, + launcher); + wl_data_source_offer(launcher->data_source, + "application/tablet-launcher"); + wl_data_source_offer(launcher->data_source, + "text/plain; charset=utf-8"); + wl_data_device_start_drag(input_get_data_device(input), + launcher->data_source, + window_get_wl_surface( + launcher->layout->homescreen->window), + launcher->drag_surface, + serial); + + input_set_pointer_image(input, CURSOR_DRAGGING); + + launcher->opaque = create_drag_cursor(launcher, x, y, 0.95); + launcher->translucent = + create_drag_cursor(launcher, x, y, 0.2); + + buffer = display_get_buffer_for_surface(display, + launcher->translucent); + + pointer = display_get_pointer_image(display, CURSOR_DRAGGING); + + wl_surface_attach(launcher->drag_surface, buffer, + -launcher->hotspot_x, -launcher->hotspot_y); + wl_surface_damage(launcher->drag_surface, 0, 0, + launcher_size + 2 * pointer->width, + launcher_size + 2 * pointer->height); + + launcher->dragging = 1; + } + + return CURSOR_HAND1; +} + +static void +launcher_data_handler(struct window *window, + struct input *input, + float x, float y, const char **types, void *data) +{ + if (!types) + return; + if (strcmp(types[0], "application/tablet-launcher") != 0) { + return; + } + input_accept(input, types[0]); +} + +static void +launcher_drop_handler(struct window *window, struct input *input, + int32_t x, int32_t y, void *data) +{ + if (gl_launcher_drag == NULL || + gl_launcher_drag->widget == NULL) { + fprintf(stderr, "ignoring drop from another client\n"); + return; + } + + struct launcher *launcher = gl_launcher_drag; + struct layout *layout = launcher->layout; + struct launcher *temp_launcher; + + launcher->dragging = 0; + launcher->pressed = 0; + gl_launcher_drag = NULL; + window_schedule_redraw(launcher->layout->homescreen->window); +} + static struct homescreen * homescreen_create(struct tablet *tablet) { @@ -257,6 +452,9 @@ homescreen_create(struct tablet *tablet) window_set_title(homescreen->window, "homescreen"); widget_set_redraw_handler(homescreen->widget, homescreen_draw); + window_set_data_handler(homescreen->window, launcher_data_handler); + window_set_drop_handler(homescreen->window, launcher_drop_handler); + wl_list_init(&homescreen->layout_list); layout_moving = 1; return homescreen; @@ -367,14 +565,24 @@ launcher_button_handler(struct widget *widget, enum wl_pointer_button_state state, void *data) { struct launcher *launcher; + struct rectangle allocation; + int32_t x, y; + + widget_get_allocation(widget, &allocation); + input_get_position(input, &x, &y); launcher = widget_get_user_data(widget); - widget_schedule_redraw(widget); if (state == WL_POINTER_BUTTON_STATE_RELEASED) { - launcher_activate(launcher); + launcher->click_time = 0; + if (launcher->pressed && !launcher->dragging) + launcher_activate(launcher); + launcher->dragging = 0; launcher->pressed = 0; - } else if (state == WL_POINTER_BUTTON_STATE_PRESSED) + } else if (state == WL_POINTER_BUTTON_STATE_PRESSED) { launcher->pressed = 1; + launcher->click_time = time; + } + widget_schedule_redraw(widget); } static void @@ -402,17 +610,19 @@ launcher_redraw_handler(struct widget *widget, void *data) allocation.y++; } - cairo_set_source_surface(cr, launcher->icon, - allocation.x, allocation.y); - cairo_paint(cr); + if (!launcher->dragging) { + cairo_set_source_surface(cr, launcher->icon, + allocation.x, allocation.y); + cairo_paint(cr); - if (launcher->focused) { - cairo_set_source_rgba(cr, 1.0, 1.0, 1.0, 0.4); - cairo_mask_surface(cr, launcher->icon, - allocation.x, allocation.y); + if (launcher->focused) { + cairo_set_source_rgba(cr, 1.0, 1.0, 1.0, 0.4); + cairo_mask_surface(cr, launcher->icon, + allocation.x, allocation.y); + } } - cairo_destroy(cr); + cairo_surface_destroy(surface); } static void @@ -737,6 +947,8 @@ layout_add_launcher(struct tablet *tablet, launcher_button_handler); widget_set_redraw_handler(launcher->widget, launcher_redraw_handler); + widget_set_motion_handler(launcher->widget, + launcher_motion_handler); } static void -- 1.7.11.5 _______________________________________________ wayland-devel mailing list wayland-devel@lists.freedesktop.org http://lists.freedesktop.org/mailman/listinfo/wayland-devel