kernelbase: Reimplement Internal_EnumCalendarInfo() using the locale.nls data.
[wine.git] / programs / conhost / window.c
blobfb02ef9fd945ae89a0746ce430d799ddf7adcc18
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 %s registry settings.\n", wine_dbgstr_w( key_name ));
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 /* read global settings */
269 if (!RegOpenKeyW( HKEY_CURRENT_USER, L"Console", &key ))
271 load_registry_key( key, config );
272 /* if requested, load part related to console title */
273 if (key_name && !RegOpenKeyW( key, key_name, &app_key ))
275 load_registry_key( app_key, config );
276 RegCloseKey( app_key );
278 RegCloseKey( key );
280 TRACE( "%s\n", debugstr_config( config ));
283 static void save_registry_key( HKEY key, const struct console_config *config )
285 DWORD val, width, height, i;
286 WCHAR color_name[13];
288 TRACE( "%s\n", debugstr_config( config ));
290 for (i = 0; i < ARRAY_SIZE(config->color_map); i++)
292 wsprintfW( color_name, L"ColorTable%02d", i );
293 val = config->color_map[i];
294 RegSetValueExW( key, color_name, 0, REG_DWORD, (BYTE *)&val, sizeof(val) );
297 val = config->cursor_size;
298 RegSetValueExW( key, L"CursorSize", 0, REG_DWORD, (BYTE *)&val, sizeof(val) );
300 val = config->cursor_visible;
301 RegSetValueExW( key, L"CursorVisible", 0, REG_DWORD, (BYTE *)&val, sizeof(val) );
303 val = config->edition_mode;
304 RegSetValueExW( key, L"EditionMode", 0, REG_DWORD, (BYTE *)&val, sizeof(val) );
306 RegSetValueExW( key, L"FaceName", 0, REG_SZ, (BYTE *)&config->face_name,
307 (lstrlenW(config->face_name) + 1) * sizeof(WCHAR) );
309 val = config->font_pitch_family;
310 RegSetValueExW( key, L"FontPitchFamily", 0, REG_DWORD, (BYTE *)&val, sizeof(val) );
312 width = MulDiv( config->cell_width, USER_DEFAULT_SCREEN_DPI, GetDpiForSystem() );
313 height = MulDiv( config->cell_height, USER_DEFAULT_SCREEN_DPI, GetDpiForSystem() );
314 val = MAKELONG( width, height );
315 RegSetValueExW( key, L"FontSize", 0, REG_DWORD, (BYTE *)&val, sizeof(val) );
317 val = config->font_weight;
318 RegSetValueExW( key, L"FontWeight", 0, REG_DWORD, (BYTE *)&val, sizeof(val) );
320 val = config->history_size;
321 RegSetValueExW( key, L"HistoryBufferSize", 0, REG_DWORD, (BYTE *)&val, sizeof(val) );
323 val = config->history_mode;
324 RegSetValueExW( key, L"HistoryNoDup", 0, REG_DWORD, (BYTE *)&val, sizeof(val) );
326 val = config->insert_mode;
327 RegSetValueExW( key, L"InsertMode", 0, REG_DWORD, (BYTE *)&val, sizeof(val) );
329 val = config->menu_mask;
330 RegSetValueExW( key, L"MenuMask", 0, REG_DWORD, (BYTE *)&val, sizeof(val) );
332 val = config->popup_attr;
333 RegSetValueExW( key, L"PopupColors", 0, REG_DWORD, (BYTE *)&val, sizeof(val) );
335 val = config->quick_edit;
336 RegSetValueExW( key, L"QuickEdit", 0, REG_DWORD, (BYTE *)&val, sizeof(val) );
338 val = MAKELONG(config->sb_width, config->sb_height);
339 RegSetValueExW( key, L"ScreenBufferSize", 0, REG_DWORD, (BYTE *)&val, sizeof(val) );
341 val = config->attr;
342 RegSetValueExW( key, L"ScreenColors", 0, REG_DWORD, (BYTE *)&val, sizeof(val) );
344 val = MAKELONG( config->win_width, config->win_height );
345 RegSetValueExW( key, L"WindowSize", 0, REG_DWORD, (BYTE *)&val, sizeof(val) );
348 static void save_config( const WCHAR *key_name, const struct console_config *config )
350 HKEY key, app_key;
352 TRACE( "%s %s\n", debugstr_w( key_name ), debugstr_config( config ));
354 if (RegCreateKeyW( HKEY_CURRENT_USER, L"Console", &key ))
356 ERR("Can't open registry for saving\n");
357 return;
360 if (key_name)
362 if (RegCreateKeyW( key, key_name, &app_key ))
364 ERR("Can't open registry for saving\n");
366 else
368 /* FIXME: maybe only save the values different from the default value ? */
369 save_registry_key( app_key, config );
370 RegCloseKey( app_key );
373 else save_registry_key( key, config );
374 RegCloseKey(key);
377 /* fill memory DC with current cells values */
378 static void fill_mem_dc( struct console *console, const RECT *update )
380 unsigned int i, j, k;
381 unsigned int attr;
382 char_info_t *cell;
383 HFONT old_font;
384 HBRUSH brush;
385 WCHAR *line;
386 INT *dx;
387 RECT r;
389 if (!console->window->font || !console->window->bitmap)
390 return;
392 if (!(line = malloc( (update->right - update->left + 1) * sizeof(WCHAR))) ) return;
393 dx = malloc( (update->right - update->left + 1) * sizeof(*dx) );
395 old_font = SelectObject( console->window->mem_dc, console->window->font );
396 for (j = update->top; j <= update->bottom; j++)
398 cell = &console->active->data[j * console->active->width];
399 for (i = update->left; i <= update->right; i++)
401 attr = cell[i].attr;
402 SetBkColor( console->window->mem_dc, console->active->color_map[(attr >> 4) & 0x0F] );
403 SetTextColor( console->window->mem_dc, console->active->color_map[attr & 0x0F] );
404 for (k = i; k <= update->right && cell[k].attr == attr; k++)
406 line[k - i] = cell[k].ch;
407 dx[k - i] = console->active->font.width;
409 ExtTextOutW( console->window->mem_dc, i * console->active->font.width,
410 j * console->active->font.height, 0, NULL, line, k - i, dx );
411 if (console->window->ext_leading &&
412 (brush = CreateSolidBrush( console->active->color_map[(attr >> 4) & 0x0F] )))
414 r.left = i * console->active->font.width;
415 r.top = (j + 1) * console->active->font.height - console->window->ext_leading;
416 r.right = k * console->active->font.width;
417 r.bottom = (j + 1) * console->active->font.height;
418 FillRect( console->window->mem_dc, &r, brush );
419 DeleteObject( brush );
421 i = k - 1;
424 SelectObject( console->window->mem_dc, old_font );
425 free( dx );
426 free( line );
429 /* set a new position for the cursor */
430 static void update_window_cursor( struct console *console )
432 if (!console->active->cursor_visible || console->win != GetFocus()) return;
434 SetCaretPos( (get_bounded_cursor_x( console->active ) - console->active->win.left) * console->active->font.width,
435 (console->active->cursor_y - console->active->win.top) * console->active->font.height );
436 ShowCaret( console->win );
439 /* sets a new shape for the cursor */
440 static void shape_cursor( struct console *console )
442 int size = console->active->cursor_size;
444 if (console->active->cursor_visible && console->win == GetFocus()) DestroyCaret();
445 if (console->window->cursor_bitmap) DeleteObject( console->window->cursor_bitmap );
446 console->window->cursor_bitmap = NULL;
447 console->window->cursor_visible = FALSE;
449 if (size != 100)
451 int w16b; /* number of bytes per row, aligned on word size */
452 int i, j, nbl;
453 BYTE *ptr;
455 w16b = ((console->active->font.width + 15) & ~15) / 8;
456 ptr = calloc( w16b, console->active->font.height );
457 if (!ptr) return;
458 nbl = max( (console->active->font.height * size) / 100, 1 );
459 for (j = console->active->font.height - nbl; j < console->active->font.height; j++)
461 for (i = 0; i < console->active->font.width; i++)
463 ptr[w16b * j + (i / 8)] |= 0x80 >> (i & 7);
466 console->window->cursor_bitmap = CreateBitmap( console->active->font.width,
467 console->active->font.height, 1, 1, ptr );
468 free(ptr);
472 static void update_window( struct console *console )
474 unsigned int win_width, win_height;
475 BOOL update_all = FALSE;
476 int dx, dy;
477 RECT r;
479 console->window->update_state = UPDATE_BUSY;
481 if (console->window->sb_width != console->active->width ||
482 console->window->sb_height != console->active->height ||
483 (!console->window->bitmap && IsWindowVisible( console->win )))
485 console->window->sb_width = console->active->width;
486 console->window->sb_height = console->active->height;
488 if (console->active->width && console->active->height && console->window->font)
490 HBITMAP bitmap;
491 HDC dc;
492 RECT r;
494 if (!(dc = GetDC( console->win ))) return;
496 bitmap = CreateCompatibleBitmap( dc,
497 console->active->width * console->active->font.width,
498 console->active->height * console->active->font.height );
499 ReleaseDC( console->win, dc );
500 SelectObject( console->window->mem_dc, bitmap );
502 if (console->window->bitmap) DeleteObject( console->window->bitmap );
503 console->window->bitmap = bitmap;
504 SetRect( &r, 0, 0, console->active->width - 1, console->active->height - 1 );
505 fill_mem_dc( console, &r );
508 empty_update_rect( console->active, &console->window->update );
509 update_all = TRUE;
512 /* compute window size from desired client size */
513 win_width = console->active->win.right - console->active->win.left + 1;
514 win_height = console->active->win.bottom - console->active->win.top + 1;
516 if (update_all || win_width != console->window->win_width ||
517 win_height != console->window->win_height)
519 console->window->win_width = win_width;
520 console->window->win_height = win_height;
522 r.left = r.top = 0;
523 r.right = win_width * console->active->font.width;
524 r.bottom = win_height * console->active->font.height;
525 AdjustWindowRect( &r, GetWindowLongW( console->win, GWL_STYLE ), FALSE );
527 dx = dy = 0;
528 if (console->active->width > win_width)
530 dy = GetSystemMetrics( SM_CYHSCROLL );
531 SetScrollRange( console->win, SB_HORZ, 0, console->active->width - win_width, FALSE );
532 SetScrollPos( console->win, SB_VERT, console->active->win.top, FALSE );
533 ShowScrollBar( console->win, SB_HORZ, TRUE );
535 else
537 ShowScrollBar( console->win, SB_HORZ, FALSE );
540 if (console->active->height > win_height)
542 dx = GetSystemMetrics( SM_CXVSCROLL );
543 SetScrollRange( console->win, SB_VERT, 0, console->active->height - win_height, FALSE );
544 SetScrollPos( console->win, SB_VERT, console->active->win.top, FALSE );
545 ShowScrollBar( console->win, SB_VERT, TRUE );
547 else
548 ShowScrollBar( console->win, SB_VERT, FALSE );
550 dx += r.right - r.left;
551 dy += r.bottom - r.top;
552 SetWindowPos( console->win, 0, 0, 0, dx, dy, SWP_NOMOVE | SWP_NOZORDER | SWP_NOACTIVATE );
554 SystemParametersInfoW( SPI_GETWORKAREA, 0, &r, 0 );
555 console->active->max_width = (r.right - r.left) / console->active->font.width;
556 console->active->max_height = (r.bottom - r.top - GetSystemMetrics( SM_CYCAPTION )) /
557 console->active->font.height;
559 InvalidateRect( console->win, NULL, FALSE );
560 UpdateWindow( console->win );
561 update_all = TRUE;
563 else if (console->active->win.left != console->window->win_pos.X ||
564 console->active->win.top != console->window->win_pos.Y)
566 ScrollWindow( console->win,
567 (console->window->win_pos.X - console->active->win.left) * console->active->font.width,
568 (console->window->win_pos.Y - console->active->win.top) * console->active->font.height,
569 NULL, NULL );
570 SetScrollPos( console->win, SB_HORZ, console->active->win.left, TRUE );
571 SetScrollPos( console->win, SB_VERT, console->active->win.top, TRUE );
572 InvalidateRect( console->win, NULL, FALSE );
575 console->window->win_pos.X = console->active->win.left;
576 console->window->win_pos.Y = console->active->win.top;
578 if (console->window->update.top <= console->window->update.bottom &&
579 console->window->update.left <= console->window->update.right)
581 RECT *update = &console->window->update;
582 r.left = (update->left - console->active->win.left) * console->active->font.width;
583 r.right = (update->right - console->active->win.left + 1) * console->active->font.width;
584 r.top = (update->top - console->active->win.top) * console->active->font.height;
585 r.bottom = (update->bottom - console->active->win.top + 1) * console->active->font.height;
586 fill_mem_dc( console, update );
587 empty_update_rect( console->active, &console->window->update );
588 InvalidateRect( console->win, &r, FALSE );
589 UpdateWindow( console->win );
592 if (update_all || console->active->cursor_size != console->window->cursor_size)
594 console->window->cursor_size = console->active->cursor_size;
595 shape_cursor( console );
598 if (console->active->cursor_visible != console->window->cursor_visible)
600 console->window->cursor_visible = console->active->cursor_visible;
601 if (console->win == GetFocus())
603 if (console->window->cursor_visible)
604 CreateCaret( console->win, console->window->cursor_bitmap,
605 console->active->font.width, console->active->font.height );
606 else
607 DestroyCaret();
611 if (update_all || get_bounded_cursor_x( console->active ) != console->window->cursor_pos.X ||
612 console->active->cursor_y != console->window->cursor_pos.Y)
614 console->window->cursor_pos.X = get_bounded_cursor_x( console->active );
615 console->window->cursor_pos.Y = console->active->cursor_y;
616 update_window_cursor( console );
619 console->window->update_state = UPDATE_NONE;
622 /* get the relevant information from the font described in lf and store them in config */
623 static HFONT select_font_config( struct console_config *config, unsigned int cp, HWND hwnd,
624 const LOGFONTW *lf )
626 HFONT font, old_font;
627 TEXTMETRICW tm;
628 CPINFO cpinfo;
629 HDC dc;
631 if (!(dc = GetDC( hwnd ))) return NULL;
632 if (!(font = CreateFontIndirectW( lf )))
634 ReleaseDC( hwnd, dc );
635 return NULL;
638 old_font = SelectObject( dc, font );
639 GetTextMetricsW( dc, &tm );
640 SelectObject( dc, old_font );
641 ReleaseDC( hwnd, dc );
643 config->cell_width = tm.tmAveCharWidth;
644 config->cell_height = tm.tmHeight + tm.tmExternalLeading;
645 config->font_weight = tm.tmWeight;
646 lstrcpyW( config->face_name, lf->lfFaceName );
648 /* FIXME: use maximum width for DBCS codepages since some chars take two cells */
649 if (GetCPInfo( cp, &cpinfo ) && cpinfo.MaxCharSize == 2)
650 config->cell_width = tm.tmMaxCharWidth;
652 return font;
655 static void fill_logfont( LOGFONTW *lf, const WCHAR *face_name, size_t face_name_size,
656 unsigned int height, unsigned int weight )
658 lf->lfHeight = height;
659 lf->lfWidth = 0;
660 lf->lfEscapement = 0;
661 lf->lfOrientation = 0;
662 lf->lfWeight = weight;
663 lf->lfItalic = FALSE;
664 lf->lfUnderline = FALSE;
665 lf->lfStrikeOut = FALSE;
666 lf->lfCharSet = DEFAULT_CHARSET;
667 lf->lfOutPrecision = OUT_DEFAULT_PRECIS;
668 lf->lfClipPrecision = CLIP_DEFAULT_PRECIS;
669 lf->lfQuality = DEFAULT_QUALITY;
670 lf->lfPitchAndFamily = FIXED_PITCH | FF_DONTCARE;
671 face_name_size = min( face_name_size, sizeof(lf->lfFaceName) - sizeof(WCHAR) );
672 memcpy( lf->lfFaceName, face_name, face_name_size );
673 lf->lfFaceName[face_name_size / sizeof(WCHAR)] = 0;
676 static BOOL set_console_font( struct console *console, const LOGFONTW *logfont )
678 struct font_info *font_info = &console->active->font;
679 HFONT font, old_font;
680 TEXTMETRICW tm;
681 CPINFO cpinfo;
682 HDC dc;
684 TRACE( "%s\n", debugstr_logfont( logfont, 0 ));
686 if (console->window->font && logfont->lfHeight == console->active->font.height &&
687 logfont->lfWeight == console->active->font.weight &&
688 !logfont->lfItalic && !logfont->lfUnderline && !logfont->lfStrikeOut &&
689 console->active->font.face_len == wcslen( logfont->lfFaceName ) &&
690 !memcmp( logfont->lfFaceName, console->active->font.face_name,
691 console->active->font.face_len * sizeof(WCHAR) ))
693 TRACE( "equal to current\n" );
694 return TRUE;
697 if (!(dc = GetDC( console->win ))) return FALSE;
698 if (!(font = CreateFontIndirectW( logfont )))
700 ReleaseDC( console->win, dc );
701 return FALSE;
704 old_font = SelectObject( dc, font );
705 GetTextMetricsW( dc, &tm );
706 SelectObject( dc, old_font );
707 ReleaseDC( console->win, dc );
709 font_info->width = tm.tmAveCharWidth;
710 font_info->height = tm.tmHeight + tm.tmExternalLeading;
711 font_info->pitch_family = tm.tmPitchAndFamily;
712 font_info->weight = tm.tmWeight;
714 free( font_info->face_name );
715 font_info->face_len = wcslen( logfont->lfFaceName );
716 font_info->face_name = malloc( font_info->face_len * sizeof(WCHAR) );
717 memcpy( font_info->face_name, logfont->lfFaceName, font_info->face_len * sizeof(WCHAR) );
719 /* FIXME: use maximum width for DBCS codepages since some chars take two cells */
720 if (GetCPInfo( console->output_cp, &cpinfo ) && cpinfo.MaxCharSize == 2)
721 font_info->width = tm.tmMaxCharWidth;
723 if (console->window->font) DeleteObject( console->window->font );
724 console->window->font = font;
725 console->window->ext_leading = tm.tmExternalLeading;
727 if (console->window->bitmap)
729 DeleteObject(console->window->bitmap);
730 console->window->bitmap = NULL;
732 return TRUE;
735 struct font_chooser
737 struct console *console;
738 int pass;
739 BOOL done;
742 /* check if the font described in tm is usable as a font for the renderer */
743 static BOOL validate_font_metric( struct console *console, const TEXTMETRICW *tm,
744 DWORD type, int pass )
746 switch (pass) /* we get increasingly lenient in later passes */
748 case 0:
749 if (type & RASTER_FONTTYPE) return FALSE;
750 /* fall through */
751 case 1:
752 if (type & RASTER_FONTTYPE)
754 if (tm->tmMaxCharWidth * (console->active->win.right - console->active->win.left + 1)
755 >= GetSystemMetrics(SM_CXSCREEN))
756 return FALSE;
757 if (tm->tmHeight * (console->active->win.bottom - console->active->win.top + 1)
758 >= GetSystemMetrics(SM_CYSCREEN))
759 return FALSE;
761 /* fall through */
762 case 2:
763 if (tm->tmCharSet != DEFAULT_CHARSET && tm->tmCharSet != console->window->ui_charset)
764 return FALSE;
765 /* fall through */
766 case 3:
767 if (tm->tmItalic || tm->tmUnderlined || tm->tmStruckOut) return FALSE;
768 break;
770 return TRUE;
773 /* check if the font family described in lf is usable as a font for the renderer */
774 static BOOL validate_font( struct console *console, const LOGFONTW *lf, int pass )
776 switch (pass) /* we get increasingly lenient in later passes */
778 case 0:
779 case 1:
780 case 2:
781 if (lf->lfCharSet != DEFAULT_CHARSET && lf->lfCharSet != console->window->ui_charset)
782 return FALSE;
783 /* fall through */
784 case 3:
785 if ((lf->lfPitchAndFamily & 3) != FIXED_PITCH) return FALSE;
786 /* fall through */
787 case 4:
788 if (lf->lfFaceName[0] == '@') return FALSE;
789 break;
791 return TRUE;
794 /* helper functions to get a decent font for the renderer */
795 static int WINAPI get_first_font_sub_enum( const LOGFONTW *lf, const TEXTMETRICW *tm,
796 DWORD font_type, LPARAM lparam)
798 struct font_chooser *fc = (struct font_chooser *)lparam;
800 TRACE( "%s\n", debugstr_textmetric( tm, font_type ));
802 if (validate_font_metric( fc->console, tm, font_type, fc->pass ))
804 LOGFONTW mlf = *lf;
806 /* Use the default sizes for the font (this is needed, especially for
807 * TrueType fonts, so that we get a decent size, not the max size)
809 mlf.lfWidth = fc->console->active->font.width;
810 mlf.lfHeight = fc->console->active->font.height;
811 if (!mlf.lfHeight)
812 mlf.lfHeight = MulDiv( 16, GetDpiForSystem(), USER_DEFAULT_SCREEN_DPI );
814 if (set_console_font( fc->console, &mlf ))
816 struct console_config config;
818 fc->done = 1;
820 /* since we've modified the current config with new font information,
821 * set this information as the new default.
823 load_config( fc->console->window->config_key, &config );
824 config.cell_width = fc->console->active->font.width;
825 config.cell_height = fc->console->active->font.height;
826 memcpy( config.face_name, fc->console->active->font.face_name,
827 fc->console->active->font.face_len * sizeof(WCHAR) );
828 config.face_name[fc->console->active->font.face_len] = 0;
830 /* Force also its writing back to the registry so that we can get it
831 * the next time.
833 save_config( fc->console->window->config_key, &config );
834 return 0;
837 return 1;
840 static int WINAPI get_first_font_enum( const LOGFONTW *lf, const TEXTMETRICW *tm,
841 DWORD font_type, LPARAM lparam )
843 struct font_chooser *fc = (struct font_chooser *)lparam;
845 TRACE("%s\n", debugstr_logfont( lf, font_type ));
847 if (validate_font( fc->console, lf, fc->pass ))
849 EnumFontFamiliesW( fc->console->window->mem_dc, lf->lfFaceName,
850 get_first_font_sub_enum, lparam );
851 return !fc->done; /* we just need the first matching one... */
853 return 1;
857 /* sets logfont as the new font for the console */
858 void update_console_font( struct console *console, const WCHAR *face_name, size_t face_name_size,
859 unsigned int height, unsigned int weight )
861 struct font_chooser fc;
862 LOGFONTW lf;
864 if (face_name[0] && height && weight)
866 fill_logfont( &lf, face_name, face_name_size, height, weight );
867 if (set_console_font( console, &lf )) return;
870 /* try to find an acceptable font */
871 WARN( "Couldn't match the font from registry, trying to find one\n" );
872 fc.console = console;
873 fc.done = FALSE;
874 for (fc.pass = 0; fc.pass <= 5; fc.pass++)
876 EnumFontFamiliesW( console->window->mem_dc, NULL, get_first_font_enum, (LPARAM)&fc );
877 if (fc.done) return;
879 ERR( "Couldn't find a decent font\n" );
882 /* get a cell from a relative coordinate in window (takes into account the scrolling) */
883 static COORD get_cell( struct console *console, LPARAM lparam )
885 COORD c;
886 c.X = console->active->win.left + (short)LOWORD(lparam) / console->active->font.width;
887 c.Y = console->active->win.top + (short)HIWORD(lparam) / console->active->font.height;
888 return c;
891 /* get the console bit mask equivalent to the VK_ status in key state */
892 static DWORD get_ctrl_state( BYTE *key_state)
894 unsigned int ret = 0;
896 GetKeyboardState(key_state);
897 if (key_state[VK_SHIFT] & 0x80) ret |= SHIFT_PRESSED;
898 if (key_state[VK_LCONTROL] & 0x80) ret |= LEFT_CTRL_PRESSED;
899 if (key_state[VK_RCONTROL] & 0x80) ret |= RIGHT_CTRL_PRESSED;
900 if (key_state[VK_LMENU] & 0x80) ret |= LEFT_ALT_PRESSED;
901 if (key_state[VK_RMENU] & 0x80) ret |= RIGHT_ALT_PRESSED;
902 if (key_state[VK_CAPITAL] & 0x01) ret |= CAPSLOCK_ON;
903 if (key_state[VK_NUMLOCK] & 0x01) ret |= NUMLOCK_ON;
904 if (key_state[VK_SCROLL] & 0x01) ret |= SCROLLLOCK_ON;
906 return ret;
909 /* get the selection rectangle */
910 static void get_selection_rect( struct console *console, RECT *r )
912 r->left = (min(console->window->selection_start.X, console->window->selection_end.X) -
913 console->active->win.left) * console->active->font.width;
914 r->top = (min(console->window->selection_start.Y, console->window->selection_end.Y) -
915 console->active->win.top) * console->active->font.height;
916 r->right = (max(console->window->selection_start.X, console->window->selection_end.X) + 1 -
917 console->active->win.left) * console->active->font.width;
918 r->bottom = (max(console->window->selection_start.Y, console->window->selection_end.Y) + 1 -
919 console->active->win.top) * console->active->font.height;
922 static void update_selection( struct console *console, HDC ref_dc )
924 HDC dc;
925 RECT r;
927 get_selection_rect( console, &r );
928 dc = ref_dc ? ref_dc : GetDC( console->win );
929 if (!dc) return;
931 if (console->win == GetFocus() && console->active->cursor_visible)
932 HideCaret( console->win );
933 InvertRect( dc, &r );
934 if (dc != ref_dc)
935 ReleaseDC( console->win, dc );
936 if (console->win == GetFocus() && console->active->cursor_visible)
937 ShowCaret( console->win );
940 static void move_selection( struct console *console, COORD c1, COORD c2 )
942 RECT r;
943 HDC dc;
945 if (c1.X < 0 || c1.X >= console->active->width ||
946 c2.X < 0 || c2.X >= console->active->width ||
947 c1.Y < 0 || c1.Y >= console->active->height ||
948 c2.Y < 0 || c2.Y >= console->active->height)
949 return;
951 get_selection_rect( console, &r );
952 dc = GetDC( console->win );
953 if (dc)
955 if (console->win == GetFocus() && console->active->cursor_visible)
956 HideCaret( console->win );
957 InvertRect( dc, &r );
959 console->window->selection_start = c1;
960 console->window->selection_end = c2;
961 if (dc)
963 get_selection_rect( console, &r );
964 InvertRect( dc, &r );
965 ReleaseDC( console->win, dc );
966 if (console->win == GetFocus() && console->active->cursor_visible)
967 ShowCaret( console->win );
971 /* copies the current selection into the clipboard */
972 static void copy_selection( struct console *console )
974 unsigned int w, h;
975 WCHAR *p, *buf;
976 HANDLE mem;
978 w = abs( console->window->selection_start.X - console->window->selection_end.X ) + 1;
979 h = abs( console->window->selection_start.Y - console->window->selection_end.Y ) + 1;
981 if (!OpenClipboard( console->win )) return;
982 EmptyClipboard();
984 mem = GlobalAlloc( GMEM_MOVEABLE, (w + 1) * h * sizeof(WCHAR) );
985 if (mem && (p = buf = GlobalLock( mem )))
987 int x, y;
988 COORD c;
990 c.X = min( console->window->selection_start.X, console->window->selection_end.X );
991 c.Y = min( console->window->selection_start.Y, console->window->selection_end.Y );
993 for (y = c.Y; y < c.Y + h; y++)
995 WCHAR *end;
997 for (x = c.X; x < c.X + w; x++)
998 p[x - c.X] = console->active->data[y * console->active->width + x].ch;
1000 /* strip spaces from the end of the line */
1001 end = p + w;
1002 while (end > p && *(end - 1) == ' ')
1003 end--;
1004 *end = (y < c.Y + h - 1) ? '\n' : '\0';
1005 p = end + 1;
1008 TRACE( "%s\n", debugstr_w( buf ));
1009 if (p - buf != (w + 1) * h)
1011 HANDLE new_mem;
1012 new_mem = GlobalReAlloc( mem, (p - buf) * sizeof(WCHAR), GMEM_MOVEABLE );
1013 if (new_mem) mem = new_mem;
1015 GlobalUnlock( mem );
1016 SetClipboardData( CF_UNICODETEXT, mem );
1018 CloseClipboard();
1021 static void paste_clipboard( struct console *console )
1023 WCHAR *ptr;
1024 HANDLE h;
1026 if (!OpenClipboard( console->win )) return;
1027 h = GetClipboardData( CF_UNICODETEXT );
1028 if (h && (ptr = GlobalLock( h )))
1030 unsigned int i, len = GlobalSize(h) / sizeof(WCHAR);
1031 INPUT_RECORD ir[2];
1032 SHORT sh;
1034 ir[0].EventType = KEY_EVENT;
1035 ir[0].Event.KeyEvent.wRepeatCount = 0;
1036 ir[0].Event.KeyEvent.dwControlKeyState = 0;
1037 ir[0].Event.KeyEvent.bKeyDown = TRUE;
1039 /* generate the corresponding input records */
1040 for (i = 0; i < len; i++)
1042 /* FIXME: the modifying keys are not generated (shift, ctrl...) */
1043 sh = VkKeyScanW( ptr[i] );
1044 ir[0].Event.KeyEvent.wVirtualKeyCode = LOBYTE(sh);
1045 ir[0].Event.KeyEvent.wVirtualScanCode = MapVirtualKeyW( LOBYTE(sh), 0 );
1046 ir[0].Event.KeyEvent.uChar.UnicodeChar = ptr[i];
1048 ir[1] = ir[0];
1049 ir[1].Event.KeyEvent.bKeyDown = FALSE;
1051 write_console_input( console, ir, 2, i == len - 1 );
1053 GlobalUnlock( h );
1056 CloseClipboard();
1059 /* handle keys while selecting an area */
1060 static void handle_selection_key( struct console *console, BOOL down, WPARAM wparam, LPARAM lparam )
1062 BYTE key_state[256];
1063 COORD c1, c2;
1064 DWORD state;
1066 if (!down) return;
1067 state = get_ctrl_state( key_state ) & ~(CAPSLOCK_ON|NUMLOCK_ON|SCROLLLOCK_ON);
1069 switch (state)
1071 case 0:
1072 switch (wparam)
1074 case VK_RETURN:
1075 console->window->in_selection = FALSE;
1076 update_selection( console, 0 );
1077 copy_selection( console );
1078 return;
1079 case VK_RIGHT:
1080 c1 = console->window->selection_start;
1081 c2 = console->window->selection_end;
1082 c1.X++; c2.X++;
1083 move_selection( console, c1, c2 );
1084 return;
1085 case VK_LEFT:
1086 c1 = console->window->selection_start;
1087 c2 = console->window->selection_end;
1088 c1.X--; c2.X--;
1089 move_selection( console, c1, c2 );
1090 return;
1091 case VK_UP:
1092 c1 = console->window->selection_start;
1093 c2 = console->window->selection_end;
1094 c1.Y--; c2.Y--;
1095 move_selection( console, c1, c2 );
1096 return;
1097 case VK_DOWN:
1098 c1 = console->window->selection_start;
1099 c2 = console->window->selection_end;
1100 c1.Y++; c2.Y++;
1101 move_selection( console, c1, c2 );
1102 return;
1104 break;
1105 case SHIFT_PRESSED:
1106 switch (wparam)
1108 case VK_RIGHT:
1109 c1 = console->window->selection_start;
1110 c2 = console->window->selection_end;
1111 c2.X++;
1112 move_selection( console, c1, c2 );
1113 return;
1114 case VK_LEFT:
1115 c1 = console->window->selection_start;
1116 c2 = console->window->selection_end;
1117 c2.X--;
1118 move_selection( console, c1, c2 );
1119 return;
1120 case VK_UP:
1121 c1 = console->window->selection_start;
1122 c2 = console->window->selection_end;
1123 c2.Y--;
1124 move_selection( console, c1, c2 );
1125 return;
1126 case VK_DOWN:
1127 c1 = console->window->selection_start;
1128 c2 = console->window->selection_end;
1129 c2.Y++;
1130 move_selection( console, c1, c2 );
1131 return;
1133 break;
1136 if (wparam < VK_SPACE) /* Shift, Alt, Ctrl, Num Lock etc. */
1137 return;
1139 update_selection( console, 0 );
1140 console->window->in_selection = FALSE;
1143 /* generate input_record from windows WM_KEYUP/WM_KEYDOWN messages */
1144 static void record_key_input( struct console *console, BOOL down, WPARAM wparam, LPARAM lparam )
1146 static WCHAR last; /* keep last char seen as feed for key up message */
1147 BYTE key_state[256];
1148 INPUT_RECORD ir;
1149 WCHAR buf[2];
1151 ir.EventType = KEY_EVENT;
1152 ir.Event.KeyEvent.bKeyDown = down;
1153 ir.Event.KeyEvent.wRepeatCount = LOWORD(lparam);
1154 ir.Event.KeyEvent.wVirtualKeyCode = wparam;
1155 ir.Event.KeyEvent.wVirtualScanCode = HIWORD(lparam) & 0xFF;
1156 ir.Event.KeyEvent.uChar.UnicodeChar = 0;
1157 ir.Event.KeyEvent.dwControlKeyState = get_ctrl_state( key_state );
1158 if (lparam & (1u << 24)) ir.Event.KeyEvent.dwControlKeyState |= ENHANCED_KEY;
1160 if (down)
1162 switch (ToUnicode(wparam, HIWORD(lparam), key_state, buf, 2, 0))
1164 case 2:
1165 /* FIXME: should generate two events */
1166 /* fall through */
1167 case 1:
1168 last = buf[0];
1169 break;
1170 default:
1171 last = 0;
1172 break;
1175 ir.Event.KeyEvent.uChar.UnicodeChar = last;
1176 if (!down) last = 0; /* FIXME: buggy HACK */
1178 write_console_input( console, &ir, 1, TRUE );
1181 static void record_mouse_input( struct console *console, COORD c, WPARAM wparam, DWORD event )
1183 BYTE key_state[256];
1184 INPUT_RECORD ir;
1186 /* MOUSE_EVENTs shouldn't be sent unless ENABLE_MOUSE_INPUT is active */
1187 if (!(console->mode & ENABLE_MOUSE_INPUT)) return;
1189 ir.EventType = MOUSE_EVENT;
1190 ir.Event.MouseEvent.dwMousePosition = c;
1191 ir.Event.MouseEvent.dwButtonState = 0;
1192 if (wparam & MK_LBUTTON) ir.Event.MouseEvent.dwButtonState |= FROM_LEFT_1ST_BUTTON_PRESSED;
1193 if (wparam & MK_MBUTTON) ir.Event.MouseEvent.dwButtonState |= FROM_LEFT_2ND_BUTTON_PRESSED;
1194 if (wparam & MK_RBUTTON) ir.Event.MouseEvent.dwButtonState |= RIGHTMOST_BUTTON_PRESSED;
1195 if (wparam & MK_CONTROL) ir.Event.MouseEvent.dwButtonState |= LEFT_CTRL_PRESSED;
1196 if (wparam & MK_SHIFT) ir.Event.MouseEvent.dwButtonState |= SHIFT_PRESSED;
1197 if (event == MOUSE_WHEELED) ir.Event.MouseEvent.dwButtonState |= wparam & 0xFFFF0000;
1198 ir.Event.MouseEvent.dwControlKeyState = get_ctrl_state( key_state );
1199 ir.Event.MouseEvent.dwEventFlags = event;
1201 write_console_input( console, &ir, 1, TRUE );
1204 struct dialog_info
1206 struct console *console;
1207 struct console_config config;
1208 HWND dialog; /* handle to active propsheet */
1211 /* dialog proc for the option property sheet */
1212 static INT_PTR WINAPI option_dialog_proc( HWND dialog, UINT msg, WPARAM wparam, LPARAM lparam )
1214 struct dialog_info *di;
1215 unsigned int idc;
1217 switch (msg)
1219 case WM_INITDIALOG:
1220 di = (struct dialog_info *)((PROPSHEETPAGEA *)lparam)->lParam;
1221 di->dialog = dialog;
1222 SetWindowLongPtrW( dialog, DWLP_USER, (LONG_PTR)di );
1224 SendMessageW( GetDlgItem( dialog, IDC_OPT_HIST_SIZE_UD ), UDM_SETRANGE, 0, MAKELPARAM(500, 0) );
1226 if (di->config.cursor_size <= 25) idc = IDC_OPT_CURSOR_SMALL;
1227 else if (di->config.cursor_size <= 50) idc = IDC_OPT_CURSOR_MEDIUM;
1228 else idc = IDC_OPT_CURSOR_LARGE;
1230 SendDlgItemMessageW( dialog, idc, BM_SETCHECK, BST_CHECKED, 0 );
1231 SetDlgItemInt( dialog, IDC_OPT_HIST_SIZE, di->config.history_size, FALSE );
1232 SendDlgItemMessageW( dialog, IDC_OPT_HIST_NODOUBLE, BM_SETCHECK,
1233 (di->config.history_mode) ? BST_CHECKED : BST_UNCHECKED, 0 );
1234 SendDlgItemMessageW( dialog, IDC_OPT_INSERT_MODE, BM_SETCHECK,
1235 (di->config.insert_mode) ? BST_CHECKED : BST_UNCHECKED, 0 );
1236 SendDlgItemMessageW( dialog, IDC_OPT_CONF_CTRL, BM_SETCHECK,
1237 (di->config.menu_mask & MK_CONTROL) ? BST_CHECKED : BST_UNCHECKED, 0 );
1238 SendDlgItemMessageW( dialog, IDC_OPT_CONF_SHIFT, BM_SETCHECK,
1239 (di->config.menu_mask & MK_SHIFT) ? BST_CHECKED : BST_UNCHECKED, 0 );
1240 SendDlgItemMessageW( dialog, IDC_OPT_QUICK_EDIT, BM_SETCHECK,
1241 (di->config.quick_edit) ? BST_CHECKED : BST_UNCHECKED, 0 );
1242 return FALSE; /* because we set the focus */
1244 case WM_COMMAND:
1245 break;
1247 case WM_NOTIFY:
1249 NMHDR *nmhdr = (NMHDR*)lparam;
1250 DWORD val;
1251 BOOL done;
1253 di = (struct dialog_info *)GetWindowLongPtrW( dialog, DWLP_USER );
1255 switch (nmhdr->code)
1257 case PSN_SETACTIVE:
1258 /* needed in propsheet to keep properly the selected radio button
1259 * otherwise, the focus would be set to the first tab stop in the
1260 * propsheet, which would always activate the first radio button
1262 if (IsDlgButtonChecked( dialog, IDC_OPT_CURSOR_SMALL ) == BST_CHECKED)
1263 idc = IDC_OPT_CURSOR_SMALL;
1264 else if (IsDlgButtonChecked( dialog, IDC_OPT_CURSOR_MEDIUM ) == BST_CHECKED)
1265 idc = IDC_OPT_CURSOR_MEDIUM;
1266 else
1267 idc = IDC_OPT_CURSOR_LARGE;
1268 PostMessageW( dialog, WM_NEXTDLGCTL, (WPARAM)GetDlgItem( dialog, idc ), TRUE );
1269 di->dialog = dialog;
1270 break;
1271 case PSN_APPLY:
1272 if (IsDlgButtonChecked( dialog, IDC_OPT_CURSOR_SMALL ) == BST_CHECKED) val = 25;
1273 else if (IsDlgButtonChecked( dialog, IDC_OPT_CURSOR_MEDIUM ) == BST_CHECKED) val = 50;
1274 else val = 100;
1275 di->config.cursor_size = val;
1277 val = GetDlgItemInt( dialog, IDC_OPT_HIST_SIZE, &done, FALSE );
1278 if (done) di->config.history_size = val;
1280 val = (IsDlgButtonChecked( dialog, IDC_OPT_HIST_NODOUBLE ) & BST_CHECKED) != 0;
1281 di->config.history_mode = val;
1283 val = (IsDlgButtonChecked( dialog, IDC_OPT_INSERT_MODE ) & BST_CHECKED) != 0;
1284 di->config.insert_mode = val;
1286 val = 0;
1287 if (IsDlgButtonChecked( dialog, IDC_OPT_CONF_CTRL ) & BST_CHECKED) val |= MK_CONTROL;
1288 if (IsDlgButtonChecked( dialog, IDC_OPT_CONF_SHIFT ) & BST_CHECKED) val |= MK_SHIFT;
1289 di->config.menu_mask = val;
1291 val = (IsDlgButtonChecked( dialog, IDC_OPT_QUICK_EDIT ) & BST_CHECKED) != 0;
1292 di->config.quick_edit = val;
1294 SetWindowLongPtrW( dialog, DWLP_MSGRESULT, PSNRET_NOERROR );
1295 return TRUE;
1296 default:
1297 return FALSE;
1299 break;
1301 default:
1302 return FALSE;
1304 return TRUE;
1307 static COLORREF get_color( struct dialog_info *di, unsigned int idc )
1309 LONG_PTR index;
1311 index = GetWindowLongPtrW(GetDlgItem( di->dialog, idc ), 0);
1312 return di->config.color_map[index];
1315 /* window proc for font previewer in font property sheet */
1316 static LRESULT WINAPI font_preview_proc( HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam )
1318 switch (msg)
1320 case WM_CREATE:
1321 SetWindowLongPtrW( hwnd, 0, 0 );
1322 break;
1324 case WM_GETFONT:
1325 return GetWindowLongPtrW( hwnd, 0 );
1327 case WM_SETFONT:
1328 SetWindowLongPtrW( hwnd, 0, wparam );
1329 if (LOWORD(lparam))
1331 InvalidateRect( hwnd, NULL, TRUE );
1332 UpdateWindow( hwnd );
1334 break;
1336 case WM_DESTROY:
1338 HFONT font = (HFONT)GetWindowLongPtrW( hwnd, 0 );
1339 if (font) DeleteObject( font );
1340 break;
1343 case WM_PAINT:
1345 struct dialog_info *di;
1346 HFONT font, old_font;
1347 PAINTSTRUCT ps;
1349 di = (struct dialog_info *)GetWindowLongPtrW( GetParent( hwnd ), DWLP_USER );
1350 BeginPaint( hwnd, &ps );
1352 font = (HFONT)GetWindowLongPtrW( hwnd, 0 );
1353 if (font)
1355 static const WCHAR ascii[] = L"ASCII: abcXYZ";
1356 COLORREF bkcolor;
1357 WCHAR buf[256];
1358 int len;
1360 old_font = SelectObject( ps.hdc, font );
1361 bkcolor = get_color( di, IDC_FNT_COLOR_BK );
1362 FillRect( ps.hdc, &ps.rcPaint, CreateSolidBrush( bkcolor ));
1363 SetBkColor( ps.hdc, bkcolor );
1364 SetTextColor( ps.hdc, get_color( di, IDC_FNT_COLOR_FG ));
1365 len = LoadStringW( GetModuleHandleW(NULL), IDS_FNT_PREVIEW, buf, ARRAY_SIZE(buf) );
1366 if (len) TextOutW( ps.hdc, 0, 0, buf, len );
1367 TextOutW( ps.hdc, 0, di->config.cell_height, ascii, ARRAY_SIZE(ascii) - 1 );
1368 SelectObject( ps.hdc, old_font );
1370 EndPaint( hwnd, &ps );
1371 break;
1374 default:
1375 return DefWindowProcW( hwnd, msg, wparam, lparam );
1377 return 0;
1380 /* window proc for color previewer */
1381 static LRESULT WINAPI color_preview_proc( HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam )
1383 switch (msg)
1385 case WM_PAINT:
1387 struct dialog_info *di;
1388 PAINTSTRUCT ps;
1389 RECT client, r;
1390 int i, step;
1391 HBRUSH brush;
1393 BeginPaint( hwnd, &ps );
1394 GetClientRect( hwnd, &client );
1395 step = client.right / 8;
1397 di = (struct dialog_info *)GetWindowLongPtrW( GetParent(hwnd), DWLP_USER );
1399 for (i = 0; i < 16; i++)
1401 r.top = (i / 8) * (client.bottom / 2);
1402 r.bottom = r.top + client.bottom / 2;
1403 r.left = (i & 7) * step;
1404 r.right = r.left + step;
1405 brush = CreateSolidBrush( di->config.color_map[i] );
1406 FillRect( ps.hdc, &r, brush );
1407 DeleteObject( brush );
1408 if (GetWindowLongW( hwnd, 0 ) == i)
1410 HPEN old_pen;
1411 int i = 2;
1413 old_pen = SelectObject( ps.hdc, GetStockObject( WHITE_PEN ));
1414 r.right--; r.bottom--;
1415 for (;;)
1417 MoveToEx( ps.hdc, r.left, r.bottom, NULL );
1418 LineTo( ps.hdc, r.left, r.top );
1419 LineTo( ps.hdc, r.right, r.top );
1420 SelectObject( ps.hdc, GetStockObject( BLACK_PEN ));
1421 LineTo( ps.hdc, r.right, r.bottom );
1422 LineTo( ps.hdc, r.left, r.bottom );
1423 if (--i == 0) break;
1424 r.left++; r.top++; r.right--; r.bottom--;
1425 SelectObject( ps.hdc, GetStockObject( WHITE_PEN ));
1427 SelectObject( ps.hdc, old_pen );
1430 EndPaint( hwnd, &ps );
1431 break;
1434 case WM_LBUTTONDOWN:
1436 int i, step;
1437 RECT client;
1439 GetClientRect( hwnd, &client );
1440 step = client.right / 8;
1441 i = (HIWORD(lparam) >= client.bottom / 2) ? 8 : 0;
1442 i += LOWORD(lparam) / step;
1443 SetWindowLongW( hwnd, 0, i );
1444 InvalidateRect( GetDlgItem( GetParent( hwnd ), IDC_FNT_PREVIEW ), NULL, FALSE );
1445 InvalidateRect( hwnd, NULL, FALSE );
1446 break;
1449 default:
1450 return DefWindowProcW( hwnd, msg, wparam, lparam );
1452 return 0;
1455 static BOOL select_font( struct dialog_info *di )
1457 int font_idx, size_idx;
1458 WCHAR face_name[LF_FACESIZE], height_buf[4];
1459 size_t len;
1460 unsigned int font_height;
1461 LOGFONTW lf;
1462 HFONT font, old_font;
1463 DWORD_PTR args[2];
1464 WCHAR buf[256];
1465 WCHAR fmt[128];
1467 font_idx = SendDlgItemMessageW( di->dialog, IDC_FNT_LIST_FONT, LB_GETCURSEL, 0, 0 );
1468 size_idx = SendDlgItemMessageW( di->dialog, IDC_FNT_LIST_SIZE, LB_GETCURSEL, 0, 0 );
1470 if (font_idx < 0 || size_idx < 0)
1471 return FALSE;
1473 len = SendDlgItemMessageW( di->dialog, IDC_FNT_LIST_FONT, LB_GETTEXT, font_idx, (LPARAM)&face_name );
1474 SendDlgItemMessageW( di->dialog, IDC_FNT_LIST_SIZE, LB_GETTEXT, size_idx, (LPARAM)&height_buf );
1475 font_height = _wtoi( height_buf );
1477 fill_logfont( &lf, face_name, len * sizeof(WCHAR), font_height, FW_NORMAL );
1478 font = select_font_config( &di->config, di->console->output_cp, di->console->win, &lf );
1479 if (!font) return FALSE;
1481 if (di->config.cell_height != font_height)
1482 TRACE( "mismatched heights (%u<>%u)\n", di->config.cell_height, font_height );
1484 old_font = (HFONT)SendDlgItemMessageW( di->dialog, IDC_FNT_PREVIEW, WM_GETFONT, 0, 0 );
1485 SendDlgItemMessageW( di->dialog, IDC_FNT_PREVIEW, WM_SETFONT, (WPARAM)font, TRUE );
1486 if (old_font) DeleteObject( old_font );
1488 LoadStringW( GetModuleHandleW(NULL), IDS_FNT_DISPLAY, fmt, ARRAY_SIZE(fmt) );
1489 args[0] = di->config.cell_width;
1490 args[1] = di->config.cell_height;
1491 FormatMessageW( FORMAT_MESSAGE_FROM_STRING|FORMAT_MESSAGE_ARGUMENT_ARRAY,
1492 fmt, 0, 0, buf, ARRAY_SIZE(buf), (__ms_va_list*)args );
1494 SendDlgItemMessageW( di->dialog, IDC_FNT_FONT_INFO, WM_SETTEXT, 0, (LPARAM)buf );
1495 return TRUE;
1498 static BOOL fill_list_size( struct dialog_info *di, BOOL init )
1500 if (init)
1502 static const int sizes[] = {8,9,10,11,12,14,16,18,20,22,24,26,28,36,48,72};
1503 unsigned int i, idx = 4;
1504 WCHAR buf[4];
1506 for (i = 0; i < ARRAY_SIZE(sizes); i++)
1508 wsprintfW( buf, L"%u", sizes[i] );
1509 SendDlgItemMessageW( di->dialog, IDC_FNT_LIST_SIZE, LB_INSERTSTRING, -1, (LPARAM)buf );
1511 if (di->config.cell_height == sizes[i]) idx = i;
1514 SendDlgItemMessageW( di->dialog, IDC_FNT_LIST_SIZE, LB_SETCURSEL, idx, 0 );
1517 select_font( di );
1519 return TRUE;
1522 static int CALLBACK enum_list_font_proc( const LOGFONTW *lf, const TEXTMETRICW *tm,
1523 DWORD font_type, LPARAM lparam )
1525 struct dialog_info *di = (struct dialog_info *)lparam;
1527 if (font_type != TRUETYPE_FONTTYPE) return 1;
1529 TRACE( "%s\n", debugstr_logfont( lf, font_type ));
1531 if (validate_font( di->console, lf, 0 ))
1532 SendDlgItemMessageW( di->dialog, IDC_FNT_LIST_FONT, LB_ADDSTRING, 0, (LPARAM)lf->lfFaceName );
1534 return 1;
1537 static BOOL fill_list_font( struct dialog_info *di )
1539 LOGFONTW lf;
1541 memset( &lf, 0, sizeof(lf) );
1542 lf.lfCharSet = DEFAULT_CHARSET;
1543 lf.lfFaceName[0] = 0;
1544 lf.lfPitchAndFamily = FIXED_PITCH | FF_MODERN;
1546 EnumFontFamiliesExW( di->console->window->mem_dc, &lf, enum_list_font_proc, (LPARAM)di, 0 );
1548 if (SendDlgItemMessageW( di->dialog, IDC_FNT_LIST_FONT, LB_SELECTSTRING,
1549 -1, (LPARAM)di->config.face_name ) == LB_ERR)
1550 SendDlgItemMessageW( di->dialog, IDC_FNT_LIST_FONT, LB_SETCURSEL, 0, 0 );
1552 fill_list_size( di, TRUE );
1554 return TRUE;
1557 /* dialog proc for the font property sheet */
1558 static INT_PTR WINAPI font_dialog_proc( HWND dialog, UINT msg, WPARAM wparam, LPARAM lparam )
1560 struct dialog_info *di;
1562 switch (msg)
1564 case WM_INITDIALOG:
1565 di = (struct dialog_info *)((PROPSHEETPAGEA*)lparam)->lParam;
1566 di->dialog = dialog;
1567 SetWindowLongPtrW( dialog, DWLP_USER, (DWORD_PTR)di );
1568 /* use default system font until user-selected font is applied */
1569 SendDlgItemMessageW( dialog, IDC_FNT_PREVIEW, WM_SETFONT, 0, 0 );
1570 fill_list_font( di );
1571 SetWindowLongW( GetDlgItem( dialog, IDC_FNT_COLOR_BK ), 0, (di->config.attr >> 4) & 0x0F );
1572 SetWindowLongW( GetDlgItem( dialog, IDC_FNT_COLOR_FG ), 0, di->config.attr & 0x0F );
1573 break;
1575 case WM_COMMAND:
1576 di = (struct dialog_info *)GetWindowLongPtrW( dialog, DWLP_USER );
1577 switch (LOWORD(wparam))
1579 case IDC_FNT_LIST_FONT:
1580 if (HIWORD(wparam) == LBN_SELCHANGE)
1581 fill_list_size( di, FALSE );
1582 break;
1583 case IDC_FNT_LIST_SIZE:
1584 if (HIWORD(wparam) == LBN_SELCHANGE)
1585 select_font( di );
1586 break;
1588 break;
1590 case WM_NOTIFY:
1592 NMHDR *nmhdr = (NMHDR*)lparam;
1593 DWORD val;
1595 di = (struct dialog_info*)GetWindowLongPtrW( dialog, DWLP_USER );
1596 switch (nmhdr->code)
1598 case PSN_SETACTIVE:
1599 di->dialog = dialog;
1600 break;
1601 case PSN_APPLY:
1602 val = (GetWindowLongW( GetDlgItem( dialog, IDC_FNT_COLOR_BK ), 0 ) << 4) |
1603 GetWindowLongW( GetDlgItem( dialog, IDC_FNT_COLOR_FG ), 0 );
1604 di->config.attr = val;
1605 SetWindowLongPtrW( dialog, DWLP_MSGRESULT, PSNRET_NOERROR );
1606 return TRUE;
1607 default:
1608 return FALSE;
1610 break;
1612 default:
1613 return FALSE;
1615 return TRUE;
1618 /* dialog proc for the config property sheet */
1619 static INT_PTR WINAPI config_dialog_proc( HWND dialog, UINT msg, WPARAM wparam, LPARAM lparam )
1621 struct dialog_info *di;
1622 int max_ud = 2000;
1624 switch (msg)
1626 case WM_INITDIALOG:
1627 di = (struct dialog_info *)((PROPSHEETPAGEA*)lparam)->lParam;
1628 di->dialog = dialog;
1630 SetWindowLongPtrW( dialog, DWLP_USER, (DWORD_PTR)di );
1631 SetDlgItemInt( dialog, IDC_CNF_SB_WIDTH, di->config.sb_width, FALSE );
1632 SetDlgItemInt( dialog, IDC_CNF_SB_HEIGHT, di->config.sb_height, FALSE );
1633 SetDlgItemInt( dialog, IDC_CNF_WIN_WIDTH, di->config.win_width, FALSE );
1634 SetDlgItemInt( dialog, IDC_CNF_WIN_HEIGHT, di->config.win_height, FALSE );
1636 SendMessageW( GetDlgItem(dialog, IDC_CNF_WIN_HEIGHT_UD), UDM_SETRANGE, 0, MAKELPARAM(max_ud, 0));
1637 SendMessageW( GetDlgItem(dialog, IDC_CNF_WIN_WIDTH_UD), UDM_SETRANGE, 0, MAKELPARAM(max_ud, 0));
1638 SendMessageW( GetDlgItem(dialog, IDC_CNF_SB_HEIGHT_UD), UDM_SETRANGE, 0, MAKELPARAM(max_ud, 0));
1639 SendMessageW( GetDlgItem(dialog, IDC_CNF_SB_WIDTH_UD), UDM_SETRANGE, 0, MAKELPARAM(max_ud, 0));
1641 SendDlgItemMessageW( dialog, IDC_CNF_CLOSE_EXIT, BM_SETCHECK, BST_CHECKED, 0 );
1643 SendDlgItemMessageW( dialog, IDC_CNF_EDITION_MODE, CB_ADDSTRING, 0, (LPARAM)L"Win32" );
1644 SendDlgItemMessageW( dialog, IDC_CNF_EDITION_MODE, CB_ADDSTRING, 0, (LPARAM)L"Emacs" );
1645 SendDlgItemMessageW( dialog, IDC_CNF_EDITION_MODE, CB_SETCURSEL, di->config.edition_mode, 0 );
1646 break;
1648 case WM_NOTIFY:
1650 NMHDR *nmhdr = (NMHDR*)lparam;
1651 int win_w, win_h, sb_w, sb_h;
1652 BOOL st1, st2;
1654 di = (struct dialog_info *)GetWindowLongPtrW( dialog, DWLP_USER );
1655 switch (nmhdr->code)
1657 case PSN_SETACTIVE:
1658 di->dialog = dialog;
1659 break;
1660 case PSN_APPLY:
1661 sb_w = GetDlgItemInt( dialog, IDC_CNF_SB_WIDTH, &st1, FALSE );
1662 sb_h = GetDlgItemInt( dialog, IDC_CNF_SB_HEIGHT, &st2, FALSE );
1663 if (!st1 || ! st2)
1665 SetWindowLongPtrW( dialog, DWLP_MSGRESULT, PSNRET_INVALID );
1666 return TRUE;
1668 win_w = GetDlgItemInt( dialog, IDC_CNF_WIN_WIDTH, &st1, FALSE );
1669 win_h = GetDlgItemInt( dialog, IDC_CNF_WIN_HEIGHT, &st2, FALSE );
1670 if (!st1 || !st2)
1672 SetWindowLongPtrW( dialog, DWLP_MSGRESULT, PSNRET_INVALID );
1673 return TRUE;
1675 if (win_w > sb_w || win_h > sb_h)
1677 WCHAR cap[256];
1678 WCHAR txt[256];
1680 LoadStringW( GetModuleHandleW(NULL), IDS_DLG_TIT_ERROR, cap, ARRAY_SIZE(cap) );
1681 LoadStringW( GetModuleHandleW(NULL), IDS_DLG_ERR_SBWINSIZE, txt, ARRAY_SIZE(txt) );
1683 MessageBoxW( dialog, txt, cap, MB_OK );
1684 SetWindowLongPtrW( dialog, DWLP_MSGRESULT, PSNRET_INVALID );
1685 return TRUE;
1687 di->config.win_width = win_w;
1688 di->config.win_height = win_h;
1689 di->config.sb_width = sb_w;
1690 di->config.sb_height = sb_h;
1692 di->config.edition_mode = SendDlgItemMessageW( dialog, IDC_CNF_EDITION_MODE,
1693 CB_GETCURSEL, 0, 0 );
1694 SetWindowLongPtrW( dialog, DWLP_MSGRESULT, PSNRET_NOERROR );
1695 return TRUE;
1696 default:
1697 return FALSE;
1699 break;
1701 default:
1702 return FALSE;
1704 return TRUE;
1707 /* dialog proc for choosing how to handle modification to the console settings */
1708 static INT_PTR WINAPI save_dialog_proc( HWND dialog, UINT msg, WPARAM wparam, LPARAM lparam )
1710 switch (msg)
1712 case WM_INITDIALOG:
1713 SendMessageW( dialog, WM_NEXTDLGCTL, (WPARAM)GetDlgItem( dialog, IDC_SAV_SESSION ), TRUE );
1714 SendDlgItemMessageW( dialog, IDC_SAV_SESSION, BM_SETCHECK, BST_CHECKED, 0 );
1715 return FALSE;
1717 case WM_COMMAND:
1718 switch (LOWORD(wparam))
1720 case IDOK:
1721 EndDialog( dialog,
1722 (IsDlgButtonChecked(dialog, IDC_SAV_SAVE) == BST_CHECKED) ?
1723 IDC_SAV_SAVE : IDC_SAV_SESSION );
1724 break;
1725 case IDCANCEL:
1726 EndDialog( dialog, IDCANCEL ); break;
1728 break;
1729 default:
1730 return FALSE;
1732 return TRUE;
1735 static void apply_config( struct console *console, const struct console_config *config )
1737 if (console->active->width != config->sb_width || console->active->height != config->sb_height)
1738 change_screen_buffer_size( console->active, config->sb_width, config->sb_height );
1740 console->window->menu_mask = config->menu_mask;
1741 console->window->quick_edit = config->quick_edit;
1743 console->edition_mode = config->edition_mode;
1744 console->history_mode = config->history_mode;
1746 if (console->history_size != config->history_size)
1748 struct history_line **mem = NULL;
1749 int i, delta;
1751 if (config->history_size && (mem = malloc( config->history_size * sizeof(*mem) )))
1753 memset( mem, 0, config->history_size * sizeof(*mem) );
1755 delta = (console->history_index > config->history_size)
1756 ? (console->history_index - config->history_size) : 0;
1758 for (i = delta; i < console->history_index; i++)
1760 mem[i - delta] = console->history[i];
1761 console->history[i] = NULL;
1763 console->history_index -= delta;
1765 for (i = 0; i < console->history_size; i++)
1766 free( console->history[i] );
1767 free( console->history );
1768 console->history = mem;
1769 console->history_size = config->history_size;
1773 if (config->insert_mode)
1774 console->mode |= ENABLE_INSERT_MODE|ENABLE_EXTENDED_FLAGS;
1775 else
1776 console->mode &= ~ENABLE_INSERT_MODE;
1778 console->active->cursor_size = config->cursor_size;
1779 console->active->cursor_visible = config->cursor_visible;
1780 console->active->attr = config->attr;
1781 console->active->popup_attr = config->popup_attr;
1782 console->active->win.left = config->win_pos.X;
1783 console->active->win.top = config->win_pos.Y;
1784 console->active->win.right = config->win_pos.X + config->win_width - 1;
1785 console->active->win.bottom = config->win_pos.Y + config->win_height - 1;
1786 memcpy( console->active->color_map, config->color_map, sizeof(config->color_map) );
1788 if (console->active->font.width != config->cell_width ||
1789 console->active->font.height != config->cell_height ||
1790 console->active->font.weight != config->font_weight ||
1791 console->active->font.pitch_family != config->font_pitch_family ||
1792 console->active->font.face_len != wcslen( config->face_name ) ||
1793 memcmp( console->active->font.face_name, config->face_name,
1794 console->active->font.face_len * sizeof(WCHAR) ))
1796 update_console_font( console, config->face_name, wcslen(config->face_name) * sizeof(WCHAR),
1797 config->cell_height, config->font_weight );
1800 update_window( console );
1802 notify_screen_buffer_size( console->active );
1805 static void current_config( struct console *console, struct console_config *config )
1807 size_t len;
1809 config->menu_mask = console->window->menu_mask;
1810 config->quick_edit = console->window->quick_edit;
1812 config->edition_mode = console->edition_mode;
1813 config->history_mode = console->history_mode;
1814 config->history_size = console->history_size;
1816 config->insert_mode = (console->mode & (ENABLE_INSERT_MODE|ENABLE_EXTENDED_FLAGS)) ==
1817 (ENABLE_INSERT_MODE|ENABLE_EXTENDED_FLAGS);
1819 config->cursor_size = console->active->cursor_size;
1820 config->cursor_visible = console->active->cursor_visible;
1821 config->attr = console->active->attr;
1822 config->popup_attr = console->active->popup_attr;
1823 memcpy( config->color_map, console->active->color_map, sizeof(config->color_map) );
1825 config->cell_width = console->active->font.width;
1826 config->cell_height = console->active->font.height;
1827 config->font_weight = console->active->font.weight;
1828 config->font_pitch_family = console->active->font.pitch_family;
1829 len = min( ARRAY_SIZE(config->face_name) - 1, console->active->font.face_len );
1830 if (len) memcpy( config->face_name, console->active->font.face_name, len * sizeof(WCHAR) );
1831 config->face_name[len] = 0;
1833 config->sb_width = console->active->width;
1834 config->sb_height = console->active->height;
1836 config->win_width = console->active->win.right - console->active->win.left + 1;
1837 config->win_height = console->active->win.bottom - console->active->win.top + 1;
1838 config->win_pos.X = console->active->win.left;
1839 config->win_pos.Y = console->active->win.top;
1842 /* run the dialog box to set up the console options */
1843 static BOOL config_dialog( struct console *console, BOOL current )
1845 struct console_config prev_config;
1846 struct dialog_info di;
1847 PROPSHEETHEADERW header;
1848 HPROPSHEETPAGE pages[3];
1849 PROPSHEETPAGEW psp;
1850 WNDCLASSW wndclass;
1851 WCHAR buff[256];
1852 BOOL modify_session = FALSE;
1853 BOOL save = FALSE;
1855 InitCommonControls();
1857 memset( &di, 0, sizeof(di) );
1858 di.console = console;
1859 if (!current)
1861 load_config( NULL, &di.config );
1862 save = TRUE;
1864 else current_config( console, &di.config );
1865 prev_config = di.config;
1867 wndclass.style = 0;
1868 wndclass.lpfnWndProc = font_preview_proc;
1869 wndclass.cbClsExtra = 0;
1870 wndclass.cbWndExtra = sizeof(HFONT);
1871 wndclass.hInstance = GetModuleHandleW( NULL );
1872 wndclass.hIcon = 0;
1873 wndclass.hCursor = LoadCursorW( 0, (const WCHAR *)IDC_ARROW );
1874 wndclass.hbrBackground = GetStockObject( BLACK_BRUSH );
1875 wndclass.lpszMenuName = NULL;
1876 wndclass.lpszClassName = L"WineConFontPreview";
1877 RegisterClassW( &wndclass );
1879 wndclass.style = 0;
1880 wndclass.lpfnWndProc = color_preview_proc;
1881 wndclass.cbClsExtra = 0;
1882 wndclass.cbWndExtra = sizeof(DWORD);
1883 wndclass.hInstance = GetModuleHandleW( NULL );
1884 wndclass.hIcon = 0;
1885 wndclass.hCursor = LoadCursorW( 0, (const WCHAR *)IDC_ARROW );
1886 wndclass.hbrBackground = GetStockObject( BLACK_BRUSH );
1887 wndclass.lpszMenuName = NULL;
1888 wndclass.lpszClassName = L"WineConColorPreview";
1889 RegisterClassW( &wndclass );
1891 memset( &psp, 0, sizeof(psp) );
1892 psp.dwSize = sizeof(psp);
1893 psp.dwFlags = 0;
1894 psp.hInstance = wndclass.hInstance;
1895 psp.lParam = (LPARAM)&di;
1897 psp.u.pszTemplate = MAKEINTRESOURCEW(IDD_OPTION);
1898 psp.pfnDlgProc = option_dialog_proc;
1899 pages[0] = CreatePropertySheetPageW( &psp );
1901 psp.u.pszTemplate = MAKEINTRESOURCEW(IDD_FONT);
1902 psp.pfnDlgProc = font_dialog_proc;
1903 pages[1] = CreatePropertySheetPageW( &psp );
1905 psp.u.pszTemplate = MAKEINTRESOURCEW(IDD_CONFIG);
1906 psp.pfnDlgProc = config_dialog_proc;
1907 pages[2] = CreatePropertySheetPageW( &psp );
1909 memset( &header, 0, sizeof(header) );
1910 header.dwSize = sizeof(header);
1912 if (!LoadStringW( GetModuleHandleW( NULL ),
1913 current ? IDS_DLG_TIT_CURRENT : IDS_DLG_TIT_DEFAULT,
1914 buff, ARRAY_SIZE(buff) ))
1915 wcscpy( buff, L"Setup" );
1917 header.pszCaption = buff;
1918 header.nPages = 3;
1919 header.hwndParent = console->win;
1920 header.u3.phpage = pages;
1921 header.dwFlags = PSH_NOAPPLYNOW;
1922 if (PropertySheetW( &header ) < 1)
1923 return TRUE;
1925 if (!memcmp( &prev_config, &di.config, sizeof(prev_config) ))
1926 return TRUE;
1928 TRACE( "%s\n", debugstr_config(&di.config) );
1930 if (!save)
1932 switch (DialogBoxW( GetModuleHandleW( NULL ), MAKEINTRESOURCEW(IDD_SAVE_SETTINGS),
1933 console->win, save_dialog_proc ))
1935 case IDC_SAV_SAVE:
1936 save = TRUE;
1937 modify_session = TRUE;
1938 break;
1939 case IDC_SAV_SESSION:
1940 modify_session = TRUE;
1941 break;
1942 default:
1943 ERR( "dialog failed\n" );
1944 /* fall through */
1945 case IDCANCEL:
1946 modify_session = FALSE;
1947 save = FALSE;
1948 break;
1952 if (modify_session)
1954 apply_config( console, &di.config );
1955 update_window( di.console );
1957 if (save)
1958 save_config( current ? console->window->config_key : NULL, &di.config );
1959 return TRUE;
1962 static void resize_window( struct console *console, int width, int height )
1964 struct console_config config;
1966 current_config( console, &config );
1967 config.win_width = width;
1968 config.win_height = height;
1970 /* auto size screen-buffer if it's now smaller than window */
1971 if (config.sb_width < config.win_width)
1972 config.sb_width = config.win_width;
1973 if (config.sb_height < config.win_height)
1974 config.sb_height = config.win_height;
1976 /* and reset window pos so that we don't display outside of the screen-buffer */
1977 if (config.win_pos.X + config.win_width > config.sb_width)
1978 config.win_pos.X = config.sb_width - config.win_width;
1979 if (config.win_pos.Y + config.win_height > config.sb_height)
1980 config.win_pos.Y = config.sb_height - config.win_height;
1982 apply_config( console, &config );
1985 /* grays / ungrays the menu items according to their state */
1986 static void set_menu_details( struct console *console, HMENU menu )
1988 EnableMenuItem( menu, IDS_COPY, MF_BYCOMMAND |
1989 (console->window->in_selection ? MF_ENABLED : MF_GRAYED) );
1990 EnableMenuItem( menu, IDS_PASTE, MF_BYCOMMAND |
1991 (IsClipboardFormatAvailable(CF_UNICODETEXT) ? MF_ENABLED : MF_GRAYED) );
1992 EnableMenuItem( menu, IDS_SCROLL, MF_BYCOMMAND | MF_GRAYED );
1993 EnableMenuItem( menu, IDS_SEARCH, MF_BYCOMMAND | MF_GRAYED );
1996 static BOOL fill_menu( HMENU menu, BOOL sep )
1998 HINSTANCE module = GetModuleHandleW( NULL );
1999 HMENU sub_menu;
2000 WCHAR buff[256];
2002 if (!menu) return FALSE;
2004 sub_menu = CreateMenu();
2005 if (!sub_menu) return FALSE;
2007 LoadStringW( module, IDS_MARK, buff, ARRAY_SIZE(buff) );
2008 InsertMenuW( sub_menu, -1, MF_BYPOSITION|MF_STRING, IDS_MARK, buff );
2009 LoadStringW( module, IDS_COPY, buff, ARRAY_SIZE(buff) );
2010 InsertMenuW( sub_menu, -1, MF_BYPOSITION|MF_STRING, IDS_COPY, buff );
2011 LoadStringW( module, IDS_PASTE, buff, ARRAY_SIZE(buff) );
2012 InsertMenuW( sub_menu, -1, MF_BYPOSITION|MF_STRING, IDS_PASTE, buff );
2013 LoadStringW( module, IDS_SELECTALL, buff, ARRAY_SIZE(buff) );
2014 InsertMenuW( sub_menu, -1, MF_BYPOSITION|MF_STRING, IDS_SELECTALL, buff );
2015 LoadStringW( module, IDS_SCROLL, buff, ARRAY_SIZE(buff) );
2016 InsertMenuW( sub_menu, -1, MF_BYPOSITION|MF_STRING, IDS_SCROLL, buff );
2017 LoadStringW( module, IDS_SEARCH, buff, ARRAY_SIZE(buff) );
2018 InsertMenuW( sub_menu, -1, MF_BYPOSITION|MF_STRING, IDS_SEARCH, buff );
2020 if (sep) InsertMenuW( menu, -1, MF_BYPOSITION|MF_SEPARATOR, 0, NULL );
2021 LoadStringW( module, IDS_EDIT, buff, ARRAY_SIZE(buff) );
2022 InsertMenuW( menu, -1, MF_BYPOSITION|MF_STRING|MF_POPUP, (UINT_PTR)sub_menu, buff );
2023 LoadStringW( module, IDS_DEFAULT, buff, ARRAY_SIZE(buff) );
2024 InsertMenuW( menu, -1, MF_BYPOSITION|MF_STRING, IDS_DEFAULT, buff );
2025 LoadStringW( module, IDS_PROPERTIES, buff, ARRAY_SIZE(buff) );
2026 InsertMenuW( menu, -1, MF_BYPOSITION|MF_STRING, IDS_PROPERTIES, buff );
2028 return TRUE;
2031 static LRESULT window_create( HWND hwnd, const CREATESTRUCTW *create )
2033 struct console *console = create->lpCreateParams;
2034 HMENU sys_menu;
2036 TRACE( "%p\n", hwnd );
2038 SetWindowLongPtrW( hwnd, 0, (DWORD_PTR)console );
2039 console->win = hwnd;
2041 if (console->window)
2043 sys_menu = GetSystemMenu( hwnd, FALSE );
2044 if (!sys_menu) return 0;
2045 console->window->popup_menu = CreatePopupMenu();
2046 if (!console->window->popup_menu) return 0;
2048 fill_menu( sys_menu, TRUE );
2049 fill_menu( console->window->popup_menu, FALSE );
2051 console->window->mem_dc = CreateCompatibleDC( 0 );
2053 return 0;
2056 static LRESULT WINAPI window_proc( HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam )
2058 struct console *console = (struct console *)GetWindowLongPtrW( hwnd, 0 );
2060 switch (msg)
2062 case WM_CREATE:
2063 return window_create( hwnd, (const CREATESTRUCTW *)lparam );
2065 case WM_DESTROY:
2066 console->win = NULL;
2067 PostQuitMessage( 0 );
2068 break;
2070 case WM_TIMER:
2071 case WM_UPDATE_CONFIG:
2072 if (console->window && console->window->update_state == UPDATE_PENDING)
2073 update_window( console );
2074 break;
2076 case WM_PAINT:
2078 PAINTSTRUCT ps;
2080 if (!console->window) break;
2082 BeginPaint( console->win, &ps );
2083 BitBlt( ps.hdc, 0, 0,
2084 (console->active->win.right - console->active->win.left + 1) * console->active->font.width,
2085 (console->active->win.bottom - console->active->win.top + 1) * console->active->font.height,
2086 console->window->mem_dc,
2087 console->active->win.left * console->active->font.width,
2088 console->active->win.top * console->active->font.height,
2089 SRCCOPY );
2090 if (console->window->in_selection) update_selection( console, ps.hdc );
2091 EndPaint( console->win, &ps );
2092 break;
2095 case WM_SHOWWINDOW:
2096 if (!console->window) break;
2097 if (wparam)
2098 update_window( console );
2099 else
2101 if (console->window->bitmap) DeleteObject( console->window->bitmap );
2102 console->window->bitmap = NULL;
2104 break;
2106 case WM_KEYDOWN:
2107 case WM_KEYUP:
2108 if (console->window && console->window->in_selection)
2109 handle_selection_key( console, msg == WM_KEYDOWN, wparam, lparam );
2110 else
2111 record_key_input( console, msg == WM_KEYDOWN, wparam, lparam );
2112 break;
2114 case WM_SYSKEYDOWN:
2115 case WM_SYSKEYUP:
2116 record_key_input( console, msg == WM_SYSKEYDOWN, wparam, lparam );
2117 break;
2119 case WM_LBUTTONDOWN:
2120 if (console->window && (console->window->quick_edit || console->window->in_selection))
2122 if (console->window->in_selection)
2123 update_selection( console, 0 );
2125 if (console->window->quick_edit && console->window->in_selection)
2127 console->window->in_selection = FALSE;
2129 else
2131 console->window->selection_end = get_cell( console, lparam );
2132 console->window->selection_start = console->window->selection_end;
2133 SetCapture( console->win );
2134 update_selection( console, 0 );
2135 console->window->in_selection = TRUE;
2138 else
2140 record_mouse_input( console, get_cell(console, lparam), wparam, 0 );
2142 break;
2144 case WM_MOUSEMOVE:
2145 if (console->window && (console->window->quick_edit || console->window->in_selection))
2147 if (GetCapture() == console->win && console->window->in_selection &&
2148 (wparam & MK_LBUTTON))
2150 move_selection( console, console->window->selection_start,
2151 get_cell(console, lparam) );
2154 else
2156 record_mouse_input( console, get_cell(console, lparam), wparam, MOUSE_MOVED );
2158 break;
2160 case WM_LBUTTONUP:
2161 if (console->window && (console->window->quick_edit || console->window->in_selection))
2163 if (GetCapture() == console->win && console->window->in_selection)
2165 move_selection( console, console->window->selection_start,
2166 get_cell(console, lparam) );
2167 ReleaseCapture();
2170 else
2172 record_mouse_input( console, get_cell(console, lparam), wparam, 0 );
2174 break;
2176 case WM_RBUTTONDOWN:
2177 if (console->window && (wparam & (MK_CONTROL|MK_SHIFT)) == console->window->menu_mask)
2179 POINT pt;
2180 pt.x = (short)LOWORD(lparam);
2181 pt.y = (short)HIWORD(lparam);
2182 ClientToScreen( hwnd, &pt );
2183 set_menu_details( console, console->window->popup_menu );
2184 TrackPopupMenu( console->window->popup_menu, TPM_LEFTALIGN|TPM_TOPALIGN|TPM_RIGHTBUTTON,
2185 pt.x, pt.y, 0, hwnd, NULL );
2187 else
2189 record_mouse_input( console, get_cell(console, lparam), wparam, 0 );
2191 break;
2193 case WM_RBUTTONUP:
2194 /* no need to track for rbutton up when opening the popup... the event will be
2195 * swallowed by TrackPopupMenu */
2196 case WM_MBUTTONDOWN:
2197 case WM_MBUTTONUP:
2198 record_mouse_input( console, get_cell(console, lparam), wparam, 0 );
2199 break;
2201 case WM_LBUTTONDBLCLK:
2202 case WM_MBUTTONDBLCLK:
2203 case WM_RBUTTONDBLCLK:
2204 record_mouse_input( console, get_cell(console, lparam), wparam, DOUBLE_CLICK );
2205 break;
2207 case WM_SETFOCUS:
2208 if (console->window && console->active->cursor_visible)
2210 CreateCaret( console->win, console->window->cursor_bitmap,
2211 console->active->font.width, console->active->font.height );
2212 update_window_cursor( console );
2214 break;
2216 case WM_KILLFOCUS:
2217 if (console->window && console->active->cursor_visible)
2218 DestroyCaret();
2219 break;
2221 case WM_SIZE:
2222 if (console->window && console->window->update_state != UPDATE_BUSY)
2223 resize_window( console,
2224 max( LOWORD(lparam) / console->active->font.width, 20 ),
2225 max( HIWORD(lparam) / console->active->font.height, 20 ));
2226 break;
2228 case WM_HSCROLL:
2230 int win_width = console->active->win.right - console->active->win.left + 1;
2231 int x = console->active->win.left;
2233 if (!console->window) break;
2234 switch (LOWORD(wparam))
2236 case SB_PAGEUP: x -= 8; break;
2237 case SB_PAGEDOWN: x += 8; break;
2238 case SB_LINEUP: x--; break;
2239 case SB_LINEDOWN: x++; break;
2240 case SB_THUMBTRACK: x = HIWORD(wparam); break;
2241 default: break;
2243 x = min( max( x, 0 ), console->active->width - win_width );
2244 if (x != console->active->win.left)
2246 console->active->win.left = x;
2247 console->active->win.right = x + win_width - 1;
2248 update_window( console );
2250 break;
2253 case WM_MOUSEWHEEL:
2254 if (console->active->height <= console->active->win.bottom - console->active->win.top + 1)
2256 record_mouse_input(console, get_cell(console, lparam), wparam, MOUSE_WHEELED);
2257 break;
2259 /* else fallthrough */
2260 case WM_VSCROLL:
2262 int win_height = console->active->win.bottom - console->active->win.top + 1;
2263 int y = console->active->win.top;
2265 if (!console->window) break;
2267 if (msg == WM_MOUSEWHEEL)
2269 UINT scroll_lines = 3;
2270 SystemParametersInfoW( SPI_GETWHEELSCROLLLINES, 0, &scroll_lines, 0 );
2271 scroll_lines *= -GET_WHEEL_DELTA_WPARAM(wparam) / WHEEL_DELTA;
2272 y += scroll_lines;
2274 else
2276 switch (LOWORD(wparam))
2278 case SB_PAGEUP: y -= 8; break;
2279 case SB_PAGEDOWN: y += 8; break;
2280 case SB_LINEUP: y--; break;
2281 case SB_LINEDOWN: y++; break;
2282 case SB_THUMBTRACK: y = HIWORD(wparam); break;
2283 default: break;
2287 y = min( max( y, 0 ), console->active->height - win_height );
2288 if (y != console->active->win.top)
2290 console->active->win.top = y;
2291 console->active->win.bottom = y + win_height - 1;
2292 update_window( console );
2294 break;
2297 case WM_SYSCOMMAND:
2298 if (!console->window) break;
2299 switch (wparam)
2301 case IDS_DEFAULT:
2302 config_dialog( console, FALSE );
2303 break;
2304 case IDS_PROPERTIES:
2305 config_dialog( console, TRUE );
2306 break;
2307 default:
2308 return DefWindowProcW( hwnd, msg, wparam, lparam );
2310 break;
2312 case WM_COMMAND:
2313 if (!console->window) break;
2314 switch (wparam)
2316 case IDS_DEFAULT:
2317 config_dialog( console, FALSE );
2318 break;
2319 case IDS_PROPERTIES:
2320 config_dialog( console, TRUE );
2321 break;
2322 case IDS_MARK:
2323 console->window->selection_start.X = console->window->selection_start.Y = 0;
2324 console->window->selection_end.X = console->window->selection_end.Y = 0;
2325 update_selection( console, 0 );
2326 console->window->in_selection = TRUE;
2327 break;
2328 case IDS_COPY:
2329 if (console->window->in_selection)
2331 console->window->in_selection = FALSE;
2332 update_selection( console, 0 );
2333 copy_selection( console );
2335 break;
2336 case IDS_PASTE:
2337 paste_clipboard( console );
2338 break;
2339 case IDS_SELECTALL:
2340 console->window->selection_start.X = console->window->selection_start.Y = 0;
2341 console->window->selection_end.X = console->active->width - 1;
2342 console->window->selection_end.Y = console->active->height - 1;
2343 update_selection( console, 0 );
2344 console->window->in_selection = TRUE;
2345 break;
2346 case IDS_SCROLL:
2347 case IDS_SEARCH:
2348 FIXME( "Unhandled yet command: %Ix\n", wparam );
2349 break;
2350 default:
2351 return DefWindowProcW( hwnd, msg, wparam, lparam );
2353 break;
2355 case WM_INITMENUPOPUP:
2356 if (!console->window || !HIWORD(lparam)) return DefWindowProcW( hwnd, msg, wparam, lparam );
2357 set_menu_details( console, GetSystemMenu(console->win, FALSE) );
2358 break;
2360 default:
2361 return DefWindowProcW( hwnd, msg, wparam, lparam );
2364 return 0;
2367 void update_window_config( struct console *console, BOOL delay )
2369 const int delay_timeout = 50;
2371 if (!console->window || console->window->update_state != UPDATE_NONE) return;
2372 console->window->update_state = UPDATE_PENDING;
2373 if (delay)
2374 SetTimer( console->win, 1, delay_timeout, NULL );
2375 else
2376 PostMessageW( console->win, WM_UPDATE_CONFIG, 0, 0 );
2379 void update_window_region( struct console *console, const RECT *update )
2381 RECT *window_rect = &console->window->update;
2382 window_rect->left = min( window_rect->left, update->left );
2383 window_rect->top = min( window_rect->top, update->top );
2384 window_rect->right = max( window_rect->right, update->right );
2385 window_rect->bottom = max( window_rect->bottom, update->bottom );
2386 update_window_config( console, TRUE );
2389 BOOL init_window( struct console *console )
2391 struct console_config config;
2392 WNDCLASSW wndclass;
2393 STARTUPINFOW si;
2394 CHARSETINFO ci;
2396 static struct console_window console_window;
2398 console->window = &console_window;
2399 if (!TranslateCharsetInfo( (DWORD *)(INT_PTR)GetACP(), &ci, TCI_SRCCODEPAGE ))
2400 return FALSE;
2402 console->window->ui_charset = ci.ciCharset;
2404 GetStartupInfoW(&si);
2405 if (si.lpTitle)
2407 size_t i, title_len = wcslen( si.lpTitle );
2408 if (!(console->window->config_key = malloc( (title_len + 1) * sizeof(WCHAR) )))
2409 return FALSE;
2410 for (i = 0; i < title_len; i++)
2411 console->window->config_key[i] = si.lpTitle[i] == '\\' ? '_' : si.lpTitle[i];
2412 console->window->config_key[title_len] = 0;
2415 load_config( console->window->config_key, &config );
2416 if (si.dwFlags & STARTF_USECOUNTCHARS)
2418 config.sb_width = si.dwXCountChars;
2419 config.sb_height = si.dwYCountChars;
2421 if (si.dwFlags & STARTF_USEFILLATTRIBUTE)
2422 config.attr = si.dwFillAttribute;
2424 wndclass.style = CS_DBLCLKS;
2425 wndclass.lpfnWndProc = window_proc;
2426 wndclass.cbClsExtra = 0;
2427 wndclass.cbWndExtra = sizeof(DWORD_PTR);
2428 wndclass.hInstance = GetModuleHandleW(NULL);
2429 wndclass.hIcon = LoadIconW( 0, (const WCHAR *)IDI_WINLOGO );
2430 wndclass.hCursor = LoadCursorW( 0, (const WCHAR *)IDC_ARROW );
2431 wndclass.hbrBackground = GetStockObject( BLACK_BRUSH );
2432 wndclass.lpszMenuName = NULL;
2433 wndclass.lpszClassName = L"WineConsoleClass";
2434 RegisterClassW(&wndclass);
2436 if (!CreateWindowW( wndclass.lpszClassName, NULL,
2437 WS_OVERLAPPED|WS_CAPTION|WS_SYSMENU|WS_THICKFRAME|WS_MINIMIZEBOX|
2438 WS_MAXIMIZEBOX|WS_HSCROLL|WS_VSCROLL, CW_USEDEFAULT, CW_USEDEFAULT,
2439 0, 0, 0, 0, wndclass.hInstance, console ))
2440 return FALSE;
2442 apply_config( console, &config );
2443 return TRUE;
2446 void init_message_window( struct console *console )
2448 WNDCLASSW wndclass;
2450 wndclass.style = CS_DBLCLKS;
2451 wndclass.lpfnWndProc = window_proc;
2452 wndclass.cbClsExtra = 0;
2453 wndclass.cbWndExtra = sizeof(DWORD_PTR);
2454 wndclass.hInstance = GetModuleHandleW( NULL );
2455 wndclass.hIcon = 0;
2456 wndclass.hCursor = 0;
2457 wndclass.hbrBackground = GetStockObject( BLACK_BRUSH );
2458 wndclass.lpszMenuName = NULL;
2459 wndclass.lpszClassName = L"WineConsoleClass";
2460 RegisterClassW(&wndclass);
2462 CreateWindowW( wndclass.lpszClassName, NULL,
2463 WS_OVERLAPPED|WS_CAPTION|WS_SYSMENU|WS_THICKFRAME|WS_MINIMIZEBOX|
2464 WS_MAXIMIZEBOX|WS_HSCROLL|WS_VSCROLL, CW_USEDEFAULT, CW_USEDEFAULT,
2465 0, 0, HWND_MESSAGE, 0, wndclass.hInstance, console );