Fix scrolling functionality
[WebThing.git] / WebThing.cs
1 using System;
2 using System.Collections.Generic;
3 using System.IO;
4 using System.Text.RegularExpressions;
5 using System.Runtime.InteropServices;
6 using Gtk;
7 using GtkSharp;
8 using WebKit;
9
10 namespace bytex64.WebThing {
11     public enum AttachPoint {
12         N, E, S, W, Interior
13     }
14
15     public class WebThing {
16         private Gtk.Window _Window;
17         public Gtk.Window Window {
18             get { return _Window; }
19         }
20         public Gtk.Window w {
21             get { return _Window; }
22         }
23
24         public ScrolledWindow ScrolledWindow {
25             get { return Tabs.CurrentPageWidget as ScrolledWindow; }
26         }
27         public ScrolledWindow sw {
28             get { return ScrolledWindow; }
29         }
30
31         public WebView WebView {
32             get { return (Tabs.CurrentPageWidget as WebThingView).WebView; }
33         }
34         public WebView wv {
35             get { return WebView; }
36         }
37
38         private Gtk.Notebook _Tabs;
39         public Gtk.Notebook Tabs {
40             get { return _Tabs; }
41         }
42
43         private Gtk.Table WidgetGrid;
44         private Gtk.Alignment InteriorOverlay;
45
46         public PluginManager Plugins;
47         public SearchHandler Search;
48
49         [DllImport ("SoupSettings.dll")]
50         private static extern void soup_settings();
51
52         // Main setup
53         public void Run() {
54             Application.Init();
55
56             soup_settings();
57
58             Config.ParseCommandLine();
59             Config.Load();
60             //Config.DumpOptions();
61
62             // Initialize Window
63             _Window = new Gtk.Window("WebThing");
64             // The GTK+ docs say not to use this, but the defaults are
65             // based on the executable name, which I don't like.
66             _Window.SetWmclass("webthing", "WebThing");  
67             _Window.Role = "browser";
68             {
69                 int w, h;
70
71                 if (Config.Options.ContainsKey("Width"))
72                     w = Convert.ToInt32(Config.Options["Width"]);
73                 else
74                     w = 640;
75
76                 if (Config.Options.ContainsKey("Height"))
77                     h = Convert.ToInt32(Config.Options["Height"]);
78                 else
79                     h = 480;
80
81                 _Window.DefaultSize = new Gdk.Size(w, h);
82             }
83             _Window.Destroyed += delegate { Quit(); };
84
85             // Initialize WidgetGrid
86             // The WidgetGrid holds the Tabs (and thus WebKit) and
87             // AttachPoint.Interior in the center, and allows widgets to
88             // be added on the sides of the browser
89             WidgetGrid = new Gtk.Table(3, 3, false);
90             _Window.Add(WidgetGrid);
91
92             // Initialize Tabs
93             // Tabs are a core feature of WebThing, not a plugin.  By
94             // default, they do nothing -- Tab manipulation is left to
95             // plugins to define.
96             _Tabs = new Gtk.Notebook();
97             _Tabs.ShowBorder = false;
98             _Tabs.Scrollable = true;
99             _Tabs.SwitchPage += Tabs_SwitchPage;
100             WidgetGrid.Attach(_Tabs, 1, 2, 1, 2);
101
102             // InteriorOverlay goes over top of the Tabs to contain
103             // widgets that hover over the content, like progress, or
104             // inline search.  This is not a very solid idea ATM.
105             InteriorOverlay = new Gtk.Alignment(1, 0, 0, 0);
106             WidgetGrid.Attach(InteriorOverlay, 1, 2, 1, 2);
107
108             _Window.ShowAll();
109
110             // Load Plugins
111             Plugins = new PluginManager(this);
112             Plugins.Load();
113
114             // Load Search Handlers
115             Search = new SearchHandler(this);
116
117             // Create a new, default WebThingView if one has not already
118             // been created.
119             if (Tabs.NPages == 0)
120                 OpenTab("http://dominionofawesome.com/");
121             WebView.GrabFocus();
122
123             Application.Run();
124         }
125
126         public void Quit() {
127             Plugins.Deinit();
128             Application.Quit();
129         }
130
131         // Widget attachment
132         public void AttachWidget(Gtk.Widget widget, AttachPoint direction, AttachOptions xoptions, AttachOptions yoptions) {
133             switch(direction) {
134             case AttachPoint.N:
135                 WidgetGrid.Attach(widget, 0, 3, 0, 1, xoptions, yoptions, 0, 0);
136                 break;
137             case AttachPoint.E:
138                 WidgetGrid.Attach(widget, 2, 3, 1, 2, xoptions, yoptions, 0, 0);
139                 break;
140             case AttachPoint.S:
141                 WidgetGrid.Attach(widget, 0, 3, 2, 3, xoptions, yoptions, 0, 0);
142                 break;
143             case AttachPoint.W:
144                 WidgetGrid.Attach(widget, 0, 1, 1, 2, xoptions, yoptions, 0, 0);
145                 break;
146             case AttachPoint.Interior:
147                 InteriorOverlay.Add(widget);
148                 break;
149             }
150         }
151
152         public void AttachWidget(Gtk.Widget widget, AttachPoint direction) {
153             AttachWidget(widget, direction, 0, 0);
154         }
155
156         // Tab management
157         public WebThingView NewTab() {
158             WebThingView newview = NewWebThingView();
159             Plugins.WebViewSetup(newview.WebView);
160             return newview;
161         }
162
163         private WebThingView NewWebThingView() {
164             WebThingView newview = new WebThingView();
165             Tabs.AppendPage(newview, new Label("Blank"));
166             newview.WebView.TitleChanged += delegate(object o, TitleChangedArgs e) {
167                 Tabs.SetTabLabelText((Gtk.Widget) newview, e.Title);
168                 if (newview == Tabs.CurrentPageWidget)
169                     _Window.Title = e.Title + " - WebThing";
170             };
171             newview.Show();
172             return newview;
173         }
174
175         public void CloseTab() {
176             CloseTab(_Tabs.Page);
177         }
178
179         public void CloseTab(int tab) {
180             if (_Tabs.NPages > 1) {
181                 try {
182                     WebThingView view = _Tabs.GetNthPage(tab) as WebThingView;
183                     _Tabs.RemovePage(tab);
184                     view.Dispose();
185                 } catch (ArgumentOutOfRangeException) {
186                     Console.WriteLine("Attempted to close tab out of range: {0}", tab);
187                 }
188             }
189         }
190
191         private void Tabs_SwitchPage(object o, SwitchPageArgs e) {
192             Gtk.Widget page = _Tabs.GetNthPage((int)e.PageNum);
193             _Window.Title = _Tabs.GetTabLabelText(page) + " - WebThing";
194         }
195
196         // Uri loading
197         private string GetUri(string query) {
198             Uri u;
199             try {
200                 u = new Uri(query);
201                 return u.ToString();
202             } catch(UriFormatException) {
203                 try {
204                     u = new Uri(String.Format("http://{0}", query));
205                     return u.ToString();
206                 } catch (UriFormatException) {
207                     return Search.Transform(query);
208                 }
209             }
210         }
211
212         public bool Open(string query) {
213             string uri = GetUri(query);
214             if (uri == null) return false;
215             
216             wv.Open(uri);
217             return true;
218         }
219
220         public bool OpenTab(string query) {
221             WebThingView wtv = NewTab();
222             string uri = GetUri(query);
223             if (uri == null) return false;
224
225             wtv.WebView.Open(uri);
226             return true;
227         }
228
229         public void Scroll(double x, double y) {
230             ScrolledWindow.Hadjustment.Value += x;
231             if (ScrolledWindow.Hadjustment.Value > ScrolledWindow.Hadjustment.Upper - ScrolledWindow.Hadjustment.PageSize)
232                 ScrolledWindow.Hadjustment.Value = ScrolledWindow.Hadjustment.Upper - ScrolledWindow.Hadjustment.PageSize;
233             ScrolledWindow.Vadjustment.Value += y;
234             if (ScrolledWindow.Vadjustment.Value > ScrolledWindow.Vadjustment.Upper - ScrolledWindow.Vadjustment.PageSize)
235                 ScrolledWindow.Vadjustment.Value = ScrolledWindow.Vadjustment.Upper - ScrolledWindow.Vadjustment.PageSize;
236         }
237
238         public void Bump(int x, int y) {
239             Scroll(x * ScrolledWindow.Hadjustment.StepIncrement, y * ScrolledWindow.Vadjustment.StepIncrement);
240         }
241     }
242 }