diff options
author | Vsevolod Kukol <sevoku@microsoft.com> | 2017-03-20 11:39:34 +0300 |
---|---|---|
committer | Vsevolod Kukol <sevoku@microsoft.com> | 2017-03-20 11:39:34 +0300 |
commit | 8d9a8e0a5e932aaaf829b287b364379a97b29f32 (patch) | |
tree | a20f87a6e4caee01824e9304f5a87c8ee90b762b /main/src/core/MonoDevelop.Ide/MonoDevelop.Components.DockNotebook | |
parent | 2d059533ec9f5e85394d2cbf70fcf5e19291c1d4 (diff) |
[Ide] Fix IWorkbenchWindow.Closing event handling with async operations
If a workbench window contains an unsaved document, we ask the user
to save it and run the save operation asynchronously. This is controlled
by the WorkbenchWindowEventArgs.Cancel property and the result
contols whether we set specific Gtk/GLib events as hanled or not
(i.e. in order to allow or disallow Gtk to close a window).
The first problem here was the async EventHandler for the Closing event
which was not awaited and the window was closed before the
Save operation had a chance to run to completion. This is solved by
an EventHandler delegate returning a Task, making it possible to
await the handlers subscribed to the event.
The second problem with this approach was that Gtk doesn't know
anything about awaiting Tasks and if one of its event handlers
leaves the synchronization context (like the asynchrounous
file saving), it will let the signal pass without waiting for its
handled state to be updated. This is solved by delaying window
closing/destruction (always set the initial delete/close event
handled state and close the window in a continuation task
synchronized with the UI thread)
(fix bug #53089)
Diffstat (limited to 'main/src/core/MonoDevelop.Ide/MonoDevelop.Components.DockNotebook')
-rw-r--r-- | main/src/core/MonoDevelop.Ide/MonoDevelop.Components.DockNotebook/DockWindow.cs | 13 |
1 files changed, 11 insertions, 2 deletions
diff --git a/main/src/core/MonoDevelop.Ide/MonoDevelop.Components.DockNotebook/DockWindow.cs b/main/src/core/MonoDevelop.Ide/MonoDevelop.Components.DockNotebook/DockWindow.cs index a421e25963..6acbdebd57 100644 --- a/main/src/core/MonoDevelop.Ide/MonoDevelop.Components.DockNotebook/DockWindow.cs +++ b/main/src/core/MonoDevelop.Ide/MonoDevelop.Components.DockNotebook/DockWindow.cs @@ -92,8 +92,17 @@ namespace MonoDevelop.Components.DockNotebook foreach (var d in documents) { if (howManyDirtyFiles > 1) d.Window.CloseWindow (true); - else if (!d.Close ()) - return true; + else { + // d.Close() could leave the UI synchronization context, letting the Gtk signal handler pass + // and Gtk would destroy the window immediately. Since we need to preserve the window + // state until the async document.Close () has finished, we interrupt the signal (return true) + // and destoy the window in a continuation task after the document has been closed. + d.Close ().ContinueWith ((arg) => { + if (arg.Result) + Destroy (); + }, Core.Runtime.MainTaskScheduler); + return true; + } } return base.OnDeleteEvent (evnt); } |