wow64win: Add stub dll.
[wine.git] / programs / conhost / window.c
blob92970b44f0eb6c4a2f58b6853566f823b47d73cd
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\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, 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( (get_bounded_cursor_x( console->active ) - 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 || get_bounded_cursor_x( console->active ) != console->window->cursor_pos.X ||
611 console->active->cursor_y != console->window->cursor_pos.Y)
613 console->window->cursor_pos.X = get_bounded_cursor_x( console->active );
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\n" );
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 );
1905 notify_screen_buffer_size( console->active );
1908 static void current_config( struct console *console, struct console_config *config )
1910 size_t len;
1912 config->menu_mask = console->window->menu_mask;
1913 config->quick_edit = console->window->quick_edit;
1915 config->edition_mode = console->edition_mode;
1916 config->history_mode = console->history_mode;
1917 config->history_size = console->history_size;
1919 config->insert_mode = (console->mode & (ENABLE_INSERT_MODE|ENABLE_EXTENDED_FLAGS)) ==
1920 (ENABLE_INSERT_MODE|ENABLE_EXTENDED_FLAGS);
1922 config->cursor_size = console->active->cursor_size;
1923 config->cursor_visible = console->active->cursor_visible;
1924 config->attr = console->active->attr;
1925 config->popup_attr = console->active->popup_attr;
1926 memcpy( config->color_map, console->active->color_map, sizeof(config->color_map) );
1928 config->win_height = console->active->win.bottom - console->active->win.top + 1;
1929 config->win_width = console->active->win.right - console->active->win.left + 1;
1930 config->cell_width = console->active->font.width;
1931 config->cell_height = console->active->font.height;
1932 config->font_weight = console->active->font.weight;
1933 config->font_pitch_family = console->active->font.pitch_family;
1934 len = min( ARRAY_SIZE(config->face_name) - 1, console->active->font.face_len / sizeof(WCHAR) );
1935 if (len) memcpy( config->face_name, console->active->font.face_name, len * sizeof(WCHAR) );
1936 config->face_name[len] = 0;
1938 config->sb_width = console->active->width;
1939 config->sb_height = console->active->height;
1941 config->win_width = console->active->win.right - console->active->win.left + 1;
1942 config->win_height = console->active->win.bottom - console->active->win.top + 1;
1943 config->win_pos.X = console->active->win.left;
1944 config->win_pos.Y = console->active->win.top;
1947 /* run the dialog box to set up the console options */
1948 static BOOL config_dialog( struct console *console, BOOL current )
1950 struct console_config prev_config;
1951 struct dialog_info di;
1952 PROPSHEETHEADERW header;
1953 HPROPSHEETPAGE pages[3];
1954 PROPSHEETPAGEW psp;
1955 WNDCLASSW wndclass;
1956 WCHAR buff[256];
1957 BOOL modify_session = FALSE;
1958 BOOL save = FALSE;
1960 InitCommonControls();
1962 memset( &di, 0, sizeof(di) );
1963 di.console = console;
1964 if (!current)
1966 load_config( NULL, &di.config );
1967 save = TRUE;
1969 else current_config( console, &di.config );
1970 prev_config = di.config;
1971 di.font_count = 0;
1972 di.font = NULL;
1974 wndclass.style = 0;
1975 wndclass.lpfnWndProc = font_preview_proc;
1976 wndclass.cbClsExtra = 0;
1977 wndclass.cbWndExtra = sizeof(HFONT);
1978 wndclass.hInstance = GetModuleHandleW( NULL );
1979 wndclass.hIcon = 0;
1980 wndclass.hCursor = LoadCursorW( 0, (const WCHAR *)IDC_ARROW );
1981 wndclass.hbrBackground = GetStockObject( BLACK_BRUSH );
1982 wndclass.lpszMenuName = NULL;
1983 wndclass.lpszClassName = L"WineConFontPreview";
1984 RegisterClassW( &wndclass );
1986 wndclass.style = 0;
1987 wndclass.lpfnWndProc = color_preview_proc;
1988 wndclass.cbClsExtra = 0;
1989 wndclass.cbWndExtra = sizeof(DWORD);
1990 wndclass.hInstance = GetModuleHandleW( NULL );
1991 wndclass.hIcon = 0;
1992 wndclass.hCursor = LoadCursorW( 0, (const WCHAR *)IDC_ARROW );
1993 wndclass.hbrBackground = GetStockObject( BLACK_BRUSH );
1994 wndclass.lpszMenuName = NULL;
1995 wndclass.lpszClassName = L"WineConColorPreview";
1996 RegisterClassW( &wndclass );
1998 memset( &psp, 0, sizeof(psp) );
1999 psp.dwSize = sizeof(psp);
2000 psp.dwFlags = 0;
2001 psp.hInstance = wndclass.hInstance;
2002 psp.lParam = (LPARAM)&di;
2004 psp.u.pszTemplate = MAKEINTRESOURCEW(IDD_OPTION);
2005 psp.pfnDlgProc = option_dialog_proc;
2006 pages[0] = CreatePropertySheetPageW( &psp );
2008 psp.u.pszTemplate = MAKEINTRESOURCEW(IDD_FONT);
2009 psp.pfnDlgProc = font_dialog_proc;
2010 pages[1] = CreatePropertySheetPageW( &psp );
2012 psp.u.pszTemplate = MAKEINTRESOURCEW(IDD_CONFIG);
2013 psp.pfnDlgProc = config_dialog_proc;
2014 pages[2] = CreatePropertySheetPageW( &psp );
2016 memset( &header, 0, sizeof(header) );
2017 header.dwSize = sizeof(header);
2019 if (!LoadStringW( GetModuleHandleW( NULL ),
2020 current ? IDS_DLG_TIT_CURRENT : IDS_DLG_TIT_DEFAULT,
2021 buff, ARRAY_SIZE(buff) ))
2022 wcscpy( buff, L"Setup" );
2024 header.pszCaption = buff;
2025 header.nPages = 3;
2026 header.hwndParent = console->win;
2027 header.u3.phpage = pages;
2028 header.dwFlags = PSH_NOAPPLYNOW;
2029 PropertySheetW( &header );
2031 if (!memcmp( &prev_config, &di.config, sizeof(prev_config) ))
2032 return TRUE;
2034 TRACE( "%s\n", debugstr_config(&di.config) );
2036 if (!save)
2038 switch (DialogBoxW( GetModuleHandleW( NULL ), MAKEINTRESOURCEW(IDD_SAVE_SETTINGS),
2039 console->win, save_dialog_proc ))
2041 case IDC_SAV_SAVE:
2042 save = TRUE;
2043 modify_session = TRUE;
2044 break;
2045 case IDC_SAV_SESSION:
2046 modify_session = TRUE;
2047 break;
2048 default:
2049 ERR( "dialog failed\n" );
2050 /* fall through */
2051 case IDCANCEL:
2052 modify_session = FALSE;
2053 save = FALSE;
2054 break;
2058 if (modify_session)
2060 apply_config( console, &di.config );
2061 update_window( di.console );
2063 if (save)
2064 save_config( current ? console->window->config_key : NULL, &di.config );
2065 return TRUE;
2068 static void resize_window( struct console *console, int width, int height )
2070 struct console_config config;
2072 current_config( console, &config );
2073 config.win_width = width;
2074 config.win_height = height;
2076 /* auto size screen-buffer if it's now smaller than window */
2077 if (config.sb_width < config.win_width)
2078 config.sb_width = config.win_width;
2079 if (config.sb_height < config.win_height)
2080 config.sb_height = config.win_height;
2082 /* and reset window pos so that we don't display outside of the screen-buffer */
2083 if (config.win_pos.X + config.win_width > config.sb_width)
2084 config.win_pos.X = config.sb_width - config.win_width;
2085 if (config.win_pos.Y + config.win_height > config.sb_height)
2086 config.win_pos.Y = config.sb_height - config.win_height;
2088 apply_config( console, &config );
2091 /* grays / ungrays the menu items according to their state */
2092 static void set_menu_details( struct console *console, HMENU menu )
2094 EnableMenuItem( menu, IDS_COPY, MF_BYCOMMAND |
2095 (console->window->in_selection ? MF_ENABLED : MF_GRAYED) );
2096 EnableMenuItem( menu, IDS_PASTE, MF_BYCOMMAND |
2097 (IsClipboardFormatAvailable(CF_UNICODETEXT) ? MF_ENABLED : MF_GRAYED) );
2098 EnableMenuItem( menu, IDS_SCROLL, MF_BYCOMMAND | MF_GRAYED );
2099 EnableMenuItem( menu, IDS_SEARCH, MF_BYCOMMAND | MF_GRAYED );
2102 static BOOL fill_menu( HMENU menu, BOOL sep )
2104 HINSTANCE module = GetModuleHandleW( NULL );
2105 HMENU sub_menu;
2106 WCHAR buff[256];
2108 if (!menu) return FALSE;
2110 sub_menu = CreateMenu();
2111 if (!sub_menu) return FALSE;
2113 LoadStringW( module, IDS_MARK, buff, ARRAY_SIZE(buff) );
2114 InsertMenuW( sub_menu, -1, MF_BYPOSITION|MF_STRING, IDS_MARK, buff );
2115 LoadStringW( module, IDS_COPY, buff, ARRAY_SIZE(buff) );
2116 InsertMenuW( sub_menu, -1, MF_BYPOSITION|MF_STRING, IDS_COPY, buff );
2117 LoadStringW( module, IDS_PASTE, buff, ARRAY_SIZE(buff) );
2118 InsertMenuW( sub_menu, -1, MF_BYPOSITION|MF_STRING, IDS_PASTE, buff );
2119 LoadStringW( module, IDS_SELECTALL, buff, ARRAY_SIZE(buff) );
2120 InsertMenuW( sub_menu, -1, MF_BYPOSITION|MF_STRING, IDS_SELECTALL, buff );
2121 LoadStringW( module, IDS_SCROLL, buff, ARRAY_SIZE(buff) );
2122 InsertMenuW( sub_menu, -1, MF_BYPOSITION|MF_STRING, IDS_SCROLL, buff );
2123 LoadStringW( module, IDS_SEARCH, buff, ARRAY_SIZE(buff) );
2124 InsertMenuW( sub_menu, -1, MF_BYPOSITION|MF_STRING, IDS_SEARCH, buff );
2126 if (sep) InsertMenuW( menu, -1, MF_BYPOSITION|MF_SEPARATOR, 0, NULL );
2127 LoadStringW( module, IDS_EDIT, buff, ARRAY_SIZE(buff) );
2128 InsertMenuW( menu, -1, MF_BYPOSITION|MF_STRING|MF_POPUP, (UINT_PTR)sub_menu, buff );
2129 LoadStringW( module, IDS_DEFAULT, buff, ARRAY_SIZE(buff) );
2130 InsertMenuW( menu, -1, MF_BYPOSITION|MF_STRING, IDS_DEFAULT, buff );
2131 LoadStringW( module, IDS_PROPERTIES, buff, ARRAY_SIZE(buff) );
2132 InsertMenuW( menu, -1, MF_BYPOSITION|MF_STRING, IDS_PROPERTIES, buff );
2134 return TRUE;
2137 static LRESULT window_create( HWND hwnd, const CREATESTRUCTW *create )
2139 struct console *console = create->lpCreateParams;
2140 HMENU sys_menu;
2142 TRACE( "%p\n", hwnd );
2144 SetWindowLongPtrW( hwnd, 0, (DWORD_PTR)console );
2145 console->win = hwnd;
2147 sys_menu = GetSystemMenu( hwnd, FALSE );
2148 if (!sys_menu) return 0;
2149 console->window->popup_menu = CreatePopupMenu();
2150 if (!console->window->popup_menu) return 0;
2152 fill_menu( sys_menu, TRUE );
2153 fill_menu( console->window->popup_menu, FALSE );
2155 console->window->mem_dc = CreateCompatibleDC( 0 );
2156 return 0;
2159 static LRESULT WINAPI window_proc( HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam )
2161 struct console *console = (struct console *)GetWindowLongPtrW( hwnd, 0 );
2163 switch (msg)
2165 case WM_CREATE:
2166 return window_create( hwnd, (const CREATESTRUCTW *)lparam );
2168 case WM_DESTROY:
2169 console->win = NULL;
2170 PostQuitMessage( 0 );
2171 break;
2173 case WM_TIMER:
2174 case WM_UPDATE_CONFIG:
2175 if (console->window->update_state == UPDATE_PENDING)
2176 update_window( console );
2177 break;
2179 case WM_PAINT:
2181 PAINTSTRUCT ps;
2183 BeginPaint( console->win, &ps );
2184 BitBlt( ps.hdc, 0, 0,
2185 (console->active->win.right - console->active->win.left + 1) * console->active->font.width,
2186 (console->active->win.bottom - console->active->win.top + 1) * console->active->font.height,
2187 console->window->mem_dc,
2188 console->active->win.left * console->active->font.width,
2189 console->active->win.top * console->active->font.height,
2190 SRCCOPY );
2191 if (console->window->in_selection) update_selection( console, ps.hdc );
2192 EndPaint( console->win, &ps );
2193 break;
2196 case WM_SHOWWINDOW:
2197 if (wparam)
2198 update_window( console );
2199 else
2201 if (console->window->bitmap) DeleteObject( console->window->bitmap );
2202 console->window->bitmap = NULL;
2204 break;
2206 case WM_KEYDOWN:
2207 case WM_KEYUP:
2208 if (console->window->in_selection)
2209 handle_selection_key( console, msg == WM_KEYDOWN, wparam, lparam );
2210 else
2211 record_key_input( console, msg == WM_KEYDOWN, wparam, lparam );
2212 break;
2214 case WM_SYSKEYDOWN:
2215 case WM_SYSKEYUP:
2216 record_key_input( console, msg == WM_SYSKEYDOWN, wparam, lparam );
2217 break;
2219 case WM_LBUTTONDOWN:
2220 if (console->window->quick_edit || console->window->in_selection)
2222 if (console->window->in_selection)
2223 update_selection( console, 0 );
2225 if (console->window->quick_edit && console->window->in_selection)
2227 console->window->in_selection = FALSE;
2229 else
2231 console->window->selection_end = get_cell( console, lparam );
2232 console->window->selection_start = console->window->selection_end;
2233 SetCapture( console->win );
2234 update_selection( console, 0 );
2235 console->window->in_selection = TRUE;
2238 else
2240 record_mouse_input( console, get_cell(console, lparam), wparam, 0 );
2242 break;
2244 case WM_MOUSEMOVE:
2245 if (console->window->quick_edit || console->window->in_selection)
2247 if (GetCapture() == console->win && console->window->in_selection &&
2248 (wparam & MK_LBUTTON))
2250 move_selection( console, console->window->selection_start,
2251 get_cell(console, lparam) );
2254 else
2256 record_mouse_input( console, get_cell(console, lparam), wparam, MOUSE_MOVED );
2258 break;
2260 case WM_LBUTTONUP:
2261 if (console->window->quick_edit || console->window->in_selection)
2263 if (GetCapture() == console->win && console->window->in_selection)
2265 move_selection( console, console->window->selection_start,
2266 get_cell(console, lparam) );
2267 ReleaseCapture();
2270 else
2272 record_mouse_input( console, get_cell(console, lparam), wparam, 0 );
2274 break;
2276 case WM_RBUTTONDOWN:
2277 if ((wparam & (MK_CONTROL|MK_SHIFT)) == console->window->menu_mask)
2279 POINT pt;
2280 pt.x = (short)LOWORD(lparam);
2281 pt.y = (short)HIWORD(lparam);
2282 ClientToScreen( hwnd, &pt );
2283 set_menu_details( console, console->window->popup_menu );
2284 TrackPopupMenu( console->window->popup_menu, TPM_LEFTALIGN|TPM_TOPALIGN|TPM_RIGHTBUTTON,
2285 pt.x, pt.y, 0, hwnd, NULL );
2287 else
2289 record_mouse_input( console, get_cell(console, lparam), wparam, 0 );
2291 break;
2293 case WM_RBUTTONUP:
2294 /* no need to track for rbutton up when opening the popup... the event will be
2295 * swallowed by TrackPopupMenu */
2296 case WM_MBUTTONDOWN:
2297 case WM_MBUTTONUP:
2298 record_mouse_input( console, get_cell(console, lparam), wparam, 0 );
2299 break;
2301 case WM_LBUTTONDBLCLK:
2302 case WM_MBUTTONDBLCLK:
2303 case WM_RBUTTONDBLCLK:
2304 record_mouse_input( console, get_cell(console, lparam), wparam, DOUBLE_CLICK );
2305 break;
2307 case WM_SETFOCUS:
2308 if (console->active->cursor_visible)
2310 CreateCaret( console->win, console->window->cursor_bitmap,
2311 console->active->font.width, console->active->font.height );
2312 update_window_cursor( console );
2314 break;
2316 case WM_KILLFOCUS:
2317 if (console->active->cursor_visible)
2318 DestroyCaret();
2319 break;
2321 case WM_SIZE:
2322 if (console->window->update_state != UPDATE_BUSY)
2323 resize_window( console,
2324 max( LOWORD(lparam) / console->active->font.width, 20 ),
2325 max( HIWORD(lparam) / console->active->font.height, 20 ));
2326 break;
2328 case WM_HSCROLL:
2330 int win_width = console->active->win.right - console->active->win.left + 1;
2331 int x = console->active->win.left;
2333 switch (LOWORD(wparam))
2335 case SB_PAGEUP: x -= 8; break;
2336 case SB_PAGEDOWN: x += 8; break;
2337 case SB_LINEUP: x--; break;
2338 case SB_LINEDOWN: x++; break;
2339 case SB_THUMBTRACK: x = HIWORD(wparam); break;
2340 default: break;
2342 x = min( max( x, 0 ), console->active->width - win_width );
2343 if (x != console->active->win.left)
2345 console->active->win.left = x;
2346 console->active->win.right = x + win_width - 1;
2347 update_window( console );
2349 break;
2352 case WM_MOUSEWHEEL:
2353 if (console->active->height <= console->active->win.bottom - console->active->win.top + 1)
2355 record_mouse_input(console, get_cell(console, lparam), wparam, MOUSE_WHEELED);
2356 break;
2358 /* else fallthrough */
2359 case WM_VSCROLL:
2361 int win_height = console->active->win.bottom - console->active->win.top + 1;
2362 int y = console->active->win.top;
2364 if (msg == WM_MOUSEWHEEL)
2366 UINT scroll_lines = 3;
2367 SystemParametersInfoW( SPI_GETWHEELSCROLLLINES, 0, &scroll_lines, 0 );
2368 scroll_lines *= -GET_WHEEL_DELTA_WPARAM(wparam) / WHEEL_DELTA;
2369 y += scroll_lines;
2371 else
2373 switch (LOWORD(wparam))
2375 case SB_PAGEUP: y -= 8; break;
2376 case SB_PAGEDOWN: y += 8; break;
2377 case SB_LINEUP: y--; break;
2378 case SB_LINEDOWN: y++; break;
2379 case SB_THUMBTRACK: y = HIWORD(wparam); break;
2380 default: break;
2384 y = min( max( y, 0 ), console->active->height - win_height );
2385 if (y != console->active->win.top)
2387 console->active->win.top = y;
2388 console->active->win.bottom = y + win_height - 1;
2389 update_window( console );
2391 break;
2394 case WM_SYSCOMMAND:
2395 switch (wparam)
2397 case IDS_DEFAULT:
2398 config_dialog( console, FALSE );
2399 break;
2400 case IDS_PROPERTIES:
2401 config_dialog( console, TRUE );
2402 break;
2403 default:
2404 return DefWindowProcW( hwnd, msg, wparam, lparam );
2406 break;
2408 case WM_COMMAND:
2409 switch (wparam)
2411 case IDS_DEFAULT:
2412 config_dialog( console, FALSE );
2413 break;
2414 case IDS_PROPERTIES:
2415 config_dialog( console, TRUE );
2416 break;
2417 case IDS_MARK:
2418 console->window->selection_start.X = console->window->selection_start.Y = 0;
2419 console->window->selection_end.X = console->window->selection_end.Y = 0;
2420 update_selection( console, 0 );
2421 console->window->in_selection = TRUE;
2422 break;
2423 case IDS_COPY:
2424 if (console->window->in_selection)
2426 console->window->in_selection = FALSE;
2427 update_selection( console, 0 );
2428 copy_selection( console );
2430 break;
2431 case IDS_PASTE:
2432 paste_clipboard( console );
2433 break;
2434 case IDS_SELECTALL:
2435 console->window->selection_start.X = console->window->selection_start.Y = 0;
2436 console->window->selection_end.X = console->active->width - 1;
2437 console->window->selection_end.Y = console->active->height - 1;
2438 update_selection( console, 0 );
2439 console->window->in_selection = TRUE;
2440 break;
2441 case IDS_SCROLL:
2442 case IDS_SEARCH:
2443 FIXME( "Unhandled yet command: %lx\n", wparam );
2444 break;
2445 default:
2446 return DefWindowProcW( hwnd, msg, wparam, lparam );
2448 break;
2450 case WM_INITMENUPOPUP:
2451 if (!HIWORD(lparam)) return DefWindowProcW( hwnd, msg, wparam, lparam );
2452 set_menu_details( console, GetSystemMenu(console->win, FALSE) );
2453 break;
2455 default:
2456 return DefWindowProcW( hwnd, msg, wparam, lparam );
2459 return 0;
2462 void update_window_config( struct console *console, BOOL delay )
2464 const int delay_timeout = 50;
2466 if (!console->win || console->window->update_state != UPDATE_NONE) return;
2467 console->window->update_state = UPDATE_PENDING;
2468 if (delay)
2469 SetTimer( console->win, 1, delay_timeout, NULL );
2470 else
2471 PostMessageW( console->win, WM_UPDATE_CONFIG, 0, 0 );
2474 void update_window_region( struct console *console, const RECT *update )
2476 RECT *window_rect = &console->window->update;
2477 window_rect->left = min( window_rect->left, update->left );
2478 window_rect->top = min( window_rect->top, update->top );
2479 window_rect->right = max( window_rect->right, update->right );
2480 window_rect->bottom = max( window_rect->bottom, update->bottom );
2481 update_window_config( console, TRUE );
2484 BOOL init_window( struct console *console )
2486 struct console_config config;
2487 WNDCLASSW wndclass;
2488 STARTUPINFOW si;
2489 CHARSETINFO ci;
2491 static struct console_window console_window;
2493 console->window = &console_window;
2494 if (!TranslateCharsetInfo( (DWORD *)(INT_PTR)GetACP(), &ci, TCI_SRCCODEPAGE ))
2495 return FALSE;
2497 console->window->ui_charset = ci.ciCharset;
2499 GetStartupInfoW(&si);
2500 if (si.lpTitle)
2502 size_t i, title_len = wcslen( si.lpTitle );
2503 if (!(console->window->config_key = malloc( (title_len + 1) * sizeof(WCHAR) )))
2504 return FALSE;
2505 for (i = 0; i < title_len; i++)
2506 console->window->config_key[i] = si.lpTitle[i] == '\\' ? '_' : si.lpTitle[i];
2507 console->window->config_key[title_len] = 0;
2510 load_config( console->window->config_key, &config );
2511 if (si.dwFlags & STARTF_USECOUNTCHARS)
2513 config.sb_width = si.dwXCountChars;
2514 config.sb_height = si.dwYCountChars;
2516 if (si.dwFlags & STARTF_USEFILLATTRIBUTE)
2517 config.attr = si.dwFillAttribute;
2519 wndclass.style = CS_DBLCLKS;
2520 wndclass.lpfnWndProc = window_proc;
2521 wndclass.cbClsExtra = 0;
2522 wndclass.cbWndExtra = sizeof(DWORD_PTR);
2523 wndclass.hInstance = GetModuleHandleW(NULL);
2524 wndclass.hIcon = LoadIconW( 0, (const WCHAR *)IDI_WINLOGO );
2525 wndclass.hCursor = LoadCursorW( 0, (const WCHAR *)IDC_ARROW );
2526 wndclass.hbrBackground = GetStockObject( BLACK_BRUSH );
2527 wndclass.lpszMenuName = NULL;
2528 wndclass.lpszClassName = L"WineConsoleClass";
2529 RegisterClassW(&wndclass);
2531 if (!CreateWindowW( wndclass.lpszClassName, NULL,
2532 WS_OVERLAPPED|WS_CAPTION|WS_SYSMENU|WS_THICKFRAME|WS_MINIMIZEBOX|
2533 WS_MAXIMIZEBOX|WS_HSCROLL|WS_VSCROLL, CW_USEDEFAULT, CW_USEDEFAULT,
2534 0, 0, 0, 0, wndclass.hInstance, console ))
2535 return FALSE;
2537 apply_config( console, &config );
2538 return TRUE;