cagebreak/xwayland.c
Cagebreak Signing Key 3 ed29a49be7 Release 1.7.0
- Improve window ordering
- Update dependency versions (adapt to wlroots 0.13.0)
2021-04-19 22:15:16 +02:00

243 lines
8.1 KiB
C

/*
* Cagebreak: A Wayland tiling compositor.
*
* Copyright (C) 2020 The Cagebreak Authors
* Copyright (C) 2018-2020 Jente Hidskes
*
* See the LICENSE file accompanying this file.
*/
#include <X11/Xutil.h>
#include <stdbool.h>
#include <wayland-server-core.h>
#include <wlr/types/wlr_box.h>
#include <wlr/types/wlr_output_damage.h>
#include <wlr/types/wlr_output_layout.h>
#include <wlr/util/log.h>
#include <wlr/xwayland.h>
#include "output.h"
#include "server.h"
#include "view.h"
#include "workspace.h"
#include "xwayland.h"
struct cg_xwayland_view *
xwayland_view_from_view(struct cg_view *view) {
return (struct cg_xwayland_view *)view;
}
static const struct cg_xwayland_view *
xwayland_view_from_const_view(const struct cg_view *view) {
return (const struct cg_xwayland_view *)view;
}
bool
xwayland_view_should_manage(const struct cg_view *view) {
const struct cg_xwayland_view *xwayland_view =
xwayland_view_from_const_view(view);
struct wlr_xwayland_surface *xwayland_surface =
xwayland_view->xwayland_surface;
return !xwayland_surface->override_redirect;
}
static char *
get_title(const struct cg_view *view) {
const struct cg_xwayland_view *xwayland_view =
xwayland_view_from_const_view(view);
return xwayland_view->xwayland_surface->title;
}
static bool
is_primary(const struct cg_view *view) {
const struct cg_xwayland_view *xwayland_view =
xwayland_view_from_const_view(view);
struct wlr_xwayland_surface *parent =
xwayland_view->xwayland_surface->parent;
return parent == NULL;
}
static void
activate(struct cg_view *view, bool activate) {
struct cg_xwayland_view *xwayland_view = xwayland_view_from_view(view);
wlr_xwayland_surface_activate(xwayland_view->xwayland_surface, activate);
}
static void
close(struct cg_view *view) {
struct cg_xwayland_view *xwayland_view = xwayland_view_from_view(view);
wlr_xwayland_surface_close(xwayland_view->xwayland_surface);
}
static void
maximize(struct cg_view *view, int width, int height) {
struct cg_xwayland_view *xwayland_view = xwayland_view_from_view(view);
struct cg_output *output = view->workspace->output;
struct wlr_box *box = wlr_output_layout_get_box(
view->server->output_layout, view->workspace->output->wlr_output);
struct wlr_xwayland_surface_size_hints *hints =
xwayland_view->xwayland_surface->size_hints;
if(hints != NULL && hints->flags & PMaxSize) {
if(width > hints->max_width) {
wlr_output_damage_add_box(output->damage,
&(struct wlr_box){.x = view->ox + box->x,
.y = view->oy + box->y,
.width = width,
.height = height});
width = hints->max_width;
}
if(height > hints->max_height) {
wlr_output_damage_add_box(output->damage,
&(struct wlr_box){.x = view->ox + box->x,
.y = view->oy + box->y,
.width = width,
.height = height});
height = hints->max_height;
}
}
wlr_xwayland_surface_configure(xwayland_view->xwayland_surface, view->ox,
view->oy, width, height);
wlr_xwayland_surface_set_maximized(xwayland_view->xwayland_surface, true);
}
static void
destroy(struct cg_view *view) {
struct cg_xwayland_view *xwayland_view = xwayland_view_from_view(view);
free(xwayland_view);
}
static void
for_each_surface(struct cg_view *view, wlr_surface_iterator_func_t iterator,
void *data) {
wlr_surface_for_each_surface(view->wlr_surface, iterator, data);
}
static struct wlr_surface *
wlr_surface_at(const struct cg_view *view, double sx, double sy, double *sub_x,
double *sub_y) {
return wlr_surface_surface_at(view->wlr_surface, sx, sy, sub_x, sub_y);
}
static void
handle_xwayland_surface_request_fullscreen(struct wl_listener *listener,
void *data) {
struct cg_xwayland_view *xwayland_view =
wl_container_of(listener, xwayland_view, request_fullscreen);
struct wlr_xwayland_surface *xwayland_surface =
xwayland_view->xwayland_surface;
wlr_xwayland_surface_set_fullscreen(xwayland_view->xwayland_surface,
xwayland_surface->fullscreen);
}
static void
handle_xwayland_surface_commit(struct wl_listener *listener, void *_data) {
struct cg_xwayland_view *xwayland_view =
wl_container_of(listener, xwayland_view, commit);
struct cg_view *view = &xwayland_view->view;
/* xwayland surface has moved */
if(xwayland_view->xwayland_surface->x != view->ox ||
xwayland_view->xwayland_surface->y != view->oy) {
output_damage_surface(view->workspace->output, view->wlr_surface,
view->ox, view->oy, true);
view->ox = xwayland_view->xwayland_surface->x;
view->oy = xwayland_view->xwayland_surface->y;
output_damage_surface(view->workspace->output, view->wlr_surface,
view->ox, view->oy, true);
} else {
view_damage_part(view);
}
}
static void
handle_xwayland_surface_unmap(struct wl_listener *listener, void *_data) {
struct cg_xwayland_view *xwayland_view =
wl_container_of(listener, xwayland_view, unmap);
struct cg_view *view = &xwayland_view->view;
wl_list_remove(&xwayland_view->commit.link);
view_unmap(view);
}
static void
handle_xwayland_surface_map(struct wl_listener *listener, void *_data) {
struct cg_xwayland_view *xwayland_view =
wl_container_of(listener, xwayland_view, map);
struct cg_view *view = &xwayland_view->view;
if(!xwayland_view_should_manage(view)) {
view->ox = xwayland_view->xwayland_surface->x;
view->oy = xwayland_view->xwayland_surface->y;
}
xwayland_view->commit.notify = handle_xwayland_surface_commit;
wl_signal_add(&xwayland_view->xwayland_surface->surface->events.commit,
&xwayland_view->commit);
view_map(view, xwayland_view->xwayland_surface->surface,
view->server->curr_output
->workspaces[view->server->curr_output->curr_workspace]);
view_damage_whole(view);
}
static void
handle_xwayland_surface_destroy(struct wl_listener *listener, void *_data) {
struct cg_xwayland_view *xwayland_view =
wl_container_of(listener, xwayland_view, destroy);
struct cg_view *view = &xwayland_view->view;
wl_list_remove(&xwayland_view->map.link);
wl_list_remove(&xwayland_view->unmap.link);
wl_list_remove(&xwayland_view->destroy.link);
wl_list_remove(&xwayland_view->request_fullscreen.link);
xwayland_view->xwayland_surface = NULL;
view_destroy(view);
}
static const struct cg_view_impl xwayland_view_impl = {
.get_title = get_title,
.is_primary = is_primary,
.activate = activate,
.close = close,
.maximize = maximize,
.destroy = destroy,
.for_each_surface = for_each_surface,
/* XWayland doesn't have a separate popup iterator. */
.for_each_popup = NULL,
.wlr_surface_at = wlr_surface_at,
};
void
handle_xwayland_surface_new(struct wl_listener *listener, void *data) {
struct cg_server *server =
wl_container_of(listener, server, new_xwayland_surface);
struct wlr_xwayland_surface *xwayland_surface = data;
struct cg_xwayland_view *xwayland_view =
calloc(1, sizeof(struct cg_xwayland_view));
if(!xwayland_view) {
wlr_log(WLR_ERROR, "Failed to allocate XWayland view");
return;
}
view_init(&xwayland_view->view, CG_XWAYLAND_VIEW, &xwayland_view_impl,
server);
xwayland_view->xwayland_surface = xwayland_surface;
xwayland_view->map.notify = handle_xwayland_surface_map;
wl_signal_add(&xwayland_surface->events.map, &xwayland_view->map);
xwayland_view->unmap.notify = handle_xwayland_surface_unmap;
wl_signal_add(&xwayland_surface->events.unmap, &xwayland_view->unmap);
xwayland_view->destroy.notify = handle_xwayland_surface_destroy;
wl_signal_add(&xwayland_surface->events.destroy, &xwayland_view->destroy);
xwayland_view->request_fullscreen.notify =
handle_xwayland_surface_request_fullscreen;
wl_signal_add(&xwayland_surface->events.request_fullscreen,
&xwayland_view->request_fullscreen);
}