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