msxml3: Fold in reset_output_buffer.
[wine/zf.git] / programs / conhost / window.c
blob5e94a1d454eeea9efdc5dc4b3f6bf0667abb5399
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=%d lfWidth=%d lfEscapement=%d "
114 "lfOrientation=%d lfWeight=%d 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=%d tmAscent=%d tmDescent=%d "
128 "tmAveCharWidth=%d tmMaxCharWidth=%d tmWeight=%d "
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 = 25;
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", 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, sizeof(config->face_name) );
308 val = config->font_pitch_family;
309 RegSetValueExW( key, L"FontPitchFamily", 0, REG_DWORD, (BYTE *)&val, sizeof(val) );
311 width = MulDiv( config->cell_width, USER_DEFAULT_SCREEN_DPI, GetDpiForSystem() );
312 height = MulDiv( config->cell_height, USER_DEFAULT_SCREEN_DPI, GetDpiForSystem() );
313 val = MAKELONG( width, height );
314 RegSetValueExW( key, L"FontSize", 0, REG_DWORD, (BYTE *)&val, sizeof(val) );
316 val = config->font_weight;
317 RegSetValueExW( key, L"FontWeight", 0, REG_DWORD, (BYTE *)&val, sizeof(val) );
319 val = config->history_size;
320 RegSetValueExW( key, L"HistoryBufferSize", 0, REG_DWORD, (BYTE *)&val, sizeof(val) );
322 val = config->history_mode;
323 RegSetValueExW( key, L"HistoryNoDup", 0, REG_DWORD, (BYTE *)&val, sizeof(val) );
325 val = config->insert_mode;
326 RegSetValueExW( key, L"InsertMode", 0, REG_DWORD, (BYTE *)&val, sizeof(val) );
328 val = config->menu_mask;
329 RegSetValueExW( key, L"MenuMask", 0, REG_DWORD, (BYTE *)&val, sizeof(val) );
331 val = config->popup_attr;
332 RegSetValueExW( key, L"PopupColors", 0, REG_DWORD, (BYTE *)&val, sizeof(val) );
334 val = config->quick_edit;
335 RegSetValueExW( key, L"QuickEdit", 0, REG_DWORD, (BYTE *)&val, sizeof(val) );
337 val = MAKELONG(config->sb_width, config->sb_height);
338 RegSetValueExW( key, L"ScreenBufferSize", 0, REG_DWORD, (BYTE *)&val, sizeof(val) );
340 val = config->attr;
341 RegSetValueExW( key, L"ScreenColors", 0, REG_DWORD, (BYTE *)&val, sizeof(val) );
343 val = MAKELONG( config->win_width, config->win_height );
344 RegSetValueExW( key, L"WindowSize", 0, REG_DWORD, (BYTE *)&val, sizeof(val) );
347 static void save_config( const WCHAR *key_name, const struct console_config *config )
349 HKEY key, app_key;
351 TRACE( "%s %s\n", debugstr_w( key_name ), debugstr_config( config ));
353 if (RegCreateKeyW( HKEY_CURRENT_USER, L"Console", &key ))
355 ERR("Can't open registry for saving\n");
356 return;
359 if (key_name)
361 if (RegCreateKeyW( key, key_name, &app_key ))
363 ERR("Can't open registry for saving\n");
365 else
367 /* FIXME: maybe only save the values different from the default value ? */
368 save_registry_key( app_key, config );
369 RegCloseKey( app_key );
372 else save_registry_key( key, config );
373 RegCloseKey(key);
376 /* fill memory DC with current cells values */
377 static void fill_mem_dc( struct console *console, const RECT *update )
379 unsigned int i, j, k;
380 unsigned int attr;
381 char_info_t *cell;
382 HFONT old_font;
383 HBRUSH brush;
384 WCHAR *line;
385 INT *dx;
386 RECT r;
388 if (!console->window->font || !console->window->bitmap)
389 return;
391 if (!(line = malloc( (update->right - update->left + 1) * sizeof(WCHAR))) ) return;
392 dx = malloc( (update->right - update->left + 1) * sizeof(*dx) );
394 old_font = SelectObject( console->window->mem_dc, console->window->font );
395 for (j = update->top; j <= update->bottom; j++)
397 cell = &console->active->data[j * console->active->width];
398 for (i = update->left; i <= update->right; i++)
400 attr = cell[i].attr;
401 SetBkColor( console->window->mem_dc, console->active->color_map[(attr >> 4) & 0x0F] );
402 SetTextColor( console->window->mem_dc, console->active->color_map[attr & 0x0F] );
403 for (k = i; k <= update->right && cell[k].attr == attr; k++)
405 line[k - i] = cell[k].ch;
406 dx[k - i] = console->active->font.width;
408 ExtTextOutW( console->window->mem_dc, i * console->active->font.width,
409 j * console->active->font.height, 0, NULL, line, k - i, dx );
410 if (console->window->ext_leading &&
411 (brush = CreateSolidBrush( console->active->color_map[(attr >> 4) & 0x0F] )))
413 r.left = i * console->active->font.width;
414 r.top = (j + 1) * console->active->font.height - console->window->ext_leading;
415 r.right = k * console->active->font.width;
416 r.bottom = (j + 1) * console->active->font.height;
417 FillRect( console->window->mem_dc, &r, brush );
418 DeleteObject( brush );
420 i = k - 1;
423 SelectObject( console->window->mem_dc, old_font );
424 free( dx );
425 free( line );
428 /* set a new position for the cursor */
429 static void update_window_cursor( struct console *console )
431 if (console->win != GetFocus() || !console->active->cursor_visible) return;
433 SetCaretPos( (console->active->cursor_x - console->active->win.left) * console->active->font.width,
434 (console->active->cursor_y - console->active->win.top) * console->active->font.height );
435 ShowCaret( console->win );
438 /* sets a new shape for the cursor */
439 static void shape_cursor( struct console *console )
441 int size = console->active->cursor_size;
443 if (console->active->cursor_visible && console->win == GetFocus()) DestroyCaret();
444 if (console->window->cursor_bitmap) DeleteObject( console->window->cursor_bitmap );
445 console->window->cursor_bitmap = NULL;
446 console->window->cursor_visible = FALSE;
448 if (size != 100)
450 int w16b; /* number of bytes per row, aligned on word size */
451 int i, j, nbl;
452 BYTE *ptr;
454 w16b = ((console->active->font.width + 15) & ~15) / 8;
455 ptr = calloc( w16b, console->active->font.height );
456 if (!ptr) return;
457 nbl = max( (console->active->font.height * size) / 100, 1 );
458 for (j = console->active->font.height - nbl; j < console->active->font.height; j++)
460 for (i = 0; i < console->active->font.width; i++)
462 ptr[w16b * j + (i / 8)] |= 0x80 >> (i & 7);
465 console->window->cursor_bitmap = CreateBitmap( console->active->font.width,
466 console->active->font.height, 1, 1, ptr );
467 free(ptr);
471 static void update_window( struct console *console )
473 unsigned int win_width, win_height;
474 BOOL update_all = FALSE;
475 int dx, dy;
476 RECT r;
478 console->window->update_state = UPDATE_BUSY;
480 if (console->window->sb_width != console->active->width ||
481 console->window->sb_height != console->active->height ||
482 (!console->window->bitmap && IsWindowVisible( console->win )))
484 console->window->sb_width = console->active->width;
485 console->window->sb_height = console->active->height;
487 if (console->active->width && console->active->height && console->window->font)
489 HBITMAP bitmap;
490 HDC dc;
491 RECT r;
493 if (!(dc = GetDC( console->win ))) return;
495 bitmap = CreateCompatibleBitmap( dc,
496 console->active->width * console->active->font.width,
497 console->active->height * console->active->font.height );
498 ReleaseDC( console->win, dc );
499 SelectObject( console->window->mem_dc, bitmap );
501 if (console->window->bitmap) DeleteObject( console->window->bitmap );
502 console->window->bitmap = bitmap;
503 SetRect( &r, 0, 0, console->active->width - 1, console->active->height - 1 );
504 fill_mem_dc( console, &r );
507 empty_update_rect( console->active, &console->window->update );
508 update_all = TRUE;
511 /* compute window size from desired client size */
512 win_width = console->active->win.right - console->active->win.left + 1;
513 win_height = console->active->win.bottom - console->active->win.top + 1;
515 if (update_all || win_width != console->window->win_width ||
516 win_height != console->window->win_height)
518 console->window->win_width = win_width;
519 console->window->win_height = win_height;
521 r.left = r.top = 0;
522 r.right = win_width * console->active->font.width;
523 r.bottom = win_height * console->active->font.height;
524 AdjustWindowRect( &r, GetWindowLongW( console->win, GWL_STYLE ), FALSE );
526 dx = dy = 0;
527 if (console->active->width > win_width)
529 dy = GetSystemMetrics( SM_CYHSCROLL );
530 SetScrollRange( console->win, SB_HORZ, 0, console->active->width - win_width, FALSE );
531 SetScrollPos( console->win, SB_VERT, console->active->win.top, FALSE );
532 ShowScrollBar( console->win, SB_HORZ, TRUE );
534 else
536 ShowScrollBar( console->win, SB_HORZ, FALSE );
539 if (console->active->height > win_height)
541 dx = GetSystemMetrics( SM_CXVSCROLL );
542 SetScrollRange( console->win, SB_VERT, 0, console->active->height - win_height, FALSE );
543 SetScrollPos( console->win, SB_VERT, console->active->win.top, FALSE );
544 ShowScrollBar( console->win, SB_VERT, TRUE );
546 else
547 ShowScrollBar( console->win, SB_VERT, FALSE );
549 dx += r.right - r.left;
550 dy += r.bottom - r.top;
551 SetWindowPos( console->win, 0, 0, 0, dx, dy, SWP_NOMOVE | SWP_NOZORDER | SWP_NOACTIVATE );
553 SystemParametersInfoW( SPI_GETWORKAREA, 0, &r, 0 );
554 console->active->max_width = (r.right - r.left) / console->active->font.width;
555 console->active->max_height = (r.bottom - r.top - GetSystemMetrics( SM_CYCAPTION )) /
556 console->active->font.height;
558 InvalidateRect( console->win, NULL, FALSE );
559 UpdateWindow( console->win );
560 update_all = TRUE;
562 else if (console->active->win.left != console->window->win_pos.X ||
563 console->active->win.top != console->window->win_pos.Y)
565 ScrollWindow( console->win,
566 (console->window->win_pos.X - console->active->win.left) * console->active->font.width,
567 (console->window->win_pos.Y - console->active->win.top) * console->active->font.height,
568 NULL, NULL );
569 SetScrollPos( console->win, SB_HORZ, console->active->win.left, TRUE );
570 SetScrollPos( console->win, SB_VERT, console->active->win.top, TRUE );
571 InvalidateRect( console->win, NULL, FALSE );
574 console->window->win_pos.X = console->active->win.left;
575 console->window->win_pos.Y = console->active->win.top;
577 if (console->window->update.top <= console->window->update.bottom &&
578 console->window->update.left <= console->window->update.right)
580 RECT *update = &console->window->update;
581 r.left = (update->left - console->active->win.left) * console->active->font.width;
582 r.right = (update->right - console->active->win.left + 1) * console->active->font.width;
583 r.top = (update->top - console->active->win.top) * console->active->font.height;
584 r.bottom = (update->bottom - console->active->win.top + 1) * console->active->font.height;
585 fill_mem_dc( console, update );
586 empty_update_rect( console->active, &console->window->update );
587 InvalidateRect( console->win, &r, FALSE );
588 UpdateWindow( console->win );
591 if (update_all || console->active->cursor_size != console->window->cursor_size)
593 console->window->cursor_size = console->active->cursor_size;
594 shape_cursor( console );
597 if (console->active->cursor_visible != console->window->cursor_visible)
599 console->window->cursor_visible = console->active->cursor_visible;
600 if (console->win == GetFocus())
602 if (console->window->cursor_visible)
603 CreateCaret( console->win, console->window->cursor_bitmap,
604 console->active->font.width, console->active->font.height );
605 else
606 DestroyCaret();
610 if (update_all || console->active->cursor_x != console->window->cursor_pos.X ||
611 console->active->cursor_y != console->window->cursor_pos.Y)
613 console->window->cursor_pos.X = console->active->cursor_x;
614 console->window->cursor_pos.Y = console->active->cursor_y;
615 update_window_cursor( console );
618 console->window->update_state = UPDATE_NONE;
621 /* get the relevant information from the font described in lf and store them in config */
622 static HFONT select_font_config( struct console_config *config, unsigned int cp, HWND hwnd,
623 const LOGFONTW *lf )
625 HFONT font, old_font;
626 TEXTMETRICW tm;
627 CPINFO cpinfo;
628 HDC dc;
630 if (!(dc = GetDC( hwnd ))) return NULL;
631 if (!(font = CreateFontIndirectW( lf )))
633 ReleaseDC( hwnd, dc );
634 return NULL;
637 old_font = SelectObject( dc, font );
638 GetTextMetricsW( dc, &tm );
639 SelectObject( dc, old_font );
640 ReleaseDC( hwnd, dc );
642 config->cell_width = tm.tmAveCharWidth;
643 config->cell_height = tm.tmHeight + tm.tmExternalLeading;
644 config->font_weight = tm.tmWeight;
645 lstrcpyW( config->face_name, lf->lfFaceName );
647 /* FIXME: use maximum width for DBCS codepages since some chars take two cells */
648 if (GetCPInfo( cp, &cpinfo ) && cpinfo.MaxCharSize > 1)
649 config->cell_width = tm.tmMaxCharWidth;
651 return font;
654 static void fill_logfont( LOGFONTW *lf, const WCHAR *name, unsigned int height, unsigned int weight )
656 lf->lfHeight = height;
657 lf->lfWidth = 0;
658 lf->lfEscapement = 0;
659 lf->lfOrientation = 0;
660 lf->lfWeight = weight;
661 lf->lfItalic = FALSE;
662 lf->lfUnderline = FALSE;
663 lf->lfStrikeOut = FALSE;
664 lf->lfCharSet = DEFAULT_CHARSET;
665 lf->lfOutPrecision = OUT_DEFAULT_PRECIS;
666 lf->lfClipPrecision = CLIP_DEFAULT_PRECIS;
667 lf->lfQuality = DEFAULT_QUALITY;
668 lf->lfPitchAndFamily = FIXED_PITCH | FF_DONTCARE;
669 lstrcpyW( lf->lfFaceName, name );
672 static BOOL set_console_font( struct console *console, const LOGFONTW *logfont )
674 struct font_info *font_info = &console->active->font;
675 HFONT font, old_font;
676 TEXTMETRICW tm;
677 CPINFO cpinfo;
678 HDC dc;
680 TRACE( "%s\n", debugstr_logfont( logfont, 0 ));
682 if (console->window->font && logfont->lfHeight == console->active->font.height &&
683 logfont->lfWeight == console->active->font.weight &&
684 !logfont->lfItalic && !logfont->lfUnderline && !logfont->lfStrikeOut &&
685 console->active->font.face_len == wcslen( logfont->lfFaceName ) * sizeof(WCHAR) &&
686 !memcmp( logfont->lfFaceName, console->active->font.face_name,
687 console->active->font.face_len ))
689 TRACE( "equal to current\n" );
690 return TRUE;
693 if (!(dc = GetDC( console->win ))) return FALSE;
694 if (!(font = CreateFontIndirectW( logfont )))
696 ReleaseDC( console->win, dc );
697 return FALSE;
700 old_font = SelectObject( dc, font );
701 GetTextMetricsW( dc, &tm );
702 SelectObject( dc, old_font );
703 ReleaseDC( console->win, dc );
705 font_info->width = tm.tmAveCharWidth;
706 font_info->height = tm.tmHeight + tm.tmExternalLeading;
707 font_info->weight = tm.tmWeight;
709 free( font_info->face_name );
710 font_info->face_len = wcslen( logfont->lfFaceName ) * sizeof(WCHAR);
711 font_info->face_name = malloc( font_info->face_len );
712 memcpy( font_info->face_name, logfont->lfFaceName, font_info->face_len );
714 /* FIXME: use maximum width for DBCS codepages since some chars take two cells */
715 if (GetCPInfo( console->output_cp, &cpinfo ) && cpinfo.MaxCharSize > 1)
716 font_info->width = tm.tmMaxCharWidth;
718 if (console->window->font) DeleteObject( console->window->font );
719 console->window->font = font;
720 console->window->ext_leading = tm.tmExternalLeading;
722 if (console->window->bitmap)
724 DeleteObject(console->window->bitmap);
725 console->window->bitmap = NULL;
727 return TRUE;
730 struct font_chooser
732 struct console *console;
733 int pass;
734 BOOL done;
737 /* check if the font described in tm is usable as a font for the renderer */
738 static BOOL validate_font_metric( struct console *console, const TEXTMETRICW *tm,
739 DWORD type, int pass )
741 switch (pass) /* we get increasingly lenient in later passes */
743 case 0:
744 if (type & RASTER_FONTTYPE) return FALSE;
745 /* fall through */
746 case 1:
747 if (type & RASTER_FONTTYPE)
749 if (tm->tmMaxCharWidth * (console->active->win.right - console->active->win.left + 1)
750 >= GetSystemMetrics(SM_CXSCREEN))
751 return FALSE;
752 if (tm->tmHeight * (console->active->win.bottom - console->active->win.top + 1)
753 >= GetSystemMetrics(SM_CYSCREEN))
754 return FALSE;
756 /* fall through */
757 case 2:
758 if (tm->tmCharSet != DEFAULT_CHARSET && tm->tmCharSet != console->window->ui_charset)
759 return FALSE;
760 /* fall through */
761 case 3:
762 if (tm->tmItalic || tm->tmUnderlined || tm->tmStruckOut) return FALSE;
763 break;
765 return TRUE;
768 /* check if the font family described in lf is usable as a font for the renderer */
769 static BOOL validate_font( struct console *console, const LOGFONTW *lf, int pass )
771 switch (pass) /* we get increasingly lenient in later passes */
773 case 0:
774 case 1:
775 case 2:
776 if (lf->lfCharSet != DEFAULT_CHARSET && lf->lfCharSet != console->window->ui_charset)
777 return FALSE;
778 /* fall through */
779 case 3:
780 if ((lf->lfPitchAndFamily & 3) != FIXED_PITCH) return FALSE;
781 /* fall through */
782 case 4:
783 if (lf->lfFaceName[0] == '@') return FALSE;
784 break;
786 return TRUE;
789 /* helper functions to get a decent font for the renderer */
790 static int WINAPI get_first_font_sub_enum( const LOGFONTW *lf, const TEXTMETRICW *tm,
791 DWORD font_type, LPARAM lparam)
793 struct font_chooser *fc = (struct font_chooser *)lparam;
795 TRACE( "%s\n", debugstr_textmetric( tm, font_type ));
797 if (validate_font_metric( fc->console, tm, font_type, fc->pass ))
799 LOGFONTW mlf = *lf;
801 /* Use the default sizes for the font (this is needed, especially for
802 * TrueType fonts, so that we get a decent size, not the max size)
804 mlf.lfWidth = fc->console->active->font.width;
805 mlf.lfHeight = fc->console->active->font.height;
806 if (!mlf.lfHeight)
807 mlf.lfHeight = MulDiv( 16, GetDpiForSystem(), USER_DEFAULT_SCREEN_DPI );
809 if (set_console_font( fc->console, &mlf ))
811 struct console_config config;
813 fc->done = 1;
815 /* since we've modified the current config with new font information,
816 * set this information as the new default.
818 load_config( fc->console->window->config_key, &config );
819 config.cell_width = fc->console->active->font.width;
820 config.cell_height = fc->console->active->font.height;
821 fc->console->active->font.face_len = wcslen( config.face_name ) * sizeof(WCHAR);
822 memcpy( fc->console->active->font.face_name, config.face_name,
823 fc->console->active->font.face_len );
824 /* Force also its writing back to the registry so that we can get it
825 * the next time.
827 save_config( fc->console->window->config_key, &config );
828 return 0;
831 return 1;
834 static int WINAPI get_first_font_enum( const LOGFONTW *lf, const TEXTMETRICW *tm,
835 DWORD font_type, LPARAM lparam )
837 struct font_chooser *fc = (struct font_chooser *)lparam;
839 TRACE("%s\n", debugstr_logfont( lf, font_type ));
841 if (validate_font( fc->console, lf, fc->pass ))
843 EnumFontFamiliesW( fc->console->window->mem_dc, lf->lfFaceName,
844 get_first_font_sub_enum, lparam );
845 return !fc->done; /* we just need the first matching one... */
847 return 1;
851 /* sets logfont as the new font for the console */
852 static void update_console_font( struct console *console, const WCHAR *font,
853 unsigned int height, unsigned int weight )
855 struct font_chooser fc;
856 LOGFONTW lf;
858 if (font[0] && height && weight)
860 fill_logfont( &lf, font, height, weight );
861 if (set_console_font( console, &lf )) return;
864 /* try to find an acceptable font */
865 WARN( "Couldn't match the font from registry, trying to find one\n" );
866 fc.console = console;
867 fc.done = FALSE;
868 for (fc.pass = 0; fc.pass <= 5; fc.pass++)
870 EnumFontFamiliesW( console->window->mem_dc, NULL, get_first_font_enum, (LPARAM)&fc );
871 if (fc.done) return;
873 ERR( "Couldn't find a decent font" );
876 /* get a cell from a relative coordinate in window (takes into account the scrolling) */
877 static COORD get_cell( struct console *console, LPARAM lparam )
879 COORD c;
880 c.X = console->active->win.left + (short)LOWORD(lparam) / console->active->font.width;
881 c.Y = console->active->win.top + (short)HIWORD(lparam) / console->active->font.height;
882 return c;
885 /* get the console bit mask equivalent to the VK_ status in key state */
886 static DWORD get_ctrl_state( BYTE *key_state)
888 unsigned int ret = 0;
890 GetKeyboardState(key_state);
891 if (key_state[VK_SHIFT] & 0x80) ret |= SHIFT_PRESSED;
892 if (key_state[VK_LCONTROL] & 0x80) ret |= LEFT_CTRL_PRESSED;
893 if (key_state[VK_RCONTROL] & 0x80) ret |= RIGHT_CTRL_PRESSED;
894 if (key_state[VK_LMENU] & 0x80) ret |= LEFT_ALT_PRESSED;
895 if (key_state[VK_RMENU] & 0x80) ret |= RIGHT_ALT_PRESSED;
896 if (key_state[VK_CAPITAL] & 0x01) ret |= CAPSLOCK_ON;
897 if (key_state[VK_NUMLOCK] & 0x01) ret |= NUMLOCK_ON;
898 if (key_state[VK_SCROLL] & 0x01) ret |= SCROLLLOCK_ON;
900 return ret;
903 /* get the selection rectangle */
904 static void get_selection_rect( struct console *console, RECT *r )
906 r->left = (min(console->window->selection_start.X, console->window->selection_end.X) -
907 console->active->win.left) * console->active->font.width;
908 r->top = (min(console->window->selection_start.Y, console->window->selection_end.Y) -
909 console->active->win.top) * console->active->font.height;
910 r->right = (max(console->window->selection_start.X, console->window->selection_end.X) + 1 -
911 console->active->win.left) * console->active->font.width;
912 r->bottom = (max(console->window->selection_start.Y, console->window->selection_end.Y) + 1 -
913 console->active->win.top) * console->active->font.height;
916 static void update_selection( struct console *console, HDC ref_dc )
918 HDC dc;
919 RECT r;
921 get_selection_rect( console, &r );
922 dc = ref_dc ? ref_dc : GetDC( console->win );
923 if (!dc) return;
925 if (console->win == GetFocus() && console->active->cursor_visible)
926 HideCaret( console->win );
927 InvertRect( dc, &r );
928 if (dc != ref_dc)
929 ReleaseDC( console->win, dc );
930 if (console->win == GetFocus() && console->active->cursor_visible)
931 ShowCaret( console->win );
934 static void move_selection( struct console *console, COORD c1, COORD c2 )
936 RECT r;
937 HDC dc;
939 if (c1.X < 0 || c1.X >= console->active->width ||
940 c2.X < 0 || c2.X >= console->active->width ||
941 c1.Y < 0 || c1.Y >= console->active->height ||
942 c2.Y < 0 || c2.Y >= console->active->height)
943 return;
945 get_selection_rect( console, &r );
946 dc = GetDC( console->win );
947 if (dc)
949 if (console->win == GetFocus() && console->active->cursor_visible)
950 HideCaret( console->win );
951 InvertRect( dc, &r );
953 console->window->selection_start = c1;
954 console->window->selection_end = c2;
955 if (dc)
957 get_selection_rect( console, &r );
958 InvertRect( dc, &r );
959 ReleaseDC( console->win, dc );
960 if (console->win == GetFocus() && console->active->cursor_visible)
961 ShowCaret( console->win );
965 /* copies the current selection into the clipboard */
966 static void copy_selection( struct console *console )
968 unsigned int w, h;
969 WCHAR *p, *buf;
970 HANDLE mem;
972 w = abs( console->window->selection_start.X - console->window->selection_end.X ) + 1;
973 h = abs( console->window->selection_start.Y - console->window->selection_end.Y ) + 1;
975 if (!OpenClipboard( console->win )) return;
976 EmptyClipboard();
978 mem = GlobalAlloc( GMEM_MOVEABLE, (w + 1) * h * sizeof(WCHAR) );
979 if (mem && (p = buf = GlobalLock( mem )))
981 int x, y;
982 COORD c;
984 c.X = min( console->window->selection_start.X, console->window->selection_end.X );
985 c.Y = min( console->window->selection_start.Y, console->window->selection_end.Y );
987 for (y = c.Y; y < c.Y + h; y++)
989 WCHAR *end;
991 for (x = c.X; x < c.X + w; x++)
992 p[x - c.X] = console->active->data[y * console->active->width + x].ch;
994 /* strip spaces from the end of the line */
995 end = p + w;
996 while (end > p && *(end - 1) == ' ')
997 end--;
998 *end = (y < c.Y + h - 1) ? '\n' : '\0';
999 p = end + 1;
1002 TRACE( "%s\n", debugstr_w( buf ));
1003 if (p - buf != (w + 1) * h)
1005 HANDLE new_mem;
1006 new_mem = GlobalReAlloc( mem, (p - buf) * sizeof(WCHAR), GMEM_MOVEABLE );
1007 if (new_mem) mem = new_mem;
1009 GlobalUnlock( mem );
1010 SetClipboardData( CF_UNICODETEXT, mem );
1012 CloseClipboard();
1015 static void paste_clipboard( struct console *console )
1017 WCHAR *ptr;
1018 HANDLE h;
1020 if (!OpenClipboard( console->win )) return;
1021 h = GetClipboardData( CF_UNICODETEXT );
1022 if (h && (ptr = GlobalLock( h )))
1024 unsigned int i, len = GlobalSize(h) / sizeof(WCHAR);
1025 INPUT_RECORD ir[2];
1026 SHORT sh;
1028 ir[0].EventType = KEY_EVENT;
1029 ir[0].Event.KeyEvent.wRepeatCount = 0;
1030 ir[0].Event.KeyEvent.dwControlKeyState = 0;
1031 ir[0].Event.KeyEvent.bKeyDown = TRUE;
1033 /* generate the corresponding input records */
1034 for (i = 0; i < len; i++)
1036 /* FIXME: the modifying keys are not generated (shift, ctrl...) */
1037 sh = VkKeyScanW( ptr[i] );
1038 ir[0].Event.KeyEvent.wVirtualKeyCode = LOBYTE(sh);
1039 ir[0].Event.KeyEvent.wVirtualScanCode = MapVirtualKeyW( LOBYTE(sh), 0 );
1040 ir[0].Event.KeyEvent.uChar.UnicodeChar = ptr[i];
1042 ir[1] = ir[0];
1043 ir[1].Event.KeyEvent.bKeyDown = FALSE;
1045 write_console_input( console, ir, 2, i == len - 1 );
1047 GlobalUnlock( h );
1050 CloseClipboard();
1053 /* handle keys while selecting an area */
1054 static void handle_selection_key( struct console *console, BOOL down, WPARAM wparam, LPARAM lparam )
1056 BYTE key_state[256];
1057 COORD c1, c2;
1058 DWORD state;
1060 if (!down) return;
1061 state = get_ctrl_state( key_state ) & ~(CAPSLOCK_ON|NUMLOCK_ON|SCROLLLOCK_ON);
1063 switch (state)
1065 case 0:
1066 switch (wparam)
1068 case VK_RETURN:
1069 console->window->in_selection = FALSE;
1070 update_selection( console, 0 );
1071 copy_selection( console );
1072 return;
1073 case VK_RIGHT:
1074 c1 = console->window->selection_start;
1075 c2 = console->window->selection_end;
1076 c1.X++; c2.X++;
1077 move_selection( console, c1, c2 );
1078 return;
1079 case VK_LEFT:
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_UP:
1086 c1 = console->window->selection_start;
1087 c2 = console->window->selection_end;
1088 c1.Y--; c2.Y--;
1089 move_selection( console, c1, c2 );
1090 return;
1091 case VK_DOWN:
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;
1098 break;
1099 case SHIFT_PRESSED:
1100 switch (wparam)
1102 case VK_RIGHT:
1103 c1 = console->window->selection_start;
1104 c2 = console->window->selection_end;
1105 c2.X++;
1106 move_selection( console, c1, c2 );
1107 return;
1108 case VK_LEFT:
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_UP:
1115 c1 = console->window->selection_start;
1116 c2 = console->window->selection_end;
1117 c2.Y--;
1118 move_selection( console, c1, c2 );
1119 return;
1120 case VK_DOWN:
1121 c1 = console->window->selection_start;
1122 c2 = console->window->selection_end;
1123 c2.Y++;
1124 move_selection( console, c1, c2 );
1125 return;
1127 break;
1130 if (wparam < VK_SPACE) /* Shift, Alt, Ctrl, Num Lock etc. */
1131 return;
1133 update_selection( console, 0 );
1134 console->window->in_selection = FALSE;
1137 /* generate input_record from windows WM_KEYUP/WM_KEYDOWN messages */
1138 static void record_key_input( struct console *console, BOOL down, WPARAM wparam, LPARAM lparam )
1140 static WCHAR last; /* keep last char seen as feed for key up message */
1141 BYTE key_state[256];
1142 INPUT_RECORD ir;
1143 WCHAR buf[2];
1145 ir.EventType = KEY_EVENT;
1146 ir.Event.KeyEvent.bKeyDown = down;
1147 ir.Event.KeyEvent.wRepeatCount = LOWORD(lparam);
1148 ir.Event.KeyEvent.wVirtualKeyCode = wparam;
1149 ir.Event.KeyEvent.wVirtualScanCode = HIWORD(lparam) & 0xFF;
1150 ir.Event.KeyEvent.uChar.UnicodeChar = 0;
1151 ir.Event.KeyEvent.dwControlKeyState = get_ctrl_state( key_state );
1152 if (lparam & (1u << 24)) ir.Event.KeyEvent.dwControlKeyState |= ENHANCED_KEY;
1154 if (down)
1156 switch (ToUnicode(wparam, HIWORD(lparam), key_state, buf, 2, 0))
1158 case 2:
1159 /* FIXME: should generate two events */
1160 /* fall through */
1161 case 1:
1162 last = buf[0];
1163 break;
1164 default:
1165 last = 0;
1166 break;
1169 ir.Event.KeyEvent.uChar.UnicodeChar = last;
1170 if (!down) last = 0; /* FIXME: buggy HACK */
1172 write_console_input( console, &ir, 1, TRUE );
1175 static void record_mouse_input( struct console *console, COORD c, WPARAM wparam, DWORD event )
1177 BYTE key_state[256];
1178 INPUT_RECORD ir;
1180 /* MOUSE_EVENTs shouldn't be sent unless ENABLE_MOUSE_INPUT is active */
1181 if (!(console->mode & ENABLE_MOUSE_INPUT)) return;
1183 ir.EventType = MOUSE_EVENT;
1184 ir.Event.MouseEvent.dwMousePosition = c;
1185 ir.Event.MouseEvent.dwButtonState = 0;
1186 if (wparam & MK_LBUTTON) ir.Event.MouseEvent.dwButtonState |= FROM_LEFT_1ST_BUTTON_PRESSED;
1187 if (wparam & MK_MBUTTON) ir.Event.MouseEvent.dwButtonState |= FROM_LEFT_2ND_BUTTON_PRESSED;
1188 if (wparam & MK_RBUTTON) ir.Event.MouseEvent.dwButtonState |= RIGHTMOST_BUTTON_PRESSED;
1189 if (wparam & MK_CONTROL) ir.Event.MouseEvent.dwButtonState |= LEFT_CTRL_PRESSED;
1190 if (wparam & MK_SHIFT) ir.Event.MouseEvent.dwButtonState |= SHIFT_PRESSED;
1191 if (event == MOUSE_WHEELED) ir.Event.MouseEvent.dwButtonState |= wparam & 0xFFFF0000;
1192 ir.Event.MouseEvent.dwControlKeyState = get_ctrl_state( key_state );
1193 ir.Event.MouseEvent.dwEventFlags = event;
1195 write_console_input( console, &ir, 1, TRUE );
1198 struct dialog_info
1200 struct console *console;
1201 struct console_config config;
1202 HWND dialog; /* handle to active propsheet */
1203 int font_count; /* number of fonts */
1204 struct dialog_font_info
1206 unsigned int height;
1207 unsigned int weight;
1208 WCHAR faceName[LF_FACESIZE];
1209 } *font; /* array of fonts */
1212 /* dialog proc for the option property sheet */
1213 static INT_PTR WINAPI option_dialog_proc( HWND dialog, UINT msg, WPARAM wparam, LPARAM lparam )
1215 struct dialog_info *di;
1216 unsigned int idc;
1218 switch (msg)
1220 case WM_INITDIALOG:
1221 di = (struct dialog_info *)((PROPSHEETPAGEA *)lparam)->lParam;
1222 di->dialog = dialog;
1223 SetWindowLongPtrW( dialog, DWLP_USER, (LONG_PTR)di );
1225 SendMessageW( GetDlgItem( dialog, IDC_OPT_HIST_SIZE_UD ), UDM_SETRANGE, 0, MAKELPARAM(500, 0) );
1227 if (di->config.cursor_size <= 25) idc = IDC_OPT_CURSOR_SMALL;
1228 else if (di->config.cursor_size <= 50) idc = IDC_OPT_CURSOR_MEDIUM;
1229 else idc = IDC_OPT_CURSOR_LARGE;
1231 SendDlgItemMessageW( dialog, idc, BM_SETCHECK, BST_CHECKED, 0 );
1232 SetDlgItemInt( dialog, IDC_OPT_HIST_SIZE, di->config.history_size, FALSE );
1233 SendDlgItemMessageW( dialog, IDC_OPT_HIST_NODOUBLE, BM_SETCHECK,
1234 (di->config.history_mode) ? BST_CHECKED : BST_UNCHECKED, 0 );
1235 SendDlgItemMessageW( dialog, IDC_OPT_INSERT_MODE, BM_SETCHECK,
1236 (di->config.insert_mode) ? BST_CHECKED : BST_UNCHECKED, 0 );
1237 SendDlgItemMessageW( dialog, IDC_OPT_CONF_CTRL, BM_SETCHECK,
1238 (di->config.menu_mask & MK_CONTROL) ? BST_CHECKED : BST_UNCHECKED, 0 );
1239 SendDlgItemMessageW( dialog, IDC_OPT_CONF_SHIFT, BM_SETCHECK,
1240 (di->config.menu_mask & MK_SHIFT) ? BST_CHECKED : BST_UNCHECKED, 0 );
1241 SendDlgItemMessageW( dialog, IDC_OPT_QUICK_EDIT, BM_SETCHECK,
1242 (di->config.quick_edit) ? BST_CHECKED : BST_UNCHECKED, 0 );
1243 return FALSE; /* because we set the focus */
1245 case WM_COMMAND:
1246 break;
1248 case WM_NOTIFY:
1250 NMHDR *nmhdr = (NMHDR*)lparam;
1251 DWORD val;
1252 BOOL done;
1254 di = (struct dialog_info *)GetWindowLongPtrW( dialog, DWLP_USER );
1256 switch (nmhdr->code)
1258 case PSN_SETACTIVE:
1259 /* needed in propsheet to keep properly the selected radio button
1260 * otherwise, the focus would be set to the first tab stop in the
1261 * propsheet, which would always activate the first radio button
1263 if (IsDlgButtonChecked( dialog, IDC_OPT_CURSOR_SMALL ) == BST_CHECKED)
1264 idc = IDC_OPT_CURSOR_SMALL;
1265 else if (IsDlgButtonChecked( dialog, IDC_OPT_CURSOR_MEDIUM ) == BST_CHECKED)
1266 idc = IDC_OPT_CURSOR_MEDIUM;
1267 else
1268 idc = IDC_OPT_CURSOR_LARGE;
1269 PostMessageW( dialog, WM_NEXTDLGCTL, (WPARAM)GetDlgItem( dialog, idc ), TRUE );
1270 di->dialog = dialog;
1271 break;
1272 case PSN_APPLY:
1273 if (IsDlgButtonChecked( dialog, IDC_OPT_CURSOR_SMALL ) == BST_CHECKED) val = 25;
1274 else if (IsDlgButtonChecked( dialog, IDC_OPT_CURSOR_MEDIUM ) == BST_CHECKED) val = 50;
1275 else val = 100;
1276 di->config.cursor_size = val;
1278 val = GetDlgItemInt( dialog, IDC_OPT_HIST_SIZE, &done, FALSE );
1279 if (done) di->config.history_size = val;
1281 val = (IsDlgButtonChecked( dialog, IDC_OPT_HIST_NODOUBLE ) & BST_CHECKED) != 0;
1282 di->config.history_mode = val;
1284 val = (IsDlgButtonChecked( dialog, IDC_OPT_INSERT_MODE ) & BST_CHECKED) != 0;
1285 di->config.insert_mode = val;
1287 val = 0;
1288 if (IsDlgButtonChecked( dialog, IDC_OPT_CONF_CTRL ) & BST_CHECKED) val |= MK_CONTROL;
1289 if (IsDlgButtonChecked( dialog, IDC_OPT_CONF_SHIFT ) & BST_CHECKED) val |= MK_SHIFT;
1290 di->config.menu_mask = val;
1292 val = (IsDlgButtonChecked( dialog, IDC_OPT_QUICK_EDIT ) & BST_CHECKED) != 0;
1293 di->config.quick_edit = val;
1295 SetWindowLongPtrW( dialog, DWLP_MSGRESULT, PSNRET_NOERROR );
1296 return TRUE;
1297 default:
1298 return FALSE;
1300 break;
1302 default:
1303 return FALSE;
1305 return TRUE;
1308 static COLORREF get_color( struct dialog_info *di, unsigned int idc )
1310 LONG_PTR index;
1312 index = GetWindowLongPtrW(GetDlgItem( di->dialog, idc ), 0);
1313 return di->config.color_map[index];
1316 /* window proc for font previewer in font property sheet */
1317 static LRESULT WINAPI font_preview_proc( HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam )
1319 switch (msg)
1321 case WM_CREATE:
1322 SetWindowLongPtrW( hwnd, 0, 0 );
1323 break;
1325 case WM_GETFONT:
1326 return GetWindowLongPtrW( hwnd, 0 );
1328 case WM_SETFONT:
1329 SetWindowLongPtrW( hwnd, 0, wparam );
1330 if (LOWORD(lparam))
1332 InvalidateRect( hwnd, NULL, TRUE );
1333 UpdateWindow( hwnd );
1335 break;
1337 case WM_DESTROY:
1339 HFONT font = (HFONT)GetWindowLongPtrW( hwnd, 0 );
1340 if (font) DeleteObject( font );
1341 break;
1344 case WM_PAINT:
1346 struct dialog_info *di;
1347 HFONT font, old_font;
1348 PAINTSTRUCT ps;
1349 int size_idx;
1351 di = (struct dialog_info *)GetWindowLongPtrW( GetParent( hwnd ), DWLP_USER );
1352 BeginPaint( hwnd, &ps );
1354 size_idx = SendDlgItemMessageW( di->dialog, IDC_FNT_LIST_SIZE, LB_GETCURSEL, 0, 0 );
1355 font = (HFONT)GetWindowLongPtrW( hwnd, 0 );
1356 if (font)
1358 static const WCHAR ascii[] = L"ASCII: abcXYZ";
1359 COLORREF bkcolor;
1360 WCHAR buf[256];
1361 int len;
1363 old_font = SelectObject( ps.hdc, font );
1364 bkcolor = get_color( di, IDC_FNT_COLOR_BK );
1365 FillRect( ps.hdc, &ps.rcPaint, CreateSolidBrush( bkcolor ));
1366 SetBkColor( ps.hdc, bkcolor );
1367 SetTextColor( ps.hdc, get_color( di, IDC_FNT_COLOR_FG ));
1368 len = LoadStringW( GetModuleHandleW(NULL), IDS_FNT_PREVIEW, buf, ARRAY_SIZE(buf) );
1369 if (len) TextOutW( ps.hdc, 0, 0, buf, len );
1370 TextOutW( ps.hdc, 0, di->font[size_idx].height, ascii, ARRAY_SIZE(ascii) - 1 );
1371 SelectObject( ps.hdc, old_font );
1373 EndPaint( hwnd, &ps );
1374 break;
1377 default:
1378 return DefWindowProcW( hwnd, msg, wparam, lparam );
1380 return 0;
1383 /* window proc for color previewer */
1384 static LRESULT WINAPI color_preview_proc( HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam )
1386 switch (msg)
1388 case WM_PAINT:
1390 struct dialog_info *di;
1391 PAINTSTRUCT ps;
1392 RECT client, r;
1393 int i, step;
1394 HBRUSH brush;
1396 BeginPaint( hwnd, &ps );
1397 GetClientRect( hwnd, &client );
1398 step = client.right / 8;
1400 di = (struct dialog_info *)GetWindowLongPtrW( GetParent(hwnd), DWLP_USER );
1402 for (i = 0; i < 16; i++)
1404 r.top = (i / 8) * (client.bottom / 2);
1405 r.bottom = r.top + client.bottom / 2;
1406 r.left = (i & 7) * step;
1407 r.right = r.left + step;
1408 brush = CreateSolidBrush( di->config.color_map[i] );
1409 FillRect( ps.hdc, &r, brush );
1410 DeleteObject( brush );
1411 if (GetWindowLongW( hwnd, 0 ) == i)
1413 HPEN old_pen;
1414 int i = 2;
1416 old_pen = SelectObject( ps.hdc, GetStockObject( WHITE_PEN ));
1417 r.right--; r.bottom--;
1418 for (;;)
1420 MoveToEx( ps.hdc, r.left, r.bottom, NULL );
1421 LineTo( ps.hdc, r.left, r.top );
1422 LineTo( ps.hdc, r.right, r.top );
1423 SelectObject( ps.hdc, GetStockObject( BLACK_PEN ));
1424 LineTo( ps.hdc, r.right, r.bottom );
1425 LineTo( ps.hdc, r.left, r.bottom );
1426 if (--i == 0) break;
1427 r.left++; r.top++; r.right--; r.bottom--;
1428 SelectObject( ps.hdc, GetStockObject( WHITE_PEN ));
1430 SelectObject( ps.hdc, old_pen );
1433 EndPaint( hwnd, &ps );
1434 break;
1437 case WM_LBUTTONDOWN:
1439 int i, step;
1440 RECT client;
1442 GetClientRect( hwnd, &client );
1443 step = client.right / 8;
1444 i = (HIWORD(lparam) >= client.bottom / 2) ? 8 : 0;
1445 i += LOWORD(lparam) / step;
1446 SetWindowLongW( hwnd, 0, i );
1447 InvalidateRect( GetDlgItem( GetParent( hwnd ), IDC_FNT_PREVIEW ), NULL, FALSE );
1448 InvalidateRect( hwnd, NULL, FALSE );
1449 break;
1452 default:
1453 return DefWindowProcW( hwnd, msg, wparam, lparam );
1455 return 0;
1458 /* enumerates all the font names with at least one valid font */
1459 static int WINAPI font_enum_size2( const LOGFONTW *lf, const TEXTMETRICW *tm,
1460 DWORD font_type, LPARAM lparam )
1462 struct dialog_info *di = (struct dialog_info *)lparam;
1463 TRACE( "%s\n", debugstr_textmetric( tm, font_type ));
1464 if (validate_font_metric( di->console, tm, font_type, 0 )) di->font_count++;
1465 return 1;
1468 static int WINAPI font_enum( const LOGFONTW *lf, const TEXTMETRICW *tm,
1469 DWORD font_type, LPARAM lparam )
1471 struct dialog_info *di = (struct dialog_info *)lparam;
1473 TRACE( "%s\n", debugstr_logfont( lf, font_type ));
1475 if (validate_font( di->console, lf, 0 ))
1477 if (font_type & RASTER_FONTTYPE)
1479 di->font_count = 0;
1480 EnumFontFamiliesW( di->console->window->mem_dc, lf->lfFaceName,
1481 font_enum_size2, (LPARAM)di );
1483 else
1484 di->font_count = 1;
1486 if (di->font_count)
1487 SendDlgItemMessageW( di->dialog, IDC_FNT_LIST_FONT, LB_ADDSTRING,
1488 0, (LPARAM)lf->lfFaceName );
1490 return 1;
1493 static int WINAPI font_enum_size( const LOGFONTW *lf, const TEXTMETRICW *tm,
1494 DWORD font_type, LPARAM lparam )
1496 struct dialog_info *di = (struct dialog_info *)lparam;
1497 WCHAR buf[32];
1499 TRACE( "%s\n", debugstr_textmetric( tm, font_type ));
1501 if (di->font_count == 0 && !(font_type & RASTER_FONTTYPE))
1503 static const int sizes[] = {8,9,10,11,12,14,16,18,20,22,24,26,28,36,48,72};
1504 int i;
1506 di->font_count = ARRAY_SIZE(sizes);
1507 di->font = malloc( di->font_count * sizeof(di->font[0]) );
1508 for (i = 0; i < di->font_count; i++)
1510 /* drop sizes where window size wouldn't fit on screen */
1511 if (sizes[i] * di->config.win_height > GetSystemMetrics( SM_CYSCREEN ))
1513 di->font_count = i;
1514 break;
1516 di->font[i].height = sizes[i];
1517 di->font[i].weight = 400;
1518 lstrcpyW( di->font[i].faceName, lf->lfFaceName );
1519 wsprintfW( buf, L"%d", sizes[i] );
1520 SendDlgItemMessageW( di->dialog, IDC_FNT_LIST_SIZE, LB_INSERTSTRING, i, (LPARAM)buf );
1522 /* don't need to enumerate other */
1523 return 0;
1526 if (validate_font_metric( di->console, tm, font_type, 0 ))
1528 int idx = 0;
1530 /* we want the string to be sorted with a numeric order, not a lexicographic...
1531 * do the job by hand... get where to insert the new string
1533 while (idx < di->font_count && tm->tmHeight > di->font[idx].height)
1534 idx++;
1535 while (idx < di->font_count &&
1536 tm->tmHeight == di->font[idx].height &&
1537 tm->tmWeight > di->font[idx].weight)
1538 idx++;
1539 if (idx == di->font_count ||
1540 tm->tmHeight != di->font[idx].height ||
1541 tm->tmWeight < di->font[idx].weight)
1543 /* here we need to add the new entry */
1544 wsprintfW( buf, L"%d", tm->tmHeight );
1545 SendDlgItemMessageW( di->dialog, IDC_FNT_LIST_SIZE, LB_INSERTSTRING, idx, (LPARAM)buf );
1547 /* now grow our arrays and insert the values at the same index than in the list box */
1548 if (di->font_count)
1550 di->font = realloc( di->font, sizeof(*di->font) * (di->font_count + 1) );
1551 if (idx != di->font_count)
1552 memmove( &di->font[idx + 1], &di->font[idx],
1553 (di->font_count - idx) * sizeof(*di->font) );
1555 else
1556 di->font = malloc( sizeof(*di->font) );
1557 di->font[idx].height = tm->tmHeight;
1558 di->font[idx].weight = tm->tmWeight;
1559 lstrcpyW( di->font[idx].faceName, lf->lfFaceName );
1560 di->font_count++;
1563 return 1;
1566 static BOOL select_font( struct dialog_info *di )
1568 struct console_config config;
1569 int font_idx, size_idx;
1570 HFONT font, old_font;
1571 DWORD_PTR args[2];
1572 WCHAR buf[256];
1573 WCHAR fmt[128];
1574 LOGFONTW lf;
1576 font_idx = SendDlgItemMessageW( di->dialog, IDC_FNT_LIST_FONT, LB_GETCURSEL, 0, 0 );
1577 size_idx = SendDlgItemMessageW( di->dialog, IDC_FNT_LIST_SIZE, LB_GETCURSEL, 0, 0 );
1579 if (font_idx < 0 || size_idx < 0 || size_idx >= di->font_count)
1580 return FALSE;
1582 fill_logfont( &lf, di->font[size_idx].faceName, di->font[size_idx].height,
1583 di->font[size_idx].weight );
1584 font = select_font_config( &config, di->console->output_cp, di->console->win, &lf );
1585 if (!font) return FALSE;
1587 if (config.cell_height != di->font[size_idx].height)
1588 TRACE( "mismatched heights (%u<>%u)\n", config.cell_height, di->font[size_idx].height );
1590 old_font = (HFONT)SendDlgItemMessageW( di->dialog, IDC_FNT_PREVIEW, WM_GETFONT, 0, 0 );
1591 SendDlgItemMessageW( di->dialog, IDC_FNT_PREVIEW, WM_SETFONT, (WPARAM)font, TRUE );
1592 if (old_font) DeleteObject( old_font );
1594 LoadStringW( GetModuleHandleW(NULL), IDS_FNT_DISPLAY, fmt, ARRAY_SIZE(fmt) );
1595 args[0] = config.cell_width;
1596 args[1] = config.cell_height;
1597 FormatMessageW( FORMAT_MESSAGE_FROM_STRING|FORMAT_MESSAGE_ARGUMENT_ARRAY,
1598 fmt, 0, 0, buf, ARRAY_SIZE(buf), (__ms_va_list*)args );
1600 SendDlgItemMessageW( di->dialog, IDC_FNT_FONT_INFO, WM_SETTEXT, 0, (LPARAM)buf );
1601 return TRUE;
1604 /* fills the size list box according to selected family in font LB */
1605 static BOOL fill_list_size( struct dialog_info *di, BOOL init )
1607 WCHAR face_name[LF_FACESIZE];
1608 int idx = 0;
1610 idx = SendDlgItemMessageW( di->dialog, IDC_FNT_LIST_FONT, LB_GETCURSEL, 0, 0 );
1611 if (idx < 0) return FALSE;
1613 SendDlgItemMessageW( di->dialog, IDC_FNT_LIST_FONT, LB_GETTEXT, idx, (LPARAM)face_name );
1614 SendDlgItemMessageW( di->dialog, IDC_FNT_LIST_SIZE, LB_RESETCONTENT, 0, 0 );
1615 free( di->font );
1616 di->font_count = 0;
1617 di->font = NULL;
1619 EnumFontFamiliesW( di->console->window->mem_dc, face_name, font_enum_size, (LPARAM)di );
1621 if (init)
1623 int ref = -1;
1624 for (idx = 0; idx < di->font_count; idx++)
1626 if (!lstrcmpW( di->font[idx].faceName, di->config.face_name ) &&
1627 di->font[idx].height == di->config.cell_height &&
1628 di->font[idx].weight == di->config.font_weight)
1630 if (ref == -1) ref = idx;
1631 else TRACE("Several matches found: ref=%d idx=%d\n", ref, idx);
1634 idx = (ref == -1) ? 0 : ref;
1637 SendDlgItemMessageW( di->dialog, IDC_FNT_LIST_SIZE, LB_SETCURSEL, idx, 0 );
1638 select_font( di );
1639 return TRUE;
1642 static BOOL fill_list_font( struct dialog_info *di )
1644 SendDlgItemMessageW( di->dialog, IDC_FNT_LIST_FONT, LB_RESETCONTENT, 0, 0 );
1645 EnumFontFamiliesW( di->console->window->mem_dc, NULL, font_enum, (LPARAM)di );
1646 if (SendDlgItemMessageW( di->dialog, IDC_FNT_LIST_FONT, LB_SELECTSTRING,
1647 -1, (LPARAM)di->config.face_name ) == LB_ERR)
1648 SendDlgItemMessageW( di->dialog, IDC_FNT_LIST_FONT, LB_SETCURSEL, 0, 0 );
1649 fill_list_size( di, TRUE );
1650 return TRUE;
1653 /* dialog proc for the font property sheet */
1654 static INT_PTR WINAPI font_dialog_proc( HWND dialog, UINT msg, WPARAM wparam, LPARAM lparam )
1656 struct dialog_info *di;
1658 switch (msg)
1660 case WM_INITDIALOG:
1661 di = (struct dialog_info *)((PROPSHEETPAGEA*)lparam)->lParam;
1662 di->dialog = dialog;
1663 SetWindowLongPtrW( dialog, DWLP_USER, (DWORD_PTR)di );
1664 /* remove dialog from this control, font will be reset when listboxes are filled */
1665 SendDlgItemMessageW( dialog, IDC_FNT_PREVIEW, WM_SETFONT, 0, 0 );
1666 fill_list_font( di );
1667 SetWindowLongW( GetDlgItem( dialog, IDC_FNT_COLOR_BK ), 0, (di->config.attr >> 4) & 0x0F );
1668 SetWindowLongW( GetDlgItem( dialog, IDC_FNT_COLOR_FG ), 0, di->config.attr & 0x0F );
1669 break;
1671 case WM_COMMAND:
1672 di = (struct dialog_info *)GetWindowLongPtrW( dialog, DWLP_USER );
1673 switch (LOWORD(wparam))
1675 case IDC_FNT_LIST_FONT:
1676 if (HIWORD(wparam) == LBN_SELCHANGE)
1677 fill_list_size( di, FALSE );
1678 break;
1679 case IDC_FNT_LIST_SIZE:
1680 if (HIWORD(wparam) == LBN_SELCHANGE)
1681 select_font( di );
1682 break;
1684 break;
1686 case WM_NOTIFY:
1688 NMHDR *nmhdr = (NMHDR*)lparam;
1689 DWORD val;
1691 di = (struct dialog_info*)GetWindowLongPtrW( dialog, DWLP_USER );
1692 switch (nmhdr->code)
1694 case PSN_SETACTIVE:
1695 di->dialog = dialog;
1696 break;
1697 case PSN_APPLY:
1698 val = SendDlgItemMessageW( dialog, IDC_FNT_LIST_SIZE, LB_GETCURSEL, 0, 0 );
1699 if (val < di->font_count)
1701 LOGFONTW lf;
1703 fill_logfont( &lf, di->font[val].faceName, di->font[val].height, di->font[val].weight );
1704 DeleteObject( select_font_config( &di->config, di->console->output_cp,
1705 di->console->win, &lf ));
1708 val = (GetWindowLongW( GetDlgItem( dialog, IDC_FNT_COLOR_BK ), 0 ) << 4) |
1709 GetWindowLongW( GetDlgItem( dialog, IDC_FNT_COLOR_FG ), 0 );
1710 di->config.attr = val;
1711 SetWindowLongPtrW( dialog, DWLP_MSGRESULT, PSNRET_NOERROR );
1712 return TRUE;
1713 default:
1714 return FALSE;
1716 break;
1718 default:
1719 return FALSE;
1721 return TRUE;
1724 /* dialog proc for the config property sheet */
1725 static INT_PTR WINAPI config_dialog_proc( HWND dialog, UINT msg, WPARAM wparam, LPARAM lparam )
1727 struct dialog_info *di;
1728 int max_ud = 2000;
1730 switch (msg)
1732 case WM_INITDIALOG:
1733 di = (struct dialog_info *)((PROPSHEETPAGEA*)lparam)->lParam;
1734 di->dialog = dialog;
1736 SetWindowLongPtrW( dialog, DWLP_USER, (DWORD_PTR)di );
1737 SetDlgItemInt( dialog, IDC_CNF_SB_WIDTH, di->config.sb_width, FALSE );
1738 SetDlgItemInt( dialog, IDC_CNF_SB_HEIGHT, di->config.sb_height, FALSE );
1739 SetDlgItemInt( dialog, IDC_CNF_WIN_WIDTH, di->config.win_width, FALSE );
1740 SetDlgItemInt( dialog, IDC_CNF_WIN_HEIGHT, di->config.win_height, FALSE );
1742 SendMessageW( GetDlgItem(dialog, IDC_CNF_WIN_HEIGHT_UD), UDM_SETRANGE, 0, MAKELPARAM(max_ud, 0));
1743 SendMessageW( GetDlgItem(dialog, IDC_CNF_WIN_WIDTH_UD), UDM_SETRANGE, 0, MAKELPARAM(max_ud, 0));
1744 SendMessageW( GetDlgItem(dialog, IDC_CNF_SB_HEIGHT_UD), UDM_SETRANGE, 0, MAKELPARAM(max_ud, 0));
1745 SendMessageW( GetDlgItem(dialog, IDC_CNF_SB_WIDTH_UD), UDM_SETRANGE, 0, MAKELPARAM(max_ud, 0));
1747 SendDlgItemMessageW( dialog, IDC_CNF_CLOSE_EXIT, BM_SETCHECK, BST_CHECKED, 0 );
1749 SendDlgItemMessageW( dialog, IDC_CNF_EDITION_MODE, CB_ADDSTRING, 0, (LPARAM)L"Win32" );
1750 SendDlgItemMessageW( dialog, IDC_CNF_EDITION_MODE, CB_ADDSTRING, 0, (LPARAM)L"Emacs" );
1751 SendDlgItemMessageW( dialog, IDC_CNF_EDITION_MODE, CB_SETCURSEL, di->config.edition_mode, 0 );
1752 break;
1754 case WM_NOTIFY:
1756 NMHDR *nmhdr = (NMHDR*)lparam;
1757 int win_w, win_h, sb_w, sb_h;
1758 BOOL st1, st2;
1760 di = (struct dialog_info *)GetWindowLongPtrW( dialog, DWLP_USER );
1761 switch (nmhdr->code)
1763 case PSN_SETACTIVE:
1764 di->dialog = dialog;
1765 break;
1766 case PSN_APPLY:
1767 sb_w = GetDlgItemInt( dialog, IDC_CNF_SB_WIDTH, &st1, FALSE );
1768 sb_h = GetDlgItemInt( dialog, IDC_CNF_SB_HEIGHT, &st2, FALSE );
1769 if (!st1 || ! st2)
1771 SetWindowLongPtrW( dialog, DWLP_MSGRESULT, PSNRET_INVALID );
1772 return TRUE;
1774 win_w = GetDlgItemInt( dialog, IDC_CNF_WIN_WIDTH, &st1, FALSE );
1775 win_h = GetDlgItemInt( dialog, IDC_CNF_WIN_HEIGHT, &st2, FALSE );
1776 if (!st1 || !st2)
1778 SetWindowLongPtrW( dialog, DWLP_MSGRESULT, PSNRET_INVALID );
1779 return TRUE;
1781 if (win_w > sb_w || win_h > sb_h)
1783 WCHAR cap[256];
1784 WCHAR txt[256];
1786 LoadStringW( GetModuleHandleW(NULL), IDS_DLG_TIT_ERROR, cap, ARRAY_SIZE(cap) );
1787 LoadStringW( GetModuleHandleW(NULL), IDS_DLG_ERR_SBWINSIZE, txt, ARRAY_SIZE(txt) );
1789 MessageBoxW( dialog, txt, cap, MB_OK );
1790 SetWindowLongPtrW( dialog, DWLP_MSGRESULT, PSNRET_INVALID );
1791 return TRUE;
1793 di->config.win_width = win_w;
1794 di->config.win_height = win_h;
1795 di->config.sb_width = sb_w;
1796 di->config.sb_height = sb_h;
1798 di->config.edition_mode = SendDlgItemMessageW( dialog, IDC_CNF_EDITION_MODE,
1799 CB_GETCURSEL, 0, 0 );
1800 SetWindowLongPtrW( dialog, DWLP_MSGRESULT, PSNRET_NOERROR );
1801 return TRUE;
1802 default:
1803 return FALSE;
1805 break;
1807 default:
1808 return FALSE;
1810 return TRUE;
1813 /* dialog proc for choosing how to handle modification to the console settings */
1814 static INT_PTR WINAPI save_dialog_proc( HWND dialog, UINT msg, WPARAM wparam, LPARAM lparam )
1816 switch (msg)
1818 case WM_INITDIALOG:
1819 SendDlgItemMessageW( dialog, IDC_SAV_SESSION, BM_SETCHECK, BST_CHECKED, 0 );
1820 break;
1822 case WM_COMMAND:
1823 switch (LOWORD(wparam))
1825 case IDOK:
1826 EndDialog( dialog,
1827 (IsDlgButtonChecked(dialog, IDC_SAV_SAVE) == BST_CHECKED) ?
1828 IDC_SAV_SAVE : IDC_SAV_SESSION );
1829 break;
1830 case IDCANCEL:
1831 EndDialog( dialog, IDCANCEL ); break;
1833 break;
1834 default:
1835 return FALSE;
1837 return TRUE;
1840 static void apply_config( struct console *console, const struct console_config *config )
1842 if (console->active->width != config->sb_width || console->active->height != config->sb_height)
1843 change_screen_buffer_size( console->active, config->sb_width, config->sb_height );
1845 console->window->menu_mask = config->menu_mask;
1846 console->window->quick_edit = config->quick_edit;
1848 console->edition_mode = config->edition_mode;
1849 console->history_mode = config->history_mode;
1851 if (console->history_size != config->history_size)
1853 struct history_line **mem = NULL;
1854 int i, delta;
1856 if (config->history_size && (mem = malloc( config->history_size * sizeof(*mem) )))
1858 memset( mem, 0, config->history_size * sizeof(*mem) );
1860 delta = (console->history_index > config->history_size)
1861 ? (console->history_index - config->history_size) : 0;
1863 for (i = delta; i < console->history_index; i++)
1865 mem[i - delta] = console->history[i];
1866 console->history[i] = NULL;
1868 console->history_index -= delta;
1870 for (i = 0; i < console->history_size; i++)
1871 free( console->history[i] );
1872 free( console->history );
1873 console->history = mem;
1874 console->history_size = config->history_size;
1878 if (config->insert_mode)
1879 console->mode |= ENABLE_INSERT_MODE|ENABLE_EXTENDED_FLAGS;
1880 else
1881 console->mode &= ~ENABLE_INSERT_MODE;
1883 console->active->cursor_size = config->cursor_size;
1884 console->active->cursor_visible = config->cursor_visible;
1885 console->active->attr = config->attr;
1886 console->active->popup_attr = config->popup_attr;
1887 console->active->win.left = config->win_pos.X;
1888 console->active->win.top = config->win_pos.Y;
1889 console->active->win.right = config->win_pos.X + config->win_width - 1;
1890 console->active->win.bottom = config->win_pos.Y + config->win_height - 1;
1891 memcpy( console->active->color_map, config->color_map, sizeof(config->color_map) );
1893 if (console->active->font.width != config->cell_width ||
1894 console->active->font.height != config->cell_height ||
1895 console->active->font.weight != config->font_weight ||
1896 console->active->font.pitch_family != config->font_pitch_family ||
1897 console->active->font.face_len != wcslen( config->face_name ) * sizeof(WCHAR) ||
1898 memcmp( console->active->font.face_name, config->face_name, console->active->font.face_len ))
1900 update_console_font( console, config->face_name, config->cell_height, config->font_weight );
1903 update_window( console );
1906 static void current_config( struct console *console, struct console_config *config )
1908 size_t len;
1910 config->menu_mask = console->window->menu_mask;
1911 config->quick_edit = console->window->quick_edit;
1913 config->edition_mode = console->edition_mode;
1914 config->history_mode = console->history_mode;
1915 config->history_size = console->history_size;
1917 config->insert_mode = (console->mode & (ENABLE_INSERT_MODE|ENABLE_EXTENDED_FLAGS)) ==
1918 (ENABLE_INSERT_MODE|ENABLE_EXTENDED_FLAGS);
1920 config->cursor_size = console->active->cursor_size;
1921 config->cursor_visible = console->active->cursor_visible;
1922 config->attr = console->active->attr;
1923 config->popup_attr = console->active->popup_attr;
1924 memcpy( config->color_map, console->active->color_map, sizeof(config->color_map) );
1926 config->win_height = console->active->win.bottom - console->active->win.top + 1;
1927 config->win_width = console->active->win.right - console->active->win.left + 1;
1928 config->cell_width = console->active->font.width;
1929 config->cell_height = console->active->font.height;
1930 config->font_weight = console->active->font.weight;
1931 config->font_pitch_family = console->active->font.pitch_family;
1932 len = min( ARRAY_SIZE(config->face_name) - 1, console->active->font.face_len / sizeof(WCHAR) );
1933 if (len) memcpy( config->face_name, console->active->font.face_name, len * sizeof(WCHAR) );
1934 config->face_name[len] = 0;
1936 config->sb_width = console->active->width;
1937 config->sb_height = console->active->height;
1939 config->win_width = console->active->win.right - console->active->win.left + 1;
1940 config->win_height = console->active->win.bottom - console->active->win.top + 1;
1941 config->win_pos.X = console->active->win.left;
1942 config->win_pos.Y = console->active->win.top;
1945 /* run the dialog box to set up the console options */
1946 static BOOL config_dialog( struct console *console, BOOL current )
1948 struct console_config prev_config;
1949 struct dialog_info di;
1950 PROPSHEETHEADERW header;
1951 HPROPSHEETPAGE pages[3];
1952 PROPSHEETPAGEW psp;
1953 WNDCLASSW wndclass;
1954 WCHAR buff[256];
1955 BOOL modify_session = FALSE;
1956 BOOL save = FALSE;
1958 InitCommonControls();
1960 memset( &di, 0, sizeof(di) );
1961 di.console = console;
1962 if (!current)
1964 load_config( NULL, &di.config );
1965 save = TRUE;
1967 else current_config( console, &di.config );
1968 prev_config = di.config;
1969 di.font_count = 0;
1970 di.font = NULL;
1972 wndclass.style = 0;
1973 wndclass.lpfnWndProc = font_preview_proc;
1974 wndclass.cbClsExtra = 0;
1975 wndclass.cbWndExtra = sizeof(HFONT);
1976 wndclass.hInstance = GetModuleHandleW( NULL );
1977 wndclass.hIcon = 0;
1978 wndclass.hCursor = LoadCursorW( 0, (const WCHAR *)IDC_ARROW );
1979 wndclass.hbrBackground = GetStockObject( BLACK_BRUSH );
1980 wndclass.lpszMenuName = NULL;
1981 wndclass.lpszClassName = L"WineConFontPreview";
1982 RegisterClassW( &wndclass );
1984 wndclass.style = 0;
1985 wndclass.lpfnWndProc = color_preview_proc;
1986 wndclass.cbClsExtra = 0;
1987 wndclass.cbWndExtra = sizeof(DWORD);
1988 wndclass.hInstance = GetModuleHandleW( NULL );
1989 wndclass.hIcon = 0;
1990 wndclass.hCursor = LoadCursorW( 0, (const WCHAR *)IDC_ARROW );
1991 wndclass.hbrBackground = GetStockObject( BLACK_BRUSH );
1992 wndclass.lpszMenuName = NULL;
1993 wndclass.lpszClassName = L"WineConColorPreview";
1994 RegisterClassW( &wndclass );
1996 memset( &psp, 0, sizeof(psp) );
1997 psp.dwSize = sizeof(psp);
1998 psp.dwFlags = 0;
1999 psp.hInstance = wndclass.hInstance;
2000 psp.lParam = (LPARAM)&di;
2002 psp.u.pszTemplate = MAKEINTRESOURCEW(IDD_OPTION);
2003 psp.pfnDlgProc = option_dialog_proc;
2004 pages[0] = CreatePropertySheetPageW( &psp );
2006 psp.u.pszTemplate = MAKEINTRESOURCEW(IDD_FONT);
2007 psp.pfnDlgProc = font_dialog_proc;
2008 pages[1] = CreatePropertySheetPageW( &psp );
2010 psp.u.pszTemplate = MAKEINTRESOURCEW(IDD_CONFIG);
2011 psp.pfnDlgProc = config_dialog_proc;
2012 pages[2] = CreatePropertySheetPageW( &psp );
2014 memset( &header, 0, sizeof(header) );
2015 header.dwSize = sizeof(header);
2017 if (!LoadStringW( GetModuleHandleW( NULL ),
2018 current ? IDS_DLG_TIT_CURRENT : IDS_DLG_TIT_DEFAULT,
2019 buff, ARRAY_SIZE(buff) ))
2020 wcscpy( buff, L"Setup" );
2022 header.pszCaption = buff;
2023 header.nPages = 3;
2024 header.hwndParent = console->win;
2025 header.u3.phpage = pages;
2026 header.dwFlags = PSH_NOAPPLYNOW;
2027 PropertySheetW( &header );
2029 if (!memcmp( &prev_config, &di.config, sizeof(prev_config) ))
2030 return TRUE;
2032 TRACE( "%s\n", debugstr_config(&di.config) );
2034 if (!save)
2036 switch (DialogBoxW( GetModuleHandleW( NULL ), MAKEINTRESOURCEW(IDD_SAVE_SETTINGS),
2037 console->win, save_dialog_proc ))
2039 case IDC_SAV_SAVE:
2040 save = TRUE;
2041 modify_session = TRUE;
2042 break;
2043 case IDC_SAV_SESSION:
2044 modify_session = TRUE;
2045 break;
2046 default:
2047 ERR( "dialog failed\n" );
2048 /* fall through */
2049 case IDCANCEL:
2050 modify_session = FALSE;
2051 save = FALSE;
2052 break;
2056 if (modify_session)
2058 apply_config( console, &di.config );
2059 update_window( di.console );
2061 if (save)
2062 save_config( current ? console->window->config_key : NULL, &di.config );
2063 return TRUE;
2066 static void resize_window( struct console *console, int width, int height )
2068 struct console_config config;
2070 current_config( console, &config );
2071 config.win_width = width;
2072 config.win_height = height;
2074 /* auto size screen-buffer if it's now smaller than window */
2075 if (config.sb_width < config.win_width)
2076 config.sb_width = config.win_width;
2077 if (config.sb_height < config.win_height)
2078 config.sb_height = config.win_height;
2080 /* and reset window pos so that we don't display outside of the screen-buffer */
2081 if (config.win_pos.X + config.win_width > config.sb_width)
2082 config.win_pos.X = config.sb_width - config.win_width;
2083 if (config.win_pos.Y + config.win_height > config.sb_height)
2084 config.win_pos.Y = config.sb_height - config.win_height;
2086 apply_config( console, &config );
2089 /* grays / ungrays the menu items according to their state */
2090 static void set_menu_details( struct console *console, HMENU menu )
2092 EnableMenuItem( menu, IDS_COPY, MF_BYCOMMAND |
2093 (console->window->in_selection ? MF_ENABLED : MF_GRAYED) );
2094 EnableMenuItem( menu, IDS_PASTE, MF_BYCOMMAND |
2095 (IsClipboardFormatAvailable(CF_UNICODETEXT) ? MF_ENABLED : MF_GRAYED) );
2096 EnableMenuItem( menu, IDS_SCROLL, MF_BYCOMMAND | MF_GRAYED );
2097 EnableMenuItem( menu, IDS_SEARCH, MF_BYCOMMAND | MF_GRAYED );
2100 static BOOL fill_menu( HMENU menu, BOOL sep )
2102 HINSTANCE module = GetModuleHandleW( NULL );
2103 HMENU sub_menu;
2104 WCHAR buff[256];
2106 if (!menu) return FALSE;
2108 sub_menu = CreateMenu();
2109 if (!sub_menu) return FALSE;
2111 LoadStringW( module, IDS_MARK, buff, ARRAY_SIZE(buff) );
2112 InsertMenuW( sub_menu, -1, MF_BYPOSITION|MF_STRING, IDS_MARK, buff );
2113 LoadStringW( module, IDS_COPY, buff, ARRAY_SIZE(buff) );
2114 InsertMenuW( sub_menu, -1, MF_BYPOSITION|MF_STRING, IDS_COPY, buff );
2115 LoadStringW( module, IDS_PASTE, buff, ARRAY_SIZE(buff) );
2116 InsertMenuW( sub_menu, -1, MF_BYPOSITION|MF_STRING, IDS_PASTE, buff );
2117 LoadStringW( module, IDS_SELECTALL, buff, ARRAY_SIZE(buff) );
2118 InsertMenuW( sub_menu, -1, MF_BYPOSITION|MF_STRING, IDS_SELECTALL, buff );
2119 LoadStringW( module, IDS_SCROLL, buff, ARRAY_SIZE(buff) );
2120 InsertMenuW( sub_menu, -1, MF_BYPOSITION|MF_STRING, IDS_SCROLL, buff );
2121 LoadStringW( module, IDS_SEARCH, buff, ARRAY_SIZE(buff) );
2122 InsertMenuW( sub_menu, -1, MF_BYPOSITION|MF_STRING, IDS_SEARCH, buff );
2124 if (sep) InsertMenuW( menu, -1, MF_BYPOSITION|MF_SEPARATOR, 0, NULL );
2125 LoadStringW( module, IDS_EDIT, buff, ARRAY_SIZE(buff) );
2126 InsertMenuW( menu, -1, MF_BYPOSITION|MF_STRING|MF_POPUP, (UINT_PTR)sub_menu, buff );
2127 LoadStringW( module, IDS_DEFAULT, buff, ARRAY_SIZE(buff) );
2128 InsertMenuW( menu, -1, MF_BYPOSITION|MF_STRING, IDS_DEFAULT, buff );
2129 LoadStringW( module, IDS_PROPERTIES, buff, ARRAY_SIZE(buff) );
2130 InsertMenuW( menu, -1, MF_BYPOSITION|MF_STRING, IDS_PROPERTIES, buff );
2132 return TRUE;
2135 static LRESULT window_create( HWND hwnd, const CREATESTRUCTW *create )
2137 struct console *console = create->lpCreateParams;
2138 HMENU sys_menu;
2140 TRACE( "%p\n", hwnd );
2142 SetWindowLongPtrW( hwnd, 0, (DWORD_PTR)console );
2143 console->win = hwnd;
2145 sys_menu = GetSystemMenu( hwnd, FALSE );
2146 if (!sys_menu) return 0;
2147 console->window->popup_menu = CreatePopupMenu();
2148 if (!console->window->popup_menu) return 0;
2150 fill_menu( sys_menu, TRUE );
2151 fill_menu( console->window->popup_menu, FALSE );
2153 console->window->mem_dc = CreateCompatibleDC( 0 );
2154 return 0;
2157 static LRESULT WINAPI window_proc( HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam )
2159 struct console *console = (struct console *)GetWindowLongPtrW( hwnd, 0 );
2161 switch (msg)
2163 case WM_CREATE:
2164 return window_create( hwnd, (const CREATESTRUCTW *)lparam );
2166 case WM_DESTROY:
2167 console->win = NULL;
2168 PostQuitMessage( 0 );
2169 break;
2171 case WM_UPDATE_CONFIG:
2172 update_window( console );
2173 break;
2175 case WM_PAINT:
2177 PAINTSTRUCT ps;
2179 BeginPaint( console->win, &ps );
2180 BitBlt( ps.hdc, 0, 0,
2181 (console->active->win.right - console->active->win.left + 1) * console->active->font.width,
2182 (console->active->win.bottom - console->active->win.top + 1) * console->active->font.height,
2183 console->window->mem_dc,
2184 console->active->win.left * console->active->font.width,
2185 console->active->win.top * console->active->font.height,
2186 SRCCOPY );
2187 if (console->window->in_selection) update_selection( console, ps.hdc );
2188 EndPaint( console->win, &ps );
2189 break;
2192 case WM_SHOWWINDOW:
2193 if (wparam)
2194 update_window( console );
2195 else
2197 if (console->window->bitmap) DeleteObject( console->window->bitmap );
2198 console->window->bitmap = NULL;
2200 break;
2202 case WM_KEYDOWN:
2203 case WM_KEYUP:
2204 if (console->window->in_selection)
2205 handle_selection_key( console, msg == WM_KEYDOWN, wparam, lparam );
2206 else
2207 record_key_input( console, msg == WM_KEYDOWN, wparam, lparam );
2208 break;
2210 case WM_SYSKEYDOWN:
2211 case WM_SYSKEYUP:
2212 record_key_input( console, msg == WM_SYSKEYDOWN, wparam, lparam );
2213 break;
2215 case WM_LBUTTONDOWN:
2216 if (console->window->quick_edit || console->window->in_selection)
2218 if (console->window->in_selection)
2219 update_selection( console, 0 );
2221 if (console->window->quick_edit && console->window->in_selection)
2223 console->window->in_selection = FALSE;
2225 else
2227 console->window->selection_end = get_cell( console, lparam );
2228 console->window->selection_start = console->window->selection_end;
2229 SetCapture( console->win );
2230 update_selection( console, 0 );
2231 console->window->in_selection = TRUE;
2234 else
2236 record_mouse_input( console, get_cell(console, lparam), wparam, 0 );
2238 break;
2240 case WM_MOUSEMOVE:
2241 if (console->window->quick_edit || console->window->in_selection)
2243 if (GetCapture() == console->win && console->window->in_selection &&
2244 (wparam & MK_LBUTTON))
2246 move_selection( console, console->window->selection_start,
2247 get_cell(console, lparam) );
2250 else
2252 record_mouse_input( console, get_cell(console, lparam), wparam, MOUSE_MOVED );
2254 break;
2256 case WM_LBUTTONUP:
2257 if (console->window->quick_edit || console->window->in_selection)
2259 if (GetCapture() == console->win && console->window->in_selection)
2261 move_selection( console, console->window->selection_start,
2262 get_cell(console, lparam) );
2263 ReleaseCapture();
2266 else
2268 record_mouse_input( console, get_cell(console, lparam), wparam, 0 );
2270 break;
2272 case WM_RBUTTONDOWN:
2273 if ((wparam & (MK_CONTROL|MK_SHIFT)) == console->window->menu_mask)
2275 POINT pt;
2276 pt.x = (short)LOWORD(lparam);
2277 pt.y = (short)HIWORD(lparam);
2278 ClientToScreen( hwnd, &pt );
2279 set_menu_details( console, console->window->popup_menu );
2280 TrackPopupMenu( console->window->popup_menu, TPM_LEFTALIGN|TPM_TOPALIGN|TPM_RIGHTBUTTON,
2281 pt.x, pt.y, 0, hwnd, NULL );
2283 else
2285 record_mouse_input( console, get_cell(console, lparam), wparam, 0 );
2287 break;
2289 case WM_RBUTTONUP:
2290 /* no need to track for rbutton up when opening the popup... the event will be
2291 * swallowed by TrackPopupMenu */
2292 case WM_MBUTTONDOWN:
2293 case WM_MBUTTONUP:
2294 record_mouse_input( console, get_cell(console, lparam), wparam, 0 );
2295 break;
2297 case WM_LBUTTONDBLCLK:
2298 case WM_MBUTTONDBLCLK:
2299 case WM_RBUTTONDBLCLK:
2300 record_mouse_input( console, get_cell(console, lparam), wparam, DOUBLE_CLICK );
2301 break;
2303 case WM_SETFOCUS:
2304 if (console->active->cursor_visible)
2306 CreateCaret( console->win, console->window->cursor_bitmap,
2307 console->active->font.width, console->active->font.height );
2308 update_window_cursor( console );
2310 break;
2312 case WM_KILLFOCUS:
2313 if (console->active->cursor_visible)
2314 DestroyCaret();
2315 break;
2317 case WM_SIZE:
2318 if (console->window->update_state != UPDATE_BUSY)
2319 resize_window( console,
2320 max( LOWORD(lparam) / console->active->font.width, 20 ),
2321 max( HIWORD(lparam) / console->active->font.height, 20 ));
2322 break;
2324 case WM_HSCROLL:
2326 int win_width = console->active->win.right - console->active->win.left + 1;
2327 int x = console->active->win.left;
2329 switch (LOWORD(wparam))
2331 case SB_PAGEUP: x -= 8; break;
2332 case SB_PAGEDOWN: x += 8; break;
2333 case SB_LINEUP: x--; break;
2334 case SB_LINEDOWN: x++; break;
2335 case SB_THUMBTRACK: x = HIWORD(wparam); break;
2336 default: break;
2338 x = min( max( x, 0 ), console->active->width - win_width );
2339 if (x != console->active->win.left)
2341 console->active->win.left = x;
2342 console->active->win.right = x + win_width - 1;
2343 update_window( console );
2345 break;
2348 case WM_MOUSEWHEEL:
2349 if (console->active->height <= console->active->win.bottom - console->active->win.top + 1)
2351 record_mouse_input(console, get_cell(console, lparam), wparam, MOUSE_WHEELED);
2352 break;
2354 /* else fallthrough */
2355 case WM_VSCROLL:
2357 int win_height = console->active->win.bottom - console->active->win.top + 1;
2358 int y = console->active->win.top;
2360 if (msg == WM_MOUSEWHEEL)
2362 UINT scroll_lines = 3;
2363 SystemParametersInfoW( SPI_GETWHEELSCROLLLINES, 0, &scroll_lines, 0 );
2364 scroll_lines *= -GET_WHEEL_DELTA_WPARAM(wparam) / WHEEL_DELTA;
2365 y += scroll_lines;
2367 else
2369 switch (LOWORD(wparam))
2371 case SB_PAGEUP: y -= 8; break;
2372 case SB_PAGEDOWN: y += 8; break;
2373 case SB_LINEUP: y--; break;
2374 case SB_LINEDOWN: y++; break;
2375 case SB_THUMBTRACK: y = HIWORD(wparam); break;
2376 default: break;
2380 y = min( max( y, 0 ), console->active->height - win_height );
2381 if (y != console->active->win.top)
2383 console->active->win.top = y;
2384 console->active->win.bottom = y + win_height - 1;
2385 update_window( console );
2387 break;
2390 case WM_SYSCOMMAND:
2391 switch (wparam)
2393 case IDS_DEFAULT:
2394 config_dialog( console, FALSE );
2395 break;
2396 case IDS_PROPERTIES:
2397 config_dialog( console, TRUE );
2398 break;
2399 default:
2400 return DefWindowProcW( hwnd, msg, wparam, lparam );
2402 break;
2404 case WM_COMMAND:
2405 switch (wparam)
2407 case IDS_DEFAULT:
2408 config_dialog( console, FALSE );
2409 break;
2410 case IDS_PROPERTIES:
2411 config_dialog( console, TRUE );
2412 break;
2413 case IDS_MARK:
2414 console->window->selection_start.X = console->window->selection_start.Y = 0;
2415 console->window->selection_end.X = console->window->selection_end.Y = 0;
2416 update_selection( console, 0 );
2417 console->window->in_selection = TRUE;
2418 break;
2419 case IDS_COPY:
2420 if (console->window->in_selection)
2422 console->window->in_selection = FALSE;
2423 update_selection( console, 0 );
2424 copy_selection( console );
2426 break;
2427 case IDS_PASTE:
2428 paste_clipboard( console );
2429 break;
2430 case IDS_SELECTALL:
2431 console->window->selection_start.X = console->window->selection_start.Y = 0;
2432 console->window->selection_end.X = console->active->width - 1;
2433 console->window->selection_end.Y = console->active->height - 1;
2434 update_selection( console, 0 );
2435 console->window->in_selection = TRUE;
2436 break;
2437 case IDS_SCROLL:
2438 case IDS_SEARCH:
2439 FIXME( "Unhandled yet command: %lx\n", wparam );
2440 break;
2441 default:
2442 return DefWindowProcW( hwnd, msg, wparam, lparam );
2444 break;
2446 case WM_INITMENUPOPUP:
2447 if (!HIWORD(lparam)) return DefWindowProcW( hwnd, msg, wparam, lparam );
2448 set_menu_details( console, GetSystemMenu(console->win, FALSE) );
2449 break;
2451 default:
2452 return DefWindowProcW( hwnd, msg, wparam, lparam );
2455 return 0;
2458 void update_window_config( struct console *console )
2460 if (!console->win || console->window->update_state != UPDATE_NONE) return;
2461 console->window->update_state = UPDATE_PENDING;
2462 PostMessageW( console->win, WM_UPDATE_CONFIG, 0, 0 );
2465 void update_window_region( struct console *console, const RECT *update )
2467 RECT *window_rect = &console->window->update;
2468 window_rect->left = min( window_rect->left, update->left );
2469 window_rect->top = min( window_rect->top, update->top );
2470 window_rect->right = max( window_rect->right, update->right );
2471 window_rect->bottom = max( window_rect->bottom, update->bottom );
2472 update_window_config( console );
2475 BOOL init_window( struct console *console )
2477 struct console_config config;
2478 WNDCLASSW wndclass;
2479 STARTUPINFOW si;
2480 CHARSETINFO ci;
2482 static struct console_window console_window;
2484 console->window = &console_window;
2485 if (!TranslateCharsetInfo( (DWORD *)(INT_PTR)GetACP(), &ci, TCI_SRCCODEPAGE ))
2486 return FALSE;
2488 console->window->ui_charset = ci.ciCharset;
2490 GetStartupInfoW(&si);
2491 if (si.lpTitle)
2493 size_t i, title_len = wcslen( si.lpTitle );
2494 if (!(console->window->config_key = malloc( (title_len + 1) * sizeof(WCHAR) )))
2495 return FALSE;
2496 for (i = 0; i < title_len; i++)
2497 console->window->config_key[i] = si.lpTitle[i] == '\\' ? '_' : si.lpTitle[i];
2498 console->window->config_key[title_len] = 0;
2501 load_config( console->window->config_key, &config );
2502 if (si.dwFlags & STARTF_USECOUNTCHARS)
2504 config.sb_width = si.dwXCountChars;
2505 config.sb_height = si.dwYCountChars;
2507 if (si.dwFlags & STARTF_USEFILLATTRIBUTE)
2508 config.attr = si.dwFillAttribute;
2510 wndclass.style = CS_DBLCLKS;
2511 wndclass.lpfnWndProc = window_proc;
2512 wndclass.cbClsExtra = 0;
2513 wndclass.cbWndExtra = sizeof(DWORD_PTR);
2514 wndclass.hInstance = GetModuleHandleW(NULL);
2515 wndclass.hIcon = LoadIconW( 0, (const WCHAR *)IDI_WINLOGO );
2516 wndclass.hCursor = LoadCursorW( 0, (const WCHAR *)IDC_ARROW );
2517 wndclass.hbrBackground = GetStockObject( BLACK_BRUSH );
2518 wndclass.lpszMenuName = NULL;
2519 wndclass.lpszClassName = L"WineConsoleClass";
2520 RegisterClassW(&wndclass);
2522 if (!CreateWindowW( wndclass.lpszClassName, NULL,
2523 WS_OVERLAPPED|WS_CAPTION|WS_SYSMENU|WS_THICKFRAME|WS_MINIMIZEBOX|
2524 WS_MAXIMIZEBOX|WS_HSCROLL|WS_VSCROLL, CW_USEDEFAULT, CW_USEDEFAULT,
2525 0, 0, 0, 0, wndclass.hInstance, console ))
2526 return FALSE;
2528 apply_config( console, &config );
2529 return TRUE;