#include "wx/dcclient.h"
#include "wx/utils.h"
#include "wx/app.h"
- #include "wx/panel.h"
#include "wx/layout.h"
#include "wx/dialog.h"
#include "wx/frame.h"
#include "wx/button.h"
#include "wx/msgdlg.h"
#include "wx/settings.h"
-
- #include <stdio.h>
+ #include "wx/statbox.h"
#endif
#if wxUSE_OWNER_DRAWN
wxMenu *wxCurrentPopupMenu = NULL;
#endif // wxUSE_MENUS_NATIVE
-extern wxList WXDLLEXPORT wxPendingDelete;
extern const wxChar *wxCanvasClassName;
// ---------------------------------------------------------------------------
// get the text metrics for the current font
static TEXTMETRIC wxGetTextMetrics(const wxWindowMSW *win);
-// check if the mouse is in the window or its child
-//static bool IsMouseInWindow(HWND hwnd);
+// wrapper around BringWindowToTop() API
+static inline void wxBringWindowToTop(HWND hwnd)
+{
+#ifdef __WXMICROWIN__
+ // It seems that MicroWindows brings the _parent_ of the window to the top,
+ // which can be the wrong one.
+
+ // activate (set focus to) specified window
+ ::SetFocus(hwnd);
+
+ // 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) )
+ {
+ wxLogLastError(_T("BringWindowToTop"));
+ }
+#endif // __WXMICROWIN__/!__WXMICROWIN__
+}
// ---------------------------------------------------------------------------
// event tables
EVT_SYS_COLOUR_CHANGED(wxWindowMSW::OnSysColourChanged)
EVT_INIT_DIALOG(wxWindowMSW::OnInitDialog)
EVT_IDLE(wxWindowMSW::OnIdle)
- EVT_SET_FOCUS(wxWindowMSW::OnSetFocus)
END_EVENT_TABLE()
// ===========================================================================
wxWindow *wxWindowMSW::FindItem(long id) const
{
#if wxUSE_CONTROLS
- wxControl *item = wxDynamicThisCast(this, wxControl);
+ wxControl *item = wxDynamicCastThis(wxControl);
if ( item )
{
// is it we or one of our "internal" children?
{
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;
#ifndef __WXMICROWIN__
::SetLastError(0);
#endif
-
+
if ( !::SetFocus(hWnd) )
{
// was there really an error?
if ( show )
{
- BringWindowToTop(hWnd);
+ wxBringWindowToTop(hWnd);
}
return TRUE;
// Raise the window to the top of the Z order
void wxWindowMSW::Raise()
{
-#ifdef __WIN16__
- ::BringWindowToTop(GetHwnd());
-#else // Win32
- ::SetForegroundWindow(GetHwnd());
-#endif
+ wxBringWindowToTop(GetHwnd());
}
// Lower the window to the bottom of the Z order
#endif // WXWIN_COMPATIBILITY
+inline int GetScrollPosition(HWND hWnd, int wOrient)
+{
+#ifdef __WXMICROWIN__
+ return ::GetScrollPosWX(hWnd, wOrient);
+#else
+ return ::GetScrollPos(hWnd, wOrient);
+#endif
+}
+
int wxWindowMSW::GetScrollPos(int orient) const
{
int wOrient;
wOrient = SB_HORZ;
else
wOrient = SB_VERT;
+
HWND hWnd = GetHwnd();
- if ( hWnd )
- {
-#ifdef __WXMICROWIN__
- return ::GetScrollPosWX(hWnd, wOrient);
-#else
- return ::GetScrollPos(hWnd, wOrient);
-#endif
- }
- else
- return 0;
+ wxCHECK_MSG( hWnd, 0, _T("no HWND in GetScrollPos") );
+
+ return GetScrollPosition(hWnd, wOrient);
}
// This now returns the whole range, not just the number
::ScrollWindow(GetHwnd(), dx, dy, prect ? &rect : NULL, NULL);
}
+static bool ScrollVertically(HWND hwnd, int kind, int count)
+{
+ int posStart = GetScrollPosition(hwnd, SB_VERT);
+
+ int pos = posStart;
+ for ( int n = 0; n < count; n++ )
+ {
+ ::SendMessage(hwnd, WM_VSCROLL, kind, 0);
+
+ int posNew = GetScrollPosition(hwnd, SB_VERT);
+ if ( posNew == pos )
+ {
+ // don't bother to continue, we're already at top/bottom
+ break;
+ }
+
+ pos = posNew;
+ }
+
+ return pos != posStart;
+}
+
+bool wxWindowMSW::ScrollLines(int lines)
+{
+ bool down = lines > 0;
+
+ return ScrollVertically(GetHwnd(),
+ down ? SB_LINEDOWN : SB_LINEUP,
+ down ? lines : -lines);
+}
+
+bool wxWindowMSW::ScrollPages(int pages)
+{
+ bool down = pages > 0;
+
+ return ScrollVertically(GetHwnd(),
+ down ? SB_PAGEDOWN : SB_PAGEUP,
+ down ? pages : -pages);
+}
+
// ---------------------------------------------------------------------------
// subclassing
// ---------------------------------------------------------------------------
wxAssociateWinWithHandle(hwnd, this);
m_oldWndProc = (WXFARPROC) GetWindowLong(hwnd, GWL_WNDPROC);
+
+ wxASSERT( (WXFARPROC) m_oldWndProc != (WXFARPROC) wxWndProc );
+
SetWindowLong(hwnd, GWL_WNDPROC, (LONG) wxWndProc);
}
dc.Clear();
}
+static inline void SendSetRedraw(HWND hwnd, bool on)
+{
+ ::SendMessage(hwnd, WM_SETREDRAW, (WPARAM)on, 0);
+}
+
+void wxWindowMSW::Freeze()
+{
+ SendSetRedraw(GetHwnd(), FALSE);
+}
+
+void wxWindowMSW::Thaw()
+{
+ SendSetRedraw(GetHwnd(), TRUE);
+
+ // we need to refresh everything or otherwise he invalidated area is not
+ // repainted
+ Refresh();
+}
+
void wxWindowMSW::Refresh(bool eraseBack, const wxRect *rect)
{
HWND hWnd = GetHwnd();
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
// ---------------------------------------------------------------------------
bProcess = FALSE;
}
-#if wxUSE_BUTTON
+ // FIXME: this should be handled by
+ // wxNavigationKeyEvent handler and not here!!
else
{
- wxPanel *panel = wxDynamicThisCast(this, wxPanel);
- wxButton *btn = NULL;
- if ( panel )
- {
- // panel may have a default button which should
- // be activated by Enter
- btn = panel->GetDefaultItem();
- }
-
+#if wxUSE_BUTTON
+ wxButton *btn = wxDynamicCast(GetDefaultItem(),
+ wxButton);
if ( btn && btn->IsEnabled() )
{
// if we do have a default button, do press it
return TRUE;
}
- // else: but if it does not it makes sense to make
- // it work like a TAB - and that's what we do.
- // Note that Ctrl-Enter always works this way.
- }
+ 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;
+ }
+ }
}
break;
if ( GetEventHandler()->ProcessEvent(event) )
{
-#if wxUSE_BUTTON
- wxButton *btn = wxDynamicCast(FindFocus(), wxButton);
- if ( btn )
- {
- // the button which has focus should be default
- btn->SetDefault();
- }
-#endif // wxUSE_BUTTON
-
return TRUE;
}
}
}
-#else
+#else // 0
// let ::IsDialogMessage() do almost everything and handle just the
// things it doesn't here: Ctrl-TAB for switching notebook pages
if ( msg->message == WM_KEYDOWN )
}
}
}
-#endif // 0
+#endif // 1/0
if ( ::IsDialogMessage(GetHwnd(), msg) )
{
#endif // wxUSE_ACCEL
}
+bool wxWindowMSW::MSWShouldPreProcessMessage(WXMSG* pMsg)
+{
+ // preprocess all messages by default
+ return TRUE;
+}
+
// ---------------------------------------------------------------------------
// message params unpackers (different for Win16 and Win32)
// ---------------------------------------------------------------------------
break;
case WM_DESTROY:
- processed = HandleDestroy();
+ // never set processed to TRUE and *always* pass WM_DESTROY to
+ // DefWindowProc() as Windows may do some internal cleanup when
+ // processing it and failing to pass the message along may cause
+ // memory and resource leaks!
+ (void)HandleDestroy();
break;
case WM_MOVE:
}
break;
-#if defined(__WXUNIVERSAL__) && !defined(__WXMICROWIN__)
+#ifndef __WXMICROWIN__
case WM_ACTIVATEAPP:
wxTheApp->SetActive(wParam != 0, FindFocus());
break;
-
- case WM_NCHITTEST:
- // we shouldn't allow the windows which don't want to get focus to
- // get it
- if ( !AcceptsFocus() )
- {
- rc.result = HTTRANSPARENT;
- processed = TRUE;
- }
- break;
-#endif // __WXUNIVERSAL__
+#endif
case WM_ACTIVATE:
{
#endif
case WM_LBUTTONDOWN:
- // set focus to this window
- if (AcceptsFocus())
- SetFocus();
-
- // fall through
-
case WM_LBUTTONUP:
case WM_LBUTTONDBLCLK:
case WM_RBUTTONDOWN:
case WM_MBUTTONDOWN:
case WM_MBUTTONUP:
case WM_MBUTTONDBLCLK:
- processed = HandleMouseEvent(message,
+ {
+ 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)
+ {
+ if (!win->IsEnabled())
+ {
+ processed = TRUE;
+ break;
+ }
+ win = win->GetParent();
+ if (win && win->IsTopLevel())
+ break;
+ }
+#endif // __WXMICROWIN__
+ if (!processed)
+ {
+ if (message == WM_LBUTTONDOWN && AcceptsFocus())
+ SetFocus();
+ processed = HandleMouseEvent(message,
GET_X_LPARAM(lParam),
GET_Y_LPARAM(lParam),
- wParam);
- break;
+ wParam);
+ }
+ break;
+ }
-#ifdef MM_JOY1MOVE // __WXMICROWIN__
+#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)
+ {
+ if (!win->IsEnabled())
+ {
+ processed = TRUE;
+ break;
+ }
+ win = win->GetParent();
+ if (win && win->IsTopLevel())
+ break;
+ }
+ break;
+ }
+#endif // __WXMICROWIN__
+
+#ifdef MM_JOY1MOVE
case MM_JOY1MOVE:
case MM_JOY2MOVE:
case MM_JOY1ZMOVE:
GET_Y_LPARAM(lParam),
wParam);
break;
-#endif
+#endif // __WXMICROWIN__
case WM_SYSCOMMAND:
processed = HandleSysCommand(wParam, lParam);
#endif // Win95
// for these messages we must return TRUE if process the message
-#ifdef WM_DRAWITEM // __WXMICROWIN__
+#ifdef WM_DRAWITEM
case WM_DRAWITEM:
case WM_MEASUREITEM:
{
rc.result = TRUE;
}
break;
-#endif
+#endif // defined(WM_DRAWITEM)
+
case WM_GETDLGCODE:
if ( m_lDlgCode )
{
lParam);
}
break;
-#endif
+#endif // !__WXMICROWIN__
// the return value for this message is ignored
case WM_SYSCOLORCHANGE:
}
break;
#endif // __WIN32__
+
+#ifdef __WXUNIVERSAL__
+ case WM_NCHITTEST:
+ // we shouldn't allow the windows which don't want to get focus to
+ // get it
+ if ( !AcceptsFocus() )
+ {
+ rc.result = HTTRANSPARENT;
+ processed = TRUE;
+ }
+ break;
+#endif // __WXUNIVERSAL__
}
if ( !processed )
wxWndHook = this;
+#ifndef __WXMICROWIN__
if ( dialog_template )
{
-#ifndef __WXMICROWIN__
// for the dialogs without wxDIALOG_NO_PARENT style, use the top level
// app window as parent - this avoids creating modal dialogs without
// parent
{
wxLogLastError(wxT("MoveWindow"));
}
-#endif
- // __WXMICROWIN__
}
else // creating a normal window, not a dialog
+#endif // !__WXMICROWIN__
{
int controlId = 0;
if ( style & WS_CHILD )
// finally try this window too (catches toolbar case)
return MSWOnNotify(idCtrl, lParam, result);
-#else
+#else // __WXMICROWIN__
return FALSE;
#endif
}
if ( !endSession )
return FALSE;
+ // only send once
+ if ( (this != wxTheApp->GetTopWindow()) )
+ return FALSE;
+
wxCloseEvent event(wxEVT_END_SESSION, -1);
event.SetEventObject(wxTheApp);
event.SetCanVeto(FALSE);
event.SetLoggingOff( (logOff == (long)ENDSESSION_LOGOFF) );
- if ( (this == wxTheApp->GetTopWindow()) && // Only send once
- wxTheApp->ProcessEvent(event))
- {
- }
- return TRUE;
+
+ return wxTheApp->ProcessEvent(event);
}
// ---------------------------------------------------------------------------
// activation/focus
// ---------------------------------------------------------------------------
-void wxWindowMSW::OnSetFocus(wxFocusEvent& event)
-{
- // panel wants to track the window which was the last to have focus in it,
- // so we want to set ourselves as the window which last had focus
- //
- // notice that it's also important to do it upwards the tree becaus
- // otherwise when the top level panel gets focus, it won't set it back to
- // us, but to some other sibling
- wxWindow *win = (wxWindow *)this;
- while ( win )
- {
- wxWindow *parent = win->GetParent();
- wxPanel *panel = wxDynamicCast(parent, wxPanel);
- if ( panel )
- {
- panel->SetLastFocus(win);
- }
-
- win = parent;
- }
-
- wxLogTrace(_T("focus"), _T("%s (0x%08x) gets focus"),
- GetClassInfo()->GetClassName(), GetHandle());
-
- event.Skip();
-}
-
bool wxWindowMSW::HandleActivate(int state,
bool WXUNUSED(minimized),
WXHWND WXUNUSED(activate))
bool wxWindowMSW::HandleSetFocus(WXHWND hwnd)
{
+ // notify the parent keeping track of focus for the kbd navigation
+ // purposes that we got it
+ wxChildFocusEvent eventFocus((wxWindow *)this);
+ (void)GetEventHandler()->ProcessEvent(eventFocus);
+
#if wxUSE_CARET
// Deal with caret
if ( m_caret )
}
#endif // wxUSE_CARET
+#if wxUSE_TEXTCTRL
+ // If it's a wxTextCtrl don't send the event as it will be done
+ // after the control gets to process it from EN_FOCUS handler
+ if ( wxDynamicCastThis(wxTextCtrl) )
+ {
+ return FALSE;
+ }
+#endif // wxUSE_TEXTCTRL
+
wxFocusEvent event(wxEVT_SET_FOCUS, m_windowId);
event.SetEventObject(this);
}
#endif // wxUSE_CARET
+#if wxUSE_TEXTCTRL
+ // If it's a wxTextCtrl don't send the event as it will be done
+ // after the control gets to process it.
+ wxTextCtrl *ctrl = wxDynamicCastThis(wxTextCtrl);
+ if ( ctrl )
+ {
+ return FALSE;
+ }
+#endif
+
wxFocusEvent event(wxEVT_KILL_FOCUS, m_windowId);
event.SetEventObject(this);
wxDropFilesEvent event(wxEVT_DROP_FILES, gwFilesDropped, files);
event.m_eventObject = this;
- event.m_pos.x = dropPoint.x; event.m_pos.x = dropPoint.y;
+ event.m_pos.x = dropPoint.x;
+ event.m_pos.y = dropPoint.y;
bool rc = GetEventHandler()->ProcessEvent(event);
delete[] files;
return rc;
-#else
+#else // __WXMICROWIN__
return FALSE;
#endif
}
// cursor set, stop here
return TRUE;
}
-#endif
+#endif // __WXMICROWIN__
+
// pass up the window chain
return FALSE;
}
#if wxUSE_MENUS_NATIVE
// is it a menu item?
- if ( id == 0 )
+ DRAWITEMSTRUCT *pDrawStruct = (DRAWITEMSTRUCT *)itemStruct;
+ if ( id == 0 && pDrawStruct->CtlType == ODT_MENU )
{
- DRAWITEMSTRUCT *pDrawStruct = (DRAWITEMSTRUCT *)itemStruct;
wxMenuItem *pMenuItem = (wxMenuItem *)(pDrawStruct->itemData);
wxCHECK( pMenuItem->IsKindOf(CLASSINFO(wxMenuItem)), FALSE );
{
#if wxUSE_OWNER_DRAWN
// is it a menu item?
- if ( id == 0 )
+ MEASUREITEMSTRUCT *pMeasureStruct = (MEASUREITEMSTRUCT *)itemStruct;
+ if ( id == 0 && pMeasureStruct->CtlType == ODT_MENU )
{
- MEASUREITEMSTRUCT *pMeasureStruct = (MEASUREITEMSTRUCT *)itemStruct;
wxMenuItem *pMenuItem = (wxMenuItem *)(pMeasureStruct->itemData);
wxCHECK( pMenuItem->IsKindOf(CLASSINFO(wxMenuItem)), FALSE );
*brush = hBrush;
return hBrush != 0;
-#else
+#else // __WXMICROWIN__
return FALSE;
#endif
}
case VK_NUMPAD7: id = WXK_NUMPAD7; break;
case VK_NUMPAD8: id = WXK_NUMPAD8; break;
case VK_NUMPAD9: id = WXK_NUMPAD9; break;
- case VK_MULTIPLY: id = WXK_MULTIPLY; break;
- case 0xBB: // VK_OEM_PLUS
- case VK_ADD: id = WXK_ADD; break;
- case 0xBD: // VK_OEM_MINUS
- case VK_SUBTRACT: id = WXK_SUBTRACT; break;
- case 0xBE: // VK_OEM_PERIOD
- case VK_DECIMAL: id = WXK_DECIMAL; break;
- case VK_DIVIDE: id = WXK_DIVIDE; break;
+ case VK_MULTIPLY: id = WXK_NUMPAD_MULTIPLY; break;
+ case VK_ADD: id = WXK_NUMPAD_ADD; break;
+ case VK_SUBTRACT: id = WXK_NUMPAD_SUBTRACT; break;
+ case VK_DECIMAL: id = WXK_NUMPAD_DECIMAL; break;
+ case VK_DIVIDE: id = WXK_NUMPAD_DIVIDE; break;
case VK_F1: id = WXK_F1; break;
case VK_F2: id = WXK_F2; break;
case VK_F3: id = WXK_F3; break;
case WXK_NUMPAD7: keySym = VK_NUMPAD7; break;
case WXK_NUMPAD8: keySym = VK_NUMPAD8; break;
case WXK_NUMPAD9: keySym = VK_NUMPAD9; break;
- case WXK_MULTIPLY: keySym = VK_MULTIPLY; break;
- case WXK_ADD: keySym = VK_ADD; break;
- case WXK_SUBTRACT: keySym = VK_SUBTRACT; break;
- case WXK_DECIMAL: keySym = VK_DECIMAL; break;
- case WXK_DIVIDE: keySym = VK_DIVIDE; break;
+ case WXK_NUMPAD_MULTIPLY: keySym = VK_MULTIPLY; break;
+ case WXK_NUMPAD_ADD: keySym = VK_ADD; break;
+ case WXK_NUMPAD_SUBTRACT: keySym = VK_SUBTRACT; break;
+ case WXK_NUMPAD_DECIMAL: keySym = VK_DECIMAL; break;
+ case WXK_NUMPAD_DIVIDE: keySym = VK_DIVIDE; break;
case WXK_F1: keySym = VK_F1; break;
case WXK_F2: keySym = VK_F2; break;
case WXK_F3: keySym = VK_F3; break;
#endif // wxUSE_SPINCTRL
#endif // Win32
-
- if ( !win )
- {
- // hwnd is not a wxWindow, try its parent next below
- hwnd = ::GetParent(hwnd);
- }
}
}
while ( hwnd && !win )
{
- win = wxFindWinFromHandle((WXHWND)hwnd);
+ // this is a really ugly hack needed to avoid mistakenly returning the
+ // parent frame wxWindow for the find/replace modeless dialog HWND -
+ // this, in turn, is needed to call IsDialogMessage() from
+ // wxApp::ProcessMessage() as for this we must return NULL from here
+ //
+ // 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
+ if ( ::GetWindow(hwnd, GW_OWNER) )
+ {
+ // it's a dialog box, don't go upwards
+ break;
+ }
+
hwnd = ::GetParent(hwnd);
+ win = wxFindWinFromHandle((WXHWND)hwnd);
}
return win;
return (int)CallNextHookEx(wxTheKeyboardHook, nCode, wParam, lParam);
}
-#endif
+
+#endif // !__WXMICROWIN__
#ifdef __WXDEBUG__
const char *wxGetMessageName(int message)