2021-09-24 21:45:48 +01:00
|
|
|
// SPDX-License-Identifier: GPL-2.0-only
|
2022-10-27 13:53:50 -04:00
|
|
|
#include <assert.h>
|
2023-01-07 17:50:33 -05:00
|
|
|
#include <wlr/xwayland.h>
|
2022-10-05 08:43:56 +02:00
|
|
|
#include "common/list.h"
|
2022-09-16 18:41:02 -04:00
|
|
|
#include "common/mem.h"
|
2020-09-04 20:25:20 +01:00
|
|
|
#include "labwc.h"
|
2023-01-07 17:50:33 -05:00
|
|
|
#include "xwayland.h"
|
2020-09-04 20:25:20 +01:00
|
|
|
|
2020-09-28 20:41:41 +01:00
|
|
|
static void
|
|
|
|
|
unmanaged_handle_request_configure(struct wl_listener *listener, void *data)
|
2020-09-04 20:25:20 +01:00
|
|
|
{
|
|
|
|
|
struct xwayland_unmanaged *unmanaged =
|
|
|
|
|
wl_container_of(listener, unmanaged, request_configure);
|
|
|
|
|
struct wlr_xwayland_surface *xsurface = unmanaged->xwayland_surface;
|
|
|
|
|
struct wlr_xwayland_surface_configure_event *ev = data;
|
2022-08-10 06:14:55 +02:00
|
|
|
wlr_xwayland_surface_configure(xsurface, ev->x, ev->y, ev->width, ev->height);
|
|
|
|
|
if (unmanaged->node) {
|
|
|
|
|
wlr_scene_node_set_position(unmanaged->node, ev->x, ev->y);
|
2022-09-12 13:14:18 -04:00
|
|
|
cursor_update_focus(unmanaged->server);
|
2022-08-10 06:14:55 +02:00
|
|
|
}
|
2020-09-04 20:25:20 +01:00
|
|
|
}
|
|
|
|
|
|
2022-06-04 13:20:40 +01:00
|
|
|
static void
|
|
|
|
|
unmanaged_handle_set_geometry(struct wl_listener *listener, void *data)
|
|
|
|
|
{
|
|
|
|
|
struct xwayland_unmanaged *unmanaged =
|
2022-06-05 20:42:02 +00:00
|
|
|
wl_container_of(listener, unmanaged, set_geometry);
|
2022-06-04 13:20:40 +01:00
|
|
|
struct wlr_xwayland_surface *xsurface = unmanaged->xwayland_surface;
|
2022-08-10 06:14:55 +02:00
|
|
|
if (unmanaged->node) {
|
|
|
|
|
wlr_scene_node_set_position(unmanaged->node, xsurface->x, xsurface->y);
|
2022-09-12 13:14:18 -04:00
|
|
|
cursor_update_focus(unmanaged->server);
|
2022-08-10 06:14:55 +02:00
|
|
|
}
|
2022-06-04 13:20:40 +01:00
|
|
|
}
|
|
|
|
|
|
2023-01-07 17:50:33 -05:00
|
|
|
static void
|
2020-09-28 20:41:41 +01:00
|
|
|
unmanaged_handle_map(struct wl_listener *listener, void *data)
|
2020-09-04 20:25:20 +01:00
|
|
|
{
|
|
|
|
|
struct xwayland_unmanaged *unmanaged =
|
|
|
|
|
wl_container_of(listener, unmanaged, map);
|
|
|
|
|
struct wlr_xwayland_surface *xsurface = unmanaged->xwayland_surface;
|
2022-10-27 13:53:50 -04:00
|
|
|
assert(!unmanaged->node);
|
2020-09-04 20:25:20 +01:00
|
|
|
|
2022-09-01 14:33:42 -04:00
|
|
|
/* Stack new surface on top */
|
|
|
|
|
wlr_xwayland_surface_restack(xsurface, NULL, XCB_STACK_MODE_ABOVE);
|
2022-10-05 08:43:56 +02:00
|
|
|
wl_list_append(&unmanaged->server->unmanaged_surfaces, &unmanaged->link);
|
2020-09-04 20:25:20 +01:00
|
|
|
|
2022-06-04 13:20:40 +01:00
|
|
|
wl_signal_add(&xsurface->events.set_geometry, &unmanaged->set_geometry);
|
|
|
|
|
unmanaged->set_geometry.notify = unmanaged_handle_set_geometry;
|
|
|
|
|
|
2020-09-28 20:41:41 +01:00
|
|
|
if (wlr_xwayland_or_surface_wants_focus(xsurface)) {
|
2020-10-08 20:22:52 +01:00
|
|
|
seat_focus_surface(&unmanaged->server->seat, xsurface->surface);
|
2020-09-28 20:41:41 +01:00
|
|
|
}
|
2022-02-11 23:12:45 +00:00
|
|
|
|
2022-02-22 07:57:17 +01:00
|
|
|
/* node will be destroyed automatically once surface is destroyed */
|
2022-07-02 13:18:31 -04:00
|
|
|
unmanaged->node = &wlr_scene_surface_create(
|
2022-06-05 15:17:35 +02:00
|
|
|
unmanaged->server->unmanaged_tree,
|
2022-06-04 14:08:46 +01:00
|
|
|
xsurface->surface)->buffer->node;
|
2022-07-23 11:20:34 -04:00
|
|
|
wlr_scene_node_set_position(unmanaged->node, xsurface->x, xsurface->y);
|
2022-09-12 13:14:18 -04:00
|
|
|
cursor_update_focus(unmanaged->server);
|
2020-09-04 20:25:20 +01:00
|
|
|
}
|
|
|
|
|
|
2022-09-03 13:10:33 -04:00
|
|
|
static void
|
|
|
|
|
focus_next_surface(struct server *server, struct wlr_xwayland_surface *xsurface)
|
|
|
|
|
{
|
|
|
|
|
/*
|
|
|
|
|
* Try to focus on parent surface
|
|
|
|
|
* This seems to fix JetBrains/Intellij window focus issues
|
|
|
|
|
*/
|
|
|
|
|
if (xsurface->parent && xsurface->parent->surface
|
|
|
|
|
&& wlr_xwayland_or_surface_wants_focus(xsurface->parent)) {
|
|
|
|
|
seat_focus_surface(&server->seat, xsurface->parent->surface);
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Try to focus on last created unmanaged xwayland surface */
|
|
|
|
|
struct xwayland_unmanaged *u;
|
|
|
|
|
struct wl_list *list = &server->unmanaged_surfaces;
|
2022-11-03 19:58:21 +00:00
|
|
|
wl_list_for_each_reverse(u, list, link) {
|
2022-09-03 13:10:33 -04:00
|
|
|
struct wlr_xwayland_surface *prev = u->xwayland_surface;
|
|
|
|
|
if (wlr_xwayland_or_surface_wants_focus(prev)) {
|
|
|
|
|
seat_focus_surface(&server->seat, prev->surface);
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* If we don't find a surface to focus fall back
|
|
|
|
|
* to the topmost mapped view. This fixes dmenu
|
|
|
|
|
* not giving focus back when closed with ESC.
|
|
|
|
|
*/
|
|
|
|
|
desktop_focus_topmost_mapped_view(server);
|
|
|
|
|
}
|
|
|
|
|
|
2020-09-28 20:41:41 +01:00
|
|
|
static void
|
|
|
|
|
unmanaged_handle_unmap(struct wl_listener *listener, void *data)
|
2020-09-04 20:25:20 +01:00
|
|
|
{
|
|
|
|
|
struct xwayland_unmanaged *unmanaged =
|
|
|
|
|
wl_container_of(listener, unmanaged, unmap);
|
|
|
|
|
struct wlr_xwayland_surface *xsurface = unmanaged->xwayland_surface;
|
2022-09-01 17:50:28 -04:00
|
|
|
struct seat *seat = &unmanaged->server->seat;
|
2022-10-27 13:53:50 -04:00
|
|
|
assert(unmanaged->node);
|
2022-09-01 17:50:28 -04:00
|
|
|
|
2020-09-04 20:25:20 +01:00
|
|
|
wl_list_remove(&unmanaged->link);
|
2022-06-04 13:20:40 +01:00
|
|
|
wl_list_remove(&unmanaged->set_geometry.link);
|
2022-10-27 13:53:50 -04:00
|
|
|
wlr_scene_node_set_enabled(unmanaged->node, false);
|
2020-09-04 20:25:20 +01:00
|
|
|
|
2022-08-10 06:14:55 +02:00
|
|
|
/*
|
|
|
|
|
* Mark the node as gone so a racing configure event
|
|
|
|
|
* won't try to reposition the node while unmapped.
|
|
|
|
|
*/
|
|
|
|
|
unmanaged->node = NULL;
|
2022-09-12 13:14:18 -04:00
|
|
|
cursor_update_focus(unmanaged->server);
|
2022-08-10 06:14:55 +02:00
|
|
|
|
2020-10-08 20:22:52 +01:00
|
|
|
if (seat->seat->keyboard_state.focused_surface == xsurface->surface) {
|
2022-09-03 13:10:33 -04:00
|
|
|
focus_next_surface(unmanaged->server, xsurface);
|
2020-09-04 20:25:20 +01:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2020-09-28 20:41:41 +01:00
|
|
|
static void
|
|
|
|
|
unmanaged_handle_destroy(struct wl_listener *listener, void *data)
|
2020-09-04 20:25:20 +01:00
|
|
|
{
|
|
|
|
|
struct xwayland_unmanaged *unmanaged =
|
|
|
|
|
wl_container_of(listener, unmanaged, destroy);
|
2022-06-05 22:10:15 +01:00
|
|
|
wl_list_remove(&unmanaged->request_configure.link);
|
|
|
|
|
wl_list_remove(&unmanaged->override_redirect.link);
|
|
|
|
|
wl_list_remove(&unmanaged->request_activate.link);
|
2020-09-04 20:25:20 +01:00
|
|
|
wl_list_remove(&unmanaged->map.link);
|
|
|
|
|
wl_list_remove(&unmanaged->unmap.link);
|
|
|
|
|
wl_list_remove(&unmanaged->destroy.link);
|
|
|
|
|
free(unmanaged);
|
|
|
|
|
}
|
|
|
|
|
|
2022-06-04 13:20:40 +01:00
|
|
|
static void
|
|
|
|
|
unmanaged_handle_override_redirect(struct wl_listener *listener, void *data)
|
|
|
|
|
{
|
2022-06-05 22:09:16 +01:00
|
|
|
wlr_log(WLR_DEBUG, "override_redirect not handled\n");
|
2022-06-04 13:20:40 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void
|
|
|
|
|
unmanaged_handle_request_activate(struct wl_listener *listener, void *data)
|
|
|
|
|
{
|
2022-06-05 22:09:16 +01:00
|
|
|
wlr_log(WLR_DEBUG, "request_activate not handled\n");
|
2022-06-04 13:20:40 +01:00
|
|
|
}
|
|
|
|
|
|
2023-01-07 17:50:33 -05:00
|
|
|
void
|
2020-09-28 20:41:41 +01:00
|
|
|
xwayland_unmanaged_create(struct server *server,
|
2023-01-07 17:50:33 -05:00
|
|
|
struct wlr_xwayland_surface *xsurface, bool mapped)
|
2020-09-04 20:25:20 +01:00
|
|
|
{
|
2022-09-18 15:22:26 -04:00
|
|
|
struct xwayland_unmanaged *unmanaged = znew(*unmanaged);
|
2020-09-08 20:18:12 +01:00
|
|
|
unmanaged->server = server;
|
2020-09-04 20:25:20 +01:00
|
|
|
unmanaged->xwayland_surface = xsurface;
|
2022-06-05 22:10:15 +01:00
|
|
|
|
2020-09-04 20:25:20 +01:00
|
|
|
wl_signal_add(&xsurface->events.request_configure,
|
2023-01-31 11:43:45 +01:00
|
|
|
&unmanaged->request_configure);
|
2020-09-04 20:25:20 +01:00
|
|
|
unmanaged->request_configure.notify =
|
|
|
|
|
unmanaged_handle_request_configure;
|
2022-06-05 22:10:15 +01:00
|
|
|
|
2020-09-04 20:25:20 +01:00
|
|
|
wl_signal_add(&xsurface->events.map, &unmanaged->map);
|
|
|
|
|
unmanaged->map.notify = unmanaged_handle_map;
|
2022-06-05 22:10:15 +01:00
|
|
|
|
2020-09-04 20:25:20 +01:00
|
|
|
wl_signal_add(&xsurface->events.unmap, &unmanaged->unmap);
|
|
|
|
|
unmanaged->unmap.notify = unmanaged_handle_unmap;
|
2022-06-05 22:10:15 +01:00
|
|
|
|
2020-09-04 20:25:20 +01:00
|
|
|
wl_signal_add(&xsurface->events.destroy, &unmanaged->destroy);
|
|
|
|
|
unmanaged->destroy.notify = unmanaged_handle_destroy;
|
2022-06-04 13:20:40 +01:00
|
|
|
|
|
|
|
|
wl_signal_add(&xsurface->events.set_override_redirect,
|
|
|
|
|
&unmanaged->override_redirect);
|
|
|
|
|
unmanaged->override_redirect.notify = unmanaged_handle_override_redirect;
|
|
|
|
|
|
|
|
|
|
wl_signal_add(&xsurface->events.request_activate,
|
|
|
|
|
&unmanaged->request_activate);
|
|
|
|
|
unmanaged->request_activate.notify = unmanaged_handle_request_activate;
|
|
|
|
|
|
2023-01-07 17:50:33 -05:00
|
|
|
if (mapped) {
|
|
|
|
|
unmanaged_handle_map(&unmanaged->map, xsurface);
|
|
|
|
|
}
|
2020-09-04 20:25:20 +01:00
|
|
|
}
|