Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
wine-mirror
GitHub Repository: wine-mirror/wine
Path: blob/master/programs/conhost/window.c
4387 views
1
/*
2
* Copyright 2001 Eric Pouech
3
* Copyright 2020 Jacek Caban for CodeWeavers
4
*
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.
9
*
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.
14
*
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
18
*/
19
20
#include <stdlib.h>
21
22
#include "conhost.h"
23
24
#include <commctrl.h>
25
#include <winreg.h>
26
27
#include "wine/debug.h"
28
29
WINE_DEFAULT_DEBUG_CHANNEL(console);
30
31
#define WM_UPDATE_CONFIG (WM_USER + 1)
32
33
enum update_state
34
{
35
UPDATE_NONE,
36
UPDATE_PENDING,
37
UPDATE_BUSY
38
};
39
40
struct console_window
41
{
42
HDC mem_dc; /* memory DC holding the bitmap below */
43
HBITMAP bitmap; /* bitmap of display window content */
44
HFONT font; /* font used for rendering, usually fixed */
45
HMENU popup_menu; /* popup menu triggered by right mouse click */
46
HBITMAP cursor_bitmap; /* bitmap used for the caret */
47
BOOL in_selection; /* an area is being selected */
48
COORD selection_start; /* selection coordinates */
49
COORD selection_end;
50
unsigned int ui_charset; /* default UI charset */
51
WCHAR *config_key; /* config registry key name */
52
LONG ext_leading; /* external leading for font */
53
54
BOOL quick_edit; /* whether mouse ops are sent to app or used for content selection */
55
unsigned int menu_mask; /* MK_CONTROL MK_SHIFT mask to drive submenu opening */
56
COORD win_pos; /* position (in cells) of visible part of screen buffer in window */
57
unsigned int win_width; /* size (in cells) of visible part of window (width & height) */
58
unsigned int win_height;
59
unsigned int cursor_size; /* in % of cell height */
60
int cursor_visible; /* cursor visibility */
61
unsigned int sb_width; /* active screen buffer width */
62
unsigned int sb_height; /* active screen buffer height */
63
COORD cursor_pos; /* cursor position */
64
65
RECT update; /* screen buffer update rect */
66
enum update_state update_state; /* update state */
67
};
68
69
struct console_config
70
{
71
DWORD color_map[16]; /* console color table */
72
unsigned int cell_width; /* width in pixels of a character */
73
unsigned int cell_height; /* height in pixels of a character */
74
unsigned int cursor_size; /* in % of cell height */
75
int cursor_visible; /* cursor visibility */
76
unsigned int attr; /* default fill attributes (screen colors) */
77
unsigned int popup_attr ; /* pop-up color attributes */
78
unsigned int history_size; /* number of commands in history buffer */
79
unsigned int history_mode; /* flag if commands are not stored twice in buffer */
80
unsigned int insert_mode; /* TRUE to insert text at the cursor location; FALSE to overwrite it */
81
unsigned int menu_mask; /* MK_CONTROL MK_SHIFT mask to drive submenu opening */
82
unsigned int quick_edit; /* whether mouse ops are sent to app or used for content selection */
83
unsigned int sb_width; /* active screen buffer width */
84
unsigned int sb_height; /* active screen buffer height */
85
unsigned int win_width; /* size (in cells) of visible part of window (width & height) */
86
unsigned int win_height;
87
COORD win_pos; /* position (in cells) of visible part of screen buffer in window */
88
unsigned int edition_mode; /* edition mode flavor while line editing */
89
unsigned int font_pitch_family;
90
unsigned int font_weight;
91
WCHAR face_name[LF_FACESIZE];
92
};
93
94
static const char *debugstr_config( const struct console_config *config )
95
{
96
return wine_dbg_sprintf( "cell=(%u,%u) cursor=(%d,%d) attr=%02x pop-up=%02x font=%s/%u/%u "
97
"hist=%u/%d flags=%c%c msk=%08x sb=(%u,%u) win=(%u,%u)x(%u,%u) edit=%u",
98
config->cell_width, config->cell_height, config->cursor_size,
99
config->cursor_visible, config->attr, config->popup_attr,
100
wine_dbgstr_w(config->face_name), config->font_pitch_family,
101
config->font_weight, config->history_size,
102
config->history_mode ? 1 : 2,
103
config->insert_mode ? 'I' : 'i',
104
config->quick_edit ? 'Q' : 'q',
105
config->menu_mask, config->sb_width, config->sb_height,
106
config->win_pos.X, config->win_pos.Y, config->win_width,
107
config->win_height, config->edition_mode );
108
}
109
110
static const char *debugstr_logfont( const LOGFONTW *lf, unsigned int ft )
111
{
112
return wine_dbg_sprintf( "%s%s%s%s lfHeight=%ld lfWidth=%ld lfEscapement=%ld "
113
"lfOrientation=%ld lfWeight=%ld lfItalic=%u lfUnderline=%u "
114
"lfStrikeOut=%u lfCharSet=%u lfPitchAndFamily=%u lfFaceName=%s",
115
(ft & RASTER_FONTTYPE) ? "raster" : "",
116
(ft & TRUETYPE_FONTTYPE) ? "truetype" : "",
117
((ft & (RASTER_FONTTYPE|TRUETYPE_FONTTYPE)) == 0) ? "vector" : "",
118
(ft & DEVICE_FONTTYPE) ? "|device" : "",
119
lf->lfHeight, lf->lfWidth, lf->lfEscapement, lf->lfOrientation,
120
lf->lfWeight, lf->lfItalic, lf->lfUnderline, lf->lfStrikeOut,
121
lf->lfCharSet, lf->lfPitchAndFamily, wine_dbgstr_w( lf->lfFaceName ));
122
}
123
124
static const char *debugstr_textmetric( const TEXTMETRICW *tm, unsigned int ft )
125
{
126
return wine_dbg_sprintf( "%s%s%s%s tmHeight=%ld tmAscent=%ld tmDescent=%ld "
127
"tmAveCharWidth=%ld tmMaxCharWidth=%ld tmWeight=%ld "
128
"tmPitchAndFamily=%u tmCharSet=%u",
129
(ft & RASTER_FONTTYPE) ? "raster" : "",
130
(ft & TRUETYPE_FONTTYPE) ? "truetype" : "",
131
((ft & (RASTER_FONTTYPE|TRUETYPE_FONTTYPE)) == 0) ? "vector" : "",
132
(ft & DEVICE_FONTTYPE) ? "|device" : "",
133
tm->tmHeight, tm->tmAscent, tm->tmDescent, tm->tmAveCharWidth,
134
tm->tmMaxCharWidth, tm->tmWeight, tm->tmPitchAndFamily,
135
tm->tmCharSet );
136
}
137
138
/* read the basic configuration from any console key or subkey */
139
static void load_registry_key( HKEY key, struct console_config *config )
140
{
141
DWORD type, count, val, i;
142
WCHAR color_name[13];
143
144
for (i = 0; i < ARRAY_SIZE(config->color_map); i++)
145
{
146
wsprintfW( color_name, L"ColorTable%02d", i );
147
count = sizeof(val);
148
if (!RegQueryValueExW( key, color_name, 0, &type, (BYTE *)&val, &count ))
149
config->color_map[i] = val;
150
}
151
152
count = sizeof(val);
153
if (!RegQueryValueExW( key, L"CursorSize", 0, &type, (BYTE *)&val, &count ))
154
config->cursor_size = val;
155
156
count = sizeof(val);
157
if (!RegQueryValueExW( key, L"CursorVisible", 0, &type, (BYTE *)&val, &count ))
158
config->cursor_visible = val;
159
160
count = sizeof(val);
161
if (!RegQueryValueExW( key, L"EditionMode", 0, &type, (BYTE *)&val, &count ))
162
config->edition_mode = val;
163
164
count = sizeof(config->face_name);
165
RegQueryValueExW( key, L"FaceName", 0, &type, (BYTE *)&config->face_name, &count );
166
167
count = sizeof(val);
168
if (!RegQueryValueExW( key, L"FontFamily", 0, &type, (BYTE *)&val, &count ) ||
169
!RegQueryValueExW( key, L"FontPitchFamily", 0, &type, (BYTE *)&val, &count ))
170
config->font_pitch_family = val;
171
172
count = sizeof(val);
173
if (!RegQueryValueExW( key, L"FontSize", 0, &type, (BYTE *)&val, &count ))
174
{
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 );
180
}
181
182
count = sizeof(val);
183
if (!RegQueryValueExW( key, L"FontWeight", 0, &type, (BYTE *)&val, &count ))
184
config->font_weight = val;
185
186
count = sizeof(val);
187
if (!RegQueryValueExW( key, L"HistoryBufferSize", 0, &type, (BYTE *)&val, &count ))
188
config->history_size = val;
189
190
count = sizeof(val);
191
if (!RegQueryValueExW( key, L"HistoryNoDup", 0, &type, (BYTE *)&val, &count ))
192
config->history_mode = val;
193
194
count = sizeof(val);
195
if (!RegQueryValueExW( key, L"wszInsertMode", 0, &type, (BYTE *)&val, &count ))
196
config->insert_mode = val;
197
198
count = sizeof(val);
199
if (!RegQueryValueExW( key, L"MenuMask", 0, &type, (BYTE *)&val, &count ))
200
config->menu_mask = val;
201
202
count = sizeof(val);
203
if (!RegQueryValueExW( key, L"PopupColors", 0, &type, (BYTE *)&val, &count ))
204
config->popup_attr = val;
205
206
count = sizeof(val);
207
if (!RegQueryValueExW( key, L"QuickEdit", 0, &type, (BYTE *)&val, &count ))
208
config->quick_edit = val;
209
210
count = sizeof(val);
211
if (!RegQueryValueExW( key, L"ScreenBufferSize", 0, &type, (BYTE *)&val, &count ))
212
{
213
config->sb_height = HIWORD(val);
214
config->sb_width = LOWORD(val);
215
}
216
217
count = sizeof(val);
218
if (!RegQueryValueExW( key, L"ScreenColors", 0, &type, (BYTE *)&val, &count ))
219
config->attr = val;
220
221
count = sizeof(val);
222
if (!RegQueryValueExW( key, L"WindowSize", 0, &type, (BYTE *)&val, &count ))
223
{
224
config->win_height = HIWORD(val);
225
config->win_width = LOWORD(val);
226
}
227
}
228
229
/* load config from registry */
230
static void load_config( const WCHAR *key_name, struct console_config *config )
231
{
232
static const COLORREF color_map[] =
233
{
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)
238
};
239
240
HKEY key, app_key;
241
242
TRACE( "Loading default console settings\n" );
243
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;
252
253
config->history_size = 50;
254
config->history_mode = 0;
255
config->insert_mode = 1;
256
config->menu_mask = 0;
257
config->popup_attr = 0xF5;
258
config->quick_edit = 0;
259
config->sb_height = 150;
260
config->sb_width = 80;
261
config->attr = 0x000F;
262
config->win_height = 25;
263
config->win_width = 80;
264
config->win_pos.X = 0;
265
config->win_pos.Y = 0;
266
config->edition_mode = 0;
267
268
/* Load default console settings */
269
if (!RegOpenKeyW( HKEY_CURRENT_USER, L"Console", &key ))
270
{
271
load_registry_key( key, config );
272
273
/* Load app-specific console settings (if any) */
274
if (key_name && !RegOpenKeyW( key, key_name, &app_key ))
275
{
276
TRACE( "Loading %s console settings\n", wine_dbgstr_w(key_name) );
277
load_registry_key( app_key, config );
278
RegCloseKey( app_key );
279
}
280
RegCloseKey( key );
281
}
282
TRACE( "%s\n", debugstr_config( config ));
283
}
284
285
static void save_registry_key( HKEY key, const struct console_config *config, BOOL save_all )
286
{
287
struct console_config default_config;
288
DWORD val, width, height, i;
289
WCHAR color_name[13];
290
291
TRACE( "%s\n", debugstr_config( config ));
292
293
if (!save_all)
294
load_config( NULL, &default_config );
295
296
for (i = 0; i < ARRAY_SIZE(config->color_map); i++)
297
{
298
if (save_all || config->color_map[i] != default_config.color_map[i])
299
{
300
wsprintfW( color_name, L"ColorTable%02d", i );
301
val = config->color_map[i];
302
RegSetValueExW( key, color_name, 0, REG_DWORD, (BYTE *)&val, sizeof(val) );
303
}
304
}
305
306
if (save_all || config->cursor_size != default_config.cursor_size)
307
{
308
val = config->cursor_size;
309
RegSetValueExW( key, L"CursorSize", 0, REG_DWORD, (BYTE *)&val, sizeof(val) );
310
}
311
312
if (save_all || config->cursor_visible != default_config.cursor_visible)
313
{
314
val = config->cursor_visible;
315
RegSetValueExW( key, L"CursorVisible", 0, REG_DWORD, (BYTE *)&val, sizeof(val) );
316
}
317
318
if (save_all || config->edition_mode != default_config.edition_mode)
319
{
320
val = config->edition_mode;
321
RegSetValueExW( key, L"EditionMode", 0, REG_DWORD, (BYTE *)&val, sizeof(val) );
322
}
323
324
if (save_all || lstrcmpW( config->face_name, default_config.face_name ))
325
{
326
RegSetValueExW( key, L"FaceName", 0, REG_SZ, (BYTE *)&config->face_name,
327
(lstrlenW(config->face_name) + 1) * sizeof(WCHAR) );
328
}
329
330
if (save_all || config->font_pitch_family != default_config.font_pitch_family)
331
{
332
val = config->font_pitch_family;
333
RegSetValueExW( key, L"FontFamily", 0, REG_DWORD, (BYTE *)&val, sizeof(val) );
334
}
335
336
if (save_all || config->cell_height != default_config.cell_height ||
337
config->cell_width != default_config.cell_width)
338
{
339
width = MulDiv( config->cell_width, USER_DEFAULT_SCREEN_DPI, GetDpiForSystem() );
340
height = MulDiv( config->cell_height, USER_DEFAULT_SCREEN_DPI, GetDpiForSystem() );
341
val = MAKELONG( width, height );
342
343
RegSetValueExW( key, L"FontSize", 0, REG_DWORD, (BYTE *)&val, sizeof(val) );
344
}
345
346
if (save_all || config->font_weight != default_config.font_weight)
347
{
348
val = config->font_weight;
349
RegSetValueExW( key, L"FontWeight", 0, REG_DWORD, (BYTE *)&val, sizeof(val) );
350
}
351
352
if (save_all || config->history_size != default_config.history_size)
353
{
354
val = config->history_size;
355
RegSetValueExW( key, L"HistoryBufferSize", 0, REG_DWORD, (BYTE *)&val, sizeof(val) );
356
}
357
358
if (save_all || config->history_mode != default_config.history_mode)
359
{
360
val = config->history_mode;
361
RegSetValueExW( key, L"HistoryNoDup", 0, REG_DWORD, (BYTE *)&val, sizeof(val) );
362
}
363
364
if (save_all || config->insert_mode != default_config.insert_mode)
365
{
366
val = config->insert_mode;
367
RegSetValueExW( key, L"InsertMode", 0, REG_DWORD, (BYTE *)&val, sizeof(val) );
368
}
369
370
if (save_all || config->menu_mask != default_config.menu_mask)
371
{
372
val = config->menu_mask;
373
RegSetValueExW( key, L"MenuMask", 0, REG_DWORD, (BYTE *)&val, sizeof(val) );
374
}
375
376
if (save_all || config->popup_attr != default_config.popup_attr)
377
{
378
val = config->popup_attr;
379
RegSetValueExW( key, L"PopupColors", 0, REG_DWORD, (BYTE *)&val, sizeof(val) );
380
}
381
382
if (save_all || config->quick_edit != default_config.quick_edit)
383
{
384
val = config->quick_edit;
385
RegSetValueExW( key, L"QuickEdit", 0, REG_DWORD, (BYTE *)&val, sizeof(val) );
386
}
387
388
if (save_all || config->sb_width != default_config.sb_width ||
389
config->sb_height != default_config.sb_height)
390
{
391
val = MAKELONG(config->sb_width, config->sb_height);
392
RegSetValueExW( key, L"ScreenBufferSize", 0, REG_DWORD, (BYTE *)&val, sizeof(val) );
393
}
394
395
if (save_all || config->attr != default_config.attr)
396
{
397
val = config->attr;
398
RegSetValueExW( key, L"ScreenColors", 0, REG_DWORD, (BYTE *)&val, sizeof(val) );
399
}
400
401
if (save_all || config->win_width != default_config.win_width ||
402
config->win_height != default_config.win_height)
403
{
404
val = MAKELONG( config->win_width, config->win_height );
405
RegSetValueExW( key, L"WindowSize", 0, REG_DWORD, (BYTE *)&val, sizeof(val) );
406
}
407
}
408
409
static void save_config( const WCHAR *key_name, const struct console_config *config )
410
{
411
HKEY key, app_key;
412
413
TRACE( "Saving %s console settings\n", key_name ? debugstr_w( key_name ) : "default" );
414
415
if (RegCreateKeyW( HKEY_CURRENT_USER, L"Console", &key ))
416
{
417
ERR("Can't open registry for saving\n");
418
return;
419
}
420
421
if (key_name)
422
{
423
if (RegCreateKeyW( key, key_name, &app_key ))
424
{
425
ERR("Can't open registry for saving\n");
426
}
427
else
428
{
429
save_registry_key( app_key, config, FALSE );
430
RegCloseKey( app_key );
431
}
432
}
433
else save_registry_key( key, config, TRUE );
434
RegCloseKey(key);
435
}
436
437
/* fill memory DC with current cells values */
438
static void fill_mem_dc( struct console *console, const RECT *update )
439
{
440
unsigned int i, j, k;
441
unsigned int attr;
442
char_info_t *cell;
443
HFONT old_font;
444
HBRUSH brush;
445
WCHAR *line;
446
INT *dx;
447
RECT r;
448
449
if (!console->window->font || !console->window->bitmap)
450
return;
451
452
if (!(line = malloc( (update->right - update->left + 1) * sizeof(WCHAR))) ) return;
453
dx = malloc( (update->right - update->left + 1) * sizeof(*dx) );
454
455
old_font = SelectObject( console->window->mem_dc, console->window->font );
456
for (j = update->top; j <= update->bottom; j++)
457
{
458
cell = &console->active->data[j * console->active->width];
459
for (i = update->left; i <= update->right; i++)
460
{
461
attr = cell[i].attr;
462
SetBkColor( console->window->mem_dc, console->active->color_map[(attr >> 4) & 0x0F] );
463
SetTextColor( console->window->mem_dc, console->active->color_map[attr & 0x0F] );
464
for (k = i; k <= update->right && cell[k].attr == attr; k++)
465
{
466
line[k - i] = cell[k].ch;
467
dx[k - i] = console->active->font.width;
468
}
469
ExtTextOutW( console->window->mem_dc, i * console->active->font.width,
470
j * console->active->font.height, 0, NULL, line, k - i, dx );
471
if (console->window->ext_leading &&
472
(brush = CreateSolidBrush( console->active->color_map[(attr >> 4) & 0x0F] )))
473
{
474
r.left = i * console->active->font.width;
475
r.top = (j + 1) * console->active->font.height - console->window->ext_leading;
476
r.right = k * console->active->font.width;
477
r.bottom = (j + 1) * console->active->font.height;
478
FillRect( console->window->mem_dc, &r, brush );
479
DeleteObject( brush );
480
}
481
i = k - 1;
482
}
483
}
484
SelectObject( console->window->mem_dc, old_font );
485
free( dx );
486
free( line );
487
}
488
489
/* set a new position for the cursor */
490
static void update_window_cursor( struct console *console )
491
{
492
if (!console->active->cursor_visible || console->win != GetFocus()) return;
493
494
SetCaretPos( (get_bounded_cursor_x( console->active ) - console->active->win.left) * console->active->font.width,
495
(console->active->cursor_y - console->active->win.top) * console->active->font.height );
496
ShowCaret( console->win );
497
}
498
499
/* sets a new shape for the cursor */
500
static void shape_cursor( struct console *console )
501
{
502
int size = console->active->cursor_size;
503
504
if (console->active->cursor_visible && console->win == GetFocus()) DestroyCaret();
505
if (console->window->cursor_bitmap) DeleteObject( console->window->cursor_bitmap );
506
console->window->cursor_bitmap = NULL;
507
console->window->cursor_visible = FALSE;
508
509
if (size != 100)
510
{
511
int w16b; /* number of bytes per row, aligned on word size */
512
int i, j, nbl;
513
BYTE *ptr;
514
515
w16b = ((console->active->font.width + 15) & ~15) / 8;
516
ptr = calloc( w16b, console->active->font.height );
517
if (!ptr) return;
518
nbl = max( (console->active->font.height * size) / 100, 1 );
519
for (j = console->active->font.height - nbl; j < console->active->font.height; j++)
520
{
521
for (i = 0; i < console->active->font.width; i++)
522
{
523
ptr[w16b * j + (i / 8)] |= 0x80 >> (i & 7);
524
}
525
}
526
console->window->cursor_bitmap = CreateBitmap( console->active->font.width,
527
console->active->font.height, 1, 1, ptr );
528
free(ptr);
529
}
530
}
531
532
static void update_window( struct console *console )
533
{
534
unsigned int win_width, win_height;
535
BOOL update_all = FALSE;
536
int dx, dy;
537
RECT r;
538
539
console->window->update_state = UPDATE_BUSY;
540
541
if (console->window->sb_width != console->active->width ||
542
console->window->sb_height != console->active->height ||
543
(!console->window->bitmap && IsWindowVisible( console->win )))
544
{
545
console->window->sb_width = console->active->width;
546
console->window->sb_height = console->active->height;
547
548
if (console->active->width && console->active->height && console->window->font)
549
{
550
HBITMAP bitmap;
551
HDC dc;
552
RECT r;
553
554
if (!(dc = GetDC( console->win ))) return;
555
556
bitmap = CreateCompatibleBitmap( dc,
557
console->active->width * console->active->font.width,
558
console->active->height * console->active->font.height );
559
ReleaseDC( console->win, dc );
560
SelectObject( console->window->mem_dc, bitmap );
561
562
if (console->window->bitmap) DeleteObject( console->window->bitmap );
563
console->window->bitmap = bitmap;
564
SetRect( &r, 0, 0, console->active->width - 1, console->active->height - 1 );
565
fill_mem_dc( console, &r );
566
}
567
568
empty_update_rect( console->active, &console->window->update );
569
update_all = TRUE;
570
}
571
572
/* compute window size from desired client size */
573
win_width = console->active->win.right - console->active->win.left + 1;
574
win_height = console->active->win.bottom - console->active->win.top + 1;
575
576
if (update_all || win_width != console->window->win_width ||
577
win_height != console->window->win_height)
578
{
579
console->window->win_width = win_width;
580
console->window->win_height = win_height;
581
582
r.left = r.top = 0;
583
r.right = win_width * console->active->font.width;
584
r.bottom = win_height * console->active->font.height;
585
AdjustWindowRect( &r, GetWindowLongW( console->win, GWL_STYLE ), FALSE );
586
587
dx = dy = 0;
588
if (console->active->width > win_width)
589
{
590
dy = GetSystemMetrics( SM_CYHSCROLL );
591
SetScrollRange( console->win, SB_HORZ, 0, console->active->width - win_width, FALSE );
592
SetScrollPos( console->win, SB_VERT, console->active->win.top, FALSE );
593
ShowScrollBar( console->win, SB_HORZ, TRUE );
594
}
595
else
596
{
597
ShowScrollBar( console->win, SB_HORZ, FALSE );
598
}
599
600
if (console->active->height > win_height)
601
{
602
dx = GetSystemMetrics( SM_CXVSCROLL );
603
SetScrollRange( console->win, SB_VERT, 0, console->active->height - win_height, FALSE );
604
SetScrollPos( console->win, SB_VERT, console->active->win.top, FALSE );
605
ShowScrollBar( console->win, SB_VERT, TRUE );
606
}
607
else
608
ShowScrollBar( console->win, SB_VERT, FALSE );
609
610
dx += r.right - r.left;
611
dy += r.bottom - r.top;
612
SetWindowPos( console->win, 0, 0, 0, dx, dy, SWP_NOMOVE | SWP_NOZORDER | SWP_NOACTIVATE );
613
614
SystemParametersInfoW( SPI_GETWORKAREA, 0, &r, 0 );
615
console->active->max_width = (r.right - r.left) / console->active->font.width;
616
console->active->max_height = (r.bottom - r.top - GetSystemMetrics( SM_CYCAPTION )) /
617
console->active->font.height;
618
619
InvalidateRect( console->win, NULL, FALSE );
620
UpdateWindow( console->win );
621
update_all = TRUE;
622
}
623
else if (console->active->win.left != console->window->win_pos.X ||
624
console->active->win.top != console->window->win_pos.Y)
625
{
626
ScrollWindow( console->win,
627
(console->window->win_pos.X - console->active->win.left) * console->active->font.width,
628
(console->window->win_pos.Y - console->active->win.top) * console->active->font.height,
629
NULL, NULL );
630
SetScrollPos( console->win, SB_HORZ, console->active->win.left, TRUE );
631
SetScrollPos( console->win, SB_VERT, console->active->win.top, TRUE );
632
InvalidateRect( console->win, NULL, FALSE );
633
}
634
635
console->window->win_pos.X = console->active->win.left;
636
console->window->win_pos.Y = console->active->win.top;
637
638
if (console->window->update.top <= console->window->update.bottom &&
639
console->window->update.left <= console->window->update.right)
640
{
641
RECT *update = &console->window->update;
642
r.left = (update->left - console->active->win.left) * console->active->font.width;
643
r.right = (update->right - console->active->win.left + 1) * console->active->font.width;
644
r.top = (update->top - console->active->win.top) * console->active->font.height;
645
r.bottom = (update->bottom - console->active->win.top + 1) * console->active->font.height;
646
fill_mem_dc( console, update );
647
empty_update_rect( console->active, &console->window->update );
648
InvalidateRect( console->win, &r, FALSE );
649
UpdateWindow( console->win );
650
}
651
652
if (update_all || console->active->cursor_size != console->window->cursor_size)
653
{
654
console->window->cursor_size = console->active->cursor_size;
655
shape_cursor( console );
656
}
657
658
if (console->active->cursor_visible != console->window->cursor_visible)
659
{
660
console->window->cursor_visible = console->active->cursor_visible;
661
if (console->win == GetFocus())
662
{
663
if (console->window->cursor_visible)
664
{
665
CreateCaret( console->win, console->window->cursor_bitmap,
666
console->active->font.width, console->active->font.height );
667
update_window_cursor( console );
668
}
669
else
670
DestroyCaret();
671
}
672
}
673
674
if (update_all || get_bounded_cursor_x( console->active ) != console->window->cursor_pos.X ||
675
console->active->cursor_y != console->window->cursor_pos.Y)
676
{
677
console->window->cursor_pos.X = get_bounded_cursor_x( console->active );
678
console->window->cursor_pos.Y = console->active->cursor_y;
679
update_window_cursor( console );
680
}
681
682
console->window->update_state = UPDATE_NONE;
683
}
684
685
/* get the relevant information from the font described in lf and store them in config */
686
static HFONT select_font_config( struct console_config *config, unsigned int cp, HWND hwnd,
687
const LOGFONTW *lf )
688
{
689
HFONT font, old_font;
690
TEXTMETRICW tm;
691
CPINFO cpinfo;
692
HDC dc;
693
694
if (!(dc = GetDC( hwnd ))) return NULL;
695
if (!(font = CreateFontIndirectW( lf )))
696
{
697
ReleaseDC( hwnd, dc );
698
return NULL;
699
}
700
701
old_font = SelectObject( dc, font );
702
GetTextMetricsW( dc, &tm );
703
SelectObject( dc, old_font );
704
ReleaseDC( hwnd, dc );
705
706
config->cell_width = tm.tmAveCharWidth;
707
config->cell_height = tm.tmHeight + tm.tmExternalLeading;
708
config->font_weight = tm.tmWeight;
709
lstrcpyW( config->face_name, lf->lfFaceName );
710
711
/* FIXME: use maximum width for DBCS codepages since some chars take two cells */
712
if (GetCPInfo( cp, &cpinfo ) && cpinfo.MaxCharSize == 2)
713
config->cell_width = tm.tmMaxCharWidth;
714
715
return font;
716
}
717
718
static void fill_logfont( LOGFONTW *lf, const WCHAR *face_name, size_t face_name_size,
719
unsigned int height, unsigned int weight )
720
{
721
lf->lfHeight = height;
722
lf->lfWidth = 0;
723
lf->lfEscapement = 0;
724
lf->lfOrientation = 0;
725
lf->lfWeight = weight;
726
lf->lfItalic = FALSE;
727
lf->lfUnderline = FALSE;
728
lf->lfStrikeOut = FALSE;
729
lf->lfCharSet = DEFAULT_CHARSET;
730
lf->lfOutPrecision = OUT_DEFAULT_PRECIS;
731
lf->lfClipPrecision = CLIP_DEFAULT_PRECIS;
732
lf->lfQuality = DEFAULT_QUALITY;
733
lf->lfPitchAndFamily = FIXED_PITCH | FF_DONTCARE;
734
face_name_size = min( face_name_size, sizeof(lf->lfFaceName) - sizeof(WCHAR) );
735
memcpy( lf->lfFaceName, face_name, face_name_size );
736
lf->lfFaceName[face_name_size / sizeof(WCHAR)] = 0;
737
}
738
739
static BOOL set_console_font( struct console *console, const LOGFONTW *logfont )
740
{
741
struct font_info *font_info = &console->active->font;
742
HFONT font, old_font;
743
TEXTMETRICW tm;
744
WCHAR face_name[LF_FACESIZE];
745
CPINFO cpinfo;
746
HDC dc;
747
748
TRACE( "%s\n", debugstr_logfont( logfont, 0 ));
749
750
if (console->window->font && logfont->lfHeight == console->active->font.height &&
751
logfont->lfWeight == console->active->font.weight &&
752
!logfont->lfItalic && !logfont->lfUnderline && !logfont->lfStrikeOut &&
753
console->active->font.face_len == wcslen( logfont->lfFaceName ) &&
754
!memcmp( logfont->lfFaceName, console->active->font.face_name,
755
console->active->font.face_len * sizeof(WCHAR) ))
756
{
757
TRACE( "equal to current\n" );
758
return TRUE;
759
}
760
761
if (!(dc = GetDC( console->win ))) return FALSE;
762
if (!(font = CreateFontIndirectW( logfont )))
763
{
764
ReleaseDC( console->win, dc );
765
return FALSE;
766
}
767
768
old_font = SelectObject( dc, font );
769
GetTextMetricsW( dc, &tm );
770
font_info->face_len = GetTextFaceW( dc, ARRAY_SIZE(face_name), face_name ) - 1;
771
SelectObject( dc, old_font );
772
ReleaseDC( console->win, dc );
773
774
font_info->width = tm.tmAveCharWidth;
775
font_info->height = tm.tmHeight + tm.tmExternalLeading;
776
font_info->pitch_family = tm.tmPitchAndFamily;
777
font_info->weight = tm.tmWeight;
778
779
free( font_info->face_name );
780
font_info->face_name = malloc( font_info->face_len * sizeof(WCHAR) );
781
memcpy( font_info->face_name, face_name, font_info->face_len * sizeof(WCHAR) );
782
783
/* FIXME: use maximum width for DBCS codepages since some chars take two cells */
784
if (GetCPInfo( console->output_cp, &cpinfo ) && cpinfo.MaxCharSize == 2)
785
font_info->width = tm.tmMaxCharWidth;
786
787
if (console->window->font) DeleteObject( console->window->font );
788
console->window->font = font;
789
console->window->ext_leading = tm.tmExternalLeading;
790
791
if (console->window->bitmap)
792
{
793
DeleteObject(console->window->bitmap);
794
console->window->bitmap = NULL;
795
}
796
return TRUE;
797
}
798
799
struct font_chooser
800
{
801
struct console *console;
802
unsigned int weight;
803
LOGFONTW lf;
804
};
805
806
/* check if the font family described in lf and tm is usable as a font for the renderer */
807
static BOOL validate_font( struct console *console, const LOGFONTW *lf,
808
const TEXTMETRICW *tm, DWORD type, int *weight )
809
{
810
int w = 0x1;
811
812
if (!tm) w |= 0x6;
813
else if (!(type & RASTER_FONTTYPE))
814
{
815
w |= 0x2;
816
if (tm->tmMaxCharWidth * (console->active->win.right - console->active->win.left + 1)
817
< GetSystemMetrics(SM_CXSCREEN)
818
&& tm->tmHeight * (console->active->win.bottom - console->active->win.top + 1)
819
< GetSystemMetrics(SM_CYSCREEN))
820
w |= 0x4;
821
}
822
if ((lf->lfPitchAndFamily & 3) == FIXED_PITCH
823
&& (!tm || (!tm->tmItalic && !tm->tmUnderlined && !tm->tmStruckOut)))
824
w |= 0x8;
825
if (lf->lfCharSet == console->window->ui_charset
826
&& (!tm || tm->tmCharSet == console->window->ui_charset))
827
w |= 0x10;
828
if (lf->lfFaceName[0] != '@')
829
w |= 0x20;
830
831
if (weight) *weight = w;
832
return w == 0x3f;
833
}
834
835
static int CALLBACK enum_first_font_proc( const LOGFONTW *lf, const TEXTMETRICW *tm,
836
DWORD font_type, LPARAM lparam )
837
{
838
struct font_chooser *fc = (struct font_chooser *)lparam;
839
int weight;
840
BOOL ret;
841
842
TRACE( "%s\n", debugstr_logfont( lf, font_type ));
843
TRACE( "%s\n", debugstr_textmetric( tm, font_type ));
844
845
ret = validate_font( fc->console, lf, tm, font_type, &weight );
846
if (weight > fc->weight)
847
{
848
fc->weight = weight;
849
fc->lf = *lf;
850
}
851
return !ret;
852
}
853
854
static void set_first_font( struct console *console, struct console_config *config )
855
{
856
LOGFONTW lf;
857
struct font_chooser fc;
858
859
TRACE("Looking for a suitable console font\n");
860
861
memset( &lf, 0, sizeof(lf) );
862
lf.lfCharSet = DEFAULT_CHARSET;
863
lf.lfPitchAndFamily = FIXED_PITCH | FF_MODERN;
864
865
memset( &fc, 0, sizeof(fc) );
866
fc.console = console;
867
868
EnumFontFamiliesExW( console->window->mem_dc, &lf, enum_first_font_proc, (LPARAM)&fc, 0);
869
870
fc.lf.lfHeight = config->cell_height;
871
fc.lf.lfWidth = config->cell_width;
872
if (!fc.weight || !set_console_font( console, &fc.lf ))
873
ERR("Unable to find a valid console font\n");
874
875
/* Update active configuration */
876
config->cell_width = console->active->font.width;
877
config->cell_height = console->active->font.height;
878
config->font_pitch_family = console->active->font.pitch_family;
879
memcpy( config->face_name, console->active->font.face_name,
880
console->active->font.face_len * sizeof(WCHAR) );
881
config->face_name[console->active->font.face_len] = 0;
882
883
/* Save default console configuration to the registry */
884
save_config( NULL, config );
885
}
886
887
/* Sets the font specified in the LOGFONT as the new console font */
888
void update_console_font( struct console *console, const WCHAR *face_name, size_t face_name_size,
889
unsigned int height, unsigned int weight )
890
{
891
LOGFONTW lf;
892
893
if (!console->window) return;
894
895
fill_logfont( &lf, face_name, face_name_size, height, weight );
896
897
set_console_font( console, &lf );
898
}
899
900
/* get a cell from a relative coordinate in window (takes into account the scrolling) */
901
static COORD get_cell( struct console *console, LPARAM lparam )
902
{
903
COORD c;
904
c.X = console->active->win.left + (short)LOWORD(lparam) / console->active->font.width;
905
c.Y = console->active->win.top + (short)HIWORD(lparam) / console->active->font.height;
906
return c;
907
}
908
909
/* get the console bit mask equivalent to the VK_ status in key state */
910
static DWORD get_ctrl_state( BYTE *key_state)
911
{
912
unsigned int ret = 0;
913
914
GetKeyboardState(key_state);
915
if (key_state[VK_SHIFT] & 0x80) ret |= SHIFT_PRESSED;
916
if (key_state[VK_LCONTROL] & 0x80) ret |= LEFT_CTRL_PRESSED;
917
if (key_state[VK_RCONTROL] & 0x80) ret |= RIGHT_CTRL_PRESSED;
918
if (key_state[VK_LMENU] & 0x80) ret |= LEFT_ALT_PRESSED;
919
if (key_state[VK_RMENU] & 0x80) ret |= RIGHT_ALT_PRESSED;
920
if (key_state[VK_CAPITAL] & 0x01) ret |= CAPSLOCK_ON;
921
if (key_state[VK_NUMLOCK] & 0x01) ret |= NUMLOCK_ON;
922
if (key_state[VK_SCROLL] & 0x01) ret |= SCROLLLOCK_ON;
923
924
return ret;
925
}
926
927
/* get the selection rectangle */
928
static void get_selection_rect( struct console *console, RECT *r )
929
{
930
r->left = (min(console->window->selection_start.X, console->window->selection_end.X) -
931
console->active->win.left) * console->active->font.width;
932
r->top = (min(console->window->selection_start.Y, console->window->selection_end.Y) -
933
console->active->win.top) * console->active->font.height;
934
r->right = (max(console->window->selection_start.X, console->window->selection_end.X) + 1 -
935
console->active->win.left) * console->active->font.width;
936
r->bottom = (max(console->window->selection_start.Y, console->window->selection_end.Y) + 1 -
937
console->active->win.top) * console->active->font.height;
938
}
939
940
static void update_selection( struct console *console, HDC ref_dc )
941
{
942
HDC dc;
943
RECT r;
944
945
get_selection_rect( console, &r );
946
dc = ref_dc ? ref_dc : GetDC( console->win );
947
if (!dc) return;
948
949
if (console->win == GetFocus() && console->active->cursor_visible)
950
HideCaret( console->win );
951
InvertRect( dc, &r );
952
if (dc != ref_dc)
953
ReleaseDC( console->win, dc );
954
if (console->win == GetFocus() && console->active->cursor_visible)
955
ShowCaret( console->win );
956
}
957
958
static void move_selection( struct console *console, COORD c1, COORD c2 )
959
{
960
RECT r;
961
HDC dc;
962
963
if (c1.X < 0 || c1.X >= console->active->width ||
964
c2.X < 0 || c2.X >= console->active->width ||
965
c1.Y < 0 || c1.Y >= console->active->height ||
966
c2.Y < 0 || c2.Y >= console->active->height)
967
return;
968
969
get_selection_rect( console, &r );
970
dc = GetDC( console->win );
971
if (dc)
972
{
973
if (console->win == GetFocus() && console->active->cursor_visible)
974
HideCaret( console->win );
975
InvertRect( dc, &r );
976
}
977
console->window->selection_start = c1;
978
console->window->selection_end = c2;
979
if (dc)
980
{
981
get_selection_rect( console, &r );
982
InvertRect( dc, &r );
983
ReleaseDC( console->win, dc );
984
if (console->win == GetFocus() && console->active->cursor_visible)
985
ShowCaret( console->win );
986
}
987
}
988
989
/* copies the current selection into the clipboard */
990
static void copy_selection( struct console *console )
991
{
992
unsigned int w, h;
993
WCHAR *p, *buf;
994
HANDLE mem;
995
996
w = abs( console->window->selection_start.X - console->window->selection_end.X ) + 1;
997
h = abs( console->window->selection_start.Y - console->window->selection_end.Y ) + 1;
998
999
if (!OpenClipboard( console->win )) return;
1000
EmptyClipboard();
1001
1002
mem = GlobalAlloc( GMEM_MOVEABLE, (w + 1) * h * sizeof(WCHAR) );
1003
if (mem && (p = buf = GlobalLock( mem )))
1004
{
1005
int x, y;
1006
COORD c;
1007
1008
c.X = min( console->window->selection_start.X, console->window->selection_end.X );
1009
c.Y = min( console->window->selection_start.Y, console->window->selection_end.Y );
1010
1011
for (y = c.Y; y < c.Y + h; y++)
1012
{
1013
WCHAR *end;
1014
1015
for (x = c.X; x < c.X + w; x++)
1016
p[x - c.X] = console->active->data[y * console->active->width + x].ch;
1017
1018
/* strip spaces from the end of the line */
1019
end = p + w;
1020
while (end > p && *(end - 1) == ' ')
1021
end--;
1022
*end = (y < c.Y + h - 1) ? '\n' : '\0';
1023
p = end + 1;
1024
}
1025
1026
TRACE( "%s\n", debugstr_w( buf ));
1027
if (p - buf != (w + 1) * h)
1028
{
1029
HANDLE new_mem;
1030
new_mem = GlobalReAlloc( mem, (p - buf) * sizeof(WCHAR), GMEM_MOVEABLE );
1031
if (new_mem) mem = new_mem;
1032
}
1033
GlobalUnlock( mem );
1034
SetClipboardData( CF_UNICODETEXT, mem );
1035
}
1036
CloseClipboard();
1037
}
1038
1039
static void paste_clipboard( struct console *console )
1040
{
1041
WCHAR *ptr;
1042
HANDLE h;
1043
1044
if (!OpenClipboard( console->win )) return;
1045
h = GetClipboardData( CF_UNICODETEXT );
1046
if (h && (ptr = GlobalLock( h )))
1047
{
1048
unsigned int i, len = GlobalSize(h) / sizeof(WCHAR);
1049
INPUT_RECORD ir[2];
1050
SHORT sh;
1051
1052
ir[0].EventType = KEY_EVENT;
1053
ir[0].Event.KeyEvent.wRepeatCount = 0;
1054
ir[0].Event.KeyEvent.dwControlKeyState = 0;
1055
ir[0].Event.KeyEvent.bKeyDown = TRUE;
1056
1057
/* generate the corresponding input records */
1058
for (i = 0; i < len; i++)
1059
{
1060
/* FIXME: the modifying keys are not generated (shift, ctrl...) */
1061
sh = VkKeyScanW( ptr[i] );
1062
ir[0].Event.KeyEvent.wVirtualKeyCode = LOBYTE(sh);
1063
ir[0].Event.KeyEvent.wVirtualScanCode = MapVirtualKeyW( LOBYTE(sh), 0 );
1064
ir[0].Event.KeyEvent.uChar.UnicodeChar = ptr[i];
1065
1066
ir[1] = ir[0];
1067
ir[1].Event.KeyEvent.bKeyDown = FALSE;
1068
1069
write_console_input( console, ir, 2, i == len - 1 );
1070
}
1071
GlobalUnlock( h );
1072
}
1073
1074
CloseClipboard();
1075
}
1076
1077
/* handle keys while selecting an area */
1078
static void handle_selection_key( struct console *console, BOOL down, WPARAM wparam, LPARAM lparam )
1079
{
1080
BYTE key_state[256];
1081
COORD c1, c2;
1082
DWORD state;
1083
1084
if (!down) return;
1085
state = get_ctrl_state( key_state ) & ~(CAPSLOCK_ON|NUMLOCK_ON|SCROLLLOCK_ON);
1086
1087
switch (state)
1088
{
1089
case 0:
1090
switch (wparam)
1091
{
1092
case VK_RETURN:
1093
console->window->in_selection = FALSE;
1094
update_selection( console, 0 );
1095
copy_selection( console );
1096
return;
1097
case VK_RIGHT:
1098
c1 = console->window->selection_start;
1099
c2 = console->window->selection_end;
1100
c1.X++; c2.X++;
1101
move_selection( console, c1, c2 );
1102
return;
1103
case VK_LEFT:
1104
c1 = console->window->selection_start;
1105
c2 = console->window->selection_end;
1106
c1.X--; c2.X--;
1107
move_selection( console, c1, c2 );
1108
return;
1109
case VK_UP:
1110
c1 = console->window->selection_start;
1111
c2 = console->window->selection_end;
1112
c1.Y--; c2.Y--;
1113
move_selection( console, c1, c2 );
1114
return;
1115
case VK_DOWN:
1116
c1 = console->window->selection_start;
1117
c2 = console->window->selection_end;
1118
c1.Y++; c2.Y++;
1119
move_selection( console, c1, c2 );
1120
return;
1121
}
1122
break;
1123
case SHIFT_PRESSED:
1124
switch (wparam)
1125
{
1126
case VK_RIGHT:
1127
c1 = console->window->selection_start;
1128
c2 = console->window->selection_end;
1129
c2.X++;
1130
move_selection( console, c1, c2 );
1131
return;
1132
case VK_LEFT:
1133
c1 = console->window->selection_start;
1134
c2 = console->window->selection_end;
1135
c2.X--;
1136
move_selection( console, c1, c2 );
1137
return;
1138
case VK_UP:
1139
c1 = console->window->selection_start;
1140
c2 = console->window->selection_end;
1141
c2.Y--;
1142
move_selection( console, c1, c2 );
1143
return;
1144
case VK_DOWN:
1145
c1 = console->window->selection_start;
1146
c2 = console->window->selection_end;
1147
c2.Y++;
1148
move_selection( console, c1, c2 );
1149
return;
1150
}
1151
break;
1152
}
1153
1154
if (wparam < VK_SPACE) /* Shift, Alt, Ctrl, Num Lock etc. */
1155
return;
1156
1157
update_selection( console, 0 );
1158
console->window->in_selection = FALSE;
1159
}
1160
1161
/* generate input_record from windows WM_KEYUP/WM_KEYDOWN messages */
1162
static void record_key_input( struct console *console, BOOL down, WPARAM wparam, LPARAM lparam )
1163
{
1164
static WCHAR last; /* keep last char seen as feed for key up message */
1165
BYTE key_state[256];
1166
INPUT_RECORD ir;
1167
WCHAR buf[2];
1168
1169
ir.EventType = KEY_EVENT;
1170
ir.Event.KeyEvent.bKeyDown = down;
1171
ir.Event.KeyEvent.wRepeatCount = LOWORD(lparam);
1172
ir.Event.KeyEvent.wVirtualKeyCode = wparam;
1173
ir.Event.KeyEvent.wVirtualScanCode = HIWORD(lparam) & 0xFF;
1174
ir.Event.KeyEvent.uChar.UnicodeChar = 0;
1175
ir.Event.KeyEvent.dwControlKeyState = get_ctrl_state( key_state );
1176
if (lparam & (1u << 24)) ir.Event.KeyEvent.dwControlKeyState |= ENHANCED_KEY;
1177
1178
if (down)
1179
{
1180
switch (ToUnicode(wparam, HIWORD(lparam), key_state, buf, 2, 0))
1181
{
1182
case 2:
1183
/* FIXME: should generate two events */
1184
/* fall through */
1185
case 1:
1186
last = buf[0];
1187
break;
1188
default:
1189
last = 0;
1190
break;
1191
}
1192
}
1193
ir.Event.KeyEvent.uChar.UnicodeChar = last;
1194
if (!down) last = 0; /* FIXME: buggy HACK */
1195
1196
write_console_input( console, &ir, 1, TRUE );
1197
}
1198
1199
/* generate input_record from WM_CHAR message. */
1200
static void record_char_input( struct console *console, WCHAR ch, LPARAM lparam )
1201
{
1202
INPUT_RECORD ir;
1203
SHORT sh = VkKeyScanW( ch );
1204
1205
if (sh == ~0) return;
1206
ir.EventType = KEY_EVENT;
1207
ir.Event.KeyEvent.bKeyDown = TRUE;
1208
ir.Event.KeyEvent.wRepeatCount = 0;
1209
ir.Event.KeyEvent.wVirtualKeyCode = LOBYTE(sh);
1210
ir.Event.KeyEvent.wVirtualScanCode = MapVirtualKeyW( LOBYTE(sh), 0 );
1211
ir.Event.KeyEvent.uChar.UnicodeChar = ch;
1212
ir.Event.KeyEvent.dwControlKeyState = 0;
1213
if (lparam & (1u << 24)) ir.Event.KeyEvent.dwControlKeyState |= ENHANCED_KEY;
1214
1215
write_console_input( console, &ir, 1, TRUE );
1216
}
1217
1218
static void record_mouse_input( struct console *console, COORD c, WPARAM wparam, DWORD event )
1219
{
1220
BYTE key_state[256];
1221
INPUT_RECORD ir;
1222
1223
/* MOUSE_EVENTs shouldn't be sent unless ENABLE_MOUSE_INPUT is active */
1224
if (!(console->mode & ENABLE_MOUSE_INPUT)) return;
1225
1226
ir.EventType = MOUSE_EVENT;
1227
ir.Event.MouseEvent.dwMousePosition = c;
1228
ir.Event.MouseEvent.dwButtonState = 0;
1229
if (wparam & MK_LBUTTON) ir.Event.MouseEvent.dwButtonState |= FROM_LEFT_1ST_BUTTON_PRESSED;
1230
if (wparam & MK_MBUTTON) ir.Event.MouseEvent.dwButtonState |= FROM_LEFT_2ND_BUTTON_PRESSED;
1231
if (wparam & MK_RBUTTON) ir.Event.MouseEvent.dwButtonState |= RIGHTMOST_BUTTON_PRESSED;
1232
if (wparam & MK_CONTROL) ir.Event.MouseEvent.dwButtonState |= LEFT_CTRL_PRESSED;
1233
if (wparam & MK_SHIFT) ir.Event.MouseEvent.dwButtonState |= SHIFT_PRESSED;
1234
if (event == MOUSE_WHEELED) ir.Event.MouseEvent.dwButtonState |= wparam & 0xFFFF0000;
1235
ir.Event.MouseEvent.dwControlKeyState = get_ctrl_state( key_state );
1236
ir.Event.MouseEvent.dwEventFlags = event;
1237
1238
write_console_input( console, &ir, 1, TRUE );
1239
}
1240
1241
struct dialog_info
1242
{
1243
struct console *console;
1244
struct console_config config;
1245
HWND dialog; /* handle to active propsheet */
1246
};
1247
1248
/* dialog proc for the option property sheet */
1249
static INT_PTR WINAPI option_dialog_proc( HWND dialog, UINT msg, WPARAM wparam, LPARAM lparam )
1250
{
1251
struct dialog_info *di;
1252
unsigned int idc;
1253
1254
switch (msg)
1255
{
1256
case WM_INITDIALOG:
1257
di = (struct dialog_info *)((PROPSHEETPAGEA *)lparam)->lParam;
1258
di->dialog = dialog;
1259
SetWindowLongPtrW( dialog, DWLP_USER, (LONG_PTR)di );
1260
1261
SendMessageW( GetDlgItem( dialog, IDC_OPT_HIST_SIZE_UD ), UDM_SETRANGE, 0, MAKELPARAM(500, 0) );
1262
1263
if (di->config.cursor_size <= 25) idc = IDC_OPT_CURSOR_SMALL;
1264
else if (di->config.cursor_size <= 50) idc = IDC_OPT_CURSOR_MEDIUM;
1265
else idc = IDC_OPT_CURSOR_LARGE;
1266
1267
SendDlgItemMessageW( dialog, idc, BM_SETCHECK, BST_CHECKED, 0 );
1268
SetDlgItemInt( dialog, IDC_OPT_HIST_SIZE, di->config.history_size, FALSE );
1269
SendDlgItemMessageW( dialog, IDC_OPT_HIST_NODOUBLE, BM_SETCHECK,
1270
(di->config.history_mode) ? BST_CHECKED : BST_UNCHECKED, 0 );
1271
SendDlgItemMessageW( dialog, IDC_OPT_INSERT_MODE, BM_SETCHECK,
1272
(di->config.insert_mode) ? BST_CHECKED : BST_UNCHECKED, 0 );
1273
SendDlgItemMessageW( dialog, IDC_OPT_CONF_CTRL, BM_SETCHECK,
1274
(di->config.menu_mask & MK_CONTROL) ? BST_CHECKED : BST_UNCHECKED, 0 );
1275
SendDlgItemMessageW( dialog, IDC_OPT_CONF_SHIFT, BM_SETCHECK,
1276
(di->config.menu_mask & MK_SHIFT) ? BST_CHECKED : BST_UNCHECKED, 0 );
1277
SendDlgItemMessageW( dialog, IDC_OPT_QUICK_EDIT, BM_SETCHECK,
1278
(di->config.quick_edit) ? BST_CHECKED : BST_UNCHECKED, 0 );
1279
return FALSE; /* because we set the focus */
1280
1281
case WM_COMMAND:
1282
break;
1283
1284
case WM_NOTIFY:
1285
{
1286
NMHDR *nmhdr = (NMHDR*)lparam;
1287
DWORD val;
1288
BOOL done;
1289
1290
di = (struct dialog_info *)GetWindowLongPtrW( dialog, DWLP_USER );
1291
1292
switch (nmhdr->code)
1293
{
1294
case PSN_SETACTIVE:
1295
/* needed in propsheet to keep properly the selected radio button
1296
* otherwise, the focus would be set to the first tab stop in the
1297
* propsheet, which would always activate the first radio button
1298
*/
1299
if (IsDlgButtonChecked( dialog, IDC_OPT_CURSOR_SMALL ) == BST_CHECKED)
1300
idc = IDC_OPT_CURSOR_SMALL;
1301
else if (IsDlgButtonChecked( dialog, IDC_OPT_CURSOR_MEDIUM ) == BST_CHECKED)
1302
idc = IDC_OPT_CURSOR_MEDIUM;
1303
else
1304
idc = IDC_OPT_CURSOR_LARGE;
1305
PostMessageW( dialog, WM_NEXTDLGCTL, (WPARAM)GetDlgItem( dialog, idc ), TRUE );
1306
di->dialog = dialog;
1307
break;
1308
case PSN_APPLY:
1309
if (IsDlgButtonChecked( dialog, IDC_OPT_CURSOR_SMALL ) == BST_CHECKED) val = 25;
1310
else if (IsDlgButtonChecked( dialog, IDC_OPT_CURSOR_MEDIUM ) == BST_CHECKED) val = 50;
1311
else val = 100;
1312
di->config.cursor_size = val;
1313
1314
val = GetDlgItemInt( dialog, IDC_OPT_HIST_SIZE, &done, FALSE );
1315
if (done) di->config.history_size = val;
1316
1317
val = (IsDlgButtonChecked( dialog, IDC_OPT_HIST_NODOUBLE ) & BST_CHECKED) != 0;
1318
di->config.history_mode = val;
1319
1320
val = (IsDlgButtonChecked( dialog, IDC_OPT_INSERT_MODE ) & BST_CHECKED) != 0;
1321
di->config.insert_mode = val;
1322
1323
val = 0;
1324
if (IsDlgButtonChecked( dialog, IDC_OPT_CONF_CTRL ) & BST_CHECKED) val |= MK_CONTROL;
1325
if (IsDlgButtonChecked( dialog, IDC_OPT_CONF_SHIFT ) & BST_CHECKED) val |= MK_SHIFT;
1326
di->config.menu_mask = val;
1327
1328
val = (IsDlgButtonChecked( dialog, IDC_OPT_QUICK_EDIT ) & BST_CHECKED) != 0;
1329
di->config.quick_edit = val;
1330
1331
SetWindowLongPtrW( dialog, DWLP_MSGRESULT, PSNRET_NOERROR );
1332
return TRUE;
1333
default:
1334
return FALSE;
1335
}
1336
break;
1337
}
1338
default:
1339
return FALSE;
1340
}
1341
return TRUE;
1342
}
1343
1344
static COLORREF get_color( struct dialog_info *di, unsigned int idc )
1345
{
1346
LONG_PTR index;
1347
1348
index = GetWindowLongW(GetDlgItem( di->dialog, idc ), 0);
1349
return di->config.color_map[index];
1350
}
1351
1352
/* window proc for font previewer in font property sheet */
1353
static LRESULT WINAPI font_preview_proc( HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam )
1354
{
1355
switch (msg)
1356
{
1357
case WM_CREATE:
1358
SetWindowLongPtrW( hwnd, 0, 0 );
1359
break;
1360
1361
case WM_GETFONT:
1362
return GetWindowLongPtrW( hwnd, 0 );
1363
1364
case WM_SETFONT:
1365
SetWindowLongPtrW( hwnd, 0, wparam );
1366
if (LOWORD(lparam))
1367
{
1368
InvalidateRect( hwnd, NULL, TRUE );
1369
UpdateWindow( hwnd );
1370
}
1371
break;
1372
1373
case WM_DESTROY:
1374
{
1375
HFONT font = (HFONT)GetWindowLongPtrW( hwnd, 0 );
1376
if (font) DeleteObject( font );
1377
break;
1378
}
1379
1380
case WM_PAINT:
1381
{
1382
struct dialog_info *di;
1383
HFONT font, old_font;
1384
PAINTSTRUCT ps;
1385
1386
di = (struct dialog_info *)GetWindowLongPtrW( GetParent( hwnd ), DWLP_USER );
1387
BeginPaint( hwnd, &ps );
1388
1389
font = (HFONT)GetWindowLongPtrW( hwnd, 0 );
1390
if (font)
1391
{
1392
static const WCHAR ascii[] = L"ASCII: abcXYZ";
1393
COLORREF bkcolor;
1394
WCHAR buf[256];
1395
int len;
1396
1397
old_font = SelectObject( ps.hdc, font );
1398
bkcolor = get_color( di, IDC_FNT_COLOR_BK );
1399
FillRect( ps.hdc, &ps.rcPaint, CreateSolidBrush( bkcolor ));
1400
SetBkColor( ps.hdc, bkcolor );
1401
SetTextColor( ps.hdc, get_color( di, IDC_FNT_COLOR_FG ));
1402
len = LoadStringW( GetModuleHandleW(NULL), IDS_FNT_PREVIEW, buf, ARRAY_SIZE(buf) );
1403
if (len) TextOutW( ps.hdc, 0, 0, buf, len );
1404
TextOutW( ps.hdc, 0, di->config.cell_height, ascii, ARRAY_SIZE(ascii) - 1 );
1405
SelectObject( ps.hdc, old_font );
1406
}
1407
EndPaint( hwnd, &ps );
1408
break;
1409
}
1410
1411
default:
1412
return DefWindowProcW( hwnd, msg, wparam, lparam );
1413
}
1414
return 0;
1415
}
1416
1417
/* window proc for color previewer */
1418
static LRESULT WINAPI color_preview_proc( HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam )
1419
{
1420
switch (msg)
1421
{
1422
case WM_PAINT:
1423
{
1424
struct dialog_info *di;
1425
PAINTSTRUCT ps;
1426
RECT client, r;
1427
int i, step;
1428
HBRUSH brush;
1429
1430
BeginPaint( hwnd, &ps );
1431
GetClientRect( hwnd, &client );
1432
step = client.right / 8;
1433
1434
di = (struct dialog_info *)GetWindowLongPtrW( GetParent(hwnd), DWLP_USER );
1435
1436
for (i = 0; i < 16; i++)
1437
{
1438
r.top = (i / 8) * (client.bottom / 2);
1439
r.bottom = r.top + client.bottom / 2;
1440
r.left = (i & 7) * step;
1441
r.right = r.left + step;
1442
brush = CreateSolidBrush( di->config.color_map[i] );
1443
FillRect( ps.hdc, &r, brush );
1444
DeleteObject( brush );
1445
if (GetWindowLongW( hwnd, 0 ) == i)
1446
{
1447
HPEN old_pen;
1448
int i = 2;
1449
1450
old_pen = SelectObject( ps.hdc, GetStockObject( WHITE_PEN ));
1451
r.right--; r.bottom--;
1452
for (;;)
1453
{
1454
MoveToEx( ps.hdc, r.left, r.bottom, NULL );
1455
LineTo( ps.hdc, r.left, r.top );
1456
LineTo( ps.hdc, r.right, r.top );
1457
SelectObject( ps.hdc, GetStockObject( BLACK_PEN ));
1458
LineTo( ps.hdc, r.right, r.bottom );
1459
LineTo( ps.hdc, r.left, r.bottom );
1460
if (--i == 0) break;
1461
r.left++; r.top++; r.right--; r.bottom--;
1462
SelectObject( ps.hdc, GetStockObject( WHITE_PEN ));
1463
}
1464
SelectObject( ps.hdc, old_pen );
1465
}
1466
}
1467
EndPaint( hwnd, &ps );
1468
break;
1469
}
1470
1471
case WM_LBUTTONDOWN:
1472
{
1473
int i, step;
1474
RECT client;
1475
1476
GetClientRect( hwnd, &client );
1477
step = client.right / 8;
1478
i = (HIWORD(lparam) >= client.bottom / 2) ? 8 : 0;
1479
i += LOWORD(lparam) / step;
1480
SetWindowLongW( hwnd, 0, i );
1481
InvalidateRect( GetDlgItem( GetParent( hwnd ), IDC_FNT_PREVIEW ), NULL, FALSE );
1482
InvalidateRect( hwnd, NULL, FALSE );
1483
break;
1484
}
1485
1486
default:
1487
return DefWindowProcW( hwnd, msg, wparam, lparam );
1488
}
1489
return 0;
1490
}
1491
1492
static BOOL select_font( struct dialog_info *di )
1493
{
1494
int font_idx, size_idx;
1495
WCHAR face_name[LF_FACESIZE], height_buf[4];
1496
size_t len;
1497
unsigned int font_height;
1498
LOGFONTW lf;
1499
HFONT font, old_font;
1500
DWORD_PTR args[2];
1501
WCHAR buf[256];
1502
WCHAR fmt[128];
1503
1504
font_idx = SendDlgItemMessageW( di->dialog, IDC_FNT_LIST_FONT, LB_GETCURSEL, 0, 0 );
1505
size_idx = SendDlgItemMessageW( di->dialog, IDC_FNT_LIST_SIZE, LB_GETCURSEL, 0, 0 );
1506
1507
if (font_idx < 0 || size_idx < 0)
1508
return FALSE;
1509
1510
len = SendDlgItemMessageW( di->dialog, IDC_FNT_LIST_FONT, LB_GETTEXT, font_idx, (LPARAM)&face_name );
1511
SendDlgItemMessageW( di->dialog, IDC_FNT_LIST_SIZE, LB_GETTEXT, size_idx, (LPARAM)&height_buf );
1512
font_height = _wtoi( height_buf );
1513
1514
fill_logfont( &lf, face_name, len * sizeof(WCHAR), font_height, FW_NORMAL );
1515
font = select_font_config( &di->config, di->console->output_cp, di->console->win, &lf );
1516
if (!font) return FALSE;
1517
1518
if (di->config.cell_height != font_height)
1519
TRACE( "mismatched heights (%u<>%u)\n", di->config.cell_height, font_height );
1520
1521
old_font = (HFONT)SendDlgItemMessageW( di->dialog, IDC_FNT_PREVIEW, WM_GETFONT, 0, 0 );
1522
SendDlgItemMessageW( di->dialog, IDC_FNT_PREVIEW, WM_SETFONT, (WPARAM)font, TRUE );
1523
if (old_font) DeleteObject( old_font );
1524
1525
LoadStringW( GetModuleHandleW(NULL), IDS_FNT_DISPLAY, fmt, ARRAY_SIZE(fmt) );
1526
args[0] = di->config.cell_width;
1527
args[1] = di->config.cell_height;
1528
FormatMessageW( FORMAT_MESSAGE_FROM_STRING|FORMAT_MESSAGE_ARGUMENT_ARRAY,
1529
fmt, 0, 0, buf, ARRAY_SIZE(buf), (va_list *)args );
1530
1531
SendDlgItemMessageW( di->dialog, IDC_FNT_FONT_INFO, WM_SETTEXT, 0, (LPARAM)buf );
1532
return TRUE;
1533
}
1534
1535
static BOOL fill_list_size( struct dialog_info *di, BOOL init )
1536
{
1537
if (init)
1538
{
1539
static const int sizes[] = {8,9,10,11,12,14,16,18,20,22,24,26,28,36,48,72};
1540
unsigned int i, idx = 4;
1541
WCHAR buf[4];
1542
1543
for (i = 0; i < ARRAY_SIZE(sizes); i++)
1544
{
1545
wsprintfW( buf, L"%u", sizes[i] );
1546
SendDlgItemMessageW( di->dialog, IDC_FNT_LIST_SIZE, LB_INSERTSTRING, -1, (LPARAM)buf );
1547
1548
if (di->config.cell_height == sizes[i]) idx = i;
1549
}
1550
1551
SendDlgItemMessageW( di->dialog, IDC_FNT_LIST_SIZE, LB_SETCURSEL, idx, 0 );
1552
}
1553
1554
select_font( di );
1555
1556
return TRUE;
1557
}
1558
1559
static int CALLBACK enum_list_font_proc( const LOGFONTW *lf, const TEXTMETRICW *tm,
1560
DWORD font_type, LPARAM lparam )
1561
{
1562
struct dialog_info *di = (struct dialog_info *)lparam;
1563
1564
TRACE( "%s\n", debugstr_logfont( lf, font_type ));
1565
1566
if (validate_font( di->console, lf, NULL, 0, NULL ))
1567
SendDlgItemMessageW( di->dialog, IDC_FNT_LIST_FONT, LB_ADDSTRING, 0, (LPARAM)lf->lfFaceName );
1568
1569
return 1;
1570
}
1571
1572
static BOOL fill_list_font( struct dialog_info *di )
1573
{
1574
LOGFONTW lf;
1575
1576
memset( &lf, 0, sizeof(lf) );
1577
lf.lfCharSet = DEFAULT_CHARSET;
1578
lf.lfFaceName[0] = 0;
1579
lf.lfPitchAndFamily = FIXED_PITCH | FF_MODERN;
1580
1581
EnumFontFamiliesExW( di->console->window->mem_dc, &lf, enum_list_font_proc, (LPARAM)di, 0 );
1582
1583
if (SendDlgItemMessageW( di->dialog, IDC_FNT_LIST_FONT, LB_SELECTSTRING,
1584
-1, (LPARAM)di->config.face_name ) == LB_ERR)
1585
SendDlgItemMessageW( di->dialog, IDC_FNT_LIST_FONT, LB_SETCURSEL, 0, 0 );
1586
1587
fill_list_size( di, TRUE );
1588
1589
return TRUE;
1590
}
1591
1592
/* dialog proc for the font property sheet */
1593
static INT_PTR WINAPI font_dialog_proc( HWND dialog, UINT msg, WPARAM wparam, LPARAM lparam )
1594
{
1595
struct dialog_info *di;
1596
1597
switch (msg)
1598
{
1599
case WM_INITDIALOG:
1600
di = (struct dialog_info *)((PROPSHEETPAGEA*)lparam)->lParam;
1601
di->dialog = dialog;
1602
SetWindowLongPtrW( dialog, DWLP_USER, (DWORD_PTR)di );
1603
/* use default system font until user-selected font is applied */
1604
SendDlgItemMessageW( dialog, IDC_FNT_PREVIEW, WM_SETFONT, 0, 0 );
1605
fill_list_font( di );
1606
SetWindowLongW( GetDlgItem( dialog, IDC_FNT_COLOR_BK ), 0, (di->config.attr >> 4) & 0x0F );
1607
SetWindowLongW( GetDlgItem( dialog, IDC_FNT_COLOR_FG ), 0, di->config.attr & 0x0F );
1608
break;
1609
1610
case WM_COMMAND:
1611
di = (struct dialog_info *)GetWindowLongPtrW( dialog, DWLP_USER );
1612
switch (LOWORD(wparam))
1613
{
1614
case IDC_FNT_LIST_FONT:
1615
if (HIWORD(wparam) == LBN_SELCHANGE)
1616
fill_list_size( di, FALSE );
1617
break;
1618
case IDC_FNT_LIST_SIZE:
1619
if (HIWORD(wparam) == LBN_SELCHANGE)
1620
select_font( di );
1621
break;
1622
}
1623
break;
1624
1625
case WM_NOTIFY:
1626
{
1627
NMHDR *nmhdr = (NMHDR*)lparam;
1628
DWORD val;
1629
1630
di = (struct dialog_info*)GetWindowLongPtrW( dialog, DWLP_USER );
1631
switch (nmhdr->code)
1632
{
1633
case PSN_SETACTIVE:
1634
di->dialog = dialog;
1635
break;
1636
case PSN_APPLY:
1637
val = (GetWindowLongW( GetDlgItem( dialog, IDC_FNT_COLOR_BK ), 0 ) << 4) |
1638
GetWindowLongW( GetDlgItem( dialog, IDC_FNT_COLOR_FG ), 0 );
1639
di->config.attr = val;
1640
SetWindowLongPtrW( dialog, DWLP_MSGRESULT, PSNRET_NOERROR );
1641
return TRUE;
1642
default:
1643
return FALSE;
1644
}
1645
break;
1646
}
1647
default:
1648
return FALSE;
1649
}
1650
return TRUE;
1651
}
1652
1653
/* dialog proc for the config property sheet */
1654
static INT_PTR WINAPI config_dialog_proc( HWND dialog, UINT msg, WPARAM wparam, LPARAM lparam )
1655
{
1656
struct dialog_info *di;
1657
int max_ud = 2000;
1658
1659
switch (msg)
1660
{
1661
case WM_INITDIALOG:
1662
di = (struct dialog_info *)((PROPSHEETPAGEA*)lparam)->lParam;
1663
di->dialog = dialog;
1664
1665
SetWindowLongPtrW( dialog, DWLP_USER, (DWORD_PTR)di );
1666
SetDlgItemInt( dialog, IDC_CNF_SB_WIDTH, di->config.sb_width, FALSE );
1667
SetDlgItemInt( dialog, IDC_CNF_SB_HEIGHT, di->config.sb_height, FALSE );
1668
SetDlgItemInt( dialog, IDC_CNF_WIN_WIDTH, di->config.win_width, FALSE );
1669
SetDlgItemInt( dialog, IDC_CNF_WIN_HEIGHT, di->config.win_height, FALSE );
1670
1671
SendMessageW( GetDlgItem(dialog, IDC_CNF_WIN_HEIGHT_UD), UDM_SETRANGE, 0, MAKELPARAM(max_ud, 0));
1672
SendMessageW( GetDlgItem(dialog, IDC_CNF_WIN_WIDTH_UD), UDM_SETRANGE, 0, MAKELPARAM(max_ud, 0));
1673
SendMessageW( GetDlgItem(dialog, IDC_CNF_SB_HEIGHT_UD), UDM_SETRANGE, 0, MAKELPARAM(max_ud, 0));
1674
SendMessageW( GetDlgItem(dialog, IDC_CNF_SB_WIDTH_UD), UDM_SETRANGE, 0, MAKELPARAM(max_ud, 0));
1675
1676
SendDlgItemMessageW( dialog, IDC_CNF_CLOSE_EXIT, BM_SETCHECK, BST_CHECKED, 0 );
1677
1678
SendDlgItemMessageW( dialog, IDC_CNF_EDITION_MODE, CB_ADDSTRING, 0, (LPARAM)L"Win32" );
1679
SendDlgItemMessageW( dialog, IDC_CNF_EDITION_MODE, CB_ADDSTRING, 0, (LPARAM)L"Emacs" );
1680
SendDlgItemMessageW( dialog, IDC_CNF_EDITION_MODE, CB_SETCURSEL, di->config.edition_mode, 0 );
1681
break;
1682
1683
case WM_NOTIFY:
1684
{
1685
NMHDR *nmhdr = (NMHDR*)lparam;
1686
int win_w, win_h, sb_w, sb_h;
1687
BOOL st1, st2;
1688
1689
di = (struct dialog_info *)GetWindowLongPtrW( dialog, DWLP_USER );
1690
switch (nmhdr->code)
1691
{
1692
case PSN_SETACTIVE:
1693
di->dialog = dialog;
1694
break;
1695
case PSN_APPLY:
1696
sb_w = GetDlgItemInt( dialog, IDC_CNF_SB_WIDTH, &st1, FALSE );
1697
sb_h = GetDlgItemInt( dialog, IDC_CNF_SB_HEIGHT, &st2, FALSE );
1698
if (!st1 || ! st2)
1699
{
1700
SetWindowLongPtrW( dialog, DWLP_MSGRESULT, PSNRET_INVALID );
1701
return TRUE;
1702
}
1703
win_w = GetDlgItemInt( dialog, IDC_CNF_WIN_WIDTH, &st1, FALSE );
1704
win_h = GetDlgItemInt( dialog, IDC_CNF_WIN_HEIGHT, &st2, FALSE );
1705
if (!st1 || !st2)
1706
{
1707
SetWindowLongPtrW( dialog, DWLP_MSGRESULT, PSNRET_INVALID );
1708
return TRUE;
1709
}
1710
if (win_w > sb_w || win_h > sb_h)
1711
{
1712
WCHAR cap[256];
1713
WCHAR txt[256];
1714
1715
LoadStringW( GetModuleHandleW(NULL), IDS_DLG_TIT_ERROR, cap, ARRAY_SIZE(cap) );
1716
LoadStringW( GetModuleHandleW(NULL), IDS_DLG_ERR_SBWINSIZE, txt, ARRAY_SIZE(txt) );
1717
1718
MessageBoxW( dialog, txt, cap, MB_OK );
1719
SetWindowLongPtrW( dialog, DWLP_MSGRESULT, PSNRET_INVALID );
1720
return TRUE;
1721
}
1722
di->config.win_width = win_w;
1723
di->config.win_height = win_h;
1724
di->config.sb_width = sb_w;
1725
di->config.sb_height = sb_h;
1726
1727
di->config.edition_mode = SendDlgItemMessageW( dialog, IDC_CNF_EDITION_MODE,
1728
CB_GETCURSEL, 0, 0 );
1729
SetWindowLongPtrW( dialog, DWLP_MSGRESULT, PSNRET_NOERROR );
1730
return TRUE;
1731
default:
1732
return FALSE;
1733
}
1734
break;
1735
}
1736
default:
1737
return FALSE;
1738
}
1739
return TRUE;
1740
}
1741
1742
static void apply_config( struct console *console, const struct console_config *config )
1743
{
1744
if (console->active->width != config->sb_width || console->active->height != config->sb_height)
1745
change_screen_buffer_size( console->active, config->sb_width, config->sb_height );
1746
1747
console->window->menu_mask = config->menu_mask;
1748
console->window->quick_edit = config->quick_edit;
1749
1750
console->edition_mode = config->edition_mode;
1751
console->history_mode = config->history_mode;
1752
1753
if (console->history_size != config->history_size)
1754
{
1755
struct history_line **mem = NULL;
1756
int i, delta;
1757
1758
if (config->history_size && (mem = malloc( config->history_size * sizeof(*mem) )))
1759
{
1760
memset( mem, 0, config->history_size * sizeof(*mem) );
1761
1762
delta = (console->history_index > config->history_size)
1763
? (console->history_index - config->history_size) : 0;
1764
1765
for (i = delta; i < console->history_index; i++)
1766
{
1767
mem[i - delta] = console->history[i];
1768
console->history[i] = NULL;
1769
}
1770
console->history_index -= delta;
1771
1772
for (i = 0; i < console->history_size; i++)
1773
free( console->history[i] );
1774
free( console->history );
1775
console->history = mem;
1776
console->history_size = config->history_size;
1777
}
1778
}
1779
1780
if (config->insert_mode)
1781
console->mode |= ENABLE_INSERT_MODE|ENABLE_EXTENDED_FLAGS;
1782
else
1783
console->mode &= ~ENABLE_INSERT_MODE;
1784
1785
console->active->cursor_size = config->cursor_size;
1786
console->active->cursor_visible = config->cursor_visible;
1787
console->active->attr = config->attr;
1788
console->active->popup_attr = config->popup_attr;
1789
console->active->win.left = config->win_pos.X;
1790
console->active->win.top = config->win_pos.Y;
1791
console->active->win.right = config->win_pos.X + config->win_width - 1;
1792
console->active->win.bottom = config->win_pos.Y + config->win_height - 1;
1793
memcpy( console->active->color_map, config->color_map, sizeof(config->color_map) );
1794
1795
if (console->active->font.width != config->cell_width ||
1796
console->active->font.height != config->cell_height ||
1797
console->active->font.weight != config->font_weight ||
1798
console->active->font.pitch_family != config->font_pitch_family ||
1799
console->active->font.face_len != wcslen( config->face_name ) ||
1800
memcmp( console->active->font.face_name, config->face_name,
1801
console->active->font.face_len * sizeof(WCHAR) ))
1802
{
1803
update_console_font( console, config->face_name, wcslen(config->face_name) * sizeof(WCHAR),
1804
config->cell_height, config->font_weight );
1805
}
1806
1807
update_window( console );
1808
1809
notify_screen_buffer_size( console->active );
1810
}
1811
1812
static void current_config( struct console *console, struct console_config *config )
1813
{
1814
size_t len;
1815
1816
config->menu_mask = console->window->menu_mask;
1817
config->quick_edit = console->window->quick_edit;
1818
1819
config->edition_mode = console->edition_mode;
1820
config->history_mode = console->history_mode;
1821
config->history_size = console->history_size;
1822
1823
config->insert_mode = (console->mode & (ENABLE_INSERT_MODE|ENABLE_EXTENDED_FLAGS)) ==
1824
(ENABLE_INSERT_MODE|ENABLE_EXTENDED_FLAGS);
1825
1826
config->cursor_size = console->active->cursor_size;
1827
config->cursor_visible = console->active->cursor_visible;
1828
config->attr = console->active->attr;
1829
config->popup_attr = console->active->popup_attr;
1830
memcpy( config->color_map, console->active->color_map, sizeof(config->color_map) );
1831
1832
config->cell_width = console->active->font.width;
1833
config->cell_height = console->active->font.height;
1834
config->font_weight = console->active->font.weight;
1835
config->font_pitch_family = console->active->font.pitch_family;
1836
len = min( ARRAY_SIZE(config->face_name) - 1, console->active->font.face_len );
1837
if (len) memcpy( config->face_name, console->active->font.face_name, len * sizeof(WCHAR) );
1838
config->face_name[len] = 0;
1839
1840
config->sb_width = console->active->width;
1841
config->sb_height = console->active->height;
1842
1843
config->win_width = console->active->win.right - console->active->win.left + 1;
1844
config->win_height = console->active->win.bottom - console->active->win.top + 1;
1845
config->win_pos.X = console->active->win.left;
1846
config->win_pos.Y = console->active->win.top;
1847
}
1848
1849
/* run the dialog box to set up the console options */
1850
static BOOL config_dialog( struct console *console, BOOL current )
1851
{
1852
struct console_config prev_config;
1853
struct dialog_info di;
1854
PROPSHEETHEADERW header;
1855
HPROPSHEETPAGE pages[3];
1856
PROPSHEETPAGEW psp;
1857
WNDCLASSW wndclass;
1858
WCHAR buff[256];
1859
1860
InitCommonControls();
1861
1862
memset( &di, 0, sizeof(di) );
1863
di.console = console;
1864
1865
if (current)
1866
current_config( console, &di.config );
1867
else
1868
load_config( NULL, &di.config );
1869
1870
prev_config = di.config;
1871
1872
wndclass.style = 0;
1873
wndclass.lpfnWndProc = font_preview_proc;
1874
wndclass.cbClsExtra = 0;
1875
wndclass.cbWndExtra = sizeof(HFONT);
1876
wndclass.hInstance = GetModuleHandleW( NULL );
1877
wndclass.hIcon = 0;
1878
wndclass.hCursor = LoadCursorW( 0, (const WCHAR *)IDC_ARROW );
1879
wndclass.hbrBackground = GetStockObject( BLACK_BRUSH );
1880
wndclass.lpszMenuName = NULL;
1881
wndclass.lpszClassName = L"WineConFontPreview";
1882
RegisterClassW( &wndclass );
1883
1884
wndclass.style = 0;
1885
wndclass.lpfnWndProc = color_preview_proc;
1886
wndclass.cbClsExtra = 0;
1887
wndclass.cbWndExtra = sizeof(DWORD);
1888
wndclass.hInstance = GetModuleHandleW( NULL );
1889
wndclass.hIcon = 0;
1890
wndclass.hCursor = LoadCursorW( 0, (const WCHAR *)IDC_ARROW );
1891
wndclass.hbrBackground = GetStockObject( BLACK_BRUSH );
1892
wndclass.lpszMenuName = NULL;
1893
wndclass.lpszClassName = L"WineConColorPreview";
1894
RegisterClassW( &wndclass );
1895
1896
memset( &psp, 0, sizeof(psp) );
1897
psp.dwSize = sizeof(psp);
1898
psp.dwFlags = 0;
1899
psp.hInstance = wndclass.hInstance;
1900
psp.lParam = (LPARAM)&di;
1901
1902
psp.pszTemplate = MAKEINTRESOURCEW(IDD_OPTION);
1903
psp.pfnDlgProc = option_dialog_proc;
1904
pages[0] = CreatePropertySheetPageW( &psp );
1905
1906
psp.pszTemplate = MAKEINTRESOURCEW(IDD_FONT);
1907
psp.pfnDlgProc = font_dialog_proc;
1908
pages[1] = CreatePropertySheetPageW( &psp );
1909
1910
psp.pszTemplate = MAKEINTRESOURCEW(IDD_CONFIG);
1911
psp.pfnDlgProc = config_dialog_proc;
1912
pages[2] = CreatePropertySheetPageW( &psp );
1913
1914
memset( &header, 0, sizeof(header) );
1915
header.dwSize = sizeof(header);
1916
1917
if (!LoadStringW( GetModuleHandleW( NULL ),
1918
current ? IDS_DLG_TIT_CURRENT : IDS_DLG_TIT_DEFAULT,
1919
buff, ARRAY_SIZE(buff) ))
1920
wcscpy( buff, L"Setup" );
1921
1922
header.pszCaption = buff;
1923
header.nPages = 3;
1924
header.hwndParent = console->win;
1925
header.phpage = pages;
1926
header.dwFlags = PSH_NOAPPLYNOW;
1927
if (PropertySheetW( &header ) < 1)
1928
return TRUE;
1929
1930
if (!memcmp( &prev_config, &di.config, sizeof(prev_config) ))
1931
return TRUE;
1932
1933
TRACE( "%s\n", debugstr_config(&di.config) );
1934
1935
if (current)
1936
{
1937
apply_config( console, &di.config );
1938
update_window( di.console );
1939
}
1940
1941
save_config( current ? console->window->config_key : NULL, &di.config );
1942
1943
return TRUE;
1944
}
1945
1946
static void resize_window( struct console *console, int width, int height )
1947
{
1948
struct console_config config;
1949
1950
current_config( console, &config );
1951
config.win_width = width;
1952
config.win_height = height;
1953
1954
/* auto size screen-buffer if it's now smaller than window */
1955
if (config.sb_width < config.win_width)
1956
config.sb_width = config.win_width;
1957
if (config.sb_height < config.win_height)
1958
config.sb_height = config.win_height;
1959
1960
/* and reset window pos so that we don't display outside of the screen-buffer */
1961
if (config.win_pos.X + config.win_width > config.sb_width)
1962
config.win_pos.X = config.sb_width - config.win_width;
1963
if (config.win_pos.Y + config.win_height > config.sb_height)
1964
config.win_pos.Y = config.sb_height - config.win_height;
1965
1966
apply_config( console, &config );
1967
}
1968
1969
/* grays / ungrays the menu items according to their state */
1970
static void set_menu_details( struct console *console, HMENU menu )
1971
{
1972
EnableMenuItem( menu, IDS_COPY, MF_BYCOMMAND |
1973
(console->window->in_selection ? MF_ENABLED : MF_GRAYED) );
1974
EnableMenuItem( menu, IDS_PASTE, MF_BYCOMMAND |
1975
(IsClipboardFormatAvailable(CF_UNICODETEXT) ? MF_ENABLED : MF_GRAYED) );
1976
EnableMenuItem( menu, IDS_SCROLL, MF_BYCOMMAND | MF_GRAYED );
1977
EnableMenuItem( menu, IDS_SEARCH, MF_BYCOMMAND | MF_GRAYED );
1978
}
1979
1980
static BOOL fill_menu( HMENU menu, BOOL sep )
1981
{
1982
HINSTANCE module = GetModuleHandleW( NULL );
1983
HMENU sub_menu;
1984
WCHAR buff[256];
1985
1986
if (!menu) return FALSE;
1987
1988
sub_menu = CreateMenu();
1989
if (!sub_menu) return FALSE;
1990
1991
LoadStringW( module, IDS_MARK, buff, ARRAY_SIZE(buff) );
1992
InsertMenuW( sub_menu, -1, MF_BYPOSITION|MF_STRING, IDS_MARK, buff );
1993
LoadStringW( module, IDS_COPY, buff, ARRAY_SIZE(buff) );
1994
InsertMenuW( sub_menu, -1, MF_BYPOSITION|MF_STRING, IDS_COPY, buff );
1995
LoadStringW( module, IDS_PASTE, buff, ARRAY_SIZE(buff) );
1996
InsertMenuW( sub_menu, -1, MF_BYPOSITION|MF_STRING, IDS_PASTE, buff );
1997
LoadStringW( module, IDS_SELECTALL, buff, ARRAY_SIZE(buff) );
1998
InsertMenuW( sub_menu, -1, MF_BYPOSITION|MF_STRING, IDS_SELECTALL, buff );
1999
LoadStringW( module, IDS_SCROLL, buff, ARRAY_SIZE(buff) );
2000
InsertMenuW( sub_menu, -1, MF_BYPOSITION|MF_STRING, IDS_SCROLL, buff );
2001
LoadStringW( module, IDS_SEARCH, buff, ARRAY_SIZE(buff) );
2002
InsertMenuW( sub_menu, -1, MF_BYPOSITION|MF_STRING, IDS_SEARCH, buff );
2003
2004
if (sep) InsertMenuW( menu, -1, MF_BYPOSITION|MF_SEPARATOR, 0, NULL );
2005
LoadStringW( module, IDS_EDIT, buff, ARRAY_SIZE(buff) );
2006
InsertMenuW( menu, -1, MF_BYPOSITION|MF_STRING|MF_POPUP, (UINT_PTR)sub_menu, buff );
2007
LoadStringW( module, IDS_DEFAULT, buff, ARRAY_SIZE(buff) );
2008
InsertMenuW( menu, -1, MF_BYPOSITION|MF_STRING, IDS_DEFAULT, buff );
2009
LoadStringW( module, IDS_PROPERTIES, buff, ARRAY_SIZE(buff) );
2010
InsertMenuW( menu, -1, MF_BYPOSITION|MF_STRING, IDS_PROPERTIES, buff );
2011
2012
return TRUE;
2013
}
2014
2015
static LRESULT window_create( HWND hwnd, const CREATESTRUCTW *create )
2016
{
2017
struct console *console = create->lpCreateParams;
2018
HMENU sys_menu;
2019
2020
TRACE( "%p\n", hwnd );
2021
2022
SetWindowLongPtrW( hwnd, 0, (DWORD_PTR)console );
2023
console->win = hwnd;
2024
2025
if (console->window)
2026
{
2027
sys_menu = GetSystemMenu( hwnd, FALSE );
2028
if (!sys_menu) return 0;
2029
console->window->popup_menu = CreatePopupMenu();
2030
if (!console->window->popup_menu) return 0;
2031
2032
fill_menu( sys_menu, TRUE );
2033
fill_menu( console->window->popup_menu, FALSE );
2034
2035
console->window->mem_dc = CreateCompatibleDC( 0 );
2036
}
2037
return 0;
2038
}
2039
2040
static LRESULT WINAPI window_proc( HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam )
2041
{
2042
struct console *console = (struct console *)GetWindowLongPtrW( hwnd, 0 );
2043
2044
switch (msg)
2045
{
2046
case WM_CREATE:
2047
return window_create( hwnd, (const CREATESTRUCTW *)lparam );
2048
2049
case WM_DESTROY:
2050
console->win = NULL;
2051
PostQuitMessage( 0 );
2052
break;
2053
2054
case WM_TIMER:
2055
case WM_UPDATE_CONFIG:
2056
if (console->window && console->window->update_state == UPDATE_PENDING)
2057
update_window( console );
2058
break;
2059
2060
case WM_PAINT:
2061
{
2062
PAINTSTRUCT ps;
2063
2064
if (!console->window) break;
2065
2066
BeginPaint( console->win, &ps );
2067
BitBlt( ps.hdc, 0, 0,
2068
(console->active->win.right - console->active->win.left + 1) * console->active->font.width,
2069
(console->active->win.bottom - console->active->win.top + 1) * console->active->font.height,
2070
console->window->mem_dc,
2071
console->active->win.left * console->active->font.width,
2072
console->active->win.top * console->active->font.height,
2073
SRCCOPY );
2074
if (console->window->in_selection) update_selection( console, ps.hdc );
2075
EndPaint( console->win, &ps );
2076
break;
2077
}
2078
2079
case WM_SHOWWINDOW:
2080
if (!console->window) break;
2081
if (wparam)
2082
update_window( console );
2083
else
2084
{
2085
if (console->window->bitmap) DeleteObject( console->window->bitmap );
2086
console->window->bitmap = NULL;
2087
}
2088
break;
2089
2090
case WM_KEYDOWN:
2091
case WM_KEYUP:
2092
if (console->window && console->window->in_selection)
2093
handle_selection_key( console, msg == WM_KEYDOWN, wparam, lparam );
2094
else
2095
record_key_input( console, msg == WM_KEYDOWN, wparam, lparam );
2096
break;
2097
2098
case WM_SYSKEYDOWN:
2099
case WM_SYSKEYUP:
2100
record_key_input( console, msg == WM_SYSKEYDOWN, wparam, lparam );
2101
break;
2102
2103
case WM_CHAR:
2104
if (console->window && console->window->in_selection)
2105
handle_selection_key( console, TRUE, LOBYTE( VkKeyScanW( (WCHAR)wparam ) ), lparam );
2106
else
2107
record_char_input( console, (WCHAR)wparam, lparam );
2108
break;
2109
2110
case WM_LBUTTONDOWN:
2111
if (console->window && (console->window->quick_edit || console->window->in_selection))
2112
{
2113
if (console->window->in_selection)
2114
update_selection( console, 0 );
2115
2116
if (console->window->quick_edit && console->window->in_selection)
2117
{
2118
console->window->in_selection = FALSE;
2119
}
2120
else
2121
{
2122
console->window->selection_end = get_cell( console, lparam );
2123
console->window->selection_start = console->window->selection_end;
2124
SetCapture( console->win );
2125
update_selection( console, 0 );
2126
console->window->in_selection = TRUE;
2127
}
2128
}
2129
else
2130
{
2131
record_mouse_input( console, get_cell(console, lparam), wparam, 0 );
2132
}
2133
break;
2134
2135
case WM_MOUSEMOVE:
2136
if (console->window && (console->window->quick_edit || console->window->in_selection))
2137
{
2138
if (GetCapture() == console->win && console->window->in_selection &&
2139
(wparam & MK_LBUTTON))
2140
{
2141
move_selection( console, console->window->selection_start,
2142
get_cell(console, lparam) );
2143
}
2144
}
2145
else
2146
{
2147
record_mouse_input( console, get_cell(console, lparam), wparam, MOUSE_MOVED );
2148
}
2149
break;
2150
2151
case WM_LBUTTONUP:
2152
if (console->window && (console->window->quick_edit || console->window->in_selection))
2153
{
2154
if (GetCapture() == console->win && console->window->in_selection)
2155
{
2156
move_selection( console, console->window->selection_start,
2157
get_cell(console, lparam) );
2158
ReleaseCapture();
2159
}
2160
}
2161
else
2162
{
2163
record_mouse_input( console, get_cell(console, lparam), wparam, 0 );
2164
}
2165
break;
2166
2167
case WM_RBUTTONDOWN:
2168
if (console->window && (wparam & (MK_CONTROL|MK_SHIFT)) == console->window->menu_mask)
2169
{
2170
POINT pt;
2171
pt.x = (short)LOWORD(lparam);
2172
pt.y = (short)HIWORD(lparam);
2173
ClientToScreen( hwnd, &pt );
2174
set_menu_details( console, console->window->popup_menu );
2175
TrackPopupMenu( console->window->popup_menu, TPM_LEFTALIGN|TPM_TOPALIGN|TPM_RIGHTBUTTON,
2176
pt.x, pt.y, 0, hwnd, NULL );
2177
}
2178
else
2179
{
2180
record_mouse_input( console, get_cell(console, lparam), wparam, 0 );
2181
}
2182
break;
2183
2184
case WM_RBUTTONUP:
2185
/* no need to track for rbutton up when opening the popup... the event will be
2186
* swallowed by TrackPopupMenu */
2187
case WM_MBUTTONDOWN:
2188
case WM_MBUTTONUP:
2189
record_mouse_input( console, get_cell(console, lparam), wparam, 0 );
2190
break;
2191
2192
case WM_LBUTTONDBLCLK:
2193
case WM_MBUTTONDBLCLK:
2194
case WM_RBUTTONDBLCLK:
2195
record_mouse_input( console, get_cell(console, lparam), wparam, DOUBLE_CLICK );
2196
break;
2197
2198
case WM_SETFOCUS:
2199
if (console->window && console->active->cursor_visible)
2200
{
2201
CreateCaret( console->win, console->window->cursor_bitmap,
2202
console->active->font.width, console->active->font.height );
2203
update_window_cursor( console );
2204
}
2205
break;
2206
2207
case WM_KILLFOCUS:
2208
if (console->window && console->active->cursor_visible)
2209
DestroyCaret();
2210
break;
2211
2212
case WM_SIZE:
2213
if (console->window && console->window->update_state != UPDATE_BUSY)
2214
resize_window( console,
2215
max( LOWORD(lparam) / console->active->font.width, 20 ),
2216
max( HIWORD(lparam) / console->active->font.height, 20 ));
2217
break;
2218
2219
case WM_HSCROLL:
2220
{
2221
int win_width = console->active->win.right - console->active->win.left + 1;
2222
int x = console->active->win.left;
2223
2224
if (!console->window) break;
2225
switch (LOWORD(wparam))
2226
{
2227
case SB_PAGEUP: x -= 8; break;
2228
case SB_PAGEDOWN: x += 8; break;
2229
case SB_LINEUP: x--; break;
2230
case SB_LINEDOWN: x++; break;
2231
case SB_THUMBTRACK: x = HIWORD(wparam); break;
2232
default: break;
2233
}
2234
x = min( max( x, 0 ), console->active->width - win_width );
2235
if (x != console->active->win.left)
2236
{
2237
console->active->win.left = x;
2238
console->active->win.right = x + win_width - 1;
2239
update_window( console );
2240
}
2241
break;
2242
}
2243
2244
case WM_MOUSEWHEEL:
2245
if (console->active->height <= console->active->win.bottom - console->active->win.top + 1)
2246
{
2247
record_mouse_input(console, get_cell(console, lparam), wparam, MOUSE_WHEELED);
2248
break;
2249
}
2250
/* else fallthrough */
2251
case WM_VSCROLL:
2252
{
2253
int win_height = console->active->win.bottom - console->active->win.top + 1;
2254
int y = console->active->win.top;
2255
2256
if (!console->window) break;
2257
2258
if (msg == WM_MOUSEWHEEL)
2259
{
2260
UINT scroll_lines = 3;
2261
SystemParametersInfoW( SPI_GETWHEELSCROLLLINES, 0, &scroll_lines, 0 );
2262
scroll_lines *= -GET_WHEEL_DELTA_WPARAM(wparam) / WHEEL_DELTA;
2263
y += scroll_lines;
2264
}
2265
else
2266
{
2267
switch (LOWORD(wparam))
2268
{
2269
case SB_PAGEUP: y -= 8; break;
2270
case SB_PAGEDOWN: y += 8; break;
2271
case SB_LINEUP: y--; break;
2272
case SB_LINEDOWN: y++; break;
2273
case SB_THUMBTRACK: y = HIWORD(wparam); break;
2274
default: break;
2275
}
2276
}
2277
2278
y = min( max( y, 0 ), console->active->height - win_height );
2279
if (y != console->active->win.top)
2280
{
2281
console->active->win.top = y;
2282
console->active->win.bottom = y + win_height - 1;
2283
update_window( console );
2284
}
2285
break;
2286
}
2287
2288
case WM_SYSCOMMAND:
2289
if (!console->window) break;
2290
switch (wparam)
2291
{
2292
case IDS_DEFAULT:
2293
config_dialog( console, FALSE );
2294
break;
2295
case IDS_PROPERTIES:
2296
config_dialog( console, TRUE );
2297
break;
2298
default:
2299
return DefWindowProcW( hwnd, msg, wparam, lparam );
2300
}
2301
break;
2302
2303
case WM_COMMAND:
2304
if (!console->window) break;
2305
switch (wparam)
2306
{
2307
case IDS_DEFAULT:
2308
config_dialog( console, FALSE );
2309
break;
2310
case IDS_PROPERTIES:
2311
config_dialog( console, TRUE );
2312
break;
2313
case IDS_MARK:
2314
console->window->selection_start.X = console->window->selection_start.Y = 0;
2315
console->window->selection_end.X = console->window->selection_end.Y = 0;
2316
update_selection( console, 0 );
2317
console->window->in_selection = TRUE;
2318
break;
2319
case IDS_COPY:
2320
if (console->window->in_selection)
2321
{
2322
console->window->in_selection = FALSE;
2323
update_selection( console, 0 );
2324
copy_selection( console );
2325
}
2326
break;
2327
case IDS_PASTE:
2328
paste_clipboard( console );
2329
break;
2330
case IDS_SELECTALL:
2331
console->window->selection_start.X = console->window->selection_start.Y = 0;
2332
console->window->selection_end.X = console->active->width - 1;
2333
console->window->selection_end.Y = console->active->height - 1;
2334
update_selection( console, 0 );
2335
console->window->in_selection = TRUE;
2336
break;
2337
case IDS_SCROLL:
2338
case IDS_SEARCH:
2339
FIXME( "Unhandled yet command: %Ix\n", wparam );
2340
break;
2341
default:
2342
return DefWindowProcW( hwnd, msg, wparam, lparam );
2343
}
2344
break;
2345
2346
case WM_INITMENUPOPUP:
2347
if (!console->window || !HIWORD(lparam)) return DefWindowProcW( hwnd, msg, wparam, lparam );
2348
set_menu_details( console, GetSystemMenu(console->win, FALSE) );
2349
break;
2350
2351
default:
2352
return DefWindowProcW( hwnd, msg, wparam, lparam );
2353
}
2354
2355
return 0;
2356
}
2357
2358
void update_window_config( struct console *console, BOOL delay )
2359
{
2360
const int delay_timeout = 50;
2361
2362
if (!console->window || console->window->update_state != UPDATE_NONE) return;
2363
console->window->update_state = UPDATE_PENDING;
2364
if (delay)
2365
SetTimer( console->win, 1, delay_timeout, NULL );
2366
else
2367
PostMessageW( console->win, WM_UPDATE_CONFIG, 0, 0 );
2368
}
2369
2370
void update_window_region( struct console *console, const RECT *update )
2371
{
2372
RECT *window_rect = &console->window->update;
2373
window_rect->left = min( window_rect->left, update->left );
2374
window_rect->top = min( window_rect->top, update->top );
2375
window_rect->right = max( window_rect->right, update->right );
2376
window_rect->bottom = max( window_rect->bottom, update->bottom );
2377
update_window_config( console, TRUE );
2378
}
2379
2380
BOOL init_window( struct console *console )
2381
{
2382
struct console_config config;
2383
WNDCLASSW wndclass;
2384
STARTUPINFOW si;
2385
CHARSETINFO ci;
2386
2387
static struct console_window console_window;
2388
2389
console->window = &console_window;
2390
if (!TranslateCharsetInfo( (DWORD *)(INT_PTR)GetACP(), &ci, TCI_SRCCODEPAGE ))
2391
return FALSE;
2392
2393
console->window->ui_charset = ci.ciCharset;
2394
2395
GetStartupInfoW(&si);
2396
if (si.lpTitle)
2397
{
2398
size_t i, title_len = wcslen( si.lpTitle );
2399
if (!(console->window->config_key = malloc( (title_len + 1) * sizeof(WCHAR) )))
2400
return FALSE;
2401
for (i = 0; i < title_len; i++)
2402
console->window->config_key[i] = si.lpTitle[i] == '\\' ? '_' : si.lpTitle[i];
2403
console->window->config_key[title_len] = 0;
2404
}
2405
2406
load_config( console->window->config_key, &config );
2407
if (si.dwFlags & STARTF_USECOUNTCHARS)
2408
{
2409
config.sb_width = si.dwXCountChars;
2410
config.sb_height = si.dwYCountChars;
2411
}
2412
if (si.dwFlags & STARTF_USEFILLATTRIBUTE)
2413
config.attr = si.dwFillAttribute;
2414
2415
wndclass.style = CS_DBLCLKS;
2416
wndclass.lpfnWndProc = window_proc;
2417
wndclass.cbClsExtra = 0;
2418
wndclass.cbWndExtra = sizeof(DWORD_PTR);
2419
wndclass.hInstance = GetModuleHandleW(NULL);
2420
wndclass.hIcon = LoadIconW( 0, (const WCHAR *)IDI_WINLOGO );
2421
wndclass.hCursor = LoadCursorW( 0, (const WCHAR *)IDC_ARROW );
2422
wndclass.hbrBackground = GetStockObject( BLACK_BRUSH );
2423
wndclass.lpszMenuName = NULL;
2424
wndclass.lpszClassName = L"WineConsoleClass";
2425
RegisterClassW(&wndclass);
2426
2427
if (!CreateWindowW( wndclass.lpszClassName, NULL,
2428
WS_OVERLAPPED|WS_CAPTION|WS_SYSMENU|WS_THICKFRAME|WS_MINIMIZEBOX|
2429
WS_MAXIMIZEBOX|WS_HSCROLL|WS_VSCROLL, CW_USEDEFAULT, CW_USEDEFAULT,
2430
0, 0, 0, 0, wndclass.hInstance, console ))
2431
return FALSE;
2432
2433
if (!config.face_name[0])
2434
set_first_font( console, &config );
2435
2436
apply_config( console, &config );
2437
return TRUE;
2438
}
2439
2440
void init_message_window( struct console *console )
2441
{
2442
WNDCLASSW wndclass;
2443
2444
wndclass.style = CS_DBLCLKS;
2445
wndclass.lpfnWndProc = window_proc;
2446
wndclass.cbClsExtra = 0;
2447
wndclass.cbWndExtra = sizeof(DWORD_PTR);
2448
wndclass.hInstance = GetModuleHandleW( NULL );
2449
wndclass.hIcon = 0;
2450
wndclass.hCursor = 0;
2451
wndclass.hbrBackground = GetStockObject( BLACK_BRUSH );
2452
wndclass.lpszMenuName = NULL;
2453
wndclass.lpszClassName = L"WineConsoleClass";
2454
RegisterClassW(&wndclass);
2455
2456
CreateWindowW( wndclass.lpszClassName, NULL,
2457
WS_OVERLAPPED|WS_CAPTION|WS_SYSMENU|WS_THICKFRAME|WS_MINIMIZEBOX|
2458
WS_MAXIMIZEBOX|WS_HSCROLL|WS_VSCROLL, CW_USEDEFAULT, CW_USEDEFAULT,
2459
0, 0, HWND_MESSAGE, 0, wndclass.hInstance, console );
2460
}
2461
2462