66 * See the LICENSE file accompanying this file.
77 */
88
9+ #include <assert.h>
910#include <stdbool.h>
1011#include <stdlib.h>
1112#include <wayland-server-core.h>
@@ -41,67 +42,32 @@ xdg_decoration_handle_request_mode(struct wl_listener *listener, void *data)
4142 wlr_xdg_toplevel_decoration_v1_set_mode (xdg_decoration -> wlr_decoration , mode );
4243}
4344
44- static void
45- xdg_popup_destroy (struct cg_view_child * child )
45+ static struct cg_view *
46+ popup_get_view (struct wlr_xdg_popup * popup )
4647{
47- if (!child ) {
48- return ;
49- }
50-
51- struct cg_xdg_popup * popup = (struct cg_xdg_popup * ) child ;
52- wl_list_remove (& popup -> destroy .link );
53- wl_list_remove (& popup -> map .link );
54- wl_list_remove (& popup -> unmap .link );
55- wl_list_remove (& popup -> new_popup .link );
56- view_child_finish (& popup -> view_child );
57- free (popup );
58- }
48+ while (true) {
49+ if (popup -> parent == NULL || !wlr_surface_is_xdg_surface (popup -> parent )) {
50+ return NULL ;
51+ }
5952
60- static void
61- handle_xdg_popup_map (struct wl_listener * listener , void * data )
62- {
63- struct cg_xdg_popup * popup = wl_container_of (listener , popup , map );
64- struct wlr_scene_node * parent_node = popup -> view_child .view -> scene_node ;
65- popup -> scene_surface = wlr_scene_surface_create (parent_node , popup -> view_child .wlr_surface );
66- if (!popup -> scene_surface ) {
67- return ;
53+ struct wlr_xdg_surface * xdg_surface = wlr_xdg_surface_from_wlr_surface (popup -> parent );
54+ switch (xdg_surface -> role ) {
55+ case WLR_XDG_SURFACE_ROLE_TOPLEVEL :
56+ return xdg_surface -> data ;
57+ case WLR_XDG_SURFACE_ROLE_POPUP :
58+ popup = xdg_surface -> popup ;
59+ break ;
60+ case WLR_XDG_SURFACE_ROLE_NONE :
61+ return NULL ;
62+ }
6863 }
69- double sx , sy ;
70- wlr_xdg_popup_get_position (popup -> wlr_popup , & sx , & sy );
71- wlr_scene_node_set_position (& popup -> scene_surface -> node , sx , sy );
72- }
73-
74- static void
75- handle_xdg_popup_unmap (struct wl_listener * listener , void * data )
76- {
77- struct cg_xdg_popup * popup = wl_container_of (listener , popup , unmap );
78- wlr_scene_node_destroy (& popup -> scene_surface -> node );
79- }
80-
81- static void
82- handle_xdg_popup_destroy (struct wl_listener * listener , void * data )
83- {
84- struct cg_xdg_popup * popup = wl_container_of (listener , popup , destroy );
85- struct cg_view_child * view_child = (struct cg_view_child * ) popup ;
86- xdg_popup_destroy (view_child );
87- }
88-
89- static void xdg_popup_create (struct cg_view * view , struct wlr_xdg_popup * wlr_popup );
90-
91- static void
92- popup_handle_new_xdg_popup (struct wl_listener * listener , void * data )
93- {
94- struct cg_xdg_popup * popup = wl_container_of (listener , popup , new_popup );
95- struct wlr_xdg_popup * wlr_popup = data ;
96- xdg_popup_create (popup -> view_child .view , wlr_popup );
9764}
9865
9966static void
100- popup_unconstrain (struct cg_xdg_popup * popup )
67+ popup_unconstrain (struct cg_view * view , struct wlr_xdg_popup * popup )
10168{
102- struct cg_view * view = popup -> view_child .view ;
10369 struct cg_server * server = view -> server ;
104- struct wlr_box * popup_box = & popup -> wlr_popup -> geometry ;
70+ struct wlr_box * popup_box = & popup -> geometry ;
10571
10672 struct wlr_output_layout * output_layout = server -> output_layout ;
10773 struct wlr_output * wlr_output =
@@ -115,38 +81,7 @@ popup_unconstrain(struct cg_xdg_popup *popup)
11581 .height = output_box -> height ,
11682 };
11783
118- wlr_xdg_popup_unconstrain_from_box (popup -> wlr_popup , & output_toplevel_box );
119- }
120-
121- static void
122- xdg_popup_create (struct cg_view * view , struct wlr_xdg_popup * wlr_popup )
123- {
124- struct cg_xdg_popup * popup = calloc (1 , sizeof (struct cg_xdg_popup ));
125- if (!popup ) {
126- return ;
127- }
128-
129- popup -> wlr_popup = wlr_popup ;
130- view_child_init (& popup -> view_child , view , wlr_popup -> base -> surface );
131- popup -> view_child .destroy = xdg_popup_destroy ;
132- popup -> destroy .notify = handle_xdg_popup_destroy ;
133- wl_signal_add (& wlr_popup -> base -> events .destroy , & popup -> destroy );
134- popup -> map .notify = handle_xdg_popup_map ;
135- wl_signal_add (& wlr_popup -> base -> events .map , & popup -> map );
136- popup -> unmap .notify = handle_xdg_popup_unmap ;
137- wl_signal_add (& wlr_popup -> base -> events .unmap , & popup -> unmap );
138- popup -> new_popup .notify = popup_handle_new_xdg_popup ;
139- wl_signal_add (& wlr_popup -> base -> events .new_popup , & popup -> new_popup );
140-
141- popup_unconstrain (popup );
142- }
143-
144- static void
145- handle_new_xdg_popup (struct wl_listener * listener , void * data )
146- {
147- struct cg_xdg_shell_view * xdg_shell_view = wl_container_of (listener , xdg_shell_view , new_popup );
148- struct wlr_xdg_popup * wlr_popup = data ;
149- xdg_popup_create (& xdg_shell_view -> view , wlr_popup );
84+ wlr_xdg_popup_unconstrain_from_box (popup , & output_toplevel_box );
15085}
15186
15287static struct cg_xdg_shell_view *
@@ -261,7 +196,6 @@ handle_xdg_shell_surface_destroy(struct wl_listener *listener, void *data)
261196 wl_list_remove (& xdg_shell_view -> unmap .link );
262197 wl_list_remove (& xdg_shell_view -> destroy .link );
263198 wl_list_remove (& xdg_shell_view -> request_fullscreen .link );
264- wl_list_remove (& xdg_shell_view -> new_popup .link );
265199 xdg_shell_view -> xdg_surface = NULL ;
266200
267201 view_destroy (view );
@@ -283,29 +217,64 @@ handle_xdg_shell_surface_new(struct wl_listener *listener, void *data)
283217 struct cg_server * server = wl_container_of (listener , server , new_xdg_shell_surface );
284218 struct wlr_xdg_surface * xdg_surface = data ;
285219
286- if (xdg_surface -> role != WLR_XDG_SURFACE_ROLE_TOPLEVEL ) {
287- return ;
288- }
220+ switch (xdg_surface -> role ) {
221+ case WLR_XDG_SURFACE_ROLE_TOPLEVEL :;
222+ struct cg_xdg_shell_view * xdg_shell_view = calloc (1 , sizeof (struct cg_xdg_shell_view ));
223+ if (!xdg_shell_view ) {
224+ wlr_log (WLR_ERROR , "Failed to allocate XDG Shell view" );
225+ return ;
226+ }
289227
290- struct cg_xdg_shell_view * xdg_shell_view = calloc (1 , sizeof (struct cg_xdg_shell_view ));
291- if (!xdg_shell_view ) {
292- wlr_log (WLR_ERROR , "Failed to allocate XDG Shell view" );
293- return ;
294- }
228+ view_init (& xdg_shell_view -> view , server , CAGE_XDG_SHELL_VIEW , & xdg_shell_view_impl );
229+ xdg_shell_view -> xdg_surface = xdg_surface ;
230+
231+ xdg_shell_view -> map .notify = handle_xdg_shell_surface_map ;
232+ wl_signal_add (& xdg_surface -> events .map , & xdg_shell_view -> map );
233+ xdg_shell_view -> unmap .notify = handle_xdg_shell_surface_unmap ;
234+ wl_signal_add (& xdg_surface -> events .unmap , & xdg_shell_view -> unmap );
235+ xdg_shell_view -> destroy .notify = handle_xdg_shell_surface_destroy ;
236+ wl_signal_add (& xdg_surface -> events .destroy , & xdg_shell_view -> destroy );
237+ xdg_shell_view -> request_fullscreen .notify = handle_xdg_shell_surface_request_fullscreen ;
238+ wl_signal_add (& xdg_surface -> toplevel -> events .request_fullscreen , & xdg_shell_view -> request_fullscreen );
239+
240+ xdg_surface -> data = xdg_shell_view ;
241+ break ;
242+ case WLR_XDG_SURFACE_ROLE_POPUP :;
243+ struct wlr_xdg_popup * popup = xdg_surface -> popup ;
244+ struct cg_view * view = popup_get_view (popup );
245+ if (view == NULL ) {
246+ return ;
247+ }
295248
296- view_init (& xdg_shell_view -> view , server , CAGE_XDG_SHELL_VIEW , & xdg_shell_view_impl );
297- xdg_shell_view -> xdg_surface = xdg_surface ;
298-
299- xdg_shell_view -> map .notify = handle_xdg_shell_surface_map ;
300- wl_signal_add (& xdg_surface -> events .map , & xdg_shell_view -> map );
301- xdg_shell_view -> unmap .notify = handle_xdg_shell_surface_unmap ;
302- wl_signal_add (& xdg_surface -> events .unmap , & xdg_shell_view -> unmap );
303- xdg_shell_view -> destroy .notify = handle_xdg_shell_surface_destroy ;
304- wl_signal_add (& xdg_surface -> events .destroy , & xdg_shell_view -> destroy );
305- xdg_shell_view -> request_fullscreen .notify = handle_xdg_shell_surface_request_fullscreen ;
306- wl_signal_add (& xdg_surface -> toplevel -> events .request_fullscreen , & xdg_shell_view -> request_fullscreen );
307- xdg_shell_view -> new_popup .notify = handle_new_xdg_popup ;
308- wl_signal_add (& xdg_surface -> events .new_popup , & xdg_shell_view -> new_popup );
249+ struct wlr_scene_node * parent_scene_node = NULL ;
250+ struct wlr_xdg_surface * parent = wlr_xdg_surface_from_wlr_surface (popup -> parent );
251+ switch (parent -> role ) {
252+ case WLR_XDG_SURFACE_ROLE_TOPLEVEL :;
253+ parent_scene_node = view -> scene_node ;
254+ break ;
255+ case WLR_XDG_SURFACE_ROLE_POPUP :
256+ parent_scene_node = parent -> data ;
257+ break ;
258+ case WLR_XDG_SURFACE_ROLE_NONE :
259+ break ;
260+ }
261+ if (parent_scene_node == NULL ) {
262+ return ;
263+ }
264+
265+ struct wlr_scene_node * popup_scene_node = wlr_scene_xdg_popup_create (parent_scene_node , popup );
266+ if (popup_scene_node == NULL ) {
267+ wlr_log (WLR_ERROR , "Failed to allocate scene-graph node for XDG popup" );
268+ return ;
269+ }
270+
271+ popup_unconstrain (view , popup );
272+
273+ xdg_surface -> data = popup_scene_node ;
274+ break ;
275+ case WLR_XDG_SURFACE_ROLE_NONE :
276+ assert (false); // unreachable
277+ }
309278}
310279
311280void
0 commit comments