include/mscvpdb.h: Use flexible array members for the rest of structures.
[wine.git] / programs / conhost / window.c
blob9817c5fdac988cdda1542cb5a5de815dda2b72b9
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 /* generate input_record from WM_CHAR message. */
1241 static void record_char_input( struct console *console, WCHAR ch, LPARAM lparam )
1243 INPUT_RECORD ir;
1244 SHORT sh = VkKeyScanW( ch );
1246 if (sh == ~0) return;
1247 ir.EventType = KEY_EVENT;
1248 ir.Event.KeyEvent.bKeyDown = TRUE;
1249 ir.Event.KeyEvent.wRepeatCount = 0;
1250 ir.Event.KeyEvent.wVirtualKeyCode = LOBYTE(sh);
1251 ir.Event.KeyEvent.wVirtualScanCode = MapVirtualKeyW( LOBYTE(sh), 0 );
1252 ir.Event.KeyEvent.uChar.UnicodeChar = ch;
1253 ir.Event.KeyEvent.dwControlKeyState = 0;
1254 if (lparam & (1u << 24)) ir.Event.KeyEvent.dwControlKeyState |= ENHANCED_KEY;
1256 write_console_input( console, &ir, 1, TRUE );
1259 static void record_mouse_input( struct console *console, COORD c, WPARAM wparam, DWORD event )
1261 BYTE key_state[256];
1262 INPUT_RECORD ir;
1264 /* MOUSE_EVENTs shouldn't be sent unless ENABLE_MOUSE_INPUT is active */
1265 if (!(console->mode & ENABLE_MOUSE_INPUT)) return;
1267 ir.EventType = MOUSE_EVENT;
1268 ir.Event.MouseEvent.dwMousePosition = c;
1269 ir.Event.MouseEvent.dwButtonState = 0;
1270 if (wparam & MK_LBUTTON) ir.Event.MouseEvent.dwButtonState |= FROM_LEFT_1ST_BUTTON_PRESSED;
1271 if (wparam & MK_MBUTTON) ir.Event.MouseEvent.dwButtonState |= FROM_LEFT_2ND_BUTTON_PRESSED;
1272 if (wparam & MK_RBUTTON) ir.Event.MouseEvent.dwButtonState |= RIGHTMOST_BUTTON_PRESSED;
1273 if (wparam & MK_CONTROL) ir.Event.MouseEvent.dwButtonState |= LEFT_CTRL_PRESSED;
1274 if (wparam & MK_SHIFT) ir.Event.MouseEvent.dwButtonState |= SHIFT_PRESSED;
1275 if (event == MOUSE_WHEELED) ir.Event.MouseEvent.dwButtonState |= wparam & 0xFFFF0000;
1276 ir.Event.MouseEvent.dwControlKeyState = get_ctrl_state( key_state );
1277 ir.Event.MouseEvent.dwEventFlags = event;
1279 write_console_input( console, &ir, 1, TRUE );
1282 struct dialog_info
1284 struct console *console;
1285 struct console_config config;
1286 HWND dialog; /* handle to active propsheet */
1289 /* dialog proc for the option property sheet */
1290 static INT_PTR WINAPI option_dialog_proc( HWND dialog, UINT msg, WPARAM wparam, LPARAM lparam )
1292 struct dialog_info *di;
1293 unsigned int idc;
1295 switch (msg)
1297 case WM_INITDIALOG:
1298 di = (struct dialog_info *)((PROPSHEETPAGEA *)lparam)->lParam;
1299 di->dialog = dialog;
1300 SetWindowLongPtrW( dialog, DWLP_USER, (LONG_PTR)di );
1302 SendMessageW( GetDlgItem( dialog, IDC_OPT_HIST_SIZE_UD ), UDM_SETRANGE, 0, MAKELPARAM(500, 0) );
1304 if (di->config.cursor_size <= 25) idc = IDC_OPT_CURSOR_SMALL;
1305 else if (di->config.cursor_size <= 50) idc = IDC_OPT_CURSOR_MEDIUM;
1306 else idc = IDC_OPT_CURSOR_LARGE;
1308 SendDlgItemMessageW( dialog, idc, BM_SETCHECK, BST_CHECKED, 0 );
1309 SetDlgItemInt( dialog, IDC_OPT_HIST_SIZE, di->config.history_size, FALSE );
1310 SendDlgItemMessageW( dialog, IDC_OPT_HIST_NODOUBLE, BM_SETCHECK,
1311 (di->config.history_mode) ? BST_CHECKED : BST_UNCHECKED, 0 );
1312 SendDlgItemMessageW( dialog, IDC_OPT_INSERT_MODE, BM_SETCHECK,
1313 (di->config.insert_mode) ? BST_CHECKED : BST_UNCHECKED, 0 );
1314 SendDlgItemMessageW( dialog, IDC_OPT_CONF_CTRL, BM_SETCHECK,
1315 (di->config.menu_mask & MK_CONTROL) ? BST_CHECKED : BST_UNCHECKED, 0 );
1316 SendDlgItemMessageW( dialog, IDC_OPT_CONF_SHIFT, BM_SETCHECK,
1317 (di->config.menu_mask & MK_SHIFT) ? BST_CHECKED : BST_UNCHECKED, 0 );
1318 SendDlgItemMessageW( dialog, IDC_OPT_QUICK_EDIT, BM_SETCHECK,
1319 (di->config.quick_edit) ? BST_CHECKED : BST_UNCHECKED, 0 );
1320 return FALSE; /* because we set the focus */
1322 case WM_COMMAND:
1323 break;
1325 case WM_NOTIFY:
1327 NMHDR *nmhdr = (NMHDR*)lparam;
1328 DWORD val;
1329 BOOL done;
1331 di = (struct dialog_info *)GetWindowLongPtrW( dialog, DWLP_USER );
1333 switch (nmhdr->code)
1335 case PSN_SETACTIVE:
1336 /* needed in propsheet to keep properly the selected radio button
1337 * otherwise, the focus would be set to the first tab stop in the
1338 * propsheet, which would always activate the first radio button
1340 if (IsDlgButtonChecked( dialog, IDC_OPT_CURSOR_SMALL ) == BST_CHECKED)
1341 idc = IDC_OPT_CURSOR_SMALL;
1342 else if (IsDlgButtonChecked( dialog, IDC_OPT_CURSOR_MEDIUM ) == BST_CHECKED)
1343 idc = IDC_OPT_CURSOR_MEDIUM;
1344 else
1345 idc = IDC_OPT_CURSOR_LARGE;
1346 PostMessageW( dialog, WM_NEXTDLGCTL, (WPARAM)GetDlgItem( dialog, idc ), TRUE );
1347 di->dialog = dialog;
1348 break;
1349 case PSN_APPLY:
1350 if (IsDlgButtonChecked( dialog, IDC_OPT_CURSOR_SMALL ) == BST_CHECKED) val = 25;
1351 else if (IsDlgButtonChecked( dialog, IDC_OPT_CURSOR_MEDIUM ) == BST_CHECKED) val = 50;
1352 else val = 100;
1353 di->config.cursor_size = val;
1355 val = GetDlgItemInt( dialog, IDC_OPT_HIST_SIZE, &done, FALSE );
1356 if (done) di->config.history_size = val;
1358 val = (IsDlgButtonChecked( dialog, IDC_OPT_HIST_NODOUBLE ) & BST_CHECKED) != 0;
1359 di->config.history_mode = val;
1361 val = (IsDlgButtonChecked( dialog, IDC_OPT_INSERT_MODE ) & BST_CHECKED) != 0;
1362 di->config.insert_mode = val;
1364 val = 0;
1365 if (IsDlgButtonChecked( dialog, IDC_OPT_CONF_CTRL ) & BST_CHECKED) val |= MK_CONTROL;
1366 if (IsDlgButtonChecked( dialog, IDC_OPT_CONF_SHIFT ) & BST_CHECKED) val |= MK_SHIFT;
1367 di->config.menu_mask = val;
1369 val = (IsDlgButtonChecked( dialog, IDC_OPT_QUICK_EDIT ) & BST_CHECKED) != 0;
1370 di->config.quick_edit = val;
1372 SetWindowLongPtrW( dialog, DWLP_MSGRESULT, PSNRET_NOERROR );
1373 return TRUE;
1374 default:
1375 return FALSE;
1377 break;
1379 default:
1380 return FALSE;
1382 return TRUE;
1385 static COLORREF get_color( struct dialog_info *di, unsigned int idc )
1387 LONG_PTR index;
1389 index = GetWindowLongW(GetDlgItem( di->dialog, idc ), 0);
1390 return di->config.color_map[index];
1393 /* window proc for font previewer in font property sheet */
1394 static LRESULT WINAPI font_preview_proc( HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam )
1396 switch (msg)
1398 case WM_CREATE:
1399 SetWindowLongPtrW( hwnd, 0, 0 );
1400 break;
1402 case WM_GETFONT:
1403 return GetWindowLongPtrW( hwnd, 0 );
1405 case WM_SETFONT:
1406 SetWindowLongPtrW( hwnd, 0, wparam );
1407 if (LOWORD(lparam))
1409 InvalidateRect( hwnd, NULL, TRUE );
1410 UpdateWindow( hwnd );
1412 break;
1414 case WM_DESTROY:
1416 HFONT font = (HFONT)GetWindowLongPtrW( hwnd, 0 );
1417 if (font) DeleteObject( font );
1418 break;
1421 case WM_PAINT:
1423 struct dialog_info *di;
1424 HFONT font, old_font;
1425 PAINTSTRUCT ps;
1427 di = (struct dialog_info *)GetWindowLongPtrW( GetParent( hwnd ), DWLP_USER );
1428 BeginPaint( hwnd, &ps );
1430 font = (HFONT)GetWindowLongPtrW( hwnd, 0 );
1431 if (font)
1433 static const WCHAR ascii[] = L"ASCII: abcXYZ";
1434 COLORREF bkcolor;
1435 WCHAR buf[256];
1436 int len;
1438 old_font = SelectObject( ps.hdc, font );
1439 bkcolor = get_color( di, IDC_FNT_COLOR_BK );
1440 FillRect( ps.hdc, &ps.rcPaint, CreateSolidBrush( bkcolor ));
1441 SetBkColor( ps.hdc, bkcolor );
1442 SetTextColor( ps.hdc, get_color( di, IDC_FNT_COLOR_FG ));
1443 len = LoadStringW( GetModuleHandleW(NULL), IDS_FNT_PREVIEW, buf, ARRAY_SIZE(buf) );
1444 if (len) TextOutW( ps.hdc, 0, 0, buf, len );
1445 TextOutW( ps.hdc, 0, di->config.cell_height, ascii, ARRAY_SIZE(ascii) - 1 );
1446 SelectObject( ps.hdc, old_font );
1448 EndPaint( hwnd, &ps );
1449 break;
1452 default:
1453 return DefWindowProcW( hwnd, msg, wparam, lparam );
1455 return 0;
1458 /* window proc for color previewer */
1459 static LRESULT WINAPI color_preview_proc( HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam )
1461 switch (msg)
1463 case WM_PAINT:
1465 struct dialog_info *di;
1466 PAINTSTRUCT ps;
1467 RECT client, r;
1468 int i, step;
1469 HBRUSH brush;
1471 BeginPaint( hwnd, &ps );
1472 GetClientRect( hwnd, &client );
1473 step = client.right / 8;
1475 di = (struct dialog_info *)GetWindowLongPtrW( GetParent(hwnd), DWLP_USER );
1477 for (i = 0; i < 16; i++)
1479 r.top = (i / 8) * (client.bottom / 2);
1480 r.bottom = r.top + client.bottom / 2;
1481 r.left = (i & 7) * step;
1482 r.right = r.left + step;
1483 brush = CreateSolidBrush( di->config.color_map[i] );
1484 FillRect( ps.hdc, &r, brush );
1485 DeleteObject( brush );
1486 if (GetWindowLongW( hwnd, 0 ) == i)
1488 HPEN old_pen;
1489 int i = 2;
1491 old_pen = SelectObject( ps.hdc, GetStockObject( WHITE_PEN ));
1492 r.right--; r.bottom--;
1493 for (;;)
1495 MoveToEx( ps.hdc, r.left, r.bottom, NULL );
1496 LineTo( ps.hdc, r.left, r.top );
1497 LineTo( ps.hdc, r.right, r.top );
1498 SelectObject( ps.hdc, GetStockObject( BLACK_PEN ));
1499 LineTo( ps.hdc, r.right, r.bottom );
1500 LineTo( ps.hdc, r.left, r.bottom );
1501 if (--i == 0) break;
1502 r.left++; r.top++; r.right--; r.bottom--;
1503 SelectObject( ps.hdc, GetStockObject( WHITE_PEN ));
1505 SelectObject( ps.hdc, old_pen );
1508 EndPaint( hwnd, &ps );
1509 break;
1512 case WM_LBUTTONDOWN:
1514 int i, step;
1515 RECT client;
1517 GetClientRect( hwnd, &client );
1518 step = client.right / 8;
1519 i = (HIWORD(lparam) >= client.bottom / 2) ? 8 : 0;
1520 i += LOWORD(lparam) / step;
1521 SetWindowLongW( hwnd, 0, i );
1522 InvalidateRect( GetDlgItem( GetParent( hwnd ), IDC_FNT_PREVIEW ), NULL, FALSE );
1523 InvalidateRect( hwnd, NULL, FALSE );
1524 break;
1527 default:
1528 return DefWindowProcW( hwnd, msg, wparam, lparam );
1530 return 0;
1533 static BOOL select_font( struct dialog_info *di )
1535 int font_idx, size_idx;
1536 WCHAR face_name[LF_FACESIZE], height_buf[4];
1537 size_t len;
1538 unsigned int font_height;
1539 LOGFONTW lf;
1540 HFONT font, old_font;
1541 DWORD_PTR args[2];
1542 WCHAR buf[256];
1543 WCHAR fmt[128];
1545 font_idx = SendDlgItemMessageW( di->dialog, IDC_FNT_LIST_FONT, LB_GETCURSEL, 0, 0 );
1546 size_idx = SendDlgItemMessageW( di->dialog, IDC_FNT_LIST_SIZE, LB_GETCURSEL, 0, 0 );
1548 if (font_idx < 0 || size_idx < 0)
1549 return FALSE;
1551 len = SendDlgItemMessageW( di->dialog, IDC_FNT_LIST_FONT, LB_GETTEXT, font_idx, (LPARAM)&face_name );
1552 SendDlgItemMessageW( di->dialog, IDC_FNT_LIST_SIZE, LB_GETTEXT, size_idx, (LPARAM)&height_buf );
1553 font_height = _wtoi( height_buf );
1555 fill_logfont( &lf, face_name, len * sizeof(WCHAR), font_height, FW_NORMAL );
1556 font = select_font_config( &di->config, di->console->output_cp, di->console->win, &lf );
1557 if (!font) return FALSE;
1559 if (di->config.cell_height != font_height)
1560 TRACE( "mismatched heights (%u<>%u)\n", di->config.cell_height, font_height );
1562 old_font = (HFONT)SendDlgItemMessageW( di->dialog, IDC_FNT_PREVIEW, WM_GETFONT, 0, 0 );
1563 SendDlgItemMessageW( di->dialog, IDC_FNT_PREVIEW, WM_SETFONT, (WPARAM)font, TRUE );
1564 if (old_font) DeleteObject( old_font );
1566 LoadStringW( GetModuleHandleW(NULL), IDS_FNT_DISPLAY, fmt, ARRAY_SIZE(fmt) );
1567 args[0] = di->config.cell_width;
1568 args[1] = di->config.cell_height;
1569 FormatMessageW( FORMAT_MESSAGE_FROM_STRING|FORMAT_MESSAGE_ARGUMENT_ARRAY,
1570 fmt, 0, 0, buf, ARRAY_SIZE(buf), (va_list *)args );
1572 SendDlgItemMessageW( di->dialog, IDC_FNT_FONT_INFO, WM_SETTEXT, 0, (LPARAM)buf );
1573 return TRUE;
1576 static BOOL fill_list_size( struct dialog_info *di, BOOL init )
1578 if (init)
1580 static const int sizes[] = {8,9,10,11,12,14,16,18,20,22,24,26,28,36,48,72};
1581 unsigned int i, idx = 4;
1582 WCHAR buf[4];
1584 for (i = 0; i < ARRAY_SIZE(sizes); i++)
1586 wsprintfW( buf, L"%u", sizes[i] );
1587 SendDlgItemMessageW( di->dialog, IDC_FNT_LIST_SIZE, LB_INSERTSTRING, -1, (LPARAM)buf );
1589 if (di->config.cell_height == sizes[i]) idx = i;
1592 SendDlgItemMessageW( di->dialog, IDC_FNT_LIST_SIZE, LB_SETCURSEL, idx, 0 );
1595 select_font( di );
1597 return TRUE;
1600 static int CALLBACK enum_list_font_proc( const LOGFONTW *lf, const TEXTMETRICW *tm,
1601 DWORD font_type, LPARAM lparam )
1603 struct dialog_info *di = (struct dialog_info *)lparam;
1605 if (font_type != TRUETYPE_FONTTYPE) return 1;
1607 TRACE( "%s\n", debugstr_logfont( lf, font_type ));
1609 if (validate_font( di->console, lf, 0 ))
1610 SendDlgItemMessageW( di->dialog, IDC_FNT_LIST_FONT, LB_ADDSTRING, 0, (LPARAM)lf->lfFaceName );
1612 return 1;
1615 static BOOL fill_list_font( struct dialog_info *di )
1617 LOGFONTW lf;
1619 memset( &lf, 0, sizeof(lf) );
1620 lf.lfCharSet = DEFAULT_CHARSET;
1621 lf.lfFaceName[0] = 0;
1622 lf.lfPitchAndFamily = FIXED_PITCH | FF_MODERN;
1624 EnumFontFamiliesExW( di->console->window->mem_dc, &lf, enum_list_font_proc, (LPARAM)di, 0 );
1626 if (SendDlgItemMessageW( di->dialog, IDC_FNT_LIST_FONT, LB_SELECTSTRING,
1627 -1, (LPARAM)di->config.face_name ) == LB_ERR)
1628 SendDlgItemMessageW( di->dialog, IDC_FNT_LIST_FONT, LB_SETCURSEL, 0, 0 );
1630 fill_list_size( di, TRUE );
1632 return TRUE;
1635 /* dialog proc for the font property sheet */
1636 static INT_PTR WINAPI font_dialog_proc( HWND dialog, UINT msg, WPARAM wparam, LPARAM lparam )
1638 struct dialog_info *di;
1640 switch (msg)
1642 case WM_INITDIALOG:
1643 di = (struct dialog_info *)((PROPSHEETPAGEA*)lparam)->lParam;
1644 di->dialog = dialog;
1645 SetWindowLongPtrW( dialog, DWLP_USER, (DWORD_PTR)di );
1646 /* use default system font until user-selected font is applied */
1647 SendDlgItemMessageW( dialog, IDC_FNT_PREVIEW, WM_SETFONT, 0, 0 );
1648 fill_list_font( di );
1649 SetWindowLongW( GetDlgItem( dialog, IDC_FNT_COLOR_BK ), 0, (di->config.attr >> 4) & 0x0F );
1650 SetWindowLongW( GetDlgItem( dialog, IDC_FNT_COLOR_FG ), 0, di->config.attr & 0x0F );
1651 break;
1653 case WM_COMMAND:
1654 di = (struct dialog_info *)GetWindowLongPtrW( dialog, DWLP_USER );
1655 switch (LOWORD(wparam))
1657 case IDC_FNT_LIST_FONT:
1658 if (HIWORD(wparam) == LBN_SELCHANGE)
1659 fill_list_size( di, FALSE );
1660 break;
1661 case IDC_FNT_LIST_SIZE:
1662 if (HIWORD(wparam) == LBN_SELCHANGE)
1663 select_font( di );
1664 break;
1666 break;
1668 case WM_NOTIFY:
1670 NMHDR *nmhdr = (NMHDR*)lparam;
1671 DWORD val;
1673 di = (struct dialog_info*)GetWindowLongPtrW( dialog, DWLP_USER );
1674 switch (nmhdr->code)
1676 case PSN_SETACTIVE:
1677 di->dialog = dialog;
1678 break;
1679 case PSN_APPLY:
1680 val = (GetWindowLongW( GetDlgItem( dialog, IDC_FNT_COLOR_BK ), 0 ) << 4) |
1681 GetWindowLongW( GetDlgItem( dialog, IDC_FNT_COLOR_FG ), 0 );
1682 di->config.attr = val;
1683 SetWindowLongPtrW( dialog, DWLP_MSGRESULT, PSNRET_NOERROR );
1684 return TRUE;
1685 default:
1686 return FALSE;
1688 break;
1690 default:
1691 return FALSE;
1693 return TRUE;
1696 /* dialog proc for the config property sheet */
1697 static INT_PTR WINAPI config_dialog_proc( HWND dialog, UINT msg, WPARAM wparam, LPARAM lparam )
1699 struct dialog_info *di;
1700 int max_ud = 2000;
1702 switch (msg)
1704 case WM_INITDIALOG:
1705 di = (struct dialog_info *)((PROPSHEETPAGEA*)lparam)->lParam;
1706 di->dialog = dialog;
1708 SetWindowLongPtrW( dialog, DWLP_USER, (DWORD_PTR)di );
1709 SetDlgItemInt( dialog, IDC_CNF_SB_WIDTH, di->config.sb_width, FALSE );
1710 SetDlgItemInt( dialog, IDC_CNF_SB_HEIGHT, di->config.sb_height, FALSE );
1711 SetDlgItemInt( dialog, IDC_CNF_WIN_WIDTH, di->config.win_width, FALSE );
1712 SetDlgItemInt( dialog, IDC_CNF_WIN_HEIGHT, di->config.win_height, FALSE );
1714 SendMessageW( GetDlgItem(dialog, IDC_CNF_WIN_HEIGHT_UD), UDM_SETRANGE, 0, MAKELPARAM(max_ud, 0));
1715 SendMessageW( GetDlgItem(dialog, IDC_CNF_WIN_WIDTH_UD), UDM_SETRANGE, 0, MAKELPARAM(max_ud, 0));
1716 SendMessageW( GetDlgItem(dialog, IDC_CNF_SB_HEIGHT_UD), UDM_SETRANGE, 0, MAKELPARAM(max_ud, 0));
1717 SendMessageW( GetDlgItem(dialog, IDC_CNF_SB_WIDTH_UD), UDM_SETRANGE, 0, MAKELPARAM(max_ud, 0));
1719 SendDlgItemMessageW( dialog, IDC_CNF_CLOSE_EXIT, BM_SETCHECK, BST_CHECKED, 0 );
1721 SendDlgItemMessageW( dialog, IDC_CNF_EDITION_MODE, CB_ADDSTRING, 0, (LPARAM)L"Win32" );
1722 SendDlgItemMessageW( dialog, IDC_CNF_EDITION_MODE, CB_ADDSTRING, 0, (LPARAM)L"Emacs" );
1723 SendDlgItemMessageW( dialog, IDC_CNF_EDITION_MODE, CB_SETCURSEL, di->config.edition_mode, 0 );
1724 break;
1726 case WM_NOTIFY:
1728 NMHDR *nmhdr = (NMHDR*)lparam;
1729 int win_w, win_h, sb_w, sb_h;
1730 BOOL st1, st2;
1732 di = (struct dialog_info *)GetWindowLongPtrW( dialog, DWLP_USER );
1733 switch (nmhdr->code)
1735 case PSN_SETACTIVE:
1736 di->dialog = dialog;
1737 break;
1738 case PSN_APPLY:
1739 sb_w = GetDlgItemInt( dialog, IDC_CNF_SB_WIDTH, &st1, FALSE );
1740 sb_h = GetDlgItemInt( dialog, IDC_CNF_SB_HEIGHT, &st2, FALSE );
1741 if (!st1 || ! st2)
1743 SetWindowLongPtrW( dialog, DWLP_MSGRESULT, PSNRET_INVALID );
1744 return TRUE;
1746 win_w = GetDlgItemInt( dialog, IDC_CNF_WIN_WIDTH, &st1, FALSE );
1747 win_h = GetDlgItemInt( dialog, IDC_CNF_WIN_HEIGHT, &st2, FALSE );
1748 if (!st1 || !st2)
1750 SetWindowLongPtrW( dialog, DWLP_MSGRESULT, PSNRET_INVALID );
1751 return TRUE;
1753 if (win_w > sb_w || win_h > sb_h)
1755 WCHAR cap[256];
1756 WCHAR txt[256];
1758 LoadStringW( GetModuleHandleW(NULL), IDS_DLG_TIT_ERROR, cap, ARRAY_SIZE(cap) );
1759 LoadStringW( GetModuleHandleW(NULL), IDS_DLG_ERR_SBWINSIZE, txt, ARRAY_SIZE(txt) );
1761 MessageBoxW( dialog, txt, cap, MB_OK );
1762 SetWindowLongPtrW( dialog, DWLP_MSGRESULT, PSNRET_INVALID );
1763 return TRUE;
1765 di->config.win_width = win_w;
1766 di->config.win_height = win_h;
1767 di->config.sb_width = sb_w;
1768 di->config.sb_height = sb_h;
1770 di->config.edition_mode = SendDlgItemMessageW( dialog, IDC_CNF_EDITION_MODE,
1771 CB_GETCURSEL, 0, 0 );
1772 SetWindowLongPtrW( dialog, DWLP_MSGRESULT, PSNRET_NOERROR );
1773 return TRUE;
1774 default:
1775 return FALSE;
1777 break;
1779 default:
1780 return FALSE;
1782 return TRUE;
1785 static void apply_config( struct console *console, const struct console_config *config )
1787 if (console->active->width != config->sb_width || console->active->height != config->sb_height)
1788 change_screen_buffer_size( console->active, config->sb_width, config->sb_height );
1790 console->window->menu_mask = config->menu_mask;
1791 console->window->quick_edit = config->quick_edit;
1793 console->edition_mode = config->edition_mode;
1794 console->history_mode = config->history_mode;
1796 if (console->history_size != config->history_size)
1798 struct history_line **mem = NULL;
1799 int i, delta;
1801 if (config->history_size && (mem = malloc( config->history_size * sizeof(*mem) )))
1803 memset( mem, 0, config->history_size * sizeof(*mem) );
1805 delta = (console->history_index > config->history_size)
1806 ? (console->history_index - config->history_size) : 0;
1808 for (i = delta; i < console->history_index; i++)
1810 mem[i - delta] = console->history[i];
1811 console->history[i] = NULL;
1813 console->history_index -= delta;
1815 for (i = 0; i < console->history_size; i++)
1816 free( console->history[i] );
1817 free( console->history );
1818 console->history = mem;
1819 console->history_size = config->history_size;
1823 if (config->insert_mode)
1824 console->mode |= ENABLE_INSERT_MODE|ENABLE_EXTENDED_FLAGS;
1825 else
1826 console->mode &= ~ENABLE_INSERT_MODE;
1828 console->active->cursor_size = config->cursor_size;
1829 console->active->cursor_visible = config->cursor_visible;
1830 console->active->attr = config->attr;
1831 console->active->popup_attr = config->popup_attr;
1832 console->active->win.left = config->win_pos.X;
1833 console->active->win.top = config->win_pos.Y;
1834 console->active->win.right = config->win_pos.X + config->win_width - 1;
1835 console->active->win.bottom = config->win_pos.Y + config->win_height - 1;
1836 memcpy( console->active->color_map, config->color_map, sizeof(config->color_map) );
1838 if (console->active->font.width != config->cell_width ||
1839 console->active->font.height != config->cell_height ||
1840 console->active->font.weight != config->font_weight ||
1841 console->active->font.pitch_family != config->font_pitch_family ||
1842 console->active->font.face_len != wcslen( config->face_name ) ||
1843 memcmp( console->active->font.face_name, config->face_name,
1844 console->active->font.face_len * sizeof(WCHAR) ))
1846 update_console_font( console, config->face_name, wcslen(config->face_name) * sizeof(WCHAR),
1847 config->cell_height, config->font_weight );
1850 update_window( console );
1852 notify_screen_buffer_size( console->active );
1855 static void current_config( struct console *console, struct console_config *config )
1857 size_t len;
1859 config->menu_mask = console->window->menu_mask;
1860 config->quick_edit = console->window->quick_edit;
1862 config->edition_mode = console->edition_mode;
1863 config->history_mode = console->history_mode;
1864 config->history_size = console->history_size;
1866 config->insert_mode = (console->mode & (ENABLE_INSERT_MODE|ENABLE_EXTENDED_FLAGS)) ==
1867 (ENABLE_INSERT_MODE|ENABLE_EXTENDED_FLAGS);
1869 config->cursor_size = console->active->cursor_size;
1870 config->cursor_visible = console->active->cursor_visible;
1871 config->attr = console->active->attr;
1872 config->popup_attr = console->active->popup_attr;
1873 memcpy( config->color_map, console->active->color_map, sizeof(config->color_map) );
1875 config->cell_width = console->active->font.width;
1876 config->cell_height = console->active->font.height;
1877 config->font_weight = console->active->font.weight;
1878 config->font_pitch_family = console->active->font.pitch_family;
1879 len = min( ARRAY_SIZE(config->face_name) - 1, console->active->font.face_len );
1880 if (len) memcpy( config->face_name, console->active->font.face_name, len * sizeof(WCHAR) );
1881 config->face_name[len] = 0;
1883 config->sb_width = console->active->width;
1884 config->sb_height = console->active->height;
1886 config->win_width = console->active->win.right - console->active->win.left + 1;
1887 config->win_height = console->active->win.bottom - console->active->win.top + 1;
1888 config->win_pos.X = console->active->win.left;
1889 config->win_pos.Y = console->active->win.top;
1892 /* run the dialog box to set up the console options */
1893 static BOOL config_dialog( struct console *console, BOOL current )
1895 struct console_config prev_config;
1896 struct dialog_info di;
1897 PROPSHEETHEADERW header;
1898 HPROPSHEETPAGE pages[3];
1899 PROPSHEETPAGEW psp;
1900 WNDCLASSW wndclass;
1901 WCHAR buff[256];
1903 InitCommonControls();
1905 memset( &di, 0, sizeof(di) );
1906 di.console = console;
1908 if (current)
1909 current_config( console, &di.config );
1910 else
1911 load_config( NULL, &di.config );
1913 prev_config = di.config;
1915 wndclass.style = 0;
1916 wndclass.lpfnWndProc = font_preview_proc;
1917 wndclass.cbClsExtra = 0;
1918 wndclass.cbWndExtra = sizeof(HFONT);
1919 wndclass.hInstance = GetModuleHandleW( NULL );
1920 wndclass.hIcon = 0;
1921 wndclass.hCursor = LoadCursorW( 0, (const WCHAR *)IDC_ARROW );
1922 wndclass.hbrBackground = GetStockObject( BLACK_BRUSH );
1923 wndclass.lpszMenuName = NULL;
1924 wndclass.lpszClassName = L"WineConFontPreview";
1925 RegisterClassW( &wndclass );
1927 wndclass.style = 0;
1928 wndclass.lpfnWndProc = color_preview_proc;
1929 wndclass.cbClsExtra = 0;
1930 wndclass.cbWndExtra = sizeof(DWORD);
1931 wndclass.hInstance = GetModuleHandleW( NULL );
1932 wndclass.hIcon = 0;
1933 wndclass.hCursor = LoadCursorW( 0, (const WCHAR *)IDC_ARROW );
1934 wndclass.hbrBackground = GetStockObject( BLACK_BRUSH );
1935 wndclass.lpszMenuName = NULL;
1936 wndclass.lpszClassName = L"WineConColorPreview";
1937 RegisterClassW( &wndclass );
1939 memset( &psp, 0, sizeof(psp) );
1940 psp.dwSize = sizeof(psp);
1941 psp.dwFlags = 0;
1942 psp.hInstance = wndclass.hInstance;
1943 psp.lParam = (LPARAM)&di;
1945 psp.pszTemplate = MAKEINTRESOURCEW(IDD_OPTION);
1946 psp.pfnDlgProc = option_dialog_proc;
1947 pages[0] = CreatePropertySheetPageW( &psp );
1949 psp.pszTemplate = MAKEINTRESOURCEW(IDD_FONT);
1950 psp.pfnDlgProc = font_dialog_proc;
1951 pages[1] = CreatePropertySheetPageW( &psp );
1953 psp.pszTemplate = MAKEINTRESOURCEW(IDD_CONFIG);
1954 psp.pfnDlgProc = config_dialog_proc;
1955 pages[2] = CreatePropertySheetPageW( &psp );
1957 memset( &header, 0, sizeof(header) );
1958 header.dwSize = sizeof(header);
1960 if (!LoadStringW( GetModuleHandleW( NULL ),
1961 current ? IDS_DLG_TIT_CURRENT : IDS_DLG_TIT_DEFAULT,
1962 buff, ARRAY_SIZE(buff) ))
1963 wcscpy( buff, L"Setup" );
1965 header.pszCaption = buff;
1966 header.nPages = 3;
1967 header.hwndParent = console->win;
1968 header.phpage = pages;
1969 header.dwFlags = PSH_NOAPPLYNOW;
1970 if (PropertySheetW( &header ) < 1)
1971 return TRUE;
1973 if (!memcmp( &prev_config, &di.config, sizeof(prev_config) ))
1974 return TRUE;
1976 TRACE( "%s\n", debugstr_config(&di.config) );
1978 if (current)
1980 apply_config( console, &di.config );
1981 update_window( di.console );
1984 save_config( current ? console->window->config_key : NULL, &di.config );
1986 return TRUE;
1989 static void resize_window( struct console *console, int width, int height )
1991 struct console_config config;
1993 current_config( console, &config );
1994 config.win_width = width;
1995 config.win_height = height;
1997 /* auto size screen-buffer if it's now smaller than window */
1998 if (config.sb_width < config.win_width)
1999 config.sb_width = config.win_width;
2000 if (config.sb_height < config.win_height)
2001 config.sb_height = config.win_height;
2003 /* and reset window pos so that we don't display outside of the screen-buffer */
2004 if (config.win_pos.X + config.win_width > config.sb_width)
2005 config.win_pos.X = config.sb_width - config.win_width;
2006 if (config.win_pos.Y + config.win_height > config.sb_height)
2007 config.win_pos.Y = config.sb_height - config.win_height;
2009 apply_config( console, &config );
2012 /* grays / ungrays the menu items according to their state */
2013 static void set_menu_details( struct console *console, HMENU menu )
2015 EnableMenuItem( menu, IDS_COPY, MF_BYCOMMAND |
2016 (console->window->in_selection ? MF_ENABLED : MF_GRAYED) );
2017 EnableMenuItem( menu, IDS_PASTE, MF_BYCOMMAND |
2018 (IsClipboardFormatAvailable(CF_UNICODETEXT) ? MF_ENABLED : MF_GRAYED) );
2019 EnableMenuItem( menu, IDS_SCROLL, MF_BYCOMMAND | MF_GRAYED );
2020 EnableMenuItem( menu, IDS_SEARCH, MF_BYCOMMAND | MF_GRAYED );
2023 static BOOL fill_menu( HMENU menu, BOOL sep )
2025 HINSTANCE module = GetModuleHandleW( NULL );
2026 HMENU sub_menu;
2027 WCHAR buff[256];
2029 if (!menu) return FALSE;
2031 sub_menu = CreateMenu();
2032 if (!sub_menu) return FALSE;
2034 LoadStringW( module, IDS_MARK, buff, ARRAY_SIZE(buff) );
2035 InsertMenuW( sub_menu, -1, MF_BYPOSITION|MF_STRING, IDS_MARK, buff );
2036 LoadStringW( module, IDS_COPY, buff, ARRAY_SIZE(buff) );
2037 InsertMenuW( sub_menu, -1, MF_BYPOSITION|MF_STRING, IDS_COPY, buff );
2038 LoadStringW( module, IDS_PASTE, buff, ARRAY_SIZE(buff) );
2039 InsertMenuW( sub_menu, -1, MF_BYPOSITION|MF_STRING, IDS_PASTE, buff );
2040 LoadStringW( module, IDS_SELECTALL, buff, ARRAY_SIZE(buff) );
2041 InsertMenuW( sub_menu, -1, MF_BYPOSITION|MF_STRING, IDS_SELECTALL, buff );
2042 LoadStringW( module, IDS_SCROLL, buff, ARRAY_SIZE(buff) );
2043 InsertMenuW( sub_menu, -1, MF_BYPOSITION|MF_STRING, IDS_SCROLL, buff );
2044 LoadStringW( module, IDS_SEARCH, buff, ARRAY_SIZE(buff) );
2045 InsertMenuW( sub_menu, -1, MF_BYPOSITION|MF_STRING, IDS_SEARCH, buff );
2047 if (sep) InsertMenuW( menu, -1, MF_BYPOSITION|MF_SEPARATOR, 0, NULL );
2048 LoadStringW( module, IDS_EDIT, buff, ARRAY_SIZE(buff) );
2049 InsertMenuW( menu, -1, MF_BYPOSITION|MF_STRING|MF_POPUP, (UINT_PTR)sub_menu, buff );
2050 LoadStringW( module, IDS_DEFAULT, buff, ARRAY_SIZE(buff) );
2051 InsertMenuW( menu, -1, MF_BYPOSITION|MF_STRING, IDS_DEFAULT, buff );
2052 LoadStringW( module, IDS_PROPERTIES, buff, ARRAY_SIZE(buff) );
2053 InsertMenuW( menu, -1, MF_BYPOSITION|MF_STRING, IDS_PROPERTIES, buff );
2055 return TRUE;
2058 static LRESULT window_create( HWND hwnd, const CREATESTRUCTW *create )
2060 struct console *console = create->lpCreateParams;
2061 HMENU sys_menu;
2063 TRACE( "%p\n", hwnd );
2065 SetWindowLongPtrW( hwnd, 0, (DWORD_PTR)console );
2066 console->win = hwnd;
2068 if (console->window)
2070 sys_menu = GetSystemMenu( hwnd, FALSE );
2071 if (!sys_menu) return 0;
2072 console->window->popup_menu = CreatePopupMenu();
2073 if (!console->window->popup_menu) return 0;
2075 fill_menu( sys_menu, TRUE );
2076 fill_menu( console->window->popup_menu, FALSE );
2078 console->window->mem_dc = CreateCompatibleDC( 0 );
2080 return 0;
2083 static LRESULT WINAPI window_proc( HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam )
2085 struct console *console = (struct console *)GetWindowLongPtrW( hwnd, 0 );
2087 switch (msg)
2089 case WM_CREATE:
2090 return window_create( hwnd, (const CREATESTRUCTW *)lparam );
2092 case WM_DESTROY:
2093 console->win = NULL;
2094 PostQuitMessage( 0 );
2095 break;
2097 case WM_TIMER:
2098 case WM_UPDATE_CONFIG:
2099 if (console->window && console->window->update_state == UPDATE_PENDING)
2100 update_window( console );
2101 break;
2103 case WM_PAINT:
2105 PAINTSTRUCT ps;
2107 if (!console->window) break;
2109 BeginPaint( console->win, &ps );
2110 BitBlt( ps.hdc, 0, 0,
2111 (console->active->win.right - console->active->win.left + 1) * console->active->font.width,
2112 (console->active->win.bottom - console->active->win.top + 1) * console->active->font.height,
2113 console->window->mem_dc,
2114 console->active->win.left * console->active->font.width,
2115 console->active->win.top * console->active->font.height,
2116 SRCCOPY );
2117 if (console->window->in_selection) update_selection( console, ps.hdc );
2118 EndPaint( console->win, &ps );
2119 break;
2122 case WM_SHOWWINDOW:
2123 if (!console->window) break;
2124 if (wparam)
2125 update_window( console );
2126 else
2128 if (console->window->bitmap) DeleteObject( console->window->bitmap );
2129 console->window->bitmap = NULL;
2131 break;
2133 case WM_KEYDOWN:
2134 case WM_KEYUP:
2135 if (console->window && console->window->in_selection)
2136 handle_selection_key( console, msg == WM_KEYDOWN, wparam, lparam );
2137 else
2138 record_key_input( console, msg == WM_KEYDOWN, wparam, lparam );
2139 break;
2141 case WM_SYSKEYDOWN:
2142 case WM_SYSKEYUP:
2143 record_key_input( console, msg == WM_SYSKEYDOWN, wparam, lparam );
2144 break;
2146 case WM_CHAR:
2147 if (console->window && console->window->in_selection)
2148 handle_selection_key( console, TRUE, LOBYTE( VkKeyScanW( (WCHAR)wparam ) ), lparam );
2149 else
2150 record_char_input( console, (WCHAR)wparam, lparam );
2151 break;
2153 case WM_LBUTTONDOWN:
2154 if (console->window && (console->window->quick_edit || console->window->in_selection))
2156 if (console->window->in_selection)
2157 update_selection( console, 0 );
2159 if (console->window->quick_edit && console->window->in_selection)
2161 console->window->in_selection = FALSE;
2163 else
2165 console->window->selection_end = get_cell( console, lparam );
2166 console->window->selection_start = console->window->selection_end;
2167 SetCapture( console->win );
2168 update_selection( console, 0 );
2169 console->window->in_selection = TRUE;
2172 else
2174 record_mouse_input( console, get_cell(console, lparam), wparam, 0 );
2176 break;
2178 case WM_MOUSEMOVE:
2179 if (console->window && (console->window->quick_edit || console->window->in_selection))
2181 if (GetCapture() == console->win && console->window->in_selection &&
2182 (wparam & MK_LBUTTON))
2184 move_selection( console, console->window->selection_start,
2185 get_cell(console, lparam) );
2188 else
2190 record_mouse_input( console, get_cell(console, lparam), wparam, MOUSE_MOVED );
2192 break;
2194 case WM_LBUTTONUP:
2195 if (console->window && (console->window->quick_edit || console->window->in_selection))
2197 if (GetCapture() == console->win && console->window->in_selection)
2199 move_selection( console, console->window->selection_start,
2200 get_cell(console, lparam) );
2201 ReleaseCapture();
2204 else
2206 record_mouse_input( console, get_cell(console, lparam), wparam, 0 );
2208 break;
2210 case WM_RBUTTONDOWN:
2211 if (console->window && (wparam & (MK_CONTROL|MK_SHIFT)) == console->window->menu_mask)
2213 POINT pt;
2214 pt.x = (short)LOWORD(lparam);
2215 pt.y = (short)HIWORD(lparam);
2216 ClientToScreen( hwnd, &pt );
2217 set_menu_details( console, console->window->popup_menu );
2218 TrackPopupMenu( console->window->popup_menu, TPM_LEFTALIGN|TPM_TOPALIGN|TPM_RIGHTBUTTON,
2219 pt.x, pt.y, 0, hwnd, NULL );
2221 else
2223 record_mouse_input( console, get_cell(console, lparam), wparam, 0 );
2225 break;
2227 case WM_RBUTTONUP:
2228 /* no need to track for rbutton up when opening the popup... the event will be
2229 * swallowed by TrackPopupMenu */
2230 case WM_MBUTTONDOWN:
2231 case WM_MBUTTONUP:
2232 record_mouse_input( console, get_cell(console, lparam), wparam, 0 );
2233 break;
2235 case WM_LBUTTONDBLCLK:
2236 case WM_MBUTTONDBLCLK:
2237 case WM_RBUTTONDBLCLK:
2238 record_mouse_input( console, get_cell(console, lparam), wparam, DOUBLE_CLICK );
2239 break;
2241 case WM_SETFOCUS:
2242 if (console->window && console->active->cursor_visible)
2244 CreateCaret( console->win, console->window->cursor_bitmap,
2245 console->active->font.width, console->active->font.height );
2246 update_window_cursor( console );
2248 break;
2250 case WM_KILLFOCUS:
2251 if (console->window && console->active->cursor_visible)
2252 DestroyCaret();
2253 break;
2255 case WM_SIZE:
2256 if (console->window && console->window->update_state != UPDATE_BUSY)
2257 resize_window( console,
2258 max( LOWORD(lparam) / console->active->font.width, 20 ),
2259 max( HIWORD(lparam) / console->active->font.height, 20 ));
2260 break;
2262 case WM_HSCROLL:
2264 int win_width = console->active->win.right - console->active->win.left + 1;
2265 int x = console->active->win.left;
2267 if (!console->window) break;
2268 switch (LOWORD(wparam))
2270 case SB_PAGEUP: x -= 8; break;
2271 case SB_PAGEDOWN: x += 8; break;
2272 case SB_LINEUP: x--; break;
2273 case SB_LINEDOWN: x++; break;
2274 case SB_THUMBTRACK: x = HIWORD(wparam); break;
2275 default: break;
2277 x = min( max( x, 0 ), console->active->width - win_width );
2278 if (x != console->active->win.left)
2280 console->active->win.left = x;
2281 console->active->win.right = x + win_width - 1;
2282 update_window( console );
2284 break;
2287 case WM_MOUSEWHEEL:
2288 if (console->active->height <= console->active->win.bottom - console->active->win.top + 1)
2290 record_mouse_input(console, get_cell(console, lparam), wparam, MOUSE_WHEELED);
2291 break;
2293 /* else fallthrough */
2294 case WM_VSCROLL:
2296 int win_height = console->active->win.bottom - console->active->win.top + 1;
2297 int y = console->active->win.top;
2299 if (!console->window) break;
2301 if (msg == WM_MOUSEWHEEL)
2303 UINT scroll_lines = 3;
2304 SystemParametersInfoW( SPI_GETWHEELSCROLLLINES, 0, &scroll_lines, 0 );
2305 scroll_lines *= -GET_WHEEL_DELTA_WPARAM(wparam) / WHEEL_DELTA;
2306 y += scroll_lines;
2308 else
2310 switch (LOWORD(wparam))
2312 case SB_PAGEUP: y -= 8; break;
2313 case SB_PAGEDOWN: y += 8; break;
2314 case SB_LINEUP: y--; break;
2315 case SB_LINEDOWN: y++; break;
2316 case SB_THUMBTRACK: y = HIWORD(wparam); break;
2317 default: break;
2321 y = min( max( y, 0 ), console->active->height - win_height );
2322 if (y != console->active->win.top)
2324 console->active->win.top = y;
2325 console->active->win.bottom = y + win_height - 1;
2326 update_window( console );
2328 break;
2331 case WM_SYSCOMMAND:
2332 if (!console->window) break;
2333 switch (wparam)
2335 case IDS_DEFAULT:
2336 config_dialog( console, FALSE );
2337 break;
2338 case IDS_PROPERTIES:
2339 config_dialog( console, TRUE );
2340 break;
2341 default:
2342 return DefWindowProcW( hwnd, msg, wparam, lparam );
2344 break;
2346 case WM_COMMAND:
2347 if (!console->window) break;
2348 switch (wparam)
2350 case IDS_DEFAULT:
2351 config_dialog( console, FALSE );
2352 break;
2353 case IDS_PROPERTIES:
2354 config_dialog( console, TRUE );
2355 break;
2356 case IDS_MARK:
2357 console->window->selection_start.X = console->window->selection_start.Y = 0;
2358 console->window->selection_end.X = console->window->selection_end.Y = 0;
2359 update_selection( console, 0 );
2360 console->window->in_selection = TRUE;
2361 break;
2362 case IDS_COPY:
2363 if (console->window->in_selection)
2365 console->window->in_selection = FALSE;
2366 update_selection( console, 0 );
2367 copy_selection( console );
2369 break;
2370 case IDS_PASTE:
2371 paste_clipboard( console );
2372 break;
2373 case IDS_SELECTALL:
2374 console->window->selection_start.X = console->window->selection_start.Y = 0;
2375 console->window->selection_end.X = console->active->width - 1;
2376 console->window->selection_end.Y = console->active->height - 1;
2377 update_selection( console, 0 );
2378 console->window->in_selection = TRUE;
2379 break;
2380 case IDS_SCROLL:
2381 case IDS_SEARCH:
2382 FIXME( "Unhandled yet command: %Ix\n", wparam );
2383 break;
2384 default:
2385 return DefWindowProcW( hwnd, msg, wparam, lparam );
2387 break;
2389 case WM_INITMENUPOPUP:
2390 if (!console->window || !HIWORD(lparam)) return DefWindowProcW( hwnd, msg, wparam, lparam );
2391 set_menu_details( console, GetSystemMenu(console->win, FALSE) );
2392 break;
2394 default:
2395 return DefWindowProcW( hwnd, msg, wparam, lparam );
2398 return 0;
2401 void update_window_config( struct console *console, BOOL delay )
2403 const int delay_timeout = 50;
2405 if (!console->window || console->window->update_state != UPDATE_NONE) return;
2406 console->window->update_state = UPDATE_PENDING;
2407 if (delay)
2408 SetTimer( console->win, 1, delay_timeout, NULL );
2409 else
2410 PostMessageW( console->win, WM_UPDATE_CONFIG, 0, 0 );
2413 void update_window_region( struct console *console, const RECT *update )
2415 RECT *window_rect = &console->window->update;
2416 window_rect->left = min( window_rect->left, update->left );
2417 window_rect->top = min( window_rect->top, update->top );
2418 window_rect->right = max( window_rect->right, update->right );
2419 window_rect->bottom = max( window_rect->bottom, update->bottom );
2420 update_window_config( console, TRUE );
2423 BOOL init_window( struct console *console )
2425 struct console_config config;
2426 WNDCLASSW wndclass;
2427 STARTUPINFOW si;
2428 CHARSETINFO ci;
2430 static struct console_window console_window;
2432 console->window = &console_window;
2433 if (!TranslateCharsetInfo( (DWORD *)(INT_PTR)GetACP(), &ci, TCI_SRCCODEPAGE ))
2434 return FALSE;
2436 console->window->ui_charset = ci.ciCharset;
2438 GetStartupInfoW(&si);
2439 if (si.lpTitle)
2441 size_t i, title_len = wcslen( si.lpTitle );
2442 if (!(console->window->config_key = malloc( (title_len + 1) * sizeof(WCHAR) )))
2443 return FALSE;
2444 for (i = 0; i < title_len; i++)
2445 console->window->config_key[i] = si.lpTitle[i] == '\\' ? '_' : si.lpTitle[i];
2446 console->window->config_key[title_len] = 0;
2449 load_config( console->window->config_key, &config );
2450 if (si.dwFlags & STARTF_USECOUNTCHARS)
2452 config.sb_width = si.dwXCountChars;
2453 config.sb_height = si.dwYCountChars;
2455 if (si.dwFlags & STARTF_USEFILLATTRIBUTE)
2456 config.attr = si.dwFillAttribute;
2458 wndclass.style = CS_DBLCLKS;
2459 wndclass.lpfnWndProc = window_proc;
2460 wndclass.cbClsExtra = 0;
2461 wndclass.cbWndExtra = sizeof(DWORD_PTR);
2462 wndclass.hInstance = GetModuleHandleW(NULL);
2463 wndclass.hIcon = LoadIconW( 0, (const WCHAR *)IDI_WINLOGO );
2464 wndclass.hCursor = LoadCursorW( 0, (const WCHAR *)IDC_ARROW );
2465 wndclass.hbrBackground = GetStockObject( BLACK_BRUSH );
2466 wndclass.lpszMenuName = NULL;
2467 wndclass.lpszClassName = L"WineConsoleClass";
2468 RegisterClassW(&wndclass);
2470 if (!CreateWindowW( wndclass.lpszClassName, NULL,
2471 WS_OVERLAPPED|WS_CAPTION|WS_SYSMENU|WS_THICKFRAME|WS_MINIMIZEBOX|
2472 WS_MAXIMIZEBOX|WS_HSCROLL|WS_VSCROLL, CW_USEDEFAULT, CW_USEDEFAULT,
2473 0, 0, 0, 0, wndclass.hInstance, console ))
2474 return FALSE;
2476 if (!config.face_name[0])
2477 set_first_font( console, &config );
2479 apply_config( console, &config );
2480 return TRUE;
2483 void init_message_window( struct console *console )
2485 WNDCLASSW wndclass;
2487 wndclass.style = CS_DBLCLKS;
2488 wndclass.lpfnWndProc = window_proc;
2489 wndclass.cbClsExtra = 0;
2490 wndclass.cbWndExtra = sizeof(DWORD_PTR);
2491 wndclass.hInstance = GetModuleHandleW( NULL );
2492 wndclass.hIcon = 0;
2493 wndclass.hCursor = 0;
2494 wndclass.hbrBackground = GetStockObject( BLACK_BRUSH );
2495 wndclass.lpszMenuName = NULL;
2496 wndclass.lpszClassName = L"WineConsoleClass";
2497 RegisterClassW(&wndclass);
2499 CreateWindowW( wndclass.lpszClassName, NULL,
2500 WS_OVERLAPPED|WS_CAPTION|WS_SYSMENU|WS_THICKFRAME|WS_MINIMIZEBOX|
2501 WS_MAXIMIZEBOX|WS_HSCROLL|WS_VSCROLL, CW_USEDEFAULT, CW_USEDEFAULT,
2502 0, 0, HWND_MESSAGE, 0, wndclass.hInstance, console );