diff options
Diffstat (limited to 'xwayland')
| -rw-r--r-- | xwayland/meson.build | 2 | ||||
| -rw-r--r-- | xwayland/xwayland.c | 40 | ||||
| -rw-r--r-- | xwayland/xwm.c | 88 | ||||
| -rw-r--r-- | xwayland/xwm.h | 9 | 
4 files changed, 130 insertions, 9 deletions
| diff --git a/xwayland/meson.build b/xwayland/meson.build index a05ae584..e92e042c 100644 --- a/xwayland/meson.build +++ b/xwayland/meson.build @@ -11,6 +11,8 @@ lib_wlr_xwayland = static_library(  		xcb,  		xcb_composite,  		xcb_xfixes, +		xcb_image, +		xcb_render,  		xcb_icccm,  		pixman,  	], diff --git a/xwayland/xwayland.c b/xwayland/xwayland.c index 81bac2ce..0452f04c 100644 --- a/xwayland/xwayland.c +++ b/xwayland/xwayland.c @@ -29,6 +29,15 @@ static inline int clearenv(void) {  }  #endif +struct wlr_xwayland_cursor { +	uint8_t *pixels; +	uint32_t stride; +	uint32_t width; +	uint32_t height; +	int32_t hotspot_x; +	int32_t hotspot_y; +}; +  static void safe_close(int fd) {  	if (fd >= 0) {  		close(fd); @@ -190,6 +199,14 @@ static int xserver_handle_ready(int signal_number, void *data) {  	wl_event_source_remove(wlr_xwayland->sigusr1_source);  	wlr_xwayland->sigusr1_source = NULL; +	if (wlr_xwayland->cursor != NULL) { +		struct wlr_xwayland_cursor *cur = wlr_xwayland->cursor; +		xwm_set_cursor(wlr_xwayland->xwm, cur->pixels, cur->stride, cur->width, +			cur->height, cur->hotspot_x, cur->hotspot_y); +		free(cur); +		wlr_xwayland->cursor = NULL; +	} +  	char display_name[16];  	snprintf(display_name, sizeof(display_name), ":%d", wlr_xwayland->display);  	setenv("DISPLAY", display_name, true); @@ -298,3 +315,26 @@ struct wlr_xwayland *wlr_xwayland_create(struct wl_display *wl_display,  	free(wlr_xwayland);  	return NULL;  } + +void wlr_xwayland_set_cursor(struct wlr_xwayland *wlr_xwayland, +		uint8_t *pixels, uint32_t stride, uint32_t width, uint32_t height, +		int32_t hotspot_x, int32_t hotspot_y) { +	if (wlr_xwayland->xwm != NULL) { +		xwm_set_cursor(wlr_xwayland->xwm, pixels, stride, width, height, +			hotspot_x, hotspot_y); +		return; +	} + +	free(wlr_xwayland->cursor); + +	wlr_xwayland->cursor = calloc(1, sizeof(struct wlr_xwayland_cursor)); +	if (wlr_xwayland->cursor == NULL) { +		return; +	} +	wlr_xwayland->cursor->pixels = pixels; +	wlr_xwayland->cursor->stride = stride; +	wlr_xwayland->cursor->width = width; +	wlr_xwayland->cursor->height = height; +	wlr_xwayland->cursor->hotspot_x = hotspot_x; +	wlr_xwayland->cursor->hotspot_y = hotspot_y; +} diff --git a/xwayland/xwm.c b/xwayland/xwm.c index 15a23797..f011587e 100644 --- a/xwayland/xwm.c +++ b/xwayland/xwm.c @@ -5,9 +5,12 @@  #include <unistd.h>  #include <xcb/composite.h>  #include <xcb/xfixes.h> +#include <xcb/xcb_image.h> +#include <xcb/render.h>  #include "wlr/util/log.h"  #include "wlr/types/wlr_surface.h"  #include "wlr/xwayland.h" +#include "wlr/xcursor.h"  #include "xwm.h"  #ifdef HAS_XCB_ICCCM @@ -1027,12 +1030,17 @@ void wlr_xwayland_surface_close(struct wlr_xwayland *wlr_xwayland,  	} else {  		xcb_kill_client(xwm->xcb_conn, xsurface->window_id);  	} + +	xcb_flush(xwm->xcb_conn);  }  void xwm_destroy(struct wlr_xwm *xwm) {  	if (!xwm) {  		return;  	} +	if (xwm->cursor) { +		xcb_free_cursor(xwm->xcb_conn, xwm->cursor); +	}  	if (xwm->event_source) {  		wl_event_source_remove(xwm->event_source);  	} @@ -1095,7 +1103,6 @@ static void xwm_get_resources(struct wlr_xwm *xwm) {  		xfixes_reply->major_version, xfixes_reply->minor_version);  	free(xfixes_reply); -  }  static void xwm_create_wm_window(struct wlr_xwm *xwm) { @@ -1168,7 +1175,7 @@ static void xwm_get_visual_and_colormap(struct wlr_xwm *xwm) {  	}  	if (visualtype == NULL) { -		wlr_log(L_DEBUG, "no 32 bit visualtype\n"); +		wlr_log(L_DEBUG, "No 32 bit visualtype\n");  		return;  	} @@ -1181,6 +1188,71 @@ static void xwm_get_visual_and_colormap(struct wlr_xwm *xwm) {  		xwm->visual_id);  } +static void xwm_get_render_format(struct wlr_xwm *xwm) { +	xcb_render_query_pict_formats_cookie_t cookie = +		xcb_render_query_pict_formats(xwm->xcb_conn); +	xcb_render_query_pict_formats_reply_t *reply = +		xcb_render_query_pict_formats_reply(xwm->xcb_conn, cookie, NULL); +	xcb_render_pictforminfo_iterator_t iter = +		xcb_render_query_pict_formats_formats_iterator(reply); +	xcb_render_pictforminfo_t *format = NULL; +	while (iter.rem > 0) { +		if (iter.data->depth == 32) { +			format = iter.data; +			break; +		} + +		xcb_render_pictforminfo_next(&iter); +	} + +	if (format == NULL) { +		wlr_log(L_DEBUG, "No 32 bit render format"); +		return; +	} + +	xwm->render_format_id = format->id; +} + +void xwm_set_cursor(struct wlr_xwm *xwm, const uint8_t *pixels, uint32_t stride, +		uint32_t width, uint32_t height, int32_t hotspot_x, int32_t hotspot_y) { +	if (!xwm->render_format_id) { +		wlr_log(L_ERROR, "Cannot set xwm cursor: no render format available"); +		return; +	} +	if (xwm->cursor) { +		xcb_free_cursor(xwm->xcb_conn, xwm->cursor); +	} + +	stride *= 4; +	int depth = 32; + +	xcb_pixmap_t pix = xcb_generate_id(xwm->xcb_conn); +	xcb_create_pixmap(xwm->xcb_conn, depth, pix, xwm->screen->root, width, +		height); + +	xcb_render_picture_t pic = xcb_generate_id(xwm->xcb_conn); +	xcb_render_create_picture(xwm->xcb_conn, pic, pix, xwm->render_format_id, +		0, 0); + +	xcb_gcontext_t gc = xcb_generate_id(xwm->xcb_conn); +	xcb_create_gc(xwm->xcb_conn, gc, pix, 0, NULL); + +	xcb_put_image(xwm->xcb_conn, XCB_IMAGE_FORMAT_Z_PIXMAP, pix, gc, +		width, height, 0, 0, 0, depth, stride * height * sizeof(uint8_t), +		pixels); +	xcb_free_gc(xwm->xcb_conn, gc); + +	xwm->cursor = xcb_generate_id(xwm->xcb_conn); +	xcb_render_create_cursor(xwm->xcb_conn, xwm->cursor, pic, hotspot_x, +		hotspot_y); +	xcb_free_pixmap(xwm->xcb_conn, pix); + +	uint32_t values[] = {xwm->cursor}; +	xcb_change_window_attributes(xwm->xcb_conn, xwm->screen->root, +		XCB_CW_CURSOR, values); +	xcb_flush(xwm->xcb_conn); +} +  struct wlr_xwm *xwm_create(struct wlr_xwayland *wlr_xwayland) {  	struct wlr_xwm *xwm = calloc(1, sizeof(struct wlr_xwm));  	if (xwm == NULL) { @@ -1217,16 +1289,16 @@ struct wlr_xwm *xwm_create(struct wlr_xwayland *wlr_xwayland) {  	xwm_get_resources(xwm);  	xwm_get_visual_and_colormap(xwm); +	xwm_get_render_format(xwm); -	uint32_t values[1]; -	values[0] = +	uint32_t values[] = {  		XCB_EVENT_MASK_SUBSTRUCTURE_NOTIFY | -		XCB_EVENT_MASK_SUBSTRUCTURE_REDIRECT | -		XCB_EVENT_MASK_PROPERTY_CHANGE; - +			XCB_EVENT_MASK_SUBSTRUCTURE_REDIRECT | +			XCB_EVENT_MASK_PROPERTY_CHANGE, +	};  	xcb_change_window_attributes(xwm->xcb_conn,  		xwm->screen->root, -		XCB_CW_EVENT_MASK /* | XCB_CW_CURSOR */, +		XCB_CW_EVENT_MASK,  		values);  	xcb_composite_redirect_subwindows(xwm->xcb_conn, diff --git a/xwayland/xwm.h b/xwayland/xwm.h index 7d30d278..547cd5eb 100644 --- a/xwayland/xwm.h +++ b/xwayland/xwm.h @@ -1,5 +1,7 @@  #ifndef XWAYLAND_INTERNALS_H  #define XWAYLAND_INTERNALS_H + +#include <xcb/render.h>  #include <wayland-server-core.h>  #include <wlr/xwayland.h> @@ -49,6 +51,8 @@ struct wlr_xwm {  	xcb_window_t window;  	xcb_visualid_t visual_id;  	xcb_colormap_t colormap; +	xcb_render_pictformat_t render_format_id; +	xcb_cursor_t cursor;  	struct wlr_xwayland_surface *focus_surface; @@ -60,8 +64,11 @@ struct wlr_xwm {  	struct wl_listener compositor_surface_create;  }; +struct wlr_xwm *xwm_create(struct wlr_xwayland *wlr_xwayland); +  void xwm_destroy(struct wlr_xwm *xwm); -struct wlr_xwm *xwm_create(struct wlr_xwayland *wlr_xwayland); +void xwm_set_cursor(struct wlr_xwm *xwm, const uint8_t *pixels, uint32_t stride, +	uint32_t width, uint32_t height, int32_t hotspot_x, int32_t hotspot_y);  #endif | 
