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