mirror of
https://github.com/morgan9e/FreeRDP
synced 2026-04-15 00:44:19 +09:00
Implements #5215: Smart sizing using libcairo
This commit is contained in:
@@ -37,9 +37,19 @@ set(${MODULE_PREFIX}_SRCS
|
||||
wlf_channels.h
|
||||
)
|
||||
|
||||
find_package(Cairo)
|
||||
|
||||
list (APPEND ${MODULE_PREFIX}_LIBS freerdp-client freerdp uwac)
|
||||
if (CAIRO_FOUND)
|
||||
add_definitions(-DCAIRO_FOUND=1)
|
||||
include_directories(${CAIRO_INCLUDE_DIR})
|
||||
list(APPEND ${MODULE_PREFIX}_LIBS ${CAIRO_LIBRARY})
|
||||
else(CAIRO_FOUND)
|
||||
message(WARNING "libcairo not detected, compiling without wayland smart scaling support!")
|
||||
endif(CAIRO_FOUND)
|
||||
|
||||
add_executable(${MODULE_NAME} ${${MODULE_PREFIX}_SRCS})
|
||||
|
||||
set(${MODULE_PREFIX}_LIBS ${${MODULE_PREFIX}_LIBS} freerdp-client freerdp uwac)
|
||||
target_link_libraries(${MODULE_NAME} ${${MODULE_PREFIX}_LIBS})
|
||||
|
||||
install(TARGETS ${MODULE_NAME} DESTINATION ${CMAKE_INSTALL_BINDIR} COMPONENT client)
|
||||
|
||||
@@ -23,33 +23,57 @@
|
||||
|
||||
#include <freerdp/locale/keyboard.h>
|
||||
|
||||
#include "wlfreerdp.h"
|
||||
#include "wlf_input.h"
|
||||
|
||||
BOOL wlf_handle_pointer_enter(freerdp* instance, UwacPointerEnterLeaveEvent* ev)
|
||||
BOOL wlf_handle_pointer_enter(freerdp* instance, const UwacPointerEnterLeaveEvent* ev)
|
||||
{
|
||||
uint32_t x, y;
|
||||
|
||||
if (!instance || !ev || !instance->input)
|
||||
return FALSE;
|
||||
|
||||
return freerdp_input_send_mouse_event(instance->input, PTR_FLAGS_MOVE, ev->x, ev->y);
|
||||
x = ev->x;
|
||||
y = ev->y;
|
||||
|
||||
if (!wlf_scale_coordinates(instance->context, &x, &y))
|
||||
return FALSE;
|
||||
|
||||
return freerdp_input_send_mouse_event(instance->input, PTR_FLAGS_MOVE, x, y);
|
||||
}
|
||||
|
||||
BOOL wlf_handle_pointer_motion(freerdp* instance, UwacPointerMotionEvent* ev)
|
||||
BOOL wlf_handle_pointer_motion(freerdp* instance, const UwacPointerMotionEvent* ev)
|
||||
{
|
||||
uint32_t x, y;
|
||||
|
||||
if (!instance || !ev || !instance->input)
|
||||
return FALSE;
|
||||
|
||||
return freerdp_input_send_mouse_event(instance->input, PTR_FLAGS_MOVE, ev->x, ev->y);
|
||||
x = ev->x;
|
||||
y = ev->y;
|
||||
|
||||
if (!wlf_scale_coordinates(instance->context, &x, &y))
|
||||
return FALSE;
|
||||
|
||||
return freerdp_input_send_mouse_event(instance->input, PTR_FLAGS_MOVE, x, y);
|
||||
}
|
||||
|
||||
BOOL wlf_handle_pointer_buttons(freerdp* instance, UwacPointerButtonEvent* ev)
|
||||
BOOL wlf_handle_pointer_buttons(freerdp* instance, const UwacPointerButtonEvent* ev)
|
||||
{
|
||||
rdpInput* input;
|
||||
UINT16 flags = 0;
|
||||
UINT16 xflags = 0;
|
||||
uint32_t x, y;
|
||||
|
||||
if (!instance || !ev || !instance->input)
|
||||
return FALSE;
|
||||
|
||||
x = ev->x;
|
||||
y = ev->y;
|
||||
|
||||
if (!wlf_scale_coordinates(instance->context, &x, &y))
|
||||
return FALSE;
|
||||
|
||||
input = instance->input;
|
||||
|
||||
if (ev->state == WL_POINTER_BUTTON_STATE_PRESSED)
|
||||
@@ -85,24 +109,31 @@ BOOL wlf_handle_pointer_buttons(freerdp* instance, UwacPointerButtonEvent* ev)
|
||||
}
|
||||
|
||||
if ((flags & ~PTR_FLAGS_DOWN) != 0)
|
||||
return freerdp_input_send_mouse_event(input, flags, ev->x, ev->y);
|
||||
return freerdp_input_send_mouse_event(input, flags, x, y);
|
||||
|
||||
if ((xflags & ~PTR_XFLAGS_DOWN) != 0)
|
||||
return freerdp_input_send_extended_mouse_event(input, xflags, ev->x, ev->y);
|
||||
return freerdp_input_send_extended_mouse_event(input, xflags, x, y);
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
|
||||
BOOL wlf_handle_pointer_axis(freerdp* instance, UwacPointerAxisEvent* ev)
|
||||
BOOL wlf_handle_pointer_axis(freerdp* instance, const UwacPointerAxisEvent* ev)
|
||||
{
|
||||
rdpInput* input;
|
||||
UINT16 flags = 0;
|
||||
int direction;
|
||||
uint32_t x, y;
|
||||
|
||||
if (!instance || !ev || !instance->input)
|
||||
return FALSE;
|
||||
|
||||
x = ev->x;
|
||||
y = ev->y;
|
||||
|
||||
if (!wlf_scale_coordinates(instance->context, &x, &y))
|
||||
return FALSE;
|
||||
|
||||
input = instance->input;
|
||||
|
||||
switch (ev->axis)
|
||||
@@ -125,10 +156,10 @@ BOOL wlf_handle_pointer_axis(freerdp* instance, UwacPointerAxisEvent* ev)
|
||||
if (direction < 0)
|
||||
flags |= PTR_FLAGS_WHEEL_NEGATIVE;
|
||||
|
||||
return freerdp_input_send_mouse_event(input, flags, ev->x, ev->y);
|
||||
return freerdp_input_send_mouse_event(input, flags, x, y);
|
||||
}
|
||||
|
||||
BOOL wlf_handle_key(freerdp* instance, UwacKeyEvent* ev)
|
||||
BOOL wlf_handle_key(freerdp* instance, const UwacKeyEvent* ev)
|
||||
{
|
||||
rdpInput* input;
|
||||
DWORD rdp_scancode;
|
||||
@@ -145,7 +176,7 @@ BOOL wlf_handle_key(freerdp* instance, UwacKeyEvent* ev)
|
||||
return freerdp_input_send_keyboard_event_ex(input, ev->pressed, rdp_scancode);
|
||||
}
|
||||
|
||||
BOOL wlf_keyboard_enter(freerdp* instance, UwacKeyboardEnterLeaveEvent* ev)
|
||||
BOOL wlf_keyboard_enter(freerdp* instance, const UwacKeyboardEnterLeaveEvent* ev)
|
||||
{
|
||||
rdpInput* input;
|
||||
|
||||
|
||||
@@ -27,12 +27,12 @@
|
||||
#include <uwac/uwac.h>
|
||||
|
||||
BOOL wlf_handle_pointer_enter(freerdp* instance,
|
||||
UwacPointerEnterLeaveEvent* ev);
|
||||
BOOL wlf_handle_pointer_motion(freerdp* instance, UwacPointerMotionEvent* ev);
|
||||
BOOL wlf_handle_pointer_buttons(freerdp* instance, UwacPointerButtonEvent* ev);
|
||||
BOOL wlf_handle_pointer_axis(freerdp* instance, UwacPointerAxisEvent* ev);
|
||||
const UwacPointerEnterLeaveEvent* ev);
|
||||
BOOL wlf_handle_pointer_motion(freerdp* instance, const UwacPointerMotionEvent* ev);
|
||||
BOOL wlf_handle_pointer_buttons(freerdp* instance, const UwacPointerButtonEvent* ev);
|
||||
BOOL wlf_handle_pointer_axis(freerdp* instance, const UwacPointerAxisEvent* ev);
|
||||
|
||||
BOOL wlf_handle_key(freerdp* instance, UwacKeyEvent* ev);
|
||||
BOOL wlf_keyboard_enter(freerdp* instance, UwacKeyboardEnterLeaveEvent* ev);
|
||||
BOOL wlf_handle_key(freerdp* instance, const UwacKeyEvent* ev);
|
||||
BOOL wlf_keyboard_enter(freerdp* instance, const UwacKeyboardEnterLeaveEvent* ev);
|
||||
|
||||
#endif /* FREERDP_CLIENT_WAYLAND_INPUT_H */
|
||||
|
||||
@@ -22,6 +22,7 @@
|
||||
#include <stdio.h>
|
||||
#include <errno.h>
|
||||
#include <locale.h>
|
||||
#include <float.h>
|
||||
|
||||
#include <freerdp/client/cmdline.h>
|
||||
#include <freerdp/channels/channels.h>
|
||||
@@ -33,6 +34,9 @@
|
||||
#include <linux/input.h>
|
||||
|
||||
#include <uwac/uwac.h>
|
||||
#if defined(CAIRO_FOUND)
|
||||
#include <cairo.h>
|
||||
#endif
|
||||
|
||||
#include "wlfreerdp.h"
|
||||
#include "wlf_input.h"
|
||||
@@ -67,6 +71,7 @@ static BOOL wl_update_buffer(wlfContext* context_w, INT32 ix, INT32 iy, INT32 iw
|
||||
UwacSize geometry;
|
||||
size_t stride;
|
||||
UwacReturnCode rc;
|
||||
RECTANGLE_16 area;
|
||||
|
||||
if (!context_w)
|
||||
return FALSE;
|
||||
@@ -93,16 +98,21 @@ static BOOL wl_update_buffer(wlfContext* context_w, INT32 ix, INT32 iy, INT32 iw
|
||||
if ((x > geometry.width) || (y > geometry.height))
|
||||
return TRUE;
|
||||
|
||||
baseSrcOffset = y * gdi->stride + x * GetBytesPerPixel(gdi->dstFormat);
|
||||
baseDstOffset = y * stride + x * 4;
|
||||
for (i = 0; i < MIN(h, geometry.height - y); i++)
|
||||
{
|
||||
const size_t srcOffset = i * gdi->stride + baseSrcOffset;
|
||||
const size_t dstOffset = i * stride + baseDstOffset;
|
||||
area.left = x;
|
||||
area.top = y;
|
||||
area.right = x + w;
|
||||
area.bottom = y + h;
|
||||
|
||||
memcpy(data + dstOffset, gdi->primary_buffer + srcOffset,
|
||||
MIN(w, geometry.width - x) * GetBytesPerPixel(gdi->dstFormat));
|
||||
}
|
||||
if (!wlf_copy_image(gdi->primary_buffer, gdi->stride, gdi->width, gdi->height,
|
||||
data, stride, geometry.width, geometry.height, &area,
|
||||
context_w->context.settings->SmartSizing))
|
||||
return FALSE;
|
||||
|
||||
if (!wlf_scale_coordinates(&context_w->context, &x, &y))
|
||||
return FALSE;
|
||||
|
||||
if (!wlf_scale_coordinates(&context_w->context, &w, &h))
|
||||
return FALSE;
|
||||
|
||||
if (UwacWindowAddDamage(context_w->window, x, y, w, h) != UWAC_SUCCESS)
|
||||
return FALSE;
|
||||
@@ -299,6 +309,9 @@ static BOOL handle_uwac_events(freerdp* instance, UwacDisplay* display)
|
||||
break;
|
||||
|
||||
case UWAC_EVENT_FRAME_DONE:
|
||||
if (UwacWindowSubmitBuffer(context->window, true) != UWAC_SUCCESS)
|
||||
return FALSE;
|
||||
|
||||
break;
|
||||
|
||||
case UWAC_EVENT_POINTER_ENTER:
|
||||
@@ -334,6 +347,7 @@ static BOOL handle_uwac_events(freerdp* instance, UwacDisplay* display)
|
||||
case UWAC_EVENT_KEYBOARD_ENTER:
|
||||
if (instance->context->settings->GrabKeyboard)
|
||||
UwacSeatInhibitShortcuts(event.keyboard_enter_leave.seat, true);
|
||||
|
||||
if (!wlf_keyboard_enter(instance, &event.keyboard_enter_leave))
|
||||
return FALSE;
|
||||
|
||||
@@ -556,3 +570,96 @@ fail:
|
||||
freerdp_client_context_free(context);
|
||||
return rc;
|
||||
}
|
||||
|
||||
BOOL wlf_copy_image(const void* src, size_t srcStride, size_t srcWidth, size_t srcHeight,
|
||||
void* dst, size_t dstStride, size_t dstWidth, size_t dstHeight,
|
||||
const RECTANGLE_16* area, BOOL scale)
|
||||
{
|
||||
BOOL rc = FALSE;
|
||||
|
||||
if (!src || !dst || !area)
|
||||
return FALSE;
|
||||
|
||||
if (scale)
|
||||
{
|
||||
#if defined(CAIRO_FOUND)
|
||||
const double sx = (double)dstWidth / (double)srcWidth;
|
||||
const double sy = (double)dstHeight / (double)srcHeight;
|
||||
cairo_t* cairo_context;
|
||||
cairo_surface_t* csrc = cairo_image_surface_create_for_data(src, CAIRO_FORMAT_ARGB32, srcWidth,
|
||||
srcHeight, srcStride);
|
||||
cairo_surface_t* cdst = cairo_image_surface_create_for_data(dst, CAIRO_FORMAT_ARGB32, dstWidth,
|
||||
dstHeight, dstStride);
|
||||
|
||||
if (!csrc || !cdst)
|
||||
goto fail;
|
||||
|
||||
cairo_context = cairo_create(cdst);
|
||||
|
||||
if (!cairo_context)
|
||||
goto fail2;
|
||||
|
||||
cairo_scale(cairo_context, sx, sy);
|
||||
cairo_set_operator(cairo_context, CAIRO_OPERATOR_SOURCE);
|
||||
cairo_set_source_surface(cairo_context, csrc, 0, 0);
|
||||
cairo_paint(cairo_context);
|
||||
rc = TRUE;
|
||||
fail2:
|
||||
cairo_destroy(cairo_context);
|
||||
fail:
|
||||
cairo_surface_destroy(csrc);
|
||||
cairo_surface_destroy(cdst);
|
||||
#else
|
||||
WLog_WARN(TAG, "SmartScaling requested but compiled without libcairo support!");
|
||||
#endif
|
||||
}
|
||||
else
|
||||
{
|
||||
size_t i;
|
||||
const size_t baseSrcOffset = area->top * srcStride + area->left * 4;
|
||||
const size_t baseDstOffset = area->top * dstStride + area->left * 4;
|
||||
const size_t width = MIN(area->right - area->left, dstWidth - area->left);
|
||||
const size_t height = MIN(area->bottom - area->top, dstHeight - area->top);
|
||||
const BYTE* psrc = (const BYTE*)src;
|
||||
BYTE* pdst = (BYTE*)dst;
|
||||
|
||||
for (i = 0; i < height; i++)
|
||||
{
|
||||
const size_t srcOffset = i * srcStride + baseSrcOffset;
|
||||
const size_t dstOffset = i * dstStride + baseDstOffset;
|
||||
memcpy(&pdst[dstOffset], &psrc[srcOffset], width * 4);
|
||||
}
|
||||
|
||||
rc = TRUE;
|
||||
}
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
BOOL wlf_scale_coordinates(rdpContext* context, UINT32* px, UINT32* py)
|
||||
{
|
||||
wlfContext* wlf = (wlfContext*)context;
|
||||
rdpGdi* gdi;
|
||||
UwacSize geometry;
|
||||
double sx, sy;
|
||||
|
||||
if (!context || !px || !py || !context->gdi)
|
||||
return FALSE;
|
||||
|
||||
if (!context->settings->SmartSizing)
|
||||
return TRUE;
|
||||
|
||||
/* If libcairo is not compiled, smart scaling is ignored. */
|
||||
#if defined(CAIRO_FOUND)
|
||||
gdi = context->gdi;
|
||||
|
||||
if (UwacWindowGetDrawingBufferGeometry(wlf->window, &geometry, NULL) != UWAC_SUCCESS)
|
||||
return FALSE;
|
||||
|
||||
sx = geometry.width / (double)gdi->width;
|
||||
sy = geometry.height / (double)gdi->height;
|
||||
*px /= sx;
|
||||
*py /= sy;
|
||||
#endif
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
@@ -54,5 +54,10 @@ struct wlf_context
|
||||
wLog* log;
|
||||
};
|
||||
|
||||
BOOL wlf_scale_coordinates(rdpContext* context, UINT32* px, UINT32* py);
|
||||
BOOL wlf_copy_image(const void* src, size_t srcStride, size_t srcWidth, size_t srcHeight,
|
||||
void* dst, size_t dstStride, size_t dstWidth, size_t dstHeight,
|
||||
const RECTANGLE_16* area, BOOL scale);
|
||||
|
||||
#endif /* FREERDP_CLIENT_WAYLAND_FREERDP_H */
|
||||
|
||||
|
||||
24
cmake/FindCairo.cmake
Normal file
24
cmake/FindCairo.cmake
Normal file
@@ -0,0 +1,24 @@
|
||||
find_package(PkgConfig QUIET)
|
||||
pkg_check_modules(CAIRO QUIET libcairo)
|
||||
|
||||
find_path(CAIRO_INCLUDE_DIR
|
||||
NAMES cairo.h
|
||||
PATHS ${CAIRO_INCLUDE_DIRS}
|
||||
PATH_SUFFIXES cairo
|
||||
)
|
||||
|
||||
# Finally the library itself
|
||||
find_library(CAIRO_LIBRARY
|
||||
NAMES cairo
|
||||
PATHS ${CAIRO_LIBRARY_DIRS}
|
||||
)
|
||||
mark_as_advanced(CAIRO_INCLUDE_DIR)
|
||||
mark_as_advanced(CAIRO_LIBRARY)
|
||||
|
||||
include(FindPackageHandleStandardArgs)
|
||||
find_package_handle_standard_args(CAIRO
|
||||
REQUIRED_VARS
|
||||
CAIRO_LIBRARY CAIRO_INCLUDE_DIR
|
||||
VERSION_VAR
|
||||
CAIRO_VERSION_STRING
|
||||
HANDLE_COMPONENTS)
|
||||
@@ -27,6 +27,7 @@ Build-Depends:
|
||||
libxdamage-dev,
|
||||
libxtst-dev,
|
||||
libcups2-dev,
|
||||
libcairo2-dev,
|
||||
libpcsclite-dev,
|
||||
libasound2-dev,
|
||||
libpulse-dev,
|
||||
|
||||
@@ -40,6 +40,7 @@ BuildRequires: libXv-devel
|
||||
BuildRequires: libXdamage-devel
|
||||
BuildRequires: libXtst-devel
|
||||
BuildRequires: cups-devel
|
||||
BuildRequires: cairo-devel
|
||||
BuildRequires: pcsc-lite-devel
|
||||
BuildRequires: uuid-devel
|
||||
BuildRequires: libxml2-devel
|
||||
|
||||
Reference in New Issue
Block a user