Merge pull request #129 from glyptodon/rdp-resize
GUAC-1164: Add parameter for automatically reconnecting when display changes
This commit is contained in:
commit
55f5d1cca3
@ -437,7 +437,6 @@ if test "x$with_rdp" != "xno"
|
|||||||
then
|
then
|
||||||
have_winpr=yes
|
have_winpr=yes
|
||||||
have_freerdp=yes
|
have_freerdp=yes
|
||||||
have_disp=yes
|
|
||||||
legacy_freerdp_extensions=no
|
legacy_freerdp_extensions=no
|
||||||
rdpsettings_interface=unknown
|
rdpsettings_interface=unknown
|
||||||
rdpsettings_audioplayback=yes
|
rdpsettings_audioplayback=yes
|
||||||
@ -554,8 +553,7 @@ then
|
|||||||
[AC_DEFINE([HAVE_FREERDP_DISPLAY_UPDATE_SUPPORT],,
|
[AC_DEFINE([HAVE_FREERDP_DISPLAY_UPDATE_SUPPORT],,
|
||||||
[Whether FreeRDP supports the display update channel])]
|
[Whether FreeRDP supports the display update channel])]
|
||||||
[AC_CHECK_MEMBERS([rdpSettings.SupportDisplayControl],,,
|
[AC_CHECK_MEMBERS([rdpSettings.SupportDisplayControl],,,
|
||||||
[[#include <freerdp/freerdp.h>]])],
|
[[#include <freerdp/freerdp.h>]])],,
|
||||||
have_disp=no,
|
|
||||||
[#include <winpr/wtypes.h>
|
[#include <winpr/wtypes.h>
|
||||||
#include <winpr/collections.h>])
|
#include <winpr/collections.h>])
|
||||||
fi
|
fi
|
||||||
@ -869,7 +867,6 @@ then
|
|||||||
fi
|
fi
|
||||||
|
|
||||||
AM_CONDITIONAL([LEGACY_FREERDP_EXTENSIONS], [test "x${legacy_freerdp_extensions}" = "xyes"])
|
AM_CONDITIONAL([LEGACY_FREERDP_EXTENSIONS], [test "x${legacy_freerdp_extensions}" = "xyes"])
|
||||||
AM_CONDITIONAL([ENABLE_DISPLAY_UPDATE], [test "x${have_disp}" = "xyes"])
|
|
||||||
AM_CONDITIONAL([ENABLE_WINPR], [test "x${have_winpr}" = "xyes"])
|
AM_CONDITIONAL([ENABLE_WINPR], [test "x${have_winpr}" = "xyes"])
|
||||||
AM_CONDITIONAL([ENABLE_RDP], [test "x${have_freerdp}" = "xyes"])
|
AM_CONDITIONAL([ENABLE_RDP], [test "x${have_freerdp}" = "xyes"])
|
||||||
|
|
||||||
|
@ -29,6 +29,7 @@
|
|||||||
|
|
||||||
#include <cairo/cairo.h>
|
#include <cairo/cairo.h>
|
||||||
#include <guacamole/client.h>
|
#include <guacamole/client.h>
|
||||||
|
#include <guacamole/layer.h>
|
||||||
#include <guacamole/protocol.h>
|
#include <guacamole/protocol.h>
|
||||||
#include <guacamole/socket.h>
|
#include <guacamole/socket.h>
|
||||||
#include <guacamole/user.h>
|
#include <guacamole/user.h>
|
||||||
@ -70,13 +71,20 @@ guac_common_cursor* guac_common_cursor_alloc(guac_client* client) {
|
|||||||
|
|
||||||
void guac_common_cursor_free(guac_common_cursor* cursor) {
|
void guac_common_cursor_free(guac_common_cursor* cursor) {
|
||||||
|
|
||||||
|
guac_client* client = cursor->client;
|
||||||
|
guac_layer* layer = cursor->layer;
|
||||||
|
cairo_surface_t* surface = cursor->surface;
|
||||||
|
|
||||||
/* Free image buffer and surface */
|
/* Free image buffer and surface */
|
||||||
free(cursor->image_buffer);
|
free(cursor->image_buffer);
|
||||||
if (cursor->surface != NULL)
|
if (surface != NULL)
|
||||||
cairo_surface_destroy(cursor->surface);
|
cairo_surface_destroy(surface);
|
||||||
|
|
||||||
|
/* Destroy layer within remotely-connected client */
|
||||||
|
guac_protocol_send_dispose(client->socket, layer);
|
||||||
|
|
||||||
/* Return layer to pool */
|
/* Return layer to pool */
|
||||||
guac_client_free_layer(cursor->client, cursor->layer);
|
guac_client_free_layer(client, layer);
|
||||||
|
|
||||||
free(cursor);
|
free(cursor);
|
||||||
|
|
||||||
|
@ -84,6 +84,9 @@ static void guac_common_display_free_layers(guac_common_display_layer* layers,
|
|||||||
/* Free surface */
|
/* Free surface */
|
||||||
guac_common_surface_free(current->surface);
|
guac_common_surface_free(current->surface);
|
||||||
|
|
||||||
|
/* Destroy layer within remotely-connected client */
|
||||||
|
guac_protocol_send_dispose(client->socket, layer);
|
||||||
|
|
||||||
/* Free layer or buffer depending on index */
|
/* Free layer or buffer depending on index */
|
||||||
if (layer->index < 0)
|
if (layer->index < 0)
|
||||||
guac_client_free_buffer(client, layer);
|
guac_client_free_buffer(client, layer);
|
||||||
|
@ -33,6 +33,7 @@ libguac_client_rdp_la_SOURCES = \
|
|||||||
rdp_bitmap.c \
|
rdp_bitmap.c \
|
||||||
rdp_cliprdr.c \
|
rdp_cliprdr.c \
|
||||||
rdp_color.c \
|
rdp_color.c \
|
||||||
|
rdp_disp.c \
|
||||||
rdp_fs.c \
|
rdp_fs.c \
|
||||||
rdp_gdi.c \
|
rdp_gdi.c \
|
||||||
rdp_glyph.c \
|
rdp_glyph.c \
|
||||||
@ -87,6 +88,7 @@ noinst_HEADERS = \
|
|||||||
rdp_bitmap.h \
|
rdp_bitmap.h \
|
||||||
rdp_cliprdr.h \
|
rdp_cliprdr.h \
|
||||||
rdp_color.h \
|
rdp_color.h \
|
||||||
|
rdp_disp.h \
|
||||||
rdp_fs.h \
|
rdp_fs.h \
|
||||||
rdp_gdi.h \
|
rdp_gdi.h \
|
||||||
rdp_glyph.h \
|
rdp_glyph.h \
|
||||||
@ -110,12 +112,6 @@ guacsnd_sources += compat/winpr-stream.c
|
|||||||
guacdr_sources += compat/winpr-stream.c
|
guacdr_sources += compat/winpr-stream.c
|
||||||
endif
|
endif
|
||||||
|
|
||||||
# Add display update channel support, if supported by FreeRDP
|
|
||||||
if ENABLE_DISPLAY_UPDATE
|
|
||||||
noinst_HEADERS += rdp_disp.h
|
|
||||||
libguac_client_rdp_la_SOURCES += rdp_disp.c
|
|
||||||
endif
|
|
||||||
|
|
||||||
#
|
#
|
||||||
# Main RDP client library
|
# Main RDP client library
|
||||||
#
|
#
|
||||||
|
@ -24,6 +24,7 @@
|
|||||||
|
|
||||||
#include "client.h"
|
#include "client.h"
|
||||||
#include "rdp.h"
|
#include "rdp.h"
|
||||||
|
#include "rdp_disp.h"
|
||||||
#include "rdp_keymap.h"
|
#include "rdp_keymap.h"
|
||||||
#include "user.h"
|
#include "user.h"
|
||||||
|
|
||||||
@ -33,10 +34,6 @@
|
|||||||
#include <guac_ssh_user.h>
|
#include <guac_ssh_user.h>
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifdef HAVE_FREERDP_DISPLAY_UPDATE_SUPPORT
|
|
||||||
#include "rdp_disp.h"
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#include <freerdp/cache/cache.h>
|
#include <freerdp/cache/cache.h>
|
||||||
#include <freerdp/channels/channels.h>
|
#include <freerdp/channels/channels.h>
|
||||||
#include <freerdp/freerdp.h>
|
#include <freerdp/freerdp.h>
|
||||||
@ -66,10 +63,11 @@ int guac_client_init(guac_client* client, int argc, char** argv) {
|
|||||||
guac_rdp_client* rdp_client = calloc(1, sizeof(guac_rdp_client));
|
guac_rdp_client* rdp_client = calloc(1, sizeof(guac_rdp_client));
|
||||||
client->data = rdp_client;
|
client->data = rdp_client;
|
||||||
|
|
||||||
/* Init clipboard and shared mouse */
|
/* Init clipboard */
|
||||||
rdp_client->clipboard = guac_common_clipboard_alloc(GUAC_RDP_CLIPBOARD_MAX_LENGTH);
|
rdp_client->clipboard = guac_common_clipboard_alloc(GUAC_RDP_CLIPBOARD_MAX_LENGTH);
|
||||||
rdp_client->requested_clipboard_format = CB_FORMAT_TEXT;
|
|
||||||
rdp_client->available_svc = guac_common_list_alloc();
|
/* Init display update module */
|
||||||
|
rdp_client->disp = guac_rdp_disp_alloc();
|
||||||
|
|
||||||
/* Recursive attribute for locks */
|
/* Recursive attribute for locks */
|
||||||
pthread_mutexattr_init(&(rdp_client->attributes));
|
pthread_mutexattr_init(&(rdp_client->attributes));
|
||||||
@ -98,54 +96,15 @@ int guac_rdp_client_free_handler(guac_client* client) {
|
|||||||
/* Wait for client thread */
|
/* Wait for client thread */
|
||||||
pthread_join(rdp_client->client_thread, NULL);
|
pthread_join(rdp_client->client_thread, NULL);
|
||||||
|
|
||||||
freerdp* rdp_inst = rdp_client->rdp_inst;
|
|
||||||
if (rdp_inst != NULL) {
|
|
||||||
rdpChannels* channels = rdp_inst->context->channels;
|
|
||||||
|
|
||||||
/* Clean up RDP client */
|
|
||||||
freerdp_channels_close(channels, rdp_inst);
|
|
||||||
freerdp_channels_free(channels);
|
|
||||||
freerdp_disconnect(rdp_inst);
|
|
||||||
freerdp_clrconv_free(((rdp_freerdp_context*) rdp_inst->context)->clrconv);
|
|
||||||
cache_free(rdp_inst->context->cache);
|
|
||||||
freerdp_free(rdp_inst);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Clean up filesystem, if allocated */
|
|
||||||
if (rdp_client->filesystem != NULL)
|
|
||||||
guac_rdp_fs_free(rdp_client->filesystem);
|
|
||||||
|
|
||||||
#ifdef ENABLE_COMMON_SSH
|
|
||||||
/* Free SFTP filesystem, if loaded */
|
|
||||||
if (rdp_client->sftp_filesystem)
|
|
||||||
guac_common_ssh_destroy_sftp_filesystem(rdp_client->sftp_filesystem);
|
|
||||||
|
|
||||||
/* Free SFTP session */
|
|
||||||
if (rdp_client->sftp_session)
|
|
||||||
guac_common_ssh_destroy_session(rdp_client->sftp_session);
|
|
||||||
|
|
||||||
/* Free SFTP user */
|
|
||||||
if (rdp_client->sftp_user)
|
|
||||||
guac_common_ssh_destroy_user(rdp_client->sftp_user);
|
|
||||||
|
|
||||||
guac_common_ssh_uninit();
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#ifdef HAVE_FREERDP_DISPLAY_UPDATE_SUPPORT
|
|
||||||
/* Free display update module */
|
|
||||||
guac_rdp_disp_free(rdp_client->disp);
|
|
||||||
#endif
|
|
||||||
|
|
||||||
/* Free SVC list */
|
|
||||||
guac_common_list_free(rdp_client->available_svc);
|
|
||||||
|
|
||||||
/* Free parsed settings */
|
/* Free parsed settings */
|
||||||
if (rdp_client->settings != NULL)
|
if (rdp_client->settings != NULL)
|
||||||
guac_rdp_settings_free(rdp_client->settings);
|
guac_rdp_settings_free(rdp_client->settings);
|
||||||
|
|
||||||
|
/* Free display update module */
|
||||||
|
guac_rdp_disp_free(rdp_client->disp);
|
||||||
|
|
||||||
/* Free client data */
|
/* Free client data */
|
||||||
guac_common_clipboard_free(rdp_client->clipboard);
|
guac_common_clipboard_free(rdp_client->clipboard);
|
||||||
guac_common_display_free(rdp_client->display);
|
|
||||||
free(rdp_client);
|
free(rdp_client);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
|
@ -25,27 +25,19 @@
|
|||||||
#include "client.h"
|
#include "client.h"
|
||||||
#include "input.h"
|
#include "input.h"
|
||||||
#include "rdp.h"
|
#include "rdp.h"
|
||||||
|
#include "rdp_disp.h"
|
||||||
#include "rdp_keymap.h"
|
#include "rdp_keymap.h"
|
||||||
|
|
||||||
#include <freerdp/freerdp.h>
|
#include <freerdp/freerdp.h>
|
||||||
#include <freerdp/input.h>
|
#include <freerdp/input.h>
|
||||||
#include <guacamole/client.h>
|
#include <guacamole/client.h>
|
||||||
|
|
||||||
#ifdef HAVE_FREERDP_DISPLAY_UPDATE_SUPPORT
|
|
||||||
#include "rdp_disp.h"
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#include <pthread.h>
|
#include <pthread.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
|
|
||||||
int guac_rdp_send_keysym(guac_client* client, int keysym, int pressed) {
|
int guac_rdp_send_keysym(guac_client* client, int keysym, int pressed) {
|
||||||
|
|
||||||
guac_rdp_client* rdp_client = (guac_rdp_client*) client->data;
|
guac_rdp_client* rdp_client = (guac_rdp_client*) client->data;
|
||||||
freerdp* rdp_inst = rdp_client->rdp_inst;
|
|
||||||
|
|
||||||
/* Skip if not yet connected */
|
|
||||||
if (rdp_inst == NULL)
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
/* If keysym can be in lookup table */
|
/* If keysym can be in lookup table */
|
||||||
if (GUAC_RDP_KEYSYM_STORABLE(keysym)) {
|
if (GUAC_RDP_KEYSYM_STORABLE(keysym)) {
|
||||||
@ -75,6 +67,13 @@ int guac_rdp_send_keysym(guac_client* client, int keysym, int pressed) {
|
|||||||
else
|
else
|
||||||
pressed_flags = KBD_FLAGS_RELEASE;
|
pressed_flags = KBD_FLAGS_RELEASE;
|
||||||
|
|
||||||
|
/* Skip if not yet connected */
|
||||||
|
freerdp* rdp_inst = rdp_client->rdp_inst;
|
||||||
|
if (rdp_inst == NULL) {
|
||||||
|
pthread_mutex_unlock(&(rdp_client->rdp_lock));
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
/* Send actual key */
|
/* Send actual key */
|
||||||
rdp_inst->input->KeyboardEvent(rdp_inst->input, keysym_desc->flags | pressed_flags,
|
rdp_inst->input->KeyboardEvent(rdp_inst->input, keysym_desc->flags | pressed_flags,
|
||||||
keysym_desc->scancode);
|
keysym_desc->scancode);
|
||||||
@ -118,6 +117,13 @@ int guac_rdp_send_keysym(guac_client* client, int keysym, int pressed) {
|
|||||||
|
|
||||||
pthread_mutex_lock(&(rdp_client->rdp_lock));
|
pthread_mutex_lock(&(rdp_client->rdp_lock));
|
||||||
|
|
||||||
|
/* Skip if not yet connected */
|
||||||
|
freerdp* rdp_inst = rdp_client->rdp_inst;
|
||||||
|
if (rdp_inst == NULL) {
|
||||||
|
pthread_mutex_unlock(&(rdp_client->rdp_lock));
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
/* Send Unicode event */
|
/* Send Unicode event */
|
||||||
rdp_inst->input->UnicodeKeyboardEvent(
|
rdp_inst->input->UnicodeKeyboardEvent(
|
||||||
rdp_inst->input,
|
rdp_inst->input,
|
||||||
@ -156,16 +162,18 @@ int guac_rdp_user_mouse_handler(guac_user* user, int x, int y, int mask) {
|
|||||||
|
|
||||||
guac_client* client = user->client;
|
guac_client* client = user->client;
|
||||||
guac_rdp_client* rdp_client = (guac_rdp_client*) client->data;
|
guac_rdp_client* rdp_client = (guac_rdp_client*) client->data;
|
||||||
freerdp* rdp_inst = rdp_client->rdp_inst;
|
|
||||||
|
pthread_mutex_lock(&(rdp_client->rdp_lock));
|
||||||
|
|
||||||
/* Store current mouse location */
|
/* Store current mouse location */
|
||||||
guac_common_cursor_move(rdp_client->display->cursor, user, x, y);
|
guac_common_cursor_move(rdp_client->display->cursor, user, x, y);
|
||||||
|
|
||||||
/* Skip if not yet connected */
|
/* Skip if not yet connected */
|
||||||
if (rdp_inst == NULL)
|
freerdp* rdp_inst = rdp_client->rdp_inst;
|
||||||
|
if (rdp_inst == NULL) {
|
||||||
|
pthread_mutex_unlock(&(rdp_client->rdp_lock));
|
||||||
return 0;
|
return 0;
|
||||||
|
}
|
||||||
pthread_mutex_lock(&(rdp_client->rdp_lock));
|
|
||||||
|
|
||||||
/* If button mask unchanged, just send move event */
|
/* If button mask unchanged, just send move event */
|
||||||
if (mask == rdp_client->mouse_button_mask)
|
if (mask == rdp_client->mouse_button_mask)
|
||||||
@ -251,28 +259,19 @@ int guac_rdp_user_key_handler(guac_user* user, int keysym, int pressed) {
|
|||||||
|
|
||||||
int guac_rdp_user_size_handler(guac_user* user, int width, int height) {
|
int guac_rdp_user_size_handler(guac_user* user, int width, int height) {
|
||||||
|
|
||||||
#ifdef HAVE_FREERDP_DISPLAY_UPDATE_SUPPORT
|
|
||||||
guac_client* client = user->client;
|
guac_client* client = user->client;
|
||||||
guac_rdp_client* rdp_client = (guac_rdp_client*) client->data;
|
guac_rdp_client* rdp_client = (guac_rdp_client*) client->data;
|
||||||
|
guac_rdp_settings* settings = rdp_client->settings;
|
||||||
freerdp* rdp_inst = rdp_client->rdp_inst;
|
freerdp* rdp_inst = rdp_client->rdp_inst;
|
||||||
|
|
||||||
/* Skip if not yet connected */
|
|
||||||
if (rdp_inst == NULL)
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
/* Convert client pixels to remote pixels */
|
/* Convert client pixels to remote pixels */
|
||||||
width = width * rdp_client->settings->resolution
|
width = width * settings->resolution / user->info.optimal_resolution;
|
||||||
/ user->info.optimal_resolution;
|
height = height * settings->resolution / user->info.optimal_resolution;
|
||||||
|
|
||||||
height = height * rdp_client->settings->resolution
|
|
||||||
/ user->info.optimal_resolution;
|
|
||||||
|
|
||||||
/* Send display update */
|
/* Send display update */
|
||||||
pthread_mutex_lock(&(rdp_client->rdp_lock));
|
pthread_mutex_lock(&(rdp_client->rdp_lock));
|
||||||
guac_rdp_disp_set_size(rdp_client->disp, rdp_inst->context, width, height);
|
guac_rdp_disp_set_size(rdp_client->disp, settings, rdp_inst, width, height);
|
||||||
pthread_mutex_unlock(&(rdp_client->rdp_lock));
|
pthread_mutex_unlock(&(rdp_client->rdp_lock));
|
||||||
#endif
|
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
|
@ -29,6 +29,7 @@
|
|||||||
#include "rdp.h"
|
#include "rdp.h"
|
||||||
#include "rdp_bitmap.h"
|
#include "rdp_bitmap.h"
|
||||||
#include "rdp_cliprdr.h"
|
#include "rdp_cliprdr.h"
|
||||||
|
#include "rdp_disp.h"
|
||||||
#include "rdp_gdi.h"
|
#include "rdp_gdi.h"
|
||||||
#include "rdp_glyph.h"
|
#include "rdp_glyph.h"
|
||||||
#include "rdp_keymap.h"
|
#include "rdp_keymap.h"
|
||||||
@ -43,10 +44,6 @@
|
|||||||
#include <guac_ssh_user.h>
|
#include <guac_ssh_user.h>
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifdef HAVE_FREERDP_DISPLAY_UPDATE_SUPPORT
|
|
||||||
#include "rdp_disp.h"
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#include <freerdp/cache/bitmap.h>
|
#include <freerdp/cache/bitmap.h>
|
||||||
#include <freerdp/cache/brush.h>
|
#include <freerdp/cache/brush.h>
|
||||||
#include <freerdp/cache/glyph.h>
|
#include <freerdp/cache/glyph.h>
|
||||||
@ -173,27 +170,30 @@ static int __guac_receive_channel_data(freerdp* rdp_inst, int channelId,
|
|||||||
static void guac_rdp_channel_connected(rdpContext* context,
|
static void guac_rdp_channel_connected(rdpContext* context,
|
||||||
ChannelConnectedEventArgs* e) {
|
ChannelConnectedEventArgs* e) {
|
||||||
|
|
||||||
|
guac_client* client = ((rdp_freerdp_context*) context)->client;
|
||||||
|
guac_rdp_client* rdp_client = (guac_rdp_client*) client->data;
|
||||||
|
guac_rdp_settings* settings = rdp_client->settings;
|
||||||
|
|
||||||
|
if (settings->resize_method == GUAC_RESIZE_DISPLAY_UPDATE) {
|
||||||
#ifdef HAVE_RDPSETTINGS_SUPPORTDISPLAYCONTROL
|
#ifdef HAVE_RDPSETTINGS_SUPPORTDISPLAYCONTROL
|
||||||
/* Store reference to the display update plugin once it's connected */
|
/* Store reference to the display update plugin once it's connected */
|
||||||
if (strcmp(e->name, DISP_DVC_CHANNEL_NAME) == 0) {
|
if (strcmp(e->name, DISP_DVC_CHANNEL_NAME) == 0) {
|
||||||
|
|
||||||
DispClientContext* disp = (DispClientContext*) e->pInterface;
|
DispClientContext* disp = (DispClientContext*) e->pInterface;
|
||||||
|
|
||||||
guac_client* client = ((rdp_freerdp_context*) context)->client;
|
/* Init module with current display size */
|
||||||
guac_rdp_client* rdp_client = (guac_rdp_client*) client->data;
|
guac_rdp_disp_set_size(rdp_client->disp, rdp_client->settings,
|
||||||
|
context->instance, guac_rdp_get_width(context->instance),
|
||||||
|
guac_rdp_get_height(context->instance));
|
||||||
|
|
||||||
/* Init module with current display size */
|
/* Store connected channel */
|
||||||
guac_rdp_disp_set_size(rdp_client->disp, context,
|
guac_rdp_disp_connect(rdp_client->disp, disp);
|
||||||
guac_rdp_get_width(context->instance),
|
guac_client_log(client, GUAC_LOG_DEBUG,
|
||||||
guac_rdp_get_height(context->instance));
|
"Display update channel connected.");
|
||||||
|
|
||||||
/* Store connected channel */
|
}
|
||||||
guac_rdp_disp_connect(rdp_client->disp, disp);
|
|
||||||
guac_client_log(client, GUAC_LOG_DEBUG,
|
|
||||||
"Display update channel connected.");
|
|
||||||
|
|
||||||
}
|
|
||||||
#endif
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
@ -201,16 +201,18 @@ static void guac_rdp_channel_connected(rdpContext* context,
|
|||||||
BOOL rdp_freerdp_pre_connect(freerdp* instance) {
|
BOOL rdp_freerdp_pre_connect(freerdp* instance) {
|
||||||
|
|
||||||
rdpContext* context = instance->context;
|
rdpContext* context = instance->context;
|
||||||
guac_client* client = ((rdp_freerdp_context*) context)->client;
|
|
||||||
rdpChannels* channels = context->channels;
|
rdpChannels* channels = context->channels;
|
||||||
|
|
||||||
|
guac_client* client = ((rdp_freerdp_context*) context)->client;
|
||||||
|
guac_rdp_client* rdp_client = (guac_rdp_client*) client->data;
|
||||||
|
guac_rdp_settings* settings = rdp_client->settings;
|
||||||
|
|
||||||
rdpBitmap* bitmap;
|
rdpBitmap* bitmap;
|
||||||
rdpGlyph* glyph;
|
rdpGlyph* glyph;
|
||||||
rdpPointer* pointer;
|
rdpPointer* pointer;
|
||||||
rdpPrimaryUpdate* primary;
|
rdpPrimaryUpdate* primary;
|
||||||
CLRCONV* clrconv;
|
CLRCONV* clrconv;
|
||||||
|
|
||||||
guac_rdp_client* rdp_client =
|
|
||||||
(guac_rdp_client*) client->data;
|
|
||||||
|
|
||||||
#ifdef HAVE_FREERDP_REGISTER_ADDIN_PROVIDER
|
#ifdef HAVE_FREERDP_REGISTER_ADDIN_PROVIDER
|
||||||
/* Init FreeRDP add-in provider */
|
/* Init FreeRDP add-in provider */
|
||||||
@ -223,17 +225,15 @@ BOOL rdp_freerdp_pre_connect(freerdp* instance) {
|
|||||||
(pChannelConnectedEventHandler) guac_rdp_channel_connected);
|
(pChannelConnectedEventHandler) guac_rdp_channel_connected);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifdef HAVE_FREERDP_DISPLAY_UPDATE_SUPPORT
|
|
||||||
/* Load virtual channel management plugin */
|
/* Load virtual channel management plugin */
|
||||||
if (freerdp_channels_load_plugin(channels, instance->settings,
|
if (freerdp_channels_load_plugin(channels, instance->settings,
|
||||||
"drdynvc", instance->settings))
|
"drdynvc", instance->settings))
|
||||||
guac_client_log(client, GUAC_LOG_WARNING,
|
guac_client_log(client, GUAC_LOG_WARNING,
|
||||||
"Failed to load drdynvc plugin.");
|
"Failed to load drdynvc plugin.");
|
||||||
|
|
||||||
/* Init display update plugin */
|
/* Init display update plugin (if available and required) */
|
||||||
rdp_client->disp = guac_rdp_disp_alloc();
|
if (settings->resize_method == GUAC_RESIZE_DISPLAY_UPDATE)
|
||||||
guac_rdp_disp_load_plugin(instance->context);
|
guac_rdp_disp_load_plugin(instance->context);
|
||||||
#endif
|
|
||||||
|
|
||||||
/* Load clipboard plugin */
|
/* Load clipboard plugin */
|
||||||
if (freerdp_channels_load_plugin(channels, instance->settings,
|
if (freerdp_channels_load_plugin(channels, instance->settings,
|
||||||
@ -242,7 +242,7 @@ BOOL rdp_freerdp_pre_connect(freerdp* instance) {
|
|||||||
"Failed to load cliprdr plugin. Clipboard will not work.");
|
"Failed to load cliprdr plugin. Clipboard will not work.");
|
||||||
|
|
||||||
/* If audio enabled, choose an encoder */
|
/* If audio enabled, choose an encoder */
|
||||||
if (rdp_client->settings->audio_enabled) {
|
if (settings->audio_enabled) {
|
||||||
|
|
||||||
rdp_client->audio = guac_audio_stream_alloc(client, NULL,
|
rdp_client->audio = guac_audio_stream_alloc(client, NULL,
|
||||||
GUAC_RDP_AUDIO_RATE,
|
GUAC_RDP_AUDIO_RATE,
|
||||||
@ -257,15 +257,15 @@ BOOL rdp_freerdp_pre_connect(freerdp* instance) {
|
|||||||
} /* end if audio enabled */
|
} /* end if audio enabled */
|
||||||
|
|
||||||
/* Load filesystem if drive enabled */
|
/* Load filesystem if drive enabled */
|
||||||
if (rdp_client->settings->drive_enabled)
|
if (settings->drive_enabled)
|
||||||
rdp_client->filesystem =
|
rdp_client->filesystem =
|
||||||
guac_rdp_fs_alloc(client, rdp_client->settings->drive_path,
|
guac_rdp_fs_alloc(client, settings->drive_path,
|
||||||
rdp_client->settings->create_drive_path);
|
settings->create_drive_path);
|
||||||
|
|
||||||
/* If RDPSND/RDPDR required, load them */
|
/* If RDPSND/RDPDR required, load them */
|
||||||
if (rdp_client->settings->printing_enabled
|
if (settings->printing_enabled
|
||||||
|| rdp_client->settings->drive_enabled
|
|| settings->drive_enabled
|
||||||
|| rdp_client->settings->audio_enabled) {
|
|| settings->audio_enabled) {
|
||||||
|
|
||||||
/* Load RDPDR plugin */
|
/* Load RDPDR plugin */
|
||||||
if (freerdp_channels_load_plugin(channels, instance->settings,
|
if (freerdp_channels_load_plugin(channels, instance->settings,
|
||||||
@ -285,15 +285,15 @@ BOOL rdp_freerdp_pre_connect(freerdp* instance) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* Load RAIL plugin if RemoteApp in use */
|
/* Load RAIL plugin if RemoteApp in use */
|
||||||
if (rdp_client->settings->remote_app != NULL) {
|
if (settings->remote_app != NULL) {
|
||||||
|
|
||||||
#ifdef LEGACY_FREERDP
|
#ifdef LEGACY_FREERDP
|
||||||
RDP_PLUGIN_DATA* plugin_data = malloc(sizeof(RDP_PLUGIN_DATA) * 2);
|
RDP_PLUGIN_DATA* plugin_data = malloc(sizeof(RDP_PLUGIN_DATA) * 2);
|
||||||
|
|
||||||
plugin_data[0].size = sizeof(RDP_PLUGIN_DATA);
|
plugin_data[0].size = sizeof(RDP_PLUGIN_DATA);
|
||||||
plugin_data[0].data[0] = rdp_client->settings->remote_app;
|
plugin_data[0].data[0] = settings->remote_app;
|
||||||
plugin_data[0].data[1] = rdp_client->settings->remote_app_dir;
|
plugin_data[0].data[1] = settings->remote_app_dir;
|
||||||
plugin_data[0].data[2] = rdp_client->settings->remote_app_args;
|
plugin_data[0].data[2] = settings->remote_app_args;
|
||||||
plugin_data[0].data[3] = NULL;
|
plugin_data[0].data[3] = NULL;
|
||||||
|
|
||||||
plugin_data[1].size = 0;
|
plugin_data[1].size = 0;
|
||||||
@ -314,9 +314,9 @@ BOOL rdp_freerdp_pre_connect(freerdp* instance) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* Load SVC plugin instances for all static channels */
|
/* Load SVC plugin instances for all static channels */
|
||||||
if (rdp_client->settings->svc_names != NULL) {
|
if (settings->svc_names != NULL) {
|
||||||
|
|
||||||
char** current = rdp_client->settings->svc_names;
|
char** current = settings->svc_names;
|
||||||
do {
|
do {
|
||||||
|
|
||||||
guac_rdp_svc* svc = guac_rdp_alloc_svc(client, *current);
|
guac_rdp_svc* svc = guac_rdp_alloc_svc(client, *current);
|
||||||
@ -691,9 +691,27 @@ static int rdp_guac_client_wait_for_messages(guac_client* client,
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void* guac_rdp_client_thread(void* data) {
|
/**
|
||||||
|
* Connects to an RDP server as described by the guac_rdp_settings structure
|
||||||
|
* associated with the given client, allocating and freeing all objects
|
||||||
|
* directly related to the RDP connection. It is expected that all objects
|
||||||
|
* which are independent of FreeRDP's state (the clipboard, display update
|
||||||
|
* management, etc.) will already be allocated and associated with the
|
||||||
|
* guac_rdp_client associated with the given guac_client. This function blocks
|
||||||
|
* for the duration of the RDP session, returning only after the session has
|
||||||
|
* completely disconnected.
|
||||||
|
*
|
||||||
|
* @param client
|
||||||
|
* The guac_client associated with the RDP settings describing the
|
||||||
|
* connection that should be established.
|
||||||
|
*
|
||||||
|
* @return
|
||||||
|
* Zero if the connection successfully terminated and a reconnect is
|
||||||
|
* desired, non-zero if an error occurs or the connection was disconnected
|
||||||
|
* and a reconnect is NOT desired.
|
||||||
|
*/
|
||||||
|
static int guac_rdp_handle_connection(guac_client* client) {
|
||||||
|
|
||||||
guac_client* client = (guac_client*) data;
|
|
||||||
guac_rdp_client* rdp_client = (guac_rdp_client*) client->data;
|
guac_rdp_client* rdp_client = (guac_rdp_client*) client->data;
|
||||||
guac_rdp_settings* settings = rdp_client->settings;
|
guac_rdp_settings* settings = rdp_client->settings;
|
||||||
|
|
||||||
@ -715,6 +733,9 @@ void* guac_rdp_client_thread(void* data) {
|
|||||||
|
|
||||||
rdp_client->current_surface = rdp_client->display->default_surface;
|
rdp_client->current_surface = rdp_client->display->default_surface;
|
||||||
|
|
||||||
|
rdp_client->requested_clipboard_format = CB_FORMAT_TEXT;
|
||||||
|
rdp_client->available_svc = guac_common_list_alloc();
|
||||||
|
|
||||||
#ifdef HAVE_FREERDP_CHANNELS_GLOBAL_INIT
|
#ifdef HAVE_FREERDP_CHANNELS_GLOBAL_INIT
|
||||||
freerdp_channels_global_init();
|
freerdp_channels_global_init();
|
||||||
#endif
|
#endif
|
||||||
@ -750,7 +771,7 @@ void* guac_rdp_client_thread(void* data) {
|
|||||||
|
|
||||||
/* Abort if username is missing */
|
/* Abort if username is missing */
|
||||||
if (settings->sftp_username == NULL)
|
if (settings->sftp_username == NULL)
|
||||||
return NULL;
|
return 1;
|
||||||
|
|
||||||
guac_client_log(client, GUAC_LOG_DEBUG,
|
guac_client_log(client, GUAC_LOG_DEBUG,
|
||||||
"Connecting via SSH for SFTP filesystem access.");
|
"Connecting via SSH for SFTP filesystem access.");
|
||||||
@ -769,7 +790,7 @@ void* guac_rdp_client_thread(void* data) {
|
|||||||
settings->sftp_private_key,
|
settings->sftp_private_key,
|
||||||
settings->sftp_passphrase)) {
|
settings->sftp_passphrase)) {
|
||||||
guac_common_ssh_destroy_user(rdp_client->sftp_user);
|
guac_common_ssh_destroy_user(rdp_client->sftp_user);
|
||||||
return NULL;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
@ -794,7 +815,7 @@ void* guac_rdp_client_thread(void* data) {
|
|||||||
if (rdp_client->sftp_session == NULL) {
|
if (rdp_client->sftp_session == NULL) {
|
||||||
/* Already aborted within guac_common_ssh_create_session() */
|
/* Already aborted within guac_common_ssh_create_session() */
|
||||||
guac_common_ssh_destroy_user(rdp_client->sftp_user);
|
guac_common_ssh_destroy_user(rdp_client->sftp_user);
|
||||||
return NULL;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Load and expose filesystem */
|
/* Load and expose filesystem */
|
||||||
@ -811,7 +832,7 @@ void* guac_rdp_client_thread(void* data) {
|
|||||||
if (rdp_client->sftp_filesystem == NULL) {
|
if (rdp_client->sftp_filesystem == NULL) {
|
||||||
guac_common_ssh_destroy_session(rdp_client->sftp_session);
|
guac_common_ssh_destroy_session(rdp_client->sftp_session);
|
||||||
guac_common_ssh_destroy_user(rdp_client->sftp_user);
|
guac_common_ssh_destroy_user(rdp_client->sftp_user);
|
||||||
return NULL;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
guac_client_log(client, GUAC_LOG_DEBUG,
|
guac_client_log(client, GUAC_LOG_DEBUG,
|
||||||
@ -833,7 +854,7 @@ void* guac_rdp_client_thread(void* data) {
|
|||||||
if (!freerdp_connect(rdp_inst)) {
|
if (!freerdp_connect(rdp_inst)) {
|
||||||
guac_client_abort(client, GUAC_PROTOCOL_STATUS_UPSTREAM_ERROR,
|
guac_client_abort(client, GUAC_PROTOCOL_STATUS_UPSTREAM_ERROR,
|
||||||
"Error connecting to RDP server");
|
"Error connecting to RDP server");
|
||||||
return NULL;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Connection complete */
|
/* Connection complete */
|
||||||
@ -842,15 +863,17 @@ void* guac_rdp_client_thread(void* data) {
|
|||||||
|
|
||||||
guac_timestamp last_frame_end = guac_timestamp_current();
|
guac_timestamp last_frame_end = guac_timestamp_current();
|
||||||
|
|
||||||
/* Handle messages from RDP server while client is running */
|
/* Signal that reconnect has been completed */
|
||||||
while (client->state == GUAC_CLIENT_RUNNING) {
|
guac_rdp_disp_reconnect_complete(rdp_client->disp);
|
||||||
|
|
||||||
|
/* Handle messages from RDP server while client is running */
|
||||||
|
while (client->state == GUAC_CLIENT_RUNNING
|
||||||
|
&& !guac_rdp_disp_reconnect_needed(rdp_client->disp)) {
|
||||||
|
|
||||||
#ifdef HAVE_FREERDP_DISPLAY_UPDATE_SUPPORT
|
|
||||||
/* Update remote display size */
|
/* Update remote display size */
|
||||||
pthread_mutex_lock(&(rdp_client->rdp_lock));
|
pthread_mutex_lock(&(rdp_client->rdp_lock));
|
||||||
guac_rdp_disp_update_size(rdp_client->disp, rdp_inst->context);
|
guac_rdp_disp_update_size(rdp_client->disp, settings, rdp_inst);
|
||||||
pthread_mutex_unlock(&(rdp_client->rdp_lock));
|
pthread_mutex_unlock(&(rdp_client->rdp_lock));
|
||||||
#endif
|
|
||||||
|
|
||||||
/* Wait for data and construct a reasonable frame */
|
/* Wait for data and construct a reasonable frame */
|
||||||
int wait_result = rdp_guac_client_wait_for_messages(client,
|
int wait_result = rdp_guac_client_wait_for_messages(client,
|
||||||
@ -873,7 +896,7 @@ void* guac_rdp_client_thread(void* data) {
|
|||||||
guac_client_log(client, GUAC_LOG_DEBUG,
|
guac_client_log(client, GUAC_LOG_DEBUG,
|
||||||
"Error handling RDP file descriptors");
|
"Error handling RDP file descriptors");
|
||||||
pthread_mutex_unlock(&(rdp_client->rdp_lock));
|
pthread_mutex_unlock(&(rdp_client->rdp_lock));
|
||||||
return NULL;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Check channel fds */
|
/* Check channel fds */
|
||||||
@ -881,7 +904,7 @@ void* guac_rdp_client_thread(void* data) {
|
|||||||
guac_client_log(client, GUAC_LOG_DEBUG,
|
guac_client_log(client, GUAC_LOG_DEBUG,
|
||||||
"Error handling RDP channel file descriptors");
|
"Error handling RDP channel file descriptors");
|
||||||
pthread_mutex_unlock(&(rdp_client->rdp_lock));
|
pthread_mutex_unlock(&(rdp_client->rdp_lock));
|
||||||
return NULL;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Check for channel events */
|
/* Check for channel events */
|
||||||
@ -910,7 +933,7 @@ void* guac_rdp_client_thread(void* data) {
|
|||||||
guac_client_log(client, GUAC_LOG_INFO,
|
guac_client_log(client, GUAC_LOG_INFO,
|
||||||
"RDP server closed connection");
|
"RDP server closed connection");
|
||||||
pthread_mutex_unlock(&(rdp_client->rdp_lock));
|
pthread_mutex_unlock(&(rdp_client->rdp_lock));
|
||||||
return NULL;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
pthread_mutex_unlock(&(rdp_client->rdp_lock));
|
pthread_mutex_unlock(&(rdp_client->rdp_lock));
|
||||||
@ -955,6 +978,62 @@ void* guac_rdp_client_thread(void* data) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
guac_client_log(client, GUAC_LOG_INFO, "Internal RDP client disconnected");
|
guac_client_log(client, GUAC_LOG_INFO, "Internal RDP client disconnected");
|
||||||
|
|
||||||
|
pthread_mutex_lock(&(rdp_client->rdp_lock));
|
||||||
|
|
||||||
|
/* Clean up RDP client */
|
||||||
|
freerdp_channels_close(channels, rdp_inst);
|
||||||
|
freerdp_channels_free(channels);
|
||||||
|
freerdp_disconnect(rdp_inst);
|
||||||
|
freerdp_clrconv_free(((rdp_freerdp_context*) rdp_inst->context)->clrconv);
|
||||||
|
cache_free(rdp_inst->context->cache);
|
||||||
|
freerdp_free(rdp_inst);
|
||||||
|
|
||||||
|
/* Clean up filesystem, if allocated */
|
||||||
|
if (rdp_client->filesystem != NULL)
|
||||||
|
guac_rdp_fs_free(rdp_client->filesystem);
|
||||||
|
|
||||||
|
#ifdef ENABLE_COMMON_SSH
|
||||||
|
/* Free SFTP filesystem, if loaded */
|
||||||
|
if (rdp_client->sftp_filesystem)
|
||||||
|
guac_common_ssh_destroy_sftp_filesystem(rdp_client->sftp_filesystem);
|
||||||
|
|
||||||
|
/* Free SFTP session */
|
||||||
|
if (rdp_client->sftp_session)
|
||||||
|
guac_common_ssh_destroy_session(rdp_client->sftp_session);
|
||||||
|
|
||||||
|
/* Free SFTP user */
|
||||||
|
if (rdp_client->sftp_user)
|
||||||
|
guac_common_ssh_destroy_user(rdp_client->sftp_user);
|
||||||
|
|
||||||
|
guac_common_ssh_uninit();
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* Free SVC list */
|
||||||
|
guac_common_list_free(rdp_client->available_svc);
|
||||||
|
|
||||||
|
/* Free display */
|
||||||
|
guac_common_display_free(rdp_client->display);
|
||||||
|
|
||||||
|
/* Mark FreeRDP instance as freed */
|
||||||
|
rdp_client->rdp_inst = NULL;
|
||||||
|
|
||||||
|
pthread_mutex_unlock(&(rdp_client->rdp_lock));
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
void* guac_rdp_client_thread(void* data) {
|
||||||
|
|
||||||
|
guac_client* client = (guac_client*) data;
|
||||||
|
|
||||||
|
while (client->state == GUAC_CLIENT_RUNNING) {
|
||||||
|
|
||||||
|
if (guac_rdp_handle_connection(client))
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -29,6 +29,7 @@
|
|||||||
#include "guac_display.h"
|
#include "guac_display.h"
|
||||||
#include "guac_surface.h"
|
#include "guac_surface.h"
|
||||||
#include "guac_list.h"
|
#include "guac_list.h"
|
||||||
|
#include "rdp_disp.h"
|
||||||
#include "rdp_fs.h"
|
#include "rdp_fs.h"
|
||||||
#include "rdp_keymap.h"
|
#include "rdp_keymap.h"
|
||||||
#include "rdp_settings.h"
|
#include "rdp_settings.h"
|
||||||
@ -44,10 +45,6 @@
|
|||||||
#include "guac_ssh_user.h"
|
#include "guac_ssh_user.h"
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifdef HAVE_FREERDP_DISPLAY_UPDATE_SUPPORT
|
|
||||||
#include "rdp_disp.h"
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#include <pthread.h>
|
#include <pthread.h>
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
|
|
||||||
@ -148,12 +145,10 @@ typedef struct guac_rdp_client {
|
|||||||
guac_common_ssh_sftp_filesystem* sftp_filesystem;
|
guac_common_ssh_sftp_filesystem* sftp_filesystem;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifdef HAVE_FREERDP_DISPLAY_UPDATE_SUPPORT
|
|
||||||
/**
|
/**
|
||||||
* Display size update module.
|
* Display size update module.
|
||||||
*/
|
*/
|
||||||
guac_rdp_disp* disp;
|
guac_rdp_disp* disp;
|
||||||
#endif
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* List of all available static virtual channels.
|
* List of all available static virtual channels.
|
||||||
@ -161,7 +156,9 @@ typedef struct guac_rdp_client {
|
|||||||
guac_common_list* available_svc;
|
guac_common_list* available_svc;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Lock which is locked and unlocked for each RDP message.
|
* Lock which is locked and unlocked for each RDP message, and for each
|
||||||
|
* part of the RDP client instance which may be dynamically freed and
|
||||||
|
* reallocated during reconnection.
|
||||||
*/
|
*/
|
||||||
pthread_mutex_t rdp_lock;
|
pthread_mutex_t rdp_lock;
|
||||||
|
|
||||||
|
@ -24,23 +24,30 @@
|
|||||||
#include "client.h"
|
#include "client.h"
|
||||||
#include "rdp.h"
|
#include "rdp.h"
|
||||||
#include "rdp_disp.h"
|
#include "rdp_disp.h"
|
||||||
|
#include "rdp_settings.h"
|
||||||
|
|
||||||
#include <freerdp/freerdp.h>
|
#include <freerdp/freerdp.h>
|
||||||
#include <freerdp/client/disp.h>
|
|
||||||
#include <guacamole/client.h>
|
#include <guacamole/client.h>
|
||||||
#include <guacamole/timestamp.h>
|
#include <guacamole/timestamp.h>
|
||||||
|
|
||||||
|
#ifdef HAVE_FREERDP_CLIENT_DISP_H
|
||||||
|
#include <freerdp/client/disp.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
guac_rdp_disp* guac_rdp_disp_alloc() {
|
guac_rdp_disp* guac_rdp_disp_alloc() {
|
||||||
|
|
||||||
guac_rdp_disp* disp = malloc(sizeof(guac_rdp_disp));
|
guac_rdp_disp* disp = malloc(sizeof(guac_rdp_disp));
|
||||||
|
|
||||||
|
#ifdef HAVE_FREERDP_DISPLAY_UPDATE_SUPPORT
|
||||||
/* Not yet connected */
|
/* Not yet connected */
|
||||||
disp->disp = NULL;
|
disp->disp = NULL;
|
||||||
|
#endif
|
||||||
|
|
||||||
/* No requests have been made */
|
/* No requests have been made */
|
||||||
disp->last_request = 0;
|
disp->last_request = guac_timestamp_current();
|
||||||
disp->requested_width = 0;
|
disp->requested_width = 0;
|
||||||
disp->requested_height = 0;
|
disp->requested_height = 0;
|
||||||
|
disp->reconnect_needed = 0;
|
||||||
|
|
||||||
return disp;
|
return disp;
|
||||||
|
|
||||||
@ -52,6 +59,7 @@ void guac_rdp_disp_free(guac_rdp_disp* disp) {
|
|||||||
|
|
||||||
void guac_rdp_disp_load_plugin(rdpContext* context) {
|
void guac_rdp_disp_load_plugin(rdpContext* context) {
|
||||||
|
|
||||||
|
#ifdef HAVE_FREERDP_DISPLAY_UPDATE_SUPPORT
|
||||||
#ifdef HAVE_RDPSETTINGS_SUPPORTDISPLAYCONTROL
|
#ifdef HAVE_RDPSETTINGS_SUPPORTDISPLAYCONTROL
|
||||||
context->settings->SupportDisplayControl = TRUE;
|
context->settings->SupportDisplayControl = TRUE;
|
||||||
#endif
|
#endif
|
||||||
@ -62,12 +70,15 @@ void guac_rdp_disp_load_plugin(rdpContext* context) {
|
|||||||
args->argv = malloc(sizeof(char**) * 1);
|
args->argv = malloc(sizeof(char**) * 1);
|
||||||
args->argv[0] = strdup("disp");
|
args->argv[0] = strdup("disp");
|
||||||
freerdp_dynamic_channel_collection_add(context->settings, args);
|
freerdp_dynamic_channel_collection_add(context->settings, args);
|
||||||
|
#endif
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#ifdef HAVE_FREERDP_DISPLAY_UPDATE_SUPPORT
|
||||||
void guac_rdp_disp_connect(guac_rdp_disp* guac_disp, DispClientContext* disp) {
|
void guac_rdp_disp_connect(guac_rdp_disp* guac_disp, DispClientContext* disp) {
|
||||||
guac_disp->disp = disp;
|
guac_disp->disp = disp;
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Fits a given dimension within the allowed bounds for Display Update
|
* Fits a given dimension within the allowed bounds for Display Update
|
||||||
@ -111,8 +122,8 @@ static void guac_rdp_disp_fit(int* a, int* b) {
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void guac_rdp_disp_set_size(guac_rdp_disp* disp, rdpContext* context,
|
void guac_rdp_disp_set_size(guac_rdp_disp* disp, guac_rdp_settings* settings,
|
||||||
int width, int height) {
|
freerdp* rdp_inst, int width, int height) {
|
||||||
|
|
||||||
/* Fit width within bounds, adjusting height to maintain aspect ratio */
|
/* Fit width within bounds, adjusting height to maintain aspect ratio */
|
||||||
guac_rdp_disp_fit(&width, &height);
|
guac_rdp_disp_fit(&width, &height);
|
||||||
@ -129,52 +140,74 @@ void guac_rdp_disp_set_size(guac_rdp_disp* disp, rdpContext* context,
|
|||||||
disp->requested_height = height;
|
disp->requested_height = height;
|
||||||
|
|
||||||
/* Send display update notification if possible */
|
/* Send display update notification if possible */
|
||||||
guac_rdp_disp_update_size(disp, context);
|
guac_rdp_disp_update_size(disp, settings, rdp_inst);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void guac_rdp_disp_update_size(guac_rdp_disp* disp, rdpContext* context) {
|
void guac_rdp_disp_update_size(guac_rdp_disp* disp,
|
||||||
|
guac_rdp_settings* settings, freerdp* rdp_inst) {
|
||||||
guac_client* client = ((rdp_freerdp_context*) context)->client;
|
|
||||||
|
|
||||||
/* Send display update notification if display channel is connected */
|
|
||||||
if (disp->disp == NULL)
|
|
||||||
return;
|
|
||||||
|
|
||||||
int width = disp->requested_width;
|
int width = disp->requested_width;
|
||||||
int height = disp->requested_height;
|
int height = disp->requested_height;
|
||||||
|
|
||||||
DISPLAY_CONTROL_MONITOR_LAYOUT monitors[1] = {{
|
/* Do not update size if no requests have been received */
|
||||||
.Flags = 0x1, /* DISPLAYCONTROL_MONITOR_PRIMARY */
|
if (width == 0 || height == 0)
|
||||||
.Left = 0,
|
return;
|
||||||
.Top = 0,
|
|
||||||
.Width = width,
|
|
||||||
.Height = height,
|
|
||||||
.PhysicalWidth = 0,
|
|
||||||
.PhysicalHeight = 0,
|
|
||||||
.Orientation = 0,
|
|
||||||
.DesktopScaleFactor = 0,
|
|
||||||
.DeviceScaleFactor = 0
|
|
||||||
}};
|
|
||||||
|
|
||||||
guac_timestamp now = guac_timestamp_current();
|
guac_timestamp now = guac_timestamp_current();
|
||||||
|
|
||||||
/* Limit display update frequency */
|
/* Limit display update frequency */
|
||||||
if (disp->last_request != 0
|
if (now - disp->last_request <= GUAC_RDP_DISP_UPDATE_INTERVAL)
|
||||||
&& now - disp->last_request <= GUAC_RDP_DISP_UPDATE_INTERVAL)
|
|
||||||
return;
|
return;
|
||||||
|
|
||||||
/* Do NOT send requests unless the size will change */
|
/* Do NOT send requests unless the size will change */
|
||||||
if (width == guac_rdp_get_width(context->instance)
|
if (rdp_inst != NULL
|
||||||
&& height == guac_rdp_get_height(context->instance))
|
&& width == guac_rdp_get_width(rdp_inst)
|
||||||
|
&& height == guac_rdp_get_height(rdp_inst))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
guac_client_log(client, GUAC_LOG_DEBUG,
|
|
||||||
"Resizing remote display to %ix%i",
|
|
||||||
width, height);
|
|
||||||
|
|
||||||
disp->last_request = now;
|
disp->last_request = now;
|
||||||
disp->disp->SendMonitorLayout(disp->disp, 1, monitors);
|
|
||||||
|
if (settings->resize_method == GUAC_RESIZE_RECONNECT) {
|
||||||
|
|
||||||
|
/* Update settings with new dimensions */
|
||||||
|
settings->width = width;
|
||||||
|
settings->height = height;
|
||||||
|
|
||||||
|
/* Signal reconnect */
|
||||||
|
disp->reconnect_needed = 1;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
else if (settings->resize_method == GUAC_RESIZE_DISPLAY_UPDATE) {
|
||||||
|
#ifdef HAVE_FREERDP_DISPLAY_UPDATE_SUPPORT
|
||||||
|
DISPLAY_CONTROL_MONITOR_LAYOUT monitors[1] = {{
|
||||||
|
.Flags = 0x1, /* DISPLAYCONTROL_MONITOR_PRIMARY */
|
||||||
|
.Left = 0,
|
||||||
|
.Top = 0,
|
||||||
|
.Width = width,
|
||||||
|
.Height = height,
|
||||||
|
.PhysicalWidth = 0,
|
||||||
|
.PhysicalHeight = 0,
|
||||||
|
.Orientation = 0,
|
||||||
|
.DesktopScaleFactor = 0,
|
||||||
|
.DeviceScaleFactor = 0
|
||||||
|
}};
|
||||||
|
|
||||||
|
/* Send display update notification if display channel is connected */
|
||||||
|
if (disp->disp != NULL)
|
||||||
|
disp->disp->SendMonitorLayout(disp->disp, 1, monitors);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int guac_rdp_disp_reconnect_needed(guac_rdp_disp* disp) {
|
||||||
|
return disp->reconnect_needed;
|
||||||
|
}
|
||||||
|
|
||||||
|
void guac_rdp_disp_reconnect_complete(guac_rdp_disp* disp) {
|
||||||
|
disp->reconnect_needed = 0;
|
||||||
|
disp->last_request = guac_timestamp_current();
|
||||||
|
}
|
||||||
|
|
||||||
|
@ -23,9 +23,14 @@
|
|||||||
#ifndef GUAC_RDP_DISP_H
|
#ifndef GUAC_RDP_DISP_H
|
||||||
#define GUAC_RDP_DISP_H
|
#define GUAC_RDP_DISP_H
|
||||||
|
|
||||||
#include <freerdp/client/disp.h>
|
#include "rdp_settings.h"
|
||||||
|
|
||||||
#include <freerdp/freerdp.h>
|
#include <freerdp/freerdp.h>
|
||||||
|
|
||||||
|
#ifdef HAVE_FREERDP_CLIENT_DISP_H
|
||||||
|
#include <freerdp/client/disp.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The minimum value for width or height, in pixels.
|
* The minimum value for width or height, in pixels.
|
||||||
*/
|
*/
|
||||||
@ -47,10 +52,12 @@
|
|||||||
*/
|
*/
|
||||||
typedef struct guac_rdp_disp {
|
typedef struct guac_rdp_disp {
|
||||||
|
|
||||||
|
#ifdef HAVE_FREERDP_DISPLAY_UPDATE_SUPPORT
|
||||||
/**
|
/**
|
||||||
* Display control interface.
|
* Display control interface.
|
||||||
*/
|
*/
|
||||||
DispClientContext* disp;
|
DispClientContext* disp;
|
||||||
|
#endif
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The timestamp of the last display update request, or 0 if no request
|
* The timestamp of the last display update request, or 0 if no request
|
||||||
@ -68,6 +75,12 @@ typedef struct guac_rdp_disp {
|
|||||||
*/
|
*/
|
||||||
int requested_height;
|
int requested_height;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Whether the size has changed and the RDP connection must be closed and
|
||||||
|
* reestablished.
|
||||||
|
*/
|
||||||
|
int reconnect_needed;
|
||||||
|
|
||||||
} guac_rdp_disp;
|
} guac_rdp_disp;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -94,6 +107,7 @@ void guac_rdp_disp_free(guac_rdp_disp* disp);
|
|||||||
*/
|
*/
|
||||||
void guac_rdp_disp_load_plugin(rdpContext* context);
|
void guac_rdp_disp_load_plugin(rdpContext* context);
|
||||||
|
|
||||||
|
#ifdef HAVE_FREERDP_DISPLAY_UPDATE_SUPPORT
|
||||||
/**
|
/**
|
||||||
* Stores the given DispClientContext within the given guac_rdp_disp, such that
|
* Stores the given DispClientContext within the given guac_rdp_disp, such that
|
||||||
* display updates can be properly sent. Until this is called, changes to the
|
* display updates can be properly sent. Until this is called, changes to the
|
||||||
@ -105,6 +119,7 @@ void guac_rdp_disp_load_plugin(rdpContext* context);
|
|||||||
* display update channel.
|
* display update channel.
|
||||||
*/
|
*/
|
||||||
void guac_rdp_disp_connect(guac_rdp_disp* guac_disp, DispClientContext* disp);
|
void guac_rdp_disp_connect(guac_rdp_disp* guac_disp, DispClientContext* disp);
|
||||||
|
#endif
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Requests a display size update, which may then be sent immediately to the
|
* Requests a display size update, which may then be sent immediately to the
|
||||||
@ -113,30 +128,72 @@ void guac_rdp_disp_connect(guac_rdp_disp* guac_disp, DispClientContext* disp);
|
|||||||
* be automatically altered to comply with the restrictions imposed by the
|
* be automatically altered to comply with the restrictions imposed by the
|
||||||
* display update channel.
|
* display update channel.
|
||||||
*
|
*
|
||||||
* @param disp The display update module which should maintain the requested
|
* @param disp
|
||||||
* size, sending the corresponding display update request when
|
* The display update module which should maintain the requested size,
|
||||||
* appropriate.
|
* sending the corresponding display update request when appropriate.
|
||||||
* @param context The rdpContext associated with the active RDP session.
|
*
|
||||||
* @param width The desired display width, in pixels. Due to the restrictions
|
* @param settings
|
||||||
* of the RDP display update channel, this will be contrained to
|
* The RDP client settings associated with the current or pending RDP
|
||||||
* the range of 200 through 8192 inclusive, and rounded down to
|
* session. These settings will be automatically adjusted to match the new
|
||||||
* the nearest even number.
|
* screen size.
|
||||||
* @param height The desired display height, in pixels. Due to the restrictions
|
*
|
||||||
* of the RDP display update channel, this will be contrained to
|
* @param rdp_inst
|
||||||
* the range of 200 through 8192 inclusive.
|
* The FreeRDP instance associated with the current or pending RDP session,
|
||||||
|
* if any. If no RDP session is active, this should be NULL.
|
||||||
|
*
|
||||||
|
* @param width
|
||||||
|
* The desired display width, in pixels. Due to the restrictions of the RDP
|
||||||
|
* display update channel, this will be contrained to the range of 200
|
||||||
|
* through 8192 inclusive, and rounded down to the nearest even number.
|
||||||
|
*
|
||||||
|
* @param height
|
||||||
|
* The desired display height, in pixels. Due to the restrictions of the
|
||||||
|
* RDP display update channel, this will be contrained to the range of 200
|
||||||
|
* through 8192 inclusive.
|
||||||
*/
|
*/
|
||||||
void guac_rdp_disp_set_size(guac_rdp_disp* disp, rdpContext* context,
|
void guac_rdp_disp_set_size(guac_rdp_disp* disp, guac_rdp_settings* settings,
|
||||||
int width, int height);
|
freerdp* rdp_inst, int width, int height);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Sends an actual display update request to the RDP server based on previous
|
* Sends an actual display update request to the RDP server based on previous
|
||||||
* calls to guac_rdp_disp_set_size(). If an update was recently sent, the
|
* calls to guac_rdp_disp_set_size(). If an update was recently sent, the
|
||||||
* update may be delayed until a future call to this function.
|
* update may be delayed until a future call to this function. If the RDP
|
||||||
|
* session has not yet been established, the request will be delayed until the
|
||||||
|
* session exists.
|
||||||
*
|
*
|
||||||
* @param disp The display update module which should track the update request.
|
* @param disp
|
||||||
* @param context The rdpContext associated with the active RDP session.
|
* The display update module which should track the update request.
|
||||||
|
*
|
||||||
|
* @param settings
|
||||||
|
* The RDP client settings associated with the current or pending RDP
|
||||||
|
* session. These settings will be automatically adjusted to match the new
|
||||||
|
* screen size.
|
||||||
|
*
|
||||||
|
* @param rdp_inst
|
||||||
|
* The FreeRDP instance associated with the current or pending RDP session,
|
||||||
|
* if any. If no RDP session is active, this should be NULL.
|
||||||
*/
|
*/
|
||||||
void guac_rdp_disp_update_size(guac_rdp_disp* disp, rdpContext* context);
|
void guac_rdp_disp_update_size(guac_rdp_disp* disp,
|
||||||
|
guac_rdp_settings* settings, freerdp* rdp_inst);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Signals the given display update module that the requested reconnect has
|
||||||
|
* been performed.
|
||||||
|
*
|
||||||
|
* @param disp
|
||||||
|
* The display update module that should be signaled regarding the state
|
||||||
|
* of reconnection.
|
||||||
|
*/
|
||||||
|
void guac_rdp_disp_reconnect_complete(guac_rdp_disp* disp);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns whether a full RDP reconnect is required for display update changes
|
||||||
|
* to take effect.
|
||||||
|
*
|
||||||
|
* @return
|
||||||
|
* Non-zero if a reconnect is needed, zero otherwise.
|
||||||
|
*/
|
||||||
|
int guac_rdp_disp_reconnect_needed(guac_rdp_disp* disp);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
@ -92,6 +92,7 @@ const char* GUAC_RDP_CLIENT_ARGS[] = {
|
|||||||
"recording-path",
|
"recording-path",
|
||||||
"recording-name",
|
"recording-name",
|
||||||
"create-recording-path",
|
"create-recording-path",
|
||||||
|
"resize-method",
|
||||||
|
|
||||||
NULL
|
NULL
|
||||||
};
|
};
|
||||||
@ -374,6 +375,12 @@ enum RDP_ARGS_IDX {
|
|||||||
*/
|
*/
|
||||||
IDX_CREATE_RECORDING_PATH,
|
IDX_CREATE_RECORDING_PATH,
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The method to use to apply screen size changes requested by the user.
|
||||||
|
* Valid values are blank, "display-update", and "reconnect".
|
||||||
|
*/
|
||||||
|
IDX_RESIZE_METHOD,
|
||||||
|
|
||||||
RDP_ARGS_COUNT
|
RDP_ARGS_COUNT
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -710,6 +717,31 @@ guac_rdp_settings* guac_rdp_parse_args(guac_user* user,
|
|||||||
guac_user_parse_args_boolean(user, GUAC_RDP_CLIENT_ARGS, argv,
|
guac_user_parse_args_boolean(user, GUAC_RDP_CLIENT_ARGS, argv,
|
||||||
IDX_CREATE_RECORDING_PATH, 0);
|
IDX_CREATE_RECORDING_PATH, 0);
|
||||||
|
|
||||||
|
/* No resize method */
|
||||||
|
if (strcmp(argv[IDX_RESIZE_METHOD], "") == 0) {
|
||||||
|
guac_user_log(user, GUAC_LOG_INFO, "Resize method: none");
|
||||||
|
settings->resize_method = GUAC_RESIZE_NONE;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Resize method: "reconnect" */
|
||||||
|
else if (strcmp(argv[IDX_RESIZE_METHOD], "reconnect") == 0) {
|
||||||
|
guac_user_log(user, GUAC_LOG_INFO, "Resize method: reconnect");
|
||||||
|
settings->resize_method = GUAC_RESIZE_RECONNECT;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Resize method: "display-update" */
|
||||||
|
else if (strcmp(argv[IDX_RESIZE_METHOD], "display-update") == 0) {
|
||||||
|
guac_user_log(user, GUAC_LOG_INFO, "Resize method: display-update");
|
||||||
|
settings->resize_method = GUAC_RESIZE_DISPLAY_UPDATE;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Default to no resize method if invalid */
|
||||||
|
else {
|
||||||
|
guac_user_log(user, GUAC_LOG_INFO, "Resize method \"%s\" invalid. ",
|
||||||
|
"Defaulting to no resize method.", argv[IDX_RESIZE_METHOD]);
|
||||||
|
settings->resize_method = GUAC_RESIZE_NONE;
|
||||||
|
}
|
||||||
|
|
||||||
/* Success */
|
/* Success */
|
||||||
return settings;
|
return settings;
|
||||||
|
|
||||||
|
@ -88,6 +88,32 @@ typedef enum guac_rdp_security {
|
|||||||
|
|
||||||
} guac_rdp_security;
|
} guac_rdp_security;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* All supported combinations screen resize methods.
|
||||||
|
*/
|
||||||
|
typedef enum guac_rdp_resize_method {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Dynamic resizing of the display will not be attempted.
|
||||||
|
*/
|
||||||
|
GUAC_RESIZE_NONE,
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Dynamic resizing will be attempted through sending requests along the
|
||||||
|
* Display Update channel. This will only work with recent versions of
|
||||||
|
* Windows and relatively-recent versions of FreeRDP.
|
||||||
|
*/
|
||||||
|
GUAC_RESIZE_DISPLAY_UPDATE,
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Guacamole will automatically disconnect and reconnect to the RDP server
|
||||||
|
* whenever the screen size changes, requesting the new size during
|
||||||
|
* reconnect.
|
||||||
|
*/
|
||||||
|
GUAC_RESIZE_RECONNECT
|
||||||
|
|
||||||
|
} guac_rdp_resize_method;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* All settings supported by the Guacamole RDP client.
|
* All settings supported by the Guacamole RDP client.
|
||||||
*/
|
*/
|
||||||
@ -350,6 +376,11 @@ typedef struct guac_rdp_settings {
|
|||||||
*/
|
*/
|
||||||
int create_recording_path;
|
int create_recording_path;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The method to apply when the user's display changes size.
|
||||||
|
*/
|
||||||
|
guac_rdp_resize_method resize_method;
|
||||||
|
|
||||||
} guac_rdp_settings;
|
} guac_rdp_settings;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
Loading…
Reference in New Issue
Block a user