Merge pull request #206 from derfian/dynamic-resize
Dynamic session resize
This commit is contained in:
commit
3d9dccbc70
2
.gitignore
vendored
2
.gitignore
vendored
@ -1,6 +1,6 @@
|
|||||||
rdesktop
|
rdesktop
|
||||||
autom4te.cache
|
autom4te.cache
|
||||||
Makefile
|
/Makefile
|
||||||
config.log
|
config.log
|
||||||
config.status
|
config.status
|
||||||
configure
|
configure
|
||||||
|
7
proto.h
7
proto.h
@ -259,12 +259,12 @@ RD_BOOL get_key_state(unsigned int state, uint32 keysym);
|
|||||||
RD_BOOL ui_init(void);
|
RD_BOOL ui_init(void);
|
||||||
void ui_init_connection(void);
|
void ui_init_connection(void);
|
||||||
void ui_deinit(void);
|
void ui_deinit(void);
|
||||||
RD_BOOL ui_create_window(void);
|
RD_BOOL ui_create_window(uint32 width, uint32 height);
|
||||||
void ui_resize_window(void);
|
void ui_resize_window(uint32 width, uint32 height);
|
||||||
void ui_destroy_window(void);
|
void ui_destroy_window(void);
|
||||||
RD_BOOL ui_have_window(void);
|
RD_BOOL ui_have_window(void);
|
||||||
void xwin_toggle_fullscreen(void);
|
void xwin_toggle_fullscreen(void);
|
||||||
int ui_select(int rdp_socket);
|
void ui_select(int rdp_socket);
|
||||||
void ui_move_pointer(int x, int y);
|
void ui_move_pointer(int x, int y);
|
||||||
RD_HBITMAP ui_create_bitmap(int width, int height, uint8 * data);
|
RD_HBITMAP ui_create_bitmap(int width, int height, uint8 * data);
|
||||||
void ui_paint_bitmap(int x, int y, int cx, int cy, int width, int height, uint8 * data);
|
void ui_paint_bitmap(int x, int y, int cx, int cy, int width, int height, uint8 * data);
|
||||||
@ -329,6 +329,7 @@ void ui_seamless_ack(unsigned int serial);
|
|||||||
RD_BOOL lspci_init(void);
|
RD_BOOL lspci_init(void);
|
||||||
/* rdpedisp.c */
|
/* rdpedisp.c */
|
||||||
void rdpedisp_init(void);
|
void rdpedisp_init(void);
|
||||||
|
RD_BOOL rdpedisp_is_available();
|
||||||
void rdpedisp_set_session_size(uint32 width, uint32 height);
|
void rdpedisp_set_session_size(uint32 width, uint32 height);
|
||||||
/* dvc.c */
|
/* dvc.c */
|
||||||
typedef void (*dvc_channel_process_fn) (STREAM s);
|
typedef void (*dvc_channel_process_fn) (STREAM s);
|
||||||
|
36
rdesktop.c
36
rdesktop.c
@ -72,10 +72,13 @@ int g_sizeopt = 0; /* If non-zero, a special size has been
|
|||||||
from _NET_WORKAREA. If negative, absolute value
|
from _NET_WORKAREA. If negative, absolute value
|
||||||
specifies the percent of the whole screen. */
|
specifies the percent of the whole screen. */
|
||||||
int g_dpi = 0; /* device DPI: default not set */
|
int g_dpi = 0; /* device DPI: default not set */
|
||||||
int g_width = 1024;
|
|
||||||
int g_height = 768;
|
/* Following variables holds the initial width and height for a
|
||||||
uint32 g_windowed_width = 1024;
|
rdesktop window, this is sent upon connect and tells the server
|
||||||
uint32 g_windowed_height = 768;
|
what size of session we want to have. Set to decent defaults. */
|
||||||
|
uint32 g_initial_width = 1024;
|
||||||
|
uint32 g_initial_height = 768;
|
||||||
|
|
||||||
int g_xpos = 0;
|
int g_xpos = 0;
|
||||||
int g_ypos = 0;
|
int g_ypos = 0;
|
||||||
int g_pos = 0; /* 0 position unspecified,
|
int g_pos = 0; /* 0 position unspecified,
|
||||||
@ -712,17 +715,17 @@ main(int argc, char *argv[])
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
g_width = strtol(optarg, &p, 10);
|
g_initial_width = strtol(optarg, &p, 10);
|
||||||
if (g_width <= 0)
|
if (g_initial_width <= 0)
|
||||||
{
|
{
|
||||||
logger(Core, Error, "invalid geometry width specified");
|
logger(Core, Error, "invalid geometry width specified");
|
||||||
return EX_USAGE;
|
return EX_USAGE;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (*p == 'x')
|
if (*p == 'x')
|
||||||
g_height = strtol(p + 1, &p, 10);
|
g_initial_height = strtol(p + 1, &p, 10);
|
||||||
|
|
||||||
if (g_height <= 0)
|
if (g_initial_height <= 0)
|
||||||
{
|
{
|
||||||
logger(Core, Error, "invalid geometry height specified");
|
logger(Core, Error, "invalid geometry height specified");
|
||||||
return EX_USAGE;
|
return EX_USAGE;
|
||||||
@ -730,16 +733,16 @@ main(int argc, char *argv[])
|
|||||||
|
|
||||||
if (*p == '%')
|
if (*p == '%')
|
||||||
{
|
{
|
||||||
g_sizeopt = -g_width;
|
g_sizeopt = -g_initial_width;
|
||||||
g_width = g_sizeopt;
|
g_initial_width = g_sizeopt;
|
||||||
|
|
||||||
if (*(p + 1) == 'x')
|
if (*(p + 1) == 'x')
|
||||||
{
|
{
|
||||||
g_height = -strtol(p + 2, &p, 10);
|
g_initial_height = -strtol(p + 2, &p, 10);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
g_height = g_sizeopt;
|
g_initial_height = g_sizeopt;
|
||||||
}
|
}
|
||||||
|
|
||||||
p++;
|
p++;
|
||||||
@ -767,9 +770,6 @@ main(int argc, char *argv[])
|
|||||||
g_ypos = strtol(p, NULL, 10);
|
g_ypos = strtol(p, NULL, 10);
|
||||||
}
|
}
|
||||||
|
|
||||||
g_windowed_height = g_height;
|
|
||||||
g_windowed_width = g_width;
|
|
||||||
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 'f':
|
case 'f':
|
||||||
@ -1240,6 +1240,8 @@ main(int argc, char *argv[])
|
|||||||
}
|
}
|
||||||
|
|
||||||
ui_init_connection();
|
ui_init_connection();
|
||||||
|
utils_apply_session_size_limitations(&g_initial_width, &g_initial_height);
|
||||||
|
|
||||||
if (!rdp_connect
|
if (!rdp_connect
|
||||||
(server, flags, domain, g_password, shell, directory, g_reconnect_loop))
|
(server, flags, domain, g_password, shell, directory, g_reconnect_loop))
|
||||||
{
|
{
|
||||||
@ -1307,6 +1309,8 @@ main(int argc, char *argv[])
|
|||||||
/* Enter a reconnect loop if we have a pending resize request */
|
/* Enter a reconnect loop if we have a pending resize request */
|
||||||
if (g_pending_resize)
|
if (g_pending_resize)
|
||||||
{
|
{
|
||||||
|
logger(Core, Verbose, "Resize reconnect loop triggered, new size %dx%d",
|
||||||
|
g_initial_width, g_initial_height);
|
||||||
g_pending_resize = False;
|
g_pending_resize = False;
|
||||||
g_reconnect_loop = True;
|
g_reconnect_loop = True;
|
||||||
continue;
|
continue;
|
||||||
@ -1839,7 +1843,7 @@ rd_create_ui()
|
|||||||
if (!ui_have_window())
|
if (!ui_have_window())
|
||||||
{
|
{
|
||||||
/* create a window if we don't have one initialized */
|
/* create a window if we don't have one initialized */
|
||||||
if (!ui_create_window())
|
if (!ui_create_window(g_initial_width, g_initial_height))
|
||||||
exit(EX_OSERR);
|
exit(EX_OSERR);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
76
rdp.c
76
rdp.c
@ -43,13 +43,16 @@ extern RDP_VERSION g_rdp_version;
|
|||||||
extern uint16 g_server_rdp_version;
|
extern uint16 g_server_rdp_version;
|
||||||
extern uint32 g_rdp5_performanceflags;
|
extern uint32 g_rdp5_performanceflags;
|
||||||
extern int g_server_depth;
|
extern int g_server_depth;
|
||||||
extern int g_width;
|
extern uint32 g_initial_width;
|
||||||
extern int g_height;
|
extern uint32 g_initial_height;
|
||||||
extern RD_BOOL g_bitmap_cache;
|
extern RD_BOOL g_bitmap_cache;
|
||||||
extern RD_BOOL g_bitmap_cache_persist_enable;
|
extern RD_BOOL g_bitmap_cache_persist_enable;
|
||||||
extern RD_BOOL g_numlock_sync;
|
extern RD_BOOL g_numlock_sync;
|
||||||
extern RD_BOOL g_pending_resize;
|
extern RD_BOOL g_pending_resize;
|
||||||
extern RD_BOOL g_network_error;
|
extern RD_BOOL g_network_error;
|
||||||
|
extern time_t g_wait_for_deactivate_ts;
|
||||||
|
|
||||||
|
RD_BOOL g_exit_mainloop = False;
|
||||||
|
|
||||||
uint8 *g_next_packet;
|
uint8 *g_next_packet;
|
||||||
uint32 g_rdp_shareid;
|
uint32 g_rdp_shareid;
|
||||||
@ -80,6 +83,11 @@ extern RD_BOOL g_has_reconnect_random;
|
|||||||
extern uint8 g_client_random[SEC_RANDOM_SIZE];
|
extern uint8 g_client_random[SEC_RANDOM_SIZE];
|
||||||
static uint32 g_packetno;
|
static uint32 g_packetno;
|
||||||
|
|
||||||
|
|
||||||
|
/* holds the actual session size reported by server */
|
||||||
|
uint16 g_session_width;
|
||||||
|
uint16 g_session_height;
|
||||||
|
|
||||||
static void rdp_out_unistr(STREAM s, char *string, int len);
|
static void rdp_out_unistr(STREAM s, char *string, int len);
|
||||||
|
|
||||||
/* Receive an RDP packet */
|
/* Receive an RDP packet */
|
||||||
@ -553,11 +561,11 @@ rdp_send_suppress_output_pdu(enum RDP_SUPPRESS_STATUS allowupdates)
|
|||||||
case SUPPRESS_DISPLAY_UPDATES: /* shut the server up */
|
case SUPPRESS_DISPLAY_UPDATES: /* shut the server up */
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case ALLOW_DISPLAY_UPDATES: /* receive data again */
|
case ALLOW_DISPLAY_UPDATES: /* receive data again */
|
||||||
out_uint16_le(s, 0); /* left */
|
out_uint16_le(s, 0); /* left */
|
||||||
out_uint16_le(s, 0); /* top */
|
out_uint16_le(s, 0); /* top */
|
||||||
out_uint16_le(s, g_width); /* right */
|
out_uint16_le(s, g_session_width); /* right */
|
||||||
out_uint16_le(s, g_height); /* bottom */
|
out_uint16_le(s, g_session_height); /* bottom */
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -659,14 +667,16 @@ rdp_out_ts_general_capabilityset(STREAM s)
|
|||||||
static void
|
static void
|
||||||
rdp_out_ts_bitmap_capabilityset(STREAM s)
|
rdp_out_ts_bitmap_capabilityset(STREAM s)
|
||||||
{
|
{
|
||||||
|
logger(Protocol, Debug, "rdp_out_ts_bitmap_capabilityset(), %dx%d",
|
||||||
|
g_session_width, g_session_height);
|
||||||
out_uint16_le(s, RDP_CAPSET_BITMAP);
|
out_uint16_le(s, RDP_CAPSET_BITMAP);
|
||||||
out_uint16_le(s, RDP_CAPLEN_BITMAP);
|
out_uint16_le(s, RDP_CAPLEN_BITMAP);
|
||||||
out_uint16_le(s, g_server_depth); /* preferredBitsPerPixel */
|
out_uint16_le(s, g_server_depth); /* preferredBitsPerPixel */
|
||||||
out_uint16_le(s, 1); /* receive1BitPerPixel (ignored, should be 1) */
|
out_uint16_le(s, 1); /* receive1BitPerPixel (ignored, should be 1) */
|
||||||
out_uint16_le(s, 1); /* receive4BitPerPixel (ignored, should be 1) */
|
out_uint16_le(s, 1); /* receive4BitPerPixel (ignored, should be 1) */
|
||||||
out_uint16_le(s, 1); /* receive8BitPerPixel (ignored, should be 1) */
|
out_uint16_le(s, 1); /* receive8BitPerPixel (ignored, should be 1) */
|
||||||
out_uint16_le(s, g_width); /* desktopWidth */
|
out_uint16_le(s, g_session_width); /* desktopWidth */
|
||||||
out_uint16_le(s, g_height); /* desktopHeight */
|
out_uint16_le(s, g_session_height); /* desktopHeight */
|
||||||
out_uint16_le(s, 0); /* pad2Octets */
|
out_uint16_le(s, 0); /* pad2Octets */
|
||||||
out_uint16_le(s, 1); /* desktopResizeFlag */
|
out_uint16_le(s, 1); /* desktopResizeFlag */
|
||||||
out_uint16_le(s, 1); /* bitmapCompressionFlag (must be 1) */
|
out_uint16_le(s, 1); /* bitmapCompressionFlag (must be 1) */
|
||||||
@ -1051,17 +1061,17 @@ rdp_process_general_caps(STREAM s)
|
|||||||
static void
|
static void
|
||||||
rdp_process_bitmap_caps(STREAM s)
|
rdp_process_bitmap_caps(STREAM s)
|
||||||
{
|
{
|
||||||
uint16 width, height, depth;
|
uint16 depth;
|
||||||
|
|
||||||
in_uint16_le(s, depth);
|
in_uint16_le(s, depth);
|
||||||
in_uint8s(s, 6);
|
in_uint8s(s, 6);
|
||||||
|
|
||||||
in_uint16_le(s, width);
|
in_uint16_le(s, g_session_width);
|
||||||
in_uint16_le(s, height);
|
in_uint16_le(s, g_session_height);
|
||||||
|
|
||||||
logger(Protocol, Debug,
|
logger(Protocol, Debug,
|
||||||
"rdp_process_bitmap_caps(), setting desktop size and depth to: %dx%dx%d", width,
|
"rdp_process_bitmap_caps(), setting desktop size and depth to: %dx%dx%d",
|
||||||
height, depth);
|
g_session_width, g_session_height, depth);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* The server may limit depth and change the size of the desktop (for
|
* The server may limit depth and change the size of the desktop (for
|
||||||
@ -1074,15 +1084,11 @@ rdp_process_bitmap_caps(STREAM s)
|
|||||||
g_server_depth, depth);
|
g_server_depth, depth);
|
||||||
g_server_depth = depth;
|
g_server_depth = depth;
|
||||||
}
|
}
|
||||||
if (g_width != width || g_height != height)
|
|
||||||
{
|
/* resize viewport window to new session size, this is an
|
||||||
logger(Protocol, Debug,
|
no-op if there is no change in size between session size
|
||||||
"rdp_process_bitmap_caps(), remote desktop changed from %dx%d to %dx%d.\n",
|
reported from server and the actual window size */
|
||||||
g_width, g_height, width, height);
|
ui_resize_window(g_session_width, g_session_height);
|
||||||
g_width = width;
|
|
||||||
g_height = height;
|
|
||||||
ui_resize_window();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Process server capabilities */
|
/* Process server capabilities */
|
||||||
@ -1790,20 +1796,23 @@ process_redirect_pdu(STREAM s, RD_BOOL enhanced_redirect /*, uint32 * ext_disc_r
|
|||||||
"process_redirect_pdu(), unhandled LB_TARGET_CERTIFICATE");
|
"process_redirect_pdu(), unhandled LB_TARGET_CERTIFICATE");
|
||||||
}
|
}
|
||||||
|
|
||||||
return True;
|
return g_redirect;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Process incoming packets */
|
/* Process incoming packets */
|
||||||
void
|
void
|
||||||
rdp_main_loop(RD_BOOL * deactivated, uint32 * ext_disc_reason)
|
rdp_main_loop(RD_BOOL * deactivated, uint32 * ext_disc_reason)
|
||||||
{
|
{
|
||||||
while (rdp_loop(deactivated, ext_disc_reason))
|
do
|
||||||
{
|
{
|
||||||
if (g_pending_resize || g_redirect)
|
if (rdp_loop(deactivated, ext_disc_reason) == False)
|
||||||
{
|
{
|
||||||
return;
|
g_exit_mainloop = True;
|
||||||
}
|
}
|
||||||
}
|
} while(g_exit_mainloop == False);
|
||||||
|
|
||||||
|
/* clear the exit main loop flag */
|
||||||
|
g_exit_mainloop = False;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* used in uiports and rdp_main_loop, processes the RDP packets waiting */
|
/* used in uiports and rdp_main_loop, processes the RDP packets waiting */
|
||||||
@ -1814,7 +1823,7 @@ rdp_loop(RD_BOOL * deactivated, uint32 * ext_disc_reason)
|
|||||||
RD_BOOL cont = True;
|
RD_BOOL cont = True;
|
||||||
STREAM s;
|
STREAM s;
|
||||||
|
|
||||||
while (cont)
|
while (g_exit_mainloop == False && cont)
|
||||||
{
|
{
|
||||||
s = rdp_recv(&type);
|
s = rdp_recv(&type);
|
||||||
if (s == NULL)
|
if (s == NULL)
|
||||||
@ -1829,12 +1838,15 @@ rdp_loop(RD_BOOL * deactivated, uint32 * ext_disc_reason)
|
|||||||
logger(Protocol, Debug,
|
logger(Protocol, Debug,
|
||||||
"rdp_loop(), RDP_PDU_DEACTIVATE packet received");
|
"rdp_loop(), RDP_PDU_DEACTIVATE packet received");
|
||||||
*deactivated = True;
|
*deactivated = True;
|
||||||
|
g_wait_for_deactivate_ts = 0;
|
||||||
break;
|
break;
|
||||||
case RDP_PDU_REDIRECT:
|
case RDP_PDU_REDIRECT:
|
||||||
return process_redirect_pdu(s, False);
|
|
||||||
break;
|
|
||||||
case RDP_PDU_ENHANCED_REDIRECT:
|
case RDP_PDU_ENHANCED_REDIRECT:
|
||||||
return process_redirect_pdu(s, True);
|
if (process_redirect_pdu(s, !(type == RDP_PDU_REDIRECT)) == True)
|
||||||
|
{
|
||||||
|
g_exit_mainloop = True;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
case RDP_PDU_DATA:
|
case RDP_PDU_DATA:
|
||||||
/* If we got a data PDU, we don't need to keep the password in memory
|
/* If we got a data PDU, we don't need to keep the password in memory
|
||||||
|
11
rdpedisp.c
11
rdpedisp.c
@ -26,6 +26,8 @@
|
|||||||
#define DISPLAYCONTROL_MONITOR_PRIMARY 0x1
|
#define DISPLAYCONTROL_MONITOR_PRIMARY 0x1
|
||||||
#define RDPEDISP_CHANNEL_NAME "Microsoft::Windows::RDS::DisplayControl"
|
#define RDPEDISP_CHANNEL_NAME "Microsoft::Windows::RDS::DisplayControl"
|
||||||
|
|
||||||
|
extern int g_dpi;
|
||||||
|
|
||||||
static void rdpedisp_send(STREAM s);
|
static void rdpedisp_send(STREAM s);
|
||||||
static void rdpedisp_init_packet(STREAM s, uint32 type, uint32 length);
|
static void rdpedisp_init_packet(STREAM s, uint32 type, uint32 length);
|
||||||
|
|
||||||
@ -89,7 +91,9 @@ rdpedisp_send_monitor_layout_pdu(uint32 width, uint32 height)
|
|||||||
out_uint32_le(&s, width); /* width */
|
out_uint32_le(&s, width); /* width */
|
||||||
out_uint32_le(&s, height); /* height */
|
out_uint32_le(&s, height); /* height */
|
||||||
|
|
||||||
utils_calculate_dpi_scale_factors(&physwidth, &physheight, &desktopscale, &devicescale);
|
utils_calculate_dpi_scale_factors(width, height, g_dpi,
|
||||||
|
&physwidth, &physheight, &desktopscale, &devicescale);
|
||||||
|
|
||||||
out_uint32_le(&s, physwidth); /* physicalwidth */
|
out_uint32_le(&s, physwidth); /* physicalwidth */
|
||||||
out_uint32_le(&s, physheight); /* physicalheight */
|
out_uint32_le(&s, physheight); /* physicalheight */
|
||||||
out_uint32_le(&s, ORIENTATION_LANDSCAPE); /* Orientation */
|
out_uint32_le(&s, ORIENTATION_LANDSCAPE); /* Orientation */
|
||||||
@ -116,7 +120,7 @@ rdpedisp_send(STREAM s)
|
|||||||
dvc_send(RDPEDISP_CHANNEL_NAME, s);
|
dvc_send(RDPEDISP_CHANNEL_NAME, s);
|
||||||
}
|
}
|
||||||
|
|
||||||
static RD_BOOL
|
RD_BOOL
|
||||||
rdpedisp_is_available()
|
rdpedisp_is_available()
|
||||||
{
|
{
|
||||||
return dvc_channels_is_available(RDPEDISP_CHANNEL_NAME);
|
return dvc_channels_is_available(RDPEDISP_CHANNEL_NAME);
|
||||||
@ -128,6 +132,9 @@ rdpedisp_set_session_size(uint32 width, uint32 height)
|
|||||||
if (rdpedisp_is_available() == False)
|
if (rdpedisp_is_available() == False)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
/* monitor width MUST be even number */
|
||||||
|
utils_apply_session_size_limitations(&width, &height);
|
||||||
|
|
||||||
rdpedisp_send_monitor_layout_pdu(width, height);
|
rdpedisp_send_monitor_layout_pdu(width, height);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
11
secure.c
11
secure.c
@ -23,8 +23,8 @@
|
|||||||
#include "ssl.h"
|
#include "ssl.h"
|
||||||
|
|
||||||
extern char g_hostname[16];
|
extern char g_hostname[16];
|
||||||
extern int g_width;
|
extern uint32 g_initial_width;
|
||||||
extern int g_height;
|
extern uint32 g_initial_height;
|
||||||
extern int g_dpi;
|
extern int g_dpi;
|
||||||
extern unsigned int g_keylayout;
|
extern unsigned int g_keylayout;
|
||||||
extern int g_keyboard_type;
|
extern int g_keyboard_type;
|
||||||
@ -426,8 +426,8 @@ sec_out_mcs_connect_initial_pdu(STREAM s, uint32 selected_protocol)
|
|||||||
out_uint16_le(s, CS_CORE); /* type */
|
out_uint16_le(s, CS_CORE); /* type */
|
||||||
out_uint16_le(s, 216 + (g_dpi > 0 ? 18 : 0)); /* length */
|
out_uint16_le(s, 216 + (g_dpi > 0 ? 18 : 0)); /* length */
|
||||||
out_uint32_le(s, rdpversion); /* version */
|
out_uint32_le(s, rdpversion); /* version */
|
||||||
out_uint16_le(s, g_width); /* desktopWidth */
|
out_uint16_le(s, g_initial_width); /* desktopWidth */
|
||||||
out_uint16_le(s, g_height); /* desktopHeight */
|
out_uint16_le(s, g_initial_height); /* desktopHeight */
|
||||||
out_uint16_le(s, RNS_UD_COLOR_8BPP); /* colorDepth */
|
out_uint16_le(s, RNS_UD_COLOR_8BPP); /* colorDepth */
|
||||||
out_uint16_le(s, RNS_UD_SAS_DEL); /* SASSequence */
|
out_uint16_le(s, RNS_UD_SAS_DEL); /* SASSequence */
|
||||||
out_uint32_le(s, g_keylayout); /* keyboardLayout */
|
out_uint32_le(s, g_keylayout); /* keyboardLayout */
|
||||||
@ -459,7 +459,8 @@ sec_out_mcs_connect_initial_pdu(STREAM s, uint32 selected_protocol)
|
|||||||
if (g_dpi > 0)
|
if (g_dpi > 0)
|
||||||
{
|
{
|
||||||
/* Extended client info describing monitor geometry */
|
/* Extended client info describing monitor geometry */
|
||||||
utils_calculate_dpi_scale_factors(&physwidth, &physheight,
|
utils_calculate_dpi_scale_factors(g_initial_width, g_initial_height, g_dpi,
|
||||||
|
&physwidth, &physheight,
|
||||||
&desktopscale, &devicescale);
|
&desktopscale, &devicescale);
|
||||||
out_uint32_le(s, physwidth); /* physicalwidth */
|
out_uint32_le(s, physwidth); /* physicalwidth */
|
||||||
out_uint32_le(s, physheight); /* physicalheight */
|
out_uint32_le(s, physheight); /* physicalheight */
|
||||||
|
13
tcp.c
13
tcp.c
@ -66,7 +66,8 @@ static RD_BOOL g_run_ui = False;
|
|||||||
static struct stream g_in;
|
static struct stream g_in;
|
||||||
static struct stream g_out[STREAM_COUNT];
|
static struct stream g_out[STREAM_COUNT];
|
||||||
int g_tcp_port_rdp = TCP_PORT_RDP;
|
int g_tcp_port_rdp = TCP_PORT_RDP;
|
||||||
extern RD_BOOL g_user_quit;
|
|
||||||
|
extern RD_BOOL g_exit_mainloop;
|
||||||
extern RD_BOOL g_network_error;
|
extern RD_BOOL g_network_error;
|
||||||
extern RD_BOOL g_reconnect_loop;
|
extern RD_BOOL g_reconnect_loop;
|
||||||
|
|
||||||
@ -220,12 +221,12 @@ tcp_recv(STREAM s, uint32 length)
|
|||||||
{
|
{
|
||||||
if ((!g_ssl || SSL_pending(g_ssl) <= 0) && g_run_ui)
|
if ((!g_ssl || SSL_pending(g_ssl) <= 0) && g_run_ui)
|
||||||
{
|
{
|
||||||
if (!ui_select(g_sock))
|
ui_select(g_sock);
|
||||||
{
|
|
||||||
/* User quit */
|
/* break out of recv, if request of exiting
|
||||||
g_user_quit = True;
|
main loop has been done */
|
||||||
|
if (g_exit_mainloop == True)
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (g_ssl)
|
if (g_ssl)
|
||||||
|
49
tests/Makefile
Normal file
49
tests/Makefile
Normal file
@ -0,0 +1,49 @@
|
|||||||
|
CC=gcc
|
||||||
|
CFLAGS=-fPIC -Wall -Wextra -ggdb -gdwarf-2 -g3
|
||||||
|
CGREEN_RUNNER=cgreen-runner
|
||||||
|
|
||||||
|
TESTS=resize rdp xwin utils
|
||||||
|
|
||||||
|
|
||||||
|
RDP_MOCKS=ui_mock.o bitmap_mock.o secure_mock.o ssl_mock.o mppc_mock.o \
|
||||||
|
cache_mock.o pstcache_mock.o orders_mock.o rdesktop_mock.o \
|
||||||
|
rdp5_mock.o xkeymap_mock.o tcp_mock.o
|
||||||
|
|
||||||
|
XWIN_MOCKS=x11_mock.o cache_mock.o xclip_mock.o xkeymap_mock.o seamless_mock.o \
|
||||||
|
ctrl_mock.o rdpdr_mock.o ewmh_mock.o rdpedisp_mock.o rdp_mock.o
|
||||||
|
|
||||||
|
UTILS_MOCKS=
|
||||||
|
|
||||||
|
RESIZE_MOCKS=x11_mock.o cache_mock.o xclip_mock.o xkeymap_mock.o seamless_mock.o \
|
||||||
|
ctrl_mock.o rdpdr_mock.o ewmh_mock.o rdpedisp_mock.o bitmap_mock.o \
|
||||||
|
ssl_mock.o mppc_mock.o pstcache_mock.o orders_mock.o rdesktop_mock.o rdp5_mock.o \
|
||||||
|
tcp_mock.o licence_mock.o mcs_mock.o channels_mock.o
|
||||||
|
|
||||||
|
|
||||||
|
all: test
|
||||||
|
|
||||||
|
.PHONY: test
|
||||||
|
test: $(foreach test, $(TESTS), runtest.$(test))
|
||||||
|
|
||||||
|
|
||||||
|
.PHONY: runtest.%
|
||||||
|
runtest.%: %
|
||||||
|
$(CGREEN_RUNNER) $^
|
||||||
|
|
||||||
|
|
||||||
|
rdp: rdp_test.o $(RDP_MOCKS)
|
||||||
|
$(CC) $(CFLAGS) -shared -lcgreen -o $@ $^
|
||||||
|
|
||||||
|
xwin: xwin_test.o $(XWIN_MOCKS)
|
||||||
|
$(CC) $(CFLAGS) -shared -lcgreen -o $@ $^ -lX11 -lXcursor
|
||||||
|
|
||||||
|
utils: utils_test.o $(UTILS_MOCKS)
|
||||||
|
$(CC) $(CFLAGS) -shared -lcgreen -o $@ $^
|
||||||
|
|
||||||
|
resize: resize_test.o $(RESIZE_MOCKS)
|
||||||
|
$(CC) $(CFLAGS) -shared -lcgreen -o $@ $^ -lX11 -lXcursor
|
||||||
|
|
||||||
|
|
||||||
|
.PHONY: clean
|
||||||
|
clean:
|
||||||
|
rm -f $(TESTS) *_mock.o *_test.o
|
26
tests/README.md
Normal file
26
tests/README.md
Normal file
@ -0,0 +1,26 @@
|
|||||||
|
# Automated test suite
|
||||||
|
|
||||||
|
An basic test suite was added while implementing the dynamic resize
|
||||||
|
feature. Improvements to this test suite are very welcome.
|
||||||
|
|
||||||
|
|
||||||
|
## Requirements
|
||||||
|
|
||||||
|
In addition to the build requirements of rdesktop itself, you also need:
|
||||||
|
|
||||||
|
* [cgreen](https://github.com/cgreen-devs/cgreen)
|
||||||
|
|
||||||
|
|
||||||
|
## Building and running the tests
|
||||||
|
|
||||||
|
cd tests
|
||||||
|
make
|
||||||
|
|
||||||
|
This will build and run each test in turn. Re-running `make` will
|
||||||
|
recompile the tests as necessary, and run them again.
|
||||||
|
|
||||||
|
|
||||||
|
## Cgreen documentation
|
||||||
|
|
||||||
|
You can find the Cgreen documentation over
|
||||||
|
at [their github site](https://cgreen-devs.github.io).
|
7
tests/bitmap_mock.c
Normal file
7
tests/bitmap_mock.c
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
#include <cgreen/mocks.h>
|
||||||
|
#include "../rdesktop.h"
|
||||||
|
|
||||||
|
RD_BOOL bitmap_decompress(uint8 * output, int width, int height, uint8 * input, int size, int Bpp)
|
||||||
|
{
|
||||||
|
return mock(output, width, height, input, size, Bpp);
|
||||||
|
};
|
46
tests/cache_mock.c
Normal file
46
tests/cache_mock.c
Normal file
@ -0,0 +1,46 @@
|
|||||||
|
#include <cgreen/mocks.h>
|
||||||
|
#include "../rdesktop.h"
|
||||||
|
|
||||||
|
RD_HCURSOR
|
||||||
|
cache_get_cursor(uint16 cache_idx)
|
||||||
|
{
|
||||||
|
return (RD_HCURSOR)mock(cache_idx);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
cache_put_cursor(uint16 cache_idx, RD_HCURSOR cursor)
|
||||||
|
{
|
||||||
|
mock(cache_idx, cursor);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
FONTGLYPH *
|
||||||
|
cache_get_font(uint8 font, uint16 character)
|
||||||
|
{
|
||||||
|
return (FONTGLYPH *) mock(font, character);
|
||||||
|
}
|
||||||
|
|
||||||
|
DATABLOB *
|
||||||
|
cache_get_text(uint8 cache_id)
|
||||||
|
{
|
||||||
|
return (DATABLOB *)mock(cache_id);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
cache_put_text(uint8 cache_id, void *data, int length)
|
||||||
|
{
|
||||||
|
mock(cache_id, data, length);
|
||||||
|
}
|
||||||
|
|
||||||
|
uint8 *
|
||||||
|
cache_get_desktop(uint32 offset, int cx, int cy, int bytes_per_pixel)
|
||||||
|
{
|
||||||
|
return (uint8 *) mock(offset, cx, cy, bytes_per_pixel);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
cache_put_desktop(uint32 offset, int cx, int cy, int scanline,
|
||||||
|
int bytes_per_pixel, uint8 * data)
|
||||||
|
{
|
||||||
|
mock(offset, cx, cy, scanline, bytes_per_pixel, data);
|
||||||
|
}
|
7
tests/channels_mock.c
Normal file
7
tests/channels_mock.c
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
#include <cgreen/mocks.h>
|
||||||
|
#include "../rdesktop.h"
|
||||||
|
|
||||||
|
void channel_process(STREAM s, uint16 mcs_channel)
|
||||||
|
{
|
||||||
|
mock(s, mcs_channel);
|
||||||
|
}
|
14
tests/ctrl_mock.c
Normal file
14
tests/ctrl_mock.c
Normal file
@ -0,0 +1,14 @@
|
|||||||
|
#include <cgreen/mocks.h>
|
||||||
|
#include "../rdesktop.h"
|
||||||
|
|
||||||
|
void
|
||||||
|
ctrl_add_fds(int *n, fd_set * rfds)
|
||||||
|
{
|
||||||
|
mock(n, rfds);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
ctrl_check_fds(fd_set * rfds, fd_set * wfds)
|
||||||
|
{
|
||||||
|
mock(rfds, wfds);
|
||||||
|
}
|
26
tests/dvc_mock.c
Normal file
26
tests/dvc_mock.c
Normal file
@ -0,0 +1,26 @@
|
|||||||
|
#include <cgreen/mocks.h>
|
||||||
|
#include "../rdesktop.h"
|
||||||
|
|
||||||
|
RD_BOOL
|
||||||
|
dvc_init(void)
|
||||||
|
{
|
||||||
|
return mock();
|
||||||
|
}
|
||||||
|
|
||||||
|
RD_BOOL
|
||||||
|
dvc_channels_register(const char *name, dvc_channel_process_fn handler)
|
||||||
|
{
|
||||||
|
return mock(name, handler);
|
||||||
|
}
|
||||||
|
|
||||||
|
RD_BOOL
|
||||||
|
dvc_channels_is_available(const char *name)
|
||||||
|
{
|
||||||
|
return mock(name);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
dvc_send(const char *name, STREAM s)
|
||||||
|
{
|
||||||
|
mock(name, s);
|
||||||
|
}
|
87
tests/ewmh_mock.c
Normal file
87
tests/ewmh_mock.c
Normal file
@ -0,0 +1,87 @@
|
|||||||
|
#include <cgreen/mocks.h>
|
||||||
|
#include "../rdesktop.h"
|
||||||
|
#include <X11/Xlib.h>
|
||||||
|
|
||||||
|
int
|
||||||
|
ewmh_get_window_state(Window w)
|
||||||
|
{
|
||||||
|
return mock(w);
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
ewmh_change_state(Window wnd, int state)
|
||||||
|
{
|
||||||
|
return mock(wnd, state);
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
ewmh_move_to_desktop(Window wnd, unsigned int desktop)
|
||||||
|
{
|
||||||
|
return mock(wnd, desktop);
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
ewmh_get_window_desktop(Window wnd)
|
||||||
|
{
|
||||||
|
return mock(wnd);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
ewmh_set_wm_name(Window wnd, const char *title)
|
||||||
|
{
|
||||||
|
mock(wnd, title);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
ewmh_set_wm_pid(Window wnd, pid_t pid)
|
||||||
|
{
|
||||||
|
mock(wnd, pid);
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
ewmh_set_window_popup(Window wnd)
|
||||||
|
{
|
||||||
|
return mock(wnd);
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
ewmh_set_window_modal(Window wnd)
|
||||||
|
{
|
||||||
|
return mock(wnd);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
ewmh_set_icon(Window wnd, int width, int height, const char *rgba_data)
|
||||||
|
{
|
||||||
|
mock(wnd, width, height, rgba_data);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
ewmh_del_icon(Window wnd, int width, int height)
|
||||||
|
{
|
||||||
|
mock(wnd, width, height);
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
ewmh_set_window_above(Window wnd)
|
||||||
|
{
|
||||||
|
return mock(wnd);
|
||||||
|
}
|
||||||
|
|
||||||
|
RD_BOOL
|
||||||
|
ewmh_is_window_above(Window w)
|
||||||
|
{
|
||||||
|
return mock(w);
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
get_current_workarea(uint32 *x, uint32 *y, uint32 *width, uint32 *height)
|
||||||
|
{
|
||||||
|
return mock(x, y, width, height);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
ewmh_init()
|
||||||
|
{
|
||||||
|
mock();
|
||||||
|
}
|
9
tests/licence_mock.c
Normal file
9
tests/licence_mock.c
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
#include <cgreen/mocks.h>
|
||||||
|
#include "../rdesktop.h"
|
||||||
|
|
||||||
|
|
||||||
|
void
|
||||||
|
licence_process(STREAM s)
|
||||||
|
{
|
||||||
|
mock(s);
|
||||||
|
}
|
51
tests/mcs_mock.c
Normal file
51
tests/mcs_mock.c
Normal file
@ -0,0 +1,51 @@
|
|||||||
|
#include <cgreen/mocks.h>
|
||||||
|
#include "../rdesktop.h"
|
||||||
|
|
||||||
|
STREAM
|
||||||
|
mcs_init(int length)
|
||||||
|
{
|
||||||
|
return (STREAM)mock(length);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
mcs_send_to_channel(STREAM s, uint16 channel)
|
||||||
|
{
|
||||||
|
mock(s, channel);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
mcs_send(STREAM s)
|
||||||
|
{
|
||||||
|
mock(s);
|
||||||
|
}
|
||||||
|
|
||||||
|
STREAM
|
||||||
|
mcs_recv(uint16 * channel, uint8 * rdpver)
|
||||||
|
{
|
||||||
|
return (STREAM)mock(channel, rdpver);
|
||||||
|
}
|
||||||
|
|
||||||
|
RD_BOOL
|
||||||
|
mcs_connect_start(char *server, char *username, char *domain, char *password,
|
||||||
|
RD_BOOL reconnect, uint32 * selected_protocol)
|
||||||
|
{
|
||||||
|
return mock(server,username,domain,password,reconnect,selected_protocol);
|
||||||
|
}
|
||||||
|
|
||||||
|
RD_BOOL
|
||||||
|
mcs_connect_finalize(STREAM s)
|
||||||
|
{
|
||||||
|
return mock(s);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
mcs_disconnect(void)
|
||||||
|
{
|
||||||
|
mock();
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
mcs_reset_state(void)
|
||||||
|
{
|
||||||
|
mock();
|
||||||
|
}
|
8
tests/mppc_mock.c
Normal file
8
tests/mppc_mock.c
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
#include <cgreen/mocks.h>
|
||||||
|
#include "../rdesktop.h"
|
||||||
|
|
||||||
|
int
|
||||||
|
mppc_expand(uint8 * data, uint32 clen, uint8 ctype, uint32 * roff, uint32 * rlen)
|
||||||
|
{
|
||||||
|
return mock(data, clen, ctype, roff, rlen);
|
||||||
|
}
|
12
tests/orders_mock.c
Normal file
12
tests/orders_mock.c
Normal file
@ -0,0 +1,12 @@
|
|||||||
|
#include <cgreen/mocks.h>
|
||||||
|
#include "../rdesktop.h"
|
||||||
|
|
||||||
|
void process_orders(STREAM s, uint16 num_orders)
|
||||||
|
{
|
||||||
|
mock(s, num_orders);
|
||||||
|
}
|
||||||
|
|
||||||
|
void reset_order_state()
|
||||||
|
{
|
||||||
|
mock();
|
||||||
|
}
|
12
tests/pstcache_mock.c
Normal file
12
tests/pstcache_mock.c
Normal file
@ -0,0 +1,12 @@
|
|||||||
|
#include <cgreen/mocks.h>
|
||||||
|
#include "../rdesktop.h"
|
||||||
|
|
||||||
|
int pstcache_enumerate(uint8 id, HASH_KEY * keylist)
|
||||||
|
{
|
||||||
|
return mock(id, keylist);
|
||||||
|
}
|
||||||
|
|
||||||
|
RD_BOOL pstcache_init(uint8 cache_id)
|
||||||
|
{
|
||||||
|
return mock(cache_id);
|
||||||
|
}
|
13
tests/rdesktop_mock.c
Normal file
13
tests/rdesktop_mock.c
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
#include <cgreen/mocks.h>
|
||||||
|
#include "../rdesktop.h"
|
||||||
|
|
||||||
|
void rd_create_ui(void)
|
||||||
|
{
|
||||||
|
mock();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void generate_random(uint8 * random)
|
||||||
|
{
|
||||||
|
mock(random);
|
||||||
|
}
|
7
tests/rdp5_mock.c
Normal file
7
tests/rdp5_mock.c
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
#include <cgreen/mocks.h>
|
||||||
|
#include "../rdesktop.h"
|
||||||
|
|
||||||
|
void process_ts_fp_updates(STREAM s)
|
||||||
|
{
|
||||||
|
mock(s);
|
||||||
|
}
|
15
tests/rdp_mock.c
Normal file
15
tests/rdp_mock.c
Normal file
@ -0,0 +1,15 @@
|
|||||||
|
#include <cgreen/mocks.h>
|
||||||
|
#include "../rdesktop.h"
|
||||||
|
|
||||||
|
void
|
||||||
|
rdp_send_input(uint32 time, uint16 message_type, uint16 device_flags, uint16 param1, uint16 param2)
|
||||||
|
{
|
||||||
|
mock(time, message_type, device_flags, param1, param2);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
rdp_send_suppress_output_pdu(enum RDP_SUPPRESS_STATUS allowupdates)
|
||||||
|
{
|
||||||
|
mock(allowupdates);
|
||||||
|
}
|
||||||
|
|
141
tests/rdp_test.c
Normal file
141
tests/rdp_test.c
Normal file
@ -0,0 +1,141 @@
|
|||||||
|
#include <cgreen/cgreen.h>
|
||||||
|
#include <cgreen/mocks.h>
|
||||||
|
#include "../rdesktop.h"
|
||||||
|
#include "../proto.h"
|
||||||
|
|
||||||
|
/* Boilerplate */
|
||||||
|
Describe(RDP);
|
||||||
|
BeforeEach(RDP) {};
|
||||||
|
AfterEach(RDP) {};
|
||||||
|
|
||||||
|
/* Global Variables.. :( */
|
||||||
|
uint16 g_mcs_userid;
|
||||||
|
char *g_username;
|
||||||
|
char g_password[64];
|
||||||
|
char g_codepage[16];
|
||||||
|
RD_BOOL g_orders;
|
||||||
|
RD_BOOL g_encryption;
|
||||||
|
RD_BOOL g_desktop_save;
|
||||||
|
RD_BOOL g_polygon_ellipse_orders;
|
||||||
|
RDP_VERSION g_rdp_version;
|
||||||
|
uint16 g_server_rdp_version;
|
||||||
|
uint32 g_rdp5_performanceflags;
|
||||||
|
int g_server_depth;
|
||||||
|
uint32 g_initial_width;
|
||||||
|
uint32 g_initial_height;
|
||||||
|
RD_BOOL g_bitmap_cache;
|
||||||
|
RD_BOOL g_bitmap_cache_persist_enable;
|
||||||
|
RD_BOOL g_numlock_sync;
|
||||||
|
RD_BOOL g_pending_resize;
|
||||||
|
RD_BOOL g_network_error;
|
||||||
|
time_t g_wait_for_deactivate_ts;
|
||||||
|
RDPCOMP g_mppc_dict;
|
||||||
|
RD_BOOL g_redirect;
|
||||||
|
char *g_redirect_server;
|
||||||
|
uint32 g_redirect_server_len;
|
||||||
|
char *g_redirect_domain;
|
||||||
|
uint32 g_redirect_domain_len;
|
||||||
|
char *g_redirect_username;
|
||||||
|
uint32 g_redirect_username_len;
|
||||||
|
uint8 *g_redirect_lb_info;
|
||||||
|
uint32 g_redirect_lb_info_len;
|
||||||
|
uint8 *g_redirect_cookie;
|
||||||
|
uint32 g_redirect_cookie_len;
|
||||||
|
uint32 g_redirect_flags;
|
||||||
|
uint32 g_redirect_session_id;
|
||||||
|
uint32 g_reconnect_logonid;
|
||||||
|
char g_reconnect_random[16];
|
||||||
|
time_t g_reconnect_random_ts;
|
||||||
|
RD_BOOL g_has_reconnect_random;
|
||||||
|
uint8 g_client_random[SEC_RANDOM_SIZE];
|
||||||
|
RD_BOOL g_local_cursor;
|
||||||
|
|
||||||
|
#include "../rdp.c"
|
||||||
|
#include "../utils.c"
|
||||||
|
#include "../stream.c"
|
||||||
|
|
||||||
|
/* malloc; exit if out of memory */
|
||||||
|
void *
|
||||||
|
xmalloc(int size)
|
||||||
|
{
|
||||||
|
void *mem = malloc(size);
|
||||||
|
if (mem == NULL)
|
||||||
|
{
|
||||||
|
logger(Core, Error, "xmalloc, failed to allocate %d bytes", size);
|
||||||
|
exit(EX_UNAVAILABLE);
|
||||||
|
}
|
||||||
|
return mem;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Exit on NULL pointer. Use to verify result from XGetImage etc */
|
||||||
|
void
|
||||||
|
exit_if_null(void *ptr)
|
||||||
|
{
|
||||||
|
if (ptr == NULL)
|
||||||
|
{
|
||||||
|
logger(Core, Error, "unexpected null pointer. Out of memory?");
|
||||||
|
exit(EX_UNAVAILABLE);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* strdup */
|
||||||
|
char *
|
||||||
|
xstrdup(const char *s)
|
||||||
|
{
|
||||||
|
char *mem = strdup(s);
|
||||||
|
if (mem == NULL)
|
||||||
|
{
|
||||||
|
logger(Core, Error, "xstrdup(), strdup() failed: %s", strerror(errno));
|
||||||
|
exit(EX_UNAVAILABLE);
|
||||||
|
}
|
||||||
|
return mem;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* realloc; exit if out of memory */
|
||||||
|
void *
|
||||||
|
xrealloc(void *oldmem, size_t size)
|
||||||
|
{
|
||||||
|
void *mem;
|
||||||
|
|
||||||
|
if (size == 0)
|
||||||
|
size = 1;
|
||||||
|
mem = realloc(oldmem, size);
|
||||||
|
if (mem == NULL)
|
||||||
|
{
|
||||||
|
logger(Core, Error, "xrealloc, failed to reallocate %ld bytes", size);
|
||||||
|
exit(EX_UNAVAILABLE);
|
||||||
|
}
|
||||||
|
return mem;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* free */
|
||||||
|
void
|
||||||
|
xfree(void *mem)
|
||||||
|
{
|
||||||
|
free(mem);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* Test function */
|
||||||
|
Ensure(RDP, ProcessBitmapCapsCallsUiResizeWindow) {
|
||||||
|
struct stream s;
|
||||||
|
memset(&s, 0, sizeof(struct stream));
|
||||||
|
|
||||||
|
expect(ui_resize_window,
|
||||||
|
when(width, is_equal_to(1024)),
|
||||||
|
when(height, is_equal_to(768)));
|
||||||
|
|
||||||
|
s_realloc(&s, 32);
|
||||||
|
s_reset(&s);
|
||||||
|
|
||||||
|
out_uint16_le(&s, 32); /* depth */
|
||||||
|
out_uint8s(&s, 6); /* pad? dunno */
|
||||||
|
out_uint16_le(&s, 1024);
|
||||||
|
out_uint16_le(&s, 768);
|
||||||
|
s_mark_end(&s);
|
||||||
|
s_reset(&s);
|
||||||
|
|
||||||
|
rdp_process_bitmap_caps(&s);
|
||||||
|
|
||||||
|
free(s.data);
|
||||||
|
}
|
14
tests/rdpdr_mock.c
Normal file
14
tests/rdpdr_mock.c
Normal file
@ -0,0 +1,14 @@
|
|||||||
|
#include <cgreen/mocks.h>
|
||||||
|
#include "../rdesktop.h"
|
||||||
|
|
||||||
|
void
|
||||||
|
rdpdr_add_fds(int *n, fd_set * rfds, fd_set * wfds, struct timeval *tv, RD_BOOL * timeout)
|
||||||
|
{
|
||||||
|
mock(n, rfds, wfds, tv, timeout);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
rdpdr_check_fds(fd_set * rfds, fd_set * wfds, RD_BOOL timed_out)
|
||||||
|
{
|
||||||
|
mock(rfds, wfds, timed_out);
|
||||||
|
}
|
14
tests/rdpedisp_mock.c
Normal file
14
tests/rdpedisp_mock.c
Normal file
@ -0,0 +1,14 @@
|
|||||||
|
#include <cgreen/mocks.h>
|
||||||
|
#include "../rdesktop.h"
|
||||||
|
|
||||||
|
RD_BOOL
|
||||||
|
rdpedisp_is_available()
|
||||||
|
{
|
||||||
|
return mock();
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
rdpedisp_set_session_size(uint32 width, uint32 height)
|
||||||
|
{
|
||||||
|
mock(width, height);
|
||||||
|
}
|
571
tests/resize_test.c
Normal file
571
tests/resize_test.c
Normal file
@ -0,0 +1,571 @@
|
|||||||
|
#include <cgreen/cgreen.h>
|
||||||
|
#include <cgreen/mocks.h>
|
||||||
|
#include <X11/Xlib.h>
|
||||||
|
#include "../rdesktop.h"
|
||||||
|
|
||||||
|
/* Boilerplate */
|
||||||
|
Describe(Resize);
|
||||||
|
BeforeEach(Resize) {};
|
||||||
|
AfterEach(Resize) {};
|
||||||
|
|
||||||
|
/* globals driven by xwin.c */
|
||||||
|
RD_BOOL g_user_quit;
|
||||||
|
RD_BOOL g_exit_mainloop;
|
||||||
|
int g_sizeopt;
|
||||||
|
uint32 g_initial_width;
|
||||||
|
uint32 g_initial_height;
|
||||||
|
uint16 g_session_width;
|
||||||
|
uint16 g_session_height;
|
||||||
|
int g_xpos;
|
||||||
|
int g_ypos;
|
||||||
|
int g_pos;
|
||||||
|
RD_BOOL g_sendmotion;
|
||||||
|
RD_BOOL g_fullscreen;
|
||||||
|
RD_BOOL g_grab_keyboard;
|
||||||
|
RD_BOOL g_hide_decorations;
|
||||||
|
RD_BOOL g_pending_resize;
|
||||||
|
char g_title[] = "MyTitle";
|
||||||
|
char g_seamless_spawn_cmd[] = "";
|
||||||
|
int g_server_depth;
|
||||||
|
int g_win_button_size;
|
||||||
|
RD_BOOL g_seamless_persistent_mode;
|
||||||
|
RD_BOOL g_seamless_rdp;
|
||||||
|
RD_BOOL g_seamless_persistent_mode;
|
||||||
|
uint32 g_embed_wnd;
|
||||||
|
Atom g_net_wm_state_atom;
|
||||||
|
Atom g_net_wm_desktop_atom;
|
||||||
|
Atom g_net_wm_ping_atom;
|
||||||
|
RD_BOOL g_ownbackstore;
|
||||||
|
RD_BOOL g_rdpsnd;
|
||||||
|
RD_BOOL g_owncolmap;
|
||||||
|
RD_BOOL g_local_cursor;
|
||||||
|
|
||||||
|
/* globals driven by utils.c */
|
||||||
|
char g_codepage[16] = "";
|
||||||
|
|
||||||
|
/* global driven by rdp.c */
|
||||||
|
uint16 g_mcs_userid;
|
||||||
|
char *g_username;
|
||||||
|
char g_password[64];
|
||||||
|
char g_codepage[16];
|
||||||
|
RD_BOOL g_orders;
|
||||||
|
RD_BOOL g_encryption;
|
||||||
|
RD_BOOL g_desktop_save;
|
||||||
|
RD_BOOL g_polygon_ellipse_orders;
|
||||||
|
RDP_VERSION g_rdp_version;
|
||||||
|
uint16 g_server_rdp_version;
|
||||||
|
uint32 g_rdp5_performanceflags;
|
||||||
|
int g_server_depth;
|
||||||
|
uint32 g_initial_width;
|
||||||
|
uint32 g_initial_height;
|
||||||
|
RD_BOOL g_bitmap_cache;
|
||||||
|
RD_BOOL g_bitmap_cache_persist_enable;
|
||||||
|
RD_BOOL g_numlock_sync;
|
||||||
|
RD_BOOL g_pending_resize;
|
||||||
|
RD_BOOL g_network_error;
|
||||||
|
time_t g_wait_for_deactivate_ts;
|
||||||
|
RDPCOMP g_mppc_dict;
|
||||||
|
RD_BOOL g_redirect;
|
||||||
|
char *g_redirect_server;
|
||||||
|
uint32 g_redirect_server_len;
|
||||||
|
char *g_redirect_domain;
|
||||||
|
uint32 g_redirect_domain_len;
|
||||||
|
char *g_redirect_username;
|
||||||
|
uint32 g_redirect_username_len;
|
||||||
|
uint8 *g_redirect_lb_info;
|
||||||
|
uint32 g_redirect_lb_info_len;
|
||||||
|
uint8 *g_redirect_cookie;
|
||||||
|
uint32 g_redirect_cookie_len;
|
||||||
|
uint32 g_redirect_flags;
|
||||||
|
uint32 g_redirect_session_id;
|
||||||
|
uint32 g_reconnect_logonid;
|
||||||
|
char g_reconnect_random[16];
|
||||||
|
time_t g_reconnect_random_ts;
|
||||||
|
RD_BOOL g_has_reconnect_random;
|
||||||
|
uint8 g_client_random[SEC_RANDOM_SIZE];
|
||||||
|
RD_BOOL g_local_cursor;
|
||||||
|
|
||||||
|
/* globals from secure.c */
|
||||||
|
char g_hostname[16];
|
||||||
|
uint32 g_initial_width;
|
||||||
|
uint32 g_initial_height;
|
||||||
|
int g_dpi;
|
||||||
|
unsigned int g_keylayout;
|
||||||
|
int g_keyboard_type;
|
||||||
|
int g_keyboard_subtype;
|
||||||
|
int g_keyboard_functionkeys;
|
||||||
|
RD_BOOL g_encryption;
|
||||||
|
RD_BOOL g_licence_issued;
|
||||||
|
RD_BOOL g_licence_error_result;
|
||||||
|
RDP_VERSION g_rdp_version;
|
||||||
|
RD_BOOL g_console_session;
|
||||||
|
uint32 g_redirect_session_id;
|
||||||
|
int g_server_depth;
|
||||||
|
VCHANNEL g_channels[1];
|
||||||
|
unsigned int g_num_channels;
|
||||||
|
uint8 g_client_random[SEC_RANDOM_SIZE];
|
||||||
|
|
||||||
|
/* Xlib macros to mock functions */
|
||||||
|
#undef DefaultRootWindow
|
||||||
|
Window DefaultRootWindow(Display *display) { return (Window) mock(display); }
|
||||||
|
|
||||||
|
#undef WidthOfScreen
|
||||||
|
int WidthOfScreen(Screen* x) { return mock(x); }
|
||||||
|
|
||||||
|
#undef HeightOfScreen
|
||||||
|
int HeightOfScreen(Screen *x) { return mock(x); }
|
||||||
|
|
||||||
|
|
||||||
|
#include "../xwin.c"
|
||||||
|
#include "../utils.c"
|
||||||
|
#include "../rdp.c"
|
||||||
|
#include "../stream.c"
|
||||||
|
#include "../secure.c"
|
||||||
|
|
||||||
|
/* malloc; exit if out of memory */
|
||||||
|
void *
|
||||||
|
xmalloc(int size)
|
||||||
|
{
|
||||||
|
void *mem = malloc(size);
|
||||||
|
if (mem == NULL)
|
||||||
|
{
|
||||||
|
logger(Core, Error, "xmalloc, failed to allocate %d bytes", size);
|
||||||
|
exit(EX_UNAVAILABLE);
|
||||||
|
}
|
||||||
|
return mem;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Exit on NULL pointer. Use to verify result from XGetImage etc */
|
||||||
|
void
|
||||||
|
exit_if_null(void *ptr)
|
||||||
|
{
|
||||||
|
if (ptr == NULL)
|
||||||
|
{
|
||||||
|
logger(Core, Error, "unexpected null pointer. Out of memory?");
|
||||||
|
exit(EX_UNAVAILABLE);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* strdup */
|
||||||
|
char *
|
||||||
|
xstrdup(const char *s)
|
||||||
|
{
|
||||||
|
char *mem = strdup(s);
|
||||||
|
if (mem == NULL)
|
||||||
|
{
|
||||||
|
logger(Core, Error, "xstrdup(), strdup() failed: %s", strerror(errno));
|
||||||
|
exit(EX_UNAVAILABLE);
|
||||||
|
}
|
||||||
|
return mem;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* realloc; exit if out of memory */
|
||||||
|
void *
|
||||||
|
xrealloc(void *oldmem, size_t size)
|
||||||
|
{
|
||||||
|
void *mem;
|
||||||
|
|
||||||
|
if (size == 0)
|
||||||
|
size = 1;
|
||||||
|
mem = realloc(oldmem, size);
|
||||||
|
if (mem == NULL)
|
||||||
|
{
|
||||||
|
logger(Core, Error, "xrealloc, failed to reallocate %ld bytes", size);
|
||||||
|
exit(EX_UNAVAILABLE);
|
||||||
|
}
|
||||||
|
return mem;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* free */
|
||||||
|
void
|
||||||
|
xfree(void *mem)
|
||||||
|
{
|
||||||
|
free(mem);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* X11 mocks */
|
||||||
|
|
||||||
|
Status
|
||||||
|
XGetWindowAttributes(Display *display, Window wnd, XWindowAttributes *attr)
|
||||||
|
{
|
||||||
|
return mock(display, wnd, attr);
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
XResizeWindow(Display *display, Window wnd, unsigned width, unsigned height)
|
||||||
|
{
|
||||||
|
return mock(display, wnd, width, height);
|
||||||
|
}
|
||||||
|
|
||||||
|
XSizeHints *
|
||||||
|
XAllocSizeHints(void)
|
||||||
|
{
|
||||||
|
return (XSizeHints *) mock();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
int
|
||||||
|
XSetClipRectangles(Display *display, GC gc, int clip_x_origin, int clip_y_origin,
|
||||||
|
XRectangle rectangles[], int n, int ordering)
|
||||||
|
{
|
||||||
|
return mock(display, gc, clip_x_origin, clip_y_origin, rectangles, n, ordering);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Test helpers */
|
||||||
|
|
||||||
|
struct stream
|
||||||
|
bitmap_caps_packet(int width, int height)
|
||||||
|
{
|
||||||
|
struct stream s;
|
||||||
|
memset(&s, 0, sizeof(s));
|
||||||
|
s_realloc(&s, 32);
|
||||||
|
s_reset(&s);
|
||||||
|
|
||||||
|
out_uint16_le(&s, 32); /* depth */
|
||||||
|
out_uint8s(&s, 6); /* pad? dunno */
|
||||||
|
out_uint16_le(&s, width);
|
||||||
|
out_uint16_le(&s, height);
|
||||||
|
s_mark_end(&s);
|
||||||
|
s_reset(&s);
|
||||||
|
|
||||||
|
return s;
|
||||||
|
}
|
||||||
|
|
||||||
|
#define RDPEDISP True
|
||||||
|
#define RECONNECT False
|
||||||
|
|
||||||
|
#define FULLSCREEN True
|
||||||
|
#define WINDOW False
|
||||||
|
|
||||||
|
void setup_user_initiated_resize(int width, int height, RD_BOOL use_rdpedisp, RD_BOOL fullscreen)
|
||||||
|
{
|
||||||
|
/* g_resize_timer = A second ago */
|
||||||
|
struct timeval tv;
|
||||||
|
gettimeofday(&tv, NULL);
|
||||||
|
tv.tv_sec -= 1;
|
||||||
|
g_resize_timer = tv;
|
||||||
|
|
||||||
|
g_fullscreen = fullscreen;
|
||||||
|
|
||||||
|
g_window_width = width;
|
||||||
|
g_window_height = height;
|
||||||
|
|
||||||
|
expect(rdpedisp_is_available,
|
||||||
|
will_return(use_rdpedisp));
|
||||||
|
}
|
||||||
|
|
||||||
|
struct stream setup_server_resize_response(int width, int height) {
|
||||||
|
expect(XGetWindowAttributes);
|
||||||
|
expect(XSetClipRectangles);
|
||||||
|
expect(XAllocSizeHints,
|
||||||
|
will_return(0));
|
||||||
|
|
||||||
|
return bitmap_caps_packet(width, height);
|
||||||
|
}
|
||||||
|
|
||||||
|
Ensure(Resize, UsingRDPEDISP)
|
||||||
|
{
|
||||||
|
struct stream s;
|
||||||
|
int user_wanted_width = 1280;
|
||||||
|
int user_wanted_height = 1024;
|
||||||
|
|
||||||
|
/* Step 1 : Act on UI side initiated resize and tell server about it using RDPEDISP */
|
||||||
|
setup_user_initiated_resize(user_wanted_width, user_wanted_height, RDPEDISP, WINDOW);
|
||||||
|
|
||||||
|
expect(rdpedisp_set_session_size,
|
||||||
|
when(width, is_equal_to(user_wanted_width)),
|
||||||
|
when(height, is_equal_to(user_wanted_height)));
|
||||||
|
|
||||||
|
/* FIXME: Move process_pending_resize out of X11 UI implementation */
|
||||||
|
assert_that(process_pending_resize(), is_equal_to(False));
|
||||||
|
|
||||||
|
/* Step 2 : Handle a BITMAP_CAPS containing session size from server
|
||||||
|
so set window size accordingly */
|
||||||
|
s = setup_server_resize_response(user_wanted_width, user_wanted_height);
|
||||||
|
|
||||||
|
expect(XResizeWindow,
|
||||||
|
when(width, is_equal_to(user_wanted_width)),
|
||||||
|
when(height, is_equal_to(user_wanted_height)));
|
||||||
|
|
||||||
|
rdp_process_bitmap_caps(&s);
|
||||||
|
free(s.data);
|
||||||
|
}
|
||||||
|
|
||||||
|
Ensure(Resize, UsingRDPEDISPHonoursServerMaximumSessionSizeLimit)
|
||||||
|
{
|
||||||
|
/* User has changed window size, X has resized, RDP needs to tell server.
|
||||||
|
RDPEDISP is available and a Windows 2012 server will limit session size
|
||||||
|
to maximum 8192x8192. We will set window size to whatever server says.
|
||||||
|
*/
|
||||||
|
struct stream s;
|
||||||
|
int user_wanted_width = 9000;
|
||||||
|
int user_wanted_height = 9000;
|
||||||
|
|
||||||
|
/* Step 1 : Act on UI side initiated resize and tell server about it
|
||||||
|
using RDPEDISP */
|
||||||
|
setup_user_initiated_resize(user_wanted_width, user_wanted_height, RDPEDISP, WINDOW);
|
||||||
|
|
||||||
|
expect(rdpedisp_set_session_size,
|
||||||
|
when(width, is_equal_to(user_wanted_width)),
|
||||||
|
when(height, is_equal_to(user_wanted_height)));
|
||||||
|
|
||||||
|
/* FIXME: Move process_pending_resize out of X11 UI implementation */
|
||||||
|
assert_that(process_pending_resize(), is_equal_to(False));
|
||||||
|
|
||||||
|
/* Step 2 : Handle a BITMAP_CAPS containing session size from server
|
||||||
|
so set window size accordingly */
|
||||||
|
|
||||||
|
int resulting_server_width = 8192;
|
||||||
|
int resulting_server_height = 8192;
|
||||||
|
|
||||||
|
s = setup_server_resize_response(resulting_server_width, resulting_server_height);
|
||||||
|
|
||||||
|
expect(XResizeWindow,
|
||||||
|
when(width, is_equal_to(resulting_server_width)),
|
||||||
|
when(height, is_equal_to(resulting_server_height)));
|
||||||
|
|
||||||
|
/* simulate response from server */
|
||||||
|
rdp_process_bitmap_caps(&s);
|
||||||
|
free(s.data);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
Ensure(Resize, UsingRDPEDISPHonoursServerMinimumSessionSizeLimit)
|
||||||
|
{
|
||||||
|
/* User has changed window size, X has resized, RDP needs to tell server.
|
||||||
|
RDPEDISP is available and a Windows 2012 server will limit session size
|
||||||
|
to minimum 200x200. We will set window size to whatever server says.
|
||||||
|
*/
|
||||||
|
|
||||||
|
struct stream s;
|
||||||
|
|
||||||
|
/* Step 1 : Act on UI side initiated resize and tell server about it
|
||||||
|
using RDPEDISP */
|
||||||
|
|
||||||
|
int user_wanted_width = 100;
|
||||||
|
int user_wanted_height = 100;
|
||||||
|
|
||||||
|
setup_user_initiated_resize(user_wanted_width, user_wanted_height, RDPEDISP, WINDOW);
|
||||||
|
|
||||||
|
expect(rdpedisp_set_session_size,
|
||||||
|
when(width, is_equal_to(user_wanted_width)),
|
||||||
|
when(height, is_equal_to(user_wanted_height)));
|
||||||
|
|
||||||
|
/* FIXME: Move process_pending_resize out of X11 UI implementation */
|
||||||
|
assert_that(process_pending_resize(), is_equal_to(False));
|
||||||
|
|
||||||
|
/* Step 2 : Handle a BITMAP_CAPS containing session size from server
|
||||||
|
so set window size accordingly */
|
||||||
|
|
||||||
|
int resulting_server_width = 200;
|
||||||
|
int resulting_server_height = 200;
|
||||||
|
|
||||||
|
s = setup_server_resize_response(resulting_server_width, resulting_server_height);
|
||||||
|
|
||||||
|
expect(XResizeWindow,
|
||||||
|
when(width, is_equal_to(resulting_server_width)),
|
||||||
|
when(height, is_equal_to(resulting_server_height)));
|
||||||
|
|
||||||
|
/* simulate response from server */
|
||||||
|
rdp_process_bitmap_caps(&s);
|
||||||
|
free(s.data);
|
||||||
|
}
|
||||||
|
|
||||||
|
Ensure(Resize, UsingRDPEDISPHonoursServerSessionWidthConstraintMustBeEven)
|
||||||
|
{
|
||||||
|
/* User has changed window size, X has resized, RDP needs to tell server.
|
||||||
|
RDPEDISP is available and a Windows 2012 server will limit session size
|
||||||
|
to minimum 200x200. We will set window size to whatever server says.
|
||||||
|
*/
|
||||||
|
struct stream s;
|
||||||
|
|
||||||
|
/* Step 1 : Act on UI side initiated resize and tell server about it
|
||||||
|
using RDPEDISP */
|
||||||
|
|
||||||
|
int user_wanted_width = 999;
|
||||||
|
int user_wanted_height = 900;
|
||||||
|
|
||||||
|
setup_user_initiated_resize(user_wanted_width, user_wanted_height, RDPEDISP, WINDOW);
|
||||||
|
|
||||||
|
expect(rdpedisp_set_session_size,
|
||||||
|
when(width, is_equal_to(user_wanted_width)),
|
||||||
|
when(height, is_equal_to(user_wanted_height)));
|
||||||
|
|
||||||
|
/* FIXME: Move process_pending_resize out of X11 UI implementation */
|
||||||
|
assert_that(process_pending_resize(), is_equal_to(False));
|
||||||
|
|
||||||
|
/* Step 2 : Handle a BITMAP_CAPS containing session size from server
|
||||||
|
so set window size accordingly */
|
||||||
|
|
||||||
|
/* FIXME: Does the server round up or down? */
|
||||||
|
int resulting_server_width = 998;
|
||||||
|
int resulting_server_height = 900;
|
||||||
|
|
||||||
|
s = setup_server_resize_response(resulting_server_width, resulting_server_height);
|
||||||
|
|
||||||
|
expect(XResizeWindow,
|
||||||
|
when(width, is_equal_to(resulting_server_width)),
|
||||||
|
when(height, is_equal_to(resulting_server_height)));
|
||||||
|
|
||||||
|
/* simulate response from server */
|
||||||
|
rdp_process_bitmap_caps(&s);
|
||||||
|
free(s.data);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* FIXME: promote to actual function in stream.c */
|
||||||
|
STREAM s_alloc(size_t capacity)
|
||||||
|
{
|
||||||
|
STREAM s;
|
||||||
|
s = xmalloc(sizeof(struct stream));
|
||||||
|
memset(s, 0, sizeof(struct stream));
|
||||||
|
s_realloc(s, capacity);
|
||||||
|
s_reset(s);
|
||||||
|
return s;
|
||||||
|
}
|
||||||
|
|
||||||
|
void get_width_and_height_from_mcs_connect_initial(int *width, int *height)
|
||||||
|
{
|
||||||
|
STREAM s;
|
||||||
|
|
||||||
|
/* Allocate stream and write mcs_connect_initial PDU to it */
|
||||||
|
s = s_alloc(4096);
|
||||||
|
sec_out_mcs_connect_initial_pdu(s, 0);
|
||||||
|
|
||||||
|
/* Rewind and extract the requested session size */
|
||||||
|
s_reset(s);
|
||||||
|
in_skip(s, 31);
|
||||||
|
in_uint16_le(s, *width); /* desktopWidth */
|
||||||
|
in_uint16_le(s, *height); /* desktopHeight */
|
||||||
|
|
||||||
|
s_free(s);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
Ensure(Resize, UsingReconnect)
|
||||||
|
{
|
||||||
|
struct stream s;
|
||||||
|
|
||||||
|
int user_wanted_width = 1280;
|
||||||
|
int user_wanted_height = 1024;
|
||||||
|
|
||||||
|
/* Step 1 : Act on UI side initiated resize */
|
||||||
|
setup_user_initiated_resize(user_wanted_width, user_wanted_height, RECONNECT, WINDOW);
|
||||||
|
|
||||||
|
assert_that(process_pending_resize(),
|
||||||
|
is_equal_to(True));
|
||||||
|
|
||||||
|
/* we assume that process_pending_resize returning True will exit the main loop and initiate a
|
||||||
|
reconnect */
|
||||||
|
|
||||||
|
|
||||||
|
/* Step 2 : Simulate parts of the connection sequence where we send
|
||||||
|
width & height through a MCS Connect Initial packet to the server */
|
||||||
|
|
||||||
|
int sent_width, sent_height;
|
||||||
|
|
||||||
|
get_width_and_height_from_mcs_connect_initial(&sent_width, &sent_height);
|
||||||
|
|
||||||
|
assert_that(sent_width, is_equal_to(user_wanted_width));
|
||||||
|
assert_that(sent_height, is_equal_to(user_wanted_height));
|
||||||
|
|
||||||
|
|
||||||
|
/* Step 3 : Handle a BITMAP_CAPS containing session size from server
|
||||||
|
so set window size accordingly */
|
||||||
|
|
||||||
|
s = setup_server_resize_response(user_wanted_width,
|
||||||
|
user_wanted_height);
|
||||||
|
|
||||||
|
expect(XResizeWindow,
|
||||||
|
when(width, is_equal_to(user_wanted_width)),
|
||||||
|
when(height, is_equal_to(user_wanted_height)));
|
||||||
|
|
||||||
|
rdp_process_bitmap_caps(&s);
|
||||||
|
free(s.data);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
Ensure(Resize, UsingReconnectHonoursServerMaximumSessionSizeLimit)
|
||||||
|
{
|
||||||
|
struct stream s;
|
||||||
|
|
||||||
|
int user_wanted_width = 9000;
|
||||||
|
int user_wanted_height = 9000;
|
||||||
|
|
||||||
|
/* Step 1 : Act on UI side initiated resize */
|
||||||
|
setup_user_initiated_resize(user_wanted_width, user_wanted_height, RECONNECT, WINDOW);
|
||||||
|
|
||||||
|
/* FIXME: Move process_pending_resize out of X11 UI implementation */
|
||||||
|
assert_that(process_pending_resize(),
|
||||||
|
is_equal_to(True));
|
||||||
|
|
||||||
|
/* We assume that process_pending_resize returning True exits the main
|
||||||
|
loop and initiates a reconnect */
|
||||||
|
|
||||||
|
|
||||||
|
/* Step 2 : Simulate parts of the connection sequence where we send
|
||||||
|
width & height through a MCS Connect Initial packet to the server */
|
||||||
|
|
||||||
|
int sent_width, sent_height;
|
||||||
|
|
||||||
|
get_width_and_height_from_mcs_connect_initial(&sent_width, &sent_height);
|
||||||
|
|
||||||
|
assert_that(sent_width, is_equal_to(user_wanted_width));
|
||||||
|
assert_that(sent_height, is_equal_to(user_wanted_height));
|
||||||
|
|
||||||
|
/* Step 3 : Handle a BITMAP_CAPS containing session size from server
|
||||||
|
so set window size accordingly */
|
||||||
|
|
||||||
|
int resulting_server_width = 4096;
|
||||||
|
int resulting_server_height = 2048;
|
||||||
|
|
||||||
|
s = setup_server_resize_response(resulting_server_width,
|
||||||
|
resulting_server_height);
|
||||||
|
|
||||||
|
expect(XResizeWindow,
|
||||||
|
when(width, is_equal_to(resulting_server_width)),
|
||||||
|
when(height, is_equal_to(resulting_server_height)));
|
||||||
|
|
||||||
|
rdp_process_bitmap_caps(&s);
|
||||||
|
free(s.data);
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
XNextEvent(Display *display, XEvent *event)
|
||||||
|
{
|
||||||
|
return mock(display, event);
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
XPending(Display *display)
|
||||||
|
{
|
||||||
|
return mock(display);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
setup_user_initiated_root_window_resize(int width, int height,
|
||||||
|
RD_BOOL use_rdpedisp, RD_BOOL fullscreen)
|
||||||
|
{
|
||||||
|
XEvent rootWindowResizeEvent;
|
||||||
|
memset(&rootWindowResizeEvent, 0, sizeof(XEvent));
|
||||||
|
|
||||||
|
rootWindowResizeEvent.xconfigure.type = ConfigureNotify;
|
||||||
|
rootWindowResizeEvent.xconfigure.window = DefaultRootWindow(g_display);
|
||||||
|
rootWindowResizeEvent.xconfigure.width = width;
|
||||||
|
rootWindowResizeEvent.xconfigure.height = height;
|
||||||
|
|
||||||
|
/* one event to process */
|
||||||
|
expect(XPending, will_return(1));
|
||||||
|
|
||||||
|
/* event is a ConfigureNotify event on root window */
|
||||||
|
expect(XNextEvent,
|
||||||
|
will_set_contents_of_parameter(event,
|
||||||
|
&rootWindowResizeEvent,
|
||||||
|
sizeof(XConfigureEvent *)));
|
||||||
|
/* no more events to process */
|
||||||
|
expect(XPending,
|
||||||
|
will_return(0));
|
||||||
|
|
||||||
|
|
||||||
|
expect(rdpedisp_is_available, will_return(use_rdpedisp));
|
||||||
|
g_fullscreen = fullscreen;
|
||||||
|
}
|
58
tests/seamless_mock.c
Normal file
58
tests/seamless_mock.c
Normal file
@ -0,0 +1,58 @@
|
|||||||
|
#include <cgreen/mocks.h>
|
||||||
|
#include "../rdesktop.h"
|
||||||
|
|
||||||
|
RD_BOOL seamless_init()
|
||||||
|
{
|
||||||
|
return mock();
|
||||||
|
}
|
||||||
|
|
||||||
|
void seamless_reset_state()
|
||||||
|
{
|
||||||
|
mock();
|
||||||
|
}
|
||||||
|
|
||||||
|
unsigned int seamless_send_sync(void)
|
||||||
|
{
|
||||||
|
return mock();
|
||||||
|
}
|
||||||
|
|
||||||
|
unsigned int seamless_send_state(unsigned long id, unsigned int state, unsigned long flags)
|
||||||
|
{
|
||||||
|
return mock(id, state, flags);
|
||||||
|
}
|
||||||
|
|
||||||
|
unsigned int seamless_send_position(unsigned long id, int x, int y,
|
||||||
|
int width, int height, unsigned long flags)
|
||||||
|
{
|
||||||
|
return mock(id, x, y, width, height, flags);
|
||||||
|
}
|
||||||
|
|
||||||
|
void seamless_select_timeout(struct timeval *tv)
|
||||||
|
{
|
||||||
|
mock(tv);
|
||||||
|
}
|
||||||
|
|
||||||
|
unsigned int seamless_send_zchange(unsigned long id, unsigned long below, unsigned long flags)
|
||||||
|
{
|
||||||
|
return mock(id, below, flags);
|
||||||
|
}
|
||||||
|
|
||||||
|
unsigned int seamless_send_focus(unsigned long id, unsigned long flags)
|
||||||
|
{
|
||||||
|
return mock(id, flags);
|
||||||
|
}
|
||||||
|
|
||||||
|
unsigned int seamless_send_destroy(unsigned long id)
|
||||||
|
{
|
||||||
|
return mock(id);
|
||||||
|
}
|
||||||
|
|
||||||
|
unsigned int seamless_send_spawn(char *cmd)
|
||||||
|
{
|
||||||
|
return mock(cmd);
|
||||||
|
}
|
||||||
|
|
||||||
|
unsigned int seamless_send_persistent(RD_BOOL enable)
|
||||||
|
{
|
||||||
|
return mock(enable);
|
||||||
|
}
|
32
tests/secure_mock.c
Normal file
32
tests/secure_mock.c
Normal file
@ -0,0 +1,32 @@
|
|||||||
|
#include <cgreen/mocks.h>
|
||||||
|
#include "../rdesktop.h"
|
||||||
|
|
||||||
|
STREAM sec_recv(uint8 * rdpver)
|
||||||
|
{
|
||||||
|
return (STREAM)mock(rdpver);
|
||||||
|
}
|
||||||
|
|
||||||
|
void sec_disconnect()
|
||||||
|
{
|
||||||
|
mock();
|
||||||
|
}
|
||||||
|
|
||||||
|
STREAM sec_init(uint32 flags, int maxlen)
|
||||||
|
{
|
||||||
|
return (STREAM) mock(flags, maxlen);
|
||||||
|
}
|
||||||
|
|
||||||
|
RD_BOOL sec_connect(char *server, char *username, char *domain, char *password, RD_BOOL reconnect)
|
||||||
|
{
|
||||||
|
return mock(server, username, domain, password, reconnect);
|
||||||
|
}
|
||||||
|
|
||||||
|
void sec_reset_state()
|
||||||
|
{
|
||||||
|
mock();
|
||||||
|
}
|
||||||
|
|
||||||
|
void sec_send(STREAM s, uint32 flags)
|
||||||
|
{
|
||||||
|
mock(s, flags);
|
||||||
|
}
|
108
tests/ssl_mock.c
Normal file
108
tests/ssl_mock.c
Normal file
@ -0,0 +1,108 @@
|
|||||||
|
#include <cgreen/mocks.h>
|
||||||
|
#include "../rdesktop.h"
|
||||||
|
#include "../ssl.h"
|
||||||
|
|
||||||
|
void rdssl_hmac_md5(const void *key, int key_len,
|
||||||
|
const unsigned char *msg, int msg_len, unsigned char *md)
|
||||||
|
{
|
||||||
|
mock(key, key_len, msg, msg_len, md);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
rdssl_cert_free(RDSSL_CERT * cert)
|
||||||
|
{
|
||||||
|
mock(cert);
|
||||||
|
}
|
||||||
|
|
||||||
|
RDSSL_CERT *
|
||||||
|
rdssl_cert_read(uint8 *data, uint32 len)
|
||||||
|
{
|
||||||
|
return (RDSSL_CERT *) mock(data, len);
|
||||||
|
}
|
||||||
|
|
||||||
|
RD_BOOL
|
||||||
|
rdssl_certs_ok(RDSSL_CERT * server_cert, RDSSL_CERT * cacert)
|
||||||
|
{
|
||||||
|
return mock(server_cert, cacert);
|
||||||
|
}
|
||||||
|
|
||||||
|
RDSSL_RKEY *
|
||||||
|
rdssl_cert_to_rkey(RDSSL_CERT * cert, uint32 * key_len)
|
||||||
|
{
|
||||||
|
return (RDSSL_RKEY *) mock(cert, key_len);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
rdssl_md5_init(RDSSL_MD5 * md5)
|
||||||
|
{
|
||||||
|
mock(md5);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
rdssl_md5_update(RDSSL_MD5 * md5, uint8 * data, uint32 len)
|
||||||
|
{
|
||||||
|
mock(md5, data, len);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
rdssl_md5_final(RDSSL_MD5 * md5, uint8 * out_data)
|
||||||
|
{
|
||||||
|
mock(md5, out_data);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
rdssl_rc4_set_key(RDSSL_RC4 * rc4, uint8 * key, uint32 len)
|
||||||
|
{
|
||||||
|
mock(rc4, key, len);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
rdssl_rc4_crypt(RDSSL_RC4 * rc4, uint8 * in_data, uint8 * out_data, uint32 len)
|
||||||
|
{
|
||||||
|
mock(rc4, in_data, out_data, len);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
rdssl_rkey_free(RDSSL_RKEY * rkey)
|
||||||
|
{
|
||||||
|
mock(rkey);
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
rdssl_rkey_get_exp_mod(RDSSL_RKEY * rkey, uint8 * exponent, uint32 max_exp_len, uint8 * modulus,
|
||||||
|
uint32 max_mod_len)
|
||||||
|
{
|
||||||
|
return mock(rkey, exponent, max_exp_len, modulus, max_mod_len);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
rdssl_rsa_encrypt(uint8 * out, uint8 * in, int len, uint32 modulus_size, uint8 * modulus,
|
||||||
|
uint8 * exponent)
|
||||||
|
{
|
||||||
|
mock(out, in, len, modulus_size, modulus, exponent);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
rdssl_sha1_final(RDSSL_SHA1 * sha1, uint8 * out_data)
|
||||||
|
{
|
||||||
|
mock(sha1, out_data);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
rdssl_sha1_init(RDSSL_SHA1 *sha1)
|
||||||
|
{
|
||||||
|
mock(sha1);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
rdssl_sha1_update(RDSSL_SHA1 *sha1, uint8 *data, uint32 len)
|
||||||
|
{
|
||||||
|
mock(sha1, data, len);
|
||||||
|
}
|
||||||
|
|
||||||
|
RD_BOOL
|
||||||
|
rdssl_sig_ok(uint8 *exponent, uint32 exp_len, uint8 *modulus, uint32 mod_len,
|
||||||
|
uint8 *signature, uint32 sig_len)
|
||||||
|
{
|
||||||
|
return mock(exponent, exp_len, modulus, mod_len, signature, sig_len);
|
||||||
|
}
|
7
tests/tcp_mock.c
Normal file
7
tests/tcp_mock.c
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
#include <cgreen/mocks.h>
|
||||||
|
#include "../rdesktop.h"
|
||||||
|
|
||||||
|
char *tcp_get_address()
|
||||||
|
{
|
||||||
|
return (char *) mock();
|
||||||
|
}
|
72
tests/ui_mock.c
Normal file
72
tests/ui_mock.c
Normal file
@ -0,0 +1,72 @@
|
|||||||
|
#include <cgreen/mocks.h>
|
||||||
|
#include "../rdesktop.h"
|
||||||
|
|
||||||
|
time_t g_wait_for_deactivate_ts;
|
||||||
|
|
||||||
|
/* Mock implementation of F1 */
|
||||||
|
void ui_resize_window(uint32 width, uint32 height)
|
||||||
|
{
|
||||||
|
mock(width, height);
|
||||||
|
}
|
||||||
|
|
||||||
|
void ui_set_cursor(RD_HCURSOR cursor)
|
||||||
|
{
|
||||||
|
mock(cursor);
|
||||||
|
}
|
||||||
|
|
||||||
|
void ui_set_standard_cursor()
|
||||||
|
{
|
||||||
|
mock();
|
||||||
|
}
|
||||||
|
|
||||||
|
void ui_bell()
|
||||||
|
{
|
||||||
|
mock();
|
||||||
|
}
|
||||||
|
|
||||||
|
void ui_paint_bitmap(int x, int y, int cx, int cy, int width, int height, uint8 * data)
|
||||||
|
{
|
||||||
|
mock(x,y,cx,cy,width,height,data);
|
||||||
|
}
|
||||||
|
|
||||||
|
void ui_begin_update()
|
||||||
|
{
|
||||||
|
mock();
|
||||||
|
}
|
||||||
|
|
||||||
|
RD_HCOLOURMAP ui_create_colourmap(COLOURMAP * colours)
|
||||||
|
{
|
||||||
|
return (RD_HCOLOURMAP) mock(colours);
|
||||||
|
}
|
||||||
|
|
||||||
|
RD_HCURSOR ui_create_cursor(unsigned int x, unsigned int y, uint32 width, uint32 height, uint8 * andmask,
|
||||||
|
uint8 * xormask, int bpp)
|
||||||
|
{
|
||||||
|
return (RD_HCURSOR) mock(x, y, width, height, andmask, xormask, bpp);
|
||||||
|
}
|
||||||
|
|
||||||
|
void ui_end_update()
|
||||||
|
{
|
||||||
|
mock();
|
||||||
|
}
|
||||||
|
|
||||||
|
void ui_move_pointer(int x, int y)
|
||||||
|
{
|
||||||
|
mock(x, y);
|
||||||
|
}
|
||||||
|
|
||||||
|
void ui_set_colourmap(RD_HCOLOURMAP map)
|
||||||
|
{
|
||||||
|
mock(map);
|
||||||
|
}
|
||||||
|
|
||||||
|
void ui_set_null_cursor()
|
||||||
|
{
|
||||||
|
mock();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void ui_set_clip(int x,int y, int cx, int cy)
|
||||||
|
{
|
||||||
|
mock(x,y,cx,cy);
|
||||||
|
}
|
179
tests/utils_test.c
Normal file
179
tests/utils_test.c
Normal file
@ -0,0 +1,179 @@
|
|||||||
|
#include <cgreen/cgreen.h>
|
||||||
|
#include <cgreen/mocks.h>
|
||||||
|
#include "../rdesktop.h"
|
||||||
|
|
||||||
|
/* Boilerplate */
|
||||||
|
Describe(Utils);
|
||||||
|
BeforeEach(Utils) {};
|
||||||
|
AfterEach(Utils) {};
|
||||||
|
|
||||||
|
/* globals */
|
||||||
|
char g_codepage[16];
|
||||||
|
|
||||||
|
#include "../utils.c"
|
||||||
|
|
||||||
|
/* malloc; exit if out of memory */
|
||||||
|
void *
|
||||||
|
xmalloc(int size)
|
||||||
|
{
|
||||||
|
void *mem = malloc(size);
|
||||||
|
if (mem == NULL)
|
||||||
|
{
|
||||||
|
logger(Core, Error, "xmalloc, failed to allocate %d bytes", size);
|
||||||
|
exit(EX_UNAVAILABLE);
|
||||||
|
}
|
||||||
|
return mem;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Exit on NULL pointer. Use to verify result from XGetImage etc */
|
||||||
|
void
|
||||||
|
exit_if_null(void *ptr)
|
||||||
|
{
|
||||||
|
if (ptr == NULL)
|
||||||
|
{
|
||||||
|
logger(Core, Error, "unexpected null pointer. Out of memory?");
|
||||||
|
exit(EX_UNAVAILABLE);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* strdup */
|
||||||
|
char *
|
||||||
|
xstrdup(const char *s)
|
||||||
|
{
|
||||||
|
char *mem = strdup(s);
|
||||||
|
if (mem == NULL)
|
||||||
|
{
|
||||||
|
logger(Core, Error, "xstrdup(), strdup() failed: %s", strerror(errno));
|
||||||
|
exit(EX_UNAVAILABLE);
|
||||||
|
}
|
||||||
|
return mem;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* realloc; exit if out of memory */
|
||||||
|
void *
|
||||||
|
xrealloc(void *oldmem, size_t size)
|
||||||
|
{
|
||||||
|
void *mem;
|
||||||
|
|
||||||
|
if (size == 0)
|
||||||
|
size = 1;
|
||||||
|
mem = realloc(oldmem, size);
|
||||||
|
if (mem == NULL)
|
||||||
|
{
|
||||||
|
logger(Core, Error, "xrealloc, failed to reallocate %ld bytes", size);
|
||||||
|
exit(EX_UNAVAILABLE);
|
||||||
|
}
|
||||||
|
return mem;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* free */
|
||||||
|
void
|
||||||
|
xfree(void *mem)
|
||||||
|
{
|
||||||
|
free(mem);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* Test function */
|
||||||
|
Ensure(Utils, CalculateDpiScaleFactorsWhenDpiIsZero) {
|
||||||
|
uint32 physical_width, physical_height, desktop_scale, device_scale;
|
||||||
|
|
||||||
|
utils_calculate_dpi_scale_factors(1024, 768, 0,
|
||||||
|
&physical_width, &physical_height,
|
||||||
|
&desktop_scale, &device_scale);
|
||||||
|
|
||||||
|
assert_that(physical_width, is_equal_to(0));
|
||||||
|
assert_that(physical_height, is_equal_to(0));
|
||||||
|
assert_that(desktop_scale, is_equal_to(0));
|
||||||
|
assert_that(device_scale, is_equal_to(0));
|
||||||
|
}
|
||||||
|
|
||||||
|
Ensure(Utils, CalculateDpiScaleFactorsWhenDpiLessThan96) {
|
||||||
|
uint32 physical_width, physical_height, desktop_scale, device_scale;
|
||||||
|
|
||||||
|
utils_calculate_dpi_scale_factors(1024, 768, 95,
|
||||||
|
&physical_width, &physical_height,
|
||||||
|
&desktop_scale, &device_scale);
|
||||||
|
|
||||||
|
assert_that(physical_width, is_equal_to(273));
|
||||||
|
assert_that(physical_height, is_equal_to(205));
|
||||||
|
assert_that(desktop_scale, is_equal_to(100));
|
||||||
|
assert_that(device_scale, is_equal_to(100));
|
||||||
|
}
|
||||||
|
|
||||||
|
Ensure(Utils, CalculateDpiScaleFactorsWhenDpiLessThan134) {
|
||||||
|
uint32 physical_width, physical_height, desktop_scale, device_scale;
|
||||||
|
|
||||||
|
utils_calculate_dpi_scale_factors(1024, 768, 133,
|
||||||
|
&physical_width, &physical_height,
|
||||||
|
&desktop_scale, &device_scale);
|
||||||
|
|
||||||
|
assert_that(physical_width, is_equal_to(195));
|
||||||
|
assert_that(physical_height, is_equal_to(146));
|
||||||
|
assert_that(desktop_scale, is_equal_to(139));
|
||||||
|
assert_that(device_scale, is_equal_to(100));
|
||||||
|
}
|
||||||
|
|
||||||
|
Ensure(Utils, CalculateDpiScaleFactorsWhenDpiLessThan173) {
|
||||||
|
uint32 physical_width, physical_height, desktop_scale, device_scale;
|
||||||
|
|
||||||
|
utils_calculate_dpi_scale_factors(1024, 768, 172,
|
||||||
|
&physical_width, &physical_height,
|
||||||
|
&desktop_scale, &device_scale);
|
||||||
|
|
||||||
|
assert_that(physical_width, is_equal_to(151));
|
||||||
|
assert_that(physical_height, is_equal_to(113));
|
||||||
|
assert_that(desktop_scale, is_equal_to(179));
|
||||||
|
assert_that(device_scale, is_equal_to(140));
|
||||||
|
}
|
||||||
|
|
||||||
|
Ensure(Utils, CalculateDpiScaleFactorsWhenDpiGreaterThanOrEqualTo173) {
|
||||||
|
uint32 physical_width, physical_height, desktop_scale, device_scale;
|
||||||
|
|
||||||
|
utils_calculate_dpi_scale_factors(1024, 768, 173,
|
||||||
|
&physical_width, &physical_height,
|
||||||
|
&desktop_scale, &device_scale);
|
||||||
|
|
||||||
|
assert_that(physical_width, is_equal_to(150));
|
||||||
|
assert_that(physical_height, is_equal_to(112));
|
||||||
|
assert_that(desktop_scale, is_equal_to(180));
|
||||||
|
assert_that(device_scale, is_equal_to(180));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
Ensure(Utils, ApplySessionSizeLimitationLimitsWidthAndHeightToMax8192)
|
||||||
|
{
|
||||||
|
uint32 width, height;
|
||||||
|
|
||||||
|
width = height = 90000;
|
||||||
|
|
||||||
|
utils_apply_session_size_limitations(&width, &height);
|
||||||
|
|
||||||
|
assert_that(width, is_equal_to(8192));
|
||||||
|
assert_that(height, is_equal_to(8192));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
Ensure(Utils, ApplySessionSizeLimitationLimitsWidthAndHeightToMin200)
|
||||||
|
{
|
||||||
|
uint32 width, height;
|
||||||
|
|
||||||
|
width = height = 100;
|
||||||
|
|
||||||
|
utils_apply_session_size_limitations(&width, &height);
|
||||||
|
|
||||||
|
assert_that(width, is_equal_to(200));
|
||||||
|
assert_that(height, is_equal_to(200));
|
||||||
|
}
|
||||||
|
|
||||||
|
Ensure(Utils, ApplySessionSizeLimitationRoundsWidthToClosestSmallerEvenNumber)
|
||||||
|
{
|
||||||
|
uint32 width, height;
|
||||||
|
|
||||||
|
width = height = 201;
|
||||||
|
|
||||||
|
utils_apply_session_size_limitations(&width, &height);
|
||||||
|
|
||||||
|
assert_that(width, is_equal_to(200));
|
||||||
|
assert_that(height, is_equal_to(201));
|
||||||
|
}
|
10
tests/x11_mock.c
Normal file
10
tests/x11_mock.c
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
#include <cgreen/mocks.h>
|
||||||
|
#include "../rdesktop.h"
|
||||||
|
#include <X11/Xlib.h>
|
||||||
|
#include <X11/Xutil.h>
|
||||||
|
|
||||||
|
|
||||||
|
XClassHint *XAllocClassHint()
|
||||||
|
{
|
||||||
|
return (XClassHint *)mock();
|
||||||
|
}
|
37
tests/xclip_mock.c
Normal file
37
tests/xclip_mock.c
Normal file
@ -0,0 +1,37 @@
|
|||||||
|
#include <cgreen/mocks.h>
|
||||||
|
#include "../rdesktop.h"
|
||||||
|
|
||||||
|
#include <X11/Xlib.h>
|
||||||
|
|
||||||
|
void xclip_init()
|
||||||
|
{
|
||||||
|
mock();
|
||||||
|
}
|
||||||
|
|
||||||
|
void xclip_deinit()
|
||||||
|
{
|
||||||
|
mock();
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
xclip_handle_SelectionNotify(XSelectionEvent * event)
|
||||||
|
{
|
||||||
|
mock(event);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
xclip_handle_SelectionRequest(XSelectionRequestEvent * xevent)
|
||||||
|
{
|
||||||
|
mock(xevent);
|
||||||
|
}
|
||||||
|
void
|
||||||
|
xclip_handle_SelectionClear(void)
|
||||||
|
{
|
||||||
|
mock();
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
xclip_handle_PropertyNotify(XPropertyEvent * xev)
|
||||||
|
{
|
||||||
|
mock(xev);
|
||||||
|
}
|
63
tests/xkeymap_mock.c
Normal file
63
tests/xkeymap_mock.c
Normal file
@ -0,0 +1,63 @@
|
|||||||
|
#include <cgreen/mocks.h>
|
||||||
|
#include "../rdesktop.h"
|
||||||
|
|
||||||
|
#include <X11/Xlib.h>
|
||||||
|
|
||||||
|
unsigned int read_keyboard_state()
|
||||||
|
{
|
||||||
|
return mock();
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
xkeymap_init()
|
||||||
|
{
|
||||||
|
mock();
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
xkeymap_send_keys(uint32 keysym, unsigned int keycode, unsigned int state, uint32 ev_time,
|
||||||
|
RD_BOOL pressed, uint8 nesting)
|
||||||
|
{
|
||||||
|
mock(keysym, keycode, state, ev_time, pressed, nesting);
|
||||||
|
}
|
||||||
|
|
||||||
|
uint16
|
||||||
|
xkeymap_translate_button(unsigned int button, uint16 * input_type)
|
||||||
|
{
|
||||||
|
return mock(button, input_type);
|
||||||
|
}
|
||||||
|
|
||||||
|
RD_BOOL
|
||||||
|
handle_special_keys(uint32 keysym, unsigned int state, uint32 ev_time, RD_BOOL pressed)
|
||||||
|
{
|
||||||
|
return mock(keysym, state, ev_time, pressed);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
set_keypress_keysym(unsigned int keycode, KeySym keysym)
|
||||||
|
{
|
||||||
|
mock(keycode, keysym);
|
||||||
|
}
|
||||||
|
|
||||||
|
KeySym
|
||||||
|
reset_keypress_keysym(unsigned int keycode, KeySym keysym)
|
||||||
|
{
|
||||||
|
return mock(keycode, keysym);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
reset_modifier_keys()
|
||||||
|
{
|
||||||
|
mock();
|
||||||
|
}
|
||||||
|
|
||||||
|
char *
|
||||||
|
get_ksname(uint32 keysym)
|
||||||
|
{
|
||||||
|
return (char *) mock(keysym);
|
||||||
|
}
|
||||||
|
|
||||||
|
uint16 ui_get_numlock_state(unsigned int state)
|
||||||
|
{
|
||||||
|
return mock(state);
|
||||||
|
}
|
216
tests/xwin_test.c
Normal file
216
tests/xwin_test.c
Normal file
@ -0,0 +1,216 @@
|
|||||||
|
#include <cgreen/cgreen.h>
|
||||||
|
#include <cgreen/mocks.h>
|
||||||
|
#include "../rdesktop.h"
|
||||||
|
#include "../proto.h"
|
||||||
|
|
||||||
|
#include <X11/Xlib.h>
|
||||||
|
#include <X11/Xutil.h>
|
||||||
|
#include <X11/Xproto.h>
|
||||||
|
#include <X11/Xatom.h>
|
||||||
|
|
||||||
|
/* Boilerplate */
|
||||||
|
Describe(XWIN);
|
||||||
|
BeforeEach(XWIN) {};
|
||||||
|
AfterEach(XWIN) {};
|
||||||
|
|
||||||
|
/* Global Variables.. :( */
|
||||||
|
RD_BOOL g_user_quit;
|
||||||
|
RD_BOOL g_exit_mainloop;
|
||||||
|
|
||||||
|
int g_sizeopt;
|
||||||
|
uint32 g_initial_width;
|
||||||
|
uint32 g_initial_height;
|
||||||
|
uint16 g_session_width;
|
||||||
|
uint16 g_session_height;
|
||||||
|
int g_xpos;
|
||||||
|
int g_ypos;
|
||||||
|
int g_pos;
|
||||||
|
RD_BOOL g_sendmotion;
|
||||||
|
RD_BOOL g_fullscreen;
|
||||||
|
RD_BOOL g_grab_keyboard;
|
||||||
|
RD_BOOL g_hide_decorations;
|
||||||
|
RD_BOOL g_pending_resize;
|
||||||
|
char g_title[64];
|
||||||
|
char g_seamless_spawn_cmd[512];
|
||||||
|
/* Color depth of the RDP session.
|
||||||
|
As of RDP 5.1, it may be 8, 15, 16 or 24. */
|
||||||
|
int g_server_depth;
|
||||||
|
int g_win_button_size;
|
||||||
|
RD_BOOL g_seamless_rdp;
|
||||||
|
RD_BOOL g_seamless_persistent_mode;
|
||||||
|
uint32 g_embed_wnd;
|
||||||
|
Atom g_net_wm_state_atom;
|
||||||
|
Atom g_net_wm_desktop_atom;
|
||||||
|
Atom g_net_wm_ping_atom;
|
||||||
|
RD_BOOL g_ownbackstore;
|
||||||
|
RD_BOOL g_rdpsnd;
|
||||||
|
RD_BOOL g_owncolmap;
|
||||||
|
RD_BOOL g_local_cursor;
|
||||||
|
char g_codepage[16];
|
||||||
|
|
||||||
|
#include "../xwin.c"
|
||||||
|
#include "../utils.c"
|
||||||
|
#include "../stream.c"
|
||||||
|
|
||||||
|
/* malloc; exit if out of memory */
|
||||||
|
void *
|
||||||
|
xmalloc(int size)
|
||||||
|
{
|
||||||
|
void *mem = malloc(size);
|
||||||
|
if (mem == NULL)
|
||||||
|
{
|
||||||
|
logger(Core, Error, "xmalloc, failed to allocate %d bytes", size);
|
||||||
|
exit(EX_UNAVAILABLE);
|
||||||
|
}
|
||||||
|
return mem;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Exit on NULL pointer. Use to verify result from XGetImage etc */
|
||||||
|
void
|
||||||
|
exit_if_null(void *ptr)
|
||||||
|
{
|
||||||
|
if (ptr == NULL)
|
||||||
|
{
|
||||||
|
logger(Core, Error, "unexpected null pointer. Out of memory?");
|
||||||
|
exit(EX_UNAVAILABLE);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* strdup */
|
||||||
|
char *
|
||||||
|
xstrdup(const char *s)
|
||||||
|
{
|
||||||
|
char *mem = strdup(s);
|
||||||
|
if (mem == NULL)
|
||||||
|
{
|
||||||
|
logger(Core, Error, "xstrdup(), strdup() failed: %s", strerror(errno));
|
||||||
|
exit(EX_UNAVAILABLE);
|
||||||
|
}
|
||||||
|
return mem;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* realloc; exit if out of memory */
|
||||||
|
void *
|
||||||
|
xrealloc(void *oldmem, size_t size)
|
||||||
|
{
|
||||||
|
void *mem;
|
||||||
|
|
||||||
|
if (size == 0)
|
||||||
|
size = 1;
|
||||||
|
mem = realloc(oldmem, size);
|
||||||
|
if (mem == NULL)
|
||||||
|
{
|
||||||
|
logger(Core, Error, "xrealloc, failed to reallocate %ld bytes", size);
|
||||||
|
exit(EX_UNAVAILABLE);
|
||||||
|
}
|
||||||
|
return mem;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* free */
|
||||||
|
void
|
||||||
|
xfree(void *mem)
|
||||||
|
{
|
||||||
|
free(mem);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Special mocks */
|
||||||
|
|
||||||
|
int XResizeWindow(Display *display, Window wnd, unsigned int width, unsigned int height)
|
||||||
|
{
|
||||||
|
return mock(display, wnd, width, height);
|
||||||
|
}
|
||||||
|
|
||||||
|
Status
|
||||||
|
XGetWindowAttributes(Display *display, Window wnd, XWindowAttributes *attr)
|
||||||
|
{
|
||||||
|
return mock(display, wnd, attr);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
XSetWMSizeHints(Display *display, Window wnd, XSizeHints *hints, Atom property)
|
||||||
|
{
|
||||||
|
mock(display, wnd, hints, property);
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
XSetClipRectangles(Display *display, GC gc, int clip_x_origin,
|
||||||
|
int clip_y_origin, XRectangle rectangles[],
|
||||||
|
int n, int ordering)
|
||||||
|
{
|
||||||
|
return mock(display, gc, clip_x_origin, clip_y_origin,
|
||||||
|
rectangles, n, ordering);
|
||||||
|
}
|
||||||
|
|
||||||
|
int XPending(Display *display)
|
||||||
|
{
|
||||||
|
return mock(display);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Test functions */
|
||||||
|
|
||||||
|
Ensure(XWIN, UiResizeWindowCallsXResizeWindow) {
|
||||||
|
int width = 1024;
|
||||||
|
int height = 768;
|
||||||
|
|
||||||
|
/* stubs */
|
||||||
|
expect(XGetWindowAttributes, will_return(True));
|
||||||
|
expect(XSetWMSizeHints);
|
||||||
|
expect(XSetClipRectangles);
|
||||||
|
|
||||||
|
/* expects */
|
||||||
|
expect(XResizeWindow,
|
||||||
|
when(width, is_equal_to(width)),
|
||||||
|
when(height, is_equal_to(height)));
|
||||||
|
|
||||||
|
ui_resize_window(width, height);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* FIXME: This test is broken */
|
||||||
|
#if 0
|
||||||
|
Ensure(XWIN, UiSelectCallsProcessPendingResizeIfGPendingResizeIsTrue)
|
||||||
|
{
|
||||||
|
g_pending_resize = True;
|
||||||
|
|
||||||
|
expect(rdpdr_add_fds);
|
||||||
|
expect(rdpdr_check_fds);
|
||||||
|
|
||||||
|
expect(ctrl_add_fds);
|
||||||
|
expect(ctrl_check_fds);
|
||||||
|
|
||||||
|
expect(seamless_select_timeout);
|
||||||
|
|
||||||
|
expect(XPending, will_return(0));
|
||||||
|
|
||||||
|
expect(rdpedisp_is_available, will_return(False));
|
||||||
|
|
||||||
|
/* HELP! How do we mock functions within the same unit? We're
|
||||||
|
drawing blanks with plenty of "redefined function" or "multiple
|
||||||
|
definition" errors from the compiler and linker.
|
||||||
|
|
||||||
|
The two attempts below does not work as intended.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/* Letting process_pending_resize return true will break the
|
||||||
|
ui_select loop. */
|
||||||
|
expect(process_pending_resize, will_return(True));
|
||||||
|
|
||||||
|
/* process_fds returning True indicates there is data on rdp socket,
|
||||||
|
assumed this will break out of ui_select loop */
|
||||||
|
//expect(process_fds, will_return(True));
|
||||||
|
|
||||||
|
ui_select(0);
|
||||||
|
}
|
||||||
|
#endif /* broken */
|
||||||
|
|
||||||
|
|
||||||
|
#if 0 /* hackety-hackety-hack /k */
|
||||||
|
Ensure(XWIN, UiSelectCallsRDPEDISPSetSessionSizeOnResize)
|
||||||
|
{
|
||||||
|
g_pending_resize = True;
|
||||||
|
g_resize_timer = (struct timeval) {0, 0};
|
||||||
|
expect(rdpedisp_is_available, will_return(True));
|
||||||
|
expect(rdpedisp_set_session_size);
|
||||||
|
|
||||||
|
ui_select(0);
|
||||||
|
}
|
||||||
|
#endif
|
33
utils.c
33
utils.c
@ -28,9 +28,6 @@
|
|||||||
#include "utils.h"
|
#include "utils.h"
|
||||||
|
|
||||||
extern char g_codepage[16];
|
extern char g_codepage[16];
|
||||||
extern int g_dpi;
|
|
||||||
extern int g_width;
|
|
||||||
extern int g_height;
|
|
||||||
|
|
||||||
static RD_BOOL g_iconv_works = True;
|
static RD_BOOL g_iconv_works = True;
|
||||||
|
|
||||||
@ -240,28 +237,46 @@ utils_locale_to_utf8(const char *src, size_t is, char *dest, size_t os)
|
|||||||
|
|
||||||
|
|
||||||
void
|
void
|
||||||
utils_calculate_dpi_scale_factors(uint32 *physwidth, uint32 *physheight,
|
utils_calculate_dpi_scale_factors(uint32 width, uint32 height, uint32 dpi,
|
||||||
|
uint32 *physwidth, uint32 *physheight,
|
||||||
uint32 *desktopscale, uint32 *devicescale)
|
uint32 *desktopscale, uint32 *devicescale)
|
||||||
{
|
{
|
||||||
*physwidth = *physheight = *desktopscale = *devicescale = 0;
|
*physwidth = *physheight = *desktopscale = *devicescale = 0;
|
||||||
|
|
||||||
if (g_dpi > 0)
|
if (dpi > 0)
|
||||||
{
|
{
|
||||||
*physwidth = g_width * 254 / (g_dpi * 10);
|
*physwidth = width * 254 / (dpi * 10);
|
||||||
*physheight = g_height * 254 / (g_dpi * 10);
|
*physheight = height * 254 / (dpi * 10);
|
||||||
|
|
||||||
/* the spec calls this out as being valid for range
|
/* the spec calls this out as being valid for range
|
||||||
100-500 but I doubt the upper range is accurate */
|
100-500 but I doubt the upper range is accurate */
|
||||||
*desktopscale = g_dpi < 96 ? 100 : (g_dpi * 100 + 48) / 96;
|
*desktopscale = dpi < 96 ? 100 : (dpi * 100 + 48) / 96;
|
||||||
|
|
||||||
/* the only allowed values for device scale factor are
|
/* the only allowed values for device scale factor are
|
||||||
100, 140, and 180. */
|
100, 140, and 180. */
|
||||||
*devicescale = g_dpi < 134 ? 100 : (g_dpi < 173 ? 140 : 180);
|
*devicescale = dpi < 134 ? 100 : (dpi < 173 ? 140 : 180);
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void
|
||||||
|
utils_apply_session_size_limitations(uint32 *width, uint32 *height)
|
||||||
|
{
|
||||||
|
/* width MUST be even number */
|
||||||
|
*width -= (*width) % 2;
|
||||||
|
|
||||||
|
if (*width > 8192)
|
||||||
|
*width = 8192;
|
||||||
|
else if (*width < 200)
|
||||||
|
*width = 200;
|
||||||
|
|
||||||
|
if (*height > 8192)
|
||||||
|
*height = 8192;
|
||||||
|
else if (*height < 200)
|
||||||
|
*height = 200;
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* component logging
|
* component logging
|
||||||
*
|
*
|
||||||
|
5
utils.h
5
utils.h
@ -28,8 +28,11 @@ char *utils_string_unescape(const char *str);
|
|||||||
int utils_locale_to_utf8(const char *src, size_t is, char *dest, size_t os);
|
int utils_locale_to_utf8(const char *src, size_t is, char *dest, size_t os);
|
||||||
int utils_mkdir_safe(const char *path, int mask);
|
int utils_mkdir_safe(const char *path, int mask);
|
||||||
int utils_mkdir_p(const char *path, int mask);
|
int utils_mkdir_p(const char *path, int mask);
|
||||||
void utils_calculate_dpi_scale_factors(uint32 *physwidth, uint32 *physheight,
|
void utils_calculate_dpi_scale_factors(uint32 width, uint32 height, uint32 dpi,
|
||||||
|
uint32 *physwidth, uint32 *physheight,
|
||||||
uint32 *desktopscale, uint32 *devicescale);
|
uint32 *desktopscale, uint32 *devicescale);
|
||||||
|
void utils_apply_session_size_limitations(uint32 *width, uint32 *height);
|
||||||
|
|
||||||
|
|
||||||
typedef enum log_level_t
|
typedef enum log_level_t
|
||||||
{
|
{
|
||||||
|
18
xkeymap.c
18
xkeymap.c
@ -44,6 +44,8 @@ extern int g_keyboard_subtype;
|
|||||||
extern int g_keyboard_functionkeys;
|
extern int g_keyboard_functionkeys;
|
||||||
extern int g_win_button_size;
|
extern int g_win_button_size;
|
||||||
extern RD_BOOL g_enable_compose;
|
extern RD_BOOL g_enable_compose;
|
||||||
|
extern RD_BOOL g_seamless_rdp;
|
||||||
|
extern RD_BOOL g_seamless_active;
|
||||||
extern RDP_VERSION g_rdp_version;
|
extern RDP_VERSION g_rdp_version;
|
||||||
extern RD_BOOL g_numlock_sync;
|
extern RD_BOOL g_numlock_sync;
|
||||||
|
|
||||||
@ -644,7 +646,21 @@ handle_special_keys(uint32 keysym, unsigned int state, uint32 ev_time, RD_BOOL p
|
|||||||
{
|
{
|
||||||
/* Ctrl-Alt-Enter: toggle full screen */
|
/* Ctrl-Alt-Enter: toggle full screen */
|
||||||
if (pressed)
|
if (pressed)
|
||||||
xwin_toggle_fullscreen();
|
{
|
||||||
|
if (!g_seamless_rdp)
|
||||||
|
{
|
||||||
|
/* only allow toggle fullscreen when not running
|
||||||
|
rdesktop in seamless mode */
|
||||||
|
xwin_toggle_fullscreen();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
/* deactivate seamless mode for debug purpose, one can
|
||||||
|
not activate seamless mode again */
|
||||||
|
if (g_seamless_active)
|
||||||
|
ui_seamless_toggle();
|
||||||
|
}
|
||||||
|
}
|
||||||
return True;
|
return True;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
607
xwin.c
607
xwin.c
@ -42,11 +42,14 @@
|
|||||||
#define HOST_NAME_MAX MAXHOSTNAMELEN
|
#define HOST_NAME_MAX MAXHOSTNAMELEN
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
extern RD_BOOL g_user_quit;
|
||||||
|
extern RD_BOOL g_exit_mainloop;
|
||||||
|
|
||||||
extern int g_sizeopt;
|
extern int g_sizeopt;
|
||||||
extern int g_width;
|
extern uint32 g_initial_width;
|
||||||
extern int g_height;
|
extern uint32 g_initial_height;
|
||||||
extern uint32 g_windowed_width;
|
extern uint16 g_session_width;
|
||||||
extern uint32 g_windowed_height;
|
extern uint16 g_session_height;
|
||||||
extern int g_xpos;
|
extern int g_xpos;
|
||||||
extern int g_ypos;
|
extern int g_ypos;
|
||||||
extern int g_pos;
|
extern int g_pos;
|
||||||
@ -62,12 +65,19 @@ extern char g_seamless_spawn_cmd[];
|
|||||||
extern int g_server_depth;
|
extern int g_server_depth;
|
||||||
extern int g_win_button_size;
|
extern int g_win_button_size;
|
||||||
|
|
||||||
|
/* This is a timer used to rate limit actual resizing */
|
||||||
|
static struct timeval g_resize_timer = {0};
|
||||||
|
|
||||||
Display *g_display;
|
Display *g_display;
|
||||||
Time g_last_gesturetime;
|
Time g_last_gesturetime;
|
||||||
static int g_x_socket;
|
static int g_x_socket;
|
||||||
static Screen *g_screen;
|
static Screen *g_screen;
|
||||||
Window g_wnd;
|
Window g_wnd;
|
||||||
|
|
||||||
|
/* These are the last known window sizes. They are updated whenever the window size is changed. */
|
||||||
|
static uint32 g_window_width;
|
||||||
|
static uint32 g_window_height;
|
||||||
|
|
||||||
/* SeamlessRDP support */
|
/* SeamlessRDP support */
|
||||||
typedef struct _seamless_group
|
typedef struct _seamless_group
|
||||||
{
|
{
|
||||||
@ -101,7 +111,7 @@ typedef struct _seamless_window
|
|||||||
static seamless_window *g_seamless_windows = NULL;
|
static seamless_window *g_seamless_windows = NULL;
|
||||||
static unsigned long g_seamless_focused = 0;
|
static unsigned long g_seamless_focused = 0;
|
||||||
static RD_BOOL g_seamless_started = False; /* Server end is up and running */
|
static RD_BOOL g_seamless_started = False; /* Server end is up and running */
|
||||||
static RD_BOOL g_seamless_active = False; /* We are currently in seamless mode */
|
RD_BOOL g_seamless_active = False; /* We are currently in seamless mode */
|
||||||
static RD_BOOL g_seamless_hidden = False; /* Desktop is hidden on server */
|
static RD_BOOL g_seamless_hidden = False; /* Desktop is hidden on server */
|
||||||
static RD_BOOL g_seamless_broken_restack = False; /* WM does not properly restack */
|
static RD_BOOL g_seamless_broken_restack = False; /* WM does not properly restack */
|
||||||
extern RD_BOOL g_seamless_rdp;
|
extern RD_BOOL g_seamless_rdp;
|
||||||
@ -1953,7 +1963,7 @@ ui_init(void)
|
|||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
Initialize connection specific data, such as session size.
|
Initialize connection specific data, such as initial session size.
|
||||||
*/
|
*/
|
||||||
void
|
void
|
||||||
ui_init_connection(void)
|
ui_init_connection(void)
|
||||||
@ -1963,8 +1973,8 @@ ui_init_connection(void)
|
|||||||
*/
|
*/
|
||||||
if (g_fullscreen)
|
if (g_fullscreen)
|
||||||
{
|
{
|
||||||
g_width = WidthOfScreen(g_screen);
|
g_initial_width = WidthOfScreen(g_screen);
|
||||||
g_height = HeightOfScreen(g_screen);
|
g_initial_height = HeightOfScreen(g_screen);
|
||||||
g_using_full_workarea = True;
|
g_using_full_workarea = True;
|
||||||
}
|
}
|
||||||
else if (g_sizeopt < 0)
|
else if (g_sizeopt < 0)
|
||||||
@ -1973,14 +1983,14 @@ ui_init_connection(void)
|
|||||||
if (-g_sizeopt >= 100)
|
if (-g_sizeopt >= 100)
|
||||||
g_using_full_workarea = True;
|
g_using_full_workarea = True;
|
||||||
|
|
||||||
if (g_width > 0)
|
if (g_initial_width > 0)
|
||||||
g_width = g_sizeopt;
|
g_initial_width = g_sizeopt;
|
||||||
|
|
||||||
if (g_height > 0)
|
if (g_initial_height > 0)
|
||||||
g_height = g_sizeopt;
|
g_initial_height = g_sizeopt;
|
||||||
|
|
||||||
g_height = HeightOfScreen(g_screen) * (-g_height) / 100;
|
g_initial_height = HeightOfScreen(g_screen) * (-g_initial_height) / 100;
|
||||||
g_width = WidthOfScreen(g_screen) * (-g_width) / 100;
|
g_initial_width = WidthOfScreen(g_screen) * (-g_initial_width) / 100;
|
||||||
}
|
}
|
||||||
else if (g_sizeopt == 1)
|
else if (g_sizeopt == 1)
|
||||||
{
|
{
|
||||||
@ -1988,21 +1998,18 @@ ui_init_connection(void)
|
|||||||
uint32 x, y, cx, cy;
|
uint32 x, y, cx, cy;
|
||||||
if (get_current_workarea(&x, &y, &cx, &cy) == 0)
|
if (get_current_workarea(&x, &y, &cx, &cy) == 0)
|
||||||
{
|
{
|
||||||
g_width = cx;
|
g_initial_width = cx;
|
||||||
g_height = cy;
|
g_initial_height = cy;
|
||||||
g_using_full_workarea = True;
|
g_using_full_workarea = True;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
logger(GUI, Warning,
|
logger(GUI, Warning,
|
||||||
"Failed to get workarea: probably your window manager does not support extended hints\n");
|
"Failed to get workarea: probably your window manager does not support extended hints\n");
|
||||||
g_width = WidthOfScreen(g_screen);
|
g_initial_width = WidthOfScreen(g_screen);
|
||||||
g_height = HeightOfScreen(g_screen);
|
g_initial_height = HeightOfScreen(g_screen);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* make sure width is a multiple of 4 */
|
|
||||||
g_width = (g_width + 3) & ~3;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -2025,14 +2032,26 @@ ui_deinit(void)
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
static void
|
static unsigned long
|
||||||
get_window_attribs(XSetWindowAttributes * attribs)
|
get_window_attribs(XSetWindowAttributes * attribs)
|
||||||
{
|
{
|
||||||
|
unsigned long vmask = 0;
|
||||||
|
|
||||||
|
vmask = CWBackPixel | CWBorderPixel | CWBackingStore | CWOverrideRedirect | CWColormap;
|
||||||
|
|
||||||
attribs->background_pixel = BlackPixelOfScreen(g_screen);
|
attribs->background_pixel = BlackPixelOfScreen(g_screen);
|
||||||
attribs->border_pixel = WhitePixelOfScreen(g_screen);
|
attribs->border_pixel = WhitePixelOfScreen(g_screen);
|
||||||
attribs->backing_store = g_ownbackstore ? NotUseful : Always;
|
attribs->backing_store = g_ownbackstore ? NotUseful : Always;
|
||||||
attribs->override_redirect = g_fullscreen;
|
attribs->override_redirect = g_fullscreen;
|
||||||
attribs->colormap = g_xcolmap;
|
attribs->colormap = g_xcolmap;
|
||||||
|
|
||||||
|
return vmask;
|
||||||
|
}
|
||||||
|
|
||||||
|
static unsigned long
|
||||||
|
get_window_attribs_seamless(XSetWindowAttributes * attribs)
|
||||||
|
{
|
||||||
|
return (get_window_attribs(attribs) & ~CWOverrideRedirect);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
@ -2051,8 +2070,38 @@ get_input_mask(long *input_mask)
|
|||||||
*input_mask |= LeaveWindowMask;
|
*input_mask |= LeaveWindowMask;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
get_sizehints(XSizeHints *sizehints, uint32 width, uint32 height)
|
||||||
|
{
|
||||||
|
if (sizehints == NULL)
|
||||||
|
return;
|
||||||
|
|
||||||
|
/* user specified position, this is needed to override the choice of
|
||||||
|
window position by window manager when a window is mapped. */
|
||||||
|
sizehints->flags = USPosition;
|
||||||
|
|
||||||
|
/* set minimal size of rdesktop main window */
|
||||||
|
sizehints->flags |= PMinSize;
|
||||||
|
sizehints->min_width = 200;
|
||||||
|
sizehints->min_height = 200;
|
||||||
|
|
||||||
|
/* resize increment */
|
||||||
|
sizehints->flags |= PResizeInc;
|
||||||
|
sizehints->width_inc = 2; /* session width must be divisible by two */
|
||||||
|
sizehints->height_inc = 1;
|
||||||
|
|
||||||
|
if (g_seamless_rdp)
|
||||||
|
{
|
||||||
|
/* disable dynamic session resize based on window size for
|
||||||
|
rdesktop main window when seamless is enabled */
|
||||||
|
sizehints->flags |= PMaxSize;
|
||||||
|
sizehints->min_width = sizehints->max_width = width;
|
||||||
|
sizehints->min_height = sizehints->max_height = height;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
RD_BOOL
|
RD_BOOL
|
||||||
ui_create_window(void)
|
ui_create_window(uint32 width, uint32 height)
|
||||||
{
|
{
|
||||||
uint8 null_pointer_mask[1] = { 0x80 };
|
uint8 null_pointer_mask[1] = { 0x80 };
|
||||||
uint8 null_pointer_data[24] = { 0x00 };
|
uint8 null_pointer_data[24] = { 0x00 };
|
||||||
@ -2060,34 +2109,27 @@ ui_create_window(void)
|
|||||||
XSetWindowAttributes attribs;
|
XSetWindowAttributes attribs;
|
||||||
XClassHint *classhints;
|
XClassHint *classhints;
|
||||||
XSizeHints *sizehints;
|
XSizeHints *sizehints;
|
||||||
|
unsigned long value_mask;
|
||||||
long input_mask, ic_input_mask;
|
long input_mask, ic_input_mask;
|
||||||
XEvent xevent;
|
XEvent xevent;
|
||||||
|
|
||||||
if (g_fullscreen)
|
/* reset stored window sizes */
|
||||||
{
|
g_window_width = 0;
|
||||||
g_width = WidthOfScreen(g_screen);
|
g_window_height = 0;
|
||||||
g_height = HeightOfScreen(g_screen);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
g_width = g_windowed_width;
|
|
||||||
g_height = g_windowed_height;
|
|
||||||
}
|
|
||||||
|
|
||||||
logger(GUI, Debug, "ui_create_window() width = %d, height = %d", g_width, g_height);
|
logger(GUI, Debug, "ui_create_window() width = %d, height = %d", width, height);
|
||||||
|
|
||||||
/* Handle -x-y portion of geometry string */
|
/* Handle -x-y portion of geometry string */
|
||||||
if (g_xpos < 0 || (g_xpos == 0 && (g_pos & 2)))
|
if (g_xpos < 0 || (g_xpos == 0 && (g_pos & 2)))
|
||||||
g_xpos = WidthOfScreen(g_screen) + g_xpos - g_width;
|
g_xpos = WidthOfScreen(g_screen) + g_xpos - width;
|
||||||
if (g_ypos < 0 || (g_ypos == 0 && (g_pos & 4)))
|
if (g_ypos < 0 || (g_ypos == 0 && (g_pos & 4)))
|
||||||
g_ypos = HeightOfScreen(g_screen) + g_ypos - g_height;
|
g_ypos = HeightOfScreen(g_screen) + g_ypos - height;
|
||||||
|
|
||||||
get_window_attribs(&attribs);
|
value_mask = get_window_attribs(&attribs);
|
||||||
|
|
||||||
|
g_wnd = XCreateWindow(g_display, RootWindowOfScreen(g_screen), g_xpos, g_ypos, width,
|
||||||
|
height, 0, g_depth, InputOutput, g_visual, value_mask, &attribs);
|
||||||
|
|
||||||
g_wnd = XCreateWindow(g_display, RootWindowOfScreen(g_screen), g_xpos, g_ypos, g_width,
|
|
||||||
g_height, 0, g_depth, InputOutput, g_visual,
|
|
||||||
CWBackPixel | CWBackingStore | CWOverrideRedirect | CWColormap |
|
|
||||||
CWBorderPixel, &attribs);
|
|
||||||
ewmh_set_wm_pid(g_wnd, getpid());
|
ewmh_set_wm_pid(g_wnd, getpid());
|
||||||
set_wm_client_machine(g_display, g_wnd);
|
set_wm_client_machine(g_display, g_wnd);
|
||||||
|
|
||||||
@ -2102,11 +2144,11 @@ ui_create_window(void)
|
|||||||
|
|
||||||
if ((g_ownbackstore) && (g_backstore == 0))
|
if ((g_ownbackstore) && (g_backstore == 0))
|
||||||
{
|
{
|
||||||
g_backstore = XCreatePixmap(g_display, g_wnd, g_width, g_height, g_depth);
|
g_backstore = XCreatePixmap(g_display, g_wnd, width, height, g_depth);
|
||||||
|
|
||||||
/* clear to prevent rubbish being exposed at startup */
|
/* clear to prevent rubbish being exposed at startup */
|
||||||
XSetForeground(g_display, g_gc, BlackPixelOfScreen(g_screen));
|
XSetForeground(g_display, g_gc, BlackPixelOfScreen(g_screen));
|
||||||
XFillRectangle(g_display, g_backstore, g_gc, 0, 0, g_width, g_height);
|
XFillRectangle(g_display, g_backstore, g_gc, 0, 0, width, height);
|
||||||
}
|
}
|
||||||
|
|
||||||
XStoreName(g_display, g_wnd, g_title);
|
XStoreName(g_display, g_wnd, g_title);
|
||||||
@ -2126,11 +2168,7 @@ ui_create_window(void)
|
|||||||
sizehints = XAllocSizeHints();
|
sizehints = XAllocSizeHints();
|
||||||
if (sizehints)
|
if (sizehints)
|
||||||
{
|
{
|
||||||
sizehints->flags = PMinSize | PMaxSize;
|
get_sizehints(sizehints, width, height);
|
||||||
if (g_pos)
|
|
||||||
sizehints->flags |= PPosition;
|
|
||||||
sizehints->min_width = sizehints->max_width = g_width;
|
|
||||||
sizehints->min_height = sizehints->max_height = g_height;
|
|
||||||
XSetWMNormalHints(g_display, g_wnd, sizehints);
|
XSetWMNormalHints(g_display, g_wnd, sizehints);
|
||||||
XFree(sizehints);
|
XFree(sizehints);
|
||||||
}
|
}
|
||||||
@ -2191,43 +2229,52 @@ ui_create_window(void)
|
|||||||
seamless_restack_test();
|
seamless_restack_test();
|
||||||
}
|
}
|
||||||
|
|
||||||
rdpedisp_set_session_size(g_width, g_height);
|
|
||||||
|
|
||||||
return True;
|
return True;
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
ui_resize_window()
|
ui_resize_window(uint32 width, uint32 height)
|
||||||
{
|
{
|
||||||
|
XWindowAttributes attr;
|
||||||
XSizeHints *sizehints;
|
XSizeHints *sizehints;
|
||||||
Pixmap bs;
|
Pixmap bs;
|
||||||
|
|
||||||
|
XGetWindowAttributes(g_display, g_wnd, &attr);
|
||||||
|
|
||||||
|
if ((attr.width == (int)width && attr.height == (int)height))
|
||||||
|
{
|
||||||
|
/* no-op */
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
logger(GUI, Debug, "ui_resize_window(), Changing window %dx%d to match new session %dx%d size",
|
||||||
|
attr.width, attr.height, width, height);
|
||||||
|
|
||||||
sizehints = XAllocSizeHints();
|
sizehints = XAllocSizeHints();
|
||||||
if (sizehints)
|
if (sizehints)
|
||||||
{
|
{
|
||||||
sizehints->flags = PMinSize | PMaxSize;
|
get_sizehints(sizehints, width, height);
|
||||||
sizehints->min_width = sizehints->max_width = g_width;
|
|
||||||
sizehints->min_height = sizehints->max_height = g_height;
|
|
||||||
XSetWMNormalHints(g_display, g_wnd, sizehints);
|
XSetWMNormalHints(g_display, g_wnd, sizehints);
|
||||||
XFree(sizehints);
|
XFree(sizehints);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!(g_fullscreen || g_embed_wnd))
|
if (!g_embed_wnd)
|
||||||
{
|
{
|
||||||
XResizeWindow(g_display, g_wnd, g_width, g_height);
|
XResizeWindow(g_display, g_wnd, width, height);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* create new backstore pixmap */
|
/* create new backstore pixmap */
|
||||||
if (g_backstore != 0)
|
if (g_backstore != 0)
|
||||||
{
|
{
|
||||||
bs = XCreatePixmap(g_display, g_wnd, g_width, g_height, g_depth);
|
bs = XCreatePixmap(g_display, g_wnd, width, height, g_depth);
|
||||||
XSetForeground(g_display, g_gc, BlackPixelOfScreen(g_screen));
|
XSetForeground(g_display, g_gc, BlackPixelOfScreen(g_screen));
|
||||||
XFillRectangle(g_display, bs, g_gc, 0, 0, g_width, g_height);
|
XFillRectangle(g_display, bs, g_gc, 0, 0, width, height);
|
||||||
XCopyArea(g_display, g_backstore, bs, g_gc, 0, 0, g_width, g_height, 0, 0);
|
XCopyArea(g_display, g_backstore, bs, g_gc, 0, 0, width, height, 0, 0);
|
||||||
XFreePixmap(g_display, g_backstore);
|
XFreePixmap(g_display, g_backstore);
|
||||||
g_backstore = bs;
|
g_backstore = bs;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ui_set_clip(0, 0, width, height);
|
||||||
}
|
}
|
||||||
|
|
||||||
RD_BOOL
|
RD_BOOL
|
||||||
@ -2255,28 +2302,96 @@ ui_destroy_window(void)
|
|||||||
void
|
void
|
||||||
xwin_toggle_fullscreen(void)
|
xwin_toggle_fullscreen(void)
|
||||||
{
|
{
|
||||||
|
uint32 x, y, width, height;
|
||||||
|
XWindowAttributes attr;
|
||||||
|
XSetWindowAttributes setattr;
|
||||||
|
unsigned long value_mask;
|
||||||
Pixmap contents = 0;
|
Pixmap contents = 0;
|
||||||
|
Window unused;
|
||||||
|
int dest_x, dest_y;
|
||||||
|
static uint32 windowed_x = 0;
|
||||||
|
static uint32 windowed_y = 0;
|
||||||
|
static uint32 windowed_height = 0;
|
||||||
|
static uint32 windowed_width = 0;
|
||||||
|
|
||||||
if (g_seamless_active)
|
/* When running rdesktop in seamless mode, toggling of fullscreen is not allowed */
|
||||||
/* Turn off SeamlessRDP mode */
|
if (g_seamless_rdp)
|
||||||
ui_seamless_toggle();
|
return;
|
||||||
|
|
||||||
|
/* get current window size and store it to be used when switching back
|
||||||
|
* from fullscreen mode.
|
||||||
|
*/
|
||||||
|
XGetWindowAttributes(g_display, g_wnd, &attr);
|
||||||
|
|
||||||
|
if (!g_fullscreen || (windowed_width == 0 || windowed_height == 0))
|
||||||
|
{
|
||||||
|
/* only stored if we toggle from windowed -> fullscreen or when
|
||||||
|
* going from fullscreen -> windowed when started in fullscreen mode.
|
||||||
|
*/
|
||||||
|
|
||||||
|
XTranslateCoordinates(g_display, g_wnd,
|
||||||
|
DefaultRootWindow(g_display),
|
||||||
|
0, 0, &dest_x, &dest_y, &unused );
|
||||||
|
|
||||||
|
windowed_x = dest_x;
|
||||||
|
windowed_y = dest_y;
|
||||||
|
windowed_width = attr.width;
|
||||||
|
windowed_height = attr.height;
|
||||||
|
}
|
||||||
|
|
||||||
if (!g_ownbackstore)
|
if (!g_ownbackstore)
|
||||||
{
|
{
|
||||||
/* need to save contents of window */
|
/* need to save contents of current window */
|
||||||
contents = XCreatePixmap(g_display, g_wnd, g_width, g_height, g_depth);
|
contents = XCreatePixmap(g_display, g_wnd, attr.width, attr.height, g_depth);
|
||||||
XCopyArea(g_display, g_wnd, contents, g_gc, 0, 0, g_width, g_height, 0, 0);
|
XCopyArea(g_display, g_wnd, contents, g_gc, 0, 0, attr.width, attr.height, 0, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
ui_destroy_window();
|
|
||||||
g_fullscreen = !g_fullscreen;
|
g_fullscreen = !g_fullscreen;
|
||||||
ui_create_window();
|
|
||||||
|
if (g_fullscreen)
|
||||||
|
{
|
||||||
|
x = 0;
|
||||||
|
y = 0,
|
||||||
|
width = WidthOfScreen(g_screen);
|
||||||
|
height = HeightOfScreen(g_screen);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
x = windowed_x;
|
||||||
|
y = windowed_y;
|
||||||
|
width = windowed_width;
|
||||||
|
height = windowed_height;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Resize rdesktop window using new size and window attributes */
|
||||||
|
XUnmapWindow(g_display, g_wnd);
|
||||||
|
|
||||||
|
XMoveResizeWindow(g_display, g_wnd, x, y, width, height);
|
||||||
|
|
||||||
|
value_mask = get_window_attribs(&setattr);
|
||||||
|
XChangeWindowAttributes(g_display, g_wnd, value_mask, &setattr);
|
||||||
|
|
||||||
|
XMapWindow(g_display, g_wnd);
|
||||||
|
|
||||||
|
/* Change session size to match new window size */
|
||||||
|
if (rdpedisp_is_available() == False)
|
||||||
|
{
|
||||||
|
/* Change session size using disconnect / reconnect mechanism */
|
||||||
|
g_pending_resize = True;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
/* Change session size using DisplayControl extension (RDPEDISP) */
|
||||||
|
rdpedisp_set_session_size(width, height);
|
||||||
|
}
|
||||||
|
|
||||||
XDefineCursor(g_display, g_wnd, g_current_cursor);
|
XDefineCursor(g_display, g_wnd, g_current_cursor);
|
||||||
|
|
||||||
if (!g_ownbackstore)
|
if (!g_ownbackstore)
|
||||||
{
|
{
|
||||||
XCopyArea(g_display, contents, g_wnd, g_gc, 0, 0, g_width, g_height, 0, 0);
|
/* copy back saved contents into new window */
|
||||||
|
XCopyArea(g_display, contents, g_wnd, g_gc, 0, 0, attr.width, attr.height, 0, 0);
|
||||||
XFreePixmap(g_display, contents);
|
XFreePixmap(g_display, contents);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -2284,7 +2399,11 @@ xwin_toggle_fullscreen(void)
|
|||||||
static void
|
static void
|
||||||
handle_button_event(XEvent xevent, RD_BOOL down)
|
handle_button_event(XEvent xevent, RD_BOOL down)
|
||||||
{
|
{
|
||||||
|
XWindowAttributes attr;
|
||||||
uint16 button, input_type, flags = 0;
|
uint16 button, input_type, flags = 0;
|
||||||
|
|
||||||
|
XGetWindowAttributes(g_display, g_wnd, &attr);
|
||||||
|
|
||||||
g_last_gesturetime = xevent.xbutton.time;
|
g_last_gesturetime = xevent.xbutton.time;
|
||||||
/* Reverse the pointer button mapping, e.g. in the case of
|
/* Reverse the pointer button mapping, e.g. in the case of
|
||||||
"left-handed mouse mode"; the RDP session expects to
|
"left-handed mouse mode"; the RDP session expects to
|
||||||
@ -2307,12 +2426,12 @@ handle_button_event(XEvent xevent, RD_BOOL down)
|
|||||||
if (xevent.xbutton.y < g_win_button_size)
|
if (xevent.xbutton.y < g_win_button_size)
|
||||||
{
|
{
|
||||||
/* Check from right to left: */
|
/* Check from right to left: */
|
||||||
if (xevent.xbutton.x >= g_width - g_win_button_size)
|
if (xevent.xbutton.x >= attr.width - g_win_button_size)
|
||||||
{
|
{
|
||||||
/* The close button, continue */
|
/* The close button, continue */
|
||||||
;
|
;
|
||||||
}
|
}
|
||||||
else if (xevent.xbutton.x >= g_width - g_win_button_size * 2)
|
else if (xevent.xbutton.x >= attr.width - g_win_button_size * 2)
|
||||||
{
|
{
|
||||||
/* The maximize/restore button. Do not send to
|
/* The maximize/restore button. Do not send to
|
||||||
server. It might be a good idea to change the
|
server. It might be a good idea to change the
|
||||||
@ -2321,7 +2440,7 @@ handle_button_event(XEvent xevent, RD_BOOL down)
|
|||||||
if (xevent.type == ButtonPress)
|
if (xevent.type == ButtonPress)
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
else if (xevent.xbutton.x >= g_width - g_win_button_size * 3)
|
else if (xevent.xbutton.x >= attr.width - g_win_button_size * 3)
|
||||||
{
|
{
|
||||||
/* The minimize button. Iconify window. */
|
/* The minimize button. Iconify window. */
|
||||||
if (xevent.type == ButtonRelease)
|
if (xevent.type == ButtonRelease)
|
||||||
@ -2376,7 +2495,6 @@ handle_button_event(XEvent xevent, RD_BOOL down)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/* Process events in Xlib queue
|
/* Process events in Xlib queue
|
||||||
Returns 0 after user quit, 1 otherwise */
|
Returns 0 after user quit, 1 otherwise */
|
||||||
static int
|
static int
|
||||||
@ -2389,6 +2507,7 @@ xwin_process_events(void)
|
|||||||
Status status;
|
Status status;
|
||||||
int events = 0;
|
int events = 0;
|
||||||
seamless_window *sw;
|
seamless_window *sw;
|
||||||
|
static RD_BOOL is_g_wnd_mapped = False;
|
||||||
|
|
||||||
while ((XPending(g_display) > 0) && events++ < 20)
|
while ((XPending(g_display) > 0) && events++ < 20)
|
||||||
{
|
{
|
||||||
@ -2682,28 +2801,101 @@ xwin_process_events(void)
|
|||||||
|
|
||||||
break;
|
break;
|
||||||
case MapNotify:
|
case MapNotify:
|
||||||
|
if (xevent.xconfigure.window == g_wnd)
|
||||||
|
{
|
||||||
|
XWindowAttributes attr;
|
||||||
|
XGetWindowAttributes(g_display, g_wnd, &attr);
|
||||||
|
g_window_width = attr.width;
|
||||||
|
g_window_height = attr.height;
|
||||||
|
|
||||||
|
logger(GUI, Debug, "xwin_process_events(), Window mapped with size %dx%d",
|
||||||
|
g_window_width, g_window_height);
|
||||||
|
|
||||||
|
is_g_wnd_mapped = True;
|
||||||
|
}
|
||||||
|
|
||||||
if (!g_seamless_active)
|
if (!g_seamless_active)
|
||||||
|
{
|
||||||
rdp_send_suppress_output_pdu(ALLOW_DISPLAY_UPDATES);
|
rdp_send_suppress_output_pdu(ALLOW_DISPLAY_UPDATES);
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
case UnmapNotify:
|
case UnmapNotify:
|
||||||
|
if (xevent.xconfigure.window == g_wnd)
|
||||||
|
{
|
||||||
|
is_g_wnd_mapped = False;
|
||||||
|
}
|
||||||
|
|
||||||
if (!g_seamless_active)
|
if (!g_seamless_active)
|
||||||
|
{
|
||||||
rdp_send_suppress_output_pdu(SUPPRESS_DISPLAY_UPDATES);
|
rdp_send_suppress_output_pdu(SUPPRESS_DISPLAY_UPDATES);
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
case ConfigureNotify:
|
case ConfigureNotify:
|
||||||
#ifdef HAVE_XRANDR
|
#ifdef HAVE_XRANDR
|
||||||
if ((g_sizeopt || g_fullscreen)
|
/* Resize on root window size change */
|
||||||
&& xevent.xconfigure.window == DefaultRootWindow(g_display))
|
if (xevent.xconfigure.window == DefaultRootWindow(g_display))
|
||||||
{
|
{
|
||||||
if (xevent.xconfigure.width != WidthOfScreen(g_screen)
|
/* only for fullscreen or x%-of-screen-sized windows */
|
||||||
|| xevent.xconfigure.height != HeightOfScreen(g_screen))
|
if (g_sizeopt || g_fullscreen)
|
||||||
{
|
{
|
||||||
XRRUpdateConfiguration(&xevent);
|
if (xevent.xconfigure.width != WidthOfScreen(g_screen)
|
||||||
XSync(g_display, False);
|
|| xevent.xconfigure.height != HeightOfScreen(g_screen))
|
||||||
g_pending_resize = True;
|
{
|
||||||
|
|
||||||
|
logger(GUI, Debug,
|
||||||
|
"xwin_process_events(), ConfigureNotify: Root window changed to %dx%d",
|
||||||
|
xevent.xconfigure.width,
|
||||||
|
xevent.xconfigure.height);
|
||||||
|
|
||||||
|
gettimeofday(&g_resize_timer, NULL);
|
||||||
|
g_pending_resize = True;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
XRRUpdateConfiguration(&xevent);
|
||||||
|
XSync(g_display, False);
|
||||||
|
|
||||||
|
} else
|
||||||
#endif
|
#endif
|
||||||
|
if (xevent.xconfigure.window == g_wnd && !g_seamless_rdp && is_g_wnd_mapped)
|
||||||
|
{
|
||||||
|
|
||||||
|
/* Update window size */
|
||||||
|
g_window_width = xevent.xconfigure.width;
|
||||||
|
g_window_height = xevent.xconfigure.height;
|
||||||
|
|
||||||
|
uint32 w, h;
|
||||||
|
w = g_window_width;
|
||||||
|
h = g_window_height;
|
||||||
|
|
||||||
|
utils_apply_session_size_limitations(&w, &h);
|
||||||
|
|
||||||
|
logger(GUI, Debug, "xwin_process_events(), ConfigureNotify: session: %dx%d, new window: %dx%d (adj: %dx%d)",
|
||||||
|
g_session_width,
|
||||||
|
g_session_height,
|
||||||
|
g_window_width,
|
||||||
|
g_window_height,
|
||||||
|
w, h);
|
||||||
|
|
||||||
|
if (g_session_width != w
|
||||||
|
|| g_session_height != h)
|
||||||
|
{
|
||||||
|
logger(GUI, Debug, "xwin_process_events(), ConfigureNotify: session: %dx%d, new window: %dx%d",
|
||||||
|
g_session_width,
|
||||||
|
g_session_height,
|
||||||
|
g_window_width,
|
||||||
|
g_window_height);
|
||||||
|
|
||||||
|
/* perform a resize */
|
||||||
|
gettimeofday(&g_resize_timer, NULL);
|
||||||
|
g_pending_resize = True;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
g_pending_resize = False;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (!g_seamless_active)
|
if (!g_seamless_active)
|
||||||
break;
|
break;
|
||||||
|
|
||||||
@ -2732,78 +2924,195 @@ xwin_process_events(void)
|
|||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Returns 0 after user quit or pending resize, 1 otherwise */
|
static inline uint32
|
||||||
int
|
time_difference_in_ms(struct timeval then, struct timeval now)
|
||||||
ui_select(int rdp_socket)
|
|
||||||
{
|
{
|
||||||
int n;
|
uint32 ms;
|
||||||
|
ms = 0;
|
||||||
|
ms += (now.tv_sec - then.tv_sec) * 1000;
|
||||||
|
ms += (now.tv_usec - then.tv_usec) / 1000;
|
||||||
|
return ms;
|
||||||
|
}
|
||||||
|
|
||||||
|
time_t g_wait_for_deactivate_ts = 0;
|
||||||
|
|
||||||
|
static RD_BOOL
|
||||||
|
process_fds(int rdp_socket, int ms)
|
||||||
|
{
|
||||||
|
int n, ret;
|
||||||
fd_set rfds, wfds;
|
fd_set rfds, wfds;
|
||||||
struct timeval tv;
|
struct timeval tv;
|
||||||
RD_BOOL s_timeout = False;
|
RD_BOOL s_timeout = False;
|
||||||
|
|
||||||
while (True)
|
n = (rdp_socket > g_x_socket) ? rdp_socket : g_x_socket;
|
||||||
|
|
||||||
|
FD_ZERO(&rfds);
|
||||||
|
FD_ZERO(&wfds);
|
||||||
|
FD_SET(rdp_socket, &rfds);
|
||||||
|
FD_SET(g_x_socket, &rfds);
|
||||||
|
|
||||||
|
/* default timeout */
|
||||||
|
tv.tv_sec = ms / 1000;
|
||||||
|
tv.tv_usec = (ms - (tv.tv_sec * 1000)) * 1000;
|
||||||
|
|
||||||
|
#ifdef WITH_RDPSND
|
||||||
|
rdpsnd_add_fds(&n, &rfds, &wfds, &tv);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* add redirection handles */
|
||||||
|
rdpdr_add_fds(&n, &rfds, &wfds, &tv, &s_timeout);
|
||||||
|
seamless_select_timeout(&tv);
|
||||||
|
|
||||||
|
/* add ctrl slaves handles */
|
||||||
|
ctrl_add_fds(&n, &rfds);
|
||||||
|
|
||||||
|
n++;
|
||||||
|
|
||||||
|
ret = select(n, &rfds, &wfds, NULL, &tv);
|
||||||
|
if (ret <= 0)
|
||||||
{
|
{
|
||||||
n = (rdp_socket > g_x_socket) ? rdp_socket : g_x_socket;
|
if (ret == -1)
|
||||||
/* Process any events already waiting */
|
|
||||||
if (!xwin_process_events())
|
|
||||||
/* User quit */
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
if (g_pending_resize)
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
if (g_seamless_active)
|
|
||||||
sw_check_timers();
|
|
||||||
|
|
||||||
FD_ZERO(&rfds);
|
|
||||||
FD_ZERO(&wfds);
|
|
||||||
FD_SET(rdp_socket, &rfds);
|
|
||||||
FD_SET(g_x_socket, &rfds);
|
|
||||||
|
|
||||||
/* default timeout */
|
|
||||||
tv.tv_sec = 60;
|
|
||||||
tv.tv_usec = 0;
|
|
||||||
|
|
||||||
#ifdef WITH_RDPSND
|
|
||||||
rdpsnd_add_fds(&n, &rfds, &wfds, &tv);
|
|
||||||
#endif
|
|
||||||
|
|
||||||
/* add redirection handles */
|
|
||||||
rdpdr_add_fds(&n, &rfds, &wfds, &tv, &s_timeout);
|
|
||||||
seamless_select_timeout(&tv);
|
|
||||||
|
|
||||||
/* add ctrl slaves handles */
|
|
||||||
ctrl_add_fds(&n, &rfds);
|
|
||||||
|
|
||||||
n++;
|
|
||||||
|
|
||||||
switch (select(n, &rfds, &wfds, NULL, &tv))
|
|
||||||
{
|
{
|
||||||
case -1:
|
logger(GUI, Error, "process_fds(), select failed: %s",
|
||||||
logger(GUI, Error, "ui_select(), select failed: %s",
|
strerror(errno));
|
||||||
strerror(errno));
|
|
||||||
|
|
||||||
case 0:
|
|
||||||
#ifdef WITH_RDPSND
|
|
||||||
rdpsnd_check_fds(&rfds, &wfds);
|
|
||||||
#endif
|
|
||||||
|
|
||||||
/* Abort serial read calls */
|
|
||||||
if (s_timeout)
|
|
||||||
rdpdr_check_fds(&rfds, &wfds, (RD_BOOL) True);
|
|
||||||
continue;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef WITH_RDPSND
|
#ifdef WITH_RDPSND
|
||||||
rdpsnd_check_fds(&rfds, &wfds);
|
rdpsnd_check_fds(&rfds, &wfds);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
rdpdr_check_fds(&rfds, &wfds, (RD_BOOL) False);
|
/* Abort serial read calls */
|
||||||
|
if (s_timeout)
|
||||||
|
rdpdr_check_fds(&rfds, &wfds, (RD_BOOL) True);
|
||||||
|
return False;
|
||||||
|
}
|
||||||
|
|
||||||
ctrl_check_fds(&rfds, &wfds);
|
#ifdef WITH_RDPSND
|
||||||
|
rdpsnd_check_fds(&rfds, &wfds);
|
||||||
|
#endif
|
||||||
|
|
||||||
if (FD_ISSET(rdp_socket, &rfds))
|
rdpdr_check_fds(&rfds, &wfds, (RD_BOOL) False);
|
||||||
return 1;
|
|
||||||
|
ctrl_check_fds(&rfds, &wfds);
|
||||||
|
|
||||||
|
if (FD_ISSET(rdp_socket, &rfds))
|
||||||
|
return True;
|
||||||
|
|
||||||
|
return False;
|
||||||
|
}
|
||||||
|
|
||||||
|
static RD_BOOL
|
||||||
|
process_ui()
|
||||||
|
{
|
||||||
|
if (!xwin_process_events())
|
||||||
|
{
|
||||||
|
/* User quit */
|
||||||
|
g_pending_resize = False;
|
||||||
|
return True;
|
||||||
|
}
|
||||||
|
return False;
|
||||||
|
}
|
||||||
|
|
||||||
|
static RD_BOOL
|
||||||
|
process_pending_resize ()
|
||||||
|
{
|
||||||
|
uint32 width, height;
|
||||||
|
time_t now_ts;
|
||||||
|
struct timeval now;
|
||||||
|
|
||||||
|
/* Rate limit ConfigureNotify events before performing a
|
||||||
|
resize - enough time has to pass after the last event
|
||||||
|
*/
|
||||||
|
gettimeofday(&now, NULL);
|
||||||
|
if (time_difference_in_ms(g_resize_timer, now) <= 500)
|
||||||
|
return False;
|
||||||
|
|
||||||
|
/* carry out a resize to desired size */
|
||||||
|
if (rdpedisp_is_available() == False)
|
||||||
|
{
|
||||||
|
/* resize session using disconnect reconnect
|
||||||
|
* sequence if RDPEDISP is not support by
|
||||||
|
* server.
|
||||||
|
*/
|
||||||
|
|
||||||
|
g_initial_width = g_window_width;
|
||||||
|
g_initial_height = g_window_height;
|
||||||
|
|
||||||
|
logger(GUI, Verbose, "Window resize detected, reconnecting to new size %dx%d",
|
||||||
|
g_initial_width,
|
||||||
|
g_initial_height);
|
||||||
|
|
||||||
|
return True;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
now_ts = time(NULL);
|
||||||
|
if (now_ts - g_wait_for_deactivate_ts <= 5)
|
||||||
|
return False;
|
||||||
|
|
||||||
|
/* size of current window */
|
||||||
|
width = g_window_width;
|
||||||
|
height = g_window_height;
|
||||||
|
|
||||||
|
/* resize session using RDPEDISP */
|
||||||
|
if (g_fullscreen || g_seamless_rdp)
|
||||||
|
{
|
||||||
|
/* size of screen */
|
||||||
|
width = WidthOfScreen(g_screen);
|
||||||
|
height = HeightOfScreen(g_screen);
|
||||||
|
}
|
||||||
|
|
||||||
|
logger(GUI, Verbose, "Window resize detected, requesting matching session size %dx%d",
|
||||||
|
width, height);
|
||||||
|
|
||||||
|
rdpedisp_set_session_size(width, height);
|
||||||
|
|
||||||
|
g_pending_resize = False;
|
||||||
|
g_wait_for_deactivate_ts = now_ts;
|
||||||
|
}
|
||||||
|
|
||||||
|
return False;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Breaks out of loop if g_exit_mainloop is set or if there is data available on rdp socket for
|
||||||
|
processing. */
|
||||||
|
void
|
||||||
|
ui_select(int rdp_socket)
|
||||||
|
{
|
||||||
|
RD_BOOL rdp_socket_has_data = False;
|
||||||
|
|
||||||
|
while (g_exit_mainloop == False && rdp_socket_has_data == False)
|
||||||
|
{
|
||||||
|
|
||||||
|
/* Process any events already waiting */
|
||||||
|
|
||||||
|
/* returns True on user quit */
|
||||||
|
if (process_ui() == True)
|
||||||
|
{
|
||||||
|
g_exit_mainloop = True;
|
||||||
|
g_user_quit = True;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (g_pending_resize == True)
|
||||||
|
{
|
||||||
|
/* returns True on disconnect-reconnect resize */
|
||||||
|
if (process_pending_resize() == True)
|
||||||
|
{
|
||||||
|
g_exit_mainloop = True;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (g_seamless_active)
|
||||||
|
sw_check_timers();
|
||||||
|
|
||||||
|
/* We end up here when we are waiting for a resize timer to expire before attempting
|
||||||
|
to resize the session. We don't want to sleep in the select for up to 60 seconds
|
||||||
|
if there are no RDP packets if the resize timer is 0.5 seconds. */
|
||||||
|
if (g_pending_resize == True)
|
||||||
|
rdp_socket_has_data = process_fds(rdp_socket, 100);
|
||||||
|
else
|
||||||
|
rdp_socket_has_data = process_fds(rdp_socket, 60000);
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -3275,11 +3584,9 @@ ui_set_clip(int x, int y, int cx, int cy)
|
|||||||
void
|
void
|
||||||
ui_reset_clip(void)
|
ui_reset_clip(void)
|
||||||
{
|
{
|
||||||
g_clip_rectangle.x = 0;
|
XWindowAttributes attr;
|
||||||
g_clip_rectangle.y = 0;
|
XGetWindowAttributes(g_display, g_wnd, &attr);
|
||||||
g_clip_rectangle.width = g_width;
|
ui_set_clip(0, 0, attr.width, attr.height);
|
||||||
g_clip_rectangle.height = g_height;
|
|
||||||
XSetClipRectangles(g_display, g_gc, 0, 0, &g_clip_rectangle, 1, YXBanded);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
@ -3756,9 +4063,12 @@ ui_draw_text(uint8 font, uint8 flags, uint8 opcode, int mixmode, int x, int y,
|
|||||||
int boxx, int boxy, int boxcx, int boxcy, BRUSH * brush,
|
int boxx, int boxy, int boxcx, int boxcy, BRUSH * brush,
|
||||||
uint32 bgcolour, uint32 fgcolour, uint8 * text, uint8 length)
|
uint32 bgcolour, uint32 fgcolour, uint8 * text, uint8 length)
|
||||||
{
|
{
|
||||||
|
XWindowAttributes attr;
|
||||||
UNUSED(opcode);
|
UNUSED(opcode);
|
||||||
UNUSED(brush);
|
UNUSED(brush);
|
||||||
|
|
||||||
|
XGetWindowAttributes(g_display, g_wnd, &attr);
|
||||||
|
|
||||||
/* TODO: use brush appropriately */
|
/* TODO: use brush appropriately */
|
||||||
|
|
||||||
FONTGLYPH *glyph;
|
FONTGLYPH *glyph;
|
||||||
@ -3770,8 +4080,8 @@ ui_draw_text(uint8 font, uint8 flags, uint8 opcode, int mixmode, int x, int y,
|
|||||||
/* Sometimes, the boxcx value is something really large, like
|
/* Sometimes, the boxcx value is something really large, like
|
||||||
32691. This makes XCopyArea fail with Xvnc. The code below
|
32691. This makes XCopyArea fail with Xvnc. The code below
|
||||||
is a quick fix. */
|
is a quick fix. */
|
||||||
if (boxx + boxcx > g_width)
|
if (boxx + boxcx > attr.width)
|
||||||
boxcx = g_width - boxx;
|
boxcx = attr.width - boxx;
|
||||||
|
|
||||||
if (boxcx > 1)
|
if (boxcx > 1)
|
||||||
{
|
{
|
||||||
@ -4062,6 +4372,7 @@ ui_seamless_create_window(unsigned long id, unsigned long group, unsigned long p
|
|||||||
XSizeHints *sizehints;
|
XSizeHints *sizehints;
|
||||||
XWMHints *wmhints;
|
XWMHints *wmhints;
|
||||||
long input_mask;
|
long input_mask;
|
||||||
|
unsigned long value_mask;
|
||||||
seamless_window *sw, *sw_parent;
|
seamless_window *sw, *sw_parent;
|
||||||
|
|
||||||
if (!g_seamless_active)
|
if (!g_seamless_active)
|
||||||
@ -4072,10 +4383,10 @@ ui_seamless_create_window(unsigned long id, unsigned long group, unsigned long p
|
|||||||
if (sw)
|
if (sw)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
get_window_attribs(&attribs);
|
value_mask = get_window_attribs_seamless(&attribs);
|
||||||
wnd = XCreateWindow(g_display, RootWindowOfScreen(g_screen), -1, -1, 1, 1, 0, g_depth,
|
wnd = XCreateWindow(g_display, RootWindowOfScreen(g_screen), -1, -1, 1, 1, 0, g_depth,
|
||||||
InputOutput, g_visual,
|
InputOutput, g_visual, value_mask, &attribs);
|
||||||
CWBackPixel | CWBackingStore | CWColormap | CWBorderPixel, &attribs);
|
|
||||||
ewmh_set_wm_pid(wnd, getpid());
|
ewmh_set_wm_pid(wnd, getpid());
|
||||||
set_wm_client_machine(g_display, wnd);
|
set_wm_client_machine(g_display, wnd);
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user