mfmediaengine/tests: Pass a device manager and output format to create_media_engine.
[wine.git] / programs / conhost / window.c
blob3db4b159696e264d3018a98a9ef9d3d4d7ffcde6
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 #define NONAMELESSUNION
21 #include <stdlib.h>
23 #include "conhost.h"
25 #include <commctrl.h>
26 #include <winreg.h>
28 #include "wine/debug.h"
30 WINE_DEFAULT_DEBUG_CHANNEL(console);
32 #define WM_UPDATE_CONFIG (WM_USER + 1)
34 enum update_state
36 UPDATE_NONE,
37 UPDATE_PENDING,
38 UPDATE_BUSY
41 struct console_window
43 HDC mem_dc; /* memory DC holding the bitmap below */
44 HBITMAP bitmap; /* bitmap of display window content */
45 HFONT font; /* font used for rendering, usually fixed */
46 HMENU popup_menu; /* popup menu triggered by right mouse click */
47 HBITMAP cursor_bitmap; /* bitmap used for the caret */
48 BOOL in_selection; /* an area is being selected */
49 COORD selection_start; /* selection coordinates */
50 COORD selection_end;
51 unsigned int ui_charset; /* default UI charset */
52 WCHAR *config_key; /* config registry key name */
53 LONG ext_leading; /* external leading for font */
55 BOOL quick_edit; /* whether mouse ops are sent to app or used for content selection */
56 unsigned int menu_mask; /* MK_CONTROL MK_SHIFT mask to drive submenu opening */
57 COORD win_pos; /* position (in cells) of visible part of screen buffer in window */
58 unsigned int win_width; /* size (in cells) of visible part of window (width & height) */
59 unsigned int win_height;
60 unsigned int cursor_size; /* in % of cell height */
61 int cursor_visible; /* cursor visibility */
62 unsigned int sb_width; /* active screen buffer width */
63 unsigned int sb_height; /* active screen buffer height */
64 COORD cursor_pos; /* cursor position */
66 RECT update; /* screen buffer update rect */
67 enum update_state update_state; /* update state */
70 struct console_config
72 DWORD color_map[16]; /* console color table */
73 unsigned int cell_width; /* width in pixels of a character */
74 unsigned int cell_height; /* height in pixels of a character */
75 unsigned int cursor_size; /* in % of cell height */
76 int cursor_visible; /* cursor visibility */
77 unsigned int attr; /* default fill attributes (screen colors) */
78 unsigned int popup_attr ; /* pop-up color attributes */
79 unsigned int history_size; /* number of commands in history buffer */
80 unsigned int history_mode; /* flag if commands are not stored twice in buffer */
81 unsigned int insert_mode; /* TRUE to insert text at the cursor location; FALSE to overwrite it */
82 unsigned int menu_mask; /* MK_CONTROL MK_SHIFT mask to drive submenu opening */
83 unsigned int quick_edit; /* whether mouse ops are sent to app or used for content selection */
84 unsigned int sb_width; /* active screen buffer width */
85 unsigned int sb_height; /* active screen buffer height */
86 unsigned int win_width; /* size (in cells) of visible part of window (width & height) */
87 unsigned int win_height;
88 COORD win_pos; /* position (in cells) of visible part of screen buffer in window */
89 unsigned int edition_mode; /* edition mode flavor while line editing */
90 unsigned int font_pitch_family;
91 unsigned int font_weight;
92 WCHAR face_name[LF_FACESIZE];
95 static const char *debugstr_config( const struct console_config *config )
97 return wine_dbg_sprintf( "cell=(%u,%u) cursor=(%d,%d) attr=%02x pop-up=%02x font=%s/%u/%u "
98 "hist=%u/%d flags=%c%c msk=%08x sb=(%u,%u) win=(%u,%u)x(%u,%u) edit=%u",
99 config->cell_width, config->cell_height, config->cursor_size,
100 config->cursor_visible, config->attr, config->popup_attr,
101 wine_dbgstr_w(config->face_name), config->font_pitch_family,
102 config->font_weight, config->history_size,
103 config->history_mode ? 1 : 2,
104 config->insert_mode ? 'I' : 'i',
105 config->quick_edit ? 'Q' : 'q',
106 config->menu_mask, config->sb_width, config->sb_height,
107 config->win_pos.X, config->win_pos.Y, config->win_width,
108 config->win_height, config->edition_mode );
111 static const char *debugstr_logfont( const LOGFONTW *lf, unsigned int ft )
113 return wine_dbg_sprintf( "%s%s%s%s lfHeight=%ld lfWidth=%ld lfEscapement=%ld "
114 "lfOrientation=%ld lfWeight=%ld lfItalic=%u lfUnderline=%u "
115 "lfStrikeOut=%u lfCharSet=%u lfPitchAndFamily=%u lfFaceName=%s",
116 (ft & RASTER_FONTTYPE) ? "raster" : "",
117 (ft & TRUETYPE_FONTTYPE) ? "truetype" : "",
118 ((ft & (RASTER_FONTTYPE|TRUETYPE_FONTTYPE)) == 0) ? "vector" : "",
119 (ft & DEVICE_FONTTYPE) ? "|device" : "",
120 lf->lfHeight, lf->lfWidth, lf->lfEscapement, lf->lfOrientation,
121 lf->lfWeight, lf->lfItalic, lf->lfUnderline, lf->lfStrikeOut,
122 lf->lfCharSet, lf->lfPitchAndFamily, wine_dbgstr_w( lf->lfFaceName ));
125 static const char *debugstr_textmetric( const TEXTMETRICW *tm, unsigned int ft )
127 return wine_dbg_sprintf( "%s%s%s%s tmHeight=%ld tmAscent=%ld tmDescent=%ld "
128 "tmAveCharWidth=%ld tmMaxCharWidth=%ld tmWeight=%ld "
129 "tmPitchAndFamily=%u tmCharSet=%u",
130 (ft & RASTER_FONTTYPE) ? "raster" : "",
131 (ft & TRUETYPE_FONTTYPE) ? "truetype" : "",
132 ((ft & (RASTER_FONTTYPE|TRUETYPE_FONTTYPE)) == 0) ? "vector" : "",
133 (ft & DEVICE_FONTTYPE) ? "|device" : "",
134 tm->tmHeight, tm->tmAscent, tm->tmDescent, tm->tmAveCharWidth,
135 tm->tmMaxCharWidth, tm->tmWeight, tm->tmPitchAndFamily,
136 tm->tmCharSet );
139 /* read the basic configuration from any console key or subkey */
140 static void load_registry_key( HKEY key, struct console_config *config )
142 DWORD type, count, val, i;
143 WCHAR color_name[13];
145 for (i = 0; i < ARRAY_SIZE(config->color_map); i++)
147 wsprintfW( color_name, L"ColorTable%02d", i );
148 count = sizeof(val);
149 if (!RegQueryValueExW( key, color_name, 0, &type, (BYTE *)&val, &count ))
150 config->color_map[i] = val;
153 count = sizeof(val);
154 if (!RegQueryValueExW( key, L"CursorSize", 0, &type, (BYTE *)&val, &count ))
155 config->cursor_size = val;
157 count = sizeof(val);
158 if (!RegQueryValueExW( key, L"CursorVisible", 0, &type, (BYTE *)&val, &count ))
159 config->cursor_visible = val;
161 count = sizeof(val);
162 if (!RegQueryValueExW( key, L"EditionMode", 0, &type, (BYTE *)&val, &count ))
163 config->edition_mode = val;
165 count = sizeof(config->face_name);
166 RegQueryValueExW( key, L"FaceName", 0, &type, (BYTE *)&config->face_name, &count );
168 count = sizeof(val);
169 if (!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"FontPitchFamily", 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 fill_logfont( &lf, face_name, face_name_size, height, weight );
936 set_console_font( console, &lf );
939 /* get a cell from a relative coordinate in window (takes into account the scrolling) */
940 static COORD get_cell( struct console *console, LPARAM lparam )
942 COORD c;
943 c.X = console->active->win.left + (short)LOWORD(lparam) / console->active->font.width;
944 c.Y = console->active->win.top + (short)HIWORD(lparam) / console->active->font.height;
945 return c;
948 /* get the console bit mask equivalent to the VK_ status in key state */
949 static DWORD get_ctrl_state( BYTE *key_state)
951 unsigned int ret = 0;
953 GetKeyboardState(key_state);
954 if (key_state[VK_SHIFT] & 0x80) ret |= SHIFT_PRESSED;
955 if (key_state[VK_LCONTROL] & 0x80) ret |= LEFT_CTRL_PRESSED;
956 if (key_state[VK_RCONTROL] & 0x80) ret |= RIGHT_CTRL_PRESSED;
957 if (key_state[VK_LMENU] & 0x80) ret |= LEFT_ALT_PRESSED;
958 if (key_state[VK_RMENU] & 0x80) ret |= RIGHT_ALT_PRESSED;
959 if (key_state[VK_CAPITAL] & 0x01) ret |= CAPSLOCK_ON;
960 if (key_state[VK_NUMLOCK] & 0x01) ret |= NUMLOCK_ON;
961 if (key_state[VK_SCROLL] & 0x01) ret |= SCROLLLOCK_ON;
963 return ret;
966 /* get the selection rectangle */
967 static void get_selection_rect( struct console *console, RECT *r )
969 r->left = (min(console->window->selection_start.X, console->window->selection_end.X) -
970 console->active->win.left) * console->active->font.width;
971 r->top = (min(console->window->selection_start.Y, console->window->selection_end.Y) -
972 console->active->win.top) * console->active->font.height;
973 r->right = (max(console->window->selection_start.X, console->window->selection_end.X) + 1 -
974 console->active->win.left) * console->active->font.width;
975 r->bottom = (max(console->window->selection_start.Y, console->window->selection_end.Y) + 1 -
976 console->active->win.top) * console->active->font.height;
979 static void update_selection( struct console *console, HDC ref_dc )
981 HDC dc;
982 RECT r;
984 get_selection_rect( console, &r );
985 dc = ref_dc ? ref_dc : GetDC( console->win );
986 if (!dc) return;
988 if (console->win == GetFocus() && console->active->cursor_visible)
989 HideCaret( console->win );
990 InvertRect( dc, &r );
991 if (dc != ref_dc)
992 ReleaseDC( console->win, dc );
993 if (console->win == GetFocus() && console->active->cursor_visible)
994 ShowCaret( console->win );
997 static void move_selection( struct console *console, COORD c1, COORD c2 )
999 RECT r;
1000 HDC dc;
1002 if (c1.X < 0 || c1.X >= console->active->width ||
1003 c2.X < 0 || c2.X >= console->active->width ||
1004 c1.Y < 0 || c1.Y >= console->active->height ||
1005 c2.Y < 0 || c2.Y >= console->active->height)
1006 return;
1008 get_selection_rect( console, &r );
1009 dc = GetDC( console->win );
1010 if (dc)
1012 if (console->win == GetFocus() && console->active->cursor_visible)
1013 HideCaret( console->win );
1014 InvertRect( dc, &r );
1016 console->window->selection_start = c1;
1017 console->window->selection_end = c2;
1018 if (dc)
1020 get_selection_rect( console, &r );
1021 InvertRect( dc, &r );
1022 ReleaseDC( console->win, dc );
1023 if (console->win == GetFocus() && console->active->cursor_visible)
1024 ShowCaret( console->win );
1028 /* copies the current selection into the clipboard */
1029 static void copy_selection( struct console *console )
1031 unsigned int w, h;
1032 WCHAR *p, *buf;
1033 HANDLE mem;
1035 w = abs( console->window->selection_start.X - console->window->selection_end.X ) + 1;
1036 h = abs( console->window->selection_start.Y - console->window->selection_end.Y ) + 1;
1038 if (!OpenClipboard( console->win )) return;
1039 EmptyClipboard();
1041 mem = GlobalAlloc( GMEM_MOVEABLE, (w + 1) * h * sizeof(WCHAR) );
1042 if (mem && (p = buf = GlobalLock( mem )))
1044 int x, y;
1045 COORD c;
1047 c.X = min( console->window->selection_start.X, console->window->selection_end.X );
1048 c.Y = min( console->window->selection_start.Y, console->window->selection_end.Y );
1050 for (y = c.Y; y < c.Y + h; y++)
1052 WCHAR *end;
1054 for (x = c.X; x < c.X + w; x++)
1055 p[x - c.X] = console->active->data[y * console->active->width + x].ch;
1057 /* strip spaces from the end of the line */
1058 end = p + w;
1059 while (end > p && *(end - 1) == ' ')
1060 end--;
1061 *end = (y < c.Y + h - 1) ? '\n' : '\0';
1062 p = end + 1;
1065 TRACE( "%s\n", debugstr_w( buf ));
1066 if (p - buf != (w + 1) * h)
1068 HANDLE new_mem;
1069 new_mem = GlobalReAlloc( mem, (p - buf) * sizeof(WCHAR), GMEM_MOVEABLE );
1070 if (new_mem) mem = new_mem;
1072 GlobalUnlock( mem );
1073 SetClipboardData( CF_UNICODETEXT, mem );
1075 CloseClipboard();
1078 static void paste_clipboard( struct console *console )
1080 WCHAR *ptr;
1081 HANDLE h;
1083 if (!OpenClipboard( console->win )) return;
1084 h = GetClipboardData( CF_UNICODETEXT );
1085 if (h && (ptr = GlobalLock( h )))
1087 unsigned int i, len = GlobalSize(h) / sizeof(WCHAR);
1088 INPUT_RECORD ir[2];
1089 SHORT sh;
1091 ir[0].EventType = KEY_EVENT;
1092 ir[0].Event.KeyEvent.wRepeatCount = 0;
1093 ir[0].Event.KeyEvent.dwControlKeyState = 0;
1094 ir[0].Event.KeyEvent.bKeyDown = TRUE;
1096 /* generate the corresponding input records */
1097 for (i = 0; i < len; i++)
1099 /* FIXME: the modifying keys are not generated (shift, ctrl...) */
1100 sh = VkKeyScanW( ptr[i] );
1101 ir[0].Event.KeyEvent.wVirtualKeyCode = LOBYTE(sh);
1102 ir[0].Event.KeyEvent.wVirtualScanCode = MapVirtualKeyW( LOBYTE(sh), 0 );
1103 ir[0].Event.KeyEvent.uChar.UnicodeChar = ptr[i];
1105 ir[1] = ir[0];
1106 ir[1].Event.KeyEvent.bKeyDown = FALSE;
1108 write_console_input( console, ir, 2, i == len - 1 );
1110 GlobalUnlock( h );
1113 CloseClipboard();
1116 /* handle keys while selecting an area */
1117 static void handle_selection_key( struct console *console, BOOL down, WPARAM wparam, LPARAM lparam )
1119 BYTE key_state[256];
1120 COORD c1, c2;
1121 DWORD state;
1123 if (!down) return;
1124 state = get_ctrl_state( key_state ) & ~(CAPSLOCK_ON|NUMLOCK_ON|SCROLLLOCK_ON);
1126 switch (state)
1128 case 0:
1129 switch (wparam)
1131 case VK_RETURN:
1132 console->window->in_selection = FALSE;
1133 update_selection( console, 0 );
1134 copy_selection( console );
1135 return;
1136 case VK_RIGHT:
1137 c1 = console->window->selection_start;
1138 c2 = console->window->selection_end;
1139 c1.X++; c2.X++;
1140 move_selection( console, c1, c2 );
1141 return;
1142 case VK_LEFT:
1143 c1 = console->window->selection_start;
1144 c2 = console->window->selection_end;
1145 c1.X--; c2.X--;
1146 move_selection( console, c1, c2 );
1147 return;
1148 case VK_UP:
1149 c1 = console->window->selection_start;
1150 c2 = console->window->selection_end;
1151 c1.Y--; c2.Y--;
1152 move_selection( console, c1, c2 );
1153 return;
1154 case VK_DOWN:
1155 c1 = console->window->selection_start;
1156 c2 = console->window->selection_end;
1157 c1.Y++; c2.Y++;
1158 move_selection( console, c1, c2 );
1159 return;
1161 break;
1162 case SHIFT_PRESSED:
1163 switch (wparam)
1165 case VK_RIGHT:
1166 c1 = console->window->selection_start;
1167 c2 = console->window->selection_end;
1168 c2.X++;
1169 move_selection( console, c1, c2 );
1170 return;
1171 case VK_LEFT:
1172 c1 = console->window->selection_start;
1173 c2 = console->window->selection_end;
1174 c2.X--;
1175 move_selection( console, c1, c2 );
1176 return;
1177 case VK_UP:
1178 c1 = console->window->selection_start;
1179 c2 = console->window->selection_end;
1180 c2.Y--;
1181 move_selection( console, c1, c2 );
1182 return;
1183 case VK_DOWN:
1184 c1 = console->window->selection_start;
1185 c2 = console->window->selection_end;
1186 c2.Y++;
1187 move_selection( console, c1, c2 );
1188 return;
1190 break;
1193 if (wparam < VK_SPACE) /* Shift, Alt, Ctrl, Num Lock etc. */
1194 return;
1196 update_selection( console, 0 );
1197 console->window->in_selection = FALSE;
1200 /* generate input_record from windows WM_KEYUP/WM_KEYDOWN messages */
1201 static void record_key_input( struct console *console, BOOL down, WPARAM wparam, LPARAM lparam )
1203 static WCHAR last; /* keep last char seen as feed for key up message */
1204 BYTE key_state[256];
1205 INPUT_RECORD ir;
1206 WCHAR buf[2];
1208 ir.EventType = KEY_EVENT;
1209 ir.Event.KeyEvent.bKeyDown = down;
1210 ir.Event.KeyEvent.wRepeatCount = LOWORD(lparam);
1211 ir.Event.KeyEvent.wVirtualKeyCode = wparam;
1212 ir.Event.KeyEvent.wVirtualScanCode = HIWORD(lparam) & 0xFF;
1213 ir.Event.KeyEvent.uChar.UnicodeChar = 0;
1214 ir.Event.KeyEvent.dwControlKeyState = get_ctrl_state( key_state );
1215 if (lparam & (1u << 24)) ir.Event.KeyEvent.dwControlKeyState |= ENHANCED_KEY;
1217 if (down)
1219 switch (ToUnicode(wparam, HIWORD(lparam), key_state, buf, 2, 0))
1221 case 2:
1222 /* FIXME: should generate two events */
1223 /* fall through */
1224 case 1:
1225 last = buf[0];
1226 break;
1227 default:
1228 last = 0;
1229 break;
1232 ir.Event.KeyEvent.uChar.UnicodeChar = last;
1233 if (!down) last = 0; /* FIXME: buggy HACK */
1235 write_console_input( console, &ir, 1, TRUE );
1238 static void record_mouse_input( struct console *console, COORD c, WPARAM wparam, DWORD event )
1240 BYTE key_state[256];
1241 INPUT_RECORD ir;
1243 /* MOUSE_EVENTs shouldn't be sent unless ENABLE_MOUSE_INPUT is active */
1244 if (!(console->mode & ENABLE_MOUSE_INPUT)) return;
1246 ir.EventType = MOUSE_EVENT;
1247 ir.Event.MouseEvent.dwMousePosition = c;
1248 ir.Event.MouseEvent.dwButtonState = 0;
1249 if (wparam & MK_LBUTTON) ir.Event.MouseEvent.dwButtonState |= FROM_LEFT_1ST_BUTTON_PRESSED;
1250 if (wparam & MK_MBUTTON) ir.Event.MouseEvent.dwButtonState |= FROM_LEFT_2ND_BUTTON_PRESSED;
1251 if (wparam & MK_RBUTTON) ir.Event.MouseEvent.dwButtonState |= RIGHTMOST_BUTTON_PRESSED;
1252 if (wparam & MK_CONTROL) ir.Event.MouseEvent.dwButtonState |= LEFT_CTRL_PRESSED;
1253 if (wparam & MK_SHIFT) ir.Event.MouseEvent.dwButtonState |= SHIFT_PRESSED;
1254 if (event == MOUSE_WHEELED) ir.Event.MouseEvent.dwButtonState |= wparam & 0xFFFF0000;
1255 ir.Event.MouseEvent.dwControlKeyState = get_ctrl_state( key_state );
1256 ir.Event.MouseEvent.dwEventFlags = event;
1258 write_console_input( console, &ir, 1, TRUE );
1261 struct dialog_info
1263 struct console *console;
1264 struct console_config config;
1265 HWND dialog; /* handle to active propsheet */
1268 /* dialog proc for the option property sheet */
1269 static INT_PTR WINAPI option_dialog_proc( HWND dialog, UINT msg, WPARAM wparam, LPARAM lparam )
1271 struct dialog_info *di;
1272 unsigned int idc;
1274 switch (msg)
1276 case WM_INITDIALOG:
1277 di = (struct dialog_info *)((PROPSHEETPAGEA *)lparam)->lParam;
1278 di->dialog = dialog;
1279 SetWindowLongPtrW( dialog, DWLP_USER, (LONG_PTR)di );
1281 SendMessageW( GetDlgItem( dialog, IDC_OPT_HIST_SIZE_UD ), UDM_SETRANGE, 0, MAKELPARAM(500, 0) );
1283 if (di->config.cursor_size <= 25) idc = IDC_OPT_CURSOR_SMALL;
1284 else if (di->config.cursor_size <= 50) idc = IDC_OPT_CURSOR_MEDIUM;
1285 else idc = IDC_OPT_CURSOR_LARGE;
1287 SendDlgItemMessageW( dialog, idc, BM_SETCHECK, BST_CHECKED, 0 );
1288 SetDlgItemInt( dialog, IDC_OPT_HIST_SIZE, di->config.history_size, FALSE );
1289 SendDlgItemMessageW( dialog, IDC_OPT_HIST_NODOUBLE, BM_SETCHECK,
1290 (di->config.history_mode) ? BST_CHECKED : BST_UNCHECKED, 0 );
1291 SendDlgItemMessageW( dialog, IDC_OPT_INSERT_MODE, BM_SETCHECK,
1292 (di->config.insert_mode) ? BST_CHECKED : BST_UNCHECKED, 0 );
1293 SendDlgItemMessageW( dialog, IDC_OPT_CONF_CTRL, BM_SETCHECK,
1294 (di->config.menu_mask & MK_CONTROL) ? BST_CHECKED : BST_UNCHECKED, 0 );
1295 SendDlgItemMessageW( dialog, IDC_OPT_CONF_SHIFT, BM_SETCHECK,
1296 (di->config.menu_mask & MK_SHIFT) ? BST_CHECKED : BST_UNCHECKED, 0 );
1297 SendDlgItemMessageW( dialog, IDC_OPT_QUICK_EDIT, BM_SETCHECK,
1298 (di->config.quick_edit) ? BST_CHECKED : BST_UNCHECKED, 0 );
1299 return FALSE; /* because we set the focus */
1301 case WM_COMMAND:
1302 break;
1304 case WM_NOTIFY:
1306 NMHDR *nmhdr = (NMHDR*)lparam;
1307 DWORD val;
1308 BOOL done;
1310 di = (struct dialog_info *)GetWindowLongPtrW( dialog, DWLP_USER );
1312 switch (nmhdr->code)
1314 case PSN_SETACTIVE:
1315 /* needed in propsheet to keep properly the selected radio button
1316 * otherwise, the focus would be set to the first tab stop in the
1317 * propsheet, which would always activate the first radio button
1319 if (IsDlgButtonChecked( dialog, IDC_OPT_CURSOR_SMALL ) == BST_CHECKED)
1320 idc = IDC_OPT_CURSOR_SMALL;
1321 else if (IsDlgButtonChecked( dialog, IDC_OPT_CURSOR_MEDIUM ) == BST_CHECKED)
1322 idc = IDC_OPT_CURSOR_MEDIUM;
1323 else
1324 idc = IDC_OPT_CURSOR_LARGE;
1325 PostMessageW( dialog, WM_NEXTDLGCTL, (WPARAM)GetDlgItem( dialog, idc ), TRUE );
1326 di->dialog = dialog;
1327 break;
1328 case PSN_APPLY:
1329 if (IsDlgButtonChecked( dialog, IDC_OPT_CURSOR_SMALL ) == BST_CHECKED) val = 25;
1330 else if (IsDlgButtonChecked( dialog, IDC_OPT_CURSOR_MEDIUM ) == BST_CHECKED) val = 50;
1331 else val = 100;
1332 di->config.cursor_size = val;
1334 val = GetDlgItemInt( dialog, IDC_OPT_HIST_SIZE, &done, FALSE );
1335 if (done) di->config.history_size = val;
1337 val = (IsDlgButtonChecked( dialog, IDC_OPT_HIST_NODOUBLE ) & BST_CHECKED) != 0;
1338 di->config.history_mode = val;
1340 val = (IsDlgButtonChecked( dialog, IDC_OPT_INSERT_MODE ) & BST_CHECKED) != 0;
1341 di->config.insert_mode = val;
1343 val = 0;
1344 if (IsDlgButtonChecked( dialog, IDC_OPT_CONF_CTRL ) & BST_CHECKED) val |= MK_CONTROL;
1345 if (IsDlgButtonChecked( dialog, IDC_OPT_CONF_SHIFT ) & BST_CHECKED) val |= MK_SHIFT;
1346 di->config.menu_mask = val;
1348 val = (IsDlgButtonChecked( dialog, IDC_OPT_QUICK_EDIT ) & BST_CHECKED) != 0;
1349 di->config.quick_edit = val;
1351 SetWindowLongPtrW( dialog, DWLP_MSGRESULT, PSNRET_NOERROR );
1352 return TRUE;
1353 default:
1354 return FALSE;
1356 break;
1358 default:
1359 return FALSE;
1361 return TRUE;
1364 static COLORREF get_color( struct dialog_info *di, unsigned int idc )
1366 LONG_PTR index;
1368 index = GetWindowLongPtrW(GetDlgItem( di->dialog, idc ), 0);
1369 return di->config.color_map[index];
1372 /* window proc for font previewer in font property sheet */
1373 static LRESULT WINAPI font_preview_proc( HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam )
1375 switch (msg)
1377 case WM_CREATE:
1378 SetWindowLongPtrW( hwnd, 0, 0 );
1379 break;
1381 case WM_GETFONT:
1382 return GetWindowLongPtrW( hwnd, 0 );
1384 case WM_SETFONT:
1385 SetWindowLongPtrW( hwnd, 0, wparam );
1386 if (LOWORD(lparam))
1388 InvalidateRect( hwnd, NULL, TRUE );
1389 UpdateWindow( hwnd );
1391 break;
1393 case WM_DESTROY:
1395 HFONT font = (HFONT)GetWindowLongPtrW( hwnd, 0 );
1396 if (font) DeleteObject( font );
1397 break;
1400 case WM_PAINT:
1402 struct dialog_info *di;
1403 HFONT font, old_font;
1404 PAINTSTRUCT ps;
1406 di = (struct dialog_info *)GetWindowLongPtrW( GetParent( hwnd ), DWLP_USER );
1407 BeginPaint( hwnd, &ps );
1409 font = (HFONT)GetWindowLongPtrW( hwnd, 0 );
1410 if (font)
1412 static const WCHAR ascii[] = L"ASCII: abcXYZ";
1413 COLORREF bkcolor;
1414 WCHAR buf[256];
1415 int len;
1417 old_font = SelectObject( ps.hdc, font );
1418 bkcolor = get_color( di, IDC_FNT_COLOR_BK );
1419 FillRect( ps.hdc, &ps.rcPaint, CreateSolidBrush( bkcolor ));
1420 SetBkColor( ps.hdc, bkcolor );
1421 SetTextColor( ps.hdc, get_color( di, IDC_FNT_COLOR_FG ));
1422 len = LoadStringW( GetModuleHandleW(NULL), IDS_FNT_PREVIEW, buf, ARRAY_SIZE(buf) );
1423 if (len) TextOutW( ps.hdc, 0, 0, buf, len );
1424 TextOutW( ps.hdc, 0, di->config.cell_height, ascii, ARRAY_SIZE(ascii) - 1 );
1425 SelectObject( ps.hdc, old_font );
1427 EndPaint( hwnd, &ps );
1428 break;
1431 default:
1432 return DefWindowProcW( hwnd, msg, wparam, lparam );
1434 return 0;
1437 /* window proc for color previewer */
1438 static LRESULT WINAPI color_preview_proc( HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam )
1440 switch (msg)
1442 case WM_PAINT:
1444 struct dialog_info *di;
1445 PAINTSTRUCT ps;
1446 RECT client, r;
1447 int i, step;
1448 HBRUSH brush;
1450 BeginPaint( hwnd, &ps );
1451 GetClientRect( hwnd, &client );
1452 step = client.right / 8;
1454 di = (struct dialog_info *)GetWindowLongPtrW( GetParent(hwnd), DWLP_USER );
1456 for (i = 0; i < 16; i++)
1458 r.top = (i / 8) * (client.bottom / 2);
1459 r.bottom = r.top + client.bottom / 2;
1460 r.left = (i & 7) * step;
1461 r.right = r.left + step;
1462 brush = CreateSolidBrush( di->config.color_map[i] );
1463 FillRect( ps.hdc, &r, brush );
1464 DeleteObject( brush );
1465 if (GetWindowLongW( hwnd, 0 ) == i)
1467 HPEN old_pen;
1468 int i = 2;
1470 old_pen = SelectObject( ps.hdc, GetStockObject( WHITE_PEN ));
1471 r.right--; r.bottom--;
1472 for (;;)
1474 MoveToEx( ps.hdc, r.left, r.bottom, NULL );
1475 LineTo( ps.hdc, r.left, r.top );
1476 LineTo( ps.hdc, r.right, r.top );
1477 SelectObject( ps.hdc, GetStockObject( BLACK_PEN ));
1478 LineTo( ps.hdc, r.right, r.bottom );
1479 LineTo( ps.hdc, r.left, r.bottom );
1480 if (--i == 0) break;
1481 r.left++; r.top++; r.right--; r.bottom--;
1482 SelectObject( ps.hdc, GetStockObject( WHITE_PEN ));
1484 SelectObject( ps.hdc, old_pen );
1487 EndPaint( hwnd, &ps );
1488 break;
1491 case WM_LBUTTONDOWN:
1493 int i, step;
1494 RECT client;
1496 GetClientRect( hwnd, &client );
1497 step = client.right / 8;
1498 i = (HIWORD(lparam) >= client.bottom / 2) ? 8 : 0;
1499 i += LOWORD(lparam) / step;
1500 SetWindowLongW( hwnd, 0, i );
1501 InvalidateRect( GetDlgItem( GetParent( hwnd ), IDC_FNT_PREVIEW ), NULL, FALSE );
1502 InvalidateRect( hwnd, NULL, FALSE );
1503 break;
1506 default:
1507 return DefWindowProcW( hwnd, msg, wparam, lparam );
1509 return 0;
1512 static BOOL select_font( struct dialog_info *di )
1514 int font_idx, size_idx;
1515 WCHAR face_name[LF_FACESIZE], height_buf[4];
1516 size_t len;
1517 unsigned int font_height;
1518 LOGFONTW lf;
1519 HFONT font, old_font;
1520 DWORD_PTR args[2];
1521 WCHAR buf[256];
1522 WCHAR fmt[128];
1524 font_idx = SendDlgItemMessageW( di->dialog, IDC_FNT_LIST_FONT, LB_GETCURSEL, 0, 0 );
1525 size_idx = SendDlgItemMessageW( di->dialog, IDC_FNT_LIST_SIZE, LB_GETCURSEL, 0, 0 );
1527 if (font_idx < 0 || size_idx < 0)
1528 return FALSE;
1530 len = SendDlgItemMessageW( di->dialog, IDC_FNT_LIST_FONT, LB_GETTEXT, font_idx, (LPARAM)&face_name );
1531 SendDlgItemMessageW( di->dialog, IDC_FNT_LIST_SIZE, LB_GETTEXT, size_idx, (LPARAM)&height_buf );
1532 font_height = _wtoi( height_buf );
1534 fill_logfont( &lf, face_name, len * sizeof(WCHAR), font_height, FW_NORMAL );
1535 font = select_font_config( &di->config, di->console->output_cp, di->console->win, &lf );
1536 if (!font) return FALSE;
1538 if (di->config.cell_height != font_height)
1539 TRACE( "mismatched heights (%u<>%u)\n", di->config.cell_height, font_height );
1541 old_font = (HFONT)SendDlgItemMessageW( di->dialog, IDC_FNT_PREVIEW, WM_GETFONT, 0, 0 );
1542 SendDlgItemMessageW( di->dialog, IDC_FNT_PREVIEW, WM_SETFONT, (WPARAM)font, TRUE );
1543 if (old_font) DeleteObject( old_font );
1545 LoadStringW( GetModuleHandleW(NULL), IDS_FNT_DISPLAY, fmt, ARRAY_SIZE(fmt) );
1546 args[0] = di->config.cell_width;
1547 args[1] = di->config.cell_height;
1548 FormatMessageW( FORMAT_MESSAGE_FROM_STRING|FORMAT_MESSAGE_ARGUMENT_ARRAY,
1549 fmt, 0, 0, buf, ARRAY_SIZE(buf), (__ms_va_list*)args );
1551 SendDlgItemMessageW( di->dialog, IDC_FNT_FONT_INFO, WM_SETTEXT, 0, (LPARAM)buf );
1552 return TRUE;
1555 static BOOL fill_list_size( struct dialog_info *di, BOOL init )
1557 if (init)
1559 static const int sizes[] = {8,9,10,11,12,14,16,18,20,22,24,26,28,36,48,72};
1560 unsigned int i, idx = 4;
1561 WCHAR buf[4];
1563 for (i = 0; i < ARRAY_SIZE(sizes); i++)
1565 wsprintfW( buf, L"%u", sizes[i] );
1566 SendDlgItemMessageW( di->dialog, IDC_FNT_LIST_SIZE, LB_INSERTSTRING, -1, (LPARAM)buf );
1568 if (di->config.cell_height == sizes[i]) idx = i;
1571 SendDlgItemMessageW( di->dialog, IDC_FNT_LIST_SIZE, LB_SETCURSEL, idx, 0 );
1574 select_font( di );
1576 return TRUE;
1579 static int CALLBACK enum_list_font_proc( const LOGFONTW *lf, const TEXTMETRICW *tm,
1580 DWORD font_type, LPARAM lparam )
1582 struct dialog_info *di = (struct dialog_info *)lparam;
1584 if (font_type != TRUETYPE_FONTTYPE) return 1;
1586 TRACE( "%s\n", debugstr_logfont( lf, font_type ));
1588 if (validate_font( di->console, lf, 0 ))
1589 SendDlgItemMessageW( di->dialog, IDC_FNT_LIST_FONT, LB_ADDSTRING, 0, (LPARAM)lf->lfFaceName );
1591 return 1;
1594 static BOOL fill_list_font( struct dialog_info *di )
1596 LOGFONTW lf;
1598 memset( &lf, 0, sizeof(lf) );
1599 lf.lfCharSet = DEFAULT_CHARSET;
1600 lf.lfFaceName[0] = 0;
1601 lf.lfPitchAndFamily = FIXED_PITCH | FF_MODERN;
1603 EnumFontFamiliesExW( di->console->window->mem_dc, &lf, enum_list_font_proc, (LPARAM)di, 0 );
1605 if (SendDlgItemMessageW( di->dialog, IDC_FNT_LIST_FONT, LB_SELECTSTRING,
1606 -1, (LPARAM)di->config.face_name ) == LB_ERR)
1607 SendDlgItemMessageW( di->dialog, IDC_FNT_LIST_FONT, LB_SETCURSEL, 0, 0 );
1609 fill_list_size( di, TRUE );
1611 return TRUE;
1614 /* dialog proc for the font property sheet */
1615 static INT_PTR WINAPI font_dialog_proc( HWND dialog, UINT msg, WPARAM wparam, LPARAM lparam )
1617 struct dialog_info *di;
1619 switch (msg)
1621 case WM_INITDIALOG:
1622 di = (struct dialog_info *)((PROPSHEETPAGEA*)lparam)->lParam;
1623 di->dialog = dialog;
1624 SetWindowLongPtrW( dialog, DWLP_USER, (DWORD_PTR)di );
1625 /* use default system font until user-selected font is applied */
1626 SendDlgItemMessageW( dialog, IDC_FNT_PREVIEW, WM_SETFONT, 0, 0 );
1627 fill_list_font( di );
1628 SetWindowLongW( GetDlgItem( dialog, IDC_FNT_COLOR_BK ), 0, (di->config.attr >> 4) & 0x0F );
1629 SetWindowLongW( GetDlgItem( dialog, IDC_FNT_COLOR_FG ), 0, di->config.attr & 0x0F );
1630 break;
1632 case WM_COMMAND:
1633 di = (struct dialog_info *)GetWindowLongPtrW( dialog, DWLP_USER );
1634 switch (LOWORD(wparam))
1636 case IDC_FNT_LIST_FONT:
1637 if (HIWORD(wparam) == LBN_SELCHANGE)
1638 fill_list_size( di, FALSE );
1639 break;
1640 case IDC_FNT_LIST_SIZE:
1641 if (HIWORD(wparam) == LBN_SELCHANGE)
1642 select_font( di );
1643 break;
1645 break;
1647 case WM_NOTIFY:
1649 NMHDR *nmhdr = (NMHDR*)lparam;
1650 DWORD val;
1652 di = (struct dialog_info*)GetWindowLongPtrW( dialog, DWLP_USER );
1653 switch (nmhdr->code)
1655 case PSN_SETACTIVE:
1656 di->dialog = dialog;
1657 break;
1658 case PSN_APPLY:
1659 val = (GetWindowLongW( GetDlgItem( dialog, IDC_FNT_COLOR_BK ), 0 ) << 4) |
1660 GetWindowLongW( GetDlgItem( dialog, IDC_FNT_COLOR_FG ), 0 );
1661 di->config.attr = val;
1662 SetWindowLongPtrW( dialog, DWLP_MSGRESULT, PSNRET_NOERROR );
1663 return TRUE;
1664 default:
1665 return FALSE;
1667 break;
1669 default:
1670 return FALSE;
1672 return TRUE;
1675 /* dialog proc for the config property sheet */
1676 static INT_PTR WINAPI config_dialog_proc( HWND dialog, UINT msg, WPARAM wparam, LPARAM lparam )
1678 struct dialog_info *di;
1679 int max_ud = 2000;
1681 switch (msg)
1683 case WM_INITDIALOG:
1684 di = (struct dialog_info *)((PROPSHEETPAGEA*)lparam)->lParam;
1685 di->dialog = dialog;
1687 SetWindowLongPtrW( dialog, DWLP_USER, (DWORD_PTR)di );
1688 SetDlgItemInt( dialog, IDC_CNF_SB_WIDTH, di->config.sb_width, FALSE );
1689 SetDlgItemInt( dialog, IDC_CNF_SB_HEIGHT, di->config.sb_height, FALSE );
1690 SetDlgItemInt( dialog, IDC_CNF_WIN_WIDTH, di->config.win_width, FALSE );
1691 SetDlgItemInt( dialog, IDC_CNF_WIN_HEIGHT, di->config.win_height, FALSE );
1693 SendMessageW( GetDlgItem(dialog, IDC_CNF_WIN_HEIGHT_UD), UDM_SETRANGE, 0, MAKELPARAM(max_ud, 0));
1694 SendMessageW( GetDlgItem(dialog, IDC_CNF_WIN_WIDTH_UD), UDM_SETRANGE, 0, MAKELPARAM(max_ud, 0));
1695 SendMessageW( GetDlgItem(dialog, IDC_CNF_SB_HEIGHT_UD), UDM_SETRANGE, 0, MAKELPARAM(max_ud, 0));
1696 SendMessageW( GetDlgItem(dialog, IDC_CNF_SB_WIDTH_UD), UDM_SETRANGE, 0, MAKELPARAM(max_ud, 0));
1698 SendDlgItemMessageW( dialog, IDC_CNF_CLOSE_EXIT, BM_SETCHECK, BST_CHECKED, 0 );
1700 SendDlgItemMessageW( dialog, IDC_CNF_EDITION_MODE, CB_ADDSTRING, 0, (LPARAM)L"Win32" );
1701 SendDlgItemMessageW( dialog, IDC_CNF_EDITION_MODE, CB_ADDSTRING, 0, (LPARAM)L"Emacs" );
1702 SendDlgItemMessageW( dialog, IDC_CNF_EDITION_MODE, CB_SETCURSEL, di->config.edition_mode, 0 );
1703 break;
1705 case WM_NOTIFY:
1707 NMHDR *nmhdr = (NMHDR*)lparam;
1708 int win_w, win_h, sb_w, sb_h;
1709 BOOL st1, st2;
1711 di = (struct dialog_info *)GetWindowLongPtrW( dialog, DWLP_USER );
1712 switch (nmhdr->code)
1714 case PSN_SETACTIVE:
1715 di->dialog = dialog;
1716 break;
1717 case PSN_APPLY:
1718 sb_w = GetDlgItemInt( dialog, IDC_CNF_SB_WIDTH, &st1, FALSE );
1719 sb_h = GetDlgItemInt( dialog, IDC_CNF_SB_HEIGHT, &st2, FALSE );
1720 if (!st1 || ! st2)
1722 SetWindowLongPtrW( dialog, DWLP_MSGRESULT, PSNRET_INVALID );
1723 return TRUE;
1725 win_w = GetDlgItemInt( dialog, IDC_CNF_WIN_WIDTH, &st1, FALSE );
1726 win_h = GetDlgItemInt( dialog, IDC_CNF_WIN_HEIGHT, &st2, FALSE );
1727 if (!st1 || !st2)
1729 SetWindowLongPtrW( dialog, DWLP_MSGRESULT, PSNRET_INVALID );
1730 return TRUE;
1732 if (win_w > sb_w || win_h > sb_h)
1734 WCHAR cap[256];
1735 WCHAR txt[256];
1737 LoadStringW( GetModuleHandleW(NULL), IDS_DLG_TIT_ERROR, cap, ARRAY_SIZE(cap) );
1738 LoadStringW( GetModuleHandleW(NULL), IDS_DLG_ERR_SBWINSIZE, txt, ARRAY_SIZE(txt) );
1740 MessageBoxW( dialog, txt, cap, MB_OK );
1741 SetWindowLongPtrW( dialog, DWLP_MSGRESULT, PSNRET_INVALID );
1742 return TRUE;
1744 di->config.win_width = win_w;
1745 di->config.win_height = win_h;
1746 di->config.sb_width = sb_w;
1747 di->config.sb_height = sb_h;
1749 di->config.edition_mode = SendDlgItemMessageW( dialog, IDC_CNF_EDITION_MODE,
1750 CB_GETCURSEL, 0, 0 );
1751 SetWindowLongPtrW( dialog, DWLP_MSGRESULT, PSNRET_NOERROR );
1752 return TRUE;
1753 default:
1754 return FALSE;
1756 break;
1758 default:
1759 return FALSE;
1761 return TRUE;
1764 static void apply_config( struct console *console, const struct console_config *config )
1766 if (console->active->width != config->sb_width || console->active->height != config->sb_height)
1767 change_screen_buffer_size( console->active, config->sb_width, config->sb_height );
1769 console->window->menu_mask = config->menu_mask;
1770 console->window->quick_edit = config->quick_edit;
1772 console->edition_mode = config->edition_mode;
1773 console->history_mode = config->history_mode;
1775 if (console->history_size != config->history_size)
1777 struct history_line **mem = NULL;
1778 int i, delta;
1780 if (config->history_size && (mem = malloc( config->history_size * sizeof(*mem) )))
1782 memset( mem, 0, config->history_size * sizeof(*mem) );
1784 delta = (console->history_index > config->history_size)
1785 ? (console->history_index - config->history_size) : 0;
1787 for (i = delta; i < console->history_index; i++)
1789 mem[i - delta] = console->history[i];
1790 console->history[i] = NULL;
1792 console->history_index -= delta;
1794 for (i = 0; i < console->history_size; i++)
1795 free( console->history[i] );
1796 free( console->history );
1797 console->history = mem;
1798 console->history_size = config->history_size;
1802 if (config->insert_mode)
1803 console->mode |= ENABLE_INSERT_MODE|ENABLE_EXTENDED_FLAGS;
1804 else
1805 console->mode &= ~ENABLE_INSERT_MODE;
1807 console->active->cursor_size = config->cursor_size;
1808 console->active->cursor_visible = config->cursor_visible;
1809 console->active->attr = config->attr;
1810 console->active->popup_attr = config->popup_attr;
1811 console->active->win.left = config->win_pos.X;
1812 console->active->win.top = config->win_pos.Y;
1813 console->active->win.right = config->win_pos.X + config->win_width - 1;
1814 console->active->win.bottom = config->win_pos.Y + config->win_height - 1;
1815 memcpy( console->active->color_map, config->color_map, sizeof(config->color_map) );
1817 if (console->active->font.width != config->cell_width ||
1818 console->active->font.height != config->cell_height ||
1819 console->active->font.weight != config->font_weight ||
1820 console->active->font.pitch_family != config->font_pitch_family ||
1821 console->active->font.face_len != wcslen( config->face_name ) ||
1822 memcmp( console->active->font.face_name, config->face_name,
1823 console->active->font.face_len * sizeof(WCHAR) ))
1825 update_console_font( console, config->face_name, wcslen(config->face_name) * sizeof(WCHAR),
1826 config->cell_height, config->font_weight );
1829 update_window( console );
1831 notify_screen_buffer_size( console->active );
1834 static void current_config( struct console *console, struct console_config *config )
1836 size_t len;
1838 config->menu_mask = console->window->menu_mask;
1839 config->quick_edit = console->window->quick_edit;
1841 config->edition_mode = console->edition_mode;
1842 config->history_mode = console->history_mode;
1843 config->history_size = console->history_size;
1845 config->insert_mode = (console->mode & (ENABLE_INSERT_MODE|ENABLE_EXTENDED_FLAGS)) ==
1846 (ENABLE_INSERT_MODE|ENABLE_EXTENDED_FLAGS);
1848 config->cursor_size = console->active->cursor_size;
1849 config->cursor_visible = console->active->cursor_visible;
1850 config->attr = console->active->attr;
1851 config->popup_attr = console->active->popup_attr;
1852 memcpy( config->color_map, console->active->color_map, sizeof(config->color_map) );
1854 config->cell_width = console->active->font.width;
1855 config->cell_height = console->active->font.height;
1856 config->font_weight = console->active->font.weight;
1857 config->font_pitch_family = console->active->font.pitch_family;
1858 len = min( ARRAY_SIZE(config->face_name) - 1, console->active->font.face_len );
1859 if (len) memcpy( config->face_name, console->active->font.face_name, len * sizeof(WCHAR) );
1860 config->face_name[len] = 0;
1862 config->sb_width = console->active->width;
1863 config->sb_height = console->active->height;
1865 config->win_width = console->active->win.right - console->active->win.left + 1;
1866 config->win_height = console->active->win.bottom - console->active->win.top + 1;
1867 config->win_pos.X = console->active->win.left;
1868 config->win_pos.Y = console->active->win.top;
1871 /* run the dialog box to set up the console options */
1872 static BOOL config_dialog( struct console *console, BOOL current )
1874 struct console_config prev_config;
1875 struct dialog_info di;
1876 PROPSHEETHEADERW header;
1877 HPROPSHEETPAGE pages[3];
1878 PROPSHEETPAGEW psp;
1879 WNDCLASSW wndclass;
1880 WCHAR buff[256];
1882 InitCommonControls();
1884 memset( &di, 0, sizeof(di) );
1885 di.console = console;
1887 if (current)
1888 current_config( console, &di.config );
1889 else
1890 load_config( NULL, &di.config );
1892 prev_config = di.config;
1894 wndclass.style = 0;
1895 wndclass.lpfnWndProc = font_preview_proc;
1896 wndclass.cbClsExtra = 0;
1897 wndclass.cbWndExtra = sizeof(HFONT);
1898 wndclass.hInstance = GetModuleHandleW( NULL );
1899 wndclass.hIcon = 0;
1900 wndclass.hCursor = LoadCursorW( 0, (const WCHAR *)IDC_ARROW );
1901 wndclass.hbrBackground = GetStockObject( BLACK_BRUSH );
1902 wndclass.lpszMenuName = NULL;
1903 wndclass.lpszClassName = L"WineConFontPreview";
1904 RegisterClassW( &wndclass );
1906 wndclass.style = 0;
1907 wndclass.lpfnWndProc = color_preview_proc;
1908 wndclass.cbClsExtra = 0;
1909 wndclass.cbWndExtra = sizeof(DWORD);
1910 wndclass.hInstance = GetModuleHandleW( NULL );
1911 wndclass.hIcon = 0;
1912 wndclass.hCursor = LoadCursorW( 0, (const WCHAR *)IDC_ARROW );
1913 wndclass.hbrBackground = GetStockObject( BLACK_BRUSH );
1914 wndclass.lpszMenuName = NULL;
1915 wndclass.lpszClassName = L"WineConColorPreview";
1916 RegisterClassW( &wndclass );
1918 memset( &psp, 0, sizeof(psp) );
1919 psp.dwSize = sizeof(psp);
1920 psp.dwFlags = 0;
1921 psp.hInstance = wndclass.hInstance;
1922 psp.lParam = (LPARAM)&di;
1924 psp.u.pszTemplate = MAKEINTRESOURCEW(IDD_OPTION);
1925 psp.pfnDlgProc = option_dialog_proc;
1926 pages[0] = CreatePropertySheetPageW( &psp );
1928 psp.u.pszTemplate = MAKEINTRESOURCEW(IDD_FONT);
1929 psp.pfnDlgProc = font_dialog_proc;
1930 pages[1] = CreatePropertySheetPageW( &psp );
1932 psp.u.pszTemplate = MAKEINTRESOURCEW(IDD_CONFIG);
1933 psp.pfnDlgProc = config_dialog_proc;
1934 pages[2] = CreatePropertySheetPageW( &psp );
1936 memset( &header, 0, sizeof(header) );
1937 header.dwSize = sizeof(header);
1939 if (!LoadStringW( GetModuleHandleW( NULL ),
1940 current ? IDS_DLG_TIT_CURRENT : IDS_DLG_TIT_DEFAULT,
1941 buff, ARRAY_SIZE(buff) ))
1942 wcscpy( buff, L"Setup" );
1944 header.pszCaption = buff;
1945 header.nPages = 3;
1946 header.hwndParent = console->win;
1947 header.u3.phpage = pages;
1948 header.dwFlags = PSH_NOAPPLYNOW;
1949 if (PropertySheetW( &header ) < 1)
1950 return TRUE;
1952 if (!memcmp( &prev_config, &di.config, sizeof(prev_config) ))
1953 return TRUE;
1955 TRACE( "%s\n", debugstr_config(&di.config) );
1957 if (current)
1959 apply_config( console, &di.config );
1960 update_window( di.console );
1963 save_config( current ? console->window->config_key : NULL, &di.config );
1965 return TRUE;
1968 static void resize_window( struct console *console, int width, int height )
1970 struct console_config config;
1972 current_config( console, &config );
1973 config.win_width = width;
1974 config.win_height = height;
1976 /* auto size screen-buffer if it's now smaller than window */
1977 if (config.sb_width < config.win_width)
1978 config.sb_width = config.win_width;
1979 if (config.sb_height < config.win_height)
1980 config.sb_height = config.win_height;
1982 /* and reset window pos so that we don't display outside of the screen-buffer */
1983 if (config.win_pos.X + config.win_width > config.sb_width)
1984 config.win_pos.X = config.sb_width - config.win_width;
1985 if (config.win_pos.Y + config.win_height > config.sb_height)
1986 config.win_pos.Y = config.sb_height - config.win_height;
1988 apply_config( console, &config );
1991 /* grays / ungrays the menu items according to their state */
1992 static void set_menu_details( struct console *console, HMENU menu )
1994 EnableMenuItem( menu, IDS_COPY, MF_BYCOMMAND |
1995 (console->window->in_selection ? MF_ENABLED : MF_GRAYED) );
1996 EnableMenuItem( menu, IDS_PASTE, MF_BYCOMMAND |
1997 (IsClipboardFormatAvailable(CF_UNICODETEXT) ? MF_ENABLED : MF_GRAYED) );
1998 EnableMenuItem( menu, IDS_SCROLL, MF_BYCOMMAND | MF_GRAYED );
1999 EnableMenuItem( menu, IDS_SEARCH, MF_BYCOMMAND | MF_GRAYED );
2002 static BOOL fill_menu( HMENU menu, BOOL sep )
2004 HINSTANCE module = GetModuleHandleW( NULL );
2005 HMENU sub_menu;
2006 WCHAR buff[256];
2008 if (!menu) return FALSE;
2010 sub_menu = CreateMenu();
2011 if (!sub_menu) return FALSE;
2013 LoadStringW( module, IDS_MARK, buff, ARRAY_SIZE(buff) );
2014 InsertMenuW( sub_menu, -1, MF_BYPOSITION|MF_STRING, IDS_MARK, buff );
2015 LoadStringW( module, IDS_COPY, buff, ARRAY_SIZE(buff) );
2016 InsertMenuW( sub_menu, -1, MF_BYPOSITION|MF_STRING, IDS_COPY, buff );
2017 LoadStringW( module, IDS_PASTE, buff, ARRAY_SIZE(buff) );
2018 InsertMenuW( sub_menu, -1, MF_BYPOSITION|MF_STRING, IDS_PASTE, buff );
2019 LoadStringW( module, IDS_SELECTALL, buff, ARRAY_SIZE(buff) );
2020 InsertMenuW( sub_menu, -1, MF_BYPOSITION|MF_STRING, IDS_SELECTALL, buff );
2021 LoadStringW( module, IDS_SCROLL, buff, ARRAY_SIZE(buff) );
2022 InsertMenuW( sub_menu, -1, MF_BYPOSITION|MF_STRING, IDS_SCROLL, buff );
2023 LoadStringW( module, IDS_SEARCH, buff, ARRAY_SIZE(buff) );
2024 InsertMenuW( sub_menu, -1, MF_BYPOSITION|MF_STRING, IDS_SEARCH, buff );
2026 if (sep) InsertMenuW( menu, -1, MF_BYPOSITION|MF_SEPARATOR, 0, NULL );
2027 LoadStringW( module, IDS_EDIT, buff, ARRAY_SIZE(buff) );
2028 InsertMenuW( menu, -1, MF_BYPOSITION|MF_STRING|MF_POPUP, (UINT_PTR)sub_menu, buff );
2029 LoadStringW( module, IDS_DEFAULT, buff, ARRAY_SIZE(buff) );
2030 InsertMenuW( menu, -1, MF_BYPOSITION|MF_STRING, IDS_DEFAULT, buff );
2031 LoadStringW( module, IDS_PROPERTIES, buff, ARRAY_SIZE(buff) );
2032 InsertMenuW( menu, -1, MF_BYPOSITION|MF_STRING, IDS_PROPERTIES, buff );
2034 return TRUE;
2037 static LRESULT window_create( HWND hwnd, const CREATESTRUCTW *create )
2039 struct console *console = create->lpCreateParams;
2040 HMENU sys_menu;
2042 TRACE( "%p\n", hwnd );
2044 SetWindowLongPtrW( hwnd, 0, (DWORD_PTR)console );
2045 console->win = hwnd;
2047 if (console->window)
2049 sys_menu = GetSystemMenu( hwnd, FALSE );
2050 if (!sys_menu) return 0;
2051 console->window->popup_menu = CreatePopupMenu();
2052 if (!console->window->popup_menu) return 0;
2054 fill_menu( sys_menu, TRUE );
2055 fill_menu( console->window->popup_menu, FALSE );
2057 console->window->mem_dc = CreateCompatibleDC( 0 );
2059 return 0;
2062 static LRESULT WINAPI window_proc( HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam )
2064 struct console *console = (struct console *)GetWindowLongPtrW( hwnd, 0 );
2066 switch (msg)
2068 case WM_CREATE:
2069 return window_create( hwnd, (const CREATESTRUCTW *)lparam );
2071 case WM_DESTROY:
2072 console->win = NULL;
2073 PostQuitMessage( 0 );
2074 break;
2076 case WM_TIMER:
2077 case WM_UPDATE_CONFIG:
2078 if (console->window && console->window->update_state == UPDATE_PENDING)
2079 update_window( console );
2080 break;
2082 case WM_PAINT:
2084 PAINTSTRUCT ps;
2086 if (!console->window) break;
2088 BeginPaint( console->win, &ps );
2089 BitBlt( ps.hdc, 0, 0,
2090 (console->active->win.right - console->active->win.left + 1) * console->active->font.width,
2091 (console->active->win.bottom - console->active->win.top + 1) * console->active->font.height,
2092 console->window->mem_dc,
2093 console->active->win.left * console->active->font.width,
2094 console->active->win.top * console->active->font.height,
2095 SRCCOPY );
2096 if (console->window->in_selection) update_selection( console, ps.hdc );
2097 EndPaint( console->win, &ps );
2098 break;
2101 case WM_SHOWWINDOW:
2102 if (!console->window) break;
2103 if (wparam)
2104 update_window( console );
2105 else
2107 if (console->window->bitmap) DeleteObject( console->window->bitmap );
2108 console->window->bitmap = NULL;
2110 break;
2112 case WM_KEYDOWN:
2113 case WM_KEYUP:
2114 if (console->window && console->window->in_selection)
2115 handle_selection_key( console, msg == WM_KEYDOWN, wparam, lparam );
2116 else
2117 record_key_input( console, msg == WM_KEYDOWN, wparam, lparam );
2118 break;
2120 case WM_SYSKEYDOWN:
2121 case WM_SYSKEYUP:
2122 record_key_input( console, msg == WM_SYSKEYDOWN, wparam, lparam );
2123 break;
2125 case WM_LBUTTONDOWN:
2126 if (console->window && (console->window->quick_edit || console->window->in_selection))
2128 if (console->window->in_selection)
2129 update_selection( console, 0 );
2131 if (console->window->quick_edit && console->window->in_selection)
2133 console->window->in_selection = FALSE;
2135 else
2137 console->window->selection_end = get_cell( console, lparam );
2138 console->window->selection_start = console->window->selection_end;
2139 SetCapture( console->win );
2140 update_selection( console, 0 );
2141 console->window->in_selection = TRUE;
2144 else
2146 record_mouse_input( console, get_cell(console, lparam), wparam, 0 );
2148 break;
2150 case WM_MOUSEMOVE:
2151 if (console->window && (console->window->quick_edit || console->window->in_selection))
2153 if (GetCapture() == console->win && console->window->in_selection &&
2154 (wparam & MK_LBUTTON))
2156 move_selection( console, console->window->selection_start,
2157 get_cell(console, lparam) );
2160 else
2162 record_mouse_input( console, get_cell(console, lparam), wparam, MOUSE_MOVED );
2164 break;
2166 case WM_LBUTTONUP:
2167 if (console->window && (console->window->quick_edit || console->window->in_selection))
2169 if (GetCapture() == console->win && console->window->in_selection)
2171 move_selection( console, console->window->selection_start,
2172 get_cell(console, lparam) );
2173 ReleaseCapture();
2176 else
2178 record_mouse_input( console, get_cell(console, lparam), wparam, 0 );
2180 break;
2182 case WM_RBUTTONDOWN:
2183 if (console->window && (wparam & (MK_CONTROL|MK_SHIFT)) == console->window->menu_mask)
2185 POINT pt;
2186 pt.x = (short)LOWORD(lparam);
2187 pt.y = (short)HIWORD(lparam);
2188 ClientToScreen( hwnd, &pt );
2189 set_menu_details( console, console->window->popup_menu );
2190 TrackPopupMenu( console->window->popup_menu, TPM_LEFTALIGN|TPM_TOPALIGN|TPM_RIGHTBUTTON,
2191 pt.x, pt.y, 0, hwnd, NULL );
2193 else
2195 record_mouse_input( console, get_cell(console, lparam), wparam, 0 );
2197 break;
2199 case WM_RBUTTONUP:
2200 /* no need to track for rbutton up when opening the popup... the event will be
2201 * swallowed by TrackPopupMenu */
2202 case WM_MBUTTONDOWN:
2203 case WM_MBUTTONUP:
2204 record_mouse_input( console, get_cell(console, lparam), wparam, 0 );
2205 break;
2207 case WM_LBUTTONDBLCLK:
2208 case WM_MBUTTONDBLCLK:
2209 case WM_RBUTTONDBLCLK:
2210 record_mouse_input( console, get_cell(console, lparam), wparam, DOUBLE_CLICK );
2211 break;
2213 case WM_SETFOCUS:
2214 if (console->window && console->active->cursor_visible)
2216 CreateCaret( console->win, console->window->cursor_bitmap,
2217 console->active->font.width, console->active->font.height );
2218 update_window_cursor( console );
2220 break;
2222 case WM_KILLFOCUS:
2223 if (console->window && console->active->cursor_visible)
2224 DestroyCaret();
2225 break;
2227 case WM_SIZE:
2228 if (console->window && console->window->update_state != UPDATE_BUSY)
2229 resize_window( console,
2230 max( LOWORD(lparam) / console->active->font.width, 20 ),
2231 max( HIWORD(lparam) / console->active->font.height, 20 ));
2232 break;
2234 case WM_HSCROLL:
2236 int win_width = console->active->win.right - console->active->win.left + 1;
2237 int x = console->active->win.left;
2239 if (!console->window) break;
2240 switch (LOWORD(wparam))
2242 case SB_PAGEUP: x -= 8; break;
2243 case SB_PAGEDOWN: x += 8; break;
2244 case SB_LINEUP: x--; break;
2245 case SB_LINEDOWN: x++; break;
2246 case SB_THUMBTRACK: x = HIWORD(wparam); break;
2247 default: break;
2249 x = min( max( x, 0 ), console->active->width - win_width );
2250 if (x != console->active->win.left)
2252 console->active->win.left = x;
2253 console->active->win.right = x + win_width - 1;
2254 update_window( console );
2256 break;
2259 case WM_MOUSEWHEEL:
2260 if (console->active->height <= console->active->win.bottom - console->active->win.top + 1)
2262 record_mouse_input(console, get_cell(console, lparam), wparam, MOUSE_WHEELED);
2263 break;
2265 /* else fallthrough */
2266 case WM_VSCROLL:
2268 int win_height = console->active->win.bottom - console->active->win.top + 1;
2269 int y = console->active->win.top;
2271 if (!console->window) break;
2273 if (msg == WM_MOUSEWHEEL)
2275 UINT scroll_lines = 3;
2276 SystemParametersInfoW( SPI_GETWHEELSCROLLLINES, 0, &scroll_lines, 0 );
2277 scroll_lines *= -GET_WHEEL_DELTA_WPARAM(wparam) / WHEEL_DELTA;
2278 y += scroll_lines;
2280 else
2282 switch (LOWORD(wparam))
2284 case SB_PAGEUP: y -= 8; break;
2285 case SB_PAGEDOWN: y += 8; break;
2286 case SB_LINEUP: y--; break;
2287 case SB_LINEDOWN: y++; break;
2288 case SB_THUMBTRACK: y = HIWORD(wparam); break;
2289 default: break;
2293 y = min( max( y, 0 ), console->active->height - win_height );
2294 if (y != console->active->win.top)
2296 console->active->win.top = y;
2297 console->active->win.bottom = y + win_height - 1;
2298 update_window( console );
2300 break;
2303 case WM_SYSCOMMAND:
2304 if (!console->window) break;
2305 switch (wparam)
2307 case IDS_DEFAULT:
2308 config_dialog( console, FALSE );
2309 break;
2310 case IDS_PROPERTIES:
2311 config_dialog( console, TRUE );
2312 break;
2313 default:
2314 return DefWindowProcW( hwnd, msg, wparam, lparam );
2316 break;
2318 case WM_COMMAND:
2319 if (!console->window) break;
2320 switch (wparam)
2322 case IDS_DEFAULT:
2323 config_dialog( console, FALSE );
2324 break;
2325 case IDS_PROPERTIES:
2326 config_dialog( console, TRUE );
2327 break;
2328 case IDS_MARK:
2329 console->window->selection_start.X = console->window->selection_start.Y = 0;
2330 console->window->selection_end.X = console->window->selection_end.Y = 0;
2331 update_selection( console, 0 );
2332 console->window->in_selection = TRUE;
2333 break;
2334 case IDS_COPY:
2335 if (console->window->in_selection)
2337 console->window->in_selection = FALSE;
2338 update_selection( console, 0 );
2339 copy_selection( console );
2341 break;
2342 case IDS_PASTE:
2343 paste_clipboard( console );
2344 break;
2345 case IDS_SELECTALL:
2346 console->window->selection_start.X = console->window->selection_start.Y = 0;
2347 console->window->selection_end.X = console->active->width - 1;
2348 console->window->selection_end.Y = console->active->height - 1;
2349 update_selection( console, 0 );
2350 console->window->in_selection = TRUE;
2351 break;
2352 case IDS_SCROLL:
2353 case IDS_SEARCH:
2354 FIXME( "Unhandled yet command: %Ix\n", wparam );
2355 break;
2356 default:
2357 return DefWindowProcW( hwnd, msg, wparam, lparam );
2359 break;
2361 case WM_INITMENUPOPUP:
2362 if (!console->window || !HIWORD(lparam)) return DefWindowProcW( hwnd, msg, wparam, lparam );
2363 set_menu_details( console, GetSystemMenu(console->win, FALSE) );
2364 break;
2366 default:
2367 return DefWindowProcW( hwnd, msg, wparam, lparam );
2370 return 0;
2373 void update_window_config( struct console *console, BOOL delay )
2375 const int delay_timeout = 50;
2377 if (!console->window || console->window->update_state != UPDATE_NONE) return;
2378 console->window->update_state = UPDATE_PENDING;
2379 if (delay)
2380 SetTimer( console->win, 1, delay_timeout, NULL );
2381 else
2382 PostMessageW( console->win, WM_UPDATE_CONFIG, 0, 0 );
2385 void update_window_region( struct console *console, const RECT *update )
2387 RECT *window_rect = &console->window->update;
2388 window_rect->left = min( window_rect->left, update->left );
2389 window_rect->top = min( window_rect->top, update->top );
2390 window_rect->right = max( window_rect->right, update->right );
2391 window_rect->bottom = max( window_rect->bottom, update->bottom );
2392 update_window_config( console, TRUE );
2395 BOOL init_window( struct console *console )
2397 struct console_config config;
2398 WNDCLASSW wndclass;
2399 STARTUPINFOW si;
2400 CHARSETINFO ci;
2402 static struct console_window console_window;
2404 console->window = &console_window;
2405 if (!TranslateCharsetInfo( (DWORD *)(INT_PTR)GetACP(), &ci, TCI_SRCCODEPAGE ))
2406 return FALSE;
2408 console->window->ui_charset = ci.ciCharset;
2410 GetStartupInfoW(&si);
2411 if (si.lpTitle)
2413 size_t i, title_len = wcslen( si.lpTitle );
2414 if (!(console->window->config_key = malloc( (title_len + 1) * sizeof(WCHAR) )))
2415 return FALSE;
2416 for (i = 0; i < title_len; i++)
2417 console->window->config_key[i] = si.lpTitle[i] == '\\' ? '_' : si.lpTitle[i];
2418 console->window->config_key[title_len] = 0;
2421 load_config( console->window->config_key, &config );
2422 if (si.dwFlags & STARTF_USECOUNTCHARS)
2424 config.sb_width = si.dwXCountChars;
2425 config.sb_height = si.dwYCountChars;
2427 if (si.dwFlags & STARTF_USEFILLATTRIBUTE)
2428 config.attr = si.dwFillAttribute;
2430 wndclass.style = CS_DBLCLKS;
2431 wndclass.lpfnWndProc = window_proc;
2432 wndclass.cbClsExtra = 0;
2433 wndclass.cbWndExtra = sizeof(DWORD_PTR);
2434 wndclass.hInstance = GetModuleHandleW(NULL);
2435 wndclass.hIcon = LoadIconW( 0, (const WCHAR *)IDI_WINLOGO );
2436 wndclass.hCursor = LoadCursorW( 0, (const WCHAR *)IDC_ARROW );
2437 wndclass.hbrBackground = GetStockObject( BLACK_BRUSH );
2438 wndclass.lpszMenuName = NULL;
2439 wndclass.lpszClassName = L"WineConsoleClass";
2440 RegisterClassW(&wndclass);
2442 if (!CreateWindowW( wndclass.lpszClassName, NULL,
2443 WS_OVERLAPPED|WS_CAPTION|WS_SYSMENU|WS_THICKFRAME|WS_MINIMIZEBOX|
2444 WS_MAXIMIZEBOX|WS_HSCROLL|WS_VSCROLL, CW_USEDEFAULT, CW_USEDEFAULT,
2445 0, 0, 0, 0, wndclass.hInstance, console ))
2446 return FALSE;
2448 if (!config.face_name[0])
2449 set_first_font( console, &config );
2451 apply_config( console, &config );
2452 return TRUE;
2455 void init_message_window( struct console *console )
2457 WNDCLASSW wndclass;
2459 wndclass.style = CS_DBLCLKS;
2460 wndclass.lpfnWndProc = window_proc;
2461 wndclass.cbClsExtra = 0;
2462 wndclass.cbWndExtra = sizeof(DWORD_PTR);
2463 wndclass.hInstance = GetModuleHandleW( NULL );
2464 wndclass.hIcon = 0;
2465 wndclass.hCursor = 0;
2466 wndclass.hbrBackground = GetStockObject( BLACK_BRUSH );
2467 wndclass.lpszMenuName = NULL;
2468 wndclass.lpszClassName = L"WineConsoleClass";
2469 RegisterClassW(&wndclass);
2471 CreateWindowW( wndclass.lpszClassName, NULL,
2472 WS_OVERLAPPED|WS_CAPTION|WS_SYSMENU|WS_THICKFRAME|WS_MINIMIZEBOX|
2473 WS_MAXIMIZEBOX|WS_HSCROLL|WS_VSCROLL, CW_USEDEFAULT, CW_USEDEFAULT,
2474 0, 0, HWND_MESSAGE, 0, wndclass.hInstance, console );