mirror of
https://git.tartarus.org/simon/putty.git
synced 2025-01-10 09:58:01 +00:00
Merge legacy-Windows fixes (mostly) from 'pre-0.77'.
This commit is contained in:
commit
accf9adac2
@ -79,6 +79,11 @@ add_executable(test_host_strfoo
|
|||||||
target_compile_definitions(test_host_strfoo PRIVATE TEST)
|
target_compile_definitions(test_host_strfoo PRIVATE TEST)
|
||||||
target_link_libraries(test_host_strfoo utils ${platform_libraries})
|
target_link_libraries(test_host_strfoo utils ${platform_libraries})
|
||||||
|
|
||||||
|
add_executable(test_decode_utf8
|
||||||
|
utils/decode_utf8.c)
|
||||||
|
target_compile_definitions(test_decode_utf8 PRIVATE TEST)
|
||||||
|
target_link_libraries(test_decode_utf8 utils ${platform_libraries})
|
||||||
|
|
||||||
add_executable(test_tree234
|
add_executable(test_tree234
|
||||||
utils/tree234.c)
|
utils/tree234.c)
|
||||||
target_compile_definitions(test_tree234 PRIVATE TEST)
|
target_compile_definitions(test_tree234 PRIVATE TEST)
|
||||||
|
4
defs.h
4
defs.h
@ -42,6 +42,8 @@
|
|||||||
#define SIZEx "Ix"
|
#define SIZEx "Ix"
|
||||||
#define SIZEu "Iu"
|
#define SIZEu "Iu"
|
||||||
uintmax_t strtoumax(const char *nptr, char **endptr, int base);
|
uintmax_t strtoumax(const char *nptr, char **endptr, int base);
|
||||||
|
/* Also, define a LEGACY_WINDOWS flag to enable other workarounds */
|
||||||
|
#define LEGACY_WINDOWS
|
||||||
#else
|
#else
|
||||||
#include <inttypes.h>
|
#include <inttypes.h>
|
||||||
/* Because we still support older MSVC libraries which don't recognise the
|
/* Because we still support older MSVC libraries which don't recognise the
|
||||||
@ -192,6 +194,8 @@ typedef struct logblank_t logblank_t;
|
|||||||
typedef struct BinaryPacketProtocol BinaryPacketProtocol;
|
typedef struct BinaryPacketProtocol BinaryPacketProtocol;
|
||||||
typedef struct PacketProtocolLayer PacketProtocolLayer;
|
typedef struct PacketProtocolLayer PacketProtocolLayer;
|
||||||
|
|
||||||
|
struct unicode_data;
|
||||||
|
|
||||||
/* Do a compile-time type-check of 'to_check' (without evaluating it),
|
/* Do a compile-time type-check of 'to_check' (without evaluating it),
|
||||||
* as a side effect of returning the value 'to_return'. Note that
|
* as a side effect of returning the value 'to_return'. Note that
|
||||||
* although this macro double-*expands* to_return, it always
|
* although this macro double-*expands* to_return, it always
|
||||||
|
15
misc.h
15
misc.h
@ -67,6 +67,10 @@ void strbuf_finalise_agent_query(strbuf *buf);
|
|||||||
* work around the rather deficient interface of mb_to_wc. */
|
* work around the rather deficient interface of mb_to_wc. */
|
||||||
wchar_t *dup_mb_to_wc_c(int codepage, int flags, const char *string, int len);
|
wchar_t *dup_mb_to_wc_c(int codepage, int flags, const char *string, int len);
|
||||||
wchar_t *dup_mb_to_wc(int codepage, int flags, const char *string);
|
wchar_t *dup_mb_to_wc(int codepage, int flags, const char *string);
|
||||||
|
char *dup_wc_to_mb_c(int codepage, int flags, const wchar_t *string, int len,
|
||||||
|
const char *defchr, struct unicode_data *ucsdata);
|
||||||
|
char *dup_wc_to_mb(int codepage, int flags, const wchar_t *string,
|
||||||
|
const char *defchr, struct unicode_data *ucsdata);
|
||||||
|
|
||||||
static inline int toint(unsigned u)
|
static inline int toint(unsigned u)
|
||||||
{
|
{
|
||||||
@ -217,6 +221,17 @@ size_t encode_utf8(void *output, unsigned long ch);
|
|||||||
* encoded in UTF-16. */
|
* encoded in UTF-16. */
|
||||||
char *encode_wide_string_as_utf8(const wchar_t *wstr);
|
char *encode_wide_string_as_utf8(const wchar_t *wstr);
|
||||||
|
|
||||||
|
/* Decode a single UTF-8 character. Returns U+FFFD for any of the
|
||||||
|
* illegal cases. */
|
||||||
|
unsigned long decode_utf8(const char **utf8);
|
||||||
|
|
||||||
|
/* Decode a single UTF-8 character to an output buffer of the
|
||||||
|
* platform's wchar_t. May write a pair of surrogates if
|
||||||
|
* sizeof(wchar_t) == 2, assuming that in that case the wide string is
|
||||||
|
* encoded in UTF-16. Otherwise, writes one character. Returns the
|
||||||
|
* number written. */
|
||||||
|
size_t decode_utf8_to_wchar(const char **utf8, wchar_t *out);
|
||||||
|
|
||||||
/* Write a string out in C string-literal format. */
|
/* Write a string out in C string-literal format. */
|
||||||
void write_c_string_literal(FILE *fp, ptrlen str);
|
void write_c_string_literal(FILE *fp, ptrlen str);
|
||||||
|
|
||||||
|
@ -47,8 +47,18 @@ void interactor_return_seat(Interactor *itr)
|
|||||||
if (!is_tempseat(tempseat))
|
if (!is_tempseat(tempseat))
|
||||||
return; /* no-op */
|
return; /* no-op */
|
||||||
|
|
||||||
tempseat_flush(tempseat);
|
/*
|
||||||
|
* We're about to hand this seat back to the parent Interactor to
|
||||||
|
* do its own thing with. It will typically expect to start in the
|
||||||
|
* same state as if the seat had never been borrowed, i.e. in the
|
||||||
|
* starting trust state.
|
||||||
|
*
|
||||||
|
* However, this may be overridden by the tempseat_flush call.
|
||||||
|
*/
|
||||||
Seat *realseat = tempseat_get_real(tempseat);
|
Seat *realseat = tempseat_get_real(tempseat);
|
||||||
|
seat_set_trust_status(realseat, true);
|
||||||
|
|
||||||
|
tempseat_flush(tempseat);
|
||||||
interactor_set_seat(itr, realseat);
|
interactor_set_seat(itr, realseat);
|
||||||
tempseat_free(tempseat);
|
tempseat_free(tempseat);
|
||||||
|
|
||||||
@ -60,14 +70,6 @@ void interactor_return_seat(Interactor *itr)
|
|||||||
Interactor *itr_top = interactor_toplevel(itr, NULL);
|
Interactor *itr_top = interactor_toplevel(itr, NULL);
|
||||||
if (itr_top->last_to_talk)
|
if (itr_top->last_to_talk)
|
||||||
interactor_announce(itr);
|
interactor_announce(itr);
|
||||||
|
|
||||||
/*
|
|
||||||
* We're about to hand this seat back to the parent Interactor to
|
|
||||||
* do its own thing with. It will typically expect to start in the
|
|
||||||
* same state as if the seat had never been borrowed, i.e. in the
|
|
||||||
* starting trust state.
|
|
||||||
*/
|
|
||||||
seat_set_trust_status(realseat, true);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
InteractionReadySeat interactor_announce(Interactor *itr)
|
InteractionReadySeat interactor_announce(Interactor *itr)
|
||||||
|
@ -347,7 +347,6 @@ char *make_dir_path(const char *path, mode_t mode);
|
|||||||
/*
|
/*
|
||||||
* Exports from unicode.c.
|
* Exports from unicode.c.
|
||||||
*/
|
*/
|
||||||
struct unicode_data;
|
|
||||||
bool init_ucs(struct unicode_data *ucsdata, char *line_codepage,
|
bool init_ucs(struct unicode_data *ucsdata, char *line_codepage,
|
||||||
bool utf8_override, int font_charset, int vtmode);
|
bool utf8_override, int font_charset, int vtmode);
|
||||||
|
|
||||||
|
@ -31,6 +31,8 @@ int mb_to_wc(int codepage, int flags, const char *mbstr, int mblen,
|
|||||||
memset(&state, 0, sizeof state);
|
memset(&state, 0, sizeof state);
|
||||||
|
|
||||||
while (mblen > 0) {
|
while (mblen > 0) {
|
||||||
|
if (n >= wclen)
|
||||||
|
return n;
|
||||||
size_t i = mbrtowc(wcstr+n, mbstr, (size_t)mblen, &state);
|
size_t i = mbrtowc(wcstr+n, mbstr, (size_t)mblen, &state);
|
||||||
if (i == (size_t)-1 || i == (size_t)-2)
|
if (i == (size_t)-1 || i == (size_t)-2)
|
||||||
break;
|
break;
|
||||||
@ -44,6 +46,8 @@ int mb_to_wc(int codepage, int flags, const char *mbstr, int mblen,
|
|||||||
int n = 0;
|
int n = 0;
|
||||||
|
|
||||||
while (mblen > 0) {
|
while (mblen > 0) {
|
||||||
|
if (n >= wclen)
|
||||||
|
return n;
|
||||||
wcstr[n] = 0xD800 | (mbstr[0] & 0xFF);
|
wcstr[n] = 0xD800 | (mbstr[0] & 0xFF);
|
||||||
n++;
|
n++;
|
||||||
mbstr++;
|
mbstr++;
|
||||||
|
@ -12,11 +12,14 @@ add_sources_from_current_dir(utils
|
|||||||
conf_launchable.c
|
conf_launchable.c
|
||||||
ctrlparse.c
|
ctrlparse.c
|
||||||
debug.c
|
debug.c
|
||||||
|
decode_utf8.c
|
||||||
|
decode_utf8_to_wchar.c
|
||||||
default_description.c
|
default_description.c
|
||||||
dupcat.c
|
dupcat.c
|
||||||
dupprintf.c
|
dupprintf.c
|
||||||
dupstr.c
|
dupstr.c
|
||||||
dup_mb_to_wc.c
|
dup_mb_to_wc.c
|
||||||
|
dup_wc_to_mb.c
|
||||||
encode_utf8.c
|
encode_utf8.c
|
||||||
encode_wide_string_as_utf8.c
|
encode_wide_string_as_utf8.c
|
||||||
fgetline.c
|
fgetline.c
|
||||||
|
178
utils/decode_utf8.c
Normal file
178
utils/decode_utf8.c
Normal file
@ -0,0 +1,178 @@
|
|||||||
|
/*
|
||||||
|
* Decode a single UTF-8 character.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "putty.h"
|
||||||
|
#include "misc.h"
|
||||||
|
|
||||||
|
unsigned long decode_utf8(const char **utf8)
|
||||||
|
{
|
||||||
|
unsigned char c = (unsigned char)*(*utf8)++;
|
||||||
|
|
||||||
|
/* One-byte cases. */
|
||||||
|
if (c < 0x80) {
|
||||||
|
return c;
|
||||||
|
} else if (c < 0xC0) {
|
||||||
|
return 0xFFFD; /* spurious continuation byte */
|
||||||
|
}
|
||||||
|
|
||||||
|
unsigned long wc, min;
|
||||||
|
size_t ncont;
|
||||||
|
if (c < 0xE0) {
|
||||||
|
wc = c & 0x1F; ncont = 1; min = 0x80;
|
||||||
|
} else if (c < 0xF0) {
|
||||||
|
wc = c & 0x0F; ncont = 2; min = 0x800;
|
||||||
|
} else if (c < 0xF8) {
|
||||||
|
wc = c & 0x07; ncont = 3; min = 0x10000;
|
||||||
|
} else if (c < 0xFC) {
|
||||||
|
wc = c & 0x03; ncont = 4; min = 0x200000;
|
||||||
|
} else if (c < 0xFE) {
|
||||||
|
wc = c & 0x01; ncont = 5; min = 0x4000000;
|
||||||
|
} else {
|
||||||
|
return 0xFFFD; /* FE or FF illegal bytes */
|
||||||
|
}
|
||||||
|
|
||||||
|
while (ncont-- > 0) {
|
||||||
|
unsigned char cont = (unsigned char)**utf8;
|
||||||
|
if (!(0x80 <= cont && cont < 0xC0))
|
||||||
|
return 0xFFFD; /* short sequence */
|
||||||
|
(*utf8)++;
|
||||||
|
|
||||||
|
wc = (wc << 6) | (cont & 0x3F);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (wc < min)
|
||||||
|
return 0xFFFD; /* overlong encoding */
|
||||||
|
if (0xD800 <= wc && wc < 0xE000)
|
||||||
|
return 0xFFFD; /* UTF-8 encoding of surrogate */
|
||||||
|
if (wc > 0x10FFFF)
|
||||||
|
return 0xFFFD; /* outside Unicode range */
|
||||||
|
return wc;
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifdef TEST
|
||||||
|
|
||||||
|
#include <stdio.h>
|
||||||
|
|
||||||
|
bool dotest(const char *file, int line, const char *input,
|
||||||
|
const unsigned long *chars, size_t nchars)
|
||||||
|
{
|
||||||
|
const char *start = input;
|
||||||
|
const char *end = input + strlen(input) + 1;
|
||||||
|
size_t noutput = 0;
|
||||||
|
|
||||||
|
printf("%s:%d: test start\n", file, line);
|
||||||
|
|
||||||
|
while (input < end) {
|
||||||
|
const char *before = input;
|
||||||
|
unsigned long wc = decode_utf8(&input);
|
||||||
|
|
||||||
|
printf("%s:%d in+%"SIZEu" out+%"SIZEu":",
|
||||||
|
file, line, (size_t)(before-start), noutput);
|
||||||
|
while (before < input)
|
||||||
|
printf(" %02x", (unsigned)(unsigned char)(*before++));
|
||||||
|
printf(" -> U-%08lx\n", wc);
|
||||||
|
|
||||||
|
if (noutput >= nchars) {
|
||||||
|
printf("%s:%d: FAIL: expected no further output\n", file, line);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (chars[noutput] != wc) {
|
||||||
|
printf("%s:%d: FAIL: expected U-%08lx\n",
|
||||||
|
file, line, chars[noutput]);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
noutput++;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (noutput < nchars) {
|
||||||
|
printf("%s:%d: FAIL: expected further output\n", file, line);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
printf("%s:%d: pass\n", file, line);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
#define DOTEST(input, ...) do { \
|
||||||
|
static const unsigned long chars[] = { __VA_ARGS__, 0 }; \
|
||||||
|
ntest++; \
|
||||||
|
if (dotest(__FILE__, __LINE__, input, chars, lenof(chars))) \
|
||||||
|
npass++; \
|
||||||
|
} while (0)
|
||||||
|
|
||||||
|
int main(void)
|
||||||
|
{
|
||||||
|
int ntest = 0, npass = 0;
|
||||||
|
|
||||||
|
DOTEST("\xCE\xBA\xE1\xBD\xB9\xCF\x83\xCE\xBC\xCE\xB5",
|
||||||
|
0x03BA, 0x1F79, 0x03C3, 0x03BC, 0x03B5);
|
||||||
|
|
||||||
|
/* First sequence of each length (not counting NUL, which is
|
||||||
|
* tested anyway by the string-termination handling in every test) */
|
||||||
|
DOTEST("\xC2\x80", 0x0080);
|
||||||
|
DOTEST("\xE0\xA0\x80", 0x0800);
|
||||||
|
DOTEST("\xF0\x90\x80\x80", 0x00010000);
|
||||||
|
DOTEST("\xF8\x88\x80\x80\x80", 0xFFFD); /* would be 0x00200000 */
|
||||||
|
DOTEST("\xFC\x84\x80\x80\x80\x80", 0xFFFD); /* would be 0x04000000 */
|
||||||
|
|
||||||
|
/* Last sequence of each length */
|
||||||
|
DOTEST("\x7F", 0x007F);
|
||||||
|
DOTEST("\xDF\xBF", 0x07FF);
|
||||||
|
DOTEST("\xEF\xBF\xBF", 0xFFFF);
|
||||||
|
DOTEST("\xF7\xBF\xBF\xBF", 0xFFFD); /* would be 0x001FFFFF */
|
||||||
|
DOTEST("\xFB\xBF\xBF\xBF\xBF", 0xFFFD); /* would be 0x03FFFFFF */
|
||||||
|
DOTEST("\xFD\xBF\xBF\xBF\xBF\xBF", 0xFFFD); /* would be 0x7FFFFFFF */
|
||||||
|
|
||||||
|
/* Endpoints of the surrogate range */
|
||||||
|
DOTEST("\xED\x9F\xBF", 0xD7FF);
|
||||||
|
DOTEST("\xED\xA0\x00", 0xFFFD); /* would be 0xD800 */
|
||||||
|
DOTEST("\xED\xBF\xBF", 0xFFFD); /* would be 0xDFFF */
|
||||||
|
DOTEST("\xEE\x80\x80", 0xE000);
|
||||||
|
|
||||||
|
/* REPLACEMENT CHARACTER itself */
|
||||||
|
DOTEST("\xEF\xBF\xBD", 0xFFFD);
|
||||||
|
|
||||||
|
/* Endpoints of the legal Unicode range */
|
||||||
|
DOTEST("\xF4\x8F\xBF\xBF", 0x0010FFFF);
|
||||||
|
DOTEST("\xF4\x90\x80\x80", 0xFFFD); /* would be 0x00110000 */
|
||||||
|
|
||||||
|
/* Spurious continuation bytes, each shown as a separate failure */
|
||||||
|
DOTEST("\x80 \x81\x82 \xBD\xBE\xBF",
|
||||||
|
0xFFFD, 0x0020, 0xFFFD, 0xFFFD, 0x0020, 0xFFFD, 0xFFFD, 0xFFFD);
|
||||||
|
|
||||||
|
/* Truncated sequences, each shown as just one failure */
|
||||||
|
DOTEST("\xC2\xE0\xA0\xF0\x90\x80\xF8\x88\x80\x80\xFC\x84\x80\x80\x80",
|
||||||
|
0xFFFD, 0xFFFD, 0xFFFD, 0xFFFD, 0xFFFD);
|
||||||
|
DOTEST("\xC2 \xE0\xA0 \xF0\x90\x80 \xF8\x88\x80\x80 \xFC\x84\x80\x80\x80",
|
||||||
|
0xFFFD, 0x0020, 0xFFFD, 0x0020, 0xFFFD, 0x0020, 0xFFFD, 0x0020,
|
||||||
|
0xFFFD);
|
||||||
|
|
||||||
|
/* Illegal bytes */
|
||||||
|
DOTEST("\xFE\xFF", 0xFFFD, 0xFFFD);
|
||||||
|
|
||||||
|
/* Overlong sequences */
|
||||||
|
DOTEST("\xC1\xBF", 0xFFFD);
|
||||||
|
DOTEST("\xE0\x9F\xBF", 0xFFFD);
|
||||||
|
DOTEST("\xF0\x8F\xBF\xBF", 0xFFFD);
|
||||||
|
DOTEST("\xF8\x87\xBF\xBF\xBF", 0xFFFD);
|
||||||
|
DOTEST("\xFC\x83\xBF\xBF\xBF\xBF", 0xFFFD);
|
||||||
|
|
||||||
|
DOTEST("\xC0\x80", 0xFFFD);
|
||||||
|
DOTEST("\xE0\x80\x80", 0xFFFD);
|
||||||
|
DOTEST("\xF0\x80\x80\x80", 0xFFFD);
|
||||||
|
DOTEST("\xF8\x80\x80\x80\x80", 0xFFFD);
|
||||||
|
DOTEST("\xFC\x80\x80\x80\x80\x80", 0xFFFD);
|
||||||
|
|
||||||
|
printf("%d tests %d passed", ntest, npass);
|
||||||
|
if (npass < ntest) {
|
||||||
|
printf(" %d FAILED\n", ntest-npass);
|
||||||
|
return 1;
|
||||||
|
} else {
|
||||||
|
printf("\n");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif
|
20
utils/decode_utf8_to_wchar.c
Normal file
20
utils/decode_utf8_to_wchar.c
Normal file
@ -0,0 +1,20 @@
|
|||||||
|
/*
|
||||||
|
* Decode a single UTF-8 character to the platform's local wchar_t.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "putty.h"
|
||||||
|
#include "misc.h"
|
||||||
|
|
||||||
|
size_t decode_utf8_to_wchar(const char **utf8, wchar_t *out)
|
||||||
|
{
|
||||||
|
size_t outlen = 0;
|
||||||
|
unsigned wc = decode_utf8(utf8);
|
||||||
|
if (sizeof(wchar_t) > 2 || wc < 0x10000) {
|
||||||
|
out[outlen++] = wc;
|
||||||
|
} else {
|
||||||
|
unsigned wcoff = wc - 0x10000;
|
||||||
|
out[outlen++] = 0xD800 | (0x3FF & (wcoff >> 10));
|
||||||
|
out[outlen++] = 0xDC00 | (0x3FF & wcoff);
|
||||||
|
}
|
||||||
|
return outlen;
|
||||||
|
}
|
39
utils/dup_wc_to_mb.c
Normal file
39
utils/dup_wc_to_mb.c
Normal file
@ -0,0 +1,39 @@
|
|||||||
|
/*
|
||||||
|
* dup_wc_to_mb: memory-allocating wrapper on wc_to_mb.
|
||||||
|
*
|
||||||
|
* Also dup_wc_to_mb_c: same but you already know the length of the
|
||||||
|
* string.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <wchar.h>
|
||||||
|
|
||||||
|
#include "putty.h"
|
||||||
|
#include "misc.h"
|
||||||
|
|
||||||
|
char *dup_wc_to_mb_c(int codepage, int flags, const wchar_t *string, int len,
|
||||||
|
const char *defchr, struct unicode_data *ucsdata)
|
||||||
|
{
|
||||||
|
size_t outsize = len+1;
|
||||||
|
char *out = snewn(outsize, char);
|
||||||
|
|
||||||
|
while (true) {
|
||||||
|
size_t outlen = wc_to_mb(codepage, flags, string, len, out, outsize,
|
||||||
|
defchr, ucsdata);
|
||||||
|
/* We can only be sure we've consumed the whole input if the
|
||||||
|
* output is not within a multibyte-character-length of the
|
||||||
|
* end of the buffer! */
|
||||||
|
if (outlen < outsize && outsize - outlen > MB_LEN_MAX) {
|
||||||
|
out[outlen] = '\0';
|
||||||
|
return out;
|
||||||
|
}
|
||||||
|
|
||||||
|
sgrowarray(out, outsize, outsize);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
char *dup_wc_to_mb(int codepage, int flags, const wchar_t *string,
|
||||||
|
const char *defchr, struct unicode_data *ucsdata)
|
||||||
|
{
|
||||||
|
return dup_wc_to_mb_c(codepage, flags, string, wcslen(string),
|
||||||
|
defchr, ucsdata);
|
||||||
|
}
|
@ -91,8 +91,6 @@ void modalfatalbox(const char *fmt, ...)
|
|||||||
exit(1);
|
exit(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool has_security;
|
|
||||||
|
|
||||||
struct PassphraseProcStruct {
|
struct PassphraseProcStruct {
|
||||||
bool modal;
|
bool modal;
|
||||||
const char *help_topic;
|
const char *help_topic;
|
||||||
@ -999,7 +997,7 @@ static char *answer_filemapping_message(const char *mapname)
|
|||||||
debug("maphandle = %p\n", maphandle);
|
debug("maphandle = %p\n", maphandle);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
if (has_security) {
|
if (should_have_security()) {
|
||||||
DWORD retd;
|
DWORD retd;
|
||||||
|
|
||||||
if ((expectedsid = get_user_sid()) == NULL) {
|
if ((expectedsid = get_user_sid()) == NULL) {
|
||||||
@ -1387,6 +1385,23 @@ static NORETURN void opt_error(const char *fmt, ...)
|
|||||||
exit(1);
|
exit(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#ifdef LEGACY_WINDOWS
|
||||||
|
BOOL sw_PeekMessage(LPMSG msg, HWND hwnd, UINT min, UINT max, UINT remove)
|
||||||
|
{
|
||||||
|
static bool unicode_unavailable = false;
|
||||||
|
if (!unicode_unavailable) {
|
||||||
|
BOOL ret = PeekMessageW(msg, hwnd, min, max, remove);
|
||||||
|
if (!ret && GetLastError() == ERROR_CALL_NOT_IMPLEMENTED)
|
||||||
|
unicode_unavailable = true; /* don't try again */
|
||||||
|
else
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
return PeekMessageA(msg, hwnd, min, max, remove);
|
||||||
|
}
|
||||||
|
#else
|
||||||
|
#define sw_PeekMessage PeekMessageW
|
||||||
|
#endif
|
||||||
|
|
||||||
int WINAPI WinMain(HINSTANCE inst, HINSTANCE prev, LPSTR cmdline, int show)
|
int WINAPI WinMain(HINSTANCE inst, HINSTANCE prev, LPSTR cmdline, int show)
|
||||||
{
|
{
|
||||||
MSG msg;
|
MSG msg;
|
||||||
@ -1409,14 +1424,7 @@ int WINAPI WinMain(HINSTANCE inst, HINSTANCE prev, LPSTR cmdline, int show)
|
|||||||
|
|
||||||
hinst = inst;
|
hinst = inst;
|
||||||
|
|
||||||
/*
|
if (should_have_security()) {
|
||||||
* Determine whether we're an NT system (should have security
|
|
||||||
* APIs) or a non-NT system (don't do security).
|
|
||||||
*/
|
|
||||||
init_winver();
|
|
||||||
has_security = (osPlatformId == VER_PLATFORM_WIN32_NT);
|
|
||||||
|
|
||||||
if (has_security) {
|
|
||||||
/*
|
/*
|
||||||
* Attempt to get the security API we need.
|
* Attempt to get the security API we need.
|
||||||
*/
|
*/
|
||||||
@ -1576,7 +1584,7 @@ int WINAPI WinMain(HINSTANCE inst, HINSTANCE prev, LPSTR cmdline, int show)
|
|||||||
*/
|
*/
|
||||||
wpc->plc.vt = &winpgnt_vtable;
|
wpc->plc.vt = &winpgnt_vtable;
|
||||||
wpc->plc.suppress_logging = true;
|
wpc->plc.suppress_logging = true;
|
||||||
{
|
if (should_have_security()) {
|
||||||
Plug *pl_plug;
|
Plug *pl_plug;
|
||||||
struct pageant_listen_state *pl =
|
struct pageant_listen_state *pl =
|
||||||
pageant_listener_new(&pl_plug, &wpc->plc);
|
pageant_listener_new(&pl_plug, &wpc->plc);
|
||||||
@ -1771,7 +1779,7 @@ int WINAPI WinMain(HINSTANCE inst, HINSTANCE prev, LPSTR cmdline, int show)
|
|||||||
handle_wait_activate(hwl, n - WAIT_OBJECT_0);
|
handle_wait_activate(hwl, n - WAIT_OBJECT_0);
|
||||||
handle_wait_list_free(hwl);
|
handle_wait_list_free(hwl);
|
||||||
|
|
||||||
while (PeekMessageW(&msg, NULL, 0, 0, PM_REMOVE)) {
|
while (sw_PeekMessage(&msg, NULL, 0, 0, PM_REMOVE)) {
|
||||||
if (msg.message == WM_QUIT)
|
if (msg.message == WM_QUIT)
|
||||||
goto finished; /* two-level break */
|
goto finished; /* two-level break */
|
||||||
|
|
||||||
|
@ -576,6 +576,7 @@ void dll_hijacking_protection(void);
|
|||||||
const char *get_system_dir(void);
|
const char *get_system_dir(void);
|
||||||
HMODULE load_system32_dll(const char *libname);
|
HMODULE load_system32_dll(const char *libname);
|
||||||
const char *win_strerror(int error);
|
const char *win_strerror(int error);
|
||||||
|
bool should_have_security(void);
|
||||||
void restrict_process_acl(void);
|
void restrict_process_acl(void);
|
||||||
bool restricted_acl(void);
|
bool restricted_acl(void);
|
||||||
void escape_registry_key(const char *in, strbuf *out);
|
void escape_registry_key(const char *in, strbuf *out);
|
||||||
@ -608,7 +609,6 @@ void EnableSizeTip(bool bEnable);
|
|||||||
/*
|
/*
|
||||||
* Exports from unicode.c.
|
* Exports from unicode.c.
|
||||||
*/
|
*/
|
||||||
struct unicode_data;
|
|
||||||
void init_ucs(Conf *, struct unicode_data *);
|
void init_ucs(Conf *, struct unicode_data *);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -1195,16 +1195,93 @@ int wc_to_mb(int codepage, int flags, const wchar_t *wcstr, int wclen,
|
|||||||
}
|
}
|
||||||
return p - mbstr;
|
return p - mbstr;
|
||||||
} else {
|
} else {
|
||||||
int defused;
|
int defused, ret;
|
||||||
return WideCharToMultiByte(codepage, flags, wcstr, wclen,
|
ret = WideCharToMultiByte(codepage, flags, wcstr, wclen,
|
||||||
mbstr, mblen, defchr, &defused);
|
mbstr, mblen, defchr, &defused);
|
||||||
|
if (ret)
|
||||||
|
return ret;
|
||||||
|
|
||||||
|
#ifdef LEGACY_WINDOWS
|
||||||
|
/*
|
||||||
|
* Fallback for legacy platforms too old to support UTF-8: if
|
||||||
|
* the codepage is UTF-8, we can do the translation ourselves.
|
||||||
|
*/
|
||||||
|
if (codepage == CP_UTF8 && mblen > 0 && wclen > 0) {
|
||||||
|
size_t remaining = mblen;
|
||||||
|
char *p = mbstr;
|
||||||
|
|
||||||
|
while (wclen > 0) {
|
||||||
|
unsigned long wc = (wclen--, *wcstr++);
|
||||||
|
if (wclen > 0 && IS_SURROGATE_PAIR(wc, *wcstr)) {
|
||||||
|
wc = FROM_SURROGATES(wc, *wcstr);
|
||||||
|
wclen--, wcstr++;
|
||||||
|
}
|
||||||
|
|
||||||
|
char utfbuf[6];
|
||||||
|
size_t utflen = encode_utf8(utfbuf, wc);
|
||||||
|
if (utflen <= remaining) {
|
||||||
|
memcpy(p, utfbuf, utflen);
|
||||||
|
p += utflen;
|
||||||
|
remaining -= utflen;
|
||||||
|
} else {
|
||||||
|
return p - mbstr;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return p - mbstr;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* No other fallbacks are available */
|
||||||
|
return 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
int mb_to_wc(int codepage, int flags, const char *mbstr, int mblen,
|
int mb_to_wc(int codepage, int flags, const char *mbstr, int mblen,
|
||||||
wchar_t *wcstr, int wclen)
|
wchar_t *wcstr, int wclen)
|
||||||
{
|
{
|
||||||
return MultiByteToWideChar(codepage, flags, mbstr, mblen, wcstr, wclen);
|
int ret = MultiByteToWideChar(codepage, flags, mbstr, mblen, wcstr, wclen);
|
||||||
|
if (ret)
|
||||||
|
return ret;
|
||||||
|
|
||||||
|
#ifdef LEGACY_WINDOWS
|
||||||
|
/*
|
||||||
|
* Fallback for legacy platforms too old to support UTF-8: if the
|
||||||
|
* codepage is UTF-8, we can do the translation ourselves.
|
||||||
|
*/
|
||||||
|
if (codepage == CP_UTF8 && mblen > 0 && wclen > 0) {
|
||||||
|
size_t remaining = wclen;
|
||||||
|
wchar_t *p = wcstr;
|
||||||
|
|
||||||
|
while (mblen > 0) {
|
||||||
|
char utfbuf[7];
|
||||||
|
int thissize = mblen < 6 ? mblen : 6;
|
||||||
|
memcpy(utfbuf, mbstr, thissize);
|
||||||
|
utfbuf[thissize] = '\0';
|
||||||
|
|
||||||
|
const char *utfptr = utfbuf;
|
||||||
|
wchar_t wcbuf[2];
|
||||||
|
size_t nwc = decode_utf8_to_wchar(&utfptr, wcbuf);
|
||||||
|
|
||||||
|
for (size_t i = 0; i < nwc; i++) {
|
||||||
|
if (remaining > 0) {
|
||||||
|
remaining--;
|
||||||
|
*p++ = wcbuf[i];
|
||||||
|
} else {
|
||||||
|
return p - wcstr;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
mbstr += (utfptr - utfbuf);
|
||||||
|
mblen -= (utfptr - utfbuf);
|
||||||
|
}
|
||||||
|
|
||||||
|
return p - wcstr;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* No other fallbacks are available */
|
||||||
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool is_dbcs_leadbyte(int codepage, char byte)
|
bool is_dbcs_leadbyte(int codepage, char byte)
|
||||||
|
@ -13,8 +13,8 @@ HANDLE lock_interprocess_mutex(const char *mutexname, char **error)
|
|||||||
PACL acl = NULL;
|
PACL acl = NULL;
|
||||||
HANDLE mutex = NULL;
|
HANDLE mutex = NULL;
|
||||||
|
|
||||||
if (!make_private_security_descriptor(MUTEX_ALL_ACCESS,
|
if (should_have_security() && !make_private_security_descriptor(
|
||||||
&psd, &acl, error))
|
MUTEX_ALL_ACCESS, &psd, &acl, error))
|
||||||
goto out;
|
goto out;
|
||||||
|
|
||||||
SECURITY_ATTRIBUTES sa;
|
SECURITY_ATTRIBUTES sa;
|
||||||
|
@ -4,20 +4,19 @@
|
|||||||
|
|
||||||
#include "putty.h"
|
#include "putty.h"
|
||||||
|
|
||||||
bool open_for_write_would_lose_data(const Filename *fn)
|
/*
|
||||||
|
* This is slightly fiddly because we want to be backwards-compatible
|
||||||
|
* with systems too old to have GetFileAttributesEx. The next best
|
||||||
|
* thing is FindFirstFile, which will return a different data
|
||||||
|
* structure, but one that also contains the fields we want. (But it
|
||||||
|
* will behave more unhelpfully - for this application - in the
|
||||||
|
* presence of wildcards, so we'd prefer to use GFAE if we can.)
|
||||||
|
*/
|
||||||
|
|
||||||
|
static inline bool open_for_write_would_lose_data_impl(
|
||||||
|
DWORD dwFileAttributes, DWORD nFileSizeHigh, DWORD nFileSizeLow)
|
||||||
{
|
{
|
||||||
WIN32_FILE_ATTRIBUTE_DATA attrs;
|
if (dwFileAttributes & (FILE_ATTRIBUTE_DEVICE|FILE_ATTRIBUTE_DIRECTORY)) {
|
||||||
if (!GetFileAttributesEx(fn->path, GetFileExInfoStandard, &attrs)) {
|
|
||||||
/*
|
|
||||||
* Generally, if we don't identify a specific reason why we
|
|
||||||
* should return true from this function, we return false, and
|
|
||||||
* let the subsequent attempt to open the file for real give a
|
|
||||||
* more useful error message.
|
|
||||||
*/
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
if (attrs.dwFileAttributes & (FILE_ATTRIBUTE_DEVICE |
|
|
||||||
FILE_ATTRIBUTE_DIRECTORY)) {
|
|
||||||
/*
|
/*
|
||||||
* File is something other than an ordinary disk file, so
|
* File is something other than an ordinary disk file, so
|
||||||
* opening it for writing will not cause truncation. (It may
|
* opening it for writing will not cause truncation. (It may
|
||||||
@ -25,7 +24,7 @@ bool open_for_write_would_lose_data(const Filename *fn)
|
|||||||
*/
|
*/
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
if (attrs.nFileSizeHigh == 0 && attrs.nFileSizeLow == 0) {
|
if (nFileSizeHigh == 0 && nFileSizeLow == 0) {
|
||||||
/*
|
/*
|
||||||
* File is zero-length (or may be a named pipe, which
|
* File is zero-length (or may be a named pipe, which
|
||||||
* dwFileAttributes can't tell apart from a regular file), so
|
* dwFileAttributes can't tell apart from a regular file), so
|
||||||
@ -36,3 +35,42 @@ bool open_for_write_would_lose_data(const Filename *fn)
|
|||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool open_for_write_would_lose_data(const Filename *fn)
|
||||||
|
{
|
||||||
|
static HMODULE kernel32_module;
|
||||||
|
DECL_WINDOWS_FUNCTION(static, BOOL, GetFileAttributesExA,
|
||||||
|
(LPCSTR, GET_FILEEX_INFO_LEVELS, LPVOID));
|
||||||
|
|
||||||
|
if (!kernel32_module) {
|
||||||
|
kernel32_module = load_system32_dll("kernel32.dll");
|
||||||
|
GET_WINDOWS_FUNCTION(kernel32_module, GetFileAttributesExA);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (p_GetFileAttributesExA) {
|
||||||
|
WIN32_FILE_ATTRIBUTE_DATA attrs;
|
||||||
|
if (!p_GetFileAttributesExA(fn->path, GetFileExInfoStandard, &attrs)) {
|
||||||
|
/*
|
||||||
|
* Generally, if we don't identify a specific reason why we
|
||||||
|
* should return true from this function, we return false, and
|
||||||
|
* let the subsequent attempt to open the file for real give a
|
||||||
|
* more useful error message.
|
||||||
|
*/
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return open_for_write_would_lose_data_impl(
|
||||||
|
attrs.dwFileAttributes, attrs.nFileSizeHigh, attrs.nFileSizeLow);
|
||||||
|
} else {
|
||||||
|
WIN32_FIND_DATA fd;
|
||||||
|
HANDLE h = FindFirstFile(fn->path, &fd);
|
||||||
|
if (h == INVALID_HANDLE_VALUE) {
|
||||||
|
/*
|
||||||
|
* As above, if we can't find the file at all, return false.
|
||||||
|
*/
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
CloseHandle(h);
|
||||||
|
return open_for_write_would_lose_data_impl(
|
||||||
|
fd.dwFileAttributes, fd.nFileSizeHigh, fd.nFileSizeLow);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@ -20,6 +20,20 @@ DEF_WINDOWS_FUNCTION(GetSecurityInfo);
|
|||||||
DEF_WINDOWS_FUNCTION(SetSecurityInfo);
|
DEF_WINDOWS_FUNCTION(SetSecurityInfo);
|
||||||
DEF_WINDOWS_FUNCTION(SetEntriesInAclA);
|
DEF_WINDOWS_FUNCTION(SetEntriesInAclA);
|
||||||
|
|
||||||
|
bool should_have_security(void)
|
||||||
|
{
|
||||||
|
#ifdef LEGACY_WINDOWS
|
||||||
|
/* Legacy pre-NT platforms are not expected to have any of these APIs */
|
||||||
|
init_winver();
|
||||||
|
return (osPlatformId == VER_PLATFORM_WIN32_NT);
|
||||||
|
#else
|
||||||
|
/* In the up-to-date PuTTY builds which do not support those
|
||||||
|
* platforms, unconditionally return true, to minimise the risk of
|
||||||
|
* compiling out security checks. */
|
||||||
|
return true;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
bool got_advapi(void)
|
bool got_advapi(void)
|
||||||
{
|
{
|
||||||
static bool attempted = false;
|
static bool attempted = false;
|
||||||
|
@ -4,6 +4,11 @@ DWORD osMajorVersion, osMinorVersion, osPlatformId;
|
|||||||
|
|
||||||
void init_winver(void)
|
void init_winver(void)
|
||||||
{
|
{
|
||||||
|
static bool initialised = false;
|
||||||
|
if (initialised)
|
||||||
|
return;
|
||||||
|
initialised = true;
|
||||||
|
|
||||||
OSVERSIONINFO osVersion;
|
OSVERSIONINFO osVersion;
|
||||||
static HMODULE kernel32_module;
|
static HMODULE kernel32_module;
|
||||||
DECL_WINDOWS_FUNCTION(static, BOOL, GetVersionExA, (LPOSVERSIONINFO));
|
DECL_WINDOWS_FUNCTION(static, BOOL, GetVersionExA, (LPOSVERSIONINFO));
|
||||||
|
197
windows/window.c
197
windows/window.c
@ -191,6 +191,9 @@ bool tried_pal = false;
|
|||||||
COLORREF colorref_modifier = 0;
|
COLORREF colorref_modifier = 0;
|
||||||
|
|
||||||
enum MONITOR_DPI_TYPE { MDT_EFFECTIVE_DPI, MDT_ANGULAR_DPI, MDT_RAW_DPI, MDT_DEFAULT };
|
enum MONITOR_DPI_TYPE { MDT_EFFECTIVE_DPI, MDT_ANGULAR_DPI, MDT_RAW_DPI, MDT_DEFAULT };
|
||||||
|
DECL_WINDOWS_FUNCTION(static, BOOL, GetMonitorInfoA, (HMONITOR, LPMONITORINFO));
|
||||||
|
DECL_WINDOWS_FUNCTION(static, HMONITOR, MonitorFromPoint, (POINT, DWORD));
|
||||||
|
DECL_WINDOWS_FUNCTION(static, HMONITOR, MonitorFromWindow, (HWND, DWORD));
|
||||||
DECL_WINDOWS_FUNCTION(static, HRESULT, GetDpiForMonitor, (HMONITOR hmonitor, enum MONITOR_DPI_TYPE dpiType, UINT *dpiX, UINT *dpiY));
|
DECL_WINDOWS_FUNCTION(static, HRESULT, GetDpiForMonitor, (HMONITOR hmonitor, enum MONITOR_DPI_TYPE dpiType, UINT *dpiX, UINT *dpiY));
|
||||||
DECL_WINDOWS_FUNCTION(static, HRESULT, GetSystemMetricsForDpi, (int nIndex, UINT dpi));
|
DECL_WINDOWS_FUNCTION(static, HRESULT, GetSystemMetricsForDpi, (int nIndex, UINT dpi));
|
||||||
DECL_WINDOWS_FUNCTION(static, HRESULT, AdjustWindowRectExForDpi, (LPRECT lpRect, DWORD dwStyle, BOOL bMenu, DWORD dwExStyle, UINT dpi));
|
DECL_WINDOWS_FUNCTION(static, HRESULT, AdjustWindowRectExForDpi, (LPRECT lpRect, DWORD dwStyle, BOOL bMenu, DWORD dwExStyle, UINT dpi));
|
||||||
@ -441,6 +444,72 @@ static void close_session(void *ignored_context)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Some machinery to deal with switching the window type between ANSI
|
||||||
|
* and Unicode. We prefer Unicode, but some PuTTY builds still try to
|
||||||
|
* run on machines so old that they don't support that mode. So we're
|
||||||
|
* prepared to fall back to an ANSI window if we have to. For this
|
||||||
|
* purpose, we swap out a few Windows API functions, and wrap
|
||||||
|
* SetWindowText so that if we're not in Unicode mode we first convert
|
||||||
|
* the wide string we're given.
|
||||||
|
*/
|
||||||
|
static bool unicode_window;
|
||||||
|
static BOOL (WINAPI *sw_PeekMessage)(LPMSG, HWND, UINT, UINT, UINT);
|
||||||
|
static LRESULT (WINAPI *sw_DispatchMessage)(const MSG *);
|
||||||
|
static LRESULT (WINAPI *sw_DefWindowProc)(HWND, UINT, WPARAM, LPARAM);
|
||||||
|
static void sw_SetWindowText(HWND hwnd, wchar_t *text)
|
||||||
|
{
|
||||||
|
if (unicode_window) {
|
||||||
|
SetWindowTextW(hwnd, text);
|
||||||
|
} else {
|
||||||
|
char *mb = dup_wc_to_mb(DEFAULT_CODEPAGE, 0, text, "?", &ucsdata);
|
||||||
|
SetWindowTextA(hwnd, mb);
|
||||||
|
sfree(mb);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static HINSTANCE hprev;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Also, registering window classes has to be done in a fiddly way.
|
||||||
|
*/
|
||||||
|
#define SETUP_WNDCLASS(wndclass, classname) do { \
|
||||||
|
wndclass.style = 0; \
|
||||||
|
wndclass.lpfnWndProc = WndProc; \
|
||||||
|
wndclass.cbClsExtra = 0; \
|
||||||
|
wndclass.cbWndExtra = 0; \
|
||||||
|
wndclass.hInstance = hinst; \
|
||||||
|
wndclass.hIcon = LoadIcon(hinst, MAKEINTRESOURCE(IDI_MAINICON)); \
|
||||||
|
wndclass.hCursor = LoadCursor(NULL, IDC_IBEAM); \
|
||||||
|
wndclass.hbrBackground = NULL; \
|
||||||
|
wndclass.lpszMenuName = NULL; \
|
||||||
|
wndclass.lpszClassName = classname; \
|
||||||
|
} while (0)
|
||||||
|
wchar_t *terminal_window_class_w(void)
|
||||||
|
{
|
||||||
|
static wchar_t *classname = NULL;
|
||||||
|
if (!classname)
|
||||||
|
classname = dup_mb_to_wc(DEFAULT_CODEPAGE, 0, appname);
|
||||||
|
if (!hprev) {
|
||||||
|
WNDCLASSW wndclassw;
|
||||||
|
SETUP_WNDCLASS(wndclassw, classname);
|
||||||
|
RegisterClassW(&wndclassw);
|
||||||
|
}
|
||||||
|
return classname;
|
||||||
|
}
|
||||||
|
char *terminal_window_class_a(void)
|
||||||
|
{
|
||||||
|
static char *classname = NULL;
|
||||||
|
if (!classname)
|
||||||
|
classname = dupcat(appname, ".ansi");
|
||||||
|
if (!hprev) {
|
||||||
|
WNDCLASSA wndclassa;
|
||||||
|
SETUP_WNDCLASS(wndclassa, classname);
|
||||||
|
RegisterClassA(&wndclassa);
|
||||||
|
}
|
||||||
|
return classname;
|
||||||
|
}
|
||||||
|
|
||||||
const unsigned cmdline_tooltype =
|
const unsigned cmdline_tooltype =
|
||||||
TOOLTYPE_HOST_ARG |
|
TOOLTYPE_HOST_ARG |
|
||||||
TOOLTYPE_PORT_ARG |
|
TOOLTYPE_PORT_ARG |
|
||||||
@ -457,6 +526,7 @@ int WINAPI WinMain(HINSTANCE inst, HINSTANCE prev, LPSTR cmdline, int show)
|
|||||||
dll_hijacking_protection();
|
dll_hijacking_protection();
|
||||||
|
|
||||||
hinst = inst;
|
hinst = inst;
|
||||||
|
hprev = prev;
|
||||||
|
|
||||||
sk_init();
|
sk_init();
|
||||||
|
|
||||||
@ -505,23 +575,6 @@ int WINAPI WinMain(HINSTANCE inst, HINSTANCE prev, LPSTR cmdline, int show)
|
|||||||
*/
|
*/
|
||||||
gui_term_process_cmdline(conf, cmdline);
|
gui_term_process_cmdline(conf, cmdline);
|
||||||
|
|
||||||
if (!prev) {
|
|
||||||
WNDCLASSW wndclass;
|
|
||||||
|
|
||||||
wndclass.style = 0;
|
|
||||||
wndclass.lpfnWndProc = WndProc;
|
|
||||||
wndclass.cbClsExtra = 0;
|
|
||||||
wndclass.cbWndExtra = 0;
|
|
||||||
wndclass.hInstance = inst;
|
|
||||||
wndclass.hIcon = LoadIcon(inst, MAKEINTRESOURCE(IDI_MAINICON));
|
|
||||||
wndclass.hCursor = LoadCursor(NULL, IDC_IBEAM);
|
|
||||||
wndclass.hbrBackground = NULL;
|
|
||||||
wndclass.lpszMenuName = NULL;
|
|
||||||
wndclass.lpszClassName = dup_mb_to_wc(DEFAULT_CODEPAGE, 0, appname);
|
|
||||||
|
|
||||||
RegisterClassW(&wndclass);
|
|
||||||
}
|
|
||||||
|
|
||||||
memset(&ucsdata, 0, sizeof(ucsdata));
|
memset(&ucsdata, 0, sizeof(ucsdata));
|
||||||
|
|
||||||
conf_cache_data();
|
conf_cache_data();
|
||||||
@ -557,6 +610,8 @@ int WINAPI WinMain(HINSTANCE inst, HINSTANCE prev, LPSTR cmdline, int show)
|
|||||||
if (vt && vt->flags & BACKEND_RESIZE_FORBIDDEN)
|
if (vt && vt->flags & BACKEND_RESIZE_FORBIDDEN)
|
||||||
resize_forbidden = true;
|
resize_forbidden = true;
|
||||||
wchar_t *uappname = dup_mb_to_wc(DEFAULT_CODEPAGE, 0, appname);
|
wchar_t *uappname = dup_mb_to_wc(DEFAULT_CODEPAGE, 0, appname);
|
||||||
|
window_name = dup_mb_to_wc(DEFAULT_CODEPAGE, 0, appname);
|
||||||
|
icon_name = dup_mb_to_wc(DEFAULT_CODEPAGE, 0, appname);
|
||||||
if (!conf_get_bool(conf, CONF_scrollbar))
|
if (!conf_get_bool(conf, CONF_scrollbar))
|
||||||
winmode &= ~(WS_VSCROLL);
|
winmode &= ~(WS_VSCROLL);
|
||||||
if (conf_get_int(conf, CONF_resize_action) == RESIZE_DISABLED ||
|
if (conf_get_int(conf, CONF_resize_action) == RESIZE_DISABLED ||
|
||||||
@ -566,9 +621,42 @@ int WINAPI WinMain(HINSTANCE inst, HINSTANCE prev, LPSTR cmdline, int show)
|
|||||||
exwinmode |= WS_EX_TOPMOST;
|
exwinmode |= WS_EX_TOPMOST;
|
||||||
if (conf_get_bool(conf, CONF_sunken_edge))
|
if (conf_get_bool(conf, CONF_sunken_edge))
|
||||||
exwinmode |= WS_EX_CLIENTEDGE;
|
exwinmode |= WS_EX_CLIENTEDGE;
|
||||||
|
|
||||||
|
#ifdef TEST_ANSI_WINDOW
|
||||||
|
/* For developer testing of ANSI window support, pretend
|
||||||
|
* CreateWindowExW failed */
|
||||||
|
wgs.term_hwnd = NULL;
|
||||||
|
SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
|
||||||
|
#else
|
||||||
|
unicode_window = true;
|
||||||
|
sw_PeekMessage = PeekMessageW;
|
||||||
|
sw_DispatchMessage = DispatchMessageW;
|
||||||
|
sw_DefWindowProc = DefWindowProcW;
|
||||||
wgs.term_hwnd = CreateWindowExW(
|
wgs.term_hwnd = CreateWindowExW(
|
||||||
exwinmode, uappname, uappname, winmode, CW_USEDEFAULT,
|
exwinmode, terminal_window_class_w(), uappname,
|
||||||
CW_USEDEFAULT, guess_width, guess_height, NULL, NULL, inst, NULL);
|
winmode, CW_USEDEFAULT, CW_USEDEFAULT,
|
||||||
|
guess_width, guess_height, NULL, NULL, inst, NULL);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if defined LEGACY_WINDOWS || defined TEST_ANSI_WINDOW
|
||||||
|
if (!wgs.term_hwnd && GetLastError() == ERROR_CALL_NOT_IMPLEMENTED) {
|
||||||
|
/* Fall back to an ANSI window, swapping in all the ANSI
|
||||||
|
* window message handling functions */
|
||||||
|
unicode_window = false;
|
||||||
|
sw_PeekMessage = PeekMessageA;
|
||||||
|
sw_DispatchMessage = DispatchMessageA;
|
||||||
|
sw_DefWindowProc = DefWindowProcA;
|
||||||
|
wgs.term_hwnd = CreateWindowExA(
|
||||||
|
exwinmode, terminal_window_class_a(), appname,
|
||||||
|
winmode, CW_USEDEFAULT, CW_USEDEFAULT,
|
||||||
|
guess_width, guess_height, NULL, NULL, inst, NULL);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
if (!wgs.term_hwnd) {
|
||||||
|
modalfatalbox("Unable to create terminal window: %s",
|
||||||
|
win_strerror(GetLastError()));
|
||||||
|
}
|
||||||
memset(&dpi_info, 0, sizeof(struct _dpi_info));
|
memset(&dpi_info, 0, sizeof(struct _dpi_info));
|
||||||
init_dpi_info();
|
init_dpi_info();
|
||||||
sfree(uappname);
|
sfree(uappname);
|
||||||
@ -761,13 +849,13 @@ int WINAPI WinMain(HINSTANCE inst, HINSTANCE prev, LPSTR cmdline, int show)
|
|||||||
handle_wait_activate(hwl, n - WAIT_OBJECT_0);
|
handle_wait_activate(hwl, n - WAIT_OBJECT_0);
|
||||||
handle_wait_list_free(hwl);
|
handle_wait_list_free(hwl);
|
||||||
|
|
||||||
while (PeekMessageW(&msg, NULL, 0, 0, PM_REMOVE)) {
|
while (sw_PeekMessage(&msg, NULL, 0, 0, PM_REMOVE)) {
|
||||||
if (msg.message == WM_QUIT)
|
if (msg.message == WM_QUIT)
|
||||||
goto finished; /* two-level break */
|
goto finished; /* two-level break */
|
||||||
|
|
||||||
HWND logbox = event_log_window();
|
HWND logbox = event_log_window();
|
||||||
if (!(IsWindow(logbox) && IsDialogMessage(logbox, &msg)))
|
if (!(IsWindow(logbox) && IsDialogMessage(logbox, &msg)))
|
||||||
DispatchMessageW(&msg);
|
sw_DispatchMessage(&msg);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* WM_NETEVENT messages seem to jump ahead of others in
|
* WM_NETEVENT messages seem to jump ahead of others in
|
||||||
@ -1271,9 +1359,9 @@ static int get_font_width(HDC hdc, const TEXTMETRIC *tm)
|
|||||||
static void init_dpi_info(void)
|
static void init_dpi_info(void)
|
||||||
{
|
{
|
||||||
if (dpi_info.cur_dpi.x == 0 || dpi_info.cur_dpi.y == 0) {
|
if (dpi_info.cur_dpi.x == 0 || dpi_info.cur_dpi.y == 0) {
|
||||||
if (p_GetDpiForMonitor) {
|
if (p_GetDpiForMonitor && p_MonitorFromWindow) {
|
||||||
UINT dpiX, dpiY;
|
UINT dpiX, dpiY;
|
||||||
HMONITOR currentMonitor = MonitorFromWindow(
|
HMONITOR currentMonitor = p_MonitorFromWindow(
|
||||||
wgs.term_hwnd, MONITOR_DEFAULTTOPRIMARY);
|
wgs.term_hwnd, MONITOR_DEFAULTTOPRIMARY);
|
||||||
if (p_GetDpiForMonitor(currentMonitor, MDT_EFFECTIVE_DPI,
|
if (p_GetDpiForMonitor(currentMonitor, MDT_EFFECTIVE_DPI,
|
||||||
&dpiX, &dpiY) == S_OK) {
|
&dpiX, &dpiY) == S_OK) {
|
||||||
@ -2177,7 +2265,8 @@ static LRESULT CALLBACK WndProc(HWND hwnd, UINT message,
|
|||||||
* within an interactive scrollbar-drag can be handled
|
* within an interactive scrollbar-drag can be handled
|
||||||
* differently. */
|
* differently. */
|
||||||
in_scrollbar_loop = true;
|
in_scrollbar_loop = true;
|
||||||
LRESULT result = DefWindowProcW(hwnd, message, wParam, lParam);
|
LRESULT result = sw_DefWindowProc(
|
||||||
|
hwnd, message, wParam, lParam);
|
||||||
in_scrollbar_loop = false;
|
in_scrollbar_loop = false;
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
@ -2596,27 +2685,26 @@ static LRESULT CALLBACK WndProc(HWND hwnd, UINT message,
|
|||||||
|
|
||||||
GetCursorPos(&pt);
|
GetCursorPos(&pt);
|
||||||
#ifndef NO_MULTIMON
|
#ifndef NO_MULTIMON
|
||||||
{
|
if (p_GetMonitorInfoA && p_MonitorFromPoint) {
|
||||||
HMONITOR mon;
|
HMONITOR mon;
|
||||||
MONITORINFO mi;
|
MONITORINFO mi;
|
||||||
|
|
||||||
mon = MonitorFromPoint(pt, MONITOR_DEFAULTTONULL);
|
mon = p_MonitorFromPoint(pt, MONITOR_DEFAULTTONULL);
|
||||||
|
|
||||||
if (mon != NULL) {
|
if (mon != NULL) {
|
||||||
mi.cbSize = sizeof(MONITORINFO);
|
mi.cbSize = sizeof(MONITORINFO);
|
||||||
GetMonitorInfo(mon, &mi);
|
p_GetMonitorInfoA(mon, &mi);
|
||||||
|
|
||||||
if (mi.rcMonitor.left == pt.x &&
|
if (mi.rcMonitor.left == pt.x &&
|
||||||
mi.rcMonitor.top == pt.y) {
|
mi.rcMonitor.top == pt.y) {
|
||||||
mouse_on_hotspot = true;
|
mouse_on_hotspot = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
} else
|
||||||
#else
|
#endif
|
||||||
if (pt.x == 0 && pt.y == 0) {
|
if (pt.x == 0 && pt.y == 0) {
|
||||||
mouse_on_hotspot = true;
|
mouse_on_hotspot = true;
|
||||||
}
|
}
|
||||||
#endif
|
|
||||||
if (is_full_screen() && press &&
|
if (is_full_screen() && press &&
|
||||||
button == MBT_LEFT && mouse_on_hotspot) {
|
button == MBT_LEFT && mouse_on_hotspot) {
|
||||||
SendMessage(hwnd, WM_SYSCOMMAND, SC_MOUSEMENU,
|
SendMessage(hwnd, WM_SYSCOMMAND, SC_MOUSEMENU,
|
||||||
@ -2960,11 +3048,11 @@ static LRESULT CALLBACK WndProc(HWND hwnd, UINT message,
|
|||||||
term, r.right - r.left, r.bottom - r.top);
|
term, r.right - r.left, r.bottom - r.top);
|
||||||
}
|
}
|
||||||
if (wParam == SIZE_MINIMIZED)
|
if (wParam == SIZE_MINIMIZED)
|
||||||
SetWindowTextW(hwnd,
|
sw_SetWindowText(hwnd,
|
||||||
conf_get_bool(conf, CONF_win_name_always) ?
|
conf_get_bool(conf, CONF_win_name_always) ?
|
||||||
window_name : icon_name);
|
window_name : icon_name);
|
||||||
if (wParam == SIZE_RESTORED || wParam == SIZE_MAXIMIZED)
|
if (wParam == SIZE_RESTORED || wParam == SIZE_MAXIMIZED)
|
||||||
SetWindowTextW(hwnd, window_name);
|
sw_SetWindowText(hwnd, window_name);
|
||||||
if (wParam == SIZE_RESTORED) {
|
if (wParam == SIZE_RESTORED) {
|
||||||
processed_resize = false;
|
processed_resize = false;
|
||||||
clear_full_screen();
|
clear_full_screen();
|
||||||
@ -3186,7 +3274,7 @@ static LRESULT CALLBACK WndProc(HWND hwnd, UINT message,
|
|||||||
} else {
|
} else {
|
||||||
len = TranslateKey(message, wParam, lParam, buf);
|
len = TranslateKey(message, wParam, lParam, buf);
|
||||||
if (len == -1)
|
if (len == -1)
|
||||||
return DefWindowProcW(hwnd, message, wParam, lParam);
|
return sw_DefWindowProc(hwnd, message, wParam, lParam);
|
||||||
|
|
||||||
if (len != 0) {
|
if (len != 0) {
|
||||||
/*
|
/*
|
||||||
@ -3284,7 +3372,7 @@ static LRESULT CALLBACK WndProc(HWND hwnd, UINT message,
|
|||||||
* post the things to us as part of a macro manoeuvre,
|
* post the things to us as part of a macro manoeuvre,
|
||||||
* we're ready to cope.
|
* we're ready to cope.
|
||||||
*/
|
*/
|
||||||
{
|
if (unicode_window) {
|
||||||
static wchar_t pending_surrogate = 0;
|
static wchar_t pending_surrogate = 0;
|
||||||
wchar_t c = wParam;
|
wchar_t c = wParam;
|
||||||
|
|
||||||
@ -3298,6 +3386,11 @@ static LRESULT CALLBACK WndProc(HWND hwnd, UINT message,
|
|||||||
} else if (!IS_SURROGATE(c)) {
|
} else if (!IS_SURROGATE(c)) {
|
||||||
term_keyinputw(term, &c, 1);
|
term_keyinputw(term, &c, 1);
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
|
char c = (unsigned char)wParam;
|
||||||
|
term_seen_key_event(term);
|
||||||
|
if (ldisc)
|
||||||
|
term_keyinput(term, CP_ACP, &c, 1);
|
||||||
}
|
}
|
||||||
return 0;
|
return 0;
|
||||||
case WM_SYSCOLORCHANGE:
|
case WM_SYSCOLORCHANGE:
|
||||||
@ -3373,7 +3466,7 @@ static LRESULT CALLBACK WndProc(HWND hwnd, UINT message,
|
|||||||
* Any messages we don't process completely above are passed through to
|
* Any messages we don't process completely above are passed through to
|
||||||
* DefWindowProc() for default processing.
|
* DefWindowProc() for default processing.
|
||||||
*/
|
*/
|
||||||
return DefWindowProcW(hwnd, message, wParam, lParam);
|
return sw_DefWindowProc(hwnd, message, wParam, lParam);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -4041,6 +4134,9 @@ static void init_winfuncs(void)
|
|||||||
GET_WINDOWS_FUNCTION(user32_module, FlashWindowEx);
|
GET_WINDOWS_FUNCTION(user32_module, FlashWindowEx);
|
||||||
GET_WINDOWS_FUNCTION(user32_module, ToUnicodeEx);
|
GET_WINDOWS_FUNCTION(user32_module, ToUnicodeEx);
|
||||||
GET_WINDOWS_FUNCTION_PP(winmm_module, PlaySound);
|
GET_WINDOWS_FUNCTION_PP(winmm_module, PlaySound);
|
||||||
|
GET_WINDOWS_FUNCTION_NO_TYPECHECK(user32_module, GetMonitorInfoA);
|
||||||
|
GET_WINDOWS_FUNCTION_NO_TYPECHECK(user32_module, MonitorFromPoint);
|
||||||
|
GET_WINDOWS_FUNCTION_NO_TYPECHECK(user32_module, MonitorFromWindow);
|
||||||
GET_WINDOWS_FUNCTION_NO_TYPECHECK(shcore_module, GetDpiForMonitor);
|
GET_WINDOWS_FUNCTION_NO_TYPECHECK(shcore_module, GetDpiForMonitor);
|
||||||
GET_WINDOWS_FUNCTION_NO_TYPECHECK(user32_module, GetSystemMetricsForDpi);
|
GET_WINDOWS_FUNCTION_NO_TYPECHECK(user32_module, GetSystemMetricsForDpi);
|
||||||
GET_WINDOWS_FUNCTION_NO_TYPECHECK(user32_module, AdjustWindowRectExForDpi);
|
GET_WINDOWS_FUNCTION_NO_TYPECHECK(user32_module, AdjustWindowRectExForDpi);
|
||||||
@ -4724,18 +4820,28 @@ static int TranslateKey(UINT message, WPARAM wParam, LPARAM lParam,
|
|||||||
|
|
||||||
static void wintw_set_title(TermWin *tw, const char *title, int codepage)
|
static void wintw_set_title(TermWin *tw, const char *title, int codepage)
|
||||||
{
|
{
|
||||||
|
wchar_t *new_window_name = dup_mb_to_wc(codepage, 0, title);
|
||||||
|
if (!wcscmp(new_window_name, window_name)) {
|
||||||
|
sfree(new_window_name);
|
||||||
|
return;
|
||||||
|
}
|
||||||
sfree(window_name);
|
sfree(window_name);
|
||||||
window_name = dup_mb_to_wc(codepage, 0, title);
|
window_name = new_window_name;
|
||||||
if (conf_get_bool(conf, CONF_win_name_always) || !IsIconic(wgs.term_hwnd))
|
if (conf_get_bool(conf, CONF_win_name_always) || !IsIconic(wgs.term_hwnd))
|
||||||
SetWindowTextW(wgs.term_hwnd, window_name);
|
sw_SetWindowText(wgs.term_hwnd, window_name);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void wintw_set_icon_title(TermWin *tw, const char *title, int codepage)
|
static void wintw_set_icon_title(TermWin *tw, const char *title, int codepage)
|
||||||
{
|
{
|
||||||
|
wchar_t *new_icon_name = dup_mb_to_wc(codepage, 0, title);
|
||||||
|
if (!wcscmp(new_icon_name, icon_name)) {
|
||||||
|
sfree(new_icon_name);
|
||||||
|
return;
|
||||||
|
}
|
||||||
sfree(icon_name);
|
sfree(icon_name);
|
||||||
icon_name = dup_mb_to_wc(codepage, 0, title);
|
icon_name = new_icon_name;
|
||||||
if (!conf_get_bool(conf, CONF_win_name_always) && IsIconic(wgs.term_hwnd))
|
if (!conf_get_bool(conf, CONF_win_name_always) && IsIconic(wgs.term_hwnd))
|
||||||
SetWindowTextW(wgs.term_hwnd, icon_name);
|
sw_SetWindowText(wgs.term_hwnd, icon_name);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void wintw_set_scrollbar(TermWin *tw, int total, int start, int page)
|
static void wintw_set_scrollbar(TermWin *tw, int total, int start, int page)
|
||||||
@ -5641,23 +5747,24 @@ static bool is_full_screen()
|
|||||||
static bool get_fullscreen_rect(RECT * ss)
|
static bool get_fullscreen_rect(RECT * ss)
|
||||||
{
|
{
|
||||||
#if defined(MONITOR_DEFAULTTONEAREST) && !defined(NO_MULTIMON)
|
#if defined(MONITOR_DEFAULTTONEAREST) && !defined(NO_MULTIMON)
|
||||||
|
if (p_GetMonitorInfoA && p_MonitorFromWindow) {
|
||||||
HMONITOR mon;
|
HMONITOR mon;
|
||||||
MONITORINFO mi;
|
MONITORINFO mi;
|
||||||
mon = MonitorFromWindow(wgs.term_hwnd, MONITOR_DEFAULTTONEAREST);
|
mon = p_MonitorFromWindow(wgs.term_hwnd, MONITOR_DEFAULTTONEAREST);
|
||||||
mi.cbSize = sizeof(mi);
|
mi.cbSize = sizeof(mi);
|
||||||
GetMonitorInfo(mon, &mi);
|
p_GetMonitorInfoA(mon, &mi);
|
||||||
|
|
||||||
/* structure copy */
|
/* structure copy */
|
||||||
*ss = mi.rcMonitor;
|
*ss = mi.rcMonitor;
|
||||||
return true;
|
return true;
|
||||||
#else
|
}
|
||||||
|
#endif
|
||||||
/* could also use code like this:
|
/* could also use code like this:
|
||||||
ss->left = ss->top = 0;
|
ss->left = ss->top = 0;
|
||||||
ss->right = GetSystemMetrics(SM_CXSCREEN);
|
ss->right = GetSystemMetrics(SM_CXSCREEN);
|
||||||
ss->bottom = GetSystemMetrics(SM_CYSCREEN);
|
ss->bottom = GetSystemMetrics(SM_CYSCREEN);
|
||||||
*/
|
*/
|
||||||
return GetClientRect(GetDesktopWindow(), ss);
|
return GetClientRect(GetDesktopWindow(), ss);
|
||||||
#endif
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user