diff --git a/include/wx/apptrait.h b/include/wx/apptrait.h index f93b90a621..c7d99aae0f 100644 --- a/include/wx/apptrait.h +++ b/include/wx/apptrait.h @@ -88,6 +88,16 @@ public: // return true to suppress subsequent asserts, false to continue as before virtual bool ShowAssertDialog(const wxString& msg) = 0; + // show the message safely to the user, i.e. show it in a message box if + // possible (even in a console application!) or return false if we can't do + // it (e.g. GUI is not initialized at all) + // + // note that this function can be called even when wxApp doesn't exist, as + // it's supposed to be always safe to call -- hence the name + // + // return true if the message box was shown, false if nothing was done + virtual bool SafeMessageBox(const wxString& text, const wxString& title) = 0; + // return true if fprintf(stderr) goes somewhere, false otherwise virtual bool HasStderr() = 0; @@ -208,6 +218,8 @@ public: virtual bool ShowAssertDialog(const wxString& msg) wxOVERRIDE; virtual bool HasStderr() wxOVERRIDE; + virtual bool SafeMessageBox(const wxString& text, + const wxString& title) wxOVERRIDE; // the GetToolkitVersion for console application is always the same wxPortId GetToolkitVersion(int *verMaj = NULL, @@ -248,6 +260,13 @@ public: virtual bool ShowAssertDialog(const wxString& msg) wxOVERRIDE; virtual bool HasStderr() wxOVERRIDE; + // Win32 has its own implementation using native message box directly in + // the base class, don't override it. +#ifndef __WIN32__ + virtual bool SafeMessageBox(const wxString& text, + const wxString& title) wxOVERRIDE; +#endif // !__WIN32__ + virtual bool IsUsingUniversalWidgets() const wxOVERRIDE { #ifdef __WXUNIVERSAL__ diff --git a/include/wx/msw/apptbase.h b/include/wx/msw/apptbase.h index c6d6ce4b45..2dea2f5eed 100644 --- a/include/wx/msw/apptbase.h +++ b/include/wx/msw/apptbase.h @@ -61,6 +61,10 @@ public: // return the main application window or 0 if none virtual WXHWND GetMainHWND() const = 0; + // implement this base class function for both console and GUI applications + virtual bool SafeMessageBox(const wxString& text, + const wxString& title) wxOVERRIDE; + protected: #if wxUSE_THREADS // implementation of WaitForThread() for the console applications which is diff --git a/interface/wx/apptrait.h b/interface/wx/apptrait.h index 9eff45d838..776c18e0ee 100644 --- a/interface/wx/apptrait.h +++ b/interface/wx/apptrait.h @@ -133,5 +133,28 @@ public: Returns @true to suppress subsequent asserts, @false to continue as before. */ virtual bool ShowAssertDialog(const wxString& msg) = 0; + + /** + Shows a message box with the given text and title if possible. + + In some ports, e.g. wxMSW, a message box will always be shown, while in + the other ones it will be only done if the GUI is available (e.g. X11 + display was successfully opened for X11-based ports) and the function + simply returns @false without doing anything otherwise. + + This function is safe in the sense that it can always be called, even + before creating wxApp, similarly to wxSafeShowMessage() which is + implemented by calling this function and then logging the message to + standard error stream if it returned @false. + + @since 3.1.5 + + @param text + The text to show to the user. + @param title + The title of the message box shown to the user. + @return @true if the message box was shown or @false otherwise. + */ + virtual bool SafeMessageBox(const wxString& text, const wxString& title) = 0; }; diff --git a/src/common/appbase.cpp b/src/common/appbase.cpp index af819469b2..c613393b90 100644 --- a/src/common/appbase.cpp +++ b/src/common/appbase.cpp @@ -944,6 +944,14 @@ bool wxConsoleAppTraitsBase::HasStderr() return true; } +bool wxConsoleAppTraitsBase::SafeMessageBox(const wxString& WXUNUSED(text), + const wxString& WXUNUSED(title)) +{ + // console applications don't show message boxes by default, although this + // can be done in platform-specific cases + return false; +} + // ---------------------------------------------------------------------------- // wxAppTraits // ---------------------------------------------------------------------------- diff --git a/src/common/appcmn.cpp b/src/common/appcmn.cpp index d257599f42..404429d4ff 100644 --- a/src/common/appcmn.cpp +++ b/src/common/appcmn.cpp @@ -25,6 +25,7 @@ #include "wx/window.h" #include "wx/bitmap.h" #include "wx/log.h" + #include "wx/module.h" #include "wx/msgdlg.h" #include "wx/confbase.h" #include "wx/utils.h" @@ -584,3 +585,21 @@ bool wxGUIAppTraitsBase::HasStderr() #endif } +#ifndef __WIN32__ + +bool wxGUIAppTraitsBase::SafeMessageBox(const wxString& text, + const wxString& title) +{ + // The modules are initialized only after a successful call to + // wxApp::Initialize() in wxEntryStart, so it can be used as a proxy for + // GUI availability (note that the mere existence of wxTheApp is not enough + // for this). + if ( !wxModule::AreInitialized() ) + return false; + + wxMessageBox(text, title, wxOK | wxICON_ERROR); + + return true; +} + +#endif // !__WIN32__ diff --git a/src/common/log.cpp b/src/common/log.cpp index 463deb04f7..c5ab359fd0 100644 --- a/src/common/log.cpp +++ b/src/common/log.cpp @@ -182,34 +182,11 @@ private: void wxSafeShowMessage(const wxString& title, const wxString& text) { -#ifdef __WINDOWS__ - const wxAppTraits* const traits = wxApp::GetTraitsIfExists(); - const HWND hwndParent = traits ? traits->GetMainHWND() : NULL; - int flags = MB_OK | MB_ICONSTOP; - - // Using MB_TASKMODAL with valid parent doesn't work well because it - // prevents the typical behaviour of modal message boxes, e.g. the message - // box doesn't come up to front when the parent is clicked. But if we don't - // have any parent anyhow, we can just as well use it, as we don't lose - // anything and it has a useful side effect of disabling any existing TLWs - // if there are any. - // - // Note that we also might have chosen to always use MB_TASKMODAL and NULL - // parent. This would have the advantage of always disabling all the window - // which, but at the cost of the behaviour mentioned above and other - // related problems, e.g. showing ugly default icon in Alt-Tab list and an - // extra taskbar button for the message box, so we don't do this, although - // perhaps we still should, at least in case when there is more than one - // TLW (but we can't check for this easily as this is non-GUI code and - // wxTopLevelWindows is not accessible from it). - if ( !hwndParent ) - flags |= MB_TASKMODAL; - - ::MessageBox(hwndParent, text.t_str(), title.t_str(), flags); -#else - wxFprintf(stderr, wxS("%s: %s\n"), title.c_str(), text.c_str()); - fflush(stderr); -#endif + if ( !wxApp::GetValidTraits().SafeMessageBox(text, title) ) + { + wxFprintf(stderr, wxS("%s: %s\n"), title.c_str(), text.c_str()); + fflush(stderr); + } } // ---------------------------------------------------------------------------- diff --git a/src/msw/basemsw.cpp b/src/msw/basemsw.cpp index ce270b73bc..7623bab46a 100644 --- a/src/msw/basemsw.cpp +++ b/src/msw/basemsw.cpp @@ -39,6 +39,35 @@ // wxAppTraits implementation // ============================================================================ +bool wxAppTraits::SafeMessageBox(const wxString& text, + const wxString& title) +{ + const HWND hwndParent = GetMainHWND(); + int flags = MB_OK | MB_ICONSTOP; + + // Using MB_TASKMODAL with valid parent doesn't work well because it + // prevents the typical behaviour of modal message boxes, e.g. the message + // box doesn't come up to front when the parent is clicked. But if we don't + // have any parent anyhow, we can just as well use it, as we don't lose + // anything and it has a useful side effect of disabling any existing TLWs + // if there are any. + // + // Note that we also might have chosen to always use MB_TASKMODAL and NULL + // parent. This would have the advantage of always disabling all the window + // which, but at the cost of the behaviour mentioned above and other + // related problems, e.g. showing ugly default icon in Alt-Tab list and an + // extra taskbar button for the message box, so we don't do this, although + // perhaps we still should, at least in case when there is more than one + // TLW (but we can't check for this easily as this is non-GUI code and + // wxTopLevelWindows is not accessible from it). + if ( !hwndParent ) + flags |= MB_TASKMODAL; + + ::MessageBox(hwndParent, text.t_str(), title.t_str(), flags); + + return true; +} + #if wxUSE_THREADS WXDWORD wxAppTraits::DoSimpleWaitForThread(WXHANDLE hThread) {