diff --git a/constants.h b/constants.h index a266de3..0d48416 100644 --- a/constants.h +++ b/constants.h @@ -682,6 +682,14 @@ enum RDP_PDU_REDIRECT_FLAGS LB_TARGET_CERTIFICATE = 0x10000 }; +/* desttop orientation */ +enum RDP_DESKTOP_ORIENTATION +{ + ORIENTATION_LANDSCAPE = 0, + ORIENTATION_PORTRAIT = 90, + ORIENTATION_LANDSCAPE_FLIPPED = 180, + ORIENTATION_PORTRAIT_FLIPPED = 270 +}; /* color depths, from [MS-RDPBCGR] 2.2.1.3.2 */ #define RNS_UD_COLOR_4BPP 0xCA00 #define RNS_UD_COLOR_8BPP 0xCA01 diff --git a/doc/rdesktop.1 b/doc/rdesktop.1 index a43b6fa..3708105 100644 --- a/doc/rdesktop.1 +++ b/doc/rdesktop.1 @@ -63,15 +63,20 @@ basic alphanumeric keys and may not work properly on all platforms so its use is discouraged. .TP .BR "-g " -Desktop geometry (WxH). If geometry is the special word "workarea", the geometry -will be fetched from the extended window manager hints property _NET_WORKAREA, from -the root window. The geometry can also be specified as a percentage of the whole -screen, e.g. "-g 80%", "-g 80%x70%". +Desktop geometry (WxH[@DPI][+X[+Y]]). If geometry is the special word +"workarea", the geometry will be fetched from the extended window +manager hints property _NET_WORKAREA, from the root window. The +geometry can also be specified as a percentage of the whole screen, +e.g. "-g 80%", "-g 80%x70%". If the specified geometry depends on the screen size, and the screen size is changed, rdesktop will automatically reconnect using the new screen size. This requires that rdesktop has been compiled with RandR support. + +The optional DPI parameter should be specified if the screen rdesktop +is being displayed on is too far from 96 DPI for unscaled Windows to +be readable. Windows currently accepts values from 96 to 480. .TP .BR "-i" Use password as smartcard pin. If a valid user certificate is matched in smart card diff --git a/rdesktop.c b/rdesktop.c index 73aacbf..26411f7 100644 --- a/rdesktop.c +++ b/rdesktop.c @@ -71,6 +71,7 @@ int g_sizeopt = 0; /* If non-zero, a special size has been requested. If 1, the geometry will be fetched 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 = 800; int g_height = 600; int g_xpos = 0; @@ -169,7 +170,7 @@ usage(char *program) fprintf(stderr, " -p: password (- to prompt)\n"); fprintf(stderr, " -n: client hostname\n"); fprintf(stderr, " -k: keyboard layout on server (en-us, de, sv, etc.)\n"); - fprintf(stderr, " -g: desktop geometry (WxH)\n"); + fprintf(stderr, " -g: desktop geometry (WxH[@dpi])\n"); #ifdef WITH_SCARD fprintf(stderr, " -i: enables smartcard authentication, password is used as pin\n"); #endif @@ -741,6 +742,16 @@ main(int argc, char *argv[]) p++; } + if (*p == '@') + { + g_dpi = strtol(p + 1, &p, 10); + if (g_dpi <= 0) + { + logger(Core, Error, "invalid DPI: expected a positive integer after @\n"); + return EX_USAGE; + } + } + if (*p == '+' || *p == '-') { g_pos |= (*p == '-') ? 2 : 1; diff --git a/secure.c b/secure.c index 9328739..1b0927f 100644 --- a/secure.c +++ b/secure.c @@ -25,6 +25,7 @@ extern char g_hostname[16]; extern int g_width; extern int g_height; +extern int g_dpi; extern unsigned int g_keylayout; extern int g_keyboard_type; extern int g_keyboard_subtype; @@ -391,7 +392,7 @@ sec_establish_key(void) static void sec_out_mcs_connect_initial_pdu(STREAM s, uint32 selected_protocol) { - int length = 162 + 76 + 12 + 4; + int length = 162 + 76 + 12 + 4 + (g_dpi > 0 ? 18 : 0); unsigned int i; uint32 rdpversion = RDP_40; uint16 capflags = RNS_UD_CS_SUPPORT_ERRINFO_PDU; @@ -422,7 +423,7 @@ sec_out_mcs_connect_initial_pdu(STREAM s, uint32 selected_protocol) /* Client information (TS_UD_CS_CORE) */ out_uint16_le(s, CS_CORE); /* type */ - out_uint16_le(s, 216); /* length */ + 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 */ @@ -454,6 +455,17 @@ sec_out_mcs_connect_initial_pdu(STREAM s, uint32 selected_protocol) out_uint8(s, 0); /* connectionType */ out_uint8(s, 0); /* pad */ out_uint32_le(s, selected_protocol); /* serverSelectedProtocol */ + if (g_dpi > 0) + { + /* Extended client info describing monitor geometry */ + out_uint32_le(s, g_width * 254 / (g_dpi * 10)); /* desktop physical width */ + out_uint32_le(s, g_height * 254 / (g_dpi * 10)); /* desktop physical height */ + out_uint16_le(s, ORIENTATION_LANDSCAPE); + out_uint32_le(s, g_dpi < 96 ? 100 : (g_dpi * 100 + 48) / 96); /* desktop scale factor */ + /* the spec calls this out as being valid for range 100-500 but I doubt the upper range is accurate */ + out_uint32_le(s, g_dpi < 134 ? 100 : (g_dpi < 173 ? 140 : 180)); /* device scale factor */ + /* the only allowed values for device scale factor are 100, 140, and 180. */ + } /* Write a Client Cluster Data (TS_UD_CS_CLUSTER) */ uint32 cluster_flags = 0;