2011-06-06 18:48:52 +00:00
using System ;
using System.Collections.Generic ;
using System.Linq ;
using System.Windows.Forms ;
2011-11-23 20:52:28 +00:00
using Duplicati.Library.Interface ;
2011-06-06 18:48:52 +00:00
namespace Duplicati.GUI.TrayIcon
{
2011-11-28 11:05:42 +00:00
public static class Program
2011-06-06 18:48:52 +00:00
{
2011-11-21 22:28:20 +00:00
public static HttpServerConnection Connection ;
2011-11-23 20:52:28 +00:00
private const string TOOLKIT_OPTION = "toolkit" ;
private const string TOOLKIT_WINDOWS_FORMS = "winforms" ;
private const string TOOLKIT_GTK = "gtk" ;
2011-11-28 11:05:42 +00:00
private const string TOOLKIT_GTK_APP_INDICATOR = "gtk-appindicator" ;
2011-11-23 20:52:28 +00:00
private const string TOOLKIT_COCOA = "cocoa" ;
2012-07-14 10:42:48 +00:00
private const string HOSTURL_OPTION = "hosturl" ;
private const string NOHOSTEDSERVER_OPTION = "no-hosted-server" ;
2011-11-28 11:05:42 +00:00
private static readonly string DEFAULT_TOOLKIT = GetDefaultToolKit ();
2012-07-14 10:42:48 +00:00
private const string DEFAULT_HOSTURL = "http://localhost:8080" ;
2011-11-28 11:05:42 +00:00
private static string GetDefaultToolKit ()
{
if ( Duplicati . Library . Utility . Utility . IsClientOSX && SupportsCocoaStatusIcon )
{
2011-12-15 09:38:58 +00:00
//Determine if we are running in an app bundle, otherwise we cannot run Cocoa
//The Duplicat.GUI.TrayIcon project, does not create the app bundle,
// so this ensures that we can run the normal project when debugging on mac,
// and it will just fall-back to Gtk. If we need to debug something Cocoa specific,
// we can load the Duplicati.GUI.MacTrayIcon project and use that as start project
string basefolder = System . IO . Path . GetDirectoryName ( System . Reflection . Assembly . GetExecutingAssembly (). Location );
string plist = System . IO . Path . Combine ( System . IO . Path . GetDirectoryName ( basefolder ), "Info.plist" );
if ( System . IO . File . Exists ( plist ))
return TOOLKIT_COCOA ;
2011-11-28 11:05:42 +00:00
}
2011-12-15 09:38:58 +00:00
if ( Duplicati . Library . Utility . Utility . IsClientLinux )
2011-11-28 11:05:42 +00:00
{
if ( SupportsAppIndicator )
return TOOLKIT_GTK_APP_INDICATOR ;
else
return TOOLKIT_GTK ;
}
else
{
//Windows users expect a WinForms element
return TOOLKIT_WINDOWS_FORMS ;
}
}
2011-11-23 20:52:28 +00:00
2011-06-06 18:48:52 +00:00
/// <summary>
/// The main entry point for the application.
/// </summary>
[STAThread]
2011-11-28 11:05:42 +00:00
public static void Main ( string [] _args )
2011-06-06 18:48:52 +00:00
{
2011-11-23 20:52:28 +00:00
List < string > args = new List < string >( _args );
2011-11-28 11:05:42 +00:00
Dictionary < string , string > options = Duplicati . Library . Utility . CommandLineParser . ExtractOptions ( args );
2011-11-23 20:52:28 +00:00
string toolkit ;
if (! options . TryGetValue ( TOOLKIT_OPTION , out toolkit ))
toolkit = DEFAULT_TOOLKIT ;
else
{
if ( TOOLKIT_WINDOWS_FORMS . Equals ( toolkit , StringComparison . InvariantCultureIgnoreCase ))
toolkit = TOOLKIT_WINDOWS_FORMS ;
else if ( TOOLKIT_GTK . Equals ( toolkit , StringComparison . InvariantCultureIgnoreCase ))
toolkit = TOOLKIT_GTK ;
2011-11-28 11:05:42 +00:00
else if ( TOOLKIT_GTK_APP_INDICATOR . Equals ( toolkit , StringComparison . InvariantCultureIgnoreCase ))
toolkit = TOOLKIT_GTK_APP_INDICATOR ;
2011-11-23 20:52:28 +00:00
else if ( TOOLKIT_COCOA . Equals ( toolkit , StringComparison . InvariantCultureIgnoreCase ))
toolkit = TOOLKIT_COCOA ;
else
toolkit = DEFAULT_TOOLKIT ;
}
2012-07-14 10:42:48 +00:00
using ( var hosted = Library . Utility . Utility . ParseBoolOption ( options , NOHOSTEDSERVER_OPTION ) ? null : new HostedInstanceKeeper ( _args ))
2011-11-21 22:28:20 +00:00
{
2012-07-14 10:42:48 +00:00
string url ;
if (! options . TryGetValue ( HOSTURL_OPTION , out url ))
{
if ( hosted == null )
{
url = DEFAULT_HOSTURL ;
}
else
{
2013-12-07 15:24:57 +01:00
int port = Duplicati . Server . Program . ServerPort ;
url = "http://127.0.0.1:" + port ;
2012-07-14 10:42:48 +00:00
}
}
using ( Connection = new HttpServerConnection ( new Uri ( url ), null ))
2011-11-21 22:28:20 +00:00
{
2011-11-28 11:05:42 +00:00
using ( var tk = RunTrayIcon ( toolkit ))
{
tk . Init ( _args );
}
2011-11-21 22:28:20 +00:00
}
}
2011-06-06 18:48:52 +00:00
}
2011-11-28 11:05:42 +00:00
private static TrayIconBase RunTrayIcon ( string toolkit )
{
if ( toolkit == TOOLKIT_WINDOWS_FORMS )
return GetWinformsInstance ();
else if ( toolkit == TOOLKIT_GTK )
return GetGtkInstance ();
else if ( toolkit == TOOLKIT_GTK_APP_INDICATOR )
return GetAppIndicatorInstance ();
else if ( toolkit == TOOLKIT_COCOA )
return GetCocoaRunnerInstance ();
else
throw new Exception ( string . Format ( "The selected toolkit '{0}' is invalid" , toolkit ));
}
//We keep these in functions to avoid attempting to load the instance,
// because the required assemblies may not exist on the machine
private static TrayIconBase GetGtkInstance () { return new GtkRunner (); }
2012-05-05 20:13:33 +00:00
private static TrayIconBase GetWinformsInstance () { return new Windows . WinFormsRunner (); }
2011-11-28 11:05:42 +00:00
private static TrayIconBase GetAppIndicatorInstance () { return new AppIndicatorRunner (); }
private static TrayIconBase GetCocoaRunnerInstance () { return new CocoaRunner (); }
2011-11-23 20:52:28 +00:00
2011-11-28 11:05:42 +00:00
//The functions below simply load the requested type,
// and if the type is not present, calling the function will result in an exception.
//This seems to be more reliable than attempting to load the assembly,
// as there are too many complex rules for when an updated assembly is also
// acceptable. This is fairly error proof, as it is just asks the runtime
// to load the required types
private static bool TryGetGtk ()
{
return typeof ( Gtk . StatusIcon ) != null && typeof ( Gdk . Image ) != null ;
}
private static bool TryGetWinforms ()
{
return typeof ( System . Windows . Forms . NotifyIcon ) != null ;
}
private static bool TryGetAppIndicator ()
{
return typeof ( AppIndicator . ApplicationIndicator ) != null ;
}
2011-11-23 20:52:28 +00:00
2011-11-28 11:05:42 +00:00
private static bool TryGetMonoMac ()
{
return typeof ( MonoMac . AppKit . NSStatusItem ) != null ;
}
//The functions below here, simply wrap the call to the above functions,
// converting the exception to a simple boolean value, so the calling
// code can be kept free of error handling
private static bool SupportsGtk
{
get
{
try { return TryGetGtk (); }
catch {}
return false ;
}
}
private static bool SupportsAppIndicator
{
get
{
try { return TryGetAppIndicator (); }
catch {}
return false ;
}
}
2011-12-15 09:38:58 +00:00
private static bool SupportsCocoaStatusIcon
2011-11-28 11:05:42 +00:00
{
get
{
try { return TryGetMonoMac (); }
catch {}
return false ;
}
}
private static bool SupportsWinForms
{
get
{
try { return TryGetWinforms (); }
catch {}
return false ;
}
}
2011-11-23 20:52:28 +00:00
public static Duplicati . Library . Interface . ICommandLineArgument [] SupportedCommands
{
get
{
return new Duplicati . Library . Interface . ICommandLineArgument []
{
2011-11-28 11:05:42 +00:00
new Duplicati . Library . Interface . CommandLineArgument ( TOOLKIT_OPTION , CommandLineArgument . ArgumentType . Enumeration , "Selects the toolkit to use" , "Choose the toolkit used to generate the TrayIcon, note that it will fail if the selected toolkit is not supported on this machine" , DEFAULT_TOOLKIT , null , new string [] { TOOLKIT_WINDOWS_FORMS , TOOLKIT_GTK , TOOLKIT_GTK_APP_INDICATOR , TOOLKIT_COCOA }),
2012-07-14 10:42:48 +00:00
new Duplicati . Library . Interface . CommandLineArgument ( HOSTURL_OPTION , CommandLineArgument . ArgumentType . String , "Selects the url to connect to" , "Supply the url that the TrayIcon will connect to and show status for" , DEFAULT_HOSTURL ),
new Duplicati . Library . Interface . CommandLineArgument ( NOHOSTEDSERVER_OPTION , CommandLineArgument . ArgumentType . String , "Disables local server" , "Set this option to not spawn a local service, use if the TrayIcon should connect to a running service" ),
2011-11-23 20:52:28 +00:00
};
}
}
2011-06-06 18:48:52 +00:00
}
}