Robert de Bath's Big Patch, part 1
[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 3411.
CommitLineData
374330e2 1#include <windows.h>
2#include <commctrl.h>
3#include <winsock.h>
4#include <stdio.h>
5#include <stdlib.h>
1d470ad2 6#include <ctype.h>
374330e2 7
8#define PUTTY_DO_GLOBALS /* actually _define_ globals */
9#include "putty.h"
10#include "win_res.h"
11
6833a413 12#define IDM_SHOWLOG 0x0010
13#define IDM_NEWSESS 0x0020
14#define IDM_DUPSESS 0x0030
15#define IDM_RECONF 0x0040
16#define IDM_CLRSB 0x0050
17#define IDM_RESET 0x0060
18#define IDM_TEL_AYT 0x0070
19#define IDM_TEL_BRK 0x0080
20#define IDM_TEL_SYNCH 0x0090
21#define IDM_TEL_EC 0x00a0
22#define IDM_TEL_EL 0x00b0
23#define IDM_TEL_GA 0x00c0
24#define IDM_TEL_NOP 0x00d0
25#define IDM_TEL_ABORT 0x00e0
26#define IDM_TEL_AO 0x00f0
27#define IDM_TEL_IP 0x0100
28#define IDM_TEL_SUSP 0x0110
29#define IDM_TEL_EOR 0x0120
30#define IDM_TEL_EOF 0x0130
31#define IDM_ABOUT 0x0140
32#define IDM_SAVEDSESS 0x0150
33
34#define IDM_SAVED_MIN 0x1000
35#define IDM_SAVED_MAX 0x2000
374330e2 36
59ad2c03 37#define WM_IGNORE_SIZE (WM_XUSER + 1)
38#define WM_IGNORE_CLIP (WM_XUSER + 2)
374330e2 39
996c8c3b 40static LRESULT CALLBACK WndProc (HWND, UINT, WPARAM, LPARAM);
c9def1b8 41static int TranslateKey(UINT message, WPARAM wParam, LPARAM lParam, unsigned char *output);
374330e2 42static void cfgtopalette(void);
43static void init_palette(void);
59ad2c03 44static void init_fonts(int);
374330e2 45
46static int extra_width, extra_height;
47
59ad2c03 48static int pending_netevent = 0;
49static WPARAM pend_netevent_wParam = 0;
50static LPARAM pend_netevent_lParam = 0;
51static void enact_pending_netevent(void);
52
374330e2 53#define FONT_NORMAL 0
54#define FONT_BOLD 1
55#define FONT_UNDERLINE 2
56#define FONT_BOLDUND 3
57#define FONT_OEM 4
58#define FONT_OEMBOLD 5
59#define FONT_OEMBOLDUND 6
60#define FONT_OEMUND 7
61static HFONT fonts[8];
62static enum {
63 BOLD_COLOURS, BOLD_SHADOW, BOLD_FONT
64} bold_mode;
65static enum {
66 UND_LINE, UND_FONT
67} und_mode;
68static int descent;
69
70#define NCOLOURS 24
71static COLORREF colours[NCOLOURS];
72static HPALETTE pal;
73static LPLOGPALETTE logpal;
74static RGBTRIPLE defpal[NCOLOURS];
75
76static HWND hwnd;
77
78static int dbltime, lasttime, lastact;
79static Mouse_Button lastbtn;
80
81static char *window_name, *icon_name;
82
83int WINAPI WinMain(HINSTANCE inst, HINSTANCE prev, LPSTR cmdline, int show) {
84 static char appname[] = "PuTTY";
85 WORD winsock_ver;
86 WSADATA wsadata;
87 WNDCLASS wndclass;
88 MSG msg;
89 int guess_width, guess_height;
90
73251d5d 91 putty_inst = inst;
92
374330e2 93 winsock_ver = MAKEWORD(1, 1);
94 if (WSAStartup(winsock_ver, &wsadata)) {
95 MessageBox(NULL, "Unable to initialise WinSock", "WinSock Error",
96 MB_OK | MB_ICONEXCLAMATION);
97 return 1;
98 }
99 if (LOBYTE(wsadata.wVersion) != 1 || HIBYTE(wsadata.wVersion) != 1) {
100 MessageBox(NULL, "WinSock version is incompatible with 1.1",
101 "WinSock Error", MB_OK | MB_ICONEXCLAMATION);
102 WSACleanup();
103 return 1;
104 }
105 /* WISHLIST: maybe allow config tweaking even if winsock not present? */
106
107 InitCommonControls();
108
109 /*
110 * Process the command line.
111 */
112 {
113 char *p;
114
e277c42d 115 default_protocol = DEFAULT_PROTOCOL;
116 default_port = DEFAULT_PORT;
117
374330e2 118 do_defaults(NULL);
119
120 p = cmdline;
121 while (*p && isspace(*p)) p++;
122
123 /*
e277c42d 124 * Process command line options first. Yes, this can be
125 * done better, and it will be as soon as I have the
126 * energy...
127 */
128 while (*p == '-') {
129 char *q = p + strcspn(p, " \t");
130 p++;
131 if (q == p + 3 &&
132 tolower(p[0]) == 's' &&
133 tolower(p[1]) == 's' &&
134 tolower(p[2]) == 'h') {
135 default_protocol = cfg.protocol = PROT_SSH;
136 default_port = cfg.port = 22;
5fd04f07 137 } else if (q == p + 3 &&
138 tolower(p[0]) == 'l' &&
139 tolower(p[1]) == 'o' &&
140 tolower(p[2]) == 'g') {
141 logfile = "putty.log";
e277c42d 142 }
143 p = q + strspn(q, " \t");
144 }
145
146 /*
374330e2 147 * An initial @ means to activate a saved session.
148 */
149 if (*p == '@') {
150 do_defaults (p+1);
151 if (!*cfg.host && !do_config()) {
152 WSACleanup();
153 return 0;
154 }
155 } else if (*p == '&') {
156 /*
157 * An initial & means we've been given a command line
158 * containing the hex value of a HANDLE for a file
159 * mapping object, which we must then extract as a
160 * config.
161 */
162 HANDLE filemap;
163 Config *cp;
1d470ad2 164 if (sscanf(p+1, "%p", &filemap) == 1 &&
374330e2 165 (cp = MapViewOfFile(filemap, FILE_MAP_READ,
166 0, 0, sizeof(Config))) != NULL) {
167 cfg = *cp;
168 UnmapViewOfFile(cp);
169 CloseHandle(filemap);
170 } else if (!do_config()) {
171 WSACleanup();
172 return 0;
173 }
174 } else if (*p) {
175 char *q = p;
4e8bc59f 176 /*
177 * If the hostname starts with "telnet://", set the
178 * protocol to Telnet and process the string as a
179 * Telnet URL.
180 */
181 if (!strncmp(q, "telnet://", 9)) {
ab21de77 182 char c;
183
4e8bc59f 184 q += 9;
185 cfg.protocol = PROT_TELNET;
186 p = q;
ab21de77 187 while (*p && *p != ':' && *p != '/') p++;
188 c = *p;
189 if (*p)
4e8bc59f 190 *p++ = '\0';
ab21de77 191 if (c == ':')
4e8bc59f 192 cfg.port = atoi(p);
ab21de77 193 else
4e8bc59f 194 cfg.port = -1;
195 strncpy (cfg.host, q, sizeof(cfg.host)-1);
196 cfg.host[sizeof(cfg.host)-1] = '\0';
197 } else {
198 while (*p && !isspace(*p)) p++;
199 if (*p)
200 *p++ = '\0';
201 strncpy (cfg.host, q, sizeof(cfg.host)-1);
202 cfg.host[sizeof(cfg.host)-1] = '\0';
203 while (*p && isspace(*p)) p++;
204 if (*p)
205 cfg.port = atoi(p);
206 else
207 cfg.port = -1;
208 }
374330e2 209 } else {
210 if (!do_config()) {
211 WSACleanup();
212 return 0;
213 }
214 }
215 }
216
89ee5268 217 /*
218 * Select protocol. This is farmed out into a table in a
219 * separate file to enable an ssh-free variant.
220 */
221 {
222 int i;
223 back = NULL;
224 for (i = 0; backends[i].backend != NULL; i++)
225 if (backends[i].protocol == cfg.protocol) {
226 back = backends[i].backend;
227 break;
228 }
229 if (back == NULL) {
230 MessageBox(NULL, "Unsupported protocol number found",
231 "PuTTY Internal Error", MB_OK | MB_ICONEXCLAMATION);
232 WSACleanup();
233 return 1;
234 }
235 }
5bc238bb 236
237 ldisc = (cfg.ldisc_term ? &ldisc_term : &ldisc_simple);
374330e2 238
239 if (!prev) {
240 wndclass.style = 0;
241 wndclass.lpfnWndProc = WndProc;
242 wndclass.cbClsExtra = 0;
243 wndclass.cbWndExtra = 0;
244 wndclass.hInstance = inst;
245 wndclass.hIcon = LoadIcon (inst,
246 MAKEINTRESOURCE(IDI_MAINICON));
1bb542b2 247 wndclass.hCursor = LoadCursor (NULL, IDC_IBEAM);
374330e2 248 wndclass.hbrBackground = GetStockObject (BLACK_BRUSH);
249 wndclass.lpszMenuName = NULL;
250 wndclass.lpszClassName = appname;
251
252 RegisterClass (&wndclass);
253 }
254
255 hwnd = NULL;
256
257 savelines = cfg.savelines;
258 term_init();
259
260 cfgtopalette();
261
262 /*
263 * Guess some defaults for the window size. This all gets
264 * updated later, so we don't really care too much. However, we
265 * do want the font width/height guesses to correspond to a
266 * large font rather than a small one...
267 */
268
269 font_width = 10;
270 font_height = 20;
271 extra_width = 25;
272 extra_height = 28;
273 term_size (cfg.height, cfg.width, cfg.savelines);
274 guess_width = extra_width + font_width * cols;
275 guess_height = extra_height + font_height * rows;
276 {
277 RECT r;
278 HWND w = GetDesktopWindow();
279 GetWindowRect (w, &r);
280 if (guess_width > r.right - r.left)
281 guess_width = r.right - r.left;
282 if (guess_height > r.bottom - r.top)
283 guess_height = r.bottom - r.top;
284 }
285
c9def1b8 286 {
287 int winmode = WS_OVERLAPPEDWINDOW|WS_VSCROLL;
288 if (!cfg.scrollbar) winmode &= ~(WS_VSCROLL);
289 if (cfg.locksize) winmode &= ~(WS_THICKFRAME|WS_MAXIMIZEBOX);
290 hwnd = CreateWindow (appname, appname,
291 winmode,
292 CW_USEDEFAULT, CW_USEDEFAULT,
293 guess_width, guess_height,
294 NULL, NULL, inst, NULL);
295 }
374330e2 296
297 /*
298 * Initialise the fonts, simultaneously correcting the guesses
299 * for font_{width,height}.
300 */
301 bold_mode = cfg.bold_colour ? BOLD_COLOURS : BOLD_FONT;
302 und_mode = UND_FONT;
59ad2c03 303 init_fonts(0);
374330e2 304
305 /*
306 * Correct the guesses for extra_{width,height}.
307 */
308 {
309 RECT cr, wr;
310 GetWindowRect (hwnd, &wr);
311 GetClientRect (hwnd, &cr);
312 extra_width = wr.right - wr.left - cr.right + cr.left;
313 extra_height = wr.bottom - wr.top - cr.bottom + cr.top;
314 }
315
316 /*
317 * Resize the window, now we know what size we _really_ want it
318 * to be.
319 */
320 guess_width = extra_width + font_width * cols;
321 guess_height = extra_height + font_height * rows;
322 SendMessage (hwnd, WM_IGNORE_SIZE, 0, 0);
323 SetWindowPos (hwnd, NULL, 0, 0, guess_width, guess_height,
324 SWP_NOMOVE | SWP_NOREDRAW | SWP_NOZORDER);
325
326 /*
327 * Initialise the scroll bar.
328 */
329 {
330 SCROLLINFO si;
331
332 si.cbSize = sizeof(si);
c9def1b8 333 si.fMask = SIF_ALL | SIF_DISABLENOSCROLL;
374330e2 334 si.nMin = 0;
335 si.nMax = rows-1;
336 si.nPage = rows;
337 si.nPos = 0;
338 SetScrollInfo (hwnd, SB_VERT, &si, FALSE);
339 }
340
341 /*
342 * Start up the telnet connection.
343 */
344 {
345 char *error;
346 char msg[1024];
347 char *realhost;
348
349 error = back->init (hwnd, cfg.host, cfg.port, &realhost);
350 if (error) {
351 sprintf(msg, "Unable to open connection:\n%s", error);
352 MessageBox(NULL, msg, "PuTTY Error", MB_ICONERROR | MB_OK);
353 return 0;
354 }
355 window_name = icon_name = NULL;
5ac36532 356 sprintf(msg, "%s - PuTTY", realhost);
374330e2 357 set_title (msg);
358 set_icon (msg);
359 }
360
d85548fe 361 session_closed = FALSE;
362
374330e2 363 /*
364 * Set up the input and output buffers.
365 */
c9def1b8 366 inbuf_head = 0;
374330e2 367 outbuf_reap = outbuf_head = 0;
368
369 /*
370 * Prepare the mouse handler.
371 */
372 lastact = MA_NOTHING;
373 lastbtn = MB_NOTHING;
374 dbltime = GetDoubleClickTime();
375
376 /*
377 * Set up the session-control options on the system menu.
378 */
379 {
380 HMENU m = GetSystemMenu (hwnd, FALSE);
0a4aa984 381 HMENU p,s;
382 int i;
374330e2 383
384 AppendMenu (m, MF_SEPARATOR, 0, 0);
385 if (cfg.protocol == PROT_TELNET) {
386 p = CreateMenu();
387 AppendMenu (p, MF_ENABLED, IDM_TEL_AYT, "Are You There");
388 AppendMenu (p, MF_ENABLED, IDM_TEL_BRK, "Break");
389 AppendMenu (p, MF_ENABLED, IDM_TEL_SYNCH, "Synch");
390 AppendMenu (p, MF_SEPARATOR, 0, 0);
391 AppendMenu (p, MF_ENABLED, IDM_TEL_EC, "Erase Character");
392 AppendMenu (p, MF_ENABLED, IDM_TEL_EL, "Erase Line");
393 AppendMenu (p, MF_ENABLED, IDM_TEL_GA, "Go Ahead");
394 AppendMenu (p, MF_ENABLED, IDM_TEL_NOP, "No Operation");
395 AppendMenu (p, MF_SEPARATOR, 0, 0);
396 AppendMenu (p, MF_ENABLED, IDM_TEL_ABORT, "Abort Process");
397 AppendMenu (p, MF_ENABLED, IDM_TEL_AO, "Abort Output");
398 AppendMenu (p, MF_ENABLED, IDM_TEL_IP, "Interrupt Process");
399 AppendMenu (p, MF_ENABLED, IDM_TEL_SUSP, "Suspend Process");
400 AppendMenu (p, MF_SEPARATOR, 0, 0);
401 AppendMenu (p, MF_ENABLED, IDM_TEL_EOR, "End Of Record");
402 AppendMenu (p, MF_ENABLED, IDM_TEL_EOF, "End Of File");
403 AppendMenu (m, MF_POPUP | MF_ENABLED, (UINT) p, "Telnet Command");
374330e2 404 AppendMenu (m, MF_SEPARATOR, 0, 0);
405 }
45c4ea18 406 AppendMenu (m, MF_ENABLED, IDM_SHOWLOG, "&Event Log");
c5e9c988 407 AppendMenu (m, MF_SEPARATOR, 0, 0);
45c4ea18 408 AppendMenu (m, MF_ENABLED, IDM_NEWSESS, "Ne&w Session");
409 AppendMenu (m, MF_ENABLED, IDM_DUPSESS, "&Duplicate Session");
0a4aa984 410 s = CreateMenu();
411 get_sesslist(TRUE);
412 for (i = 1 ; i < ((nsessions < 256) ? nsessions : 256) ; i++)
413 AppendMenu (s, MF_ENABLED, IDM_SAVED_MIN + (16 * i) , sessions[i]);
45c4ea18 414 AppendMenu (m, MF_POPUP | MF_ENABLED, (UINT) s, "Sa&ved Sessions");
415 AppendMenu (m, MF_ENABLED, IDM_RECONF, "Chan&ge Settings");
374330e2 416 AppendMenu (m, MF_SEPARATOR, 0, 0);
45c4ea18 417 AppendMenu (m, MF_ENABLED, IDM_CLRSB, "C&lear Scrollback");
418 AppendMenu (m, MF_ENABLED, IDM_RESET, "Rese&t Terminal");
374330e2 419 AppendMenu (m, MF_SEPARATOR, 0, 0);
45c4ea18 420 AppendMenu (m, MF_ENABLED, IDM_ABOUT, "&About PuTTY");
374330e2 421 }
422
423 /*
424 * Finally show the window!
425 */
426 ShowWindow (hwnd, show);
427
428 /*
429 * Set the palette up.
430 */
431 pal = NULL;
432 logpal = NULL;
433 init_palette();
434
435 has_focus = (GetForegroundWindow() == hwnd);
436 UpdateWindow (hwnd);
437
59ad2c03 438 {
439 int timer_id = 0, long_timer = 0;
440
441 while (GetMessage (&msg, NULL, 0, 0) == 1) {
442 /* Sometimes DispatchMessage calls routines that use their own
443 * GetMessage loop, setup this timer so we get some control back.
444 *
445 * Also call term_update() from the timer so that if the host
446 * is sending data flat out we still do redraws.
447 */
448 if(timer_id && long_timer) {
449 KillTimer(hwnd, timer_id);
450 long_timer = timer_id = 0;
451 }
452 if(!timer_id)
453 timer_id = SetTimer(hwnd, 1, 20, NULL);
454 DispatchMessage (&msg);
455
456 /* This is too fast, but I'll leave it for now 'cause it shows
457 * how often term_update is called (far too often at times!)
458 */
459 term_blink(0);
460
c9def1b8 461 /* Send the paste buffer if there's anything to send */
462 term_paste();
463
59ad2c03 464 /* If there's nothing new in the queue then we can do everything
465 * we've delayed, reading the socket, writing, and repainting
466 * the window.
467 */
468 if (!PeekMessage (&msg, NULL, 0, 0, PM_NOREMOVE)) {
469 if (pending_netevent) {
470 enact_pending_netevent();
471
472 term_blink(1);
473 }
474 } else continue;
475 if (!PeekMessage (&msg, NULL, 0, 0, PM_NOREMOVE)) {
476 if (timer_id) {
477 KillTimer(hwnd, timer_id);
478 timer_id = 0;
479 }
c9def1b8 480 if (inbuf_head)
59ad2c03 481 term_out();
482 term_update();
c9def1b8 483 if (!has_focus)
484 timer_id = SetTimer(hwnd, 1, 2000, NULL);
485 else if (cfg.blinktext)
486 timer_id = SetTimer(hwnd, 1, 250, NULL);
487 else
488 timer_id = SetTimer(hwnd, 1, 500, NULL);
59ad2c03 489 long_timer = 1;
490 }
491 }
374330e2 492 }
493
494 /*
495 * Clean up.
496 */
497 {
498 int i;
499 for (i=0; i<8; i++)
500 if (fonts[i])
501 DeleteObject(fonts[i]);
502 }
503 sfree(logpal);
504 if (pal)
505 DeleteObject(pal);
506 WSACleanup();
507
8f203108 508 if (cfg.protocol == PROT_SSH) {
374330e2 509 random_save_seed();
8f203108 510#ifdef MSCRYPTOAPI
511 crypto_wrapup();
512#endif
513 }
374330e2 514
515 return msg.wParam;
516}
517
518/*
59ad2c03 519 * Actually do the job requested by a WM_NETEVENT
520 */
521static void enact_pending_netevent(void) {
522 int i;
523 pending_netevent = FALSE;
524 i = back->msg (pend_netevent_wParam, pend_netevent_lParam);
525
526 if (i < 0) {
527 char buf[1024];
528 switch (WSABASEERR + (-i) % 10000) {
529 case WSAECONNRESET:
530 sprintf(buf, "Connection reset by peer");
531 break;
532 default:
533 sprintf(buf, "Unexpected network error %d", -i);
534 break;
535 }
536 MessageBox(hwnd, buf, "PuTTY Fatal Error",
537 MB_ICONERROR | MB_OK);
538 PostQuitMessage(1);
539 } else if (i == 0) {
540 if (cfg.close_on_exit)
541 PostQuitMessage(0);
542 else {
543 session_closed = TRUE;
544 MessageBox(hwnd, "Connection closed by remote host",
545 "PuTTY", MB_OK | MB_ICONINFORMATION);
546 SetWindowText (hwnd, "PuTTY (inactive)");
547 }
548 }
549}
550
551/*
374330e2 552 * Copy the colour palette from the configuration data into defpal.
553 * This is non-trivial because the colour indices are different.
554 */
555static void cfgtopalette(void) {
556 int i;
557 static const int ww[] = {
558 6, 7, 8, 9, 10, 11, 12, 13,
559 14, 15, 16, 17, 18, 19, 20, 21,
560 0, 1, 2, 3, 4, 4, 5, 5
561 };
562
563 for (i=0; i<24; i++) {
564 int w = ww[i];
565 defpal[i].rgbtRed = cfg.colours[w][0];
566 defpal[i].rgbtGreen = cfg.colours[w][1];
567 defpal[i].rgbtBlue = cfg.colours[w][2];
568 }
569}
570
571/*
572 * Set up the colour palette.
573 */
574static void init_palette(void) {
575 int i;
576 HDC hdc = GetDC (hwnd);
577 if (hdc) {
578 if (cfg.try_palette &&
579 GetDeviceCaps (hdc, RASTERCAPS) & RC_PALETTE) {
580 logpal = smalloc(sizeof(*logpal)
581 - sizeof(logpal->palPalEntry)
582 + NCOLOURS * sizeof(PALETTEENTRY));
583 logpal->palVersion = 0x300;
584 logpal->palNumEntries = NCOLOURS;
585 for (i = 0; i < NCOLOURS; i++) {
586 logpal->palPalEntry[i].peRed = defpal[i].rgbtRed;
587 logpal->palPalEntry[i].peGreen = defpal[i].rgbtGreen;
588 logpal->palPalEntry[i].peBlue = defpal[i].rgbtBlue;
589 logpal->palPalEntry[i].peFlags = PC_NOCOLLAPSE;
590 }
591 pal = CreatePalette (logpal);
592 if (pal) {
593 SelectPalette (hdc, pal, FALSE);
594 RealizePalette (hdc);
595 SelectPalette (hdc, GetStockObject (DEFAULT_PALETTE),
596 FALSE);
597 }
598 }
599 ReleaseDC (hwnd, hdc);
600 }
601 if (pal)
602 for (i=0; i<NCOLOURS; i++)
603 colours[i] = PALETTERGB(defpal[i].rgbtRed,
604 defpal[i].rgbtGreen,
605 defpal[i].rgbtBlue);
606 else
607 for(i=0; i<NCOLOURS; i++)
608 colours[i] = RGB(defpal[i].rgbtRed,
609 defpal[i].rgbtGreen,
610 defpal[i].rgbtBlue);
611}
612
613/*
614 * Initialise all the fonts we will need. There may be as many as
615 * eight or as few as one. We also:
616 *
617 * - check the font width and height, correcting our guesses if
618 * necessary.
619 *
620 * - verify that the bold font is the same width as the ordinary
621 * one, and engage shadow bolding if not.
622 *
623 * - verify that the underlined font is the same width as the
624 * ordinary one (manual underlining by means of line drawing can
625 * be done in a pinch).
374330e2 626 */
59ad2c03 627static void init_fonts(int pick_width) {
374330e2 628 TEXTMETRIC tm;
97fc891e 629 int i;
59ad2c03 630 int fsize[8];
374330e2 631 HDC hdc;
632 int fw_dontcare, fw_bold;
97fc891e 633 int firstchar = ' ';
374330e2 634
59ad2c03 635#ifdef CHECKOEMFONT
97fc891e 636font_messup:
59ad2c03 637#endif
374330e2 638 for (i=0; i<8; i++)
639 fonts[i] = NULL;
640
641 if (cfg.fontisbold) {
642 fw_dontcare = FW_BOLD;
643 fw_bold = FW_BLACK;
644 } else {
645 fw_dontcare = FW_DONTCARE;
646 fw_bold = FW_BOLD;
647 }
648
97fc891e 649 hdc = GetDC(hwnd);
650
651 font_height = cfg.fontheight;
59ad2c03 652 font_width = pick_width;
97fc891e 653
374330e2 654#define f(i,c,w,u) \
97fc891e 655 fonts[i] = CreateFont (font_height, font_width, 0, 0, w, FALSE, u, FALSE, \
374330e2 656 c, OUT_DEFAULT_PRECIS, \
657 CLIP_DEFAULT_PRECIS, DEFAULT_QUALITY, \
658 FIXED_PITCH | FF_DONTCARE, cfg.font)
97fc891e 659
374330e2 660 if (cfg.vtmode != VT_OEMONLY) {
14963b8f 661 f(FONT_NORMAL, cfg.fontcharset, fw_dontcare, FALSE);
97fc891e 662
663 SelectObject (hdc, fonts[FONT_NORMAL]);
664 GetTextMetrics(hdc, &tm);
665 font_height = tm.tmHeight;
666 font_width = tm.tmAveCharWidth;
667
14963b8f 668 f(FONT_UNDERLINE, cfg.fontcharset, fw_dontcare, TRUE);
97fc891e 669
670 if (bold_mode == BOLD_FONT) {
14963b8f 671 f(FONT_BOLD, cfg.fontcharset, fw_bold, FALSE);
672 f(FONT_BOLDUND, cfg.fontcharset, fw_bold, TRUE);
374330e2 673 }
97fc891e 674
675 if (cfg.vtmode == VT_OEMANSI) {
676 f(FONT_OEM, OEM_CHARSET, fw_dontcare, FALSE);
677 f(FONT_OEMUND, OEM_CHARSET, fw_dontcare, TRUE);
678
679 if (bold_mode == BOLD_FONT) {
680 f(FONT_OEMBOLD, OEM_CHARSET, fw_bold, FALSE);
681 f(FONT_OEMBOLDUND, OEM_CHARSET, fw_bold, TRUE);
682 }
683 }
684 }
685 else
686 {
687 f(FONT_OEM, cfg.fontcharset, fw_dontcare, FALSE);
688
689 SelectObject (hdc, fonts[FONT_OEM]);
690 GetTextMetrics(hdc, &tm);
691 font_height = tm.tmHeight;
692 font_width = tm.tmAveCharWidth;
693
694 f(FONT_OEMUND, cfg.fontcharset, fw_dontcare, TRUE);
695
696 if (bold_mode == BOLD_FONT) {
697 f(FONT_BOLD, cfg.fontcharset, fw_bold, FALSE);
698 f(FONT_BOLDUND, cfg.fontcharset, fw_bold, TRUE);
374330e2 699 }
374330e2 700 }
701#undef f
702
97fc891e 703 descent = tm.tmAscent + 1;
704 if (descent >= font_height)
705 descent = font_height - 1;
706 firstchar = tm.tmFirstChar;
374330e2 707
97fc891e 708 for (i=0; i<8; i++) {
709 if (fonts[i]) {
59ad2c03 710 if (SelectObject (hdc, fonts[i]) &&
711 GetTextMetrics(hdc, &tm) )
712 fsize[i] = tm.tmAveCharWidth + 256 * tm.tmHeight;
713 else fsize[i] = -i;
374330e2 714 }
59ad2c03 715 else fsize[i] = -i;
374330e2 716 }
717
718 ReleaseDC (hwnd, hdc);
719
59ad2c03 720 /* ... This is wrong in OEM only mode */
97fc891e 721 if (fsize[FONT_UNDERLINE] != fsize[FONT_NORMAL] ||
374330e2 722 (bold_mode == BOLD_FONT &&
97fc891e 723 fsize[FONT_BOLDUND] != fsize[FONT_BOLD])) {
374330e2 724 und_mode = UND_LINE;
725 DeleteObject (fonts[FONT_UNDERLINE]);
726 if (bold_mode == BOLD_FONT)
727 DeleteObject (fonts[FONT_BOLDUND]);
728 }
729
730 if (bold_mode == BOLD_FONT &&
97fc891e 731 fsize[FONT_BOLD] != fsize[FONT_NORMAL]) {
374330e2 732 bold_mode = BOLD_SHADOW;
733 DeleteObject (fonts[FONT_BOLD]);
734 if (und_mode == UND_FONT)
735 DeleteObject (fonts[FONT_BOLDUND]);
736 }
737
59ad2c03 738#ifdef CHECKOEMFONT
3cfb9f1c 739 /* With the fascist font painting it doesn't matter if the linedraw font
59ad2c03 740 * isn't exactly the right size anymore so we don't have to check this.
741 */
97fc891e 742 if (cfg.vtmode == VT_OEMANSI && fsize[FONT_OEM] != fsize[FONT_NORMAL] ) {
743 if( cfg.fontcharset == OEM_CHARSET )
744 {
745 MessageBox(NULL, "The OEM and ANSI versions of this font are\n"
374330e2 746 "different sizes. Using OEM-only mode instead",
747 "Font Size Mismatch", MB_ICONINFORMATION | MB_OK);
97fc891e 748 cfg.vtmode = VT_OEMONLY;
749 }
750 else if( firstchar < ' ' )
751 {
752 MessageBox(NULL, "The OEM and ANSI versions of this font are\n"
753 "different sizes. Using XTerm mode instead",
754 "Font Size Mismatch", MB_ICONINFORMATION | MB_OK);
755 cfg.vtmode = VT_XWINDOWS;
756 }
757 else
758 {
759 MessageBox(NULL, "The OEM and ANSI versions of this font are\n"
760 "different sizes. Using ISO8859-1 mode instead",
761 "Font Size Mismatch", MB_ICONINFORMATION | MB_OK);
762 cfg.vtmode = VT_POORMAN;
763 }
764
765 for (i=0; i<8; i++)
374330e2 766 if (fonts[i])
767 DeleteObject (fonts[i]);
97fc891e 768 goto font_messup;
374330e2 769 }
59ad2c03 770#endif
374330e2 771}
772
59ad2c03 773void request_resize (int w, int h, int refont) {
774 int width, height;
c9def1b8 775
776 /* If the window is maximized supress resizing attempts */
777 if(IsZoomed(hwnd)) return;
59ad2c03 778
779#ifdef CHECKOEMFONT
780 /* Don't do this in OEMANSI, you may get disable messages */
781 if (refont && w != cols && (cols==80 || cols==132)
782 && cfg.vtmode != VT_OEMANSI)
783#else
784 if (refont && w != cols && (cols==80 || cols==132))
785#endif
786 {
787 /* If font width too big for screen should we shrink the font more ? */
788 if (w==132)
789 font_width = ((font_width*cols+w/2)/w);
790 else
791 font_width = 0;
792 {
793 int i;
794 for (i=0; i<8; i++)
795 if (fonts[i])
796 DeleteObject(fonts[i]);
797 }
798 bold_mode = cfg.bold_colour ? BOLD_COLOURS : BOLD_FONT;
799 und_mode = UND_FONT;
800 init_fonts(font_width);
801 }
c9def1b8 802 else
803 {
804 static int first_time = 1;
805 static RECT ss;
806
807 switch(first_time)
808 {
809 case 1:
810 /* Get the size of the screen */
811 if (GetClientRect(GetDesktopWindow(),&ss))
812 /* first_time = 0 */;
813 else { first_time = 2; break; }
814 case 0:
815 /* Make sure the values are sane */
816 width = (ss.right-ss.left-extra_width ) / font_width;
817 height = (ss.bottom-ss.top-extra_height ) / font_height;
818
819 if (w>width) w=width;
820 if (h>height) h=height;
821 if (w<15) w = 15;
822 if (h<1) w = 1;
823 }
824 }
59ad2c03 825
826 width = extra_width + font_width * w;
827 height = extra_height + font_height * h;
374330e2 828
829 SetWindowPos (hwnd, NULL, 0, 0, width, height,
830 SWP_NOACTIVATE | SWP_NOCOPYBITS |
831 SWP_NOMOVE | SWP_NOZORDER);
832}
833
834static void click (Mouse_Button b, int x, int y) {
fdedf2c8 835 int thistime = GetMessageTime();
836
837 if (lastbtn == b && thistime - lasttime < dbltime) {
374330e2 838 lastact = (lastact == MA_CLICK ? MA_2CLK :
839 lastact == MA_2CLK ? MA_3CLK :
840 lastact == MA_3CLK ? MA_CLICK : MA_NOTHING);
841 } else {
842 lastbtn = b;
843 lastact = MA_CLICK;
844 }
845 if (lastact != MA_NOTHING)
846 term_mouse (b, lastact, x, y);
fdedf2c8 847 lasttime = thistime;
374330e2 848}
849
996c8c3b 850static LRESULT CALLBACK WndProc (HWND hwnd, UINT message,
851 WPARAM wParam, LPARAM lParam) {
374330e2 852 HDC hdc;
853 static int ignore_size = FALSE;
854 static int ignore_clip = FALSE;
855 static int just_reconfigged = FALSE;
856
857 switch (message) {
59ad2c03 858 case WM_TIMER:
859 if (pending_netevent)
860 enact_pending_netevent();
c9def1b8 861 if (inbuf_head)
59ad2c03 862 term_out();
863 term_update();
864 return 0;
374330e2 865 case WM_CREATE:
866 break;
68130d34 867 case WM_CLOSE:
d85548fe 868 if (!cfg.warn_on_close || session_closed ||
9ef49106 869 MessageBox(hwnd, "Are you sure you want to close this session?",
68130d34 870 "PuTTY Exit Confirmation",
871 MB_ICONWARNING | MB_OKCANCEL) == IDOK)
872 DestroyWindow(hwnd);
873 return 0;
374330e2 874 case WM_DESTROY:
875 PostQuitMessage (0);
876 return 0;
6833a413 877 case WM_SYSCOMMAND:
878 switch (wParam & ~0xF) { /* low 4 bits reserved to Windows */
374330e2 879 case IDM_SHOWLOG:
c5e9c988 880 showeventlog(hwnd);
374330e2 881 break;
882 case IDM_NEWSESS:
883 case IDM_DUPSESS:
6833a413 884 case IDM_SAVEDSESS:
374330e2 885 {
886 char b[2048];
887 char c[30], *cl;
e4e4cc7e 888 int freecl = FALSE;
374330e2 889 STARTUPINFO si;
890 PROCESS_INFORMATION pi;
891 HANDLE filemap = NULL;
892
893 if (wParam == IDM_DUPSESS) {
894 /*
895 * Allocate a file-mapping memory chunk for the
896 * config structure.
897 */
898 SECURITY_ATTRIBUTES sa;
899 Config *p;
900
901 sa.nLength = sizeof(sa);
902 sa.lpSecurityDescriptor = NULL;
903 sa.bInheritHandle = TRUE;
904 filemap = CreateFileMapping((HANDLE)0xFFFFFFFF,
905 &sa,
906 PAGE_READWRITE,
907 0,
908 sizeof(Config),
909 NULL);
910 if (filemap) {
911 p = (Config *)MapViewOfFile(filemap,
912 FILE_MAP_WRITE,
913 0, 0, sizeof(Config));
914 if (p) {
915 *p = cfg; /* structure copy */
916 UnmapViewOfFile(p);
917 }
918 }
1d470ad2 919 sprintf(c, "putty &%p", filemap);
374330e2 920 cl = c;
0a4aa984 921 } else if (wParam == IDM_SAVEDSESS) {
e4e4cc7e 922 char *session = sessions[(lParam - IDM_SAVED_MIN) / 16];
923 cl = malloc(16 + strlen(session)); /* 8, but play safe */
924 if (!cl)
925 cl = NULL; /* not a very important failure mode */
94e6450e 926 else {
927 sprintf(cl, "putty @%s", session);
928 freecl = TRUE;
929 }
374330e2 930 } else
6833a413 931 cl = NULL;
374330e2 932
933 GetModuleFileName (NULL, b, sizeof(b)-1);
934 si.cb = sizeof(si);
935 si.lpReserved = NULL;
936 si.lpDesktop = NULL;
937 si.lpTitle = NULL;
938 si.dwFlags = 0;
939 si.cbReserved2 = 0;
940 si.lpReserved2 = NULL;
941 CreateProcess (b, cl, NULL, NULL, TRUE,
942 NORMAL_PRIORITY_CLASS, NULL, NULL, &si, &pi);
943
944 if (filemap)
945 CloseHandle(filemap);
e4e4cc7e 946 if (freecl)
947 free(cl);
374330e2 948 }
949 break;
950 case IDM_RECONF:
951 if (!do_reconfig(hwnd))
952 break;
953 just_reconfigged = TRUE;
954 {
955 int i;
956 for (i=0; i<8; i++)
957 if (fonts[i])
958 DeleteObject(fonts[i]);
959 }
960 bold_mode = cfg.bold_colour ? BOLD_COLOURS : BOLD_FONT;
961 und_mode = UND_FONT;
59ad2c03 962 init_fonts(0);
374330e2 963 sfree(logpal);
59ad2c03 964 /* Telnet will change local echo -> remote if the remote asks */
965 if (cfg.protocol != PROT_TELNET)
966 ldisc = (cfg.ldisc_term ? &ldisc_term : &ldisc_simple);
374330e2 967 if (pal)
968 DeleteObject(pal);
969 logpal = NULL;
970 pal = NULL;
971 cfgtopalette();
972 init_palette();
c9def1b8 973
974 /* Enable or disable the scroll bar, etc */
975 {
976 LONG nflg, flag = GetWindowLong(hwnd, GWL_STYLE);
977
978 nflg = flag;
979 if (cfg.scrollbar) nflg |= WS_VSCROLL;
980 else nflg &= ~WS_VSCROLL;
981 if (cfg.locksize)
982 nflg &= ~(WS_THICKFRAME|WS_MAXIMIZEBOX);
983 else
984 nflg |= (WS_THICKFRAME|WS_MAXIMIZEBOX);
985
986 if (nflg != flag)
987 {
988 RECT cr, wr;
989
990 SetWindowLong(hwnd, GWL_STYLE, nflg);
991 SendMessage (hwnd, WM_IGNORE_SIZE, 0, 0);
992 SetWindowPos(hwnd, NULL, 0,0,0,0,
993 SWP_NOACTIVATE|SWP_NOCOPYBITS|
994 SWP_NOMOVE|SWP_NOSIZE| SWP_NOZORDER|
995 SWP_FRAMECHANGED);
996
997 GetWindowRect (hwnd, &wr);
998 GetClientRect (hwnd, &cr);
999 extra_width = wr.right - wr.left - cr.right + cr.left;
1000 extra_height = wr.bottom - wr.top - cr.bottom + cr.top;
1001 }
1002 }
1003
374330e2 1004 term_size(cfg.height, cfg.width, cfg.savelines);
1005 InvalidateRect(hwnd, NULL, TRUE);
1006 SetWindowPos (hwnd, NULL, 0, 0,
1007 extra_width + font_width * cfg.width,
1008 extra_height + font_height * cfg.height,
1009 SWP_NOACTIVATE | SWP_NOCOPYBITS |
1010 SWP_NOMOVE | SWP_NOZORDER);
1011 if (IsIconic(hwnd)) {
1012 SetWindowText (hwnd,
1013 cfg.win_name_always ? window_name : icon_name);
1014 }
1015 break;
1016 case IDM_CLRSB:
1017 term_clrsb();
1018 break;
1019 case IDM_RESET:
1020 term_pwron();
1021 break;
1022 case IDM_TEL_AYT: back->special (TS_AYT); break;
1023 case IDM_TEL_BRK: back->special (TS_BRK); break;
1024 case IDM_TEL_SYNCH: back->special (TS_SYNCH); break;
1025 case IDM_TEL_EC: back->special (TS_EC); break;
1026 case IDM_TEL_EL: back->special (TS_EL); break;
1027 case IDM_TEL_GA: back->special (TS_GA); break;
1028 case IDM_TEL_NOP: back->special (TS_NOP); break;
1029 case IDM_TEL_ABORT: back->special (TS_ABORT); break;
1030 case IDM_TEL_AO: back->special (TS_AO); break;
1031 case IDM_TEL_IP: back->special (TS_IP); break;
1032 case IDM_TEL_SUSP: back->special (TS_SUSP); break;
1033 case IDM_TEL_EOR: back->special (TS_EOR); break;
1034 case IDM_TEL_EOF: back->special (TS_EOF); break;
1035 case IDM_ABOUT:
1036 showabout (hwnd);
1037 break;
0a4aa984 1038 default:
1039 if (wParam >= IDM_SAVED_MIN && wParam <= IDM_SAVED_MAX) {
1040 SendMessage(hwnd, WM_SYSCOMMAND, IDM_SAVEDSESS, wParam);
1041 }
374330e2 1042 }
1043 break;
37508af4 1044
1045#define X_POS(l) ((int)(short)LOWORD(l))
1046#define Y_POS(l) ((int)(short)HIWORD(l))
1047
fdedf2c8 1048#define TO_CHR_X(x) (((x)<0 ? (x)-font_width+1 : (x)) / font_width)
1049#define TO_CHR_Y(y) (((y)<0 ? (y)-font_height+1: (y)) / font_height)
1050
374330e2 1051 case WM_LBUTTONDOWN:
fdedf2c8 1052 click (MB_SELECT, TO_CHR_X(X_POS(lParam)),
1053 TO_CHR_Y(Y_POS(lParam)));
fef97f43 1054 SetCapture(hwnd);
374330e2 1055 return 0;
1056 case WM_LBUTTONUP:
fdedf2c8 1057 term_mouse (MB_SELECT, MA_RELEASE, TO_CHR_X(X_POS(lParam)),
1058 TO_CHR_Y(Y_POS(lParam)));
37508af4 1059 ReleaseCapture();
374330e2 1060 return 0;
1061 case WM_MBUTTONDOWN:
37508af4 1062 SetCapture(hwnd);
374330e2 1063 click (cfg.mouse_is_xterm ? MB_PASTE : MB_EXTEND,
fdedf2c8 1064 TO_CHR_X(X_POS(lParam)),
1065 TO_CHR_Y(Y_POS(lParam)));
374330e2 1066 return 0;
1067 case WM_MBUTTONUP:
1068 term_mouse (cfg.mouse_is_xterm ? MB_PASTE : MB_EXTEND,
fdedf2c8 1069 MA_RELEASE, TO_CHR_X(X_POS(lParam)),
1070 TO_CHR_Y(Y_POS(lParam)));
37508af4 1071 ReleaseCapture();
a0b1cefc 1072 return 0;
374330e2 1073 case WM_RBUTTONDOWN:
37508af4 1074 SetCapture(hwnd);
374330e2 1075 click (cfg.mouse_is_xterm ? MB_EXTEND : MB_PASTE,
fdedf2c8 1076 TO_CHR_X(X_POS(lParam)),
1077 TO_CHR_Y(Y_POS(lParam)));
374330e2 1078 return 0;
1079 case WM_RBUTTONUP:
1080 term_mouse (cfg.mouse_is_xterm ? MB_EXTEND : MB_PASTE,
fdedf2c8 1081 MA_RELEASE, TO_CHR_X(X_POS(lParam)),
1082 TO_CHR_Y(Y_POS(lParam)));
37508af4 1083 ReleaseCapture();
374330e2 1084 return 0;
1085 case WM_MOUSEMOVE:
1086 /*
1087 * Add the mouse position and message time to the random
1088 * number noise, if we're using ssh.
1089 */
1090 if (cfg.protocol == PROT_SSH)
1091 noise_ultralight(lParam);
1092
1093 if (wParam & (MK_LBUTTON | MK_MBUTTON | MK_RBUTTON)) {
1094 Mouse_Button b;
1095 if (wParam & MK_LBUTTON)
1096 b = MB_SELECT;
1097 else if (wParam & MK_MBUTTON)
1098 b = cfg.mouse_is_xterm ? MB_PASTE : MB_EXTEND;
1099 else
1100 b = cfg.mouse_is_xterm ? MB_EXTEND : MB_PASTE;
fdedf2c8 1101 term_mouse (b, MA_DRAG, TO_CHR_X(X_POS(lParam)),
1102 TO_CHR_Y(Y_POS(lParam)));
374330e2 1103 }
374330e2 1104 return 0;
1105 case WM_IGNORE_CLIP:
1106 ignore_clip = wParam; /* don't panic on DESTROYCLIPBOARD */
1107 break;
1108 case WM_DESTROYCLIPBOARD:
1109 if (!ignore_clip)
1110 term_deselect();
1111 ignore_clip = FALSE;
1112 return 0;
1113 case WM_PAINT:
1114 {
1115 PAINTSTRUCT p;
1116 hdc = BeginPaint (hwnd, &p);
1117 if (pal) {
1118 SelectPalette (hdc, pal, TRUE);
1119 RealizePalette (hdc);
1120 }
1121 term_paint (hdc, p.rcPaint.left, p.rcPaint.top,
1122 p.rcPaint.right, p.rcPaint.bottom);
1123 SelectObject (hdc, GetStockObject(SYSTEM_FONT));
1124 SelectObject (hdc, GetStockObject(WHITE_PEN));
1125 EndPaint (hwnd, &p);
1126 }
1127 return 0;
1128 case WM_NETEVENT:
59ad2c03 1129 /* Notice we can get multiple netevents, FD_READ, FD_WRITE etc
1130 * but the only one that's likely to try to overload us is FD_READ.
1131 * This means buffering just one is fine.
1132 */
1133 if (pending_netevent)
1134 enact_pending_netevent();
1135
1136 pending_netevent = TRUE;
1137 pend_netevent_wParam=wParam;
1138 pend_netevent_lParam=lParam;
374330e2 1139 return 0;
1140 case WM_SETFOCUS:
1141 has_focus = TRUE;
1142 term_out();
1143 term_update();
1144 break;
1145 case WM_KILLFOCUS:
1146 has_focus = FALSE;
1147 term_out();
1148 term_update();
1149 break;
1150 case WM_IGNORE_SIZE:
1151 ignore_size = TRUE; /* don't panic on next WM_SIZE msg */
1152 break;
73251d5d 1153 case WM_ENTERSIZEMOVE:
996c8c3b 1154 EnableSizeTip(1);
1155 break;
73251d5d 1156 case WM_EXITSIZEMOVE:
996c8c3b 1157 EnableSizeTip(0);
1158 break;
374330e2 1159 case WM_SIZING:
1160 {
1161 int width, height, w, h, ew, eh;
1162 LPRECT r = (LPRECT)lParam;
1163
1164 width = r->right - r->left - extra_width;
1165 height = r->bottom - r->top - extra_height;
1166 w = (width + font_width/2) / font_width; if (w < 1) w = 1;
1167 h = (height + font_height/2) / font_height; if (h < 1) h = 1;
996c8c3b 1168 UpdateSizeTip(hwnd, w, h);
374330e2 1169 ew = width - w * font_width;
1170 eh = height - h * font_height;
1171 if (ew != 0) {
1172 if (wParam == WMSZ_LEFT ||
1173 wParam == WMSZ_BOTTOMLEFT ||
1174 wParam == WMSZ_TOPLEFT)
1175 r->left += ew;
1176 else
1177 r->right -= ew;
1178 }
1179 if (eh != 0) {
1180 if (wParam == WMSZ_TOP ||
1181 wParam == WMSZ_TOPRIGHT ||
1182 wParam == WMSZ_TOPLEFT)
1183 r->top += eh;
1184 else
1185 r->bottom -= eh;
1186 }
1187 if (ew || eh)
1188 return 1;
1189 else
1190 return 0;
1191 }
996c8c3b 1192 /* break; (never reached) */
374330e2 1193 case WM_SIZE:
1194 if (wParam == SIZE_MINIMIZED) {
1195 SetWindowText (hwnd,
1196 cfg.win_name_always ? window_name : icon_name);
1197 break;
1198 }
1199 if (wParam == SIZE_RESTORED || wParam == SIZE_MAXIMIZED)
1200 SetWindowText (hwnd, window_name);
1201 if (!ignore_size) {
1a6f78fe 1202 int width, height, w, h;
1203#if 0 /* we have fixed this using WM_SIZING now */
1204 int ew, eh;
1205#endif
374330e2 1206
1207 width = LOWORD(lParam);
1208 height = HIWORD(lParam);
1209 w = width / font_width; if (w < 1) w = 1;
1210 h = height / font_height; if (h < 1) h = 1;
1211#if 0 /* we have fixed this using WM_SIZING now */
1212 ew = width - w * font_width;
1213 eh = height - h * font_height;
1214 if (ew != 0 || eh != 0) {
1215 RECT r;
1216 GetWindowRect (hwnd, &r);
1217 SendMessage (hwnd, WM_IGNORE_SIZE, 0, 0);
1218 SetWindowPos (hwnd, NULL, 0, 0,
1219 r.right - r.left - ew, r.bottom - r.top - eh,
1220 SWP_NOACTIVATE | SWP_NOMOVE | SWP_NOZORDER);
1221 }
1222#endif
1223 if (w != cols || h != rows || just_reconfigged) {
1224 term_invalidate();
1225 term_size (h, w, cfg.savelines);
1226 back->size();
1227 just_reconfigged = FALSE;
1228 }
1229 }
1230 ignore_size = FALSE;
1231 return 0;
1232 case WM_VSCROLL:
1233 switch (LOWORD(wParam)) {
1234 case SB_BOTTOM: term_scroll(-1, 0); break;
1235 case SB_TOP: term_scroll(+1, 0); break;
1236 case SB_LINEDOWN: term_scroll (0, +1); break;
1237 case SB_LINEUP: term_scroll (0, -1); break;
1238 case SB_PAGEDOWN: term_scroll (0, +rows/2); break;
1239 case SB_PAGEUP: term_scroll (0, -rows/2); break;
1240 case SB_THUMBPOSITION: case SB_THUMBTRACK:
1241 term_scroll (1, HIWORD(wParam)); break;
1242 }
1243 break;
1244 case WM_PALETTECHANGED:
1245 if ((HWND) wParam != hwnd && pal != NULL) {
1246 HDC hdc = get_ctx();
1247 if (hdc) {
1248 if (RealizePalette (hdc) > 0)
1249 UpdateColors (hdc);
1250 free_ctx (hdc);
1251 }
1252 }
1253 break;
1254 case WM_QUERYNEWPALETTE:
1255 if (pal != NULL) {
1256 HDC hdc = get_ctx();
1257 if (hdc) {
1258 if (RealizePalette (hdc) > 0)
1259 UpdateColors (hdc);
1260 free_ctx (hdc);
1261 return TRUE;
1262 }
1263 }
1264 return FALSE;
1265 case WM_KEYDOWN:
1266 case WM_SYSKEYDOWN:
c9def1b8 1267 case WM_KEYUP:
1268 case WM_SYSKEYUP:
374330e2 1269 /*
1270 * Add the scan code and keypress timing to the random
1271 * number noise, if we're using ssh.
1272 */
1273 if (cfg.protocol == PROT_SSH)
1274 noise_ultralight(lParam);
1275
1276 /*
1277 * We don't do TranslateMessage since it disassociates the
1278 * resulting CHAR message from the KEYDOWN that sparked it,
1279 * which we occasionally don't want. Instead, we process
1280 * KEYDOWN, and call the Win32 translator functions so that
1281 * we get the translations under _our_ control.
1282 */
1283 {
1284 unsigned char buf[20];
1285 int len;
1286
c9def1b8 1287 len = TranslateKey (message, wParam, lParam, buf);
c5e9c988 1288 if (len == -1)
1289 return DefWindowProc (hwnd, message, wParam, lParam);
5bc238bb 1290 ldisc->send (buf, len);
374330e2 1291 }
1292 return 0;
1293 case WM_CHAR:
1294 case WM_SYSCHAR:
1295 /*
1296 * Nevertheless, we are prepared to deal with WM_CHAR
1297 * messages, should they crop up. So if someone wants to
1298 * post the things to us as part of a macro manoeuvre,
1299 * we're ready to cope.
1300 */
1301 {
14963b8f 1302 char c = xlat_kbd2tty((unsigned char)wParam);
5bc238bb 1303 ldisc->send (&c, 1);
374330e2 1304 }
1305 return 0;
1306 }
1307
1308 return DefWindowProc (hwnd, message, wParam, lParam);
1309}
1310
1311/*
1312 * Draw a line of text in the window, at given character
1313 * coordinates, in given attributes.
1314 *
1315 * We are allowed to fiddle with the contents of `text'.
1316 */
1317void do_text (Context ctx, int x, int y, char *text, int len,
c9def1b8 1318 unsigned long attr, int lattr) {
374330e2 1319 COLORREF fg, bg, t;
1320 int nfg, nbg, nfont;
1321 HDC hdc = ctx;
59ad2c03 1322 RECT line_box;
1323 int force_manual_underline = 0;
c9def1b8 1324 int fnt_width = font_width*(1+(lattr!=LATTR_NORM));
59ad2c03 1325static int *IpDx = 0, IpDxLEN = 0;;
1326
c9def1b8 1327 if (len>IpDxLEN || IpDx[0] != fnt_width) {
59ad2c03 1328 int i;
1329 if (len>IpDxLEN) {
1330 sfree(IpDx);
1331 IpDx = smalloc((len+16)*sizeof(int));
1332 IpDxLEN = (len+16);
1333 }
c9def1b8 1334 for(i=0; i<IpDxLEN; i++)
1335 IpDx[i] = fnt_width;
59ad2c03 1336 }
374330e2 1337
c9def1b8 1338 x *= fnt_width;
374330e2 1339 y *= font_height;
1340
1341 if (attr & ATTR_ACTCURS) {
c9def1b8 1342 attr &= (bold_mode == BOLD_COLOURS ? 0x300200 : 0x300300);
374330e2 1343 attr ^= ATTR_CUR_XOR;
1344 }
1345
1346 nfont = 0;
1347 if (cfg.vtmode == VT_OEMONLY)
1348 nfont |= FONT_OEM;
1349
1350 /*
1351 * Map high-half characters in order to approximate ISO using
59ad2c03 1352 * OEM character set. No characters are missing if the OEM codepage
1353 * is CP850.
374330e2 1354 */
1355 if (nfont & FONT_OEM) {
1356 int i;
1357 for (i=0; i<len; i++)
1358 if (text[i] >= '\xA0' && text[i] <= '\xFF') {
59ad2c03 1359#if 0
1360 /* This is CP850 ... perfect translation */
374330e2 1361 static const char oemhighhalf[] =
1362 "\x20\xAD\xBD\x9C\xCF\xBE\xDD\xF5" /* A0-A7 */
1363 "\xF9\xB8\xA6\xAE\xAA\xF0\xA9\xEE" /* A8-AF */
1364 "\xF8\xF1\xFD\xFC\xEF\xE6\xF4\xFA" /* B0-B7 */
1365 "\xF7\xFB\xA7\xAF\xAC\xAB\xF3\xA8" /* B8-BF */
59ad2c03 1366 "\xB7\xB5\xB6\xC7\x8E\x8F\x92\x80" /* C0-C7 */
1367 "\xD4\x90\xD2\xD3\xDE\xD6\xD7\xD8" /* C8-CF */
374330e2 1368 "\xD1\xA5\xE3\xE0\xE2\xE5\x99\x9E" /* D0-D7 */
1369 "\x9D\xEB\xE9\xEA\x9A\xED\xE8\xE1" /* D8-DF */
1370 "\x85\xA0\x83\xC6\x84\x86\x91\x87" /* E0-E7 */
1371 "\x8A\x82\x88\x89\x8D\xA1\x8C\x8B" /* E8-EF */
1372 "\xD0\xA4\x95\xA2\x93\xE4\x94\xF6" /* F0-F7 */
1373 "\x9B\x97\xA3\x96\x81\xEC\xE7\x98" /* F8-FF */
1374 ;
59ad2c03 1375#endif
1376 /* This is CP437 ... junk translation */
1377 static const unsigned char oemhighhalf[] = {
1378 0xff, 0xad, 0x9b, 0x9c, 0x6f, 0x9d, 0x7c, 0x15,
1379 0x22, 0x43, 0xa6, 0xae, 0xaa, 0x2d, 0x52, 0xc4,
1380 0xf8, 0xf1, 0xfd, 0x33, 0x27, 0xe6, 0x14, 0xfa,
1381 0x2c, 0x31, 0xa7, 0xaf, 0xac, 0xab, 0x2f, 0xa8,
1382 0x41, 0x41, 0x41, 0x41, 0x8e, 0x8f, 0x92, 0x80,
1383 0x45, 0x90, 0x45, 0x45, 0x49, 0x49, 0x49, 0x49,
1384 0x44, 0xa5, 0x4f, 0x4f, 0x4f, 0x4f, 0x99, 0x78,
1385 0xed, 0x55, 0x55, 0x55, 0x9a, 0x59, 0x50, 0xe1,
1386 0x85, 0xa0, 0x83, 0x61, 0x84, 0x86, 0x91, 0x87,
1387 0x8a, 0x82, 0x88, 0x89, 0x8d, 0xa1, 0x8c, 0x8b,
1388 0x0b, 0xa4, 0x95, 0xa2, 0x93, 0x6f, 0x94, 0xf6,
1389 0xed, 0x97, 0xa3, 0x96, 0x81, 0x79, 0x70, 0x98
1390 };
1391
374330e2 1392 text[i] = oemhighhalf[(unsigned char)text[i] - 0xA0];
1393 }
1394 }
1395
1396 if (attr & ATTR_GBCHR) {
1397 int i;
1398 /*
1399 * GB mapping: map # to pound, and everything else stays
1400 * normal.
1401 */
1402 for (i=0; i<len; i++)
1403 if (text[i] == '#')
1404 text[i] = cfg.vtmode == VT_OEMONLY ? '\x9C' : '\xA3';
1405 } else if (attr & ATTR_LINEDRW) {
1406 int i;
59ad2c03 1407 /* ISO 8859-1 */
374330e2 1408 static const char poorman[] =
1409 "*#****\xB0\xB1**+++++-----++++|****\xA3\xB7";
59ad2c03 1410
1411 /* CP437 */
1412 static const char oemmap_437[] =
ed91c385 1413 "\x04\xB1****\xF8\xF1**\xD9\xBF\xDA\xC0\xC5"
1414 "\xC4\xC4\xC4\xC4\xC4\xC3\xB4\xC1\xC2\xB3\xF3\xF2\xE3*\x9C\xFA";
374330e2 1415
59ad2c03 1416 /* CP850 */
1417 static const char oemmap_850[] =
1418 "\x04\xB1****\xF8\xF1**\xD9\xBF\xDA\xC0\xC5"
1419 "\xC4\xC4\xC4\xC4\xC4\xC3\xB4\xC1\xC2\xB3****\x9C\xFA";
1420
1421 /* Poor windows font ... eg: windows courier */
1422 static const char oemmap[] =
1423 "*\xB1****\xF8\xF1**\xD9\xBF\xDA\xC0\xC5"
1424 "\xC4\xC4\xC4\xC4\xC4\xC3\xB4\xC1\xC2\xB3****\x9C\xFA";
1425
374330e2 1426 /*
1427 * Line drawing mapping: map ` thru ~ (0x60 thru 0x7E) to
1428 * VT100 line drawing chars; everything else stays normal.
1429 */
1430 switch (cfg.vtmode) {
1431 case VT_XWINDOWS:
1432 for (i=0; i<len; i++)
1433 if (text[i] >= '\x60' && text[i] <= '\x7E')
1434 text[i] += '\x01' - '\x60';
1435 break;
1436 case VT_OEMANSI:
59ad2c03 1437 /* Make sure we actually have an OEM font */
1438 if (fonts[nfont|FONT_OEM]) {
374330e2 1439 case VT_OEMONLY:
59ad2c03 1440 nfont |= FONT_OEM;
1441 for (i=0; i<len; i++)
1442 if (text[i] >= '\x60' && text[i] <= '\x7E')
1443 text[i] = oemmap[(unsigned char)text[i] - 0x60];
1444 break;
1445 }
374330e2 1446 case VT_POORMAN:
1447 for (i=0; i<len; i++)
1448 if (text[i] >= '\x60' && text[i] <= '\x7E')
1449 text[i] = poorman[(unsigned char)text[i] - 0x60];
1450 break;
1451 }
1452 }
1453
1454 nfg = 2 * ((attr & ATTR_FGMASK) >> ATTR_FGSHIFT);
1455 nbg = 2 * ((attr & ATTR_BGMASK) >> ATTR_BGSHIFT);
1456 if (bold_mode == BOLD_FONT && (attr & ATTR_BOLD))
1457 nfont |= FONT_BOLD;
1458 if (und_mode == UND_FONT && (attr & ATTR_UNDER))
1459 nfont |= FONT_UNDERLINE;
59ad2c03 1460 if (!fonts[nfont])
1461 {
1462 if (nfont&FONT_UNDERLINE)
1463 force_manual_underline = 1;
1464 /* Don't do the same for manual bold, it could be bad news. */
1465
1466 nfont &= ~(FONT_BOLD|FONT_UNDERLINE);
1467 }
374330e2 1468 if (attr & ATTR_REVERSE) {
1469 t = nfg; nfg = nbg; nbg = t;
1470 }
1471 if (bold_mode == BOLD_COLOURS && (attr & ATTR_BOLD))
1472 nfg++;
59ad2c03 1473 if (bold_mode == BOLD_COLOURS && (attr & ATTR_BLINK))
1474 nbg++;
374330e2 1475 fg = colours[nfg];
1476 bg = colours[nbg];
1477 SelectObject (hdc, fonts[nfont]);
1478 SetTextColor (hdc, fg);
1479 SetBkColor (hdc, bg);
1480 SetBkMode (hdc, OPAQUE);
59ad2c03 1481 line_box.left = x;
1482 line_box.top = y;
c9def1b8 1483 line_box.right = x+fnt_width*len;
59ad2c03 1484 line_box.bottom = y+font_height;
1485 ExtTextOut (hdc, x, y, ETO_CLIPPED|ETO_OPAQUE, &line_box, text, len, IpDx);
374330e2 1486 if (bold_mode == BOLD_SHADOW && (attr & ATTR_BOLD)) {
1487 SetBkMode (hdc, TRANSPARENT);
59ad2c03 1488
1489 /* GRR: This draws the character outside it's box and can leave
1490 * 'droppings' even with the clip box! I suppose I could loop it
c9def1b8 1491 * one character at a time ... yuk.
1492 *
1493 * Or ... I could do a test print with "W", and use +1 or -1 for this
1494 * shift depending on if the leftmost column is blank...
1495 */
59ad2c03 1496 ExtTextOut (hdc, x-1, y, ETO_CLIPPED, &line_box, text, len, IpDx);
374330e2 1497 }
59ad2c03 1498 if (force_manual_underline ||
1499 (und_mode == UND_LINE && (attr & ATTR_UNDER))) {
1a6f78fe 1500 HPEN oldpen;
1501 oldpen = SelectObject (hdc, CreatePen(PS_SOLID, 0, fg));
374330e2 1502 MoveToEx (hdc, x, y+descent, NULL);
c9def1b8 1503 LineTo (hdc, x+len*fnt_width, y+descent);
1a6f78fe 1504 oldpen = SelectObject (hdc, oldpen);
1505 DeleteObject (oldpen);
374330e2 1506 }
1507 if (attr & ATTR_PASCURS) {
1508 POINT pts[5];
1a6f78fe 1509 HPEN oldpen;
374330e2 1510 pts[0].x = pts[1].x = pts[4].x = x;
c9def1b8 1511 pts[2].x = pts[3].x = x+fnt_width-1;
374330e2 1512 pts[0].y = pts[3].y = pts[4].y = y;
1513 pts[1].y = pts[2].y = y+font_height-1;
1a6f78fe 1514 oldpen = SelectObject (hdc, CreatePen(PS_SOLID, 0, colours[23]));
374330e2 1515 Polyline (hdc, pts, 5);
1a6f78fe 1516 oldpen = SelectObject (hdc, oldpen);
1517 DeleteObject (oldpen);
374330e2 1518 }
1519}
1520
c9def1b8 1521static int check_compose(int first, int second) {
1522
1523 static char * composetbl[] = {
1524