Dylan Smith 3fbe40e2f9 wineconsole: Handle mouse wheel scrolling for user backend.
The mouse wheel will scroll if the buffer height is greater than the
console window's height in lines, otherwise console mouse input events
are generated.
2010-02-26 13:02:24 +01:00

1454 lines
47 KiB
C

/*
* a GUI application for displaying a console
* USER32 back end
* Copyright 2001 Eric Pouech
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
*/
#include <stdio.h>
#include <stdlib.h>
#include "winecon_user.h"
#include "winnls.h"
#include "wine/debug.h"
WINE_DEFAULT_DEBUG_CHANNEL(wineconsole);
WINE_DECLARE_DEBUG_CHANNEL(wc_font);
UINT g_uiDefaultCharset;
/* mapping console colors to RGB values */
const COLORREF WCUSER_ColorMap[16] =
{
RGB(0x00, 0x00, 0x00), RGB(0x00, 0x00, 0x80), RGB(0x00, 0x80, 0x00), RGB(0x00, 0x80, 0x80),
RGB(0x80, 0x00, 0x00), RGB(0x80, 0x00, 0x80), RGB(0x80, 0x80, 0x00), RGB(0x80, 0x80, 0x80),
RGB(0xC0, 0xC0, 0xC0), RGB(0x00, 0x00, 0xFF), RGB(0x00, 0xFF, 0x00), RGB(0x00, 0xFF, 0xFF),
RGB(0xFF, 0x00, 0x00), RGB(0xFF, 0x00, 0xFF), RGB(0xFF, 0xFF, 0x00), RGB(0xFF, 0xFF, 0xFF),
};
static BOOL WCUSER_SetFont(struct inner_data* data, const LOGFONT* font);
/******************************************************************
* WCUSER_FillMemDC
*
* Fills the Mem DC with current cells values
*/
static void WCUSER_FillMemDC(const struct inner_data* data, int upd_tp, int upd_bm)
{
unsigned i, j, k;
CHAR_INFO* cell;
HFONT hOldFont;
WORD attr;
WCHAR* line;
RECT r;
HBRUSH hbr;
/* no font has been set up yet, don't worry about filling the bitmap,
* we'll do it once a font is chosen
*/
if (!PRIVATE(data)->hFont) return;
/* FIXME: could set up a mechanism to reuse the line between different
* calls to this function
*/
if (!(line = HeapAlloc(GetProcessHeap(), 0, data->curcfg.sb_width * sizeof(WCHAR))))
WINECON_Fatal("OOM\n");
hOldFont = SelectObject(PRIVATE(data)->hMemDC, PRIVATE(data)->hFont);
for (j = upd_tp; j <= upd_bm; j++)
{
cell = &data->cells[j * data->curcfg.sb_width];
for (i = 0; i < data->curcfg.sb_width; i++)
{
attr = cell[i].Attributes;
SetBkColor(PRIVATE(data)->hMemDC, WCUSER_ColorMap[(attr>>4)&0x0F]);
SetTextColor(PRIVATE(data)->hMemDC, WCUSER_ColorMap[attr&0x0F]);
for (k = i; k < data->curcfg.sb_width && cell[k].Attributes == attr; k++)
{
line[k - i] = cell[k].Char.UnicodeChar;
}
TextOut(PRIVATE(data)->hMemDC, i * data->curcfg.cell_width, j * data->curcfg.cell_height,
line, k - i);
if (PRIVATE(data)->ext_leading &&
(hbr = CreateSolidBrush(WCUSER_ColorMap[(attr>>4)&0x0F])))
{
r.left = i * data->curcfg.cell_width;
r.top = (j + 1) * data->curcfg.cell_height - PRIVATE(data)->ext_leading;
r.right = k * data->curcfg.cell_width;
r.bottom = (j + 1) * data->curcfg.cell_height;
FillRect(PRIVATE(data)->hMemDC, &r, hbr);
DeleteObject(hbr);
}
i = k - 1;
}
}
SelectObject(PRIVATE(data)->hMemDC, hOldFont);
HeapFree(GetProcessHeap(), 0, line);
}
/******************************************************************
* WCUSER_NewBitmap
*
* Either the font geometry or the sb geometry has changed. we need
* to recreate the bitmap geometry.
*/
static void WCUSER_NewBitmap(struct inner_data* data)
{
HDC hDC;
HBITMAP hnew, hold;
if (!data->curcfg.sb_width || !data->curcfg.sb_height ||
!PRIVATE(data)->hFont || !(hDC = GetDC(data->hWnd)))
return;
hnew = CreateCompatibleBitmap(hDC,
data->curcfg.sb_width * data->curcfg.cell_width,
data->curcfg.sb_height * data->curcfg.cell_height);
ReleaseDC(data->hWnd, hDC);
hold = SelectObject(PRIVATE(data)->hMemDC, hnew);
if (PRIVATE(data)->hBitmap)
{
if (hold == PRIVATE(data)->hBitmap)
DeleteObject(PRIVATE(data)->hBitmap);
else
WINE_FIXME("leak\n");
}
PRIVATE(data)->hBitmap = hnew;
WCUSER_FillMemDC(data, 0, data->curcfg.sb_height - 1);
}
/******************************************************************
* WCUSER_ResizeScreenBuffer
*
*
*/
static void WCUSER_ResizeScreenBuffer(struct inner_data* data)
{
WCUSER_NewBitmap(data);
}
/******************************************************************
* WCUSER_PosCursor
*
* Set a new position for the cursor
*/
static void WCUSER_PosCursor(const struct inner_data* data)
{
if (data->hWnd != GetFocus() || !data->curcfg.cursor_visible) return;
SetCaretPos((data->cursor.X - data->curcfg.win_pos.X) * data->curcfg.cell_width,
(data->cursor.Y - data->curcfg.win_pos.Y) * data->curcfg.cell_height);
ShowCaret(data->hWnd);
}
/******************************************************************
* WCUSER_ShapeCursor
*
* Sets a new shape for the cursor
*/
static void WCUSER_ShapeCursor(struct inner_data* data, int size, int vis, BOOL force)
{
if (force || size != data->curcfg.cursor_size)
{
if (data->curcfg.cursor_visible && data->hWnd == GetFocus()) DestroyCaret();
if (PRIVATE(data)->cursor_bitmap) DeleteObject(PRIVATE(data)->cursor_bitmap);
PRIVATE(data)->cursor_bitmap = NULL;
if (size != 100)
{
int w16b; /* number of bytes per row, aligned on word size */
BYTE* ptr;
int i, j, nbl;
w16b = ((data->curcfg.cell_width + 15) & ~15) / 8;
ptr = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, w16b * data->curcfg.cell_height);
if (!ptr) WINECON_Fatal("OOM");
nbl = max((data->curcfg.cell_height * size) / 100, 1);
for (j = data->curcfg.cell_height - nbl; j < data->curcfg.cell_height; j++)
{
for (i = 0; i < data->curcfg.cell_width; i++)
{
ptr[w16b * j + (i / 8)] |= 0x80 >> (i & 7);
}
}
PRIVATE(data)->cursor_bitmap = CreateBitmap(data->curcfg.cell_width,
data->curcfg.cell_height, 1, 1, ptr);
HeapFree(GetProcessHeap(), 0, ptr);
}
data->curcfg.cursor_size = size;
data->curcfg.cursor_visible = -1;
}
vis = (vis) ? TRUE : FALSE;
if (force || vis != data->curcfg.cursor_visible)
{
data->curcfg.cursor_visible = vis;
if (data->hWnd == GetFocus())
{
if (vis)
{
CreateCaret(data->hWnd, PRIVATE(data)->cursor_bitmap,
data->curcfg.cell_width, data->curcfg.cell_height);
WCUSER_PosCursor(data);
}
else
{
DestroyCaret();
}
}
}
WINECON_DumpConfig("crsr", &data->curcfg);
}
/******************************************************************
* WCUSER_ComputePositions
*
* Recomputes all the components (mainly scroll bars) positions
*/
static void WCUSER_ComputePositions(struct inner_data* data)
{
RECT r;
int dx, dy;
/* compute window size from desired client size */
r.left = r.top = 0;
r.right = data->curcfg.win_width * data->curcfg.cell_width;
r.bottom = data->curcfg.win_height * data->curcfg.cell_height;
if (IsRectEmpty(&r)) return;
AdjustWindowRect(&r, GetWindowLong(data->hWnd, GWL_STYLE), FALSE);
dx = dy = 0;
if (data->curcfg.sb_width > data->curcfg.win_width)
{
dy = GetSystemMetrics(SM_CYHSCROLL);
SetScrollRange(data->hWnd, SB_HORZ, 0,
data->curcfg.sb_width - data->curcfg.win_width, FALSE);
SetScrollPos(data->hWnd, SB_HORZ, 0, FALSE); /* FIXME */
ShowScrollBar(data->hWnd, SB_HORZ, TRUE);
}
else
{
ShowScrollBar(data->hWnd, SB_HORZ, FALSE);
}
if (data->curcfg.sb_height > data->curcfg.win_height)
{
dx = GetSystemMetrics(SM_CXVSCROLL);
SetScrollRange(data->hWnd, SB_VERT, 0,
data->curcfg.sb_height - data->curcfg.win_height, FALSE);
SetScrollPos(data->hWnd, SB_VERT, 0, FALSE); /* FIXME */
ShowScrollBar(data->hWnd, SB_VERT, TRUE);
}
else
{
ShowScrollBar(data->hWnd, SB_VERT, FALSE);
}
SetWindowPos(data->hWnd, 0, 0, 0, r.right - r.left + dx, r.bottom - r.top + dy,
SWP_NOMOVE|SWP_NOZORDER);
WCUSER_ShapeCursor(data, data->curcfg.cursor_size, data->curcfg.cursor_visible, TRUE);
WCUSER_PosCursor(data);
}
/******************************************************************
* WCUSER_SetTitle
*
* Sets the title to the wine console
*/
static void WCUSER_SetTitle(const struct inner_data* data)
{
WCHAR buffer[256];
if (WINECON_GetConsoleTitle(data->hConIn, buffer, sizeof(buffer)))
SetWindowText(data->hWnd, buffer);
}
void WCUSER_DumpLogFont(const char* pfx, const LOGFONT* lf, DWORD ft)
{
WINE_TRACE_(wc_font)("%s %s%s%s%s\n"
"\tlf.lfHeight=%d lf.lfWidth=%d lf.lfEscapement=%d lf.lfOrientation=%d\n"
"\tlf.lfWeight=%d lf.lfItalic=%u lf.lfUnderline=%u lf.lfStrikeOut=%u\n"
"\tlf.lfCharSet=%u lf.lfOutPrecision=%u lf.lfClipPrecision=%u lf.lfQuality=%u\n"
"\tlf->lfPitchAndFamily=%u lf.lfFaceName=%s\n",
pfx,
(ft & RASTER_FONTTYPE) ? "raster" : "",
(ft & TRUETYPE_FONTTYPE) ? "truetype" : "",
((ft & (RASTER_FONTTYPE|TRUETYPE_FONTTYPE)) == 0) ? "vector" : "",
(ft & DEVICE_FONTTYPE) ? "|device" : "",
lf->lfHeight, lf->lfWidth, lf->lfEscapement, lf->lfOrientation,
lf->lfWeight, lf->lfItalic, lf->lfUnderline, lf->lfStrikeOut, lf->lfCharSet,
lf->lfOutPrecision, lf->lfClipPrecision, lf->lfQuality, lf->lfPitchAndFamily,
wine_dbgstr_w(lf->lfFaceName));
}
void WCUSER_DumpTextMetric(const TEXTMETRIC* tm, DWORD ft)
{
WINE_TRACE_(wc_font)("%s%s%s%s\n"
"\ttmHeight=%d tmAscent=%d tmDescent=%d tmInternalLeading=%d tmExternalLeading=%d\n"
"\ttmAveCharWidth=%d tmMaxCharWidth=%d tmWeight=%d tmOverhang=%d\n"
"\ttmDigitizedAspectX=%d tmDigitizedAspectY=%d\n"
"\ttmFirstChar=%d tmLastChar=%d tmDefaultChar=%d tmBreakChar=%d\n"
"\ttmItalic=%u tmUnderlined=%u tmStruckOut=%u tmPitchAndFamily=%u tmCharSet=%u\n",
(ft & RASTER_FONTTYPE) ? "raster" : "",
(ft & TRUETYPE_FONTTYPE) ? "truetype" : "",
((ft & (RASTER_FONTTYPE|TRUETYPE_FONTTYPE)) == 0) ? "vector" : "",
(ft & DEVICE_FONTTYPE) ? "|device" : "",
tm->tmHeight, tm->tmAscent, tm->tmDescent, tm->tmInternalLeading, tm->tmExternalLeading, tm->tmAveCharWidth,
tm->tmMaxCharWidth, tm->tmWeight, tm->tmOverhang, tm->tmDigitizedAspectX, tm->tmDigitizedAspectY,
tm->tmFirstChar, tm->tmLastChar, tm->tmDefaultChar, tm->tmBreakChar, tm->tmItalic, tm->tmUnderlined, tm->tmStruckOut,
tm->tmPitchAndFamily, tm->tmCharSet);
}
/******************************************************************
* WCUSER_AreFontsEqual
*
*
*/
static BOOL WCUSER_AreFontsEqual(const struct config_data* config, const LOGFONT* lf)
{
return lf->lfHeight == config->cell_height &&
lf->lfWeight == config->font_weight &&
!lf->lfItalic && !lf->lfUnderline && !lf->lfStrikeOut &&
!lstrcmp(lf->lfFaceName, config->face_name);
}
struct font_chooser
{
struct inner_data* data;
int done;
};
/******************************************************************
* WCUSER_ValidateFontMetric
*
* Returns true if the font described in tm is usable as a font for the renderer
*/
BOOL WCUSER_ValidateFontMetric(const struct inner_data* data, const TEXTMETRIC* tm, DWORD fontType)
{
BOOL ret = TRUE;
if (fontType & RASTER_FONTTYPE)
ret = (tm->tmMaxCharWidth * data->curcfg.win_width < GetSystemMetrics(SM_CXSCREEN) &&
tm->tmHeight * data->curcfg.win_height < GetSystemMetrics(SM_CYSCREEN));
return ret && !tm->tmItalic && !tm->tmUnderlined && !tm->tmStruckOut &&
(tm->tmCharSet == DEFAULT_CHARSET || tm->tmCharSet == g_uiDefaultCharset);
}
/******************************************************************
* WCUSER_ValidateFont
*
* Returns true if the font family described in lf is usable as a font for the renderer
*/
BOOL WCUSER_ValidateFont(const struct inner_data* data, const LOGFONT* lf)
{
return (lf->lfPitchAndFamily & 3) == FIXED_PITCH &&
/* (lf->lfPitchAndFamily & 0xF0) == FF_MODERN && */
(lf->lfCharSet == DEFAULT_CHARSET || lf->lfCharSet == g_uiDefaultCharset);
}
/******************************************************************
* get_first_font_enum_2
* get_first_font_enum
*
* Helper functions to get a decent font for the renderer
*/
static int CALLBACK get_first_font_enum_2(const LOGFONT* lf, const TEXTMETRIC* tm,
DWORD FontType, LPARAM lParam)
{
struct font_chooser* fc = (struct font_chooser*)lParam;
WCUSER_DumpTextMetric(tm, FontType);
if (WCUSER_ValidateFontMetric(fc->data, tm, FontType))
{
LOGFONT mlf = *lf;
/* Use the default sizes for the font (this is needed, especially for
* TrueType fonts, so that we get a decent size, not the max size)
*/
mlf.lfWidth = fc->data->curcfg.cell_width;
mlf.lfHeight = fc->data->curcfg.cell_height;
if (WCUSER_SetFont(fc->data, &mlf))
{
struct config_data defcfg;
WCUSER_DumpLogFont("InitChoosing: ", &mlf, FontType);
fc->done = 1;
/* since we've modified the current config with new font information,
* set this information as the new default.
*/
WINECON_RegLoad(NULL, &defcfg);
defcfg.cell_width = fc->data->curcfg.cell_width;
defcfg.cell_height = fc->data->curcfg.cell_height;
lstrcpyW(defcfg.face_name, fc->data->curcfg.face_name);
/* Force also its writing back to the registry so that we can get it
* the next time.
*/
WINECON_RegSave(&defcfg);
return 0;
}
}
return 1;
}
static int CALLBACK get_first_font_enum(const LOGFONT* lf, const TEXTMETRIC* tm,
DWORD FontType, LPARAM lParam)
{
struct font_chooser* fc = (struct font_chooser*)lParam;
WCUSER_DumpLogFont("InitFamily: ", lf, FontType);
if (WCUSER_ValidateFont(fc->data, lf))
{
EnumFontFamilies(PRIVATE(fc->data)->hMemDC, lf->lfFaceName,
get_first_font_enum_2, lParam);
return !fc->done; /* we just need the first matching one... */
}
return 1;
}
/******************************************************************
* WCUSER_CopyFont
*
* get the relevant information from the font described in lf and store them
* in config
*/
HFONT WCUSER_CopyFont(struct config_data* config, HWND hWnd, const LOGFONT* lf, LONG* el)
{
TEXTMETRIC tm;
HDC hDC;
HFONT hFont, hOldFont;
int w, i, buf[256];
if (!(hDC = GetDC(hWnd))) return NULL;
if (!(hFont = CreateFontIndirect(lf))) goto err1;
hOldFont = SelectObject(hDC, hFont);
GetTextMetrics(hDC, &tm);
/* FIXME:
* the current freetype engine (at least 2.0.x with x <= 8) and its implementation
* in Wine don't return adequate values for fixed fonts
* In Windows, those fonts are expected to return the same value for
* - the average width
* - the largest width
* - the width of all characters in the font
* This isn't true in Wine. As a temporary workaround, we get as the width of the
* cell, the width of the first character in the font, after checking that all
* characters in the font have the same width (I hear paranoïa coming)
* when this gets fixed, the code should be using tm.tmAveCharWidth
* or tm.tmMaxCharWidth as the cell width.
*/
GetCharWidth32(hDC, tm.tmFirstChar, tm.tmFirstChar, &w);
for (i = tm.tmFirstChar + 1; i <= tm.tmLastChar; i += sizeof(buf) / sizeof(buf[0]))
{
int j, k;
k = min(tm.tmLastChar - i, sizeof(buf) / sizeof(buf[0]) - 1);
GetCharWidth32(hDC, i, i + k, buf);
for (j = 0; j <= k; j++)
{
if (buf[j] != w)
{
WINE_WARN("Non uniform cell width: [%d]=%d [%d]=%d\n"
"This may be caused by old freetype libraries, >= 2.0.8 is recommended\n",
i + j, buf[j], tm.tmFirstChar, w);
goto err;
}
}
}
SelectObject(hDC, hOldFont);
ReleaseDC(hWnd, hDC);
config->cell_width = w;
config->cell_height = tm.tmHeight + tm.tmExternalLeading;
config->font_weight = tm.tmWeight;
lstrcpy(config->face_name, lf->lfFaceName);
if (el) *el = tm.tmExternalLeading;
return hFont;
err:
if (hDC && hOldFont) SelectObject(hDC, hOldFont);
if (hFont) DeleteObject(hFont);
err1:
if (hDC) ReleaseDC(hWnd, hDC);
return NULL;
}
/******************************************************************
* WCUSER_FillLogFont
*
*
*/
void WCUSER_FillLogFont(LOGFONT* lf, const WCHAR* name, UINT height, UINT weight)
{
lf->lfHeight = height;
lf->lfWidth = 0;
lf->lfEscapement = 0;
lf->lfOrientation = 0;
lf->lfWeight = weight;
lf->lfItalic = FALSE;
lf->lfUnderline = FALSE;
lf->lfStrikeOut = FALSE;
lf->lfCharSet = DEFAULT_CHARSET;
lf->lfOutPrecision = OUT_DEFAULT_PRECIS;
lf->lfClipPrecision = CLIP_DEFAULT_PRECIS;
lf->lfQuality = DEFAULT_QUALITY;
lf->lfPitchAndFamily = FIXED_PITCH | FF_DONTCARE;
lstrcpy(lf->lfFaceName, name);
}
/******************************************************************
* WCUSER_SetFont
*
* sets logfont as the new font for the console
*/
BOOL WCUSER_SetFont(struct inner_data* data, const LOGFONT* logfont)
{
HFONT hFont;
LONG el;
if (PRIVATE(data)->hFont != 0 && WCUSER_AreFontsEqual(&data->curcfg, logfont))
return TRUE;
hFont = WCUSER_CopyFont(&data->curcfg, data->hWnd, logfont, &el);
if (!hFont) {WINE_ERR("wrong font\n"); return FALSE;}
if (PRIVATE(data)->hFont) DeleteObject(PRIVATE(data)->hFont);
PRIVATE(data)->hFont = hFont;
PRIVATE(data)->ext_leading = el;
WCUSER_ComputePositions(data);
WCUSER_NewBitmap(data);
InvalidateRect(data->hWnd, NULL, FALSE);
UpdateWindow(data->hWnd);
return TRUE;
}
/******************************************************************
* WCUSER_SetFontPmt
*
* Sets a new font for the console.
* In fact a wrapper for WCUSER_SetFont
*/
static void WCUSER_SetFontPmt(struct inner_data* data, const WCHAR* font,
unsigned height, unsigned weight)
{
LOGFONT lf;
struct font_chooser fc;
WINE_TRACE_(wc_font)("=> %s h=%u w=%u\n",
wine_dbgstr_wn(font, -1), height, weight);
if (font[0] != '\0' && height != 0 && weight != 0)
{
WCUSER_FillLogFont(&lf, font, height, weight);
if (WCUSER_SetFont(data, &lf))
{
WCUSER_DumpLogFont("InitReuses: ", &lf, 0);
return;
}
}
/* try to find an acceptable font */
WINE_WARN("Couldn't match the font from registry... trying to find one\n");
fc.data = data;
fc.done = 0;
EnumFontFamilies(PRIVATE(data)->hMemDC, NULL, get_first_font_enum, (LPARAM)&fc);
if (!fc.done) WINECON_Fatal("Couldn't find a decent font, aborting\n");
}
/******************************************************************
* WCUSER_GetCell
*
* Get a cell from a relative coordinate in window (takes into
* account the scrolling)
*/
static COORD WCUSER_GetCell(const struct inner_data* data, LPARAM lParam)
{
COORD c;
c.X = data->curcfg.win_pos.X + (short)LOWORD(lParam) / data->curcfg.cell_width;
c.Y = data->curcfg.win_pos.Y + (short)HIWORD(lParam) / data->curcfg.cell_height;
return c;
}
/******************************************************************
* WCUSER_GetSelectionRect
*
* Get the selection rectangle
*/
static void WCUSER_GetSelectionRect(const struct inner_data* data, LPRECT r)
{
r->left = (min(PRIVATE(data)->selectPt1.X, PRIVATE(data)->selectPt2.X) - data->curcfg.win_pos.X) * data->curcfg.cell_width;
r->top = (min(PRIVATE(data)->selectPt1.Y, PRIVATE(data)->selectPt2.Y) - data->curcfg.win_pos.Y) * data->curcfg.cell_height;
r->right = (max(PRIVATE(data)->selectPt1.X, PRIVATE(data)->selectPt2.X) + 1 - data->curcfg.win_pos.X) * data->curcfg.cell_width;
r->bottom = (max(PRIVATE(data)->selectPt1.Y, PRIVATE(data)->selectPt2.Y) + 1 - data->curcfg.win_pos.Y) * data->curcfg.cell_height;
}
/******************************************************************
* WCUSER_SetSelection
*
*
*/
static void WCUSER_SetSelection(const struct inner_data* data, HDC hRefDC)
{
HDC hDC;
RECT r;
WCUSER_GetSelectionRect(data, &r);
hDC = hRefDC ? hRefDC : GetDC(data->hWnd);
if (hDC)
{
if (data->hWnd == GetFocus() && data->curcfg.cursor_visible)
HideCaret(data->hWnd);
InvertRect(hDC, &r);
if (hDC != hRefDC)
ReleaseDC(data->hWnd, hDC);
if (data->hWnd == GetFocus() && data->curcfg.cursor_visible)
ShowCaret(data->hWnd);
}
}
/******************************************************************
* WCUSER_MoveSelection
*
*
*/
static void WCUSER_MoveSelection(struct inner_data* data, COORD c1, COORD c2)
{
RECT r;
HDC hDC;
if (c1.X < 0 || c1.X >= data->curcfg.sb_width ||
c2.X < 0 || c2.X >= data->curcfg.sb_width ||
c1.Y < 0 || c1.Y >= data->curcfg.sb_height ||
c2.Y < 0 || c2.Y >= data->curcfg.sb_height)
return;
WCUSER_GetSelectionRect(data, &r);
hDC = GetDC(data->hWnd);
if (hDC)
{
if (data->hWnd == GetFocus() && data->curcfg.cursor_visible)
HideCaret(data->hWnd);
InvertRect(hDC, &r);
}
PRIVATE(data)->selectPt1 = c1;
PRIVATE(data)->selectPt2 = c2;
if (hDC)
{
WCUSER_GetSelectionRect(data, &r);
InvertRect(hDC, &r);
ReleaseDC(data->hWnd, hDC);
if (data->hWnd == GetFocus() && data->curcfg.cursor_visible)
ShowCaret(data->hWnd);
}
}
/******************************************************************
* WCUSER_CopySelectionToClipboard
*
* Copies the current selection into the clipboard
*/
static void WCUSER_CopySelectionToClipboard(const struct inner_data* data)
{
HANDLE hMem;
LPWSTR p;
unsigned w, h;
w = abs(PRIVATE(data)->selectPt1.X - PRIVATE(data)->selectPt2.X) + 2;
h = abs(PRIVATE(data)->selectPt1.Y - PRIVATE(data)->selectPt2.Y) + 1;
if (!OpenClipboard(data->hWnd)) return;
EmptyClipboard();
hMem = GlobalAlloc(GMEM_MOVEABLE, (w * h) * sizeof(WCHAR));
if (hMem && (p = GlobalLock(hMem)))
{
COORD c;
int y;
c.X = min(PRIVATE(data)->selectPt1.X, PRIVATE(data)->selectPt2.X);
c.Y = min(PRIVATE(data)->selectPt1.Y, PRIVATE(data)->selectPt2.Y);
for (y = 0; y < h; y++, c.Y++)
{
LPWSTR end;
ReadConsoleOutputCharacter(data->hConOut, p, w - 1, c, NULL);
/* strip spaces from the end of the line */
end = p + w - 1;
while (end > p && *(end - 1) == ' ')
end--;
*end = (y < h - 1) ? '\n' : '\0';
p = end + 1;
}
GlobalUnlock(hMem);
SetClipboardData(CF_UNICODETEXT, hMem);
}
CloseClipboard();
}
/******************************************************************
* WCUSER_PasteFromClipboard
*
*
*/
static void WCUSER_PasteFromClipboard(struct inner_data* data)
{
HANDLE h;
WCHAR* ptr;
if (!OpenClipboard(data->hWnd)) return;
h = GetClipboardData(CF_UNICODETEXT);
if (h && (ptr = GlobalLock(h)))
{
int i, len = GlobalSize(h) / sizeof(WCHAR);
INPUT_RECORD ir[2];
DWORD n;
SHORT sh;
ir[0].EventType = KEY_EVENT;
ir[0].Event.KeyEvent.wRepeatCount = 0;
ir[0].Event.KeyEvent.dwControlKeyState = 0;
ir[0].Event.KeyEvent.bKeyDown = TRUE;
/* generate the corresponding input records */
for (i = 0; i < len; i++)
{
/* FIXME: the modifying keys are not generated (shift, ctrl...) */
sh = VkKeyScan(ptr[i]);
ir[0].Event.KeyEvent.wVirtualKeyCode = LOBYTE(sh);
ir[0].Event.KeyEvent.wVirtualScanCode = MapVirtualKey(LOBYTE(sh), 0);
ir[0].Event.KeyEvent.uChar.UnicodeChar = ptr[i];
ir[1] = ir[0];
ir[1].Event.KeyEvent.bKeyDown = FALSE;
WriteConsoleInput(data->hConIn, ir, 2, &n);
}
GlobalUnlock(h);
}
CloseClipboard();
}
/******************************************************************
* WCUSER_Refresh
*
*
*/
static void WCUSER_Refresh(const struct inner_data* data, int tp, int bm)
{
WCUSER_FillMemDC(data, tp, bm);
if (data->curcfg.win_pos.Y <= bm && data->curcfg.win_pos.Y + data->curcfg.win_height >= tp)
{
RECT r;
r.left = 0;
r.right = data->curcfg.win_width * data->curcfg.cell_width;
r.top = (tp - data->curcfg.win_pos.Y) * data->curcfg.cell_height;
r.bottom = (bm - data->curcfg.win_pos.Y + 1) * data->curcfg.cell_height;
InvalidateRect(data->hWnd, &r, FALSE);
UpdateWindow(data->hWnd);
}
}
/******************************************************************
* WCUSER_Paint
*
*
*/
static void WCUSER_Paint(const struct inner_data* data)
{
PAINTSTRUCT ps;
BeginPaint(data->hWnd, &ps);
BitBlt(ps.hdc, 0, 0,
data->curcfg.win_width * data->curcfg.cell_width,
data->curcfg.win_height * data->curcfg.cell_height,
PRIVATE(data)->hMemDC,
data->curcfg.win_pos.X * data->curcfg.cell_width,
data->curcfg.win_pos.Y * data->curcfg.cell_height,
SRCCOPY);
if (PRIVATE(data)->has_selection)
WCUSER_SetSelection(data, ps.hdc);
EndPaint(data->hWnd, &ps);
}
/******************************************************************
* WCUSER_Scroll
*
*
*/
static void WCUSER_Scroll(struct inner_data* data, int pos, BOOL horz)
{
if (horz)
{
SetScrollPos(data->hWnd, SB_HORZ, pos, TRUE);
data->curcfg.win_pos.X = pos;
}
else
{
SetScrollPos(data->hWnd, SB_VERT, pos, TRUE);
data->curcfg.win_pos.Y = pos;
}
InvalidateRect(data->hWnd, NULL, FALSE);
}
/******************************************************************
* WCUSER_FillMenu
*
*
*/
static BOOL WCUSER_FillMenu(HMENU hMenu, BOOL sep)
{
HMENU hSubMenu;
HINSTANCE hInstance = GetModuleHandle(NULL);
WCHAR buff[256];
if (!hMenu) return FALSE;
/* FIXME: error handling & memory cleanup */
hSubMenu = CreateMenu();
if (!hSubMenu) return FALSE;
LoadString(hInstance, IDS_MARK, buff, sizeof(buff) / sizeof(WCHAR));
InsertMenu(hSubMenu, -1, MF_BYPOSITION|MF_STRING, IDS_MARK, buff);
LoadString(hInstance, IDS_COPY, buff, sizeof(buff) / sizeof(WCHAR));
InsertMenu(hSubMenu, -1, MF_BYPOSITION|MF_STRING, IDS_COPY, buff);
LoadString(hInstance, IDS_PASTE, buff, sizeof(buff) / sizeof(WCHAR));
InsertMenu(hSubMenu, -1, MF_BYPOSITION|MF_STRING, IDS_PASTE, buff);
LoadString(hInstance, IDS_SELECTALL, buff, sizeof(buff) / sizeof(WCHAR));
InsertMenu(hSubMenu, -1, MF_BYPOSITION|MF_STRING, IDS_SELECTALL, buff);
LoadString(hInstance, IDS_SCROLL, buff, sizeof(buff) / sizeof(WCHAR));
InsertMenu(hSubMenu, -1, MF_BYPOSITION|MF_STRING, IDS_SCROLL, buff);
LoadString(hInstance, IDS_SEARCH, buff, sizeof(buff) / sizeof(WCHAR));
InsertMenu(hSubMenu, -1, MF_BYPOSITION|MF_STRING, IDS_SEARCH, buff);
if (sep) InsertMenu(hMenu, -1, MF_BYPOSITION|MF_SEPARATOR, 0, NULL);
LoadString(hInstance, IDS_EDIT, buff, sizeof(buff) / sizeof(WCHAR));
InsertMenu(hMenu, -1, MF_BYPOSITION|MF_STRING|MF_POPUP, (UINT_PTR)hSubMenu, buff);
LoadString(hInstance, IDS_DEFAULT, buff, sizeof(buff) / sizeof(WCHAR));
InsertMenu(hMenu, -1, MF_BYPOSITION|MF_STRING, IDS_DEFAULT, buff);
LoadString(hInstance, IDS_PROPERTIES, buff, sizeof(buff) / sizeof(WCHAR));
InsertMenu(hMenu, -1, MF_BYPOSITION|MF_STRING, IDS_PROPERTIES, buff);
return TRUE;
}
/******************************************************************
* WCUSER_SetMenuDetails
*
* Grays / ungrays the menu items according to their state
*/
static void WCUSER_SetMenuDetails(const struct inner_data* data, HMENU hMenu)
{
if (!hMenu) {WINE_ERR("Issue in getting menu bits\n");return;}
EnableMenuItem(hMenu, IDS_COPY,
MF_BYCOMMAND|(PRIVATE(data)->has_selection ? MF_ENABLED : MF_GRAYED));
EnableMenuItem(hMenu, IDS_PASTE,
MF_BYCOMMAND|(IsClipboardFormatAvailable(CF_UNICODETEXT)
? MF_ENABLED : MF_GRAYED));
EnableMenuItem(hMenu, IDS_SCROLL, MF_BYCOMMAND|MF_GRAYED);
EnableMenuItem(hMenu, IDS_SEARCH, MF_BYCOMMAND|MF_GRAYED);
}
/******************************************************************
* WCUSER_Create
*
* Creates the window for the rendering
*/
static LRESULT WCUSER_Create(HWND hWnd, LPCREATESTRUCT lpcs)
{
struct inner_data* data;
HMENU hSysMenu;
data = lpcs->lpCreateParams;
SetWindowLongPtr(hWnd, 0L, (DWORD_PTR)data);
data->hWnd = hWnd;
hSysMenu = GetSystemMenu(hWnd, FALSE);
if (!hSysMenu) return 0;
PRIVATE(data)->hPopMenu = CreatePopupMenu();
if (!PRIVATE(data)->hPopMenu) return 0;
WCUSER_FillMenu(hSysMenu, TRUE);
WCUSER_FillMenu(PRIVATE(data)->hPopMenu, FALSE);
PRIVATE(data)->hMemDC = CreateCompatibleDC(0);
if (!PRIVATE(data)->hMemDC) {WINE_ERR("no mem dc\n");return 0;}
data->curcfg.quick_edit = FALSE;
return 0;
}
/******************************************************************
* WCUSER_GetCtrlKeyState
*
* Get the console bit mask equivalent to the VK_ status in keyState
*/
static DWORD WCUSER_GetCtrlKeyState(BYTE* keyState)
{
DWORD ret = 0;
GetKeyboardState(keyState);
if (keyState[VK_SHIFT] & 0x80) ret |= SHIFT_PRESSED;
if (keyState[VK_LCONTROL] & 0x80) ret |= LEFT_CTRL_PRESSED;
if (keyState[VK_RCONTROL] & 0x80) ret |= RIGHT_CTRL_PRESSED;
if (keyState[VK_LMENU] & 0x80) ret |= LEFT_ALT_PRESSED;
if (keyState[VK_RMENU] & 0x80) ret |= RIGHT_ALT_PRESSED;
if (keyState[VK_CAPITAL] & 0x01) ret |= CAPSLOCK_ON;
if (keyState[VK_NUMLOCK] & 0x01) ret |= NUMLOCK_ON;
if (keyState[VK_SCROLL] & 0x01) ret |= SCROLLLOCK_ON;
return ret;
}
/******************************************************************
* WCUSER_HandleSelectionKey
*
* Handles keys while selecting an area
*/
static void WCUSER_HandleSelectionKey(struct inner_data* data, BOOL down,
WPARAM wParam, LPARAM lParam)
{
BYTE keyState[256];
DWORD state = WCUSER_GetCtrlKeyState(keyState) & ~(CAPSLOCK_ON|NUMLOCK_ON|SCROLLLOCK_ON);
COORD c1, c2;
if (!down) return;
switch (state)
{
case 0:
switch (wParam)
{
case VK_RETURN:
PRIVATE(data)->has_selection = FALSE;
WCUSER_SetSelection(data, 0);
WCUSER_CopySelectionToClipboard(data);
return;
case VK_RIGHT:
c1 = PRIVATE(data)->selectPt1;
c2 = PRIVATE(data)->selectPt2;
c1.X++; c2.X++;
WCUSER_MoveSelection(data, c1, c2);
return;
case VK_LEFT:
c1 = PRIVATE(data)->selectPt1;
c2 = PRIVATE(data)->selectPt2;
c1.X--; c2.X--;
WCUSER_MoveSelection(data, c1, c2);
return;
case VK_UP:
c1 = PRIVATE(data)->selectPt1;
c2 = PRIVATE(data)->selectPt2;
c1.Y--; c2.Y--;
WCUSER_MoveSelection(data, c1, c2);
return;
case VK_DOWN:
c1 = PRIVATE(data)->selectPt1;
c2 = PRIVATE(data)->selectPt2;
c1.Y++; c2.Y++;
WCUSER_MoveSelection(data, c1, c2);
return;
}
break;
case SHIFT_PRESSED:
switch (wParam)
{
case VK_RIGHT:
c1 = PRIVATE(data)->selectPt1;
c2 = PRIVATE(data)->selectPt2;
c2.X++;
WCUSER_MoveSelection(data, c1, c2);
return;
case VK_LEFT:
c1 = PRIVATE(data)->selectPt1;
c2 = PRIVATE(data)->selectPt2;
c2.X--;
WCUSER_MoveSelection(data, c1, c2);
return;
case VK_UP:
c1 = PRIVATE(data)->selectPt1;
c2 = PRIVATE(data)->selectPt2;
c2.Y--;
WCUSER_MoveSelection(data, c1, c2);
return;
case VK_DOWN:
c1 = PRIVATE(data)->selectPt1;
c2 = PRIVATE(data)->selectPt2;
c2.Y++;
WCUSER_MoveSelection(data, c1, c2);
return;
}
break;
}
if (wParam < VK_SPACE) /* Shift, Alt, Ctrl, Num Lock etc. */
return;
WCUSER_SetSelection(data, 0);
PRIVATE(data)->has_selection = FALSE;
}
/******************************************************************
* WCUSER_GenerateKeyInputRecord
*
* generates input_record from windows WM_KEYUP/WM_KEYDOWN messages
*/
static void WCUSER_GenerateKeyInputRecord(struct inner_data* data, BOOL down,
WPARAM wParam, LPARAM lParam)
{
INPUT_RECORD ir;
DWORD n;
WCHAR buf[2];
static WCHAR last; /* keep last char seen as feed for key up message */
BYTE keyState[256];
ir.EventType = KEY_EVENT;
ir.Event.KeyEvent.bKeyDown = down;
ir.Event.KeyEvent.wRepeatCount = LOWORD(lParam);
ir.Event.KeyEvent.wVirtualKeyCode = wParam;
ir.Event.KeyEvent.wVirtualScanCode = HIWORD(lParam) & 0xFF;
ir.Event.KeyEvent.uChar.UnicodeChar = 0;
ir.Event.KeyEvent.dwControlKeyState = WCUSER_GetCtrlKeyState(keyState);
if (lParam & (1L << 24)) ir.Event.KeyEvent.dwControlKeyState |= ENHANCED_KEY;
if (down)
{
switch (ToUnicode(wParam, HIWORD(lParam), keyState, buf, 2, 0))
{
case 2:
/* FIXME... should generate two events... */
/* fall thru */
case 1:
last = buf[0];
break;
default:
last = 0;
break;
}
}
ir.Event.KeyEvent.uChar.UnicodeChar = last; /* FIXME: HACKY... and buggy because it should be a stack, not a single value */
if (!down) last = 0;
WriteConsoleInput(data->hConIn, &ir, 1, &n);
}
/******************************************************************
* WCUSER_GenerateMouseInputRecord
*
*
*/
static void WCUSER_GenerateMouseInputRecord(struct inner_data* data, COORD c,
WPARAM wParam, DWORD event)
{
INPUT_RECORD ir;
BYTE keyState[256];
DWORD mode, n;
/* MOUSE_EVENTs shouldn't be sent unless ENABLE_MOUSE_INPUT is active */
if (!GetConsoleMode(data->hConIn, &mode) || !(mode & ENABLE_MOUSE_INPUT))
return;
ir.EventType = MOUSE_EVENT;
ir.Event.MouseEvent.dwMousePosition = c;
ir.Event.MouseEvent.dwButtonState = 0;
if (wParam & MK_LBUTTON) ir.Event.MouseEvent.dwButtonState |= FROM_LEFT_1ST_BUTTON_PRESSED;
if (wParam & MK_MBUTTON) ir.Event.MouseEvent.dwButtonState |= FROM_LEFT_2ND_BUTTON_PRESSED;
if (wParam & MK_RBUTTON) ir.Event.MouseEvent.dwButtonState |= RIGHTMOST_BUTTON_PRESSED;
if (wParam & MK_CONTROL) ir.Event.MouseEvent.dwButtonState |= LEFT_CTRL_PRESSED;
if (wParam & MK_SHIFT) ir.Event.MouseEvent.dwButtonState |= SHIFT_PRESSED;
if (event == MOUSE_WHEELED) ir.Event.MouseEvent.dwButtonState |= wParam & 0xFFFF0000;
ir.Event.MouseEvent.dwControlKeyState = WCUSER_GetCtrlKeyState(keyState);
ir.Event.MouseEvent.dwEventFlags = event;
WriteConsoleInput(data->hConIn, &ir, 1, &n);
}
/******************************************************************
* WCUSER_Proc
*
*
*/
static LRESULT CALLBACK WCUSER_Proc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
struct inner_data* data = (struct inner_data*)GetWindowLongPtr(hWnd, 0);
switch (uMsg)
{
case WM_CREATE:
return WCUSER_Create(hWnd, (LPCREATESTRUCT)lParam);
case WM_DESTROY:
data->hWnd = 0;
PostQuitMessage(0);
break;
case WM_PAINT:
WCUSER_Paint(data);
break;
case WM_KEYDOWN:
case WM_KEYUP:
if (PRIVATE(data)->has_selection)
WCUSER_HandleSelectionKey(data, uMsg == WM_KEYDOWN, wParam, lParam);
else
WCUSER_GenerateKeyInputRecord(data, uMsg == WM_KEYDOWN, wParam, lParam);
break;
case WM_SYSKEYDOWN:
case WM_SYSKEYUP:
WCUSER_GenerateKeyInputRecord(data, uMsg == WM_SYSKEYDOWN, wParam, lParam);
break;
case WM_LBUTTONDOWN:
if (data->curcfg.quick_edit || PRIVATE(data)->has_selection)
{
if (PRIVATE(data)->has_selection)
WCUSER_SetSelection(data, 0);
if (data->curcfg.quick_edit && PRIVATE(data)->has_selection)
{
PRIVATE(data)->has_selection = FALSE;
}
else
{
PRIVATE(data)->selectPt1 = PRIVATE(data)->selectPt2 = WCUSER_GetCell(data, lParam);
SetCapture(data->hWnd);
WCUSER_SetSelection(data, 0);
PRIVATE(data)->has_selection = TRUE;
}
}
else
{
WCUSER_GenerateMouseInputRecord(data, WCUSER_GetCell(data, lParam), wParam, 0);
}
break;
case WM_MOUSEMOVE:
if (data->curcfg.quick_edit || PRIVATE(data)->has_selection)
{
if (GetCapture() == data->hWnd && PRIVATE(data)->has_selection &&
(wParam & MK_LBUTTON))
{
WCUSER_MoveSelection(data, PRIVATE(data)->selectPt1, WCUSER_GetCell(data, lParam));
}
}
else
{
WCUSER_GenerateMouseInputRecord(data, WCUSER_GetCell(data, lParam), wParam, MOUSE_MOVED);
}
break;
case WM_LBUTTONUP:
if (data->curcfg.quick_edit || PRIVATE(data)->has_selection)
{
if (GetCapture() == data->hWnd && PRIVATE(data)->has_selection)
{
WCUSER_MoveSelection(data, PRIVATE(data)->selectPt1, WCUSER_GetCell(data, lParam));
ReleaseCapture();
}
}
else
{
WCUSER_GenerateMouseInputRecord(data, WCUSER_GetCell(data, lParam), wParam, 0);
}
break;
case WM_RBUTTONDOWN:
if ((wParam & (MK_CONTROL|MK_SHIFT)) == data->curcfg.menu_mask)
{
POINT pt;
pt.x = (short)LOWORD(lParam);
pt.y = (short)HIWORD(lParam);
ClientToScreen(hWnd, &pt);
WCUSER_SetMenuDetails(data, PRIVATE(data)->hPopMenu);
TrackPopupMenu(PRIVATE(data)->hPopMenu, TPM_LEFTALIGN|TPM_TOPALIGN,
pt.x, pt.y, 0, hWnd, NULL);
}
else
{
WCUSER_GenerateMouseInputRecord(data, WCUSER_GetCell(data, lParam), wParam, 0);
}
break;
case WM_RBUTTONUP:
/* no need to track for rbutton up when opening the popup... the event will be
* swallowed by TrackPopupMenu */
case WM_MBUTTONDOWN:
case WM_MBUTTONUP:
WCUSER_GenerateMouseInputRecord(data, WCUSER_GetCell(data, lParam), wParam, 0);
break;
case WM_LBUTTONDBLCLK:
case WM_MBUTTONDBLCLK:
case WM_RBUTTONDBLCLK:
WCUSER_GenerateMouseInputRecord(data, WCUSER_GetCell(data, lParam), wParam, DOUBLE_CLICK);
break;
case WM_SETFOCUS:
if (data->curcfg.cursor_visible)
{
CreateCaret(data->hWnd, PRIVATE(data)->cursor_bitmap,
data->curcfg.cell_width, data->curcfg.cell_height);
WCUSER_PosCursor(data);
}
break;
case WM_KILLFOCUS:
if (data->curcfg.cursor_visible)
DestroyCaret();
break;
case WM_HSCROLL:
{
int pos = data->curcfg.win_pos.X;
switch (LOWORD(wParam))
{
case SB_PAGEUP: pos -= 8; break;
case SB_PAGEDOWN: pos += 8; break;
case SB_LINEUP: pos--; break;
case SB_LINEDOWN: pos++; break;
case SB_THUMBTRACK: pos = HIWORD(wParam); break;
default: break;
}
if (pos < 0) pos = 0;
if (pos > data->curcfg.sb_width - data->curcfg.win_width)
pos = data->curcfg.sb_width - data->curcfg.win_width;
if (pos != data->curcfg.win_pos.X)
{
ScrollWindow(hWnd, (data->curcfg.win_pos.X - pos) * data->curcfg.cell_width, 0,
NULL, NULL);
data->curcfg.win_pos.X = pos;
SetScrollPos(hWnd, SB_HORZ, pos, TRUE);
UpdateWindow(hWnd);
WCUSER_PosCursor(data);
WINECON_NotifyWindowChange(data);
}
}
break;
case WM_MOUSEWHEEL:
if (data->curcfg.sb_height <= data->curcfg.win_height)
{
WCUSER_GenerateMouseInputRecord(data, WCUSER_GetCell(data, lParam), wParam, MOUSE_WHEELED);
break;
}
/* else fallthrough */
case WM_VSCROLL:
{
int pos = data->curcfg.win_pos.Y;
if (uMsg == WM_MOUSEWHEEL)
{
UINT scrollLines = 3;
SystemParametersInfoW(SPI_GETWHEELSCROLLLINES, 0, &scrollLines, 0);
scrollLines *= -GET_WHEEL_DELTA_WPARAM(wParam) / WHEEL_DELTA;
pos += scrollLines;
} else {
switch (LOWORD(wParam))
{
case SB_PAGEUP: pos -= 8; break;
case SB_PAGEDOWN: pos += 8; break;
case SB_LINEUP: pos--; break;
case SB_LINEDOWN: pos++; break;
case SB_THUMBTRACK: pos = HIWORD(wParam); break;
default: break;
}
}
if (pos < 0) pos = 0;
if (pos > data->curcfg.sb_height - data->curcfg.win_height)
pos = data->curcfg.sb_height - data->curcfg.win_height;
if (pos != data->curcfg.win_pos.Y)
{
ScrollWindow(hWnd, 0, (data->curcfg.win_pos.Y - pos) * data->curcfg.cell_height,
NULL, NULL);
data->curcfg.win_pos.Y = pos;
SetScrollPos(hWnd, SB_VERT, pos, TRUE);
UpdateWindow(hWnd);
WCUSER_PosCursor(data);
WINECON_NotifyWindowChange(data);
}
}
break;
case WM_SYSCOMMAND:
switch (wParam)
{
case IDS_DEFAULT:
WCUSER_GetProperties(data, FALSE);
break;
case IDS_PROPERTIES:
WCUSER_GetProperties(data, TRUE);
break;
default:
return DefWindowProc(hWnd, uMsg, wParam, lParam);
}
break;
case WM_COMMAND:
switch (wParam)
{
case IDS_DEFAULT:
WCUSER_GetProperties(data, FALSE);
break;
case IDS_PROPERTIES:
WCUSER_GetProperties(data, TRUE);
break;
case IDS_MARK:
PRIVATE(data)->selectPt1.X = PRIVATE(data)->selectPt1.Y = 0;
PRIVATE(data)->selectPt2.X = PRIVATE(data)->selectPt2.Y = 0;
WCUSER_SetSelection(data, 0);
PRIVATE(data)->has_selection = TRUE;
break;
case IDS_COPY:
if (PRIVATE(data)->has_selection)
{
PRIVATE(data)->has_selection = FALSE;
WCUSER_SetSelection(data, 0);
WCUSER_CopySelectionToClipboard(data);
}
break;
case IDS_PASTE:
WCUSER_PasteFromClipboard(data);
break;
case IDS_SELECTALL:
PRIVATE(data)->selectPt1.X = PRIVATE(data)->selectPt1.Y = 0;
PRIVATE(data)->selectPt2.X = (data->curcfg.sb_width - 1) * data->curcfg.cell_width;
PRIVATE(data)->selectPt2.Y = (data->curcfg.sb_height - 1) * data->curcfg.cell_height;
WCUSER_SetSelection(data, 0);
PRIVATE(data)->has_selection = TRUE;
break;
case IDS_SCROLL:
case IDS_SEARCH:
WINE_FIXME("Unhandled yet command: %lx\n", wParam);
break;
default:
return DefWindowProc(hWnd, uMsg, wParam, lParam);
}
break;
case WM_INITMENUPOPUP:
if (!HIWORD(lParam)) return DefWindowProc(hWnd, uMsg, wParam, lParam);
WCUSER_SetMenuDetails(data, GetSystemMenu(data->hWnd, FALSE));
break;
default:
return DefWindowProc(hWnd, uMsg, wParam, lParam);
}
return 0;
}
/******************************************************************
* WCUSER_DeleteBackend
*
*
*/
static void WCUSER_DeleteBackend(struct inner_data* data)
{
if (!PRIVATE(data)) return;
if (PRIVATE(data)->hMemDC) DeleteDC(PRIVATE(data)->hMemDC);
if (data->hWnd) DestroyWindow(data->hWnd);
if (PRIVATE(data)->hFont) DeleteObject(PRIVATE(data)->hFont);
if (PRIVATE(data)->cursor_bitmap) DeleteObject(PRIVATE(data)->cursor_bitmap);
if (PRIVATE(data)->hBitmap) DeleteObject(PRIVATE(data)->hBitmap);
HeapFree(GetProcessHeap(), 0, PRIVATE(data));
}
/******************************************************************
* WCUSER_MainLoop
*
*
*/
static int WCUSER_MainLoop(struct inner_data* data)
{
MSG msg;
ShowWindow(data->hWnd, data->nCmdShow);
for (;;)
{
switch (MsgWaitForMultipleObjects(1, &data->hSynchro, FALSE, INFINITE, QS_ALLINPUT))
{
case WAIT_OBJECT_0:
if (!WINECON_GrabChanges(data) && data->curcfg.exit_on_die)
PostQuitMessage(0);
break;
case WAIT_OBJECT_0+1:
/* need to use PeekMessage loop instead of simple GetMessage:
* multiple messages might have arrived in between,
* so GetMessage would lead to delayed processing */
while (PeekMessage(&msg, 0, 0, 0, PM_REMOVE))
{
if (msg.message == WM_QUIT) return 0;
WINE_TRACE("dispatching msg %04x\n", msg.message);
DispatchMessage(&msg);
}
break;
default:
WINE_ERR("got pb\n");
/* err */
break;
}
}
}
/******************************************************************
* WCUSER_InitBackend
*
* Initialisation part II: creation of window.
*
*/
enum init_return WCUSER_InitBackend(struct inner_data* data)
{
static const WCHAR wClassName[] = {'W','i','n','e','C','o','n','s','o','l','e','C','l','a','s','s',0};
WNDCLASS wndclass;
CHARSETINFO ci;
if (!TranslateCharsetInfo((DWORD *)(INT_PTR)GetACP(), &ci, TCI_SRCCODEPAGE))
return init_failed;
g_uiDefaultCharset = ci.ciCharset;
WINE_TRACE_(wc_font)("Code page %d => Default charset: %d\n", GetACP(), g_uiDefaultCharset);
data->private = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(struct inner_data_user));
if (!data->private) return init_failed;
data->fnMainLoop = WCUSER_MainLoop;
data->fnPosCursor = WCUSER_PosCursor;
data->fnShapeCursor = WCUSER_ShapeCursor;
data->fnComputePositions = WCUSER_ComputePositions;
data->fnRefresh = WCUSER_Refresh;
data->fnResizeScreenBuffer = WCUSER_ResizeScreenBuffer;
data->fnSetTitle = WCUSER_SetTitle;
data->fnSetFont = WCUSER_SetFontPmt;
data->fnScroll = WCUSER_Scroll;
data->fnDeleteBackend = WCUSER_DeleteBackend;
wndclass.style = CS_DBLCLKS;
wndclass.lpfnWndProc = WCUSER_Proc;
wndclass.cbClsExtra = 0;
wndclass.cbWndExtra = sizeof(DWORD_PTR);
wndclass.hInstance = GetModuleHandle(NULL);
wndclass.hIcon = LoadIcon(0, IDI_WINLOGO);
wndclass.hCursor = LoadCursor(0, IDC_ARROW);
wndclass.hbrBackground = GetStockObject(BLACK_BRUSH);
wndclass.lpszMenuName = NULL;
wndclass.lpszClassName = wClassName;
RegisterClass(&wndclass);
data->hWnd = CreateWindow(wndclass.lpszClassName, NULL,
WS_OVERLAPPED|WS_CAPTION|WS_SYSMENU|WS_THICKFRAME|WS_MINIMIZEBOX|WS_HSCROLL|WS_VSCROLL,
CW_USEDEFAULT, CW_USEDEFAULT, 0, 0, 0, 0, wndclass.hInstance, data);
if (!data->hWnd) return init_not_supported;
return init_success;
}