wined3d: Pass a wined3d_adapter instead of wined3d_gl_info to FFP pipe emulation...
[wine.git] / programs / conhost / window.c
blob043ecd5510f46f06ba223c6861844cf93566eee8
1 /*
2 * Copyright 2001 Eric Pouech
3 * Copyright 2020 Jacek Caban for CodeWeavers
5 * This library is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU Lesser General Public
7 * License as published by the Free Software Foundation; either
8 * version 2.1 of the License, or (at your option) any later version.
10 * This library is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 * Lesser General Public License for more details.
15 * You should have received a copy of the GNU Lesser General Public
16 * License along with this library; if not, write to the Free Software
17 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
20 #include <stdlib.h>
22 #include "conhost.h"
24 #include <commctrl.h>
25 #include <winreg.h>
27 #include "wine/debug.h"
29 WINE_DEFAULT_DEBUG_CHANNEL(console);
31 #define WM_UPDATE_CONFIG (WM_USER + 1)
33 enum update_state
35 UPDATE_NONE,
36 UPDATE_PENDING,
37 UPDATE_BUSY
40 struct console_window
42 HDC mem_dc; /* memory DC holding the bitmap below */
43 HBITMAP bitmap; /* bitmap of display window content */
44 HFONT font; /* font used for rendering, usually fixed */
45 HMENU popup_menu; /* popup menu triggered by right mouse click */
46 HBITMAP cursor_bitmap; /* bitmap used for the caret */
47 BOOL in_selection; /* an area is being selected */
48 COORD selection_start; /* selection coordinates */
49 COORD selection_end;
50 unsigned int ui_charset; /* default UI charset */
51 WCHAR *config_key; /* config registry key name */
52 LONG ext_leading; /* external leading for font */
54 BOOL quick_edit; /* whether mouse ops are sent to app or used for content selection */
55 unsigned int menu_mask; /* MK_CONTROL MK_SHIFT mask to drive submenu opening */
56 COORD win_pos; /* position (in cells) of visible part of screen buffer in window */
57 unsigned int win_width; /* size (in cells) of visible part of window (width & height) */
58 unsigned int win_height;
59 unsigned int cursor_size; /* in % of cell height */
60 int cursor_visible; /* cursor visibility */
61 unsigned int sb_width; /* active screen buffer width */
62 unsigned int sb_height; /* active screen buffer height */
63 COORD cursor_pos; /* cursor position */
65 RECT update; /* screen buffer update rect */
66 enum update_state update_state; /* update state */
69 struct console_config
71 DWORD color_map[16]; /* console color table */
72 unsigned int cell_width; /* width in pixels of a character */
73 unsigned int cell_height; /* height in pixels of a character */
74 unsigned int cursor_size; /* in % of cell height */
75 int cursor_visible; /* cursor visibility */
76 unsigned int attr; /* default fill attributes (screen colors) */
77 unsigned int popup_attr ; /* pop-up color attributes */
78 unsigned int history_size; /* number of commands in history buffer */
79 unsigned int history_mode; /* flag if commands are not stored twice in buffer */
80 unsigned int insert_mode; /* TRUE to insert text at the cursor location; FALSE to overwrite it */
81 unsigned int menu_mask; /* MK_CONTROL MK_SHIFT mask to drive submenu opening */
82 unsigned int quick_edit; /* whether mouse ops are sent to app or used for content selection */
83 unsigned int sb_width; /* active screen buffer width */
84 unsigned int sb_height; /* active screen buffer height */
85 unsigned int win_width; /* size (in cells) of visible part of window (width & height) */
86 unsigned int win_height;
87 COORD win_pos; /* position (in cells) of visible part of screen buffer in window */
88 unsigned int edition_mode; /* edition mode flavor while line editing */
89 unsigned int font_pitch_family;
90 unsigned int font_weight;
91 WCHAR face_name[LF_FACESIZE];
94 static const char *debugstr_config( const struct console_config *config )
96 return wine_dbg_sprintf( "cell=(%u,%u) cursor=(%d,%d) attr=%02x pop-up=%02x font=%s/%u/%u "
97 "hist=%u/%d flags=%c%c msk=%08x sb=(%u,%u) win=(%u,%u)x(%u,%u) edit=%u",
98 config->cell_width, config->cell_height, config->cursor_size,
99 config->cursor_visible, config->attr, config->popup_attr,
100 wine_dbgstr_w(config->face_name), config->font_pitch_family,
101 config->font_weight, config->history_size,
102 config->history_mode ? 1 : 2,
103 config->insert_mode ? 'I' : 'i',
104 config->quick_edit ? 'Q' : 'q',
105 config->menu_mask, config->sb_width, config->sb_height,
106 config->win_pos.X, config->win_pos.Y, config->win_width,
107 config->win_height, config->edition_mode );
110 static const char *debugstr_logfont( const LOGFONTW *lf, unsigned int ft )
112 return wine_dbg_sprintf( "%s%s%s%s lfHeight=%ld lfWidth=%ld lfEscapement=%ld "
113 "lfOrientation=%ld lfWeight=%ld lfItalic=%u lfUnderline=%u "
114 "lfStrikeOut=%u lfCharSet=%u lfPitchAndFamily=%u lfFaceName=%s",
115 (ft & RASTER_FONTTYPE) ? "raster" : "",
116 (ft & TRUETYPE_FONTTYPE) ? "truetype" : "",
117 ((ft & (RASTER_FONTTYPE|TRUETYPE_FONTTYPE)) == 0) ? "vector" : "",
118 (ft & DEVICE_FONTTYPE) ? "|device" : "",
119 lf->lfHeight, lf->lfWidth, lf->lfEscapement, lf->lfOrientation,
120 lf->lfWeight, lf->lfItalic, lf->lfUnderline, lf->lfStrikeOut,
121 lf->lfCharSet, lf->lfPitchAndFamily, wine_dbgstr_w( lf->lfFaceName ));
124 static const char *debugstr_textmetric( const TEXTMETRICW *tm, unsigned int ft )
126 return wine_dbg_sprintf( "%s%s%s%s tmHeight=%ld tmAscent=%ld tmDescent=%ld "
127 "tmAveCharWidth=%ld tmMaxCharWidth=%ld tmWeight=%ld "
128 "tmPitchAndFamily=%u tmCharSet=%u",
129 (ft & RASTER_FONTTYPE) ? "raster" : "",
130 (ft & TRUETYPE_FONTTYPE) ? "truetype" : "",
131 ((ft & (RASTER_FONTTYPE|TRUETYPE_FONTTYPE)) == 0) ? "vector" : "",
132 (ft & DEVICE_FONTTYPE) ? "|device" : "",
133 tm->tmHeight, tm->tmAscent, tm->tmDescent, tm->tmAveCharWidth,
134 tm->tmMaxCharWidth, tm->tmWeight, tm->tmPitchAndFamily,
135 tm->tmCharSet );
138 /* read the basic configuration from any console key or subkey */
139 static void load_registry_key( HKEY key, struct console_config *config )
141 DWORD type, count, val, i;
142 WCHAR color_name[13];
144 for (i = 0; i < ARRAY_SIZE(config->color_map); i++)
146 wsprintfW( color_name, L"ColorTable%02d", i );
147 count = sizeof(val);
148 if (!RegQueryValueExW( key, color_name, 0, &type, (BYTE *)&val, &count ))
149 config->color_map[i] = val;
152 count = sizeof(val);
153 if (!RegQueryValueExW( key, L"CursorSize", 0, &type, (BYTE *)&val, &count ))
154 config->cursor_size = val;
156 count = sizeof(val);
157 if (!RegQueryValueExW( key, L"CursorVisible", 0, &type, (BYTE *)&val, &count ))
158 config->cursor_visible = val;
160 count = sizeof(val);
161 if (!RegQueryValueExW( key, L"EditionMode", 0, &type, (BYTE *)&val, &count ))
162 config->edition_mode = val;
164 count = sizeof(config->face_name);
165 RegQueryValueExW( key, L"FaceName", 0, &type, (BYTE *)&config->face_name, &count );
167 count = sizeof(val);
168 if (!RegQueryValueExW( key, L"FontFamily", 0, &type, (BYTE *)&val, &count ) ||
169 !RegQueryValueExW( key, L"FontPitchFamily", 0, &type, (BYTE *)&val, &count ))
170 config->font_pitch_family = val;
172 count = sizeof(val);
173 if (!RegQueryValueExW( key, L"FontSize", 0, &type, (BYTE *)&val, &count ))
175 int height = HIWORD(val);
176 int width = LOWORD(val);
177 /* A value of zero reflects the default settings */
178 if (height) config->cell_height = MulDiv( height, GetDpiForSystem(), USER_DEFAULT_SCREEN_DPI );
179 if (width) config->cell_width = MulDiv( width, GetDpiForSystem(), USER_DEFAULT_SCREEN_DPI );
182 count = sizeof(val);
183 if (!RegQueryValueExW( key, L"FontWeight", 0, &type, (BYTE *)&val, &count ))
184 config->font_weight = val;
186 count = sizeof(val);
187 if (!RegQueryValueExW( key, L"HistoryBufferSize", 0, &type, (BYTE *)&val, &count ))
188 config->history_size = val;
190 count = sizeof(val);
191 if (!RegQueryValueExW( key, L"HistoryNoDup", 0, &type, (BYTE *)&val, &count ))
192 config->history_mode = val;
194 count = sizeof(val);
195 if (!RegQueryValueExW( key, L"wszInsertMode", 0, &type, (BYTE *)&val, &count ))
196 config->insert_mode = val;
198 count = sizeof(val);
199 if (!RegQueryValueExW( key, L"MenuMask", 0, &type, (BYTE *)&val, &count ))
200 config->menu_mask = val;
202 count = sizeof(val);
203 if (!RegQueryValueExW( key, L"PopupColors", 0, &type, (BYTE *)&val, &count ))
204 config->popup_attr = val;
206 count = sizeof(val);
207 if (!RegQueryValueExW( key, L"QuickEdit", 0, &type, (BYTE *)&val, &count ))
208 config->quick_edit = val;
210 count = sizeof(val);
211 if (!RegQueryValueExW( key, L"ScreenBufferSize", 0, &type, (BYTE *)&val, &count ))
213 config->sb_height = HIWORD(val);
214 config->sb_width = LOWORD(val);
217 count = sizeof(val);
218 if (!RegQueryValueExW( key, L"ScreenColors", 0, &type, (BYTE *)&val, &count ))
219 config->attr = val;
221 count = sizeof(val);
222 if (!RegQueryValueExW( key, L"WindowSize", 0, &type, (BYTE *)&val, &count ))
224 config->win_height = HIWORD(val);
225 config->win_width = LOWORD(val);
229 /* load config from registry */
230 static void load_config( const WCHAR *key_name, struct console_config *config )
232 static const COLORREF color_map[] =
234 RGB(0x00, 0x00, 0x00), RGB(0x00, 0x00, 0x80), RGB(0x00, 0x80, 0x00), RGB(0x00, 0x80, 0x80),
235 RGB(0x80, 0x00, 0x00), RGB(0x80, 0x00, 0x80), RGB(0x80, 0x80, 0x00), RGB(0xC0, 0xC0, 0xC0),
236 RGB(0x80, 0x80, 0x80), RGB(0x00, 0x00, 0xFF), RGB(0x00, 0xFF, 0x00), RGB(0x00, 0xFF, 0xFF),
237 RGB(0xFF, 0x00, 0x00), RGB(0xFF, 0x00, 0xFF), RGB(0xFF, 0xFF, 0x00), RGB(0xFF, 0xFF, 0xFF)
240 HKEY key, app_key;
242 TRACE( "Loading default console settings\n" );
244 memcpy( config->color_map, color_map, sizeof(color_map) );
245 memset( config->face_name, 0, sizeof(config->face_name) );
246 config->cursor_size = 25;
247 config->cursor_visible = 1;
248 config->font_pitch_family = FIXED_PITCH | FF_DONTCARE;
249 config->cell_height = MulDiv( 16, GetDpiForSystem(), USER_DEFAULT_SCREEN_DPI );
250 config->cell_width = MulDiv( 8, GetDpiForSystem(), USER_DEFAULT_SCREEN_DPI );
251 config->font_weight = FW_NORMAL;
253 config->history_size = 50;
254 config->history_mode = 0;
255 config->insert_mode = 1;
256 config->menu_mask = 0;
257 config->popup_attr = 0xF5;
258 config->quick_edit = 0;
259 config->sb_height = 150;
260 config->sb_width = 80;
261 config->attr = 0x000F;
262 config->win_height = 25;
263 config->win_width = 80;
264 config->win_pos.X = 0;
265 config->win_pos.Y = 0;
266 config->edition_mode = 0;
268 /* Load default console settings */
269 if (!RegOpenKeyW( HKEY_CURRENT_USER, L"Console", &key ))
271 load_registry_key( key, config );
273 /* Load app-specific console settings (if any) */
274 if (key_name && !RegOpenKeyW( key, key_name, &app_key ))
276 TRACE( "Loading %s console settings\n", wine_dbgstr_w(key_name) );
277 load_registry_key( app_key, config );
278 RegCloseKey( app_key );
280 RegCloseKey( key );
282 TRACE( "%s\n", debugstr_config( config ));
285 static void save_registry_key( HKEY key, const struct console_config *config, BOOL save_all )
287 struct console_config default_config;
288 DWORD val, width, height, i;
289 WCHAR color_name[13];
291 TRACE( "%s\n", debugstr_config( config ));
293 if (!save_all)
294 load_config( NULL, &default_config );
296 for (i = 0; i < ARRAY_SIZE(config->color_map); i++)
298 if (save_all || config->color_map[i] != default_config.color_map[i])
300 wsprintfW( color_name, L"ColorTable%02d", i );
301 val = config->color_map[i];
302 RegSetValueExW( key, color_name, 0, REG_DWORD, (BYTE *)&val, sizeof(val) );
306 if (save_all || config->cursor_size != default_config.cursor_size)
308 val = config->cursor_size;
309 RegSetValueExW( key, L"CursorSize", 0, REG_DWORD, (BYTE *)&val, sizeof(val) );
312 if (save_all || config->cursor_visible != default_config.cursor_visible)
314 val = config->cursor_visible;
315 RegSetValueExW( key, L"CursorVisible", 0, REG_DWORD, (BYTE *)&val, sizeof(val) );
318 if (save_all || config->edition_mode != default_config.edition_mode)
320 val = config->edition_mode;
321 RegSetValueExW( key, L"EditionMode", 0, REG_DWORD, (BYTE *)&val, sizeof(val) );
324 if (save_all || lstrcmpW( config->face_name, default_config.face_name ))
326 RegSetValueExW( key, L"FaceName", 0, REG_SZ, (BYTE *)&config->face_name,
327 (lstrlenW(config->face_name) + 1) * sizeof(WCHAR) );
330 if (save_all || config->font_pitch_family != default_config.font_pitch_family)
332 val = config->font_pitch_family;
333 RegSetValueExW( key, L"FontFamily", 0, REG_DWORD, (BYTE *)&val, sizeof(val) );
336 if (save_all || config->cell_height != default_config.cell_height ||
337 config->cell_width != default_config.cell_width)
339 width = MulDiv( config->cell_width, USER_DEFAULT_SCREEN_DPI, GetDpiForSystem() );
340 height = MulDiv( config->cell_height, USER_DEFAULT_SCREEN_DPI, GetDpiForSystem() );
341 val = MAKELONG( width, height );
343 RegSetValueExW( key, L"FontSize", 0, REG_DWORD, (BYTE *)&val, sizeof(val) );
346 if (save_all || config->font_weight != default_config.font_weight)
348 val = config->font_weight;
349 RegSetValueExW( key, L"FontWeight", 0, REG_DWORD, (BYTE *)&val, sizeof(val) );
352 if (save_all || config->history_size != default_config.history_size)
354 val = config->history_size;
355 RegSetValueExW( key, L"HistoryBufferSize", 0, REG_DWORD, (BYTE *)&val, sizeof(val) );
358 if (save_all || config->history_mode != default_config.history_mode)
360 val = config->history_mode;
361 RegSetValueExW( key, L"HistoryNoDup", 0, REG_DWORD, (BYTE *)&val, sizeof(val) );
364 if (save_all || config->insert_mode != default_config.insert_mode)
366 val = config->insert_mode;
367 RegSetValueExW( key, L"InsertMode", 0, REG_DWORD, (BYTE *)&val, sizeof(val) );
370 if (save_all || config->menu_mask != default_config.menu_mask)
372 val = config->menu_mask;
373 RegSetValueExW( key, L"MenuMask", 0, REG_DWORD, (BYTE *)&val, sizeof(val) );
376 if (save_all || config->popup_attr != default_config.popup_attr)
378 val = config->popup_attr;
379 RegSetValueExW( key, L"PopupColors", 0, REG_DWORD, (BYTE *)&val, sizeof(val) );
382 if (save_all || config->quick_edit != default_config.quick_edit)
384 val = config->quick_edit;
385 RegSetValueExW( key, L"QuickEdit", 0, REG_DWORD, (BYTE *)&val, sizeof(val) );
388 if (save_all || config->sb_width != default_config.sb_width ||
389 config->sb_height != default_config.sb_height)
391 val = MAKELONG(config->sb_width, config->sb_height);
392 RegSetValueExW( key, L"ScreenBufferSize", 0, REG_DWORD, (BYTE *)&val, sizeof(val) );
395 if (save_all || config->attr != default_config.attr)
397 val = config->attr;
398 RegSetValueExW( key, L"ScreenColors", 0, REG_DWORD, (BYTE *)&val, sizeof(val) );
401 if (save_all || config->win_width != default_config.win_width ||
402 config->win_height != default_config.win_height)
404 val = MAKELONG( config->win_width, config->win_height );
405 RegSetValueExW( key, L"WindowSize", 0, REG_DWORD, (BYTE *)&val, sizeof(val) );
409 static void save_config( const WCHAR *key_name, const struct console_config *config )
411 HKEY key, app_key;
413 TRACE( "Saving %s console settings\n", key_name ? debugstr_w( key_name ) : "default" );
415 if (RegCreateKeyW( HKEY_CURRENT_USER, L"Console", &key ))
417 ERR("Can't open registry for saving\n");
418 return;
421 if (key_name)
423 if (RegCreateKeyW( key, key_name, &app_key ))
425 ERR("Can't open registry for saving\n");
427 else
429 save_registry_key( app_key, config, FALSE );
430 RegCloseKey( app_key );
433 else save_registry_key( key, config, TRUE );
434 RegCloseKey(key);
437 /* fill memory DC with current cells values */
438 static void fill_mem_dc( struct console *console, const RECT *update )
440 unsigned int i, j, k;
441 unsigned int attr;
442 char_info_t *cell;
443 HFONT old_font;
444 HBRUSH brush;
445 WCHAR *line;
446 INT *dx;
447 RECT r;
449 if (!console->window->font || !console->window->bitmap)
450 return;
452 if (!(line = malloc( (update->right - update->left + 1) * sizeof(WCHAR))) ) return;
453 dx = malloc( (update->right - update->left + 1) * sizeof(*dx) );
455 old_font = SelectObject( console->window->mem_dc, console->window->font );
456 for (j = update->top; j <= update->bottom; j++)
458 cell = &console->active->data[j * console->active->width];
459 for (i = update->left; i <= update->right; i++)
461 attr = cell[i].attr;
462 SetBkColor( console->window->mem_dc, console->active->color_map[(attr >> 4) & 0x0F] );
463 SetTextColor( console->window->mem_dc, console->active->color_map[attr & 0x0F] );
464 for (k = i; k <= update->right && cell[k].attr == attr; k++)
466 line[k - i] = cell[k].ch;
467 dx[k - i] = console->active->font.width;
469 ExtTextOutW( console->window->mem_dc, i * console->active->font.width,
470 j * console->active->font.height, 0, NULL, line, k - i, dx );
471 if (console->window->ext_leading &&
472 (brush = CreateSolidBrush( console->active->color_map[(attr >> 4) & 0x0F] )))
474 r.left = i * console->active->font.width;
475 r.top = (j + 1) * console->active->font.height - console->window->ext_leading;
476 r.right = k * console->active->font.width;
477 r.bottom = (j + 1) * console->active->font.height;
478 FillRect( console->window->mem_dc, &r, brush );
479 DeleteObject( brush );
481 i = k - 1;
484 SelectObject( console->window->mem_dc, old_font );
485 free( dx );
486 free( line );
489 /* set a new position for the cursor */
490 static void update_window_cursor( struct console *console )
492 if (!console->active->cursor_visible || console->win != GetFocus()) return;
494 SetCaretPos( (get_bounded_cursor_x( console->active ) - console->active->win.left) * console->active->font.width,
495 (console->active->cursor_y - console->active->win.top) * console->active->font.height );
496 ShowCaret( console->win );
499 /* sets a new shape for the cursor */
500 static void shape_cursor( struct console *console )
502 int size = console->active->cursor_size;
504 if (console->active->cursor_visible && console->win == GetFocus()) DestroyCaret();
505 if (console->window->cursor_bitmap) DeleteObject( console->window->cursor_bitmap );
506 console->window->cursor_bitmap = NULL;
507 console->window->cursor_visible = FALSE;
509 if (size != 100)
511 int w16b; /* number of bytes per row, aligned on word size */
512 int i, j, nbl;
513 BYTE *ptr;
515 w16b = ((console->active->font.width + 15) & ~15) / 8;
516 ptr = calloc( w16b, console->active->font.height );
517 if (!ptr) return;
518 nbl = max( (console->active->font.height * size) / 100, 1 );
519 for (j = console->active->font.height - nbl; j < console->active->font.height; j++)
521 for (i = 0; i < console->active->font.width; i++)
523 ptr[w16b * j + (i / 8)] |= 0x80 >> (i & 7);
526 console->window->cursor_bitmap = CreateBitmap( console->active->font.width,
527 console->active->font.height, 1, 1, ptr );
528 free(ptr);
532 static void update_window( struct console *console )
534 unsigned int win_width, win_height;
535 BOOL update_all = FALSE;
536 int dx, dy;
537 RECT r;
539 console->window->update_state = UPDATE_BUSY;
541 if (console->window->sb_width != console->active->width ||
542 console->window->sb_height != console->active->height ||
543 (!console->window->bitmap && IsWindowVisible( console->win )))
545 console->window->sb_width = console->active->width;
546 console->window->sb_height = console->active->height;
548 if (console->active->width && console->active->height && console->window->font)
550 HBITMAP bitmap;
551 HDC dc;
552 RECT r;
554 if (!(dc = GetDC( console->win ))) return;
556 bitmap = CreateCompatibleBitmap( dc,
557 console->active->width * console->active->font.width,
558 console->active->height * console->active->font.height );
559 ReleaseDC( console->win, dc );
560 SelectObject( console->window->mem_dc, bitmap );
562 if (console->window->bitmap) DeleteObject( console->window->bitmap );
563 console->window->bitmap = bitmap;
564 SetRect( &r, 0, 0, console->active->width - 1, console->active->height - 1 );
565 fill_mem_dc( console, &r );
568 empty_update_rect( console->active, &console->window->update );
569 update_all = TRUE;
572 /* compute window size from desired client size */
573 win_width = console->active->win.right - console->active->win.left + 1;
574 win_height = console->active->win.bottom - console->active->win.top + 1;
576 if (update_all || win_width != console->window->win_width ||
577 win_height != console->window->win_height)
579 console->window->win_width = win_width;
580 console->window->win_height = win_height;
582 r.left = r.top = 0;
583 r.right = win_width * console->active->font.width;
584 r.bottom = win_height * console->active->font.height;
585 AdjustWindowRect( &r, GetWindowLongW( console->win, GWL_STYLE ), FALSE );
587 dx = dy = 0;
588 if (console->active->width > win_width)
590 dy = GetSystemMetrics( SM_CYHSCROLL );
591 SetScrollRange( console->win, SB_HORZ, 0, console->active->width - win_width, FALSE );
592 SetScrollPos( console->win, SB_VERT, console->active->win.top, FALSE );
593 ShowScrollBar( console->win, SB_HORZ, TRUE );
595 else
597 ShowScrollBar( console->win, SB_HORZ, FALSE );
600 if (console->active->height > win_height)
602 dx = GetSystemMetrics( SM_CXVSCROLL );
603 SetScrollRange( console->win, SB_VERT, 0, console->active->height - win_height, FALSE );
604 SetScrollPos( console->win, SB_VERT, console->active->win.top, FALSE );
605 ShowScrollBar( console->win, SB_VERT, TRUE );
607 else
608 ShowScrollBar( console->win, SB_VERT, FALSE );
610 dx += r.right - r.left;
611 dy += r.bottom - r.top;
612 SetWindowPos( console->win, 0, 0, 0, dx, dy, SWP_NOMOVE | SWP_NOZORDER | SWP_NOACTIVATE );
614 SystemParametersInfoW( SPI_GETWORKAREA, 0, &r, 0 );
615 console->active->max_width = (r.right - r.left) / console->active->font.width;
616 console->active->max_height = (r.bottom - r.top - GetSystemMetrics( SM_CYCAPTION )) /
617 console->active->font.height;
619 InvalidateRect( console->win, NULL, FALSE );
620 UpdateWindow( console->win );
621 update_all = TRUE;
623 else if (console->active->win.left != console->window->win_pos.X ||
624 console->active->win.top != console->window->win_pos.Y)
626 ScrollWindow( console->win,
627 (console->window->win_pos.X - console->active->win.left) * console->active->font.width,
628 (console->window->win_pos.Y - console->active->win.top) * console->active->font.height,
629 NULL, NULL );
630 SetScrollPos( console->win, SB_HORZ, console->active->win.left, TRUE );
631 SetScrollPos( console->win, SB_VERT, console->active->win.top, TRUE );
632 InvalidateRect( console->win, NULL, FALSE );
635 console->window->win_pos.X = console->active->win.left;
636 console->window->win_pos.Y = console->active->win.top;
638 if (console->window->update.top <= console->window->update.bottom &&
639 console->window->update.left <= console->window->update.right)
641 RECT *update = &console->window->update;
642 r.left = (update->left - console->active->win.left) * console->active->font.width;
643 r.right = (update->right - console->active->win.left + 1) * console->active->font.width;
644 r.top = (update->top - console->active->win.top) * console->active->font.height;
645 r.bottom = (update->bottom - console->active->win.top + 1) * console->active->font.height;
646 fill_mem_dc( console, update );
647 empty_update_rect( console->active, &console->window->update );
648 InvalidateRect( console->win, &r, FALSE );
649 UpdateWindow( console->win );
652 if (update_all || console->active->cursor_size != console->window->cursor_size)
654 console->window->cursor_size = console->active->cursor_size;
655 shape_cursor( console );
658 if (console->active->cursor_visible != console->window->cursor_visible)
660 console->window->cursor_visible = console->active->cursor_visible;
661 if (console->win == GetFocus())
663 if (console->window->cursor_visible)
665 CreateCaret( console->win, console->window->cursor_bitmap,
666 console->active->font.width, console->active->font.height );
667 update_window_cursor( console );
669 else
670 DestroyCaret();
674 if (update_all || get_bounded_cursor_x( console->active ) != console->window->cursor_pos.X ||
675 console->active->cursor_y != console->window->cursor_pos.Y)
677 console->window->cursor_pos.X = get_bounded_cursor_x( console->active );
678 console->window->cursor_pos.Y = console->active->cursor_y;
679 update_window_cursor( console );
682 console->window->update_state = UPDATE_NONE;
685 /* get the relevant information from the font described in lf and store them in config */
686 static HFONT select_font_config( struct console_config *config, unsigned int cp, HWND hwnd,
687 const LOGFONTW *lf )
689 HFONT font, old_font;
690 TEXTMETRICW tm;
691 CPINFO cpinfo;
692 HDC dc;
694 if (!(dc = GetDC( hwnd ))) return NULL;
695 if (!(font = CreateFontIndirectW( lf )))
697 ReleaseDC( hwnd, dc );
698 return NULL;
701 old_font = SelectObject( dc, font );
702 GetTextMetricsW( dc, &tm );
703 SelectObject( dc, old_font );
704 ReleaseDC( hwnd, dc );
706 config->cell_width = tm.tmAveCharWidth;
707 config->cell_height = tm.tmHeight + tm.tmExternalLeading;
708 config->font_weight = tm.tmWeight;
709 lstrcpyW( config->face_name, lf->lfFaceName );
711 /* FIXME: use maximum width for DBCS codepages since some chars take two cells */
712 if (GetCPInfo( cp, &cpinfo ) && cpinfo.MaxCharSize == 2)
713 config->cell_width = tm.tmMaxCharWidth;
715 return font;
718 static void fill_logfont( LOGFONTW *lf, const WCHAR *face_name, size_t face_name_size,
719 unsigned int height, unsigned int weight )
721 lf->lfHeight = height;
722 lf->lfWidth = 0;
723 lf->lfEscapement = 0;
724 lf->lfOrientation = 0;
725 lf->lfWeight = weight;
726 lf->lfItalic = FALSE;
727 lf->lfUnderline = FALSE;
728 lf->lfStrikeOut = FALSE;
729 lf->lfCharSet = DEFAULT_CHARSET;
730 lf->lfOutPrecision = OUT_DEFAULT_PRECIS;
731 lf->lfClipPrecision = CLIP_DEFAULT_PRECIS;
732 lf->lfQuality = DEFAULT_QUALITY;
733 lf->lfPitchAndFamily = FIXED_PITCH | FF_DONTCARE;
734 face_name_size = min( face_name_size, sizeof(lf->lfFaceName) - sizeof(WCHAR) );
735 memcpy( lf->lfFaceName, face_name, face_name_size );
736 lf->lfFaceName[face_name_size / sizeof(WCHAR)] = 0;
739 static BOOL set_console_font( struct console *console, const LOGFONTW *logfont )
741 struct font_info *font_info = &console->active->font;
742 HFONT font, old_font;
743 TEXTMETRICW tm;
744 WCHAR face_name[LF_FACESIZE];
745 CPINFO cpinfo;
746 HDC dc;
748 TRACE( "%s\n", debugstr_logfont( logfont, 0 ));
750 if (console->window->font && logfont->lfHeight == console->active->font.height &&
751 logfont->lfWeight == console->active->font.weight &&
752 !logfont->lfItalic && !logfont->lfUnderline && !logfont->lfStrikeOut &&
753 console->active->font.face_len == wcslen( logfont->lfFaceName ) &&
754 !memcmp( logfont->lfFaceName, console->active->font.face_name,
755 console->active->font.face_len * sizeof(WCHAR) ))
757 TRACE( "equal to current\n" );
758 return TRUE;
761 if (!(dc = GetDC( console->win ))) return FALSE;
762 if (!(font = CreateFontIndirectW( logfont )))
764 ReleaseDC( console->win, dc );
765 return FALSE;
768 old_font = SelectObject( dc, font );
769 GetTextMetricsW( dc, &tm );
770 font_info->face_len = GetTextFaceW( dc, ARRAY_SIZE(face_name), face_name ) - 1;
771 SelectObject( dc, old_font );
772 ReleaseDC( console->win, dc );
774 font_info->width = tm.tmAveCharWidth;
775 font_info->height = tm.tmHeight + tm.tmExternalLeading;
776 font_info->pitch_family = tm.tmPitchAndFamily;
777 font_info->weight = tm.tmWeight;
779 free( font_info->face_name );
780 font_info->face_name = malloc( font_info->face_len * sizeof(WCHAR) );
781 memcpy( font_info->face_name, face_name, font_info->face_len * sizeof(WCHAR) );
783 /* FIXME: use maximum width for DBCS codepages since some chars take two cells */
784 if (GetCPInfo( console->output_cp, &cpinfo ) && cpinfo.MaxCharSize == 2)
785 font_info->width = tm.tmMaxCharWidth;
787 if (console->window->font) DeleteObject( console->window->font );
788 console->window->font = font;
789 console->window->ext_leading = tm.tmExternalLeading;
791 if (console->window->bitmap)
793 DeleteObject(console->window->bitmap);
794 console->window->bitmap = NULL;
796 return TRUE;
799 struct font_chooser
801 struct console *console;
802 int pass;
803 unsigned int font_height;
804 unsigned int font_width;
805 BOOL done;
808 /* check if the font described in tm is usable as a font for the renderer */
809 static BOOL validate_font_metric( struct console *console, const TEXTMETRICW *tm,
810 DWORD type, int pass )
812 switch (pass) /* we get increasingly lenient in later passes */
814 case 0:
815 if (type & RASTER_FONTTYPE) return FALSE;
816 /* fall through */
817 case 1:
818 if (type & RASTER_FONTTYPE)
820 if (tm->tmMaxCharWidth * (console->active->win.right - console->active->win.left + 1)
821 >= GetSystemMetrics(SM_CXSCREEN))
822 return FALSE;
823 if (tm->tmHeight * (console->active->win.bottom - console->active->win.top + 1)
824 >= GetSystemMetrics(SM_CYSCREEN))
825 return FALSE;
827 /* fall through */
828 case 2:
829 if (tm->tmCharSet != DEFAULT_CHARSET && tm->tmCharSet != console->window->ui_charset)
830 return FALSE;
831 /* fall through */
832 case 3:
833 if (tm->tmItalic || tm->tmUnderlined || tm->tmStruckOut) return FALSE;
834 break;
836 return TRUE;
839 /* check if the font family described in lf is usable as a font for the renderer */
840 static BOOL validate_font( struct console *console, const LOGFONTW *lf, int pass )
842 switch (pass) /* we get increasingly lenient in later passes */
844 case 0:
845 case 1:
846 case 2:
847 if (lf->lfCharSet != DEFAULT_CHARSET && lf->lfCharSet != console->window->ui_charset)
848 return FALSE;
849 /* fall through */
850 case 3:
851 if ((lf->lfPitchAndFamily & 3) != FIXED_PITCH) return FALSE;
852 /* fall through */
853 case 4:
854 if (lf->lfFaceName[0] == '@') return FALSE;
855 break;
857 return TRUE;
860 static int CALLBACK enum_first_font_proc( const LOGFONTW *lf, const TEXTMETRICW *tm,
861 DWORD font_type, LPARAM lparam )
863 struct font_chooser *fc = (struct font_chooser *)lparam;
864 LOGFONTW mlf;
866 if (font_type != TRUETYPE_FONTTYPE) return 1;
868 TRACE( "%s\n", debugstr_logfont( lf, font_type ));
870 if (!validate_font( fc->console, lf, fc->pass ))
871 return 1;
873 TRACE( "%s\n", debugstr_textmetric( tm, font_type ));
875 if (!validate_font_metric( fc->console, tm, font_type, fc->pass ))
876 return 1;
878 /* set default font size */
879 mlf = *lf;
880 mlf.lfHeight = fc->font_height;
881 mlf.lfWidth = fc->font_width;
883 if (!set_console_font( fc->console, &mlf ))
884 return 1;
886 fc->done = TRUE;
888 return 0;
891 static void set_first_font( struct console *console, struct console_config *config )
893 LOGFONTW lf;
894 struct font_chooser fc;
896 TRACE("Looking for a suitable console font\n");
898 memset( &lf, 0, sizeof(lf) );
899 lf.lfCharSet = DEFAULT_CHARSET;
900 lf.lfPitchAndFamily = FIXED_PITCH | FF_MODERN;
902 fc.console = console;
903 fc.font_height = config->cell_height;
904 fc.font_width = config->cell_width;
905 fc.done = FALSE;
907 for (fc.pass = 0; fc.pass <= 5; fc.pass++)
909 EnumFontFamiliesExW( console->window->mem_dc, &lf, enum_first_font_proc, (LPARAM)&fc, 0);
910 if (fc.done) break;
913 if (fc.pass > 5)
914 ERR("Unable to find a valid console font\n");
916 /* Update active configuration */
917 config->cell_width = console->active->font.width;
918 config->cell_height = console->active->font.height;
919 config->font_pitch_family = console->active->font.pitch_family;
920 memcpy( config->face_name, console->active->font.face_name,
921 console->active->font.face_len * sizeof(WCHAR) );
922 config->face_name[console->active->font.face_len] = 0;
924 /* Save default console configuration to the registry */
925 save_config( NULL, config );
928 /* Sets the font specified in the LOGFONT as the new console font */
929 void update_console_font( struct console *console, const WCHAR *face_name, size_t face_name_size,
930 unsigned int height, unsigned int weight )
932 LOGFONTW lf;
934 if (!console->window) return;
936 fill_logfont( &lf, face_name, face_name_size, height, weight );
938 set_console_font( console, &lf );
941 /* get a cell from a relative coordinate in window (takes into account the scrolling) */
942 static COORD get_cell( struct console *console, LPARAM lparam )
944 COORD c;
945 c.X = console->active->win.left + (short)LOWORD(lparam) / console->active->font.width;
946 c.Y = console->active->win.top + (short)HIWORD(lparam) / console->active->font.height;
947 return c;
950 /* get the console bit mask equivalent to the VK_ status in key state */
951 static DWORD get_ctrl_state( BYTE *key_state)
953 unsigned int ret = 0;
955 GetKeyboardState(key_state);
956 if (key_state[VK_SHIFT] & 0x80) ret |= SHIFT_PRESSED;
957 if (key_state[VK_LCONTROL] & 0x80) ret |= LEFT_CTRL_PRESSED;
958 if (key_state[VK_RCONTROL] & 0x80) ret |= RIGHT_CTRL_PRESSED;
959 if (key_state[VK_LMENU] & 0x80) ret |= LEFT_ALT_PRESSED;
960 if (key_state[VK_RMENU] & 0x80) ret |= RIGHT_ALT_PRESSED;
961 if (key_state[VK_CAPITAL] & 0x01) ret |= CAPSLOCK_ON;
962 if (key_state[VK_NUMLOCK] & 0x01) ret |= NUMLOCK_ON;
963 if (key_state[VK_SCROLL] & 0x01) ret |= SCROLLLOCK_ON;
965 return ret;
968 /* get the selection rectangle */
969 static void get_selection_rect( struct console *console, RECT *r )
971 r->left = (min(console->window->selection_start.X, console->window->selection_end.X) -
972 console->active->win.left) * console->active->font.width;
973 r->top = (min(console->window->selection_start.Y, console->window->selection_end.Y) -
974 console->active->win.top) * console->active->font.height;
975 r->right = (max(console->window->selection_start.X, console->window->selection_end.X) + 1 -
976 console->active->win.left) * console->active->font.width;
977 r->bottom = (max(console->window->selection_start.Y, console->window->selection_end.Y) + 1 -
978 console->active->win.top) * console->active->font.height;
981 static void update_selection( struct console *console, HDC ref_dc )
983 HDC dc;
984 RECT r;
986 get_selection_rect( console, &r );
987 dc = ref_dc ? ref_dc : GetDC( console->win );
988 if (!dc) return;
990 if (console->win == GetFocus() && console->active->cursor_visible)
991 HideCaret( console->win );
992 InvertRect( dc, &r );
993 if (dc != ref_dc)
994 ReleaseDC( console->win, dc );
995 if (console->win == GetFocus() && console->active->cursor_visible)
996 ShowCaret( console->win );
999 static void move_selection( struct console *console, COORD c1, COORD c2 )
1001 RECT r;
1002 HDC dc;
1004 if (c1.X < 0 || c1.X >= console->active->width ||
1005 c2.X < 0 || c2.X >= console->active->width ||
1006 c1.Y < 0 || c1.Y >= console->active->height ||
1007 c2.Y < 0 || c2.Y >= console->active->height)
1008 return;
1010 get_selection_rect( console, &r );
1011 dc = GetDC( console->win );
1012 if (dc)
1014 if (console->win == GetFocus() && console->active->cursor_visible)
1015 HideCaret( console->win );
1016 InvertRect( dc, &r );
1018 console->window->selection_start = c1;
1019 console->window->selection_end = c2;
1020 if (dc)
1022 get_selection_rect( console, &r );
1023 InvertRect( dc, &r );
1024 ReleaseDC( console->win, dc );
1025 if (console->win == GetFocus() && console->active->cursor_visible)
1026 ShowCaret( console->win );
1030 /* copies the current selection into the clipboard */
1031 static void copy_selection( struct console *console )
1033 unsigned int w, h;
1034 WCHAR *p, *buf;
1035 HANDLE mem;
1037 w = abs( console->window->selection_start.X - console->window->selection_end.X ) + 1;
1038 h = abs( console->window->selection_start.Y - console->window->selection_end.Y ) + 1;
1040 if (!OpenClipboard( console->win )) return;
1041 EmptyClipboard();
1043 mem = GlobalAlloc( GMEM_MOVEABLE, (w + 1) * h * sizeof(WCHAR) );
1044 if (mem && (p = buf = GlobalLock( mem )))
1046 int x, y;
1047 COORD c;
1049 c.X = min( console->window->selection_start.X, console->window->selection_end.X );
1050 c.Y = min( console->window->selection_start.Y, console->window->selection_end.Y );
1052 for (y = c.Y; y < c.Y + h; y++)
1054 WCHAR *end;
1056 for (x = c.X; x < c.X + w; x++)
1057 p[x - c.X] = console->active->data[y * console->active->width + x].ch;
1059 /* strip spaces from the end of the line */
1060 end = p + w;
1061 while (end > p && *(end - 1) == ' ')
1062 end--;
1063 *end = (y < c.Y + h - 1) ? '\n' : '\0';
1064 p = end + 1;
1067 TRACE( "%s\n", debugstr_w( buf ));
1068 if (p - buf != (w + 1) * h)
1070 HANDLE new_mem;
1071 new_mem = GlobalReAlloc( mem, (p - buf) * sizeof(WCHAR), GMEM_MOVEABLE );
1072 if (new_mem) mem = new_mem;
1074 GlobalUnlock( mem );
1075 SetClipboardData( CF_UNICODETEXT, mem );
1077 CloseClipboard();
1080 static void paste_clipboard( struct console *console )
1082 WCHAR *ptr;
1083 HANDLE h;
1085 if (!OpenClipboard( console->win )) return;
1086 h = GetClipboardData( CF_UNICODETEXT );
1087 if (h && (ptr = GlobalLock( h )))
1089 unsigned int i, len = GlobalSize(h) / sizeof(WCHAR);
1090 INPUT_RECORD ir[2];
1091 SHORT sh;
1093 ir[0].EventType = KEY_EVENT;
1094 ir[0].Event.KeyEvent.wRepeatCount = 0;
1095 ir[0].Event.KeyEvent.dwControlKeyState = 0;
1096 ir[0].Event.KeyEvent.bKeyDown = TRUE;
1098 /* generate the corresponding input records */
1099 for (i = 0; i < len; i++)
1101 /* FIXME: the modifying keys are not generated (shift, ctrl...) */
1102 sh = VkKeyScanW( ptr[i] );
1103 ir[0].Event.KeyEvent.wVirtualKeyCode = LOBYTE(sh);
1104 ir[0].Event.KeyEvent.wVirtualScanCode = MapVirtualKeyW( LOBYTE(sh), 0 );
1105 ir[0].Event.KeyEvent.uChar.UnicodeChar = ptr[i];
1107 ir[1] = ir[0];
1108 ir[1].Event.KeyEvent.bKeyDown = FALSE;
1110 write_console_input( console, ir, 2, i == len - 1 );
1112 GlobalUnlock( h );
1115 CloseClipboard();
1118 /* handle keys while selecting an area */
1119 static void handle_selection_key( struct console *console, BOOL down, WPARAM wparam, LPARAM lparam )
1121 BYTE key_state[256];
1122 COORD c1, c2;
1123 DWORD state;
1125 if (!down) return;
1126 state = get_ctrl_state( key_state ) & ~(CAPSLOCK_ON|NUMLOCK_ON|SCROLLLOCK_ON);
1128 switch (state)
1130 case 0:
1131 switch (wparam)
1133 case VK_RETURN:
1134 console->window->in_selection = FALSE;
1135 update_selection( console, 0 );
1136 copy_selection( console );
1137 return;
1138 case VK_RIGHT:
1139 c1 = console->window->selection_start;
1140 c2 = console->window->selection_end;
1141 c1.X++; c2.X++;
1142 move_selection( console, c1, c2 );
1143 return;
1144 case VK_LEFT:
1145 c1 = console->window->selection_start;
1146 c2 = console->window->selection_end;
1147 c1.X--; c2.X--;
1148 move_selection( console, c1, c2 );
1149 return;
1150 case VK_UP:
1151 c1 = console->window->selection_start;
1152 c2 = console->window->selection_end;
1153 c1.Y--; c2.Y--;
1154 move_selection( console, c1, c2 );
1155 return;
1156 case VK_DOWN:
1157 c1 = console->window->selection_start;
1158 c2 = console->window->selection_end;
1159 c1.Y++; c2.Y++;
1160 move_selection( console, c1, c2 );
1161 return;
1163 break;
1164 case SHIFT_PRESSED:
1165 switch (wparam)
1167 case VK_RIGHT:
1168 c1 = console->window->selection_start;
1169 c2 = console->window->selection_end;
1170 c2.X++;
1171 move_selection( console, c1, c2 );
1172 return;
1173 case VK_LEFT:
1174 c1 = console->window->selection_start;
1175 c2 = console->window->selection_end;
1176 c2.X--;
1177 move_selection( console, c1, c2 );
1178 return;
1179 case VK_UP:
1180 c1 = console->window->selection_start;
1181 c2 = console->window->selection_end;
1182 c2.Y--;
1183 move_selection( console, c1, c2 );
1184 return;
1185 case VK_DOWN:
1186 c1 = console->window->selection_start;
1187 c2 = console->window->selection_end;
1188 c2.Y++;
1189 move_selection( console, c1, c2 );
1190 return;
1192 break;
1195 if (wparam < VK_SPACE) /* Shift, Alt, Ctrl, Num Lock etc. */
1196 return;
1198 update_selection( console, 0 );
1199 console->window->in_selection = FALSE;
1202 /* generate input_record from windows WM_KEYUP/WM_KEYDOWN messages */
1203 static void record_key_input( struct console *console, BOOL down, WPARAM wparam, LPARAM lparam )
1205 static WCHAR last; /* keep last char seen as feed for key up message */
1206 BYTE key_state[256];
1207 INPUT_RECORD ir;
1208 WCHAR buf[2];
1210 ir.EventType = KEY_EVENT;
1211 ir.Event.KeyEvent.bKeyDown = down;
1212 ir.Event.KeyEvent.wRepeatCount = LOWORD(lparam);
1213 ir.Event.KeyEvent.wVirtualKeyCode = wparam;
1214 ir.Event.KeyEvent.wVirtualScanCode = HIWORD(lparam) & 0xFF;
1215 ir.Event.KeyEvent.uChar.UnicodeChar = 0;
1216 ir.Event.KeyEvent.dwControlKeyState = get_ctrl_state( key_state );
1217 if (lparam & (1u << 24)) ir.Event.KeyEvent.dwControlKeyState |= ENHANCED_KEY;
1219 if (down)
1221 switch (ToUnicode(wparam, HIWORD(lparam), key_state, buf, 2, 0))
1223 case 2:
1224 /* FIXME: should generate two events */
1225 /* fall through */
1226 case 1:
1227 last = buf[0];
1228 break;
1229 default:
1230 last = 0;
1231 break;
1234 ir.Event.KeyEvent.uChar.UnicodeChar = last;
1235 if (!down) last = 0; /* FIXME: buggy HACK */
1237 write_console_input( console, &ir, 1, TRUE );
1240 static void record_mouse_input( struct console *console, COORD c, WPARAM wparam, DWORD event )
1242 BYTE key_state[256];
1243 INPUT_RECORD ir;
1245 /* MOUSE_EVENTs shouldn't be sent unless ENABLE_MOUSE_INPUT is active */
1246 if (!(console->mode & ENABLE_MOUSE_INPUT)) return;
1248 ir.EventType = MOUSE_EVENT;
1249 ir.Event.MouseEvent.dwMousePosition = c;
1250 ir.Event.MouseEvent.dwButtonState = 0;
1251 if (wparam & MK_LBUTTON) ir.Event.MouseEvent.dwButtonState |= FROM_LEFT_1ST_BUTTON_PRESSED;
1252 if (wparam & MK_MBUTTON) ir.Event.MouseEvent.dwButtonState |= FROM_LEFT_2ND_BUTTON_PRESSED;
1253 if (wparam & MK_RBUTTON) ir.Event.MouseEvent.dwButtonState |= RIGHTMOST_BUTTON_PRESSED;
1254 if (wparam & MK_CONTROL) ir.Event.MouseEvent.dwButtonState |= LEFT_CTRL_PRESSED;
1255 if (wparam & MK_SHIFT) ir.Event.MouseEvent.dwButtonState |= SHIFT_PRESSED;
1256 if (event == MOUSE_WHEELED) ir.Event.MouseEvent.dwButtonState |= wparam & 0xFFFF0000;
1257 ir.Event.MouseEvent.dwControlKeyState = get_ctrl_state( key_state );
1258 ir.Event.MouseEvent.dwEventFlags = event;
1260 write_console_input( console, &ir, 1, TRUE );
1263 struct dialog_info
1265 struct console *console;
1266 struct console_config config;
1267 HWND dialog; /* handle to active propsheet */
1270 /* dialog proc for the option property sheet */
1271 static INT_PTR WINAPI option_dialog_proc( HWND dialog, UINT msg, WPARAM wparam, LPARAM lparam )
1273 struct dialog_info *di;
1274 unsigned int idc;
1276 switch (msg)
1278 case WM_INITDIALOG:
1279 di = (struct dialog_info *)((PROPSHEETPAGEA *)lparam)->lParam;
1280 di->dialog = dialog;
1281 SetWindowLongPtrW( dialog, DWLP_USER, (LONG_PTR)di );
1283 SendMessageW( GetDlgItem( dialog, IDC_OPT_HIST_SIZE_UD ), UDM_SETRANGE, 0, MAKELPARAM(500, 0) );
1285 if (di->config.cursor_size <= 25) idc = IDC_OPT_CURSOR_SMALL;
1286 else if (di->config.cursor_size <= 50) idc = IDC_OPT_CURSOR_MEDIUM;
1287 else idc = IDC_OPT_CURSOR_LARGE;
1289 SendDlgItemMessageW( dialog, idc, BM_SETCHECK, BST_CHECKED, 0 );
1290 SetDlgItemInt( dialog, IDC_OPT_HIST_SIZE, di->config.history_size, FALSE );
1291 SendDlgItemMessageW( dialog, IDC_OPT_HIST_NODOUBLE, BM_SETCHECK,
1292 (di->config.history_mode) ? BST_CHECKED : BST_UNCHECKED, 0 );
1293 SendDlgItemMessageW( dialog, IDC_OPT_INSERT_MODE, BM_SETCHECK,
1294 (di->config.insert_mode) ? BST_CHECKED : BST_UNCHECKED, 0 );
1295 SendDlgItemMessageW( dialog, IDC_OPT_CONF_CTRL, BM_SETCHECK,
1296 (di->config.menu_mask & MK_CONTROL) ? BST_CHECKED : BST_UNCHECKED, 0 );
1297 SendDlgItemMessageW( dialog, IDC_OPT_CONF_SHIFT, BM_SETCHECK,
1298 (di->config.menu_mask & MK_SHIFT) ? BST_CHECKED : BST_UNCHECKED, 0 );
1299 SendDlgItemMessageW( dialog, IDC_OPT_QUICK_EDIT, BM_SETCHECK,
1300 (di->config.quick_edit) ? BST_CHECKED : BST_UNCHECKED, 0 );
1301 return FALSE; /* because we set the focus */
1303 case WM_COMMAND:
1304 break;
1306 case WM_NOTIFY:
1308 NMHDR *nmhdr = (NMHDR*)lparam;
1309 DWORD val;
1310 BOOL done;
1312 di = (struct dialog_info *)GetWindowLongPtrW( dialog, DWLP_USER );
1314 switch (nmhdr->code)
1316 case PSN_SETACTIVE:
1317 /* needed in propsheet to keep properly the selected radio button
1318 * otherwise, the focus would be set to the first tab stop in the
1319 * propsheet, which would always activate the first radio button
1321 if (IsDlgButtonChecked( dialog, IDC_OPT_CURSOR_SMALL ) == BST_CHECKED)
1322 idc = IDC_OPT_CURSOR_SMALL;
1323 else if (IsDlgButtonChecked( dialog, IDC_OPT_CURSOR_MEDIUM ) == BST_CHECKED)
1324 idc = IDC_OPT_CURSOR_MEDIUM;
1325 else
1326 idc = IDC_OPT_CURSOR_LARGE;
1327 PostMessageW( dialog, WM_NEXTDLGCTL, (WPARAM)GetDlgItem( dialog, idc ), TRUE );
1328 di->dialog = dialog;
1329 break;
1330 case PSN_APPLY:
1331 if (IsDlgButtonChecked( dialog, IDC_OPT_CURSOR_SMALL ) == BST_CHECKED) val = 25;
1332 else if (IsDlgButtonChecked( dialog, IDC_OPT_CURSOR_MEDIUM ) == BST_CHECKED) val = 50;
1333 else val = 100;
1334 di->config.cursor_size = val;
1336 val = GetDlgItemInt( dialog, IDC_OPT_HIST_SIZE, &done, FALSE );
1337 if (done) di->config.history_size = val;
1339 val = (IsDlgButtonChecked( dialog, IDC_OPT_HIST_NODOUBLE ) & BST_CHECKED) != 0;
1340 di->config.history_mode = val;
1342 val = (IsDlgButtonChecked( dialog, IDC_OPT_INSERT_MODE ) & BST_CHECKED) != 0;
1343 di->config.insert_mode = val;
1345 val = 0;
1346 if (IsDlgButtonChecked( dialog, IDC_OPT_CONF_CTRL ) & BST_CHECKED) val |= MK_CONTROL;
1347 if (IsDlgButtonChecked( dialog, IDC_OPT_CONF_SHIFT ) & BST_CHECKED) val |= MK_SHIFT;
1348 di->config.menu_mask = val;
1350 val = (IsDlgButtonChecked( dialog, IDC_OPT_QUICK_EDIT ) & BST_CHECKED) != 0;
1351 di->config.quick_edit = val;
1353 SetWindowLongPtrW( dialog, DWLP_MSGRESULT, PSNRET_NOERROR );
1354 return TRUE;
1355 default:
1356 return FALSE;
1358 break;
1360 default:
1361 return FALSE;
1363 return TRUE;
1366 static COLORREF get_color( struct dialog_info *di, unsigned int idc )
1368 LONG_PTR index;
1370 index = GetWindowLongPtrW(GetDlgItem( di->dialog, idc ), 0);
1371 return di->config.color_map[index];
1374 /* window proc for font previewer in font property sheet */
1375 static LRESULT WINAPI font_preview_proc( HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam )
1377 switch (msg)
1379 case WM_CREATE:
1380 SetWindowLongPtrW( hwnd, 0, 0 );
1381 break;
1383 case WM_GETFONT:
1384 return GetWindowLongPtrW( hwnd, 0 );
1386 case WM_SETFONT:
1387 SetWindowLongPtrW( hwnd, 0, wparam );
1388 if (LOWORD(lparam))
1390 InvalidateRect( hwnd, NULL, TRUE );
1391 UpdateWindow( hwnd );
1393 break;
1395 case WM_DESTROY:
1397 HFONT font = (HFONT)GetWindowLongPtrW( hwnd, 0 );
1398 if (font) DeleteObject( font );
1399 break;
1402 case WM_PAINT:
1404 struct dialog_info *di;
1405 HFONT font, old_font;
1406 PAINTSTRUCT ps;
1408 di = (struct dialog_info *)GetWindowLongPtrW( GetParent( hwnd ), DWLP_USER );
1409 BeginPaint( hwnd, &ps );
1411 font = (HFONT)GetWindowLongPtrW( hwnd, 0 );
1412 if (font)
1414 static const WCHAR ascii[] = L"ASCII: abcXYZ";
1415 COLORREF bkcolor;
1416 WCHAR buf[256];
1417 int len;
1419 old_font = SelectObject( ps.hdc, font );
1420 bkcolor = get_color( di, IDC_FNT_COLOR_BK );
1421 FillRect( ps.hdc, &ps.rcPaint, CreateSolidBrush( bkcolor ));
1422 SetBkColor( ps.hdc, bkcolor );
1423 SetTextColor( ps.hdc, get_color( di, IDC_FNT_COLOR_FG ));
1424 len = LoadStringW( GetModuleHandleW(NULL), IDS_FNT_PREVIEW, buf, ARRAY_SIZE(buf) );
1425 if (len) TextOutW( ps.hdc, 0, 0, buf, len );
1426 TextOutW( ps.hdc, 0, di->config.cell_height, ascii, ARRAY_SIZE(ascii) - 1 );
1427 SelectObject( ps.hdc, old_font );
1429 EndPaint( hwnd, &ps );
1430 break;
1433 default:
1434 return DefWindowProcW( hwnd, msg, wparam, lparam );
1436 return 0;
1439 /* window proc for color previewer */
1440 static LRESULT WINAPI color_preview_proc( HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam )
1442 switch (msg)
1444 case WM_PAINT:
1446 struct dialog_info *di;
1447 PAINTSTRUCT ps;
1448 RECT client, r;
1449 int i, step;
1450 HBRUSH brush;
1452 BeginPaint( hwnd, &ps );
1453 GetClientRect( hwnd, &client );
1454 step = client.right / 8;
1456 di = (struct dialog_info *)GetWindowLongPtrW( GetParent(hwnd), DWLP_USER );
1458 for (i = 0; i < 16; i++)
1460 r.top = (i / 8) * (client.bottom / 2);
1461 r.bottom = r.top + client.bottom / 2;
1462 r.left = (i & 7) * step;
1463 r.right = r.left + step;
1464 brush = CreateSolidBrush( di->config.color_map[i] );
1465 FillRect( ps.hdc, &r, brush );
1466 DeleteObject( brush );
1467 if (GetWindowLongW( hwnd, 0 ) == i)
1469 HPEN old_pen;
1470 int i = 2;
1472 old_pen = SelectObject( ps.hdc, GetStockObject( WHITE_PEN ));
1473 r.right--; r.bottom--;
1474 for (;;)
1476 MoveToEx( ps.hdc, r.left, r.bottom, NULL );
1477 LineTo( ps.hdc, r.left, r.top );
1478 LineTo( ps.hdc, r.right, r.top );
1479 SelectObject( ps.hdc, GetStockObject( BLACK_PEN ));
1480 LineTo( ps.hdc, r.right, r.bottom );
1481 LineTo( ps.hdc, r.left, r.bottom );
1482 if (--i == 0) break;
1483 r.left++; r.top++; r.right--; r.bottom--;
1484 SelectObject( ps.hdc, GetStockObject( WHITE_PEN ));
1486 SelectObject( ps.hdc, old_pen );
1489 EndPaint( hwnd, &ps );
1490 break;
1493 case WM_LBUTTONDOWN:
1495 int i, step;
1496 RECT client;
1498 GetClientRect( hwnd, &client );
1499 step = client.right / 8;
1500 i = (HIWORD(lparam) >= client.bottom / 2) ? 8 : 0;
1501 i += LOWORD(lparam) / step;
1502 SetWindowLongW( hwnd, 0, i );
1503 InvalidateRect( GetDlgItem( GetParent( hwnd ), IDC_FNT_PREVIEW ), NULL, FALSE );
1504 InvalidateRect( hwnd, NULL, FALSE );
1505 break;
1508 default:
1509 return DefWindowProcW( hwnd, msg, wparam, lparam );
1511 return 0;
1514 static BOOL select_font( struct dialog_info *di )
1516 int font_idx, size_idx;
1517 WCHAR face_name[LF_FACESIZE], height_buf[4];
1518 size_t len;
1519 unsigned int font_height;
1520 LOGFONTW lf;
1521 HFONT font, old_font;
1522 DWORD_PTR args[2];
1523 WCHAR buf[256];
1524 WCHAR fmt[128];
1526 font_idx = SendDlgItemMessageW( di->dialog, IDC_FNT_LIST_FONT, LB_GETCURSEL, 0, 0 );
1527 size_idx = SendDlgItemMessageW( di->dialog, IDC_FNT_LIST_SIZE, LB_GETCURSEL, 0, 0 );
1529 if (font_idx < 0 || size_idx < 0)
1530 return FALSE;
1532 len = SendDlgItemMessageW( di->dialog, IDC_FNT_LIST_FONT, LB_GETTEXT, font_idx, (LPARAM)&face_name );
1533 SendDlgItemMessageW( di->dialog, IDC_FNT_LIST_SIZE, LB_GETTEXT, size_idx, (LPARAM)&height_buf );
1534 font_height = _wtoi( height_buf );
1536 fill_logfont( &lf, face_name, len * sizeof(WCHAR), font_height, FW_NORMAL );
1537 font = select_font_config( &di->config, di->console->output_cp, di->console->win, &lf );
1538 if (!font) return FALSE;
1540 if (di->config.cell_height != font_height)
1541 TRACE( "mismatched heights (%u<>%u)\n", di->config.cell_height, font_height );
1543 old_font = (HFONT)SendDlgItemMessageW( di->dialog, IDC_FNT_PREVIEW, WM_GETFONT, 0, 0 );
1544 SendDlgItemMessageW( di->dialog, IDC_FNT_PREVIEW, WM_SETFONT, (WPARAM)font, TRUE );
1545 if (old_font) DeleteObject( old_font );
1547 LoadStringW( GetModuleHandleW(NULL), IDS_FNT_DISPLAY, fmt, ARRAY_SIZE(fmt) );
1548 args[0] = di->config.cell_width;
1549 args[1] = di->config.cell_height;
1550 FormatMessageW( FORMAT_MESSAGE_FROM_STRING|FORMAT_MESSAGE_ARGUMENT_ARRAY,
1551 fmt, 0, 0, buf, ARRAY_SIZE(buf), (va_list *)args );
1553 SendDlgItemMessageW( di->dialog, IDC_FNT_FONT_INFO, WM_SETTEXT, 0, (LPARAM)buf );
1554 return TRUE;
1557 static BOOL fill_list_size( struct dialog_info *di, BOOL init )
1559 if (init)
1561 static const int sizes[] = {8,9,10,11,12,14,16,18,20,22,24,26,28,36,48,72};
1562 unsigned int i, idx = 4;
1563 WCHAR buf[4];
1565 for (i = 0; i < ARRAY_SIZE(sizes); i++)
1567 wsprintfW( buf, L"%u", sizes[i] );
1568 SendDlgItemMessageW( di->dialog, IDC_FNT_LIST_SIZE, LB_INSERTSTRING, -1, (LPARAM)buf );
1570 if (di->config.cell_height == sizes[i]) idx = i;
1573 SendDlgItemMessageW( di->dialog, IDC_FNT_LIST_SIZE, LB_SETCURSEL, idx, 0 );
1576 select_font( di );
1578 return TRUE;
1581 static int CALLBACK enum_list_font_proc( const LOGFONTW *lf, const TEXTMETRICW *tm,
1582 DWORD font_type, LPARAM lparam )
1584 struct dialog_info *di = (struct dialog_info *)lparam;
1586 if (font_type != TRUETYPE_FONTTYPE) return 1;
1588 TRACE( "%s\n", debugstr_logfont( lf, font_type ));
1590 if (validate_font( di->console, lf, 0 ))
1591 SendDlgItemMessageW( di->dialog, IDC_FNT_LIST_FONT, LB_ADDSTRING, 0, (LPARAM)lf->lfFaceName );
1593 return 1;
1596 static BOOL fill_list_font( struct dialog_info *di )
1598 LOGFONTW lf;
1600 memset( &lf, 0, sizeof(lf) );
1601 lf.lfCharSet = DEFAULT_CHARSET;
1602 lf.lfFaceName[0] = 0;
1603 lf.lfPitchAndFamily = FIXED_PITCH | FF_MODERN;
1605 EnumFontFamiliesExW( di->console->window->mem_dc, &lf, enum_list_font_proc, (LPARAM)di, 0 );
1607 if (SendDlgItemMessageW( di->dialog, IDC_FNT_LIST_FONT, LB_SELECTSTRING,
1608 -1, (LPARAM)di->config.face_name ) == LB_ERR)
1609 SendDlgItemMessageW( di->dialog, IDC_FNT_LIST_FONT, LB_SETCURSEL, 0, 0 );
1611 fill_list_size( di, TRUE );
1613 return TRUE;
1616 /* dialog proc for the font property sheet */
1617 static INT_PTR WINAPI font_dialog_proc( HWND dialog, UINT msg, WPARAM wparam, LPARAM lparam )
1619 struct dialog_info *di;
1621 switch (msg)
1623 case WM_INITDIALOG:
1624 di = (struct dialog_info *)((PROPSHEETPAGEA*)lparam)->lParam;
1625 di->dialog = dialog;
1626 SetWindowLongPtrW( dialog, DWLP_USER, (DWORD_PTR)di );
1627 /* use default system font until user-selected font is applied */
1628 SendDlgItemMessageW( dialog, IDC_FNT_PREVIEW, WM_SETFONT, 0, 0 );
1629 fill_list_font( di );
1630 SetWindowLongW( GetDlgItem( dialog, IDC_FNT_COLOR_BK ), 0, (di->config.attr >> 4) & 0x0F );
1631 SetWindowLongW( GetDlgItem( dialog, IDC_FNT_COLOR_FG ), 0, di->config.attr & 0x0F );
1632 break;
1634 case WM_COMMAND:
1635 di = (struct dialog_info *)GetWindowLongPtrW( dialog, DWLP_USER );
1636 switch (LOWORD(wparam))
1638 case IDC_FNT_LIST_FONT:
1639 if (HIWORD(wparam) == LBN_SELCHANGE)
1640 fill_list_size( di, FALSE );
1641 break;
1642 case IDC_FNT_LIST_SIZE:
1643 if (HIWORD(wparam) == LBN_SELCHANGE)
1644 select_font( di );
1645 break;
1647 break;
1649 case WM_NOTIFY:
1651 NMHDR *nmhdr = (NMHDR*)lparam;
1652 DWORD val;
1654 di = (struct dialog_info*)GetWindowLongPtrW( dialog, DWLP_USER );
1655 switch (nmhdr->code)
1657 case PSN_SETACTIVE:
1658 di->dialog = dialog;
1659 break;
1660 case PSN_APPLY:
1661 val = (GetWindowLongW( GetDlgItem( dialog, IDC_FNT_COLOR_BK ), 0 ) << 4) |
1662 GetWindowLongW( GetDlgItem( dialog, IDC_FNT_COLOR_FG ), 0 );
1663 di->config.attr = val;
1664 SetWindowLongPtrW( dialog, DWLP_MSGRESULT, PSNRET_NOERROR );
1665 return TRUE;
1666 default:
1667 return FALSE;
1669 break;
1671 default:
1672 return FALSE;
1674 return TRUE;
1677 /* dialog proc for the config property sheet */
1678 static INT_PTR WINAPI config_dialog_proc( HWND dialog, UINT msg, WPARAM wparam, LPARAM lparam )
1680 struct dialog_info *di;
1681 int max_ud = 2000;
1683 switch (msg)
1685 case WM_INITDIALOG:
1686 di = (struct dialog_info *)((PROPSHEETPAGEA*)lparam)->lParam;
1687 di->dialog = dialog;
1689 SetWindowLongPtrW( dialog, DWLP_USER, (DWORD_PTR)di );
1690 SetDlgItemInt( dialog, IDC_CNF_SB_WIDTH, di->config.sb_width, FALSE );
1691 SetDlgItemInt( dialog, IDC_CNF_SB_HEIGHT, di->config.sb_height, FALSE );
1692 SetDlgItemInt( dialog, IDC_CNF_WIN_WIDTH, di->config.win_width, FALSE );
1693 SetDlgItemInt( dialog, IDC_CNF_WIN_HEIGHT, di->config.win_height, FALSE );
1695 SendMessageW( GetDlgItem(dialog, IDC_CNF_WIN_HEIGHT_UD), UDM_SETRANGE, 0, MAKELPARAM(max_ud, 0));
1696 SendMessageW( GetDlgItem(dialog, IDC_CNF_WIN_WIDTH_UD), UDM_SETRANGE, 0, MAKELPARAM(max_ud, 0));
1697 SendMessageW( GetDlgItem(dialog, IDC_CNF_SB_HEIGHT_UD), UDM_SETRANGE, 0, MAKELPARAM(max_ud, 0));
1698 SendMessageW( GetDlgItem(dialog, IDC_CNF_SB_WIDTH_UD), UDM_SETRANGE, 0, MAKELPARAM(max_ud, 0));
1700 SendDlgItemMessageW( dialog, IDC_CNF_CLOSE_EXIT, BM_SETCHECK, BST_CHECKED, 0 );
1702 SendDlgItemMessageW( dialog, IDC_CNF_EDITION_MODE, CB_ADDSTRING, 0, (LPARAM)L"Win32" );
1703 SendDlgItemMessageW( dialog, IDC_CNF_EDITION_MODE, CB_ADDSTRING, 0, (LPARAM)L"Emacs" );
1704 SendDlgItemMessageW( dialog, IDC_CNF_EDITION_MODE, CB_SETCURSEL, di->config.edition_mode, 0 );
1705 break;
1707 case WM_NOTIFY:
1709 NMHDR *nmhdr = (NMHDR*)lparam;
1710 int win_w, win_h, sb_w, sb_h;
1711 BOOL st1, st2;
1713 di = (struct dialog_info *)GetWindowLongPtrW( dialog, DWLP_USER );
1714 switch (nmhdr->code)
1716 case PSN_SETACTIVE:
1717 di->dialog = dialog;
1718 break;
1719 case PSN_APPLY:
1720 sb_w = GetDlgItemInt( dialog, IDC_CNF_SB_WIDTH, &st1, FALSE );
1721 sb_h = GetDlgItemInt( dialog, IDC_CNF_SB_HEIGHT, &st2, FALSE );
1722 if (!st1 || ! st2)
1724 SetWindowLongPtrW( dialog, DWLP_MSGRESULT, PSNRET_INVALID );
1725 return TRUE;
1727 win_w = GetDlgItemInt( dialog, IDC_CNF_WIN_WIDTH, &st1, FALSE );
1728 win_h = GetDlgItemInt( dialog, IDC_CNF_WIN_HEIGHT, &st2, FALSE );
1729 if (!st1 || !st2)
1731 SetWindowLongPtrW( dialog, DWLP_MSGRESULT, PSNRET_INVALID );
1732 return TRUE;
1734 if (win_w > sb_w || win_h > sb_h)
1736 WCHAR cap[256];
1737 WCHAR txt[256];
1739 LoadStringW( GetModuleHandleW(NULL), IDS_DLG_TIT_ERROR, cap, ARRAY_SIZE(cap) );
1740 LoadStringW( GetModuleHandleW(NULL), IDS_DLG_ERR_SBWINSIZE, txt, ARRAY_SIZE(txt) );
1742 MessageBoxW( dialog, txt, cap, MB_OK );
1743 SetWindowLongPtrW( dialog, DWLP_MSGRESULT, PSNRET_INVALID );
1744 return TRUE;
1746 di->config.win_width = win_w;
1747 di->config.win_height = win_h;
1748 di->config.sb_width = sb_w;
1749 di->config.sb_height = sb_h;
1751 di->config.edition_mode = SendDlgItemMessageW( dialog, IDC_CNF_EDITION_MODE,
1752 CB_GETCURSEL, 0, 0 );
1753 SetWindowLongPtrW( dialog, DWLP_MSGRESULT, PSNRET_NOERROR );
1754 return TRUE;
1755 default:
1756 return FALSE;
1758 break;
1760 default:
1761 return FALSE;
1763 return TRUE;
1766 static void apply_config( struct console *console, const struct console_config *config )
1768 if (console->active->width != config->sb_width || console->active->height != config->sb_height)
1769 change_screen_buffer_size( console->active, config->sb_width, config->sb_height );
1771 console->window->menu_mask = config->menu_mask;
1772 console->window->quick_edit = config->quick_edit;
1774 console->edition_mode = config->edition_mode;
1775 console->history_mode = config->history_mode;
1777 if (console->history_size != config->history_size)
1779 struct history_line **mem = NULL;
1780 int i, delta;
1782 if (config->history_size && (mem = malloc( config->history_size * sizeof(*mem) )))
1784 memset( mem, 0, config->history_size * sizeof(*mem) );
1786 delta = (console->history_index > config->history_size)
1787 ? (console->history_index - config->history_size) : 0;
1789 for (i = delta; i < console->history_index; i++)
1791 mem[i - delta] = console->history[i];
1792 console->history[i] = NULL;
1794 console->history_index -= delta;
1796 for (i = 0; i < console->history_size; i++)
1797 free( console->history[i] );
1798 free( console->history );
1799 console->history = mem;
1800 console->history_size = config->history_size;
1804 if (config->insert_mode)
1805 console->mode |= ENABLE_INSERT_MODE|ENABLE_EXTENDED_FLAGS;
1806 else
1807 console->mode &= ~ENABLE_INSERT_MODE;
1809 console->active->cursor_size = config->cursor_size;
1810 console->active->cursor_visible = config->cursor_visible;
1811 console->active->attr = config->attr;
1812 console->active->popup_attr = config->popup_attr;
1813 console->active->win.left = config->win_pos.X;
1814 console->active->win.top = config->win_pos.Y;
1815 console->active->win.right = config->win_pos.X + config->win_width - 1;
1816 console->active->win.bottom = config->win_pos.Y + config->win_height - 1;
1817 memcpy( console->active->color_map, config->color_map, sizeof(config->color_map) );
1819 if (console->active->font.width != config->cell_width ||
1820 console->active->font.height != config->cell_height ||
1821 console->active->font.weight != config->font_weight ||
1822 console->active->font.pitch_family != config->font_pitch_family ||
1823 console->active->font.face_len != wcslen( config->face_name ) ||
1824 memcmp( console->active->font.face_name, config->face_name,
1825 console->active->font.face_len * sizeof(WCHAR) ))
1827 update_console_font( console, config->face_name, wcslen(config->face_name) * sizeof(WCHAR),
1828 config->cell_height, config->font_weight );
1831 update_window( console );
1833 notify_screen_buffer_size( console->active );
1836 static void current_config( struct console *console, struct console_config *config )
1838 size_t len;
1840 config->menu_mask = console->window->menu_mask;
1841 config->quick_edit = console->window->quick_edit;
1843 config->edition_mode = console->edition_mode;
1844 config->history_mode = console->history_mode;
1845 config->history_size = console->history_size;
1847 config->insert_mode = (console->mode & (ENABLE_INSERT_MODE|ENABLE_EXTENDED_FLAGS)) ==
1848 (ENABLE_INSERT_MODE|ENABLE_EXTENDED_FLAGS);
1850 config->cursor_size = console->active->cursor_size;
1851 config->cursor_visible = console->active->cursor_visible;
1852 config->attr = console->active->attr;
1853 config->popup_attr = console->active->popup_attr;
1854 memcpy( config->color_map, console->active->color_map, sizeof(config->color_map) );
1856 config->cell_width = console->active->font.width;
1857 config->cell_height = console->active->font.height;
1858 config->font_weight = console->active->font.weight;
1859 config->font_pitch_family = console->active->font.pitch_family;
1860 len = min( ARRAY_SIZE(config->face_name) - 1, console->active->font.face_len );
1861 if (len) memcpy( config->face_name, console->active->font.face_name, len * sizeof(WCHAR) );
1862 config->face_name[len] = 0;
1864 config->sb_width = console->active->width;
1865 config->sb_height = console->active->height;
1867 config->win_width = console->active->win.right - console->active->win.left + 1;
1868 config->win_height = console->active->win.bottom - console->active->win.top + 1;
1869 config->win_pos.X = console->active->win.left;
1870 config->win_pos.Y = console->active->win.top;
1873 /* run the dialog box to set up the console options */
1874 static BOOL config_dialog( struct console *console, BOOL current )
1876 struct console_config prev_config;
1877 struct dialog_info di;
1878 PROPSHEETHEADERW header;
1879 HPROPSHEETPAGE pages[3];
1880 PROPSHEETPAGEW psp;
1881 WNDCLASSW wndclass;
1882 WCHAR buff[256];
1884 InitCommonControls();
1886 memset( &di, 0, sizeof(di) );
1887 di.console = console;
1889 if (current)
1890 current_config( console, &di.config );
1891 else
1892 load_config( NULL, &di.config );
1894 prev_config = di.config;
1896 wndclass.style = 0;
1897 wndclass.lpfnWndProc = font_preview_proc;
1898 wndclass.cbClsExtra = 0;
1899 wndclass.cbWndExtra = sizeof(HFONT);
1900 wndclass.hInstance = GetModuleHandleW( NULL );
1901 wndclass.hIcon = 0;
1902 wndclass.hCursor = LoadCursorW( 0, (const WCHAR *)IDC_ARROW );
1903 wndclass.hbrBackground = GetStockObject( BLACK_BRUSH );
1904 wndclass.lpszMenuName = NULL;
1905 wndclass.lpszClassName = L"WineConFontPreview";
1906 RegisterClassW( &wndclass );
1908 wndclass.style = 0;
1909 wndclass.lpfnWndProc = color_preview_proc;
1910 wndclass.cbClsExtra = 0;
1911 wndclass.cbWndExtra = sizeof(DWORD);
1912 wndclass.hInstance = GetModuleHandleW( NULL );
1913 wndclass.hIcon = 0;
1914 wndclass.hCursor = LoadCursorW( 0, (const WCHAR *)IDC_ARROW );
1915 wndclass.hbrBackground = GetStockObject( BLACK_BRUSH );
1916 wndclass.lpszMenuName = NULL;
1917 wndclass.lpszClassName = L"WineConColorPreview";
1918 RegisterClassW( &wndclass );
1920 memset( &psp, 0, sizeof(psp) );
1921 psp.dwSize = sizeof(psp);
1922 psp.dwFlags = 0;
1923 psp.hInstance = wndclass.hInstance;
1924 psp.lParam = (LPARAM)&di;
1926 psp.pszTemplate = MAKEINTRESOURCEW(IDD_OPTION);
1927 psp.pfnDlgProc = option_dialog_proc;
1928 pages[0] = CreatePropertySheetPageW( &psp );
1930 psp.pszTemplate = MAKEINTRESOURCEW(IDD_FONT);
1931 psp.pfnDlgProc = font_dialog_proc;
1932 pages[1] = CreatePropertySheetPageW( &psp );
1934 psp.pszTemplate = MAKEINTRESOURCEW(IDD_CONFIG);
1935 psp.pfnDlgProc = config_dialog_proc;
1936 pages[2] = CreatePropertySheetPageW( &psp );
1938 memset( &header, 0, sizeof(header) );
1939 header.dwSize = sizeof(header);
1941 if (!LoadStringW( GetModuleHandleW( NULL ),
1942 current ? IDS_DLG_TIT_CURRENT : IDS_DLG_TIT_DEFAULT,
1943 buff, ARRAY_SIZE(buff) ))
1944 wcscpy( buff, L"Setup" );
1946 header.pszCaption = buff;
1947 header.nPages = 3;
1948 header.hwndParent = console->win;
1949 header.phpage = pages;
1950 header.dwFlags = PSH_NOAPPLYNOW;
1951 if (PropertySheetW( &header ) < 1)
1952 return TRUE;
1954 if (!memcmp( &prev_config, &di.config, sizeof(prev_config) ))
1955 return TRUE;
1957 TRACE( "%s\n", debugstr_config(&di.config) );
1959 if (current)
1961 apply_config( console, &di.config );
1962 update_window( di.console );
1965 save_config( current ? console->window->config_key : NULL, &di.config );
1967 return TRUE;
1970 static void resize_window( struct console *console, int width, int height )
1972 struct console_config config;
1974 current_config( console, &config );
1975 config.win_width = width;
1976 config.win_height = height;
1978 /* auto size screen-buffer if it's now smaller than window */
1979 if (config.sb_width < config.win_width)
1980 config.sb_width = config.win_width;
1981 if (config.sb_height < config.win_height)
1982 config.sb_height = config.win_height;
1984 /* and reset window pos so that we don't display outside of the screen-buffer */
1985 if (config.win_pos.X + config.win_width > config.sb_width)
1986 config.win_pos.X = config.sb_width - config.win_width;
1987 if (config.win_pos.Y + config.win_height > config.sb_height)
1988 config.win_pos.Y = config.sb_height - config.win_height;
1990 apply_config( console, &config );
1993 /* grays / ungrays the menu items according to their state */
1994 static void set_menu_details( struct console *console, HMENU menu )
1996 EnableMenuItem( menu, IDS_COPY, MF_BYCOMMAND |
1997 (console->window->in_selection ? MF_ENABLED : MF_GRAYED) );
1998 EnableMenuItem( menu, IDS_PASTE, MF_BYCOMMAND |
1999 (IsClipboardFormatAvailable(CF_UNICODETEXT) ? MF_ENABLED : MF_GRAYED) );
2000 EnableMenuItem( menu, IDS_SCROLL, MF_BYCOMMAND | MF_GRAYED );
2001 EnableMenuItem( menu, IDS_SEARCH, MF_BYCOMMAND | MF_GRAYED );
2004 static BOOL fill_menu( HMENU menu, BOOL sep )
2006 HINSTANCE module = GetModuleHandleW( NULL );
2007 HMENU sub_menu;
2008 WCHAR buff[256];
2010 if (!menu) return FALSE;
2012 sub_menu = CreateMenu();
2013 if (!sub_menu) return FALSE;
2015 LoadStringW( module, IDS_MARK, buff, ARRAY_SIZE(buff) );
2016 InsertMenuW( sub_menu, -1, MF_BYPOSITION|MF_STRING, IDS_MARK, buff );
2017 LoadStringW( module, IDS_COPY, buff, ARRAY_SIZE(buff) );
2018 InsertMenuW( sub_menu, -1, MF_BYPOSITION|MF_STRING, IDS_COPY, buff );
2019 LoadStringW( module, IDS_PASTE, buff, ARRAY_SIZE(buff) );
2020 InsertMenuW( sub_menu, -1, MF_BYPOSITION|MF_STRING, IDS_PASTE, buff );
2021 LoadStringW( module, IDS_SELECTALL, buff, ARRAY_SIZE(buff) );
2022 InsertMenuW( sub_menu, -1, MF_BYPOSITION|MF_STRING, IDS_SELECTALL, buff );
2023 LoadStringW( module, IDS_SCROLL, buff, ARRAY_SIZE(buff) );
2024 InsertMenuW( sub_menu, -1, MF_BYPOSITION|MF_STRING, IDS_SCROLL, buff );
2025 LoadStringW( module, IDS_SEARCH, buff, ARRAY_SIZE(buff) );
2026 InsertMenuW( sub_menu, -1, MF_BYPOSITION|MF_STRING, IDS_SEARCH, buff );
2028 if (sep) InsertMenuW( menu, -1, MF_BYPOSITION|MF_SEPARATOR, 0, NULL );
2029 LoadStringW( module, IDS_EDIT, buff, ARRAY_SIZE(buff) );
2030 InsertMenuW( menu, -1, MF_BYPOSITION|MF_STRING|MF_POPUP, (UINT_PTR)sub_menu, buff );
2031 LoadStringW( module, IDS_DEFAULT, buff, ARRAY_SIZE(buff) );
2032 InsertMenuW( menu, -1, MF_BYPOSITION|MF_STRING, IDS_DEFAULT, buff );
2033 LoadStringW( module, IDS_PROPERTIES, buff, ARRAY_SIZE(buff) );
2034 InsertMenuW( menu, -1, MF_BYPOSITION|MF_STRING, IDS_PROPERTIES, buff );
2036 return TRUE;
2039 static LRESULT window_create( HWND hwnd, const CREATESTRUCTW *create )
2041 struct console *console = create->lpCreateParams;
2042 HMENU sys_menu;
2044 TRACE( "%p\n", hwnd );
2046 SetWindowLongPtrW( hwnd, 0, (DWORD_PTR)console );
2047 console->win = hwnd;
2049 if (console->window)
2051 sys_menu = GetSystemMenu( hwnd, FALSE );
2052 if (!sys_menu) return 0;
2053 console->window->popup_menu = CreatePopupMenu();
2054 if (!console->window->popup_menu) return 0;
2056 fill_menu( sys_menu, TRUE );
2057 fill_menu( console->window->popup_menu, FALSE );
2059 console->window->mem_dc = CreateCompatibleDC( 0 );
2061 return 0;
2064 static LRESULT WINAPI window_proc( HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam )
2066 struct console *console = (struct console *)GetWindowLongPtrW( hwnd, 0 );
2068 switch (msg)
2070 case WM_CREATE:
2071 return window_create( hwnd, (const CREATESTRUCTW *)lparam );
2073 case WM_DESTROY:
2074 console->win = NULL;
2075 PostQuitMessage( 0 );
2076 break;
2078 case WM_TIMER:
2079 case WM_UPDATE_CONFIG:
2080 if (console->window && console->window->update_state == UPDATE_PENDING)
2081 update_window( console );
2082 break;
2084 case WM_PAINT:
2086 PAINTSTRUCT ps;
2088 if (!console->window) break;
2090 BeginPaint( console->win, &ps );
2091 BitBlt( ps.hdc, 0, 0,
2092 (console->active->win.right - console->active->win.left + 1) * console->active->font.width,
2093 (console->active->win.bottom - console->active->win.top + 1) * console->active->font.height,
2094 console->window->mem_dc,
2095 console->active->win.left * console->active->font.width,
2096 console->active->win.top * console->active->font.height,
2097 SRCCOPY );
2098 if (console->window->in_selection) update_selection( console, ps.hdc );
2099 EndPaint( console->win, &ps );
2100 break;
2103 case WM_SHOWWINDOW:
2104 if (!console->window) break;
2105 if (wparam)
2106 update_window( console );
2107 else
2109 if (console->window->bitmap) DeleteObject( console->window->bitmap );
2110 console->window->bitmap = NULL;
2112 break;
2114 case WM_KEYDOWN:
2115 case WM_KEYUP:
2116 if (console->window && console->window->in_selection)
2117 handle_selection_key( console, msg == WM_KEYDOWN, wparam, lparam );
2118 else
2119 record_key_input( console, msg == WM_KEYDOWN, wparam, lparam );
2120 break;
2122 case WM_SYSKEYDOWN:
2123 case WM_SYSKEYUP:
2124 record_key_input( console, msg == WM_SYSKEYDOWN, wparam, lparam );
2125 break;
2127 case WM_LBUTTONDOWN:
2128 if (console->window && (console->window->quick_edit || console->window->in_selection))
2130 if (console->window->in_selection)
2131 update_selection( console, 0 );
2133 if (console->window->quick_edit && console->window->in_selection)
2135 console->window->in_selection = FALSE;
2137 else
2139 console->window->selection_end = get_cell( console, lparam );
2140 console->window->selection_start = console->window->selection_end;
2141 SetCapture( console->win );
2142 update_selection( console, 0 );
2143 console->window->in_selection = TRUE;
2146 else
2148 record_mouse_input( console, get_cell(console, lparam), wparam, 0 );
2150 break;
2152 case WM_MOUSEMOVE:
2153 if (console->window && (console->window->quick_edit || console->window->in_selection))
2155 if (GetCapture() == console->win && console->window->in_selection &&
2156 (wparam & MK_LBUTTON))
2158 move_selection( console, console->window->selection_start,
2159 get_cell(console, lparam) );
2162 else
2164 record_mouse_input( console, get_cell(console, lparam), wparam, MOUSE_MOVED );
2166 break;
2168 case WM_LBUTTONUP:
2169 if (console->window && (console->window->quick_edit || console->window->in_selection))
2171 if (GetCapture() == console->win && console->window->in_selection)
2173 move_selection( console, console->window->selection_start,
2174 get_cell(console, lparam) );
2175 ReleaseCapture();
2178 else
2180 record_mouse_input( console, get_cell(console, lparam), wparam, 0 );
2182 break;
2184 case WM_RBUTTONDOWN:
2185 if (console->window && (wparam & (MK_CONTROL|MK_SHIFT)) == console->window->menu_mask)
2187 POINT pt;
2188 pt.x = (short)LOWORD(lparam);
2189 pt.y = (short)HIWORD(lparam);
2190 ClientToScreen( hwnd, &pt );
2191 set_menu_details( console, console->window->popup_menu );
2192 TrackPopupMenu( console->window->popup_menu, TPM_LEFTALIGN|TPM_TOPALIGN|TPM_RIGHTBUTTON,
2193 pt.x, pt.y, 0, hwnd, NULL );
2195 else
2197 record_mouse_input( console, get_cell(console, lparam), wparam, 0 );
2199 break;
2201 case WM_RBUTTONUP:
2202 /* no need to track for rbutton up when opening the popup... the event will be
2203 * swallowed by TrackPopupMenu */
2204 case WM_MBUTTONDOWN:
2205 case WM_MBUTTONUP:
2206 record_mouse_input( console, get_cell(console, lparam), wparam, 0 );
2207 break;
2209 case WM_LBUTTONDBLCLK:
2210 case WM_MBUTTONDBLCLK:
2211 case WM_RBUTTONDBLCLK:
2212 record_mouse_input( console, get_cell(console, lparam), wparam, DOUBLE_CLICK );
2213 break;
2215 case WM_SETFOCUS:
2216 if (console->window && console->active->cursor_visible)
2218 CreateCaret( console->win, console->window->cursor_bitmap,
2219 console->active->font.width, console->active->font.height );
2220 update_window_cursor( console );
2222 break;
2224 case WM_KILLFOCUS:
2225 if (console->window && console->active->cursor_visible)
2226 DestroyCaret();
2227 break;
2229 case WM_SIZE:
2230 if (console->window && console->window->update_state != UPDATE_BUSY)
2231 resize_window( console,
2232 max( LOWORD(lparam) / console->active->font.width, 20 ),
2233 max( HIWORD(lparam) / console->active->font.height, 20 ));
2234 break;
2236 case WM_HSCROLL:
2238 int win_width = console->active->win.right - console->active->win.left + 1;
2239 int x = console->active->win.left;
2241 if (!console->window) break;
2242 switch (LOWORD(wparam))
2244 case SB_PAGEUP: x -= 8; break;
2245 case SB_PAGEDOWN: x += 8; break;
2246 case SB_LINEUP: x--; break;
2247 case SB_LINEDOWN: x++; break;
2248 case SB_THUMBTRACK: x = HIWORD(wparam); break;
2249 default: break;
2251 x = min( max( x, 0 ), console->active->width - win_width );
2252 if (x != console->active->win.left)
2254 console->active->win.left = x;
2255 console->active->win.right = x + win_width - 1;
2256 update_window( console );
2258 break;
2261 case WM_MOUSEWHEEL:
2262 if (console->active->height <= console->active->win.bottom - console->active->win.top + 1)
2264 record_mouse_input(console, get_cell(console, lparam), wparam, MOUSE_WHEELED);
2265 break;
2267 /* else fallthrough */
2268 case WM_VSCROLL:
2270 int win_height = console->active->win.bottom - console->active->win.top + 1;
2271 int y = console->active->win.top;
2273 if (!console->window) break;
2275 if (msg == WM_MOUSEWHEEL)
2277 UINT scroll_lines = 3;
2278 SystemParametersInfoW( SPI_GETWHEELSCROLLLINES, 0, &scroll_lines, 0 );
2279 scroll_lines *= -GET_WHEEL_DELTA_WPARAM(wparam) / WHEEL_DELTA;
2280 y += scroll_lines;
2282 else
2284 switch (LOWORD(wparam))
2286 case SB_PAGEUP: y -= 8; break;
2287 case SB_PAGEDOWN: y += 8; break;
2288 case SB_LINEUP: y--; break;
2289 case SB_LINEDOWN: y++; break;
2290 case SB_THUMBTRACK: y = HIWORD(wparam); break;
2291 default: break;
2295 y = min( max( y, 0 ), console->active->height - win_height );
2296 if (y != console->active->win.top)
2298 console->active->win.top = y;
2299 console->active->win.bottom = y + win_height - 1;
2300 update_window( console );
2302 break;
2305 case WM_SYSCOMMAND:
2306 if (!console->window) break;
2307 switch (wparam)
2309 case IDS_DEFAULT:
2310 config_dialog( console, FALSE );
2311 break;
2312 case IDS_PROPERTIES:
2313 config_dialog( console, TRUE );
2314 break;
2315 default:
2316 return DefWindowProcW( hwnd, msg, wparam, lparam );
2318 break;
2320 case WM_COMMAND:
2321 if (!console->window) break;
2322 switch (wparam)
2324 case IDS_DEFAULT:
2325 config_dialog( console, FALSE );
2326 break;
2327 case IDS_PROPERTIES:
2328 config_dialog( console, TRUE );
2329 break;
2330 case IDS_MARK:
2331 console->window->selection_start.X = console->window->selection_start.Y = 0;
2332 console->window->selection_end.X = console->window->selection_end.Y = 0;
2333 update_selection( console, 0 );
2334 console->window->in_selection = TRUE;
2335 break;
2336 case IDS_COPY:
2337 if (console->window->in_selection)
2339 console->window->in_selection = FALSE;
2340 update_selection( console, 0 );
2341 copy_selection( console );
2343 break;
2344 case IDS_PASTE:
2345 paste_clipboard( console );
2346 break;
2347 case IDS_SELECTALL:
2348 console->window->selection_start.X = console->window->selection_start.Y = 0;
2349 console->window->selection_end.X = console->active->width - 1;
2350 console->window->selection_end.Y = console->active->height - 1;
2351 update_selection( console, 0 );
2352 console->window->in_selection = TRUE;
2353 break;
2354 case IDS_SCROLL:
2355 case IDS_SEARCH:
2356 FIXME( "Unhandled yet command: %Ix\n", wparam );
2357 break;
2358 default:
2359 return DefWindowProcW( hwnd, msg, wparam, lparam );
2361 break;
2363 case WM_INITMENUPOPUP:
2364 if (!console->window || !HIWORD(lparam)) return DefWindowProcW( hwnd, msg, wparam, lparam );
2365 set_menu_details( console, GetSystemMenu(console->win, FALSE) );
2366 break;
2368 default:
2369 return DefWindowProcW( hwnd, msg, wparam, lparam );
2372 return 0;
2375 void update_window_config( struct console *console, BOOL delay )
2377 const int delay_timeout = 50;
2379 if (!console->window || console->window->update_state != UPDATE_NONE) return;
2380 console->window->update_state = UPDATE_PENDING;
2381 if (delay)
2382 SetTimer( console->win, 1, delay_timeout, NULL );
2383 else
2384 PostMessageW( console->win, WM_UPDATE_CONFIG, 0, 0 );
2387 void update_window_region( struct console *console, const RECT *update )
2389 RECT *window_rect = &console->window->update;
2390 window_rect->left = min( window_rect->left, update->left );
2391 window_rect->top = min( window_rect->top, update->top );
2392 window_rect->right = max( window_rect->right, update->right );
2393 window_rect->bottom = max( window_rect->bottom, update->bottom );
2394 update_window_config( console, TRUE );
2397 BOOL init_window( struct console *console )
2399 struct console_config config;
2400 WNDCLASSW wndclass;
2401 STARTUPINFOW si;
2402 CHARSETINFO ci;
2404 static struct console_window console_window;
2406 console->window = &console_window;
2407 if (!TranslateCharsetInfo( (DWORD *)(INT_PTR)GetACP(), &ci, TCI_SRCCODEPAGE ))
2408 return FALSE;
2410 console->window->ui_charset = ci.ciCharset;
2412 GetStartupInfoW(&si);
2413 if (si.lpTitle)
2415 size_t i, title_len = wcslen( si.lpTitle );
2416 if (!(console->window->config_key = malloc( (title_len + 1) * sizeof(WCHAR) )))
2417 return FALSE;
2418 for (i = 0; i < title_len; i++)
2419 console->window->config_key[i] = si.lpTitle[i] == '\\' ? '_' : si.lpTitle[i];
2420 console->window->config_key[title_len] = 0;
2423 load_config( console->window->config_key, &config );
2424 if (si.dwFlags & STARTF_USECOUNTCHARS)
2426 config.sb_width = si.dwXCountChars;
2427 config.sb_height = si.dwYCountChars;
2429 if (si.dwFlags & STARTF_USEFILLATTRIBUTE)
2430 config.attr = si.dwFillAttribute;
2432 wndclass.style = CS_DBLCLKS;
2433 wndclass.lpfnWndProc = window_proc;
2434 wndclass.cbClsExtra = 0;
2435 wndclass.cbWndExtra = sizeof(DWORD_PTR);
2436 wndclass.hInstance = GetModuleHandleW(NULL);
2437 wndclass.hIcon = LoadIconW( 0, (const WCHAR *)IDI_WINLOGO );
2438 wndclass.hCursor = LoadCursorW( 0, (const WCHAR *)IDC_ARROW );
2439 wndclass.hbrBackground = GetStockObject( BLACK_BRUSH );
2440 wndclass.lpszMenuName = NULL;
2441 wndclass.lpszClassName = L"WineConsoleClass";
2442 RegisterClassW(&wndclass);
2444 if (!CreateWindowW( wndclass.lpszClassName, NULL,
2445 WS_OVERLAPPED|WS_CAPTION|WS_SYSMENU|WS_THICKFRAME|WS_MINIMIZEBOX|
2446 WS_MAXIMIZEBOX|WS_HSCROLL|WS_VSCROLL, CW_USEDEFAULT, CW_USEDEFAULT,
2447 0, 0, 0, 0, wndclass.hInstance, console ))
2448 return FALSE;
2450 if (!config.face_name[0])
2451 set_first_font( console, &config );
2453 apply_config( console, &config );
2454 return TRUE;
2457 void init_message_window( struct console *console )
2459 WNDCLASSW wndclass;
2461 wndclass.style = CS_DBLCLKS;
2462 wndclass.lpfnWndProc = window_proc;
2463 wndclass.cbClsExtra = 0;
2464 wndclass.cbWndExtra = sizeof(DWORD_PTR);
2465 wndclass.hInstance = GetModuleHandleW( NULL );
2466 wndclass.hIcon = 0;
2467 wndclass.hCursor = 0;
2468 wndclass.hbrBackground = GetStockObject( BLACK_BRUSH );
2469 wndclass.lpszMenuName = NULL;
2470 wndclass.lpszClassName = L"WineConsoleClass";
2471 RegisterClassW(&wndclass);
2473 CreateWindowW( wndclass.lpszClassName, NULL,
2474 WS_OVERLAPPED|WS_CAPTION|WS_SYSMENU|WS_THICKFRAME|WS_MINIMIZEBOX|
2475 WS_MAXIMIZEBOX|WS_HSCROLL|WS_VSCROLL, CW_USEDEFAULT, CW_USEDEFAULT,
2476 0, 0, HWND_MESSAGE, 0, wndclass.hInstance, console );