blob: bf9cf40913ca862f242f1f99da8fb2a401da1cac [file] [log] [blame]
// Copyright 2017 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
// Needed to include both wayland-client.h and wayland-server.h.
#ifndef WL_HIDE_DEPRECATED
#define WL_HIDE_DEPRECATED
#endif
// Needed for pipe2.
#ifndef _GNU_SOURCE
#define _GNU_SOURCE
#endif
#include <assert.h>
#include <errno.h>
#include <fcntl.h>
#include <libgen.h>
#include <math.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/file.h>
#include <sys/socket.h>
#include <sys/stat.h>
#include <sys/un.h>
#include <sys/wait.h>
#include <systemd/sd-daemon.h>
#include <unistd.h>
#include <wayland-client.h>
#include <wayland-server.h>
#include <wayland-util.h>
#include <xcb/composite.h>
#include <xcb/xcb.h>
#include <xcb/xfixes.h>
#include "aura-shell-client-protocol.h"
#include "drm-server-protocol.h"
#include "linux-dmabuf-unstable-v1-client-protocol.h"
#include "version.h"
#include "viewporter-client-protocol.h"
#include "xdg-shell-unstable-v6-client-protocol.h"
#include "xdg-shell-unstable-v6-server-protocol.h"
#ifndef XWAYLAND_PATH
#define XWAYLAND_PATH "/usr/bin"
#endif
struct xwl;
struct xwl_global {
struct xwl *xwl;
const struct wl_interface *interface;
uint32_t name;
uint32_t version;
void *data;
wl_global_bind_func_t bind;
struct wl_list link;
};
struct xwl_host_registry {
struct xwl *xwl;
struct wl_resource *resource;
struct wl_list link;
};
struct xwl_host_callback {
struct wl_resource *resource;
struct wl_callback *proxy;
};
struct xwl_compositor {
struct xwl *xwl;
uint32_t id;
uint32_t version;
struct xwl_global *host_global;
struct wl_compositor *internal;
};
struct xwl_host_surface {
struct xwl *xwl;
struct wl_resource *resource;
struct wl_surface *proxy;
struct wp_viewport *viewport;
uint32_t contents_width;
uint32_t contents_height;
int32_t contents_scale;
int is_cursor;
uint32_t last_event_serial;
};
struct xwl_host_region {
struct xwl *xwl;
struct wl_resource *resource;
struct wl_region *proxy;
};
struct xwl_host_compositor {
struct xwl_compositor *compositor;
struct wl_resource *resource;
struct wl_compositor *proxy;
};
struct xwl_host_buffer {
struct wl_resource *resource;
struct wl_buffer *proxy;
uint32_t width;
uint32_t height;
};
struct xwl_host_shm_pool {
struct wl_resource *resource;
struct wl_shm_pool *proxy;
};
struct xwl_host_shm {
struct xwl_shm *shm;
struct wl_resource *resource;
struct wl_shm *proxy;
};
struct xwl_shm {
struct xwl *xwl;
uint32_t id;
struct xwl_global *host_global;
};
struct xwl_host_shell {
struct xwl_shell *shell;
struct wl_resource *resource;
struct wl_shell *proxy;
};
struct xwl_shell {
struct xwl *xwl;
uint32_t id;
struct xwl_global *host_global;
};
struct xwl_host_output {
struct xwl_output *output;
struct wl_resource *resource;
struct wl_output *proxy;
struct zaura_output *aura_output;
uint32_t flags;
int width;
int height;
int refresh;
int factor;
double scale;
double max_scale;
};
struct xwl_output {
struct xwl *xwl;
uint32_t id;
uint32_t version;
struct xwl_global *host_global;
struct wl_list link;
};
struct xwl_seat {
struct xwl *xwl;
uint32_t id;
uint32_t version;
struct xwl_global *host_global;
uint32_t last_serial;
struct wl_list link;
};
struct xwl_host_pointer {
struct xwl_seat *seat;
struct wl_resource *resource;
struct wl_pointer *proxy;
struct wl_resource *focus_resource;
struct wl_listener focus_resource_listener;
uint32_t focus_serial;
};
struct xwl_host_keyboard {
struct xwl_seat *seat;
struct wl_resource *resource;
struct wl_keyboard *proxy;
struct wl_resource *focus_resource;
struct wl_listener focus_resource_listener;
uint32_t focus_serial;
};
struct xwl_host_touch {
struct xwl_seat *seat;
struct wl_resource *resource;
struct wl_touch *proxy;
struct wl_resource *focus_resource;
struct wl_listener focus_resource_listener;
};
struct xwl_host_seat {
struct xwl_seat *seat;
struct wl_resource *resource;
struct wl_seat *proxy;
};
struct xwl_data_device_manager {
struct xwl *xwl;
uint32_t id;
uint32_t version;
struct xwl_global *host_global;
struct wl_data_device_manager *internal;
};
struct xwl_host_data_device_manager {
struct xwl *xwl;
struct wl_resource *resource;
struct wl_data_device_manager *proxy;
};
struct xwl_host_data_device {
struct xwl *xwl;
struct wl_resource *resource;
struct wl_data_device *proxy;
};
struct xwl_host_data_source {
struct wl_resource *resource;
struct wl_data_source *proxy;
};
struct xwl_host_data_offer {
struct wl_resource *resource;
struct wl_data_offer *proxy;
};
struct xwl_data_offer {
struct xwl *xwl;
struct wl_data_offer *internal;
int utf8_text;
};
struct xwl_data_source {
struct xwl *xwl;
struct wl_data_source *internal;
};
struct xwl_xdg_shell {
struct xwl *xwl;
uint32_t id;
struct xwl_global *host_global;
struct zxdg_shell_v6 *internal;
};
struct xwl_host_xdg_shell {
struct xwl_xdg_shell *xdg_shell;
struct wl_resource *resource;
struct zxdg_shell_v6 *proxy;
};
struct xwl_host_xdg_surface {
struct xwl *xwl;
struct wl_resource *resource;
struct zxdg_surface_v6 *proxy;
};
struct xwl_host_xdg_toplevel {
struct xwl *xwl;
struct wl_resource *resource;
struct zxdg_toplevel_v6 *proxy;
};
struct xwl_host_xdg_popup {
struct xwl *xwl;
struct wl_resource *resource;
struct zxdg_popup_v6 *proxy;
};
struct xwl_host_xdg_positioner {
struct xwl *xwl;
struct wl_resource *resource;
struct zxdg_positioner_v6 *proxy;
};
struct xwl_subcompositor {
struct xwl *xwl;
uint32_t id;
struct xwl_global *host_global;
};
struct xwl_host_subcompositor {
struct xwl *xwl;
struct wl_resource *resource;
struct wl_subcompositor *proxy;
};
struct xwl_host_subsurface {
struct xwl *xwl;
struct wl_resource *resource;
struct wl_subsurface *proxy;
};
struct xwl_aura_shell {
struct xwl *xwl;
uint32_t id;
uint32_t version;
struct zaura_shell *internal;
};
struct xwl_viewporter {
struct xwl *xwl;
uint32_t id;
struct wp_viewporter *internal;
};
struct xwl_linux_dmabuf {
struct xwl *xwl;
uint32_t id;
uint32_t version;
struct xwl_global *host_drm_global;
struct zwp_linux_dmabuf_v1 *internal;
};
struct xwl_host_drm {
struct xwl_linux_dmabuf *linux_dmabuf;
uint32_t version;
struct wl_resource *resource;
};
struct xwl_config {
uint32_t serial;
uint32_t mask;
uint32_t values[5];
uint32_t states_length;
uint32_t states[3];
};
struct xwl_window {
struct xwl *xwl;
xcb_window_t id;
xcb_window_t frame_id;
uint32_t host_surface_id;
int unpaired;
int x;
int y;
int width;
int height;
int border_width;
int depth;
int managed;
int realized;
int activated;
xcb_window_t transient_for;
int decorated;
char *name;
char *clazz;
uint32_t size_flags;
struct xwl_config next_config;
struct xwl_config pending_config;
struct zxdg_surface_v6 *xdg_surface;
struct zxdg_toplevel_v6 *xdg_toplevel;
struct zxdg_popup_v6 *xdg_popup;
struct zaura_surface *aura_surface;
struct wl_list link;
};
enum {
ATOM_WM_S0,
ATOM_WM_PROTOCOLS,
ATOM_WM_STATE,
ATOM_WM_DELETE_WINDOW,
ATOM_WM_TAKE_FOCUS,
ATOM_WL_SURFACE_ID,
ATOM_UTF8_STRING,
ATOM_MOTIF_WM_HINTS,
ATOM_NET_FRAME_EXTENTS,
ATOM_NET_SUPPORTING_WM_CHECK,
ATOM_NET_WM_NAME,
ATOM_NET_WM_MOVERESIZE,
ATOM_NET_WM_STATE,
ATOM_NET_WM_STATE_FULLSCREEN,
ATOM_NET_WM_STATE_MAXIMIZED_VERT,
ATOM_NET_WM_STATE_MAXIMIZED_HORZ,
ATOM_CLIPBOARD,
ATOM_CLIPBOARD_MANAGER,
ATOM_TARGETS,
ATOM_TIMESTAMP,
ATOM_TEXT,
ATOM_INCR,
ATOM_WL_SELECTION,
ATOM_LAST = ATOM_WL_SELECTION,
};
struct xwl {
char **runprog;
struct wl_display *display;
struct wl_display *host_display;
struct wl_client *client;
struct xwl_compositor *compositor;
struct xwl_subcompositor *subcompositor;
struct xwl_shm *shm;
struct xwl_shell *shell;
struct xwl_data_device_manager *data_device_manager;
struct xwl_xdg_shell *xdg_shell;
struct xwl_aura_shell *aura_shell;
struct xwl_viewporter *viewporter;
struct xwl_linux_dmabuf *linux_dmabuf;
struct wl_list outputs;
struct wl_list seats;
struct wl_event_source *display_event_source;
struct wl_event_source *display_ready_event_source;
struct wl_event_source *sigchld_event_source;
int wm_fd;
const char *drm_device;
int xwayland;
pid_t xwayland_pid;
pid_t child_pid;
pid_t peer_pid;
struct wl_list registries;
struct wl_list globals;
int next_global_id;
xcb_connection_t *connection;
struct wl_event_source *connection_event_source;
const xcb_query_extension_reply_t *xfixes_extension;
xcb_screen_t *screen;
xcb_window_t window;
struct wl_list windows, unpaired_windows;
struct xwl_window *host_focus_window;
int needs_set_input_focus;
double scale;
const char *app_id;
int exit_with_child;
int clipboard_manager;
uint32_t frame_color;
int has_frame_color;
int show_window_title;
struct xwl_host_seat *default_seat;
xcb_window_t selection_window;
xcb_window_t selection_owner;
int selection_incremental_transfer;
xcb_selection_request_event_t selection_request;
xcb_timestamp_t selection_timestamp;
struct wl_data_device *selection_data_device;
struct xwl_data_offer *selection_data_offer;
struct xwl_data_source *selection_data_source;
int selection_data_source_send_fd;
struct wl_event_source *selection_send_event_source;
xcb_get_property_reply_t *selection_property_reply;
int selection_property_offset;
struct wl_event_source *selection_event_source;
struct wl_array selection_data;
int selection_data_offer_receive_fd;
int selection_data_ack_pending;
union {
const char *name;
xcb_intern_atom_cookie_t cookie;
xcb_atom_t value;
} atoms[ATOM_LAST + 1];
xcb_visualid_t visual_ids[256];
xcb_colormap_t colormaps[256];
};
enum {
PROPERTY_WM_NAME,
PROPERTY_WM_CLASS,
PROPERTY_WM_TRANSIENT_FOR,
PROPERTY_WM_NORMAL_HINTS,
PROPERTY_MOTIF_WM_HINTS,
};
#define US_POSITION (1L << 0)
#define US_SIZE (1L << 1)
#define P_POSITION (1L << 2)
#define P_SIZE (1L << 3)
#define P_MIN_SIZE (1L << 4)
#define P_MAX_SIZE (1L << 5)
#define P_RESIZE_INC (1L << 6)
#define P_ASPECT (1L << 7)
#define P_BASE_SIZE (1L << 8)
#define P_WIN_GRAVITY (1L << 9)
#define MWM_HINTS_FUNCTIONS (1L << 0)
#define MWM_HINTS_DECORATIONS (1L << 1)
#define MWM_HINTS_INPUT_MODE (1L << 2)
#define MWM_HINTS_STATUS (1L << 3)
#define MWM_DECOR_ALL (1L << 0)
#define MWM_DECOR_BORDER (1L << 1)
#define MWM_DECOR_RESIZEH (1L << 2)
#define MWM_DECOR_TITLE (1L << 3)
#define MWM_DECOR_MENU (1L << 4)
#define MWM_DECOR_MINIMIZE (1L << 5)
#define MWM_DECOR_MAXIMIZE (1L << 6)
#define NET_WM_MOVERESIZE_SIZE_TOPLEFT 0
#define NET_WM_MOVERESIZE_SIZE_TOP 1
#define NET_WM_MOVERESIZE_SIZE_TOPRIGHT 2
#define NET_WM_MOVERESIZE_SIZE_RIGHT 3
#define NET_WM_MOVERESIZE_SIZE_BOTTOMRIGHT 4
#define NET_WM_MOVERESIZE_SIZE_BOTTOM 5
#define NET_WM_MOVERESIZE_SIZE_BOTTOMLEFT 6
#define NET_WM_MOVERESIZE_SIZE_LEFT 7
#define NET_WM_MOVERESIZE_MOVE 8
#define NET_WM_STATE_REMOVE 0
#define NET_WM_STATE_ADD 1
#define NET_WM_STATE_TOGGLE 2
#define WM_STATE_WITHDRAWN 0
#define WM_STATE_NORMAL 1
#define WM_STATE_ICONIC 3
#define SEND_EVENT_MASK 0x80
#define CAPTION_HEIGHT 32
#define MIN_SCALE 0.1
#define MAX_SCALE 10.0
#define MIN(a, b) (((a) < (b)) ? (a) : (b))
#define MAX(a, b) (((a) > (b)) ? (a) : (b))
#define ARRAY_SIZE(a) (sizeof(a) / sizeof(a[0]))
#ifndef UNIX_PATH_MAX
#define UNIX_PATH_MAX 108
#endif
#define LOCK_SUFFIX ".lock"
#define LOCK_SUFFIXLEN 5
static void xwl_internal_xdg_shell_ping(void *data,
struct zxdg_shell_v6 *xdg_shell,
uint32_t serial) {
zxdg_shell_v6_pong(xdg_shell, serial);
}
static const struct zxdg_shell_v6_listener xwl_internal_xdg_shell_listener = {
xwl_internal_xdg_shell_ping};
static void xwl_send_configure_notify(struct xwl_window *window) {
xcb_configure_notify_event_t event = {
.response_type = XCB_CONFIGURE_NOTIFY,
.event = window->id,
.window = window->id,
.above_sibling = XCB_WINDOW_NONE,
.x = window->x,
.y = window->y,
.width = window->width,
.height = window->height,
.border_width = window->border_width,
.override_redirect = 0,
.pad0 = 0,
.pad1 = 0,
};
xcb_send_event(window->xwl->connection, 0, window->id,
XCB_EVENT_MASK_STRUCTURE_NOTIFY, (char *)&event);
}
static void xwl_adjust_window_size_for_screen_size(struct xwl_window *window) {
struct xwl *xwl = window->xwl;
// Clamp size to screen.
window->width = MIN(window->width, xwl->screen->width_in_pixels);
window->height = MIN(window->height, xwl->screen->height_in_pixels);
}
static void
xwl_adjust_window_position_for_screen_size(struct xwl_window *window) {
struct xwl *xwl = window->xwl;
// Center horizontally/vertically.
window->x = xwl->screen->width_in_pixels / 2 - window->width / 2;
window->y = xwl->screen->height_in_pixels / 2 - window->height / 2;
}
static void xwl_configure_window(struct xwl_window *window) {
assert(!window->pending_config.serial);
if (window->next_config.mask) {
int x = window->x;
int y = window->y;
int i = 0;
xcb_configure_window(window->xwl->connection, window->frame_id,
window->next_config.mask, window->next_config.values);
if (window->next_config.mask & XCB_CONFIG_WINDOW_X)
x = window->next_config.values[i++];
if (window->next_config.mask & XCB_CONFIG_WINDOW_Y)
y = window->next_config.values[i++];
assert(window->managed);
xcb_configure_window(window->xwl->connection, window->id,
window->next_config.mask &
~(XCB_CONFIG_WINDOW_X | XCB_CONFIG_WINDOW_Y),
&window->next_config.values[i]);
if (window->next_config.mask & XCB_CONFIG_WINDOW_WIDTH)
window->width = window->next_config.values[i++];
if (window->next_config.mask & XCB_CONFIG_WINDOW_HEIGHT)
window->height = window->next_config.values[i++];
if (window->next_config.mask & XCB_CONFIG_WINDOW_BORDER_WIDTH)
window->border_width = window->next_config.values[i++];
if (x != window->x || y != window->y) {
window->x = x;
window->y = y;
xwl_send_configure_notify(window);
}
}
if (window->managed) {
xcb_change_property(window->xwl->connection, XCB_PROP_MODE_REPLACE,
window->id, window->xwl->atoms[ATOM_NET_WM_STATE].value,
XCB_ATOM_ATOM, 32, window->next_config.states_length,
window->next_config.states);
}
window->pending_config = window->next_config;
window->next_config.serial = 0;
window->next_config.mask = 0;
window->next_config.states_length = 0;
}
static void xwl_set_input_focus(struct xwl *xwl, struct xwl_window *window) {
if (window) {
xcb_client_message_event_t event = {
.response_type = XCB_CLIENT_MESSAGE,
.format = 32,
.window = window->id,
.type = xwl->atoms[ATOM_WM_PROTOCOLS].value,
.data.data32 =
{
xwl->atoms[ATOM_WM_TAKE_FOCUS].value, XCB_CURRENT_TIME,
},
};
if (!window->managed)
return;
xcb_send_event(xwl->connection, 0, window->id,
XCB_EVENT_MASK_SUBSTRUCTURE_REDIRECT, (char *)&event);
xcb_set_input_focus(xwl->connection, XCB_INPUT_FOCUS_NONE, window->id,
XCB_CURRENT_TIME);
} else {
xcb_set_input_focus(xwl->connection, XCB_INPUT_FOCUS_NONE, XCB_NONE,
XCB_CURRENT_TIME);
}
}
static void xwl_restack_windows(struct xwl *xwl, uint32_t focus_resource_id) {
struct xwl_window *sibling;
uint32_t values[1];
wl_list_for_each(sibling, &xwl->windows, link) {
if (!sibling->managed)
continue;
// Move focus window to the top and all other windows to the bottom.
values[0] = sibling->host_surface_id == focus_resource_id
? XCB_STACK_MODE_ABOVE
: XCB_STACK_MODE_BELOW;
xcb_configure_window(xwl->connection, sibling->frame_id,
XCB_CONFIG_WINDOW_STACK_MODE, values);
}
}
static void xwl_roundtrip(struct xwl *xwl) {
free(xcb_get_input_focus_reply(xwl->connection,
xcb_get_input_focus(xwl->connection), NULL));
}
static int
xwl_process_pending_configure_acks(struct xwl_window *window,
struct xwl_host_surface *host_surface) {
if (!window->pending_config.serial)
return 0;
if (window->managed && host_surface) {
int width = window->width + window->border_width * 2;
int height = window->height + window->border_width * 2;
// Early out if we expect contents to match window size at some point in
// the future.
if (width != host_surface->contents_width ||
height != host_surface->contents_height) {
return 0;
}
}
if (window->xdg_surface) {
zxdg_surface_v6_ack_configure(window->xdg_surface,
window->pending_config.serial);
}
window->pending_config.serial = 0;
if (window->next_config.serial)
xwl_configure_window(window);
return 1;
}
static void xwl_internal_xdg_surface_configure(
void *data, struct zxdg_surface_v6 *xdg_surface, uint32_t serial) {
struct xwl_window *window = zxdg_surface_v6_get_user_data(xdg_surface);
window->next_config.serial = serial;
if (!window->pending_config.serial) {
struct wl_resource *host_resource;
struct xwl_host_surface *host_surface = NULL;
host_resource =
wl_client_get_object(window->xwl->client, window->host_surface_id);
if (host_resource)
host_surface = wl_resource_get_user_data(host_resource);
xwl_configure_window(window);
if (xwl_process_pending_configure_acks(window, host_surface)) {
if (host_surface)
wl_surface_commit(host_surface->proxy);
}
}
}
static const struct zxdg_surface_v6_listener xwl_internal_xdg_surface_listener =
{xwl_internal_xdg_surface_configure};
static void xwl_internal_xdg_toplevel_configure(
void *data, struct zxdg_toplevel_v6 *xdg_toplevel, int32_t width,
int32_t height, struct wl_array *states) {
struct xwl_window *window = zxdg_toplevel_v6_get_user_data(xdg_toplevel);
int activated = 0;
uint32_t *state;
int i = 0;
if (!window->managed)
return;
if (width && height) {
int32_t width_in_pixels = width * window->xwl->scale;
int32_t height_in_pixels = height * window->xwl->scale;
int i = 0;
window->next_config.mask = XCB_CONFIG_WINDOW_WIDTH |
XCB_CONFIG_WINDOW_HEIGHT |
XCB_CONFIG_WINDOW_BORDER_WIDTH;
if (!(window->size_flags & (US_POSITION | P_POSITION))) {
window->next_config.mask |= XCB_CONFIG_WINDOW_X | XCB_CONFIG_WINDOW_Y;
window->next_config.values[i++] =
window->xwl->screen->width_in_pixels / 2 - width_in_pixels / 2;
window->next_config.values[i++] =
window->xwl->screen->height_in_pixels / 2 - height_in_pixels / 2;
}
window->next_config.values[i++] = width_in_pixels;
window->next_config.values[i++] = height_in_pixels;
window->next_config.values[i++] = 0;
}
wl_array_for_each(state, states) {
if (*state == ZXDG_TOPLEVEL_V6_STATE_FULLSCREEN) {
window->next_config.states[i++] =
window->xwl->atoms[ATOM_NET_WM_STATE_FULLSCREEN].value;
}
if (*state == ZXDG_TOPLEVEL_V6_STATE_MAXIMIZED) {
window->next_config.states[i++] =
window->xwl->atoms[ATOM_NET_WM_STATE_MAXIMIZED_VERT].value;
window->next_config.states[i++] =
window->xwl->atoms[ATOM_NET_WM_STATE_MAXIMIZED_HORZ].value;
}
if (*state == ZXDG_TOPLEVEL_V6_STATE_ACTIVATED)
activated = 1;
}
if (activated != window->activated) {
if (activated != (window->xwl->host_focus_window == window)) {
window->xwl->host_focus_window = activated ? window : NULL;
window->xwl->needs_set_input_focus = 1;
}
window->activated = activated;
}
window->next_config.states_length = i;
}
static void
xwl_internal_xdg_toplevel_close(void *data,
struct zxdg_toplevel_v6 *xdg_toplevel) {
struct xwl_window *window = zxdg_toplevel_v6_get_user_data(xdg_toplevel);
xcb_client_message_event_t event = {
.response_type = XCB_CLIENT_MESSAGE,
.format = 32,
.window = window->id,
.type = window->xwl->atoms[ATOM_WM_PROTOCOLS].value,
.data.data32 =
{
window->xwl->atoms[ATOM_WM_DELETE_WINDOW].value, XCB_CURRENT_TIME,
},
};
xcb_send_event(window->xwl->connection, 0, window->id,
XCB_EVENT_MASK_NO_EVENT, (const char *)&event);
}
static const struct zxdg_toplevel_v6_listener
xwl_internal_xdg_toplevel_listener = {xwl_internal_xdg_toplevel_configure,
xwl_internal_xdg_toplevel_close};
static void xwl_internal_xdg_popup_configure(void *data,
struct zxdg_popup_v6 *xdg_popup,
int32_t x, int32_t y,
int32_t width, int32_t height) {}
static void xwl_internal_xdg_popup_done(void *data,
struct zxdg_popup_v6 *zxdg_popup_v6) {}
static const struct zxdg_popup_v6_listener xwl_internal_xdg_popup_listener = {
xwl_internal_xdg_popup_configure, xwl_internal_xdg_popup_done};
static void xwl_window_set_wm_state(struct xwl_window *window, int state) {
struct xwl *xwl = window->xwl;
uint32_t values[2];
values[0] = state;
values[1] = XCB_WINDOW_NONE;
xcb_change_property(xwl->connection, XCB_PROP_MODE_REPLACE, window->id,
xwl->atoms[ATOM_WM_STATE].value,
xwl->atoms[ATOM_WM_STATE].value, 32, 2, values);
}
static void xwl_window_update(struct xwl_window *window) {
struct wl_resource *host_resource = NULL;
struct xwl_host_surface *host_surface;
struct xwl *xwl = window->xwl;
struct xwl_window *parent = NULL;
const char *app_id = NULL;
if (window->host_surface_id) {
host_resource = wl_client_get_object(xwl->client, window->host_surface_id);
if (host_resource && window->unpaired) {
wl_list_remove(&window->link);
wl_list_insert(&xwl->windows, &window->link);
window->unpaired = 0;
}
} else if (!window->unpaired) {
wl_list_remove(&window->link);
wl_list_insert(&xwl->unpaired_windows, &window->link);
window->unpaired = 1;
}
if (!host_resource) {
if (window->aura_surface) {
zaura_surface_destroy(window->aura_surface);
window->aura_surface = NULL;
}
if (window->xdg_toplevel) {
zxdg_toplevel_v6_destroy(window->xdg_toplevel);
window->xdg_toplevel = NULL;
}
if (window->xdg_popup) {
zxdg_popup_v6_destroy(window->xdg_popup);
window->xdg_popup = NULL;
}
if (window->xdg_surface) {
zxdg_surface_v6_destroy(window->xdg_surface);
window->xdg_surface = NULL;
}
return;
}
host_surface = wl_resource_get_user_data(host_resource);
assert(host_surface);
assert(!host_surface->is_cursor);
assert(xwl->xdg_shell);
assert(xwl->xdg_shell->internal);
if (window->managed) {
app_id = xwl->app_id ? xwl->app_id : window->clazz;
if (window->transient_for != XCB_WINDOW_NONE) {
struct xwl_window *sibling;
wl_list_for_each(sibling, &xwl->windows, link) {
if (sibling->id == window->transient_for) {
if (sibling->xdg_toplevel)
parent = sibling;
break;
}
}
}
} else {
struct xwl_window *sibling;
uint32_t parent_last_event_serial = 0;
wl_list_for_each(sibling, &xwl->windows, link) {
struct wl_resource *sibling_host_resource;
struct xwl_host_surface *sibling_host_surface;
if (!sibling->realized)
continue;
sibling_host_resource =
wl_client_get_object(xwl->client, sibling->host_surface_id);
if (!sibling_host_resource)
continue;
// Any parent will do but prefer last event window.
sibling_host_surface = wl_resource_get_user_data(sibling_host_resource);
if (parent_last_event_serial > sibling_host_surface->last_event_serial)
continue;
parent = sibling;
parent_last_event_serial = sibling_host_surface->last_event_serial;
}
}
if (!window->depth) {
xcb_get_geometry_reply_t *geometry_reply = xcb_get_geometry_reply(
xwl->connection, xcb_get_geometry(xwl->connection, window->id), NULL);
if (geometry_reply) {
window->depth = geometry_reply->depth;
free(geometry_reply);
}
}
if (!window->xdg_surface) {
window->xdg_surface = zxdg_shell_v6_get_xdg_surface(
xwl->xdg_shell->internal, host_surface->proxy);
zxdg_surface_v6_set_user_data(window->xdg_surface, window);
zxdg_surface_v6_add_listener(window->xdg_surface,
&xwl_internal_xdg_surface_listener, window);
}
if (xwl->aura_shell) {
if (!window->aura_surface) {
window->aura_surface = zaura_shell_get_aura_surface(
xwl->aura_shell->internal, host_surface->proxy);
}
zaura_surface_set_frame(window->aura_surface,
window->decorated
? ZAURA_SURFACE_FRAME_TYPE_NORMAL
: window->depth == 32
? ZAURA_SURFACE_FRAME_TYPE_NONE
: ZAURA_SURFACE_FRAME_TYPE_SHADOW);
if (xwl->has_frame_color &&
xwl->aura_shell->version >=
ZAURA_SURFACE_SET_FRAME_COLORS_SINCE_VERSION) {
zaura_surface_set_frame_colors(window->aura_surface, xwl->frame_color,
xwl->frame_color);
}
}
if (window->managed || !parent) {
if (!window->xdg_toplevel) {
window->xdg_toplevel = zxdg_surface_v6_get_toplevel(window->xdg_surface);
zxdg_toplevel_v6_set_user_data(window->xdg_toplevel, window);
zxdg_toplevel_v6_add_listener(
window->xdg_toplevel, &xwl_internal_xdg_toplevel_listener, window);
}
if (parent)
zxdg_toplevel_v6_set_parent(window->xdg_toplevel, parent->xdg_toplevel);
if (window->name && xwl->show_window_title)
zxdg_toplevel_v6_set_title(window->xdg_toplevel, window->name);
if (app_id)
zxdg_toplevel_v6_set_app_id(window->xdg_toplevel, app_id);
} else if (!window->xdg_popup) {
struct zxdg_positioner_v6 *positioner;
positioner = zxdg_shell_v6_create_positioner(xwl->xdg_shell->internal);
assert(positioner);
zxdg_positioner_v6_set_anchor(positioner,
ZXDG_POSITIONER_V6_ANCHOR_TOP |
ZXDG_POSITIONER_V6_ANCHOR_LEFT);
zxdg_positioner_v6_set_gravity(positioner,
ZXDG_POSITIONER_V6_GRAVITY_BOTTOM |
ZXDG_POSITIONER_V6_GRAVITY_RIGHT);
zxdg_positioner_v6_set_anchor_rect(
positioner, (window->x - parent->x) / xwl->scale,
(window->y - parent->y) / xwl->scale, 1, 1);
window->xdg_popup = zxdg_surface_v6_get_popup(
window->xdg_surface, parent->xdg_surface, positioner);
zxdg_popup_v6_set_user_data(window->xdg_popup, window);
zxdg_popup_v6_add_listener(window->xdg_popup,
&xwl_internal_xdg_popup_listener, window);
zxdg_positioner_v6_destroy(positioner);
}
if ((window->size_flags & (US_POSITION | P_POSITION)) && parent &&
xwl->aura_shell &&
xwl->aura_shell->version >= ZAURA_SURFACE_SET_PARENT_SINCE_VERSION) {
zaura_surface_set_parent(window->aura_surface, parent->aura_surface,
(window->x - parent->x) / xwl->scale,
(window->y - parent->y) / xwl->scale);
}
wl_surface_commit(host_surface->proxy);
if (host_surface->contents_width && host_surface->contents_height)
window->realized = 1;
}
static void xwl_host_surface_destroy(struct wl_client *client,
struct wl_resource *resource) {
wl_resource_destroy(resource);
}
static void xwl_set_host_surface_scale(struct xwl_host_surface *host) {
double scale = host->xwl->scale * host->contents_scale;
if (!host->contents_width || !host->contents_height)
return;
if (host->viewport) {
wp_viewport_set_destination(host->viewport,
ceil(host->contents_width / scale),
ceil(host->contents_height / scale));
} else {
wl_surface_set_buffer_scale(host->proxy, scale);
}
}
static void xwl_host_surface_attach(struct wl_client *client,
struct wl_resource *resource,
struct wl_resource *buffer_resource,
int32_t x, int32_t y) {
struct xwl_host_surface *host = wl_resource_get_user_data(resource);
struct xwl_host_buffer *host_buffer =
buffer_resource ? wl_resource_get_user_data(buffer_resource) : NULL;
struct wl_buffer *buffer_proxy = NULL;
struct xwl_window *window;
double scale = host->xwl->scale;
if (host_buffer) {
host->contents_width = host_buffer->width;
host->contents_height = host_buffer->height;
buffer_proxy = host_buffer->proxy;
}
wl_surface_attach(host->proxy, buffer_proxy, x / scale, y / scale);
xwl_set_host_surface_scale(host);
wl_list_for_each(window, &host->xwl->windows, link) {
if (window->host_surface_id == wl_resource_get_id(resource)) {
while (xwl_process_pending_configure_acks(window, host))
continue;
break;
}
}
}
static void xwl_host_surface_damage(struct wl_client *client,
struct wl_resource *resource, int32_t x,
int32_t y, int32_t width, int32_t height) {
struct xwl_host_surface *host = wl_resource_get_user_data(resource);
double scale = host->xwl->scale;
int32_t x1, y1, x2, y2;
// Enclosing rect after scaling and outset by one pixel to account for
// potential filtering.
x1 = (x - 1) / scale;
y1 = (y - 1) / scale;
x2 = ceil((x + width + 1) / scale);
y2 = ceil((y + height + 1) / scale);
wl_surface_damage(host->proxy, x1, y1, x2 - x1, y2 - y1);
}
static void xwl_frame_callback_done(void *data, struct wl_callback *callback,
uint32_t time) {
struct xwl_host_callback *host = wl_callback_get_user_data(callback);
wl_callback_send_done(host->resource, time);
wl_resource_destroy(host->resource);
}
static const struct wl_callback_listener xwl_frame_callback_listener = {
xwl_frame_callback_done};
static void xwl_host_callback_destroy(struct wl_resource *resource) {
struct xwl_host_callback *host = wl_resource_get_user_data(resource);
wl_callback_destroy(host->proxy);
wl_resource_set_user_data(resource, NULL);
free(host);
}
static void xwl_host_surface_frame(struct wl_client *client,
struct wl_resource *resource,
uint32_t callback) {
struct xwl_host_surface *host = wl_resource_get_user_data(resource);
struct xwl_host_callback *host_callback;
host_callback = malloc(sizeof(*host_callback));
assert(host_callback);
host_callback->resource =
wl_resource_create(client, &wl_callback_interface, 1, callback);
wl_resource_set_implementation(host_callback->resource, NULL, host_callback,
xwl_host_callback_destroy);
host_callback->proxy = wl_surface_frame(host->proxy);
wl_callback_set_user_data(host_callback->proxy, host_callback);
wl_callback_add_listener(host_callback->proxy, &xwl_frame_callback_listener,
host_callback);
}
static void
xwl_host_surface_set_opaque_region(struct wl_client *client,
struct wl_resource *resource,
struct wl_resource *region_resource) {
struct xwl_host_surface *host = wl_resource_get_user_data(resource);
struct xwl_host_region *host_region =
region_resource ? wl_resource_get_user_data(region_resource) : NULL;
wl_surface_set_opaque_region(host->proxy,
host_region ? host_region->proxy : NULL);
}
static void
xwl_host_surface_set_input_region(struct wl_client *client,
struct wl_resource *resource,
struct wl_resource *region_resource) {
struct xwl_host_surface *host = wl_resource_get_user_data(resource);
struct xwl_host_region *host_region =
region_resource ? wl_resource_get_user_data(region_resource) : NULL;
wl_surface_set_input_region(host->proxy,
host_region ? host_region->proxy : NULL);
}
static void xwl_host_surface_commit(struct wl_client *client,
struct wl_resource *resource) {
struct xwl_host_surface *host = wl_resource_get_user_data(resource);
struct xwl_window *window;
// No need to defer cursor or non-xwayland client commits.
if (host->is_cursor || !host->xwl->xwayland) {
wl_surface_commit(host->proxy);
return;
}
// Commit if surface is associated with a window. Otherwise, defer
// commit until window is created.
wl_list_for_each(window, &host->xwl->windows, link) {
if (window->host_surface_id == wl_resource_get_id(resource)) {
if (window->xdg_surface) {
wl_surface_commit(host->proxy);
if (host->contents_width && host->contents_height)
window->realized = 1;
}
break;
}
}
}
static void xwl_host_surface_set_buffer_transform(struct wl_client *client,
struct wl_resource *resource,
int32_t transform) {
struct xwl_host_surface *host = wl_resource_get_user_data(resource);
wl_surface_set_buffer_transform(host->proxy, transform);
}
static void xwl_host_surface_set_buffer_scale(struct wl_client *client,
struct wl_resource *resource,
int32_t scale) {
struct xwl_host_surface *host = wl_resource_get_user_data(resource);
host->contents_scale = scale;
xwl_set_host_surface_scale(host);
}
static void xwl_host_surface_damage_buffer(struct wl_client *client,
struct wl_resource *resource,
int32_t x, int32_t y, int32_t width,
int32_t height) {
assert(0);
}
static const struct wl_surface_interface xwl_surface_implementation = {
xwl_host_surface_destroy,
xwl_host_surface_attach,
xwl_host_surface_damage,
xwl_host_surface_frame,
xwl_host_surface_set_opaque_region,
xwl_host_surface_set_input_region,
xwl_host_surface_commit,
xwl_host_surface_set_buffer_transform,
xwl_host_surface_set_buffer_scale,
xwl_host_surface_damage_buffer};
static void xwl_destroy_host_surface(struct wl_resource *resource) {
struct xwl_host_surface *host = wl_resource_get_user_data(resource);
struct xwl_window *window, *surface_window = NULL;
wl_list_for_each(window, &host->xwl->windows, link) {
if (window->host_surface_id == wl_resource_get_id(resource)) {
surface_window = window;
break;
}
}
if (surface_window) {
surface_window->host_surface_id = 0;
xwl_window_update(surface_window);
}
if (host->viewport)
wp_viewport_destroy(host->viewport);
wl_surface_destroy(host->proxy);
wl_resource_set_user_data(resource, NULL);
free(host);
}
static void xwl_region_destroy(struct wl_client *client,
struct wl_resource *resource) {
wl_resource_destroy(resource);
}
static void xwl_region_add(struct wl_client *client,
struct wl_resource *resource, int32_t x, int32_t y,
int32_t width, int32_t height) {
struct xwl_host_region *host = wl_resource_get_user_data(resource);
double scale = host->xwl->scale;
int32_t x1, y1, x2, y2;
x1 = x / scale;
y1 = y / scale;
x2 = (x + width) / scale;
y2 = (y + height) / scale;
wl_region_add(host->proxy, x1, y1, x2 - x1, y2 - y1);
}
static void xwl_region_subtract(struct wl_client *client,
struct wl_resource *resource, int32_t x,
int32_t y, int32_t width, int32_t height) {
struct xwl_host_region *host = wl_resource_get_user_data(resource);
double scale = host->xwl->scale;
int32_t x1, y1, x2, y2;
x1 = x / scale;
y1 = y / scale;
x2 = (x + width) / scale;
y2 = (y + height) / scale;
wl_region_subtract(host->proxy, x1, y1, x2 - x1, y2 - y1);
}
static const struct wl_region_interface xwl_region_implementation = {
xwl_region_destroy, xwl_region_add, xwl_region_subtract};
static void xwl_destroy_host_region(struct wl_resource *resource) {
struct xwl_host_region *host = wl_resource_get_user_data(resource);
wl_region_destroy(host->proxy);
wl_resource_set_user_data(resource, NULL);
free(host);
}
static void xwl_compositor_create_host_surface(struct wl_client *client,
struct wl_resource *resource,
uint32_t id) {
struct xwl_host_compositor *host = wl_resource_get_user_data(resource);
struct xwl_host_surface *host_surface;
struct xwl_window *window, *unpaired_window = NULL;
host_surface = malloc(sizeof(*host_surface));
assert(host_surface);
host_surface->xwl = host->compositor->xwl;
host_surface->contents_width = 0;
host_surface->contents_height = 0;
host_surface->contents_scale = 1;
host_surface->is_cursor = 0;
host_surface->last_event_serial = 0;
host_surface->resource = wl_resource_create(
client, &wl_surface_interface, wl_resource_get_version(resource), id);
wl_resource_set_implementation(host_surface->resource,
&xwl_surface_implementation, host_surface,
xwl_destroy_host_surface);
host_surface->proxy = wl_compositor_create_surface(host->proxy);
wl_surface_set_user_data(host_surface->proxy, host_surface);
if (host_surface->xwl->viewporter) {
host_surface->viewport = wp_viewporter_get_viewport(
host_surface->xwl->viewporter->internal, host_surface->proxy);
}
wl_list_for_each(window, &host->compositor->xwl->unpaired_windows, link) {
if (window->host_surface_id == id) {
unpaired_window = window;
break;
}
}
if (unpaired_window)
xwl_window_update(window);
}
static void xwl_compositor_create_host_region(struct wl_client *client,
struct wl_resource *resource,
uint32_t id) {
struct xwl_host_compositor *host = wl_resource_get_user_data(resource);
struct xwl_host_region *host_region;
host_region = malloc(sizeof(*host_region));
assert(host_region);
host_region->xwl = host->compositor->xwl;
host_region->resource = wl_resource_create(
client, &wl_region_interface, wl_resource_get_version(resource), id);
wl_resource_set_implementation(host_region->resource,
&xwl_region_implementation, host_region,
xwl_destroy_host_region);
host_region->proxy = wl_compositor_create_region(host->proxy);
wl_region_set_user_data(host_region->proxy, host_region);
}
static const struct wl_compositor_interface xwl_compositor_implementation = {
xwl_compositor_create_host_surface, xwl_compositor_create_host_region};
static void xwl_destroy_host_compositor(struct wl_resource *resource) {
struct xwl_host_compositor *host = wl_resource_get_user_data(resource);
wl_compositor_destroy(host->proxy);
wl_resource_set_user_data(resource, NULL);
free(host);
}
static void xwl_bind_host_compositor(struct wl_client *client, void *data,
uint32_t version, uint32_t id) {
struct xwl_compositor *compositor = (struct xwl_compositor *)data;
struct xwl_host_compositor *host;
host = malloc(sizeof(*host));
assert(host);
host->compositor = compositor;
host->resource = wl_resource_create(client, &wl_compositor_interface,
MIN(version, compositor->version), id);
wl_resource_set_implementation(host->resource, &xwl_compositor_implementation,
host, xwl_destroy_host_compositor);
host->proxy = wl_registry_bind(
wl_display_get_registry(compositor->xwl->display), compositor->id,
&wl_compositor_interface, compositor->version);
wl_compositor_set_user_data(host->proxy, host);
}
static void xwl_host_buffer_destroy(struct wl_client *client,
struct wl_resource *resource) {
wl_resource_destroy(resource);
}
static const struct wl_buffer_interface xwl_buffer_implementation = {
xwl_host_buffer_destroy};
static void xwl_buffer_release(void *data, struct wl_buffer *buffer) {
struct xwl_host_buffer *host = wl_buffer_get_user_data(buffer);
wl_buffer_send_release(host->resource);
}
static const struct wl_buffer_listener xwl_buffer_listener = {
xwl_buffer_release};
static void xwl_destroy_host_buffer(struct wl_resource *resource) {
struct xwl_host_buffer *host = wl_resource_get_user_data(resource);
wl_buffer_destroy(host->proxy);
wl_resource_set_user_data(resource, NULL);
free(host);
}
static void xwl_host_shm_pool_create_host_buffer(struct wl_client *client,
struct wl_resource *resource,
uint32_t id, int32_t offset,
int32_t width, int32_t height,
int32_t stride,
uint32_t format) {
struct xwl_host_shm_pool *host = wl_resource_get_user_data(resource);
struct xwl_host_buffer *host_buffer;
host_buffer = malloc(sizeof(*host_buffer));
assert(host_buffer);
host_buffer->width = width;
host_buffer->height = height;
host_buffer->resource =
wl_resource_create(client, &wl_buffer_interface, 1, id);
wl_resource_set_implementation(host_buffer->resource,
&xwl_buffer_implementation, host_buffer,
xwl_destroy_host_buffer);
host_buffer->proxy = wl_shm_pool_create_buffer(host->proxy, offset, width,
height, stride, format);
wl_buffer_set_user_data(host_buffer->proxy, host_buffer);
wl_buffer_add_listener(host_buffer->proxy, &xwl_buffer_listener, host_buffer);
}
static void xwl_host_shm_pool_destroy(struct wl_client *client,
struct wl_resource *resource) {
wl_resource_destroy(resource);
}
static void xwl_host_shm_pool_resize(struct wl_client *client,
struct wl_resource *resource,
int32_t size) {
struct xwl_host_shm_pool *host = wl_resource_get_user_data(resource);
wl_shm_pool_resize(host->proxy, size);
}
static const struct wl_shm_pool_interface xwl_shm_pool_implementation = {
xwl_host_shm_pool_create_host_buffer, xwl_host_shm_pool_destroy,
xwl_host_shm_pool_resize};
static void xwl_destroy_host_shm_pool(struct wl_resource *resource) {
struct xwl_host_shm_pool *host = wl_resource_get_user_data(resource);
wl_shm_pool_destroy(host->proxy);
wl_resource_set_user_data(resource, NULL);
free(host);
}
static void xwl_shm_create_host_pool(struct wl_client *client,
struct wl_resource *resource, uint32_t id,
int fd, int32_t size) {
struct xwl_host_shm *host = wl_resource_get_user_data(resource);
struct xwl_host_shm_pool *host_shm_pool;
host_shm_pool = malloc(sizeof(*host_shm_pool));
assert(host_shm_pool);
host_shm_pool->resource =
wl_resource_create(client, &wl_shm_pool_interface, 1, id);
wl_resource_set_implementation(host_shm_pool->resource,
&xwl_shm_pool_implementation, host_shm_pool,
xwl_destroy_host_shm_pool);
host_shm_pool->proxy = wl_shm_create_pool(host->proxy, fd, size);
wl_shm_pool_set_user_data(host_shm_pool->proxy, host_shm_pool);
close(fd);
}
static const struct wl_shm_interface xwl_shm_implementation = {
xwl_shm_create_host_pool};
static void xwl_shm_format(void *data, struct wl_shm *shm, uint32_t format) {
struct xwl_host_shm *host = wl_shm_get_user_data(shm);
wl_shm_send_format(host->resource, format);
}
static const struct wl_shm_listener xwl_shm_listener = {xwl_shm_format};
static void xwl_destroy_host_shm(struct wl_resource *resource) {
struct xwl_host_shm *host = wl_resource_get_user_data(resource);
wl_shm_destroy(host->proxy);
wl_resource_set_user_data(resource, NULL);
free(host);
}
static void xwl_bind_host_shm(struct wl_client *client, void *data,
uint32_t version, uint32_t id) {
struct xwl_shm *shm = (struct xwl_shm *)data;
struct xwl_host_shm *host;
host = malloc(sizeof(*host));
assert(host);
host->shm = shm;
host->resource = wl_resource_create(client, &wl_shm_interface, 1, id);
wl_resource_set_implementation(host->resource, &xwl_shm_implementation, host,
xwl_destroy_host_shm);
host->proxy = wl_registry_bind(wl_display_get_registry(shm->xwl->display),
shm->id, &wl_shm_interface,
wl_resource_get_version(host->resource));
wl_shm_set_user_data(host->proxy, host);
wl_shm_add_listener(host->proxy, &xwl_shm_listener, host);
}
static void
xwl_host_shell_get_host_shell_surface(struct wl_client *client,
struct wl_resource *resource, uint32_t id,
struct wl_resource *surface_resource) {
assert(0);
}
static const struct wl_shell_interface xwl_shell_implementation = {
xwl_host_shell_get_host_shell_surface};
static void xwl_destroy_host_shell(struct wl_resource *resource) {
struct xwl_host_shell *host = wl_resource_get_user_data(resource);
wl_shell_destroy(host->proxy);
wl_resource_set_user_data(resource, NULL);
free(host);
}
static void xwl_bind_host_shell(struct wl_client *client, void *data,
uint32_t version, uint32_t id) {
struct xwl_shell *shell = (struct xwl_shell *)data;
struct xwl_host_shell *host;
host = malloc(sizeof(*host));
assert(host);
host->shell = shell;
host->resource = wl_resource_create(client, &wl_shell_interface, 1, id);
wl_resource_set_implementation(host->resource, &xwl_shell_implementation,
host, xwl_destroy_host_shell);
host->proxy = wl_registry_bind(wl_display_get_registry(shell->xwl->display),
shell->id, &wl_shell_interface,
wl_resource_get_version(host->resource));
wl_shell_set_user_data(host->proxy, host);
}
static void xwl_output_geometry(void *data, struct wl_output *output, int x,
int y, int physical_width, int physical_height,
int subpixel, const char *make,
const char *model, int transform) {
struct xwl_host_output *host = wl_output_get_user_data(output);
wl_output_send_geometry(host->resource, x, y, physical_width, physical_height,
subpixel, make, model, transform);
}
static void xwl_output_mode(void *data, struct wl_output *output,
uint32_t flags, int width, int height,
int refresh) {
struct xwl_host_output *host = wl_output_get_user_data(output);
// Wait until scale is known before sending mode.
host->flags = flags;
host->width = width;
host->height = height;
host->refresh = refresh;
}
static void xwl_output_done(void *data, struct wl_output *output) {
struct xwl_host_output *host = wl_output_get_user_data(output);
double scale = host->output->xwl->scale;
if (!host->max_scale)
return;
// Send mode now that scale is known.
wl_output_send_mode(host->resource, host->flags | WL_OUTPUT_MODE_CURRENT,
(scale * host->scale * host->width) / host->max_scale,
(scale * host->scale * host->height) / host->max_scale,
host->refresh);
wl_output_send_scale(host->resource, ceil(host->factor / scale));
wl_output_send_done(host->resource);
host->max_scale = 1.0;
if (host->aura_output)
host->max_scale = 0.0;
}
static void xwl_output_scale(void *data, struct wl_output *output,
int32_t factor) {
struct xwl_host_output *host = wl_output_get_user_data(output);
host->factor = factor;
}
static const struct wl_output_listener xwl_output_listener = {
xwl_output_geometry, xwl_output_mode, xwl_output_done, xwl_output_scale};
static void xwl_aura_output_scale(void *data, struct zaura_output *output,
uint32_t flags, uint32_t scale) {
struct xwl_host_output *host = zaura_output_get_user_data(output);
switch (scale) {
case ZAURA_OUTPUT_SCALE_FACTOR_0500:
case ZAURA_OUTPUT_SCALE_FACTOR_0600:
case ZAURA_OUTPUT_SCALE_FACTOR_0625:
case ZAURA_OUTPUT_SCALE_FACTOR_0750:
case ZAURA_OUTPUT_SCALE_FACTOR_0800:
case ZAURA_OUTPUT_SCALE_FACTOR_1000:
case ZAURA_OUTPUT_SCALE_FACTOR_1125:
case ZAURA_OUTPUT_SCALE_FACTOR_1200:
case ZAURA_OUTPUT_SCALE_FACTOR_1250:
case ZAURA_OUTPUT_SCALE_FACTOR_1500:
case ZAURA_OUTPUT_SCALE_FACTOR_1600:
case ZAURA_OUTPUT_SCALE_FACTOR_2000:
break;
default:
fprintf(stderr, "Warning: Unknown scale factor: %d\n", scale);
break;
}
host->max_scale = MAX(host->max_scale, scale / 1000.0);
if (flags & ZAURA_OUTPUT_SCALE_PROPERTY_CURRENT)
host->scale = scale / 1000.0;
}
static const struct zaura_output_listener xwl_aura_output_listener = {
xwl_aura_output_scale};
static void xwl_destroy_host_output(struct wl_resource *resource) {
struct xwl_host_output *host = wl_resource_get_user_data(resource);
if (host->aura_output)
zaura_output_destroy(host->aura_output);
if (wl_output_get_version(host->proxy) >= WL_OUTPUT_RELEASE_SINCE_VERSION) {
wl_output_release(host->proxy);
} else {
wl_output_destroy(host->proxy);
}
wl_resource_set_user_data(resource, NULL);
free(host);
}
static void xwl_bind_host_output(struct wl_client *client, void *data,
uint32_t version, uint32_t id) {
struct xwl_output *output = (struct xwl_output *)data;
struct xwl *xwl = output->xwl;
struct xwl_host_output *host;
host = malloc(sizeof(*host));
assert(host);
host->output = output;
host->resource = wl_resource_create(client, &wl_output_interface,
MIN(version, output->version), id);
wl_resource_set_implementation(host->resource, NULL, host,
xwl_destroy_host_output);
host->proxy = wl_registry_bind(wl_display_get_registry(xwl->display),
output->id, &wl_output_interface,
wl_resource_get_version(host->resource));
wl_output_set_user_data(host->proxy, host);
wl_output_add_listener(host->proxy, &xwl_output_listener, host);
host->aura_output = NULL;
host->flags = 0;
host->width = 1024;
host->height = 768;
host->refresh = 60000;
host->factor = 1;
host->scale = 1.0;
host->max_scale = 1.0;
if (xwl->aura_shell &&
(xwl->aura_shell->version >= ZAURA_SHELL_GET_AURA_OUTPUT_SINCE_VERSION)) {
host->max_scale = 0.0;
host->aura_output =
zaura_shell_get_aura_output(xwl->aura_shell->internal, host->proxy);
zaura_output_set_user_data(host->aura_output, host);
zaura_output_add_listener(host->aura_output, &xwl_aura_output_listener,
host);
}
}
static void xwl_internal_data_offer_destroy(struct xwl_data_offer *host) {
wl_data_offer_destroy(host->internal);
free(host);
}
static void xwl_set_selection(struct xwl *xwl,
struct xwl_data_offer *data_offer) {
if (xwl->selection_data_offer) {
xwl_internal_data_offer_destroy(xwl->selection_data_offer);
xwl->selection_data_offer = NULL;
}
if (xwl->clipboard_manager) {
if (!data_offer) {
if (xwl->selection_owner == xwl->selection_window)
xcb_set_selection_owner(xwl->connection, XCB_ATOM_NONE,
xwl->atoms[ATOM_CLIPBOARD].value,
xwl->selection_timestamp);
return;
}
xcb_set_selection_owner(xwl->connection, xwl->selection_window,
xwl->atoms[ATOM_CLIPBOARD].value, XCB_CURRENT_TIME);
}
xwl->selection_data_offer = data_offer;
}
static const char *xwl_utf8_mime_type = "text/plain;charset=utf-8";
static void xwl_internal_data_offer_offer(void *data,
struct wl_data_offer *data_offer,
const char *type) {
struct xwl_data_offer *host = data;
if (strcmp(type, xwl_utf8_mime_type) == 0)
host->utf8_text = 1;
}
static void xwl_internal_data_offer_source_actions(
void *data, struct wl_data_offer *data_offer, uint32_t source_actions) {}
static void xwl_internal_data_offer_action(void *data,
struct wl_data_offer *data_offer,
uint32_t dnd_action) {}
static const struct wl_data_offer_listener xwl_internal_data_offer_listener = {
xwl_internal_data_offer_offer, xwl_internal_data_offer_source_actions,
xwl_internal_data_offer_action};
static void
xwl_internal_data_device_data_offer(void *data,
struct wl_data_device *data_device,
struct wl_data_offer *data_offer) {
struct xwl *xwl = (struct xwl *)data;
struct xwl_data_offer *host_data_offer;
host_data_offer = malloc(sizeof(*host_data_offer));
assert(host_data_offer);
host_data_offer->xwl = xwl;
host_data_offer->internal = data_offer;
host_data_offer->utf8_text = 0;
wl_data_offer_add_listener(host_data_offer->internal,
&xwl_internal_data_offer_listener,
host_data_offer);
}
static void xwl_internal_data_device_enter(void *data,
struct wl_data_device *data_device,
uint32_t serial,
struct wl_surface *surface,
wl_fixed_t x, wl_fixed_t y,
struct wl_data_offer *data_offer) {}
static void xwl_internal_data_device_leave(void *data,
struct wl_data_device *data_device) {
}
static void xwl_internal_data_device_motion(void *data,
struct wl_data_device *data_device,
uint32_t time, wl_fixed_t x,
wl_fixed_t y) {}
static void xwl_internal_data_device_drop(void *data,
struct wl_data_device *data_device) {}
static void
xwl_internal_data_device_selection(void *data,
struct wl_data_device *data_device,
struct wl_data_offer *data_offer) {
struct xwl *xwl = (struct xwl *)data;
struct xwl_data_offer *host_data_offer =
data_offer ? wl_data_offer_get_user_data(data_offer) : NULL;
xwl_set_selection(xwl, host_data_offer);
}
static const struct wl_data_device_listener xwl_internal_data_device_listener =
{xwl_internal_data_device_data_offer, xwl_internal_data_device_enter,
xwl_internal_data_device_leave, xwl_internal_data_device_motion,
xwl_internal_data_device_drop, xwl_internal_data_device_selection};
static void xwl_host_pointer_set_cursor(struct wl_client *client,
struct wl_resource *resource,
uint32_t serial,
struct wl_resource *surface_resource,
int32_t hotspot_x, int32_t hotspot_y) {
struct xwl_host_pointer *host = wl_resource_get_user_data(resource);
struct xwl_host_surface *host_surface = NULL;
double scale = host->seat->xwl->scale;
if (surface_resource) {
host_surface = wl_resource_get_user_data(surface_resource);
host_surface->is_cursor = 1;
if (host_surface->contents_width && host_surface->contents_height)
wl_surface_commit(host_surface->proxy);
}
wl_pointer_set_cursor(host->proxy, serial,
host_surface ? host_surface->proxy : NULL,
hotspot_x / scale, hotspot_y / scale);
}
static void xwl_host_pointer_release(struct wl_client *client,
struct wl_resource *resource) {
wl_resource_destroy(resource);
}
static const struct wl_pointer_interface xwl_pointer_implementation = {
xwl_host_pointer_set_cursor, xwl_host_pointer_release};
static void xwl_set_last_event_serial(struct wl_resource *surface_resource,
uint32_t serial) {
struct xwl_host_surface *host_surface =
wl_resource_get_user_data(surface_resource);
host_surface->last_event_serial = serial;
}
static void xwl_pointer_set_focus(struct xwl_host_pointer *host,
uint32_t serial,
struct xwl_host_surface *host_surface,
wl_fixed_t x, wl_fixed_t y) {
struct wl_resource *surface_resource =
host_surface ? host_surface->resource : NULL;
if (surface_resource == host->focus_resource)
return;
if (host->focus_resource)
wl_pointer_send_leave(host->resource, serial, host->focus_resource);
wl_list_remove(&host->focus_resource_listener.link);
wl_list_init(&host->focus_resource_listener.link);
host->focus_resource = surface_resource;
host->focus_serial = serial;
if (surface_resource) {
double scale = host->seat->xwl->scale;
if (host->seat->xwl->xwayland) {
// Make sure focus surface is on top before sending enter event.
xwl_restack_windows(host->seat->xwl,
wl_resource_get_id(surface_resource));
xwl_roundtrip(host->seat->xwl);
}
wl_resource_add_destroy_listener(surface_resource,
&host->focus_resource_listener);
wl_pointer_send_enter(host->resource, serial, surface_resource, x * scale,
y * scale);
}
}
static void xwl_pointer_enter(void *data, struct wl_pointer *pointer,
uint32_t serial, struct wl_surface *surface,
wl_fixed_t x, wl_fixed_t y) {
struct xwl_host_pointer *host = wl_pointer_get_user_data(pointer);
struct xwl_host_surface *host_surface =
surface ? wl_surface_get_user_data(surface) : NULL;
if (!host_surface)
return;
xwl_pointer_set_focus(host, serial, host_surface, x, y);
if (host->focus_resource)
xwl_set_last_event_serial(host->focus_resource, serial);
host->seat->last_serial = serial;
}
static void xwl_pointer_leave(void *data, struct wl_pointer *pointer,
uint32_t serial, struct wl_surface *surface) {
struct xwl_host_pointer *host = wl_pointer_get_user_data(pointer);
xwl_pointer_set_focus(host, serial, NULL, 0, 0);
}
static void xwl_pointer_motion(void *data, struct wl_pointer *pointer,
uint32_t time, wl_fixed_t x, wl_fixed_t y) {
struct xwl_host_pointer *host = wl_pointer_get_user_data(pointer);
double scale = host->seat->xwl->scale;
wl_pointer_send_motion(host->resource, time, x * scale, y * scale);
}
static void xwl_pointer_button(void *data, struct wl_pointer *pointer,
uint32_t serial, uint32_t time, uint32_t button,
uint32_t state) {
struct xwl_host_pointer *host = wl_pointer_get_user_data(pointer);
wl_pointer_send_button(host->resource, serial, time, button, state);
if (host->focus_resource)
xwl_set_last_event_serial(host->focus_resource, serial);
host->seat->last_serial = serial;
}
static void xwl_pointer_axis(void *data, struct wl_pointer *pointer,
uint32_t time, uint32_t axis, wl_fixed_t value) {
struct xwl_host_pointer *host = wl_pointer_get_user_data(pointer);
double scale = host->seat->xwl->scale;
wl_pointer_send_axis(host->resource, time, axis, value * scale);
}
static void xwl_pointer_frame(void *data, struct wl_pointer *pointer) {
struct xwl_host_pointer *host = wl_pointer_get_user_data(pointer);
wl_pointer_send_frame(host->resource);
}
void xwl_pointer_axis_source(void *data, struct wl_pointer *pointer,
uint32_t axis_source) {
struct xwl_host_pointer *host = wl_pointer_get_user_data(pointer);
wl_pointer_send_axis_source(host->resource, axis_source);
}
static void xwl_pointer_axis_stop(void *data, struct wl_pointer *pointer,
uint32_t time, uint32_t axis) {
struct xwl_host_pointer *host = wl_pointer_get_user_data(pointer);
wl_pointer_send_axis_stop(host->resource, time, axis);
}
static void xwl_pointer_axis_discrete(void *data, struct wl_pointer *pointer,
uint32_t axis, int32_t discrete) {
struct xwl_host_pointer *host = wl_pointer_get_user_data(pointer);
wl_pointer_send_axis_discrete(host->resource, axis, discrete);
}
static const struct wl_pointer_listener xwl_pointer_listener = {
xwl_pointer_enter, xwl_pointer_leave, xwl_pointer_motion,
xwl_pointer_button, xwl_pointer_axis, xwl_pointer_frame,
xwl_pointer_axis_source, xwl_pointer_axis_stop, xwl_pointer_axis_discrete};
static void xwl_host_keyboard_release(struct wl_client *client,
struct wl_resource *resource) {
wl_resource_destroy(resource);
}
static const struct wl_keyboard_interface xwl_keyboard_implementation = {
xwl_host_keyboard_release};
static void xwl_keyboard_keymap(void *data, struct wl_keyboard *keyboard,
uint32_t format, int32_t fd, uint32_t size) {
struct xwl_host_keyboard *host = wl_keyboard_get_user_data(keyboard);
wl_keyboard_send_keymap(host->resource, format, fd, size);
close(fd);
}
static void xwl_keyboard_set_focus(struct xwl_host_keyboard *host,
uint32_t serial,
struct xwl_host_surface *host_surface,
struct wl_array *keys) {
struct wl_resource *surface_resource =
host_surface ? host_surface->resource : NULL;
if (surface_resource == host->focus_resource)
return;
if (host->focus_resource)
wl_keyboard_send_leave(host->resource, serial, host->focus_resource);
wl_list_remove(&host->focus_resource_listener.link);
wl_list_init(&host->focus_resource_listener.link);
host->focus_resource = surface_resource;
host->focus_serial = serial;
if (surface_resource) {
wl_resource_add_destroy_listener(surface_resource,
&host->focus_resource_listener);
wl_keyboard_send_enter(host->resource, serial, surface_resource, keys);
}
host->seat->last_serial = serial;
}
static void xwl_keyboard_enter(void *data, struct wl_keyboard *keyboard,
uint32_t serial, struct wl_surface *surface,
struct wl_array *keys) {
struct xwl_host_keyboard *host = wl_keyboard_get_user_data(keyboard);
struct xwl_host_surface *host_surface =
surface ? wl_surface_get_user_data(surface) : NULL;
if (!host_surface)
return;
xwl_keyboard_set_focus(host, serial, host_surface, keys);
host->seat->last_serial = serial;
}
static void xwl_keyboard_leave(void *data, struct wl_keyboard *keyboard,
uint32_t serial, struct wl_surface *surface) {
struct xwl_host_keyboard *host = wl_keyboard_get_user_data(keyboard);
xwl_keyboard_set_focus(host, serial, NULL, NULL);
}
static void xwl_keyboard_key(void *data, struct wl_keyboard *keyboard,
uint32_t serial, uint32_t time, uint32_t key,
uint32_t state) {
struct xwl_host_keyboard *host = wl_keyboard_get_user_data(keyboard);
wl_keyboard_send_key(host->resource, serial, time, key, state);
if (host->focus_resource)
xwl_set_last_event_serial(host->focus_resource, serial);
host->seat->last_serial = serial;
}
static void xwl_keyboard_modifiers(void *data, struct wl_keyboard *keyboard,
uint32_t serial, uint32_t mods_depressed,
uint32_t mods_latched, uint32_t mods_locked,
uint32_t group) {
struct xwl_host_keyboard *host = wl_keyboard_get_user_data(keyboard);
wl_keyboard_send_modifiers(host->resource, serial, mods_depressed,
mods_latched, mods_locked, group);
if (host->focus_resource)
xwl_set_last_event_serial(host->focus_resource, serial);
host->seat->last_serial = serial;
}
static void xwl_keyboard_repeat_info(void *data, struct wl_keyboard *keyboard,
int32_t rate, int32_t delay) {
struct xwl_host_keyboard *host = wl_keyboard_get_user_data(keyboard);
wl_keyboard_send_repeat_info(host->resource, rate, delay);
}
static const struct wl_keyboard_listener xwl_keyboard_listener = {
xwl_keyboard_keymap, xwl_keyboard_enter, xwl_keyboard_leave,
xwl_keyboard_key, xwl_keyboard_modifiers, xwl_keyboard_repeat_info};
static void xwl_host_touch_release(struct wl_client *client,
struct wl_resource *resource) {
wl_resource_destroy(resource);
}
static const struct wl_touch_interface xwl_touch_implementation = {
xwl_host_touch_release};
static void xwl_host_touch_down(void *data, struct wl_touch *touch,
uint32_t serial, uint32_t time,
struct wl_surface *surface, int32_t id,
wl_fixed_t x, wl_fixed_t y) {
struct xwl_host_touch *host = wl_touch_get_user_data(touch);
struct xwl_host_surface *host_surface =
surface ? wl_surface_get_user_data(surface) : NULL;
double scale = host->seat->xwl->scale;
if (!host_surface)
return;
if (host_surface->resource != host->focus_resource) {
wl_list_remove(&host->focus_resource_listener.link);
wl_list_init(&host->focus_resource_listener.link);
host->focus_resource = host_surface->resource;
wl_resource_add_destroy_listener(host_surface->resource,
&host->focus_resource_listener);
}
if (host->seat->xwl->xwayland) {
// Make sure focus surface is on top before sending down event.
xwl_restack_windows(host->seat->xwl,
wl_resource_get_id(host_surface->resource));
xwl_roundtrip(host->seat->xwl);
}
wl_touch_send_down(host->resource, serial, time, host_surface->resource, id,
x * scale, y * scale);
if (host->focus_resource)
xwl_set_last_event_serial(host->focus_resource, serial);
host->seat->last_serial = serial;
}
static void xwl_host_touch_up(void *data, struct wl_touch *touch,
uint32_t serial, uint32_t time, int32_t id) {
struct xwl_host_touch *host = wl_touch_get_user_data(touch);
wl_list_remove(&host->focus_resource_listener.link);
wl_list_init(&host->focus_resource_listener.link);
host->focus_resource = NULL;
wl_touch_send_up(host->resource, serial, time, id);
if (host->focus_resource)
xwl_set_last_event_serial(host->focus_resource, serial);
host->seat->last_serial = serial;
}
static void xwl_host_touch_motion(void *data, struct wl_touch *touch,
uint32_t time, int32_t id, wl_fixed_t x,
wl_fixed_t y) {
struct xwl_host_touch *host = wl_touch_get_user_data(touch);
double scale = host->seat->xwl->scale;
wl_touch_send_motion(host->resource, time, id, x * scale, y * scale);
}
static void xwl_host_touch_frame(void *data, struct wl_touch *touch) {
struct xwl_host_touch *host = wl_touch_get_user_data(touch);
wl_touch_send_frame(host->resource);
}
static void xwl_host_touch_cancel(void *data, struct wl_touch *touch) {
struct xwl_host_touch *host = wl_touch_get_user_data(touch);
wl_touch_send_cancel(host->resource);
}
static const struct wl_touch_listener xwl_touch_listener = {
xwl_host_touch_down, xwl_host_touch_up, xwl_host_touch_motion,
xwl_host_touch_frame, xwl_host_touch_cancel};
static void xwl_destroy_host_pointer(struct wl_resource *resource) {
struct xwl_host_pointer *host = wl_resource_get_user_data(resource);
if (wl_pointer_get_version(host->proxy) >= WL_POINTER_RELEASE_SINCE_VERSION) {
wl_pointer_release(host->proxy);
} else {
wl_pointer_destroy(host->proxy);
}
wl_list_remove(&host->focus_resource_listener.link);
wl_resource_set_user_data(resource, NULL);
free(host);
}
static void xwl_pointer_focus_resource_destroyed(struct wl_listener *listener,
void *data) {
struct xwl_host_pointer *host;
host = wl_container_of(listener, host, focus_resource_listener);
xwl_pointer_set_focus(host, host->focus_serial, NULL, 0, 0);
}
static void xwl_host_seat_get_host_pointer(struct wl_client *client,
struct wl_resource *resource,
uint32_t id) {
struct xwl_host_seat *host = wl_resource_get_user_data(resource);
struct xwl_host_pointer *host_pointer;
host_pointer = malloc(sizeof(*host_pointer));
assert(host_pointer);
host_pointer->seat = host->seat;
host_pointer->resource = wl_resource_create(
client, &wl_pointer_interface, wl_resource_get_version(resource), id);
wl_resource_set_implementation(host_pointer->resource,
&xwl_pointer_implementation, host_pointer,
xwl_destroy_host_pointer);
host_pointer->proxy = wl_seat_get_pointer(host->proxy);
wl_pointer_set_user_data(host_pointer->proxy, host_pointer);
wl_pointer_add_listener(host_pointer->proxy, &xwl_pointer_listener,
host_pointer);
wl_list_init(&host_pointer->focus_resource_listener.link);
host_pointer->focus_resource_listener.notify =
xwl_pointer_focus_resource_destroyed;
host_pointer->focus_resource = NULL;
host_pointer->focus_serial = 0;
}
static void xwl_destroy_host_keyboard(struct wl_resource *resource) {
struct xwl_host_keyboard *host = wl_resource_get_user_data(resource);
if (wl_keyboard_get_version(host->proxy) >=
WL_KEYBOARD_RELEASE_SINCE_VERSION) {
wl_keyboard_release(host->proxy);
} else {
wl_keyboard_destroy(host->proxy);
}
wl_list_remove(&host->focus_resource_listener.link);
wl_resource_set_user_data(resource, NULL);
free(host);
}
static void xwl_keyboard_focus_resource_destroyed(struct wl_listener *listener,
void *data) {
struct xwl_host_keyboard *host;
host = wl_container_of(listener, host, focus_resource_listener);
xwl_keyboard_set_focus(host, host->focus_serial, NULL, NULL);
}
static void xwl_host_seat_get_host_keyboard(struct wl_client *client,
struct wl_resource *resource,
uint32_t id) {
struct xwl_host_seat *host = wl_resource_get_user_data(resource);
struct xwl_host_keyboard *host_keyboard;
host_keyboard = malloc(sizeof(*host_keyboard));
assert(host_keyboard);
host_keyboard->seat = host->seat;
host_keyboard->resource = wl_resource_create(
client, &wl_keyboard_interface, wl_resource_get_version(resource), id);
wl_resource_set_implementation(host_keyboard->resource,
&xwl_keyboard_implementation, host_keyboard,
xwl_destroy_host_keyboard);
host_keyboard->proxy = wl_seat_get_keyboard(host->proxy);
wl_keyboard_set_user_data(host_keyboard->proxy, host_keyboard);
wl_keyboard_add_listener(host_keyboard->proxy, &xwl_keyboard_listener,
host_keyboard);
wl_list_init(&host_keyboard->focus_resource_listener.link);
host_keyboard->focus_resource_listener.notify =
xwl_keyboard_focus_resource_destroyed;
host_keyboard->focus_resource = NULL;
host_keyboard->focus_serial = 0;
}
static void xwl_destroy_host_touch(struct wl_resource *resource) {
struct xwl_host_touch *host = wl_resource_get_user_data(resource);
if (wl_touch_get_version(host->proxy) >= WL_TOUCH_RELEASE_SINCE_VERSION) {
wl_touch_release(host->proxy);
} else {
wl_touch_destroy(host->proxy);
}
wl_resource_set_user_data(resource, NULL);
free(host);
}
static void xwl_touch_focus_resource_destroyed(struct wl_listener *listener,
void *data) {
struct xwl_host_touch *host;
host = wl_container_of(listener, host, focus_resource_listener);
wl_list_remove(&host->focus_resource_listener.link);
wl_list_init(&host->focus_resource_listener.link);
host->focus_resource = NULL;
}
static void xwl_host_seat_get_host_touch(struct wl_client *client,
struct wl_resource *resource,
uint32_t id) {
struct xwl_host_seat *host = wl_resource_get_user_data(resource);
struct xwl_host_touch *host_touch;
host_touch = malloc(sizeof(*host_touch));
assert(host_touch);
host_touch->seat = host->seat;
host_touch->resource = wl_resource_create(
client, &wl_touch_interface, wl_resource_get_version(resource), id);
wl_resource_set_implementation(host_touch->resource,
&xwl_touch_implementation, host_touch,
xwl_destroy_host_touch);
host_touch->proxy = wl_seat_get_touch(host->proxy);
wl_touch_set_user_data(host_touch->proxy, host_touch);
wl_touch_add_listener(host_touch->proxy, &xwl_touch_listener, host_touch);
wl_list_init(&host_touch->focus_resource_listener.link);
host_touch->focus_resource_listener.notify =
xwl_touch_focus_resource_destroyed;
host_touch->focus_resource = NULL;
}
static void xwl_host_seat_release(struct wl_client *client,
struct wl_resource *resource) {
struct xwl_host_seat *host = wl_resource_get_user_data(resource);
wl_seat_release(host->proxy);
}
static const struct wl_seat_interface xwl_seat_implementation = {
xwl_host_seat_get_host_pointer, xwl_host_seat_get_host_keyboard,
xwl_host_seat_get_host_touch, xwl_host_seat_release};
static void xwl_seat_capabilities(void *data, struct wl_seat *seat,
uint32_t capabilities) {
struct xwl_host_seat *host = wl_seat_get_user_data(seat);
wl_seat_send_capabilities(host->resource, capabilities);
}
static void xwl_seat_name(void *data, struct wl_seat *seat, const char *name) {
struct xwl_host_seat *host = wl_seat_get_user_data(seat);
if (wl_resource_get_version(host->resource) >= WL_SEAT_NAME_SINCE_VERSION)
wl_seat_send_name(host->resource, name);
}
static const struct wl_seat_listener xwl_seat_listener = {xwl_seat_capabilities,
xwl_seat_name};
static void xwl_destroy_host_seat(struct wl_resource *resource) {
struct xwl_host_seat *host = wl_resource_get_user_data(resource);
if (host->seat->xwl->default_seat == host)
host->seat->xwl->default_seat = NULL;
if (wl_seat_get_version(host->proxy) >= WL_SEAT_RELEASE_SINCE_VERSION)
wl_seat_release(host->proxy);
else
wl_seat_destroy(host->proxy);
wl_resource_set_user_data(resource, NULL);
free(host);
}
static void xwl_bind_host_seat(struct wl_client *client, void *data,
uint32_t version, uint32_t id) {
struct xwl_seat *seat = (struct xwl_seat *)data;
struct xwl_host_seat *host;
host = malloc(sizeof(*host));
assert(host);
host->seat = seat;
host->resource = wl_resource_create(client, &wl_seat_interface,
MIN(version, seat->version), id);
wl_resource_set_implementation(host->resource, &xwl_seat_implementation, host,
xwl_destroy_host_seat);
host->proxy = wl_registry_bind(wl_display_get_registry(seat->xwl->display),
seat->id, &wl_seat_interface,
wl_resource_get_version(host->resource));
wl_seat_set_user_data(host->proxy, host);
wl_seat_add_listener(host->proxy, &xwl_seat_listener, host);
if (!seat->xwl->default_seat) {
seat->xwl->default_seat = host;
if (seat->xwl->data_device_manager &&
seat->xwl->data_device_manager->internal) {
seat->xwl->selection_data_device = wl_data_device_manager_get_data_device(
seat->xwl->data_device_manager->internal, host->proxy);
wl_data_device_add_listener(seat->xwl->selection_data_device,
&xwl_internal_data_device_listener,
seat->xwl);
}
}
}
static void xwl_drm_authenticate(struct wl_client *client,
struct wl_resource *resource, uint32_t id) {}
static void xwl_drm_create_buffer(struct wl_client *client,
struct wl_resource *resource, uint32_t id,
uint32_t name, int32_t width, int32_t height,
uint32_t stride, uint32_t format) {
assert(0);
}
static void xwl_drm_create_planar_buffer(
struct wl_client *client, struct wl_resource *resource, uint32_t id,
uint32_t name, int32_t width, int32_t height, uint32_t format,
int32_t offset0, int32_t stride0, int32_t offset1, int32_t stride1,
int32_t offset2, int32_t stride2) {
assert(0);
}
static void xwl_drm_create_prime_buffer(
struct wl_client *client, struct wl_resource *resource, uint32_t id,
int32_t name, int32_t width, int32_t height, uint32_t format,
int32_t offset0, int32_t stride0, int32_t offset1, int32_t stride1,
int32_t offset2, int32_t stride2) {
struct xwl_host_drm *host = wl_resource_get_user_data(resource);
struct xwl_host_buffer *host_buffer;
struct zwp_linux_buffer_params_v1 *buffer_params;
assert(name >= 0);
assert(!offset1);
assert(!stride1);
assert(!offset2);
assert(!stride2);
host_buffer = malloc(sizeof(*host_buffer));
assert(host_buffer);
host_buffer->width = width;
host_buffer->height = height;
host_buffer->resource =
wl_resource_create(client, &wl_buffer_interface, 1, id);
wl_resource_set_implementation(host_buffer->resource,
&xwl_buffer_implementation, host_buffer,
xwl_destroy_host_buffer);
buffer_params =
zwp_linux_dmabuf_v1_create_params(host->linux_dmabuf->internal);
zwp_linux_buffer_params_v1_add(buffer_params, name, 0, offset0, stride0, 0,
0);
host_buffer->proxy = zwp_linux_buffer_params_v1_create_immed(
buffer_params, width, height, format, 0);
zwp_linux_buffer_params_v1_destroy(buffer_params);
close(name);
wl_buffer_set_user_data(host_buffer->proxy, host_buffer);
wl_buffer_add_listener(host_buffer->proxy, &xwl_buffer_listener, host_buffer);
}
static const struct wl_drm_interface xwl_drm_implementation = {
xwl_drm_authenticate, xwl_drm_create_buffer, xwl_drm_create_planar_buffer,
xwl_drm_create_prime_buffer};
static void xwl_destroy_host_drm(struct wl_resource *resource) {
struct xwl_host_drm *host = wl_resource_get_user_data(resource);
wl_resource_set_user_data(resource, NULL);
free(host);
}
static void xwl_bind_host_drm(struct wl_client *client, void *data,
uint32_t version, uint32_t id) {
struct xwl_linux_dmabuf *linux_dmabuf = (struct xwl_linux_dmabuf *)data;
struct xwl_host_drm *host;
host = malloc(sizeof(*host));
assert(host);
host->linux_dmabuf = linux_dmabuf;
host->version = MIN(version, 2);
host->resource =
wl_resource_create(client, &wl_drm_interface, host->version, id);
wl_resource_set_implementation(host->resource, &xwl_drm_implementation, host,
xwl_destroy_host_drm);
wl_drm_send_device(host->resource, linux_dmabuf->xwl->drm_device);
wl_drm_send_format(host->resource, WL_DRM_FORMAT_ARGB8888);
wl_drm_send_format(host->resource, WL_DRM_FORMAT_XRGB8888);
wl_drm_send_format(host->resource, WL_DRM_FORMAT_RGB565);
if (host->version >= WL_DRM_CREATE_PRIME_BUFFER_SINCE_VERSION)
wl_drm_send_capabilities(host->resource, WL_DRM_CAPABILITY_PRIME);
}
static void xwl_xdg_positioner_destroy(struct wl_client *client,
struct wl_resource *resource) {
wl_resource_destroy(resource);
}
static void xwl_xdg_positioner_set_size(struct wl_client *client,
struct wl_resource *resource,
int32_t width, int32_t height) {
struct xwl_host_xdg_positioner *host = wl_resource_get_user_data(resource);
double scale = host->xwl->scale;
zxdg_positioner_v6_set_size(host->proxy, width / scale, height / scale);
}
static void xwl_xdg_positioner_set_anchor_rect(struct wl_client *client,
struct wl_resource *resource,
int32_t x, int32_t y,
int32_t width, int32_t height) {
struct xwl_host_xdg_positioner *host = wl_resource_get_user_data(resource);
double scale = host->xwl->scale;
int32_t x1, y1, x2, y2;
x1 = x / scale;
y1 = y / scale;
x2 = (x + width) / scale;
y2 = (y + height) / scale;
zxdg_positioner_v6_set_anchor_rect(host->proxy, x1, y1, x2 - x1, y2 - y1);
}
static void xwl_xdg_positioner_set_anchor(struct wl_client *client,
struct wl_resource *resource,
uint32_t anchor) {
struct xwl_host_xdg_positioner *host = wl_resource_get_user_data(resource);
zxdg_positioner_v6_set_anchor(host->proxy, anchor);
}
static void xwl_xdg_positioner_set_gravity(struct wl_client *client,
struct wl_resource *resource,
uint32_t gravity) {
struct xwl_host_xdg_positioner *host = wl_resource_get_user_data(resource);
zxdg_positioner_v6_set_gravity(host->proxy, gravity);
}
static void
xwl_xdg_positioner_set_constraint_adjustment(struct wl_client *client,
struct wl_resource *resource,
uint32_t constraint_adjustment) {
struct xwl_host_xdg_positioner *host = wl_resource_get_user_data(resource);
zxdg_positioner_v6_set_constraint_adjustment(host->proxy,
constraint_adjustment);
}
static void xwl_xdg_positioner_set_offset(struct wl_client *client,
struct wl_resource *resource,
int32_t x, int32_t y) {
struct xwl_host_xdg_positioner *host = wl_resource_get_user_data(resource);
double scale = host->xwl->scale;
zxdg_positioner_v6_set_offset(host->proxy, x / scale, y / scale);
}
static const struct zxdg_positioner_v6_interface
xwl_xdg_positioner_implementation = {
xwl_xdg_positioner_destroy,
xwl_xdg_positioner_set_size,
xwl_xdg_positioner_set_anchor_rect,
xwl_xdg_positioner_set_anchor,
xwl_xdg_positioner_set_gravity,
xwl_xdg_positioner_set_constraint_adjustment,
xwl_xdg_positioner_set_offset};
static void xwl_destroy_host_xdg_positioner(struct wl_resource *resource) {
struct xwl_host_xdg_positioner *host = wl_resource_get_user_data(resource);
zxdg_positioner_v6_destroy(host->proxy);
wl_resource_set_user_data(resource, NULL);
free(host);
}
static void xwl_xdg_popup_destroy(struct wl_client *client,
struct wl_resource *resource) {
wl_resource_destroy(resource);
}
static void xwl_xdg_popup_grab(struct wl_client *client,
struct wl_resource *resource,
struct wl_resource *seat_resource,
uint32_t serial) {
struct xwl_host_xdg_popup *host = wl_resource_get_user_data(resource);
struct xwl_host_seat *host_seat = wl_resource_get_user_data(seat_resource);
zxdg_popup_v6_grab(host->proxy, host_seat->proxy, serial);
}
static const struct zxdg_popup_v6_interface xwl_xdg_popup_implementation = {
xwl_xdg_popup_destroy, xwl_xdg_popup_grab};
static void xwl_xdg_popup_configure(void *data, struct zxdg_popup_v6 *xdg_popup,
int32_t x, int32_t y, int32_t width,
int32_t height) {
struct xwl_host_xdg_popup *host = zxdg_popup_v6_get_user_data(xdg_popup);
double scale = host->xwl->scale;
int32_t x1, y1, x2, y2;
x1 = x * scale;
y1 = y * scale;
x2 = (x + width) * scale;
y2 = (y + height) * scale;
zxdg_popup_v6_send_configure(host->resource, x1, y1, x2 - x1, y2 - y1);
}
static void xwl_xdg_popup_popup_done(void *data,
struct zxdg_popup_v6 *xdg_popup) {
struct xwl_host_xdg_popup *host = zxdg_popup_v6_get_user_data(xdg_popup);
zxdg_popup_v6_send_popup_done(host->resource);
}
static const struct zxdg_popup_v6_listener xwl_xdg_popup_listener = {
xwl_xdg_popup_configure, xwl_xdg_popup_popup_done};
static void xwl_destroy_host_xdg_popup(struct wl_resource *resource) {
struct xwl_host_xdg_popup *host = wl_resource_get_user_data(resource);
zxdg_popup_v6_destroy(host->proxy);
wl_resource_set_user_data(resource, NULL);
free(host);
}
static void xwl_xdg_toplevel_destroy(struct wl_client *client,
struct wl_resource *resource) {
wl_resource_destroy(resource);
}
static void xwl_xdg_toplevel_set_parent(struct wl_client *client,
struct wl_resource *resource,
struct wl_resource *parent_resource) {
struct xwl_host_xdg_toplevel *host = wl_resource_get_user_data(resource);
struct xwl_host_xdg_toplevel *host_parent =
parent_resource ? wl_resource_get_user_data(parent_resource) : NULL;
zxdg_toplevel_v6_set_parent(host->proxy,
host_parent ? host_parent->proxy : NULL);
}
static void xwl_xdg_toplevel_set_title(struct wl_client *client,
struct wl_resource *resource,
const char *title) {
struct xwl_host_xdg_toplevel *host = wl_resource_get_user_data(resource);
zxdg_toplevel_v6_set_title(host->proxy, title);
}
static void xwl_xdg_toplevel_set_app_id(struct wl_client *client,
struct wl_resource *resource,
const char *app_id) {
struct xwl_host_xdg_toplevel *host = wl_resource_get_user_data(resource);
zxdg_toplevel_v6_set_app_id(host->proxy, app_id);
}
static void xwl_xdg_toplevel_show_window_menu(struct wl_client *client,
struct wl_resource *resource,
struct wl_resource *seat,
uint32_t serial, int32_t x,
int32_t y) {
assert(0);
}
static void xwl_xdg_toplevel_move(struct wl_client *client,
struct wl_resource *resource,
struct wl_resource *seat_resource,
uint32_t serial) {
struct xwl_host_xdg_toplevel *host = wl_resource_get_user_data(resource);
struct xwl_host_seat *host_seat =
seat_resource ? wl_resource_get_user_data(seat_resource) : NULL;
zxdg_toplevel_v6_move(host->proxy, host_seat ? host_seat->proxy : NULL,
serial);
}
static void xwl_xdg_toplevel_resize(struct wl_client *client,
struct wl_resource *resource,
struct wl_resource *seat_resource,
uint32_t serial, uint32_t edges) {
struct xwl_host_xdg_toplevel *host = wl_resource_get_user_data(resource);
struct xwl_host_seat *host_seat =
seat_resource ? wl_resource_get_user_data(seat_resource) : NULL;
zxdg_toplevel_v6_resize(host->proxy, host_seat ? host_seat->proxy : NULL,
serial, edges);
}
static void xwl_xdg_toplevel_set_max_size(struct wl_client *client,
struct wl_resource *resource,
int32_t width, int32_t height) {
struct xwl_host_xdg_toplevel *host