2013-04-01 21:43:58 +00:00
|
|
|
/*
|
|
|
|
* Copyright © 2013 Hardening <rdp.effort@gmail.com>
|
|
|
|
*
|
2015-06-11 22:35:43 +00:00
|
|
|
* Permission is hereby granted, free of charge, to any person obtaining
|
|
|
|
* a copy of this software and associated documentation files (the
|
|
|
|
* "Software"), to deal in the Software without restriction, including
|
|
|
|
* without limitation the rights to use, copy, modify, merge, publish,
|
|
|
|
* distribute, sublicense, and/or sell copies of the Software, and to
|
|
|
|
* permit persons to whom the Software is furnished to do so, subject to
|
|
|
|
* the following conditions:
|
2013-04-01 21:43:58 +00:00
|
|
|
*
|
2015-06-11 22:35:43 +00:00
|
|
|
* The above copyright notice and this permission notice (including the
|
|
|
|
* next paragraph) shall be included in all copies or substantial
|
|
|
|
* portions of the Software.
|
|
|
|
*
|
|
|
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
|
|
|
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
|
|
|
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
|
|
|
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
|
|
|
|
* BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
|
|
|
|
* ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
|
|
|
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
|
|
* SOFTWARE.
|
2013-04-01 21:43:58 +00:00
|
|
|
*/
|
|
|
|
|
2013-05-22 15:03:19 +00:00
|
|
|
#include "config.h"
|
2013-04-01 21:43:58 +00:00
|
|
|
|
2016-09-30 12:11:08 +00:00
|
|
|
#include <assert.h>
|
2016-07-19 11:16:27 +00:00
|
|
|
#include <stdint.h>
|
2013-04-01 21:43:58 +00:00
|
|
|
#include <stdlib.h>
|
|
|
|
#include <string.h>
|
|
|
|
#include <errno.h>
|
|
|
|
#include <linux/input.h>
|
2022-04-29 12:22:41 +00:00
|
|
|
#include <unistd.h>
|
2013-04-01 21:43:58 +00:00
|
|
|
|
2022-03-11 17:36:01 +00:00
|
|
|
#include "rdp.h"
|
|
|
|
|
2013-04-06 21:39:26 +00:00
|
|
|
#include <winpr/input.h>
|
2017-09-27 10:01:10 +00:00
|
|
|
#include <winpr/ssl.h>
|
|
|
|
|
2017-11-24 16:01:46 +00:00
|
|
|
#include "shared/timespec-util.h"
|
2022-08-03 15:36:36 +00:00
|
|
|
#include "shared/xalloc.h"
|
2019-03-28 14:28:47 +00:00
|
|
|
#include <libweston/libweston.h>
|
2019-03-29 14:39:12 +00:00
|
|
|
#include <libweston/backend-rdp.h>
|
2013-04-01 21:43:58 +00:00
|
|
|
#include "pixman-renderer.h"
|
|
|
|
|
2022-05-09 13:16:59 +00:00
|
|
|
/* These can be removed when we bump FreeRDP dependency past 3.0.0 in the future */
|
2022-04-27 19:16:06 +00:00
|
|
|
#ifndef KBD_PERSIAN
|
|
|
|
#define KBD_PERSIAN 0x50429
|
|
|
|
#endif
|
2022-05-09 13:16:59 +00:00
|
|
|
#ifndef KBD_HEBREW_STANDARD
|
|
|
|
#define KBD_HEBREW_STANDARD 0x2040D
|
|
|
|
#endif
|
2022-04-27 19:16:06 +00:00
|
|
|
|
2022-05-10 17:28:58 +00:00
|
|
|
extern PWtsApiFunctionTable FreeRDP_InitWtsApi(void);
|
|
|
|
|
2022-08-09 18:52:51 +00:00
|
|
|
static BOOL
|
|
|
|
xf_peer_adjust_monitor_layout(freerdp_peer *client);
|
|
|
|
|
2022-08-03 14:45:30 +00:00
|
|
|
static struct rdp_output *
|
|
|
|
rdp_get_first_output(struct rdp_backend *b)
|
|
|
|
{
|
|
|
|
struct weston_output *output;
|
|
|
|
struct rdp_output *rdp_output;
|
|
|
|
|
|
|
|
wl_list_for_each(output, &b->compositor->output_list, link) {
|
|
|
|
rdp_output = to_rdp_output(output);
|
|
|
|
if (rdp_output)
|
|
|
|
return rdp_output;
|
|
|
|
}
|
|
|
|
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
2013-04-01 21:43:58 +00:00
|
|
|
static void
|
|
|
|
rdp_peer_refresh_rfx(pixman_region32_t *damage, pixman_image_t *image, freerdp_peer *peer)
|
|
|
|
{
|
|
|
|
int width, height, nrects, i;
|
|
|
|
pixman_box32_t *region, *rects;
|
|
|
|
uint32_t *ptr;
|
|
|
|
RFX_RECT *rfxRect;
|
2022-06-07 16:42:09 +00:00
|
|
|
rdpUpdate *update = peer->context->update;
|
2020-09-29 21:56:06 +00:00
|
|
|
SURFACE_BITS_COMMAND cmd = { 0 };
|
2013-04-01 21:43:58 +00:00
|
|
|
RdpPeerContext *context = (RdpPeerContext *)peer->context;
|
|
|
|
|
2013-05-22 21:40:16 +00:00
|
|
|
Stream_Clear(context->encode_stream);
|
|
|
|
Stream_SetPosition(context->encode_stream, 0);
|
2013-04-01 21:43:58 +00:00
|
|
|
|
|
|
|
width = (damage->extents.x2 - damage->extents.x1);
|
|
|
|
height = (damage->extents.y2 - damage->extents.y1);
|
|
|
|
|
2018-12-04 22:25:39 +00:00
|
|
|
cmd.skipCompression = TRUE;
|
2020-04-11 22:05:59 +00:00
|
|
|
cmd.cmdType = CMDTYPE_STREAM_SURFACE_BITS;
|
2018-12-04 22:25:39 +00:00
|
|
|
cmd.destLeft = damage->extents.x1;
|
|
|
|
cmd.destTop = damage->extents.y1;
|
|
|
|
cmd.destRight = damage->extents.x2;
|
|
|
|
cmd.destBottom = damage->extents.y2;
|
2020-09-29 21:56:06 +00:00
|
|
|
cmd.bmp.bpp = 32;
|
2022-06-07 16:42:09 +00:00
|
|
|
cmd.bmp.codecID = peer->context->settings->RemoteFxCodecId;
|
2020-09-29 21:56:06 +00:00
|
|
|
cmd.bmp.width = width;
|
|
|
|
cmd.bmp.height = height;
|
2013-04-01 21:43:58 +00:00
|
|
|
|
|
|
|
ptr = pixman_image_get_data(image) + damage->extents.x1 +
|
|
|
|
damage->extents.y1 * (pixman_image_get_stride(image) / sizeof(uint32_t));
|
|
|
|
|
|
|
|
rects = pixman_region32_rectangles(damage, &nrects);
|
|
|
|
context->rfx_rects = realloc(context->rfx_rects, nrects * sizeof *rfxRect);
|
|
|
|
|
|
|
|
for (i = 0; i < nrects; i++) {
|
|
|
|
region = &rects[i];
|
|
|
|
rfxRect = &context->rfx_rects[i];
|
|
|
|
|
|
|
|
rfxRect->x = (region->x1 - damage->extents.x1);
|
|
|
|
rfxRect->y = (region->y1 - damage->extents.y1);
|
|
|
|
rfxRect->width = (region->x2 - region->x1);
|
|
|
|
rfxRect->height = (region->y2 - region->y1);
|
|
|
|
}
|
|
|
|
|
|
|
|
rfx_compose_message(context->rfx_context, context->encode_stream, context->rfx_rects, nrects,
|
|
|
|
(BYTE *)ptr, width, height,
|
|
|
|
pixman_image_get_stride(image)
|
|
|
|
);
|
|
|
|
|
2020-09-29 21:56:06 +00:00
|
|
|
cmd.bmp.bitmapDataLength = Stream_GetPosition(context->encode_stream);
|
|
|
|
cmd.bmp.bitmapData = Stream_Buffer(context->encode_stream);
|
2013-04-01 21:43:58 +00:00
|
|
|
|
2018-12-04 22:25:39 +00:00
|
|
|
update->SurfaceBits(update->context, &cmd);
|
2013-04-01 21:43:58 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
static void
|
|
|
|
rdp_peer_refresh_nsc(pixman_region32_t *damage, pixman_image_t *image, freerdp_peer *peer)
|
|
|
|
{
|
|
|
|
int width, height;
|
|
|
|
uint32_t *ptr;
|
2022-06-07 16:42:09 +00:00
|
|
|
rdpUpdate *update = peer->context->update;
|
2020-09-29 21:56:06 +00:00
|
|
|
SURFACE_BITS_COMMAND cmd = { 0 };
|
2013-04-01 21:43:58 +00:00
|
|
|
RdpPeerContext *context = (RdpPeerContext *)peer->context;
|
|
|
|
|
2013-05-22 21:40:16 +00:00
|
|
|
Stream_Clear(context->encode_stream);
|
|
|
|
Stream_SetPosition(context->encode_stream, 0);
|
2013-04-01 21:43:58 +00:00
|
|
|
|
|
|
|
width = (damage->extents.x2 - damage->extents.x1);
|
|
|
|
height = (damage->extents.y2 - damage->extents.y1);
|
|
|
|
|
2020-04-11 22:05:59 +00:00
|
|
|
cmd.cmdType = CMDTYPE_SET_SURFACE_BITS;
|
2020-09-29 21:56:06 +00:00
|
|
|
cmd.skipCompression = TRUE;
|
2018-12-04 22:25:39 +00:00
|
|
|
cmd.destLeft = damage->extents.x1;
|
|
|
|
cmd.destTop = damage->extents.y1;
|
|
|
|
cmd.destRight = damage->extents.x2;
|
|
|
|
cmd.destBottom = damage->extents.y2;
|
2020-09-29 21:56:06 +00:00
|
|
|
cmd.bmp.bpp = 32;
|
2022-06-07 16:42:09 +00:00
|
|
|
cmd.bmp.codecID = peer->context->settings->NSCodecId;
|
2020-09-29 21:56:06 +00:00
|
|
|
cmd.bmp.width = width;
|
|
|
|
cmd.bmp.height = height;
|
2013-04-01 21:43:58 +00:00
|
|
|
|
|
|
|
ptr = pixman_image_get_data(image) + damage->extents.x1 +
|
|
|
|
damage->extents.y1 * (pixman_image_get_stride(image) / sizeof(uint32_t));
|
|
|
|
|
|
|
|
nsc_compose_message(context->nsc_context, context->encode_stream, (BYTE *)ptr,
|
2018-05-27 21:56:43 +00:00
|
|
|
width, height,
|
2013-04-01 21:43:58 +00:00
|
|
|
pixman_image_get_stride(image));
|
2018-05-27 21:56:43 +00:00
|
|
|
|
2020-09-29 21:56:06 +00:00
|
|
|
cmd.bmp.bitmapDataLength = Stream_GetPosition(context->encode_stream);
|
|
|
|
cmd.bmp.bitmapData = Stream_Buffer(context->encode_stream);
|
2018-05-27 21:56:43 +00:00
|
|
|
|
2018-12-04 22:25:39 +00:00
|
|
|
update->SurfaceBits(update->context, &cmd);
|
2013-04-01 21:43:58 +00:00
|
|
|
}
|
|
|
|
|
2013-05-22 21:40:20 +00:00
|
|
|
static void
|
2015-08-06 20:12:19 +00:00
|
|
|
pixman_image_flipped_subrect(const pixman_box32_t *rect, pixman_image_t *img, BYTE *dest)
|
|
|
|
{
|
2013-05-22 21:40:20 +00:00
|
|
|
int stride = pixman_image_get_stride(img);
|
|
|
|
int h;
|
|
|
|
int toCopy = (rect->x2 - rect->x1) * 4;
|
|
|
|
int height = (rect->y2 - rect->y1);
|
|
|
|
const BYTE *src = (const BYTE *)pixman_image_get_data(img);
|
|
|
|
src += ((rect->y2-1) * stride) + (rect->x1 * 4);
|
|
|
|
|
|
|
|
for (h = 0; h < height; h++, src -= stride, dest += toCopy)
|
|
|
|
memcpy(dest, src, toCopy);
|
|
|
|
}
|
|
|
|
|
2013-04-01 21:43:58 +00:00
|
|
|
static void
|
|
|
|
rdp_peer_refresh_raw(pixman_region32_t *region, pixman_image_t *image, freerdp_peer *peer)
|
|
|
|
{
|
2022-06-07 16:42:09 +00:00
|
|
|
rdpUpdate *update = peer->context->update;
|
2020-09-29 21:56:06 +00:00
|
|
|
SURFACE_BITS_COMMAND cmd = { 0 };
|
2018-12-04 22:25:39 +00:00
|
|
|
SURFACE_FRAME_MARKER marker;
|
2013-05-22 21:40:20 +00:00
|
|
|
pixman_box32_t *rect, subrect;
|
|
|
|
int nrects, i;
|
|
|
|
int heightIncrement, remainingHeight, top;
|
|
|
|
|
|
|
|
rect = pixman_region32_rectangles(region, &nrects);
|
|
|
|
if (!nrects)
|
|
|
|
return;
|
|
|
|
|
2018-12-04 22:25:39 +00:00
|
|
|
marker.frameId++;
|
|
|
|
marker.frameAction = SURFACECMD_FRAMEACTION_BEGIN;
|
|
|
|
update->SurfaceFrameMarker(peer->context, &marker);
|
2013-04-01 21:43:58 +00:00
|
|
|
|
2020-04-11 22:05:59 +00:00
|
|
|
cmd.cmdType = CMDTYPE_SET_SURFACE_BITS;
|
2020-09-29 21:56:06 +00:00
|
|
|
cmd.bmp.bpp = 32;
|
|
|
|
cmd.bmp.codecID = 0;
|
2013-05-22 21:40:20 +00:00
|
|
|
|
|
|
|
for (i = 0; i < nrects; i++, rect++) {
|
|
|
|
/*weston_log("rect(%d,%d, %d,%d)\n", rect->x1, rect->y1, rect->x2, rect->y2);*/
|
2018-12-04 22:25:39 +00:00
|
|
|
cmd.destLeft = rect->x1;
|
|
|
|
cmd.destRight = rect->x2;
|
2020-09-29 21:56:06 +00:00
|
|
|
cmd.bmp.width = (rect->x2 - rect->x1);
|
2013-05-22 21:40:20 +00:00
|
|
|
|
2022-06-07 16:42:09 +00:00
|
|
|
heightIncrement = peer->context->settings->MultifragMaxRequestSize / (16 + cmd.bmp.width * 4);
|
2013-05-22 21:40:20 +00:00
|
|
|
remainingHeight = rect->y2 - rect->y1;
|
|
|
|
top = rect->y1;
|
|
|
|
|
|
|
|
subrect.x1 = rect->x1;
|
|
|
|
subrect.x2 = rect->x2;
|
|
|
|
|
|
|
|
while (remainingHeight) {
|
2020-09-29 21:56:06 +00:00
|
|
|
cmd.bmp.height = (remainingHeight > heightIncrement) ? heightIncrement : remainingHeight;
|
2018-12-04 22:25:39 +00:00
|
|
|
cmd.destTop = top;
|
2020-09-29 21:56:06 +00:00
|
|
|
cmd.destBottom = top + cmd.bmp.height;
|
|
|
|
cmd.bmp.bitmapDataLength = cmd.bmp.width * cmd.bmp.height * 4;
|
|
|
|
cmd.bmp.bitmapData = (BYTE *)realloc(cmd.bmp.bitmapData, cmd.bmp.bitmapDataLength);
|
2013-05-22 21:40:20 +00:00
|
|
|
|
|
|
|
subrect.y1 = top;
|
2020-09-29 21:56:06 +00:00
|
|
|
subrect.y2 = top + cmd.bmp.height;
|
|
|
|
pixman_image_flipped_subrect(&subrect, image, cmd.bmp.bitmapData);
|
2013-05-22 21:40:20 +00:00
|
|
|
|
|
|
|
/*weston_log("* sending (%d,%d, %d,%d)\n", subrect.x1, subrect.y1, subrect.x2, subrect.y2); */
|
2018-12-04 22:25:39 +00:00
|
|
|
update->SurfaceBits(peer->context, &cmd);
|
2013-05-22 21:40:20 +00:00
|
|
|
|
2020-09-29 21:56:06 +00:00
|
|
|
remainingHeight -= cmd.bmp.height;
|
|
|
|
top += cmd.bmp.height;
|
2013-05-22 21:40:20 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-09-29 21:56:06 +00:00
|
|
|
free(cmd.bmp.bitmapData);
|
2019-06-17 10:33:35 +00:00
|
|
|
|
2018-12-04 22:25:39 +00:00
|
|
|
marker.frameAction = SURFACECMD_FRAMEACTION_END;
|
|
|
|
update->SurfaceFrameMarker(peer->context, &marker);
|
2013-04-01 21:43:58 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
rdp_peer_refresh_region(pixman_region32_t *region, freerdp_peer *peer)
|
|
|
|
{
|
|
|
|
RdpPeerContext *context = (RdpPeerContext *)peer->context;
|
2022-08-03 14:45:30 +00:00
|
|
|
struct rdp_output *output = rdp_get_first_output(context->rdpBackend);
|
2022-06-07 16:42:09 +00:00
|
|
|
rdpSettings *settings = peer->context->settings;
|
2013-05-22 21:40:20 +00:00
|
|
|
|
|
|
|
if (settings->RemoteFxCodec)
|
|
|
|
rdp_peer_refresh_rfx(region, output->shadow_surface, peer);
|
|
|
|
else if (settings->NSCodec)
|
|
|
|
rdp_peer_refresh_nsc(region, output->shadow_surface, peer);
|
|
|
|
else
|
2013-04-01 21:43:58 +00:00
|
|
|
rdp_peer_refresh_raw(region, output->shadow_surface, peer);
|
|
|
|
}
|
|
|
|
|
2019-06-30 13:51:10 +00:00
|
|
|
static int
|
2013-04-05 21:07:11 +00:00
|
|
|
rdp_output_start_repaint_loop(struct weston_output *output)
|
|
|
|
{
|
2014-09-24 02:08:45 +00:00
|
|
|
struct timespec ts;
|
2013-04-05 21:07:11 +00:00
|
|
|
|
2015-03-18 10:17:26 +00:00
|
|
|
weston_compositor_read_presentation_clock(output->compositor, &ts);
|
2016-02-18 14:53:27 +00:00
|
|
|
weston_output_finish_frame(output, &ts, WP_PRESENTATION_FEEDBACK_INVALID);
|
2019-06-30 13:51:10 +00:00
|
|
|
|
|
|
|
return 0;
|
2013-04-05 21:07:11 +00:00
|
|
|
}
|
2013-04-01 21:43:58 +00:00
|
|
|
|
2013-10-22 15:11:26 +00:00
|
|
|
static int
|
compositor: remove repaint_data from compositor
The repaint_data is entirely backend specific. Moreover, it is only used by the
drm backend, while other backends ignore the repaint data.
There will always be only one repaint active, thus, there is no need to pass the
repaint data from the outside.
The repaint_data breaks with the multi-backend series, which calls repaint begin
for all backends to get the repaint_data. The repaint_data of the last backend
will then be passed to all other backend. At the moment, this works, because the
drm backend is the only backend that implements the begin_repaint call.
Another option would be to track the repaint data per backend in the compositor,
but actually, it the backend needs to track state across the calls, it's its own
responsibility.
Signed-off-by: Michael Tretter <m.tretter@pengutronix.de>
2021-11-03 10:14:11 +00:00
|
|
|
rdp_output_repaint(struct weston_output *output_base, pixman_region32_t *damage)
|
2013-04-01 21:43:58 +00:00
|
|
|
{
|
|
|
|
struct rdp_output *output = container_of(output_base, struct rdp_output, base);
|
|
|
|
struct weston_compositor *ec = output->base.compositor;
|
2022-05-21 11:28:16 +00:00
|
|
|
struct rdp_backend *b = output->backend;
|
2022-07-12 14:39:05 +00:00
|
|
|
struct rdp_peers_item *peer;
|
2022-03-29 17:42:30 +00:00
|
|
|
struct timespec now, target;
|
|
|
|
int refresh_nsec = millihz_to_nsec(output_base->current_mode->refresh);
|
|
|
|
int refresh_msec = refresh_nsec / 1000000;
|
|
|
|
int next_frame_delta;
|
|
|
|
|
|
|
|
/* Calculate the time we should complete this frame such that frames
|
|
|
|
are spaced out by the specified monitor refresh. Note that our timer
|
|
|
|
mechanism only has msec precision, so we won't exactly hit our
|
|
|
|
target refresh rate.
|
|
|
|
*/
|
|
|
|
weston_compositor_read_presentation_clock(ec, &now);
|
|
|
|
|
|
|
|
timespec_add_nsec(&target, &output_base->frame_time, refresh_nsec);
|
|
|
|
|
|
|
|
next_frame_delta = (int)timespec_sub_to_msec(&target, &now);
|
|
|
|
if (next_frame_delta < 1 || next_frame_delta > refresh_msec) {
|
|
|
|
next_frame_delta = refresh_msec;
|
|
|
|
}
|
2013-04-01 21:43:58 +00:00
|
|
|
|
2021-03-11 10:27:17 +00:00
|
|
|
assert(output);
|
|
|
|
|
2013-04-01 21:43:58 +00:00
|
|
|
pixman_renderer_output_set_buffer(output_base, output->shadow_surface);
|
|
|
|
ec->renderer->repaint_output(&output->base, damage);
|
|
|
|
|
2014-03-20 21:34:30 +00:00
|
|
|
if (pixman_region32_not_empty(damage)) {
|
2022-08-09 12:50:35 +00:00
|
|
|
pixman_region32_t transformed_damage;
|
|
|
|
pixman_region32_init(&transformed_damage);
|
|
|
|
weston_region_global_to_output(&transformed_damage,
|
|
|
|
output_base,
|
|
|
|
damage);
|
2022-07-12 14:39:05 +00:00
|
|
|
wl_list_for_each(peer, &b->peers, link) {
|
|
|
|
if ((peer->flags & RDP_PEER_ACTIVATED) &&
|
2022-08-09 12:50:35 +00:00
|
|
|
(peer->flags & RDP_PEER_OUTPUT_ENABLED)) {
|
|
|
|
rdp_peer_refresh_region(&transformed_damage, peer->peer);
|
2014-03-20 21:34:30 +00:00
|
|
|
}
|
2013-04-01 21:43:58 +00:00
|
|
|
}
|
2022-08-09 12:50:35 +00:00
|
|
|
pixman_region32_fini(&transformed_damage);
|
2013-04-01 21:43:58 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
pixman_region32_subtract(&ec->primary_plane.damage,
|
|
|
|
&ec->primary_plane.damage, damage);
|
|
|
|
|
2022-03-29 17:42:30 +00:00
|
|
|
wl_event_source_timer_update(output->finish_frame_timer, next_frame_delta);
|
2013-10-22 15:11:26 +00:00
|
|
|
return 0;
|
2013-04-01 21:43:58 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
static int
|
|
|
|
finish_frame_handler(void *data)
|
|
|
|
{
|
compositor: set presentation.presented flags
Change weston_output_finish_frame() signature so that backends are
required to set the flags, that will be reported on the Presentation
'presented' event. This is meant for output-wide feedback flags. Flags
that vary per wl_surface are subject for the following patch.
All start_repaint_loop functions use the special private flag
PRESENTATION_FEEDBACK_INVALID to mark, that this call of
weston_output_finish_frame() cannot trigger the 'presented' event. If it
does, we now hit an assert, and should then investigate why a fake update
triggered Presentation feedback.
DRM:
Page flip is always vsync'd, and always gets the completion timestamp
from the kernel which should correspond well to hardware. Completion is
triggered by the kernel/hardware.
Vblank handler is only used with the broken planes path, therefore do
not report VSYNC, because we cannot guarantee all the planes updated at
the same time. We cannot set the INVALID, because it would abort the
compositor if the broken planes path was ever used. This is a hack that
will get fixed with nuclear pageflip support in the future.
fbdev:
No vsync, update done by copy, no completion event from hardware, and
completion time is totally fake.
headless:
No real output to update.
RDP:
Guessing that maybe no vsync, fake time, and copy make sense (pixels
sent over network). Also no event that the pixels have been shown?
RPI:
Presumably Dispmanx updates are vsync'd. We get a completion event from
the driver, but need to read the clock ourselves, so the completion time
is somewhat unreliable. Zero-copy flag not implemented though it would
be theoretically possible with EGL clients (zero-copy is a per-surface
flag anyway, so in this patch).
Wayland:
No information how the host compositor is doing updates, so make a safe
guess without assuming vsync or hardware completion event. While we do
get some timestamp from the host compositor, it is not the completion
time. Would need to hook to the Presentation extension of the host
compositor to get more accurate flags.
X11:
No idea about vsync, completion event, or copying. Also the timestamp is
a fake.
Signed-off-by: Pekka Paalanen <pekka.paalanen@collabora.co.uk>
Reviewed-by: Mario Kleiner <mario.kleiner.de@gmail.com>
Tested-by: Mario Kleiner <mario.kleiner.de@gmail.com>
Acked-by: Mario Kleiner <mario.kleiner.de@gmail.com>
2014-12-17 14:20:40 +00:00
|
|
|
struct rdp_output *output = data;
|
|
|
|
struct timespec ts;
|
|
|
|
|
2015-03-18 10:17:26 +00:00
|
|
|
weston_compositor_read_presentation_clock(output->base.compositor, &ts);
|
compositor: set presentation.presented flags
Change weston_output_finish_frame() signature so that backends are
required to set the flags, that will be reported on the Presentation
'presented' event. This is meant for output-wide feedback flags. Flags
that vary per wl_surface are subject for the following patch.
All start_repaint_loop functions use the special private flag
PRESENTATION_FEEDBACK_INVALID to mark, that this call of
weston_output_finish_frame() cannot trigger the 'presented' event. If it
does, we now hit an assert, and should then investigate why a fake update
triggered Presentation feedback.
DRM:
Page flip is always vsync'd, and always gets the completion timestamp
from the kernel which should correspond well to hardware. Completion is
triggered by the kernel/hardware.
Vblank handler is only used with the broken planes path, therefore do
not report VSYNC, because we cannot guarantee all the planes updated at
the same time. We cannot set the INVALID, because it would abort the
compositor if the broken planes path was ever used. This is a hack that
will get fixed with nuclear pageflip support in the future.
fbdev:
No vsync, update done by copy, no completion event from hardware, and
completion time is totally fake.
headless:
No real output to update.
RDP:
Guessing that maybe no vsync, fake time, and copy make sense (pixels
sent over network). Also no event that the pixels have been shown?
RPI:
Presumably Dispmanx updates are vsync'd. We get a completion event from
the driver, but need to read the clock ourselves, so the completion time
is somewhat unreliable. Zero-copy flag not implemented though it would
be theoretically possible with EGL clients (zero-copy is a per-surface
flag anyway, so in this patch).
Wayland:
No information how the host compositor is doing updates, so make a safe
guess without assuming vsync or hardware completion event. While we do
get some timestamp from the host compositor, it is not the completion
time. Would need to hook to the Presentation extension of the host
compositor to get more accurate flags.
X11:
No idea about vsync, completion event, or copying. Also the timestamp is
a fake.
Signed-off-by: Pekka Paalanen <pekka.paalanen@collabora.co.uk>
Reviewed-by: Mario Kleiner <mario.kleiner.de@gmail.com>
Tested-by: Mario Kleiner <mario.kleiner.de@gmail.com>
Acked-by: Mario Kleiner <mario.kleiner.de@gmail.com>
2014-12-17 14:20:40 +00:00
|
|
|
weston_output_finish_frame(&output->base, &ts, 0);
|
2013-04-01 21:43:58 +00:00
|
|
|
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
2014-03-20 21:34:30 +00:00
|
|
|
static struct weston_mode *
|
2015-08-06 20:12:19 +00:00
|
|
|
rdp_insert_new_mode(struct weston_output *output, int width, int height, int rate)
|
|
|
|
{
|
2014-03-20 21:34:30 +00:00
|
|
|
struct weston_mode *ret;
|
2022-08-04 16:42:25 +00:00
|
|
|
ret = xzalloc(sizeof *ret);
|
2014-03-20 21:34:30 +00:00
|
|
|
ret->width = width;
|
|
|
|
ret->height = height;
|
|
|
|
ret->refresh = rate;
|
2022-08-04 18:21:19 +00:00
|
|
|
ret->flags = WL_OUTPUT_MODE_PREFERRED;
|
2014-03-20 21:34:30 +00:00
|
|
|
wl_list_insert(&output->mode_list, &ret->link);
|
|
|
|
return ret;
|
|
|
|
}
|
2013-04-01 21:43:58 +00:00
|
|
|
|
2022-08-04 18:21:19 +00:00
|
|
|
/* It doesn't make sense for RDP to have more than one mode, so
|
|
|
|
* we make sure that we have only one.
|
|
|
|
*/
|
2013-04-01 21:43:58 +00:00
|
|
|
static struct weston_mode *
|
2022-08-04 18:21:19 +00:00
|
|
|
ensure_single_mode(struct weston_output *output, struct weston_mode *target)
|
2015-08-06 20:12:19 +00:00
|
|
|
{
|
2022-05-21 11:28:16 +00:00
|
|
|
struct rdp_output *rdpOutput = to_rdp_output(output);
|
|
|
|
struct rdp_backend *b = rdpOutput->backend;
|
2022-08-04 18:21:19 +00:00
|
|
|
struct weston_mode *iter, *local = NULL, *new_mode;
|
|
|
|
|
|
|
|
wl_list_for_each(iter, &output->mode_list, link) {
|
|
|
|
assert(!local);
|
2013-04-01 21:43:58 +00:00
|
|
|
|
2022-08-04 18:21:19 +00:00
|
|
|
if ((iter->width == target->width) &&
|
|
|
|
(iter->height == target->height) &&
|
|
|
|
(iter->refresh == target->refresh)) {
|
|
|
|
return iter;
|
|
|
|
} else {
|
|
|
|
local = iter;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
/* Make sure we create the new one before freeing the old one
|
|
|
|
* because some mode switch code uses pointer comparisons! If
|
|
|
|
* we freed the old mode first, malloc could theoretically give
|
|
|
|
* us back the same pointer.
|
|
|
|
*/
|
|
|
|
new_mode = rdp_insert_new_mode(output,
|
|
|
|
target->width, target->height,
|
|
|
|
b->rdp_monitor_refresh_rate);
|
|
|
|
if (local) {
|
|
|
|
wl_list_remove(&local->link);
|
|
|
|
free(local);
|
2013-04-01 21:43:58 +00:00
|
|
|
}
|
2014-03-20 21:34:30 +00:00
|
|
|
|
2022-08-04 18:21:19 +00:00
|
|
|
return new_mode;
|
2013-04-01 21:43:58 +00:00
|
|
|
}
|
|
|
|
|
2022-08-09 18:52:51 +00:00
|
|
|
static void
|
|
|
|
rdp_output_set_mode(struct weston_output *base, struct weston_mode *mode)
|
2015-08-06 20:12:19 +00:00
|
|
|
{
|
2022-08-09 18:52:51 +00:00
|
|
|
struct rdp_output *rdpOutput = container_of(base, struct rdp_output, base);
|
2022-05-21 11:28:16 +00:00
|
|
|
struct rdp_backend *b = rdpOutput->backend;
|
2022-08-09 18:52:51 +00:00
|
|
|
struct weston_mode *cur;
|
|
|
|
struct weston_output *output = base;
|
2013-04-01 21:43:58 +00:00
|
|
|
struct rdp_peers_item *rdpPeer;
|
|
|
|
rdpSettings *settings;
|
|
|
|
pixman_image_t *new_shadow_buffer;
|
|
|
|
|
2022-08-09 18:52:51 +00:00
|
|
|
mode->refresh = b->rdp_monitor_refresh_rate;
|
|
|
|
cur = ensure_single_mode(base, mode);
|
|
|
|
|
|
|
|
base->current_mode = cur;
|
|
|
|
base->native_mode = cur;
|
|
|
|
if (base->enabled) {
|
|
|
|
weston_renderer_resize_output(output, &(struct weston_size){
|
|
|
|
.width = output->current_mode->width,
|
|
|
|
.height = output->current_mode->height }, NULL);
|
|
|
|
|
|
|
|
new_shadow_buffer = pixman_image_create_bits(PIXMAN_x8r8g8b8, mode->width,
|
|
|
|
mode->height, 0, mode->width * 4);
|
|
|
|
pixman_image_composite32(PIXMAN_OP_SRC, rdpOutput->shadow_surface, 0, new_shadow_buffer,
|
|
|
|
0, 0, 0, 0, 0, 0, mode->width, mode->height);
|
|
|
|
pixman_image_unref(rdpOutput->shadow_surface);
|
|
|
|
rdpOutput->shadow_surface = new_shadow_buffer;
|
|
|
|
}
|
2013-04-01 21:43:58 +00:00
|
|
|
|
2022-08-09 18:52:51 +00:00
|
|
|
/* Apparently settings->DesktopWidth is supposed to be primary only.
|
|
|
|
* For now we only work with a single monitor, so we don't need to
|
|
|
|
* check that we're primary here.
|
|
|
|
*/
|
|
|
|
wl_list_for_each(rdpPeer, &b->peers, link) {
|
2022-06-07 16:42:09 +00:00
|
|
|
settings = rdpPeer->peer->context->settings;
|
2022-08-09 18:52:51 +00:00
|
|
|
if (settings->DesktopWidth == (uint32_t)mode->width &&
|
|
|
|
settings->DesktopHeight == (uint32_t)mode->height)
|
2014-03-20 21:34:30 +00:00
|
|
|
continue;
|
|
|
|
|
|
|
|
if (!settings->DesktopResize) {
|
2013-04-01 21:43:58 +00:00
|
|
|
/* too bad this peer does not support desktop resize */
|
2022-08-09 18:52:51 +00:00
|
|
|
weston_log("desktop resize is not allowed\n");
|
2013-04-01 21:43:58 +00:00
|
|
|
rdpPeer->peer->Close(rdpPeer->peer);
|
|
|
|
} else {
|
2022-08-09 18:52:51 +00:00
|
|
|
settings->DesktopWidth = mode->width;
|
|
|
|
settings->DesktopHeight = mode->height;
|
2022-06-07 16:42:09 +00:00
|
|
|
rdpPeer->peer->context->update->DesktopResize(rdpPeer->peer->context);
|
2013-04-01 21:43:58 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
static int
|
2022-08-09 18:52:51 +00:00
|
|
|
rdp_output_switch_mode(struct weston_output *base, struct weston_mode *mode)
|
2013-04-01 21:43:58 +00:00
|
|
|
{
|
2022-08-09 18:52:51 +00:00
|
|
|
rdp_output_set_mode(base, mode);
|
2013-04-01 21:43:58 +00:00
|
|
|
|
2022-08-09 18:52:51 +00:00
|
|
|
return 0;
|
|
|
|
}
|
2017-03-24 13:39:24 +00:00
|
|
|
|
2022-08-09 18:52:51 +00:00
|
|
|
static void
|
|
|
|
rdp_head_get_monitor(struct weston_head *base,
|
|
|
|
struct weston_rdp_monitor *monitor)
|
|
|
|
{
|
|
|
|
struct rdp_head *h = to_rdp_head(base);
|
2016-09-30 12:11:08 +00:00
|
|
|
|
2022-08-09 18:52:51 +00:00
|
|
|
monitor->x = h->config.x;
|
|
|
|
monitor->y = h->config.y;
|
|
|
|
monitor->width = h->config.width;
|
|
|
|
monitor->height = h->config.height;
|
|
|
|
monitor->desktop_scale = h->config.attributes.desktopScaleFactor;
|
2016-09-30 12:11:08 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
static int
|
|
|
|
rdp_output_enable(struct weston_output *base)
|
|
|
|
{
|
2023-01-11 20:28:52 +00:00
|
|
|
struct weston_renderer *renderer = base->compositor->renderer;
|
2016-09-30 12:11:08 +00:00
|
|
|
struct rdp_output *output = to_rdp_output(base);
|
2021-03-11 10:27:17 +00:00
|
|
|
struct rdp_backend *b;
|
2016-09-30 12:11:08 +00:00
|
|
|
struct wl_event_loop *loop;
|
2020-03-06 12:46:30 +00:00
|
|
|
const struct pixman_renderer_output_options options = {
|
2022-07-22 11:47:03 +00:00
|
|
|
.fb_size = {
|
|
|
|
.width = output->base.current_mode->width,
|
|
|
|
.height = output->base.current_mode->height
|
|
|
|
},
|
2020-03-06 12:46:30 +00:00
|
|
|
};
|
2016-09-30 12:11:08 +00:00
|
|
|
|
2021-03-11 10:27:17 +00:00
|
|
|
assert(output);
|
|
|
|
|
2022-05-21 11:28:16 +00:00
|
|
|
b = output->backend;
|
2021-03-11 10:27:17 +00:00
|
|
|
|
2013-04-01 21:43:58 +00:00
|
|
|
output->shadow_surface = pixman_image_create_bits(PIXMAN_x8r8g8b8,
|
2016-09-30 12:11:08 +00:00
|
|
|
output->base.current_mode->width,
|
|
|
|
output->base.current_mode->height,
|
|
|
|
NULL,
|
|
|
|
output->base.current_mode->width * 4);
|
2013-04-01 21:43:58 +00:00
|
|
|
if (output->shadow_surface == NULL) {
|
|
|
|
weston_log("Failed to create surface for frame buffer.\n");
|
2016-09-30 12:11:08 +00:00
|
|
|
return -1;
|
2013-04-01 21:43:58 +00:00
|
|
|
}
|
|
|
|
|
2023-01-11 20:28:52 +00:00
|
|
|
if (renderer->pixman->output_create(&output->base, &options) < 0) {
|
2016-09-30 12:11:08 +00:00
|
|
|
pixman_image_unref(output->shadow_surface);
|
|
|
|
return -1;
|
|
|
|
}
|
2013-04-01 21:43:58 +00:00
|
|
|
|
2014-10-11 15:27:30 +00:00
|
|
|
loop = wl_display_get_event_loop(b->compositor->wl_display);
|
2013-04-01 21:43:58 +00:00
|
|
|
output->finish_frame_timer = wl_event_loop_add_timer(loop, finish_frame_handler, output);
|
|
|
|
|
|
|
|
return 0;
|
2016-09-30 12:11:08 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
static int
|
|
|
|
rdp_output_disable(struct weston_output *base)
|
|
|
|
{
|
2023-01-11 20:28:52 +00:00
|
|
|
struct weston_renderer *renderer = base->compositor->renderer;
|
2016-09-30 12:11:08 +00:00
|
|
|
struct rdp_output *output = to_rdp_output(base);
|
2021-03-11 10:27:17 +00:00
|
|
|
|
|
|
|
assert(output);
|
|
|
|
|
2016-09-30 12:11:08 +00:00
|
|
|
if (!output->base.enabled)
|
|
|
|
return 0;
|
|
|
|
|
2016-09-30 12:11:15 +00:00
|
|
|
pixman_image_unref(output->shadow_surface);
|
2023-01-11 20:28:52 +00:00
|
|
|
renderer->pixman->output_destroy(&output->base);
|
2016-09-30 12:11:15 +00:00
|
|
|
|
2016-09-30 12:11:08 +00:00
|
|
|
wl_event_source_remove(output->finish_frame_timer);
|
2013-04-01 21:43:58 +00:00
|
|
|
|
2016-09-30 12:11:08 +00:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2021-03-11 10:27:17 +00:00
|
|
|
void
|
2016-09-30 12:11:08 +00:00
|
|
|
rdp_output_destroy(struct weston_output *base)
|
|
|
|
{
|
|
|
|
struct rdp_output *output = to_rdp_output(base);
|
|
|
|
|
2021-03-11 10:27:17 +00:00
|
|
|
assert(output);
|
|
|
|
|
2016-09-30 12:11:08 +00:00
|
|
|
rdp_output_disable(&output->base);
|
2017-08-16 09:07:14 +00:00
|
|
|
weston_output_release(&output->base);
|
2016-09-30 12:11:08 +00:00
|
|
|
|
2013-04-01 21:43:58 +00:00
|
|
|
free(output);
|
2016-09-30 12:11:08 +00:00
|
|
|
}
|
|
|
|
|
2017-10-12 13:21:26 +00:00
|
|
|
static struct weston_output *
|
2023-01-13 17:21:31 +00:00
|
|
|
rdp_output_create(struct weston_backend *backend, const char *name)
|
2016-09-30 12:11:08 +00:00
|
|
|
{
|
2023-01-13 17:21:31 +00:00
|
|
|
struct rdp_backend *b = container_of(backend, struct rdp_backend, base);
|
|
|
|
struct weston_compositor *compositor = b->compositor;
|
2016-09-30 12:11:08 +00:00
|
|
|
struct rdp_output *output;
|
|
|
|
|
2022-08-09 13:13:09 +00:00
|
|
|
output = xzalloc(sizeof *output);
|
2016-09-30 12:11:08 +00:00
|
|
|
|
2017-10-12 13:21:26 +00:00
|
|
|
weston_output_init(&output->base, compositor, name);
|
2017-04-03 10:18:13 +00:00
|
|
|
|
2016-09-30 12:11:08 +00:00
|
|
|
output->base.destroy = rdp_output_destroy;
|
|
|
|
output->base.disable = rdp_output_disable;
|
|
|
|
output->base.enable = rdp_output_enable;
|
2022-08-09 13:16:25 +00:00
|
|
|
|
|
|
|
output->base.start_repaint_loop = rdp_output_start_repaint_loop;
|
|
|
|
output->base.repaint = rdp_output_repaint;
|
2022-08-09 18:52:51 +00:00
|
|
|
output->base.switch_mode = rdp_output_switch_mode;
|
2016-09-30 12:11:08 +00:00
|
|
|
|
2022-05-21 11:28:16 +00:00
|
|
|
output->backend = b;
|
|
|
|
|
2016-09-30 12:11:08 +00:00
|
|
|
weston_compositor_add_pending_output(&output->base, compositor);
|
|
|
|
|
2017-10-12 13:21:26 +00:00
|
|
|
return &output->base;
|
|
|
|
}
|
|
|
|
|
2022-08-09 18:40:30 +00:00
|
|
|
void
|
|
|
|
rdp_head_create(struct weston_compositor *compositor, rdpMonitor *config)
|
2017-10-12 13:21:26 +00:00
|
|
|
{
|
2021-03-11 12:26:45 +00:00
|
|
|
struct rdp_backend *backend = to_rdp_backend(compositor);
|
2017-10-12 13:21:26 +00:00
|
|
|
struct rdp_head *head;
|
2022-08-09 18:40:30 +00:00
|
|
|
char name[13] = {}; /* "rdp-" + 8 chars for hex uint32_t + NULL. */
|
2017-10-12 13:21:26 +00:00
|
|
|
|
2022-08-09 13:08:57 +00:00
|
|
|
head = xzalloc(sizeof *head);
|
2022-08-09 18:40:30 +00:00
|
|
|
head->index = backend->head_index++;
|
|
|
|
if (config)
|
|
|
|
head->config = *config;
|
|
|
|
else {
|
|
|
|
/* Before any client conenctions we create a default head
|
|
|
|
* with no configuration. Make it the primary, and make
|
|
|
|
* it avoid the high dpi scaling paths.
|
|
|
|
*/
|
|
|
|
head->config.is_primary = true;
|
|
|
|
head->config.attributes.desktopScaleFactor = 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
sprintf(name, "rdp-%x", head->index);
|
2017-10-12 13:21:26 +00:00
|
|
|
|
|
|
|
weston_head_init(&head->base, name);
|
2022-08-03 21:04:00 +00:00
|
|
|
weston_head_set_monitor_strings(&head->base, "weston", "rdp", NULL);
|
|
|
|
|
2022-08-09 18:40:30 +00:00
|
|
|
if (config)
|
|
|
|
weston_head_set_physical_size(&head->base,
|
|
|
|
config->attributes.physicalWidth,
|
|
|
|
config->attributes.physicalHeight);
|
|
|
|
else
|
|
|
|
weston_head_set_physical_size(&head->base, 0, 0);
|
2021-03-11 10:27:17 +00:00
|
|
|
|
2021-03-11 12:26:45 +00:00
|
|
|
head->base.backend = &backend->base;
|
2021-03-11 10:27:17 +00:00
|
|
|
|
2017-10-12 13:21:26 +00:00
|
|
|
weston_head_set_connection_status(&head->base, true);
|
|
|
|
weston_compositor_add_head(compositor, &head->base);
|
2013-04-01 21:43:58 +00:00
|
|
|
}
|
|
|
|
|
2022-12-13 16:15:55 +00:00
|
|
|
void
|
2021-03-11 10:27:17 +00:00
|
|
|
rdp_head_destroy(struct weston_head *base)
|
2017-10-12 13:21:26 +00:00
|
|
|
{
|
2021-03-11 10:27:17 +00:00
|
|
|
struct rdp_head *head = to_rdp_head(base);
|
|
|
|
|
|
|
|
assert(head);
|
|
|
|
|
2017-10-12 13:21:26 +00:00
|
|
|
weston_head_release(&head->base);
|
|
|
|
free(head);
|
|
|
|
}
|
|
|
|
|
2021-03-11 12:26:45 +00:00
|
|
|
void
|
2023-01-13 17:21:31 +00:00
|
|
|
rdp_destroy(struct weston_backend *backend)
|
2013-04-01 21:43:58 +00:00
|
|
|
{
|
2023-01-13 17:21:31 +00:00
|
|
|
struct rdp_backend *b = container_of(backend, struct rdp_backend, base);
|
|
|
|
struct weston_compositor *ec = b->compositor;
|
2017-10-12 13:21:26 +00:00
|
|
|
struct weston_head *base, *next;
|
2019-06-20 15:39:36 +00:00
|
|
|
struct rdp_peers_item *rdp_peer, *tmp;
|
2015-08-05 20:21:28 +00:00
|
|
|
int i;
|
|
|
|
|
2022-07-12 14:39:05 +00:00
|
|
|
wl_list_for_each_safe(rdp_peer, tmp, &b->peers, link) {
|
2019-06-20 15:39:36 +00:00
|
|
|
freerdp_peer* client = rdp_peer->peer;
|
|
|
|
|
|
|
|
client->Disconnect(client);
|
|
|
|
freerdp_peer_context_free(client);
|
|
|
|
freerdp_peer_free(client);
|
|
|
|
}
|
|
|
|
|
2019-06-20 15:34:00 +00:00
|
|
|
for (i = 0; i < MAX_FREERDP_FDS; i++)
|
|
|
|
if (b->listener_events[i])
|
|
|
|
wl_event_source_remove(b->listener_events[i]);
|
|
|
|
|
2022-05-10 18:16:55 +00:00
|
|
|
if (b->clipboard_debug) {
|
|
|
|
weston_log_scope_destroy(b->clipboard_debug);
|
|
|
|
b->clipboard_debug = NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (b->clipboard_verbose) {
|
|
|
|
weston_log_scope_destroy(b->clipboard_verbose);
|
|
|
|
b->clipboard_verbose = NULL;
|
|
|
|
}
|
|
|
|
|
2022-03-11 19:29:11 +00:00
|
|
|
if (b->debug) {
|
|
|
|
weston_log_scope_destroy(b->debug);
|
|
|
|
b->debug = NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (b->verbose) {
|
|
|
|
weston_log_scope_destroy(b->verbose);
|
|
|
|
b->verbose = NULL;
|
|
|
|
}
|
|
|
|
|
2013-04-01 21:43:58 +00:00
|
|
|
weston_compositor_shutdown(ec);
|
2017-10-12 13:21:26 +00:00
|
|
|
|
2021-03-11 10:27:17 +00:00
|
|
|
wl_list_for_each_safe(base, next, &ec->head_list, compositor_link) {
|
|
|
|
if (to_rdp_head(base))
|
|
|
|
rdp_head_destroy(base);
|
|
|
|
}
|
2017-10-12 13:21:26 +00:00
|
|
|
|
2015-08-05 20:21:28 +00:00
|
|
|
freerdp_listener_free(b->listener);
|
2013-04-01 21:43:58 +00:00
|
|
|
|
2015-08-05 20:21:28 +00:00
|
|
|
free(b->server_cert);
|
|
|
|
free(b->server_key);
|
|
|
|
free(b->rdp_key);
|
|
|
|
free(b);
|
2013-04-01 21:43:58 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
static
|
2015-08-06 20:12:19 +00:00
|
|
|
int rdp_listener_activity(int fd, uint32_t mask, void *data)
|
|
|
|
{
|
2013-04-01 21:43:58 +00:00
|
|
|
freerdp_listener* instance = (freerdp_listener *)data;
|
|
|
|
|
|
|
|
if (!(mask & WL_EVENT_READABLE))
|
|
|
|
return 0;
|
2015-08-06 20:12:19 +00:00
|
|
|
if (!instance->CheckFileDescriptor(instance)) {
|
2013-04-01 21:43:58 +00:00
|
|
|
weston_log("failed to check FreeRDP file descriptor\n");
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
static
|
2015-08-06 20:12:19 +00:00
|
|
|
int rdp_implant_listener(struct rdp_backend *b, freerdp_listener* instance)
|
|
|
|
{
|
2013-04-01 21:43:58 +00:00
|
|
|
int i, fd;
|
2022-06-07 16:50:28 +00:00
|
|
|
int handle_count = 0;
|
|
|
|
HANDLE handles[MAX_FREERDP_FDS];
|
2013-04-01 21:43:58 +00:00
|
|
|
struct wl_event_loop *loop;
|
|
|
|
|
2022-06-07 16:50:28 +00:00
|
|
|
handle_count = instance->GetEventHandles(instance, handles, MAX_FREERDP_FDS);
|
|
|
|
if (!handle_count) {
|
|
|
|
weston_log("Failed to get FreeRDP handles\n");
|
2013-04-01 21:43:58 +00:00
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
2014-10-11 15:27:30 +00:00
|
|
|
loop = wl_display_get_event_loop(b->compositor->wl_display);
|
2022-06-07 16:50:28 +00:00
|
|
|
for (i = 0; i < handle_count; i++) {
|
|
|
|
fd = GetEventFileDescriptor(handles[i]);
|
2014-10-11 15:27:30 +00:00
|
|
|
b->listener_events[i] = wl_event_loop_add_fd(loop, fd, WL_EVENT_READABLE,
|
2013-04-01 21:43:58 +00:00
|
|
|
rdp_listener_activity, instance);
|
|
|
|
}
|
|
|
|
|
2015-08-06 20:12:19 +00:00
|
|
|
for ( ; i < MAX_FREERDP_FDS; i++)
|
2014-10-11 15:27:30 +00:00
|
|
|
b->listener_events[i] = 0;
|
2013-04-01 21:43:58 +00:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2020-09-29 21:56:06 +00:00
|
|
|
static BOOL
|
2013-04-01 21:43:58 +00:00
|
|
|
rdp_peer_context_new(freerdp_peer* client, RdpPeerContext* context)
|
|
|
|
{
|
|
|
|
context->item.peer = client;
|
2013-08-16 22:30:31 +00:00
|
|
|
context->item.flags = RDP_PEER_OUTPUT_ENABLED;
|
2013-04-01 21:43:58 +00:00
|
|
|
|
2022-04-29 12:22:41 +00:00
|
|
|
context->loop_task_event_source_fd = -1;
|
|
|
|
context->loop_task_event_source = NULL;
|
|
|
|
wl_list_init(&context->loop_task_list);
|
|
|
|
|
2014-01-10 10:33:06 +00:00
|
|
|
context->rfx_context = rfx_context_new(TRUE);
|
2020-09-29 21:56:06 +00:00
|
|
|
if (!context->rfx_context)
|
|
|
|
return FALSE;
|
2016-04-26 21:34:05 +00:00
|
|
|
|
2013-04-01 21:43:58 +00:00
|
|
|
context->rfx_context->mode = RLGR3;
|
2022-06-07 16:42:09 +00:00
|
|
|
context->rfx_context->width = client->context->settings->DesktopWidth;
|
|
|
|
context->rfx_context->height = client->context->settings->DesktopHeight;
|
2017-01-20 11:53:34 +00:00
|
|
|
rfx_context_set_pixel_format(context->rfx_context, DEFAULT_PIXEL_FORMAT);
|
2013-04-01 21:43:58 +00:00
|
|
|
|
|
|
|
context->nsc_context = nsc_context_new();
|
2016-04-26 21:34:05 +00:00
|
|
|
if (!context->nsc_context)
|
|
|
|
goto out_error_nsc;
|
|
|
|
|
2020-04-11 22:05:59 +00:00
|
|
|
nsc_context_set_parameters(context->nsc_context, NSC_COLOR_FORMAT, DEFAULT_PIXEL_FORMAT);
|
2013-05-22 21:40:16 +00:00
|
|
|
context->encode_stream = Stream_New(NULL, 65536);
|
2016-04-26 21:34:05 +00:00
|
|
|
if (!context->encode_stream)
|
|
|
|
goto out_error_stream;
|
|
|
|
|
2020-09-29 21:56:06 +00:00
|
|
|
return TRUE;
|
2016-04-26 21:34:05 +00:00
|
|
|
|
|
|
|
out_error_nsc:
|
|
|
|
rfx_context_free(context->rfx_context);
|
|
|
|
out_error_stream:
|
|
|
|
nsc_context_free(context->nsc_context);
|
2020-09-29 21:56:06 +00:00
|
|
|
return FALSE;
|
2013-04-01 21:43:58 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
rdp_peer_context_free(freerdp_peer* client, RdpPeerContext* context)
|
|
|
|
{
|
2022-05-17 21:16:24 +00:00
|
|
|
struct rdp_backend *b;
|
2022-05-10 17:28:58 +00:00
|
|
|
unsigned i;
|
2022-05-17 21:16:24 +00:00
|
|
|
|
2014-03-20 21:34:30 +00:00
|
|
|
if (!context)
|
2013-04-01 21:43:58 +00:00
|
|
|
return;
|
|
|
|
|
2022-05-17 21:16:24 +00:00
|
|
|
b = context->rdpBackend;
|
|
|
|
|
2013-04-01 21:43:58 +00:00
|
|
|
wl_list_remove(&context->item.link);
|
2022-05-10 17:28:58 +00:00
|
|
|
|
|
|
|
for (i = 0; i < ARRAY_LENGTH(context->events); i++) {
|
2013-05-26 21:34:00 +00:00
|
|
|
if (context->events[i])
|
2013-04-01 21:43:58 +00:00
|
|
|
wl_event_source_remove(context->events[i]);
|
|
|
|
}
|
|
|
|
|
2022-05-17 21:16:24 +00:00
|
|
|
if (context->audio_in_private)
|
|
|
|
b->audio_in_teardown(context->audio_in_private);
|
|
|
|
|
|
|
|
if (context->audio_out_private)
|
|
|
|
b->audio_out_teardown(context->audio_out_private);
|
|
|
|
|
2022-05-10 18:16:55 +00:00
|
|
|
rdp_clipboard_destroy(context);
|
|
|
|
|
2022-05-10 17:28:58 +00:00
|
|
|
if (context->vcm)
|
|
|
|
WTSCloseServer(context->vcm);
|
|
|
|
|
2022-04-29 12:22:41 +00:00
|
|
|
rdp_destroy_dispatch_task_event_source(context);
|
|
|
|
|
2014-03-20 21:34:30 +00:00
|
|
|
if (context->item.flags & RDP_PEER_ACTIVATED) {
|
2016-05-27 21:22:56 +00:00
|
|
|
weston_seat_release_keyboard(context->item.seat);
|
|
|
|
weston_seat_release_pointer(context->item.seat);
|
2019-06-20 15:41:16 +00:00
|
|
|
weston_seat_release(context->item.seat);
|
|
|
|
free(context->item.seat);
|
2013-12-21 22:19:11 +00:00
|
|
|
}
|
2015-05-11 21:19:02 +00:00
|
|
|
|
2013-05-22 21:40:16 +00:00
|
|
|
Stream_Free(context->encode_stream, TRUE);
|
2013-04-01 21:43:58 +00:00
|
|
|
nsc_context_free(context->nsc_context);
|
|
|
|
rfx_context_free(context->rfx_context);
|
|
|
|
free(context->rfx_rects);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
static int
|
2015-08-06 20:12:19 +00:00
|
|
|
rdp_client_activity(int fd, uint32_t mask, void *data)
|
|
|
|
{
|
2013-04-01 21:43:58 +00:00
|
|
|
freerdp_peer* client = (freerdp_peer *)data;
|
2022-05-10 17:28:58 +00:00
|
|
|
RdpPeerContext *peerCtx = (RdpPeerContext *)client->context;
|
2013-04-01 21:43:58 +00:00
|
|
|
|
|
|
|
if (!client->CheckFileDescriptor(client)) {
|
|
|
|
weston_log("unable to checkDescriptor for %p\n", client);
|
|
|
|
goto out_clean;
|
|
|
|
}
|
2022-05-10 17:28:58 +00:00
|
|
|
|
|
|
|
if (peerCtx && peerCtx->vcm)
|
|
|
|
{
|
|
|
|
if (!WTSVirtualChannelManagerCheckFileDescriptor(peerCtx->vcm)) {
|
|
|
|
weston_log("failed to check FreeRDP WTS VC file descriptor for %p\n", client);
|
|
|
|
goto out_clean;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2013-04-01 21:43:58 +00:00
|
|
|
return 0;
|
|
|
|
|
|
|
|
out_clean:
|
|
|
|
freerdp_peer_context_free(client);
|
|
|
|
freerdp_peer_free(client);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
static BOOL
|
|
|
|
xf_peer_capabilities(freerdp_peer* client)
|
|
|
|
{
|
|
|
|
return TRUE;
|
|
|
|
}
|
|
|
|
|
|
|
|
struct rdp_to_xkb_keyboard_layout {
|
2013-04-06 21:39:26 +00:00
|
|
|
UINT32 rdpLayoutCode;
|
2014-04-11 07:49:57 +00:00
|
|
|
const char *xkbLayout;
|
|
|
|
const char *xkbVariant;
|
2013-04-01 21:43:58 +00:00
|
|
|
};
|
|
|
|
|
2014-04-11 07:49:57 +00:00
|
|
|
/* table reversed from
|
|
|
|
https://github.com/awakecoding/FreeRDP/blob/master/libfreerdp/locale/xkb_layout_ids.c#L811 */
|
2019-06-20 20:45:02 +00:00
|
|
|
static const
|
2014-04-11 07:49:57 +00:00
|
|
|
struct rdp_to_xkb_keyboard_layout rdp_keyboards[] = {
|
|
|
|
{KBD_ARABIC_101, "ara", 0},
|
|
|
|
{KBD_BULGARIAN, 0, 0},
|
|
|
|
{KBD_CHINESE_TRADITIONAL_US, 0},
|
|
|
|
{KBD_CZECH, "cz", 0},
|
|
|
|
{KBD_CZECH_PROGRAMMERS, "cz", "bksl"},
|
|
|
|
{KBD_CZECH_QWERTY, "cz", "qwerty"},
|
|
|
|
{KBD_DANISH, "dk", 0},
|
|
|
|
{KBD_GERMAN, "de", 0},
|
|
|
|
{KBD_GERMAN_NEO, "de", "neo"},
|
|
|
|
{KBD_GERMAN_IBM, "de", "qwerty"},
|
|
|
|
{KBD_GREEK, "gr", 0},
|
|
|
|
{KBD_GREEK_220, "gr", "simple"},
|
|
|
|
{KBD_GREEK_319, "gr", "extended"},
|
|
|
|
{KBD_GREEK_POLYTONIC, "gr", "polytonic"},
|
|
|
|
{KBD_US, "us", 0},
|
2022-05-09 13:18:56 +00:00
|
|
|
{KBD_UNITED_STATES_INTERNATIONAL, "us", "intl"},
|
2014-04-11 07:49:57 +00:00
|
|
|
{KBD_US_ENGLISH_TABLE_FOR_IBM_ARABIC_238_L, "ara", "buckwalter"},
|
|
|
|
{KBD_SPANISH, "es", 0},
|
|
|
|
{KBD_SPANISH_VARIATION, "es", "nodeadkeys"},
|
|
|
|
{KBD_FINNISH, "fi", 0},
|
|
|
|
{KBD_FRENCH, "fr", 0},
|
|
|
|
{KBD_HEBREW, "il", 0},
|
2022-05-09 13:16:59 +00:00
|
|
|
{KBD_HEBREW_STANDARD, "il", "basic"},
|
2014-04-11 07:49:57 +00:00
|
|
|
{KBD_HUNGARIAN, "hu", 0},
|
|
|
|
{KBD_HUNGARIAN_101_KEY, "hu", "standard"},
|
|
|
|
{KBD_ICELANDIC, "is", 0},
|
|
|
|
{KBD_ITALIAN, "it", 0},
|
|
|
|
{KBD_ITALIAN_142, "it", "nodeadkeys"},
|
|
|
|
{KBD_JAPANESE, "jp", 0},
|
2022-03-10 22:18:57 +00:00
|
|
|
{KBD_JAPANESE_INPUT_SYSTEM_MS_IME2002, "jp", 0},
|
2014-04-11 07:49:57 +00:00
|
|
|
{KBD_KOREAN, "kr", 0},
|
|
|
|
{KBD_KOREAN_INPUT_SYSTEM_IME_2000, "kr", "kr104"},
|
|
|
|
{KBD_DUTCH, "nl", 0},
|
|
|
|
{KBD_NORWEGIAN, "no", 0},
|
|
|
|
{KBD_POLISH_PROGRAMMERS, "pl", 0},
|
|
|
|
{KBD_POLISH_214, "pl", "qwertz"},
|
|
|
|
{KBD_ROMANIAN, "ro", 0},
|
|
|
|
{KBD_RUSSIAN, "ru", 0},
|
|
|
|
{KBD_RUSSIAN_TYPEWRITER, "ru", "typewriter"},
|
|
|
|
{KBD_CROATIAN, "hr", 0},
|
|
|
|
{KBD_SLOVAK, "sk", 0},
|
|
|
|
{KBD_SLOVAK_QWERTY, "sk", "qwerty"},
|
|
|
|
{KBD_ALBANIAN, 0, 0},
|
|
|
|
{KBD_SWEDISH, "se", 0},
|
|
|
|
{KBD_THAI_KEDMANEE, "th", 0},
|
|
|
|
{KBD_THAI_KEDMANEE_NON_SHIFTLOCK, "th", "tis"},
|
|
|
|
{KBD_TURKISH_Q, "tr", 0},
|
|
|
|
{KBD_TURKISH_F, "tr", "f"},
|
|
|
|
{KBD_URDU, "in", "urd-phonetic3"},
|
|
|
|
{KBD_UKRAINIAN, "ua", 0},
|
|
|
|
{KBD_BELARUSIAN, "by", 0},
|
|
|
|
{KBD_SLOVENIAN, "si", 0},
|
|
|
|
{KBD_ESTONIAN, "ee", 0},
|
|
|
|
{KBD_LATVIAN, "lv", 0},
|
|
|
|
{KBD_LITHUANIAN_IBM, "lt", "ibm"},
|
2022-04-27 19:22:10 +00:00
|
|
|
{KBD_FARSI, "ir", "pes"},
|
2022-04-27 19:16:06 +00:00
|
|
|
{KBD_PERSIAN, "af", "basic"},
|
2014-04-11 07:49:57 +00:00
|
|
|
{KBD_VIETNAMESE, "vn", 0},
|
|
|
|
{KBD_ARMENIAN_EASTERN, "am", 0},
|
|
|
|
{KBD_AZERI_LATIN, 0, 0},
|
|
|
|
{KBD_FYRO_MACEDONIAN, "mk", 0},
|
|
|
|
{KBD_GEORGIAN, "ge", 0},
|
|
|
|
{KBD_FAEROESE, 0, 0},
|
|
|
|
{KBD_DEVANAGARI_INSCRIPT, 0, 0},
|
|
|
|
{KBD_MALTESE_47_KEY, 0, 0},
|
|
|
|
{KBD_NORWEGIAN_WITH_SAMI, "no", "smi"},
|
|
|
|
{KBD_KAZAKH, "kz", 0},
|
|
|
|
{KBD_KYRGYZ_CYRILLIC, "kg", "phonetic"},
|
|
|
|
{KBD_TATAR, "ru", "tt"},
|
|
|
|
{KBD_BENGALI, "bd", 0},
|
|
|
|
{KBD_BENGALI_INSCRIPT, "bd", "probhat"},
|
|
|
|
{KBD_PUNJABI, 0, 0},
|
|
|
|
{KBD_GUJARATI, "in", "guj"},
|
|
|
|
{KBD_TAMIL, "in", "tam"},
|
|
|
|
{KBD_TELUGU, "in", "tel"},
|
|
|
|
{KBD_KANNADA, "in", "kan"},
|
|
|
|
{KBD_MALAYALAM, "in", "mal"},
|
|
|
|
{KBD_HINDI_TRADITIONAL, "in", 0},
|
|
|
|
{KBD_MARATHI, 0, 0},
|
|
|
|
{KBD_MONGOLIAN_CYRILLIC, "mn", 0},
|
|
|
|
{KBD_UNITED_KINGDOM_EXTENDED, "gb", "intl"},
|
|
|
|
{KBD_SYRIAC, "syc", 0},
|
|
|
|
{KBD_SYRIAC_PHONETIC, "syc", "syc_phonetic"},
|
|
|
|
{KBD_NEPALI, "np", 0},
|
|
|
|
{KBD_PASHTO, "af", "ps"},
|
|
|
|
{KBD_DIVEHI_PHONETIC, 0, 0},
|
|
|
|
{KBD_LUXEMBOURGISH, 0, 0},
|
|
|
|
{KBD_MAORI, "mao", 0},
|
|
|
|
{KBD_CHINESE_SIMPLIFIED_US, 0, 0},
|
|
|
|
{KBD_SWISS_GERMAN, "ch", "de_nodeadkeys"},
|
|
|
|
{KBD_UNITED_KINGDOM, "gb", 0},
|
|
|
|
{KBD_LATIN_AMERICAN, "latam", 0},
|
|
|
|
{KBD_BELGIAN_FRENCH, "be", 0},
|
|
|
|
{KBD_BELGIAN_PERIOD, "be", "oss_sundeadkeys"},
|
|
|
|
{KBD_PORTUGUESE, "pt", 0},
|
|
|
|
{KBD_SERBIAN_LATIN, "rs", 0},
|
|
|
|
{KBD_AZERI_CYRILLIC, "az", "cyrillic"},
|
|
|
|
{KBD_SWEDISH_WITH_SAMI, "se", "smi"},
|
|
|
|
{KBD_UZBEK_CYRILLIC, "af", "uz"},
|
|
|
|
{KBD_INUKTITUT_LATIN, "ca", "ike"},
|
|
|
|
{KBD_CANADIAN_FRENCH_LEGACY, "ca", "fr-legacy"},
|
|
|
|
{KBD_SERBIAN_CYRILLIC, "rs", 0},
|
|
|
|
{KBD_CANADIAN_FRENCH, "ca", "fr-legacy"},
|
|
|
|
{KBD_SWISS_FRENCH, "ch", "fr"},
|
|
|
|
{KBD_BOSNIAN, "ba", 0},
|
|
|
|
{KBD_IRISH, 0, 0},
|
|
|
|
{KBD_BOSNIAN_CYRILLIC, "ba", "us"},
|
|
|
|
{KBD_UNITED_STATES_DVORAK, "us", "dvorak"},
|
2022-04-27 19:17:02 +00:00
|
|
|
{KBD_PORTUGUESE_BRAZILIAN_ABNT2, "br", "abnt2"},
|
2014-04-11 07:49:57 +00:00
|
|
|
{KBD_CANADIAN_MULTILINGUAL_STANDARD, "ca", "multix"},
|
|
|
|
{KBD_GAELIC, "ie", "CloGaelach"},
|
|
|
|
|
|
|
|
{0x00000000, 0, 0},
|
2013-04-01 21:43:58 +00:00
|
|
|
};
|
|
|
|
|
2022-03-22 16:57:42 +00:00
|
|
|
void
|
|
|
|
convert_rdp_keyboard_to_xkb_rule_names(UINT32 KeyboardType,
|
|
|
|
UINT32 KeyboardSubType,
|
|
|
|
UINT32 KeyboardLayout,
|
|
|
|
struct xkb_rule_names *xkbRuleNames)
|
|
|
|
{
|
|
|
|
int i;
|
|
|
|
|
|
|
|
memset(xkbRuleNames, 0, sizeof(*xkbRuleNames));
|
|
|
|
xkbRuleNames->model = "pc105";
|
|
|
|
for (i = 0; rdp_keyboards[i].rdpLayoutCode; i++) {
|
|
|
|
if (rdp_keyboards[i].rdpLayoutCode == KeyboardLayout) {
|
|
|
|
xkbRuleNames->layout = rdp_keyboards[i].xkbLayout;
|
|
|
|
xkbRuleNames->variant = rdp_keyboards[i].xkbVariant;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-04-27 19:32:09 +00:00
|
|
|
/* Korean keyboard support (KeyboardType 8, LangID 0x412) */
|
|
|
|
if (KeyboardType == KBD_TYPE_KOREAN && ((KeyboardLayout & 0xFFFF) == 0x412)) {
|
|
|
|
/* TODO: PC/AT 101 Enhanced Korean Keyboard (Type B) and (Type C) are not supported yet
|
|
|
|
because default Xkb settings for Korean layout don't have corresponding
|
|
|
|
configuration.
|
|
|
|
(Type B): KeyboardSubType:4: rctrl_hangul/ratl_hanja
|
|
|
|
(Type C): KeyboardSubType:5: shift_space_hangul/crtl_space_hanja
|
|
|
|
*/
|
|
|
|
if (KeyboardSubType == 0 ||
|
|
|
|
KeyboardSubType == 3) /* PC/AT 101 Enhanced Korean Keyboard (Type A) */
|
|
|
|
xkbRuleNames->variant = "kr104"; /* kr(ralt_hangul)/kr(rctrl_hanja) */
|
|
|
|
else if (KeyboardSubType == 6) /* PC/AT 103 Enhanced Korean Keyboard */
|
|
|
|
xkbRuleNames->variant = "kr106"; /* kr(hw_keys) */
|
2022-04-27 19:33:17 +00:00
|
|
|
} else if (KeyboardType != KBD_TYPE_JAPANESE && ((KeyboardLayout & 0xFFFF) == 0x411)) {
|
|
|
|
/* when Japanese keyboard layout is used without a Japanese 106/109
|
|
|
|
* keyboard (keyboard type 7), use the "us" layout, since the "jp"
|
|
|
|
* layout in xkb expects the Japanese 106/109 keyboard layout.
|
|
|
|
*/
|
|
|
|
xkbRuleNames->layout = "us";
|
|
|
|
xkbRuleNames->variant = 0;
|
2022-04-27 19:32:09 +00:00
|
|
|
}
|
2022-04-27 19:33:17 +00:00
|
|
|
|
2022-05-12 15:14:11 +00:00
|
|
|
weston_log("%s: matching model=%s layout=%s variant=%s\n",
|
2022-03-22 16:57:42 +00:00
|
|
|
__func__, xkbRuleNames->model, xkbRuleNames->layout,
|
2022-05-12 15:14:11 +00:00
|
|
|
xkbRuleNames->variant);
|
2022-03-22 16:57:42 +00:00
|
|
|
}
|
|
|
|
|
2022-08-09 12:47:17 +00:00
|
|
|
static void
|
|
|
|
rdp_full_refresh(freerdp_peer *peer, struct rdp_output *output)
|
|
|
|
{
|
|
|
|
pixman_box32_t box;
|
|
|
|
pixman_region32_t damage;
|
|
|
|
|
|
|
|
box.x1 = 0;
|
|
|
|
box.y1 = 0;
|
|
|
|
box.x2 = output->base.current_mode->width;
|
|
|
|
box.y2 = output->base.current_mode->height;
|
|
|
|
pixman_region32_init_with_extents(&damage, &box);
|
|
|
|
|
|
|
|
rdp_peer_refresh_region(&damage, peer);
|
|
|
|
|
|
|
|
pixman_region32_fini(&damage);
|
|
|
|
}
|
|
|
|
|
2013-04-01 21:43:58 +00:00
|
|
|
static BOOL
|
2015-05-11 21:19:02 +00:00
|
|
|
xf_peer_activate(freerdp_peer* client)
|
2013-04-01 21:43:58 +00:00
|
|
|
{
|
|
|
|
RdpPeerContext *peerCtx;
|
2014-10-11 15:27:30 +00:00
|
|
|
struct rdp_backend *b;
|
2013-04-01 21:43:58 +00:00
|
|
|
struct rdp_output *output;
|
|
|
|
rdpSettings *settings;
|
2013-05-22 21:40:19 +00:00
|
|
|
rdpPointerUpdate *pointer;
|
2015-05-11 21:19:02 +00:00
|
|
|
struct rdp_peers_item *peersItem;
|
2013-04-01 21:43:58 +00:00
|
|
|
struct xkb_rule_names xkbRuleNames;
|
|
|
|
struct xkb_keymap *keymap;
|
2016-05-01 21:32:07 +00:00
|
|
|
struct weston_output *weston_output;
|
2015-05-11 21:19:02 +00:00
|
|
|
char seat_name[50];
|
2018-12-04 22:25:39 +00:00
|
|
|
POINTER_SYSTEM_UPDATE pointer_system;
|
2022-08-09 13:18:35 +00:00
|
|
|
int width, height;
|
2013-04-01 21:43:58 +00:00
|
|
|
|
|
|
|
peerCtx = (RdpPeerContext *)client->context;
|
2014-10-11 15:27:30 +00:00
|
|
|
b = peerCtx->rdpBackend;
|
2015-05-11 21:19:02 +00:00
|
|
|
peersItem = &peerCtx->item;
|
2022-08-03 16:38:55 +00:00
|
|
|
output = rdp_get_first_output(b);
|
2022-06-07 16:42:09 +00:00
|
|
|
settings = client->context->settings;
|
2013-04-01 21:43:58 +00:00
|
|
|
|
2013-09-18 21:56:36 +00:00
|
|
|
if (!settings->SurfaceCommandsEnabled) {
|
2013-04-01 21:43:58 +00:00
|
|
|
weston_log("client doesn't support required SurfaceCommands\n");
|
|
|
|
return FALSE;
|
|
|
|
}
|
|
|
|
|
2019-06-20 14:27:27 +00:00
|
|
|
if (b->force_no_compression && settings->CompressionEnabled) {
|
2022-03-11 19:29:11 +00:00
|
|
|
rdp_debug(b, "Forcing compression off\n");
|
2019-06-20 14:27:27 +00:00
|
|
|
settings->CompressionEnabled = FALSE;
|
|
|
|
}
|
|
|
|
|
2022-05-17 21:16:24 +00:00
|
|
|
settings->AudioPlayback = b->audio_out_setup && b->audio_out_teardown;
|
|
|
|
settings->AudioCapture = b->audio_in_setup && b->audio_in_teardown;
|
|
|
|
|
|
|
|
if (settings->RedirectClipboard ||
|
|
|
|
settings->AudioPlayback ||
|
|
|
|
settings->AudioCapture) {
|
2022-05-10 18:16:55 +00:00
|
|
|
if (!peerCtx->vcm) {
|
2022-05-17 21:16:24 +00:00
|
|
|
weston_log("Virtual channel is required for clipboard, audio playback/capture\n");
|
2022-05-10 18:16:55 +00:00
|
|
|
goto error_exit;
|
|
|
|
}
|
2022-05-17 21:16:24 +00:00
|
|
|
/* Audio setup will return NULL on failure, and we'll proceed without audio */
|
|
|
|
if (settings->AudioPlayback)
|
|
|
|
peerCtx->audio_out_private = b->audio_out_setup(b->compositor, peerCtx->vcm);
|
|
|
|
|
|
|
|
if (settings->AudioCapture)
|
|
|
|
peerCtx->audio_in_private = b->audio_in_setup(b->compositor, peerCtx->vcm);
|
2022-05-10 18:16:55 +00:00
|
|
|
}
|
|
|
|
|
2022-08-09 18:52:51 +00:00
|
|
|
/* If we don't allow resize, we need to tell the client to resize itself.
|
|
|
|
* We still need the xf_peer_adjust_monitor_layout() call to make sure
|
|
|
|
* we've set up scaling appropriately.
|
|
|
|
*/
|
|
|
|
if (b->no_clients_resize) {
|
|
|
|
struct weston_mode *mode = output->base.current_mode;
|
|
|
|
|
|
|
|
if (mode->width != (int)settings->DesktopWidth ||
|
|
|
|
mode->height != (int)settings->DesktopHeight) {
|
2014-04-03 00:54:00 +00:00
|
|
|
if (!settings->DesktopResize) {
|
|
|
|
/* peer does not support desktop resize */
|
2022-08-09 18:52:51 +00:00
|
|
|
weston_log("client doesn't support resizing, closing connection\n");
|
2014-04-03 00:54:00 +00:00
|
|
|
return FALSE;
|
|
|
|
} else {
|
2022-08-09 18:52:51 +00:00
|
|
|
settings->DesktopWidth = mode->width;
|
|
|
|
settings->DesktopHeight = mode->height;
|
2022-06-07 16:42:09 +00:00
|
|
|
client->context->update->DesktopResize(client->context);
|
2014-04-03 00:54:00 +00:00
|
|
|
}
|
2013-04-01 21:43:58 +00:00
|
|
|
}
|
2022-08-09 18:52:51 +00:00
|
|
|
} else {
|
|
|
|
xf_peer_adjust_monitor_layout(client);
|
2013-04-01 21:43:58 +00:00
|
|
|
}
|
|
|
|
|
2016-05-01 21:32:07 +00:00
|
|
|
weston_output = &output->base;
|
2022-08-09 13:18:35 +00:00
|
|
|
width = weston_output->width * weston_output->scale;
|
|
|
|
height = weston_output->height * weston_output->scale;
|
|
|
|
rfx_context_reset(peerCtx->rfx_context, width, height);
|
|
|
|
nsc_context_reset(peerCtx->nsc_context, width, height);
|
2015-05-11 21:19:02 +00:00
|
|
|
|
|
|
|
if (peersItem->flags & RDP_PEER_ACTIVATED)
|
|
|
|
return TRUE;
|
|
|
|
|
|
|
|
/* when here it's the first reactivation, we need to setup a little more */
|
2022-03-11 19:29:11 +00:00
|
|
|
rdp_debug(b, "kbd_layout:0x%x kbd_type:0x%x kbd_subType:0x%x kbd_functionKeys:0x%x\n",
|
2013-04-01 21:43:58 +00:00
|
|
|
settings->KeyboardLayout, settings->KeyboardType, settings->KeyboardSubType,
|
|
|
|
settings->KeyboardFunctionKey);
|
|
|
|
|
2022-03-22 16:57:42 +00:00
|
|
|
convert_rdp_keyboard_to_xkb_rule_names(settings->KeyboardType,
|
|
|
|
settings->KeyboardSubType,
|
|
|
|
settings->KeyboardLayout,
|
|
|
|
&xkbRuleNames);
|
2013-04-01 21:43:58 +00:00
|
|
|
|
|
|
|
keymap = NULL;
|
2014-03-20 21:34:30 +00:00
|
|
|
if (xkbRuleNames.layout) {
|
2019-06-20 20:45:49 +00:00
|
|
|
keymap = xkb_keymap_new_from_names(b->compositor->xkb_context,
|
|
|
|
&xkbRuleNames, 0);
|
2013-04-01 21:43:58 +00:00
|
|
|
}
|
|
|
|
|
2015-05-11 21:19:02 +00:00
|
|
|
if (settings->ClientHostname)
|
|
|
|
snprintf(seat_name, sizeof(seat_name), "RDP %s", settings->ClientHostname);
|
|
|
|
else
|
|
|
|
snprintf(seat_name, sizeof(seat_name), "RDP peer @%s", settings->ClientAddress);
|
|
|
|
|
2016-05-27 21:22:56 +00:00
|
|
|
peersItem->seat = zalloc(sizeof(*peersItem->seat));
|
|
|
|
if (!peersItem->seat) {
|
|
|
|
xkb_keymap_unref(keymap);
|
|
|
|
weston_log("unable to create a weston_seat\n");
|
|
|
|
return FALSE;
|
|
|
|
}
|
|
|
|
|
|
|
|
weston_seat_init(peersItem->seat, b->compositor, seat_name);
|
|
|
|
weston_seat_init_keyboard(peersItem->seat, keymap);
|
2019-06-20 20:54:54 +00:00
|
|
|
xkb_keymap_unref(keymap);
|
2016-05-27 21:22:56 +00:00
|
|
|
weston_seat_init_pointer(peersItem->seat);
|
2015-05-11 21:19:02 +00:00
|
|
|
|
2022-05-10 18:16:55 +00:00
|
|
|
/* Initialize RDP clipboard after seat is initialized */
|
|
|
|
if (settings->RedirectClipboard)
|
|
|
|
if (rdp_clipboard_init(client) != 0)
|
|
|
|
goto error_exit;
|
|
|
|
|
2015-05-11 21:19:02 +00:00
|
|
|
peersItem->flags |= RDP_PEER_ACTIVATED;
|
2013-05-22 21:40:19 +00:00
|
|
|
|
|
|
|
/* disable pointer on the client side */
|
2022-06-07 16:42:09 +00:00
|
|
|
pointer = client->context->update->pointer;
|
2018-12-04 22:25:39 +00:00
|
|
|
pointer_system.type = SYSPTR_NULL;
|
|
|
|
pointer->PointerSystem(client->context, &pointer_system);
|
2013-05-22 21:40:19 +00:00
|
|
|
|
2022-08-09 12:47:17 +00:00
|
|
|
rdp_full_refresh(client, output);
|
2013-05-22 21:40:19 +00:00
|
|
|
|
2013-04-01 21:43:58 +00:00
|
|
|
return TRUE;
|
2022-05-10 18:16:55 +00:00
|
|
|
|
|
|
|
error_exit:
|
|
|
|
|
|
|
|
rdp_clipboard_destroy(peerCtx);
|
|
|
|
|
2022-05-17 21:16:24 +00:00
|
|
|
if (settings->AudioPlayback && peerCtx->audio_out_private)
|
|
|
|
b->audio_out_teardown(peerCtx->audio_out_private);
|
|
|
|
|
|
|
|
if (settings->AudioCapture && peerCtx->audio_in_private)
|
|
|
|
b->audio_in_teardown(peerCtx->audio_in_private);
|
|
|
|
|
2022-05-10 18:16:55 +00:00
|
|
|
return FALSE;
|
2013-04-01 21:43:58 +00:00
|
|
|
}
|
|
|
|
|
2017-09-27 10:01:10 +00:00
|
|
|
static BOOL
|
|
|
|
xf_peer_post_connect(freerdp_peer *client)
|
2013-04-01 21:43:58 +00:00
|
|
|
{
|
|
|
|
return TRUE;
|
|
|
|
}
|
|
|
|
|
2022-08-09 18:52:51 +00:00
|
|
|
static bool
|
|
|
|
rdp_translate_and_notify_mouse_position(RdpPeerContext *peerContext, UINT16 x, UINT16 y)
|
|
|
|
{
|
|
|
|
struct timespec time;
|
|
|
|
int sx, sy;
|
|
|
|
|
|
|
|
if (!peerContext->item.seat)
|
|
|
|
return FALSE;
|
|
|
|
|
|
|
|
/* (TS_POINTERX_EVENT):The xy-coordinate of the pointer relative to the top-left
|
|
|
|
* corner of the server's desktop combined all monitors */
|
|
|
|
|
|
|
|
/* first, convert the coordinate based on primary monitor's upper-left as (0,0) */
|
|
|
|
sx = x + peerContext->desktop_left;
|
|
|
|
sy = y + peerContext->desktop_top;
|
|
|
|
|
|
|
|
/* translate client's x/y to the coordinate in weston space. */
|
|
|
|
/* TODO: to_weston_coordinate() is translate based on where pointer is,
|
|
|
|
not based-on where/which window underneath. Thus, this doesn't
|
|
|
|
work when window lays across more than 2 monitors and each monitor has
|
|
|
|
different scaling. In such case, hit test to that window area on
|
|
|
|
non primary-resident monitor (surface->output) dosn't work. */
|
|
|
|
if (to_weston_coordinate(peerContext, &sx, &sy)) {
|
|
|
|
weston_compositor_get_time(&time);
|
|
|
|
notify_motion_absolute(peerContext->item.seat, &time, sx, sy);
|
|
|
|
return TRUE;
|
|
|
|
}
|
|
|
|
return FALSE;
|
|
|
|
}
|
|
|
|
|
2022-03-15 22:12:01 +00:00
|
|
|
static void
|
|
|
|
dump_mouseinput(RdpPeerContext *peerContext, UINT16 flags, UINT16 x, UINT16 y, bool is_ex)
|
|
|
|
{
|
|
|
|
struct rdp_backend *b = peerContext->rdpBackend;
|
|
|
|
|
|
|
|
rdp_debug_verbose(b, "RDP mouse input%s: (%d, %d): flags:%x: ", is_ex ? "_ex" : "", x, y, flags);
|
|
|
|
if (is_ex) {
|
|
|
|
if (flags & PTR_XFLAGS_DOWN)
|
|
|
|
rdp_debug_verbose_continue(b, "DOWN ");
|
|
|
|
if (flags & PTR_XFLAGS_BUTTON1)
|
|
|
|
rdp_debug_verbose_continue(b, "XBUTTON1 ");
|
|
|
|
if (flags & PTR_XFLAGS_BUTTON2)
|
|
|
|
rdp_debug_verbose_continue(b, "XBUTTON2 ");
|
|
|
|
} else {
|
|
|
|
if (flags & PTR_FLAGS_WHEEL)
|
|
|
|
rdp_debug_verbose_continue(b, "WHEEL ");
|
|
|
|
if (flags & PTR_FLAGS_WHEEL_NEGATIVE)
|
|
|
|
rdp_debug_verbose_continue(b, "WHEEL_NEGATIVE ");
|
|
|
|
if (flags & PTR_FLAGS_HWHEEL)
|
|
|
|
rdp_debug_verbose_continue(b, "HWHEEL ");
|
|
|
|
if (flags & PTR_FLAGS_MOVE)
|
|
|
|
rdp_debug_verbose_continue(b, "MOVE ");
|
|
|
|
if (flags & PTR_FLAGS_DOWN)
|
|
|
|
rdp_debug_verbose_continue(b, "DOWN ");
|
|
|
|
if (flags & PTR_FLAGS_BUTTON1)
|
|
|
|
rdp_debug_verbose_continue(b, "BUTTON1 ");
|
|
|
|
if (flags & PTR_FLAGS_BUTTON2)
|
|
|
|
rdp_debug_verbose_continue(b, "BUTTON2 ");
|
|
|
|
if (flags & PTR_FLAGS_BUTTON3)
|
|
|
|
rdp_debug_verbose_continue(b, "BUTTON3 ");
|
|
|
|
}
|
|
|
|
rdp_debug_verbose_continue(b, "\n");
|
|
|
|
}
|
|
|
|
|
2022-03-15 21:40:15 +00:00
|
|
|
static void
|
|
|
|
rdp_validate_button_state(RdpPeerContext *peerContext, bool pressed, uint32_t *button)
|
|
|
|
{
|
|
|
|
struct rdp_backend *b = peerContext->rdpBackend;
|
|
|
|
uint32_t index;
|
|
|
|
|
|
|
|
if (*button < BTN_LEFT || *button > BTN_EXTRA) {
|
|
|
|
weston_log("RDP client posted invalid button event\n");
|
|
|
|
goto ignore;
|
|
|
|
}
|
|
|
|
|
|
|
|
index = *button - BTN_LEFT;
|
|
|
|
assert(index < ARRAY_LENGTH(peerContext->button_state));
|
|
|
|
|
|
|
|
if (pressed == peerContext->button_state[index]) {
|
|
|
|
rdp_debug_verbose(b, "%s: inconsistent button state button:%d (index:%d) pressed:%d\n",
|
|
|
|
__func__, *button, index, pressed);
|
|
|
|
goto ignore;
|
|
|
|
} else {
|
|
|
|
peerContext->button_state[index] = pressed;
|
|
|
|
}
|
|
|
|
return;
|
|
|
|
ignore:
|
|
|
|
/* ignore button input */
|
|
|
|
*button = 0;
|
|
|
|
}
|
|
|
|
|
2022-03-22 16:13:46 +00:00
|
|
|
static bool
|
2022-03-22 16:15:56 +00:00
|
|
|
rdp_notify_wheel_scroll(RdpPeerContext *peerContext, UINT16 flags, uint32_t axis)
|
2022-03-22 15:48:29 +00:00
|
|
|
{
|
|
|
|
struct weston_pointer_axis_event weston_event;
|
2022-03-22 16:13:46 +00:00
|
|
|
struct rdp_backend *b = peerContext->rdpBackend;
|
|
|
|
int ivalue;
|
2022-03-22 15:48:29 +00:00
|
|
|
double value;
|
|
|
|
struct timespec time;
|
2022-03-22 16:13:46 +00:00
|
|
|
int *accumWheelRotationPrecise;
|
|
|
|
int *accumWheelRotationDiscrete;
|
|
|
|
|
|
|
|
/*
|
|
|
|
* The RDP specs says the lower bits of flags contains the "the number of rotation
|
|
|
|
* units the mouse wheel was rotated".
|
|
|
|
*/
|
|
|
|
ivalue = ((int)flags & 0x000000ff);
|
2022-03-22 15:48:29 +00:00
|
|
|
if (flags & PTR_FLAGS_WHEEL_NEGATIVE)
|
2022-03-22 16:13:46 +00:00
|
|
|
ivalue = (0xff - ivalue) * -1;
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Flip the scroll direction as the RDP direction is inverse of X/Wayland
|
|
|
|
* for vertical scroll
|
|
|
|
*/
|
2022-03-22 16:15:56 +00:00
|
|
|
if (axis == WL_POINTER_AXIS_VERTICAL_SCROLL) {
|
|
|
|
ivalue *= -1;
|
2022-03-22 16:13:46 +00:00
|
|
|
|
2022-03-22 16:15:56 +00:00
|
|
|
accumWheelRotationPrecise = &peerContext->verticalAccumWheelRotationPrecise;
|
|
|
|
accumWheelRotationDiscrete = &peerContext->verticalAccumWheelRotationDiscrete;
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
accumWheelRotationPrecise = &peerContext->horizontalAccumWheelRotationPrecise;
|
|
|
|
accumWheelRotationDiscrete = &peerContext->horizontalAccumWheelRotationDiscrete;
|
|
|
|
}
|
2022-03-22 16:13:46 +00:00
|
|
|
|
|
|
|
/*
|
|
|
|
* Accumulate the wheel increments.
|
|
|
|
*
|
|
|
|
* Every 12 wheel increments, we will send an update to our Wayland
|
|
|
|
* clients with an updated value for the wheel for smooth scrolling.
|
|
|
|
*
|
|
|
|
* Every 120 wheel increments, we tick one discrete wheel click.
|
|
|
|
*
|
|
|
|
* https://devblogs.microsoft.com/oldnewthing/20130123-00/?p=5473 explains the 120 value
|
|
|
|
*/
|
|
|
|
*accumWheelRotationPrecise += ivalue;
|
|
|
|
*accumWheelRotationDiscrete += ivalue;
|
|
|
|
rdp_debug_verbose(b, "wheel: rawValue:%d accumPrecise:%d accumDiscrete %d\n",
|
|
|
|
ivalue, *accumWheelRotationPrecise, *accumWheelRotationDiscrete);
|
|
|
|
|
|
|
|
if (abs(*accumWheelRotationPrecise) >= 12) {
|
|
|
|
value = (double)(*accumWheelRotationPrecise / 12);
|
|
|
|
|
2022-03-22 16:15:56 +00:00
|
|
|
weston_event.axis = axis;
|
2022-03-22 16:13:46 +00:00
|
|
|
weston_event.value = value;
|
|
|
|
weston_event.discrete = *accumWheelRotationDiscrete / 120;
|
|
|
|
weston_event.has_discrete = true;
|
|
|
|
|
|
|
|
rdp_debug_verbose(b, "wheel: value:%f discrete:%d\n",
|
|
|
|
weston_event.value, weston_event.discrete);
|
|
|
|
|
|
|
|
weston_compositor_get_time(&time);
|
|
|
|
|
|
|
|
notify_axis(peerContext->item.seat, &time, &weston_event);
|
2022-03-22 15:48:29 +00:00
|
|
|
|
2022-03-22 16:13:46 +00:00
|
|
|
*accumWheelRotationPrecise %= 12;
|
|
|
|
*accumWheelRotationDiscrete %= 120;
|
2022-03-22 15:48:29 +00:00
|
|
|
|
2022-03-22 16:13:46 +00:00
|
|
|
return true;
|
|
|
|
}
|
2022-03-22 15:48:29 +00:00
|
|
|
|
2022-03-22 16:13:46 +00:00
|
|
|
return false;
|
2022-03-22 15:48:29 +00:00
|
|
|
}
|
|
|
|
|
2020-09-29 21:56:06 +00:00
|
|
|
static BOOL
|
2015-08-06 20:12:19 +00:00
|
|
|
xf_mouseEvent(rdpInput *input, UINT16 flags, UINT16 x, UINT16 y)
|
|
|
|
{
|
2013-04-01 21:43:58 +00:00
|
|
|
RdpPeerContext *peerContext = (RdpPeerContext *)input->context;
|
|
|
|
uint32_t button = 0;
|
2016-01-18 06:38:22 +00:00
|
|
|
bool need_frame = false;
|
2017-11-24 16:01:46 +00:00
|
|
|
struct timespec time;
|
2013-04-01 21:43:58 +00:00
|
|
|
|
2022-03-15 22:12:01 +00:00
|
|
|
dump_mouseinput(peerContext, flags, x, y, false);
|
|
|
|
|
2022-03-16 16:26:04 +00:00
|
|
|
/* Per RDP spec, the x,y position is valid on all input mouse messages,
|
|
|
|
* except for PTR_FLAGS_WHEEL and PTR_FLAGS_HWHEEL event. Take the opportunity
|
|
|
|
* to resample our x,y position even when PTR_FLAGS_MOVE isn't explicitly set,
|
|
|
|
* for example a button down/up only notification, to ensure proper sync with
|
|
|
|
* the RDP client.
|
|
|
|
*/
|
|
|
|
if (!(flags & (PTR_FLAGS_WHEEL | PTR_FLAGS_HWHEEL))) {
|
2022-08-09 18:52:51 +00:00
|
|
|
if (rdp_translate_and_notify_mouse_position(peerContext, x, y))
|
2016-01-18 06:38:22 +00:00
|
|
|
need_frame = true;
|
2013-04-01 21:43:58 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
if (flags & PTR_FLAGS_BUTTON1)
|
|
|
|
button = BTN_LEFT;
|
|
|
|
else if (flags & PTR_FLAGS_BUTTON2)
|
|
|
|
button = BTN_RIGHT;
|
|
|
|
else if (flags & PTR_FLAGS_BUTTON3)
|
|
|
|
button = BTN_MIDDLE;
|
|
|
|
|
2022-03-15 21:40:15 +00:00
|
|
|
if (button) {
|
|
|
|
rdp_validate_button_state(peerContext,
|
|
|
|
flags & PTR_FLAGS_DOWN ? true : false,
|
|
|
|
&button);
|
|
|
|
}
|
|
|
|
|
2014-03-20 21:34:30 +00:00
|
|
|
if (button) {
|
2017-11-16 16:21:01 +00:00
|
|
|
weston_compositor_get_time(&time);
|
2017-11-16 16:20:55 +00:00
|
|
|
notify_button(peerContext->item.seat, &time, button,
|
2013-04-01 21:43:58 +00:00
|
|
|
(flags & PTR_FLAGS_DOWN) ? WL_POINTER_BUTTON_STATE_PRESSED : WL_POINTER_BUTTON_STATE_RELEASED
|
|
|
|
);
|
2016-01-18 06:38:22 +00:00
|
|
|
need_frame = true;
|
2013-04-01 21:43:58 +00:00
|
|
|
}
|
2013-06-03 20:55:47 +00:00
|
|
|
|
2022-03-22 16:15:56 +00:00
|
|
|
/* Per RDP spec, if both PTRFLAGS_WHEEL and PTRFLAGS_HWHEEL are specified
|
|
|
|
* then PTRFLAGS_WHEEL takes precedent
|
|
|
|
*/
|
2013-06-03 20:55:47 +00:00
|
|
|
if (flags & PTR_FLAGS_WHEEL) {
|
2022-03-22 16:15:56 +00:00
|
|
|
if (rdp_notify_wheel_scroll(peerContext, flags, WL_POINTER_AXIS_VERTICAL_SCROLL))
|
|
|
|
need_frame = true;
|
|
|
|
} else if (flags & PTR_FLAGS_HWHEEL) {
|
|
|
|
if (rdp_notify_wheel_scroll(peerContext, flags, WL_POINTER_AXIS_HORIZONTAL_SCROLL))
|
2022-03-22 16:13:46 +00:00
|
|
|
need_frame = true;
|
2013-06-03 20:55:47 +00:00
|
|
|
}
|
2015-05-11 21:19:02 +00:00
|
|
|
|
2016-01-18 06:38:22 +00:00
|
|
|
if (need_frame)
|
2016-05-27 21:22:56 +00:00
|
|
|
notify_pointer_frame(peerContext->item.seat);
|
2016-01-18 06:38:22 +00:00
|
|
|
|
2020-09-29 21:56:06 +00:00
|
|
|
return TRUE;
|
2013-04-01 21:43:58 +00:00
|
|
|
}
|
|
|
|
|
2020-09-29 21:56:06 +00:00
|
|
|
static BOOL
|
2015-08-06 20:12:19 +00:00
|
|
|
xf_extendedMouseEvent(rdpInput *input, UINT16 flags, UINT16 x, UINT16 y)
|
|
|
|
{
|
2013-04-01 21:43:58 +00:00
|
|
|
RdpPeerContext *peerContext = (RdpPeerContext *)input->context;
|
2022-03-16 15:54:07 +00:00
|
|
|
uint32_t button = 0;
|
|
|
|
bool need_frame = false;
|
2013-04-01 21:43:58 +00:00
|
|
|
struct rdp_output *output;
|
2017-11-24 16:01:46 +00:00
|
|
|
struct timespec time;
|
2013-04-01 21:43:58 +00:00
|
|
|
|
2022-03-15 22:12:01 +00:00
|
|
|
dump_mouseinput(peerContext, flags, x, y, true);
|
|
|
|
|
2022-03-16 15:54:07 +00:00
|
|
|
if (flags & PTR_XFLAGS_BUTTON1)
|
|
|
|
button = BTN_SIDE;
|
|
|
|
else if (flags & PTR_XFLAGS_BUTTON2)
|
|
|
|
button = BTN_EXTRA;
|
|
|
|
|
2022-03-15 21:40:15 +00:00
|
|
|
if (button) {
|
|
|
|
rdp_validate_button_state(peerContext,
|
|
|
|
flags & PTR_XFLAGS_DOWN ? true : false,
|
|
|
|
&button);
|
|
|
|
}
|
|
|
|
|
2022-03-16 15:54:07 +00:00
|
|
|
if (button) {
|
|
|
|
weston_compositor_get_time(&time);
|
|
|
|
notify_button(peerContext->item.seat, &time, button,
|
|
|
|
(flags & PTR_XFLAGS_DOWN) ? WL_POINTER_BUTTON_STATE_PRESSED : WL_POINTER_BUTTON_STATE_RELEASED);
|
|
|
|
need_frame = true;
|
|
|
|
}
|
|
|
|
|
2022-08-03 16:38:55 +00:00
|
|
|
output = rdp_get_first_output(peerContext->rdpBackend);
|
2014-03-20 21:34:30 +00:00
|
|
|
if (x < output->base.width && y < output->base.height) {
|
2017-11-16 16:21:01 +00:00
|
|
|
weston_compositor_get_time(&time);
|
2017-11-24 16:01:46 +00:00
|
|
|
notify_motion_absolute(peerContext->item.seat, &time, x, y);
|
2022-03-16 15:54:07 +00:00
|
|
|
need_frame = true;
|
2013-04-01 21:43:58 +00:00
|
|
|
}
|
2015-05-11 21:19:02 +00:00
|
|
|
|
2022-03-16 15:54:07 +00:00
|
|
|
if (need_frame)
|
|
|
|
notify_pointer_frame(peerContext->item.seat);
|
|
|
|
|
2020-09-29 21:56:06 +00:00
|
|
|
return TRUE;
|
2013-04-01 21:43:58 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2020-09-29 21:56:06 +00:00
|
|
|
static BOOL
|
2013-04-01 21:43:58 +00:00
|
|
|
xf_input_synchronize_event(rdpInput *input, UINT32 flags)
|
|
|
|
{
|
|
|
|
freerdp_peer *client = input->context->peer;
|
|
|
|
RdpPeerContext *peerCtx = (RdpPeerContext *)input->context;
|
2022-03-11 19:29:11 +00:00
|
|
|
struct rdp_backend *b = peerCtx->rdpBackend;
|
2022-08-03 16:38:55 +00:00
|
|
|
struct rdp_output *output = rdp_get_first_output(b);
|
2022-03-16 18:21:33 +00:00
|
|
|
struct weston_keyboard *keyboard;
|
2013-04-01 21:43:58 +00:00
|
|
|
|
2022-03-11 19:29:11 +00:00
|
|
|
rdp_debug_verbose(b, "RDP backend: %s ScrLk:%d, NumLk:%d, CapsLk:%d, KanaLk:%d\n",
|
|
|
|
__func__,
|
|
|
|
flags & KBD_SYNC_SCROLL_LOCK ? 1 : 0,
|
|
|
|
flags & KBD_SYNC_NUM_LOCK ? 1 : 0,
|
|
|
|
flags & KBD_SYNC_CAPS_LOCK ? 1 : 0,
|
|
|
|
flags & KBD_SYNC_KANA_LOCK ? 1 : 0);
|
|
|
|
|
2022-03-16 18:21:33 +00:00
|
|
|
keyboard = weston_seat_get_keyboard(peerCtx->item.seat);
|
|
|
|
if (keyboard) {
|
|
|
|
uint32_t value = 0;
|
|
|
|
|
|
|
|
if (flags & KBD_SYNC_NUM_LOCK)
|
|
|
|
value |= WESTON_NUM_LOCK;
|
|
|
|
if (flags & KBD_SYNC_CAPS_LOCK)
|
|
|
|
value |= WESTON_CAPS_LOCK;
|
|
|
|
weston_keyboard_set_locks(keyboard,
|
|
|
|
WESTON_NUM_LOCK | WESTON_CAPS_LOCK,
|
|
|
|
value);
|
|
|
|
}
|
|
|
|
|
2022-08-09 12:47:17 +00:00
|
|
|
rdp_full_refresh(client, output);
|
2013-04-01 21:43:58 +00:00
|
|
|
|
2020-09-29 21:56:06 +00:00
|
|
|
return TRUE;
|
2013-04-01 21:43:58 +00:00
|
|
|
}
|
|
|
|
|
2013-04-06 21:39:26 +00:00
|
|
|
|
2020-09-29 21:56:06 +00:00
|
|
|
static BOOL
|
2013-04-01 21:43:58 +00:00
|
|
|
xf_input_keyboard_event(rdpInput *input, UINT16 flags, UINT16 code)
|
|
|
|
{
|
2013-04-06 21:39:26 +00:00
|
|
|
uint32_t scan_code, vk_code, full_code;
|
2013-04-01 21:43:58 +00:00
|
|
|
enum wl_keyboard_key_state keyState;
|
2022-04-27 19:32:09 +00:00
|
|
|
freerdp_peer *client = input->context->peer;
|
2013-04-01 21:43:58 +00:00
|
|
|
RdpPeerContext *peerContext = (RdpPeerContext *)input->context;
|
2022-04-27 19:32:09 +00:00
|
|
|
bool send_release_key = false;
|
2013-04-01 21:43:58 +00:00
|
|
|
int notify = 0;
|
2017-11-16 16:20:57 +00:00
|
|
|
struct timespec time;
|
2013-04-01 21:43:58 +00:00
|
|
|
|
2015-05-11 21:19:02 +00:00
|
|
|
if (!(peerContext->item.flags & RDP_PEER_ACTIVATED))
|
2020-09-29 21:56:06 +00:00
|
|
|
return TRUE;
|
2015-05-11 21:19:02 +00:00
|
|
|
|
2013-04-01 21:43:58 +00:00
|
|
|
if (flags & KBD_FLAGS_DOWN) {
|
|
|
|
keyState = WL_KEYBOARD_KEY_STATE_PRESSED;
|
|
|
|
notify = 1;
|
|
|
|
} else if (flags & KBD_FLAGS_RELEASE) {
|
|
|
|
keyState = WL_KEYBOARD_KEY_STATE_RELEASED;
|
|
|
|
notify = 1;
|
|
|
|
}
|
|
|
|
|
2014-03-20 21:34:30 +00:00
|
|
|
if (notify) {
|
2013-04-06 21:39:26 +00:00
|
|
|
full_code = code;
|
2014-03-20 21:34:30 +00:00
|
|
|
if (flags & KBD_FLAGS_EXTENDED)
|
2013-04-06 21:39:26 +00:00
|
|
|
full_code |= KBD_FLAGS_EXTENDED;
|
|
|
|
|
2022-04-27 19:32:09 +00:00
|
|
|
/* Korean keyboard support:
|
|
|
|
* WinPR's GetVirtualKeyCodeFromVirtualScanCode() can't handle hangul/hanja keys
|
|
|
|
* hanja and hangeul keys are only present on Korean 103 keyboard (Type 8:SubType 6) */
|
2022-06-07 16:42:09 +00:00
|
|
|
if (client->context->settings->KeyboardType == 8 &&
|
|
|
|
client->context->settings->KeyboardSubType == 6 &&
|
2022-04-27 19:32:09 +00:00
|
|
|
((full_code == (KBD_FLAGS_EXTENDED | ATKBD_RET_HANJA)) ||
|
|
|
|
(full_code == (KBD_FLAGS_EXTENDED | ATKBD_RET_HANGEUL)))) {
|
|
|
|
if (full_code == (KBD_FLAGS_EXTENDED | ATKBD_RET_HANJA))
|
|
|
|
vk_code = VK_HANJA;
|
|
|
|
else if (full_code == (KBD_FLAGS_EXTENDED | ATKBD_RET_HANGEUL))
|
|
|
|
vk_code = VK_HANGUL;
|
|
|
|
/* From Linux's keyboard driver at drivers/input/keyboard/atkbd.c */
|
|
|
|
/*
|
|
|
|
* HANGEUL and HANJA keys do not send release events so we need to
|
|
|
|
* generate such events ourselves
|
|
|
|
*/
|
|
|
|
/* Similarly, for RDP there is no release for those 2 Korean keys,
|
|
|
|
* thus generate release right after press. */
|
|
|
|
if (keyState != WL_KEYBOARD_KEY_STATE_PRESSED) {
|
|
|
|
weston_log("RDP: Received invalid key release\n");
|
|
|
|
return TRUE;
|
|
|
|
}
|
|
|
|
send_release_key = true;
|
|
|
|
} else {
|
2022-06-07 16:42:09 +00:00
|
|
|
vk_code = GetVirtualKeyCodeFromVirtualScanCode(full_code, client->context->settings->KeyboardType);
|
2022-04-27 19:32:09 +00:00
|
|
|
}
|
|
|
|
/* Korean keyboard support */
|
|
|
|
/* WinPR's GetKeycodeFromVirtualKeyCode() expects no extended bit for VK_HANGUL and VK_HANJA */
|
|
|
|
if (vk_code != VK_HANGUL && vk_code != VK_HANJA)
|
|
|
|
if (flags & KBD_FLAGS_EXTENDED)
|
|
|
|
vk_code |= KBDEXT;
|
2013-04-06 21:39:26 +00:00
|
|
|
|
2014-04-11 08:24:22 +00:00
|
|
|
scan_code = GetKeycodeFromVirtualKeyCode(vk_code, KEYCODE_TYPE_EVDEV);
|
2013-04-06 21:39:26 +00:00
|
|
|
|
|
|
|
/*weston_log("code=%x ext=%d vk_code=%x scan_code=%x\n", code, (flags & KBD_FLAGS_EXTENDED) ? 1 : 0,
|
|
|
|
vk_code, scan_code);*/
|
2017-11-16 16:21:01 +00:00
|
|
|
weston_compositor_get_time(&time);
|
2017-11-16 16:20:57 +00:00
|
|
|
notify_key(peerContext->item.seat, &time,
|
2014-04-11 08:24:22 +00:00
|
|
|
scan_code - 8, keyState, STATE_UPDATE_AUTOMATIC);
|
2022-04-27 19:32:09 +00:00
|
|
|
|
|
|
|
if (send_release_key) {
|
|
|
|
notify_key(peerContext->item.seat, &time,
|
|
|
|
scan_code - 8,
|
|
|
|
WL_KEYBOARD_KEY_STATE_RELEASED,
|
|
|
|
STATE_UPDATE_AUTOMATIC);
|
|
|
|
}
|
2013-04-06 21:39:26 +00:00
|
|
|
}
|
2015-05-11 21:19:02 +00:00
|
|
|
|
2020-09-29 21:56:06 +00:00
|
|
|
return TRUE;
|
2013-04-01 21:43:58 +00:00
|
|
|
}
|
|
|
|
|
2020-09-29 21:56:06 +00:00
|
|
|
static BOOL
|
2013-04-01 21:43:58 +00:00
|
|
|
xf_input_unicode_keyboard_event(rdpInput *input, UINT16 flags, UINT16 code)
|
|
|
|
{
|
2022-03-11 19:29:11 +00:00
|
|
|
RdpPeerContext *peerContext = (RdpPeerContext *)input->context;
|
|
|
|
struct rdp_backend *b = peerContext->rdpBackend;
|
|
|
|
|
|
|
|
rdp_debug(b, "Client sent a unicode keyboard event (flags:0x%X code:0x%X)\n", flags, code);
|
|
|
|
|
2020-09-29 21:56:06 +00:00
|
|
|
return TRUE;
|
2013-04-01 21:43:58 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2020-09-29 21:56:06 +00:00
|
|
|
static BOOL
|
2017-09-27 10:01:10 +00:00
|
|
|
xf_suppress_output(rdpContext *context, BYTE allow, const RECTANGLE_16 *area)
|
2015-08-06 20:12:19 +00:00
|
|
|
{
|
2013-04-01 21:43:58 +00:00
|
|
|
RdpPeerContext *peerContext = (RdpPeerContext *)context;
|
2015-05-11 21:19:02 +00:00
|
|
|
|
2014-03-20 21:34:30 +00:00
|
|
|
if (allow)
|
2013-04-01 21:43:58 +00:00
|
|
|
peerContext->item.flags |= RDP_PEER_OUTPUT_ENABLED;
|
|
|
|
else
|
|
|
|
peerContext->item.flags &= (~RDP_PEER_OUTPUT_ENABLED);
|
2015-05-11 21:19:02 +00:00
|
|
|
|
2020-09-29 21:56:06 +00:00
|
|
|
return TRUE;
|
2013-04-01 21:43:58 +00:00
|
|
|
}
|
|
|
|
|
2022-08-09 18:52:51 +00:00
|
|
|
static BOOL
|
|
|
|
xf_peer_adjust_monitor_layout(freerdp_peer *client)
|
|
|
|
{
|
|
|
|
RdpPeerContext *peerCtx = (RdpPeerContext *)client->context;
|
|
|
|
struct rdp_backend *b = peerCtx->rdpBackend;
|
|
|
|
rdpSettings *settings = client->context->settings;
|
|
|
|
rdpMonitor *monitors;
|
|
|
|
unsigned int monitor_count;
|
|
|
|
BOOL success;
|
|
|
|
bool fallback = false;
|
|
|
|
unsigned int i;
|
|
|
|
|
|
|
|
rdp_debug(b, "%s:\n", __func__);
|
|
|
|
rdp_debug(b, " DesktopWidth:%d, DesktopHeight:%d\n", settings->DesktopWidth, settings->DesktopHeight);
|
|
|
|
rdp_debug(b, " UseMultimon:%d\n", settings->UseMultimon);
|
|
|
|
rdp_debug(b, " ForceMultimon:%d\n", settings->ForceMultimon);
|
|
|
|
rdp_debug(b, " MonitorCount:%d\n", settings->MonitorCount);
|
|
|
|
rdp_debug(b, " HasMonitorAttributes:%d\n", settings->HasMonitorAttributes);
|
|
|
|
rdp_debug(b, " HiDefRemoteApp:%d\n", settings->HiDefRemoteApp);
|
|
|
|
|
|
|
|
if (settings->MonitorCount > 1) {
|
|
|
|
weston_log("multiple monitor is not supported");
|
|
|
|
fallback = true;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (b->no_clients_resize)
|
|
|
|
fallback = true;
|
|
|
|
|
|
|
|
if (settings->MonitorCount > RDP_MAX_MONITOR) {
|
|
|
|
weston_log("Client reports more monitors then expected:(%d)\n",
|
|
|
|
settings->MonitorCount);
|
|
|
|
return FALSE;
|
|
|
|
}
|
|
|
|
if ((settings->MonitorCount > 0 && settings->MonitorDefArray) && !fallback) {
|
|
|
|
rdpMonitor *rdp_monitor = settings->MonitorDefArray;
|
|
|
|
monitor_count = settings->MonitorCount;
|
|
|
|
monitors = xmalloc(sizeof(*monitors) * monitor_count);
|
|
|
|
for (i = 0; i < monitor_count; i++) {
|
|
|
|
monitors[i] = rdp_monitor[i];
|
|
|
|
if (!settings->HasMonitorAttributes) {
|
|
|
|
monitors[i].attributes.physicalWidth = 0;
|
|
|
|
monitors[i].attributes.physicalHeight = 0;
|
|
|
|
monitors[i].attributes.orientation = ORIENTATION_LANDSCAPE;
|
|
|
|
monitors[i].attributes.desktopScaleFactor = 100;
|
|
|
|
monitors[i].attributes.deviceScaleFactor = 100;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
monitor_count = 1;
|
|
|
|
monitors = xmalloc(sizeof(*monitors) * monitor_count);
|
|
|
|
/* when no monitor array provided, generate from desktop settings */
|
|
|
|
monitors[0].x = 0;
|
|
|
|
monitors[0].y = 0;
|
|
|
|
monitors[0].width = settings->DesktopWidth;
|
|
|
|
monitors[0].height = settings->DesktopHeight;
|
|
|
|
monitors[0].is_primary = 1;
|
|
|
|
monitors[0].attributes.physicalWidth = settings->DesktopPhysicalWidth;
|
|
|
|
monitors[0].attributes.physicalHeight = settings->DesktopPhysicalHeight;
|
|
|
|
monitors[0].attributes.orientation = settings->DesktopOrientation;
|
|
|
|
monitors[0].attributes.desktopScaleFactor = settings->DesktopScaleFactor;
|
|
|
|
monitors[0].attributes.deviceScaleFactor = settings->DeviceScaleFactor;
|
|
|
|
monitors[0].orig_screen = 0;
|
|
|
|
|
|
|
|
if (b->no_clients_resize) {
|
|
|
|
/* If we're not allowing clients to resize us, set these
|
|
|
|
* to 0 so the front end knows it needs to make something
|
|
|
|
* up.
|
|
|
|
*/
|
|
|
|
monitors[0].width = 0;
|
|
|
|
monitors[0].height = 0;
|
|
|
|
monitors[0].attributes.desktopScaleFactor = 0;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
success = handle_adjust_monitor_layout(client, monitor_count, monitors);
|
|
|
|
|
|
|
|
free(monitors);
|
|
|
|
return success;
|
|
|
|
}
|
|
|
|
|
2013-04-01 21:43:58 +00:00
|
|
|
static int
|
2014-10-11 15:27:30 +00:00
|
|
|
rdp_peer_init(freerdp_peer *client, struct rdp_backend *b)
|
2013-04-01 21:43:58 +00:00
|
|
|
{
|
2022-06-07 16:50:28 +00:00
|
|
|
int handle_count = 0;
|
|
|
|
HANDLE handles[MAX_FREERDP_FDS + 1]; /* +1 for virtual channel */
|
2013-04-01 21:43:58 +00:00
|
|
|
int i, fd;
|
|
|
|
struct wl_event_loop *loop;
|
|
|
|
rdpSettings *settings;
|
|
|
|
rdpInput *input;
|
|
|
|
RdpPeerContext *peerCtx;
|
|
|
|
|
2013-07-07 22:51:34 +00:00
|
|
|
client->ContextSize = sizeof(RdpPeerContext);
|
2013-04-01 21:43:58 +00:00
|
|
|
client->ContextNew = (psPeerContextNew)rdp_peer_context_new;
|
|
|
|
client->ContextFree = (psPeerContextFree)rdp_peer_context_free;
|
|
|
|
freerdp_peer_context_new(client);
|
|
|
|
|
|
|
|
peerCtx = (RdpPeerContext *) client->context;
|
2014-10-11 15:27:30 +00:00
|
|
|
peerCtx->rdpBackend = b;
|
2013-04-01 21:43:58 +00:00
|
|
|
|
2022-06-07 16:42:09 +00:00
|
|
|
settings = client->context->settings;
|
2015-05-11 21:19:02 +00:00
|
|
|
/* configure security settings */
|
2014-10-11 15:27:30 +00:00
|
|
|
if (b->rdp_key)
|
|
|
|
settings->RdpKeyFile = strdup(b->rdp_key);
|
|
|
|
if (b->tls_enabled) {
|
|
|
|
settings->CertificateFile = strdup(b->server_cert);
|
|
|
|
settings->PrivateKeyFile = strdup(b->server_key);
|
2013-04-01 21:43:58 +00:00
|
|
|
} else {
|
|
|
|
settings->TlsSecurity = FALSE;
|
|
|
|
}
|
|
|
|
settings->NlaSecurity = FALSE;
|
|
|
|
|
2015-08-01 22:35:30 +00:00
|
|
|
if (!client->Initialize(client)) {
|
|
|
|
weston_log("peer initialization failed\n");
|
|
|
|
goto error_initialize;
|
|
|
|
}
|
2015-07-20 12:39:21 +00:00
|
|
|
|
2015-05-11 21:19:02 +00:00
|
|
|
settings->OsMajorType = OSMAJORTYPE_UNIX;
|
|
|
|
settings->OsMinorType = OSMINORTYPE_PSEUDO_XSERVER;
|
|
|
|
settings->ColorDepth = 32;
|
|
|
|
settings->RefreshRect = TRUE;
|
2022-04-14 17:25:43 +00:00
|
|
|
settings->RemoteFxCodec = b->remotefx_codec;
|
2015-05-11 21:19:02 +00:00
|
|
|
settings->NSCodec = TRUE;
|
|
|
|
settings->FrameMarkerCommandEnabled = TRUE;
|
|
|
|
settings->SurfaceFrameMarkerEnabled = TRUE;
|
2022-05-10 18:16:55 +00:00
|
|
|
settings->RedirectClipboard = TRUE;
|
2022-03-16 15:54:07 +00:00
|
|
|
settings->HasExtendedMouseEvent = TRUE;
|
2022-03-22 16:15:56 +00:00
|
|
|
settings->HasHorizontalWheel = TRUE;
|
2015-05-11 21:19:02 +00:00
|
|
|
|
2013-04-01 21:43:58 +00:00
|
|
|
client->Capabilities = xf_peer_capabilities;
|
|
|
|
client->PostConnect = xf_peer_post_connect;
|
|
|
|
client->Activate = xf_peer_activate;
|
|
|
|
|
2022-08-09 18:52:51 +00:00
|
|
|
if (!b->no_clients_resize) {
|
|
|
|
settings->SupportMonitorLayoutPdu = TRUE;
|
|
|
|
client->AdjustMonitorsLayout = xf_peer_adjust_monitor_layout;
|
|
|
|
}
|
|
|
|
|
2022-06-07 16:42:09 +00:00
|
|
|
client->context->update->SuppressOutput = (pSuppressOutput)xf_suppress_output;
|
2013-04-01 21:43:58 +00:00
|
|
|
|
2022-06-07 16:42:09 +00:00
|
|
|
input = client->context->input;
|
2013-04-01 21:43:58 +00:00
|
|
|
input->SynchronizeEvent = xf_input_synchronize_event;
|
|
|
|
input->MouseEvent = xf_mouseEvent;
|
|
|
|
input->ExtendedMouseEvent = xf_extendedMouseEvent;
|
|
|
|
input->KeyboardEvent = xf_input_keyboard_event;
|
|
|
|
input->UnicodeKeyboardEvent = xf_input_unicode_keyboard_event;
|
2013-05-31 17:09:50 +00:00
|
|
|
|
2022-06-07 16:50:28 +00:00
|
|
|
handle_count = client->GetEventHandles(client, handles, MAX_FREERDP_FDS);
|
|
|
|
if (!handle_count) {
|
|
|
|
weston_log("unable to retrieve client handles\n");
|
2015-08-01 22:35:30 +00:00
|
|
|
goto error_initialize;
|
2013-04-01 21:43:58 +00:00
|
|
|
}
|
|
|
|
|
2022-05-10 17:28:58 +00:00
|
|
|
PWtsApiFunctionTable fn = FreeRDP_InitWtsApi();
|
|
|
|
WTSRegisterWtsApiFunctionTable(fn);
|
|
|
|
peerCtx->vcm = WTSOpenServerA((LPSTR)peerCtx);
|
|
|
|
if (peerCtx->vcm) {
|
2022-06-07 16:50:28 +00:00
|
|
|
handles[handle_count++] = WTSVirtualChannelManagerGetEventHandle(peerCtx->vcm);
|
2022-05-10 17:28:58 +00:00
|
|
|
} else {
|
|
|
|
weston_log("WTSOpenServer is failed! continue without virtual channel.\n");
|
|
|
|
}
|
|
|
|
|
2014-10-11 15:27:30 +00:00
|
|
|
loop = wl_display_get_event_loop(b->compositor->wl_display);
|
2022-06-07 16:50:28 +00:00
|
|
|
for (i = 0; i < handle_count; i++) {
|
|
|
|
fd = GetEventFileDescriptor(handles[i]);
|
2013-04-01 21:43:58 +00:00
|
|
|
|
|
|
|
peerCtx->events[i] = wl_event_loop_add_fd(loop, fd, WL_EVENT_READABLE,
|
|
|
|
rdp_client_activity, client);
|
|
|
|
}
|
2022-05-10 17:28:58 +00:00
|
|
|
for ( ; i < (int)ARRAY_LENGTH(peerCtx->events); i++)
|
2013-04-01 21:43:58 +00:00
|
|
|
peerCtx->events[i] = 0;
|
|
|
|
|
2022-07-12 14:39:05 +00:00
|
|
|
wl_list_insert(&b->peers, &peerCtx->item.link);
|
2022-04-29 12:22:41 +00:00
|
|
|
|
|
|
|
if (!rdp_initialize_dispatch_task_event_source(peerCtx))
|
2022-05-10 17:28:58 +00:00
|
|
|
goto error_dispatch_initialize;
|
2022-04-29 12:22:41 +00:00
|
|
|
|
2013-04-01 21:43:58 +00:00
|
|
|
return 0;
|
2015-08-01 22:35:30 +00:00
|
|
|
|
2022-05-10 17:28:58 +00:00
|
|
|
error_dispatch_initialize:
|
|
|
|
for (i = 0; i < (int)ARRAY_LENGTH(peerCtx->events); i++) {
|
|
|
|
if (peerCtx->events[i]) {
|
|
|
|
wl_event_source_remove(peerCtx->events[i]);
|
|
|
|
peerCtx->events[i] = NULL;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (peerCtx->vcm) {
|
|
|
|
WTSCloseServer(peerCtx->vcm);
|
|
|
|
peerCtx->vcm = NULL;
|
|
|
|
}
|
|
|
|
|
2015-08-01 22:35:30 +00:00
|
|
|
error_initialize:
|
|
|
|
client->Close(client);
|
|
|
|
return -1;
|
2013-04-01 21:43:58 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2020-09-29 21:56:06 +00:00
|
|
|
static BOOL
|
2013-04-01 21:43:58 +00:00
|
|
|
rdp_incoming_peer(freerdp_listener *instance, freerdp_peer *client)
|
|
|
|
{
|
2014-10-11 15:27:30 +00:00
|
|
|
struct rdp_backend *b = (struct rdp_backend *)instance->param4;
|
|
|
|
if (rdp_peer_init(client, b) < 0) {
|
2015-08-01 22:35:30 +00:00
|
|
|
weston_log("error when treating incoming peer\n");
|
2020-09-29 21:56:06 +00:00
|
|
|
return FALSE;
|
2015-05-11 21:19:02 +00:00
|
|
|
}
|
|
|
|
|
2020-09-29 21:56:06 +00:00
|
|
|
return TRUE;
|
2013-04-01 21:43:58 +00:00
|
|
|
}
|
|
|
|
|
2016-09-30 12:11:08 +00:00
|
|
|
static const struct weston_rdp_output_api api = {
|
2022-08-09 18:52:51 +00:00
|
|
|
rdp_head_get_monitor,
|
|
|
|
rdp_output_set_mode,
|
2016-09-30 12:11:08 +00:00
|
|
|
};
|
|
|
|
|
2014-10-11 15:27:30 +00:00
|
|
|
static struct rdp_backend *
|
|
|
|
rdp_backend_create(struct weston_compositor *compositor,
|
2016-04-22 15:05:26 +00:00
|
|
|
struct weston_rdp_backend_config *config)
|
2013-04-01 21:43:58 +00:00
|
|
|
{
|
2014-10-11 15:27:30 +00:00
|
|
|
struct rdp_backend *b;
|
2013-04-01 21:43:58 +00:00
|
|
|
char *fd_str;
|
2016-07-09 01:48:19 +00:00
|
|
|
char *fd_tail;
|
2016-09-30 12:11:08 +00:00
|
|
|
int fd, ret;
|
2013-04-01 21:43:58 +00:00
|
|
|
|
2021-03-11 09:05:16 +00:00
|
|
|
struct weston_head *base, *next;
|
|
|
|
|
2022-08-03 15:36:36 +00:00
|
|
|
b = xzalloc(sizeof *b);
|
2022-04-29 12:22:41 +00:00
|
|
|
b->compositor_tid = gettid();
|
2014-10-11 15:27:30 +00:00
|
|
|
b->compositor = compositor;
|
|
|
|
b->base.destroy = rdp_destroy;
|
2017-10-12 13:21:26 +00:00
|
|
|
b->base.create_output = rdp_output_create;
|
2014-10-11 15:27:30 +00:00
|
|
|
b->rdp_key = config->rdp_key ? strdup(config->rdp_key) : NULL;
|
|
|
|
b->no_clients_resize = config->no_clients_resize;
|
2019-06-20 14:27:27 +00:00
|
|
|
b->force_no_compression = config->force_no_compression;
|
2022-04-14 17:25:43 +00:00
|
|
|
b->remotefx_codec = config->remotefx_codec;
|
2022-05-17 21:16:24 +00:00
|
|
|
b->audio_in_setup = config->audio_in_setup;
|
|
|
|
b->audio_in_teardown = config->audio_in_teardown;
|
|
|
|
b->audio_out_setup = config->audio_out_setup;
|
|
|
|
b->audio_out_teardown = config->audio_out_teardown;
|
2013-04-01 21:43:58 +00:00
|
|
|
|
2022-03-11 19:29:11 +00:00
|
|
|
b->debug = weston_compositor_add_log_scope(compositor,
|
|
|
|
"rdp-backend",
|
|
|
|
"Debug messages from RDP backend\n",
|
|
|
|
NULL, NULL, NULL);
|
|
|
|
b->verbose = weston_compositor_add_log_scope(compositor,
|
|
|
|
"rdp-backend-verbose",
|
|
|
|
"Verbose debug messages from RDP backend\n",
|
|
|
|
NULL, NULL, NULL);
|
|
|
|
|
|
|
|
/* After here, rdp_debug() is ready to be used */
|
|
|
|
|
2022-03-17 17:08:42 +00:00
|
|
|
b->rdp_monitor_refresh_rate = config->refresh_rate * 1000;
|
|
|
|
rdp_debug(b, "RDP backend: WESTON_RDP_MONITOR_REFRESH_RATE: %d\n", b->rdp_monitor_refresh_rate);
|
|
|
|
|
2022-05-10 18:16:55 +00:00
|
|
|
b->clipboard_debug = weston_log_ctx_add_log_scope(b->compositor->weston_log_ctx,
|
|
|
|
"rdp-backend-clipboard",
|
|
|
|
"Debug messages from RDP backend clipboard\n",
|
|
|
|
NULL, NULL, NULL);
|
|
|
|
b->clipboard_verbose = weston_log_ctx_add_log_scope(b->compositor->weston_log_ctx,
|
|
|
|
"rdp-backend-clipboard-verbose",
|
|
|
|
"Debug messages from RDP backend clipboard\n",
|
|
|
|
NULL, NULL, NULL);
|
|
|
|
|
2017-08-30 08:29:49 +00:00
|
|
|
compositor->backend = &b->base;
|
|
|
|
|
2014-03-20 21:34:30 +00:00
|
|
|
if (config->server_cert && config->server_key) {
|
2014-10-11 15:27:30 +00:00
|
|
|
b->server_cert = strdup(config->server_cert);
|
|
|
|
b->server_key = strdup(config->server_key);
|
|
|
|
if (!b->server_cert || !b->server_key)
|
2013-04-01 21:43:58 +00:00
|
|
|
goto err_free_strings;
|
2022-03-15 17:24:42 +00:00
|
|
|
}
|
|
|
|
|
2022-12-29 20:36:20 +00:00
|
|
|
switch (config->renderer) {
|
|
|
|
case WESTON_RENDERER_PIXMAN:
|
|
|
|
case WESTON_RENDERER_AUTO:
|
|
|
|
weston_log("Using Pixman renderer\n");
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
weston_log("Unsupported renderer requested\n");
|
|
|
|
goto err_free_strings;
|
|
|
|
}
|
|
|
|
|
2022-03-15 17:24:42 +00:00
|
|
|
/* if we are listening for client connections on an external listener
|
|
|
|
* fd, we don't need to enforce TLS or RDP security, since FreeRDP
|
|
|
|
* will consider it to be a local connection */
|
|
|
|
fd = config->external_listener_fd;
|
|
|
|
if (fd < 0) {
|
|
|
|
if (!b->rdp_key && (!b->server_cert || !b->server_key)) {
|
|
|
|
weston_log("the RDP compositor requires keys and an optional certificate for RDP or TLS security ("
|
|
|
|
"--rdp4-key or --rdp-tls-cert/--rdp-tls-key)\n");
|
|
|
|
goto err_free_strings;
|
|
|
|
}
|
|
|
|
if (b->server_cert && b->server_key) {
|
|
|
|
b->tls_enabled = 1;
|
|
|
|
rdp_debug(b, "TLS support activated\n");
|
|
|
|
}
|
2013-04-01 21:43:58 +00:00
|
|
|
}
|
|
|
|
|
2022-07-12 14:39:05 +00:00
|
|
|
wl_list_init(&b->peers);
|
|
|
|
|
2014-10-11 15:27:30 +00:00
|
|
|
if (weston_compositor_set_presentation_clock_software(compositor) < 0)
|
2014-09-24 02:08:45 +00:00
|
|
|
goto err_compositor;
|
|
|
|
|
2014-10-11 15:27:30 +00:00
|
|
|
if (pixman_renderer_init(compositor) < 0)
|
2013-04-01 21:43:58 +00:00
|
|
|
goto err_compositor;
|
|
|
|
|
2022-08-09 18:40:30 +00:00
|
|
|
rdp_head_create(compositor, NULL);
|
2013-04-01 21:43:58 +00:00
|
|
|
|
2014-10-11 15:27:30 +00:00
|
|
|
compositor->capabilities |= WESTON_CAP_ARBITRARY_MODES;
|
2014-04-03 00:53:46 +00:00
|
|
|
|
2015-08-06 20:12:19 +00:00
|
|
|
if (!config->env_socket) {
|
2014-10-11 15:27:30 +00:00
|
|
|
b->listener = freerdp_listener_new();
|
|
|
|
b->listener->PeerAccepted = rdp_incoming_peer;
|
|
|
|
b->listener->param4 = b;
|
2022-03-15 17:24:42 +00:00
|
|
|
if (fd >= 0) {
|
|
|
|
rdp_debug(b, "Using external fd for incoming connections: %d\n", fd);
|
|
|
|
|
|
|
|
if (!b->listener->OpenFromSocket(b->listener, fd)) {
|
|
|
|
weston_log("RDP unable to use external listener fd: %d\n", fd);
|
|
|
|
goto err_listener;
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
if (!b->listener->Open(b->listener, config->bind_address, config->port)) {
|
|
|
|
weston_log("RDP unable to bind socket\n");
|
|
|
|
goto err_listener;
|
|
|
|
}
|
2013-04-01 21:43:58 +00:00
|
|
|
}
|
|
|
|
|
2014-10-11 15:27:30 +00:00
|
|
|
if (rdp_implant_listener(b, b->listener) < 0)
|
2022-03-16 21:07:27 +00:00
|
|
|
goto err_listener;
|
2013-04-01 21:43:58 +00:00
|
|
|
} else {
|
|
|
|
/* get the socket from RDP_FD var */
|
|
|
|
fd_str = getenv("RDP_FD");
|
2014-03-20 21:34:30 +00:00
|
|
|
if (!fd_str) {
|
2015-10-01 14:51:32 +00:00
|
|
|
weston_log("RDP_FD env variable not set\n");
|
2022-08-03 16:29:53 +00:00
|
|
|
goto err_compositor;
|
2013-04-01 21:43:58 +00:00
|
|
|
}
|
|
|
|
|
2016-07-09 01:48:19 +00:00
|
|
|
fd = strtoul(fd_str, &fd_tail, 10);
|
2016-07-12 00:02:44 +00:00
|
|
|
if (errno != 0 || fd_tail == fd_str || *fd_tail != '\0'
|
|
|
|
|| rdp_peer_init(freerdp_peer_new(fd), b))
|
2022-08-03 16:29:53 +00:00
|
|
|
goto err_compositor;
|
2013-04-01 21:43:58 +00:00
|
|
|
}
|
|
|
|
|
2016-09-30 12:11:08 +00:00
|
|
|
ret = weston_plugin_api_register(compositor, WESTON_RDP_OUTPUT_API_NAME,
|
|
|
|
&api, sizeof(api));
|
|
|
|
|
|
|
|
if (ret < 0) {
|
|
|
|
weston_log("Failed to register output API.\n");
|
2022-08-03 16:11:53 +00:00
|
|
|
goto err_listener;
|
2016-09-30 12:11:08 +00:00
|
|
|
}
|
|
|
|
|
2014-10-11 15:27:30 +00:00
|
|
|
return b;
|
2013-04-01 21:43:58 +00:00
|
|
|
|
|
|
|
err_listener:
|
2014-10-11 15:27:30 +00:00
|
|
|
freerdp_listener_free(b->listener);
|
2013-04-01 21:43:58 +00:00
|
|
|
err_compositor:
|
2021-03-11 10:27:17 +00:00
|
|
|
wl_list_for_each_safe(base, next, &compositor->head_list, compositor_link) {
|
|
|
|
if (to_rdp_head(base))
|
|
|
|
rdp_head_destroy(base);
|
|
|
|
}
|
2021-03-11 09:05:16 +00:00
|
|
|
|
2014-10-11 15:27:30 +00:00
|
|
|
weston_compositor_shutdown(compositor);
|
2013-04-01 21:43:58 +00:00
|
|
|
err_free_strings:
|
2022-05-10 18:16:55 +00:00
|
|
|
if (b->clipboard_debug)
|
|
|
|
weston_log_scope_destroy(b->clipboard_debug);
|
|
|
|
if (b->clipboard_verbose)
|
|
|
|
weston_log_scope_destroy(b->clipboard_verbose);
|
2022-03-11 19:29:11 +00:00
|
|
|
if (b->debug)
|
|
|
|
weston_log_scope_destroy(b->debug);
|
|
|
|
if (b->verbose)
|
|
|
|
weston_log_scope_destroy(b->verbose);
|
2015-08-01 14:02:54 +00:00
|
|
|
free(b->rdp_key);
|
|
|
|
free(b->server_cert);
|
|
|
|
free(b->server_key);
|
2014-10-11 15:27:30 +00:00
|
|
|
free(b);
|
2013-04-01 21:43:58 +00:00
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
2016-04-22 15:05:26 +00:00
|
|
|
static void
|
|
|
|
config_init_to_defaults(struct weston_rdp_backend_config *config)
|
|
|
|
{
|
2022-12-29 20:36:20 +00:00
|
|
|
config->renderer = WESTON_RENDERER_AUTO;
|
2016-04-22 15:05:26 +00:00
|
|
|
config->bind_address = NULL;
|
|
|
|
config->port = 3389;
|
|
|
|
config->rdp_key = NULL;
|
|
|
|
config->server_cert = NULL;
|
|
|
|
config->server_key = NULL;
|
|
|
|
config->env_socket = 0;
|
|
|
|
config->no_clients_resize = 0;
|
2019-06-20 14:27:27 +00:00
|
|
|
config->force_no_compression = 0;
|
2022-04-14 17:25:43 +00:00
|
|
|
config->remotefx_codec = true;
|
2022-03-15 17:24:42 +00:00
|
|
|
config->external_listener_fd = -1;
|
2022-03-17 17:08:42 +00:00
|
|
|
config->refresh_rate = RDP_DEFAULT_FREQ;
|
2022-05-17 21:16:24 +00:00
|
|
|
config->audio_in_setup = NULL;
|
|
|
|
config->audio_in_teardown = NULL;
|
|
|
|
config->audio_out_setup = NULL;
|
|
|
|
config->audio_out_teardown = NULL;
|
2016-04-22 15:05:26 +00:00
|
|
|
}
|
|
|
|
|
2014-10-11 15:27:30 +00:00
|
|
|
WL_EXPORT int
|
2016-12-02 13:08:44 +00:00
|
|
|
weston_backend_init(struct weston_compositor *compositor,
|
|
|
|
struct weston_backend_config *config_base)
|
2013-04-01 21:43:58 +00:00
|
|
|
{
|
2014-10-11 15:27:30 +00:00
|
|
|
struct rdp_backend *b;
|
2016-04-22 15:05:26 +00:00
|
|
|
struct weston_rdp_backend_config config = {{ 0, }};
|
2013-04-01 21:43:58 +00:00
|
|
|
int major, minor, revision;
|
|
|
|
|
2017-09-27 10:01:10 +00:00
|
|
|
#if FREERDP_VERSION_MAJOR >= 2
|
|
|
|
winpr_InitializeSSL(0);
|
|
|
|
#endif
|
2013-04-01 21:43:58 +00:00
|
|
|
freerdp_get_version(&major, &minor, &revision);
|
|
|
|
weston_log("using FreeRDP version %d.%d.%d\n", major, minor, revision);
|
|
|
|
|
2016-04-22 15:05:26 +00:00
|
|
|
if (config_base == NULL ||
|
|
|
|
config_base->struct_version != WESTON_RDP_BACKEND_CONFIG_VERSION ||
|
|
|
|
config_base->struct_size > sizeof(struct weston_rdp_backend_config)) {
|
|
|
|
weston_log("RDP backend config structure is invalid\n");
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
config_init_to_defaults(&config);
|
|
|
|
memcpy(&config, config_base, config_base->struct_size);
|
|
|
|
|
|
|
|
b = rdp_backend_create(compositor, &config);
|
2014-10-11 15:27:30 +00:00
|
|
|
if (b == NULL)
|
|
|
|
return -1;
|
|
|
|
return 0;
|
2013-04-01 21:43:58 +00:00
|
|
|
}
|