Debugging improvements. Started using Dave Hinton's dmemdump
[u/mdw/putty] / window.c
Content-type: text/html git.distorted.org.uk Git - u/mdw/putty/blame - window.c


500 - Internal Server Error

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