X-Git-Url: https://git.saurik.com/wxWidgets.git/blobdiff_plain/cde9f08e1f2bba81294708c1d65bb869ed744e56..06298235850b7e576ef77a9a95b521534f18a4d9:/src/msw/dialog.cpp?ds=inline diff --git a/src/msw/dialog.cpp b/src/msw/dialog.cpp index af8ad17747..2820cfaa33 100644 --- a/src/msw/dialog.cpp +++ b/src/msw/dialog.cpp @@ -26,9 +26,12 @@ #include "wx/frame.h" #include "wx/app.h" #include "wx/settings.h" +#include "wx/intl.h" +#include "wx/log.h" #endif #include "wx/msw/private.h" +#include "wx/log.h" #if wxUSE_COMMON_DIALOGS #include @@ -39,41 +42,23 @@ // Lists to keep track of windows, so we can disable/enable them // for modal dialogs -wxList wxModalDialogs; -wxList wxModelessWindows; // Frames and modeless dialogs +wxWindowList wxModalDialogs; +wxWindowList wxModelessWindows; // Frames and modeless dialogs extern wxList WXDLLEXPORT wxPendingDelete; -#if !USE_SHARED_LIBRARY -IMPLEMENT_DYNAMIC_CLASS(wxDialog, wxPanel) + IMPLEMENT_DYNAMIC_CLASS(wxDialog, wxPanel) -BEGIN_EVENT_TABLE(wxDialog, wxPanel) - EVT_SIZE(wxDialog::OnSize) - EVT_BUTTON(wxID_OK, wxDialog::OnOK) - EVT_BUTTON(wxID_APPLY, wxDialog::OnApply) - EVT_BUTTON(wxID_CANCEL, wxDialog::OnCancel) - EVT_CHAR_HOOK(wxDialog::OnCharHook) - EVT_SYS_COLOUR_CHANGED(wxDialog::OnSysColourChanged) - EVT_CLOSE(wxDialog::OnCloseWindow) -END_EVENT_TABLE() + BEGIN_EVENT_TABLE(wxDialog, wxPanel) + EVT_SIZE(wxDialog::OnSize) + EVT_BUTTON(wxID_OK, wxDialog::OnOK) + EVT_BUTTON(wxID_APPLY, wxDialog::OnApply) + EVT_BUTTON(wxID_CANCEL, wxDialog::OnCancel) + EVT_CHAR_HOOK(wxDialog::OnCharHook) + EVT_SYS_COLOUR_CHANGED(wxDialog::OnSysColourChanged) + EVT_CLOSE(wxDialog::OnCloseWindow) + END_EVENT_TABLE() -#endif - -long wxDialog::MSWDefWindowProc(WXUINT nMsg, WXWPARAM wParam, WXLPARAM lParam) -{ - return ::CallWindowProc(CASTWNDPROC m_oldWndProc, (HWND) GetHWND(), (UINT) nMsg, (WPARAM) wParam, (LPARAM) lParam); -} - -bool wxDialog::MSWProcessMessage(WXMSG* pMsg) -{ - return (::IsDialogMessage((HWND) GetHWND(), (MSG*)pMsg) != 0); -} - -bool wxDialog::MSWOnClose(void) -{ - return Close(); -} - -wxDialog::wxDialog(void) +wxDialog::wxDialog() { m_isShown = FALSE; m_modalShowing = FALSE; @@ -82,65 +67,87 @@ wxDialog::wxDialog(void) } bool wxDialog::Create(wxWindow *parent, wxWindowID id, - const wxString& title, - const wxPoint& pos, - const wxSize& size, - long style, - const wxString& name) + const wxString& title, + const wxPoint& pos, + const wxSize& size, + long style, + const wxString& name) { - SetBackgroundColour(wxSystemSettings::GetSystemColour(wxSYS_COLOUR_3DFACE)); - SetName(name); - - if (!parent) - wxTopLevelWindows.Append(this); +#if wxUSE_TOOLTIPS + m_hwndToolTip = 0; +#endif -// windowFont = wxTheFontList->FindOrCreateFont(11, wxSWISS, wxNORMAL, wxNORMAL); + SetBackgroundColour(wxSystemSettings::GetSystemColour(wxSYS_COLOUR_3DFACE)); + SetName(name); - if (parent) parent->AddChild(this); + if (!parent) + wxTopLevelWindows.Append(this); - if ( id == -1 ) - m_windowId = (int)NewControlId(); - else - m_windowId = id; + // windowFont = wxTheFontList->FindOrCreateFont(11, wxSWISS, wxNORMAL, wxNORMAL); - int x = pos.x; - int y = pos.y; - int width = size.x; - int height = size.y; + if (parent) parent->AddChild(this); - if (x < 0) x = wxDIALOG_DEFAULT_X; - if (y < 0) y = wxDIALOG_DEFAULT_Y; + if ( id == -1 ) + m_windowId = (int)NewControlId(); + else + m_windowId = id; - m_windowStyle = style; + int x = pos.x; + int y = pos.y; + int width = size.x; + int height = size.y; - m_isShown = FALSE; - m_modalShowing = FALSE; + if (x < 0) x = wxDIALOG_DEFAULT_X; + if (y < 0) y = wxDIALOG_DEFAULT_Y; - if (width < 0) - width = 500; - if (height < 0) - height = 500; + m_windowStyle = style; - WXDWORD extendedStyle = MakeExtendedStyle(m_windowStyle); - if (m_windowStyle & wxSTAY_ON_TOP) - extendedStyle |= WS_EX_TOPMOST; + m_isShown = FALSE; + m_modalShowing = FALSE; - // Allows creation of dialogs with & without captions under MSWindows - if(style & wxCAPTION){ - MSWCreate(m_windowId, (wxWindow *)parent, NULL, this, NULL, x, y, width, height, 0, "wxCaptionDialog", - extendedStyle); - } - else{ - MSWCreate(m_windowId, (wxWindow *)parent, NULL, this, NULL, x, y, width, height, 0, "wxNoCaptionDialog", - extendedStyle); - } + if (width < 0) + width = 500; + if (height < 0) + height = 500; - SubclassWin(GetHWND()); + // All dialogs should really have this style + m_windowStyle |= wxTAB_TRAVERSAL; - SetWindowText((HWND) GetHWND(), (const char *)title); - SetFont(wxSystemSettings::GetSystemFont(wxSYS_DEFAULT_GUI_FONT)); + WXDWORD extendedStyle = MakeExtendedStyle(m_windowStyle); + if (m_windowStyle & wxSTAY_ON_TOP) + extendedStyle |= WS_EX_TOPMOST; - return TRUE; + // Allows creation of dialogs with & without captions under MSWindows, + // resizeable or not (but a resizeable dialog always has caption - + // otherwise it would look too strange) + const wxChar *dlg; + if ( style & wxRESIZE_BORDER ) + dlg = wxT("wxResizeableDialog"); + else if ( style & wxCAPTION ) + dlg = wxT("wxCaptionDialog"); + else + dlg = wxT("wxNoCaptionDialog"); + MSWCreate(m_windowId, parent, NULL, this, NULL, + x, y, width, height, + 0, // style is not used if we have dlg template + dlg, + extendedStyle); + + HWND hwnd = (HWND)GetHWND(); + + if ( !hwnd ) + { + wxLogError(_("Failed to create dialog.")); + + return FALSE; + } + + SubclassWin(GetHWND()); + + SetWindowText(hwnd, title); + SetFont(wxSystemSettings::GetSystemFont(wxSYS_DEFAULT_GUI_FONT)); + + return TRUE; } void wxDialog::SetModal(bool flag) @@ -150,7 +157,7 @@ void wxDialog::SetModal(bool flag) else if ( m_windowStyle & wxDIALOG_MODAL ) m_windowStyle -= wxDIALOG_MODAL ; - + wxModelessWindows.DeleteObject(this); if (!flag) wxModelessWindows.Append(this); @@ -162,9 +169,10 @@ wxDialog::~wxDialog() wxTopLevelWindows.DeleteObject(this); + Show(FALSE); + if (m_modalShowing) { - Show(FALSE); // For some reason, wxWindows can activate another task altogether // when a frame is destroyed after a modal dialog has been invoked. // Try to bring the parent to the top. @@ -176,14 +184,10 @@ wxDialog::~wxDialog() } m_modalShowing = FALSE; - if ( GetHWND() ) - ShowWindow((HWND) GetHWND(), SW_HIDE); if ( (GetWindowStyleFlag() & wxDIALOG_MODAL) != wxDIALOG_MODAL ) wxModelessWindows.DeleteObject(this); - UnsubclassWin(); - // If this is the last top-level window, exit. if (wxTheApp && (wxTopLevelWindows.Number() == 0)) { @@ -203,13 +207,16 @@ void wxDialog::OnCharHook(wxKeyEvent& event) { if (event.m_keyCode == WXK_ESCAPE) { - // Behaviour changed in 2.0: we'll send a Cancel message - // to the dialog instead of Close. - wxCommandEvent cancelEvent(wxEVT_COMMAND_BUTTON_CLICKED, wxID_CANCEL); - cancelEvent.SetEventObject( this ); - GetEventHandler()->ProcessEvent(cancelEvent); - - return; + // Behaviour changed in 2.0: we'll send a Cancel message + // to the dialog instead of Close. + wxCommandEvent cancelEvent(wxEVT_COMMAND_BUTTON_CLICKED, wxID_CANCEL); + cancelEvent.SetEventObject( this ); + GetEventHandler()->ProcessEvent(cancelEvent); + + // ensure that there is another message for this window so the + // ShowModal loop will exit and won't get stuck in GetMessage(). + ::PostMessage(GetHwnd(), WM_NULL, 0, 0); + return; } } // We didn't process this event. @@ -223,7 +230,7 @@ void wxDialog::OnPaint(wxPaintEvent& event) // wxWindow::OnPaint(event); } -void wxDialog::Fit(void) +void wxDialog::Fit() { wxWindow::Fit(); } @@ -233,16 +240,16 @@ void wxDialog::Iconize(bool WXUNUSED(iconize)) // Windows dialog boxes can't be iconized } -bool wxDialog::IsIconized(void) const +bool wxDialog::IsIconized() const { return FALSE; } -void wxDialog::SetClientSize(int width, int height) +void wxDialog::DoSetClientSize(int width, int height) { HWND hWnd = (HWND) GetHWND(); RECT rect; - GetClientRect(hWnd, &rect); + ::GetClientRect(hWnd, &rect); RECT rect2; GetWindowRect(hWnd, &rect2); @@ -270,11 +277,16 @@ void wxDialog::GetPosition(int *x, int *y) const *y = rect.top; } -bool wxDialog::IsShown(void) const +bool wxDialog::IsShown() const { return m_isShown; } +bool wxDialog::IsModal() const +{ + return wxModalDialogs.Find((wxDialog *)this) != 0; // const_cast +} + bool wxDialog::Show(bool show) { m_isShown = show; @@ -287,13 +299,13 @@ bool wxDialog::Show(bool show) #if WXGARBAGE_COLLECTION_ON /* MATTHEW: GC */ if (!modal) { if (show) { - if (!wxModelessWindows.Member(this)) - wxModelessWindows.Append(this); + if (!wxModelessWindows.Find(this)) + wxModelessWindows.Append(this); } else wxModelessWindows.DeleteObject(this); } if (show) { - if (!wxTopLevelWindows.Member(this)) + if (!wxTopLevelWindows.Find(this)) wxTopLevelWindows.Append(this); } else wxTopLevelWindows.DeleteObject(this); @@ -303,14 +315,20 @@ bool wxDialog::Show(bool show) { if (show) { - m_hwndOldFocus = (WXHWND)::GetFocus(); + // find the top level window which had focus before - we will restore + // focus to it later + m_hwndOldFocus = 0; + for ( HWND hwnd = ::GetFocus(); hwnd; hwnd = ::GetParent(hwnd) ) + { + m_hwndOldFocus = (WXHWND)hwnd; + } if (m_modalShowing) { BringWindowToTop((HWND) GetHWND()); return TRUE; } - + m_modalShowing = TRUE; wxNode *node = wxModalDialogs.First(); while (node) @@ -343,24 +361,30 @@ bool wxDialog::Show(bool show) EnableWindow((HWND) GetHWND(), TRUE); BringWindowToTop((HWND) GetHWND()); - if (!wxModalDialogs.Member(this)) + if ( !wxModalDialogs.Find(this) ) wxModalDialogs.Append(this); MSG msg; // Must test whether this dialog still exists: we may not process // a message before the deletion. - while (wxModalDialogs.Member(this) && m_modalShowing && GetMessage(&msg, NULL, 0, 0)) + while (wxModalDialogs.Find(this) && m_modalShowing && GetMessage(&msg, NULL, 0, 0)) { - if (m_acceleratorTable.Ok() && - ::TranslateAccelerator((HWND) GetHWND(), (HACCEL) m_acceleratorTable.GetHACCEL(), &msg)) + if ( m_acceleratorTable.Ok() && + ::TranslateAccelerator((HWND)GetHWND(), + (HACCEL)m_acceleratorTable.GetHACCEL(), + &msg) ) { // Have processed the message } - else if (!IsDialogMessage((HWND) GetHWND(), &msg)) + else if ( !wxTheApp->ProcessMessage((WXMSG *)&msg) ) { TranslateMessage(&msg); DispatchMessage(&msg); } + + // If we get crashes (as per George Tasker's message) with nested modal dialogs, + // we should try removing the m_modalShowing test + if (m_modalShowing && !::PeekMessage(&msg, 0, 0, 0, PM_NOREMOVE)) // dfgg: NB MUST test m_modalShowing again as the message loop could have triggered // a Show(FALSE) in the mean time!!! @@ -376,9 +400,12 @@ bool wxDialog::Show(bool show) node=disabledWindows.First(); while(node) { wxWindow* win = (wxWindow*) node->Data(); - HWND hWnd = (HWND) win->GetHWND(); - if (::IsWindow(hWnd) && (wxModalDialogs.Member(win) || wxModelessWindows.Member(win) )) - ::EnableWindow(hWnd,TRUE); + if (wxModalDialogs.Find(win) || wxModelessWindows.Find(win)) + { + HWND hWnd = (HWND) win->GetHWND(); + if (::IsWindow(hWnd)) + ::EnableWindow(hWnd,TRUE); + } node=node->Next(); } } @@ -394,9 +421,13 @@ bool wxDialog::Show(bool show) // enable it, else we enable all modeless windows if (last) { + // VZ: I don't understand what this is supposed to do, so I'll leave + // it out for now and look for horrible consequences wxDialog *box = (wxDialog *)last->Data(); HWND hwnd = (HWND) box->GetHWND(); - if (box->m_winEnabled) +#if 0 + if (box->IsUserEnabled()) +#endif // 0 EnableWindow(hwnd, TRUE); BringWindowToTop(hwnd); } @@ -408,7 +439,9 @@ bool wxDialog::Show(bool show) wxWindow *win = (wxWindow *)node->Data(); HWND hwnd = (HWND) win->GetHWND(); // Only enable again if not user-disabled. +#if 0 if (win->IsUserEnabled()) +#endif // 0 EnableWindow(hwnd, TRUE); node = node->Next(); } @@ -442,7 +475,9 @@ bool wxDialog::Show(bool show) if (hWndParent) ::BringWindowToTop(hWndParent); } - ShowWindow((HWND) GetHWND(), SW_HIDE); + + if ( m_hWnd ) + ShowWindow((HWND) GetHWND(), SW_HIDE); } } return TRUE; @@ -450,10 +485,10 @@ bool wxDialog::Show(bool show) void wxDialog::SetTitle(const wxString& title) { - SetWindowText((HWND) GetHWND(), (const char *)title); + SetWindowText((HWND) GetHWND(), title.c_str()); } -wxString wxDialog::GetTitle(void) const +wxString wxDialog::GetTitle() const { GetWindowText((HWND) GetHWND(), wxBuffer, 1000); return wxString(wxBuffer); @@ -489,7 +524,7 @@ void wxDialog::Centre(int direction) } // Replacement for Show(TRUE) for modal dialogs - returns return code -int wxDialog::ShowModal(void) +int wxDialog::ShowModal() { m_windowStyle |= wxDIALOG_MODAL; Show(TRUE); @@ -506,7 +541,7 @@ void wxDialog::EndModal(int retCode) WXHBRUSH wxDialog::OnCtlColor(WXHDC pDC, WXHWND pWnd, WXUINT nCtlColor, WXUINT message, WXWPARAM wParam, WXLPARAM lParam) { -#if CTL3D +#if wxUSE_CTL3D HBRUSH hbrush = Ctl3dCtlColorEx(message, wParam, lParam); return (WXHBRUSH) hbrush; #else @@ -543,64 +578,62 @@ void wxDialog::OnCancel(wxCommandEvent& event) else { SetReturnCode(wxID_CANCEL); - this->Show(FALSE); + this->Show(FALSE); } } -bool wxDialog::OnClose(void) +void wxDialog::OnCloseWindow(wxCloseEvent& event) { - // Behaviour changed in 2.0: we'll send a Cancel message by default, + // We'll send a Cancel message by default, // which may close the dialog. - // Check for looping if the Cancel event handler calls Close() + // Check for looping if the Cancel event handler calls Close(). + + // Note that if a cancel button and handler aren't present in the dialog, + // nothing will happen when you close the dialog via the window manager, or + // via Close(). + // We wouldn't want to destroy the dialog by default, since the dialog may have been + // created on the stack. + // However, this does mean that calling dialog->Close() won't delete the dialog + // unless the handler for wxID_CANCEL does so. So use Destroy() if you want to be + // sure to destroy the dialog. + // The default OnCancel (above) simply ends a modal dialog, and hides a modeless dialog. static wxList closing; if ( closing.Member(this) ) - return FALSE; + return; closing.Append(this); wxCommandEvent cancelEvent(wxEVT_COMMAND_BUTTON_CLICKED, wxID_CANCEL); cancelEvent.SetEventObject( this ); - GetEventHandler()->ProcessEvent(cancelEvent); + GetEventHandler()->ProcessEvent(cancelEvent); // This may close the dialog closing.DeleteObject(this); +} - return FALSE; +// Destroy the window (delayed, if a managed window) +bool wxDialog::Destroy() +{ + if (!wxPendingDelete.Member(this)) + wxPendingDelete.Append(this); + return TRUE; } void wxDialog::OnSize(wxSizeEvent& WXUNUSED(event)) { // if we're using constraints - do use them #if wxUSE_CONSTRAINTS - if ( GetAutoLayout() ) { + if ( GetAutoLayout() ) + { Layout(); } #endif } -void wxDialog::OnCloseWindow(wxCloseEvent& event) -{ - // Compatibility - if ( GetEventHandler()->OnClose() || event.GetForce()) - { - this->Destroy(); - } - else - event.Veto(TRUE); -} - -// Destroy the window (delayed, if a managed window) -bool wxDialog::Destroy(void) -{ - if (!wxPendingDelete.Member(this)) - wxPendingDelete.Append(this); - return TRUE; -} - void wxDialog::OnSysColourChanged(wxSysColourChangedEvent& event) { -#if CTL3D +#if wxUSE_CTL3D Ctl3dColorChange(); #else SetBackgroundColour(wxSystemSettings::GetSystemColour(wxSYS_COLOUR_3DFACE)); @@ -608,8 +641,26 @@ void wxDialog::OnSysColourChanged(wxSysColourChangedEvent& event) #endif } +// --------------------------------------------------------------------------- +// dialog window proc +// --------------------------------------------------------------------------- + long wxDialog::MSWWindowProc(WXUINT message, WXWPARAM wParam, WXLPARAM lParam) { - return wxWindow::MSWWindowProc(message, wParam, lParam); -} + long rc = 0; + bool processed = FALSE; + switch ( message ) + { + case WM_CLOSE: + // if we can't close, tell the system that we processed the + // message - otherwise it would close us + processed = !Close(); + break; + } + + if ( !processed ) + rc = wxWindow::MSWWindowProc(message, wParam, lParam); + + return rc; +}