2013-04-01 21:43:58 +00:00
|
|
|
/*
|
|
|
|
* Copyright © 2013 Hardening <rdp.effort@gmail.com>
|
|
|
|
*
|
|
|
|
* Permission to use, copy, modify, distribute, and sell this software and
|
|
|
|
* its documentation for any purpose is hereby granted without fee, provided
|
|
|
|
* that the above copyright notice appear in all copies and that both that
|
|
|
|
* copyright notice and this permission notice appear in supporting
|
|
|
|
* documentation, and that the name of the copyright holders not be used in
|
|
|
|
* advertising or publicity pertaining to distribution of the software
|
|
|
|
* without specific, written prior permission. The copyright holders make
|
|
|
|
* no representations about the suitability of this software for any
|
|
|
|
* purpose. It is provided "as is" without express or implied warranty.
|
|
|
|
*
|
|
|
|
* THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS
|
|
|
|
* SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
|
|
|
|
* FITNESS, IN NO EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY
|
|
|
|
* SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER
|
|
|
|
* RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF
|
|
|
|
* CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
|
|
|
|
* CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
|
|
|
*/
|
|
|
|
|
2013-05-22 15:03:19 +00:00
|
|
|
#include "config.h"
|
2013-04-01 21:43:58 +00:00
|
|
|
|
|
|
|
#include <stdlib.h>
|
|
|
|
#include <string.h>
|
|
|
|
#include <errno.h>
|
|
|
|
#include <linux/input.h>
|
|
|
|
|
2014-01-10 10:33:06 +00:00
|
|
|
#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
|
|
|
|
#endif
|
|
|
|
|
2013-04-01 21:43:58 +00:00
|
|
|
#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>
|
2014-04-11 07:49:57 +00:00
|
|
|
#include <freerdp/locale/keyboard.h>
|
2013-04-06 21:39:26 +00:00
|
|
|
#include <winpr/input.h>
|
2013-04-01 21:43:58 +00:00
|
|
|
|
|
|
|
#include "compositor.h"
|
|
|
|
#include "pixman-renderer.h"
|
|
|
|
|
|
|
|
#define MAX_FREERDP_FDS 32
|
2013-06-03 20:55:47 +00:00
|
|
|
#define DEFAULT_AXIS_STEP_DISTANCE wl_fixed_from_int(10)
|
2014-03-20 21:34:30 +00:00
|
|
|
#define RDP_MODE_FREQ 60 * 1000
|
2013-04-01 21:43:58 +00:00
|
|
|
|
|
|
|
struct rdp_compositor_config {
|
|
|
|
int width;
|
|
|
|
int height;
|
|
|
|
char *bind_address;
|
|
|
|
int port;
|
|
|
|
char *rdp_key;
|
|
|
|
char *server_cert;
|
|
|
|
char *server_key;
|
|
|
|
int env_socket;
|
2014-04-03 00:54:00 +00:00
|
|
|
int no_clients_resize;
|
2013-04-01 21:43:58 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
struct rdp_output;
|
|
|
|
|
|
|
|
struct rdp_compositor {
|
|
|
|
struct weston_compositor base;
|
|
|
|
|
|
|
|
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;
|
2014-04-03 00:54:00 +00:00
|
|
|
int no_clients_resize;
|
2013-04-01 21:43:58 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
enum peer_item_flags {
|
|
|
|
RDP_PEER_ACTIVATED = (1 << 0),
|
|
|
|
RDP_PEER_OUTPUT_ENABLED = (1 << 1),
|
|
|
|
};
|
|
|
|
|
|
|
|
struct rdp_peers_item {
|
|
|
|
int flags;
|
|
|
|
freerdp_peer *peer;
|
|
|
|
struct weston_seat seat;
|
|
|
|
|
|
|
|
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;
|
|
|
|
|
2013-05-26 21:34:00 +00:00
|
|
|
struct rdp_compositor *rdpCompositor;
|
2013-04-01 21:43:58 +00:00
|
|
|
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;
|
|
|
|
|
|
|
|
static void
|
|
|
|
rdp_compositor_config_init(struct rdp_compositor_config *config) {
|
|
|
|
config->width = 640;
|
|
|
|
config->height = 480;
|
|
|
|
config->bind_address = NULL;
|
|
|
|
config->port = 3389;
|
|
|
|
config->rdp_key = NULL;
|
|
|
|
config->server_cert = NULL;
|
|
|
|
config->server_key = NULL;
|
|
|
|
config->env_socket = 0;
|
2014-04-03 00:54:00 +00:00
|
|
|
config->no_clients_resize = 0;
|
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;
|
|
|
|
rdpUpdate *update = peer->update;
|
|
|
|
SURFACE_BITS_COMMAND *cmd = &update->surface_bits_command;
|
|
|
|
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);
|
|
|
|
|
|
|
|
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)
|
|
|
|
);
|
|
|
|
|
2013-05-22 21:40:16 +00:00
|
|
|
cmd->bitmapDataLength = Stream_GetPosition(context->encode_stream);
|
|
|
|
cmd->bitmapData = Stream_Buffer(context->encode_stream);
|
2013-04-01 21:43:58 +00:00
|
|
|
|
|
|
|
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;
|
|
|
|
|
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);
|
|
|
|
|
|
|
|
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));
|
2013-05-22 21:40:16 +00:00
|
|
|
cmd->bitmapDataLength = Stream_GetPosition(context->encode_stream);
|
|
|
|
cmd->bitmapData = Stream_Buffer(context->encode_stream);
|
2013-04-01 21:43:58 +00:00
|
|
|
update->SurfaceBits(update->context, cmd);
|
|
|
|
}
|
|
|
|
|
2013-05-22 21:40:20 +00:00
|
|
|
static void
|
|
|
|
pixman_image_flipped_subrect(const pixman_box32_t *rect, pixman_image_t *img, BYTE *dest) {
|
|
|
|
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)
|
|
|
|
{
|
|
|
|
rdpUpdate *update = peer->update;
|
|
|
|
SURFACE_BITS_COMMAND *cmd = &update->surface_bits_command;
|
2013-05-22 21:40:20 +00:00
|
|
|
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);
|
2013-04-01 21:43:58 +00:00
|
|
|
|
|
|
|
cmd->bpp = 32;
|
|
|
|
cmd->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);*/
|
|
|
|
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);
|
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;
|
|
|
|
struct rdp_output *output = context->rdpCompositor->output;
|
|
|
|
rdpSettings *settings = peer->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);
|
|
|
|
}
|
|
|
|
|
2013-04-05 21:07:11 +00:00
|
|
|
static void
|
|
|
|
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);
|
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, &ts, PRESENTATION_FEEDBACK_INVALID);
|
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
|
2013-04-01 21:43:58 +00:00
|
|
|
rdp_output_repaint(struct weston_output *output_base, pixman_region32_t *damage)
|
|
|
|
{
|
|
|
|
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);
|
|
|
|
|
2014-03-20 21:34:30 +00:00
|
|
|
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);
|
|
|
|
}
|
2013-04-01 21:43:58 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
pixman_region32_subtract(&ec->primary_plane.damage,
|
|
|
|
&ec->primary_plane.damage, damage);
|
|
|
|
|
|
|
|
wl_event_source_timer_update(output->finish_frame_timer, 16);
|
2013-10-22 15:11:26 +00:00
|
|
|
return 0;
|
2013-04-01 21:43:58 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
rdp_output_destroy(struct weston_output *output_base)
|
|
|
|
{
|
|
|
|
struct rdp_output *output = (struct rdp_output *)output_base;
|
|
|
|
|
|
|
|
wl_event_source_remove(output->finish_frame_timer);
|
|
|
|
free(output);
|
|
|
|
}
|
|
|
|
|
|
|
|
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 *
|
|
|
|
rdp_insert_new_mode(struct weston_output *output, int width, int height, int rate) {
|
|
|
|
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;
|
|
|
|
}
|
2013-04-01 21:43:58 +00:00
|
|
|
|
|
|
|
static struct weston_mode *
|
2014-03-20 21:34:30 +00:00
|
|
|
ensure_matching_mode(struct weston_output *output, struct weston_mode *target) {
|
2013-04-01 21:43:58 +00:00
|
|
|
struct weston_mode *local;
|
|
|
|
|
|
|
|
wl_list_for_each(local, &output->mode_list, link) {
|
2014-03-20 21:34:30 +00:00
|
|
|
if ((local->width == target->width) && (local->height == target->height))
|
2013-04-01 21:43:58 +00:00
|
|
|
return local;
|
|
|
|
}
|
2014-03-20 21:34:30 +00:00
|
|
|
|
|
|
|
return rdp_insert_new_mode(output, target->width, target->height, RDP_MODE_FREQ);
|
2013-04-01 21:43:58 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
static int
|
|
|
|
rdp_switch_mode(struct weston_output *output, struct weston_mode *target_mode) {
|
|
|
|
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;
|
|
|
|
|
2014-03-20 21:34:30 +00:00
|
|
|
local_mode = ensure_matching_mode(output, target_mode);
|
|
|
|
if (!local_mode) {
|
2013-04-01 21:43:58 +00:00
|
|
|
weston_log("mode %dx%d not available\n", target_mode->width, target_mode->height);
|
|
|
|
return -ENOENT;
|
|
|
|
}
|
|
|
|
|
2014-03-20 21:34:30 +00:00
|
|
|
if (local_mode == output->current_mode)
|
2013-04-01 21:43:58 +00:00
|
|
|
return 0;
|
|
|
|
|
2013-09-18 21:56:36 +00:00
|
|
|
output->current_mode->flags &= ~WL_OUTPUT_MODE_CURRENT;
|
|
|
|
|
2013-09-18 21:56:35 +00:00
|
|
|
output->current_mode = local_mode;
|
2013-09-18 21:56:36 +00:00
|
|
|
output->current_mode->flags |= WL_OUTPUT_MODE_CURRENT;
|
2013-04-01 21:43:58 +00:00
|
|
|
|
|
|
|
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;
|
2014-04-03 00:54:00 +00:00
|
|
|
if (settings->DesktopWidth == (UINT32)target_mode->width &&
|
|
|
|
settings->DesktopHeight == (UINT32)target_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 */
|
|
|
|
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
|
2014-03-20 21:34:30 +00:00
|
|
|
rdp_compositor_create_output(struct rdp_compositor *c, int width, int height)
|
2013-04-01 21:43:58 +00:00
|
|
|
{
|
|
|
|
struct rdp_output *output;
|
|
|
|
struct wl_event_loop *loop;
|
2014-03-20 21:34:30 +00:00
|
|
|
struct weston_mode *currentMode;
|
|
|
|
struct weston_mode initMode;
|
2013-04-01 21:43:58 +00:00
|
|
|
|
2013-08-08 01:57:05 +00:00
|
|
|
output = zalloc(sizeof *output);
|
2013-04-01 21:43:58 +00:00
|
|
|
if (output == NULL)
|
|
|
|
return -1;
|
|
|
|
|
|
|
|
wl_list_init(&output->peers);
|
|
|
|
wl_list_init(&output->base.mode_list);
|
|
|
|
|
2014-03-20 21:34:30 +00:00
|
|
|
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)
|
2013-04-01 21:43:58 +00:00
|
|
|
goto out_free_output;
|
|
|
|
|
2013-09-18 21:56:36 +00:00
|
|
|
output->base.current_mode = output->base.native_mode = currentMode;
|
2013-04-01 21:43:58 +00:00
|
|
|
weston_output_init(&output->base, &c->base, 0, 0, width, height,
|
2013-05-23 01:53:09 +00:00
|
|
|
WL_OUTPUT_TRANSFORM_NORMAL, 1);
|
2013-04-01 21:43:58 +00:00
|
|
|
|
|
|
|
output->base.make = "weston";
|
|
|
|
output->base.model = "rdp";
|
|
|
|
output->shadow_surface = pixman_image_create_bits(PIXMAN_x8r8g8b8,
|
|
|
|
width, height,
|
|
|
|
NULL,
|
|
|
|
width * 4);
|
|
|
|
if (output->shadow_surface == NULL) {
|
|
|
|
weston_log("Failed to create surface for frame buffer.\n");
|
|
|
|
goto out_output;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (pixman_renderer_output_create(&output->base) < 0)
|
|
|
|
goto out_shadow_surface;
|
|
|
|
|
|
|
|
loop = wl_display_get_event_loop(c->base.wl_display);
|
|
|
|
output->finish_frame_timer = wl_event_loop_add_timer(loop, finish_frame_handler, output);
|
|
|
|
|
2013-04-05 21:07:11 +00:00
|
|
|
output->base.start_repaint_loop = rdp_output_start_repaint_loop;
|
2013-04-01 21:43:58 +00:00
|
|
|
output->base.repaint = rdp_output_repaint;
|
|
|
|
output->base.destroy = rdp_output_destroy;
|
|
|
|
output->base.assign_planes = NULL;
|
|
|
|
output->base.set_backlight = NULL;
|
|
|
|
output->base.set_dpms = NULL;
|
|
|
|
output->base.switch_mode = rdp_switch_mode;
|
|
|
|
c->output = output;
|
|
|
|
|
2015-05-06 18:41:57 +00:00
|
|
|
weston_compositor_add_output(&c->base, &output->base);
|
2013-04-01 21:43:58 +00:00
|
|
|
return 0;
|
|
|
|
|
|
|
|
out_shadow_surface:
|
|
|
|
pixman_image_unref(output->shadow_surface);
|
|
|
|
out_output:
|
|
|
|
weston_output_destroy(&output->base);
|
|
|
|
out_free_output:
|
|
|
|
free(output);
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
rdp_restore(struct weston_compositor *ec)
|
|
|
|
{
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
rdp_destroy(struct weston_compositor *ec)
|
|
|
|
{
|
|
|
|
weston_compositor_shutdown(ec);
|
|
|
|
|
|
|
|
free(ec);
|
|
|
|
}
|
|
|
|
|
|
|
|
static
|
|
|
|
int rdp_listener_activity(int fd, uint32_t mask, void *data) {
|
|
|
|
freerdp_listener* instance = (freerdp_listener *)data;
|
|
|
|
|
|
|
|
if (!(mask & WL_EVENT_READABLE))
|
|
|
|
return 0;
|
|
|
|
if (!instance->CheckFileDescriptor(instance))
|
|
|
|
{
|
|
|
|
weston_log("failed to check FreeRDP file descriptor\n");
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
static
|
|
|
|
int rdp_implant_listener(struct rdp_compositor *c, freerdp_listener* instance) {
|
|
|
|
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;
|
|
|
|
}
|
|
|
|
|
|
|
|
loop = wl_display_get_event_loop(c->base.wl_display);
|
|
|
|
for (i = 0; i < rcount; i++) {
|
|
|
|
fd = (int)(long)(rfds[i]);
|
|
|
|
c->listener_events[i] = wl_event_loop_add_fd(loop, fd, WL_EVENT_READABLE,
|
|
|
|
rdp_listener_activity, instance);
|
|
|
|
}
|
|
|
|
|
|
|
|
for( ; i < MAX_FREERDP_FDS; i++)
|
|
|
|
c->listener_events[i] = 0;
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
static void
|
|
|
|
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
|
|
|
|
2014-01-10 10:33:06 +00:00
|
|
|
#if FREERDP_VERSION_MAJOR == 1 && FREERDP_VERSION_MINOR == 1
|
2013-04-01 21:43:58 +00:00
|
|
|
context->rfx_context = rfx_context_new();
|
2014-01-10 10:33:06 +00:00
|
|
|
#else
|
|
|
|
context->rfx_context = rfx_context_new(TRUE);
|
|
|
|
#endif
|
2013-04-01 21:43:58 +00:00
|
|
|
context->rfx_context->mode = RLGR3;
|
|
|
|
context->rfx_context->width = client->settings->DesktopWidth;
|
|
|
|
context->rfx_context->height = client->settings->DesktopHeight;
|
|
|
|
rfx_context_set_pixel_format(context->rfx_context, RDP_PIXEL_FORMAT_B8G8R8A8);
|
|
|
|
|
|
|
|
context->nsc_context = nsc_context_new();
|
2013-05-22 21:40:18 +00:00
|
|
|
nsc_context_set_pixel_format(context->nsc_context, RDP_PIXEL_FORMAT_B8G8R8A8);
|
2013-04-01 21:43:58 +00:00
|
|
|
|
2013-05-22 21:40:16 +00:00
|
|
|
context->encode_stream = Stream_New(NULL, 65536);
|
2013-04-01 21:43:58 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
rdp_peer_context_free(freerdp_peer* client, RdpPeerContext* context)
|
|
|
|
{
|
|
|
|
int i;
|
2014-03-20 21:34:30 +00:00
|
|
|
if (!context)
|
2013-04-01 21:43:58 +00:00
|
|
|
return;
|
|
|
|
|
|
|
|
wl_list_remove(&context->item.link);
|
|
|
|
for(i = 0; i < MAX_FREERDP_FDS; 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]);
|
|
|
|
}
|
|
|
|
|
2014-03-20 21:34:30 +00:00
|
|
|
if (context->item.flags & RDP_PEER_ACTIVATED) {
|
2013-12-21 22:19:11 +00:00
|
|
|
weston_seat_release_keyboard(&context->item.seat);
|
|
|
|
weston_seat_release_pointer(&context->item.seat);
|
2013-04-01 21:43:58 +00:00
|
|
|
weston_seat_release(&context->item.seat);
|
2013-12-21 22:19:11 +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
|
|
|
|
rdp_client_activity(int fd, uint32_t mask, void *data) {
|
|
|
|
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 {
|
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 */
|
|
|
|
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_PORTUGUESE_BRAZILIAN_ABN0416, 0},
|
|
|
|
{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},
|
2013-04-01 21:43:58 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
/* taken from 2.2.7.1.6 Input Capability Set (TS_INPUT_CAPABILITYSET) */
|
|
|
|
static char *rdp_keyboard_types[] = {
|
2013-04-06 21:39:26 +00:00
|
|
|
"", /* 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 */
|
2013-04-01 21:43:58 +00:00
|
|
|
"pc102",/* 4: IBM enhanced (101- or 102-key) keyboard */
|
2013-04-06 21:39:26 +00:00
|
|
|
"", /* 5: Nokia 1050 and similar keyboards */
|
|
|
|
"", /* 6: Nokia 9140 and similar keyboards */
|
|
|
|
"" /* 7: Japanese keyboard */
|
2013-04-01 21:43:58 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
static BOOL
|
|
|
|
xf_peer_post_connect(freerdp_peer* client)
|
|
|
|
{
|
|
|
|
RdpPeerContext *peerCtx;
|
|
|
|
struct rdp_compositor *c;
|
|
|
|
struct rdp_output *output;
|
|
|
|
rdpSettings *settings;
|
2013-05-22 21:40:19 +00:00
|
|
|
rdpPointerUpdate *pointer;
|
2013-04-01 21:43:58 +00:00
|
|
|
struct xkb_context *xkbContext;
|
|
|
|
struct xkb_rule_names xkbRuleNames;
|
|
|
|
struct xkb_keymap *keymap;
|
|
|
|
int i;
|
2013-05-22 21:40:19 +00:00
|
|
|
pixman_box32_t box;
|
|
|
|
pixman_region32_t damage;
|
|
|
|
|
2013-04-01 21:43:58 +00:00
|
|
|
|
|
|
|
peerCtx = (RdpPeerContext *)client->context;
|
|
|
|
c = peerCtx->rdpCompositor;
|
|
|
|
output = c->output;
|
|
|
|
settings = client->settings;
|
|
|
|
|
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;
|
|
|
|
}
|
|
|
|
|
2013-09-18 21:56:36 +00:00
|
|
|
if (output->base.width != (int)settings->DesktopWidth ||
|
2013-04-01 21:43:58 +00:00
|
|
|
output->base.height != (int)settings->DesktopHeight)
|
|
|
|
{
|
2014-04-03 00:54:00 +00:00
|
|
|
if (c->no_clients_resize) {
|
|
|
|
/* 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;
|
|
|
|
}
|
2014-11-04 16:47:33 +00:00
|
|
|
weston_output_mode_set_native(&output->base, target_mode, 1);
|
2014-04-03 00:54:00 +00:00
|
|
|
output->base.width = new_mode.width;
|
|
|
|
output->base.height = new_mode.height;
|
2013-04-01 21:43:58 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
weston_log("kbd_layout:%x kbd_type:%x kbd_subType:%x kbd_functionKeys:%x\n",
|
|
|
|
settings->KeyboardLayout, settings->KeyboardType, settings->KeyboardSubType,
|
|
|
|
settings->KeyboardFunctionKey);
|
|
|
|
|
|
|
|
memset(&xkbRuleNames, 0, sizeof(xkbRuleNames));
|
2014-03-20 21:34:30 +00:00
|
|
|
if (settings->KeyboardType <= 7)
|
2013-04-01 21:43:58 +00:00
|
|
|
xkbRuleNames.model = rdp_keyboard_types[settings->KeyboardType];
|
2014-04-11 07:49:57 +00:00
|
|
|
for(i = 0; rdp_keyboards[i].rdpLayoutCode; i++) {
|
2014-03-20 21:34:30 +00:00
|
|
|
if (rdp_keyboards[i].rdpLayoutCode == settings->KeyboardLayout) {
|
2013-04-01 21:43:58 +00:00
|
|
|
xkbRuleNames.layout = rdp_keyboards[i].xkbLayout;
|
2014-04-11 07:49:57 +00:00
|
|
|
xkbRuleNames.variant = rdp_keyboards[i].xkbVariant;
|
2014-04-11 08:24:22 +00:00
|
|
|
weston_log("%s: matching layout=%s variant=%s\n", __FUNCTION__,
|
|
|
|
xkbRuleNames.layout, xkbRuleNames.variant);
|
2013-04-01 21:43:58 +00:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
keymap = NULL;
|
2014-03-20 21:34:30 +00:00
|
|
|
if (xkbRuleNames.layout) {
|
2013-04-01 21:43:58 +00:00
|
|
|
xkbContext = xkb_context_new(0);
|
2014-03-20 21:34:30 +00:00
|
|
|
if (!xkbContext) {
|
2013-04-01 21:43:58 +00:00
|
|
|
weston_log("unable to create a xkb_context\n");
|
|
|
|
return FALSE;
|
|
|
|
}
|
|
|
|
|
|
|
|
keymap = xkb_keymap_new_from_names(xkbContext, &xkbRuleNames, 0);
|
|
|
|
}
|
|
|
|
weston_seat_init_keyboard(&peerCtx->item.seat, keymap);
|
|
|
|
weston_seat_init_pointer(&peerCtx->item.seat);
|
|
|
|
|
|
|
|
peerCtx->item.flags |= RDP_PEER_ACTIVATED;
|
2013-05-22 21:40:19 +00:00
|
|
|
|
|
|
|
/* 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);
|
|
|
|
|
2013-04-01 21:43:58 +00:00
|
|
|
return TRUE;
|
|
|
|
}
|
|
|
|
|
|
|
|
static BOOL
|
|
|
|
xf_peer_activate(freerdp_peer *client)
|
|
|
|
{
|
2013-05-22 21:40:18 +00:00
|
|
|
RdpPeerContext *context = (RdpPeerContext *)client->context;
|
|
|
|
rfx_context_reset(context->rfx_context);
|
2013-04-01 21:43:58 +00:00
|
|
|
return TRUE;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
xf_mouseEvent(rdpInput *input, UINT16 flags, UINT16 x, UINT16 y) {
|
2013-06-03 20:55:47 +00:00
|
|
|
wl_fixed_t wl_x, wl_y, axis;
|
2013-04-01 21:43:58 +00:00
|
|
|
RdpPeerContext *peerContext = (RdpPeerContext *)input->context;
|
|
|
|
struct rdp_output *output;
|
|
|
|
uint32_t button = 0;
|
|
|
|
|
|
|
|
if (flags & PTR_FLAGS_MOVE) {
|
|
|
|
output = peerContext->rdpCompositor->output;
|
2014-03-20 21:34:30 +00:00
|
|
|
if (x < output->base.width && y < output->base.height) {
|
2013-04-01 21:43:58 +00:00
|
|
|
wl_x = wl_fixed_from_int((int)x);
|
|
|
|
wl_y = wl_fixed_from_int((int)y);
|
|
|
|
notify_motion_absolute(&peerContext->item.seat, weston_compositor_get_time(),
|
|
|
|
wl_x, wl_y);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
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;
|
|
|
|
|
2014-03-20 21:34:30 +00:00
|
|
|
if (button) {
|
2013-04-01 21:43:58 +00:00
|
|
|
notify_button(&peerContext->item.seat, weston_compositor_get_time(), button,
|
|
|
|
(flags & PTR_FLAGS_DOWN) ? WL_POINTER_BUTTON_STATE_PRESSED : WL_POINTER_BUTTON_STATE_RELEASED
|
|
|
|
);
|
|
|
|
}
|
2013-06-03 20:55:47 +00:00
|
|
|
|
|
|
|
if (flags & PTR_FLAGS_WHEEL) {
|
|
|
|
/* 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".
|
|
|
|
*
|
|
|
|
* http://blogs.msdn.com/b/oldnewthing/archive/2013/01/23/10387366.aspx explains the 120 value
|
|
|
|
*/
|
|
|
|
axis = (DEFAULT_AXIS_STEP_DISTANCE * (flags & 0xff)) / 120;
|
|
|
|
if (flags & PTR_FLAGS_WHEEL_NEGATIVE)
|
|
|
|
axis = -axis;
|
|
|
|
|
|
|
|
notify_axis(&peerContext->item.seat, weston_compositor_get_time(),
|
|
|
|
WL_POINTER_AXIS_VERTICAL_SCROLL,
|
|
|
|
axis);
|
|
|
|
}
|
2013-04-01 21:43:58 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
xf_extendedMouseEvent(rdpInput *input, UINT16 flags, UINT16 x, UINT16 y) {
|
|
|
|
wl_fixed_t wl_x, wl_y;
|
|
|
|
RdpPeerContext *peerContext = (RdpPeerContext *)input->context;
|
|
|
|
struct rdp_output *output;
|
|
|
|
|
|
|
|
output = peerContext->rdpCompositor->output;
|
2014-03-20 21:34:30 +00:00
|
|
|
if (x < output->base.width && y < output->base.height) {
|
2013-04-01 21:43:58 +00:00
|
|
|
wl_x = wl_fixed_from_int((int)x);
|
|
|
|
wl_y = wl_fixed_from_int((int)y);
|
|
|
|
notify_motion_absolute(&peerContext->item.seat, weston_compositor_get_time(),
|
|
|
|
wl_x, wl_y);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
static void
|
|
|
|
xf_input_synchronize_event(rdpInput *input, UINT32 flags)
|
|
|
|
{
|
|
|
|
freerdp_peer *client = input->context->peer;
|
|
|
|
RdpPeerContext *peerCtx = (RdpPeerContext *)input->context;
|
|
|
|
struct rdp_output *output = peerCtx->rdpCompositor->output;
|
|
|
|
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);
|
|
|
|
}
|
|
|
|
|
2013-04-06 21:39:26 +00:00
|
|
|
|
2013-04-01 21:43:58 +00:00
|
|
|
static void
|
|
|
|
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;
|
|
|
|
RdpPeerContext *peerContext = (RdpPeerContext *)input->context;
|
|
|
|
int notify = 0;
|
|
|
|
|
|
|
|
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;
|
|
|
|
|
|
|
|
vk_code = GetVirtualKeyCodeFromVirtualScanCode(full_code, 4);
|
2014-04-11 08:24:22 +00:00
|
|
|
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);*/
|
2013-04-01 21:43:58 +00:00
|
|
|
notify_key(&peerContext->item.seat, weston_compositor_get_time(),
|
2014-04-11 08:24:22 +00:00
|
|
|
scan_code - 8, keyState, STATE_UPDATE_AUTOMATIC);
|
2013-04-06 21:39:26 +00:00
|
|
|
}
|
2013-04-01 21:43:58 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
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);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
static void
|
|
|
|
xf_suppress_output(rdpContext *context, BYTE allow, RECTANGLE_16 *area) {
|
|
|
|
RdpPeerContext *peerContext = (RdpPeerContext *)context;
|
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);
|
|
|
|
}
|
|
|
|
|
|
|
|
static int
|
|
|
|
rdp_peer_init(freerdp_peer *client, struct rdp_compositor *c)
|
|
|
|
{
|
|
|
|
int rcount = 0;
|
|
|
|
void *rfds[MAX_FREERDP_FDS];
|
|
|
|
int i, fd;
|
|
|
|
struct wl_event_loop *loop;
|
|
|
|
rdpSettings *settings;
|
|
|
|
rdpInput *input;
|
|
|
|
RdpPeerContext *peerCtx;
|
2013-05-31 17:09:50 +00:00
|
|
|
char seat_name[32];
|
2013-04-01 21:43:58 +00:00
|
|
|
|
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;
|
|
|
|
peerCtx->rdpCompositor = c;
|
|
|
|
|
|
|
|
settings = client->settings;
|
|
|
|
settings->RdpKeyFile = c->rdp_key;
|
2014-03-20 21:34:30 +00:00
|
|
|
if (c->tls_enabled) {
|
2013-04-01 21:43:58 +00:00
|
|
|
settings->CertificateFile = c->server_cert;
|
|
|
|
settings->PrivateKeyFile = c->server_key;
|
|
|
|
} else {
|
|
|
|
settings->TlsSecurity = FALSE;
|
|
|
|
}
|
|
|
|
|
|
|
|
settings->NlaSecurity = FALSE;
|
|
|
|
|
|
|
|
client->Capabilities = xf_peer_capabilities;
|
|
|
|
client->PostConnect = xf_peer_post_connect;
|
|
|
|
client->Activate = xf_peer_activate;
|
|
|
|
|
|
|
|
client->update->SuppressOutput = xf_suppress_output;
|
|
|
|
|
|
|
|
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;
|
2013-05-31 17:09:50 +00:00
|
|
|
|
|
|
|
if (snprintf(seat_name, 32, "rdp:%d:%s", client->sockfd, client->hostname) >= 32)
|
|
|
|
seat_name[31] = '\0';
|
|
|
|
|
|
|
|
weston_seat_init(&peerCtx->item.seat, &c->base, seat_name);
|
2013-04-01 21:43:58 +00:00
|
|
|
|
|
|
|
client->Initialize(client);
|
|
|
|
|
|
|
|
if (!client->GetFileDescriptor(client, rfds, &rcount)) {
|
|
|
|
weston_log("unable to retrieve client fds\n");
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
loop = wl_display_get_event_loop(c->base.wl_display);
|
|
|
|
for(i = 0; i < rcount; i++) {
|
|
|
|
fd = (int)(long)(rfds[i]);
|
|
|
|
|
|
|
|
peerCtx->events[i] = wl_event_loop_add_fd(loop, fd, WL_EVENT_READABLE,
|
|
|
|
rdp_client_activity, client);
|
|
|
|
}
|
2013-05-26 21:34:00 +00:00
|
|
|
for ( ; i < MAX_FREERDP_FDS; i++)
|
2013-04-01 21:43:58 +00:00
|
|
|
peerCtx->events[i] = 0;
|
|
|
|
|
|
|
|
wl_list_insert(&c->output->peers, &peerCtx->item.link);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
static void
|
|
|
|
rdp_incoming_peer(freerdp_listener *instance, freerdp_peer *client)
|
|
|
|
{
|
|
|
|
struct rdp_compositor *c = (struct rdp_compositor *)instance->param4;
|
|
|
|
if (rdp_peer_init(client, c) < 0)
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
static struct weston_compositor *
|
|
|
|
rdp_compositor_create(struct wl_display *display,
|
|
|
|
struct rdp_compositor_config *config,
|
2013-05-27 21:13:45 +00:00
|
|
|
int *argc, char *argv[], struct weston_config *wconfig)
|
2013-04-01 21:43:58 +00:00
|
|
|
{
|
|
|
|
struct rdp_compositor *c;
|
|
|
|
char *fd_str;
|
|
|
|
int fd;
|
|
|
|
|
2013-08-08 01:57:05 +00:00
|
|
|
c = zalloc(sizeof *c);
|
2013-04-01 21:43:58 +00:00
|
|
|
if (c == NULL)
|
|
|
|
return NULL;
|
|
|
|
|
2013-05-27 21:13:45 +00:00
|
|
|
if (weston_compositor_init(&c->base, display, argc, argv, wconfig) < 0)
|
2013-04-01 21:43:58 +00:00
|
|
|
goto err_free;
|
|
|
|
|
|
|
|
c->base.destroy = rdp_destroy;
|
|
|
|
c->base.restore = rdp_restore;
|
|
|
|
c->rdp_key = config->rdp_key ? strdup(config->rdp_key) : NULL;
|
2014-04-03 00:54:00 +00:00
|
|
|
c->no_clients_resize = config->no_clients_resize;
|
2013-04-01 21:43:58 +00:00
|
|
|
|
|
|
|
/* activate TLS only if certificate/key are available */
|
2014-03-20 21:34:30 +00:00
|
|
|
if (config->server_cert && config->server_key) {
|
2013-04-01 21:43:58 +00:00
|
|
|
weston_log("TLS support activated\n");
|
|
|
|
c->server_cert = strdup(config->server_cert);
|
|
|
|
c->server_key = strdup(config->server_key);
|
2014-03-20 21:34:30 +00:00
|
|
|
if (!c->server_cert || !c->server_key)
|
2013-04-01 21:43:58 +00:00
|
|
|
goto err_free_strings;
|
|
|
|
c->tls_enabled = 1;
|
|
|
|
}
|
|
|
|
|
2014-09-24 02:08:45 +00:00
|
|
|
if (weston_compositor_set_presentation_clock_software(&c->base) < 0)
|
|
|
|
goto err_compositor;
|
|
|
|
|
2013-04-01 21:43:58 +00:00
|
|
|
if (pixman_renderer_init(&c->base) < 0)
|
|
|
|
goto err_compositor;
|
|
|
|
|
2014-03-20 21:34:30 +00:00
|
|
|
if (rdp_compositor_create_output(c, config->width, config->height) < 0)
|
2013-04-01 21:43:58 +00:00
|
|
|
goto err_compositor;
|
|
|
|
|
2014-04-03 00:53:46 +00:00
|
|
|
c->base.capabilities |= WESTON_CAP_ARBITRARY_MODES;
|
|
|
|
|
|
|
|
if(!config->env_socket) {
|
2013-04-01 21:43:58 +00:00
|
|
|
c->listener = freerdp_listener_new();
|
|
|
|
c->listener->PeerAccepted = rdp_incoming_peer;
|
|
|
|
c->listener->param4 = c;
|
2014-03-20 21:34:30 +00:00
|
|
|
if (!c->listener->Open(c->listener, config->bind_address, config->port)) {
|
2013-04-01 21:43:58 +00:00
|
|
|
weston_log("unable to bind rdp socket\n");
|
|
|
|
goto err_listener;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (rdp_implant_listener(c, c->listener) < 0)
|
|
|
|
goto err_compositor;
|
|
|
|
} else {
|
|
|
|
/* get the socket from RDP_FD var */
|
|
|
|
fd_str = getenv("RDP_FD");
|
2014-03-20 21:34:30 +00:00
|
|
|
if (!fd_str) {
|
2013-04-01 21:43:58 +00:00
|
|
|
weston_log("RDP_FD env variable not set");
|
|
|
|
goto err_output;
|
|
|
|
}
|
|
|
|
|
|
|
|
fd = strtoul(fd_str, NULL, 10);
|
2014-03-20 21:34:30 +00:00
|
|
|
if (rdp_peer_init(freerdp_peer_new(fd), c))
|
2013-04-01 21:43:58 +00:00
|
|
|
goto err_output;
|
|
|
|
}
|
|
|
|
|
|
|
|
return &c->base;
|
|
|
|
|
|
|
|
err_listener:
|
|
|
|
freerdp_listener_free(c->listener);
|
|
|
|
err_output:
|
|
|
|
weston_output_destroy(&c->output->base);
|
|
|
|
err_compositor:
|
|
|
|
weston_compositor_shutdown(&c->base);
|
|
|
|
err_free_strings:
|
2014-03-20 21:34:30 +00:00
|
|
|
if (c->rdp_key)
|
2013-04-01 21:43:58 +00:00
|
|
|
free(c->rdp_key);
|
2014-03-20 21:34:30 +00:00
|
|
|
if (c->server_cert)
|
2013-04-01 21:43:58 +00:00
|
|
|
free(c->server_cert);
|
2014-03-20 21:34:30 +00:00
|
|
|
if (c->server_key)
|
2013-04-01 21:43:58 +00:00
|
|
|
free(c->server_key);
|
|
|
|
err_free:
|
|
|
|
free(c);
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
WL_EXPORT struct weston_compositor *
|
|
|
|
backend_init(struct wl_display *display, int *argc, char *argv[],
|
2013-05-27 21:13:45 +00:00
|
|
|
struct weston_config *wconfig)
|
2013-04-01 21:43:58 +00:00
|
|
|
{
|
|
|
|
struct rdp_compositor_config config;
|
|
|
|
rdp_compositor_config_init(&config);
|
|
|
|
int major, minor, revision;
|
|
|
|
|
|
|
|
freerdp_get_version(&major, &minor, &revision);
|
|
|
|
weston_log("using FreeRDP version %d.%d.%d\n", major, minor, revision);
|
|
|
|
|
|
|
|
const struct weston_option rdp_options[] = {
|
|
|
|
{ WESTON_OPTION_BOOLEAN, "env-socket", 0, &config.env_socket },
|
|
|
|
{ WESTON_OPTION_INTEGER, "width", 0, &config.width },
|
|
|
|
{ WESTON_OPTION_INTEGER, "height", 0, &config.height },
|
|
|
|
{ WESTON_OPTION_STRING, "address", 0, &config.bind_address },
|
|
|
|
{ WESTON_OPTION_INTEGER, "port", 0, &config.port },
|
2014-04-03 00:54:00 +00:00
|
|
|
{ WESTON_OPTION_BOOLEAN, "no-clients-resize", 0, &config.no_clients_resize },
|
2013-04-01 21:43:58 +00:00
|
|
|
{ WESTON_OPTION_STRING, "rdp4-key", 0, &config.rdp_key },
|
|
|
|
{ WESTON_OPTION_STRING, "rdp-tls-cert", 0, &config.server_cert },
|
|
|
|
{ WESTON_OPTION_STRING, "rdp-tls-key", 0, &config.server_key }
|
|
|
|
};
|
|
|
|
|
|
|
|
parse_options(rdp_options, ARRAY_LENGTH(rdp_options), argc, argv);
|
2013-05-27 21:13:45 +00:00
|
|
|
return rdp_compositor_create(display, &config, argc, argv, wconfig);
|
2013-04-01 21:43:58 +00:00
|
|
|
}
|