diff --git a/Makefile b/Makefile index 10a5229..2e85080 100644 --- a/Makefile +++ b/Makefile @@ -5,5 +5,6 @@ proto: compile: proto gcc -o absinthe src/* \ + -DXWAYLAND \ -I./ -I./include -DWLR_USE_UNSTABLE $(shell pkg-config wlroots-0.20 --libs --cflags) -lwayland-server -lxkbcommon \ -ggdb diff --git a/include/absinthe-toplevel.h b/include/absinthe-toplevel.h index 44283c2..033275d 100644 --- a/include/absinthe-toplevel.h +++ b/include/absinthe-toplevel.h @@ -1,6 +1,7 @@ #include "types.h" bool absinthe_toplevel_is_x11(struct absinthe_toplevel *toplevel); +bool absinthe_toplevel_is_unmanaged(struct absinthe_toplevel *toplevel); struct absinthe_toplevel *absinthe_toplevel_at(struct absinthe_server *server, double lx, double ly, struct wlr_surface **surface, double *sx, double *sy); diff --git a/include/server.h b/include/server.h index df97446..63855f3 100644 --- a/include/server.h +++ b/include/server.h @@ -8,6 +8,11 @@ void server_new_xdg_toplevel(struct wl_listener *listener, void *data); void server_new_xdg_popup(struct wl_listener *listener, void *data); void server_new_xdg_decoration(struct wl_listener *listener, void *data); +#ifdef XWAYLAND +void server_xwayland_ready(struct wl_listener *listener, void *data); +void server_xwayland_new_surface(struct wl_listener *listener, void *data); +#endif + void server_cursor_motion(struct wl_listener *listener, void *data); void server_cursor_motion_absolute(struct wl_listener *listener, void *data); void server_cursor_button(struct wl_listener *listener, void *data); diff --git a/include/types.h b/include/types.h index 6271f98..894424f 100644 --- a/include/types.h +++ b/include/types.h @@ -72,6 +72,12 @@ struct absinthe_server { struct wlr_xdg_decoration_manager_v1 *xdg_decoration_mgr; struct wl_listener new_xdg_decoration; +#ifdef XWAYLAND + struct wlr_xwayland *xwayland; + struct wl_listener xwayland_new_surface; + struct wl_listener xwayland_ready; +#endif + struct wlr_cursor *cursor; struct wlr_xcursor_manager *cursor_mgr; struct wl_listener cursor_motion; @@ -152,11 +158,11 @@ struct absinthe_toplevel { struct wl_listener decoration_destroy; #ifdef XWAYLAND - struct wl_listener activate; - struct wl_listener associate; - struct wl_listener dissociate; - struct wl_listener configure; - struct wl_listener set_hints; + struct wl_listener xwayland_activate; + struct wl_listener xwayland_associate; + struct wl_listener xwayland_dissociate; + struct wl_listener xwayland_configure; + struct wl_listener xwayland_set_hints; #endif }; diff --git a/include/xwayland.h b/include/xwayland.h new file mode 100644 index 0000000..7b0b92c --- /dev/null +++ b/include/xwayland.h @@ -0,0 +1,9 @@ +#pragma once + +#include + +void xwayland_activate(struct wl_listener *listener, void *data); +void xwayland_associate(struct wl_listener *listener, void *data); +void xwayland_dissociate(struct wl_listener *listener, void *data); +void xwayland_configure(struct wl_listener *listener, void *data); +void xwayland_set_hints(struct wl_listener *listener, void *data); diff --git a/src/absinthe-toplevel.c b/src/absinthe-toplevel.c index d24cdaf..c932c4d 100644 --- a/src/absinthe-toplevel.c +++ b/src/absinthe-toplevel.c @@ -6,7 +6,16 @@ bool absinthe_toplevel_is_x11(struct absinthe_toplevel *toplevel) { #ifdef XWAYLAND - return toplevel->type == ABSINTHE_TOPLEVEL_TYPE_X11; + return toplevel->type == ABSINTHE_TOPLEVEL_X11; +#endif + return false; +} + +bool absinthe_toplevel_is_unmanaged(struct absinthe_toplevel *toplevel) +{ +#ifdef XWAYLAND + if (absinthe_toplevel_is_x11(toplevel)) + return toplevel->toplevel.x11->override_redirect; #endif return false; } diff --git a/src/main.c b/src/main.c index 55114d9..eaf0aa6 100644 --- a/src/main.c +++ b/src/main.c @@ -131,6 +131,8 @@ int main(int argc, char **argv) server.request_set_selection.notify = seat_request_set_selection; wl_signal_add(&server.seat->events.request_set_selection, &server.request_set_selection); + unsetenv("DISPLAY"); + const char *socket = wl_display_add_socket_auto(server.display); if (!socket) { wlr_log(WLR_ERROR, "Failed to add socket"); @@ -145,6 +147,19 @@ int main(int argc, char **argv) return 1; } +#ifdef XWAYLAND + if ((server.xwayland = wlr_xwayland_create(server.display, server.compositor, 1))) { + server.xwayland_ready.notify = server_xwayland_ready; + wl_signal_add(&server.xwayland->events.ready, &server.xwayland_ready); + server.xwayland_new_surface.notify = server_xwayland_new_surface; + wl_signal_add(&server.xwayland->events.new_surface, &server.xwayland_new_surface); + + setenv("DISPLAY", server.xwayland->display_name, 1); + } else { + wlr_log(WLR_ERROR, "Failed to setup XWayland, continuing without it"); + } +#endif + setenv("WAYLAND_DISPLAY", socket, true); wlr_log(WLR_INFO, "Running absinthe on WAYLAND_DISPLAY=%s", socket); diff --git a/src/server.c b/src/server.c index 15a324b..b576c7e 100644 --- a/src/server.c +++ b/src/server.c @@ -2,6 +2,7 @@ #include #include +#include #include "types.h" #include "output.h" @@ -13,6 +14,11 @@ #include "keyboard.h" #include "cursor.h" +#ifdef XWAYLAND +#include +#include "xwayland.h" +#endif + void server_new_output(struct wl_listener *listener, void *data) { struct absinthe_server *server = wl_container_of(listener, server, new_output); @@ -118,8 +124,57 @@ void server_new_xdg_decoration(struct wl_listener *listener, void *data) wl_signal_add(&xdg_decoration->events.destroy, &toplevel->decoration_destroy); xdg_decoration_request_mode(&toplevel->decoration_request_mode, xdg_decoration); + + toplevel->destroy.notify = xdg_toplevel_destroy; + wl_signal_add(&toplevel->toplevel.xdg->events.destroy, &toplevel->destroy); } +#ifdef XWAYLAND +void server_xwayland_ready(struct wl_listener *listener, void *data) +{ + struct absinthe_server *server = wl_container_of(listener, server, xwayland_ready); + struct wlr_xcursor *xcursor; + + wlr_xwayland_set_seat(server->xwayland, server->seat); + + if ((xcursor = wlr_xcursor_manager_get_xcursor(server->cursor_mgr, "default", 1))) + wlr_xwayland_set_cursor(server->xwayland, + xcursor->images[0]->buffer, xcursor->images[0]->width * 4, + xcursor->images[0]->width, xcursor->images[0]->height, + xcursor->images[0]->hotspot_x, xcursor->images[0]->hotspot_y); +} + +void server_xwayland_new_surface(struct wl_listener *listener, void *data) +{ + struct wlr_xwayland_surface *surface = data; + struct absinthe_toplevel *toplevel = malloc(sizeof(*toplevel)); + + toplevel->type = ABSINTHE_TOPLEVEL_X11; + toplevel->toplevel.x11 = surface; + toplevel->border_width = absinthe_toplevel_is_unmanaged(toplevel) + ? 0 + : ABSINTHE_TOPLEVEL_BORDER_WIDTH; + + toplevel->destroy.notify = xdg_toplevel_destroy; + wl_signal_add(&surface->events.destroy, &toplevel->destroy); + toplevel->request_maximize.notify = xdg_toplevel_request_maximize; + wl_signal_add(&surface->events.request_maximize, &toplevel->request_maximize); + toplevel->request_fullscreen.notify = xdg_toplevel_request_fullscreen; + wl_signal_add(&surface->events.request_fullscreen, &toplevel->request_fullscreen); + + toplevel->xwayland_activate.notify = xwayland_activate; + wl_signal_add(&surface->events.request_activate, &toplevel->xwayland_activate); + toplevel->xwayland_associate.notify = xwayland_associate; + wl_signal_add(&surface->events.associate, &toplevel->xwayland_associate); + toplevel->xwayland_dissociate.notify = xwayland_dissociate; + wl_signal_add(&surface->events.dissociate, &toplevel->xwayland_dissociate); + toplevel->xwayland_configure.notify = xwayland_configure; + wl_signal_add(&surface->events.request_configure, &toplevel->xwayland_configure); + toplevel->xwayland_set_hints.notify = xwayland_set_hints; + wl_signal_add(&surface->events.set_hints, &toplevel->xwayland_set_hints); +} +#endif + void server_cursor_motion(struct wl_listener *listener, void *data) { struct absinthe_server *server = wl_container_of(listener, server, cursor_motion); diff --git a/src/xdg-toplevel.c b/src/xdg-toplevel.c index d8ea7c5..5692b00 100644 --- a/src/xdg-toplevel.c +++ b/src/xdg-toplevel.c @@ -70,15 +70,24 @@ void xdg_toplevel_destroy(struct wl_listener *listener, void *data) { struct absinthe_toplevel *toplevel = wl_container_of(listener, toplevel, destroy); - wl_list_remove(&toplevel->map.link); - wl_list_remove(&toplevel->unmap.link); - wl_list_remove(&toplevel->commit.link); wl_list_remove(&toplevel->destroy.link); - wl_list_remove(&toplevel->request_move.link); - wl_list_remove(&toplevel->request_resize.link); wl_list_remove(&toplevel->request_maximize.link); wl_list_remove(&toplevel->request_fullscreen.link); + if (absinthe_toplevel_is_x11(toplevel)) { + wl_list_remove(&toplevel->xwayland_activate.link); + wl_list_remove(&toplevel->xwayland_associate.link); + wl_list_remove(&toplevel->xwayland_dissociate.link); + wl_list_remove(&toplevel->xwayland_configure.link); + wl_list_remove(&toplevel->xwayland_set_hints.link); + } else { + wl_list_remove(&toplevel->map.link); + wl_list_remove(&toplevel->unmap.link); + wl_list_remove(&toplevel->commit.link); + wl_list_remove(&toplevel->request_move.link); + wl_list_remove(&toplevel->request_resize.link); + } + free(toplevel); } diff --git a/src/xwayland.c b/src/xwayland.c new file mode 100644 index 0000000..b89a195 --- /dev/null +++ b/src/xwayland.c @@ -0,0 +1,12 @@ +#ifdef XWAYLAND +#include "types.h" +#include "absinthe-toplevel.h" +#include "xwayland.h" + +void xwayland_activate(struct wl_listener *listener, void *data) {} +void xwayland_associate(struct wl_listener *listener, void *data) {} +void xwayland_dissociate(struct wl_listener *listener, void *data) {} +void xwayland_configure(struct wl_listener *listener, void *data) {} +void xwayland_set_hints(struct wl_listener *listener, void *data) {} + +#endif