Remove diagnostics and attempt to work around VC compiler bug :-(
[sgt/putty] / window.c
Content-type: text/html mdw@git.distorted.org.uk Git - sgt/putty/blame - window.c


500 - Internal Server Error

Malformed UTF-8 character (fatal) at (eval 5) line 1, <$fd> line 4776.
CommitLineData
374330e2 1#include <windows.h>
49bad831 2#include <imm.h>
374330e2 3#include <commctrl.h>
f0a70059 4#include <mmsystem.h>
4d331a77 5#ifndef AUTO_WINSOCK
6#ifdef WINSOCK_TWO
7#include <winsock2.h>
8#else
374330e2 9#include <winsock.h>
4d331a77 10#endif
11#endif
374330e2 12#include <stdio.h>
13#include <stdlib.h>
1d470ad2 14#include <ctype.h>
ec55b220 15#include <time.h>
374330e2 16
17#define PUTTY_DO_GLOBALS /* actually _define_ globals */
18#include "putty.h"
8c3cd914 19#include "winstuff.h"
d5859615 20#include "storage.h"
374330e2 21#include "win_res.h"
22
6833a413 23#define IDM_SHOWLOG 0x0010
24#define IDM_NEWSESS 0x0020
25#define IDM_DUPSESS 0x0030
26#define IDM_RECONF 0x0040
27#define IDM_CLRSB 0x0050
28#define IDM_RESET 0x0060
29#define IDM_TEL_AYT 0x0070
30#define IDM_TEL_BRK 0x0080
31#define IDM_TEL_SYNCH 0x0090
32#define IDM_TEL_EC 0x00a0
33#define IDM_TEL_EL 0x00b0
34#define IDM_TEL_GA 0x00c0
35#define IDM_TEL_NOP 0x00d0
36#define IDM_TEL_ABORT 0x00e0
37#define IDM_TEL_AO 0x00f0
38#define IDM_TEL_IP 0x0100
39#define IDM_TEL_SUSP 0x0110
40#define IDM_TEL_EOR 0x0120
41#define IDM_TEL_EOF 0x0130
42#define IDM_ABOUT 0x0140
43#define IDM_SAVEDSESS 0x0150
bc1235d4 44#define IDM_COPYALL 0x0160
6833a413 45
9f89f96e 46#define IDM_SESSLGP 0x0250 /* log type printable */
47#define IDM_SESSLGA 0x0260 /* log type all chars */
48#define IDM_SESSLGE 0x0270 /* log end */
6833a413 49#define IDM_SAVED_MIN 0x1000
50#define IDM_SAVED_MAX 0x2000
374330e2 51
59ad2c03 52#define WM_IGNORE_SIZE (WM_XUSER + 1)
53#define WM_IGNORE_CLIP (WM_XUSER + 2)
374330e2 54
3cf144db 55/* Needed for Chinese support and apparently not always defined. */
56#ifndef VK_PROCESSKEY
57#define VK_PROCESSKEY 0xE5
58#endif
59
996c8c3b 60static LRESULT CALLBACK WndProc (HWND, UINT, WPARAM, LPARAM);
c9def1b8 61static int TranslateKey(UINT message, WPARAM wParam, LPARAM lParam, unsigned char *output);
374330e2 62static void cfgtopalette(void);
63static void init_palette(void);
59ad2c03 64static void init_fonts(int);
374330e2 65
66static int extra_width, extra_height;
67
59ad2c03 68static int pending_netevent = 0;
69static WPARAM pend_netevent_wParam = 0;
70static LPARAM pend_netevent_lParam = 0;
71static void enact_pending_netevent(void);
72
ec55b220 73static time_t last_movement = 0;
74
374330e2 75#define FONT_NORMAL 0
76#define FONT_BOLD 1
77#define FONT_UNDERLINE 2
78#define FONT_BOLDUND 3
79#define FONT_OEM 4
80#define FONT_OEMBOLD 5
81#define FONT_OEMBOLDUND 6
82#define FONT_OEMUND 7
83static HFONT fonts[8];
09798031 84static int font_needs_hand_underlining;
374330e2 85static enum {
86 BOLD_COLOURS, BOLD_SHADOW, BOLD_FONT
87} bold_mode;
88static enum {
89 UND_LINE, UND_FONT
90} und_mode;
91static int descent;
92
93#define NCOLOURS 24
94static COLORREF colours[NCOLOURS];
95static HPALETTE pal;
96static LPLOGPALETTE logpal;
97static RGBTRIPLE defpal[NCOLOURS];
98
99static HWND hwnd;
100
934c0b7a 101static HBITMAP caretbm;
102
374330e2 103static int dbltime, lasttime, lastact;
104static Mouse_Button lastbtn;
105
106static char *window_name, *icon_name;
107
03f23ad6 108static int compose_state = 0;
109
0965bee0 110/* Dummy routine, only required in plink. */
111void ldisc_update(int echo, int edit) {}
6f34e365 112
374330e2 113int WINAPI WinMain(HINSTANCE inst, HINSTANCE prev, LPSTR cmdline, int show) {
114 static char appname[] = "PuTTY";
115 WORD winsock_ver;
116 WSADATA wsadata;
117 WNDCLASS wndclass;
118 MSG msg;
119 int guess_width, guess_height;
120
8c3cd914 121 hinst = inst;
67779be7 122 flags = FLAG_VERBOSE | FLAG_INTERACTIVE;
73251d5d 123
374330e2 124 winsock_ver = MAKEWORD(1, 1);
125 if (WSAStartup(winsock_ver, &wsadata)) {
126 MessageBox(NULL, "Unable to initialise WinSock", "WinSock Error",
127 MB_OK | MB_ICONEXCLAMATION);
128 return 1;
129 }
130 if (LOBYTE(wsadata.wVersion) != 1 || HIBYTE(wsadata.wVersion) != 1) {
131 MessageBox(NULL, "WinSock version is incompatible with 1.1",
132 "WinSock Error", MB_OK | MB_ICONEXCLAMATION);
133 WSACleanup();
134 return 1;
135 }
136 /* WISHLIST: maybe allow config tweaking even if winsock not present? */
8df7a775 137 sk_init();
374330e2 138
139 InitCommonControls();
140
301b66db 141 /* Ensure a Maximize setting in Explorer doesn't maximise the
142 * config box. */
143 defuse_showwindow();
144
374330e2 145 /*
146 * Process the command line.
147 */
148 {
149 char *p;
150
e277c42d 151 default_protocol = DEFAULT_PROTOCOL;
152 default_port = DEFAULT_PORT;
e1c8e0ed 153 cfg.logtype = LGTYP_NONE;
e277c42d 154
a9422f39 155 do_defaults(NULL, &cfg);
374330e2 156
157 p = cmdline;
158 while (*p && isspace(*p)) p++;
159
160 /*
e277c42d 161 * Process command line options first. Yes, this can be
162 * done better, and it will be as soon as I have the
163 * energy...
164 */
165 while (*p == '-') {
166 char *q = p + strcspn(p, " \t");
167 p++;
168 if (q == p + 3 &&
169 tolower(p[0]) == 's' &&
170 tolower(p[1]) == 's' &&
171 tolower(p[2]) == 'h') {
172 default_protocol = cfg.protocol = PROT_SSH;
173 default_port = cfg.port = 22;
de3df031 174 } else if (q == p + 7 &&
175 tolower(p[0]) == 'c' &&
176 tolower(p[1]) == 'l' &&
177 tolower(p[2]) == 'e' &&
178 tolower(p[3]) == 'a' &&
179 tolower(p[4]) == 'n' &&
180 tolower(p[5]) == 'u' &&
181 tolower(p[6]) == 'p') {
182 /*
183 * `putty -cleanup'. Remove all registry entries
184 * associated with PuTTY, and also find and delete
185 * the random seed file.
186 */
187 if (MessageBox(NULL,
188 "This procedure will remove ALL Registry\n"
189 "entries associated with PuTTY, and will\n"
190 "also remove the PuTTY random seed file.\n"
191 "\n"
192 "THIS PROCESS WILL DESTROY YOUR SAVED\n"
193 "SESSIONS. Are you really sure you want\n"
194 "to continue?",
195 "PuTTY Warning",
196 MB_YESNO | MB_ICONWARNING) == IDYES) {
d5859615 197 cleanup_all();
de3df031 198 }
199 exit(0);
e277c42d 200 }
201 p = q + strspn(q, " \t");
202 }
203
204 /*
374330e2 205 * An initial @ means to activate a saved session.
206 */
207 if (*p == '@') {
f317611e 208 int i = strlen(p);
209 while (i > 1 && isspace(p[i-1]))
210 i--;
211 p[i] = '\0';
a9422f39 212 do_defaults (p+1, &cfg);
374330e2 213 if (!*cfg.host && !do_config()) {
214 WSACleanup();
215 return 0;
216 }
217 } else if (*p == '&') {
218 /*
219 * An initial & means we've been given a command line
220 * containing the hex value of a HANDLE for a file
221 * mapping object, which we must then extract as a
222 * config.
223 */
224 HANDLE filemap;
225 Config *cp;
1d470ad2 226 if (sscanf(p+1, "%p", &filemap) == 1 &&
374330e2 227 (cp = MapViewOfFile(filemap, FILE_MAP_READ,
228 0, 0, sizeof(Config))) != NULL) {
229 cfg = *cp;
230 UnmapViewOfFile(cp);
231 CloseHandle(filemap);
232 } else if (!do_config()) {
233 WSACleanup();
234 return 0;
235 }
236 } else if (*p) {
237 char *q = p;
4e8bc59f 238 /*
70887be9 239 * If the hostname starts with "telnet:", set the
4e8bc59f 240 * protocol to Telnet and process the string as a
241 * Telnet URL.
242 */
70887be9 243 if (!strncmp(q, "telnet:", 7)) {
ab21de77 244 char c;
245
70887be9 246 q += 7;
247 if (q[0] == '/' && q[1] == '/')
248 q += 2;
4e8bc59f 249 cfg.protocol = PROT_TELNET;
250 p = q;
ab21de77 251 while (*p && *p != ':' && *p != '/') p++;
252 c = *p;
253 if (*p)
4e8bc59f 254 *p++ = '\0';
ab21de77 255 if (c == ':')
4e8bc59f 256 cfg.port = atoi(p);
ab21de77 257 else
4e8bc59f 258 cfg.port = -1;
259 strncpy (cfg.host, q, sizeof(cfg.host)-1);
260 cfg.host[sizeof(cfg.host)-1] = '\0';
261 } else {
262 while (*p && !isspace(*p)) p++;
263 if (*p)
264 *p++ = '\0';
265 strncpy (cfg.host, q, sizeof(cfg.host)-1);
266 cfg.host[sizeof(cfg.host)-1] = '\0';
267 while (*p && isspace(*p)) p++;
268 if (*p)
269 cfg.port = atoi(p);
270 else
271 cfg.port = -1;
272 }
374330e2 273 } else {
274 if (!do_config()) {
275 WSACleanup();
276 return 0;
277 }
278 }
13eafebf 279
280 /* See if host is of the form user@host */
281 if (cfg.host[0] != '\0') {
282 char *atsign = strchr(cfg.host, '@');
283 /* Make sure we're not overflowing the user field */
284 if (atsign) {
285 if (atsign-cfg.host < sizeof cfg.username) {
286 strncpy (cfg.username, cfg.host, atsign-cfg.host);
287 cfg.username[atsign-cfg.host] = '\0';
288 }
289 memmove(cfg.host, atsign+1, 1+strlen(atsign+1));
290 }
291 }
374330e2 292 }
293
89ee5268 294 /*
295 * Select protocol. This is farmed out into a table in a
296 * separate file to enable an ssh-free variant.
297 */
298 {
299 int i;
300 back = NULL;
301 for (i = 0; backends[i].backend != NULL; i++)
302 if (backends[i].protocol == cfg.protocol) {
303 back = backends[i].backend;
304 break;
305 }
306 if (back == NULL) {
307 MessageBox(NULL, "Unsupported protocol number found",
308 "PuTTY Internal Error", MB_OK | MB_ICONEXCLAMATION);
309 WSACleanup();
310 return 1;
311 }
312 }
5bc238bb 313
b278b14a 314 /* Check for invalid Port number (i.e. zero) */
315 if (cfg.port == 0) {
316 MessageBox(NULL, "Invalid Port Number",
317 "PuTTY Internal Error", MB_OK |MB_ICONEXCLAMATION);
318 WSACleanup();
319 return 1;
320 }
321
374330e2 322 if (!prev) {
323 wndclass.style = 0;
324 wndclass.lpfnWndProc = WndProc;
325 wndclass.cbClsExtra = 0;
326 wndclass.cbWndExtra = 0;
327 wndclass.hInstance = inst;
328 wndclass.hIcon = LoadIcon (inst,
329 MAKEINTRESOURCE(IDI_MAINICON));
1bb542b2 330 wndclass.hCursor = LoadCursor (NULL, IDC_IBEAM);
374330e2 331 wndclass.hbrBackground = GetStockObject (BLACK_BRUSH);
332 wndclass.lpszMenuName = NULL;
333 wndclass.lpszClassName = appname;
334
335 RegisterClass (&wndclass);
336 }
337
338 hwnd = NULL;
339
340 savelines = cfg.savelines;
341 term_init();
342
343 cfgtopalette();
344
345 /*
346 * Guess some defaults for the window size. This all gets
347 * updated later, so we don't really care too much. However, we
348 * do want the font width/height guesses to correspond to a
349 * large font rather than a small one...
350 */
351
352 font_width = 10;
353 font_height = 20;
354 extra_width = 25;
355 extra_height = 28;
356 term_size (cfg.height, cfg.width, cfg.savelines);
357 guess_width = extra_width + font_width * cols;
358 guess_height = extra_height + font_height * rows;
359 {
360 RECT r;
361 HWND w = GetDesktopWindow();
362 GetWindowRect (w, &r);
363 if (guess_width > r.right - r.left)
364 guess_width = r.right - r.left;
365 if (guess_height > r.bottom - r.top)
366 guess_height = r.bottom - r.top;
367 }
368
c9def1b8 369 {
3cf144db 370 int winmode = WS_OVERLAPPEDWINDOW|WS_VSCROLL;
e95edc00 371 int exwinmode = 0;
372 if (!cfg.scrollbar) winmode &= ~(WS_VSCROLL);
373 if (cfg.locksize) winmode &= ~(WS_THICKFRAME|WS_MAXIMIZEBOX);
57d08f2f 374 if (cfg.alwaysontop) exwinmode |= WS_EX_TOPMOST;
375 if (cfg.sunken_edge) exwinmode |= WS_EX_CLIENTEDGE;
e95edc00 376 hwnd = CreateWindowEx (exwinmode, appname, appname,
377 winmode, CW_USEDEFAULT, CW_USEDEFAULT,
378 guess_width, guess_height,
379 NULL, NULL, inst, NULL);
380 }
374330e2 381
382 /*
383 * Initialise the fonts, simultaneously correcting the guesses
384 * for font_{width,height}.
385 */
386 bold_mode = cfg.bold_colour ? BOLD_COLOURS : BOLD_FONT;
387 und_mode = UND_FONT;
59ad2c03 388 init_fonts(0);
374330e2 389
390 /*
391 * Correct the guesses for extra_{width,height}.
392 */
393 {
394 RECT cr, wr;
395 GetWindowRect (hwnd, &wr);
396 GetClientRect (hwnd, &cr);
397 extra_width = wr.right - wr.left - cr.right + cr.left;
398 extra_height = wr.bottom - wr.top - cr.bottom + cr.top;
399 }
400
401 /*
402 * Resize the window, now we know what size we _really_ want it
403 * to be.
404 */
405 guess_width = extra_width + font_width * cols;
406 guess_height = extra_height + font_height * rows;
407 SendMessage (hwnd, WM_IGNORE_SIZE, 0, 0);
408 SetWindowPos (hwnd, NULL, 0, 0, guess_width, guess_height,
409 SWP_NOMOVE | SWP_NOREDRAW | SWP_NOZORDER);
410
411 /*
934c0b7a 412 * Set up a caret bitmap, with no content.
413 */
414 {
415 char *bits;
416 int size = (font_width+15)/16 * 2 * font_height;
dcbde236 417 bits = smalloc(size);
418 memset(bits, 0, size);
934c0b7a 419 caretbm = CreateBitmap(font_width, font_height, 1, 1, bits);
dcbde236 420 sfree(bits);
934c0b7a 421 }
5b7ce734 422 CreateCaret(hwnd, caretbm, font_width, font_height);
934c0b7a 423
424 /*
374330e2 425 * Initialise the scroll bar.
426 */
427 {
428 SCROLLINFO si;
429
430 si.cbSize = sizeof(si);
c9def1b8 431 si.fMask = SIF_ALL | SIF_DISABLENOSCROLL;
374330e2 432 si.nMin = 0;
433 si.nMax = rows-1;
434 si.nPage = rows;
435 si.nPos = 0;
436 SetScrollInfo (hwnd, SB_VERT, &si, FALSE);
437 }
438
439 /*
440 * Start up the telnet connection.
441 */
442 {
443 char *error;
9ca5da42 444 char msg[1024], *title;
374330e2 445 char *realhost;
446
8df7a775 447 error = back->init (cfg.host, cfg.port, &realhost);
374330e2 448 if (error) {
582c0054 449 sprintf(msg, "Unable to open connection to\n"
450 "%.800s\n"
451 "%s", cfg.host, error);
374330e2 452 MessageBox(NULL, msg, "PuTTY Error", MB_ICONERROR | MB_OK);
453 return 0;
454 }
455 window_name = icon_name = NULL;
9ca5da42 456 if (*cfg.wintitle) {
457 title = cfg.wintitle;
458 } else {
459 sprintf(msg, "%s - PuTTY", realhost);
460 title = msg;
461 }
462 set_title (title);
463 set_icon (title);
374330e2 464 }
465
d85548fe 466 session_closed = FALSE;
467
374330e2 468 /*
469 * Set up the input and output buffers.
470 */
c9def1b8 471 inbuf_head = 0;
374330e2 472 outbuf_reap = outbuf_head = 0;
473
474 /*
475 * Prepare the mouse handler.
476 */
477 lastact = MA_NOTHING;
478 lastbtn = MB_NOTHING;
479 dbltime = GetDoubleClickTime();
480
481 /*
482 * Set up the session-control options on the system menu.
483 */
484 {
485 HMENU m = GetSystemMenu (hwnd, FALSE);
0a4aa984 486 HMENU p,s;
487 int i;
374330e2 488
489 AppendMenu (m, MF_SEPARATOR, 0, 0);
490 if (cfg.protocol == PROT_TELNET) {
491 p = CreateMenu();
492 AppendMenu (p, MF_ENABLED, IDM_TEL_AYT, "Are You There");
493 AppendMenu (p, MF_ENABLED, IDM_TEL_BRK, "Break");
494 AppendMenu (p, MF_ENABLED, IDM_TEL_SYNCH, "Synch");
495 AppendMenu (p, MF_SEPARATOR, 0, 0);
496 AppendMenu (p, MF_ENABLED, IDM_TEL_EC, "Erase Character");
497 AppendMenu (p, MF_ENABLED, IDM_TEL_EL, "Erase Line");
498 AppendMenu (p, MF_ENABLED, IDM_TEL_GA, "Go Ahead");
499 AppendMenu (p, MF_ENABLED, IDM_TEL_NOP, "No Operation");
500 AppendMenu (p, MF_SEPARATOR, 0, 0);
501 AppendMenu (p, MF_ENABLED, IDM_TEL_ABORT, "Abort Process");
502 AppendMenu (p, MF_ENABLED, IDM_TEL_AO, "Abort Output");
503 AppendMenu (p, MF_ENABLED, IDM_TEL_IP, "Interrupt Process");
504 AppendMenu (p, MF_ENABLED, IDM_TEL_SUSP, "Suspend Process");
505 AppendMenu (p, MF_SEPARATOR, 0, 0);
506 AppendMenu (p, MF_ENABLED, IDM_TEL_EOR, "End Of Record");
507 AppendMenu (p, MF_ENABLED, IDM_TEL_EOF, "End Of File");
508 AppendMenu (m, MF_POPUP | MF_ENABLED, (UINT) p, "Telnet Command");
374330e2 509 AppendMenu (m, MF_SEPARATOR, 0, 0);
510 }
45c4ea18 511 AppendMenu (m, MF_ENABLED, IDM_SHOWLOG, "&Event Log");
c5e9c988 512 AppendMenu (m, MF_SEPARATOR, 0, 0);
239e40c0 513 AppendMenu (m, MF_ENABLED, IDM_NEWSESS, "Ne&w Session...");
45c4ea18 514 AppendMenu (m, MF_ENABLED, IDM_DUPSESS, "&Duplicate Session");
0a4aa984 515 s = CreateMenu();
516 get_sesslist(TRUE);
517 for (i = 1 ; i < ((nsessions < 256) ? nsessions : 256) ; i++)
518 AppendMenu (s, MF_ENABLED, IDM_SAVED_MIN + (16 * i) , sessions[i]);
45c4ea18 519 AppendMenu (m, MF_POPUP | MF_ENABLED, (UINT) s, "Sa&ved Sessions");
239e40c0 520 AppendMenu (m, MF_ENABLED, IDM_RECONF, "Chan&ge Settings...");
374330e2 521 AppendMenu (m, MF_SEPARATOR, 0, 0);
bc1235d4 522 AppendMenu (m, MF_ENABLED, IDM_COPYALL, "C&opy All to Clipboard");
45c4ea18 523 AppendMenu (m, MF_ENABLED, IDM_CLRSB, "C&lear Scrollback");
524 AppendMenu (m, MF_ENABLED, IDM_RESET, "Rese&t Terminal");
374330e2 525 AppendMenu (m, MF_SEPARATOR, 0, 0);
45c4ea18 526 AppendMenu (m, MF_ENABLED, IDM_ABOUT, "&About PuTTY");
374330e2 527 }
528
529 /*
530 * Finally show the window!
531 */
532 ShowWindow (hwnd, show);
533
534 /*
e1c8e0ed 535 * Open the initial log file if there is one.
536 */
537 logfopen();
538
539 /*
374330e2 540 * Set the palette up.
541 */
542 pal = NULL;
543 logpal = NULL;
544 init_palette();
545
546 has_focus = (GetForegroundWindow() == hwnd);
547 UpdateWindow (hwnd);
548
ec55b220 549 if (GetMessage (&msg, NULL, 0, 0) == 1)
59ad2c03 550 {
551 int timer_id = 0, long_timer = 0;
552
ec55b220 553 while (msg.message != WM_QUIT) {
59ad2c03 554 /* Sometimes DispatchMessage calls routines that use their own
555 * GetMessage loop, setup this timer so we get some control back.
556 *
557 * Also call term_update() from the timer so that if the host
558 * is sending data flat out we still do redraws.
559 */
560 if(timer_id && long_timer) {
561 KillTimer(hwnd, timer_id);
562 long_timer = timer_id = 0;
563 }
564 if(!timer_id)
565 timer_id = SetTimer(hwnd, 1, 20, NULL);
475eebf9 566 if (!(IsWindow(logbox) && IsDialogMessage(logbox, &msg)))
567 DispatchMessage (&msg);
59ad2c03 568
ec55b220 569 /* Make sure we blink everything that needs it. */
59ad2c03 570 term_blink(0);
571
c9def1b8 572 /* Send the paste buffer if there's anything to send */
573 term_paste();
574
59ad2c03 575 /* If there's nothing new in the queue then we can do everything
576 * we've delayed, reading the socket, writing, and repainting
577 * the window.
578 */
ec55b220 579 if (PeekMessage (&msg, NULL, 0, 0, PM_REMOVE))
580 continue;
59ad2c03 581
ec55b220 582 if (pending_netevent) {
583 enact_pending_netevent();
584
585 /* Force the cursor blink on */
586 term_blink(1);
587
588 if (PeekMessage (&msg, NULL, 0, 0, PM_REMOVE))
589 continue;
59ad2c03 590 }
ec55b220 591
592 /* Okay there is now nothing to do so we make sure the screen is
593 * completely up to date then tell windows to call us in a little
594 * while.
595 */
596 if (timer_id) {
597 KillTimer(hwnd, timer_id);
598 timer_id = 0;
599 }
600 HideCaret(hwnd);
601 if (inbuf_head)
602 term_out();
603 term_update();
604 ShowCaret(hwnd);
156686ef 605 if (in_vbell)
606 /* Hmm, term_update didn't want to do an update too soon ... */
607 timer_id = SetTimer(hwnd, 1, 50, NULL);
608 else if (!has_focus)
fde67d86 609 timer_id = SetTimer(hwnd, 1, 2000, NULL);
ec55b220 610 else
81076d5d 611 timer_id = SetTimer(hwnd, 1, 100, NULL);
ec55b220 612 long_timer = 1;
613
614 /* There's no point rescanning everything in the message queue
156686ef 615 * so we do an apparently unnecessary wait here
ec55b220 616 */
617 WaitMessage();
618 if (GetMessage (&msg, NULL, 0, 0) != 1)
619 break;
59ad2c03 620 }
374330e2 621 }
622
623 /*
624 * Clean up.
625 */
626 {
627 int i;
628 for (i=0; i<8; i++)
629 if (fonts[i])
630 DeleteObject(fonts[i]);
631 }
632 sfree(logpal);
633 if (pal)
634 DeleteObject(pal);
635 WSACleanup();
636
8f203108 637 if (cfg.protocol == PROT_SSH) {
374330e2 638 random_save_seed();
8f203108 639#ifdef MSCRYPTOAPI
640 crypto_wrapup();
641#endif
642 }
374330e2 643
644 return msg.wParam;
645}
646
647/*
8df7a775 648 * Set up, or shut down, an AsyncSelect. Called from winnet.c.
649 */
650char *do_select(SOCKET skt, int startup) {
651 int msg, events;
652 if (startup) {
653 msg = WM_NETEVENT;
654 events = FD_READ | FD_WRITE | FD_OOB | FD_CLOSE;
655 } else {
656 msg = events = 0;
657 }
658 if (!hwnd)
659 return "do_select(): internal error (hwnd==NULL)";
660 if (WSAAsyncSelect (skt, hwnd, msg, events) == SOCKET_ERROR) {
661 switch (WSAGetLastError()) {
662 case WSAENETDOWN: return "Network is down";
663 default: return "WSAAsyncSelect(): unknown error";
664 }
665 }
666 return NULL;
667}
668
669/*
8d5de777 670 * Print a message box and close the connection.
671 */
672void connection_fatal(char *fmt, ...) {
673 va_list ap;
674 char stuff[200];
675
676 va_start(ap, fmt);
677 vsprintf(stuff, fmt, ap);
678 va_end(ap);
679 MessageBox(hwnd, stuff, "PuTTY Fatal Error", MB_ICONERROR | MB_OK);
b41069ff 680 if (cfg.close_on_exit == COE_ALWAYS)
8d5de777 681 PostQuitMessage(1);
682 else {
683 session_closed = TRUE;
684 SetWindowText (hwnd, "PuTTY (inactive)");
685 }
686}
687
688/*
59ad2c03 689 * Actually do the job requested by a WM_NETEVENT
690 */
691static void enact_pending_netevent(void) {
9dde0b46 692 static int reentering = 0;
8df7a775 693 extern int select_result(WPARAM, LPARAM);
694 int ret;
9dde0b46 695
696 if (reentering)
697 return; /* don't unpend the pending */
698
59ad2c03 699 pending_netevent = FALSE;
9dde0b46 700
701 reentering = 1;
8df7a775 702 ret = select_result (pend_netevent_wParam, pend_netevent_lParam);
9dde0b46 703 reentering = 0;
59ad2c03 704
b41069ff 705 if (ret == 0 && !session_closed) {
706 /* Abnormal exits will already have set session_closed and taken
707 * appropriate action. */
708 if (cfg.close_on_exit == COE_ALWAYS ||
709 cfg.close_on_exit == COE_NORMAL)
59ad2c03 710 PostQuitMessage(0);
711 else {
b41069ff 712 session_closed = TRUE;
713 SetWindowText (hwnd, "PuTTY (inactive)");
714 MessageBox(hwnd, "Connection closed by remote host",
715 "PuTTY", MB_OK | MB_ICONINFORMATION);
59ad2c03 716 }
717 }
718}
719
720/*
374330e2 721 * Copy the colour palette from the configuration data into defpal.
722 * This is non-trivial because the colour indices are different.
723 */
724static void cfgtopalette(void) {
725 int i;
726 static const int ww[] = {
727 6, 7, 8, 9, 10, 11, 12, 13,
728 14, 15, 16, 17, 18, 19, 20, 21,
729 0, 1, 2, 3, 4, 4, 5, 5
730 };
731
732 for (i=0; i<24; i++) {
733 int w = ww[i];
734 defpal[i].rgbtRed = cfg.colours[w][0];
735 defpal[i].rgbtGreen = cfg.colours[w][1];
736 defpal[i].rgbtBlue = cfg.colours[w][2];
737 }
738}
739
740/*
741 * Set up the colour palette.
742 */
743static void init_palette(void) {
744 int i;
745 HDC hdc = GetDC (hwnd);
746 if (hdc) {
747 if (cfg.try_palette &&
748 GetDeviceCaps (hdc, RASTERCAPS) & RC_PALETTE) {
749 logpal = smalloc(sizeof(*logpal)
750 - sizeof(logpal->palPalEntry)
751 + NCOLOURS * sizeof(PALETTEENTRY));
752 logpal->palVersion = 0x300;
753 logpal->palNumEntries = NCOLOURS;
754 for (i = 0; i < NCOLOURS; i++) {
755 logpal->palPalEntry[i].peRed = defpal[i].rgbtRed;
756 logpal->palPalEntry[i].peGreen = defpal[i].rgbtGreen;
757 logpal->palPalEntry[i].peBlue = defpal[i].rgbtBlue;
758 logpal->palPalEntry[i].peFlags = PC_NOCOLLAPSE;
759 }
760 pal = CreatePalette (logpal);
761 if (pal) {
762 SelectPalette (hdc, pal, FALSE);
763 RealizePalette (hdc);
764 SelectPalette (hdc, GetStockObject (DEFAULT_PALETTE),
765 FALSE);
766 }
767 }
768 ReleaseDC (hwnd, hdc);
769 }
770 if (pal)
771 for (i=0; i<NCOLOURS; i++)
772 colours[i] = PALETTERGB(defpal[i].rgbtRed,
773 defpal[i].rgbtGreen,
774 defpal[i].rgbtBlue);
775 else
776 for(i=0; i<NCOLOURS; i++)
777 colours[i] = RGB(defpal[i].rgbtRed,
778 defpal[i].rgbtGreen,
779 defpal[i].rgbtBlue);
780}
781
782/*
783 * Initialise all the fonts we will need. There may be as many as
784 * eight or as few as one. We also:
785 *
786 * - check the font width and height, correcting our guesses if
787 * necessary.
788 *
789 * - verify that the bold font is the same width as the ordinary
790 * one, and engage shadow bolding if not.
791 *
792 * - verify that the underlined font is the same width as the
793 * ordinary one (manual underlining by means of line drawing can
794 * be done in a pinch).
374330e2 795 */
59ad2c03 796static void init_fonts(int pick_width) {
374330e2 797 TEXTMETRIC tm;
97fc891e 798 int i;
59ad2c03 799 int fsize[8];
374330e2 800 HDC hdc;
801 int fw_dontcare, fw_bold;
97fc891e 802 int firstchar = ' ';
374330e2 803
59ad2c03 804#ifdef CHECKOEMFONT
97fc891e 805font_messup:
59ad2c03 806#endif
374330e2 807 for (i=0; i<8; i++)
808 fonts[i] = NULL;
809
810 if (cfg.fontisbold) {
811 fw_dontcare = FW_BOLD;
5b80d07f 812 fw_bold = FW_HEAVY;
374330e2 813 } else {
814 fw_dontcare = FW_DONTCARE;
815 fw_bold = FW_BOLD;
816 }
817
97fc891e 818 hdc = GetDC(hwnd);
819
820 font_height = cfg.fontheight;
3b2c664e 821 if (font_height > 0) {
822 font_height = -MulDiv(font_height, GetDeviceCaps(hdc, LOGPIXELSY), 72);
823 }
59ad2c03 824 font_width = pick_width;
97fc891e 825
374330e2 826#define f(i,c,w,u) \
97fc891e 827 fonts[i] = CreateFont (font_height, font_width, 0, 0, w, FALSE, u, FALSE, \
374330e2 828 c, OUT_DEFAULT_PRECIS, \
829 CLIP_DEFAULT_PRECIS, DEFAULT_QUALITY, \
830 FIXED_PITCH | FF_DONTCARE, cfg.font)
97fc891e 831
374330e2 832 if (cfg.vtmode != VT_OEMONLY) {
14963b8f 833 f(FONT_NORMAL, cfg.fontcharset, fw_dontcare, FALSE);
97fc891e 834
835 SelectObject (hdc, fonts[FONT_NORMAL]);
836 GetTextMetrics(hdc, &tm);
837 font_height = tm.tmHeight;
838 font_width = tm.tmAveCharWidth;
839
14963b8f 840 f(FONT_UNDERLINE, cfg.fontcharset, fw_dontcare, TRUE);
97fc891e 841
09798031 842 /*
843 * Some fonts, e.g. 9-pt Courier, draw their underlines
844 * outside their character cell. We successfully prevent
845 * screen corruption by clipping the text output, but then
846 * we lose the underline completely. Here we try to work
847 * out whether this is such a font, and if it is, we set a
848 * flag that causes underlines to be drawn by hand.
849 *
850 * Having tried other more sophisticated approaches (such
851 * as examining the TEXTMETRIC structure or requesting the
852 * height of a string), I think we'll do this the brute
853 * force way: we create a small bitmap, draw an underlined
854 * space on it, and test to see whether any pixels are
855 * foreground-coloured. (Since we expect the underline to
856 * go all the way across the character cell, we only search
857 * down a single column of the bitmap, half way across.)
858 */
859 {
860 HDC und_dc;
861 HBITMAP und_bm, und_oldbm;
862 int i, gotit;
863 COLORREF c;
864
865 und_dc = CreateCompatibleDC(hdc);
866 und_bm = CreateCompatibleBitmap(hdc, font_width, font_height);
867 und_oldbm = SelectObject(und_dc, und_bm);
868 SelectObject(und_dc, fonts[FONT_UNDERLINE]);
869 SetTextAlign(und_dc, TA_TOP | TA_LEFT | TA_NOUPDATECP);
870 SetTextColor (und_dc, RGB(255,255,255));
871 SetBkColor (und_dc, RGB(0,0,0));
872 SetBkMode (und_dc, OPAQUE);
873 ExtTextOut (und_dc, 0, 0, ETO_OPAQUE, NULL, " ", 1, NULL);
874 gotit = FALSE;
875 for (i = 0; i < font_height; i++) {
876 c = GetPixel(und_dc, font_width/2, i);
877 if (c != RGB(0,0,0))
878 gotit = TRUE;
879 }
880 SelectObject(und_dc, und_oldbm);
881 DeleteObject(und_bm);
882 DeleteDC(und_dc);
883 font_needs_hand_underlining = !gotit;
884 }
885
97fc891e 886 if (bold_mode == BOLD_FONT) {
14963b8f 887 f(FONT_BOLD, cfg.fontcharset, fw_bold, FALSE);
888 f(FONT_BOLDUND, cfg.fontcharset, fw_bold, TRUE);
374330e2 889 }
97fc891e 890
891 if (cfg.vtmode == VT_OEMANSI) {
892 f(FONT_OEM, OEM_CHARSET, fw_dontcare, FALSE);
893 f(FONT_OEMUND, OEM_CHARSET, fw_dontcare, TRUE);
894
895 if (bold_mode == BOLD_FONT) {
896 f(FONT_OEMBOLD, OEM_CHARSET, fw_bold, FALSE);
897 f(FONT_OEMBOLDUND, OEM_CHARSET, fw_bold, TRUE);
898 }
899 }
900 }
901 else
902 {
903 f(FONT_OEM, cfg.fontcharset, fw_dontcare, FALSE);
904
905 SelectObject (hdc, fonts[FONT_OEM]);
906 GetTextMetrics(hdc, &tm);
907 font_height = tm.tmHeight;
908 font_width = tm.tmAveCharWidth;
909
910 f(FONT_OEMUND, cfg.fontcharset, fw_dontcare, TRUE);
911
912 if (bold_mode == BOLD_FONT) {
913 f(FONT_BOLD, cfg.fontcharset, fw_bold, FALSE);
914 f(FONT_BOLDUND, cfg.fontcharset, fw_bold, TRUE);
374330e2 915 }
374330e2 916 }
917#undef f
918
97fc891e 919 descent = tm.tmAscent + 1;
920 if (descent >= font_height)
921 descent = font_height - 1;
922 firstchar = tm.tmFirstChar;
374330e2 923
97fc891e 924 for (i=0; i<8; i++) {
925 if (fonts[i]) {
59ad2c03 926 if (SelectObject (hdc, fonts[i]) &&
927 GetTextMetrics(hdc, &tm) )
928 fsize[i] = tm.tmAveCharWidth + 256 * tm.tmHeight;
929 else fsize[i] = -i;
374330e2 930 }
59ad2c03 931 else fsize[i] = -i;
374330e2 932 }
933
934 ReleaseDC (hwnd, hdc);
935
59ad2c03 936 /* ... This is wrong in OEM only mode */
97fc891e 937 if (fsize[FONT_UNDERLINE] != fsize[FONT_NORMAL] ||
374330e2 938 (bold_mode == BOLD_FONT &&
97fc891e 939 fsize[FONT_BOLDUND] != fsize[FONT_BOLD])) {
374330e2 940 und_mode = UND_LINE;
941 DeleteObject (fonts[FONT_UNDERLINE]);
942 if (bold_mode == BOLD_FONT)
943 DeleteObject (fonts[FONT_BOLDUND]);
944 }
945
946 if (bold_mode == BOLD_FONT &&
97fc891e 947 fsize[FONT_BOLD] != fsize[FONT_NORMAL]) {
374330e2 948 bold_mode = BOLD_SHADOW;
949 DeleteObject (fonts[FONT_BOLD]);
950 if (und_mode == UND_FONT)
951 DeleteObject (fonts[FONT_BOLDUND]);
952 }
953
59ad2c03 954#ifdef CHECKOEMFONT
3cfb9f1c 955 /* With the fascist font painting it doesn't matter if the linedraw font
59ad2c03 956 * isn't exactly the right size anymore so we don't have to check this.
957 */
97fc891e 958 if (cfg.vtmode == VT_OEMANSI && fsize[FONT_OEM] != fsize[FONT_NORMAL] ) {
959 if( cfg.fontcharset == OEM_CHARSET )
960 {
961 MessageBox(NULL, "The OEM and ANSI versions of this font are\n"
374330e2 962 "different sizes. Using OEM-only mode instead",
963 "Font Size Mismatch", MB_ICONINFORMATION | MB_OK);
97fc891e 964 cfg.vtmode = VT_OEMONLY;
965 }
966 else if( firstchar < ' ' )
967 {
968 MessageBox(NULL, "The OEM and ANSI versions of this font are\n"
969 "different sizes. Using XTerm mode instead",
970 "Font Size Mismatch", MB_ICONINFORMATION | MB_OK);
971 cfg.vtmode = VT_XWINDOWS;
972 }
973 else
974 {
975 MessageBox(NULL, "The OEM and ANSI versions of this font are\n"
976 "different sizes. Using ISO8859-1 mode instead",
977 "Font Size Mismatch", MB_ICONINFORMATION | MB_OK);
978 cfg.vtmode = VT_POORMAN;
979 }
980
981 for (i=0; i<8; i++)
374330e2 982 if (fonts[i])
983 DeleteObject (fonts[i]);
97fc891e 984 goto font_messup;
374330e2 985 }
59ad2c03 986#endif
374330e2 987}
988
59ad2c03 989void request_resize (int w, int h, int refont) {
990 int width, height;
c9def1b8 991
992 /* If the window is maximized supress resizing attempts */
993 if(IsZoomed(hwnd)) return;
59ad2c03 994
995#ifdef CHECKOEMFONT
996 /* Don't do this in OEMANSI, you may get disable messages */
997 if (refont && w != cols && (cols==80 || cols==132)
998 && cfg.vtmode != VT_OEMANSI)
999#else
1000 if (refont && w != cols && (cols==80 || cols==132))
1001#endif
1002 {
1003 /* If font width too big for screen should we shrink the font more ? */
1004 if (w==132)
1005 font_width = ((font_width*cols+w/2)/w);
1006 else
1007 font_width = 0;
1008 {
1009 int i;
1010 for (i=0; i<8; i++)
1011 if (fonts[i])
1012 DeleteObject(fonts[i]);
1013 }
1014 bold_mode = cfg.bold_colour ? BOLD_COLOURS : BOLD_FONT;
1015 und_mode = UND_FONT;
1016 init_fonts(font_width);
1017 }
c9def1b8 1018 else
1019 {
1020 static int first_time = 1;
1021 static RECT ss;
1022
1023 switch(first_time)
1024 {
1025 case 1:
1026 /* Get the size of the screen */
1027 if (GetClientRect(GetDesktopWindow(),&ss))
1028 /* first_time = 0 */;
1029 else { first_time = 2; break; }
1030 case 0:
1031 /* Make sure the values are sane */
1032 width = (ss.right-ss.left-extra_width ) / font_width;
1033 height = (ss.bottom-ss.top-extra_height ) / font_height;
1034
1035 if (w>width) w=width;
1036 if (h>height) h=height;
1037 if (w<15) w = 15;
1038 if (h<1) w = 1;
1039 }
1040 }
59ad2c03 1041
1042 width = extra_width + font_width * w;
1043 height = extra_height + font_height * h;
374330e2 1044
1045 SetWindowPos (hwnd, NULL, 0, 0, width, height,
1046 SWP_NOACTIVATE | SWP_NOCOPYBITS |
1047 SWP_NOMOVE | SWP_NOZORDER);
1048}
1049
1050static void click (Mouse_Button b, int x, int y) {
fdedf2c8 1051 int thistime = GetMessageTime();
1052
1053 if (lastbtn == b && thistime - lasttime < dbltime) {
374330e2 1054 lastact = (lastact == MA_CLICK ? MA_2CLK :
1055 lastact == MA_2CLK ? MA_3CLK :
1056 lastact == MA_3CLK ? MA_CLICK : MA_NOTHING);
1057 } else {
1058 lastbtn = b;
1059 lastact = MA_CLICK;
1060 }
1061 if (lastact != MA_NOTHING)
1062 term_mouse (b, lastact, x, y);
fdedf2c8 1063 lasttime = thistime;
374330e2 1064}
1065
554c540d 1066static void show_mouseptr(int show) {
1067 static int cursor_visible = 1;
1068 if (!cfg.hide_mouseptr) /* override if this feature disabled */
1069 show = 1;
1070 if (cursor_visible && !show)
1071 ShowCursor(FALSE);
1072 else if (!cursor_visible && show)
1073 ShowCursor(TRUE);
1074 cursor_visible = show;
1075}
1076
996c8c3b 1077static LRESULT CALLBACK WndProc (HWND hwnd, UINT message,
1078 WPARAM wParam, LPARAM lParam) {
374330e2 1079 HDC hdc;
1080 static int ignore_size = FALSE;
1081 static int ignore_clip = FALSE;
1082 static int just_reconfigged = FALSE;
ffc31afe 1083 static int resizing = FALSE;
3ad8c6db 1084 static int need_backend_resize = FALSE;
374330e2 1085
1086 switch (message) {
59ad2c03 1087 case WM_TIMER:
1088 if (pending_netevent)
1089 enact_pending_netevent();
c9def1b8 1090 if (inbuf_head)
59ad2c03 1091 term_out();
7d6ee6ff 1092 noise_regular();
934c0b7a 1093 HideCaret(hwnd);
59ad2c03 1094 term_update();
934c0b7a 1095 ShowCaret(hwnd);
ec55b220 1096 if (cfg.ping_interval > 0)
1097 {
1098 time_t now;
1099 time(&now);
edce8e45 1100 if (now-last_movement > cfg.ping_interval)
ec55b220 1101 {
1102 back->special(TS_PING);
1103 last_movement = now;
1104 }
1105 }
59ad2c03 1106 return 0;
374330e2 1107 case WM_CREATE:
1108 break;
68130d34 1109 case WM_CLOSE:
554c540d 1110 show_mouseptr(1);
d85548fe 1111 if (!cfg.warn_on_close || session_closed ||
9ef49106 1112 MessageBox(hwnd, "Are you sure you want to close this session?",
68130d34 1113 "PuTTY Exit Confirmation",
1114 MB_ICONWARNING | MB_OKCANCEL) == IDOK)
1115 DestroyWindow(hwnd);
1116 return 0;
374330e2 1117 case WM_DESTROY:
554c540d 1118 show_mouseptr(1);
374330e2 1119 PostQuitMessage (0);
1120 return 0;
6833a413 1121 case WM_SYSCOMMAND:
1122 switch (wParam & ~0xF) { /* low 4 bits reserved to Windows */
374330e2 1123 case IDM_SHOWLOG:
c5e9c988 1124 showeventlog(hwnd);
374330e2 1125 break;
1126 case IDM_NEWSESS:
1127 case IDM_DUPSESS:
6833a413 1128 case IDM_SAVEDSESS:
374330e2 1129 {
1130 char b[2048];
1131 char c[30], *cl;
e4e4cc7e 1132 int freecl = FALSE;
374330e2 1133 STARTUPINFO si;
1134 PROCESS_INFORMATION pi;
1135 HANDLE filemap = NULL;
1136
1137 if (wParam == IDM_DUPSESS) {
1138 /*
1139 * Allocate a file-mapping memory chunk for the
1140 * config structure.
1141 */
1142 SECURITY_ATTRIBUTES sa;
1143 Config *p;
1144
1145 sa.nLength = sizeof(sa);
1146 sa.lpSecurityDescriptor = NULL;
1147 sa.bInheritHandle = TRUE;
1148 filemap = CreateFileMapping((HANDLE)0xFFFFFFFF,
1149 &sa,
1150 PAGE_READWRITE,
1151 0,
1152 sizeof(Config),
1153 NULL);
1154 if (filemap) {
1155 p = (Config *)MapViewOfFile(filemap,
1156 FILE_MAP_WRITE,
1157 0, 0, sizeof(Config));
1158 if (p) {
1159 *p = cfg; /* structure copy */
1160 UnmapViewOfFile(p);
1161 }
1162 }
1d470ad2 1163 sprintf(c, "putty &%p", filemap);
374330e2 1164 cl = c;
0a4aa984 1165 } else if (wParam == IDM_SAVEDSESS) {
e4e4cc7e 1166 char *session = sessions[(lParam - IDM_SAVED_MIN) / 16];
dcbde236 1167 cl = smalloc(16 + strlen(session)); /* 8, but play safe */
e4e4cc7e 1168 if (!cl)
1169 cl = NULL; /* not a very important failure mode */
94e6450e 1170 else {
1171 sprintf(cl, "putty @%s", session);
1172 freecl = TRUE;
1173 }
374330e2 1174 } else
6833a413 1175 cl = NULL;
374330e2 1176
1177 GetModuleFileName (NULL, b, sizeof(b)-1);
1178 si.cb = sizeof(si);
1179 si.lpReserved = NULL;
1180 si.lpDesktop = NULL;
1181 si.lpTitle = NULL;
1182 si.dwFlags = 0;
1183 si.cbReserved2 = 0;
1184 si.lpReserved2 = NULL;
1185 CreateProcess (b, cl, NULL, NULL, TRUE,
1186 NORMAL_PRIORITY_CLASS, NULL, NULL, &si, &pi);
1187
1188 if (filemap)
1189 CloseHandle(filemap);
e4e4cc7e 1190 if (freecl)
dcbde236 1191 sfree(cl);
374330e2 1192 }
1193 break;
e95edc00 1194 case IDM_RECONF:
fbc1b6e9 1195 {
1196 int prev_alwaysontop = cfg.alwaysontop;
57d08f2f 1197 int prev_sunken_edge = cfg.sunken_edge;
e1c8e0ed 1198 char oldlogfile[FILENAME_MAX];
1199 int oldlogtype;
3da0b1d2 1200 int need_setwpos = FALSE;
cbc3272b 1201 int old_fwidth, old_fheight;
e1c8e0ed 1202
1203 strcpy(oldlogfile, cfg.logfilename);
1204 oldlogtype = cfg.logtype;
3da0b1d2 1205 cfg.width = cols;
1206 cfg.height = rows;
cbc3272b 1207 old_fwidth = font_width;
1208 old_fheight = font_height;
b65d182b 1209 GetWindowText(hwnd, cfg.wintitle, sizeof(cfg.wintitle));
e1c8e0ed 1210
fbc1b6e9 1211 if (!do_reconfig(hwnd))
1212 break;
e1c8e0ed 1213
1214 if (strcmp(oldlogfile, cfg.logfilename) ||
1215 oldlogtype != cfg.logtype) {
1216 logfclose(); /* reset logging */
1217 logfopen();
1218 }
1219
fbc1b6e9 1220 just_reconfigged = TRUE;
1221 {
1222 int i;
1223 for (i=0; i<8; i++)
1224 if (fonts[i])
1225 DeleteObject(fonts[i]);
1226 }
1227 bold_mode = cfg.bold_colour ? BOLD_COLOURS : BOLD_FONT;
1228 und_mode = UND_FONT;
1229 init_fonts(0);
1230 sfree(logpal);
1231 /*
0965bee0 1232 * Flush the line discipline's edit buffer in the
1233 * case where local editing has just been disabled.
fbc1b6e9 1234 */
0965bee0 1235 ldisc_send(NULL, 0);
fbc1b6e9 1236 if (pal)
1237 DeleteObject(pal);
1238 logpal = NULL;
1239 pal = NULL;
1240 cfgtopalette();
1241 init_palette();
1242
1243 /* Enable or disable the scroll bar, etc */
1244 {
1245 LONG nflg, flag = GetWindowLong(hwnd, GWL_STYLE);
1246 LONG nexflag, exflag = GetWindowLong(hwnd, GWL_EXSTYLE);
1247
1248 nexflag = exflag;
1249 if (cfg.alwaysontop != prev_alwaysontop) {
1250 if (cfg.alwaysontop) {
57d08f2f 1251 nexflag |= WS_EX_TOPMOST;
fbc1b6e9 1252 SetWindowPos(hwnd, HWND_TOPMOST, 0, 0, 0, 0,
1253 SWP_NOMOVE | SWP_NOSIZE);
1254 } else {
57d08f2f 1255 nexflag &= ~(WS_EX_TOPMOST);
fbc1b6e9 1256 SetWindowPos(hwnd, HWND_NOTOPMOST, 0, 0, 0, 0,
1257 SWP_NOMOVE | SWP_NOSIZE);
1258 }
1259 }
57d08f2f 1260 if (cfg.sunken_edge)
1261 nexflag |= WS_EX_CLIENTEDGE;
1262 else
1263 nexflag &= ~(WS_EX_CLIENTEDGE);
fbc1b6e9 1264
1265 nflg = flag;
1266 if (cfg.scrollbar) nflg |= WS_VSCROLL;
1267 else nflg &= ~WS_VSCROLL;
1268 if (cfg.locksize)
1269 nflg &= ~(WS_THICKFRAME|WS_MAXIMIZEBOX);
1270 else
1271 nflg |= (WS_THICKFRAME|WS_MAXIMIZEBOX);
1272
1273 if (nflg != flag || nexflag != exflag)
1274 {
1275 RECT cr, wr;
1276
1277 if (nflg != flag)
1278 SetWindowLong(hwnd, GWL_STYLE, nflg);
1279 if (nexflag != exflag)
1280 SetWindowLong(hwnd, GWL_EXSTYLE, nexflag);
1281
1282 SendMessage (hwnd, WM_IGNORE_SIZE, 0, 0);
3da0b1d2 1283
fbc1b6e9 1284 SetWindowPos(hwnd, NULL, 0,0,0,0,
1285 SWP_NOACTIVATE|SWP_NOCOPYBITS|
1286 SWP_NOMOVE|SWP_NOSIZE|SWP_NOZORDER|
1287 SWP_FRAMECHANGED);
1288
1289 GetWindowRect (hwnd, &wr);
1290 GetClientRect (hwnd, &cr);
1291 extra_width = wr.right - wr.left - cr.right + cr.left;
1292 extra_height = wr.bottom - wr.top - cr.bottom + cr.top;
1293 }
e95edc00 1294 }
c9def1b8 1295
3da0b1d2 1296 if (cfg.height != rows ||
1297 cfg.width != cols ||
cbc3272b 1298 old_fwidth != font_width ||
1299 old_fheight != font_height ||
57d08f2f 1300 cfg.savelines != savelines ||
1301 cfg.sunken_edge != prev_sunken_edge)
3da0b1d2 1302 need_setwpos = TRUE;
fbc1b6e9 1303 term_size(cfg.height, cfg.width, cfg.savelines);
1304 InvalidateRect(hwnd, NULL, TRUE);
3da0b1d2 1305 if (need_setwpos) {
1306 force_normal(hwnd);
1307 SetWindowPos (hwnd, NULL, 0, 0,
1308 extra_width + font_width * cfg.width,
1309 extra_height + font_height * cfg.height,
1310 SWP_NOACTIVATE | SWP_NOCOPYBITS |
1311 SWP_NOMOVE | SWP_NOZORDER);
1312 }
b65d182b 1313 set_title(cfg.wintitle);
fbc1b6e9 1314 if (IsIconic(hwnd)) {
1315 SetWindowText (hwnd,
1316 cfg.win_name_always ? window_name : icon_name);
1317 }
1318 }
e95edc00 1319 break;
bc1235d4 1320 case IDM_COPYALL:
1321 term_copyall();
1322 break;
fbc1b6e9 1323 case IDM_CLRSB:
1324 term_clrsb();
1325 break;
1326 case IDM_RESET:
1327 term_pwron();
1328 break;
1329 case IDM_TEL_AYT: back->special (TS_AYT); break;
374330e2 1330 case IDM_TEL_BRK: back->special (TS_BRK); break;
1331 case IDM_TEL_SYNCH: back->special (TS_SYNCH); break;
1332 case IDM_TEL_EC: back->special (TS_EC); break;
1333 case IDM_TEL_EL: back->special (TS_EL); break;
1334 case IDM_TEL_GA: back->special (TS_GA); break;
1335 case IDM_TEL_NOP: back->special (TS_NOP); break;
1336 case IDM_TEL_ABORT: back->special (TS_ABORT); break;
1337 case IDM_TEL_AO: back->special (TS_AO); break;
1338 case IDM_TEL_IP: back->special (TS_IP); break;
1339 case IDM_TEL_SUSP: back->special (TS_SUSP); break;
1340 case IDM_TEL_EOR: back->special (TS_EOR); break;
1341 case IDM_TEL_EOF: back->special (TS_EOF); break;
1342 case IDM_ABOUT:
1343 showabout (hwnd);
1344 break;
0a4aa984 1345 default:
1346 if (wParam >= IDM_SAVED_MIN && wParam <= IDM_SAVED_MAX) {
1347 SendMessage(hwnd, WM_SYSCOMMAND, IDM_SAVEDSESS, wParam);
1348 }
374330e2 1349 }
1350 break;
37508af4 1351
1352#define X_POS(l) ((int)(short)LOWORD(l))
1353#define Y_POS(l) ((int)(short)HIWORD(l))
1354
fdedf2c8 1355#define TO_CHR_X(x) (((x)<0 ? (x)-font_width+1 : (x)) / font_width)
1356#define TO_CHR_Y(y) (((y)<0 ? (y)-font_height+1: (y)) / font_height)
1357
374330e2 1358 case WM_LBUTTONDOWN:
554c540d 1359 show_mouseptr(1);
fdedf2c8 1360 click (MB_SELECT, TO_CHR_X(X_POS(lParam)),
1361 TO_CHR_Y(Y_POS(lParam)));
fef97f43 1362 SetCapture(hwnd);
374330e2 1363 return 0;
1364 case WM_LBUTTONUP:
554c540d 1365 show_mouseptr(1);
fdedf2c8 1366 term_mouse (MB_SELECT, MA_RELEASE, TO_CHR_X(X_POS(lParam)),
1367 TO_CHR_Y(Y_POS(lParam)));
37508af4 1368 ReleaseCapture();
374330e2 1369 return 0;
1370 case WM_MBUTTONDOWN:
554c540d 1371 show_mouseptr(1);
37508af4 1372 SetCapture(hwnd);
374330e2 1373 click (cfg.mouse_is_xterm ? MB_PASTE : MB_EXTEND,
fdedf2c8 1374 TO_CHR_X(X_POS(lParam)),
1375 TO_CHR_Y(Y_POS(lParam)));
374330e2 1376 return 0;
1377 case WM_MBUTTONUP:
554c540d 1378 show_mouseptr(1);
374330e2 1379 term_mouse (cfg.mouse_is_xterm ? MB_PASTE : MB_EXTEND,
fdedf2c8 1380 MA_RELEASE, TO_CHR_X(X_POS(lParam)),
1381 TO_CHR_Y(Y_POS(lParam)));
37508af4 1382 ReleaseCapture();
a0b1cefc 1383 return 0;
374330e2 1384 case WM_RBUTTONDOWN:
554c540d 1385 show_mouseptr(1);
37508af4 1386 SetCapture(hwnd);
374330e2 1387 click (cfg.mouse_is_xterm ? MB_EXTEND : MB_PASTE,
fdedf2c8 1388 TO_CHR_X(X_POS(lParam)),
1389 TO_CHR_Y(Y_POS(lParam)));
374330e2 1390 return 0;
1391 case WM_RBUTTONUP:
554c540d 1392 show_mouseptr(1);
374330e2 1393 term_mouse (cfg.mouse_is_xterm ? MB_EXTEND : MB_PASTE,
fdedf2c8 1394 MA_RELEASE, TO_CHR_X(X_POS(lParam)),
1395 TO_CHR_Y(Y_POS(lParam)));
37508af4 1396 ReleaseCapture();
374330e2 1397 return 0;
1398 case WM_MOUSEMOVE:
554c540d 1399 show_mouseptr(1);
374330e2 1400 /*
1401 * Add the mouse position and message time to the random
7d6ee6ff 1402 * number noise.
374330e2 1403 */
7d6ee6ff 1404 noise_ultralight(lParam);
374330e2 1405
1406 if (wParam & (MK_LBUTTON | MK_MBUTTON | MK_RBUTTON)) {
1407 Mouse_Button b;
1408 if (wParam & MK_LBUTTON)
1409 b = MB_SELECT;
1410 else if (wParam & MK_MBUTTON)
1411 b = cfg.mouse_is_xterm ? MB_PASTE : MB_EXTEND;
1412 else
1413 b = cfg.mouse_is_xterm ? MB_EXTEND : MB_PASTE;
fdedf2c8 1414 term_mouse (b, MA_DRAG, TO_CHR_X(X_POS(lParam)),
1415 TO_CHR_Y(Y_POS(lParam)));
374330e2 1416 }
374330e2 1417 return 0;
d318ef8e 1418 case WM_NCMOUSEMOVE:
1419 show_mouseptr(1);
1420 noise_ultralight(lParam);
1421 return 0;
374330e2 1422 case WM_IGNORE_CLIP:
1423 ignore_clip = wParam; /* don't panic on DESTROYCLIPBOARD */
1424 break;
1425 case WM_DESTROYCLIPBOARD:
1426 if (!ignore_clip)
1427 term_deselect();
1428 ignore_clip = FALSE;
1429 return 0;
1430 case WM_PAINT:
1431 {
1432 PAINTSTRUCT p;
934c0b7a 1433 HideCaret(hwnd);
374330e2 1434 hdc = BeginPaint (hwnd, &p);
1435 if (pal) {
1436 SelectPalette (hdc, pal, TRUE);
1437 RealizePalette (hdc);
1438 }
1439 term_paint (hdc, p.rcPaint.left, p.rcPaint.top,
1440 p.rcPaint.right, p.rcPaint.bottom);
1441 SelectObject (hdc, GetStockObject(SYSTEM_FONT));
1442 SelectObject (hdc, GetStockObject(WHITE_PEN));
1443 EndPaint (hwnd, &p);
934c0b7a 1444 ShowCaret(hwnd);
374330e2 1445 }
1446 return 0;
1447 case WM_NETEVENT:
59ad2c03 1448 /* Notice we can get multiple netevents, FD_READ, FD_WRITE etc
1449 * but the only one that's likely to try to overload us is FD_READ.
1450 * This means buffering just one is fine.
1451 */
1452 if (pending_netevent)
1453 enact_pending_netevent();
1454
1455 pending_netevent = TRUE;
1456 pend_netevent_wParam=wParam;
1457 pend_netevent_lParam=lParam;
ec55b220 1458 time(&last_movement);
374330e2 1459 return 0;
1460 case WM_SETFOCUS:
1461 has_focus = TRUE;
5b7ce734 1462 CreateCaret(hwnd, caretbm, font_width, font_height);
934c0b7a 1463 ShowCaret(hwnd);
03f23ad6 1464 compose_state = 0;
374330e2 1465 term_out();
1466 term_update();
1467 break;
1468 case WM_KILLFOCUS:
554c540d 1469 show_mouseptr(1);
374330e2 1470 has_focus = FALSE;
ec8679e9 1471 DestroyCaret();
374330e2 1472 term_out();
1473 term_update();
1474 break;
1475 case WM_IGNORE_SIZE:
1476 ignore_size = TRUE; /* don't panic on next WM_SIZE msg */
1477 break;
73251d5d 1478 case WM_ENTERSIZEMOVE:
996c8c3b 1479 EnableSizeTip(1);
ffc31afe 1480 resizing = TRUE;
3ad8c6db 1481 need_backend_resize = FALSE;
996c8c3b 1482 break;
73251d5d 1483 case WM_EXITSIZEMOVE:
996c8c3b 1484 EnableSizeTip(0);
ffc31afe 1485 resizing = FALSE;
3ad8c6db 1486 if (need_backend_resize)
1487 back->size();
996c8c3b 1488 break;
374330e2 1489 case WM_SIZING:
1490 {
1491 int width, height, w, h, ew, eh;
1492 LPRECT r = (LPRECT)lParam;
1493
1494 width = r->right - r->left - extra_width;
1495 height = r->bottom - r->top - extra_height;
1496 w = (width + font_width/2) / font_width; if (w < 1) w = 1;
1497 h = (height + font_height/2) / font_height; if (h < 1) h = 1;
996c8c3b 1498 UpdateSizeTip(hwnd, w, h);
374330e2 1499 ew = width - w * font_width;
1500 eh = height - h * font_height;
1501 if (ew != 0) {
1502 if (wParam == WMSZ_LEFT ||
1503 wParam == WMSZ_BOTTOMLEFT ||
1504 wParam == WMSZ_TOPLEFT)
1505 r->left += ew;
1506 else
1507 r->right -= ew;
1508 }
1509 if (eh != 0) {
1510 if (wParam == WMSZ_TOP ||
1511 wParam == WMSZ_TOPRIGHT ||
1512 wParam == WMSZ_TOPLEFT)
1513 r->top += eh;
1514 else
1515 r->bottom -= eh;
1516 }
1517 if (ew || eh)
1518 return 1;
1519 else
1520 return 0;
1521 }
996c8c3b 1522 /* break; (never reached) */
374330e2 1523 case WM_SIZE:
1524 if (wParam == SIZE_MINIMIZED) {
1525 SetWindowText (hwnd,
1526 cfg.win_name_always ? window_name : icon_name);
1527 break;
1528 }
1529 if (wParam == SIZE_RESTORED || wParam == SIZE_MAXIMIZED)
1530 SetWindowText (hwnd, window_name);
1531 if (!ignore_size) {
1a6f78fe 1532 int width, height, w, h;
1533#if 0 /* we have fixed this using WM_SIZING now */
1534 int ew, eh;
1535#endif
374330e2 1536
1537 width = LOWORD(lParam);
1538 height = HIWORD(lParam);
1539 w = width / font_width; if (w < 1) w = 1;
1540 h = height / font_height; if (h < 1) h = 1;
1541#if 0 /* we have fixed this using WM_SIZING now */
1542 ew = width - w * font_width;
1543 eh = height - h * font_height;
1544 if (ew != 0 || eh != 0) {
1545 RECT r;
1546 GetWindowRect (hwnd, &r);
1547 SendMessage (hwnd, WM_IGNORE_SIZE, 0, 0);
1548 SetWindowPos (hwnd, NULL, 0, 0,
1549 r.right - r.left - ew, r.bottom - r.top - eh,
1550 SWP_NOACTIVATE | SWP_NOMOVE | SWP_NOZORDER);
1551 }
1552#endif
1553 if (w != cols || h != rows || just_reconfigged) {
1554 term_invalidate();
1555 term_size (h, w, cfg.savelines);
ffc31afe 1556 /*
1557 * Don't call back->size in mid-resize. (To prevent
1558 * massive numbers of resize events getting sent
1559 * down the connection during an NT opaque drag.)
1560 */
1561 if (!resizing)
1562 back->size();
3ad8c6db 1563 else
1564 need_backend_resize = TRUE;
374330e2 1565 just_reconfigged = FALSE;
1566 }
1567 }
1568 ignore_size = FALSE;
1569 return 0;
1570 case WM_VSCROLL:
1571 switch (LOWORD(wParam)) {
1572 case SB_BOTTOM: term_scroll(-1, 0); break;
1573 case SB_TOP: term_scroll(+1, 0); break;
1574 case SB_LINEDOWN: term_scroll (0, +1); break;
1575 case SB_LINEUP: term_scroll (0, -1); break;
1576 case SB_PAGEDOWN: term_scroll (0, +rows/2); break;
1577 case SB_PAGEUP: term_scroll (0, -rows/2); break;
1578 case SB_THUMBPOSITION: case SB_THUMBTRACK:
1579 term_scroll (1, HIWORD(wParam)); break;
1580 }
1581 break;
1582 case WM_PALETTECHANGED:
1583 if ((HWND) wParam != hwnd && pal != NULL) {
1584 HDC hdc = get_ctx();
1585 if (hdc) {
1586 if (RealizePalette (hdc) > 0)
1587 UpdateColors (hdc);
1588 free_ctx (hdc);
1589 }
1590 }
1591 break;
1592 case WM_QUERYNEWPALETTE:
1593 if (pal != NULL) {
1594 HDC hdc = get_ctx();
1595 if (hdc) {
1596 if (RealizePalette (hdc) > 0)
1597 UpdateColors (hdc);
1598 free_ctx (hdc);
1599 return TRUE;
1600 }
1601 }
1602 return FALSE;
1603 case WM_KEYDOWN:
1604 case WM_SYSKEYDOWN:
c9def1b8 1605 case WM_KEYUP:
1606 case WM_SYSKEYUP:
374330e2 1607 /*
1608 * Add the scan code and keypress timing to the random
7d6ee6ff 1609 * number noise.
374330e2 1610 */
7d6ee6ff 1611 noise_ultralight(lParam);
374330e2 1612
1613 /*
1614 * We don't do TranslateMessage since it disassociates the
1615 * resulting CHAR message from the KEYDOWN that sparked it,
1616 * which we occasionally don't want. Instead, we process
1617 * KEYDOWN, and call the Win32 translator functions so that
1618 * we get the translations under _our_ control.
1619 */
1620 {
1621 unsigned char buf[20];
1622 int len;
1623
3cf144db 1624 if (wParam==VK_PROCESSKEY) {
1625 MSG m;
1626 m.hwnd = hwnd;
1627 m.message = WM_KEYDOWN;
1628 m.wParam = wParam;
1629 m.lParam = lParam & 0xdfff;
1630 TranslateMessage(&m);
1631 } else {
1632 len = TranslateKey (message, wParam, lParam, buf);
1633 if (len == -1)
1634 return DefWindowProc (hwnd, message, wParam, lParam);
0965bee0 1635 ldisc_send (buf, len);
554c540d 1636
1637 if (len > 0)
1638 show_mouseptr(0);
3cf144db 1639 }
374330e2 1640 }
1641 return 0;
3cf144db 1642 case WM_IME_CHAR:
1643 {
1644 unsigned char buf[2];
1645
1646 buf[1] = wParam;
1647 buf[0] = wParam >> 8;
0965bee0 1648 ldisc_send (buf, 2);
3cf144db 1649 }
374330e2 1650 case WM_CHAR:
1651 case WM_SYSCHAR:
1652 /*
1653 * Nevertheless, we are prepared to deal with WM_CHAR
1654 * messages, should they crop up. So if someone wants to
1655 * post the things to us as part of a macro manoeuvre,
1656 * we're ready to cope.
1657 */
1658 {
14963b8f 1659 char c = xlat_kbd2tty((unsigned char)wParam);
0965bee0 1660 ldisc_send (&c, 1);
374330e2 1661 }
1662 return 0;
1663 }
1664
1665 return DefWindowProc (hwnd, message, wParam, lParam);
1666}
1667
1668/*
ec8679e9 1669 * Move the system caret. (We maintain one, even though it's
1670 * invisible, for the benefit of blind people: apparently some
1671 * helper software tracks the system caret, so we should arrange to
1672 * have one.)
1673 */
1674void sys_cursor(int x, int y) {
a21ea6e7 1675 if (has_focus)
1676 SetCaretPos(x * font_width, y * font_height);
ec8679e9 1677}
1678
1679/*
374330e2 1680 * Draw a line of text in the window, at given character
1681 * coordinates, in given attributes.
1682 *
1683 * We are allowed to fiddle with the contents of `text'.
1684 */
1685void do_text (Context ctx, int x, int y, char *text, int len,
c9def1b8 1686 unsigned long attr, int lattr) {
374330e2 1687 COLORREF fg, bg, t;
1688 int nfg, nbg, nfont;
1689 HDC hdc = ctx;
59ad2c03 1690 RECT line_box;
1691 int force_manual_underline = 0;
c9def1b8 1692 int fnt_width = font_width*(1+(lattr!=LATTR_NORM));
09798031 1693 static int *IpDx = 0, IpDxLEN = 0;;
59ad2c03 1694
c9def1b8 1695 if (len>IpDxLEN || IpDx[0] != fnt_width) {
59ad2c03 1696 int i;
1697 if (len>IpDxLEN) {
1698 sfree(IpDx);
1699 IpDx = smalloc((len+16)*sizeof(int));
1700 IpDxLEN = (len+16);
1701 }
c9def1b8 1702 for(i=0; i<IpDxLEN; i++)
1703 IpDx[i] = fnt_width;
59ad2c03 1704 }
374330e2 1705
c9def1b8 1706 x *= fnt_width;
374330e2 1707 y *= font_height;
1708
4e30ff69 1709 if ((attr & ATTR_ACTCURS) && cfg.cursor_type == 0) {
c9def1b8 1710 attr &= (bold_mode == BOLD_COLOURS ? 0x300200 : 0x300300);
374330e2 1711 attr ^= ATTR_CUR_XOR;
1712 }
1713
1714 nfont = 0;
1715 if (cfg.vtmode == VT_OEMONLY)
1716 nfont |= FONT_OEM;
1717
1718 /*
1719 * Map high-half characters in order to approximate ISO using
59ad2c03 1720 * OEM character set. No characters are missing if the OEM codepage
1721 * is CP850.
374330e2 1722 */
1723 if (nfont & FONT_OEM) {
1724 int i;
1725 for (i=0; i<len; i++)
1726 if (text[i] >= '\xA0' && text[i] <= '\xFF') {
59ad2c03 1727#if 0
1728 /* This is CP850 ... perfect translation */
374330e2 1729 static const char oemhighhalf[] =
1730 "\x20\xAD\xBD\x9C\xCF\xBE\xDD\xF5" /* A0-A7 */
1731 "\xF9\xB8\xA6\xAE\xAA\xF0\xA9\xEE" /* A8-AF */
1732 "\xF8\xF1\xFD\xFC\xEF\xE6\xF4\xFA" /* B0-B7 */
1733 "\xF7\xFB\xA7\xAF\xAC\xAB\xF3\xA8" /* B8-BF */
59ad2c03 1734 "\xB7\xB5\xB6\xC7\x8E\x8F\x92\x80" /* C0-C7 */
1735 "\xD4\x90\xD2\xD3\xDE\xD6\xD7\xD8" /* C8-CF */
374330e2 1736 "\xD1\xA5\xE3\xE0\xE2\xE5\x99\x9E" /* D0-D7 */
1737 "\x9D\xEB\xE9\xEA\x9A\xED\xE8\xE1" /* D8-DF */
1738 "\x85\xA0\x83\xC6\x84\x86\x91\x87" /* E0-E7 */
1739 "\x8A\x82\x88\x89\x8D\xA1\x8C\x8B" /* E8-EF */
1740 "\xD0\xA4\x95\xA2\x93\xE4\x94\xF6" /* F0-F7 */
1741 "\x9B\x97\xA3\x96\x81\xEC\xE7\x98" /* F8-FF */
1742 ;
59ad2c03 1743#endif
1744 /* This is CP437 ... junk translation */
1745 static const unsigned char oemhighhalf[] = {
5350aeb9 1746 0x20, 0xad, 0x9b, 0x9c, 0x6f, 0x9d, 0x7c, 0x15,
59ad2c03 1747 0x22, 0x43, 0xa6, 0xae, 0xaa, 0x2d, 0x52, 0xc4,
1748 0xf8, 0xf1, 0xfd, 0x33, 0x27, 0xe6, 0x14, 0xfa,
1749 0x2c, 0x31, 0xa7, 0xaf, 0xac, 0xab, 0x2f, 0xa8,
1750 0x41, 0x41, 0x41, 0x41, 0x8e, 0x8f, 0x92, 0x80,
1751 0x45, 0x90, 0x45, 0x45, 0x49, 0x49, 0x49, 0x49,
1752 0x44, 0xa5, 0x4f, 0x4f, 0x4f, 0x4f, 0x99, 0x78,
1753 0xed, 0x55, 0x55, 0x55, 0x9a, 0x59, 0x50, 0xe1,
1754 0x85, 0xa0, 0x83, 0x61, 0x84, 0x86, 0x91, 0x87,
1755 0x8a, 0x82, 0x88, 0x89, 0x8d, 0xa1, 0x8c, 0x8b,
1756 0x0b, 0xa4, 0x95, 0xa2, 0x93, 0x6f, 0x94, 0xf6,
1757 0xed, 0x97, 0xa3, 0x96, 0x81, 0x79, 0x70, 0x98
1758 };
1759
374330e2 1760 text[i] = oemhighhalf[(unsigned char)text[i] - 0xA0];
1761 }
1762 }
1763
ec55b220 1764 if (attr & ATTR_LINEDRW) {
374330e2 1765 int i;
59ad2c03 1766 /* ISO 8859-1 */
374330e2 1767 static const char poorman[] =
1768 "*#****\xB0\xB1**+++++-----++++|****\xA3\xB7";
59ad2c03 1769
1770 /* CP437 */
1771 static const char oemmap_437[] =
ed91c385 1772 "\x04\xB1****\xF8\xF1**\xD9\xBF\xDA\xC0\xC5"
1773 "\xC4\xC4\xC4\xC4\xC4\xC3\xB4\xC1\xC2\xB3\xF3\xF2\xE3*\x9C\xFA";
374330e2 1774
59ad2c03 1775 /* CP850 */
1776 static const char oemmap_850[] =
1777 "\x04\xB1****\xF8\xF1**\xD9\xBF\xDA\xC0\xC5"
1778 "\xC4\xC4\xC4\xC4\xC4\xC3\xB4\xC1\xC2\xB3****\x9C\xFA";
1779
1780 /* Poor windows font ... eg: windows courier */
1781 static const char oemmap[] =
1782 "*\xB1****\xF8\xF1**\xD9\xBF\xDA\xC0\xC5"
1783 "\xC4\xC4\xC4\xC4\xC4\xC3\xB4\xC1\xC2\xB3****\x9C\xFA";
1784
374330e2 1785 /*
1786 * Line drawing mapping: map ` thru ~ (0x60 thru 0x7E) to
1787 * VT100 line drawing chars; everything else stays normal.
ec55b220 1788 *
1789 * Actually '_' maps to space too, but that's done before.
374330e2 1790 */
1791 switch (cfg.vtmode) {
1792 case VT_XWINDOWS:
1793 for (i=0; i<len; i++)
1794 if (text[i] >= '\x60' && text[i] <= '\x7E')
1795 text[i] += '\x01' - '\x60';
1796 break;
1797 case VT_OEMANSI:
59ad2c03 1798 /* Make sure we actually have an OEM font */
1799 if (fonts[nfont|FONT_OEM]) {
374330e2 1800 case VT_OEMONLY:
59ad2c03 1801 nfont |= FONT_OEM;
1802 for (i=0; i<len; i++)
1803 if (text[i] >= '\x60' && text[i] <= '\x7E')
1804 text[i] = oemmap[(unsigned char)text[i] - 0x60];
1805 break;
1806 }
374330e2 1807 case VT_POORMAN:
1808 for (i=0; i<len; i++)
1809 if (text[i] >= '\x60' && text[i] <= '\x7E')
1810 text[i] = poorman[(unsigned char)text[i] - 0x60];
1811 break;
1812 }
1813 }
1814
1815 nfg = 2 * ((attr & ATTR_FGMASK) >> ATTR_FGSHIFT);
1816 nbg = 2 * ((attr & ATTR_BGMASK) >> ATTR_BGSHIFT);
1817 if (bold_mode == BOLD_FONT && (attr & ATTR_BOLD))
1818 nfont |= FONT_BOLD;
1819 if (und_mode == UND_FONT && (attr & ATTR_UNDER))
1820 nfont |= FONT_UNDERLINE;
59ad2c03 1821 if (!fonts[nfont])
1822 {
1823 if (nfont&FONT_UNDERLINE)
1824 force_manual_underline = 1;
1825 /* Don't do the same for manual bold, it could be bad news. */
1826
1827 nfont &= ~(FONT_BOLD|FONT_UNDERLINE);
1828 }
09798031 1829 if (font_needs_hand_underlining && (attr & ATTR_UNDER))
1830 force_manual_underline = 1;
374330e2 1831 if (attr & ATTR_REVERSE) {
1832 t = nfg; nfg = nbg; nbg = t;
1833 }
1834 if (bold_mode == BOLD_COLOURS && (attr & ATTR_BOLD))
1835 nfg++;
59ad2c03 1836 if (bold_mode == BOLD_COLOURS && (attr & ATTR_BLINK))
1837 nbg++;
374330e2 1838 fg = colours[nfg];
1839 bg = colours[nbg];
1840 SelectObject (hdc, fonts[nfont]);
1841 SetTextColor (hdc, fg);
1842 SetBkColor (hdc, bg);
1843 SetBkMode (hdc, OPAQUE);
59ad2c03 1844 line_box.left = x;
1845 line_box.top = y;
c9def1b8 1846 line_box.right = x+fnt_width*len;
59ad2c03 1847 line_box.bottom = y+font_height;
1848 ExtTextOut (hdc, x, y, ETO_CLIPPED|ETO_OPAQUE, &line_box, text, len, IpDx);
374330e2 1849 if (bold_mode == BOLD_SHADOW && (attr & ATTR_BOLD)) {
1850 SetBkMode (hdc, TRANSPARENT);
59ad2c03 1851
1852 /* GRR: This draws the character outside it's box and can leave
1853 * 'droppings' even with the clip box! I suppose I could loop it
c9def1b8 1854 * one character at a time ... yuk.
1855 *
1856 * Or ... I could do a test print with "W", and use +1 or -1 for this
1857 * shift depending on if the leftmost column is blank...
1858 */
59ad2c03 1859 ExtTextOut (hdc, x-1, y, ETO_CLIPPED, &line_box, text, len, IpDx);
374330e2 1860 }
59ad2c03 1861 if (force_manual_underline ||
1862 (und_mode == UND_LINE && (attr & ATTR_UNDER))) {
1a6f78fe 1863 HPEN oldpen;
1864 oldpen = SelectObject (hdc, CreatePen(PS_SOLID, 0, fg));
374330e2 1865 MoveToEx (hdc, x, y+descent, NULL);
c9def1b8 1866 LineTo (hdc, x+len*fnt_width, y+descent);
1a6f78fe 1867 oldpen = SelectObject (hdc, oldpen);
1868 DeleteObject (oldpen);
374330e2 1869 }
2d3411e9 1870 if ((attr & ATTR_PASCURS) && cfg.cursor_type == 0) {
374330e2 1871 POINT pts[5];
1a6f78fe 1872 HPEN oldpen;
374330e2 1873 pts[0].x = pts[1].x = pts[4].x = x;
c9def1b8 1874 pts[2].x = pts[3].x = x+fnt_width-1;
374330e2 1875 pts[0].y = pts[3].y = pts[4].y = y;
1876 pts[1].y = pts[2].y = y+font_height-1;
1a6f78fe 1877 oldpen = SelectObject (hdc, CreatePen(PS_SOLID, 0, colours[23]));
374330e2 1878 Polyline (hdc, pts, 5);
1a6f78fe 1879 oldpen = SelectObject (hdc, oldpen);
1880 DeleteObject (oldpen);
374330e2 1881 }
4e30ff69 1882 if ((attr & (ATTR_ACTCURS | ATTR_PASCURS)) && cfg.cursor_type != 0) {
2d3411e9 1883 int startx, starty, dx, dy, length, i;
4e30ff69 1884 if (cfg.cursor_type == 1) {
2d3411e9 1885 startx = x; starty = y+descent;
1886 dx = 1; dy = 0; length = fnt_width;
1887 } else {
4e30ff69 1888 int xadjust = 0;
1889 if (attr & ATTR_RIGHTCURS)
1890 xadjust = fnt_width-1;
2d3411e9 1891 startx = x+xadjust; starty = y;
1892 dx = 0; dy = 1; length = font_height;
4e30ff69 1893 }
2d3411e9 1894 if (attr & ATTR_ACTCURS) {
1895 HPEN oldpen;
1896 oldpen = SelectObject (hdc, CreatePen(PS_SOLID, 0, colours[23]));
1897 MoveToEx (hdc, startx, starty, NULL);
1898 LineTo (hdc, startx+dx*length, starty+dy*length);
1899 oldpen = SelectObject (hdc, oldpen);
1900 DeleteObject (oldpen);
1901 } else {
1902 for (i = 0; i < length; i++) {
1903 if (i % 2 == 0) {
1904 SetPixel(hdc, startx, starty, colours[23]);
1905 }
1906 startx += dx; starty += dy;
1907 }
1908 }
4e30ff69 1909 }
374330e2 1910}
1911
c9def1b8 1912static int check_compose(int first, int second) {
1913
1914 static char * composetbl[] = {
1915