Compare commits

..

1 Commits

Author SHA1 Message Date
Virtually Nick
f906b14f9f GUACAMOLE-1741: Build Docker image against OpenSSL 1.1 for VNC compatibility 2023-03-15 10:38:57 -04:00
45 changed files with 168 additions and 1092 deletions

View File

@ -39,7 +39,7 @@ RUN apk add --no-cache \
libtool \ libtool \
libwebp-dev \ libwebp-dev \
make \ make \
openssl-dev \ openssl1.1-compat-dev \
pango-dev \ pango-dev \
pulseaudio-dev \ pulseaudio-dev \
util-linux-dev util-linux-dev

View File

@ -22,7 +22,6 @@
#include "common-ssh/user.h" #include "common-ssh/user.h"
#include <guacamole/client.h> #include <guacamole/client.h>
#include <guacamole/fips.h>
#include <libssh2.h> #include <libssh2.h>
#ifdef LIBSSH2_USES_GCRYPT #ifdef LIBSSH2_USES_GCRYPT
@ -47,20 +46,6 @@
GCRY_THREAD_OPTION_PTHREAD_IMPL; GCRY_THREAD_OPTION_PTHREAD_IMPL;
#endif #endif
/**
* A list of all key exchange algorithms that are both FIPS-compliant, and
* OpenSSL-supported. Note that "ext-info-c" is also included. While not a key
* exchange algorithm per se, it must be in the list to ensure that the server
* will send a SSH_MSG_EXT_INFO response, which is required to perform RSA key
* upgrades.
*/
#define FIPS_COMPLIANT_KEX_ALGORITHMS "diffie-hellman-group-exchange-sha256,ext-info-c"
/**
* A list of ciphers that are both FIPS-compliant, and OpenSSL-supported.
*/
#define FIPS_COMPLIANT_CIPHERS "aes128-ctr,aes192-ctr,aes256-ctr,aes128-cbc,aes192-cbc,aes256-cbc"
#ifdef OPENSSL_REQUIRES_THREADING_CALLBACKS #ifdef OPENSSL_REQUIRES_THREADING_CALLBACKS
/** /**
* Array of mutexes, used by OpenSSL. * Array of mutexes, used by OpenSSL.
@ -180,11 +165,9 @@ int guac_common_ssh_init(guac_client* client) {
CRYPTO_set_locking_callback(guac_common_ssh_openssl_locking_callback); CRYPTO_set_locking_callback(guac_common_ssh_openssl_locking_callback);
#endif #endif
#if OPENSSL_VERSION_NUMBER < 0x10100000L /* Init OpenSSL */
/* Init OpenSSL - only required for OpenSSL Versions < 1.1.0 */
SSL_library_init(); SSL_library_init();
ERR_load_crypto_strings(); ERR_load_crypto_strings();
#endif
/* Init libssh2 */ /* Init libssh2 */
libssh2_init(0); libssh2_init(0);
@ -501,17 +484,6 @@ guac_common_ssh_session* guac_common_ssh_create_session(guac_client* client,
return NULL; return NULL;
} }
/*
* If FIPS mode is enabled, prefer only FIPS-compatible algorithms and
* ciphers that are also supported by libssh2. For more info, see:
* https://csrc.nist.gov/CSRC/media/projects/cryptographic-module-validation-program/documents/security-policies/140sp2906.pdf
*/
if (guac_fips_enabled()) {
libssh2_session_method_pref(session, LIBSSH2_METHOD_KEX, FIPS_COMPLIANT_KEX_ALGORITHMS);
libssh2_session_method_pref(session, LIBSSH2_METHOD_CRYPT_CS, FIPS_COMPLIANT_CIPHERS);
libssh2_session_method_pref(session, LIBSSH2_METHOD_CRYPT_SC, FIPS_COMPLIANT_CIPHERS);
}
/* Perform handshake */ /* Perform handshake */
if (libssh2_session_handshake(session, fd)) { if (libssh2_session_handshake(session, fd)) {
guac_client_abort(client, GUAC_PROTOCOL_STATUS_UPSTREAM_ERROR, guac_client_abort(client, GUAC_PROTOCOL_STATUS_UPSTREAM_ERROR,

View File

@ -166,8 +166,6 @@ void guac_common_display_free(guac_common_display* display) {
void guac_common_display_dup(guac_common_display* display, guac_user* user, void guac_common_display_dup(guac_common_display* display, guac_user* user,
guac_socket* socket) { guac_socket* socket) {
guac_client* client = user->client;
pthread_mutex_lock(&display->_lock); pthread_mutex_lock(&display->_lock);
/* Sunchronize shared cursor */ /* Sunchronize shared cursor */
@ -180,9 +178,6 @@ void guac_common_display_dup(guac_common_display* display, guac_user* user,
guac_common_display_dup_layers(display->layers, user, socket); guac_common_display_dup_layers(display->layers, user, socket);
guac_common_display_dup_layers(display->buffers, user, socket); guac_common_display_dup_layers(display->buffers, user, socket);
/* Sends a sync instruction to mark the boundary of the first frame */
guac_protocol_send_sync(socket, client->last_sent_timestamp, 1);
pthread_mutex_unlock(&display->_lock); pthread_mutex_unlock(&display->_lock);
} }
@ -389,3 +384,4 @@ void guac_common_display_free_buffer(guac_common_display* display,
pthread_mutex_unlock(&display->_lock); pthread_mutex_unlock(&display->_lock);
} }

View File

@ -381,15 +381,10 @@ int main(int argc, char* argv[]) {
CRYPTO_set_locking_callback(guacd_openssl_locking_callback); CRYPTO_set_locking_callback(guacd_openssl_locking_callback);
#endif #endif
#if OPENSSL_VERSION_NUMBER < 0x10100000L /* Init SSL */
/* Init OpenSSL for OpenSSL Versions < 1.1.0 */
SSL_library_init(); SSL_library_init();
SSL_load_error_strings(); SSL_load_error_strings();
ssl_context = SSL_CTX_new(SSLv23_server_method()); ssl_context = SSL_CTX_new(SSLv23_server_method());
#else
/* Set up OpenSSL for OpenSSL Versions >= 1.1.0 */
ssl_context = SSL_CTX_new(TLS_server_method());
#endif
/* Load key */ /* Load key */
if (config->key_file != NULL) { if (config->key_file != NULL) {

View File

@ -213,7 +213,7 @@ int guacenc_avcodec_encode_video(guacenc_video* video, AVFrame* frame) {
#endif #endif
} }
AVCodecContext* guacenc_build_avcodeccontext(AVStream* stream, const AVCodec* codec, AVCodecContext* guacenc_build_avcodeccontext(AVStream* stream, AVCodec* codec,
int bitrate, int width, int height, int gop_size, int qmax, int qmin, int bitrate, int width, int height, int gop_size, int qmax, int qmin,
int pix_fmt, AVRational time_base) { int pix_fmt, AVRational time_base) {
@ -249,7 +249,7 @@ AVCodecContext* guacenc_build_avcodeccontext(AVStream* stream, const AVCodec* co
} }
int guacenc_open_avcodec(AVCodecContext *avcodec_context, int guacenc_open_avcodec(AVCodecContext *avcodec_context,
const AVCodec *codec, AVDictionary **options, AVCodec *codec, AVDictionary **options,
AVStream* stream) { AVStream* stream) {
int ret = avcodec_open2(avcodec_context, codec, options); int ret = avcodec_open2(avcodec_context, codec, options);

View File

@ -128,7 +128,7 @@ int guacenc_avcodec_encode_video(guacenc_video* video, AVFrame* frame);
* The pointer to the configured AVCodecContext. * The pointer to the configured AVCodecContext.
* *
*/ */
AVCodecContext* guacenc_build_avcodeccontext(AVStream* stream, const AVCodec* codec, AVCodecContext* guacenc_build_avcodeccontext(AVStream* stream, AVCodec* codec,
int bitrate, int width, int height, int gop_size, int qmax, int qmin, int bitrate, int width, int height, int gop_size, int qmax, int qmin,
int pix_fmt, AVRational time_base); int pix_fmt, AVRational time_base);
@ -158,7 +158,7 @@ AVCodecContext* guacenc_build_avcodeccontext(AVStream* stream, const AVCodec* co
* Zero on success, a negative value on error. * Zero on success, a negative value on error.
*/ */
int guacenc_open_avcodec(AVCodecContext *avcodec_context, int guacenc_open_avcodec(AVCodecContext *avcodec_context,
const AVCodec *codec, AVDictionary **options, AVCodec *codec, AVDictionary **options,
AVStream* stream); AVStream* stream);
#endif #endif

View File

@ -47,7 +47,7 @@
guacenc_video* guacenc_video_alloc(const char* path, const char* codec_name, guacenc_video* guacenc_video_alloc(const char* path, const char* codec_name,
int width, int height, int bitrate) { int width, int height, int bitrate) {
const AVOutputFormat *container_format; AVOutputFormat *container_format;
AVFormatContext *container_format_context; AVFormatContext *container_format_context;
AVStream *video_stream; AVStream *video_stream;
int ret; int ret;
@ -63,7 +63,7 @@ guacenc_video* guacenc_video_alloc(const char* path, const char* codec_name,
container_format = container_format_context->oformat; container_format = container_format_context->oformat;
/* Pull codec based on name */ /* Pull codec based on name */
const AVCodec* codec = avcodec_find_encoder_by_name(codec_name); AVCodec* codec = avcodec_find_encoder_by_name(codec_name);
if (codec == NULL) { if (codec == NULL) {
guacenc_log(GUAC_LOG_ERROR, "Failed to locate codec \"%s\".", guacenc_log(GUAC_LOG_ERROR, "Failed to locate codec \"%s\".",
codec_name); codec_name);

View File

@ -44,7 +44,6 @@ libguacinc_HEADERS = \
guacamole/client-types.h \ guacamole/client-types.h \
guacamole/error.h \ guacamole/error.h \
guacamole/error-types.h \ guacamole/error-types.h \
guacamole/fips.h \
guacamole/hash.h \ guacamole/hash.h \
guacamole/layer.h \ guacamole/layer.h \
guacamole/layer-types.h \ guacamole/layer-types.h \
@ -94,7 +93,6 @@ libguac_la_SOURCES = \
encode-jpeg.c \ encode-jpeg.c \
encode-png.c \ encode-png.c \
error.c \ error.c \
fips.c \
hash.c \ hash.c \
id.c \ id.c \
palette.c \ palette.c \
@ -102,7 +100,7 @@ libguac_la_SOURCES = \
pool.c \ pool.c \
protocol.c \ protocol.c \
raw_encoder.c \ raw_encoder.c \
recording.c \ recording.c \
socket.c \ socket.c \
socket-broadcast.c \ socket-broadcast.c \
socket-fd.c \ socket-fd.c \

View File

@ -421,19 +421,15 @@ void* guac_client_for_user(guac_client* client, guac_user* user,
} }
int guac_client_end_frame(guac_client* client) { int guac_client_end_frame(guac_client* client) {
return guac_client_end_multiple_frames(client, 0);
}
int guac_client_end_multiple_frames(guac_client* client, int frames) {
/* Update and send timestamp */ /* Update and send timestamp */
client->last_sent_timestamp = guac_timestamp_current(); client->last_sent_timestamp = guac_timestamp_current();
/* Log received timestamp and calculated lag (at TRACE level only) */ /* Log received timestamp and calculated lag (at TRACE level only) */
guac_client_log(client, GUAC_LOG_TRACE, "Server completed " guac_client_log(client, GUAC_LOG_TRACE, "Server completed "
"frame %" PRIu64 "ms (%i logical frames)", client->last_sent_timestamp, frames); "frame %" PRIu64 "ms.", client->last_sent_timestamp);
return guac_protocol_send_sync(client->socket, client->last_sent_timestamp, frames); return guac_protocol_send_sync(client->socket, client->last_sent_timestamp);
} }

View File

@ -1,51 +0,0 @@
/*
* 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 "config.h"
#include "guacamole/fips.h"
/* If OpenSSL is available, include header for version numbers */
#ifdef ENABLE_SSL
#include <openssl/opensslv.h>
/* OpenSSL versions prior to 0.9.7e did not have FIPS support */
#if !defined(OPENSSL_VERSION_NUMBER) || (OPENSSL_VERSION_NUMBER < 0x00090705f)
#define GUAC_FIPS_ENABLED 0
/* OpenSSL 3+ uses EVP_default_properties_is_fips_enabled() */
#elif defined(OPENSSL_VERSION_MAJOR) && (OPENSSL_VERSION_MAJOR >= 3)
#include <openssl/evp.h>
#define GUAC_FIPS_ENABLED EVP_default_properties_is_fips_enabled(NULL)
/* For OpenSSL versions between 0.9.7e and 3.0, use FIPS_mode() */
#else
#include <openssl/crypto.h>
#define GUAC_FIPS_ENABLED FIPS_mode()
#endif
/* FIPS support does not exist if OpenSSL is not available. */
#else
#define GUAC_FIPS_ENABLED 0
#endif
int guac_fips_enabled() {
return GUAC_FIPS_ENABLED;
}

View File

@ -509,47 +509,18 @@ void* guac_client_for_user(guac_client* client, guac_user* user,
guac_user_callback* callback, void* data); guac_user_callback* callback, void* data);
/** /**
* Marks the end of the current frame by sending a "sync" instruction to all * Marks the end of the current frame by sending a "sync" instruction to
* connected users, where the number of input frames that were considered in * all connected users. This instruction will contain the current timestamp.
* creating this frame is either unknown or inapplicable. This instruction will * The last_sent_timestamp member of guac_client will be updated accordingly.
* contain the current timestamp. The last_sent_timestamp member of guac_client
* will be updated accordingly.
* *
* If an error occurs sending the instruction, a non-zero value is * If an error occurs sending the instruction, a non-zero value is
* returned, and guac_error is set appropriately. * returned, and guac_error is set appropriately.
* *
* @param client * @param client The guac_client which has finished a frame.
* The guac_client which has finished a frame. * @return Zero on success, non-zero on error.
*
* @return
* Zero on success, non-zero on error.
*/ */
int guac_client_end_frame(guac_client* client); int guac_client_end_frame(guac_client* client);
/**
* Marks the end of the current frame by sending a "sync" instruction to all
* connected users, where that frame may combine or otherwise represent the
* changes of an arbitrary number of input frames. This instruction will
* contain the current timestamp, as well as the number of frames that were
* considered in creating that frame. The last_sent_timestamp member of
* guac_client will be updated accordingly.
*
* If an error occurs sending the instruction, a non-zero value is
* returned, and guac_error is set appropriately.
*
* @param client
* The guac_client which has finished a frame.
*
* @param frames
* The number of distinct frames that were considered or combined when
* generating the current frame, or zero if the boundaries of relevant
* frames are unknown.
*
* @return
* Zero on success, non-zero on error.
*/
int guac_client_end_multiple_frames(guac_client* client, int frames);
/** /**
* Initializes the given guac_client using the initialization routine provided * Initializes the given guac_client using the initialization routine provided
* by the plugin corresponding to the named protocol. This will automatically * by the plugin corresponding to the named protocol. This will automatically

View File

@ -1,33 +0,0 @@
/*
* 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.
*/
#ifndef GUAC_FIPS_H
#define GUAC_FIPS_H
/**
* Returns a non-zero value if FIPS mode is enabled, or zero if FIPS mode
* is not enabled.
*
* @return
* A non-zero value if FIPS mode is enabled, or zero if FIPS mode is
* not enabled.
*/
int guac_fips_enabled();
#endif

View File

@ -384,22 +384,11 @@ int guac_protocol_send_select(guac_socket* socket, const char* protocol);
* If an error occurs sending the instruction, a non-zero value is * If an error occurs sending the instruction, a non-zero value is
* returned, and guac_error is set appropriately. * returned, and guac_error is set appropriately.
* *
* @param socket * @param socket The guac_socket connection to use.
* The guac_socket connection to use. * @param timestamp The current timestamp (in milliseconds).
* * @return Zero on success, non-zero on error.
* @param timestamp
* The current timestamp (in milliseconds).
*
* @param frames
* The number of distinct frames that were considered or combined when
* generating the frame terminated by this instruction, or zero if the
* boundaries of relevant frames are unknown.
*
* @return
* Zero on success, non-zero on error.
*/ */
int guac_protocol_send_sync(guac_socket* socket, guac_timestamp timestamp, int guac_protocol_send_sync(guac_socket* socket, guac_timestamp timestamp);
int frames);
/* OBJECT INSTRUCTIONS */ /* OBJECT INSTRUCTIONS */

View File

@ -1199,8 +1199,7 @@ int guac_protocol_send_start(guac_socket* socket, const guac_layer* layer,
} }
int guac_protocol_send_sync(guac_socket* socket, guac_timestamp timestamp, int guac_protocol_send_sync(guac_socket* socket, guac_timestamp timestamp) {
int frames) {
int ret_val; int ret_val;
@ -1208,8 +1207,6 @@ int guac_protocol_send_sync(guac_socket* socket, guac_timestamp timestamp,
ret_val = ret_val =
guac_socket_write_string(socket, "4.sync,") guac_socket_write_string(socket, "4.sync,")
|| __guac_socket_write_length_int(socket, timestamp) || __guac_socket_write_length_int(socket, timestamp)
|| guac_socket_write_string(socket, ",")
|| __guac_socket_write_length_int(socket, frames)
|| guac_socket_write_string(socket, ";"); || guac_socket_write_string(socket, ";");
guac_socket_instruction_end(socket); guac_socket_instruction_end(socket);

View File

@ -54,7 +54,7 @@ static void write_instructions(int fd) {
/* Write instructions */ /* Write instructions */
guac_protocol_send_name(socket, "a" UTF8_4 "b" UTF8_4 "c"); guac_protocol_send_name(socket, "a" UTF8_4 "b" UTF8_4 "c");
guac_protocol_send_sync(socket, 12345, 1); guac_protocol_send_sync(socket, 12345);
guac_socket_flush(socket); guac_socket_flush(socket);
/* Close and free socket */ /* Close and free socket */
@ -76,7 +76,7 @@ static void read_expected_instructions(int fd) {
char expected[] = char expected[] =
"4.name,11.a" UTF8_4 "b" UTF8_4 "c;" "4.name,11.a" UTF8_4 "b" UTF8_4 "c;"
"4.sync,5.12345,1.1;"; "4.sync,5.12345;";
int numread; int numread;
char buffer[1024]; char buffer[1024];

View File

@ -65,7 +65,7 @@ static void write_instructions(int fd) {
/* Write instructions */ /* Write instructions */
guac_protocol_send_name(nested_socket, "a" UTF8_4 "b" UTF8_4 "c"); guac_protocol_send_name(nested_socket, "a" UTF8_4 "b" UTF8_4 "c");
guac_protocol_send_sync(nested_socket, 12345, 1); guac_protocol_send_sync(nested_socket, 12345);
/* Close and free sockets */ /* Close and free sockets */
guac_socket_free(nested_socket); guac_socket_free(nested_socket);
@ -86,9 +86,9 @@ static void write_instructions(int fd) {
static void read_expected_instructions(int fd) { static void read_expected_instructions(int fd) {
char expected[] = char expected[] =
"4.nest,3.123,41." "4.nest,3.123,37."
"4.name,11.a" UTF8_4 "b" UTF8_4 "c;" "4.name,11.a" UTF8_4 "b" UTF8_4 "c;"
"4.sync,5.12345,1.1;" "4.sync,5.12345;"
";"; ";";
int numread; int numread;

View File

@ -121,39 +121,31 @@ int __guac_handle_sync(guac_user* user, int argc, char** argv) {
/* Calculate length of frame, including network and processing lag */ /* Calculate length of frame, including network and processing lag */
frame_duration = current - timestamp; frame_duration = current - timestamp;
/* Calculate processing lag portion of length of frame */ /* Update lag statistics if at least one frame has been rendered */
int frame_processing_lag = 0;
if (user->last_frame_duration != 0) { if (user->last_frame_duration != 0) {
/* Calculate lag using the previous frame as a baseline */ /* Calculate lag using the previous frame as a baseline */
frame_processing_lag = frame_duration - user->last_frame_duration; int processing_lag = frame_duration - user->last_frame_duration;
/* Adjust back to zero if cumulative error leads to a negative /* Adjust back to zero if cumulative error leads to a negative
* value */ * value */
if (frame_processing_lag < 0) if (processing_lag < 0)
frame_processing_lag = 0; processing_lag = 0;
user->processing_lag = processing_lag;
} }
/* Record baseline duration of frame by excluding lag (this is the /* Record baseline duration of frame by excluding lag */
* network round-trip time) */ user->last_frame_duration = frame_duration - user->processing_lag;
int estimated_rtt = frame_duration - frame_processing_lag;
user->last_frame_duration = estimated_rtt;
/* Calculate cumulative accumulated processing lag relative to server timeline */
int processing_lag = current - user->last_received_timestamp - estimated_rtt;
if (processing_lag < 0)
processing_lag = 0;
user->processing_lag = processing_lag;
} }
/* Log received timestamp and calculated lag (at TRACE level only) */ /* Log received timestamp and calculated lag (at TRACE level only) */
guac_user_log(user, GUAC_LOG_TRACE, guac_user_log(user, GUAC_LOG_TRACE,
"User confirmation of frame %" PRIu64 "ms received " "User confirmation of frame %" PRIu64 "ms received "
"at %" PRIu64 "ms (processing_lag=%ims, estimated_rtt=%ims)", "at %" PRIu64 "ms (processing_lag=%ims)",
timestamp, current, user->processing_lag, user->last_frame_duration); timestamp, current, user->processing_lag);
if (user->sync_handler) if (user->sync_handler)
return user->sync_handler(user, timestamp); return user->sync_handler(user, timestamp);

View File

@ -57,7 +57,6 @@ libguac_client_rdp_la_SOURCES = \
channels/rdpdr/rdpdr-printer.c \ channels/rdpdr/rdpdr-printer.c \
channels/rdpdr/rdpdr.c \ channels/rdpdr/rdpdr.c \
channels/rdpei.c \ channels/rdpei.c \
channels/rdpgfx.c \
channels/rdpsnd/rdpsnd-messages.c \ channels/rdpsnd/rdpsnd-messages.c \
channels/rdpsnd/rdpsnd.c \ channels/rdpsnd/rdpsnd.c \
client.c \ client.c \
@ -104,7 +103,6 @@ noinst_HEADERS = \
channels/rdpdr/rdpdr-printer.h \ channels/rdpdr/rdpdr-printer.h \
channels/rdpdr/rdpdr.h \ channels/rdpdr/rdpdr.h \
channels/rdpei.h \ channels/rdpei.h \
channels/rdpgfx.h \
channels/rdpsnd/rdpsnd-messages.h \ channels/rdpsnd/rdpsnd-messages.h \
channels/rdpsnd/rdpsnd.h \ channels/rdpsnd/rdpsnd.h \
client.h \ client.h \
@ -230,7 +228,6 @@ BUILT_SOURCES = \
rdp_keymaps = \ rdp_keymaps = \
$(srcdir)/keymaps/base.keymap \ $(srcdir)/keymaps/base.keymap \
$(srcdir)/keymaps/failsafe.keymap \ $(srcdir)/keymaps/failsafe.keymap \
$(srcdir)/keymaps/cs-cz-qwertz.keymap \
$(srcdir)/keymaps/de_de_qwertz.keymap \ $(srcdir)/keymaps/de_de_qwertz.keymap \
$(srcdir)/keymaps/de_ch_qwertz.keymap \ $(srcdir)/keymaps/de_ch_qwertz.keymap \
$(srcdir)/keymaps/en_gb_qwerty.keymap \ $(srcdir)/keymaps/en_gb_qwerty.keymap \
@ -238,7 +235,6 @@ rdp_keymaps = \
$(srcdir)/keymaps/es_es_qwerty.keymap \ $(srcdir)/keymaps/es_es_qwerty.keymap \
$(srcdir)/keymaps/es_latam_qwerty.keymap \ $(srcdir)/keymaps/es_latam_qwerty.keymap \
$(srcdir)/keymaps/fr_be_azerty.keymap \ $(srcdir)/keymaps/fr_be_azerty.keymap \
$(srcdir)/keymaps/fr_ca_qwerty.keymap \
$(srcdir)/keymaps/fr_ch_qwertz.keymap \ $(srcdir)/keymaps/fr_ch_qwertz.keymap \
$(srcdir)/keymaps/fr_fr_azerty.keymap \ $(srcdir)/keymaps/fr_fr_azerty.keymap \
$(srcdir)/keymaps/hu_hu_qwertz.keymap \ $(srcdir)/keymaps/hu_hu_qwertz.keymap \

View File

@ -149,7 +149,7 @@ BOOL guac_rdp_bitmap_setsurface(rdpContext* context, rdpBitmap* bitmap, BOOL pri
else { else {
/* Make sure that the received bitmap is not NULL before processing */ /* Make sure that the recieved bitmap is not NULL before processing */
if (bitmap == NULL) { if (bitmap == NULL) {
guac_client_log(client, GUAC_LOG_INFO, "NULL bitmap found in bitmap_setsurface instruction."); guac_client_log(client, GUAC_LOG_INFO, "NULL bitmap found in bitmap_setsurface instruction.");
return TRUE; return TRUE;

View File

@ -509,12 +509,12 @@ static UINT guac_rdp_cliprdr_format_data_response(CliprdrClientContext* cliprdr,
* @param context * @param context
* The rdpContext associated with the active RDP session. * The rdpContext associated with the active RDP session.
* *
* @param args * @param e
* Event-specific arguments, mainly the name of the channel, and a * Event-specific arguments, mainly the name of the channel, and a
* reference to the associated plugin loaded for that channel by FreeRDP. * reference to the associated plugin loaded for that channel by FreeRDP.
*/ */
static void guac_rdp_cliprdr_channel_connected(rdpContext* context, static void guac_rdp_cliprdr_channel_connected(rdpContext* context,
ChannelConnectedEventArgs* args) { ChannelConnectedEventArgs* e) {
guac_client* client = ((rdp_freerdp_context*) context)->client; guac_client* client = ((rdp_freerdp_context*) context)->client;
guac_rdp_client* rdp_client = (guac_rdp_client*) client->data; guac_rdp_client* rdp_client = (guac_rdp_client*) client->data;
@ -526,12 +526,12 @@ static void guac_rdp_cliprdr_channel_connected(rdpContext* context,
assert(clipboard != NULL); assert(clipboard != NULL);
/* Ignore connection event if it's not for the CLIPRDR channel */ /* Ignore connection event if it's not for the CLIPRDR channel */
if (strcmp(args->name, CLIPRDR_SVC_CHANNEL_NAME) != 0) if (strcmp(e->name, CLIPRDR_SVC_CHANNEL_NAME) != 0)
return; return;
/* The structure pointed to by pInterface is guaranteed to be a /* The structure pointed to by pInterface is guaranteed to be a
* CliprdrClientContext if the channel is CLIPRDR */ * CliprdrClientContext if the channel is CLIPRDR */
CliprdrClientContext* cliprdr = (CliprdrClientContext*) args->pInterface; CliprdrClientContext* cliprdr = (CliprdrClientContext*) e->pInterface;
/* Associate FreeRDP CLIPRDR context and its Guacamole counterpart with /* Associate FreeRDP CLIPRDR context and its Guacamole counterpart with
* eachother */ * eachother */
@ -562,12 +562,12 @@ static void guac_rdp_cliprdr_channel_connected(rdpContext* context,
* @param context * @param context
* The rdpContext associated with the active RDP session. * The rdpContext associated with the active RDP session.
* *
* @param args * @param e
* Event-specific arguments, mainly the name of the channel, and a * Event-specific arguments, mainly the name of the channel, and a
* reference to the associated plugin loaded for that channel by FreeRDP. * reference to the associated plugin loaded for that channel by FreeRDP.
*/ */
static void guac_rdp_cliprdr_channel_disconnected(rdpContext* context, static void guac_rdp_cliprdr_channel_disconnected(rdpContext* context,
ChannelDisconnectedEventArgs* args) { ChannelDisconnectedEventArgs* e) {
guac_client* client = ((rdp_freerdp_context*) context)->client; guac_client* client = ((rdp_freerdp_context*) context)->client;
guac_rdp_client* rdp_client = (guac_rdp_client*) client->data; guac_rdp_client* rdp_client = (guac_rdp_client*) client->data;
@ -579,7 +579,7 @@ static void guac_rdp_cliprdr_channel_disconnected(rdpContext* context,
assert(clipboard != NULL); assert(clipboard != NULL);
/* Ignore disconnection event if it's not for the CLIPRDR channel */ /* Ignore disconnection event if it's not for the CLIPRDR channel */
if (strcmp(args->name, CLIPRDR_SVC_CHANNEL_NAME) != 0) if (strcmp(e->name, CLIPRDR_SVC_CHANNEL_NAME) != 0)
return; return;
/* Channel is no longer connected */ /* Channel is no longer connected */

View File

@ -115,7 +115,7 @@ struct guac_rdp_common_svc {
guac_rdp_common_svc_receive_handler* _receive_handler; guac_rdp_common_svc_receive_handler* _receive_handler;
/** /**
* Handler which is involved when the SVC has been disconnected and is * Handler which is invokved when the SVC has been disconnected and is
* about to be freed. * about to be freed.
*/ */
guac_rdp_common_svc_terminate_handler* _terminate_handler; guac_rdp_common_svc_terminate_handler* _terminate_handler;

View File

@ -68,19 +68,19 @@ void guac_rdp_disp_free(guac_rdp_disp* disp) {
* @param context * @param context
* The rdpContext associated with the active RDP session. * The rdpContext associated with the active RDP session.
* *
* @param args * @param e
* Event-specific arguments, mainly the name of the channel, and a * Event-specific arguments, mainly the name of the channel, and a
* reference to the associated plugin loaded for that channel by FreeRDP. * reference to the associated plugin loaded for that channel by FreeRDP.
*/ */
static void guac_rdp_disp_channel_connected(rdpContext* context, static void guac_rdp_disp_channel_connected(rdpContext* context,
ChannelConnectedEventArgs* args) { ChannelConnectedEventArgs* e) {
guac_client* client = ((rdp_freerdp_context*) context)->client; guac_client* client = ((rdp_freerdp_context*) context)->client;
guac_rdp_client* rdp_client = (guac_rdp_client*) client->data; guac_rdp_client* rdp_client = (guac_rdp_client*) client->data;
guac_rdp_disp* guac_disp = rdp_client->disp; guac_rdp_disp* guac_disp = rdp_client->disp;
/* Ignore connection event if it's not for the Display Update channel */ /* Ignore connection event if it's not for the Display Update channel */
if (strcmp(args->name, DISP_DVC_CHANNEL_NAME) != 0) if (strcmp(e->name, DISP_DVC_CHANNEL_NAME) != 0)
return; return;
/* Init module with current display size */ /* Init module with current display size */
@ -89,7 +89,7 @@ static void guac_rdp_disp_channel_connected(rdpContext* context,
guac_rdp_get_height(context->instance)); guac_rdp_get_height(context->instance));
/* Store reference to the display update plugin once it's connected */ /* Store reference to the display update plugin once it's connected */
DispClientContext* disp = (DispClientContext*) args->pInterface; DispClientContext* disp = (DispClientContext*) e->pInterface;
guac_disp->disp = disp; guac_disp->disp = disp;
guac_client_log(client, GUAC_LOG_DEBUG, "Display update channel " guac_client_log(client, GUAC_LOG_DEBUG, "Display update channel "
@ -110,19 +110,19 @@ static void guac_rdp_disp_channel_connected(rdpContext* context,
* @param context * @param context
* The rdpContext associated with the active RDP session. * The rdpContext associated with the active RDP session.
* *
* @param args * @param e
* Event-specific arguments, mainly the name of the channel, and a * Event-specific arguments, mainly the name of the channel, and a
* reference to the associated plugin loaded for that channel by FreeRDP. * reference to the associated plugin loaded for that channel by FreeRDP.
*/ */
static void guac_rdp_disp_channel_disconnected(rdpContext* context, static void guac_rdp_disp_channel_disconnected(rdpContext* context,
ChannelDisconnectedEventArgs* args) { ChannelDisconnectedEventArgs* e) {
guac_client* client = ((rdp_freerdp_context*) context)->client; guac_client* client = ((rdp_freerdp_context*) context)->client;
guac_rdp_client* rdp_client = (guac_rdp_client*) client->data; guac_rdp_client* rdp_client = (guac_rdp_client*) client->data;
guac_rdp_disp* guac_disp = rdp_client->disp; guac_rdp_disp* guac_disp = rdp_client->disp;
/* Ignore disconnection event if it's not for the Display Update channel */ /* Ignore disconnection event if it's not for the Display Update channel */
if (strcmp(args->name, DISP_DVC_CHANNEL_NAME) != 0) if (strcmp(e->name, DISP_DVC_CHANNEL_NAME) != 0)
return; return;
/* Channel is no longer connected */ /* Channel is no longer connected */

View File

@ -109,7 +109,7 @@ void guac_rdp_disp_free(guac_rdp_disp* disp);
/** /**
* Adds FreeRDP's "disp" plugin to the list of dynamic virtual channel plugins * Adds FreeRDP's "disp" plugin to the list of dynamic virtual channel plugins
* to be loaded by FreeRDP's "drdynvc" plugin. The context of the plugin will * to be loaded by FreeRDP's "drdynvc" plugin. The context of the plugin will
* automatically be associated with the guac_rdp_disp instance pointed to by the * automatically be assicated with the guac_rdp_disp instance pointed to by the
* current guac_rdp_client. The plugin will only be loaded once the "drdynvc" * current guac_rdp_client. The plugin will only be loaded once the "drdynvc"
* plugin is loaded. The "disp" plugin ultimately adds support for the Display * plugin is loaded. The "disp" plugin ultimately adds support for the Display
* Update channel. * Update channel.

View File

@ -230,22 +230,22 @@ static UINT guac_rdp_rail_handshake_ex(RailClientContext* rail,
* @param context * @param context
* The rdpContext associated with the active RDP session. * The rdpContext associated with the active RDP session.
* *
* @param args * @param e
* Event-specific arguments, mainly the name of the channel, and a * Event-specific arguments, mainly the name of the channel, and a
* reference to the associated plugin loaded for that channel by FreeRDP. * reference to the associated plugin loaded for that channel by FreeRDP.
*/ */
static void guac_rdp_rail_channel_connected(rdpContext* context, static void guac_rdp_rail_channel_connected(rdpContext* context,
ChannelConnectedEventArgs* args) { ChannelConnectedEventArgs* e) {
guac_client* client = ((rdp_freerdp_context*) context)->client; guac_client* client = ((rdp_freerdp_context*) context)->client;
/* Ignore connection event if it's not for the RAIL channel */ /* Ignore connection event if it's not for the RAIL channel */
if (strcmp(args->name, RAIL_SVC_CHANNEL_NAME) != 0) if (strcmp(e->name, RAIL_SVC_CHANNEL_NAME) != 0)
return; return;
/* The structure pointed to by pInterface is guaranteed to be a /* The structure pointed to by pInterface is guaranteed to be a
* RailClientContext if the channel is RAIL */ * RailClientContext if the channel is RAIL */
RailClientContext* rail = (RailClientContext*) args->pInterface; RailClientContext* rail = (RailClientContext*) e->pInterface;
/* Init FreeRDP RAIL context, ensuring the guac_client can be accessed from /* Init FreeRDP RAIL context, ensuring the guac_client can be accessed from
* within any RAIL-specific callbacks */ * within any RAIL-specific callbacks */

View File

@ -66,23 +66,23 @@ void guac_rdp_rdpei_free(guac_rdp_rdpei* rdpei) {
* @param context * @param context
* The rdpContext associated with the active RDP session. * The rdpContext associated with the active RDP session.
* *
* @param args * @param e
* Event-specific arguments, mainly the name of the channel, and a * Event-specific arguments, mainly the name of the channel, and a
* reference to the associated plugin loaded for that channel by FreeRDP. * reference to the associated plugin loaded for that channel by FreeRDP.
*/ */
static void guac_rdp_rdpei_channel_connected(rdpContext* context, static void guac_rdp_rdpei_channel_connected(rdpContext* context,
ChannelConnectedEventArgs* args) { ChannelConnectedEventArgs* e) {
guac_client* client = ((rdp_freerdp_context*) context)->client; guac_client* client = ((rdp_freerdp_context*) context)->client;
guac_rdp_client* rdp_client = (guac_rdp_client*) client->data; guac_rdp_client* rdp_client = (guac_rdp_client*) client->data;
guac_rdp_rdpei* guac_rdpei = rdp_client->rdpei; guac_rdp_rdpei* guac_rdpei = rdp_client->rdpei;
/* Ignore connection event if it's not for the RDPEI channel */ /* Ignore connection event if it's not for the RDPEI channel */
if (strcmp(args->name, RDPEI_DVC_CHANNEL_NAME) != 0) if (strcmp(e->name, RDPEI_DVC_CHANNEL_NAME) != 0)
return; return;
/* Store reference to the RDPEI plugin once it's connected */ /* Store reference to the RDPEI plugin once it's connected */
RdpeiClientContext* rdpei = (RdpeiClientContext*) args->pInterface; RdpeiClientContext* rdpei = (RdpeiClientContext*) e->pInterface;
guac_rdpei->rdpei = rdpei; guac_rdpei->rdpei = rdpei;
/* Declare level of multi-touch support */ /* Declare level of multi-touch support */
@ -107,19 +107,19 @@ static void guac_rdp_rdpei_channel_connected(rdpContext* context,
* @param context * @param context
* The rdpContext associated with the active RDP session. * The rdpContext associated with the active RDP session.
* *
* @param args * @param e
* Event-specific arguments, mainly the name of the channel, and a * Event-specific arguments, mainly the name of the channel, and a
* reference to the associated plugin loaded for that channel by FreeRDP. * reference to the associated plugin loaded for that channel by FreeRDP.
*/ */
static void guac_rdp_rdpei_channel_disconnected(rdpContext* context, static void guac_rdp_rdpei_channel_disconnected(rdpContext* context,
ChannelDisconnectedEventArgs* args) { ChannelDisconnectedEventArgs* e) {
guac_client* client = ((rdp_freerdp_context*) context)->client; guac_client* client = ((rdp_freerdp_context*) context)->client;
guac_rdp_client* rdp_client = (guac_rdp_client*) client->data; guac_rdp_client* rdp_client = (guac_rdp_client*) client->data;
guac_rdp_rdpei* guac_rdpei = rdp_client->rdpei; guac_rdp_rdpei* guac_rdpei = rdp_client->rdpei;
/* Ignore disconnection event if it's not for the RDPEI channel */ /* Ignore disconnection event if it's not for the RDPEI channel */
if (strcmp(args->name, RDPEI_DVC_CHANNEL_NAME) != 0) if (strcmp(e->name, RDPEI_DVC_CHANNEL_NAME) != 0)
return; return;
/* Channel is no longer connected */ /* Channel is no longer connected */

View File

@ -110,7 +110,7 @@ void guac_rdp_rdpei_free(guac_rdp_rdpei* rdpei);
/** /**
* Adds FreeRDP's "rdpei" plugin to the list of dynamic virtual channel plugins * Adds FreeRDP's "rdpei" plugin to the list of dynamic virtual channel plugins
* to be loaded by FreeRDP's "drdynvc" plugin. The context of the plugin will * to be loaded by FreeRDP's "drdynvc" plugin. The context of the plugin will
* automatically be associated with the guac_rdp_rdpei instance pointed to by the * automatically be assicated with the guac_rdp_rdpei instance pointed to by the
* current guac_rdp_client. The plugin will only be loaded once the "drdynvc" * current guac_rdp_client. The plugin will only be loaded once the "drdynvc"
* plugin is loaded. The "rdpei" plugin ultimately adds support for multi-touch * plugin is loaded. The "rdpei" plugin ultimately adds support for multi-touch
* input via the RDPEI channel. * input via the RDPEI channel.

View File

@ -1,122 +0,0 @@
/*
* 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/rdpgfx.h"
#include "plugins/channels.h"
#include "rdp.h"
#include "settings.h"
#include <freerdp/client/rdpgfx.h>
#include <freerdp/freerdp.h>
#include <freerdp/gdi/gfx.h>
#include <freerdp/event.h>
#include <guacamole/client.h>
#include <stdlib.h>
#include <string.h>
/**
* Callback which associates handlers specific to Guacamole with the
* RdpgfxClientContext instance allocated by FreeRDP to deal with received
* RDPGFX (Graphics Pipeline) messages.
*
* This function is called whenever a channel connects via the PubSub event
* system within FreeRDP, but only has any effect if the connected channel is
* the RDPGFX channel. This specific callback is registered with the
* PubSub system of the relevant rdpContext when guac_rdp_rdpgfx_load_plugin() is
* called.
*
* @param context
* The rdpContext associated with the active RDP session.
*
* @param args
* Event-specific arguments, mainly the name of the channel, and a
* reference to the associated plugin loaded for that channel by FreeRDP.
*/
static void guac_rdp_rdpgfx_channel_connected(rdpContext* context,
ChannelConnectedEventArgs* args) {
guac_client* client = ((rdp_freerdp_context*) context)->client;
/* Ignore connection event if it's not for the RDPGFX channel */
if (strcmp(args->name, RDPGFX_DVC_CHANNEL_NAME) != 0)
return;
/* Init GDI-backed support for the Graphics Pipeline */
RdpgfxClientContext* rdpgfx = (RdpgfxClientContext*) args->pInterface;
rdpGdi* gdi = context->gdi;
if (!gdi_graphics_pipeline_init(gdi, rdpgfx))
guac_client_log(client, GUAC_LOG_WARNING, "Rendering backend for RDPGFX "
"channel could not be loaded. Graphics may not render at all!");
else
guac_client_log(client, GUAC_LOG_DEBUG, "RDPGFX channel will be used for "
"the RDP Graphics Pipeline Extension.");
}
/**
* Callback which handles any RDPGFX cleanup specific to Guacamole.
*
* This function is called whenever a channel disconnects via the PubSub event
* system within FreeRDP, but only has any effect if the disconnected channel
* is the RDPGFX channel. This specific callback is registered with the PubSub
* system of the relevant rdpContext when guac_rdp_rdpgfx_load_plugin() is
* called.
*
* @param context
* The rdpContext associated with the active RDP session.
*
* @param args
* Event-specific arguments, mainly the name of the channel, and a
* reference to the associated plugin loaded for that channel by FreeRDP.
*/
static void guac_rdp_rdpgfx_channel_disconnected(rdpContext* context,
ChannelDisconnectedEventArgs* args) {
guac_client* client = ((rdp_freerdp_context*) context)->client;
/* Ignore disconnection event if it's not for the RDPGFX channel */
if (strcmp(args->name, RDPGFX_DVC_CHANNEL_NAME) != 0)
return;
/* Un-init GDI-backed support for the Graphics Pipeline */
RdpgfxClientContext* rdpgfx = (RdpgfxClientContext*) args->pInterface;
rdpGdi* gdi = context->gdi;
gdi_graphics_pipeline_uninit(gdi, rdpgfx);
guac_client_log(client, GUAC_LOG_DEBUG, "RDPGFX channel support unloaded.");
}
void guac_rdp_rdpgfx_load_plugin(rdpContext* context) {
/* Subscribe to and handle channel connected events */
PubSub_SubscribeChannelConnected(context->pubSub,
(pChannelConnectedEventHandler) guac_rdp_rdpgfx_channel_connected);
/* Subscribe to and handle channel disconnected events */
PubSub_SubscribeChannelDisconnected(context->pubSub,
(pChannelDisconnectedEventHandler) guac_rdp_rdpgfx_channel_disconnected);
/* Add "rdpgfx" channel */
guac_freerdp_dynamic_channel_collection_add(context->settings, "rdpgfx", NULL);
}

View File

@ -1,49 +0,0 @@
/*
* 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.
*/
#ifndef GUAC_RDP_CHANNELS_RDPGFX_H
#define GUAC_RDP_CHANNELS_RDPGFX_H
#include "settings.h"
#include <freerdp/client/rdpgfx.h>
#include <freerdp/freerdp.h>
#include <guacamole/client.h>
/**
* Adds FreeRDP's "rdpgfx" plugin to the list of dynamic virtual channel plugins
* to be loaded by FreeRDP's "drdynvc" plugin. The context of the plugin will
* automatically be associated with the guac_rdp_rdpgfx instance pointed to by the
* current guac_rdp_client. The plugin will only be loaded once the "drdynvc"
* plugin is loaded. The "rdpgfx" plugin ultimately adds support for the RDP
* Graphics Pipeline Extension.
*
* If failures occur, messages noting the specifics of those failures will be
* logged.
*
* This MUST be called within the PreConnect callback of the freerdp instance
* for Graphics Pipeline support to be loaded.
*
* @param context
* The rdpContext associated with the active RDP session.
*/
void guac_rdp_rdpgfx_load_plugin(rdpContext* context);
#endif

View File

@ -30,7 +30,6 @@
#include <guacamole/stream.h> #include <guacamole/stream.h>
#include <guacamole/string.h> #include <guacamole/string.h>
#include <guacamole/user.h> #include <guacamole/user.h>
#include <winpr/file.h>
#include <winpr/nt.h> #include <winpr/nt.h>
#include <winpr/shell.h> #include <winpr/shell.h>

View File

@ -26,7 +26,6 @@
#include <cairo/cairo.h> #include <cairo/cairo.h>
#include <freerdp/freerdp.h> #include <freerdp/freerdp.h>
#include <freerdp/gdi/gdi.h>
#include <freerdp/graphics.h> #include <freerdp/graphics.h>
#include <freerdp/primary.h> #include <freerdp/primary.h>
#include <guacamole/client.h> #include <guacamole/client.h>
@ -248,7 +247,7 @@ BOOL guac_rdp_gdi_memblt(rdpContext* context, MEMBLT_ORDER* memblt) {
int x_src = memblt->nXSrc; int x_src = memblt->nXSrc;
int y_src = memblt->nYSrc; int y_src = memblt->nYSrc;
/* Make sure that the received bitmap is not NULL before processing */ /* Make sure that the recieved bitmap is not NULL before processing */
if (bitmap == NULL) { if (bitmap == NULL) {
guac_client_log(client, GUAC_LOG_INFO, "NULL bitmap found in memblt instruction."); guac_client_log(client, GUAC_LOG_INFO, "NULL bitmap found in memblt instruction.");
return TRUE; return TRUE;
@ -372,110 +371,9 @@ BOOL guac_rdp_gdi_set_bounds(rdpContext* context, const rdpBounds* bounds) {
} }
void guac_rdp_gdi_mark_frame(rdpContext* context, int starting) {
guac_client* client = ((rdp_freerdp_context*) context)->client;
guac_rdp_client* rdp_client = (guac_rdp_client*) client->data;
/* The server supports defining explicit frames */
rdp_client->frames_supported = 1;
/* A new frame is beginning */
if (starting) {
rdp_client->in_frame = 1;
return;
}
/* The current frame has ended */
guac_timestamp frame_end = guac_timestamp_current();
int time_elapsed = frame_end - client->last_sent_timestamp;
rdp_client->in_frame = 0;
/* A new frame has been received from the RDP server and processed */
rdp_client->frames_received++;
/* Flush a new frame if the client is ready for it */
if (time_elapsed >= guac_client_get_processing_lag(client)) {
guac_common_display_flush(rdp_client->display);
guac_client_end_multiple_frames(client, rdp_client->frames_received);
guac_socket_flush(client->socket);
rdp_client->frames_received = 0;
}
}
BOOL guac_rdp_gdi_frame_marker(rdpContext* context, const FRAME_MARKER_ORDER* frame_marker) {
guac_rdp_gdi_mark_frame(context, frame_marker->action == FRAME_START);
return TRUE;
}
BOOL guac_rdp_gdi_surface_frame_marker(rdpContext* context, const SURFACE_FRAME_MARKER* surface_frame_marker) {
guac_rdp_gdi_mark_frame(context, surface_frame_marker->frameAction == SURFACECMD_FRAMEACTION_END);
if (context->settings->FrameAcknowledge > 0)
IFCALL(context->update->SurfaceFrameAcknowledge, context,
surface_frame_marker->frameId);
return TRUE;
}
BOOL guac_rdp_gdi_begin_paint(rdpContext* context) {
guac_client* client = ((rdp_freerdp_context*) context)->client;
guac_rdp_client* rdp_client = (guac_rdp_client*) client->data;
/* Leverage BeginPaint handler to detect start of frame for RDPGFX channel */
if (rdp_client->settings->enable_gfx && rdp_client->frames_supported)
guac_rdp_gdi_mark_frame(context, 1);
return TRUE;
}
BOOL guac_rdp_gdi_end_paint(rdpContext* context) { BOOL guac_rdp_gdi_end_paint(rdpContext* context) {
/* IGNORE */
guac_client* client = ((rdp_freerdp_context*) context)->client;
guac_rdp_client* rdp_client = (guac_rdp_client*) client->data;
rdpGdi* gdi = context->gdi;
/* Ignore EndPaint handler unless needed to detect end of frame for RDPGFX
* channel */
if (!rdp_client->settings->enable_gfx)
return TRUE;
/* Ignore paint if GDI output is suppressed */
if (gdi->suppressOutput)
return TRUE;
/* Ignore paint if nothing has been done (empty rect) */
if (gdi->primary->hdc->hwnd->invalid->null)
return TRUE;
INT32 x = gdi->primary->hdc->hwnd->invalid->x;
INT32 y = gdi->primary->hdc->hwnd->invalid->y;
UINT32 w = gdi->primary->hdc->hwnd->invalid->w;
UINT32 h = gdi->primary->hdc->hwnd->invalid->h;
/* Create surface from image data */
cairo_surface_t* surface = cairo_image_surface_create_for_data(
gdi->primary_buffer + 4*x + y*gdi->stride,
CAIRO_FORMAT_RGB24, w, h, gdi->stride);
/* Send surface to buffer */
guac_common_surface_draw(rdp_client->display->default_surface, x, y, surface);
/* Free surface */
cairo_surface_destroy(surface);
/* Next frame */
if (gdi->inGfxFrame) {
guac_rdp_gdi_mark_frame(context, 0);
}
return TRUE; return TRUE;
} }
BOOL guac_rdp_gdi_desktop_resize(rdpContext* context) { BOOL guac_rdp_gdi_desktop_resize(rdpContext* context) {
@ -493,8 +391,7 @@ BOOL guac_rdp_gdi_desktop_resize(rdpContext* context) {
guac_rdp_get_width(context->instance), guac_rdp_get_width(context->instance),
guac_rdp_get_height(context->instance)); guac_rdp_get_height(context->instance));
return gdi_resize(context->gdi, guac_rdp_get_width(context->instance), return TRUE;
guac_rdp_get_height(context->instance));
} }

View File

@ -156,68 +156,8 @@ BOOL guac_rdp_gdi_opaquerect(rdpContext* context,
BOOL guac_rdp_gdi_set_bounds(rdpContext* context, const rdpBounds* bounds); BOOL guac_rdp_gdi_set_bounds(rdpContext* context, const rdpBounds* bounds);
/** /**
* Notifies the internal GDI implementation that a frame is either starting or * Handler called when a paint operation is complete. We don't actually
* ending. If the frame is ending and the connected client is ready to receive * use this, but FreeRDP requires it. Calling this function has no effect.
* a new frame, a new frame will be flushed to the client.
*
* @param context
* The rdpContext associated with the current RDP session.
*
* @param starting
* Non-zero if the frame in question is starting, zero if the frame is
* ending.
*/
void guac_rdp_gdi_mark_frame(rdpContext* context, int starting);
/**
* Handler called when a frame boundary is received from the RDP server in the
* form of a frame marker command. Each frame boundary may be the beginning or
* the end of a frame.
*
* @param context
* The rdpContext associated with the current RDP session.
*
* @param frame_marker
* The received frame marker.
*
* @return
* TRUE if successful, FALSE otherwise.
*/
BOOL guac_rdp_gdi_frame_marker(rdpContext* context, const FRAME_MARKER_ORDER* frame_marker);
/**
* Handler called when a frame boundary is received from the RDP server in the
* form of a surface frame marker. Each frame boundary may be the beginning or
* the end of a frame.
*
* @param context
* The rdpContext associated with the current RDP session.
*
* @param surface_frame_marker
* The received frame marker.
*
* @return
* TRUE if successful, FALSE otherwise.
*/
BOOL guac_rdp_gdi_surface_frame_marker(rdpContext* context, const SURFACE_FRAME_MARKER* surface_frame_marker);
/**
* Handler called when a paint operation is beginning. This function is
* expected to be called by the FreeRDP GDI implementation of RemoteFX when a
* new frame has started.
*
* @param context
* The rdpContext associated with the current RDP session.
*
* @return
* TRUE if successful, FALSE otherwise.
*/
BOOL guac_rdp_gdi_begin_paint(rdpContext* context);
/**
* Handler called when a paint operation is complete. This function is
* expected to be called by the FreeRDP GDI implementation of RemoteFX when a
* new frame has been completed.
* *
* @param context * @param context
* The rdpContext associated with the current RDP session. * The rdpContext associated with the current RDP session.

View File

@ -96,11 +96,11 @@ BOOL guac_rdp_glyph_new(rdpContext* context, const rdpGlyph* glyph);
* The height of the glyph being drawn. * The height of the glyph being drawn.
* *
* @param sx * @param sx
* The X coordinate of the upper-left corner of the glyph within the source * The X coordinare of the upper-left corner of the glyph within the source
* cache surface containing the glyph. * cache surface containing the glyph.
* *
* @param sy * @param sy
* The Y coordinate of the upper-left corner of the glyph within the source * The Y coordinare of the upper-left corner of the glyph within the source
* cache surface containing the glyph. * cache surface containing the glyph.
* *
* @param redundant * @param redundant

View File

@ -140,7 +140,7 @@ static void guac_rdp_send_unicode_event(guac_rdp_client* rdp_client,
} }
/** /**
* Immediately sends an RDP synchronize event having the given flags. An RDP * Immediately sends an RDP synchonize event having the given flags. An RDP
* synchronize event sets the state of remote lock keys absolutely, where a * synchronize event sets the state of remote lock keys absolutely, where a
* lock key will be active only if its corresponding flag is set in the event. * lock key will be active only if its corresponding flag is set in the event.
* *

View File

@ -1,79 +0,0 @@
#
# 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.
#
parent "base"
name "cs-cz-qwertz"
freerdp "KBD_CZECH"
#
# Basic keys
#
map -caps -altgr -shift 0x29 0x02..0x0D ~ ";+ěščřžýáíé=´"
map -caps -altgr -shift 0x10..0x1B ~ "qwertzuıopú)"
map -caps -altgr -shift 0x1E..0x28 0x2B ~ "asdfghjklů§¨"
map -caps -altgr -shift 0x2C..0x35 ~ "yxcvbnm,.-"
map -caps -altgr +shift 0x29 0x02..0x0D ~ "°1234567890%ˇ"
map -caps -altgr +shift 0x10..0x1B ~ "QWERTZUIOP/("
map -caps -altgr +shift 0x1E..0x28 0x2B ~ "ASDFGHJKL"!'"
map -caps -altgr +shift 0x2C..0x35 ~ "YXCVBNM?:_"
map +caps -altgr -shift 0x29 0x02..0x0D ~ ";+ĚŠČŘŽÝÁÍÉ=´"
map +caps -altgr -shift 0x10..0x1B ~ "QWERTZUIOPÚ)"
map +caps -altgr -shift 0x1E..0x28 0x2B ~ "ASDFGHJKL٧¨"
map +caps -altgr -shift 0x2C..0x35 ~ "YXCVBNM,.-"
map +caps -altgr +shift 0x29 0x02..0x0D ~ "°1234567890%ˇ"
map +caps -altgr +shift 0x10..0x1B ~ "qwertzuiop/("
map +caps -altgr +shift 0x1E..0x28 0x2B ~ "asdfghjkl"!'"
map +caps -altgr +shift 0x2C..0x35 ~ "yxcvbnm?:_"
#
# Keys requiring AltGr
#
map +altgr -shift 0x02 ~ "~"
map +altgr -shift 0x10 ~ "\"
map +altgr -shift 0x11 ~ "|"
map +altgr -shift 0x12 ~ "€"
map +altgr -shift 0x1A ~ "÷"
map +altgr -shift 0x1B ~ "×"
map +altgr -shift 0x1F ~ "đ"
map +altgr -shift 0x20 ~ "Đ"
map +altgr -shift 0x21 ~ "["
map +altgr -shift 0x22 ~ "]"
map +altgr -shift 0x25 ~ "ł"
map +altgr -shift 0x26 ~ "Ł"
map +altgr -shift 0x27 ~ "$"
map +altgr -shift 0x28 ~ "ß"
map +altgr -shift 0x2B ~ "¤"
map +altgr -shift 0x2D ~ "#"
map +altgr -shift 0x2E ~ "&"
map +altgr -shift 0x2F ~ "@"
map +altgr -shift 0x30 ~ "{"
map +altgr -shift 0x31 ~ "}"
map +altgr -shift 0x33 ~ "<"
map +altgr -shift 0x34 ~ ">"
map +altgr -shift 0x35 ~ "*"
# END

View File

@ -1,55 +0,0 @@
#
# 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.
#
parent "base"
name "fr-ca-qwerty"
freerdp "KBD_CANADIAN_FRENCH"
#
# Basic keys
#
map -altgr -shift 0x29 0x02..0x0D ~ "#1234567890-="
map -altgr -shift 0x10..0x1B 0x2B ~ "qwertyuiop^¸<"
map -altgr -shift 0x1E..0x28 ~ "asdfghjkl;`"
map -altgr -shift 0x2C..0x35 ~ "zxcvbnm,.é"
map -altgr +shift 0x29 0x02..0x0D ~ "|!"/$%?&*()_+"
map -altgr +shift 0x10..0x1B 0x2B ~ "QWERTYUIOP^¨>"
map -altgr +shift 0x1E..0x28 ~ "ASDFGHJKL:`"
map -altgr +shift 0x2C..0x35 ~ "ZXCVBNM'.É"
#
# Keys requiring AltGr
#
map +altgr -shift 0x29 0x02..0x0D ~ "\±@£¢¤¬¦²³¼½¾"
map +altgr -shift 0x18..0x1B 0x2B ~ "§¶[]}"
map +altgr -shift 0x27..0x28 ~ "~{"
map +altgr -shift 0x32..0x33 0x35 ~ "µ¯´"
#
# Combined accents
#
map -altgr -shift 0x1A ~ 0x0302 # COMBINING CIRCUMFLEX ACCENT
map -altgr -shift 0x1B ~ 0x0327 # COMBINING CEDILLA
map -altgr +shift 0x1B ~ 0x0308 # COMBINING DIAERESIS
map -altgr -shift 0x28 ~ 0x0300 # COMBINING GRAVE ACCENT
map +altgr -shift 0x35 ~ 0x0301 # COMBINING ACUTE ACCENT

View File

@ -25,7 +25,6 @@
#include <guacamole/socket.h> #include <guacamole/socket.h>
#include <guacamole/stream.h> #include <guacamole/stream.h>
#include <guacamole/user.h> #include <guacamole/user.h>
#include <winpr/file.h>
#include <winpr/nt.h> #include <winpr/nt.h>
#include <winpr/shell.h> #include <winpr/shell.h>

View File

@ -251,7 +251,7 @@ void guac_rdp_ai_process_version(guac_client* client,
/* Verify we have at least 4 bytes available (UINT32) */ /* Verify we have at least 4 bytes available (UINT32) */
if (Stream_GetRemainingLength(stream) < 4) { if (Stream_GetRemainingLength(stream) < 4) {
guac_client_log(client, GUAC_LOG_WARNING, "Audio input Version PDU " guac_client_log(client, GUAC_LOG_WARNING, "Audio input Versoin PDU "
"does not contain the expected number of bytes. Audio input " "does not contain the expected number of bytes. Audio input "
"redirection may not work as expected."); "redirection may not work as expected.");
return; return;

View File

@ -21,7 +21,6 @@
#include "common/cursor.h" #include "common/cursor.h"
#include "common/display.h" #include "common/display.h"
#include "common/surface.h" #include "common/surface.h"
#include "gdi.h"
#include "pointer.h" #include "pointer.h"
#include "rdp.h" #include "rdp.h"
@ -79,22 +78,11 @@ BOOL guac_rdp_pointer_set(rdpContext* context, const rdpPointer* pointer) {
guac_client* client = ((rdp_freerdp_context*) context)->client; guac_client* client = ((rdp_freerdp_context*) context)->client;
guac_rdp_client* rdp_client = (guac_rdp_client*) client->data; guac_rdp_client* rdp_client = (guac_rdp_client*) client->data;
/* Add explicit frame boundaries around cursor set operation if not already
* in a frame (the RDP protocol does not send nor expect frame boundaries
* for cursor changes, but Guacamole does expect this) */
int in_frame = rdp_client->in_frame;
if (rdp_client->frames_supported && !in_frame)
guac_rdp_gdi_mark_frame(context, 1);
/* Set cursor */ /* Set cursor */
guac_common_cursor_set_surface(rdp_client->display->cursor, guac_common_cursor_set_surface(rdp_client->display->cursor,
pointer->xPos, pointer->yPos, pointer->xPos, pointer->yPos,
((guac_rdp_pointer*) pointer)->layer->surface); ((guac_rdp_pointer*) pointer)->layer->surface);
if (rdp_client->frames_supported && !in_frame)
guac_rdp_gdi_mark_frame(context, 0);
return TRUE; return TRUE;
} }
@ -118,20 +106,9 @@ BOOL guac_rdp_pointer_set_null(rdpContext* context) {
guac_client* client = ((rdp_freerdp_context*) context)->client; guac_client* client = ((rdp_freerdp_context*) context)->client;
guac_rdp_client* rdp_client = (guac_rdp_client*) client->data; guac_rdp_client* rdp_client = (guac_rdp_client*) client->data;
/* Add explicit frame boundaries around cursor set operation if not already
* in a frame (the RDP protocol does not send nor expect frame boundaries
* for cursor changes, but Guacamole does expect this) */
int in_frame = rdp_client->in_frame;
if (rdp_client->frames_supported && !in_frame)
guac_rdp_gdi_mark_frame(context, 1);
/* Set cursor to empty/blank graphic */ /* Set cursor to empty/blank graphic */
guac_common_cursor_set_blank(rdp_client->display->cursor); guac_common_cursor_set_blank(rdp_client->display->cursor);
if (rdp_client->frames_supported && !in_frame)
guac_rdp_gdi_mark_frame(context, 0);
return TRUE; return TRUE;
} }
@ -141,20 +118,9 @@ BOOL guac_rdp_pointer_set_default(rdpContext* context) {
guac_client* client = ((rdp_freerdp_context*) context)->client; guac_client* client = ((rdp_freerdp_context*) context)->client;
guac_rdp_client* rdp_client = (guac_rdp_client*) client->data; guac_rdp_client* rdp_client = (guac_rdp_client*) client->data;
/* Add explicit frame boundaries around cursor set operation if not already
* in a frame (the RDP protocol does not send nor expect frame boundaries
* for cursor changes, but Guacamole does expect this) */
int in_frame = rdp_client->in_frame;
if (rdp_client->frames_supported && !in_frame)
guac_rdp_gdi_mark_frame(context, 1);
/* Set cursor to embedded pointer */ /* Set cursor to embedded pointer */
guac_common_cursor_set_pointer(rdp_client->display->cursor); guac_common_cursor_set_pointer(rdp_client->display->cursor);
if (rdp_client->frames_supported && !in_frame)
guac_rdp_gdi_mark_frame(context, 0);
return TRUE; return TRUE;
} }

View File

@ -28,7 +28,6 @@
#include "channels/rail.h" #include "channels/rail.h"
#include "channels/rdpdr/rdpdr.h" #include "channels/rdpdr/rdpdr.h"
#include "channels/rdpei.h" #include "channels/rdpei.h"
#include "channels/rdpgfx.h"
#include "channels/rdpsnd/rdpsnd.h" #include "channels/rdpsnd/rdpsnd.h"
#include "client.h" #include "client.h"
#include "color.h" #include "color.h"
@ -138,6 +137,15 @@ BOOL rdp_freerdp_pre_connect(freerdp* instance) {
} }
/* Load plugin providing Dynamic Virtual Channel support, if required */
if (instance->settings->SupportDynamicChannels &&
guac_freerdp_channels_load_plugin(context, "drdynvc",
instance->settings)) {
guac_client_log(client, GUAC_LOG_WARNING,
"Failed to load drdynvc plugin. Display update and audio "
"input support will be disabled.");
}
/* Init FreeRDP internal GDI implementation */ /* Init FreeRDP internal GDI implementation */
if (!gdi_init(instance, guac_rdp_get_native_pixel_format(FALSE))) if (!gdi_init(instance, guac_rdp_get_native_pixel_format(FALSE)))
return FALSE; return FALSE;
@ -179,13 +187,9 @@ BOOL rdp_freerdp_pre_connect(freerdp* instance) {
/* Set up GDI */ /* Set up GDI */
instance->update->DesktopResize = guac_rdp_gdi_desktop_resize; instance->update->DesktopResize = guac_rdp_gdi_desktop_resize;
instance->update->BeginPaint = guac_rdp_gdi_begin_paint;
instance->update->EndPaint = guac_rdp_gdi_end_paint; instance->update->EndPaint = guac_rdp_gdi_end_paint;
instance->update->SetBounds = guac_rdp_gdi_set_bounds; instance->update->SetBounds = guac_rdp_gdi_set_bounds;
instance->update->SurfaceFrameMarker = guac_rdp_gdi_surface_frame_marker;
instance->update->altsec->FrameMarker = guac_rdp_gdi_frame_marker;
rdpPrimaryUpdate* primary = instance->update->primary; rdpPrimaryUpdate* primary = instance->update->primary;
primary->DstBlt = guac_rdp_gdi_dstblt; primary->DstBlt = guac_rdp_gdi_dstblt;
primary->PatBlt = guac_rdp_gdi_patblt; primary->PatBlt = guac_rdp_gdi_patblt;
@ -200,19 +204,6 @@ BOOL rdp_freerdp_pre_connect(freerdp* instance) {
offscreen_cache_register_callbacks(instance->update); offscreen_cache_register_callbacks(instance->update);
palette_cache_register_callbacks(instance->update); palette_cache_register_callbacks(instance->update);
/* Load "rdpgfx" plugin for Graphics Pipeline Extension */
if (settings->enable_gfx)
guac_rdp_rdpgfx_load_plugin(context);
/* Load plugin providing Dynamic Virtual Channel support, if required */
if (instance->settings->SupportDynamicChannels &&
guac_freerdp_channels_load_plugin(context, "drdynvc",
instance->settings)) {
guac_client_log(client, GUAC_LOG_WARNING,
"Failed to load drdynvc plugin. Display update and audio "
"input support will be disabled.");
}
return TRUE; return TRUE;
} }
@ -553,6 +544,7 @@ static int guac_rdp_handle_connection(guac_client* client) {
if (wait_result > 0) { if (wait_result > 0) {
int processing_lag = guac_client_get_processing_lag(client); int processing_lag = guac_client_get_processing_lag(client);
guac_timestamp frame_start = guac_timestamp_current();
/* Read server messages until frame is built */ /* Read server messages until frame is built */
do { do {
@ -572,15 +564,7 @@ static int guac_rdp_handle_connection(guac_client* client) {
break; break;
} }
/* Continue handling inbound data if we are in the middle of an RDP frame */
if (rdp_client->in_frame) {
wait_result = rdp_guac_client_wait_for_messages(client, GUAC_RDP_FRAME_START_TIMEOUT);
if (wait_result >= 0)
continue;
}
/* Calculate time remaining in frame */ /* Calculate time remaining in frame */
guac_timestamp frame_start = client->last_sent_timestamp;
frame_end = guac_timestamp_current(); frame_end = guac_timestamp_current();
frame_remaining = frame_start + GUAC_RDP_FRAME_DURATION frame_remaining = frame_start + GUAC_RDP_FRAME_DURATION
- frame_end; - frame_end;
@ -603,6 +587,12 @@ static int guac_rdp_handle_connection(guac_client* client) {
} while (wait_result > 0); } while (wait_result > 0);
/* Record end of frame, excluding server-side rendering time (we
* assume server-side rendering time will be consistent between any
* two subsequent frames, and that this time should thus be
* excluded from the required wait period of the next frame). */
last_frame_end = frame_start;
} }
/* Test whether the RDP server is closing the connection */ /* Test whether the RDP server is closing the connection */
@ -617,13 +607,11 @@ static int guac_rdp_handle_connection(guac_client* client) {
guac_client_abort(client, GUAC_PROTOCOL_STATUS_UPSTREAM_UNAVAILABLE, guac_client_abort(client, GUAC_PROTOCOL_STATUS_UPSTREAM_UNAVAILABLE,
"Connection closed."); "Connection closed.");
/* Flush frame only if successful and an RDP frame is not known to be /* Flush frame only if successful */
* in progress */ else {
else if (!rdp_client->frames_supported || rdp_client->frames_received) {
guac_common_display_flush(rdp_client->display); guac_common_display_flush(rdp_client->display);
guac_client_end_multiple_frames(client, rdp_client->frames_received); guac_client_end_frame(client);
guac_socket_flush(client->socket); guac_socket_flush(client->socket);
rdp_client->frames_received = 0;
} }
} }

View File

@ -91,24 +91,6 @@ typedef struct guac_rdp_client {
*/ */
guac_common_surface* current_surface; guac_common_surface* current_surface;
/**
* Whether the RDP server supports defining explicit frame boundaries.
*/
int frames_supported;
/**
* Whether the RDP server has reported that a new frame is in progress, and
* we are now receiving updates relevant to that frame.
*/
int in_frame;
/**
* The number of distinct frames received from the RDP server since last
* flush, if the RDP server supports reporting frame boundaries. If the RDP
* server does not support tracking frames, this will be zero.
*/
int frames_received;
/** /**
* The current state of the keyboard with respect to the RDP session. * The current state of the keyboard with respect to the RDP session.
*/ */

View File

@ -28,7 +28,6 @@
#include <freerdp/settings.h> #include <freerdp/settings.h>
#include <freerdp/freerdp.h> #include <freerdp/freerdp.h>
#include <guacamole/client.h> #include <guacamole/client.h>
#include <guacamole/fips.h>
#include <guacamole/string.h> #include <guacamole/string.h>
#include <guacamole/user.h> #include <guacamole/user.h>
#include <guacamole/wol-constants.h> #include <guacamole/wol-constants.h>
@ -40,16 +39,6 @@
#include <stdlib.h> #include <stdlib.h>
#include <string.h> #include <string.h>
/**
* A warning to log when NLA mode is selected while FIPS mode is active on the
* guacd server.
*/
const char fips_nla_mode_warning[] = (
"NLA security mode was selected, but is known to be currently incompatible "
"with FIPS mode (see FreeRDP/FreeRDP#3412). Security negotiation with the "
"RDP server may fail unless TLS security mode is selected instead."
);
/* Client plugin arguments */ /* Client plugin arguments */
const char* GUAC_RDP_CLIENT_ARGS[] = { const char* GUAC_RDP_CLIENT_ARGS[] = {
"hostname", "hostname",
@ -91,7 +80,6 @@ const char* GUAC_RDP_CLIENT_ARGS[] = {
"disable-bitmap-caching", "disable-bitmap-caching",
"disable-offscreen-caching", "disable-offscreen-caching",
"disable-glyph-caching", "disable-glyph-caching",
"disable-gfx",
"preconnection-id", "preconnection-id",
"preconnection-blob", "preconnection-blob",
"timezone", "timezone",
@ -372,7 +360,7 @@ enum RDP_ARGS_IDX {
IDX_DISABLE_BITMAP_CACHING, IDX_DISABLE_BITMAP_CACHING,
/** /**
* "true" if the offscreen caching should be disabled, false if offscreen * "true" if the offscreen caching should be disabled, false if offscren
* caching should remain enabled. * caching should remain enabled.
*/ */
IDX_DISABLE_OFFSCREEN_CACHING, IDX_DISABLE_OFFSCREEN_CACHING,
@ -383,13 +371,6 @@ enum RDP_ARGS_IDX {
*/ */
IDX_DISABLE_GLYPH_CACHING, IDX_DISABLE_GLYPH_CACHING,
/**
* "true" if the RDP Graphics Pipeline Extension should not be used, and
* traditional RDP graphics should be used instead, "false" or blank if the
* Graphics Pipeline Extension should be used if available.
*/
IDX_DISABLE_GFX,
/** /**
* The preconnection ID to send within the preconnection PDU when * The preconnection ID to send within the preconnection PDU when
* initiating an RDP connection, if any. * initiating an RDP connection, if any.
@ -717,27 +698,12 @@ guac_rdp_settings* guac_rdp_parse_args(guac_user* user,
if (strcmp(argv[IDX_SECURITY], "nla") == 0) { if (strcmp(argv[IDX_SECURITY], "nla") == 0) {
guac_user_log(user, GUAC_LOG_INFO, "Security mode: NLA"); guac_user_log(user, GUAC_LOG_INFO, "Security mode: NLA");
settings->security_mode = GUAC_SECURITY_NLA; settings->security_mode = GUAC_SECURITY_NLA;
/*
* NLA is known not to work with FIPS; allow the mode selection but
* warn that it will not work.
*/
if (guac_fips_enabled())
guac_user_log(user, GUAC_LOG_WARNING, fips_nla_mode_warning);
} }
/* Extended NLA security */ /* Extended NLA security */
else if (strcmp(argv[IDX_SECURITY], "nla-ext") == 0) { else if (strcmp(argv[IDX_SECURITY], "nla-ext") == 0) {
guac_user_log(user, GUAC_LOG_INFO, "Security mode: Extended NLA"); guac_user_log(user, GUAC_LOG_INFO, "Security mode: Extended NLA");
settings->security_mode = GUAC_SECURITY_EXTENDED_NLA; settings->security_mode = GUAC_SECURITY_EXTENDED_NLA;
/*
* NLA is known not to work with FIPS; allow the mode selection but
* warn that it will not work.
*/
if (guac_fips_enabled())
guac_user_log(user, GUAC_LOG_WARNING, fips_nla_mode_warning);
} }
/* TLS security */ /* TLS security */
@ -942,6 +908,11 @@ guac_rdp_settings* guac_rdp_parse_args(guac_user* user,
GUAC_RDP_CLIENT_ARGS[IDX_DISABLE_GLYPH_CACHING]); GUAC_RDP_CLIENT_ARGS[IDX_DISABLE_GLYPH_CACHING]);
} }
/* Session color depth */
settings->color_depth =
guac_user_parse_args_int(user, GUAC_RDP_CLIENT_ARGS, argv,
IDX_COLOR_DEPTH, RDP_DEFAULT_DEPTH);
/* Preconnection ID */ /* Preconnection ID */
settings->preconnection_id = -1; settings->preconnection_id = -1;
if (argv[IDX_PRECONNECTION_ID][0] != '\0') { if (argv[IDX_PRECONNECTION_ID][0] != '\0') {
@ -1158,16 +1129,6 @@ guac_rdp_settings* guac_rdp_parse_args(guac_user* user,
settings->resize_method = GUAC_RESIZE_NONE; settings->resize_method = GUAC_RESIZE_NONE;
} }
/* RDP Graphics Pipeline enable/disable */
settings->enable_gfx =
!guac_user_parse_args_boolean(user, GUAC_RDP_CLIENT_ARGS, argv,
IDX_DISABLE_GFX, 0);
/* Session color depth */
settings->color_depth =
guac_user_parse_args_int(user, GUAC_RDP_CLIENT_ARGS, argv,
IDX_COLOR_DEPTH, settings->enable_gfx ? RDP_GFX_REQUIRED_DEPTH : RDP_DEFAULT_DEPTH);
/* Multi-touch input enable/disable */ /* Multi-touch input enable/disable */
settings->enable_touch = settings->enable_touch =
guac_user_parse_args_boolean(user, GUAC_RDP_CLIENT_ARGS, argv, guac_user_parse_args_boolean(user, GUAC_RDP_CLIENT_ARGS, argv,
@ -1436,29 +1397,6 @@ void guac_rdp_push_settings(guac_client* client,
/* Explicitly set flag value */ /* Explicitly set flag value */
rdp_settings->PerformanceFlags = guac_rdp_get_performance_flags(guac_settings); rdp_settings->PerformanceFlags = guac_rdp_get_performance_flags(guac_settings);
/* Always request frame markers */
rdp_settings->FrameMarkerCommandEnabled = TRUE;
rdp_settings->SurfaceFrameMarkerEnabled = TRUE;
/* Enable RemoteFX / Graphics Pipeline */
if (guac_settings->enable_gfx) {
rdp_settings->SupportGraphicsPipeline = TRUE;
rdp_settings->RemoteFxCodec = TRUE;
if (rdp_settings->ColorDepth != RDP_GFX_REQUIRED_DEPTH) {
guac_client_log(client, GUAC_LOG_WARNING, "Ignoring requested "
"color depth of %i bpp, as the RDP Graphics Pipeline "
"requires %i bpp.", rdp_settings->ColorDepth, RDP_GFX_REQUIRED_DEPTH);
}
/* Required for RemoteFX / Graphics Pipeline */
rdp_settings->FastPathOutput = TRUE;
rdp_settings->ColorDepth = RDP_GFX_REQUIRED_DEPTH;
rdp_settings->SoftwareGdi = TRUE;
}
/* Set individual flags - some FreeRDP versions overwrite the above */ /* Set individual flags - some FreeRDP versions overwrite the above */
rdp_settings->AllowFontSmoothing = guac_settings->font_smoothing_enabled; rdp_settings->AllowFontSmoothing = guac_settings->font_smoothing_enabled;
rdp_settings->DisableWallpaper = !guac_settings->wallpaper_enabled; rdp_settings->DisableWallpaper = !guac_settings->wallpaper_enabled;
@ -1555,21 +1493,7 @@ void guac_rdp_push_settings(guac_client* client,
case GUAC_SECURITY_ANY: case GUAC_SECURITY_ANY:
rdp_settings->RdpSecurity = TRUE; rdp_settings->RdpSecurity = TRUE;
rdp_settings->TlsSecurity = TRUE; rdp_settings->TlsSecurity = TRUE;
rdp_settings->NlaSecurity = guac_settings->username && guac_settings->password;
/* Explicitly disable NLA if FIPS mode is enabled - it won't work */
if (guac_fips_enabled()) {
guac_client_log(client, GUAC_LOG_INFO,
"FIPS mode is enabled. Excluding NLA security mode from security negotiation "
"(see: https://github.com/FreeRDP/FreeRDP/issues/3412).");
rdp_settings->NlaSecurity = FALSE;
}
/* NLA mode is allowed if FIPS is not enabled */
else
rdp_settings->NlaSecurity = TRUE;
rdp_settings->ExtSecurity = FALSE; rdp_settings->ExtSecurity = FALSE;
break; break;

View File

@ -58,11 +58,6 @@
*/ */
#define RDP_DEFAULT_DEPTH 16 #define RDP_DEFAULT_DEPTH 16
/**
* The color depth required by the RDPGFX channel, in bits.
*/
#define RDP_GFX_REQUIRED_DEPTH 32
/** /**
* The filename to use for the screen recording, if not specified. * The filename to use for the screen recording, if not specified.
*/ */
@ -557,11 +552,6 @@ typedef struct guac_rdp_settings {
*/ */
int enable_audio_input; int enable_audio_input;
/**
* Whether the RDP Graphics Pipeline Extension is enabled.
*/
int enable_gfx;
/** /**
* Whether multi-touch support is enabled. * Whether multi-touch support is enabled.
*/ */

View File

@ -202,19 +202,6 @@ int __guac_terminal_set(guac_terminal_display* display, int row, int col, int co
} }
/**
* Calculate the size of margins around the terminal based on DPI.
*
* @param dpi
* The resolution of the display in DPI.
*
* @return
* Calculated size of margin in pixels.
*/
static int get_margin_by_dpi(int dpi) {
return dpi * GUAC_TERMINAL_MARGINS / GUAC_TERMINAL_MM_PER_INCH;
}
guac_terminal_display* guac_terminal_display_alloc(guac_client* client, guac_terminal_display* guac_terminal_display_alloc(guac_client* client,
const char* font_name, int font_size, int dpi, const char* font_name, int font_size, int dpi,
guac_terminal_color* foreground, guac_terminal_color* background, guac_terminal_color* foreground, guac_terminal_color* background,
@ -242,13 +229,6 @@ guac_terminal_display* guac_terminal_display_alloc(guac_client* client,
guac_protocol_send_move(client->socket, display->select_layer, guac_protocol_send_move(client->socket, display->select_layer,
display->display_layer, 0, 0, 0); display->display_layer, 0, 0, 0);
/* Calculate margin size by DPI */
display->margin = get_margin_by_dpi(dpi);
/* Offset the Default Layer to make margins even on all sides */
guac_protocol_send_move(client->socket, display->display_layer,
GUAC_DEFAULT_LAYER, display->margin, display->margin, 0);
display->default_foreground = display->glyph_foreground = *foreground; display->default_foreground = display->glyph_foreground = *foreground;
display->default_background = display->glyph_background = *background; display->default_background = display->glyph_background = *background;
display->default_palette = palette; display->default_palette = palette;
@ -467,10 +447,6 @@ void guac_terminal_display_set_columns(guac_terminal_display* display, int row,
void guac_terminal_display_resize(guac_terminal_display* display, int width, int height) { void guac_terminal_display_resize(guac_terminal_display* display, int width, int height) {
/* Resize display only if dimensions have changed */
if (width == display->width && height == display->height)
return;
guac_terminal_operation* current; guac_terminal_operation* current;
int x, y; int x, y;
@ -852,10 +828,6 @@ void guac_terminal_display_dup(guac_terminal_display* display, guac_user* user,
guac_protocol_send_move(socket, display->select_layer, guac_protocol_send_move(socket, display->select_layer,
display->display_layer, 0, 0, 0); display->display_layer, 0, 0, 0);
/* Offset the Default Layer to make margins even on all sides */
guac_protocol_send_move(socket, display->display_layer,
GUAC_DEFAULT_LAYER, display->margin, display->margin, 0);
/* Send select layer size */ /* Send select layer size */
guac_protocol_send_size(socket, display->select_layer, guac_protocol_send_size(socket, display->select_layer,
display->char_width * display->width, display->char_width * display->width,
@ -1048,7 +1020,7 @@ int guac_terminal_display_set_font(guac_terminal_display* display,
if (new_width != display->width || new_height != display->height) if (new_width != display->width || new_height != display->height)
guac_terminal_display_resize(display, new_width, new_height); guac_terminal_display_resize(display, new_width, new_height);
return 0; return 0;
} }

View File

@ -20,7 +20,6 @@
#include "common/clipboard.h" #include "common/clipboard.h"
#include "common/cursor.h" #include "common/cursor.h"
#include "common/iconv.h"
#include "terminal/buffer.h" #include "terminal/buffer.h"
#include "terminal/color-scheme.h" #include "terminal/color-scheme.h"
#include "terminal/common.h" #include "terminal/common.h"
@ -336,97 +335,6 @@ guac_terminal_options* guac_terminal_options_create(
return options; return options;
} }
/**
* Calculate the available height and width in characters for text display in
* the terminal and store the results in the pointer arguments.
*
* @param terminal
* The terminal provides character width and height for calculations.
*
* @param height
* The outer height of the terminal, in pixels.
*
* @param width
* The outer width of the terminal, in pixels.
*
* @param rows
* Pointer to the calculated height of the terminal for text display,
* in characters.
*
* @param columns
* Pointer to the calculated width of the terminal for text display,
* in characters.
*/
static void calculate_rows_and_columns(guac_terminal* term,
int height, int width, int *rows, int *columns) {
int margin = term->display->margin;
int char_width = term->display->char_width;
int char_height = term->display->char_height;
/* Calculate available display area */
int available_width = width - GUAC_TERMINAL_SCROLLBAR_WIDTH - 2 * margin;
if (available_width < 0)
available_width = 0;
int available_height = height - 2 * margin;
if (available_height < 0)
available_height = 0;
/* Calculate dimensions */
*rows = available_height / char_height;
*columns = available_width / char_width;
/* Keep height within predefined maximum */
if (*rows > GUAC_TERMINAL_MAX_ROWS)
*rows = GUAC_TERMINAL_MAX_ROWS;
/* Keep width within predefined maximum */
if (*columns > GUAC_TERMINAL_MAX_COLUMNS)
*columns = GUAC_TERMINAL_MAX_COLUMNS;
}
/**
* Calculate the available height and width in pixels of the terminal for text
* display in the terminal and store the results in the pointer arguments.
*
* @param terminal
* The terminal provides character width and height for calculations.
*
* @param rows
* The available height of the terminal for text display, in characters.
*
* @param columns
* The available width of the terminal for text display, in characters.
*
* @param height
* Pointer to the calculated available height of the terminal for text
* display, in pixels.
*
* @param width
* Pointer to the calculated available width of the terminal for text
* display, in pixels.
*/
static void calculate_height_and_width(guac_terminal* term,
int rows, int columns, int *height, int *width) {
int margin = term->display->margin;
int char_width = term->display->char_width;
int char_height = term->display->char_height;
/* Recalculate height if max rows reached */
if (rows == GUAC_TERMINAL_MAX_ROWS) {
int available_height = GUAC_TERMINAL_MAX_ROWS * char_height;
*height = available_height + 2 * margin;
}
/* Recalculate width if max columns reached */
if (columns == GUAC_TERMINAL_MAX_COLUMNS) {
int available_width = GUAC_TERMINAL_MAX_COLUMNS * char_width;
*width = available_width + GUAC_TERMINAL_SCROLLBAR_WIDTH + 2 * margin;
}
}
guac_terminal* guac_terminal_create(guac_client* client, guac_terminal* guac_terminal_create(guac_client* client,
guac_terminal_options* options) { guac_terminal_options* options) {
@ -455,6 +363,11 @@ guac_terminal* guac_terminal_create(guac_client* client,
&default_char.attributes.background, &default_char.attributes.background,
default_palette); default_palette);
/* Calculate available display area */
int available_width = width - GUAC_TERMINAL_SCROLLBAR_WIDTH;
if (available_width < 0)
available_width = 0;
guac_terminal* term = malloc(sizeof(guac_terminal)); guac_terminal* term = malloc(sizeof(guac_terminal));
term->started = false; term->started = false;
term->client = client; term->client = client;
@ -466,6 +379,10 @@ guac_terminal* guac_terminal_create(guac_client* client,
term->font_name = strdup(options->font_name); term->font_name = strdup(options->font_name);
term->font_size = options->font_size; term->font_size = options->font_size;
/* Set size of available screen area */
term->outer_width = width;
term->outer_height = height;
/* Init modified flag and conditional */ /* Init modified flag and conditional */
term->modified = 0; term->modified = 0;
pthread_cond_init(&(term->modified_cond), NULL); pthread_cond_init(&(term->modified_cond), NULL);
@ -508,27 +425,29 @@ guac_terminal* guac_terminal_create(guac_client* client,
term->clipboard = guac_common_clipboard_alloc(); term->clipboard = guac_common_clipboard_alloc();
term->disable_copy = options->disable_copy; term->disable_copy = options->disable_copy;
/* Calculate available text display area by character size */ /* Calculate character size */
int rows, columns; int rows = height / term->display->char_height;
calculate_rows_and_columns(term, height, width, &rows, &columns); int columns = available_width / term->display->char_width;
/* Calculate available display area in pixels */ /* Keep height within predefined maximum */
int adjusted_height = height; if (rows > GUAC_TERMINAL_MAX_ROWS) {
int adjusted_width = width; rows = GUAC_TERMINAL_MAX_ROWS;
calculate_height_and_width(term, rows, columns, height = rows * term->display->char_height;
&adjusted_height, &adjusted_width); }
/* Set size of available screen area */ /* Keep width within predefined maximum */
term->outer_height = height; if (columns > GUAC_TERMINAL_MAX_COLUMNS) {
term->outer_width = width; columns = GUAC_TERMINAL_MAX_COLUMNS;
available_width = columns * term->display->char_width;
/* Set rows and columns size */ width = available_width + GUAC_TERMINAL_SCROLLBAR_WIDTH;
term->term_height = rows; }
term->term_width = columns;
/* Set pixel size */ /* Set pixel size */
term->height = adjusted_height; term->width = width;
term->width = adjusted_width; term->height = height;
term->term_width = columns;
term->term_height = rows;
/* Open STDIN pipe */ /* Open STDIN pipe */
if (pipe(term->stdin_pipe_fd)) { if (pipe(term->stdin_pipe_fd)) {
@ -557,7 +476,7 @@ guac_terminal* guac_terminal_create(guac_client* client,
/* Allocate scrollbar */ /* Allocate scrollbar */
term->scrollbar = guac_terminal_scrollbar_alloc(term->client, GUAC_DEFAULT_LAYER, term->scrollbar = guac_terminal_scrollbar_alloc(term->client, GUAC_DEFAULT_LAYER,
term->outer_width, term->outer_height, term->term_height); width, height, term->term_height);
/* Associate scrollbar with this terminal */ /* Associate scrollbar with this terminal */
term->scrollbar->data = term; term->scrollbar->data = term;
@ -566,10 +485,6 @@ guac_terminal* guac_terminal_create(guac_client* client,
/* Init terminal */ /* Init terminal */
guac_terminal_reset(term); guac_terminal_reset(term);
/* All mouse buttons are released */
term->mouse_mask = 0;
/* All keyboard modifiers are released */
term->mod_alt = term->mod_alt =
term->mod_ctrl = term->mod_ctrl =
term->mod_shift = 0; term->mod_shift = 0;
@ -1383,7 +1298,7 @@ static void __guac_terminal_resize(guac_terminal* term, int width, int height) {
guac_terminal_display_flush(term->display); guac_terminal_display_flush(term->display);
guac_terminal_display_resize(term->display, width, height); guac_terminal_display_resize(term->display, width, height);
/* Redraw any characters on right if widening */ /* Reraw any characters on right if widening */
if (width > term->term_width) if (width > term->term_width)
__guac_terminal_redraw_rect(term, 0, term->term_width-1, height-1, width-1); __guac_terminal_redraw_rect(term, 0, term->term_width-1, height-1, width-1);
@ -1466,39 +1381,55 @@ int guac_terminal_resize(guac_terminal* terminal, int width, int height) {
/* Acquire exclusive access to terminal */ /* Acquire exclusive access to terminal */
guac_terminal_lock(terminal); guac_terminal_lock(terminal);
/* Calculate available text display area by character size */
int rows, columns;
calculate_rows_and_columns(terminal, height, width, &rows, &columns);
/* Calculate available display area in pixels */
int adjusted_height = height;
int adjusted_width = width;
calculate_height_and_width(terminal, rows, columns,
&adjusted_height, &adjusted_width);
/* Set size of available screen area */ /* Set size of available screen area */
terminal->outer_height = height;
terminal->outer_width = width; terminal->outer_width = width;
terminal->outer_height = height;
/* Set pixel size */ /* Calculate available display area */
terminal->height = adjusted_height; int available_width = width - GUAC_TERMINAL_SCROLLBAR_WIDTH;
terminal->width = adjusted_width; if (available_width < 0)
available_width = 0;
/* Calculate dimensions */
int rows = height / display->char_height;
int columns = available_width / display->char_width;
/* Keep height within predefined maximum */
if (rows > GUAC_TERMINAL_MAX_ROWS) {
rows = GUAC_TERMINAL_MAX_ROWS;
height = rows * display->char_height;
}
/* Keep width within predefined maximum */
if (columns > GUAC_TERMINAL_MAX_COLUMNS) {
columns = GUAC_TERMINAL_MAX_COLUMNS;
available_width = columns * display->char_width;
width = available_width + GUAC_TERMINAL_SCROLLBAR_WIDTH;
}
/* Set pixel sizes */
terminal->width = width;
terminal->height = height;
/* Resize default layer to given pixel dimensions */ /* Resize default layer to given pixel dimensions */
guac_terminal_repaint_default_layer(terminal, client->socket); guac_terminal_repaint_default_layer(terminal, client->socket);
/* Resize terminal if row/column dimensions have changed */ /* Resize terminal if row/column dimensions have changed */
if (columns != terminal->term_width || rows != terminal->term_height) { if (columns != terminal->term_width || rows != terminal->term_height) {
/* Resize terminal and set the columns and rows on the terminal struct */
guac_client_log(client, GUAC_LOG_DEBUG,
"Resizing terminal to %ix%i", rows, columns);
/* Resize terminal */
__guac_terminal_resize(terminal, columns, rows); __guac_terminal_resize(terminal, columns, rows);
/* Reset scroll region */ /* Reset scroll region */
terminal->scroll_end = rows - 1; terminal->scroll_end = rows - 1;
} }
/* Notify scrollbar of resize */ /* Notify scrollbar of resize */
guac_terminal_scrollbar_parent_resized(terminal->scrollbar, guac_terminal_scrollbar_parent_resized(terminal->scrollbar, width, height, rows);
terminal->outer_width, terminal->outer_height, terminal->term_height);
guac_terminal_scrollbar_set_bounds(terminal->scrollbar, guac_terminal_scrollbar_set_bounds(terminal->scrollbar,
-guac_terminal_get_available_scroll(terminal), 0); -guac_terminal_get_available_scroll(terminal), 0);
@ -2165,16 +2096,7 @@ void guac_terminal_clipboard_reset(guac_terminal* terminal,
void guac_terminal_clipboard_append(guac_terminal* terminal, void guac_terminal_clipboard_append(guac_terminal* terminal,
const char* data, int length) { const char* data, int length) {
guac_common_clipboard_append(terminal->clipboard, data, length);
/* Allocate and clear space for the converted data */
char output_data[GUAC_COMMON_CLIPBOARD_MAX_LENGTH];
char* output = output_data;
/* Convert clipboard contents */
guac_iconv(GUAC_READ_UTF8_NORMALIZED, &data, length,
GUAC_WRITE_UTF8, &output, GUAC_COMMON_CLIPBOARD_MAX_LENGTH);
guac_common_clipboard_append(terminal->clipboard, output_data, output - output_data);
} }
void guac_terminal_remove_user(guac_terminal* terminal, guac_user* user) { void guac_terminal_remove_user(guac_terminal* terminal, guac_user* user) {

View File

@ -44,17 +44,6 @@
*/ */
#define GUAC_TERMINAL_MAX_CHAR_WIDTH 2 #define GUAC_TERMINAL_MAX_CHAR_WIDTH 2
/**
* The size of margins between the console text and the border in mm.
*/
#define GUAC_TERMINAL_MARGINS 2
/**
* 1 inch is 25.4 millimeters, and we can therefore use the following
* to create a mm to px formula: (mm × dpi) ÷ 25.4 = px.
*/
#define GUAC_TERMINAL_MM_PER_INCH 25.4
/** /**
* All available terminal operations which affect character cells. * All available terminal operations which affect character cells.
*/ */
@ -134,11 +123,6 @@ typedef struct guac_terminal_display {
*/ */
int height; int height;
/**
* The size of margins between the console text and the border in pixels.
*/
int margin;
/** /**
* The description of the font to use for rendering. * The description of the font to use for rendering.
*/ */