commit 3ecd720

Michael Forney  ·  2020-10-22 22:03:59 +0000 UTC
parent 9e70081
xdg_shell: Initial implementation of xdg_popup

There is still more work to do in terms of handling window geometry
and surface roles correctly, but it's a start.

Based on patch by Ian Beyst.
1 files changed,  +153, -1
+153, -1
  1@@ -23,6 +23,7 @@
  2 
  3 #include "xdg_shell.h"
  4 #include "internal.h"
  5+#include "compositor.h"
  6 #include "seat.h"
  7 #include "surface.h"
  8 #include "util.h"
  9@@ -57,6 +58,13 @@ struct xdg_toplevel {
 10 	struct xdg_surface *xdg_surface;
 11 };
 12 
 13+struct xdg_popup {
 14+	struct wl_resource *resource;
 15+	struct xdg_surface *xdg_surface;
 16+	struct xdg_positioner positioner;
 17+	struct compositor_view *view;
 18+};
 19+
 20 /* xdg_positioner */
 21 static void
 22 destroy_positioner(struct wl_resource *resource)
 23@@ -137,6 +145,75 @@ static const struct xdg_positioner_interface positioner_impl = {
 24 	.set_offset = set_offset,
 25 };
 26 
 27+static struct swc_rectangle
 28+calculate_position(struct xdg_positioner *positioner)
 29+{
 30+	struct swc_rectangle r = {
 31+		.x = positioner->offset_x,
 32+		.y = positioner->offset_y,
 33+		.width = positioner->width,
 34+		.height = positioner->height,
 35+	};
 36+
 37+	switch (positioner->anchor) {
 38+	case XDG_POSITIONER_ANCHOR_TOP:
 39+	case XDG_POSITIONER_ANCHOR_TOP_LEFT:
 40+	case XDG_POSITIONER_ANCHOR_TOP_RIGHT:
 41+		r.y += positioner->anchor_y;
 42+		break;
 43+	case XDG_POSITIONER_ANCHOR_BOTTOM:
 44+	case XDG_POSITIONER_ANCHOR_BOTTOM_LEFT:
 45+	case XDG_POSITIONER_ANCHOR_BOTTOM_RIGHT:
 46+		r.y += positioner->anchor_y + positioner->anchor_height;
 47+		break;
 48+	default:
 49+		r.y += positioner->anchor_y + positioner->anchor_height / 2;
 50+	}
 51+	switch (positioner->anchor) {
 52+	case XDG_POSITIONER_ANCHOR_LEFT:
 53+	case XDG_POSITIONER_ANCHOR_TOP_LEFT:
 54+	case XDG_POSITIONER_ANCHOR_BOTTOM_LEFT:
 55+		r.x += positioner->anchor_x;
 56+		break;
 57+	case XDG_POSITIONER_ANCHOR_RIGHT:
 58+	case XDG_POSITIONER_ANCHOR_TOP_RIGHT:
 59+	case XDG_POSITIONER_ANCHOR_BOTTOM_RIGHT:
 60+		r.x += positioner->anchor_x + positioner->anchor_width;
 61+		break;
 62+	default:
 63+		r.x += positioner->anchor_x + positioner->anchor_width / 2;
 64+	}
 65+
 66+	switch (positioner->gravity) {
 67+	case XDG_POSITIONER_GRAVITY_TOP:
 68+	case XDG_POSITIONER_GRAVITY_TOP_LEFT:
 69+	case XDG_POSITIONER_GRAVITY_TOP_RIGHT:
 70+		r.y -= r.height;
 71+		break;
 72+	case XDG_POSITIONER_GRAVITY_BOTTOM:
 73+	case XDG_POSITIONER_GRAVITY_BOTTOM_LEFT:
 74+	case XDG_POSITIONER_GRAVITY_BOTTOM_RIGHT:
 75+		break;
 76+	default:
 77+		r.y -= r.height / 2;
 78+	}
 79+	switch (positioner->gravity) {
 80+	case XDG_POSITIONER_GRAVITY_LEFT:
 81+	case XDG_POSITIONER_GRAVITY_TOP_LEFT:
 82+	case XDG_POSITIONER_GRAVITY_BOTTOM_LEFT:
 83+		r.x -= r.width;
 84+		break;
 85+	case XDG_POSITIONER_GRAVITY_RIGHT:
 86+	case XDG_POSITIONER_GRAVITY_TOP_RIGHT:
 87+	case XDG_POSITIONER_GRAVITY_BOTTOM_RIGHT:
 88+		break;
 89+	default:
 90+		r.x -= r.width / 2;
 91+	}
 92+
 93+	return r;
 94+}
 95+
 96 /* xdg_toplevel */
 97 static void
 98 destroy_toplevel(struct wl_resource *resource)
 99@@ -393,6 +470,65 @@ error0:
100 	return NULL;
101 }
102 
103+/* xdg_popup */
104+static void
105+destroy_popup(struct wl_resource *resource)
106+{
107+	struct xdg_popup *popup = wl_resource_get_user_data(resource);
108+
109+	compositor_view_destroy(popup->view);
110+	free(popup);
111+}
112+
113+static void
114+grab(struct wl_client *client, struct wl_resource *resource, struct wl_resource *seat, uint32_t serial)
115+{
116+}
117+
118+static const struct xdg_popup_interface popup_impl = {
119+	.destroy = destroy_resource,
120+	.grab = grab,
121+};
122+
123+static struct xdg_popup *
124+xdg_popup_new(struct wl_client *client, uint32_t version, uint32_t id, struct xdg_surface *xdg_surface, struct xdg_surface *parent, struct xdg_positioner *positioner)
125+{
126+	struct xdg_popup *popup;
127+	struct compositor_view *parent_view = compositor_view(parent->surface->view);
128+	uint32_t serial = wl_display_next_serial(swc.display);
129+	struct swc_rectangle rect;
130+
131+	if (!parent_view)
132+		goto error0;
133+	popup = malloc(sizeof(*popup));
134+	if (!popup)
135+		goto error0;
136+	popup->xdg_surface = xdg_surface;
137+	popup->positioner = *positioner;
138+	popup->resource = wl_resource_create(client, &xdg_popup_interface, version, id);
139+	if (!popup->resource)
140+		goto error1;
141+	wl_resource_set_implementation(popup->resource, &popup_impl, popup, &destroy_popup);
142+	popup->view = compositor_create_view(xdg_surface->surface);
143+	if (!popup->view)
144+		goto error2;
145+
146+	rect = calculate_position(positioner);
147+	compositor_view_set_parent(popup->view, parent_view);
148+	view_move(&popup->view->base, parent_view->base.geometry.x + rect.x, parent_view->base.geometry.y + rect.y);
149+	xdg_popup_send_configure(popup->resource, rect.x, rect.y, rect.width, rect.height);
150+	xdg_surface_send_configure(xdg_surface->resource, serial);
151+
152+	return popup;
153+
154+error2:
155+	wl_resource_destroy(popup->resource);
156+error1:
157+	free(popup);
158+error0:
159+	return NULL;
160+}
161+
162 /* xdg_surface */
163 static void
164 get_toplevel(struct wl_client *client, struct wl_resource *resource, uint32_t id)
165@@ -414,8 +550,24 @@ get_toplevel(struct wl_client *client, struct wl_resource *resource, uint32_t id
166 }
167 
168 static void
169-get_popup(struct wl_client *client, struct wl_resource *resource, uint32_t id, struct wl_resource *parent, struct wl_resource *positioner)
170+get_popup(struct wl_client *client, struct wl_resource *resource, uint32_t id, struct wl_resource *parent_resource, struct wl_resource *positioner_resource)
171 {
172+	struct xdg_surface *xdg_surface = wl_resource_get_user_data(resource);
173+	struct xdg_surface *parent = wl_resource_get_user_data(parent_resource);
174+	struct xdg_positioner *positioner = wl_resource_get_user_data(positioner_resource);
175+	struct xdg_popup *popup;
176+
177+	if (xdg_surface->role) {
178+		wl_resource_post_error(resource, XDG_WM_BASE_ERROR_ROLE, "surface already has a role");
179+		return;
180+	}
181+	popup = xdg_popup_new(client, wl_resource_get_version(resource), id, xdg_surface, parent, positioner);
182+	if (!popup) {
183+		wl_client_post_no_memory(client);
184+		return;
185+	}
186+	xdg_surface->role = popup->resource;
187+	wl_resource_add_destroy_listener(xdg_surface->role, &xdg_surface->role_destroy_listener);
188 }
189 
190 static void