1 /*
2  * Smuxi - Smart MUltipleXed Irc
3  *
4  * Copyright (c) 2005-2008, 2012-2013, 2015 Mirco Bauer <meebey@meebey.net>
5  *
6  * Full GPL License: <http://www.gnu.org/licenses/gpl.txt>
7  *
8  * This program is free software; you can redistribute it and/or modify
9  * it under the terms of the GNU General Public License as published by
10  * the Free Software Foundation; either version 2 of the License, or
11  * (at your option) any later version.
12  *
13  * This program is distributed in the hope that it will be useful,
14  * but WITHOUT ANY WARRANTY; without even the implied warranty of
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16  * GNU General Public License for more details.
17  *
18  * You should have received a copy of the GNU General Public License
19  * along with this program; if not, write to the Free Software
20  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
21  */
22 
23 using System;
24 using System.Runtime.Remoting;
25 using System.Reflection;
26 using Gtk.Extensions;
27 using NDesk.Options;
28 using Smuxi.Common;
29 
30 namespace Smuxi.Frontend.Gnome
31 {
32     public class MainClass
33     {
34 #if LOG4NET
35         private static readonly log4net.ILog _Logger = log4net.LogManager.GetLogger(System.Reflection.MethodBase.GetCurrentMethod().DeclaringType);
36 #endif
37         static readonly string LibraryTextDomain = "smuxi-frontend-gnome";
38         static SingleApplicationInstance<CommandLineInterface> Instance { get; set; }
39 
Main(string[] args)40         public static void Main(string[] args)
41         {
42             var debug = false;
43             var link = String.Empty;
44             var engine = String.Empty;
45             var newInstance = false;
46             var options = new OptionSet();
47             options.Add(
48                 "d|debug",
49                 _("Enable debug output"),
50                 v => {
51                     debug = true;
52                 }
53             );
54             options.Add(
55                 "h|help",
56                 _("Show this help"),
57                 v => {
58                     Console.WriteLine("Usage: smuxi-frontend-gnome [options]");
59                     Console.WriteLine();
60                     Console.WriteLine(_("Options:"));
61                     options.WriteOptionDescriptions(Console.Out);
62                     Environment.Exit(0);
63                 }
64             );
65             options.Add(
66                 "e|engine=",
67                 _("Connect to engine"),
68                 v => {
69                     engine = v;
70                 }
71             );
72             options.Add(
73                 "open|open-link=",
74                 _("Opens the specified link in Smuxi"),
75                 v => {
76                     link = v;
77                 }
78             );
79             options.Add(
80                 "new-instance",
81                 _("Starts a new Smuxi instance and ignores an existing one"),
82                 v => {
83                     newInstance = true;
84                 }
85             );
86 
87             try {
88                 options.Parse(args);
89 
90 #if LOG4NET
91                 // initialize log level
92                 log4net.Repository.ILoggerRepository repo = log4net.LogManager.GetRepository();
93                 if (debug) {
94                     repo.Threshold = log4net.Core.Level.Debug;
95                 } else {
96                     repo.Threshold = log4net.Core.Level.Info;
97                 }
98 #endif
99 
100                 try {
101                     Instance = new SingleApplicationInstance<CommandLineInterface>();
102                     if (Instance.IsFirstInstance) {
103                         Instance.FirstInstance = new CommandLineInterface();
104                         if (!String.IsNullOrEmpty(link)) {
105                             Instance.FirstInstance.OpenLink(link);
106                         }
107                     } else {
108                         if (!String.IsNullOrEmpty(link)) {
109                             var msg = _("Passing link to already running Smuxi instance...");
110 #if LOG4NET
111                             _Logger.Info(msg);
112 #else
113                             Console.WriteLine(msg);
114 #endif
115                             Instance.FirstInstance.OpenLink(link);
116                         } else if (!newInstance) {
117                             var msg = _("Bringing already running Smuxi instance to foreground...");
118 #if LOG4NET
119                             _Logger.Info(msg);
120 #else
121                             Console.WriteLine(msg);
122 #endif
123                             Instance.FirstInstance.PresentMainWindow();
124                         }
125 
126                         if (!newInstance) {
127                             // don't initialize/spawn another instance
128                             return;
129                         }
130                     }
131                 } catch (Exception ex) {
132 #if LOG4NET
133                     _Logger.Warn("Single application instance error, ignoring...", ex);
134 #endif
135                 }
136 
137                 Frontend.Init(args, engine);
138             } catch (Exception e) {
139 #if LOG4NET
140                 _Logger.Fatal(e);
141 #endif
142                 // when Gtk# receives an exception it is not usable/relyable anymore!
143                 // except the exception was thrown in Frontend.Init() itself
144                 if (Frontend.IsGtkInitialized && !Frontend.InGtkApplicationRun) {
145                     Frontend.ShowException(e);
146                 }
147 
148                 // rethrow the exception for console output
149                 throw;
150             }
151         }
152 
_(string msg)153         static string _(string msg)
154         {
155             return LibraryCatalog.GetString(msg, LibraryTextDomain);
156         }
157     }
158 
159     public class CommandLineInterface : SingleApplicationInterface
160     {
161 #if LOG4NET
162         static readonly log4net.ILog Logger = log4net.LogManager.GetLogger(System.Reflection.MethodBase.GetCurrentMethod().DeclaringType);
163 #endif
164 
PresentMainWindow()165         public void PresentMainWindow()
166         {
167             if (!Frontend.IsGtkInitialized || !Frontend.InGtkApplicationRun) {
168                 return;
169             }
170 
171             Gtk.Application.Invoke(delegate {
172                 var window = Frontend.MainWindow;
173                 if (window == null) {
174                     return;
175                 }
176                 window.PresentWithServerTime();
177             });
178         }
179 
OpenLink(string link)180         public void OpenLink(string link)
181         {
182             if (Frontend.Session == null) {
183                 // we don't have a session yet, probably local instance that is
184                 // just starting or a remote engine that isn't connected yet
185                 EventHandler handler = null;
186                 handler = delegate {
187                     if (Frontend.Session == null) {
188                         return;
189                     }
190                     // we can't know which thread invokes SessionPropertyChanged
191                     Gtk.Application.Invoke((o, e) => {
192 #if LOG4NET
193                         Logger.Info("Opening the link...");
194 #endif
195                         Frontend.OpenLink(new Uri(link));
196                     });
197                     // only process the link once
198                     Frontend.SessionPropertyChanged -= handler;
199                 };
200 #if LOG4NET
201                 Logger.Info("Delaying opening the link as the session isn't initialized yet...");
202 #endif
203                 // install event handler and wait till the session gets initialized
204                 Frontend.SessionPropertyChanged += handler;
205             } else {
206                 Gtk.Application.Invoke((o, e) => {
207                     Frontend.OpenLink(new Uri(link));
208                 });
209             }
210         }
211 
InitializeLifetimeService()212         public override object InitializeLifetimeService()
213         {
214             // live forever
215             return null;
216         }
217     }
218 }
219