Skip to content
Browse files

Merge branch 'develop'

  • Loading branch information...
2 parents 985bfd8 + 5004307 commit e982ac6d2b2e576c4bcfa586b9e5061a9fc8879f @mason-larobina mason-larobina committed Aug 13, 2010
Showing with 969 additions and 182 deletions.
  1. +15 −7 AUTHORS
  2. +6 −6 COPYING
  3. +0 −21 COPYING.MIT
  4. +3 −1 Makefile
  5. +1 −1 common/luaclass.c
  6. +1 −1 common/luaclass.h
  7. +1 −1 common/lualib.h
  8. +1 −1 common/luaobject.c
  9. +1 −1 common/luaobject.h
  10. +1 −1 common/signal.h
  11. +3 −0 common/tokenize.gperf
  12. +9 −6 common/util.c
  13. +1 −9 common/util.h
  14. +1 −1 config.mk
  15. +3 −1 globalconf.h.in
  16. +2 −0 lib/bind.lua
  17. +2 −0 lib/mode.lua
  18. +40 −1 lib/util.lua
  19. +45 −3 luah.c
  20. +1 −1 luah.h
  21. +8 −17 luakit.c
  22. +1 −1 luakit.h
  23. +315 −25 rc.lua
  24. +246 −0 scripts/follow.js
  25. +1 −1 widget.c
  26. +1 −1 widget.h
  27. +1 −1 widgets/box.c
  28. +1 −1 widgets/common.c
  29. +1 −1 widgets/common.h
  30. +1 −1 widgets/entry.c
  31. +1 −1 widgets/eventbox.c
  32. +1 −1 widgets/label.c
  33. +1 −1 widgets/notebook.c
  34. +1 −1 widgets/textbutton.c
  35. +251 −65 widgets/webview.c
  36. +1 −1 widgets/window.c
View
22 AUTHORS
@@ -1,16 +1,24 @@
-Luakit project:
- Mason Larobina (mason-l) <mason.larobina<AT>gmail.com> 2010
+Authors in the luakit project:
+ Clint Adams (Clint) <schizo<AT>debian.org> 2010
+ Gregor Uhlenheuer (kongo2002) <kongo2002<AT>googlemail.com> 2010
+ Mason Larobina (mason-l) <mason.larobina<AT>gmail.com> 2010
+ Pawel Zuzelski (pawelz) <pawelz<AT>pld-linux.org> 2010
+
+Author of `scripts/follow.js`:
+ Fabian Streitel <karottenreibe<AT>gmail.com> 2010
Inherited authors from the awesomewm project:
- Julien Danjou <julien<AT>danjou.info> 2007-2009
- Pierre Habouzit <madcoder<AT>debian.org> 2008
+ Julien Danjou <julien<AT>danjou.info> 2007-2009
+ Pierre Habouzit <madcoder<AT>debian.org> 2008
Inherited authors from the uzbl project:
- Robert Manea (robm) <rob.manea<AT>gmail.com> 2009-2010
- Dieter Plaetinck (Dieter@be) <dieter<AT>plaetinck.be> 2009-2010
+ Dequis <dx<AT>dxzone.com.ar> 2009
+ Dieter Plaetinck (Dieter@be) <dieter<AT>plaetinck.be> 2009-2010
+ Robert Manea (robm) <rob.manea<AT>gmail.com> 2009-2010
+ Simon Lipp (sloonz) <sloonz<AT>gmail.com> 2010
Inherited authors from the surf project:
- Enno Boland <g<AT>s01.de> 2009
+ Enno Boland (tox) <tox<AT>s01.de> 2009-2010
If you believe you should be in this file or notice that I have missed an
attribution to somebody else please contact me (Mason) or email me a patch
View
12 COPYING
@@ -1,13 +1,13 @@
See AUTHORS file for list of copyright holders.
-Several source files are based on files in the surf micro-browser project and
-those sections are licensed under the MIT licence (see COPYING.MIT).
+Several source files are based on files in the surf micro-browser project
+and those sections have been re-licensed under the GPLv3 licence
+(see COPYING.GPLv3).
-Several source files are based on files in the uzbl micro-browser project and
-those sections and are licensed under the GPLv3 license (see COPYING.GPLv3).
+Several source files are based on files in the uzbl micro-browser project
+and those sections are licensed under the GPLv3 license (see COPYING.GPLv3).
Several source files are based on files in the awesome window-manager project
and those sections are licensed under the GPLv3 licence (see COPYING.GPLv3).
-Everything else is GPLv3 (see COPYING.GPLv3) unless otherwise mentioned at
-the beginning of the file.
+Everything else is GPLv3 (see COPYING.GPLv3).
View
21 COPYING.MIT
@@ -1,21 +0,0 @@
-MIT/X Consortium License
-
-(C) 2009 Enno Boland <gottox@s01.de>
-
-Permission is hereby granted, free of charge, to any person obtaining a
-copy of this software and associated documentation files (the "Software"),
-to deal in the Software without restriction, including without limitation
-the rights to use, copy, modify, merge, publish, distribute, sublicense,
-and/or sell copies of the Software, and to permit persons to whom the
-Software is furnished to do so, subject to the following conditions:
-
-The above copyright notice and this permission notice shall be included in
-all copies or substantial portions of the Software.
-
-THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
-THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
-FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
-DEALINGS IN THE SOFTWARE.
View
4 Makefile
@@ -35,7 +35,7 @@ ${GSRC} ${GHEAD}: ${GPERF}
@${CC} -c ${CFLAGS} ${CPPFLAGS} $< -o $@
globalconf.h: globalconf.h.in
- sed 's#LUAKIT_LUA_LIB_PATH .*#LUAKIT_LUA_LIB_PATH "$(PREFIX)/share/luakit/lib"#' globalconf.h.in > globalconf.h
+ sed 's#LUAKIT_INSTALL_PATH .*#LUAKIT_INSTALL_PATH "$(PREFIX)/share/luakit"#' globalconf.h.in > globalconf.h
${OBJS}: ${HEADS} config.mk globalconf.h
@@ -52,6 +52,8 @@ install:
install -m644 README.md AUTHORS COPYING* $(DOCDIR)
cp -r lib/ $(INSTALLDIR)/share/luakit/
chmod -R 755 $(INSTALLDIR)/share/luakit/lib/
+ cp -r scripts/ $(INSTALLDIR)/share/luakit/
+ chmod -R 755 $(INSTALLDIR)/share/luakit/scripts/
install -D luakit $(INSTALLDIR)/bin/luakit
install -d $(DESTDIR)/etc/xdg/luakit/
install -D rc.lua $(DESTDIR)/etc/xdg/luakit/rc.lua
View
2 common/luaclass.c
@@ -314,4 +314,4 @@ luaH_class_new(lua_State *L, lua_class_t *lua_class) {
return 1;
}
-// vim: ft=c:et:sw=4:ts=8:sts=4:enc=utf-8:tw=80
+// vim: ft=c:et:sw=4:ts=8:sts=4:tw=80
View
2 common/luaclass.h
@@ -121,4 +121,4 @@ luaH_checkudataornil(lua_State *L, gint udx, lua_class_t *class) {
#endif
-// vim: ft=c:et:sw=4:ts=8:sts=4:enc=utf-8:tw=80
+// vim: ft=c:et:sw=4:ts=8:sts=4:tw=80
View
2 common/lualib.h
@@ -118,4 +118,4 @@ luaH_dofunction(lua_State *L, gint nargs, gint nret) {
#endif
-// vim: ft=c:et:sw=4:ts=8:sts=4:enc=utf-8:tw=80
+// vim: ft=c:et:sw=4:ts=8:sts=4:tw=80
View
2 common/luaobject.c
@@ -296,4 +296,4 @@ luaH_object_gc(lua_State *L) {
return 0;
}
-// vim: ft=c:et:sw=4:ts=8:sts=4:enc=utf-8:tw=80
+// vim: ft=c:et:sw=4:ts=8:sts=4:tw=80
View
2 common/luaobject.h
@@ -193,4 +193,4 @@ gint luaH_object_gc(lua_State *);
#endif
-// vim: ft=c:et:sw=4:ts=8:sts=4:enc=utf-8:tw=80
+// vim: ft=c:et:sw=4:ts=8:sts=4:tw=80
View
2 common/signal.h
@@ -114,4 +114,4 @@ signal_remove(signal_t *signals, const gchar *name, gpointer ref) {
}
#endif
-// vim: ft=c:et:sw=4:ts=8:sts=4:enc=utf-8:tw=80
+// vim: ft=c:et:sw=4:ts=8:sts=4:tw=80
View
3 common/tokenize.gperf
@@ -6,6 +6,7 @@ count
current
destroy
entry
+eval_js
eventbox
fg
focus
@@ -27,6 +28,7 @@ hovered_uri
icon
indexof
insert
+install_path
label
loading
notebook
@@ -35,6 +37,7 @@ pack_start
remove
search
selectable
+selection
set_alignment
set_child
set_padding
View
15 common/util.c
@@ -24,6 +24,7 @@
#include <stdarg.h>
#include <stdlib.h>
+#include "globalconf.h"
#include "common/util.h"
/* Print error and exit with EXIT_FAILURE code. */
@@ -52,12 +53,14 @@ _warn(int line, const char *fct, const char *fmt, ...) {
/* Print debug message on stderr. */
void
_debug(int line, const char *fct, const char *fmt, ...) {
- va_list ap;
- va_start(ap, fmt);
- g_fprintf(stderr, "D: luakit: %s:%d: ", fct, line);
- g_vfprintf(stderr, fmt, ap);
- va_end(ap);
- g_fprintf(stderr, "\n");
+ if (globalconf.verbose) {
+ va_list ap;
+ va_start(ap, fmt);
+ g_fprintf(stderr, "D: luakit: %s:%d: ", fct, line);
+ g_vfprintf(stderr, fmt, ap);
+ va_end(ap);
+ g_fprintf(stderr, "\n");
+ }
}
gboolean
View
10 common/util.h
@@ -37,17 +37,9 @@ void _fatal(int, const gchar *, const gchar *, ...);
#define warn(string, ...) _warn(__LINE__, __FUNCTION__, string, ##__VA_ARGS__)
void _warn(int, const gchar *, const gchar *, ...);
-#ifdef DEBUG_MESSAGES
-
#define debug(string, ...) _debug(__LINE__, __FUNCTION__, string, ##__VA_ARGS__)
void _debug(int, const gchar *, const gchar *, ...);
-#else
-
-#define debug(string, ...)
-
-#endif
-
/* A NULL resistant strlen. Unlike it's libc sibling, l_strlen returns a
* ssize_t, and supports its argument being NULL. */
static inline ssize_t l_strlen(const gchar *s) {
@@ -59,4 +51,4 @@ static inline ssize_t l_strlen(const gchar *s) {
gboolean file_exists(const gchar*);
#endif
-// vim: ft=c:et:sw=4:ts=8:sts=4:enc=utf-8:tw=80
+// vim: ft=c:et:sw=4:ts=8:sts=4:tw=80
View
2 config.mk
@@ -14,7 +14,7 @@ INCS := $(shell pkg-config --cflags ${PKGS}) -I./
LIBS := $(shell pkg-config --libs ${PKGS})
# Add flags
-CPPFLAGS := -DVERSION=\"${VERSION}\" -DDEBUG_MESSAGES ${CPPFLAGS}
+CPPFLAGS := -DVERSION=\"${VERSION}\" ${CPPFLAGS}
CFLAGS := -std=c99 -ggdb -W -Wall -Wextra ${INCS} ${CFLAGS}
LDFLAGS := ${LIBS} ${LDFLAGS}
View
4 globalconf.h.in
@@ -21,7 +21,7 @@
#ifndef LUAKIT_GLOBALCONF
#define LUAKIT_GLOBALCONF
-#define LUAKIT_LUA_LIB_PATH "/usr/local/share/luakit/lib"
+#define LUAKIT_INSTALL_PATH "/usr/local/share/luakit"
#define LUAKIT_OBJECT_REGISTRY_KEY "luakit.object.registry"
#include <glib/gtypes.h>
@@ -35,6 +35,8 @@ typedef struct {
gchar *base_data_directory;
/* Path to the current config file */
gchar *confpath;
+ /* Print verbose output */
+ gboolean verbose;
/* Lua VM state */
lua_State *L;
/* Global signals table */
View
2 lib/bind.lua
@@ -120,3 +120,5 @@ function hit(binds, mods, key, buffer, enable_buffer, arg)
end
return true
end
+
+-- vim: ft=lua:et:sw=4:ts=8:sts=4:tw=80
View
2 lib/mode.lua
@@ -56,3 +56,5 @@ function set_default(win, mode)
end
setmetatable(_M, { __call = function(_, ...) return set(...) end })
+
+-- vim: ft=lua:et:sw=4:ts=8:sts=4:tw=80
View
41 lib/util.lua
@@ -15,6 +15,8 @@ local rtable = table
local string = string
local type = type
local print = print
+local error = error
+local capi = { luakit = luakit }
-- Utility module for awful
module("util")
@@ -139,4 +141,41 @@ function table.pop(t, k)
return v
end
--- vim: filetype=lua:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:encoding=utf-8:textwidth=80
+-- Check if a file exists
+function os.exists(f)
+ fh, err = io.open(f)
+ if fh then
+ fh:close()
+ return true
+ end
+end
+
+-- Table of xdg home paths or their default locations
+xdg = {
+ config_home = (os.getenv("XDG_CONFIG_HOME") or (os.getenv("HOME") .. "/.config")) .. "/luakit",
+ data_home = (os.getenv("XDG_DATA_HOME") or (os.getenv("HOME") .. "/.local/share")) .. "/luakit",
+ cache_home = (os.getenv("XDG_CACHE_HOME") or (os.getenv("HOME") .. "/.cache")) .. "/luakit",
+}
+
+-- Search locally, xdg home path and then luakit install path for a given file
+function xdg_find(f, xdg_home_path)
+ -- Ignore absolute paths
+ if string.match(f, "^/") then
+ if os.exists(f) then return f end
+ error(string.format("xdg_find: No such file: %s\n", f))
+ end
+
+ -- Check if file exists at the following locations & return first match
+ local paths = { f, xdg_home_path .. "/" .. f, capi.luakit.install_path .. "/" .. f }
+ for _, p in ipairs(paths) do
+ if os.exists(p) then return p end
+ end
+
+ error(string.format("xdg_find: No such file at:\n\t%s\n", rtable.concat(paths, ",\n\t")))
+end
+
+function find_config(f) return xdg_find(f, xdg.config_home) end
+function find_data(f) return xdg_find(f, xdg.data_home) end
+function find_cache(f) return xdg_find(f, xdg.cache_home) end
+
+-- vim: ft=lua:et:sw=4:ts=8:sts=4:tw=80
View
48 luah.c
@@ -311,6 +311,40 @@ luaH_isloop(lua_State *L, gint idx)
return !ret;
}
+/* Returns a string from X selection.
+ * \param L The Lua VM state.
+ * \return The number of elements pushed on stack (1).
+ */
+static gint
+luaH_luakit_selection(lua_State *L)
+{
+ int n = lua_gettop(L);
+ GdkAtom atom = GDK_SELECTION_PRIMARY;
+
+ if (n) {
+ const gchar *arg = luaL_checkstring(L, 1);
+ /* Follow xclip(1) behavior: check only the first character of argument */
+ switch (arg[0]) {
+ case 'p':
+ break;
+ case 's':
+ atom = GDK_SELECTION_SECONDARY;
+ break;
+ case 'c':
+ atom = GDK_SELECTION_CLIPBOARD;
+ break;
+ default:
+ luaL_argerror(L, 1, "should be 'primary', 'secondary' or 'clipboard'");
+ break;
+ }
+ }
+ GtkClipboard *selection = gtk_clipboard_get(atom);
+ gchar *text = gtk_clipboard_wait_for_text(selection);
+ lua_pushstring(L, text);
+ g_free(text);
+ return 1;
+}
+
/* luakit global table.
* \param L The Lua VM state.
* \return The number of elements pushed on stack.
@@ -341,6 +375,14 @@ luaH_luakit_index(lua_State *L)
}
return 1;
+ case L_TK_SELECTION:
+ lua_pushcfunction(L, luaH_luakit_selection);
+ return 1;
+
+ case L_TK_INSTALL_PATH:
+ lua_pushstring(L, LUAKIT_INSTALL_PATH);
+ return 1;
+
default:
break;
}
@@ -522,8 +564,8 @@ luaH_init(xdgHandle *xdg)
}
/* add Lua lib path (/usr/share/luakit/lib by default) */
- lua_pushliteral(L, ";" LUAKIT_LUA_LIB_PATH "/?.lua");
- lua_pushliteral(L, ";" LUAKIT_LUA_LIB_PATH "/?/init.lua");
+ lua_pushliteral(L, ";" LUAKIT_INSTALL_PATH "/lib/?.lua");
+ lua_pushliteral(L, ";" LUAKIT_INSTALL_PATH "/lib/?/init.lua");
lua_concat(L, 3); /* concatenate with package.path */
lua_setfield(L, 1, "path"); /* package.path = "concatenated string" */
}
@@ -603,4 +645,4 @@ luaH_class_newindex_miss_property(lua_State *L, lua_object_t *obj)
return 0;
}
-// vim: ft=c:et:sw=4:ts=8:sts=4:enc=utf-8:tw=80
+// vim: ft=c:et:sw=4:ts=8:sts=4:tw=80
View
2 luah.h
@@ -157,4 +157,4 @@ void luaH_modifier_table_push(lua_State *, guint);
void luaH_keystr_push(lua_State *, guint);
#endif
-// vim: ft=c:et:sw=4:ts=8:sts=4:enc=utf-8:tw=80
+// vim: ft=c:et:sw=4:ts=8:sts=4:tw=80
View
25 luakit.c
@@ -2,6 +2,7 @@
* luakit.c - luakit main functions
*
* Copyright (C) 2010 Mason Larobina <mason.larobina@gmail.com>
+ * Copyright (C) 2009 Enno Boland <gottox@s01.de>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -18,15 +19,6 @@
*
*/
-/*
- * MIT/X Consortium License (applies to some functions from surf.c)
- *
- * (C) 2009 Enno Boland <gottox@s01.de>
- *
- * See COPYING.MIT for the full license.
- *
- */
-
#include <gtk/gtk.h>
#include <signal.h>
#include <stdlib.h>
@@ -55,13 +47,12 @@ parseopts(int argc, char *argv[]) {
/* define command line options */
const GOptionEntry entries[] = {
- { "uri", 'u', 0, G_OPTION_ARG_STRING_ARRAY, &uris,
- "uri(s) to load at startup", "URI" },
- { "config", 'c', 0, G_OPTION_ARG_STRING, &globalconf.confpath,
- "configuration file to use", "FILE" },
- { "version", 'V', 0, G_OPTION_ARG_NONE, &only_version,
- "show version", NULL },
- { NULL, 0, 0, 0, NULL, NULL, NULL }};
+ { "uri", 'u', 0, G_OPTION_ARG_STRING_ARRAY, &uris, "uri(s) to load at startup", "URI" },
+ { "config", 'c', 0, G_OPTION_ARG_STRING, &globalconf.confpath, "configuration file to use", "FILE" },
+ { "version", 'V', 0, G_OPTION_ARG_NONE, &only_version, "print version and exit", NULL },
+ { "verbose", 'v', 0, G_OPTION_ARG_NONE, &globalconf.verbose, "print debugging output", NULL },
+ { NULL, 0, 0, 0, NULL, NULL, NULL },
+ };
/* parse command line options */
context = g_option_context_new("[URI...]");
@@ -157,4 +148,4 @@ main(int argc, char *argv[]) {
return EXIT_SUCCESS;
}
-// vim: ft=c:et:sw=4:ts=8:sts=4:enc=utf-8:tw=80
+// vim: ft=c:et:sw=4:ts=8:sts=4:tw=80
View
2 luakit.h
@@ -37,4 +37,4 @@ typedef struct {
extern Luakit luakit;
#endif
-// vim: ft=c:et:sw=4:ts=8:sts=4:enc=utf-8:tw=80
+// vim: ft=c:et:sw=4:ts=8:sts=4:tw=80
View
340 rc.lua
@@ -17,8 +17,14 @@ function entry() return widget{type="entry"} end
-- Variable definitions
HOMEPAGE = "http://luakit.org/"
--HOMEPAGE = "http://github.com/mason-larobina/luakit"
-SCROLL_STEP = 20
-MAX_HISTORY = 100
+SCROLL_STEP = 20
+MAX_CMD_HISTORY = 100
+MAX_SRCH_HISTORY = 100
+--HTTPPROXY = "http://example.com:3128"
+
+-- Setup download directory
+DOWNLOAD_DIR = (os.getenv("HOME") or ".") .. "/downloads"
+os.execute(string.format("mkdir -p %q", DOWNLOAD_DIR))
-- Luakit theme
theme = theme or {
@@ -56,6 +62,13 @@ widget.add_signal("new", function(wi)
end)
end)
+-- Search engines
+search_engines = {
+ google = "http://google.com/search?q={0}",
+ imdb = "http://imdb.com/find?s=all&q={0}",
+ sourceforge = "http://sf.net/search/?words={0}"
+}
+
-- Add key bindings to be used across all windows
mode_binds = {
-- bind.buf(Pattern, function (w, buffer, opts) .. end, opts),
@@ -81,6 +94,15 @@ mode_binds = {
bind.buf("^G$", function (w) w:scroll_vert("100%") end),
bind.buf("^[\-\+]?[0-9]+[%%G]$", function (w, b) w:scroll_vert(string.match(b, "^([\-\+]?%d+)[%%G]$") .. "%") end),
+ -- Clipboard
+ bind.key({}, "p", function (w) w:navigate(luakit.selection()) end),
+ bind.key({}, "P", function (w) w:new_tab(luakit.selection()) end),
+
+ -- Commands
+ bind.buf("^o$", function (w, c) w:enter_cmd(":open ") end),
+ bind.buf("^t$", function (w, c) w:enter_cmd(":tabopen ") end),
+ bind.buf("^,g$", function (w, c) w:enter_cmd(":websearch google ") end),
+
-- Searching
bind.key({}, "/", function (w) w:start_search(true) end),
bind.key({}, "?", function (w) w:start_search(false) end),
@@ -95,13 +117,25 @@ mode_binds = {
bind.buf("^[0-9]*gT$", function (w, b) w:prev_tab(tonumber(string.match(b, "^(%d*)gT$") or 1)) end),
bind.buf("^[0-9]*gt$", function (w, b) w:next_tab(tonumber(string.match(b, "^(%d*)gt$") or 1)) end),
bind.buf("^gH$", function (w) w:new_tab(HOMEPAGE) end),
+ bind.buf("^d$", function (w) w:close_tab() end),
bind.buf("^gh$", function (w) w:navigate(HOMEPAGE) end),
bind.buf("^ZZ$", function (w) luakit.quit() end),
+
+ -- Link following
+ bind.key({}, "f", function (w) w:set_mode("follow") end),
},
command = {
+ bind.key({"Shift"}, "Insert", function (w) w:insert_cmd(luakit.selection()) end),
bind.key({}, "Up", function (w) w:cmd_hist_prev() end),
bind.key({}, "Down", function (w) w:cmd_hist_next() end),
+ bind.key({}, "Tab", function (w) w:cmd_completion() end),
+ bind.key({"Control"}, "w", function (w) w:del_word() end),
+ bind.key({"Control"}, "u", function (w) w:del_line() end),
+ },
+ search = {
+ bind.key({}, "Up", function (w) w:srch_hist_prev() end),
+ bind.key({}, "Down", function (w) w:srch_hist_next() end),
},
insert = { },
}
@@ -115,8 +149,19 @@ commands = {
bind.cmd({"forward", "f"}, function (w, a) w:forward(tonumber(a) or 1) end),
bind.cmd({"scroll" }, function (w, a) w:scroll_vert(a) end),
bind.cmd({"quit", "q"}, function (w) luakit.quit() end),
+ bind.cmd({"close", "c"}, function (w) w:close_tab() end),
+ bind.cmd({"websearch", "ws"}, function (w, e, s) w:websearch(e, s) end),
}
+function set_http_options(w)
+ local proxy = HTTPPROXY or os.getenv("http_proxy")
+ if proxy then w:set('proxy-uri', proxy) end
+ w:set('user-agent', 'luakit')
+ -- Uncomment the following options if you want to enable SSL certs validation.
+ -- w:set('ssl-ca-file', '/etc/certs/ca-certificates.crt')
+ -- w:set('ssl-strict', true)
+end
+
-- Build and pack window widgets
function build_window()
-- Create a table for widgets and state variables for a window
@@ -228,38 +273,62 @@ function attach_window_signals(w)
-- Attach window widget signals
w.win:add_signal("key-press", function(win, 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)
w.win:add_signal("mode-changed", function(win, mode)
+ local i, p = w.ibar.input, w.ibar.prompt
+
w:update_binds(mode)
w.cmd_hist_cursor = nil
+ -- Clear following hints if the user exits follow mode
+ if w.showing_hints then
+ w:eval_js("clear();");
+ w.showing_hints = false
+ end
+
-- If a user aborts a search return to the original position
if w.search_start_marker then
w:get_current():set_scroll_vert(w.search_start_marker)
w.search_start_marker = nil
end
if mode == "normal" then
- w.ibar.prompt:hide()
- w.ibar.input:hide()
+ p:hide()
+ i:hide()
elseif mode == "insert" then
- w.ibar.input:hide()
- w.ibar.input.text = ""
- w.ibar.prompt.text = "-- INSERT --"
- w.ibar.prompt:show()
+ i:hide()
+ i.text = ""
+ p.text = "-- INSERT --"
+ p:show()
elseif mode == "command" then
- w.ibar.prompt:hide()
- w.ibar.input.text = ":"
- w.ibar.input:show()
- w.ibar.input:focus()
- w.ibar.input:set_position(-1)
+ p:hide()
+ i.text = ":"
+ i:show()
+ i:focus()
+ i:set_position(-1)
elseif mode == "search" then
- w.ibar.prompt:hide()
- w.ibar.input:show()
+ p:hide()
+ i:show()
+ elseif mode == "follow" then
+ w:eval_js_from_file(util.find_data("scripts/follow.js"))
+ w:eval_js("clear(); show_hints();")
+ w.showing_hints = true
+ p.text = "Follow:"
+ p:show()
+ i.text = ""
+ i:show()
+ i:focus()
+ i:set_position(-1)
else
w.ibar.prompt.text = ""
w.ibar.input.text = ""
@@ -280,6 +349,8 @@ function attach_window_signals(w)
w:clear_search()
w:set_mode()
end
+ elseif w:is_mode("follow") then
+ w:eval_js(string.format("update(%q)", w.ibar.input.text))
end
end)
@@ -290,12 +361,12 @@ function attach_window_signals(w)
w:match_cmd(string.sub(text, 2))
w:set_mode()
elseif w:is_mode("search") then
- -- TODO add search term to some history list
- w:search(string.sub(text, 2), (string.sub(text, 1, 1) == "/"))
+ w:srch_hist_add(text)
+ w:search(string.sub(text, 2), string.sub(text, 1, 1) == "/")
-- User doesn't want to return to start position
w.search_start_marker = nil
w:set_mode()
- w.ibar.prompt.text = text
+ w.ibar.prompt.text = util.escape(text)
w.ibar.prompt:show()
end
end)
@@ -317,6 +388,18 @@ function attach_webview_signals(w, view)
end
end)
+ view:add_signal("link-hover", function (v, link)
+ if w:is_current(v) and link then
+ w.sbar.l.uri.text = "Link: " .. util.escape(link)
+ end
+ end)
+
+ view:add_signal("link-unhover", function (v)
+ if w:is_current(v) then
+ w:update_uri(v)
+ end
+ end)
+
view:add_signal("key-press", function ()
-- Only allow key press events to hit the webview if the user is in
-- "insert" mode.
@@ -332,6 +415,35 @@ function attach_webview_signals(w, view)
end
end)
+ -- 'link' contains the download link
+ -- 'mime' contains the mime type that is requested
+ -- return TRUE to accept or FALSE to reject
+ view:add_signal("mime-type-decision", function (v, link, mime)
+ if w:is_current(v) then
+ print(string.format("Requested link: %s (%s)", link, mime))
+
+ -- i.e. block binary files like *.exe
+ if string.match(mime, "application/octet-stream") then
+ return false
+ end
+ end
+ end)
+
+ -- 'link' contains the download link
+ -- 'filename' contains the suggested filename (from server or webkit)
+ view:add_signal("download-request", function (v, link, filename)
+ if w:is_current(v) and filename then
+ local dl = DOWNLOAD_DIR .. "/" .. filename
+
+ print ("Download request:", link)
+ print ("Suggested filename:", filename)
+
+ local wget = string.format("wget -q %q -O %q &", link, dl)
+ print("Launching: " .. wget)
+ os.execute(wget)
+ end
+ end)
+
view:add_signal("progress-update", function (v)
if w:is_current(v) then
w:update_progress(v)
@@ -393,18 +505,48 @@ window_helpers = {
end,
navigate = function(w, uri, view)
- (view or w:get_current()).uri = uri
+ local v = view or w:get_current()
+ if v then
+ v.uri = uri
+ else
+ return w:new_tab(uri)
+ end
end,
new_tab = function(w, uri)
local view = webview()
w.tabs:append(view)
+ set_http_options(w)
attach_webview_signals(w, view)
if uri then view.uri = uri end
view.show_scrollbars = false
w:update_tab_count()
end,
+ -- close the current tab
+ close_tab = function(w)
+ view = w:get_current()
+ if not view then return end
+ w.tabs:remove(view)
+ view:destroy()
+ w:update_tab_count()
+ end,
+
+ -- evaluate javascript code and return string result
+ eval_js = function(w, script, file, view)
+ if not view then view = w:get_current() end
+ return view:eval_js(script, file or "(buffer)")
+ end,
+
+ -- evaluate javascript code from file and return string result
+ eval_js_from_file = function(w, file, view)
+ local fh, err = io.open(file)
+ if not fh then return error(err) end
+ local script = fh:read("*a")
+ fh:close()
+ return w:eval_js(script, file, view)
+ end,
+
-- Wrapper around the bind plugin's hit method
hit = function (w, mods, key)
local caught, newbuf = bind.hit(w.binds or {}, mods, key, w.buffer, w:is_mode("normal"), w)
@@ -418,12 +560,157 @@ window_helpers = {
return bind.match_cmd(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 nil 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,
+
+ -- 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)
+ if not search_engines[engine] then
+ print("E: No matching search engine found:", engine)
+ return 0
+ end
+ local uri = string.gsub(search_engines[engine], "{%d}", search)
+ return w:navigate(uri)
+ 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(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 = 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
+ if #w.srch_hist > ((MAX_SRCH_HISTORY or 100) + 5) then
+ while #w.srch_hist > (MAX_SRCH_HISTORY or 100) 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
- if #w.cmd_hist > ((MAX_HISTORY or 100) + 5) then
- while #w.cmd_hist > (MAX_HISTORY or 100) do
+ if #w.cmd_hist > ((MAX_CMD_HISTORY or 100) + 5) then
+ while #w.cmd_hist > (MAX_CMD_HISTORY or 100) do
table.remove(w.cmd_hist, 1)
end
end
@@ -561,8 +848,9 @@ window_helpers = {
end,
update_uri = function (w, view, uri)
- if not view then view = w:get_current() end
- w.sbar.l.uri.text = (uri or view.uri or "about:blank")
+ local v = view or w:get_current()
+ if not v then return end
+ w.sbar.l.uri.text = util.escape((uri or v.uri or "about:blank"))
end,
update_progress = function (w, view, p)
@@ -589,7 +877,7 @@ window_helpers = {
update_buf = function (w)
if w.buffer then
- w.sbar.r.buf.text = string.format(" %-3s", w.buffer)
+ w.sbar.r.buf.text = util.escape(string.format(" %-3s", w.buffer))
w.sbar.r.buf:show()
else
w.sbar.r.buf:hide()
@@ -654,7 +942,7 @@ window_helpers = {
for i = 1, count do
local t = tb.titles[i]
local title = " " ..i.. " "..w:get_tab_title(w.tabs:atindex(i))
- t.label.text = string.format(theme.tablabel_format or "%s", title)
+ t.label.text = util.escape(string.format(theme.tablabel_format or "%s", title))
w:apply_tablabel_theme(t, i == current)
end
end
@@ -740,3 +1028,5 @@ function new_window(uris)
end
new_window(uris)
+
+-- vim: ft=lua:et:sw=4:ts=8:sts=4:tw=80
View
246 scripts/follow.js
@@ -0,0 +1,246 @@
+var elements = [];
+var active_arr = [];
+var hints;
+var overlays;
+var active;
+var lastpos = 0;
+var last_input = "";
+var last_strings = [];
+
+focus_color = "#00ff00";
+normal_color = "#ffff99";
+opacity = 0.3;
+border = "1px dotted #000000";
+
+hint_foreground = "#ffffff";
+hint_background = "#000088";
+hint_border = "2px dashed #000000";
+hint_opacity = 0.4;
+hint_font = "11px monospace bold";
+
+vertical_offset = 0;
+horizontal_offset = -10;
+
+function Hint(element) {
+ this.element = element;
+ this.rect = element.getBoundingClientRect();
+
+ function create_span(element, h, v) {
+ var span = document.createElement("span");
+ var leftpos = Math.max((element.rect.left + document.defaultView.scrollX), document.defaultView.scrollX) + h;
+ var toppos = Math.max((element.rect.top + document.defaultView.scrollY), document.defaultView.scrollY) + v;
+ span.style.position = "absolute";
+ span.style.left = leftpos + "px";
+ span.style.top = toppos + "px";
+ return span;
+ }
+ function create_hint(element) {
+ var hint = create_span(element, horizontal_offset, vertical_offset - element.rect.height/2);
+ hint.style.font = hint_font;
+ hint.style.color = hint_foreground;
+ hint.style.background = hint_background;
+ hint.style.opacity = hint_opacity;
+ hint.style.border = hint_border;
+ hint.style.zIndex = 10001;
+ hint.style.visibility = 'visible';
+ return hint;
+ }
+ function create_overlay(element) {
+ var overlay = create_span(element, 0, 0);
+ overlay.style.width = element.rect.width + "px";
+ overlay.style.height = element.rect.height + "px";
+ overlay.style.opacity = opacity;
+ overlay.style.backgroundColor = normal_color;
+ overlay.style.border = border;
+ overlay.style.zIndex = 10000;
+ overlay.style.visibility = 'visible';
+ overlay.addEventListener( 'click', function() { click_element(element); }, false );
+ return overlay;
+ }
+
+ this.hint = create_hint(this);
+ this.overlay = create_overlay(this);
+}
+function reload_hints(array, input, keep) {
+ var length = array.length;
+ var start = length < 10 ? 1 : length < 100 ? 10 : 100;
+ var bestposition = 37;
+
+ for (var i=0; i<length; i++) {
+ var e = array[i];
+ e.overlay.style.backgroundColor = normal_color;
+ if (!e.hint.parentNode && !e.hint.firstchild) {
+ var content = document.createTextNode(start + i);
+ e.hint.appendChild(content);
+ hints.appendChild(e.hint);
+ }
+ else if (!keep) {
+ e.hint.textContent = start + i;
+ }
+ if (!e.overlay.parentNode && !e.overlay.firstchild) {
+ overlays.appendChild(e.overlay);
+ }
+ if (input && bestposition != 0) {
+ // match word beginnings
+ var content = e.element.textContent.toLowerCase().split(" ");
+ for (var cl=0; cl<content.length; cl++) {
+ if (content[cl].toLowerCase().indexOf(input) == 0) {
+ if (cl < bestposition) {
+ lastpos = i;
+ bestposition = cl;
+ break;
+ }
+ }
+ }
+ }
+ }
+ active = array[lastpos];
+ active.overlay.style.backgroundColor = focus_color;
+}
+function click_element(e) {
+ var mouseEvent = document.createEvent("MouseEvent");
+ mouseEvent.initMouseEvent("click", true, true, window, 0, 0, 0, 0, 0, false, false, false, false, 0, null);
+ e.element.dispatchEvent(mouseEvent);
+ clear();
+}
+function show_hints() {
+ document.activeElement.blur();
+ if ( elements ) {
+ var res = document.body.querySelectorAll('a, area, textarea, select, link, input:not([type=hidden]), button, frame, iframe');
+ hints = document.createElement("div");
+ overlays = document.createElement("div");
+ for (var i=0; i<res.length; i++) {
+ var e = new Hint(res[i]);
+ var rects = e.element.getClientRects()[0];
+ var r = e.rect;
+ if (!r || r.top > window.innerHeight || r.bottom < 0 || r.left > window.innerWidth || r < 0 || !rects ) {
+ continue;
+ }
+ var style = document.defaultView.getComputedStyle(e.element, null);
+ if (style.getPropertyValue("visibility") != "visible" || style.getPropertyValue("display") == "none") {
+ continue;
+ }
+ elements.push(e);
+ };
+ elements.sort( function(a,b) { return a.rect.top - b.rect.top; });
+ active_arr = elements;
+ reload_hints(elements);
+ document.body.appendChild(hints);
+ document.body.appendChild(overlays);
+ }
+}
+function is_input(element) {
+ var e = element.element;
+ var type = e.type.toLowerCase();
+ if (e.tagName == "INPUT" || e.tagName == "TEXTAREA" ) {
+ if (type == "radio" || type == "checkbox") {
+ e.checked = !e.checked;
+ }
+ else if (type == "submit" || type == "reset" || type == "button") {
+ click_element(element);
+ }
+ else {
+ e.focus();
+ }
+ return true;
+ }
+ return false;
+}
+function update_hints(input) {
+ var array = [];
+ var text_content;
+ var keep = false;
+ if (input) {
+ input = input.toLowerCase();
+ }
+ for (var i=0; i<active_arr.length; i++) {
+ var e = active_arr[i];
+ if (parseInt(input) == input) {
+ text_content = e.hint.textContent;
+ keep = true;
+ }
+ else {
+ text_content = e.element.textContent.toLowerCase();
+ }
+ if (text_content.match(input)) {
+ array.push(e);
+ }
+ else {
+ e.hint.style.visibility = 'hidden';
+ e.overlay.style.visibility = 'hidden';
+ }
+ }
+ active_arr = array;
+ if (array.length == 0) {
+ clear();
+ return;
+ }
+ if (array.length == 1) {
+ if (evaluate(array[0])) {
+ return "__HINT_EVALUATED__"
+ }
+ }
+ reload_hints(array, input, keep);
+}
+function clear() {
+ if (overlays && overlays.parentNode) {
+ overlays.parentNode.removeChild(overlays);
+ }
+ if (hints && hints.parentNode) {
+ hints.parentNode.removeChild(hints);
+ }
+ elements = [];
+ active_arr = [];
+ active = undefined;
+}
+function evaluate(element) {
+ var ret = false;
+ var e = element.element;
+ if (!is_input(element) && e.href) {
+ if (e.href.match(/javascript:/) || (e.type.toLowerCase() == "button")) {
+ click_element(element);
+ ret = true;
+ }
+ else {
+ document.location = e.href;
+ ret = true;
+ }
+ }
+ clear();
+ return ret;
+}
+function get_active() {
+ return evaluate(active);
+}
+function focus(newpos) {
+ active_arr[lastpos].overlay.style.backgroundColor = normal_color;
+ active_arr[newpos].overlay.style.backgroundColor = focus_color;
+ active = active_arr[newpos];
+ lastpos = newpos;
+}
+function focus_next() {
+ var newpos = lastpos == active_arr.length-1 ? 0 : lastpos + 1;
+ focus(newpos);
+}
+function focus_prev() {
+ var newpos = lastpos == 0 ? active_arr.length-1 : lastpos - 1;
+ focus(newpos);
+}
+
+function update(input) {
+ input = input.replace(/(\d+)$/, " $1");
+ strings = input.split(" ");
+ if (input.length < last_input.length || strings.length < last_strings.length) {
+ // user removed a char
+ clear();
+ show_hints();
+ for (var i = 0; i < strings.length; i += 1) {
+ update_hints(strings[i]);
+ }
+ } else {
+ update_hints(strings[strings.length-1]);
+ }
+ last_input = input;
+ last_strings = strings;
+}
+
View
2 widget.c
@@ -179,4 +179,4 @@ widget_class_setup(lua_State *L)
NULL);
}
-// vim: ft=c:et:sw=4:ts=8:sts=4:enc=utf-8:tw=80
+// vim: ft=c:et:sw=4:ts=8:sts=4:tw=80
View
2 widget.h
@@ -75,4 +75,4 @@ void widget_class_setup(lua_State *);
#endif
-// vim: ft=c:et:sw=4:ts=8:sts=4:enc=utf-8:tw=80
+// vim: ft=c:et:sw=4:ts=8:sts=4:tw=80
View
2 widgets/box.c
@@ -150,4 +150,4 @@ BOX_WIDGET_CONSTRUCTOR(hbox)
#undef BOX_WIDGET_CONSTRUCTOR
-// vim: ft=c:et:sw=4:ts=8:sts=4:enc=utf-8:tw=80
+// vim: ft=c:et:sw=4:ts=8:sts=4:tw=80
View
2 widgets/common.c
@@ -189,4 +189,4 @@ luaH_widget_destroy(lua_State *L)
return 0;
}
-// vim: ft=c:et:sw=4:ts=8:sts=4:enc=utf-8:tw=80
+// vim: ft=c:et:sw=4:ts=8:sts=4:tw=80
View
2 widgets/common.h
@@ -41,4 +41,4 @@ void parent_set_cb(GtkWidget*, GtkObject*, widget_t*);
void remove_cb(GtkContainer*, GtkWidget*, widget_t*);
#endif
-// vim: ft=c:et:sw=4:ts=8:sts=4:enc=utf-8:tw=80
+// vim: ft=c:et:sw=4:ts=8:sts=4:tw=80
View
2 widgets/entry.c
@@ -244,4 +244,4 @@ widget_entry(widget_t *w)
return w;
}
-// vim: ft=c:et:sw=4:ts=8:sts=4:enc=utf-8:tw=80
+// vim: ft=c:et:sw=4:ts=8:sts=4:tw=80
View
2 widgets/eventbox.c
@@ -114,4 +114,4 @@ widget_eventbox(widget_t *w)
return w;
}
-// vim: ft=c:et:sw=4:ts=8:sts=4:enc=utf-8:tw=80
+// vim: ft=c:et:sw=4:ts=8:sts=4:tw=80
View
2 widgets/label.c
@@ -202,4 +202,4 @@ widget_label(widget_t *w)
return w;
}
-// vim: ft=c:et:sw=4:ts=8:sts=4:enc=utf-8:tw=80
+// vim: ft=c:et:sw=4:ts=8:sts=4:tw=80
View
2 widgets/notebook.c
@@ -343,4 +343,4 @@ widget_notebook(widget_t *w)
return w;
}
-// vim: ft=c:et:sw=4:ts=8:sts=4:enc=utf-8:tw=80
+// vim: ft=c:et:sw=4:ts=8:sts=4:tw=80
View
2 widgets/textbutton.c
@@ -109,4 +109,4 @@ widget_textbutton(widget_t *w)
return w;
}
-// vim: ft=c:et:sw=4:ts=8:sts=4:enc=utf-8:tw=80
+// vim: ft=c:et:sw=4:ts=8:sts=4:tw=80
View
316 widgets/webview.c
@@ -31,7 +31,8 @@ static struct {
SoupCookieJar *cookiejar;
} Soup = { NULL, NULL };
-typedef enum { BOOL, CHAR, INT, FLOAT, DOUBLE } property_value_type;
+typedef enum { BOOL, CHAR, INT, FLOAT, DOUBLE, URI } property_value_type;
+typedef enum { SETTINGS, WEBKITVIEW, SOUPSESSION } property_value_scope;
typedef union {
gchar *c;
@@ -44,63 +45,169 @@ typedef union {
const struct property_t {
const gchar *name;
property_value_type type;
- gboolean webkitview;
+ property_value_scope scope;
gboolean writable;
} properties[] = {
- { "auto-load-images", BOOL, FALSE, TRUE },
- { "auto-resize-window", BOOL, FALSE, TRUE },
- { "auto-shrink-images", BOOL, FALSE, TRUE },
- { "cursive-font-family", CHAR, FALSE, TRUE },
- { "custom-encoding", CHAR, TRUE, TRUE },
- { "default-encoding", CHAR, FALSE, TRUE },
- { "default-font-family", CHAR, FALSE, TRUE },
- { "default-font-size", INT, FALSE, TRUE },
- { "default-monospace-font-size", INT, FALSE, TRUE },
- { "editable", BOOL, TRUE, TRUE },
- { "enable-caret-browsing", BOOL, FALSE, TRUE },
- { "enable-default-context-menu", BOOL, FALSE, TRUE },
- { "enable-developer-extras", BOOL, FALSE, TRUE },
- { "enable-dom-paste", BOOL, FALSE, TRUE },
- { "enable-file-access-from-file-uris", BOOL, FALSE, TRUE },
- { "enable-html5-database", BOOL, FALSE, TRUE },
- { "enable-html5-local-storage", BOOL, FALSE, TRUE },
- { "enable-java-applet", BOOL, FALSE, TRUE },
- { "enable-offline-web-application-cache", BOOL, FALSE, TRUE },
- { "enable-page-cache", BOOL, FALSE, TRUE },
- { "enable-plugins", BOOL, FALSE, TRUE },
- { "enable-private-browsing", BOOL, FALSE, TRUE },
- { "enable-scripts", BOOL, FALSE, TRUE },
- { "enable-site-specific-quirks", BOOL, FALSE, TRUE },
- { "enable-spatial-navigation", BOOL, FALSE, TRUE },
- { "enable-spell-checking", BOOL, FALSE, TRUE },
- { "enable-universal-access-from-file-uris", BOOL, FALSE, TRUE },
- { "enable-xss-auditor", BOOL, FALSE, TRUE },
- { "encoding", CHAR, TRUE, FALSE },
- { "enforce-96-dpi", BOOL, FALSE, TRUE },
- { "fantasy-font-family", CHAR, FALSE, TRUE },
- { "full-content-zoom", BOOL, TRUE, TRUE },
- { "icon-uri", CHAR, TRUE, FALSE },
- { "javascript-can-access-clipboard", BOOL, FALSE, TRUE },
- { "javascript-can-open-windows-automatically", BOOL, FALSE, TRUE },
- { "minimum-font-size", INT, FALSE, TRUE },
- { "minimum-logical-font-size", INT, FALSE, TRUE },
- { "monospace-font-family", CHAR, FALSE, TRUE },
- { "print-backgrounds", BOOL, FALSE, TRUE },
- { "progress", DOUBLE, TRUE, FALSE },
- { "resizable-text-areas", BOOL, FALSE, TRUE },
- { "sans-serif-font-family", CHAR, FALSE, TRUE },
- { "serif-font-family", CHAR, FALSE, TRUE },
- { "spell-checking-languages", CHAR, FALSE, TRUE },
- { "tab-key-cycles-through-elements", BOOL, FALSE, TRUE },
- { "title", CHAR, TRUE, FALSE },
- { "transparent", BOOL, TRUE, TRUE },
- { "user-agent", CHAR, FALSE, TRUE },
- { "user-stylesheet-uri", CHAR, FALSE, TRUE },
- { "zoom-level", FLOAT, TRUE, TRUE },
- { "zoom-step", FLOAT, FALSE, TRUE },
+ { "accept-language", CHAR, SOUPSESSION, TRUE },
+ { "accept-language-auto", BOOL, SOUPSESSION, TRUE },
+ { "auto-load-images", BOOL, SETTINGS, TRUE },
+ { "auto-resize-window", BOOL, SETTINGS, TRUE },
+ { "auto-shrink-images", BOOL, SETTINGS, TRUE },
+ { "cursive-font-family", CHAR, SETTINGS, TRUE },
+ { "custom-encoding", CHAR, WEBKITVIEW, TRUE },
+ { "default-encoding", CHAR, SETTINGS, TRUE },
+ { "default-font-family", CHAR, SETTINGS, TRUE },
+ { "default-font-size", INT, SETTINGS, TRUE },
+ { "default-monospace-font-size", INT, SETTINGS, TRUE },
+ { "editable", BOOL, WEBKITVIEW, TRUE },
+ { "enable-caret-browsing", BOOL, SETTINGS, TRUE },
+ { "enable-default-context-menu", BOOL, SETTINGS, TRUE },
+ { "enable-developer-extras", BOOL, SETTINGS, TRUE },
+ { "enable-dom-paste", BOOL, SETTINGS, TRUE },
+ { "enable-file-access-from-file-uris", BOOL, SETTINGS, TRUE },
+ { "enable-html5-database", BOOL, SETTINGS, TRUE },
+ { "enable-html5-local-storage", BOOL, SETTINGS, TRUE },
+ { "enable-java-applet", BOOL, SETTINGS, TRUE },
+ { "enable-offline-web-application-cache", BOOL, SETTINGS, TRUE },
+ { "enable-page-cache", BOOL, SETTINGS, TRUE },
+ { "enable-plugins", BOOL, SETTINGS, TRUE },
+ { "enable-private-browsing", BOOL, SETTINGS, TRUE },
+ { "enable-scripts", BOOL, SETTINGS, TRUE },
+ { "enable-site-specific-quirks", BOOL, SETTINGS, TRUE },
+ { "enable-spatial-navigation", BOOL, SETTINGS, TRUE },
+ { "enable-spell-checking", BOOL, SETTINGS, TRUE },
+ { "enable-universal-access-from-file-uris", BOOL, SETTINGS, TRUE },
+ { "enable-xss-auditor", BOOL, SETTINGS, TRUE },
+ { "encoding", CHAR, WEBKITVIEW, FALSE },
+ { "enforce-96-dpi", BOOL, SETTINGS, TRUE },
+ { "fantasy-font-family", CHAR, SETTINGS, TRUE },
+ { "full-content-zoom", BOOL, WEBKITVIEW, TRUE },
+ { "idle-timeout", INT, SOUPSESSION, TRUE },
+ { "icon-uri", CHAR, WEBKITVIEW, FALSE },
+ { "javascript-can-access-clipboard", BOOL, SETTINGS, TRUE },
+ { "javascript-can-open-windows-automatically", BOOL, SETTINGS, TRUE },
+ { "max-conns", INT, SOUPSESSION, TRUE },
+ { "max-conns-per-host", INT, SOUPSESSION, TRUE },
+ { "minimum-font-size", INT, SETTINGS, TRUE },
+ { "minimum-logical-font-size", INT, SETTINGS, TRUE },
+ { "monospace-font-family", CHAR, SETTINGS, TRUE },
+ { "print-backgrounds", BOOL, SETTINGS, TRUE },
+ { "progress", DOUBLE, WEBKITVIEW, FALSE },
+ { "proxy-uri", URI, SOUPSESSION, TRUE },
+ { "resizable-text-areas", BOOL, SETTINGS, TRUE },
+ { "sans-serif-font-family", CHAR, SETTINGS, TRUE },
+ { "serif-font-family", CHAR, SETTINGS, TRUE },
+ { "spell-checking-languages", CHAR, SETTINGS, TRUE },
+ { "ssl-ca-file", CHAR, SOUPSESSION, TRUE },
+ { "ssl-strict", BOOL, SOUPSESSION, TRUE },
+ { "tab-key-cycles-through-elements", BOOL, SETTINGS, TRUE },
+ { "timeout", INT, SOUPSESSION, TRUE },
+ { "title", CHAR, WEBKITVIEW, FALSE },
+ { "transparent", BOOL, WEBKITVIEW, TRUE },
+ { "use-ntlm", BOOL, SOUPSESSION, TRUE },
+ { "user-agent", CHAR, SETTINGS, TRUE },
+ { "user-stylesheet-uri", CHAR, SETTINGS, TRUE },
+ { "zoom-level", FLOAT, WEBKITVIEW, TRUE },
+ { "zoom-step", FLOAT, SETTINGS, TRUE },
{ NULL, 0, 0, 0 },
};
+static const gchar*
+webview_eval_js(WebKitWebView *view, const gchar *script, const gchar *file) {
+ WebKitWebFrame *frame;
+ JSGlobalContextRef context;
+ JSObjectRef globalobject;
+ JSStringRef js_file;
+ JSStringRef js_script;
+ JSValueRef js_result;
+ JSValueRef js_exc = NULL;
+ JSStringRef js_result_string;
+ GString *result = g_string_new(NULL);
+ size_t js_result_size;
+
+ frame = webkit_web_view_get_main_frame(WEBKIT_WEB_VIEW(view));
+ context = webkit_web_frame_get_global_context(frame);
+ globalobject = JSContextGetGlobalObject(context);
+
+ /* evaluate the script and get return value*/
+ js_script = JSStringCreateWithUTF8CString(script);
+ js_file = JSStringCreateWithUTF8CString(file);
+ js_result = JSEvaluateScript(context, js_script, globalobject, js_file, 0, &js_exc);
+ if (js_result && !JSValueIsUndefined(context, js_result)) {
+ js_result_string = JSValueToStringCopy(context, js_result, NULL);
+ js_result_size = JSStringGetMaximumUTF8CStringSize(js_result_string);
+
+ if (js_result_size) {
+ char js_result_utf8[js_result_size];
+ JSStringGetUTF8CString(js_result_string, js_result_utf8, js_result_size);
+ g_string_assign(result, js_result_utf8);
+ }
+
+ JSStringRelease(js_result_string);
+ }
+ else if (js_exc) {
+ size_t size;
+ JSStringRef prop, val;
+ JSObjectRef exc = JSValueToObject(context, js_exc, NULL);
+
+ printf("Exception occured while executing script:\n");
+
+ /* Print file */
+ prop = JSStringCreateWithUTF8CString("sourceURL");
+ val = JSValueToStringCopy(context, JSObjectGetProperty(context, exc, prop, NULL), NULL);
+ size = JSStringGetMaximumUTF8CStringSize(val);
+ if(size) {
+ char cstr[size];
+ JSStringGetUTF8CString(val, cstr, size);
+ printf("At %s", cstr);
+ }
+ JSStringRelease(prop);
+ JSStringRelease(val);
+
+ /* Print line */
+ prop = JSStringCreateWithUTF8CString("line");
+ val = JSValueToStringCopy(context, JSObjectGetProperty(context, exc, prop, NULL), NULL);
+ size = JSStringGetMaximumUTF8CStringSize(val);
+ if(size) {
+ char cstr[size];
+ JSStringGetUTF8CString(val, cstr, size);
+ printf(":%s: ", cstr);
+ }
+ JSStringRelease(prop);
+ JSStringRelease(val);
+
+ /* Print message */
+ val = JSValueToStringCopy(context, exc, NULL);
+ size = JSStringGetMaximumUTF8CStringSize(val);
+ if(size) {
+ char cstr[size];
+ JSStringGetUTF8CString(val, cstr, size);
+ printf("%s\n", cstr);
+ }
+ JSStringRelease(val);
+ }
+
+ /* cleanup */
+ JSStringRelease(js_script);
+ JSStringRelease(js_file);
+
+ return g_string_free(result, FALSE);
+}
+
+static gint
+luaH_webview_eval_js(lua_State *L)
+{
+ widget_t *w = luaH_checkudata(L, 1, &widget_class);
+ WebKitWebView *view = WEBKIT_WEB_VIEW(g_object_get_data(G_OBJECT(w->widget), "webview"));
+ const gchar *script = luaL_checkstring(L, 2);
+ const gchar *filename = luaL_checkstring(L, 3);
+
+ /* evaluate javascript script and push return result onto lua stack */
+ const gchar *result = webview_eval_js(view, script, filename);
+ lua_pushstring(L, result);
+ return 1;
+}
+
static void
progress_cb(WebKitWebView *v, gint p, widget_t *w)
{
@@ -172,6 +279,51 @@ load_finish_cb(WebKitWebView *v, WebKitWebFrame *f, widget_t *w)
lua_pop(L, 1);
}
+static gboolean
+mime_type_decision_cb(WebKitWebView *v, WebKitWebFrame *f,
+ WebKitNetworkRequest *r, gchar *mime, WebKitWebPolicyDecision *pd,
+ widget_t *w)
+{
+ (void) v;
+ (void) f;
+ lua_State *L = globalconf.L;
+ const gchar *uri = webkit_network_request_get_uri(r);
+ gint ret;
+
+ luaH_object_push(L, w->ref);
+ lua_pushstring(L, uri);
+ lua_pushstring(L, mime);
+ ret = luaH_object_emit_signal(L, -3, "mime-type-decision", 2, 1);
+
+ if (ret && !luaH_checkboolean(L, -1))
+ /* User responded with false, ignore request */
+ webkit_web_policy_decision_ignore(pd);
+ else if (!webkit_web_view_can_show_mime_type(v, mime))
+ webkit_web_policy_decision_download(pd);
+ else
+ webkit_web_policy_decision_use(pd);
+
+ lua_pop(L, ret + 1);
+ return TRUE;
+}
+
+static gboolean
+download_request_cb(WebKitWebView *v, GObject *dl, widget_t *w)
+{
+ (void) v;
+ const gchar *uri = webkit_download_get_uri((WebKitDownload *) dl);
+ const gchar *filename = webkit_download_get_suggested_filename((WebKitDownload *) dl);
+
+ lua_State *L = globalconf.L;
+ luaH_object_push(L, w->ref);
+ lua_pushstring(L, uri);
+ lua_pushstring(L, filename);
+ luaH_object_emit_signal(L, -3, "download-request", 2, 0);
+ lua_pop(L, 1);
+
+ return FALSE;
+}
+
static void
link_hover_cb(WebKitWebView *view, const char *t, const gchar *link, widget_t *w)
{
@@ -226,8 +378,6 @@ navigation_decision_cb(WebKitWebView *v, WebKitWebFrame *f,
const gchar *uri = webkit_network_request_get_uri(r);
gint ret;
- debug("Navigation requested: %s", uri);
-
luaH_object_push(L, w->ref);
lua_pushstring(L, uri);
ret = luaH_object_emit_signal(L, -2, "navigation-request", 1, 1);
@@ -238,7 +388,7 @@ navigation_decision_cb(WebKitWebView *v, WebKitWebFrame *f,
else
webkit_web_policy_decision_use(p);
- lua_pop(L, ret);
+ lua_pop(L, ret + 1);
return TRUE;
}
@@ -344,6 +494,22 @@ luaH_webview_clear_search(lua_State *L)
return 0;
}
+inline static GObject*
+get_settings_object(GtkWidget *view, property_value_scope scope)
+{
+ switch (scope) {
+ case SETTINGS:
+ return G_OBJECT(webkit_web_view_get_settings(WEBKIT_WEB_VIEW(view)));
+ case WEBKITVIEW:
+ return G_OBJECT(view);
+ case SOUPSESSION:
+ return G_OBJECT(Soup.session);
+ default:
+ break;
+ }
+ return NULL;
+}
+
static gint
luaH_webview_get_prop(lua_State *L)
{
@@ -352,15 +518,13 @@ luaH_webview_get_prop(lua_State *L)
GtkWidget *view = GTK_WIDGET(g_object_get_data(G_OBJECT(w->widget), "webview"));
GObject *ws;
property_tmp_values tmp;
+ SoupURI *u;
for (guint i = 0; i < LENGTH(properties); i++) {
if (g_strcmp0(properties[i].name, prop))
continue;
- if (properties[i].webkitview)
- ws = G_OBJECT(view);
- else
- ws = G_OBJECT(webkit_web_view_get_settings(WEBKIT_WEB_VIEW(view)));
+ ws = get_settings_object(view, properties[i].scope);
switch(properties[i].type) {
case BOOL:
@@ -389,6 +553,14 @@ luaH_webview_get_prop(lua_State *L)
lua_pushnumber(L, tmp.d);
return 1;
+ case URI:
+ g_object_get(ws, prop, &u, NULL);
+ tmp.c = soup_uri_to_string(u, 0);
+ lua_pushstring(L, tmp.c);
+ soup_uri_free(u);
+ g_free(tmp.c);
+ return 1;
+
default:
warn("unknown property type for: %s", properties[i].name);
break;
@@ -407,6 +579,7 @@ luaH_webview_set_prop(lua_State *L)
GtkWidget *view = g_object_get_data(G_OBJECT(w->widget), "webview");
GObject *ws;
property_tmp_values tmp;
+ SoupURI *u;
for (guint i = 0; i < LENGTH(properties); i++) {
if (g_strcmp0(properties[i].name, prop))
@@ -417,10 +590,7 @@ luaH_webview_set_prop(lua_State *L)
return 0;
}
- if (properties[i].webkitview)
- ws = G_OBJECT(view);
- else
- ws = G_OBJECT(webkit_web_view_get_settings(WEBKIT_WEB_VIEW(view)));
+ ws = get_settings_object(view, properties[i].scope);
switch(properties[i].type) {
case BOOL:
@@ -448,6 +618,16 @@ luaH_webview_set_prop(lua_State *L)
g_object_set(ws, prop, tmp.d, NULL);
return 0;
+ case URI:
+ tmp.c = (gchar*) luaL_checkstring(L, 3);
+ u = soup_uri_new(tmp.c);
+ if (SOUP_URI_VALID_FOR_HTTP(u))
+ g_object_set(ws, prop, u, NULL);
+ else
+ luaL_error(L, "cannot parse uri: %s", tmp.c);
+ soup_uri_free(u);
+ return 0;
+
default:
warn("unknown property type for: %s", properties[i].name);
break;
@@ -525,6 +705,10 @@ luaH_webview_index(lua_State *L, luakit_token_t token)
lua_pushcfunction(L, luaH_webview_set_scroll_horiz);
return 1;
+ case L_TK_EVAL_JS:
+ lua_pushcfunction(L, luaH_webview_eval_js);
+ return 1;
+
case L_TK_SEARCH:
lua_pushcfunction(L, luaH_webview_search);
return 1;
@@ -695,6 +879,8 @@ widget_webview(widget_t *w)
"signal::navigation-policy-decision-requested", (GCallback)navigation_decision_cb, w,
"signal::parent-set", (GCallback)parent_set_cb, w,
"signal::title-changed", (GCallback)title_changed_cb, w,
+ "signal::download-requested", (GCallback)download_request_cb, w,
+ "signal::mime-type-policy-decision-requested", (GCallback)mime_type_decision_cb, w,
NULL);
/* setup */
@@ -704,4 +890,4 @@ widget_webview(widget_t *w)
return w;
}
-// vim: ft=c:et:sw=4:ts=8:sts=4:enc=utf-8:tw=80
+// vim: ft=c:et:sw=4:ts=8:sts=4:tw=80
View
2 widgets/window.c
@@ -142,4 +142,4 @@ widget_window(widget_t *w)
return w;
}
-// vim: ft=c:et:sw=4:ts=8:sts=4:enc=utf-8:tw=80
+// vim: ft=c:et:sw=4:ts=8:sts=4:tw=80

0 comments on commit e982ac6

Please sign in to comment.
Something went wrong with that request. Please try again.