X-Git-Url: https://git.saurik.com/wxWidgets.git/blobdiff_plain/47d67540a017101b3e46abe9ef0f55914d8de37e..7b9da2077d0975db6c965a85c91d5aca671ab5e3:/src/msw/dialog.cpp diff --git a/src/msw/dialog.cpp b/src/msw/dialog.cpp index 85ba82edd0..0ded488a51 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,109 +42,114 @@ // Lists to keep track of windows, so we can disable/enable them // for modal dialogs -wxList wxModalDialogs; -wxList wxModelessWindows; // Frames and modeless dialogs -extern wxList wxPendingDelete; +wxWindowList wxModalDialogs; +wxWindowList wxModelessWindows; // Frames and modeless dialogs +extern wxList WXDLLEXPORT wxPendingDelete; #if !USE_SHARED_LIBRARY -IMPLEMENT_DYNAMIC_CLASS(wxDialog, wxPanel) - -BEGIN_EVENT_TABLE(wxDialog, wxPanel) - 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() - + 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() #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; SetBackgroundColour(wxSystemSettings::GetSystemColour(wxSYS_COLOUR_3DFACE)); - SetDefaultBackgroundColour(wxSystemSettings::GetSystemColour(wxSYS_COLOUR_3DFACE)); } 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)); - SetDefaultBackgroundColour(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) @@ -151,7 +159,7 @@ void wxDialog::SetModal(bool flag) else if ( m_windowStyle & wxDIALOG_MODAL ) m_windowStyle -= wxDIALOG_MODAL ; - + wxModelessWindows.DeleteObject(this); if (!flag) wxModelessWindows.Append(this); @@ -163,9 +171,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. @@ -177,14 +186,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)) { @@ -204,13 +209,13 @@ 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); + // 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; + return; } } // We didn't process this event. @@ -224,7 +229,7 @@ void wxDialog::OnPaint(wxPaintEvent& event) // wxWindow::OnPaint(event); } -void wxDialog::Fit(void) +void wxDialog::Fit() { wxWindow::Fit(); } @@ -234,21 +239,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::SetSize(int x, int y, int width, int height, int WXUNUSED(sizeFlags)) -{ - wxWindow::SetSize(x, y, width, height); -} - -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); @@ -276,11 +276,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; @@ -293,13 +298,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); @@ -309,15 +314,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; + } - wxList DisabledWindows; if (m_modalShowing) { BringWindowToTop((HWND) GetHWND()); return TRUE; } - + m_modalShowing = TRUE; wxNode *node = wxModalDialogs.First(); while (node) @@ -327,6 +337,13 @@ bool wxDialog::Show(bool show) ::EnableWindow((HWND) box->GetHWND(), FALSE); node = node->Next(); } + + // if we don't do it, some window might be deleted while we have pointers + // to them in our disabledWindows list and the program will crash when it + // will try to reenable them after the modal dialog end + wxTheApp->DeletePendingObjects(); + wxList disabledWindows; + node = wxModelessWindows.First(); while (node) { @@ -334,7 +351,7 @@ bool wxDialog::Show(bool show) if (::IsWindowEnabled((HWND) win->GetHWND())) { ::EnableWindow((HWND) win->GetHWND(), FALSE); - DisabledWindows.Append(win); + disabledWindows.Append(win); } node = node->Next(); } @@ -343,24 +360,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!!! @@ -373,12 +396,15 @@ bool wxDialog::Show(bool show) } } // dfgg: now must specifically re-enable all other app windows that we disabled earlier - node=DisabledWindows.First(); + 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 +420,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 +438,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 +474,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 +484,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 +523,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 +540,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 @@ -523,8 +557,8 @@ void wxDialog::OnOK(wxCommandEvent& event) EndModal(wxID_OK); else { - SetReturnCode(wxID_OK); - this->Show(FALSE); + SetReturnCode(wxID_OK); + this->Show(FALSE); } } } @@ -543,62 +577,89 @@ 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); + wxCommandEvent cancelEvent(wxEVT_COMMAND_BUTTON_CLICKED, wxID_CANCEL); + cancelEvent.SetEventObject( this ); + GetEventHandler()->ProcessEvent(cancelEvent); // This may close the dialog closing.DeleteObject(this); - - return FALSE; -} - -void wxDialog::OnCloseWindow(wxCloseEvent& event) -{ - // Compatibility - if ( GetEventHandler()->OnClose() || event.GetForce()) - { - this->Destroy(); - } } // Destroy the window (delayed, if a managed window) -bool wxDialog::Destroy(void) +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() ) + { + Layout(); + } + #endif +} + void wxDialog::OnSysColourChanged(wxSysColourChangedEvent& event) { -#if CTL3D +#if wxUSE_CTL3D Ctl3dColorChange(); #else SetBackgroundColour(wxSystemSettings::GetSystemColour(wxSYS_COLOUR_3DFACE)); - SetDefaultBackgroundColour(wxSystemSettings::GetSystemColour(wxSYS_COLOUR_3DFACE)); Refresh(); #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; +}