2 * a GUI application for displaying a console
4 * Copyright 2001 Eric Pouech
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2.1 of the License, or (at your option) any later version.
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with this library; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
23 #include "winecon_user.h"
26 #include "wine/debug.h"
28 WINE_DEFAULT_DEBUG_CHANNEL(wineconsole
);
29 WINE_DECLARE_DEBUG_CHANNEL(wc_font
);
31 UINT g_uiDefaultCharset
;
33 /* mapping console colors to RGB values */
34 const COLORREF WCUSER_ColorMap
[16] =
36 RGB(0x00, 0x00, 0x00), RGB(0x00, 0x00, 0x80), RGB(0x00, 0x80, 0x00), RGB(0x00, 0x80, 0x80),
37 RGB(0x80, 0x00, 0x00), RGB(0x80, 0x00, 0x80), RGB(0x80, 0x80, 0x00), RGB(0xC0, 0xC0, 0xC0),
38 RGB(0x80, 0x80, 0x80), RGB(0x00, 0x00, 0xFF), RGB(0x00, 0xFF, 0x00), RGB(0x00, 0xFF, 0xFF),
39 RGB(0xFF, 0x00, 0x00), RGB(0xFF, 0x00, 0xFF), RGB(0xFF, 0xFF, 0x00), RGB(0xFF, 0xFF, 0xFF),
42 static BOOL
WCUSER_SetFont(struct inner_data
* data
, const LOGFONTW
* font
);
44 /******************************************************************
47 * Fills the Mem DC with current cells values
49 static void WCUSER_FillMemDC(const struct inner_data
* data
, int upd_tp
, int upd_bm
)
60 /* no font has been set up yet, don't worry about filling the bitmap,
61 * we'll do it once a font is chosen
63 if (!PRIVATE(data
)->hFont
) return;
65 /* FIXME: could set up a mechanism to reuse the line between different
66 * calls to this function
68 if (!(line
= HeapAlloc(GetProcessHeap(), 0, data
->curcfg
.sb_width
* sizeof(WCHAR
))))
69 WINECON_Fatal("OOM\n");
70 dx
= HeapAlloc( GetProcessHeap(), 0, data
->curcfg
.sb_width
* sizeof(*dx
) );
72 hOldFont
= SelectObject(PRIVATE(data
)->hMemDC
, PRIVATE(data
)->hFont
);
73 for (j
= upd_tp
; j
<= upd_bm
; j
++)
75 cell
= &data
->cells
[j
* data
->curcfg
.sb_width
];
76 for (i
= 0; i
< data
->curcfg
.sb_width
; i
++)
78 attr
= cell
[i
].Attributes
;
79 SetBkColor(PRIVATE(data
)->hMemDC
, WCUSER_ColorMap
[(attr
>>4)&0x0F]);
80 SetTextColor(PRIVATE(data
)->hMemDC
, WCUSER_ColorMap
[attr
&0x0F]);
81 for (k
= i
; k
< data
->curcfg
.sb_width
&& cell
[k
].Attributes
== attr
; k
++)
83 line
[k
- i
] = cell
[k
].Char
.UnicodeChar
;
84 dx
[k
- i
] = data
->curcfg
.cell_width
;
86 ExtTextOutW( PRIVATE(data
)->hMemDC
, i
* data
->curcfg
.cell_width
, j
* data
->curcfg
.cell_height
,
87 0, NULL
, line
, k
- i
, dx
);
88 if (PRIVATE(data
)->ext_leading
&&
89 (hbr
= CreateSolidBrush(WCUSER_ColorMap
[(attr
>>4)&0x0F])))
91 r
.left
= i
* data
->curcfg
.cell_width
;
92 r
.top
= (j
+ 1) * data
->curcfg
.cell_height
- PRIVATE(data
)->ext_leading
;
93 r
.right
= k
* data
->curcfg
.cell_width
;
94 r
.bottom
= (j
+ 1) * data
->curcfg
.cell_height
;
95 FillRect(PRIVATE(data
)->hMemDC
, &r
, hbr
);
101 SelectObject(PRIVATE(data
)->hMemDC
, hOldFont
);
102 HeapFree(GetProcessHeap(), 0, dx
);
103 HeapFree(GetProcessHeap(), 0, line
);
106 /******************************************************************
109 * Either the font geometry or the sb geometry has changed. we need
110 * to recreate the bitmap geometry.
112 static void WCUSER_NewBitmap(struct inner_data
* data
)
117 if (!data
->curcfg
.sb_width
|| !data
->curcfg
.sb_height
||
118 !PRIVATE(data
)->hFont
|| !(hDC
= GetDC(data
->hWnd
)))
120 hnew
= CreateCompatibleBitmap(hDC
,
121 data
->curcfg
.sb_width
* data
->curcfg
.cell_width
,
122 data
->curcfg
.sb_height
* data
->curcfg
.cell_height
);
123 ReleaseDC(data
->hWnd
, hDC
);
124 hold
= SelectObject(PRIVATE(data
)->hMemDC
, hnew
);
126 if (PRIVATE(data
)->hBitmap
)
128 if (hold
== PRIVATE(data
)->hBitmap
)
129 DeleteObject(PRIVATE(data
)->hBitmap
);
131 WINE_FIXME("leak\n");
133 PRIVATE(data
)->hBitmap
= hnew
;
134 WCUSER_FillMemDC(data
, 0, data
->curcfg
.sb_height
- 1);
137 /******************************************************************
138 * WCUSER_ResizeScreenBuffer
142 static void WCUSER_ResizeScreenBuffer(struct inner_data
* data
)
144 WCUSER_NewBitmap(data
);
147 /******************************************************************
150 * Set a new position for the cursor
152 static void WCUSER_PosCursor(const struct inner_data
* data
)
154 if (data
->hWnd
!= GetFocus() || !data
->curcfg
.cursor_visible
) return;
156 SetCaretPos((data
->cursor
.X
- data
->curcfg
.win_pos
.X
) * data
->curcfg
.cell_width
,
157 (data
->cursor
.Y
- data
->curcfg
.win_pos
.Y
) * data
->curcfg
.cell_height
);
158 ShowCaret(data
->hWnd
);
161 /******************************************************************
164 * Sets a new shape for the cursor
166 static void WCUSER_ShapeCursor(struct inner_data
* data
, int size
, int vis
, BOOL force
)
168 if (force
|| size
!= data
->curcfg
.cursor_size
)
170 if (data
->curcfg
.cursor_visible
&& data
->hWnd
== GetFocus()) DestroyCaret();
171 if (PRIVATE(data
)->cursor_bitmap
) DeleteObject(PRIVATE(data
)->cursor_bitmap
);
172 PRIVATE(data
)->cursor_bitmap
= NULL
;
175 int w16b
; /* number of bytes per row, aligned on word size */
179 w16b
= ((data
->curcfg
.cell_width
+ 15) & ~15) / 8;
180 ptr
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, w16b
* data
->curcfg
.cell_height
);
181 if (!ptr
) WINECON_Fatal("OOM");
182 nbl
= max((data
->curcfg
.cell_height
* size
) / 100, 1);
183 for (j
= data
->curcfg
.cell_height
- nbl
; j
< data
->curcfg
.cell_height
; j
++)
185 for (i
= 0; i
< data
->curcfg
.cell_width
; i
++)
187 ptr
[w16b
* j
+ (i
/ 8)] |= 0x80 >> (i
& 7);
190 PRIVATE(data
)->cursor_bitmap
= CreateBitmap(data
->curcfg
.cell_width
,
191 data
->curcfg
.cell_height
, 1, 1, ptr
);
192 HeapFree(GetProcessHeap(), 0, ptr
);
194 data
->curcfg
.cursor_size
= size
;
195 data
->curcfg
.cursor_visible
= -1;
199 if (force
|| vis
!= data
->curcfg
.cursor_visible
)
201 data
->curcfg
.cursor_visible
= vis
;
202 if (data
->hWnd
== GetFocus())
206 CreateCaret(data
->hWnd
, PRIVATE(data
)->cursor_bitmap
,
207 data
->curcfg
.cell_width
, data
->curcfg
.cell_height
);
208 WCUSER_PosCursor(data
);
216 WINECON_DumpConfig("crsr", &data
->curcfg
);
219 /******************************************************************
220 * WCUSER_ComputePositions
222 * Recomputes all the components (mainly scroll bars) positions
224 static void WCUSER_ComputePositions(struct inner_data
* data
)
229 /* compute window size from desired client size */
231 r
.right
= data
->curcfg
.win_width
* data
->curcfg
.cell_width
;
232 r
.bottom
= data
->curcfg
.win_height
* data
->curcfg
.cell_height
;
234 if (IsRectEmpty(&r
)) return;
236 AdjustWindowRect(&r
, GetWindowLongW(data
->hWnd
, GWL_STYLE
), FALSE
);
239 if (data
->curcfg
.sb_width
> data
->curcfg
.win_width
)
241 dy
= GetSystemMetrics(SM_CYHSCROLL
);
242 SetScrollRange(data
->hWnd
, SB_HORZ
, 0,
243 data
->curcfg
.sb_width
- data
->curcfg
.win_width
, FALSE
);
244 SetScrollPos(data
->hWnd
, SB_HORZ
, 0, FALSE
); /* FIXME */
245 ShowScrollBar(data
->hWnd
, SB_HORZ
, TRUE
);
249 ShowScrollBar(data
->hWnd
, SB_HORZ
, FALSE
);
252 if (data
->curcfg
.sb_height
> data
->curcfg
.win_height
)
254 dx
= GetSystemMetrics(SM_CXVSCROLL
);
255 SetScrollRange(data
->hWnd
, SB_VERT
, 0,
256 data
->curcfg
.sb_height
- data
->curcfg
.win_height
, FALSE
);
257 SetScrollPos(data
->hWnd
, SB_VERT
, 0, FALSE
); /* FIXME */
258 ShowScrollBar(data
->hWnd
, SB_VERT
, TRUE
);
262 ShowScrollBar(data
->hWnd
, SB_VERT
, FALSE
);
265 SetWindowPos(data
->hWnd
, 0, 0, 0, r
.right
- r
.left
+ dx
, r
.bottom
- r
.top
+ dy
,
266 SWP_NOMOVE
|SWP_NOZORDER
);
267 WCUSER_ShapeCursor(data
, data
->curcfg
.cursor_size
, data
->curcfg
.cursor_visible
, TRUE
);
268 WCUSER_PosCursor(data
);
271 /******************************************************************
274 * Sets the title to the wine console
276 static void WCUSER_SetTitle(const struct inner_data
* data
)
280 if (WINECON_GetConsoleTitle(data
->hConIn
, buffer
, sizeof(buffer
)))
281 SetWindowTextW(data
->hWnd
, buffer
);
284 void WCUSER_DumpLogFont(const char* pfx
, const LOGFONTW
* lf
, DWORD ft
)
286 WINE_TRACE_(wc_font
)("%s %s%s%s%s\n"
287 "\tlf.lfHeight=%d lf.lfWidth=%d lf.lfEscapement=%d lf.lfOrientation=%d\n"
288 "\tlf.lfWeight=%d lf.lfItalic=%u lf.lfUnderline=%u lf.lfStrikeOut=%u\n"
289 "\tlf.lfCharSet=%u lf.lfOutPrecision=%u lf.lfClipPrecision=%u lf.lfQuality=%u\n"
290 "\tlf->lfPitchAndFamily=%u lf.lfFaceName=%s\n",
292 (ft
& RASTER_FONTTYPE
) ? "raster" : "",
293 (ft
& TRUETYPE_FONTTYPE
) ? "truetype" : "",
294 ((ft
& (RASTER_FONTTYPE
|TRUETYPE_FONTTYPE
)) == 0) ? "vector" : "",
295 (ft
& DEVICE_FONTTYPE
) ? "|device" : "",
296 lf
->lfHeight
, lf
->lfWidth
, lf
->lfEscapement
, lf
->lfOrientation
,
297 lf
->lfWeight
, lf
->lfItalic
, lf
->lfUnderline
, lf
->lfStrikeOut
, lf
->lfCharSet
,
298 lf
->lfOutPrecision
, lf
->lfClipPrecision
, lf
->lfQuality
, lf
->lfPitchAndFamily
,
299 wine_dbgstr_w(lf
->lfFaceName
));
302 void WCUSER_DumpTextMetric(const TEXTMETRICW
* tm
, DWORD ft
)
304 WINE_TRACE_(wc_font
)("%s%s%s%s\n"
305 "\ttmHeight=%d tmAscent=%d tmDescent=%d tmInternalLeading=%d tmExternalLeading=%d\n"
306 "\ttmAveCharWidth=%d tmMaxCharWidth=%d tmWeight=%d tmOverhang=%d\n"
307 "\ttmDigitizedAspectX=%d tmDigitizedAspectY=%d\n"
308 "\ttmFirstChar=%d tmLastChar=%d tmDefaultChar=%d tmBreakChar=%d\n"
309 "\ttmItalic=%u tmUnderlined=%u tmStruckOut=%u tmPitchAndFamily=%u tmCharSet=%u\n",
310 (ft
& RASTER_FONTTYPE
) ? "raster" : "",
311 (ft
& TRUETYPE_FONTTYPE
) ? "truetype" : "",
312 ((ft
& (RASTER_FONTTYPE
|TRUETYPE_FONTTYPE
)) == 0) ? "vector" : "",
313 (ft
& DEVICE_FONTTYPE
) ? "|device" : "",
314 tm
->tmHeight
, tm
->tmAscent
, tm
->tmDescent
, tm
->tmInternalLeading
, tm
->tmExternalLeading
, tm
->tmAveCharWidth
,
315 tm
->tmMaxCharWidth
, tm
->tmWeight
, tm
->tmOverhang
, tm
->tmDigitizedAspectX
, tm
->tmDigitizedAspectY
,
316 tm
->tmFirstChar
, tm
->tmLastChar
, tm
->tmDefaultChar
, tm
->tmBreakChar
, tm
->tmItalic
, tm
->tmUnderlined
, tm
->tmStruckOut
,
317 tm
->tmPitchAndFamily
, tm
->tmCharSet
);
320 /******************************************************************
321 * WCUSER_AreFontsEqual
325 static BOOL
WCUSER_AreFontsEqual(const struct config_data
* config
, const LOGFONTW
* lf
)
327 return lf
->lfHeight
== config
->cell_height
&&
328 lf
->lfWeight
== config
->font_weight
&&
329 !lf
->lfItalic
&& !lf
->lfUnderline
&& !lf
->lfStrikeOut
&&
330 !lstrcmpW(lf
->lfFaceName
, config
->face_name
);
335 struct inner_data
* data
;
336 BOOL check_screen_size
;
340 /******************************************************************
341 * WCUSER_ValidateFontMetric
343 * Returns true if the font described in tm is usable as a font for the renderer
345 BOOL
WCUSER_ValidateFontMetric(const struct inner_data
* data
, const TEXTMETRICW
* tm
,
346 DWORD type
, BOOL check_screen_size
)
350 if (check_screen_size
&& (type
& RASTER_FONTTYPE
))
351 ret
= (tm
->tmMaxCharWidth
* data
->curcfg
.win_width
< GetSystemMetrics(SM_CXSCREEN
) &&
352 tm
->tmHeight
* data
->curcfg
.win_height
< GetSystemMetrics(SM_CYSCREEN
));
353 return ret
&& !tm
->tmItalic
&& !tm
->tmUnderlined
&& !tm
->tmStruckOut
&&
354 (tm
->tmCharSet
== DEFAULT_CHARSET
|| tm
->tmCharSet
== g_uiDefaultCharset
);
357 /******************************************************************
358 * WCUSER_ValidateFont
360 * Returns true if the font family described in lf is usable as a font for the renderer
362 BOOL
WCUSER_ValidateFont(const struct inner_data
* data
, const LOGFONTW
* lf
)
364 return (lf
->lfPitchAndFamily
& 3) == FIXED_PITCH
&&
365 /* (lf->lfPitchAndFamily & 0xF0) == FF_MODERN && */
366 lf
->lfFaceName
[0] != '@' &&
367 (lf
->lfCharSet
== DEFAULT_CHARSET
|| lf
->lfCharSet
== g_uiDefaultCharset
);
370 /******************************************************************
371 * get_first_font_enum_2
372 * get_first_font_enum
374 * Helper functions to get a decent font for the renderer
376 static int CALLBACK
get_first_font_enum_2(const LOGFONTW
* lf
, const TEXTMETRICW
* tm
,
377 DWORD FontType
, LPARAM lParam
)
379 struct font_chooser
* fc
= (struct font_chooser
*)lParam
;
381 WCUSER_DumpTextMetric(tm
, FontType
);
382 if (WCUSER_ValidateFontMetric(fc
->data
, tm
, FontType
, fc
->check_screen_size
))
386 /* Use the default sizes for the font (this is needed, especially for
387 * TrueType fonts, so that we get a decent size, not the max size)
389 mlf
.lfWidth
= fc
->data
->curcfg
.cell_width
;
390 mlf
.lfHeight
= fc
->data
->curcfg
.cell_height
;
391 if (WCUSER_SetFont(fc
->data
, &mlf
))
393 struct config_data defcfg
;
395 WCUSER_DumpLogFont("InitChoosing: ", &mlf
, FontType
);
397 /* since we've modified the current config with new font information,
398 * set this information as the new default.
400 WINECON_RegLoad(NULL
, &defcfg
);
401 defcfg
.cell_width
= fc
->data
->curcfg
.cell_width
;
402 defcfg
.cell_height
= fc
->data
->curcfg
.cell_height
;
403 lstrcpyW(defcfg
.face_name
, fc
->data
->curcfg
.face_name
);
404 /* Force also its writing back to the registry so that we can get it
407 WINECON_RegSave(&defcfg
);
414 static int CALLBACK
get_first_font_enum(const LOGFONTW
* lf
, const TEXTMETRICW
* tm
,
415 DWORD FontType
, LPARAM lParam
)
417 struct font_chooser
* fc
= (struct font_chooser
*)lParam
;
419 WCUSER_DumpLogFont("InitFamily: ", lf
, FontType
);
420 if (WCUSER_ValidateFont(fc
->data
, lf
))
422 EnumFontFamiliesW(PRIVATE(fc
->data
)->hMemDC
, lf
->lfFaceName
,
423 get_first_font_enum_2
, lParam
);
424 return !fc
->done
; /* we just need the first matching one... */
429 /******************************************************************
432 * get the relevant information from the font described in lf and store them
435 HFONT
WCUSER_CopyFont(struct config_data
* config
, HWND hWnd
, const LOGFONTW
* lf
, LONG
* el
)
439 HFONT hFont
, hOldFont
;
441 if (!(hDC
= GetDC(hWnd
))) return NULL
;
442 if (!(hFont
= CreateFontIndirectW(lf
)))
444 ReleaseDC(hWnd
, hDC
);
447 hOldFont
= SelectObject(hDC
, hFont
);
448 GetTextMetricsW(hDC
, &tm
);
449 SelectObject(hDC
, hOldFont
);
450 ReleaseDC(hWnd
, hDC
);
452 config
->cell_width
= tm
.tmMaxCharWidth
;
453 config
->cell_height
= tm
.tmHeight
+ tm
.tmExternalLeading
;
454 config
->font_weight
= tm
.tmWeight
;
455 lstrcpyW(config
->face_name
, lf
->lfFaceName
);
456 if (el
) *el
= tm
.tmExternalLeading
;
461 /******************************************************************
466 void WCUSER_FillLogFont(LOGFONTW
* lf
, const WCHAR
* name
, UINT height
, UINT weight
)
468 lf
->lfHeight
= height
;
470 lf
->lfEscapement
= 0;
471 lf
->lfOrientation
= 0;
472 lf
->lfWeight
= weight
;
473 lf
->lfItalic
= FALSE
;
474 lf
->lfUnderline
= FALSE
;
475 lf
->lfStrikeOut
= FALSE
;
476 lf
->lfCharSet
= DEFAULT_CHARSET
;
477 lf
->lfOutPrecision
= OUT_DEFAULT_PRECIS
;
478 lf
->lfClipPrecision
= CLIP_DEFAULT_PRECIS
;
479 lf
->lfQuality
= DEFAULT_QUALITY
;
480 lf
->lfPitchAndFamily
= FIXED_PITCH
| FF_DONTCARE
;
481 lstrcpyW(lf
->lfFaceName
, name
);
484 /******************************************************************
487 * sets logfont as the new font for the console
489 BOOL
WCUSER_SetFont(struct inner_data
* data
, const LOGFONTW
* logfont
)
494 if (PRIVATE(data
)->hFont
!= 0 && WCUSER_AreFontsEqual(&data
->curcfg
, logfont
))
497 hFont
= WCUSER_CopyFont(&data
->curcfg
, data
->hWnd
, logfont
, &el
);
498 if (!hFont
) {WINE_ERR("wrong font\n"); return FALSE
;}
500 if (PRIVATE(data
)->hFont
) DeleteObject(PRIVATE(data
)->hFont
);
501 PRIVATE(data
)->hFont
= hFont
;
502 PRIVATE(data
)->ext_leading
= el
;
504 WCUSER_ComputePositions(data
);
505 WCUSER_NewBitmap(data
);
506 InvalidateRect(data
->hWnd
, NULL
, FALSE
);
507 UpdateWindow(data
->hWnd
);
512 /******************************************************************
515 * Sets a new font for the console.
516 * In fact a wrapper for WCUSER_SetFont
518 static void WCUSER_SetFontPmt(struct inner_data
* data
, const WCHAR
* font
,
519 unsigned height
, unsigned weight
)
522 struct font_chooser fc
;
524 WINE_TRACE_(wc_font
)("=> %s h=%u w=%u\n",
525 wine_dbgstr_wn(font
, -1), height
, weight
);
527 if (font
[0] != '\0' && height
!= 0 && weight
!= 0)
529 WCUSER_FillLogFont(&lf
, font
, height
, weight
);
530 if (WCUSER_SetFont(data
, &lf
))
532 WCUSER_DumpLogFont("InitReuses: ", &lf
, 0);
537 /* try to find an acceptable font */
538 WINE_WARN("Couldn't match the font from registry... trying to find one\n");
540 fc
.check_screen_size
= TRUE
;
542 EnumFontFamiliesW(PRIVATE(data
)->hMemDC
, NULL
, get_first_font_enum
, (LPARAM
)&fc
);
544 fc
.check_screen_size
= FALSE
;
545 EnumFontFamiliesW(PRIVATE(data
)->hMemDC
, NULL
, get_first_font_enum
, (LPARAM
)&fc
);
546 if (!fc
.done
) WINECON_Fatal("Couldn't find a decent font, aborting\n");
549 /******************************************************************
552 * Get a cell from a relative coordinate in window (takes into
553 * account the scrolling)
555 static COORD
WCUSER_GetCell(const struct inner_data
* data
, LPARAM lParam
)
559 c
.X
= data
->curcfg
.win_pos
.X
+ (short)LOWORD(lParam
) / data
->curcfg
.cell_width
;
560 c
.Y
= data
->curcfg
.win_pos
.Y
+ (short)HIWORD(lParam
) / data
->curcfg
.cell_height
;
565 /******************************************************************
566 * WCUSER_GetSelectionRect
568 * Get the selection rectangle
570 static void WCUSER_GetSelectionRect(const struct inner_data
* data
, LPRECT r
)
572 r
->left
= (min(PRIVATE(data
)->selectPt1
.X
, PRIVATE(data
)->selectPt2
.X
) - data
->curcfg
.win_pos
.X
) * data
->curcfg
.cell_width
;
573 r
->top
= (min(PRIVATE(data
)->selectPt1
.Y
, PRIVATE(data
)->selectPt2
.Y
) - data
->curcfg
.win_pos
.Y
) * data
->curcfg
.cell_height
;
574 r
->right
= (max(PRIVATE(data
)->selectPt1
.X
, PRIVATE(data
)->selectPt2
.X
) + 1 - data
->curcfg
.win_pos
.X
) * data
->curcfg
.cell_width
;
575 r
->bottom
= (max(PRIVATE(data
)->selectPt1
.Y
, PRIVATE(data
)->selectPt2
.Y
) + 1 - data
->curcfg
.win_pos
.Y
) * data
->curcfg
.cell_height
;
578 /******************************************************************
579 * WCUSER_SetSelection
583 static void WCUSER_SetSelection(const struct inner_data
* data
, HDC hRefDC
)
588 WCUSER_GetSelectionRect(data
, &r
);
589 hDC
= hRefDC
? hRefDC
: GetDC(data
->hWnd
);
592 if (data
->hWnd
== GetFocus() && data
->curcfg
.cursor_visible
)
593 HideCaret(data
->hWnd
);
596 ReleaseDC(data
->hWnd
, hDC
);
597 if (data
->hWnd
== GetFocus() && data
->curcfg
.cursor_visible
)
598 ShowCaret(data
->hWnd
);
602 /******************************************************************
603 * WCUSER_MoveSelection
607 static void WCUSER_MoveSelection(struct inner_data
* data
, COORD c1
, COORD c2
)
612 if (c1
.X
< 0 || c1
.X
>= data
->curcfg
.sb_width
||
613 c2
.X
< 0 || c2
.X
>= data
->curcfg
.sb_width
||
614 c1
.Y
< 0 || c1
.Y
>= data
->curcfg
.sb_height
||
615 c2
.Y
< 0 || c2
.Y
>= data
->curcfg
.sb_height
)
618 WCUSER_GetSelectionRect(data
, &r
);
619 hDC
= GetDC(data
->hWnd
);
622 if (data
->hWnd
== GetFocus() && data
->curcfg
.cursor_visible
)
623 HideCaret(data
->hWnd
);
626 PRIVATE(data
)->selectPt1
= c1
;
627 PRIVATE(data
)->selectPt2
= c2
;
630 WCUSER_GetSelectionRect(data
, &r
);
632 ReleaseDC(data
->hWnd
, hDC
);
633 if (data
->hWnd
== GetFocus() && data
->curcfg
.cursor_visible
)
634 ShowCaret(data
->hWnd
);
638 /******************************************************************
639 * WCUSER_CopySelectionToClipboard
641 * Copies the current selection into the clipboard
643 static void WCUSER_CopySelectionToClipboard(const struct inner_data
* data
)
649 w
= abs(PRIVATE(data
)->selectPt1
.X
- PRIVATE(data
)->selectPt2
.X
) + 2;
650 h
= abs(PRIVATE(data
)->selectPt1
.Y
- PRIVATE(data
)->selectPt2
.Y
) + 1;
652 if (!OpenClipboard(data
->hWnd
)) return;
655 hMem
= GlobalAlloc(GMEM_MOVEABLE
, (w
* h
) * sizeof(WCHAR
));
656 if (hMem
&& (p
= GlobalLock(hMem
)))
661 c
.X
= min(PRIVATE(data
)->selectPt1
.X
, PRIVATE(data
)->selectPt2
.X
);
662 c
.Y
= min(PRIVATE(data
)->selectPt1
.Y
, PRIVATE(data
)->selectPt2
.Y
);
664 for (y
= 0; y
< h
; y
++, c
.Y
++)
669 ReadConsoleOutputCharacterW(data
->hConOut
, p
, w
- 1, c
, &count
);
671 /* strip spaces from the end of the line */
673 while (end
> p
&& *(end
- 1) == ' ')
675 *end
= (y
< h
- 1) ? '\n' : '\0';
679 SetClipboardData(CF_UNICODETEXT
, hMem
);
684 /******************************************************************
685 * WCUSER_PasteFromClipboard
689 static void WCUSER_PasteFromClipboard(struct inner_data
* data
)
694 if (!OpenClipboard(data
->hWnd
)) return;
695 h
= GetClipboardData(CF_UNICODETEXT
);
696 if (h
&& (ptr
= GlobalLock(h
)))
698 int i
, len
= GlobalSize(h
) / sizeof(WCHAR
);
703 ir
[0].EventType
= KEY_EVENT
;
704 ir
[0].Event
.KeyEvent
.wRepeatCount
= 0;
705 ir
[0].Event
.KeyEvent
.dwControlKeyState
= 0;
706 ir
[0].Event
.KeyEvent
.bKeyDown
= TRUE
;
708 /* generate the corresponding input records */
709 for (i
= 0; i
< len
; i
++)
711 /* FIXME: the modifying keys are not generated (shift, ctrl...) */
712 sh
= VkKeyScanW(ptr
[i
]);
713 ir
[0].Event
.KeyEvent
.wVirtualKeyCode
= LOBYTE(sh
);
714 ir
[0].Event
.KeyEvent
.wVirtualScanCode
= MapVirtualKeyW(LOBYTE(sh
), 0);
715 ir
[0].Event
.KeyEvent
.uChar
.UnicodeChar
= ptr
[i
];
718 ir
[1].Event
.KeyEvent
.bKeyDown
= FALSE
;
720 WriteConsoleInputW(data
->hConIn
, ir
, 2, &n
);
727 /******************************************************************
732 static void WCUSER_Refresh(const struct inner_data
* data
, int tp
, int bm
)
734 WCUSER_FillMemDC(data
, tp
, bm
);
735 if (data
->curcfg
.win_pos
.Y
<= bm
&& data
->curcfg
.win_pos
.Y
+ data
->curcfg
.win_height
>= tp
)
740 r
.right
= data
->curcfg
.win_width
* data
->curcfg
.cell_width
;
741 r
.top
= (tp
- data
->curcfg
.win_pos
.Y
) * data
->curcfg
.cell_height
;
742 r
.bottom
= (bm
- data
->curcfg
.win_pos
.Y
+ 1) * data
->curcfg
.cell_height
;
743 InvalidateRect(data
->hWnd
, &r
, FALSE
);
744 UpdateWindow(data
->hWnd
);
748 /******************************************************************
753 static void WCUSER_Paint(const struct inner_data
* data
)
757 if (data
->in_set_config
) return; /* in order to avoid some flicker */
758 BeginPaint(data
->hWnd
, &ps
);
760 data
->curcfg
.win_width
* data
->curcfg
.cell_width
,
761 data
->curcfg
.win_height
* data
->curcfg
.cell_height
,
762 PRIVATE(data
)->hMemDC
,
763 data
->curcfg
.win_pos
.X
* data
->curcfg
.cell_width
,
764 data
->curcfg
.win_pos
.Y
* data
->curcfg
.cell_height
,
766 if (PRIVATE(data
)->has_selection
)
767 WCUSER_SetSelection(data
, ps
.hdc
);
768 EndPaint(data
->hWnd
, &ps
);
771 /******************************************************************
776 static void WCUSER_Scroll(struct inner_data
* data
, int pos
, BOOL horz
)
780 ScrollWindow(data
->hWnd
, (data
->curcfg
.win_pos
.X
- pos
) * data
->curcfg
.cell_width
, 0, NULL
, NULL
);
781 SetScrollPos(data
->hWnd
, SB_HORZ
, pos
, TRUE
);
782 data
->curcfg
.win_pos
.X
= pos
;
786 ScrollWindow(data
->hWnd
, 0, (data
->curcfg
.win_pos
.Y
- pos
) * data
->curcfg
.cell_height
, NULL
, NULL
);
787 SetScrollPos(data
->hWnd
, SB_VERT
, pos
, TRUE
);
788 data
->curcfg
.win_pos
.Y
= pos
;
790 InvalidateRect(data
->hWnd
, NULL
, FALSE
);
793 /******************************************************************
798 static BOOL
WCUSER_FillMenu(HMENU hMenu
, BOOL sep
)
801 HINSTANCE hInstance
= GetModuleHandleW(NULL
);
804 if (!hMenu
) return FALSE
;
806 /* FIXME: error handling & memory cleanup */
807 hSubMenu
= CreateMenu();
808 if (!hSubMenu
) return FALSE
;
810 LoadStringW(hInstance
, IDS_MARK
, buff
, sizeof(buff
) / sizeof(buff
[0]));
811 InsertMenuW(hSubMenu
, -1, MF_BYPOSITION
|MF_STRING
, IDS_MARK
, buff
);
812 LoadStringW(hInstance
, IDS_COPY
, buff
, sizeof(buff
) / sizeof(buff
[0]));
813 InsertMenuW(hSubMenu
, -1, MF_BYPOSITION
|MF_STRING
, IDS_COPY
, buff
);
814 LoadStringW(hInstance
, IDS_PASTE
, buff
, sizeof(buff
) / sizeof(buff
[0]));
815 InsertMenuW(hSubMenu
, -1, MF_BYPOSITION
|MF_STRING
, IDS_PASTE
, buff
);
816 LoadStringW(hInstance
, IDS_SELECTALL
, buff
, sizeof(buff
) / sizeof(buff
[0]));
817 InsertMenuW(hSubMenu
, -1, MF_BYPOSITION
|MF_STRING
, IDS_SELECTALL
, buff
);
818 LoadStringW(hInstance
, IDS_SCROLL
, buff
, sizeof(buff
) / sizeof(buff
[0]));
819 InsertMenuW(hSubMenu
, -1, MF_BYPOSITION
|MF_STRING
, IDS_SCROLL
, buff
);
820 LoadStringW(hInstance
, IDS_SEARCH
, buff
, sizeof(buff
) / sizeof(buff
[0]));
821 InsertMenuW(hSubMenu
, -1, MF_BYPOSITION
|MF_STRING
, IDS_SEARCH
, buff
);
823 if (sep
) InsertMenuW(hMenu
, -1, MF_BYPOSITION
|MF_SEPARATOR
, 0, NULL
);
824 LoadStringW(hInstance
, IDS_EDIT
, buff
, sizeof(buff
) / sizeof(buff
[0]));
825 InsertMenuW(hMenu
, -1, MF_BYPOSITION
|MF_STRING
|MF_POPUP
, (UINT_PTR
)hSubMenu
, buff
);
826 LoadStringW(hInstance
, IDS_DEFAULT
, buff
, sizeof(buff
) / sizeof(buff
[0]));
827 InsertMenuW(hMenu
, -1, MF_BYPOSITION
|MF_STRING
, IDS_DEFAULT
, buff
);
828 LoadStringW(hInstance
, IDS_PROPERTIES
, buff
, sizeof(buff
) / sizeof(buff
[0]));
829 InsertMenuW(hMenu
, -1, MF_BYPOSITION
|MF_STRING
, IDS_PROPERTIES
, buff
);
834 /******************************************************************
835 * WCUSER_SetMenuDetails
837 * Grays / ungrays the menu items according to their state
839 static void WCUSER_SetMenuDetails(const struct inner_data
* data
, HMENU hMenu
)
841 if (!hMenu
) {WINE_ERR("Issue in getting menu bits\n");return;}
843 EnableMenuItem(hMenu
, IDS_COPY
,
844 MF_BYCOMMAND
|(PRIVATE(data
)->has_selection
? MF_ENABLED
: MF_GRAYED
));
845 EnableMenuItem(hMenu
, IDS_PASTE
,
846 MF_BYCOMMAND
|(IsClipboardFormatAvailable(CF_UNICODETEXT
)
847 ? MF_ENABLED
: MF_GRAYED
));
848 EnableMenuItem(hMenu
, IDS_SCROLL
, MF_BYCOMMAND
|MF_GRAYED
);
849 EnableMenuItem(hMenu
, IDS_SEARCH
, MF_BYCOMMAND
|MF_GRAYED
);
852 /******************************************************************
855 * Creates the window for the rendering
857 static LRESULT
WCUSER_Create(HWND hWnd
, LPCREATESTRUCTW lpcs
)
859 struct inner_data
* data
;
862 data
= lpcs
->lpCreateParams
;
863 SetWindowLongPtrW(hWnd
, 0, (DWORD_PTR
)data
);
866 hSysMenu
= GetSystemMenu(hWnd
, FALSE
);
867 if (!hSysMenu
) return 0;
868 PRIVATE(data
)->hPopMenu
= CreatePopupMenu();
869 if (!PRIVATE(data
)->hPopMenu
) return 0;
871 WCUSER_FillMenu(hSysMenu
, TRUE
);
872 WCUSER_FillMenu(PRIVATE(data
)->hPopMenu
, FALSE
);
874 PRIVATE(data
)->hMemDC
= CreateCompatibleDC(0);
875 if (!PRIVATE(data
)->hMemDC
) {WINE_ERR("no mem dc\n");return 0;}
877 data
->curcfg
.quick_edit
= FALSE
;
881 /******************************************************************
882 * WCUSER_GetCtrlKeyState
884 * Get the console bit mask equivalent to the VK_ status in keyState
886 static DWORD
WCUSER_GetCtrlKeyState(BYTE
* keyState
)
890 GetKeyboardState(keyState
);
891 if (keyState
[VK_SHIFT
] & 0x80) ret
|= SHIFT_PRESSED
;
892 if (keyState
[VK_LCONTROL
] & 0x80) ret
|= LEFT_CTRL_PRESSED
;
893 if (keyState
[VK_RCONTROL
] & 0x80) ret
|= RIGHT_CTRL_PRESSED
;
894 if (keyState
[VK_LMENU
] & 0x80) ret
|= LEFT_ALT_PRESSED
;
895 if (keyState
[VK_RMENU
] & 0x80) ret
|= RIGHT_ALT_PRESSED
;
896 if (keyState
[VK_CAPITAL
] & 0x01) ret
|= CAPSLOCK_ON
;
897 if (keyState
[VK_NUMLOCK
] & 0x01) ret
|= NUMLOCK_ON
;
898 if (keyState
[VK_SCROLL
] & 0x01) ret
|= SCROLLLOCK_ON
;
903 /******************************************************************
904 * WCUSER_HandleSelectionKey
906 * Handles keys while selecting an area
908 static void WCUSER_HandleSelectionKey(struct inner_data
* data
, BOOL down
,
909 WPARAM wParam
, LPARAM lParam
)
912 DWORD state
= WCUSER_GetCtrlKeyState(keyState
) & ~(CAPSLOCK_ON
|NUMLOCK_ON
|SCROLLLOCK_ON
);
923 PRIVATE(data
)->has_selection
= FALSE
;
924 WCUSER_SetSelection(data
, 0);
925 WCUSER_CopySelectionToClipboard(data
);
928 c1
= PRIVATE(data
)->selectPt1
;
929 c2
= PRIVATE(data
)->selectPt2
;
931 WCUSER_MoveSelection(data
, c1
, c2
);
934 c1
= PRIVATE(data
)->selectPt1
;
935 c2
= PRIVATE(data
)->selectPt2
;
937 WCUSER_MoveSelection(data
, c1
, c2
);
940 c1
= PRIVATE(data
)->selectPt1
;
941 c2
= PRIVATE(data
)->selectPt2
;
943 WCUSER_MoveSelection(data
, c1
, c2
);
946 c1
= PRIVATE(data
)->selectPt1
;
947 c2
= PRIVATE(data
)->selectPt2
;
949 WCUSER_MoveSelection(data
, c1
, c2
);
957 c1
= PRIVATE(data
)->selectPt1
;
958 c2
= PRIVATE(data
)->selectPt2
;
960 WCUSER_MoveSelection(data
, c1
, c2
);
963 c1
= PRIVATE(data
)->selectPt1
;
964 c2
= PRIVATE(data
)->selectPt2
;
966 WCUSER_MoveSelection(data
, c1
, c2
);
969 c1
= PRIVATE(data
)->selectPt1
;
970 c2
= PRIVATE(data
)->selectPt2
;
972 WCUSER_MoveSelection(data
, c1
, c2
);
975 c1
= PRIVATE(data
)->selectPt1
;
976 c2
= PRIVATE(data
)->selectPt2
;
978 WCUSER_MoveSelection(data
, c1
, c2
);
984 if (wParam
< VK_SPACE
) /* Shift, Alt, Ctrl, Num Lock etc. */
987 WCUSER_SetSelection(data
, 0);
988 PRIVATE(data
)->has_selection
= FALSE
;
991 /******************************************************************
992 * WCUSER_GenerateKeyInputRecord
994 * generates input_record from windows WM_KEYUP/WM_KEYDOWN messages
996 static void WCUSER_GenerateKeyInputRecord(struct inner_data
* data
, BOOL down
,
997 WPARAM wParam
, LPARAM lParam
)
1002 static WCHAR last
; /* keep last char seen as feed for key up message */
1005 ir
.EventType
= KEY_EVENT
;
1006 ir
.Event
.KeyEvent
.bKeyDown
= down
;
1007 ir
.Event
.KeyEvent
.wRepeatCount
= LOWORD(lParam
);
1008 ir
.Event
.KeyEvent
.wVirtualKeyCode
= wParam
;
1010 ir
.Event
.KeyEvent
.wVirtualScanCode
= HIWORD(lParam
) & 0xFF;
1012 ir
.Event
.KeyEvent
.uChar
.UnicodeChar
= 0;
1013 ir
.Event
.KeyEvent
.dwControlKeyState
= WCUSER_GetCtrlKeyState(keyState
);
1014 if (lParam
& (1L << 24)) ir
.Event
.KeyEvent
.dwControlKeyState
|= ENHANCED_KEY
;
1018 switch (ToUnicode(wParam
, HIWORD(lParam
), keyState
, buf
, 2, 0))
1021 /* FIXME... should generate two events... */
1031 ir
.Event
.KeyEvent
.uChar
.UnicodeChar
= last
; /* FIXME: HACKY... and buggy because it should be a stack, not a single value */
1032 if (!down
) last
= 0;
1034 WriteConsoleInputW(data
->hConIn
, &ir
, 1, &n
);
1037 /******************************************************************
1038 * WCUSER_GenerateMouseInputRecord
1042 static void WCUSER_GenerateMouseInputRecord(struct inner_data
* data
, COORD c
,
1043 WPARAM wParam
, DWORD event
)
1049 /* MOUSE_EVENTs shouldn't be sent unless ENABLE_MOUSE_INPUT is active */
1050 if (!GetConsoleMode(data
->hConIn
, &mode
) || !(mode
& ENABLE_MOUSE_INPUT
))
1053 ir
.EventType
= MOUSE_EVENT
;
1054 ir
.Event
.MouseEvent
.dwMousePosition
= c
;
1055 ir
.Event
.MouseEvent
.dwButtonState
= 0;
1056 if (wParam
& MK_LBUTTON
) ir
.Event
.MouseEvent
.dwButtonState
|= FROM_LEFT_1ST_BUTTON_PRESSED
;
1057 if (wParam
& MK_MBUTTON
) ir
.Event
.MouseEvent
.dwButtonState
|= FROM_LEFT_2ND_BUTTON_PRESSED
;
1058 if (wParam
& MK_RBUTTON
) ir
.Event
.MouseEvent
.dwButtonState
|= RIGHTMOST_BUTTON_PRESSED
;
1059 if (wParam
& MK_CONTROL
) ir
.Event
.MouseEvent
.dwButtonState
|= LEFT_CTRL_PRESSED
;
1060 if (wParam
& MK_SHIFT
) ir
.Event
.MouseEvent
.dwButtonState
|= SHIFT_PRESSED
;
1061 if (event
== MOUSE_WHEELED
) ir
.Event
.MouseEvent
.dwButtonState
|= wParam
& 0xFFFF0000;
1062 ir
.Event
.MouseEvent
.dwControlKeyState
= WCUSER_GetCtrlKeyState(keyState
);
1063 ir
.Event
.MouseEvent
.dwEventFlags
= event
;
1065 WriteConsoleInputW(data
->hConIn
, &ir
, 1, &n
);
1068 /******************************************************************
1073 static LRESULT CALLBACK
WCUSER_Proc(HWND hWnd
, UINT uMsg
, WPARAM wParam
, LPARAM lParam
)
1075 struct inner_data
* data
= (struct inner_data
*)GetWindowLongPtrW(hWnd
, 0);
1080 return WCUSER_Create(hWnd
, (LPCREATESTRUCTW
)lParam
);
1090 if (PRIVATE(data
)->has_selection
)
1091 WCUSER_HandleSelectionKey(data
, uMsg
== WM_KEYDOWN
, wParam
, lParam
);
1093 WCUSER_GenerateKeyInputRecord(data
, uMsg
== WM_KEYDOWN
, wParam
, lParam
);
1097 WCUSER_GenerateKeyInputRecord(data
, uMsg
== WM_SYSKEYDOWN
, wParam
, lParam
);
1099 case WM_LBUTTONDOWN
:
1100 if (data
->curcfg
.quick_edit
|| PRIVATE(data
)->has_selection
)
1102 if (PRIVATE(data
)->has_selection
)
1103 WCUSER_SetSelection(data
, 0);
1105 if (data
->curcfg
.quick_edit
&& PRIVATE(data
)->has_selection
)
1107 PRIVATE(data
)->has_selection
= FALSE
;
1111 PRIVATE(data
)->selectPt1
= PRIVATE(data
)->selectPt2
= WCUSER_GetCell(data
, lParam
);
1112 SetCapture(data
->hWnd
);
1113 WCUSER_SetSelection(data
, 0);
1114 PRIVATE(data
)->has_selection
= TRUE
;
1119 WCUSER_GenerateMouseInputRecord(data
, WCUSER_GetCell(data
, lParam
), wParam
, 0);
1123 if (data
->curcfg
.quick_edit
|| PRIVATE(data
)->has_selection
)
1125 if (GetCapture() == data
->hWnd
&& PRIVATE(data
)->has_selection
&&
1126 (wParam
& MK_LBUTTON
))
1128 WCUSER_MoveSelection(data
, PRIVATE(data
)->selectPt1
, WCUSER_GetCell(data
, lParam
));
1133 WCUSER_GenerateMouseInputRecord(data
, WCUSER_GetCell(data
, lParam
), wParam
, MOUSE_MOVED
);
1137 if (data
->curcfg
.quick_edit
|| PRIVATE(data
)->has_selection
)
1139 if (GetCapture() == data
->hWnd
&& PRIVATE(data
)->has_selection
)
1141 WCUSER_MoveSelection(data
, PRIVATE(data
)->selectPt1
, WCUSER_GetCell(data
, lParam
));
1147 WCUSER_GenerateMouseInputRecord(data
, WCUSER_GetCell(data
, lParam
), wParam
, 0);
1150 case WM_RBUTTONDOWN
:
1151 if ((wParam
& (MK_CONTROL
|MK_SHIFT
)) == data
->curcfg
.menu_mask
)
1155 pt
.x
= (short)LOWORD(lParam
);
1156 pt
.y
= (short)HIWORD(lParam
);
1157 ClientToScreen(hWnd
, &pt
);
1158 WCUSER_SetMenuDetails(data
, PRIVATE(data
)->hPopMenu
);
1159 TrackPopupMenu(PRIVATE(data
)->hPopMenu
, TPM_LEFTALIGN
|TPM_TOPALIGN
|TPM_RIGHTBUTTON
,
1160 pt
.x
, pt
.y
, 0, hWnd
, NULL
);
1164 WCUSER_GenerateMouseInputRecord(data
, WCUSER_GetCell(data
, lParam
), wParam
, 0);
1168 /* no need to track for rbutton up when opening the popup... the event will be
1169 * swallowed by TrackPopupMenu */
1170 case WM_MBUTTONDOWN
:
1172 WCUSER_GenerateMouseInputRecord(data
, WCUSER_GetCell(data
, lParam
), wParam
, 0);
1174 case WM_LBUTTONDBLCLK
:
1175 case WM_MBUTTONDBLCLK
:
1176 case WM_RBUTTONDBLCLK
:
1177 WCUSER_GenerateMouseInputRecord(data
, WCUSER_GetCell(data
, lParam
), wParam
, DOUBLE_CLICK
);
1180 if (data
->curcfg
.cursor_visible
)
1182 CreateCaret(data
->hWnd
, PRIVATE(data
)->cursor_bitmap
,
1183 data
->curcfg
.cell_width
, data
->curcfg
.cell_height
);
1184 WCUSER_PosCursor(data
);
1188 if (data
->curcfg
.cursor_visible
)
1193 struct config_data cfg
= data
->curcfg
;
1195 switch (LOWORD(wParam
))
1197 case SB_PAGEUP
: cfg
.win_pos
.X
-= 8; break;
1198 case SB_PAGEDOWN
: cfg
.win_pos
.X
+= 8; break;
1199 case SB_LINEUP
: cfg
.win_pos
.X
--; break;
1200 case SB_LINEDOWN
: cfg
.win_pos
.X
++; break;
1201 case SB_THUMBTRACK
: cfg
.win_pos
.X
= HIWORD(wParam
); break;
1204 if (cfg
.win_pos
.X
< 0) cfg
.win_pos
.X
= 0;
1205 if (cfg
.win_pos
.X
> data
->curcfg
.sb_width
- data
->curcfg
.win_width
)
1206 cfg
.win_pos
.X
= data
->curcfg
.sb_width
- data
->curcfg
.win_width
;
1207 if (cfg
.win_pos
.X
!= data
->curcfg
.win_pos
.X
)
1209 WINECON_SetConfig(data
, &cfg
);
1214 if (data
->curcfg
.sb_height
<= data
->curcfg
.win_height
)
1216 WCUSER_GenerateMouseInputRecord(data
, WCUSER_GetCell(data
, lParam
), wParam
, MOUSE_WHEELED
);
1219 /* else fallthrough */
1222 struct config_data cfg
= data
->curcfg
;
1224 if (uMsg
== WM_MOUSEWHEEL
)
1226 UINT scrollLines
= 3;
1227 SystemParametersInfoW(SPI_GETWHEELSCROLLLINES
, 0, &scrollLines
, 0);
1228 scrollLines
*= -GET_WHEEL_DELTA_WPARAM(wParam
) / WHEEL_DELTA
;
1229 cfg
.win_pos
.Y
+= scrollLines
;
1231 switch (LOWORD(wParam
))
1233 case SB_PAGEUP
: cfg
.win_pos
.Y
-= 8; break;
1234 case SB_PAGEDOWN
: cfg
.win_pos
.Y
+= 8; break;
1235 case SB_LINEUP
: cfg
.win_pos
.Y
--; break;
1236 case SB_LINEDOWN
: cfg
.win_pos
.Y
++; break;
1237 case SB_THUMBTRACK
: cfg
.win_pos
.Y
= HIWORD(wParam
); break;
1242 if (cfg
.win_pos
.Y
< 0) cfg
.win_pos
.Y
= 0;
1243 if (cfg
.win_pos
.Y
> data
->curcfg
.sb_height
- data
->curcfg
.win_height
)
1244 cfg
.win_pos
.Y
= data
->curcfg
.sb_height
- data
->curcfg
.win_height
;
1245 if (cfg
.win_pos
.Y
!= data
->curcfg
.win_pos
.Y
)
1247 WINECON_SetConfig(data
, &cfg
);
1255 WCUSER_GetProperties(data
, FALSE
);
1257 case IDS_PROPERTIES
:
1258 WCUSER_GetProperties(data
, TRUE
);
1261 return DefWindowProcW(hWnd
, uMsg
, wParam
, lParam
);
1268 WCUSER_GetProperties(data
, FALSE
);
1270 case IDS_PROPERTIES
:
1271 WCUSER_GetProperties(data
, TRUE
);
1274 PRIVATE(data
)->selectPt1
.X
= PRIVATE(data
)->selectPt1
.Y
= 0;
1275 PRIVATE(data
)->selectPt2
.X
= PRIVATE(data
)->selectPt2
.Y
= 0;
1276 WCUSER_SetSelection(data
, 0);
1277 PRIVATE(data
)->has_selection
= TRUE
;
1280 if (PRIVATE(data
)->has_selection
)
1282 PRIVATE(data
)->has_selection
= FALSE
;
1283 WCUSER_SetSelection(data
, 0);
1284 WCUSER_CopySelectionToClipboard(data
);
1288 WCUSER_PasteFromClipboard(data
);
1291 PRIVATE(data
)->selectPt1
.X
= PRIVATE(data
)->selectPt1
.Y
= 0;
1292 PRIVATE(data
)->selectPt2
.X
= (data
->curcfg
.sb_width
- 1) * data
->curcfg
.cell_width
;
1293 PRIVATE(data
)->selectPt2
.Y
= (data
->curcfg
.sb_height
- 1) * data
->curcfg
.cell_height
;
1294 WCUSER_SetSelection(data
, 0);
1295 PRIVATE(data
)->has_selection
= TRUE
;
1299 WINE_FIXME("Unhandled yet command: %lx\n", wParam
);
1302 return DefWindowProcW(hWnd
, uMsg
, wParam
, lParam
);
1305 case WM_INITMENUPOPUP
:
1306 if (!HIWORD(lParam
)) return DefWindowProcW(hWnd
, uMsg
, wParam
, lParam
);
1307 WCUSER_SetMenuDetails(data
, GetSystemMenu(data
->hWnd
, FALSE
));
1310 WINECON_ResizeWithContainer(data
, LOWORD(lParam
) / data
->curcfg
.cell_width
,
1311 HIWORD(lParam
) / data
->curcfg
.cell_height
);
1314 return DefWindowProcW(hWnd
, uMsg
, wParam
, lParam
);
1319 /******************************************************************
1320 * WCUSER_DeleteBackend
1324 static void WCUSER_DeleteBackend(struct inner_data
* data
)
1326 if (!PRIVATE(data
)) return;
1327 if (PRIVATE(data
)->hMemDC
) DeleteDC(PRIVATE(data
)->hMemDC
);
1328 if (data
->hWnd
) DestroyWindow(data
->hWnd
);
1329 if (PRIVATE(data
)->hFont
) DeleteObject(PRIVATE(data
)->hFont
);
1330 if (PRIVATE(data
)->cursor_bitmap
) DeleteObject(PRIVATE(data
)->cursor_bitmap
);
1331 if (PRIVATE(data
)->hBitmap
) DeleteObject(PRIVATE(data
)->hBitmap
);
1332 HeapFree(GetProcessHeap(), 0, PRIVATE(data
));
1335 /******************************************************************
1340 static int WCUSER_MainLoop(struct inner_data
* data
)
1344 ShowWindow(data
->hWnd
, data
->nCmdShow
);
1345 while (!data
->dying
|| !data
->curcfg
.exit_on_die
)
1347 switch (MsgWaitForMultipleObjects(1, &data
->hSynchro
, FALSE
, INFINITE
, QS_ALLINPUT
))
1350 WINECON_GrabChanges(data
);
1352 case WAIT_OBJECT_0
+1:
1353 /* need to use PeekMessageW loop instead of simple GetMessage:
1354 * multiple messages might have arrived in between,
1355 * so GetMessage would lead to delayed processing */
1356 while (PeekMessageW(&msg
, 0, 0, 0, PM_REMOVE
))
1358 if (msg
.message
== WM_QUIT
) return 1;
1359 WINE_TRACE("dispatching msg %04x\n", msg
.message
);
1360 DispatchMessageW(&msg
);
1364 WINE_ERR("got pb\n");
1373 /******************************************************************
1374 * WCUSER_InitBackend
1376 * Initialisation part II: creation of window.
1379 enum init_return
WCUSER_InitBackend(struct inner_data
* data
)
1381 static const WCHAR wClassName
[] = {'W','i','n','e','C','o','n','s','o','l','e','C','l','a','s','s',0};
1386 if (!TranslateCharsetInfo((DWORD
*)(INT_PTR
)GetACP(), &ci
, TCI_SRCCODEPAGE
))
1388 g_uiDefaultCharset
= ci
.ciCharset
;
1389 WINE_TRACE_(wc_font
)("Code page %d => Default charset: %d\n", GetACP(), g_uiDefaultCharset
);
1391 data
->private = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(struct inner_data_user
));
1392 if (!data
->private) return init_failed
;
1394 data
->fnMainLoop
= WCUSER_MainLoop
;
1395 data
->fnPosCursor
= WCUSER_PosCursor
;
1396 data
->fnShapeCursor
= WCUSER_ShapeCursor
;
1397 data
->fnComputePositions
= WCUSER_ComputePositions
;
1398 data
->fnRefresh
= WCUSER_Refresh
;
1399 data
->fnResizeScreenBuffer
= WCUSER_ResizeScreenBuffer
;
1400 data
->fnSetTitle
= WCUSER_SetTitle
;
1401 data
->fnSetFont
= WCUSER_SetFontPmt
;
1402 data
->fnScroll
= WCUSER_Scroll
;
1403 data
->fnDeleteBackend
= WCUSER_DeleteBackend
;
1405 wndclass
.style
= CS_DBLCLKS
;
1406 wndclass
.lpfnWndProc
= WCUSER_Proc
;
1407 wndclass
.cbClsExtra
= 0;
1408 wndclass
.cbWndExtra
= sizeof(DWORD_PTR
);
1409 wndclass
.hInstance
= GetModuleHandleW(NULL
);
1410 wndclass
.hIcon
= LoadIconW(0, (LPCWSTR
)IDI_WINLOGO
);
1411 wndclass
.hCursor
= LoadCursorW(0, (LPCWSTR
)IDC_ARROW
);
1412 wndclass
.hbrBackground
= GetStockObject(BLACK_BRUSH
);
1413 wndclass
.lpszMenuName
= NULL
;
1414 wndclass
.lpszClassName
= wClassName
;
1416 RegisterClassW(&wndclass
);
1418 data
->hWnd
= CreateWindowW(wndclass
.lpszClassName
, NULL
,
1419 WS_OVERLAPPED
|WS_CAPTION
|WS_SYSMENU
|WS_THICKFRAME
|WS_MINIMIZEBOX
|WS_HSCROLL
|WS_VSCROLL
,
1420 CW_USEDEFAULT
, CW_USEDEFAULT
, 0, 0, 0, 0, wndclass
.hInstance
, data
);
1421 if (!data
->hWnd
) return init_not_supported
;
1423 return init_success
;