using System;
using System.Collections.Generic;
-using System.Reflection;
using System.IO;
using System.Text.RegularExpressions;
using System.Runtime.InteropServices;
using WebKit;
namespace bytex64.WebThing {
- public enum CompassDirection {
+ public enum AttachPoint {
N, E, S, W, Interior
}
public class WebThing {
+ private Gtk.Window _Window;
public Gtk.Window Window {
get { return _Window; }
}
-
public Gtk.Window w {
get { return _Window; }
}
- public Gtk.ScrolledWindow ScrolledWindow {
- get { return _ScrolledWindow; }
+ public ScrolledWindow ScrolledWindow {
+ get { return Tabs.CurrentPageWidget as ScrolledWindow; }
}
-
- public Gtk.ScrolledWindow sw {
- get { return _ScrolledWindow; }
+ public ScrolledWindow sw {
+ get { return ScrolledWindow; }
}
- public WebKit.WebView WebView {
- get { return _WebView; }
+ public WebView WebView {
+ get { return (Tabs.CurrentPageWidget as WebThingView).WebView; }
+ }
+ public WebView wv {
+ get { return WebView; }
}
- public WebKit.WebView wv {
- get { return _WebView; }
+ private Gtk.Notebook _Tabs;
+ public Gtk.Notebook Tabs {
+ get { return _Tabs; }
}
- private Gtk.Window _Window;
- private ScrolledWindow _ScrolledWindow;
- private WebKit.WebView _WebView;
private Gtk.Table WidgetGrid;
private Gtk.Alignment InteriorOverlay;
- public Dictionary<string,WebThingPlugin> Plugins;
- public Dictionary<string,string> Options;
- public string[] Arguments;
+ public PluginManager Plugins;
+ public SearchHandler Search;
[DllImport ("SoupSettings.dll")]
private static extern void soup_settings();
+ // Main setup
public void Run() {
Application.Init();
- ParseArgs();
+ soup_settings();
+
+ Config.ParseCommandLine();
+ Config.Load();
+ //Config.DumpOptions();
+ // Initialize Window
_Window = new Gtk.Window("WebThing");
- _Window.SetWmclass("webthing", "WebThing");
+ // The GTK+ docs say not to use this, but the defaults are
+ // based on the executable name, which I don't like.
+ _Window.SetWmclass("webthing", "WebThing");
_Window.Role = "browser";
+ {
+ int w, h;
+
+ if (Config.Options.ContainsKey("Width"))
+ w = Convert.ToInt32(Config.Options["Width"]);
+ else
+ w = 640;
+
+ if (Config.Options.ContainsKey("Height"))
+ h = Convert.ToInt32(Config.Options["Height"]);
+ else
+ h = 480;
+
+ _Window.DefaultSize = new Gdk.Size(w, h);
+ }
_Window.Destroyed += delegate { Quit(); };
+ // Initialize WidgetGrid
+ // The WidgetGrid holds the Tabs (and thus WebKit) and
+ // AttachPoint.Interior in the center, and allows widgets to
+ // be added on the sides of the browser
WidgetGrid = new Gtk.Table(3, 3, false);
_Window.Add(WidgetGrid);
- _ScrolledWindow = new Gtk.ScrolledWindow();
- WidgetGrid.Attach(_ScrolledWindow, 1, 2, 1, 2);
-
+ // Initialize Tabs
+ // Tabs are a core feature of WebThing, not a plugin. By
+ // default, they do nothing -- Tab manipulation is left to
+ // plugins to define.
+ _Tabs = new Gtk.Notebook();
+ _Tabs.ShowBorder = false;
+ _Tabs.Scrollable = true;
+ _Tabs.SwitchPage += Tabs_SwitchPage;
+ WidgetGrid.Attach(_Tabs, 1, 2, 1, 2);
+
+ // InteriorOverlay goes over top of the Tabs to contain
+ // widgets that hover over the content, like progress, or
+ // inline search. This is not a very solid idea ATM.
InteriorOverlay = new Gtk.Alignment(1, 0, 0, 0);
WidgetGrid.Attach(InteriorOverlay, 1, 2, 1, 2);
- _WebView = new WebKit.WebView();
- _WebView.TitleChanged += delegate(object o, TitleChangedArgs e) {
- _Window.Title = e.Title + " - WebThing";
- };
- soup_settings();
+ _Window.ShowAll();
- _ScrolledWindow.Add(_WebView);
+ // Load Plugins
+ Plugins = new PluginManager(this);
+ Plugins.Load();
- _Window.ShowAll();
+ // Load Search Handlers
+ Search = new SearchHandler(this);
- Plugins = new Dictionary<string,WebThingPlugin>();
- // TODO: Conf.Get("plugins") instead of hard-coded path?
- using (TextReader f = new StreamReader("plugins.conf")) {
- string line;
- while ((line = f.ReadLine()) != null) {
- line = line.Trim();
- LoadPlugin(line);
- }
- }
+ // Create a new, default WebThingView if one has not already
+ // been created.
+ if (Tabs.NPages == 0)
+ OpenTab("http://dominionofawesome.com/");
+ WebView.GrabFocus();
Application.Run();
}
- protected void ParseArgs() {
- Options = new Dictionary<string,string>();
- Queue<string> q = new Queue<string>();
- foreach (string s in System.Environment.GetCommandLineArgs()) {
- q.Enqueue(s);
- }
- q.Dequeue(); // Remove self argument
-
- Regex SimpleOpt = new Regex(@"^-([a-zA-Z0-9]+)$");
- Regex LongOpt = new Regex(@"^--([\w-]+)$");
- string OptLast = null;
- List<string> args = new List<string>();
-
- while (q.Count > 0) {
- string opt = q.Dequeue();
- Match m;
-
- m = SimpleOpt.Match(opt);
- if (m.Success) {
- string s = m.Groups[1].Value;
- if (s.Length > 1) {
- foreach (char c in s) {
- Options[c.ToString()] = "";
- }
- OptLast = null;
- } else {
- Options[s] = "";
- OptLast = s;
- }
- continue;
- }
-
- m = LongOpt.Match(opt);
- if (m.Success) {
- string s = m.Groups[1].Value;
- Options[s] = "";
- OptLast = s;
- continue;
- }
-
- // else
-
- if (OptLast != null) {
- Options[OptLast] = opt;
- OptLast = null;
- } else {
- args.Add(opt);
- }
- }
- Arguments = args.ToArray();
-
- /*
- Console.WriteLine("Options:");
- foreach (string key in Options.Keys)
- Console.WriteLine(" {0}\t{1}", key, Options[key]);
-
- Console.WriteLine("Arguments: {0}", String.Join(" ", Arguments));
- */
- }
-
- public void LoadPlugin(string assemblyname) {
- Assembly a = Assembly.LoadFile("plugins/" + assemblyname + ".dll");
- Type[] types = a.GetTypes();
- foreach (Type t in types) {
- if (t.GetInterface("WebThingPlugin") != null) {
- WebThingPlugin p = (WebThingPlugin) a.CreateInstance(t.FullName, false, BindingFlags.ExactBinding, null, null, null, null);
- p.Init(this);
- Plugins[t.FullName] = p;
- Console.WriteLine("Successfully loaded {0}", t.FullName);
- }
- }
+ public void Quit() {
+ Plugins.Deinit();
+ Application.Quit();
}
- public void AttachWidget(Gtk.Widget widget, CompassDirection direction, AttachOptions xoptions, AttachOptions yoptions) {
+ // Widget attachment
+ public void AttachWidget(Gtk.Widget widget, AttachPoint direction, AttachOptions xoptions, AttachOptions yoptions) {
switch(direction) {
- case CompassDirection.N:
+ case AttachPoint.N:
WidgetGrid.Attach(widget, 0, 3, 0, 1, xoptions, yoptions, 0, 0);
break;
- case CompassDirection.E:
+ case AttachPoint.E:
WidgetGrid.Attach(widget, 2, 3, 1, 2, xoptions, yoptions, 0, 0);
break;
- case CompassDirection.S:
+ case AttachPoint.S:
WidgetGrid.Attach(widget, 0, 3, 2, 3, xoptions, yoptions, 0, 0);
break;
- case CompassDirection.W:
+ case AttachPoint.W:
WidgetGrid.Attach(widget, 0, 1, 1, 2, xoptions, yoptions, 0, 0);
break;
- case CompassDirection.Interior:
+ case AttachPoint.Interior:
InteriorOverlay.Add(widget);
break;
}
}
- public void AttachWidget(Gtk.Widget widget, CompassDirection direction) {
+ public void AttachWidget(Gtk.Widget widget, AttachPoint direction) {
AttachWidget(widget, direction, 0, 0);
}
- public void OpenUri(string Uri) {
- if (!Regex.IsMatch(Uri, @"://")) {
- Uri = String.Format("http://{0}", Uri);
+ // Tab management
+ public WebThingView NewTab() {
+ WebThingView newview = NewWebThingView();
+ Plugins.WebViewSetup(newview.WebView);
+ return newview;
+ }
+
+ private WebThingView NewWebThingView() {
+ WebThingView newview = new WebThingView();
+ Tabs.AppendPage(newview, new Label("Blank"));
+ newview.WebView.TitleChanged += delegate(object o, TitleChangedArgs e) {
+ Tabs.SetTabLabelText((Gtk.Widget) newview, e.Title);
+ if (newview == Tabs.CurrentPageWidget)
+ _Window.Title = e.Title + " - WebThing";
+ };
+ newview.Show();
+ return newview;
+ }
+
+ public void CloseTab() {
+ CloseTab(_Tabs.Page);
+ }
+
+ public void CloseTab(int tab) {
+ if (_Tabs.NPages > 1) {
+ try {
+ WebThingView view = _Tabs.GetNthPage(tab) as WebThingView;
+ _Tabs.RemovePage(tab);
+ view.Dispose();
+ } catch (ArgumentOutOfRangeException) {
+ Console.WriteLine("Attempted to close tab out of range: {0}", tab);
+ }
}
- wv.Open(Uri);
}
- public void Quit() {
- // TODO: Create a way of shutting down plugins
- Application.Quit();
+ private void Tabs_SwitchPage(object o, SwitchPageArgs e) {
+ Gtk.Widget page = _Tabs.GetNthPage((int)e.PageNum);
+ _Window.Title = _Tabs.GetTabLabelText(page) + " - WebThing";
+ }
+
+ // Uri loading
+ private string GetUri(string query) {
+ Uri u;
+ try {
+ u = new Uri(query);
+ return u.ToString();
+ } catch(UriFormatException) {
+ try {
+ u = new Uri(String.Format("http://{0}", query));
+ return u.ToString();
+ } catch (UriFormatException) {
+ return Search.Transform(query);
+ }
+ }
+ }
+
+ public bool Open(string query) {
+ string uri = GetUri(query);
+ if (uri == null) return false;
+
+ wv.Open(uri);
+ return true;
+ }
+
+ public bool OpenTab(string query) {
+ WebThingView wtv = NewTab();
+ string uri = GetUri(query);
+ if (uri == null) return false;
+
+ wtv.WebView.Open(uri);
+ return true;
+ }
+
+ public void Scroll(double x, double y) {
+ ScrolledWindow.Hadjustment.Value += x;
+ if (ScrolledWindow.Hadjustment.Value > ScrolledWindow.Hadjustment.Upper - ScrolledWindow.Hadjustment.PageSize)
+ ScrolledWindow.Hadjustment.Value = ScrolledWindow.Hadjustment.Upper - ScrolledWindow.Hadjustment.PageSize;
+ ScrolledWindow.Vadjustment.Value += y;
+ if (ScrolledWindow.Vadjustment.Value > ScrolledWindow.Vadjustment.Upper - ScrolledWindow.Vadjustment.PageSize)
+ ScrolledWindow.Vadjustment.Value = ScrolledWindow.Vadjustment.Upper - ScrolledWindow.Vadjustment.PageSize;
+ }
+
+ public void Bump(int x, int y) {
+ Scroll(x * ScrolledWindow.Hadjustment.StepIncrement, y * ScrolledWindow.Vadjustment.StepIncrement);
}
}
}