Initial commit of default luakit config from 2010.08.30

Wed, 01 Sep 2010 03:53:30 +0100

author
Matthew Wild <mwild1@gmail.com>
date
Wed, 01 Sep 2010 03:53:30 +0100
changeset 0
98e4b0c9fcac
child 1
4d7540af8518

Initial commit of default luakit config from 2010.08.30

binds.lua file | annotate | diff | comparison | revisions
globals.lua file | annotate | diff | comparison | revisions
modes.lua file | annotate | diff | comparison | revisions
rc.lua file | annotate | diff | comparison | revisions
theme.lua file | annotate | diff | comparison | revisions
webview.lua file | annotate | diff | comparison | revisions
window.lua file | annotate | diff | comparison | revisions
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/binds.lua	Wed Sep 01 03:53:30 2010 +0100
@@ -0,0 +1,221 @@
+-----------------
+-- Keybindings --
+-----------------
+
+binds = {}
+
+-- Binding aliases
+local key, buf, but, cmd = lousy.bind.key, lousy.bind.buf, lousy.bind.but, lousy.bind.cmd
+
+-- Globals or defaults that are used in binds
+local scroll_step = globals.scroll_step or 20
+local zoom_step   = globals.zoom_step or 0.1
+local homepage    = globals.homepage or "http://luakit.org"
+
+-- Add key bindings to be used across all windows in the given modes.
+binds.mode_binds = {
+     -- buf(Pattern,                    function (w, buffer, opts) .. end, opts),
+     -- key({Modifiers}, Key name,      function (w, opts)         .. end, opts),
+     -- but({Modifiers}, Button num,    function (w, opts)         .. end, opts),
+    all = {
+        key({},          "Escape",      function (w) w:set_mode() end),
+        key({"Control"}, "[",           function (w) w:set_mode() end),
+
+        but({},          8,             function (w) w:back()    end),
+        but({},          9,             function (w) w:forward() end),
+    },
+    normal = {
+        key({},          "i",           function (w) w:set_mode("insert")  end),
+        key({},          ":",           function (w) w:set_mode("command") end),
+
+        -- Scrolling
+        key({},          "j",           function (w) w:scroll_vert("+"..scroll_step.."px") end),
+        key({},          "k",           function (w) w:scroll_vert("-"..scroll_step.."px") end),
+        key({},          "h",           function (w) w:scroll_horiz("-"..scroll_step.."px") end),
+        key({},          "l",           function (w) w:scroll_horiz("+"..scroll_step.."px") end),
+        key({"Control"}, "d",           function (w) w:scroll_page(0.5)    end),
+        key({"Control"}, "u",           function (w) w:scroll_page(-0.5)   end),
+        key({"Control"}, "f",           function (w) w:scroll_page(1.0)    end),
+        key({"Control"}, "b",           function (w) w:scroll_page(-1.0)   end),
+        buf("^gg$",                     function (w) w:scroll_vert("0%")   end),
+        buf("^G$",                      function (w) w:scroll_vert("100%") end),
+        buf("^[\-\+]?[0-9]+[%%G]$",     function (w, b) w:scroll_vert(string.match(b, "^([\-\+]?%d+)[%%G]$") .. "%") end),
+
+        -- Traditional scrolling commands
+        key({},          "Down",        function (w) w:scroll_vert("+"..scroll_step.."px") end),
+        key({},          "Up",          function (w) w:scroll_vert("-"..scroll_step.."px") end),
+        key({},          "Left",        function (w) w:scroll_horiz("-"..scroll_step.."px") end),
+        key({},          "Right",       function (w) w:scroll_horiz("+"..scroll_step.."px") end),
+        key({},          "Page_Down",   function (w) w:scroll_page(1.0)    end),
+        key({},          "Page_Up",     function (w) w:scroll_page(-1.0)   end),
+        key({},          "Home",        function (w) w:scroll_vert("0%")   end),
+        key({},          "End",         function (w) w:scroll_vert("100%") end),
+
+        -- Zooming
+        buf("^z0$",                     function (w) w:zoom_reset()        end),
+        buf("^zI$",                     function (w) w:zoom_in(zoom_step)  end),
+        buf("^zO$",                     function (w) w:zoom_out(zoom_step) end),
+        key({"Control"}, "+",           function (w) w:zoom_in(zoom_step)  end),
+        key({"Control"}, "-",           function (w) w:zoom_out(zoom_step) end),
+
+        -- Clipboard
+        key({},          "p",           function (w) w:navigate(luakit.get_selection()) end),
+        key({},          "P",           function (w) w:new_tab(luakit.get_selection())  end),
+        buf("^yy$",                     function (w) luakit.set_selection((w:get_current() or {}).uri or "") end),
+        buf("^yt$",                     function (w) luakit.set_selection(w.win.title) end),
+
+        -- Commands
+        buf("^o$",                      function (w, c) w:enter_cmd(":open ")    end),
+        buf("^t$",                      function (w, c) w:enter_cmd(":tabopen ") end),
+        buf("^w$",                      function (w, c) w:enter_cmd(":winopen ") end),
+        buf("^O$",                      function (w, c) w:enter_cmd(":open "    .. ((w:get_current() or {}).uri or "")) end),
+        buf("^T$",                      function (w, c) w:enter_cmd(":tabopen " .. ((w:get_current() or {}).uri or "")) end),
+        buf("^W$",                      function (w, c) w:enter_cmd(":winopen " .. ((w:get_current() or {}).uri or "")) end),
+        buf("^,g$",                     function (w, c) w:enter_cmd(":websearch google ") end),
+
+        -- Debian search shorcut access
+        buf("^\\dbug$",                function (w, c) w:enter_cmd(":websearch debbugs ") end),
+        buf("^\\dpts$",                function (w, c) w:enter_cmd(":websearch dpts ") end),
+        buf("^\\dpkg$",                function (w, c) w:enter_cmd(":websearch dpkg ") end),
+
+        -- Searching
+        key({},          "/",           function (w) w:start_search("/")  end),
+        key({},          "?",           function (w) w:start_search("?") end),
+        key({},          "n",           function (w) w:search(nil, true) end),
+        key({},          "N",           function (w) w:search(nil, false) end),
+
+        -- History
+        buf("^[0-9]*H$",                function (w, b) w:back   (tonumber(string.match(b, "^(%d*)H$") or 1)) end),
+        buf("^[0-9]*L$",                function (w, b) w:forward(tonumber(string.match(b, "^(%d*)L$") or 1)) end),
+        key({},          "b",           function (w) w:back() end),
+        key({},          "XF86Back",    function (w) w:back() end),
+        key({},          "XF86Forward", function (w) w:forward() end),
+
+        -- Tab
+        key({"Control"}, "Page_Up",     function (w) w:prev_tab() end),
+        key({"Control"}, "Page_Down",   function (w) w:next_tab() end),
+        buf("^[0-9]*gT$",               function (w, b) w:prev_tab(tonumber(string.match(b, "^(%d*)gT$") or 1)) end),
+        buf("^[0-9]*gt$",               function (w, b) w:next_tab(tonumber(string.match(b, "^(%d*)gt$") or 1)) end),
+        buf("^gH$",                     function (w)    w:new_tab(homepage) end),
+        buf("^d$",                      function (w)    w:close_tab() end),
+
+        key({},          "r",           function (w) w:reload() end),
+        buf("^gh$",                     function (w) w:navigate(homepage) end),
+
+        -- Window
+        buf("^ZZ$",                     function (w) w:close_win() end),
+        buf("^D$",                      function (w) w:close_win() end),
+
+        -- Link following
+        key({},          "f",           function (w) w:set_mode("follow") end),
+
+        -- Bookmarking
+        key({},          "B",           function (w) w:enter_cmd(":bookmark " .. ((w:get_current() or {}).uri or "http://") .. " ") end),
+        buf("^gb$",                     function (w) w:navigate(bookmarks.dump_html()) end),
+        buf("^gB$",                     function (w) w:new_tab (bookmarks.dump_html()) end),
+
+        -- Mouse bindings
+        but({},          2,             function (w)
+                                            -- Open hovered uri in new tab
+                                            local uri = w:get_current().hovered_uri
+                                            if uri then w:new_tab(uri)
+                                            else -- Open selection in current tab
+                                                uri = luakit.get_selection()
+                                                if uri then w:get_current().uri = uri end
+                                            end
+                                        end),
+    },
+    command = {
+        key({"Shift"},   "Insert",      function (w) w:insert_cmd(luakit.get_selection()) end),
+        key({},          "Up",          function (w) w:cmd_hist_prev() end),
+        key({},          "Down",        function (w) w:cmd_hist_next() end),
+        key({},          "Tab",         function (w) w:cmd_completion() end),
+        key({"Control"}, "w",           function (w) w:del_word() end),
+        key({"Control"}, "u",           function (w) w:del_line() end),
+    },
+    search = {
+        key({},          "Up",          function (w) w:srch_hist_prev() end),
+        key({},          "Down",        function (w) w:srch_hist_next() end),
+    },
+    insert = { },
+}
+
+-- Command bindings which are matched in the "command" mode from text
+-- entered into the input bar.
+binds.commands = {
+ -- cmd({Command, Alias1, ...},         function (w, arg, opts) .. end, opts),
+    cmd({"open",        "o"  },         function (w, a)    w:navigate(a) end),
+    cmd({"tabopen",     "t"  },         function (w, a)    w:new_tab(a) end),
+    cmd({"winopen",     "w"  },         function (w, a)    window.new{a} end),
+    cmd({"back"              },         function (w, a)    w:back(tonumber(a) or 1) end),
+    cmd({"forward",     "f"  },         function (w, a)    w:forward(tonumber(a) or 1) end),
+    cmd({"scroll"            },         function (w, a)    w:scroll_vert(a) end),
+    cmd({"quit",        "q"  },         function (w)       luakit.quit() end),
+    cmd({"close",       "c"  },         function (w)       w:close_tab() end),
+    cmd({"websearch",   "ws" },         function (w, e, s) w:websearch(e, s) end),
+    cmd({"reload",           },         function (w)       w:reload() end),
+    cmd({"viewsource",  "vs" },         function (w)       w:toggle_source(true) end),
+    cmd({"viewsource!", "vs!"},         function (w)       w:toggle_source() end),
+    cmd({"bookmark",    "bm" },         function (w, a)
+                                            local args = lousy.util.string.split(a)
+                                            local uri = table.remove(args, 1)
+                                            bookmarks.add(uri, args)
+                                        end),
+}
+
+-- Helper functions which are added to the window struct
+binds.helper_methods = {
+    -- Navigate current view or open new tab
+    navigate = function (w, uri, view)
+        if not view then view = w:get_current() end
+        if view then
+            view.uri = uri
+        else
+            return w:new_tab(uri)
+        end
+    end,
+
+    -- search engine wrapper
+    websearch = function (w, args)
+        local sep = string.find(args, " ")
+        local engine = string.sub(args, 1, sep-1)
+        local search = string.sub(args, sep+1)
+        search = string.gsub(search, "^%s*(.-)%s*$", "%1")
+        if not search_engines[engine] then
+            return error("No matching search engine found: " .. engine)
+        end
+        local uri = string.gsub(search_engines[engine], "{%d}", search)
+        return w:navigate(uri)
+    end,
+
+    -- Tab traversing functions
+    next_tab = function (w, n)
+        w.tabs:switch((((n or 1) + w.tabs:current() -1) % w.tabs:count()) + 1)
+    end,
+
+    prev_tab = function (w, n)
+        w.tabs:switch(((w.tabs:current() - (n or 1) -1) % w.tabs:count()) + 1)
+    end,
+
+    goto_tab = function (w, n)
+        w.tabs:switch(n)
+    end,
+
+    -- If argument is form-active or root-active, emits signal. Ignores all
+    -- other signals.
+    emit_form_root_active_signal = function (w, s)
+        if s == "form-active" then
+            w:get_current():emit_signal("form-active")
+        elseif s == "root-active" then
+            w:get_current():emit_signal("root-active")
+        end
+    end,
+}
+
+-- Insert webview method lookup on window structure
+table.insert(window.indexes, 1, function (w, k)
+    -- Lookup bind helper method
+    return binds.helper_methods[k]
+end)
+
+-- vim: et:sw=4:ts=8:sts=4:tw=80
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/globals.lua	Wed Sep 01 03:53:30 2010 +0100
@@ -0,0 +1,68 @@
+-- Global variables for luakit
+globals = {
+    homepage         = "http://luakit.org/",
+ -- homepage         = "http://github.com/mason-larobina/luakit",
+    scroll_step      = 20,
+    zoom_step        = 0.1,
+    max_cmd_history  = 100,
+    max_srch_history = 100,
+ -- http_proxy       = "http://example.com:3128",
+    download_dir     = luakit.get_special_dir("DOWNLOAD") or (os.getenv("HOME") .. "/downloads"),
+}
+
+-- Make useragent
+local rv, out, err = luakit.spawn_sync("uname -sm")
+local webkit_version = string.format("WebKitGTK+/%d.%d.%d", luakit.webkit_major_version,
+    luakit.webkit_minor_version, luakit.webkit_micro_version)
+local luakit_version = string.format("luakit/%s", luakit.version)
+globals.useragent = string.format("Mozilla/5.0 (%s) %s %s", string.match(out, "([^\n]*)"), webkit_version, luakit_version)
+
+-- Search common locations for a ca file which is used for ssl connection validation.
+local ca_files = {luakit.data_dir .. "/ca-certificates.crt",
+    "/etc/certs/ca-certificates.crt", "/etc/ssl/certs/ca-certificates.crt",}
+for _, ca_file in ipairs(ca_files) do
+    if os.exists(ca_file) then
+        globals.ca_file = ca_file
+        break
+    end
+end
+
+-- Change to stop navigation sites with invalid or expired ssl certificates
+globals.ssl_strict = false
+
+-- Search engines
+search_engines = {
+    luakit      = "http://luakit.org/search/index/luakit?q={0}",
+    google      = "http://google.com/search?q={0}",
+    wikipedia   = "http://en.wikipedia.org/wiki/Special:Search?search={0}",
+    debbugs     = "http://bugs.debian.org/{0}",
+    imdb        = "http://imdb.com/find?s=all&q={0}",
+    sourceforge = "http://sf.net/search/?words={0}",
+}
+
+-- Fake the cookie policy enum here
+cookie_policy = { always = 0, never = 1, no_third_party = 2 }
+
+-- Per-domain webview properties
+domain_props = { --[[
+    ["all"] = {
+        ["enable-scripts"]          = false,
+        ["enable-plugins"]          = false,
+        ["enable-private-browsing"] = false,
+        ["user-stylesheet-uri"]     = "",
+        ["accept-policy"]           = cookie_policy.never,
+    },
+    ["youtube.com"] = {
+        ["enable-scripts"] = true,
+        ["enable-plugins"] = true,
+    },
+    ["lwn.net"] = {
+       ["accept-policy"] = cookie_policy.no_third_party,
+    },
+    ["forums.archlinux.org"] = {
+        ["user-stylesheet-uri"]     = luakit.data_dir .. "/styles/dark.css",
+        ["enable-private-browsing"] = true,
+    }, ]]
+}
+
+-- vim: et:sw=4:ts=8:sts=4:tw=80
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/modes.lua	Wed Sep 01 03:53:30 2010 +0100
@@ -0,0 +1,162 @@
+-------------------------------
+-- luakit mode configuration --
+-------------------------------
+
+-- Table of modes and their callback hooks
+modes = {}
+
+-- Currently active mode hooks
+local current
+
+-- Update a modes hook table with new hooks
+function new_mode(mode, hooks)
+    modes[mode] = lousy.util.table.join(modes[mode] or {}, hooks)
+end
+
+-- Attach window & input bar signals for mode hooks
+window.init_funcs.modes_setup = function (w)
+    -- Calls the `enter` and `leave` mode hooks.
+    w.win:add_signal("mode-changed", function (_, mode)
+        -- Call the last modes `leave` hook.
+        if current and current.leave then
+            current.leave(w)
+        end
+
+        -- Update window binds
+        w:update_binds(mode)
+
+        -- Get new modes functions
+        current = modes[mode]
+        if not current then
+            error("changed to un-handled mode: " .. mode)
+        end
+
+        -- Call new modes `enter` hook.
+        if current.enter then current.enter(w) end
+    end)
+
+    -- Calls the `changed` hook on input widget changed.
+    w.ibar.input:add_signal("changed", function()
+        local text = w.ibar.input.text
+        if current and current.changed then
+            current.changed(w, text)
+        end
+    end)
+
+    -- Calls the `activate` hook on input widget activate.
+    w.ibar.input:add_signal("activate", function()
+        local text = w.ibar.input.text
+        if current and current.activate then
+            current.activate(w, text)
+        end
+    end)
+end
+
+-- Add mode related window methods
+for name, func in pairs({
+    set_mode = function (w, name) lousy.mode.set(w.win, name)  end,
+    get_mode = function (w)       return lousy.mode.get(w.win) end,
+    is_mode  = function (w, name) return name == w:get_mode()  end,
+}) do window.methods[name] = func end
+
+-- Setup normal mode
+new_mode("normal", {
+    enter = function (w)
+        local i, p = w.ibar.input, w.ibar.prompt
+        i:hide()
+        p:hide()
+    end,
+})
+
+-- Setup insert mode
+new_mode("insert", {
+    enter = function (w)
+        local i, p = w.ibar.input, w.ibar.prompt
+        i:hide()
+        i.text = ""
+        p.text = "-- INSERT --"
+        p:show()
+    end,
+})
+
+-- Setup command mode
+new_mode("command", {
+    enter = function (w)
+        local i, p = w.ibar.input, w.ibar.prompt
+        p:hide()
+        i.text = ":"
+        i:show()
+        i:focus()
+        i:set_position(-1)
+    end,
+    changed = function (w, text)
+        -- Auto-exit command mode if user backspaces ":" in the input bar.
+        if not string.match(text, "^:") then w:set_mode() end
+    end,
+    activate = function (w, text)
+        w:cmd_hist_add(text)
+        w:match_cmd(string.sub(text, 2))
+        w:set_mode()
+    end,
+})
+
+-- Setup search mode
+new_mode("search", {
+    enter = function (w)
+        -- Clear old search state
+        w.search_state = {}
+        local i, p = w.ibar.input, w.ibar.prompt
+        p:hide()
+        p.text = ""
+        i.text = "/"
+        i:show()
+    end,
+    leave = function (w)
+        -- Check if search was aborted and return to original position
+        local s = w.search_state
+        if s.marker then
+            w:get_current():set_scroll_vert(s.marker)
+            s.marker = nil
+        end
+    end,
+    changed = function (w, text)
+        -- Check that the first character is '/' or '?' and update search
+        if string.match(text, "^[\?\/]") then
+            w:search(string.sub(text, 2), (string.sub(text, 1, 1) == "/"))
+        else
+            w:clear_search()
+            w:set_mode()
+        end
+    end,
+    activate = function (w, text)
+        w.search_state.marker = nil
+        w:srch_hist_add(text)
+        w:set_mode()
+        -- Ghost the search term in the prompt
+        local p = w.ibar.prompt
+        p.text = lousy.util.escape(text)
+        p:show()
+    end,
+})
+
+-- Setup follow mode
+new_mode("follow", {
+    enter = function (w)
+        local i, p = w.ibar.input, w.ibar.prompt
+        w:eval_js_from_file(lousy.util.find_data("scripts/follow.js"))
+        w:eval_js("clear(); show_hints();")
+        p.text = "Follow:"
+        p:show()
+        i.text = ""
+        i:show()
+        i:focus()
+        i:set_position(-1)
+    end,
+    leave = function (w)
+        if w.eval_js then w:eval_js("clear();") end
+    end,
+    changed = function (w, text)
+        local ret = w:eval_js(string.format("update(%q);", text))
+        w:emit_form_root_active_signal(ret)
+    end,
+})
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/rc.lua	Wed Sep 01 03:53:30 2010 +0100
@@ -0,0 +1,43 @@
+-- Luakit configuration file, more information at http://luakit.org/
+
+-- Load library of useful functions for luakit
+require "lousy"
+
+-- Small util function to print output only when luakit.verbose is true
+function info(...) if luakit.verbose then print(string.format(...)) end end
+
+-- Load users global config
+-- ("$XDG_CONFIG_HOME/luakit/globals.lua" or "/etc/xdg/luakit/globals.lua")
+require "globals"
+
+-- Load users theme
+-- ("$XDG_CONFIG_HOME/luakit/theme.lua" or "/etc/xdg/luakit/theme.lua")
+lousy.theme.init(lousy.util.find_config("theme.lua"))
+
+-- Load users window class
+-- ("$XDG_CONFIG_HOME/luakit/window.lua" or "/etc/xdg/luakit/window.lua")
+require "window"
+
+-- Load users mode configuration
+-- ("$XDG_CONFIG_HOME/luakit/modes.lua" or "/etc/xdg/luakit/modes.lua")
+require "modes"
+
+-- Load users webview class
+-- ("$XDG_CONFIG_HOME/luakit/webview.lua" or "/etc/xdg/luakit/webview.lua")
+require "webview"
+
+-- Load users keybindings
+-- ("$XDG_CONFIG_HOME/luakit/binds.lua" or "/etc/xdg/luakit/binds.lua")
+require "binds"
+
+-- Init formfiller lib
+require "formfiller"
+
+-- Init bookmarks lib
+require "bookmarks"
+bookmarks.load()
+bookmarks.dump_html()
+
+window.new(uris)
+
+-- vim: et:sw=4:ts=8:sts=4:tw=80
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/theme.lua	Wed Sep 01 03:53:30 2010 +0100
@@ -0,0 +1,32 @@
+--------------------------
+-- Default luakit theme --
+--------------------------
+
+theme = {}
+
+-- Default settings
+theme.font = "monospace normal 9"
+theme.fg   = "#fff"
+theme.bg   = "#000"
+
+-- Statusbar specific
+theme.sbar_fg           = "#fff"
+theme.sbar_bg           = "#000"
+theme.loaded_sbar_fg    = "#33AADD"
+
+-- Input bar specific
+theme.ibar_fg           = "#000"
+theme.ibar_bg           = "#fff"
+
+-- Tab label
+theme.tab_fg            = "#888"
+theme.tab_bg            = "#222"
+theme.selected_fg       = "#fff"
+theme.selected_bg       = "#000"
+
+-- Trusted/untrusted ssl colours
+theme.trust_fg          = "#0F0"
+theme.notrust_fg        = "#F00"
+
+return theme
+-- vim: et:sw=4:ts=8:sts=4:tw=80
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/webview.lua	Wed Sep 01 03:53:30 2010 +0100
@@ -0,0 +1,373 @@
+--------------------------
+-- WebKit WebView class --
+--------------------------
+
+-- Webview class table
+webview = {}
+
+-- Table of functions which are called on new webview widgets.
+webview.init_funcs = {
+    -- Set global properties
+    set_global_props = function (view, w)
+        -- Set proxy options
+        local proxy = globals.http_proxy or os.getenv("http_proxy")
+        if proxy then view:set_prop('proxy-uri', proxy) end
+        view:set_prop('user-agent', globals.useragent)
+
+        -- Set ssl options
+        if globals.ssl_strict ~= nil then
+            view:set_prop('ssl-strict', globals.ssl_strict)
+        end
+        if globals.ca_file and os.exists(globals.ca_file) then
+            view:set_prop('ssl-ca-file', globals.ca_file)
+            -- Warning: update the following variable if 'ssl-ca-file' is
+            -- changed anywhere else.
+            w.checking_ssl = true
+        end
+    end,
+
+    -- Update window and tab titles
+    title_update = function (view, w)
+        view:add_signal("property::title", function (v)
+            w:update_tab_labels()
+            if w:is_current(v) then
+                w:update_win_title()
+            end
+        end)
+    end,
+
+    -- Update uri label in statusbar
+    uri_update = function (view, w)
+        view:add_signal("property::uri", function (v)
+            w:update_tab_labels()
+            if w:is_current(v) then
+                w:update_uri(v)
+            end
+        end)
+    end,
+
+    -- Update scroll widget
+    scroll_update = function (view, w)
+        view:add_signal("expose", function (v)
+            if w:is_current(v) then
+                w:update_scroll(v)
+            end
+        end)
+    end,
+
+    -- Update progress widget
+    progress_update = function (view, w)
+        for _, sig in ipairs({"load-status", "property::progress"}) do
+            view:add_signal(sig, function (v)
+                if w:is_current(v) then
+                    w:update_progress(v)
+                    w:update_ssl(v)
+                end
+            end)
+        end
+    end,
+
+    -- Display hovered link in statusbar
+    link_hover_display = function (view, w)
+        view:add_signal("link-hover", function (v, link)
+            if w:is_current(v) and link then
+                w.sbar.l.uri.text = "Link: " .. lousy.util.escape(link)
+            end
+        end)
+        view:add_signal("link-unhover", function (v)
+            if w:is_current(v) then
+                w:update_uri(v)
+            end
+        end)
+    end,
+
+    -- Clicking a form field automatically enters insert mode
+    form_insert_mode = function (view, w)
+        view:add_signal("form-active", function ()
+            (w.search_state or {}).marker = nil
+            w:set_mode("insert")
+        end)
+        view:add_signal("root-active", function ()
+            (w.search_state or {}).marker = nil
+            w:set_mode()
+        end)
+    end,
+
+    -- Stop key events hitting the webview if the user isn't in insert mode
+    mode_key_filter = function (view, w)
+        view:add_signal("key-press", function ()
+            if not w:is_mode("insert") then return true end
+        end)
+    end,
+
+    -- Try to match a button event to a users button binding else let the
+    -- press hit the webview.
+    button_bind_match = function (view, w)
+        -- Match button press
+        view:add_signal("button-release", function (v, mods, button)
+            (w.search_state or {}).marker = nil
+            if w:hit(mods, button) then return true end
+        end)
+    end,
+
+    -- Reset the mode on navigation
+    mode_reset_on_nav = function (view, w)
+        view:add_signal("load-status", function (v, status)
+            if w:is_current(v) and status == "provisional" then w:set_mode() end
+        end)
+    end,
+
+    -- Domain properties
+    domain_properties = function (view, w)
+        view:add_signal("load-status", function (v, status)
+            if status ~= "provisional" then return end
+            local domain = (v.uri and string.match(v.uri, "^%a+://([^/]*)/?")) or "about:blank"
+            if string.match(domain, "^www.") then domain = string.sub(domain, 5) end
+            local props = lousy.util.table.join(domain_props.all or {}, domain_props[domain] or {})
+            for k, v in pairs(props) do
+                info("Domain prop: %s = %s (%s)", k, tostring(v), domain)
+                view:set_prop(k, v)
+            end
+        end)
+    end,
+
+    -- Action to take on mime type decision request.
+    mime_decision = function (view, w)
+        -- Return true to accept or false to reject from this signal.
+        view:add_signal("mime-type-decision", function (v, link, mime)
+            info("Requested link: %s (%s)", link, mime)
+            -- i.e. block binary files like *.exe
+            --if mime == "application/octet-stream" then
+            --    return false
+            --end
+        end)
+    end,
+
+    -- Action to take on window open request.
+    window_decision = function (view, w)
+        -- 'link' contains the download link
+        -- 'reason' contains the reason of the request (i.e. "link-clicked")
+        -- return TRUE to handle the request by yourself or FALSE to proceed
+        -- with default behaviour
+        view:add_signal("new-window-decision", function (v, link, reason)
+            info("New window decision: %s (%s)", link, reason)
+            if reason == "link-clicked" then
+                window.new({ link })
+                return true
+            end
+            w:new_tab(link)
+        end)
+    end,
+
+    create_webview = function (view, w)
+        -- Return a newly created webview in a new tab
+        view:add_signal("create-web-view", function (v)
+            return w:new_tab()
+        end)
+    end,
+
+    -- Action to take on download request.
+    download_request = function (view, w)
+        -- 'link' contains the download link
+        -- 'filename' contains the suggested filename (from server or webkit)
+        view:add_signal("download-request", function (v, link, filename)
+            if not filename then return end
+            -- Make download dir
+            os.execute(string.format("mkdir -p %q", globals.download_dir))
+            local dl = globals.download_dir .. "/" .. filename
+            local wget = string.format("wget -q %q -O %q", link, dl)
+            info("Launching: %s", wget)
+            luakit.spawn(wget)
+        end)
+    end,
+
+    -- Creates context menu popup from table (and nested tables).
+    -- Use `true` for menu separators.
+    populate_popup = function (view, w)
+        view:add_signal("populate-popup", function (v)
+            return {
+                true,
+                { "_Toggle Source", function () w:toggle_source() end },
+                { "_Zoom", {
+                    { "Zoom _In",    function () w:zoom_in(globals.zoom_step) end },
+                    { "Zoom _Out",   function () w:zoom_out(globals.zoom_step) end },
+                    true,
+                    { "Zoom _Reset", function () w:zoom_reset() end }, }, },
+            }
+        end)
+    end,
+
+    -- Action to take on resource request.
+    resource_request_decision = function (view, w)
+        view:add_signal("resource-request-starting", function(v, uri)
+            if luakit.verbose then print("Requesting: "..uri) end
+            -- Return false to cancel the request.
+        end)
+    end,
+}
+
+-- These methods are present when you index a window instance and no window
+-- method is found in `window.methods`. The window then checks if there is an
+-- active webview and calls the following methods with the given view instance
+-- as the first argument. All methods must take `view` & `w` as the first two
+-- arguments.
+webview.methods = {
+    reload = function (view, w)
+        view:reload()
+    end,
+
+    -- Property functions
+    get = function (view, w, k)
+        return view:get_prop(k)
+    end,
+
+    set = function (view, w, k, v)
+        view:set_prop(k, v)
+    end,
+
+    -- evaluate javascript code and return string result
+    eval_js = function (view, w, script, file)
+        return view:eval_js(script, file or "(inline)")
+    end,
+
+    -- evaluate javascript code from file and return string result
+    eval_js_from_file = function (view, w, file)
+        local fh, err = io.open(file)
+        if not fh then return error(err) end
+        local script = fh:read("*a")
+        fh:close()
+        return view:eval_js(script, file)
+    end,
+
+    -- close the current tab
+    close_tab = function (view, w)
+        w.tabs:remove(view)
+        view.uri = "about:blank"
+        view:destroy()
+        w:update_tab_count()
+        w:update_tab_labels()
+    end,
+
+    -- Toggle source view
+    toggle_source = function (view, w, show)
+        if show == nil then show = not view:get_view_source() end
+        view:set_view_source(show)
+    end,
+
+    -- Zoom functions
+    zoom_in = function (view, w, step)
+        view:set_prop("zoom-level", view:get_prop("zoom-level") + step)
+    end,
+
+    zoom_out = function (view, w, step)
+        local value = view:get_prop("zoom-level") - step
+        view:set_prop("zoom-level", ((value > 0.01) and value) or 0.01)
+    end,
+
+    zoom_reset = function (view, w)
+        view:set_prop("zoom-level", 1.0)
+    end,
+
+    -- Searching functions
+    start_search = function (view, w, text)
+        if string.match(text, "^[\?\/]") then
+            w:set_mode("search")
+            local i = w.ibar.input
+            i.text = text
+            i:focus()
+            i:set_position(-1)
+        else
+            return error("invalid search term, must start with '?' or '/'")
+        end
+    end,
+
+    search = function (view, w, text, forward)
+        if forward == nil then forward = true end
+
+        -- Get search state (or new state)
+        if not w.search_state then w.search_state = {} end
+        local s = w.search_state
+
+        -- Get search term
+        text = text or s.last_search
+        if not text or #text == 0 then
+            return w:clear_search()
+        end
+        s.last_search = text
+
+        if s.forward == nil then
+            -- Haven't searched before, save some state.
+            s.forward = forward
+            s.marker = view:get_scroll_vert()
+        else
+            -- Invert direction if originally searching in reverse
+            forward = (s.forward == forward)
+        end
+
+        view:search(text, false, forward, true);
+    end,
+
+    clear_search = function (view, w)
+        view:clear_search()
+        w.search_state = {}
+    end,
+
+    -- Webview scroll functions
+    scroll_vert = function (view, w, value)
+        local cur, max = view:get_scroll_vert()
+        if type(value) == "string" then
+            value = lousy.util.parse_scroll(cur, max, value)
+        end
+        view:set_scroll_vert(value)
+    end,
+
+    scroll_horiz = function (view, w, value)
+        local cur, max = view:get_scroll_horiz()
+        if type(value) == "string" then
+            value = lousy.util.parse_scroll(cur, max, value)
+        end
+        view:set_scroll_horiz(value)
+    end,
+
+    -- vertical scroll of a multiple of the view_size
+    scroll_page = function (view, w, value)
+        local cur, max, size = view:get_scroll_vert()
+        view:set_scroll_vert(cur + (size * value))
+    end,
+
+    -- History traversing functions
+    back = function (view, w, n)
+        view:go_back(n or 1)
+    end,
+
+    forward = function (view, w, n)
+        view:go_forward(n or 1)
+    end,
+}
+
+function webview.new(w, uri)
+    local view = widget{type = "webview"}
+
+    -- Call webview init functions
+    for k, func in pairs(webview.init_funcs) do
+        func(view, w)
+    end
+
+    if uri then view.uri = uri end
+    view.show_scrollbars = false
+    return view
+end
+
+-- Insert webview method lookup on window structure
+table.insert(window.indexes, 1, function (w, k)
+    -- Get current webview
+    local view = w.tabs:atindex(w.tabs:current())
+    if not view then return end
+    -- Lookup webview method
+    local func = webview.methods[k]
+    if not func then return end
+    -- Return webview method wrapper function
+    return function (_, ...) return func(view, w, ...) end
+end)
+
+-- vim: et:sw=4:ts=8:sts=4:tw=80
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/window.lua	Wed Sep 01 03:53:30 2010 +0100
@@ -0,0 +1,638 @@
+------------------
+-- Window class --
+------------------
+
+-- Window class table
+window = {}
+
+-- Widget construction aliases
+local function entry()    return widget{type="entry"}    end
+local function eventbox() return widget{type="eventbox"} end
+local function hbox()     return widget{type="hbox"}     end
+local function label()    return widget{type="label"}    end
+local function notebook() return widget{type="notebook"} end
+local function vbox()     return widget{type="vbox"}     end
+
+-- Build and pack window widgets
+function window.build()
+    -- Create a table for widgets and state variables for a window
+    local w = {
+        win    = widget{type="window"},
+        ebox   = eventbox(),
+        layout = vbox(),
+        tabs   = notebook(),
+        -- Tab bar widgets
+        tbar = {
+            layout = hbox(),
+            ebox   = eventbox(),
+            titles = { },
+        },
+        -- Status bar widgets
+        sbar = {
+            layout = hbox(),
+            ebox   = eventbox(),
+            -- Left aligned widgets
+            l = {
+                layout = hbox(),
+                ebox   = eventbox(),
+                uri    = label(),
+                loaded = label(),
+            },
+            -- Fills space between the left and right aligned widgets
+            sep = eventbox(),
+            -- Right aligned widgets
+            r = {
+                layout = hbox(),
+                ebox   = eventbox(),
+                buf    = label(),
+                ssl    = label(),
+                tabi   = label(),
+                scroll = label(),
+            },
+        },
+        -- Input bar widgets
+        ibar = {
+            layout  = hbox(),
+            ebox    = eventbox(),
+            prompt  = label(),
+            input   = entry(),
+        },
+    }
+
+    -- Assemble window
+    w.ebox:set_child(w.layout)
+    w.win:set_child(w.ebox)
+
+    -- Pack tab bar
+    local t = w.tbar
+    t.ebox:set_child(t.layout, false, false, 0)
+    w.layout:pack_start(t.ebox, false, false, 0)
+
+    -- Pack notebook
+    w.layout:pack_start(w.tabs, true, true, 0)
+
+    -- Pack left-aligned statusbar elements
+    local l = w.sbar.l
+    l.layout:pack_start(l.uri,    false, false, 0)
+    l.layout:pack_start(l.loaded, false, false, 0)
+    l.ebox:set_child(l.layout)
+
+    -- Pack right-aligned statusbar elements
+    local r = w.sbar.r
+    r.layout:pack_start(r.buf,    false, false, 0)
+    r.layout:pack_start(r.ssl,    false, false, 0)
+    r.layout:pack_start(r.tabi,   false, false, 0)
+    r.layout:pack_start(r.scroll, false, false, 0)
+    r.ebox:set_child(r.layout)
+
+    -- Pack status bar elements
+    local s = w.sbar
+    s.layout:pack_start(l.ebox,   false, false, 0)
+    s.layout:pack_start(s.sep,    true,  true,  0)
+    s.layout:pack_start(r.ebox,   false, false, 0)
+    s.ebox:set_child(s.layout)
+    w.layout:pack_start(s.ebox,   false, false, 0)
+
+    -- Pack input bar
+    local i = w.ibar
+    i.layout:pack_start(i.prompt, false, false, 0)
+    i.layout:pack_start(i.input,  true,  true,  0)
+    i.ebox:set_child(i.layout)
+    w.layout:pack_start(i.ebox,    false, false, 0)
+
+    -- Other settings
+    i.input.show_frame = false
+    w.tabs.show_tabs = false
+    l.loaded:hide()
+    l.uri.selectable = true
+    r.ssl:hide()
+
+    return w
+end
+
+-- Table of functions to call on window creation. Normally used to add signal
+-- handlers to the new windows widgets.
+window.init_funcs = {
+    -- Attach notebook widget signals
+    notebook_signals = function (w)
+        w.tabs:add_signal("page-added", function (nbook, view, idx)
+            w:update_tab_count(idx)
+            w:update_tab_labels()
+        end)
+        w.tabs:add_signal("switch-page", function (nbook, view, idx)
+            w:set_mode()
+            w:update_tab_count(idx)
+            w:update_win_title(view)
+            w:update_uri(view)
+            w:update_progress(view)
+            w:update_tab_labels(idx)
+            w:update_buf()
+            w:update_ssl(view)
+        end)
+    end,
+
+    last_win_check = function (w)
+        w.win:add_signal("destroy", function ()
+            -- call the quit function if this was the last window left
+            if #luakit.windows == 0 then luakit.quit() end
+        end)
+    end,
+
+    key_press_match = function (w)
+        w.win:add_signal("key-press", function (_, mods, key)
+            -- Reset command line completion
+            if w:get_mode() == "command" and key ~= "Tab" and w.compl_start then
+                w:update_uri()
+                w.compl_index = 0
+            end
+
+            if w:hit(mods, key) then
+                return true
+            end
+        end)
+    end,
+
+    apply_window_theme = function (w)
+        local theme = lousy.theme.get()
+        local s, i  = w.sbar, w.ibar
+
+        -- Set foregrounds
+        for wi, v in pairs({
+            [s.l.uri]    = theme.uri_sbar_fg,
+            [s.l.loaded] = theme.loaded_sbar_fg,
+            [s.r.buf]    = theme.buf_sbar_fg,
+            [s.r.tabi]   = theme.tabi_sbar_fg,
+            [s.r.scroll] = theme.scroll_sbar_fg,
+            [i.prompt]   = theme.prompt_ibar_fg,
+            [i.input]    = theme.input_ibar_fg,
+        }) do wi.fg = v end
+
+        -- Set backgrounds
+        for wi, v in pairs({
+            [s.l.ebox]   = theme.sbar_bg,
+            [s.r.ebox]   = theme.sbar_bg,
+            [s.sep]      = theme.sbar_bg,
+            [s.ebox]     = theme.sbar_bg,
+            [i.ebox]     = theme.ibar_bg,
+            [i.input]    = theme.input_ibar_bg,
+        }) do wi.bg = v end
+
+        -- Set fonts
+        for wi, v in pairs({
+            [s.l.uri]    = theme.uri_sbar_font,
+            [s.l.loaded] = theme.loaded_sbar_font,
+            [s.r.buf]    = theme.buf_sbar_font,
+            [s.r.ssl]    = theme.ssl_sbar_font,
+            [s.r.tabi]   = theme.tabi_sbar_font,
+            [s.r.scroll] = theme.scroll_sbar_font,
+            [i.prompt]   = theme.prompt_ibar_font,
+            [i.input]    = theme.input_ibar_font,
+        }) do wi.font = v end
+    end,
+}
+
+-- Helper functions which operate on the window widgets or structure.
+window.methods = {
+    -- Return the widget in the currently active tab
+    get_current = function (w)       return w.tabs:atindex(w.tabs:current())       end,
+    -- Check if given widget is the widget in the currently active tab
+    is_current  = function (w, wi)   return w.tabs:indexof(wi) == w.tabs:current() end,
+
+    get_tab_title = function (w, view)
+        if not view then view = w:get_current() end
+        return view:get_prop("title") or view.uri or "(Untitled)"
+    end,
+
+    new_tab = function (w, uri)
+        local view = webview.new(w, uri)
+        w.tabs:append(view)
+        w:update_tab_count()
+        return view
+    end,
+
+    -- Wrapper around the bind plugin's hit method
+    hit = function (w, mods, key)
+        local caught, newbuf = lousy.bind.hit(w.binds or {}, mods, key, w.buffer, w:is_mode("normal"), w)
+        if w.win then
+            w.buffer = newbuf
+            w:update_buf()
+        end
+        return caught
+    end,
+
+    -- Wrapper around the bind plugin's match_cmd method
+    match_cmd = function (w, buffer)
+        return lousy.bind.match_cmd(binds.commands, buffer, w)
+    end,
+
+    -- enter command or characters into command line
+    enter_cmd = function (w, cmd)
+        local i = w.ibar.input
+        w:set_mode("command")
+        i.text = cmd
+        i:set_position(-1)
+    end,
+
+    -- insert a string into the command line at the current cursor position
+    insert_cmd = function (w, str)
+        if not str then return end
+        local i = w.ibar.input
+        local text = i.text
+        local pos = i:get_position()
+        local left, right = string.sub(text, 1, pos), string.sub(text, pos+1)
+        i.text = left .. str .. right
+        i:set_position(pos + #str + 1)
+    end,
+
+    -- Command line completion of available commands
+    cmd_completion = function (w)
+        local i = w.ibar.input
+        local s = w.sbar.l.uri
+        local cmpl = {}
+
+        -- Get last completion (is reset on key press other than <Tab>)
+        if not w.compl_start or w.compl_index == 0 then
+            w.compl_start = "^" .. string.sub(i.text, 2)
+            w.compl_index = 1
+        end
+
+        -- Get suitable commands
+        for _, b in ipairs(binds.commands) do
+            for _, c in pairs(b.commands) do
+                if c and string.match(c, w.compl_start) then
+                    table.insert(cmpl, c)
+                end
+            end
+        end
+
+        table.sort(cmpl)
+
+        if #cmpl > 0 then
+            local text = ""
+            for index, comp in pairs(cmpl) do
+                if index == w.compl_index then
+                    i.text = ":" .. comp .. " "
+                    i:set_position(-1)
+                end
+                if text ~= "" then
+                    text = text .. " | "
+                end
+                text = text .. comp
+            end
+
+            -- cycle through all possible completions
+            if w.compl_index == #cmpl then
+                w.compl_index = 1
+            else
+                w.compl_index = w.compl_index + 1
+            end
+            s.text = lousy.util.escape(text)
+        end
+    end,
+
+    del_word = function (w)
+        local i = w.ibar.input
+        local text = i.text
+        local pos = i:get_position()
+        if text and #text > 1 and pos > 1 then
+            local left, right = string.sub(text, 2, pos), string.sub(text, pos+1)
+            if not string.find(left, "%s") then
+                left = ""
+            elseif string.find(left, "%w+%s*$") then
+                left = string.sub(left, 0, string.find(left, "%w+%s*$") - 1)
+            elseif string.find(left, "%W+%s*$") then
+                left = string.sub(left, 0, string.find(left, "%W+%s*$") - 1)
+            end
+            i.text =  string.sub(text, 1, 1) .. left .. right
+            i:set_position(#left + 2)
+        end
+    end,
+
+    del_line = function (w)
+        local i = w.ibar.input
+        if i.text ~= ":" then
+            i.text = ":"
+            i:set_position(-1)
+        end
+    end,
+
+    -- Search history adding
+    srch_hist_add = function (w, srch)
+        if not w.srch_hist then w.srch_hist = {} end
+        -- Check overflow
+        local max_hist = globals.max_srch_history or 100
+        if #w.srch_hist > (max_hist + 5) then
+            while #w.srch_hist > max_hist do
+                table.remove(w.srch_hist, 1)
+            end
+        end
+        table.insert(w.srch_hist, srch)
+    end,
+
+    -- Search history traversing
+    srch_hist_prev = function (w)
+        if not w.srch_hist then w.srch_hist = {} end
+        if not w.srch_hist_cursor then
+            w.srch_hist_cursor = #w.srch_hist + 1
+            w.srch_hist_current = w.ibar.input.text
+        end
+        local c = w.srch_hist_cursor - 1
+        if w.srch_hist[c] then
+            w.srch_hist_cursor = c
+            w.ibar.input.text = w.srch_hist[c]
+            w.ibar.input:set_position(-1)
+        end
+    end,
+
+    srch_hist_next = function (w)
+        if not w.srch_hist then w.srch_hist = {} end
+        local c = (w.srch_hist_cursor or #w.srch_hist) + 1
+        if w.srch_hist[c] then
+            w.srch_hist_cursor = c
+            w.ibar.input.text = w.srch_hist[c]
+            w.ibar.input:set_position(-1)
+        elseif w.srch_hist_current then
+            w.srch_hist_cursor = nil
+            w.ibar.input.text = w.srch_hist_current
+            w.ibar.input:set_position(-1)
+        end
+    end,
+
+    -- Command history adding
+    cmd_hist_add = function (w, cmd)
+        if not w.cmd_hist then w.cmd_hist = {} end
+        -- Make sure history doesn't overflow
+        local max_hist = globals.max_cmd_hist or 100
+        if #w.cmd_hist > (max_hist + 5) then
+            while #w.cmd_hist > max_hist do
+                table.remove(w.cmd_hist, 1)
+            end
+        end
+        table.insert(w.cmd_hist, cmd)
+    end,
+
+    -- Command history traversing
+    cmd_hist_prev = function (w)
+        if not w.cmd_hist then w.cmd_hist = {} end
+        if not w.cmd_hist_cursor then
+            w.cmd_hist_cursor = #w.cmd_hist + 1
+            w.cmd_hist_current = w.ibar.input.text
+        end
+        local c = w.cmd_hist_cursor - 1
+        if w.cmd_hist[c] then
+            w.cmd_hist_cursor = c
+            w.ibar.input.text = w.cmd_hist[c]
+            w.ibar.input:set_position(-1)
+        end
+    end,
+
+    cmd_hist_next = function (w)
+        if not w.cmd_hist then w.cmd_hist = {} end
+        local c = (w.cmd_hist_cursor or #w.cmd_hist) + 1
+        if w.cmd_hist[c] then
+            w.cmd_hist_cursor = c
+            w.ibar.input.text = w.cmd_hist[c]
+            w.ibar.input:set_position(-1)
+        elseif w.cmd_hist_current then
+            w.cmd_hist_cursor = nil
+            w.ibar.input.text = w.cmd_hist_current
+            w.ibar.input:set_position(-1)
+        end
+    end,
+
+    -- GUI content update functions
+    update_tab_count = function (w, i, t)
+        w.sbar.r.tabi.text = string.format("[%d/%d]", i or w.tabs:current(), t or w.tabs:count())
+    end,
+
+    update_win_title = function (w, view)
+        if not view then view = w:get_current() end
+        local title = view:get_prop("title")
+        local uri = view.uri
+        if not title and not uri then
+            w.win.title = "luakit"
+        else
+            w.win.title = (title or "luakit") .. " - " .. (uri or "about:blank")
+        end
+    end,
+
+    update_uri = function (w, view, uri)
+        if not view then view = w:get_current() end
+        w.sbar.l.uri.text = lousy.util.escape((uri or (view and view.uri) or "about:blank"))
+    end,
+
+    update_progress = function (w, view, p)
+        if not view then view = w:get_current() end
+        if not p then p = view:get_prop("progress") end
+        local loaded = w.sbar.l.loaded
+        if not view:loading() or p == 1 then
+            loaded:hide()
+        else
+            loaded:show()
+            loaded.text = string.format("(%d%%)", p * 100)
+        end
+    end,
+
+    update_scroll = function (w, view)
+        if not view then view = w:get_current() end
+        local scroll = w.sbar.r.scroll
+        if view then
+            local val, max = view:get_scroll_vert()
+            if max == 0 then val = "All"
+            elseif val == 0 then val = "Top"
+            elseif val == max then val = "Bot"
+            else val = string.format("%2d%%", (val/max) * 100)
+            end
+            if scroll.text ~= val then scroll.text = val end
+            scroll:show()
+        else
+            scroll:hide()
+        end
+    end,
+
+    update_ssl = function (w, view)
+        if not view then view = w:get_current() end
+        local trusted = view:ssl_trusted()
+        local theme = lousy.theme.get()
+        local ssl = w.sbar.r.ssl
+        if trusted ~= nil and not w.checking_ssl then
+            ssl.fg = theme.notrust_fg
+            ssl.text = "(nocheck)"
+            ssl:show()
+        elseif trusted == true then
+            ssl.fg = theme.trust_fg
+            ssl.text = "(trust)"
+            ssl:show()
+        elseif trusted == false then
+            ssl.fg = theme.notrust_fg
+            ssl.text = "(notrust)"
+            ssl:show()
+        else
+            ssl:hide()
+        end
+    end,
+
+    update_buf = function (w)
+        local buf = w.sbar.r.buf
+        if w.buffer then
+            buf.text = lousy.util.escape(string.format(" %-3s", w.buffer))
+            buf:show()
+        else
+            buf:hide()
+        end
+    end,
+
+    update_binds = function (w, mode)
+        -- Generate the list of active key & buffer binds for this mode
+        w.binds = lousy.util.table.join(binds.mode_binds[mode], binds.mode_binds.all)
+        -- Clear & hide buffer
+        w.buffer = nil
+        w:update_buf()
+    end,
+
+    -- Tab label functions
+    -- TODO: Move these functions into a module (I.e. lousy.widget.tablist)
+    make_tab_label = function (w, pos)
+        local theme = lousy.theme.get()
+        local t = {
+            label  = label(),
+            sep    = eventbox(),
+            ebox   = eventbox(),
+            layout = hbox(),
+        }
+        t.label.font = theme.tab_font
+        t.label:set_width(1)
+        t.layout:pack_start(t.label, true,  true, 0)
+        t.layout:pack_start(t.sep,   false,  false, 0)
+        t.ebox:set_child(t.layout)
+        t.ebox:add_signal("button-release", function (e, m, b)
+            if b == 1 then
+                w.tabs:switch(pos)
+                return true
+            elseif b == 2 then
+                w:close_tab(w.tabs:atindex(pos))
+                return true
+            end
+        end)
+        return t
+    end,
+
+    destroy_tab_label = function (w, t)
+        if not t then t = table.remove(w.tbar.titles) end
+        -- Destroy widgets without their own windows first (I.e. labels)
+        for _, wi in ipairs{ t.label, t.sep, t.ebox, t.layout } do wi:destroy() end
+    end,
+
+    update_tab_labels = function (w, current)
+        local tb = w.tbar
+        local count, current = w.tabs:count(), current or w.tabs:current()
+        tb.ebox:hide()
+
+        -- Leave the tablist hidden if there is only one tab open
+        if count <= 1 then
+            return nil
+        end
+
+        if count ~= #tb.titles then
+            -- Grow the number of labels
+            while count > #tb.titles do
+                local t = w:make_tab_label(#tb.titles + 1)
+                tb.layout:pack_start(t.ebox, true, true,  0)
+                table.insert(tb.titles, t)
+            end
+            -- Prune number of labels
+            while count < #tb.titles do
+                w:destroy_tab_label()
+            end
+        end
+
+        if count ~= 0 then
+            for i = 1, count do
+                local view = w.tabs:atindex(i)
+                local t = tb.titles[i]
+                local title = " " ..i.. " "..w:get_tab_title(view)
+                t.label.text = lousy.util.escape(string.format("%-40s", title))
+                w:apply_tablabel_theme(t, i == current)
+            end
+        end
+        tb.ebox:show()
+    end,
+
+    -- Theme functions
+    apply_tablabel_theme = function (w, t, selected)
+        local theme = lousy.theme.get()
+        selected = (selected and "_selected") or ""
+        t.label.fg = theme[string.format("tab%s_fg", selected)]
+        t.ebox.bg = theme[string.format("tab%s_bg", selected)]
+    end,
+
+    close_win = function (w)
+        -- Close all tabs
+        while w.tabs:count() ~= 0 do
+            w:close_tab()
+        end
+
+        -- Recursively remove widgets from window
+        local children = lousy.util.recursive_remove(w.win)
+        -- Destroy all widgets
+        for i, c in ipairs(lousy.util.table.join(children, {w.win})) do
+            if c.hide then c:hide() end
+            c:destroy()
+        end
+
+        -- Clear window struct
+        w = setmetatable(w, {})
+        for k, _ in pairs(w) do w[k] = nil end
+
+        -- Quit if closed last window
+        if #luakit.windows == 0 then luakit.quit() end
+    end,
+}
+
+-- Ordered list of class index functions. Other classes (E.g. webview) are able
+-- to add their own index functions to this list.
+window.indexes = {
+    -- Find function in window.methods first
+    function (w, k) return window.methods[k] end
+}
+
+-- Create new window
+function window.new(uris)
+    local w = window.build()
+
+    -- Set window metatable
+    setmetatable(w, {
+        __index = function (_, k)
+            -- Check widget structure first
+            local v = rawget(w, k)
+            if v then return v end
+            -- Call each window index function
+            for _, index in ipairs(window.indexes) do
+                v = index(w, k)
+                if v then return v end
+            end
+        end,
+    })
+
+    -- Call window init functions
+    for _, func in pairs(window.init_funcs) do
+        func(w)
+    end
+
+    -- Populate notebook with tabs
+    for _, uri in ipairs(uris or {}) do
+        w:new_tab(uri)
+    end
+
+    -- Make sure something is loaded
+    if w.tabs:count() == 0 then
+        w:new_tab(globals.homepage)
+    end
+
+    -- Set initial mode
+    w:set_mode()
+
+    return w
+end
+
+-- vim: et:sw=4:ts=8:sts=4:tw=80

mercurial