|  |  |  | @ -38,6 +38,7 @@ static void popup_destroy(struct sway_view_child *child) { | 
			
		
	
		
			
				
					|  |  |  |  | 		return; | 
			
		
	
		
			
				
					|  |  |  |  | 	} | 
			
		
	
		
			
				
					|  |  |  |  | 	struct sway_xdg_popup *popup = (struct sway_xdg_popup *)child; | 
			
		
	
		
			
				
					|  |  |  |  | 	wl_list_remove(&popup->surface_commit.link); | 
			
		
	
		
			
				
					|  |  |  |  | 	wl_list_remove(&popup->new_popup.link); | 
			
		
	
		
			
				
					|  |  |  |  | 	wl_list_remove(&popup->destroy.link); | 
			
		
	
		
			
				
					|  |  |  |  | 	free(popup); | 
			
		
	
	
		
			
				
					|  |  |  | @ -51,18 +52,6 @@ static const struct sway_view_child_impl popup_impl = { | 
			
		
	
		
			
				
					|  |  |  |  | static struct sway_xdg_popup *popup_create( | 
			
		
	
		
			
				
					|  |  |  |  | 	struct wlr_xdg_popup *wlr_popup, struct sway_view *view); | 
			
		
	
		
			
				
					|  |  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  |  | static void popup_handle_new_popup(struct wl_listener *listener, void *data) { | 
			
		
	
		
			
				
					|  |  |  |  | 	struct sway_xdg_popup *popup = | 
			
		
	
		
			
				
					|  |  |  |  | 		wl_container_of(listener, popup, new_popup); | 
			
		
	
		
			
				
					|  |  |  |  | 	struct wlr_xdg_popup *wlr_popup = data; | 
			
		
	
		
			
				
					|  |  |  |  | 	popup_create(wlr_popup, popup->child.view); | 
			
		
	
		
			
				
					|  |  |  |  | } | 
			
		
	
		
			
				
					|  |  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  |  | static void popup_handle_destroy(struct wl_listener *listener, void *data) { | 
			
		
	
		
			
				
					|  |  |  |  | 	struct sway_xdg_popup *popup = wl_container_of(listener, popup, destroy); | 
			
		
	
		
			
				
					|  |  |  |  | 	view_child_destroy(&popup->child); | 
			
		
	
		
			
				
					|  |  |  |  | } | 
			
		
	
		
			
				
					|  |  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  |  | static void popup_unconstrain(struct sway_xdg_popup *popup) { | 
			
		
	
		
			
				
					|  |  |  |  | 	struct sway_view *view = popup->child.view; | 
			
		
	
		
			
				
					|  |  |  |  | 	struct wlr_xdg_popup *wlr_popup = popup->wlr_xdg_popup; | 
			
		
	
	
		
			
				
					|  |  |  | @ -87,6 +76,25 @@ static void popup_unconstrain(struct sway_xdg_popup *popup) { | 
			
		
	
		
			
				
					|  |  |  |  | 	wlr_xdg_popup_unconstrain_from_box(wlr_popup, &output_toplevel_sx_box); | 
			
		
	
		
			
				
					|  |  |  |  | } | 
			
		
	
		
			
				
					|  |  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  |  | static void popup_handle_surface_commit(struct wl_listener *listener, void *data) { | 
			
		
	
		
			
				
					|  |  |  |  | 	struct sway_xdg_popup *popup = wl_container_of(listener, popup, surface_commit); | 
			
		
	
		
			
				
					|  |  |  |  | 	if (popup->wlr_xdg_popup->base->initial_commit) { | 
			
		
	
		
			
				
					|  |  |  |  | 		popup_unconstrain(popup); | 
			
		
	
		
			
				
					|  |  |  |  | 	} | 
			
		
	
		
			
				
					|  |  |  |  | } | 
			
		
	
		
			
				
					|  |  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  |  | static void popup_handle_new_popup(struct wl_listener *listener, void *data) { | 
			
		
	
		
			
				
					|  |  |  |  | 	struct sway_xdg_popup *popup = | 
			
		
	
		
			
				
					|  |  |  |  | 		wl_container_of(listener, popup, new_popup); | 
			
		
	
		
			
				
					|  |  |  |  | 	struct wlr_xdg_popup *wlr_popup = data; | 
			
		
	
		
			
				
					|  |  |  |  | 	popup_create(wlr_popup, popup->child.view); | 
			
		
	
		
			
				
					|  |  |  |  | } | 
			
		
	
		
			
				
					|  |  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  |  | static void popup_handle_destroy(struct wl_listener *listener, void *data) { | 
			
		
	
		
			
				
					|  |  |  |  | 	struct sway_xdg_popup *popup = wl_container_of(listener, popup, destroy); | 
			
		
	
		
			
				
					|  |  |  |  | 	view_child_destroy(&popup->child); | 
			
		
	
		
			
				
					|  |  |  |  | } | 
			
		
	
		
			
				
					|  |  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  |  | static struct sway_xdg_popup *popup_create( | 
			
		
	
		
			
				
					|  |  |  |  | 		struct wlr_xdg_popup *wlr_popup, struct sway_view *view) { | 
			
		
	
		
			
				
					|  |  |  |  | 	struct wlr_xdg_surface *xdg_surface = wlr_popup->base; | 
			
		
	
	
		
			
				
					|  |  |  | @ -97,22 +105,21 @@ static struct sway_xdg_popup *popup_create( | 
			
		
	
		
			
				
					|  |  |  |  | 		return NULL; | 
			
		
	
		
			
				
					|  |  |  |  | 	} | 
			
		
	
		
			
				
					|  |  |  |  | 	view_child_init(&popup->child, &popup_impl, view, xdg_surface->surface); | 
			
		
	
		
			
				
					|  |  |  |  | 	popup->wlr_xdg_popup = xdg_surface->popup; | 
			
		
	
		
			
				
					|  |  |  |  | 	popup->wlr_xdg_popup = wlr_popup; | 
			
		
	
		
			
				
					|  |  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  |  | 	wl_signal_add(&xdg_surface->surface->events.commit, &popup->surface_commit); | 
			
		
	
		
			
				
					|  |  |  |  | 	popup->surface_commit.notify = popup_handle_surface_commit; | 
			
		
	
		
			
				
					|  |  |  |  | 	wl_signal_add(&xdg_surface->events.new_popup, &popup->new_popup); | 
			
		
	
		
			
				
					|  |  |  |  | 	popup->new_popup.notify = popup_handle_new_popup; | 
			
		
	
		
			
				
					|  |  |  |  | 	wl_signal_add(&xdg_surface->events.destroy, &popup->destroy); | 
			
		
	
		
			
				
					|  |  |  |  | 	wl_signal_add(&wlr_popup->events.destroy, &popup->destroy); | 
			
		
	
		
			
				
					|  |  |  |  | 	popup->destroy.notify = popup_handle_destroy; | 
			
		
	
		
			
				
					|  |  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  |  | 	wl_signal_add(&xdg_surface->surface->events.map, &popup->child.surface_map); | 
			
		
	
		
			
				
					|  |  |  |  | 	wl_signal_add(&xdg_surface->surface->events.unmap, &popup->child.surface_unmap); | 
			
		
	
		
			
				
					|  |  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  |  | 	popup_unconstrain(popup); | 
			
		
	
		
			
				
					|  |  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  |  | 	return popup; | 
			
		
	
		
			
				
					|  |  |  |  | } | 
			
		
	
		
			
				
					|  |  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  |  | static struct sway_xdg_shell_view *xdg_shell_view_from_view( | 
			
		
	
		
			
				
					|  |  |  |  | 		struct sway_view *view) { | 
			
		
	
		
			
				
					|  |  |  |  | 	if (!sway_assert(view->type == SWAY_VIEW_XDG_SHELL, | 
			
		
	
	
		
			
				
					|  |  |  | @ -286,6 +293,19 @@ static void handle_commit(struct wl_listener *listener, void *data) { | 
			
		
	
		
			
				
					|  |  |  |  | 	struct sway_view *view = &xdg_shell_view->view; | 
			
		
	
		
			
				
					|  |  |  |  | 	struct wlr_xdg_surface *xdg_surface = view->wlr_xdg_toplevel->base; | 
			
		
	
		
			
				
					|  |  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  |  | 	if (xdg_surface->initial_commit) { | 
			
		
	
		
			
				
					|  |  |  |  | 		if (view->xdg_decoration != NULL) { | 
			
		
	
		
			
				
					|  |  |  |  | 			set_xdg_decoration_mode(view->xdg_decoration); | 
			
		
	
		
			
				
					|  |  |  |  | 		} | 
			
		
	
		
			
				
					|  |  |  |  | 		// XXX: https://github.com/swaywm/sway/issues/2176
 | 
			
		
	
		
			
				
					|  |  |  |  | 		wlr_xdg_surface_schedule_configure(xdg_surface); | 
			
		
	
		
			
				
					|  |  |  |  | 		return; | 
			
		
	
		
			
				
					|  |  |  |  | 	} | 
			
		
	
		
			
				
					|  |  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  |  | 	if (!xdg_surface->surface->mapped) { | 
			
		
	
		
			
				
					|  |  |  |  | 		return; | 
			
		
	
		
			
				
					|  |  |  |  | 	} | 
			
		
	
		
			
				
					|  |  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  |  | 	struct wlr_box new_geo; | 
			
		
	
		
			
				
					|  |  |  |  | 	wlr_xdg_surface_get_geometry(xdg_surface, &new_geo); | 
			
		
	
		
			
				
					|  |  |  |  | 	bool new_size = new_geo.width != view->geometry.width || | 
			
		
	
	
		
			
				
					|  |  |  | @ -421,7 +441,6 @@ static void handle_unmap(struct wl_listener *listener, void *data) { | 
			
		
	
		
			
				
					|  |  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  |  | 	view_unmap(view); | 
			
		
	
		
			
				
					|  |  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  |  | 	wl_list_remove(&xdg_shell_view->commit.link); | 
			
		
	
		
			
				
					|  |  |  |  | 	wl_list_remove(&xdg_shell_view->new_popup.link); | 
			
		
	
		
			
				
					|  |  |  |  | 	wl_list_remove(&xdg_shell_view->request_maximize.link); | 
			
		
	
		
			
				
					|  |  |  |  | 	wl_list_remove(&xdg_shell_view->request_fullscreen.link); | 
			
		
	
	
		
			
				
					|  |  |  | @ -464,10 +483,6 @@ static void handle_map(struct wl_listener *listener, void *data) { | 
			
		
	
		
			
				
					|  |  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  |  | 	transaction_commit_dirty(); | 
			
		
	
		
			
				
					|  |  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  |  | 	xdg_shell_view->commit.notify = handle_commit; | 
			
		
	
		
			
				
					|  |  |  |  | 	wl_signal_add(&toplevel->base->surface->events.commit, | 
			
		
	
		
			
				
					|  |  |  |  | 		&xdg_shell_view->commit); | 
			
		
	
		
			
				
					|  |  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  |  | 	xdg_shell_view->new_popup.notify = handle_new_popup; | 
			
		
	
		
			
				
					|  |  |  |  | 	wl_signal_add(&toplevel->base->events.new_popup, | 
			
		
	
		
			
				
					|  |  |  |  | 		&xdg_shell_view->new_popup); | 
			
		
	
	
		
			
				
					|  |  |  | @ -507,6 +522,7 @@ static void handle_destroy(struct wl_listener *listener, void *data) { | 
			
		
	
		
			
				
					|  |  |  |  | 	wl_list_remove(&xdg_shell_view->destroy.link); | 
			
		
	
		
			
				
					|  |  |  |  | 	wl_list_remove(&xdg_shell_view->map.link); | 
			
		
	
		
			
				
					|  |  |  |  | 	wl_list_remove(&xdg_shell_view->unmap.link); | 
			
		
	
		
			
				
					|  |  |  |  | 	wl_list_remove(&xdg_shell_view->commit.link); | 
			
		
	
		
			
				
					|  |  |  |  | 	view->wlr_xdg_toplevel = NULL; | 
			
		
	
		
			
				
					|  |  |  |  | 	if (view->xdg_decoration) { | 
			
		
	
		
			
				
					|  |  |  |  | 		view->xdg_decoration->view = NULL; | 
			
		
	
	
		
			
				
					|  |  |  | @ -519,17 +535,12 @@ struct sway_view *view_from_wlr_xdg_surface( | 
			
		
	
		
			
				
					|  |  |  |  | 	return xdg_surface->data; | 
			
		
	
		
			
				
					|  |  |  |  | } | 
			
		
	
		
			
				
					|  |  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  |  | void handle_xdg_shell_surface(struct wl_listener *listener, void *data) { | 
			
		
	
		
			
				
					|  |  |  |  | 	struct wlr_xdg_surface *xdg_surface = data; | 
			
		
	
		
			
				
					|  |  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  |  | 	if (xdg_surface->role == WLR_XDG_SURFACE_ROLE_POPUP) { | 
			
		
	
		
			
				
					|  |  |  |  | 		sway_log(SWAY_DEBUG, "New xdg_shell popup"); | 
			
		
	
		
			
				
					|  |  |  |  | 		return; | 
			
		
	
		
			
				
					|  |  |  |  | 	} | 
			
		
	
		
			
				
					|  |  |  |  | void handle_xdg_shell_toplevel(struct wl_listener *listener, void *data) { | 
			
		
	
		
			
				
					|  |  |  |  | 	struct wlr_xdg_toplevel *xdg_toplevel = data; | 
			
		
	
		
			
				
					|  |  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  |  | 	sway_log(SWAY_DEBUG, "New xdg_shell toplevel title='%s' app_id='%s'", | 
			
		
	
		
			
				
					|  |  |  |  | 		xdg_surface->toplevel->title, xdg_surface->toplevel->app_id); | 
			
		
	
		
			
				
					|  |  |  |  | 	wlr_xdg_surface_ping(xdg_surface); | 
			
		
	
		
			
				
					|  |  |  |  | 		xdg_toplevel->title, xdg_toplevel->app_id); | 
			
		
	
		
			
				
					|  |  |  |  | 	wlr_xdg_surface_ping(xdg_toplevel->base); | 
			
		
	
		
			
				
					|  |  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  |  | 	struct sway_xdg_shell_view *xdg_shell_view = | 
			
		
	
		
			
				
					|  |  |  |  | 		calloc(1, sizeof(struct sway_xdg_shell_view)); | 
			
		
	
	
		
			
				
					|  |  |  | @ -538,16 +549,20 @@ void handle_xdg_shell_surface(struct wl_listener *listener, void *data) { | 
			
		
	
		
			
				
					|  |  |  |  | 	} | 
			
		
	
		
			
				
					|  |  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  |  | 	view_init(&xdg_shell_view->view, SWAY_VIEW_XDG_SHELL, &view_impl); | 
			
		
	
		
			
				
					|  |  |  |  | 	xdg_shell_view->view.wlr_xdg_toplevel = xdg_surface->toplevel; | 
			
		
	
		
			
				
					|  |  |  |  | 	xdg_shell_view->view.wlr_xdg_toplevel = xdg_toplevel; | 
			
		
	
		
			
				
					|  |  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  |  | 	xdg_shell_view->map.notify = handle_map; | 
			
		
	
		
			
				
					|  |  |  |  | 	wl_signal_add(&xdg_surface->surface->events.map, &xdg_shell_view->map); | 
			
		
	
		
			
				
					|  |  |  |  | 	wl_signal_add(&xdg_toplevel->base->surface->events.map, &xdg_shell_view->map); | 
			
		
	
		
			
				
					|  |  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  |  | 	xdg_shell_view->unmap.notify = handle_unmap; | 
			
		
	
		
			
				
					|  |  |  |  | 	wl_signal_add(&xdg_surface->surface->events.unmap, &xdg_shell_view->unmap); | 
			
		
	
		
			
				
					|  |  |  |  | 	wl_signal_add(&xdg_toplevel->base->surface->events.unmap, &xdg_shell_view->unmap); | 
			
		
	
		
			
				
					|  |  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  |  | 	xdg_shell_view->commit.notify = handle_commit; | 
			
		
	
		
			
				
					|  |  |  |  | 	wl_signal_add(&xdg_toplevel->base->surface->events.commit, | 
			
		
	
		
			
				
					|  |  |  |  | 		&xdg_shell_view->commit); | 
			
		
	
		
			
				
					|  |  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  |  | 	xdg_shell_view->destroy.notify = handle_destroy; | 
			
		
	
		
			
				
					|  |  |  |  | 	wl_signal_add(&xdg_surface->events.destroy, &xdg_shell_view->destroy); | 
			
		
	
		
			
				
					|  |  |  |  | 	wl_signal_add(&xdg_toplevel->events.destroy, &xdg_shell_view->destroy); | 
			
		
	
		
			
				
					|  |  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  |  | 	xdg_surface->data = xdg_shell_view; | 
			
		
	
		
			
				
					|  |  |  |  | 	xdg_toplevel->base->data = xdg_shell_view; | 
			
		
	
		
			
				
					|  |  |  |  | } | 
			
		
	
	
		
			
				
					|  |  |  | 
 |