[tasque/viewmodel: 30/78] Add Windows single app instance logic
- From: Antonius Riha <antoniusri src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [tasque/viewmodel: 30/78] Add Windows single app instance logic
- Date: Wed, 29 Aug 2012 18:37:11 +0000 (UTC)
commit 7d6f9720d7e27037c8abf74db517f8ec9558a355
Author: Antonius Riha <antoniusriha gmail com>
Date: Sun Jul 29 18:24:41 2012 +0200
Add Windows single app instance logic
* split GtkApp in two classes which are conditionally built:
- GtkLinuxApplication: holds single app instance logic with dbus
- GtkWinApplication: holds single app instance logic with named events
* GtkApplicationBase: Common base class
* Program.cs: Add GtkWinApplication init
* WindowsSingleInstanceSolution.cs: don't needed anymore (saved though in
a gist: https://gist.github.com/3199448)
.../{GtkApplication.cs => GtkApplicationBase.cs} | 141 +++++++++-----------
src/Tasque.Gtk/GtkLinuxApplication.cs | 65 +++++++++
src/Tasque.Gtk/GtkWinApplication.cs | 75 +++++++++++
.../Samples/WindowsSingleInstanceSolution.cs | 89 ------------
src/Tasque.Gtk/Tasque.Gtk.csproj | 7 +-
src/tasque/Program.cs | 4 +-
6 files changed, 212 insertions(+), 169 deletions(-)
---
diff --git a/src/Tasque.Gtk/GtkApplication.cs b/src/Tasque.Gtk/GtkApplicationBase.cs
similarity index 58%
rename from src/Tasque.Gtk/GtkApplication.cs
rename to src/Tasque.Gtk/GtkApplicationBase.cs
index b8d276c..ef3c955 100644
--- a/src/Tasque.Gtk/GtkApplication.cs
+++ b/src/Tasque.Gtk/GtkApplicationBase.cs
@@ -33,9 +33,36 @@ using Tasque.UIModel.Legacy;
namespace Tasque
{
- public class GtkApplication : NativeApplication
+ public abstract class GtkApplicationBase : NativeApplication
{
- public GtkApplication ()
+ #region just copied
+ public UIManager UIManager
+ {
+ get { return uiManager; }
+ }
+
+ #region implemented abstract members of Tasque.UIModel.Legacy.NativeApplication
+ public override Backend CurrentBackend {
+ get {
+ throw new System.NotImplementedException ();
+ }
+ }
+
+ public override System.Collections.ObjectModel.ReadOnlyCollection<Backend> AvailableBackends {
+ get {
+ throw new System.NotImplementedException ();
+ }
+ }
+
+ public override Tasque.UIModel.Legacy.MainWindowModel MainWindowModel {
+ get {
+ throw new System.NotImplementedException ();
+ }
+ }
+ #endregion
+ #endregion
+
+ public GtkApplicationBase ()
{
confDir = Path.Combine (
Environment.GetFolderPath (Environment.SpecialFolder.ApplicationData), "tasque");
@@ -73,88 +100,51 @@ namespace Tasque
}
}
- protected override bool IsRemoteInstanceRunning ()
- {
-#if !WIN32
- // Register Tasque RemoteControl
- try {
- remoteInstance = RemoteControl.Register ();
- if (remoteInstance != null) {
- remoteInstance.RemoteInstanceKnocked = HandleRemoteInstanceKnocked;
- Debug.Write ("Tasque remote control active.");
- } else {
- // If Tasque is already running, open the tasks window
- // so the user gets some sort of feedback when they
- // attempt to run Tasque again.
- RemoteControl remote = null;
- try {
- remote = RemoteControl.GetInstance ();
- remote.KnockKnock ();
- } catch {}
-
- Debug.WriteLine ("Tasque is already running. Exiting...");
- return true;
- }
- } catch (Exception e) {
- Debug.WriteLine ("Tasque remote control disabled (DBus exception): {0}", e.Message);
- }
- return false;
-#else
-
-#endif
- }
-
protected override event EventHandler RemoteInstanceKnocked;
- void HandleRemoteInstanceKnocked ()
+ protected void OnRemoteInstanceKnocked ()
{
if (RemoteInstanceKnocked != null)
RemoteInstanceKnocked (this, EventArgs.Empty);
}
- protected override void Dispose (bool disposing)
- {
- if (disposing)
- remoteInstance.RemoteInstanceKnocked = null;
- }
-
void RegisterUIManager ()
{
ActionGroup trayActionGroup = new ActionGroup ("Tray");
- trayActionGroup.Add (new ActionEntry [] {
- new ActionEntry ("NewTaskAction",
- Stock.New,
- Catalog.GetString ("New Task ..."),
- null,
- null,
- OnNewTask),
-
- new ActionEntry ("ShowTasksAction",
- null,
- Catalog.GetString ("Show Tasks ..."),
- null,
- null,
- OnShowTaskWindow),
-
- new ActionEntry ("AboutAction",
- Stock.About,
- OnAbout),
-
- new ActionEntry ("PreferencesAction",
- Stock.Preferences,
- OnPreferences),
-
- new ActionEntry ("RefreshAction",
- Stock.Execute,
- Catalog.GetString ("Refresh Tasks ..."),
- null,
- null,
- OnRefreshAction),
-
- new ActionEntry ("QuitAction",
- Stock.Quit,
- OnQuit)
- });
+// trayActionGroup.Add (new ActionEntry [] {
+// new ActionEntry ("NewTaskAction",
+// Stock.New,
+// Catalog.GetString ("New Task ..."),
+// null,
+// null,
+// OnNewTask),
+//
+// new ActionEntry ("ShowTasksAction",
+// null,
+// Catalog.GetString ("Show Tasks ..."),
+// null,
+// null,
+// OnShowTaskWindow),
+//
+// new ActionEntry ("AboutAction",
+// Stock.About,
+// OnAbout),
+//
+// new ActionEntry ("PreferencesAction",
+// Stock.Preferences,
+// OnPreferences),
+//
+// new ActionEntry ("RefreshAction",
+// Stock.Execute,
+// Catalog.GetString ("Refresh Tasks ..."),
+// null,
+// null,
+// OnRefreshAction),
+//
+// new ActionEntry ("QuitAction",
+// Stock.Quit,
+// OnQuit)
+// });
uiManager = new UIManager ();
uiManager.AddUiFromString (MenuXml);
@@ -178,8 +168,5 @@ namespace Tasque
";
string confDir;
-#if !WIN32
- RemoteControl remoteInstance;
-#endif
}
}
diff --git a/src/Tasque.Gtk/GtkLinuxApplication.cs b/src/Tasque.Gtk/GtkLinuxApplication.cs
new file mode 100644
index 0000000..25f3159
--- /dev/null
+++ b/src/Tasque.Gtk/GtkLinuxApplication.cs
@@ -0,0 +1,65 @@
+//
+// GtkLinuxApplication.cs
+//
+// Author:
+// Antonius Riha <antoniusriha gmail com>
+//
+// Copyright (c) 2012 Antonius Riha
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to deal
+// in the Software without restriction, including without limitation the rights
+// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+// copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+// THE SOFTWARE.
+using System;
+using System.Diagnostics;
+
+namespace Tasque
+{
+ public class GtkLinuxApplication : GtkApplicationBase
+ {
+ protected override void Dispose (bool disposing)
+ {
+ if (disposing)
+ remoteInstance = null;
+
+ base.Dispose (disposing);
+ }
+
+ protected override bool IsRemoteInstanceRunning ()
+ {
+ // Register Tasque RemoteControl
+ try {
+ remoteInstance = RemoteControl.Register ();
+ if (remoteInstance != null) {
+ remoteInstance.RemoteInstanceKnocked = OnRemoteInstanceKnocked;
+ Debug.WriteLine ("Tasque remote control created.");
+ } else {
+ RemoteControl remote = null;
+ try {
+ remote = RemoteControl.GetInstance ();
+ remote.KnockKnock ();
+ } catch {}
+ return true;
+ }
+ } catch (Exception e) {
+ Debug.WriteLine ("Tasque remote control disabled (DBus exception): {0}", e.Message);
+ }
+ return false;
+ }
+
+ RemoteControl remoteInstance;
+ }
+}
diff --git a/src/Tasque.Gtk/GtkWinApplication.cs b/src/Tasque.Gtk/GtkWinApplication.cs
new file mode 100644
index 0000000..183bbd6
--- /dev/null
+++ b/src/Tasque.Gtk/GtkWinApplication.cs
@@ -0,0 +1,75 @@
+//
+// GtkWinApplication.cs
+//
+// Author:
+// Antonius Riha <antoniusriha gmail com>
+//
+// Copyright (c) 2012 Antonius Riha
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to deal
+// in the Software without restriction, including without limitation the rights
+// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+// copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+// THE SOFTWARE.
+using System;
+using System.Diagnostics;
+using System.Threading;
+
+namespace Tasque
+{
+ public class GtkWinApplication : GtkApplicationBase
+ {
+ protected override void Dispose (bool disposing)
+ {
+ if (disposing) {
+ waitHandle.Dispose ();
+ waitHandle = null;
+ }
+
+ base.Dispose (disposing);
+ }
+
+ protected override bool IsRemoteInstanceRunning ()
+ {
+ try {
+ waitHandle = EventWaitHandle.OpenExisting(waitHandleName);
+ waitHandle.Set();
+ return true;
+ } catch (WaitHandleCannotBeOpenedException) {
+ waitHandle = new EventWaitHandle(false, EventResetMode.AutoReset, waitHandleName);
+ Debug.WriteLine("EventWaitHandle created.");
+
+ var porter = new Thread(new ThreadStart(WaitForAnotherInstance));
+ porter.Start();
+ }
+ return false;
+ }
+
+ void WaitForAnotherInstance ()
+ {
+ while (!exiting) {
+ waitHandle.WaitOne ();
+ if (!exiting) {
+ Debug.WriteLine ("Another app instance has just knocked on the door.");
+ OnRemoteInstanceKnocked ();
+ }
+ }
+ }
+
+ bool exiting;
+ EventWaitHandle waitHandle;
+ readonly string waitHandleName = "Tasque." + Environment.UserName;
+ }
+}
diff --git a/src/Tasque.Gtk/Tasque.Gtk.csproj b/src/Tasque.Gtk/Tasque.Gtk.csproj
index 059d97e..1edd6c6 100644
--- a/src/Tasque.Gtk/Tasque.Gtk.csproj
+++ b/src/Tasque.Gtk/Tasque.Gtk.csproj
@@ -99,7 +99,6 @@
<Link>data\sounds\notify.wav</Link>
</None>
<None Include="Samples\Gtk3SingleInstanceSolution.cs" />
- <None Include="Samples\WindowsSingleInstanceSolution.cs" />
</ItemGroup>
<ItemGroup>
<Compile Include="Properties\AssemblyInfo.cs" />
@@ -113,7 +112,6 @@
<Compile Include="CellRendererDate.cs" />
<Compile Include="CompletedTaskGroup.cs" />
<Compile Include="DateButton.cs" />
- <Compile Include="GtkApplication.cs" />
<Compile Include="NoteDialog.cs" />
<Compile Include="NoteWidget.cs" />
<Compile Include="Preferences.cs" />
@@ -123,8 +121,13 @@
<Compile Include="TaskTreeView.cs" />
<Compile Include="TaskWindow.cs" />
<Compile Include="Utilities.cs" />
+ <Compile Include="GtkApplicationBase.cs" />
+ </ItemGroup>
+ <ItemGroup Condition=" '$(Configuration)' == 'GtkWinDebug' or '$(Configuration)' == 'GtkWinRelease' ">
+ <Compile Include="GtkWinApplication.cs" />
</ItemGroup>
<ItemGroup Condition=" '$(Configuration)' == 'GtkLinuxDebug' or '$(Configuration)' == 'GtkLinuxRelease' ">
+ <Compile Include="GtkLinuxApplication.cs" />
<Compile Include="RemoteControl.cs" />
</ItemGroup>
<ItemGroup>
diff --git a/src/tasque/Program.cs b/src/tasque/Program.cs
index 0ba8262..fd8d2e7 100644
--- a/src/tasque/Program.cs
+++ b/src/tasque/Program.cs
@@ -39,8 +39,10 @@ namespace Tasque
NativeApplication app;
#if OSX
app = new OSXApplication ();
+#elif WIN32
+ app = new GtkWinApplication ();
#else
- app = new GtkApplication ();
+ app = new GtkLinuxApplication ();
#endif
return app;
}
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]