[PATCH weston v2] desktop-shell: Implement panel window list.

Scott Moreau oreaus at gmail.com
Mon Oct 1 04:02:36 PDT 2012


The compositor sends surface info as necessary to the wl_shell client, using
a special interface extension. Surfaces are identified by a specific id value.
The value of the id isn't particularly important as long as 1) the value is
unique for each surface 2) the client and compositor use the same id values.
In this implementation, the id is a pointer to a struct weston_surface.

---

v2:

* Optimized drawing by setting window list size and item focus color upfront
* Removed goto hack in load_icon_or_fallback()
* General cleanup

 clients/desktop-shell.c    | 457 +++++++++++++++++++++++++++++++++++++++++++--
 protocol/desktop-shell.xml |  27 +++
 src/compositor.c           |   2 +
 src/compositor.h           |   1 +
 src/shell.c                |  58 +++++-
 5 files changed, 527 insertions(+), 18 deletions(-)

diff --git a/clients/desktop-shell.c b/clients/desktop-shell.c
index 588dc1c..3ee3577 100644
--- a/clients/desktop-shell.c
+++ b/clients/desktop-shell.c
@@ -44,6 +44,8 @@
 
 #include "desktop-shell-client-protocol.h"
 
+#define MIN(x, y) (((x) < (y)) ? (x) : (y))
+
 extern char **environ; /* defined by libc */
 
 struct desktop {
@@ -52,6 +54,7 @@ struct desktop {
 	struct unlock_dialog *unlock_dialog;
 	struct task unlock_task;
 	struct wl_list outputs;
+	uint32_t output_count;
 
 	struct window *grab_window;
 	struct widget *grab_widget;
@@ -60,28 +63,44 @@ struct desktop {
 };
 
 struct surface {
+	struct wl_list item_list;
+	uint32_t id;
+	uint32_t output_mask;
+	char *title;
+};
+
+struct resize {
 	void (*configure)(void *data,
 			  struct desktop_shell *desktop_shell,
 			  uint32_t edges, struct window *window,
 			  int32_t width, int32_t height);
 };
 
+struct rgba {
+	float r, g, b, a;
+};
+
 struct panel {
-	struct surface base;
+	struct resize base;
 	struct window *window;
 	struct widget *widget;
 	struct wl_list launcher_list;
+	struct wl_list window_list;
+	uint32_t surface_count;
 	struct panel_clock *clock;
+	struct rectangle window_list_rect;
+	struct rgba focused_item;
 };
 
 struct background {
-	struct surface base;
+	struct resize base;
 	struct window *window;
 	struct widget *widget;
 };
 
 struct output {
 	struct wl_output *output;
+	uint32_t id;
 	struct wl_list link;
 
 	struct panel *panel;
@@ -99,6 +118,16 @@ struct panel_launcher {
 	struct wl_array argv;
 };
 
+struct list_item {
+	struct surface *surface;
+	struct widget *widget;
+	struct panel *panel;
+	cairo_surface_t *icon;
+	int focused, pressed;
+	struct wl_list link;
+	struct wl_list surface_link;
+};
+
 struct panel_clock {
 	struct widget *widget;
 	struct panel *panel;
@@ -249,6 +278,19 @@ set_hex_color(cairo_t *cr, uint32_t color)
 }
 
 static void
+get_hex_color_rgba(uint32_t color,
+				float *r,
+				float *g,
+				float *b,
+				float *a)
+{
+	*r = ((color >> 16) & 0xff) / 255.0;
+	*g = ((color >>  8) & 0xff) / 255.0;
+	*b = ((color >>  0) & 0xff) / 255.0;
+	*a = ((color >> 24) & 0xff) / 255.0;
+}
+
+static void
 panel_redraw_handler(struct widget *widget, void *data)
 {
 	cairo_surface_t *surface;
@@ -303,6 +345,131 @@ panel_launcher_button_handler(struct widget *widget,
 }
 
 static void
+panel_list_item_redraw_handler(struct widget *widget, void *data)
+{
+	cairo_t *cr;
+	cairo_surface_t *surface;
+	struct list_item *item = data;
+	struct rectangle allocation;
+	cairo_text_extents_t extents;
+	cairo_font_extents_t font_extents;
+	int icon_width;
+	unsigned int dots = 3;
+	char title[128];
+
+	widget_get_allocation(widget, &allocation);
+	if (allocation.width == 0)
+		return;
+
+	surface = window_get_surface(item->panel->window);
+	cr = cairo_create(surface);
+
+	if (item->focused) {
+		cairo_set_source_rgba(cr,
+					item->panel->focused_item.r,
+					item->panel->focused_item.g,
+					item->panel->focused_item.b,
+					item->panel->focused_item.a);
+		cairo_move_to(cr, allocation.x, allocation.y);
+		cairo_line_to(cr, allocation.x + allocation.width, allocation.y);
+		cairo_line_to(cr, allocation.x + allocation.width, allocation.y + allocation.height);
+		cairo_line_to(cr, allocation.x, allocation.y + allocation.height);
+		cairo_line_to(cr, allocation.x, allocation.y);
+		cairo_fill(cr);
+	}
+
+	icon_width = cairo_image_surface_get_width(item->icon);
+	if (allocation.width > icon_width * 2) {
+		cairo_set_source_surface(cr, item->icon,
+					 allocation.x, allocation.y);
+		cairo_paint(cr);
+	} else
+		icon_width = 0;
+
+	strcpy(title, item->surface->title);
+	cairo_select_font_face(cr, "helvetica",
+			       CAIRO_FONT_SLANT_NORMAL,
+			       CAIRO_FONT_WEIGHT_NORMAL);
+	cairo_set_font_size(cr, 14);
+	cairo_text_extents(cr, title, &extents);
+
+	/* If the string is too long, clip text to button width */
+	while (extents.width > (allocation.width - (10 + icon_width))) {
+		title[strlen(title) - 1] = '\0';
+		cairo_text_extents(cr, title, &extents);
+		if (extents.width <= 0) {
+			title[0] = '\0';
+			break;
+		}
+	}
+
+	/* If the text is clipped, add an ellipsis */
+	if (strlen(title) < dots)
+		dots = strlen(title) + 1;
+	if (strlen(title) != strlen(item->surface->title))
+		while (dots-- > 0)
+			title[strlen(title) - dots] = '.';
+
+	cairo_font_extents (cr, &font_extents);
+	cairo_move_to(cr, allocation.x + 10 + icon_width,
+		      allocation.y + 3 * (allocation.height >> 2) + 1);
+	cairo_set_source_rgb(cr, 0, 0, 0);
+	cairo_show_text(cr, title);
+	cairo_move_to(cr, allocation.x + 9 + icon_width,
+		      allocation.y + 3 * (allocation.height >> 2));
+	if (item->focused)
+		cairo_set_source_rgb(cr, 1, 1, 1);
+	else
+		cairo_set_source_rgb(cr, 0.85, 0.85, 0.85);
+	cairo_show_text(cr, title);
+	cairo_destroy(cr);
+}
+
+static int
+panel_list_item_motion_handler(struct widget *widget, struct input *input,
+			      uint32_t time, float x, float y, void *data)
+{
+	struct list_item *item = data;
+
+	widget_set_tooltip(widget, basename((char *)item->surface->title), x, y);
+
+	return CURSOR_LEFT_PTR;
+}
+
+static int
+panel_list_item_enter_handler(struct widget *widget, struct input *input,
+			     float x, float y, void *data)
+{
+	struct list_item *item = data;
+
+	item->focused = 1;
+	widget_schedule_redraw(widget);
+
+	return CURSOR_LEFT_PTR;
+}
+
+static void
+panel_list_item_leave_handler(struct widget *widget,
+			     struct input *input, void *data)
+{
+	struct list_item *item = data;
+
+	item->focused = 0;
+	widget_destroy_tooltip(widget);
+	widget_schedule_redraw(widget);
+}
+
+static void
+panel_list_item_button_handler(struct widget *widget,
+			      struct input *input, uint32_t time,
+			      uint32_t button,
+			      enum wl_pointer_button_state state, void *data)
+{
+	widget_schedule_redraw(widget);
+	/* TODO: Toggle minimize */
+}
+
+static void
 clock_func(struct task *task, uint32_t events)
 {
 	struct panel_clock *clock =
@@ -337,7 +504,7 @@ panel_clock_redraw_handler(struct widget *widget, void *data)
 
 	surface = window_get_surface(clock->panel->window);
 	cr = cairo_create(surface);
-	cairo_select_font_face(cr, "sans",
+	cairo_select_font_face(cr, "helvetica",
 			       CAIRO_FONT_SLANT_NORMAL,
 			       CAIRO_FONT_WEIGHT_NORMAL);
 	cairo_set_font_size(cr, 14);
@@ -415,11 +582,16 @@ panel_resize_handler(struct widget *widget,
 		     int32_t width, int32_t height, void *data)
 {
 	struct panel_launcher *launcher;
+	struct rectangle launcher_rect;
+	struct rectangle clock_rect;
+	struct rectangle panel_rect;
 	struct panel *panel = data;
 	int x, y, w, h;
-	
+
 	x = 10;
 	y = 16;
+	launcher_rect.x = x;
+	launcher_rect.y = y;
 	wl_list_for_each(launcher, &panel->launcher_list, link) {
 		w = cairo_image_surface_get_width(launcher->icon);
 		h = cairo_image_surface_get_height(launcher->icon);
@@ -427,12 +599,24 @@ panel_resize_handler(struct widget *widget,
 				      x, y - h / 2, w + 1, h + 1);
 		x += w + 10;
 	}
-	h=20;
+	launcher_rect.width = x - launcher_rect.x;
+	launcher_rect.height = 24;
 	w=170;
+	h=20;
 
 	if (panel->clock)
 		widget_set_allocation(panel->clock->widget,
 				      width - w - 8, y - h / 2, w + 1, h + 1);
+
+	widget_get_allocation(panel->clock->widget, &clock_rect);
+	widget_get_allocation(panel->widget, &panel_rect);
+
+	panel->window_list_rect.x = launcher_rect.x + launcher_rect.width;
+	panel->window_list_rect.y = 2;
+	panel->window_list_rect.width = panel_rect.width -
+					panel->window_list_rect.x -
+					(clock_rect.width + 20);
+	panel->window_list_rect.height = 28;
 }
 
 static void
@@ -441,12 +625,31 @@ panel_configure(void *data,
 		uint32_t edges, struct window *window,
 		int32_t width, int32_t height)
 {
-	struct surface *surface = window_get_user_data(window);
+	struct resize *surface = window_get_user_data(window);
 	struct panel *panel = container_of(surface, struct panel, base);
 
 	window_schedule_resize(panel->window, width, 32);
 }
 
+static void
+panel_set_list_item_focus_color(struct panel *panel)
+{
+	float r, g, b, a;
+
+	/* Consider panel color when choosing item highlight color */
+	get_hex_color_rgba(key_panel_color, &r, &b, &g, &a);
+	if (r += 0.2, g += 0.2, b += 0.2, r > 1.0 || g > 1.0 || b > 1.0) {
+		panel->focused_item.r = 0.6;
+		panel->focused_item.g = 0.6;
+		panel->focused_item.b = 0.6;
+	} else {
+		panel->focused_item.r = r;
+		panel->focused_item.g = g;
+		panel->focused_item.b = b;
+	}
+	panel->focused_item.a = 0.75;
+}
+
 static struct panel *
 panel_create(struct display *display)
 {
@@ -459,6 +662,7 @@ panel_create(struct display *display)
 	panel->window = window_create_custom(display);
 	panel->widget = window_add_widget(panel->window, panel);
 	wl_list_init(&panel->launcher_list);
+	wl_list_init(&panel->window_list);
 
 	window_set_title(panel->window, "panel");
 	window_set_user_data(panel->window, panel);
@@ -466,8 +670,10 @@ panel_create(struct display *display)
 	widget_set_redraw_handler(panel->widget, panel_redraw_handler);
 	widget_set_resize_handler(panel->widget, panel_resize_handler);
 	widget_set_button_handler(panel->widget, panel_button_handler);
-	
+
+	panel->surface_count = 0;
 	panel_add_clock(panel);
+	panel_set_list_item_focus_color(panel);
 
 	return panel;
 }
@@ -475,18 +681,20 @@ panel_create(struct display *display)
 static cairo_surface_t *
 load_icon_or_fallback(const char *icon)
 {
-	cairo_surface_t *surface = cairo_image_surface_create_from_png(icon);
+	cairo_surface_t *surface;
 	cairo_t *cr;
 
-	if (cairo_surface_status(surface) == CAIRO_STATUS_SUCCESS)
-		return surface;
+	if (icon) {
+		surface = cairo_image_surface_create_from_png(icon);
+		if (cairo_surface_status(surface) == CAIRO_STATUS_SUCCESS)
+			return surface;
 
-	cairo_surface_destroy(surface);
-	fprintf(stderr, "ERROR loading icon from file '%s'\n", icon);
+		cairo_surface_destroy(surface);
+		fprintf(stderr, "ERROR loading icon from file '%s'\n", icon);
+	}
 
 	/* draw fallback icon */
-	surface = cairo_image_surface_create(CAIRO_FORMAT_ARGB32,
-					     20, 20);
+	surface = cairo_image_surface_create(CAIRO_FORMAT_ARGB32, 20, 20);
 	cr = cairo_create(surface);
 
 	cairo_set_source_rgba(cr, 0.8, 0.8, 0.8, 1);
@@ -506,6 +714,44 @@ load_icon_or_fallback(const char *icon)
 	return surface;
 }
 
+static struct list_item *
+panel_add_list_item(struct panel *panel, const char *icon, const char *text)
+{
+	struct list_item *item;
+	item = malloc(sizeof *item);
+	memset(item, 0, sizeof *item);
+
+	item->icon = load_icon_or_fallback(icon);
+
+	item->panel = panel;
+	wl_list_insert(panel->window_list.prev, &item->link);
+	panel->surface_count++;
+
+	item->widget = widget_add_widget(panel->widget, item);
+	widget_set_enter_handler(item->widget,
+				 panel_list_item_enter_handler);
+	widget_set_leave_handler(item->widget,
+				   panel_list_item_leave_handler);
+	widget_set_button_handler(item->widget,
+				    panel_list_item_button_handler);
+	widget_set_redraw_handler(item->widget,
+				  panel_list_item_redraw_handler);
+	widget_set_motion_handler(item->widget,
+				  panel_list_item_motion_handler);
+
+	return item;
+}
+
+static void
+panel_remove_list_item(struct list_item *item)
+{
+	item->panel->surface_count--;
+	wl_list_remove(&item->link);
+	wl_list_remove(&item->surface_link);
+	widget_destroy(item->widget);
+	free(item);
+}
+
 static void
 panel_add_launcher(struct panel *panel, const char *icon, const char *path)
 {
@@ -810,7 +1056,7 @@ desktop_shell_configure(void *data,
 			int32_t width, int32_t height)
 {
 	struct window *window = wl_surface_get_user_data(surface);
-	struct surface *s = window_get_user_data(window);
+	struct resize *s = window_get_user_data(window);
 
 	s->configure(data, desktop_shell, edges, window, width, height);
 }
@@ -879,10 +1125,181 @@ desktop_shell_grab_cursor(void *data,
 	}
 }
 
+static struct surface*
+create_surface(void)
+{
+	struct surface *surface;
+
+	surface = calloc(1, sizeof *surface);
+
+	if (!surface) {
+		fprintf(stderr, "ERROR: Failed to allocate memory!\n");
+		exit(-1);
+	}
+
+	wl_list_init(&surface->item_list);
+
+	return surface;
+}
+
+static void
+destroy_surface(struct surface *surface)
+{
+	struct list_item *item, *next;
+
+	wl_list_for_each_safe(item, next, &surface->item_list, surface_link)
+		panel_remove_list_item(item);
+
+	free(surface->title);
+	free(surface);
+}
+
+static void
+draw_window_list(struct panel *panel)
+{
+	struct list_item *item;
+	float x, y, w, h;
+	float item_width, padding;
+
+	/* If there are no window list items, redraw the panel to clear it */
+	if (wl_list_empty(&panel->window_list)) {
+		widget_schedule_redraw(panel->widget);
+		return;
+	}
+
+	item_width = ((float) panel->window_list_rect.width /
+							panel->surface_count);
+	padding = MIN(item_width * 0.1f, 10.0f);
+
+	x = panel->window_list_rect.x + padding;
+	y = 16;
+	w = MIN(item_width - padding, 200);
+	h = 24;
+
+	wl_list_for_each(item, &panel->window_list, link) {
+		widget_set_allocation(item->widget,
+				      x, y - h / 2, w + 1, h + 1);
+		x += w + padding;
+		widget_schedule_redraw(item->widget);
+	}
+}
+
+static void
+update_panel_list_items(struct desktop *desktop, struct surface *surface)
+{
+	struct list_item *item, *next;
+	struct output *output;
+	int item_exists;
+
+	/* Make a list item for each panel of the surfaces output mask */
+	wl_list_for_each(output, &desktop->outputs, link) {
+		if ((1 << output->id) & surface->output_mask) {
+			item_exists = 0;
+			wl_list_for_each(item, &output->panel->window_list,
+									link) {
+				wl_list_for_each(next, &surface->item_list,
+								surface_link) {
+					if (next == item &&
+						item->panel == output->panel) {
+						item_exists = 1;
+						break;
+					}
+				}
+			}
+			if (!item_exists) {
+				/* TODO: Use a real icon instead of
+				 * passing NULL for the fallback */
+				item = panel_add_list_item(output->panel,
+							NULL, surface->title);
+				wl_list_insert(surface->item_list.prev,
+							&item->surface_link);
+				item->surface = surface;
+			}
+		} else {
+			/* Remove item from panel if surface
+			 * is no longer on the output */
+			wl_list_for_each_safe(item, next,
+					&surface->item_list, surface_link) {
+				if (item->panel == output->panel)
+					panel_remove_list_item(item);
+			}
+		}
+		draw_window_list(output->panel);
+	}
+}
+
+static void
+desktop_shell_surface_info(void *data,
+				struct desktop_shell *desktop_shell,
+				uint32_t id,
+				uint32_t output_mask,
+				const char *title)
+{
+	struct desktop *desktop;
+	struct surface *surface;
+	struct list_item *item;
+	struct output *output;
+	int surface_exists = 0;
+
+	desktop = data;
+
+	/* If this surface is already in our list, prepare to update its info */
+	wl_list_for_each(output, &desktop->outputs, link) {
+		wl_list_for_each(item, &output->panel->window_list, link) {
+			surface = item->surface;
+			if (id == surface->id) {
+				surface_exists = 1;
+				break;
+			}
+		}
+		if (surface_exists)
+			break;
+	}
+
+	/* Else, create a new surface intance to track it */
+	if (!surface_exists)
+		surface = create_surface();
+
+	surface->id = id;
+	surface->output_mask = output_mask;
+	if (surface->title)
+		free(surface->title);
+	surface->title = strdup(title);
+
+	update_panel_list_items(desktop, surface);
+}
+
+static void
+desktop_shell_surface_destroy(void *data,
+				  struct desktop_shell *desktop_shell,
+				  uint32_t id)
+{
+	struct desktop *desktop = data;
+	struct list_item *item, *next;
+	struct panel *panel;
+	struct surface *surface;
+	struct output *output;
+
+	wl_list_for_each(output, &desktop->outputs, link) {
+		panel = output->panel;
+		wl_list_for_each_safe(item, next, &panel->window_list, link) {
+			surface = item->surface;
+			if (id == surface->id) {
+				/* Free resources and redraw window list */
+				destroy_surface(surface);
+				draw_window_list(output->panel);
+				return;
+			}
+		}
+	}
+}
+
 static const struct desktop_shell_listener listener = {
 	desktop_shell_configure,
 	desktop_shell_prepare_lock_surface,
-	desktop_shell_grab_cursor
+	desktop_shell_grab_cursor,
+	desktop_shell_surface_info,
+	desktop_shell_surface_destroy
 };
 
 static struct background *
@@ -941,10 +1358,12 @@ create_output(struct desktop *desktop, uint32_t id)
 	if (!output)
 		return;
 
+	output->id = desktop->output_count++;
+
 	output->output = wl_display_bind(display_get_display(desktop->display),
 					 id, &wl_output_interface);
 
-	wl_list_insert(&desktop->outputs, &output->link);
+	wl_list_insert(desktop->outputs.prev, &output->link);
 }
 
 static void
@@ -1011,6 +1430,8 @@ int main(int argc, char *argv[])
 		return -1;
 	}
 
+	desktop.output_count = 0;
+
 	display_set_user_data(desktop.display, &desktop);
 	wl_display_add_global_listener(display_get_display(desktop.display),
 				       global_handler, &desktop);
@@ -1041,6 +1462,8 @@ int main(int argc, char *argv[])
 
 	signal(SIGCHLD, sigchild_handler);
 
+	desktop_shell_get_surface_info(desktop.shell);
+
 	display_run(desktop.display);
 
 	return 0;
diff --git a/protocol/desktop-shell.xml b/protocol/desktop-shell.xml
index 2b6afbd..376d423 100644
--- a/protocol/desktop-shell.xml
+++ b/protocol/desktop-shell.xml
@@ -80,6 +80,33 @@
 
       <entry name="busy" value="11"/>
     </enum>
+
+    <request name="get_surface_info">
+      <description summary="request surface list">
+	The wl_shell client can use this request to ask the window manager to
+	send surface_info events for all surfaces. The window manager should
+	send only normal surfaces that can be part of a common window list.
+      </description>
+    </request>
+
+    <event name="surface_info">
+      <description summary="surface information">
+	Surface information sent to a wl_shell client. This information is
+	intended to allow the wl_shell client to build a window list. It
+	should be sent when a wl_shell_surface is created.
+      </description>
+      <arg name="id" type="uint"/>
+      <arg name="output_mask" type="uint"/>
+      <arg name="title" type="string"/>
+    </event>
+
+    <event name="surface_destroy">
+      <description summary="surface destroy notification">
+	This should be sent when a wl_shell_surface is destroyed. The wl_shell
+	client can use this information to keep the window list current.
+      </description>
+      <arg name="id" type="uint"/>
+    </event>
   </interface>
 
   <interface name="screensaver" version="1">
diff --git a/src/compositor.c b/src/compositor.c
index 417c508..7afdbdb 100644
--- a/src/compositor.c
+++ b/src/compositor.c
@@ -368,6 +368,8 @@ weston_surface_update_output_mask(struct weston_surface *es, uint32_t mask)
 		if (1 << output->id & left)
 			wl_surface_send_leave(&es->surface.resource, resource);
 	}
+
+	es->compositor->shell_interface.send_info(es);
 }
 
 static void
diff --git a/src/compositor.h b/src/compositor.h
index aea4f8d..4304d21 100644
--- a/src/compositor.h
+++ b/src/compositor.h
@@ -89,6 +89,7 @@ struct weston_shell_interface {
 	int (*move)(struct shell_surface *shsurf, struct weston_seat *ws);
 	int (*resize)(struct shell_surface *shsurf,
 		      struct weston_seat *ws, uint32_t edges);
+	void (*send_info)(struct weston_surface *surface);
 
 };
 
diff --git a/src/shell.c b/src/shell.c
index e2715d6..31b15b6 100644
--- a/src/shell.c
+++ b/src/shell.c
@@ -1392,6 +1392,36 @@ shell_surface_pong(struct wl_client *client, struct wl_resource *resource,
 }
 
 static void
+shell_surface_send_info(struct weston_surface *surface)
+{
+	struct shell_surface *shsurf;
+	struct desktop_shell *shell;
+
+	shsurf = get_shell_surface(surface);
+	if (!shsurf)
+		return;
+
+	shell = shsurf->shell;
+
+	switch (shsurf->type) {
+	default:
+	case SHELL_SURFACE_TRANSIENT:
+	case SHELL_SURFACE_POPUP:
+	case SHELL_SURFACE_NONE:
+		return;
+	case SHELL_SURFACE_FULLSCREEN:
+	case SHELL_SURFACE_MAXIMIZED:
+	case SHELL_SURFACE_TOPLEVEL:
+		desktop_shell_send_surface_info(shell->child.desktop_shell,
+						(long unsigned int) surface,
+						surface->output_mask,
+						shsurf->title == NULL ?
+						"Surface" : shsurf->title);
+		return;
+	}
+}
+
+static void
 shell_surface_set_title(struct wl_client *client,
 			struct wl_resource *resource, const char *title)
 {
@@ -1399,6 +1429,7 @@ shell_surface_set_title(struct wl_client *client,
 
 	free(shsurf->title);
 	shsurf->title = strdup(title);
+	shell_surface_send_info(shsurf->surface);
 }
 
 static void
@@ -1907,6 +1938,8 @@ static const struct wl_shell_surface_interface shell_surface_implementation = {
 static void
 destroy_shell_surface(struct shell_surface *shsurf)
 {
+	desktop_shell_send_surface_destroy(shsurf->shell->child.desktop_shell,
+					(long unsigned int) shsurf->surface);
 	if (shsurf->popup.grab.pointer)
 		wl_pointer_end_grab(shsurf->popup.grab.pointer);
 
@@ -2283,12 +2316,28 @@ desktop_shell_set_grab_surface(struct wl_client *client,
 	shell->grab_surface = surface_resource->data;
 }
 
+static void
+desktop_shell_surface_info_requested(struct wl_client *client,
+					struct wl_resource *resource)
+{
+	struct weston_surface *surface;
+	struct desktop_shell *shell;
+	struct workspace *ws;
+
+	shell = resource->data;
+	ws = get_current_workspace(shell);
+
+	wl_list_for_each(surface, &ws->layer.surface_list, layer_link)
+		shell_surface_send_info(surface);
+}
+
 static const struct desktop_shell_interface desktop_shell_implementation = {
 	desktop_shell_set_background,
 	desktop_shell_set_panel,
 	desktop_shell_set_lock_surface,
 	desktop_shell_unlock,
-	desktop_shell_set_grab_surface
+	desktop_shell_set_grab_surface,
+	desktop_shell_surface_info_requested
 };
 
 static enum shell_surface_type
@@ -2915,6 +2964,12 @@ map(struct desktop_shell *shell, struct weston_surface *surface,
 	default:
 		ws = get_current_workspace(shell);
 		wl_list_insert(&ws->layer.surface_list, &surface->layer_link);
+		weston_surface_update_transform(surface);
+		desktop_shell_send_surface_info(shsurf->shell->child.desktop_shell,
+						(long unsigned int) surface,
+						surface->output_mask,
+						shsurf->title == NULL ?
+						"Surface" : shsurf->title);
 		break;
 	}
 
@@ -3723,6 +3778,7 @@ module_init(struct weston_compositor *ec)
 	ec->shell_interface.set_transient = set_transient;
 	ec->shell_interface.move = surface_move;
 	ec->shell_interface.resize = surface_resize;
+	ec->shell_interface.send_info = shell_surface_send_info;
 
 	wl_list_init(&shell->screensaver.surfaces);
 	wl_list_init(&shell->input_panel.surfaces);
-- 
1.7.11.4



More information about the wayland-devel mailing list