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

Reply via email to