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
|
||||
autom4te.cache
|
||||
Makefile
|
||||
/Makefile
|
||||
config.log
|
||||
config.status
|
||||
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);
|
||||
void ui_init_connection(void);
|
||||
void ui_deinit(void);
|
||||
RD_BOOL ui_create_window(void);
|
||||
void ui_resize_window(void);
|
||||
RD_BOOL ui_create_window(uint32 width, uint32 height);
|
||||
void ui_resize_window(uint32 width, uint32 height);
|
||||
void ui_destroy_window(void);
|
||||
RD_BOOL ui_have_window(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);
|
||||
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);
|
||||
@ -329,6 +329,7 @@ void ui_seamless_ack(unsigned int serial);
|
||||
RD_BOOL lspci_init(void);
|
||||
/* rdpedisp.c */
|
||||
void rdpedisp_init(void);
|
||||
RD_BOOL rdpedisp_is_available();
|
||||
void rdpedisp_set_session_size(uint32 width, uint32 height);
|
||||
/* dvc.c */
|
||||
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
|
||||
specifies the percent of the whole screen. */
|
||||
int g_dpi = 0; /* device DPI: default not set */
|
||||
int g_width = 1024;
|
||||
int g_height = 768;
|
||||
uint32 g_windowed_width = 1024;
|
||||
uint32 g_windowed_height = 768;
|
||||
|
||||
/* Following variables holds the initial width and height for a
|
||||
rdesktop window, this is sent upon connect and tells the server
|
||||
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_ypos = 0;
|
||||
int g_pos = 0; /* 0 position unspecified,
|
||||
@ -712,17 +715,17 @@ main(int argc, char *argv[])
|
||||
break;
|
||||
}
|
||||
|
||||
g_width = strtol(optarg, &p, 10);
|
||||
if (g_width <= 0)
|
||||
g_initial_width = strtol(optarg, &p, 10);
|
||||
if (g_initial_width <= 0)
|
||||
{
|
||||
logger(Core, Error, "invalid geometry width specified");
|
||||
return EX_USAGE;
|
||||
}
|
||||
|
||||
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");
|
||||
return EX_USAGE;
|
||||
@ -730,16 +733,16 @@ main(int argc, char *argv[])
|
||||
|
||||
if (*p == '%')
|
||||
{
|
||||
g_sizeopt = -g_width;
|
||||
g_width = g_sizeopt;
|
||||
g_sizeopt = -g_initial_width;
|
||||
g_initial_width = g_sizeopt;
|
||||
|
||||
if (*(p + 1) == 'x')
|
||||
{
|
||||
g_height = -strtol(p + 2, &p, 10);
|
||||
g_initial_height = -strtol(p + 2, &p, 10);
|
||||
}
|
||||
else
|
||||
{
|
||||
g_height = g_sizeopt;
|
||||
g_initial_height = g_sizeopt;
|
||||
}
|
||||
|
||||
p++;
|
||||
@ -767,9 +770,6 @@ main(int argc, char *argv[])
|
||||
g_ypos = strtol(p, NULL, 10);
|
||||
}
|
||||
|
||||
g_windowed_height = g_height;
|
||||
g_windowed_width = g_width;
|
||||
|
||||
break;
|
||||
|
||||
case 'f':
|
||||
@ -1240,6 +1240,8 @@ main(int argc, char *argv[])
|
||||
}
|
||||
|
||||
ui_init_connection();
|
||||
utils_apply_session_size_limitations(&g_initial_width, &g_initial_height);
|
||||
|
||||
if (!rdp_connect
|
||||
(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 */
|
||||
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_reconnect_loop = True;
|
||||
continue;
|
||||
@ -1839,7 +1843,7 @@ rd_create_ui()
|
||||
if (!ui_have_window())
|
||||
{
|
||||
/* 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);
|
||||
}
|
||||
else
|
||||
|
70
rdp.c
70
rdp.c
@ -43,13 +43,16 @@ extern RDP_VERSION g_rdp_version;
|
||||
extern uint16 g_server_rdp_version;
|
||||
extern uint32 g_rdp5_performanceflags;
|
||||
extern int g_server_depth;
|
||||
extern int g_width;
|
||||
extern int g_height;
|
||||
extern uint32 g_initial_width;
|
||||
extern uint32 g_initial_height;
|
||||
extern RD_BOOL g_bitmap_cache;
|
||||
extern RD_BOOL g_bitmap_cache_persist_enable;
|
||||
extern RD_BOOL g_numlock_sync;
|
||||
extern RD_BOOL g_pending_resize;
|
||||
extern RD_BOOL g_network_error;
|
||||
extern time_t g_wait_for_deactivate_ts;
|
||||
|
||||
RD_BOOL g_exit_mainloop = False;
|
||||
|
||||
uint8 *g_next_packet;
|
||||
uint32 g_rdp_shareid;
|
||||
@ -80,6 +83,11 @@ extern RD_BOOL g_has_reconnect_random;
|
||||
extern uint8 g_client_random[SEC_RANDOM_SIZE];
|
||||
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);
|
||||
|
||||
/* Receive an RDP packet */
|
||||
@ -556,8 +564,8 @@ rdp_send_suppress_output_pdu(enum RDP_SUPPRESS_STATUS allowupdates)
|
||||
case ALLOW_DISPLAY_UPDATES: /* receive data again */
|
||||
out_uint16_le(s, 0); /* left */
|
||||
out_uint16_le(s, 0); /* top */
|
||||
out_uint16_le(s, g_width); /* right */
|
||||
out_uint16_le(s, g_height); /* bottom */
|
||||
out_uint16_le(s, g_session_width); /* right */
|
||||
out_uint16_le(s, g_session_height); /* bottom */
|
||||
break;
|
||||
}
|
||||
|
||||
@ -659,14 +667,16 @@ rdp_out_ts_general_capabilityset(STREAM s)
|
||||
static void
|
||||
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_CAPLEN_BITMAP);
|
||||
out_uint16_le(s, g_server_depth); /* preferredBitsPerPixel */
|
||||
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); /* receive8BitPerPixel (ignored, should be 1) */
|
||||
out_uint16_le(s, g_width); /* desktopWidth */
|
||||
out_uint16_le(s, g_height); /* desktopHeight */
|
||||
out_uint16_le(s, g_session_width); /* desktopWidth */
|
||||
out_uint16_le(s, g_session_height); /* desktopHeight */
|
||||
out_uint16_le(s, 0); /* pad2Octets */
|
||||
out_uint16_le(s, 1); /* desktopResizeFlag */
|
||||
out_uint16_le(s, 1); /* bitmapCompressionFlag (must be 1) */
|
||||
@ -1051,17 +1061,17 @@ rdp_process_general_caps(STREAM s)
|
||||
static void
|
||||
rdp_process_bitmap_caps(STREAM s)
|
||||
{
|
||||
uint16 width, height, depth;
|
||||
uint16 depth;
|
||||
|
||||
in_uint16_le(s, depth);
|
||||
in_uint8s(s, 6);
|
||||
|
||||
in_uint16_le(s, width);
|
||||
in_uint16_le(s, height);
|
||||
in_uint16_le(s, g_session_width);
|
||||
in_uint16_le(s, g_session_height);
|
||||
|
||||
logger(Protocol, Debug,
|
||||
"rdp_process_bitmap_caps(), setting desktop size and depth to: %dx%dx%d", width,
|
||||
height, depth);
|
||||
"rdp_process_bitmap_caps(), setting desktop size and depth to: %dx%dx%d",
|
||||
g_session_width, g_session_height, depth);
|
||||
|
||||
/*
|
||||
* 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;
|
||||
}
|
||||
if (g_width != width || g_height != height)
|
||||
{
|
||||
logger(Protocol, Debug,
|
||||
"rdp_process_bitmap_caps(), remote desktop changed from %dx%d to %dx%d.\n",
|
||||
g_width, g_height, width, height);
|
||||
g_width = width;
|
||||
g_height = height;
|
||||
ui_resize_window();
|
||||
}
|
||||
|
||||
/* resize viewport window to new session size, this is an
|
||||
no-op if there is no change in size between session size
|
||||
reported from server and the actual window size */
|
||||
ui_resize_window(g_session_width, g_session_height);
|
||||
}
|
||||
|
||||
/* 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");
|
||||
}
|
||||
|
||||
return True;
|
||||
return g_redirect;
|
||||
}
|
||||
|
||||
/* Process incoming packets */
|
||||
void
|
||||
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 */
|
||||
@ -1814,7 +1823,7 @@ rdp_loop(RD_BOOL * deactivated, uint32 * ext_disc_reason)
|
||||
RD_BOOL cont = True;
|
||||
STREAM s;
|
||||
|
||||
while (cont)
|
||||
while (g_exit_mainloop == False && cont)
|
||||
{
|
||||
s = rdp_recv(&type);
|
||||
if (s == NULL)
|
||||
@ -1829,12 +1838,15 @@ rdp_loop(RD_BOOL * deactivated, uint32 * ext_disc_reason)
|
||||
logger(Protocol, Debug,
|
||||
"rdp_loop(), RDP_PDU_DEACTIVATE packet received");
|
||||
*deactivated = True;
|
||||
g_wait_for_deactivate_ts = 0;
|
||||
break;
|
||||
case RDP_PDU_REDIRECT:
|
||||
return process_redirect_pdu(s, False);
|
||||
break;
|
||||
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;
|
||||
case RDP_PDU_DATA:
|
||||
/* 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 RDPEDISP_CHANNEL_NAME "Microsoft::Windows::RDS::DisplayControl"
|
||||
|
||||
extern int g_dpi;
|
||||
|
||||
static void rdpedisp_send(STREAM s);
|
||||
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, 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, physheight); /* physicalheight */
|
||||
out_uint32_le(&s, ORIENTATION_LANDSCAPE); /* Orientation */
|
||||
@ -116,7 +120,7 @@ rdpedisp_send(STREAM s)
|
||||
dvc_send(RDPEDISP_CHANNEL_NAME, s);
|
||||
}
|
||||
|
||||
static RD_BOOL
|
||||
RD_BOOL
|
||||
rdpedisp_is_available()
|
||||
{
|
||||
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)
|
||||
return;
|
||||
|
||||
/* monitor width MUST be even number */
|
||||
utils_apply_session_size_limitations(&width, &height);
|
||||
|
||||
rdpedisp_send_monitor_layout_pdu(width, height);
|
||||
}
|
||||
|
||||
|
11
secure.c
11
secure.c
@ -23,8 +23,8 @@
|
||||
#include "ssl.h"
|
||||
|
||||
extern char g_hostname[16];
|
||||
extern int g_width;
|
||||
extern int g_height;
|
||||
extern uint32 g_initial_width;
|
||||
extern uint32 g_initial_height;
|
||||
extern int g_dpi;
|
||||
extern unsigned int g_keylayout;
|
||||
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, 216 + (g_dpi > 0 ? 18 : 0)); /* length */
|
||||
out_uint32_le(s, rdpversion); /* version */
|
||||
out_uint16_le(s, g_width); /* desktopWidth */
|
||||
out_uint16_le(s, g_height); /* desktopHeight */
|
||||
out_uint16_le(s, g_initial_width); /* desktopWidth */
|
||||
out_uint16_le(s, g_initial_height); /* desktopHeight */
|
||||
out_uint16_le(s, RNS_UD_COLOR_8BPP); /* colorDepth */
|
||||
out_uint16_le(s, RNS_UD_SAS_DEL); /* SASSequence */
|
||||
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)
|
||||
{
|
||||
/* 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);
|
||||
out_uint32_le(s, physwidth); /* physicalwidth */
|
||||
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_out[STREAM_COUNT];
|
||||
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_reconnect_loop;
|
||||
|
||||
@ -220,13 +221,13 @@ tcp_recv(STREAM s, uint32 length)
|
||||
{
|
||||
if ((!g_ssl || SSL_pending(g_ssl) <= 0) && g_run_ui)
|
||||
{
|
||||
if (!ui_select(g_sock))
|
||||
{
|
||||
/* User quit */
|
||||
g_user_quit = True;
|
||||
ui_select(g_sock);
|
||||
|
||||
/* break out of recv, if request of exiting
|
||||
main loop has been done */
|
||||
if (g_exit_mainloop == True)
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
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"
|
||||
|
||||
extern char g_codepage[16];
|
||||
extern int g_dpi;
|
||||
extern int g_width;
|
||||
extern int g_height;
|
||||
|
||||
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
|
||||
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)
|
||||
{
|
||||
*physwidth = *physheight = *desktopscale = *devicescale = 0;
|
||||
|
||||
if (g_dpi > 0)
|
||||
if (dpi > 0)
|
||||
{
|
||||
*physwidth = g_width * 254 / (g_dpi * 10);
|
||||
*physheight = g_height * 254 / (g_dpi * 10);
|
||||
*physwidth = width * 254 / (dpi * 10);
|
||||
*physheight = height * 254 / (dpi * 10);
|
||||
|
||||
/* the spec calls this out as being valid for range
|
||||
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
|
||||
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
|
||||
*
|
||||
|
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_mkdir_safe(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);
|
||||
void utils_apply_session_size_limitations(uint32 *width, uint32 *height);
|
||||
|
||||
|
||||
typedef enum log_level_t
|
||||
{
|
||||
|
16
xkeymap.c
16
xkeymap.c
@ -44,6 +44,8 @@ extern int g_keyboard_subtype;
|
||||
extern int g_keyboard_functionkeys;
|
||||
extern int g_win_button_size;
|
||||
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 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 */
|
||||
if (pressed)
|
||||
{
|
||||
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;
|
||||
}
|
||||
break;
|
||||
|
535
xwin.c
535
xwin.c
@ -42,11 +42,14 @@
|
||||
#define HOST_NAME_MAX MAXHOSTNAMELEN
|
||||
#endif
|
||||
|
||||
extern RD_BOOL g_user_quit;
|
||||
extern RD_BOOL g_exit_mainloop;
|
||||
|
||||
extern int g_sizeopt;
|
||||
extern int g_width;
|
||||
extern int g_height;
|
||||
extern uint32 g_windowed_width;
|
||||
extern uint32 g_windowed_height;
|
||||
extern uint32 g_initial_width;
|
||||
extern uint32 g_initial_height;
|
||||
extern uint16 g_session_width;
|
||||
extern uint16 g_session_height;
|
||||
extern int g_xpos;
|
||||
extern int g_ypos;
|
||||
extern int g_pos;
|
||||
@ -62,12 +65,19 @@ extern char g_seamless_spawn_cmd[];
|
||||
extern int g_server_depth;
|
||||
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;
|
||||
Time g_last_gesturetime;
|
||||
static int g_x_socket;
|
||||
static Screen *g_screen;
|
||||
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 */
|
||||
typedef struct _seamless_group
|
||||
{
|
||||
@ -101,7 +111,7 @@ typedef struct _seamless_window
|
||||
static seamless_window *g_seamless_windows = NULL;
|
||||
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_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_broken_restack = False; /* WM does not properly restack */
|
||||
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
|
||||
ui_init_connection(void)
|
||||
@ -1963,8 +1973,8 @@ ui_init_connection(void)
|
||||
*/
|
||||
if (g_fullscreen)
|
||||
{
|
||||
g_width = WidthOfScreen(g_screen);
|
||||
g_height = HeightOfScreen(g_screen);
|
||||
g_initial_width = WidthOfScreen(g_screen);
|
||||
g_initial_height = HeightOfScreen(g_screen);
|
||||
g_using_full_workarea = True;
|
||||
}
|
||||
else if (g_sizeopt < 0)
|
||||
@ -1973,14 +1983,14 @@ ui_init_connection(void)
|
||||
if (-g_sizeopt >= 100)
|
||||
g_using_full_workarea = True;
|
||||
|
||||
if (g_width > 0)
|
||||
g_width = g_sizeopt;
|
||||
if (g_initial_width > 0)
|
||||
g_initial_width = g_sizeopt;
|
||||
|
||||
if (g_height > 0)
|
||||
g_height = g_sizeopt;
|
||||
if (g_initial_height > 0)
|
||||
g_initial_height = g_sizeopt;
|
||||
|
||||
g_height = HeightOfScreen(g_screen) * (-g_height) / 100;
|
||||
g_width = WidthOfScreen(g_screen) * (-g_width) / 100;
|
||||
g_initial_height = HeightOfScreen(g_screen) * (-g_initial_height) / 100;
|
||||
g_initial_width = WidthOfScreen(g_screen) * (-g_initial_width) / 100;
|
||||
}
|
||||
else if (g_sizeopt == 1)
|
||||
{
|
||||
@ -1988,21 +1998,18 @@ ui_init_connection(void)
|
||||
uint32 x, y, cx, cy;
|
||||
if (get_current_workarea(&x, &y, &cx, &cy) == 0)
|
||||
{
|
||||
g_width = cx;
|
||||
g_height = cy;
|
||||
g_initial_width = cx;
|
||||
g_initial_height = cy;
|
||||
g_using_full_workarea = True;
|
||||
}
|
||||
else
|
||||
{
|
||||
logger(GUI, Warning,
|
||||
"Failed to get workarea: probably your window manager does not support extended hints\n");
|
||||
g_width = WidthOfScreen(g_screen);
|
||||
g_height = HeightOfScreen(g_screen);
|
||||
g_initial_width = WidthOfScreen(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)
|
||||
{
|
||||
unsigned long vmask = 0;
|
||||
|
||||
vmask = CWBackPixel | CWBorderPixel | CWBackingStore | CWOverrideRedirect | CWColormap;
|
||||
|
||||
attribs->background_pixel = BlackPixelOfScreen(g_screen);
|
||||
attribs->border_pixel = WhitePixelOfScreen(g_screen);
|
||||
attribs->backing_store = g_ownbackstore ? NotUseful : Always;
|
||||
attribs->override_redirect = g_fullscreen;
|
||||
attribs->colormap = g_xcolmap;
|
||||
|
||||
return vmask;
|
||||
}
|
||||
|
||||
static unsigned long
|
||||
get_window_attribs_seamless(XSetWindowAttributes * attribs)
|
||||
{
|
||||
return (get_window_attribs(attribs) & ~CWOverrideRedirect);
|
||||
}
|
||||
|
||||
static void
|
||||
@ -2051,8 +2070,38 @@ get_input_mask(long *input_mask)
|
||||
*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
|
||||
ui_create_window(void)
|
||||
ui_create_window(uint32 width, uint32 height)
|
||||
{
|
||||
uint8 null_pointer_mask[1] = { 0x80 };
|
||||
uint8 null_pointer_data[24] = { 0x00 };
|
||||
@ -2060,34 +2109,27 @@ ui_create_window(void)
|
||||
XSetWindowAttributes attribs;
|
||||
XClassHint *classhints;
|
||||
XSizeHints *sizehints;
|
||||
unsigned long value_mask;
|
||||
long input_mask, ic_input_mask;
|
||||
XEvent xevent;
|
||||
|
||||
if (g_fullscreen)
|
||||
{
|
||||
g_width = WidthOfScreen(g_screen);
|
||||
g_height = HeightOfScreen(g_screen);
|
||||
}
|
||||
else
|
||||
{
|
||||
g_width = g_windowed_width;
|
||||
g_height = g_windowed_height;
|
||||
}
|
||||
/* reset stored window sizes */
|
||||
g_window_width = 0;
|
||||
g_window_height = 0;
|
||||
|
||||
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 */
|
||||
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)))
|
||||
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());
|
||||
set_wm_client_machine(g_display, g_wnd);
|
||||
|
||||
@ -2102,11 +2144,11 @@ ui_create_window(void)
|
||||
|
||||
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 */
|
||||
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);
|
||||
@ -2126,11 +2168,7 @@ ui_create_window(void)
|
||||
sizehints = XAllocSizeHints();
|
||||
if (sizehints)
|
||||
{
|
||||
sizehints->flags = PMinSize | PMaxSize;
|
||||
if (g_pos)
|
||||
sizehints->flags |= PPosition;
|
||||
sizehints->min_width = sizehints->max_width = g_width;
|
||||
sizehints->min_height = sizehints->max_height = g_height;
|
||||
get_sizehints(sizehints, width, height);
|
||||
XSetWMNormalHints(g_display, g_wnd, sizehints);
|
||||
XFree(sizehints);
|
||||
}
|
||||
@ -2191,43 +2229,52 @@ ui_create_window(void)
|
||||
seamless_restack_test();
|
||||
}
|
||||
|
||||
rdpedisp_set_session_size(g_width, g_height);
|
||||
|
||||
return True;
|
||||
}
|
||||
|
||||
void
|
||||
ui_resize_window()
|
||||
ui_resize_window(uint32 width, uint32 height)
|
||||
{
|
||||
XWindowAttributes attr;
|
||||
XSizeHints *sizehints;
|
||||
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();
|
||||
if (sizehints)
|
||||
{
|
||||
sizehints->flags = PMinSize | PMaxSize;
|
||||
sizehints->min_width = sizehints->max_width = g_width;
|
||||
sizehints->min_height = sizehints->max_height = g_height;
|
||||
get_sizehints(sizehints, width, height);
|
||||
XSetWMNormalHints(g_display, g_wnd, 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 */
|
||||
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));
|
||||
XFillRectangle(g_display, bs, g_gc, 0, 0, g_width, g_height);
|
||||
XCopyArea(g_display, g_backstore, bs, g_gc, 0, 0, g_width, g_height, 0, 0);
|
||||
XFillRectangle(g_display, bs, g_gc, 0, 0, width, height);
|
||||
XCopyArea(g_display, g_backstore, bs, g_gc, 0, 0, width, height, 0, 0);
|
||||
XFreePixmap(g_display, g_backstore);
|
||||
g_backstore = bs;
|
||||
}
|
||||
|
||||
ui_set_clip(0, 0, width, height);
|
||||
}
|
||||
|
||||
RD_BOOL
|
||||
@ -2255,28 +2302,96 @@ ui_destroy_window(void)
|
||||
void
|
||||
xwin_toggle_fullscreen(void)
|
||||
{
|
||||
uint32 x, y, width, height;
|
||||
XWindowAttributes attr;
|
||||
XSetWindowAttributes setattr;
|
||||
unsigned long value_mask;
|
||||
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)
|
||||
/* Turn off SeamlessRDP mode */
|
||||
ui_seamless_toggle();
|
||||
/* When running rdesktop in seamless mode, toggling of fullscreen is not allowed */
|
||||
if (g_seamless_rdp)
|
||||
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)
|
||||
{
|
||||
/* need to save contents of window */
|
||||
contents = XCreatePixmap(g_display, g_wnd, g_width, g_height, g_depth);
|
||||
XCopyArea(g_display, g_wnd, contents, g_gc, 0, 0, g_width, g_height, 0, 0);
|
||||
/* need to save contents of current window */
|
||||
contents = XCreatePixmap(g_display, g_wnd, attr.width, attr.height, g_depth);
|
||||
XCopyArea(g_display, g_wnd, contents, g_gc, 0, 0, attr.width, attr.height, 0, 0);
|
||||
}
|
||||
|
||||
ui_destroy_window();
|
||||
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);
|
||||
|
||||
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);
|
||||
}
|
||||
}
|
||||
@ -2284,7 +2399,11 @@ xwin_toggle_fullscreen(void)
|
||||
static void
|
||||
handle_button_event(XEvent xevent, RD_BOOL down)
|
||||
{
|
||||
XWindowAttributes attr;
|
||||
uint16 button, input_type, flags = 0;
|
||||
|
||||
XGetWindowAttributes(g_display, g_wnd, &attr);
|
||||
|
||||
g_last_gesturetime = xevent.xbutton.time;
|
||||
/* Reverse the pointer button mapping, e.g. in the case of
|
||||
"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)
|
||||
{
|
||||
/* 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 */
|
||||
;
|
||||
}
|
||||
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
|
||||
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)
|
||||
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. */
|
||||
if (xevent.type == ButtonRelease)
|
||||
@ -2376,7 +2495,6 @@ handle_button_event(XEvent xevent, RD_BOOL down)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/* Process events in Xlib queue
|
||||
Returns 0 after user quit, 1 otherwise */
|
||||
static int
|
||||
@ -2389,6 +2507,7 @@ xwin_process_events(void)
|
||||
Status status;
|
||||
int events = 0;
|
||||
seamless_window *sw;
|
||||
static RD_BOOL is_g_wnd_mapped = False;
|
||||
|
||||
while ((XPending(g_display) > 0) && events++ < 20)
|
||||
{
|
||||
@ -2682,28 +2801,101 @@ xwin_process_events(void)
|
||||
|
||||
break;
|
||||
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)
|
||||
{
|
||||
rdp_send_suppress_output_pdu(ALLOW_DISPLAY_UPDATES);
|
||||
}
|
||||
break;
|
||||
case UnmapNotify:
|
||||
if (xevent.xconfigure.window == g_wnd)
|
||||
{
|
||||
is_g_wnd_mapped = False;
|
||||
}
|
||||
|
||||
if (!g_seamless_active)
|
||||
{
|
||||
rdp_send_suppress_output_pdu(SUPPRESS_DISPLAY_UPDATES);
|
||||
}
|
||||
break;
|
||||
case ConfigureNotify:
|
||||
#ifdef HAVE_XRANDR
|
||||
if ((g_sizeopt || g_fullscreen)
|
||||
&& xevent.xconfigure.window == DefaultRootWindow(g_display))
|
||||
/* Resize on root window size change */
|
||||
if (xevent.xconfigure.window == DefaultRootWindow(g_display))
|
||||
{
|
||||
/* only for fullscreen or x%-of-screen-sized windows */
|
||||
if (g_sizeopt || g_fullscreen)
|
||||
{
|
||||
if (xevent.xconfigure.width != WidthOfScreen(g_screen)
|
||||
|| xevent.xconfigure.height != HeightOfScreen(g_screen))
|
||||
{
|
||||
XRRUpdateConfiguration(&xevent);
|
||||
XSync(g_display, False);
|
||||
|
||||
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
|
||||
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)
|
||||
break;
|
||||
|
||||
@ -2732,28 +2924,27 @@ xwin_process_events(void)
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* Returns 0 after user quit or pending resize, 1 otherwise */
|
||||
int
|
||||
ui_select(int rdp_socket)
|
||||
static inline uint32
|
||||
time_difference_in_ms(struct timeval then, struct timeval now)
|
||||
{
|
||||
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;
|
||||
struct timeval tv;
|
||||
RD_BOOL s_timeout = False;
|
||||
|
||||
while (True)
|
||||
{
|
||||
n = (rdp_socket > g_x_socket) ? rdp_socket : g_x_socket;
|
||||
/* 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);
|
||||
@ -2761,8 +2952,8 @@ ui_select(int rdp_socket)
|
||||
FD_SET(g_x_socket, &rfds);
|
||||
|
||||
/* default timeout */
|
||||
tv.tv_sec = 60;
|
||||
tv.tv_usec = 0;
|
||||
tv.tv_sec = ms / 1000;
|
||||
tv.tv_usec = (ms - (tv.tv_sec * 1000)) * 1000;
|
||||
|
||||
#ifdef WITH_RDPSND
|
||||
rdpsnd_add_fds(&n, &rfds, &wfds, &tv);
|
||||
@ -2777,13 +2968,14 @@ ui_select(int rdp_socket)
|
||||
|
||||
n++;
|
||||
|
||||
switch (select(n, &rfds, &wfds, NULL, &tv))
|
||||
ret = select(n, &rfds, &wfds, NULL, &tv);
|
||||
if (ret <= 0)
|
||||
{
|
||||
case -1:
|
||||
logger(GUI, Error, "ui_select(), select failed: %s",
|
||||
if (ret == -1)
|
||||
{
|
||||
logger(GUI, Error, "process_fds(), select failed: %s",
|
||||
strerror(errno));
|
||||
|
||||
case 0:
|
||||
}
|
||||
#ifdef WITH_RDPSND
|
||||
rdpsnd_check_fds(&rfds, &wfds);
|
||||
#endif
|
||||
@ -2791,7 +2983,7 @@ ui_select(int rdp_socket)
|
||||
/* Abort serial read calls */
|
||||
if (s_timeout)
|
||||
rdpdr_check_fds(&rfds, &wfds, (RD_BOOL) True);
|
||||
continue;
|
||||
return False;
|
||||
}
|
||||
|
||||
#ifdef WITH_RDPSND
|
||||
@ -2803,7 +2995,124 @@ ui_select(int rdp_socket)
|
||||
ctrl_check_fds(&rfds, &wfds);
|
||||
|
||||
if (FD_ISSET(rdp_socket, &rfds))
|
||||
return 1;
|
||||
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
|
||||
ui_reset_clip(void)
|
||||
{
|
||||
g_clip_rectangle.x = 0;
|
||||
g_clip_rectangle.y = 0;
|
||||
g_clip_rectangle.width = g_width;
|
||||
g_clip_rectangle.height = g_height;
|
||||
XSetClipRectangles(g_display, g_gc, 0, 0, &g_clip_rectangle, 1, YXBanded);
|
||||
XWindowAttributes attr;
|
||||
XGetWindowAttributes(g_display, g_wnd, &attr);
|
||||
ui_set_clip(0, 0, attr.width, attr.height);
|
||||
}
|
||||
|
||||
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,
|
||||
uint32 bgcolour, uint32 fgcolour, uint8 * text, uint8 length)
|
||||
{
|
||||
XWindowAttributes attr;
|
||||
UNUSED(opcode);
|
||||
UNUSED(brush);
|
||||
|
||||
XGetWindowAttributes(g_display, g_wnd, &attr);
|
||||
|
||||
/* TODO: use brush appropriately */
|
||||
|
||||
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
|
||||
32691. This makes XCopyArea fail with Xvnc. The code below
|
||||
is a quick fix. */
|
||||
if (boxx + boxcx > g_width)
|
||||
boxcx = g_width - boxx;
|
||||
if (boxx + boxcx > attr.width)
|
||||
boxcx = attr.width - boxx;
|
||||
|
||||
if (boxcx > 1)
|
||||
{
|
||||
@ -4062,6 +4372,7 @@ ui_seamless_create_window(unsigned long id, unsigned long group, unsigned long p
|
||||
XSizeHints *sizehints;
|
||||
XWMHints *wmhints;
|
||||
long input_mask;
|
||||
unsigned long value_mask;
|
||||
seamless_window *sw, *sw_parent;
|
||||
|
||||
if (!g_seamless_active)
|
||||
@ -4072,10 +4383,10 @@ ui_seamless_create_window(unsigned long id, unsigned long group, unsigned long p
|
||||
if (sw)
|
||||
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,
|
||||
InputOutput, g_visual,
|
||||
CWBackPixel | CWBackingStore | CWColormap | CWBorderPixel, &attribs);
|
||||
InputOutput, g_visual, value_mask, &attribs);
|
||||
|
||||
ewmh_set_wm_pid(wnd, getpid());
|
||||
set_wm_client_machine(g_display, wnd);
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user