Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

introduce xwayland #309

Open
wants to merge 2 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions include/zen/screen/compositor.h
Original file line number Diff line number Diff line change
Expand Up @@ -3,15 +3,19 @@
#include <wlr/render/wlr_renderer.h>
#include <wlr/types/wlr_compositor.h>
#include <wlr/types/wlr_xdg_shell.h>
#include <wlr/xwayland.h>

struct zn_screen_compositor {
struct wl_display *display;

// These objects will be automatically destroyed when wl_display is destroyed
struct wlr_compositor *compositor;
struct wlr_xdg_shell *xdg_shell;
struct wlr_xwayland *xwayland;

struct wl_listener xdg_shell_new_surface_listener;
struct wl_listener xwayland_ready_listener;
struct wl_listener xwayland_new_surface_listener;
};

struct zn_screen_compositor *zn_screen_compositor_create(
Expand Down
22 changes: 22 additions & 0 deletions include/zen/screen/xwayland.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
#pragma once

#include <wayland-server-core.h>
#include <wlr/xwayland.h>

struct zn_view;

struct zn_xwayland_view {
struct wlr_xwayland_surface *xwayland_surface; // nonnull

struct zn_view *view; // null if not mapped

struct wl_listener map_listener;
struct wl_listener unmap_listener;
struct wl_listener move_listener;
struct wl_listener resize_listener;
struct wl_listener maximize_listener;
struct wl_listener wlr_xwayland_surface_destroy_listener;
};

struct zn_xwayland_view *zn_xwayland_view_create(
struct wlr_xwayland_surface *xwayland_surface);
7 changes: 6 additions & 1 deletion include/zen/view.h
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

#include <cglm/types.h>
#include <wlr/types/wlr_surface.h>
#include <xcb/xproto.h>

#include "zen/appearance/view.h"

Expand All @@ -17,8 +18,11 @@ struct zn_view_interface {
uint32_t (*get_current_configure_serial)(struct zn_view *view);
uint32_t (*set_size)(struct zn_view *view, double width, double height);
uint32_t (*set_maximized)(struct zn_view *view, bool maximized);
void (*set_position)(struct zn_view *view, double x, double y); // nulable
void (*set_activated)(struct zn_view *view, bool activated);
uint32_t (*schedule_configure)(struct zn_view *view);
void (*restack)(
struct zn_view *view, enum xcb_stack_mode_t mode); // nullable
uint32_t (*schedule_configure)(struct zn_view *view); // nullable
void (*close_popups)(struct zn_view *view);
void (*for_each_popup_surface)(struct zn_view *view,
wlr_surface_iterator_func_t iterator, void *user_data);
Expand Down Expand Up @@ -46,6 +50,7 @@ struct zn_view {

struct {
bool maximized;
bool maximize_status_changed;
uint32_t changed_serial;
struct wlr_fbox reset_box;
} maximize_status;
Expand Down
1 change: 1 addition & 0 deletions zen/meson.build
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ _zen_srcs = [
'screen/renderer.c',
'screen/xdg-popup.c',
'screen/xdg-toplevel.c',
'screen/xwayland.c',
'screen/cursor-grab/default.c',
'screen/cursor-grab/down.c',
'screen/cursor-grab/move.c',
Expand Down
44 changes: 44 additions & 0 deletions zen/screen/compositor.c
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,22 @@

#include <zen-common.h>

#include "zen/input/input-manager.h"
#include "zen/screen/xdg-toplevel.h"
#include "zen/screen/xwayland.h"
#include "zen/server.h"

static void
zn_screen_compositor_handle_xwayland_ready(
struct wl_listener *listener, void *data)
{
UNUSED(data);
struct zn_screen_compositor *self =
zn_container_of(listener, self, xwayland_ready_listener);

struct zn_server *server = zn_server_get_singleton();
wlr_xwayland_set_seat(self->xwayland, server->input_manager->seat->wlr_seat);
}

static void
zn_screen_compositor_handle_xdg_shell_new_surface(
Expand All @@ -22,6 +37,16 @@ zn_screen_compositor_handle_xdg_shell_new_surface(
// TODO: handle other roles
}

static void
zn_screen_compositor_handle_xwayland_new_surface(
struct wl_listener *listener, void *data)
{
UNUSED(listener);
struct wlr_xwayland_surface *xwayland_surface = data;
wlr_xwayland_surface_ping(xwayland_surface);
(void)zn_xwayland_view_create(xwayland_surface);
}

struct zn_screen_compositor *
zn_screen_compositor_create(
struct wl_display *display, struct wlr_renderer *renderer)
Expand All @@ -48,11 +73,27 @@ zn_screen_compositor_create(
goto err_free;
}

self->xwayland = wlr_xwayland_create(display, self->compositor, true);
if (self->xwayland == NULL) {
zn_error("Failed to create a wlr_xwayland");
goto err_free;
}
setenv("DISPLAY", self->xwayland->display_name, true);

self->xwayland_ready_listener.notify =
zn_screen_compositor_handle_xwayland_ready;
wl_signal_add(&self->xwayland->events.ready, &self->xwayland_ready_listener);

self->xdg_shell_new_surface_listener.notify =
zn_screen_compositor_handle_xdg_shell_new_surface;
wl_signal_add(&self->xdg_shell->events.new_surface,
&self->xdg_shell_new_surface_listener);

self->xwayland_new_surface_listener.notify =
zn_screen_compositor_handle_xwayland_new_surface;
wl_signal_add(&self->xwayland->events.new_surface,
&self->xwayland_new_surface_listener);

return self;

err_free:
Expand All @@ -65,6 +106,9 @@ zn_screen_compositor_create(
void
zn_screen_compositor_destroy(struct zn_screen_compositor *self)
{
wl_list_remove(&self->xwayland_ready_listener.link);
wl_list_remove(&self->xwayland_new_surface_listener.link);
wl_list_remove(&self->xdg_shell_new_surface_listener.link);
wlr_xwayland_destroy(self->xwayland);
free(self);
}
229 changes: 229 additions & 0 deletions zen/screen/xwayland.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,229 @@
#include "zen/screen/xwayland.h"

#include <zen-common.h>

#include "zen/screen/cursor-grab/move.h"
#include "zen/screen/cursor-grab/resize.h"
#include "zen/server.h"
#include "zen/view.h"

static void zn_xwayland_view_destroy(struct zn_xwayland_view *self);

static struct wlr_surface *
zn_xwayland_view_impl_get_wlr_surface_at(struct zn_view *view, double view_sx,
double view_sy, double *surface_x, double *surface_y)
{
struct zn_xwayland_view *self = view->user_data;

return wlr_surface_surface_at(
self->xwayland_surface->surface, view_sx, view_sy, surface_x, surface_y);
}

static void
zn_xwayland_view_impl_get_window_geom(struct zn_view *view, struct wlr_box *box)
{
struct zn_xwayland_view *self = view->user_data;
box->x = 0;
box->y = 0;
box->width = self->xwayland_surface->width;
box->height = self->xwayland_surface->height;
}

static uint32_t
zn_xwayland_view_impl_get_current_configure_serial(struct zn_view *view)
{
UNUSED(view);
return 0;
}

static uint32_t
zn_xwayland_view_impl_set_size(
struct zn_view *view, double width, double height)
{
struct zn_xwayland_view *self = view->user_data;

wlr_xwayland_surface_configure(self->xwayland_surface,
self->xwayland_surface->x, self->xwayland_surface->y, width, height);

return 0;
}

static void
zn_xwayland_view_impl_set_position(struct zn_view *view, double x, double y)
{
struct zn_xwayland_view *self = view->user_data;

wlr_xwayland_surface_configure(self->xwayland_surface, x, y,
self->xwayland_surface->width, self->xwayland_surface->height);
}

static uint32_t
zn_xwayland_view_impl_set_maximized(struct zn_view *view, bool maximized)
{
struct zn_xwayland_view *self = view->user_data;

wlr_xwayland_surface_set_maximized(self->xwayland_surface, maximized);

return 0;
}

static void
zn_xwayland_view_impl_set_activated(struct zn_view *view, bool activated)
{
struct zn_xwayland_view *self = view->user_data;

wlr_xwayland_surface_activate(self->xwayland_surface, activated);
}

static void
zn_xwayland_view_impl_restack(struct zn_view *view, enum xcb_stack_mode_t mode)
{
struct zn_xwayland_view *self = view->user_data;
wlr_xwayland_surface_restack(self->xwayland_surface, NULL, mode);
}

static const struct zn_view_interface zn_xwayland_view_impl = {
.get_wlr_surface_at = zn_xwayland_view_impl_get_wlr_surface_at,
.get_window_geom = zn_xwayland_view_impl_get_window_geom,
.get_current_configure_serial =
zn_xwayland_view_impl_get_current_configure_serial,
.set_size = zn_xwayland_view_impl_set_size,
.set_maximized = zn_xwayland_view_impl_set_maximized,
.set_position = zn_xwayland_view_impl_set_position,
.set_activated = zn_xwayland_view_impl_set_activated,
.restack = zn_xwayland_view_impl_restack,
};

static void
zn_xwayland_view_handle_move(struct wl_listener *listener, void *data)
{
UNUSED(data);
struct zn_xwayland_view *self =
zn_container_of(listener, self, move_listener);
struct zn_server *server = zn_server_get_singleton();

zn_move_cursor_grab_start(server->scene->cursor, self->view);
}

static void
zn_xwayland_view_handle_resize(struct wl_listener *listener, void *data)
{
struct zn_xwayland_view *self =
zn_container_of(listener, self, resize_listener);
struct wlr_xwayland_resize_event *event = data;
struct zn_server *server = zn_server_get_singleton();

zn_resize_cursor_grab_start(server->scene->cursor, self->view, event->edges);
}

static void
zn_xwayland_view_handle_maximize(struct wl_listener *listener, void *data)
{
UNUSED(data);
struct zn_xwayland_view *self =
zn_container_of(listener, self, maximize_listener);
if (!self->view) {
return;
}
zn_view_set_maximized(self->view, !self->view->maximize_status.maximized);
}

static void
zn_xwayland_view_handle_map(struct wl_listener *listener, void *data)
{
UNUSED(data);

struct zn_server *server = zn_server_get_singleton();
struct zn_xwayland_view *self = zn_container_of(listener, self, map_listener);

if (!zn_assert(self->view == NULL, "xwayland has already mapped")) {
return;
}

self->view = zn_view_create(
self->xwayland_surface->surface, &zn_xwayland_view_impl, self);
zn_scene_new_view(server->scene, self->view);
}

static void
zn_xwayland_view_handle_unmap(struct wl_listener *listener, void *data)
{
UNUSED(data);

struct zn_xwayland_view *self =
zn_container_of(listener, self, unmap_listener);

if (!zn_assert(self->view, "xwayland has not mapped yet")) {
return;
}

zn_view_destroy(self->view);
self->view = NULL;
}

static void
zn_xwayland_view_handle_xwayland_surface_destroy(
struct wl_listener *listener, void *data)
{
UNUSED(data);

struct zn_xwayland_view *self =
zn_container_of(listener, self, wlr_xwayland_surface_destroy_listener);

zn_xwayland_view_destroy(self);
}

struct zn_xwayland_view *
zn_xwayland_view_create(struct wlr_xwayland_surface *xwayland_surface)
{
struct zn_xwayland_view *self;

self = zalloc(sizeof *self);
if (self == NULL) {
zn_error("Failed to allocate memory");
goto err;
}

self->xwayland_surface = xwayland_surface;
self->view = NULL;

self->wlr_xwayland_surface_destroy_listener.notify =
zn_xwayland_view_handle_xwayland_surface_destroy;
wl_signal_add(&xwayland_surface->events.destroy,
&self->wlr_xwayland_surface_destroy_listener);

self->map_listener.notify = zn_xwayland_view_handle_map;
wl_signal_add(&xwayland_surface->events.map, &self->map_listener);

self->unmap_listener.notify = zn_xwayland_view_handle_unmap;
wl_signal_add(&xwayland_surface->events.unmap, &self->unmap_listener);

self->move_listener.notify = zn_xwayland_view_handle_move;
wl_signal_add(&xwayland_surface->events.request_move, &self->move_listener);

self->resize_listener.notify = zn_xwayland_view_handle_resize;
wl_signal_add(
&xwayland_surface->events.request_resize, &self->resize_listener);

self->maximize_listener.notify = zn_xwayland_view_handle_maximize;
wl_signal_add(
&xwayland_surface->events.request_maximize, &self->maximize_listener);

return self;

err:
return NULL;
}

static void
zn_xwayland_view_destroy(struct zn_xwayland_view *self)
{
wl_list_remove(&self->unmap_listener.link);
wl_list_remove(&self->map_listener.link);
wl_list_remove(&self->move_listener.link);
wl_list_remove(&self->resize_listener.link);
wl_list_remove(&self->maximize_listener.link);
wl_list_remove(&self->wlr_xwayland_surface_destroy_listener.link);
if (self->view) zn_view_destroy(self->view);
free(self);
}
1 change: 1 addition & 0 deletions zen/server.c
Original file line number Diff line number Diff line change
Expand Up @@ -240,6 +240,7 @@ zn_server_create(struct wl_display *display)
setenv("WAYLAND_DISPLAY", self->socket, true);
xdg = getenv("XDG_RUNTIME_DIR");
zn_debug("WAYLAND_DISPLAY=%s", self->socket);
zn_debug("DISPLAY=%s", self->screen_compositor->xwayland->display_name);
zn_debug("XDG_RUNTIME_DIR=%s", xdg);

self->shell = zn_shell_create(self->display, self->scene);
Expand Down
Loading