[PATCH 2/2] desktop-shell: Add sliding layout on background

tecton69 at gmail.com tecton69 at gmail.com
Mon Jul 9 20:04:58 PDT 2012


From: Ning Tang <tecton69 at gmail.com>

 This patch is based on Zhi Wen's patch.
 Dragging the layout have an effect of switching between them.
 Shortcuts are placed on layouts and can be activated as launcher.
 They are also draggable and can be deleted.

 The section name in weston.ini is "layout" and with no keys.
 It will add following shortcuts to the layout. The structure of
 shortcut is similar to launcher so reuse some of its functions.

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

---
 clients/desktop-shell.c | 862 ++++++++++++++++++++++++++++++++++++++++++++----
 weston.ini              |   2 +
 2 files changed, 807 insertions(+), 57 deletions(-)

diff --git a/clients/desktop-shell.c b/clients/desktop-shell.c
index 81ff1b4..39144c0 100644
--- a/clients/desktop-shell.c
+++ b/clients/desktop-shell.c
@@ -37,6 +37,7 @@
 #include <time.h>
 
 #include <wayland-client.h>
+#include <wayland-cursor.h>
 #include "window.h"
 #include "../shared/cairo-util.h"
 #include "../shared/config-parser.h"
@@ -71,9 +72,28 @@ struct panel {
 	struct panel_clock *clock;
 };
 
+/* container of shortcuts on background */
+struct layout {
+	struct widget *widget;
+	struct surface *parent;
+	struct wl_list shortcut_list;
+	struct wl_list link;
+	int pressed;
+	int showing;
+	int offset;
+	int last_x;
+	int hmargin;
+	int vmargin;
+	uint32_t click_time;			/* ms */
+	int switching;	                /* if the layout is switching 0-no 1-right -1-left*/
+	int s_speed;	                /* switching speed */
+	struct wl_list *layout_list;	/* we need know the number of list */
+};
+
 struct background {
 	struct surface base;
-	struct wl_list shortcut_list;
+	struct wl_list layout_list;
+	cairo_surface_t *image;
 };
 
 struct output {
@@ -84,6 +104,27 @@ struct output {
 	struct background *background;
 };
 
+struct shortcut {
+	struct widget *widget;
+	struct surface *parent;
+	cairo_surface_t *icon;
+	int focused, pressed;
+	const 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;
+
+	struct layout *parent_layout;
+	const char *mime_type;
+	struct wl_surface *drag_surface;
+	struct wl_data_source *data_source;
+};
+
 struct launcher {
 	struct widget *widget;
 	struct surface *parent;
@@ -119,7 +160,21 @@ static char *key_shortcut_icon;
 static char *key_shortcut_path;
 static void panel_launcher_section_done(void *data);
 static void shortcut_section_done(void *data);
+static void layout_section_done(void *data);
 static int key_locking = 1;
+/* trash image string */
+static char *key_trash_image;
+/* shortcut drag */
+struct shortcut *gl_shortcut_drag = NULL;
+/* shortcut size */
+static int shortcut_size = 146;
+/* trash parameters */
+static cairo_surface_t *trash_surface = NULL;
+static int trash_x, trash_y;
+static int trash_w, trash_h;
+static int trash_highlight = 0;
+
+
 
 static const struct config_key shell_config_keys[] = {
 	{ "background-image", CONFIG_KEY_STRING, &key_background_image },
@@ -127,6 +182,7 @@ static const struct config_key shell_config_keys[] = {
 	{ "panel-color", CONFIG_KEY_UNSIGNED_INTEGER, &key_panel_color },
 	{ "background-color", CONFIG_KEY_UNSIGNED_INTEGER, &key_background_color },
 	{ "locking", CONFIG_KEY_BOOLEAN, &key_locking },
+	{ "trash-image", CONFIG_KEY_STRING, &key_trash_image },
 };
 
 static const struct config_key panel_launcher_config_keys[] = {
@@ -145,6 +201,9 @@ static const struct config_section config_sections[] = {
 	{ "launcher",
 	  panel_launcher_config_keys, ARRAY_LENGTH(panel_launcher_config_keys),
 	  panel_launcher_section_done },
+	{ "layout",
+	  NULL, 0,
+	  layout_section_done },
 	{ "shortcut",
 	  shortcut_config_keys, ARRAY_LENGTH(shortcut_config_keys),
 	  shortcut_section_done },
@@ -181,6 +240,91 @@ show_menu(struct panel *panel, struct input *input, uint32_t time)
 }
 
 static void
+data_source_target(void *data,
+		   struct wl_data_source *source, const char *mime_type)
+{
+	struct shortcut *shortcut = data;
+	cairo_surface_t *surface;
+	struct wl_buffer *buffer;
+	struct display *display = window_get_display(shortcut->parent->window);
+
+	shortcut->mime_type = mime_type;
+	if (mime_type)
+		surface = shortcut->opaque;
+	else
+		surface = shortcut->translucent;
+
+	buffer = display_get_buffer_for_surface(display, surface);
+	wl_surface_attach(shortcut->drag_surface, buffer, 0, 0);
+	wl_surface_damage(shortcut->drag_surface, 0, 0,
+			  shortcut_size, shortcut_size);
+}
+
+static const struct wl_data_source_listener data_source_listener = {
+	data_source_target,
+	NULL,
+	NULL,
+};
+
+static int
+layout_delete_shortcut(struct shortcut *shortcut) {
+	char *config_file = config_file_path("weston.ini");
+	FILE *fp;
+	char line[512];
+	uint32_t found_pos = 0;
+	uint32_t next_pos = 0;
+	uint32_t end_length = 0;
+	uint32_t layout_num = shortcut->layout_index;
+	uint32_t shortcut_num = shortcut->index;
+
+	fp = fopen(config_file, "r");
+	if (fp == NULL) {
+		fprintf(stderr, "couldn't open %s.\n", config_file);
+		return -1;
+	}
+	while (fgets(line, sizeof line, fp)) {
+		if (strcmp("[layout]\n", line) == 0)
+		    layout_num--;
+		if (layout_num == 0 && strcmp("[shortcut]\n", line) == 0) {
+		    shortcut_num--;
+		    if (shortcut_num == 0) {
+				found_pos = ftell(fp) - 11;
+				break;
+		    }
+		}
+	}
+	fseek(fp, found_pos, SEEK_SET);
+	if (!fread(line, 1, 511, fp))
+	{
+		fprintf(stderr, "read ini file error.\n");
+	}
+	char *next = strchr(line + 10, '[');
+	next_pos = next - line + found_pos;
+
+	char *start_content = malloc(sizeof (char) * (found_pos + 1));
+	fseek(fp, 0, SEEK_END);
+	end_length = ftell(fp) - next_pos;
+	char *end_content = malloc(sizeof (char) * (end_length + 1));
+	if (!start_content || !end_content) {
+		fprintf(stderr, "Not enough memory when changing ini file.\n");
+		return -1;
+	}
+	fseek(fp, 0, SEEK_SET);
+	if (!fread(start_content, 1, found_pos, fp))
+		fprintf(stderr, "read ini file error.\n");
+	fseek(fp, next_pos, SEEK_SET);
+	if (!fread(end_content, 1, end_length, fp))
+		fprintf(stderr, "read ini file error.\n");
+	fclose(fp);
+	fp = fopen(config_file, "w");
+	fwrite(start_content, found_pos, 1, fp);
+	fwrite(end_content, end_length, 1, fp);
+	fclose(fp);
+	printf("shortcut deleted.\n");
+	return 1;
+}
+
+static void
 launcher_activate(struct launcher *widget)
 {
 	pid_t pid;
@@ -226,8 +370,8 @@ launcher_redraw_handler(struct widget *widget, void *data)
 		cairo_mask_surface(cr, launcher->icon,
 				   allocation.x, allocation.y);
 	}
-
 	cairo_destroy(cr);
+	cairo_surface_destroy(surface);
 }
 
 static int
@@ -241,6 +385,248 @@ launcher_motion_handler(struct widget *widget, struct input *input,
 	return CURSOR_LEFT_PTR;
 }
 
+static cairo_surface_t *
+create_drag_cursor(struct shortcut *shortcut,
+			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(shortcut->widget, &allocation);
+	display = window_get_display(shortcut->parent->window);
+	pointer = display_get_pointer_image(display, CURSOR_DRAGGING);
+
+	rectangle.width = shortcut_size + 2 * pointer->width;
+	rectangle.height = shortcut_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, shortcut->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);
+
+	shortcut->hotspot_x = pointer->width + x - allocation.x;
+	shortcut->hotspot_y = pointer->height + y - allocation.y;
+
+	return surface;
+}
+
+static void
+shortcut_activate(struct shortcut *widget)
+{
+	pid_t pid;
+
+	pid = fork();
+	if (pid < 0) {
+		fprintf(stderr, "fork failed: %m\n");
+		return;
+	}
+
+	if (pid)
+		return;
+
+	if (execl(widget->path, widget->path, NULL) < 0) {
+		fprintf(stderr, "execl '%s' failed: %m\n", widget->path);
+		exit(1);
+	}
+}
+
+static void
+shortcut_redraw_handler(struct widget *widget, void *data)
+{
+	struct shortcut *shortcut = data;
+	cairo_surface_t *surface;
+	struct rectangle allocation;
+	struct rectangle parent_allocation;
+	cairo_t *cr;
+
+	widget_get_allocation(widget, &allocation);
+
+	widget_get_allocation(shortcut->parent->widget, &parent_allocation);
+
+	/* avoid drawing out of bounding. */
+	if (allocation.x <= (0 - allocation.width)
+		|| allocation.x > parent_allocation.width)
+		return;
+
+	surface = window_get_surface(shortcut->parent->window);
+	cr = cairo_create(surface);
+
+	if (shortcut->pressed) {
+		allocation.x++;
+		allocation.y++;
+	}
+	if (!shortcut->dragging) {
+		cairo_set_source_surface(cr, shortcut->icon,
+					allocation.x, allocation.y);
+		cairo_paint(cr);
+
+		if (shortcut->focused) {
+			cairo_set_source_rgba(cr, 1.0, 1.0, 1.0, 0.4);
+			cairo_mask_surface(cr, shortcut->icon,
+					allocation.x, allocation.y);
+		}
+	}
+	cairo_destroy(cr);
+	cairo_surface_destroy(surface);
+}
+
+static int
+shortcut_motion_handler(struct widget *widget, struct input *input,
+			uint32_t time, float x, float y, void *data)
+{
+	struct shortcut *shortcut = 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((char *)shortcut->path),
+			x, allocation.y + allocation.height);
+
+	if (!shortcut->dragging && shortcut->pressed == 1
+		&& time - shortcut->click_time > 600)
+	{
+		widget_destroy_tooltip(widget);
+		// draging mode
+		shortcut->focused = 0;
+		if (gl_shortcut_drag)
+			free(gl_shortcut_drag);
+		gl_shortcut_drag = shortcut;
+		display = window_get_display(shortcut->parent->window);
+		compositor = display_get_compositor(display);
+		serial = display_get_serial(display);
+		shortcut->drag_surface = wl_compositor_create_surface(compositor);
+
+		input_ungrab(input);
+
+		shortcut->data_source = display_create_data_source(display);
+		wl_data_source_add_listener(shortcut->data_source,
+				&data_source_listener,
+				shortcut);
+		wl_data_source_offer(shortcut->data_source,
+				"application/desktop-shortct");
+		wl_data_source_offer(shortcut->data_source,
+				"text/plain; charset=utf-8");
+		wl_data_device_start_drag(input_get_data_device(input),
+				shortcut->data_source,
+				window_get_wl_surface(shortcut->parent->window),
+				shortcut->drag_surface,
+				serial);
+
+		input_set_pointer_image(input, CURSOR_DRAGGING);
+
+		shortcut->opaque =
+				create_drag_cursor(shortcut, x, y, 0.95);
+		shortcut->translucent =
+				create_drag_cursor(shortcut, x, y, 0.2);
+
+		buffer = display_get_buffer_for_surface(display, shortcut->translucent);
+
+		pointer = display_get_pointer_image(display, CURSOR_DRAGGING);
+
+		wl_surface_attach(shortcut->drag_surface, buffer,
+				-shortcut->hotspot_x, -shortcut->hotspot_y);
+		wl_surface_damage(shortcut->drag_surface, 0, 0,
+				shortcut_size + 2 * pointer->width,
+				shortcut_size + 2 * pointer->height);
+
+		shortcut->dragging = 1;
+	} else if (!shortcut->dragging && shortcut->pressed == 1) {
+		shortcut->pressed = 0;
+		widget_schedule_redraw(shortcut->widget);
+	}
+
+	return CURSOR_HAND1;
+}
+
+static void
+shortcut_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/desktop-shortct") != 0) {
+		return;
+	}
+	if (x > trash_x - trash_w / 2 && x < trash_x + trash_w / 2
+		&& y > trash_y - trash_h / 2 && y < trash_y + trash_h / 2) {
+		input_accept(input, NULL);
+	} else {
+		input_accept(input, types[0]);
+	}
+}
+
+static void
+shortcut_drop_handler(struct window *window, struct input *input,
+		 int32_t x, int32_t y, void *data)
+{
+	if (gl_shortcut_drag == NULL
+		|| gl_shortcut_drag->widget == NULL) {
+		fprintf(stderr, "ignoring drop from another client\n");
+		return;
+	}
+
+	struct shortcut *shortcut = gl_shortcut_drag;
+	struct layout *layout = shortcut->parent_layout;
+	struct shortcut *temp_shortcut;
+	int left, right, top, bottom;
+
+	// set bounds
+	left = trash_x - trash_w / 2;
+	right = trash_x + trash_w / 2;
+	top = trash_y - trash_h / 2;
+	bottom = trash_y + trash_h / 2;
+
+	shortcut->dragging = 0;
+	shortcut->pressed = 0;
+
+	if (x > left && x < right && y > top && y < bottom) {
+		if (layout_delete_shortcut(shortcut)) {
+			wl_list_remove(&shortcut->link);
+			widget_destroy(shortcut->widget);
+			shortcut->widget = NULL;
+			free((char*)shortcut->path);
+			cairo_surface_destroy(shortcut->icon);
+			wl_data_source_destroy(shortcut->data_source);
+			wl_surface_destroy(shortcut->drag_surface);
+			cairo_surface_destroy(shortcut->translucent);
+			cairo_surface_destroy(shortcut->opaque);
+			int i = 1;
+			wl_list_for_each(temp_shortcut, &layout->shortcut_list, link) {
+				temp_shortcut->index = i++;
+			}
+			window_schedule_redraw(layout->parent->window);
+		}
+	} else {
+		gl_shortcut_drag = NULL;
+	}
+	window_schedule_redraw(shortcut->parent->window);
+}
+
 static void
 set_hex_color(cairo_t *cr, uint32_t color)
 {
@@ -306,7 +692,273 @@ launcher_button_handler(struct widget *widget,
 		launcher_activate(launcher);
 	} else if (state == WL_POINTER_BUTTON_STATE_PRESSED)
 		launcher->pressed = 1;
+}
+
+static void
+shortcut_button_handler(struct widget *widget,
+			struct input *input, uint32_t time,
+			uint32_t button,
+			enum wl_pointer_button_state state, void *data)
+{
+	struct shortcut *shortcut;
+	struct rectangle allocation;
+	int32_t x, y;
+
+	widget_get_allocation(widget, &allocation);
+	input_get_position(input, &x, &y);
 
+	shortcut = widget_get_user_data(widget);
+	widget_schedule_redraw(widget);
+	if (state == WL_POINTER_BUTTON_STATE_RELEASED) {
+		shortcut->click_time = 0;
+		if (shortcut->pressed && !shortcut->dragging)
+			shortcut_activate(shortcut);
+		shortcut->dragging = 0;
+		shortcut->pressed = 0;
+	} else if (state == WL_POINTER_BUTTON_STATE_PRESSED) {
+		shortcut->pressed = 1;
+		shortcut->click_time = time;
+	}
+}
+
+static void
+layout_frame_callback(void *data, struct wl_callback *callback, uint32_t time)
+{
+	struct layout *layout = data;
+
+	if (abs(layout->offset) < layout->s_speed) {
+		/* stop switching */
+		layout->offset = 0;
+		layout->switching = 0;
+	} else {
+		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 shortcut *shortcut;
+	struct rectangle allocation;
+	const int rows = 3, columns = 4, icon_width = shortcut_size,
+				icon_height = shortcut_size;
+	int x, y, i, width, height, vpadding, hpadding;
+	struct wl_callback *callback;
+
+	if (layout->showing != 1)
+	{
+		return;
+	}
+
+	widget_get_allocation(widget, &allocation);
+
+	width = allocation.width - columns * icon_width;
+	/* width between icons */
+	hpadding = width / (columns - 1);
+
+	height = allocation.height - rows * icon_height;
+	vpadding = height / (rows - 1);
+
+	x = allocation.x;
+	y = allocation.y;
+	i = 0;
+
+	wl_list_for_each(shortcut, &layout->shortcut_list, link) {
+		widget_set_allocation(shortcut->widget,
+				x + layout->offset, y, icon_width, icon_height);
+		x += icon_width + hpadding;
+		i++;
+		if (i == columns) {
+			x = allocation.x;
+			y += icon_height + vpadding;
+			i = 0;
+		}
+	}
+
+	if (layout->offset < 0 && layout->link.next != layout->layout_list){
+		/* need to draw right layout */
+		x = allocation.x + layout->offset
+			+ allocation.width + 2 * layout->hmargin;
+		y = allocation.y;
+		i = 0;
+
+		layout = __wl_container_of(layout->link.next, layout, link);
+
+		/* add background width */
+		wl_list_for_each(shortcut, &layout->shortcut_list, link) {
+			if (x < allocation.width + 2 * layout->hmargin){
+				/* show icon */
+				widget_set_allocation(shortcut->widget,
+							x, y, icon_width, icon_height);
+			} else {
+				/* set icon out -- see launcher_redraw_handler */
+				widget_set_allocation(shortcut->widget, 0, 0, 0, 0);
+			}
+			x += icon_width + hpadding;
+			i++;
+			if (i == columns) {
+				x = allocation.x + layout->offset
+					+ allocation.width + 2 * layout->hmargin;
+				y += icon_height + vpadding;
+				i = 0;
+			}
+		}
+	} else if (layout->offset > 0 && layout->link.prev != layout->layout_list) {
+		/* need to draw left layout */
+		width = allocation.x + layout->offset - 2 * layout->hmargin;
+		x = width - allocation.width;
+		y = allocation.y;
+		i = 0;
+
+		layout = __wl_container_of(layout->link.prev, layout, link);
+
+		/* add layout width */
+		wl_list_for_each(shortcut, &layout->shortcut_list, link) {
+			if(x > -icon_width) {
+				/* show icon */
+				widget_set_allocation(shortcut->widget,
+							x, y, icon_width, icon_height);
+			} else {
+				/* set icon out -- see launcher_redraw_handler */
+				widget_set_allocation(shortcut->widget, 0, 0, 0, 0);
+			}
+			x += icon_width + hpadding;
+			i++;
+			if (i == columns) {
+				x = width - allocation.width;
+				y += icon_height + vpadding;
+				i = 0;
+			}
+		}
+	}
+
+	if (current->switching) {
+		callback = wl_surface_frame(window_get_wl_surface(current->parent->window));
+		wl_callback_add_listener(callback, &layout_listener, current);
+	}
+}
+
+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 shortcut *shortcut;
+	int y;
+	int width;
+	int fast_slide = 0;
+	struct rectangle allocation;
+
+	layout = widget_get_user_data(widget);
+
+	if (state == WL_POINTER_BUTTON_STATE_RELEASED) {
+		layout->pressed = 0;
+
+		/* do offset check to determine switch direction */
+		widget_get_allocation(widget, &allocation);
+		width = allocation.width + layout->hmargin * 2;
+
+		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 */
+			layout->showing = 0;
+			widget_set_allocation(layout->widget, 0, 0, 0, 0);
+			/* set icons out of bound -- see launcher_redraw_handler */
+			wl_list_for_each(shortcut, &layout->shortcut_list, link) {
+				widget_set_allocation(shortcut->widget,0,0,0,0);
+		}
+
+		if (layout->offset < 0) {
+			/* move to next */
+			if (fast_slide)
+				layout->offset += (layout->offset > 0)? -width / 2 : width / 2;
+			next_layout->offset = width + layout->offset;
+			next_layout->showing = 1;
+			/* switch animation */
+			next_layout->switching = -1;
+			widget_set_allocation(next_layout->widget,
+							layout->hmargin, layout->vmargin,
+							allocation.width, allocation.height);
+		} else {
+			/* move to previous */
+			if (fast_slide)
+				layout->offset += (layout->offset > 0)? -width / 2 : width / 2;
+			prev_layout->offset = layout->offset - width;
+			prev_layout->showing = 1;
+			/* switch animation */
+			prev_layout->switching = 1;
+			widget_set_allocation(prev_layout->widget,
+						layout->hmargin, layout->vmargin,
+						allocation.width, allocation.height);
+		}
+	} else {
+		/* back to itself */
+		layout->switching = (layout->offset > 0)? -1 : 1;
+		if (fast_slide && layout->offset != 0)
+				layout->offset += (layout->offset > 0)? -width / 2 : width / 2;
+		if (prev_layout != NULL) {
+			wl_list_for_each(shortcut, &prev_layout->shortcut_list, link) {
+                widget_set_allocation(shortcut->widget,0,0,0,0);
+            }
+		}
+		if (next_layout != NULL) {
+			wl_list_for_each(shortcut, &next_layout->shortcut_list, link) {
+				widget_set_allocation(shortcut->widget,0,0,0,0);
+			}
+		}
+	}
+	/* update scene */
+	widget_schedule_redraw(layout->widget);
+	} else if (state == WL_POINTER_BUTTON_STATE_PRESSED) {
+		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;
+
+	if (layout->pressed)
+	{
+		layout->offset += x - layout->last_x;
+		layout->last_x = x;
+		widget_schedule_redraw(layout->widget);
+	}
+
+	return CURSOR_LEFT_PTR;
 }
 
 static void
@@ -359,6 +1011,7 @@ panel_clock_redraw_handler(struct widget *widget, void *data)
 	cairo_set_source_rgb(cr, 1, 1, 1);
 	cairo_show_text(cr, string);
 	cairo_destroy(cr);
+	cairo_surface_destroy(surface);
 }
 
 static int
@@ -463,7 +1116,6 @@ panel_create(struct display *display)
 	memset(panel, 0, sizeof *panel);
 
 	panel->base.configure = panel_configure;
-
 	panel->base.window = window_create_custom(display);
 	panel->base.widget = window_add_widget(panel->base.window, panel);
 	wl_list_init(&panel->launcher_list);
@@ -481,28 +1133,73 @@ panel_create(struct display *display)
 }
 
 static void
-background_add_shortcut(struct background *background, const char *icon, const char *path)
+layout_add_shortcut(struct background *background, const char *icon, const char *path)
 {
-	struct launcher *shortcut;
+	struct shortcut *shortcut;
+	struct layout *layout = NULL;
+
+	wl_list_for_each(layout, &background->layout_list, link) {
+	}
+	/* find the last layout */
+	layout = __wl_container_of(layout->link.prev, layout, link);
 
 	shortcut = malloc(sizeof *shortcut);
 	memset(shortcut, 0, sizeof *shortcut);
 	shortcut->icon = cairo_image_surface_create_from_png(icon);
 	shortcut->path = strdup(path);
-	shortcut->parent = &background->base;
-	wl_list_insert(background->shortcut_list.prev, &shortcut->link);
 
-	shortcut->widget = widget_add_widget(background->base.widget, shortcut);
+	shortcut->parent = layout->parent;
+	shortcut->parent_layout = layout;
+
+	wl_list_insert(layout->shortcut_list.prev, &shortcut->link);
+	shortcut->layout_index = wl_list_length(layout->layout_list);
+	shortcut->index = wl_list_length(&layout->shortcut_list);
+
+	shortcut->widget = widget_add_widget(layout->widget, shortcut);
 	widget_set_enter_handler(shortcut->widget,
-				 launcher_enter_handler);
+				  launcher_enter_handler);
 	widget_set_leave_handler(shortcut->widget,
-				 launcher_leave_handler);
+				  launcher_leave_handler);
 	widget_set_button_handler(shortcut->widget,
-				  launcher_button_handler);
+				  shortcut_button_handler);
 	widget_set_redraw_handler(shortcut->widget,
-				  launcher_redraw_handler);
+				  shortcut_redraw_handler);
 	widget_set_motion_handler(shortcut->widget,
-				  launcher_motion_handler);
+				  shortcut_motion_handler);
+}
+
+static void
+background_add_layout(struct background *background)
+{
+	struct layout *layout;
+	struct rectangle allocation;
+	widget_get_allocation(background->base.widget, &allocation);
+
+	layout = malloc(sizeof *layout);
+	memset(layout, 0, sizeof *layout);
+	wl_list_init(&layout->shortcut_list);
+	layout->widget = widget_add_widget(background->base.widget, layout);
+	layout->parent = &background->base;
+	layout->hmargin = 100;
+	layout->vmargin = 50;
+	layout->switching = 0;
+	layout->s_speed = 30;
+	if (wl_list_empty(&background->layout_list))
+		layout->showing = 1;
+	else
+		layout->showing = 0;
+	layout->offset = 0;
+
+	/* let layout know number of layouts */
+	layout->layout_list = &background->layout_list;
+
+	wl_list_insert(background->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);
 }
 
 static void
@@ -535,20 +1232,65 @@ enum {
 	BACKGROUND_TILE
 };
 
+/*simple draw trash function*/
+static void background_draw_trash(void *data, int x, int y){
+	int w, h;
+	cairo_t *cr;
+	cairo_surface_t *surface;
+	struct background *background = data;
+
+	if (key_trash_image) {
+		if (!trash_surface) {
+			trash_surface = load_cairo_surface(key_trash_image);
+		}
+	} else {
+		trash_surface = NULL;
+	}
+
+	if (!trash_surface) {
+		fprintf(stderr, "no trash image.\n");
+		return;
+	}
+
+	// get image size
+	w = cairo_image_surface_get_width(trash_surface);
+	h = cairo_image_surface_get_height(trash_surface);
+
+	// set up trash allocation
+	trash_x = x;
+	trash_y = y;
+	trash_w = w;
+	trash_h = h;
+
+	surface = window_get_surface(background->base.window);
+	cr = cairo_create(surface);
+
+	cairo_set_source_surface(cr, trash_surface,
+				 x - w / 2, y - h / 2);
+	cairo_paint(cr);
+
+	// highlight trash
+	if (trash_highlight) {
+		cairo_set_source_rgba(cr, 1.0, 1.0, 1.0, 0.4);
+		cairo_mask_surface(cr, trash_surface,
+				x - w / 2, y - h / 2);
+	}
+	cairo_destroy(cr);
+	cairo_surface_destroy(surface);
+}
+
 static void
 background_draw(struct widget *widget, void *data)
 {
 	struct background *background = data;
-	cairo_surface_t *surface, *image;
+	cairo_surface_t *surface;
 	cairo_pattern_t *pattern;
 	cairo_matrix_t matrix;
 	cairo_t *cr;
 	double sx, sy;
 	struct rectangle allocation;
 	int type = -1;
-	struct launcher *shortcut;
-	const int rows = 3, columns = 4, icon_width = 128, icon_height = 128;
-	int x, y, i, width, height, vmargin, hmargin, vpadding, hpadding;
+	struct layout *layout;
 
 	surface = window_get_surface(background->base.window);
 
@@ -558,9 +1300,10 @@ background_draw(struct widget *widget, void *data)
 	cairo_paint(cr);
 
 	widget_get_allocation(widget, &allocation);
-	image = NULL;
-	if (key_background_image)
-		image = load_cairo_surface(key_background_image);
+	if (key_background_image && background->image == NULL)
+		background->image = load_cairo_surface(key_background_image);
+	else if (!key_background_image)
+		background->image = NULL;
 
 	if (strcmp(key_background_type, "scale") == 0)
 		type = BACKGROUND_SCALE;
@@ -570,13 +1313,13 @@ background_draw(struct widget *widget, void *data)
 		fprintf(stderr, "invalid background-type: %s\n",
 			key_background_type);
 
-	if (image && type != -1) {
-		pattern = cairo_pattern_create_for_surface(image);
+	if (background->image && type != -1) {
+		pattern = cairo_pattern_create_for_surface(background->image);
 		switch (type) {
 		case BACKGROUND_SCALE:
-			sx = (double) cairo_image_surface_get_width(image) /
+			sx = (double) cairo_image_surface_get_width(background->image) /
 				allocation.width;
-			sy = (double) cairo_image_surface_get_height(image) /
+			sy = (double) cairo_image_surface_get_height(background->image) /
 				allocation.height;
 			cairo_matrix_init_scale(&matrix, sx, sy);
 			cairo_pattern_set_matrix(pattern, &matrix);
@@ -587,40 +1330,30 @@ background_draw(struct widget *widget, void *data)
 		}
 		cairo_set_source(cr, pattern);
 		cairo_pattern_destroy (pattern);
-		cairo_surface_destroy(image);
 	} else {
 		set_hex_color(cr, key_background_color);
 	}
 
 	cairo_paint(cr);
 
-	/* draw shortcuts */
-	cairo_set_operator(cr, CAIRO_OPERATOR_OVER);
-
-	width = allocation.width - columns * icon_width;
-	hpadding = width / (columns + 1);
-	hmargin = (width - hpadding * (columns - 1)) / 2;
-
-	height = allocation.height - rows * icon_height;
-	vpadding = height / (rows + 1);
-	vmargin = (height - vpadding * (rows - 1)) / 2;
-
-	x = hmargin;
-	y = vmargin;
-	i = 0;
-
-	wl_list_for_each(shortcut, &background->shortcut_list, link) {
-		widget_set_allocation(shortcut->widget,
-				      x, y, icon_width, icon_height);
-		x += icon_width + hpadding;
-		i++;
-		if (i == columns) {
-			x = hmargin;
-			y += icon_height + vpadding;
-			i = 0;
+	/* draw current layout */
+	wl_list_for_each(layout, &background->layout_list, link) {
+		if (layout->showing) {
+			widget_set_allocation(layout->widget,
+							  layout->hmargin, layout->vmargin,
+							  allocation.width - 2 * layout->hmargin,
+							  allocation.height - 2 * layout->vmargin);
+			break;
 		}
 	}
 
+	/* draw trash if dragging*/
+	if(gl_shortcut_drag && gl_shortcut_drag->widget){
+		background_draw_trash(background,
+					allocation.width * 0.75,
+					allocation.height * 0.75);
+	}
+
 	cairo_destroy(cr);
 	cairo_surface_destroy(surface);
 }
@@ -749,16 +1482,16 @@ unlock_dialog_create(struct desktop *desktop)
 
 	window_set_user_data(dialog->window, dialog);
 	window_set_keyboard_focus_handler(dialog->window,
-					  unlock_dialog_keyboard_focus_handler);
+					unlock_dialog_keyboard_focus_handler);
 	dialog->button = widget_add_widget(dialog->widget, dialog);
 	widget_set_redraw_handler(dialog->widget,
-				  unlock_dialog_redraw_handler);
+					unlock_dialog_redraw_handler);
 	widget_set_enter_handler(dialog->button,
-				 unlock_dialog_widget_enter_handler);
+					unlock_dialog_widget_enter_handler);
 	widget_set_leave_handler(dialog->button,
-				 unlock_dialog_widget_leave_handler);
+					unlock_dialog_widget_leave_handler);
 	widget_set_button_handler(dialog->button,
-				  unlock_dialog_button_handler);
+					unlock_dialog_button_handler);
 
 	desktop_shell_set_lock_surface(desktop->shell,
 				       window_get_wl_surface(dialog->window));
@@ -876,9 +1609,13 @@ background_create(struct desktop *desktop)
 
 	background->base.configure = background_configure;
 	background->base.window = window_create_custom(desktop->display);
-	background->base.widget = window_add_widget(background->base.window, background);
+	background->base.widget = window_add_widget(background->base.window,
+										background);
+
+	window_set_data_handler(background->base.window, shortcut_data_handler);
+	window_set_drop_handler(background->base.window, shortcut_drop_handler);
 
-	wl_list_init(&background->shortcut_list);
+	wl_list_init(&background->layout_list);
 	window_set_user_data(background->base.window, background);
 	widget_set_redraw_handler(background->base.widget, background_draw);
 
@@ -957,7 +1694,7 @@ shortcut_section_done(void *data)
 	}
 
 	wl_list_for_each(output, &desktop->outputs, link) {
-		background_add_shortcut(output->background,
+		layout_add_shortcut(output->background,
 				        key_shortcut_icon, key_shortcut_path);
 	}
 
@@ -968,6 +1705,17 @@ shortcut_section_done(void *data)
 }
 
 static void
+layout_section_done(void *data)
+{
+	struct desktop *desktop = data;
+	struct output *output;
+
+	wl_list_for_each(output, &desktop->outputs, link) {
+		background_add_layout(output->background);
+	}
+}
+
+static void
 panel_launcher_section_done(void *data)
 {
 	struct desktop *desktop = data;
diff --git a/weston.ini b/weston.ini
index 26b6587..234b7d5 100644
--- a/weston.ini
+++ b/weston.ini
@@ -27,6 +27,7 @@ path=/usr/bin/google-chrome
 icon=/usr/share/icons/gnome/24x24/apps/arts.png
 path=./clients/flower
 
+[layout]
 [shortcut]
 icon=/usr/share/icons/gnome/24x24/apps/utilities-terminal.png
 path=/usr/bin/weston-terminal
@@ -37,6 +38,7 @@ path=/usr/bin/weston-terminal
 
 #==============================================================================
 
+[layout]
 [shortcut]
 icon=/usr/share/icons/hicolor/24x24/apps/google-chrome.png
 path=/usr/bin/google-chrome
-- 
1.7.11.1



More information about the wayland-devel mailing list