// Modified by: VZ on 13.05.99: no more Default(), MSWOnXXX() reorganisation
// Created: 04/01/98
// RCS-ID: $Id$
-// Copyright: (c) Julian Smart and Markus Holzem
-// Licence: wxWindows license
+// Copyright: (c) Julian Smart
+// Licence: wxWindows licence
/////////////////////////////////////////////////////////////////////////////
// ===========================================================================
// headers
// ---------------------------------------------------------------------------
-#ifdef __GNUG__
+#if defined(__GNUG__) && !defined(NO_GCC_PRAGMA)
#pragma implementation "window.h"
#endif
#endif
#ifndef WX_PRECOMP
- #include <windows.h>
- #include "wx/msw/winundef.h"
+ #include "wx/msw/wrapwin.h"
#include "wx/window.h"
#include "wx/accel.h"
#include "wx/setup.h"
#include "wx/menu.h"
#include "wx/dc.h"
#include "wx/dcclient.h"
+ #include "wx/dcmemory.h"
#include "wx/utils.h"
#include "wx/app.h"
#include "wx/layout.h"
#include "wx/statbox.h"
#endif
-#if wxUSE_OWNER_DRAWN
+#if wxUSE_OWNER_DRAWN && !defined(__WXUNIVERSAL__)
#include "wx/ownerdrw.h"
#endif
#include "wx/dnd.h"
#endif
+#if wxUSE_ACCESSIBILITY
+ #include "wx/access.h"
+ #include <ole2.h>
+ #include <oleacc.h>
+ #ifndef WM_GETOBJECT
+ #define WM_GETOBJECT 0x003D
+ #endif
+ #ifndef OBJID_CLIENT
+ #define OBJID_CLIENT 0xFFFFFFFC
+ #endif
+#endif
+
#include "wx/menuitem.h"
#include "wx/log.h"
#include "wx/textctrl.h"
#include "wx/notebook.h"
+#include "wx/listctrl.h"
#include <string.h>
-#if (!defined(__GNUWIN32_OLD__) && !defined(__WXMICROWIN__)) || defined(__CYGWIN10__)
+#if (!defined(__GNUWIN32_OLD__) && !defined(__WXMICROWIN__) && !defined(__WXWINCE__)) || defined(__CYGWIN10__)
#include <shellapi.h>
#include <mmsystem.h>
#endif
#include <windowsx.h>
#endif
-#if (!defined(__GNUWIN32_OLD__) && !defined(__TWIN32__) && !defined(__WXMICROWIN__)) || defined(__CYGWIN10__)
+#if (!defined(__GNUWIN32_OLD__) && !defined(__WXMICROWIN__) && !defined(__WXWINCE__)) || defined(__CYGWIN10__)
#ifdef __WIN95__
#include <commctrl.h>
#endif
-#elif !defined(__WXMICROWIN__) // broken compiler
- #ifndef __TWIN32__
- #include "wx/msw/gnuwin32/extra.h"
- #endif
+#elif !defined(__WXMICROWIN__) && !defined(__WXWINCE__) // broken compiler
+ #include "wx/msw/gnuwin32/extra.h"
+#endif
+
+#if defined(__GNUG__)
+#include "wx/msw/missing.h"
#endif
+#if defined(__WXWINCE__)
+#include "wx/msw/wince/missing.h"
+#endif
+
+// ----------------------------------------------------------------------------
+// standard constants not available with all compilers/headers
+// ----------------------------------------------------------------------------
+
// This didn't appear in mingw until 2.95.2
#ifndef SIF_TRACKPOS
#define SIF_TRACKPOS 16
#ifndef SPI_GETWHEELSCROLLLINES
#define SPI_GETWHEELSCROLLLINES 104
#endif
+#endif // wxUSE_MOUSEWHEEL
+
+#ifndef VK_OEM_1
+ #define VK_OEM_1 0xBA
+ #define VK_OEM_2 0xBF
+ #define VK_OEM_3 0xC0
+ #define VK_OEM_4 0xDB
+ #define VK_OEM_5 0xDC
+ #define VK_OEM_6 0xDD
+ #define VK_OEM_7 0xDE
#endif
+#ifndef VK_OEM_COMMA
+ #define VK_OEM_PLUS 0xBB
+ #define VK_OEM_COMMA 0xBC
+ #define VK_OEM_MINUS 0xBD
+ #define VK_OEM_PERIOD 0xBE
+#endif
// ---------------------------------------------------------------------------
// global variables
// ---------------------------------------------------------------------------
-// the last Windows message we got (MT-UNSAFE)
+// the last Windows message we got (FIXME-MT)
extern MSG s_currentMsg;
#if wxUSE_MENUS_NATIVE
extern const wxChar *wxCanvasClassName;
+// true if we had already created the std colour map, used by
+// wxGetStdColourMap() and wxWindow::OnSysColourChanged() (FIXME-MT)
+static bool gs_hasStdCmap = FALSE;
+
// ---------------------------------------------------------------------------
// private functions
// ---------------------------------------------------------------------------
LRESULT WXDLLEXPORT APIENTRY _EXPORT wxWndProc(HWND hWnd, UINT message,
WPARAM wParam, LPARAM lParam);
+
#ifdef __WXDEBUG__
const char *wxGetMessageName(int message);
#endif //__WXDEBUG__
void wxRemoveHandleAssociation(wxWindowMSW *win);
-void wxAssociateWinWithHandle(HWND hWnd, wxWindowMSW *win);
+extern void wxAssociateWinWithHandle(HWND hWnd, wxWindowMSW *win);
wxWindow *wxFindWinFromHandle(WXHWND hWnd);
// this magical function is used to translate VK_APPS key presses to right
// get the text metrics for the current font
static TEXTMETRIC wxGetTextMetrics(const wxWindowMSW *win);
+// find the window for the mouse event at the specified position
+static wxWindowMSW *FindWindowForMouseEvent(wxWindowMSW *win, int *x, int *y); //TW:REQ:Univ
+
// wrapper around BringWindowToTop() API
static inline void wxBringWindowToTop(HWND hwnd)
{
// activate (set focus to) specified window
::SetFocus(hwnd);
+#endif
// raise top level parent to top of z order
- ::SetWindowPos(hwnd, HWND_TOP, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE);
-#else // !__WXMICROWIN__
- if ( !::BringWindowToTop(hwnd) )
+ if (!::SetWindowPos(hwnd, HWND_TOP, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE))
+ {
+ wxLogLastError(_T("SetWindowPos"));
+ }
+}
+
+// ensure that all our parent windows have WS_EX_CONTROLPARENT style
+static void EnsureParentHasControlParentStyle(wxWindow *parent)
+{
+ /*
+ If we have WS_EX_CONTROLPARENT flag we absolutely *must* set it for our
+ parent as well as otherwise several Win32 functions using
+ GetNextDlgTabItem() to iterate over all controls such as
+ IsDialogMessage() or DefDlgProc() would enter an infinite loop: indeed,
+ all of them iterate over all the controls starting from the currently
+ focused one and stop iterating when they get back to the focus but
+ unless all parents have WS_EX_CONTROLPARENT bit set, they would never
+ get back to the initial (focused) window: as we do have this style,
+ GetNextDlgTabItem() will leave this window and continue in its parent,
+ but if the parent doesn't have it, it wouldn't recurse inside it later
+ on and so wouldn't have a chance of getting back to this window neither.
+ */
+#ifndef __WXWINCE__
+ while ( parent && !parent->IsTopLevel() )
{
- wxLogLastError(_T("BringWindowToTop"));
+ LONG exStyle = ::GetWindowLong(GetHwndOf(parent), GWL_EXSTYLE);
+ if ( !(exStyle & WS_EX_CONTROLPARENT) )
+ {
+ // force the parent to have this style
+ ::SetWindowLong(GetHwndOf(parent), GWL_EXSTYLE,
+ exStyle | WS_EX_CONTROLPARENT);
+ }
+
+ parent = parent->GetParent();
}
-#endif // __WXMICROWIN__/!__WXMICROWIN__
+#endif // !__WXWINCE__
}
// ---------------------------------------------------------------------------
#ifdef __WXUNIVERSAL__
IMPLEMENT_ABSTRACT_CLASS(wxWindowMSW, wxWindowBase)
#else // __WXMSW__
+#if wxUSE_EXTENDED_RTTI
+
+// windows that are created from a parent window during its Create method, eg. spin controls in a calendar controls
+// must never been streamed out separately otherwise chaos occurs. Right now easiest is to test for negative ids, as
+// windows with negative ids never can be recreated anyway
+
+bool wxWindowStreamingCallback( const wxObject *object, wxWriter * , wxPersister * , wxxVariantArray & )
+{
+ const wxWindow * win = dynamic_cast<const wxWindow*>(object) ;
+ if ( win && win->GetId() < 0 )
+ return false ;
+ return true ;
+}
+
+IMPLEMENT_DYNAMIC_CLASS_XTI_CALLBACK(wxWindow, wxWindowBase,"wx/window.h", wxWindowStreamingCallback)
+
+// make wxWindowList known before the property is used
+
+wxCOLLECTION_TYPE_INFO( wxWindow* , wxWindowList ) ;
+
+template<> void wxCollectionToVariantArray( wxWindowList const &theList, wxxVariantArray &value)
+{
+ wxListCollectionToVariantArray<wxWindowList::compatibility_iterator>( theList , value ) ;
+}
+
+WX_DEFINE_FLAGS( wxWindowStyle )
+
+wxBEGIN_FLAGS( wxWindowStyle )
+ // new style border flags, we put them first to
+ // use them for streaming out
+
+ wxFLAGS_MEMBER(wxBORDER_SIMPLE)
+ wxFLAGS_MEMBER(wxBORDER_SUNKEN)
+ wxFLAGS_MEMBER(wxBORDER_DOUBLE)
+ wxFLAGS_MEMBER(wxBORDER_RAISED)
+ wxFLAGS_MEMBER(wxBORDER_STATIC)
+ wxFLAGS_MEMBER(wxBORDER_NONE)
+
+ // old style border flags
+ wxFLAGS_MEMBER(wxSIMPLE_BORDER)
+ wxFLAGS_MEMBER(wxSUNKEN_BORDER)
+ wxFLAGS_MEMBER(wxDOUBLE_BORDER)
+ wxFLAGS_MEMBER(wxRAISED_BORDER)
+ wxFLAGS_MEMBER(wxSTATIC_BORDER)
+ wxFLAGS_MEMBER(wxNO_BORDER)
+
+ // standard window styles
+ wxFLAGS_MEMBER(wxTAB_TRAVERSAL)
+ wxFLAGS_MEMBER(wxCLIP_CHILDREN)
+ wxFLAGS_MEMBER(wxTRANSPARENT_WINDOW)
+ wxFLAGS_MEMBER(wxWANTS_CHARS)
+ wxFLAGS_MEMBER(wxNO_FULL_REPAINT_ON_RESIZE)
+ wxFLAGS_MEMBER(wxALWAYS_SHOW_SB )
+ wxFLAGS_MEMBER(wxVSCROLL)
+ wxFLAGS_MEMBER(wxHSCROLL)
+
+wxEND_FLAGS( wxWindowStyle )
+
+wxBEGIN_PROPERTIES_TABLE(wxWindow)
+ wxEVENT_PROPERTY( Close , wxEVT_CLOSE_WINDOW , wxCloseEvent)
+ wxEVENT_PROPERTY( Create , wxEVT_CREATE , wxWindowCreateEvent )
+ wxEVENT_PROPERTY( Destroy , wxEVT_DESTROY , wxWindowDestroyEvent )
+ // Always constructor Properties first
+
+ wxREADONLY_PROPERTY( Parent,wxWindow*, GetParent, , 0 /*flags*/ , wxT("Helpstring") , wxT("group"))
+ wxPROPERTY( Id,wxWindowID, SetId, GetId, -1, 0 /*flags*/ , wxT("Helpstring") , wxT("group") )
+ wxPROPERTY( Position,wxPoint, SetPosition , GetPosition, wxPoint(-1,-1) , 0 /*flags*/ , wxT("Helpstring") , wxT("group")) // pos
+ wxPROPERTY( Size,wxSize, SetSize, GetSize, wxSize(-1,-1) , 0 /*flags*/ , wxT("Helpstring") , wxT("group")) // size
+ wxPROPERTY( WindowStyle , long , SetWindowStyleFlag , GetWindowStyleFlag , , 0 /*flags*/ , wxT("Helpstring") , wxT("group")) // style
+
+ // Then all relations of the object graph
+
+ wxREADONLY_PROPERTY_COLLECTION( Children , wxWindowList , wxWindowBase* , GetWindowChildren , wxPROP_OBJECT_GRAPH /*flags*/ , wxT("Helpstring") , wxT("group"))
+
+ // and finally all other properties
+
+ wxPROPERTY( ExtraStyle , long , SetExtraStyle , GetExtraStyle , , 0 /*flags*/ , wxT("Helpstring") , wxT("group")) // extstyle
+ wxPROPERTY( BackgroundColour , wxColour , SetBackgroundColour , GetBackgroundColour , , 0 /*flags*/ , wxT("Helpstring") , wxT("group")) // bg
+ wxPROPERTY( ForegroundColour , wxColour , SetForegroundColour , GetForegroundColour , , 0 /*flags*/ , wxT("Helpstring") , wxT("group")) // fg
+ wxPROPERTY( Enabled , bool , Enable , IsEnabled , wxxVariant((bool)true) , 0 /*flags*/ , wxT("Helpstring") , wxT("group"))
+ wxPROPERTY( Shown , bool , Show , IsShown , wxxVariant((bool)true) , 0 /*flags*/ , wxT("Helpstring") , wxT("group"))
+#if 0
+ // possible property candidates (not in xrc) or not valid in all subclasses
+ wxPROPERTY( Title,wxString, SetTitle, GetTitle, wxT("") )
+ wxPROPERTY( Font , wxFont , SetFont , GetWindowFont , )
+ wxPROPERTY( Label,wxString, SetLabel, GetLabel, wxT("") )
+ // MaxHeight, Width , MinHeight , Width
+ // TODO switch label to control and title to toplevels
+
+ wxPROPERTY( ThemeEnabled , bool , SetThemeEnabled , GetThemeEnabled , )
+ //wxPROPERTY( Cursor , wxCursor , SetCursor , GetCursor , )
+ // wxPROPERTY( ToolTip , wxString , SetToolTip , GetToolTipText , )
+ wxPROPERTY( AutoLayout , bool , SetAutoLayout , GetAutoLayout , )
+
+
+
+#endif
+wxEND_PROPERTIES_TABLE()
+
+wxBEGIN_HANDLERS_TABLE(wxWindow)
+wxEND_HANDLERS_TABLE()
+
+wxCONSTRUCTOR_DUMMY(wxWindow)
+
+#else
IMPLEMENT_DYNAMIC_CLASS(wxWindow, wxWindowBase)
+#endif
#endif // __WXUNIVERSAL__/__WXMSW__
BEGIN_EVENT_TABLE(wxWindowMSW, wxWindowBase)
EVT_ERASE_BACKGROUND(wxWindowMSW::OnEraseBackground)
EVT_SYS_COLOUR_CHANGED(wxWindowMSW::OnSysColourChanged)
EVT_INIT_DIALOG(wxWindowMSW::OnInitDialog)
- EVT_IDLE(wxWindowMSW::OnIdle)
END_EVENT_TABLE()
// ===========================================================================
}
#endif // wxUSE_CONTROLS
- wxWindowList::Node *current = GetChildren().GetFirst();
+ wxWindowList::compatibility_iterator current = GetChildren().GetFirst();
while (current)
{
wxWindow *childWin = current->GetData();
// Find an item given the MS Windows handle
wxWindow *wxWindowMSW::FindItemByHWND(WXHWND hWnd, bool controlOnly) const
{
- wxWindowList::Node *current = GetChildren().GetFirst();
+ wxWindowList::compatibility_iterator current = GetChildren().GetFirst();
while (current)
{
wxWindow *parent = current->GetData();
InitBase();
// MSW specific
- m_doubleClickAllowed = 0;
-
m_isBeingDeleted = FALSE;
- m_oldWndProc = 0;
- m_useCtl3D = FALSE;
+ m_oldWndProc = NULL;
m_mouseInWindow = FALSE;
+ m_lastKeydownProcessed = FALSE;
+
+ m_childrenDisabled = NULL;
// wxWnd
m_hMenu = 0;
m_hWnd = 0;
- // pass WM_GETDLGCODE to DefWindowProc()
- m_lDlgCode = 0;
-
m_xThumbSize = 0;
m_yThumbSize = 0;
- m_backgroundTransparent = FALSE;
// as all windows are created with WS_VISIBLE style...
m_isShown = TRUE;
{
m_isBeingDeleted = TRUE;
- MSWDetachWindowMenu();
-
+#ifndef __WXUNIVERSAL__
// VS: make sure there's no wxFrame with last focus set to us:
- for (wxWindow *win = GetParent(); win; win = win->GetParent())
+ for ( wxWindow *win = GetParent(); win; win = win->GetParent() )
{
- wxFrame *frame = wxDynamicCast(win, wxFrame);
+ wxTopLevelWindow *frame = wxDynamicCast(win, wxTopLevelWindow);
if ( frame )
{
if ( frame->GetLastFocus() == this )
- frame->SetLastFocus((wxWindow*)NULL);
+ {
+ frame->SetLastFocus(NULL);
+ }
break;
}
}
+#endif // __WXUNIVERSAL__
// VS: destroy children first and _then_ detach *this from its parent.
// If we'd do it the other way around, children wouldn't be able
// remove hWnd <-> wxWindow association
wxRemoveHandleAssociation(this);
}
+
+ delete m_childrenDisabled;
}
// real construction (Init() must have been called before!)
{
wxCHECK_MSG( parent, FALSE, wxT("can't create wxWindow without parent") );
-#if wxUSE_STATBOX
- // wxGTK doesn't allow to create controls with static box as the parent so
- // this will result in a crash when the program is ported to wxGTK - warn
- // about it
- //
- // the correct solution is to create the controls as siblings of the
- // static box
- wxASSERT_MSG( !wxDynamicCastThis(wxStaticBox),
- _T("wxStaticBox can't be used as a window parent!") );
-#endif // wxUSE_STATBOX
-
if ( !CreateBase(parent, id, pos, size, style, wxDefaultValidator, name) )
return FALSE;
parent->AddChild(this);
- // all windows are created visible
- DWORD msflags = WS_CHILD | WS_VISIBLE;
+ WXDWORD exstyle;
+ DWORD msflags = MSWGetCreateWindowFlags(&exstyle);
#ifdef __WXUNIVERSAL__
- // no 3d effects, we draw them ourselves
- WXDWORD exStyle = 0;
-#else // !wxUniversal
- if ( style & wxCLIP_CHILDREN )
- msflags |= WS_CLIPCHILDREN;
- if ( style & wxCLIP_SIBLINGS )
- msflags |= WS_CLIPSIBLINGS;
-
- bool want3D;
- WXDWORD exStyle = Determine3DEffects(WS_EX_CLIENTEDGE, &want3D);
-
- // Even with extended styles, need to combine with WS_BORDER
- // for them to look right.
- if ( want3D ||
- (m_windowStyle & (wxBORDER |
- wxSIMPLE_BORDER |
- wxRAISED_BORDER |
- wxSUNKEN_BORDER |
- wxDOUBLE_BORDER)) )
- {
- msflags |= WS_BORDER;
- }
-
- // calculate the value to return from WM_GETDLGCODE handler
- if ( GetWindowStyleFlag() & wxWANTS_CHARS )
- {
- // want everything: i.e. all keys and WM_CHAR message
- m_lDlgCode = DLGC_WANTARROWS | DLGC_WANTCHARS |
- DLGC_WANTTAB | DLGC_WANTMESSAGE;
- }
-#endif // wxUniversal/!wxUniversal
-
+ // no borders, we draw them ourselves
+ exstyle &= ~(WS_EX_DLGMODALFRAME |
+ WS_EX_STATICEDGE |
+ WS_EX_CLIENTEDGE |
+ WS_EX_WINDOWEDGE);
+ msflags &= ~WS_BORDER;
+#endif // wxUniversal
+
+ // all windows are created visible by default except popup ones (which are
+ // like the wxTopLevelWindows in this aspect)
if ( style & wxPOPUP_WINDOW )
{
- // a popup window floats on top of everything
- exStyle |= WS_EX_TOPMOST | WS_EX_TOOLWINDOW;
-
- // it is also created hidden as other top level windows
msflags &= ~WS_VISIBLE;
m_isShown = FALSE;
}
+ else
+ {
+ msflags |= WS_VISIBLE;
+ }
- return MSWCreate(m_windowId, parent, wxCanvasClassName,
- (wxWindow *)this, NULL,
- pos.x, pos.y,
- WidthDefault(size.x), HeightDefault(size.y),
- msflags, NULL, exStyle);
+ return MSWCreate(wxCanvasClassName, NULL, pos, size, msflags, exstyle);
}
// ---------------------------------------------------------------------------
HWND hWnd = GetHwnd();
wxCHECK_RET( hWnd, _T("can't set focus to invalid window") );
-#ifndef __WXMICROWIN__
+#if !defined(__WXMICROWIN__) && !defined(__WXWINCE__)
::SetLastError(0);
#endif
if ( !::SetFocus(hWnd) )
{
+#if defined(__WXDEBUG__) && !defined(__WXMICROWIN__)
// was there really an error?
-#ifndef __WXMICROWIN__
DWORD dwRes = ::GetLastError();
-#else
-
- DWORD dwRes = 0;
-#endif
if ( dwRes )
{
- wxLogApiError(_T("SetFocus"), dwRes);
+ HWND hwndFocus = ::GetFocus();
+ if ( hwndFocus != hWnd )
+ {
+ wxLogApiError(_T("SetFocus"), dwRes);
+ }
}
+#endif // Debug
+ }
+}
- // VZ: just why does this happen sometimes?? any idea?
-#if 0
- HWND hwndFocus = ::GetFocus();
- wxASSERT_MSG( hwndFocus == hWnd, _T("SetFocus() didn't work?") );
-#endif // 0
+void wxWindowMSW::SetFocusFromKbd()
+{
+ // when the focus is given to the control with DLGC_HASSETSEL style from
+ // keyboard its contents should be entirely selected: this is what
+ // ::IsDialogMessage() does and so we should do it as well to provide the
+ // same LNF as the native programs
+ if ( ::SendMessage(GetHwnd(), WM_GETDLGCODE, 0, 0) & DLGC_HASSETSEL )
+ {
+ ::SendMessage(GetHwnd(), EM_SETSEL, 0, -1);
}
+
+ // do this after (maybe) setting the selection as like this when
+ // wxEVT_SET_FOCUS handler is called, the selection would have been already
+ // set correctly -- this may be important
+ wxWindowBase::SetFocusFromKbd();
}
// Get the window with the focus
if ( hWnd )
::EnableWindow(hWnd, (BOOL)enable);
- // VZ: no, this is a bad idea: imagine that you have a dialog with some
- // disabled controls and disable it - you really wouldn't like the
- // disabled controls be reenabled too when you reenable the dialog!
-#if 0
- wxWindowList::Node *node = GetChildren().GetFirst();
- while ( node )
+ // the logic below doesn't apply to the top level windows -- otherwise
+ // showing a modal dialog would result in total greying out (and ungreying
+ // out later) of everything which would be really ugly
+ if ( IsTopLevel() )
+ return TRUE;
+
+ // when the parent is disabled, all of its children should be disabled as
+ // well but when it is enabled back, only those of the children which
+ // hadn't been already disabled in the beginning should be enabled again,
+ // so we have to keep the list of those children
+ for ( wxWindowList::compatibility_iterator node = GetChildren().GetFirst();
+ node;
+ node = node->GetNext() )
{
wxWindow *child = node->GetData();
- child->Enable(enable);
+ if ( child->IsTopLevel() )
+ {
+ // the logic below doesn't apply to top level children
+ continue;
+ }
- node = node->GetNext();
+ if ( enable )
+ {
+ // enable the child back unless it had been disabled before us
+ if ( !m_childrenDisabled || !m_childrenDisabled->Find(child) )
+ child->Enable();
+ }
+ else // we're being disabled
+ {
+ if ( child->IsEnabled() )
+ {
+ // disable it as children shouldn't stay enabled while the
+ // parent is not
+ child->Disable();
+ }
+ else // child already disabled, remember it
+ {
+ // have we created the list of disabled children already?
+ if ( !m_childrenDisabled )
+ m_childrenDisabled = new wxWindowList;
+
+ m_childrenDisabled->Append(child);
+ }
+ }
+ }
+
+ if ( enable && m_childrenDisabled )
+ {
+ // we don't need this list any more, don't keep unused memory
+ delete m_childrenDisabled;
+ m_childrenDisabled = NULL;
}
-#endif // 0
return TRUE;
}
int cshow = show ? SW_SHOW : SW_HIDE;
::ShowWindow(hWnd, cshow);
- if ( show )
+ if ( show && IsTopLevel() )
{
wxBringWindowToTop(hWnd);
}
return wxGetWindowText(GetHWND());
}
-void wxWindowMSW::CaptureMouse()
+void wxWindowMSW::DoCaptureMouse()
{
HWND hWnd = GetHwnd();
if ( hWnd )
}
}
-void wxWindowMSW::ReleaseMouse()
+void wxWindowMSW::DoReleaseMouse()
{
if ( !::ReleaseCapture() )
{
POINT point;
::GetCursorPos(&point);
- RECT rect;
- ::GetWindowRect(hWnd, &rect);
+ RECT rect = wxGetWindowRect(hWnd);
if ( ::PtInRect(&rect, point) && !wxIsBusy() )
::SetCursor(GetHcursorOf(m_cursor));
}
}
-#if WXWIN_COMPATIBILITY
-void wxWindowMSW::MSWDeviceToLogical (float *x, float *y) const
-{
-}
-#endif // WXWIN_COMPATIBILITY
-
// ---------------------------------------------------------------------------
// scrolling stuff
// ---------------------------------------------------------------------------
-#if WXWIN_COMPATIBILITY
-void wxWindowMSW::SetScrollRange(int orient, int range, bool refresh)
-{
-#if defined(__WIN95__)
-
- int range1 = range;
-
- // Try to adjust the range to cope with page size > 1
- // - a Windows API quirk
- int pageSize = GetScrollPage(orient);
- if ( pageSize > 1 && range > 0)
- {
- range1 += (pageSize - 1);
- }
-
- SCROLLINFO info;
- int dir;
-
- if ( orient == wxHORIZONTAL ) {
- dir = SB_HORZ;
- } else {
- dir = SB_VERT;
- }
-
- info.cbSize = sizeof(SCROLLINFO);
- info.nPage = pageSize; // Have to set this, or scrollbar goes awry
- info.nMin = 0;
- info.nMax = range1;
- info.nPos = 0;
- info.fMask = SIF_RANGE | SIF_PAGE;
-
- HWND hWnd = GetHwnd();
- if ( hWnd )
- ::SetScrollInfo(hWnd, dir, &info, refresh);
-#else
- int wOrient;
- if ( orient == wxHORIZONTAL )
- wOrient = SB_HORZ;
- else
- wOrient = SB_VERT;
-
- HWND hWnd = GetHwnd();
- if ( hWnd )
- ::SetScrollRange(hWnd, wOrient, 0, range, refresh);
-#endif
-}
-
-void wxWindowMSW::SetScrollPage(int orient, int page, bool refresh)
-{
-#if defined(__WIN95__)
- SCROLLINFO info;
- int dir;
-
- if ( orient == wxHORIZONTAL ) {
- dir = SB_HORZ;
- m_xThumbSize = page;
- } else {
- dir = SB_VERT;
- m_yThumbSize = page;
- }
-
- info.cbSize = sizeof(SCROLLINFO);
- info.nPage = page;
- info.nMin = 0;
- info.fMask = SIF_PAGE;
-
- HWND hWnd = GetHwnd();
- if ( hWnd )
- ::SetScrollInfo(hWnd, dir, &info, refresh);
-#else
- if ( orient == wxHORIZONTAL )
- m_xThumbSize = page;
- else
- m_yThumbSize = page;
-#endif
-}
-
-int wxWindowMSW::OldGetScrollRange(int orient) const
-{
- int wOrient;
- if ( orient == wxHORIZONTAL )
- wOrient = SB_HORZ;
- else
- wOrient = SB_VERT;
-
-#if __WATCOMC__ && defined(__WINDOWS_386__)
- short minPos, maxPos;
-#else
- int minPos, maxPos;
-#endif
- HWND hWnd = GetHwnd();
- if ( hWnd )
- {
- ::GetScrollRange(hWnd, wOrient, &minPos, &maxPos);
-#if defined(__WIN95__)
- // Try to adjust the range to cope with page size > 1
- // - a Windows API quirk
- int pageSize = GetScrollPage(orient);
- if ( pageSize > 1 )
- {
- maxPos -= (pageSize - 1);
- }
-#endif
- return maxPos;
- }
- else
- return 0;
-}
-
-int wxWindowMSW::GetScrollPage(int orient) const
+// convert wxHORIZONTAL/wxVERTICAL to SB_HORZ/SB_VERT
+static inline int wxDirToWinStyle(int orient)
{
- if ( orient == wxHORIZONTAL )
- return m_xThumbSize;
- else
- return m_yThumbSize;
+ return orient == wxHORIZONTAL ? SB_HORZ : SB_VERT;
}
-#endif // WXWIN_COMPATIBILITY
-
inline int GetScrollPosition(HWND hWnd, int wOrient)
{
#ifdef __WXMICROWIN__
return ::GetScrollPosWX(hWnd, wOrient);
#else
- return ::GetScrollPos(hWnd, wOrient);
+ WinStruct<SCROLLINFO> scrollInfo;
+ scrollInfo.cbSize = sizeof(SCROLLINFO);
+ scrollInfo.fMask = SIF_POS;
+ if ( !::GetScrollInfo(hWnd,
+ wOrient,
+ &scrollInfo) )
+ {
+ // Not neccessarily an error, if there are no scrollbars yet.
+ // wxLogLastError(_T("GetScrollInfo"));
+ }
+ return scrollInfo.nPos;
+// return ::GetScrollPos(hWnd, wOrient);
#endif
}
int wxWindowMSW::GetScrollPos(int orient) const
{
- int wOrient;
- if ( orient == wxHORIZONTAL )
- wOrient = SB_HORZ;
- else
- wOrient = SB_VERT;
-
HWND hWnd = GetHwnd();
wxCHECK_MSG( hWnd, 0, _T("no HWND in GetScrollPos") );
- return GetScrollPosition(hWnd, wOrient);
+ return GetScrollPosition(hWnd, orient == wxHORIZONTAL ? SB_HORZ : SB_VERT);
}
// This now returns the whole range, not just the number
// of positions that we can scroll.
int wxWindowMSW::GetScrollRange(int orient) const
{
- int wOrient;
- if ( orient == wxHORIZONTAL )
- wOrient = SB_HORZ;
- else
- wOrient = SB_VERT;
-
-#if __WATCOMC__ && defined(__WINDOWS_386__)
- short minPos, maxPos;
-#else
- int minPos, maxPos;
-#endif
+ int maxPos;
HWND hWnd = GetHwnd();
- if ( hWnd )
- {
- ::GetScrollRange(hWnd, wOrient, &minPos, &maxPos);
-#if defined(__WIN95__)
- // Try to adjust the range to cope with page size > 1
- // - a Windows API quirk
- int pageSize = GetScrollThumb(orient);
- if ( pageSize > 1 )
- {
- maxPos -= (pageSize - 1);
- }
- // October 10th: new range concept.
- maxPos += pageSize;
+ if ( !hWnd )
+ return 0;
+#if 0
+ ::GetScrollRange(hWnd, orient == wxHORIZONTAL ? SB_HORZ : SB_VERT,
+ &minPos, &maxPos);
#endif
-
- return maxPos;
+ WinStruct<SCROLLINFO> scrollInfo;
+ scrollInfo.fMask = SIF_RANGE;
+ if ( !::GetScrollInfo(hWnd,
+ orient == wxHORIZONTAL ? SB_HORZ : SB_VERT,
+ &scrollInfo) )
+ {
+ // Most of the time this is not really an error, since the return
+ // value can also be zero when there is no scrollbar yet.
+ // wxLogLastError(_T("GetScrollInfo"));
}
- else
- return 0;
+ maxPos = scrollInfo.nMax;
+
+ // undo "range - 1" done in SetScrollbar()
+ return maxPos + 1;
}
int wxWindowMSW::GetScrollThumb(int orient) const
{
- if ( orient == wxHORIZONTAL )
- return m_xThumbSize;
- else
- return m_yThumbSize;
+ return orient == wxHORIZONTAL ? m_xThumbSize : m_yThumbSize;
}
void wxWindowMSW::SetScrollPos(int orient, int pos, bool refresh)
{
-#if defined(__WIN95__)
- SCROLLINFO info;
- int dir;
-
- if ( orient == wxHORIZONTAL ) {
- dir = SB_HORZ;
- } else {
- dir = SB_VERT;
- }
+ HWND hWnd = GetHwnd();
+ wxCHECK_RET( hWnd, _T("SetScrollPos: no HWND") );
- info.cbSize = sizeof(SCROLLINFO);
+ WinStruct<SCROLLINFO> info;
info.nPage = 0;
info.nMin = 0;
info.nPos = pos;
info.fMask = SIF_POS;
-
- HWND hWnd = GetHwnd();
- if ( hWnd )
- ::SetScrollInfo(hWnd, dir, &info, refresh);
-#else
- int wOrient;
- if ( orient == wxHORIZONTAL )
- wOrient = SB_HORZ;
- else
- wOrient = SB_VERT;
-
- HWND hWnd = GetHwnd();
- if ( hWnd )
- ::SetScrollPos(hWnd, wOrient, pos, refresh);
-#endif
-}
-
-// New function that will replace some of the above.
-void wxWindowMSW::SetScrollbar(int orient, int pos, int thumbVisible,
- int range, bool refresh)
-{
-#if defined(__WIN95__)
- int oldRange = range - thumbVisible;
-
- int range1 = oldRange;
-
- // Try to adjust the range to cope with page size > 1
- // - a Windows API quirk
- int pageSize = thumbVisible;
- if ( pageSize > 1 && range > 0)
+ if ( HasFlag(wxALWAYS_SHOW_SB) )
{
- range1 += (pageSize - 1);
+ // disable scrollbar instead of removing it then
+ info.fMask |= SIF_DISABLENOSCROLL;
}
- SCROLLINFO info;
- int dir;
-
- if ( orient == wxHORIZONTAL ) {
- dir = SB_HORZ;
- } else {
- dir = SB_VERT;
- }
+ ::SetScrollInfo(hWnd, orient == wxHORIZONTAL ? SB_HORZ : SB_VERT,
+ &info, refresh);
+}
- info.cbSize = sizeof(SCROLLINFO);
- info.nPage = pageSize; // Have to set this, or scrollbar goes awry
- info.nMin = 0;
- info.nMax = range1;
+// New function that will replace some of the above.
+void wxWindowMSW::SetScrollbar(int orient,
+ int pos,
+ int pageSize,
+ int range,
+ bool refresh)
+{
+ WinStruct<SCROLLINFO> info;
+ info.nPage = pageSize;
+ info.nMin = 0; // range is nMax - nMin + 1
+ info.nMax = range - 1; // as both nMax and nMax are inclusive
info.nPos = pos;
info.fMask = SIF_RANGE | SIF_PAGE | SIF_POS;
-
- HWND hWnd = GetHwnd();
- if ( hWnd )
- ::SetScrollInfo(hWnd, dir, &info, refresh);
-#else
- int wOrient;
- if ( orient == wxHORIZONTAL )
- wOrient = SB_HORZ;
- else
- wOrient = SB_VERT;
+ if ( HasFlag(wxALWAYS_SHOW_SB) )
+ {
+ // disable scrollbar instead of removing it then
+ info.fMask |= SIF_DISABLENOSCROLL;
+ }
HWND hWnd = GetHwnd();
if ( hWnd )
{
- ::SetScrollRange(hWnd, wOrient, 0, range, FALSE);
- ::SetScrollPos(hWnd, wOrient, pos, refresh);
- }
-#endif
- if ( orient == wxHORIZONTAL ) {
- m_xThumbSize = thumbVisible;
- } else {
- m_yThumbSize = thumbVisible;
+ ::SetScrollInfo(hWnd, orient == wxHORIZONTAL ? SB_HORZ : SB_VERT,
+ &info, refresh);
}
+
+ *(orient == wxHORIZONTAL ? &m_xThumbSize : &m_yThumbSize) = pageSize;
}
void wxWindowMSW::ScrollWindow(int dx, int dy, const wxRect *prect)
{
RECT rect;
+ RECT *pr;
if ( prect )
{
rect.left = prect->x;
rect.top = prect->y;
rect.right = prect->x + prect->width;
rect.bottom = prect->y + prect->height;
+ pr = ▭
+ }
+ else
+ {
+ pr = NULL;
}
- ::ScrollWindow(GetHwnd(), dx, dy, prect ? &rect : NULL, NULL);
+#ifdef __WXWINCE__
+ // FIXME: is this the exact equivalent of the line below?
+ ::ScrollWindowEx(GetHwnd(), dx, dy, pr, pr, 0, 0, SW_ERASE|SW_INVALIDATE);
+#else
+ ::ScrollWindow(GetHwnd(), dx, dy, pr, pr);
+#endif
}
static bool ScrollVertically(HWND hwnd, int kind, int count)
wxAssociateWinWithHandle(hwnd, this);
- m_oldWndProc = (WXFARPROC) GetWindowLong(hwnd, GWL_WNDPROC);
-
- wxASSERT( (WXFARPROC) m_oldWndProc != (WXFARPROC) wxWndProc );
+ m_oldWndProc = (WXFARPROC)::GetWindowLong((HWND)hWnd, GWL_WNDPROC);
- SetWindowLong(hwnd, GWL_WNDPROC, (LONG) wxWndProc);
+ // we don't need to subclass the window of our own class (in the Windows
+ // sense of the word)
+ if ( !wxCheckWindowWndProc(hWnd, (WXFARPROC)wxWndProc) )
+ {
+ ::SetWindowLong(hwnd, GWL_WNDPROC, (LONG) wxWndProc);
+ }
+ else
+ {
+ // don't bother restoring it neither: this also makes it easy to
+ // implement IsOfStandardClass() method which returns TRUE for the
+ // standard controls and FALSE for the wxWindows own windows as it can
+ // simply check m_oldWndProc
+ m_oldWndProc = NULL;
+ }
}
void wxWindowMSW::UnsubclassWin()
wxCHECK_RET( ::IsWindow(hwnd), wxT("invalid HWND in UnsubclassWin") );
- FARPROC farProc = (FARPROC) GetWindowLong(hwnd, GWL_WNDPROC);
- if ( (m_oldWndProc != 0) && (farProc != (FARPROC) m_oldWndProc) )
+ if ( m_oldWndProc )
{
- SetWindowLong(hwnd, GWL_WNDPROC, (LONG) m_oldWndProc);
- m_oldWndProc = 0;
+ if ( !wxCheckWindowWndProc((WXHWND)hwnd, m_oldWndProc) )
+ {
+ ::SetWindowLong(hwnd, GWL_WNDPROC, (LONG) m_oldWndProc);
+ }
+
+ m_oldWndProc = NULL;
}
}
}
-// Make a Windows extended style from the given wxWindows window style
-WXDWORD wxWindowMSW::MakeExtendedStyle(long style, bool eliminateBorders)
-{
- WXDWORD exStyle = 0;
- if ( style & wxTRANSPARENT_WINDOW )
- exStyle |= WS_EX_TRANSPARENT;
-
- if ( !eliminateBorders )
+bool wxCheckWindowWndProc(WXHWND hWnd, WXFARPROC wndProc)
+{
+ // Unicows note: the code below works, but only because WNDCLASS contains
+ // original window handler rather that the unicows fake one. This may not
+ // be on purpose, though; if it stops working with future versions of
+ // unicows.dll, we can override unicows hooks by setting
+ // Unicows_{Set,Get}WindowLong and Unicows_RegisterClass to our own
+ // versions that keep track of fake<->real wnd proc mapping.
+
+ // On WinCE (at least), the wndproc comparison doesn't work,
+ // so have to use something like this.
+#ifdef __WXWINCE__
+ extern const wxChar *wxCanvasClassName;
+ extern const wxChar *wxCanvasClassNameNR;
+ extern const wxChar *wxMDIFrameClassName;
+ extern const wxChar *wxMDIFrameClassNameNoRedraw;
+ extern const wxChar *wxMDIChildFrameClassName;
+ extern const wxChar *wxMDIChildFrameClassNameNoRedraw;
+ wxString str(wxGetWindowClass(hWnd));
+ if (str == wxCanvasClassName ||
+ str == wxCanvasClassNameNR ||
+ str == wxMDIFrameClassName ||
+ str == wxMDIFrameClassNameNoRedraw ||
+ str == wxMDIChildFrameClassName ||
+ str == wxMDIChildFrameClassNameNoRedraw ||
+ str == _T("wxTLWHiddenParent"))
+ return TRUE; // Effectively means don't subclass
+ else
+ return FALSE;
+#else
+ WNDCLASS cls;
+ if ( !::GetClassInfo(wxGetInstance(), wxGetWindowClass(hWnd), &cls) )
{
- if ( style & wxSUNKEN_BORDER )
- exStyle |= WS_EX_CLIENTEDGE;
- if ( style & wxDOUBLE_BORDER )
- exStyle |= WS_EX_DLGMODALFRAME;
-#if defined(__WIN95__)
- if ( style & wxRAISED_BORDER )
- // It seems that WS_EX_WINDOWEDGE doesn't work, but WS_EX_DLGMODALFRAME does
- exStyle |= WS_EX_DLGMODALFRAME; /* WS_EX_WINDOWEDGE */;
- if ( style & wxSTATIC_BORDER )
- exStyle |= WS_EX_STATICEDGE;
-#endif
+ wxLogLastError(_T("GetClassInfo"));
+
+ return FALSE;
}
- return exStyle;
+
+ return wndProc == (WXFARPROC)cls.lpfnWndProc;
+#endif
}
-// Determines whether native 3D effects or CTL3D should be used,
-// applying a default border style if required, and returning an extended
-// style to pass to CreateWindowEx.
-WXDWORD wxWindowMSW::Determine3DEffects(WXDWORD defaultBorderStyle,
- bool *want3D) const
-{
- // If matches certain criteria, then assume no 3D effects
- // unless specifically requested (dealt with in MakeExtendedStyle)
- if ( !GetParent()
-#if wxUSE_CONTROLS
- || !IsKindOf(CLASSINFO(wxControl))
-#endif // wxUSE_CONTROLS
- || (m_windowStyle & wxNO_BORDER) )
- {
- *want3D = FALSE;
- return MakeExtendedStyle(m_windowStyle, FALSE);
- }
+// ----------------------------------------------------------------------------
+// Style handling
+// ----------------------------------------------------------------------------
- // Determine whether we should be using 3D effects or not.
- bool nativeBorder = FALSE; // by default, we don't want a Win95 effect
+void wxWindowMSW::SetWindowStyleFlag(long flags)
+{
+ long flagsOld = GetWindowStyleFlag();
+ if ( flags == flagsOld )
+ return;
- // 1) App can specify global 3D effects
- *want3D = wxTheApp->GetAuto3D();
+ // update the internal variable
+ wxWindowBase::SetWindowStyleFlag(flags);
- // 2) If the parent is being drawn with user colours, or simple border specified,
- // switch effects off. TODO: replace wxUSER_COLOURS with wxNO_3D
- if ( GetParent() && (GetParent()->GetWindowStyleFlag() & wxUSER_COLOURS) || (m_windowStyle & wxSIMPLE_BORDER) )
- *want3D = FALSE;
+ // now update the Windows style as well if needed - and if the window had
+ // been already created
+ if ( !GetHwnd() )
+ return;
- // 3) Control can override this global setting by defining
- // a border style, e.g. wxSUNKEN_BORDER
- if ( m_windowStyle & wxSUNKEN_BORDER )
- *want3D = TRUE;
+ WXDWORD exstyle, exstyleOld;
+ long style = MSWGetStyle(flags, &exstyle),
+ styleOld = MSWGetStyle(flagsOld, &exstyleOld);
- // 4) If it's a special border, CTL3D can't cope so we want a native border
- if ( (m_windowStyle & wxDOUBLE_BORDER) || (m_windowStyle & wxRAISED_BORDER) ||
- (m_windowStyle & wxSTATIC_BORDER) )
+ if ( style != styleOld )
{
- *want3D = TRUE;
- nativeBorder = TRUE;
+ // some flags (e.g. WS_VISIBLE or WS_DISABLED) should not be changed by
+ // this function so instead of simply setting the style to the new
+ // value we clear the bits which were set in styleOld but are set in
+ // the new one and set the ones which were not set before
+ long styleReal = ::GetWindowLong(GetHwnd(), GWL_STYLE);
+ styleReal &= ~styleOld;
+ styleReal |= style;
+
+ ::SetWindowLong(GetHwnd(), GWL_STYLE, styleReal);
}
- // 5) If this isn't a Win95 app, and we are using CTL3D, remove border
- // effects from extended style
-#if wxUSE_CTL3D
- if ( *want3D )
- nativeBorder = FALSE;
-#endif
-
- DWORD exStyle = MakeExtendedStyle(m_windowStyle, !nativeBorder);
+ // and the extended style
+ if ( exstyle != exstyleOld )
+ {
+ long exstyleReal = ::GetWindowLong(GetHwnd(), GWL_EXSTYLE);
+ exstyleReal &= ~exstyleOld;
+ exstyleReal |= exstyle;
- // If we want 3D, but haven't specified a border here,
- // apply the default border style specified.
- // TODO what about non-Win95 WIN32? Does it have borders?
-#if defined(__WIN95__) && !wxUSE_CTL3D
- if ( defaultBorderStyle && (*want3D) && ! ((m_windowStyle & wxDOUBLE_BORDER) || (m_windowStyle & wxRAISED_BORDER ) ||
- (m_windowStyle & wxSTATIC_BORDER) || (m_windowStyle & wxSIMPLE_BORDER) ))
- exStyle |= defaultBorderStyle; // WS_EX_CLIENTEDGE;
-#endif
+ ::SetWindowLong(GetHwnd(), GWL_EXSTYLE, exstyleReal);
- return exStyle;
+ // we must call SetWindowPos() to flash the cached extended style and
+ // also to make the change to wxSTAY_ON_TOP style take effect: just
+ // setting the style simply doesn't work
+ if ( !::SetWindowPos(GetHwnd(),
+ exstyleReal & WS_EX_TOPMOST ? HWND_TOPMOST
+ : HWND_NOTOPMOST,
+ 0, 0, 0, 0,
+ SWP_NOMOVE | SWP_NOSIZE) )
+ {
+ wxLogLastError(_T("SetWindowPos"));
+ }
+ }
}
-#if WXWIN_COMPATIBILITY
-// If nothing defined for this, try the parent.
-// E.g. we may be a button loaded from a resource, with no callback function
-// defined.
-void wxWindowMSW::OnCommand(wxWindow& win, wxCommandEvent& event)
+WXDWORD wxWindowMSW::MSWGetStyle(long flags, WXDWORD *exstyle) const
{
- if ( GetEventHandler()->ProcessEvent(event) )
- return;
- if ( m_parent )
- m_parent->GetEventHandler()->OnCommand(win, event);
-}
-#endif // WXWIN_COMPATIBILITY_2
+ // translate the style
+ WXDWORD style = WS_CHILD | WS_VISIBLE;
-#if WXWIN_COMPATIBILITY
-wxObject* wxWindowMSW::GetChild(int number) const
-{
- // Return a pointer to the Nth object in the Panel
- wxNode *node = GetChildren().First();
- int n = number;
- while (node && n--)
- node = node->Next();
- if ( node )
+ if ( flags & wxCLIP_CHILDREN )
+ style |= WS_CLIPCHILDREN;
+
+ if ( flags & wxCLIP_SIBLINGS )
+ style |= WS_CLIPSIBLINGS;
+
+ if ( flags & wxVSCROLL )
+ style |= WS_VSCROLL;
+
+ if ( flags & wxHSCROLL )
+ style |= WS_HSCROLL;
+
+ const wxBorder border = GetBorder(flags);
+
+ // WS_BORDER is only required for wxBORDER_SIMPLE
+ if ( border == wxBORDER_SIMPLE )
+ style |= WS_BORDER;
+
+ // now deal with ext style if the caller wants it
+ if ( exstyle )
{
- wxObject *obj = (wxObject *)node->Data();
- return(obj);
+ *exstyle = 0;
+
+#ifndef __WXWINCE__
+ if ( flags & wxTRANSPARENT_WINDOW )
+ *exstyle |= WS_EX_TRANSPARENT;
+#endif
+
+ switch ( border )
+ {
+ default:
+ case wxBORDER_DEFAULT:
+ wxFAIL_MSG( _T("unknown border style") );
+ // fall through
+
+ case wxBORDER_NONE:
+ case wxBORDER_SIMPLE:
+ break;
+
+ case wxBORDER_STATIC:
+ *exstyle |= WS_EX_STATICEDGE;
+ break;
+
+ case wxBORDER_RAISED:
+ *exstyle |= WS_EX_DLGMODALFRAME;
+ break;
+
+ case wxBORDER_SUNKEN:
+ *exstyle |= WS_EX_CLIENTEDGE;
+ style &= ~WS_BORDER;
+ break;
+
+ case wxBORDER_DOUBLE:
+ *exstyle |= WS_EX_DLGMODALFRAME;
+ break;
+ }
+
+ // wxUniv doesn't use Windows dialog navigation functions at all
+#if !defined(__WXUNIVERSAL__) && !defined(__WXWINCE__)
+ // to make the dialog navigation work with the nested panels we must
+ // use this style (top level windows such as dialogs don't need it)
+ if ( (flags & wxTAB_TRAVERSAL) && !IsTopLevel() )
+ {
+ *exstyle |= WS_EX_CONTROLPARENT;
+ }
+#endif // __WXUNIVERSAL__
}
- else
- return NULL;
+
+ return style;
}
-#endif // WXWIN_COMPATIBILITY
// Setup background and foreground colours correctly
void wxWindowMSW::SetupColours()
return hwnd != NULL;
}
-void wxWindowMSW::OnIdle(wxIdleEvent& WXUNUSED(event))
+void wxWindowMSW::OnInternalIdle()
{
// Check if we need to send a LEAVE event
if ( m_mouseInWindow )
{
+ // note that we should generate the leave event whether the window has
+ // or doesn't have mouse capture
if ( !IsMouseInWindow() )
{
// Generate a LEAVE event
m_mouseInWindow = FALSE;
// Unfortunately the mouse button and keyboard state may have
- // changed by the time the OnIdle function is called, so 'state'
+ // changed by the time the OnInternalIdle function is called, so 'state'
// may be meaningless.
int state = 0;
if ( wxIsShiftDown() )
// we need to have client coordinates here for symmetry with
// wxEVT_ENTER_WINDOW
- RECT rect;
- if ( !::GetWindowRect(GetHwnd(), &rect) )
- {
- wxLogLastError(_T("GetWindowRect"));
- }
+ RECT rect = wxGetWindowRect(GetHwnd());
pt.x -= rect.left;
pt.y -= rect.top;
}
}
- UpdateWindowUI();
+ if (wxUpdateUIEvent::CanUpdate(this))
+ UpdateWindowUI(wxUPDATE_UI_FROMIDLE);
}
// Set this window to be the child of 'parent'.
::SetParent(hWndChild, hWndParent);
- return TRUE;
-}
+#ifndef __WXWINCE__
+ if ( ::GetWindowLong(hWndChild, GWL_EXSTYLE) & WS_EX_CONTROLPARENT )
+ {
+ EnsureParentHasControlParentStyle(GetParent());
+ }
+#endif // !__WXWINCE__
-void wxWindowMSW::Clear()
-{
- wxClientDC dc((wxWindow *)this);
- wxBrush brush(GetBackgroundColour(), wxSOLID);
- dc.SetBackground(brush);
- dc.Clear();
+ return TRUE;
}
static inline void SendSetRedraw(HWND hwnd, bool on)
{
+#ifndef __WXMICROWIN__
::SendMessage(hwnd, WM_SETREDRAW, (WPARAM)on, 0);
+#endif
}
void wxWindowMSW::Freeze()
wxLogLastError(_T("UpdateWindow"));
}
-#if defined(__WIN32__) && !defined(__WXMICROWIN__)
+#if !defined(__WXMICROWIN__) && !defined(__WXWINCE__)
// just calling UpdateWindow() is not enough, what we did in our WM_PAINT
// handler needs to be really drawn right now
(void)::GdiFlush();
// drag and drop
// ---------------------------------------------------------------------------
-#if wxUSE_DRAG_AND_DROP
+#if wxUSE_DRAG_AND_DROP
void wxWindowMSW::SetDropTarget(wxDropTarget *pDropTarget)
{
if ( m_dropTarget != 0 ) {
if ( m_dropTarget != 0 )
m_dropTarget->Register(m_hWnd);
}
-
#endif // wxUSE_DRAG_AND_DROP
// old style file-manager drag&drop support: we retain the old-style
// DragAcceptFiles in parallel with SetDropTarget.
void wxWindowMSW::DragAcceptFiles(bool accept)
{
+#if !defined(__WXWINCE__)
HWND hWnd = GetHwnd();
if ( hWnd )
::DragAcceptFiles(hWnd, (BOOL)accept);
+#endif
}
// ----------------------------------------------------------------------------
wxWindowBase::DoSetToolTip(tooltip);
if ( m_tooltip )
- m_tooltip->SetWindow(this);
+ m_tooltip->SetWindow((wxWindow *)this);
}
#endif // wxUSE_TOOLTIPS
// Get total size
void wxWindowMSW::DoGetSize(int *x, int *y) const
{
- HWND hWnd = GetHwnd();
- RECT rect;
-#ifdef __WIN16__
- ::GetWindowRect(hWnd, &rect);
-#else
- if ( !::GetWindowRect(hWnd, &rect) )
- {
- wxLogLastError(_T("GetWindowRect"));
- }
-#endif
+ RECT rect = wxGetWindowRect(GetHwnd());
+
if ( x )
*x = rect.right - rect.left;
if ( y )
*y = rect.bottom - rect.top;
}
-void wxWindowMSW::DoGetPosition(int *x, int *y) const
+// Get size *available for subwindows* i.e. excluding menu bar etc.
+void wxWindowMSW::DoGetClientSize(int *x, int *y) const
{
- HWND hWnd = GetHwnd();
+ RECT rect = wxGetClientRect(GetHwnd());
- RECT rect;
- GetWindowRect(hWnd, &rect);
+ if ( x )
+ *x = rect.right;
+ if ( y )
+ *y = rect.bottom;
+}
+
+void wxWindowMSW::DoGetPosition(int *x, int *y) const
+{
+ RECT rect = wxGetWindowRect(GetHwnd());
POINT point;
point.x = rect.left;
if ( y )
pt.y = *y;
- HWND hWnd = GetHwnd();
- ::ScreenToClient(hWnd, &pt);
+ ::ScreenToClient(GetHwnd(), &pt);
if ( x )
*x = pt.x;
if ( y )
pt.y = *y;
- HWND hWnd = GetHwnd();
- ::ClientToScreen(hWnd, &pt);
+ ::ClientToScreen(GetHwnd(), &pt);
if ( x )
*x = pt.x;
*y = pt.y;
}
-// Get size *available for subwindows* i.e. excluding menu bar etc.
-void wxWindowMSW::DoGetClientSize(int *x, int *y) const
-{
- HWND hWnd = GetHwnd();
- RECT rect;
- ::GetClientRect(hWnd, &rect);
- if ( x )
- *x = rect.right;
- if ( y )
- *y = rect.bottom;
-}
-
void wxWindowMSW::DoMoveWindow(int x, int y, int width, int height)
{
+ // TODO: is this consistent with other platforms?
+ // Still, negative width or height shouldn't be allowed
+ if (width < 0)
+ width = 0;
+ if (height < 0)
+ height = 0;
if ( !::MoveWindow(GetHwnd(), x, y, width, height, TRUE) )
{
wxLogLastError(wxT("MoveWindow"));
void wxWindowMSW::DoSetClientSize(int width, int height)
{
- wxWindow *parent = GetParent();
- HWND hWnd = GetHwnd();
- HWND hParentWnd = (HWND) 0;
- if ( parent )
- hParentWnd = (HWND) parent->GetHWND();
-
- RECT rect;
- ::GetClientRect(hWnd, &rect);
+ // setting the client size is less obvious than it it could have been
+ // because in the result of changing the total size the window scrollbar
+ // may [dis]appear and/or its menubar may [un]wrap and so the client size
+ // will not be correct as the difference between the total and client size
+ // changes - so we keep changing it until we get it right
+ //
+ // normally this loop shouldn't take more than 3 iterations (usually 1 but
+ // if scrollbars [dis]appear as the result of the first call, then 2 and it
+ // may become 3 if the window had 0 size originally and so we didn't
+ // calculate the scrollbar correction correctly during the first iteration)
+ // but just to be on the safe side we check for it instead of making it an
+ // "infinite" loop (i.e. leaving break inside as the only way to get out)
+ for ( int i = 0; i < 4; i++ )
+ {
+ RECT rectClient;
+ ::GetClientRect(GetHwnd(), &rectClient);
+
+ // if the size is already ok, stop here (rectClient.left = top = 0)
+ if ( (rectClient.right == width || width == -1) &&
+ (rectClient.bottom == height || height == -1) )
+ {
+ break;
+ }
- RECT rect2;
- GetWindowRect(hWnd, &rect2);
+ int widthClient = width,
+ heightClient = height;
- // Find the difference between the entire window (title bar and all)
- // and the client area; add this to the new client size to move the
- // window
- int actual_width = rect2.right - rect2.left - rect.right + width;
- int actual_height = rect2.bottom - rect2.top - rect.bottom + height;
+ // Find the difference between the entire window (title bar and all)
+ // and the client area; add this to the new client size to move the
+ // window
+ RECT rectWin;
+ ::GetWindowRect(GetHwnd(), &rectWin);
- // If there's a parent, must subtract the parent's top left corner
- // since MoveWindow moves relative to the parent
+ widthClient += rectWin.right - rectWin.left - rectClient.right;
+ heightClient += rectWin.bottom - rectWin.top - rectClient.bottom;
- POINT point;
- point.x = rect2.left;
- point.y = rect2.top;
- if ( parent )
- {
- ::ScreenToClient(hParentWnd, &point);
- }
+ POINT point;
+ point.x = rectWin.left;
+ point.y = rectWin.top;
- DoMoveWindow(point.x, point.y, actual_width, actual_height);
+ // MoveWindow positions the child windows relative to the parent, so
+ // adjust if necessary
+ if ( !IsTopLevel() )
+ {
+ wxWindow *parent = GetParent();
+ if ( parent )
+ {
+ ::ScreenToClient(GetHwndOf(parent), &point);
+ }
+ }
- wxSizeEvent event(wxSize(width, height), m_windowId);
- event.SetEventObject(this);
- GetEventHandler()->ProcessEvent(event);
+ DoMoveWindow(point.x, point.y, widthClient, heightClient);
+ }
}
// For implementation purposes - sometimes decorations make the client area
return wxPoint(0, 0);
}
-// Makes an adjustment to the window position (for example, a frame that has
-// a toolbar that it manages itself).
-void wxWindowMSW::AdjustForParentClientOrigin(int& x, int& y, int sizeFlags)
-{
- // don't do it for the dialogs/frames - they float independently of their
- // parent
- if ( !IsTopLevel() )
- {
- wxWindow *parent = GetParent();
- if ( !(sizeFlags & wxSIZE_NO_ADJUSTMENTS) && parent )
- {
- wxPoint pt(parent->GetClientAreaOrigin());
- x += pt.x;
- y += pt.y;
- }
- }
-}
-
// ---------------------------------------------------------------------------
// text metrics
// ---------------------------------------------------------------------------
*externalLeading = tm.tmExternalLeading;
}
-#if wxUSE_CARET && WXWIN_COMPATIBILITY
-// ---------------------------------------------------------------------------
-// Caret manipulation
-// ---------------------------------------------------------------------------
-
-void wxWindowMSW::CreateCaret(int w, int h)
-{
- SetCaret(new wxCaret(this, w, h));
-}
-
-void wxWindowMSW::CreateCaret(const wxBitmap *WXUNUSED(bitmap))
-{
- wxFAIL_MSG("not implemented");
-}
-
-void wxWindowMSW::ShowCaret(bool show)
-{
- wxCHECK_RET( m_caret, "no caret to show" );
-
- m_caret->Show(show);
-}
-
-void wxWindowMSW::DestroyCaret()
-{
- SetCaret(NULL);
-}
-
-void wxWindowMSW::SetCaretPos(int x, int y)
-{
- wxCHECK_RET( m_caret, "no caret to move" );
-
- m_caret->Move(x, y);
-}
-
-void wxWindowMSW::GetCaretPos(int *x, int *y) const
-{
- wxCHECK_RET( m_caret, "no caret to get position of" );
-
- m_caret->GetPosition(x, y);
-}
-#endif // wxUSE_CARET
-
// ---------------------------------------------------------------------------
// popup menu
// ---------------------------------------------------------------------------
+#if wxUSE_MENUS_NATIVE
+
// yield for WM_COMMAND events only, i.e. process all WM_COMMANDs in the queue
// immediately, without waiting for the next event loop iteration
//
{
wxTheApp->DoMessage((WXMSG *)&msg);
}
-}
-#if wxUSE_MENUS_NATIVE
+ // If we retrieved a WM_QUIT, insert back into the message queue.
+ if (msg.message == WM_QUIT)
+ ::PostQuitMessage(0);
+}
bool wxWindowMSW::DoPopupMenu(wxMenu *menu, int x, int y)
{
point.y = y;
::ClientToScreen(hWnd, &point);
wxCurrentPopupMenu = menu;
- ::TrackPopupMenu(hMenu, TPM_RIGHTBUTTON, point.x, point.y, 0, hWnd, NULL);
+ UINT flags = 0;
+#if !defined(__WXWINCE__)
+ flags = TPM_RIGHTBUTTON;
+#endif
+ ::TrackPopupMenu(hMenu, flags, point.x, point.y, 0, hWnd, NULL);
// we need to do it righ now as otherwise the events are never going to be
// sent to wxCurrentPopupMenu from HandleCommand()
// here we try to do all the job which ::IsDialogMessage() usually does
// internally
#if 1
- bool bProcess = TRUE;
- if ( msg->message != WM_KEYDOWN )
- bProcess = FALSE;
-
- if ( bProcess && (HIWORD(msg->lParam) & KF_ALTDOWN) == KF_ALTDOWN )
- bProcess = FALSE;
-
- if ( bProcess )
+ if ( msg->message == WM_KEYDOWN )
{
bool bCtrlDown = wxIsCtrlDown();
bool bShiftDown = wxIsShiftDown();
if ( !bCtrlDown )
{
lDlgCode = ::SendMessage(msg->hwnd, WM_GETDLGCODE, 0, 0);
+
+ // surprizingly, DLGC_WANTALLKEYS bit mask doesn't contain the
+ // DLGC_WANTTAB nor DLGC_WANTARROWS bits although, logically,
+ // it, of course, implies them
+ if ( lDlgCode & DLGC_WANTALLKEYS )
+ {
+ lDlgCode |= DLGC_WANTTAB | DLGC_WANTARROWS;
+ }
}
bool bForward = TRUE,
bWindowChange = FALSE;
+ // should we process this message specially?
+ bool bProcess = TRUE;
switch ( msg->wParam )
{
case VK_TAB:
return TRUE;
}
else // no default button
-#endif // wxUSE_BUTTON
{
- // no special function for enter and don't even
- // let IsDialogMessage() have it: it seems to
- // do something really strange with it
- return FALSE;
+#endif // wxUSE_BUTTON
+ // this is a quick and dirty test for a text
+ // control
+ if ( !(lDlgCode & DLGC_HASSETSEL) )
+ {
+ // don't process Enter, the control might
+ // need it for itself and don't let
+ // ::IsDialogMessage() have it as it can
+ // eat the Enter events sometimes
+ return FALSE;
+ }
+ else if (!IsTopLevel())
+ {
+ // if not a top level window, let parent
+ // handle it
+ return FALSE;
+ }
+ //else: treat Enter as TAB: pass to the next
+ // control as this is the best thing to do
+ // if the text doesn't handle Enter itself
}
}
}
}
#endif // 1/0
- if ( ::IsDialogMessage(GetHwnd(), msg) )
+ // we handle VK_ESCAPE ourselves in wxDialog::OnCharHook() and we
+ // shouldn't let IsDialogMessage() get it as it _always_ eats the
+ // message even when there is no cancel button and when the message is
+ // needed by the control itself: in particular, it prevents the tree in
+ // place edit control from being closed with Escape in a dialog
+ if ( msg->message != WM_KEYDOWN || msg->wParam != VK_ESCAPE )
{
- // IsDialogMessage() did something...
- return TRUE;
+ // ::IsDialogMessage() is broken and may sometimes hang the
+ // application by going into an infinite loop, so we try to detect
+ // [some of] the situatations when this may happen and not call it
+ // then
+
+ // assume we can call it by default
+ bool canSafelyCallIsDlgMsg = TRUE;
+
+ HWND hwndFocus = ::GetFocus();
+
+ // if the currently focused window itself has WS_EX_CONTROLPARENT style, ::IsDialogMessage() will also enter
+ // an infinite loop, because it will recursively check the child
+ // windows but not the window itself and so if none of the children
+ // accepts focus it loops forever (as it only stops when it gets
+ // back to the window it started from)
+ //
+ // while it is very unusual that a window with WS_EX_CONTROLPARENT
+ // style has the focus, it can happen. One such possibility is if
+ // all windows are either toplevel, wxDialog, wxPanel or static
+ // controls and no window can actually accept keyboard input.
+#if !defined(__WXWINCE__)
+ if ( ::GetWindowLong(hwndFocus, GWL_EXSTYLE) & WS_EX_CONTROLPARENT )
+ {
+ // passimistic by default
+ canSafelyCallIsDlgMsg = FALSE;
+ for ( wxWindowList::compatibility_iterator node = GetChildren().GetFirst();
+ node;
+ node = node->GetNext() )
+ {
+ wxWindow * const win = node->GetData();
+ if ( win->AcceptsFocus() &&
+ !(::GetWindowLong(GetHwndOf(win), GWL_EXSTYLE) &
+ WS_EX_CONTROLPARENT) )
+ {
+ // it shouldn't hang...
+ canSafelyCallIsDlgMsg = TRUE;
+
+ break;
+ }
+ }
+ }
+#endif // !__WXWINCE__
+
+ if ( canSafelyCallIsDlgMsg )
+ {
+ // ::IsDialogMessage() can enter in an infinite loop when the
+ // currently focused window is disabled or hidden and its
+ // parent has WS_EX_CONTROLPARENT style, so don't call it in
+ // this case
+ while ( hwndFocus )
+ {
+ if ( !::IsWindowEnabled(hwndFocus) ||
+ !::IsWindowVisible(hwndFocus) )
+ {
+ // it would enter an infinite loop if we do this!
+ canSafelyCallIsDlgMsg = FALSE;
+
+ break;
+ }
+
+ if ( !(::GetWindowLong(hwndFocus, GWL_STYLE) & WS_CHILD) )
+ {
+ // it's a top level window, don't go further -- e.g. even
+ // if the parent of a dialog is disabled, this doesn't
+ // break navigation inside the dialog
+ break;
+ }
+
+ hwndFocus = ::GetParent(hwndFocus);
+ }
+ }
+
+ // let IsDialogMessage() have the message if it's safe to call it
+ if ( canSafelyCallIsDlgMsg && ::IsDialogMessage(GetHwnd(), msg) )
+ {
+ // IsDialogMessage() did something...
+ return TRUE;
+ }
}
}
#endif // __WXUNIVERSAL__
#if wxUSE_ACCEL && !defined(__WXUNIVERSAL__)
return m_acceleratorTable.Translate(this, pMsg);
#else
+ (void) pMsg;
return FALSE;
#endif // wxUSE_ACCEL
}
-bool wxWindowMSW::MSWShouldPreProcessMessage(WXMSG* pMsg)
+bool wxWindowMSW::MSWShouldPreProcessMessage(WXMSG* WXUNUSED(pMsg))
{
// preprocess all messages by default
return TRUE;
}
// ---------------------------------------------------------------------------
-// message params unpackers (different for Win16 and Win32)
+// message params unpackers
// ---------------------------------------------------------------------------
-#ifdef __WIN32__
-
void wxWindowMSW::UnpackCommand(WXWPARAM wParam, WXLPARAM lParam,
WORD *id, WXHWND *hwnd, WORD *cmd)
{
*hmenu = (WXHMENU)lParam;
}
-#else // Win16
-
-void wxWindowMSW::UnpackCommand(WXWPARAM wParam, WXLPARAM lParam,
- WXWORD *id, WXHWND *hwnd, WXWORD *cmd)
-{
- *id = (WXWORD)wParam;
- *hwnd = (WXHWND)LOWORD(lParam);
- *cmd = HIWORD(lParam);
-}
-
-void wxWindowMSW::UnpackActivate(WXWPARAM wParam, WXLPARAM lParam,
- WXWORD *state, WXWORD *minimized, WXHWND *hwnd)
-{
- *state = (WXWORD)wParam;
- *minimized = LOWORD(lParam);
- *hwnd = (WXHWND)HIWORD(lParam);
-}
+// ---------------------------------------------------------------------------
+// Main wxWindows window proc and the window proc for wxWindow
+// ---------------------------------------------------------------------------
-void wxWindowMSW::UnpackScroll(WXWPARAM wParam, WXLPARAM lParam,
- WXWORD *code, WXWORD *pos, WXHWND *hwnd)
-{
- *code = (WXWORD)wParam;
- *pos = LOWORD(lParam);
- *hwnd = (WXHWND)HIWORD(lParam);
-}
+// Hook for new window just as it's being created, when the window isn't yet
+// associated with the handle
+static wxWindowMSW *gs_winBeingCreated = NULL;
-void wxWindowMSW::UnpackCtlColor(WXWPARAM wParam, WXLPARAM lParam,
- WXWORD *nCtlColor, WXHDC *hdc, WXHWND *hwnd)
+// implementation of wxWindowCreationHook class: it just sets gs_winBeingCreated to the
+// window being created and insures that it's always unset back later
+wxWindowCreationHook::wxWindowCreationHook(wxWindowMSW *winBeingCreated)
{
- *hwnd = (WXHWND)LOWORD(lParam);
- *nCtlColor = (int)HIWORD(lParam);
- *hdc = (WXHDC)wParam;
+ gs_winBeingCreated = winBeingCreated;
}
-void wxWindowMSW::UnpackMenuSelect(WXWPARAM wParam, WXLPARAM lParam,
- WXWORD *item, WXWORD *flags, WXHMENU *hmenu)
+wxWindowCreationHook::~wxWindowCreationHook()
{
- *item = (WXWORD)wParam;
- *flags = LOWORD(lParam);
- *hmenu = (WXHMENU)HIWORD(lParam);
+ gs_winBeingCreated = NULL;
}
-#endif // Win32/16
-
-// ---------------------------------------------------------------------------
-// Main wxWindows window proc and the window proc for wxWindow
-// ---------------------------------------------------------------------------
-
-// Hook for new window just as it's being created, when the window isn't yet
-// associated with the handle
-wxWindowMSW *wxWndHook = NULL;
-
// Main window proc
LRESULT WXDLLEXPORT APIENTRY _EXPORT wxWndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
// trace all messages - useful for the debugging
#ifdef __WXDEBUG__
- wxLogTrace(wxTraceMessages, wxT("Processing %s(wParam=%8lx, lParam=%8lx)"),
- wxGetMessageName(message), wParam, lParam);
+ wxLogTrace(wxTraceMessages,
+ wxT("Processing %s(hWnd=%08lx, wParam=%8lx, lParam=%8lx)"),
+ wxGetMessageName(message), (long)hWnd, (long)wParam, lParam);
#endif // __WXDEBUG__
wxWindowMSW *wnd = wxFindWinFromHandle((WXHWND) hWnd);
// when we get the first message for the HWND we just created, we associate
- // it with wxWindow stored in wxWndHook
- if ( !wnd && wxWndHook )
+ // it with wxWindow stored in gs_winBeingCreated
+ if ( !wnd && gs_winBeingCreated )
{
-#if 0 // def __WXDEBUG__
- char buf[512];
- ::GetClassNameA((HWND) hWnd, buf, 512);
- wxString className(buf);
-#endif
-
- wxAssociateWinWithHandle(hWnd, wxWndHook);
- wnd = wxWndHook;
- wxWndHook = NULL;
+ wxAssociateWinWithHandle(hWnd, gs_winBeingCreated);
+ wnd = gs_winBeingCreated;
+ gs_winBeingCreated = NULL;
wnd->SetHWND((WXHWND)hWnd);
}
LRESULT rc;
- // Stop right here if we don't have a valid handle in our wxWindow object.
- if ( wnd && !wnd->GetHWND() )
- {
- // FIXME: why do we do this?
- wnd->SetHWND((WXHWND) hWnd);
- rc = wnd->MSWDefWindowProc(message, wParam, lParam );
- wnd->SetHWND(0);
- }
+ if ( wnd )
+ rc = wnd->MSWWindowProc(message, wParam, lParam);
else
- {
- if ( wnd )
- rc = wnd->MSWWindowProc(message, wParam, lParam);
- else
- rc = DefWindowProc( hWnd, message, wParam, lParam );
- }
+ rc = ::DefWindowProc(hWnd, message, wParam, lParam);
return rc;
}
processed = HandleMove(GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam));
break;
+#if !defined(__WXWINCE__)
+ case WM_MOVING:
+ {
+ LPRECT pRect = (LPRECT)lParam;
+ wxRect rc;
+ rc.SetLeft(pRect->left);
+ rc.SetTop(pRect->top);
+ rc.SetRight(pRect->right);
+ rc.SetBottom(pRect->bottom);
+ processed = HandleMoving(rc);
+ if (processed) {
+ pRect->left = rc.GetLeft();
+ pRect->top = rc.GetTop();
+ pRect->right = rc.GetRight();
+ pRect->bottom = rc.GetBottom();
+ }
+ }
+ break;
+#endif
+
case WM_SIZE:
switch ( wParam )
{
}
break;
-#ifndef __WXMICROWIN__
+#if !defined(__WXWINCE__)
+ case WM_SIZING:
+ {
+ LPRECT pRect = (LPRECT)lParam;
+ wxRect rc;
+ rc.SetLeft(pRect->left);
+ rc.SetTop(pRect->top);
+ rc.SetRight(pRect->right);
+ rc.SetBottom(pRect->bottom);
+ processed = HandleSizing(rc);
+ if (processed) {
+ pRect->left = rc.GetLeft();
+ pRect->top = rc.GetTop();
+ pRect->right = rc.GetRight();
+ pRect->bottom = rc.GetBottom();
+ }
+ }
+ break;
+#endif
+
+#if !defined(__WXMICROWIN__) && !defined(__WXWINCE__)
case WM_ACTIVATEAPP:
wxTheApp->SetActive(wParam != 0, FindFocus());
break;
break;
case WM_PAINT:
- processed = HandlePaint();
+ {
+ if ( wParam )
+ {
+ // cast to wxWindow is needed for wxUniv
+ wxPaintDCEx dc((wxWindow *)this, (WXHDC)wParam);
+ processed = HandlePaint();
+ }
+ else
+ {
+ processed = HandlePaint();
+ }
+ break;
+ }
+
+ case WM_PRINT:
+ {
+ // Don't call the wx handlers in this case
+ if ( wxIsKindOf(this, wxListCtrl) )
+ break;
+
+ if ( lParam & PRF_ERASEBKGND )
+ HandleEraseBkgnd((WXHDC)(HDC)wParam);
+
+ wxPaintDCEx dc((wxWindow *)this, (WXHDC)wParam);
+ processed = HandlePaint();
+ }
break;
case WM_CLOSE:
+#ifdef __WXUNIVERSAL__
+ // Universal uses its own wxFrame/wxDialog, so we don't receive
+ // close events unless we have this.
+ Close();
+ processed = TRUE;
+ rc.result = TRUE;
+#else
// don't let the DefWindowProc() destroy our window - we'll do it
// ourselves in ~wxWindow
processed = TRUE;
rc.result = TRUE;
+#endif
break;
case WM_SHOWWINDOW:
case WM_MBUTTONDOWN:
case WM_MBUTTONUP:
case WM_MBUTTONDBLCLK:
- {
- processed = FALSE;
+ {
#ifdef __WXMICROWIN__
// MicroWindows seems to ignore the fact that a window is
// disabled. So catch mouse events and throw them away if
// necessary.
wxWindowMSW* win = this;
- while (win)
+ for ( ;; )
{
if (!win->IsEnabled())
{
processed = TRUE;
break;
}
+
win = win->GetParent();
- if (win && win->IsTopLevel())
+ if ( !win || win->IsTopLevel() )
break;
}
+
+ if ( processed )
+ break;
+
#endif // __WXMICROWIN__
- if (!processed)
+ int x = GET_X_LPARAM(lParam),
+ y = GET_Y_LPARAM(lParam);
+
+ // redirect the event to a static control if necessary by
+ // finding one under mouse
+ wxWindowMSW *win;
+ if ( GetCapture() == this )
{
- if (message == WM_LBUTTONDOWN && AcceptsFocus())
- SetFocus();
- processed = HandleMouseEvent(message,
- GET_X_LPARAM(lParam),
- GET_Y_LPARAM(lParam),
- wParam);
+ // but don't do it if the mouse is captured by this window
+ // because then it should really get this event itself
+ win = this;
}
- break;
- }
-
-#ifdef __WXMICROWIN__
- case WM_NCLBUTTONDOWN:
- case WM_NCLBUTTONUP:
- case WM_NCLBUTTONDBLCLK:
- case WM_NCRBUTTONDOWN:
- case WM_NCRBUTTONUP:
- case WM_NCRBUTTONDBLCLK:
-#if 0
- case WM_NCMBUTTONDOWN:
- case WM_NCMBUTTONUP:
- case WM_NCMBUTTONDBLCLK:
-#endif
- {
- // MicroWindows seems to ignore the fact that a window
- // is disabled. So catch mouse events and throw them away if necessary.
- processed = FALSE;
- wxWindowMSW* win = this;
- while (win)
+ else
{
- if (!win->IsEnabled())
+ win = FindWindowForMouseEvent(this, &x, &y);
+
+ // this should never happen
+ wxCHECK_MSG( win, 0,
+ _T("FindWindowForMouseEvent() returned NULL") );
+
+ // for the standard classes their WndProc sets the focus to
+ // them anyhow and doing it from here results in some weird
+ // problems, but for our windows we want them to acquire
+ // focus when clicked
+ if ( !win->IsOfStandardClass() )
{
- processed = TRUE;
- break;
+ if ( message == WM_LBUTTONDOWN && win->AcceptsFocus() )
+ win->SetFocus();
}
- win = win->GetParent();
- if (win && win->IsTopLevel())
- break;
}
- break;
+
+ processed = win->HandleMouseEvent(message, x, y, wParam);
}
-#endif // __WXMICROWIN__
+ break;
#ifdef MM_JOY1MOVE
case MM_JOY1MOVE:
}
break;
-#ifdef __WIN95__
case WM_NOTIFY:
processed = HandleNotify((int)wParam, lParam, &rc.result);
break;
-#endif // Win95
// for these messages we must return TRUE if process the message
#ifdef WM_DRAWITEM
#endif // defined(WM_DRAWITEM)
case WM_GETDLGCODE:
- if ( m_lDlgCode )
+ if ( !IsOfStandardClass() )
{
- rc.result = m_lDlgCode;
+ // we always want to get the char events
+ rc.result = DLGC_WANTCHARS;
+
+ if ( GetWindowStyleFlag() & wxWANTS_CHARS )
+ {
+ // in fact, we want everything
+ rc.result |= DLGC_WANTARROWS |
+ DLGC_WANTTAB |
+ DLGC_WANTALLKEYS;
+ }
+
processed = TRUE;
}
//else: get the dlg code from the DefWindowProc()
case WM_SYSKEYDOWN:
case WM_KEYDOWN:
- // If this has been processed by an event handler,
- // return 0 now (we've handled it).
- if ( HandleKeyDown((WORD) wParam, lParam) )
- {
- processed = TRUE;
-
- break;
- }
-
- // we consider these message "not interesting" to OnChar
- if ( wParam == VK_SHIFT || wParam == VK_CONTROL )
+ // If this has been processed by an event handler, return 0 now
+ // (we've handled it).
+ m_lastKeydownProcessed = HandleKeyDown((WORD) wParam, lParam);
+ if ( m_lastKeydownProcessed )
{
processed = TRUE;
-
- break;
}
- switch ( wParam )
+ if ( !processed )
{
- // avoid duplicate messages to OnChar for these ASCII keys: they
- // will be translated by TranslateMessage() and received in WM_CHAR
- case VK_ESCAPE:
- case VK_SPACE:
- case VK_RETURN:
- case VK_BACK:
- case VK_TAB:
- case VK_ADD:
- case VK_SUBTRACT:
- // but set processed to FALSE, not TRUE to still pass them to
- // the control's default window proc - otherwise built-in
- // keyboard handling won't work
- processed = FALSE;
+ switch ( wParam )
+ {
+ // we consider these message "not interesting" to OnChar, so
+ // just don't do anything more with them
+ case VK_SHIFT:
+ case VK_CONTROL:
+ case VK_MENU:
+ case VK_CAPITAL:
+ case VK_NUMLOCK:
+ case VK_SCROLL:
+ processed = TRUE;
+ break;
- break;
+ // avoid duplicate messages to OnChar for these ASCII keys:
+ // they will be translated by TranslateMessage() and received
+ // in WM_CHAR
+ case VK_ESCAPE:
+ case VK_SPACE:
+ case VK_RETURN:
+ case VK_BACK:
+ case VK_TAB:
+ case VK_ADD:
+ case VK_SUBTRACT:
+ case VK_MULTIPLY:
+ case VK_DIVIDE:
+ case VK_OEM_1:
+ case VK_OEM_2:
+ case VK_OEM_3:
+ case VK_OEM_4:
+ case VK_OEM_5:
+ case VK_OEM_6:
+ case VK_OEM_7:
+ case VK_OEM_PLUS:
+ case VK_OEM_COMMA:
+ case VK_OEM_MINUS:
+ case VK_OEM_PERIOD:
+ // but set processed to FALSE, not TRUE to still pass them
+ // to the control's default window proc - otherwise
+ // built-in keyboard handling won't work
+ processed = FALSE;
+ break;
#ifdef VK_APPS
- // special case of VK_APPS: treat it the same as right mouse
- // click because both usually pop up a context menu
- case VK_APPS:
- {
- WPARAM flags;
- int x, y;
+ // special case of VK_APPS: treat it the same as right mouse
+ // click because both usually pop up a context menu
+ case VK_APPS:
+ {
+ WPARAM flags;
+ int x, y;
- TranslateKbdEventToMouse(this, &x, &y, &flags);
- processed = HandleMouseEvent(WM_RBUTTONDOWN, x, y, flags);
- }
- break;
+ TranslateKbdEventToMouse(this, &x, &y, &flags);
+ processed = HandleMouseEvent(WM_RBUTTONDOWN, x, y, flags);
+ }
+ break;
#endif // VK_APPS
- case VK_LEFT:
- case VK_RIGHT:
- case VK_DOWN:
- case VK_UP:
- default:
- processed = HandleChar((WORD)wParam, lParam);
+ default:
+ // do generate a CHAR event
+ processed = HandleChar((WORD)wParam, lParam);
+ }
}
+ if (message == WM_SYSKEYDOWN) // Let Windows still handle the SYSKEYs
+ processed = FALSE;
break;
case WM_SYSKEYUP:
case WM_SYSCHAR:
case WM_CHAR: // Always an ASCII character
- processed = HandleChar((WORD)wParam, lParam, TRUE);
+ if ( m_lastKeydownProcessed )
+ {
+ // The key was handled in the EVT_KEY_DOWN and handling
+ // a key in an EVT_KEY_DOWN handler is meant, by
+ // design, to prevent EVT_CHARs from happening
+ m_lastKeydownProcessed = FALSE;
+ processed = TRUE;
+ }
+ else
+ {
+ processed = HandleChar((WORD)wParam, lParam, TRUE);
+ }
break;
+#if wxUSE_HOTKEY
+ case WM_HOTKEY:
+ processed = HandleHotKey((WORD)wParam, lParam);
+ break;
+#endif // wxUSE_HOTKEY
+
case WM_HSCROLL:
case WM_VSCROLL:
{
// CTLCOLOR messages are sent by children to query the parent for their
// colors#ifndef __WXMICROWIN__
#ifndef __WXMICROWIN__
-#ifdef __WIN32__
case WM_CTLCOLORMSGBOX:
case WM_CTLCOLOREDIT:
case WM_CTLCOLORLISTBOX:
case WM_CTLCOLORDLG:
case WM_CTLCOLORSCROLLBAR:
case WM_CTLCOLORSTATIC:
-#else // Win16
- case WM_CTLCOLOR:
-#endif // Win32/16
{
WXWORD nCtlColor;
WXHDC hdc;
break;
#endif // !__WXMICROWIN__
- // the return value for this message is ignored
case WM_SYSCOLORCHANGE:
+ // the return value for this message is ignored
processed = HandleSysColorChange();
break;
+#if !defined(__WXWINCE__)
+ case WM_DISPLAYCHANGE:
+ processed = HandleDisplayChange();
+ break;
+#endif
+
case WM_PALETTECHANGED:
processed = HandlePaletteChanged((WXHWND) (HWND) wParam);
break;
+ case WM_CAPTURECHANGED:
+ processed = HandleCaptureChanged((WXHWND) (HWND) lParam);
+ break;
+
case WM_QUERYNEWPALETTE:
processed = HandleQueryNewPalette();
break;
}
break;
+#if !defined(__WXWINCE__)
case WM_DROPFILES:
processed = HandleDropFiles(wParam);
break;
+#endif
case WM_INITDIALOG:
processed = HandleInitDialog((WXHWND)(HWND)wParam);
}
break;
+#if !defined(__WXWINCE__)
case WM_QUERYENDSESSION:
processed = HandleQueryEndSession(lParam, &rc.allow);
break;
case WM_GETMINMAXINFO:
processed = HandleGetMinMaxInfo((MINMAXINFO*)lParam);
break;
+#endif
case WM_SETCURSOR:
processed = HandleSetCursor((WXHWND)(HWND)wParam,
}
break;
-#if defined(__WIN32__) && defined(WM_HELP)
+#if wxUSE_ACCESSIBILITY
+ case WM_GETOBJECT:
+ {
+ //WPARAM dwFlags = (WPARAM) (DWORD) wParam;
+ LPARAM dwObjId = (LPARAM) (DWORD) lParam;
+
+ if (dwObjId == OBJID_CLIENT && GetOrCreateAccessible())
+ {
+ return LresultFromObject(IID_IAccessible, wParam, (IUnknown*) GetAccessible()->GetIAccessible());
+ }
+ break;
+ }
+#endif
+
+#if defined(WM_HELP)
case WM_HELP:
{
+ // HELPINFO doesn't seem to be supported on WinCE.
+#ifndef __WXWINCE__
HELPINFO* info = (HELPINFO*) lParam;
// Don't yet process menu help events, just windows
if (info->iContextType == HELPINFO_WINDOW)
{
+#endif
wxWindowMSW* subjectOfHelp = this;
bool eventProcessed = FALSE;
while (subjectOfHelp && !eventProcessed)
{
wxHelpEvent helpEvent(wxEVT_HELP,
subjectOfHelp->GetId(),
- wxPoint(info->MousePos.x,
- info->MousePos.y) );
+#ifdef __WXWINCE__
+ wxPoint(0, 0)
+#else
+ wxPoint(info->MousePos.x, info->MousePos.y)
+#endif
+ );
+
helpEvent.SetEventObject(this);
eventProcessed =
GetEventHandler()->ProcessEvent(helpEvent);
}
processed = eventProcessed;
+#ifndef __WXWINCE__
}
else if (info->iContextType == HELPINFO_MENUITEM)
{
}
//else: processed is already FALSE
+#endif
}
break;
+#endif
+#if !defined(__WXWINCE__)
case WM_CONTEXTMENU:
{
// we don't convert from screen to client coordinates as
processed = GetEventHandler()->ProcessEvent(evtCtx);
}
break;
-#endif // __WIN32__
+#endif
-#ifdef __WXUNIVERSAL__
- case WM_NCHITTEST:
- // we shouldn't allow the windows which don't want to get focus to
- // get it
- if ( !AcceptsFocus() )
+ case WM_MENUCHAR:
+ // we're only interested in our own menus, not MF_SYSMENU
+ if ( HIWORD(wParam) == MF_POPUP )
{
- rc.result = HTTRANSPARENT;
- processed = TRUE;
+ // handle menu chars for ownerdrawn menu items
+ int i = HandleMenuChar(toupper(LOWORD(wParam)), lParam);
+ if ( i != wxNOT_FOUND )
+ {
+ rc.result = MAKELRESULT(i, MNC_EXECUTE);
+ processed = TRUE;
+ }
}
break;
-#endif // __WXUNIVERSAL__
}
if ( !processed )
return rc.result;
}
-// Dialog window proc
-LONG APIENTRY _EXPORT
-wxDlgProc(HWND WXUNUSED(hWnd), UINT message, WPARAM WXUNUSED(wParam), LPARAM WXUNUSED(lParam))
-{
- if ( message == WM_INITDIALOG )
- {
- // for this message, returning TRUE tells system to set focus to the
- // first control in the dialog box
- return TRUE;
- }
- else
- {
- // for all the other ones, FALSE means that we didn't process the
- // message
- return 0;
- }
-}
+// ----------------------------------------------------------------------------
+// wxWindow <-> HWND map
+// ----------------------------------------------------------------------------
+
+wxWinHashTable *wxWinHandleHash = NULL;
-wxList *wxWinHandleList = NULL;
wxWindow *wxFindWinFromHandle(WXHWND hWnd)
{
- wxNode *node = wxWinHandleList->Find((long)hWnd);
- if ( !node )
- return NULL;
- return (wxWindow *)node->Data();
+ return wxWinHandleHash->Get((long)hWnd);
}
-#if 0 // def __WXDEBUG__
-static int gs_AssociationCount = 0;
-#endif
-
void wxAssociateWinWithHandle(HWND hWnd, wxWindowMSW *win)
{
// adding NULL hWnd is (first) surely a result of an error and
wxCHECK_RET( hWnd != (HWND)NULL,
wxT("attempt to add a NULL hWnd to window list ignored") );
-
wxWindow *oldWin = wxFindWinFromHandle((WXHWND) hWnd);
+#ifdef __WXDEBUG__
if ( oldWin && (oldWin != win) )
{
- wxString str(win->GetClassInfo()->GetClassName());
- wxLogError(wxT("Bug! Found existing HWND %X for new window of class %s"), (int) hWnd, (const wxChar*) str);
+ wxLogDebug(wxT("HWND %X already associated with another window (%s)"),
+ (int) hWnd, win->GetClassInfo()->GetClassName());
}
- else if (!oldWin)
+ else
+#endif // __WXDEBUG__
+ if (!oldWin)
{
-#if 0 // def __WXDEBUG__
- gs_AssociationCount ++;
- wxLogDebug("+ Association %d", gs_AssociationCount);
-#endif
-
- wxWinHandleList->Append((long)hWnd, win);
+ wxWinHandleHash->Put((long)hWnd, (wxWindow *)win);
}
}
void wxRemoveHandleAssociation(wxWindowMSW *win)
{
-#if 0 // def __WXDEBUG__
- if (wxWinHandleList->Member(win))
- {
- wxLogDebug("- Association %d", gs_AssociationCount);
- gs_AssociationCount --;
- }
-#endif
- wxWinHandleList->DeleteObject(win);
+ wxWinHandleHash->Delete((long)win->GetHWND());
}
+// ----------------------------------------------------------------------------
+// various MSW speciic class dependent functions
+// ----------------------------------------------------------------------------
+
// Default destroyer - override if you destroy it in some other way
// (e.g. with MDI child windows)
void wxWindowMSW::MSWDestroyWindow()
{
}
-void wxWindowMSW::MSWDetachWindowMenu()
+bool wxWindowMSW::MSWGetCreateWindowCoords(const wxPoint& pos,
+ const wxSize& size,
+ int& x, int& y,
+ int& w, int& h) const
{
-#ifndef __WXUNIVERSAL__
- if ( m_hMenu )
- {
- wxChar buf[1024];
- HMENU hMenu = (HMENU)m_hMenu;
-
- int N = ::GetMenuItemCount(hMenu);
- for ( int i = 0; i < N; i++ )
- {
- if ( !::GetMenuString(hMenu, i, buf, WXSIZEOF(buf), MF_BYPOSITION) )
- {
- wxLogLastError(wxT("GetMenuString"));
+ static const int DEFAULT_Y = 200;
+ static const int DEFAULT_H = 250;
- continue;
- }
+ bool nonDefault = FALSE;
- if ( wxStrcmp(buf, _("&Window")) == 0 )
- {
- if ( !::RemoveMenu(hMenu, i, MF_BYPOSITION) )
- {
- wxLogLastError(wxT("RemoveMenu"));
- }
+ if ( pos.x == -1 )
+ {
+ // if set x to CW_USEDEFAULT, y parameter is ignored anyhow so we can
+ // just as well set it to CW_USEDEFAULT as well
+ x =
+ y = CW_USEDEFAULT;
+ }
+ else
+ {
+ // OTOH, if x is not set to CW_USEDEFAULT, y shouldn't be set to it
+ // neither because it is not handled as a special value by Windows then
+ // and so we have to choose some default value for it
+ x = pos.x;
+ y = pos.y == -1 ? DEFAULT_Y : pos.y;
+
+ nonDefault = TRUE;
+ }
+
+ /*
+ NB: there used to be some code here which set the initial size of the
+ window to the client size of the parent if no explicit size was
+ specified. This was wrong because wxWindows programs often assume
+ that they get a WM_SIZE (EVT_SIZE) upon creation, however this broke
+ it. To see why, you should understand that Windows sends WM_SIZE from
+ inside ::CreateWindow() anyhow. However, ::CreateWindow() is called
+ from some base class ctor and so this WM_SIZE is not processed in the
+ real class' OnSize() (because it's not fully constructed yet and the
+ event goes to some base class OnSize() instead). So the WM_SIZE we
+ rely on is the one sent when the parent frame resizes its children
+ but here is the problem: if the child already has just the right
+ size, nothing will happen as both wxWindows and Windows check for
+ this and ignore any attempts to change the window size to the size it
+ already has - so no WM_SIZE would be sent.
+ */
+ if ( size.x == -1 )
+ {
+ // as above, h is not used at all in this case anyhow
+ w =
+ h = CW_USEDEFAULT;
+ }
+ else
+ {
+ // and, again as above, we can't set the height to CW_USEDEFAULT here
+ w = size.x;
+ h = size.y == -1 ? DEFAULT_H : size.y;
- break;
- }
- }
+ nonDefault = TRUE;
}
-#endif
+
+ return nonDefault;
+}
+
+WXHWND wxWindowMSW::MSWGetParent() const
+{
+ return m_parent ? m_parent->GetHWND() : WXHWND(NULL);
}
-bool wxWindowMSW::MSWCreate(int id,
- wxWindow *parent,
- const wxChar *wclass,
- wxWindow * WXUNUSED(wx_win),
+bool wxWindowMSW::MSWCreate(const wxChar *wclass,
const wxChar *title,
- int x,
- int y,
- int width,
- int height,
+ const wxPoint& pos,
+ const wxSize& size,
WXDWORD style,
- const wxChar *dialog_template,
WXDWORD extendedStyle)
{
- int x1 = CW_USEDEFAULT;
- int y1 = 0;
- int width1 = CW_USEDEFAULT;
- int height1 = 100;
-
- // Find parent's size, if it exists, to set up a possible default
- // panel size the size of the parent window
- RECT rectParent;
- if ( parent )
- {
- ::GetClientRect(GetHwndOf(parent), &rectParent);
-
- width1 = rectParent.right - rectParent.left;
- height1 = rectParent.bottom - rectParent.top;
- }
+ // choose the position/size for the new window
+ int x, y, w, h;
+ (void)MSWGetCreateWindowCoords(pos, size, x, y, w, h);
- if ( x != -1 )
- x1 = x;
- if ( y != -1 )
- y1 = y;
- if ( width != -1 )
- width1 = width;
- if ( height != -1 )
- height1 = height;
+ // controlId is menu handle for the top level windows, so set it to 0
+ // unless we're creating a child window
+ int controlId = style & WS_CHILD ? GetId() : 0;
- // unfortunately, setting WS_EX_CONTROLPARENT only for some windows in the
- // hierarchy with several embedded panels (and not all of them) causes the
- // program to hang during the next call to IsDialogMessage() due to the bug
- // in this function (at least in Windows NT 4.0, it seems to work ok in
- // Win2K)
-#if 0
- // if we have wxTAB_TRAVERSAL style, we want WS_EX_CONTROLPARENT or
- // IsDialogMessage() won't work for us
- if ( GetWindowStyleFlag() & wxTAB_TRAVERSAL )
+ // for each class "Foo" we have we also have "FooNR" ("no repaint") class
+ // which is the same but without CS_[HV]REDRAW class styles so using it
+ // ensures that the window is not fully repainted on each resize
+ wxString className(wclass);
+ if ( GetWindowStyleFlag() & wxNO_FULL_REPAINT_ON_RESIZE )
{
- extendedStyle |= WS_EX_CONTROLPARENT;
+ className += wxT("NR");
}
-#endif // 0
- HWND hParent;
- if ( GetWindowStyleFlag() & wxPOPUP_WINDOW )
- {
- // popup windows should have desktop as parent because they shouldn't
- // be limited to the parents client area as child windows usually are
- hParent = ::GetDesktopWindow();
- }
- else if ( parent )
+ // do create the window
+ wxWindowCreationHook hook(this);
+
+#ifdef __WXWINCE__
+ if (extendedStyle == 0)
{
- hParent = GetHwndOf(parent);
+ m_hWnd = (WXHWND)::CreateWindow
+ (
+ className,
+ title ? title : wxEmptyString,
+ style,
+ x, y, w, h,
+ (HWND)MSWGetParent(),
+ (HMENU)controlId,
+ wxGetInstance(),
+ NULL // no extra data
+ );
}
else
+#endif
{
- // top level window
- hParent = NULL;
+ m_hWnd = (WXHWND)::CreateWindowEx
+ (
+ extendedStyle,
+ className,
+ title ? title : wxEmptyString,
+ style,
+ x, y, w, h,
+ (HWND)MSWGetParent(),
+ (HMENU)controlId,
+ wxGetInstance(),
+ NULL // no extra data
+ );
}
- wxWndHook = this;
-
-#ifndef __WXMICROWIN__
- if ( dialog_template )
+ if ( !m_hWnd )
{
- // for the dialogs without wxDIALOG_NO_PARENT style, use the top level
- // app window as parent - this avoids creating modal dialogs without
- // parent
- if ( !hParent && !(GetWindowStyleFlag() & wxDIALOG_NO_PARENT) )
- {
- wxWindow *winTop = wxTheApp->GetTopWindow();
- if ( winTop )
- hParent = GetHwndOf(winTop);
- }
-
- m_hWnd = (WXHWND)::CreateDialog(wxGetInstance(),
- dialog_template,
- hParent,
- (DLGPROC)wxDlgProc);
-
- if ( m_hWnd == 0 )
- {
- wxLogError(_("Can't find dialog template '%s'!\nCheck resource include path for finding wx.rc."),
- dialog_template);
-
- return FALSE;
- }
-
- if ( extendedStyle != 0 )
- {
- ::SetWindowLong(GetHwnd(), GWL_EXSTYLE, extendedStyle);
- ::SetWindowPos(GetHwnd(), NULL, 0, 0, 0, 0,
- SWP_NOSIZE |
- SWP_NOMOVE |
- SWP_NOZORDER |
- SWP_NOACTIVATE);
- }
-
-#if defined(__WIN95__)
- // For some reason, the system menu is activated when we use the
- // WS_EX_CONTEXTHELP style, so let's set a reasonable icon
- if (extendedStyle & WS_EX_CONTEXTHELP)
- {
- wxFrame *winTop = wxDynamicCast(wxTheApp->GetTopWindow(), wxFrame);
- if ( winTop )
- {
- wxIcon icon = winTop->GetIcon();
- if ( icon.Ok() )
- {
- ::SendMessage(GetHwnd(), WM_SETICON,
- (WPARAM)TRUE,
- (LPARAM)GetHiconOf(icon));
- }
- }
- }
-#endif // __WIN95__
-
-
- // JACS: is the following still necessary? The above seems to work.
-
- // ::SetWindowLong(GWL_EXSTYLE) doesn't work for the dialogs, so try
- // to take care of (at least some) extended style flags ourselves
- if ( extendedStyle & WS_EX_TOPMOST )
- {
- if ( !::SetWindowPos(GetHwnd(), HWND_TOPMOST, 0, 0, 0, 0,
- SWP_NOSIZE | SWP_NOMOVE) )
- {
- wxLogLastError(wxT("SetWindowPos"));
- }
- }
+ wxLogSysError(_("Can't create window of class %s"), wclass);
- // move the dialog to its initial position without forcing repainting
- if ( !::MoveWindow(GetHwnd(), x1, y1, width1, height1, FALSE) )
- {
- wxLogLastError(wxT("MoveWindow"));
- }
-
- }
- else // creating a normal window, not a dialog
-#endif // !__WXMICROWIN__
- {
- int controlId = 0;
- if ( style & WS_CHILD )
- {
- controlId = id;
-
- if ( GetWindowStyleFlag() & wxCLIP_SIBLINGS )
- {
- style |= WS_CLIPSIBLINGS;
- }
- }
-
- wxString className(wclass);
- if ( GetWindowStyleFlag() & wxNO_FULL_REPAINT_ON_RESIZE )
- {
- className += wxT("NR");
- }
-
- m_hWnd = (WXHWND)CreateWindowEx(extendedStyle,
- className,
- title ? title : wxT(""),
- style,
- x1, y1,
- width1, height1,
- hParent, (HMENU)controlId,
- wxGetInstance(),
- NULL);
-
- if ( !m_hWnd )
- {
- wxLogError(_("Can't create window of class %s!\nPossible Windows 3.x compatibility problem?"),
- wclass);
-
- return FALSE;
- }
- }
-
- wxWndHook = NULL;
-
-#ifdef __WXDEBUG__
- wxNode* node = wxWinHandleList->Member(this);
- if (node)
- {
- HWND hWnd = (HWND) node->GetKeyInteger();
- if (hWnd != (HWND) m_hWnd)
- {
- wxLogError(wxT("A second HWND association is being added for the same window!"));
- }
+ return FALSE;
}
-#endif // Debug
- wxAssociateWinWithHandle((HWND) m_hWnd, this);
+ SubclassWin(m_hWnd);
- SetFont(wxSystemSettings::GetSystemFont(wxSYS_DEFAULT_GUI_FONT));
+ SetFont(wxSystemSettings::GetFont(wxSYS_DEFAULT_GUI_FONT));
return TRUE;
}
// ---------------------------------------------------------------------------
#ifdef __WIN95__
-// FIXME: VZ: I'm not sure at all that the order of processing is correct
+
bool wxWindowMSW::HandleNotify(int idCtrl, WXLPARAM lParam, WXLPARAM *result)
{
#ifndef __WXMICROWIN__
HWND hWnd = hdr->hwndFrom;
wxWindow *win = wxFindWinFromHandle((WXHWND)hWnd);
- // is this one of our windows?
+ // if the control is one of our windows, let it handle the message itself
if ( win )
{
return win->MSWOnNotify(idCtrl, lParam, result);
}
+ // VZ: why did we do it? normally this is unnecessary and, besides, it
+ // breaks the message processing for the toolbars because the tooltip
+ // notifications were being forwarded to the toolbar child controls
+ // (if it had any) before being passed to the toolbar itself, so in my
+ // example the tooltip for the combobox was always shown instead of the
+ // correct button tooltips
+#if 0
// try all our children
- wxWindowList::Node *node = GetChildren().GetFirst();
+ wxWindowList::compatibility_iterator node = GetChildren().GetFirst();
while ( node )
{
wxWindow *child = node->GetData();
node = node->GetNext();
}
+#endif // 0
- // finally try this window too (catches toolbar case)
+ // by default, handle it ourselves
return MSWOnNotify(idCtrl, lParam, result);
#else // __WXMICROWIN__
return FALSE;
#endif
}
+#if wxUSE_TOOLTIPS
+
+bool wxWindowMSW::HandleTooltipNotify(WXUINT code,
+ WXLPARAM lParam,
+ const wxString& ttip)
+{
+ // I don't know why it happens, but the versions of comctl32.dll starting
+ // from 4.70 sometimes send TTN_NEEDTEXTW even to ANSI programs (normally,
+ // this message is supposed to be sent to Unicode programs only) -- hence
+ // we need to handle it as well, otherwise no tooltips will be shown in
+ // this case
+#ifndef __WXWINCE__
+ if ( !(code == (WXUINT) TTN_NEEDTEXTA || code == (WXUINT) TTN_NEEDTEXTW) || ttip.empty() )
+ {
+ // not a tooltip message or no tooltip to show anyhow
+ return FALSE;
+ }
+#endif
+
+ LPTOOLTIPTEXT ttText = (LPTOOLTIPTEXT)lParam;
+
+#if !wxUSE_UNICODE
+ if ( code == (WXUINT) TTN_NEEDTEXTA )
+ {
+ // we pass just the pointer as we store the string internally anyhow
+ ttText->lpszText = (char *)ttip.c_str();
+ }
+ else // TTN_NEEDTEXTW
+#endif // !Unicode
+ {
+#if wxUSE_UNICODE
+ // in Unicode mode this is just what we need
+ ttText->lpszText = (wxChar *)ttip.c_str();
+#else // !Unicode
+/*
+ MultiByteToWideChar(CP_ACP, 0, ttip, ttip.length()+1,
+ (wchar_t *)ttText->szText,
+ sizeof(ttText->szText) / sizeof(wchar_t));
+*/
+ // Fix by dimitrishortcut: see patch 771772
+
+ // FIXME: szText has a max of 80 bytes, so limit the tooltip string
+ // length accordingly. Ideally lpszText should be used, but who
+ // would be responsible for freeing the buffer?
+
+ // Maximum length of a tip is 39 characters. 39 is 80/2 minus 1 byte
+ // needed for NULL character.
+ size_t tipLength = wxMin(ttip.Len(), 39);
+
+ // Convert to WideChar without adding the NULL character. The NULL
+ // character is added afterwards (Could have used ttip.Left(tipLength)
+ // and a cchMultiByte parameter of tipLength+1, but this is more
+ //efficient.
+ ::MultiByteToWideChar(CP_ACP, 0, ttip, tipLength,
+ (wchar_t *)ttText->szText,
+ sizeof(ttText->szText) / sizeof(wchar_t));
+
+ // Add the NULL character.
+ ttText->szText[tipLength*2+0] = '\0';
+ ttText->szText[tipLength*2+1] = '\0';
+
+#endif // Unicode/!Unicode
+ }
+
+ return TRUE;
+}
+
+#endif // wxUSE_TOOLTIPS
+
bool wxWindowMSW::MSWOnNotify(int WXUNUSED(idCtrl),
- WXLPARAM lParam,
- WXLPARAM* WXUNUSED(result))
+ WXLPARAM lParam,
+ WXLPARAM* WXUNUSED(result))
{
#if wxUSE_TOOLTIPS
- NMHDR* hdr = (NMHDR *)lParam;
- if ( (int)hdr->code == TTN_NEEDTEXT && m_tooltip )
+ if ( m_tooltip )
{
- TOOLTIPTEXT *ttt = (TOOLTIPTEXT *)lParam;
- ttt->lpszText = (wxChar *)m_tooltip->GetTip().c_str();
-
- // processed
- return TRUE;
+ NMHDR* hdr = (NMHDR *)lParam;
+ if ( HandleTooltipNotify(hdr->code, lParam, m_tooltip->GetTip()))
+ {
+ // processed
+ return TRUE;
+ }
}
#endif // wxUSE_TOOLTIPS
return FALSE;
}
+
#endif // __WIN95__
// ---------------------------------------------------------------------------
bool wxWindowMSW::HandleQueryEndSession(long logOff, bool *mayEnd)
{
+#ifndef __WXWINCE__
wxCloseEvent event(wxEVT_QUERY_END_SESSION, -1);
event.SetEventObject(wxTheApp);
event.SetCanVeto(TRUE);
}
return rc;
+#else
+ return FALSE;
+#endif
}
bool wxWindowMSW::HandleEndSession(bool endSession, long logOff)
{
+#ifndef __WXWINCE__
// do nothing if the session isn't ending
if ( !endSession )
return FALSE;
event.SetLoggingOff( (logOff == (long)ENDSESSION_LOGOFF) );
return wxTheApp->ProcessEvent(event);
+#else
+ return FALSE;
+#endif
}
// ---------------------------------------------------------------------------
// window creation/destruction
// ---------------------------------------------------------------------------
-bool wxWindowMSW::HandleCreate(WXLPCREATESTRUCT WXUNUSED(cs), bool *mayCreate)
+bool wxWindowMSW::HandleCreate(WXLPCREATESTRUCT cs, bool *mayCreate)
{
+ // VZ: why is this commented out for WinCE? If it doesn't support
+ // WS_EX_CONTROLPARENT at all it should be somehow handled globally,
+ // not with multiple #ifdef's!
+#ifndef __WXWINCE__
+ if ( ((CREATESTRUCT *)cs)->dwExStyle & WS_EX_CONTROLPARENT )
+ EnsureParentHasControlParentStyle(GetParent());
+#endif // !__WXWINCE__
+
// TODO: should generate this event from WM_NCCREATE
wxWindowCreateEvent event((wxWindow *)this);
(void)GetEventHandler()->ProcessEvent(event);
bool wxWindowMSW::HandleDestroy()
{
- wxWindowDestroyEvent event((wxWindow *)this);
- (void)GetEventHandler()->ProcessEvent(event);
+ SendDestroyEvent();
// delete our drop target if we've got one
#if wxUSE_DRAG_AND_DROP
}
#endif
+ // Don't send the event when in the process of being deleted. This can
+ // only cause problems if the event handler tries to access the object.
+ if ( m_isBeingDeleted )
+ {
+ return FALSE;
+ }
+
wxFocusEvent event(wxEVT_KILL_FOCUS, m_windowId);
event.SetEventObject(this);
bool wxWindowMSW::HandleDropFiles(WXWPARAM wParam)
{
-#ifndef __WXMICROWIN__
+#if defined (__WXMICROWIN__) || defined(__WXWINCE__)
+ return FALSE;
+#else // __WXMICROWIN__
HDROP hFilesInfo = (HDROP) wParam;
- POINT dropPoint;
- DragQueryPoint(hFilesInfo, (LPPOINT) &dropPoint);
// Get the total number of files dropped
- WORD gwFilesDropped = (WORD)::DragQueryFile
+ UINT gwFilesDropped = ::DragQueryFile
(
(HDROP)hFilesInfo,
(UINT)-1,
);
wxString *files = new wxString[gwFilesDropped];
- int wIndex;
- for (wIndex=0; wIndex < (int)gwFilesDropped; wIndex++)
+ for ( UINT wIndex = 0; wIndex < gwFilesDropped; wIndex++ )
{
- DragQueryFile (hFilesInfo, wIndex, (LPTSTR) wxBuffer, 1000);
- files[wIndex] = wxBuffer;
+ // first get the needed buffer length (+1 for terminating NUL)
+ size_t len = ::DragQueryFile(hFilesInfo, wIndex, NULL, 0) + 1;
+
+ // and now get the file name
+ ::DragQueryFile(hFilesInfo, wIndex,
+ wxStringBuffer(files[wIndex], len), len);
}
DragFinish (hFilesInfo);
wxDropFilesEvent event(wxEVT_DROP_FILES, gwFilesDropped, files);
event.m_eventObject = this;
+
+ POINT dropPoint;
+ DragQueryPoint(hFilesInfo, (LPPOINT) &dropPoint);
event.m_pos.x = dropPoint.x;
event.m_pos.y = dropPoint.y;
- bool rc = GetEventHandler()->ProcessEvent(event);
-
- delete[] files;
-
- return rc;
-#else // __WXMICROWIN__
- return FALSE;
+ return GetEventHandler()->ProcessEvent(event);
#endif
}
+
bool wxWindowMSW::HandleSetCursor(WXHWND WXUNUSED(hWnd),
short nHitTest,
int WXUNUSED(mouseMsg))
// first ask the user code - it may wish to set the cursor in some very
// specific way (for example, depending on the current position)
POINT pt;
-#ifdef __WIN32__
if ( !::GetCursorPos(&pt) )
{
wxLogLastError(wxT("GetCursorPos"));
}
-#else
- // In WIN16 it doesn't return a value.
- ::GetCursorPos(&pt);
-#endif
int x = pt.x,
y = pt.y;
if ( hcursor )
{
+// wxLogDebug("HandleSetCursor: Setting cursor %ld", (long) hcursor);
+
::SetCursor(hcursor);
// cursor set, stop here
// owner drawn stuff
// ---------------------------------------------------------------------------
-bool wxWindowMSW::MSWOnDrawItem(int id, WXDRAWITEMSTRUCT *itemStruct)
+#if (wxUSE_OWNER_DRAWN && wxUSE_MENUS_NATIVE) || \
+ (wxUSE_CONTROLS && !defined(__WXUNIVERSAL__))
+ #define WXUNUSED_UNLESS_ODRAWN(param) param
+#else
+ #define WXUNUSED_UNLESS_ODRAWN(param)
+#endif
+
+bool
+wxWindowMSW::MSWOnDrawItem(int WXUNUSED_UNLESS_ODRAWN(id),
+ WXDRAWITEMSTRUCT * WXUNUSED_UNLESS_ODRAWN(itemStruct))
{
#if wxUSE_OWNER_DRAWN
}
#endif // wxUSE_MENUS_NATIVE
-#if wxUSE_CONTROLS
- wxWindow *item = FindItem(id);
- if ( item && item->IsKindOf(CLASSINFO(wxControl)) )
+#endif // USE_OWNER_DRAWN
+
+#if wxUSE_CONTROLS && !defined(__WXUNIVERSAL__)
+
+#if wxUSE_OWNER_DRAWN
+ wxControl *item = wxDynamicCast(FindItem(id), wxControl);
+#else // !wxUSE_OWNER_DRAWN
+ // we may still have owner-drawn buttons internally because we have to make
+ // them owner-drawn to support colour change
+ wxControl *item = wxDynamicCast(FindItem(id), wxButton);
+#endif // USE_OWNER_DRAWN
+
+ if ( item )
{
- return ((wxControl *)item)->MSWOnDraw(itemStruct);
+ return item->MSWOnDraw(itemStruct);
}
-#endif // wxUSE_CONTROLS
-#endif // USE_OWNER_DRAWN
+#endif // wxUSE_CONTROLS
return FALSE;
}
-bool wxWindowMSW::MSWOnMeasureItem(int id, WXMEASUREITEMSTRUCT *itemStruct)
+bool
+wxWindowMSW::MSWOnMeasureItem(int WXUNUSED_UNLESS_ODRAWN(id),
+ WXMEASUREITEMSTRUCT *
+ WXUNUSED_UNLESS_ODRAWN(itemStruct))
{
-#if wxUSE_OWNER_DRAWN
+#if wxUSE_OWNER_DRAWN && wxUSE_MENUS_NATIVE
// is it a menu item?
MEASUREITEMSTRUCT *pMeasureStruct = (MEASUREITEMSTRUCT *)itemStruct;
if ( id == 0 && pMeasureStruct->CtlType == ODT_MENU )
&pMeasureStruct->itemHeight);
}
- wxWindow *item = FindItem(id);
- if ( item && item->IsKindOf(CLASSINFO(wxControl)) )
+ wxControl *item = wxDynamicCast(FindItem(id), wxControl);
+ if ( item )
{
- return ((wxControl *)item)->MSWOnMeasure(itemStruct);
+ return item->MSWOnMeasure(itemStruct);
}
-#endif // owner-drawn menus
+#endif // wxUSE_OWNER_DRAWN
+
return FALSE;
}
wxSysColourChangedEvent event;
event.SetEventObject(this);
+ (void)GetEventHandler()->ProcessEvent(event);
+
+ // always let the system carry on the default processing to allow the
+ // native controls to react to the colours update
+ return FALSE;
+}
+
+bool wxWindowMSW::HandleDisplayChange()
+{
+ wxDisplayChangedEvent event;
+ event.SetEventObject(this);
+
return GetEventHandler()->ProcessEvent(event);
}
#ifndef __WXMICROWIN__
WXHBRUSH hBrush = 0;
+#ifdef __WXWINCE__
+ if (FALSE)
+#else
if ( nCtlColor == CTLCOLOR_DLG )
+#endif
{
hBrush = OnCtlColor(pDC, pWnd, nCtlColor, message, wParam, lParam);
}
bool wxWindowMSW::HandlePaletteChanged(WXHWND hWndPalChange)
{
+#if wxUSE_PALETTE
+ // same as below except we don't respond to our own messages
+ if ( hWndPalChange != GetHWND() )
+ {
+ // check to see if we our our parents have a custom palette
+ wxWindowMSW *win = this;
+ while ( win && !win->HasCustomPalette() )
+ {
+ win = win->GetParent();
+ }
+
+ if ( win && win->HasCustomPalette() )
+ {
+ // realize the palette to see whether redrawing is needed
+ HDC hdc = ::GetDC((HWND) hWndPalChange);
+ win->m_palette.SetHPALETTE((WXHPALETTE)
+ ::SelectPalette(hdc, GetHpaletteOf(win->m_palette), FALSE));
+
+ int result = ::RealizePalette(hdc);
+
+ // restore the palette (before releasing the DC)
+ win->m_palette.SetHPALETTE((WXHPALETTE)
+ ::SelectPalette(hdc, GetHpaletteOf(win->m_palette), FALSE));
+ ::RealizePalette(hdc);
+ ::ReleaseDC((HWND) hWndPalChange, hdc);
+
+ // now check for the need to redraw
+ if (result > 0)
+ InvalidateRect((HWND) hWndPalChange, NULL, TRUE);
+ }
+
+ }
+#endif // wxUSE_PALETTE
+
wxPaletteChangedEvent event(GetId());
event.SetEventObject(this);
event.SetChangedWindow(wxFindWinFromHandle(hWndPalChange));
return GetEventHandler()->ProcessEvent(event);
}
+bool wxWindowMSW::HandleCaptureChanged(WXHWND hWndGainedCapture)
+{
+ wxMouseCaptureChangedEvent event(GetId(), wxFindWinFromHandle(hWndGainedCapture));
+ event.SetEventObject(this);
+
+ return GetEventHandler()->ProcessEvent(event);
+}
+
bool wxWindowMSW::HandleQueryNewPalette()
{
+
+#if wxUSE_PALETTE
+ // check to see if we our our parents have a custom palette
+ wxWindowMSW *win = this;
+ while (!win->HasCustomPalette() && win->GetParent()) win = win->GetParent();
+ if (win->HasCustomPalette()) {
+ /* realize the palette to see whether redrawing is needed */
+ HDC hdc = GetDC((HWND) GetHWND());
+ win->m_palette.SetHPALETTE( (WXHPALETTE)
+ ::SelectPalette(hdc, (HPALETTE) win->m_palette.GetHPALETTE(), FALSE) );
+
+ int result = ::RealizePalette(hdc);
+ /* restore the palette (before releasing the DC) */
+ win->m_palette.SetHPALETTE( (WXHPALETTE)
+ ::SelectPalette(hdc, (HPALETTE) win->m_palette.GetHPALETTE(), TRUE) );
+ ::RealizePalette(hdc);
+ ::ReleaseDC((HWND) GetHWND(), hdc);
+ /* now check for the need to redraw */
+ if (result > 0)
+ ::InvalidateRect((HWND) GetHWND(), NULL, TRUE);
+ }
+#endif // wxUSE_PALETTE
+
wxQueryNewPaletteEvent event(GetId());
event.SetEventObject(this);
}
// Responds to colour changes: passes event on to children.
-void wxWindowMSW::OnSysColourChanged(wxSysColourChangedEvent& event)
+void wxWindowMSW::OnSysColourChanged(wxSysColourChangedEvent& WXUNUSED(event))
{
- wxNode *node = GetChildren().First();
+ // the top level window also reset the standard colour map as it might have
+ // changed (there is no need to do it for the non top level windows as we
+ // only have to do it once)
+ if ( IsTopLevel() )
+ {
+ // FIXME-MT
+ gs_hasStdCmap = FALSE;
+ }
+ wxWindowList::compatibility_iterator node = GetChildren().GetFirst();
while ( node )
{
- // Only propagate to non-top-level windows
- wxWindow *win = (wxWindow *)node->Data();
- if ( win->GetParent() )
+ // Only propagate to non-top-level windows because Windows already
+ // sends this event to all top-level ones
+ wxWindow *win = node->GetData();
+ if ( !win->IsTopLevel() )
+ {
+ // we need to send the real WM_SYSCOLORCHANGE and not just trigger
+ // EVT_SYS_COLOUR_CHANGED call because the latter wouldn't work for
+ // the standard controls
+ ::SendMessage(GetHwndOf(win), WM_SYSCOLORCHANGE, 0, 0);
+ }
+
+ node = node->GetNext();
+ }
+
+ // update the colours we use if they were not set explicitly by the user:
+ // this must be done or OnCtlColor() would continue to use the old colours
+ if ( !m_hasFgCol )
+ {
+ m_foregroundColour = wxSystemSettings::
+ GetSystemColour(wxSYS_COLOUR_WINDOWTEXT);
+ }
+
+ if ( !m_hasBgCol )
+ {
+ m_backgroundColour = wxSystemSettings::
+ GetSystemColour(wxSYS_COLOUR_BTNFACE);
+ }
+}
+
+extern wxCOLORMAP *wxGetStdColourMap()
+{
+ static COLORREF s_stdColours[wxSTD_COL_MAX];
+ static wxCOLORMAP s_cmap[wxSTD_COL_MAX];
+
+ if ( !gs_hasStdCmap )
+ {
+ static bool s_coloursInit = FALSE;
+
+ if ( !s_coloursInit )
{
- wxSysColourChangedEvent event2;
- event.m_eventObject = win;
- win->GetEventHandler()->ProcessEvent(event2);
+ // When a bitmap is loaded, the RGB values can change (apparently
+ // because Windows adjusts them to care for the old programs always
+ // using 0xc0c0c0 while the transparent colour for the new Windows
+ // versions is different). But we do this adjustment ourselves so
+ // we want to avoid Windows' "help" and for this we need to have a
+ // reference bitmap which can tell us what the RGB values change
+ // to.
+ wxBitmap stdColourBitmap(_T("wxBITMAP_STD_COLOURS"));
+ if ( stdColourBitmap.Ok() )
+ {
+ // the pixels in the bitmap must correspond to wxSTD_COL_XXX!
+ wxASSERT_MSG( stdColourBitmap.GetWidth() == wxSTD_COL_MAX,
+ _T("forgot to update wxBITMAP_STD_COLOURS!") );
+
+ wxMemoryDC memDC;
+ memDC.SelectObject(stdColourBitmap);
+
+ wxColour colour;
+ for ( size_t i = 0; i < WXSIZEOF(s_stdColours); i++ )
+ {
+ memDC.GetPixel(i, 0, &colour);
+ s_stdColours[i] = wxColourToRGB(colour);
+ }
+ }
+ else // wxBITMAP_STD_COLOURS couldn't be loaded
+ {
+ s_stdColours[0] = RGB(000,000,000); // black
+ s_stdColours[1] = RGB(128,128,128); // dark grey
+ s_stdColours[2] = RGB(192,192,192); // light grey
+ s_stdColours[3] = RGB(255,255,255); // white
+ //s_stdColours[4] = RGB(000,000,255); // blue
+ //s_stdColours[5] = RGB(255,000,255); // magenta
+ }
+
+ s_coloursInit = TRUE;
}
- node = node->Next();
+ gs_hasStdCmap = TRUE;
+
+ // create the colour map
+#define INIT_CMAP_ENTRY(col) \
+ s_cmap[wxSTD_COL_##col].from = s_stdColours[wxSTD_COL_##col]; \
+ s_cmap[wxSTD_COL_##col].to = ::GetSysColor(COLOR_##col)
+
+ INIT_CMAP_ENTRY(BTNTEXT);
+ INIT_CMAP_ENTRY(BTNSHADOW);
+ INIT_CMAP_ENTRY(BTNFACE);
+ INIT_CMAP_ENTRY(BTNHIGHLIGHT);
+
+#undef INIT_CMAP_ENTRY
}
+
+ return s_cmap;
}
// ---------------------------------------------------------------------------
bool wxWindowMSW::HandlePaint()
{
-#ifdef __WIN32__
+// if (GetExtraStyle() & wxWS_EX_THEMED_BACKGROUND)
+// return FALSE;
+
HRGN hRegion = ::CreateRectRgn(0, 0, 0, 0); // Dummy call to get a handle
if ( !hRegion )
wxLogLastError(wxT("CreateRectRgn"));
wxLogLastError(wxT("GetUpdateRgn"));
m_updateRegion = wxRegion((WXHRGN) hRegion);
-#else // Win16
- RECT updateRect;
- ::GetUpdateRect(GetHwnd(), &updateRect, FALSE);
-
- m_updateRegion = wxRegion(updateRect.left, updateRect.top,
- updateRect.right - updateRect.left,
- updateRect.bottom - updateRect.top);
-#endif // Win32/16
wxPaintEvent event(m_windowId);
event.SetEventObject(this);
if ( ::IsIconic(GetHwnd()) )
return TRUE;
+#if 0
+ if (GetParent() && GetParent()->GetExtraStyle() & wxWS_EX_THEMED_BACKGROUND)
+ {
+ return FALSE;
+ }
+
+ if (GetExtraStyle() & wxWS_EX_THEMED_BACKGROUND)
+ {
+ if (wxUxThemeEngine::Get())
+ {
+ WXHTHEME hTheme = wxUxThemeEngine::Get()->m_pfnOpenThemeData(GetHWND(), L"TAB");
+ if (hTheme)
+ {
+ WXURECT rect;
+ ::GetClientRect((HWND) GetHWND(), (RECT*) & rect);
+ wxUxThemeEngine::Get()->m_pfnDrawThemeBackground(hTheme, hdc, 10 /* TABP_BODY */, 0, &rect, &rect);
+ wxUxThemeEngine::Get()->m_pfnCloseThemeData(hTheme);
+ return TRUE;
+ }
+ }
+ }
+#endif
+
wxDCTemp dc(hdc);
dc.SetHDC(hdc);
HDC hdc = (HDC)event.GetDC()->GetHDC();
+#ifndef __WXWINCE__
int mode = ::SetMapMode(hdc, MM_TEXT);
+#endif
::FillRect(hdc, &rect, hBrush);
::DeleteObject(hBrush);
+
+#ifndef __WXWINCE__
::SetMapMode(hdc, mode);
+#endif
}
// ---------------------------------------------------------------------------
return GetEventHandler()->ProcessEvent(event);
}
-bool wxWindowMSW::HandleSize(int w, int h, WXUINT WXUNUSED(flag))
+bool wxWindowMSW::HandleMoving(wxRect& rect)
+{
+ wxMoveEvent event(rect, m_windowId);
+ event.SetEventObject(this);
+
+ bool rc = GetEventHandler()->ProcessEvent(event);
+ if (rc)
+ rect = event.GetRect();
+ return rc;
+}
+
+bool wxWindowMSW::HandleSize(int WXUNUSED(w), int WXUNUSED(h),
+ WXUINT WXUNUSED(flag))
{
- wxSizeEvent event(wxSize(w, h), m_windowId);
+ // don't use w and h parameters as they specify the client size while
+ // according to the docs EVT_SIZE handler is supposed to receive the total
+ // size
+ wxSizeEvent event(GetSize(), m_windowId);
event.SetEventObject(this);
return GetEventHandler()->ProcessEvent(event);
}
+bool wxWindowMSW::HandleSizing(wxRect& rect)
+{
+ wxSizeEvent event(rect, m_windowId);
+ event.SetEventObject(this);
+
+ bool rc = GetEventHandler()->ProcessEvent(event);
+ if (rc)
+ rect = event.GetRect();
+ return rc;
+}
+
bool wxWindowMSW::HandleGetMinMaxInfo(void *mmInfo)
{
+#ifdef __WXWINCE__
+ return FALSE;
+#else
MINMAXINFO *info = (MINMAXINFO *)mmInfo;
bool rc = FALSE;
- if ( m_minWidth != -1 )
+ int minWidth = GetMinWidth(),
+ minHeight = GetMinHeight(),
+ maxWidth = GetMaxWidth(),
+ maxHeight = GetMaxHeight();
+
+ if ( minWidth != -1 )
{
- info->ptMinTrackSize.x = m_minWidth;
+ info->ptMinTrackSize.x = minWidth;
rc = TRUE;
}
- if ( m_minHeight != -1 )
+ if ( minHeight != -1 )
{
- info->ptMinTrackSize.y = m_minHeight;
+ info->ptMinTrackSize.y = minHeight;
rc = TRUE;
}
- if ( m_maxWidth != -1 )
+ if ( maxWidth != -1 )
{
- info->ptMaxTrackSize.x = m_maxWidth;
+ info->ptMaxTrackSize.x = maxWidth;
rc = TRUE;
}
- if ( m_maxHeight != -1 )
+ if ( maxHeight != -1 )
{
- info->ptMaxTrackSize.y = m_maxHeight;
+ info->ptMaxTrackSize.y = maxHeight;
rc = TRUE;
}
return rc;
+#endif
}
// ---------------------------------------------------------------------------
bool wxWindowMSW::HandleCommand(WXWORD id, WXWORD cmd, WXHWND control)
{
#if wxUSE_MENUS_NATIVE
- if ( wxCurrentPopupMenu )
+ if ( !cmd && wxCurrentPopupMenu )
{
wxMenu *popupMenu = wxCurrentPopupMenu;
wxCurrentPopupMenu = NULL;
}
#endif // wxUSE_MENUS_NATIVE
- wxWindow *win = (wxWindow*) NULL;
- if ( cmd == 0 || cmd == 1 ) // menu or accel - use id
+ wxWindow *win = NULL;
+
+ // first try to find it from HWND - this works even with the broken
+ // programs using the same ids for different controls
+ if ( control )
{
- // must cast to a signed type before comparing with other ids!
- win = FindItem((signed short)id);
+ win = wxFindWinFromHandle(control);
}
- if (!win && control)
+ // try the id
+ if ( !win )
{
- // find it from HWND - this works even with the broken programs using
- // the same ids for different controls
- win = wxFindWinFromHandle(control);
+ // must cast to a signed type before comparing with other ids!
+ win = FindItem((signed short)id);
}
if ( win )
bool wxWindowMSW::HandleSysCommand(WXWPARAM wParam, WXLPARAM WXUNUSED(lParam))
{
+#ifndef __WXWINCE__
// 4 bits are reserved
switch ( wParam & 0xFFFFFFF0 )
{
case SC_MINIMIZE:
return HandleMinimize();
}
+#endif
return FALSE;
}
event.m_leftDown = (flags & MK_LBUTTON) != 0;
event.m_middleDown = (flags & MK_MBUTTON) != 0;
event.m_rightDown = (flags & MK_RBUTTON) != 0;
- event.m_altDown = (::GetKeyState(VK_MENU) & 0x80000000) != 0;
+ // event.m_altDown = (::GetKeyState(VK_MENU) & 0x80000000) != 0;
+ // Returns different negative values on WinME and WinNT,
+ // so simply test for negative value.
+ event.m_altDown = ::GetKeyState(VK_MENU) < 0;
event.SetTimestamp(s_currentMsg.time);
event.m_eventObject = this;
+ event.SetId(GetId());
#if wxUSE_MOUSEEVENT_HACK
m_lastMouseX = x;
#endif // wxUSE_MOUSEEVENT_HACK
}
+// Windows doesn't send the mouse events to the static controls (which are
+// transparent in the sense that their WM_NCHITTEST handler returns
+// HTTRANSPARENT) at all but we want all controls to receive the mouse events
+// and so we manually check if we don't have a child window under mouse and if
+// we do, send the event to it instead of the window Windows had sent WM_XXX
+// to.
+//
+// Notice that this is not done for the mouse move events because this could
+// (would?) be too slow, but only for clicks which means that the static texts
+// still don't get move, enter nor leave events.
+static wxWindowMSW *FindWindowForMouseEvent(wxWindowMSW *win, int *x, int *y) //TW:REQ:Univ
+{
+ wxCHECK_MSG( x && y, win, _T("NULL pointer in FindWindowForMouseEvent") );
+
+ // first try to find a non transparent child: this allows us to send events
+ // to a static text which is inside a static box, for example
+ POINT pt = { *x, *y };
+ HWND hwnd = GetHwndOf(win),
+ hwndUnderMouse;
+
+#ifdef __WXWINCE__
+ hwndUnderMouse = ::ChildWindowFromPoint
+ (
+ hwnd,
+ pt
+ );
+#else
+ hwndUnderMouse = ::ChildWindowFromPointEx
+ (
+ hwnd,
+ pt,
+ CWP_SKIPINVISIBLE |
+ CWP_SKIPDISABLED |
+ CWP_SKIPTRANSPARENT
+ );
+#endif
+
+ if ( !hwndUnderMouse || hwndUnderMouse == hwnd )
+ {
+ // now try any child window at all
+ hwndUnderMouse = ::ChildWindowFromPoint(hwnd, pt);
+ }
+
+ // check that we have a child window which is susceptible to receive mouse
+ // events: for this it must be shown and enabled
+ if ( hwndUnderMouse &&
+ hwndUnderMouse != hwnd &&
+ ::IsWindowVisible(hwndUnderMouse) &&
+ ::IsWindowEnabled(hwndUnderMouse) )
+ {
+ wxWindow *winUnderMouse = wxFindWinFromHandle((WXHWND)hwndUnderMouse);
+ if ( winUnderMouse )
+ {
+ // translate the mouse coords to the other window coords
+ win->ClientToScreen(x, y);
+ winUnderMouse->ScreenToClient(x, y);
+
+ win = winUnderMouse;
+ }
+ }
+
+ return win;
+}
+
bool wxWindowMSW::HandleMouseEvent(WXUINT msg, int x, int y, WXUINT flags)
{
// the mouse events take consecutive IDs from WM_MOUSEFIRST to
event.m_wheelRotation = (short)HIWORD(wParam);
event.m_wheelDelta = WHEEL_DELTA;
-#ifdef __WIN32__
static int s_linesPerRotation = -1;
if ( s_linesPerRotation == -1 )
{
s_linesPerRotation = 3;
}
}
-#else // Win16
- // no SystemParametersInfo() under Win16
- static const int s_linesPerRotation = 3;
-#endif
event.m_linesPerAction = s_linesPerRotation;
return GetEventHandler()->ProcessEvent(event);
// create the key event of the given type for the given key - used by
// HandleChar and HandleKeyDown/Up
wxKeyEvent wxWindowMSW::CreateKeyEvent(wxEventType evType,
- int id,
- WXLPARAM lParam) const
+ int id,
+ WXLPARAM lParam,
+ WXWPARAM wParam) const
{
wxKeyEvent event(evType);
event.SetId(GetId());
event.m_eventObject = (wxWindow *)this; // const_cast
event.m_keyCode = id;
+ event.m_rawCode = (wxUint32) wParam;
+ event.m_rawFlags = (wxUint32) lParam;
event.SetTimestamp(s_currentMsg.time);
// translate the position to client coords
// WM_KEYDOWN one
bool wxWindowMSW::HandleChar(WXWPARAM wParam, WXLPARAM lParam, bool isASCII)
{
- bool ctrlDown = FALSE;
-
int id;
if ( isASCII )
{
- // If 1 -> 26, translate to CTRL plus a letter.
+ // If 1 -> 26, translate to either special keycode or just set
+ // ctrlDown. IOW, Ctrl-C should result in keycode == 3 and
+ // ControlDown() == TRUE.
id = wParam;
if ( (id > 0) && (id < 27) )
{
break;
default:
- ctrlDown = TRUE;
- id = id + 96;
+ //ctrlDown = TRUE;
+ break;
}
}
}
- else if ( (id = wxCharCodeMSWToWX(wParam)) == 0 )
- {
- // it's ASCII and will be processed here only when called from
- // WM_CHAR (i.e. when isASCII = TRUE), don't process it now
- id = -1;
- }
-
- if ( id != -1 )
+ else // we're called from WM_KEYDOWN
{
- wxKeyEvent event(CreateKeyEvent(wxEVT_CHAR, id, lParam));
- if ( ctrlDown )
+ id = wxCharCodeMSWToWX(wParam);
+ if ( id == 0 )
{
- event.m_controlDown = TRUE;
+ // it's ASCII and will be processed here only when called from
+ // WM_CHAR (i.e. when isASCII = TRUE), don't process it now
+ return FALSE;
}
+ }
- if ( GetEventHandler()->ProcessEvent(event) )
- return TRUE;
+ wxKeyEvent event(CreateKeyEvent(wxEVT_CHAR, id, lParam, wParam));
+
+ // the alphanumeric keys produced by pressing AltGr+something on European
+ // keyboards have both Ctrl and Alt modifiers which may confuse the user
+ // code as, normally, keys with Ctrl and/or Alt don't result in anything
+ // alphanumeric, so pretend that there are no modifiers at all (the
+ // KEY_DOWN event would still have the correct modifiers if they're really
+ // needed)
+ if ( event.m_controlDown && event.m_altDown &&
+ (id >= 32 && id < 256) )
+ {
+ event.m_controlDown =
+ event.m_altDown = FALSE;
}
- return FALSE;
+ return GetEventHandler()->ProcessEvent(event);
}
bool wxWindowMSW::HandleKeyDown(WXWPARAM wParam, WXLPARAM lParam)
if ( id != -1 ) // VZ: does this ever happen (FIXME)?
{
- wxKeyEvent event(CreateKeyEvent(wxEVT_KEY_DOWN, id, lParam));
+ wxKeyEvent event(CreateKeyEvent(wxEVT_KEY_DOWN, id, lParam, wParam));
if ( GetEventHandler()->ProcessEvent(event) )
{
return TRUE;
if ( id != -1 ) // VZ: does this ever happen (FIXME)?
{
- wxKeyEvent event(CreateKeyEvent(wxEVT_KEY_UP, id, lParam));
+ wxKeyEvent event(CreateKeyEvent(wxEVT_KEY_UP, id, lParam, wParam));
if ( GetEventHandler()->ProcessEvent(event) )
return TRUE;
}
return FALSE;
}
+int wxWindowMSW::HandleMenuChar(int chAccel, WXLPARAM lParam)
+{
+ // FIXME: implement GetMenuItemCount for WinCE, possibly
+ // in terms of GetMenuItemInfo
+#ifndef __WXWINCE__
+ const HMENU hmenu = (HMENU)lParam;
+
+ MENUITEMINFO mii;
+ wxZeroMemory(mii);
+ mii.cbSize = sizeof(MENUITEMINFO);
+ mii.fMask = MIIM_TYPE | MIIM_DATA;
+
+ // find if we have this letter in any owner drawn item
+ const int count = ::GetMenuItemCount(hmenu);
+ for ( int i = 0; i < count; i++ )
+ {
+ if ( ::GetMenuItemInfo(hmenu, i, TRUE, &mii) )
+ {
+ if ( mii.fType == MFT_OWNERDRAW )
+ {
+ // dwItemData member of the MENUITEMINFO is a
+ // pointer to the associated wxMenuItem -- see the
+ // menu creation code
+ wxMenuItem *item = (wxMenuItem*)mii.dwItemData;
+
+ const wxChar *p = wxStrchr(item->GetText(), _T('&'));
+ while ( p++ )
+ {
+ if ( *p == _T('&') )
+ {
+ // this is not the accel char, find the real one
+ p = wxStrchr(p + 1, _T('&'));
+ }
+ else // got the accel char
+ {
+ // FIXME-UNICODE: this comparison doesn't risk to work
+ // for non ASCII accelerator characters I'm afraid, but
+ // what can we do?
+ if ( wxToupper(*p) == chAccel )
+ {
+ return i;
+ }
+ else
+ {
+ // this one doesn't match
+ break;
+ }
+ }
+ }
+ }
+ }
+ else // failed to get the menu text?
+ {
+ // it's not fatal, so don't show error, but still log
+ // it
+ wxLogLastError(_T("GetMenuItemInfo"));
+ }
+ }
+#endif
+ return wxNOT_FOUND;
+}
+
// ---------------------------------------------------------------------------
// joystick
// ---------------------------------------------------------------------------
// ---------------------------------------------------------------------------
bool wxWindowMSW::MSWOnScroll(int orientation, WXWORD wParam,
- WXWORD pos, WXHWND control)
+ WXWORD pos, WXHWND control)
{
if ( control )
{
case SB_THUMBPOSITION:
case SB_THUMBTRACK:
-#ifdef __WIN32__
// under Win32, the scrollbar range and position are 32 bit integers,
// but WM_[HV]SCROLL only carry the low 16 bits of them, so we must
// explicitly query the scrollbar for the correct position (this must
// be done only for these two SB_ events as they are the only one
// carrying the scrollbar position)
{
- SCROLLINFO scrollInfo;
- wxZeroMemory(scrollInfo);
- scrollInfo.cbSize = sizeof(SCROLLINFO);
+ WinStruct<SCROLLINFO> scrollInfo;
scrollInfo.fMask = SIF_TRACKPOS;
if ( !::GetScrollInfo(GetHwnd(),
: SB_VERT,
&scrollInfo) )
{
- wxLogLastError(_T("GetScrollInfo"));
+ // Not neccessarily an error, if there are no scrollbars yet.
+ // wxLogLastError(_T("GetScrollInfo"));
}
event.SetPosition(scrollInfo.nTrackPos);
}
-#endif // Win32
event.m_eventType = wParam == SB_THUMBPOSITION
? wxEVT_SCROLLWIN_THUMBRELEASE
case VK_CONTROL: id = WXK_CONTROL; break;
case VK_MENU : id = WXK_MENU; break;
case VK_PAUSE: id = WXK_PAUSE; break;
+ case VK_CAPITAL: id = WXK_CAPITAL; break;
case VK_SPACE: id = WXK_SPACE; break;
case VK_ESCAPE: id = WXK_ESCAPE; break;
case VK_PRIOR: id = WXK_PRIOR; break;
case VK_F24: id = WXK_F24; break;
case VK_NUMLOCK: id = WXK_NUMLOCK; break;
case VK_SCROLL: id = WXK_SCROLL; break;
+
+ case VK_OEM_1: id = ';'; break;
+ case VK_OEM_PLUS: id = '+'; break;
+ case VK_OEM_COMMA: id = ','; break;
+ case VK_OEM_MINUS: id = '-'; break;
+ case VK_OEM_PERIOD: id = '.'; break;
+ case VK_OEM_2: id = '/'; break;
+ case VK_OEM_3: id = '~'; break;
+ case VK_OEM_4: id = '['; break;
+ case VK_OEM_5: id = '\\'; break;
+ case VK_OEM_6: id = ']'; break;
+ case VK_OEM_7: id = '\''; break;
+
+#ifdef VK_APPS
+ case VK_LWIN: id = WXK_WINDOWS_LEFT; break;
+ case VK_RWIN: id = WXK_WINDOWS_RIGHT; break;
+ case VK_APPS: id = WXK_WINDOWS_MENU; break;
+#endif // VK_APPS defined
+
default:
id = 0;
}
win = wxFindWinFromHandle((WXHWND)hwnd);
if ( !win )
{
- // all these hacks only work under Win32 anyhow
-#ifdef __WIN32__
-
#if wxUSE_RADIOBOX
// native radiobuttons return DLGC_RADIOBUTTON here and for any
// wxWindow class which overrides WM_GETDLGCODE processing to
win = wxSpinCtrl::GetSpinForTextCtrl((WXHWND)hwnd);
}
#endif // wxUSE_SPINCTRL
-
-#endif // Win32
}
}
// FIXME: this is clearly not the best way to do it but I think we'll
// need to change HWND <-> wxWindow code more heavily than I can
// do it now to fix it
+#ifndef __WXMICROWIN__
if ( ::GetWindow(hwnd, GW_OWNER) )
{
// it's a dialog box, don't go upwards
break;
}
+#endif
hwnd = ::GetParent(hwnd);
win = wxFindWinFromHandle((WXHWND)hwnd);
return win;
}
-#ifndef __WXMICROWIN__
+#if !defined(__WXMICROWIN__) && !defined(__WXWINCE__)
// Windows keyboard hook. Allows interception of e.g. F1, ESCAPE
// in active frames and dialogs, regardless of where the focus is.
wxTheKeyboardHookProc = MakeProcInstance((FARPROC) wxKeyboardHook, wxGetInstance());
wxTheKeyboardHook = SetWindowsHookEx(WH_KEYBOARD, (HOOKPROC) wxTheKeyboardHookProc, wxGetInstance(),
-#if defined(__WIN32__) && !defined(__TWIN32__)
GetCurrentThreadId()
// (DWORD)GetCurrentProcess()); // This is another possibility. Which is right?
-#else
- GetCurrentTask()
-#endif
);
}
else
{
UnhookWindowsHookEx(wxTheKeyboardHook);
-
- // avoids warning about statement with no effect (FreeProcInstance
- // doesn't do anything under Win32)
-#if !defined(WIN32) && !defined(_WIN32) && !defined(__WIN32__) && !defined(__NT__) && !defined(__GNUWIN32__)
- FreeProcInstance(wxTheKeyboardHookProc);
-#endif
}
}
case 0x0047: return "WM_WINDOWPOSCHANGED";
case 0x0048: return "WM_POWER";
-#ifdef __WIN32__
case 0x004A: return "WM_COPYDATA";
case 0x004B: return "WM_CANCELJOURNAL";
case 0x004E: return "WM_NOTIFY";
case 0x007E: return "WM_DISPLAYCHANGE";
case 0x007F: return "WM_GETICON";
case 0x0080: return "WM_SETICON";
-#endif //WIN32
case 0x0081: return "WM_NCCREATE";
case 0x0082: return "WM_NCDESTROY";
case 0x0107: return "WM_SYSDEADCHAR";
case 0x0108: return "WM_KEYLAST";
-#ifdef __WIN32__
case 0x010D: return "WM_IME_STARTCOMPOSITION";
case 0x010E: return "WM_IME_ENDCOMPOSITION";
case 0x010F: return "WM_IME_COMPOSITION";
-#endif //WIN32
case 0x0110: return "WM_INITDIALOG";
case 0x0111: return "WM_COMMAND";
case 0x0211: return "WM_ENTERMENULOOP";
case 0x0212: return "WM_EXITMENULOOP";
-#ifdef __WIN32__
case 0x0213: return "WM_NEXTMENU";
case 0x0214: return "WM_SIZING";
case 0x0215: return "WM_CAPTURECHANGED";
case 0x0216: return "WM_MOVING";
case 0x0218: return "WM_POWERBROADCAST";
case 0x0219: return "WM_DEVICECHANGE";
-#endif //WIN32
case 0x0220: return "WM_MDICREATE";
case 0x0221: return "WM_MDIDESTROY";
case 0x0230: return "WM_MDISETMENU";
case 0x0233: return "WM_DROPFILES";
-#ifdef __WIN32__
case 0x0281: return "WM_IME_SETCONTEXT";
case 0x0282: return "WM_IME_NOTIFY";
case 0x0283: return "WM_IME_CONTROL";
case 0x0286: return "WM_IME_CHAR";
case 0x0290: return "WM_IME_KEYDOWN";
case 0x0291: return "WM_IME_KEYUP";
-#endif //WIN32
case 0x0300: return "WM_CUT";
case 0x0301: return "WM_COPY";
case 0x030F: return "WM_QUERYNEWPALETTE";
case 0x0310: return "WM_PALETTEISCHANGING";
case 0x0311: return "WM_PALETTECHANGED";
+#if wxUSE_HOTKEY
+ case 0x0312: return "WM_HOTKEY";
+#endif
-#ifdef __WIN32__
// common controls messages - although they're not strictly speaking
// standard, it's nice to decode them nevertheless
case WM_USER+61: return "TB_GETTEXTROWS";
case WM_USER+41: return "TB_GETBITMAPFLAGS";
-#endif //WIN32
-
default:
static char s_szBuf[128];
sprintf(s_szBuf, "<unknown message = %d>", message);
// Find the wxWindow at the current mouse position, returning the mouse
// position.
-wxWindow* wxFindWindowAtPointer(wxPoint& WXUNUSED(pt))
+wxWindow* wxFindWindowAtPointer(wxPoint& pt)
{
- return wxFindWindowAtPoint(wxGetMousePosition());
+ pt = wxGetMousePosition();
+ return wxFindWindowAtPoint(pt);
}
wxWindow* wxFindWindowAtPoint(const wxPoint& pt)
{
POINT pt;
GetCursorPos( & pt );
+
return wxPoint(pt.x, pt.y);
}
+#if wxUSE_HOTKEY
+
+bool wxWindowMSW::RegisterHotKey(int hotkeyId, int modifiers, int keycode)
+{
+ UINT win_modifiers=0;
+ if ( modifiers & wxMOD_ALT )
+ win_modifiers |= MOD_ALT;
+ if ( modifiers & wxMOD_SHIFT )
+ win_modifiers |= MOD_SHIFT;
+ if ( modifiers & wxMOD_CONTROL )
+ win_modifiers |= MOD_CONTROL;
+ if ( modifiers & wxMOD_WIN )
+ win_modifiers |= MOD_WIN;
+
+ if ( !::RegisterHotKey(GetHwnd(), hotkeyId, win_modifiers, keycode) )
+ {
+ wxLogLastError(_T("RegisterHotKey"));
+
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+bool wxWindowMSW::UnregisterHotKey(int hotkeyId)
+{
+ if ( !::UnregisterHotKey(GetHwnd(), hotkeyId) )
+ {
+ wxLogLastError(_T("UnregisterHotKey"));
+
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+bool wxWindowMSW::HandleHotKey(WXWPARAM wParam, WXLPARAM lParam)
+{
+ int hotkeyId = wParam;
+ int virtualKey = HIWORD(lParam);
+ int win_modifiers = LOWORD(lParam);
+
+ wxKeyEvent event(CreateKeyEvent(wxEVT_HOTKEY, virtualKey, wParam, lParam));
+ event.SetId(hotkeyId);
+ event.m_shiftDown = (win_modifiers & MOD_SHIFT) != 0;
+ event.m_controlDown = (win_modifiers & MOD_CONTROL) != 0;
+ event.m_altDown = (win_modifiers & MOD_ALT) != 0;
+ event.m_metaDown = (win_modifiers & MOD_WIN) != 0;
+
+ return GetEventHandler()->ProcessEvent(event);
+}
+
+#endif // wxUSE_HOTKEY
+