Welcome to mirror list, hosted at ThFree Co, Russian Federation.

github.com/mono/monodevelop.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorVsevolod Kukol <sevoku@microsoft.com>2017-03-20 11:39:34 +0300
committerVsevolod Kukol <sevoku@microsoft.com>2017-03-20 11:39:34 +0300
commit8d9a8e0a5e932aaaf829b287b364379a97b29f32 (patch)
treea20f87a6e4caee01824e9304f5a87c8ee90b762b /main/src/core/MonoDevelop.Ide/MonoDevelop.Ide.Gui
parent2d059533ec9f5e85394d2cbf70fcf5e19291c1d4 (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.Ide.Gui')
-rw-r--r--main/src/core/MonoDevelop.Ide/MonoDevelop.Ide.Gui/DefaultWorkbench.cs22
-rw-r--r--main/src/core/MonoDevelop.Ide/MonoDevelop.Ide.Gui/Document.cs4
-rw-r--r--main/src/core/MonoDevelop.Ide/MonoDevelop.Ide.Gui/HiddenWorkbenchWindow.cs7
-rw-r--r--main/src/core/MonoDevelop.Ide/MonoDevelop.Ide.Gui/IWorkbenchWindow.cs6
-rw-r--r--main/src/core/MonoDevelop.Ide/MonoDevelop.Ide.Gui/SdiWorkspaceWindow.cs13
-rw-r--r--main/src/core/MonoDevelop.Ide/MonoDevelop.Ide.Gui/Workbench.cs8
6 files changed, 36 insertions, 24 deletions
diff --git a/main/src/core/MonoDevelop.Ide/MonoDevelop.Ide.Gui/DefaultWorkbench.cs b/main/src/core/MonoDevelop.Ide/MonoDevelop.Ide.Gui/DefaultWorkbench.cs
index 3ee80e6944..056046ce66 100644
--- a/main/src/core/MonoDevelop.Ide/MonoDevelop.Ide.Gui/DefaultWorkbench.cs
+++ b/main/src/core/MonoDevelop.Ide/MonoDevelop.Ide.Gui/DefaultWorkbench.cs
@@ -687,13 +687,21 @@ namespace MonoDevelop.Ide.Gui
}
}
}
-
- protected /*override*/ void OnClosing(object o, Gtk.DeleteEventArgs e)
+
+ bool closing;
+ protected /*override*/ async void OnClosing(object o, Gtk.DeleteEventArgs e)
{
- if (Close()) {
+ // close the window in case DeleteEvent fires again after a successful close
+ if (closing)
+ return;
+
+ // don't allow Gtk to close the workspace, in case Close() leaves the synchronization context
+ // Gtk.Application.Quit () will handle it for us.
+ e.RetVal = true;
+ if (await Close ()) {
+ closing = true;
+ Destroy (); // default delete action
Gtk.Application.Quit ();
- } else {
- e.RetVal = true;
}
}
@@ -720,7 +728,7 @@ namespace MonoDevelop.Ide.Gui
Destroy ();
}
- public bool Close()
+ public async Task<bool> Close()
{
if (!IdeApp.OnExit ())
return false;
@@ -745,7 +753,7 @@ namespace MonoDevelop.Ide.Gui
}
}
- if (!IdeApp.Workspace.Close (false, false))
+ if (!await IdeApp.Workspace.Close (false, false))
return false;
CloseAllViews ();
diff --git a/main/src/core/MonoDevelop.Ide/MonoDevelop.Ide.Gui/Document.cs b/main/src/core/MonoDevelop.Ide/MonoDevelop.Ide.Gui/Document.cs
index 56481b7d61..4bd8a5e6b2 100644
--- a/main/src/core/MonoDevelop.Ide/MonoDevelop.Ide.Gui/Document.cs
+++ b/main/src/core/MonoDevelop.Ide/MonoDevelop.Ide.Gui/Document.cs
@@ -516,9 +516,9 @@ namespace MonoDevelop.Ide.Gui
await UpdateParseDocument ();
}
- public bool Close ()
+ public async Task<bool> Close ()
{
- return ((SdiWorkspaceWindow)Window).CloseWindow (false, true);
+ return await ((SdiWorkspaceWindow)Window).CloseWindow (false, true);
}
protected override void OnSaved (EventArgs e)
diff --git a/main/src/core/MonoDevelop.Ide/MonoDevelop.Ide.Gui/HiddenWorkbenchWindow.cs b/main/src/core/MonoDevelop.Ide/MonoDevelop.Ide.Gui/HiddenWorkbenchWindow.cs
index 34d6fef15f..b5e3110a4e 100644
--- a/main/src/core/MonoDevelop.Ide/MonoDevelop.Ide.Gui/HiddenWorkbenchWindow.cs
+++ b/main/src/core/MonoDevelop.Ide/MonoDevelop.Ide.Gui/HiddenWorkbenchWindow.cs
@@ -26,6 +26,7 @@
using System;
using System.Collections.Generic;
+using System.Threading.Tasks;
using Mono.Addins;
namespace MonoDevelop.Ide.Gui
@@ -74,9 +75,9 @@ namespace MonoDevelop.Ide.Gui
set {}
}
- public bool CloseWindow (bool force)
+ public Task<bool> CloseWindow (bool force)
{
- return true;
+ return Task.FromResult (true);
}
public void SelectWindow ()
@@ -112,7 +113,7 @@ namespace MonoDevelop.Ide.Gui
public event EventHandler TitleChanged { add {} remove {} }
public event EventHandler DocumentChanged { add {} remove {} }
- public event MonoDevelop.Ide.Gui.WorkbenchWindowEventHandler Closing { add {} remove {} }
+ public event MonoDevelop.Ide.Gui.WorkbenchWindowAsyncEventHandler Closing { add {} remove {} }
public event MonoDevelop.Ide.Gui.WorkbenchWindowEventHandler Closed { add {} remove {} }
public event MonoDevelop.Ide.Gui.ActiveViewContentEventHandler ActiveViewContentChanged { add {} remove {} }
public event EventHandler ViewsChanged { add {} remove {} }
diff --git a/main/src/core/MonoDevelop.Ide/MonoDevelop.Ide.Gui/IWorkbenchWindow.cs b/main/src/core/MonoDevelop.Ide/MonoDevelop.Ide.Gui/IWorkbenchWindow.cs
index 8bcc0cde5c..4614f4fe51 100644
--- a/main/src/core/MonoDevelop.Ide/MonoDevelop.Ide.Gui/IWorkbenchWindow.cs
+++ b/main/src/core/MonoDevelop.Ide/MonoDevelop.Ide.Gui/IWorkbenchWindow.cs
@@ -30,6 +30,7 @@ using System.ComponentModel;
using System.Collections.Generic;
using Mono.Addins;
using MonoDevelop.Components.Docking;
+using System.Threading.Tasks;
namespace MonoDevelop.Ide.Gui
{
@@ -53,7 +54,7 @@ namespace MonoDevelop.Ide.Gui
void SwitchView (BaseViewContent subViewContent);
int FindView <T>();
- bool CloseWindow (bool force);
+ Task<bool> CloseWindow (bool force);
void SelectWindow ();
/// <summary>
@@ -63,11 +64,12 @@ namespace MonoDevelop.Ide.Gui
event EventHandler DocumentChanged;
event WorkbenchWindowEventHandler Closed;
- event WorkbenchWindowEventHandler Closing;
+ event WorkbenchWindowAsyncEventHandler Closing;
event ActiveViewContentEventHandler ActiveViewContentChanged;
event EventHandler ViewsChanged;
}
+ public delegate Task WorkbenchWindowAsyncEventHandler (object o, WorkbenchWindowEventArgs e);
public delegate void WorkbenchWindowEventHandler (object o, WorkbenchWindowEventArgs e);
public class WorkbenchWindowEventArgs : CancelEventArgs
{
diff --git a/main/src/core/MonoDevelop.Ide/MonoDevelop.Ide.Gui/SdiWorkspaceWindow.cs b/main/src/core/MonoDevelop.Ide/MonoDevelop.Ide.Gui/SdiWorkspaceWindow.cs
index b6eeec99d7..20c876f248 100644
--- a/main/src/core/MonoDevelop.Ide/MonoDevelop.Ide.Gui/SdiWorkspaceWindow.cs
+++ b/main/src/core/MonoDevelop.Ide/MonoDevelop.Ide.Gui/SdiWorkspaceWindow.cs
@@ -38,6 +38,7 @@ using MonoDevelop.Components.Commands;
using MonoDevelop.Ide.Extensions;
using MonoDevelop.Ide.Gui.Content;
using MonoDevelop.Components.DockNotebook;
+using System.Threading.Tasks;
namespace MonoDevelop.Ide.Gui
{
@@ -443,17 +444,17 @@ namespace MonoDevelop.Ide.Gui
}
}
- public bool CloseWindow (bool force)
+ public Task<bool> CloseWindow (bool force)
{
return CloseWindow (force, false);
}
- public bool CloseWindow (bool force, bool animate)
+ public async Task<bool> CloseWindow (bool force, bool animate)
{
bool wasActive = workbench.ActiveWorkbenchWindow == this;
WorkbenchWindowEventArgs args = new WorkbenchWindowEventArgs (force, wasActive);
args.Cancel = false;
- OnClosing (args);
+ await OnClosing (args);
if (args.Cancel)
return false;
@@ -808,10 +809,10 @@ namespace MonoDevelop.Ide.Gui
}
}
- protected virtual void OnClosing (WorkbenchWindowEventArgs e)
+ protected virtual async System.Threading.Tasks.Task OnClosing (WorkbenchWindowEventArgs e)
{
if (Closing != null) {
- Closing (this, e);
+ await Closing (this, e);
}
}
@@ -830,7 +831,7 @@ namespace MonoDevelop.Ide.Gui
public event EventHandler TitleChanged;
public event WorkbenchWindowEventHandler Closed;
- public event WorkbenchWindowEventHandler Closing;
+ public event WorkbenchWindowAsyncEventHandler Closing;
public event ActiveViewContentEventHandler ActiveViewContentChanged;
}
}
diff --git a/main/src/core/MonoDevelop.Ide/MonoDevelop.Ide.Gui/Workbench.cs b/main/src/core/MonoDevelop.Ide/MonoDevelop.Ide.Gui/Workbench.cs
index 324f2fc919..2840b11442 100644
--- a/main/src/core/MonoDevelop.Ide/MonoDevelop.Ide.Gui/Workbench.cs
+++ b/main/src/core/MonoDevelop.Ide/MonoDevelop.Ide.Gui/Workbench.cs
@@ -142,9 +142,9 @@ namespace MonoDevelop.Ide.Gui
Present ();
}
- internal bool Close ()
+ internal async Task<bool> Close ()
{
- return workbench.Close();
+ return await workbench.Close();
}
public ImmutableList<Document> Documents {
@@ -584,7 +584,7 @@ namespace MonoDevelop.Ide.Gui
}
return doc;
} else {
- if (!doc.Close ())
+ if (!await doc.Close ())
return doc;
break;
}
@@ -841,7 +841,7 @@ namespace MonoDevelop.Ide.Gui
return pad;
}
- async void OnWindowClosing (object sender, WorkbenchWindowEventArgs args)
+ async Task OnWindowClosing (object sender, WorkbenchWindowEventArgs args)
{
var window = (IWorkbenchWindow) sender;
var viewContent = window.ViewContent;