Added tabs
[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.SwitchPage += Tabs_SwitchPage;
94             WidgetGrid.Attach(_Tabs, 1, 2, 1, 2);
95
96             InteriorOverlay = new Gtk.Alignment(1, 0, 0, 0);
97             WidgetGrid.Attach(InteriorOverlay, 1, 2, 1, 2);
98
99             _Window.ShowAll();
100
101             WebThingView newview = NewWebThingView();
102
103             // TODO: Conf.Get("plugins") instead of hard-coded path?
104             using (TextReader f = new StreamReader("plugins.conf")) {
105                 string line;
106                 while ((line = f.ReadLine()) != null) {
107                     line = line.Trim();
108                     LoadPlugin(line);
109                 }
110             }
111
112             WebViewSetupPlugins(newview.WebView);
113             newview.WebView.GrabFocus();
114
115             Application.Run();
116         }
117
118         protected void ParseArgs() {
119             Options = new Dictionary<string,string>();
120             Queue<string> q = new Queue<string>();
121             foreach (string s in System.Environment.GetCommandLineArgs()) {
122                 q.Enqueue(s);
123             }
124             q.Dequeue();   // Remove self argument
125
126             Regex SimpleOpt = new Regex(@"^-([a-zA-Z0-9]+)$");
127             Regex LongOpt   = new Regex(@"^--([\w-]+)$");
128             string OptLast = null;
129             List<string> args = new List<string>();
130
131             while (q.Count > 0) {
132                 string opt = q.Dequeue();
133                 Match m;
134                    
135                 m = SimpleOpt.Match(opt);
136                 if (m.Success) {
137                     string s = m.Groups[1].Value;
138                     if (s.Length > 1) {
139                         foreach (char c in s) {
140                             Options[c.ToString()] = "";
141                         }
142                         OptLast = null;
143                     } else {
144                         Options[s] = "";
145                         OptLast = s;
146                     }
147                     continue;
148                 }
149
150                 m = LongOpt.Match(opt);
151                 if (m.Success) {
152                     string s = m.Groups[1].Value;
153                     Options[s] = "";
154                     OptLast = s;
155                     continue;
156                 }
157
158                 // else
159
160                 if (OptLast != null) {
161                     Options[OptLast] = opt;
162                     OptLast = null;
163                 } else {
164                     args.Add(opt);
165                 }
166             }
167             Arguments = args.ToArray();
168
169             /*
170             Console.WriteLine("Options:");
171             foreach (string key in Options.Keys)
172                 Console.WriteLine("   {0}\t{1}", key, Options[key]);
173
174             Console.WriteLine("Arguments: {0}", String.Join(" ", Arguments));
175             */
176         }
177
178         public void LoadPlugin(string assemblyname) {
179             Assembly a = Assembly.LoadFile("plugins/" + assemblyname + ".dll");
180             Type[] types = a.GetTypes();
181             foreach (Type t in types) {
182                 if (t.IsSubclassOf(typeof(WebThingPlugin))) {
183                     WebThingPlugin p = (WebThingPlugin) a.CreateInstance(t.FullName, false, BindingFlags.ExactBinding, null, null, null, null);
184                     p.Init(this);
185                     Plugins[t.FullName] = p;
186                     Console.WriteLine("Successfully loaded {0}", t.FullName);
187                 }
188             }
189         }
190
191         public void AttachWidget(Gtk.Widget widget, CompassDirection direction, AttachOptions xoptions, AttachOptions yoptions) {
192             switch(direction) {
193             case CompassDirection.N:
194                 WidgetGrid.Attach(widget, 0, 3, 0, 1, xoptions, yoptions, 0, 0);
195                 break;
196             case CompassDirection.E:
197                 WidgetGrid.Attach(widget, 2, 3, 1, 2, xoptions, yoptions, 0, 0);
198                 break;
199             case CompassDirection.S:
200                 WidgetGrid.Attach(widget, 0, 3, 2, 3, xoptions, yoptions, 0, 0);
201                 break;
202             case CompassDirection.W:
203                 WidgetGrid.Attach(widget, 0, 1, 1, 2, xoptions, yoptions, 0, 0);
204                 break;
205             case CompassDirection.Interior:
206                 InteriorOverlay.Add(widget);
207                 break;
208             }
209         }
210
211         public void AttachWidget(Gtk.Widget widget, CompassDirection direction) {
212             AttachWidget(widget, direction, 0, 0);
213         }
214
215         public WebView NewTab() {
216             WebThingView newview = NewWebThingView();
217             WebViewSetupPlugins(newview.WebView);
218             return newview.WebView;
219         }
220
221         private WebThingView NewWebThingView() {
222             WebThingView newview = new WebThingView();
223             Tabs.AppendPage(newview, new Label("Blank"));
224             newview.WebView.TitleChanged += delegate(object o, TitleChangedArgs e) {
225                 Tabs.SetTabLabelText((Gtk.Widget) newview, e.Title);
226                 if (newview == Tabs.CurrentPageWidget)
227                     _Window.Title = e.Title + " - WebThing";
228             };
229             newview.Show();
230             return newview;
231         }
232
233         private void WebViewSetupPlugins(WebView view) {
234             foreach (string key in Plugins.Keys) {
235                 Plugins[key].InitWebView(view);
236             }
237         }
238
239         public void CloseTab() {
240             CloseTab(_Tabs.Page);
241         }
242
243         public void CloseTab(int tab) {
244             if (_Tabs.NPages > 1) {
245                 try {
246                     WebThingView view = _Tabs.GetNthPage(tab) as WebThingView;
247                     _Tabs.RemovePage(tab);
248                     view.Dispose();
249                 } catch (ArgumentOutOfRangeException) {
250                 }
251             }
252         }
253
254         public string FixUri(string Uri) {
255             if (!Regex.IsMatch(Uri, @"://")) {
256                 return String.Format("http://{0}", Uri);
257             }
258             return Uri;
259         }
260
261         public void OpenUri(string Uri) {
262             wv.Open(FixUri(Uri));
263         }
264
265         public void OpenUriTab(string Uri) {
266             WebView view = NewTab();
267             view.Open(FixUri(Uri));
268         }
269
270         public void Quit() {
271             // TODO: Create a way of shutting down plugins
272             Application.Quit();
273         }
274
275         private void Tabs_SwitchPage(object o, SwitchPageArgs e) {
276             Gtk.Widget page = _Tabs.GetNthPage((int)e.PageNum);
277             _Window.Title = _Tabs.GetTabLabelText(page) + " - WebThing";
278         }
279     }
280 }