compositor-rdp.c 39.5 KB
Newer Older
David Fort's avatar
David Fort committed
1 2 3
/*
 * Copyright © 2013 Hardening <rdp.effort@gmail.com>
 *
4 5 6 7 8 9 10
 * 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:
David Fort's avatar
David Fort committed
11
 *
12 13 14 15 16 17 18 19 20 21 22 23
 * 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.
David Fort's avatar
David Fort committed
24 25
 */

26
#include "config.h"
David Fort's avatar
David Fort committed
27

28
#include <assert.h>
29
#include <stdint.h>
David Fort's avatar
David Fort committed
30 31 32 33 34
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include <linux/input.h>

35 36 37 38 39 40
#if HAVE_FREERDP_VERSION_H
#include <freerdp/version.h>
#else
/* assume it's a early 1.1 version */
#define FREERDP_VERSION_MAJOR 1
#define FREERDP_VERSION_MINOR 1
41 42 43 44 45 46
#define FREERDP_VERSION_REVISION 0
#endif

#define FREERDP_VERSION_NUMBER ((FREERDP_VERSION_MAJOR * 0x10000) + \
		(FREERDP_VERSION_MINOR * 0x100) + FREERDP_VERSION_REVISION)

47

48 49 50 51 52
#if FREERDP_VERSION_NUMBER >= 0x10201
#define HAVE_SKIP_COMPRESSION
#endif

#if FREERDP_VERSION_NUMBER < 0x10202
53 54 55 56 57 58 59 60
#	define FREERDP_CB_RET_TYPE void
#	define FREERDP_CB_RETURN(V) return
#	define NSC_RESET(C, W, H)
#	define RFX_RESET(C, W, H) do { rfx_context_reset(C); C->width = W; C->height = H; } while(0)
#else
#if FREERDP_VERSION_MAJOR >= 2
#	define NSC_RESET(C, W, H) nsc_context_reset(C, W, H)
#	define RFX_RESET(C, W, H) rfx_context_reset(C, W, H)
61
#else
62
#	define NSC_RESET(C, W, H) do { nsc_context_reset(C); C->width = W; C->height = H; } while(0)
63 64
#	define RFX_RESET(C, W, H) do { rfx_context_reset(C); C->width = W; C->height = H; } while(0)
#endif
65 66
#define FREERDP_CB_RET_TYPE BOOL
#define FREERDP_CB_RETURN(V) return TRUE
67 68
#endif

David Fort's avatar
David Fort committed
69 70 71 72 73 74 75
#include <freerdp/freerdp.h>
#include <freerdp/listener.h>
#include <freerdp/update.h>
#include <freerdp/input.h>
#include <freerdp/codec/color.h>
#include <freerdp/codec/rfx.h>
#include <freerdp/codec/nsc.h>
76
#include <freerdp/locale/keyboard.h>
77
#include <winpr/input.h>
David Fort's avatar
David Fort committed
78

79 80 81 82
#if FREERDP_VERSION_MAJOR >= 2
#include <winpr/ssl.h>
#endif

83
#include "shared/helpers.h"
84
#include "shared/timespec-util.h"
David Fort's avatar
David Fort committed
85
#include "compositor.h"
86
#include "compositor-rdp.h"
David Fort's avatar
David Fort committed
87 88 89
#include "pixman-renderer.h"

#define MAX_FREERDP_FDS 32
90
#define DEFAULT_AXIS_STEP_DISTANCE 10
91
#define RDP_MODE_FREQ 60 * 1000
David Fort's avatar
David Fort committed
92

93
#if FREERDP_VERSION_MAJOR >= 2 && defined(PIXEL_FORMAT_BGRA32) && !defined(PIXEL_FORMAT_B8G8R8A8)
94 95 96 97 98 99 100 101
	/* The RDP API is truly wonderful: the pixel format definition changed
	 * from BGRA32 to B8G8R8A8, but some versions ship with a definition of
	 * PIXEL_FORMAT_BGRA32 which doesn't actually build. Try really, really,
	 * hard to find one which does. */
#	define DEFAULT_PIXEL_FORMAT PIXEL_FORMAT_BGRA32
#else
#	define DEFAULT_PIXEL_FORMAT RDP_PIXEL_FORMAT_B8G8R8A8
#endif
David Fort's avatar
David Fort committed
102 103 104

struct rdp_output;

105 106 107
struct rdp_backend {
	struct weston_backend base;
	struct weston_compositor *compositor;
David Fort's avatar
David Fort committed
108 109 110 111 112 113 114 115 116

	freerdp_listener *listener;
	struct wl_event_source *listener_events[MAX_FREERDP_FDS];
	struct rdp_output *output;

	char *server_cert;
	char *server_key;
	char *rdp_key;
	int tls_enabled;
117
	int no_clients_resize;
David Fort's avatar
David Fort committed
118 119 120 121 122 123 124 125 126 127
};

enum peer_item_flags {
	RDP_PEER_ACTIVATED      = (1 << 0),
	RDP_PEER_OUTPUT_ENABLED = (1 << 1),
};

struct rdp_peers_item {
	int flags;
	freerdp_peer *peer;
128
	struct weston_seat *seat;
David Fort's avatar
David Fort committed
129 130 131 132 133 134 135 136 137 138 139 140 141 142 143

	struct wl_list link;
};

struct rdp_output {
	struct weston_output base;
	struct wl_event_source *finish_frame_timer;
	pixman_image_t *shadow_surface;

	struct wl_list peers;
};

struct rdp_peer_context {
	rdpContext _p;

144
	struct rdp_backend *rdpBackend;
David Fort's avatar
David Fort committed
145 146 147 148 149 150 151 152 153 154
	struct wl_event_source *events[MAX_FREERDP_FDS];
	RFX_CONTEXT *rfx_context;
	wStream *encode_stream;
	RFX_RECT *rfx_rects;
	NSC_CONTEXT *nsc_context;

	struct rdp_peers_item item;
};
typedef struct rdp_peer_context RdpPeerContext;

155 156 157 158 159 160 161 162 163 164 165 166
static inline struct rdp_output *
to_rdp_output(struct weston_output *base)
{
	return container_of(base, struct rdp_output, base);
}

static inline struct rdp_backend *
to_rdp_backend(struct weston_compositor *base)
{
	return container_of(base->backend, struct rdp_backend, base);
}

David Fort's avatar
David Fort committed
167 168 169 170 171 172 173 174 175 176 177
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;
	rdpUpdate *update = peer->update;
	SURFACE_BITS_COMMAND *cmd = &update->surface_bits_command;
	RdpPeerContext *context = (RdpPeerContext *)peer->context;

178 179
	Stream_Clear(context->encode_stream);
	Stream_SetPosition(context->encode_stream, 0);
David Fort's avatar
David Fort committed
180 181 182 183

	width = (damage->extents.x2 - damage->extents.x1);
	height = (damage->extents.y2 - damage->extents.y1);

184 185 186 187 188
#ifdef HAVE_SKIP_COMPRESSION
	cmd->skipCompression = TRUE;
#else
	memset(cmd, 0, sizeof(*cmd));
#endif
David Fort's avatar
David Fort committed
189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218
	cmd->destLeft = damage->extents.x1;
	cmd->destTop = damage->extents.y1;
	cmd->destRight = damage->extents.x2;
	cmd->destBottom = damage->extents.y2;
	cmd->bpp = 32;
	cmd->codecID = peer->settings->RemoteFxCodecId;
	cmd->width = width;
	cmd->height = height;

	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)
	);

219 220
	cmd->bitmapDataLength = Stream_GetPosition(context->encode_stream);
	cmd->bitmapData = Stream_Buffer(context->encode_stream);
David Fort's avatar
David Fort committed
221 222 223 224 225 226 227 228 229 230 231 232 233 234

	update->SurfaceBits(update->context, cmd);
}


static void
rdp_peer_refresh_nsc(pixman_region32_t *damage, pixman_image_t *image, freerdp_peer *peer)
{
	int width, height;
	uint32_t *ptr;
	rdpUpdate *update = peer->update;
	SURFACE_BITS_COMMAND *cmd = &update->surface_bits_command;
	RdpPeerContext *context = (RdpPeerContext *)peer->context;

235 236
	Stream_Clear(context->encode_stream);
	Stream_SetPosition(context->encode_stream, 0);
David Fort's avatar
David Fort committed
237 238 239 240

	width = (damage->extents.x2 - damage->extents.x1);
	height = (damage->extents.y2 - damage->extents.y1);

241 242 243 244 245
#ifdef HAVE_SKIP_COMPRESSION
	cmd->skipCompression = TRUE;
#else
	memset(cmd, 0, sizeof(*cmd));
#endif
David Fort's avatar
David Fort committed
246 247 248 249 250 251 252 253 254 255 256 257 258 259 260
	cmd->destLeft = damage->extents.x1;
	cmd->destTop = damage->extents.y1;
	cmd->destRight = damage->extents.x2;
	cmd->destBottom = damage->extents.y2;
	cmd->bpp = 32;
	cmd->codecID = peer->settings->NSCodecId;
	cmd->width = width;
	cmd->height = height;

	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,
			cmd->width,	cmd->height,
			pixman_image_get_stride(image));
261 262
	cmd->bitmapDataLength = Stream_GetPosition(context->encode_stream);
	cmd->bitmapData = Stream_Buffer(context->encode_stream);
David Fort's avatar
David Fort committed
263 264 265
	update->SurfaceBits(update->context, cmd);
}

David Fort's avatar
David Fort committed
266
static void
Dawid Gajownik's avatar
Dawid Gajownik committed
267 268
pixman_image_flipped_subrect(const pixman_box32_t *rect, pixman_image_t *img, BYTE *dest)
{
David Fort's avatar
David Fort committed
269 270 271 272 273 274 275 276 277 278 279
	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);
}

David Fort's avatar
David Fort committed
280 281 282 283 284
static void
rdp_peer_refresh_raw(pixman_region32_t *region, pixman_image_t *image, freerdp_peer *peer)
{
	rdpUpdate *update = peer->update;
	SURFACE_BITS_COMMAND *cmd = &update->surface_bits_command;
David Fort's avatar
David Fort committed
285 286 287 288 289 290 291 292 293 294 295 296
	SURFACE_FRAME_MARKER *marker = &update->surface_frame_marker;
	pixman_box32_t *rect, subrect;
	int nrects, i;
	int heightIncrement, remainingHeight, top;

	rect = pixman_region32_rectangles(region, &nrects);
	if (!nrects)
		return;

	marker->frameId++;
	marker->frameAction = SURFACECMD_FRAMEACTION_BEGIN;
	update->SurfaceFrameMarker(peer->context, marker);
David Fort's avatar
David Fort committed
297

298
	memset(cmd, 0, sizeof(*cmd));
David Fort's avatar
David Fort committed
299 300
	cmd->bpp = 32;
	cmd->codecID = 0;
David Fort's avatar
David Fort committed
301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335

	for (i = 0; i < nrects; i++, rect++) {
		/*weston_log("rect(%d,%d, %d,%d)\n", rect->x1, rect->y1, rect->x2, rect->y2);*/
		cmd->destLeft = rect->x1;
		cmd->destRight = rect->x2;
		cmd->width = rect->x2 - rect->x1;

		heightIncrement = peer->settings->MultifragMaxRequestSize / (16 + cmd->width * 4);
		remainingHeight = rect->y2 - rect->y1;
		top = rect->y1;

		subrect.x1 = rect->x1;
		subrect.x2 = rect->x2;

		while (remainingHeight) {
			   cmd->height = (remainingHeight > heightIncrement) ? heightIncrement : remainingHeight;
			   cmd->destTop = top;
			   cmd->destBottom = top + cmd->height;
			   cmd->bitmapDataLength = cmd->width * cmd->height * 4;
			   cmd->bitmapData = (BYTE *)realloc(cmd->bitmapData, cmd->bitmapDataLength);

			   subrect.y1 = top;
			   subrect.y2 = top + cmd->height;
			   pixman_image_flipped_subrect(&subrect, image, cmd->bitmapData);

			   /*weston_log("*  sending (%d,%d, %d,%d)\n", subrect.x1, subrect.y1, subrect.x2, subrect.y2); */
			   update->SurfaceBits(peer->context, cmd);

			   remainingHeight -= cmd->height;
			   top += cmd->height;
		}
	}

	marker->frameAction = SURFACECMD_FRAMEACTION_END;
	update->SurfaceFrameMarker(peer->context, marker);
David Fort's avatar
David Fort committed
336 337 338 339 340 341
}

static void
rdp_peer_refresh_region(pixman_region32_t *region, freerdp_peer *peer)
{
	RdpPeerContext *context = (RdpPeerContext *)peer->context;
342
	struct rdp_output *output = context->rdpBackend->output;
David Fort's avatar
David Fort committed
343
	rdpSettings *settings = peer->settings;
David Fort's avatar
David Fort committed
344 345 346 347 348 349

	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
David Fort's avatar
David Fort committed
350 351 352
		rdp_peer_refresh_raw(region, output->shadow_surface, peer);
}

353 354 355
static void
rdp_output_start_repaint_loop(struct weston_output *output)
{
356
	struct timespec ts;
357

358
	weston_compositor_read_presentation_clock(output->compositor, &ts);
359
	weston_output_finish_frame(output, &ts, WP_PRESENTATION_FEEDBACK_INVALID);
360
}
David Fort's avatar
David Fort committed
361

362
static int
363 364
rdp_output_repaint(struct weston_output *output_base, pixman_region32_t *damage,
		   void *repaint_data)
David Fort's avatar
David Fort committed
365 366 367 368 369 370 371 372
{
	struct rdp_output *output = container_of(output_base, struct rdp_output, base);
	struct weston_compositor *ec = output->base.compositor;
	struct rdp_peers_item *outputPeer;

	pixman_renderer_output_set_buffer(output_base, output->shadow_surface);
	ec->renderer->repaint_output(&output->base, damage);

373 374 375 376 377 378 379
	if (pixman_region32_not_empty(damage)) {
		wl_list_for_each(outputPeer, &output->peers, link) {
			if ((outputPeer->flags & RDP_PEER_ACTIVATED) &&
					(outputPeer->flags & RDP_PEER_OUTPUT_ENABLED))
			{
				rdp_peer_refresh_region(damage, outputPeer->peer);
			}
David Fort's avatar
David Fort committed
380 381 382 383 384 385 386
		}
	}

	pixman_region32_subtract(&ec->primary_plane.damage,
				 &ec->primary_plane.damage, damage);

	wl_event_source_timer_update(output->finish_frame_timer, 16);
387
	return 0;
David Fort's avatar
David Fort committed
388 389 390 391 392
}

static int
finish_frame_handler(void *data)
{
393 394 395
	struct rdp_output *output = data;
	struct timespec ts;

396
	weston_compositor_read_presentation_clock(output->base.compositor, &ts);
397
	weston_output_finish_frame(&output->base, &ts, 0);
David Fort's avatar
David Fort committed
398 399 400 401

	return 1;
}

402
static struct weston_mode *
Dawid Gajownik's avatar
Dawid Gajownik committed
403 404
rdp_insert_new_mode(struct weston_output *output, int width, int height, int rate)
{
405 406 407 408 409 410 411 412 413 414
	struct weston_mode *ret;
	ret = zalloc(sizeof *ret);
	if (!ret)
		return NULL;
	ret->width = width;
	ret->height = height;
	ret->refresh = rate;
	wl_list_insert(&output->mode_list, &ret->link);
	return ret;
}
David Fort's avatar
David Fort committed
415 416

static struct weston_mode *
Dawid Gajownik's avatar
Dawid Gajownik committed
417 418
ensure_matching_mode(struct weston_output *output, struct weston_mode *target)
{
David Fort's avatar
David Fort committed
419 420 421
	struct weston_mode *local;

	wl_list_for_each(local, &output->mode_list, link) {
422
		if ((local->width == target->width) && (local->height == target->height))
David Fort's avatar
David Fort committed
423 424
			return local;
	}
425 426

	return rdp_insert_new_mode(output, target->width, target->height, RDP_MODE_FREQ);
David Fort's avatar
David Fort committed
427 428 429
}

static int
Dawid Gajownik's avatar
Dawid Gajownik committed
430 431
rdp_switch_mode(struct weston_output *output, struct weston_mode *target_mode)
{
David Fort's avatar
David Fort committed
432 433 434 435 436 437
	struct rdp_output *rdpOutput = container_of(output, struct rdp_output, base);
	struct rdp_peers_item *rdpPeer;
	rdpSettings *settings;
	pixman_image_t *new_shadow_buffer;
	struct weston_mode *local_mode;

438 439
	local_mode = ensure_matching_mode(output, target_mode);
	if (!local_mode) {
David Fort's avatar
David Fort committed
440 441 442 443
		weston_log("mode %dx%d not available\n", target_mode->width, target_mode->height);
		return -ENOENT;
	}

444
	if (local_mode == output->current_mode)
David Fort's avatar
David Fort committed
445 446
		return 0;

David Fort's avatar
David Fort committed
447 448
	output->current_mode->flags &= ~WL_OUTPUT_MODE_CURRENT;

449
	output->current_mode = local_mode;
David Fort's avatar
David Fort committed
450
	output->current_mode->flags |= WL_OUTPUT_MODE_CURRENT;
David Fort's avatar
David Fort committed
451 452 453 454 455 456 457 458 459 460 461 462 463

	pixman_renderer_output_destroy(output);
	pixman_renderer_output_create(output);

	new_shadow_buffer = pixman_image_create_bits(PIXMAN_x8r8g8b8, target_mode->width,
			target_mode->height, 0, target_mode->width * 4);
	pixman_image_composite32(PIXMAN_OP_SRC, rdpOutput->shadow_surface, 0, new_shadow_buffer,
			0, 0, 0, 0, 0, 0, target_mode->width, target_mode->height);
	pixman_image_unref(rdpOutput->shadow_surface);
	rdpOutput->shadow_surface = new_shadow_buffer;

	wl_list_for_each(rdpPeer, &rdpOutput->peers, link) {
		settings = rdpPeer->peer->settings;
464 465
		if (settings->DesktopWidth == (UINT32)target_mode->width &&
				settings->DesktopHeight == (UINT32)target_mode->height)
466 467 468
			continue;

		if (!settings->DesktopResize) {
David Fort's avatar
David Fort committed
469 470 471 472 473 474 475 476 477 478 479 480
			/* too bad this peer does not support desktop resize */
			rdpPeer->peer->Close(rdpPeer->peer);
		} else {
			settings->DesktopWidth = target_mode->width;
			settings->DesktopHeight = target_mode->height;
			rdpPeer->peer->update->DesktopResize(rdpPeer->peer->context);
		}
	}
	return 0;
}

static int
481 482
rdp_output_set_size(struct weston_output *base,
		    int width, int height)
David Fort's avatar
David Fort committed
483
{
484
	struct rdp_output *output = to_rdp_output(base);
485 486
	struct weston_mode *currentMode;
	struct weston_mode initMode;
David Fort's avatar
David Fort committed
487

488 489
	/* We can only be called once. */
	assert(!output->base.current_mode);
David Fort's avatar
David Fort committed
490 491 492

	wl_list_init(&output->peers);

493 494 495 496 497 498 499
	initMode.flags = WL_OUTPUT_MODE_CURRENT | WL_OUTPUT_MODE_PREFERRED;
	initMode.width = width;
	initMode.height = height;
	initMode.refresh = RDP_MODE_FREQ;

	currentMode = ensure_matching_mode(&output->base, &initMode);
	if (!currentMode)
500
		return -1;
David Fort's avatar
David Fort committed
501

David Fort's avatar
David Fort committed
502
	output->base.current_mode = output->base.native_mode = currentMode;
David Fort's avatar
David Fort committed
503 504
	output->base.make = "weston";
	output->base.model = "rdp";
505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526

	/* XXX: Calculate proper size. */
	output->base.mm_width = width;
	output->base.mm_height = height;

	output->base.start_repaint_loop = rdp_output_start_repaint_loop;
	output->base.repaint = rdp_output_repaint;
	output->base.assign_planes = NULL;
	output->base.set_backlight = NULL;
	output->base.set_dpms = NULL;
	output->base.switch_mode = rdp_switch_mode;

	return 0;
}

static int
rdp_output_enable(struct weston_output *base)
{
	struct rdp_output *output = to_rdp_output(base);
	struct rdp_backend *b = to_rdp_backend(base->compositor);
	struct wl_event_loop *loop;

David Fort's avatar
David Fort committed
527
	output->shadow_surface = pixman_image_create_bits(PIXMAN_x8r8g8b8,
528 529 530 531
							  output->base.current_mode->width,
							  output->base.current_mode->height,
							  NULL,
							  output->base.current_mode->width * 4);
David Fort's avatar
David Fort committed
532 533
	if (output->shadow_surface == NULL) {
		weston_log("Failed to create surface for frame buffer.\n");
534
		return -1;
David Fort's avatar
David Fort committed
535 536
	}

537 538 539 540
	if (pixman_renderer_output_create(&output->base) < 0) {
		pixman_image_unref(output->shadow_surface);
		return -1;
	}
David Fort's avatar
David Fort committed
541

542
	loop = wl_display_get_event_loop(b->compositor->wl_display);
David Fort's avatar
David Fort committed
543 544
	output->finish_frame_timer = wl_event_loop_add_timer(loop, finish_frame_handler, output);

545
	b->output = output;
David Fort's avatar
David Fort committed
546 547

	return 0;
548 549 550 551 552 553 554 555 556 557 558
}

static int
rdp_output_disable(struct weston_output *base)
{
	struct rdp_output *output = to_rdp_output(base);
	struct rdp_backend *b = to_rdp_backend(base->compositor);

	if (!output->base.enabled)
		return 0;

559 560 561
	pixman_image_unref(output->shadow_surface);
	pixman_renderer_output_destroy(&output->base);

562 563
	wl_event_source_remove(output->finish_frame_timer);
	b->output = NULL;
David Fort's avatar
David Fort committed
564

565 566 567 568 569 570 571 572 573
	return 0;
}

static void
rdp_output_destroy(struct weston_output *base)
{
	struct rdp_output *output = to_rdp_output(base);

	rdp_output_disable(&output->base);
574
	weston_output_release(&output->base);
575

David Fort's avatar
David Fort committed
576
	free(output);
577 578 579 580 581 582 583 584 585 586 587
}

static int
rdp_backend_create_output(struct weston_compositor *compositor)
{
	struct rdp_output *output;

	output = zalloc(sizeof *output);
	if (output == NULL)
		return -1;

588 589
	weston_output_init(&output->base, compositor, "rdp");

590 591 592 593 594 595 596
	output->base.destroy = rdp_output_destroy;
	output->base.disable = rdp_output_disable;
	output->base.enable = rdp_output_enable;

	weston_compositor_add_pending_output(&output->base, compositor);

	return 0;
David Fort's avatar
David Fort committed
597 598 599 600 601 602 603 604 605 606
}

static void
rdp_restore(struct weston_compositor *ec)
{
}

static void
rdp_destroy(struct weston_compositor *ec)
{
607
	struct rdp_backend *b = to_rdp_backend(ec);
608 609
	int i;

David Fort's avatar
David Fort committed
610
	weston_compositor_shutdown(ec);
611 612 613 614 615
	for (i = 0; i < MAX_FREERDP_FDS; i++)
		if (b->listener_events[i])
			wl_event_source_remove(b->listener_events[i]);

	freerdp_listener_free(b->listener);
David Fort's avatar
David Fort committed
616

617 618 619 620
	free(b->server_cert);
	free(b->server_key);
	free(b->rdp_key);
	free(b);
David Fort's avatar
David Fort committed
621 622 623
}

static
Dawid Gajownik's avatar
Dawid Gajownik committed
624 625
int rdp_listener_activity(int fd, uint32_t mask, void *data)
{
David Fort's avatar
David Fort committed
626 627 628 629
	freerdp_listener* instance = (freerdp_listener *)data;

	if (!(mask & WL_EVENT_READABLE))
		return 0;
Dawid Gajownik's avatar
Dawid Gajownik committed
630
	if (!instance->CheckFileDescriptor(instance)) {
David Fort's avatar
David Fort committed
631 632 633 634 635 636 637
		weston_log("failed to check FreeRDP file descriptor\n");
		return -1;
	}
	return 0;
}

static
Dawid Gajownik's avatar
Dawid Gajownik committed
638 639
int rdp_implant_listener(struct rdp_backend *b, freerdp_listener* instance)
{
David Fort's avatar
David Fort committed
640 641 642 643 644 645 646 647 648 649
	int i, fd;
	int rcount = 0;
	void* rfds[MAX_FREERDP_FDS];
	struct wl_event_loop *loop;

	if (!instance->GetFileDescriptor(instance, rfds, &rcount)) {
		weston_log("Failed to get FreeRDP file descriptor\n");
		return -1;
	}

650
	loop = wl_display_get_event_loop(b->compositor->wl_display);
David Fort's avatar
David Fort committed
651 652
	for (i = 0; i < rcount; i++) {
		fd = (int)(long)(rfds[i]);
653
		b->listener_events[i] = wl_event_loop_add_fd(loop, fd, WL_EVENT_READABLE,
David Fort's avatar
David Fort committed
654 655 656
				rdp_listener_activity, instance);
	}

Dawid Gajownik's avatar
Dawid Gajownik committed
657
	for ( ; i < MAX_FREERDP_FDS; i++)
658
		b->listener_events[i] = 0;
David Fort's avatar
David Fort committed
659 660 661 662
	return 0;
}


663
static FREERDP_CB_RET_TYPE
David Fort's avatar
David Fort committed
664 665 666
rdp_peer_context_new(freerdp_peer* client, RdpPeerContext* context)
{
	context->item.peer = client;
667
	context->item.flags = RDP_PEER_OUTPUT_ENABLED;
David Fort's avatar
David Fort committed
668

669
#if FREERDP_VERSION_MAJOR == 1 && FREERDP_VERSION_MINOR == 1
David Fort's avatar
David Fort committed
670
	context->rfx_context = rfx_context_new();
671 672 673
#else
	context->rfx_context = rfx_context_new(TRUE);
#endif
674 675 676 677
	if (!context->rfx_context) {
		FREERDP_CB_RETURN(FALSE);
	}

David Fort's avatar
David Fort committed
678 679 680
	context->rfx_context->mode = RLGR3;
	context->rfx_context->width = client->settings->DesktopWidth;
	context->rfx_context->height = client->settings->DesktopHeight;
681
	rfx_context_set_pixel_format(context->rfx_context, DEFAULT_PIXEL_FORMAT);
David Fort's avatar
David Fort committed
682 683

	context->nsc_context = nsc_context_new();
684 685 686
	if (!context->nsc_context)
		goto out_error_nsc;

687
	nsc_context_set_pixel_format(context->nsc_context, DEFAULT_PIXEL_FORMAT);
David Fort's avatar
David Fort committed
688

689
	context->encode_stream = Stream_New(NULL, 65536);
690 691 692 693 694 695 696 697 698 699
	if (!context->encode_stream)
		goto out_error_stream;

	FREERDP_CB_RETURN(TRUE);

out_error_nsc:
	rfx_context_free(context->rfx_context);
out_error_stream:
	nsc_context_free(context->nsc_context);
	FREERDP_CB_RETURN(FALSE);
David Fort's avatar
David Fort committed
700 701 702 703 704 705
}

static void
rdp_peer_context_free(freerdp_peer* client, RdpPeerContext* context)
{
	int i;
706
	if (!context)
David Fort's avatar
David Fort committed
707 708 709
		return;

	wl_list_remove(&context->item.link);
Dawid Gajownik's avatar
Dawid Gajownik committed
710
	for (i = 0; i < MAX_FREERDP_FDS; i++) {
711
		if (context->events[i])
David Fort's avatar
David Fort committed
712 713 714
			wl_event_source_remove(context->events[i]);
	}

715
	if (context->item.flags & RDP_PEER_ACTIVATED) {
716 717 718 719
		weston_seat_release_keyboard(context->item.seat);
		weston_seat_release_pointer(context->item.seat);
		/* XXX we should weston_seat_release(context->item.seat); here
		 * but it would crash on reconnect */
720
	}
721

722
	Stream_Free(context->encode_stream, TRUE);
David Fort's avatar
David Fort committed
723 724 725 726 727 728 729
	nsc_context_free(context->nsc_context);
	rfx_context_free(context->rfx_context);
	free(context->rfx_rects);
}


static int
Dawid Gajownik's avatar
Dawid Gajownik committed
730 731
rdp_client_activity(int fd, uint32_t mask, void *data)
{
David Fort's avatar
David Fort committed
732 733 734 735 736 737 738 739 740 741 742 743 744 745 746 747 748 749 750 751 752
	freerdp_peer* client = (freerdp_peer *)data;

	if (!client->CheckFileDescriptor(client)) {
		weston_log("unable to checkDescriptor for %p\n", client);
		goto out_clean;
	}
	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 {
753
	UINT32 rdpLayoutCode;
754 755
	const char *xkbLayout;
	const char *xkbVariant;
David Fort's avatar
David Fort committed
756 757
};

758 759 760 761 762 763 764 765 766 767 768 769 770 771 772 773 774 775 776 777 778 779 780 781 782 783 784 785 786 787 788 789 790 791 792 793 794 795 796 797 798 799 800 801 802 803 804 805 806 807 808 809 810 811 812 813 814 815 816 817 818 819 820 821 822 823 824 825 826 827 828 829 830 831 832 833 834 835 836 837 838 839 840 841 842 843 844 845 846 847 848 849 850 851 852 853 854 855 856 857 858 859 860 861 862 863 864 865 866 867 868 869 870 871
/* table reversed from
	https://github.com/awakecoding/FreeRDP/blob/master/libfreerdp/locale/xkb_layout_ids.c#L811 */
static
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},
	{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},
	{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},
	{KBD_JAPANESE_INPUT_SYSTEM_MS_IME2002, "jp", "kana"},
	{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"},
	{KBD_FARSI, "af", 0},
	{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"},
	{KBD_PORTUGUESE_BRAZILIAN_ABNT2, "br", "nativo"},
	{KBD_CANADIAN_MULTILINGUAL_STANDARD, "ca", "multix"},
	{KBD_GAELIC, "ie", "CloGaelach"},

	{0x00000000, 0, 0},
David Fort's avatar
David Fort committed
872 873 874 875
};

/* taken from 2.2.7.1.6 Input Capability Set (TS_INPUT_CAPABILITYSET) */
static char *rdp_keyboard_types[] = {
876 877 878 879
	"",	/* 0: unused */
	"", /* 1: IBM PC/XT or compatible (83-key) keyboard */
	"", /* 2: Olivetti "ICO" (102-key) keyboard */
	"", /* 3: IBM PC/AT (84-key) or similar keyboard */
David Fort's avatar
David Fort committed
880
	"pc102",/* 4: IBM enhanced (101- or 102-key) keyboard */
881 882 883
	"", /* 5: Nokia 1050 and similar keyboards */
	"",	/* 6: Nokia 9140 and similar keyboards */
	""	/* 7: Japanese keyboard */
David Fort's avatar
David Fort committed
884 885 886
};

static BOOL
887
xf_peer_activate(freerdp_peer* client)
David Fort's avatar
David Fort committed
888 889
{
	RdpPeerContext *peerCtx;
890
	struct rdp_backend *b;
David Fort's avatar
David Fort committed
891 892
	struct rdp_output *output;
	rdpSettings *settings;
893
	rdpPointerUpdate *pointer;
894
	struct rdp_peers_item *peersItem;
David Fort's avatar
David Fort committed
895 896 897
	struct xkb_context *xkbContext;
	struct xkb_rule_names xkbRuleNames;
	struct xkb_keymap *keymap;
898
	struct weston_output *weston_output;
David Fort's avatar
David Fort committed
899
	int i;
900 901
	pixman_box32_t box;
	pixman_region32_t damage;
902
	char seat_name[50];
903

David Fort's avatar
David Fort committed
904 905

	peerCtx = (RdpPeerContext *)client->context;
906
	b = peerCtx->rdpBackend;
907
	peersItem = &peerCtx->item;
908
	output = b->output;
David Fort's avatar
David Fort committed
909 910
	settings = client->settings;

David Fort's avatar
David Fort committed
911
	if (!settings->SurfaceCommandsEnabled) {
David Fort's avatar
David Fort committed
912 913 914 915
		weston_log("client doesn't support required SurfaceCommands\n");
		return FALSE;
	}

David Fort's avatar
David Fort committed
916
	if (output->base.width != (int)settings->DesktopWidth ||
David Fort's avatar
David Fort committed
917 918
			output->base.height != (int)settings->DesktopHeight)
	{
919
		if (b->no_clients_resize) {
920 921 922 923 924 925 926 927 928 929 930 931 932 933 934 935 936 937 938 939 940
			/* RDP peers don't dictate their resolution to weston */
			if (!settings->DesktopResize) {
				/* peer does not support desktop resize */
				weston_log("%s: client doesn't support resizing, closing connection\n", __FUNCTION__);
				return FALSE;
			} else {
				settings->DesktopWidth = output->base.width;
				settings->DesktopHeight = output->base.height;
				client->update->DesktopResize(client->context);
			}
		} else {
			/* ask weston to adjust size */
			struct weston_mode new_mode;
			struct weston_mode *target_mode;
			new_mode.width = (int)settings->DesktopWidth;
			new_mode.height = (int)settings->DesktopHeight;
			target_mode = ensure_matching_mode(&output->base, &new_mode);
			if (!target_mode) {
				weston_log("client mode not found\n");
				return FALSE;
			}
941
			weston_output_mode_set_native(&output->base, target_mode, 1);
942 943
			output->base.width = new_mode.width;
			output->base.height = new_mode.height;
David Fort's avatar
David Fort committed
944 945 946
		}
	}

947 948 949
	weston_output = &output->base;
	RFX_RESET(peerCtx->rfx_context, weston_output->width, weston_output->height);
	NSC_RESET(peerCtx->nsc_context, weston_output->width, weston_output->height);
950 951 952 953 954 955

	if (peersItem->flags & RDP_PEER_ACTIVATED)
		return TRUE;

	/* when here it's the first reactivation, we need to setup a little more */
	weston_log("kbd_layout:0x%x kbd_type:0x%x kbd_subType:0x%x kbd_functionKeys:0x%x\n",
David Fort's avatar
David Fort committed
956 957 958 959
			settings->KeyboardLayout, settings->KeyboardType, settings->KeyboardSubType,
			settings->KeyboardFunctionKey);

	memset(&xkbRuleNames, 0, sizeof(xkbRuleNames));
960
	if (settings->KeyboardType <= 7)
David Fort's avatar
David Fort committed
961
		xkbRuleNames.model = rdp_keyboard_types[settings->KeyboardType];
Dawid Gajownik's avatar
Dawid Gajownik committed
962
	for (i = 0; rdp_keyboards[i].rdpLayoutCode; i++) {
963
		if (rdp_keyboards[i].rdpLayoutCode == settings->KeyboardLayout) {
David Fort's avatar
David Fort committed
964
			xkbRuleNames.layout = rdp_keyboards[i].xkbLayout;
965
			xkbRuleNames.variant = rdp_keyboards[i].xkbVariant;
966 967
			weston_log("%s: matching layout=%s variant=%s\n", __FUNCTION__,
					xkbRuleNames.layout, xkbRuleNames.variant);
David Fort's avatar
David Fort committed
968 969 970 971 972
			break;
		}
	}

	keymap = NULL;
973
	if (xkbRuleNames.layout) {
David Fort's avatar
David Fort committed
974
		xkbContext = xkb_context_new(0);
975
		if (!xkbContext) {
David Fort's avatar
David Fort committed
976 977 978 979 980 981 982
			weston_log("unable to create a xkb_context\n");
			return FALSE;
		}

		keymap = xkb_keymap_new_from_names(xkbContext, &xkbRuleNames, 0);
	}

983 984 985 986 987
	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);

988 989 990 991 992 993 994 995 996 997
	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);
	weston_seat_init_pointer(peersItem->seat);
998 999

	peersItem->flags |= RDP_PEER_ACTIVATED;
1000 1001 1002 1003 1004 1005 1006 1007 1008 1009 1010 1011 1012 1013 1014 1015 1016

	/* disable pointer on the client side */
	pointer = client->update->pointer;
	pointer->pointer_system.type = SYSPTR_NULL;
	pointer->PointerSystem(client->context, &pointer->pointer_system);

	/* sends a full refresh */
	box.x1 = 0;
	box.y1 = 0;
	box.x2 = output->base.width;
	box.y2 = output->base.height;
	pixman_region32_init_with_extents(&damage, &box);

	rdp_peer_refresh_region(&damage, client);

	pixman_region32_fini(&damage);

David Fort's avatar
David Fort committed
1017 1018 1019
	return TRUE;
}

1020 1021
static BOOL
xf_peer_post_connect(freerdp_peer *client)
David Fort's avatar
David Fort committed
1022 1023 1024 1025
{
	return TRUE;
}

1026
static FREERDP_CB_RET_TYPE
Dawid Gajownik's avatar
Dawid Gajownik committed
1027 1028
xf_mouseEvent(rdpInput *input, UINT16 flags, UINT16 x, UINT16 y)
{
David Fort's avatar
David Fort committed
1029 1030 1031
	RdpPeerContext *peerContext = (RdpPeerContext *)input->context;
	struct rdp_output *output;
	uint32_t button = 0;
1032
	bool need_frame = false;
1033
	struct timespec time;
David Fort's avatar
David Fort committed
1034 1035

	if (flags & PTR_FLAGS_MOVE) {
1036
		output = peerContext->rdpBackend->output;
1037
		if (x < output->base.width && y < output->base.height) {
1038 1039
			timespec_from_msec(&time, weston_compositor_get_time());
			notify_motion_absolute(peerContext->item.seat, &time,
1040
					x, y);
1041
			need_frame = true;
David Fort's avatar
David Fort committed
1042 1043 1044 1045 1046 1047 1048 1049 1050 1051
		}
	}

	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;

1052
	if (button) {
1053 1054
		timespec_from_msec(&time, weston_compositor_get_time());
		notify_button(peerContext->item.seat, &time, button,
David Fort's avatar
David Fort committed
1055 1056
			(flags & PTR_FLAGS_DOWN) ? WL_POINTER_BUTTON_STATE_PRESSED : WL_POINTER_BUTTON_STATE_RELEASED
		);
1057
		need_frame = true;
David Fort's avatar
David Fort committed
1058
	}
David Fort's avatar
David Fort committed
1059 1060

	if (flags & PTR_FLAGS_WHEEL) {
1061
		struct weston_pointer_axis_event weston_event;
1062
		double value;
1063

David Fort's avatar
David Fort committed
1064 1065 1066 1067
		/* DEFAULT_AXIS_STEP_DISTANCE is stolen from compositor-x11.c
		 * The RDP specs says the lower bits of flags contains the "the number of rotation
		 * units the mouse wheel was rotated".
		 *
1068
		 * https://blogs.msdn.microsoft.com/oldnewthing/20130123-00/?p=5473 explains the 120 value
David Fort's avatar
David Fort committed
1069
		 */
1070
		value = (flags & 0xff) / 120.0;
David Fort's avatar
David Fort committed
1071
		if (flags & PTR_FLAGS_WHEEL_NEGATIVE)
1072
			value = -value;
David Fort's avatar
David Fort committed
1073

1074
		weston_event.axis = WL_POINTER_AXIS_VERTICAL_SCROLL;
1075
		weston_event.value = DEFAULT_AXIS_STEP_DISTANCE * value;
1076 1077
		weston_event.discrete = (int)value;
		weston_event.has_discrete = true;
1078

1079 1080 1081
		timespec_from_msec(&time, weston_compositor_get_time());

		notify_axis(peerContext->item.seat, &time, &weston_event);
1082
		need_frame = true;
David Fort's avatar
David Fort committed
1083
	}
1084

1085
	if (need_frame)
1086
		notify_pointer_frame(peerContext->item.seat);
1087

1088
	FREERDP_CB_RETURN(TRUE);
David Fort's avatar
David Fort committed
1089 1090
}

1091
static FREERDP_CB_RET_TYPE
Dawid Gajownik's avatar
Dawid Gajownik committed
1092 1093
xf_extendedMouseEvent(rdpInput *input, UINT16 flags, UINT16 x, UINT16 y)
{
David Fort's avatar
David Fort committed
1094 1095
	RdpPeerContext *peerContext = (RdpPeerContext *)input->context;
	struct rdp_output *output;
1096
	struct timespec time;
David Fort's avatar
David Fort committed
1097

1098
	output = peerContext->rdpBackend->output;
1099
	if (x < output->base.width && y < output->base.height) {
1100 1101
		timespec_from_msec(&time, weston_compositor_get_time());
		notify_motion_absolute(peerContext->item.seat, &time, x, y);
David Fort's avatar
David Fort committed
1102
	}
1103 1104

	FREERDP_CB_RETURN(TRUE);
David Fort's avatar
David Fort committed
1105 1106 1107
}


1108
static FREERDP_CB_RET_TYPE
David Fort's avatar
David Fort committed
1109 1110 1111 1112
xf_input_synchronize_event(rdpInput *input, UINT32 flags)
{
	freerdp_peer *client = input->context->peer;
	RdpPeerContext *peerCtx = (RdpPeerContext *)input->context;
1113
	struct rdp_output *output = peerCtx->rdpBackend->output;
David Fort's avatar
David Fort committed
1114 1115 1116 1117 1118 1119 1120 1121 1122 1123 1124 1125 1126
	pixman_box32_t box;
	pixman_region32_t damage;

	/* sends a full refresh */
	box.x1 = 0;
	box.y1 = 0;
	box.x2 = output->base.width;
	box.y2 = output->base.height;
	pixman_region32_init_with_extents(&damage, &box);

	rdp_peer_refresh_region(&damage, client);

	pixman_region32_fini(&damage);
1127
	FREERDP_CB_RETURN(TRUE);
David Fort's avatar
David Fort committed
1128 1129
}

1130

1131
static FREERDP_CB_RET_TYPE
David Fort's avatar
David Fort committed
1132 1133
xf_input_keyboard_event(rdpInput *input, UINT16 flags, UINT16 code)
{
1134
	uint32_t scan_code, vk_code, full_code;
David Fort's avatar
David Fort committed
1135 1136 1137
	enum wl_keyboard_key_state keyState;
	RdpPeerContext *peerContext = (RdpPeerContext *)input->context;
	int notify = 0;
1138
	struct timespec time;
David Fort's avatar
David Fort committed
1139

1140 1141 1142
	if (!(peerContext->item.flags & RDP_PEER_ACTIVATED))
		FREERDP_CB_RETURN(TRUE);

David Fort's avatar
David Fort committed
1143 1144 1145 1146 1147 1148 1149 1150
	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;
	}

1151
	if (notify) {
1152
		full_code = code;
1153
		if (flags & KBD_FLAGS_EXTENDED)
1154 1155 1156
			full_code |= KBD_FLAGS_EXTENDED;

		vk_code = GetVirtualKeyCodeFromVirtualScanCode(full_code, 4);
Dawid Gajownik's avatar
Dawid Gajownik committed
1157
		if (flags & KBD_FLAGS_EXTENDED)
1158
			vk_code |= KBDEXT;
1159

1160
		scan_code = GetKeycodeFromVirtualKeyCode(vk_code, KEYCODE_TYPE_EVDEV);
1161 1162 1163

		/*weston_log("code=%x ext=%d vk_code=%x scan_code=%x\n", code, (flags & KBD_FLAGS_EXTENDED) ? 1 : 0,
				vk_code, scan_code);*/
1164 1165
		timespec_from_msec(&time, weston_compositor_get_time());
		notify_key(peerContext->item.seat, &time,
1166
					scan_code - 8, keyState, STATE_UPDATE_AUTOMATIC);
1167
	}
1168 1169

	FREERDP_CB_RETURN(TRUE);
David Fort's avatar
David Fort committed
1170 1171
}

1172
static FREERDP_CB_RET_TYPE
David Fort's avatar
David Fort committed
1173 1174 1175
xf_input_unicode_keyboard_event(rdpInput *input, UINT16 flags, UINT16 code)
{
	weston_log("Client sent a unicode keyboard event (flags:0x%X code:0x%X)\n", flags, code);
1176
	FREERDP_CB_RETURN(TRUE);
David Fort's avatar
David Fort committed
1177 1178 1179
}


1180
static FREERDP_CB_RET_TYPE
1181
xf_suppress_output(rdpContext *context, BYTE allow, const RECTANGLE_16 *area)
Dawid Gajownik's avatar
Dawid Gajownik committed
1182
{
David Fort's avatar
David Fort committed
1183
	RdpPeerContext *peerContext = (RdpPeerContext *)context;
1184

1185
	if (allow)
David Fort's avatar
David Fort committed
1186 1187 1188
		peerContext->item.flags |= RDP_PEER_OUTPUT_ENABLED;
	else
		peerContext->item.flags &= (~RDP_PEER_OUTPUT_ENABLED);
1189 1190

	FREERDP_CB_RETURN(TRUE);
David Fort's avatar
David Fort committed
1191 1192 1193
}

static int
1194
rdp_peer_init(freerdp_peer *client, struct rdp_backend *b)
David Fort's avatar
David Fort committed
1195 1196 1197 1198 1199 1200 1201 1202 1203
{
	int rcount = 0;
	void *rfds[MAX_FREERDP_FDS];
	int i, fd;
	struct wl_event_loop *loop;
	rdpSettings	*settings;
	rdpInput *input;
	RdpPeerContext *peerCtx;

1204
	client->ContextSize = sizeof(RdpPeerContext);
David Fort's avatar
David Fort committed
1205 1206 1207 1208 1209
	client->ContextNew = (psPeerContextNew)rdp_peer_context_new;
	client->ContextFree = (psPeerContextFree)rdp_peer_context_free;
	freerdp_peer_context_new(client);

	peerCtx = (RdpPeerContext *) client->context;
1210
	peerCtx->rdpBackend = b;
David Fort's avatar
David Fort committed
1211 1212

	settings = client->settings;
1213
	/* configure security settings */
1214 1215 1216 1217 1218
	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);
David Fort's avatar
David Fort committed
1219 1220 1221 1222 1223
	} else {
		settings->TlsSecurity = FALSE;
	}
	settings->NlaSecurity = FALSE;

1224 1225 1226 1227
	if (!client->Initialize(client)) {
		weston_log("peer initialization failed\n");
		goto error_initialize;
	}
1228

1229 1230 1231 1232 1233 1234 1235 1236 1237
	settings->OsMajorType = OSMAJORTYPE_UNIX;
	settings->OsMinorType = OSMINORTYPE_PSEUDO_XSERVER;
	settings->ColorDepth = 32;
	settings->RefreshRect = TRUE;
	settings->RemoteFxCodec = TRUE;
	settings->NSCodec = TRUE;
	settings->FrameMarkerCommandEnabled = TRUE;
	settings->SurfaceFrameMarkerEnabled = TRUE;

David Fort's avatar
David Fort committed
1238 1239 1240 1241
	client->Capabilities = xf_peer_capabilities;
	client->PostConnect = xf_peer_post_connect;
	client->Activate = xf_peer_activate;

1242
	client->update->SuppressOutput = (pSuppressOutput)xf_suppress_output;
David Fort's avatar
David Fort committed
1243 1244 1245 1246 1247 1248 1249

	input = client->input;
	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;
1250

David Fort's avatar
David Fort committed
1251 1252
	if (!client->GetFileDescriptor(client, rfds, &rcount)) {
		weston_log("unable to retrieve client fds\n");
1253
		goto error_initialize;
David Fort's avatar
David Fort committed
1254 1255
	}

1256
	loop = wl_display_get_event_loop(b->compositor->wl_display);
Dawid Gajownik's avatar
Dawid Gajownik committed
1257
	for (i = 0; i < rcount; i++) {
David Fort's avatar
David Fort committed
1258 1259 1260 1261 1262
		fd = (int)(long)(rfds[i]);

		peerCtx->events[i] = wl_event_loop_add_fd(loop, fd, WL_EVENT_READABLE,
				rdp_client_activity, client);
	}
1263
	for ( ; i < MAX_FREERDP_FDS; i++)
David Fort's avatar
David Fort committed
1264 1265
		peerCtx->events[i] = 0;

1266
	wl_list_insert(&b->output->peers, &peerCtx->item.link);
David Fort's avatar
David Fort committed
1267
	return 0;
1268 1269 1270 1271

error_initialize:
	client->Close(client);
	return -1;
David Fort's avatar
David Fort committed
1272 1273 1274
}


1275
static FREERDP_CB_RET_TYPE
David Fort's avatar
David Fort committed
1276 1277
rdp_incoming_peer(freerdp_listener *instance, freerdp_peer *client)
{
1278 1279
	struct rdp_backend *b = (struct rdp_backend *)instance->param4;
	if (rdp_peer_init(client, b) < 0) {
1280
		weston_log("error when treating incoming peer\n");
1281 1282 1283 1284
		FREERDP_CB_RETURN(FALSE);
	}

	FREERDP_CB_RETURN(TRUE);
David Fort's avatar
David Fort committed
1285 1286
}

1287 1288 1289 1290
static const struct weston_rdp_output_api api = {
	rdp_output_set_size,
};

1291 1292
static struct rdp_backend *
rdp_backend_create(struct weston_compositor *compositor,
1293
		   struct weston_rdp_backend_config *config)
David Fort's avatar
David Fort committed
1294
{
1295
	struct rdp_backend *b;
David Fort's avatar
David Fort committed
1296
	char *fd_str;
1297
	char *fd_tail;
1298
	int fd, ret;
David Fort's avatar
David Fort committed
1299

1300 1301
	b = zalloc(sizeof *b);
	if (b == NULL)
David Fort's avatar
David Fort committed
1302 1303
		return NULL;

1304 1305 1306 1307 1308
	b->compositor = compositor;
	b->base.destroy = rdp_destroy;
	b->base.restore = rdp_restore;
	b->rdp_key = config->rdp_key ? strdup(config->rdp_key) : NULL;
	b->no_clients_resize = config->no_clients_resize;
David Fort's avatar
David Fort committed
1309

1310 1311
	compositor->backend = &b->base;

David Fort's avatar
David Fort committed
1312
	/* activate TLS only if certificate/key are available */
1313
	if (config->server_cert && config->server_key) {
David Fort's avatar
David Fort committed
1314
		weston_log("TLS support activated\n");
1315 1316 1317
		b->server_cert = strdup(config->server_cert);
		b->server_key = strdup(config->server_key);
		if (!b->server_cert || !b->server_key)
David Fort's avatar
David Fort committed
1318
			goto err_free_strings;