summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorportix <none@none>2012-05-17 23:09:27 +0200
committerportix <none@none>2012-05-17 23:09:27 +0200
commit6096a98157490ca7fa6ac71960c592c3ea1400fe (patch)
tree6c810a9ebed943f67a83069c632da51e56a2845c
parentd4f4a7faea6799346a6ccc1448f4750e4304be97 (diff)
parent86e9256be77d62324fc82e2bd1474fc96d1efd97 (diff)
downloaddwb-6096a98157490ca7fa6ac71960c592c3ea1400fe.zip
Merging branch scripts into default
-rw-r--r--Makefile22
-rw-r--r--api/Makefile3
-rw-r--r--api/jsapi.txt1832
-rw-r--r--config.mk11
-rw-r--r--doc/dwb.15578
-rw-r--r--examples/autoquvi.js31
-rw-r--r--scripts/lib/data.js35
-rw-r--r--scripts/lib/enums.js73
-rw-r--r--scripts/lib/extensions.js130
-rw-r--r--scripts/lib/signals.js92
-rw-r--r--src/application.c2
-rw-r--r--src/callback.c20
-rw-r--r--src/commands.c15
-rw-r--r--src/commands.h1
-rw-r--r--src/config.h4
-rw-r--r--src/download.c26
-rw-r--r--src/dwb.c123
-rw-r--r--src/dwb.h14
-rw-r--r--src/js.c61
-rw-r--r--src/js.h8
-rw-r--r--src/scripts.c1511
-rw-r--r--src/scripts.h75
-rw-r--r--src/soup.c11
-rw-r--r--src/soup.h2
-rw-r--r--src/util.c87
-rw-r--r--src/util.h5
-rw-r--r--src/view.c109
27 files changed, 7702 insertions, 2179 deletions
diff --git a/Makefile b/Makefile
index 8595ea5c..66a6c694 100644
--- a/Makefile
+++ b/Makefile
@@ -28,20 +28,24 @@ install-man: all
install -m 644 $(DOCDIR)/$(MANFILE) $(DESTDIR)$(MAN1DIR)/$(MANFILE)
install-data: all
- install -d $(DESTDIR)$(DATADIR)/$(REAL_NAME)/scripts
- install -m 644 $(JSDIR)/$(HINT_SCRIPT) $(DESTDIR)$(DATADIR)/$(REAL_NAME)/scripts/$(HINT_SCRIPT)
+ @# Lib
install -d $(DESTDIR)$(DATADIR)/$(REAL_NAME)/$(LIBDIR)
- install -m 644 $(LIBDIR)/$(INFO_FILE) $(DESTDIR)$(DATADIR)/$(REAL_NAME)/$(LIBDIR)/$(INFO_FILE)
- install -m 644 $(LIBDIR)/$(HEAD_FILE) $(DESTDIR)$(DATADIR)/$(REAL_NAME)/$(LIBDIR)/$(HEAD_FILE)
- install -m 644 $(LIBDIR)/$(SETTINGS_FILE) $(DESTDIR)$(DATADIR)/$(REAL_NAME)/$(LIBDIR)/$(SETTINGS_FILE)
- install -m 644 $(LIBDIR)/$(KEY_FILE) $(DESTDIR)$(DATADIR)/$(REAL_NAME)/$(LIBDIR)/$(KEY_FILE)
- install -m 644 $(LIBDIR)/$(PLUGIN_FILE) $(DESTDIR)$(DATADIR)/$(REAL_NAME)/$(LIBDIR)/$(PLUGIN_FILE)
- install -m 644 $(LIBDIR)/$(ERROR_FILE) $(DESTDIR)$(DATADIR)/$(REAL_NAME)/$(LIBDIR)/$(ERROR_FILE)
- install -m 644 $(LIBDIR)/$(LOCAL_FILE) $(DESTDIR)$(DATADIR)/$(REAL_NAME)/$(LIBDIR)/$(LOCAL_FILE)
+ for file in $(LIBDIR)/*; do \
+ install -m 644 $$file $(DESTDIR)$(DATADIR)/$(REAL_NAME)/$$file; \
+ done
+ @# Share
install -d $(DESTDIR)$(DATADIR)/pixmaps
install -m 644 $(SHAREDIR)/dwb.png $(DESTDIR)$(DATADIR)/pixmaps/dwb.png
install -d $(DESTDIR)$(DATADIR)/applications
install -m 644 $(SHAREDIR)/dwb.desktop $(DESTDIR)$(DATADIR)/applications/dwb.desktop
+ @# Libjs
+ install -d $(DESTDIR)$(DATADIR)/$(REAL_NAME)/$(LIBJSDIR)
+ for file in $(LIBJSDIR)/*; do \
+ install -m 644 $$file $(DESTDIR)$(DATADIR)/$(REAL_NAME)/$$file; \
+ done
+ @# Hints
+ install -d $(DESTDIR)$(DATADIR)/$(REAL_NAME)/$(JSDIR)
+ install -m 644 $(JSDIR)/$(HINT_SCRIPT) $(DESTDIR)$(DATADIR)/$(REAL_NAME)/$(JSDIR)/$(HINT_SCRIPT)
uninstall: uninstall-man uninstall-data
@echo "Removing executable from $(subst //,/,$(DESTDIR)$(BINDIR))"
diff --git a/api/Makefile b/api/Makefile
new file mode 100644
index 00000000..91c4497d
--- /dev/null
+++ b/api/Makefile
@@ -0,0 +1,3 @@
+jsapi.html: jsapi.txt
+ @echo gen $@
+ @asciidoc -b html5 -a toc2 $<
diff --git a/api/jsapi.txt b/api/jsapi.txt
new file mode 100644
index 00000000..0bbc6686
--- /dev/null
+++ b/api/jsapi.txt
@@ -0,0 +1,1832 @@
+= dwb's JavaScript API documentation =
+
+== Abstract ==
+
+*dwb* can be extended with different types of userscripts.
+This api documentation describes the javascript interface.
+
+== Getting Started ==
+Scripts that use the javascript api must be located in
++$XDG_CONFIG_HOME/dwb/userscripts+ like any other script.
+To include a userscript put a script with
+shebang
+
+-------
+#!javascript
+-------
+
+in the userscripts directory.
+
+All native javascript methods can be used in scripts, however there are
+limitations:
+
+* The execution context of userscripts is completely seperated from the web
+execution context. Due to security concerns it is not possible to communicate
+with the web execution context, it is only possible to inject scripts into the
+web context.
+* In contrast to the global +window+ object in the web execution context,
+the global object is a readonly object, i.e. it is not possible to set
+properties on the global object, see also <<Globaldata,global data>> for details.
+
+:numbered!:
+:caption:
+
+
+
+== Global ==
+
+Functions from the global object.
+
+=== Functions ===
+
+
+****
+[[bind]]
+[float]
+==== *bind()* ====
+
+[source,javascript]
+----
+void bind(String shortcut, Function callback)
+----
+
+Bind a javascript function to a shortcut. This is the preferred method of
+binding keys to shortcuts since the shortcut is evaluated using the native
+method, but also the keyPress-signal can be used to bind shortcuts.
+
+ ::
+
+_shortcut_;; a shortcut shortcut, will be parsed the same way as if set in
+dwb:keys
+_callback_;; callback function that will be called when the shortcut is pressed
+****
+
+****
+[[execute]]
+[float]
+==== *execute()* ====
+
+[source,javascript]
+----
+Boolean execute(String command)
+----
+
+Executes a dwb command
+
+ ::
+
+_command_;; a dwb command to execute, will be parsed the same way as if executed
+from commandline
+_returns_;; +true+ if execution was successful
+****
+
+
+****
+[[include]]
+[float]
+==== *include()* ====
+
+[source,javascript]
+----
+Boolean include(String path, [Boolean global])
+----
+
+Includes a file. Note that there is only one context, all scripts are
+executed in this context. Included files are not visible in other scripts unless
++true+ is passed as second parameter.
+
+ ::
+
+_path_;; Path to a file to include
+_global_;; Whether to include the script into the global scope, optional
+_returns_;; The return value of the included file
+****
+
+****
+[[timerStart]]
+[float]
+==== *timerStart()* ====
+
+[source,javascript]
+----
+Number timerStart(Number interval, Function func)
+----
+
+Executes a function repeatedly until the function returns +false+ or
+<<timerStop>> is called on the +id+ returned from this function
+
+ ::
+
+_interval_;; Interval in milliseconds
+_func_;; Function to execute
+_returns_;; An id that can be passed to timerStop
+****
+
+****
+[[timerStop]]
+[float]
+==== *timerStop()* ====
+
+[source,javascript]
+----
+Number timerStop(Number id)
+----
+
+Stops a timer started by <<timerStart>>
+
+ ::
+
+_id_;; The id returned from <<timerStart>>
+_returns_;; +true+ if the timer was stopped
+****
+
+****
+[[domainFromHost]]
+[float]
+==== *domainFromHost()* ====
+
+[source,javascript]
+----
+String domainFromHost(String hostname)
+----
+
+Gets the base domain name from a hostname where the base domain name is the
+effective second level domain name, e.g. for www.example.com it will be
+example.com, for www.example.co.uk it will be example.co.uk.
+
+ ::
+
+_hostname_;; a hostname
+_returns_;; the base domain
+****
+
+======
+.Example
+[source,javascript]
+---------------------------------
+execute("tabopen ixquick.com");
+
+// Execute a function once, similar to window.setTimeout()
+timerStart(2000, function() {
+ tabs.current.inject("alert('Hello world')");
+ return false;
+});
+---------------------------------
+======
+
+NOTE: Scripts included with +include+ are either visible in the global scope or
+invisible, even in the including script. To use an included script it can return
+an object with its public objects:
+
+======
+[source,javascript]
+---------------------------------
+// included script
+
+var private = 37;
+return {
+ getPrivate : function () {
+ return private;
+ }
+};
+
+// Scripts that includes the above
+var i = include("/path/to/script");
+var p = i.getPrivate(); // 37
+---------------------------------
+======
+
+
+
+[[Globalobjects]]
+== Global Objects ==
+
+[[data]]
+=== data ===
+The +data+ object can be used to determine internally used data securely. All
+properties are readonly Strings.
+
+****
+ ::
+
+_data.bookmarks_;; Bookmark file
+_data.cacheDir_;; Cache directory
+_data.configDir_;; Config directory
+_data.cookies_;; Cookie file
+_data.cookiesWhitelist_;; Whitelist for persistent cookies
+_data.customKeys_;; Custom keyboard shortcuts
+_data.history_;; History file
+_data.keys_;; Shortcuts configuration file
+_data.pluginsWhitelist_;; Whitelist for the plugin blocker
+_data.profile_;; Profile which will be +default+ unless another profile is specified on command line
+_data.quickmarks_;; Quickmark file
+_data.scriptWhitelist_;; Whitelist for scripts
+_data.session_;; File with stored sessions for this profile
+_data.sessionCookiesWhitelist_;; Whitelist for session cookies
+_data.settings_;; Settings configuration file
+_data.searchEngines_;; Searchengines
+****
+
+====
+.Example
+[source,javascript]
+---------------------------------
+// Get contents of the currently used bookmark file
+var bookmarks = io.read(data.bookmarks);
+--------------------------------
+====
+
+[[io]]
+=== io ===
+The +io+ object implements functions for input and output.
+
+****
+[[error]]
+[float]
+==== *error()* ====
+
+[source,javascript]
+----
+void io.error(String text)
+----
+
+Shows an error message in the browser window.
+
+ ::
+
+_text_;; The message to show
+****
+
+****
+[[notify]]
+[float]
+==== *notify()* ====
+
+[source,javascript]
+----
+void io.notify(String text)
+----
+
+Shows a message in the browser window.
+
+ ::
+
+_text_;; The message to show
+****
+
+****
+[[print]]
+[float]
+==== *print()* ====
+
+[source,javascript]
+----
+void io.print(String text, [String stream])
+----
+
+Print text to +stdout+ or +stderr+
+
+ ::
+
+_text_;; the text to print
+_stream_;; pass +"stderr"+ to print to stderr, optional
+****
+
+****
+[[prompt]]
+[float]
+==== *prompt()* ====
+
+[source,javascript]
+----
+String io.prompt(String text, [Boolean visible])
+----
+
+Gets user input synchronously.
+
+ ::
+
+_text_;; The message for the prompt
+_visible_;; Whether the chars should be visible, pass +false+ for a password
+prompt, default +true+, optional
+_returns_;; The text that was entered or +null+
+****
+
+
+****
+[[write]]
+[float]
+==== *write()* ====
+
+[source,javascript]
+----
+Boolean io.write(String path, String mode, String text)
+----
+
+Write to a file
+
+ ::
+
+_path_;; Path to a file to write to
+_mode_;; Either +"a"+ to append to the file, or +"w"+ to strip the file or
+create a new file.
+_text_;; The text that should be written to the file
+_returns_;; +true+ if writing was successful
+****
+
+****
+[[read]]
+[float]
+==== *read()* ====
+
+[source,javascript]
+----
+String io.read(String path)
+----
+
+Read from a file.
+
+ ::
+
+_path_;; Path to a file that should be read
+_returns_;; A string with the file content
+****
+
+
+====
+.Example
+[source,javascript]
+---------------------------------
+var text = io.read("/home/foo/textfile.txt");
+io.print(text);
+--------------------------------
+====
+
+[[system]]
+=== system ===
+
+The +system+ object implements system functions.
+
+****
+[[fileTest]]
+[float]
+==== *fileTest()* ====
+
+[source,javascript]
+----
+Boolean system.fileTest(String path, FileTest flags)
+----
+
+Checks for <<FileTest>> flags on a file.
+
+ ::
+
+_path_;; Path to a file to check
+_flags_;; The flags to test
+_returns_;; +true+ if any of the test on the flags is true
+****
+
+****
+[[mkdir]]
+[float]
+==== *mkdir()* ====
+
+[source,javascript]
+----
+Boolean system.mkdir(String path, Number mode)
+----
+
+Creates a directory and all parent directories.
+
+ ::
+
+_path_;; Path to create
+_mode_;; The permissions the directory will get
+_returns_;; +true+ if creation was successful or directory already existed
+****
+
+****
+[[spawn]]
+[float]
+==== *spawn()* ====
+
+[source,javascript]
+----
+SpawnError system.spawn(String command, [Function stdin], [Function stderr])
+----
+
+Executes a shell command using the default search path
+
+ ::
+
+_command_;; The command to execute
+_stdin(String)_;; Callback function for stdin, pass +null+ if only stderr is
+needed, optional
+_stderr(String)_;; Callback function for stderr, optional
+_returns_;; <<SpawnError>> if an error occured, 0 otherwise
+****
+
+****
+[[getEnv]]
+[float]
+==== *getEnv()* ====
+
+[source,javascript]
+----
+String system.getEnv(String name)
+----
+
+Get a system environment variable
+
+ ::
+
+_name_;; Name of the variable
+_returns_;; The variable or +null+ if the variable wasn't found
+****
+
+====
+.Example
+[source,javascript]
+------------
+var home = system.getEnv("HOME");
+// asynchronous wrapped read
+function asyncread(filename) {
+ system.spawn("cat " + filename, function (response) {
+ ...
+ });
+}
+asyncread(home + "/.bashrc");
+------------
+====
+
+
+[[tabs]]
+=== tabs ===
+The +tabs+ object implements functions and properties to get +webview+ objects.
+
+==== Properties ====
+
+****
+[float]
+==== *current* ====
+
+[source,javascript]
+----
+tabs.current webview read
+----
+
+The currently focused webview
+****
+
+****
+[float]
+==== *length* ====
+
+[source,javascript]
+----
+tabs.length Number read
+----
+
+Total number of tabs
+****
+
+****
+[float]
+==== *number* ====
+
+[source,javascript]
+----
+tabs.number Number read
+----
+
+Number of the currently focused tab
+****
+
+
+
+
+==== Functions ====
+
+****
+[float]
+==== *nth()* ====
+
+[source,javascript]
+----
+webview tabs.nth(Number n)
+----
+
+Gets the webview object of the nth tab
+
+ ::
+
+_n_;; Number of the tab
+_returns_;; The corresponding <<webview>>
+****
+
+
+====
+.Example
+[source,javascript]
+----
+var c = tabs.current;
+tabs.nth(2).loadUri(c.uri);
+----
+====
+
+[[Webkitobjects]]
+== Webkit objects ==
+
+All webkit objects correspond to gobject objects, i.e. they have the same
+properties, but the javascript properties are all camelcase.
+For example, a +WebKitWebView+ has the property +zoom-level+, the corresponding
+javascript property is +zoomLevel+:
+
+====
+[source,javascript]
+---------------------------------
+var webview = tabs.current
+webview.zoomLevel = webview.zoomLevel * 2;
+---------------------------------
+====
+
+Webkit objects should not be compared using +==+, since it may happen that the
+same gobject is represented by different javascript objects, instead every
+webkit object implements an equals method.
+
+****
+[float]
+==== *equals()* ====
+
+[source,javascript]
+----
+Boolean object.equals(Object compareObject)
+----
+
+Compare two webkit objects
+
+ ::
+
+_compareObject_;; The object to compare
+_returns_;; +true+ if the the corresponding gobjects are equal
+****
+
+
+====
+[float]
+==== *Example* ====
+[source,javascript]
+------------
+signals.connect("navigation" function(wv, frame) {
+ if (frame.equals(wv.mainFrame) {
+ ...
+ }
+});
+------------
+====
+
+An exception is the webview object, for webview objects +==+ always gives the
+same result as +equals+.
+
+
+[[webview]]
+=== webview ===
+The +webview+ object represents the widget that actually displays the site
+content.
+
+==== Properties ====
+
+The properties correspond to the gobject properties in camelcase. Additional
+properties are
+
+****
+[float]
+==== *allFrames* ====
+
+[source,javascript]
+----
+wv.allFrames array of frames read
+----
+
+All frames of a webview including the mainframe
+****
+
+****
+[float]
+==== *mainFrame* ====
+
+[source,javascript]
+----
+wv.mainFrame frame read
+----
+
+The main frame of the webview
+****
+
+****
+[float]
+==== *number* ====
+
+[source,javascript]
+----
+wv.number frame read
+----
+
+The number of the webview, starting at 0
+****
+
+****
+[float]
+==== *focusedFrame* ====
+
+[source,javascript]
+----
+wv.focusedFrame frame read
+----
+
+The focused frame of the webview
+****
+
+==== Functions ====
+
+****
+[float]
+==== *inject()* ====
+
+[source,javascript]
+----
+Boolean wv.inject(String script, [Boolean global])
+----
+
+Injects a script into a webview
+
+ ::
+
+_script_;; the script to inject
+_global_;; +true+ to inject it into the global scope, +false+ to encapsulate it
+in a function, optional
+_returns_;; +true+ if the script was injected, +false+ if an error occured
+****
+
+****
+[float]
+==== *history()* ====
+
+[source,javascript]
+----
+void wv.history(Number steps)
+----
+
+Loads a history item +steps+ away from the current history item
+
+ ::
+
+_steps_;; Number of steps, pass a negative value to go back in history
+****
+
+****
+[float]
+==== *loadUri()* ====
+
+[source,javascript]
+----
+Boolean wv.loadUri(String uri, [Function callback])
+----
+
+Load an uri in a webview.
+
+ ::
+
+_uri_;; The uri to load
+_callback_;; A callback function that will be called when the load status
+changes, return +true+ to stop the emission, optional
+_returns_;; +true+ if the uri is loaded
+****
+
+
+****
+[float]
+==== *reload()* ====
+
+[source,javascript]
+----
+void wv.reload(void)
+----
+
+Reload a webview
+****
+
+
+====
+[float]
+==== *Example* ====
+[source,javascript]
+------------
+var wv = tabs.current;
+
+wv.loadUri("http://www.example.com", function() {
+ if (wv.loadStatus == LoadStatus.finished) {
+ wv.inject("alert('Hello ' + wv.uri + "!!!");
+
+ return true;
+ }
+});
+------------
+====
+
+
+NOTE: If a script is injected from a <<loadStatus>>-callback the script must be
+injected after +LoadStatus.committed+ has been emitted.
+On +LoadStatus.committed+ the document
+hasn't been created, if the script modifies the DOM it should be injected on
++LoadStatus.finished+.
+If only +LoadStatus.committed+ or +loadFinished.committed+ are used it is better
+to use the corresponding signals instead to reduce overhead.
+
+
+[[frame]]
+=== frame ===
+
+A frame represents a +frame+ or +iframe+. Due to same origin policy it
+is not possible to inject scripts from a <<webview>> into iframes with a
+different domain. For this purpose the +frame+ object can be used.
+
+==== Properties ====
+
+The properties correspond to the gobject properties in camelcase.
+Additional properties are
+
+****
+[float]
+==== *domain* ====
+
+[source,javascript]
+----
+frame.domain frame read
+----
+
+The domain name of the frame which is the effective second level domain
+****
+
+****
+[float]
+==== *host* ====
+
+[source,javascript]
+----
+frame.host frame read
+----
+
+The host name of the frame
+****
+
+====
+To get the domain or hostname of a webview
+[source,javascript]
+----
+webview.mainFrame.domain
+webview.mainFrame.host
+----
+can be used.
+====
+
+
+
+==== Functions ====
+
+****
+[float]
+==== *inject()* ====
+
+[source,javascript]
+----
+Boolean frame.inject(String script, [Boolean global])
+----
+
+Injects a script into a frame
+
+ ::
+
+_script_;; the script to inject
+_global_;; +true+ to inject it into the global scope, +false+ to encapsulate it
+in a function, optional
+_returns_;; +true+ if the script was injected, +false+ if an error occured
+****
+
+
+[[Download]]
+=== download ===
+
+Corresponds to a +WebKitDownload+.
+
+==== Constructor ====
+
+****
+[float]
+==== *Download()* ====
+[source,javascript]
+----
+new Download(String uri)
+----
+
+Constructs a new download
+
+ ::
+_uri_;; The uri of the download
+****
+
+==== Functions ====
+
+****
+[float]
+==== *start()* ====
+
+[source,javascript]
+----
+Boolean download.start([Function callback])
+----
+
+Starts a download
+
+ ::
+
+_callback_;; A callback function that will be executed whenever the
+<<DownloadStatus>> changes, return +true+ to stop the emission, optional.
+****
+
+
+****
+[float]
+==== *cancel()* ====
+
+[source,javascript]
+----
+void download.cancel()
+----
+
+Cancels a download
+****
+
+====
+.Example
+[source,javascript]
+------
+var download = new Download("http://www.example.org/foo.pdf");
+var filename = "/tmp/" + download.suggestedFilename;
+download.destinationUri = "file://" + filename;
+download.start(function () {
+ if (download.status == DownloadStatus.finished) {
+ system.spawn("xpdf " + filename);
+ }
+});
+------
+====
+
+
+[[request]]
+=== request ===
+
+Corresponds to a +WebKitNavigationRequest+.
+
+[[navigationAction]]
+=== navigationAction ===
+
+Corresponds to a +WebKitWebNavigationAction+.
+
+
+== Signals ==
+With the +signals+ object *dwb* communicates with the script on certain events.
+To connect to a signal one can call the connect function that is implemented by
+the signals object, that takes 2 arguments, the name of the signal and a
+callback function.
+
+The callback function has a varying number of parameters.
+The last paramter is always a json-object which might be empty or contain
+additional data relevant to the signal.
+A callback function should either return +true+ or +false+ or nothing which is
+equivalent to +false+.
+If multiple callbacks are connected to the same signal and one callback
+function returns +true+ the overall return value will be +true+.
+
+*dwb* only emits signals as long as one callback is connected to a signal. To
+reduce overhead one should disconnect from signals when no longer
+needed.
+
+The +signals+ object is not a readonly object, properties can be added to the
+object which are visible in all scripts but it should be avoided to add
+properties on the +signals+ object. +signals+ should only be used to connect to
+signals or define custom signals.
+
+The +signals+ object implements the following functions
+
+=== Functions ===
+
+[[connect]]
+[float]
+==== *connect()* ====
+
+****
+[source,javascript]
+----
+Number signals.connect(String signal, Function callback)
+----
+Connect to a signal
+
+ ::
+
+_signal_;; The signal to connect to
+_callback_;; The callback function which will be called when the signal is emitted
+_returns_;; Unique id for this connection, can be passed to <<disconnect>>
+****
+
+****
+[[emit]]
+[float]
+==== *emit()* ====
+
+[source,javascript]
+----
+Boolean signals.emit(String signal, ...)
+----
+
+Emits a signal with a variable number of arguments passed to the callback
+function
+
+ ::
+
+_signal_;; The signal to emit
+_..._;; Objects passed to the callback function
+_returns_;; Overall return value from all connected callback functions
+****
+
+****
+[[disconnect]]
+[float]
+==== *disconnect()* ====
+
+[source,javascript]
+----
+Boolean signals.disconnect(Number id)
+----
+disconnect from a signal
+
+ ::
+
+_id_;; The id returned from <<connect>>
+_returns_;; +true+ if the signal was disconnected, +false+ if the signal
+wasn't found or was already disconnected.
+****
+
+
+****
+[[disconnectByFunction]]
+[float]
+==== *disconnectByFunction()* ====
+
+[source,javascript]
+----
+Boolean signals.disconnectByFunction(Function callback)
+----
+disconnect from all signals with matching callback function
+
+ ::
+
+_callback_;; The callback function passed to <<connect>>
+_returns_;; +true+ if signals were disconnected, +false+ if no signal
+was disconnected
+****
+
+****
+[[disconnectByName]]
+[float]
+==== *disconnectByName()* ====
+
+[source,javascript]
+----
+Boolean signals.disconnectByName(String signal)
+----
+
+disconnect from all signals with matching name,
+It should be avoided to call +disconnectByName+
+on signals implemented by dwb since it will completely stop the emission of the
+signal in all scripts.
+
+ ::
+
+_signal_;; The callback function passed to <<connect>>
+_returns_;; +true+ if signals were disconnected, +false+ if no signal
+was disconnected
+****
+
+=== Emitted signals ===
+
+Custom signals can be created by simply calling
+
+[source,javascript]
+-----
+signals.connect("nameOfNewSignal", callbackFunction);
+-----
+
+
+
+Signals emitted by dwb are the following:
+
+
+****
+[[buttonPress]]
+[float]
+==== *buttonPress* ====
+
+[source,javascript]
+----
+Boolean callback(webview, hittestresult, json)
+----
+
+Emitted when a button is pressed on the <<webview>>, return +true+ to prevent
+the default action
+
+ ::
+
+_webview_;; The <<webview>> which received the signal
+_hittestresult_;; Hittestresult under the cursor
+_json.button_;; The button that is pressed, usually a value between 1 and 5
+_json.state_;; A bitmap of modifiers pressed, see <<Modifier>>
+_json.time_;; The time in milliseconds when the button was pressed
+_json.type_;; A <<ClickType>>
+_json.x_;; x-position relative to the window
+_json.xRoot_;; x-position relative to the screen
+_json.y_;; y-position relative to the window
+_json.yRoot_;; y-position relative to the screen
+****
+
+****
+[[buttonRelease]]
+[float]
+==== *buttonRelease* ====
+
+[source,javascript]
+----
+Boolean callback(webview, hittestresult, json)
+----
+
+Emitted when a button is released, return +true+ to prevent the default action
+
+ ::
+
+_webview_;; The <<webview>> which received the signal
+_hittestresult_;; Hittestresult under the cursor
+_json_;; Same as <<buttonPress>> but without _json.type_
+****
+
+****
+[[createTab]]
+[float]
+==== *createTab* ====
+
+[source,javascript]
+----
+Boolean callback(webview)
+----
+
+Emitted when a tab is created
+
+ ::
+
+_webview_;; The <<webview>> that corresponds to the created tab
+****
+
+****
+[[closeTab]]
+[float]
+==== *closeTab* ====
+
+[source,javascript]
+----
+Boolean callback(webview)
+----
+
+Emitted when a tab is closed
+
+ ::
+
+_webview_;; The <<webview>> that corresponds to the tab
+****
+
+****
+[[download]]
+[float]
+==== *download* ====
+
+[source,javascript]
+----
+Boolean callback(webview, download, json)
+----
+
+Emitted before a download starts, return +true+ if the signal was handled.
+
+ ::
+
+_webview_;; The <<webview>> that emitted the signal
+_download_;; The <<Download>>
+_json.referer_;; The referer
+_json.mimeType_;; The mimetype of the file
+****
+
+****
+[[downloadStatus]]
+[float]
+==== *downloadStatus* ====
+
+[source,javascript]
+----
+Boolean callback(download)
+----
+
+Emitted when the <<DownloadStatus>> changes.
+
+ ::
+
+_download_;; The <<Download>>
+****
+
+
+****
+[[frameCreated]]
+[float]
+==== *frameCreated* ====
+
+[source,javascript]
+----
+void callback(webview, frame)
+----
+
+Emitted when the frame is created
+
+ ::
+
+_webview_;; The webview the frame belongs to
+_frame_;; The frame
+****
+
+****
+[[frameStatus]]
+[float]
+==== *frameStatus* ====
+
+[source,javascript]
+----
+void callback(webview, frame)
+----
+
+Emitted when the <<LoadStatus>> of a frame changes
+
+ ::
+
+_webview_;; The webview the frame belongs to
+_frame_;; The frame
+****
+
+****
+[[hoveringOverLink]]
+[float]
+==== *hoveringOverLink* ====
+
+[source,javascript]
+----
+void callback(webview, json)
+----
+
+Emitted when the mouse is over a link
+
+ ::
+
+_webview_;; The webview that emitted the signal
+_json.uri_;; The uri of the link or +null+ if there is no link under the pointer, i.e. the pointer left a link
+_json.title_;; The link's title or +null+ if the pointer left a link
+****
+
+****
+[[keyPress]]
+[float]
+==== *keyPress* ====
+
+[source,javascript]
+----
+Boolean callback(webview, json)
+----
+
+Emitted when a key is pressed, return +true+ to prevent the default action
+
+ ::
+
+_webview_;; The focused webview
+_json.isModifier_;; Whether or not the key is a modifier
+_json.keyCode_;; Hardware keycode
+_json.keyVal_;; Keycode as listed in gdkkeysyms.h
+_json.name_;; A string represantation of the key
+_json.state_;; A bitmap of modifiers pressed, see <<Modifier>>
+****
+
+****
+[[keyRelease]]
+[float]
+==== *keyRelease* ====
+
+[source,javascript]
+----
+Boolean callback(webview, json)
+----
+
+Emitted when a key is released, return +true+ to prevent the default action
+
+ ::
+
+_webview_;; The focused webview
+_json_;; Same as <<keyPress>>
+****
+
+
+****
+[[loadCommitted]]
+[float]
+==== *loadCommitted* ====
+
+[source,javascript]
+----
+void callback(webview)
+----
+
+Emitted when the load has just commited, no data has been loaded when this
+signal is emitted. This is the preferred signal for injected scripts that do not
+manipulate the DOM.
+
+ ::
+
+_webview_;; The webview that emitted the signal
+****
+
+****
+[[loadFinished]]
+[float]
+==== *loadFinished* ====
+
+[source,javascript]
+----
+Boolean callback(webview)
+----
+
+Emitted when the site has completely loaded.
+
+ ::
+
+_webview_;; The webview that emitted the signal
+****
+
+****
+[[loadStatus]]
+[float]
+==== *loadStatus* ====
+
+[source,javascript]
+----
+void callback(webview)
+----
+
+Emitted when the load status changes
+
+ ::
+
+_webview_;; The webview that emitted the signal
+****
+
+****
+[[mimeType]]
+[float]
+==== *mimeType* ====
+
+[source,javascript]
+----
+Boolean callback(webview, frame, request, json)
+----
+
+Decide whether or not to show a given mimetype. Return +true+ to stop the request.
+
+ ::
+
+_webview_;; The webview that emitted the signal
+_frame_;; The frames requires the decision
+_request_;; The network request
+_json.mimeType_;; The mimetype
+****
+
+****
+[[navigation]]
+[float]
+==== *navigation* ====
+
+[source,javascript]
+----
+Boolean callback(webview, frame, request, action)
+----
+
+Emitted before a new site is loaded, return +true+ to stop the request.
+
+ ::
+
+_webview_;; The webview that emitted the signal
+_frame_;; The frame that requires the navigation
+_request_;; The network request
+_action_;; The navigation action
+****
+
+****
+[[resource]]
+[float]
+==== *resource* ====
+
+[source,javascript]
+----
+Boolean callback(webview, frame, request, response)
+----
+
+Emitted before a new resource is going to be loaded
+
+ ::
+
+_webview_;; The webview that emitted the signal
+_frame_;; The frame that dispatched the request
+_request_;; The network request
+_response_;; The network response
+****
+
+****
+[[tabFocus]]
+[float]
+==== *tabFocus* ====
+
+[source,javascript]
+----
+Boolean callback(webview, json)
+----
+
+Emitted when another tab gets focus, return +true+ to stop the event
+
+ ::
+
+_webview_;; The new tab
+_json.last_;; The number of the previously focused tab
+****
+
+
+
+====
+.Example
+[source,javascript]
+------
+// Prevent example.com from being loaded
+function navigationCallback(wv, frame, request, action) {
+ if (/.*\.example\.com.*/.test(request.uri)) {
+ return true;
+ }
+}
+signals.connect("navigation", navigationCallback);
+------
+====
+
+== Enum objects ==
+Enum objects are objects that have only readonly properties, mapping
+gtk/webkit enums to javascript objects.
+
+****
+[[ButtonContext]]
+[float]
+==== *ButtonContext* ====
+
+[source,javascript]
+--------
+const ButtonContext = {
+ document : 1 << 1,
+ link : 1 << 2,
+ image : 1 << 3,
+ media : 1 << 4,
+ selection : 1 << 5,
+ editable : 1 << 6
+};
+--------
+****
+
+****
+[[ChecksumType]]
+[float]
+==== *ChecksumType* ====
+
+[source,javascript]
+--------
+const ChecksumType = {
+ md5 : 0,
+ sha1 : 1,
+ sha256 : 2
+};
+--------
+****
+
+****
+[[ClickType]]
+[float]
+==== *ClickType* ====
+
+[source,javascript]
+--------
+const ClickType = {
+ click : 4,
+ doubleClick : 5,
+ tripleClick : 6
+};
+--------
+****
+
+****
+[[DownloadStatus]]
+[float]
+==== *DownloadStatus* ====
+
+[source,javascript]
+-------
+const DownloadStatus = {
+ error : -1,
+ created : 0,
+ started : 1,
+ cancelled : 2,
+ finished : 3
+};
+-------
+****
+
+****
+[[FileTest]]
+[float]
+==== *FileTest* ====
+
+[source,javascript]
+-------
+const FileTest = {
+ regular : 1 << 0,
+ symlink : 1 << 1,
+ dir : 1 << 2,
+ executable : 1 << 3,
+ exists : 1 << 4
+};
+-------
+****
+
+****
+[[LoadStatus]]
+[float]
+==== *LoadStatus* ====
+
+[source,javascript]
+---------
+const LoadStatus = {
+ provisional : 0,
+ committed : 1,
+ finished : 2,
+ firstVisualLayout : 3,
+ failed : 4
+};
+---------
+****
+
+****
+[[Modifier]]
+[float]
+==== *Modifier* ====
+
+[source,javascript]
+--------
+const Modifier = {
+ Shift : 1 << 0,
+ Lock : 1 << 1,
+ Control : 1 << 2,
+ Mod1 : 1 << 3,
+ Mod2 : 1 << 4,
+ Mod3 : 1 << 5,
+ Mod4 : 1 << 6,
+ Mod5 : 1 << 7,
+ Button1 : 1 << 8,
+ Button2 : 1 << 9,
+ Button3 : 1 << 10,
+ Button4 : 1 << 11,
+ Button5 : 1 << 12,
+ Super : 1 << 26,
+ Hyper : 1 << 27,
+ Meta : 1 << 28,
+ Release : 1 << 30,
+ Modifier : 0x5c001fff
+};
+--------
+****
+
+****
+[[NavigationReason]]
+[float]
+==== *NavigationReason* ====
+
+[source,javascript]
+--------
+const NavigationReason = {
+ linkClicked : 0,
+ formSubmitted : 1,
+ backForward : 2,
+ reload : 3,
+ formResubmitted : 4,
+ other : 5
+};
+--------
+****
+
+****
+[[SpawnError]]
+[float]
+==== *SpawnError* ====
+[source,javascript]
+--------
+const SpawnError = {
+ success : 0,
+ spawnFailed : 1<<0,
+ stdoutFailed : 1<<1,
+ stderrFailed : 1<<2
+};
+--------
+****
+
+
+[[Globaldata]]
+== Global data ==
+Since all scripts share the same execution context, they are encapsulated in a
+function. To avoid conflicts with other scripts it is not allowed to set properties
+on the global object, i.e.
+
+[source,javascript]
+-------
+#!javascript
+
+// not allowed, the global object is readonly
+number = 0;
+io.print(number); // undefined
+
+// always use var instead
+var number = 0;
+io.print(number2); // 0
+
+// won't work either
+function foo() {
+ bar = 1;
+}
+foo();
+io.print(bar); // undefined
+-------
+
+For sharing data between scripts either signals can be created or the
++globals+-object can be used. To share data with the globals object securely when the
+scripts are loaded the script can return an +init+ function that will be called
+after all scripts have been initialized:
+
+
+.Script 1
+[source,javascript]
+-------
+#!javascript
+
+// set when the script is initialized.
+globals.foo = "bar";
+-------
+
+.Script 2
+[source,javascript]
+-------
+#!javascript
+
+// The behaviour is undefined, depending on if Script 1 was initialized before
+// Script 2 or the other way round.
+io.print(globals.foo) // undefined or "bar"
+
+// Will be called after all scripts have been initialized
+return {
+ init : function () {
+ // globals.foo has been initialized
+ io.print(globals.foo); // "bar"
+ }
+};
+-------
+
+One exception is <<include>>, scripts that are explicitly included into the
+global scope setting the second parameter to true are visible in every script.
+
+.foo
+[source,javascript]
+-------
+var foo = "bar";
+-------
+
+.Script 1
+
+[source,javascript]
+-------
+#!javascript
+
+include("/path/to/foo", true); // visible in every script
+-------
+.Script 2
+
+[source,javascript]
+-------
+#!javascript
+
+// Make sure Script 1 has been initialized
+return {
+ init : function() {
+ io.print(foo); // "bar";
+ }
+};
+-------
+
+[[Extensions]]
+== Extensions ==
+*dwb* provides the possibility to load extensions.
+It is recommended to implement javascript-userscripts as an extension to have
+consistent configuration locations for scripts.
+
+The +extensions+ object has the following properties and functions
+
+=== Properties ===
+
+****
+[float]
+==== *enableDebugging* ====
+
+[source,javascript]
+----
+extensions.enableDebugging Boolean read
+----
+
+Whether to enable debugging messages.
+****
+
+=== Functions ===
+
+****
+[[extensiondebug,debug]]
+[float]
+==== *debug()* ====
+
+[source,javascript]
+----
+void extensions.debug(String name, String message)
+----
+Prints a debug message and the call stack to stdout, +enableDebugging+ must be
+set to +true+ in order to print debug messages.
+
+ ::
+
+_name_;; Name of the extension
+_message_;; The debug message to print.
+****
+
+****
+[[extensionload,load]]
+[float]
+==== *load()* ====
+
+[source,javascript]
+----
+Boolean extensions.load(String name, [Object config])
+----
+Loads an extension
+
+ ::
+
+_name_;; Name of the extension
+_config_;; The config for the script, if omitted the config is read from
+$XDG_CONFIG_HOME/dwb/extensionrc, optional
+_returns_;; True if the extension was loaded
+****
+
+****
+[[error]]
+[float]
+==== *error()* ====
+
+[source,javascript]
+----
+void extensions.error(String name, String message|Error e, [String message])
+----
+
+Print an error message and call stack to stderr.
+
+ ::
+
+_name_;; Name of the extension
+_message|e_;; The error message or an Error
+_message_;; If the second parameter is an Error, an optional message can be
+specified.
+****
+
+****
+[[message]]
+[float]
+==== *message()* ====
+
+[source,javascript]
+----
+void extensions.message(String name, String message)
+----
+
+Print a consistent message to stderr
+
+ ::
+
+_name_;; Name of the extension
+_message_;; The message
+****
+
+
+****
+[[warning]]
+[float]
+==== *warning()* ====
+
+[source,javascript]
+----
+void extensions.warning(String name, String message)
+----
+
+Print a consistent warning to stderr
+
+ ::
+
+_name_;; Name of the extension
+_message_;; The warning message
+****
+
+
+.Example
+
+[source,javascript]
+--------
+#!javascript
+
+extensions.load("foobar");
+--------
+
+.Writing extensions
+
+The default searchpath for extensions isn +$XDG_DATA_HOME/dwb/extensions+ and
++SHARE_DIR/dwb/extensions+ where the
++SHARE_DIR+ with sharedirectory being the share-dir of the installation.
+
+The configuration for extensions is in +$XDG_CONFIG_HOME/dwb/extensionsrc+ and should
+return a javascript object.
+
+Every extension must implement one function named +init+ that takes one
+argument, the config for the extension. The function should return +true+ if the
+extension was successfully loaded, +false+ otherwise.
++init+ should be returned from the extension.
+
+.Example
+
+A extension called *foobar* in +$HOME/.local/share/dwb/extensions/foobar+.
+
+[source,javascript]
+--------
+function foo(val) {
+ ....
+}
+function bar(val) {
+ ....
+}
+return {
+ init : function (config) {
+ if (config.foo > 36) {
+ bar(config.foo);
+ foo(config.bar);
+ return true;
+ }
+ return false;
+ }
+};
+--------
+
+====
+.Example extensionrc
+[source,javascript]
+--------
+return {
+ foobar : { bar : "X", foo : 37 }, // config for extension foobar
+ barfoo : { } // config for extension barfoo
+
+};
+--------
+====
+
+
+// vim: set ft=asciidoc:
diff --git a/config.mk b/config.mk
index b43636bc..c00e8148 100644
--- a/config.mk
+++ b/config.mk
@@ -7,6 +7,8 @@ DOCDIR=doc
SRCDIR=src
JSDIR=scripts
LIBDIR=lib
+LIBJSDIR=$(JSDIR)/$(LIBDIR)
+LIBJSFILES=$(LIBJSDIR)/signals.js $(LIBJSDIR)/enums.js $(LIBJSDIR)/data.js
SHAREDIR=share
UTILDIR=util
SUBDIRS=$(SRCDIR) $(UTILDIR)
@@ -125,6 +127,7 @@ CFLAGS += -DERROR_FILE=\"$(ERROR_FILE)\"
CFLAGS += -DLOCAL_FILE=\"$(LOCAL_FILE)\"
CFLAGS += -DHINT_SCRIPT=\"$(HINT_SCRIPT)\"
CFLAGS += -DSYSTEM_DATA_DIR=\"$(DATADIR)\"
+CFLAGS += -DLIBJS_DIR=\"$(LIBJSDIR)\"
ifeq ($(shell pkg-config --exists '$(LIBSOUP) >= 2.38' && echo 1), 1)
CFLAGS += -DWITH_LIBSOUP_2_38=1
@@ -136,10 +139,10 @@ CFLAGS += -DHAS_EXECINFO
endif
ifeq (USEGTK3, 1)
-CFLAGS+=-DGTK_DISABLE_SINGLE_INCLUDES
-CFLAGS+=-DGTK_DISABLE_DEPRECATED
-CFLAGS+=-DGDK_DISABLE_DEPRECATED
-CFLAGS+=-DGSEAL_ENABLE
+CPPFLAGS+=-DGTK_DISABLE_SINGLE_INCLUDES
+CPPFLAGS+=-DGTK_DISABLE_DEPRECATED
+CPPFLAGS+=-DGDK_DISABLE_DEPRECATED
+CPPFLAGS+=-DGSEAL_ENABLE
endif
CFLAGS +=-I/usr/lib/dwb/
diff --git a/doc/dwb.1 b/doc/dwb.1
index 0b120729..f3bd7700 100644
--- a/doc/dwb.1
+++ b/doc/dwb.1
@@ -1,2130 +1,3584 @@
-.TH DWB 1 "March 2012" dwb "USER COMMANDS"
-.SH NAME
+'\" t
+.\" Title: dwb
+.\" Author: [FIXME: author] [see http://docbook.sf.net/el/author]
+.\" Generator: DocBook XSL Stylesheets v1.76.1 <http://docbook.sf.net/>
+.\" Date: 05/14/2012
+.\" Manual: \ \&
+.\" Source: \ \&
+.\" Language: English
+.\"
+.TH "DWB" "1" "05/14/2012" "\ \&" "\ \&"
+.\" -----------------------------------------------------------------
+.\" * Define some portability stuff
+.\" -----------------------------------------------------------------
+.\" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+.\" http://bugs.debian.org/507673
+.\" http://lists.gnu.org/archive/html/groff/2009-02/msg00013.html
+.\" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+.ie \n(.g .ds Aq \(aq
+.el .ds Aq '
+.\" -----------------------------------------------------------------
+.\" * set default formatting
+.\" -----------------------------------------------------------------
+.\" disable hyphenation
+.nh
+.\" disable justification (adjust text to left margin only)
+.ad l
+.\" -----------------------------------------------------------------
+.\" * MAIN CONTENT STARTS HERE *
+.\" -----------------------------------------------------------------
+.SH "NAME"
dwb \- dynamic web browser
-.SH SYNOPSIS
-.B dwb
-[ options ] [ <urls> ]
-.SH DESCRIPTION
-dwb is a small webbrowser based on WebKit and GTK which aims to be mostly
-keyboard-driven.
-
-.SH COMMAND LINE ARGUMENTS
-.TP
-.BR \-e ,\ --embed \ <wid>
-Embed dwb into <wid>.
-.TP
-.BR \-f ,\ --force
-Force restoring a previously saved session, even if it seems that another
-process has opened a session with the same name.
-.TP
-.BR \-l ,\ --list-sessions
-List previously saved sessions. A
-.I *
-indicates that another instance has currently opened the session.
-.TP
-.BR \-n ,\ --new-instance
-New instance, overrides setting
-.IR single-instance .
-.TP
-.BR \-p ,\ --profile \ <name>
-Load configuration for profile
-.I <name>
-.TP
-.BR \-r ,\ --restore \ <name>
-Restore session with name
-.I <sessionname>
-or the default session, if sessionname is omitted.
-.TP
-.BR \-R ,\ --override-restore
-Open a new session, even if
-.I save-session
-is enabled.
-.TP
-.BR \-x ,\ --execute \ <commands>
-Execute a list of dwb commands separated by
-.IR ;; ,
-see
-.B CUSTOM COMMANDS
+.SH "SYNOPSIS"
+.sp
+\fBdwb\fR [\fIOPTIONS\fR] [ \fIURLS\fR ]
+.SH "DESCRIPTION"
+.sp
+dwb(1) is a small webbrowser based on WebKit and GTK which aims to be mostly keyboard\-driven\&.
+.SH "OPTIONS"
+.PP
+\fB\-e, \-\-embed\fR=\fIwid\fR
+.RS 4
+Embed dwb into <wid>\&.
+.RE
+.PP
+\fB\-f, \-\-force\fR
+.RS 4
+Force restoring a previously saved session, even if it seems that another process has opened a session with the same name\&.
+.RE
+.PP
+\fB\-l, \-\-list\-sessions\fR
+.RS 4
+List previously saved sessions\&. A
+\fI*\fR
+indicates that another instance has currently opened the session\&.
+.RE
+.PP
+\fB\-n, \-\-new\-instance\fR
+.RS 4
+New instance, overrides setting
+\fIsingle\-instance\fR\&.
+.RE
+.PP
+\fB\-p, \-\-profile\fR=\fIprofilename\fR
+.RS 4
+Load configuration for profile
+\fIprofilename\fR\&.
+.RE
+.PP
+\fB\-r, \-\-profile\fR=\fIsessionname\fR
+.RS 4
+Restore session with name
+\fIsessionname\fR
+or the default session, if
+\fIsessionname\fR
+is omitted\&.
+.RE
+.PP
+\fB\-R, \-\-override\-restore\fR
+.RS 4
+Open a new session, even if
+\fIsave\-session\fR
+is enabled\&.
+.RE
+.PP
+\fB\-x, \-\-execute\fR=\fIcommands\fR
+.RS 4
+Execute a list of dwb commands seperated by
+\fI;;\fR, see
+\fICUSTOM COMMANDS\fR
and
-.B COMMAND OVERVIEW
-for details.
-If
-.I single instance
-is enabled all commands will be executed in the primary instance.
-.TP
-.B \-v
-Show version information and exit.
-.TP
-.B <urls>
-URLs loaded on startup.
-
-.SH MODES
+\fICOMMAND OVERVIEW\fR
+for details\&. If
+\fIsingle instance\fR
+is enabled all commands will be executed in the primary instance\&.
+.RE
+.PP
+\fB\-v, \-\-version\fR
+.RS 4
+Show version information and exit\&.
+.RE
+.SH "MODES"
+.sp
dwb has different modes:
-.TP
-.B Normal mode
-The default mode. Pressing "Escape" will get you always back to
-normal mode.
-.TP
-.B Insert mode
-Used for editing text elements in a webpage.
-.TP
-.B Hint mode
-Follow links via hints.
-.TP
-.B Command mode
-Execute dwb commands from the builtin commandline.
-
-
-.SH SHORTCUTS
-Note: all shortcuts are case sensitive, e.g. C-H means Control-Shift-h.
-.SS "Normal mode shortcuts:"
-.TP
-.BR [n]j
-Scroll [n times] down (command:
-.BR scroll_down ,
-aliases:
-.BR down ).
-.TP
-.BR [n]k
-Scroll [n times] up (command:
-.BR scroll_up ,
-aliases:
-.BR up ).
-.TP
-.BR [n]h
-Scroll [n times] left (command:
-.BR scroll_left ,
-aliases:
-.BR left ).
-.TP
-.BR [n]l
-Scroll [n times] right (command
-.BR scroll_right ,
-aliases:
-.BR right ).
-.TP
-.BR [n]gg
-Scroll to the top or to n% of the page (command
-.BR scroll_top ,
-aliases:
-.BR top ).
-.TP
-.BR [n]G
-Scroll to the bottom or to n% of the page (command
-.BR scroll_bottom ,
-aliases:
-.BR bottom ).
-.TP
-.BR [n]C-f
-Scroll [n] pages down (command
-.BR scroll_page_down ,
-aliases:
-.BR pagedown ).
-.TP
-.BR [n]C-b
-Scroll [n] pages up (comman
-.BR scroll_page_up ,
-aliases:
-.BR pageup ).
-.TP
-.BR [n]C-d
-Scroll [n] half pages down (command
-.BR scroll_halfpage_down ,
-aliases:
-.BR halfdown ).
-.TP
-.BR [n]C-u
-Scroll [n] half pages up (command
-.BR scroll_halfpage_up ,
-aliases:
-.BR halfup ).
-.TP
-.B :
-Enter Command mode.
-.TP
-.BR o
-Open new url in the focused tab, the argument $URI will be replaced by the
-current uri (command
-.BR open ,
-aliases:
-.BR o ).
-.TP
-.BR go
-Open url in the focused tab, set current url in the navigation bar (command
-.BR open_url ).
-.TP
-.BR O
-Open url in a new tab, the argument $URI will be replaced by the current uri (command
-.BR tabopen ,
-aliases:
-.BR topen ,
-.BR t ).
-.TP
-.BR gO
-Open url in a new tab, set current url in the navigation bar (command
-.IR tabopen_url ).
-.TP
-.BR xo
-Open url in a new tab in background, the argument $URI will be repaced with the
-current uri (command
-.BR backopen ,
-aliases:
-.BR bopen ).
-.TP
-.BR xO
-Open url in a new tab in background, set current url in the navigation bar (command
-.IR backopen_url ).
-.TP
-.BR wo
-Open url in a new instance (command
-.BR winopen ,
-aliases:
-.BR wopen ,
-.BR w ).
-.TP
-.BR wO
-Open url in a new window, set current url in the navigation bar (command
-.BR winopen_url ).
-.TP
-.BR i
-Enter insert mode (command
-.BR insert_mode ,
-aliases:
-.BR i ,
-.BR insert ).
-.TP
-.B C-n
-Enter normal mode.
-.TP
-.BR ga
-Add a new blank tab (command
-.BR tab_new ).
-.TP
-.BR d
-Close current tab (command
-.BR close_tab ,
-aliases:
-.BR close ).
-.TP
-.BR [n]gc
-Clear tab n or of current tab, clears the history of the tab and loads
-.IR about:blank .
-(command
-.BR clear_tab ,
-aliases:
-.BR clear ).
-.TP
-.BR co
+.PP
+\fBNormal mode\fR
+.RS 4
+The default mode\&. Pressing
+\fIEscape\fR
+always enter normal mode, all keyboard inputs will be interpreted as shortcuts, keypresses are not sent to the webview\&.
+.RE
+.PP
+\fBInsert mode\fR
+.RS 4
+Used for editing text elements in a webpage\&.
+.RE
+.PP
+\fBHint mode\fR
+.RS 4
+Follow links via hints\&.
+.RE
+.PP
+\fBCommand mode\fR
+.RS 4
+Execute dwb commands from the builtin commandline\&.
+.RE
+.SH "SHORTCUTS"
+.SS "Normal mode shortcuts"
+.PP
+\fB[n]j\fR
+.RS 4
+Scroll [n times] down (command:
+\fIscroll_down\fR, aliases:
+\fIdown\fR)\&.
+.RE
+.PP
+\fB[n]k\fR
+.RS 4
+Scroll [n times] up (command:
+\fIscroll_up\fR, aliases:
+\fIup\fR)\&.
+.RE
+.PP
+\fB[n]h\fR
+.RS 4
+Scroll [n times] left (command:
+\fIscroll_left\fR, aliases:
+\fIleft\fR)\&.
+.RE
+.PP
+\fB[n]l\fR
+.RS 4
+Scroll [n times] right (command:
+\fIscroll_right\fR, aliases:
+\fIright\fR)\&.
+.RE
+.PP
+\fB[n]gg\fR
+.RS 4
+Scroll to the top or to n% of the page (command:
+\fIscroll_top\fR, aliases:
+\fItop\fR)\&.
+.RE
+.PP
+\fB[n]G\fR
+.RS 4
+Scroll to the bottom or to n% of the page (command:
+\fIscroll_bottom\fR, aliases:
+\fIbottom\fR)\&.
+.RE
+.PP
+\fB[n]C\-f\fR
+.RS 4
+Scroll [n] pages down (command:
+\fIscroll_page_down\fR, aliases:
+\fIpagedown\fR)\&.
+.RE
+.PP
+\fB[n]C\-b\fR
+.RS 4
+Scroll [n] pages up (command:
+\fIscroll_page_up\fR, aliases:
+\fIpageup\fR)\&.
+.RE
+.PP
+\fB[n]C\-d\fR
+.RS 4
+Scroll [n] half pages down (command:
+\fIscroll_halfpage_down\fR, aliases:
+\fIhalfdown\fR)\&.
+.RE
+.PP
+\fB[n]C\-u\fR
+.RS 4
+Scroll [n] half pages up (command:
+\fIscroll_halfpage_up\fR, aliases:
+\fIhalfup\fR)\&.
+.RE
+.PP
+\fB:\fR
+.RS 4
+Enter Command mode\&.
+.RE
+.PP
+\fBo\fR
+.RS 4
+Open new url in the focused tab, the argument $URI will be replaced by the current uri (command:
+\fIopen\fR, aliases:
+\fIo\fR)\&.
+.RE
+.PP
+\fBgo\fR
+.RS 4
+Open url in the focused tab, set current url in the navigation bar (command:
+\fIopen_url\fR)\&.
+.RE
+.PP
+\fBO\fR
+.RS 4
+Open url in a new tab, the argument $URI will be replaced by the current uri (command:
+\fItabopen\fR, aliases:
+\fItopen\fR,
+\fIt\fR)\&.
+.RE
+.PP
+\fBgO\fR
+.RS 4
+Open url in a new tab, set current url in the navigation bar (command
+\fItabopen_url\fR)\&.
+.RE
+.PP
+\fBxo\fR
+.RS 4
+Open url in a new tab in background, the argument $URI will be repaced with the current uri (command:
+\fIbackopen\fR, aliases:
+\fIbopen\fR
+)\&.
+.RE
+.PP
+\fBxO\fR
+.RS 4
+Open url in a new tab in background, set current url in the navigation bar (command:
+\fIbackopen_url\fR)\&.
+.RE
+.PP
+\fBwo\fR
+.RS 4
+Open url in a new instance (command:
+\fIwinopen\fR, aliases:
+\fIwopen\fR,
+\fIw\fR)\&.
+.RE
+.PP
+\fBi\fR
+.RS 4
+Enter insert mode (command:
+\fIinsert_mode\fR, aliases:
+\fIi\fR,
+\fIinsert\fR)\&.
+.RE
+.PP
+\fBC\-n\fR
+.RS 4
+Enter normal mode\&.
+.RE
+.PP
+\fBga\fR
+.RS 4
+Add a new blank tab (command:
+\fItab_new\fR)\&.
+.RE
+.PP
+\fBd\fR
+.RS 4
+Close current tab (command:
+\fIclose_tab\fR, aliases:
+\fIclose\fR)\&.
+.RE
+.PP
+\fB[n]gc\fR
+.RS 4
+Clear tab n or of current tab, clears the history of the tab and loads
+\fIabout:blank\fR\&. (command
+\fIclear_tab\fR, aliases:
+\fIclear\fR)\&.
+.RE
+.PP
+\fBco\fR
+.RS 4
Close all tabs except for the current one (command
-.BR only ).
-.TP
-.BR C-q
+\fIonly\fR)\&.
+.RE
+.PP
+\fBC\-q\fR
+.RS 4
Quit (command
-.BR quit ,
-aliases:
-.BR q ).
-.TP
-.BR u
+\fIquit\fR, aliases:
+\fIq\fR)\&.
+.RE
+.PP
+\fBu\fR
+.RS 4
Undo closing last tab (command
-.BR undo ,
-aliases:
-.BR u ).
-.TP
-.BR C-h
+\fIundo\fR, aliases:
+\fIu\fR)\&.
+.RE
+.PP
+\fBC\-h\fR
+.RS 4
Open the default startpage (command
-.BR start_page ,
-aliases:
-.BR home ).
-.TP
-.BR H
-Go back (command
-.BR history_back ,
-aliases:
-.BR back ,
-.BR ba ).
-.TP
-.BR L
-Go forward (command
-.BR history_forward ,
-aliases:
-.BR forward ,
-.BR fo ).
-.TP
-.BR th
-Go back in a new tab (command
-.BR tab_hist_back,
-aliases:
-.BR tabback ,
-.BR tba ).
-.TP
-.BR tl
-Go forward in a new tab (command
-.BR tab_hist_forward ,
-aliases:
-.BR tabforward ,
-.BR tfo ).
-.TP
-.BR wh
-Go back in a new window (command
-.BR win_hist_back ,
-aliases:
-.BR winback ,
-.BR wba ).
-.TP
-.BR wl
-Go forward in a new window (command
-.BR win_hist_forward ,
-aliases:
-.BR winforward ,
-.BR wfo ).
-.TP
-.BR /
+\fIstart_page\fR, aliases:
+\fIhome\fR)\&.
+.RE
+.PP
+\fBH\fR
+.RS 4
+Go back (command
+\fIhistory_back\fR, aliases:
+\fIback\fR,
+\fIba\fR)\&.
+.RE
+.PP
+\fBL\fR
+.RS 4
+Go forward (command
+\fIhistory_forward\fR, aliases:
+\fIforward\fR,
+\fIfo\fR)\&.
+.RE
+.PP
+\fBth\fR
+.RS 4
+Go back in a new tab (command
+\fItab_hist_back\fR, aliases:
+\fItabback\fR,
+\fItba\fR)\&.
+.RE
+.PP
+\fBtl\fR
+.RS 4
+Go forward in a new tab (command
+\fItab_hist_forward\fR, aliases:
+\fItabforward\fR,
+\fItfo\fR)\&.
+.RE
+.PP
+\fBwh\fR
+.RS 4
+Go back in a new window (command
+\fIwin_hist_back\fR, aliases:
+\fIwinback\fR,
+\fIwba\fR)\&.
+.RE
+.PP
+\fBwl\fR
+.RS 4
+Go forward in a new window (command
+\fIwin_hist_forward\fR, aliases:
+\fIwinforward\fR,
+\fIwfo\fR)\&.
+.RE
+.PP
+\fB/\fR
+.RS 4
Find forward (command
-.BR find_forward ,
-alias:
-.BR ffind ).
-.TP
-.BR ?
+\fIfind_forward\fR, alias:
+\fIffind\fR)\&.
+.RE
+.PP
+\fB?\fR
+.RS 4
Find backward (command
-.BR find_backward ,
-alias
-.BR bfind ).
-.TP
-.BR c/
+\fIfind_backward\fR, alias
+\fIbfind\fR)\&.
+.RE
+.PP
+\fBc/\fR
+.RS 4
Find forward, ignore case (command
-.BR find_forward_ic ,
-alias:
-.BR iffind ).
-.TP
-.BR c?
+\fIfind_forward_ic\fR, alias:
+\fIiffind\fR)\&.
+.RE
+.PP
+\fBc?\fR
+.RS 4
Find backward, ignore case (command
-.BR find_backward_ic ,
-alias
-.BR ibfind ).
-.TP
-.BR M
+\fIfind_backward_ic\fR, alias
+\fIibfind\fR)\&.
+.RE
+.PP
+\fBM\fR
+.RS 4
Add a bookmark (command
-.BR bookmark ,
-aliases:
-.BR bmark ,
-.BR bma ).
-.TP
-.B gb
+\fIbookmark\fR, aliases:
+\fIbmark\fR,
+\fIbma\fR)\&.
+.RE
+.PP
+\fBgb\fR
+.RS 4
Show Bookmarks (command
-.BR bookmarks ,
-aliases:
-.BR bmarks ,
-.BR bmas ).
-.TP
-.B gB
+\fIbookmarks\fR, aliases:
+\fIbmarks\fR,
+\fIbmas\fR)\&.
+.RE
+.PP
+\fBgB\fR
+.RS 4
Show Bookmarks, open bookmark in a new tab (command
-.BR tab_bookmarks ,
-aliases:
-.BR tabmarks ).
-.TP
-.B wB
+\fItab_bookmarks\fR, aliases:
+\fItabmarks\fR)\&.
+.RE
+.PP
+\fBwB\fR
+.RS 4
Show Bookmarks, open bookmark in a new window (command
-.BR win_bookmarks ,
-aliases:
-.BR winmarks ).
-.TP
-.BR m
-Add a quickmark (command
-.BR save_quickmark ,
-aliases:
-.BR quickmark ,
-.BR qmark ).
-.TP
-.BR b
-Open quickmark (command
-.BR quickmark ,
-aliases:
-.BR qmarks ).
-.TP
-.BR B
+\fIwin_bookmarks\fR, aliases:
+\fIwinmarks\fR)\&.
+.RE
+.PP
+\fBm\fR
+.RS 4
+Add a quickmark (command
+\fIsave_quickmark\fR, aliases:
+\fIquickmark\fR,
+\fIqmark\fR)\&.
+.RE
+.PP
+\fBb\fR
+.RS 4
+Open quickmark (command
+\fIquickmark\fR, aliases:
+\fIqmarks\fR)\&.
+.RE
+.PP
+\fBB\fR
+.RS 4
Open quickmark in a new tab (command
-.BR tab_quickmark ,
-aliases:
-.BR tabqmarks ).
-.TP
-.BR wb[:graph:]
+\fItab_quickmark\fR, aliases:
+\fItabqmarks\fR)\&.
+.RE
+.PP
+\fBwb[:graph:]\fR
+.RS 4
Open quickmark in a new window (command
-.BR win_quickmark ,
-aliases:
-.BR winqmarks ).
-.TP
-.BR [n]r
+\fIwin_quickmark\fR, aliases:
+\fIwinqmarks\fR)\&.
+.RE
+.PP
+\fB[n]r\fR
+.RS 4
Reload tab n or current tab if n is omitted (command
-.BR reload ,
-aliases:
-.BR re ).
-.TP
-.BR [n]R
+\fIreload\fR, aliases:
+\fIre\fR)\&.
+.RE
+.PP
+\fB[n]R\fR
+.RS 4
Reload tab n or current tab if n is omitted without using any cached data (command
-.BR reload_bypass_cache ,
-aliases:
-.BR refull ).
-.TP
-.BR [n]C-s
+\fIreload_bypass_cache\fR, aliases:
+\fIrefull\fR)\&.
+.RE
+.PP
+\fB[n]C\-s\fR
+.RS 4
Stop loading of tab n or of current tab is [n] is omitted (command
-.BR stop_loading ,
-aliases:
-.BR stop ,
-.BR st ).
-.TP
-.BR [n]+
+\fIstop_loading\fR, aliases:
+\fIstop\fR,
+\fIst\fR)\&.
+.RE
+.PP
+\fB[n]+\fR
+.RS 4
Zoom in [n times] (command
-.BR zoom_in ,
-aliases:
-.BR zi ).
-.TP
-.BR [n]-
-Zoom out [n times] (command
-.BR zoom_out ,
-aliases:
-.BR zo ).
-.TP
-.BR [n]=
-Zoom to n percent or to 100% if n is omitted(command
-.BR zoom,
-aliases:
-.BR z ).
-.TP
-.BR sf
+\fIzoom_in\fR, aliases:
+\fIzi\fR)\&.
+.RE
+.PP
+\fB[n]\-\fR
+.RS 4
+Zoom out [n times] (command
+\fIzoom_out\fR, aliases:
+\fIzo\fR)\&.
+.RE
+.PP
+\fB[n]=\fR
+.RS 4
+Zoom to n percent or to 100% if n is omitted(command
+\fIzoom\fR, aliases:
+\fIz\fR)\&.
+.RE
+.PP
+\fBsf\fR
+.RS 4
Save all configuration files (command
-.BR save ).
-.TP
-.BR ZZ
-Save current session and exit (command
-.BR save_session ,
-aliases:
-.BR wq ).
-.TP
-.BR gZZ
-Save current session with name and exit (command
-.BR save_named_session ,
-aliases:
-.BR wqn ).
-.TP
-.BR [n]J
-Cycle focus [n tab] forwards. (command
-.BR focus_next ,
-aliases:
-.BR tabnext ).
-.TP
-.BR [n]K
-Cycle focus [n tab] backwards. (command
-.BR focus_prev ,
-aliases:
-.BR tabprev ).
-.TP
-.BR [n]T
-Focus nth tab or first, if n is omitted.
-(command
-.BR focus_tab ,
-aliases:
-.BR tab ).
-.TP
-.BR [n]gm
-Move current tab to position [n] or to first position if n is omitted.
-(command
-.BR tab_move ,
-aliases:
-.BR tabm ).
-.TP
-.BR [n]gl
-Move current tab [n] positions left.
-(command
-.BR tab_move_left ,
-aliases:
-.BR tabl ).
-.TP
-.BR [n]gr
-Move current tab [n] positions right.
-(command
-.BR tab_move_right ,
-aliases:
-.BR tabr ).
-.TP
-.BR gt
-Show all open tabs. (command
-.BR buffers ,
-aliases:
-.BR bu ).
-.TP
-.BR [n]C-P
-Protect tab [n]. Closing this tab must be confirmed (command
-.BR protect ,
-aliases:
-.BR prot ).
-.TP
-.BR [n]xd
-Lock tab [n]. Locking a tab will lock this tab to the current domain, it's not
-possible to navigate to another domain until unlocked.
-.BR lock_domain ,
-aliases:
-.BR dlock ).
-.TP
-.BR [n]xu
-Lock tab [n]. Locking a tab will lock this tab to the current uri, it's not
-possible to navigate to another uri until unlocked.
-.BR lock_uri ,
-aliases:
-.BR ulock ).
-.TP
-.BR f
-Show hints (command
-.BR hints ,
-aliases:
-.BR hints ,
-.BR hi ).
-.TP
-.BR F
-Show hints, open link in a new foreground tab. (command
-.BR hints_tab ,
-aliases:
-.BR tabhints ,
-.BR thi ).
-.TP
-.BR ;b
-Show hints, open link in a new background tab. (command
-.BR hints_background ,
-aliases:
-.BR backhints ,
-.BR bhi ).
-.TP
-.BR wf
-Show hints, open link in a new tab. (command
-.BR hints_win ,
-aliases:
-.BR winhints ,
-.BR whi ).
-.TP
-.BR ;i
-Follow image (command
-.BR hints_images ,
-aliases:
-.BR ihints ,
-ihi ).
-.TP
-.BR ;I
-Follow image in a new tab (command
-.BR hints_images_tab ,
-aliases:
-.BR itabhints ,
-.BR ithi ).
-.TP
-.BR .i
-Follow image in a background tab (command
-.BR hints_images_background ,
-aliases:
-.BR ibackhints ).
-.TP
-.BR ;e
-Focus editable elements via hints (command
-.BR hints_editable ,
-aliases:
-.BR ehints ,
-.BR ehi ).
-.TP
-.BR ;o
-Set hint\'s url in commandline (command
-.BR hints_url ,
-aliases:
-.BR uhints ,
-.BR uhi ).
-.TP
-.BR ;O
-Set hint\'s url in commandline, open in a new tab (command
-.BR hints_url_tab ,
-aliases:
-.BR utabhints ,
-.BR uthi ).
-.TP
-.BR .o
-Set hint\'s url in commandline, open in a background tab (command
-.BR hints_url_background ,
-aliases:
-.BR ubackhints ).
-.TP
-.BR ;d
-Download via hints (command
-.BR hints_download ,
-aliases:
-.BR dhints ).
-.TP
-.BR ;y
-Save link location to clipboard (command
-.BR hints_clipboard ,
-aliases:
-.BR chints ,
-.BR chi ).
-.TP
-.BR ;Y
-Save link location to primary selection (command
-.BR hints_primary ,
-aliases:
-.BR phints ,
-.BR phi ).
-.TP
-.BR ;r
-Rapid hint mode, each matching hint opens a new tab in background. (command
-.BR hints_rapid ,
-aliases:
-.BR rhints ,
-.BR rhi ).
-.TP
-.BR ;R
-Rapid hint mode, each matching hint opens a new window. (command
-.BR hints_rapid_win ,
-aliases:
-.BR wrhints ,
-.BR wrhi ).
-.TP
-.BR gf
-Toggle "view source" (command
-.BR view_source ,
-aliases:
-.BR source ,
-.BR so ).
-.TP
-.BR CC
-Allow persistent cookie for the current website. The domain will be saved in
-.IR cookies.allow .
-Cookies that are allowed by the cookies.allow whitelist are stored in
-$XDG_CONFIG_HOME/dwb/$profilename/cookies. (command
-.BR allow_cookie ,
-aliases:
-.BR cookie ).
-.TP
-.BR CS
-Allow session cookie for the current website. The domain will be saved in
-.IR cookies_session.allow .
-This is only useful if 'cookies-store-policy' is set to 'never', see
-cookies-store-policy for details. (command
-.BR allow_session_cookie ,
-aliases:
-.BR scookie ).
-.TP
-.BR CT
-Allow session cookies for the current website temporarily. Only first party
-cookies are allowed. The domain is not saved to a whitelist and the cookies will
-not be saved persitently. (command
-.BR allow_session_cookie_tmp ,
-aliases:
-.BR tcookie ).
-.TP
-.BR [n]yy
-Yank the url of tab n or of current tab if n is omitted to clipboard
-(command
-.BR yank ).
-.TP
-.BR yY
-Yank the url of tab n or of current tab if n is omitted to primary
-selection (command
-.BR yank_primary ,
-aliases:
-.BR pyank ).
-.TP
-.BR yt
-Yank the title of tab n or of current tab if n is omitted to clipboard
-(command
-.BR yank_title ,
-aliases:
-.BR tyank ).
-.TP
-.BR yT
-Yank the title of tab n or of current tab if n is omitted to primary
-selection (command
-.BR yank_title_primary ,
-aliases:
-.BR tpyank ).
-.TP
-.BR pp
-Paste from clipboard (command
-.BR paste ).
-.TP
-.BR pP
+\fIsave\fR)\&.
+.RE
+.PP
+\fBZZ\fR
+.RS 4
+Save current session and exit (command
+\fIsave_session\fR, aliases:
+\fIwq\fR)\&.
+.RE
+.PP
+*gZZ *
+.RS 4
+Save current session with name and exit (command
+\fIsave_named_session\fR, aliases:
+\fIwqn\fR)\&.
+.RE
+.PP
+\fB[n]J\fR
+.RS 4
+Cycle focus [n tab] forwards\&. (command
+\fIfocus_next\fR, aliases:
+\fItabnext\fR)\&.
+.RE
+.PP
+\fB[n]K\fR
+.RS 4
+Cycle focus [n tab] backwards\&. (command
+\fIfocus_prev\fR, aliases:
+\fItabprev\fR)\&.
+.RE
+.PP
+\fB[n]T\fR
+.RS 4
+Focus nth tab or first, if n is omitted\&. (command
+\fIfocus_tab\fR, aliases:
+\fItab\fR)\&.
+.RE
+.PP
+\fB[n]gm\fR
+.RS 4
+Move current tab to position [n] or to first position if n is omitted\&. (command
+\fItab_move\fR, aliases:
+\fItabm\fR)\&.
+.RE
+.PP
+\fB[n]gl\fR
+.RS 4
+Move current tab [n] positions left\&. (command
+\fItab_move_left\fR, aliases:
+\fItabl\fR)\&.
+.RE
+.PP
+\fB[n]gr\fR
+.RS 4
+Move current tab [n] positions right\&. (command
+\fItab_move_right\fR, aliases:
+\fItabr\fR)\&.
+.RE
+.PP
+\fBgt\fR
+.RS 4
+Show all open tabs\&. (command
+\fIbuffers\fR, aliases:
+\fIbu\fR)\&.
+.RE
+.PP
+\fB[n]C\-P\fR
+.RS 4
+Protect tab [n]\&. Closing this tab must be confirmed (command
+\fIprotect\fR, aliases:
+\fIprot\fR)\&.
+.RE
+.PP
+\fB[n]xd\fR
+.RS 4
+Lock tab [n]\&. Locking a tab will lock this tab to the current domain, it\(cqs not possible to navigate to another domain until unlocked\&.
+\fIlock_domain\fR, aliases:
+\fIdlock\fR)\&.
+.RE
+.PP
+\fB[n]xu\fR
+.RS 4
+Lock tab [n]\&. Locking a tab will lock this tab to the current uri, it\(cqs not possible to navigate to another uri until unlocked\&.
+\fIlock_uri\fR, aliases:
+\fIulock\fR)\&.
+.RE
+.PP
+\fBf\fR
+.RS 4
+Show hints (command
+\fIhints\fR, aliases:
+\fIhints\fR,
+\fIhi\fR)\&.
+.RE
+.PP
+\fBF\fR
+.RS 4
+Show hints, open link in a new foreground tab\&. (command
+\fIhints_tab\fR, aliases:
+\fItabhints\fR,
+\fIthi\fR)\&.
+.RE
+.PP
+\fB;b\fR
+.RS 4
+Show hints, open link in a new background tab\&. (command
+\fIhints_background\fR, aliases:
+\fIbackhints\fR,
+\fIbhi\fR)\&.
+.RE
+.PP
+\fBwf\fR
+.RS 4
+Show hints, open link in a new tab\&. (command
+\fIhints_win\fR, aliases:
+\fIwinhints\fR,
+\fIwhi\fR)\&.
+.RE
+.PP
+\fB;i\fR
+.RS 4
+Follow image (command
+\fIhints_images\fR, aliases:
+\fIihints\fR,
+\fIihi\fR)\&.
+.RE
+.PP
+\fB;I\fR
+.RS 4
+Follow image in a new tab (command
+\fIhints_images_tab\fR, aliases:
+\fIitabhints\fR,
+\fIithi\fR)\&.
+.RE
+.PP
+\fB\&.i\fR
+.RS 4
+Follow image in a background tab (command
+\fIhints_images_background\fR, aliases:
+\fIibackhints\fR)\&.
+.RE
+.PP
+\fB;e\fR
+.RS 4
+Focus editable elements via hints (command
+\fIhints_editable\fR, aliases:
+\fIehints\fR,
+\fIehi\fR)\&.
+.RE
+.PP
+\fB;o\fR
+.RS 4
+Set hint\(cqs url in commandline (command
+\fIhints_url\fR, aliases:
+\fIuhints\fR,
+\fIuhi\fR)\&.
+.RE
+.PP
+\fB;O\fR
+.RS 4
+Set hint\(cqs url in commandline, open in a new tab (command
+\fIhints_url_tab\fR, aliases:
+\fIutabhints\fR,
+\fIuthi\fR)\&.
+.RE
+.PP
+\fB\&.o\fR
+.RS 4
+Set hint\(cqs url in commandline, open in a background tab (command
+\fIhints_url_background\fR, aliases:
+\fIubackhints\fR)\&.
+.RE
+.PP
+\fB;d\fR
+.RS 4
+Download via hints (command
+\fIhints_download\fR, aliases:
+\fIdhints\fR)\&.
+.RE
+.PP
+\fB;y\fR
+.RS 4
+Save link location to clipboard (command
+\fIhints_clipboard\fR, aliases:
+\fIchints\fR,
+\fIchi\fR)\&.
+.RE
+.PP
+\fB;Y\fR
+.RS 4
+Save link location to primary selection (command
+\fIhints_primary\fR, aliases:
+\fIphints\fR,
+\fIphi\fR)\&.
+.RE
+.PP
+\fB;r\fR
+.RS 4
+Rapid hint mode, each matching hint opens a new tab in background\&. (command
+\fIhints_rapid\fR, aliases:
+\fIrhints\fR,
+\fIrhi\fR)\&.
+.RE
+.PP
+\fB;R\fR
+.RS 4
+Rapid hint mode, each matching hint opens a new window\&. (command
+\fIhints_rapid_win\fR, aliases:
+\fIwrhints\fR,
+\fIwrhi\fR)\&.
+.RE
+.PP
+\fBgf\fR
+.RS 4
+Toggle "view source" (command
+\fIview_source\fR, aliases:
+\fIsource\fR,
+\fIso\fR)\&.
+.RE
+.PP
+\fBCC\fR
+.RS 4
+Allow persistent cookie for the current website\&. The domain will be saved in
+\fIcookies\&.allow\fR\&. Cookies that are allowed by the cookies\&.allow whitelist are stored in $XDG_CONFIG_HOME/dwb/$profilename/cookies\&. (command
+\fIallow_cookie\fR, aliases:
+\fIcookie\fR)\&.
+.RE
+.PP
+\fBCS\fR
+.RS 4
+Allow session cookie for the current website\&. The domain will be saved in
+\fIcookies_session\&.allow\fR\&. This is only useful if
+\fIcookies\-store\-policy\fR
+is set to
+\fInever\fR, see cookies\-store\-policy for details\&. (command
+\fIallow_session_cookie\fR, aliases:
+\fIscookie\fR)\&.
+.RE
+.PP
+\fBCT\fR
+.RS 4
+Allow session cookies for the current website temporarily\&. Only first party cookies are allowed\&. The domain is not saved to a whitelist and the cookies will not be saved persitently\&. (command
+\fIallow_session_cookie_tmp\fR, aliases:
+\fItcookie\fR)\&.
+.RE
+.PP
+\fB[n]yy\fR
+.RS 4
+Yank the url of tab n or of current tab if n is omitted to clipboard (command
+\fIyank\fR)\&.
+.RE
+.PP
+\fByY\fR
+.RS 4
+Yank the url of tab n or of current tab if n is omitted to primary selection (command
+\fIyank_primary\fR, aliases:
+\fIpyank\fR)\&.
+.RE
+.PP
+\fByt\fR
+.RS 4
+Yank the title of tab n or of current tab if n is omitted to clipboard (command
+\fIyank_title\fR, aliases:
+\fItyank\fR)\&.
+.RE
+.PP
+\fByT\fR
+.RS 4
+Yank the title of tab n or of current tab if n is omitted to primary selection (command
+\fIyank_title_primary\fR, aliases:
+\fItpyank\fR)\&.
+.RE
+.PP
+\fBpp\fR
+.RS 4
+Paste from clipboard (command
+\fIpaste\fR)\&.
+.RE
+.PP
+\fBpP\fR
+.RS 4
Paste from primary selection (command
-.BR paste_primary ,
-aliases:
-.BR ppaste ).
-.TP
-.BR Pp
-Paste from clipboard and load in a new tab (command
-.BR tab_paste ,
-aliases:
-.BR tpaste ).
-.TP
-.BR PP
+\fIpaste_primary\fR, aliases:
+\fIppaste\fR)\&.
+.RE
+.PP
+\fBPp\fR
+.RS 4
+Paste from clipboard and load in a new tab (command
+\fItab_paste\fR, aliases:
+\fItpaste\fR)\&.
+.RE
+.PP
+\fBPP\fR
+.RS 4
Paste from primary selection and load in a new tab (command
-.BR tab_paste_primary ,
-aliases:
-.BR tppaste ).
-.TP
-.BR wp
-Paste from clipboard and load in a new window (command
-.BR paste_nw ,
-aliases:
-.BR winpaste ).
-.TP
-.BR wP
+\fItab_paste_primary\fR, aliases:
+\fItppaste\fR)\&.
+.RE
+.PP
+\fBwp\fR
+.RS 4
+Paste from clipboard and load in a new window (command
+\fIpaste_nw\fR, aliases:
+\fIwinpaste\fR)\&.
+.RE
+.PP
+\fBwP\fR
+.RS 4
Paste from primary selection and load in a new window (command
-.BR paste_primary_nw ,
-aliases:
-.BR winppaste ).
-.TP
-.BR [n]ad
-Cancel the download with number n or the first download in the lists of running
-downloads if n is omitted. (command
-.BR cancel_download ).
-.TP
-.BR gs
-Add a searchengine. Textfields can be chosen with tab and a keyword must be
-specified. The first defined searchengine will be the default searchengine. The
-keyword can be used in all open commands, e.g.
-.I :open <keyword> <searchterm>
-(command
-.BR save_search_field ,
-aliases:
-.BR search ).
-.TP
-.BR Sb
+\fIpaste_primary_nw\fR, aliases:
+\fIwinppaste\fR)\&.
+.RE
+.PP
+\fB[n]ad\fR
+.RS 4
+Cancel the download with number n or the first download in the lists of running downloads if n is omitted\&. (command
+\fIcancel_download\fR)\&.
+.RE
+.PP
+\fBgs\fR
+.RS 4
+Add a searchengine\&. Textfields can be chosen with tab and a keyword must be specified\&. The first defined searchengine will be the default searchengine\&. The keyword can be used in all open commands, e\&.g\&. \&.I :open <keyword> <searchterm> (command
+\fIsave_search_field\fR, aliases:
+\fIsearch\fR)\&.
+.RE
+.PP
+\fBSb\fR
+.RS 4
Show bookmarks (command
-.BR show_bookmarks ,
-aliases:
-.BR sbookmarks ).
-.TP
-.BR Sq
+\fIshow_bookmarks\fR, aliases:
+\fIsbookmarks\fR)\&.
+.RE
+.PP
+\fBSq\fR
+.RS 4
Show quickmarks (command
-.BR show_quickmarks ,
-aliases:
-.BR squickmarks ).
-.TP
-.BR Sh
+\fIshow_quickmarks\fR, aliases:
+\fIsquickmarks\fR)\&.
+.RE
+.PP
+\fBSh\fR
+.RS 4
Show history (command
-.BR show_history ,
-aliases:
-.BR shistory ).
-.TP
-.BR Sd
+\fIshow_history\fR, aliases:
+\fIshistory\fR)\&.
+.RE
+.PP
+\fBSd\fR
+.RS 4
Show download (command
-.BR show_downloads ,
-aliases:
-.BR sdownloads ).
-.TP
-.BR Sk
+\fIshow_downloads\fR, aliases:
+\fIsdownloads\fR)\&.
+.RE
+.PP
+\fBSk\fR
+.RS 4
Show keys (command
-.BR show_keys ,
-aliases:
-.BR skeys ).
-.TP
-.BR Ss
+\fIshow_keys\fR, aliases:
+\fIskeys\fR)\&.
+.RE
+.PP
+\fBSs\fR
+.RS 4
Show settings (command
-.BR show_settings ,
-aliases:
-.BR ssettings ).
-.TP
-.BR ss
-Set setting, the interactive version of the command set, for changing settings
-in scripts use set instead (command
-.BR set_setting ).
-.TP
-.BR sl
-Set local setting, changes a setting but doesn't save the setting to
-configuration file. The interactive version of the command local_set, for
-changing settings locally in scripts use local_set instead
-(command
-.BR set_local_setting ).
-.TP
-.BR sk
+\fIshow_settings\fR, aliases:
+\fIssettings\fR)\&.
+.RE
+.PP
+\fBss\fR
+.RS 4
+Set setting, the interactive version of the command set, for changing settings in scripts use set instead (command
+\fIset_setting\fR)\&.
+.RE
+.PP
+\fBsl\fR
+.RS 4
+Set local setting, changes a setting but doesn\(cqt save the setting to configuration file\&. The interactive version of the command local_set, for changing settings locally in scripts use local_set instead (command
+\fIset_local_setting\fR)\&.
+.RE
+.PP
+\fBsk\fR
+.RS 4
Set keyboard shortcut (command
-.BR set_key ,
-aliases:
-.BR keys ).
-.TP
-.BR C-p
+\fIset_key\fR, aliases:
+\fIkeys\fR)\&.
+.RE
+.PP
+\fBC\-p\fR
+.RS 4
Toggle proxy (command
-.BR proxy ).
-.TP
-.BR tsh
+\fIproxy\fR)\&.
+.RE
+.PP
+\fBtsh\fR
+.RS 4
Toggle scripts for current host permanently (command
-.BR toggle_scripts_host ,
-aliases:
-.BR hscript ).
-.TP
-.BR tsu
+\fItoggle_scripts_host\fR, aliases:
+\fIhscript\fR)\&.
+.RE
+.PP
+\fBtsu\fR
+.RS 4
Toggle scripts for current url permanently (command
-.BR toggle_scripts_uri ,
-aliases:
-.BR uscript ).
-.TP
-.BR tth
+\fItoggle_scripts_uri\fR, aliases:
+\fIuscript\fR)\&.
+.RE
+.PP
+\fBtth\fR
+.RS 4
Toggle scripts for current host temporarily (command
-.BR toggle_scripts_host_tmp ,
-aliases:
-.BR thscript ).
-.TP
-.BR ttu
+\fItoggle_scripts_host_tmp\fR, aliases:
+\fIthscript\fR)\&.
+.RE
+.PP
+\fBttu\fR
+.RS 4
Toggle scripts for current url temporarily (command
-.BR toggle_scripts_uri_tmp ,
-aliases:
-.BR tuscript ).
-.TP
-.BR ph
+\fItoggle_scripts_uri_tmp\fR, aliases:
+\fItuscript\fR)\&.
+.RE
+.PP
+\fBph\fR
+.RS 4
Toggle plugins for current host permanently (command
-.BR toggle_plugins_host ,
-aliases:
-.BR hplugin ).
-.TP
-.BR pu
+\fItoggle_plugins_host\fR, aliases:
+\fIhplugin\fR)\&.
+.RE
+.PP
+\fBpu\fR
+.RS 4
Toggle plugins for current url permanently (command
-.BR toggle_plugins_uri ,
-aliases:
-.BR uplugin ).
-.TP
-.BR pth
+\fItoggle_plugins_uri\fR, aliases:
+\fIuplugin\fR)\&.
+.RE
+.PP
+\fBpth\fR
+.RS 4
Toggle plugins for current host temporarily (command
-.BR toggle_plugins_host_tmp ,
-aliases:
-.BR thplugin ).
-.TP
-.BR ptu
+\fItoggle_plugins_host_tmp\fR, aliases:
+\fIthplugin\fR)\&.
+.RE
+.PP
+\fBptu\fR
+.RS 4
Toggle plugins for current url temporarily (command
-.BR toggle_plugins_uri_tmp ,
-aliases:
-.BR tuplugin ).
-.TP
-.BR V
+\fItoggle_plugins_uri_tmp\fR, aliases:
+\fItuplugin\fR)\&.
+.RE
+.PP
+\fBV\fR
+.RS 4
Next navigation action will be opened in a new tab (command
-.BR new_tab ).
-.TP
-.BR W
+\fInew_tab\fR)\&.
+.RE
+.PP
+\fBW\fR
+.RS 4
Next navigation action will be opened in a new window (command
-.BR new_win ).
-.TP
-.BR eu
-Show userscripts (command
-.TP
-.BR [n]wi
-Show the webinspector of tab n or of current tab if n is omitted. Note that 'enable-developer-extras' has to be set.
-(commmand
-.BR web_inspector ,
-aliases:
-.BR inspect ,
-.BR insp ).
-.TP
-.BR C-e
+\fInew_win\fR)\&. \&.TP \&.BR eu Show and execute userscripts (command
+\fIexecute_userscript\fR)\&.
+.RE
+.PP
+\fB[n]wi\fR
+.RS 4
+Show the webinspector of tab n or of current tab if n is omitted\&. Note that
+\fIenable\-developer\-extras\fR
+has to be set\&. (commmand
+\fIweb_inspector\fR, aliases:
+\fIinspect\fR,
+\fIinsp\fR)\&.
+.RE
+.PP
+\fBC\-e\fR
+.RS 4
Open external editor for current input/textarea (command
-.BR open_editor ,
-aliases:
-.BR editor ).
-.TP
-.BR g.
-Toggle hidden files when browsing local filesystem.
-(command
-.BR open_editor ,
-aliases:
-editor ).
-.TP
-.BR F11
-Toggle fullscreen
-(command
-.BR fullscreen ,
-aliases:
-.BR fs ).
-.TP
-.BR F12
-Toggle presentation mode.
-(command
-.BR presentation_mode ,
-aliases:
-.BR present ).
-.TP
-.BR xx
-Toggle visibility of tabbar and statusbar.
-(command
-.BR toggle_bars ,
-aliases:
-.BR bars ).
-.TP
-.BR xt
-Toggle visibility of tabbar.
-(command
-.BR toggle_tabbar ,
-aliases:
-.BR tbar ).
-.TP
-.BR xb
-Toggle visibility of statusbar.
-(command
-.BR toggle_statusbar ,
-aliases:
-.BR sbar ).
-.TP
-.BR xv
-Toggle visibility of a tab.
-(command
-.BR visible ,
-aliases:
-.BR vis ).
-.TP
-.BR [n]C-M-p
-Print focused frame of tab n or of current tab if n is omitted.
-(command
-.BR print ,
-aliases:
-.BR ha ).
-.TP
-.BR unbound
-Execute a javascript snippet (command
-.BR execute_javascript ,
-aliases:
-.BR exja, js ).
-.TP
-.BR unbound
-Set a setting from commandline (command
-.BR set ).
-.TP
-.BR unbound
-Toggle a boolean setting from commandline (command
-.BR toggle_setting ,
-aliases:
-.BR toggle ,
-.BR tog ).
-.TP
-.BR unbound
-Load a html string. This command is mainly intended for use in userscripts (command
-.BR load_html ).
-.TP
-.BR unbound
-Load a html string in a new tab. This command is mainly intended for use in userscripts (command
-.BR load_html_tab ).
-.TP
-.B Tab (S-Tab)
-In normal mode Tab shows the next (previous) shortcut, that matches the
-currently entered keysequence.
-When opening a url, the next (previous) item in command
-history, bookmarks or history will be completed. In hint mode the next (previous)
-hint will get focus. Tab also completes settings and shortcut-settings.
-When initiating a download, full paths (downloads and spawning programs) and
-binaries (spawning programs) in PATH will be completed.
-In command mode tab will complete builtin commands and urls if the command
-accepts an url.
-
+\fIopen_editor\fR, aliases:
+\fIeditor\fR)\&.
+.RE
+.PP
+\fBg\&.\fR
+.RS 4
+Toggle hidden files when browsing local filesystem\&. (command
+\fIopen_editor\fR, aliases:
+\fIeditor\fR)\&.
+.RE
+.PP
+\fBF11\fR
+.RS 4
+Toggle fullscreen (command
+\fIfullscreen\fR, aliases:
+\fIfs\fR)\&.
+.RE
+.PP
+\fBF12\fR
+.RS 4
+Toggle presentation mode\&. (command
+\fIpresentation_mode\fR, aliases:
+\fIpresent\fR)\&.
+.RE
+.PP
+\fBxx\fR
+.RS 4
+Toggle visibility of tabbar and statusbar\&. (command
+\fItoggle_bars\fR, aliases:
+\fIbars\fR)\&.
+.RE
+.PP
+\fBxt\fR
+.RS 4
+Toggle visibility of tabbar\&. (command
+\fItoggle_tabbar\fR, aliases:
+\fItbar\fR)\&.
+.RE
+.PP
+\fBxb\fR
+.RS 4
+Toggle visibility of statusbar\&. (command
+\fItoggle_statusbar\fR, aliases:
+\fIsbar\fR)\&.
+.RE
+.PP
+\fBxv\fR
+.RS 4
+Toggle visibility of a tab\&. (command
+\fIvisible\fR, aliases:
+\fIvis\fR)\&.
+.RE
+.PP
+\fB[n]C\-M\-p\fR
+.RS 4
+Print focused frame of tab n or of current tab if n is omitted\&. (command
+\fIprint\fR, aliases:
+\fIha\fR)\&.
+.RE
+.PP
+\fBunbound\fR
+.RS 4
+Execute a javascript snippet (command
+\fIexecute_javascript\fR, aliases:
+\fIexja\fR,
+\fIjs\fR)\&.
+.RE
+.PP
+\fBunbound\fR
+.RS 4
+Set a setting from commandline (command
+\fIset\fR)\&.
+.RE
+.PP
+\fBunbound\fR
+.RS 4
+Toggle a boolean setting from commandline (command
+\fItoggle_setting\fR, aliases:
+\fItoggle\fR,
+\fItog\fR)\&.
+.RE
+.PP
+\fBunbound\fR
+.RS 4
+Load a html string\&. This command is mainly intended for use in userscripts (command
+\fIload_html\fR)\&.
+.RE
+.PP
+\fBunbound\fR
+.RS 4
+Load a html string in a new tab\&. This command is mainly intended for use in userscripts (command
+\fIload_html_tab\fR)\&.
+.RE
+.PP
+\fBTab (S\-Tab)\fR
+.RS 4
+In normal mode Tab shows the next (previous) shortcut, that matches the currently entered keysequence\&. When opening a url, the next (previous) item in command history, bookmarks or history will be completed\&. In hint mode the next (previous) hint will get focus\&. Tab also completes settings and shortcut\-settings\&. When initiating a download, full paths (downloads and spawning programs) and binaries (spawning programs) in PATH will be completed\&. In command mode tab will complete builtin commands and urls if the command accepts an url\&.
+.RE
.SS "Textentry shortcuts"
-.TP
-.BR C-h
-Delete a single letter.
-.TP
-.BR C-w
-Delete word back.
-.TP
-.BR C-e
-Delete word forward.
-.TP
-.BR C-u
-Delete to the beginning of the entry.
-.TP
-.BR C-i
-Delete to the end of the entry.
-.TP
-.BR C-f
-Move cursor one word forward.
-.TP
-.BR C-b
-Move cursor one word back.
-.TP
-.BR C-j
-Show next item in command history.
-.TP
-.BR C-k
-Show previous item in command history.
-.TP
-.BR C-x
-When initalizing a download, C-x toggles between choosing a file path and
-choosing a spawning application.
-.TP
-.BR C-g
-Alternative shortcut for activate.
-.TP
-.BR C-c
-Alternative shortcut for escape, the corresponding setting is
-.IR entry_escape .
-.TP
-.BR C-p
-Init local path completion.
-.TP
-.BR C-H
-Init history completion.
-.TP
-.BR C-B
-Init bookmark completion.
-.TP
-.BR C-I
-Init input history completion.
-.TP
-.BR C-S
-Init searchengine completion.
-.TP
-.BR C-U
-Init userscript completion.
-.TP
-.BR C-p
-Complete local path.
-
-.SS Shortcut Syntax
-All printable shortcuts are case sensitive, i.e. aH means press a then press
-shift, then press h. Shortcuts can be combined with a modifier, valid modifiers
-are
-.BR Control ,
-.BR Mod1 ,
-.BR Mod4 ,
-.BR Button1 ,
-.BR Button2 ,
-.BR Button3 ,
-.BR Button4 ,
-.BR Button5
-and
-.B Shift
-where Shift can only be used with non printable keys such as F1, space, Tab, ... .
-Non printable keys must be surrounded by @, e.g. "Control @F1@", Shift @space@.
-\e and @ itself must be escaped with \e.
-
-.SH CUSTOM COMMANDS
-Custom commands are a sequence of dwb commands that can be bound to a shortcut.
-The syntax is
-.RS
-
-.I <shortcut>:<command>;;<command>;;...
-
-.RE
-where shortcut is the shortcut for the commandsequence,
-.B :
-may be escaped with
-.BR \e:
-and command is of the form
-.RS
-
-.I [numerical modifier]<command or alias> [argument for the command]
-
-.RE
-for example
-.RS
-
-.I Control W:tabopen http://example.com;; 150zoom
-
+.PP
+\fBC\-h\fR
+.RS 4
+Delete a single letter\&.
.RE
-opens http://example.com in a new tab and zooms to 150%.
-
-
-.SH COMMAND OVERVIEW
+.PP
+\fBC\-w\fR
+.RS 4
+Delete word back\&.
+.RE
+.PP
+\fBC\-e\fR
+.RS 4
+Delete word forward\&.
+.RE
+.PP
+\fBC\-u\fR
+.RS 4
+Delete to the beginning of the entry\&.
+.RE
+.PP
+\fBC\-i\fR
+.RS 4
+Delete to the end of the entry\&.
+.RE
+.PP
+\fBC\-f\fR
+.RS 4
+Move cursor one word forward\&.
+.RE
+.PP
+\fBC\-b\fR
+.RS 4
+Move cursor one word back\&.
+.RE
+.PP
+\fBC\-j\fR
+.RS 4
+Show next item in command history\&.
+.RE
+.PP
+\fBC\-k\fR
+.RS 4
+Show previous item in command history\&.
+.RE
+.PP
+\fBC\-x\fR
+.RS 4
+When initalizing a download, C\-x toggles between choosing a file path and choosing a spawning application\&.
+.RE
+.PP
+\fBC\-g\fR
+.RS 4
+Alternative shortcut for activate\&.
+.RE
+.PP
+\fBC\-c\fR
+.RS 4
+Alternative shortcut for escape, the corresponding setting is \&.IR entry_escape \&.
+.RE
+.PP
+\fBC\-p\fR
+.RS 4
+Init local path completion\&.
+.RE
+.PP
+\fBC\-H\fR
+.RS 4
+Init history completion\&.
+.RE
+.PP
+\fBC\-B\fR
+.RS 4
+Init bookmark completion\&.
+.RE
+.PP
+\fBC\-I\fR
+.RS 4
+Init input history completion\&.
+.RE
+.PP
+\fBC\-S\fR
+.RS 4
+Init searchengine completion\&.
+.RE
+.PP
+\fBC\-U\fR
+.RS 4
+Init userscript completion\&.
+.RE
+.PP
+\fBC\-p\fR
+.RS 4
+Complete local path\&.
+.RE
+.SS "Shortcut syntax"
+.sp
+All printable shortcuts are case sensitive, i\&.e\&. aH means press a then press shift, then press h\&. Shortcuts can be combined with a modifier, valid modifiers are \fIControl\fR, \fIMod1\fR, \fIMod4\fR, \fIButton1\fR, \fIButton2\fR, \fIButton3\fR, \fIButton4\fR, \fIButton5\fR and \fIShift\fR where Shift can only be used with non printable keys such as F1, space, Tab, \&... \&. Non printable keys must be surrounded by @, e\&.g\&. "Control @F1@", Shift @space@\&. \e and @ itself must be escaped with \e\&.
+.SH "CUSTOM COMMANDS"
+.sp
+Custom commands are a sequence of dwb commands that can be bound to a shortcut\&. The syntax is
+.sp
+.if n \{\
+.RS 4
+.\}
.nf
-Command |Alias |Description
----------------------------------------------------------------------------
-allow_cookie |cookie |Allow persistent cookies for site
-allow_session_cookie |scookie |Allow session cookies for site
-allow_session_cookie_tmp|tcookie |Allow session cookies for site
- | |temporarily
-bookmark |bma, bmark |Bookmark current page
-bookmarks |bmas, bmarks |Show bookmarks
-buffers |bu |Show all open tabs
-cancel_download | |Cancel a download
-clear_tab |clear |Clear tab
-close_tab |close |Close tab
-dump | |Write html of current website to a
- | |file or stdout if no argument is given
-execute_javascript |exja, js |Execute a javascript snippet
-execute_userscript | |Execute userscript
-find_backward |bfind |Find backward
-find_backward_ic |ibfind |Find backward case sensitive
-find_forward |ffind |Find forward
-find_forward_ic |iffind |Find forward case sensitive
-find_next |fnext |Find next
-find_previous |fprev |Find previous
-focus_input | |Focus next input
-focus_next |tabnext |Focus next tab
-focus_prev |tabprev |Focus previous tab
-focus_tab |tab |Focus nth tab
-fullscreen |fs |Toggle fullscreen
-hints |hi |Follow hints
-hints_background |backhints, bhi |Follow hints in a background tab
-hints_clipboard |chints, chi |Save link location to clipboard
-hints_download |dhints, dhi |Download via hints
-hints_editable |ehints, ehi |Focus editable elements
-hints_images |ihints, ihi |Follow images
-hints_images_tab |itabhints, ithi |Follow images in a new tab
-hints_images_background |ibackhints |Follow images in a background tab
-hints_links |lhints, lhi |Follow links
-hints_primary |phints, phi |Save link location to primary
- | |selection
-hints_rapid |rhints, rhi |Open new tabs in background
- | |rapidly
-hints_rapid_win |wrhints, wrhi |Open new windows rapidly
-hints_tab |tabhints, thi |Follow hints in a new tab
-hints_url |uhints, uhi |Set hints url in commandline
-hints_url_tab |utabhints, uthi |Set hints url in commandline,
- | |open in a new tab
-hints_url_background |ubackhints |Set hints url in commandline,
- | |open in a background tab
-hints_win |winhints, whi |Follow hints in a new window
-history_back |ba, back |Go back
-history_forward |fo, forward |Go forward
-insert_mode |i, insert |Insert mode
-local_set | |Set a setting only for the running
- | |instance, don't save it to the
- | |configuration file
-lock_domain |dlock |Lock tab to current domain
-lock_uri |ulock |Lock tab to current uri
-new_tab | |Open next navigation action in
- | |new tab
-new_win | |Open next navigation action in
- | |new window
-only | |Close all tabs except for the
- | |current one
-open |o |Open url
-open_editor |editor |Open external editor for
- | |input/textarea.
-open_url | |Open, edit current url
-paste | |Open from clipboard
-paste_primary |ppaste |Open from primary selection
-presentation_mode |present |Toggle presentation mode
-print |ha |Print page
-protect |prot |Protect/unprotect tab
-proxy | |Toggle proxy
-quickmark |qmarks |Open quickmark
-quit |q |Quit
-reload |re |Reload current page
-reload_bypass_cache |refull |Reload without using cached data
-reload_scripts | |Reload all javascript userscripts
-reload_userscripts | |Reload userscripts
-save | |Save all configuration files
-save_named_session |wqn |Save current session with name
-save_quickmark |qmark, quickmark|Save a quickmark
-save_search_field |search |Add a new searchengine
-save_session |wq |Save current session
-scroll_bottom |bottom |Scroll to bottom of the page
-scroll_down |down |Scroll down
-scroll_halfpage_down |halfdown |Scroll one-half page down
-scroll_halfpage_up |halfup |Scroll one-half page up
-scroll_left |left |Scroll left
-scroll_page_down |pagedown |Scroll one page down
-scroll_page_up |pageup |Scroll one page up
-scroll_right |right |Scroll right
-scroll_top |top |Scroll to the top of the page
-scroll_up |up |Scroll up
-set | |Set a setting
-set_key |keys |Set keybinding
-set_local_setting | |Set a setting for the running instance
- | |interactively
-set_setting | |Set a setting interactive
-show_keys |skeys |Show and modify keyboard
- | |configuration
-show_settings |ssettings |Show and modify global properties
-start_page |home |Open the default homepage
-stop_loading |st, stop |Stop loading current page
-tab_bookmarks |tabmarks |Show bookmarks, open in new tab
-tab_hist_back |tba, tabback |Go back in a new tab
-tab_hist_forward |tfo, tabforward |Go forward in a new tab
-tab_move |tabm |Move tab
-tab_move_left |tabl |Move tab left
-tab_move_right |tabr |Move tab right
-tab_new | |Open a new blank tab
-tab_paste |tpaste |Open from clipboard in a new tab
-tab_paste_primary |tppaste |Open from primary selection in a
- | |new tab
-tab_quickmark |tabqmarks |Open quickmark in a new tab
-tabopen |t, topen |Open in a new tab
-tabopen_url | |Open in a new tab, edit current
- | |url
-toggle_bars |bars |Toggle tabbar and statusbar
-toggle_hidden_files |hidden |Toggle hidden files in directory
- | |listings
-toggle_plugins_host |hplugin |Toggle plugin blocker for host
-toggle_plugins_host_tmp |tuplugin |Toggle plugin blocker for domain
- | |for this session
-toggle_plugins_uri |uplugin |Toggle plugin blocker for uri
-toggle_plugins_uri_tmp |tuplugin |Toggle plugin blocker for uri for
- | |this session
-toggle_scripts_host |hscript |Toggle scripts for current domain
-toggle_scripts_host_tmp |thscript |Toggle scripts for current host
- | |for this session
-toggle_scripts_uri |uscript |Toggle scripts for current uri
-toggle_scripts_uri_tmp |tuscript |Toggle scripts for current uri
- | |for this session
-toggle_setting |tog, toggle |Toggle a setting
-toggle_local_setting |loctog |Toggle a setting for the current
- | |session
-toggle_statusbar |sbar |Toggle statusbar
-toggle_tabbar |tbar |Toggle tabbar
-undo |u |Undo closing last tab
-view_source |so, source |View page source
-visible |vis |Toggle visibility of a tab
-web_inspector |insp, inspect |Open the webinspector
-win_bookmarks |winmarks |Show bookmarks, open in new
- | |window
-win_hist_back |wba, winback |Go back in a new window
-win_hist_forward |wfo, winforward |Go forward in a new window
-win_paste |wpaste |Open from clipboard in a new
- | |window
-win_paste_primary |wppaste |Open primary selection in a new
- | |window
-win_quickmark |winqmarks |Open quickmark in a new window
-winopen |w, wopen |Open in a new window
-winopen_url | |Open in a new window, edit
- | |current url
-yank | |Yank url to clipboard
-yank_primary |pyank |Yank url to primary selection
-yank_title |tyank |Yank title to clipboard
-yank_title_primary |tpyank |Yank title to primary selection
-zoom |z |Zoom
-zoom_in |zi |Zoom in
-zoom_out |zo |Zoom out
+<shortcut>:<command>;;<command>;;\&.\&.\&.
.fi
-
-.SH CUSTOMIZATION
-dwb can be customized in a web interface (command
-.BR show_settings )
-or via command line (command
-.BR set_setting ).
-Modified settings
-will be saved in
-.IR ~/.config/dwb/settings
-when closing dwb.
-Shorcuts can also be modified in a web interface (command
-.BR show_keys )
-or via command line (command
-.BR set_key ).
-Shortcuts will be saved in
-.IR ~/.config/dwb/keys .
-
-If a string value is set to
-.IR NULL
-the default value will be used. The settings in detail are:
-
-.SS WebKit builtin settings
-.TP
-.BR auto-load-images
-Load images automatically. Possible values: true/false,
-default value:
-.IR true .
-.TP
-.BR auto-resize-window
-Resize window through DOM-methods. Possible values: true/false,
-default value:
-.IR false .
-.TP
-.BR auto-shrink-images
-Automatically shrink standalone images to fit. Possible values: true/false,
-default value:
-.IR true .
-.TP
-.BR cursive-font-family
-Default cursive font family used to display text. Possible values: a font description or
-NULL,
-default value:
-.IR NULL .
-.TP
-.BR custom-encoding
-A custom encoding used for the webview. Possible values: encoding string or
-NULL,
-default value:
-.IR NULL .
-.TP
-.BR default-encoding
-The default encoding used to display text. Possible values: encoding string or
-NULL,
-default value:
-.IR NULL .
-.TP
-.BR default-font-family
-The default font family used to display text. Possible values: a font
-description or
-NULL,
-default value:
-.IR sans-serif .
-.TP
-.BR default-font-size
-The default font size used to display text. Possible values: a font size
-(integer),
-default value:
-.IR 12 .
-.TP
-.BR default-monospace-font-size
-The default font size used to display monospace text. Possible values: a font size
-(integer),
-default value:
-.IR 10 .
-.TP
-.BR editable
-Whether the content of a webpage should be editable. Possible values:
-true/false,
-default value:
-.IR false .
-.TP
-.BR enable-caret-browsing
-Whether to enable caret browsing. Possible values: true/false,
-default value:
-.IR false .
-.TP
-.BR enable-default-context-menu
-Whether right-clicks open a context menu. Possible values: true/false,
-default value:
-.IR false .
-.TP
-.BR enable-dns-prefetching
-Whether webkit prefetches domain names.
-default value:
-.IR true .
-.TP
-.BR enable-developer-extras
-Whether the web-inspector should be enabled. Possible values: true/false,
-default value:
-.IR false .
-.TP
-.BR enable-dom-paste
-Whether enable DOM-paste. Possible values: true/false,
-default value:
-.IR false .
-.TP
-.BR enable-frame-flattening
-Whether to enable the Frame Flattening. With this setting each subframe is expanded
-to its contents, which will flatten all the frames to become one scrollable page.
-Whether file uris can be accessed. Possible values: true/false,
-default value:
-.IR false .
-.TP
-.BR enable-file-access-from-file-uris
-Whether file uris can be accessed. Possible values: true/false,
-default value:
-.IR true .
-.TP
-.BR enable-html5-database
-Whether to enable HTML5 client-side SQL database support.
-Possible values: true/false,
-default value:
-.IR true .
-.TP
-.BR enable-html5-local-storage
-Whether to enable HTML5 localStorage support.
-Possible values: true/false,
-default value:
-.IR true .
-.TP
-.BR enable-java-applet
-Whether to enable Java <applet>-tag.
-Possible values: true/false,
-default value:
-.IR true .
-.TP
-.BR enable-offline-web-application-cache
-Enable or disable HTML5 offline web application cache support.
-Possible values: true/false,
-default value:
-.IR true .
-.TP
-.BR enable-page-cache
-Enable or disable page cache.
-Possible values: true/false,
-default value:
-.IR false .
-.TP
-.BR enable-plugins
-Enable or disable embedded plugins.
-Possible values: true/false,
-default value:
-.IR true .
-.TP
-.BR enable-private-browsing
-Enable or disable private browsing.
-Possible values: true/false,
-default value:
-.IR false .
-.TP
-.BR enable-scripts
-Enable or disable embedded scripting-languages.
-Possible values: true/false,
-default value:
-.IR true .
-.TP
-.BR enable-site-specific-quirks
-Enables the site-specific compatibility workarounds.
-Possible values: true/false,
-default value:
-.IR false .
-.TP
-.BR enable-spatial-navigation
-Whether to enable the Spatial Navigation. This feature consists in the ability
-to navigate between focusable elements in a Web page, such as hyperlinks and
-form controls, by using Left, Right, Up and Down arrow keys.
-Possible values: true/false,
-default value:
-.IR false .
-.TP
-.BR enable-spell-checking
-Whether to enable spell checking.
-Possible values: true/false,
-default value:
-.IR false .
-.TP
-.BR enable-universal-access-from-file-uris
-Whether to allow files loaded through file:// URIs universal access to all pages.
-Possible values: true/false,
-default value:
-.IR true .
-.TP
-.BR enable-xss-auditor
-Whether to enable the XSS Auditor. This feature filters some kinds of reflective
-XSS attacks on vulnerable web sites.
-Possible values: true/false,
-default value:
-.IR true .
-.TP
-.BR enforce-96-dpi
-Enforce a resolution of 96 DPI.
-Possible values: true/false,
-default value:
-.IR false .
-.TP
-.BR fantasy-font-family
-Default fantasy font family used to display text. Possible values: a font description or
-NULL,
-default value:
-.IR serif .
-.TP
-.BR javascript-can-access-clipboard
-Whether javascript can access Clipboard.
-Possible values: true/false,
-default value:
-.IR false .
-.TP
-.BR full-content-zoom
-Whether the full content is scaled when zooming.
-Possible values: true/false,
-default value:
-.IR false .
-.TP
-.BR javascript-can-open-windows-automatically
-Whether JavaScript can open popup windows automatically without user intervention.
-Possible values: true/false,
-default value:
-.IR false .
-.TP
-.BR minimum-font-size
-The minimum font size used to display text. Possible values: a font size
-(integer),
-default value:
-.IR 5 .
-.TP
-.BR minimum-logical-font-size
-The minimum logical font size used to display text. Possible values: a font size
-(integer),
-default value:
-.IR 5 .
-.TP
-.BR monospace-font-family
-Default font family used to display monospace text. Possible values: a font description or
-NULL,
-default value:
-.IR monospace .
-.TP
-.BR print-backgrounds
-Whether background images should be printed.
-Possible values: true/false,
-default value:
-.IR true .
-.TP
-.BR resizable-text-areas
-Whether text areas are resizable.
-Possible values: true/false,
-default value:
-.IR true .
-.TP
-.BR sans-serif-font-family
-Default sans-serif font family used to display text. Possible values: a font description or
-NULL,
-default value:
-.IR sans-serif .
-.TP
-.BR serif-font-family
-Default serif font family used to display text. Possible values: a font description or
-NULL,
-default value:
-.IR serif .
-.TP
-.BR spell-checking-language
-The languages to be used for spell checking, separated by commas. Possible
-values: a string or
-NULL,
-default value:
-.IR NULL .
-.TP
-.BR tab-cycles-through-elements
-Whether the tab key cycles through elements on the page.
-Possible values: true/false,
-default value:
-.IR true .
-.TP
-.BR user-agent
-The user-agent-string. Possible values: a user-agent or
-NULL,
-default value:
-.IR NULL .
-.TP
-.BR user-stylesheet-uri
-The URI of a stylesheet that is applied to every page. If a local file is used,
-must start with file://. Possible values: an
-uri-string or NULL,
-default value:
-.IR NULL .
-.TP
-.BR zoom-level
-The zoom level of the content. Possible values: a decimal,
-default value:
-.IR 1.0 .
-.TP
-.BR zoom-step
-The value by which the zoom level is changed when zooming in or out. Possible
-values: a decimal,
-default value:
-.IR 0.1 .
-
-.SS Other settings
-.TP
-.BR active-completion-bg-color
-The background color for an active element in tab-completion. Possible values:
-an rgb color-string,
-default value:
-.IR #000000 .
-.TP
-.BR active-completion-fg-color
-The foreground color for an active element in tab-completion. Possible values:
-an rgb color-string.
-default value:
-.IR #53868b .
-.TP
-.BR adblocker
-Block advertisements using a filterlist, see also
-.IR adblocker-filterlist .
-Default value:
-.IR false .
-.TP
-.BR adblocker-filterlist
-A path to a adblock plus compatible filterlist for the adblocker.
-Default value:
-.IR NULL .
-.TP
-.BR background-color
-The background color of the statusbar. Possible values: an rgb color-string,
-default value:
-.IR #000000 .
-.TP
-.TP
-.BR foreground-color
-The foreground color of statusbar. Possible values: an rgb color-string.
-default value:
-.IR #ffffff .
-.TP
-.BR auto-completion
-Whether possible keystrokes should be shown. (Shift-) Tab cycles through keystrokes.
-Possible values: true/false,
-default value:
-.IR true .
-.TP
-.BR auto-insert-mode
-Whether to go automatically in insert mode if an editable element has focus
-after loading a site.
-Possible values: true/false,
-default value:
-.IR false .
-.TP
-.BR background-tabs
-Open new tabs in background.
-Possible values: true/false,
-default value:
-.IR false .
-.TP
-.BR cache-model
+.if n \{\
+.RE
+.\}
+.sp
+where shortcut is the shortcut for the commandsequence, \fB:\fR may be escaped with \fB\e:\fR and command is of the form
+.sp
+.if n \{\
+.RS 4
+.\}
+.nf
+[numerical modifier]<command or alias> [argument for the command]
+.fi
+.if n \{\
+.RE
+.\}
+.sp
+for example
+.sp
+.if n \{\
+.RS 4
+.\}
+.nf
+Control W:tabopen http://example\&.com;; 150zoom
+.fi
+.if n \{\
+.RE
+.\}
+.sp
+opens http://example\&.com in a new tab and zooms to 150%\&.
+.SH "COMMAND OVERVIEW"
+.TS
+allbox tab(:);
+ltB ltB ltB.
+T{
+Command
+T}:T{
+Alias
+T}:T{
+Description
+T}
+.T&
+lt lt lt
+lt lt lt
+lt lt lt
+lt lt lt
+lt lt lt
+lt lt lt
+lt lt lt
+lt lt lt
+lt lt lt
+lt lt lt
+lt lt lt
+lt lt lt
+lt lt lt
+lt lt lt
+lt lt lt
+lt lt lt
+lt lt lt
+lt lt lt
+lt lt lt
+lt lt lt
+lt lt lt
+lt lt lt
+lt lt lt
+lt lt lt
+lt lt lt
+lt lt lt
+lt lt lt
+lt lt lt
+lt lt lt
+lt lt lt
+lt lt lt
+lt lt lt
+lt lt lt
+lt lt lt
+lt lt lt
+lt lt lt
+lt lt lt
+lt lt lt
+lt lt lt
+lt lt lt
+lt lt lt
+lt lt lt
+lt lt lt
+lt lt lt
+lt lt lt
+lt lt lt
+lt lt lt
+lt lt lt
+lt lt lt
+lt lt lt
+lt lt lt
+lt lt lt
+lt lt lt
+lt lt lt
+lt lt lt
+lt lt lt
+lt lt lt
+lt lt lt
+lt lt lt
+lt lt lt
+lt lt lt
+lt lt lt
+lt lt lt
+lt lt lt
+lt lt lt
+lt lt lt
+lt lt lt
+lt lt lt
+lt lt lt
+lt lt lt
+lt lt lt
+lt lt lt
+lt lt lt
+lt lt lt
+lt lt lt
+lt lt lt
+lt lt lt
+lt lt lt
+lt lt lt
+lt lt lt
+lt lt lt
+lt lt lt
+lt lt lt
+lt lt lt
+lt lt lt
+lt lt lt
+lt lt lt
+lt lt lt
+lt lt lt
+lt lt lt
+lt lt lt
+lt lt lt
+lt lt lt
+lt lt lt
+lt lt lt
+lt lt lt
+lt lt lt
+lt lt lt
+lt lt lt
+lt lt lt
+lt lt lt
+lt lt lt
+lt lt lt
+lt lt lt
+lt lt lt
+lt lt lt
+lt lt lt
+lt lt lt
+lt lt lt
+lt lt lt
+lt lt lt
+lt lt lt
+lt lt lt
+lt lt lt
+lt lt lt
+lt lt lt
+lt lt lt
+lt lt lt
+lt lt lt
+lt lt lt
+lt lt lt
+lt lt lt
+lt lt lt
+lt lt lt
+lt lt lt
+lt lt lt
+lt lt lt
+lt lt lt
+lt lt lt
+lt lt lt.
+T{
+.sp
+allow_cookie
+T}:T{
+.sp
+cookie
+T}:T{
+.sp
+Allow persistent cookies for site
+T}
+T{
+.sp
+allow_session_cookie
+T}:T{
+.sp
+scookie
+T}:T{
+.sp
+Allow session cookies for site
+T}
+T{
+.sp
+allow_session_cookie_tmp
+T}:T{
+.sp
+tcookie
+T}:T{
+.sp
+Allow session cookies for site temporarily
+T}
+T{
+.sp
+bookmark
+T}:T{
+.sp
+bma, bmark
+T}:T{
+.sp
+Bookmark current page
+T}
+T{
+.sp
+bookmarks
+T}:T{
+.sp
+bmas, bmarks
+T}:T{
+.sp
+Show bookmarks
+T}
+T{
+.sp
+buffers
+T}:T{
+.sp
+bu
+T}:T{
+.sp
+Show all open tabs
+T}
+T{
+.sp
+cancel_download
+T}:T{
+.sp
+T}:T{
+.sp
+Cancel a download
+T}
+T{
+.sp
+clear_tab
+T}:T{
+.sp
+clear
+T}:T{
+.sp
+Clear tab
+T}
+T{
+.sp
+close_tab
+T}:T{
+.sp
+close
+T}:T{
+.sp
+Close tab
+T}
+T{
+.sp
+dump
+T}:T{
+.sp
+T}:T{
+.sp
+Write html of current website to a file or stdout if no argument is given
+T}
+T{
+.sp
+execute_javascript
+T}:T{
+.sp
+exja, js
+T}:T{
+.sp
+Execute a javascript snippet
+T}
+T{
+.sp
+execute_userscript
+T}:T{
+.sp
+T}:T{
+.sp
+Execute userscript
+T}
+T{
+.sp
+find_backward
+T}:T{
+.sp
+bfind
+T}:T{
+.sp
+Find backward
+T}
+T{
+.sp
+find_backward_ic
+T}:T{
+.sp
+ibfind
+T}:T{
+.sp
+Find backward case sensitive
+T}
+T{
+.sp
+find_forward
+T}:T{
+.sp
+ffind
+T}:T{
+.sp
+Find forward
+T}
+T{
+.sp
+find_forward_ic
+T}:T{
+.sp
+iffind
+T}:T{
+.sp
+Find forward case sensitive
+T}
+T{
+.sp
+find_next
+T}:T{
+.sp
+fnext
+T}:T{
+.sp
+Find next
+T}
+T{
+.sp
+find_previous
+T}:T{
+.sp
+fprev
+T}:T{
+.sp
+Find previous
+T}
+T{
+.sp
+focus_input
+T}:T{
+.sp
+T}:T{
+.sp
+Focus next input
+T}
+T{
+.sp
+focus_next
+T}:T{
+.sp
+tabnext
+T}:T{
+.sp
+Focus next tab
+T}
+T{
+.sp
+focus_prev
+T}:T{
+.sp
+tabprev
+T}:T{
+.sp
+Focus previous tab
+T}
+T{
+.sp
+focus_tab
+T}:T{
+.sp
+tab
+T}:T{
+.sp
+Focus nth tab
+T}
+T{
+.sp
+fullscreen
+T}:T{
+.sp
+fs
+T}:T{
+.sp
+Toggle fullscreen
+T}
+T{
+.sp
+hints
+T}:T{
+.sp
+hi
+T}:T{
+.sp
+Follow hints
+T}
+T{
+.sp
+hints_background
+T}:T{
+.sp
+backhints, bhi
+T}:T{
+.sp
+Follow hints in a background tab
+T}
+T{
+.sp
+hints_clipboard
+T}:T{
+.sp
+chints, chi
+T}:T{
+.sp
+Save link location to clipboard
+T}
+T{
+.sp
+hints_download
+T}:T{
+.sp
+dhints, dhi
+T}:T{
+.sp
+Download via hints
+T}
+T{
+.sp
+hints_editable
+T}:T{
+.sp
+ehints, ehi
+T}:T{
+.sp
+Focus editable elements
+T}
+T{
+.sp
+hints_images
+T}:T{
+.sp
+ihints, ihi
+T}:T{
+.sp
+Follow images
+T}
+T{
+.sp
+hints_images_tab
+T}:T{
+.sp
+itabhints, ithi
+T}:T{
+.sp
+Follow images in a new tab
+T}
+T{
+.sp
+hints_images_background
+T}:T{
+.sp
+ibackhints
+T}:T{
+.sp
+Follow images in a background tab
+T}
+T{
+.sp
+hints_links
+T}:T{
+.sp
+lhints, lhi
+T}:T{
+.sp
+Follow links
+T}
+T{
+.sp
+hints_primary
+T}:T{
+.sp
+phints, phi
+T}:T{
+.sp
+Save link location to primary selection
+T}
+T{
+.sp
+hints_rapid
+T}:T{
+.sp
+rhints, rhi
+T}:T{
+.sp
+Open new tabs in background rapidly
+T}
+T{
+.sp
+hints_rapid_win
+T}:T{
+.sp
+wrhints, wrhi
+T}:T{
+.sp
+Open new windows rapidly
+T}
+T{
+.sp
+hints_tab
+T}:T{
+.sp
+tabhints, thi
+T}:T{
+.sp
+Follow hints in a new tab
+T}
+T{
+.sp
+hints_url
+T}:T{
+.sp
+uhints, uhi
+T}:T{
+.sp
+Set hints url in commandline
+T}
+T{
+.sp
+hints_url_tab
+T}:T{
+.sp
+utabhints, uthi
+T}:T{
+.sp
+Set hints url in commandline, open in a new tab
+T}
+T{
+.sp
+hints_url_background
+T}:T{
+.sp
+ubackhints
+T}:T{
+.sp
+Set hints url in commandline, open in a background tab
+T}
+T{
+.sp
+hints_win
+T}:T{
+.sp
+winhints, whi
+T}:T{
+.sp
+Follow hints in a new window
+T}
+T{
+.sp
+history_back
+T}:T{
+.sp
+ba, back
+T}:T{
+.sp
+Go back
+T}
+T{
+.sp
+history_forward
+T}:T{
+.sp
+fo, forward
+T}:T{
+.sp
+Go forward
+T}
+T{
+.sp
+insert_mode
+T}:T{
+.sp
+i, insert
+T}:T{
+.sp
+Insert mode local_set Set a setting only for the running instance, don\(cqt save it to the configuration file
+T}
+T{
+.sp
+lock_domain
+T}:T{
+.sp
+dlock
+T}:T{
+.sp
+Lock tab to current domain
+T}
+T{
+.sp
+lock_uri
+T}:T{
+.sp
+ulock
+T}:T{
+.sp
+Lock tab to current uri
+T}
+T{
+.sp
+new_tab
+T}:T{
+.sp
+T}:T{
+.sp
+Open next navigation action in new tab
+T}
+T{
+.sp
+new_win
+T}:T{
+.sp
+T}:T{
+.sp
+Open next navigation action in new window
+T}
+T{
+.sp
+only
+T}:T{
+.sp
+T}:T{
+.sp
+Close all tabs except for the current one
+T}
+T{
+.sp
+open
+T}:T{
+.sp
+o
+T}:T{
+.sp
+Open url
+T}
+T{
+.sp
+open_editor
+T}:T{
+.sp
+editor
+T}:T{
+.sp
+Open external editor for input/textarea\&.
+T}
+T{
+.sp
+open_url
+T}:T{
+.sp
+T}:T{
+.sp
+Open, edit current url
+T}
+T{
+.sp
+paste
+T}:T{
+.sp
+T}:T{
+.sp
+Open from clipboard
+T}
+T{
+.sp
+paste_primary
+T}:T{
+.sp
+ppaste
+T}:T{
+.sp
+Open from primary selection
+T}
+T{
+.sp
+presentation_mode
+T}:T{
+.sp
+present
+T}:T{
+.sp
+Toggle presentation mode
+T}
+T{
+.sp
+print
+T}:T{
+.sp
+ha
+T}:T{
+.sp
+Print page
+T}
+T{
+.sp
+protect
+T}:T{
+.sp
+prot
+T}:T{
+.sp
+Protect/unprotect tab
+T}
+T{
+.sp
+proxy
+T}:T{
+.sp
+T}:T{
+.sp
+Toggle proxy
+T}
+T{
+.sp
+quickmark
+T}:T{
+.sp
+qmarks
+T}:T{
+.sp
+Open quickmark
+T}
+T{
+.sp
+quit
+T}:T{
+.sp
+q
+T}:T{
+.sp
+Quit
+T}
+T{
+.sp
+reload
+T}:T{
+.sp
+re
+T}:T{
+.sp
+Reload current page
+T}
+T{
+.sp
+reload_bypass_cache
+T}:T{
+.sp
+refull
+T}:T{
+.sp
+Reload without using cached data
+T}
+T{
+.sp
+reload_userscripts
+T}:T{
+.sp
+T}:T{
+.sp
+Reload userscripts
+T}
+T{
+.sp
+save
+T}:T{
+.sp
+T}:T{
+.sp
+Save all configuration files
+T}
+T{
+.sp
+save_named_session
+T}:T{
+.sp
+wqn
+T}:T{
+.sp
+Save current session with name
+T}
+T{
+.sp
+save_quickmark
+T}:T{
+.sp
+qmark, quickmark
+T}:T{
+.sp
+Save a quickmark
+T}
+T{
+.sp
+save_search_field
+T}:T{
+.sp
+search
+T}:T{
+.sp
+Add a new searchengine
+T}
+T{
+.sp
+save_session
+T}:T{
+.sp
+wq
+T}:T{
+.sp
+Save current session
+T}
+T{
+.sp
+scroll_bottom
+T}:T{
+.sp
+bottom
+T}:T{
+.sp
+Scroll to bottom of the page
+T}
+T{
+.sp
+scroll_down
+T}:T{
+.sp
+down
+T}:T{
+.sp
+Scroll down
+T}
+T{
+.sp
+scroll_halfpage_down
+T}:T{
+.sp
+halfdown
+T}:T{
+.sp
+Scroll one\-half page down
+T}
+T{
+.sp
+scroll_halfpage_up
+T}:T{
+.sp
+halfup
+T}:T{
+.sp
+Scroll one\-half page up
+T}
+T{
+.sp
+scroll_left
+T}:T{
+.sp
+left
+T}:T{
+.sp
+Scroll left
+T}
+T{
+.sp
+scroll_page_down
+T}:T{
+.sp
+pagedown
+T}:T{
+.sp
+Scroll one page down
+T}
+T{
+.sp
+scroll_page_up
+T}:T{
+.sp
+pageup
+T}:T{
+.sp
+Scroll one page up
+T}
+T{
+.sp
+scroll_right
+T}:T{
+.sp
+right
+T}:T{
+.sp
+Scroll right
+T}
+T{
+.sp
+scroll_top
+T}:T{
+.sp
+top
+T}:T{
+.sp
+Scroll to the top of the page
+T}
+T{
+.sp
+scroll_up
+T}:T{
+.sp
+up
+T}:T{
+.sp
+Scroll up
+T}
+T{
+.sp
+set
+T}:T{
+.sp
+T}:T{
+.sp
+Set a setting
+T}
+T{
+.sp
+set_key
+T}:T{
+.sp
+keys
+T}:T{
+.sp
+Set keybinding
+T}
+T{
+.sp
+set_local_setting
+T}:T{
+.sp
+T}:T{
+.sp
+Set a setting for the running instance interactively
+T}
+T{
+.sp
+set_setting
+T}:T{
+.sp
+T}:T{
+.sp
+Set a setting interactive
+T}
+T{
+.sp
+show_keys
+T}:T{
+.sp
+skeys
+T}:T{
+.sp
+Show and modify keyboard configuration
+T}
+T{
+.sp
+show_settings
+T}:T{
+.sp
+ssettings
+T}:T{
+.sp
+Show and modify global properties
+T}
+T{
+.sp
+start_page
+T}:T{
+.sp
+home
+T}:T{
+.sp
+Open the default homepage
+T}
+T{
+.sp
+stop_loading
+T}:T{
+.sp
+st, stop
+T}:T{
+.sp
+Stop loading current page
+T}
+T{
+.sp
+tab_bookmarks
+T}:T{
+.sp
+tabmarks
+T}:T{
+.sp
+Show bookmarks, open in new tab
+T}
+T{
+.sp
+tab_hist_back
+T}:T{
+.sp
+tba, tabback
+T}:T{
+.sp
+Go back in a new tab
+T}
+T{
+.sp
+tab_hist_forward
+T}:T{
+.sp
+tfo, tabforward
+T}:T{
+.sp
+Go forward in a new tab
+T}
+T{
+.sp
+tab_move
+T}:T{
+.sp
+tabm
+T}:T{
+.sp
+Move tab
+T}
+T{
+.sp
+tab_move_left
+T}:T{
+.sp
+tabl
+T}:T{
+.sp
+Move tab left
+T}
+T{
+.sp
+tab_move_right
+T}:T{
+.sp
+tabr
+T}:T{
+.sp
+Move tab right
+T}
+T{
+.sp
+tab_new
+T}:T{
+.sp
+T}:T{
+.sp
+Open a new blank tab
+T}
+T{
+.sp
+tab_paste
+T}:T{
+.sp
+tpaste
+T}:T{
+.sp
+Open from clipboard in a new tab
+T}
+T{
+.sp
+tab_paste_primary
+T}:T{
+.sp
+tppaste
+T}:T{
+.sp
+Open from primary selection in a new tab
+T}
+T{
+.sp
+tab_quickmark
+T}:T{
+.sp
+tabqmarks
+T}:T{
+.sp
+Open quickmark in a new tab
+T}
+T{
+.sp
+tabopen
+T}:T{
+.sp
+t, topen
+T}:T{
+.sp
+Open in a new tab
+T}
+T{
+.sp
+tabopen_url
+T}:T{
+.sp
+T}:T{
+.sp
+Open in a new tab, edit current url
+T}
+T{
+.sp
+toggle_bars
+T}:T{
+.sp
+bars
+T}:T{
+.sp
+Toggle tabbar and statusbar
+T}
+T{
+.sp
+toggle_hidden_files
+T}:T{
+.sp
+hidden
+T}:T{
+.sp
+Toggle hidden files in directory listings
+T}
+T{
+.sp
+toggle_plugins_host
+T}:T{
+.sp
+hplugin
+T}:T{
+.sp
+Toggle plugin blocker for host
+T}
+T{
+.sp
+toggle_plugins_host_tmp
+T}:T{
+.sp
+tuplugin
+T}:T{
+.sp
+Toggle plugin blocker for domain for this session
+T}
+T{
+.sp
+toggle_plugins_uri
+T}:T{
+.sp
+uplugin
+T}:T{
+.sp
+Toggle plugin blocker for uri
+T}
+T{
+.sp
+toggle_plugins_uri_tmp
+T}:T{
+.sp
+tuplugin
+T}:T{
+.sp
+Toggle plugin blocker for uri for this session
+T}
+T{
+.sp
+toggle_scripts_host
+T}:T{
+.sp
+hscript
+T}:T{
+.sp
+Toggle scripts for current domain
+T}
+T{
+.sp
+toggle_scripts_host_tmp
+T}:T{
+.sp
+thscript
+T}:T{
+.sp
+Toggle scripts for current host for this session
+T}
+T{
+.sp
+toggle_scripts_uri
+T}:T{
+.sp
+uscript
+T}:T{
+.sp
+Toggle scripts for current uri
+T}
+T{
+.sp
+toggle_scripts_uri_tmp
+T}:T{
+.sp
+tuscript
+T}:T{
+.sp
+Toggle scripts for current uri for this session
+T}
+T{
+.sp
+toggle_setting
+T}:T{
+.sp
+tog, toggle
+T}:T{
+.sp
+Toggle a setting
+T}
+T{
+.sp
+toggle_local_setting
+T}:T{
+.sp
+loctog
+T}:T{
+.sp
+Toggle a setting for the current session
+T}
+T{
+.sp
+toggle_statusbar
+T}:T{
+.sp
+sbar
+T}:T{
+.sp
+Toggle statusbar
+T}
+T{
+.sp
+toggle_tabbar
+T}:T{
+.sp
+tbar
+T}:T{
+.sp
+Toggle tabbar
+T}
+T{
+.sp
+undo
+T}:T{
+.sp
+u
+T}:T{
+.sp
+Undo closing last tab
+T}
+T{
+.sp
+view_source
+T}:T{
+.sp
+so, source
+T}:T{
+.sp
+View page source
+T}
+T{
+.sp
+visible
+T}:T{
+.sp
+vis
+T}:T{
+.sp
+Toggle visibility of a tab
+T}
+T{
+.sp
+web_inspector
+T}:T{
+.sp
+insp, inspect
+T}:T{
+.sp
+Open the webinspector
+T}
+T{
+.sp
+win_bookmarks
+T}:T{
+.sp
+winmarks
+T}:T{
+.sp
+Show bookmarks, open in new window
+T}
+T{
+.sp
+win_hist_back
+T}:T{
+.sp
+wba, winback
+T}:T{
+.sp
+Go back in a new window
+T}
+T{
+.sp
+win_hist_forward
+T}:T{
+.sp
+wfo, winforward
+T}:T{
+.sp
+Go forward in a new window
+T}
+T{
+.sp
+win_paste
+T}:T{
+.sp
+wpaste
+T}:T{
+.sp
+Open from clipboard in a new window
+T}
+T{
+.sp
+win_paste_primary
+T}:T{
+.sp
+wppaste
+T}:T{
+.sp
+Open primary selection in a new window
+T}
+T{
+.sp
+win_quickmark
+T}:T{
+.sp
+winqmarks
+T}:T{
+.sp
+Open quickmark in a new window
+T}
+T{
+.sp
+winopen
+T}:T{
+.sp
+w, wopen
+T}:T{
+.sp
+Open in a new window
+T}
+T{
+.sp
+winopen_url
+T}:T{
+.sp
+T}:T{
+.sp
+Open in a new window, edit current url
+T}
+T{
+.sp
+yank
+T}:T{
+.sp
+T}:T{
+.sp
+Yank url to clipboard
+T}
+T{
+.sp
+yank_primary
+T}:T{
+.sp
+pyank
+T}:T{
+.sp
+Yank url to primary selection
+T}
+T{
+.sp
+yank_title
+T}:T{
+.sp
+tyank
+T}:T{
+.sp
+Yank title to clipboard
+T}
+T{
+.sp
+yank_title_primary
+T}:T{
+.sp
+tpyank
+T}:T{
+.sp
+Yank title to primary selection
+T}
+T{
+.sp
+zoom
+T}:T{
+.sp
+z
+T}:T{
+.sp
+Zoom
+T}
+T{
+.sp
+zoom_in
+T}:T{
+.sp
+zi
+T}:T{
+.sp
+Zoom in
+T}
+T{
+.sp
+zoom_out
+T}:T{
+.sp
+zo
+T}:T{
+.sp
+Zoom out
+T}
+.TE
+.sp 1
+.sp
+dwb can be customized in a web interface (command \fIshow_settings\fR) or via command line (command \fIset_setting\fR)\&. Modified settings will be saved in Modified settings will be saved in \fI~/\&.config/dwb/settings\fR when closing dwb\&. Shorcuts can also be modified in a web interface (command \fIshow_keys\fR) or via command line (command \fIset_key\fR)\&. Shortcuts will be saved in \fI$HOME/\&.config/dwb/keys\fR\&.
+.sp
+If a string value is set to \fINULL\fR the default value will be used\&.
+.SS "WebKit builtin settings"
+.PP
+\fBauto\-load\-images\fR
+.RS 4
+Load images automatically\&. Possible values: true/false, default value:
+\fItrue\fR\&.
+.RE
+.PP
+\fBauto\-resize\-window\fR
+.RS 4
+Resize window through DOM\-methods\&. Possible values: true/false, default value:
+\fIfalse\fR\&.
+.RE
+.PP
+\fBauto\-shrink\-images\fR
+.RS 4
+Automatically shrink standalone images to fit\&. Possible values: true/false, default value:
+\fItrue\fR\&.
+.RE
+.PP
+\fBcursive\-font\-family\fR
+.RS 4
+Default cursive font family used to display text\&. Possible values: a font description or NULL, default value:
+\fINULL\fR\&.
+.RE
+.PP
+\fBcustom\-encoding\fR
+.RS 4
+A custom encoding used for the webview\&. Possible values: encoding string or NULL, default value:
+\fINULL\fR\&.
+.RE
+.PP
+\fBdefault\-encoding\fR
+.RS 4
+The default encoding used to display text\&. Possible values: encoding string or NULL, default value:
+\fINULL\fR\&.
+.RE
+.PP
+\fBdefault\-font\-family\fR
+.RS 4
+The default font family used to display text\&. Possible values: a font description or NULL, default value:
+\fIsans\-serif\fR\&.
+.RE
+.PP
+\fBdefault\-font\-size\fR
+.RS 4
+The default font size used to display text\&. Possible values: a font size (integer), default value:
+\fI12\fR\&.
+.RE
+.PP
+\fBdefault\-monospace\-font\-size\fR
+.RS 4
+The default font size used to display monospace text\&. Possible values: a font size (integer), default value:
+\fI10\fR\&.
+.RE
+.PP
+\fBeditable\fR
+.RS 4
+Whether the content of a webpage should be editable\&. Possible values: true/false, default value:
+\fIfalse\fR\&.
+.RE
+.PP
+\fBenable\-caret\-browsing\fR
+.RS 4
+Whether to enable caret browsing\&. Possible values: true/false, default value:
+\fIfalse\fR\&.
+.RE
+.PP
+\fBenable\-default\-context\-menu\fR
+.RS 4
+Whether right\-clicks open a context menu\&. Possible values: true/false, default value:
+\fIfalse\fR\&.
+.RE
+.PP
+\fBenable\-dns\-prefetching\fR
+.RS 4
+Whether webkit prefetches domain names\&. default value:
+\fItrue\fR\&.
+.RE
+.PP
+\fBenable\-developer\-extras\fR
+.RS 4
+Whether the web\-inspector should be enabled\&. Possible values: true/false, default value:
+\fIfalse\fR\&.
+.RE
+.PP
+\fBenable\-dom\-paste\fR
+.RS 4
+Whether enable DOM\-paste\&. Possible values: true/false, default value:
+\fIfalse\fR\&.
+.RE
+.PP
+\fBenable\-frame\-flattening\fR
+.RS 4
+Whether to enable the Frame Flattening\&. With this setting each subframe is expanded to its contents, which will flatten all the frames to become one scrollable page\&. Whether file uris can be accessed\&. Possible values: true/false, default value:
+\fIfalse\fR\&.
+.RE
+.PP
+\fBenable\-file\-access\-from\-file\-uris\fR
+.RS 4
+Whether file uris can be accessed\&. Possible values: true/false, default value:
+\fItrue\fR\&.
+.RE
+.PP
+\fBenable\-html5\-database\fR
+.RS 4
+Whether to enable HTML5 client\-side SQL database support\&. Possible values: true/false, default value:
+\fItrue\fR\&.
+.RE
+.PP
+\fBenable\-html5\-local\-storage\fR
+.RS 4
+Whether to enable HTML5 localStorage support\&. Possible values: true/false, default value:
+\fItrue\fR\&.
+.RE
+.PP
+\fBenable\-java\-applet\fR
+.RS 4
+Whether to enable Java <applet>\-tag\&. Possible values: true/false, default value:
+\fItrue\fR\&.
+.RE
+.PP
+\fBenable\-offline\-web\-application\-cache\fR
+.RS 4
+Enable or disable HTML5 offline web application cache support\&. Possible values: true/false, default value:
+\fItrue\fR\&.
+.RE
+.PP
+\fBenable\-page\-cache\fR
+.RS 4
+Enable or disable page cache\&. Possible values: true/false, default value:
+\fIfalse\fR\&.
+.RE
+.PP
+\fBenable\-plugins\fR
+.RS 4
+Enable or disable embedded plugins\&. Possible values: true/false, default value:
+\fItrue\fR\&.
+.RE
+.PP
+\fBenable\-private\-browsing\fR
+.RS 4
+Enable or disable private browsing\&. Possible values: true/false, default value:
+\fIfalse\fR\&.
+.RE
+.PP
+\fBenable\-scripts\fR
+.RS 4
+Enable or disable embedded scripting\-languages\&. Possible values: true/false, default value:
+\fItrue\fR\&.
+.RE
+.PP
+\fBenable\-site\-specific\-quirks\fR
+.RS 4
+Enables the site\-specific compatibility workarounds\&. Possible values: true/false, default value:
+\fIfalse\fR\&.
+.RE
+.PP
+\fBenable\-spatial\-navigation\fR
+.RS 4
+Whether to enable the Spatial Navigation\&. This feature consists in the ability to navigate between focusable elements in a Web page, such as hyperlinks and form controls, by using Left, Right, Up and Down arrow keys\&. Possible values: true/false, default value:
+\fIfalse\fR\&.
+.RE
+.PP
+\fBenable\-spell\-checking\fR
+.RS 4
+Whether to enable spell checking\&. Possible values: true/false, default value:
+\fIfalse\fR\&.
+.RE
+.PP
+\fBenable\-universal\-access\-from\-file\-uris\fR
+.RS 4
+Whether to allow files loaded through file:// URIs universal access to all pages\&. Possible values: true/false, default value:
+\fItrue\fR\&.
+.RE
+.PP
+\fBenable\-xss\-auditor\fR
+.RS 4
+Whether to enable the XSS Auditor\&. This feature filters some kinds of reflective XSS attacks on vulnerable web sites\&. Possible values: true/false, default value:
+\fItrue\fR\&.
+.RE
+.PP
+\fBenforce\-96\-dpi\fR
+.RS 4
+Enforce a resolution of 96 DPI\&. Possible values: true/false, default value:
+\fIfalse\fR\&.
+.RE
+.PP
+\fBfantasy\-font\-family\fR
+.RS 4
+Default fantasy font family used to display text\&. Possible values: a font description or NULL, default value:
+\fIserif\fR\&.
+.RE
+.PP
+\fBjavascript\-can\-access\-clipboard\fR
+.RS 4
+Whether javascript can access Clipboard\&. Possible values: true/false, default value:
+\fIfalse\fR\&.
+.RE
+.PP
+\fBfull\-content\-zoom\fR
+.RS 4
+Whether the full content is scaled when zooming\&. Possible values: true/false, default value:
+\fIfalse\fR\&.
+.RE
+.PP
+\fBjavascript\-can\-open\-windows\-automatically\fR
+.RS 4
+Whether JavaScript can open popup windows automatically without user intervention\&. Possible values: true/false, default value:
+\fIfalse\fR\&.
+.RE
+.PP
+\fBminimum\-font\-size\fR
+.RS 4
+The minimum font size used to display text\&. Possible values: a font size (integer), default value:
+\fI5\fR\&.
+.RE
+.PP
+\fBminimum\-logical\-font\-size\fR
+.RS 4
+The minimum logical font size used to display text\&. Possible values: a font size (integer), default value:
+\fI5\fR\&.
+.RE
+.PP
+\fBmonospace\-font\-family\fR
+.RS 4
+Default font family used to display monospace text\&. Possible values: a font description or NULL, default value:
+\fImonospace\fR\&.
+.RE
+.PP
+\fBprint\-backgrounds\fR
+.RS 4
+Whether background images should be printed\&. Possible values: true/false, default value:
+\fItrue\fR\&.
+.RE
+.PP
+\fBresizable\-text\-areas\fR
+.RS 4
+Whether text areas are resizable\&. Possible values: true/false, default value:
+\fItrue\fR\&.
+.RE
+.PP
+\fBsans\-serif\-font\-family\fR
+.RS 4
+Default sans\-serif font family used to display text\&. Possible values: a font description or NULL, default value:
+\fIsans\-serif\fR\&.
+.RE
+.PP
+\fBserif\-font\-family\fR
+.RS 4
+Default serif font family used to display text\&. Possible values: a font description or NULL, default value:
+\fIserif\fR\&.
+.RE
+.PP
+\fBspell\-checking\-language\fR
+.RS 4
+The languages to be used for spell checking, separated by commas\&. Possible values: a string or NULL, default value:
+\fINULL\fR\&.
+.RE
+.PP
+\fBtab\-cycles\-through\-elements\fR
+.RS 4
+Whether the tab key cycles through elements on the page\&. Possible values: true/false, default value:
+\fItrue\fR\&.
+.RE
+.PP
+\fBuser\-agent\fR
+.RS 4
+The user\-agent\-string\&. Possible values: a user\-agent or NULL, default value:
+\fINULL\fR\&.
+.RE
+.PP
+\fBuser\-stylesheet\-uri\fR
+.RS 4
+The URI of a stylesheet that is applied to every page\&. If a local file is used, must start with file://\&. Possible values: an uri\-string or NULL, default value:
+\fINULL\fR\&.
+.RE
+.PP
+\fBzoom\-level\fR
+.RS 4
+The zoom level of the content\&. Possible values: a decimal, default value:
+\fI1\&.0\fR\&.
+.RE
+.PP
+\fBzoom\-step\fR
+.RS 4
+The value by which the zoom level is changed when zooming in or out\&. Possible values: a decimal, default value:
+\fI0\&.1\fR\&.
+.RE
+.SS "Other settings"
+.PP
+\fBactive\-completion\-bg\-color\fR
+.RS 4
+The background color for an active element in tab\-completion\&. Possible values: an rgb color\-string, default value:
+\fI#000000\fR\&.
+.RE
+.PP
+\fBactive\-completion\-fg\-color\fR
+.RS 4
+The foreground color for an active element in tab\-completion\&. Possible values: an rgb color\-string\&. default value:
+\fI#53868b\fR\&.
+.RE
+.PP
+\fBadblocker\fR
+.RS 4
+Block advertisements using a filterlist, see also \&.IR adblocker\-filterlist \&. Default value:
+\fIfalse\fR\&.
+.RE
+.PP
+\fBadblocker\-filterlist\fR
+.RS 4
+A path to a adblock plus compatible filterlist for the adblocker\&. Default value:
+\fINULL\fR\&.
+.RE
+.PP
+\fBbackground\-color\fR
+.RS 4
+The background color of the statusbar\&. Possible values: an rgb color\-string, default value:
+\fI#000000\fR\&.
+.RE
+.PP
+\fBforeground\-color\fR
+.RS 4
+The foreground color of statusbar\&. Possible values: an rgb color\-string\&. default value:
+\fI#ffffff\fR\&.
+.RE
+.PP
+\fBauto\-completion\fR
+.RS 4
+Whether possible keystrokes should be shown\&. (Shift\-) Tab cycles through keystrokes\&. Possible values: true/false, default value:
+\fItrue\fR\&.
+.RE
+.PP
+\fBauto\-insert\-mode\fR
+.RS 4
+Whether to go automatically in insert mode if an editable element has focus after loading a site\&. Possible values: true/false, default value:
+\fIfalse\fR\&.
+.RE
+.PP
+\fBbackground\-tabs\fR
+.RS 4
+Open new tabs in background\&. Possible values: true/false, default value:
+\fIfalse\fR\&.
+.RE
+.PP
+\fBcache\-model\fR
+.RS 4
The cache model used by webkit, possible values are
-.B webbrowser
-and
-.BR documentviewer .
-Webbrowser increases loading speed but increases memory usage, documentviewer
-reduces memory usage but also decreases browsing speed. Default Value:
-.IR webbrowser .
-.TP
-.BR close-tab-focus-policy
-Controls the focus when the focused tab is closed, possible values are
-.IR right ,
-.IR left ,
-.IR rightmost ,
+\fIwebbrowser\fR
and
-.IR leftmost ;
-default value:
-.IR right .
-.TP
-.BR complete-bookmarks
-Whether to complete bookmarks with tab-completion. Possible values: true/false,
-default value:
-.IR true .
-.TP
-.BR complete-history
-Whether to complete browsing history with tab-completion. Possible values:
-true/false,
-default value:
-.IR true .
-.TP
-.BR complete-searchengines
-Whether to complete searchengines with tab-completion. Possible values:
-true/false,
-default value:
-.IR false .
-.TP
-.BR complete-userscripts
-Whether to complete userscripts with tab-completion. Possible values:
-true/false,
-default value:
-.IR false .
-.TP
-.BR cookies-store-policy
-The storage policy for cookies, possible values are
-.IR session ,
-.IR persistent ,
-and
-.IR never .
-If set to
-.I session
-all session cookies are accepted, only cookies with a matching domain in
-cookies.allow will be stored persistently.
-If set to
-.I persistent
-all cookies are stored persistently.
-If set to
-.I never
-the cookies allowed by cookies_session.allow are allowed for the current
-session and cookies allowed by cookies.allow are save persistently, all other
-cookies are rejected.
-Default value:
-.IR session .
-.TP
-.BR cookies-accept-policy
-The accept policy for cookies.
-.IR always
-will accept all cookies,
-.IR nothirdparty
+\fIdocumentviewer\fR\&. Webbrowser increases loading speed but increases memory usage, documentviewer reduces memory usage but also decreases browsing speed\&. Default Value:
+\fIwebbrowser\fR\&.
+.RE
+.PP
+\fBclose\-tab\-focus\-policy\fR
+.RS 4
+Controls the focus when the focused tab is closed, possible values are
+\fIright\fR,
+\fIleft\fR,
+\fIrightmost\fR, and
+\fIleftmost\fR; default value:
+\fIright\fR\&.
+.RE
+.PP
+\fBcomplete\-bookmarks\fR
+.RS 4
+Whether to complete bookmarks with tab\-completion\&. Possible values: true/false, default value:
+\fItrue\fR\&.
+.RE
+.PP
+\fBcomplete\-history\fR
+.RS 4
+Whether to complete browsing history with tab\-completion\&. Possible values: true/false, default value:
+\fItrue\fR\&.
+.RE
+.PP
+\fBcomplete\-searchengines\fR
+.RS 4
+Whether to complete searchengines with tab\-completion\&. Possible values: true/false, default value:
+\fIfalse\fR\&.
+.RE
+.PP
+\fBcomplete\-userscripts\fR
+.RS 4
+Whether to complete userscripts with tab\-completion\&. Possible values: true/false, default value:
+\fIfalse\fR\&.
+.RE
+.PP
+\fBcookies\-store\-policy\fR
+.RS 4
+The storage policy for cookies, possible values are
+\fIsession\fR,
+\fIpersistent\fR, and
+\fInever\fR\&. If set to session all session cookies are accepted, only cookies with a matching domain in cookies\&.allow will be stored persistently\&. If set to
+\fIpersistent\fR
+all cookies are stored persistently\&. If set to
+\fInever\fR
+the cookies allowed by cookies_session\&.allow are allowed for the current session and cookies allowed by cookies\&.allow are save persistently, all other cookies are rejected\&. Default value:
+\fIsession\fR\&.
+.RE
+.PP
+\fBcookies\-accept\-policy\fR
+.RS 4
+The accept policy for cookies\&.
+\fIalways\fR
+will accept all cookies,
+\fInothirdparty\fR
will accept all cookies except for third party cookies,
-.IR never
-will reject all cookies. This setting also affects session cookies.
-default value:
-.IR always .
-.TP
-.TP
-.BR default-width
-The default width of dwb's window. Possible values: width in pixel,
-default value:
-.IR 800 .
-.TP
-.BR default-height
-The default height of dwb's window. Possible values: height in pixel,
-default value:
-.IR 600 .
-.TP
-.BR download-fg-color
-The foreground color of the download bar, default value:
-.IR #ffffff .
-.TP
-.BR download-bg-color
-The background color of the download bar, default value:
-.IR #000000 .
-.TP
-.BR download-gradient-start
-The start color for the download progress gradient color, default value
-.IR #0000aa .
-.TP
-.BR download-gradient-stop
-The end color for the download progress gradient color, default value
-.IR #00aa00 .
-.TP
-.BR download-external-command
-A command that will be invoked if 'download-use-external-program' is set. There
-are four variables that can be used in the command:
-.IR dwb_uri
-will be replaced with the download-uri,
-.IR dwb_output
-will be replaced with the fullpath of the destination,
-.IR dwb_cookies
-will be replaced with the path to the cookie-file,
-.IR dwb_referer
-will be replaced with the uri of the site the download started.
-Additionally the environment-variables
-.IR DWB_URI ,
-.IR DWB_FILENAME ,
-.IR DWB_COOKIES ,
-.IR DWB_REFERER ,
-.IR DWB_MIME_TYPE
-and
-.I DWB_USER_AGENT
-are set.
-Default value:
-.I xterm -e wget dwb_uri -O dwb_output --load-cookies
-.IR dwb_cookies .
-.TP
-.BR download-directory
-The default download directory, if empty, the current working directory is used
-or the last download path is used.
-default value:
-.IR NULL .
-.TP
-.BR download-no-confirm
+\fInever\fR
+will reject all cookies\&. This setting also affects session cookies\&. default value:
+\fIalways\fR\&.
+.RE
+.PP
+\fBdefault\-width\fR
+.RS 4
+The default width of dwb\(cqs window\&. Possible values: width in pixel, default value:
+\fI800\fR\&.
+.RE
+.PP
+\fBdefault\-height\fR
+.RS 4
+The default height of dwb\(cqs window\&. Possible values: height in pixel, default value:
+\fI600\fR\&.
+.RE
+.PP
+\fBdownload\-fg\-color\fR
+.RS 4
+The foreground color of the download bar, default value:
+\fI#ffffff\fR\&.
+.RE
+.PP
+\fBdownload\-bg\-color\fR
+.RS 4
+The background color of the download bar, default value:
+\fI#000000\fR\&.
+.RE
+.PP
+\fBdownload\-gradient\-start\fR
+.RS 4
+The start color for the download progress gradient color, default value
+\fI#0000aa\fR\&.
+.RE
+.PP
+\fBdownload\-gradient\-stop\fR
+.RS 4
+The end color for the download progress gradient color, default value
+\fI#00aa00\fR\&.
+.RE
+.PP
+\fBdownload\-external\-command\fR
+.RS 4
+A command that will be invoked if
+\fIdownload\-use\-external\-program\fR
+is set\&. There are four variables that can be used in the command:
+\fIdwb_uri\fR
+will be replaced with the download\-uri,
+\fIdwb_output\fR
+will be replaced with the fullpath of the destination,
+\fIdwb_cookies\fR
+will be replaced with the path to the cookie\-file,
+\fIdwb_referer\fR
+will be replaced with the uri of the site the download started\&. Additionally the environment\-variables
+\fIDWB_URI\fR,
+\fIDWB_FILENAME\fR,
+\fIDWB_COOKIES\fR,
+\fIDWB_REFERER\fR,
+\fIDWB_MIME_TYPE\fR
+and
+\fIDWB_USER_AGENT\fR
+are set\&. Default value:
+\fIxterm \-e wget dwb_uri \-O dwb_output \-\-load\-cookies dwb_cookies\fR\&.
+.RE
+.PP
+\fBdownload\-directory\fR
+.RS 4
+The default download directory, if empty, the current working directory is used or the last download path is used\&. default value:
+\fINULL\fR\&.
+.RE
+.PP
+\fBdownload\-no\-confirm\fR
+.RS 4
Whether to start downloads immediately without asking for a path,
-.I download-directory
-needs to be set to an existing path.
-default value:
-.IR false .
-.TP
-.BR download-use-external-program
-Whether to use an external download program specified in
-\'download-external-programm\' or the builtin download helper.
-Possible values: true/false,
-default value:
-.IR true .
-.TP
-.BR editor
-External editor used for inputs/textareas.
-default value:
-.IR xterm\ -e\ vim\ dwb_uri .
-.TP
-.BR enable-favicon
-Whether to show a favicon in the tab.
-default value:
-.IR true .
-.TP
-.BR error-color
-The color for error-messages. Possible values: an rgb color-string,
-default value:
-.IR #ff0000 .
-.TP
-.BR error-color
-The color for prompt-messages. Possible values: an rgb color-string,
-default value:
-.IR #00ff00 .
-.TP
-.BR font
-The font used for the ui. Possible values: a font description
-string,
-default value:
-.I monospace\ 8.
-.TP
-.BR font-completion
-The font used for tabcompletion. Possible values: a font description
-string,
-default value:
-.TP
-.BR font-entry
-The font used for the address bar. Possible values: a font description
-string,
-default value:
-.TP
-.BR font-hidden-statusbar
-The font used for status elements if the statusbar is hidden. Possible values: a
-css font description.
-Default value:
-.BR normal 10px helvetica .
-.TP
-.BR font-nofocus
-The font used for tablabels without focus and completion items without focus. Possible values: a font description
-string,
-default value:
-.TP
-.BR hint-active-color
-The background color for active link, i.e. the link followed when Return is
-pressed. Possible values: a rgb color string,
-default value:
-.IR #00ff00 .
-.TP
-.BR hint-autofollow
-Whether to follow hints automatically if only one hint matches the typed
-letters. Default value:
-.IR true .
-.TP
-.BR hint-bg-color
-The background color used for hints. Possible values: a rgb color string,
-default value:
-.IR #000088 .
-.TP
-.BR hint-border
-The boreder used for hints. Possible values: a css border description,
-default value:
-.IR 2px\ dashed\ #000000 .
-.TP
-.BR hint-fg-color
-The foreground color used for hints. Possible values: a rgb color string,
-default value:
-.IR #ffffff .
-.TP
-.BR hint-font
-The font used for hints. Possible values: css font description,
-default value:
-.IR bold\ 10px\ monospace .
-.TP
-.BR hint-highlight-links
-Whether to highlight all links in hint-mode,
-default value:
-.IR false .
-.TP
-.BR hint-letter-seq
-A letter sequence used for letter hints. Possible values: a letter sequence,
-every letter should appear only once.
-Default value:
-.IR FDSARTGBVECWXQYIOPMNHZULKJ .
-.TP
-.BR hint-normal-color
-The background color for a normal link. Possible values: a rgb color string,
-default value:
-.IR #ffff99 .
-.TP
-.BR hint-opacity
-The opacity of a hint. Possible values: a decimal from 0.0 to 1.0,
-default value:
-.IR 0.75 .
-.TP
-.BR hint-style
-The type of hints, that are used. When set to "number", letters will match the
-links text. Possible values: letter/number,
-default value:
-.IR letter .
-.TP
-.BR history-length
-The urls that are saved in the browsing history. Specifying a too large value
-can make tab-completion slow. Possible values: number of urls,
-default value:
-.IR 500 .
-.TP
-.BR insertmode-bg-color
-The background color of the statusbar in insertmode. Possible values: an rgb
-color-string,
-default value:
-.IR #dddddd .
-.TP
-.BR insertmode-fg-color
-The foreground color of the statusbar in insertmode. Possible values: an rgb
-color-string,
-default value:
-.IR #000000 .
-.TP
-.BR javascript-schemes
-Whether to allow loading javascript snippets with scheme 'javascript',
-default value:
-.IR true .
-.TP
-.BR message-delay
-The duration messages are shown. Possible values: duration in seconds (integer),
-default value:
-.IR 2 .
-.TP
-.BR navigation-history-max
-Maximum length of navigation history. 'enable-private-browsing' must be disabled to
-save command history at all.
-default value:
-.IR 500 .
-.TP
-.BR new-tab-position-policy
-Controls the position of a newly created tab, possible values are
-.IR right ,
-a new tab is created right of the current tab,
-.IR left ,
-a new tab is created left of the current tab,
-.IR rightmost ,
-a new tab is created left of the last tab and
-.IR leftmost ,
-a new tab is created left of the first tab.
-Default value:
-.IR right .
-.TP
-.BR normal-completion-bg-color
-The background color of inactive element in tab-completion. Possible values: an
-rgb color-string,
-default value:
-.IR #151515 .
-.TP
-.BR normal-completion-fg-color
-The foreground color of inactive element in tab-completion. Possible values: an rgb color-string.
-color-string,
-default value:
-.IR #eeeeee .
-.TP
-.BR proxy
-Whether to use a HTTP-proxy. Possible values: true/false,
-default value:
-.IR false .
-.TP
-.BR proxy-url
-The proxy-url, can also be set via the http_proxy environment variable. Possible
-values: an url string,
-default value:
-.IR NULL .
-.TP
-.BR save-session
-Save the session when dwb is closed and restore the last saved session when
-invoking dwb. Possible values: true/false,
-default value:
-.IR false .
-.TP
-.BR scheme-handler
-A script or application that handles uris that cannot be loaded by dwb. dwb only
-loads uris with scheme
-.BR http ,
-.BR https ,
-.BR file ,
-.B about
-and
-.BR dwb ;
-support for e.g. ftp is provided through a scheme handler. The scheme handler
-can either be an application or a script. The first command line argument will
-be the uri for your application, so you can simply set this to
-.IR xdg-open .
-There are also the environment variables
-.IR DWB_URI ,
-.IR DWB_SCHEME ,
-.IR DWB_COOKIES ,
-.IR DWB_USER_AGENT ,
-and
-.I DWB_REFERER
+\fIdownload\-directory\fR
+needs to be set to an existing path\&. default value:
+\fIfalse\fR\&.
+.RE
+.PP
+\fBdownload\-use\-external\-program\fR
+.RS 4
+Whether to use an external download program specified in \*(Aqdownload\-external\-programm\e\*(Aq or the builtin download helper\&. Possible values: true/false, default value:
+\fItrue\fR\&.
+.RE
+.PP
+\fBeditor\fR
+.RS 4
+External editor used for inputs/textareas\&. default value:
+\fIxterm \-e vim dwb_uri\fR\&.
+.RE
+.PP
+\fBenable\-favicon\fR
+.RS 4
+Whether to show a favicon in the tab\&. default value:
+\fItrue\fR\&.
+.RE
+.PP
+\fBerror\-color\fR
+.RS 4
+The color for error\-messages\&. Possible values: an rgb color\-string, default value:
+\fI#ff0000\fR\&.
+.RE
+.PP
+\fBerror\-color\fR
+.RS 4
+The color for prompt\-messages\&. Possible values: an rgb color\-string, default value:
+\fI#00ff00\fR\&.
+.RE
+.PP
+\fBfont\fR
+.RS 4
+The font used for the ui\&. Possible values: a font description string, default value:
+\fImonospace 8\fR\&.
+.RE
+.PP
+\fBfont\-completion\fR
+.RS 4
+The font used for tabcompletion\&. Possible values: a font description string\&.
+.RE
+.PP
+\fBfont\-entry\fR
+.RS 4
+The font used for the address bar\&. Possible values: a font description string\&.
+.RE
+.PP
+\fBfont\-hidden\-statusbar\fR
+.RS 4
+The font used for status elements if the statusbar is hidden\&. Possible values: a css font description\&. Default value: \*(Aqnormal\(cq10px helvetica \&.
+.RE
+.PP
+\fBfont\-nofocus\fR
+.RS 4
+The font used for tablabels without focus and completion items without focus\&. Possible values: a font description string\&.
+.RE
+.PP
+\fBhint\-active\-color\fR
+.RS 4
+The background color for active link, i\&.e\&. the link followed when Return is pressed\&. Possible values: a rgb color string, default value:
+\fI#00ff00\fR\&.
+.RE
+.PP
+\fBhint\-autofollow\fR
+.RS 4
+Whether to follow hints automatically if only one hint matches the typed letters\&. Default value:
+\fItrue\fR\&.
+.RE
+.PP
+\fBhint\-bg\-color\fR
+.RS 4
+The background color used for hints\&. Possible values: a rgb color string, default value:
+\fI#000088\fR\&.
+.RE
+.PP
+\fBhint\-border\fR
+.RS 4
+The boreder used for hints\&. Possible values: a css border description, default value:
+\fI2px dashed #000000\fR\&.
+.RE
+.PP
+\fBhint\-fg\-color\fR
+.RS 4
+The foreground color used for hints\&. Possible values: a rgb color string, default value:
+\fI#ffffff\fR\&.
+.RE
+.PP
+\fBhint\-font\fR
+.RS 4
+The font used for hints\&. Possible values: css font description, default value:
+\fIbold 10px monospace\fR\&.
+.RE
+.PP
+\fBhint\-highlight\-links\fR
+.RS 4
+Whether to highlight all links in hint\-mode, default value:
+\fIfalse\fR\&.
+.RE
+.PP
+\fBhint\-letter\-seq\fR
+.RS 4
+A letter sequence used for letter hints\&. Possible values: a letter sequence, every letter should appear only once\&. Default value:
+\fIFDSARTGBVECWXQYIOPMNHZULKJ\fR\&.
+.RE
+.PP
+\fBhint\-normal\-color\fR
+.RS 4
+The background color for a normal link\&. Possible values: a rgb color string, default value:
+\fI#ffff99\fR\&.
+.RE
+.PP
+\fBhint\-opacity\fR
+.RS 4
+The opacity of a hint\&. Possible values: a decimal from 0\&.0 to 1\&.0, default value:
+\fI0\&.75\fR\&.
+.RE
+.PP
+\fBhint\-style\fR
+.RS 4
+The type of hints, that are used\&. When set to "number", letters will match the links text\&. Possible values: letter/number, default value:
+\fIletter\fR\&.
+.RE
+.PP
+\fBhistory\-length\fR
+.RS 4
+The urls that are saved in the browsing history\&. Specifying a too large value can make tab\-completion slow\&. Possible values: number of urls, default value:
+\fI500\fR\&.
+.RE
+.PP
+\fBinsertmode\-bg\-color\fR
+.RS 4
+The background color of the statusbar in insertmode\&. Possible values: an rgb color\-string, default value:
+\fI#dddddd\fR\&.
+.RE
+.PP
+\fBinsertmode\-fg\-color\fR
+.RS 4
+The foreground color of the statusbar in insertmode\&. Possible values: an rgb color\-string, default value:
+\fI#000000\fR\&.
+.RE
+.PP
+\fBjavascript\-schemes\fR
+.RS 4
+Whether to allow loading javascript snippets with scheme
+\fIjavascript\fR, default value:
+\fItrue\fR\&.
+.RE
+.PP
+\fBmessage\-delay\fR
+.RS 4
+The duration messages are shown\&. Possible values: duration in seconds (integer), default value:
+\fI2\fR\&.
+.RE
+.PP
+\fBnavigation\-history\-max\fR
+.RS 4
+Maximum length of navigation history\&.
+\fIenable\-private\-browsing\fR
+must be disabled to save command history at all\&. default value:
+\fI500\fR\&.
+.RE
+.PP
+\fBnew\-tab\-position\-policy\fR
+.RS 4
+Controls the position of a newly created tab, possible values are
+\fIright\fR, a new tab is created right of the current tab,
+\fIleft\fR, a new tab is created left of the current tab,
+\fIrightmost\fR, a new tab is created left of the last tab and
+\fIleftmost\fR, a new tab is created left of the first tab\&. Default value:
+\fIright\fR\&.
+.RE
+.PP
+\fBnormal\-completion\-bg\-color\fR
+.RS 4
+The background color of inactive element in tab\-completion\&. Possible values: an rgb color\-string, default value:
+\fI#151515\fR\&.
+.RE
+.PP
+\fBnormal\-completion\-fg\-color\fR
+.RS 4
+The foreground color of inactive element in tab\-completion\&. Possible values: an rgb color\-string\&. color\-string, default value:
+\fI#eeeeee\fR\&.
+.RE
+.PP
+\fBproxy\fR
+.RS 4
+Whether to use a HTTP\-proxy\&. Possible values: true/false, default value:
+\fIfalse\fR\&.
+.RE
+.PP
+\fBproxy\-url\fR
+.RS 4
+The proxy\-url, can also be set via the http_proxy environment variable\&. Possible values: an url string, default value:
+\fINULL\fR\&.
+.RE
+.PP
+\fBsave\-session\fR
+.RS 4
+Save the session when dwb is closed and restore the last saved session when invoking dwb\&. Possible values: true/false, default value:
+\fIfalse\fR\&.
+.RE
+.PP
+\fBscheme\-handler\fR
+.RS 4
+A script or application that handles uris that cannot be loaded by dwb\&. dwb only loads uris with scheme
+\fIhttp\fR,
+\fIhttps\fR,
+\fIfile\fR,
+\fIabout\fR
+and
+\fIdwb\fR; support for e\&.g\&. ftp is provided through a scheme handler\&. The scheme handler can either be an application or a script\&. The first command line argument will be the uri for your application, so you can simply set this to
+\fIxdg\-open\fR\&. There are also the environment variables
+\fIDWB_URI\fR,
+\fIDWB_SCHEME\fR,
+\fIDWB_COOKIES\fR,
+\fIDWB_USER_AGENT\fR, and
+\fIDWB_REFERER\fR
available which can be used in a script, for example:
-
+.RE
+.sp
+.if n \{\
+.RS 4
+.\}
.nf
- #!/bin/sh
+#!/bin/sh
- case ${DWB_SCHEME} in
- mailto) xterm -\(hye "mutt ${DWB_URI}";;
- ftp) xterm \(hye "ncftp ${DWB_URI}";;
- *) xdg-open ${DWB_URI}
- esac
+case ${DWB_SCHEME} in
+ mailto) xterm \-\e(hye "mutt ${DWB_URI}";;
+ ftp) xterm \e(hye "ncftp ${DWB_URI}";;
+ *) xdg\-open ${DWB_URI}
+esac
.fi
-
-.TP
-.BR scroll-step
-The step-increment in pixels for scrolling. If set to a value lower or equal 0,
-the default step-increment will be used.
-default value:
-.IR 0.0 .
-.TP
-.BR scrollbars
-Whether scrollbars should be enabled.
-default value:
-.IR false .
-.TP
-.BR single-instance
-Only one instance of dwb per user. This option will be overridden by the
-commandlineoption \(hyn. Possible values: true/false,
-default value:
-.IR true .
-.TP
-.BR ssl-strict
-Whether to allow only save ssl-certificates.
-default value:
-.IR true .
-.TP
-.BR ssl-ca-cert
-Path to ssl-certificate.
-.TP
-.BR ssl-trusted-color
-Color of the url in the statusbar for ssl-encrypted sites and trusted
-certificate.
-default value:
-.IR #00ff00 .
-.TP
-.BR ssl-untrusted-color
-Color of the url in the statusbar for ssl-encrypted sites and untrusted
-certificate.
-default value:
-.IR #ff0000 .
-.TP
-.BR startpage
-The default startpage. Possible values: an url or "about:blank" for an empty
-startpage,
-default value:
-.IR about:blank .
-.TP
-.BR sync-files
-Interval in seconds to save history and cookies to hdd or 0 to immediately save
-to hdd, default value: 0.
-.TP
-.BR tabbar-visible
-When the tabbar is hidden specifies the number of seconds the tabbar is visible
-when switching between tabs.
-.IR 2 .
-.TP
-.BR tab-active-bg-color
-The background color the tab of the focused tab. Possible values: an rgb
-color-string,
-default value:
-.IR #000000 .
-.TP
-.BR tab-active-fg-color
-The foreground color of the tab of the focused tab. Possible values: an rgb
-color-string,
-default value:
-.IR #ffffff .
-.TP
-.BR tab-normal-bg-color
-The background color the tab of a not focused tab. Possible values: an rgb
-color-string,
-default value:
-.IR #505050 .
-.TP
-.BR tab-normal-fg-color
-The foreground color of the tab of a not focused tab. Possible values: an rgb
-color-string,
-default value:
-.IR #cccccc .
-.TP
-.BR tab-normal-fg-color
-The foreground color of the tab of a not focused tab. Possible values: an rgb
-color-string,
-default value:
-.IR #cccccc .
-.TP
-.BR tab-protected-color
-The color of the tabnumber of protected tabs. Possible values: an rgb color-string,
-default value:
-.IR #ff0000 .
-.TP
-.BR tab-number-color
-The color of the tabnumber. Possible values: an rgb color-string,
-default value:
-.IR #ff0000 .
-.TP
-.BR tabbed-browsing
-Enable tabbed-browsing. If disabled, all new window/new tab requests will be
-opened in a new window,
-default value:
-.IR true .
-.TP
-.BR update-search-delay
-Delay in milliseconds before updating search results. If set to 0 search results
-will be updated after every keypress. If set to a value greater than 0 search
-results will be updated after that delay but only if the search-term has not
-changed since the timeout started. It is recommended to set this value greater
-than 0, default value:
-.IR 200 .
-.TP
-.BR use-ntlm
-Whether to use NTLM-authentication,
-default value:
-.IR false .
-.TP
-.BR widget-packing
-A string consisting of 4 characters, where possible characters are:
-.BR d ,
-.BR w ,
-.B T ,
-.BR t ,
-.B S
-and
-.BR s .
-The order of the widgets correspond the the order of characters in the string
-where
-.B d
-corresponds to the download bar,
-.B t
-and
-.B T
-to the tab bar where
-.B T
-means that the tabbar will not be visible,
-.B w
+.if n \{\
+.RE
+.\}
+.PP
+\fBscroll\-step\fR
+.RS 4
+The step\-increment in pixels for scrolling\&. If set to a value lower or equal 0, the default step\-increment will be used\&. default value:
+\fI0\&.0\fR\&.
+.RE
+.PP
+\fBscrollbars\fR
+.RS 4
+Whether scrollbars should be enabled\&. default value:
+\fIfalse\fR\&.
+.RE
+.PP
+\fBsingle\-instance\fR
+.RS 4
+Only one instance of dwb per user\&. This option will be overridden by the commandlineoption \e(hyn\&. Possible values: true/false, default value:
+\fItrue\fR\&.
+.RE
+.PP
+\fBssl\-strict\fR
+.RS 4
+Whether to allow only save ssl\-certificates\&. default value:
+\fItrue\fR\&.
+.RE
+.PP
+\fBssl\-ca\-cert\fR
+.RS 4
+Path to ssl\-certificate, only with libsoup < 2\&.38\&.
+.RE
+.PP
+\fBssl\-use\-system\-ca\-cert\fR
+.RS 4
+Path to ssl\-certificate, only with libsoup >= 2\&.38\&.
+.RE
+.PP
+\fBssl\-trusted\-color\fR
+.RS 4
+Color of the url in the statusbar for ssl\-encrypted sites and trusted certificate\&. default value:
+\fI#00ff00\fR\&.
+.RE
+.PP
+\fBssl\-untrusted\-color\fR
+.RS 4
+Color of the url in the statusbar for ssl\-encrypted sites and untrusted certificate\&. default value:
+\fI#ff0000\fR\&.
+.RE
+.PP
+\fBstartpage\fR
+.RS 4
+The default startpage\&. Possible values: an url or "about:blank" for an empty startpage, default value:
+\fIabout:blank\fR\&.
+.RE
+.PP
+\fBsync\-files\fR
+.RS 4
+Interval in seconds to save history and cookies to hdd or 0 to immediately save to hdd, default value: 0\&.
+.RE
+.PP
+\fBtabbar\-visible\fR
+.RS 4
+When the tabbar is hidden specifies the number of seconds the tabbar is visible when switching between tabs, default value:
+\fI2\fR\&.
+.RE
+.PP
+\fBtab\-active\-bg\-color\fR
+.RS 4
+The background color the tab of the focused tab\&. Possible values: an rgb color\-string, default value:
+\fI#000000\fR\&.
+.RE
+.PP
+\fBtab\-active\-fg\-color\fR
+.RS 4
+The foreground color of the tab of the focused tab\&. Possible values: an rgb color\-string, default value:
+\fI#ffffff\fR\&.
+.RE
+.PP
+\fBtab\-normal\-bg\-color\fR
+.RS 4
+The background color the tab of a not focused tab\&. Possible values: an rgb color\-string, default value:
+\fI#505050\fR\&.
+.RE
+.PP
+\fBtab\-normal\-fg\-color\fR
+.RS 4
+The foreground color of the tab of a not focused tab\&. Possible values: an rgb color\-string, default value:
+\fI#cccccc\fR\&.
+.RE
+.PP
+\fBtab\-normal\-fg\-color\fR
+.RS 4
+The foreground color of the tab of a not focused tab\&. Possible values: an rgb color\-string, default value:
+\fI#cccccc\fR\&.
+.RE
+.PP
+\fBtab\-protected\-color\fR
+.RS 4
+The color of the tabnumber of protected tabs\&. Possible values: an rgb color\-string, default value:
+\fI#ff0000\fR\&.
+.RE
+.PP
+\fBtab\-number\-color\fR
+.RS 4
+The color of the tabnumber\&. Possible values: an rgb color\-string, default value:
+\fI#ff0000\fR\&.
+.RE
+.PP
+\fBtabbed\-browsing\fR
+.RS 4
+Enable tabbed\-browsing\&. If disabled, all new window/new tab requests will be opened in a new window, default value:
+\fItrue\fR\&.
+.RE
+.PP
+\fBupdate\-search\-delay\fR
+.RS 4
+Delay in milliseconds before updating search results\&. If set to 0 search results will be updated after every keypress\&. If set to a value greater than 0 search results will be updated after that delay but only if the search\-term has not changed since the timeout started\&. It is recommended to set this value greater than 0, default value:
+\fI200\fR\&.
+.RE
+.PP
+\fBuse\-ntlm\fR
+.RS 4
+Whether to use NTLM\-authentication, default value:
+\fIfalse\fR\&.
+.RE
+.PP
+\fBwidget\-packing\fR
+.RS 4
+A string consisting of 4 characters, where possible characters are:
+\fId\fR,
+\fIw\fR,
+\fIT\fR,
+\fIt\fR,
+\fIS\fR
+and
+\fIs\fR\&. The order of the widgets correspond the the order of characters in the string where
+\fId\fR
+corresponds to the download bar,
+\fIt\fR
+and
+\fIT\fR
+to the tab bar where
+\fIT\fR
+means that the tabbar will not be visible,
+\fIw\fR
to the webview and
-.B s
-and
-.B S
-to the statusbar where
-.B S
-means that the statusbar won't be visible.
-Default value:
-.IR dtws .
-
-.SH FILES
-.SS Scripts
-Javascript userscripts can be stored in
-.IR ~/.config/dwb/scripts .
-The scripts are applied to pages depending on their filename extension, there
-are 4 possible extensions:
-.TP
-.B .js
-Scripts with extension
-.I .js
-are injected into the page directly after the load of a
-new page is committed.
-.TP
-.B .all.js
-Scripts with extension
-.I .all.js
-are injected into all frames of a page directly after the load of a
-new frame is committed.
-.TP
-.B .onload.js
-Scripts with extension
-.I .onload.js
-are injected into the page directly when loading of a page is done.
-.TP
-.B .onload.all.js
-Scripts with extension
-.I .onload.all.js
-are injected into all frames of a page when the load of a
-frame is done.
-
-.SS CSS
-dwb creates some html-elements at runtime, namely hints and a bar that show the
-current url under the cursor. They can be styled in user-stylesheets using the
-selector
-.I .dwb_hint
-for hints and
-.I #dwb_hover_element
-for the hover element.
-
-.SS Userscripts
-Userscripts can be stored in
-.IR ~/.config/dwb/userscripts .
-The first argument of the script will be the current url, the second argument is
-the title, the third argument will be the profile name, the fourth argument is
-the numerical modifier and the fifth argument is a commandline argument. Also
-the variables
-.IR DWB_URI ,
-.IR DWB_TITLE ,
-.IR DWB_PROFILE ,
-.IR DWB_NUMMOD ,
-.IR DWB_ARGUMENT ,
-.IR DWB_REFERER ,
+\fIs\fR
and
-.I DWB_USER_AGENT
-are set.
-The keybinding for
-the script must be defined in the script itself in a commented line of the form
-.B <comment symbols> dwb: <keybinding>.
-Commands can be executed by sending the command to ${DWB_FIFO}.
-
-.SS Examples
+\fIS\fR
+to the statusbar where
+\fIS\fR
+means that the statusbar won\(cqt be visible\&. Default value:
+\fIdtws\fR\&.
+.RE
+.SH "FILES"
+.SS "Userscripts"
+.sp
+Userscripts can be stored in \fI~/\&.config/dwb/userscripts\fR\&. The first argument of the script will be the current url, the second argument is the title, the third argument will be the profile name, the fourth argument is the numerical modifier and the fifth argument is a commandline argument\&. Also the variables \fIDWB_URI\fR, \fIDWB_TITLE\fR, \fIDWB_PROFILE\fR, \fIDWB_NUMMOD\fR, \fIDWB_ARGUMENT\fR, \fIDWB_REFERER\fR, and \fIDWB_USER_AGENT\fR are set\&. The keybinding for the script must be defined in the script itself in a commented line of the form \fB<comment symbols> dwb: <keybinding>\fR\&.
+.sp
+dwb also provides a small javascript api, scripts that use the api must have the special shebang \fB#!javascript\fR, for details see http://portix\&.bitbucket\&.org/dwb/resources/jsapi\&.html\&.
+.sp
+.it 1 an-trap
+.nr an-no-space-flag 1
+.nr an-break-flag 1
+.br
+.ps +1
+\fBExamples\fR
+.RS 4
+.sp
The following script will download the current webpage:
+.sp
+.if n \{\
+.RS 4
+.\}
.nf
+#!/bin/bash
+# dwb: Control w
- #!/bin/bash
- # dwb: Control w
-
- wget $DWB_URI
-
+wget $DWB_URI
.fi
-
+.if n \{\
+.RE
+.\}
+.sp
Popup an alert dialog:
+.sp
+.if n \{\
+.RS 4
+.\}
.nf
+#!/bin/bash
+# dwb: Control h
- #!/bin/bash
- # dwb: Control h
-
- echo "js window.alert('Hello world');" > ${DWB_FIFO}
-
+echo "js window\&.alert(\*(AqHello world\*(Aq);" > ${DWB_FIFO}
.fi
+.if n \{\
+.RE
+.\}
+.sp
+Block requests from specific sites:
+.sp
+.if n \{\
+.RS 4
+.\}
+.nf
+#!javascript
+var block = [ new RegExp("https://example\&.org\&.*"), new RegExp("https://example\&.co\&.uk\&.*") ];
-.SH AUTHOR
-portix <portix@gmx.net>
+signals\&.connect("resource", function(wv, frame, request) {
+ var i, r;
+ for (i=0; i<block\&.length; i++)
+ {
+ if (block[i]\&.test(request\&.uri))
+ {
+ request\&.uri = "about:blank";
+ return true;
+ }
+ }
+});
+.fi
+.if n \{\
+.RE
+.\}
+.RE
+.SH "RESOURCES"
+.sp
+bitbucket: http://bitbucket\&.org/portix/dwb
+.sp
+homepage: http://portix\&.bitbucket\&.org/dwb/
diff --git a/examples/autoquvi.js b/examples/autoquvi.js
new file mode 100644
index 00000000..41ea5f3d
--- /dev/null
+++ b/examples/autoquvi.js
@@ -0,0 +1,31 @@
+#!javascript
+
+var supported = [];
+var quvi = "quvi -f best ";
+var mplayer = ' --exec "mplayer %u"';
+function quviSpawn(wv, o) {
+ var host = wv.host;
+ for (var i=0; i<supported.length; i++) {
+ var s = supported[i];
+ if (s.test(host)) {
+ system.spawn(quvi + wv.uri + mplayer, null, null);
+ }
+ }
+}
+
+function stdoutCallback(response) {
+ var lines = response.split("\n");
+ for (var i=0; i<lines.length; i++) {
+ try {
+ var pattern = lines[i].match(/^\s*\S+/)[0];
+ supported.push(new RegExp(pattern.replace(/%/g, "\\")));
+ }
+ catch(e) {
+ io.print(e);
+ }
+ }
+ signals.connect("loadCommitted", quviSpawn);
+}
+if (system.spawn("quvi --support", stdoutCallback) & SpawnError.spawnFailed) {
+ io.print("\033[31mDWB SCRIPT ERROR:\033[0m Initiating quvi failed, aborting");
+}
diff --git a/scripts/lib/data.js b/scripts/lib/data.js
new file mode 100644
index 00000000..80e2eff5
--- /dev/null
+++ b/scripts/lib/data.js
@@ -0,0 +1,35 @@
+(function () {
+ var configDir = data.configDir;
+ var profile = data.profile;
+ Object.defineProperties(data, {
+ "bookmarks" : { value : configDir + "/" + profile + "/bookmarks", enumerable : true },
+ "history" : { value : configDir + "/" + profile + "/history", enumerable : true },
+ "cookies" : { value : configDir + "/" + profile + "/cookies", enumerable : true },
+ "quickmarks" : { value : configDir + "/" + profile + "/cookies", enumerable : true },
+ "cookies" : { value : configDir + "/" + profile + "/cookies", enumerable : true },
+ "cookiesWhitelist" : { value : configDir + "/" + profile + "/cookies.allow", enumerable : true },
+ "sessionCookiesWhitelist" : { value : configDir + "/" + profile + "/cookies_session.allow", enumerable : true },
+ "sessionCookiesWhitelist" : { value : configDir + "/" + profile + "/cookies_session.allow", enumerable : true },
+ "pluginsWhitelist" : { value : configDir + "/" + profile + "/plugins.allow", enumerable : true },
+ "scriptWhitelist" : { value : configDir + "/" + profile + "/scripts.allow", enumerable : true },
+ "session" : { value : configDir + "/" + profile + "/session", enumerable : true },
+ "customKeys" : { value : configDir + "/" + profile + "/custom_keys", enumerable : true },
+ "keys" : { value : configDir + "/keys", enumerable : true },
+ "settings" : { value : configDir + "/settings", enumerable : true },
+ "searchEngines" : { value : configDir + "/searchengines", enumerable : true },
+ "cookies" : { value : configDir + "/" + profile + "/cookies", enumerable : true },
+ "quickmarks" : { value : configDir + "/" + profile + "/cookies", enumerable : true },
+ "cookies" : { value : configDir + "/" + profile + "/cookies", enumerable : true },
+ "cookiesWhitelist" : { value : configDir + "/" + profile + "/cookies.allow", enumerable : true },
+ "sessionCookiesWhitelist" : { value : configDir + "/" + profile + "/cookies_session.allow", enumerable : true },
+ "sessionCookiesWhitelist" : { value : configDir + "/" + profile + "/cookies_session.allow", enumerable : true },
+ "pluginsWhitelist" : { value : configDir + "/" + profile + "/plugins.allow", enumerable : true },
+ "scriptWhitelist" : { value : configDir + "/" + profile + "/scripts.allow", enumerable : true },
+ "session" : { value : configDir + "/" + profile + "/session", enumerable : true },
+ "customKeys" : { value : configDir + "/" + profile + "/custom_keys", enumerable : true },
+ "keys" : { value : configDir + "/keys", enumerable : true },
+ "settings" : { value : configDir + "/settings", enumerable : true },
+ "searchEngines" : { value : configDir + "/searchengines", enumerable : true }
+ });
+})();
+Object.freeze(data);
diff --git a/scripts/lib/enums.js b/scripts/lib/enums.js
new file mode 100644
index 00000000..f59a7409
--- /dev/null
+++ b/scripts/lib/enums.js
@@ -0,0 +1,73 @@
+const LoadStatus = {
+ provisional : 0,
+ committed : 1,
+ finished : 2,
+ firstVisualLayout : 3,
+ failed : 4
+};
+const Modifier = {
+ Shift : 1 << 0,
+ Lock : 1 << 1,
+ Control : 1 << 2,
+ Mod1 : 1 << 3,
+ Mod2 : 1 << 4,
+ Mod3 : 1 << 5,
+ Mod4 : 1 << 6,
+ Mod5 : 1 << 7,
+ Button1 : 1 << 8,
+ Button2 : 1 << 9,
+ Button3 : 1 << 10,
+ Button4 : 1 << 11,
+ Button5 : 1 << 12,
+ Super : 1 << 26,
+ Hyper : 1 << 27,
+ Meta : 1 << 28,
+ Release : 1 << 30,
+ Modifier : 0x5c001fff
+};
+const ButtonContext = {
+ document : 1 << 1,
+ link : 1 << 2,
+ image : 1 << 3,
+ media : 1 << 4,
+ selection : 1 << 5,
+ editable : 1 << 6
+};
+const ClickType = {
+ click : 4,
+ doubleClick : 5,
+ tripleClick : 6
+};
+const NavigationReason = {
+ linkClicked : 0,
+ formSubmitted : 1,
+ backForward : 2,
+ reload : 3,
+ formResubmitted : 4,
+ other : 5
+};
+const DownloadStatus = {
+ error : -1,
+ created : 0,
+ started : 1,
+ cancelled : 2,
+ finished : 3
+};
+const SpawnError = {
+ success : 0,
+ spawnFailed : 1<<0,
+ stdoutFailed : 1<<1,
+ stderrFailed : 1<<2
+};
+const ChecksumType = {
+ md5 : 0,
+ sha1 : 1,
+ sha256 : 2
+};
+const FileTest = {
+ regular : 1 << 0,
+ symlink : 1 << 1,
+ dir : 1 << 2,
+ executable : 1 << 3,
+ exists : 1 << 4
+};
diff --git a/scripts/lib/extensions.js b/scripts/lib/extensions.js
new file mode 100644
index 00000000..a1f40d7a
--- /dev/null
+++ b/scripts/lib/extensions.js
@@ -0,0 +1,130 @@
+(function () {
+ var _config = undefined;
+ var _debug = false;
+ function getPlugin(name, filename) {
+ var ret = null;
+ try {
+ if (system.fileTest(filename, FileTest.exists)) {
+ ret = include(filename);
+ }
+ }
+ catch(e) {
+ extensions.error(name, "Error in line " + e.line + " parsing " + filename);
+ }
+ return ret;
+ }
+ function getStack(offset) {
+ if (arguments.length === 0) {
+ offset = 0;
+ }
+ try {
+ throw Error (message);
+ }
+ catch (e) {
+ var stack = e.stack.match(/[^\n]+/g);
+ return "STACK: [" + stack.slice(offset+1).join("] [")+"]";
+ }
+ }
+ Object.defineProperties(extensions, {
+ "warning" : {
+ value : function (name, message) {
+ io.print("\033[1mDWB EXTENSION WARNING: \033[0mextension \033[1m" + name + "\033[0m: " + message, "stderr");
+ }
+ },
+ "enableDebugging" : {
+ set : function (value) {
+ if (typeof value == "boolean")
+ _debug = value;
+ }
+ },
+ "debug" : {
+ value : function (name, message) {
+ if (_debug) {
+ io.print("\033[1mDWB EXTENSION DEBUG: \033[0mextension \033[1m" + name + "\033[0m\n" + getStack(1), "stderr");
+ }
+ }
+ },
+ "error" : {
+ value : function (name, a, b) {
+ var message = "";
+ if (a instanceof Error) {
+ if (a.message) {
+ message = a.message;
+ }
+ else if (arguments.length > 2)
+ message = b;
+ else
+ b = "";
+ io.print("\033[31mDWB EXTENSION ERROR: \033[0mextension \033[1m" + name + "\033[0m in line " + a.line + ": " +
+ message + "\nSTACK: [" + a.stack.match(/[^\n]+/g).join("] [") + "]", "stderr");
+ }
+ else {
+ io.print("\033[31mDWB EXTENSION ERROR: \033[0mextension \033[1m" + name + "\033[0m: " + a + "\n" + getStack(1), "stderr");
+ }
+ }
+ },
+ "message" : {
+ value : function (name, message) {
+ io.print("\033[1mDWB EXTENSION: \033[0mextension \033[1m" + name + "\033[0m: " + message, "stderr");
+ }
+ },
+ "load" : {
+ value : function(name, c) {
+ var boldname = "\033[1m" + name + "\033[0m";
+
+ var config, dataBase, pluginPath, plugin = null;
+ var extConfig = null;
+
+ /* Get default config if the config hasn't been read yet */
+ if (arguments.length == 2) {
+ extConfig = c;
+ }
+ else {
+ if (_config === undefined) {
+ try {
+ config = include(data.configDir + "/extensionrc");
+ }
+ catch (e) {
+ extensions.error(name, "loading config failed : " + e);
+ }
+ if (config === null) {
+ extensions.warning(name, "Could not load config.");
+ }
+ else {
+ _config = config;
+ }
+ }
+ if (_config) {
+ extConfig = _config[name] || null;
+ }
+ }
+
+ /* Load extension */
+ var filename = data.userDataDir + "/extensions/" + name;
+ plugin = getPlugin(name, data.userDataDir + "/extensions/" + name);
+ if (plugin === null) {
+ plugin = getPlugin(name, data.systemDataDir + "/extensions/" + name);
+ if (plugin === null) {
+ extensions.error(name, "Couldn't find extension.");
+ return false;
+ }
+ }
+ try {
+ if (plugin.init(extConfig)) {
+ extensions.message(name, "Successfully loaded and initialized.");
+ return true;
+ }
+ else {
+ extensions.error(name, "Initialization failed.");
+ return false;
+ }
+ }
+ catch (e) {
+ extensions.error(name, "Initialization failed: " + e);
+ return false;
+ }
+ }
+ }
+ });
+})();
+Object.freeze(extensions);
diff --git a/scripts/lib/signals.js b/scripts/lib/signals.js
new file mode 100644
index 00000000..f254aea9
--- /dev/null
+++ b/scripts/lib/signals.js
@@ -0,0 +1,92 @@
+(function () {
+ var _registered = {};
+ Object.defineProperties(signals, {
+ "emit" : {
+ value : function(sig, args) {
+ var sigs = _registered[sig];
+ var ret = false;
+ var i = 0;
+ do {
+ if (sigs[i].connected) {
+ ret = sigs[i].callback.apply(this, args) || ret;
+ i++;
+ }
+ else {
+ sigs.splice(i, 1);
+ }
+ } while (i<sigs.length);
+ if (_registered[sig].length === 0) {
+ signals[sig] = null;
+ }
+ return ret;
+ }
+ },
+ "connect" : {
+ value : (function () {
+ var id = 0;
+ return function(sig, func) {
+ ++id;
+ if (_registered[sig] === undefined || _registered[sig] === null) {
+ _registered[sig] = [];
+ signals[sig] = function () { return signals.emit(sig, arguments); };
+ }
+ if (func === null || typeof func !== "function") {
+ return -1;
+ }
+ _registered[sig].push({callback : func, id : id, connected : true });
+ return id;
+ };
+ })()
+ },
+ "disconnect" : {
+ value : function(id) {
+ var sig, i, sigs;
+ for (sig in _registered) {
+ sigs = _registered[sig];
+ for (i = 0; i<sigs.length; i++) {
+ if (sigs[i].id == id) {
+ if (_registered[sig].length === 1) {
+ signals[sig] = null;
+ }
+ else {
+ sigs[i].connected = false;
+ }
+ return true;
+ }
+ }
+ }
+ return false;
+ }
+ },
+ "disconnectByFunction" : {
+ value : function(func) {
+ var sig, i, sigs, ret = false;
+ for (sig in _registered) {
+ sigs = _registered[sig];
+ for (i = 0; i<sigs.length; i++) {
+ if (sigs[i].callback == func) {
+ if (_registered[sig].length === 1) {
+ signals[sig] = null;
+ }
+ else {
+ sigs[i].connected = false;
+ }
+ ret = true;
+ }
+ }
+ }
+ return ret;
+ }
+ },
+ "disconnectByName" : {
+ value : function (name) {
+ io.print(name);
+ if (signals[name] !== null && signals[name] !== undefined) {
+ signals[name] = null;
+ return true;
+ }
+ return false;
+ }
+ }
+ });
+})();
diff --git a/src/application.c b/src/application.c
index ee19d53d..27d622a4 100644
--- a/src/application.c
+++ b/src/application.c
@@ -24,6 +24,7 @@
#include "view.h"
#include "session.h"
#include "util.h"
+#include "scripts.h"
static gboolean application_parse_option(const gchar *, const gchar *, gpointer , GError **);
static void application_execute_args(char **);
@@ -304,6 +305,7 @@ application_start(GApplication *app, char **argv) {
dwb_init();
dwb_pack(GET_CHAR("widget-packing"), false);
+ scripts_init();
if (opt_force)
session_flags |= SESSION_FORCE;
diff --git a/src/callback.c b/src/callback.c
index a445d02f..91c87ac5 100644
--- a/src/callback.c
+++ b/src/callback.c
@@ -21,6 +21,8 @@
#include "completion.h"
#include "commands.h"
#include "entry.h"
+#include "scripts.h"
+#include "util.h"
/* dwb_entry_keyrelease_cb {{{*/
@@ -146,6 +148,14 @@ callback_key_press(GtkWidget *w, GdkEventKey *e) {
gboolean ret = false;
Mode mode = CLEAN_MODE(dwb.state.mode);
+ if (EMIT_SCRIPT(KEY_PRESS)) {
+ char *json = util_create_json(5, UINTEGER, "state", e->state,
+ UINTEGER, "keyVal", e->keyval, UINTEGER, "keyCode", e->hardware_keycode,
+ BOOLEAN, "isModifier", e->is_modifier, CHAR, "name", gdk_keyval_name(e->keyval));
+ ScriptSignal signal = { SCRIPTS_WV(dwb.state.fview), SCRIPTS_SIG_META(json, KEY_PRESS, 0) };
+ SCRIPTS_EMIT_RETURN(signal, json);
+ }
+
if (e->keyval == GDK_KEY_Escape) {
if (dwb.state.mode & COMPLETION_MODE)
completion_clean_completion(true);
@@ -186,6 +196,16 @@ callback_key_press(GtkWidget *w, GdkEventKey *e) {
/* dwb_key_release_cb {{{*/
gboolean
callback_key_release(GtkWidget *w, GdkEventKey *e) {
+ if (EMIT_SCRIPT(KEY_RELEASE)) {
+ char *json = util_create_json(5, UINTEGER, "state", e->state,
+ UINTEGER, "keyVal", e->keyval, UINTEGER, "keyCode", e->hardware_keycode,
+ BOOLEAN, "isModifier", e->is_modifier, CHAR, "name", gdk_keyval_name(e->keyval));
+ ScriptSignal signal = { SCRIPTS_WV(dwb.state.fview), SCRIPTS_SIG_META(json, KEY_RELEASE, 0) };
+ SCRIPTS_EMIT_RETURN(signal, json);
+ }
+ //SCRIPTS_EMIT_RETURN(SCRIPT(dwb.state.fview), KEY_RELEASE, 5, UINTEGER, "state", e->state,
+ // UINTEGER, "keyVal", e->keyval, UINTEGER, "keyCode", e->hardware_keycode,
+ // BOOLEAN, "isModifier", e->is_modifier, CHAR, "name", gdk_keyval_name(e->keyval));
if (DWB_TAB_KEY(e)) {
return true;
}
diff --git a/src/commands.c b/src/commands.c
index e67724cf..feff6849 100644
--- a/src/commands.c
+++ b/src/commands.c
@@ -360,7 +360,8 @@ commands_focus(KeyMap *km, Arg *arg) {
if (dwb.state.views->next) {
int pos = modulo(g_list_position(dwb.state.views, dwb.state.fview) + NUMMOD * arg->n, g_list_length(dwb.state.views));
GList *g = g_list_nth(dwb.state.views, pos);
- dwb_focus_view(g);
+ if (dwb_focus_view(g))
+ return STATUS_OK;
if (! (dwb.state.bar_visible & BAR_VIS_TOP) && dwb.misc.tabbar_delay > 0) {
gtk_widget_show(dwb.gui.topbox);
if (running != 0)
@@ -381,7 +382,8 @@ commands_focus_nth_view(KeyMap *km, Arg *arg) {
GList *l = g_list_nth(dwb.state.views, dwb.state.nummod - 1);
if (!l)
return STATUS_ERROR;
- dwb_focus_view(l);
+ if (dwb_focus_view(l))
+ return STATUS_OK;
if (! (dwb.state.bar_visible & BAR_VIS_TOP)) {
gtk_widget_show(dwb.gui.topbox);
if (running != 0)
@@ -648,15 +650,6 @@ commands_quit(KeyMap *km, Arg *arg) {
return STATUS_END;
}/*}}}*/
-/* commands_reload_scripts {{{*/
-DwbStatus
-commands_reload_scripts(KeyMap *km, Arg *arg) {
- dwb_init_scripts();
- for (GList *l = dwb.state.views; l; l=l->next) {
- webkit_web_view_reload(WEBVIEW(l));
- }
- return STATUS_OK;
-}/*}}}*/
DwbStatus
commands_reload_user_scripts(KeyMap *km, Arg *arg) {
dwb_reload_userscripts();
diff --git a/src/commands.h b/src/commands.h
index 903e9b1e..37c87ece 100644
--- a/src/commands.h
+++ b/src/commands.h
@@ -74,7 +74,6 @@ DwbStatus commands_set_zoom_level(KeyMap *, Arg *);
DwbStatus commands_toggle_hidden_files(KeyMap *, Arg *);
DwbStatus commands_web_inspector(KeyMap *, Arg *);
DwbStatus commands_quit(KeyMap *, Arg *);
-DwbStatus commands_reload_scripts(KeyMap *, Arg *);
DwbStatus commands_reload_user_scripts(KeyMap *, Arg *);
DwbStatus commands_fullscreen(KeyMap *, Arg *);
DwbStatus commands_open_editor(KeyMap *, Arg *);
diff --git a/src/config.h b/src/config.h
index 779de90b..20e7af20 100644
--- a/src/config.h
+++ b/src/config.h
@@ -99,7 +99,6 @@ static KeyValue KEYS[] = {
{ "zoom", { "=", 0, }, },
{ "zoom_out", { "-", 0, }, },
{ "save_search_field", { "gs", 0, }, },
- { "reload_scripts", { NULL, 0, }, },
{ "reload_userscripts", { NULL, 0, }, },
{ "proxy", { "p" , GDK_CONTROL_MASK, }, },
{ "focus_input", { "gi", 0, }, },
@@ -691,9 +690,6 @@ static FunctionMap FMAP [] = {
(Func)commands_web_inspector, "Enable developer extras for the webinspector", POST_SM,
{ 0 }, EP_NONE, { "inspect", "insp", NULL }, },
- { { "reload_scripts", "Reload scripts", }, CP_COMMANDLINE,
- (Func)commands_reload_scripts, NULL, ALWAYS_SM,
- { 0 }, EP_NONE, { NULL }, },
{ { "reload_userscripts", "Reload userscripts", }, CP_COMMANDLINE,
(Func)commands_reload_user_scripts, NULL, POST_SM,
{ 0 }, EP_NONE, { NULL }, },
diff --git a/src/download.c b/src/download.c
index 24e5e341..9af8c22d 100644
--- a/src/download.c
+++ b/src/download.c
@@ -21,15 +21,7 @@
#include "entry.h"
#include "util.h"
#include "soup.h"
-
-typedef struct _DwbDownloadStatus {
-#if _HAS_GTK3
- gdouble blue, red, green, alpha;
-#else
- guint blue, red, green;
-#endif
- gint64 time;
-} DwbDownloadStatus;
+#include "scripts.h"
typedef struct _DwbDownload {
GtkWidget *event;
@@ -42,6 +34,16 @@ typedef struct _DwbDownload {
guint sig_button;
char *mimetype;
} DwbDownload;
+typedef struct _DwbDownloadStatus {
+#if _HAS_GTK3
+ gdouble blue, red, green, alpha;
+#else
+ guint blue, red, green;
+#endif
+ gint64 time;
+ DwbDownload *download;
+} DwbDownloadStatus;
+
#define DWB_DOWNLOAD(X) ((DwbDownload*)((X)->data))
static GList *_downloads = NULL;
@@ -246,7 +248,10 @@ download_delay(DwbDownload *download) {
static void
download_status_cb(WebKitDownload *download, GParamSpec *p, DwbDownloadStatus *dstatus) {
WebKitDownloadStatus status = webkit_download_get_status(download);
-
+ if (EMIT_SCRIPT(DOWNLOAD_STATUS)) {
+ ScriptSignal signal = { .jsobj = NULL, { G_OBJECT(download) }, SCRIPTS_SIG_META(NULL, DOWNLOAD_STATUS, 1) };
+ scripts_emit(&signal);
+ }
if (status == WEBKIT_DOWNLOAD_STATUS_FINISHED || status == WEBKIT_DOWNLOAD_STATUS_CANCELLED || status == WEBKIT_DOWNLOAD_STATUS_ERROR) {
GList *list = download_get_download_label(download);
if (list) {
@@ -447,6 +452,7 @@ download_start(const char *path) {
_downloads = g_list_prepend(_downloads, active);
DwbDownloadStatus *s = dwb_malloc(sizeof(DwbDownloadStatus));
s->blue = s->time = 0;
+ s->download = active;
active->sig_button = g_signal_connect(active->event, "button-press-event", G_CALLBACK(download_button_press_cb), _downloads);
g_signal_connect(dwb.state.download, "notify::current-size", G_CALLBACK(download_progress_cb), s);
g_signal_connect(dwb.state.download, "notify::status", G_CALLBACK(download_status_cb), s);
diff --git a/src/dwb.c b/src/dwb.c
index 8fc5b3e7..38c97fd2 100644
--- a/src/dwb.c
+++ b/src/dwb.c
@@ -45,6 +45,7 @@
#include "adblock.h"
#include "domain.h"
#include "application.h"
+#include "scripts.h"
/* DECLARATIONS {{{*/
static DwbStatus dwb_webkit_setting(GList *, WebSettings *);
@@ -1175,9 +1176,15 @@ dwb_get_host(WebKitWebView *web) {
}/*}}}*/
/* dwb_focus_view(GList *gl){{{*/
-void
+gboolean
dwb_focus_view(GList *gl) {
if (gl != dwb.state.fview) {
+ if (EMIT_SCRIPT(TAB_FOCUS)) {
+ //ScriptSignal signal = { SCRIPTS_WV(gl), .objects = { SCRIPTS_WV(dwb.state.fview) }, SCRIPTS_SIG_META(NULL, TAB_FOCUS, 1) };
+ ScriptSignal signal = {
+ SCRIPTS_WV(gl), .objects = { G_OBJECT(VIEW(dwb.state.fview)->web) }, SCRIPTS_SIG_META(NULL, TAB_FOCUS, 1) };
+ SCRIPTS_EMIT_RETURN(signal, NULL);
+ }
gtk_widget_show(VIEW(gl)->scroll);
dwb_soup_clean();
if (! (CURRENT_VIEW()->status->lockprotect & LP_VISIBLE) )
@@ -1185,7 +1192,9 @@ dwb_focus_view(GList *gl) {
dwb_change_mode(NORMAL_MODE, true);
dwb_unfocus();
dwb_focus(gl);
+ return false;
}
+ return true;
}/*}}}*/
/* dwb_toggle_allowed(const char *filename, const char *data) {{{*/
@@ -1646,7 +1655,7 @@ dwb_execute_script(WebKitWebFrame *frame, const char *com, gboolean ret) {
return NULL;
if (eval_ret && ret) {
- return js_value_to_char(context, eval_ret);
+ return js_value_to_char(context, eval_ret, JS_STRING_MAX, NULL);
}
return NULL;
}
@@ -1695,7 +1704,6 @@ dwb_prepend_navigation(GList *gl, GList **fc) {
return STATUS_OK;
}
return STATUS_ERROR;
-
}/*}}}*/
/* dwb_confirm_snooper {{{*/
@@ -1713,6 +1721,19 @@ dwb_confirm_snooper_cb(GtkWidget *w, GdkEventKey *e, int *state) {
dwb.state.mode &= ~CONFIRM;
return true;
}/*}}}*/
+static gboolean
+dwb_prompt_snooper_cb(GtkWidget *w, GdkEventKey *e, int *state) {
+ gboolean ret = false;
+ if (e->type == GDK_KEY_RELEASE)
+ return false;
+ switch (e->keyval) {
+ case GDK_KEY_Return: *state = 0; ret = true; break;
+ case GDK_KEY_Escape: ret = true; break;
+ default: return false;
+ }
+ dwb.state.mode &= ~CONFIRM;
+ return ret;
+}
/* dwb_confirm() return confirmed (gboolean) {{{
* yes / no confirmation
@@ -1744,6 +1765,35 @@ dwb_confirm(GList *gl, char *prompt, ...) {
return state > 0;
}/*}}}*/
+const char *
+dwb_prompt(gboolean visibility, char *prompt, ...) {
+ dwb.state.mode |= CONFIRM;
+
+ va_list arg_list;
+ va_start(arg_list, prompt);
+ char message[STRING_LENGTH];
+ vsnprintf(message, STRING_LENGTH, prompt, arg_list);
+ va_end(arg_list);
+ dwb_set_status_bar_text(dwb.gui.lstatus, message, &dwb.color.active_fg, dwb.font.fd_active, false);
+ if (! (dwb.state.bar_visible & BAR_VIS_STATUS) )
+ gtk_widget_show(dwb.gui.bottombox);
+ gtk_entry_set_visibility(GTK_ENTRY(dwb.gui.entry), visibility);
+ int state = -1;
+ entry_focus();
+ int id = gtk_key_snooper_install((GtkKeySnoopFunc)dwb_prompt_snooper_cb, &state);
+ while ((dwb.state.mode & CONFIRM) && state == -1) {
+ gtk_main_iteration();
+ }
+ if (! (dwb.state.bar_visible & BAR_VIS_STATUS) )
+ gtk_widget_hide(dwb.gui.bottombox);
+ gtk_key_snooper_remove(id);
+ dwb_focus_scroll(dwb.state.fview);
+ CLEAR_COMMAND_TEXT();
+
+ gtk_entry_set_visibility(GTK_ENTRY(dwb.gui.entry), true);
+ return state == 0 ? GET_TEXT() : NULL;
+}
+
/* dwb_save_quickmark(const char *key) {{{*/
void
dwb_save_quickmark(const char *key) {
@@ -2503,9 +2553,12 @@ dwb_get_scripts() {
GList *gl = NULL;
Navigation *n;
GError *error = NULL;
+ FILE *f;
if ( (dir = g_dir_open(dwb.files.userscripts, 0, NULL)) ) {
while ( (filename = (char*)g_dir_read_name(dir)) ) {
+ gboolean javascript = false;
+ char buf[11] = {0};
char *path = g_build_filename(dwb.files.userscripts, filename, NULL);
char *realpath;
/* ignore subdirectories */
@@ -2520,7 +2573,21 @@ dwb_get_scripts() {
g_free(path);
path = realpath;
}
- if (!g_file_test(path, G_FILE_TEST_IS_EXECUTABLE)) {
+ if ( (f = fopen(path, "r")) != NULL) {
+ if (fgetc(f) == '#' && fgetc(f) == '!') {
+ fgets(buf, 11, f);
+ if (!g_strcmp0(buf, "javascript")) {
+ int next = fgetc(f);
+ if (g_ascii_isspace(next)) {
+ javascript = true;
+ }
+ }
+ }
+ fclose(f);
+
+ }
+
+ if (!javascript && !g_file_test(path, G_FILE_TEST_IS_EXECUTABLE)) {
fprintf(stderr, "Warning: userscript %s isn't executable and will be ignored.\n", path);
continue;
}
@@ -2528,9 +2595,18 @@ dwb_get_scripts() {
g_file_get_contents(path, &content, NULL, NULL);
if (content == NULL)
continue;
+ if (javascript) {
+ char *script = strchr(content, '\n');
+ if (script && *(script+1)) {
+ scripts_init_script(script+1);
+ g_free(content);
+ continue;
+ }
+ }
char **lines = g_strsplit(content, "\n", -1);
+
g_free(content);
content = NULL;
@@ -2683,6 +2759,7 @@ dwb_clean_up() {
util_rmdir(dwb.files.cachedir, true, true);
gtk_widget_destroy(dwb.gui.window);
+ scripts_end();
return true;
}/*}}}*/
@@ -3056,35 +3133,9 @@ dwb_init_settings() {
g_strfreev(keys);
}/*}}}*/
-/* dwb_init_scripts{{{*/
-void
-dwb_init_scripts() {
- g_free(dwb.misc.scripts);
- GString *normalbuffer = g_string_new(NULL);
- GString *allbuffer = g_string_new(NULL);
-
- setlocale(LC_NUMERIC, "C");
- /* user scripts */
- util_get_directory_content(&allbuffer, dwb.files.scriptdir, "onload.all.js");
- dwb.misc.allscripts_onload = g_strdup(allbuffer->str);
- util_get_directory_content(&allbuffer, dwb.files.scriptdir, "onload.js");
- dwb.misc.scripts_onload = g_strdup(allbuffer->str);
- g_string_erase(allbuffer, 0, -1);
-
- util_get_directory_content(&normalbuffer, dwb.files.scriptdir, "js");
- util_get_directory_content(&allbuffer, dwb.files.scriptdir, "all.js");
-
- /* systemscripts */
- g_string_append(normalbuffer, allbuffer->str);
- dwb.misc.scripts = normalbuffer->str;
- dwb.misc.allscripts = allbuffer->str;
- g_string_free(normalbuffer, false);
- g_string_free(allbuffer, false);
- dwb_init_hints(NULL, NULL);
-}/*}}}*/
-
static DwbStatus
dwb_init_hints(GList *gl, WebSettings *s) {
+ setlocale(LC_NUMERIC, "C");
g_free(dwb.misc.hints);
char *scriptpath = util_get_data_file(HINT_SCRIPT, "scripts");
dwb.misc.hints = util_get_file_content(scriptpath);
@@ -3193,13 +3244,13 @@ dwb_pack(const char *layout, gboolean rebuild) {
}
while (g_ascii_isspace(*layout))
layout++;
- if (strlen(layout) != 4) {
+ if (strlen(layout) != WIDGET_PACK_LENGTH) {
layout = default_layout;
ret = STATUS_ERROR;
}
const char *valid_chars = default_layout;
- char *buf = g_ascii_strdown(layout, 4);
+ char *buf = g_ascii_strdown(layout, WIDGET_PACK_LENGTH);
char *matched;
while (*valid_chars) {
if ((matched = strchr(buf, *valid_chars)) == NULL) {
@@ -3450,7 +3501,7 @@ void
dwb_init_files() {
char *path = util_build_path();
char *profile_path = util_check_directory(g_build_filename(path, dwb.misc.profile, NULL));
- char *userscripts, *scripts, *cachedir;
+ char *userscripts, *cachedir;
dwb.fc.bookmarks = NULL;
dwb.fc.history = NULL;
@@ -3496,8 +3547,6 @@ dwb_init_files() {
dwb.files.custom_keys = g_build_filename(profile_path, "custom_keys", NULL);
dwb_check_create(dwb.files.custom_keys);
- scripts = g_build_filename(path, "scripts", NULL);
- dwb.files.scriptdir = util_check_directory(scripts);
userscripts = g_build_filename(path, "userscripts", NULL);
dwb.files.userscripts = util_check_directory(userscripts);
@@ -3666,10 +3715,10 @@ dwb_init() {
dwb_init_key_map();
dwb_init_style();
dwb_init_gui();
- dwb_init_scripts();
dwb_init_custom_keys(false);
domain_init();
adblock_init();
+ dwb_init_hints(NULL, NULL);
dwb_soup_init();
} /*}}}*/ /*}}}*/
diff --git a/src/dwb.h b/src/dwb.h
index 1faac06f..1571da52 100644
--- a/src/dwb.h
+++ b/src/dwb.h
@@ -106,6 +106,7 @@
#define CURRENT_WEBVIEW_WIDGET() (((View*)dwb.state.fview->data)->web)
#define CURRENT_WEBVIEW() (WEBKIT_WEB_VIEW(((View*)dwb.state.fview->data)->web))
#define MAIN_FRAME() (webkit_web_view_get_main_frame(CURRENT_WEBVIEW()))
+#define MAIN_FRAME_CAST(X) (webkit_web_view_get_main_frame(WEBKIT_WEB_VIEW(X)))
#define FOCUSED_FRAME() (webkit_web_view_get_focused_frame(CURRENT_WEBVIEW()))
#define VIEW_FROM_ARG(X) (X && X->p ? ((GSList*)X->p)->data : dwb.state.fview->data)
#define WEBVIEW_FROM_ARG(arg) (WEBKIT_WEB_VIEW(((View*)(arg && arg->p ? ((GSList*)arg->p)->data : dwb.state.fview->data))->web))
@@ -170,6 +171,7 @@ GTimer *__timer;
#define BPGB 1073741824
#define DEFAULT_WIDGET_PACKING "dtws"
+#define WIDGET_PACK_LENGTH 4
/*}}}*/
@@ -346,6 +348,9 @@ typedef enum {
BOOLEAN = 0x04,
COLOR_CHAR = 0x05,
HTML_STRING = 0x06,
+ ULONG = 0x07,
+ LONG = 0x08,
+ UINTEGER = 0x09,
} DwbType;
typedef enum {
@@ -608,6 +613,7 @@ struct _ViewStatus {
GSList *allowed_plugins;
unsigned int lockprotect;
WebKitDOMElement *style;
+ GSList *frames;
};
struct _View {
GtkWidget *web;
@@ -624,6 +630,7 @@ struct _View {
} hover;
WebKitDOMElement *status_element;
JSObjectRef hint_object;
+ JSObjectRef script_wv;
};
struct _Color {
DwbColor active_fg;
@@ -690,8 +697,6 @@ struct _Misc {
char *scripts_onload;
char *hints;
/* applied to all frames */
- char *allscripts;
- char *allscripts_onload;
const char *profile;
const char *default_search;
gint find_delay;
@@ -723,6 +728,7 @@ struct _Misc {
int bar_height;
TabPosition tab_position;
char *hint_style;
+ int script_signals;
};
struct _Files {
const char *bookmarks;
@@ -736,7 +742,6 @@ struct _Files {
const char *keys;
const char *mimetypes;
const char *quickmarks;
- const char *scriptdir;
const char *searchengines;
const char *session;
const char *settings;
@@ -858,7 +863,7 @@ void dwb_update_uri(GList *);
gboolean dwb_get_allowed(const char *, const char *);
gboolean dwb_toggle_allowed(const char *, const char *, GList **);
char * dwb_get_host(WebKitWebView *);
-void dwb_focus_view(GList *);
+gboolean dwb_focus_view(GList *);
void dwb_clean_key_buffer(void);
void dwb_set_key(const char *, char *);
DwbStatus dwb_set_setting(const char *, char *value, int);
@@ -904,6 +909,7 @@ void dwb_init_signals(void);
void dwb_parse_commands(const char *line);
DwbStatus dwb_scheme_handler(GList *gl, WebKitNetworkRequest *request);
GList *dwb_get_simple_list(GList *, const char *filename);
+const char * dwb_prompt(gboolean visibility, char *prompt, ...);
gboolean dwb_dom_remove_from_parent(WebKitDOMNode *node, GError **error);
char * dwb_get_raw_data(GList *gl);
diff --git a/src/js.c b/src/js.c
index 1ffd572a..73b7bd75 100644
--- a/src/js.c
+++ b/src/js.c
@@ -20,8 +20,17 @@
#include "dwb.h"
#include "util.h"
#include "js.h"
-#define JS_STRING_MAX 1024
+void
+js_make_exception(JSContextRef ctx, JSValueRef *exception, const gchar *format, ...) {
+ va_list arg_list;
+
+ va_start(arg_list, format);
+ gchar message[STRING_LENGTH];
+ vsnprintf(message, STRING_LENGTH, format, arg_list);
+ va_end(arg_list);
+ *exception = js_char_to_value(ctx, message);
+}
/* js_get_object_property {{{*/
JSObjectRef
js_get_object_property(JSContextRef ctx, JSObjectRef arg, const char *name) {
@@ -40,6 +49,13 @@ js_get_object_property(JSContextRef ctx, JSObjectRef arg, const char *name) {
}/*}}}*/
+JSValueRef
+js_char_to_value(JSContextRef ctx, const char *text) {
+ JSStringRef string = JSStringCreateWithUTF8CString(text);
+ JSValueRef ret = JSValueMakeString(ctx, string);
+ JSStringRelease(string);
+ return ret;
+}
/* js_get_string_property {{{*/
char *
js_get_string_property(JSContextRef ctx, JSObjectRef arg, const char *name) {
@@ -49,7 +65,7 @@ js_get_string_property(JSContextRef ctx, JSObjectRef arg, const char *name) {
JSStringRelease(buffer);
if (exc != NULL || !JSValueIsString(ctx, val) )
return NULL;
- return js_value_to_char(ctx, val);
+ return js_value_to_char(ctx, val, JS_STRING_MAX, NULL);
}/*}}}*/
/* js_get_double_property {{{*/
@@ -72,14 +88,15 @@ js_get_double_property(JSContextRef ctx, JSObjectRef arg, const char *name) {
* Converts a JSStringRef, return a newly allocated char.
* {{{*/
char *
-js_string_to_char(JSContextRef ctx, JSStringRef jsstring) {
- size_t length = MIN(JSStringGetLength(jsstring), JS_STRING_MAX) + 1;
-
- char *ret = g_new(char, length);
- size_t written = JSStringGetUTF8CString(jsstring, ret, length);
- /* TODO: handle length error */
- if (written != length)
- return NULL;
+js_string_to_char(JSContextRef ctx, JSStringRef jsstring, size_t size) {
+ size_t length;
+ if (size > 0)
+ length = MIN(JSStringGetMaximumUTF8CStringSize(jsstring), size);
+ else
+ length = JSStringGetMaximumUTF8CStringSize(jsstring);
+
+ char *ret = g_malloc(sizeof(gchar) * length);
+ JSStringGetUTF8CString(jsstring, ret, length);
return ret;
}/*}}}*/
@@ -145,7 +162,7 @@ js_call_as_function(WebKitWebFrame *frame, JSObjectRef obj, const char *string,
js_ret = JSObjectCallAsFunction(ctx, function_object, NULL, 0, NULL, NULL);
}
if (char_ret != NULL) {
- ret = js_value_to_char(ctx, js_ret);
+ ret = js_value_to_char(ctx, js_ret, JS_STRING_MAX, NULL);
}
error_out:
if (js_name)
@@ -157,17 +174,29 @@ error_out:
/*{{{*/
char *
-js_value_to_char(JSContextRef ctx, JSValueRef value) {
- JSValueRef exc = NULL;
+js_value_to_char(JSContextRef ctx, JSValueRef value, size_t limit, JSValueRef *exc) {
if (value == NULL)
return NULL;
if (! JSValueIsString(ctx, value))
return NULL;
- JSStringRef jsstring = JSValueToStringCopy(ctx, value, &exc);
- if (exc != NULL)
+ JSStringRef jsstring = JSValueToStringCopy(ctx, value, exc);
+ if (jsstring == NULL)
return NULL;
- char *ret = js_string_to_char(ctx, jsstring);
+ char *ret = js_string_to_char(ctx, jsstring, limit);
JSStringRelease(jsstring);
return ret;
}/*}}}*/
+
+char *
+js_value_to_json(JSContextRef ctx, JSValueRef value, size_t limit, JSValueRef *exc) {
+ if (value == NULL)
+ return NULL;
+ JSStringRef js_json = JSValueCreateJSONString(ctx, value, 2, exc);
+ if (js_json == NULL)
+ return NULL;
+ char *json = js_string_to_char(ctx, js_json, limit);
+ JSStringRelease(js_json);
+ return json;
+}
+
diff --git a/src/js.h b/src/js.h
index 8bbe0dfe..22b4f58c 100644
--- a/src/js.h
+++ b/src/js.h
@@ -19,13 +19,17 @@
#ifndef JS_H
#define JS_H
-char * js_string_to_char(JSContextRef ctx, JSStringRef jsstring);
-char * js_value_to_char(JSContextRef ctx, JSValueRef value);
+void js_make_exception(JSContextRef ctx, JSValueRef *exception, const gchar *format, ...);
+char * js_string_to_char(JSContextRef ctx, JSStringRef jsstring, size_t );
+char * js_value_to_char(JSContextRef ctx, JSValueRef value, size_t limit, JSValueRef *);
JSObjectRef js_get_object_property(JSContextRef ctx, JSObjectRef arg, const char *name);
JSObjectRef js_get_object_property(JSContextRef ctx, JSObjectRef arg, const char *name);
char * js_get_string_property(JSContextRef ctx, JSObjectRef arg, const char *name);
double js_get_double_property(JSContextRef ctx, JSObjectRef arg, const char *name);
JSObjectRef js_create_object(WebKitWebFrame *, const char *);
char * js_call_as_function(WebKitWebFrame *, JSObjectRef, const char *string, const char *args, char **char_ret);
+JSValueRef js_char_to_value(JSContextRef ctx, const char *text);
+char * js_value_to_json(JSContextRef ctx, JSValueRef value, size_t limit, JSValueRef *exc);
+#define JS_STRING_MAX 1024
#endif
diff --git a/src/scripts.c b/src/scripts.c
new file mode 100644
index 00000000..575de8cf
--- /dev/null
+++ b/src/scripts.c
@@ -0,0 +1,1511 @@
+/*
+ * Copyright (c) 2010-2012 Stefan Bolte <portix@gmx.net>
+ *
+ * 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
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#include <stdio.h>
+#include <ctype.h>
+#include <string.h>
+#include <math.h>
+#include <JavaScriptCore/JavaScript.h>
+#include <glib.h>
+#include "dwb.h"
+#include "scripts.h"
+#include "util.h"
+#include "js.h"
+#include "soup.h"
+#include "domain.h"
+//#define kJSDefaultFunction (kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete )
+#define kJSDefaultProperty (kJSPropertyAttributeDontDelete | kJSPropertyAttributeReadOnly )
+#define kJSDefaultAttributes (kJSPropertyAttributeDontDelete | kJSPropertyAttributeReadOnly )
+
+#define SCRIPT_WEBVIEW(o) (WEBVIEW(((GList*)JSObjectGetPrivate(o))))
+#define EXCEPTION(X) "DWB EXCEPTION : "X
+#define PROP_LENGTH 128
+#define G_FILE_TEST_VALID (G_FILE_TEST_IS_REGULAR | G_FILE_TEST_IS_SYMLINK | G_FILE_TEST_IS_DIR | G_FILE_TEST_IS_EXECUTABLE | G_FILE_TEST_EXISTS)
+
+typedef struct _Sigmap {
+ int sig;
+ const char *name;
+} Sigmap;
+
+typedef struct _CallbackData CallbackData;
+typedef gboolean (*StopCallbackNotify)(CallbackData *);
+
+struct _CallbackData {
+ GObject *gobject;
+ JSObjectRef object;
+ JSObjectRef callback;
+ StopCallbackNotify notify;
+};
+
+static Sigmap _sigmap[] = {
+ { SCRIPTS_SIG_NAVIGATION, "navigation" },
+ { SCRIPTS_SIG_LOAD_STATUS, "loadStatus" },
+ { SCRIPTS_SIG_MIME_TYPE, "mimeType" },
+ { SCRIPTS_SIG_DOWNLOAD, "download" },
+ { SCRIPTS_SIG_DOWNLOAD_STATUS, "downloadStatus" },
+ { SCRIPTS_SIG_RESOURCE, "resource" },
+ { SCRIPTS_SIG_KEY_PRESS, "keyPress" },
+ { SCRIPTS_SIG_KEY_RELEASE, "keyRelease" },
+ { SCRIPTS_SIG_BUTTON_PRESS, "buttonPress" },
+ { SCRIPTS_SIG_BUTTON_RELEASE, "buttonRelease" },
+ { SCRIPTS_SIG_TAB_FOCUS, "tabFocus" },
+ { SCRIPTS_SIG_FRAME_STATUS, "frameStatus" },
+ { SCRIPTS_SIG_LOAD_FINISHED, "loadFinished" },
+ { SCRIPTS_SIG_LOAD_COMMITTED, "loadCommitted" },
+ { SCRIPTS_SIG_HOVERING_OVER_LINK, "hoveringOverLink" },
+ { SCRIPTS_SIG_CLOSE_TAB, "closeTab" },
+ { SCRIPTS_SIG_CREATE_TAB, "createTab" },
+ { SCRIPTS_SIG_FRAME_CREATED, "frameCreated" },
+};
+
+
+static JSValueRef equals(JSContextRef ctx, JSObjectRef function, JSObjectRef this, size_t argc, const JSValueRef argv[], JSValueRef* exc);
+
+static JSValueRef wv_load_uri(JSContextRef ctx, JSObjectRef function, JSObjectRef this, size_t argc, const JSValueRef argv[], JSValueRef* exc);
+static JSValueRef wv_history(JSContextRef ctx, JSObjectRef function, JSObjectRef this, size_t argc, const JSValueRef argv[], JSValueRef* exc);
+static JSValueRef wv_reload(JSContextRef ctx, JSObjectRef function, JSObjectRef this, size_t argc, const JSValueRef argv[], JSValueRef* exc);
+static JSValueRef wv_inject(JSContextRef ctx, JSObjectRef function, JSObjectRef this, size_t argc, const JSValueRef argv[], JSValueRef* exc);
+static JSStaticFunction default_functions[] = {
+ { "equals", equals, kJSDefaultAttributes },
+ { 0, 0, 0 },
+};
+static JSStaticFunction wv_functions[] = {
+ { "loadUri", wv_load_uri, kJSDefaultAttributes },
+ { "history", wv_history, kJSDefaultAttributes },
+ { "reload", wv_reload, kJSDefaultAttributes },
+ { "inject", wv_inject, kJSDefaultAttributes },
+ { "equals", equals, kJSDefaultAttributes },
+ { 0, 0, 0 },
+};
+static JSValueRef wv_get_main_frame(JSContextRef ctx, JSObjectRef object, JSStringRef js_name, JSValueRef* exception);
+static JSValueRef wv_get_focused_frame(JSContextRef ctx, JSObjectRef object, JSStringRef js_name, JSValueRef* exception);
+static JSValueRef wv_get_all_frames(JSContextRef ctx, JSObjectRef object, JSStringRef js_name, JSValueRef* exception);
+static JSValueRef wv_get_number(JSContextRef ctx, JSObjectRef object, JSStringRef js_name, JSValueRef* exception);
+static JSStaticValue wv_values[] = {
+ { "mainFrame", wv_get_main_frame, NULL, kJSDefaultAttributes },
+ { "focusedFrame", wv_get_focused_frame, NULL, kJSDefaultAttributes },
+ { "allFrames", wv_get_all_frames, NULL, kJSDefaultAttributes },
+ { "number", wv_get_number, NULL, kJSDefaultAttributes },
+ { 0, 0, 0, 0 },
+};
+
+static JSValueRef frame_inject(JSContextRef ctx, JSObjectRef function, JSObjectRef this, size_t argc, const JSValueRef argv[], JSValueRef* exc);
+static JSStaticFunction frame_functions[] = {
+ { "inject", frame_inject, kJSDefaultAttributes },
+ { "equals", equals, kJSDefaultAttributes },
+ { 0, 0, 0 },
+};
+static JSValueRef frame_get_domain(JSContextRef ctx, JSObjectRef object, JSStringRef js_name, JSValueRef* exception);
+static JSValueRef frame_get_host(JSContextRef ctx, JSObjectRef object, JSStringRef js_name, JSValueRef* exception);
+static JSStaticValue frame_values[] = {
+ { "host", frame_get_host, NULL, kJSDefaultAttributes },
+ { "domain", frame_get_domain, NULL, kJSDefaultAttributes },
+ { 0, 0, 0, 0 },
+};
+
+static JSValueRef download_start(JSContextRef ctx, JSObjectRef function, JSObjectRef this, size_t argc, const JSValueRef argv[], JSValueRef* exc);
+static JSValueRef download_cancel(JSContextRef ctx, JSObjectRef function, JSObjectRef this, size_t argc, const JSValueRef argv[], JSValueRef* exc);
+static JSStaticFunction download_functions[] = {
+ { "start", download_start, kJSDefaultAttributes },
+ { "cancel", download_cancel, kJSDefaultAttributes },
+ { "equals", equals, kJSDefaultAttributes },
+ { 0, 0, 0 },
+};
+enum {
+ SPAWN_SUCCESS = 0,
+ SPAWN_FAILED = 1<<0,
+ SPAWN_STDOUT_FAILED = 1<<1,
+ SPAWN_STDERR_FAILED = 1<<2,
+};
+
+
+static void callback(CallbackData *c);
+static void make_callback(JSContextRef ctx, JSObjectRef this, GObject *gobject, const char *signalname, JSValueRef value, StopCallbackNotify notify, JSValueRef *exception);
+static JSObjectRef make_object(JSContextRef ctx, GObject *o);
+
+static JSObjectRef _sigObjects[SCRIPTS_SIG_LAST];
+static JSGlobalContextRef _global_context;
+static GSList *_script_list;
+static JSClassRef _webview_class, _frame_class, _download_class, _default_class, _download_class;
+
+/* MISC {{{*/
+/* uncamelize {{{*/
+static char *
+uncamelize(char *uncamel, const char *camel, char rep, size_t length) {
+ char *ret = uncamel;
+ size_t written = 0;
+ if (isupper(*camel) && length > 1) {
+ *uncamel++ = tolower(*camel++);
+ written++;
+ }
+ while (written++<length-1 && *camel != 0) {
+ if (isupper(*camel)) {
+ *uncamel++ = rep;
+ if (++written >= length-1)
+ break;
+ *uncamel++ = tolower(*camel++);
+ }
+ else {
+ *uncamel++ = *camel++;
+ }
+ }
+ while (!(*uncamel = 0) && written++<length-1);
+ return ret;
+}/*}}}*/
+
+/* print_exception {{{*/
+static gboolean
+print_exception(JSContextRef ctx, JSValueRef exception) {
+ if (exception == NULL)
+ return false;
+ if (!JSValueIsObject(ctx, exception))
+ return false;
+ JSObjectRef o = JSValueToObject(ctx, exception, NULL);
+ if (o == NULL)
+ return false;
+
+ gint line = (int)js_get_double_property(ctx, o, "line");
+ gchar *message = js_get_string_property(ctx, o, "message");
+ fprintf(stderr, "DWB SCRIPT EXCEPTION: in line %d: %s\n", line, message == NULL ? "unknown" : message);
+ g_free(message);
+ return true;
+}
+/*}}}*/
+
+/* inject {{{*/
+static JSValueRef
+inject(JSContextRef ctx, JSContextRef wctx, JSObjectRef function, JSObjectRef this, size_t argc, const JSValueRef argv[], JSValueRef* exc) {
+ gboolean ret = false, global = false;
+ if (argc < 1) {
+ js_make_exception(ctx, exc, EXCEPTION("webview.inject: missing argument"));
+ return JSValueMakeBoolean(ctx, false);
+ }
+ if (argc > 1 && JSValueIsBoolean(ctx, argv[1]))
+ global = JSValueToBoolean(ctx, argv[1]);
+
+ JSStringRef script = JSValueToStringCopy(ctx, argv[0], exc);
+ if (script == NULL)
+ return JSValueMakeBoolean(ctx, false);
+
+ if (!JSCheckScriptSyntax(wctx, script, NULL, 0, NULL))
+ return JSValueMakeBoolean(ctx, false);
+
+ if (global) {
+ ret = JSEvaluateScript(wctx, script, NULL, NULL, 0, NULL) != NULL;
+ }
+ else {
+ JSObjectRef function = JSObjectMakeFunction(wctx, NULL, 0, NULL, script, NULL, 0, NULL);
+ if (function != NULL && JSObjectIsFunction(ctx, function)) {
+ ret = JSObjectCallAsFunction(wctx, function, NULL, 0, NULL, NULL) != NULL;
+ }
+ }
+ JSStringRelease(script);
+ return JSValueMakeBoolean(ctx, ret);
+}/*}}}*/
+/*}}}*/
+
+/* CALLBACK {{{*/
+/* callback_data_new {{{*/
+static CallbackData *
+callback_data_new(GObject *gobject, JSObjectRef object, JSObjectRef callback, StopCallbackNotify notify) {
+ CallbackData *c = g_malloc(sizeof(CallbackData));
+ c->gobject = gobject != NULL ? g_object_ref(gobject) : NULL;
+ if (object != NULL) {
+ JSValueProtect(_global_context, object);
+ c->object = object;
+ }
+ if (object != NULL) {
+ JSValueProtect(_global_context, callback);
+ c->callback = callback;
+ }
+ c->notify = notify;
+ return c;
+}/*}}}*/
+
+/* callback_data_free {{{*/
+static void
+callback_data_free(CallbackData *c) {
+ if (c != NULL) {
+ if (c->gobject != NULL)
+ g_object_unref(c->gobject);
+ if (c->object != NULL)
+ JSValueUnprotect(_global_context, c->object);
+ JSValueUnprotect(_global_context, c->object);
+ if (c->object != NULL)
+ JSValueUnprotect(_global_context, c->callback);
+ g_free(c);
+ }
+}/*}}}*/
+
+/* make_callback {{{*/
+static void
+make_callback(JSContextRef ctx, JSObjectRef this, GObject *gobject, const char *signalname, JSValueRef value, StopCallbackNotify notify, JSValueRef *exception) {
+ JSObjectRef func = JSValueToObject(ctx, value, exception);
+ if (func != NULL && JSObjectIsFunction(ctx, func)) {
+ CallbackData *c = callback_data_new(gobject, this, func, notify);
+ g_signal_connect_swapped(gobject, signalname, G_CALLBACK(callback), c);
+ }
+}/*}}}*/
+
+/* callback {{{*/
+static void
+callback(CallbackData *c) {
+ gboolean ret = false;
+ JSValueRef val[] = { c->object != NULL ? c->object : JSValueMakeNull(_global_context) };
+ JSValueRef jsret = JSObjectCallAsFunction(_global_context, c->callback, NULL, 1, val, NULL);
+ if (JSValueIsBoolean(_global_context, jsret))
+ ret = JSValueToBoolean(_global_context, jsret);
+ if (ret || (c != NULL && c->gobject != NULL && c->notify != NULL && c->notify(c))) {
+ g_signal_handlers_disconnect_by_func(c->gobject, callback, c);
+ callback_data_free(c);
+ }
+}/*}}}*/
+/*}}}*/
+
+/* TABS {{{*/
+/* tabs_current {{{*/
+static JSValueRef
+tabs_current(JSContextRef ctx, JSObjectRef this, JSStringRef name, JSValueRef* exc) {
+ return CURRENT_VIEW()->script_wv;
+}/*}}}*/
+
+/* tabs_number {{{*/
+static JSValueRef
+tabs_number(JSContextRef ctx, JSObjectRef this, JSStringRef name, JSValueRef* exc) {
+ return JSValueMakeNumber(ctx, g_list_position(dwb.state.views, dwb.state.fview));
+}/*}}}*/
+
+/* tabs_length {{{*/
+static JSValueRef
+tabs_length(JSContextRef ctx, JSObjectRef this, JSStringRef name, JSValueRef* exc) {
+ return JSValueMakeNumber(ctx, g_list_length(dwb.state.views));
+}/*}}}*/
+
+/* tabs_get_nth {{{*/
+static JSValueRef
+tabs_get_nth(JSContextRef ctx, JSObjectRef function, JSObjectRef thisObject, size_t argc, const JSValueRef argv[], JSValueRef* exc) {
+ if (argc < 1) {
+ js_make_exception(ctx, exc, EXCEPTION("tabs.nth: missing argument"));
+ return JSValueMakeNull(ctx);
+ }
+ double n = JSValueToNumber(ctx, argv[0], exc);
+ if (n == NAN)
+ return JSValueMakeNull(ctx);
+ GList *nth = g_list_nth(dwb.state.views, (int)n);
+ if (nth == NULL)
+ return JSValueMakeNull(ctx);
+ return VIEW(nth)->script_wv;
+}/*}}}*/
+/*}}}*/
+
+/* WEBVIEW {{{*/
+/* wv_status_cb {{{*/
+static gboolean
+wv_status_cb(CallbackData *c) {
+ WebKitLoadStatus status = webkit_web_view_get_load_status(WEBKIT_WEB_VIEW(c->gobject));
+ if (status == WEBKIT_LOAD_FINISHED || status == WEBKIT_LOAD_FAILED) {
+ return true;
+ }
+ return false;
+}/*}}}*/
+
+/* wv_load_uri {{{*/
+static JSValueRef
+wv_load_uri(JSContextRef ctx, JSObjectRef function, JSObjectRef this, size_t argc, const JSValueRef argv[], JSValueRef* exc) {
+ if (argc == 0) {
+ js_make_exception(ctx, exc, EXCEPTION("webview.loadUri: missing argument."));
+ return JSValueMakeBoolean(ctx, false);
+ }
+ WebKitWebView *wv = JSObjectGetPrivate(this);
+
+ if (wv != NULL) {
+ char *uri = js_value_to_char(ctx, argv[0], -1, exc);
+ if (uri == NULL)
+ return false;
+ webkit_web_view_load_uri(wv, uri);
+ g_free(uri);
+ if (argc > 1) {
+ make_callback(ctx, this, G_OBJECT(wv), "notify::load-status", argv[1], wv_status_cb, exc);
+ }
+ return JSValueMakeBoolean(ctx, true);
+ }
+ return false;
+}/*}}}*/
+
+/* wv_history {{{*/
+static JSValueRef
+wv_history(JSContextRef ctx, JSObjectRef function, JSObjectRef this, size_t argc, const JSValueRef argv[], JSValueRef* exc) {
+ JSValueRef ret = JSValueMakeUndefined(ctx);
+ if (argc < 1) {
+ js_make_exception(ctx, exc, EXCEPTION("webview.history: missing argument."));
+ return ret;
+ }
+ double steps = JSValueToNumber(ctx, argv[0], exc);
+ if (steps != NAN) {
+ webkit_web_view_go_back_or_forward(JSObjectGetPrivate(this), (int)steps);
+ }
+ return ret;
+}/*}}}*/
+
+/* wv_reload {{{*/
+static JSValueRef
+wv_reload(JSContextRef ctx, JSObjectRef function, JSObjectRef this, size_t argc, const JSValueRef argv[], JSValueRef* exc) {
+ webkit_web_view_reload(JSObjectGetPrivate(this));
+ return JSValueMakeUndefined(ctx);
+}/*}}}*/
+
+/* wv_inject {{{*/
+static JSValueRef
+wv_inject(JSContextRef ctx, JSObjectRef function, JSObjectRef this, size_t argc, const JSValueRef argv[], JSValueRef* exc) {
+ WebKitWebView *wv = JSObjectGetPrivate(this);
+ JSContextRef wctx = webkit_web_frame_get_global_context(webkit_web_view_get_main_frame(wv));
+ return inject(ctx, wctx, function, this, argc, argv, exc);
+}/*}}}*/
+/* wv_get_main_frame {{{*/
+static JSValueRef
+wv_get_main_frame(JSContextRef ctx, JSObjectRef object, JSStringRef js_name, JSValueRef* exception) {
+ WebKitWebView *wv = JSObjectGetPrivate(object);
+ WebKitWebFrame *frame = webkit_web_view_get_main_frame(wv);
+ return make_object(ctx, G_OBJECT(frame));
+}/*}}}*/
+
+/* wv_get_focused_frame {{{*/
+static JSValueRef
+wv_get_focused_frame(JSContextRef ctx, JSObjectRef object, JSStringRef js_name, JSValueRef* exception) {
+ WebKitWebView *wv = JSObjectGetPrivate(object);
+ WebKitWebFrame *frame = webkit_web_view_get_focused_frame(wv);
+ return make_object(ctx, G_OBJECT(frame));
+}/*}}}*/
+
+/* wv_get_all_frames {{{*/
+static JSValueRef
+wv_get_all_frames(JSContextRef ctx, JSObjectRef object, JSStringRef js_name, JSValueRef* exception) {
+ GList *gl = NULL;
+ for (gl = dwb.state.views; gl && VIEW(gl)->script_wv != object; gl=gl->next);
+ if (gl == NULL)
+ return JSValueMakeNull(ctx);
+ int argc = g_slist_length(VIEW(gl)->status->frames);
+ JSValueRef argv[argc];
+ int n=0;
+ for (GSList *sl = VIEW(gl)->status->frames; sl; sl=sl->next) {
+ argv[n++] = make_object(ctx, G_OBJECT(sl->data));
+ }
+ return JSObjectMakeArray(ctx, argc, argv, exception);
+}/*}}}*/
+
+/* wv_get_number {{{*/
+static JSValueRef
+wv_get_number(JSContextRef ctx, JSObjectRef object, JSStringRef js_name, JSValueRef* exception) {
+ WebKitWebView *wv = JSObjectGetPrivate(object);
+ GList *gl = dwb.state.views;
+ for (int i=0; gl; i++, gl=gl->next) {
+ if (wv == WEBVIEW(gl))
+ return JSValueMakeNumber(ctx, i);
+ }
+ return JSValueMakeNumber(ctx, -1);
+}/*}}}*/
+/*}}}*/
+
+/* FRAMES {{{*/
+/* frame_get_domain {{{*/
+static JSValueRef
+frame_get_domain(JSContextRef ctx, JSObjectRef object, JSStringRef js_name, JSValueRef* exception) {
+ SoupMessage *msg = dwb_soup_get_message(JSObjectGetPrivate(object));
+ if (msg == NULL)
+ return JSValueMakeNull(ctx);
+ SoupURI *uri = soup_message_get_uri(msg);
+ const char *host = soup_uri_get_host(uri);
+ return js_char_to_value(ctx, domain_get_base_for_host(host));
+}/*}}}*/
+
+/* frame_get_host {{{*/
+static JSValueRef
+frame_get_host(JSContextRef ctx, JSObjectRef object, JSStringRef js_name, JSValueRef* exception) {
+ SoupMessage *msg = dwb_soup_get_message(JSObjectGetPrivate(object));
+ if (msg == NULL)
+ return JSValueMakeNull(ctx);
+ SoupURI *uri = soup_message_get_uri(msg);
+ return js_char_to_value(ctx, soup_uri_get_host(uri));
+}/*}}}*/
+
+/* frame_inject {{{*/
+static JSValueRef
+frame_inject(JSContextRef ctx, JSObjectRef function, JSObjectRef this, size_t argc, const JSValueRef argv[], JSValueRef* exc) {
+ WebKitWebFrame *frame = JSObjectGetPrivate(this);
+ JSContextRef wctx = webkit_web_frame_get_global_context(frame);
+ return inject(ctx, wctx, function, this, argc, argv, exc);
+}/*}}}*/
+/*}}}*/
+
+/* GLOBAL {{{*/
+/* global_checksum {{{*/
+static JSValueRef
+global_checksum(JSContextRef ctx, JSObjectRef function, JSObjectRef thisObject, size_t argc, const JSValueRef argv[], JSValueRef* exc) {
+ JSValueRef ret;
+ if (argc < 1) {
+ js_make_exception(ctx, exc, EXCEPTION("checksum: missing argument."));
+ return JSValueMakeNull(ctx);
+ }
+ guchar *original = (guchar*)js_value_to_char(ctx, argv[0], -1, exc);
+ if (original == NULL)
+ return JSValueMakeNull(ctx);
+ GChecksumType type = G_CHECKSUM_SHA256;
+ if (argc > 1) {
+ type = JSValueToNumber(ctx, argv[1], exc);
+ if (type == NAN) {
+ ret = JSValueMakeNull(ctx);
+ goto error_out;
+ }
+ type = MIN(MAX(type, G_CHECKSUM_MD5), G_CHECKSUM_SHA256);
+ }
+ char *checksum = g_compute_checksum_for_data(type, original, -1);
+
+ ret = js_char_to_value(ctx, checksum);
+
+error_out:
+ g_free(original);
+ g_free(checksum);
+ return ret;
+}/*}}}*/
+
+/* scripts_eval_key {{{*/
+DwbStatus
+scripts_eval_key(KeyMap *m, Arg *arg) {
+ JSObjectCallAsFunction(_global_context, arg->p, NULL, 0, NULL, NULL);
+ return STATUS_OK;
+}/*}}}*/
+
+/* global_bind {{{*/
+static JSValueRef
+global_bind(JSContextRef ctx, JSObjectRef function, JSObjectRef thisObject, size_t argc, const JSValueRef argv[], JSValueRef* exc) {
+ gboolean ret = false;
+ if (argc < 2) {
+ js_make_exception(ctx, exc, EXCEPTION("bind: missing argument."));
+ return JSValueMakeBoolean(ctx, false);
+ }
+ char *keystr = js_value_to_char(ctx, argv[0], JS_STRING_MAX, exc);
+ if (keystr == NULL)
+ goto error_out;
+ JSObjectRef func = JSValueToObject(ctx, argv[1], exc);
+ if (func == NULL)
+ goto error_out;
+ if (!JSObjectIsFunction(ctx, func)) {
+ js_make_exception(ctx, exc, EXCEPTION("bind: not a function."));
+ goto error_out;
+ }
+ JSValueProtect(ctx, func);
+ KeyMap *map = dwb_malloc(sizeof(KeyMap));
+ FunctionMap *fmap = dwb_malloc(sizeof(FunctionMap));
+ Key key = dwb_str_to_key(keystr);
+ map->key = key.str;
+ map->mod = key.mod;
+ FunctionMap fm = { { NULL, NULL }, CP_DONT_SAVE, (Func)scripts_eval_key, NULL, ALWAYS_SM, { .p = func, .ro = true } };
+ *fmap = fm;
+ map->map = fmap;
+ dwb.keymap = g_list_prepend(dwb.keymap, map);
+
+ ret = true;
+error_out:
+ g_free(keystr);
+ return JSValueMakeBoolean(ctx, ret);
+}/*}}}*/
+
+/* global_execute {{{*/
+static JSValueRef
+global_execute(JSContextRef ctx, JSObjectRef function, JSObjectRef thisObject, size_t argc, const JSValueRef argv[], JSValueRef* exc) {
+ DwbStatus status = STATUS_ERROR;
+ if (argc < 1) {
+ js_make_exception(ctx, exc, EXCEPTION("execute: missing argument."));
+ return JSValueMakeBoolean(ctx, false);
+ }
+ char *command = js_value_to_char(ctx, argv[0], -1, exc);
+ if (command != NULL) {
+ status = dwb_parse_command_line(command);
+ g_free(command);
+ }
+ return JSValueMakeBoolean(ctx, status == STATUS_OK);
+}/*}}}*/
+
+/* global_include {{{*/
+static JSValueRef
+global_include(JSContextRef ctx, JSObjectRef f, JSObjectRef thisObject, size_t argc, const JSValueRef argv[], JSValueRef* exc) {
+ JSValueRef ret = NULL;
+ gboolean global = false;
+ if (argc < 1) {
+ js_make_exception(ctx, exc, EXCEPTION("include: missing argument."));
+ return JSValueMakeNull(ctx);
+ }
+ if (argc > 1 && JSValueIsBoolean(ctx, argv[1]))
+ global = JSValueToBoolean(ctx, argv[1]);
+
+ char *path = NULL, *content = NULL;
+ if ( (path = js_value_to_char(ctx, argv[0], PATH_MAX, exc)) == NULL)
+ goto error_out;
+ if ( (content = util_get_file_content(path)) == NULL) {
+ js_make_exception(ctx, exc, EXCEPTION("include: reading %s failed."), path);
+ goto error_out;
+ }
+ JSStringRef script = JSStringCreateWithUTF8CString(content);
+
+ if (global) {
+ ret = JSEvaluateScript(ctx, script, NULL, NULL, 0, exc);
+ }
+ else {
+ JSObjectRef function = JSObjectMakeFunction(ctx, NULL, 0, NULL, script, NULL, 0, exc);
+ if (function != NULL) {
+ ret = JSObjectCallAsFunction(ctx, function, thisObject, 0, NULL, exc);
+ }
+ }
+ JSStringRelease(script);
+
+error_out:
+ g_free(content);
+ g_free(path);
+ if (ret == NULL)
+ return JSValueMakeNull(ctx);
+ return ret;
+}/*}}}*/
+
+/* global_domain_from_host {{{*/
+static JSValueRef
+global_domain_from_host(JSContextRef ctx, JSObjectRef f, JSObjectRef thisObject, size_t argc, const JSValueRef argv[], JSValueRef* exc) {
+ if (argc < 1) {
+ js_make_exception(ctx, exc, EXCEPTION("domainFromHost: missing argument."));
+ return JSValueMakeBoolean(ctx, false);
+ }
+ char *host = js_value_to_char(ctx, argv[0], -1, exc);
+ const char *domain = domain_get_base_for_host(host);
+ if (domain == NULL)
+ return JSValueMakeNull(ctx);
+ JSValueRef ret = js_char_to_value(ctx, domain);
+ g_free(host);
+ return ret;
+}/*}}}*/
+
+/* timeout_callback {{{*/
+static gboolean
+timeout_callback(JSObjectRef obj) {
+ JSValueRef val = JSObjectCallAsFunction(_global_context, obj, NULL, 0, NULL, NULL);
+ if (val == NULL)
+ return false;
+ return !JSValueIsBoolean(_global_context, val) || JSValueToBoolean(_global_context, val);
+}/*}}}*/
+
+/* global_timer_stop {{{*/
+static JSValueRef
+global_timer_stop(JSContextRef ctx, JSObjectRef f, JSObjectRef thisObject, size_t argc, const JSValueRef argv[], JSValueRef* exc) {
+ gdouble sigid;
+ if (argc < 1) {
+ js_make_exception(ctx, exc, EXCEPTION("timerStop: missing argument."));
+ return JSValueMakeBoolean(ctx, false);
+ }
+ if ((sigid = JSValueToNumber(ctx, argv[0], exc)) != NAN) {
+ gboolean ret = g_source_remove((int)sigid);
+ return JSValueMakeBoolean(ctx, ret);
+ }
+ return JSValueMakeBoolean(ctx, false);
+}/*}}}*/
+
+/* global_timer_start {{{*/
+static JSValueRef
+global_timer_start(JSContextRef ctx, JSObjectRef f, JSObjectRef thisObject, size_t argc, const JSValueRef argv[], JSValueRef* exc) {
+ if (argc < 2) {
+ js_make_exception(ctx, exc, EXCEPTION("timerStart: missing argument."));
+ return JSValueMakeNumber(ctx, -1);
+ }
+ double msec = 10;
+ if ((msec = JSValueToNumber(ctx, argv[0], exc)) == NAN )
+ return JSValueMakeNumber(ctx, -1);
+ JSObjectRef func = JSValueToObject(ctx, argv[1], exc);
+ if (func == NULL || !JSObjectIsFunction(ctx, func)) {
+ js_make_exception(ctx, exc, EXCEPTION("timerStart: argument 2 is not a function."));
+ return JSValueMakeNumber(ctx, -1);
+ }
+ int ret = g_timeout_add((int)msec, (GSourceFunc)timeout_callback, func);
+ return JSValueMakeNumber(ctx, ret);
+}/*}}}*/
+/*}}}*/
+
+/* DATA {{{*/
+/* data_get_profile {{{*/
+static JSValueRef
+data_get_profile(JSContextRef ctx, JSObjectRef object, JSStringRef js_name, JSValueRef* exception) {
+ return js_char_to_value(ctx, dwb.misc.profile);
+}/*}}}*/
+
+/* data_get_cache_dir {{{*/
+static JSValueRef
+data_get_cache_dir(JSContextRef ctx, JSObjectRef object, JSStringRef js_name, JSValueRef* exception) {
+ return js_char_to_value(ctx, dwb.files.cachedir);
+}/*}}}*/
+
+/* data_get_config_dir {{{*/
+static JSValueRef
+data_get_config_dir(JSContextRef ctx, JSObjectRef object, JSStringRef js_name, JSValueRef* exception) {
+ char *dir = util_build_path();
+ if (dir == NULL) {
+ js_make_exception(ctx, exception, EXCEPTION("configDir: cannot get config path."));
+ return JSValueMakeNull(ctx);
+ }
+ JSValueRef ret = js_char_to_value(ctx, dir);
+ g_free(dir);
+ return ret;
+}/*}}}*/
+
+/* data_get_system_data_dir {{{*/
+static JSValueRef
+data_get_system_data_dir(JSContextRef ctx, JSObjectRef object, JSStringRef js_name, JSValueRef* exception) {
+ char *dir = util_get_system_data_dir(NULL);
+ if (dir == NULL) {
+ js_make_exception(ctx, exception, EXCEPTION("systemDataDir: cannot get system data directory."));
+ return JSValueMakeNull(ctx);
+ }
+ JSValueRef ret = js_char_to_value(ctx, dir);
+ g_free(dir);
+ return ret;
+}/*}}}*/
+
+/* data_get_user_data_dir {{{*/
+static JSValueRef
+data_get_user_data_dir(JSContextRef ctx, JSObjectRef object, JSStringRef js_name, JSValueRef* exception) {
+ char *dir = util_get_user_data_dir(NULL);
+ if (dir == NULL) {
+ js_make_exception(ctx, exception, EXCEPTION("userDataDir: cannot get user data directory."));
+ return JSValueMakeNull(ctx);
+ }
+ JSValueRef ret = js_char_to_value(ctx, dir);
+ g_free(dir);
+ return ret;
+}/*}}}*/
+/*}}}*/
+
+/* SYSTEM {{{*/
+/* system_get_env {{{*/
+static JSValueRef
+system_get_env(JSContextRef ctx, JSObjectRef function, JSObjectRef thisObject, size_t argc, const JSValueRef argv[], JSValueRef* exc) {
+ if (argc < 1) {
+ js_make_exception(ctx, exc, EXCEPTION("system.getEnv: missing argument"));
+ return JSValueMakeNull(ctx);
+ }
+ char *name = js_value_to_char(ctx, argv[0], -1, exc);
+ if (name == NULL)
+ return JSValueMakeNull(ctx);
+ const char *env = g_getenv(name);
+ g_free(name);
+ if (env == NULL)
+ return JSValueMakeNull(ctx);
+ return js_char_to_value(ctx, env);
+}/*}}}*/
+
+/* spawn_output {{{*/
+static gboolean
+spawn_output(GIOChannel *channel, GIOCondition condition, JSObjectRef callback) {
+ char *content;
+ gsize length;
+ if (condition == G_IO_HUP || condition == G_IO_ERR || condition == G_IO_NVAL) {
+ g_io_channel_unref(channel);
+ return false;
+ }
+ else if (g_io_channel_read_to_end(channel, &content, &length, NULL) == G_IO_STATUS_NORMAL && content != NULL) {
+ JSValueRef arg = js_char_to_value(_global_context, content);
+ if (arg != NULL) {
+ JSValueRef argv[] = { arg };
+ JSObjectCallAsFunction(_global_context, callback, NULL, 1, argv , NULL);
+ }
+ g_free(content);
+ return true;
+ }
+ return false;
+}/*}}}*/
+
+/* system_spawn {{{*/
+static JSValueRef
+system_spawn(JSContextRef ctx, JSObjectRef function, JSObjectRef thisObject, size_t argc, const JSValueRef argv[], JSValueRef* exc) {
+ int ret = 0;
+ int outfd, errfd;
+ char **srgv = NULL;
+ int srgc;
+ GIOChannel *out_channel, *err_channel;
+ JSObjectRef oc = NULL, ec = NULL;
+ if (argc < 1) {
+ js_make_exception(ctx, exc, EXCEPTION("spawn needs an argument."));
+ return JSValueMakeBoolean(ctx, SPAWN_FAILED);
+ }
+ if (argc > 1) {
+ oc = JSValueToObject(ctx, argv[1], NULL);
+ if ( oc == NULL || !JSObjectIsFunction(ctx, oc) ) {
+ if (!JSValueIsNull(ctx, argv[1]))
+ ret |= SPAWN_STDOUT_FAILED;
+ oc = NULL;
+ }
+ }
+ if (argc > 2) {
+ ec = JSValueToObject(ctx, argv[2], NULL);
+ if ( ec == NULL || !JSObjectIsFunction(ctx, ec) ) {
+ if (!JSValueIsNull(ctx, argv[2]))
+ ret |= SPAWN_STDERR_FAILED;
+ ec = NULL;
+ }
+ }
+ char *cmdline = js_value_to_char(ctx, argv[0], -1, exc);
+ if (cmdline == NULL) {
+ ret |= SPAWN_FAILED;
+ goto error_out;
+ }
+
+ if (!g_shell_parse_argv(cmdline, &srgc, &srgv, NULL) ||
+ !g_spawn_async_with_pipes(NULL, srgv, NULL, G_SPAWN_SEARCH_PATH, NULL, NULL, NULL, NULL, oc != NULL ? &outfd : NULL, ec != NULL ? &errfd : NULL, NULL)) {
+ js_make_exception(ctx, exc, EXCEPTION("spawning %s failed."), cmdline);
+ ret |= SPAWN_FAILED;
+ goto error_out;
+ }
+ if (oc != NULL) {
+ out_channel = g_io_channel_unix_new(outfd);
+ g_io_add_watch(out_channel, G_IO_IN | G_IO_HUP | G_IO_ERR | G_IO_NVAL, (GIOFunc)spawn_output, oc);
+ g_io_channel_set_close_on_unref(out_channel, true);
+ }
+ if (ec != NULL) {
+ err_channel = g_io_channel_unix_new(errfd);
+ g_io_add_watch(err_channel, G_IO_IN | G_IO_HUP | G_IO_ERR | G_IO_NVAL, (GIOFunc)spawn_output, ec);
+ g_io_channel_set_close_on_unref(err_channel, true);
+ }
+error_out:
+ g_free(cmdline);
+ return JSValueMakeNumber(ctx, ret);
+}/*}}}*/
+
+/* system_file_test {{{*/
+static JSValueRef
+system_file_test(JSContextRef ctx, JSObjectRef function, JSObjectRef thisObject, size_t argc, const JSValueRef argv[], JSValueRef* exc) {
+ if (argc < 2) {
+ js_make_exception(ctx, exc, EXCEPTION("system.fileTest needs an argument."));
+ return JSValueMakeBoolean(ctx, false);
+ }
+ char *path = js_value_to_char(ctx, argv[0], PATH_MAX, exc);
+ if (path == NULL)
+ return JSValueMakeBoolean(ctx, false);
+ double test = JSValueToNumber(ctx, argv[1], exc);
+ if (test == NAN || ! ( (((guint)test) & G_FILE_TEST_VALID) == (guint)test) )
+ return JSValueMakeBoolean(ctx, false);
+ gboolean ret = g_file_test(path, (GFileTest) test);
+ g_free(path);
+ return JSValueMakeBoolean(ctx, ret);
+}/*}}}*/
+
+/* system_mkdir {{{*/
+static JSValueRef
+system_mkdir(JSContextRef ctx, JSObjectRef function, JSObjectRef thisObject, size_t argc, const JSValueRef argv[], JSValueRef* exc) {
+ gboolean ret = false;
+ if (argc < 2) {
+ js_make_exception(ctx, exc, EXCEPTION("system.mkdir needs an argument."));
+ return JSValueMakeBoolean(ctx, false);
+ }
+ char *path = js_value_to_char(ctx, argv[0], PATH_MAX, exc);
+ double mode = JSValueToNumber(ctx, argv[1], exc);
+ if (path != NULL && mode != NAN) {
+ ret = g_mkdir_with_parents(path, (gint)mode) == 0;
+ }
+ g_free(path);
+ return JSValueMakeBoolean(ctx, ret);
+
+}/*}}}*/
+
+/*}}}*/
+
+/* IO {{{*/
+/* io_prompt {{{*/
+static JSValueRef
+io_prompt(JSContextRef ctx, JSObjectRef function, JSObjectRef thisObject, size_t argc, const JSValueRef argv[], JSValueRef* exc) {
+ char *prompt = NULL;
+ gboolean visibility = true;
+ if (argc > 0) {
+ prompt = js_value_to_char(ctx, argv[0], JS_STRING_MAX, exc);
+ }
+ if (argc > 1 && JSValueIsBoolean(ctx, argv[1]))
+ visibility = JSValueToBoolean(ctx, argv[1]);
+
+ const char *response = dwb_prompt(visibility, prompt);
+ g_free(prompt);
+ if (response == NULL)
+ return JSValueMakeNull(ctx);
+
+ return js_char_to_value(ctx, response);
+}/*}}}*/
+
+/* io_read {{{*/
+static JSValueRef
+io_read(JSContextRef ctx, JSObjectRef function, JSObjectRef thisObject, size_t argc, const JSValueRef argv[], JSValueRef* exc) {
+ JSValueRef ret = NULL;
+ char *path = NULL, *content = NULL;
+ if (argc < 1) {
+ js_make_exception(ctx, exc, EXCEPTION("io.read needs an argument."));
+ return JSValueMakeNull(ctx);
+ }
+ if ( (path = js_value_to_char(ctx, argv[0], PATH_MAX, exc) ) == NULL )
+ goto error_out;
+ if ( (content = util_get_file_content(path) ) == NULL ) {
+ goto error_out;
+ }
+ ret = js_char_to_value(ctx, content);
+
+error_out:
+ g_free(path);
+ g_free(content);
+ if (ret == NULL)
+ return JSValueMakeNull(ctx);
+ return ret;
+
+}/*}}}*/
+
+/* io_notify {{{*/
+static JSValueRef
+io_notify(JSContextRef ctx, JSObjectRef function, JSObjectRef thisObject, size_t argc, const JSValueRef argv[], JSValueRef* exc) {
+ if (argc < 1)
+ return JSValueMakeUndefined(ctx);
+ char *message = js_value_to_char(ctx, argv[0], -1, exc);
+ if (message != NULL) {
+ dwb_set_normal_message(dwb.state.fview, true, message);
+ g_free(message);
+ }
+ return JSValueMakeUndefined(ctx);
+}/*}}}*/
+
+/* io_error {{{*/
+static JSValueRef
+io_error(JSContextRef ctx, JSObjectRef function, JSObjectRef thisObject, size_t argc, const JSValueRef argv[], JSValueRef* exc) {
+ if (argc < 1)
+ return JSValueMakeUndefined(ctx);
+ char *message = js_value_to_char(ctx, argv[0], -1, exc);
+ if (message != NULL) {
+ dwb_set_error_message(dwb.state.fview, message);
+ g_free(message);
+ }
+ return JSValueMakeUndefined(ctx);
+}/*}}}*/
+
+/* io_write {{{*/
+static JSValueRef
+io_write(JSContextRef ctx, JSObjectRef function, JSObjectRef thisObject, size_t argc, const JSValueRef argv[], JSValueRef* exc) {
+ gboolean ret = false;
+ FILE *f;
+ char *path = NULL, *content = NULL, *mode = NULL;
+ if (argc < 3) {
+ js_make_exception(ctx, exc, EXCEPTION("io.write needs 3 arguments."));
+ return JSValueMakeBoolean(ctx, false);
+ }
+ if ( (path = js_value_to_char(ctx, argv[0], PATH_MAX, exc)) == NULL )
+ goto error_out;
+ if ( (mode = js_value_to_char(ctx, argv[1], -1, exc)) == NULL )
+ goto error_out;
+ if (g_strcmp0(mode, "w") && g_strcmp0(mode, "a")) {
+ js_make_exception(ctx, exc, EXCEPTION("io.write: invalid mode."));
+ goto error_out;
+ }
+ if ( (content = js_value_to_char(ctx, argv[2], -1, exc)) == NULL )
+ goto error_out;
+ if ( (f = fopen(path, mode)) != NULL) {
+ fprintf(f, content);
+ fclose(f);
+ }
+ else {
+ js_make_exception(ctx, exc, EXCEPTION("io.write: cannot open %s for writing."), path);
+ }
+error_out:
+ g_free(path);
+ g_free(mode);
+ g_free(content);
+ return JSValueMakeBoolean(ctx, ret);
+}/*}}}*/
+
+/* io_print {{{*/
+static JSValueRef
+io_print(JSContextRef ctx, JSObjectRef function, JSObjectRef thisObject, size_t argc, const JSValueRef argv[], JSValueRef* exc) {
+ if (argc == 0) {
+ js_make_exception(ctx, exc, EXCEPTION("io.print needs an argument."));
+ return JSValueMakeUndefined(_global_context);
+ }
+
+ FILE *stream = stdout;
+ if (argc >= 2) {
+ JSStringRef js_string = JSValueToStringCopy(ctx, argv[1], exc);
+ if (JSStringIsEqualToUTF8CString(js_string, "stderr"))
+ stream = stderr;
+ JSStringRelease(js_string);
+ }
+
+ char *out;
+ double dout;
+ char *json = NULL;
+ int type = JSValueGetType(ctx, argv[0]);
+ switch (type) {
+ case kJSTypeString :
+ out = js_value_to_char(ctx, argv[0], -1, exc);
+ if (out != NULL) {
+ fprintf(stream, "%s\n", out);
+ g_free(out);
+ }
+ break;
+ case kJSTypeBoolean :
+ fprintf(stream, "%s\n", JSValueToBoolean(ctx, argv[0]) ? "true" : "false");
+ break;
+ case kJSTypeNumber :
+ dout = JSValueToNumber(ctx, argv[0], exc);
+ if (dout != NAN)
+ fprintf(stream, "%f\n", dout);
+ else
+ fprintf(stream, "NAN\n");
+ break;
+ case kJSTypeUndefined :
+ fprintf(stream, "undefined\n");
+ break;
+ case kJSTypeNull :
+ fprintf(stream, "null\n");
+ break;
+ case kJSTypeObject :
+ json = js_value_to_json(ctx, argv[0], -1, NULL);
+ if (json != NULL) {
+ fprintf(stream, "%s\n", json);
+ g_free(json);
+ }
+ break;
+ default : break;
+ }
+ return JSValueMakeUndefined(ctx);
+}/*}}}*/
+/*}}}*/
+
+/* DOWNLOAD {{{*/
+/* download_constructor_cb {{{*/
+static JSObjectRef
+download_constructor_cb(JSContextRef ctx, JSObjectRef constructor, size_t argc, const JSValueRef argv[], JSValueRef* exception) {
+ if (argc<1) {
+ js_make_exception(ctx, exception, EXCEPTION("Download constructor: missing argument"));
+ return JSValueToObject(ctx, JSValueMakeNull(ctx), NULL);
+ }
+ char *uri = js_value_to_char(ctx, argv[0], -1, exception);
+ if (uri == NULL) {
+ js_make_exception(ctx, exception, EXCEPTION("Download constructor: invalid argument"));
+ return JSValueToObject(ctx, JSValueMakeNull(ctx), NULL);
+ }
+ WebKitNetworkRequest *request = webkit_network_request_new(uri);
+ g_free(uri);
+ if (request == NULL) {
+ js_make_exception(ctx, exception, EXCEPTION("Download constructor: invalid uri"));
+ return JSValueToObject(ctx, JSValueMakeNull(ctx), NULL);
+ }
+ WebKitDownload *download = webkit_download_new(request);
+ return JSObjectMake(ctx, _download_class, download);
+}/*}}}*/
+
+/* stop_download_notify {{{*/
+static gboolean
+stop_download_notify(CallbackData *c) {
+ WebKitDownloadStatus status = webkit_download_get_status(WEBKIT_DOWNLOAD(c->gobject));
+ if (status == WEBKIT_DOWNLOAD_STATUS_ERROR || status == WEBKIT_DOWNLOAD_STATUS_CANCELLED || status == WEBKIT_DOWNLOAD_STATUS_FINISHED) {
+ return true;
+ }
+ return false;
+}/*}}}*/
+
+/* download_start {{{*/
+static JSValueRef
+download_start(JSContextRef ctx, JSObjectRef function, JSObjectRef this, size_t argc, const JSValueRef argv[], JSValueRef* exc) {
+ WebKitDownload *download = JSObjectGetPrivate(this);
+ if (webkit_download_get_destination_uri(download) == NULL) {
+ js_make_exception(ctx, exc, EXCEPTION("Download.start: destination == null"));
+ return JSValueMakeBoolean(ctx, false);
+ }
+ if (argc > 0) {
+ make_callback(ctx, this, G_OBJECT(download), "notify::status", argv[0], stop_download_notify, exc);
+ }
+ webkit_download_start(download);
+ return JSValueMakeBoolean(ctx, true);
+
+}/*}}}*/
+
+/* download_cancel {{{*/
+static JSValueRef
+download_cancel(JSContextRef ctx, JSObjectRef function, JSObjectRef this, size_t argc, const JSValueRef argv[], JSValueRef* exc) {
+ webkit_download_cancel(JSObjectGetPrivate(this));
+ return JSValueMakeUndefined(ctx);
+}/*}}}*/
+/*}}}*/
+
+/* SIGNALS {{{*/
+/* signal_set {{{*/
+static bool
+signal_set(JSContextRef ctx, JSObjectRef object, JSStringRef js_name, JSValueRef value, JSValueRef* exception) {
+ char *name = js_string_to_char(ctx, js_name, -1);
+ JSObjectRef o;
+ if (name == NULL)
+ return false;
+
+ for (int i = SCRIPTS_SIG_FIRST; i<SCRIPTS_SIG_LAST; i++) {
+ if (strcmp(name, _sigmap[i].name))
+ continue;
+ if (JSValueIsNull(ctx, value)) {
+ dwb.misc.script_signals &= ~(1<<i);
+ }
+ else if ( (o = JSValueToObject(ctx, value, exception)) != NULL && JSObjectIsFunction(ctx, o)) {
+ _sigObjects[i] = o;
+ dwb.misc.script_signals |= (1<<i);
+ }
+ break;
+ }
+ return false;
+}/*}}}*/
+
+/* scripts_emit {{{*/
+gboolean
+scripts_emit(ScriptSignal *sig) {
+ JSObjectRef function = _sigObjects[sig->signal];
+ if (function == NULL)
+ return false;
+
+ int additional = sig->jsobj != NULL ? 2 : 1;
+ int numargs = MIN(sig->numobj, SCRIPT_MAX_SIG_OBJECTS)+additional;
+ JSValueRef val[numargs];
+ int i = 0;
+
+ if (sig->jsobj != NULL) {
+ val[i++] = sig->jsobj;
+ }
+ for (int j=0; j<sig->numobj; j++) {
+ val[i++] = make_object(_global_context, G_OBJECT(sig->objects[j]));
+ }
+ JSValueRef vson = NULL;
+ JSStringRef js_json = JSStringCreateWithUTF8CString(sig->json == NULL ? "{}" : sig->json);
+ vson = JSValueMakeFromJSONString(_global_context, js_json);
+ JSStringRelease(js_json);
+ val[i++] = vson == NULL ? JSValueMakeNull(_global_context) : vson;
+ JSValueRef js_ret = JSObjectCallAsFunction(_global_context, function, NULL, numargs, val, NULL);
+ if (JSValueIsBoolean(_global_context, js_ret)) {
+ return JSValueToBoolean(_global_context, js_ret);
+ }
+ return false;
+}/*}}}*/
+/*}}}*/
+
+/* OBJECTS {{{*/
+// TODO : creating 1000000 objects leaks ~ 4MB
+/* make_object {{{*/
+static JSObjectRef
+make_object(JSContextRef ctx, GObject *o) {
+ if (o == NULL) {
+ JSValueRef v = JSValueMakeNull(ctx);
+ return JSValueToObject(ctx, v, NULL);
+ }
+ JSClassRef class;
+ if (WEBKIT_IS_WEB_VIEW(o))
+ class = _webview_class;
+ else if (WEBKIT_IS_WEB_FRAME(o))
+ class = _frame_class;
+ else if (WEBKIT_IS_DOWNLOAD(o))
+ class = _download_class;
+ else
+ class = _default_class;
+
+ JSObjectRef retobj = JSObjectMake(ctx, class, o);
+ return retobj;
+}/*}}}*/
+
+/* equals {{{*/
+static JSValueRef
+equals(JSContextRef ctx, JSObjectRef function, JSObjectRef this, size_t argc, const JSValueRef argv[], JSValueRef* exc) {
+ if (argc < 1) {
+ js_make_exception(ctx, exc, EXCEPTION("object.equals: missing argument."));
+ return JSValueMakeBoolean(ctx, false);
+ }
+ JSObjectRef jscomp = JSValueToObject(ctx, argv[0], exc);
+ if (jscomp == NULL)
+ return JSValueMakeBoolean(ctx, false);
+ GObject *comp = JSObjectGetPrivate(jscomp);
+ if (comp == NULL)
+ return JSValueMakeBoolean(ctx, false);
+ GObject *o = JSObjectGetPrivate(this);
+ return JSValueMakeBoolean(ctx, o == comp);
+}/*}}}*/
+
+/* set_property_cb {{{*/
+static bool
+set_property_cb(JSContextRef ctx, JSObjectRef object, JSStringRef propertyName, JSValueRef value, JSValueRef* exception) {
+ return false;
+ //return true;
+}/*}}}*/
+
+/* create_class {{{*/
+static JSClassRef
+create_class(const char *name, JSStaticFunction staticFunctions[], JSStaticValue staticValues[]) {
+ JSClassDefinition cd = kJSClassDefinitionEmpty;
+ cd.className = name;
+ cd.staticFunctions = staticFunctions;
+ cd.staticValues = staticValues;
+ cd.setProperty = set_property_cb;
+ return JSClassCreate(&cd);
+}/*}}}*/
+
+/* create_object {{{*/
+static JSObjectRef
+create_object(JSContextRef ctx, JSClassRef class, JSObjectRef obj, JSClassAttributes attr, const char *name, void *private) {
+ JSObjectRef ret = JSObjectMake(ctx, class, private);
+ JSStringRef js_name = JSStringCreateWithUTF8CString(name);
+ JSObjectSetProperty(ctx, obj, js_name, ret, attr, NULL);
+ JSStringRelease(js_name);
+ return ret;
+}/*}}}*/
+
+/* set_property {{{*/
+static bool
+set_property(JSContextRef ctx, JSObjectRef object, JSStringRef js_name, JSValueRef jsvalue, JSValueRef* exception) {
+ char buf[PROP_LENGTH];
+ char *name = js_string_to_char(ctx, js_name, -1);
+ if (name == NULL)
+ return false;
+ uncamelize(buf, name, '-', PROP_LENGTH);
+ g_free(name);
+
+ GObject *o = JSObjectGetPrivate(object);
+ GObjectClass *class = G_OBJECT_GET_CLASS(o);
+ GParamSpec *pspec = g_object_class_find_property(class, buf);
+
+ if (pspec == NULL)
+ return false;
+ if (! (pspec->flags & G_PARAM_WRITABLE))
+ return false;
+ int jstype = JSValueGetType(ctx, jsvalue);
+ GType gtype = G_TYPE_IS_FUNDAMENTAL(pspec->value_type) ? pspec->value_type : g_type_parent(pspec->value_type);
+
+ if (jstype == kJSTypeNumber &&
+ (gtype == G_TYPE_INT || gtype == G_TYPE_UINT || gtype == G_TYPE_LONG || gtype == G_TYPE_ULONG ||
+ gtype == G_TYPE_FLOAT || gtype == G_TYPE_DOUBLE || gtype == G_TYPE_ENUM || gtype == G_TYPE_INT64 ||
+ gtype == G_TYPE_UINT64 || gtype == G_TYPE_FLAGS)) {
+ double value = JSValueToNumber(ctx, jsvalue, exception);
+ if (value != NAN) {
+ g_object_set(o, buf, value, NULL);
+ return true;
+ }
+ return false;
+ }
+ else if (jstype == kJSTypeBoolean && gtype == G_TYPE_BOOLEAN) {
+ bool value = JSValueToBoolean(ctx, jsvalue);
+ g_object_set(o, buf, value, NULL);
+ return true;
+ }
+ else if (jstype == kJSTypeString && gtype == G_TYPE_STRING) {
+ char *value = js_value_to_char(ctx, jsvalue, -1, exception);
+ g_object_set(o, buf, value, NULL);
+ g_free(value);
+ return true;
+ }
+ return false;
+ // TODO object
+}/*}}}*/
+
+/* get_property {{{*/
+static JSValueRef
+get_property(JSContextRef ctx, JSObjectRef jsobj, JSStringRef js_name, JSValueRef *exception) {
+ char buf[PROP_LENGTH];
+ JSValueRef ret = NULL;
+ char *name = js_string_to_char(ctx, js_name, -1);
+ if (name == NULL)
+ return NULL;
+ uncamelize(buf, name, '-', PROP_LENGTH);
+ g_free(name);
+
+ GObject *o = JSObjectGetPrivate(jsobj);
+ GObjectClass *class = G_OBJECT_GET_CLASS(o);
+ GParamSpec *pspec = g_object_class_find_property(class, buf);
+ if (pspec == NULL)
+ return NULL;
+ if (! (pspec->flags & G_PARAM_READABLE))
+ return NULL;
+
+ GType gtype = pspec->value_type, act;
+ while ((act = g_type_parent(gtype))) {
+ gtype = act;
+ }
+#define CHECK_NUMBER(GTYPE, TYPE) G_STMT_START if (gtype == G_TYPE_##GTYPE) { \
+ TYPE value; g_object_get(o, buf, &value, NULL); return JSValueMakeNumber(ctx, (double)value); \
+} G_STMT_END
+ CHECK_NUMBER(INT, gint);
+ CHECK_NUMBER(UINT, guint);
+ CHECK_NUMBER(LONG, glong);
+ CHECK_NUMBER(ULONG, gulong);
+ CHECK_NUMBER(FLOAT, gfloat);
+ CHECK_NUMBER(DOUBLE, gdouble);
+ CHECK_NUMBER(ENUM, gint);
+ CHECK_NUMBER(INT64, gint64);
+ CHECK_NUMBER(UINT64, guint64);
+ CHECK_NUMBER(FLAGS, guint);
+#undef CHECK_NUMBER
+ if (pspec->value_type == G_TYPE_BOOLEAN) {
+ gboolean bval;
+ g_object_get(o, buf, &bval, NULL);
+ ret = JSValueMakeBoolean(ctx, bval);
+ }
+ else if (pspec->value_type == G_TYPE_STRING) {
+ char *value;
+ g_object_get(o, buf, &value, NULL);
+ ret = js_char_to_value(ctx, value);
+ g_free(value);
+ }
+ else if (G_TYPE_IS_CLASSED(gtype)) {
+ GObject *object;
+ g_object_get(o, buf, &object, NULL);
+ if (object == NULL)
+ return NULL;
+ JSObjectRef retobj = make_object(ctx, object);
+ g_object_unref(object);
+ ret = retobj;
+ }
+ return ret;
+}/*}}}*/
+
+/* create_global_object {{{*/
+static void
+create_global_object() {
+ JSStaticFunction global_functions[] = {
+ { "execute", global_execute, kJSDefaultAttributes },
+ { "bind", global_bind, kJSDefaultAttributes },
+ { "checksum", global_checksum, kJSDefaultAttributes },
+ { "include", global_include, kJSDefaultAttributes },
+ { "timerStart", global_timer_start, kJSDefaultAttributes },
+ { "timerStop", global_timer_stop, kJSDefaultAttributes },
+ { "domainFromHost", global_domain_from_host, kJSDefaultAttributes },
+ { 0, 0, 0 },
+ };
+
+ JSClassRef class = create_class("dwb", global_functions, NULL);
+ _global_context = JSGlobalContextCreate(class);
+ JSClassRelease(class);
+
+
+ JSObjectRef global_object = JSContextGetGlobalObject(_global_context);
+
+ JSStaticValue data_values[] = {
+ { "profile", data_get_profile, NULL, kJSDefaultAttributes },
+ { "cacheDir", data_get_cache_dir, NULL, kJSDefaultAttributes },
+ { "configDir", data_get_config_dir, NULL, kJSDefaultAttributes },
+ { "systemDataDir", data_get_system_data_dir, NULL, kJSDefaultAttributes },
+ { "userDataDir", data_get_user_data_dir, NULL, kJSDefaultAttributes },
+ { 0, 0, 0, 0 },
+ };
+ class = create_class("data", NULL, data_values);
+ create_object(_global_context, class, global_object, kJSDefaultAttributes, "data", NULL);
+ JSClassRelease(class);
+
+ JSStaticFunction io_functions[] = {
+ { "print", io_print, kJSDefaultAttributes },
+ { "prompt", io_prompt, kJSDefaultAttributes },
+ { "read", io_read, kJSDefaultAttributes },
+ { "write", io_write, kJSDefaultAttributes },
+ { "notify", io_notify, kJSDefaultAttributes },
+ { "error", io_error, kJSDefaultAttributes },
+ { 0, 0, 0 },
+ };
+ class = create_class("io", io_functions, NULL);
+ create_object(_global_context, class, global_object, kJSDefaultAttributes, "io", NULL);
+ JSClassRelease(class);
+
+ JSStaticFunction system_functions[] = {
+ { "spawn", system_spawn, kJSDefaultAttributes },
+ { "getEnv", system_get_env, kJSDefaultAttributes },
+ { "fileTest", system_file_test, kJSDefaultAttributes },
+ { "mkdir", system_mkdir, kJSDefaultAttributes },
+ { 0, 0, 0 },
+ };
+ class = create_class("system", system_functions, NULL);
+ create_object(_global_context, class, global_object, kJSDefaultAttributes, "system", NULL);
+ JSClassRelease(class);
+
+ JSStaticFunction tab_functions[] = {
+ { "nth", tabs_get_nth, kJSDefaultAttributes },
+ { 0, 0, 0 },
+ };
+ JSStaticValue tab_values[] = {
+ { "current", tabs_current, NULL, kJSDefaultAttributes },
+ { "number", tabs_number, NULL, kJSDefaultAttributes },
+ { "length", tabs_length, NULL, kJSDefaultAttributes },
+ { 0, 0, 0, 0 },
+ };
+ class = create_class("tabs", tab_functions, tab_values);
+ create_object(_global_context, class, global_object, kJSDefaultAttributes, "tabs", NULL);
+ JSClassRelease(class);
+
+ JSClassDefinition cd = kJSClassDefinitionEmpty;
+ cd.className = "signals";
+ cd.setProperty = signal_set;
+ class = JSClassCreate(&cd);
+
+ create_object(_global_context, class, global_object, kJSDefaultAttributes, "signals", NULL);
+ JSClassRelease(class);
+
+ class = create_class("extensions", NULL, NULL);
+ create_object(_global_context, class, global_object, kJSDefaultAttributes, "extensions", NULL);
+ JSClassRelease(class);
+
+ cd = kJSClassDefinitionEmpty;
+ cd.className = "globals";
+ class = JSClassCreate(&cd);
+ create_object(_global_context, class, global_object, kJSPropertyAttributeDontDelete, "globals", NULL);
+ class = JSClassCreate(&cd);
+
+ /* Default gobject class */
+ cd = kJSClassDefinitionEmpty;
+ cd.staticFunctions = default_functions;
+ cd.getProperty = get_property;
+ cd.setProperty = set_property;
+
+ _default_class = JSClassCreate(&cd);
+
+ /* Webview */
+ cd.staticFunctions = wv_functions;
+ cd.staticValues = wv_values;
+ _webview_class = JSClassCreate(&cd);
+
+ /* Frame */
+ cd.staticFunctions = frame_functions;
+ cd.staticValues = frame_values;
+ _frame_class = JSClassCreate(&cd);
+
+ /* download */
+ cd.className = "Download";
+ cd.staticFunctions = download_functions;
+ cd.staticValues = NULL;
+ _download_class = JSClassCreate(&cd);
+ JSObjectRef constructor = JSObjectMakeConstructor(_global_context, _download_class, download_constructor_cb);
+ JSStringRef name = JSStringCreateWithUTF8CString("Download");
+ JSObjectSetProperty(_global_context, JSContextGetGlobalObject(_global_context), name, constructor, kJSDefaultProperty, NULL);
+ JSStringRelease(name);
+}/*}}}*/
+/*}}}*/
+
+/* INIT AND END {{{*/
+/* apply_scripts {{{*/
+static void
+apply_scripts() {
+ JSStringRef on_init = JSStringCreateWithUTF8CString("init");
+ JSValueRef ret, init;
+ JSObjectRef retobj, initobj;
+ GSList *scripts = NULL;
+ for (GSList *l = _script_list; l; l=l->next) {
+ JSObjectRef o = JSObjectMake(_global_context, NULL, NULL);
+ if ( (ret = JSObjectCallAsFunction(_global_context, l->data, o, 0, NULL, NULL)) == NULL)
+ continue;
+ if ( (retobj = JSValueToObject(_global_context, ret, NULL)) == NULL)
+ continue;
+ if ( (init = JSObjectGetProperty(_global_context, retobj, on_init, NULL)) == NULL)
+ continue;
+ if ((initobj = JSValueToObject(_global_context, init, NULL)) != NULL && JSObjectIsFunction(_global_context, initobj)) {
+ scripts = g_slist_prepend(scripts, initobj);
+ }
+ }
+ g_slist_free(_script_list);
+ for (GSList *l = scripts; l; l=l->next) {
+ JSObjectCallAsFunction(_global_context, l->data, NULL, 0, NULL, NULL);
+ }
+ g_slist_free(scripts);
+ _script_list = NULL;
+ JSStringRelease(on_init);
+}/*}}}*/
+
+/* scripts_create_tab {{{*/
+void
+scripts_create_tab(GList *gl) {
+ static gboolean applied = false;
+ if (_global_context == NULL ) {
+ VIEW(gl)->script_wv = NULL;
+ return;
+ }
+ JSObjectRef o = make_object(_global_context, G_OBJECT(VIEW(gl)->web));
+
+ if (EMIT_SCRIPT(CREATE_TAB)) {
+ ScriptSignal signal = { o, SCRIPTS_SIG_META(NULL, CREATE_TAB, 0) };
+ scripts_emit(&signal);
+ }
+
+ JSValueProtect(_global_context, o);
+ VIEW(gl)->script_wv = o;
+ if (!applied) {
+ apply_scripts();
+ applied = true;
+ }
+}/*}}}*/
+
+/* scripts_remove_tab {{{*/
+void
+scripts_remove_tab(JSObjectRef obj) {
+ if (obj != NULL) {
+ if (EMIT_SCRIPT(CLOSE_TAB)) {
+ ScriptSignal signal = { obj, SCRIPTS_SIG_META(NULL, CLOSE_TAB, 0) };
+ scripts_emit(&signal);
+ }
+ JSValueUnprotect(_global_context, obj);
+ }
+}/*}}}*/
+
+/* scripts_init_script {{{*/
+void
+scripts_init_script(const char *script) {
+ if (_global_context == NULL)
+ create_global_object();
+ JSStringRef body = JSStringCreateWithUTF8CString(script);
+ JSValueRef exc = NULL;
+ JSObjectRef function = JSObjectMakeFunction(_global_context, NULL, 0, NULL, body, NULL, 0, &exc);
+ if (function != NULL) {
+ _script_list = g_slist_prepend(_script_list, function);
+ }
+ else {
+ print_exception(_global_context, exc);
+ }
+ JSStringRelease(body);
+}/*}}}*/
+
+/* scripts_init {{{*/
+void
+scripts_init() {
+ dwb.misc.script_signals = 0;
+ if (_global_context == NULL)
+ return;
+
+ char *dir = util_get_data_dir(LIBJS_DIR);
+ if (dir != NULL) {
+ GString *content = g_string_new(NULL);
+ util_get_directory_content(content, dir, "js");
+ if (content != NULL) {
+ JSStringRef js_script = JSStringCreateWithUTF8CString(content->str);
+ JSEvaluateScript(_global_context, js_script, NULL, NULL, 0, NULL);
+ JSStringRelease(js_script);
+ }
+ g_string_free(content, true);
+ g_free(dir);
+ }
+}/*}}}*/
+
+/* scripts_end {{{*/
+void
+scripts_end() {
+ if (_global_context != NULL) {
+ JSClassRelease(_default_class);
+ JSClassRelease(_webview_class);
+ JSClassRelease(_frame_class);
+ JSClassRelease(_download_class);
+ JSGlobalContextRelease(_global_context);
+ _global_context = NULL;
+ }
+}/*}}}*//*}}}*/
diff --git a/src/scripts.h b/src/scripts.h
new file mode 100644
index 00000000..87322bbc
--- /dev/null
+++ b/src/scripts.h
@@ -0,0 +1,75 @@
+/*
+ * Copyright (c) 2010-2012 Stefan Bolte <portix@gmx.net>
+ *
+ * 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
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#ifndef SCRIPTS_H
+#define SCRIPTS_H
+
+#include <JavaScriptCore/JavaScript.h>
+
+enum SIGNALS {
+ SCRIPTS_SIG_FIRST = 0,
+ SCRIPTS_SIG_NAVIGATION = 0,
+ SCRIPTS_SIG_LOAD_STATUS,
+ SCRIPTS_SIG_MIME_TYPE,
+ SCRIPTS_SIG_DOWNLOAD,
+ SCRIPTS_SIG_DOWNLOAD_STATUS,
+ SCRIPTS_SIG_RESOURCE,
+ SCRIPTS_SIG_KEY_PRESS,
+ SCRIPTS_SIG_KEY_RELEASE,
+ SCRIPTS_SIG_BUTTON_PRESS,
+ SCRIPTS_SIG_BUTTON_RELEASE,
+ SCRIPTS_SIG_TAB_FOCUS,
+ SCRIPTS_SIG_FRAME_STATUS,
+ SCRIPTS_SIG_LOAD_FINISHED,
+ SCRIPTS_SIG_LOAD_COMMITTED,
+ SCRIPTS_SIG_HOVERING_OVER_LINK,
+ SCRIPTS_SIG_CLOSE_TAB,
+ SCRIPTS_SIG_CREATE_TAB,
+ SCRIPTS_SIG_FRAME_CREATED,
+ SCRIPTS_SIG_LAST,
+} ;
+
+#define SCRIPT_MAX_SIG_OBJECTS 8
+
+typedef struct _ScriptSignal {
+ JSObjectRef jsobj;
+ GObject *objects[SCRIPT_MAX_SIG_OBJECTS];
+ char *json;
+ unsigned int signal;
+ int numobj;
+} ScriptSignal;
+
+gboolean scripts_emit(ScriptSignal *);
+void scripts_create_tab(GList *gl);
+void scripts_remove_tab(JSObjectRef );
+void scripts_end(void);
+void scripts_init_script(const char *);
+void scripts_init(void);
+DwbStatus scripts_eval_key(KeyMap *m, Arg *arg);
+
+#define EMIT_SCRIPT(sig) ((dwb.misc.script_signals & (1<<SCRIPTS_SIG_##sig)))
+#define SCRIPTS_EMIT_RETURN(signal, json) G_STMT_START \
+ if (scripts_emit(&signal)) { \
+ g_free(json); \
+ return true; \
+ } else g_free(json); \
+G_STMT_END
+
+#define SCRIPTS_WV(gl) .jsobj = (VIEW(gl)->script_wv)
+#define SCRIPTS_SIG_META(js, sig, num) .json = js, .signal = SCRIPTS_SIG_##sig, .numobj = num
+#endif
diff --git a/src/soup.c b/src/soup.c
index 82a3bfe3..1f919769 100644
--- a/src/soup.c
+++ b/src/soup.c
@@ -67,7 +67,16 @@ soup_get_header_from_request(WebKitNetworkRequest *request, const char *name) {
}
return NULL;
}
-
+SoupMessage *
+dwb_soup_get_message(WebKitWebFrame *frame) {
+ WebKitWebDataSource *ds = webkit_web_frame_get_data_source(frame);
+ if (ds == NULL)
+ return NULL;
+ WebKitNetworkRequest *request = webkit_web_data_source_get_request(ds);
+ if (request == NULL)
+ return NULL;
+ return webkit_network_request_get_message(request);
+}
const char *
soup_get_header(GList *gl, const char *name) {
WebKitWebFrame *frame = webkit_web_view_get_main_frame(WEBVIEW(gl));
diff --git a/src/soup.h b/src/soup.h
index a215f35e..9fb9c35d 100644
--- a/src/soup.h
+++ b/src/soup.h
@@ -24,6 +24,8 @@ void dwb_soup_sync_cookies(void);
void dwb_soup_allow_cookie_tmp(void);
DwbStatus dwb_soup_allow_cookie(GList **, const char *, CookieStorePolicy);
const char * dwb_soup_get_host_from_request(WebKitNetworkRequest *);
+SoupMessage * dwb_soup_get_message(WebKitWebFrame *);
+SoupMessage * dwb_soup_get_message_from_wv(WebKitWebView *);
DwbStatus dwb_soup_set_cookie_accept_policy(const char *);
void dwb_soup_set_ntlm(gboolean);
void dwb_soup_cookies_set_accept_policy(Arg *);
diff --git a/src/util.c b/src/util.c
index 7a0d0ea9..07f1e465 100644
--- a/src/util.c
+++ b/src/util.c
@@ -243,7 +243,7 @@ util_web_settings_sort_second(WebSettings *a, WebSettings *b) {
/*util_get_directory_content(GString **, const char *filename) {{{*/
void
-util_get_directory_content(GString **buffer, const char *dirname, const char *extension) {
+util_get_directory_content(GString *buffer, const char *dirname, const char *extension) {
GDir *dir;
char *content;
GError *error = NULL;
@@ -263,7 +263,7 @@ util_get_directory_content(GString **buffer, const char *dirname, const char *ex
}
filepath = g_build_filename(dirname, filename, NULL);
if (g_file_get_contents(filepath, &content, NULL, &error)) {
- g_string_append((*buffer), content);
+ g_string_append(buffer, content);
}
else {
fprintf(stderr, "Cannot read %s: %s\n", filename, error->message);
@@ -339,6 +339,9 @@ util_set_file_content(const char *filename, const char *content) {
char *dname = NULL;
char *realpath = NULL;
char buffer[PATH_MAX];
+ if (content == NULL || filename == NULL)
+ return false;
+
filename = util_expand_home(buffer, filename, PATH_MAX);
if (g_file_test(filename, G_FILE_TEST_IS_SYMLINK)) {
link = g_file_read_link(filename, &error);
@@ -420,6 +423,16 @@ util_get_user_data_dir(const char *dir) {
return path;
}/*}}}*/
+char *
+util_get_data_dir(const char *dir) {
+ char *path;
+ if ( (path = util_get_user_data_dir(dir)) )
+ return path;
+ if ( (path = util_get_system_data_dir(dir)) )
+ return path;
+ return NULL;
+}
+
/* util_get_data_file(const char *filename) return: filename (alloc) or NULL {{{*/
char *
@@ -706,6 +719,76 @@ util_str_chug(const char *str) {
str++;
return str;
}
+gchar *
+util_create_json(int n, ...) {
+ va_list args;
+ va_start(args, n);
+ const gchar *key, *cval;
+ gdouble dval;
+ gint ival; guint uival; gulong ulval; glong lval;
+ gboolean bval;
+ gchar *ret;
+
+ gint type;
+
+ GString *string = g_string_new("{");
+
+ for (int i=0; i<n; i++) {
+ type = va_arg(args, gint);
+ key = va_arg(args, gchar*);
+ g_string_append_printf(string, "\"%s\":", key);
+ switch (type) {
+ case CHAR :
+ cval = va_arg(args, gchar*);
+ if (cval == NULL) {
+ g_string_append(string, "null");
+ }
+ else {
+ g_string_append_c(string, '"');
+ while (*cval) {
+ if (*cval == '"')
+ g_string_append_c(string, '\\');
+ g_string_append_c(string, *cval);
+ cval++;
+ }
+ g_string_append_c(string, '"');
+ }
+ break;
+ case INTEGER :
+ ival = va_arg(args, gint);
+ g_string_append_printf(string, "%d", ival);
+ break;
+ case UINTEGER :
+ uival = va_arg(args, guint);
+ g_string_append_printf(string, "%u", uival);
+ break;
+ case LONG :
+ lval = va_arg(args, glong);
+ g_string_append_printf(string, "%ld", lval);
+ break;
+ case ULONG :
+ ulval = va_arg(args, gulong);
+ g_string_append_printf(string, "%lu", ulval);
+ break;
+ case DOUBLE :
+ dval = va_arg(args, double);
+ g_string_append_printf(string, "%f", dval);
+ break;
+ case BOOLEAN:
+ bval = va_arg(args, gboolean);
+ g_string_append_printf(string, "%s", bval ? "true" : "false");
+ break;
+ default : g_string_append(string, "null"); break;
+ }
+ if (i<n-1)
+ g_string_append_c(string, ',');
+ }
+ va_end(args);
+ g_string_append_c(string, '}');
+ ret = string->str;
+ g_string_free(string, false);
+ return ret;
+}
Sanitize
util_string_to_sanitize(const char *string) {
Sanitize s = 0;
diff --git a/src/util.h b/src/util.h
index 18a8a864..4e8bc398 100644
--- a/src/util.h
+++ b/src/util.h
@@ -49,7 +49,7 @@ int util_web_settings_sort_first(WebSettings *, WebSettings *);
// files
char * util_expand_home(char *buffer, const char *filename, size_t length);
-void util_get_directory_content(GString **, const char *, const char *extension);
+void util_get_directory_content(GString *, const char *, const char *extension);
char * util_get_file_content(const char *);
char ** util_get_lines(const char *);
gboolean util_set_file_content(const char *, const char *);
@@ -57,6 +57,7 @@ char * util_build_path(void);
char * util_get_system_data_dir(const char *);
char * util_get_user_data_dir(const char *);
char * util_get_data_file(const char *, const char *);
+char * util_get_data_dir(const char *dir);
// navigation
Navigation * dwb_navigation_new_from_line(const char *);
@@ -96,4 +97,6 @@ int util_strlen_trailing_space(const char *str);
const char * util_str_chug(const char *str);
Sanitize util_string_to_sanitize(const char *);
+char *util_create_json(int, ...);
+
#endif
diff --git a/src/view.c b/src/view.c
index 225714eb..abfd0fae 100644
--- a/src/view.c
+++ b/src/view.c
@@ -31,6 +31,7 @@
#include "soup.h"
#include "adblock.h"
#include "js.h"
+#include "scripts.h"
static void view_ssl_state(GList *);
static unsigned long _click_time;
@@ -71,10 +72,16 @@ view_main_frame_committed_cb(WebKitWebFrame *frame, GList *gl) {
// dwb_change_mode(NORMAL_MODE, true);
// }
}/*}}}*/
+#endif
+
static void
view_resource_request_cb(WebKitWebView *wv, WebKitWebFrame *frame, WebKitWebResource *resource, WebKitNetworkRequest *request, WebKitNetworkResponse *response, GList *gl) {
+ if (EMIT_SCRIPT(RESOURCE)) {
+ ScriptSignal signal = {
+ SCRIPTS_WV(gl), .objects = { G_OBJECT(frame), G_OBJECT(request), G_OBJECT(response) }, SCRIPTS_SIG_META(NULL, RESOURCE, 3) };
+ scripts_emit(&signal);
+ }
}
-#endif
/* view_button_press_cb(WebKitWebView *web, GdkEventButton *button, GList *gl) {{{*/
static void
@@ -122,6 +129,15 @@ view_button_press_cb(WebKitWebView *web, GdkEventButton *e, GList *gl) {
g_object_get(result, "context", &context, NULL);
gboolean ret = false;
_click_time = e->time;
+ if (EMIT_SCRIPT(BUTTON_PRESS)) {
+ char *json = util_create_json(8,
+ UINTEGER, "time", e->time, UINTEGER, "type", e->type,
+ DOUBLE, "x", e->x, DOUBLE, "y", e->y,
+ UINTEGER, "state", e->state, UINTEGER, "button", e->button,
+ DOUBLE, "xRoot", e->x_root, DOUBLE, "yRoot", e->y_root);
+ ScriptSignal signal = { SCRIPTS_WV(gl), { G_OBJECT(result) }, SCRIPTS_SIG_META(json, BUTTON_PRESS, 1) };
+ SCRIPTS_EMIT_RETURN(signal, json);
+ }
if (gtk_widget_has_focus(dwb.gui.entry)) {
dwb_focus_scroll(gl);
@@ -179,6 +195,17 @@ view_button_release_cb(WebKitWebView *web, GdkEventButton *e, GList *gl) {
WebKitHitTestResult *result = webkit_web_view_get_hit_test_result(web, e);
g_object_get(result, "context", &context, NULL);
+
+ if (EMIT_SCRIPT(BUTTON_RELEASE)) {
+ char *json = util_create_json(7,
+ UINTEGER, "time", e->time,
+ DOUBLE, "x", e->x, DOUBLE, "y", e->y,
+ UINTEGER, "state", e->state, UINTEGER, "button", e->button,
+ DOUBLE, "xRoot", e->x_root, DOUBLE, "yRoot", e->y_root);
+ ScriptSignal signal = { SCRIPTS_WV(gl), { G_OBJECT(result) }, SCRIPTS_SIG_META(json, BUTTON_RELEASE, 1) };
+ SCRIPTS_EMIT_RETURN(signal, json);
+ }
+
if (context & WEBKIT_HIT_TEST_RESULT_CONTEXT_LINK) {
if (e->button == 2 || (e->time - _click_time < 200 && (e->button == 1 && e->state & GDK_CONTROL_MASK))) {
g_object_get(result, "link-uri", &uri, NULL);
@@ -200,22 +227,22 @@ view_close_web_view_cb(WebKitWebView *web, GList *gl) {
/* view_frame_committed_cb {{{*/
static void
view_frame_committed_cb(WebKitWebFrame *frame, GList *gl) {
- WebKitLoadStatus status = webkit_web_frame_get_load_status(frame);
- switch (status) {
- case WEBKIT_LOAD_COMMITTED:
- dwb_execute_script(frame, dwb.misc.allscripts, false);
- break;
- case WEBKIT_LOAD_FINISHED:
- dwb_execute_script(frame, dwb.misc.allscripts_onload, false);
- break;
- default: return;
+ if (EMIT_SCRIPT(FRAME_STATUS)) {
+ ScriptSignal signal = { SCRIPTS_WV(gl),
+ .objects = { G_OBJECT(frame) }, SCRIPTS_SIG_META(NULL, FRAME_STATUS, 1) };
+ scripts_emit(&signal);
}
}/*}}}*/
/* view_frame_created_cb {{{*/
static void
view_frame_created_cb(WebKitWebView *wv, WebKitWebFrame *frame, GList *gl) {
+ if (EMIT_SCRIPT(FRAME_CREATED)) {
+ ScriptSignal signal = { SCRIPTS_WV(gl), .objects = { G_OBJECT(frame) }, SCRIPTS_SIG_META(NULL, FRAME_CREATED, 1) };
+ scripts_emit(&signal);
+ }
g_signal_connect(frame, "notify::load-status", G_CALLBACK(view_frame_committed_cb), gl);
+ VIEW(gl)->status->frames = g_slist_prepend(VIEW(gl)->status->frames, frame);
}/*}}}*/
/* view_console_message_cb(WebKitWebView *web, char *message, int line, char *sourceid, GList *gl) {{{*/
@@ -240,6 +267,13 @@ view_create_web_view_cb(WebKitWebView *web, WebKitWebFrame *frame, GList *gl) {
/* view_download_requested_cb(WebKitWebView *, WebKitDownload *, GList *) {{{*/
static gboolean
view_download_requested_cb(WebKitWebView *web, WebKitDownload *download, GList *gl) {
+ if (EMIT_SCRIPT(DOWNLOAD)) {
+ char *json = util_create_json(2,
+ CHAR, "referer", soup_get_header_from_request(webkit_download_get_network_request(download), "Referer"),
+ CHAR, "mimeType", dwb.state.mimetype_request);
+ ScriptSignal signal = { SCRIPTS_WV(gl), .objects = { G_OBJECT(download) }, SCRIPTS_SIG_META(json, DOWNLOAD, 1) };
+ SCRIPTS_EMIT_RETURN(signal, json);
+ }
download_get_path(gl, download);
return true;
}/*}}}*/
@@ -278,6 +312,12 @@ view_inspect_web_view_cb(WebKitWebInspector *inspector, WebKitWebView *wv, GList
/* view_hovering_over_link_cb(WebKitWebView *, char *title, char *uri, GList *) {{{*/
static void
view_hovering_over_link_cb(WebKitWebView *web, char *title, char *uri, GList *gl) {
+ if (EMIT_SCRIPT(HOVERING_OVER_LINK)) {
+ char *json = util_create_json(2, CHAR, "uri", uri, CHAR, "title", title);
+ ScriptSignal signal = { SCRIPTS_WV(gl), SCRIPTS_SIG_META(json, HOVERING_OVER_LINK, 0) };
+ scripts_emit(&signal);
+ g_free(json);
+ }
if (uri) {
VIEW(gl)->status->hover_uri = g_strdup(uri);
dwb_set_status_bar_text(dwb.gui.urilabel, uri, &dwb.color.active_fg, NULL, false);
@@ -305,6 +345,17 @@ view_mime_type_policy_cb(WebKitWebView *web, WebKitWebFrame *frame, WebKitNetwor
if ( !mimetype || strlen(mimetype) == 0 )
return false;
+ if (EMIT_SCRIPT(MIME_TYPE)) {
+ char *json = util_create_json(1, CHAR, "mimeType", mimetype);
+ ScriptSignal signal = { SCRIPTS_WV(gl), { G_OBJECT(frame), G_OBJECT(request) }, SCRIPTS_SIG_META(json, MIME_TYPE, 2) };
+ if (scripts_emit(&signal)) {
+ webkit_web_policy_decision_ignore(policy);
+ g_free(json);
+ return true;
+ }
+ g_free(json);
+ }
+
if (!webkit_web_view_can_show_mime_type(web, mimetype) || dwb.state.nv & OPEN_DOWNLOAD) {
dwb.state.mimetype_request = g_strdup(mimetype);
webkit_web_policy_decision_download(policy);
@@ -313,6 +364,8 @@ view_mime_type_policy_cb(WebKitWebView *web, WebKitWebFrame *frame, WebKitNetwor
return false;
}/*}}}*/
+
+
/* view_navigation_policy_cb {{{*/
static gboolean
view_navigation_policy_cb(WebKitWebView *web, WebKitWebFrame *frame, WebKitNetworkRequest *request, WebKitWebNavigationAction *action,
@@ -322,6 +375,14 @@ view_navigation_policy_cb(WebKitWebView *web, WebKitWebFrame *frame, WebKitNetwo
gboolean ret = false;
WebKitWebNavigationReason reason = webkit_web_navigation_action_get_reason(action);
+ if (EMIT_SCRIPT(NAVIGATION)) {
+ ScriptSignal signal = { SCRIPTS_WV(gl), { G_OBJECT(frame), G_OBJECT(request), G_OBJECT(action) }, SCRIPTS_SIG_META(NULL, NAVIGATION, 3) };
+ if (scripts_emit(&signal)) {
+ webkit_web_policy_decision_ignore(policy);
+ return true;
+ }
+ }
+
if (!g_str_has_prefix(uri, "http:") && !g_str_has_prefix(uri, "https:") &&
!g_str_has_prefix(uri, "about:") && !g_str_has_prefix(uri, "dwb:") &&
!g_str_has_prefix(uri, "file:")) {
@@ -539,9 +600,13 @@ view_load_status_cb(WebKitWebView *web, GParamSpec *pspec, GList *gl) {
char *host = NULL;
const char *uri = webkit_web_view_get_uri(web);
+
switch (status) {
case WEBKIT_LOAD_PROVISIONAL:
dwb_clean_load_begin(gl);
+ g_slist_free(v->status->frames);
+ v->status->frames = NULL;
+ v->status->frames = g_slist_prepend(v->status->frames, webkit_web_view_get_main_frame(WEBVIEW(gl)));
break;
case WEBKIT_LOAD_FIRST_VISUALLY_NON_EMPTY_LAYOUT:
/* This is more or less a dummy call, to compile the script and speed up
@@ -571,6 +636,10 @@ view_load_status_cb(WebKitWebView *web, GParamSpec *pspec, GList *gl) {
)) {
plugins_disconnect(gl);
}
+ if (EMIT_SCRIPT(LOAD_COMMITTED)) {
+ ScriptSignal signal = { SCRIPTS_WV(gl), SCRIPTS_SIG_META(NULL, LOAD_COMMITTED, 0) };
+ scripts_emit(&signal);
+ }
view_ssl_state(gl);
g_free(host);
break;
@@ -587,12 +656,20 @@ view_load_status_cb(WebKitWebView *web, GParamSpec *pspec, GList *gl) {
dwb_execute_script(webkit_web_view_get_main_frame(web), dwb.misc.scripts_onload, false);
if (dwb.state.auto_insert_mode)
dwb_check_auto_insert(gl);
+ if (EMIT_SCRIPT(LOAD_FINISHED)) {
+ ScriptSignal signal = { SCRIPTS_WV(gl), SCRIPTS_SIG_META(NULL, LOAD_FINISHED, 0) };
+ scripts_emit(&signal);
+ }
break;
case WEBKIT_LOAD_FAILED:
break;
default:
break;
}
+ if (EMIT_SCRIPT(LOAD_STATUS)) {
+ ScriptSignal signal = { SCRIPTS_WV(gl), SCRIPTS_SIG_META(NULL, LOAD_STATUS, 0) };
+ scripts_emit(&signal);
+ }
}/*}}}*/
/* view_load_error_cb {{{*/
@@ -729,7 +806,7 @@ view_init_signals(GList *gl) {
v->status->signals[SIG_MIME_TYPE] = g_signal_connect(v->web, "mime-type-policy-decision-requested", G_CALLBACK(view_mime_type_policy_cb), gl);
v->status->signals[SIG_NAVIGATION] = g_signal_connect(v->web, "navigation-policy-decision-requested", G_CALLBACK(view_navigation_policy_cb), gl);
v->status->signals[SIG_NEW_WINDOW] = g_signal_connect(v->web, "new-window-policy-decision-requested", G_CALLBACK(view_new_window_policy_cb), gl);
- //v->status->signals[SIG_RESOURCE_REQUEST] = g_signal_connect(v->web, "resource-request-starting", G_CALLBACK(view_resource_request_cb), gl);
+ v->status->signals[SIG_RESOURCE_REQUEST] = g_signal_connect(v->web, "resource-request-starting", G_CALLBACK(view_resource_request_cb), gl);
v->status->signals[SIG_CREATE_PLUGIN_WIDGET] = g_signal_connect(v->web, "create-plugin-widget", G_CALLBACK(view_create_plugin_widget_cb), gl);
v->status->signals[SIG_FRAME_CREATED] = g_signal_connect(v->web, "frame-created", G_CALLBACK(view_frame_created_cb), gl);
@@ -769,6 +846,7 @@ view_create_web_view() {
status->allowed_plugins = NULL;
status->style = NULL;
status->lockprotect = 0;
+ status->frames = NULL;
v->hint_object = NULL;
v->plugins = plugins_new();
@@ -814,6 +892,7 @@ view_create_web_view() {
gtk_container_add(GTK_CONTAINER(v->tabevent), v->tabbox);
+
/* gtk_container_add(GTK_CONTAINER(v->tabevent), v->tablabel); */
DWB_WIDGET_OVERRIDE_FONT(v->tablabel, dwb.font.fd_inactive);
@@ -940,6 +1019,8 @@ view_remove(GList *gl) {
dwb_source_remove();
plugins_free(v->plugins);
+ scripts_remove_tab(v->script_wv);
+
if (v->status->style) {
g_object_unref(v->status->style);
}
@@ -973,10 +1054,7 @@ view_ssl_state(GList *gl) {
const char *uri = webkit_web_view_get_uri(WEBKIT_WEB_VIEW(v->web));
if (uri && g_str_has_prefix(uri, "https")) {
- WebKitWebFrame *frame = webkit_web_view_get_main_frame(WEBKIT_WEB_VIEW(v->web));
- WebKitWebDataSource *ds = webkit_web_frame_get_data_source(frame);
- WebKitNetworkRequest *request = webkit_web_data_source_get_request(ds);
- SoupMessage *msg = webkit_network_request_get_message(request);
+ SoupMessage *msg = dwb_soup_get_message(MAIN_FRAME_CAST(v->web));
if (msg) {
ssl = soup_message_get_flags(msg) & SOUP_MESSAGE_CERTIFICATE_TRUSTED
? SSL_TRUSTED
@@ -1033,6 +1111,7 @@ view_add(const char *uri, gboolean background) {
dwb_focus(ret);
}
+ scripts_create_tab(ret);
view_init_signals(ret);
view_init_settings(ret);
if (GET_BOOL("adblocker"))