1 /*
2 * Copyright (C) 2001-2008 Scott Klement
3 *
4 * This file is part of TN5250
5 *
6 * TN5250 is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU Lesser General Public License as published by
8 * the Free Software Foundation; either version 2.1, or (at your option)
9 * any later version.
10 *
11 * TN5250 is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU Lesser General Public License for more details.
15 *
16 * You should have received a copy of the GNU Lesser General Public License
17 * along with this software; see the file COPYING. If not, write to
18 * the Free Software Foundation, Inc., 59 Temple Place, Suite 330,
19 * Boston, MA 02111-1307 USA
20 *
21 */
22
23 #define _TN5250_TERMINAL_PRIVATE_DEFINED
24 #include "tn5250-private.h"
25 #include "resource.h"
26
27 #define TN5250_WNDCLASS "tn5250-win32-terminal"
28 #define WM_TN5250_STREAM_DATA (WM_USER+2000)
29 #define WM_TN5250_KEY_DATA (WM_USER+2001)
30 #define MB_BEEPFILE (MB_OK+2000)
31
32 #define CARETSTYLE_BLINK 0
33 #define CARETSTYLE_LINE 1
34 #define CARETSTYLE_NOBLINK 2
35
36 #define COLSEPSTYLE_NONE 0
37 #define COLSEPSTYLE_FULL 1
38 #define COLSEPSTYLE_DOTS 2
39
40 /* Mapping of 5250 colors to windows colors */
41 struct _win32_color_map {
42 char *name;
43 COLORREF ref;
44 };
45 typedef struct _win32_color_map win32_color_map;
46
47 static win32_color_map colorlist[] =
48 {
49 { "green", RGB(0, 255, 0 ) },
50 { "white", RGB(255, 255, 255) },
51 { "red", RGB(255, 0, 0 ) },
52 { "turquoise", RGB(0, 128, 128) },
53 { "yellow", RGB(255, 255, 0 ) },
54 { "pink", RGB(255, 0, 255) },
55 { "blue", RGB(0, 255, 255) },
56 { "black", RGB(0, 0, 0 ) },
57 { "ruler_color", RGB(192, 0, 0 ) },
58 { NULL, -1 }
59 };
60
61 #define A_5250_GREEN 0
62 #define A_5250_WHITE 1
63 #define A_5250_RED 2
64 #define A_5250_TURQ 3
65 #define A_5250_YELLOW 4
66 #define A_5250_PINK 5
67 #define A_5250_BLUE 6
68 #define A_5250_BLACK 7
69 #define A_5250_RULER_COLOR 8
70
71
72 #define A_UNDERLINE 0x01
73 #define A_BLINK 0x02
74 #define A_NONDISPLAY 0x04
75 #define A_VERTICAL 0x08
76 #define A_REVERSE 0x10
77
78 struct _Tn5250Win32Attribute {
79 COLORREF fg;
80 int colorindex;
81 UINT flags;
82 };
83 typedef struct _Tn5250Win32Attribute Tn5250Win32Attribute;
84
85
86 static Tn5250Win32Attribute attribute_map[] =
87 {
88 { 0, A_5250_GREEN, 0 },
89 { 0, A_5250_GREEN, A_REVERSE },
90 { 0, A_5250_WHITE, 0 },
91 { 0, A_5250_WHITE, A_REVERSE },
92 { 0, A_5250_GREEN, A_UNDERLINE },
93 { 0, A_5250_GREEN, A_REVERSE|A_UNDERLINE },
94 { 0, A_5250_WHITE, A_UNDERLINE },
95 { 0, A_5250_BLACK, A_NONDISPLAY },
96 { 0, A_5250_RED, 0 },
97 { 0, A_5250_RED, A_REVERSE },
98 { 0, A_5250_RED, A_BLINK },
99 { 0, A_5250_RED, A_REVERSE|A_BLINK },
100 { 0, A_5250_RED, A_UNDERLINE },
101 { 0, A_5250_RED, A_REVERSE|A_UNDERLINE },
102 { 0, A_5250_RED, A_UNDERLINE|A_BLINK },
103 { 0, A_5250_BLACK, A_NONDISPLAY },
104 { 0, A_5250_TURQ, A_VERTICAL },
105 { 0, A_5250_TURQ, A_REVERSE|A_VERTICAL },
106 { 0, A_5250_YELLOW,A_VERTICAL },
107 { 0, A_5250_YELLOW,A_REVERSE|A_VERTICAL },
108 { 0, A_5250_TURQ, A_VERTICAL|A_UNDERLINE },
109 { 0, A_5250_TURQ, A_REVERSE|A_VERTICAL|A_UNDERLINE },
110 { 0, A_5250_YELLOW,A_VERTICAL|A_UNDERLINE },
111 { 0, A_5250_BLACK, A_REVERSE|A_NONDISPLAY },
112 { 0, A_5250_PINK, 0 },
113 { 0, A_5250_PINK, A_REVERSE },
114 { 0, A_5250_BLUE, 0 },
115 { 0, A_5250_BLUE, A_REVERSE },
116 { 0, A_5250_PINK, A_UNDERLINE },
117 { 0, A_5250_PINK, A_REVERSE|A_UNDERLINE },
118 { 0, A_5250_BLUE, A_UNDERLINE },
119 { 0, A_5250_BLACK, A_NONDISPLAY },
120 { -1, -1, -1 },
121 };
122
123 static HFONT font_80;
124 static HFONT font_132;
125 static HBITMAP screenbuf;
126 static Tn5250Terminal *globTerm = NULL;
127 static Tn5250Display *globDisplay = NULL;
128 static HDC bmphdc;
129 static HBITMAP caretbm;
130 static HBRUSH background_brush;
131 static int colsep_style = COLSEPSTYLE_FULL;
132
133 static void win32_terminal_init(Tn5250Terminal * This);
134 static void win32_terminal_term(Tn5250Terminal * This);
135 static void win32_terminal_destroy(Tn5250Terminal *This);
136 void tn5250_win32_init_fonts (Tn5250Terminal *This,
137 const char *myfont80, const char *myfont132);
138 static void win32_terminal_font(Tn5250Terminal *This, const char *fontname,
139 int cols, int rows, int fontwidth, int fontheight);
140 void win32_parse_fontspec(const char *fontspec, char *fontname,
141 int maxlen, int *w, int *h);
142 void win32_calc_default_font_size(HWND hwnd,
143 int cols, int rows, int *w, int *h);
144 static int win32_terminal_width(Tn5250Terminal * This);
145 static int win32_terminal_height(Tn5250Terminal * This);
146 static int win32_terminal_flags(Tn5250Terminal * This);
147 static void win32_terminal_update(Tn5250Terminal * This,
148 Tn5250Display * display);
149 static void win32_terminal_update_indicators(Tn5250Terminal * This,
150 Tn5250Display * display);
151 static int win32_terminal_set_config(Tn5250Terminal *This, Tn5250Config *conf);
152 static int win32_terminal_waitevent(Tn5250Terminal * This);
153 static int win32_terminal_getkey(Tn5250Terminal * This);
154 void win32_terminal_queuekey(HWND hwnd, Tn5250Terminal *This, int key);
155 void win32_terminal_clear_screenbuf(HWND hwnd,int width,int height,
156 int delet, int mknew);
157 void tn5250_win32_set_beep (Tn5250Terminal *This, const char *beepfile);
158 void tn5250_win32_terminal_display_ruler (Tn5250Terminal *This, int f);
159 static void win32_terminal_beep(Tn5250Terminal * This);
160 void win32_terminal_draw_text(HDC hdc, int attr, const char *text, int len, int x, int y, int *spacing, Tn5250Win32Attribute *map, int ox, int oy);
161 LRESULT CALLBACK
162 win32_terminal_wndproc( HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam);
163 void win32_make_new_caret(Tn5250Terminal *This);
164 void win32_move_caret(HDC hdc, Tn5250Terminal *This);
165 void win32_hide_caret(HDC hdc, Tn5250Terminal *This);
166 void win32_expand_text_selection(Tn5250Terminal *This);
167 void win32_copy_text_selection(Tn5250Terminal *This, Tn5250Display *display);
168 void win32_paste_text_selection(HWND hwnd, Tn5250Terminal *term,
169 Tn5250Display *display);
170 PRINTDLG * win32_get_printer_info(Tn5250Terminal *This);
171 void win32_destroy_printer_info(Tn5250Terminal *This);
172 void win32_print_screen(Tn5250Terminal *This, Tn5250Display *display);
173 static void win32_do_terminal_update(HDC hdc, Tn5250Terminal *This,
174 Tn5250Display *display, Tn5250Win32Attribute *map,
175 int ox, int oy);
176 void win32_move_caret_to(Tn5250Terminal *This, Tn5250Display *disp,
177 short y, short x);
178 static int setNumLock(int state);
179
180 extern void msgboxf(const char *fmt, ...);
181
182 struct _MY_POINT {
183 int x;
184 int y;
185 };
186 typedef struct _MY_POINT MY_POINT;
187
188
189 #define MAX_K_BUF_LEN 64
190 struct _Tn5250TerminalPrivate {
191 HINSTANCE hInst;
192 HINSTANCE hPrev;
193 HWND hwndMain;
194 HFONT font;
195 unsigned int beeptype;
196 char * beepfile;
197 int show;
198 int last_width, last_height;
199 char * font_80;
200 int font_80_h;
201 int font_80_w;
202 char * font_132;
203 int font_132_h;
204 int font_132_w;
205 LOGFONT font_in_use;
206 DWORD k_buf[MAX_K_BUF_LEN];
207 int k_buf_len;
208 int font_height;
209 int font_width;
210 int caretx;
211 int carety;
212 int caretok;
213 MY_POINT selstr;
214 MY_POINT selend;
215 int * spacing;
216 Tn5250Config * config;
217 BYTE copymode;
218 BYTE caret_style;
219 PRINTDLG * pd;
220 int resized : 1;
221 int quit_flag : 1;
222 int display_ruler : 1;
223 int is_focused : 1;
224 int selecting: 1;
225 int selected: 1;
226 int maximized: 1;
227 int dont_auto_size: 1;
228 int unix_like_copy: 1;
229 int resize_fonts: 1;
230 int local_print: 1;
231 int always_ask: 1;
232 int click_moves_caret: 1;
233 };
234
235
236 /*
237 * This array converts windows "keystrokes" into character messages
238 * for those that aren't handled by the "TranslateMessage" function.
239 *
240 * The smaller this array is, the better the keyboard handling will
241 * perform :)
242 *
243 */
244
245 typedef struct _func_key {
246 SHORT keystate;
247 DWORD win32_key;
248 DWORD func_key;
249 BYTE ctx;
250 BYTE ext;
251 } keystroke_to_msg;
252
253 static keystroke_to_msg keydown2msg[] =
254 {
255 /* KeyState Win32 VirtKey 5250 key ctx ext */
256 { VK_SHIFT, VK_TAB, K_BACKTAB, 0, 0 },
257 { VK_SHIFT, VK_F1, K_F13 , 0, 0 },
258 { VK_SHIFT, VK_F2, K_F14 , 0, 0 },
259 { VK_SHIFT, VK_F3, K_F15 , 0, 0 },
260 { VK_SHIFT, VK_F4, K_F16 , 0, 0 },
261 { VK_SHIFT, VK_F5, K_F17 , 0, 0 },
262 { VK_SHIFT, VK_F6, K_F18 , 0, 0 },
263 { VK_SHIFT, VK_F7, K_F19 , 0, 0 },
264 { VK_SHIFT, VK_F8, K_F20 , 0, 0 },
265 { VK_SHIFT, VK_F9, K_F21 , 0, 0 },
266 { VK_SHIFT, VK_F10, K_F22 , 0, 0 },
267 { VK_SHIFT, VK_F11, K_F23 , 0, 0 },
268 { VK_SHIFT, VK_F12, K_F24 , 0, 0 },
269 { VK_SHIFT, VK_INSERT, K_PASTE_TEXT, 0, 1 },
270 { VK_SHIFT, VK_DELETE, K_COPY_TEXT, 0, 1 },
271 { VK_CONTROL, VK_LEFT, K_PREVFLD, 0, 1 },
272 { VK_CONTROL, VK_RIGHT, K_NEXTFLD, 0, 1 },
273 { VK_SHIFT, K_ENTER, K_NEWLINE, 0, 1 },
274 { 0, VK_F1, K_F1 , 0, 0 },
275 { 0, VK_F2, K_F2 , 0, 0 },
276 { 0, VK_F3, K_F3 , 0, 0 },
277 { 0, VK_F4, K_F4 , 0, 0 },
278 { 0, VK_F5, K_F5 , 0, 0 },
279 { 0, VK_F6, K_F6 , 0, 0 },
280 { 0, VK_F7, K_F7 , 0, 0 },
281 { 0, VK_F8, K_F8 , 0, 0 },
282 { 0, VK_F9, K_F9 , 0, 0 },
283 { 0, VK_F10, K_F10 , 0, 0 },
284 { 0, VK_F11, K_F11 , 0, 0 },
285 { 0, VK_F12, K_F12 , 0, 0 },
286 { 0, VK_PRIOR, K_ROLLDN , 0, 1 },
287 { 0, VK_NEXT, K_ROLLUP , 0, 1 },
288 { 0, VK_UP, K_UP , 0, 1 },
289 { 0, VK_DOWN, K_DOWN , 0, 1 },
290 { 0, VK_LEFT, K_LEFT , 0, 1 },
291 { 0, VK_RIGHT, K_RIGHT , 0, 1 },
292 { 0, VK_INSERT, K_INSERT , 0, 1 },
293 { 0, VK_DELETE, K_DELETE , 0, 1 },
294 { 0, VK_HOME, K_HOME , 0, 1 },
295 { 0, VK_END, K_END , 0, 1 },
296 { 0, VK_ADD, K_FIELDPLUS , 0, 0 },
297 { 0, VK_SUBTRACT, K_FIELDMINUS , 0, 0 },
298 { 0, VK_SCROLL, K_HELP , 0, 0 },
299 { -1, -1, -1, -1, -1 },
300 };
301
302 static keystroke_to_msg keyup2msg[] =
303 {
304 /* KeyState Win32 VirtKey 5250 key ctx ext */
305 { 0, VK_CONTROL, K_RESET , 0, 0 },
306 { 0, VK_CONTROL, K_FIELDEXIT, 0, 1 },
307 { VK_MENU, VK_SNAPSHOT, K_SYSREQ, 1, 0 },
308 { 0, VK_SNAPSHOT, K_PRINT, 1, 0 },
309 { -1, -1 },
310 };
311
312 /*
313 * This array translates Windows "Character messages" into 5250
314 * keys. Some function keys are not available as character messages,
315 * so those need to be handled in the array above.
316 *
317 */
318 typedef struct _key_map {
319 DWORD win32_key;
320 DWORD tn5250_key;
321 } win32_key_map;
322
323 static win32_key_map win_kb[] =
324 {
325 /* Win32 CharMsg 5250 key */
326 { 0x01, K_ATTENTION }, /* CTRL-A */
327 { 0x02, K_ROLLDN }, /* CTRL-B */
328 { 0x03, K_COPY_TEXT }, /* CTRL-C */
329 { 0x04, K_ROLLUP }, /* CTRL-D */
330 { 0x05, K_ERASE }, /* CTRL-E */
331 { 0x06, K_ROLLUP }, /* CTRL-F */
332 { VK_BACK,K_BACKSPACE }, /* CTRL-H (backspace key) */
333 { 0x0b, K_FIELDEXIT }, /* CTRL-K */
334 { 0x0c, K_REFRESH }, /* CTRL-L */
335 { 0x0f, K_HOME }, /* CTRL-O */
336 { 0x10, K_PRINT }, /* CTRL-P */
337 { 0x12, K_RESET }, /* CTRL-R */
338 { 0x13, K_MEMO }, /* CTRL-S */
339 { 0x14, K_TESTREQ }, /* CTRL-T */
340 { 0x15, K_ROLLDN }, /* CTRL-U */
341 { 0x16, K_PASTE_TEXT }, /* Ctrl-V */
342 { 0x17, K_EXEC }, /* Ctrl-W */
343 { 0x18, K_FIELDPLUS }, /* CTRL-X */
344 { 0x1b, K_ATTENTION }, /* ESCAPE */
345 { -1, -1 },
346 };
347
348
349 /****f* lib5250/tn5250_win32_terminal_new
350 * NAME
351 * tn5250_win32_terminal_enhanced
352 * SYNOPSIS
353 * ret = tn5250_win32_terminal_enhanced (This);
354 * INPUTS
355 * None
356 * DESCRIPTION
357 * Disallow support of the enhanced protocol
358 *****/
tn5250_win32_terminal_enhanced(Tn5250Terminal * This)359 static int tn5250_win32_terminal_enhanced(Tn5250Terminal * This)
360 {
361 return 0;
362 }
363
364 /****f* lib5250/tn5250_win32_terminal_new
365 * NAME
366 * tn5250_win32_terminal_new
367 * SYNOPSIS
368 * ret = tn5250_win32_terminal_new ();
369 * INPUTS
370 * None
371 * DESCRIPTION
372 * Create a new Windows terminal object
373 *****/
tn5250_win32_terminal_new(HINSTANCE hInst,HINSTANCE hPrev,int show)374 Tn5250Terminal *tn5250_win32_terminal_new(HINSTANCE hInst,
375 HINSTANCE hPrev, int show)
376 {
377 Tn5250Terminal *r = tn5250_new(Tn5250Terminal, 1);
378 if (r == NULL)
379 return NULL;
380
381 r->data = tn5250_new(struct _Tn5250TerminalPrivate, 1);
382 if (r->data == NULL) {
383 free(r);
384 return NULL;
385 }
386
387 r->data->hInst = hInst;
388 r->data->hPrev = hPrev;
389 r->data->show = show;
390 r->data->beeptype = MB_OK;
391 r->data->beepfile = NULL;
392 r->data->quit_flag = 0;
393 r->data->last_width = 0;
394 r->data->last_height = 0;
395 r->data->font_80 = NULL;
396 r->data->font_80_h = 0;
397 r->data->font_80_w = 0;
398 r->data->font_132 = NULL;
399 r->data->font_132_h = 0;
400 r->data->font_132_w = 0;
401 memset(&r->data->font_in_use, 0, sizeof(r->data->font_in_use));
402 r->data->display_ruler = 0;
403 r->data->spacing = NULL;
404 r->data->caretx = 0;
405 r->data->caretok = 0;
406 r->data->carety = 0;
407 r->data->quit_flag = 0;
408 r->data->k_buf_len = 0;
409 r->data->selstr.x = 0;
410 r->data->selstr.y = 0;
411 r->data->selend.x = 0;
412 r->data->selend.y = 0;
413 r->data->selecting = 0;
414 r->data->selected = 0;
415 r->data->copymode = 0;
416 r->data->config = NULL;
417 r->data->maximized = 0;
418 r->data->dont_auto_size = 0;
419 r->data->unix_like_copy = 0;
420 r->data->click_moves_caret = 0;
421 r->data->resize_fonts = 0;
422 r->data->local_print = 0;
423 r->data->always_ask = 0;
424 r->data->caret_style = CARETSTYLE_NOBLINK;
425 r->data->pd = NULL;
426
427 r->conn_fd = -1;
428 r->init = win32_terminal_init;
429 r->term = win32_terminal_term;
430 r->destroy = win32_terminal_destroy;
431 r->width = win32_terminal_width;
432 r->height = win32_terminal_height;
433 r->flags = win32_terminal_flags;
434 r->update = win32_terminal_update;
435 r->update_indicators = win32_terminal_update_indicators;
436 r->waitevent = win32_terminal_waitevent;
437 r->getkey = win32_terminal_getkey;
438 r->putkey = NULL;
439 r->beep = win32_terminal_beep;
440 r->config = win32_terminal_set_config;
441 r->enhanced = tn5250_win32_terminal_enhanced;
442 r->create_window = NULL;
443 r->destroy_window = NULL;
444 r->create_scrollbar = NULL;
445 r->destroy_scrollbar = NULL;
446 return r;
447 }
448
449
450 /****i* lib5250/win32_terminal_init
451 * NAME
452 * win32_terminal_init
453 * SYNOPSIS
454 * win32_terminal_init (This);
455 * INPUTS
456 * Tn5250Terminal * This -
457 * DESCRIPTION
458 * DOCUMENT ME!!!
459 *****/
win32_terminal_init(Tn5250Terminal * This)460 static void win32_terminal_init(Tn5250Terminal * This)
461 {
462 int i = 0, c, s;
463 struct timeval tv;
464 char *str;
465 HDC hdc;
466 RECT rect;
467 int height, width;
468 int len;
469 char *title;
470 int r, g, b;
471 LOGBRUSH lb;
472 const char *cs;
473
474 WNDCLASSEX wndclass;
475
476 This->data->spacing = NULL;
477 This->data->caretx = 0;
478 This->data->caretok = 0;
479 This->data->carety = 0;
480 This->data->quit_flag = 0;
481 This->data->k_buf_len = 0;
482 This->data->copymode = 0;
483 This->data->pd = NULL;
484 globTerm = This;
485
486 if (This->data->config != NULL) {
487
488 if (tn5250_config_get_bool(This->data->config, "local_print_key"))
489 This->data->local_print = 1;
490
491 if (tn5250_config_get_bool(This->data->config, "always_ask"))
492 This->data->always_ask = 1;
493
494 if (tn5250_config_get(This->data->config, "copymode")) {
495 if (!strcasecmp(tn5250_config_get(This->data->config,"copymode"),
496 "text"))
497 This->data->copymode = 1;
498 if (!strcasecmp(tn5250_config_get(This->data->config,"copymode"),
499 "bitmap"))
500 This->data->copymode = 2;
501 }
502
503
504 if (tn5250_config_get (This->data->config, "ruler")) {
505 tn5250_win32_terminal_display_ruler(This,
506 tn5250_config_get_bool (This->data->config, "ruler"));
507 }
508
509 if ( tn5250_config_get (This->data->config, "pcspeaker"))
510 tn5250_win32_set_beep(This, "!!PCSPEAKER!!");
511 else
512 tn5250_win32_set_beep(This,
513 tn5250_config_get (This->data->config, "beepfile"));
514
515 if ( tn5250_config_get (This->data->config, "unix_like_copy")) {
516 This->data->unix_like_copy =
517 tn5250_config_get_bool(This->data->config, "unix_like_copy");
518 }
519
520 if ( tn5250_config_get (This->data->config, "click_moves_cursor")) {
521 This->data->click_moves_caret =
522 tn5250_config_get_bool(This->data->config, "click_moves_cursor");
523 }
524
525 if ( tn5250_config_get (This->data->config, "resize_fonts")) {
526 This->data->resize_fonts =
527 tn5250_config_get_bool(This->data->config, "resize_fonts");
528 }
529
530 if ( (cs=tn5250_config_get (This->data->config, "colsep_style"))) {
531 if (!strcmp(cs, "full")) {
532 colsep_style = COLSEPSTYLE_FULL;
533 } else if (!strcmp(cs, "dots")) {
534 colsep_style = COLSEPSTYLE_DOTS;
535 } else if (!strcmp(cs, "none")) {
536 colsep_style = COLSEPSTYLE_NONE;
537 }
538 }
539
540 if (tn5250_config_get_bool(This->data->config, "no_colseps")) {
541 colsep_style = COLSEPSTYLE_NONE;
542 }
543
544 if ( (cs=tn5250_config_get (This->data->config, "caret_style"))) {
545 if (!strcmp(cs, "line")) {
546 This->data->caret_style = CARETSTYLE_LINE;
547 }
548 else if (!strcmp(cs, "blink")) {
549 This->data->caret_style = CARETSTYLE_BLINK;
550 }
551 }
552
553 /* FIXME: This opt should not exist when we have full keyboard mapping */
554 if ( tn5250_config_get_bool (This->data->config, "unix_sysreq") ) {
555 i=0;
556 while (win_kb[i].win32_key != -1) {
557 if (win_kb[i].win32_key == 0x03) {
558 win_kb[i].tn5250_key = K_SYSREQ;
559 break;
560 }
561 i++;
562 }
563 }
564
565
566 /* set color list for black on white */
567
568 if (tn5250_config_get_bool(This->data->config, "black_on_white")) {
569 for (i=A_5250_GREEN; i<A_5250_BLACK; i++)
570 colorlist[i].ref = RGB(0,0,0);
571 colorlist[A_5250_BLACK].ref = RGB(255,255,255);
572 }
573
574
575 /* set color list for black on white */
576
577 if (tn5250_config_get_bool(This->data->config, "white_on_black")) {
578 for (i=A_5250_GREEN; i<A_5250_BLACK; i++)
579 colorlist[i].ref = RGB(255,255,255);
580 colorlist[A_5250_BLACK].ref = RGB(0,0,0);
581 }
582
583
584 /* load any colors from the config file & set the attribute map */
585
586 i = 0;
587 while (colorlist[i].name != NULL) {
588 if (tn5250_parse_color(This->data->config, colorlist[i].name,
589 &r, &g, &b)!=-1) {
590 colorlist[i].ref = RGB(r, g, b);
591 }
592 TN5250_LOG(("color %d (%s) = %02x%02x%02x\n", i, colorlist[i].name,
593 colorlist[i].ref&0xff, (colorlist[i].ref>>8)&0xff,
594 (colorlist[i].ref>>16)&0xff));
595 i++;
596 }
597 i = 0;
598 while (attribute_map[i].colorindex != -1) {
599 attribute_map[i].fg = colorlist[attribute_map[i].colorindex].ref;
600 i++;
601 }
602
603 }
604
605 lb.lbStyle = BS_SOLID;
606 lb.lbColor = colorlist[A_5250_BLACK].ref;
607 lb.lbHatch = 0;
608 background_brush = CreateBrushIndirect(&lb);
609
610
611 if ( tn5250_config_get (This->data->config, "host") ) {
612 if ( tn5250_config_get (This->data->config, "env.DEVNAME") ) {
613 len = strlen(tn5250_config_get(This->data->config,"host"));
614 len += strlen(tn5250_config_get(This->data->config,"env.DEVNAME"));
615 len += strlen("tn5250 - x - x");
616 title = malloc(len+1);
617 sprintf(title, "tn5250 - %s - %s",
618 tn5250_config_get(This->data->config, "env.DEVNAME"),
619 tn5250_config_get(This->data->config, "host"));
620 }
621 else {
622 len = strlen("tn5250 - x");
623 len += strlen(tn5250_config_get(This->data->config, "host"));
624 title = malloc(len+1);
625 sprintf(title, "tn5250 - %s",
626 tn5250_config_get(This->data->config, "host"));
627 }
628 }
629 else {
630 len = strlen("tn5250");
631 title = malloc(len+1);
632 strcpy(title, "tn5250");
633 }
634
635 /* build a Window Class */
636
637 memset (&wndclass, 0, sizeof(WNDCLASSEX));
638 wndclass.lpszClassName = TN5250_WNDCLASS;
639 wndclass.lpszMenuName = "tn5250-win32-menu";
640 wndclass.cbSize = sizeof(WNDCLASSEX);
641 wndclass.style = CS_HREDRAW | CS_VREDRAW;
642 wndclass.lpfnWndProc = win32_terminal_wndproc;
643 wndclass.hInstance = This->data->hInst;
644 wndclass.hIcon = LoadIcon (This->data->hInst, MAKEINTRESOURCE(IDI_TN5250_ICON));
645 wndclass.hIconSm = LoadIcon (This->data->hInst, MAKEINTRESOURCE(IDI_TN5250_ICON));
646 wndclass.hCursor = LoadCursor (NULL, IDC_ARROW);
647 wndclass.hbrBackground = background_brush;
648 RegisterClassEx (&wndclass);
649
650 /* create our main window */
651 This->data->hwndMain = CreateWindow (TN5250_WNDCLASS,
652 title,
653 This->data->resize_fonts ? WS_OVERLAPPEDWINDOW : (WS_OVERLAPPEDWINDOW&(~WS_MAXIMIZEBOX)),
654 CW_USEDEFAULT,
655 CW_USEDEFAULT,
656 CW_USEDEFAULT,
657 CW_USEDEFAULT,
658 NULL,
659 NULL,
660 This->data->hInst,
661 NULL
662 );
663 free(title);
664
665
666 /* create a bitmap act as a screen buffer. we will draw all of
667 our data to this buffer, then BitBlt it to the screen when we
668 need to re-draw the screen. This'll make it easy for us to
669 re-paint sections of the screen when necessary */
670
671 GetClientRect(This->data->hwndMain, &rect);
672 width = (rect.right - rect.left) + 1;
673 height = (rect.bottom - rect.top) + 1;
674 bmphdc = CreateCompatibleDC(NULL);
675 win32_terminal_clear_screenbuf(This->data->hwndMain, width, height, 0, 1);
676
677 tn5250_win32_init_fonts(This,
678 tn5250_config_get(This->data->config, "font_80"),
679 tn5250_config_get(This->data->config, "font_132"));
680
681 ShowWindow (This->data->hwndMain, This->data->show);
682 UpdateWindow (This->data->hwndMain);
683
684 if ( tn5250_config_get (This->data->config, "numlock") )
685 setNumLock(tn5250_config_get_bool(This->data->config, "numlock"));
686
687 /* FIXME: This might be a nice place to load the keyboard map */
688
689 }
690
setNumLock(int state)691 static int setNumLock(int state) {
692
693 BYTE keys[256];
694 int curstate;
695 memset(keys, 0, sizeof(keys));
696
697 /* ---- Get the current num-lock state ---- */
698
699 if (!GetKeyboardState(keys))
700 return -1;
701
702 curstate = keys[VK_NUMLOCK] ? 1 : 0;
703
704 /* ---- If it needs to toggle, send keypress as if the actual
705 key was pressed on the keyboard ---- */
706
707 if (state != curstate) {
708 keybd_event( VK_NUMLOCK,
709 0x45,
710 KEYEVENTF_EXTENDEDKEY,
711 0);
712 keybd_event( VK_NUMLOCK,
713 0x45,
714 KEYEVENTF_EXTENDEDKEY|KEYEVENTF_KEYUP,
715 0);
716 }
717
718 return 0;
719 }
720
721
722
723 /****i* lib5250/win32_terminal_set_config
724 * NAME
725 * win32_terminal_set_config
726 * SYNOPSIS
727 * win32_terminal_set_config (This, config);
728 * INPUTS
729 * Tn5250Terminal * This - The win32 terminal object.
730 * Tn5250Config * conf - config object
731 * DESCRIPTION
732 * Associates a config object with the terminal object
733 *****/
win32_terminal_set_config(Tn5250Terminal * This,Tn5250Config * conf)734 static int win32_terminal_set_config(Tn5250Terminal *This, Tn5250Config *conf)
735 {
736
737 This->data->config = conf;
738 if (conf==NULL) return -1;
739 return 0;
740 }
741
742
743 /****i* lib5250/tn5250_win32_terminal_display_ruler
744 * NAME
745 * tn5250_win32_terminal_display_ruler
746 * SYNOPSIS
747 * tn5250_win32_terminal_display_ruler (This, f);
748 * INPUTS
749 * Tn5250Terminal * This - The win32 terminal object.
750 * int f - Flag, set to 1 to show ruler
751 * DESCRIPTION
752 * Call this function to tell the Win32 terminal to display a
753 * "ruler" that pinpoints where the cursor is on a given screen.
754 *****/
tn5250_win32_terminal_display_ruler(Tn5250Terminal * This,int f)755 void tn5250_win32_terminal_display_ruler (Tn5250Terminal *This, int f)
756 {
757 This->data->display_ruler = f;
758 }
759
760
761 /****i* lib5250/tn5250_win32_set_beep
762 * NAME
763 * tn5250_win32_set_beep
764 * SYNOPSIS
765 * tn5250_win32_set_beep
766 * INPUTS
767 * Tn5250Terminal * This - The win32 terminal object.
768 * const char * beepfile - \path\to\file.wav
769 * DESCRIPTION
770 * Call this function to change how a beep works. If you send
771 * a NULL, we use the standard windows "SystemDefault" beep sound.
772 * If you send a "!!PCSPEAKER!!", we use the PC speaker instead.
773 * Otherwise, the filename will be a .wav file to be played.
774 * (deluxe, eh?)
775 *****/
tn5250_win32_set_beep(Tn5250Terminal * This,const char * beepfile)776 void tn5250_win32_set_beep (Tn5250Terminal *This, const char *beepfile)
777 {
778 if (This->data->beepfile != NULL)
779 free(This->data->beepfile);
780
781 if (beepfile==NULL)
782 This->data->beeptype = MB_OK;
783 else if (!strcmp(beepfile, "!!PCSPEAKER!!"))
784 This->data->beeptype = 0xFFFFFFFF;
785 else {
786 This->data->beeptype = MB_BEEPFILE;
787 This->data->beepfile = malloc(strlen(beepfile)+1);
788 strcpy(This->data->beepfile, beepfile);
789 }
790
791 }
792
793
794 /****i* lib5250/tn5250_win32_init_fonts
795 * NAME
796 * tn5250_win32_init_fonts
797 * SYNOPSIS
798 * tn5250_win32_init_fonts (This, font80, font132);
799 * INPUTS
800 * Tn5250Terminal * This - win32 terminal object
801 * const char * font80 - string to send when using 80 col font
802 * const char * font132 - string to send when using 132 col font
803 * DESCRIPTION
804 * DOCUMENT ME!!!
805 *****/
tn5250_win32_init_fonts(Tn5250Terminal * This,const char * myfont80,const char * myfont132)806 void tn5250_win32_init_fonts (Tn5250Terminal *This,
807 const char *myfont80, const char *myfont132)
808 {
809 int size;
810 int h, w;
811 int default_h, default_w;
812
813 win32_calc_default_font_size(This->data->hwndMain,
814 80, 25, &default_w, &default_h);
815
816 if (myfont80 != NULL) {
817 size = strlen(myfont80) + 1;
818 if (This->data->font_80)
819 free(This->data->font_80);
820 This->data->font_80 = malloc(size+1);
821 win32_parse_fontspec(myfont80, This->data->font_80, size, &w, &h);
822 This->data->font_80_h = h;
823 This->data->font_80_w = w;
824 } else {
825 This->data->font_80 = NULL;
826 This->data->font_80_h = 0;
827 This->data->font_80_w = 0;
828 }
829
830 if (This->data->font_80_h == 0 && This->data->font_80_w == 0) {
831 This->data->font_80_h = default_h;
832 This->data->font_80_w = default_w;
833 }
834
835 win32_terminal_font(This, This->data->font_80, 80, 25, This->data->font_80_w, This->data->font_80_h);
836
837 if (myfont132 != NULL) {
838 size = strlen(myfont132) + 1;
839 if (This->data->font_132)
840 free(This->data->font_132);
841 This->data->font_132 = malloc(size+1);
842 win32_parse_fontspec(myfont132, This->data->font_132, size, &w, &h);
843 This->data->font_132_h = h;
844 This->data->font_132_w = w;
845 } else {
846 This->data->font_132 = NULL;
847 if (This->data->font_80!=NULL) {
848 This->data->font_132 = malloc(strlen(This->data->font_80)+1);
849 strcpy(This->data->font_132, This->data->font_80);
850 }
851 This->data->font_132_h = This->data->font_80_h;
852 This->data->font_132_w = This->data->font_80_w;
853 }
854
855 if (This->data->font_132_h == 0 && This->data->font_132_w == 0) {
856 This->data->font_132_h = default_h;
857 This->data->font_132_w = default_w;
858 }
859 }
860
861
862 /****i* lib5250/win32_parse_fontspec
863 * NAME
864 * win32_parse_fontspec
865 * SYNOPSIS
866 * win32_parse_fontspec ("System-5x10", fontname, sizeof(fontname), &w &h);
867 * INPUTS
868 * const char * fontspec -
869 * char * fontname -
870 * int maxlen -
871 * int * w -
872 * int * h -
873 * DESCRIPTION
874 * DOCUMENT ME!!!
875 *****/
win32_parse_fontspec(const char * fontspec,char * fontname,int maxlen,int * w,int * h)876 void win32_parse_fontspec(const char *fontspec, char *fontname,
877 int maxlen, int *w, int *h) {
878
879 const char *p;
880 char height[11], width[11];
881 char ch;
882 int namelen = 0;
883 int widthlen = 0;
884 int heightlen = 0;
885 int state = 0;
886
887 p = fontspec;
888 *width = '\0';
889 *height = '\0';
890 *fontname = '\0';
891
892 while (*p) {
893 ch = *p;
894 switch (state) {
895 case 0:
896 if (ch == ' ')
897 break;
898 else
899 state++;
900 /* FALLTHROUGH */
901
902 case 1:
903 if (ch == '-') {
904 state++;
905 } else if (namelen<maxlen) {
906 namelen++;
907 fontname[namelen-1] = ch;
908 fontname[namelen] = '\0';
909 }
910 break;
911
912 case 2:
913 if (ch == 'x' || ch == 'X') {
914 state++;
915 } else if (widthlen < sizeof(width)) {
916 widthlen ++;
917 width[widthlen-1] = ch;
918 width[widthlen] = '\0';
919 }
920 break;
921
922 case 3:
923 if (ch == 'x' || ch == 'X') {
924 state++;
925 } else if (heightlen < sizeof(height)) {
926 heightlen ++;
927 height[heightlen-1] = ch;
928 height[heightlen] = '\0';
929 }
930 break;
931 }
932
933 p++;
934 }
935
936 *h = atoi(height);
937 *w = atoi(width);
938
939 TN5250_LOG(("WIN32: font name=%s, height=%d, width=%d\n", fontname,*h,*w));
940 return;
941 }
942
943
944 /****i* lib5250/win32_calc_default_font_size
945 * NAME
946 * win32_calc_default_font_size
947 * SYNOPSIS
948 * win32_calc_default_font_size (hwnd, cols, rows, &w, &h);
949 * INPUTS
950 * HWND hwnd -
951 * int cols -
952 * int rows -
953 * int * w -
954 * int * h -
955 * DESCRIPTION
956 * DOCUMENT ME!!!
957 *****/
win32_calc_default_font_size(HWND hwnd,int cols,int rows,int * w,int * h)958 void win32_calc_default_font_size(HWND hwnd,
959 int cols, int rows, int *w, int *h) {
960
961 RECT cr;
962 int cli_height, cli_width;
963
964 if (!GetClientRect(hwnd, &cr))
965 return;
966
967 TN5250_LOG(("WIN32: Rows = %d, Cols = %d\n", rows, cols));
968 TN5250_LOG(("WIN32: Client Rect top=%d, bottom=%d, left=%d, right=%d\n",
969 cr.top, cr.bottom, cr.left, cr.right));
970
971 cli_height = (cr.bottom - cr.top) + 1;
972 cli_width = (cr.right - cr.left) + 1;
973
974 *h = cli_height / rows;
975 *w = cli_width / cols;
976
977 TN5250_LOG(("WIN32: defaulting font size to height=%d, width=%d\n",*h,*w));
978
979 return;
980 }
981
982
983 /****i* lib5250/win32_terminal_font
984 * NAME
985 * win32_terminal_font
986 * SYNOPSIS
987 * win32_terminal_font (This, "Terminal", 80, 24, 8, 16);
988 * INPUTS
989 * Tn5250Terminal * This - The win32 terminal object.
990 * const char * fontname - name of font to try
991 * int cols - number of screen cols to size font for
992 * int rows - number of screen rows to size font for
993 * int fontwidth - width of the font
994 * int fontheight - height of the font
995 * DESCRIPTION
996 * This takes the font name, height & width that you pass
997 * and finds the closest match on the system. It then
998 * re-sizes the terminal window to the size of the font
999 * that it used.
1000 *****/
win32_terminal_font(Tn5250Terminal * This,const char * fontname,int cols,int rows,int fontwidth,int fontheight)1001 static void win32_terminal_font(Tn5250Terminal *This, const char *fontname,
1002 int cols, int rows, int fontwidth, int fontheight) {
1003
1004 int cli_height, cli_width;
1005 int win_height, win_width;
1006 RECT cr, wr;
1007 HDC hdc;
1008 TEXTMETRIC tm;
1009 HFONT oldfont;
1010
1011
1012 /* create a font using the size from our config data */
1013
1014 hdc = GetDC(This->data->hwndMain);
1015 This->data->font_in_use.lfHeight = fontheight;
1016 This->data->font_in_use.lfWidth = fontwidth;
1017 This->data->font_in_use.lfEscapement = 0;
1018 This->data->font_in_use.lfOrientation = 0;
1019 This->data->font_in_use.lfWeight = FW_DONTCARE;
1020 This->data->font_in_use.lfItalic = FALSE;
1021 This->data->font_in_use.lfUnderline = FALSE;
1022 This->data->font_in_use.lfStrikeOut = FALSE;
1023 This->data->font_in_use.lfCharSet = DEFAULT_CHARSET;
1024 This->data->font_in_use.lfOutPrecision = OUT_DEFAULT_PRECIS;
1025 This->data->font_in_use.lfClipPrecision = CLIP_DEFAULT_PRECIS;
1026 This->data->font_in_use.lfQuality = DEFAULT_QUALITY;
1027 This->data->font_in_use.lfPitchAndFamily = FIXED_PITCH|FF_DONTCARE;
1028 strcpy(This->data->font_in_use.lfFaceName, fontname);
1029
1030 This->data->font = CreateFontIndirect(&This->data->font_in_use);
1031
1032 /* set the new font as active and get rid of the old one */
1033
1034 oldfont = SelectObject(hdc, This->data->font);
1035 DeleteObject(oldfont);
1036
1037 /* calculate the actual size of the font we selected */
1038
1039 GetTextMetrics(hdc, &tm);
1040 ReleaseDC(This->data->hwndMain, hdc);
1041 This->data->font_height = tm.tmHeight + tm.tmExternalLeading;
1042 This->data->font_width = tm.tmAveCharWidth;
1043
1044 TN5250_LOG(("WIN32: Using font size: Loaded with height=%d, width=%d, got height=%d, width=%d\n",
1045 fontheight, fontwidth, This->data->font_height, This->data->font_width));
1046
1047
1048 /* set up the font spacing array for this font */
1049 {
1050 int x;
1051 if (This->data->spacing != NULL)
1052 free(This->data->spacing);
1053 This->data->spacing = malloc((cols+1)*sizeof(int));
1054 for (x=0; x<=cols; x++)
1055 This->data->spacing[x] = This->data->font_width;
1056 }
1057
1058
1059 /* Now figure out what size the Window should be with the new font */
1060
1061 if (!GetWindowRect(This->data->hwndMain, &wr))
1062 return;
1063 win_height = (wr.bottom - wr.top) + 1;
1064 win_width = (wr.right - wr.left) + 1;
1065
1066 if (!GetClientRect(This->data->hwndMain, &cr))
1067 return;
1068 cli_height = (cr.bottom - cr.top) + 1;
1069 cli_width = (cr.right - cr.left) + 1;
1070
1071 win_height = (win_height - cli_height) + This->data->font_height * rows;
1072 win_width = (win_width - cli_width ) + This->data->font_width * cols;
1073
1074
1075 /* re-calculate the position of the caret (text cursor) */
1076
1077 if (globDisplay != NULL) {
1078 This->data->caretx = tn5250_display_cursor_x(globDisplay)
1079 * This->data->font_width;
1080 This->data->carety = tn5250_display_cursor_y(globDisplay)
1081 * This->data->font_height;
1082 }
1083
1084 if (This->data->hwndMain == GetFocus())
1085 win32_hide_caret(hdc, This);
1086
1087 /* make the system resize the window */
1088
1089 if ((!This->data->maximized)&&(!This->data->dont_auto_size)) {
1090 TN5250_LOG(("WIN32: Re-sizing window to %d by %d\n", win_width,
1091 win_height));
1092 SetWindowPos(This->data->hwndMain, NULL, 0, 0, win_width, win_height,
1093 SWP_NOMOVE | SWP_NOZORDER);
1094 }
1095
1096
1097 /* draw the new caret */
1098
1099 if (This->data->hwndMain == GetFocus()) {
1100 hdc = GetDC(This->data->hwndMain);
1101 win32_make_new_caret(This);
1102 if (This->data->caret_style != CARETSTYLE_NOBLINK) {
1103 win32_move_caret(hdc, This);
1104 ShowCaret (This->data->hwndMain);
1105 }
1106 ReleaseDC(This->data->hwndMain, hdc);
1107 }
1108 }
1109
1110
1111 /****i* lib5250/win32_terminal_term
1112 * NAME
1113 * win32_terminal_term
1114 * SYNOPSIS
1115 * win32_terminal_term (This);
1116 * INPUTS
1117 * Tn5250Terminal * This -
1118 * DESCRIPTION
1119 * DOCUMENT ME!!!
1120 *****/
win32_terminal_term(Tn5250Terminal * This)1121 static void win32_terminal_term(Tn5250Terminal /*@unused@*/ * This)
1122 {
1123 PostQuitMessage(0);
1124 }
1125
1126 /****i* lib5250/win32_terminal_destroy
1127 * NAME
1128 * win32_terminal_destroy
1129 * SYNOPSIS
1130 * win32_terminal_destroy (This);
1131 * INPUTS
1132 * Tn5250Terminal * This -
1133 * DESCRIPTION
1134 * DOCUMENT ME!!!
1135 *****/
win32_terminal_destroy(Tn5250Terminal * This)1136 static void win32_terminal_destroy(Tn5250Terminal * This)
1137 {
1138 if (This->data->font_80 !=NULL)
1139 free(This->data->font_80);
1140 if (This->data->font_132 !=NULL)
1141 free(This->data->font_132);
1142 if (This->data->beepfile != NULL)
1143 free(This->data->beepfile);
1144 if (This->data->pd != NULL)
1145 win32_destroy_printer_info(This);
1146 if (This->data != NULL)
1147 free(This->data);
1148 free(This);
1149 DeleteDC(bmphdc);
1150 }
1151
1152 /****i* lib5250/win32_terminal_width
1153 * NAME
1154 * win32_terminal_width
1155 * SYNOPSIS
1156 * ret = win32_terminal_width (This);
1157 * INPUTS
1158 * Tn5250Terminal * This -
1159 * DESCRIPTION
1160 * Returns the current width (in chars) of the terminal.
1161 *****/
win32_terminal_width(Tn5250Terminal * This)1162 static int win32_terminal_width(Tn5250Terminal *This)
1163 {
1164 RECT r;
1165 GetClientRect(This->data->hwndMain, &r);
1166 return ( (r.right - r.left) / This->data->font_width ) + 1;
1167 }
1168
1169 /****i* lib5250/win32_terminal_height
1170 * NAME
1171 * win32_terminal_height
1172 * SYNOPSIS
1173 * ret = win32_terminal_height (This);
1174 * INPUTS
1175 * Tn5250Terminal * This -
1176 * DESCRIPTION
1177 * Returns the current height of the terminal.
1178 *****/
win32_terminal_height(Tn5250Terminal * This)1179 static int win32_terminal_height(Tn5250Terminal *This)
1180 {
1181 RECT r;
1182 GetClientRect(This->data->hwndMain, &r);
1183 return ( (r.bottom-r.top) / (This->data->font_height) ) + 1;
1184 }
1185
1186 /****i* lib5250/win32_terminal_flags
1187 * NAME
1188 * win32_terminal_flags
1189 * SYNOPSIS
1190 * ret = win32_terminal_flags (This);
1191 * INPUTS
1192 * Tn5250Terminal * This -
1193 * DESCRIPTION
1194 * DOCUMENT ME!!!
1195 *****/
win32_terminal_flags(Tn5250Terminal * This)1196 static int win32_terminal_flags(Tn5250Terminal /*@unused@*/ * This)
1197 {
1198 int f = 0;
1199 f |= TN5250_TERMINAL_HAS_COLOR;
1200 return f;
1201 }
1202
1203 /****i* lib5250/win32_terminal_update
1204 * NAME
1205 * win32_terminal_update
1206 * SYNOPSIS
1207 * win32_terminal_update (This, display);
1208 * INPUTS
1209 * Tn5250Terminal * This -
1210 * Tn5250Display * display -
1211 * DESCRIPTION
1212 * DOCUMENT ME!!!
1213 *****/
win32_terminal_update(Tn5250Terminal * This,Tn5250Display * display)1214 static void win32_terminal_update(Tn5250Terminal * This, Tn5250Display *display)
1215 {
1216 RECT cr;
1217
1218 /* we do all drawing to the screen buffer, then bitblt that to the
1219 actual window when WM_PAINT occurs */
1220
1221 SelectObject(bmphdc, screenbuf);
1222
1223 /* clear the screen buffer (one big black rectangle) */
1224
1225 GetClientRect(This->data->hwndMain, &cr);
1226 win32_terminal_clear_screenbuf(This->data->hwndMain, cr.right-cr.left+1,
1227 cr.bottom-cr.top+1, 0, 0);
1228
1229 win32_do_terminal_update(bmphdc, This, display, attribute_map, 0, 0);
1230
1231 This->data->caretok = 0;
1232 win32_terminal_update_indicators(This, display);
1233 }
1234
1235 /****i* lib5250/win32_do_terminal_update
1236 * NAME
1237 * win32_do_terminal_update
1238 * SYNOPSIS
1239 * win32_do_terminal_update (This, display);
1240 * INPUTS
1241 * HDC hdc -
1242 * Tn5250Terminal * This -
1243 * Tn5250Display * display -
1244 * Tn5250Win32Attribute *map -
1245 * int ox - text offset on x axis
1246 * int oy - text offset on y axis
1247 * DESCRIPTION
1248 * draw the screen to the specified device context, using the
1249 * specified attribute map.
1250 *****/
win32_do_terminal_update(HDC hdc,Tn5250Terminal * This,Tn5250Display * display,Tn5250Win32Attribute * map,int ox,int oy)1251 static void win32_do_terminal_update(HDC hdc, Tn5250Terminal *This,
1252 Tn5250Display *display, Tn5250Win32Attribute *map,
1253 int ox, int oy) {
1254 int y, x;
1255 int mx, my;
1256 unsigned char attr, c;
1257 unsigned char text[132*27];
1258 HBRUSH oldbrush;
1259 HPEN oldpen;
1260 int len;
1261 TEXTMETRIC tm;
1262
1263
1264 if (This->data->resized ||
1265 This->data->last_height != tn5250_display_height(display) ||
1266 This->data->last_width != tn5250_display_width(display)) {
1267 if (tn5250_display_width (display)<100) {
1268 This->data->dont_auto_size = 0;
1269 win32_terminal_font(This, This->data->font_80,
1270 tn5250_display_width(display),
1271 tn5250_display_height(display)+1,
1272 This->data->font_80_w, This->data->font_80_h);
1273 } else {
1274 This->data->dont_auto_size = 0;
1275 win32_terminal_font(This, This->data->font_132,
1276 tn5250_display_width(display),
1277 tn5250_display_height(display)+1,
1278 This->data->font_132_w, This->data->font_132_h);
1279 }
1280 This->data->last_height = tn5250_display_height(display);
1281 This->data->last_width = tn5250_display_width (display);
1282 This->data->resized = 0;
1283 }
1284
1285 SelectObject(hdc, This->data->font);
1286 SetTextAlign(hdc, TA_TOP|TA_LEFT|TA_NOUPDATECP);
1287
1288 attr = 0x20;
1289 len = 0;
1290
1291 for (y = 0; y < tn5250_display_height(display); y++) {
1292
1293 for (x = 0; x < tn5250_display_width(display); x++) {
1294 c = tn5250_display_char_at(display, y, x);
1295 if ((c & 0xe0) == 0x20) { /* ATTRIBUTE */
1296 if (len>0)
1297 win32_terminal_draw_text(hdc, attr, text, len, mx, my,
1298 This->data->spacing, map, ox, oy);
1299 len = 0;
1300 attr = (c & 0xff);
1301 } else { /* DATA */
1302 if (len==0) {
1303 mx = x;
1304 my = y;
1305 }
1306 if ((c==0x1f) || (c==0x3F)) {
1307 if (len>0)
1308 win32_terminal_draw_text(hdc, attr, text, len, mx,
1309 my, This->data->spacing, map, ox, oy);
1310 len = 0;
1311 c = ' ';
1312 win32_terminal_draw_text(hdc, 0x21, &c, 1, x, y,
1313 This->data->spacing, map, ox, oy);
1314 } else if ((c < 0x40 && c > 0x00) || (c == 0xff)) {
1315 text[len] = ' ';
1316 len++;
1317 } else {
1318 text[len] = tn5250_char_map_to_local(
1319 tn5250_display_char_map(display), c);
1320 len++;
1321 }
1322 }
1323 }
1324
1325 if (len>0)
1326 win32_terminal_draw_text(hdc, attr, text, len, mx, my,
1327 This->data->spacing, map, ox, oy);
1328 len = 0;
1329
1330 }
1331
1332 return;
1333 }
1334
1335 /****i* lib5250/win32_terminal_draw_text
1336 * NAME
1337 * win32_terminal_draw_text
1338 * SYNOPSIS
1339 * win32_terminal_draw_text (hdc, a, "Hello", 5, 12, 5);
1340 * INPUTS
1341 * HDC hdc - Device context to draw onto
1342 * int attr - 5250 attribute byte
1343 * const char * text - text to draw
1344 * int len - length of text
1345 * int x - position to start (along x axis)
1346 * int y - position to start (along y axis)
1347 * int * spacing - pointer to array specifying char spacing
1348 * Tn5250Win32Attribute *map - attribute map
1349 * int ox - offset text by (along x axis)
1350 * int oy - offset text by (along y axis)
1351 * DESCRIPTION
1352 * This draws text on the terminal in the specified attribute
1353 *****/
win32_terminal_draw_text(HDC hdc,int attr,const char * text,int len,int x,int y,int * spacing,Tn5250Win32Attribute * map,int ox,int oy)1354 void win32_terminal_draw_text(HDC hdc, int attr, const char *text, int len, int x, int y, int *spacing, Tn5250Win32Attribute *map, int ox, int oy) {
1355
1356 static UINT flags;
1357 static RECT rect;
1358
1359 flags = map[attr-0x20].flags;
1360
1361 /* hmm.. how _do_ you draw something that's invisible? */
1362 if (flags&A_NONDISPLAY)
1363 return;
1364
1365 /* create a rect to "opaque" our text. (defines the background area
1366 that the text is painted on) */
1367
1368 rect.top = y * globTerm->data->font_height + oy;
1369 rect.bottom = rect.top + globTerm->data->font_height;
1370 rect.left = x * globTerm->data->font_width + ox;
1371 rect.right = rect.left + (globTerm->data->font_width * len);
1372
1373 /* this builds an array telling Windows how to space the text.
1374 Some fonts end up being slightly smaller than the text metrics
1375 tell us that they are... so without this, the caret (aka "cursor")
1376 will not appear in the right place. */
1377
1378
1379 /* set up colors for this drawing style */
1380
1381 SetBkMode(hdc, OPAQUE);
1382 if (flags&A_REVERSE) {
1383 SetBkColor(hdc, map[attr-0x20].fg);
1384 SetTextColor(hdc, map[7].fg);
1385 } else {
1386 SetBkColor(hdc, map[7].fg);
1387 SetTextColor(hdc, map[attr-0x20].fg);
1388 }
1389
1390
1391 #ifdef LOG_DRAWTEXT
1392 /* debugging: log what we're drawing */
1393 {
1394 char *dbg;
1395 dbg = malloc(len+1);
1396 memcpy(dbg, text, len);
1397 dbg[len]=0;
1398 TN5250_LOG(("WIN32: draw text(%d, %d) %s\n", x,y , dbg));
1399 free(dbg);
1400 }
1401 #endif
1402
1403 /* draw the text */
1404
1405 if (ExtTextOut(hdc, rect.left, rect.top, ETO_CLIPPED|ETO_OPAQUE, &rect,
1406 text, len, spacing)==0) {
1407 msgboxf("ExtTextOut(): Error %d\n", GetLastError());
1408 }
1409
1410 if (flags&A_VERTICAL && colsep_style==COLSEPSTYLE_NONE) {
1411 flags &= ~A_VERTICAL;
1412 /* flags |= A_UNDERLINE; */
1413 }
1414
1415 /* draw underlines */
1416 /* Note: We don't use the underlining capability of the font itself
1417 because on some fonts, it changes the font height, and that
1418 would just mess us up. */
1419
1420 if (flags&A_UNDERLINE) {
1421 HPEN savepen;
1422 savepen = SelectObject(hdc,
1423 CreatePen(PS_SOLID, 0, map[attr-0x20].fg));
1424 MoveToEx(hdc, rect.left, rect.bottom-1, NULL);
1425 LineTo(hdc, rect.right, rect.bottom-1);
1426 savepen = SelectObject(hdc, savepen);
1427 DeleteObject(savepen);
1428 }
1429 if (flags&A_VERTICAL && colsep_style==COLSEPSTYLE_FULL) {
1430 HPEN savepen;
1431 if (flags&A_REVERSE)
1432 savepen = SelectObject(hdc, CreatePen(PS_SOLID, 0,
1433 colorlist[A_5250_BLACK].ref));
1434 else
1435 savepen = SelectObject(hdc, CreatePen(PS_SOLID, 0,
1436 map[attr-0x20].fg));
1437 for (x=rect.left; x<=rect.right; x+=spacing[0]) {
1438 MoveToEx(hdc, x, rect.top, NULL);
1439 LineTo (hdc, x, rect.bottom);
1440 }
1441 MoveToEx(hdc, rect.right, rect.top, NULL);
1442 LineTo (hdc, rect.right, rect.bottom);
1443 savepen = SelectObject(hdc, savepen);
1444 DeleteObject(savepen);
1445 }
1446 if (flags&A_VERTICAL && colsep_style==COLSEPSTYLE_DOTS) {
1447 HPEN savepen;
1448 if (flags&A_REVERSE)
1449 savepen = SelectObject(hdc, CreatePen(PS_SOLID, 0,
1450 colorlist[A_5250_BLACK].ref));
1451 else
1452 savepen = SelectObject(hdc, CreatePen(PS_SOLID, 0,
1453 map[attr-0x20].fg));
1454 for (x=rect.left; x<=rect.right; x+=spacing[0]) {
1455 MoveToEx(hdc, x, rect.bottom-2, NULL);
1456 LineTo (hdc, x, rect.bottom);
1457 }
1458 MoveToEx(hdc, rect.right, rect.bottom-2, NULL);
1459 LineTo (hdc, rect.right, rect.bottom);
1460 savepen = SelectObject(hdc, savepen);
1461 DeleteObject(savepen);
1462 }
1463
1464 return;
1465 }
1466
1467
1468 /****i* lib5250/win32_terminal_update_indicators
1469 * NAME
1470 * win32_terminal_update_indicators
1471 * SYNOPSIS
1472 * win32_terminal_update_indicators (This, display);
1473 * INPUTS
1474 * Tn5250Terminal * This -
1475 * Tn5250Display * display -
1476 * DESCRIPTION
1477 * DOCUMENT ME!!!
1478 *****/
win32_terminal_update_indicators(Tn5250Terminal * This,Tn5250Display * display)1479 static void win32_terminal_update_indicators(Tn5250Terminal *This, Tn5250Display *display)
1480 {
1481 int inds = tn5250_display_indicators(display);
1482 char ind_buf[80];
1483 HDC hdc;
1484 static unsigned char c;
1485
1486 SelectObject(bmphdc, screenbuf);
1487 SetTextAlign(bmphdc, TA_TOP|TA_LEFT|TA_NOUPDATECP);
1488 SelectObject(bmphdc, This->data->font);
1489
1490 memset(ind_buf, ' ', sizeof(ind_buf));
1491 memcpy(ind_buf, "5250", 4);
1492 if ((inds & TN5250_DISPLAY_IND_MESSAGE_WAITING) != 0)
1493 memcpy(ind_buf + 23, "MW", 2);
1494 if ((inds & TN5250_DISPLAY_IND_INHIBIT) != 0)
1495 memcpy(ind_buf + 9, "X II", 4);
1496 else if ((inds & TN5250_DISPLAY_IND_X_CLOCK) != 0)
1497 memcpy(ind_buf + 9, "X CLOCK", 7);
1498 else if ((inds & TN5250_DISPLAY_IND_X_SYSTEM) != 0)
1499 memcpy(ind_buf + 9, "X SYSTEM", 8);
1500 if ((inds & TN5250_DISPLAY_IND_INSERT) != 0)
1501 memcpy(ind_buf + 30, "IM", 2);
1502 if ((inds & TN5250_DISPLAY_IND_FER) != 0)
1503 memcpy(ind_buf + 33, "FER", 3);
1504 if ((inds & TN5250_DISPLAY_IND_MACRO) != 0)
1505 memcpy(ind_buf + 54, tn5250_macro_printstate (display), 11);
1506 sprintf(ind_buf+72,"%03.3d/%03.3d",tn5250_display_cursor_x(display)+1,
1507 tn5250_display_cursor_y(display)+1);
1508
1509 win32_terminal_draw_text(bmphdc, 0x22, ind_buf, 79, 0,
1510 tn5250_display_height(display), This->data->spacing, attribute_map,
1511 0, 0);
1512
1513 This->data->caretx=tn5250_display_cursor_x(display)*This->data->font_width;
1514 This->data->carety=tn5250_display_cursor_y(display)*This->data->font_height;
1515
1516 globDisplay = display;
1517
1518 if (This->data->display_ruler) {
1519 HPEN savepen;
1520 RECT rect;
1521 int x, y;
1522 int savemixmode;
1523 x = This->data->caretx;
1524 y = This->data->carety + This->data->font_height;
1525 GetClientRect(This->data->hwndMain, &rect);
1526 savepen = SelectObject(bmphdc,
1527 CreatePen(PS_SOLID, 0, colorlist[A_5250_RULER_COLOR].ref));
1528 MoveToEx(bmphdc, x, rect.top, NULL);
1529 LineTo (bmphdc, x, rect.bottom);
1530 MoveToEx(bmphdc, rect.left, y, NULL);
1531 LineTo (bmphdc, rect.right, y);
1532 hdc = GetDC(This->data->hwndMain);
1533 savepen = SelectObject(hdc, savepen);
1534 ReleaseDC(This->data->hwndMain, hdc);
1535 DeleteObject(savepen);
1536 }
1537
1538 This->data->selected = This->data->selecting = 0;
1539
1540 if (This->data->caret_style == CARETSTYLE_NOBLINK)
1541 win32_move_caret(bmphdc, This);
1542
1543 InvalidateRect(This->data->hwndMain, NULL, FALSE);
1544 UpdateWindow(This->data->hwndMain);
1545 }
1546
1547
1548 /****i* lib5250/win32_terminal_waitevent
1549 * NAME
1550 * win32_terminal_waitevent
1551 * SYNOPSIS
1552 * ret = win32_terminal_waitevent (This);
1553 * INPUTS
1554 * Tn5250Terminal * This -
1555 * DESCRIPTION
1556 * DOCUMENT ME!!!
1557 *****/
win32_terminal_waitevent(Tn5250Terminal * This)1558 static int win32_terminal_waitevent(Tn5250Terminal * This)
1559 {
1560 fd_set fdr;
1561 int result = 0;
1562 int sm;
1563 static MSG msg;
1564
1565
1566 if (This->data->quit_flag)
1567 return TN5250_TERMINAL_EVENT_QUIT;
1568
1569 if (This->conn_fd != -1) {
1570 if (WSAAsyncSelect(This->conn_fd, This->data->hwndMain,
1571 WM_TN5250_STREAM_DATA, FD_READ) == SOCKET_ERROR) {
1572 TN5250_LOG(("WIN32: WSAASyncSelect failed, reason: %d\n",
1573 WSAGetLastError()));
1574 return TN5250_TERMINAL_EVENT_QUIT;
1575 }
1576 }
1577
1578 result = TN5250_TERMINAL_EVENT_QUIT;
1579 while ( GetMessage(&msg, NULL, 0, 0) ) {
1580 DispatchMessage(&msg);
1581 if (msg.message == WM_TN5250_STREAM_DATA) {
1582 result = TN5250_TERMINAL_EVENT_DATA;
1583 break;
1584 }
1585 if (msg.message == WM_CHAR || msg.message == WM_TN5250_KEY_DATA) {
1586 result = TN5250_TERMINAL_EVENT_KEY;
1587 break;
1588 }
1589 }
1590
1591 if (This->conn_fd != -1)
1592 WSAAsyncSelect(This->conn_fd, This->data->hwndMain, 0, 0);
1593
1594 return result;
1595 }
1596
1597
1598 /****i* lib5250/win32_terminal_beep
1599 * NAME
1600 * win32_terminal_beep
1601 * SYNOPSIS
1602 * win32_terminal_beep (This);
1603 * INPUTS
1604 * Tn5250Terminal * This -
1605 * DESCRIPTION
1606 * This plays a beep, either using a .wav file or
1607 * by using the stock Windows methods.
1608 *****/
win32_terminal_beep(Tn5250Terminal * This)1609 static void win32_terminal_beep (Tn5250Terminal *This)
1610 {
1611 if (This->data->beeptype != MB_BEEPFILE) {
1612 TN5250_LOG (("WIN32: beep\n"));
1613 MessageBeep(This->data->beeptype);
1614 } else {
1615 TN5250_LOG (("WIN32: PlaySound\n"));
1616 if (!PlaySound(This->data->beepfile, NULL, SND_ASYNC|SND_FILENAME)) {
1617 TN5250_LOG (("WIN32: PlaySound failed, switching back to beep\n"));
1618 tn5250_win32_set_beep(This, NULL);
1619 MessageBeep(This->data->beeptype);
1620 }
1621 }
1622 }
1623
1624
1625 /****i* lib5250/win32_get_key
1626 * NAME
1627 * win32_get_key
1628 * SYNOPSIS
1629 * key = win32_get_key (This);
1630 * INPUTS
1631 * Tn5250Terminal * This -
1632 * DESCRIPTION
1633 * Read the next key from the keyboard buffer.
1634 *****/
win32_get_key(Tn5250Terminal * This)1635 static int win32_get_key (Tn5250Terminal *This)
1636 {
1637 int i, j;
1638 int have_incomplete_match = -1;
1639 int have_complete_match = -1;
1640 int complete_match_len;
1641
1642 if (This->data->k_buf_len == 0)
1643 return -1;
1644
1645 i = This->data->k_buf[0];
1646 This->data->k_buf_len --;
1647 for (j=0; j<This->data->k_buf_len; j++)
1648 This->data->k_buf[j] = This->data->k_buf[j+1];
1649
1650 #if 0
1651 {
1652 char *blah;
1653 blah = malloc(This->data->k_buf_len+1);
1654 for (j=0; j<This->data->k_buf_len; j++)
1655 blah[j] = This->data->k_buf[j];
1656 blah[This->data->k_buf_len] = '\0';
1657 TN5250_LOG(("WIN32: getkey %c, %d bytes left:\n", i, This->data->k_buf_len));
1658 TN5250_LOG(("WIN32: buffer %s\n", blah));
1659 free(blah);
1660 }
1661 #endif
1662
1663 return i;
1664
1665 }
1666
1667
1668 /****i* lib5250/win32_terminal_getkey
1669 * NAME
1670 * win32_terminal_getkey
1671 * SYNOPSIS
1672 * key = win32_terminal_getkey (This);
1673 * INPUTS
1674 * Tn5250Terminal * This -
1675 * DESCRIPTION
1676 * Read the next key from the terminal, and do any
1677 * required translations.
1678 *****/
win32_terminal_getkey(Tn5250Terminal * This)1679 static int win32_terminal_getkey (Tn5250Terminal *This)
1680 {
1681 int ch;
1682
1683 /* we don't actually read the keyboard here... that's done by
1684 win32_terminal_wndproc. */
1685
1686 ch = win32_get_key (This);
1687 switch (ch) {
1688 case K_CTRL('Q'):
1689 This->data->quit_flag = 1;
1690 return -1;
1691 case K_PRINT:
1692 if (This->data->local_print) {
1693 win32_print_screen(This, globDisplay);
1694 ch = K_RESET;
1695 }
1696 break;
1697 case 0x0a:
1698 return 0x0d;
1699 }
1700
1701 return ch;
1702 }
1703
1704
1705 /****i* lib5250/win32_terminal_queuekey
1706 * NAME
1707 * win32_terminal_queuekey
1708 * SYNOPSIS
1709 * key = win32_terminal_queuekey (hwnd, This, key);
1710 * INPUTS
1711 * HWND hwnd -
1712 * Tn5250Terminal * This -
1713 * int key -
1714 * DESCRIPTION
1715 * Add a key to the terminal's keyboard buffer
1716 *****/
win32_terminal_queuekey(HWND hwnd,Tn5250Terminal * This,int key)1717 void win32_terminal_queuekey(HWND hwnd, Tn5250Terminal *This, int key) {
1718
1719 switch (key) {
1720
1721 case K_PASTE_TEXT:
1722 win32_paste_text_selection(hwnd, This, globDisplay);
1723 break;
1724
1725 case K_COPY_TEXT:
1726 if (This->data->selected) {
1727 win32_expand_text_selection(This);
1728 win32_copy_text_selection(This, globDisplay);
1729 globTerm->data->selected = 0;
1730 InvalidateRect(hwnd, NULL, FALSE);
1731 UpdateWindow(hwnd);
1732 }
1733 break;
1734
1735 default:
1736 if (This->data->k_buf_len<MAX_K_BUF_LEN) {
1737 This->data->k_buf[This->data->k_buf_len] = key;
1738 This->data->k_buf_len ++;
1739 }
1740 break;
1741 }
1742
1743 }
1744
1745
1746 /****i* lib5250/win32_terminal_new_screenbuf
1747 * NAME
1748 * win32_terminal_new_screenbuf
1749 * SYNOPSIS
1750 * win32_terminal_new_screenbuf (hwnd, width, height);
1751 * INPUTS
1752 * HWND hwnd -
1753 * int width -
1754 * int height -
1755 * DESCRIPTION
1756 * Create/Resize the bitmap that we use as the screen buffer.
1757 *****/
win32_terminal_clear_screenbuf(HWND hwnd,int width,int height,int delet,int mknew)1758 void win32_terminal_clear_screenbuf(HWND hwnd, int width, int height,
1759 int delet, int mknew) {
1760
1761 HDC hdc;
1762 HBRUSH oldbrush;
1763 HPEN oldpen;
1764
1765 if (delet)
1766 DeleteObject(screenbuf);
1767
1768 if (mknew) {
1769 hdc = GetDC(hwnd);
1770 screenbuf = CreateCompatibleBitmap(hdc, width, height);
1771 ReleaseDC(hwnd, hdc);
1772 }
1773
1774 SelectObject(bmphdc, screenbuf);
1775 oldbrush = SelectObject(bmphdc, background_brush);
1776 oldpen = SelectObject(bmphdc,
1777 CreatePen(PS_SOLID, 0, colorlist[A_5250_BLACK].ref));
1778 Rectangle(bmphdc, 0, 0, width+3, height+3);
1779 SelectObject(bmphdc, oldbrush);
1780 oldpen = SelectObject(bmphdc, oldpen);
1781 DeleteObject(oldpen);
1782
1783 return;
1784 }
1785
1786 /****i* lib5250/win32_terminal_choosefont
1787 * DESCRIPTION
1788 * Pops a dialog box and let the user choose a new font for the current display.
1789 *****/
win32_terminal_choosefont(HWND hwnd)1790 void win32_terminal_choosefont(HWND hwnd) {
1791 CHOOSEFONT cf = { sizeof(cf) };
1792 cf.hwndOwner = hwnd;
1793 cf.hDC = GetDC(hwnd);
1794 cf.lpLogFont = &globTerm->data->font_in_use;
1795 cf.Flags = CF_INITTOLOGFONTSTRUCT|CF_FIXEDPITCHONLY|CF_FORCEFONTEXIST|CF_LIMITSIZE|CF_SCREENFONTS;
1796 cf.iPointSize = globTerm->data->font_in_use.lfHeight*10;
1797 cf.nSizeMin = 5;
1798 cf.nSizeMax = 100;
1799 if (ChooseFont(&cf))
1800 {
1801 char fontName[LF_FACESIZE+32];
1802 /* It always returns a width of 0. How to change that? */
1803 if (globTerm->data->font_in_use.lfHeight<0)
1804 globTerm->data->font_in_use.lfHeight = -globTerm->data->font_in_use.lfHeight;
1805
1806 sprintf(fontName, "%s-%dx%d", globTerm->data->font_in_use.lfFaceName,
1807 globTerm->data->font_in_use.lfWidth, globTerm->data->font_in_use.lfHeight);
1808
1809 if (tn5250_display_width (globDisplay)<100) {
1810 // Change the 80
1811 int h = strlen(globTerm->data->font_in_use.lfFaceName) + 1;
1812 if (globTerm->data->font_80)
1813 free(globTerm->data->font_80);
1814 globTerm->data->font_80 = malloc(h+1);
1815 strcpy(globTerm->data->font_80, globTerm->data->font_in_use.lfFaceName);
1816 globTerm->data->font_80_h = globTerm->data->font_in_use.lfHeight;
1817 globTerm->data->font_80_w = globTerm->data->font_in_use.lfWidth;
1818 win32_terminal_font(globTerm, globTerm->data->font_in_use.lfFaceName, tn5250_display_width (globDisplay), tn5250_display_height (globDisplay)+1, globTerm->data->font_80_w, globTerm->data->font_80_h);
1819 tn5250_config_set(globTerm->data->config, "font_80", fontName);
1820 }
1821 else {
1822 // Change the 132
1823 int h = strlen(globTerm->data->font_in_use.lfFaceName) + 1;
1824 if (globTerm->data->font_132)
1825 free(globTerm->data->font_132);
1826 globTerm->data->font_132 = malloc(h+1);
1827 strcpy(globTerm->data->font_132, globTerm->data->font_in_use.lfFaceName);
1828 globTerm->data->font_132_h = globTerm->data->font_in_use.lfHeight;
1829 globTerm->data->font_132_w = globTerm->data->font_in_use.lfWidth;
1830 win32_terminal_font(globTerm, globTerm->data->font_in_use.lfFaceName, tn5250_display_width (globDisplay), tn5250_display_height (globDisplay)+1, globTerm->data->font_132_w, globTerm->data->font_132_h);
1831 tn5250_config_set(globTerm->data->config, "font_132", fontName);
1832 }
1833 }
1834 ReleaseDC(hwnd, cf.hDC);
1835 }
1836
1837 /****i* lib5250/win32_terminal_wndproc
1838 * NAME
1839 * win32_terminal_wndproc
1840 * SYNOPSIS
1841 * Called as a result of the DispatchMesage() API.
1842 * INPUTS
1843 * HWND hwnd -
1844 * UINT msg -
1845 * WPARAM wParam -
1846 * LPARAM lParam -
1847 * DESCRIPTION
1848 * Windows calls this function to report events such
1849 * as mouse clicks, keypresses and the receipt of network data.
1850 *****/
1851 LRESULT CALLBACK
win32_terminal_wndproc(HWND hwnd,UINT msg,WPARAM wParam,LPARAM lParam)1852 win32_terminal_wndproc( HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam) {
1853
1854 PAINTSTRUCT ps;
1855 HDC hdc;
1856 int h, w, x, y;
1857 RECT rect;
1858 static BYTE ks[256];
1859 MSG m;
1860 int ctx, ext;
1861 static int handledkey=0;
1862 HMENU hMenu;
1863 int redraw;
1864
1865 switch (msg) {
1866 case WM_CREATE:
1867 /* add buttons & other controls here */
1868 break;
1869
1870 case WM_DESTROY:
1871 PostQuitMessage(0);
1872 return 0;
1873 break;
1874
1875 case WM_COMMAND:
1876 hMenu = GetMenu(hwnd);
1877 switch (LOWORD(wParam)) {
1878 case IDM_APP_EXIT:
1879 SendMessage(hwnd, WM_CLOSE, 0, 0);
1880 return 0;
1881 case IDM_APP_PRINT:
1882 win32_print_screen(globTerm, globDisplay);
1883 return 0;
1884 case IDM_APP_ABOUT:
1885 msgboxf("%s version %s:\n"
1886 "Copyright (C) 1997-2008 by Michael Madore,"
1887 " Jason M. Felice, and Scott Klement\n"
1888 "\n"
1889 "Portions of this software were contributed "
1890 #ifdef BINARY_RELEASE
1891 "by many people. See the AUTHORS.txt file for\n"
1892 "details.\n"
1893 "\n"
1894 "For license information, see the COPYING.txt file "
1895 "that was installed with this software.\n"
1896 #else
1897 "by many people. See the AUTHORS file for\n"
1898 "details.\n"
1899 "\n"
1900 "For license information, see the COPYING file "
1901 "that was included with this software.\n"
1902 #endif
1903
1904 #ifdef HAVE_LIBSSL
1905 #ifdef BINARY_RELEASE
1906 "\n"
1907 "OpenSSL:\n"
1908 "This product includes software developed by the "
1909 "OpenSSL Project for use in the OpenSSL Toolkit "
1910 "(http://www.openssl.org/)\n"
1911 "This product includes cryptographic software "
1912 "written by Eric Young (eay@crypsoft.com).\n"
1913 "This product includes software written by Tim "
1914 "Hudson (tjh@cryptsoft.com).\n"
1915 "\n"
1916 "For OpenSSL license information, see the "
1917 "COPYING.txt file that was installed with "
1918 "this software."
1919 #else
1920 "\n"
1921 "OpenSSL:\n"
1922 "This product includes software developed by the "
1923 "OpenSSL Project for use in the OpenSSL Toolkit "
1924 "(http://www.openssl.org/)\n"
1925 "This product includes cryptographic software "
1926 "written by Eric Young (eay@crypsoft.com).\n"
1927 "This product includes software written by Tim "
1928 "Hudson (tjh@cryptsoft.com).\n"
1929 "\n"
1930 "For OpenSSL license information, see the LICENSE "
1931 "file that was included in the OpenSSL package.\n"
1932 #endif
1933 #endif
1934 ,PACKAGE, VERSION);
1935 return 0;
1936 case IDM_EDIT_COPY:
1937 win32_terminal_queuekey(hwnd, globTerm, K_COPY_TEXT);
1938 return 0;
1939 case IDM_EDIT_PASTE:
1940 win32_terminal_queuekey(hwnd, globTerm, K_PASTE_TEXT);
1941 return 0;
1942 case IDM_EDIT_SELECT_ALL:
1943 globTerm->data->selecting = 0;
1944 globTerm->data->selstr.x = 2;
1945 globTerm->data->selstr.y = 2;
1946 globTerm->data->selend.x =
1947 (tn5250_display_width(globDisplay)
1948 * globTerm->data->font_width) - 2;
1949 globTerm->data->selend.y =
1950 (tn5250_display_height(globDisplay)
1951 * globTerm->data->font_height) - 2;
1952 globTerm->data->selected = 1;
1953 win32_expand_text_selection(globTerm);
1954 if (globTerm->data->unix_like_copy) {
1955 win32_copy_text_selection(globTerm, globDisplay);
1956 }
1957 InvalidateRect(hwnd, NULL, FALSE);
1958 UpdateWindow(hwnd);
1959 return 0;
1960 case IDM_VIEW_FONT:
1961 win32_terminal_choosefont(hwnd);
1962 return 0;
1963 case IDM_MACRO_RECORD1:
1964 case IDM_MACRO_RECORD2:
1965 case IDM_MACRO_RECORD3:
1966 case IDM_MACRO_RECORD4:
1967 tn5250_display_kf_macro(globDisplay, K_MEMO);
1968 if (tn5250_macro_rstate(globDisplay)) {
1969 int key = LOWORD(wParam) - IDM_MACRO_RECORD1;
1970 win32_terminal_queuekey(hwnd, globTerm, K_F1+key);
1971 PostMessage(hwnd, WM_TN5250_KEY_DATA, 0, 0);
1972 }
1973 else {
1974 win32_terminal_update(globTerm,globDisplay);
1975 }
1976 return 0;
1977 case IDM_MACRO_EXEC1:
1978 case IDM_MACRO_EXEC2:
1979 case IDM_MACRO_EXEC3:
1980 case IDM_MACRO_EXEC4: {
1981 int key = LOWORD(wParam) - IDM_MACRO_EXEC1;
1982 tn5250_display_kf_macro(globDisplay, K_EXEC);
1983 win32_terminal_queuekey(hwnd, globTerm, K_F1+key);
1984 PostMessage(hwnd, WM_TN5250_KEY_DATA, 0, 0);
1985 return 0;
1986 }
1987 default:
1988 break;
1989 }
1990 return 0;
1991
1992 case WM_SIZING:
1993 // Block it if needed
1994 if (!globTerm->data->resize_fonts)
1995 {
1996 GetWindowRect(hwnd, (RECT*)lParam);
1997 return 1;
1998 }
1999 break;
2000
2001 /* TBA case WM_NCCALCSIZE:
2002 // NCCALCSIZE_PARAMS::rgrc[0] == RECT
2003 win32_terminal_on_resize(hwnd, (RECT*)lParam);
2004 if (lParam)
2005 return WVR_REDRAW;
2006 else
2007 return 0;*/
2008
2009 case WM_SIZE:
2010 w = LOWORD(lParam);
2011 h = HIWORD(lParam);
2012 if (wParam==SIZE_MAXIMIZED)
2013 globTerm->data->maximized = 1;
2014 else
2015 globTerm->data->maximized = 0;
2016 if (h>0 && w>0) {
2017 int c,r;
2018 win32_terminal_clear_screenbuf(hwnd, w, h, 1, 1);
2019 if (globTerm!=NULL && globDisplay!=NULL) {
2020 if (globTerm->data->resize_fonts) {
2021 win32_calc_default_font_size(hwnd, 80, 24, &c, &r);
2022 globTerm->data->font_80_h = r;
2023 globTerm->data->font_80_w = c;
2024 win32_calc_default_font_size(hwnd, 132, 27, &c, &r);
2025 globTerm->data->font_132_h = r;
2026 globTerm->data->font_132_w = c;
2027 globTerm->data->resized = 1;
2028 }
2029 win32_terminal_update(globTerm, globDisplay);
2030 }
2031 }
2032 return 0;
2033
2034 case WM_SYSKEYUP:
2035 case WM_KEYUP:
2036 ext = (HIWORD (lParam) & 0x0100) >> 8;
2037 GetKeyboardState(ks);
2038 ks[0] = 0xff; /* so that keystate=0 always works. */
2039 x = 0;
2040 while (keyup2msg[x].win32_key != -1) {
2041 if ((int)wParam == keyup2msg[x].win32_key &&
2042 (keyup2msg[x].ctx || !handledkey) &&
2043 keyup2msg[x].ext == ext &&
2044 (ks[keyup2msg[x].keystate]&0x80)) {
2045 win32_terminal_queuekey(hwnd,
2046 globTerm,keyup2msg[x].func_key);
2047 PostMessage(hwnd, WM_TN5250_KEY_DATA, 0, 0);
2048 TN5250_LOG(("WM_KEYUP: handling key\n"));
2049 return 0;
2050 }
2051 x++;
2052 }
2053 break;
2054
2055 case WM_SYSKEYDOWN:
2056 case WM_KEYDOWN:
2057 ctx = HIWORD (lParam) & 0x2000;
2058 ext = (HIWORD (lParam) & 0x0100) >> 8;
2059 GetKeyboardState(ks);
2060 ks[0] = 0xff; /* so that keystate=0 always works. */
2061 x = 0;
2062 handledkey = 0;
2063 while (keydown2msg[x].win32_key != -1) {
2064 if ((int)wParam == keydown2msg[x].win32_key &&
2065 keydown2msg[x].ctx == ctx &&
2066 keydown2msg[x].ext == ext &&
2067 (ks[keydown2msg[x].keystate]&0x80)) {
2068 int repeat = LOWORD (lParam);
2069 for (; repeat>0; repeat--) {
2070 win32_terminal_queuekey(hwnd, globTerm,
2071 keydown2msg[x].func_key);
2072 }
2073 PostMessage(hwnd, WM_TN5250_KEY_DATA, 0, 0);
2074 TN5250_LOG(("WM_KEYDOWN: handling key\n"));
2075 handledkey = 1;
2076 return 0;
2077 }
2078 x++;
2079 }
2080 /* if we didn't handle a keystroke, let Windows send it
2081 back to us as a character message */
2082 m.hwnd = hwnd;
2083 m.message = msg;
2084 m.wParam = wParam;
2085 m.lParam = lParam;
2086 m.time = GetMessageTime();
2087 x = GetMessagePos();
2088 memcpy(&(m.pt), &x, sizeof(m.pt));
2089 TranslateMessage(&m);
2090 break;
2091
2092 case WM_CHAR:
2093 x=0;
2094 while (win_kb[x].win32_key != -1) {
2095 if (wParam == win_kb[x].win32_key) {
2096 wParam = win_kb[x].tn5250_key;
2097 break;
2098 }
2099 x++;
2100 }
2101 handledkey = 1;
2102 TN5250_LOG(("WM_CHAR: handling key\n"));
2103 win32_terminal_queuekey(hwnd, globTerm, (int)wParam);
2104 break;
2105
2106 case WM_TN5250_KEY_DATA:
2107 case WM_TN5250_STREAM_DATA:
2108 /* somewhere in this program we're signalling waitevent()
2109 to process an event. */
2110 return 0;
2111 break;
2112
2113 case WM_ERASEBKGND:
2114 /* don't let background get erased, that causes "flashing" */
2115 return 0;
2116 break;
2117
2118 case WM_SETFOCUS:
2119 win32_make_new_caret(globTerm);
2120 hdc = GetDC(hwnd);
2121 globTerm->data->caretok = 0;
2122 if (globTerm->data->caret_style != CARETSTYLE_NOBLINK) {
2123 win32_move_caret(hdc, globTerm);
2124 ShowCaret(hwnd);
2125 }
2126 ReleaseDC(hwnd, hdc);
2127 globTerm->data->is_focused = 1;
2128 return 0;
2129
2130 case WM_KILLFOCUS:
2131 hdc = GetDC(hwnd);
2132 win32_hide_caret(hdc, globTerm);
2133 ReleaseDC(hwnd, hdc);
2134 globTerm->data->is_focused = 0;
2135 return 0;
2136
2137 case WM_PAINT:
2138 hdc = BeginPaint (hwnd, &ps);
2139 GetClientRect(hwnd, &rect);
2140 x = rect.left;
2141 y = rect.top;
2142 h = (rect.bottom - rect.top) + 1;
2143 w = (rect.right - rect.left) + 1;
2144 SelectObject(bmphdc, screenbuf);
2145 if (BitBlt(hdc, x, y, w, h, bmphdc, x, y, SRCCOPY)==0) {
2146 TN5250_LOG(("WIN32: BitBlt failed: %d\n", GetLastError()));
2147 TN5250_ASSERT(0);
2148 }
2149 if (globTerm->data->caret_style != CARETSTYLE_NOBLINK) {
2150 if (hwnd == GetFocus())
2151 win32_move_caret(hdc, globTerm);
2152 }
2153 if (globTerm->data->selected) {
2154 SetROP2(hdc, R2_NOT);
2155 if (globTerm->data->selecting)
2156 SelectObject(hdc, GetStockObject(NULL_BRUSH) );
2157 else
2158 SelectObject(hdc, GetStockObject(WHITE_BRUSH) );
2159 Rectangle(hdc, globTerm->data->selstr.x,
2160 globTerm->data->selstr.y,
2161 globTerm->data->selend.x,
2162 globTerm->data->selend.y);
2163 }
2164 EndPaint (hwnd, &ps);
2165 return 0;
2166 break;
2167
2168 case WM_RBUTTONDOWN:
2169 if (globTerm->data->unix_like_copy) {
2170 win32_paste_text_selection(hwnd, globTerm, globDisplay);
2171 return 0;
2172 }
2173 break;
2174
2175 case WM_LBUTTONDOWN:
2176 if (globDisplay != NULL) {
2177 globTerm->data->selecting = 1;
2178 globTerm->data->selstr.x = (short)LOWORD(lParam);
2179 globTerm->data->selstr.y = (short)HIWORD(lParam);
2180 SetCapture(hwnd);
2181 SetCursor (LoadCursor (NULL, IDC_CROSS));
2182 if (globTerm->data->selected) {
2183 globTerm->data->selected = 0;
2184 InvalidateRect(hwnd, NULL, FALSE);
2185 UpdateWindow(hwnd);
2186 }
2187 return 0;
2188 }
2189 break;
2190
2191 case WM_MOUSEMOVE:
2192 if (globTerm->data->selecting && globDisplay!=NULL) {
2193 globTerm->data->selected = 1;
2194 globTerm->data->selend.x = (short)LOWORD(lParam);
2195 globTerm->data->selend.y = (short)HIWORD(lParam);
2196 SetCursor (LoadCursor (NULL, IDC_CROSS));
2197 InvalidateRect(hwnd, NULL, FALSE);
2198 UpdateWindow(hwnd);
2199 return 0;
2200 }
2201 break;
2202
2203 case WM_LBUTTONUP:
2204 redraw = 0;
2205 if (globTerm->data->click_moves_caret && globDisplay!=NULL) {
2206 win32_move_caret_to(globTerm,
2207 globDisplay,
2208 (short)HIWORD(lParam),
2209 (short)LOWORD(lParam) );
2210 redraw = 1;
2211 }
2212 if (globTerm->data->selecting && globDisplay!=NULL) {
2213 globTerm->data->selecting = 0;
2214 globTerm->data->selend.x = (short)LOWORD(lParam);
2215 globTerm->data->selend.y = (short)HIWORD(lParam);
2216 ReleaseCapture();
2217 SetCursor (LoadCursor (NULL, IDC_ARROW));
2218 win32_expand_text_selection(globTerm);
2219 if (globTerm->data->unix_like_copy) {
2220 win32_copy_text_selection(globTerm, globDisplay);
2221 }
2222 redraw = 1;
2223 }
2224 if (redraw) {
2225 InvalidateRect(hwnd, NULL, FALSE);
2226 UpdateWindow(hwnd);
2227 return 0;
2228 }
2229 break;
2230
2231 #ifdef LOG_KEYCODES
2232 case WM_SYSCOMMAND:
2233 x = LOWORD(lParam);
2234 y = HIWORD(lParam);
2235 TN5250_LOG(("WIN32: WM_SYSCOMMAND: (%d,%d) %d\n", x, y, wParam));
2236 break;
2237
2238 case WM_DEADCHAR:
2239 case WM_SYSDEADCHAR:
2240 TN5250_LOG(("WIN32: WM_DEADCHAR: Dead character %d\n", wParam));
2241 break;
2242
2243 default:
2244 TN5250_LOG(("WIN32: Unhandled msg %d\n", msg));
2245 break;
2246 #endif
2247
2248 }
2249
2250 return DefWindowProc (hwnd, msg, wParam, lParam);
2251 }
2252
2253
2254 /****i* lib5250/win32_make_new_caret
2255 * NAME
2256 * win32_make_new_caret
2257 * SYNOPSIS
2258 * win32_make_new_caret (globTerm);
2259 * INPUTS
2260 * Tn5250Terminal * This -
2261 * DESCRIPTION
2262 * If you're wondering, "Caret" is the Windows term for
2263 * the cursor used when typing at the keyboard. In Windows
2264 * terminology, cursor=mouse, caret=keyboard.
2265 *
2266 * There is only one cursor in Windows, shared by all Windows apps.
2267 * So, we create it when focus returns to us, and destroy it when
2268 * we lose focus. This is where it gets created.
2269 *****/
win32_make_new_caret(Tn5250Terminal * This)2270 void win32_make_new_caret(Tn5250Terminal *This) {
2271 if (This->data->caret_style == CARETSTYLE_NOBLINK) {
2272 /* We make the Windows Caret invisible, so we can maintain control
2273 of the caret without the user seeing it blink */
2274 unsigned char *bits;
2275 int size, bytewidth;
2276 HPEN savepen;
2277 HDC hdc;
2278
2279 bytewidth = (This->data->font_width + 15) / 16 * 2;
2280 size = bytewidth * This->data->font_height;
2281 bits = malloc(size);
2282 memset(bits, 0x00, size);
2283 caretbm = CreateBitmap(This->data->font_width,
2284 This->data->font_height, 1, 1, bits);
2285 free(bits);
2286 CreateCaret(This->data->hwndMain, caretbm,
2287 This->data->font_height, This->data->font_width);
2288 }
2289 /* Here we create a small bitmap to use as the caret
2290 we simply draw a line at the bottom of the bitmap */
2291 if (This->data->caret_style == CARETSTYLE_LINE ) {
2292 unsigned char *bits;
2293 int size, bytewidth;
2294 HPEN savepen;
2295 HDC hdc;
2296
2297 bytewidth = (This->data->font_width + 15) / 16 * 2;
2298 size = bytewidth * This->data->font_height;
2299 bits = malloc(size);
2300 memset(bits, 0x00, size);
2301 caretbm = CreateBitmap(This->data->font_width,
2302 This->data->font_height, 1, 1, bits);
2303 free(bits);
2304 hdc = CreateCompatibleDC(NULL);
2305 SelectObject(hdc, caretbm);
2306 savepen = SelectObject(hdc,
2307 CreatePen(PS_SOLID, 0, RGB(255,255,255)));
2308 MoveToEx(hdc, 0, This->data->font_height-2, NULL);
2309 LineTo(hdc, This->data->font_width, This->data->font_height-2);
2310 savepen = SelectObject(hdc, savepen);
2311 DeleteObject(savepen);
2312 DeleteDC(hdc);
2313 CreateCaret(This->data->hwndMain, caretbm,
2314 This->data->font_height, This->data->font_width);
2315 }
2316 else {
2317 /* for the standard "blinking block", we just use the windows default
2318 shape for the caret */
2319 CreateCaret(This->data->hwndMain, NULL, This->data->font_width,
2320 This->data->font_height);
2321 }
2322 }
2323
2324 /****i* lib5250/win32_move_caret
2325 * NAME
2326 * win32_move_caret
2327 * SYNOPSIS
2328 * win32_move_caret (globTerm);
2329 * INPUTS
2330 * Tn5250Terminal * This -
2331 * DESCRIPTION
2332 * Move the caret to a position on the screen.
2333 * to the coordinates in This->data->caretx, This->data->carety
2334 *****/
2335
win32_move_caret(HDC hdc,Tn5250Terminal * This)2336 void win32_move_caret(HDC hdc, Tn5250Terminal *This) {
2337
2338 /* move the Windows caret */
2339
2340 SetCaretPos(This->data->caretx, This->data->carety);
2341
2342 /* Since the Windows caret is invisible, make our own box now */
2343 if ( (This->data->caret_style == CARETSTYLE_NOBLINK) &&
2344 (! This->data->caretok) )
2345 {
2346 HPEN savepen;
2347 HBRUSH savebrush;
2348 int savemode;
2349 savepen = SelectObject(hdc, GetStockObject(WHITE_PEN));
2350 savebrush = SelectObject(hdc, GetStockObject(WHITE_BRUSH));
2351 savemode = SetROP2(hdc, R2_NOT);
2352 Rectangle(hdc, This->data->caretx, This->data->carety,
2353 (This->data->caretx + This->data->font_width),
2354 (This->data->carety + This->data->font_height));
2355 SetROP2(hdc, savemode);
2356 SelectObject(hdc, savepen);
2357 SelectObject(hdc, savebrush);
2358 This->data->caretok = 1;
2359 }
2360
2361 return;
2362 }
2363
2364
2365 /****i* lib5250/win32_hide_caret
2366 * NAME
2367 * win32_hide_caret
2368 * SYNOPSIS
2369 * win32_hide_caret (globTerm);
2370 * INPUTS
2371 * Tn5250Terminal * This -
2372 * DESCRIPTION
2373 * Hide the caret, usually done when the window loses focus
2374 *****/
win32_hide_caret(HDC hdc,Tn5250Terminal * This)2375 void win32_hide_caret(HDC hdc, Tn5250Terminal *This) {
2376
2377 HideCaret (This->data->hwndMain);
2378 DestroyCaret ();
2379
2380 return;
2381 }
2382
2383
2384 /****i* lib5250/win32_expand_text_selection
2385 * NAME
2386 * win32_expand_text_selection
2387 * SYNOPSIS
2388 * win32_expand_text_selection (globTerm);
2389 * INPUTS
2390 * Tn5250Terminal * This -
2391 * DESCRIPTION
2392 * This converts the mouse selection points (defined by
2393 * This->data->selstr & This->data->selend) to a rectangle of
2394 * selected text (by aligning the points with the text start/end pos)
2395 *****/
win32_expand_text_selection(Tn5250Terminal * This)2396 void win32_expand_text_selection(Tn5250Terminal *This) {
2397
2398 RECT cr;
2399 int cx, cy;
2400 int x;
2401
2402 TN5250_ASSERT(This!=NULL);
2403 TN5250_ASSERT(This->data->font_width>0);
2404
2405 /* change the points so that selstr is the upper left corner
2406 and selend is the lower right corner. */
2407
2408 #define TN5250_FLIPEM(a, b) if (a>b) { x = a; a = b; b = x; }
2409 TN5250_FLIPEM(This->data->selstr.x, This->data->selend.x)
2410 TN5250_FLIPEM(This->data->selstr.y, This->data->selend.y)
2411 #undef TN5250_FLIPEM
2412
2413 /* constrain the coordinates to the window's client area */
2414
2415 GetClientRect(This->data->hwndMain, &cr);
2416
2417 if (This->data->selend.x < cr.left) This->data->selend.x = cr.left;
2418 if (This->data->selend.x > cr.right) This->data->selend.x = cr.right;
2419 if (This->data->selend.y < cr.top) This->data->selend.y = cr.top;
2420 if (This->data->selend.y > cr.bottom) This->data->selend.y = cr.bottom;
2421
2422 if (This->data->selstr.x < cr.left) This->data->selstr.x = cr.left;
2423 if (This->data->selstr.x > cr.right) This->data->selstr.x = cr.right;
2424 if (This->data->selstr.y < cr.top) This->data->selstr.y = cr.top;
2425 if (This->data->selstr.y > cr.bottom) This->data->selstr.y = cr.bottom;
2426
2427
2428 /* move selection start position to nearest character */
2429
2430 cx = This->data->selstr.x / This->data->font_width;
2431 This->data->selstr.x = cx * This->data->font_width;
2432 cy = This->data->selstr.y / This->data->font_height;
2433 This->data->selstr.y = cy * This->data->font_height;
2434
2435 TN5250_LOG (("Selection starts at sx=%d,sy=%d\n", cx,cy));
2436
2437 /* move selection end position to nearest character */
2438
2439 cx = This->data->selend.x / This->data->font_width;
2440 This->data->selend.x = cx * This->data->font_width
2441 + (This->data->font_width-1);
2442 cy = This->data->selend.y / This->data->font_height;
2443 This->data->selend.y = cy * This->data->font_height
2444 + (This->data->font_height-1);
2445
2446 TN5250_LOG (("Selection ends at ex=%d,ey=%d\n", cx,cy));
2447
2448 }
2449
2450
2451 /****i* lib5250/win32_copy_text_selection
2452 * NAME
2453 * win32_copy_text_selection
2454 * SYNOPSIS
2455 * win32_copy_text_selection (globTerm, globDisplay);
2456 * INPUTS
2457 * Tn5250Terminal * This -
2458 * Tn5250Display * display -
2459 * DESCRIPTION
2460 * This retrieves the text in the selected area and copies it to
2461 * the global Windows clipboard.
2462 *****/
win32_copy_text_selection(Tn5250Terminal * This,Tn5250Display * display)2463 void win32_copy_text_selection(Tn5250Terminal *This, Tn5250Display *display)
2464 {
2465 int x, y;
2466 int cx, cy;
2467 int sx, sy, ex, ey;
2468 unsigned char c;
2469 unsigned char *buf;
2470 int bp;
2471 int bufsize;
2472 HGLOBAL hBuf;
2473 HBITMAP hBm;
2474 HDC hdc;
2475
2476 TN5250_ASSERT(This!=NULL);
2477 TN5250_ASSERT(display!=NULL);
2478 TN5250_ASSERT(This->data->font_width>0);
2479
2480 /* figure out the dimensions (in text chars) and make a global buffer */
2481
2482 sx = This->data->selstr.x / This->data->font_width;
2483 ex = This->data->selend.x / This->data->font_width;
2484 sy = This->data->selstr.y / This->data->font_height;
2485 ey = This->data->selend.y / This->data->font_height;
2486
2487 while (ey>tn5250_display_height(display)) ey--;
2488
2489 TN5250_LOG (("Copy to clipboard sx=%d,sy=%d,ex=%d,ey=%d\n",
2490 sx,sy,ex,ey));
2491
2492 bufsize = ((ex-sx)+3) * ((ey-sy)+1) - 1;
2493 hBuf = GlobalAlloc(GHND|GMEM_SHARE, bufsize);
2494 TN5250_ASSERT(hBuf!=NULL);
2495
2496 /* populate the global buffer with the text data, inserting CR/LF
2497 in between each line that was selected */
2498
2499 buf = GlobalLock(hBuf);
2500 bp = -1;
2501 for (y = sy; y <= ey; y++) {
2502
2503 for (x = sx; x <= ex; x++) {
2504 c = tn5250_display_char_at(display, y, x);
2505 if (((c & 0xe0) == 0x20 )||(c < 0x40 && c > 0x00)||(c == 0xff))
2506 c = ' ';
2507 else
2508 c = tn5250_char_map_to_local(
2509 tn5250_display_char_map(display), c);
2510 bp++;
2511 if (bp==bufsize) break;
2512 buf[bp] = c;
2513 }
2514
2515 if (y != ey) {
2516 bp++;
2517 if (bp==bufsize) break;
2518 buf[bp] = '\r';
2519 bp++;
2520 if (bp==bufsize) break;
2521 buf[bp] = '\n';
2522 }
2523
2524 }
2525
2526 TN5250_LOG (("Clipboard buffer size = %d\n", bufsize));
2527 for (bp=0; bp<bufsize; bp++) {
2528 TN5250_LOG (("%x ", buf[bp]));
2529 }
2530 TN5250_LOG (("<end>\n"));
2531
2532 GlobalUnlock(hBuf);
2533
2534 /* create a bitmap version of the copy buffer as well...
2535 this allows image programs to paste the buffer as a bitmap */
2536
2537 cx = (This->data->selend.x - This->data->selstr.x) + 1;
2538 cy = (This->data->selend.y - This->data->selstr.y) + 1;
2539
2540 hdc = GetDC(This->data->hwndMain);
2541 hBm = CreateCompatibleBitmap(hdc, cx, cy);
2542 ReleaseDC(This->data->hwndMain, hdc);
2543 hdc = CreateCompatibleDC(NULL);
2544 SelectObject(hdc, hBm);
2545 BitBlt(hdc, 0, 0, cx, cy, bmphdc, This->data->selstr.x,
2546 This->data->selstr.y, SRCCOPY);
2547 DeleteDC(hdc);
2548
2549
2550 /* finally, copy both the global buffer & the bitmap to the
2551 clipboard. After this, we should not try to use (or free!)
2552 the buffer/bitmap... they're Windows' property now!
2553 */
2554
2555 OpenClipboard (This->data->hwndMain);
2556 EmptyClipboard ();
2557
2558 switch (This->data->copymode) {
2559 case 1: /* plain text only */
2560 SetClipboardData(CF_TEXT, hBuf);
2561 DeleteObject(hBm);
2562 break;
2563 case 2: /* bitmap only */
2564 SetClipboardData(CF_BITMAP, hBm);
2565 GlobalFree(hBuf);
2566 break;
2567 default:
2568 SetClipboardData(CF_TEXT, hBuf);
2569 SetClipboardData(CF_BITMAP, hBm);
2570 break;
2571 }
2572
2573 CloseClipboard ();
2574 }
2575
2576
2577 /****i* lib5250/win32_paste_text_selection
2578 * NAME
2579 * win32_paste_text_selection
2580 * SYNOPSIS
2581 * win32_paste_text_selection (globTerm, globDisplay);
2582 * INPUTS
2583 * Tn5250Terminal * This -
2584 * Tn5250Display * display -
2585 * DESCRIPTION
2586 * Convert data in the windows clipboard into keystrokes
2587 * and paste them into the keyboard buffer.
2588 * Note: Increasing the MAX_K_BUF_LEN will speed this
2589 * routine up...
2590 *****/
win32_paste_text_selection(HWND hwnd,Tn5250Terminal * term,Tn5250Display * display)2591 void win32_paste_text_selection(HWND hwnd, Tn5250Terminal *term,
2592 Tn5250Display *display) {
2593
2594 HGLOBAL hBuf;
2595 unsigned char *pBuf;
2596 unsigned char *pNewBuf;
2597 int size, pos;
2598 int thisrow;
2599
2600 pNewBuf = NULL;
2601
2602 /*
2603 * If there's any data that we can paste, read it from
2604 * the clipboard.
2605 */
2606
2607 if (IsClipboardFormatAvailable(CF_TEXT)) {
2608
2609 OpenClipboard(hwnd);
2610
2611 hBuf = GetClipboardData(CF_TEXT);
2612
2613 if (hBuf != NULL) {
2614 size = GlobalSize(hBuf);
2615 pNewBuf = malloc(size);
2616 pBuf = GlobalLock(hBuf);
2617 strncpy(pNewBuf, pBuf, size);
2618 pNewBuf[size] = '\0'; /* just a precaution */
2619 GlobalUnlock(hBuf);
2620 }
2621
2622 CloseClipboard();
2623
2624 }
2625
2626 /*
2627 * convert text data into keyboard messages, just as if someone
2628 * was typing this data at the keyboard.
2629 */
2630
2631 if (pNewBuf != NULL) {
2632 int dump_count = MAX_K_BUF_LEN;
2633 size = strlen(pNewBuf);
2634 thisrow = 0;
2635 for (pos=0; pos<size; pos++) {
2636 switch (pNewBuf[pos]) {
2637 case '\r':
2638 while (thisrow > 0) {
2639 win32_terminal_queuekey(hwnd, term, K_LEFT);
2640 thisrow --;
2641 if (term->data->k_buf_len == dump_count) {
2642 tn5250_display_do_keys(display);
2643 }
2644 }
2645 break;
2646 case '\n':
2647 thisrow = 0;
2648 win32_terminal_queuekey(hwnd, term, K_DOWN);
2649 tn5250_display_do_keys(display);
2650 break;
2651 default:
2652 thisrow++;
2653 win32_terminal_queuekey(hwnd, term, pNewBuf[pos]);
2654 break;
2655 }
2656 if (term->data->k_buf_len == dump_count) {
2657 tn5250_display_do_keys(display);
2658 }
2659 }
2660 free(pNewBuf);
2661 PostMessage(hwnd, WM_TN5250_KEY_DATA, 0, 0);
2662 }
2663
2664 }
2665
2666
2667 /****i* lib5250/win32_get_printer_info
2668 * NAME
2669 * win32_get_printer_info
2670 * SYNOPSIS
2671 * win32_get_printer_info (globTerm);
2672 * INPUTS
2673 * Tn5250Terminal * This -
2674 * DESCRIPTION
2675 * This displays a standard Windows printer dialog allowing
2676 * the user to choose which printer he would like to print to
2677 * and stores a pointer to the resulting PRINTDLG structure
2678 * in This->data->pd.
2679 *
2680 * If you call this again without first calling the
2681 * win32_destroy_printer_info function, no dialog is displayed,
2682 * and the same pointer is returned.
2683 *****/
win32_get_printer_info(Tn5250Terminal * This)2684 PRINTDLG * win32_get_printer_info(Tn5250Terminal *This) {
2685
2686 PRINTDLG *pd;
2687
2688 if (This->data->pd != NULL)
2689 return This->data->pd;
2690
2691 This->data->pd = (PRINTDLG *) malloc(sizeof(PRINTDLG));
2692
2693 pd = This->data->pd; /* save a little typing */
2694
2695 memset(pd, 0, sizeof(PRINTDLG));
2696 pd->lStructSize = sizeof(PRINTDLG);
2697 pd->hwndOwner = This->data->hwndMain;
2698 pd->hDevMode = NULL; /* windows will make one. */
2699 pd->hDevNames = NULL; /* windows will make one. */
2700 pd->Flags = PD_USEDEVMODECOPIESANDCOLLATE | PD_RETURNDC
2701 | PD_NOPAGENUMS | PD_NOSELECTION | PD_ALLPAGES;
2702 pd->nCopies = 1;
2703 pd->nMinPage = 1;
2704 pd->nMaxPage = 1;
2705
2706
2707 if (PrintDlg(This->data->pd) == 0) {
2708 TN5250_LOG (("PrintDlg() error %d\n", CommDlgExtendedError()));
2709 free(This->data->pd);
2710 This->data->pd = NULL;
2711 return NULL;
2712 }
2713
2714 if (!(GetDeviceCaps(pd->hDC, RASTERCAPS) & RC_STRETCHBLT)) {
2715 win32_destroy_printer_info(This);
2716 TN5250_LOG (("WIN32: StretchBlt not available for this printer.\n"));
2717 msgboxf("This printer does not support the StretchBlt function.\r\n"
2718 "Printing cancelled.");
2719 }
2720
2721 return This->data->pd;
2722 }
2723
2724
2725 /****i* lib5250/win32_destroy_printer_info
2726 * NAME
2727 * win32_destroy_printer_info
2728 * SYNOPSIS
2729 * win32_destroy_printer_info (globTerm);
2730 * INPUTS
2731 * Tn5250Terminal * This -
2732 * DESCRIPTION
2733 * This frees up the data allocated by the function
2734 * win32_get_printer_info()
2735 *****/
win32_destroy_printer_info(Tn5250Terminal * This)2736 void win32_destroy_printer_info(Tn5250Terminal *This) {
2737
2738 if (This->data->pd->hDC != NULL)
2739 DeleteDC(This->data->pd->hDC);
2740 if (This->data->pd->hDevMode != NULL)
2741 free(This->data->pd->hDevMode);
2742 if (This->data->pd->hDevNames != NULL)
2743 free(This->data->pd->hDevNames);
2744 free(This->data->pd);
2745 This->data->pd = NULL;
2746
2747 return;
2748 }
2749
2750
2751
2752 /****i* lib5250/win32_print_screen
2753 * NAME
2754 * win32_print_screen
2755 * SYNOPSIS
2756 * win32_print_screen(globTerm, globDisplay);
2757 * INPUTS
2758 * Tn5250Display * This - TN5250 terminal object
2759 * Tn5250Display * display - TN5250 display object
2760 * DESCRIPTION
2761 * This builds a B&W bitmap of our current display buffer, and
2762 * sends it to the printer.
2763 *****/
win32_print_screen(Tn5250Terminal * This,Tn5250Display * display)2764 void win32_print_screen(Tn5250Terminal *This, Tn5250Display *display) {
2765
2766 PRINTDLG *pd;
2767 DOCINFO di;
2768 HBITMAP bmap;
2769 HDC screenDC, hdc;
2770 float pelsX1, pelsX2;
2771 float scaleX, pixMax;
2772 int rc;
2773 int x, y, h, w, h2, w2;
2774 int i, size;
2775 RECT rect;
2776 LOGBRUSH lb;
2777 HBRUSH oldbrush;
2778 HPEN oldpen;
2779 Tn5250Win32Attribute *mymap;
2780
2781
2782 /* get info about the printer. The GDI device context will
2783 be in pd->hDC. We need this to print. */
2784
2785 if ((pd = win32_get_printer_info(This)) == NULL) {
2786 TN5250_LOG(("win32_get_printer_info failed.\n"));
2787 return;
2788 }
2789 if ( pd->hDC == NULL ) {
2790 TN5250_LOG(("pd->hDC == NULL!!\n"));
2791 }
2792 TN5250_ASSERT ( pd->hDC != NULL );
2793
2794
2795 /* Get screen size & horizontal resolution. We need this to
2796 scale the screen output so that it looks good on the printer. */
2797
2798 GetClientRect(This->data->hwndMain, &rect);
2799 x = rect.left;
2800 y = rect.top;
2801 h = (rect.bottom - rect.top) + 7;
2802 w = (rect.right - rect.left) + 7;
2803 screenDC = GetDC(This->data->hwndMain);
2804 pelsX1 = (float) GetDeviceCaps(screenDC, LOGPIXELSX);
2805
2806
2807 /* create a bitmap to draw the screen into. We want to redraw the
2808 screen in black & white and put a border around it */
2809
2810 bmap = CreateCompatibleBitmap(screenDC, w+6, h+6);
2811 hdc = CreateCompatibleDC(NULL);
2812 SelectObject(hdc, bmap);
2813
2814
2815 /* fill the bitmap by making a white rectangle with a black border */
2816
2817 lb.lbStyle = BS_SOLID;
2818 lb.lbColor = RGB(255,255,255);
2819 lb.lbHatch = 0;
2820
2821 oldbrush = SelectObject(hdc, CreateBrushIndirect(&lb));
2822 oldpen = SelectObject(hdc, CreatePen(PS_SOLID, 0, RGB(0,0,0)));
2823 Rectangle(hdc, 0, 0, w, h);
2824 SelectObject(hdc, oldbrush);
2825 oldpen = SelectObject(hdc, oldpen);
2826 DeleteObject(oldpen);
2827 oldbrush = SelectObject(hdc, oldbrush);
2828 DeleteObject(oldbrush);
2829
2830 /* create a black on white attribute map, so that win32_do_terminal_update
2831 will paint the screen in our colors. */
2832
2833 i = 0;
2834 while (attribute_map[i].colorindex != -1)
2835 i++;
2836 size = (i+1) * sizeof(Tn5250Win32Attribute);
2837 mymap = (Tn5250Win32Attribute *) malloc(size);
2838 if ( mymap == NULL ) {
2839 TN5250_LOG(("mymap == NULL. Unable to allocate memory.\n"));
2840 }
2841 memcpy(mymap, attribute_map, size);
2842 for (i=0; mymap[i].colorindex != -1; i++) {
2843 if ( mymap[i].colorindex == A_5250_BLACK )
2844 mymap[i].fg = RGB(255,255,255);
2845 else
2846 mymap[i].fg = RGB(0,0,0);
2847 }
2848
2849 /* re-draw the screen into our new bitmap */
2850
2851 win32_do_terminal_update(hdc, This, display, mymap, 3, 3);
2852 free(mymap);
2853
2854
2855 /* start a new printer document */
2856
2857 memset(&di, 0, sizeof(DOCINFO));
2858 di.cbSize = sizeof(DOCINFO);
2859 di.lpszDocName = "TN5250 Print Screen";
2860 di.lpszOutput = (LPTSTR) NULL;
2861 di.lpszDatatype= (LPTSTR) NULL;
2862 di.fwType = 0;
2863
2864 rc = StartDoc(pd->hDC, &di);
2865 if (rc == SP_ERROR) {
2866 msgboxf("StartDoc() ended in error.\r\n");
2867 win32_destroy_printer_info(This);
2868 return;
2869 }
2870
2871 rc = StartPage(pd->hDC);
2872 if (rc <= 0) {
2873 msgboxf("StartPage() ended in error.\r\n");
2874 win32_destroy_printer_info(This);
2875 return;
2876 }
2877
2878
2879 /* calculate the scaling factor:
2880 a) If possible, scale the screen image so that it uses the same
2881 number of logical inches on the printout as it did on the screen.
2882 (we do this by dividing the printer's logical pixels per inch
2883 by the screen's logical pixels per inch)
2884 b) If that doesn't fit on the page, then just scale it to the width
2885 of the page.
2886 */
2887
2888 pelsX2 = (float) GetDeviceCaps(pd->hDC, LOGPIXELSX);
2889 pixMax = (float) GetDeviceCaps(pd->hDC, HORZRES);
2890
2891 TN5250_LOG (("WIN32: PrintKey: Screen is %f pix/in, Printer is %f pix/in"
2892 " and %f pix wide\n", pelsX1, pelsX2, pixMax));
2893
2894 if (pelsX1 > pelsX2)
2895 scaleX = (pelsX1 / pelsX2);
2896 else
2897 scaleX = (pelsX2 / pelsX1);
2898
2899 w2 = w * scaleX;
2900 if (w2 > pixMax)
2901 scaleX = pixMax / w;
2902 w2 = w * scaleX;
2903 h2 = h * scaleX;
2904
2905 TN5250_LOG (("WIN32: PrintKey: Since Window is %d pixels wide, we'll "
2906 "make the printer image %d by %d\n", w, w2, h2));
2907
2908 /* This will stretch the bitmap to the new height & width while (at the
2909 same time) copying it to the printer */
2910
2911 if (StretchBlt(pd->hDC, 0, 0, w2, h2, hdc, x, y, w, h, SRCCOPY)==0) {
2912 LPVOID lpMsgBuf;
2913 FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM|FORMAT_MESSAGE_ALLOCATE_BUFFER,
2914 NULL, GetLastError(), MAKELANGID(LANG_NEUTRAL,SUBLANG_DEFAULT),
2915 (LPTSTR) &lpMsgBuf, 0, NULL);
2916 TN5250_LOG (("StretchBlt error %s\n", (char *)lpMsgBuf));
2917 MessageBox(NULL, lpMsgBuf, "StretchBlt", MB_OK|MB_ICONINFORMATION);
2918 LocalFree(lpMsgBuf);
2919 BitBlt(pd->hDC, 0, 0, w, h, hdc, x, y, SRCCOPY); // worth a try!
2920 EndPage(pd->hDC);
2921 EndDoc(pd->hDC);
2922 free(This->data->pd);
2923 This->data->pd = NULL;
2924 pd = NULL;
2925 return;
2926 }
2927
2928 /* close printer document */
2929
2930 EndPage(pd->hDC);
2931 EndDoc(pd->hDC);
2932
2933 /* notify user */
2934
2935 MessageBox(This->data->hwndMain, "Print screen successful!", "TN5250",
2936 MB_OK|MB_ICONINFORMATION);
2937
2938 if (This->data->always_ask)
2939 win32_destroy_printer_info(This);
2940 }
2941
2942 /****i* lib5250/win32_move_caret_to
2943 * NAME
2944 * win32_move_caret_to
2945 * SYNOPSIS
2946 * win32_move_caret_to(globTerm, globDisplay, y, x);
2947 * INPUTS
2948 * Tn5250Display * This - TN5250 terminal object
2949 * Tn5250Display * disp - TN5250 display object
2950 * short y - y position (pixels)
2951 * short x - x position (pixels)
2952 * DESCRIPTION
2953 * This moves the caret to a given position on the display.
2954 * (So that the cursor can be moved to the position that the
2955 * mouse was clicked in.)
2956 *****/
win32_move_caret_to(Tn5250Terminal * This,Tn5250Display * disp,short y,short x)2957 void win32_move_caret_to(Tn5250Terminal *This, Tn5250Display *disp,
2958 short y, short x) {
2959
2960 int cx, cy;
2961
2962 /* erase old caret if needed */
2963
2964 if (This->data->caret_style == CARETSTYLE_NOBLINK) {
2965 This->data->caretok = 0;
2966 win32_move_caret(bmphdc, This);
2967 }
2968
2969 /* Set new caret position */
2970
2971 cx = x / This->data->font_width;
2972 cy = y / This->data->font_height;
2973 tn5250_display_set_cursor(disp, cy, cx);
2974
2975 This->data->caretx = cx * This->data->font_width;
2976 This->data->carety = cy * This->data->font_height;
2977
2978 /* redraw caret */
2979
2980 This->data->caretok = 0;
2981 win32_move_caret(bmphdc, This);
2982
2983 TN5250_LOG(("Caret moved to %d, %d\n",
2984 tn5250_display_cursor_x(disp),
2985 tn5250_display_cursor_y(disp)));
2986
2987 }
2988