use a common m_isInsideYield flag instead of static booleans in all ports; add a IsYielding() test which can help to fix unwanted re-entrancies

git-svn-id: https://svn.wxwidgets.org/svn/wx/wxWidgets/trunk@57637 c3d73ce0-8a6f-49c7-b76d-6d57e0e08775
This commit is contained in:
Francesco Montorsi 2008-12-29 15:03:39 +00:00
parent 67badd5753
commit d181e877b0
14 changed files with 66 additions and 79 deletions

View File

@ -454,6 +454,10 @@ public:
// with _extreme_ care or, better, don't use at all!
virtual bool Yield(bool onlyIfNeeded = false) = 0;
// returns true if the main thread is inside a Yield() call
bool IsYielding() const
{ return m_isInsideYield; }
// this virtual function is called in the GUI mode when the application
// becomes idle and normally just sends wxIdleEvent to all interested
// parties
@ -576,6 +580,7 @@ protected:
// does any of our windows have focus?
bool m_isActive;
bool m_isInsideYield;
DECLARE_NO_COPY_CLASS(wxAppBase)
};

View File

@ -176,6 +176,11 @@ public:
*/
static bool IsMainLoopRunning();
/**
Returns @true if called from inside Yield().
*/
bool IsYielding() const;
/**
Process all pending events; it is necessary to call this function to
process posted events.
@ -466,6 +471,7 @@ public:
user to perform actions which are not compatible with the current task.
Disabling menu items or whole menus during processing can avoid unwanted
reentrance of code: see ::wxSafeYield for a better function.
You can avoid unwanted reentrancies also using IsYielding().
Note that Yield() will not flush the message logs. This is intentional as
calling Yield() is usually done to quickly update the screen and popping up

View File

@ -297,16 +297,13 @@ void wxApp::Exit()
// Yield to other processes
bool wxApp::Yield(bool onlyIfNeeded)
{
// MT-FIXME
static bool s_inYield = false;
#if wxUSE_LOG
// disable log flushing from here because a call to wxYield() shouldn't
// normally result in message boxes popping up &c
wxLog::Suspend();
#endif // wxUSE_LOG
if (s_inYield)
if (m_isInsideYield)
{
if ( !onlyIfNeeded )
{
@ -316,7 +313,7 @@ bool wxApp::Yield(bool onlyIfNeeded)
return false;
}
s_inYield = true;
m_isInsideYield = true;
// Run the event loop until it is out of events
while(1)
@ -358,7 +355,7 @@ bool wxApp::Yield(bool onlyIfNeeded)
wxLog::Resume();
#endif // wxUSE_LOG
s_inYield = false;
m_isInsideYield = false;
return true;
}

View File

@ -78,6 +78,8 @@ wxAppBase::wxAppBase()
m_isActive = true;
m_isInsideYield = false;
// We don't want to exit the app if the user code shows a dialog from its
// OnInit() -- but this is what would happen if we set m_exitOnFrameDelete
// to Yes initially as this dialog would be the last top level window.

View File

@ -171,9 +171,7 @@ bool wxApp::Yield(bool onlyIfNeeded)
return true; // can't process events from other threads
#endif // wxUSE_THREADS
static bool s_inYield = false;
if ( s_inYield )
if ( m_isInsideYield )
{
if ( !onlyIfNeeded )
{
@ -183,7 +181,7 @@ bool wxApp::Yield(bool onlyIfNeeded)
return false;
}
s_inYield = true;
m_isInsideYield = true;
#if wxUSE_LOG
wxLog::Suspend();
@ -203,7 +201,7 @@ bool wxApp::Yield(bool onlyIfNeeded)
wxLog::Resume();
#endif // wxUSE_LOG
s_inYield = false;
m_isInsideYield = false;
return true;
}

View File

@ -54,14 +54,9 @@ static GtkWidget *gs_RootWindow = (GtkWidget*) NULL;
// wxYield
//-----------------------------------------------------------------------------
// not static because used by textctrl.cpp
//
// MT-FIXME
bool wxIsInsideYield = false;
bool wxApp::Yield(bool onlyIfNeeded)
{
if ( wxIsInsideYield )
if ( m_isInsideYield )
{
if ( !onlyIfNeeded )
{
@ -79,7 +74,7 @@ bool wxApp::Yield(bool onlyIfNeeded)
}
#endif // wxUSE_THREADS
wxIsInsideYield = true;
m_isInsideYield = true;
#if wxUSE_LOG
// disable log flushing from here because a call to wxYield() shouldn't
@ -103,7 +98,7 @@ bool wxApp::Yield(bool onlyIfNeeded)
wxLog::Resume();
#endif
wxIsInsideYield = false;
m_isInsideYield = false;
return true;
}

View File

@ -103,14 +103,9 @@ static wxMutex gs_idleTagsMutex;
// wxYield
//-----------------------------------------------------------------------------
// not static because used by textctrl.cpp
//
// MT-FIXME
bool wxIsInsideYield = false;
bool wxApp::Yield(bool onlyIfNeeded)
{
if ( wxIsInsideYield )
if ( m_isInsideYield )
{
if ( !onlyIfNeeded )
{
@ -128,7 +123,7 @@ bool wxApp::Yield(bool onlyIfNeeded)
}
#endif // wxUSE_THREADS
wxIsInsideYield = true;
m_isInsideYield = true;
// We need to remove idle callbacks or the loop will
// never finish.
@ -156,7 +151,7 @@ bool wxApp::Yield(bool onlyIfNeeded)
wxLog::Resume();
#endif
wxIsInsideYield = false;
m_isInsideYield = false;
return true;
}

View File

@ -175,8 +175,6 @@ gtk_scrollbar_changed_callback( GtkWidget *WXUNUSED(widget), wxTextCtrl *win )
// which implicitly calls wxYield()) so we override GtkText::draw() and simply
// don't do anything if we're inside wxYield()
extern bool wxIsInsideYield;
extern "C" {
typedef void (*GtkDrawCallback)(GtkWidget *widget, GdkRectangle *rect);
}
@ -186,7 +184,7 @@ static GtkDrawCallback gs_gtk_text_draw = NULL;
extern "C" {
static void wxgtk_text_draw( GtkWidget *widget, GdkRectangle *rect)
{
if ( !wxIsInsideYield )
if ( !wxTheApp->IsYielding() )
{
wxCHECK_RET( gs_gtk_text_draw != wxgtk_text_draw,
_T("infinite recursion in wxgtk_text_draw aborted") );

View File

@ -48,11 +48,9 @@ void wxApp::Exit()
// wxYield
//-----------------------------------------------------------------------------
static bool gs_inYield = false;
bool wxApp::Yield(bool onlyIfNeeded)
{
if ( gs_inYield )
if ( m_isInsideYield )
{
if ( !onlyIfNeeded )
{
@ -70,7 +68,7 @@ bool wxApp::Yield(bool onlyIfNeeded)
}
#endif // wxUSE_THREADS
gs_inYield = true;
m_isInsideYield = true;
wxLog::Suspend();
@ -88,7 +86,7 @@ bool wxApp::Yield(bool onlyIfNeeded)
wxLog::Resume();
gs_inYield = false;
m_isInsideYield = false;
return true;
}

View File

@ -472,9 +472,7 @@ void wxApp::SetTopLevelRealizedWidget(WXDisplay* display, WXWidget widget)
bool wxApp::Yield(bool onlyIfNeeded)
{
static bool s_inYield = false;
if ( s_inYield )
if ( m_isInsideYield )
{
if ( !onlyIfNeeded )
{
@ -484,13 +482,13 @@ bool wxApp::Yield(bool onlyIfNeeded)
return false;
}
s_inYield = true;
m_isInsideYield = true;
wxEventLoopGuarantor dummyLoopIfNeeded;
while (wxTheApp && wxTheApp->Pending())
wxTheApp->Dispatch();
s_inYield = false;
m_isInsideYield = false;
return true;
}

View File

@ -1015,10 +1015,7 @@ int wxApp::GetShell32Version()
bool wxApp::Yield(bool onlyIfNeeded)
{
// MT-FIXME
static bool s_inYield = false;
if ( s_inYield )
if ( m_isInsideYield )
{
if ( !onlyIfNeeded )
{
@ -1029,8 +1026,8 @@ bool wxApp::Yield(bool onlyIfNeeded)
}
// set the flag and don't forget to reset it before returning
s_inYield = true;
wxON_BLOCK_EXIT_SET(s_inYield, false);
m_isInsideYield = true;
wxON_BLOCK_EXIT_SET(m_isInsideYield, false);
#if wxUSE_LOG

View File

@ -509,9 +509,7 @@ void wxApp::OnQueryEndSession( wxCloseEvent& rEvent )
//
bool wxApp::Yield(bool onlyIfNeeded)
{
static bool s_inYield = false;
if ( s_inYield )
if ( m_isInsideYield )
{
if ( !onlyIfNeeded )
{
@ -530,7 +528,7 @@ bool wxApp::Yield(bool onlyIfNeeded)
//
wxLog::Suspend();
s_inYield = true;
m_isInsideYield = true;
//
// We want to go back to the main message loop
@ -545,6 +543,7 @@ bool wxApp::Yield(bool onlyIfNeeded)
if (!wxTheApp->Dispatch())
break;
}
//
// If they are pending events, we must process them.
//
@ -552,11 +551,13 @@ bool wxApp::Yield(bool onlyIfNeeded)
wxTheApp->ProcessPendingEvents();
HandleSockets();
//
// Let the logs be flashed again
//
wxLog::Resume();
s_inYield = false;
m_isInsideYield = false;
return true;
} // end of wxYield

View File

@ -184,7 +184,7 @@ short wxApp::MacHandleAEGURL(const WXEVENTREF event, WXEVENTREF WXUNUSED(reply))
if (err != noErr)
return err;
url[actualSize] = '\0'; // Terminate the C string
url[actualSize] = '\0'; // Terminate the C string
ProcessSerialNumber PSN ;
PSN.highLongOfPSN = 0 ;
@ -357,9 +357,9 @@ void wxApp::MacReopenApp()
// make sure we don't show 'virtual toplevel windows' like wxTaskBarIconWindow
if ( firstHidden == NULL && ( wxDynamicCast( win, wxFrame ) || wxDynamicCast( win, wxDialog ) ) )
firstHidden = win ;
}
}
else if ( win->IsIconized() )
{
{
if ( firstIconized == NULL )
firstIconized = win ;
}
@ -499,7 +499,7 @@ wxMenu* wxFindMenuFromMacCommand( const HICommand &command , wxMenuItem* &item )
// is it part of the application or the Help menu, then look for the id directly
if ( ( GetMenuHandle( kwxMacAppleMenuId ) != NULL && command.menu.menuRef == GetMenuHandle( kwxMacAppleMenuId ) ) ||
( helpMenuHandle != NULL && command.menu.menuRef == helpMenuHandle ) ||
( helpMenuHandle != NULL && command.menu.menuRef == helpMenuHandle ) ||
wxMenuBar::MacGetWindowMenuHMenu() != NULL && command.menu.menuRef == wxMenuBar::MacGetWindowMenuHMenu() )
{
wxMenuBar* mbar = wxMenuBar::MacGetInstalledMenuBar() ;
@ -576,7 +576,7 @@ wxMacAppMenuEventHandler( EventHandlerCallRef WXUNUSED(handler),
case kEventMenuTargetItem:
{
HICommand command ;
command.menu.menuRef = menuRef;
command.menu.menuItemIndex = cEvent.GetParameter<MenuItemIndex>(kEventParamMenuItemIndex,typeMenuItemIndex) ;
command.commandID = cEvent.GetParameter<MenuCommand>(kEventParamMenuCommand,typeMenuCommand) ;
@ -900,7 +900,7 @@ bool wxApp::DoInitGui()
if ( !wxMacInitCocoa() )
return false;
return true;
}
@ -1130,9 +1130,7 @@ bool wxApp::Yield(bool onlyIfNeeded)
}
#endif // wxUSE_THREADS
static bool s_inYield = false;
if (s_inYield)
if (m_isInsideYield)
{
if ( !onlyIfNeeded )
{
@ -1142,7 +1140,7 @@ bool wxApp::Yield(bool onlyIfNeeded)
return false;
}
s_inYield = true;
m_isInsideYield = true;
#if wxUSE_LOG
// disable log flushing from here because a call to wxYield() shouldn't
@ -1158,16 +1156,16 @@ bool wxApp::Yield(bool onlyIfNeeded)
while ( loop->Pending() )
loop->Dispatch();
}
// it's necessary to call ProcessIdle() to update the frames sizes which
// might have been changed (it also will update other things set from
// OnUpdateUI() which is a nice (and desired) side effect)
while ( ProcessIdle() ) {}
#if wxUSE_LOG
wxLog::Resume();
#endif // wxUSE_LOG
s_inYield = false;
m_isInsideYield = false;
return true;
}
@ -1558,34 +1556,34 @@ void wxApp::MacCreateKeyEvent( wxKeyEvent& event, wxWindow* focus , long keymess
{
keyval = (keyval - '0') + WXK_NUMPAD0;
}
else if (keycode >= 65 && keycode <= 81)
else if (keycode >= 65 && keycode <= 81)
{
switch (keycode)
{
case 76 :
keyval = WXK_NUMPAD_ENTER;
break;
case 81:
keyval = WXK_NUMPAD_EQUAL;
break;
case 67:
keyval = WXK_NUMPAD_MULTIPLY;
break;
case 75:
keyval = WXK_NUMPAD_DIVIDE;
break;
case 78:
keyval = WXK_NUMPAD_SUBTRACT;
break;
case 69:
keyval = WXK_NUMPAD_ADD;
break;
case 65:
keyval = WXK_NUMPAD_DECIMAL;
break;
@ -1594,7 +1592,7 @@ void wxApp::MacCreateKeyEvent( wxKeyEvent& event, wxWindow* focus , long keymess
}
}
}
event.m_shiftDown = modifiers & shiftKey;
event.m_controlDown = modifiers & controlKey;
event.m_altDown = modifiers & optionKey;
@ -1621,7 +1619,7 @@ void wxApp::MacHideApp()
HICommand command;
memset( &command, 0 , sizeof(command) );
command.commandID = kHICommandHide ;
event.SetParameter<HICommand>(kEventParamDirectObject, command );
event.SetParameter<HICommand>(kEventParamDirectObject, command );
SendEventToApplication( event );
#endif
}

View File

@ -777,9 +777,7 @@ bool wxApp::Yield(bool onlyIfNeeded)
int i;
for (i = 0; i < 2; i++)
{
static bool s_inYield = false;
if ( s_inYield )
if ( m_isInsideYield )
{
if ( !onlyIfNeeded )
{
@ -789,11 +787,12 @@ bool wxApp::Yield(bool onlyIfNeeded)
return false;
}
s_inYield = true;
m_isInsideYield = true;
// Make sure we have an event loop object,
// or Pending/Dispatch will fail
wxEventLoopGuarantor dummyLoopIfNeeded;
wxEventLoopGuarantor dummyLoopIfNeeded;
// Call dispatch at least once so that sockets
// can be tested
wxTheApp->Dispatch();
@ -806,7 +805,7 @@ bool wxApp::Yield(bool onlyIfNeeded)
#endif
ProcessIdle();
s_inYield = false;
m_isInsideYield = false;
}
return true;