Opened 10 years ago
Closed 9 years ago
#12703 closed defect (fixed)
wxApp::OnInit and event handling
Reported by: | ryazanov | Owned by: | |
---|---|---|---|
Priority: | high | Milestone: | 2.9.3 |
Component: | GUI-all | Version: | 2.9.0 |
Keywords: | regression | Cc: | f18m_cpp217828@… |
Blocked By: | Blocking: | ||
Patch: | no |
Description
There was an important change in version 2.9:
- Processing of pending events now requires a running event loop. Thus initialization code (e.g. showing a dialog) previously done in wxApp::OnRun() or equivalent function should now be done into wxApp::OnEventLoopEnter(). See wxApp::OnEventLoopEnter() and wxApp::OnEventLoopExit() docs for more info.
however it is not reflected in OnInit() method documentation. There are some hints in wxAppConsole::GetMainLoop() and wxAppConsole::OnEventLoopEnter() descriptions, but there is not clue to look there.
Attachments (1)
Change History (8)
comment:1 Changed 10 years ago by vadz
- Cc f18m_cpp217828@… added
- Status changed from new to infoneeded_new
- Summary changed from wxApp...::OnInit and event handling to wxApp::OnInit and event handling
comment:2 Changed 10 years ago by ryazanov
- Status changed from infoneeded_new to new
End process detection during OnInit() does not work in wxGTK (but seems to work in wxMSW). I noticed that while debugging #12636. Namely, at some point I checked and saw that wxAppConsole::GetMainLoop() returns NULL. However, if logging with frequent calling of wxLog::FlushActive() was introduced, the end process event was processed from the event loop of the log dialog (according to debugger's backtrace).
What was the point to call OnInit() without a running event loop? If there is no real advantage, and the "old behaviour" was restored at least somewhere, please check whether it was restored everywhere.
And in any case the documentation needs to be brought in correspondence with the reality.
comment:3 Changed 10 years ago by vadz
- Milestone set to 3.0
I think OnInit() was always called before starting the main event loop (which was done by OnRun()). I don't really know what would happen if we started it before OnInit() but I suspect this wouldn't be without some undesirable consequences...
How exactly does the end process detection fail to work BTW? For me it would be acceptable if the process termination were not detected before the main loop is started but not if it were lost entirely. What really happens?
Thanks!
P.S. Francesco, could you please confirm or deny that this note in docs/changes.txt is not needed any more? I'm afraid I didn't follow all changes here in details...
comment:4 Changed 10 years ago by ryazanov
- Status changed from new to confirmed
I'm attaching a minimalistic example (test.cpp) to illustrate the end process detection problem. In wxW 2.8.11 the log looks like
22:03:15: Event loop = 00000000 22:03:15: Process started. 22:03:15: Waiting for 1324. 22:03:15: Waiting for 1324. [cut] 22:03:15: Waiting for 1324. 22:03:15: Waiting for 1324. 22:03:15: Process 1324 terminated. 22:03:15: Process stopped.
In the current wxW version the program hangs in the loop
while (pid) { wxLogMessage("Waiting for %ld.", pid); //wxLog::FlushActive(); wxSafeYield(); }
unless wxLog::FlushActive(); is enabled.
Actually, now I understand, that the problem is really not in the missing event loop (it was missing before, according to the log above), but in wxSafeYield(), which did call ProcessPendingEvents() in 2.8 and now does nothing, if there is no active event loop.
I don't think, that the process termination event is entirely lost, but for my purposes (running external programs to obtain some configuration data) I need it to be processed within the initialization code.
Anyway, please improve the documentation, making clear, that event processing does not work in OnInit() — this is not obvious!
Another question: "How to do it right?" I mean, initialization code, that requires events. The wxAppConsole::OnEventLoopEnter() documentation says
"this function is called whenever an event loop is activated; you may want to use wxEventLoopBase::IsMain() to perform initialization specific for the app's main event loop."
Does this "whenever activated" mean, that OnEventLoopEnter() might be called many times for the main loop (when some other loops are created and destroyed), so that the "initialization" code must maintain a flag in order to run only once?
comment:5 Changed 10 years ago by Andrew.Smart
This defect might be related to #12930 "wxAppConsole abnormal termination when using event loop on user initiated app close".
comment:6 Changed 10 years ago by vadz
- Component changed from documentation to GUI-all
- Keywords regression added
- Milestone changed from 3.0 to 2.9.3
- Priority changed from normal to high
More I think about this, more I become certain that we need to actually dispatch the events when wxYield() is called instead of just silently doing nothing when there is no active event loop. IOW I think we need to create the event loop if necessary as I just don't see how can the user code deal with its absence in a sane manner otherwise.
And, indeed, doing something like this:
-
src/common/appbase.cpp
a b bool wxAppConsoleBase::Dispatch() 345 345 bool wxAppConsoleBase::Yield(bool onlyIfNeeded) 346 346 { 347 347 wxEventLoopBase * const loop = wxEventLoopBase::GetActive(); 348 if ( loop ) 349 return loop->Yield(onlyIfNeeded); 348 350 349 return loop && loop->Yield(onlyIfNeeded); 351 wxScopedPtr<wxEventLoopBase> tmpLoop(CreateMainLoop()); 352 return tmpLoop->Yield(onlyIfNeeded); 350 353 } 351 354 352 355 void wxAppConsoleBase::WakeUpIdle()
does solve the problem but it doesn't look like a good idea because we probably don't want to recreate the event loop on each wxYield() call. So we probably should create m_mainLoop on demand instead.
But this is a detail, the main question is whether there is any reason we can't create (without running it!) the main event loop before OnRun() is called. If nobody sees any reason not to do this, I'm going to change this as proposed.
comment:7 Changed 9 years ago by vadz
- Resolution set to fixed
- Status changed from confirmed to closed
Is this note in docs/changes.txt really correct? I thought we (well, Francesco) restored the old behaviour to keep compatibility.
What exactly doesn't work when done in OnRun() instead of in OnEventLoopEnter() now?