[PATCH 04/14] tablet-shell: add sliding effect of layout.

tecton69 at gmail.com tecton69 at gmail.com
Tue Aug 21 04:49:18 PDT 2012


From: Ning Tang <ning.tang at intel.com>

Use frame callback to enable layout moving, so dragging layout
will cause layout's offset changes.
And redraw function will allocate corresponding positions to launchers.
The allocation of layout won't change until sliding ends.

 Signed-off-by: Ning Tang <tecton69 at gmail.com>

---
 clients/tablet-shell.c | 225 ++++++++++++++++++++++++++++++++++++++++++++++++-
 1 file changed, 224 insertions(+), 1 deletion(-)

diff --git a/clients/tablet-shell.c b/clients/tablet-shell.c
index 3a0f04c..515d198 100644
--- a/clients/tablet-shell.c
+++ b/clients/tablet-shell.c
@@ -47,6 +47,7 @@ struct homescreen {
 	struct window *window;
 	struct widget *widget;
 	struct wl_list layout_list;
+	struct input *input;
 };
 
 struct lockscreen {
@@ -60,12 +61,17 @@ struct layout {
 	struct homescreen *homescreen;
 	struct wl_list launcher_list;
 	struct wl_list link;
+	int index;
 	int pressed;
 	int showing;
 	int offset;
+	int to_offset;
+	int last_x;
 	int hmargin;
 	int vmargin;
-
+	uint32_t click_time;		/* ms */
+	int switching;			/* 0-no 1-right -1-left*/
+	int s_speed;			/* switching speed */
 	struct wl_list *layout_list;	/* we need know the number of list */
 };
 
@@ -88,6 +94,7 @@ static void layout_section_done(void *data);
 static int launcher_size;
 static int key_layout_rows;
 static int key_layout_columns;
+static int layout_moving;
 
 static const struct config_key shell_config_keys[] = {
 	{ "lockscreen-icon", CONFIG_KEY_STRING, &key_lockscreen_icon },
@@ -251,6 +258,7 @@ homescreen_create(struct tablet *tablet)
 	widget_set_redraw_handler(homescreen->widget, homescreen_draw);
 
 	wl_list_init(&homescreen->layout_list);
+	layout_moving = 1;
 	return homescreen;
 }
 
@@ -408,13 +416,54 @@ launcher_redraw_handler(struct widget *widget, void *data)
 }
 
 static void
+layout_frame_callback(void *data, struct wl_callback *callback, uint32_t time)
+{
+	struct layout *layout = data;
+	struct rectangle allocation;
+
+	if (abs(layout->offset - layout->to_offset) < layout->s_speed) {
+		/* stop switching */
+		layout->offset = 0;
+		layout->switching = 0;
+		widget_get_allocation(layout->homescreen->widget, &allocation);
+		if (layout->to_offset) {
+			layout->showing = 0;
+			widget_set_allocation(layout->widget,
+					      0, 0, 0, 0);
+		} else {
+			widget_set_allocation(layout->widget,
+					      layout->hmargin,
+					      layout->vmargin,
+					      allocation.width - 2 *
+					      layout->hmargin,
+					      allocation.height - 2 *
+					      layout->vmargin);
+			input_ungrab(layout->homescreen->input);
+		}
+	} else if (layout_moving) {
+		layout->offset += layout->switching * layout->s_speed;
+	}
+
+	widget_schedule_redraw(layout->widget);
+
+	if (callback)
+		wl_callback_destroy(callback);
+}
+
+static const struct wl_callback_listener layout_listener = {
+	layout_frame_callback
+};
+
+static void
 layout_redraw_handler(struct widget *widget, void *data)
 {
 	struct layout *layout = data;
+	struct layout *current = data;
 	struct launcher *launcher;
 	struct rectangle allocation;
 	const int icon_width = launcher_size, icon_height = launcher_size;
 	int x, y, i, width, height, vpadding, hpadding;
+	struct wl_callback *callback;
 
 	if (layout->showing != 1)
 		return;
@@ -447,6 +496,174 @@ layout_redraw_handler(struct widget *widget, void *data)
 			i = 0;
 		}
 	}
+
+	if (current->switching) {
+		callback = wl_surface_frame(window_get_wl_surface(
+					    current->homescreen->window));
+		wl_callback_add_listener(callback, &layout_listener, current);
+	}
+}
+
+static void
+layout_sliding(struct layout *layout, int offset,
+	       int to_offset, int switching)
+{
+	struct rectangle allocation;
+	widget_get_allocation(layout->widget, &allocation);
+	layout->showing = 1;
+	layout->offset = offset;
+	if (switching) {
+		layout->switching = switching;
+		layout->to_offset = to_offset;
+	}
+	widget_set_allocation(layout->widget,
+			      layout->hmargin,
+			      layout->vmargin,
+			      allocation.width,
+			      allocation.height);
+	widget_schedule_redraw(layout->widget);
+}
+
+static void
+layout_button_handler(struct widget *widget,
+		      struct input *input, uint32_t time,
+		      uint32_t button,
+		      enum wl_pointer_button_state state, void *data)
+{
+	struct layout *layout;
+	struct layout *prev_layout = NULL, *next_layout = NULL;
+	struct layout *show_layout = NULL;
+	int y;
+	int width;
+	int fast_slide = 0;
+	struct rectangle layout_allocation;
+	struct rectangle screen_allocation;
+
+	layout = widget_get_user_data(widget);
+	layout->homescreen->input = input;
+	if (state == WL_POINTER_BUTTON_STATE_RELEASED) {
+		layout_moving = 1;
+		layout->pressed = 0;
+
+		/* do offset check to determine switch direction */
+		widget_get_allocation(widget, &layout_allocation);
+		widget_get_allocation(layout->homescreen->widget,
+				      &screen_allocation);
+		width = screen_allocation.width;
+
+		if (time - layout->click_time < 700) {
+			fast_slide = 1;
+			/* less than 0.7 second, also slide layout. */
+			if (layout->offset > 0)
+				layout->offset += width / 2;
+			else if (layout->offset < 0)
+				layout->offset -= width / 2;
+		}
+
+		if (layout->link.next != layout->layout_list)
+			next_layout = __wl_container_of(layout->link.next,
+							layout, link);
+		if (layout->link.prev != layout->layout_list)
+			prev_layout = __wl_container_of(layout->link.prev,
+							layout, link);
+
+		if ((layout->offset < -width / 2 && next_layout != NULL) ||
+		    (layout->offset > width / 2 && prev_layout != NULL)) {
+			/* origin hide to show the other */
+			if (fast_slide)
+				layout->offset += (layout->offset > 0) ?
+						  -width / 2:width / 2;
+			layout_sliding(layout,
+				       layout->offset,
+				       layout->offset > 0 ?
+				       width: -width,
+				       layout->offset > 0 ?
+				       1: -1);
+
+			if (layout->offset < 0) {
+				/* move to next */
+				layout_sliding(next_layout,
+					       width + layout->offset,
+					       0, -1);
+			} else {
+				/* move to previous */
+				layout_sliding(prev_layout,
+					       -width + layout->offset,
+					       0, 1);
+			}
+		} else {
+			/* back to itself */
+			layout->switching = (layout->offset > 0)? -1 : 1;
+			layout->showing = 1;
+			layout->to_offset = 0;
+			if (fast_slide && layout->offset != 0)
+				layout->offset += (layout->offset > 0)?
+						  -width / 2 : width / 2;
+			show_layout = (layout->offset < 0)? next_layout :
+							    prev_layout;
+			if (!show_layout) {
+				widget_schedule_redraw(layout->widget);
+				return;
+			}
+			layout_sliding(show_layout,
+				       layout->offset > 0 ?
+				       layout->offset - screen_allocation.width:
+				       layout->offset + screen_allocation.width,
+				       layout->offset > 0 ?
+				       -screen_allocation.width :
+				       screen_allocation.width,
+				       layout->offset > 0 ? -1: 1);
+		}
+		/* update scene */
+		widget_schedule_redraw(layout->widget);
+	} else if (state == WL_POINTER_BUTTON_STATE_PRESSED) {
+		layout_moving = 0;
+		layout->pressed = 1;
+		layout->click_time = time;
+		/* record first position */
+		input_get_position(input, &layout->last_x, &y);
+	}
+}
+
+static int
+layout_motion_handler(struct widget *widget, struct input *input,
+		      uint32_t time, float x, float y, void *data)
+{
+	struct layout *layout = data;
+	struct layout *show_layout = NULL;
+	struct rectangle layout_allocation, screen_allocation;
+
+	widget_get_allocation(layout->widget,
+			      &layout_allocation);
+	widget_get_allocation(layout->homescreen->widget,
+			      &screen_allocation);
+
+	if (layout->pressed)
+	{
+		layout->offset += x - layout->last_x;
+		layout->last_x = x;
+		widget_schedule_redraw(layout->widget);
+		if (layout->offset < 0 &&
+		    layout->link.next != layout->layout_list) {
+			show_layout = __wl_container_of(layout->link.next,
+							layout, link);
+			show_layout->offset = layout->offset +
+					      screen_allocation.width;
+		} else if (layout->offset > 0 &&
+			   layout->link.prev != layout->layout_list) {
+			show_layout = __wl_container_of(layout->link.prev,
+							layout, link);
+			show_layout->offset = layout->offset -
+					      screen_allocation.width;
+		}
+		if (show_layout) {
+			layout_sliding(show_layout,
+				       show_layout->offset,
+				       0, 0);
+		}
+	}
+
+	return CURSOR_LEFT_PTR;
 }
 
 static void
@@ -464,6 +681,8 @@ tablet_shell_add_layout(struct tablet *tablet)
 	layout->homescreen = homescreen;
 	layout->hmargin = 100;
 	layout->vmargin = 50;
+	layout->switching = 0;
+	layout->s_speed = 30;
 	if (wl_list_empty(&homescreen->layout_list)) {
 		layout->showing = 1;
 	}
@@ -473,6 +692,10 @@ tablet_shell_add_layout(struct tablet *tablet)
 	layout->layout_list = &homescreen->layout_list;
 
 	wl_list_insert(homescreen->layout_list.prev, &layout->link);
+	widget_set_button_handler(layout->widget,
+				  layout_button_handler);
+	widget_set_motion_handler(layout->widget,
+				  layout_motion_handler);
 	widget_set_redraw_handler(layout->widget,
 				  layout_redraw_handler);
 }
-- 
1.7.11.5



More information about the wayland-devel mailing list