mirror of
				https://github.com/labwc/labwc.git
				synced 2025-10-29 05:40:24 -04:00 
			
		
		
		
	output,xwayland: Add support for _NET_WM_STRUT_PARTIAL
Account for space taken up by XWayland panels (as indicated by the _NET_WM_STRUT_PARTIAL property) in the usable_area calculation. This makes it possible to use labwc in a "transitional" setup, where it replaces the X11 window manager and compositor, but most other parts of a existing X11 desktop environment can still be used via XWayland. (Some remaining drawbacks of such a setup would be the lack of desktop icons, and native Wayland clients not showing up in X11-based taskbars.)
This commit is contained in:
		
							parent
							
								
									a9076f2a01
								
							
						
					
					
						commit
						0a5255f062
					
				
					 3 changed files with 129 additions and 0 deletions
				
			
		|  | @ -6,6 +6,8 @@ | |||
| #include "view.h" | ||||
| 
 | ||||
| struct wlr_compositor; | ||||
| struct wlr_output; | ||||
| struct wlr_output_layout; | ||||
| 
 | ||||
| struct xwayland_unmanaged { | ||||
| 	struct server *server; | ||||
|  | @ -37,6 +39,7 @@ struct xwayland_view { | |||
| 	struct wl_listener set_class; | ||||
| 	struct wl_listener set_decorations; | ||||
| 	struct wl_listener set_override_redirect; | ||||
| 	struct wl_listener set_strut_partial; | ||||
| 
 | ||||
| 	/* Not (yet) implemented */ | ||||
| /*	struct wl_listener set_role; */ | ||||
|  | @ -58,6 +61,10 @@ void xwayland_server_init(struct server *server, | |||
| 	struct wlr_compositor *compositor); | ||||
| void xwayland_server_finish(struct server *server); | ||||
| 
 | ||||
| void xwayland_adjust_usable_area(struct view *view, | ||||
| 	struct wlr_output_layout *layout, struct wlr_output *output, | ||||
| 	struct wlr_box *usable); | ||||
| 
 | ||||
| void xwayland_update_workarea(struct server *server); | ||||
| 
 | ||||
| #endif /* HAVE_XWAYLAND */ | ||||
|  |  | |||
							
								
								
									
										10
									
								
								src/output.c
									
										
									
									
									
								
							
							
						
						
									
										10
									
								
								src/output.c
									
										
									
									
									
								
							|  | @ -603,6 +603,16 @@ update_usable_area(struct output *output) | |||
| 	struct wlr_box old = output->usable_area; | ||||
| 	layers_arrange(output); | ||||
| 
 | ||||
| #if HAVE_XWAYLAND | ||||
| 	struct view *view; | ||||
| 	wl_list_for_each(view, &output->server->views, link) { | ||||
| 		if (view->mapped && view->type == LAB_XWAYLAND_VIEW) { | ||||
| 			xwayland_adjust_usable_area(view, | ||||
| 				output->server->output_layout, | ||||
| 				output->wlr_output, &output->usable_area); | ||||
| 		} | ||||
| 	} | ||||
| #endif | ||||
| 	return !wlr_box_equal(&old, &output->usable_area); | ||||
| } | ||||
| 
 | ||||
|  |  | |||
							
								
								
									
										112
									
								
								src/xwayland.c
									
										
									
									
									
								
							
							
						
						
									
										112
									
								
								src/xwayland.c
									
										
									
									
									
								
							|  | @ -291,6 +291,7 @@ handle_destroy(struct wl_listener *listener, void *data) | |||
| 	wl_list_remove(&xwayland_view->set_class.link); | ||||
| 	wl_list_remove(&xwayland_view->set_decorations.link); | ||||
| 	wl_list_remove(&xwayland_view->set_override_redirect.link); | ||||
| 	wl_list_remove(&xwayland_view->set_strut_partial.link); | ||||
| 
 | ||||
| 	view_destroy(view); | ||||
| } | ||||
|  | @ -463,6 +464,18 @@ handle_set_override_redirect(struct wl_listener *listener, void *data) | |||
| 	xwayland_unmanaged_create(server, xsurface, mapped); | ||||
| } | ||||
| 
 | ||||
| static void | ||||
| handle_set_strut_partial(struct wl_listener *listener, void *data) | ||||
| { | ||||
| 	struct xwayland_view *xwayland_view = | ||||
| 		wl_container_of(listener, xwayland_view, set_strut_partial); | ||||
| 	struct view *view = &xwayland_view->base; | ||||
| 
 | ||||
| 	if (view->mapped) { | ||||
| 		output_update_all_usable_areas(view->server, false); | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| static void | ||||
| set_initial_position(struct view *view, | ||||
| 		struct wlr_xwayland_surface *xwayland_surface) | ||||
|  | @ -605,6 +618,11 @@ xwayland_view_map(struct view *view) | |||
| 
 | ||||
| 	view_impl_map(view); | ||||
| 	view->been_mapped = true; | ||||
| 
 | ||||
| 	/* Update usable area to account for XWayland "struts" (panels) */ | ||||
| 	if (xwayland_surface->strut_partial) { | ||||
| 		output_update_all_usable_areas(view->server, false); | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| static void | ||||
|  | @ -618,6 +636,11 @@ xwayland_view_unmap(struct view *view, bool client_request) | |||
| 	wlr_scene_node_set_enabled(&view->scene_tree->node, false); | ||||
| 	view_impl_unmap(view); | ||||
| 
 | ||||
| 	/* Update usable area to account for XWayland "struts" (panels) */ | ||||
| 	if (xwayland_surface_from_view(view)->strut_partial) { | ||||
| 		output_update_all_usable_areas(view->server, false); | ||||
| 	} | ||||
| 
 | ||||
| 	/*
 | ||||
| 	 * If the view was explicitly unmapped by the client (rather | ||||
| 	 * than just minimized), destroy the foreign toplevel handle so | ||||
|  | @ -806,6 +829,7 @@ xwayland_view_create(struct server *server, | |||
| 	CONNECT_SIGNAL(xsurface, xwayland_view, set_class); | ||||
| 	CONNECT_SIGNAL(xsurface, xwayland_view, set_decorations); | ||||
| 	CONNECT_SIGNAL(xsurface, xwayland_view, set_override_redirect); | ||||
| 	CONNECT_SIGNAL(xsurface, xwayland_view, set_strut_partial); | ||||
| 
 | ||||
| 	wl_list_insert(&view->server->views, &view->link); | ||||
| 
 | ||||
|  | @ -930,6 +954,94 @@ xwayland_server_finish(struct server *server) | |||
| 	wlr_xwayland_destroy(xwayland); | ||||
| } | ||||
| 
 | ||||
| static bool | ||||
| intervals_overlap(int start_a, int end_a, int start_b, int end_b) | ||||
| { | ||||
| 	/* check for empty intervals */ | ||||
| 	if (end_a <= start_a || end_b <= start_b) { | ||||
| 		return false; | ||||
| 	} | ||||
| 
 | ||||
| 	return start_a < start_b ? | ||||
| 		start_b < end_a :  /* B starts within A */ | ||||
| 		start_a < end_b;   /* A starts within B */ | ||||
| } | ||||
| 
 | ||||
| /*
 | ||||
|  * Subtract the area of an XWayland view (e.g. panel) from the usable | ||||
|  * area of the output based on _NET_WM_STRUT_PARTIAL property. | ||||
|  */ | ||||
| void | ||||
| xwayland_adjust_usable_area(struct view *view, struct wlr_output_layout *layout, | ||||
| 		struct wlr_output *output, struct wlr_box *usable) | ||||
| { | ||||
| 	assert(view); | ||||
| 	assert(layout); | ||||
| 	assert(output); | ||||
| 	assert(usable); | ||||
| 
 | ||||
| 	if (view->type != LAB_XWAYLAND_VIEW) { | ||||
| 		return; | ||||
| 	} | ||||
| 
 | ||||
| 	xcb_ewmh_wm_strut_partial_t *strut = | ||||
| 		xwayland_surface_from_view(view)->strut_partial; | ||||
| 	if (!strut) { | ||||
| 		return; | ||||
| 	} | ||||
| 
 | ||||
| 	/* these are layout coordinates */ | ||||
| 	struct wlr_box lb = { 0 }; | ||||
| 	wlr_output_layout_get_box(layout, NULL, &lb); | ||||
| 	struct wlr_box ob = { 0 }; | ||||
| 	wlr_output_layout_get_box(layout, output, &ob); | ||||
| 
 | ||||
| 	/*
 | ||||
| 	 * strut->right/bottom are offsets from the lower right corner | ||||
| 	 * of the X11 screen, which should generally correspond with the | ||||
| 	 * lower right corner of the output layout | ||||
| 	 */ | ||||
| 	double strut_left = strut->left; | ||||
| 	double strut_right = (lb.x + lb.width) - strut->right; | ||||
| 	double strut_top = strut->top; | ||||
| 	double strut_bottom = (lb.y + lb.height) - strut->bottom; | ||||
| 
 | ||||
| 	/* convert layout to output coordinates */ | ||||
| 	wlr_output_layout_output_coords(layout, output, | ||||
| 		&strut_left, &strut_top); | ||||
| 	wlr_output_layout_output_coords(layout, output, | ||||
| 		&strut_right, &strut_bottom); | ||||
| 
 | ||||
| 	/* deal with right/bottom rather than width/height */ | ||||
| 	int usable_right = usable->x + usable->width; | ||||
| 	int usable_bottom = usable->y + usable->height; | ||||
| 
 | ||||
| 	/* here we mix output and layout coordinates; be careful */ | ||||
| 	if (strut_left > usable->x && strut_left < usable_right | ||||
| 			&& intervals_overlap(ob.y, ob.y + ob.height, | ||||
| 			strut->left_start_y, strut->left_end_y + 1)) { | ||||
| 		usable->x = strut_left; | ||||
| 	} | ||||
| 	if (strut_right > usable->x && strut_right < usable_right | ||||
| 			&& intervals_overlap(ob.y, ob.y + ob.height, | ||||
| 			strut->right_start_y, strut->right_end_y + 1)) { | ||||
| 		usable_right = strut_right; | ||||
| 	} | ||||
| 	if (strut_top > usable->y && strut_top < usable_bottom | ||||
| 			&& intervals_overlap(ob.x, ob.x + ob.width, | ||||
| 			strut->top_start_x, strut->top_end_x + 1)) { | ||||
| 		usable->y = strut_top; | ||||
| 	} | ||||
| 	if (strut_bottom > usable->y && strut_bottom < usable_bottom | ||||
| 			&& intervals_overlap(ob.x, ob.x + ob.width, | ||||
| 			strut->bottom_start_x, strut->bottom_end_x + 1)) { | ||||
| 		usable_bottom = strut_bottom; | ||||
| 	} | ||||
| 
 | ||||
| 	usable->width = usable_right - usable->x; | ||||
| 	usable->height = usable_bottom - usable->y; | ||||
| } | ||||
| 
 | ||||
| void | ||||
| xwayland_update_workarea(struct server *server) | ||||
| { | ||||
|  |  | |||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue
	
	 John Lindgren
						John Lindgren