mirror of
https://github.com/hyprwm/wlroots-hyprland.git
synced 2024-11-26 14:45:58 +01:00
Merge remote-tracking branch 'origin/master' into hidpi
This commit is contained in:
commit
86b8729998
48 changed files with 499 additions and 198 deletions
|
@ -6,6 +6,7 @@ packages:
|
|||
- mesa
|
||||
- libinput
|
||||
- libxkbcommon
|
||||
- xcb-util-image
|
||||
- libcap
|
||||
- pixman
|
||||
- clang
|
||||
|
|
|
@ -16,6 +16,7 @@ arch:
|
|||
- libinput
|
||||
- pixman
|
||||
- libxkbcommon
|
||||
- xcb-util-image
|
||||
- libcap
|
||||
script:
|
||||
- "meson build"
|
||||
|
|
|
@ -29,8 +29,8 @@ static void wlr_drm_backend_destroy(struct wlr_backend *backend) {
|
|||
|
||||
wlr_drm_restore_outputs(drm);
|
||||
|
||||
struct wlr_drm_connector *conn;
|
||||
wl_list_for_each(conn, &drm->outputs, link) {
|
||||
struct wlr_drm_connector *conn, *next;
|
||||
wl_list_for_each_safe(conn, next, &drm->outputs, link) {
|
||||
wlr_output_destroy(&conn->output);
|
||||
}
|
||||
|
||||
|
|
|
@ -533,13 +533,14 @@ static bool wlr_drm_connector_set_cursor(struct wlr_output *output,
|
|||
return false;
|
||||
}
|
||||
|
||||
if (!wlr_drm_surface_init(&plane->surf, renderer, w, h, GBM_FORMAT_ARGB8888, 0)) {
|
||||
if (!wlr_drm_surface_init(&plane->surf, renderer, w, h,
|
||||
GBM_FORMAT_ARGB8888, 0)) {
|
||||
wlr_log(L_ERROR, "Cannot allocate cursor resources");
|
||||
return false;
|
||||
}
|
||||
|
||||
plane->cursor_bo = gbm_bo_create(renderer->gbm, w, h, GBM_FORMAT_ARGB8888,
|
||||
GBM_BO_USE_CURSOR | GBM_BO_USE_WRITE);
|
||||
plane->cursor_bo = gbm_bo_create(renderer->gbm, w, h,
|
||||
GBM_FORMAT_ARGB8888, GBM_BO_USE_CURSOR | GBM_BO_USE_WRITE);
|
||||
if (!plane->cursor_bo) {
|
||||
wlr_log_errno(L_ERROR, "Failed to create cursor bo");
|
||||
return false;
|
||||
|
@ -552,45 +553,26 @@ static bool wlr_drm_connector_set_cursor(struct wlr_output *output,
|
|||
|
||||
// TODO the image needs to be rotated depending on the output rotation
|
||||
|
||||
plane->wlr_tex = wlr_render_texture_create(plane->surf.renderer->wlr_rend);
|
||||
plane->wlr_tex =
|
||||
wlr_render_texture_create(plane->surf.renderer->wlr_rend);
|
||||
if (!plane->wlr_tex) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
switch (output->transform) {
|
||||
case WL_OUTPUT_TRANSFORM_90:
|
||||
plane->cursor_hotspot_x = hotspot_x;
|
||||
plane->cursor_hotspot_y = -plane->surf.height + hotspot_y;
|
||||
break;
|
||||
case WL_OUTPUT_TRANSFORM_180:
|
||||
plane->cursor_hotspot_x = plane->surf.width - hotspot_x;
|
||||
plane->cursor_hotspot_y = plane->surf.height - hotspot_y;
|
||||
break;
|
||||
case WL_OUTPUT_TRANSFORM_270:
|
||||
plane->cursor_hotspot_x = -plane->surf.height + hotspot_x;
|
||||
plane->cursor_hotspot_y = hotspot_y;
|
||||
break;
|
||||
case WL_OUTPUT_TRANSFORM_FLIPPED:
|
||||
plane->cursor_hotspot_x = plane->surf.width - hotspot_x;
|
||||
plane->cursor_hotspot_y = hotspot_y;
|
||||
break;
|
||||
case WL_OUTPUT_TRANSFORM_FLIPPED_90:
|
||||
plane->cursor_hotspot_x = hotspot_x;
|
||||
plane->cursor_hotspot_y = -hotspot_y;
|
||||
break;
|
||||
case WL_OUTPUT_TRANSFORM_FLIPPED_180:
|
||||
plane->cursor_hotspot_x = hotspot_x;
|
||||
plane->cursor_hotspot_y = plane->surf.height - hotspot_y;
|
||||
break;
|
||||
case WL_OUTPUT_TRANSFORM_FLIPPED_270:
|
||||
plane->cursor_hotspot_x = -plane->surf.height + hotspot_x;
|
||||
plane->cursor_hotspot_y = plane->surf.width - hotspot_y;
|
||||
break;
|
||||
default: // WL_OUTPUT_TRANSFORM_NORMAL
|
||||
plane->cursor_hotspot_x = hotspot_x;
|
||||
plane->cursor_hotspot_y = hotspot_y;
|
||||
}
|
||||
struct wlr_box hotspot = {
|
||||
.width = plane->surf.width,
|
||||
.height = plane->surf.height,
|
||||
.x = hotspot_x,
|
||||
.y = hotspot_y,
|
||||
};
|
||||
enum wl_output_transform transform =
|
||||
wlr_output_transform_invert(output->transform);
|
||||
struct wlr_box transformed_hotspot;
|
||||
wlr_output_transform_apply_to_box(transform, &hotspot,
|
||||
&transformed_hotspot);
|
||||
plane->cursor_hotspot_x = transformed_hotspot.x;
|
||||
plane->cursor_hotspot_y = transformed_hotspot.y;
|
||||
|
||||
if (!update_pixels) {
|
||||
// Only update the cursor hotspot
|
||||
|
@ -620,11 +602,13 @@ static bool wlr_drm_connector_set_cursor(struct wlr_output *output,
|
|||
|
||||
float matrix[16];
|
||||
wlr_texture_get_matrix(plane->wlr_tex, &matrix, &plane->matrix, 0, 0);
|
||||
wlr_render_with_matrix(plane->surf.renderer->wlr_rend, plane->wlr_tex, &matrix);
|
||||
wlr_render_with_matrix(plane->surf.renderer->wlr_rend, plane->wlr_tex,
|
||||
&matrix);
|
||||
|
||||
glFinish();
|
||||
glPixelStorei(GL_UNPACK_ROW_LENGTH_EXT, bo_stride);
|
||||
glReadPixels(0, 0, plane->surf.width, plane->surf.height, GL_BGRA_EXT, GL_UNSIGNED_BYTE, bo_data);
|
||||
glReadPixels(0, 0, plane->surf.width, plane->surf.height, GL_BGRA_EXT,
|
||||
GL_UNSIGNED_BYTE, bo_data);
|
||||
glPixelStorei(GL_UNPACK_ROW_LENGTH_EXT, 0);
|
||||
|
||||
wlr_drm_surface_swap_buffers(&plane->surf);
|
||||
|
@ -638,41 +622,30 @@ static bool wlr_drm_connector_move_cursor(struct wlr_output *output,
|
|||
int x, int y) {
|
||||
struct wlr_drm_connector *conn = (struct wlr_drm_connector *)output;
|
||||
struct wlr_drm_backend *drm = (struct wlr_drm_backend *)output->backend;
|
||||
|
||||
struct wlr_drm_plane *plane = conn->crtc->cursor;
|
||||
x -= plane->cursor_hotspot_x;
|
||||
y -= plane->cursor_hotspot_y;
|
||||
|
||||
int width, height, tmp;
|
||||
wlr_output_effective_resolution(output, &width, &height);
|
||||
struct wlr_box box;
|
||||
box.x = x;
|
||||
box.y = y;
|
||||
wlr_output_effective_resolution(output, &box.width, &box.height);
|
||||
|
||||
switch (output->transform) {
|
||||
case WL_OUTPUT_TRANSFORM_NORMAL:
|
||||
case WL_OUTPUT_TRANSFORM_FLIPPED:
|
||||
case WL_OUTPUT_TRANSFORM_FLIPPED_180:
|
||||
// nothing to do
|
||||
break;
|
||||
case WL_OUTPUT_TRANSFORM_270:
|
||||
case WL_OUTPUT_TRANSFORM_FLIPPED_270:
|
||||
tmp = x;
|
||||
x = y;
|
||||
y = -(tmp - width);
|
||||
break;
|
||||
case WL_OUTPUT_TRANSFORM_90:
|
||||
case WL_OUTPUT_TRANSFORM_FLIPPED_90:
|
||||
tmp = x;
|
||||
x = -(y - height);
|
||||
y = tmp;
|
||||
break;
|
||||
}
|
||||
enum wl_output_transform transform =
|
||||
wlr_output_transform_invert(output->transform);
|
||||
struct wlr_box transformed_box;
|
||||
wlr_output_transform_apply_to_box(transform, &box, &transformed_box);
|
||||
|
||||
return drm->iface->crtc_move_cursor(drm, conn->crtc, x, y);
|
||||
transformed_box.x -= plane->cursor_hotspot_x;
|
||||
transformed_box.y -= plane->cursor_hotspot_y;
|
||||
|
||||
return drm->iface->crtc_move_cursor(drm, conn->crtc, transformed_box.x,
|
||||
transformed_box.y);
|
||||
}
|
||||
|
||||
static void wlr_drm_connector_destroy(struct wlr_output *output) {
|
||||
struct wlr_drm_connector *conn = (struct wlr_drm_connector *)output;
|
||||
wlr_drm_connector_cleanup(conn);
|
||||
wl_event_source_remove(conn->retry_pageflip);
|
||||
wl_list_remove(&conn->link);
|
||||
free(conn);
|
||||
}
|
||||
|
||||
|
@ -851,6 +824,7 @@ void wlr_drm_scan_connectors(struct wlr_drm_backend *drm) {
|
|||
|
||||
drmModeFreeCrtc(conn->old_crtc);
|
||||
wl_event_source_remove(conn->retry_pageflip);
|
||||
wl_list_remove(&conn->link);
|
||||
free(conn);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -99,13 +99,13 @@ static void wlr_libinput_backend_destroy(struct wlr_backend *_backend) {
|
|||
}
|
||||
struct wlr_libinput_backend *backend = (struct wlr_libinput_backend *)_backend;
|
||||
for (size_t i = 0; i < backend->wlr_device_lists->length; i++) {
|
||||
struct wlr_list *wlr_devices = backend->wlr_device_lists->items[i];
|
||||
for (size_t j = 0; j < wlr_devices->length; j++) {
|
||||
struct wlr_input_device *wlr_dev = wlr_devices->items[j];
|
||||
struct wl_list *wlr_devices = backend->wlr_device_lists->items[i];
|
||||
struct wlr_input_device *wlr_dev, *next;
|
||||
wl_list_for_each_safe(wlr_dev, next, wlr_devices, link) {
|
||||
wl_signal_emit(&backend->backend.events.input_remove, wlr_dev);
|
||||
wlr_input_device_destroy(wlr_dev);
|
||||
}
|
||||
wlr_list_free(wlr_devices);
|
||||
free(wlr_devices);
|
||||
}
|
||||
wlr_list_free(backend->wlr_device_lists);
|
||||
wl_event_source_remove(backend->input_event);
|
||||
|
|
|
@ -26,6 +26,7 @@ struct wlr_input_device *get_appropriate_device(
|
|||
static void wlr_libinput_device_destroy(struct wlr_input_device *_dev) {
|
||||
struct wlr_libinput_input_device *dev = (struct wlr_libinput_input_device *)_dev;
|
||||
libinput_device_unref(dev->handle);
|
||||
wl_list_remove(&dev->wlr_input_device.link);
|
||||
free(dev);
|
||||
}
|
||||
|
||||
|
|
|
@ -30,8 +30,8 @@ static bool multi_backend_start(struct wlr_backend *_backend) {
|
|||
|
||||
static void multi_backend_destroy(struct wlr_backend *_backend) {
|
||||
struct wlr_multi_backend *backend = (struct wlr_multi_backend *)_backend;
|
||||
struct subbackend_state *sub;
|
||||
wl_list_for_each(sub, &backend->backends, link) {
|
||||
struct subbackend_state *sub, *next;
|
||||
wl_list_for_each_safe(sub, next, &backend->backends, link) {
|
||||
wlr_backend_destroy(sub->backend);
|
||||
free(sub);
|
||||
}
|
||||
|
|
|
@ -59,6 +59,7 @@ static bool wlr_wl_output_set_cursor(struct wlr_output *_output,
|
|||
(struct wlr_wl_backend_output *)_output;
|
||||
struct wlr_wl_backend *backend = output->backend;
|
||||
|
||||
// TODO: use output->wlr_output.transform to transform pixels and hotpot
|
||||
output->cursor.hotspot_x = hotspot_x;
|
||||
output->cursor.hotspot_y = hotspot_y;
|
||||
|
||||
|
|
|
@ -42,21 +42,30 @@ static void pointer_handle_motion(void *data, struct wl_pointer *wl_pointer,
|
|||
uint32_t time, wl_fixed_t surface_x, wl_fixed_t surface_y) {
|
||||
struct wlr_input_device *dev = data;
|
||||
assert(dev && dev->pointer);
|
||||
struct wlr_wl_pointer *wlr_wl_pointer = (struct wlr_wl_pointer *)dev->pointer;
|
||||
struct wlr_wl_pointer *wlr_wl_pointer =
|
||||
(struct wlr_wl_pointer *)dev->pointer;
|
||||
if (!wlr_wl_pointer->current_output) {
|
||||
wlr_log(L_ERROR, "pointer motion event without current output");
|
||||
return;
|
||||
}
|
||||
int width, height;
|
||||
|
||||
struct wlr_box box;
|
||||
wl_egl_window_get_attached_size(wlr_wl_pointer->current_output->egl_window,
|
||||
&width, &height);
|
||||
&box.width, &box.height);
|
||||
box.x = wl_fixed_to_int(surface_x);
|
||||
box.y = wl_fixed_to_int(surface_y);
|
||||
struct wlr_box transformed;
|
||||
wlr_output_transform_apply_to_box(
|
||||
wlr_wl_pointer->current_output->wlr_output.transform, &box,
|
||||
&transformed);
|
||||
|
||||
struct wlr_event_pointer_motion_absolute wlr_event;
|
||||
wlr_event.device = dev;
|
||||
wlr_event.time_msec = time;
|
||||
wlr_event.width_mm = width;
|
||||
wlr_event.height_mm = height;
|
||||
wlr_event.x_mm = wl_fixed_to_double(surface_x);
|
||||
wlr_event.y_mm = wl_fixed_to_double(surface_y);
|
||||
wlr_event.width_mm = transformed.width;
|
||||
wlr_event.height_mm = transformed.height;
|
||||
wlr_event.x_mm = transformed.x;
|
||||
wlr_event.y_mm = transformed.y;
|
||||
wl_signal_emit(&dev->pointer->events.motion_absolute, &wlr_event);
|
||||
}
|
||||
|
||||
|
|
|
@ -1,7 +1,8 @@
|
|||
lib_shared = static_library(
|
||||
'shared',
|
||||
['shared.c', 'cat.c', 'ini.c', 'config.c'],
|
||||
['support/shared.c', 'support/cat.c', 'support/ini.c', 'support/config.c'],
|
||||
dependencies: wlroots,
|
||||
include_directories: include_directories('support')
|
||||
)
|
||||
|
||||
executable('simple', 'simple.c', dependencies: wlroots, link_with: lib_shared)
|
||||
|
|
|
@ -22,9 +22,9 @@
|
|||
#include <wlr/types/wlr_cursor.h>
|
||||
#include <wlr/util/log.h>
|
||||
#include <wlr/types/wlr_list.h>
|
||||
#include "shared.h"
|
||||
#include "config.h"
|
||||
#include "cat.h"
|
||||
#include "support/shared.h"
|
||||
#include "support/config.h"
|
||||
#include "support/cat.h"
|
||||
|
||||
struct sample_state;
|
||||
|
||||
|
|
|
@ -21,9 +21,9 @@
|
|||
#include <wlr/types/wlr_output.h>
|
||||
#include <wlr/types/wlr_keyboard.h>
|
||||
#include <math.h>
|
||||
#include "shared.h"
|
||||
#include "config.h"
|
||||
#include "cat.h"
|
||||
#include "support/shared.h"
|
||||
#include "support/config.h"
|
||||
#include "support/cat.h"
|
||||
|
||||
struct sample_state {
|
||||
struct example_config *config;
|
||||
|
|
|
@ -22,9 +22,9 @@
|
|||
#include <wlr/types/wlr_cursor.h>
|
||||
#include <wlr/util/log.h>
|
||||
#include <wlr/types/wlr_list.h>
|
||||
#include "shared.h"
|
||||
#include "config.h"
|
||||
#include "cat.h"
|
||||
#include "support/shared.h"
|
||||
#include "support/config.h"
|
||||
#include "support/cat.h"
|
||||
|
||||
struct sample_state {
|
||||
struct compositor_state *compositor;
|
||||
|
|
|
@ -18,9 +18,9 @@
|
|||
#include <wlr/types/wlr_keyboard.h>
|
||||
#include <wlr/util/log.h>
|
||||
#include <math.h>
|
||||
#include "shared.h"
|
||||
#include "config.h"
|
||||
#include "cat.h"
|
||||
#include "support/shared.h"
|
||||
#include "support/config.h"
|
||||
#include "support/cat.h"
|
||||
|
||||
struct sample_state {
|
||||
struct example_config *config;
|
||||
|
|
|
@ -11,7 +11,7 @@
|
|||
#include <wlr/types/wlr_output.h>
|
||||
#include <wlr/util/log.h>
|
||||
#include <xkbcommon/xkbcommon.h>
|
||||
#include "shared.h"
|
||||
#include "support/shared.h"
|
||||
|
||||
struct sample_state {
|
||||
float color[3];
|
||||
|
|
2
examples/support/README
Normal file
2
examples/support/README
Normal file
|
@ -0,0 +1,2 @@
|
|||
Support code for the examples. Code that's not relevant to the principle each
|
||||
example demonstrates is largely offloaded to this directory.
|
|
@ -19,8 +19,8 @@
|
|||
#include <wlr/types/wlr_tablet_pad.h>
|
||||
#include <wlr/util/log.h>
|
||||
#include <math.h>
|
||||
#include "shared.h"
|
||||
#include "cat.h"
|
||||
#include "support/shared.h"
|
||||
#include "support/cat.h"
|
||||
|
||||
struct sample_state {
|
||||
struct wlr_renderer *renderer;
|
||||
|
|
|
@ -18,8 +18,8 @@
|
|||
#include <wlr/backend/session.h>
|
||||
#include <wlr/types/wlr_list.h>
|
||||
#include <wlr/util/log.h>
|
||||
#include "shared.h"
|
||||
#include "cat.h"
|
||||
#include "support/shared.h"
|
||||
#include "support/cat.h"
|
||||
|
||||
struct sample_state {
|
||||
struct wlr_renderer *renderer;
|
||||
|
|
|
@ -2,6 +2,7 @@
|
|||
#define WLR_INTERFACES_WLR_OUTPUT_H
|
||||
|
||||
#include <stdbool.h>
|
||||
#include <wlr/types/wlr_box.h>
|
||||
#include <wlr/types/wlr_output.h>
|
||||
#include <wlr/backend.h>
|
||||
|
||||
|
@ -31,4 +32,8 @@ struct wl_global *wlr_output_create_global(struct wlr_output *wlr_output,
|
|||
struct wl_display *display);
|
||||
void wlr_output_destroy_global(struct wlr_output *wlr_output);
|
||||
|
||||
void wlr_output_transform_apply_to_box(enum wl_output_transform transform,
|
||||
struct wlr_box *box, struct wlr_box *dest);
|
||||
enum wl_output_transform wlr_output_transform_invert(enum wl_output_transform);
|
||||
|
||||
#endif
|
||||
|
|
|
@ -1,9 +1,9 @@
|
|||
#ifndef WLR_TYPES_WLR_OUTPUT_H
|
||||
#define WLR_TYPES_WLR_OUTPUT_H
|
||||
|
||||
#include <stdbool.h>
|
||||
#include <wayland-util.h>
|
||||
#include <wayland-server.h>
|
||||
#include <stdbool.h>
|
||||
|
||||
struct wlr_output_mode {
|
||||
uint32_t flags; // enum wl_output_mode
|
||||
|
@ -15,10 +15,12 @@ struct wlr_output_mode {
|
|||
struct wlr_output_cursor {
|
||||
struct wlr_output *output;
|
||||
int32_t x, y;
|
||||
bool enabled;
|
||||
uint32_t width, height;
|
||||
int32_t hotspot_x, hotspot_y;
|
||||
struct wl_list link;
|
||||
|
||||
// only when using a software cursor without a surface
|
||||
struct wlr_renderer *renderer;
|
||||
struct wlr_texture *texture;
|
||||
|
||||
|
@ -44,8 +46,9 @@ struct wlr_output {
|
|||
uint32_t scale;
|
||||
int32_t width, height;
|
||||
int32_t phys_width, phys_height; // mm
|
||||
int32_t subpixel; // enum wl_output_subpixel
|
||||
int32_t transform; // enum wl_output_transform
|
||||
enum wl_output_subpixel subpixel;
|
||||
enum wl_output_transform transform;
|
||||
bool needs_swap;
|
||||
|
||||
float transform_matrix[16];
|
||||
|
||||
|
|
|
@ -142,6 +142,7 @@ struct wlr_seat {
|
|||
struct wlr_seat_pointer_request_set_cursor_event {
|
||||
struct wlr_seat_client *seat_client;
|
||||
struct wlr_surface *surface;
|
||||
uint32_t serial;
|
||||
int32_t hotspot_x, hotspot_y;
|
||||
};
|
||||
|
||||
|
|
|
@ -12,6 +12,7 @@
|
|||
#endif
|
||||
|
||||
struct wlr_xwm;
|
||||
struct wlr_xwayland_cursor;
|
||||
|
||||
struct wlr_xwayland {
|
||||
pid_t pid;
|
||||
|
@ -25,6 +26,7 @@ struct wlr_xwayland {
|
|||
struct wl_event_source *sigusr1_source;
|
||||
struct wl_listener destroy_listener;
|
||||
struct wlr_xwm *xwm;
|
||||
struct wlr_xwayland_cursor *cursor;
|
||||
|
||||
struct {
|
||||
struct wl_signal new_surface;
|
||||
|
@ -148,6 +150,10 @@ struct wlr_xwayland *wlr_xwayland_create(struct wl_display *wl_display,
|
|||
|
||||
void wlr_xwayland_destroy(struct wlr_xwayland *wlr_xwayland);
|
||||
|
||||
void wlr_xwayland_set_cursor(struct wlr_xwayland *wlr_xwayland,
|
||||
uint8_t *pixels, uint32_t stride, uint32_t width, uint32_t height,
|
||||
int32_t hotspot_x, int32_t hotspot_y);
|
||||
|
||||
void wlr_xwayland_surface_activate(struct wlr_xwayland *wlr_xwayland,
|
||||
struct wlr_xwayland_surface *surface, bool activated);
|
||||
|
||||
|
|
|
@ -52,6 +52,8 @@ pixman = dependency('pixman-1')
|
|||
xcb = dependency('xcb')
|
||||
xcb_composite = dependency('xcb-composite')
|
||||
xcb_xfixes = dependency('xcb-xfixes')
|
||||
xcb_image = dependency('xcb-image')
|
||||
xcb_render = dependency('xcb-render')
|
||||
xcb_icccm = dependency('xcb-icccm', required: false)
|
||||
x11_xcb = dependency('x11-xcb')
|
||||
libcap = dependency('libcap', required: false)
|
||||
|
|
|
@ -232,7 +232,9 @@ static int config_ini_handler(void *user, const char *section, const char *name,
|
|||
oc->scale = strtol(value, NULL, 10);
|
||||
assert(oc->scale >= 1);
|
||||
} else if (strcmp(name, "rotate") == 0) {
|
||||
if (strcmp(value, "90") == 0) {
|
||||
if (strcmp(value, "normal") == 0) {
|
||||
oc->transform = WL_OUTPUT_TRANSFORM_NORMAL;
|
||||
} else if (strcmp(value, "90") == 0) {
|
||||
oc->transform = WL_OUTPUT_TRANSFORM_90;
|
||||
} else if (strcmp(value, "180") == 0) {
|
||||
oc->transform = WL_OUTPUT_TRANSFORM_180;
|
||||
|
|
|
@ -4,6 +4,7 @@
|
|||
#include <wlr/types/wlr_cursor.h>
|
||||
#include <wlr/util/log.h>
|
||||
#include <wlr/xcursor.h>
|
||||
#include <wlr/xwayland.h>
|
||||
#include "rootston/server.h"
|
||||
#include "rootston/config.h"
|
||||
#include "rootston/input.h"
|
||||
|
@ -96,6 +97,14 @@ struct roots_input *input_create(struct roots_server *server,
|
|||
return NULL;
|
||||
}
|
||||
|
||||
if (server->desktop->xwayland != NULL) {
|
||||
struct wlr_xcursor_image *xcursor_image = xcursor->images[0];
|
||||
wlr_xwayland_set_cursor(server->desktop->xwayland,
|
||||
xcursor_image->buffer, xcursor_image->width, xcursor_image->width,
|
||||
xcursor_image->height, xcursor_image->hotspot_x,
|
||||
xcursor_image->hotspot_y);
|
||||
}
|
||||
|
||||
input->wl_seat = wlr_seat_create(server->wl_display, "seat0");
|
||||
if (input->wl_seat == NULL) {
|
||||
wlr_log(L_ERROR, "Cannot create seat");
|
||||
|
|
|
@ -13,10 +13,21 @@ static void destroy_surface_listener(struct wl_listener *listener, void *data) {
|
|||
static void wl_compositor_create_surface(struct wl_client *client,
|
||||
struct wl_resource *resource, uint32_t id) {
|
||||
struct wlr_compositor *compositor = wl_resource_get_user_data(resource);
|
||||
|
||||
struct wl_resource *surface_resource = wl_resource_create(client,
|
||||
&wl_surface_interface, wl_resource_get_version(resource), id);
|
||||
if (surface_resource == NULL) {
|
||||
wl_resource_post_no_memory(resource);
|
||||
return;
|
||||
}
|
||||
|
||||
struct wlr_surface *surface = wlr_surface_create(surface_resource,
|
||||
compositor->renderer);
|
||||
if (surface == NULL) {
|
||||
wl_resource_destroy(surface_resource);
|
||||
wl_resource_post_no_memory(resource);
|
||||
return;
|
||||
}
|
||||
surface->compositor_data = compositor;
|
||||
surface->compositor_listener.notify = &destroy_surface_listener;
|
||||
wl_resource_add_destroy_listener(surface_resource,
|
||||
|
@ -49,13 +60,17 @@ static void wl_compositor_destroy(struct wl_resource *resource) {
|
|||
}
|
||||
}
|
||||
|
||||
static void wl_compositor_bind(struct wl_client *wl_client, void *_compositor,
|
||||
static void wl_compositor_bind(struct wl_client *wl_client, void *data,
|
||||
uint32_t version, uint32_t id) {
|
||||
struct wlr_compositor *compositor = _compositor;
|
||||
struct wlr_compositor *compositor = data;
|
||||
assert(wl_client && compositor);
|
||||
|
||||
struct wl_resource *wl_resource =
|
||||
wl_resource_create(wl_client, &wl_compositor_interface, version, id);
|
||||
if (wl_resource == NULL) {
|
||||
wl_client_post_no_memory(wl_client);
|
||||
return;
|
||||
}
|
||||
wl_resource_set_implementation(wl_resource, &wl_compositor_impl,
|
||||
compositor, wl_compositor_destroy);
|
||||
wl_list_insert(&compositor->wl_resources,
|
||||
|
|
|
@ -233,6 +233,9 @@ static struct wlr_data_offer *wlr_data_source_send_offer(
|
|||
struct wlr_data_source *source,
|
||||
struct wl_resource *target) {
|
||||
struct wlr_data_offer *offer = calloc(1, sizeof(struct wlr_data_offer));
|
||||
if (offer == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
offer->resource =
|
||||
wl_resource_create(wl_resource_get_client(target),
|
||||
|
@ -781,9 +784,7 @@ data_device_manager_impl = {
|
|||
|
||||
static void data_device_manager_bind(struct wl_client *client,
|
||||
void *data, uint32_t version, uint32_t id) {
|
||||
struct wl_resource *resource;
|
||||
|
||||
resource = wl_resource_create(client,
|
||||
struct wl_resource *resource = wl_resource_create(client,
|
||||
&wl_data_device_manager_interface,
|
||||
version, id);
|
||||
if (resource == NULL) {
|
||||
|
@ -791,8 +792,8 @@ static void data_device_manager_bind(struct wl_client *client,
|
|||
return;
|
||||
}
|
||||
|
||||
wl_resource_set_implementation(resource,
|
||||
&data_device_manager_impl, NULL, NULL);
|
||||
wl_resource_set_implementation(resource, &data_device_manager_impl,
|
||||
NULL, NULL);
|
||||
}
|
||||
|
||||
struct wlr_data_device_manager *wlr_data_device_manager_create(
|
||||
|
@ -807,7 +808,6 @@ struct wlr_data_device_manager *wlr_data_device_manager_create(
|
|||
manager->global =
|
||||
wl_global_create(display, &wl_data_device_manager_interface,
|
||||
3, NULL, data_device_manager_bind);
|
||||
|
||||
if (!manager->global) {
|
||||
wlr_log(L_ERROR, "could not create data device manager wl global");
|
||||
free(manager);
|
||||
|
|
|
@ -83,8 +83,8 @@ static void gamma_control_manager_get_gamma_control(struct wl_client *client,
|
|||
gamma_control->resource = wl_resource_create(client,
|
||||
&gamma_control_interface, version, id);
|
||||
if (gamma_control->resource == NULL) {
|
||||
wl_client_post_no_memory(client);
|
||||
free(gamma_control);
|
||||
wl_client_post_no_memory(client);
|
||||
return;
|
||||
}
|
||||
wlr_log(L_DEBUG, "new gamma_control %p (res %p)", gamma_control,
|
||||
|
@ -109,10 +109,9 @@ static struct gamma_control_manager_interface gamma_control_manager_impl = {
|
|||
.get_gamma_control = gamma_control_manager_get_gamma_control,
|
||||
};
|
||||
|
||||
static void gamma_control_manager_bind(struct wl_client *client,
|
||||
void *_gamma_control_manager, uint32_t version, uint32_t id) {
|
||||
struct wlr_gamma_control_manager *gamma_control_manager =
|
||||
_gamma_control_manager;
|
||||
static void gamma_control_manager_bind(struct wl_client *client, void *data,
|
||||
uint32_t version, uint32_t id) {
|
||||
struct wlr_gamma_control_manager *gamma_control_manager = data;
|
||||
assert(client && gamma_control_manager);
|
||||
|
||||
struct wl_resource *resource = wl_resource_create(client,
|
||||
|
|
|
@ -91,13 +91,17 @@ static struct wl_output_interface wl_output_impl = {
|
|||
.release = wl_output_release
|
||||
};
|
||||
|
||||
static void wl_output_bind(struct wl_client *wl_client, void *_wlr_output,
|
||||
static void wl_output_bind(struct wl_client *wl_client, void *data,
|
||||
uint32_t version, uint32_t id) {
|
||||
struct wlr_output *wlr_output = _wlr_output;
|
||||
struct wlr_output *wlr_output = data;
|
||||
assert(wl_client && wlr_output);
|
||||
|
||||
struct wl_resource *wl_resource = wl_resource_create(wl_client,
|
||||
&wl_output_interface, version, id);
|
||||
if (wl_resource == NULL) {
|
||||
wl_client_post_no_memory(wl_client);
|
||||
return;
|
||||
}
|
||||
wl_resource_set_implementation(wl_resource, &wl_output_impl, wlr_output,
|
||||
wl_output_destroy);
|
||||
wl_list_insert(&wlr_output->wl_resources,
|
||||
|
@ -254,10 +258,6 @@ static void output_cursor_render(struct wlr_output_cursor *cursor) {
|
|||
struct wlr_texture *texture = cursor->texture;
|
||||
struct wlr_renderer *renderer = cursor->renderer;
|
||||
if (cursor->surface != NULL) {
|
||||
// Some clients commit a cursor surface with a NULL buffer to hide it.
|
||||
if (!wlr_surface_has_buffer(cursor->surface)) {
|
||||
return;
|
||||
}
|
||||
texture = cursor->surface->texture;
|
||||
renderer = cursor->surface->renderer;
|
||||
}
|
||||
|
@ -268,8 +268,8 @@ static void output_cursor_render(struct wlr_output_cursor *cursor) {
|
|||
|
||||
struct wlr_box output_box;
|
||||
output_box.x = output_box.y = 0;
|
||||
output_box.width = cursor->output->width;
|
||||
output_box.height = cursor->output->height;
|
||||
wlr_output_effective_resolution(cursor->output, &output_box.width,
|
||||
&output_box.height);
|
||||
|
||||
struct wlr_box cursor_box;
|
||||
output_cursor_get_box(cursor, &cursor_box);
|
||||
|
@ -284,25 +284,32 @@ static void output_cursor_render(struct wlr_output_cursor *cursor) {
|
|||
glEnable(GL_BLEND);
|
||||
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
|
||||
|
||||
int x = cursor->x - cursor->hotspot_x;
|
||||
int y = cursor->y - cursor->hotspot_y;
|
||||
if (cursor->surface != NULL) {
|
||||
x += cursor->surface->current->sx;
|
||||
y += cursor->surface->current->sy;
|
||||
}
|
||||
|
||||
float matrix[16];
|
||||
wlr_texture_get_matrix(texture, &matrix,
|
||||
&cursor->output->transform_matrix, cursor->x - cursor->hotspot_x,
|
||||
cursor->y - cursor->hotspot_y);
|
||||
wlr_texture_get_matrix(texture, &matrix, &cursor->output->transform_matrix,
|
||||
x, y);
|
||||
wlr_render_with_matrix(renderer, texture, &matrix);
|
||||
}
|
||||
|
||||
void wlr_output_swap_buffers(struct wlr_output *output) {
|
||||
wl_signal_emit(&output->events.swap_buffers, &output);
|
||||
|
||||
struct wlr_output_cursor *cursor;
|
||||
wl_list_for_each(cursor, &output->cursors, link) {
|
||||
if (output->hardware_cursor == cursor) {
|
||||
if (!cursor->enabled || output->hardware_cursor == cursor) {
|
||||
continue;
|
||||
}
|
||||
output_cursor_render(cursor);
|
||||
}
|
||||
|
||||
wl_signal_emit(&output->events.swap_buffers, &output);
|
||||
|
||||
output->impl->swap_buffers(output);
|
||||
output->needs_swap = false;
|
||||
}
|
||||
|
||||
void wlr_output_set_gamma(struct wlr_output *output,
|
||||
|
@ -320,6 +327,9 @@ uint32_t wlr_output_get_gamma_size(struct wlr_output *output) {
|
|||
}
|
||||
|
||||
static void output_cursor_reset(struct wlr_output_cursor *cursor) {
|
||||
if (cursor->output->hardware_cursor != cursor) {
|
||||
cursor->output->needs_swap = true;
|
||||
}
|
||||
if (cursor->surface != NULL) {
|
||||
wl_list_remove(&cursor->surface_commit.link);
|
||||
wl_list_remove(&cursor->surface_destroy.link);
|
||||
|
@ -348,6 +358,12 @@ bool wlr_output_cursor_set_image(struct wlr_output_cursor *cursor,
|
|||
}
|
||||
|
||||
wlr_log(L_INFO, "Falling back to software cursor");
|
||||
cursor->output->needs_swap = true;
|
||||
|
||||
cursor->enabled = pixels != NULL;
|
||||
if (!cursor->enabled) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (cursor->renderer == NULL) {
|
||||
cursor->renderer = wlr_gles2_renderer_create(cursor->output->backend);
|
||||
|
@ -368,10 +384,16 @@ bool wlr_output_cursor_set_image(struct wlr_output_cursor *cursor,
|
|||
}
|
||||
|
||||
static void output_cursor_commit(struct wlr_output_cursor *cursor) {
|
||||
// Some clients commit a cursor surface with a NULL buffer to hide it.
|
||||
cursor->enabled = wlr_surface_has_buffer(cursor->surface);
|
||||
cursor->width = cursor->surface->current->width;
|
||||
cursor->height = cursor->surface->current->height;
|
||||
|
||||
// TODO: if hardware cursor, upload pixels
|
||||
if (cursor->output->hardware_cursor != cursor) {
|
||||
cursor->output->needs_swap = true;
|
||||
} else {
|
||||
// TODO: upload pixels
|
||||
}
|
||||
}
|
||||
|
||||
static inline int64_t timespec_to_msec(const struct timespec *a) {
|
||||
|
@ -410,10 +432,6 @@ void wlr_output_cursor_set_surface(struct wlr_output_cursor *cursor,
|
|||
return;
|
||||
}
|
||||
|
||||
if (surface) {
|
||||
cursor->width = surface->current->width;
|
||||
cursor->height = surface->current->height;
|
||||
}
|
||||
cursor->hotspot_x = hotspot_x;
|
||||
cursor->hotspot_y = hotspot_y;
|
||||
|
||||
|
@ -446,6 +464,10 @@ void wlr_output_cursor_set_surface(struct wlr_output_cursor *cursor,
|
|||
wl_signal_add(&surface->events.destroy, &cursor->surface_destroy);
|
||||
output_cursor_commit(cursor);
|
||||
} else {
|
||||
cursor->enabled = false;
|
||||
cursor->width = 0;
|
||||
cursor->height = 0;
|
||||
|
||||
// TODO: if hardware cursor, disable cursor
|
||||
}
|
||||
}
|
||||
|
@ -457,6 +479,7 @@ bool wlr_output_cursor_move(struct wlr_output_cursor *cursor, int x, int y) {
|
|||
cursor->y = y;
|
||||
|
||||
if (cursor->output->hardware_cursor != cursor) {
|
||||
cursor->output->needs_swap = true;
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -503,3 +526,58 @@ void wlr_output_cursor_destroy(struct wlr_output_cursor *cursor) {
|
|||
wl_list_remove(&cursor->link);
|
||||
free(cursor);
|
||||
}
|
||||
|
||||
void wlr_output_transform_apply_to_box(enum wl_output_transform transform,
|
||||
struct wlr_box *box, struct wlr_box *dest) {
|
||||
if (transform % 2 == 0) {
|
||||
dest->width = box->width;
|
||||
dest->height = box->height;
|
||||
} else {
|
||||
dest->width = box->height;
|
||||
dest->height = box->width;
|
||||
}
|
||||
|
||||
switch (transform) {
|
||||
case WL_OUTPUT_TRANSFORM_NORMAL:
|
||||
dest->x = box->x;
|
||||
dest->y = box->y;
|
||||
break;
|
||||
case WL_OUTPUT_TRANSFORM_90:
|
||||
dest->x = box->y;
|
||||
dest->y = box->width - box->x;
|
||||
break;
|
||||
case WL_OUTPUT_TRANSFORM_180:
|
||||
dest->x = box->width - box->x;
|
||||
dest->y = box->height - box->y;
|
||||
break;
|
||||
case WL_OUTPUT_TRANSFORM_270:
|
||||
dest->x = box->height - box->y;
|
||||
dest->y = box->x;
|
||||
break;
|
||||
case WL_OUTPUT_TRANSFORM_FLIPPED:
|
||||
dest->x = box->width - box->x;
|
||||
dest->y = box->y;
|
||||
break;
|
||||
case WL_OUTPUT_TRANSFORM_FLIPPED_90:
|
||||
dest->x = box->y;
|
||||
dest->y = box->x;
|
||||
break;
|
||||
case WL_OUTPUT_TRANSFORM_FLIPPED_180:
|
||||
dest->x = box->x;
|
||||
dest->y = box->height - box->y;
|
||||
break;
|
||||
case WL_OUTPUT_TRANSFORM_FLIPPED_270:
|
||||
dest->x = box->height - box->y;
|
||||
dest->y = box->width - box->x;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
enum wl_output_transform wlr_output_transform_invert(
|
||||
enum wl_output_transform transform) {
|
||||
if ((transform & WL_OUTPUT_TRANSFORM_90) &&
|
||||
!(transform & WL_OUTPUT_TRANSFORM_FLIPPED)) {
|
||||
transform ^= WL_OUTPUT_TRANSFORM_180;
|
||||
}
|
||||
return transform;
|
||||
}
|
||||
|
|
|
@ -51,16 +51,17 @@ static void output_frame_notify(struct wl_listener *listener, void *_data) {
|
|||
}
|
||||
|
||||
static void screenshooter_shoot(struct wl_client *client,
|
||||
struct wl_resource *_screenshooter, uint32_t id,
|
||||
struct wl_resource *_output, struct wl_resource *_buffer) {
|
||||
struct wl_resource *screenshooter_resource, uint32_t id,
|
||||
struct wl_resource *output_resource,
|
||||
struct wl_resource *buffer_resource) {
|
||||
struct wlr_screenshooter *screenshooter =
|
||||
wl_resource_get_user_data(_screenshooter);
|
||||
struct wlr_output *output = wl_resource_get_user_data(_output);
|
||||
if (!wl_shm_buffer_get(_buffer)) {
|
||||
wl_resource_get_user_data(screenshooter_resource);
|
||||
struct wlr_output *output = wl_resource_get_user_data(output_resource);
|
||||
if (!wl_shm_buffer_get(buffer_resource)) {
|
||||
wlr_log(L_ERROR, "Invalid buffer: not a shared memory buffer");
|
||||
return;
|
||||
}
|
||||
struct wl_shm_buffer *shm_buffer = wl_shm_buffer_get(_buffer);
|
||||
struct wl_shm_buffer *shm_buffer = wl_shm_buffer_get(buffer_resource);
|
||||
int32_t width = wl_shm_buffer_get_width(shm_buffer);
|
||||
int32_t height = wl_shm_buffer_get_height(shm_buffer);
|
||||
int32_t stride = wl_shm_buffer_get_stride(shm_buffer);
|
||||
|
@ -84,23 +85,31 @@ static void screenshooter_shoot(struct wl_client *client,
|
|||
struct wlr_screenshot *screenshot =
|
||||
calloc(1, sizeof(struct wlr_screenshot));
|
||||
if (!screenshot) {
|
||||
wl_client_post_no_memory(client);
|
||||
wl_resource_post_no_memory(screenshooter_resource);
|
||||
return;
|
||||
}
|
||||
screenshot->output_resource = _output;
|
||||
screenshot->output_resource = output_resource;
|
||||
screenshot->output = output;
|
||||
screenshot->screenshooter = screenshooter;
|
||||
screenshot->resource = wl_resource_create(client,
|
||||
&orbital_screenshot_interface, wl_resource_get_version(_screenshooter),
|
||||
id);
|
||||
wlr_log(L_DEBUG, "new screenshot %p (res %p)", screenshot,
|
||||
screenshot->resource);
|
||||
&orbital_screenshot_interface,
|
||||
wl_resource_get_version(screenshooter_resource), id);
|
||||
if (screenshot->resource == NULL) {
|
||||
free(screenshot);
|
||||
wl_resource_post_no_memory(screenshooter_resource);
|
||||
return;
|
||||
}
|
||||
wl_resource_set_implementation(screenshot->resource, NULL, screenshot,
|
||||
NULL);
|
||||
|
||||
wlr_log(L_DEBUG, "new screenshot %p (res %p)", screenshot,
|
||||
screenshot->resource);
|
||||
|
||||
struct screenshot_state *state = calloc(1, sizeof(struct screenshot_state));
|
||||
if (!state) {
|
||||
wl_client_post_no_memory(client);
|
||||
wl_resource_destroy(screenshot->resource);
|
||||
free(screenshot);
|
||||
wl_resource_post_no_memory(screenshooter_resource);
|
||||
return;
|
||||
}
|
||||
state->width = width;
|
||||
|
@ -117,13 +126,17 @@ static struct orbital_screenshooter_interface screenshooter_impl = {
|
|||
.shoot = screenshooter_shoot,
|
||||
};
|
||||
|
||||
static void screenshooter_bind(struct wl_client *wl_client,
|
||||
void *_screenshooter, uint32_t version, uint32_t id) {
|
||||
struct wlr_screenshooter *screenshooter = _screenshooter;
|
||||
static void screenshooter_bind(struct wl_client *wl_client, void *data,
|
||||
uint32_t version, uint32_t id) {
|
||||
struct wlr_screenshooter *screenshooter = data;
|
||||
assert(wl_client && screenshooter);
|
||||
|
||||
struct wl_resource *wl_resource = wl_resource_create(wl_client,
|
||||
&orbital_screenshooter_interface, version, id);
|
||||
if (wl_resource == NULL) {
|
||||
wl_client_post_no_memory(wl_client);
|
||||
return;
|
||||
}
|
||||
wl_resource_set_implementation(wl_resource, &screenshooter_impl,
|
||||
screenshooter, NULL);
|
||||
}
|
||||
|
@ -137,13 +150,12 @@ struct wlr_screenshooter *wlr_screenshooter_create(struct wl_display *display,
|
|||
}
|
||||
screenshooter->renderer = renderer;
|
||||
|
||||
struct wl_global *wl_global = wl_global_create(display,
|
||||
screenshooter->wl_global = wl_global_create(display,
|
||||
&orbital_screenshooter_interface, 1, screenshooter, screenshooter_bind);
|
||||
if (!wl_global) {
|
||||
if (screenshooter->wl_global == NULL) {
|
||||
free(screenshooter);
|
||||
return NULL;
|
||||
}
|
||||
screenshooter->wl_global = wl_global;
|
||||
|
||||
return screenshooter;
|
||||
}
|
||||
|
|
|
@ -43,6 +43,7 @@ static void wl_pointer_set_cursor(struct wl_client *client,
|
|||
}
|
||||
event->seat_client = seat_client;
|
||||
event->surface = surface;
|
||||
event->serial = serial;
|
||||
event->hotspot_x = hotspot_x;
|
||||
event->hotspot_y = hotspot_y;
|
||||
|
||||
|
@ -64,9 +65,9 @@ static void wl_pointer_destroy(struct wl_resource *resource) {
|
|||
}
|
||||
|
||||
static void wl_seat_get_pointer(struct wl_client *client,
|
||||
struct wl_resource *pointer_resource, uint32_t id) {
|
||||
struct wl_resource *seat_resource, uint32_t id) {
|
||||
struct wlr_seat_client *seat_client =
|
||||
wl_resource_get_user_data(pointer_resource);
|
||||
wl_resource_get_user_data(seat_resource);
|
||||
if (!(seat_client->seat->capabilities & WL_SEAT_CAPABILITY_POINTER)) {
|
||||
return;
|
||||
}
|
||||
|
@ -77,7 +78,11 @@ static void wl_seat_get_pointer(struct wl_client *client,
|
|||
wl_resource_destroy(seat_client->pointer);
|
||||
}
|
||||
seat_client->pointer = wl_resource_create(client, &wl_pointer_interface,
|
||||
wl_resource_get_version(pointer_resource), id);
|
||||
wl_resource_get_version(seat_resource), id);
|
||||
if (seat_client->pointer == NULL) {
|
||||
wl_resource_post_no_memory(seat_resource);
|
||||
return;
|
||||
}
|
||||
wl_resource_set_implementation(seat_client->pointer, &wl_pointer_impl,
|
||||
seat_client, &wl_pointer_destroy);
|
||||
}
|
||||
|
@ -125,6 +130,10 @@ static void wl_seat_get_keyboard(struct wl_client *client,
|
|||
}
|
||||
seat_client->keyboard = wl_resource_create(client, &wl_keyboard_interface,
|
||||
wl_resource_get_version(seat_resource), id);
|
||||
if (seat_client->keyboard == NULL) {
|
||||
wl_resource_post_no_memory(seat_resource);
|
||||
return;
|
||||
}
|
||||
wl_resource_set_implementation(seat_client->keyboard, &wl_keyboard_impl,
|
||||
seat_client, &wl_keyboard_destroy);
|
||||
|
||||
|
@ -161,6 +170,10 @@ static void wl_seat_get_touch(struct wl_client *client,
|
|||
}
|
||||
seat_client->touch = wl_resource_create(client, &wl_touch_interface,
|
||||
wl_resource_get_version(seat_resource), id);
|
||||
if (seat_client->touch == NULL) {
|
||||
wl_resource_post_no_memory(seat_resource);
|
||||
return;
|
||||
}
|
||||
wl_resource_set_implementation(seat_client->touch, &wl_touch_impl,
|
||||
seat_client, &wl_touch_destroy);
|
||||
}
|
||||
|
@ -212,6 +225,11 @@ static void wl_seat_bind(struct wl_client *client, void *_wlr_seat,
|
|||
}
|
||||
seat_client->wl_resource =
|
||||
wl_resource_create(client, &wl_seat_interface, version, id);
|
||||
if (seat_client->wl_resource == NULL) {
|
||||
free(seat_client);
|
||||
wl_client_post_no_memory(client);
|
||||
return;
|
||||
}
|
||||
seat_client->client = client;
|
||||
seat_client->seat = wlr_seat;
|
||||
wl_resource_set_implementation(seat_client->wl_resource, &wl_seat_impl,
|
||||
|
@ -408,7 +426,6 @@ static void pointer_surface_destroy_notify(struct wl_listener *listener,
|
|||
listener, state, surface_destroy);
|
||||
wl_list_remove(&state->surface_destroy.link);
|
||||
wl_list_init(&state->surface_destroy.link);
|
||||
state->focused_surface = NULL;
|
||||
wlr_seat_pointer_clear_focus(state->seat);
|
||||
}
|
||||
|
||||
|
@ -418,7 +435,6 @@ static void pointer_resource_destroy_notify(struct wl_listener *listener,
|
|||
listener, state, resource_destroy);
|
||||
wl_list_remove(&state->resource_destroy.link);
|
||||
wl_list_init(&state->resource_destroy.link);
|
||||
state->focused_surface = NULL;
|
||||
wlr_seat_pointer_clear_focus(state->seat);
|
||||
}
|
||||
|
||||
|
@ -680,7 +696,6 @@ static void keyboard_surface_destroy_notify(struct wl_listener *listener,
|
|||
listener, state, surface_destroy);
|
||||
wl_list_remove(&state->surface_destroy.link);
|
||||
wl_list_init(&state->surface_destroy.link);
|
||||
state->focused_surface = NULL;
|
||||
wlr_seat_keyboard_clear_focus(state->seat);
|
||||
}
|
||||
|
||||
|
@ -690,7 +705,6 @@ static void keyboard_resource_destroy_notify(struct wl_listener *listener,
|
|||
listener, state, resource_destroy);
|
||||
wl_list_remove(&state->resource_destroy.link);
|
||||
wl_list_init(&state->resource_destroy.link);
|
||||
state->focused_surface = NULL;
|
||||
wlr_seat_keyboard_clear_focus(state->seat);
|
||||
}
|
||||
|
||||
|
|
|
@ -73,8 +73,8 @@ static void server_decoration_manager_handle_create(struct wl_client *client,
|
|||
decoration->resource = wl_resource_create(client,
|
||||
&org_kde_kwin_server_decoration_interface, version, id);
|
||||
if (decoration->resource == NULL) {
|
||||
wl_client_post_no_memory(client);
|
||||
free(decoration);
|
||||
wl_client_post_no_memory(client);
|
||||
return;
|
||||
}
|
||||
wl_resource_set_implementation(decoration->resource,
|
||||
|
@ -120,9 +120,9 @@ void server_decoration_manager_destroy_resource(struct wl_resource *resource) {
|
|||
wl_list_remove(wl_resource_get_link(resource));
|
||||
}
|
||||
|
||||
static void server_decoration_manager_bind(struct wl_client *client,
|
||||
void *_manager, uint32_t version, uint32_t id) {
|
||||
struct wlr_server_decoration_manager *manager = _manager;
|
||||
static void server_decoration_manager_bind(struct wl_client *client, void *data,
|
||||
uint32_t version, uint32_t id) {
|
||||
struct wlr_server_decoration_manager *manager = data;
|
||||
assert(client && manager);
|
||||
|
||||
struct wl_resource *resource = wl_resource_create(client,
|
||||
|
|
|
@ -819,14 +819,21 @@ static void subsurface_handle_parent_destroy(struct wl_listener *listener,
|
|||
|
||||
void wlr_surface_make_subsurface(struct wlr_surface *surface,
|
||||
struct wlr_surface *parent, uint32_t id) {
|
||||
struct wl_client *client = wl_resource_get_client(surface->resource);
|
||||
assert(surface->subsurface == NULL);
|
||||
|
||||
struct wlr_subsurface *subsurface =
|
||||
calloc(1, sizeof(struct wlr_subsurface));
|
||||
if (!subsurface) {
|
||||
wl_client_post_no_memory(client);
|
||||
return;
|
||||
}
|
||||
subsurface->cached = wlr_surface_state_create();
|
||||
if (subsurface->cached == NULL) {
|
||||
free(subsurface);
|
||||
wl_client_post_no_memory(client);
|
||||
return;
|
||||
}
|
||||
subsurface->synchronized = true;
|
||||
subsurface->surface = surface;
|
||||
|
||||
|
@ -840,10 +847,14 @@ void wlr_surface_make_subsurface(struct wlr_surface *surface,
|
|||
wl_list_insert(&parent->subsurface_pending_list,
|
||||
&subsurface->parent_pending_link);
|
||||
|
||||
struct wl_client *client = wl_resource_get_client(surface->resource);
|
||||
|
||||
subsurface->resource =
|
||||
wl_resource_create(client, &wl_subsurface_interface, 1, id);
|
||||
if (subsurface->resource == NULL) {
|
||||
wlr_surface_state_destroy(subsurface->cached);
|
||||
free(subsurface);
|
||||
wl_client_post_no_memory(client);
|
||||
return;
|
||||
}
|
||||
|
||||
wl_resource_set_implementation(subsurface->resource,
|
||||
&subsurface_implementation, subsurface,
|
||||
|
|
|
@ -506,19 +506,19 @@ static int shell_surface_ping_timeout(void *user_data) {
|
|||
}
|
||||
|
||||
static void shell_protocol_get_shell_surface(struct wl_client *client,
|
||||
struct wl_resource *resource, uint32_t id,
|
||||
struct wl_resource *shell_resource, uint32_t id,
|
||||
struct wl_resource *surface_resource) {
|
||||
struct wlr_surface *surface = wl_resource_get_user_data(surface_resource);
|
||||
if (wlr_surface_set_role(surface, wlr_wl_shell_surface_role,
|
||||
resource, WL_SHELL_ERROR_ROLE)) {
|
||||
shell_resource, WL_SHELL_ERROR_ROLE)) {
|
||||
return;
|
||||
}
|
||||
|
||||
struct wlr_wl_shell *wl_shell = wl_resource_get_user_data(resource);
|
||||
struct wlr_wl_shell *wl_shell = wl_resource_get_user_data(shell_resource);
|
||||
struct wlr_wl_shell_surface *wl_surface =
|
||||
calloc(1, sizeof(struct wlr_wl_shell_surface));
|
||||
if (wl_surface == NULL) {
|
||||
wl_client_post_no_memory(client);
|
||||
wl_resource_post_no_memory(shell_resource);
|
||||
return;
|
||||
}
|
||||
wl_list_init(&wl_surface->grab_link);
|
||||
|
@ -530,13 +530,20 @@ static void shell_protocol_get_shell_surface(struct wl_client *client,
|
|||
wl_surface->surface = surface;
|
||||
|
||||
wl_surface->resource = wl_resource_create(client,
|
||||
&wl_shell_surface_interface, wl_resource_get_version(resource), id);
|
||||
wlr_log(L_DEBUG, "new wl_shell %p (res %p)", wl_surface,
|
||||
wl_surface->resource);
|
||||
&wl_shell_surface_interface, wl_resource_get_version(shell_resource),
|
||||
id);
|
||||
if (wl_surface->resource == NULL) {
|
||||
free(wl_surface);
|
||||
wl_resource_post_no_memory(shell_resource);
|
||||
return;
|
||||
}
|
||||
wl_resource_set_implementation(wl_surface->resource,
|
||||
&shell_surface_impl, wl_surface,
|
||||
shell_surface_resource_destroy);
|
||||
|
||||
wlr_log(L_DEBUG, "new wl_shell %p (res %p)", wl_surface,
|
||||
wl_surface->resource);
|
||||
|
||||
wl_signal_init(&wl_surface->events.destroy);
|
||||
wl_signal_init(&wl_surface->events.ping_timeout);
|
||||
wl_signal_init(&wl_surface->events.request_move);
|
||||
|
@ -574,13 +581,17 @@ static void shell_destroy(struct wl_resource *resource) {
|
|||
wl_list_remove(wl_resource_get_link(resource));
|
||||
}
|
||||
|
||||
static void shell_bind(struct wl_client *wl_client, void *_wl_shell,
|
||||
static void shell_bind(struct wl_client *wl_client, void *data,
|
||||
uint32_t version, uint32_t id) {
|
||||
struct wlr_wl_shell *wl_shell = _wl_shell;
|
||||
struct wlr_wl_shell *wl_shell = data;
|
||||
assert(wl_client && wl_shell);
|
||||
|
||||
struct wl_resource *wl_resource = wl_resource_create(wl_client,
|
||||
&wl_shell_interface, version, id);
|
||||
if (wl_resource == NULL) {
|
||||
wl_client_post_no_memory(wl_client);
|
||||
return;
|
||||
}
|
||||
wl_resource_set_implementation(wl_resource, &shell_impl, wl_shell,
|
||||
shell_destroy);
|
||||
wl_list_insert(&wl_shell->wl_resources, wl_resource_get_link(wl_resource));
|
||||
|
|
|
@ -343,8 +343,8 @@ static void xdg_shell_create_positioner(struct wl_client *wl_client,
|
|||
wl_resource_get_version(resource),
|
||||
id);
|
||||
if (positioner->resource == NULL) {
|
||||
wl_client_post_no_memory(wl_client);
|
||||
free(positioner);
|
||||
wl_client_post_no_memory(wl_client);
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -486,7 +486,7 @@ static void xdg_surface_get_popup(struct wl_client *client,
|
|||
|
||||
surface->popup_state = calloc(1, sizeof(struct wlr_xdg_popup_v6));
|
||||
if (!surface->popup_state) {
|
||||
wl_client_post_no_memory(client);
|
||||
wl_resource_post_no_memory(resource);
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -495,6 +495,7 @@ static void xdg_surface_get_popup(struct wl_client *client,
|
|||
wl_resource_get_version(resource), id);
|
||||
if (surface->popup_state->resource == NULL) {
|
||||
free(surface->popup_state);
|
||||
wl_resource_post_no_memory(resource);
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -735,7 +736,7 @@ static void xdg_surface_get_toplevel(struct wl_client *client,
|
|||
|
||||
surface->toplevel_state = calloc(1, sizeof(struct wlr_xdg_toplevel_v6));
|
||||
if (surface->toplevel_state == NULL) {
|
||||
wl_client_post_no_memory(client);
|
||||
wl_resource_post_no_memory(resource);
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -744,6 +745,11 @@ static void xdg_surface_get_toplevel(struct wl_client *client,
|
|||
|
||||
struct wl_resource *toplevel_resource = wl_resource_create(client,
|
||||
&zxdg_toplevel_v6_interface, wl_resource_get_version(resource), id);
|
||||
if (toplevel_resource == NULL) {
|
||||
free(surface->toplevel_state);
|
||||
wl_resource_post_no_memory(resource);
|
||||
return;
|
||||
}
|
||||
|
||||
surface->toplevel_state->resource = toplevel_resource;
|
||||
|
||||
|
@ -1118,9 +1124,20 @@ static void xdg_shell_get_xdg_surface(struct wl_client *wl_client,
|
|||
surface->resource = wl_resource_create(wl_client,
|
||||
&zxdg_surface_v6_interface, wl_resource_get_version(client_resource),
|
||||
id);
|
||||
if (surface->resource == NULL) {
|
||||
free(surface->next_geometry);
|
||||
free(surface->geometry);
|
||||
free(surface);
|
||||
wl_client_post_no_memory(wl_client);
|
||||
return;
|
||||
}
|
||||
|
||||
if (wlr_surface_has_buffer(surface->surface)) {
|
||||
wl_resource_post_error(surface->resource,
|
||||
wl_resource_destroy(surface->resource);
|
||||
free(surface->next_geometry);
|
||||
free(surface->geometry);
|
||||
free(surface);
|
||||
wl_resource_post_error(surface_resource,
|
||||
ZXDG_SURFACE_V6_ERROR_UNCONFIGURED_BUFFER,
|
||||
"xdg_surface must not have a buffer at creation");
|
||||
return;
|
||||
|
@ -1199,9 +1216,9 @@ static int wlr_xdg_client_v6_ping_timeout(void *user_data) {
|
|||
return 1;
|
||||
}
|
||||
|
||||
static void xdg_shell_bind(struct wl_client *wl_client, void *_xdg_shell,
|
||||
static void xdg_shell_bind(struct wl_client *wl_client, void *data,
|
||||
uint32_t version, uint32_t id) {
|
||||
struct wlr_xdg_shell_v6 *xdg_shell = _xdg_shell;
|
||||
struct wlr_xdg_shell_v6 *xdg_shell = data;
|
||||
assert(wl_client && xdg_shell);
|
||||
|
||||
struct wlr_xdg_client_v6 *client =
|
||||
|
@ -1215,6 +1232,11 @@ static void xdg_shell_bind(struct wl_client *wl_client, void *_xdg_shell,
|
|||
|
||||
client->resource =
|
||||
wl_resource_create(wl_client, &zxdg_shell_v6_interface, version, id);
|
||||
if (client->resource == NULL) {
|
||||
free(client);
|
||||
wl_client_post_no_memory(wl_client);
|
||||
return;
|
||||
}
|
||||
client->client = wl_client;
|
||||
client->shell = xdg_shell;
|
||||
|
||||
|
|
|
@ -11,6 +11,8 @@ lib_wlr_xwayland = static_library(
|
|||
xcb,
|
||||
xcb_composite,
|
||||
xcb_xfixes,
|
||||
xcb_image,
|
||||
xcb_render,
|
||||
xcb_icccm,
|
||||
pixman,
|
||||
],
|
||||
|
|
|
@ -29,6 +29,15 @@ static inline int clearenv(void) {
|
|||
}
|
||||
#endif
|
||||
|
||||
struct wlr_xwayland_cursor {
|
||||
uint8_t *pixels;
|
||||
uint32_t stride;
|
||||
uint32_t width;
|
||||
uint32_t height;
|
||||
int32_t hotspot_x;
|
||||
int32_t hotspot_y;
|
||||
};
|
||||
|
||||
static void safe_close(int fd) {
|
||||
if (fd >= 0) {
|
||||
close(fd);
|
||||
|
@ -190,6 +199,14 @@ static int xserver_handle_ready(int signal_number, void *data) {
|
|||
wl_event_source_remove(wlr_xwayland->sigusr1_source);
|
||||
wlr_xwayland->sigusr1_source = NULL;
|
||||
|
||||
if (wlr_xwayland->cursor != NULL) {
|
||||
struct wlr_xwayland_cursor *cur = wlr_xwayland->cursor;
|
||||
xwm_set_cursor(wlr_xwayland->xwm, cur->pixels, cur->stride, cur->width,
|
||||
cur->height, cur->hotspot_x, cur->hotspot_y);
|
||||
free(cur);
|
||||
wlr_xwayland->cursor = NULL;
|
||||
}
|
||||
|
||||
char display_name[16];
|
||||
snprintf(display_name, sizeof(display_name), ":%d", wlr_xwayland->display);
|
||||
setenv("DISPLAY", display_name, true);
|
||||
|
@ -298,3 +315,26 @@ struct wlr_xwayland *wlr_xwayland_create(struct wl_display *wl_display,
|
|||
free(wlr_xwayland);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void wlr_xwayland_set_cursor(struct wlr_xwayland *wlr_xwayland,
|
||||
uint8_t *pixels, uint32_t stride, uint32_t width, uint32_t height,
|
||||
int32_t hotspot_x, int32_t hotspot_y) {
|
||||
if (wlr_xwayland->xwm != NULL) {
|
||||
xwm_set_cursor(wlr_xwayland->xwm, pixels, stride, width, height,
|
||||
hotspot_x, hotspot_y);
|
||||
return;
|
||||
}
|
||||
|
||||
free(wlr_xwayland->cursor);
|
||||
|
||||
wlr_xwayland->cursor = calloc(1, sizeof(struct wlr_xwayland_cursor));
|
||||
if (wlr_xwayland->cursor == NULL) {
|
||||
return;
|
||||
}
|
||||
wlr_xwayland->cursor->pixels = pixels;
|
||||
wlr_xwayland->cursor->stride = stride;
|
||||
wlr_xwayland->cursor->width = width;
|
||||
wlr_xwayland->cursor->height = height;
|
||||
wlr_xwayland->cursor->hotspot_x = hotspot_x;
|
||||
wlr_xwayland->cursor->hotspot_y = hotspot_y;
|
||||
}
|
||||
|
|
|
@ -5,9 +5,12 @@
|
|||
#include <unistd.h>
|
||||
#include <xcb/composite.h>
|
||||
#include <xcb/xfixes.h>
|
||||
#include <xcb/xcb_image.h>
|
||||
#include <xcb/render.h>
|
||||
#include "wlr/util/log.h"
|
||||
#include "wlr/types/wlr_surface.h"
|
||||
#include "wlr/xwayland.h"
|
||||
#include "wlr/xcursor.h"
|
||||
#include "xwm.h"
|
||||
|
||||
#ifdef HAS_XCB_ICCCM
|
||||
|
@ -1027,12 +1030,17 @@ void wlr_xwayland_surface_close(struct wlr_xwayland *wlr_xwayland,
|
|||
} else {
|
||||
xcb_kill_client(xwm->xcb_conn, xsurface->window_id);
|
||||
}
|
||||
|
||||
xcb_flush(xwm->xcb_conn);
|
||||
}
|
||||
|
||||
void xwm_destroy(struct wlr_xwm *xwm) {
|
||||
if (!xwm) {
|
||||
return;
|
||||
}
|
||||
if (xwm->cursor) {
|
||||
xcb_free_cursor(xwm->xcb_conn, xwm->cursor);
|
||||
}
|
||||
if (xwm->event_source) {
|
||||
wl_event_source_remove(xwm->event_source);
|
||||
}
|
||||
|
@ -1095,7 +1103,6 @@ static void xwm_get_resources(struct wlr_xwm *xwm) {
|
|||
xfixes_reply->major_version, xfixes_reply->minor_version);
|
||||
|
||||
free(xfixes_reply);
|
||||
|
||||
}
|
||||
|
||||
static void xwm_create_wm_window(struct wlr_xwm *xwm) {
|
||||
|
@ -1168,7 +1175,7 @@ static void xwm_get_visual_and_colormap(struct wlr_xwm *xwm) {
|
|||
}
|
||||
|
||||
if (visualtype == NULL) {
|
||||
wlr_log(L_DEBUG, "no 32 bit visualtype\n");
|
||||
wlr_log(L_DEBUG, "No 32 bit visualtype\n");
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -1181,6 +1188,71 @@ static void xwm_get_visual_and_colormap(struct wlr_xwm *xwm) {
|
|||
xwm->visual_id);
|
||||
}
|
||||
|
||||
static void xwm_get_render_format(struct wlr_xwm *xwm) {
|
||||
xcb_render_query_pict_formats_cookie_t cookie =
|
||||
xcb_render_query_pict_formats(xwm->xcb_conn);
|
||||
xcb_render_query_pict_formats_reply_t *reply =
|
||||
xcb_render_query_pict_formats_reply(xwm->xcb_conn, cookie, NULL);
|
||||
xcb_render_pictforminfo_iterator_t iter =
|
||||
xcb_render_query_pict_formats_formats_iterator(reply);
|
||||
xcb_render_pictforminfo_t *format = NULL;
|
||||
while (iter.rem > 0) {
|
||||
if (iter.data->depth == 32) {
|
||||
format = iter.data;
|
||||
break;
|
||||
}
|
||||
|
||||
xcb_render_pictforminfo_next(&iter);
|
||||
}
|
||||
|
||||
if (format == NULL) {
|
||||
wlr_log(L_DEBUG, "No 32 bit render format");
|
||||
return;
|
||||
}
|
||||
|
||||
xwm->render_format_id = format->id;
|
||||
}
|
||||
|
||||
void xwm_set_cursor(struct wlr_xwm *xwm, const uint8_t *pixels, uint32_t stride,
|
||||
uint32_t width, uint32_t height, int32_t hotspot_x, int32_t hotspot_y) {
|
||||
if (!xwm->render_format_id) {
|
||||
wlr_log(L_ERROR, "Cannot set xwm cursor: no render format available");
|
||||
return;
|
||||
}
|
||||
if (xwm->cursor) {
|
||||
xcb_free_cursor(xwm->xcb_conn, xwm->cursor);
|
||||
}
|
||||
|
||||
stride *= 4;
|
||||
int depth = 32;
|
||||
|
||||
xcb_pixmap_t pix = xcb_generate_id(xwm->xcb_conn);
|
||||
xcb_create_pixmap(xwm->xcb_conn, depth, pix, xwm->screen->root, width,
|
||||
height);
|
||||
|
||||
xcb_render_picture_t pic = xcb_generate_id(xwm->xcb_conn);
|
||||
xcb_render_create_picture(xwm->xcb_conn, pic, pix, xwm->render_format_id,
|
||||
0, 0);
|
||||
|
||||
xcb_gcontext_t gc = xcb_generate_id(xwm->xcb_conn);
|
||||
xcb_create_gc(xwm->xcb_conn, gc, pix, 0, NULL);
|
||||
|
||||
xcb_put_image(xwm->xcb_conn, XCB_IMAGE_FORMAT_Z_PIXMAP, pix, gc,
|
||||
width, height, 0, 0, 0, depth, stride * height * sizeof(uint8_t),
|
||||
pixels);
|
||||
xcb_free_gc(xwm->xcb_conn, gc);
|
||||
|
||||
xwm->cursor = xcb_generate_id(xwm->xcb_conn);
|
||||
xcb_render_create_cursor(xwm->xcb_conn, xwm->cursor, pic, hotspot_x,
|
||||
hotspot_y);
|
||||
xcb_free_pixmap(xwm->xcb_conn, pix);
|
||||
|
||||
uint32_t values[] = {xwm->cursor};
|
||||
xcb_change_window_attributes(xwm->xcb_conn, xwm->screen->root,
|
||||
XCB_CW_CURSOR, values);
|
||||
xcb_flush(xwm->xcb_conn);
|
||||
}
|
||||
|
||||
struct wlr_xwm *xwm_create(struct wlr_xwayland *wlr_xwayland) {
|
||||
struct wlr_xwm *xwm = calloc(1, sizeof(struct wlr_xwm));
|
||||
if (xwm == NULL) {
|
||||
|
@ -1217,16 +1289,16 @@ struct wlr_xwm *xwm_create(struct wlr_xwayland *wlr_xwayland) {
|
|||
|
||||
xwm_get_resources(xwm);
|
||||
xwm_get_visual_and_colormap(xwm);
|
||||
xwm_get_render_format(xwm);
|
||||
|
||||
uint32_t values[1];
|
||||
values[0] =
|
||||
uint32_t values[] = {
|
||||
XCB_EVENT_MASK_SUBSTRUCTURE_NOTIFY |
|
||||
XCB_EVENT_MASK_SUBSTRUCTURE_REDIRECT |
|
||||
XCB_EVENT_MASK_PROPERTY_CHANGE;
|
||||
|
||||
XCB_EVENT_MASK_PROPERTY_CHANGE,
|
||||
};
|
||||
xcb_change_window_attributes(xwm->xcb_conn,
|
||||
xwm->screen->root,
|
||||
XCB_CW_EVENT_MASK /* | XCB_CW_CURSOR */,
|
||||
XCB_CW_EVENT_MASK,
|
||||
values);
|
||||
|
||||
xcb_composite_redirect_subwindows(xwm->xcb_conn,
|
||||
|
|
|
@ -1,5 +1,7 @@
|
|||
#ifndef XWAYLAND_INTERNALS_H
|
||||
#define XWAYLAND_INTERNALS_H
|
||||
|
||||
#include <xcb/render.h>
|
||||
#include <wayland-server-core.h>
|
||||
#include <wlr/xwayland.h>
|
||||
|
||||
|
@ -49,6 +51,8 @@ struct wlr_xwm {
|
|||
xcb_window_t window;
|
||||
xcb_visualid_t visual_id;
|
||||
xcb_colormap_t colormap;
|
||||
xcb_render_pictformat_t render_format_id;
|
||||
xcb_cursor_t cursor;
|
||||
|
||||
struct wlr_xwayland_surface *focus_surface;
|
||||
|
||||
|
@ -60,8 +64,11 @@ struct wlr_xwm {
|
|||
struct wl_listener compositor_surface_create;
|
||||
};
|
||||
|
||||
void xwm_destroy(struct wlr_xwm *xwm);
|
||||
|
||||
struct wlr_xwm *xwm_create(struct wlr_xwayland *wlr_xwayland);
|
||||
|
||||
void xwm_destroy(struct wlr_xwm *xwm);
|
||||
|
||||
void xwm_set_cursor(struct wlr_xwm *xwm, const uint8_t *pixels, uint32_t stride,
|
||||
uint32_t width, uint32_t height, int32_t hotspot_x, int32_t hotspot_y);
|
||||
|
||||
#endif
|
||||
|
|
Loading…
Reference in a new issue