[PATCH 1/2 weston] Install infrastructure for surface_data objects.

Scott Moreau oreaus at gmail.com
Tue Oct 2 23:20:16 PDT 2012


We needed a way to send surface data to the shell client. This patch introduces
a new surface_data_manager interface that allows the compositor to send surface
data to the shell client, using the new surface_data object interface. This
allows the shell client to receive information about surfaces to build a window
list, for example.

---
 clients/desktop-shell.c    |  63 +++++++++++++++---
 protocol/desktop-shell.xml |  51 ++++++++++++++
 src/compositor.c           |   2 +
 src/compositor.h           |   1 +
 src/shell.c                | 163 +++++++++++++++++++++++++++++++++++++++++++++
 5 files changed, 272 insertions(+), 8 deletions(-)

diff --git a/clients/desktop-shell.c b/clients/desktop-shell.c
index 588dc1c..5c629cb 100644
--- a/clients/desktop-shell.c
+++ b/clients/desktop-shell.c
@@ -57,9 +57,17 @@ struct desktop {
 	struct widget *grab_widget;
 
 	enum cursor_type grab_cursor;
+
+	struct surface_data_manager *surface_data_manager;
 };
 
 struct surface {
+	struct surface_data *surface_data;
+	uint32_t output_mask;
+	char *title;
+};
+
+struct resize {
 	void (*configure)(void *data,
 			  struct desktop_shell *desktop_shell,
 			  uint32_t edges, struct window *window,
@@ -67,7 +75,7 @@ struct surface {
 };
 
 struct panel {
-	struct surface base;
+	struct resize base;
 	struct window *window;
 	struct widget *widget;
 	struct wl_list launcher_list;
@@ -75,7 +83,7 @@ struct panel {
 };
 
 struct background {
-	struct surface base;
+	struct resize base;
 	struct window *window;
 	struct widget *widget;
 };
@@ -417,7 +425,7 @@ panel_resize_handler(struct widget *widget,
 	struct panel_launcher *launcher;
 	struct panel *panel = data;
 	int x, y, w, h;
-	
+
 	x = 10;
 	y = 16;
 	wl_list_for_each(launcher, &panel->launcher_list, link) {
@@ -441,7 +449,7 @@ 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);
@@ -466,7 +474,7 @@ 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_add_clock(panel);
 
 	return panel;
@@ -485,8 +493,7 @@ load_icon_or_fallback(const char *icon)
 	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);
@@ -810,7 +817,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);
 }
@@ -885,6 +892,38 @@ static const struct desktop_shell_listener listener = {
 	desktop_shell_grab_cursor
 };
 
+static void
+surface_data_receive_info(void *data,
+				struct surface_data *surface_data,
+				uint32_t output_mask,
+				const char *title)
+{
+}
+
+static void
+surface_data_destroy_handler(void *data, struct surface_data *surface_data)
+{
+	surface_data_destroy_request(surface_data);
+}
+
+static const struct surface_data_listener surface_data_listener = {
+	surface_data_receive_info,
+	surface_data_destroy_handler
+};
+
+static void
+surface_data_receive_surface_object(void *data,
+				struct surface_data_manager *manager,
+				struct surface_data *surface_data)
+{
+	surface_data_add_listener(surface_data,
+				   &surface_data_listener, data);
+}
+
+static const struct surface_data_manager_listener surface_data_manager_listener = {
+	surface_data_receive_surface_object
+};
+
 static struct background *
 background_create(struct desktop *desktop)
 {
@@ -957,6 +996,12 @@ global_handler(struct wl_display *display, uint32_t id,
 		desktop->shell =
 			wl_display_bind(display, id, &desktop_shell_interface);
 		desktop_shell_add_listener(desktop->shell, &listener, desktop);
+	} else if (strcmp(interface, "surface_data_manager") == 0) {
+		desktop->surface_data_manager =
+			wl_display_bind(display, id,
+					&surface_data_manager_interface);
+		surface_data_manager_add_listener(desktop->surface_data_manager,
+					&surface_data_manager_listener, desktop);
 	} else if (!strcmp(interface, "wl_output")) {
 		create_output(desktop, id);
 	}
@@ -1041,6 +1086,8 @@ int main(int argc, char *argv[])
 
 	signal(SIGCHLD, sigchild_handler);
 
+	surface_data_manager_get_surface_info(desktop.surface_data_manager);
+
 	display_run(desktop.display);
 
 	return 0;
diff --git a/protocol/desktop-shell.xml b/protocol/desktop-shell.xml
index 2b6afbd..7030786 100644
--- a/protocol/desktop-shell.xml
+++ b/protocol/desktop-shell.xml
@@ -82,6 +82,57 @@
     </enum>
   </interface>
 
+  <interface name="surface_data" version="1">
+    <description summary="the surface data offer object">
+      The wl_shell client can use this interface to receive surface information
+      or make requests for this surface.
+    </description>
+    <event name="info">
+      <description summary="surface information">
+	Surface information sent to a wl_shell client. This information is
+	intended to give the wl_shell client additional information about the
+	surface.
+      </description>
+      <arg name="output_mask" type="uint"/>
+      <arg name="title" type="string"/>
+    </event>
+    <request name="destroy_request" type="destructor">
+      <description summary="destroy surface request">
+	The wl_shell client must send this request in response to a gone event
+	so the compositor can destroy the object properly.
+      </description>
+    </request>
+    <event name="gone" type="destructor">
+      <description summary="destroy surface notification">
+	The compositor should send this event to notify the wl_shell client that
+	a surface has been destroyed. The client must respond with a destroy
+	request.
+      </description>
+    </event>
+  </interface>
+
+  <interface name="surface_data_manager" version="1">
+    <description summary="send surface object to shell client">
+      The compositor can offer surface data to a wl_shell client. The client can
+      use this interface as a way to receive special surface_data objects.
+    </description>
+    <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_object">
+      <description summary="surface object">
+	Surface object sent to a wl_shell client. This object is intended to
+	allow the wl_shell to initiate a surface_data object interface. It
+	should be sent once, when a wl_shell_surface is created.
+      </description>
+      <arg name="id" type="new_id" interface="surface_data"/>
+    </event>
+  </interface>
+
   <interface name="screensaver" version="1">
     <description summary="interface for implementing screensavers">
       Only one client can bind this interface at a time.
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..2d86265 100644
--- a/src/shell.c
+++ b/src/shell.c
@@ -97,6 +97,8 @@ struct desktop_shell {
 		uint32_t deathstamp;
 	} child;
 
+	struct wl_resource *surface_data_manager;
+
 	bool locked;
 	bool showing_input_panels;
 	bool prepare_event_sent;
@@ -152,6 +154,11 @@ struct ping_timer {
 	uint32_t serial;
 };
 
+struct surface_data {
+	struct shell_surface *shsurf;
+	struct wl_resource resource;
+};
+
 struct shell_surface {
 	struct wl_resource resource;
 
@@ -202,6 +209,7 @@ struct shell_surface {
 	struct wl_list link;
 
 	const struct weston_shell_client *client;
+	struct surface_data *surface_data;
 };
 
 struct shell_grab {
@@ -1392,6 +1400,101 @@ shell_surface_pong(struct wl_client *client, struct wl_resource *resource,
 }
 
 static void
+surface_data_object_destroy(struct wl_resource *resource)
+{
+	struct shell_surface *shsurf;
+	struct surface_data *surface_data = resource->data;
+
+	shsurf = surface_data->shsurf;
+
+	free(surface_data);
+
+	if (!shsurf)
+		return;
+
+	shsurf->surface_data = NULL;
+}
+
+static void
+surface_data_destroy_handler(struct wl_client *client,
+					struct wl_resource *resource)
+{
+	wl_resource_destroy(resource);
+}
+
+static const struct surface_data_interface
+					surface_data_implementation = {
+	surface_data_destroy_handler
+};
+
+static int
+create_surface_data(struct desktop_shell *shell, struct shell_surface *shsurf)
+{
+	struct surface_data *surface_data;
+
+	surface_data = malloc(sizeof *surface_data);
+	if (surface_data == NULL)
+		return -1;
+
+	surface_data->resource.data = surface_data;
+	surface_data->resource.object.id = 0;
+	surface_data->resource.object.interface = &surface_data_interface;
+	surface_data->resource.destroy = surface_data_object_destroy;
+	surface_data->resource.object.implementation =
+			(void (**)(void)) &surface_data_implementation;
+	surface_data->shsurf = shsurf;
+	wl_signal_init(&surface_data->resource.destroy_signal);
+
+	wl_client_add_resource(shell->surface_data_manager->client,
+					&surface_data->resource);
+
+	shsurf->surface_data = surface_data;
+
+	return 0;
+}
+
+static void
+send_surface_object(struct desktop_shell *shell, struct shell_surface *shsurf)
+{
+	surface_data_manager_send_surface_object(shell->surface_data_manager,
+					&shsurf->surface_data->resource);
+}
+
+static void
+send_surface_info(struct weston_surface *surface)
+{
+	struct desktop_shell *shell;
+	struct shell_surface *shsurf;
+
+	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:
+		if (!shsurf->surface_data) {
+			if (create_surface_data(shell, shsurf))
+				return;
+			send_surface_object(shell, shsurf);
+		}
+		surface_data_send_info(&shsurf->surface_data->resource,
+						shsurf->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 +1502,7 @@ shell_surface_set_title(struct wl_client *client,
 
 	free(shsurf->title);
 	shsurf->title = strdup(title);
+	send_surface_info(shsurf->surface);
 }
 
 static void
@@ -1907,6 +2011,10 @@ static const struct wl_shell_surface_interface shell_surface_implementation = {
 static void
 destroy_shell_surface(struct shell_surface *shsurf)
 {
+	if (shsurf->surface_data) {
+		shsurf->surface_data->shsurf = NULL;
+		surface_data_send_gone(&shsurf->surface_data->resource);
+	}
 	if (shsurf->popup.grab.pointer)
 		wl_pointer_end_grab(shsurf->popup.grab.pointer);
 
@@ -2291,6 +2399,26 @@ static const struct desktop_shell_interface desktop_shell_implementation = {
 	desktop_shell_set_grab_surface
 };
 
+static void
+surface_data_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)
+		send_surface_info(surface);
+}
+
+static const struct surface_data_manager_interface
+					surface_data_manager_implementation = {
+	surface_data_surface_info_requested
+};
+
 static enum shell_surface_type
 get_shell_surface_type(struct weston_surface *surface)
 {
@@ -2915,6 +3043,8 @@ 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);
+		send_surface_info(surface);
 		break;
 	}
 
@@ -3118,6 +3248,34 @@ bind_desktop_shell(struct wl_client *client,
 }
 
 static void
+unbind_surface_data_manager(struct wl_resource *resource)
+{
+	free(resource);
+}
+
+static void
+bind_surface_data_manager(struct wl_client *client,
+		   void *data, uint32_t version, uint32_t id)
+{
+	struct desktop_shell *shell = data;
+	struct wl_resource *resource;
+
+	resource = wl_client_add_object(client, &surface_data_manager_interface,
+					&surface_data_manager_implementation,
+					id, shell);
+
+	if (client == shell->child.client) {
+		resource->destroy = unbind_surface_data_manager;
+		shell->surface_data_manager = resource;
+		return;
+	}
+
+	wl_resource_post_error(resource, WL_DISPLAY_ERROR_INVALID_OBJECT,
+			       "permission to bind desktop_shell denied");
+	wl_resource_destroy(resource);
+}
+
+static void
 screensaver_configure(struct weston_surface *surface, int32_t sx, int32_t sy)
 {
 	struct desktop_shell *shell = surface->private;
@@ -3723,6 +3881,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 = send_surface_info;
 
 	wl_list_init(&shell->screensaver.surfaces);
 	wl_list_init(&shell->input_panel.surfaces);
@@ -3774,6 +3933,10 @@ module_init(struct weston_compositor *ec)
 				  shell, bind_workspace_manager) == NULL)
 		return -1;
 
+	if (wl_display_add_global(ec->wl_display, &surface_data_manager_interface,
+				  shell, bind_surface_data_manager) == NULL)
+		return -1;
+
 	shell->child.deathstamp = weston_compositor_get_time();
 	if (launch_desktop_shell_process(shell) != 0)
 		return -1;
-- 
1.7.11.4



More information about the wayland-devel mailing list