diff --git a/include/labwc.h b/include/labwc.h index 84254cef..1d383d1f 100644 --- a/include/labwc.h +++ b/include/labwc.h @@ -43,9 +43,6 @@ #include #include #include -#if HAVE_XWAYLAND -#include -#endif #include #include "cursor.h" #include "config/keybind.h" @@ -217,7 +214,7 @@ struct server { #if HAVE_XWAYLAND struct wlr_xwayland *xwayland; struct wl_listener xwayland_ready; - struct wl_listener new_xwayland_surface; + struct wl_listener xwayland_new_surface; #endif struct wlr_input_inhibit_manager *input_inhibit; @@ -322,24 +319,6 @@ struct output { #undef LAB_NR_LAYERS -#if HAVE_XWAYLAND -struct xwayland_unmanaged { - struct server *server; - struct wlr_xwayland_surface *xwayland_surface; - struct wlr_scene_node *node; - struct wl_list link; - - struct wl_listener request_activate; - struct wl_listener request_configure; -/* struct wl_listener request_fullscreen; */ - struct wl_listener set_geometry; - struct wl_listener map; - struct wl_listener unmap; - struct wl_listener destroy; - struct wl_listener override_redirect; -}; -#endif - struct constraint { struct seat *seat; struct wlr_pointer_constraint_v1 *constraint; @@ -358,14 +337,6 @@ void xdg_toplevel_decoration(struct wl_listener *listener, void *data); void xdg_surface_new(struct wl_listener *listener, void *data); -#if HAVE_XWAYLAND -bool xwayland_apply_size_hints(struct view *view, int *w, int *h); -void xwayland_surface_new(struct wl_listener *listener, void *data); -struct xwayland_unmanaged *xwayland_unmanaged_create(struct server *server, - struct wlr_xwayland_surface *xsurface); -void unmanaged_handle_map(struct wl_listener *listener, void *data); -#endif - void foreign_toplevel_handle_create(struct view *view); /* diff --git a/include/view.h b/include/view.h index cf3637cf..3ee49a67 100644 --- a/include/view.h +++ b/include/view.h @@ -97,24 +97,6 @@ struct xdg_toplevel_view { struct wl_listener new_popup; }; -#if HAVE_XWAYLAND -struct xwayland_view { - struct view base; - struct wlr_xwayland_surface *xwayland_surface; - - /* Events unique to XWayland views */ - struct wl_listener request_configure; - struct wl_listener set_app_id; /* TODO: s/set_app_id/class/ */ - struct wl_listener set_decorations; - struct wl_listener override_redirect; - - /* Not (yet) implemented */ -/* struct wl_listener set_role; */ -/* struct wl_listener set_window_type; */ -/* struct wl_listener set_hints; */ -}; -#endif - void view_set_activated(struct view *view); void view_close(struct view *view); @@ -169,9 +151,4 @@ void view_destroy(struct view *view); /* xdg.c */ struct wlr_xdg_surface *xdg_surface_from_view(struct view *view); -/* xwayland.c */ -#if HAVE_XWAYLAND -struct wlr_xwayland_surface *xwayland_surface_from_view(struct view *view); -#endif - #endif /* __LABWC_VIEW_H */ diff --git a/include/xwayland.h b/include/xwayland.h new file mode 100644 index 00000000..584e6e71 --- /dev/null +++ b/include/xwayland.h @@ -0,0 +1,56 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +#ifndef __LABWC_XWAYLAND_H +#define __LABWC_XWAYLAND_H +#include "config.h" +#if HAVE_XWAYLAND +#include "view.h" + +struct wlr_compositor; + +struct xwayland_unmanaged { + struct server *server; + struct wlr_xwayland_surface *xwayland_surface; + struct wlr_scene_node *node; + struct wl_list link; + + struct wl_listener request_activate; + struct wl_listener request_configure; +/* struct wl_listener request_fullscreen; */ + struct wl_listener set_geometry; + struct wl_listener map; + struct wl_listener unmap; + struct wl_listener destroy; + struct wl_listener override_redirect; +}; + +struct xwayland_view { + struct view base; + struct wlr_xwayland_surface *xwayland_surface; + + /* Events unique to XWayland views */ + struct wl_listener request_configure; + struct wl_listener set_app_id; /* TODO: s/set_app_id/class/ */ + struct wl_listener set_decorations; + struct wl_listener override_redirect; + + /* Not (yet) implemented */ +/* struct wl_listener set_role; */ +/* struct wl_listener set_window_type; */ +/* struct wl_listener set_hints; */ +}; + +void xwayland_unmanaged_create(struct server *server, + struct wlr_xwayland_surface *xsurface, bool mapped); + +struct wlr_xwayland_surface *xwayland_surface_from_view(struct view *view); + +bool xwayland_apply_size_hints(struct view *view, int *w, int *h); +void xwayland_move_sub_views_to_front(struct view *parent, + void (*move_to_front)(struct view *view)); + +void xwayland_server_init(struct server *server, + struct wlr_compositor *compositor); +void xwayland_server_finish(struct server *server); + +#endif /* HAVE_XWAYLAND */ +#endif /* __LABWC_XWAYLAND_H */ diff --git a/src/desktop.c b/src/desktop.c index 9abea27b..28a7518f 100644 --- a/src/desktop.c +++ b/src/desktop.c @@ -10,6 +10,7 @@ #include "ssd.h" #include "view.h" #include "workspaces.h" +#include "xwayland.h" static void move_to_front(struct view *view) @@ -19,47 +20,6 @@ move_to_front(struct view *view) wlr_scene_node_raise_to_top(&view->scene_tree->node); } -#if HAVE_XWAYLAND -static struct wlr_xwayland_surface * -top_parent_of(struct view *view) -{ - struct wlr_xwayland_surface *s = xwayland_surface_from_view(view); - while (s->parent) { - s = s->parent; - } - return s; -} - -static void -move_xwayland_sub_views_to_front(struct view *parent) -{ - if (!parent || parent->type != LAB_XWAYLAND_VIEW) { - return; - } - struct wlr_xwayland_surface *parent_xwayland_surface = - xwayland_surface_from_view(parent); - struct view *view, *next; - wl_list_for_each_reverse_safe(view, next, &parent->server->views, link) - { - /* need to stop here, otherwise loops keeps going forever */ - if (view == parent) { - break; - } - if (view->type != LAB_XWAYLAND_VIEW) { - continue; - } - if (!view->mapped && !view->minimized) { - continue; - } - if (top_parent_of(view) != parent_xwayland_surface) { - continue; - } - move_to_front(view); - /* TODO: we should probably focus on these too here */ - } -} -#endif - void desktop_move_to_front(struct view *view) { @@ -68,7 +28,7 @@ desktop_move_to_front(struct view *view) } move_to_front(view); #if HAVE_XWAYLAND - move_xwayland_sub_views_to_front(view); + xwayland_move_sub_views_to_front(view, move_to_front); #endif cursor_update_focus(view->server); } diff --git a/src/server.c b/src/server.c index 8ea3c644..e36c2880 100644 --- a/src/server.c +++ b/src/server.c @@ -11,6 +11,9 @@ #include #include #include +#if HAVE_XWAYLAND +#include +#endif #include "drm-lease-v1-protocol.h" #include "config/rcxml.h" #include "config/session.h" @@ -20,6 +23,7 @@ #include "theme.h" #include "view.h" #include "workspaces.h" +#include "xwayland.h" #define LAB_XDG_SHELL_VERSION (2) @@ -148,16 +152,6 @@ handle_drm_lease_request(struct wl_listener *listener, void *data) } } -#if HAVE_XWAYLAND -static void -handle_xwayland_ready(struct wl_listener *listener, void *data) -{ - struct server *server = - wl_container_of(listener, server, xwayland_ready); - wlr_xwayland_set_seat(server->xwayland, server->seat.seat); -} -#endif - static bool server_global_filter(const struct wl_client *client, const struct wl_global *global, void *data) { @@ -396,40 +390,8 @@ server_init(struct server *server) layers_init(server); #if HAVE_XWAYLAND - /* Init xwayland */ - server->xwayland = - wlr_xwayland_create(server->wl_display, compositor, true); - if (!server->xwayland) { - wlr_log(WLR_ERROR, "cannot create xwayland server"); - exit(EXIT_FAILURE); - } - server->new_xwayland_surface.notify = xwayland_surface_new; - wl_signal_add(&server->xwayland->events.new_surface, - &server->new_xwayland_surface); - - server->xwayland_ready.notify = handle_xwayland_ready; - wl_signal_add(&server->xwayland->events.ready, - &server->xwayland_ready); - - if (setenv("DISPLAY", server->xwayland->display_name, true) < 0) { - wlr_log_errno(WLR_ERROR, "unable to set DISPLAY for xwayland"); - } else { - wlr_log(WLR_DEBUG, "xwayland is running on display %s", - server->xwayland->display_name); - } - - struct wlr_xcursor *xcursor; - xcursor = wlr_xcursor_manager_get_xcursor(server->seat.xcursor_manager, - XCURSOR_DEFAULT, 1); - if (xcursor) { - struct wlr_xcursor_image *image = xcursor->images[0]; - wlr_xwayland_set_cursor(server->xwayland, image->buffer, - image->width * 4, image->width, - image->height, image->hotspot_x, - image->hotspot_y); - } + xwayland_server_init(server, compositor); #endif - /* used when handling SIGHUP */ g_server = server; } @@ -464,7 +426,7 @@ void server_finish(struct server *server) { #if HAVE_XWAYLAND - wlr_xwayland_destroy(server->xwayland); + xwayland_server_finish(server); #endif if (sighup_source) { wl_event_source_remove(sighup_source); diff --git a/src/view.c b/src/view.c index 468c019d..c53e16a3 100644 --- a/src/view.c +++ b/src/view.c @@ -8,6 +8,7 @@ #include "ssd.h" #include "view.h" #include "workspaces.h" +#include "xwayland.h" #define LAB_MIN_VIEW_WIDTH 100 #define LAB_MIN_VIEW_HEIGHT 60 diff --git a/src/xwayland-unmanaged.c b/src/xwayland-unmanaged.c index 5a6fb12a..1eb22619 100644 --- a/src/xwayland-unmanaged.c +++ b/src/xwayland-unmanaged.c @@ -1,8 +1,10 @@ // SPDX-License-Identifier: GPL-2.0-only #include +#include #include "common/list.h" #include "common/mem.h" #include "labwc.h" +#include "xwayland.h" static void unmanaged_handle_request_configure(struct wl_listener *listener, void *data) @@ -30,7 +32,7 @@ unmanaged_handle_set_geometry(struct wl_listener *listener, void *data) } } -void +static void unmanaged_handle_map(struct wl_listener *listener, void *data) { struct xwayland_unmanaged *unmanaged = @@ -140,9 +142,9 @@ unmanaged_handle_request_activate(struct wl_listener *listener, void *data) wlr_log(WLR_DEBUG, "request_activate not handled\n"); } -struct xwayland_unmanaged * +void xwayland_unmanaged_create(struct server *server, - struct wlr_xwayland_surface *xsurface) + struct wlr_xwayland_surface *xsurface, bool mapped) { struct xwayland_unmanaged *unmanaged = znew(*unmanaged); unmanaged->server = server; @@ -170,5 +172,7 @@ xwayland_unmanaged_create(struct server *server, &unmanaged->request_activate); unmanaged->request_activate.notify = unmanaged_handle_request_activate; - return unmanaged; + if (mapped) { + unmanaged_handle_map(&unmanaged->map, xsurface); + } } diff --git a/src/xwayland.c b/src/xwayland.c index 7c935dad..cc61ea6a 100644 --- a/src/xwayland.c +++ b/src/xwayland.c @@ -1,11 +1,15 @@ // SPDX-License-Identifier: GPL-2.0-only +#define _POSIX_C_SOURCE 200809L #include +#include +#include #include "common/mem.h" #include "labwc.h" #include "node.h" #include "ssd.h" #include "view.h" #include "workspaces.h" +#include "xwayland.h" static int round_to_increment(int val, int base, int inc) @@ -18,6 +22,7 @@ round_to_increment(int val, int base, int inc) bool xwayland_apply_size_hints(struct view *view, int *w, int *h) { + assert(view); if (view->type == LAB_XWAYLAND_VIEW) { xcb_size_hints_t *hints = xwayland_surface_from_view(view)->size_hints; @@ -42,6 +47,50 @@ xwayland_apply_size_hints(struct view *view, int *w, int *h) return false; } +static struct wlr_xwayland_surface * +top_parent_of(struct view *view) +{ + struct wlr_xwayland_surface *s = xwayland_surface_from_view(view); + while (s->parent) { + s = s->parent; + } + return s; +} + +void +xwayland_move_sub_views_to_front(struct view *parent, + void (*move_to_front)(struct view *view)) +{ + assert(parent); + assert(move_to_front); + + if (parent->type != LAB_XWAYLAND_VIEW) { + return; + } + + struct wlr_xwayland_surface *parent_xwayland_surface = + xwayland_surface_from_view(parent); + struct view *view, *next; + wl_list_for_each_reverse_safe(view, next, &parent->server->views, link) + { + /* need to stop here, otherwise loops keeps going forever */ + if (view == parent) { + break; + } + if (view->type != LAB_XWAYLAND_VIEW) { + continue; + } + if (!view->mapped && !view->minimized) { + continue; + } + if (top_parent_of(view) != parent_xwayland_surface) { + continue; + } + move_to_front(view); + /* TODO: we should probably focus on these too here */ + } +} + static struct xwayland_view * xwayland_view_from_view(struct view *view) { @@ -360,11 +409,7 @@ handle_override_redirect(struct wl_listener *listener, void *data) } handle_destroy(&view->destroy, xsurface); /* view is invalid after this point */ - struct xwayland_unmanaged *unmanaged = - xwayland_unmanaged_create(server, xsurface); - if (mapped) { - unmanaged_handle_map(&unmanaged->map, xsurface); - } + xwayland_unmanaged_create(server, xsurface, mapped); } static void @@ -534,11 +579,11 @@ static const struct view_impl xwl_view_impl = { .maximize = maximize }; -void -xwayland_surface_new(struct wl_listener *listener, void *data) +static void +handle_new_surface(struct wl_listener *listener, void *data) { struct server *server = - wl_container_of(listener, server, new_xwayland_surface); + wl_container_of(listener, server, xwayland_new_surface); struct wlr_xwayland_surface *xsurface = data; wlr_xwayland_surface_ping(xsurface); @@ -547,7 +592,7 @@ xwayland_surface_new(struct wl_listener *listener, void *data) * but add them to server.unmanaged_surfaces so that we can render them */ if (xsurface->override_redirect) { - xwayland_unmanaged_create(server, xsurface); + xwayland_unmanaged_create(server, xsurface, /* mapped */ false); return; } @@ -614,3 +659,54 @@ xwayland_surface_new(struct wl_listener *listener, void *data) wl_list_insert(&view->server->views, &view->link); } + +static void +handle_ready(struct wl_listener *listener, void *data) +{ + struct server *server = + wl_container_of(listener, server, xwayland_ready); + wlr_xwayland_set_seat(server->xwayland, server->seat.seat); +} + +void +xwayland_server_init(struct server *server, struct wlr_compositor *compositor) +{ + server->xwayland = + wlr_xwayland_create(server->wl_display, compositor, true); + if (!server->xwayland) { + wlr_log(WLR_ERROR, "cannot create xwayland server"); + exit(EXIT_FAILURE); + } + server->xwayland_new_surface.notify = handle_new_surface; + wl_signal_add(&server->xwayland->events.new_surface, + &server->xwayland_new_surface); + + server->xwayland_ready.notify = handle_ready; + wl_signal_add(&server->xwayland->events.ready, + &server->xwayland_ready); + + if (setenv("DISPLAY", server->xwayland->display_name, true) < 0) { + wlr_log_errno(WLR_ERROR, "unable to set DISPLAY for xwayland"); + } else { + wlr_log(WLR_DEBUG, "xwayland is running on display %s", + server->xwayland->display_name); + } + + struct wlr_xcursor *xcursor; + xcursor = wlr_xcursor_manager_get_xcursor(server->seat.xcursor_manager, + XCURSOR_DEFAULT, 1); + if (xcursor) { + struct wlr_xcursor_image *image = xcursor->images[0]; + wlr_xwayland_set_cursor(server->xwayland, image->buffer, + image->width * 4, image->width, + image->height, image->hotspot_x, + image->hotspot_y); + } +} + +void +xwayland_server_finish(struct server *server) +{ + wlr_xwayland_destroy(server->xwayland); + server->xwayland = NULL; +}