- Sync edit control with Wine code

- Add imm32 dependency to user32, which is needed for edit control. This may not be a good solution, since Windows XP's user32.dll doesn't import imm32.dll. So maybe in future this should change to dynamic binding instead. But for now it works
- Update Wine-sync doc

This update reduces number of failing "user32_winetest.exe edit" tests from 44 to 43.

svn path=/trunk/; revision=22631
This commit is contained in:
Aleksey Bragin 2006-06-26 09:20:47 +00:00
parent 16240136f4
commit 7f0a19c743
3 changed files with 225 additions and 30 deletions

View file

@ -141,6 +141,11 @@ typedef struct
#endif
HLOCAL hloc32A; /* alias for ANSI control receiving EM_GETHANDLE
or EM_SETHANDLE */
/*
* IME Data
*/
UINT composition_len; /* length of composition, 0 == no composition */
int composition_start; /* the character position for the composition */
} EDITSTATE;
@ -203,6 +208,7 @@ static void EDIT_MoveWordForward(EDITSTATE *es, BOOL extend);
static void EDIT_PaintLine(EDITSTATE *es, HDC hdc, INT line, BOOL rev);
static INT EDIT_PaintText(EDITSTATE *es, HDC hdc, INT x, INT y, INT line, INT col, INT count, BOOL rev);
static void EDIT_SetCaretPos(EDITSTATE *es, INT pos, BOOL after_wrap);
static void EDIT_AdjustFormatRect(EDITSTATE *es);
static void EDIT_SetRectNP(EDITSTATE *es, LPRECT lprc);
static void EDIT_UnlockBuffer(EDITSTATE *es, BOOL force);
static void EDIT_UpdateScrollInfo(EDITSTATE *es);
@ -277,6 +283,7 @@ static void EDIT_WM_Timer(EDITSTATE *es);
static LRESULT EDIT_WM_VScroll(EDITSTATE *es, INT action, INT pos);
static void EDIT_UpdateText(EDITSTATE *es, LPRECT rc, BOOL bErase);
static void EDIT_UpdateTextRegion(EDITSTATE *es, HRGN hrgn, BOOL bErase);
static void EDIT_ImeComposition(HWND hwnd, LPARAM CompFlag, EDITSTATE *es);
LRESULT WINAPI EditWndProcA(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam);
LRESULT WINAPI EditWndProcW(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam);
@ -1048,6 +1055,52 @@ static LRESULT WINAPI EditWndProc_common( HWND hwnd, UINT msg,
}
}
break;
/* IME messages to make the edit control IME aware */
case WM_IME_SETCONTEXT:
break;
case WM_IME_STARTCOMPOSITION:
/*
* FIXME in IME: This message is not always sent like it should be
*/
if (es->selection_start != es->selection_end)
{
static const WCHAR empty_stringW[] = {0};
EDIT_EM_ReplaceSel(es, TRUE, empty_stringW, TRUE, TRUE);
}
es->composition_start = es->selection_end;
es->composition_len = 0;
break;
case WM_IME_COMPOSITION:
if (es->composition_len == 0)
{
if (es->selection_start != es->selection_end)
{
static const WCHAR empty_stringW[] = {0};
EDIT_EM_ReplaceSel(es, TRUE, empty_stringW, TRUE, TRUE);
}
es->composition_start = es->selection_end;
}
EDIT_ImeComposition(hwnd,lParam,es);
break;
case WM_IME_ENDCOMPOSITION:
es->composition_len= 0;
break;
case WM_IME_COMPOSITIONFULL:
break;
case WM_IME_SELECT:
break;
case WM_IME_CONTROL:
break;
default:
result = DefWindowProcT(hwnd, msg, wParam, lParam, unicode);
break;
@ -1055,6 +1108,8 @@ static LRESULT WINAPI EditWndProc_common( HWND hwnd, UINT msg,
if (es) EDIT_UnlockBuffer(es, FALSE);
//TRACE("hwnd=%p msg=%x (%s) -- 0x%08lx\n", hwnd, msg, SPY_GetMsgName(msg, hwnd), result);
return result;
}
@ -1300,7 +1355,7 @@ static void EDIT_BuildLineDefs_ML(EDITSTATE *es, INT istart, INT iend, INT delta
es->line_count--;
}
}
else
else if (delta != 0)
{
while (current_line)
{
@ -1401,17 +1456,9 @@ static void EDIT_CalcLineWidth_SL(EDITSTATE *es)
*/
static INT EDIT_CallWordBreakProc(EDITSTATE *es, INT start, INT index, INT count, INT action)
{
#ifdef __REACTOS__
INT ret;
#else
INT ret, iWndsLocks;
#endif
/* To avoid any deadlocks, all the locks on the window structures
must be suspended before the control is passed to the application */
#ifndef __REACTOS__
iWndsLocks = WIN_SuspendWndsLock();
if (es->word_break_proc16) {
HGLOBAL16 hglob16;
SEGPTR segptr;
@ -1464,9 +1511,6 @@ static INT EDIT_CallWordBreakProc(EDITSTATE *es, INT start, INT index, INT count
else
ret = EDIT_WordBreakProc(es->text + start, index, count, action);
#ifndef __REACTOS__
WIN_RestoreWndsLock(iWndsLocks);
#endif
return ret;
}
@ -1680,7 +1724,7 @@ static LPWSTR EDIT_GetPasswordPointer_SL(EDITSTATE *es)
*
* Initially the edit control allocates a HLOCAL32 buffer
* (32 bit linear memory handler). However, 16 bit application
* might send a EM_GETHANDLE message and expect a HLOCAL16 (16 bit SEG:OFF
* might send an EM_GETHANDLE message and expect a HLOCAL16 (16 bit SEG:OFF
* handler). From that moment on we have to keep using this 16 bit memory
* handler, because it is supposed to be valid at all times after EM_GETHANDLE.
* What we do is create a HLOCAL16 buffer, copy the text, and do pointer
@ -1846,7 +1890,7 @@ static void EDIT_ML_InvalidateText(EDITSTATE *es, INT start, INT end)
*
* EDIT_InvalidateText
*
* Invalidate the text from offset start upto, but not including,
* Invalidate the text from offset start up to, but not including,
* offset end. Useful for (re)painting the selection.
* Regions outside the linewidth are not invalidated.
* end == -1 means end == TextLength.
@ -2254,6 +2298,9 @@ static INT EDIT_PaintText(EDITSTATE *es, HDC dc, INT x, INT y, INT line, INT col
{
COLORREF BkColor;
COLORREF TextColor;
LOGFONTW underline_font;
HFONT hUnderline = 0;
HFONT old_font = 0;
INT ret;
INT li;
INT BkMode;
@ -2265,9 +2312,20 @@ static INT EDIT_PaintText(EDITSTATE *es, HDC dc, INT x, INT y, INT line, INT col
BkColor = GetBkColor(dc);
TextColor = GetTextColor(dc);
if (rev) {
if (es->composition_len == 0)
{
SetBkColor(dc, GetSysColor(COLOR_HIGHLIGHT));
SetTextColor(dc, GetSysColor(COLOR_HIGHLIGHTTEXT));
SetBkMode( dc, OPAQUE);
}
else
{
HFONT current = GetCurrentObject(dc,OBJ_FONT);
GetObjectW(current,sizeof(LOGFONTW),&underline_font);
underline_font.lfUnderline = TRUE;
hUnderline = CreateFontIndirectW(&underline_font);
old_font = SelectObject(dc,hUnderline);
}
}
li = EDIT_EM_LineIndex(es, line);
if (es->style & ES_MULTILINE) {
@ -2282,9 +2340,19 @@ static INT EDIT_PaintText(EDITSTATE *es, HDC dc, INT x, INT y, INT line, INT col
HeapFree(GetProcessHeap(), 0, text);
}
if (rev) {
if (es->composition_len == 0)
{
SetBkColor(dc, BkColor);
SetTextColor(dc, TextColor);
SetBkMode( dc, BkMode);
}
else
{
if (old_font)
SelectObject(dc,old_font);
if (hUnderline)
DeleteObject(hUnderline);
}
}
return ret;
}
@ -2408,9 +2476,6 @@ static void EDIT_SetRectNP(EDITSTATE *es, LPRECT rc)
*/
static void EDIT_UnlockBuffer(EDITSTATE *es, BOOL force)
{
#ifndef __REACTOS__
HINSTANCE16 hInstance = GetWindowLongW( es->hwndSelf, GWL_HINSTANCE );
#endif
/* Edit window might be already destroyed */
if(!IsWindow(es->hwndSelf))
@ -2431,11 +2496,12 @@ static void EDIT_UnlockBuffer(EDITSTATE *es, BOOL force)
if (force || (es->lock_count == 1)) {
if (es->hloc32W) {
CHAR *textA = NULL;
#ifndef __REACTOS__
BOOL _16bit = FALSE;
#endif
UINT countA = 0;
UINT countW = strlenW(es->text) + 1;
#ifndef __REACTOS__
STACK16FRAME* stack16 = NULL;
HANDLE16 oldDS = 0;
#endif
if(es->hloc32A)
{
@ -2552,7 +2618,7 @@ static void EDIT_UpdateScrollInfo(EDITSTATE *es)
*
* Find the beginning of words.
* Note: unlike the specs for a WordBreakProc, this function only
* allows to be called without linebreaks between s[0] upto
* allows to be called without linebreaks between s[0] up to
* s[count - 1]. Remember it is only called
* internally, so we can decide this for ourselves.
*
@ -3006,7 +3072,7 @@ static BOOL EDIT_EM_LineScroll_internal(EDITSTATE *es, INT dx, INT dy)
dx = es->text_width - x_offset_in_pixels;
nyoff = max(0, es->y_offset + dy);
if (nyoff >= es->line_count - lines_per_page)
nyoff = max(0,es->line_count - lines_per_page);
nyoff = max(0, es->line_count - lines_per_page);
dy = (es->y_offset - nyoff) * es->line_height;
if (dx || dy) {
RECT rc1;
@ -3469,10 +3535,6 @@ static void EDIT_EM_ScrollCaret(EDITSTATE *es)
*/
static void EDIT_EM_SetHandle(EDITSTATE *es, HLOCAL hloc)
{
#ifndef __REACTOS__
HINSTANCE16 hInstance = GetWindowLongW( es->hwndSelf, GWL_HINSTANCE );
#endif
if (!(es->style & ES_MULTILINE))
return;
@ -4142,7 +4204,7 @@ static LRESULT EDIT_WM_Create(EDITSTATE *es, LPCWSTR name)
EDIT_SetRectNP(es, &clientRect);
if (name && *name) {
EDIT_EM_ReplaceSel(es, FALSE, name, FALSE, TRUE);
EDIT_EM_ReplaceSel(es, FALSE, name, FALSE, FALSE);
/* if we insert text to the editline, the text scrolls out
* of the window, as the caret is placed after the insert
* pos normally; thus we reset es->selection... to 0 and
@ -4242,7 +4304,6 @@ static INT EDIT_WM_GetText(EDITSTATE *es, INT count, LPWSTR dst, BOOL unicode)
}
}
/*********************************************************************
*
* WM_HSCROLL
@ -4706,7 +4767,7 @@ static LRESULT EDIT_WM_NCCreate(HWND hwnd, LPCREATESTRUCTW lpcs, BOOL unicode)
if (!(es = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*es))))
return FALSE;
SetWindowLongPtrW( hwnd, 0, (LONG)es );
SetWindowLongPtrW( hwnd, 0, (LONG_PTR)es );
/*
* Note: since the EDITSTATE has not been fully initialized yet,
@ -5304,3 +5365,136 @@ static void EDIT_UpdateText(EDITSTATE *es, LPRECT rc, BOOL bErase)
}
InvalidateRect(es->hwndSelf, rc, bErase);
}
/********************************************************************
*
* The Following code is to handle inline editing from IMEs
*/
static void EDIT_GetCompositionStr(HWND hwnd, LPARAM CompFlag, EDITSTATE *es)
{
DWORD dwBufLen;
LPWSTR lpCompStr = NULL;
HIMC hIMC;
LPSTR lpCompStrAttr = NULL;
DWORD dwBufLenAttr;
if (!(hIMC = ImmGetContext(hwnd)))
return;
dwBufLen = ImmGetCompositionStringW(hIMC, GCS_COMPSTR, NULL, 0);
if (dwBufLen <= 0)
{
ImmReleaseContext(hwnd, hIMC);
return;
}
lpCompStr = HeapAlloc(GetProcessHeap(),0,dwBufLen);
if (!lpCompStr)
{
ERR("Unable to allocate IME CompositionString\n");
ImmReleaseContext(hwnd,hIMC);
return;
}
ImmGetCompositionStringW(hIMC, GCS_COMPSTR, lpCompStr, dwBufLen);
lpCompStr[dwBufLen/sizeof(WCHAR)] = 0;
if (CompFlag & GCS_COMPATTR)
{
/*
* We do not use the attributes yet. it would tell us what characters
* are in transition and which are converted or decided upon
*/
dwBufLenAttr = ImmGetCompositionStringW(hIMC, GCS_COMPATTR, NULL, 0);
if (dwBufLenAttr)
{
dwBufLenAttr ++;
lpCompStrAttr = HeapAlloc(GetProcessHeap(),0,dwBufLenAttr);
if (!lpCompStrAttr)
{
ERR("Unable to allocate IME Attribute String\n");
HeapFree(GetProcessHeap(),0,lpCompStr);
ImmReleaseContext(hwnd,hIMC);
return;
}
ImmGetCompositionStringW(hIMC,GCS_COMPATTR, lpCompStrAttr,
dwBufLenAttr);
lpCompStrAttr[dwBufLenAttr] = 0;
}
else
lpCompStrAttr = NULL;
}
/* check for change in composition start */
if (es->selection_end < es->composition_start)
es->composition_start = es->selection_end;
/* replace existing selection string */
es->selection_start = es->composition_start;
if (es->composition_len > 0)
es->selection_end = es->composition_start + es->composition_len;
else
es->selection_end = es->selection_start;
EDIT_EM_ReplaceSel(es, FALSE, lpCompStr, TRUE, TRUE);
es->composition_len = abs(es->composition_start - es->selection_end);
es->selection_start = es->composition_start;
es->selection_end = es->selection_start + es->composition_len;
HeapFree(GetProcessHeap(),0,lpCompStrAttr);
HeapFree(GetProcessHeap(),0,lpCompStr);
ImmReleaseContext(hwnd,hIMC);
}
static void EDIT_GetResultStr(HWND hwnd, EDITSTATE *es)
{
DWORD dwBufLen;
LPWSTR lpResultStr;
HIMC hIMC;
if ( !(hIMC = ImmGetContext(hwnd)))
return;
dwBufLen = ImmGetCompositionStringW(hIMC, GCS_RESULTSTR, NULL, 0);
if (dwBufLen <= 0)
{
ImmReleaseContext(hwnd, hIMC);
return;
}
lpResultStr = HeapAlloc(GetProcessHeap(),0, dwBufLen);
if (!lpResultStr)
{
ERR("Unable to alloc buffer for IME string\n");
ImmReleaseContext(hwnd, hIMC);
return;
}
ImmGetCompositionStringW(hIMC, GCS_RESULTSTR, lpResultStr, dwBufLen);
lpResultStr[dwBufLen/sizeof(WCHAR)] = 0;
/* check for change in composition start */
if (es->selection_end < es->composition_start)
es->composition_start = es->selection_end;
es->selection_start = es->composition_start;
es->selection_end = es->composition_start + es->composition_len;
EDIT_EM_ReplaceSel(es, TRUE, lpResultStr, TRUE, TRUE);
es->composition_start = es->selection_end;
es->composition_len = 0;
HeapFree(GetProcessHeap(),0,lpResultStr);
ImmReleaseContext(hwnd, hIMC);
}
static void EDIT_ImeComposition(HWND hwnd, LPARAM CompFlag, EDITSTATE *es)
{
if (CompFlag & GCS_RESULTSTR)
EDIT_GetResultStr(hwnd,es);
if (CompFlag & GCS_COMPSTR)
EDIT_GetCompositionStr(hwnd, CompFlag, es);
}

View file

@ -14,6 +14,7 @@
<library>gdi32</library>
<library>kernel32</library>
<library>advapi32</library>
<library>imm32</library>
<directory name="include">
<pch>user32.h</pch>
</directory>

View file

@ -116,7 +116,7 @@ msvcrt -
User32 -
reactos/dll/win32/user32/controls/button.c # Synced at 20060621
reactos/dll/win32/user32/controls/combo.c # Synced at 20060617
reactos/dll/win32/user32/controls/edit.c # Synced at 20051210
reactos/dll/win32/user32/controls/edit.c # Synced at 20060623
reactos/dll/win32/user32/controls/icontitle.c # Synced at 20060617
reactos/dll/win32/user32/controls/listbox.c # Synced at 20060616
reactos/dll/win32/user32/controls/scrollbar.c # Forked