Merge changes from patch branch back to main.
This commit is contained in:
commit
fc5073fb69
@ -62,6 +62,7 @@ static void* guac_display_render_loop(void* data) {
|
||||
|
||||
guac_display_render_thread* render_thread = (guac_display_render_thread*) data;
|
||||
guac_display* display = render_thread->display;
|
||||
guac_client* client = display->client;
|
||||
|
||||
for (;;) {
|
||||
|
||||
@ -84,7 +85,6 @@ static void* guac_display_render_loop(void* data) {
|
||||
/* Lacking explicit frame boundaries, handle the change in frame state,
|
||||
* continuing to accumulate frame modifications while still within
|
||||
* heuristically determined frame boundaries */
|
||||
int allowed_wait = 0;
|
||||
guac_timestamp frame_start = guac_timestamp_current();
|
||||
do {
|
||||
|
||||
@ -97,6 +97,49 @@ static void* guac_display_render_loop(void* data) {
|
||||
break;
|
||||
}
|
||||
|
||||
/* Copy cursor state for later flushing with final frame,
|
||||
* regardless of whether it's changed (there's really no need to
|
||||
* compare here - that will be done by the actual guac_display
|
||||
* frame flush) */
|
||||
cursor_state = render_thread->cursor_state;
|
||||
|
||||
/* Frame is no longer modified - prepare for possible future wait
|
||||
* for further changes */
|
||||
guac_flag_clear(&render_thread->state, GUAC_DISPLAY_RENDER_THREAD_STATE_FRAME_MODIFIED);
|
||||
guac_flag_unlock(&render_thread->state);
|
||||
|
||||
/* Use the amount of time that the client has been waiting
|
||||
* for a frame vs. the amount of time that it took the
|
||||
* client to process the most recently acknowledged frame
|
||||
* to calculate the amount of additional delay required to
|
||||
* allow the client to catch up. This value is used later,
|
||||
* after everything else related to the frame has been
|
||||
* finalized. */
|
||||
int time_since_last_frame = guac_timestamp_current() - client->last_sent_timestamp;
|
||||
int processing_lag = guac_client_get_processing_lag(client);
|
||||
int required_wait = processing_lag - time_since_last_frame;
|
||||
|
||||
/* Do not exceed a reasonable maximum framerate without an
|
||||
* explicit frame boundary terminating the frame early */
|
||||
int minimum_wait = GUAC_DISPLAY_RENDER_THREAD_MIN_FRAME_DURATION - frame_duration;
|
||||
if (minimum_wait > required_wait)
|
||||
required_wait = minimum_wait;
|
||||
|
||||
/* Ensure we don't wait without bound when compensating for
|
||||
* client-side processing delays */
|
||||
else if (required_wait > GUAC_DISPLAY_MAX_LAG_COMPENSATION)
|
||||
required_wait = GUAC_DISPLAY_MAX_LAG_COMPENSATION;
|
||||
|
||||
/* Wait for client to catch up, if necessary. Note that we don't do
|
||||
* this via guac_flag_timedwait_and_lock() to avoid causing
|
||||
* contention around the render_thread state lock. */
|
||||
if (required_wait > 0) {
|
||||
guac_client_log(client, GUAC_LOG_TRACE,
|
||||
"Waiting %ims to compensate for client-side "
|
||||
"processing delays.\n", required_wait);
|
||||
guac_timestamp_msleep(required_wait);
|
||||
}
|
||||
|
||||
/* Use explicit frame boundaries whenever available */
|
||||
if (render_thread->state.value & GUAC_DISPLAY_RENDER_THREAD_STATE_FRAME_READY) {
|
||||
|
||||
@ -111,27 +154,12 @@ static void* guac_display_render_loop(void* data) {
|
||||
|
||||
}
|
||||
|
||||
/* Copy cursor state for later flushing with final frame,
|
||||
* regardless of whether it's changed (there's really no need to
|
||||
* compare here - that will be done by the actual guac_display
|
||||
* frame flush) */
|
||||
cursor_state = render_thread->cursor_state;
|
||||
|
||||
/* Do not exceed a reasonable maximum framerate without an
|
||||
* explicit frame boundary terminating the frame early */
|
||||
allowed_wait = GUAC_DISPLAY_RENDER_THREAD_MIN_FRAME_DURATION - frame_duration;
|
||||
if (allowed_wait < 0)
|
||||
allowed_wait = 0;
|
||||
|
||||
/* Wait for further modifications or other changes to frame state */
|
||||
|
||||
guac_flag_clear(&render_thread->state, GUAC_DISPLAY_RENDER_THREAD_STATE_FRAME_MODIFIED);
|
||||
guac_flag_unlock(&render_thread->state);
|
||||
|
||||
} while (guac_flag_timedwait_and_lock(&render_thread->state,
|
||||
GUAC_DISPLAY_RENDER_THREAD_STATE_STOPPING
|
||||
| GUAC_DISPLAY_RENDER_THREAD_STATE_FRAME_READY
|
||||
| GUAC_DISPLAY_RENDER_THREAD_STATE_FRAME_MODIFIED, allowed_wait));
|
||||
| GUAC_DISPLAY_RENDER_THREAD_STATE_FRAME_MODIFIED, 0));
|
||||
|
||||
/* Pass on cursor state for consumption by guac_display frame flush */
|
||||
guac_rwlock_acquire_write_lock(&display->pending_frame.lock);
|
||||
|
||||
@ -401,17 +401,6 @@ void* guac_display_worker_thread(void* data) {
|
||||
cursor->last_frame.height);
|
||||
}
|
||||
|
||||
/* Use the amount of time that the client has been waiting
|
||||
* for a frame vs. the amount of time that it took the
|
||||
* client to process the most recently acknowledged frame
|
||||
* to calculate the amount of additional delay required to
|
||||
* allow the client to catch up. This value is used later,
|
||||
* after everything else related to the frame has been
|
||||
* finalized. */
|
||||
int time_since_last_frame = guac_timestamp_current() - client->last_sent_timestamp;
|
||||
int processing_lag = guac_client_get_processing_lag(client);
|
||||
int required_wait = processing_lag - time_since_last_frame;
|
||||
|
||||
/* Allow connected clients to move forward with rendering */
|
||||
guac_client_end_multiple_frames(client, display->last_frame.frames);
|
||||
|
||||
@ -457,31 +446,6 @@ void* guac_display_worker_thread(void* data) {
|
||||
guac_flag_clear(&display->render_state, GUAC_DISPLAY_RENDER_STATE_FRAME_IN_PROGRESS);
|
||||
guac_flag_unlock(&display->render_state);
|
||||
|
||||
/* Exclude local, server-side frame processing latency from
|
||||
* waiting period */
|
||||
int latency = (int) (guac_timestamp_current() - display->last_frame.timestamp);
|
||||
if (latency >= 0) {
|
||||
guac_client_log(display->client, GUAC_LOG_TRACE,
|
||||
"Rendering latency: %ims (%i:1 frame)\n",
|
||||
latency, display->last_frame.frames);
|
||||
required_wait -= latency;
|
||||
}
|
||||
|
||||
/* Ensure we don't wait without bound when compensating for
|
||||
* client-side processing delays */
|
||||
if (required_wait > GUAC_DISPLAY_MAX_LAG_COMPENSATION)
|
||||
required_wait = GUAC_DISPLAY_MAX_LAG_COMPENSATION;
|
||||
|
||||
/* Allow connected clients to catch up if they're taking
|
||||
* longer to process frames than the server is taking to
|
||||
* generate them */
|
||||
if (required_wait > 0) {
|
||||
guac_client_log(display->client, GUAC_LOG_TRACE,
|
||||
"Waiting %ims to compensate for client-side "
|
||||
"processing delays.\n", required_wait);
|
||||
guac_timestamp_msleep(required_wait);
|
||||
}
|
||||
|
||||
has_outstanding_frames = display->frame_deferred;
|
||||
|
||||
}
|
||||
|
||||
@ -67,6 +67,7 @@ libguac_client_rdp_la_SOURCES = \
|
||||
fs.c \
|
||||
gdi.c \
|
||||
input.c \
|
||||
input-queue.c \
|
||||
keyboard.c \
|
||||
keymap.c \
|
||||
log.c \
|
||||
|
||||
@ -205,6 +205,13 @@ int guac_client_init(guac_client* client, int argc, char** argv) {
|
||||
guac_rdp_client* rdp_client = guac_mem_zalloc(sizeof(guac_rdp_client));
|
||||
client->data = rdp_client;
|
||||
|
||||
/* Create queue for input events (to avoid RDP I/O blocking processing of
|
||||
* further Guacamole instructions) and associated signalling handle */
|
||||
guac_fifo_init(&rdp_client->input_events, &rdp_client->input_events_items,
|
||||
GUAC_RDP_INPUT_EVENT_QUEUE_SIZE, sizeof(guac_rdp_input_event));
|
||||
|
||||
rdp_client->input_event_queued = CreateEvent(NULL, TRUE, FALSE, NULL);
|
||||
|
||||
/* Init display update module */
|
||||
rdp_client->disp = guac_rdp_disp_alloc(client);
|
||||
|
||||
@ -252,6 +259,10 @@ int guac_rdp_client_free_handler(guac_client* client) {
|
||||
/* Wait for client thread */
|
||||
pthread_join(rdp_client->client_thread, NULL);
|
||||
|
||||
/* Clean up event queue and associated signalling handle */
|
||||
guac_fifo_destroy(&rdp_client->input_events);
|
||||
CloseHandle(rdp_client->input_event_queued);
|
||||
|
||||
/* Free parsed settings */
|
||||
if (rdp_client->settings != NULL)
|
||||
guac_rdp_settings_free(rdp_client->settings);
|
||||
|
||||
@ -134,10 +134,14 @@ BOOL guac_rdp_gdi_end_paint(rdpContext* context) {
|
||||
guac_rect_constrain(&dst_rect, ¤t_context->bounds);
|
||||
guac_rect_extend(¤t_context->dirty, &dst_rect);
|
||||
|
||||
guac_display_render_thread_notify_modified(rdp_client->render_thread);
|
||||
rdp_client->gdi_modified = 1;
|
||||
|
||||
paint_complete:
|
||||
|
||||
/* Clear GDI state for future draws */
|
||||
gdi->primary->hdc->hwnd->invalid->null = TRUE;
|
||||
gdi->primary->hdc->hwnd->ninvalid = 0;
|
||||
|
||||
/* There will be no further drawing operations */
|
||||
rdp_client->current_context = NULL;
|
||||
guac_display_layer_close_raw(default_layer, current_context);
|
||||
|
||||
282
src/protocols/rdp/input-queue.c
Normal file
282
src/protocols/rdp/input-queue.c
Normal file
@ -0,0 +1,282 @@
|
||||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one
|
||||
* or more contributor license agreements. See the NOTICE file
|
||||
* distributed with this work for additional information
|
||||
* regarding copyright ownership. The ASF licenses this file
|
||||
* to you under the Apache License, Version 2.0 (the
|
||||
* "License"); you may not use this file except in compliance
|
||||
* with the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing,
|
||||
* software distributed under the License is distributed on an
|
||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
* KIND, either express or implied. See the License for the
|
||||
* specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
|
||||
#include "channels/disp.h"
|
||||
#include "channels/rdpei.h"
|
||||
#include "input.h"
|
||||
#include "guacamole/display.h"
|
||||
#include "keyboard.h"
|
||||
#include "rdp.h"
|
||||
#include "settings.h"
|
||||
|
||||
#include <freerdp/freerdp.h>
|
||||
#include <freerdp/input.h>
|
||||
#include <guacamole/assert.h>
|
||||
#include <guacamole/client.h>
|
||||
#include <guacamole/display.h>
|
||||
#include <guacamole/recording.h>
|
||||
#include <guacamole/rwlock.h>
|
||||
#include <guacamole/user.h>
|
||||
|
||||
#include <stdlib.h>
|
||||
|
||||
/**
|
||||
* Processes a single mouse event, updating client state and sending any
|
||||
* associated RDP PDUs via the provided RDP client instance.
|
||||
*
|
||||
* @param rdp_client
|
||||
* The RDP client instance that should be updated and used to send any PDUs
|
||||
* associated with the event.
|
||||
*
|
||||
* @param event
|
||||
* The mouse event to process.
|
||||
*/
|
||||
static void guac_rdp_handle_mouse_event(guac_rdp_client* rdp_client,
|
||||
const guac_rdp_input_event* event) {
|
||||
|
||||
/* This function exclusively processes mouse events, and it's on the caller
|
||||
* to ensure only mouse events are provided */
|
||||
GUAC_ASSERT(event->type == GUAC_RDP_INPUT_EVENT_MOUSE);
|
||||
|
||||
guac_user* user = event->user;
|
||||
int x = event->details.mouse.x;
|
||||
int y = event->details.mouse.y;
|
||||
int mask = event->details.mouse.mask;
|
||||
|
||||
guac_rwlock_acquire_read_lock(&(rdp_client->lock));
|
||||
|
||||
/* Skip if not yet connected */
|
||||
freerdp* rdp_inst = rdp_client->rdp_inst;
|
||||
if (rdp_inst == NULL)
|
||||
goto complete;
|
||||
|
||||
/* Store current mouse location/state */
|
||||
guac_display_render_thread_notify_user_moved_mouse(rdp_client->render_thread, user, x, y, mask);
|
||||
|
||||
/* Report mouse position within recording */
|
||||
if (rdp_client->recording != NULL)
|
||||
guac_recording_report_mouse(rdp_client->recording, x, y, mask);
|
||||
|
||||
/* If button mask unchanged, just send move event */
|
||||
if (mask == rdp_client->mouse_button_mask) {
|
||||
pthread_mutex_lock(&(rdp_client->message_lock));
|
||||
GUAC_RDP_CONTEXT(rdp_inst)->input->MouseEvent(
|
||||
GUAC_RDP_CONTEXT(rdp_inst)->input, PTR_FLAGS_MOVE, x, y);
|
||||
pthread_mutex_unlock(&(rdp_client->message_lock));
|
||||
}
|
||||
|
||||
/* Otherwise, send events describing button change */
|
||||
else {
|
||||
|
||||
/* Mouse buttons which have JUST become released */
|
||||
int released_mask = rdp_client->mouse_button_mask & ~mask;
|
||||
|
||||
/* Mouse buttons which have JUST become pressed */
|
||||
int pressed_mask = ~rdp_client->mouse_button_mask & mask;
|
||||
|
||||
/* Release event */
|
||||
if (released_mask & 0x07) {
|
||||
|
||||
/* Calculate flags */
|
||||
int flags = 0;
|
||||
if (released_mask & 0x01) flags |= PTR_FLAGS_BUTTON1;
|
||||
if (released_mask & 0x02) flags |= PTR_FLAGS_BUTTON3;
|
||||
if (released_mask & 0x04) flags |= PTR_FLAGS_BUTTON2;
|
||||
|
||||
pthread_mutex_lock(&(rdp_client->message_lock));
|
||||
GUAC_RDP_CONTEXT(rdp_inst)->input->MouseEvent(
|
||||
GUAC_RDP_CONTEXT(rdp_inst)->input, flags, x, y);
|
||||
pthread_mutex_unlock(&(rdp_client->message_lock));
|
||||
|
||||
}
|
||||
|
||||
/* Press event */
|
||||
if (pressed_mask & 0x07) {
|
||||
|
||||
/* Calculate flags */
|
||||
int flags = PTR_FLAGS_DOWN;
|
||||
if (pressed_mask & 0x01) flags |= PTR_FLAGS_BUTTON1;
|
||||
if (pressed_mask & 0x02) flags |= PTR_FLAGS_BUTTON3;
|
||||
if (pressed_mask & 0x04) flags |= PTR_FLAGS_BUTTON2;
|
||||
if (pressed_mask & 0x08) flags |= PTR_FLAGS_WHEEL | 0x78;
|
||||
if (pressed_mask & 0x10) flags |= PTR_FLAGS_WHEEL | PTR_FLAGS_WHEEL_NEGATIVE | 0x88;
|
||||
|
||||
/* Send event */
|
||||
pthread_mutex_lock(&(rdp_client->message_lock));
|
||||
GUAC_RDP_CONTEXT(rdp_inst)->input->MouseEvent(
|
||||
GUAC_RDP_CONTEXT(rdp_inst)->input, flags, x, y);
|
||||
pthread_mutex_unlock(&(rdp_client->message_lock));
|
||||
|
||||
}
|
||||
|
||||
/* Scroll event */
|
||||
if (pressed_mask & 0x18) {
|
||||
|
||||
/* Down */
|
||||
if (pressed_mask & 0x08) {
|
||||
pthread_mutex_lock(&(rdp_client->message_lock));
|
||||
GUAC_RDP_CONTEXT(rdp_inst)->input->MouseEvent(
|
||||
GUAC_RDP_CONTEXT(rdp_inst)->input, PTR_FLAGS_WHEEL | 0x78, x, y);
|
||||
pthread_mutex_unlock(&(rdp_client->message_lock));
|
||||
}
|
||||
|
||||
/* Up */
|
||||
if (pressed_mask & 0x10) {
|
||||
pthread_mutex_lock(&(rdp_client->message_lock));
|
||||
GUAC_RDP_CONTEXT(rdp_inst)->input->MouseEvent(
|
||||
GUAC_RDP_CONTEXT(rdp_inst)->input, PTR_FLAGS_WHEEL | PTR_FLAGS_WHEEL_NEGATIVE | 0x88, x, y);
|
||||
pthread_mutex_unlock(&(rdp_client->message_lock));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
rdp_client->mouse_button_mask = mask;
|
||||
}
|
||||
|
||||
complete:
|
||||
guac_rwlock_release_lock(&(rdp_client->lock));
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Processes a single key event, updating client state and sending any
|
||||
* associated RDP PDUs via the provided RDP client instance.
|
||||
*
|
||||
* @param rdp_client
|
||||
* The RDP client instance that should be updated and used to send any PDUs
|
||||
* associated with the event.
|
||||
*
|
||||
* @param event
|
||||
* The key event to process.
|
||||
*/
|
||||
static void guac_rdp_handle_key_event(guac_rdp_client* rdp_client,
|
||||
const guac_rdp_input_event* event) {
|
||||
|
||||
/* This function exclusively processes key events, and it's on the caller
|
||||
* to ensure only key events are provided */
|
||||
GUAC_ASSERT(event->type == GUAC_RDP_INPUT_EVENT_KEY);
|
||||
|
||||
int keysym = event->details.key.keysym;
|
||||
int pressed = event->details.key.pressed;
|
||||
|
||||
guac_rwlock_acquire_read_lock(&(rdp_client->lock));
|
||||
|
||||
/* Report key state within recording */
|
||||
if (rdp_client->recording != NULL)
|
||||
guac_recording_report_key(rdp_client->recording,
|
||||
keysym, pressed);
|
||||
|
||||
/* Skip if keyboard not yet ready */
|
||||
if (rdp_client->keyboard == NULL)
|
||||
goto complete;
|
||||
|
||||
/* Update keysym state */
|
||||
guac_rdp_keyboard_update_keysym(rdp_client->keyboard,
|
||||
keysym, pressed, GUAC_RDP_KEY_SOURCE_CLIENT);
|
||||
|
||||
complete:
|
||||
guac_rwlock_release_lock(&(rdp_client->lock));
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Processes a single touch event, updating client state and sending any
|
||||
* associated RDP PDUs via the provided RDP client instance.
|
||||
*
|
||||
* @param rdp_client
|
||||
* The RDP client instance that should be updated and used to send any PDUs
|
||||
* associated with the event.
|
||||
*
|
||||
* @param event
|
||||
* The touch event to process.
|
||||
*/
|
||||
static void guac_rdp_handle_touch_event(guac_rdp_client* rdp_client,
|
||||
const guac_rdp_input_event* event) {
|
||||
|
||||
/* This function exclusively processes touch. events, and it's on the
|
||||
* caller to ensure only touch. events are provided */
|
||||
GUAC_ASSERT(event->type == GUAC_RDP_INPUT_EVENT_TOUCH);
|
||||
|
||||
int id = event->details.touch.id;
|
||||
int x = event->details.touch.x;
|
||||
int y = event->details.touch.y;
|
||||
int x_radius = event->details.touch.x_radius;
|
||||
int y_radius = event->details.touch.y_radius;
|
||||
double angle = event->details.touch.angle;
|
||||
double force = event->details.touch.force;
|
||||
|
||||
guac_rwlock_acquire_read_lock(&(rdp_client->lock));
|
||||
|
||||
/* Skip if not yet connected */
|
||||
freerdp* rdp_inst = rdp_client->rdp_inst;
|
||||
if (rdp_inst == NULL)
|
||||
goto complete;
|
||||
|
||||
/* Report touch event within recording */
|
||||
if (rdp_client->recording != NULL)
|
||||
guac_recording_report_touch(rdp_client->recording, id, x, y,
|
||||
x_radius, y_radius, angle, force);
|
||||
|
||||
/* Forward touch event along RDPEI channel */
|
||||
guac_rdp_rdpei_touch_update(rdp_client->rdpei, id, x, y, force);
|
||||
|
||||
complete:
|
||||
guac_rwlock_release_lock(&(rdp_client->lock));
|
||||
|
||||
}
|
||||
|
||||
void guac_rdp_input_event_enqueue(guac_rdp_client* rdp_client,
|
||||
const guac_rdp_input_event* input_event) {
|
||||
|
||||
guac_fifo_enqueue_and_lock(&rdp_client->input_events, input_event);
|
||||
SetEvent(rdp_client->input_event_queued);
|
||||
guac_fifo_unlock(&rdp_client->input_events);
|
||||
|
||||
}
|
||||
|
||||
void guac_rdp_handle_input_events(guac_rdp_client* rdp_client) {
|
||||
|
||||
guac_fifo_lock(&rdp_client->input_events);
|
||||
|
||||
guac_rdp_input_event input_event;
|
||||
while (guac_fifo_timed_dequeue(&rdp_client->input_events, &input_event, 0)) {
|
||||
switch (input_event.type) {
|
||||
|
||||
/* Mouse event */
|
||||
case GUAC_RDP_INPUT_EVENT_MOUSE:
|
||||
guac_rdp_handle_mouse_event(rdp_client, &input_event);
|
||||
break;
|
||||
|
||||
/* Keyboard event */
|
||||
case GUAC_RDP_INPUT_EVENT_KEY:
|
||||
guac_rdp_handle_key_event(rdp_client, &input_event);
|
||||
break;
|
||||
|
||||
/* Touch event */
|
||||
case GUAC_RDP_INPUT_EVENT_TOUCH:
|
||||
guac_rdp_handle_touch_event(rdp_client, &input_event);
|
||||
break;
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
ResetEvent(rdp_client->input_event_queued);
|
||||
guac_fifo_unlock(&rdp_client->input_events);
|
||||
|
||||
}
|
||||
@ -40,100 +40,19 @@ int guac_rdp_user_mouse_handler(guac_user* user, int x, int y, int mask) {
|
||||
guac_client* client = user->client;
|
||||
guac_rdp_client* rdp_client = (guac_rdp_client*) client->data;
|
||||
|
||||
guac_rwlock_acquire_read_lock(&(rdp_client->lock));
|
||||
|
||||
/* Skip if not yet connected */
|
||||
freerdp* rdp_inst = rdp_client->rdp_inst;
|
||||
if (rdp_inst == NULL)
|
||||
goto complete;
|
||||
|
||||
/* Store current mouse location/state */
|
||||
guac_display_render_thread_notify_user_moved_mouse(rdp_client->render_thread, user, x, y, mask);
|
||||
|
||||
/* Report mouse position within recording */
|
||||
if (rdp_client->recording != NULL)
|
||||
guac_recording_report_mouse(rdp_client->recording, x, y, mask);
|
||||
|
||||
/* If button mask unchanged, just send move event */
|
||||
if (mask == rdp_client->mouse_button_mask) {
|
||||
pthread_mutex_lock(&(rdp_client->message_lock));
|
||||
GUAC_RDP_CONTEXT(rdp_inst)->input->MouseEvent(
|
||||
GUAC_RDP_CONTEXT(rdp_inst)->input, PTR_FLAGS_MOVE, x, y);
|
||||
pthread_mutex_unlock(&(rdp_client->message_lock));
|
||||
}
|
||||
|
||||
/* Otherwise, send events describing button change */
|
||||
else {
|
||||
|
||||
/* Mouse buttons which have JUST become released */
|
||||
int released_mask = rdp_client->mouse_button_mask & ~mask;
|
||||
|
||||
/* Mouse buttons which have JUST become pressed */
|
||||
int pressed_mask = ~rdp_client->mouse_button_mask & mask;
|
||||
|
||||
/* Release event */
|
||||
if (released_mask & 0x07) {
|
||||
|
||||
/* Calculate flags */
|
||||
int flags = 0;
|
||||
if (released_mask & 0x01) flags |= PTR_FLAGS_BUTTON1;
|
||||
if (released_mask & 0x02) flags |= PTR_FLAGS_BUTTON3;
|
||||
if (released_mask & 0x04) flags |= PTR_FLAGS_BUTTON2;
|
||||
|
||||
pthread_mutex_lock(&(rdp_client->message_lock));
|
||||
GUAC_RDP_CONTEXT(rdp_inst)->input->MouseEvent(
|
||||
GUAC_RDP_CONTEXT(rdp_inst)->input, flags, x, y);
|
||||
pthread_mutex_unlock(&(rdp_client->message_lock));
|
||||
|
||||
guac_rdp_input_event mouse_event = {
|
||||
.type = GUAC_RDP_INPUT_EVENT_MOUSE,
|
||||
.user = user,
|
||||
.details.mouse = {
|
||||
.x = x,
|
||||
.y = y,
|
||||
.mask = mask
|
||||
}
|
||||
};
|
||||
|
||||
/* Press event */
|
||||
if (pressed_mask & 0x07) {
|
||||
|
||||
/* Calculate flags */
|
||||
int flags = PTR_FLAGS_DOWN;
|
||||
if (pressed_mask & 0x01) flags |= PTR_FLAGS_BUTTON1;
|
||||
if (pressed_mask & 0x02) flags |= PTR_FLAGS_BUTTON3;
|
||||
if (pressed_mask & 0x04) flags |= PTR_FLAGS_BUTTON2;
|
||||
if (pressed_mask & 0x08) flags |= PTR_FLAGS_WHEEL | 0x78;
|
||||
if (pressed_mask & 0x10) flags |= PTR_FLAGS_WHEEL | PTR_FLAGS_WHEEL_NEGATIVE | 0x88;
|
||||
|
||||
/* Send event */
|
||||
pthread_mutex_lock(&(rdp_client->message_lock));
|
||||
GUAC_RDP_CONTEXT(rdp_inst)->input->MouseEvent(
|
||||
GUAC_RDP_CONTEXT(rdp_inst)->input, flags, x, y);
|
||||
pthread_mutex_unlock(&(rdp_client->message_lock));
|
||||
|
||||
}
|
||||
|
||||
/* Scroll event */
|
||||
if (pressed_mask & 0x18) {
|
||||
|
||||
/* Down */
|
||||
if (pressed_mask & 0x08) {
|
||||
pthread_mutex_lock(&(rdp_client->message_lock));
|
||||
GUAC_RDP_CONTEXT(rdp_inst)->input->MouseEvent(
|
||||
GUAC_RDP_CONTEXT(rdp_inst)->input, PTR_FLAGS_WHEEL | 0x78, x, y);
|
||||
pthread_mutex_unlock(&(rdp_client->message_lock));
|
||||
}
|
||||
|
||||
/* Up */
|
||||
if (pressed_mask & 0x10) {
|
||||
pthread_mutex_lock(&(rdp_client->message_lock));
|
||||
GUAC_RDP_CONTEXT(rdp_inst)->input->MouseEvent(
|
||||
GUAC_RDP_CONTEXT(rdp_inst)->input, PTR_FLAGS_WHEEL | PTR_FLAGS_WHEEL_NEGATIVE | 0x88, x, y);
|
||||
pthread_mutex_unlock(&(rdp_client->message_lock));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
rdp_client->mouse_button_mask = mask;
|
||||
}
|
||||
|
||||
complete:
|
||||
guac_rwlock_release_lock(&(rdp_client->lock));
|
||||
|
||||
guac_rdp_input_event_enqueue(rdp_client, &mouse_event);
|
||||
return 0;
|
||||
|
||||
}
|
||||
|
||||
int guac_rdp_user_touch_handler(guac_user* user, int id, int x, int y,
|
||||
@ -142,52 +61,41 @@ int guac_rdp_user_touch_handler(guac_user* user, int id, int x, int y,
|
||||
guac_client* client = user->client;
|
||||
guac_rdp_client* rdp_client = (guac_rdp_client*) client->data;
|
||||
|
||||
guac_rwlock_acquire_read_lock(&(rdp_client->lock));
|
||||
|
||||
/* Skip if not yet connected */
|
||||
freerdp* rdp_inst = rdp_client->rdp_inst;
|
||||
if (rdp_inst == NULL)
|
||||
goto complete;
|
||||
|
||||
/* Report touch event within recording */
|
||||
if (rdp_client->recording != NULL)
|
||||
guac_recording_report_touch(rdp_client->recording, id, x, y,
|
||||
x_radius, y_radius, angle, force);
|
||||
|
||||
/* Forward touch event along RDPEI channel */
|
||||
guac_rdp_rdpei_touch_update(rdp_client->rdpei, id, x, y, force);
|
||||
|
||||
complete:
|
||||
guac_rwlock_release_lock(&(rdp_client->lock));
|
||||
guac_rdp_input_event touch_event = {
|
||||
.type = GUAC_RDP_INPUT_EVENT_TOUCH,
|
||||
.user = user,
|
||||
.details.touch = {
|
||||
.id = id,
|
||||
.x = x,
|
||||
.y = y,
|
||||
.x_radius = x_radius,
|
||||
.y_radius = y_radius,
|
||||
.angle = angle,
|
||||
.force = force
|
||||
}
|
||||
};
|
||||
|
||||
guac_rdp_input_event_enqueue(rdp_client, &touch_event);
|
||||
return 0;
|
||||
|
||||
}
|
||||
|
||||
int guac_rdp_user_key_handler(guac_user* user, int keysym, int pressed) {
|
||||
|
||||
guac_client* client = user->client;
|
||||
guac_rdp_client* rdp_client = (guac_rdp_client*) client->data;
|
||||
int retval = 0;
|
||||
|
||||
guac_rwlock_acquire_read_lock(&(rdp_client->lock));
|
||||
guac_rdp_input_event key_event = {
|
||||
.type = GUAC_RDP_INPUT_EVENT_KEY,
|
||||
.user = user,
|
||||
.details.key = {
|
||||
.keysym = keysym,
|
||||
.pressed = pressed
|
||||
}
|
||||
};
|
||||
|
||||
/* Report key state within recording */
|
||||
if (rdp_client->recording != NULL)
|
||||
guac_recording_report_key(rdp_client->recording,
|
||||
keysym, pressed);
|
||||
|
||||
/* Skip if keyboard not yet ready */
|
||||
if (rdp_client->keyboard == NULL)
|
||||
goto complete;
|
||||
|
||||
/* Update keysym state */
|
||||
retval = guac_rdp_keyboard_update_keysym(rdp_client->keyboard,
|
||||
keysym, pressed, GUAC_RDP_KEY_SOURCE_CLIENT);
|
||||
|
||||
complete:
|
||||
guac_rwlock_release_lock(&(rdp_client->lock));
|
||||
|
||||
return retval;
|
||||
guac_rdp_input_event_enqueue(rdp_client, &key_event);
|
||||
return 0;
|
||||
|
||||
}
|
||||
|
||||
|
||||
@ -22,6 +22,183 @@
|
||||
|
||||
#include <guacamole/user.h>
|
||||
|
||||
/**
|
||||
* All event types supported by the guac_rdp_input_event structure.
|
||||
*/
|
||||
typedef enum guac_rdp_input_event_type {
|
||||
|
||||
/**
|
||||
* A mouse event, such as mouse movement or press/release of a mouse
|
||||
* button.
|
||||
*/
|
||||
GUAC_RDP_INPUT_EVENT_MOUSE,
|
||||
|
||||
/**
|
||||
* A key event, such as press/release of a keyboard key.
|
||||
*/
|
||||
GUAC_RDP_INPUT_EVENT_KEY,
|
||||
|
||||
/**
|
||||
* A touch event, such as movement of an established touch or a change in
|
||||
* touch pressure.
|
||||
*/
|
||||
GUAC_RDP_INPUT_EVENT_TOUCH
|
||||
|
||||
} guac_rdp_input_event_type;
|
||||
|
||||
/**
|
||||
* Event details specific to GUAC_RDP_INPUT_EVENT_MOUSE events.
|
||||
*/
|
||||
typedef struct guac_rdp_input_event_mouse_details {
|
||||
|
||||
/**
|
||||
* The X coordinate of the mouse pointer, in pixels. This value is not
|
||||
* guaranteed to be within the bounds of the display area.
|
||||
*/
|
||||
int x;
|
||||
|
||||
/**
|
||||
* The Y coordinate of the mouse pointer, in pixels. This value is not
|
||||
* guaranteed to be within the bounds of the display area.
|
||||
*/
|
||||
int y;
|
||||
|
||||
/**
|
||||
* An integer value representing the current state of each button, where
|
||||
* the Nth bit within the integer is set to 1 if and only if the Nth mouse
|
||||
* button is currently pressed. The lowest-order bit is the left mouse
|
||||
* button, followed by the middle button, right button, and finally the up
|
||||
* and down buttons of the scroll wheel.
|
||||
*
|
||||
* @see GUAC_CLIENT_MOUSE_LEFT
|
||||
* @see GUAC_CLIENT_MOUSE_MIDDLE
|
||||
* @see GUAC_CLIENT_MOUSE_RIGHT
|
||||
* @see GUAC_CLIENT_MOUSE_SCROLL_UP
|
||||
* @see GUAC_CLIENT_MOUSE_SCROLL_DOWN
|
||||
*/
|
||||
int mask;
|
||||
|
||||
} guac_rdp_input_event_mouse_details;
|
||||
|
||||
/**
|
||||
* Event details specific to GUAC_RDP_INPUT_EVENT_KEY events.
|
||||
*/
|
||||
typedef struct guac_rdp_input_event_key_details {
|
||||
|
||||
/**
|
||||
* The X11 keysym of the key that was pressed or released.
|
||||
*/
|
||||
int keysym;
|
||||
|
||||
/**
|
||||
* Non-zero if the key was pressed, zero if the key was released.
|
||||
*/
|
||||
int pressed;
|
||||
|
||||
} guac_rdp_input_event_key_details;
|
||||
|
||||
/**
|
||||
* Event details specific to GUAC_RDP_INPUT_EVENT_TOUCH events.
|
||||
*/
|
||||
typedef struct guac_rdp_input_event_touch_details {
|
||||
|
||||
/**
|
||||
* An arbitrary integer ID which uniquely identifies this contact relative
|
||||
* to other active contacts.
|
||||
*/
|
||||
int id;
|
||||
|
||||
/**
|
||||
* The X coordinate of the center of the touch contact within the display
|
||||
* when the event occurred, in pixels. This value is not guaranteed to be
|
||||
* within the bounds of the display area.
|
||||
*/
|
||||
int x;
|
||||
|
||||
/**
|
||||
* The Y coordinate of the center of the touch contact within the display
|
||||
* when the event occurred, in pixels. This value is not guaranteed to be
|
||||
* within the bounds of the display area.
|
||||
*/
|
||||
int y;
|
||||
|
||||
/**
|
||||
* The X radius of the ellipse covering the general area of the touch
|
||||
* contact, in pixels.
|
||||
*/
|
||||
int x_radius;
|
||||
|
||||
/**
|
||||
* The Y radius of the ellipse covering the general area of the touch
|
||||
* contact, in pixels.
|
||||
*/
|
||||
int y_radius;
|
||||
|
||||
/**
|
||||
* The rough angle of clockwise rotation of the general area of the touch
|
||||
* contact, in degrees.
|
||||
*/
|
||||
double angle;
|
||||
|
||||
/**
|
||||
* The relative force exerted by the touch contact, where 0 is no force
|
||||
* (the touch has been lifted) and 1 is maximum force (the maximum amount
|
||||
* of force representable by the device).
|
||||
*/
|
||||
double force;
|
||||
|
||||
} guac_rdp_input_event_touch_details;
|
||||
|
||||
/**
|
||||
* Generic input event that may represent any one of several possible event
|
||||
* types, as dictated by guac_rdp_input_event_type. The available details of
|
||||
* the event depend on the event type.
|
||||
*/
|
||||
typedef struct guac_rdp_input_event {
|
||||
|
||||
/**
|
||||
* The type of this event. This value dictates which event details are
|
||||
* relevant.
|
||||
*/
|
||||
guac_rdp_input_event_type type;
|
||||
|
||||
/**
|
||||
* The user that originated this event. NOTE: This pointer is not
|
||||
* guaranteed to be valid and MUST NOT be dereferenced without verifying
|
||||
* the pointer is actually still valid.
|
||||
*/
|
||||
guac_user* user;
|
||||
|
||||
/**
|
||||
* Event details that are type-specific.
|
||||
*/
|
||||
union {
|
||||
|
||||
/**
|
||||
* Event details specific to GUAC_RDP_INPUT_EVENT_MOUSE events. This
|
||||
* details structure MUST NOT be used for any other event type. Doing
|
||||
* otherwise may overwrite valid event details.
|
||||
*/
|
||||
guac_rdp_input_event_mouse_details mouse;
|
||||
|
||||
/**
|
||||
* Event details specific to GUAC_RDP_INPUT_EVENT_KEY events. This
|
||||
* details structure MUST NOT be used for any other event type. Doing
|
||||
* otherwise may overwrite valid event details.
|
||||
*/
|
||||
guac_rdp_input_event_key_details key;
|
||||
|
||||
/**
|
||||
* Event details specific to GUAC_RDP_INPUT_EVENT_TOUCH events. This
|
||||
* details structure MUST NOT be used for any other event type. Doing
|
||||
* otherwise may overwrite valid event details.
|
||||
*/
|
||||
guac_rdp_input_event_touch_details touch;
|
||||
|
||||
} details;
|
||||
|
||||
} guac_rdp_input_event;
|
||||
|
||||
/**
|
||||
* Handler for Guacamole user mouse events.
|
||||
*/
|
||||
|
||||
@ -35,7 +35,7 @@
|
||||
#include "error.h"
|
||||
#include "fs.h"
|
||||
#include "gdi.h"
|
||||
#include "guacamole/display-types.h"
|
||||
#include "input.h"
|
||||
#include "keyboard.h"
|
||||
#include "plugins/channels.h"
|
||||
#include "pointer.h"
|
||||
@ -433,20 +433,26 @@ static DWORD rdp_freerdp_verify_certificate(freerdp* instance,
|
||||
* A positive value if messages are ready, zero if the specified timeout
|
||||
* period elapsed, or a negative value if an error occurs.
|
||||
*/
|
||||
static int rdp_guac_client_wait_for_messages(guac_client* client,
|
||||
static int rdp_guac_client_wait_for_events(guac_client* client,
|
||||
int timeout_msecs) {
|
||||
|
||||
guac_rdp_client* rdp_client = (guac_rdp_client*) client->data;
|
||||
freerdp* rdp_inst = rdp_client->rdp_inst;
|
||||
|
||||
HANDLE handles[GUAC_RDP_MAX_FILE_DESCRIPTORS];
|
||||
int num_handles = freerdp_get_event_handles(GUAC_RDP_CONTEXT(rdp_inst), handles,
|
||||
GUAC_RDP_MAX_FILE_DESCRIPTORS);
|
||||
int num_handles = 0;
|
||||
|
||||
handles[num_handles++] = rdp_client->input_event_queued;
|
||||
|
||||
num_handles += freerdp_get_event_handles(GUAC_RDP_CONTEXT(rdp_inst),
|
||||
handles + num_handles, GUAC_RDP_MAX_FILE_DESCRIPTORS - num_handles);
|
||||
|
||||
/* Wait for data and construct a reasonable frame */
|
||||
DWORD result = WaitForMultipleObjects(num_handles, handles, FALSE,
|
||||
timeout_msecs);
|
||||
|
||||
ResetEvent(rdp_client->input_event_queued);
|
||||
|
||||
/* Translate WaitForMultipleObjects() return values */
|
||||
switch (result) {
|
||||
|
||||
@ -608,23 +614,38 @@ static int guac_rdp_handle_connection(guac_client* client) {
|
||||
|
||||
/* Wait for data and construct a reasonable frame */
|
||||
|
||||
int wait_result = rdp_guac_client_wait_for_messages(client, GUAC_RDP_MESSAGE_CHECK_INTERVAL);
|
||||
int wait_result = rdp_guac_client_wait_for_events(client, GUAC_RDP_MESSAGE_CHECK_INTERVAL);
|
||||
if (wait_result < 0)
|
||||
break;
|
||||
|
||||
/* Handle any queued FreeRDP events (this may result in RDP messages
|
||||
* being sent), aborting later if FreeRDP event handling fails */
|
||||
if (!guac_rdp_handle_events(rdp_client))
|
||||
wait_result = -1;
|
||||
|
||||
/* Test whether the RDP server is closing the connection */
|
||||
int connection_closing;
|
||||
do {
|
||||
|
||||
/* Handle any queued FreeRDP events (this may result in RDP messages
|
||||
* being sent), aborting later if FreeRDP event handling fails */
|
||||
if (!guac_rdp_handle_events(rdp_client))
|
||||
wait_result = -1;
|
||||
|
||||
/* Test whether the RDP server is closing the connection */
|
||||
#ifdef HAVE_DISCONNECT_CONTEXT
|
||||
connection_closing = freerdp_shall_disconnect_context(rdp_inst->context);
|
||||
connection_closing = freerdp_shall_disconnect_context(rdp_inst->context);
|
||||
#else
|
||||
connection_closing = freerdp_shall_disconnect(rdp_inst);
|
||||
connection_closing = freerdp_shall_disconnect(rdp_inst);
|
||||
#endif
|
||||
|
||||
} while (!connection_closing &&
|
||||
(wait_result = rdp_guac_client_wait_for_events(client, 0)) > 0);
|
||||
|
||||
/* Notify display of any changes to the GDI that may have occurred
|
||||
* while handling events/messages */
|
||||
if (rdp_client->gdi_modified) {
|
||||
guac_display_render_thread_notify_modified(rdp_client->render_thread);
|
||||
rdp_client->gdi_modified = 0;
|
||||
}
|
||||
|
||||
/* Handle any input events that have been received */
|
||||
guac_rdp_handle_input_events(rdp_client);
|
||||
|
||||
/* Close connection cleanly if server is disconnecting */
|
||||
if (connection_closing)
|
||||
guac_rdp_client_abort(client, rdp_inst);
|
||||
|
||||
@ -28,6 +28,7 @@
|
||||
#include "common/list.h"
|
||||
#include "config.h"
|
||||
#include "fs.h"
|
||||
#include "input.h"
|
||||
#include "keyboard.h"
|
||||
#include "print-job.h"
|
||||
#include "settings.h"
|
||||
@ -44,6 +45,7 @@
|
||||
#include <guacamole/audio.h>
|
||||
#include <guacamole/client.h>
|
||||
#include <guacamole/display.h>
|
||||
#include <guacamole/fifo.h>
|
||||
#include <guacamole/rwlock.h>
|
||||
#include <guacamole/recording.h>
|
||||
#include <winpr/wtypes.h>
|
||||
@ -65,6 +67,11 @@
|
||||
#define GUAC_RDP_CONTEXT(rdp_instance) ((rdp_instance))
|
||||
#endif
|
||||
|
||||
/**
|
||||
* The maximum number of input events to allow in the event queue.
|
||||
*/
|
||||
#define GUAC_RDP_INPUT_EVENT_QUEUE_SIZE 4096
|
||||
|
||||
/**
|
||||
* RDP-specific client data.
|
||||
*/
|
||||
@ -114,12 +121,40 @@ typedef struct guac_rdp_client {
|
||||
*/
|
||||
guac_display_layer_raw_context* current_context;
|
||||
|
||||
/**
|
||||
* Whether the graphical state of FreeRDP's GDI has changed since the last
|
||||
* time a frame was sent to the client.
|
||||
*/
|
||||
int gdi_modified;
|
||||
|
||||
/**
|
||||
* The current instance of the guac_display render thread. If the thread
|
||||
* has not yet been started, this will be NULL.
|
||||
*/
|
||||
guac_display_render_thread* render_thread;
|
||||
|
||||
/**
|
||||
* Queue of mouse, keyboard, and touch events. These events are accumulated
|
||||
* and flushed within the RDP client thread to avoid spending excessive
|
||||
* time within Guacamole's event handlers. If an attempt to send an RDP
|
||||
* event to the RDP server takes a noticable amount of time, that time will
|
||||
* otherwise block handling of Guacamole events, including critical events
|
||||
* like "sync" (resulting in miscalculation of processing lag).
|
||||
*/
|
||||
guac_fifo input_events;
|
||||
|
||||
/**
|
||||
* Storage for the input_events queue (see above).
|
||||
*/
|
||||
guac_rdp_input_event input_events_items[GUAC_RDP_INPUT_EVENT_QUEUE_SIZE];
|
||||
|
||||
/**
|
||||
* FreeRDP event handle that is set with SetEvent() when at least one input
|
||||
* event has been added to the input_events queue. When all input events
|
||||
* have been processed, this event handle is cleared with ResetEvent().
|
||||
*/
|
||||
HANDLE input_event_queued;
|
||||
|
||||
/**
|
||||
* The current state of the keyboard with respect to the RDP session.
|
||||
*/
|
||||
@ -253,4 +288,32 @@ typedef struct rdp_freerdp_context {
|
||||
*/
|
||||
void* guac_rdp_client_thread(void* data);
|
||||
|
||||
/**
|
||||
* Enqueues the given input event for future processing by a call to
|
||||
* guac_rdp_handle_input_events(). The values from the input event will be
|
||||
* copied and stored independently of the provided pointer. Calling this
|
||||
* function will automatically notify any threads waiting on the
|
||||
* input_event_queued handle.
|
||||
*
|
||||
* @param rdp_client
|
||||
* The RDP client instance associated with the RDP session receiving the
|
||||
* event.
|
||||
*
|
||||
* @param input_event
|
||||
* The input event to add to the queue.
|
||||
*/
|
||||
void guac_rdp_input_event_enqueue(guac_rdp_client* rdp_client,
|
||||
const guac_rdp_input_event* input_event);
|
||||
|
||||
/**
|
||||
* Processes all events that have been enqueued with
|
||||
* guac_rdp_input_event_enqueue(), clearing the event queue and the state of
|
||||
* the input_event_queued handle. Events are processed in the order they are
|
||||
* received.
|
||||
*
|
||||
* @param rdp_client
|
||||
* The RDP client instance whose queued input events should be processed.
|
||||
*/
|
||||
void guac_rdp_handle_input_events(guac_rdp_client* rdp_client);
|
||||
|
||||
#endif
|
||||
|
||||
@ -1562,6 +1562,9 @@ void guac_rdp_push_settings(guac_client* client,
|
||||
freerdp_settings_set_bool(rdp_settings, FreeRDP_FrameMarkerCommandEnabled, TRUE);
|
||||
freerdp_settings_set_bool(rdp_settings, FreeRDP_SurfaceFrameMarkerEnabled, TRUE);
|
||||
|
||||
freerdp_settings_set_bool(rdp_settings, FreeRDP_FastPathInput, TRUE);
|
||||
freerdp_settings_set_bool(rdp_settings, FreeRDP_FastPathOutput, TRUE);
|
||||
|
||||
/* Enable RemoteFX / Graphics Pipeline */
|
||||
if (guac_settings->enable_gfx) {
|
||||
|
||||
@ -1575,7 +1578,6 @@ void guac_rdp_push_settings(guac_client* client,
|
||||
}
|
||||
|
||||
/* Required for RemoteFX / Graphics Pipeline */
|
||||
freerdp_settings_set_bool(rdp_settings, FreeRDP_FastPathOutput, TRUE);
|
||||
freerdp_settings_set_uint32(rdp_settings, FreeRDP_ColorDepth, RDP_GFX_REQUIRED_DEPTH);
|
||||
freerdp_settings_set_bool(rdp_settings, FreeRDP_SoftwareGdi, TRUE);
|
||||
|
||||
@ -1760,19 +1762,6 @@ void guac_rdp_push_settings(guac_client* client,
|
||||
freerdp_settings_set_uint32(rdp_settings, FreeRDP_OsMinorType, OSMINORTYPE_UNSPECIFIED);
|
||||
freerdp_settings_set_bool(rdp_settings, FreeRDP_DesktopResize, TRUE);
|
||||
|
||||
/* Claim support only for specific updates, independent of FreeRDP defaults */
|
||||
BYTE* order_support = freerdp_settings_get_pointer_writable(rdp_settings, FreeRDP_OrderSupport);
|
||||
if (order_support) {
|
||||
ZeroMemory(order_support, GUAC_RDP_ORDER_SUPPORT_LENGTH);
|
||||
order_support[NEG_DSTBLT_INDEX] = TRUE;
|
||||
order_support[NEG_SCRBLT_INDEX] = TRUE;
|
||||
order_support[NEG_MEMBLT_INDEX] = !guac_settings->disable_bitmap_caching;
|
||||
order_support[NEG_MEMBLT_V2_INDEX] = !guac_settings->disable_bitmap_caching;
|
||||
order_support[NEG_GLYPH_INDEX_INDEX] = !guac_settings->disable_glyph_caching;
|
||||
order_support[NEG_FAST_INDEX_INDEX] = !guac_settings->disable_glyph_caching;
|
||||
order_support[NEG_FAST_GLYPH_INDEX] = !guac_settings->disable_glyph_caching;
|
||||
}
|
||||
|
||||
#ifdef HAVE_RDPSETTINGS_ALLOWUNANOUNCEDORDERSFROMSERVER
|
||||
/* Do not consider server use of unannounced orders to be a fatal error */
|
||||
freerdp_settings_set_bool(rdp_settings, FreeRDP_AllowUnanouncedOrdersFromServer, TRUE);
|
||||
@ -1807,9 +1796,8 @@ void guac_rdp_push_settings(guac_client* client,
|
||||
rdp_settings->FrameMarkerCommandEnabled = TRUE;
|
||||
rdp_settings->SurfaceFrameMarkerEnabled = TRUE;
|
||||
|
||||
/* Always handle input events asynchronously (rather than synchronously
|
||||
* with the rest of FreeRDP's event loop, including graphics) */
|
||||
rdp_settings->AsyncInput = TRUE;
|
||||
rdp_settings->FastPathInput = TRUE;
|
||||
rdp_settings->FastPathOutput = TRUE;
|
||||
|
||||
/* Enable RemoteFX / Graphics Pipeline */
|
||||
if (guac_settings->enable_gfx) {
|
||||
@ -1824,7 +1812,6 @@ void guac_rdp_push_settings(guac_client* client,
|
||||
}
|
||||
|
||||
/* Required for RemoteFX / Graphics Pipeline */
|
||||
rdp_settings->FastPathOutput = TRUE;
|
||||
rdp_settings->ColorDepth = RDP_GFX_REQUIRED_DEPTH;
|
||||
rdp_settings->SoftwareGdi = TRUE;
|
||||
|
||||
@ -2009,16 +1996,6 @@ void guac_rdp_push_settings(guac_client* client,
|
||||
rdp_settings->OsMinorType = OSMINORTYPE_UNSPECIFIED;
|
||||
rdp_settings->DesktopResize = TRUE;
|
||||
|
||||
/* Claim support only for specific updates, independent of FreeRDP defaults */
|
||||
ZeroMemory(rdp_settings->OrderSupport, GUAC_RDP_ORDER_SUPPORT_LENGTH);
|
||||
rdp_settings->OrderSupport[NEG_DSTBLT_INDEX] = TRUE;
|
||||
rdp_settings->OrderSupport[NEG_SCRBLT_INDEX] = TRUE;
|
||||
rdp_settings->OrderSupport[NEG_MEMBLT_INDEX] = !guac_settings->disable_bitmap_caching;
|
||||
rdp_settings->OrderSupport[NEG_MEMBLT_V2_INDEX] = !guac_settings->disable_bitmap_caching;
|
||||
rdp_settings->OrderSupport[NEG_GLYPH_INDEX_INDEX] = !guac_settings->disable_glyph_caching;
|
||||
rdp_settings->OrderSupport[NEG_FAST_INDEX_INDEX] = !guac_settings->disable_glyph_caching;
|
||||
rdp_settings->OrderSupport[NEG_FAST_GLYPH_INDEX] = !guac_settings->disable_glyph_caching;
|
||||
|
||||
#ifdef HAVE_RDPSETTINGS_ALLOWUNANOUNCEDORDERSFROMSERVER
|
||||
/* Do not consider server use of unannounced orders to be a fatal error */
|
||||
rdp_settings->AllowUnanouncedOrdersFromServer = TRUE;
|
||||
|
||||
@ -629,7 +629,7 @@ void* guac_vnc_client_thread(void* data) {
|
||||
|
||||
/* Wait for data and construct a reasonable frame */
|
||||
int wait_result = guac_vnc_wait_for_messages(rfb_client, GUAC_VNC_MESSAGE_CHECK_INTERVAL);
|
||||
if (wait_result > 0) {
|
||||
while (wait_result > 0) {
|
||||
|
||||
/* Handle any message received */
|
||||
if (!guac_vnc_handle_messages(client)) {
|
||||
@ -639,10 +639,12 @@ void* guac_vnc_client_thread(void* data) {
|
||||
break;
|
||||
}
|
||||
|
||||
wait_result = guac_vnc_wait_for_messages(rfb_client, 0);
|
||||
|
||||
}
|
||||
|
||||
/* If an error occurs, log it and fail */
|
||||
else if (wait_result < 0)
|
||||
if (wait_result < 0)
|
||||
guac_client_abort(client, GUAC_PROTOCOL_STATUS_UPSTREAM_ERROR, "Connection closed.");
|
||||
|
||||
}
|
||||
|
||||
Loading…
Reference in New Issue
Block a user