5e4ca343d34d89784b020853a8a485c812a0dfb2
[WebThing.git] / WebThing.cs
1 using System;
2 using System.Collections.Generic;
3 using System.Reflection;
4 using System.IO;
5 using System.Text.RegularExpressions;
6 using System.Runtime.InteropServices;
7 using Gtk;
8 using GtkSharp;
9 using WebKit;
10
11 namespace bytex64.WebThing {
12     public enum CompassDirection {
13         N, E, S, W, Interior
14     }
15
16     public class WebThing {
17         private Gtk.Window _Window;
18         public Gtk.Window Window {
19             get { return _Window; }
20         }
21         public Gtk.Window w {
22             get { return _Window; }
23         }
24
25         public ScrolledWindow ScrolledWindow {
26             get { return Tabs.CurrentPageWidget as ScrolledWindow; }
27         }
28         public ScrolledWindow sw {
29             get { return ScrolledWindow; }
30         }
31
32         public WebView WebView {
33             get { return (Tabs.CurrentPageWidget as WebThingView).WebView; }
34         }
35         public WebView wv {
36             get { return WebView; }
37         }
38
39         private Gtk.Notebook _Tabs;
40         public Gtk.Notebook Tabs {
41             get { return _Tabs; }
42         }
43         /*
44         private int _CurrentTab;
45         public int CurrentTab {
46             get { return _CurrentTab; }
47             set {
48                 if (value >= _Tabs.Count)
49                     _CurrentTab = _Tabs.Count - 1;
50                 else if (value < 0)
51                     _CurrentTab = 0;
52                 else
53                     _CurrentTab = value;
54
55                 _WebView.Hide();
56                 _ScrolledWindow.Remove(_WebView);
57                 _WebView = _Tabs[_CurrentTab];
58                 _ScrolledWindow.Add(_WebView);
59                 foreach (WebView view in Tabs)
60                     Console.WriteLine(view.MainFrame.Uri);
61                 _WebView.Show();
62                 _WebView.GrabFocus();
63             }
64         }
65         */
66
67         private Gtk.Table WidgetGrid;
68         private Gtk.Alignment InteriorOverlay;
69
70         public Dictionary<string,WebThingPlugin> Plugins;
71         public Dictionary<string,string> Options;
72         public string[] Arguments;
73
74         [DllImport ("SoupSettings.dll")]
75         private static extern void soup_settings();
76
77         public void Run() {
78             Application.Init();
79             Plugins = new Dictionary<string,WebThingPlugin>();
80             ParseArgs();
81
82             soup_settings();
83
84             _Window = new Gtk.Window("WebThing");
85             _Window.SetWmclass("webthing", "WebThing");
86             _Window.Role = "browser";
87             _Window.Destroyed += delegate { Quit(); };
88
89             WidgetGrid = new Gtk.Table(3, 3, false);
90             _Window.Add(WidgetGrid);
91
92             _Tabs = new Gtk.Notebook();
93             _Tabs.ShowBorder = false;
94             _Tabs.SwitchPage += Tabs_SwitchPage;
95             WidgetGrid.Attach(_Tabs, 1, 2, 1, 2);
96
97             InteriorOverlay = new Gtk.Alignment(1, 0, 0, 0);
98             WidgetGrid.Attach(InteriorOverlay, 1, 2, 1, 2);
99
100             _Window.ShowAll();
101
102             WebThingView newview = NewWebThingView();
103
104             // TODO: Conf.Get("plugins") instead of hard-coded path?
105             using (TextReader f = new StreamReader("plugins.conf")) {
106                 string line;
107                 while ((line = f.ReadLine()) != null) {
108                     line = line.Trim();
109                     LoadPlugin(line);
110                 }
111             }
112
113             WebViewSetupPlugins(newview.WebView);
114             newview.WebView.GrabFocus();
115
116             Application.Run();
117         }
118
119         protected void ParseArgs() {
120             Options = new Dictionary<string,string>();
121             Queue<string> q = new Queue<string>();
122             foreach (string s in System.Environment.GetCommandLineArgs()) {
123                 q.Enqueue(s);
124             }
125             q.Dequeue();   // Remove self argument
126
127             Regex SimpleOpt = new Regex(@"^-([a-zA-Z0-9]+)$");
128             Regex LongOpt   = new Regex(@"^--([\w-]+)$");
129             string OptLast = null;
130             List<string> args = new List<string>();
131
132             while (q.Count > 0) {
133                 string opt = q.Dequeue();
134                 Match m;
135                    
136                 m = SimpleOpt.Match(opt);
137                 if (m.Success) {
138                     string s = m.Groups[1].Value;
139                     if (s.Length > 1) {
140                         foreach (char c in s) {
141                             Options[c.ToString()] = "";
142                         }
143                         OptLast = null;
144                     } else {
145                         Options[s] = "";
146                         OptLast = s;
147                     }
148                     continue;
149                 }
150
151                 m = LongOpt.Match(opt);
152                 if (m.Success) {
153                     string s = m.Groups[1].Value;
154                     Options[s] = "";
155                     OptLast = s;
156                     continue;
157                 }
158
159                 // else
160
161                 if (OptLast != null) {
162                     Options[OptLast] = opt;
163                     OptLast = null;
164                 } else {
165                     args.Add(opt);
166                 }
167             }
168             Arguments = args.ToArray();
169
170             /*
171             Console.WriteLine("Options:");
172             foreach (string key in Options.Keys)
173                 Console.WriteLine("   {0}\t{1}", key, Options[key]);
174
175             Console.WriteLine("Arguments: {0}", String.Join(" ", Arguments));
176             */
177         }
178
179         public void LoadPlugin(string assemblyname) {
180             Assembly a = Assembly.LoadFile("plugins/" + assemblyname + ".dll");
181             Type[] types = a.GetTypes();
182             foreach (Type t in types) {
183                 if (t.IsSubclassOf(typeof(WebThingPlugin))) {
184                     WebThingPlugin p = (WebThingPlugin) a.CreateInstance(t.FullName, false, BindingFlags.ExactBinding, null, null, null, null);
185                     p.Init(this);
186                     Plugins[t.FullName] = p;
187                     Console.WriteLine("Successfully loaded {0}", t.FullName);
188                 }
189             }
190         }
191
192         public void AttachWidget(Gtk.Widget widget, CompassDirection direction, AttachOptions xoptions, AttachOptions yoptions) {
193             switch(direction) {
194             case CompassDirection.N:
195                 WidgetGrid.Attach(widget, 0, 3, 0, 1, xoptions, yoptions, 0, 0);
196                 break;
197             case CompassDirection.E:
198                 WidgetGrid.Attach(widget, 2, 3, 1, 2, xoptions, yoptions, 0, 0);
199                 break;
200             case CompassDirection.S:
201                 WidgetGrid.Attach(widget, 0, 3, 2, 3, xoptions, yoptions, 0, 0);
202                 break;
203             case CompassDirection.W:
204                 WidgetGrid.Attach(widget, 0, 1, 1, 2, xoptions, yoptions, 0, 0);
205                 break;
206             case CompassDirection.Interior:
207                 InteriorOverlay.Add(widget);
208                 break;
209             }
210         }
211
212         public void AttachWidget(Gtk.Widget widget, CompassDirection direction) {
213             AttachWidget(widget, direction, 0, 0);
214         }
215
216         public WebView NewTab() {
217             WebThingView newview = NewWebThingView();
218             WebViewSetupPlugins(newview.WebView);
219             return newview.WebView;
220         }
221
222         private WebThingView NewWebThingView() {
223             WebThingView newview = new WebThingView();
224             Tabs.AppendPage(newview, new Label("Blank"));
225             newview.WebView.TitleChanged += delegate(object o, TitleChangedArgs e) {
226                 Tabs.SetTabLabelText((Gtk.Widget) newview, e.Title);
227                 if (newview == Tabs.CurrentPageWidget)
228                     _Window.Title = e.Title + " - WebThing";
229             };
230             newview.Show();
231             return newview;
232         }
233
234         private void WebViewSetupPlugins(WebView view) {
235             foreach (string key in Plugins.Keys) {
236                 Plugins[key].InitWebView(view);
237             }
238         }
239
240         public void CloseTab() {
241             CloseTab(_Tabs.Page);
242         }
243
244         public void CloseTab(int tab) {
245             if (_Tabs.NPages > 1) {
246                 try {
247                     WebThingView view = _Tabs.GetNthPage(tab) as WebThingView;
248                     _Tabs.RemovePage(tab);
249                     view.Dispose();
250                 } catch (ArgumentOutOfRangeException) {
251                 }
252             }
253         }
254
255         public string FixUri(string Uri) {
256             if (!Regex.IsMatch(Uri, @"://")) {
257                 return String.Format("http://{0}", Uri);
258             }
259             return Uri;
260         }
261
262         public void OpenUri(string Uri) {
263             wv.Open(FixUri(Uri));
264         }
265
266         public void OpenUriTab(string Uri) {
267             WebView view = NewTab();
268             view.Open(FixUri(Uri));
269         }
270
271         public void Quit() {
272             // TODO: Create a way of shutting down plugins
273             Application.Quit();
274         }
275
276         private void Tabs_SwitchPage(object o, SwitchPageArgs e) {
277             Gtk.Widget page = _Tabs.GetNthPage((int)e.PageNum);
278             _Window.Title = _Tabs.GetTabLabelText(page) + " - WebThing";
279         }
280     }
281 }