[RFC 2/2] window: Use wl_probe_visible when positioning menus

Jonas Ådahl jadahl at gmail.com
Wed Sep 30 23:51:46 PDT 2015


To avoid positioning the menu offscreen, probe the visibility of the
intended rectangle and adapt it before showing the popup. This patch is
based by a patch[0] by Rob Bradford from 2013.

[0] http://lists.freedesktop.org/archives/wayland-devel/2013-April/008667.html

Signed-off-by: Jonas Ådahl <jadahl at gmail.com>
---
 Makefile.am      |  2 ++
 clients/window.c | 61 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 2 files changed, 63 insertions(+)

diff --git a/Makefile.am b/Makefile.am
index 00f3ad2..71a5763 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -553,6 +553,8 @@ nodist_libtoytoolkit_la_SOURCES =			\
 	protocol/workspaces-client-protocol.h		\
 	protocol/presentation_timing-protocol.c		\
 	protocol/presentation_timing-client-protocol.h	\
+	protocol/probe-visible-protocol.c		\
+	protocol/probe-visible-client-protocol.h	\
 	protocol/xdg-shell-protocol.c			\
 	protocol/xdg-shell-client-protocol.h		\
 	protocol/ivi-application-protocol.c		\
diff --git a/clients/window.c b/clients/window.c
index 47a79aa..ab561a4 100644
--- a/clients/window.c
+++ b/clients/window.c
@@ -71,6 +71,7 @@ typedef void *EGLContext;
 #include "xdg-shell-client-protocol.h"
 #include "text-cursor-position-client-protocol.h"
 #include "workspaces-client-protocol.h"
+#include "probe-visible-client-protocol.h"
 #include "shared/os-compatibility.h"
 
 #include "window.h"
@@ -99,6 +100,7 @@ struct display {
 	struct workspace_manager *workspace_manager;
 	struct xdg_shell *xdg_shell;
 	struct ivi_application *ivi_application; /* ivi style shell */
+	struct _wl_probe_visible *probe_visible;
 	EGLDisplay dpy;
 	EGLConfig argb_config;
 	EGLContext argb_ctx;
@@ -401,6 +403,8 @@ struct menu {
 	int count;
 	int release_count;
 	menu_func_t func;
+	int width;
+	int height;
 };
 
 struct tooltip {
@@ -4813,6 +4817,46 @@ static const struct xdg_popup_listener xdg_popup_listener = {
 	handle_popup_popup_done,
 };
 
+static void
+probe_visible_visible_rectangle (void *data,
+				 struct _wl_probe_visible_result *result,
+				 int32_t x, int32_t y,
+				 int32_t w, int32_t h)
+{
+	struct menu *menu = data;
+	struct window *window = menu->window;
+
+	/* Clipped to the left */
+	if (x != window->x)
+		window->x = x;
+	/* Clipped to the right */
+	else if (x == window->x && w < menu->width)
+		window->x = window->x - (menu->width - w);
+	/* Spans the output ? */
+	else {
+		window->x = x;
+		menu->width = w;
+	}
+
+	/* Clipped to the top */
+	if (y != window->y)
+		window->y = y;
+	/* Clipped to the bottom */
+	else if (y == window->y && h < menu->height)
+		window->y = y - (menu->height - h);
+	/* Spans the output */
+	else {
+		window->y = y;
+		menu->height = h;
+	}
+
+	_wl_probe_visible_result_destroy(result);
+}
+
+struct _wl_probe_visible_result_listener probe_result_listener = {
+    probe_visible_visible_rectangle,
+};
+
 static struct menu *
 create_menu(struct display *display,
 	    struct input *input, uint32_t time,
@@ -4888,6 +4932,8 @@ window_show_menu(struct display *display,
 	struct menu *menu;
 	struct window *window;
 	int32_t ix, iy;
+	struct _wl_probe_visible_result *result;
+	int margin;
 
 	menu = create_menu(display, input, time, func, entries, count, parent);
 
@@ -4901,12 +4947,23 @@ window_show_menu(struct display *display,
 
 	window->x = x;
 	window->y = y;
+	margin = window_get_shadow_margin(window);
+	menu->width = 200;
+	menu->height = menu->count * 20 + margin * 2;
 
 	frame_interior(menu->frame, &ix, &iy, NULL, NULL);
 
 	if (!display->xdg_shell)
 		return;
 
+	result = _wl_probe_visible_probe_rectangle(display->probe_visible,
+						   parent->main_surface->surface,
+						   window->x, window->y,
+						   menu->width, menu->height);
+
+	_wl_probe_visible_result_add_listener(result, &probe_result_listener, menu);
+	wl_display_roundtrip(display->display);
+
 	window->xdg_popup = xdg_shell_get_xdg_popup(display->xdg_shell,
 						    window->main_surface->surface,
 						    parent->main_surface->surface,
@@ -5378,6 +5435,10 @@ registry_handle_global(void *data, struct wl_registry *registry, uint32_t id,
 		d->ivi_application =
 			wl_registry_bind(registry, id,
 					 &ivi_application_interface, 1);
+	} else if (strcmp(interface, "_wl_probe_visible") == 0) {
+		d->probe_visible =
+			wl_registry_bind(registry, id,
+					 &_wl_probe_visible_interface, 1);
 	}
 
 	if (d->global_handler)
-- 
2.4.3



More information about the wayland-devel mailing list