Merge pull request #3592 from matt335672/vnc_support_forwarded_resize
Vnc support forwarded resize
This commit is contained in:
@@ -75,6 +75,8 @@ libcommon_la_SOURCES = \
|
||||
string_calls.h \
|
||||
thread_calls.c \
|
||||
thread_calls.h \
|
||||
timers.c \
|
||||
timers.h \
|
||||
trans.c \
|
||||
trans.h \
|
||||
unicode_defines.h \
|
||||
|
||||
@@ -0,0 +1,94 @@
|
||||
/**
|
||||
* xrdp: A Remote Desktop Protocol server.
|
||||
*
|
||||
* Copyright (C) Jay Sorg 2004-2025
|
||||
*
|
||||
* Licensed 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.
|
||||
*
|
||||
*/
|
||||
|
||||
/**
|
||||
* @file common/timers.h
|
||||
* @brief Timers and related functions (declarations)
|
||||
* @author Matt Burt
|
||||
*/
|
||||
|
||||
#if defined(HAVE_CONFIG_H)
|
||||
#include "config_ac.h"
|
||||
#endif
|
||||
|
||||
#include "os_calls.h"
|
||||
#include "timers.h"
|
||||
|
||||
struct timers_oneshot
|
||||
{
|
||||
unsigned int add_time; // Time event was added from_g_get_elapsed_ms()
|
||||
int trigger_time;
|
||||
};
|
||||
|
||||
/******************************************************************************/
|
||||
struct timers_oneshot *
|
||||
timers_oneshot_init(int ms)
|
||||
{
|
||||
struct timers_oneshot *t = (struct timers_oneshot *)malloc(sizeof(*t));
|
||||
if (t != NULL)
|
||||
{
|
||||
t->add_time = g_get_elapsed_ms();
|
||||
t->trigger_time = (ms <= 0) ? 0 : ms;
|
||||
}
|
||||
return t;
|
||||
}
|
||||
|
||||
/******************************************************************************/
|
||||
int
|
||||
timers_oneshot_get_remaining(struct timers_oneshot *timer,
|
||||
unsigned int now)
|
||||
{
|
||||
int rv = -1;
|
||||
if (timer != NULL)
|
||||
{
|
||||
if (timer->trigger_time == 0)
|
||||
{
|
||||
rv = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
rv = timer->trigger_time - (int)(now - timer->add_time);
|
||||
if (rv <= 0)
|
||||
{
|
||||
rv = 0;
|
||||
// (pathological) Make sure the timer doesn't stop
|
||||
// triggering if it isn't attended to for the rollover
|
||||
// period (~20 days for a 32-bit timer).
|
||||
timer->trigger_time = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return rv;
|
||||
}
|
||||
|
||||
/******************************************************************************/
|
||||
void
|
||||
timers_oneshot_update_poll(struct timers_oneshot *timer, unsigned int now,
|
||||
int *timeout)
|
||||
{
|
||||
if (timer != NULL && timeout != NULL)
|
||||
{
|
||||
int remaining = timers_oneshot_get_remaining(timer, now);
|
||||
if (*timeout < 0 || *timeout > remaining)
|
||||
{
|
||||
*timeout = remaining;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,74 @@
|
||||
/**
|
||||
* xrdp: A Remote Desktop Protocol server.
|
||||
*
|
||||
* Copyright (C) Jay Sorg 2004-2025
|
||||
*
|
||||
* Licensed 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.
|
||||
*
|
||||
*/
|
||||
|
||||
/**
|
||||
* @file common/timers.h
|
||||
* @brief Timers and related functions (declarations)
|
||||
* @author Matt Burt
|
||||
*/
|
||||
|
||||
#ifndef TIMERS_H
|
||||
#define TIMERS_H
|
||||
|
||||
#include "arch.h"
|
||||
|
||||
struct timers_oneshot;
|
||||
|
||||
/**
|
||||
* Initialise a one-shot timer
|
||||
* @param ms Milliseconds until timer fires (>= 0)
|
||||
* @return pointer to timer
|
||||
*
|
||||
* Returns NULL if no memory.
|
||||
*
|
||||
* When the timer is no longer required, it can simply be passed to free()
|
||||
*/
|
||||
struct timers_oneshot *
|
||||
timers_oneshot_init(int ms);
|
||||
|
||||
/**
|
||||
* Return ms remaining on a one-shot timer
|
||||
* @param timer pointer to timer (or NULL)
|
||||
* @param now Value of g_get_elapsed_ms()
|
||||
* @return remaining ms
|
||||
*
|
||||
* Once this routine has returned 0 for a particular timer, it will never
|
||||
* return anything else. Don't pass anything to 'now' apart from a recent
|
||||
* value from g_get_elapsed_ms()
|
||||
*
|
||||
* If the timer is NULL, -1 is returned.
|
||||
*/
|
||||
int
|
||||
timers_oneshot_get_remaining(struct timers_oneshot *timer,
|
||||
unsigned int now);
|
||||
|
||||
/**
|
||||
* Variant of timers_oneshot_get_remaining() for g_obj_wait()
|
||||
* @param timer pointer to timer (or NULL)
|
||||
* @param now Value of g_get_elapsed_ms()
|
||||
* @param[in,out] poll timeout
|
||||
*
|
||||
* Use this to update a timeout passed to g_obj_wait() (or poll()). The
|
||||
* timeout is updated if the timer will fire before the current timeout.
|
||||
*/
|
||||
void
|
||||
timers_oneshot_update_poll(struct timers_oneshot *timer, unsigned int now,
|
||||
int *timeout);
|
||||
|
||||
#endif // TIMERS_H
|
||||
@@ -26,7 +26,8 @@ test_common_SOURCES = \
|
||||
test_ssl_calls.c \
|
||||
test_base64.c \
|
||||
test_guid.c \
|
||||
test_scancode.c
|
||||
test_scancode.c \
|
||||
test_timers.c
|
||||
|
||||
test_common_CFLAGS = \
|
||||
@CHECK_CFLAGS@ \
|
||||
|
||||
@@ -19,6 +19,7 @@ Suite *make_suite_test_ssl_calls(void);
|
||||
Suite *make_suite_test_base64(void);
|
||||
Suite *make_suite_test_guid(void);
|
||||
Suite *make_suite_test_scancode(void);
|
||||
Suite *make_suite_test_timers(void);
|
||||
|
||||
TCase *make_tcase_test_os_calls_signals(void);
|
||||
|
||||
|
||||
@@ -58,6 +58,7 @@ int main (void)
|
||||
srunner_add_suite(sr, make_suite_test_base64());
|
||||
srunner_add_suite(sr, make_suite_test_guid());
|
||||
srunner_add_suite(sr, make_suite_test_scancode());
|
||||
srunner_add_suite(sr, make_suite_test_timers());
|
||||
|
||||
srunner_set_tap(sr, "-");
|
||||
/*
|
||||
|
||||
@@ -0,0 +1,88 @@
|
||||
|
||||
#if defined(HAVE_CONFIG_H)
|
||||
#include "config_ac.h"
|
||||
#endif
|
||||
|
||||
#include "limits.h"
|
||||
#include "os_calls.h"
|
||||
#include "timers.h"
|
||||
|
||||
#include "test_common.h"
|
||||
|
||||
/******************************************************************************/
|
||||
START_TEST(test_timers__null_timer)
|
||||
{
|
||||
unsigned int now = g_get_elapsed_ms();
|
||||
struct timers_oneshot *timer = NULL;
|
||||
int v = timers_oneshot_get_remaining(timer, now);
|
||||
ck_assert_int_eq(v, -1);
|
||||
|
||||
// Check any value of 'v' is not changed with a NULL timer
|
||||
timers_oneshot_update_poll(timer, now, &v);
|
||||
ck_assert_int_eq(v, -1);
|
||||
|
||||
v = 0;
|
||||
timers_oneshot_update_poll(timer, now, &v);
|
||||
ck_assert_int_eq(v, 0);
|
||||
|
||||
v = INT_MAX;
|
||||
timers_oneshot_update_poll(timer, now, &v);
|
||||
ck_assert_int_eq(v, INT_MAX);
|
||||
}
|
||||
END_TEST
|
||||
|
||||
/******************************************************************************/
|
||||
START_TEST(test_timers__two_secs)
|
||||
{
|
||||
#define TOLERANCE 25 // Percent
|
||||
#define HALF_WAIT 1000 // A second
|
||||
struct timers_oneshot *timer = timers_oneshot_init(2 * HALF_WAIT);
|
||||
ck_assert_ptr_ne(timer, NULL);
|
||||
|
||||
// Wait for half the total period and check the elapsed timer is
|
||||
// within limits
|
||||
g_sleep(HALF_WAIT);
|
||||
int remaining = timers_oneshot_get_remaining(timer, g_get_elapsed_ms());
|
||||
|
||||
ck_assert_int_ge(remaining, HALF_WAIT - (HALF_WAIT * TOLERANCE / 100));
|
||||
ck_assert_int_le(remaining, HALF_WAIT + (HALF_WAIT * TOLERANCE / 100));
|
||||
|
||||
// Wait for the rest of the period and check the timer is zero (or near it)
|
||||
g_sleep(remaining);
|
||||
unsigned int now = g_get_elapsed_ms();
|
||||
int v = timers_oneshot_get_remaining(timer, now);
|
||||
ck_assert_int_ge(v, 0);
|
||||
ck_assert_int_le(v, 1);
|
||||
|
||||
// Check the timer is zero in the future
|
||||
v = timers_oneshot_get_remaining(timer, now + 1000); // Second
|
||||
ck_assert_int_eq(v, 0);
|
||||
v = timers_oneshot_get_remaining(timer, now + 3600 * 1000); // Hour
|
||||
ck_assert_int_eq(v, 0);
|
||||
v = timers_oneshot_get_remaining(timer, now + 86400 * 1000); // Day
|
||||
ck_assert_int_eq(v, 0);
|
||||
v = timers_oneshot_get_remaining(timer, now + 7 * 86400 * 1000); // Week
|
||||
ck_assert_int_eq(v, 0);
|
||||
|
||||
free(timer);
|
||||
#undef TOLERANCE
|
||||
#undef HALF_WAIT
|
||||
}
|
||||
END_TEST
|
||||
|
||||
/******************************************************************************/
|
||||
Suite *
|
||||
make_suite_test_timers(void)
|
||||
{
|
||||
Suite *s;
|
||||
TCase *tc_timers;
|
||||
|
||||
s = suite_create("timers");
|
||||
|
||||
tc_timers = tcase_create("timers");
|
||||
suite_add_tcase(s, tc_timers);
|
||||
tcase_add_test(tc_timers, test_timers__null_timer);
|
||||
tcase_add_test(tc_timers, test_timers__two_secs);
|
||||
|
||||
return s;
|
||||
}
|
||||
@@ -31,6 +31,7 @@ static const char *eds_status_msg[] =
|
||||
/* 1 */ "Resize is administratively prohibited",
|
||||
/* 2 */ "Out of resources",
|
||||
/* 3 */ "Invalid screen layout",
|
||||
/* 4 */ "Request forwarded",
|
||||
/* others */ "Unknown code"
|
||||
};
|
||||
|
||||
|
||||
@@ -80,6 +80,18 @@ enum sec_type
|
||||
#define RFBPROTO_VER_3_7 MAKE_RFBPROTO_VER(3,7)
|
||||
#define RFBPROTO_VER_3_8 MAKE_RFBPROTO_VER(3,8)
|
||||
|
||||
/*
|
||||
* ExtendedDesktopSize status codes
|
||||
*/
|
||||
enum
|
||||
{
|
||||
RFB_EDS_NO_ERROR = 0,
|
||||
RFB_EDS_ADMINISTRATIVELY_PROHIBITED = 1,
|
||||
RFB_EDS_OUT_OF_RESOURCES = 2,
|
||||
RFB_EDS_INVALID_SCREEN_LAYOUT = 3,
|
||||
RFB_EDS_REQUEST_FORWARDED = 4
|
||||
};
|
||||
|
||||
/**
|
||||
* Returns an error string for an ExtendedDesktopSize status code
|
||||
*/
|
||||
|
||||
@@ -38,6 +38,7 @@
|
||||
#include "vnc_clip.h"
|
||||
#include "rfb.h"
|
||||
#include "log.h"
|
||||
#include "timers.h"
|
||||
#include "trans.h"
|
||||
#include "ssl_calls.h"
|
||||
#include "string_calls.h"
|
||||
@@ -53,6 +54,12 @@ enum
|
||||
MSK_EXTENDED_DESKTOP_SIZE = (1 << 0)
|
||||
};
|
||||
|
||||
enum
|
||||
{
|
||||
/** Time to wait for a forwarded resize to complete */
|
||||
FORWARDED_RESIZE_TIMEOUT = 1500 /* milli-seconds */
|
||||
};
|
||||
|
||||
/******************************************************************************/
|
||||
int
|
||||
lib_send_copy(struct vnc *v, struct stream *s)
|
||||
@@ -309,7 +316,8 @@ send_set_desktop_size(struct vnc *v, const struct vnc_screen_layout *layout)
|
||||
out_uint32_be(s, layout->s[i].flags);
|
||||
}
|
||||
s_mark_end(s);
|
||||
LOG(LOG_LEVEL_DEBUG, "VNC Sending SetDesktopSize");
|
||||
LOG(LOG_LEVEL_DEBUG, "VNC_RESIZE: Sending SetDesktopSize %dx%d",
|
||||
layout->total_width, layout->total_height);
|
||||
error = lib_send_copy(v, s);
|
||||
free_stream(s);
|
||||
|
||||
@@ -954,7 +962,7 @@ skip_encoding(struct vnc *v, int x, int y, int cx, int cy,
|
||||
{
|
||||
struct vnc_screen_layout layout = {0};
|
||||
LOG(LOG_LEVEL_DEBUG,
|
||||
"Skipping RFB_ENC_EXTENDED_DESKTOP_SIZE encoding "
|
||||
"VNC_RESIZE: Skipping RFB_ENC_EXTENDED_DESKTOP_SIZE encoding "
|
||||
"x=%d, y=%d geom=%dx%d",
|
||||
x, y, cx, cy);
|
||||
error = read_extended_desktop_size_rect(v, &layout);
|
||||
@@ -1033,7 +1041,7 @@ find_matching_extended_rect(struct vnc *v,
|
||||
match(x, y, cx, cy))
|
||||
{
|
||||
LOG(LOG_LEVEL_DEBUG,
|
||||
"VNC matched ExtendedDesktopSize rectangle "
|
||||
"VNC_RESIZE: VNC matched ExtendedDesktopSize rectangle "
|
||||
"x=%d, y=%d geom=%dx%d",
|
||||
x, y, cx, cy);
|
||||
found = 1;
|
||||
@@ -1149,6 +1157,18 @@ rect_is_reply_to_us(int x, int y, int cx, int cy)
|
||||
return (x == 1);
|
||||
}
|
||||
|
||||
/**************************************************************************//**
|
||||
* Tests if extended desktop size rect is a general change.
|
||||
*
|
||||
* This happens when we are looking for a layout change that the
|
||||
* VNC server has reported as forwarded to the real desktop.
|
||||
*/
|
||||
static int
|
||||
rect_is_general_change(int x, int y, int cx, int cy)
|
||||
{
|
||||
return (x == 0);
|
||||
}
|
||||
|
||||
/**************************************************************************//**
|
||||
* Handles the first framebuffer update from the server
|
||||
*
|
||||
@@ -1249,9 +1269,21 @@ lib_framebuffer_waiting_for_resize_confirm(struct vnc *v)
|
||||
{
|
||||
if (layout.count > 0)
|
||||
{
|
||||
if (response_code == 0)
|
||||
if (response_code == RFB_EDS_REQUEST_FORWARDED)
|
||||
{
|
||||
LOG(LOG_LEVEL_DEBUG, "VNC server successfully resized");
|
||||
LOG(LOG_LEVEL_DEBUG, "VNC_RESIZE: VNC server resize forwarded");
|
||||
log_screen_layout(LOG_LEVEL_INFO, "ForwardedLayout", &layout);
|
||||
v->forward_timer =
|
||||
timers_oneshot_init(FORWARDED_RESIZE_TIMEOUT);
|
||||
v->forwarded_layout = layout;
|
||||
}
|
||||
else
|
||||
{
|
||||
// The resize has either succeeded or failed
|
||||
if (response_code == RFB_EDS_NO_ERROR)
|
||||
{
|
||||
LOG(LOG_LEVEL_DEBUG, "VNC_RESIZE:"
|
||||
" VNC server successfully resized");
|
||||
log_screen_layout(LOG_LEVEL_INFO, "NewLayout", &layout);
|
||||
v->server_layout = layout;
|
||||
}
|
||||
@@ -1261,35 +1293,114 @@ lib_framebuffer_waiting_for_resize_confirm(struct vnc *v)
|
||||
"VNC server resize failed - error code %d [%s]",
|
||||
response_code,
|
||||
rfb_get_eds_status_msg(response_code));
|
||||
// This is awkward. The client has asked for a specific size
|
||||
// which we can't support.
|
||||
// This is awkward. The client has asked for a
|
||||
// specific size which we can't support.
|
||||
//
|
||||
// Currently we handle this by queueing a resize to our
|
||||
// supported size, and continuing with the resize state
|
||||
// machine in xrdp_mm.c
|
||||
// Currently we handle this by queueing a resize
|
||||
// to our supported size, and continuing with the
|
||||
// resize state machine in xrdp_mm.c
|
||||
LOG(LOG_LEVEL_WARNING, "Resizing client to server");
|
||||
error = resize_client_to_server(v, 0);
|
||||
}
|
||||
|
||||
v->resize_status = VRS_DONE;
|
||||
if (error == 0)
|
||||
{
|
||||
// If this resize was requested by the client mid-session
|
||||
// (dynamic resize), we need to tell xrdp_mm that
|
||||
// it's OK to continue with the resize state machine.
|
||||
error = v->server_monitor_resize_done(v);
|
||||
}
|
||||
v->resize_status = VRS_DONE;
|
||||
}
|
||||
}
|
||||
|
||||
if (error == 0)
|
||||
{
|
||||
error = send_update_request_for_resize_status(v);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
return error;
|
||||
}
|
||||
|
||||
/**************************************************************************//**
|
||||
* Looks for the forwarded screen layout in a framebuffer update request
|
||||
*
|
||||
* Looks for an ExtendedDesktopSize rectangle following a notification
|
||||
* from the VNC server that the request has been forwarded to the real
|
||||
* desktop. See rfbproto/pfbproto#32 for more info.
|
||||
*
|
||||
* @param v VNC object
|
||||
* @return != 0 for error
|
||||
*/
|
||||
static int
|
||||
lib_framebuffer_look_for_forwarded_layout(struct vnc *v)
|
||||
{
|
||||
int error;
|
||||
struct vnc_screen_layout layout = {0};
|
||||
int x = 0;
|
||||
int y = 0;
|
||||
|
||||
error = find_matching_extended_rect(v,
|
||||
rect_is_general_change,
|
||||
&x,
|
||||
&y,
|
||||
&layout);
|
||||
if (error == 0)
|
||||
{
|
||||
if (layout.count > 0)
|
||||
{
|
||||
if (vnc_screen_layouts_equal(&layout, &v->forwarded_layout))
|
||||
{
|
||||
LOG(LOG_LEVEL_DEBUG,
|
||||
"VNC_RESIZE: VNC server forwarded resize complete");
|
||||
free(v->forward_timer);
|
||||
v->forward_timer = NULL;
|
||||
v->server_layout = layout;
|
||||
error = v->server_monitor_resize_done(v);
|
||||
v->resize_status = VRS_DONE;
|
||||
}
|
||||
else
|
||||
{
|
||||
LOG(LOG_LEVEL_DEBUG,
|
||||
"VNC_RESIZE: Ignored ExtendedDesktopSize %dx%d x=%d y=%d",
|
||||
layout.total_width, layout.total_height, x, y);
|
||||
// Delay for a little before we send another request for
|
||||
// the size
|
||||
g_sleep(100);
|
||||
}
|
||||
|
||||
error = send_update_request_for_resize_status(v);
|
||||
}
|
||||
}
|
||||
|
||||
return error;
|
||||
}
|
||||
|
||||
/******************************************************************************/
|
||||
/*
|
||||
* The VNC server has not actioned a forwarded resize request
|
||||
*/
|
||||
static int
|
||||
forward_timer_expired(struct vnc *v)
|
||||
{
|
||||
LOG(LOG_LEVEL_WARNING, "VNC server forwarded resize timed out");
|
||||
LOG(LOG_LEVEL_DEBUG,
|
||||
"VNC_RESIZE: VNC server forwarded resize timed out");
|
||||
free(v->forward_timer);
|
||||
v->forward_timer = NULL;
|
||||
v->resize_status = VRS_DONE;
|
||||
|
||||
int rv = v->server_monitor_resize_done(v);
|
||||
if (rv == 0)
|
||||
{
|
||||
LOG(LOG_LEVEL_WARNING, "Resizing client to server");
|
||||
rv = resize_client_to_server(v, 0);
|
||||
}
|
||||
|
||||
return rv;
|
||||
}
|
||||
|
||||
/******************************************************************************/
|
||||
static int
|
||||
lib_framebuffer_update(struct vnc *v)
|
||||
@@ -1433,6 +1544,9 @@ lib_framebuffer_update(struct vnc *v)
|
||||
layout.total_height = cy;
|
||||
error = read_extended_desktop_size_rect(v, &layout);
|
||||
/* If this is a reply to a request from us, x == 1 */
|
||||
LOG(LOG_LEVEL_DEBUG,
|
||||
"VNC_RESIZE: Read ExtendedDesktopSize %dx%d x=%d y=%d",
|
||||
layout.total_width, layout.total_height, x, y);
|
||||
if (error == 0 && x != 1)
|
||||
{
|
||||
if (!vnc_screen_layouts_equal(&v->server_layout, &layout))
|
||||
@@ -1574,7 +1688,14 @@ lib_mod_process_message(struct vnc *v, struct stream *s)
|
||||
break;
|
||||
|
||||
case VRS_WAITING_FOR_RESIZE_CONFIRM:
|
||||
if (v->forward_timer != NULL)
|
||||
{
|
||||
error = lib_framebuffer_look_for_forwarded_layout(v);
|
||||
}
|
||||
else
|
||||
{
|
||||
error = lib_framebuffer_waiting_for_resize_confirm(v);
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
@@ -2533,6 +2654,10 @@ lib_mod_get_wait_objs(struct vnc *v, tbus *read_objs, int *rcount,
|
||||
trans_get_wait_objs_rw(v->trans, read_objs, rcount,
|
||||
write_objs, wcount, timeout);
|
||||
}
|
||||
|
||||
// Update timeout with any active timers
|
||||
unsigned int now = g_get_elapsed_ms();
|
||||
timers_oneshot_update_poll(v->forward_timer, now, timeout);
|
||||
}
|
||||
|
||||
return 0;
|
||||
@@ -2550,13 +2675,22 @@ lib_mod_check_wait_objs(struct vnc *v)
|
||||
{
|
||||
if (v->trans != 0)
|
||||
{
|
||||
rv = trans_check_wait_objs(v->trans);
|
||||
if (rv != 0)
|
||||
if ((rv = trans_check_wait_objs(v->trans)) != 0)
|
||||
{
|
||||
LOG(LOG_LEVEL_ERROR, "VNC server closed connection");
|
||||
}
|
||||
else
|
||||
{
|
||||
// Check timers
|
||||
unsigned int now = g_get_elapsed_ms();
|
||||
if (timers_oneshot_get_remaining(v->forward_timer, now) == 0)
|
||||
{
|
||||
rv = forward_timer_expired(v);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return rv;
|
||||
}
|
||||
|
||||
|
||||
@@ -31,6 +31,8 @@
|
||||
|
||||
#define CURRENT_MOD_VER 4
|
||||
|
||||
struct timers_oneshot;
|
||||
|
||||
/* Screen used for ExtendedDesktopSize / Set DesktopSize */
|
||||
struct vnc_screen
|
||||
{
|
||||
@@ -188,6 +190,11 @@ struct vnc
|
||||
struct vnc_screen_layout server_layout;
|
||||
enum vnc_resize_status resize_status;
|
||||
enum vnc_resize_support_status resize_supported;
|
||||
/* forwarded resize */
|
||||
// This occurs when the VNC server forwards a resize request
|
||||
// elsewhere (RFB_EDS_REQUEST_FORWARDED)
|
||||
struct timers_oneshot *forward_timer;
|
||||
struct vnc_screen_layout forwarded_layout;
|
||||
};
|
||||
|
||||
/*
|
||||
|
||||
Reference in New Issue
Block a user