[tasque] Refactor single instance logic for Linux



commit d001c7c5040e04aad44a868a880add31c7603a47
Author: Antonius Riha <antoniusriha gmail com>
Date:   Fri Nov 30 16:44:31 2012 +0100

    Refactor single instance logic for Linux
    
    * moved to GtkApplication
    * INativeApplication inherits from IDisposable now
    * Logger has been moved to libtasque
    * RemoteControlProxy dropped and incorporated in RemoteControl

 src/Gtk.Tasque/Application.cs           |   29 +---------------
 src/Gtk.Tasque/Gtk.Tasque.csproj        |    2 -
 src/Gtk.Tasque/GtkApplication.cs        |   57 +++++++++++++++++++++++++++++-
 src/Gtk.Tasque/RemoteControl.cs         |   35 ++++++++++++++++++-
 src/Gtk.Tasque/RemoteControlProxy.cs    |   36 -------------------
 src/libtasque/INativeApplication.cs     |    2 +-
 src/{Gtk.Tasque => libtasque}/Logger.cs |    0
 src/libtasque/NativeApplication.cs      |   37 +++++++++++++++++++-
 src/libtasque/libtasque.csproj          |    1 +
 9 files changed, 127 insertions(+), 72 deletions(-)
---
diff --git a/src/Gtk.Tasque/Application.cs b/src/Gtk.Tasque/Application.cs
index 5f00b91..14b3afc 100644
--- a/src/Gtk.Tasque/Application.cs
+++ b/src/Gtk.Tasque/Application.cs
@@ -53,9 +53,7 @@ namespace Tasque
 		private static System.Object locker = new System.Object();
 		private bool initialized;
 		private INativeApplication nativeApp;
-#if !WIN && !OSX
-		private RemoteControl remoteControl;
-#endif
+
 		private Gdk.Pixbuf normalPixBuf;
 		private Gtk.Image trayImage;
 		private GtkTray trayIcon;
@@ -145,31 +143,6 @@ namespace Tasque
 			
 			preferences = new Preferences (nativeApp.ConfDir);
 			
-#if !WIN && !OSX
-			// Register Tasque RemoteControl
-			try {
-				remoteControl = RemoteControlProxy.Register ();
-				if (remoteControl != null) {
-					Logger.Debug ("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 = RemoteControlProxy.GetInstance ();
-						remote.ShowTasks ();
-					} catch {}
-
-					Logger.Debug ("Tasque is already running.  Exiting...");
-					System.Environment.Exit (0);
-				}
-			} catch (Exception e) {
-				Logger.Debug ("Tasque remote control disabled (DBus exception): {0}",
-				            e.Message);
-			}
-#endif
-			
 			string potentialBackendClassName = null;
 			
 			for (int i = 0; i < args.Length; i++) {
diff --git a/src/Gtk.Tasque/Gtk.Tasque.csproj b/src/Gtk.Tasque/Gtk.Tasque.csproj
index ea3135c..0a43d44 100644
--- a/src/Gtk.Tasque/Gtk.Tasque.csproj
+++ b/src/Gtk.Tasque/Gtk.Tasque.csproj
@@ -92,7 +92,6 @@
     <Compile Include="CompletedTaskGroupModel.cs" />
     <Compile Include="DateButton.cs" />
     <Compile Include="GtkApplication.cs" />
-    <Compile Include="Logger.cs" />
     <Compile Include="NoteDialog.cs" />
     <Compile Include="NoteWidget.cs" />
     <None Include="OSXApplication.cs" />
@@ -112,7 +111,6 @@
   </ItemGroup>
   <ItemGroup Condition=" '$(Configuration)' == 'LinuxDebug' Or '$(Configuration)' == 'LinuxRelease' ">
     <Compile Include="RemoteControl.cs" />
-    <Compile Include="RemoteControlProxy.cs" />
   </ItemGroup>
   <ItemGroup>
     <Substitute Include="Defines.cs.in" />
diff --git a/src/Gtk.Tasque/GtkApplication.cs b/src/Gtk.Tasque/GtkApplication.cs
index 7c9cd16..c7c6681 100644
--- a/src/Gtk.Tasque/GtkApplication.cs
+++ b/src/Gtk.Tasque/GtkApplication.cs
@@ -31,8 +31,6 @@ namespace Tasque
 {
 	public class GtkApplication : NativeApplication
 	{
-		private string confDir;
-
 		public GtkApplication ()
 		{
 			confDir = Path.Combine (
@@ -48,6 +46,8 @@ namespace Tasque
 			Mono.Unix.Catalog.Init ("tasque", Defines.LocaleDir);
 
 			Gtk.Application.Init ();
+			
+			base.Initialize (args);
 
 			// add package icon path to default icon theme search paths
 			Gtk.IconTheme.Default.PrependSearchPath (Defines.IconsDir);
@@ -82,5 +82,58 @@ namespace Tasque
 				Logger.Error ("Error opening url [{0}]:\n{1}", url, e.ToString ());
 			}
 		}
+
+		protected override bool IsRemoteInstanceRunning ()
+		{
+#if LINUX
+			// Register Tasque RemoteControl
+			try {
+				remoteInstance = RemoteControl.Register ();
+				if (remoteInstance != null) {
+					remoteInstance.RemoteInstanceKnocked = HandleRemoteInstanceKnocked;
+					Logger.Debug ("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 {}
+
+					Logger.Debug ("Tasque is already running.  Exiting...");
+					return true;
+				}
+			} catch (Exception e) {
+				Logger.Debug ("Tasque remote control disabled (DBus exception): {0}", e.Message);
+			}
+			return false;
+#endif
+		}
+
+		protected override void ShowMainWindow ()
+		{
+			TaskWindow.ShowWindow ();
+		}
+		
+		protected override event EventHandler RemoteInstanceKnocked;
+		
+		void HandleRemoteInstanceKnocked ()
+		{
+			if (RemoteInstanceKnocked != null)
+				RemoteInstanceKnocked (this, EventArgs.Empty);
+		}
+		
+		protected override void Dispose (bool disposing)
+		{
+			if (disposing)
+				remoteInstance.RemoteInstanceKnocked = null;
+		}
+
+		string confDir;
+#if LINUX
+		RemoteControl remoteInstance;
+#endif
 	}
 }
diff --git a/src/Gtk.Tasque/RemoteControl.cs b/src/Gtk.Tasque/RemoteControl.cs
index ec74ce4..be8d7c5 100644
--- a/src/Gtk.Tasque/RemoteControl.cs
+++ b/src/Gtk.Tasque/RemoteControl.cs
@@ -21,15 +21,47 @@ namespace Tasque
 	[Interface ("org.gnome.Tasque.RemoteControl")]
 	public class RemoteControl : MarshalByRefObject
 	{
+		const string Namespace = "org.gnome.Tasque";
+		const string Path = "/org/gnome/Tasque/RemoteControl";
+		
 		static Gdk.Pixbuf tasqueIcon;
 		static RemoteControl ()
 		{
 			tasqueIcon = Utilities.GetIcon ("tasque", 48);
 		}
 		
-		public RemoteControl()
+		public static RemoteControl GetInstance ()
 		{
+			BusG.Init ();
+			
+			if (!Bus.Session.NameHasOwner (Namespace))
+				Bus.Session.StartServiceByName (Namespace);
+			
+			return Bus.Session.GetObject<RemoteControl> (Namespace, new ObjectPath (Path));
 		}
+		
+		public static RemoteControl Register ()
+		{
+			BusG.Init ();
+			
+			var remoteControl = new RemoteControl ();
+			Bus.Session.Register (new ObjectPath (Path), remoteControl);
+			
+			if (Bus.Session.RequestName (Namespace) != RequestNameReply.PrimaryOwner)
+				return null;
+			
+			return remoteControl;
+		}
+		
+		RemoteControl () {}
+		
+		public void KnockKnock ()
+		{
+			if (RemoteInstanceKnocked != null)
+				RemoteInstanceKnocked ();
+		}
+		
+		public Action RemoteInstanceKnocked { get; set; }
 				
 		/// <summary>
 		/// Create a new task in Tasque using the given categoryName and name.
@@ -470,7 +502,6 @@ namespace Tasque
 			task.Delete ();
 			return true;
 		}
-
 		
 		/// <summary>
 		/// Looks up a task by ID in the backend
diff --git a/src/libtasque/INativeApplication.cs b/src/libtasque/INativeApplication.cs
index 11a8f06..4ec1f1e 100644
--- a/src/libtasque/INativeApplication.cs
+++ b/src/libtasque/INativeApplication.cs
@@ -2,7 +2,7 @@ using System;
 
 namespace Tasque
 {
-	public interface INativeApplication
+	public interface INativeApplication : IDisposable
 	{
 		string ConfDir { get; }
 
diff --git a/src/Gtk.Tasque/Logger.cs b/src/libtasque/Logger.cs
similarity index 100%
rename from src/Gtk.Tasque/Logger.cs
rename to src/libtasque/Logger.cs
diff --git a/src/libtasque/NativeApplication.cs b/src/libtasque/NativeApplication.cs
index 92565f2..ae28e34 100644
--- a/src/libtasque/NativeApplication.cs
+++ b/src/libtasque/NativeApplication.cs
@@ -43,7 +43,15 @@ namespace Tasque
 			Environment.Exit (exitcode);
 		}
 
-		public abstract void Initialize (string[] args);
+		public virtual void Initialize (string[] args)
+		{
+			if (IsRemoteInstanceRunning ()) {
+				Logger.Info ("Another instance of Tasque is already running.");
+				Exit (0);
+			}
+			
+			RemoteInstanceKnocked += delegate { ShowMainWindow (); };
+		}
 
 		public virtual void InitializeIdle () {}
 
@@ -59,6 +67,33 @@ namespace Tasque
 		public abstract void StartMainLoop ();
 
 		public event EventHandler Exiting;
+
+		/// <summary>
+		/// Determines whether this a remote instance is running.
+		/// </summary>
+		/// <returns>
+		/// <c>true</c> if a remote instance is running; otherwise, <c>false</c>.
+		/// </returns>
+		protected abstract bool IsRemoteInstanceRunning ();
+
+		protected abstract void ShowMainWindow ();
+		
+		protected abstract event EventHandler RemoteInstanceKnocked;
+		
+		#region IDisposable implementation
+		public void Dispose ()
+		{
+			Dispose (true);
+			GC.SuppressFinalize (this);
+		}
+		
+		protected virtual void Dispose (bool disposing) {}
+		
+		~NativeApplication ()
+		{
+			Dispose (false);
+		}
+		#endregion
 	}
 }
 
diff --git a/src/libtasque/libtasque.csproj b/src/libtasque/libtasque.csproj
index f3503bf..8e078c7 100644
--- a/src/libtasque/libtasque.csproj
+++ b/src/libtasque/libtasque.csproj
@@ -72,6 +72,7 @@
     </Compile>
     <Compile Include="IBackendPreferences.cs" />
     <Compile Include="NativeApplication.cs" />
+    <Compile Include="Logger.cs" />
   </ItemGroup>
   <ItemGroup>
     <Folder Include="DateFormatters\" />



[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]