[PATCH 4/5] tablet-shell: Make launchers draggable.
tecton69 at gmail.com
tecton69 at gmail.com
Tue Jul 17 02:09:34 PDT 2012
From: Ning Tang <tecton69 at gmail.com>
The determination is occurred in launcher motion function.
If the launcher is pressed some time, it will create the drag surface.
That launcher's icon would follow cursor.
Signed-off-by: Li Chen <cl.zhejiang.china at gmail.com>
Signed-off-by: Yi Yuan <harryyuan910702 at gmail.com>
Signed-off-by: Ning Tang <tecton69 at gmail.com>
---
clients/tablet-shell.c | 211 ++++++++++++++++++++++++++++++++++++++++++++++---
1 file changed, 200 insertions(+), 11 deletions(-)
diff --git a/clients/tablet-shell.c b/clients/tablet-shell.c
index 0a9e868..6cf40a7 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"
@@ -79,6 +80,18 @@ 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;
+ int layout_index;
+
+ const char *mime_type;
+ struct wl_surface *drag_surface;
+ struct wl_data_source *data_source;
};
static char *key_lockscreen_icon;
@@ -88,6 +101,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;
/* launcher size */
static int launcher_size = 146;
@@ -188,6 +203,34 @@ 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);
+
+ 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, launcher_size);
+}
+
+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;
@@ -236,6 +279,137 @@ 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;
+ } else if (!launcher->dragging && launcher->pressed == 1) {
+ launcher->pressed = 0;
+ widget_schedule_redraw(launcher->widget);
+ }
+
+ 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 struct homescreen *
homescreen_create(struct tablet *tablet)
{
@@ -251,6 +425,8 @@ 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);
+
wl_list_init(&homescreen->layout_list);
return homescreen;
}
@@ -360,14 +536,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;
+ }
}
static void
@@ -391,23 +577,24 @@ launcher_redraw_handler(struct widget *widget, void *data)
surface = window_get_surface(launcher->layout->homescreen->window);
cr = cairo_create(surface);
- widget_get_allocation(widget, &allocation);
if (launcher->pressed) {
allocation.x++;
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
@@ -740,6 +927,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.1
More information about the wayland-devel
mailing list