Added mouse cursor callback stubs.

This commit is contained in:
Armin Novak 2019-01-25 13:05:51 +01:00
parent 05d9d89796
commit 23fa6b9182
10 changed files with 395 additions and 2 deletions

View File

@ -27,6 +27,8 @@ set(${MODULE_PREFIX}_SRCS
wlfreerdp.h
wlf_disp.c
wlf_disp.h
wlf_pointer.c
wlf_pointer.h
wlf_input.c
wlf_input.h
wlf_cliprdr.c

View File

@ -0,0 +1,136 @@
/**
* FreeRDP: A Remote Desktop Protocol Implementation
* Wayland Mouse Pointer
*
* Copyright 2019 Armin Novak <armin.novak@thincast.com>
* Copyright 2019 Thincast Technologies GmbH
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#include "wlf_pointer.h"
#include "wlfreerdp.h"
#include <freerdp/log.h>
#define TAG CLIENT_TAG("wayland.pointer")
struct wlf_pointer
{
rdpPointer pointer;
size_t size;
void* data;
};
typedef struct wlf_pointer wlfPointer;
static BOOL wlf_Pointer_New(rdpContext* context, rdpPointer* pointer)
{
wlfPointer* ptr = (wlfPointer*)pointer;
if (!ptr)
return FALSE;
ptr->size = pointer->width * pointer->height * 4;
ptr->data = _aligned_malloc(ptr->size, 16);
if (!ptr->data)
return FALSE;
if (!freerdp_image_copy_from_pointer_data(
ptr->data, PIXEL_FORMAT_ARGB32,
0, 0, 0, pointer->width, pointer->height,
pointer->xorMaskData, pointer->lengthXorMask,
pointer->andMaskData, pointer->lengthAndMask,
pointer->xorBpp, &context->gdi->palette))
{
_aligned_free(ptr->data);
return FALSE;
}
return TRUE;
}
static void wlf_Pointer_Free(rdpContext* context, rdpPointer* pointer)
{
wlfPointer* ptr = (wlfPointer*)pointer;
WINPR_UNUSED(context);
if (ptr)
_aligned_free(ptr->data);
}
static BOOL wlf_Pointer_Set(rdpContext* context,
const rdpPointer* pointer)
{
wlfContext* wlf = (wlfContext*)context;
wlfPointer* ptr = (wlfPointer*)pointer;
if (!wlf || !wlf->seat)
return FALSE;
// TODO: Scale according to SmartSizing
if (UwacSeatSetMouseCursor(wlf->seat, ptr->data, ptr->size, pointer->width, pointer->height, pointer->xPos, pointer->yPos) != UWAC_SUCCESS)
return FALSE;
return TRUE;
}
static BOOL wlf_Pointer_SetNull(rdpContext* context)
{
wlfContext* wlf = (wlfContext*)context;
if (!wlf || !wlf->seat)
return FALSE;
if (UwacSeatSetMouseCursor(wlf->seat, NULL, 0, 0, 0, 0, 0) != UWAC_SUCCESS)
return FALSE;
return TRUE;
}
static BOOL wlf_Pointer_SetDefault(rdpContext* context)
{
wlfContext* wlf = (wlfContext*)context;
if (!wlf || !wlf->seat)
return FALSE;
if (UwacSeatSetMouseCursor(wlf->seat, NULL, 1, 0, 0, 0, 0) != UWAC_SUCCESS)
return FALSE;
return TRUE;
}
static BOOL wlf_Pointer_SetPosition(rdpContext* context, UINT32 x, UINT32 y)
{
// TODO
WLog_WARN(TAG, "%s not implemented", __FUNCTION__);
return TRUE;
}
BOOL wlf_register_pointer(rdpGraphics* graphics)
{
rdpPointer* pointer = NULL;
if (!(pointer = (rdpPointer*) calloc(1, sizeof(rdpPointer))))
return FALSE;
pointer->size = sizeof(wlfPointer);
pointer->New = wlf_Pointer_New;
pointer->Free = wlf_Pointer_Free;
pointer->Set = wlf_Pointer_Set;
pointer->SetNull = wlf_Pointer_SetNull;
pointer->SetDefault = wlf_Pointer_SetDefault;
pointer->SetPosition = wlf_Pointer_SetPosition;
graphics_register_pointer(graphics, pointer);
free(pointer);
return TRUE;
}

View File

@ -0,0 +1,28 @@
/**
* FreeRDP: A Remote Desktop Protocol Implementation
* Wayland Mouse Pointer
*
* Copyright 2019 Armin Novak <armin.novak@thincast.com>
* Copyright 2019 Thincast Technologies GmbH
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef FREERDP_CLIENT_WAYLAND_POINTER_H
#define FREERDP_CLIENT_WAYLAND_POINTER_H
#include <freerdp/graphics.h>
BOOL wlf_register_pointer(rdpGraphics* graphics);
#endif /* FREERDP_CLIENT_WAYLAND_POINTER_H */

View File

@ -39,6 +39,7 @@
#include "wlf_cliprdr.h"
#include "wlf_disp.h"
#include "wlf_channels.h"
#include "wlf_pointer.h"
static BOOL wl_begin_paint(rdpContext* context)
{
@ -222,6 +223,9 @@ static BOOL wl_post_connect(freerdp* instance)
if (!gdi || (gdi->width < 0) || (gdi->height < 0))
return FALSE;
if (!wlf_register_pointer(instance->context->graphics))
return FALSE;
w = (UINT32)gdi->width;
h = (UINT32)gdi->height;
context = (wlfContext*) instance->context;
@ -286,6 +290,14 @@ static BOOL handle_uwac_events(freerdp* instance, UwacDisplay* display)
/*printf("UWAC event type %d\n", event.type);*/
switch (event.type)
{
case UWAC_EVENT_NEW_SEAT:
context->seat = event.seat_new.seat;
break;
case UWAC_EVENT_REMOVED_SEAT:
context->seat = NULL;
break;
case UWAC_EVENT_FRAME_DONE:
break;

View File

@ -41,6 +41,7 @@ struct wlf_context
UwacDisplay* display;
HANDLE displayHandle;
UwacWindow* window;
UwacSeat* seat;
BOOL fullscreen;

View File

@ -30,6 +30,7 @@ include(FindPkgConfig)
if(PKG_CONFIG_FOUND)
pkg_check_modules(WAYLAND_SCANNER_PC wayland-scanner)
pkg_check_modules(WAYLAND_CLIENT_PC wayland-client)
pkg_check_modules(WAYLAND_CURSOR_PC wayland-cursor)
pkg_check_modules(XKBCOMMON_PC xkbcommon)
endif()
@ -41,11 +42,20 @@ find_path(WAYLAND_INCLUDE_DIR wayland-client.h
HINTS ${WAYLAND_CLIENT_PC_INCLUDE_DIRS}
)
find_library(WAYLAND_LIBS
find_library(WAYLAND_CLIENT_LIB
NAMES "wayland-client"
HINTS "${WAYLAND_CLIENT_PC_LIBRARY_DIRS}"
)
find_library(WAYLAND_CURSOR_LIB
NAMES "wayland-cursor"
HINTS "${WAYLAND_CURSOR_PC_LIBRARY_DIRS}"
)
if (WAYLAND_CLIENT_LIB AND WAYLAND_CURSOR_LIB)
list(INSERT WAYLAND_LIBS ${WAYLAND_CLIENT_LIB} ${WAYLAND_CURSOR_LIB})
endif (WAYLAND_CLIENT_LIB AND WAYLAND_CURSOR_LIB)
find_path(XKBCOMMON_INCLUDE_DIR xkbcommon/xkbcommon.h
HINTS ${XKBCOMMON_PC_INCLUDE_DIRS}
)

View File

@ -564,6 +564,25 @@ UWAC_API void* UwacClipboardDataGet(UwacSeat* seat, const char* mime, size_t* si
*/
UWAC_API UwacReturnCode UwacSeatInhibitShortcuts(UwacSeat* seat, bool inhibit);
/**
* @brief UwacSeatSetMouseCursor Sets the specified image as the new mouse cursor.
* Special values: If data == NULL && lenght == 0
* the cursor is hidden, if data == NULL && length != 0
* the default system cursor is used.
*
* @param seat The UwacSeat to apply the cursor image to
* @param data A pointer to the image data
* @param length The size of the image data
* @param width The image width in pixel
* @param height The image height in pixel
* @param hot_x The hotspot horizontal offset in pixel
* @param hot_y The hotspot vertical offset in pixel
*
* @return UWAC_SUCCESS if successful, an appropriate error otherwise.
*/
UWAC_API UwacReturnCode UwacSeatSetMouseCursor(UwacSeat* seat, const void* data, size_t length,
size_t width, size_t height, size_t hot_x, size_t hot_y);
#ifdef __cplusplus
}
#endif

View File

@ -33,6 +33,7 @@
#include <sys/epoll.h>
#include "uwac-os.h"
#include "wayland-cursor.h"
#define TARGET_COMPOSITOR_INTERFACE 3
#define TARGET_SHM_INTERFACE 1
@ -151,6 +152,14 @@ static void UwacSeatRegisterDDM(UwacSeat *seat)
seat->data_device = wl_data_device_manager_get_data_device(d->data_device_manager, seat->seat);
}
static void UwacRegisterCursor(UwacSeat* seat)
{
if (!seat || !seat->display || !seat->display->compositor)
return;
seat->pointer_surface = wl_compositor_create_surface(seat->display->compositor);
}
static void registry_handle_global(void* data, struct wl_registry* registry, uint32_t id,
const char* interface, uint32_t version)
{
@ -171,6 +180,18 @@ static void registry_handle_global(void* data, struct wl_registry* registry, uin
{
d->shm = wl_registry_bind(registry, id, &wl_shm_interface, min(TARGET_SHM_INTERFACE, version));
wl_shm_add_listener(d->shm, &shm_listener, d);
d->cursor_theme = wl_cursor_theme_load(NULL, 32, d->shm);
if (!d->cursor_theme) {
assert(uwacErrorHandler(d, UWAC_ERROR_NOMEMORY, "unable to get wayland cursor theme\n"));
return;
}
d->default_cursor = wl_cursor_theme_get_cursor(d->cursor_theme, "left_ptr");
if (!d->default_cursor) {
assert(uwacErrorHandler(d, UWAC_ERROR_NOMEMORY, "unable to get wayland cursor left_ptr\n"));
return;
}
}
else if (strcmp(interface, "wl_output") == 0)
{
@ -203,6 +224,7 @@ static void registry_handle_global(void* data, struct wl_registry* registry, uin
UwacSeatRegisterDDM(seat);
UwacSeatRegisterClipboard(seat);
UwacRegisterCursor(seat);
ev = (UwacSeatNewEvent*)UwacDisplayNewEvent(d, UWAC_EVENT_NEW_SEAT);
if (!ev)
@ -224,6 +246,7 @@ static void registry_handle_global(void* data, struct wl_registry* registry, uin
{
UwacSeatRegisterDDM(seat);
UwacSeatRegisterClipboard(seat);
UwacRegisterCursor(seat);
}
}
else if (strcmp(interface, "wl_shell") == 0)
@ -573,6 +596,9 @@ UwacReturnCode UwacCloseDisplay(UwacDisplay** pdisplay)
if (display->shell)
wl_shell_destroy(display->shell);
if (display->cursor_theme)
wl_cursor_theme_destroy(display->cursor_theme);
if (display->shm)
wl_shm_destroy(display->shm);

View File

@ -32,6 +32,62 @@
#include <sys/timerfd.h>
#include <sys/epoll.h>
#include "uwac-os.h"
#include "wayland-cursor.h"
#include "wayland-client-protocol.h"
static UwacReturnCode
set_cursor_image(UwacSeat* seat, uint32_t serial)
{
struct wl_buffer* buffer;
struct wl_cursor* cursor;
struct wl_cursor_image* image;
struct wl_surface* surface = NULL;
int32_t x = 0, y = 0;
if (!seat || !seat->display || !seat->display->default_cursor || !seat->display->default_cursor->images)
return UWAC_ERROR_INTERNAL;
switch(seat->pointer_type) {
case 2: /* Custom poiner */
image = seat->pointer_image;
buffer = seat->pointer_buffer;
surface = seat->pointer_surface;
x = image->hotspot_x;
y = image->hotspot_y;
break;
case 1: /* NULL pointer */
break;
default: /* Default system pointer */
cursor = seat->display->default_cursor;
if (!cursor)
return UWAC_ERROR_INTERNAL;
image = cursor->images[0];
if (!image)
return UWAC_ERROR_INTERNAL;
x = image->hotspot_x;
y = image->hotspot_y;
buffer = wl_cursor_image_get_buffer(image);
if (!buffer)
return UWAC_ERROR_INTERNAL;
surface = seat->pointer_surface;
break;
}
wl_pointer_set_cursor(seat->pointer,
serial,
surface,
x, y);
if (surface) {
wl_surface_attach(surface, buffer, 0, 0);
wl_surface_damage(surface, 0, 0,
image->width, image->height);
wl_surface_commit(surface);
}
return UWAC_SUCCESS;
}
static void keyboard_repeat_func(UwacTask *task, uint32_t events)
{
@ -588,6 +644,10 @@ static void pointer_handle_enter(void *data, struct wl_pointer *pointer, uint32_
event->window = window;
event->x = sx;
event->y = sy;
/* Apply cursor theme */
set_cursor_image(input, serial);
}
static void pointer_handle_leave(void *data, struct wl_pointer *pointer, uint32_t serial,
@ -871,6 +931,14 @@ void UwacSeatDestroy(UwacSeat *s) {
if (s->data_source)
wl_data_source_destroy(s->data_source);
if (s->pointer_surface)
wl_surface_destroy(s->pointer_surface);
if (s->pointer_buffer)
wl_buffer_destroy(s->pointer_buffer);
free(s->pointer_image);
wl_list_remove(&s->link);
free(s);
}
@ -898,3 +966,90 @@ UwacReturnCode UwacSeatInhibitShortcuts(UwacSeat* s, bool inhibit)
return UWAC_ERROR_INTERNAL;
return UWAC_SUCCESS;
}
UwacReturnCode create_pointer_buffer(UwacSeat* seat, const void* src, size_t size)
{
UwacReturnCode ret = UWAC_SUCCESS;
UwacBuffer* newBuffers;
int fd;
void* data;
struct wl_shm_pool* pool;
if (!newBuffers)
return UWAC_ERROR_NOMEMORY;
fd = uwac_create_anonymous_file(size);
if (fd < 0)
{
return UWAC_ERROR_INTERNAL;
}
data = mmap(NULL, size, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
if (data == MAP_FAILED)
{
ret = UWAC_ERROR_NOMEMORY;
goto error_mmap;
}
memcpy(data, src, size);
pool = wl_shm_create_pool(seat->display->shm, fd, size * 2);
if (!pool)
{
munmap(data, size);
ret = UWAC_ERROR_NOMEMORY;
goto error_mmap;
}
seat->pointer_buffer = wl_shm_pool_create_buffer(pool, size,
seat->pointer_image->width,
seat->pointer_image->height,
seat->pointer_image->width * 4,
WL_SHM_FORMAT_XRGB8888);
wl_shm_pool_destroy(pool);
error_mmap:
close(fd);
return ret;
}
UwacReturnCode UwacSeatSetMouseCursor(UwacSeat* seat, const void* data, size_t length,
size_t width, size_t height,
size_t hot_x, size_t hot_y)
{
if (!seat)
return UWAC_ERROR_CLOSED;
free(seat->pointer_image);
if (seat->pointer_buffer)
wl_buffer_destroy(seat->pointer_buffer);
seat->pointer_image = NULL;
seat->pointer_buffer = NULL;
/* There is a cursor provided */
if ((data != NULL) && (length != 0))
{
seat->pointer_image = calloc(1, sizeof(struct wl_cursor_image));
if (!seat->pointer_image)
return UWAC_ERROR_NOMEMORY;
seat->pointer_image->width = width;
seat->pointer_image->height = height;
seat->pointer_image->hotspot_x = hot_x;
seat->pointer_image->hotspot_y = hot_y;
create_pointer_buffer(seat, data, length);
seat->pointer_type = 2;
}
/* We want to use the system cursor */
else if (length != 0) {
seat->pointer_type = 0;
}
/* Hide the cursor */
else {
seat->pointer_type = 1;
}
return set_cursor_image(seat, seat->display->serial);
}

View File

@ -121,7 +121,7 @@ struct uwac_display {
uint32_t serial;
struct wl_cursor_theme *cursor_theme;
struct wl_cursor **cursors;
struct wl_cursor *default_cursor;
struct wl_list windows;
@ -158,6 +158,10 @@ struct uwac_seat {
struct wl_data_device* data_device;
struct wl_data_source* data_source;
struct wl_pointer *pointer;
struct wl_surface *pointer_surface;
struct wl_cursor_image *pointer_image;
int pointer_type;
struct wl_buffer *pointer_buffer;
struct wl_keyboard *keyboard;
struct wl_touch *touch;
struct wl_data_offer* offer;