diff options
Diffstat (limited to 'vcl/win/source/window')
-rw-r--r-- | vcl/win/source/window/MAKEFILE.MK | 65 | ||||
-rw-r--r-- | vcl/win/source/window/salframe.cxx | 6432 | ||||
-rw-r--r-- | vcl/win/source/window/salmenu.cxx | 413 | ||||
-rw-r--r-- | vcl/win/source/window/salobj.cxx | 841 |
4 files changed, 7751 insertions, 0 deletions
diff --git a/vcl/win/source/window/MAKEFILE.MK b/vcl/win/source/window/MAKEFILE.MK new file mode 100644 index 000000000000..9a65a5000ccf --- /dev/null +++ b/vcl/win/source/window/MAKEFILE.MK @@ -0,0 +1,65 @@ +#************************************************************************* +# +# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. +# +# Copyright 2008 by Sun Microsystems, Inc. +# +# OpenOffice.org - a multi-platform office productivity suite +# +# $RCSfile: MAKEFILE.MK,v $ +# +# $Revision: 1.14.94.2 $ +# +# This file is part of OpenOffice.org. +# +# OpenOffice.org is free software: you can redistribute it and/or modify +# it under the terms of the GNU Lesser General Public License version 3 +# only, as published by the Free Software Foundation. +# +# OpenOffice.org 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 version 3 for more details +# (a copy is included in the LICENSE file that accompanied this code). +# +# You should have received a copy of the GNU Lesser General Public License +# version 3 along with OpenOffice.org. If not, see +# <http://www.openoffice.org/license.html> +# for a copy of the LGPLv3 License. +# +#************************************************************************* + + +PRJ=..$/..$/.. + +PRJNAME=vcl +TARGET=salwin +ENABLE_EXCEPTIONS=TRUE + +# --- Settings ----------------------------------------------------- + +.INCLUDE : settings.mk +.INCLUDE : $(PRJ)$/util$/makefile2.pmk + +# --- #105371# +.IF "$(COM)"=="GCC" +CDEFS += -UWINVER -DWINVER=0x0400 -D_WIN32_WINNT=0x0501 +.ELSE +CFLAGS += -DWINVER=0x0400 -D_WIN32_WINNT=0x0501 + +.ENDIF + +# --- Files -------------------------------------------------------- + +SLOFILES= \ + $(SLO)$/salframe.obj \ + $(SLO)$/salmenu.obj \ + $(SLO)$/salobj.obj + +.IF "$(COM)"=="GCC" +EXCEPTIONSFILES= $(SLO)$/salframe.obj +.ENDIF + +# --- Targets ------------------------------------------------------ + +.INCLUDE : target.mk diff --git a/vcl/win/source/window/salframe.cxx b/vcl/win/source/window/salframe.cxx new file mode 100644 index 000000000000..140e506686fc --- /dev/null +++ b/vcl/win/source/window/salframe.cxx @@ -0,0 +1,6432 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2008 by Sun Microsystems, Inc. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * $RCSfile: salframe.cxx,v $ + * $Revision: 1.157.20.2 $ + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org 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 version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_vcl.hxx" + +// i72022: ad-hoc to forcibly enable reconversion +#if WINVER < 0x0500 +#undef WINVER +#define WINVER 0x0500 +#endif + +#include <com/sun/star/lang/XMultiServiceFactory.hpp> +#include <com/sun/star/container/XIndexAccess.hpp> +#include <com/sun/star/beans/XPropertySet.hpp> +#include <com/sun/star/awt/Rectangle.hpp> +#include <comphelper/processfactory.hxx> + +#include <string.h> +#include <limits.h> + +#include <stdio.h> + +#ifndef _SVWIN_HXX +#include <tools/svwin.h> +#endif +#ifdef __MINGW32__ +#include <excpt.h> +#endif +#include <rtl/string.h> +#include <rtl/ustring.h> + +#include <osl/module.h> +#include <tools/debug.hxx> + +// Warning in SDK header +#if defined(_MSC_VER) && (_MSC_VER > 1400) +#pragma warning( disable: 4242 4244 ) +#endif +#include <wincomp.hxx> +#ifndef _SV_SALIDS_HRC +#include <salids.hrc> +#endif +#include <vcl/sysdata.hxx> +#include <saldata.hxx> +#include <salinst.h> +#include <salbmp.h> +#include <salgdi.h> +#include <salsys.h> +#include <salframe.h> +#include <salvd.h> +#include <salmenu.h> +#include <salobj.h> +#include <vcl/impbmp.hxx> +#include <vcl/timer.hxx> +#include <saltimer.h> +#include <vcl/settings.hxx> +#ifndef _SV_KEYCOES_HXX +#include <vcl/keycodes.hxx> +#endif +#include <vcl/window.h> +#include <vcl/window.hxx> +#include <vcl/wrkwin.hxx> +#include <vcl/sallayout.hxx> +#include <vcl/svapp.hxx> +#ifndef _VCL_IMPDEL_HXX +#include <impdel.hxx> +#endif +#define COMPILE_MULTIMON_STUBS +#include <multimon.h> +#include <vector> +#ifdef __MINGW32__ +#include <algorithm> +using ::std::max; +#endif + +#include <com/sun/star/uno/Exception.hdl> + +#include <time.h> + +using ::rtl::OUString; +using namespace ::com::sun::star::uno; +using namespace ::com::sun::star::lang; +using namespace ::com::sun::star::container; +using namespace ::com::sun::star::beans; + +// The following defines are newly added in Longhorn +#ifndef WM_MOUSEHWHEEL +# define WM_MOUSEHWHEEL 0x020E +#endif +#ifndef SPI_GETWHEELSCROLLCHARS +# define SPI_GETWHEELSCROLLCHARS 0x006C +#endif +#ifndef SPI_SETWHEELSCROLLCHARS +# define SPI_SETWHEELSCROLLCHARS 0x006D +#endif + + + +#if OSL_DEBUG_LEVEL > 1 +void MyOutputDebugString( char *s) { OutputDebugString( s ); } +#endif + +// misssing prototypes and constants for LayeredWindows +extern "C" { + //WINUSERAPI BOOL WINAPI SetLayeredWindowAttributes(HWND,COLORREF,BYTE,DWORD); + typedef BOOL ( WINAPI * SetLayeredWindowAttributes_Proc_T ) (HWND,COLORREF,BYTE,DWORD); + static SetLayeredWindowAttributes_Proc_T lpfnSetLayeredWindowAttributes; +}; + +// ======================================================================= + +const unsigned int WM_USER_SYSTEM_WINDOW_ACTIVATED = RegisterWindowMessageA("SYSTEM_WINDOW_ACTIVATED"); + +BOOL WinSalFrame::mbInReparent = FALSE; + +// ======================================================================= + +// Wegen Fehler in Windows-Headerfiles +#ifndef IMN_OPENCANDIDATE +#define IMN_OPENCANDIDATE 0x0005 +#endif +#ifndef IMN_CLOSECANDIDATE +#define IMN_CLOSECANDIDATE 0x0004 +#endif + +#ifndef WM_THEMECHANGED +#define WM_THEMECHANGED 0x031A +#endif + +// Macros for support of WM_UNICHAR & Keyman 6.0 +#define Uni_UTF32ToSurrogate1(ch) (((unsigned long) (ch) - 0x10000) / 0x400 + 0xD800) +#define Uni_UTF32ToSurrogate2(ch) (((unsigned long) (ch) - 0x10000) % 0x400 + 0xDC00) +#define Uni_SupplementaryPlanesStart 0x10000 + +// ======================================================================= + +static void UpdateFrameGeometry( HWND hWnd, WinSalFrame* pFrame ); +static void SetMaximizedFrameGeometry( HWND hWnd, WinSalFrame* pFrame ); + +static void ImplSaveFrameState( WinSalFrame* pFrame ) +{ + // Position, Groesse und Status fuer GetWindowState() merken + if ( !pFrame->mbFullScreen ) + { + BOOL bVisible = (GetWindowStyle( pFrame->mhWnd ) & WS_VISIBLE) != 0; + if ( IsIconic( pFrame->mhWnd ) ) + { + pFrame->maState.mnState |= SAL_FRAMESTATE_MINIMIZED; + if ( bVisible ) + pFrame->mnShowState = SW_SHOWMAXIMIZED; + } + else if ( IsZoomed( pFrame->mhWnd ) ) + { + pFrame->maState.mnState &= ~SAL_FRAMESTATE_MINIMIZED; + pFrame->maState.mnState |= SAL_FRAMESTATE_MAXIMIZED; + if ( bVisible ) + pFrame->mnShowState = SW_SHOWMAXIMIZED; + pFrame->mbRestoreMaximize = TRUE; + } + else + { + RECT aRect; + GetWindowRect( pFrame->mhWnd, &aRect ); + + // to be consistent with Unix, the frame state is without(!) decoration + RECT aRect2 = aRect; + AdjustWindowRectEx( &aRect2, GetWindowStyle( pFrame->mhWnd ), + FALSE, GetWindowExStyle( pFrame->mhWnd ) ); + long nTopDeco = abs( aRect.top - aRect2.top ); + long nLeftDeco = abs( aRect.left - aRect2.left ); + long nBottomDeco = abs( aRect.bottom - aRect2.bottom ); + long nRightDeco = abs( aRect.right - aRect2.right ); + + pFrame->maState.mnState &= ~(SAL_FRAMESTATE_MINIMIZED | SAL_FRAMESTATE_MAXIMIZED); + // subtract decoration + pFrame->maState.mnX = aRect.left+nLeftDeco; + pFrame->maState.mnY = aRect.top+nTopDeco; + pFrame->maState.mnWidth = aRect.right-aRect.left-nLeftDeco-nRightDeco; + pFrame->maState.mnHeight = aRect.bottom-aRect.top-nTopDeco-nBottomDeco; + if ( bVisible ) + pFrame->mnShowState = SW_SHOWNORMAL; + pFrame->mbRestoreMaximize = FALSE; + } + } +} + +// ----------------------------------------------------------------------- + +// if pParentRect is set, the workarea of the monitor that contains pParentRect is returned +void ImplSalGetWorkArea( HWND hWnd, RECT *pRect, const RECT *pParentRect ) +{ + static int winVerChecked = 0; + static int winVerOk = 0; + + // check if we or our parent is fullscreen, then the taskbar should be ignored + bool bIgnoreTaskbar = false; + WinSalFrame* pFrame = GetWindowPtr( hWnd ); + if( pFrame ) + { + Window *pWin = pFrame->GetWindow(); + while( pWin ) + { + WorkWindow *pWorkWin = (pWin->GetType() == WINDOW_WORKWINDOW) ? (WorkWindow *) pWin : NULL; + if( pWorkWin && pWorkWin->ImplGetWindowImpl()->mbReallyVisible && pWorkWin->IsFullScreenMode() ) + { + bIgnoreTaskbar = true; + break; + } + else + pWin = pWin->ImplGetWindowImpl()->mpParent; + } + } + + if( !winVerChecked ) + { + winVerChecked = 1; + winVerOk = 1; + + // multi monitor calls not available on Win95/NT + if ( aSalShlData.maVersionInfo.dwPlatformId == VER_PLATFORM_WIN32_NT ) + { + if ( aSalShlData.maVersionInfo.dwMajorVersion <= 4 ) + winVerOk = 0; // NT + } + else if( aSalShlData.maVersionInfo.dwPlatformId == VER_PLATFORM_WIN32_WINDOWS ) + { + if ( aSalShlData.maVersionInfo.dwMajorVersion == 4 && aSalShlData.maVersionInfo.dwMinorVersion == 0 ) + winVerOk = 0; // Win95 + } + } + + // calculates the work area taking multiple monitors into account + if( winVerOk ) + { + static int nMonitors = GetSystemMetrics( SM_CMONITORS ); + if( nMonitors == 1 ) + { + if( bIgnoreTaskbar ) + { + pRect->left = pRect->top = 0; + pRect->right = GetSystemMetrics( SM_CXSCREEN ); + pRect->bottom = GetSystemMetrics( SM_CYSCREEN ); + } + else + SystemParametersInfo( SPI_GETWORKAREA, 0, pRect, 0 ); + } + else + { + if( pParentRect != NULL ) + { + // return the size of the monitor where pParentRect lives + HMONITOR hMonitor; + MONITORINFO mi; + + // get the nearest monitor to the passed rect. + hMonitor = MonitorFromRect(pParentRect, MONITOR_DEFAULTTONEAREST); + + // get the work area or entire monitor rect. + mi.cbSize = sizeof(mi); + GetMonitorInfo(hMonitor, &mi); + if( !bIgnoreTaskbar ) + *pRect = mi.rcWork; + else + *pRect = mi.rcMonitor; + } + else + { + // return the union of all monitors + pRect->left = GetSystemMetrics( SM_XVIRTUALSCREEN ); + pRect->top = GetSystemMetrics( SM_YVIRTUALSCREEN ); + pRect->right = pRect->left + GetSystemMetrics( SM_CXVIRTUALSCREEN ); + pRect->bottom = pRect->top + GetSystemMetrics( SM_CYVIRTUALSCREEN ); + + // virtualscreen does not take taskbar into account, so use the corresponding + // diffs between screen and workarea from the default screen + // however, this is still not perfect: the taskbar might not be on the primary screen + if( !bIgnoreTaskbar ) + { + RECT wRect, scrRect; + SystemParametersInfo( SPI_GETWORKAREA, 0, &wRect, 0 ); + scrRect.left = 0; + scrRect.top = 0; + scrRect.right = GetSystemMetrics( SM_CXSCREEN ); + scrRect.bottom = GetSystemMetrics( SM_CYSCREEN ); + + pRect->left += wRect.left; + pRect->top += wRect.top; + pRect->right -= scrRect.right - wRect.right; + pRect->bottom -= scrRect.bottom - wRect.bottom; + } + } + } + } + else + { + if( bIgnoreTaskbar ) + { + pRect->left = pRect->top = 0; + pRect->right = GetSystemMetrics( SM_CXSCREEN ); + pRect->bottom = GetSystemMetrics( SM_CYSCREEN ); + } + else + SystemParametersInfo( SPI_GETWORKAREA, 0, pRect, 0 ); + } +} + +// ======================================================================= + +SalFrame* ImplSalCreateFrame( WinSalInstance* pInst, + HWND hWndParent, ULONG nSalFrameStyle ) +{ + WinSalFrame* pFrame = new WinSalFrame; + HWND hWnd; + DWORD nSysStyle = 0; + DWORD nExSysStyle = 0; + BOOL bSubFrame = FALSE; + + if( getenv( "SAL_SYNCHRONIZE" ) ) // no buffering of drawing commands + GdiSetBatchLimit( 1 ); + + static int bLayeredAPI = -1; + if( bLayeredAPI == -1 ) + { + bLayeredAPI = 0; + // check for W2k and XP + if ( aSalShlData.maVersionInfo.dwPlatformId == VER_PLATFORM_WIN32_NT && aSalShlData.maVersionInfo.dwMajorVersion >= 5 ) + { + OUString aLibraryName( RTL_CONSTASCII_USTRINGPARAM( "user32" ) ); + oslModule pLib = osl_loadModule( aLibraryName.pData, SAL_LOADMODULE_DEFAULT ); + void *pFunc = NULL; + if( pLib ) + { + OUString queryFuncName( RTL_CONSTASCII_USTRINGPARAM( "SetLayeredWindowAttributes" ) ); + pFunc = osl_getSymbol( pLib, queryFuncName.pData ); + } + + lpfnSetLayeredWindowAttributes = ( SetLayeredWindowAttributes_Proc_T ) pFunc; + + if ( pFunc ) + bLayeredAPI = 1; + else + bLayeredAPI = 0; + } + } + static const char* pEnvTransparentFloats = getenv("SAL_TRANSPARENT_FLOATS" ); + + // determine creation data + if ( nSalFrameStyle & (SAL_FRAME_STYLE_PLUG | SAL_FRAME_STYLE_SYSTEMCHILD) ) + { + nSysStyle |= WS_CHILD; + if( nSalFrameStyle & SAL_FRAME_STYLE_SYSTEMCHILD ) + nSysStyle |= WS_CLIPSIBLINGS; + } + else + { + // #i87402# commenting out WS_CLIPCHILDREN + // this breaks SAL_FRAME_STYLE_SYSTEMCHILD handling, which is not + // used currently. Probably SAL_FRAME_STYLE_SYSTEMCHILD should be + // removed again. + + // nSysStyle |= WS_CLIPCHILDREN; + if ( hWndParent ) + { + nSysStyle |= WS_POPUP; + bSubFrame = TRUE; + pFrame->mbNoIcon = TRUE; + } + else + { + // Only with WS_OVRLAPPED we get a useful default position/size + if ( (nSalFrameStyle & (SAL_FRAME_STYLE_SIZEABLE | SAL_FRAME_STYLE_MOVEABLE)) == + (SAL_FRAME_STYLE_SIZEABLE | SAL_FRAME_STYLE_MOVEABLE) ) + nSysStyle |= WS_OVERLAPPED; + else + { + nSysStyle |= WS_POPUP; + if ( !(nSalFrameStyle & SAL_FRAME_STYLE_MOVEABLE) ) + nExSysStyle |= WS_EX_TOOLWINDOW; // avoid taskbar appearance, for eg splash screen + } + } + + if ( nSalFrameStyle & SAL_FRAME_STYLE_MOVEABLE ) + { + pFrame->mbCaption = TRUE; + nSysStyle |= WS_SYSMENU | WS_CAPTION; + if ( !hWndParent ) + nSysStyle |= WS_SYSMENU | WS_MINIMIZEBOX; + else + nExSysStyle |= WS_EX_DLGMODALFRAME; + + if ( nSalFrameStyle & SAL_FRAME_STYLE_SIZEABLE ) + { + pFrame->mbSizeBorder = TRUE; + nSysStyle |= WS_THICKFRAME; + if ( !hWndParent ) + nSysStyle |= WS_MAXIMIZEBOX; + } + else + pFrame->mbFixBorder = TRUE; + + if ( nSalFrameStyle & SAL_FRAME_STYLE_DEFAULT ) + nExSysStyle |= WS_EX_APPWINDOW; + } + if( nSalFrameStyle & SAL_FRAME_STYLE_TOOLWINDOW + // #100656# toolwindows lead to bad alt-tab behaviour, if they have the focus + // you must press it twice to leave the application + // so toolwindows are only used for non sizeable windows + // which are typically small, so a small caption makes sense + + // #103578# looked too bad - above changes reverted + /* && !(nSalFrameStyle & SAL_FRAME_STYLE_SIZEABLE) */ ) + { + pFrame->mbNoIcon = TRUE; + nExSysStyle |= WS_EX_TOOLWINDOW; + if ( pEnvTransparentFloats && bLayeredAPI == 1 /*&& !(nSalFrameStyle & SAL_FRAME_STYLE_MOVEABLE) */) + nExSysStyle |= WS_EX_LAYERED; + } + } + if ( nSalFrameStyle & SAL_FRAME_STYLE_FLOAT ) + { + nExSysStyle |= WS_EX_TOOLWINDOW; + pFrame->mbFloatWin = TRUE; + + if ( pEnvTransparentFloats && bLayeredAPI == 1 /*&& !(nSalFrameStyle & SAL_FRAME_STYLE_MOVEABLE) */) + nExSysStyle |= WS_EX_LAYERED; + + } + if( nSalFrameStyle & SAL_FRAME_STYLE_TOOLTIP ) + nExSysStyle |= WS_EX_TOPMOST; + + // init frame data + pFrame->mnStyle = nSalFrameStyle; + + // determine show style + pFrame->mnShowState = SW_SHOWNORMAL; + if ( (nSysStyle & (WS_POPUP | WS_MAXIMIZEBOX | WS_THICKFRAME)) == (WS_MAXIMIZEBOX | WS_THICKFRAME) ) + { + if ( GetSystemMetrics( SM_CXSCREEN ) <= 1024 ) + pFrame->mnShowState = SW_SHOWMAXIMIZED; + else + { + if ( nSalFrameStyle & SAL_FRAME_STYLE_DEFAULT ) + { + SalData* pSalData = GetSalData(); + pFrame->mnShowState = pSalData->mnCmdShow; + if ( (pFrame->mnShowState != SW_SHOWMINIMIZED) && + (pFrame->mnShowState != SW_MINIMIZE) && + (pFrame->mnShowState != SW_SHOWMINNOACTIVE) ) + { + if ( (pFrame->mnShowState == SW_SHOWMAXIMIZED) || + (pFrame->mnShowState == SW_MAXIMIZE) ) + pFrame->mbOverwriteState = FALSE; + pFrame->mnShowState = SW_SHOWMAXIMIZED; + } + else + pFrame->mbOverwriteState = FALSE; + } + else + { + // Document Windows are also maximized, if the current Document Window + // is also maximized + HWND hWnd = GetForegroundWindow(); + if ( hWnd && IsMaximized( hWnd ) && + (GetWindowInstance( hWnd ) == pInst->mhInst) && + ((GetWindowStyle( hWnd ) & (WS_POPUP | WS_MAXIMIZEBOX | WS_THICKFRAME)) == (WS_MAXIMIZEBOX | WS_THICKFRAME)) ) + pFrame->mnShowState = SW_SHOWMAXIMIZED; + } + } + } + + // create frame + if ( aSalShlData.mbWNT ) + { + LPCWSTR pClassName; + if ( bSubFrame ) + { + if ( nSalFrameStyle & (SAL_FRAME_STYLE_MOVEABLE|SAL_FRAME_STYLE_NOSHADOW) ) // check if shadow not wanted + pClassName = SAL_SUBFRAME_CLASSNAMEW; + else + pClassName = SAL_TMPSUBFRAME_CLASSNAMEW; // undecorated floaters will get shadow on XP + } + else + { + if ( nSalFrameStyle & SAL_FRAME_STYLE_MOVEABLE ) + pClassName = SAL_FRAME_CLASSNAMEW; + else + pClassName = SAL_TMPSUBFRAME_CLASSNAMEW; + } + hWnd = CreateWindowExW( nExSysStyle, pClassName, L"", nSysStyle, + CW_USEDEFAULT, 0, CW_USEDEFAULT, 0, + hWndParent, 0, pInst->mhInst, (void*)pFrame ); + if( !hWnd ) + ImplWriteLastError( GetLastError(), "CreateWindowEx" ); +#if OSL_DEBUG_LEVEL > 1 + // set transparency value + if( bLayeredAPI == 1 && GetWindowExStyle( hWnd ) & WS_EX_LAYERED ) + lpfnSetLayeredWindowAttributes( hWnd, 0, 230, 0x00000002 /*LWA_ALPHA*/ ); +#endif + } + else + { + LPCSTR pClassName; + if ( bSubFrame ) + pClassName = SAL_SUBFRAME_CLASSNAMEA; + else + pClassName = SAL_FRAME_CLASSNAMEA; + hWnd = CreateWindowExA( nExSysStyle, pClassName, "", nSysStyle, + CW_USEDEFAULT, 0, CW_USEDEFAULT, 0, + hWndParent, 0, pInst->mhInst, (void*)pFrame ); + } + if ( !hWnd ) + { + delete pFrame; + return NULL; + } + + // If we have an Window with an Caption Bar and without + // an MaximizeBox, we change the SystemMenu + if ( (nSysStyle & (WS_CAPTION | WS_MAXIMIZEBOX)) == (WS_CAPTION) ) + { + HMENU hSysMenu = GetSystemMenu( hWnd, FALSE ); + if ( hSysMenu ) + { + if ( !(nSysStyle & (WS_MINIMIZEBOX | WS_MAXIMIZEBOX)) ) + DeleteMenu( hSysMenu, SC_RESTORE, MF_BYCOMMAND ); + else + EnableMenuItem( hSysMenu, SC_RESTORE, MF_BYCOMMAND | MF_GRAYED | MF_DISABLED ); + if ( !(nSysStyle & WS_MINIMIZEBOX) ) + DeleteMenu( hSysMenu, SC_MINIMIZE, MF_BYCOMMAND ); + if ( !(nSysStyle & WS_MAXIMIZEBOX) ) + DeleteMenu( hSysMenu, SC_MAXIMIZE, MF_BYCOMMAND ); + if ( !(nSysStyle & WS_THICKFRAME) ) + DeleteMenu( hSysMenu, SC_SIZE, MF_BYCOMMAND ); + } + } + if ( (nSysStyle & WS_SYSMENU) && !(nSalFrameStyle & SAL_FRAME_STYLE_CLOSEABLE) ) + { + HMENU hSysMenu = GetSystemMenu( hWnd, FALSE ); + if ( hSysMenu ) + EnableMenuItem( hSysMenu, SC_CLOSE, MF_BYCOMMAND | MF_GRAYED | MF_DISABLED ); + } + + // reset input context + pFrame->mhDefIMEContext = ImmAssociateContext( hWnd, 0 ); + + // determine output size and state + RECT aRect; + GetClientRect( hWnd, &aRect ); + pFrame->mnWidth = aRect.right; + pFrame->mnHeight = aRect.bottom; + ImplSaveFrameState( pFrame ); + pFrame->mbDefPos = TRUE; + + UpdateFrameGeometry( hWnd, pFrame ); + + if( pFrame->mnShowState == SW_SHOWMAXIMIZED ) + { + // #96084 set a useful internal window size because + // the window will not be maximized (and the size updated) before show() + + SetMaximizedFrameGeometry( hWnd, pFrame ); + } + + return pFrame; +} + +// helper that only creates the HWND +// to allow for easy reparenting of system windows, (i.e. destroy and create new) +HWND ImplSalReCreateHWND( HWND hWndParent, HWND oldhWnd, BOOL bAsChild ) +{ + HINSTANCE hInstance = GetSalData()->mhInst; + ULONG nSysStyle = GetWindowLong( oldhWnd, GWL_STYLE ); + ULONG nExSysStyle = GetWindowLong( oldhWnd, GWL_EXSTYLE ); + + if( bAsChild ) + { + nSysStyle = WS_CHILD; + nExSysStyle = 0; + } + + HWND hWnd = NULL; + if ( aSalShlData.mbWNT ) + { + LPCWSTR pClassName = SAL_SUBFRAME_CLASSNAMEW; + hWnd = CreateWindowExW( nExSysStyle, pClassName, L"", nSysStyle, + CW_USEDEFAULT, 0, CW_USEDEFAULT, 0, + hWndParent, 0, hInstance, (void*)GetWindowPtr( oldhWnd ) ); + } + else + { + LPCSTR pClassName = SAL_SUBFRAME_CLASSNAMEA; + hWnd = CreateWindowExA( nExSysStyle, pClassName, "", nSysStyle, + CW_USEDEFAULT, 0, CW_USEDEFAULT, 0, + hWndParent, 0, hInstance, (void*)GetWindowPtr( oldhWnd ) ); + } + return hWnd; +} + +// ======================================================================= + +// Uebersetzungstabelle von System-Keycodes in StarView-Keycodes +#define KEY_TAB_SIZE 146 + +static USHORT aImplTranslateKeyTab[KEY_TAB_SIZE] = +{ + // StarView-Code System-Code Index + 0, // 0 + 0, // VK_LBUTTON 1 + 0, // VK_RBUTTON 2 + 0, // VK_CANCEL 3 + 0, // VK_MBUTTON 4 + 0, // 5 + 0, // 6 + 0, // 7 + KEY_BACKSPACE, // VK_BACK 8 + KEY_TAB, // VK_TAB 9 + 0, // 10 + 0, // 11 + 0, // VK_CLEAR 12 + KEY_RETURN, // VK_RETURN 13 + 0, // 14 + 0, // 15 + 0, // VK_SHIFT 16 + 0, // VK_CONTROL 17 + 0, // VK_MENU 18 + 0, // VK_PAUSE 19 + 0, // VK_CAPITAL 20 + 0, // VK_HANGUL 21 + 0, // 22 + 0, // 23 + 0, // 24 + KEY_HANGUL_HANJA, // VK_HANJA 25 + 0, // 26 + KEY_ESCAPE, // VK_ESCAPE 27 + 0, // 28 + 0, // 29 + 0, // 30 + 0, // 31 + KEY_SPACE, // VK_SPACE 32 + KEY_PAGEUP, // VK_PRIOR 33 + KEY_PAGEDOWN, // VK_NEXT 34 + KEY_END, // VK_END 35 + KEY_HOME, // VK_HOME 36 + KEY_LEFT, // VK_LEFT 37 + KEY_UP, // VK_UP 38 + KEY_RIGHT, // VK_RIGHT 39 + KEY_DOWN, // VK_DOWN 40 + 0, // VK_SELECT 41 + 0, // VK_PRINT 42 + 0, // VK_EXECUTE 43 + 0, // VK_SNAPSHOT 44 + KEY_INSERT, // VK_INSERT 45 + KEY_DELETE, // VK_DELETE 46 + KEY_HELP, // VK_HELP 47 + KEY_0, // 48 + KEY_1, // 49 + KEY_2, // 50 + KEY_3, // 51 + KEY_4, // 52 + KEY_5, // 53 + KEY_6, // 54 + KEY_7, // 55 + KEY_8, // 56 + KEY_9, // 57 + 0, // 58 + 0, // 59 + 0, // 60 + 0, // 61 + 0, // 62 + 0, // 63 + 0, // 64 + KEY_A, // 65 + KEY_B, // 66 + KEY_C, // 67 + KEY_D, // 68 + KEY_E, // 69 + KEY_F, // 70 + KEY_G, // 71 + KEY_H, // 72 + KEY_I, // 73 + KEY_J, // 74 + KEY_K, // 75 + KEY_L, // 76 + KEY_M, // 77 + KEY_N, // 78 + KEY_O, // 79 + KEY_P, // 80 + KEY_Q, // 81 + KEY_R, // 82 + KEY_S, // 83 + KEY_T, // 84 + KEY_U, // 85 + KEY_V, // 86 + KEY_W, // 87 + KEY_X, // 88 + KEY_Y, // 89 + KEY_Z, // 90 + 0, // VK_LWIN 91 + 0, // VK_RWIN 92 + KEY_CONTEXTMENU, // VK_APPS 93 + 0, // 94 + 0, // 95 + KEY_0, // VK_NUMPAD0 96 + KEY_1, // VK_NUMPAD1 97 + KEY_2, // VK_NUMPAD2 98 + KEY_3, // VK_NUMPAD3 99 + KEY_4, // VK_NUMPAD4 100 + KEY_5, // VK_NUMPAD5 101 + KEY_6, // VK_NUMPAD6 102 + KEY_7, // VK_NUMPAD7 103 + KEY_8, // VK_NUMPAD8 104 + KEY_9, // VK_NUMPAD9 105 + KEY_MULTIPLY, // VK_MULTIPLY 106 + KEY_ADD, // VK_ADD 107 + KEY_DECIMAL, // VK_SEPARATOR 108 + KEY_SUBTRACT, // VK_SUBTRACT 109 + KEY_DECIMAL, // VK_DECIMAL 110 + KEY_DIVIDE, // VK_DIVIDE 111 + KEY_F1, // VK_F1 112 + KEY_F2, // VK_F2 113 + KEY_F3, // VK_F3 114 + KEY_F4, // VK_F4 115 + KEY_F5, // VK_F5 116 + KEY_F6, // VK_F6 117 + KEY_F7, // VK_F7 118 + KEY_F8, // VK_F8 119 + KEY_F9, // VK_F9 120 + KEY_F10, // VK_F10 121 + KEY_F11, // VK_F11 122 + KEY_F12, // VK_F12 123 + KEY_F13, // VK_F13 124 + KEY_F14, // VK_F14 125 + KEY_F15, // VK_F15 126 + KEY_F16, // VK_F16 127 + KEY_F17, // VK_F17 128 + KEY_F18, // VK_F18 129 + KEY_F19, // VK_F19 130 + KEY_F20, // VK_F20 131 + KEY_F21, // VK_F21 132 + KEY_F22, // VK_F22 133 + KEY_F23, // VK_F23 134 + KEY_F24, // VK_F24 135 + 0, // 136 + 0, // 137 + 0, // 138 + 0, // 139 + 0, // 140 + 0, // 141 + 0, // 142 + 0, // 143 + 0, // NUMLOCK 144 + 0 // SCROLLLOCK 145 +}; + +// ======================================================================= + +static UINT ImplSalGetWheelScrollLines() +{ + UINT nScrLines = 0; + HWND hWndMsWheel = WIN_FindWindow( MSH_WHEELMODULE_CLASS, MSH_WHEELMODULE_TITLE ); + if ( hWndMsWheel ) + { + UINT nGetScrollLinesMsgId = RegisterWindowMessage( MSH_SCROLL_LINES ); + nScrLines = (UINT)ImplSendMessage( hWndMsWheel, nGetScrollLinesMsgId, 0, 0 ); + } + + if ( !nScrLines ) + if( !SystemParametersInfo( SPI_GETWHEELSCROLLLINES, 0, &nScrLines, 0 ) ) + nScrLines = 0 ; + + if ( !nScrLines ) + nScrLines = 3; + + return nScrLines; +} + +// ----------------------------------------------------------------------- + +static UINT ImplSalGetWheelScrollChars() +{ + UINT nScrChars = 0; + if( !SystemParametersInfo( SPI_GETWHEELSCROLLCHARS, 0, &nScrChars, 0 ) ) + { + // Depending on Windows version, use proper default or 1 (when + // driver emulates hscroll) + if( VER_PLATFORM_WIN32_NT == aSalShlData.maVersionInfo.dwPlatformId && + aSalShlData.maVersionInfo.dwMajorVersion < 6 ) + { + // Windows 2000 & WinXP : emulating driver, use step size + // of 1 + return 1; + } + else + { + // Longhorn or above: use proper default value of 3 + return 3; + } + } + + // system settings successfully read + return nScrChars; +} + +// ----------------------------------------------------------------------- + +static void ImplSalAddBorder( const WinSalFrame* pFrame, int& width, int& height ) +{ + // transform client size into window size + RECT aWinRect; + aWinRect.left = 0; + aWinRect.right = width-1; + aWinRect.top = 0; + aWinRect.bottom = height-1; + AdjustWindowRectEx( &aWinRect, GetWindowStyle( pFrame->mhWnd ), + FALSE, GetWindowExStyle( pFrame->mhWnd ) ); + width = aWinRect.right - aWinRect.left + 1; + height = aWinRect.bottom - aWinRect.top + 1; +} + +// ----------------------------------------------------------------------- + +static void ImplSalCalcFullScreenSize( const WinSalFrame* pFrame, + int& rX, int& rY, int& rDX, int& rDY ) +{ + // set window to screen size + int nFrameX; + int nFrameY; + int nCaptionY; + int nScreenX = 0; + int nScreenY = 0; + int nScreenDX = 0; + int nScreenDY = 0; + + if ( pFrame->mbSizeBorder ) + { + nFrameX = GetSystemMetrics( SM_CXSIZEFRAME ); + nFrameY = GetSystemMetrics( SM_CYSIZEFRAME ); + } + else if ( pFrame->mbFixBorder ) + { + nFrameX = GetSystemMetrics( SM_CXFIXEDFRAME ); + nFrameY = GetSystemMetrics( SM_CYFIXEDFRAME ); + } + else if ( pFrame->mbBorder ) + { + nFrameX = GetSystemMetrics( SM_CXBORDER ); + nFrameY = GetSystemMetrics( SM_CYBORDER ); + } + else + { + nFrameX = 0; + nFrameY = 0; + } + if ( pFrame->mbCaption ) + nCaptionY = GetSystemMetrics( SM_CYCAPTION ); + else + nCaptionY = 0; + + try + { + Reference< XMultiServiceFactory > xFactory( ::comphelper::getProcessServiceFactory(), UNO_QUERY_THROW ); + Reference< XIndexAccess > xMultiMon( xFactory->createInstance(OUString( RTL_CONSTASCII_USTRINGPARAM( "com.sun.star.awt.DisplayAccess" ) ) ), UNO_QUERY_THROW ); + if( (pFrame->mnDisplay >= 0) && (pFrame->mnDisplay < xMultiMon->getCount()) ) + { + Reference< XPropertySet > xMonitor( xMultiMon->getByIndex( pFrame->mnDisplay ), UNO_QUERY_THROW ); + com::sun::star::awt::Rectangle aRect; + if( xMonitor->getPropertyValue( OUString( RTL_CONSTASCII_USTRINGPARAM( "ScreenArea" ) ) ) >>= aRect ) + { + nScreenX = aRect.X; + nScreenY = aRect.Y; + nScreenDX = aRect.Width+1; // difference between java/awt convention and vcl + nScreenDY = aRect.Height+1; // difference between java/awt convention and vcl + } + } + else + { + nScreenX = GetSystemMetrics( SM_XVIRTUALSCREEN ); + nScreenY = GetSystemMetrics( SM_YVIRTUALSCREEN ); + nScreenDX = GetSystemMetrics( SM_CXVIRTUALSCREEN ); + nScreenDY = GetSystemMetrics( SM_CYVIRTUALSCREEN ); + } + } + catch( Exception& ) + { + } + + if( !nScreenDX || !nScreenDY ) + { + nScreenDX = GetSystemMetrics( SM_CXSCREEN ); + nScreenDY = GetSystemMetrics( SM_CYSCREEN ); + } + + rX = nScreenX -nFrameX; + rY = nScreenY -(nFrameY+nCaptionY); + rDX = nScreenDX+(nFrameX*2); + rDY = nScreenDY+(nFrameY*2)+nCaptionY; +} + +// ----------------------------------------------------------------------- + +static void ImplSalFrameFullScreenPos( WinSalFrame* pFrame, BOOL bAlways = FALSE ) +{ + if ( bAlways || !IsIconic( pFrame->mhWnd ) ) + { + // set window to screen size + int nX; + int nY; + int nWidth; + int nHeight; + ImplSalCalcFullScreenSize( pFrame, nX, nY, nWidth, nHeight ); + SetWindowPos( pFrame->mhWnd, 0, + nX, nY, nWidth, nHeight, + SWP_NOZORDER | SWP_NOACTIVATE ); + } +} + +// ----------------------------------------------------------------------- + +WinSalFrame::WinSalFrame() +{ + SalData* pSalData = GetSalData(); + + mhWnd = 0; + mhCursor = LoadCursor( 0, IDC_ARROW ); + mhDefIMEContext = 0; + mpGraphics = NULL; + mpGraphics2 = NULL; + mnShowState = SW_SHOWNORMAL; + mnWidth = 0; + mnHeight = 0; + mnMinWidth = 0; + mnMinHeight = 0; + mnMaxWidth = SHRT_MAX; + mnMaxHeight = SHRT_MAX; + mnInputLang = 0; + mnInputCodePage = 0; + mbGraphics = FALSE; + mbCaption = FALSE; + mbBorder = FALSE; + mbFixBorder = FALSE; + mbSizeBorder = FALSE; + mbFullScreen = FALSE; + mbPresentation = FALSE; + mbInShow = FALSE; + mbRestoreMaximize = FALSE; + mbInMoveMsg = FALSE; + mbInSizeMsg = FALSE; + mbFullScreenToolWin = FALSE; + mbDefPos = TRUE; + mbOverwriteState = TRUE; + mbIME = FALSE; + mbHandleIME = FALSE; + mbSpezIME = FALSE; + mbAtCursorIME = FALSE; + mbCandidateMode = FALSE; + mbFloatWin = FALSE; + mbNoIcon = FALSE; + mSelectedhMenu = 0; + mLastActivatedhMenu = 0; + mpClipRgnData = NULL; + mbFirstClipRect = TRUE; + mpNextClipRect = NULL; + mnDisplay = 0; + + memset( &maState, 0, sizeof( SalFrameState ) ); + maSysData.nSize = sizeof( SystemEnvData ); + + memset( &maGeometry, 0, sizeof( maGeometry ) ); + + // Daten ermitteln, wenn erster Frame angelegt wird + if ( !pSalData->mpFirstFrame ) + { + if ( !aSalShlData.mnWheelMsgId ) + aSalShlData.mnWheelMsgId = RegisterWindowMessage( MSH_MOUSEWHEEL ); + if ( !aSalShlData.mnWheelScrollLines ) + aSalShlData.mnWheelScrollLines = ImplSalGetWheelScrollLines(); + if ( !aSalShlData.mnWheelScrollChars ) + aSalShlData.mnWheelScrollChars = ImplSalGetWheelScrollChars(); + } + + // insert frame in framelist + mpNextFrame = pSalData->mpFirstFrame; + pSalData->mpFirstFrame = this; +} + +// ----------------------------------------------------------------------- +void WinSalFrame::updateScreenNumber() +{ + WinSalSystem* pSys = static_cast<WinSalSystem*>(ImplGetSalSystem()); + if( pSys ) + { + const std::vector<WinSalSystem::DisplayMonitor>& rMonitors = + pSys->getMonitors(); + Point aPoint( maGeometry.nX, maGeometry.nY ); + size_t nMon = rMonitors.size(); + for( size_t i = 0; i < nMon; i++ ) + { + if( rMonitors[i].m_aArea.IsInside( aPoint ) ) + { + mnDisplay = static_cast<sal_Int32>(i); + maGeometry.nScreenNumber = static_cast<unsigned int>(i); + } + } + } +} + +// ----------------------------------------------------------------------- + +WinSalFrame::~WinSalFrame() +{ + SalData* pSalData = GetSalData(); + + if( mpClipRgnData ) + delete [] (BYTE*)mpClipRgnData; + + // remove frame from framelist + WinSalFrame** ppFrame = &pSalData->mpFirstFrame; + for(; (*ppFrame != this) && *ppFrame; ppFrame = &(*ppFrame)->mpNextFrame ); + if( *ppFrame ) + *ppFrame = mpNextFrame; + mpNextFrame = NULL; + + // Release Cache DC + if ( mpGraphics2 && + mpGraphics2->mhDC ) + ReleaseGraphics( mpGraphics2 ); + + // destroy saved DC + if ( mpGraphics ) + { + if ( mpGraphics->mhDefPal ) + SelectPalette( mpGraphics->mhDC, mpGraphics->mhDefPal, TRUE ); + ImplSalDeInitGraphics( mpGraphics ); + ReleaseDC( mhWnd, mpGraphics->mhDC ); + delete mpGraphics; + mpGraphics = NULL; + } + + if ( mhWnd ) + { + // reset mouse leave data + if ( pSalData->mhWantLeaveMsg == mhWnd ) + { + pSalData->mhWantLeaveMsg = 0; + if ( pSalData->mpMouseLeaveTimer ) + { + delete pSalData->mpMouseLeaveTimer; + pSalData->mpMouseLeaveTimer = NULL; + } + } + + // destroy system frame + if ( !DestroyWindow( mhWnd ) ) + SetWindowPtr( mhWnd, 0 ); + + mhWnd = 0; + } +} + +// ----------------------------------------------------------------------- + +SalGraphics* WinSalFrame::GetGraphics() +{ + if ( mbGraphics ) + return NULL; + + // Other threads get an own DC, because Windows modify in the + // other case our DC (changing clip region), when they send a + // WM_ERASEBACKGROUND message + SalData* pSalData = GetSalData(); + if ( pSalData->mnAppThreadId != GetCurrentThreadId() ) + { + // We use only three CacheDC's for all threads, because W9x is limited + // to max. 5 Cache DC's per thread + if ( pSalData->mnCacheDCInUse >= 3 ) + return NULL; + + if ( !mpGraphics2 ) + { + mpGraphics2 = new WinSalGraphics; + mpGraphics2->mhDC = 0; + mpGraphics2->mhWnd = mhWnd; + mpGraphics2->mbPrinter = FALSE; + mpGraphics2->mbVirDev = FALSE; + mpGraphics2->mbWindow = TRUE; + mpGraphics2->mbScreen = TRUE; + } + + HDC hDC = (HDC)ImplSendMessage( pSalData->mpFirstInstance->mhComWnd, + SAL_MSG_GETDC, + (WPARAM)mhWnd, 0 ); + if ( hDC ) + { + mpGraphics2->mhDC = hDC; + if ( pSalData->mhDitherPal ) + { + mpGraphics2->mhDefPal = SelectPalette( hDC, pSalData->mhDitherPal, TRUE ); + RealizePalette( hDC ); + } + ImplSalInitGraphics( mpGraphics2 ); + mbGraphics = TRUE; + + pSalData->mnCacheDCInUse++; + return mpGraphics2; + } + else + return NULL; + } + else + { + if ( !mpGraphics ) + { + HDC hDC = GetDC( mhWnd ); + if ( hDC ) + { + mpGraphics = new WinSalGraphics; + mpGraphics->mhDC = hDC; + mpGraphics->mhWnd = mhWnd; + mpGraphics->mbPrinter = FALSE; + mpGraphics->mbVirDev = FALSE; + mpGraphics->mbWindow = TRUE; + mpGraphics->mbScreen = TRUE; + if ( pSalData->mhDitherPal ) + { + mpGraphics->mhDefPal = SelectPalette( hDC, pSalData->mhDitherPal, TRUE ); + RealizePalette( hDC ); + } + ImplSalInitGraphics( mpGraphics ); + mbGraphics = TRUE; + } + } + else + mbGraphics = TRUE; + + return mpGraphics; + } +} + +// ----------------------------------------------------------------------- + +void WinSalFrame::ReleaseGraphics( SalGraphics* pGraphics ) +{ + if ( mpGraphics2 == pGraphics ) + { + if ( mpGraphics2->mhDC ) + { + SalData* pSalData = GetSalData(); + if ( mpGraphics2->mhDefPal ) + SelectPalette( mpGraphics2->mhDC, mpGraphics2->mhDefPal, TRUE ); + ImplSalDeInitGraphics( mpGraphics2 ); + ImplSendMessage( pSalData->mpFirstInstance->mhComWnd, + SAL_MSG_RELEASEDC, + (WPARAM)mhWnd, + (LPARAM)mpGraphics2->mhDC ); + mpGraphics2->mhDC = 0; + pSalData->mnCacheDCInUse--; + } + } + + mbGraphics = FALSE; +} + +// ----------------------------------------------------------------------- + +BOOL WinSalFrame::PostEvent( void* pData ) +{ + return (BOOL)ImplPostMessage( mhWnd, SAL_MSG_USEREVENT, 0, (LPARAM)pData ); +} + +// ----------------------------------------------------------------------- + +void WinSalFrame::SetTitle( const XubString& rTitle ) +{ + DBG_ASSERT( sizeof( WCHAR ) == sizeof( xub_Unicode ), "WinSalFrame::SetTitle(): WCHAR != sal_Unicode" ); + + if ( !SetWindowTextW( mhWnd, reinterpret_cast<LPCWSTR>(rTitle.GetBuffer()) ) ) + { + ByteString aAnsiTitle = ImplSalGetWinAnsiString( rTitle ); + SetWindowTextA( mhWnd, aAnsiTitle.GetBuffer() ); + } +} + +// ----------------------------------------------------------------------- + +void WinSalFrame::SetIcon( USHORT nIcon ) +{ + // If we have a window without an Icon (for example a dialog), ignore this call + if ( mbNoIcon ) + return; + + // 0 means default (class) icon + HICON hIcon = NULL, hSmIcon = NULL; + if ( !nIcon ) + nIcon = 1; + + ImplLoadSalIcon( nIcon, hIcon, hSmIcon ); + + DBG_ASSERT( hIcon , "WinSalFrame::SetIcon(): Could not load large icon !" ); + DBG_ASSERT( hSmIcon , "WinSalFrame::SetIcon(): Could not load small icon !" ); + + ImplSendMessage( mhWnd, WM_SETICON, ICON_BIG, (LPARAM)hIcon ); + ImplSendMessage( mhWnd, WM_SETICON, ICON_SMALL, (LPARAM)hSmIcon ); +} + +// ----------------------------------------------------------------------- + +void WinSalFrame::SetMenu( SalMenu* pSalMenu ) +{ + WinSalMenu* pWMenu = static_cast<WinSalMenu*>(pSalMenu); + if( pSalMenu && pWMenu->mbMenuBar ) + ::SetMenu( mhWnd, pWMenu->mhMenu ); +} + +void WinSalFrame::DrawMenuBar() +{ + ::DrawMenuBar( mhWnd ); +} + +// ----------------------------------------------------------------------- +HWND ImplGetParentHwnd( HWND hWnd ) +{ + WinSalFrame* pFrame = GetWindowPtr( hWnd ); + if( !pFrame || !pFrame->GetWindow()) + return ::GetParent( hWnd ); + Window *pRealParent = pFrame->GetWindow()->ImplGetWindowImpl()->mpRealParent; + if( pRealParent ) + return static_cast<WinSalFrame*>(pRealParent->ImplGetWindowImpl()->mpFrame)->mhWnd; + else + return ::GetParent( hWnd ); + +} + +// ----------------------------------------------------------------------- + +SalFrame* WinSalFrame::GetParent() const +{ + return GetWindowPtr( ImplGetParentHwnd( mhWnd ) ); +} + +// ----------------------------------------------------------------------- + +static void ImplSalShow( HWND hWnd, BOOL bVisible, BOOL bNoActivate ) +{ + WinSalFrame* pFrame = GetWindowPtr( hWnd ); + if ( !pFrame ) + return; + + if ( bVisible ) + { + pFrame->mbDefPos = FALSE; + pFrame->mbOverwriteState = TRUE; + pFrame->mbInShow = TRUE; + + // #i4715, save position + RECT aRectPreMatrox, aRectPostMatrox; + GetWindowRect( hWnd, &aRectPreMatrox ); + + vcl::DeletionListener aDogTag( pFrame ); + if( bNoActivate ) + ShowWindow( hWnd, SW_SHOWNOACTIVATE ); + else + ShowWindow( hWnd, pFrame->mnShowState ); + if( aDogTag.isDeleted() ) + return; + + if ( aSalShlData.mbWXP && pFrame->mbFloatWin && !(pFrame->mnStyle & SAL_FRAME_STYLE_NOSHADOW)) + { + // erase the window immediately to improve XP shadow effect + // otherwise the shadow may appears long time before the rest of the window + // especially when accessibility is on + HDC dc = GetDC( hWnd ); + RECT aRect; + GetClientRect( hWnd, &aRect ); + FillRect( dc, &aRect, (HBRUSH) (COLOR_MENU+1) ); // choose the menucolor, because its mostly noticeable for menues + ReleaseDC( hWnd, dc ); + } + + // #i4715, matrox centerpopup might have changed our position + // reposition popups without caption (menues, dropdowns, tooltips) + GetWindowRect( hWnd, &aRectPostMatrox ); + if( (GetWindowStyle( hWnd ) & WS_POPUP) && + !pFrame->mbCaption && + (aRectPreMatrox.left != aRectPostMatrox.left || aRectPreMatrox.top != aRectPostMatrox.top) ) + SetWindowPos( hWnd, 0, aRectPreMatrox.left, aRectPreMatrox.top, 0, 0, SWP_NOZORDER | SWP_NOACTIVATE | SWP_NOSIZE ); + + if( aDogTag.isDeleted() ) + return; + Window *pClientWin = pFrame->GetWindow()->ImplGetClientWindow(); + if ( pFrame->mbFloatWin || ( pClientWin && (pClientWin->GetStyle() & WB_SYSTEMFLOATWIN) ) ) + pFrame->mnShowState = SW_SHOWNOACTIVATE; + else + pFrame->mnShowState = SW_SHOW; + // Damit Taskleiste unter W98 auch gleich ausgeblendet wird + if ( pFrame->mbPresentation ) + { + HWND hWndParent = ::GetParent( hWnd ); + if ( hWndParent ) + SetForegroundWindow( hWndParent ); + SetForegroundWindow( hWnd ); + } + + pFrame->mbInShow = FALSE; + pFrame->updateScreenNumber(); + + // Direct Paint only, if we get the SolarMutx + if ( ImplSalYieldMutexTryToAcquire() ) + { + UpdateWindow( hWnd ); + ImplSalYieldMutexRelease(); + } + } + else + { + // See also Bug #91813# and #68467# + if ( pFrame->mbFullScreen && + pFrame->mbPresentation && + (aSalShlData.mnVersion < 500) && + !::GetParent( hWnd ) ) + { + // Damit im Impress-Player in der Taskleiste nicht durch + // einen Windows-Fehler hin- und wieder mal ein leerer + // Button stehen bleibt, muessen wir hier die Taskleiste + // etwas austricksen. Denn wenn wir im FullScreenMode sind + // und das Fenster hiden kommt Windows anscheinend etwas aus + // dem tritt und somit minimieren wir das Fenster damit es + // nicht flackert + ANIMATIONINFO aInfo; + aInfo.cbSize = sizeof( aInfo ); + SystemParametersInfo( SPI_GETANIMATION, 0, &aInfo, 0 ); + if ( aInfo.iMinAnimate ) + { + int nOldAni = aInfo.iMinAnimate; + aInfo.iMinAnimate = 0; + SystemParametersInfo( SPI_SETANIMATION, 0, &aInfo, 0 ); + ShowWindow( pFrame->mhWnd, SW_SHOWMINNOACTIVE ); + aInfo.iMinAnimate = nOldAni; + SystemParametersInfo( SPI_SETANIMATION, 0, &aInfo, 0 ); + } + else + ShowWindow( hWnd, SW_SHOWMINNOACTIVE ); + ShowWindow( hWnd, SW_HIDE ); + } + else + ShowWindow( hWnd, SW_HIDE ); + } +} + +// ----------------------------------------------------------------------- + + +void WinSalFrame::SetExtendedFrameStyle( SalExtStyle ) +{ +} + +// ----------------------------------------------------------------------- + +void WinSalFrame::Show( BOOL bVisible, BOOL bNoActivate ) +{ + // Post this Message to the window, because this only works + // in the thread of the window, which has create this window. + // We post this message to avoid deadlocks + if ( GetSalData()->mnAppThreadId != GetCurrentThreadId() ) + ImplPostMessage( mhWnd, SAL_MSG_SHOW, bVisible, bNoActivate ); + else + ImplSalShow( mhWnd, bVisible, bNoActivate ); +} + +// ----------------------------------------------------------------------- + +void WinSalFrame::Enable( BOOL bEnable ) +{ + EnableWindow( mhWnd, bEnable ); +} + +// ----------------------------------------------------------------------- + +void WinSalFrame::SetMinClientSize( long nWidth, long nHeight ) +{ + mnMinWidth = nWidth; + mnMinHeight = nHeight; +} + +void WinSalFrame::SetMaxClientSize( long nWidth, long nHeight ) +{ + mnMaxWidth = nWidth; + mnMaxHeight = nHeight; +} + +// ----------------------------------------------------------------------- + +void WinSalFrame::SetPosSize( long nX, long nY, long nWidth, long nHeight, + USHORT nFlags ) +{ + BOOL bVisible = (GetWindowStyle( mhWnd ) & WS_VISIBLE) != 0; + if ( !bVisible ) + { + Window *pClientWin = GetWindow()->ImplGetClientWindow(); + if ( mbFloatWin || ( pClientWin && (pClientWin->GetStyle() & WB_SYSTEMFLOATWIN) ) ) + mnShowState = SW_SHOWNOACTIVATE; + else + mnShowState = SW_SHOWNORMAL; + } + else + { + if ( IsIconic( mhWnd ) || IsZoomed( mhWnd ) ) + ShowWindow( mhWnd, SW_RESTORE ); + } + + USHORT nEvent = 0; + UINT nPosSize = 0; + RECT aClientRect, aWindowRect; + GetClientRect( mhWnd, &aClientRect ); // x,y always 0,0, but width and height without border + GetWindowRect( mhWnd, &aWindowRect ); // x,y in screen coordinates, width and height with border + + if ( !(nFlags & (SAL_FRAME_POSSIZE_X | SAL_FRAME_POSSIZE_Y)) ) + nPosSize |= SWP_NOMOVE; + else + { + //DBG_ASSERT( nX && nY, " Windowposition of (0,0) requested!" ); + nEvent = SALEVENT_MOVE; + } + if ( !(nFlags & (SAL_FRAME_POSSIZE_WIDTH | SAL_FRAME_POSSIZE_HEIGHT)) ) + nPosSize |= SWP_NOSIZE; + else + nEvent = (nEvent == SALEVENT_MOVE) ? SALEVENT_MOVERESIZE : SALEVENT_RESIZE; + + if ( !(nFlags & SAL_FRAME_POSSIZE_X) ) + nX = aWindowRect.left; + if ( !(nFlags & SAL_FRAME_POSSIZE_Y) ) + nY = aWindowRect.top; + if ( !(nFlags & SAL_FRAME_POSSIZE_WIDTH) ) + nWidth = aClientRect.right-aClientRect.left; + if ( !(nFlags & SAL_FRAME_POSSIZE_HEIGHT) ) + nHeight = aClientRect.bottom-aClientRect.top; + + // Calculate window size including the border + RECT aWinRect; + aWinRect.left = 0; + aWinRect.right = (int)nWidth-1; + aWinRect.top = 0; + aWinRect.bottom = (int)nHeight-1; + AdjustWindowRectEx( &aWinRect, GetWindowStyle( mhWnd ), + FALSE, GetWindowExStyle( mhWnd ) ); + nWidth = aWinRect.right - aWinRect.left + 1; + nHeight = aWinRect.bottom - aWinRect.top + 1; + + if ( !(nPosSize & SWP_NOMOVE) && ::GetParent( mhWnd ) ) + { + // --- RTL --- (mirror window pos) + RECT aParentRect; + GetClientRect( ImplGetParentHwnd( mhWnd ), &aParentRect ); + if( Application::GetSettings().GetLayoutRTL() ) + nX = (aParentRect.right - aParentRect.left) - nWidth-1 - nX; + + //#110386#, do not transform coordinates for system child windows + if( !(GetWindowStyle( mhWnd ) & WS_CHILD) ) + { + POINT aPt; + aPt.x = nX; + aPt.y = nY; + + HWND parentHwnd = ImplGetParentHwnd( mhWnd ); + WinSalFrame* pParentFrame = GetWindowPtr( parentHwnd ); + if ( pParentFrame && pParentFrame->mnShowState == SW_SHOWMAXIMIZED ) + { + // #i42485#: parent will be shown maximized in which case + // a ClientToScreen uses the wrong coordinates (i.e. those from the restore pos) + // so use the (already updated) frame geometry for the transformation + aPt.x += pParentFrame->maGeometry.nX; + aPt.y += pParentFrame->maGeometry.nY; + } + else + ClientToScreen( parentHwnd, &aPt ); + + nX = aPt.x; + nY = aPt.y; + } + } + + // #i3338# to be conformant to UNIX we must position the client window, ie without the decoration + // #i43250# if the position was read from the system (GetWindowRect(), see above), it must not be modified + if ( nFlags & SAL_FRAME_POSSIZE_X ) + nX += aWinRect.left; + if ( nFlags & SAL_FRAME_POSSIZE_Y ) + nY += aWinRect.top; + + int nScreenX; + int nScreenY; + int nScreenWidth; + int nScreenHeight; + + + RECT aRect; + ImplSalGetWorkArea( mhWnd, &aRect, NULL ); + nScreenX = aRect.left; + nScreenY = aRect.top; + nScreenWidth = aRect.right-aRect.left; + nScreenHeight = aRect.bottom-aRect.top; + + if ( mbDefPos && (nPosSize & SWP_NOMOVE)) // we got no positioning request, so choose default position + { + // center window + + HWND hWndParent = ::GetParent( mhWnd ); + // Search for TopLevel Frame + while ( hWndParent && (GetWindowStyle( hWndParent ) & WS_CHILD) ) + hWndParent = ::GetParent( hWndParent ); + // if the Window has a Parent, than center the window to + // the parent, in the other case to the screen + if ( hWndParent && !IsIconic( hWndParent ) && + (GetWindowStyle( hWndParent ) & WS_VISIBLE) ) + { + RECT aParentRect; + GetWindowRect( hWndParent, &aParentRect ); + int nParentWidth = aParentRect.right-aParentRect.left; + int nParentHeight = aParentRect.bottom-aParentRect.top; + + // We don't center, when Parent is smaller than our window + if ( (nParentWidth-GetSystemMetrics( SM_CXFIXEDFRAME ) <= nWidth) && + (nParentHeight-GetSystemMetrics( SM_CYFIXEDFRAME ) <= nHeight) ) + { + int nOff = GetSystemMetrics( SM_CYSIZEFRAME ) + GetSystemMetrics( SM_CYCAPTION ); + nX = aParentRect.left+nOff; + nY = aParentRect.top+nOff; + } + else + { + nX = (nParentWidth-nWidth)/2 + aParentRect.left; + nY = (nParentHeight-nHeight)/2 + aParentRect.top; + } + } + else + { + POINT pt; + GetCursorPos( &pt ); + RECT aRect; + aRect.left = pt.x; + aRect.top = pt.y; + aRect.right = pt.x+2; + aRect.bottom = pt.y+2; + + // dualmonitor support: + // Get screensize of the monitor whith the mouse pointer + ImplSalGetWorkArea( mhWnd, &aRect, &aRect ); + + nX = ((aRect.right-aRect.left)-nWidth)/2 + aRect.left; + nY = ((aRect.bottom-aRect.top)-nHeight)/2 + aRect.top; + } + + + //if ( bVisible ) + // mbDefPos = FALSE; + + mbDefPos = FALSE; // center only once + nPosSize &= ~SWP_NOMOVE; // activate positioning + nEvent = SALEVENT_MOVERESIZE; + } + + + // Adjust Window in the screen + BOOL bCheckOffScreen = TRUE; + + // but don't do this for floaters or ownerdraw windows that are currently moved interactively + if( (mnStyle & SAL_FRAME_STYLE_FLOAT) && !(mnStyle & SAL_FRAME_STYLE_OWNERDRAWDECORATION) ) + bCheckOffScreen = FALSE; + + if( mnStyle & SAL_FRAME_STYLE_OWNERDRAWDECORATION ) + { + // may be the window is currently being moved (mouse is captured), then no check is required + if( mhWnd == ::GetCapture() ) + bCheckOffScreen = FALSE; + else + bCheckOffScreen = TRUE; + } + + if( bCheckOffScreen ) + { + if ( nX+nWidth > nScreenX+nScreenWidth ) + nX = (nScreenX+nScreenWidth) - nWidth; + if ( nY+nHeight > nScreenY+nScreenHeight ) + nY = (nScreenY+nScreenHeight) - nHeight; + if ( nX < nScreenX ) + nX = nScreenX; + if ( nY < nScreenY ) + nY = nScreenY; + } + + UINT nPosFlags = SWP_NOACTIVATE | SWP_NOOWNERZORDER | nPosSize; + // bring floating windows always to top + if( !(mnStyle & SAL_FRAME_STYLE_FLOAT) ) + nPosFlags |= SWP_NOZORDER; // do not change z-order + + SetWindowPos( mhWnd, HWND_TOP, nX, nY, (int)nWidth, (int)nHeight, nPosFlags ); + + UpdateFrameGeometry( mhWnd, this ); + + // Notification -- really ??? + if( nEvent ) + CallCallback( nEvent, NULL ); +} + +// ----------------------------------------------------------------------- + +static void ImplSetParentFrame( WinSalFrame* pThis, HWND hNewParentWnd, BOOL bAsChild ) +{ + // save hwnd, will be overwritten in WM_CREATE during createwindow + HWND hWndOld = pThis->mhWnd; + HWND hWndOldParent = ::GetParent( hWndOld ); + SalData* pSalData = GetSalData(); + + if( hNewParentWnd == hWndOldParent ) + return; + + ::std::vector< WinSalFrame* > children; + ::std::vector< WinSalObject* > systemChildren; + + // search child windows + WinSalFrame *pFrame = pSalData->mpFirstFrame; + while( pFrame ) + { + HWND hWndParent = ::GetParent( pFrame->mhWnd ); + if( pThis->mhWnd == hWndParent ) + children.push_back( pFrame ); + pFrame = pFrame->mpNextFrame; + } + + // search system child windows (plugins etc.) + WinSalObject *pObject = pSalData->mpFirstObject; + while( pObject ) + { + HWND hWndParent = ::GetParent( pObject->mhWnd ); + if( pThis->mhWnd == hWndParent ) + systemChildren.push_back( pObject ); + pObject = pObject->mpNextObject; + } + + BOOL bNeedGraphics = pThis->mbGraphics; + BOOL bNeedCacheDC = FALSE; + + HFONT hFont = NULL; + HPEN hPen = NULL; + HBRUSH hBrush = NULL; + + #if OSL_DEBUG_LEVEL > 0 + int oldCount = pSalData->mnCacheDCInUse; + (void)oldCount; + #endif + + // Release Cache DC + if ( pThis->mpGraphics2 && + pThis->mpGraphics2->mhDC ) + { + // save current gdi objects before hdc is gone + hFont = (HFONT) GetCurrentObject( pThis->mpGraphics2->mhDC, OBJ_FONT); + hPen = (HPEN) GetCurrentObject( pThis->mpGraphics2->mhDC, OBJ_PEN); + hBrush = (HBRUSH) GetCurrentObject( pThis->mpGraphics2->mhDC, OBJ_BRUSH); + pThis->ReleaseGraphics( pThis->mpGraphics2 ); + + // recreate cache dc only if it was destroyed + bNeedCacheDC = TRUE; + } + + // destroy saved DC + if ( pThis->mpGraphics ) + { + if ( pThis->mpGraphics->mhDefPal ) + SelectPalette( pThis->mpGraphics->mhDC, pThis->mpGraphics->mhDefPal, TRUE ); + ImplSalDeInitGraphics( pThis->mpGraphics ); + ReleaseDC( pThis->mhWnd, pThis->mpGraphics->mhDC ); + } + + // create a new hwnd with the same styles + HWND hWndParent = hNewParentWnd; + // forward to main thread + HWND hWnd = (HWND) ImplSendMessage( pSalData->mpFirstInstance->mhComWnd, + bAsChild ? SAL_MSG_RECREATECHILDHWND : SAL_MSG_RECREATEHWND, + (WPARAM) hWndParent, (LPARAM)pThis->mhWnd ); + + // succeeded ? + DBG_ASSERT( IsWindow( hWnd ), "WinSalFrame::SetParent not successful"); + + // recreate DCs + if( bNeedGraphics ) + { + if( pThis->mpGraphics2 ) + { + pThis->mpGraphics2->mhWnd = hWnd; + + if( bNeedCacheDC ) + { + // re-create cached DC + HDC hDC = (HDC)ImplSendMessage( pSalData->mpFirstInstance->mhComWnd, + SAL_MSG_GETDC, + (WPARAM) hWnd, 0 ); + if ( hDC ) + { + pThis->mpGraphics2->mhDC = hDC; + if ( pSalData->mhDitherPal ) + { + pThis->mpGraphics2->mhDefPal = SelectPalette( hDC, pSalData->mhDitherPal, TRUE ); + RealizePalette( hDC ); + } + ImplSalInitGraphics( pThis->mpGraphics2 ); + + // re-select saved gdi objects + if( hFont ) + SelectObject( hDC, hFont ); + if( hPen ) + SelectObject( hDC, hPen ); + if( hBrush ) + SelectObject( hDC, hBrush ); + + pThis->mbGraphics = TRUE; + + pSalData->mnCacheDCInUse++; + + DBG_ASSERT( oldCount == pSalData->mnCacheDCInUse, "WinSalFrame::SetParent() hDC count corrupted"); + } + } + } + + if( pThis->mpGraphics ) + { + // re-create DC + pThis->mpGraphics->mhWnd = hWnd; + pThis->mpGraphics->mhDC = GetDC( hWnd ); + if ( GetSalData()->mhDitherPal ) + { + pThis->mpGraphics->mhDefPal = SelectPalette( pThis->mpGraphics->mhDC, GetSalData()->mhDitherPal, TRUE ); + RealizePalette( pThis->mpGraphics->mhDC ); + } + ImplSalInitGraphics( pThis->mpGraphics ); + pThis->mbGraphics = TRUE; + } + } + + + // TODO: add SetParent() call for SalObjects + DBG_ASSERT( systemChildren.empty(), "WinSalFrame::SetParent() parent of living system child window will be destroyed!"); + + // reparent children before old parent is destroyed + for( ::std::vector< WinSalFrame* >::iterator iChild = children.begin(); iChild != children.end(); iChild++ ) + ImplSetParentFrame( *iChild, hWnd, FALSE ); + + children.clear(); + systemChildren.clear(); + + // Now destroy original HWND in the thread where it was created. + ImplSendMessage( GetSalData()->mpFirstInstance->mhComWnd, + SAL_MSG_DESTROYHWND, (WPARAM) 0, (LPARAM)hWndOld); +} + +// ----------------------------------------------------------------------- + +void WinSalFrame::SetParent( SalFrame* pNewParent ) +{ + WinSalFrame::mbInReparent = TRUE; + ImplSetParentFrame( this, static_cast<WinSalFrame*>(pNewParent)->mhWnd, FALSE ); + WinSalFrame::mbInReparent = FALSE; +} + +bool WinSalFrame::SetPluginParent( SystemParentData* pNewParent ) +{ + if ( pNewParent->hWnd == 0 ) + { + pNewParent->hWnd = GetDesktopWindow(); + } + + WinSalFrame::mbInReparent = TRUE; + ImplSetParentFrame( this, pNewParent->hWnd, TRUE ); + WinSalFrame::mbInReparent = FALSE; + return true; +} + + +// ----------------------------------------------------------------------- + +void WinSalFrame::GetWorkArea( Rectangle &rRect ) +{ + RECT aRect; + ImplSalGetWorkArea( mhWnd, &aRect, NULL ); + rRect.nLeft = aRect.left; + rRect.nRight = aRect.right-1; + rRect.nTop = aRect.top; + rRect.nBottom = aRect.bottom-1; +} + +// ----------------------------------------------------------------------- + +void WinSalFrame::GetClientSize( long& rWidth, long& rHeight ) +{ + rWidth = maGeometry.nWidth; + rHeight = maGeometry.nHeight; +} + +// ----------------------------------------------------------------------- + +void WinSalFrame::SetWindowState( const SalFrameState* pState ) +{ + // Wir testen, ob das Fenster ueberhaupt auf den Bildschirm passt, damit + // nicht wenn die Bildschirm-Aufloesung geaendert wurde, das Fenster aus + // diesem herausragt + int nX; + int nY; + int nWidth; + int nHeight; + int nScreenX; + int nScreenY; + int nScreenWidth; + int nScreenHeight; + + RECT aRect; + ImplSalGetWorkArea( mhWnd, &aRect, NULL ); + // #102500# allow some overlap, the window could have been made a little larger than the physical screen + nScreenX = aRect.left-10; + nScreenY = aRect.top-10; + nScreenWidth = aRect.right-aRect.left+20; + nScreenHeight = aRect.bottom-aRect.top+20; + + UINT nPosSize = 0; + RECT aWinRect; + GetWindowRect( mhWnd, &aWinRect ); + + // to be consistent with Unix, the frame state is without(!) decoration + // ->add the decoration + RECT aRect2 = aWinRect; + AdjustWindowRectEx( &aRect2, GetWindowStyle( mhWnd ), + FALSE, GetWindowExStyle( mhWnd ) ); + long nTopDeco = abs( aWinRect.top - aRect2.top ); + long nLeftDeco = abs( aWinRect.left - aRect2.left ); + long nBottomDeco = abs( aWinRect.bottom - aRect2.bottom ); + long nRightDeco = abs( aWinRect.right - aRect2.right ); + + // Fenster-Position/Groesse in den Bildschirm einpassen + if ( !(pState->mnMask & (SAL_FRAMESTATE_MASK_X | SAL_FRAMESTATE_MASK_Y)) ) + nPosSize |= SWP_NOMOVE; + if ( !(pState->mnMask & (SAL_FRAMESTATE_MASK_WIDTH | SAL_FRAMESTATE_MASK_HEIGHT)) ) + nPosSize |= SWP_NOSIZE; + if ( pState->mnMask & SAL_FRAMESTATE_MASK_X ) + nX = (int)pState->mnX - nLeftDeco; + else + nX = aWinRect.left; + if ( pState->mnMask & SAL_FRAMESTATE_MASK_Y ) + nY = (int)pState->mnY - nTopDeco; + else + nY = aWinRect.top; + if ( pState->mnMask & SAL_FRAMESTATE_MASK_WIDTH ) + nWidth = (int)pState->mnWidth + nLeftDeco + nRightDeco; + else + nWidth = aWinRect.right-aWinRect.left; + if ( pState->mnMask & SAL_FRAMESTATE_MASK_HEIGHT ) + nHeight = (int)pState->mnHeight + nTopDeco + nBottomDeco; + else + nHeight = aWinRect.bottom-aWinRect.top; + + // Adjust Window in the screen: + // if it does not fit into the screen do nothing, ie default pos/size will be used + // if there is an overlap with the screen border move the window while keeping its size + + if( nWidth > nScreenWidth || nHeight > nScreenHeight ) + nPosSize |= (SWP_NOMOVE | SWP_NOSIZE); + + if ( nX+nWidth > nScreenX+nScreenWidth ) + nX = (nScreenX+nScreenWidth) - nWidth; + if ( nY+nHeight > nScreenY+nScreenHeight ) + nY = (nScreenY+nScreenHeight) - nHeight; + if ( nX < nScreenX ) + nX = nScreenX; + if ( nY < nScreenY ) + nY = nScreenY; + + // Restore-Position setzen + WINDOWPLACEMENT aPlacement; + aPlacement.length = sizeof( aPlacement ); + GetWindowPlacement( mhWnd, &aPlacement ); + + // Status setzen + BOOL bVisible = (GetWindowStyle( mhWnd ) & WS_VISIBLE) != 0; + BOOL bUpdateHiddenFramePos = FALSE; + if ( !bVisible ) + { + aPlacement.showCmd = SW_HIDE; + + if ( mbOverwriteState ) + { + if ( pState->mnMask & SAL_FRAMESTATE_MASK_STATE ) + { + if ( pState->mnState & SAL_FRAMESTATE_MINIMIZED ) + mnShowState = SW_SHOWMINIMIZED; + else if ( pState->mnState & SAL_FRAMESTATE_MAXIMIZED ) + { + mnShowState = SW_SHOWMAXIMIZED; + bUpdateHiddenFramePos = TRUE; + } + else if ( pState->mnState & SAL_FRAMESTATE_NORMAL ) + mnShowState = SW_SHOWNORMAL; + } + } + } + else + { + if ( pState->mnMask & SAL_FRAMESTATE_MASK_STATE ) + { + if ( pState->mnState & SAL_FRAMESTATE_MINIMIZED ) + { + if ( pState->mnState & SAL_FRAMESTATE_MAXIMIZED ) + aPlacement.flags |= WPF_RESTORETOMAXIMIZED; + aPlacement.showCmd = SW_SHOWMINIMIZED; + } + else if ( pState->mnState & SAL_FRAMESTATE_MAXIMIZED ) + aPlacement.showCmd = SW_SHOWMAXIMIZED; + else if ( pState->mnState & SAL_FRAMESTATE_NORMAL ) + aPlacement.showCmd = SW_RESTORE; + } + } + + // Wenn Fenster nicht minimiert/maximiert ist oder nicht optisch + // umgesetzt werden muss, dann SetWindowPos() benutzen, da + // SetWindowPlacement() die TaskBar mit einrechnet + if ( !IsIconic( mhWnd ) && !IsZoomed( mhWnd ) && + (!bVisible || (aPlacement.showCmd == SW_RESTORE)) ) + { + if( bUpdateHiddenFramePos ) + { + // #96084 set a useful internal window size because + // the window will not be maximized (and the size updated) before show() + SetMaximizedFrameGeometry( mhWnd, this ); + } + else + SetWindowPos( mhWnd, 0, + nX, nY, nWidth, nHeight, + SWP_NOZORDER | SWP_NOACTIVATE | nPosSize ); + } + else + { + if( !(nPosSize & (SWP_NOMOVE|SWP_NOSIZE)) ) + { + aPlacement.rcNormalPosition.left = nX-nScreenX; + aPlacement.rcNormalPosition.top = nY-nScreenY; + aPlacement.rcNormalPosition.right = nX+nWidth-nScreenX; + aPlacement.rcNormalPosition.bottom = nY+nHeight-nScreenY; + } + SetWindowPlacement( mhWnd, &aPlacement ); + } + + if( !(nPosSize & SWP_NOMOVE) ) + mbDefPos = FALSE; // window was positioned +} + +// ----------------------------------------------------------------------- + +BOOL WinSalFrame::GetWindowState( SalFrameState* pState ) +{ + if ( maState.mnWidth && maState.mnHeight ) + { + *pState = maState; + // #94144# allow Minimize again, should be masked out when read from configuration + // 91625 - Don't save minimize + //if ( !(pState->mnState & SAL_FRAMESTATE_MAXIMIZED) ) + if ( !(pState->mnState & (SAL_FRAMESTATE_MINIMIZED | SAL_FRAMESTATE_MAXIMIZED)) ) + pState->mnState |= SAL_FRAMESTATE_NORMAL; + return TRUE; + } + + return FALSE; +} + +// ----------------------------------------------------------------------- + +void WinSalFrame::SetScreenNumber( unsigned int nNewScreen ) +{ + WinSalSystem* pSys = static_cast<WinSalSystem*>(ImplGetSalSystem()); + if( pSys ) + { + const std::vector<WinSalSystem::DisplayMonitor>& rMonitors = + pSys->getMonitors(); + size_t nMon = rMonitors.size(); + if( nNewScreen < nMon ) + { + Point aOldMonPos, aNewMonPos( rMonitors[nNewScreen].m_aArea.TopLeft() ); + Point aCurPos( maGeometry.nX, maGeometry.nY ); + for( size_t i = 0; i < nMon; i++ ) + { + if( rMonitors[i].m_aArea.IsInside( aCurPos ) ) + { + aOldMonPos = rMonitors[i].m_aArea.TopLeft(); + break; + } + } + mnDisplay = nNewScreen; + maGeometry.nScreenNumber = nNewScreen; + SetPosSize( aNewMonPos.X() + (maGeometry.nX - aOldMonPos.X()), + aNewMonPos.Y() + (maGeometry.nY - aOldMonPos.Y()), + 0, 0, + SAL_FRAME_POSSIZE_X | SAL_FRAME_POSSIZE_Y ); + } + } +} + +// ----------------------------------------------------------------------- + +void WinSalFrame::ShowFullScreen( BOOL bFullScreen, sal_Int32 nDisplay ) +{ + if ( (mbFullScreen == bFullScreen) && (!bFullScreen || (mnDisplay == nDisplay)) ) + return; + + mbFullScreen = bFullScreen; + mnDisplay = nDisplay; + + if ( bFullScreen ) + { + // Damit Taskleiste von Windows ausgeblendet wird + DWORD nExStyle = GetWindowExStyle( mhWnd ); + if ( nExStyle & WS_EX_TOOLWINDOW ) + { + mbFullScreenToolWin = TRUE; + nExStyle &= ~WS_EX_TOOLWINDOW; + SetWindowExStyle( mhWnd, nExStyle ); + } + // save old position + GetWindowRect( mhWnd, &maFullScreenRect ); + + // save show state + mnFullScreenShowState = mnShowState; + if ( !(GetWindowStyle( mhWnd ) & WS_VISIBLE) ) + mnShowState = SW_SHOW; + + // set window to screen size + ImplSalFrameFullScreenPos( this, TRUE ); + } + else + { + // wenn ShowState wieder hergestellt werden muss, hiden wir zuerst + // das Fenster, damit es nicht so sehr flackert + BOOL bVisible = (GetWindowStyle( mhWnd ) & WS_VISIBLE) != 0; + if ( bVisible && (mnShowState != mnFullScreenShowState) ) + ShowWindow( mhWnd, SW_HIDE ); + + if ( mbFullScreenToolWin ) + SetWindowExStyle( mhWnd, GetWindowExStyle( mhWnd ) | WS_EX_TOOLWINDOW ); + mbFullScreenToolWin = FALSE; + + SetWindowPos( mhWnd, 0, + maFullScreenRect.left, + maFullScreenRect.top, + maFullScreenRect.right-maFullScreenRect.left, + maFullScreenRect.bottom-maFullScreenRect.top, + SWP_NOZORDER | SWP_NOACTIVATE ); + + // restore show state + if ( mnShowState != mnFullScreenShowState ) + { + mnShowState = mnFullScreenShowState; + if ( bVisible ) + { + mbInShow = TRUE; + ShowWindow( mhWnd, mnShowState ); + mbInShow = FALSE; + UpdateWindow( mhWnd ); + } + } + } +} + +// ----------------------------------------------------------------------- + +void WinSalFrame::StartPresentation( BOOL bStart ) +{ + if ( mbPresentation == bStart ) + return; + + mbPresentation = bStart; + + SalData* pSalData = GetSalData(); + if ( bStart ) + { + if ( !pSalData->mpSageEnableProc ) + { + if ( pSalData->mnSageStatus != DISABLE_AGENT ) + { + OFSTRUCT aOS; + OpenFile( "SAGE.DLL", &aOS, OF_EXIST ); + + if ( !aOS.nErrCode ) + { + OUString aLibraryName( OUString::createFromAscii( aOS.szPathName ) ); + oslModule mhSageInst = osl_loadModule( aLibraryName.pData, SAL_LOADMODULE_DEFAULT ); + OUString queryFuncName( RTL_CONSTASCII_USTRINGPARAM( "System_Agent_Enable" ) ); + pSalData->mpSageEnableProc = (SysAgt_Enable_PROC) osl_getSymbol( mhSageInst, queryFuncName.pData ); + } + else + pSalData->mnSageStatus = DISABLE_AGENT; + } + } + + if ( pSalData->mpSageEnableProc ) + { + pSalData->mnSageStatus = pSalData->mpSageEnableProc( GET_AGENT_STATUS ); + if ( pSalData->mnSageStatus == ENABLE_AGENT ) + pSalData->mpSageEnableProc( DISABLE_AGENT ); + } + + // Bildschirmschoner ausschalten, wenn Praesentation laueft + SystemParametersInfo( SPI_GETSCREENSAVEACTIVE, 0, + &(pSalData->mbScrSvrEnabled), 0 ); + if ( pSalData->mbScrSvrEnabled ) + SystemParametersInfo( SPI_SETSCREENSAVEACTIVE, FALSE, 0, 0 ); + } + else + { + // Bildschirmschoner wieder einschalten + if ( pSalData->mbScrSvrEnabled ) + SystemParametersInfo( SPI_SETSCREENSAVEACTIVE, pSalData->mbScrSvrEnabled, 0, 0 ); + + // Systemagenten wieder aktivieren + if ( pSalData->mnSageStatus == ENABLE_AGENT ) + pSalData->mpSageEnableProc( pSalData->mnSageStatus ); + } +} + +// ----------------------------------------------------------------------- + +void WinSalFrame::SetAlwaysOnTop( BOOL bOnTop ) +{ + HWND hWnd; + if ( bOnTop ) + hWnd = HWND_TOPMOST; + else + hWnd = HWND_NOTOPMOST; + SetWindowPos( mhWnd, hWnd, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE | SWP_NOACTIVATE ); +} + +// ----------------------------------------------------------------------- + +static void ImplSalToTop( HWND hWnd, USHORT nFlags ) +{ + WinSalFrame* pToTopFrame = GetWindowPtr( hWnd ); + if( pToTopFrame && (pToTopFrame->mnStyle & SAL_FRAME_STYLE_SYSTEMCHILD) != 0 ) + BringWindowToTop( hWnd ); + + if ( nFlags & SAL_FRAME_TOTOP_FOREGROUNDTASK ) + SetForegroundWindow( hWnd ); + + if ( nFlags & SAL_FRAME_TOTOP_RESTOREWHENMIN ) + { + HWND hIconicWnd = hWnd; + while ( hIconicWnd ) + { + if ( IsIconic( hIconicWnd ) ) + { + WinSalFrame* pFrame = GetWindowPtr( hIconicWnd ); + if ( pFrame ) + { + if ( GetWindowPtr( hWnd )->mbRestoreMaximize ) + ShowWindow( hIconicWnd, SW_MAXIMIZE ); + else + ShowWindow( hIconicWnd, SW_RESTORE ); + } + else + ShowWindow( hIconicWnd, SW_RESTORE ); + } + + hIconicWnd = ::GetParent( hIconicWnd ); + } + } + + if ( !IsIconic( hWnd ) && IsWindowVisible( hWnd ) ) + { + SetFocus( hWnd ); + + // Windows behauptet oefters mal, das man den Focus hat, obwohl + // man diesen nicht hat. Wenn dies der Fall ist, dann versuchen + // wir diesen auch ganz richtig zu bekommen. + if ( ::GetFocus() == hWnd ) + SetForegroundWindow( hWnd ); + } +} + +// ----------------------------------------------------------------------- + +void WinSalFrame::ToTop( USHORT nFlags ) +{ + nFlags &= ~SAL_FRAME_TOTOP_GRABFOCUS; // this flag is not needed on win32 + // Post this Message to the window, because this only works + // in the thread of the window, which has create this window. + // We post this message to avoid deadlocks + if ( GetSalData()->mnAppThreadId != GetCurrentThreadId() ) + ImplPostMessage( mhWnd, SAL_MSG_TOTOP, nFlags, 0 ); + else + ImplSalToTop( mhWnd, nFlags ); +} + +// ----------------------------------------------------------------------- + +void WinSalFrame::SetPointer( PointerStyle ePointerStyle ) +{ + struct ImplPtrData + { + HCURSOR mhCursor; + LPCSTR mnSysId; + UINT mnOwnId; + }; + + static ImplPtrData aImplPtrTab[POINTER_COUNT] = + { + { 0, IDC_ARROW, 0 }, // POINTER_ARROW + { 0, 0, SAL_RESID_POINTER_NULL }, // POINTER_NULL + { 0, IDC_WAIT, 0 }, // POINTER_WAIT + { 0, IDC_IBEAM, 0 }, // POINTER_TEXT + { 0, IDC_HELP, 0 }, // POINTER_HELP + { 0, 0, SAL_RESID_POINTER_CROSS }, // POINTER_CROSS + { 0, 0, SAL_RESID_POINTER_MOVE }, // POINTER_MOVE + { 0, IDC_SIZENS, 0 }, // POINTER_NSIZE + { 0, IDC_SIZENS, 0 }, // POINTER_SSIZE + { 0, IDC_SIZEWE, 0 }, // POINTER_WSIZE + { 0, IDC_SIZEWE, 0 }, // POINTER_ESIZE + { 0, IDC_SIZENWSE, 0 }, // POINTER_NWSIZE + { 0, IDC_SIZENESW, 0 }, // POINTER_NESIZE + { 0, IDC_SIZENESW, 0 }, // POINTER_SWSIZE + { 0, IDC_SIZENWSE, 0 }, // POINTER_SESIZE + { 0, IDC_SIZENS, 0 }, // POINTER_WINDOW_NSIZE + { 0, IDC_SIZENS, 0 }, // POINTER_WINDOW_SSIZE + { 0, IDC_SIZEWE, 0 }, // POINTER_WINDOW_WSIZE + { 0, IDC_SIZEWE, 0 }, // POINTER_WINDOW_ESIZE + { 0, IDC_SIZENWSE, 0 }, // POINTER_WINDOW_NWSIZE + { 0, IDC_SIZENESW, 0 }, // POINTER_WINDOW_NESIZE + { 0, IDC_SIZENESW, 0 }, // POINTER_WINDOW_SWSIZE + { 0, IDC_SIZENWSE, 0 }, // POINTER_WINDOW_SESIZE + { 0, 0, SAL_RESID_POINTER_HSPLIT }, // POINTER_HSPLIT + { 0, 0, SAL_RESID_POINTER_VSPLIT }, // POINTER_VSPLIT + { 0, 0, SAL_RESID_POINTER_HSIZEBAR }, // POINTER_HSIZEBAR + { 0, 0, SAL_RESID_POINTER_VSIZEBAR }, // POINTER_VSIZEBAR + { 0, 0, SAL_RESID_POINTER_HAND }, // POINTER_HAND + { 0, 0, SAL_RESID_POINTER_REFHAND }, // POINTER_REFHAND + { 0, 0, SAL_RESID_POINTER_PEN }, // POINTER_PEN + { 0, 0, SAL_RESID_POINTER_MAGNIFY }, // POINTER_MAGNIFY + { 0, 0, SAL_RESID_POINTER_FILL }, // POINTER_FILL + { 0, 0, SAL_RESID_POINTER_ROTATE }, // POINTER_ROTATE + { 0, 0, SAL_RESID_POINTER_HSHEAR }, // POINTER_HSHEAR + { 0, 0, SAL_RESID_POINTER_VSHEAR }, // POINTER_VSHEAR + { 0, 0, SAL_RESID_POINTER_MIRROR }, // POINTER_MIRROR + { 0, 0, SAL_RESID_POINTER_CROOK }, // POINTER_CROOK + { 0, 0, SAL_RESID_POINTER_CROP }, // POINTER_CROP + { 0, 0, SAL_RESID_POINTER_MOVEPOINT }, // POINTER_MOVEPOINT + { 0, 0, SAL_RESID_POINTER_MOVEBEZIERWEIGHT }, // POINTER_MOVEBEZIERWEIGHT + { 0, 0, SAL_RESID_POINTER_MOVEDATA }, // POINTER_MOVEDATA + { 0, 0, SAL_RESID_POINTER_COPYDATA }, // POINTER_COPYDATA + { 0, 0, SAL_RESID_POINTER_LINKDATA }, // POINTER_LINKDATA + { 0, 0, SAL_RESID_POINTER_MOVEDATALINK }, // POINTER_MOVEDATALINK + { 0, 0, SAL_RESID_POINTER_COPYDATALINK }, // POINTER_COPYDATALINK + { 0, 0, SAL_RESID_POINTER_MOVEFILE }, // POINTER_MOVEFILE + { 0, 0, SAL_RESID_POINTER_COPYFILE }, // POINTER_COPYFILE + { 0, 0, SAL_RESID_POINTER_LINKFILE }, // POINTER_LINKFILE + { 0, 0, SAL_RESID_POINTER_MOVEFILELINK }, // POINTER_MOVEFILELINK + { 0, 0, SAL_RESID_POINTER_COPYFILELINK }, // POINTER_COPYFILELINK + { 0, 0, SAL_RESID_POINTER_MOVEFILES }, // POINTER_MOVEFILES + { 0, 0, SAL_RESID_POINTER_COPYFILES }, // POINTER_COPYFILES + { 0, 0, SAL_RESID_POINTER_NOTALLOWED }, // POINTER_NOTALLOWED + { 0, 0, SAL_RESID_POINTER_DRAW_LINE }, // POINTER_DRAW_LINE + { 0, 0, SAL_RESID_POINTER_DRAW_RECT }, // POINTER_DRAW_RECT + { 0, 0, SAL_RESID_POINTER_DRAW_POLYGON }, // POINTER_DRAW_POLYGON + { 0, 0, SAL_RESID_POINTER_DRAW_BEZIER }, // POINTER_DRAW_BEZIER + { 0, 0, SAL_RESID_POINTER_DRAW_ARC }, // POINTER_DRAW_ARC + { 0, 0, SAL_RESID_POINTER_DRAW_PIE }, // POINTER_DRAW_PIE + { 0, 0, SAL_RESID_POINTER_DRAW_CIRCLECUT }, // POINTER_DRAW_CIRCLECUT + { 0, 0, SAL_RESID_POINTER_DRAW_ELLIPSE }, // POINTER_DRAW_ELLIPSE + { 0, 0, SAL_RESID_POINTER_DRAW_FREEHAND }, // POINTER_DRAW_FREEHAND + { 0, 0, SAL_RESID_POINTER_DRAW_CONNECT }, // POINTER_DRAW_CONNECT + { 0, 0, SAL_RESID_POINTER_DRAW_TEXT }, // POINTER_DRAW_TEXT + { 0, 0, SAL_RESID_POINTER_DRAW_CAPTION }, // POINTER_DRAW_CAPTION + { 0, 0, SAL_RESID_POINTER_CHART }, // POINTER_CHART + { 0, 0, SAL_RESID_POINTER_DETECTIVE }, // POINTER_DETECTIVE + { 0, 0, SAL_RESID_POINTER_PIVOT_COL }, // POINTER_PIVOT_COL + { 0, 0, SAL_RESID_POINTER_PIVOT_ROW }, // POINTER_PIVOT_ROW + { 0, 0, SAL_RESID_POINTER_PIVOT_FIELD }, // POINTER_PIVOT_FIELD + { 0, 0, SAL_RESID_POINTER_CHAIN }, // POINTER_CHAIN + { 0, 0, SAL_RESID_POINTER_CHAIN_NOTALLOWED }, // POINTER_CHAIN_NOTALLOWED + { 0, 0, SAL_RESID_POINTER_TIMEEVENT_MOVE }, // POINTER_TIMEEVENT_MOVE + { 0, 0, SAL_RESID_POINTER_TIMEEVENT_SIZE }, // POINTER_TIMEEVENT_SIZE + { 0, 0, SAL_RESID_POINTER_AUTOSCROLL_N }, // POINTER_AUTOSCROLL_N + { 0, 0, SAL_RESID_POINTER_AUTOSCROLL_S }, // POINTER_AUTOSCROLL_S + { 0, 0, SAL_RESID_POINTER_AUTOSCROLL_W }, // POINTER_AUTOSCROLL_W + { 0, 0, SAL_RESID_POINTER_AUTOSCROLL_E }, // POINTER_AUTOSCROLL_E + { 0, 0, SAL_RESID_POINTER_AUTOSCROLL_NW }, // POINTER_AUTOSCROLL_NW + { 0, 0, SAL_RESID_POINTER_AUTOSCROLL_NE }, // POINTER_AUTOSCROLL_NE + { 0, 0, SAL_RESID_POINTER_AUTOSCROLL_SW }, // POINTER_AUTOSCROLL_SW + { 0, 0, SAL_RESID_POINTER_AUTOSCROLL_SE }, // POINTER_AUTOSCROLL_SE + { 0, 0, SAL_RESID_POINTER_AUTOSCROLL_NS }, // POINTER_AUTOSCROLL_NS + { 0, 0, SAL_RESID_POINTER_AUTOSCROLL_WE }, // POINTER_AUTOSCROLL_WE + { 0, 0, SAL_RESID_POINTER_AUTOSCROLL_NSWE }, // POINTER_AUTOSCROLL_NSWE + { 0, 0, SAL_RESID_POINTER_AIRBRUSH }, // POINTER_AIRBRUSH + { 0, 0, SAL_RESID_POINTER_TEXT_VERTICAL }, // POINTER_TEXT_VERTICAL + { 0, 0, SAL_RESID_POINTER_PIVOT_DELETE }, // POINTER_PIVOT_DELETE + + // --> FME 2004-07-30 #i32329# Enhanced table selection + { 0, 0, SAL_RESID_POINTER_TAB_SELECT_S }, // POINTER_TAB_SELECT_S + { 0, 0, SAL_RESID_POINTER_TAB_SELECT_E }, // POINTER_TAB_SELECT_E + { 0, 0, SAL_RESID_POINTER_TAB_SELECT_SE }, // POINTER_TAB_SELECT_SE + { 0, 0, SAL_RESID_POINTER_TAB_SELECT_W }, // POINTER_TAB_SELECT_W + { 0, 0, SAL_RESID_POINTER_TAB_SELECT_SW }, // POINTER_TAB_SELECT_SW + // <-- + + // --> FME 2004-08-16 #i20119# Paintbrush tool + { 0, 0, SAL_RESID_POINTER_PAINTBRUSH } // POINTER_PAINTBRUSH + // <-- + + }; + +#if POINTER_COUNT != 94 +#error New Pointer must be defined! +#endif + + // Mousepointer loaded ? + if ( !aImplPtrTab[ePointerStyle].mhCursor ) + { + if ( aImplPtrTab[ePointerStyle].mnOwnId ) + aImplPtrTab[ePointerStyle].mhCursor = ImplLoadSalCursor( aImplPtrTab[ePointerStyle].mnOwnId ); + else + aImplPtrTab[ePointerStyle].mhCursor = LoadCursor( 0, aImplPtrTab[ePointerStyle].mnSysId ); + } + + // Unterscheidet sich der Mauspointer, dann den neuen setzen + if ( mhCursor != aImplPtrTab[ePointerStyle].mhCursor ) + { + mhCursor = aImplPtrTab[ePointerStyle].mhCursor; + SetCursor( mhCursor ); + } +} + +// ----------------------------------------------------------------------- + +void WinSalFrame::CaptureMouse( BOOL bCapture ) +{ + // Send this Message to the window, because CaptureMouse() only work + // in the thread of the window, which has create this window + int nMsg; + if ( bCapture ) + nMsg = SAL_MSG_CAPTUREMOUSE; + else + nMsg = SAL_MSG_RELEASEMOUSE; + ImplSendMessage( mhWnd, nMsg, 0, 0 ); +} + +// ----------------------------------------------------------------------- + +void WinSalFrame::SetPointerPos( long nX, long nY ) +{ + POINT aPt; + aPt.x = (int)nX; + aPt.y = (int)nY; + ClientToScreen( mhWnd, &aPt ); + SetCursorPos( aPt.x, aPt.y ); +} + +// ----------------------------------------------------------------------- + +void WinSalFrame::Flush() +{ + GdiFlush(); +} + +// ----------------------------------------------------------------------- + +void WinSalFrame::Sync() +{ + GdiFlush(); +} + +// ----------------------------------------------------------------------- + +static void ImplSalFrameSetInputContext( HWND hWnd, const SalInputContext* pContext ) +{ + WinSalFrame* pFrame = GetWindowPtr( hWnd ); + BOOL bIME = (pContext->mnOptions & SAL_INPUTCONTEXT_TEXT) != 0; + if ( bIME ) + { + if ( !pFrame->mbIME ) + { + pFrame->mbIME = TRUE; + + if ( pFrame->mhDefIMEContext ) + { + ImmAssociateContext( pFrame->mhWnd, pFrame->mhDefIMEContext ); + UINT nImeProps = ImmGetProperty( GetKeyboardLayout( 0 ), IGP_PROPERTY ); + pFrame->mbSpezIME = (nImeProps & IME_PROP_SPECIAL_UI) != 0; + pFrame->mbAtCursorIME = (nImeProps & IME_PROP_AT_CARET) != 0; + pFrame->mbHandleIME = !pFrame->mbSpezIME; + } + } + + // When the application can't handle IME messages, then the + // System should handle the IME handling + if ( !(pContext->mnOptions & SAL_INPUTCONTEXT_EXTTEXTINPUT) ) + pFrame->mbHandleIME = FALSE; + + // Set the Font for IME Handling + if ( pContext->mpFont ) + { + HIMC hIMC = ImmGetContext( pFrame->mhWnd ); + if ( hIMC ) + { + LOGFONTW aLogFont; + HDC hDC = GetDC( pFrame->mhWnd ); + // In case of vertical writing, always append a '@' to the + // Windows font name, not only if such a Windows font really is + // available (bTestVerticalAvail == false in the below call): + // The Windows IME's candidates window seems to always use a + // font that has all necessary glyphs, not necessarily the one + // specified by this font name; but it seems to decide whether + // to use that font's horizontal or vertical variant based on a + // '@' in front of this font name. + ImplGetLogFontFromFontSelect( hDC, pContext->mpFont, aLogFont, + false ); + ReleaseDC( pFrame->mhWnd, hDC ); + ImmSetCompositionFontW( hIMC, &aLogFont ); + ImmReleaseContext( pFrame->mhWnd, hIMC ); + } + } + } + else + { + if ( pFrame->mbIME ) + { + pFrame->mbIME = FALSE; + pFrame->mbHandleIME = FALSE; + ImmAssociateContext( pFrame->mhWnd, 0 ); + } + } +} + +// ----------------------------------------------------------------------- + +void WinSalFrame::SetInputContext( SalInputContext* pContext ) +{ + // Must be called in the main thread! + ImplSendMessage( mhWnd, SAL_MSG_SETINPUTCONTEXT, 0, (LPARAM)(void*)pContext ); +} + +// ----------------------------------------------------------------------- + +static void ImplSalFrameEndExtTextInput( HWND hWnd, USHORT nFlags ) +{ + HIMC hIMC = ImmGetContext( hWnd ); + if ( hIMC ) + { + DWORD nIndex; + if ( nFlags & SAL_FRAME_ENDEXTTEXTINPUT_COMPLETE ) + nIndex = CPS_COMPLETE; + else + nIndex = CPS_CANCEL; + + ImmNotifyIME( hIMC, NI_COMPOSITIONSTR, nIndex, 0 ); + ImmReleaseContext( hWnd, hIMC ); + } +} + +// ----------------------------------------------------------------------- + +void WinSalFrame::EndExtTextInput( USHORT nFlags ) +{ + // Must be called in the main thread! + ImplSendMessage( mhWnd, SAL_MSG_ENDEXTTEXTINPUT, (WPARAM)nFlags, 0 ); +} + +// ----------------------------------------------------------------------- + +static void ImplGetKeyNameText( LONG lParam, sal_Unicode* pBuf, + UINT& rCount, UINT nMaxSize, + const sal_Char* pReplace ) +{ + DBG_ASSERT( sizeof( WCHAR ) == sizeof( xub_Unicode ), "WinSalFrame::ImplGetKeyNameTextW(): WCHAR != sal_Unicode" ); + + static const int nMaxKeyLen = 350; + WCHAR aKeyBuf[ nMaxKeyLen ]; + int nKeyLen = 0; + if ( lParam ) + { + if ( aSalShlData.mbWNT ) + { + nKeyLen = GetKeyNameTextW( lParam, aKeyBuf, nMaxKeyLen ); + // #i12401# the current unicows.dll has a bug in CharUpperBuffW, which corrupts the stack + // fall back to the ANSI version instead + DBG_ASSERT( nKeyLen <= nMaxKeyLen, "Invalid key name length!" ); + if( nKeyLen > nMaxKeyLen ) + nKeyLen = 0; + else if( nKeyLen > 0 ) + { + // Capitalize just the first letter of key names + CharLowerBuffW( aKeyBuf, nKeyLen ); + + bool bUpper = true; + for( WCHAR *pW=aKeyBuf, *pE=pW+nKeyLen; pW < pE; ++pW ) + { + if( bUpper ) + CharUpperBuffW( pW, 1 ); + bUpper = (*pW=='+') || (*pW=='-') || (*pW==' ') || (*pW=='.'); + } + } + } + else // !mbWnt + { + sal_Char aAnsiKeyBuf[ nMaxKeyLen ]; + int nAnsiKeyLen = GetKeyNameTextA( lParam, aAnsiKeyBuf, nMaxKeyLen ); + DBG_ASSERT( nAnsiKeyLen <= nMaxKeyLen, "Invalid key name length!" ); + if( nAnsiKeyLen > nMaxKeyLen ) + nAnsiKeyLen = 0; + else if( nAnsiKeyLen > 0 ) + { + // Capitalize just the first letter of key names + // TODO: check MCBS key names + CharLowerBuffA( aAnsiKeyBuf, nAnsiKeyLen ); + + bool bUpper = true; + for( sal_Char *pA=aAnsiKeyBuf, *pE=pA+nAnsiKeyLen; pA < pE; ++pA ) + { + if( bUpper ) + CharUpperBuffA( pA, 1 ); + bUpper = (*pA=='+') || (*pA=='-') || (*pA==' ') || (*pA=='.'); + } + + // Convert to Unicode and copy the data in the Unicode Buffer + nKeyLen = MultiByteToWideChar( CP_ACP, MB_PRECOMPOSED, + aAnsiKeyBuf, nAnsiKeyLen, aKeyBuf, nMaxKeyLen ); + } + } + } + + if ( (nKeyLen > 0) || pReplace ) + { + if( (rCount > 0) && (rCount < nMaxSize) ) + { + pBuf[rCount] = '+'; + rCount++; + } + + if( nKeyLen > 0 ) + { + if( nKeyLen + rCount > nMaxSize ) + nKeyLen = nMaxSize - rCount; + memcpy( pBuf+rCount, aKeyBuf, nKeyLen*sizeof( sal_Unicode ) ); + rCount += nKeyLen; + } + else // fall back to provided default name + { + while( *pReplace && (rCount < nMaxSize) ) + { + pBuf[rCount] = *pReplace; + rCount++; + pReplace++; + } + } + } + else + rCount = 0; +} + +// ----------------------------------------------------------------------- + +XubString WinSalFrame::GetKeyName( USHORT nKeyCode ) +{ + static const int nMaxKeyLen = 350; + sal_Unicode aKeyBuf[ nMaxKeyLen ]; + UINT nKeyBufLen = 0; + UINT nSysCode = 0; + + if ( nKeyCode & KEY_MOD1 ) + { + nSysCode = MapVirtualKey( VK_CONTROL, 0 ); + nSysCode = (nSysCode << 16) | (((ULONG)1) << 25); + ImplGetKeyNameText( nSysCode, aKeyBuf, nKeyBufLen, nMaxKeyLen, "Ctrl" ); + } + + if ( nKeyCode & KEY_MOD2 ) + { + nSysCode = MapVirtualKey( VK_MENU, 0 ); + nSysCode = (nSysCode << 16) | (((ULONG)1) << 25); + ImplGetKeyNameText( nSysCode, aKeyBuf, nKeyBufLen, nMaxKeyLen, "Alt" ); + } + + if ( nKeyCode & KEY_SHIFT ) + { + nSysCode = MapVirtualKey( VK_SHIFT, 0 ); + nSysCode = (nSysCode << 16) | (((ULONG)1) << 25); + ImplGetKeyNameText( nSysCode, aKeyBuf, nKeyBufLen, nMaxKeyLen, "Shift" ); + } + + USHORT nCode = nKeyCode & 0x0FFF; + ULONG nSysCode2 = 0; + sal_Char* pReplace = NULL; + sal_Unicode cSVCode = 0; + sal_Char aFBuf[4]; + nSysCode = 0; + + if ( (nCode >= KEY_0) && (nCode <= KEY_9) ) + cSVCode = '0' + (nCode - KEY_0); + else if ( (nCode >= KEY_A) && (nCode <= KEY_Z) ) + cSVCode = 'A' + (nCode - KEY_A); + else if ( (nCode >= KEY_F1) && (nCode <= KEY_F26) ) + { + nSysCode = VK_F1 + (nCode - KEY_F1); + aFBuf[0] = 'F'; + if ( (nCode >= KEY_F1) && (nCode <= KEY_F9) ) + { + aFBuf[1] = sal::static_int_cast<sal_Char>('1' + (nCode - KEY_F1)); + aFBuf[2] = 0; + } + else if ( (nCode >= KEY_F10) && (nCode <= KEY_F19) ) + { + aFBuf[1] = '1'; + aFBuf[2] = sal::static_int_cast<sal_Char>('0' + (nCode - KEY_F10)); + aFBuf[3] = 0; + } + else + { + aFBuf[1] = '2'; + aFBuf[2] = sal::static_int_cast<sal_Char>('0' + (nCode - KEY_F20)); + aFBuf[3] = 0; + } + pReplace = aFBuf; + } + else + { + switch ( nCode ) + { + case KEY_DOWN: + nSysCode = VK_DOWN; + nSysCode2 = (((ULONG)1) << 24); + pReplace = "Down"; + break; + case KEY_UP: + nSysCode = VK_UP; + nSysCode2 = (((ULONG)1) << 24); + pReplace = "Up"; + break; + case KEY_LEFT: + nSysCode = VK_LEFT; + nSysCode2 = (((ULONG)1) << 24); + pReplace = "Left"; + break; + case KEY_RIGHT: + nSysCode = VK_RIGHT; + nSysCode2 = (((ULONG)1) << 24); + pReplace = "Right"; + break; + case KEY_HOME: + nSysCode = VK_HOME; + nSysCode2 = (((ULONG)1) << 24); + pReplace = "Home"; + break; + case KEY_END: + nSysCode = VK_END; + nSysCode2 = (((ULONG)1) << 24); + pReplace = "End"; + break; + case KEY_PAGEUP: + nSysCode = VK_PRIOR; + nSysCode2 = (((ULONG)1) << 24); + pReplace = "Page Up"; + break; + case KEY_PAGEDOWN: + nSysCode = VK_NEXT; + nSysCode2 = (((ULONG)1) << 24); + pReplace = "Page Down"; + break; + case KEY_RETURN: + nSysCode = VK_RETURN; + pReplace = "Enter"; + break; + case KEY_ESCAPE: + nSysCode = VK_ESCAPE; + pReplace = "Escape"; + break; + case KEY_TAB: + nSysCode = VK_TAB; + pReplace = "Tab"; + break; + case KEY_BACKSPACE: + nSysCode = VK_BACK; + pReplace = "Backspace"; + break; + case KEY_SPACE: + nSysCode = VK_SPACE; + pReplace = "Space"; + break; + case KEY_INSERT: + nSysCode = VK_INSERT; + nSysCode2 = (((ULONG)1) << 24); + pReplace = "Insert"; + break; + case KEY_DELETE: + nSysCode = VK_DELETE; + nSysCode2 = (((ULONG)1) << 24); + pReplace = "Delete"; + break; + + case KEY_ADD: + cSVCode = '+'; + break; + case KEY_SUBTRACT: + cSVCode = '-'; + break; + case KEY_MULTIPLY: + cSVCode = '*'; + break; + case KEY_DIVIDE: + cSVCode = '/'; + break; + case KEY_POINT: + cSVCode = '.'; + break; + case KEY_COMMA: + cSVCode = ','; + break; + case KEY_LESS: + cSVCode = '<'; + break; + case KEY_GREATER: + cSVCode = '>'; + break; + case KEY_EQUAL: + cSVCode = '='; + break; + } + } + + if ( nSysCode ) + { + nSysCode = MapVirtualKey( (UINT)nSysCode, 0 ); + if ( nSysCode ) + nSysCode = (nSysCode << 16) | nSysCode2; + ImplGetKeyNameText( nSysCode, aKeyBuf, nKeyBufLen, nMaxKeyLen, pReplace ); + } + else + { + if ( cSVCode ) + { + if ( nKeyBufLen > 0 ) + aKeyBuf[ nKeyBufLen++ ] = '+'; + if( nKeyBufLen < nMaxKeyLen ) + aKeyBuf[ nKeyBufLen++ ] = cSVCode; + } + } + + if( !nKeyBufLen ) + return XubString(); + + return XubString( aKeyBuf, sal::static_int_cast< USHORT >(nKeyBufLen) ); +} + +// ----------------------------------------------------------------------- + +XubString WinSalFrame::GetSymbolKeyName( const XubString&, USHORT nKeyCode ) +{ + return GetKeyName( nKeyCode ); +} + +// ----------------------------------------------------------------------- + +inline Color ImplWinColorToSal( COLORREF nColor ) +{ + return Color( GetRValue( nColor ), GetGValue( nColor ), GetBValue( nColor ) ); +} + +// ----------------------------------------------------------------------- + +static void ImplSalUpdateStyleFontA( HDC hDC, const LOGFONTA& rLogFont, Font& rFont ) +{ + ImplSalLogFontToFontA( hDC, rLogFont, rFont ); + + // On Windows 9x, Windows NT we get sometimes very small sizes + // (for example for the small Caption height). + // So if it is MS Sans Serif, a none scalable font we use + // 8 Point as the minimum control height, in all other cases + // 6 Point is the smallest one + if ( rFont.GetHeight() < 8 ) + { + if ( rtl_str_compareIgnoreAsciiCase( rLogFont.lfFaceName, "MS Sans Serif" ) == 0 ) + rFont.SetHeight( 8 ); + else if ( rFont.GetHeight() < 6 ) + rFont.SetHeight( 6 ); + } +} + +// ----------------------------------------------------------------------- + +static void ImplSalUpdateStyleFontW( HDC hDC, const LOGFONTW& rLogFont, Font& rFont ) +{ + ImplSalLogFontToFontW( hDC, rLogFont, rFont ); + + // On Windows 9x, Windows NT we get sometimes very small sizes + // (for example for the small Caption height). + // So if it is MS Sans Serif, a none scalable font we use + // 8 Point as the minimum control height, in all other cases + // 6 Point is the smallest one + if ( rFont.GetHeight() < 8 ) + { + if ( rtl_ustr_compareIgnoreAsciiCase( reinterpret_cast<const sal_Unicode*>(rLogFont.lfFaceName), reinterpret_cast<const sal_Unicode*>(L"MS Sans Serif") ) == 0 ) + rFont.SetHeight( 8 ); + else if ( rFont.GetHeight() < 6 ) + rFont.SetHeight( 6 ); + } +} + +// ----------------------------------------------------------------------- + +static long ImplA2I( const BYTE* pStr ) +{ + long n = 0; + int nSign = 1; + + if ( *pStr == '-' ) + { + nSign = -1; + pStr++; + } + + while( (*pStr >= 48) && (*pStr <= 57) ) + { + n *= 10; + n += ((*pStr) - 48); + pStr++; + } + + n *= nSign; + + return n; +} + +// ----------------------------------------------------------------------- + +void WinSalFrame::UpdateSettings( AllSettings& rSettings ) +{ + MouseSettings aMouseSettings = rSettings.GetMouseSettings(); + aMouseSettings.SetDoubleClickTime( GetDoubleClickTime() ); + aMouseSettings.SetDoubleClickWidth( GetSystemMetrics( SM_CXDOUBLECLK ) ); + aMouseSettings.SetDoubleClickHeight( GetSystemMetrics( SM_CYDOUBLECLK ) ); + long nDragWidth = GetSystemMetrics( SM_CXDRAG ); + long nDragHeight = GetSystemMetrics( SM_CYDRAG ); + if ( nDragWidth ) + aMouseSettings.SetStartDragWidth( nDragWidth ); + if ( nDragHeight ) + aMouseSettings.SetStartDragHeight( nDragHeight ); + HKEY hRegKey; + if ( RegOpenKey( HKEY_CURRENT_USER, + "Control Panel\\Desktop", + &hRegKey ) == ERROR_SUCCESS ) + { + BYTE aValueBuf[10]; + DWORD nValueSize = sizeof( aValueBuf ); + DWORD nType; + if ( RegQueryValueEx( hRegKey, "MenuShowDelay", 0, + &nType, aValueBuf, &nValueSize ) == ERROR_SUCCESS ) + { + if ( nType == REG_SZ ) + aMouseSettings.SetMenuDelay( (ULONG)ImplA2I( aValueBuf ) ); + } + + RegCloseKey( hRegKey ); + } + + StyleSettings aStyleSettings = rSettings.GetStyleSettings(); + BOOL bCompBorder = (aStyleSettings.GetOptions() & (STYLE_OPTION_MACSTYLE | STYLE_OPTION_UNIXSTYLE)) == 0; + // TODO: once those options vanish: just set bCompBorder to TRUE + // to have the system colors read + aStyleSettings.SetScrollBarSize( Min( GetSystemMetrics( SM_CXVSCROLL ), 20 ) ); // #99956# do not allow huge scrollbars, most of the UI is not scaled anymore + aStyleSettings.SetSpinSize( Min( GetSystemMetrics( SM_CXVSCROLL ), 20 ) ); + aStyleSettings.SetCursorBlinkTime( GetCaretBlinkTime() ); + if ( bCompBorder ) + { + aStyleSettings.SetFloatTitleHeight( GetSystemMetrics( SM_CYSMCAPTION ) ); + aStyleSettings.SetTitleHeight( GetSystemMetrics( SM_CYCAPTION ) ); + aStyleSettings.SetActiveBorderColor( ImplWinColorToSal( GetSysColor( COLOR_ACTIVEBORDER ) ) ); + aStyleSettings.SetDeactiveBorderColor( ImplWinColorToSal( GetSysColor( COLOR_INACTIVEBORDER ) ) ); + if ( aSalShlData.mnVersion >= 410 ) + { + aStyleSettings.SetActiveColor2( ImplWinColorToSal( GetSysColor( COLOR_GRADIENTACTIVECAPTION ) ) ); + aStyleSettings.SetDeactiveColor( ImplWinColorToSal( GetSysColor( COLOR_GRADIENTINACTIVECAPTION ) ) ); + } + aStyleSettings.SetFaceColor( ImplWinColorToSal( GetSysColor( COLOR_3DFACE ) ) ); + aStyleSettings.SetInactiveTabColor( aStyleSettings.GetFaceColor() ); + aStyleSettings.SetLightColor( ImplWinColorToSal( GetSysColor( COLOR_3DHILIGHT ) ) ); + aStyleSettings.SetLightBorderColor( ImplWinColorToSal( GetSysColor( COLOR_3DLIGHT ) ) ); + aStyleSettings.SetShadowColor( ImplWinColorToSal( GetSysColor( COLOR_3DSHADOW ) ) ); + aStyleSettings.SetDarkShadowColor( ImplWinColorToSal( GetSysColor( COLOR_3DDKSHADOW ) ) ); + } + aStyleSettings.SetWorkspaceColor( ImplWinColorToSal( GetSysColor( COLOR_APPWORKSPACE ) ) ); + aStyleSettings.SetHelpColor( ImplWinColorToSal( GetSysColor( COLOR_INFOBK ) ) ); + aStyleSettings.SetHelpTextColor( ImplWinColorToSal( GetSysColor( COLOR_INFOTEXT ) ) ); + aStyleSettings.SetDialogColor( aStyleSettings.GetFaceColor() ); + aStyleSettings.SetDialogTextColor( aStyleSettings.GetButtonTextColor() ); + aStyleSettings.SetButtonTextColor( ImplWinColorToSal( GetSysColor( COLOR_BTNTEXT ) ) ); + aStyleSettings.SetButtonRolloverTextColor( aStyleSettings.GetButtonTextColor() ); + aStyleSettings.SetRadioCheckTextColor( ImplWinColorToSal( GetSysColor( COLOR_WINDOWTEXT ) ) ); + aStyleSettings.SetGroupTextColor( aStyleSettings.GetRadioCheckTextColor() ); + aStyleSettings.SetLabelTextColor( aStyleSettings.GetRadioCheckTextColor() ); + aStyleSettings.SetInfoTextColor( aStyleSettings.GetRadioCheckTextColor() ); + aStyleSettings.SetWindowColor( ImplWinColorToSal( GetSysColor( COLOR_WINDOW ) ) ); + aStyleSettings.SetActiveTabColor( aStyleSettings.GetWindowColor() ); + aStyleSettings.SetWindowTextColor( ImplWinColorToSal( GetSysColor( COLOR_WINDOWTEXT ) ) ); + aStyleSettings.SetFieldColor( aStyleSettings.GetWindowColor() ); + aStyleSettings.SetFieldTextColor( aStyleSettings.GetWindowTextColor() ); + aStyleSettings.SetFieldRolloverTextColor( aStyleSettings.GetFieldTextColor() ); + aStyleSettings.SetHighlightColor( ImplWinColorToSal( GetSysColor( COLOR_HIGHLIGHT ) ) ); + aStyleSettings.SetHighlightTextColor( ImplWinColorToSal( GetSysColor( COLOR_HIGHLIGHTTEXT ) ) ); + aStyleSettings.SetMenuHighlightColor( aStyleSettings.GetHighlightColor() ); + aStyleSettings.SetMenuHighlightTextColor( aStyleSettings.GetHighlightTextColor() ); + if ( bCompBorder ) + { + aStyleSettings.SetMenuColor( ImplWinColorToSal( GetSysColor( COLOR_MENU ) ) ); + aStyleSettings.SetMenuBarColor( aStyleSettings.GetMenuColor() ); + aStyleSettings.SetMenuBorderColor( aStyleSettings.GetLightBorderColor() ); // overriden below for flat menus + aStyleSettings.SetUseFlatBorders( FALSE ); + aStyleSettings.SetUseFlatMenues( FALSE ); + aStyleSettings.SetMenuTextColor( ImplWinColorToSal( GetSysColor( COLOR_MENUTEXT ) ) ); + aStyleSettings.SetActiveColor( ImplWinColorToSal( GetSysColor( COLOR_ACTIVECAPTION ) ) ); + aStyleSettings.SetActiveTextColor( ImplWinColorToSal( GetSysColor( COLOR_CAPTIONTEXT ) ) ); + aStyleSettings.SetDeactiveColor( ImplWinColorToSal( GetSysColor( COLOR_INACTIVECAPTION ) ) ); + aStyleSettings.SetDeactiveTextColor( ImplWinColorToSal( GetSysColor( COLOR_INACTIVECAPTIONTEXT ) ) ); + if ( aSalShlData.mbWXP ) + { + // only xp supports a different menu bar color + long bFlatMenues = 0; + SystemParametersInfo( SPI_GETFLATMENU, 0, &bFlatMenues, 0); + if( bFlatMenues ) + { + aStyleSettings.SetUseFlatMenues( TRUE ); + aStyleSettings.SetMenuBarColor( ImplWinColorToSal( GetSysColor( COLOR_MENUBAR ) ) ); + aStyleSettings.SetMenuHighlightColor( ImplWinColorToSal( GetSysColor( COLOR_MENUHILIGHT ) ) ); + aStyleSettings.SetMenuBorderColor( ImplWinColorToSal( GetSysColor( COLOR_3DSHADOW ) ) ); + + // flat borders for our controls etc. as well in this mode (ie, no 3d borders) + // this is not active in the classic style appearance + aStyleSettings.SetUseFlatBorders( TRUE ); + } + } + } + // Bei hellgrau geben wir die Farbe vor, damit es besser aussieht + if ( aStyleSettings.GetFaceColor() == COL_LIGHTGRAY ) + aStyleSettings.SetCheckedColor( Color( 0xCC, 0xCC, 0xCC ) ); + else + { + // Checked-Color berechnen + Color aColor1 = aStyleSettings.GetFaceColor(); + Color aColor2 = aStyleSettings.GetLightColor(); + BYTE nRed = (BYTE)(((USHORT)aColor1.GetRed() + (USHORT)aColor2.GetRed())/2); + BYTE nGreen = (BYTE)(((USHORT)aColor1.GetGreen() + (USHORT)aColor2.GetGreen())/2); + BYTE nBlue = (BYTE)(((USHORT)aColor1.GetBlue() + (USHORT)aColor2.GetBlue())/2); + aStyleSettings.SetCheckedColor( Color( nRed, nGreen, nBlue ) ); + } + + // High contrast + HIGHCONTRAST hc; + hc.cbSize = sizeof( HIGHCONTRAST ); + if( SystemParametersInfo( SPI_GETHIGHCONTRAST, hc.cbSize, &hc, 0) && (hc.dwFlags & HCF_HIGHCONTRASTON) ) + aStyleSettings.SetHighContrastMode( 1 ); + else + aStyleSettings.SetHighContrastMode( 0 ); + + + // Query Fonts + Font aMenuFont = aStyleSettings.GetMenuFont(); + Font aTitleFont = aStyleSettings.GetTitleFont(); + Font aFloatTitleFont = aStyleSettings.GetFloatTitleFont(); + Font aHelpFont = aStyleSettings.GetHelpFont(); + Font aAppFont = aStyleSettings.GetAppFont(); + Font aIconFont = aStyleSettings.GetIconFont(); + HDC hDC = GetDC( 0 ); + if ( aSalShlData.mbWNT ) + { + NONCLIENTMETRICSW aNonClientMetrics; + aNonClientMetrics.cbSize = sizeof( aNonClientMetrics ); + if ( SystemParametersInfoW( SPI_GETNONCLIENTMETRICS, sizeof( aNonClientMetrics ), &aNonClientMetrics, 0 ) ) + { + ImplSalUpdateStyleFontW( hDC, aNonClientMetrics.lfMenuFont, aMenuFont ); + ImplSalUpdateStyleFontW( hDC, aNonClientMetrics.lfCaptionFont, aTitleFont ); + ImplSalUpdateStyleFontW( hDC, aNonClientMetrics.lfSmCaptionFont, aFloatTitleFont ); + ImplSalUpdateStyleFontW( hDC, aNonClientMetrics.lfStatusFont, aHelpFont ); + ImplSalUpdateStyleFontW( hDC, aNonClientMetrics.lfMessageFont, aAppFont ); + + LOGFONTW aLogFont; + if ( SystemParametersInfoW( SPI_GETICONTITLELOGFONT, 0, &aLogFont, 0 ) ) + ImplSalUpdateStyleFontW( hDC, aLogFont, aIconFont ); + } + } + else + { + NONCLIENTMETRICSA aNonClientMetrics; + aNonClientMetrics.cbSize = sizeof( aNonClientMetrics ); + if ( SystemParametersInfoA( SPI_GETNONCLIENTMETRICS, sizeof( aNonClientMetrics ), &aNonClientMetrics, 0 ) ) + { + ImplSalUpdateStyleFontA( hDC, aNonClientMetrics.lfMenuFont, aMenuFont ); + ImplSalUpdateStyleFontA( hDC, aNonClientMetrics.lfCaptionFont, aTitleFont ); + ImplSalUpdateStyleFontA( hDC, aNonClientMetrics.lfSmCaptionFont, aFloatTitleFont ); + ImplSalUpdateStyleFontA( hDC, aNonClientMetrics.lfStatusFont, aHelpFont ); + ImplSalUpdateStyleFontA( hDC, aNonClientMetrics.lfMessageFont, aAppFont ); + + LOGFONTA aLogFont; + if ( SystemParametersInfoA( SPI_GETICONTITLELOGFONT, 0, &aLogFont, 0 ) ) + ImplSalUpdateStyleFontA( hDC, aLogFont, aIconFont ); + } + } + + // get screen font resolution to calculate toolbox item size + long nDPIY = GetDeviceCaps( hDC, LOGPIXELSY ); + + ReleaseDC( 0, hDC ); + + long nHeightPx = aMenuFont.GetHeight() * nDPIY / 72; + aStyleSettings.SetToolbarIconSize( (((nHeightPx-1)*2) >= 28) ? STYLE_TOOLBAR_ICONSIZE_LARGE : STYLE_TOOLBAR_ICONSIZE_SMALL ); + + aStyleSettings.SetMenuFont( aMenuFont ); + aStyleSettings.SetTitleFont( aTitleFont ); + aStyleSettings.SetFloatTitleFont( aFloatTitleFont ); + aStyleSettings.SetHelpFont( aHelpFont ); + aStyleSettings.SetIconFont( aIconFont ); + // We prefer Arial in the russian version, because MS Sans Serif + // is to wide for the dialogs + if ( rSettings.GetLanguage() == LANGUAGE_RUSSIAN ) + { + XubString aFontName = aAppFont.GetName(); + XubString aFirstName = aFontName.GetToken( 0, ';' ); + if ( aFirstName.EqualsIgnoreCaseAscii( "MS Sans Serif" ) ) + { + aFontName.InsertAscii( "Arial;", 0 ); + aAppFont.SetName( aFontName ); + } + } + aStyleSettings.SetAppFont( aAppFont ); + aStyleSettings.SetGroupFont( aAppFont ); + aStyleSettings.SetLabelFont( aAppFont ); + aStyleSettings.SetRadioCheckFont( aAppFont ); + aStyleSettings.SetPushButtonFont( aAppFont ); + aStyleSettings.SetFieldFont( aAppFont ); + if ( aAppFont.GetWeight() > WEIGHT_NORMAL ) + aAppFont.SetWeight( WEIGHT_NORMAL ); + aStyleSettings.SetInfoFont( aAppFont ); + aStyleSettings.SetToolFont( aAppFont ); + + WIN_BOOL bDragFull; + if ( SystemParametersInfo( SPI_GETDRAGFULLWINDOWS, 0, &bDragFull, 0 ) ) + { + ULONG nDragFullOptions = aStyleSettings.GetDragFullOptions(); + if ( bDragFull ) + nDragFullOptions |= DRAGFULL_OPTION_WINDOWMOVE | DRAGFULL_OPTION_WINDOWSIZE | DRAGFULL_OPTION_DOCKING | DRAGFULL_OPTION_SPLIT; + else + nDragFullOptions &= ~(DRAGFULL_OPTION_WINDOWMOVE | DRAGFULL_OPTION_WINDOWSIZE | DRAGFULL_OPTION_DOCKING | DRAGFULL_OPTION_SPLIT); + aStyleSettings.SetDragFullOptions( nDragFullOptions ); + } + + aStyleSettings.SetIconHorzSpace( GetSystemMetrics( SM_CXICONSPACING ) ); + aStyleSettings.SetIconVertSpace( GetSystemMetrics( SM_CYICONSPACING ) ); + if ( RegOpenKey( HKEY_CURRENT_USER, + "Control Panel\\International\\Calendars\\TwoDigitYearMax", + &hRegKey ) == ERROR_SUCCESS ) + { + BYTE aValueBuf[10]; + DWORD nValue; + DWORD nValueSize = sizeof( aValueBuf ); + DWORD nType; + if ( RegQueryValueEx( hRegKey, "1", 0, + &nType, aValueBuf, &nValueSize ) == ERROR_SUCCESS ) + { + if ( nType == REG_SZ ) + { + nValue = (ULONG)ImplA2I( aValueBuf ); + if ( (nValue > 1000) && (nValue < 10000) ) + { + MiscSettings aMiscSettings = rSettings.GetMiscSettings(); + aMiscSettings.SetTwoDigitYearStart( (USHORT)(nValue-99) ); + rSettings.SetMiscSettings( aMiscSettings ); + } + } + } + + RegCloseKey( hRegKey ); + } + + rSettings.SetMouseSettings( aMouseSettings ); + rSettings.SetStyleSettings( aStyleSettings ); +} + +// ----------------------------------------------------------------------- + +SalBitmap* WinSalFrame::SnapShot() +{ + WinSalBitmap* pSalBitmap = NULL; + + RECT aRect; + GetWindowRect( mhWnd, &aRect ); + + int nDX = aRect.right-aRect.left; + int nDY = aRect.bottom-aRect.top; + HDC hDC = GetWindowDC( mhWnd ); + HBITMAP hBmpBitmap = CreateCompatibleBitmap( hDC, nDX, nDY ); + HDC hBmpDC = ImplGetCachedDC( CACHED_HDC_1, hBmpBitmap ); + BOOL bRet; + + bRet = BitBlt( hBmpDC, 0, 0, nDX, nDY, hDC, 0, 0, SRCCOPY ) ? TRUE : FALSE; + ImplReleaseCachedDC( CACHED_HDC_1 ); + + if ( bRet ) + { + pSalBitmap = new WinSalBitmap; + + if ( !pSalBitmap->Create( hBmpBitmap, FALSE, FALSE ) ) + { + delete pSalBitmap; + pSalBitmap = NULL; + } + } + + return pSalBitmap; +} + +// ----------------------------------------------------------------------- + +const SystemEnvData* WinSalFrame::GetSystemData() const +{ + return &maSysData; +} + +// ----------------------------------------------------------------------- + +void WinSalFrame::Beep( SoundType eSoundType ) +{ + static UINT aImplSoundTab[5] = + { + 0, // SOUND_DEFAULT + MB_ICONASTERISK, // SOUND_INFO + MB_ICONEXCLAMATION, // SOUND_WARNING + MB_ICONHAND, // SOUND_ERROR + MB_ICONQUESTION // SOUND_QUERY + }; + + MessageBeep( aImplSoundTab[eSoundType] ); +} + +// ----------------------------------------------------------------------- + +SalFrame::SalPointerState WinSalFrame::GetPointerState() +{ + SalPointerState aState; + aState.mnState = 0; + + if ( GetKeyState( VK_LBUTTON ) & 0x8000 ) + aState.mnState |= MOUSE_LEFT; + if ( GetKeyState( VK_MBUTTON ) & 0x8000 ) + aState.mnState |= MOUSE_MIDDLE; + if ( GetKeyState( VK_RBUTTON ) & 0x8000 ) + aState.mnState |= MOUSE_RIGHT; + if ( GetKeyState( VK_SHIFT ) & 0x8000 ) + aState.mnState |= KEY_SHIFT; + if ( GetKeyState( VK_CONTROL ) & 0x8000 ) + aState.mnState |= KEY_MOD1; + if ( GetKeyState( VK_MENU ) & 0x8000 ) + aState.mnState |= KEY_MOD2; + + POINT pt; + GetCursorPos( &pt ); + + aState.maPos = Point( pt.x - maGeometry.nX, pt.y - maGeometry.nY ); + return aState; +} + +// ----------------------------------------------------------------------- + +void WinSalFrame::SetBackgroundBitmap( SalBitmap* ) +{ +} + +// ----------------------------------------------------------------------- + +void WinSalFrame::ResetClipRegion() +{ + SetWindowRgn( mhWnd, 0, TRUE ); +} + +// ----------------------------------------------------------------------- + +void WinSalFrame::BeginSetClipRegion( ULONG nRects ) +{ + if( mpClipRgnData ) + delete [] (BYTE*)mpClipRgnData; + ULONG nRectBufSize = sizeof(RECT)*nRects; + mpClipRgnData = (RGNDATA*)new BYTE[sizeof(RGNDATA)-1+nRectBufSize]; + mpClipRgnData->rdh.dwSize = sizeof( RGNDATAHEADER ); + mpClipRgnData->rdh.iType = RDH_RECTANGLES; + mpClipRgnData->rdh.nCount = nRects; + mpClipRgnData->rdh.nRgnSize = nRectBufSize; + SetRectEmpty( &(mpClipRgnData->rdh.rcBound) ); + mpNextClipRect = (RECT*)(&(mpClipRgnData->Buffer)); + mbFirstClipRect = TRUE; +} + +// ----------------------------------------------------------------------- + +void WinSalFrame::UnionClipRegion( long nX, long nY, long nWidth, long nHeight ) +{ + if( ! mpClipRgnData ) + return; + + RECT* pRect = mpNextClipRect; + RECT* pBoundRect = &(mpClipRgnData->rdh.rcBound); + long nRight = nX + nWidth; + long nBottom = nY + nHeight; + + if ( mbFirstClipRect ) + { + pBoundRect->left = nX; + pBoundRect->top = nY; + pBoundRect->right = nRight; + pBoundRect->bottom = nBottom; + mbFirstClipRect = FALSE; + } + else + { + if ( nX < pBoundRect->left ) + pBoundRect->left = (int)nX; + + if ( nY < pBoundRect->top ) + pBoundRect->top = (int)nY; + + if ( nRight > pBoundRect->right ) + pBoundRect->right = (int)nRight; + + if ( nBottom > pBoundRect->bottom ) + pBoundRect->bottom = (int)nBottom; + } + + pRect->left = (int)nX; + pRect->top = (int)nY; + pRect->right = (int)nRight; + pRect->bottom = (int)nBottom; + if( (mpNextClipRect - (RECT*)(&mpClipRgnData->Buffer)) < (int)mpClipRgnData->rdh.nCount ) + mpNextClipRect++; +} + +// ----------------------------------------------------------------------- + +void WinSalFrame::EndSetClipRegion() +{ + if( ! mpClipRgnData ) + return; + + HRGN hRegion; + + // create region from accumulated rectangles + if ( mpClipRgnData->rdh.nCount == 1 ) + { + RECT* pRect = &(mpClipRgnData->rdh.rcBound); + hRegion = CreateRectRgn( pRect->left, pRect->top, + pRect->right, pRect->bottom ); + } + else + { + ULONG nSize = mpClipRgnData->rdh.nRgnSize+sizeof(RGNDATAHEADER); + hRegion = ExtCreateRegion( NULL, nSize, mpClipRgnData ); + } + delete [] (BYTE*)mpClipRgnData; + mpClipRgnData = NULL; + + DBG_ASSERT( hRegion, "WinSalFrame::EndSetClipRegion() - Can't create ClipRegion" ); + if( hRegion ) + { + RECT aWindowRect; + GetWindowRect( mhWnd, &aWindowRect ); + POINT aPt; + aPt.x=0; + aPt.y=0; + ClientToScreen( mhWnd, &aPt ); + OffsetRgn( hRegion, aPt.x - aWindowRect.left, aPt.y - aWindowRect.top ); + + if( SetWindowRgn( mhWnd, hRegion, TRUE ) == 0 ) + DeleteObject( hRegion ); + } +} + +// ----------------------------------------------------------------------- + +static long ImplHandleMouseMsg( HWND hWnd, UINT nMsg, + WPARAM wParam, LPARAM lParam ) +{ + WinSalFrame* pFrame = GetWindowPtr( hWnd ); + if ( !pFrame ) + return 0; + + if( nMsg == WM_LBUTTONDOWN || nMsg == WM_MBUTTONDOWN || nMsg == WM_RBUTTONDOWN ) + { + // #103168# post again if async focus has not arrived yet + // hopefully we will not receive the corresponding button up before this + // button down arrives again + Window *pWin = pFrame->GetWindow(); + if( pWin && pWin->ImplGetWindowImpl()->mpFrameData->mnFocusId ) + { + ImplPostMessage( hWnd, nMsg, wParam, lParam ); + return 1; + } + } + SalMouseEvent aMouseEvt; + long nRet; + USHORT nEvent = 0; + BOOL bCall = TRUE; + + aMouseEvt.mnX = (short)LOWORD( lParam ); + aMouseEvt.mnY = (short)HIWORD( lParam ); + aMouseEvt.mnCode = 0; + aMouseEvt.mnTime = GetMessageTime(); + + // Wegen (Logitech-)MouseTreiber ueber GetKeyState() gehen, die auf + // mittlerer Maustaste Doppelklick simulieren und den KeyStatus nicht + // beruecksichtigen + + if ( GetKeyState( VK_LBUTTON ) & 0x8000 ) + aMouseEvt.mnCode |= MOUSE_LEFT; + if ( GetKeyState( VK_MBUTTON ) & 0x8000 ) + aMouseEvt.mnCode |= MOUSE_MIDDLE; + if ( GetKeyState( VK_RBUTTON ) & 0x8000 ) + aMouseEvt.mnCode |= MOUSE_RIGHT; + if ( GetKeyState( VK_SHIFT ) & 0x8000 ) + aMouseEvt.mnCode |= KEY_SHIFT; + if ( GetKeyState( VK_CONTROL ) & 0x8000 ) + aMouseEvt.mnCode |= KEY_MOD1; + if ( GetKeyState( VK_MENU ) & 0x8000 ) + aMouseEvt.mnCode |= KEY_MOD2; + + switch ( nMsg ) + { + case WM_MOUSEMOVE: + { + // Da bei Druecken von Modifier-Tasten die MouseEvents + // nicht zusammengefast werden (da diese durch KeyEvents + // unterbrochen werden), machen wir dieses hier selber + if ( aMouseEvt.mnCode & (KEY_SHIFT | KEY_MOD1 | KEY_MOD2) ) + { + MSG aTempMsg; + if ( ImplPeekMessage( &aTempMsg, hWnd, WM_MOUSEFIRST, WM_MOUSELAST, PM_NOREMOVE | PM_NOYIELD ) ) + { + if ( (aTempMsg.message == WM_MOUSEMOVE) && + (aTempMsg.wParam == wParam) ) + return 1; + } + } + + SalData* pSalData = GetSalData(); + // Test for MouseLeave + if ( pSalData->mhWantLeaveMsg && (pSalData->mhWantLeaveMsg != hWnd) ) + ImplSendMessage( pSalData->mhWantLeaveMsg, SAL_MSG_MOUSELEAVE, 0, GetMessagePos() ); + + pSalData->mhWantLeaveMsg = hWnd; + // Start MouseLeave-Timer + if ( !pSalData->mpMouseLeaveTimer ) + { + pSalData->mpMouseLeaveTimer = new AutoTimer; + pSalData->mpMouseLeaveTimer->SetTimeout( SAL_MOUSELEAVE_TIMEOUT ); + pSalData->mpMouseLeaveTimer->Start(); + // We dont need to set a timeout handler, because we test + // for mouseleave in the timeout callback + } + aMouseEvt.mnButton = 0; + nEvent = SALEVENT_MOUSEMOVE; + } + break; + + case WM_NCMOUSEMOVE: + case SAL_MSG_MOUSELEAVE: + { + SalData* pSalData = GetSalData(); + if ( pSalData->mhWantLeaveMsg == hWnd ) + { + pSalData->mhWantLeaveMsg = 0; + if ( pSalData->mpMouseLeaveTimer ) + { + delete pSalData->mpMouseLeaveTimer; + pSalData->mpMouseLeaveTimer = NULL; + } + // Mouse-Coordinaates are relativ to the screen + POINT aPt; + aPt.x = (short)LOWORD( lParam ); + aPt.y = (short)HIWORD( lParam ); + ScreenToClient( hWnd, &aPt ); + aMouseEvt.mnX = aPt.x; + aMouseEvt.mnY = aPt.y; + aMouseEvt.mnButton = 0; + nEvent = SALEVENT_MOUSELEAVE; + } + else + bCall = FALSE; + } + break; + + case WM_LBUTTONDOWN: + aMouseEvt.mnButton = MOUSE_LEFT; + nEvent = SALEVENT_MOUSEBUTTONDOWN; + break; + + case WM_MBUTTONDOWN: + aMouseEvt.mnButton = MOUSE_MIDDLE; + nEvent = SALEVENT_MOUSEBUTTONDOWN; + break; + + case WM_RBUTTONDOWN: + aMouseEvt.mnButton = MOUSE_RIGHT; + nEvent = SALEVENT_MOUSEBUTTONDOWN; + break; + + case WM_LBUTTONUP: + aMouseEvt.mnButton = MOUSE_LEFT; + nEvent = SALEVENT_MOUSEBUTTONUP; + break; + + case WM_MBUTTONUP: + aMouseEvt.mnButton = MOUSE_MIDDLE; + nEvent = SALEVENT_MOUSEBUTTONUP; + break; + + case WM_RBUTTONUP: + aMouseEvt.mnButton = MOUSE_RIGHT; + nEvent = SALEVENT_MOUSEBUTTONUP; + break; + } + + // check if this window was destroyed - this might happen if we are the help window + // and sent a mouse leave message to the application which killed the help window, ie ourself + if( !IsWindow( hWnd ) ) + return 0; + + if ( bCall ) + { + if ( nEvent == SALEVENT_MOUSEBUTTONDOWN ) + UpdateWindow( hWnd ); + + // --- RTL --- (mirror mouse pos) + if( Application::GetSettings().GetLayoutRTL() ) + aMouseEvt.mnX = pFrame->maGeometry.nWidth-1-aMouseEvt.mnX; + + nRet = pFrame->CallCallback( nEvent, &aMouseEvt ); + if ( nMsg == WM_MOUSEMOVE ) + SetCursor( pFrame->mhCursor ); + } + else + nRet = 0; + + return nRet; +} + +// ----------------------------------------------------------------------- + +static long ImplHandleMouseActivateMsg( HWND hWnd ) +{ + WinSalFrame* pFrame = GetWindowPtr( hWnd ); + if ( !pFrame ) + return 0; + + if ( pFrame->mbFloatWin ) + return TRUE; + + SalMouseActivateEvent aMouseActivateEvt; + POINT aPt; + GetCursorPos( &aPt ); + ScreenToClient( hWnd, &aPt ); + aMouseActivateEvt.mnX = aPt.x; + aMouseActivateEvt.mnY = aPt.y; + return pFrame->CallCallback( SALEVENT_MOUSEACTIVATE, &aMouseActivateEvt ); +} + +// ----------------------------------------------------------------------- + +static long ImplHandleWheelMsg( HWND hWnd, UINT nMsg, WPARAM wParam, LPARAM lParam ) +{ + DBG_ASSERT( nMsg == WM_MOUSEWHEEL || + nMsg == WM_MOUSEHWHEEL, + "ImplHandleWheelMsg() called with no wheel mouse event" ); + + ImplSalYieldMutexAcquireWithWait(); + + long nRet = 0; + WinSalFrame* pFrame = GetWindowPtr( hWnd ); + if ( pFrame ) + { + WORD nWinModCode = LOWORD( wParam ); + POINT aWinPt; + aWinPt.x = (short)LOWORD( lParam ); + aWinPt.y = (short)HIWORD( lParam ); + ScreenToClient( hWnd, &aWinPt ); + + SalWheelMouseEvent aWheelEvt; + aWheelEvt.mnTime = GetMessageTime(); + aWheelEvt.mnX = aWinPt.x; + aWheelEvt.mnY = aWinPt.y; + aWheelEvt.mnCode = 0; + aWheelEvt.mnDelta = (short)HIWORD( wParam ); + aWheelEvt.mnNotchDelta = aWheelEvt.mnDelta/WHEEL_DELTA; + if( aWheelEvt.mnNotchDelta == 0 ) + { + if( aWheelEvt.mnDelta > 0 ) + aWheelEvt.mnNotchDelta = 1; + else if( aWheelEvt.mnDelta < 0 ) + aWheelEvt.mnNotchDelta = -1; + } + + if( nMsg == WM_MOUSEWHEEL ) + { + if ( aSalShlData.mnWheelScrollLines == WHEEL_PAGESCROLL ) + aWheelEvt.mnScrollLines = SAL_WHEELMOUSE_EVENT_PAGESCROLL; + else + aWheelEvt.mnScrollLines = aSalShlData.mnWheelScrollLines; + aWheelEvt.mbHorz = FALSE; + } + else + { + aWheelEvt.mnScrollLines = aSalShlData.mnWheelScrollChars; + aWheelEvt.mbHorz = TRUE; + } + + if ( nWinModCode & MK_SHIFT ) + aWheelEvt.mnCode |= KEY_SHIFT; + if ( nWinModCode & MK_CONTROL ) + aWheelEvt.mnCode |= KEY_MOD1; + if ( GetKeyState( VK_MENU ) & 0x8000 ) + aWheelEvt.mnCode |= KEY_MOD2; + + // --- RTL --- (mirror mouse pos) + if( Application::GetSettings().GetLayoutRTL() ) + aWheelEvt.mnX = pFrame->maGeometry.nWidth-1-aWheelEvt.mnX; + + nRet = pFrame->CallCallback( SALEVENT_WHEELMOUSE, &aWheelEvt ); + } + + ImplSalYieldMutexRelease(); + + return nRet; +} + +// ----------------------------------------------------------------------- + +static USHORT ImplSalGetKeyCode( WPARAM wParam ) +{ + USHORT nKeyCode; + + // convert KeyCode + if ( wParam < KEY_TAB_SIZE ) + nKeyCode = aImplTranslateKeyTab[wParam]; + else + { + SalData* pSalData = GetSalData(); + std::map< UINT, USHORT >::const_iterator it = pSalData->maVKMap.find( (UINT)wParam ); + if( it != pSalData->maVKMap.end() ) + nKeyCode = it->second; + else + nKeyCode = 0; + } + + return nKeyCode; +} + +// ----------------------------------------------------------------------- + +static UINT ImplStrToNum( const sal_Char* pStr ) +{ + USHORT n = 0; + + // Solange es sich um eine Ziffer handelt, String umwandeln + while( (*pStr >= 48) && (*pStr <= 57) ) + { + n *= 10; + n += ((*pStr) - 48); + pStr++; + } + + return n; +} + +// ----------------------------------------------------------------------- + +static void ImplUpdateInputLang( WinSalFrame* pFrame ) +{ + BOOL bLanguageChange = FALSE; + UINT nLang = LOWORD( GetKeyboardLayout( 0 ) ); + if ( nLang && nLang != pFrame->mnInputLang ) + { + // keep input lang up-to-date + pFrame->mnInputLang = nLang; + bLanguageChange = TRUE; + } + + // If we are on Windows NT we use Unicode FrameProcs and so we + // get Unicode charcodes directly from Windows + // no need to set up a code page + if ( aSalShlData.mbWNT ) + return; + + if ( !nLang ) + { + pFrame->mnInputLang = 0; + pFrame->mnInputCodePage = GetACP(); + } + else if ( bLanguageChange ) + { + sal_Char aBuf[10]; + if ( GetLocaleInfoA( MAKELCID( nLang, SORT_DEFAULT ), LOCALE_IDEFAULTANSICODEPAGE, + aBuf, sizeof(aBuf) ) > 0 ) + { + pFrame->mnInputCodePage = ImplStrToNum( aBuf ); + if ( !pFrame->mnInputCodePage ) + pFrame->mnInputCodePage = GetACP(); + } + else + pFrame->mnInputCodePage = GetACP(); + } +} + + +static sal_Unicode ImplGetCharCode( WinSalFrame* pFrame, WPARAM nCharCode ) +{ + ImplUpdateInputLang( pFrame ); + + // If we are on Windows NT we use Unicode FrameProcs and so we + // get Unicode charcodes directly from Windows + if ( aSalShlData.mbWNT ) + return (sal_Unicode)nCharCode; + + sal_Char aCharBuf[2]; + int nCharLen; + WCHAR c; + if ( nCharCode > 0xFF ) + { + aCharBuf[0] = (sal_Char)(nCharCode>>8); + aCharBuf[1] = (sal_Char)nCharCode; + nCharLen = 2; + } + else + { + aCharBuf[0] = (sal_Char)nCharCode; + nCharLen = 1; + } + if ( ::MultiByteToWideChar( pFrame->mnInputCodePage, + MB_PRECOMPOSED, + aCharBuf, nCharLen, &c, 1 ) ) + return (sal_Unicode)c; + else + return (sal_Unicode)nCharCode; +} + +// ----------------------------------------------------------------------- + +LanguageType WinSalFrame::GetInputLanguage() +{ + if( !mnInputLang ) + ImplUpdateInputLang( this ); + + if( !mnInputLang ) + return LANGUAGE_DONTKNOW; + else + return (LanguageType) mnInputLang; +} + +// ----------------------------------------------------------------------- + +BOOL WinSalFrame::MapUnicodeToKeyCode( sal_Unicode aUnicode, LanguageType aLangType, KeyCode& rKeyCode ) +{ + BOOL bRet = FALSE; + HKL hkl = 0; + + // just use the passed language identifier, do not try to load additional keyboard support + hkl = (HKL) aLangType; + + if( hkl ) + { + SHORT scan = VkKeyScanExW( aUnicode, hkl ); + if( LOWORD(scan) == 0xFFFF ) + // keyboard not loaded or key cannot be mapped + bRet = FALSE; + else + { + BYTE vkeycode = LOBYTE(scan); + BYTE shiftstate = HIBYTE(scan); + + // Last argument is set to FALSE, because there's no decission made + // yet which key should be assigned to MOD3 modifier on Windows. + // Windows key - user's can be confused, because it should display + // Windows menu (applies to both left/right key) + // Menu key - this key is used to display context menu + // AltGr key - probably it has no sense + rKeyCode = KeyCode( ImplSalGetKeyCode( vkeycode ), + (shiftstate & 0x01) ? TRUE : FALSE, // shift + (shiftstate & 0x02) ? TRUE : FALSE, // ctrl + (shiftstate & 0x04) ? TRUE : FALSE, // alt + FALSE ); + bRet = TRUE; + } + } + + return bRet; +} + +// ----------------------------------------------------------------------- + +static long ImplHandleKeyMsg( HWND hWnd, UINT nMsg, + WPARAM wParam, LPARAM lParam, LRESULT& rResult ) +{ + static BOOL bIgnoreCharMsg = FALSE; + static WPARAM nDeadChar = 0; + static WPARAM nLastVKChar = 0; + static USHORT nLastChar = 0; + static USHORT nLastModKeyCode = 0; + static bool bWaitForModKeyRelease = false; + USHORT nRepeat = LOWORD( lParam )-1; + USHORT nModCode = 0; + + // Key wurde evtl. durch SysChild an uns weitergeleitet und + // darf somit dann nicht doppelt verarbeitet werden + GetSalData()->mnSalObjWantKeyEvt = 0; + + if ( nMsg == WM_DEADCHAR ) + { + nDeadChar = wParam; + return 0; + } + + WinSalFrame* pFrame = GetWindowPtr( hWnd ); + if ( !pFrame ) + return 0; + + // Wir restaurieren den Background-Modus bei jeder Texteingabe, + // da einige Tools wie RichWin uns diesen hin- und wieder umsetzen + if ( pFrame->mpGraphics && + pFrame->mpGraphics->mhDC ) + SetBkMode( pFrame->mpGraphics->mhDC, TRANSPARENT ); + + // determine modifiers + if ( GetKeyState( VK_SHIFT ) & 0x8000 ) + nModCode |= KEY_SHIFT; + if ( GetKeyState( VK_CONTROL ) & 0x8000 ) + nModCode |= KEY_MOD1; + if ( GetKeyState( VK_MENU ) & 0x8000 ) + nModCode |= KEY_MOD2; + + if ( (nMsg == WM_CHAR) || (nMsg == WM_SYSCHAR) ) + { + nDeadChar = 0; + + if ( bIgnoreCharMsg ) + { + bIgnoreCharMsg = FALSE; + // #101635# if zero is returned here for WM_SYSCHAR (ALT+<key>) Windows will beep + // becaus this 'hotkey' was not processed -> better return 1 + // except for Alt-SPACE which should always open the sysmenu (#104616#) + + // also return zero if a system menubar is available that might process this hotkey + // this also applies to the OLE inplace embedding where we are a child window + if( (GetWindowStyle( hWnd ) & WS_CHILD) || GetMenu( hWnd ) || (wParam == 0x20) ) + return 0; + else + return 1; + } + + // Backspace ignorieren wir als eigenstaendige Taste, + // damit wir keine Probleme in Kombination mit einem + // DeadKey bekommen + if ( wParam == 0x08 ) // BACKSPACE + return 0; + + // Hier kommen nur "freifliegende" WM_CHAR Message an, die durch + // eintippen einer ALT-NUMPAD Kombination erzeugt wurden + SalKeyEvent aKeyEvt; + + if ( (wParam >= '0') && (wParam <= '9') ) + aKeyEvt.mnCode = sal::static_int_cast<USHORT>(KEYGROUP_NUM + wParam - '0'); + else if ( (wParam >= 'A') && (wParam <= 'Z') ) + aKeyEvt.mnCode = sal::static_int_cast<USHORT>(KEYGROUP_ALPHA + wParam - 'A'); + else if ( (wParam >= 'a') && (wParam <= 'z') ) + aKeyEvt.mnCode = sal::static_int_cast<USHORT>(KEYGROUP_ALPHA + wParam - 'a'); + else if ( wParam == 0x0D ) // RETURN + aKeyEvt.mnCode = KEY_RETURN; + else if ( wParam == 0x1B ) // ESCAPE + aKeyEvt.mnCode = KEY_ESCAPE; + else if ( wParam == 0x09 ) // TAB + aKeyEvt.mnCode = KEY_TAB; + else if ( wParam == 0x20 ) // SPACE + aKeyEvt.mnCode = KEY_SPACE; + else + aKeyEvt.mnCode = 0; + + aKeyEvt.mnTime = GetMessageTime(); + aKeyEvt.mnCode |= nModCode; + aKeyEvt.mnCharCode = ImplGetCharCode( pFrame, wParam ); + aKeyEvt.mnRepeat = nRepeat; + nLastChar = 0; + nLastVKChar = 0; + long nRet = pFrame->CallCallback( SALEVENT_KEYINPUT, &aKeyEvt ); + pFrame->CallCallback( SALEVENT_KEYUP, &aKeyEvt ); + return nRet; + } + // #i11583#, MCD, 2003-01-13, Support for WM_UNICHAR & Keyman 6.0; addition begins + else if( nMsg == WM_UNICHAR ) + { + // If Windows is asking if we accept WM_UNICHAR, return TRUE + if(wParam == UNICODE_NOCHAR) + { + rResult = TRUE; // ssa: this will actually return TRUE to windows + return 1; // ...but this will only avoid calling the defwindowproc + } + + SalKeyEvent aKeyEvt; + aKeyEvt.mnCode = nModCode; // Or should it be 0? - as this is always a character returned + aKeyEvt.mnTime = GetMessageTime(); + aKeyEvt.mnRepeat = 0; + + if( wParam >= Uni_SupplementaryPlanesStart ) + { + // character is supplementary char in UTF-32 format - must be converted to UTF-16 supplementary pair + // sal_Unicode ch = (sal_Unicode) Uni_UTF32ToSurrogate1(wParam); + nLastChar = 0; + nLastVKChar = 0; + pFrame->CallCallback( SALEVENT_KEYINPUT, &aKeyEvt ); + pFrame->CallCallback( SALEVENT_KEYUP, &aKeyEvt ); + wParam = (sal_Unicode) Uni_UTF32ToSurrogate2( wParam ); + } + + aKeyEvt.mnCharCode = (sal_Unicode) wParam; + + nLastChar = 0; + nLastVKChar = 0; + long nRet = pFrame->CallCallback( SALEVENT_KEYINPUT, &aKeyEvt ); + pFrame->CallCallback( SALEVENT_KEYUP, &aKeyEvt ); + + return nRet; + } + // MCD, 2003-01-13, Support for WM_UNICHAR & Keyman 6.0; addition ends + else + { + // Bei Shift, Control und Menu schicken wir einen KeyModChange-Event + if ( (wParam == VK_SHIFT) || (wParam == VK_CONTROL) || (wParam == VK_MENU) ) + { + SalKeyModEvent aModEvt; + aModEvt.mnTime = GetMessageTime(); + aModEvt.mnCode = nModCode; + aModEvt.mnModKeyCode = 0; // no command events will be sent if this member is 0 + + USHORT tmpCode = 0; + if( GetKeyState( VK_LSHIFT ) & 0x8000 ) + tmpCode |= MODKEY_LSHIFT; + if( GetKeyState( VK_RSHIFT ) & 0x8000 ) + tmpCode |= MODKEY_RSHIFT; + if( GetKeyState( VK_LCONTROL ) & 0x8000 ) + tmpCode |= MODKEY_LMOD1; + if( GetKeyState( VK_RCONTROL ) & 0x8000 ) + tmpCode |= MODKEY_RMOD1; + if( GetKeyState( VK_LMENU ) & 0x8000 ) + tmpCode |= MODKEY_LMOD2; + if( GetKeyState( VK_RMENU ) & 0x8000 ) + tmpCode |= MODKEY_RMOD2; + + if( tmpCode < nLastModKeyCode ) + { + aModEvt.mnModKeyCode = nLastModKeyCode; + nLastModKeyCode = 0; + bWaitForModKeyRelease = true; + } + else + { + if( !bWaitForModKeyRelease ) + nLastModKeyCode = tmpCode; + } + + if( !tmpCode ) + bWaitForModKeyRelease = false; + + return pFrame->CallCallback( SALEVENT_KEYMODCHANGE, &aModEvt ); + } + else + { + SalKeyEvent aKeyEvt; + USHORT nEvent; + MSG aCharMsg; + WIN_BOOL bCharPeek = FALSE; + UINT nCharMsg = WM_CHAR; + BOOL bKeyUp = (nMsg == WM_KEYUP) || (nMsg == WM_SYSKEYUP); + + nLastModKeyCode = 0; // make sure no modkey messages are sent if they belong to a hotkey (see above) + aKeyEvt.mnCharCode = 0; + aKeyEvt.mnCode = 0; + + aKeyEvt.mnCode = ImplSalGetKeyCode( wParam ); + if ( !bKeyUp ) + { + // check for charcode + // Mit Hilfe von PeekMessage holen wir uns jetzt die + // zugehoerige WM_CHAR Message, wenn vorhanden. + // Diese WM_CHAR Message steht immer am Anfang der + // Messagequeue. Ausserdem ist sichergestellt, dass immer + // nur eine WM_CHAR Message in der Queue steht. + bCharPeek = ImplPeekMessage( &aCharMsg, hWnd, + WM_CHAR, WM_CHAR, PM_NOREMOVE | PM_NOYIELD ); + if ( bCharPeek && (nDeadChar == aCharMsg.wParam) ) + { + bCharPeek = FALSE; + nDeadChar = 0; + + if ( wParam == VK_BACK ) + { + ImplPeekMessage( &aCharMsg, hWnd, + nCharMsg, nCharMsg, PM_REMOVE | PM_NOYIELD ); + return 0; + } + } + else + { + if ( !bCharPeek ) + { + bCharPeek = ImplPeekMessage( &aCharMsg, hWnd, + WM_SYSCHAR, WM_SYSCHAR, PM_NOREMOVE | PM_NOYIELD ); + nCharMsg = WM_SYSCHAR; + } + } + if ( bCharPeek ) + aKeyEvt.mnCharCode = ImplGetCharCode( pFrame, aCharMsg.wParam ); + else + aKeyEvt.mnCharCode = 0; + + nLastChar = aKeyEvt.mnCharCode; + nLastVKChar = wParam; + } + else + { + if ( wParam == nLastVKChar ) + { + aKeyEvt.mnCharCode = nLastChar; + nLastChar = 0; + nLastVKChar = 0; + } + } + + if ( aKeyEvt.mnCode || aKeyEvt.mnCharCode ) + { + if ( bKeyUp ) + nEvent = SALEVENT_KEYUP; + else + nEvent = SALEVENT_KEYINPUT; + + aKeyEvt.mnTime = GetMessageTime(); + aKeyEvt.mnCode |= nModCode; + aKeyEvt.mnRepeat = nRepeat; + + if( (nModCode & (KEY_MOD1|KEY_MOD2)) == (KEY_MOD1|KEY_MOD2) && + aKeyEvt.mnCharCode ) + { + // this is actually AltGr and should not be handled as Alt + aKeyEvt.mnCode &= ~(KEY_MOD1|KEY_MOD2); + } + + bIgnoreCharMsg = bCharPeek ? TRUE : FALSE; + long nRet = pFrame->CallCallback( nEvent, &aKeyEvt ); + // independent part only reacts on keyup but Windows does not send + // keyup for VK_HANJA + if( aKeyEvt.mnCode == KEY_HANGUL_HANJA ) + nRet = pFrame->CallCallback( SALEVENT_KEYUP, &aKeyEvt ); + + bIgnoreCharMsg = FALSE; + + // char-message, than remove or ignore + if ( bCharPeek ) + { + nDeadChar = 0; + if ( nRet ) + { + ImplPeekMessage( &aCharMsg, hWnd, + nCharMsg, nCharMsg, PM_REMOVE | PM_NOYIELD ); + } + else + bIgnoreCharMsg = TRUE; + } + + return nRet; + } + else + return 0; + } + } +} + +// ----------------------------------------------------------------------- + +long ImplHandleSalObjKeyMsg( HWND hWnd, UINT nMsg, + WPARAM wParam, LPARAM lParam ) +{ + if ( (nMsg == WM_KEYDOWN) || (nMsg == WM_KEYUP) ) + { + WinSalFrame* pFrame = GetWindowPtr( hWnd ); + if ( !pFrame ) + return 0; + + USHORT nRepeat = LOWORD( lParam )-1; + USHORT nModCode = 0; + + // determine modifiers + if ( GetKeyState( VK_SHIFT ) & 0x8000 ) + nModCode |= KEY_SHIFT; + if ( GetKeyState( VK_CONTROL ) & 0x8000 ) + nModCode |= KEY_MOD1; + if ( GetKeyState( VK_MENU ) & 0x8000 ) + nModCode |= KEY_MOD2; + + if ( (wParam != VK_SHIFT) && (wParam != VK_CONTROL) && (wParam != VK_MENU) ) + { + SalKeyEvent aKeyEvt; + USHORT nEvent; + BOOL bKeyUp = (nMsg == WM_KEYUP) || (nMsg == WM_SYSKEYUP); + + // convert KeyCode + aKeyEvt.mnCode = ImplSalGetKeyCode( wParam ); + aKeyEvt.mnCharCode = 0; + + if ( aKeyEvt.mnCode ) + { + if ( bKeyUp ) + nEvent = SALEVENT_KEYUP; + else + nEvent = SALEVENT_KEYINPUT; + + aKeyEvt.mnTime = GetMessageTime(); + aKeyEvt.mnCode |= nModCode; + aKeyEvt.mnRepeat = nRepeat; + long nRet = pFrame->CallCallback( nEvent, &aKeyEvt ); + return nRet; + } + else + return 0; + } + } + + return 0; +} + +// ----------------------------------------------------------------------- + +long ImplHandleSalObjSysCharMsg( HWND hWnd, WPARAM wParam, LPARAM lParam ) +{ + WinSalFrame* pFrame = GetWindowPtr( hWnd ); + if ( !pFrame ) + return 0; + + USHORT nRepeat = LOWORD( lParam )-1; + USHORT nModCode = 0; + USHORT cKeyCode = (USHORT)wParam; + + // determine modifiers + if ( GetKeyState( VK_SHIFT ) & 0x8000 ) + nModCode |= KEY_SHIFT; + if ( GetKeyState( VK_CONTROL ) & 0x8000 ) + nModCode |= KEY_MOD1; + nModCode |= KEY_MOD2; + + // KeyEvent zusammenbauen + SalKeyEvent aKeyEvt; + aKeyEvt.mnTime = GetMessageTime(); + if ( (cKeyCode >= 48) && (cKeyCode <= 57) ) + aKeyEvt.mnCode = KEY_0+(cKeyCode-48); + else if ( (cKeyCode >= 65) && (cKeyCode <= 90) ) + aKeyEvt.mnCode = KEY_A+(cKeyCode-65); + else if ( (cKeyCode >= 97) && (cKeyCode <= 122) ) + aKeyEvt.mnCode = KEY_A+(cKeyCode-97); + else + aKeyEvt.mnCode = 0; + aKeyEvt.mnCode |= nModCode; + aKeyEvt.mnCharCode = ImplGetCharCode( pFrame, cKeyCode ); + aKeyEvt.mnRepeat = nRepeat; + long nRet = pFrame->CallCallback( SALEVENT_KEYINPUT, &aKeyEvt ); + pFrame->CallCallback( SALEVENT_KEYUP, &aKeyEvt ); + return nRet; +} + +// ----------------------------------------------------------------------- + +static bool ImplHandlePaintMsg( HWND hWnd ) +{ + BOOL bMutex = FALSE; + if ( ImplSalYieldMutexTryToAcquire() ) + bMutex = TRUE; + + // if we don't get the mutex, we can also change the clip region, + // because other threads doesn't use the mutex from the main + // thread --> see GetGraphics() + + WinSalFrame* pFrame = GetWindowPtr( hWnd ); + if ( pFrame ) + { + // Clip-Region muss zurueckgesetzt werden, da wir sonst kein + // ordentliches Bounding-Rectangle bekommen + if ( pFrame->mpGraphics && pFrame->mpGraphics->mhRegion ) + SelectClipRgn( pFrame->mpGraphics->mhDC, 0 ); + + // Laut Window-Doku soll man erst abfragen, ob ueberhaupt eine + // Paint-Region anliegt + if ( GetUpdateRect( hWnd, NULL, FALSE ) ) + { + // Call BeginPaint/EndPaint to query the rect and send + // this Notofication to rect + RECT aUpdateRect; + PAINTSTRUCT aPs; + BeginPaint( hWnd, &aPs ); + CopyRect( &aUpdateRect, &aPs.rcPaint ); + + // Paint + // ClipRegion wieder herstellen + if ( pFrame->mpGraphics && pFrame->mpGraphics->mhRegion ) + { + SelectClipRgn( pFrame->mpGraphics->mhDC, + pFrame->mpGraphics->mhRegion ); + } + + if ( bMutex ) + { + SalPaintEvent aPEvt( aUpdateRect.left, aUpdateRect.top, aUpdateRect.right-aUpdateRect.left, aUpdateRect.bottom-aUpdateRect.top, pFrame->mbPresentation ); + pFrame->CallCallback( SALEVENT_PAINT, &aPEvt ); + } + else + { + RECT* pRect = new RECT; + CopyRect( pRect, &aUpdateRect ); + ImplPostMessage( hWnd, SAL_MSG_POSTPAINT, (WPARAM)pRect, 0 ); + } + EndPaint( hWnd, &aPs ); + } + else + { + // ClipRegion wieder herstellen + if ( pFrame->mpGraphics && pFrame->mpGraphics->mhRegion ) + { + SelectClipRgn( pFrame->mpGraphics->mhDC, + pFrame->mpGraphics->mhRegion ); + } + } + } + + if ( bMutex ) + ImplSalYieldMutexRelease(); + + return bMutex ? true : false; +} + +// ----------------------------------------------------------------------- + +static void ImplHandlePaintMsg2( HWND hWnd, RECT* pRect ) +{ + // Paint + if ( ImplSalYieldMutexTryToAcquire() ) + { + WinSalFrame* pFrame = GetWindowPtr( hWnd ); + if ( pFrame ) + { + SalPaintEvent aPEvt( pRect->left, pRect->top, pRect->right-pRect->left, pRect->bottom-pRect->top ); + pFrame->CallCallback( SALEVENT_PAINT, &aPEvt ); + } + ImplSalYieldMutexRelease(); + delete pRect; + } + else + ImplPostMessage( hWnd, SAL_MSG_POSTPAINT, (WPARAM)pRect, 0 ); +} + +// ----------------------------------------------------------------------- + +static void SetMaximizedFrameGeometry( HWND hWnd, WinSalFrame* pFrame ) +{ + // calculate and set frame geometry of a maximized window - useful if the window is still hidden + + // dualmonitor support: + // Get screensize of the monitor whith the mouse pointer + + POINT pt; + GetCursorPos( &pt ); + RECT aRectMouse; + aRectMouse.left = pt.x; + aRectMouse.top = pt.y; + aRectMouse.right = pt.x+2; + aRectMouse.bottom = pt.y+2; + + RECT aRect; + ImplSalGetWorkArea( hWnd, &aRect, &aRectMouse ); + + // a maximized window has no other borders than the caption + pFrame->maGeometry.nLeftDecoration = pFrame->maGeometry.nRightDecoration = pFrame->maGeometry.nBottomDecoration = 0; + pFrame->maGeometry.nTopDecoration = pFrame->mbCaption ? GetSystemMetrics( SM_CYCAPTION ) : 0; + + aRect.top += pFrame->maGeometry.nTopDecoration; + pFrame->maGeometry.nX = aRect.left; + pFrame->maGeometry.nY = aRect.top; + pFrame->maGeometry.nWidth = aRect.right - aRect.left; + pFrame->maGeometry.nHeight = aRect.bottom - aRect.top; +} + +static void UpdateFrameGeometry( HWND hWnd, WinSalFrame* pFrame ) +{ + if( !pFrame ) + return; + + RECT aRect; + GetWindowRect( hWnd, &aRect ); + memset(&pFrame->maGeometry, 0, sizeof(SalFrameGeometry) ); + + if ( IsIconic( hWnd ) ) + return; + + POINT aPt; + aPt.x=0; + aPt.y=0; + ClientToScreen(hWnd, &aPt); + int cx = aPt.x - aRect.left; + pFrame->maGeometry.nTopDecoration = aPt.y - aRect.top; + + pFrame->maGeometry.nLeftDecoration = cx; + pFrame->maGeometry.nRightDecoration = cx; + + pFrame->maGeometry.nX = aPt.x; + pFrame->maGeometry.nY = aPt.y; + + RECT aInnerRect; + GetClientRect( hWnd, &aInnerRect ); + if( aInnerRect.right ) + { + // improve right decoration + aPt.x=aInnerRect.right; + aPt.y=aInnerRect.top; + ClientToScreen(hWnd, &aPt); + pFrame->maGeometry.nRightDecoration = aRect.right - aPt.x; + } + if( aInnerRect.bottom ) // may be zero if window was not shown yet + pFrame->maGeometry.nBottomDecoration += aRect.bottom - aPt.y - aInnerRect.bottom; + else + // bottom border is typically the same as left/right + pFrame->maGeometry.nBottomDecoration = pFrame->maGeometry.nLeftDecoration; + + int nWidth = aRect.right - aRect.left + - pFrame->maGeometry.nRightDecoration - pFrame->maGeometry.nLeftDecoration; + int nHeight = aRect.bottom - aRect.top + - pFrame->maGeometry.nBottomDecoration - pFrame->maGeometry.nTopDecoration; + // clamp to zero + pFrame->maGeometry.nHeight = nHeight < 0 ? 0 : nHeight; + pFrame->maGeometry.nWidth = nWidth < 0 ? 0 : nWidth; + pFrame->updateScreenNumber(); +} + +// ----------------------------------------------------------------------- + +static void ImplCallMoveHdl( HWND hWnd ) +{ + WinSalFrame* pFrame = GetWindowPtr( hWnd ); + if ( pFrame ) + { + pFrame->CallCallback( SALEVENT_MOVE, 0 ); + // Um doppelte Paints von VCL und SAL zu vermeiden + //if ( IsWindowVisible( hWnd ) && !pFrame->mbInShow ) + // UpdateWindow( hWnd ); + } +} + +// ----------------------------------------------------------------------- + +static void ImplCallClosePopupsHdl( HWND hWnd ) +{ + WinSalFrame* pFrame = GetWindowPtr( hWnd ); + if ( pFrame ) + { + pFrame->CallCallback( SALEVENT_CLOSEPOPUPS, 0 ); + } +} + +// ----------------------------------------------------------------------- + +static void ImplHandleMoveMsg( HWND hWnd ) +{ + if ( ImplSalYieldMutexTryToAcquire() ) + { + WinSalFrame* pFrame = GetWindowPtr( hWnd ); + if ( pFrame ) + { + UpdateFrameGeometry( hWnd, pFrame ); + + if ( GetWindowStyle( hWnd ) & WS_VISIBLE ) + pFrame->mbDefPos = FALSE; + + // Gegen moegliche Rekursionen sichern + if ( !pFrame->mbInMoveMsg ) + { + // Fenster im FullScreenModus wieder einpassen + pFrame->mbInMoveMsg = TRUE; + if ( pFrame->mbFullScreen ) + ImplSalFrameFullScreenPos( pFrame ); + pFrame->mbInMoveMsg = FALSE; + } + + // Status merken + ImplSaveFrameState( pFrame ); + + // Call Hdl + //#93851 if we call this handler, VCL floating windows are not updated correctly + ImplCallMoveHdl( hWnd ); + + } + + ImplSalYieldMutexRelease(); + } + else + ImplPostMessage( hWnd, SAL_MSG_POSTMOVE, 0, 0 ); +} + +// ----------------------------------------------------------------------- + +static void ImplCallSizeHdl( HWND hWnd ) +{ + // Da Windows diese Messages auch senden kann, muss hier auch die + // Solar-Semaphore beruecksichtigt werden + if ( ImplSalYieldMutexTryToAcquire() ) + { + WinSalFrame* pFrame = GetWindowPtr( hWnd ); + if ( pFrame ) + { + pFrame->CallCallback( SALEVENT_RESIZE, 0 ); + // Um doppelte Paints von VCL und SAL zu vermeiden + if ( IsWindowVisible( hWnd ) && !pFrame->mbInShow ) + UpdateWindow( hWnd ); + } + + ImplSalYieldMutexRelease(); + } + else + ImplPostMessage( hWnd, SAL_MSG_POSTCALLSIZE, 0, 0 ); +} + +// ----------------------------------------------------------------------- + +static void ImplHandleSizeMsg( HWND hWnd, WPARAM wParam, LPARAM lParam ) +{ + if ( (wParam != SIZE_MAXSHOW) && (wParam != SIZE_MAXHIDE) ) + { + WinSalFrame* pFrame = GetWindowPtr( hWnd ); + if ( pFrame ) + { + UpdateFrameGeometry( hWnd, pFrame ); + + pFrame->mnWidth = (int)LOWORD(lParam); + pFrame->mnHeight = (int)HIWORD(lParam); + // Status merken + ImplSaveFrameState( pFrame ); + // Call Hdl + ImplCallSizeHdl( hWnd ); + } + } +} + +// ----------------------------------------------------------------------- + +static void ImplHandleFocusMsg( HWND hWnd ) +{ + if ( ImplSalYieldMutexTryToAcquire() ) + { + WinSalFrame* pFrame = GetWindowPtr( hWnd ); + if ( pFrame && !WinSalFrame::mbInReparent ) + { + // Query the actual status + if ( ::GetFocus() == hWnd ) + { + if ( IsWindowVisible( hWnd ) && !pFrame->mbInShow ) + UpdateWindow( hWnd ); + + // Feststellen, ob wir IME unterstuetzen + if ( pFrame->mbIME && pFrame->mhDefIMEContext ) + { + UINT nImeProps = ImmGetProperty( GetKeyboardLayout( 0 ), IGP_PROPERTY ); + + pFrame->mbSpezIME = (nImeProps & IME_PROP_SPECIAL_UI) != 0; + pFrame->mbAtCursorIME = (nImeProps & IME_PROP_AT_CARET) != 0; + pFrame->mbHandleIME = !pFrame->mbSpezIME; + } + + pFrame->CallCallback( SALEVENT_GETFOCUS, 0 ); + } + else + { + pFrame->CallCallback( SALEVENT_LOSEFOCUS, 0 ); + } + } + + ImplSalYieldMutexRelease(); + } + else + ImplPostMessage( hWnd, SAL_MSG_POSTFOCUS, 0, 0 ); +} + +// ----------------------------------------------------------------------- + +static void ImplHandleCloseMsg( HWND hWnd ) +{ + if ( ImplSalYieldMutexTryToAcquire() ) + { + WinSalFrame* pFrame = GetWindowPtr( hWnd ); + if ( pFrame ) + { + pFrame->CallCallback( SALEVENT_CLOSE, 0 ); + } + + ImplSalYieldMutexRelease(); + } + else + ImplPostMessage( hWnd, WM_CLOSE, 0, 0 ); +} + +// ----------------------------------------------------------------------- + +static long ImplHandleShutDownMsg( HWND hWnd ) +{ + ImplSalYieldMutexAcquireWithWait(); + long nRet = 0; + WinSalFrame* pFrame = GetWindowPtr( hWnd ); + if ( pFrame ) + { + nRet = pFrame->CallCallback( SALEVENT_SHUTDOWN, 0 ); + } + ImplSalYieldMutexRelease(); + return nRet; +} + +// ----------------------------------------------------------------------- + +static void ImplHandleSettingsChangeMsg( HWND hWnd, UINT nMsg, + WPARAM wParam, LPARAM lParam ) +{ + USHORT nSalEvent = SALEVENT_SETTINGSCHANGED; + + if ( nMsg == WM_DEVMODECHANGE ) + nSalEvent = SALEVENT_PRINTERCHANGED; + else if ( nMsg == WM_DISPLAYCHANGE ) + nSalEvent = SALEVENT_DISPLAYCHANGED; + else if ( nMsg == WM_FONTCHANGE ) + nSalEvent = SALEVENT_FONTCHANGED; + else if ( nMsg == WM_TIMECHANGE ) + nSalEvent = SALEVENT_DATETIMECHANGED; + else if ( nMsg == WM_WININICHANGE ) + { + if ( lParam ) + { + if ( aSalShlData.mbWNT ) + { + if ( ImplSalWICompareAscii( (const wchar_t*)lParam, "devices" ) == 0 ) + nSalEvent = SALEVENT_PRINTERCHANGED; + } + else + { + if ( stricmp( (const char*)lParam, "devices" ) == 0 ) + nSalEvent = SALEVENT_PRINTERCHANGED; + } + } + } + + if ( nMsg == WM_SETTINGCHANGE ) + { + if ( wParam == SPI_SETWHEELSCROLLLINES ) + aSalShlData.mnWheelScrollLines = ImplSalGetWheelScrollLines(); + else if( wParam == SPI_SETWHEELSCROLLCHARS ) + aSalShlData.mnWheelScrollChars = ImplSalGetWheelScrollChars(); + } + + if ( WM_SYSCOLORCHANGE == nMsg && GetSalData()->mhDitherPal ) + ImplUpdateSysColorEntries(); + + ImplSalYieldMutexAcquireWithWait(); + + WinSalFrame* pFrame = GetWindowPtr( hWnd ); + if ( pFrame ) + { + if ( (nMsg == WM_DISPLAYCHANGE) || (nMsg == WM_WININICHANGE) ) + { + if ( pFrame->mbFullScreen ) + ImplSalFrameFullScreenPos( pFrame ); + } + + pFrame->CallCallback( nSalEvent, 0 ); + } + + ImplSalYieldMutexRelease(); +} + +// ----------------------------------------------------------------------- + +static void ImplHandleUserEvent( HWND hWnd, LPARAM lParam ) +{ + ImplSalYieldMutexAcquireWithWait(); + WinSalFrame* pFrame = GetWindowPtr( hWnd ); + if ( pFrame ) + { + pFrame->CallCallback( SALEVENT_USEREVENT, (void*)lParam ); + } + ImplSalYieldMutexRelease(); +} + +// ----------------------------------------------------------------------- + +static void ImplHandleForcePalette( HWND hWnd ) +{ + SalData* pSalData = GetSalData(); + HPALETTE hPal = pSalData->mhDitherPal; + if ( hPal ) + { + if ( !ImplSalYieldMutexTryToAcquire() ) + { + ImplPostMessage( hWnd, SAL_MSG_FORCEPALETTE, 0, 0 ); + return; + } + + WinSalFrame* pFrame = GetWindowPtr( hWnd ); + if ( pFrame && pFrame->mpGraphics ) + { + WinSalGraphics* pGraphics = pFrame->mpGraphics; + if ( pGraphics && pGraphics->mhDefPal ) + { + SelectPalette( pGraphics->mhDC, hPal, FALSE ); + if ( RealizePalette( pGraphics->mhDC ) ) + { + InvalidateRect( hWnd, NULL, FALSE ); + UpdateWindow( hWnd ); + pFrame->CallCallback( SALEVENT_DISPLAYCHANGED, 0 ); + } + } + } + + ImplSalYieldMutexRelease(); + } +} + +// ----------------------------------------------------------------------- + +static LRESULT ImplHandlePalette( BOOL bFrame, HWND hWnd, UINT nMsg, + WPARAM wParam, LPARAM lParam, int& rDef ) +{ + SalData* pSalData = GetSalData(); + HPALETTE hPal = pSalData->mhDitherPal; + if ( !hPal ) + return 0; + + rDef = FALSE; + if ( pSalData->mbInPalChange ) + return 0; + + if ( (nMsg == WM_PALETTECHANGED) || (nMsg == SAL_MSG_POSTPALCHANGED) ) + { + if ( (HWND)wParam == hWnd ) + return 0; + } + + BOOL bReleaseMutex = FALSE; + if ( (nMsg == WM_QUERYNEWPALETTE) || (nMsg == WM_PALETTECHANGED) ) + { + // Da Windows diese Messages auch sendet, muss hier auch die + // Solar-Semaphore beruecksichtigt werden + if ( ImplSalYieldMutexTryToAcquire() ) + bReleaseMutex = TRUE; + else if ( nMsg == WM_QUERYNEWPALETTE ) + ImplPostMessage( hWnd, SAL_MSG_POSTQUERYNEWPAL, wParam, lParam ); + else /* ( nMsg == WM_PALETTECHANGED ) */ + ImplPostMessage( hWnd, SAL_MSG_POSTPALCHANGED, wParam, lParam ); + } + + WinSalVirtualDevice*pTempVD; + WinSalFrame* pTempFrame; + WinSalGraphics* pGraphics; + HDC hDC; + HPALETTE hOldPal; + UINT nCols; + BOOL bStdDC; + BOOL bUpdate; + + pSalData->mbInPalChange = TRUE; + + // Alle Paletten in VirDevs und Frames zuruecksetzen + pTempVD = pSalData->mpFirstVD; + while ( pTempVD ) + { + pGraphics = pTempVD->mpGraphics; + if ( pGraphics->mhDefPal ) + { + SelectPalette( pGraphics->mhDC, + pGraphics->mhDefPal, + TRUE ); + } + pTempVD = pTempVD->mpNext; + } + pTempFrame = pSalData->mpFirstFrame; + while ( pTempFrame ) + { + pGraphics = pTempFrame->mpGraphics; + if ( pGraphics && pGraphics->mhDefPal ) + { + SelectPalette( pGraphics->mhDC, + pGraphics->mhDefPal, + TRUE ); + } + pTempFrame = pTempFrame->mpNextFrame; + } + + // Palette neu realizen + WinSalFrame* pFrame = NULL; + if ( bFrame ) + pFrame = GetWindowPtr( hWnd ); + if ( pFrame && pFrame->mpGraphics ) + { + hDC = pFrame->mpGraphics->mhDC; + bStdDC = TRUE; + } + else + { + hDC = GetDC( hWnd ); + bStdDC = FALSE; + } + UnrealizeObject( hPal ); + hOldPal = SelectPalette( hDC, hPal, TRUE ); + nCols = RealizePalette( hDC ); + bUpdate = nCols != 0; + if ( !bStdDC ) + { + SelectPalette( hDC, hOldPal, TRUE ); + ReleaseDC( hWnd, hDC ); + } + + // Alle Paletten in VirDevs und Frames neu setzen + pTempVD = pSalData->mpFirstVD; + while ( pTempVD ) + { + pGraphics = pTempVD->mpGraphics; + if ( pGraphics->mhDefPal ) + { + SelectPalette( pGraphics->mhDC, hPal, TRUE ); + RealizePalette( pGraphics->mhDC ); + } + pTempVD = pTempVD->mpNext; + } + pTempFrame = pSalData->mpFirstFrame; + while ( pTempFrame ) + { + if ( pTempFrame != pFrame ) + { + pGraphics = pTempFrame->mpGraphics; + if ( pGraphics && pGraphics->mhDefPal ) + { + SelectPalette( pGraphics->mhDC, hPal, TRUE ); + if ( RealizePalette( pGraphics->mhDC ) ) + bUpdate = TRUE; + } + } + pTempFrame = pTempFrame->mpNextFrame; + } + + // Wenn sich Farben geaendert haben, dann die Fenster updaten + if ( bUpdate ) + { + pTempFrame = pSalData->mpFirstFrame; + while ( pTempFrame ) + { + pGraphics = pTempFrame->mpGraphics; + if ( pGraphics && pGraphics->mhDefPal ) + { + InvalidateRect( pTempFrame->mhWnd, NULL, FALSE ); + UpdateWindow( pTempFrame->mhWnd ); + pTempFrame->CallCallback( SALEVENT_DISPLAYCHANGED, 0 ); + } + pTempFrame = pTempFrame->mpNextFrame; + } + } + + pSalData->mbInPalChange = FALSE; + + if ( bReleaseMutex ) + ImplSalYieldMutexRelease(); + + if ( nMsg == WM_PALETTECHANGED ) + return 0; + else + return nCols; +} + +// ----------------------------------------------------------------------- + +static int ImplHandleMinMax( HWND hWnd, LPARAM lParam ) +{ + int bRet = FALSE; + + if ( ImplSalYieldMutexTryToAcquire() ) + { + WinSalFrame* pFrame = GetWindowPtr( hWnd ); + if ( pFrame ) + { + MINMAXINFO* pMinMax = (MINMAXINFO*)lParam; + + if ( pFrame->mbFullScreen ) + { + int nX; + int nY; + int nDX; + int nDY; + ImplSalCalcFullScreenSize( pFrame, nX, nY, nDX, nDY ); + + if ( pMinMax->ptMaxPosition.x > nX ) + pMinMax->ptMaxPosition.x = nX; + if ( pMinMax->ptMaxPosition.y > nY ) + pMinMax->ptMaxPosition.y = nY; + + if ( pMinMax->ptMaxSize.x < nDX ) + pMinMax->ptMaxSize.x = nDX; + if ( pMinMax->ptMaxSize.y < nDY ) + pMinMax->ptMaxSize.y = nDY; + if ( pMinMax->ptMaxTrackSize.x < nDX ) + pMinMax->ptMaxTrackSize.x = nDX; + if ( pMinMax->ptMaxTrackSize.y < nDY ) + pMinMax->ptMaxTrackSize.y = nDY; + + pMinMax->ptMinTrackSize.x = nDX; + pMinMax->ptMinTrackSize.y = nDY; + + bRet = TRUE; + } + + if ( pFrame->mnMinWidth || pFrame->mnMinHeight ) + { + int nWidth = pFrame->mnMinWidth; + int nHeight = pFrame->mnMinHeight; + + ImplSalAddBorder( pFrame, nWidth, nHeight ); + + if ( pMinMax->ptMinTrackSize.x < nWidth ) + pMinMax->ptMinTrackSize.x = nWidth; + if ( pMinMax->ptMinTrackSize.y < nHeight ) + pMinMax->ptMinTrackSize.y = nHeight; + } + + if ( pFrame->mnMaxWidth || pFrame->mnMaxHeight ) + { + int nWidth = pFrame->mnMaxWidth; + int nHeight = pFrame->mnMaxHeight; + + ImplSalAddBorder( pFrame, nWidth, nHeight ); + + if( nWidth > 0 && nHeight > 0 ) // protect against int overflow due to INT_MAX initialisation + { + if ( pMinMax->ptMaxTrackSize.x > nWidth ) + pMinMax->ptMaxTrackSize.x = nWidth; + if ( pMinMax->ptMaxTrackSize.y > nHeight ) + pMinMax->ptMaxTrackSize.y = nHeight; + } + } + } + + ImplSalYieldMutexRelease(); + } + + return bRet; +} + +// ----------------------------------------------------------------------- + +// retrieves the SalMenuItem pointer from a hMenu +// the pointer is stored in every item, so if no position +// is specified we just use the first item (ie, pos=0) +// if bByPosition is FALSE then nPos denotes a menu id instead of a position +static WinSalMenuItem* ImplGetSalMenuItem( HMENU hMenu, UINT nPos, BOOL bByPosition=TRUE ) +{ + DWORD err=0; + + MENUITEMINFOW mi; + memset(&mi, 0, sizeof(mi)); + mi.cbSize = sizeof( mi ); + mi.fMask = MIIM_DATA; + if( !GetMenuItemInfoW( hMenu, nPos, bByPosition, &mi) ) + err = GetLastError(); + + return (WinSalMenuItem *) mi.dwItemData; +} + +// returns the index of the currently selected item if any or -1 +static int ImplGetSelectedIndex( HMENU hMenu ) +{ + DWORD err=0; + + MENUITEMINFOW mi; + memset(&mi, 0, sizeof(mi)); + mi.cbSize = sizeof( mi ); + mi.fMask = MIIM_STATE; + int n = GetMenuItemCount( hMenu ); + if( n != -1 ) + { + for(int i=0; i<n; i++ ) + { + if( !GetMenuItemInfoW( hMenu, i, TRUE, &mi) ) + err = GetLastError(); + else + { + if( mi.fState & MFS_HILITE ) + return i; + } + } + } + return -1; +} + +static int ImplMenuChar( HWND, WPARAM wParam, LPARAM lParam ) +{ + int nRet = MNC_IGNORE; + HMENU hMenu = (HMENU) lParam; + String aMnemonic; + aMnemonic.AssignAscii("&"); + aMnemonic.Append( (sal_Unicode) LOWORD(wParam) ); + aMnemonic.ToLowerAscii(); // we only have ascii mnemonics + + // search the mnemonic in the current menu + int nItemCount = GetMenuItemCount( hMenu ); + int nFound = 0; + int idxFound = -1; + int idxSelected = ImplGetSelectedIndex( hMenu ); + int idx = idxSelected != -1 ? idxSelected+1 : 0; // if duplicate mnemonics cycle through menu + for( int i=0; i< nItemCount; i++, idx++ ) + { + WinSalMenuItem* pSalMenuItem = ImplGetSalMenuItem( hMenu, idx % nItemCount ); + if( !pSalMenuItem ) + continue; + String aStr = pSalMenuItem->mText; + aStr.ToLowerAscii(); + if( aStr.Search( aMnemonic ) != STRING_NOTFOUND) + { + if( idxFound == -1 ) + idxFound = idx % nItemCount; + if( nFound++ ) + break; // duplicate found + } + } + if( nFound == 1 ) + nRet = MAKELRESULT( idxFound, MNC_EXECUTE ); + else + // duplicate mnemonics, just select the next occurence + nRet = MAKELRESULT( idxFound, MNC_SELECT ); + + return nRet; +} + +static int ImplMeasureItem( HWND hWnd, WPARAM wParam, LPARAM lParam ) +{ + int nRet = 0; + if( !wParam ) + { + // request was sent by a menu + nRet = 1; + MEASUREITEMSTRUCT *pMI = (LPMEASUREITEMSTRUCT) lParam; + if( pMI->CtlType != ODT_MENU ) + return 0; + + WinSalMenuItem *pSalMenuItem = (WinSalMenuItem *) pMI->itemData; + if( !pSalMenuItem ) + return 0; + + HDC hdc = GetDC( hWnd ); + SIZE strSize; + + NONCLIENTMETRICS ncm; + memset( &ncm, 0, sizeof(ncm) ); + ncm.cbSize = sizeof( ncm ); + SystemParametersInfo( SPI_GETNONCLIENTMETRICS, 0, (PVOID) &ncm, 0 ); + + // Assume every menu item can be default and printed bold + //ncm.lfMenuFont.lfWeight = FW_BOLD; + + HFONT hfntOld = (HFONT) SelectObject(hdc, (HFONT) CreateFontIndirect( &ncm.lfMenuFont )); + + // menu text and accelerator + String aStr(pSalMenuItem->mText.GetBuffer() ); + if( pSalMenuItem->mAccelText.Len() ) + { + aStr.AppendAscii(" "); + aStr.Append( pSalMenuItem->mAccelText ); + } + GetTextExtentPoint32W( hdc, (LPWSTR) aStr.GetBuffer(), + aStr.Len(), &strSize ); + + // image + Size bmpSize( 16, 16 ); + //if( !!pSalMenuItem->maBitmap ) + // bmpSize = pSalMenuItem->maBitmap.GetSizePixel(); + + // checkmark + Size checkSize( GetSystemMetrics( SM_CXMENUCHECK ), GetSystemMetrics( SM_CYMENUCHECK ) ); + + pMI->itemWidth = checkSize.Width() + 3 + bmpSize.Width() + 3 + strSize.cx; + pMI->itemHeight = Max( Max( checkSize.Height(), bmpSize.Height() ), strSize.cy ); + pMI->itemHeight += 4; + + DeleteObject( SelectObject(hdc, hfntOld) ); + ReleaseDC( hWnd, hdc ); + } + + return nRet; +} + +static int ImplDrawItem(HWND, WPARAM wParam, LPARAM lParam ) +{ + int nRet = 0; + DWORD err = 0; + if( !wParam ) + { + // request was sent by a menu + nRet = 1; + DRAWITEMSTRUCT *pDI = (LPDRAWITEMSTRUCT) lParam; + if( pDI->CtlType != ODT_MENU ) + return 0; + + WinSalMenuItem *pSalMenuItem = (WinSalMenuItem *) pDI->itemData; + if( !pSalMenuItem ) + return 0; + + COLORREF clrPrevText, clrPrevBkgnd; + HFONT hfntOld; + HBRUSH hbrOld; + BOOL fChecked = (pDI->itemState & ODS_CHECKED) ? TRUE : FALSE; + BOOL fSelected = (pDI->itemState & ODS_SELECTED) ? TRUE : FALSE; + BOOL fDisabled = (pDI->itemState & (ODS_DISABLED | ODS_GRAYED)) ? TRUE : FALSE; + + // Set the appropriate foreground and background colors. + RECT aRect = pDI->rcItem; + + clrPrevBkgnd = SetBkColor( pDI->hDC, GetSysColor( COLOR_MENU ) ); + + if ( fDisabled ) + clrPrevText = SetTextColor( pDI->hDC, GetSysColor( COLOR_GRAYTEXT ) ); + else + clrPrevText = SetTextColor( pDI->hDC, GetSysColor( fSelected ? COLOR_HIGHLIGHTTEXT : COLOR_MENUTEXT ) ); + + DWORD colBackground = GetSysColor( fSelected ? COLOR_HIGHLIGHT : COLOR_MENU ); + if ( fSelected ) + clrPrevBkgnd = SetBkColor( pDI->hDC, colBackground ); + else + clrPrevBkgnd = SetBkColor( pDI->hDC, colBackground ); + + hbrOld = (HBRUSH)SelectObject( pDI->hDC, CreateSolidBrush( GetBkColor( pDI->hDC ) ) ); + + // Fill background + if(!PatBlt( pDI->hDC, aRect.left, aRect.top, aRect.right-aRect.left, aRect.bottom-aRect.top, PATCOPY )) + err = GetLastError(); + + int lineHeight = aRect.bottom-aRect.top; + + int x = aRect.left; + int y = aRect.top; + + int checkWidth = GetSystemMetrics( SM_CXMENUCHECK ); + int checkHeight = GetSystemMetrics( SM_CYMENUCHECK ); + if( fChecked ) + { + RECT r; + r.left = 0; + r.top = 0; + r.right = checkWidth; + r.bottom = checkWidth; + HDC memDC = CreateCompatibleDC( pDI->hDC ); + HBITMAP memBmp = CreateCompatibleBitmap( pDI->hDC, checkWidth, checkHeight ); + HBITMAP hOldBmp = (HBITMAP) SelectObject( memDC, memBmp ); + DrawFrameControl( memDC, &r, DFC_MENU, DFCS_MENUCHECK ); + BitBlt( pDI->hDC, x, y+(lineHeight-checkHeight)/2, checkWidth, checkHeight, memDC, 0, 0, SRCAND ); + DeleteObject( SelectObject( memDC, hOldBmp ) ); + DeleteDC( memDC ); + } + x += checkWidth+3; + + //Size bmpSize = aBitmap.GetSizePixel(); + Size bmpSize(16, 16); + if( !!pSalMenuItem->maBitmap ) + { + Bitmap aBitmap( pSalMenuItem->maBitmap ); + + // set transparent pixels to background color + if( fDisabled ) + colBackground = RGB(255,255,255); + aBitmap.Replace( Color( COL_LIGHTMAGENTA ), + Color( GetRValue(colBackground),GetGValue(colBackground),GetBValue(colBackground) ), 0); + + WinSalBitmap* pSalBmp = static_cast<WinSalBitmap*>(aBitmap.ImplGetImpBitmap()->ImplGetSalBitmap()); + HGLOBAL hDrawDIB = pSalBmp->ImplGethDIB(); + + if( hDrawDIB ) + { + PBITMAPINFO pBI = (PBITMAPINFO) GlobalLock( hDrawDIB ); + PBITMAPINFOHEADER pBIH = (PBITMAPINFOHEADER) pBI; + PBYTE pBits = (PBYTE) pBI + *(DWORD*) pBI + + pSalBmp->ImplGetDIBColorCount( hDrawDIB ) * sizeof( RGBQUAD ); + + HBITMAP hBmp = CreateDIBitmap( pDI->hDC, pBIH, CBM_INIT, pBits, pBI, DIB_RGB_COLORS ); + GlobalUnlock( hDrawDIB ); + + HBRUSH hbrIcon = CreateSolidBrush( GetSysColor( COLOR_GRAYTEXT ) ); + DrawStateW( pDI->hDC, (HBRUSH)hbrIcon, (DRAWSTATEPROC)NULL, (LPARAM)hBmp, (WPARAM)0, + x, y+(lineHeight-bmpSize.Height())/2, bmpSize.Width(), bmpSize.Height(), + DST_BITMAP | (fDisabled ? (fSelected ? DSS_MONO : DSS_DISABLED) : DSS_NORMAL) ); + + DeleteObject( hbrIcon ); + DeleteObject( hBmp ); + } + + } + x += bmpSize.Width() + 3; + aRect.left = x; + + NONCLIENTMETRICS ncm; + memset( &ncm, 0, sizeof(ncm) ); + ncm.cbSize = sizeof( ncm ); + SystemParametersInfo( SPI_GETNONCLIENTMETRICS, 0, (PVOID) &ncm, 0 ); + + // Print default menu entry with bold font + //if ( pDI->itemState & ODS_DEFAULT ) + // ncm.lfMenuFont.lfWeight = FW_BOLD; + + hfntOld = (HFONT) SelectObject(pDI->hDC, (HFONT) CreateFontIndirect( &ncm.lfMenuFont )); + + SIZE strSize; + String aStr( pSalMenuItem->mText.GetBuffer() ); + GetTextExtentPoint32W( pDI->hDC, (LPWSTR) aStr.GetBuffer(), + aStr.Len(), &strSize ); + + if(!DrawStateW( pDI->hDC, (HBRUSH)NULL, (DRAWSTATEPROC)NULL, + (LPARAM)(LPWSTR) aStr.GetBuffer(), + (WPARAM)0, aRect.left, aRect.top + (lineHeight - strSize.cy)/2, 0, 0, + DST_PREFIXTEXT | (fDisabled && !fSelected ? DSS_DISABLED : DSS_NORMAL) ) ) + err = GetLastError(); + + if( pSalMenuItem->mAccelText.Len() ) + { + SIZE strSizeA; + aStr = pSalMenuItem->mAccelText; + GetTextExtentPoint32W( pDI->hDC, (LPWSTR) aStr.GetBuffer(), + aStr.Len(), &strSizeA ); + TEXTMETRIC tm; + GetTextMetrics( pDI->hDC, &tm ); + + // position the accelerator string to the right but leave space for the + // (potential) submenu arrow (tm.tmMaxCharWidth) + if(!DrawStateW( pDI->hDC, (HBRUSH)NULL, (DRAWSTATEPROC)NULL, + (LPARAM)(LPWSTR) aStr.GetBuffer(), + (WPARAM)0, aRect.right-strSizeA.cx-tm.tmMaxCharWidth, aRect.top + (lineHeight - strSizeA.cy)/2, 0, 0, + DST_TEXT | (fDisabled && !fSelected ? DSS_DISABLED : DSS_NORMAL) ) ) + err = GetLastError(); + } + + // Restore the original font and colors. + DeleteObject( SelectObject( pDI->hDC, hbrOld ) ); + DeleteObject( SelectObject( pDI->hDC, hfntOld) ); + SetTextColor(pDI->hDC, clrPrevText); + SetBkColor(pDI->hDC, clrPrevBkgnd); + } + return nRet; +} + +static int ImplHandleMenuActivate( HWND hWnd, WPARAM wParam, LPARAM ) +{ + // Menu activation + WinSalFrame* pFrame = GetWindowPtr( hWnd ); + if ( !pFrame ) + return 0; + + HMENU hMenu = (HMENU) wParam; + // WORD nPos = LOWORD (lParam); + // BOOL bWindowMenu = (BOOL) HIWORD(lParam); + + // Send activate and deactivate together, so we have not keep track of opened menues + // this will be enough to have the menues updated correctly + SalMenuEvent aMenuEvt; + WinSalMenuItem *pSalMenuItem = ImplGetSalMenuItem( hMenu, 0 ); + if( pSalMenuItem ) + aMenuEvt.mpMenu = pSalMenuItem->mpMenu; + else + aMenuEvt.mpMenu = NULL; + + long nRet = pFrame->CallCallback( SALEVENT_MENUACTIVATE, &aMenuEvt ); + if( nRet ) + nRet = pFrame->CallCallback( SALEVENT_MENUDEACTIVATE, &aMenuEvt ); + if( nRet ) + pFrame->mLastActivatedhMenu = hMenu; + + return (nRet!=0); +} + +static int ImplHandleMenuSelect( HWND hWnd, WPARAM wParam, LPARAM lParam ) +{ + // Menu selection + WinSalFrame* pFrame = GetWindowPtr( hWnd ); + if ( !pFrame ) + return 0; + + WORD nId = LOWORD(wParam); // menu item or submenu index + WORD nFlags = HIWORD(wParam); + HMENU hMenu = (HMENU) lParam; + + // check if we have to process the message + if( !GetSalData()->IsKnownMenuHandle( hMenu ) ) + return 0; + + BOOL bByPosition = FALSE; + if( nFlags & MF_POPUP ) + bByPosition = TRUE; + + long nRet = 0; + if ( hMenu && !pFrame->mLastActivatedhMenu ) + { + // we never activated a menu (ie, no WM_INITMENUPOPUP has occured yet) + // which means this must be the menubar -> send activation/deactivation + SalMenuEvent aMenuEvt; + WinSalMenuItem *pSalMenuItem = ImplGetSalMenuItem( hMenu, nId, bByPosition ); + if( pSalMenuItem ) + aMenuEvt.mpMenu = pSalMenuItem->mpMenu; + else + aMenuEvt.mpMenu = NULL; + + nRet = pFrame->CallCallback( SALEVENT_MENUACTIVATE, &aMenuEvt ); + if( nRet ) + nRet = pFrame->CallCallback( SALEVENT_MENUDEACTIVATE, &aMenuEvt ); + if( nRet ) + pFrame->mLastActivatedhMenu = hMenu; + } + + if( !hMenu && nFlags == 0xFFFF ) + { + // all menus are closed, reset activation logic + pFrame->mLastActivatedhMenu = NULL; + } + + if( hMenu ) + { + // hMenu must be saved, as it is not passed in WM_COMMAND which always occurs after a selection + // if a menu is closed due to a command selection then hMenu is NULL, but WM_COMMAND comes later + // so we must not overwrite it in this case + pFrame->mSelectedhMenu = hMenu; + + // send highlight event + if( nFlags & MF_POPUP ) + { + // submenu selected + // wParam now carries an index instead of an id -> retrieve id + MENUITEMINFOW mi; + memset(&mi, 0, sizeof(mi)); + mi.cbSize = sizeof( mi ); + mi.fMask = MIIM_ID; + if( GetMenuItemInfoW( hMenu, LOWORD(wParam), TRUE, &mi) ) + nId = sal::static_int_cast<WORD>(mi.wID); + } + + SalMenuEvent aMenuEvt; + aMenuEvt.mnId = nId; + WinSalMenuItem *pSalMenuItem = ImplGetSalMenuItem( hMenu, nId, FALSE ); + if( pSalMenuItem ) + aMenuEvt.mpMenu = pSalMenuItem->mpMenu; + else + aMenuEvt.mpMenu = NULL; + + nRet = pFrame->CallCallback( SALEVENT_MENUHIGHLIGHT, &aMenuEvt ); + } + + return (nRet != 0); +} + +static int ImplHandleCommand( HWND hWnd, WPARAM wParam, LPARAM ) +{ + WinSalFrame* pFrame = GetWindowPtr( hWnd ); + if ( !pFrame ) + return 0; + + long nRet = 0; + if( !HIWORD(wParam) ) + { + // Menu command + WORD nId = LOWORD(wParam); + if( nId ) // zero for separators + { + SalMenuEvent aMenuEvt; + aMenuEvt.mnId = nId; + WinSalMenuItem *pSalMenuItem = ImplGetSalMenuItem( pFrame->mSelectedhMenu, nId, FALSE ); + if( pSalMenuItem ) + aMenuEvt.mpMenu = pSalMenuItem->mpMenu; + else + aMenuEvt.mpMenu = NULL; + + nRet = pFrame->CallCallback( SALEVENT_MENUCOMMAND, &aMenuEvt ); + } + } + return (nRet != 0); +} + +static int ImplHandleSysCommand( HWND hWnd, WPARAM wParam, LPARAM lParam ) +{ + WinSalFrame* pFrame = GetWindowPtr( hWnd ); + if ( !pFrame ) + return 0; + + WPARAM nCommand = wParam & 0xFFF0; + + if ( pFrame->mbFullScreen ) + { + WIN_BOOL bMaximize = IsZoomed( pFrame->mhWnd ); + WIN_BOOL bMinimize = IsIconic( pFrame->mhWnd ); + if ( (nCommand == SC_SIZE) || + (!bMinimize && (nCommand == SC_MOVE)) || + (!bMaximize && (nCommand == SC_MAXIMIZE)) || + (bMaximize && (nCommand == SC_RESTORE)) ) + { + MessageBeep( 0 ); + return TRUE; + } + } + + if ( nCommand == SC_KEYMENU ) + { + // do not process SC_KEYMENU if we have a native menu + // Windows should handle this + if( GetMenu( hWnd ) ) + return FALSE; + + // Hier verarbeiten wir nur KeyMenu-Events fuer Alt um + // den MenuBar zu aktivieren, oder wenn ein SysChild-Fenster + // den Focus hat, da diese Alt+Tasten-Kombinationen nur + // ueber diesen Event verarbeitet werden + if ( !LOWORD( lParam ) ) + { + // Nur ausloesen, wenn keine weitere Taste gedrueckt ist. Im + // Gegensatz zur Doku wird in der X-Koordinaate der CharCode + // geliefert, der zusaetzlich gedrueckt ist + // Also 32 fuer Space, 99 fuer c, 100 fuer d, ... + // Da dies nicht dokumentiert ist, fragen wir vorsichtshalber + // auch den Status der Space-Taste ab + if ( GetKeyState( VK_SPACE ) & 0x8000 ) + return 0; + + // Damit nicht bei Alt+Maustaste auch der MenuBar aktiviert wird + if ( (GetKeyState( VK_LBUTTON ) & 0x8000) || + (GetKeyState( VK_RBUTTON ) & 0x8000) || + (GetKeyState( VK_MBUTTON ) & 0x8000) || + (GetKeyState( VK_SHIFT ) & 0x8000) ) + return 1; + + SalKeyEvent aKeyEvt; + aKeyEvt.mnTime = GetMessageTime(); + aKeyEvt.mnCode = KEY_MENU; + aKeyEvt.mnCharCode = 0; + aKeyEvt.mnRepeat = 0; + long nRet = pFrame->CallCallback( SALEVENT_KEYINPUT, &aKeyEvt ); + pFrame->CallCallback( SALEVENT_KEYUP, &aKeyEvt ); + return (nRet != 0); + } + else + { + // Testen, ob ein SysChild den Focus hat + HWND hFocusWnd = ::GetFocus(); + if ( hFocusWnd && ImplFindSalObject( hFocusWnd ) ) + { + char cKeyCode = (char)(unsigned char)LOWORD( lParam ); + // LowerCase + if ( (cKeyCode >= 65) && (cKeyCode <= 90) ) + cKeyCode += 32; + // Wir nehmen nur 0-9 und A-Z, alle anderen Tasten muessen durch + // den Hook vom SalObj verarbeitet werden + if ( ((cKeyCode >= 48) && (cKeyCode <= 57)) || + ((cKeyCode >= 97) && (cKeyCode <= 122)) ) + { + USHORT nModCode = 0; + if ( GetKeyState( VK_SHIFT ) & 0x8000 ) + nModCode |= KEY_SHIFT; + if ( GetKeyState( VK_CONTROL ) & 0x8000 ) + nModCode |= KEY_MOD1; + nModCode |= KEY_MOD2; + + SalKeyEvent aKeyEvt; + aKeyEvt.mnTime = GetMessageTime(); + if ( (cKeyCode >= 48) && (cKeyCode <= 57) ) + aKeyEvt.mnCode = KEY_0+(cKeyCode-48); + else + aKeyEvt.mnCode = KEY_A+(cKeyCode-97); + aKeyEvt.mnCode |= nModCode; + aKeyEvt.mnCharCode = cKeyCode; + aKeyEvt.mnRepeat = 0; + long nRet = pFrame->CallCallback( SALEVENT_KEYINPUT, &aKeyEvt ); + pFrame->CallCallback( SALEVENT_KEYUP, &aKeyEvt ); + return (nRet != 0); + } + } + } + } + + return FALSE; +} + +// ----------------------------------------------------------------------- + +static void ImplHandleInputLangChange( HWND hWnd, WPARAM, LPARAM lParam ) +{ + ImplSalYieldMutexAcquireWithWait(); + + // Feststellen, ob wir IME unterstuetzen + WinSalFrame* pFrame = GetWindowPtr( hWnd ); + if ( pFrame && pFrame->mbIME && pFrame->mhDefIMEContext ) + { + HKL hKL = (HKL)lParam; + UINT nImeProps = ImmGetProperty( hKL, IGP_PROPERTY ); + + pFrame->mbSpezIME = (nImeProps & IME_PROP_SPECIAL_UI) != 0; + pFrame->mbAtCursorIME = (nImeProps & IME_PROP_AT_CARET) != 0; + pFrame->mbHandleIME = !pFrame->mbSpezIME; + } + + // trigger input language and codepage update + UINT nLang = pFrame->mnInputLang; + ImplUpdateInputLang( pFrame ); + + // notify change + if( nLang != pFrame->mnInputLang ) + pFrame->CallCallback( SALEVENT_INPUTLANGUAGECHANGE, 0 ); + + ImplSalYieldMutexRelease(); +} + +// ----------------------------------------------------------------------- + +static void ImplUpdateIMECursorPos( WinSalFrame* pFrame, HIMC hIMC ) +{ + COMPOSITIONFORM aForm; + memset( &aForm, 0, sizeof( aForm ) ); + + // Cursor-Position ermitteln und aus der die Default-Position fuer + // das Composition-Fenster berechnen + SalExtTextInputPosEvent aPosEvt; + pFrame->CallCallback( SALEVENT_EXTTEXTINPUTPOS, (void*)&aPosEvt ); + if ( (aPosEvt.mnX == -1) && (aPosEvt.mnY == -1) ) + aForm.dwStyle |= CFS_DEFAULT; + else + { + aForm.dwStyle |= CFS_POINT; + aForm.ptCurrentPos.x = aPosEvt.mnX; + aForm.ptCurrentPos.y = aPosEvt.mnY; + } + ImmSetCompositionWindow( hIMC, &aForm ); + + // Because not all IME's use this values, we create + // a Windows caret to force the Position from the IME + if ( GetFocus() == pFrame->mhWnd ) + { + CreateCaret( pFrame->mhWnd, 0, + aPosEvt.mnWidth, aPosEvt.mnHeight ); + SetCaretPos( aPosEvt.mnX, aPosEvt.mnY ); + } +} + +// ----------------------------------------------------------------------- + +static BOOL ImplHandleIMEStartComposition( HWND hWnd ) +{ + BOOL bDef = TRUE; + + ImplSalYieldMutexAcquireWithWait(); + + WinSalFrame* pFrame = GetWindowPtr( hWnd ); + if ( pFrame ) + { + HIMC hIMC = ImmGetContext( hWnd ); + if ( hIMC ) + { + ImplUpdateIMECursorPos( pFrame, hIMC ); + ImmReleaseContext( hWnd, hIMC ); + } + + if ( pFrame->mbHandleIME ) + { + if ( pFrame->mbAtCursorIME ) + bDef = FALSE; + } + } + + ImplSalYieldMutexRelease(); + + return bDef; +} + +// ----------------------------------------------------------------------- + +static BOOL ImplHandleIMECompositionInput( WinSalFrame* pFrame, + HIMC hIMC, LPARAM lParam ) +{ + BOOL bDef = TRUE; + + // Init Event + SalExtTextInputEvent aEvt; + aEvt.mnTime = GetMessageTime(); + aEvt.mpTextAttr = NULL; + aEvt.mnCursorPos = 0; + aEvt.mnDeltaStart = 0; + aEvt.mbOnlyCursor = FALSE; + aEvt.mnCursorFlags = 0; + + // If we get a result string, then we handle this input + if ( lParam & GCS_RESULTSTR ) + { + bDef = FALSE; + + LONG nTextLen = ImmGetCompositionStringW( hIMC, GCS_RESULTSTR, 0, 0 ) / sizeof( WCHAR ); + if ( nTextLen >= 0 ) + { + WCHAR* pTextBuf = new WCHAR[nTextLen]; + ImmGetCompositionStringW( hIMC, GCS_RESULTSTR, pTextBuf, nTextLen*sizeof( WCHAR ) ); + aEvt.maText = XubString( reinterpret_cast<const xub_Unicode*>(pTextBuf), (xub_StrLen)nTextLen ); + delete pTextBuf; + } + + aEvt.mnCursorPos = aEvt.maText.Len(); + pFrame->CallCallback( SALEVENT_EXTTEXTINPUT, (void*)&aEvt ); + pFrame->CallCallback( SALEVENT_ENDEXTTEXTINPUT, (void*)NULL ); + ImplUpdateIMECursorPos( pFrame, hIMC ); + } + + // If the IME doesn't support OnSpot input, then there is nothing to do + if ( !pFrame->mbAtCursorIME ) + return !bDef; + + // If we get new Composition data, then we handle this new input + if ( (lParam & (GCS_COMPSTR | GCS_COMPATTR)) || + ((lParam & GCS_CURSORPOS) && !(lParam & GCS_RESULTSTR)) ) + { + bDef = FALSE; + + USHORT* pSalAttrAry = NULL; + LONG nTextLen = ImmGetCompositionStringW( hIMC, GCS_COMPSTR, 0, 0 ) / sizeof( WCHAR ); + if ( nTextLen > 0 ) + { + WCHAR* pTextBuf = new WCHAR[nTextLen]; + ImmGetCompositionStringW( hIMC, GCS_COMPSTR, pTextBuf, nTextLen*sizeof( WCHAR ) ); + aEvt.maText = XubString( reinterpret_cast<const xub_Unicode*>(pTextBuf), (xub_StrLen)nTextLen ); + delete pTextBuf; + + WIN_BYTE* pAttrBuf = NULL; + LONG nAttrLen = ImmGetCompositionStringW( hIMC, GCS_COMPATTR, 0, 0 ); + if ( nAttrLen > 0 ) + { + pAttrBuf = new WIN_BYTE[nAttrLen]; + ImmGetCompositionStringW( hIMC, GCS_COMPATTR, pAttrBuf, nAttrLen ); + } + + if ( pAttrBuf ) + { + xub_StrLen nTextLen = aEvt.maText.Len(); + pSalAttrAry = new USHORT[nTextLen]; + memset( pSalAttrAry, 0, nTextLen*sizeof( USHORT ) ); + for ( xub_StrLen i = 0; (i < nTextLen) && (i < nAttrLen); i++ ) + { + WIN_BYTE nWinAttr = pAttrBuf[i]; + USHORT nSalAttr; + if ( nWinAttr == ATTR_TARGET_CONVERTED ) + { + nSalAttr = SAL_EXTTEXTINPUT_ATTR_BOLDUNDERLINE; + aEvt.mnCursorFlags |= SAL_EXTTEXTINPUT_CURSOR_INVISIBLE; + } + else if ( nWinAttr == ATTR_CONVERTED ) + nSalAttr = SAL_EXTTEXTINPUT_ATTR_DASHDOTUNDERLINE; + else if ( nWinAttr == ATTR_TARGET_NOTCONVERTED ) + nSalAttr = SAL_EXTTEXTINPUT_ATTR_HIGHLIGHT; + else if ( nWinAttr == ATTR_INPUT_ERROR ) + nSalAttr = SAL_EXTTEXTINPUT_ATTR_REDTEXT | SAL_EXTTEXTINPUT_ATTR_DOTTEDUNDERLINE; + else /* ( nWinAttr == ATTR_INPUT ) */ + nSalAttr = SAL_EXTTEXTINPUT_ATTR_DOTTEDUNDERLINE; + pSalAttrAry[i] = nSalAttr; + } + + aEvt.mpTextAttr = pSalAttrAry; + delete pAttrBuf; + } + } + + // Only when we get new composition data, we must send this event + if ( (nTextLen > 0) || !(lParam & GCS_RESULTSTR) ) + { + // End the mode, if the last character is deleted + if ( !nTextLen && !pFrame->mbCandidateMode ) + { + pFrame->CallCallback( SALEVENT_EXTTEXTINPUT, (void*)&aEvt ); + pFrame->CallCallback( SALEVENT_ENDEXTTEXTINPUT, (void*)NULL ); + } + else + { + // Because Cursor-Position and DeltaStart never updated + // from the korean input engine, we must handle this here + if ( lParam & CS_INSERTCHAR ) + { + aEvt.mnCursorPos = nTextLen; + if ( aEvt.mnCursorPos && (lParam & CS_NOMOVECARET) ) + aEvt.mnCursorPos--; + } + else + aEvt.mnCursorPos = LOWORD( ImmGetCompositionStringW( hIMC, GCS_CURSORPOS, 0, 0 ) ); + + if ( pFrame->mbCandidateMode ) + aEvt.mnCursorFlags |= SAL_EXTTEXTINPUT_CURSOR_INVISIBLE; + if ( lParam & CS_NOMOVECARET ) + aEvt.mnCursorFlags |= SAL_EXTTEXTINPUT_CURSOR_OVERWRITE; + + pFrame->CallCallback( SALEVENT_EXTTEXTINPUT, (void*)&aEvt ); + } + ImplUpdateIMECursorPos( pFrame, hIMC ); + } + + if ( pSalAttrAry ) + delete pSalAttrAry; + } + + return !bDef; +} + +// ----------------------------------------------------------------------- + +static BOOL ImplHandleIMEComposition( HWND hWnd, LPARAM lParam ) +{ + BOOL bDef = TRUE; + ImplSalYieldMutexAcquireWithWait(); + + WinSalFrame* pFrame = GetWindowPtr( hWnd ); + if ( pFrame && (!lParam || (lParam & GCS_RESULTSTR)) ) + { + // Wir restaurieren den Background-Modus bei jeder Texteingabe, + // da einige Tools wie RichWin uns diesen hin- und wieder umsetzen + if ( pFrame->mpGraphics && + pFrame->mpGraphics->mhDC ) + SetBkMode( pFrame->mpGraphics->mhDC, TRANSPARENT ); + } + + if ( pFrame && pFrame->mbHandleIME ) + { + if ( !lParam ) + { + SalExtTextInputEvent aEvt; + aEvt.mnTime = GetMessageTime(); + aEvt.mpTextAttr = NULL; + aEvt.mnCursorPos = 0; + aEvt.mnDeltaStart = 0; + aEvt.mbOnlyCursor = FALSE; + aEvt.mnCursorFlags = 0; + pFrame->CallCallback( SALEVENT_EXTTEXTINPUT, (void*)&aEvt ); + pFrame->CallCallback( SALEVENT_ENDEXTTEXTINPUT, (void*)NULL ); + } + else if ( lParam & (GCS_RESULTSTR | GCS_COMPSTR | GCS_COMPATTR | GCS_CURSORPOS) ) + { + HIMC hIMC = ImmGetContext( hWnd ); + if ( hIMC ) + { + if ( ImplHandleIMECompositionInput( pFrame, hIMC, lParam ) ) + bDef = FALSE; + + ImmReleaseContext( hWnd, hIMC ); + } + } + } + + ImplSalYieldMutexRelease(); + return bDef; +} + +// ----------------------------------------------------------------------- + +static BOOL ImplHandleIMEEndComposition( HWND hWnd ) +{ + BOOL bDef = TRUE; + + ImplSalYieldMutexAcquireWithWait(); + + WinSalFrame* pFrame = GetWindowPtr( hWnd ); + if ( pFrame && pFrame->mbHandleIME ) + { + if ( pFrame->mbAtCursorIME ) + bDef = FALSE; + } + + ImplSalYieldMutexRelease(); + + return bDef; +} + +// ----------------------------------------------------------------------- + +static boolean ImplHandleAppCommand( HWND hWnd, LPARAM lParam ) +{ + sal_Int16 nCommand = 0; + switch( GET_APPCOMMAND_LPARAM(lParam) ) + { + case APPCOMMAND_MEDIA_CHANNEL_DOWN: nCommand = MEDIA_COMMAND_CHANNEL_DOWN; break; + case APPCOMMAND_MEDIA_CHANNEL_UP: nCommand = MEDIA_COMMAND_CHANNEL_UP; break; + case APPCOMMAND_MEDIA_NEXTTRACK: nCommand = MEDIA_COMMAND_NEXTTRACK; break; + case APPCOMMAND_MEDIA_PAUSE: nCommand = MEDIA_COMMAND_PAUSE; break; + case APPCOMMAND_MEDIA_PLAY: nCommand = MEDIA_COMMAND_PLAY; break; + case APPCOMMAND_MEDIA_PLAY_PAUSE: nCommand = MEDIA_COMMAND_PLAY_PAUSE; break; + case APPCOMMAND_MEDIA_PREVIOUSTRACK: nCommand = MEDIA_COMMAND_PREVIOUSTRACK; break; + case APPCOMMAND_MEDIA_RECORD: nCommand = MEDIA_COMMAND_RECORD; break; + case APPCOMMAND_MEDIA_REWIND: nCommand = MEDIA_COMMAND_REWIND; break; + case APPCOMMAND_MEDIA_STOP: nCommand = MEDIA_COMMAND_STOP; break; + case APPCOMMAND_MIC_ON_OFF_TOGGLE: nCommand = MEDIA_COMMAND_MIC_ON_OFF_TOGGLE; break; + case APPCOMMAND_MICROPHONE_VOLUME_DOWN: nCommand = MEDIA_COMMAND_MICROPHONE_VOLUME_DOWN; break; + case APPCOMMAND_MICROPHONE_VOLUME_MUTE: nCommand = MEDIA_COMMAND_MICROPHONE_VOLUME_MUTE; break; + case APPCOMMAND_MICROPHONE_VOLUME_UP: nCommand = MEDIA_COMMAND_MICROPHONE_VOLUME_UP; break; + case APPCOMMAND_VOLUME_DOWN: nCommand = MEDIA_COMMAND_VOLUME_DOWN; break; + case APPCOMMAND_VOLUME_MUTE: nCommand = MEDIA_COMMAND_VOLUME_MUTE; break; + case APPCOMMAND_VOLUME_UP: nCommand = MEDIA_COMMAND_VOLUME_UP; break; + break; + default: + return false; + } + + WinSalFrame* pFrame = GetWindowPtr( hWnd ); + Window *pWindow = pFrame ? pFrame->GetWindow() : NULL; + + if( pWindow ) + { + const Point aPoint; + CommandEvent aCEvt( aPoint, COMMAND_MEDIA, FALSE, &nCommand ); + NotifyEvent aNCmdEvt( EVENT_COMMAND, pWindow, &aCEvt ); + + if ( !ImplCallPreNotify( aNCmdEvt ) ) + { + pWindow->Command( aCEvt ); + return true; + } + } + + return false; +} + + +static void ImplHandleIMENotify( HWND hWnd, WPARAM wParam ) +{ + if ( wParam == (WPARAM)IMN_OPENCANDIDATE ) + { + ImplSalYieldMutexAcquireWithWait(); + + WinSalFrame* pFrame = GetWindowPtr( hWnd ); + if ( pFrame && pFrame->mbHandleIME && + pFrame->mbAtCursorIME ) + { + // Wir wollen den Cursor hiden + pFrame->mbCandidateMode = TRUE; + ImplHandleIMEComposition( hWnd, GCS_CURSORPOS ); + + HWND hWnd = pFrame->mhWnd; + HIMC hIMC = ImmGetContext( hWnd ); + if ( hIMC ) + { + LONG nBufLen = ImmGetCompositionStringW( hIMC, GCS_COMPSTR, 0, 0 ); + if ( nBufLen >= 1 ) + { + SalExtTextInputPosEvent aPosEvt; + pFrame->CallCallback( SALEVENT_EXTTEXTINPUTPOS, (void*)&aPosEvt ); + + // Vertical !!! + CANDIDATEFORM aForm; + aForm.dwIndex = 0; + aForm.dwStyle = CFS_EXCLUDE; + aForm.ptCurrentPos.x = aPosEvt.mnX; + aForm.ptCurrentPos.y = aPosEvt.mnY+1; + aForm.rcArea.left = aPosEvt.mnX; + aForm.rcArea.top = aPosEvt.mnY; + aForm.rcArea.right = aForm.rcArea.left+aPosEvt.mnExtWidth+1; + aForm.rcArea.bottom = aForm.rcArea.top+aPosEvt.mnHeight+1; + ImmSetCandidateWindow( hIMC, &aForm ); + } + + ImmReleaseContext( hWnd, hIMC ); + } + } + + ImplSalYieldMutexRelease(); + } + else if ( wParam == (WPARAM)IMN_CLOSECANDIDATE ) + { + ImplSalYieldMutexAcquireWithWait(); + WinSalFrame* pFrame = GetWindowPtr( hWnd ); + if ( pFrame ) + pFrame->mbCandidateMode = FALSE; + ImplSalYieldMutexRelease(); + } +} + +// ----------------------------------------------------------------------- +#if WINVER >= 0x0500 + +static LRESULT ImplHandleIMEReconvertString( HWND hWnd, LPARAM lParam ) +{ + WinSalFrame* pFrame = GetWindowPtr( hWnd ); + LPRECONVERTSTRING pReconvertString = (LPRECONVERTSTRING) lParam; + LRESULT nRet = 0; + SalSurroundingTextRequestEvent aEvt; + aEvt.maText = UniString(); + aEvt.mnStart = aEvt.mnEnd = 0; + + UINT nImeProps = ImmGetProperty( GetKeyboardLayout( 0 ), IGP_SETCOMPSTR ); + if( (nImeProps & SCS_CAP_SETRECONVERTSTRING) == 0 ) + { + // This IME does not support reconversion. + return 0; + } + + if( !pReconvertString ) + { + // The first call for reconversion. + pFrame->CallCallback( SALEVENT_STARTRECONVERSION, (void*)NULL ); + + // Retrieve the surrounding text from the focused control. + pFrame->CallCallback( SALEVENT_SURROUNDINGTEXTREQUEST, (void*)&aEvt ); + + if( aEvt.maText.Len() == 0 ) + { + return 0; + } + + nRet = sizeof(RECONVERTSTRING) + (aEvt.maText.Len() + 1) * sizeof(WCHAR); + } + else + { + // The second call for reconversion. + + // Retrieve the surrounding text from the focused control. + pFrame->CallCallback( SALEVENT_SURROUNDINGTEXTREQUEST, (void*)&aEvt ); + nRet = sizeof(RECONVERTSTRING) + (aEvt.maText.Len() + 1) * sizeof(WCHAR); + + pReconvertString->dwStrOffset = sizeof(RECONVERTSTRING); + pReconvertString->dwStrLen = aEvt.maText.Len(); + pReconvertString->dwCompStrOffset = aEvt.mnStart * sizeof(WCHAR); + pReconvertString->dwCompStrLen = aEvt.mnEnd - aEvt.mnStart; + pReconvertString->dwTargetStrOffset = pReconvertString->dwCompStrOffset; + pReconvertString->dwTargetStrLen = pReconvertString->dwCompStrLen; + + memcpy( (LPWSTR)(pReconvertString + 1), aEvt.maText.GetBuffer(), (aEvt.maText.Len() + 1) * sizeof(WCHAR) ); + } + + // just return the required size of buffer to reconvert. + return nRet; +} + +// ----------------------------------------------------------------------- + +static LRESULT ImplHandleIMEConfirmReconvertString( HWND hWnd, LPARAM lParam ) +{ + WinSalFrame* pFrame = GetWindowPtr( hWnd ); + LPRECONVERTSTRING pReconvertString = (LPRECONVERTSTRING) lParam; + SalSurroundingTextRequestEvent aEvt; + aEvt.maText = UniString(); + aEvt.mnStart = aEvt.mnEnd = 0; + + pFrame->CallCallback( SALEVENT_SURROUNDINGTEXTREQUEST, (void*)&aEvt ); + + ULONG nTmpStart = pReconvertString->dwCompStrOffset / sizeof(WCHAR); + ULONG nTmpEnd = nTmpStart + pReconvertString->dwCompStrLen; + + if( nTmpStart != aEvt.mnStart || nTmpEnd != aEvt.mnEnd ) + { + SalSurroundingTextSelectionChangeEvent aSelEvt; + aSelEvt.mnStart = nTmpStart; + aSelEvt.mnEnd = nTmpEnd; + + pFrame->CallCallback( SALEVENT_SURROUNDINGTEXTSELECTIONCHANGE, (void*)&aSelEvt ); + } + + return TRUE; +} + +#endif // WINVER >= 0x0500 + +// ----------------------------------------------------------------------- + +void SalTestMouseLeave() +{ + SalData* pSalData = GetSalData(); + + if ( pSalData->mhWantLeaveMsg && !::GetCapture() ) + { + POINT aPt; + GetCursorPos( &aPt ); + if ( pSalData->mhWantLeaveMsg != WindowFromPoint( aPt ) ) + ImplSendMessage( pSalData->mhWantLeaveMsg, SAL_MSG_MOUSELEAVE, 0, MAKELPARAM( aPt.x, aPt.y ) ); + } +} + +// ----------------------------------------------------------------------- + +static int ImplSalWheelMousePos( HWND hWnd, UINT nMsg, WPARAM wParam, LPARAM lParam , + LRESULT& rResult ) +{ + POINT aPt; + POINT aScreenPt; + aScreenPt.x = (short)LOWORD( lParam ); + aScreenPt.y = (short)HIWORD( lParam ); + // Child-Fenster suchen, welches an der entsprechenden + // Position liegt + HWND hChildWnd; + HWND hWheelWnd = hWnd; + do + { + hChildWnd = hWheelWnd; + aPt = aScreenPt; + ScreenToClient( hChildWnd, &aPt ); + hWheelWnd = ChildWindowFromPointEx( hChildWnd, aPt, CWP_SKIPINVISIBLE | CWP_SKIPTRANSPARENT ); + } + while ( hWheelWnd && (hWheelWnd != hChildWnd) ); + if ( hWheelWnd && (hWheelWnd != hWnd) && + (hWheelWnd != ::GetFocus()) && IsWindowEnabled( hWheelWnd ) ) + { + rResult = ImplSendMessage( hWheelWnd, nMsg, wParam, lParam ); + return FALSE; + } + + return TRUE; +} + +// ----------------------------------------------------------------------- + +LRESULT CALLBACK SalFrameWndProc( HWND hWnd, UINT nMsg, WPARAM wParam, LPARAM lParam, int& rDef ) +{ + LRESULT nRet = 0; + static int bInWheelMsg = FALSE; + static int bInQueryEnd = FALSE; + + // By WM_CRETAE we connect the frame with the window handle + if ( nMsg == WM_CREATE ) + { + // Window-Instanz am Windowhandle speichern + // Can also be used for the W-Version, because the struct + // to access lpCreateParams is the same structure + CREATESTRUCTA* pStruct = (CREATESTRUCTA*)lParam; + WinSalFrame* pFrame = (WinSalFrame*)pStruct->lpCreateParams; + if ( pFrame != 0 ) + { + SetWindowPtr( hWnd, pFrame ); + // HWND schon hier setzen, da schon auf den Instanzdaten + // gearbeitet werden kann, wenn Messages waehrend + // CreateWindow() gesendet werden + pFrame->mhWnd = hWnd; + pFrame->maSysData.hWnd = hWnd; + } + return 0; + } + + ImplSVData* pSVData = ImplGetSVData(); + // #i72707# TODO: the mbDeInit check will not be needed + // once all windows that are not properly closed on exit got fixed + if( pSVData->mbDeInit ) + return 0; + + if ( WM_USER_SYSTEM_WINDOW_ACTIVATED == nMsg ) + { + if (pSVData->mpIntroWindow) + pSVData->mpIntroWindow->Hide(); + + return 0; + } + + bool bCheckTimers = false; + + switch( nMsg ) + { + case WM_MOUSEMOVE: + case WM_LBUTTONDOWN: + case WM_MBUTTONDOWN: + case WM_RBUTTONDOWN: + case WM_LBUTTONUP: + case WM_MBUTTONUP: + case WM_RBUTTONUP: + case WM_NCMOUSEMOVE: + case SAL_MSG_MOUSELEAVE: + ImplSalYieldMutexAcquireWithWait(); + rDef = !ImplHandleMouseMsg( hWnd, nMsg, wParam, lParam ); + ImplSalYieldMutexRelease(); + break; + + case WM_NCLBUTTONDOWN: + case WM_NCMBUTTONDOWN: + case WM_NCRBUTTONDOWN: + ImplSalYieldMutexAcquireWithWait(); + ImplCallClosePopupsHdl( hWnd ); // close popups... + ImplSalYieldMutexRelease(); + break; + + case WM_MOUSEACTIVATE: + if ( LOWORD( lParam ) == HTCLIENT ) + { + ImplSalYieldMutexAcquireWithWait(); + nRet = ImplHandleMouseActivateMsg( hWnd ); + ImplSalYieldMutexRelease(); + if ( nRet ) + { + nRet = MA_NOACTIVATE; + rDef = FALSE; + } + } + break; + + case WM_KEYDOWN: + case WM_KEYUP: + case WM_DEADCHAR: + case WM_CHAR: + case WM_UNICHAR: // MCD, 2003-01-13, Support for WM_UNICHAR & Keyman 6.0 + case WM_SYSKEYDOWN: + case WM_SYSKEYUP: + case WM_SYSCHAR: + ImplSalYieldMutexAcquireWithWait(); + rDef = !ImplHandleKeyMsg( hWnd, nMsg, wParam, lParam, nRet ); + ImplSalYieldMutexRelease(); + break; + + case WM_MOUSEWHEEL: + // FALLTHROUGH intended + case WM_MOUSEHWHEEL: + // Gegen Rekursion absichern, falls wir vom IE oder dem externen + // Fenster die Message wieder zurueckbekommen + if ( !bInWheelMsg ) + { + bInWheelMsg++; + rDef = !ImplHandleWheelMsg( hWnd, nMsg, wParam, lParam ); + // Wenn wir die Message nicht ausgewertet haben, schauen wir + // noch einmal nach, ob dort ein geplugtes Fenster steht, + // welches wir dann benachrichtigen + if ( rDef ) + rDef = ImplSalWheelMousePos( hWnd, nMsg, wParam, lParam, nRet ); + bInWheelMsg--; + } + break; + + case WM_COMMAND: + ImplSalYieldMutexAcquireWithWait(); + rDef = !ImplHandleCommand( hWnd, wParam, lParam ); + ImplSalYieldMutexRelease(); + break; + + case WM_INITMENUPOPUP: + ImplSalYieldMutexAcquireWithWait(); + rDef = !ImplHandleMenuActivate( hWnd, wParam, lParam ); + ImplSalYieldMutexRelease(); + break; + + case WM_MENUSELECT: + ImplSalYieldMutexAcquireWithWait(); + rDef = !ImplHandleMenuSelect( hWnd, wParam, lParam ); + ImplSalYieldMutexRelease(); + break; + + case WM_SYSCOMMAND: + ImplSalYieldMutexAcquireWithWait(); + nRet = ImplHandleSysCommand( hWnd, wParam, lParam ); + ImplSalYieldMutexRelease(); + if ( nRet ) + rDef = FALSE; + break; + + case WM_MENUCHAR: + nRet = ImplMenuChar( hWnd, wParam, lParam ); + if( nRet ) + rDef = FALSE; + break; + + case WM_MEASUREITEM: + nRet = ImplMeasureItem(hWnd, wParam, lParam); + if( nRet ) + rDef = FALSE; + break; + + case WM_DRAWITEM: + nRet = ImplDrawItem(hWnd, wParam, lParam); + if( nRet ) + rDef = FALSE; + break; + + case WM_MOVE: + case SAL_MSG_POSTMOVE: + ImplHandleMoveMsg( hWnd ); + rDef = FALSE; + break; + case WM_SIZE: + ImplHandleSizeMsg( hWnd, wParam, lParam ); + rDef = FALSE; + break; + case SAL_MSG_POSTCALLSIZE: + ImplCallSizeHdl( hWnd ); + rDef = FALSE; + break; + + case WM_GETMINMAXINFO: + if ( ImplHandleMinMax( hWnd, lParam ) ) + rDef = FALSE; + break; + + case WM_ERASEBKGND: + nRet = 1; + rDef = FALSE; + break; + case WM_PAINT: + bCheckTimers = ImplHandlePaintMsg( hWnd ); + rDef = FALSE; + break; + case SAL_MSG_POSTPAINT: + ImplHandlePaintMsg2( hWnd, (RECT*)wParam ); + bCheckTimers = true; + rDef = FALSE; + break; + + case SAL_MSG_FORCEPALETTE: + ImplHandleForcePalette( hWnd ); + rDef = FALSE; + break; + + case WM_QUERYNEWPALETTE: + case SAL_MSG_POSTQUERYNEWPAL: + nRet = ImplHandlePalette( TRUE, hWnd, nMsg, wParam, lParam, rDef ); + break; + + case WM_ACTIVATE: + // Wenn wir aktiviert werden, dann wollen wir auch unsere + // Palette setzen. Wir machen dieses in Activate, + // damit andere externe Child-Fenster auch unsere Palette + // ueberschreiben koennen. So wird unsere jedenfalls nur einmal + // gesetzt und nicht immer rekursiv, da an allen anderen Stellen + // diese nur als Background-Palette gesetzt wird + if ( LOWORD( wParam ) != WA_INACTIVE ) + ImplSendMessage( hWnd, SAL_MSG_FORCEPALETTE, 0, 0 ); + break; + + case WM_ENABLE: + // #95133# a system dialog is opened/closed, using our app window as parent + { + WinSalFrame* pFrame = GetWindowPtr( hWnd ); + Window *pWin = NULL; + if( pFrame ) + pWin = pFrame->GetWindow(); + + if( !wParam ) + { + ImplSVData* pSVData = ImplGetSVData(); + pSVData->maAppData.mnModalMode++; + + // #106431#, hide SplashScreen + if( pSVData->mpIntroWindow ) + pSVData->mpIntroWindow->Hide(); + + if( pWin ) + { + pWin->EnableInput( FALSE, TRUE, TRUE, NULL ); + pWin->ImplIncModalCount(); // #106303# support frame based modal count + } + } + else + { + ImplGetSVData()->maAppData.mnModalMode--; + if( pWin ) + { + pWin->EnableInput( TRUE, TRUE, TRUE, NULL ); + pWin->ImplDecModalCount(); // #106303# support frame based modal count + } + } + } + break; + + case WM_KILLFOCUS: + DestroyCaret(); + case WM_SETFOCUS: + case SAL_MSG_POSTFOCUS: + ImplHandleFocusMsg( hWnd ); + rDef = FALSE; + break; + + case WM_CLOSE: + ImplHandleCloseMsg( hWnd ); + rDef = FALSE; + break; + + case WM_QUERYENDSESSION: + if( !bInQueryEnd ) + { + // handle queryendsession only once + bInQueryEnd = TRUE; + nRet = !ImplHandleShutDownMsg( hWnd ); + rDef = FALSE; + + // Issue #16314#: ImplHandleShutDownMsg causes a PostMessage in case of allowing shutdown. + // This posted message was never processed and cause Windows XP to hang after log off + // if there are multiple sessions and the current session wasn't the first one started. + // So if shutdown is allowed we assume that a post message was done and retrieve all + // messages in the message queue and dispatch them before we return control to the system. + + if ( nRet ) + { + MSG msg; + + while( PeekMessage( &msg, NULL, 0, 0, PM_REMOVE ) ) + { + DispatchMessage( &msg ); + } + } + } + else + { + ImplSalYieldMutexAcquireWithWait(); + ImplSalYieldMutexRelease(); + rDef = TRUE; + } + break; + + case WM_ENDSESSION: + if( !wParam ) + bInQueryEnd = FALSE; // no shutdown: allow query again + nRet = FALSE; + rDef = FALSE; + break; + + case WM_DISPLAYCHANGE: + case WM_SETTINGCHANGE: + case WM_DEVMODECHANGE: + case WM_FONTCHANGE: + case WM_SYSCOLORCHANGE: + case WM_TIMECHANGE: + ImplHandleSettingsChangeMsg( hWnd, nMsg, wParam, lParam ); + break; + + case WM_THEMECHANGED: + GetSalData()->mbThemeChanged = TRUE; + break; + + case SAL_MSG_USEREVENT: + ImplHandleUserEvent( hWnd, lParam ); + rDef = FALSE; + break; + + case SAL_MSG_CAPTUREMOUSE: + SetCapture( hWnd ); + rDef = FALSE; + break; + case SAL_MSG_RELEASEMOUSE: + if ( ::GetCapture() == hWnd ) + ReleaseCapture(); + rDef = FALSE; + break; + case SAL_MSG_TOTOP: + ImplSalToTop( hWnd, (USHORT)wParam ); + rDef = FALSE; + break; + case SAL_MSG_SHOW: + ImplSalShow( hWnd, (BOOL)wParam, (BOOL)lParam ); + rDef = FALSE; + break; + case SAL_MSG_SETINPUTCONTEXT: + ImplSalFrameSetInputContext( hWnd, (const SalInputContext*)(void*)lParam ); + rDef = FALSE; + break; + case SAL_MSG_ENDEXTTEXTINPUT: + ImplSalFrameEndExtTextInput( hWnd, (USHORT)(ULONG)(void*)wParam ); + rDef = FALSE; + break; + + case WM_INPUTLANGCHANGE: + ImplHandleInputLangChange( hWnd, wParam, lParam ); + break; + + case WM_IME_CHAR: + // #103487#, some IMEs (eg, those that do not work onspot) + // may send WM_IME_CHAR instead of WM_IME_COMPOSITION + // we just handle it like a WM_CHAR message - seems to work fine + ImplSalYieldMutexAcquireWithWait(); + rDef = !ImplHandleKeyMsg( hWnd, WM_CHAR, wParam, lParam, nRet ); + ImplSalYieldMutexRelease(); + break; + + case WM_IME_STARTCOMPOSITION: + rDef = ImplHandleIMEStartComposition( hWnd ); + break; + + case WM_IME_COMPOSITION: + rDef = ImplHandleIMEComposition( hWnd, lParam ); + break; + + case WM_IME_ENDCOMPOSITION: + rDef = ImplHandleIMEEndComposition( hWnd ); + break; + + case WM_IME_NOTIFY: + ImplHandleIMENotify( hWnd, wParam ); + break; + case WM_APPCOMMAND: + if( ImplHandleAppCommand( hWnd, lParam ) ) + { + rDef = false; + nRet = 1; + } + break; +#if WINVER >= 0x0500 + case WM_IME_REQUEST: + if ( PtrToInt( wParam ) == IMR_RECONVERTSTRING ) + { + nRet = ImplHandleIMEReconvertString( hWnd, lParam ); + rDef = FALSE; + } + else if( PtrToInt( wParam ) == IMR_CONFIRMRECONVERTSTRING ) + { + nRet = ImplHandleIMEConfirmReconvertString( hWnd, lParam ); + rDef = FALSE; + } + break; +#endif // WINVER >= 0x0500 + } + + // WheelMouse-Message abfangen + if ( rDef && (nMsg == aSalShlData.mnWheelMsgId) && aSalShlData.mnWheelMsgId ) + { + // Gegen Rekursion absichern, falls wir vom IE oder dem externen + // Fenster die Message wieder zurueckbekommen + if ( !bInWheelMsg ) + { + bInWheelMsg++; + // Zuerst wollen wir die Message dispatchen und dann darf auch + // das SystemWindow drankommen + WORD nKeyState = 0; + if ( GetKeyState( VK_SHIFT ) & 0x8000 ) + nKeyState |= MK_SHIFT; + if ( GetKeyState( VK_CONTROL ) & 0x8000 ) + nKeyState |= MK_CONTROL; + // Mutex handling is inside from this call + rDef = !ImplHandleWheelMsg( hWnd, + WM_MOUSEWHEEL, + MAKEWPARAM( nKeyState, (WORD)wParam ), + lParam ); + if ( rDef ) + { + HWND hWheelWnd = ::GetFocus(); + if ( hWheelWnd && (hWheelWnd != hWnd) ) + { + nRet = ImplSendMessage( hWheelWnd, nMsg, wParam, lParam ); + rDef = FALSE; + } + else + rDef = ImplSalWheelMousePos( hWnd, nMsg, wParam, lParam, nRet ); + } + bInWheelMsg--; + } + } + + if( bCheckTimers ) + { + SalData* pSalData = GetSalData(); + if( pSalData->mnNextTimerTime ) + { + DWORD nCurTime = GetTickCount(); + if( pSalData->mnNextTimerTime < nCurTime ) + { + MSG aMsg; + if( ! ImplPeekMessage( &aMsg, 0, WM_PAINT, WM_PAINT, PM_NOREMOVE | PM_NOYIELD ) ) + ImplPostMessage( pSalData->mpFirstInstance->mhComWnd, SAL_MSG_POSTTIMER, 0, nCurTime ); + } + } + } + + return nRet; +} + +LRESULT CALLBACK SalFrameWndProcA( HWND hWnd, UINT nMsg, WPARAM wParam, LPARAM lParam ) +{ + int bDef = TRUE; + LRESULT nRet = 0; +#ifdef __MINGW32__ + jmp_buf jmpbuf; + __SEHandler han; + if (__builtin_setjmp(jmpbuf) == 0) + { + han.Set(jmpbuf, NULL, (__SEHandler::PF)EXCEPTION_EXECUTE_HANDLER); +#else + __try + { +#endif + nRet = SalFrameWndProc( hWnd, nMsg, wParam, lParam, bDef ); + } +#ifdef __MINGW32__ + han.Reset(); +#else + __except(WinSalInstance::WorkaroundExceptionHandlingInUSER32Lib(GetExceptionCode(), GetExceptionInformation())) + { + } +#endif + if ( bDef ) + nRet = DefWindowProcA( hWnd, nMsg, wParam, lParam ); + return nRet; +} + +LRESULT CALLBACK SalFrameWndProcW( HWND hWnd, UINT nMsg, WPARAM wParam, LPARAM lParam ) +{ + int bDef = TRUE; + LRESULT nRet = 0; +#ifdef __MINGW32__ + jmp_buf jmpbuf; + __SEHandler han; + if (__builtin_setjmp(jmpbuf) == 0) + { + han.Set(jmpbuf, NULL, (__SEHandler::PF)EXCEPTION_EXECUTE_HANDLER); +#else + __try + { +#endif + nRet = SalFrameWndProc( hWnd, nMsg, wParam, lParam, bDef ); + } +#ifdef __MINGW32__ + han.Reset(); +#else + __except(WinSalInstance::WorkaroundExceptionHandlingInUSER32Lib(GetExceptionCode(), GetExceptionInformation())) + { + } +#endif + + if ( bDef ) + nRet = DefWindowProcW( hWnd, nMsg, wParam, lParam ); + return nRet; +} + +// ----------------------------------------------------------------------- + +BOOL ImplHandleGlobalMsg( HWND hWnd, UINT nMsg, WPARAM wParam, LPARAM lParam, LRESULT& rlResult ) +{ + // handle all messages concerning all frames so they get processed only once + // Must work for Unicode and none Unicode + BOOL bResult = FALSE; + if ( (nMsg == WM_PALETTECHANGED) || (nMsg == SAL_MSG_POSTPALCHANGED) ) + { + int bDef = TRUE; + rlResult = ImplHandlePalette( FALSE, hWnd, nMsg, wParam, lParam, bDef ); + bResult = (bDef != 0); + } + else if( nMsg == WM_DISPLAYCHANGE ) + { + WinSalSystem* pSys = static_cast<WinSalSystem*>(ImplGetSalSystem()); + if( pSys ) + pSys->clearMonitors(); + bResult = (pSys != NULL); + } + return bResult; +} + +// ----------------------------------------------------------------------- + +BOOL ImplWriteLastError( DWORD lastError, const char *szApiCall ) +{ + static int first=1; + // if VCL_LOGFILE_ENABLED is set, Win32 API error messages can be written + // to %TMP%/vcl.log or %TEMP%/vcl.log + static char *logEnabled = getenv("VCL_LOGFILE_ENABLED"); + if( logEnabled ) + { + BOOL bSuccess = FALSE; + static char *szTmp = getenv("TMP"); + if( !szTmp || !*szTmp ) + szTmp = getenv("TEMP"); + if( szTmp && *szTmp ) + { + char fname[5000]; + strcpy( fname, szTmp ); + if( fname[strlen(fname) - 1] != '\\' ) + strcat( fname, "\\"); + strcat( fname, "vcl.log" ); + FILE *fp = fopen( fname, "a" ); // always append + if( fp ) + { + if( first ) + { + first = 0; + fprintf( fp, "Process ID: %d (0x%x)\n", GetCurrentProcessId(), GetCurrentProcessId() ); + } + time_t aclock; + time( &aclock ); // Get time in seconds + struct tm *newtime = localtime( &aclock ); // Convert time to struct tm form + fprintf( fp, asctime( newtime ) ); // print time stamp + + fprintf( fp, "%s returned %u (0x%x)\n", szApiCall, lastError, lastError ); + bSuccess = TRUE; // may be FormatMessage fails but we wrote at least the error code + + LPVOID lpMsgBuf; + if (FormatMessageA( + FORMAT_MESSAGE_ALLOCATE_BUFFER | + FORMAT_MESSAGE_FROM_SYSTEM | + FORMAT_MESSAGE_IGNORE_INSERTS, + NULL, + lastError, + MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), // Default language + (LPSTR) &lpMsgBuf, + 0, + NULL )) + { + fprintf( fp, " %s\n", (LPSTR)lpMsgBuf ); + LocalFree( lpMsgBuf ); + } + + fclose( fp ); + } + } + return bSuccess; + } + else + return TRUE; +} + +// ----------------------------------------------------------------------- + diff --git a/vcl/win/source/window/salmenu.cxx b/vcl/win/source/window/salmenu.cxx new file mode 100644 index 000000000000..d3602aeabf0e --- /dev/null +++ b/vcl/win/source/window/salmenu.cxx @@ -0,0 +1,413 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2008 by Sun Microsystems, Inc. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * $RCSfile: salmenu.cxx,v $ + * $Revision: 1.14 $ + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org 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 version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_vcl.hxx" +#include <tools/svwin.h> +#include <wincomp.hxx> +#include <saldata.hxx> +#include <salinst.h> +#include <vcl/salgdi.hxx> +#include <salmenu.h> +#include <vcl/menu.hxx> +#include <vcl/sysdata.hxx> +#include <salframe.h> +#include <vcl/impbmp.hxx> + +// uncomment the following line to have ownerdrawn menues, ie, with bitmaps +// however, this is incompatible with OLE inplace editing +// so it is not activated by default +//#define OWNERDRAW + +static DWORD myerr=0; + +// ======================================================================= + +BOOL SalData::IsKnownMenuHandle( HMENU hMenu ) +{ + if( mhMenuSet.find( hMenu ) == mhMenuSet.end() ) + return FALSE; + else + return TRUE; +} + +// ======================================================================= + +// WinSalInst factory methods + +SalMenu* WinSalInstance::CreateMenu( BOOL bMenuBar ) +{ + WinSalMenu *pSalMenu = new WinSalMenu(); + + pSalMenu->mbMenuBar = bMenuBar; + pSalMenu->mhWnd = NULL; + if( bMenuBar ) + pSalMenu->mhMenu = ::CreateMenu(); + else + pSalMenu->mhMenu = ::CreatePopupMenu(); + + if( pSalMenu->mhMenu ) + GetSalData()->mhMenuSet.insert( pSalMenu->mhMenu ); + + return pSalMenu; +} + +void WinSalInstance::DestroyMenu( SalMenu* pSalMenu ) +{ + delete pSalMenu; +} + + +SalMenuItem* WinSalInstance::CreateMenuItem( const SalItemParams* pItemData ) +{ + if( !pItemData ) + return NULL; + + WinSalMenuItem *pSalMenuItem = new WinSalMenuItem(); + memset( &pSalMenuItem->mInfo, 0, sizeof( MENUITEMINFOW ) ); + pSalMenuItem->mInfo.cbSize = sizeof( MENUITEMINFOW ); + + if( pItemData->eType == MENUITEM_SEPARATOR ) + { + // separator + pSalMenuItem->mInfo.fMask = MIIM_TYPE; + pSalMenuItem->mInfo.fType = MFT_SEPARATOR; + } + else + { + // item + pSalMenuItem->mText = pItemData->aText; + pSalMenuItem->mpMenu = pItemData->pMenu; + pSalMenuItem->maBitmap= !!pItemData->aImage ? pItemData->aImage.GetBitmapEx().GetBitmap() : Bitmap(); + pSalMenuItem->mnId = pItemData->nId; + + // 'translate' mnemonics + pSalMenuItem->mText.SearchAndReplace( '~', '&' ); + + pSalMenuItem->mInfo.fMask = MIIM_TYPE | MIIM_STATE | MIIM_ID | MIIM_DATA; + pSalMenuItem->mInfo.fType = MFT_STRING; +#ifdef OWNERDRAW + if( pItemData->pMenu && !pItemData->pMenu->IsMenuBar() ) + pSalMenuItem->mInfo.fType |= MFT_OWNERDRAW; + pSalMenuItem->mInfo.fState = MFS_ENABLED; +#endif + pSalMenuItem->mInfo.dwTypeData = (LPWSTR) pSalMenuItem->mText.GetBuffer(); + pSalMenuItem->mInfo.cch = pSalMenuItem->mText.Len(); + + pSalMenuItem->mInfo.wID = pItemData->nId; + pSalMenuItem->mInfo.dwItemData = (ULONG_PTR) pSalMenuItem; // user data + } + + return pSalMenuItem; +} + +void WinSalInstance::DestroyMenuItem( SalMenuItem* pSalMenuItem ) +{ + delete pSalMenuItem; +} + + +// ======================================================================= + +static void ImplDrawMenuBar( SalMenu *pMenu ) +{ + if( pMenu->VisibleMenuBar() ) + { + // redrawing the menubar all the time actually seems to be unnecessary (it just flickers) + /* + WinSalMenu *pMenuBar = ImplFindMenuBar( pMenu ); + if( pMenuBar && pMenuBar->mhWnd ) + ::DrawMenuBar( pMenuBar->mhWnd ); + */ + } +} + +// ======================================================================= + + +/* + * WinSalMenu + */ + +WinSalMenu::WinSalMenu() +{ + mhMenu = NULL; + mbMenuBar = FALSE; + mhWnd = NULL; + mpParentMenu = NULL; +} + +WinSalMenu::~WinSalMenu() +{ + // only required if not associated to a window... + GetSalData()->mhMenuSet.erase( mhMenu ); + ::DestroyMenu( mhMenu ); +} + +BOOL WinSalMenu::VisibleMenuBar() +{ + // The Win32 implementation never shows a native + // menubar. Thus, native menues are only visible + // when the menu is merged with an OLE container. + // The reason are missing tooltips, ownerdraw + // issues and accessibility which are better supported + // by VCL menues. + // Nevertheless, the native menues are always created + // and the application will properly react to all native + // menu messages. + + return FALSE; +} + +void WinSalMenu::SetFrame( const SalFrame *pFrame ) +{ + if( pFrame ) + mhWnd = static_cast<const WinSalFrame*>(pFrame)->mhWnd; + else + mhWnd = NULL; +} + +void WinSalMenu::InsertItem( SalMenuItem* pSalMenuItem, unsigned nPos ) +{ + if( pSalMenuItem ) + { + WinSalMenuItem* pWItem = static_cast<WinSalMenuItem*>(pSalMenuItem); + if( nPos == MENU_APPEND ) + { + nPos = ::GetMenuItemCount( mhMenu ); + if( nPos == -1 ) + return; + } + + if(!::InsertMenuItemW( mhMenu, nPos, TRUE, &pWItem->mInfo )) + myerr = GetLastError(); + else + { + pWItem->mpSalMenu = this; + ImplDrawMenuBar( this ); + } + } +} + +void WinSalMenu::RemoveItem( unsigned nPos ) +{ + int num = ::GetMenuItemCount( mhMenu ); + if( num != -1 && nPos < (unsigned)num ) + { + WinSalMenuItem *pSalMenuItem = NULL; + + MENUITEMINFOW mi; + memset( &mi, 0, sizeof(mi) ); + mi.cbSize = sizeof( mi ); + mi.fMask = MIIM_DATA; + if( !GetMenuItemInfoW( mhMenu, nPos, TRUE, &mi) ) + myerr = GetLastError(); + else + pSalMenuItem = (WinSalMenuItem *) mi.dwItemData; + + if( !::RemoveMenu( mhMenu, nPos, MF_BYPOSITION ) ) + myerr = GetLastError(); + else + { + if( pSalMenuItem ) + pSalMenuItem->mpSalMenu = NULL; + ImplDrawMenuBar( this ); + } + } +} + +void ImplRemoveItemById( WinSalMenu *pSalMenu, unsigned nItemId ) +{ + if( !pSalMenu ) + return; + + WinSalMenuItem *pSalMenuItem = NULL; + + MENUITEMINFOW mi; + memset( &mi, 0, sizeof(mi) ); + mi.cbSize = sizeof( mi ); + mi.fMask = MIIM_DATA; + if( !GetMenuItemInfoW( pSalMenu->mhMenu, nItemId, FALSE, &mi) ) + myerr = GetLastError(); + else + pSalMenuItem = (WinSalMenuItem *) mi.dwItemData; + + if( !::RemoveMenu( pSalMenu->mhMenu, nItemId, MF_BYCOMMAND ) ) + myerr = GetLastError(); + else + { + if( pSalMenuItem ) + pSalMenuItem->mpSalMenu = NULL; + ImplDrawMenuBar( pSalMenu ); + } +} + +void WinSalMenu::SetSubMenu( SalMenuItem* pSalMenuItem, SalMenu* pSubMenu, unsigned nPos ) +{ + if( pSalMenuItem ) + { + WinSalMenuItem* pWMenuItem = static_cast<WinSalMenuItem*>(pSalMenuItem); + WinSalMenu* pWSubMenu = static_cast<WinSalMenu*>(pSubMenu); + if( pWMenuItem->mInfo.hSubMenu ) + { + GetSalData()->mhMenuSet.erase( pWMenuItem->mInfo.hSubMenu ); + ::DestroyMenu( pWMenuItem->mInfo.hSubMenu ); + } + + pWMenuItem->mInfo.fMask |= MIIM_SUBMENU; + if( !pSubMenu ) + pWMenuItem->mInfo.hSubMenu = NULL; + else + { + pWMenuItem->mInfo.hSubMenu = pWSubMenu->mhMenu; + pWSubMenu->mpParentMenu = this; + } + + if(!::SetMenuItemInfoW( mhMenu, nPos, TRUE, &pWMenuItem->mInfo ) ) + myerr = GetLastError(); + else + ImplDrawMenuBar( this ); + } +} + +void WinSalMenu::CheckItem( unsigned nPos, BOOL bCheck ) +{ + if( -1 != ::CheckMenuItem( mhMenu, nPos, MF_BYPOSITION|(bCheck ? MF_CHECKED : MF_UNCHECKED) ) ) + ImplDrawMenuBar( this ); +} + +void WinSalMenu::EnableItem( unsigned nPos, BOOL bEnable ) +{ + if( -1 != ::EnableMenuItem( mhMenu, nPos, MF_BYPOSITION|(bEnable ? MF_ENABLED : (MF_DISABLED|MF_GRAYED) ) ) ) + ImplDrawMenuBar( this ); +} + +void WinSalMenu::SetItemImage( unsigned /*nPos*/, SalMenuItem* pSalMenuItem, const Image& rImage ) +{ + if( pSalMenuItem ) + { + WinSalMenuItem* pWItem = static_cast<WinSalMenuItem*>(pSalMenuItem); + if( !!rImage ) + pWItem->maBitmap = rImage.GetBitmapEx().GetBitmap(); + else + pWItem->maBitmap = Bitmap(); + } +} + +void WinSalMenu::SetItemText( unsigned nPos, SalMenuItem* pSalMenuItem, const XubString& rText ) +{ + if( pSalMenuItem ) + { + WinSalMenuItem* pWItem = static_cast<WinSalMenuItem*>(pSalMenuItem); + pWItem->mText = rText; + // 'translate' mnemonics + pWItem->mText.SearchAndReplace( '~', '&' ); + pWItem->mInfo.fMask = MIIM_TYPE | MIIM_DATA; + pWItem->mInfo.fType = MFT_STRING; +#ifdef OWNERDRAW + if( pWItem->mpMenu && !((Menu*) pWItem->mpMenu)->IsMenuBar() ) + pWItem->mInfo.fType |= MFT_OWNERDRAW; +#endif + + // combine text and accelerator text + XubString aStr( pWItem->mText ); + if( pWItem->mAccelText.Len() ) + { + aStr.AppendAscii("\t"); + aStr.Append( pWItem->mAccelText ); + } + pWItem->mInfo.dwTypeData = (LPWSTR) aStr.GetBuffer(); + pWItem->mInfo.cch = aStr.Len(); + + if(!::SetMenuItemInfoW( mhMenu, nPos, TRUE, &pWItem->mInfo )) + myerr = GetLastError(); + else + ImplDrawMenuBar( this ); + } +} + +void WinSalMenu::SetAccelerator( unsigned nPos, SalMenuItem* pSalMenuItem, const KeyCode&, const XubString& rKeyName ) +{ + if( pSalMenuItem ) + { + WinSalMenuItem* pWItem = static_cast<WinSalMenuItem*>(pSalMenuItem); + pWItem->mAccelText = rKeyName; + pWItem->mInfo.fMask = MIIM_TYPE | MIIM_DATA; + pWItem->mInfo.fType = MFT_STRING; +#ifdef OWNERDRAW + if( pWItem->mpMenu && !((Menu*)pWItem->mpMenu)->IsMenuBar() ) + pWItem->mInfo.fType |= MFT_OWNERDRAW; +#endif + // combine text and accelerator text + XubString aStr( pWItem->mText ); + if( pWItem->mAccelText.Len() ) + { + aStr.AppendAscii("\t"); + aStr.Append( pWItem->mAccelText ); + } + pWItem->mInfo.dwTypeData = (LPWSTR) aStr.GetBuffer(); + pWItem->mInfo.cch = aStr.Len(); + + if(!::SetMenuItemInfoW( mhMenu, nPos, TRUE, &pWItem->mInfo )) + myerr = GetLastError(); + else + ImplDrawMenuBar( this ); + } +} + +void WinSalMenu::GetSystemMenuData( SystemMenuData* pData ) +{ + if( pData ) + pData->hMenu = mhMenu; +} + +// ======================================================================= + +/* + * SalMenuItem + */ + + +WinSalMenuItem::WinSalMenuItem() +{ + memset( &mInfo, 0, sizeof( MENUITEMINFOW ) ); + mpMenu = NULL; + mnId = 0xFFFF; + mpSalMenu = NULL; +} + +WinSalMenuItem::~WinSalMenuItem() +{ + if( mpSalMenu ) + ImplRemoveItemById( mpSalMenu, mnId ); +} + +// ------------------------------------------------------------------- + diff --git a/vcl/win/source/window/salobj.cxx b/vcl/win/source/window/salobj.cxx new file mode 100644 index 000000000000..f0bdfc266b0c --- /dev/null +++ b/vcl/win/source/window/salobj.cxx @@ -0,0 +1,841 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2008 by Sun Microsystems, Inc. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * $RCSfile: salobj.cxx,v $ + * $Revision: 1.11 $ + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org 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 version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_vcl.hxx" + +#include <string.h> + +#ifndef _SVWIN_HXX +#include <tools/svwin.h> +#endif +#include <wincomp.hxx> +#include <saldata.hxx> +#include <salinst.h> +#include <salframe.h> +#include <salobj.h> +#include <tools/debug.hxx> + +// ======================================================================= + +static BOOL ImplIsSysWindowOrChild( HWND hWndParent, HWND hWndChild ) +{ + if ( hWndParent == hWndChild ) + return TRUE; + + HWND hTempWnd = ::GetParent( hWndChild ); + while ( hTempWnd ) + { + // Ab nicht Child-Fenstern hoeren wir auf zu suchen + if ( !(GetWindowStyle( hTempWnd ) & WS_CHILD) ) + return FALSE; + if ( hTempWnd == hWndParent ) + return TRUE; + hTempWnd = ::GetParent( hTempWnd ); + } + + return FALSE; +} + +// ----------------------------------------------------------------------- + +WinSalObject* ImplFindSalObject( HWND hWndChild ) +{ + SalData* pSalData = GetSalData(); + WinSalObject* pObject = pSalData->mpFirstObject; + while ( pObject ) + { + if ( ImplIsSysWindowOrChild( pObject->mhWndChild, hWndChild ) ) + return pObject; + + pObject = pObject->mpNextObject; + } + + return NULL; +} + +// ----------------------------------------------------------------------- + +WinSalFrame* ImplFindSalObjectFrame( HWND hWnd ) +{ + WinSalFrame* pFrame = NULL; + WinSalObject* pObject = ImplFindSalObject( hWnd ); + if ( pObject ) + { + // Dazugehoerenden Frame suchen + HWND hWnd = ::GetParent( pObject->mhWnd ); + pFrame = GetSalData()->mpFirstFrame; + while ( pFrame ) + { + if ( pFrame->mhWnd == hWnd ) + break; + + pFrame = pFrame->mpNextFrame; + } + } + + return pFrame; +} + +// ----------------------------------------------------------------------- + +LRESULT CALLBACK SalSysMsgProc( int nCode, WPARAM wParam, LPARAM lParam ) +{ + // Used for Unicode and none Unicode + SalData* pSalData = GetSalData(); + + if ( (nCode >= 0) && lParam ) + { + CWPSTRUCT* pData = (CWPSTRUCT*)lParam; + if ( (pData->message != WM_KEYDOWN) && + (pData->message != WM_KEYUP) ) + pSalData->mnSalObjWantKeyEvt = 0; + + // Testen, ob wir Daten fuer ein SalObject-Fenster behandeln + // muessen + WinSalObject* pObject; + if ( pData->message == WM_SETFOCUS ) + { + pObject = ImplFindSalObject( pData->hwnd ); + if ( pObject ) + { + pObject->mhLastFocusWnd = pData->hwnd; + if ( ImplSalYieldMutexTryToAcquire() ) + { + pObject->CallCallback( SALOBJ_EVENT_GETFOCUS, 0 ); + ImplSalYieldMutexRelease(); + } + else + ImplPostMessage( pObject->mhWnd, SALOBJ_MSG_POSTFOCUS, 0, 0 ); + } + } + else if ( pData->message == WM_KILLFOCUS ) + { + pObject = ImplFindSalObject( pData->hwnd ); + if ( pObject && !ImplFindSalObject( (HWND)pData->wParam ) ) + { + // LoseFocus nur rufen, wenn wirklich kein ChildFenster + // den Focus bekommt + if ( !pData->wParam || !ImplFindSalObject( (HWND)pData->wParam ) ) + { + if ( ImplSalYieldMutexTryToAcquire() ) + { + pObject->CallCallback( SALOBJ_EVENT_LOSEFOCUS, 0 ); + ImplSalYieldMutexRelease(); + } + else + ImplPostMessage( pObject->mhWnd, SALOBJ_MSG_POSTFOCUS, 0, 0 ); + } + else + pObject->mhLastFocusWnd = (HWND)pData->wParam; + } + } + } + + return CallNextHookEx( pSalData->mhSalObjMsgHook, nCode, wParam, lParam ); +} + +// ----------------------------------------------------------------------- + +BOOL ImplSalPreDispatchMsg( MSG* pMsg ) +{ + // Used for Unicode and none Unicode + SalData* pSalData = GetSalData(); + WinSalObject* pObject; + + if ( (pMsg->message == WM_LBUTTONDOWN) || + (pMsg->message == WM_RBUTTONDOWN) || + (pMsg->message == WM_MBUTTONDOWN) ) + { + ImplSalYieldMutexAcquireWithWait(); + pObject = ImplFindSalObject( pMsg->hwnd ); + if ( pObject && !pObject->IsMouseTransparent() ) + ImplPostMessage( pObject->mhWnd, SALOBJ_MSG_TOTOP, 0, 0 ); + ImplSalYieldMutexRelease(); + } + + if ( (pMsg->message == WM_KEYDOWN) || + (pMsg->message == WM_KEYUP) ) + { + // KeyEvents wollen wir nach Moeglichkeit auch abarbeiten, + // wenn das Control diese nicht selber auswertet + // SysKeys werden als WM_SYSCOMMAND verarbeitet + // Char-Events verarbeiten wir nicht, da wir nur + // Accelerator relevante Keys verarbeiten wollen + BOOL bWantedKeyCode = FALSE; + // A-Z, 0-9 nur in Verbindung mit Control-Taste + if ( ((pMsg->wParam >= 65) && (pMsg->wParam <= 90)) || + ((pMsg->wParam >= 48) && (pMsg->wParam <= 57)) ) + { + if ( GetKeyState( VK_CONTROL ) & 0x8000 ) + bWantedKeyCode = TRUE; + } + else if ( ((pMsg->wParam >= VK_F1) && (pMsg->wParam <= VK_F24)) || + ((pMsg->wParam >= VK_SPACE) && (pMsg->wParam <= VK_HELP)) || + (pMsg->wParam == VK_BACK) || (pMsg->wParam == VK_TAB) || + (pMsg->wParam == VK_CLEAR) || (pMsg->wParam == VK_RETURN) || + (pMsg->wParam == VK_ESCAPE) ) + bWantedKeyCode = TRUE; + if ( bWantedKeyCode ) + { + ImplSalYieldMutexAcquireWithWait(); + pObject = ImplFindSalObject( pMsg->hwnd ); + if ( pObject ) + pSalData->mnSalObjWantKeyEvt = pMsg->wParam; + ImplSalYieldMutexRelease(); + } + } + // Hier WM_SYSCHAR abfangen, um mit Alt+Taste evtl. Menu zu aktivieren + else if ( pMsg->message == WM_SYSCHAR ) + { + pSalData->mnSalObjWantKeyEvt = 0; + + USHORT nKeyCode = LOWORD( pMsg->wParam ); + // Nur 0-9 und A-Z + if ( ((nKeyCode >= 48) && (nKeyCode <= 57)) || + ((nKeyCode >= 65) && (nKeyCode <= 90)) || + ((nKeyCode >= 97) && (nKeyCode <= 122)) ) + { + BOOL bRet = FALSE; + ImplSalYieldMutexAcquireWithWait(); + pObject = ImplFindSalObject( pMsg->hwnd ); + if ( pObject ) + { + if ( pMsg->hwnd == ::GetFocus() ) + { + WinSalFrame* pFrame = ImplFindSalObjectFrame( pMsg->hwnd ); + if ( pFrame ) + { + if ( ImplHandleSalObjSysCharMsg( pFrame->mhWnd, pMsg->wParam, pMsg->lParam ) ) + bRet = TRUE; + } + } + } + ImplSalYieldMutexRelease(); + if ( bRet ) + return TRUE; + } + } + else + pSalData->mnSalObjWantKeyEvt = 0; + + return FALSE; +} + +// ----------------------------------------------------------------------- + +void ImplSalPostDispatchMsg( MSG* pMsg, LRESULT /* nDispatchResult */ ) +{ + // Used for Unicode and none Unicode + SalData* pSalData = GetSalData(); + WinSalFrame* pFrame; + + if ( (pMsg->message == WM_KEYDOWN) || (pMsg->message == WM_KEYUP) ) + { + if ( pSalData->mnSalObjWantKeyEvt == pMsg->wParam ) + { + pSalData->mnSalObjWantKeyEvt = 0; + if ( pMsg->hwnd == ::GetFocus() ) + { + ImplSalYieldMutexAcquireWithWait(); + pFrame = ImplFindSalObjectFrame( pMsg->hwnd ); + if ( pFrame ) + ImplHandleSalObjKeyMsg( pFrame->mhWnd, pMsg->message, pMsg->wParam, pMsg->lParam ); + ImplSalYieldMutexRelease(); + } + } + } + + pSalData->mnSalObjWantKeyEvt = 0; +} + +// ======================================================================= + +LRESULT CALLBACK SalSysObjWndProc( HWND hWnd, UINT nMsg, WPARAM wParam, LPARAM lParam, int& rDef ) +{ + WinSalObject* pSysObj; + LRESULT nRet = 0; + + switch( nMsg ) + { + case WM_ERASEBKGND: + nRet = 1; + rDef = FALSE; + break; + case WM_PAINT: + { + PAINTSTRUCT aPs; + BeginPaint( hWnd, &aPs ); + EndPaint( hWnd, &aPs ); + rDef = FALSE; + } + break; + + case WM_PARENTNOTIFY: + { + UINT nNotifyMsg = LOWORD( wParam ); + if ( (nNotifyMsg == WM_LBUTTONDOWN) || + (nNotifyMsg == WM_RBUTTONDOWN) || + (nNotifyMsg == WM_MBUTTONDOWN) ) + { + ImplSalYieldMutexAcquireWithWait(); + pSysObj = GetSalObjWindowPtr( hWnd ); + if ( pSysObj && !pSysObj->IsMouseTransparent() ) + pSysObj->CallCallback( SALOBJ_EVENT_TOTOP, 0 ); + ImplSalYieldMutexRelease(); + } + } + break; + + case WM_MOUSEACTIVATE: + { + ImplSalYieldMutexAcquireWithWait(); + pSysObj = GetSalObjWindowPtr( hWnd ); + if ( pSysObj && !pSysObj->IsMouseTransparent() ) + ImplPostMessage( hWnd, SALOBJ_MSG_TOTOP, 0, 0 ); + ImplSalYieldMutexRelease(); + } + break; + + case SALOBJ_MSG_TOTOP: + if ( ImplSalYieldMutexTryToAcquire() ) + { + pSysObj = GetSalObjWindowPtr( hWnd ); + pSysObj->CallCallback( SALOBJ_EVENT_TOTOP, 0 ); + ImplSalYieldMutexRelease(); + rDef = FALSE; + } + else + ImplPostMessage( hWnd, SALOBJ_MSG_TOTOP, 0, 0 ); + break; + + case SALOBJ_MSG_POSTFOCUS: + if ( ImplSalYieldMutexTryToAcquire() ) + { + pSysObj = GetSalObjWindowPtr( hWnd ); + HWND hFocusWnd = ::GetFocus(); + USHORT nEvent; + if ( hFocusWnd && ImplIsSysWindowOrChild( hWnd, hFocusWnd ) ) + nEvent = SALOBJ_EVENT_GETFOCUS; + else + nEvent = SALOBJ_EVENT_LOSEFOCUS; + pSysObj->CallCallback( nEvent, 0 ); + ImplSalYieldMutexRelease(); + } + else + ImplPostMessage( hWnd, SALOBJ_MSG_POSTFOCUS, 0, 0 ); + rDef = FALSE; + break; + + case WM_SIZE: + { + HWND hWndChild = GetWindow( hWnd, GW_CHILD ); + if ( hWndChild ) + { + SetWindowPos( hWndChild, + 0, 0, 0, (int)LOWORD( lParam ), (int)HIWORD( lParam ), + SWP_NOZORDER | SWP_NOACTIVATE ); + } + } + rDef = FALSE; + break; + + case WM_CREATE: + { + // Window-Instanz am Windowhandle speichern + // Can also be used for the W-Version, because the struct + // to access lpCreateParams is the same structure + CREATESTRUCTA* pStruct = (CREATESTRUCTA*)lParam; + pSysObj = (WinSalObject*)pStruct->lpCreateParams; + SetSalObjWindowPtr( hWnd, pSysObj ); + // HWND schon hier setzen, da schon auf den Instanzdaten + // gearbeitet werden kann, wenn Messages waehrend + // CreateWindow() gesendet werden + pSysObj->mhWnd = hWnd; + rDef = FALSE; + } + break; + } + + return nRet; +} + +LRESULT CALLBACK SalSysObjWndProcA( HWND hWnd, UINT nMsg, WPARAM wParam, LPARAM lParam ) +{ + int bDef = TRUE; + LRESULT nRet = SalSysObjWndProc( hWnd, nMsg, wParam, lParam, bDef ); + if ( bDef ) + nRet = DefWindowProcA( hWnd, nMsg, wParam, lParam ); + return nRet; +} + +LRESULT CALLBACK SalSysObjWndProcW( HWND hWnd, UINT nMsg, WPARAM wParam, LPARAM lParam ) +{ + int bDef = TRUE; + LRESULT nRet = SalSysObjWndProc( hWnd, nMsg, wParam, lParam, bDef ); + if ( bDef ) + nRet = DefWindowProcW( hWnd, nMsg, wParam, lParam ); + return nRet; +} + +// ----------------------------------------------------------------------- + +LRESULT CALLBACK SalSysObjChildWndProc( HWND hWnd, UINT nMsg, WPARAM wParam, LPARAM lParam, int& rDef ) +{ + LRESULT nRet = 0; + + switch( nMsg ) + { + // Wegen PlugIn's loeschen wir erstmal den Hintergrund + case WM_ERASEBKGND: + { + WinSalObject* pSysObj = GetSalObjWindowPtr( ::GetParent( hWnd ) ); + + if( pSysObj && !pSysObj->IsEraseBackgroundEnabled() ) + { + // do not erase background + nRet = 1; + rDef = FALSE; + } + } + break; + + case WM_PAINT: + { + PAINTSTRUCT aPs; + BeginPaint( hWnd, &aPs ); + EndPaint( hWnd, &aPs ); + rDef = FALSE; + } + break; + + case WM_MOUSEMOVE: + case WM_LBUTTONDOWN: + case WM_MBUTTONDOWN: + case WM_RBUTTONDOWN: + case WM_LBUTTONUP: + case WM_MBUTTONUP: + case WM_RBUTTONUP: + { + WinSalObject* pSysObj; + pSysObj = GetSalObjWindowPtr( ::GetParent( hWnd ) ); + + if( pSysObj && pSysObj->IsMouseTransparent() ) + { + // forward mouse events to parent frame + HWND hWndParent = ::GetParent( pSysObj->mhWnd ); + + // transform coordinates + POINT pt; + pt.x = (long) LOWORD( lParam ); + pt.y = (long) HIWORD( lParam ); + MapWindowPoints( hWnd, hWndParent, &pt, 1 ); + lParam = MAKELPARAM( (WORD) pt.x, (WORD) pt.y ); + + nRet = ImplSendMessage( hWndParent, nMsg, wParam, lParam ); + rDef = FALSE; + } + } + break; + } + + return nRet; +} + +LRESULT CALLBACK SalSysObjChildWndProcA( HWND hWnd, UINT nMsg, WPARAM wParam, LPARAM lParam ) +{ + int bDef = TRUE; + LRESULT nRet = SalSysObjChildWndProc( hWnd, nMsg, wParam, lParam, bDef ); + if ( bDef ) + nRet = DefWindowProcA( hWnd, nMsg, wParam, lParam ); + return nRet; +} + +LRESULT CALLBACK SalSysObjChildWndProcW( HWND hWnd, UINT nMsg, WPARAM wParam, LPARAM lParam ) +{ + int bDef = TRUE; + LRESULT nRet = SalSysObjChildWndProc( hWnd, nMsg, wParam, lParam, bDef ); + if ( bDef ) + nRet = DefWindowProcW( hWnd, nMsg, wParam, lParam ); + return nRet; +} + +// ======================================================================= + +SalObject* ImplSalCreateObject( WinSalInstance* pInst, WinSalFrame* pParent ) +{ + SalData* pSalData = GetSalData(); + + // Hook installieren, wenn es das erste SalObject ist + if ( !pSalData->mpFirstObject ) + { + if ( aSalShlData.mbWNT ) + { + pSalData->mhSalObjMsgHook = SetWindowsHookExW( WH_CALLWNDPROC, + SalSysMsgProc, + pSalData->mhInst, + pSalData->mnAppThreadId ); + } + else + { + pSalData->mhSalObjMsgHook = SetWindowsHookExA( WH_CALLWNDPROC, + SalSysMsgProc, + pSalData->mhInst, + pSalData->mnAppThreadId ); + } + } + + if ( !pSalData->mbObjClassInit ) + { + // #95301# shockwave plugin has bug; expects ASCII functions to be used + if ( false )//aSalShlData.mbWNT ) + { + WNDCLASSEXW aWndClassEx; + aWndClassEx.cbSize = sizeof( aWndClassEx ); + aWndClassEx.style = 0; + aWndClassEx.lpfnWndProc = SalSysObjWndProcW; + aWndClassEx.cbClsExtra = 0; + aWndClassEx.cbWndExtra = SAL_OBJECT_WNDEXTRA; + aWndClassEx.hInstance = pSalData->mhInst; + aWndClassEx.hIcon = 0; + aWndClassEx.hIconSm = 0; + aWndClassEx.hCursor = LoadCursor( 0, IDC_ARROW ); + aWndClassEx.hbrBackground = 0; + aWndClassEx.lpszMenuName = 0; + aWndClassEx.lpszClassName = SAL_OBJECT_CLASSNAMEW; + if ( RegisterClassExW( &aWndClassEx ) ) + { + // Wegen PlugIn's loeschen wir erstmal den Hintergrund + aWndClassEx.cbWndExtra = 0; + aWndClassEx.hbrBackground = (HBRUSH)(COLOR_WINDOW+1); + aWndClassEx.lpfnWndProc = SalSysObjChildWndProcW; + aWndClassEx.lpszClassName = SAL_OBJECT_CHILDCLASSNAMEW; + if ( RegisterClassExW( &aWndClassEx ) ) + pSalData->mbObjClassInit = TRUE; + } + } + else + { + WNDCLASSEXA aWndClassEx; + aWndClassEx.cbSize = sizeof( aWndClassEx ); + aWndClassEx.style = 0; + aWndClassEx.lpfnWndProc = SalSysObjWndProcA; + aWndClassEx.cbClsExtra = 0; + aWndClassEx.cbWndExtra = SAL_OBJECT_WNDEXTRA; + aWndClassEx.hInstance = pSalData->mhInst; + aWndClassEx.hIcon = 0; + aWndClassEx.hIconSm = 0; + aWndClassEx.hCursor = LoadCursor( 0, IDC_ARROW ); + aWndClassEx.hbrBackground = 0; + aWndClassEx.lpszMenuName = 0; + aWndClassEx.lpszClassName = SAL_OBJECT_CLASSNAMEA; + if ( RegisterClassExA( &aWndClassEx ) ) + { + // Wegen PlugIn's loeschen wir erstmal den Hintergrund + aWndClassEx.cbWndExtra = 0; + aWndClassEx.hbrBackground = (HBRUSH)(COLOR_WINDOW+1); + aWndClassEx.lpfnWndProc = SalSysObjChildWndProcA; + aWndClassEx.lpszClassName = SAL_OBJECT_CHILDCLASSNAMEA; + if ( RegisterClassExA( &aWndClassEx ) ) + pSalData->mbObjClassInit = TRUE; + } + } + } + + if ( pSalData->mbObjClassInit ) + { + WinSalObject* pObject = new WinSalObject; + + // #135235# Clip siblings of this + // SystemChildWindow. Otherwise, DXCanvas (using a hidden + // SystemChildWindow) clobbers applets/plugins during + // animations . + HWND hWnd = CreateWindowExA( 0, SAL_OBJECT_CLASSNAMEA, "", + WS_CHILD | WS_CLIPSIBLINGS, 0, 0, 0, 0, + pParent->mhWnd, 0, + pInst->mhInst, (void*)pObject ); + + HWND hWndChild = 0; + if ( hWnd ) + { + // #135235# Explicitely stack SystemChildWindows in + // the order they're created - since there's no notion + // of zorder. + SetWindowPos(hWnd,HWND_TOP,0,0,0,0, + SWP_NOACTIVATE|SWP_NOMOVE|SWP_NOREDRAW|SWP_NOSIZE); + hWndChild = CreateWindowExA( 0, SAL_OBJECT_CHILDCLASSNAMEA, "", + WS_CHILD | WS_CLIPCHILDREN | WS_CLIPSIBLINGS | WS_VISIBLE, + 0, 0, 0, 0, + hWnd, 0, + pInst->mhInst, NULL ); + } + + if ( !hWndChild ) + { + delete pObject; + return NULL; + } + + if ( hWnd ) + { + pObject->mhWnd = hWnd; + pObject->mhWndChild = hWndChild; + pObject->maSysData.hWnd = hWndChild; + return pObject; + } + } + + return NULL; +} + +// ======================================================================= + +WinSalObject::WinSalObject() +{ + SalData* pSalData = GetSalData(); + + mhWnd = 0; + mhWndChild = 0; + mhLastFocusWnd = 0; + maSysData.nSize = sizeof( SystemEnvData ); + mpStdClipRgnData = NULL; + + // Insert object in objectlist + mpNextObject = pSalData->mpFirstObject; + pSalData->mpFirstObject = this; +} + +// ----------------------------------------------------------------------- + +WinSalObject::~WinSalObject() +{ + SalData* pSalData = GetSalData(); + + // remove frame from framelist + if ( this == pSalData->mpFirstObject ) + { + pSalData->mpFirstObject = mpNextObject; + + // Wenn letztes SalObject, dann Hook wieder entfernen + if ( !pSalData->mpFirstObject ) + UnhookWindowsHookEx( pSalData->mhSalObjMsgHook ); + } + else + { + WinSalObject* pTempObject = pSalData->mpFirstObject; + while ( pTempObject->mpNextObject != this ) + pTempObject = pTempObject->mpNextObject; + + pTempObject->mpNextObject = mpNextObject; + } + + // Cache-Daten zerstoeren + if ( mpStdClipRgnData ) + delete mpStdClipRgnData; + + HWND hWndParent = ::GetParent( mhWnd ); + + if ( mhWndChild ) + DestroyWindow( mhWndChild ); + if ( mhWnd ) + DestroyWindow( mhWnd ); + + // Palette wieder zuruecksetzen, wenn kein externes Child-Fenster + // mehr vorhanden ist, da diese unsere Palette ueberschrieben haben + // koennen + if ( hWndParent && + ::GetActiveWindow() == hWndParent && + !GetWindow( hWndParent, GW_CHILD ) ) + ImplSendMessage( hWndParent, SAL_MSG_FORCEPALETTE, 0, 0 ); +} + +// ----------------------------------------------------------------------- + +void WinSalObject::ResetClipRegion() +{ + SetWindowRgn( mhWnd, 0, TRUE ); +} + +// ----------------------------------------------------------------------- + +USHORT WinSalObject::GetClipRegionType() +{ + return SAL_OBJECT_CLIP_INCLUDERECTS; +} + +// ----------------------------------------------------------------------- + +void WinSalObject::BeginSetClipRegion( ULONG nRectCount ) +{ + ULONG nRectBufSize = sizeof(RECT)*nRectCount; + if ( nRectCount < SAL_CLIPRECT_COUNT ) + { + if ( !mpStdClipRgnData ) + mpStdClipRgnData = (RGNDATA*)new BYTE[sizeof(RGNDATA)-1+(SAL_CLIPRECT_COUNT*sizeof(RECT))]; + mpClipRgnData = mpStdClipRgnData; + } + else + mpClipRgnData = (RGNDATA*)new BYTE[sizeof(RGNDATA)-1+nRectBufSize]; + mpClipRgnData->rdh.dwSize = sizeof( RGNDATAHEADER ); + mpClipRgnData->rdh.iType = RDH_RECTANGLES; + mpClipRgnData->rdh.nCount = nRectCount; + mpClipRgnData->rdh.nRgnSize = nRectBufSize; + SetRectEmpty( &(mpClipRgnData->rdh.rcBound) ); + mpNextClipRect = (RECT*)(&(mpClipRgnData->Buffer)); + mbFirstClipRect = TRUE; +} + +// ----------------------------------------------------------------------- + +void WinSalObject::UnionClipRegion( long nX, long nY, long nWidth, long nHeight ) +{ + RECT* pRect = mpNextClipRect; + RECT* pBoundRect = &(mpClipRgnData->rdh.rcBound); + long nRight = nX + nWidth; + long nBottom = nY + nHeight; + + if ( mbFirstClipRect ) + { + pBoundRect->left = nX; + pBoundRect->top = nY; + pBoundRect->right = nRight; + pBoundRect->bottom = nBottom; + mbFirstClipRect = FALSE; + } + else + { + if ( nX < pBoundRect->left ) + pBoundRect->left = (int)nX; + + if ( nY < pBoundRect->top ) + pBoundRect->top = (int)nY; + + if ( nRight > pBoundRect->right ) + pBoundRect->right = (int)nRight; + + if ( nBottom > pBoundRect->bottom ) + pBoundRect->bottom = (int)nBottom; + } + + pRect->left = (int)nX; + pRect->top = (int)nY; + pRect->right = (int)nRight; + pRect->bottom = (int)nBottom; + mpNextClipRect++; +} + +// ----------------------------------------------------------------------- + +void WinSalObject::EndSetClipRegion() +{ + HRGN hRegion; + + // Aus den Region-Daten muessen wir jetzt eine ClipRegion erzeugen + if ( mpClipRgnData->rdh.nCount == 1 ) + { + RECT* pRect = &(mpClipRgnData->rdh.rcBound); + hRegion = CreateRectRgn( pRect->left, pRect->top, + pRect->right, pRect->bottom ); + } + else + { + ULONG nSize = mpClipRgnData->rdh.nRgnSize+sizeof(RGNDATAHEADER); + hRegion = ExtCreateRegion( NULL, nSize, mpClipRgnData ); + if ( mpClipRgnData != mpStdClipRgnData ) + delete [] (BYTE*)mpClipRgnData; + } + + DBG_ASSERT( hRegion, "SalObject::EndSetClipRegion() - Can't create ClipRegion" ); + SetWindowRgn( mhWnd, hRegion, TRUE ); +} + +// ----------------------------------------------------------------------- + +void WinSalObject::SetPosSize( long nX, long nY, long nWidth, long nHeight ) +{ + ULONG nStyle = 0; + BOOL bVisible = (GetWindowStyle( mhWnd ) & WS_VISIBLE) != 0; + if ( bVisible ) + { + ShowWindow( mhWnd, SW_HIDE ); + nStyle |= SWP_SHOWWINDOW; + } + SetWindowPos( mhWnd, 0, + (int)nX, (int)nY, (int)nWidth, (int)nHeight, + SWP_NOZORDER | SWP_NOACTIVATE | nStyle ); +} + +// ----------------------------------------------------------------------- + +void WinSalObject::Show( BOOL bVisible ) +{ + if ( bVisible ) + ShowWindow( mhWnd, SW_SHOWNORMAL ); + else + ShowWindow( mhWnd, SW_HIDE ); +} + +// ----------------------------------------------------------------------- + +void WinSalObject::Enable( BOOL bEnable ) +{ + EnableWindow( mhWnd, bEnable ); +} + +// ----------------------------------------------------------------------- + +void WinSalObject::GrabFocus() +{ + if ( mhLastFocusWnd && + IsWindow( mhLastFocusWnd ) && + ImplIsSysWindowOrChild( mhWndChild, mhLastFocusWnd ) ) + ::SetFocus( mhLastFocusWnd ); + else + ::SetFocus( mhWndChild ); +} + +// ----------------------------------------------------------------------- + +void WinSalObject::SetBackground() +{ +} + +// ----------------------------------------------------------------------- + +void WinSalObject::SetBackground( SalColor ) +{ +} + +// ----------------------------------------------------------------------- + +const SystemEnvData* WinSalObject::GetSystemData() const +{ + return &maSysData; +} |