mirror of
				https://github.com/cage-kiosk/cage.git
				synced 2025-10-29 05:40:19 -04:00 
			
		
		
		
	Add XWayland support
With Cage becoming more popular since its mention on Phoronix and
therefore getting more use-cases than just my own project, add XWayland
support. The refactoring of 2cf40f7 makes this much easier. Note that
this is a no-cost addition for those of us not using XWayland as it is a
compile-time option that needs to be explicitly enabled by adding
`-Dxwayland=true` to your meson command.
			
			
This commit is contained in:
		
							parent
							
								
									48f8f69556
								
							
						
					
					
						commit
						a34c726a1c
					
				
					 10 changed files with 213 additions and 3 deletions
				
			
		
							
								
								
									
										49
									
								
								cage.c
									
										
									
									
									
								
							
							
						
						
									
										49
									
								
								cage.c
									
										
									
									
									
								
							|  | @ -8,6 +8,8 @@ | |||
| 
 | ||||
| #define _POSIX_C_SOURCE 200112L | ||||
| 
 | ||||
| #include "config.h" | ||||
| 
 | ||||
| #include <signal.h> | ||||
| #include <stdio.h> | ||||
| #include <stdlib.h> | ||||
|  | @ -17,15 +19,24 @@ | |||
| #include <wlr/backend.h> | ||||
| #include <wlr/render/wlr_renderer.h> | ||||
| #include <wlr/types/wlr_compositor.h> | ||||
| #if CAGE_HAS_XWAYLAND | ||||
| #include <wlr/types/wlr_xcursor_manager.h> | ||||
| #endif | ||||
| #include <wlr/types/wlr_data_device.h> | ||||
| #include <wlr/types/wlr_output_layout.h> | ||||
| #include <wlr/types/wlr_xdg_shell.h> | ||||
| #include <wlr/util/log.h> | ||||
| #if CAGE_HAS_XWAYLAND | ||||
| #include <wlr/xwayland.h> | ||||
| #endif | ||||
| 
 | ||||
| #include "output.h" | ||||
| #include "seat.h" | ||||
| #include "server.h" | ||||
| #include "xdg_shell.h" | ||||
| #if CAGE_HAS_XWAYLAND | ||||
| #include "xwayland.h" | ||||
| #endif | ||||
| 
 | ||||
| static bool | ||||
| spawn_primary_client(char *argv[], pid_t *pid_out) | ||||
|  | @ -69,6 +80,9 @@ main(int argc, char *argv[]) | |||
| 	struct wlr_compositor *compositor = NULL; | ||||
| 	struct wlr_data_device_manager *data_device_mgr = NULL; | ||||
| 	struct wlr_xdg_shell *xdg_shell = NULL; | ||||
| #if CAGE_HAS_XWAYLAND | ||||
| 	struct wlr_xwayland *xwayland = NULL; | ||||
| #endif | ||||
| 	int ret = 0; | ||||
| 
 | ||||
| 	if (argc < 2) { | ||||
|  | @ -146,6 +160,31 @@ main(int argc, char *argv[]) | |||
| 	server.new_xdg_shell_surface.notify = handle_xdg_shell_surface_new; | ||||
| 	wl_signal_add(&xdg_shell->events.new_surface, &server.new_xdg_shell_surface); | ||||
| 
 | ||||
| #if CAGE_HAS_XWAYLAND | ||||
| 	xwayland = wlr_xwayland_create(server.wl_display, compositor, true); | ||||
| 	server.new_xwayland_surface.notify = handle_xwayland_surface_new; | ||||
| 	wl_signal_add(&xwayland->events.new_surface, &server.new_xwayland_surface); | ||||
| 
 | ||||
| 	struct wlr_xcursor_manager *xcursor_manager = | ||||
| 		wlr_xcursor_manager_create(DEFAULT_XCURSOR, XCURSOR_SIZE); | ||||
| 	if (!xcursor_manager) { | ||||
| 		wlr_log(WLR_ERROR, "Cannot create XWayland XCursor manager"); | ||||
| 	        ret = 1; | ||||
| 		goto end; | ||||
| 	} | ||||
| 	if (wlr_xcursor_manager_load(xcursor_manager, 1)) { | ||||
| 		wlr_log(WLR_ERROR, "Cannot load XWayland XCursor theme"); | ||||
| 	} | ||||
| 	struct wlr_xcursor *xcursor = | ||||
| 		wlr_xcursor_manager_get_xcursor(xcursor_manager, DEFAULT_XCURSOR, 1); | ||||
| 	if (xcursor) { | ||||
| 		struct wlr_xcursor_image *image = xcursor->images[0]; | ||||
| 		wlr_xwayland_set_cursor(xwayland, image->buffer, | ||||
| 					image->width * 4, image->width, image->height, | ||||
| 					image->hotspot_x, image->hotspot_y); | ||||
| 	} | ||||
| #endif | ||||
| 
 | ||||
| 	const char *socket = wl_display_add_socket_auto(server.wl_display); | ||||
| 	if (!socket) { | ||||
| 		wlr_log_errno(WLR_ERROR, "Unable to open Wayland socket"); | ||||
|  | @ -165,6 +204,12 @@ main(int argc, char *argv[]) | |||
| 			      "Clients may not be able to connect"); | ||||
| 	} | ||||
| 
 | ||||
| #if CAGE_HAS_XWAYLAND | ||||
| 	if (xwayland) { | ||||
| 		wlr_xwayland_set_seat(xwayland, server.seat->seat); | ||||
| 	} | ||||
| #endif | ||||
| 
 | ||||
| 	pid_t pid; | ||||
| 	if (!spawn_primary_client(argv + 1, &pid)) { | ||||
| 		ret = 1; | ||||
|  | @ -178,6 +223,10 @@ main(int argc, char *argv[]) | |||
| 
 | ||||
| end: | ||||
| 	cg_seat_destroy(server.seat); | ||||
| #if CAGE_HAS_XWAYLAND | ||||
| 	wlr_xwayland_destroy(xwayland); | ||||
| 	wlr_xcursor_manager_destroy(xcursor_manager); | ||||
| #endif | ||||
| 	wlr_xdg_shell_destroy(xdg_shell); | ||||
| 	wlr_data_device_manager_destroy(data_device_mgr); | ||||
| 	wlr_compositor_destroy(compositor); | ||||
|  |  | |||
							
								
								
									
										20
									
								
								meson.build
									
										
									
									
									
								
							
							
						
						
									
										20
									
								
								meson.build
									
										
									
									
									
								
							|  | @ -51,6 +51,9 @@ server_protos = declare_dependency( | |||
|   sources: server_protos_headers, | ||||
| ) | ||||
| 
 | ||||
| conf_data = configuration_data() | ||||
| conf_data.set10('CAGE_HAS_XWAYLAND', get_option('xwayland')) | ||||
| 
 | ||||
| cage_sources = [ | ||||
|   'cage.c', | ||||
|   'output.c', | ||||
|  | @ -60,6 +63,9 @@ cage_sources = [ | |||
| ] | ||||
| 
 | ||||
| cage_headers = [ | ||||
|   configure_file(input: 'config.h.in', | ||||
| 		 output: 'config.h', | ||||
| 		 configuration: conf_data), | ||||
|   'output.h', | ||||
|   'seat.h', | ||||
|   'server.h', | ||||
|  | @ -67,6 +73,11 @@ cage_headers = [ | |||
|   'xdg_shell.h', | ||||
| ] | ||||
| 
 | ||||
| if conf_data.get('CAGE_HAS_XWAYLAND', 0) == 1 | ||||
|   cage_sources += 'xwayland.c' | ||||
|   cage_headers += 'xwayland.h' | ||||
| endif | ||||
| 
 | ||||
| executable( | ||||
|   meson.project_name(), | ||||
|   cage_sources + cage_headers, | ||||
|  | @ -78,3 +89,12 @@ executable( | |||
|   ], | ||||
|   install: true, | ||||
| ) | ||||
| 
 | ||||
| summary = [ | ||||
| 	'', | ||||
| 	'Cage @0@'.format(meson.project_version()), | ||||
| 	'', | ||||
| 	'    xwayland: @0@'.format(conf_data.get('CAGE_HAS_XWAYLAND', false)), | ||||
| 	'' | ||||
| ] | ||||
| message('\n'.join(summary)) | ||||
|  |  | |||
							
								
								
									
										1
									
								
								meson_options.txt
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										1
									
								
								meson_options.txt
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1 @@ | |||
| option('xwayland', type: 'boolean', value: 'false', description: 'Enable support for X11 applications') | ||||
							
								
								
									
										10
									
								
								output.c
									
										
									
									
									
								
							
							
						
						
									
										10
									
								
								output.c
									
										
									
									
									
								
							|  | @ -8,6 +8,8 @@ | |||
| 
 | ||||
| #define _POSIX_C_SOURCE 200112L | ||||
| 
 | ||||
| #include "config.h" | ||||
| 
 | ||||
| #include <stdlib.h> | ||||
| #include <unistd.h> | ||||
| #include <wayland-server.h> | ||||
|  | @ -19,6 +21,9 @@ | |||
| #include <wlr/types/wlr_surface.h> | ||||
| #include <wlr/types/wlr_xdg_shell.h> | ||||
| #include <wlr/util/log.h> | ||||
| #if CAGE_HAS_XWAYLAND | ||||
| #include <wlr/xwayland.h> | ||||
| #endif | ||||
| 
 | ||||
| #include "output.h" | ||||
| #include "server.h" | ||||
|  | @ -76,6 +81,11 @@ view_for_each_surface(struct cg_view *view, struct render_data *rdata, | |||
| 	case CAGE_XDG_SHELL_VIEW: | ||||
| 		wlr_xdg_surface_for_each_surface(view->xdg_surface, iterator, rdata); | ||||
| 		break; | ||||
| #ifdef CAGE_HAS_XWAYLAND | ||||
| 	case CAGE_XWAYLAND_VIEW: | ||||
| 		wlr_surface_for_each_surface(view->wlr_surface, iterator, rdata); | ||||
| 		break; | ||||
| #endif | ||||
| 	default: | ||||
| 		wlr_log(WLR_ERROR, "Unrecognized view type: %d", view->type); | ||||
| 	} | ||||
|  |  | |||
							
								
								
									
										22
									
								
								seat.c
									
										
									
									
									
								
							
							
						
						
									
										22
									
								
								seat.c
									
										
									
									
									
								
							|  | @ -6,6 +6,8 @@ | |||
|  * See the LICENSE file accompanying this file. | ||||
|  */ | ||||
| 
 | ||||
| #include "config.h" | ||||
| 
 | ||||
| #include <stdlib.h> | ||||
| #include <wayland-server.h> | ||||
| #include <wlr/backend.h> | ||||
|  | @ -14,15 +16,15 @@ | |||
| #include <wlr/types/wlr_surface.h> | ||||
| #include <wlr/types/wlr_xcursor_manager.h> | ||||
| #include <wlr/util/log.h> | ||||
| #if CAGE_HAS_XWAYLAND | ||||
| #include <wlr/xwayland.h> | ||||
| #endif | ||||
| 
 | ||||
| #include "output.h" | ||||
| #include "seat.h" | ||||
| #include "server.h" | ||||
| #include "view.h" | ||||
| 
 | ||||
| #define DEFAULT_XCURSOR "left_ptr" | ||||
| #define XCURSOR_SIZE 24 | ||||
| 
 | ||||
| static inline bool | ||||
| have_dialogs_open(struct cg_server *server) | ||||
| { | ||||
|  | @ -52,6 +54,13 @@ view_at(struct cg_view *view, double lx, double ly, | |||
| 						      view_sx, view_sy, | ||||
| 						      &_sx, &_sy); | ||||
| 		break; | ||||
| #ifdef CAGE_HAS_XWAYLAND | ||||
| 	case CAGE_XWAYLAND_VIEW: | ||||
| 		_surface = wlr_surface_surface_at(view->wlr_surface, | ||||
| 						  view_sx, view_sy, | ||||
| 						  &_sx, &_sy); | ||||
| 		break; | ||||
| #endif | ||||
| 	default: | ||||
| 		wlr_log(WLR_ERROR, "Unrecognized view type: %d", view->type); | ||||
| 	} | ||||
|  | @ -501,6 +510,13 @@ seat_set_focus(struct cg_seat *seat, struct cg_view *view) | |||
| 		return; | ||||
| 	} | ||||
| 
 | ||||
| #if CAGE_HAS_XWAYLAND | ||||
| 	if (view->type == CAGE_XWAYLAND_VIEW && | ||||
| 	    !wlr_xwayland_or_surface_wants_focus(view->xwayland_surface)) { | ||||
| 		return; | ||||
| 	} | ||||
| #endif | ||||
| 
 | ||||
| 	if (prev_view) { | ||||
| 		view_activate(prev_view, false); | ||||
| 	} | ||||
|  |  | |||
							
								
								
									
										3
									
								
								seat.h
									
										
									
									
									
								
							
							
						
						
									
										3
									
								
								seat.h
									
										
									
									
									
								
							|  | @ -10,6 +10,9 @@ | |||
| #include "server.h" | ||||
| #include "view.h" | ||||
| 
 | ||||
| #define DEFAULT_XCURSOR "left_ptr" | ||||
| #define XCURSOR_SIZE 24 | ||||
| 
 | ||||
| struct cg_seat { | ||||
| 	struct wlr_seat *seat; | ||||
| 	struct cg_server *server; | ||||
|  |  | |||
							
								
								
									
										9
									
								
								server.h
									
										
									
									
									
								
							
							
						
						
									
										9
									
								
								server.h
									
										
									
									
									
								
							|  | @ -1,9 +1,14 @@ | |||
| #ifndef CG_SERVER_H | ||||
| #define CG_SERVER_H | ||||
| 
 | ||||
| #include "config.h" | ||||
| 
 | ||||
| #include <wayland-server.h> | ||||
| #include <wlr/backend.h> | ||||
| #include <wlr/types/wlr_output_layout.h> | ||||
| #ifdef CAGE_HAS_XWAYLAND | ||||
| #include <wlr/xwayland.h> | ||||
| #endif | ||||
| 
 | ||||
| #include "output.h" | ||||
| #include "seat.h" | ||||
|  | @ -20,6 +25,10 @@ struct cg_server { | |||
| 	struct wlr_output_layout *output_layout; | ||||
| 	struct cg_output *output; | ||||
| 	struct wl_listener new_output; | ||||
| 
 | ||||
| #if CAGE_HAS_XWAYLAND | ||||
| 	struct wl_listener new_xwayland_surface; | ||||
| #endif | ||||
| }; | ||||
| 
 | ||||
| #endif | ||||
|  |  | |||
							
								
								
									
										8
									
								
								view.h
									
										
									
									
									
								
							
							
						
						
									
										8
									
								
								view.h
									
										
									
									
									
								
							|  | @ -1,6 +1,8 @@ | |||
| #ifndef CG_VIEW_H | ||||
| #define CG_VIEW_H | ||||
| 
 | ||||
| #include "config.h" | ||||
| 
 | ||||
| #include <stdbool.h> | ||||
| #include <wayland-server.h> | ||||
| #include <wlr/types/wlr_box.h> | ||||
|  | @ -11,6 +13,9 @@ | |||
| 
 | ||||
| enum cg_view_type { | ||||
| 	CAGE_XDG_SHELL_VIEW, | ||||
| #ifdef CAGE_HAS_XWAYLAND | ||||
| 	CAGE_XWAYLAND_VIEW, | ||||
| #endif | ||||
| }; | ||||
| 
 | ||||
| struct cg_view { | ||||
|  | @ -22,6 +27,9 @@ struct cg_view { | |||
| 	enum cg_view_type type; | ||||
| 	union { | ||||
| 		struct wlr_xdg_surface *xdg_surface; | ||||
| #ifdef CAGE_HAS_XWAYLAND | ||||
| 		struct wlr_xwayland_surface *xwayland_surface; | ||||
| #endif | ||||
| 	}; | ||||
| 
 | ||||
| 	struct wl_listener destroy; | ||||
|  |  | |||
							
								
								
									
										86
									
								
								xwayland.c
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										86
									
								
								xwayland.c
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,86 @@ | |||
| /*
 | ||||
|  * Cage: A Wayland kiosk. | ||||
|  * | ||||
|  * Copyright (C) 2018 Jente Hidskes | ||||
|  * | ||||
|  * See the LICENSE file accompanying this file. | ||||
|  */ | ||||
| 
 | ||||
| #include <stdbool.h> | ||||
| #include <wayland-server.h> | ||||
| #include <wlr/types/wlr_box.h> | ||||
| #include <wlr/xwayland.h> | ||||
| 
 | ||||
| #include "server.h" | ||||
| #include "view.h" | ||||
| 
 | ||||
| static void | ||||
| activate(struct cg_view *view, bool activate) | ||||
| { | ||||
| 	wlr_xwayland_surface_activate(view->xwayland_surface, activate); | ||||
| } | ||||
| 
 | ||||
| static void | ||||
| maximize(struct cg_view *view, int output_width, int output_height) | ||||
| { | ||||
| 	wlr_xwayland_surface_configure(view->xwayland_surface, 0, 0, output_width, output_height); | ||||
| 	wlr_xwayland_surface_set_maximized(view->xwayland_surface, true); | ||||
| } | ||||
| 
 | ||||
| static void | ||||
| get_geometry(struct cg_view *view, int *width_out, int *height_out) | ||||
| { | ||||
| 	*width_out = view->xwayland_surface->surface->current.width; | ||||
| 	*height_out = view->xwayland_surface->surface->current.height; | ||||
| } | ||||
| 
 | ||||
| static bool | ||||
| is_primary(struct cg_view *view) | ||||
| { | ||||
| 	struct wlr_xwayland_surface *parent = view->xwayland_surface->parent; | ||||
| 	return parent == NULL; | ||||
| } | ||||
| 
 | ||||
| static void | ||||
| handle_xwayland_surface_unmap(struct wl_listener *listener, void *data) | ||||
| { | ||||
| 	struct cg_view *view = wl_container_of(listener, view, unmap); | ||||
| 	view_unmap(view); | ||||
| } | ||||
| 
 | ||||
| static void | ||||
| handle_xwayland_surface_map(struct wl_listener *listener, void *data) | ||||
| { | ||||
| 	struct cg_view *view = wl_container_of(listener, view, map); | ||||
| 	view_map(view, view->xwayland_surface->surface); | ||||
| } | ||||
| 
 | ||||
| static void | ||||
| handle_xwayland_surface_destroy(struct wl_listener *listener, void *data) | ||||
| { | ||||
| 	struct cg_view *view = wl_container_of(listener, view, destroy); | ||||
| 	view_destroy(view); | ||||
| } | ||||
| 
 | ||||
| void | ||||
| handle_xwayland_surface_new(struct wl_listener *listener, void *data) | ||||
| { | ||||
| 	struct cg_server *server = wl_container_of(listener, server, new_xwayland_surface); | ||||
| 	struct wlr_xwayland_surface *xwayland_surface = data; | ||||
| 
 | ||||
| 	struct cg_view *view = cg_view_create(server); | ||||
| 	view->type = CAGE_XWAYLAND_VIEW; | ||||
| 	view->xwayland_surface = xwayland_surface; | ||||
| 
 | ||||
| 	view->map.notify = handle_xwayland_surface_map; | ||||
| 	wl_signal_add(&xwayland_surface->events.map, &view->map); | ||||
| 	view->unmap.notify = handle_xwayland_surface_unmap; | ||||
| 	wl_signal_add(&xwayland_surface->events.unmap, &view->unmap); | ||||
| 	view->destroy.notify = handle_xwayland_surface_destroy; | ||||
| 	wl_signal_add(&xwayland_surface->events.destroy, &view->destroy); | ||||
| 
 | ||||
| 	view->activate = activate; | ||||
| 	view->maximize = maximize; | ||||
| 	view->get_geometry = get_geometry; | ||||
| 	view->is_primary = is_primary; | ||||
| } | ||||
							
								
								
									
										8
									
								
								xwayland.h
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										8
									
								
								xwayland.h
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,8 @@ | |||
| #ifndef XWAYLAND_H | ||||
| #define XWAYLAND_H | ||||
| 
 | ||||
| #include <wayland-server.h> | ||||
| 
 | ||||
| void handle_xwayland_surface_new(struct wl_listener *listener, void *data); | ||||
| 
 | ||||
| #endif | ||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue
	
	 Jente Hidskes
						Jente Hidskes