[PATCH weston] shell: Implement wl_notification_daemon

Quentin Glidic sardemff7+wayland at sardemff7.net
Thu Mar 14 06:49:43 PDT 2013


From: Quentin Glidic <sardemff7+git at sardemff7.net>

Implement the "bubbles list" style notifications.
Corner anchor, margin and order can be changed in the configuration.

Signed-off-by: Quentin Glidic <sardemff7+git at sardemff7.net>
---

Rebase on top of current master

 src/shell.c | 196 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++---
 weston.ini  |   5 ++
 2 files changed, 193 insertions(+), 8 deletions(-)

diff --git a/src/shell.c b/src/shell.c
index 3da5321..a066dc3 100644
--- a/src/shell.c
+++ b/src/shell.c
@@ -42,6 +42,8 @@
 #define DEFAULT_NUM_WORKSPACES 1
 #define DEFAULT_WORKSPACE_CHANGE_ANIMATION_LENGTH 200
 
+#define DEFAULT_NOTIFICATIONS_MARGIN 20
+
 enum animation_type {
 	ANIMATION_NONE,
 
@@ -54,6 +56,25 @@ enum fade_type {
 	FADE_OUT
 };
 
+enum edge_anchor {
+	EDGE_TOP    = 1<<0,
+	EDGE_BOTTOM = 1<<1,
+	EDGE_LEFT   = 1<<2,
+	EDGE_RIGHT  = 1<<3
+};
+
+enum corner_anchor {
+	CORNER_TOP_RIGHT    = EDGE_TOP | EDGE_RIGHT,
+	CORNER_TOP_LEFT     = EDGE_TOP | EDGE_LEFT,
+	CORNER_BOTTOM_RIGHT = EDGE_BOTTOM | EDGE_RIGHT,
+	CORNER_BOTTOM_LEFT  = EDGE_BOTTOM | EDGE_LEFT,
+};
+
+enum notifications_order {
+	ORDER_NEWEST_FIRST,
+	ORDER_OLDEST_FIRST
+};
+
 struct focus_state {
 	struct weston_seat *seat;
 	struct workspace *ws;
@@ -89,6 +110,7 @@ struct desktop_shell {
 	struct wl_listener show_input_panel_listener;
 	struct wl_listener hide_input_panel_listener;
 
+	struct weston_layer notification_layer;
 	struct weston_layer fullscreen_layer;
 	struct weston_layer panel_layer;
 	struct weston_layer background_layer;
@@ -144,6 +166,14 @@ struct desktop_shell {
 	} input_panel;
 
 	struct {
+		enum corner_anchor corner;
+		enum notifications_order order;
+		int32_t margin;
+		struct weston_output *output;
+		struct wl_resource *binding;
+	} notification_daemon;
+
+	struct {
 		struct weston_surface *surface;
 		struct weston_surface_animation *animation;
 		enum fade_type type;
@@ -356,6 +386,43 @@ get_animation_type(char *animation)
 		return ANIMATION_NONE;
 }
 
+static enum corner_anchor
+get_corner_anchor(char *placement, enum corner_anchor default_anchor)
+{
+	if (placement == NULL)
+		return default_anchor;
+
+	if (strcmp("top-left", placement) == 0)
+		return CORNER_TOP_LEFT;
+	if (strcmp("top-right", placement) == 0)
+		return CORNER_TOP_RIGHT;
+	if (strcmp("bottom-right", placement) == 0)
+		return CORNER_BOTTOM_RIGHT;
+	if (strcmp("bottom-left", placement) == 0)
+		return CORNER_BOTTOM_LEFT;
+
+	return default_anchor;
+}
+
+static enum notifications_order
+get_notification_order(char *order)
+{
+	if (order == NULL)
+		return ORDER_NEWEST_FIRST;
+
+	if (strcmp("oldest-first", order) == 0)
+		return ORDER_OLDEST_FIRST;
+
+	return ORDER_NEWEST_FIRST;
+}
+
+static struct weston_output *
+get_default_output(struct weston_compositor *compositor)
+{
+	return container_of(compositor->output_list.next,
+			    struct weston_output, link);
+}
+
 static void
 shell_configuration(struct desktop_shell *shell, const char *config_file)
 {
@@ -364,6 +431,9 @@ shell_configuration(struct desktop_shell *shell, const char *config_file)
 	unsigned int num_workspaces = DEFAULT_NUM_WORKSPACES;
 	char *modifier = NULL;
 	char *win_animation = NULL;
+	char *notifications_corner = NULL;
+	char *notifications_order = NULL;
+	int notifications_margin = DEFAULT_NOTIFICATIONS_MARGIN;
 
 	struct config_key shell_keys[] = {
 		{ "binding-modifier",   CONFIG_KEY_STRING, &modifier },
@@ -377,9 +447,16 @@ shell_configuration(struct desktop_shell *shell, const char *config_file)
 		{ "duration",   CONFIG_KEY_INTEGER, &duration },
 	};
 
+	struct config_key notifications_keys[] = {
+		{ "corner", CONFIG_KEY_STRING,  &notifications_corner },
+		{ "order",     CONFIG_KEY_STRING,  &notifications_order },
+		{ "margin",    CONFIG_KEY_INTEGER, &notifications_margin },
+	};
+
 	struct config_section cs[] = {
 		{ "shell", shell_keys, ARRAY_LENGTH(shell_keys), NULL },
 		{ "screensaver", saver_keys, ARRAY_LENGTH(saver_keys), NULL },
+		{ "notifications", notifications_keys, ARRAY_LENGTH(notifications_keys), NULL },
 	};
 
 	parse_config_file(config_file, cs, ARRAY_LENGTH(cs), shell);
@@ -389,6 +466,13 @@ shell_configuration(struct desktop_shell *shell, const char *config_file)
 	shell->binding_modifier = get_modifier(modifier);
 	shell->win_animation_type = get_animation_type(win_animation);
 	shell->workspaces.num = num_workspaces > 0 ? num_workspaces : 1;
+	shell->notification_daemon.corner = get_corner_anchor(notifications_corner, CORNER_TOP_RIGHT);
+	shell->notification_daemon.order = get_notification_order(notifications_order);
+	shell->notification_daemon.margin = notifications_margin;
+	shell->notification_daemon.output = get_default_output(shell->compositor);
+
+	free(notifications_order);
+	free(notifications_corner);
 }
 
 static void
@@ -1434,13 +1518,6 @@ shell_surface_set_class(struct wl_client *client,
 	shsurf->class = strdup(class);
 }
 
-static struct weston_output *
-get_default_output(struct weston_compositor *compositor)
-{
-	return container_of(compositor->output_list.next,
-			    struct weston_output, link);
-}
-
 static void
 shell_unset_fullscreen(struct shell_surface *shsurf)
 {
@@ -2137,6 +2214,73 @@ static const struct wl_shell_interface shell_implementation = {
 };
 
 static void
+notification_daemon_map_surfaces(struct desktop_shell *shell)
+{
+	bool right;
+	bool bottom;
+	int32_t x, y;
+	struct weston_surface *ws;
+
+	right = shell->notification_daemon.corner & EDGE_RIGHT;
+	bottom = shell->notification_daemon.corner & EDGE_BOTTOM;
+
+	if (right)
+		x = shell->notification_daemon.output->width - shell->notification_daemon.margin;
+	else
+		x = shell->notification_daemon.margin;
+	if (bottom)
+		y = shell->notification_daemon.output->height - shell->notification_daemon.margin;
+	else
+		y = shell->notification_daemon.margin;
+
+	wl_list_for_each(ws, &shell->notification_layer.surface_list, layer_link) {
+		if (bottom)
+			y -= ws->geometry.height;
+		if (right)
+			x -= ws->geometry.width;
+		weston_surface_set_position(ws, x, y);
+		if (right)
+			x += ws->geometry.width;
+		if (bottom)
+			y -= shell->notification_daemon.margin;
+		else
+			y += ws->geometry.height + shell->notification_daemon.margin;
+	}
+}
+
+static void
+notification_daemon_add_surface(struct wl_client *client, struct wl_resource *resource,
+				struct wl_resource *surface_resource)
+{
+	struct desktop_shell *shell = resource->data;
+	struct weston_surface *surface = surface_resource->data;
+
+	if (surface->configure != NULL) {
+		wl_resource_post_error(surface_resource,
+				       WL_DISPLAY_ERROR_INVALID_OBJECT,
+				       "surface role already assigned");
+		return;
+	}
+
+	surface->geometry.width = weston_surface_buffer_width(surface);
+	surface->geometry.height = weston_surface_buffer_height(surface);
+
+	surface->output = shell->notification_daemon.output;
+
+	if (shell->notification_daemon.order == ORDER_NEWEST_FIRST)
+		wl_list_insert(&shell->notification_layer.surface_list, &surface->layer_link);
+	else
+		wl_list_insert(shell->notification_layer.surface_list.prev, &surface->layer_link);
+	notification_daemon_map_surfaces(shell);
+
+	weston_compositor_schedule_repaint(shell->compositor);
+}
+
+static const struct wl_notification_daemon_interface notification_daemon_implementation = {
+	notification_daemon_add_surface
+};
+
+static void
 shell_fade(struct desktop_shell *shell, enum fade_type type);
 
 static int
@@ -3269,6 +3413,37 @@ bind_shell(struct wl_client *client, void *data, uint32_t version, uint32_t id)
 }
 
 static void
+unbind_notification_daemon(struct wl_resource *resource)
+{
+	struct desktop_shell *shell = resource->data;
+
+	shell->notification_daemon.binding = NULL;
+	free(resource);
+}
+
+static void
+bind_notification_daemon(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, &wl_notification_daemon_interface,
+					&notification_daemon_implementation,
+					id, shell);
+
+	if (shell->notification_daemon.binding == NULL) {
+		resource->destroy = unbind_notification_daemon;
+		shell->notification_daemon.binding = resource;
+		return;
+	}
+
+	wl_resource_post_error(resource, WL_DISPLAY_ERROR_INVALID_OBJECT,
+			       "interface object already bound");
+	wl_resource_destroy(resource);
+}
+
+static void
 unbind_desktop_shell(struct wl_resource *resource)
 {
 	struct desktop_shell *shell = resource->data;
@@ -4098,7 +4273,8 @@ module_init(struct weston_compositor *ec,
 
 	wl_list_init(&shell->input_panel.surfaces);
 
-	weston_layer_init(&shell->fullscreen_layer, &ec->cursor_layer.link);
+	weston_layer_init(&shell->notification_layer, &ec->cursor_layer.link);
+	weston_layer_init(&shell->fullscreen_layer, &shell->notification_layer.link);
 	weston_layer_init(&shell->panel_layer, &shell->fullscreen_layer.link);
 	weston_layer_init(&shell->background_layer, &shell->panel_layer.link);
 	weston_layer_init(&shell->lock_layer, NULL);
@@ -4128,6 +4304,10 @@ module_init(struct weston_compositor *ec,
 				  shell, bind_shell) == NULL)
 		return -1;
 
+	if (wl_display_add_global(ec->wl_display, &wl_notification_daemon_interface,
+				  shell, bind_notification_daemon) == NULL)
+		return -1;
+
 	if (wl_display_add_global(ec->wl_display,
 				  &desktop_shell_interface,
 				  shell, bind_desktop_shell) == NULL)
diff --git a/weston.ini b/weston.ini
index 98092a1..07aaa5a 100644
--- a/weston.ini
+++ b/weston.ini
@@ -36,6 +36,11 @@ path=./clients/flower
 path=/usr/libexec/weston-screensaver
 duration=600
 
+[notifications]
+#corner=top-right
+#order=newest-first
+#margin=20
+
 [input-method]
 path=/usr/libexec/weston-keyboard
 
-- 
1.8.1.5



More information about the wayland-devel mailing list