[PATCH weston 4/6] desktop-shell: implement the presented() GUI notifier

Manuel Bachmann manuel.bachmann at open.eurogiciel.org
Thu Apr 9 09:24:22 PDT 2015


Each time a managed_surface receives a "presented"
event, a red tooltip will be created on the panel and
stacked on the right side (near the clock).

The user can click on the tooltip to make the shell
send an "activate" request, and raise the surface
to the foreground of its current workspace.

The tooltip is destroyed after having been clicked,
or whenever the corresponding shell surface gets
destroyed by any means.

Signed-off-by: Manuel Bachmann <manuel.bachmann at open.eurogiciel.org>
---
 clients/desktop-shell.c | 207 ++++++++++++++++++++++++++++++++++++++++++++++--
 1 file changed, 203 insertions(+), 6 deletions(-)

diff --git a/clients/desktop-shell.c b/clients/desktop-shell.c
index 3c63c28..5c5a1aa 100644
--- a/clients/desktop-shell.c
+++ b/clients/desktop-shell.c
@@ -72,6 +72,7 @@ struct desktop {
 struct desktop_managed_surface {
 	struct managed_surface *managed_surface;
 	char *title;
+	struct desktop *desktop;
 	struct wl_list link;
 };
 
@@ -87,6 +88,7 @@ struct panel {
 	struct window *window;
 	struct widget *widget;
 	struct wl_list launcher_list;
+	struct wl_list notifier_list;
 	struct panel_clock *clock;
 	int painted;
 	uint32_t color;
@@ -123,6 +125,13 @@ struct panel_launcher {
 	struct wl_array argv;
 };
 
+struct panel_notifier {
+	struct widget *widget;
+	struct panel *panel;
+	struct desktop_managed_surface *mgsurf;
+	struct wl_list link;
+};
+
 struct panel_clock {
 	struct widget *widget;
 	struct panel *panel;
@@ -172,6 +181,16 @@ show_menu(struct panel *panel, struct input *input, uint32_t time)
 			 x - 10, y - 10, menu_func, entries, 4);
 }
 
+static void
+update_window(struct window *window)
+{
+	struct rectangle allocation;
+
+	window_get_allocation(window, &allocation);
+	window_schedule_resize(window, allocation.width,
+				       allocation.height);
+}
+
 static int
 is_desktop_painted(struct desktop *desktop)
 {
@@ -204,6 +223,25 @@ check_desktop_ready(struct window *window)
 	}
 }
 
+static struct panel_notifier *
+managed_surface_get_notifier(struct output *output,
+			      struct desktop_managed_surface *mgsurf)
+{
+	struct panel *panel;
+	struct panel_notifier *notifier;
+
+	panel = output->panel;
+	if (!panel)
+		return NULL;
+
+	wl_list_for_each(notifier, &panel->notifier_list, link) {
+		if (notifier->mgsurf == mgsurf)
+			return notifier;
+	}
+
+	return NULL;
+}
+
 static void
 panel_launcher_activate(struct panel_launcher *widget)
 {
@@ -358,6 +396,112 @@ panel_launcher_touch_up_handler(struct widget *widget, struct input *input,
 }
 
 static void
+panel_destroy_notifier(struct panel_notifier *notifier)
+{
+	wl_list_remove(&notifier->link);
+	update_window(notifier->panel->window);
+
+	widget_destroy(notifier->widget);
+	notifier->mgsurf = NULL;
+	free(notifier);
+}
+
+static void
+panel_notifier_activate(struct panel_notifier *notifier)
+{
+	if (notifier->mgsurf)
+		managed_surface_activate(notifier->mgsurf->managed_surface);
+
+	panel_destroy_notifier(notifier);
+}
+
+static void
+panel_notifier_touch_up_handler(struct widget *widget, struct input *input,
+				uint32_t serial, uint32_t time, int32_t id,
+				void *data)
+{
+	struct panel_notifier *notifier;
+
+	notifier = widget_get_user_data(widget);
+	widget_schedule_redraw(widget);
+	panel_notifier_activate(notifier);
+}
+
+static void
+panel_notifier_button_handler(struct widget *widget, struct input *input,
+			      uint32_t time, uint32_t button,
+			      enum wl_pointer_button_state state,
+			      void *data)
+{
+	struct panel_notifier *notifier;
+
+	notifier = widget_get_user_data(widget);
+	widget_schedule_redraw(widget);
+	if (state == WL_POINTER_BUTTON_STATE_RELEASED)
+		panel_notifier_activate(notifier);
+}
+
+static void
+panel_notifier_redraw_handler(struct widget *widget, void *data)
+{
+	struct panel_notifier *notifier = data;
+	struct rectangle allocation;
+	char *title;
+	cairo_text_extents_t extents;
+	cairo_t *cr;
+
+	widget_get_allocation(widget, &allocation);
+	if (allocation.width == 0 || !notifier->mgsurf)
+		return;
+
+	cr = widget_cairo_create(notifier->panel->widget);
+
+	rounded_rect(cr, allocation.x, allocation.y,
+			 allocation.x + allocation.width + 3,
+			 allocation.y + allocation.height + 3, 3);
+	cairo_set_operator(cr, CAIRO_OPERATOR_OVER);
+	cairo_set_source_rgba(cr, 0.8, 0.0, 0.0, 0.8);
+	cairo_fill(cr);
+
+	cairo_set_source_rgb(cr, 1.0, 1.0, 1.0);
+	title = (notifier->mgsurf->title) ?
+		notifier->mgsurf->title : "<Default>";
+	cairo_text_extents(cr, title, &extents);
+	cairo_move_to(cr,
+		      allocation.x + (allocation.width - extents.width) / 2,
+		      allocation.y + allocation.height);
+	cairo_show_text(cr, title);
+
+	cairo_destroy(cr);
+}
+
+static struct panel_notifier *
+panel_add_notifier(struct panel *panel,
+		   struct desktop_managed_surface *mgsurf)
+{
+	struct panel_notifier *notifier;
+
+	notifier = xzalloc(sizeof *notifier);
+	notifier->panel = panel;
+	notifier->mgsurf = mgsurf;
+
+	wl_list_insert(panel->notifier_list.prev, &notifier->link);
+
+	notifier->widget = widget_add_widget(panel->widget, notifier);
+	widget_set_touch_up_handler(notifier->widget,
+				    panel_notifier_touch_up_handler);
+	widget_set_button_handler(notifier->widget,
+				  panel_notifier_button_handler);
+	widget_set_redraw_handler(notifier->widget,
+				  panel_notifier_redraw_handler);
+
+	widget_schedule_redraw(notifier->widget);
+	update_window(panel->window);
+
+	return notifier;
+}
+
+static void
 clock_func(struct task *task, uint32_t events)
 {
 	struct panel_clock *clock =
@@ -477,8 +621,12 @@ panel_resize_handler(struct widget *widget,
 		     int32_t width, int32_t height, void *data)
 {
 	struct panel_launcher *launcher;
+	struct panel_notifier *notifier;
 	struct panel *panel = data;
+	cairo_t *cr;
+	cairo_text_extents_t extents;
 	int x, y, w, h;
+	int last_launcher_x;
 	
 	x = 10;
 	y = 16;
@@ -489,6 +637,26 @@ panel_resize_handler(struct widget *widget,
 				      x, y - h / 2, w + 1, h + 1);
 		x += w + 10;
 	}
+
+	last_launcher_x = x;
+	x = width - 180;
+	wl_list_for_each(notifier, &panel->notifier_list, link) {
+		widget_set_allocation(notifier->widget, 0, 0, 0, 0);
+		if (!notifier->mgsurf)
+			continue;
+		cr = widget_cairo_create(notifier->widget);
+		cairo_text_extents(cr, (notifier->mgsurf->title) ?
+				       notifier->mgsurf->title : "<Default>",
+				       &extents);
+		x -= extents.width + 10;
+		if (x > last_launcher_x)
+			widget_set_allocation(notifier->widget,
+					      x, y - extents.height /2,
+					      extents.width + 1,
+					      extents.height + 1);
+		cairo_destroy(cr);
+	}
+
 	h=20;
 	w=170;
 
@@ -528,14 +696,17 @@ panel_destroy_launcher(struct panel_launcher *launcher)
 static void
 panel_destroy(struct panel *panel)
 {
-	struct panel_launcher *tmp;
-	struct panel_launcher *launcher;
+	struct panel_launcher *launcher, *l_tmp;
+	struct panel_notifier *notifier, *n_tmp;
 
 	panel_destroy_clock(panel->clock);
 
-	wl_list_for_each_safe(launcher, tmp, &panel->launcher_list, link)
+	wl_list_for_each_safe(launcher, l_tmp, &panel->launcher_list, link)
 		panel_destroy_launcher(launcher);
 
+	wl_list_for_each_safe(notifier, n_tmp, &panel->notifier_list, link)
+		panel_destroy_notifier(notifier);
+
 	widget_destroy(panel->widget);
 	window_destroy(panel->window);
 
@@ -554,6 +725,7 @@ panel_create(struct desktop *desktop)
 	panel->window = window_create_custom(desktop->display);
 	panel->widget = window_add_widget(panel->window, panel);
 	wl_list_init(&panel->launcher_list);
+	wl_list_init(&panel->notifier_list);
 
 	window_set_title(panel->window, "panel");
 	window_set_user_data(panel->window, panel);
@@ -952,6 +1124,17 @@ static void
 managed_surface_presented(void *data,
 			  struct managed_surface *managed_surface)
 {
+	struct desktop_managed_surface *mgsurf = data;
+	struct desktop *desktop = mgsurf->desktop;
+	struct output *output;
+	struct panel_notifier *notifier;
+
+	wl_list_for_each(output, &desktop->outputs, link) {
+		notifier = managed_surface_get_notifier(output, mgsurf);
+
+		if (!notifier && output->panel)
+			notifier = panel_add_notifier(output->panel, mgsurf);
+	}
 }
 
 static void
@@ -972,13 +1155,26 @@ managed_surface_removed(void *data,
 			struct managed_surface *managed_surface)
 {
 	struct desktop_managed_surface *mgsurf = data;
+	struct desktop *desktop = mgsurf->desktop;
+	struct output *output;
+	struct panel_notifier *notifier;
+
+	wl_list_for_each(output, &desktop->outputs, link) {
+		notifier = managed_surface_get_notifier(output, mgsurf);
+
+		if (notifier)
+			panel_destroy_notifier(notifier);
+	}
+
+	managed_surface_destroy(mgsurf->managed_surface);
 
 	if (mgsurf->title)
 		free(mgsurf->title);
+	mgsurf->title = NULL;
+	mgsurf->desktop = NULL;
 	wl_list_remove(&mgsurf->link);
-	free(mgsurf);
 
-	managed_surface_destroy(managed_surface);
+	free(mgsurf);
 }
 
 static const struct managed_surface_listener managed_surface_listener = {
@@ -1076,6 +1272,7 @@ desktop_shell_add_managed_surface(void *data,
 	mgsurf = xzalloc(sizeof *mgsurf);
 	mgsurf->managed_surface = managed_surface;
 	mgsurf->title = (title) ? xstrdup(title) : NULL;
+	mgsurf->desktop = desktop;
 
 	wl_list_insert(desktop->managed_surfaces.prev, &mgsurf->link);
 
-- 
1.8.3.1



More information about the wayland-devel mailing list