summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDaniel Carl <danielcarl@gmx.de>2015-09-19 20:47:37 +0200
committerDaniel Carl <danielcarl@gmx.de>2016-03-30 23:32:23 +0200
commit6608f8fc19ef4b587596c9ed3cb3b3fcc37c1eb6 (patch)
tree12f055b9e671cb41ea8097add3e3833890a65fe8
parente3ea1d3081cc7dbe86f95ee0888660c292c355eb (diff)
Startup webkit2 branch from the scratch.
-rw-r--r--.gitignore10
-rw-r--r--CHANGELOG.md8
-rw-r--r--Makefile54
-rw-r--r--README.md200
-rw-r--r--config.mk88
-rw-r--r--doc/vimb.11617
-rwxr-xr-xexamples/formfiller/formfiller78
-rw-r--r--examples/formfiller/scripts.js50
-rw-r--r--src/.gitignore2
-rw-r--r--src/Makefile58
-rw-r--r--src/arh.c199
-rw-r--r--src/ascii.h7
-rw-r--r--src/autocmd.c488
-rw-r--r--src/autocmd.h50
-rw-r--r--src/bookmark.c326
-rw-r--r--src/bookmark.h34
-rw-r--r--src/command.c180
-rw-r--r--src/command.h11
-rw-r--r--src/completion.c217
-rw-r--r--src/completion.h16
-rw-r--r--src/config.def.h102
-rw-r--r--src/cookiejar.c105
-rw-r--r--src/cookiejar.h43
-rw-r--r--src/dom.c330
-rw-r--r--src/dom.h46
-rw-r--r--src/ex.c632
-rw-r--r--src/ex.h11
-rw-r--r--src/ext-proxy.c214
-rw-r--r--src/ext-proxy.h (renamed from src/arh.h)17
-rw-r--r--src/handlers.c96
-rw-r--r--src/hints.c398
-rw-r--r--src/hints.js611
-rw-r--r--src/hints.js.h1
-rw-r--r--src/history.c172
-rw-r--r--src/history.h6
-rw-r--r--src/hsts.c458
-rw-r--r--src/hsts.h52
-rw-r--r--src/input.c138
-rw-r--r--src/input.h8
-rw-r--r--src/io.c170
-rw-r--r--src/js.c179
-rw-r--r--src/js.h14
-rwxr-xr-xsrc/js2h.sh15
-rw-r--r--src/main.c2314
-rw-r--r--src/main.h477
-rw-r--r--src/map.c610
-rw-r--r--src/map.h14
-rw-r--r--src/normal.c489
-rw-r--r--src/normal.h12
-rw-r--r--src/scripts/.gitignore1
-rw-r--r--src/scripts/Makefile19
-rw-r--r--src/scripts/increment_uri_number.js16
-rwxr-xr-xsrc/scripts/js2h.sh38
-rw-r--r--src/setting.c793
-rw-r--r--src/setting.h10
-rw-r--r--src/shortcut.c56
-rw-r--r--src/shortcut.h15
-rw-r--r--src/util.c758
-rw-r--r--src/util.h35
-rw-r--r--src/webextension/Makefile19
-rw-r--r--src/webextension/ext-dom.c179
-rw-r--r--src/webextension/ext-dom.h (renamed from src/handlers.h)18
-rw-r--r--src/webextension/ext-main.c360
-rw-r--r--src/webextension/ext-main.h (renamed from src/hints.h)20
-rw-r--r--src/webextension/ext-util.c60
-rw-r--r--src/webextension/ext-util.h (renamed from src/io.h)13
-rw-r--r--tests/Makefile19
-rw-r--r--tests/manual/112-editable-focus.html39
-rw-r--r--tests/manual/146-hsts-iframe.html14
-rw-r--r--tests/manual/201-editable-focus-in-iframes.html9
-rw-r--r--tests/test-handlers.c80
-rw-r--r--tests/test-map.c176
-rw-r--r--tests/test-shortcut.c142
-rw-r--r--tests/test-util.c285
74 files changed, 3752 insertions, 10849 deletions
diff --git a/.gitignore b/.gitignore
index 00a41de..711ddb0 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,11 +1,5 @@
*.[oad]
*.lo
+*.so
*.tar.gz
-src/hints.js.h
-src/config.h
-src/vimb
-src/libvimb.so
-tests/*
-!tests/Makefile
-!tests/*.c
-!tests/manual/
+sandbox
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 77da6f6..9fb2ea4 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,5 +1,12 @@
# Changes in vimb
+## [unreleased]
+
+### Removed
+
+* `FEATURE_COOKIE` precompiler flag was removed bcause compiling without cookie
+ support does not bring any real benefit
+
## [2.11] - 2015-12-17
### Added
@@ -37,4 +44,5 @@
cookie file
* Fixed none POSIX `echo -n` call
+[unreleased]: https://github.com/fanglingsu/vimb/compare/2.11...HEAD
[2.11]: https://github.com/fanglingsu/vimb/compare/2.10...2.11
diff --git a/Makefile b/Makefile
index e21743e..b7abcfd 100644
--- a/Makefile
+++ b/Makefile
@@ -1,49 +1,39 @@
include config.mk
-SRCDIR=src
-DOCDIR=doc
+all: vimb
-all: $(TARGET)
options:
- @echo "$(PROJECT) build options:"
+ @echo "vimb build options:"
@echo "LIBS = $(LIBS)"
@echo "CFLAGS = $(CFLAGS)"
@echo "LDFLAGS = $(LDFLAGS)"
@echo "CC = $(CC)"
-test: $(LIBTARGET)
- @$(MAKE) $(MFLAGS) -s -C tests
+install: vimb
+ @# binary
+ install -d $(BINPREFIX)
+ install -m 755 $(SRCDIR)/vimb $(BINPREFIX)/vimb
+ @# extension
+ install -d $(EXTPREFIX)
+ install -m 644 $(SRCDIR)/webextension/$(EXTTARGET) $(EXTPREFIX)/$(EXTTARGET)
-clean:
- @$(MAKE) $(MFLAGS) -C src clean
- @$(MAKE) $(MFLAGS) -C tests clean
+uninstall:
+ $(RM) $(BINPREFIX)/vimb $(EXTPREFIX)/$(EXTTARGET)
-install: $(TARGET) $(DOCDIR)/$(MAN1)
- install -d $(DESTDIR)$(BINDIR)
- install -m 755 $(SRCDIR)/$(TARGET) $(DESTDIR)$(BINDIR)/$(TARGET)
- install -d $(DESTDIR)$(EXAMPLEDIR)
- cp -r examples/* $(DESTDIR)$(EXAMPLEDIR)
- install -d $(DESTDIR)$(MANDIR)/man1
- @sed -e "s!VERSION!$(VERSION)!g" \
- -e "s!PREFIX!$(PREFIX)!g" \
- -e "s!DATE!`date +'%m %Y'`!g" $(DOCDIR)/$(MAN1) > $(DESTDIR)$(MANDIR)/man1/$(MAN1)
+vimb: $(SUBDIRS:%=%.subdir-all)
-uninstall:
- $(RM) $(DESTDIR)$(BINDIR)/$(TARGET)
- $(RM) $(DESTDIR)$(MANDIR)/man1/$(MAN1)
- $(RM) -r $(DESTDIR)$(EXAMPLEDIR)
+%.subdir-all:
+ $(MAKE) $(MFLAGS) -C $*
-dist: dist-clean
- @echo "Creating tarball."
- @git archive --format tar -o $(DIST_FILE) HEAD
+%.subdir-clean:
+ $(MAKE) $(MFLAGS) -C $* clean
-dist-clean:
- $(RM) $(DIST_FILE)
+clean: $(SUBDIRS:%=%.subdir-clean)
-$(TARGET):
- @$(MAKE) $(MFLAGS) -C src $(TARGET)
+runsandbox: sandbox
+ sandbox/usr/bin/vimb
-$(LIBTARGET):
- @$(MAKE) $(MFLAGS) -C src $(LIBTARGET)
+sandbox:
+ make RUNPREFIX=$(CURDIR)/sandbox/usr PREFIX=/usr DESTDIR=./sandbox install
-.PHONY: clean all install uninstall options dist dist-clean test
+.PHONY: all options clean install uninstall sandbox
diff --git a/README.md b/README.md
index 0944100..b2e0331 100644
--- a/README.md
+++ b/README.md
@@ -1,89 +1,111 @@
-# Vimb - the Vim-like browser
-
-Vimb is a Vim-like web browser that is inspired by Pentadactyl and Vimprobable.
-The goal of Vimb is to build a completely keyboard-driven, efficient and
-pleasurable browsing-experience with low memory and CPU usage that is
-intuitive to use for Vim users.
-
-More information and some screenshots of Vimb browser in action can be found on
-the project page of [Vimb][].
-
-## Features
-
-- it's modal like Vim
-- Vim like [keybindings][] - assignable for each browser mode
-- nearly every configuration can be changed at runtime with Vim like [set syntax][set]
-- [history][] for `ex` commands, search queries, URLs
-- completions for: commands, URLs, bookmarked URLs, variable names of settings, search-queries
-- [hinting][hints] - marks links, form fields and other clickable elements to
- be clicked, opened or inspected
-- SSL validation against ca-certificate file
-- HTTP Strict Transport Security (HSTS)
-- open input or textarea with configurable external editor
-- user defined URL-shortcuts with placeholders
-- custom [protocol handlers][handlers]
-- read it later [queue][] to collect URIs for later use
-- multiple yank/paste [registers][]
-- Vim like [autocmd][]
-
-## Packages
-
-- Arch Linux [vimb-git][arch-git], [vimb][arch]
-- [NetBSD][]
-- [FreeBSD][]
-- [Void Linux][]
-
-## Dependencies
-
-- libwebkit >=1.5.0
-- libgtk+-2.0
-- libsoup >=2.38
-
-On Ubuntu these dependencies can be installed by
-`sudo apt-get install libsoup2.4-dev libwebkit-dev libgtk-3-dev libwebkitgtk-3.0-dev`.
-
-## Install
-
-Edit `config.mk` to match your local setup.
-
-Edit src/config.h to match your personal preferences.
-Edit `src/config.h` to match your personal preferences.
-
-The default `Makefile` will not overwrite your customised `config.h` with the
-contents of `config.def.h`, even if it was updated in the latest git pull.
-Therefore, you should always compare your customised `config.h` with
-`config.def.h` and make sure you include any changes to the latter in your
-`config.h`.
-
-Run the following commands to compile and install Vimb (if necessary, the last one as
-root).
-
- make clean
- make // or make GTK=3 to compile against gtk3
- make install
-
-To build Vimb against GTK3 you can use `make GTK=3`.
-
-# License
-
-Information about the license is found in the file: LICENSE.
-
-# Mailing list
-
-- feature requests, issues and patches can be discussed on the [mailing list][mail]
-
-[vimb]: http://fanglingsu.github.io/vimb/ "Vimb - Vim like browser project page"
-[keybindings]: http://fanglingsu.github.io/vimb/keybindings.html "vimb keybindings"
-[hints]: http://fanglingsu.github.io/vimb/keybindings.html#hinting "vimb hinting"
-[queue]: http://fanglingsu.github.io/vimb/commands.html#queue "vimb read it later queue feature"
-[history]: http://fanglingsu.github.io/vimb/keybindings.html#history "vimb keybindings to access history"
-[handlers]: http://fanglingsu.github.io/vimb/commands.html#handlers "vimb custom protocol handlers"
-[registers]: http://fanglingsu.github.io/vimb/keybindings.html#registers "vimb yank/paste registers"
-[mail]: https://lists.sourceforge.net/lists/listinfo/vimb-users "vimb - mailing list"
-[NetBSD]: http://pkgsrc.se/wip/vimb "vimb - NetBSD package"
-[autocmd]: http://fanglingsu.github.io/vimb/commands.html#autocmd "Vim like autocmd and augroup feature"
-[set]: http://fanglingsu.github.io/vimb/commands.html#settings "Vim like set syntax"
-[Arch-git]: https://aur.archlinux.org/packages/vimb-git/ "vimb - archlinux package"
-[Arch]: https://aur.archlinux.org/packages/vimb/ "vimb - archlinux package"
-[FreeBSD]: http://www.freshports.org/www/vimb/ "vimb - FreeBSD port"
-[Void Linux]: https://github.com/voidlinux/void-packages/blob/master/srcpkgs/vimb/template "vimb - Void Linux package"
+# vimb - the vim like browser
+
+This is the development branch for the new webkit2 port of vimb. This branch
+does not work and lags a lot of features of the webkit1 version of vimb. So
+this is only meant to be the playground for the developers at the moment.
+
+If you like to have a working vimb, please use the master branch.
+
+## Patching and Coding style
+
+- the code is indented by 4 spaces - if you use vim to code you can set
+ `:set expandtab ts=4 sts=4 sw=4`
+- the functions are sorted alphabetically within the c files
+- it's a good advice to orientate on the already available code
+- if you are using `indent`, following options describe best the code style
+ - `--k-and-r-style`
+ - `--case-indentation4`
+ - `--dont-break-function-decl-args`
+ - `--dont-break-procedure-type`
+ - `--dont-line-up-parentheses`
+ - `--no-tabs`
+
+## directories
+
+ ├── doc documentation like manual page
+ └── src all sources to build vimb
+ ├── scripts JavaScripts that are compiled in to various purposes
+ └── webextension Source files for the webextension
+
+## dependencies
+
+- webkit2gtk-4.0 >= 2.3.5
+
+## compile and run
+
+To inform vimb during compile time where the webextension should be loaded
+from, the `RUNPREFIX` option can be set to a full qualified path to the
+directory where the extension should be sotred in.
+
+To run vimb wihtout installation you could run as a sandbox like this
+
+ make runsandbox
+
+This will compile and install vimb into the local _sandbox_ folder in the
+project directory.
+
+## Tasks
+
+1. general infrastructure and built
+ - [x] write make file
+ - [x] allow to built as sandbox for local testing
+ - [x] add a way to specify the target of the webextension shared objects
+ this is now available with the `RUNPREFIX` oprion for the make
+ - [x] establish communication channel between the vimb instance and the now
+ required webextension (dbus)
+2. migrate as many of the features of the webkit1 vimb
+ - [ ] starting with custom config file `--config,-c` option
+ - [ ] running multiple ex-commands during startup `--cmd,-C` options
+ - [ ] starting with a named profile `--profile,-p` option
+ - [ ] xembed `--embed,-e` option
+ - [ ] socket support `--socket,-s` and `--dump,-d` option to print the actual
+ used socket path to stdout
+ - [ ] kiosk-mode `--kiosk,-k`
+ - [ ] allow to start vimb reading html from `stdin` by `vimb -`
+ - [ ] browser modes normal, input, command, pass-through and hintmode
+ - [ ] download support
+ - [ ] editor command
+ - [ ] external downloader
+ - [ ] hinting
+ - [ ] searching and matching of search results
+ - [ ] navigation j, k, h, l, ...
+ - [ ] history and history lookup
+ - [ ] completion
+ - [ ] HSTS
+ - [ ] auto-response-header
+ - [ ] cookies support
+ - [ ] register support and `:register` command
+ - [ ] read it later queue
+ - [ ] show scroll indicator in statusbar as top, x%, bttom or all
+ how can we get this information from webview easily?
+ - [ ] find a way to disable the scrollbars on the main frame
+ - [ ] page marks - maybe we change make them global (shared between
+ instances and to work also if the page was reloaded or changed like
+ the marks in vim)
+ - [x] zooming
+ - [ ] yanking
+ - [x] keymapping
+ - [ ] URL handler
+ - [x] shortcuts
+ - [ ] autocommands and augroups
+3. documentation
+4. testing
+ - [ ] write automatic test to the essential main features
+ - [ ] adapt the manual test cases and add some more to avoid regressions
+ before a release
+ - [ ] write new test cases for essential things like mode switching of vimb
+ when clicking form fields or tabbing over them.
+5. new features and changed behaviour
+ - [ ] try to use the webkit2 feature of running multiple pages with related
+ view instance `webkit_web_view_new_with_related_view`
+ - [ ] allow setting of different scopes, global and instance (new feature)
+ - [ ] remove the settings related to the gui like `status-color-bg` this was
+ only a hack and is not recommended for new gtk3 applications. the
+ color and font settings should be setup by css instead.
+ - [ ] webkit2 does not provide the view mode `source` so maybe this is going
+ to be removed together with the `gf` keybinding or we find a simple
+ workaround for this
+
+# license
+
+Information about the license are found in the file LICENSE.
diff --git a/config.mk b/config.mk
index 3809336..e3f1800 100644
--- a/config.mk
+++ b/config.mk
@@ -1,63 +1,37 @@
-#----------------user/install options----------------
-VERSION = 2.11
-
-PROJECT = vimb
-PREFIX ?= /usr/local
-BINDIR ?= $(PREFIX)/bin
-MANDIR ?= $(PREFIX)/share/man
-EXAMPLEDIR ?= $(PREFIX)/share/$(PROJECT)/examples
-
-#----------------compile options---------------------
-
-VERBOSE ?= 0
-
-LIBS = libsoup-2.4
-
-GTK3LIBS=gtk+-3.0 webkitgtk-3.0
-GTK2LIBS=gtk+-2.0 webkit-1.0
-
-ifeq (${GTK}, 3)
-ifeq ($(shell pkg-config --exists $(GTK3LIBS) && echo 1), 1) #has gtk3 libs
-LIBS += $(GTK3LIBS)
-USEGTK3 = 1
-else
-LIBS += $(GTK2LIBS)
-$(warning Cannot find gtk3-libs, falling back to gtk2)
-endif
-else
-LIBS += $(GTK2LIBS)
-endif
-
-# generate a first char upper case project name
-PROJECT_UCFIRST = $(shell echo '${PROJECT}' | awk '{for(i=1;i<=NF;i++){$$i=toupper(substr($$i,1,1))substr($$i,2)}}1')
-
-CPPFLAGS = -DVERSION=\"${VERSION}\"
-CPPFLAGS += -DPROJECT=\"${PROJECT}\" -DPROJECT_UCFIRST=\"${PROJECT_UCFIRST}\"
+VERSION = dev-3.0
+
+PREFIX ?= /usr/local
+BINPREFIX := $(DESTDIR)$(PREFIX)/bin
+MANPREFIX := $(DESTDIR)$(PREFIX)/share/man
+EXAMPLEPREFIX := $(DESTDIR)$(PREFIX)/share/vimb/example
+RUNPREFIX := $(PREFIX)
+EXTPREFIX := $(RUNPREFIX)/lib/vimb
+
+# define some directories
+SRCDIR = src
+DOCDIR = doc
+SUBDIRS = $(SRCDIR)/scripts $(SRCDIR)/webextension $(SRCDIR)
+
+# used libs
+LIBS = gtk+-3.0 webkit2gtk-4.0
+
+# setup general used CFLAGS
+CFLAGS += -std=c99 -pipe -Wall
+#CPPFLAGS += -pedantic
+CPPFLAGS += -DVERSION=\"${VERSION}\" -DEXTPREFIX=\"${EXTPREFIX}\"
+CPPFLAGS += -DPROJECT=\"vimb\" -DPROJECT_UCFIRST=\"Vimb\"
CPPFLAGS += -D_XOPEN_SOURCE=500
-CPPFLAGS += -D_POSIX_SOURCE
-ifeq ($(USEGTK3), 1)
-CPPFLAGS += -DHAS_GTK3
CPPFLAGS += -DGSEAL_ENABLE
CPPFLAGS += -DGTK_DISABLE_SINGLE_INCLUDES
-CPPFLAGS += -DGTK_DISABLE_DEPRECATED
CPPFLAGS += -DGDK_DISABLE_DEPRECATED
-endif
-
-# prepare the lib flags used for the linker
-LIBFLAGS = $(shell pkg-config --libs $(LIBS))
-
-# some compiler flags in case CFLAGS is not set by user
-# -Wno-typedef-redefinition to avoid redifinition warnings caused by glib
-CFLAGS ?= -Wall -pipe -Wno-overlength-strings -Werror=format-security -Wno-typedef-redefinition
-# normal compiler flags
-CFLAGS += $(shell pkg-config --cflags $(LIBS))
-CFLAGS += -std=c99
-CFLAGS += ${CPPFLAGS}
-LDFLAGS += ${LIBFLAGS}
-TARGET = $(PROJECT)
-LIBTARGET = lib$(PROJECT).so
-DIST_FILE = $(PROJECT)_$(VERSION).tar.gz
-MAN1 = $(PROJECT).1
+# flags used to build webextension
+EXTTARGET = webext_main.so
+EXTCFLAGS = ${CFLAGS} -fPIC $(shell pkg-config --cflags webkit2gtk-4.0)
+EXTCFLAGS += $(CPPFLAGS)
+EXTLDFLAGS = $(shell pkg-config --libs webkit2gtk-4.0) -shared
-MFLAGS ?= --no-print-directory
+# flags used for the main application
+CFLAGS += $(shell pkg-config --cflags $(LIBS))
+CFLAGS += ${CPPFLAGS}
+LDFLAGS += $(shell pkg-config --libs $(LIBS))
diff --git a/doc/vimb.1 b/doc/vimb.1
deleted file mode 100644
index 7c0e2ea..0000000
--- a/doc/vimb.1
+++ /dev/null
@@ -1,1617 +0,0 @@
-.\" vim: ft=groff
-.ad l
-.TH VIMB 1 "DATE" "vimb/VERSION" "Vimb Manual"
-.de EX
-.nf
-.ft CW
-..
-.de EE
-.ft R
-.fi
-..
-.SH NAME
-Vimb - Vim Browser - A modal web browser based on WebKit, inspired by Vim: the
-great editor.
-.SH SYNOPSIS
-.B vimb
-.OP OPTIONS
-.RI [ URI "|" file "|" - ]
-.SH DESCRIPTION
-Vimb is a WebKit based web browser that behaves like the Vimperator
-plugin for Firefox and has usage paradigms from the great editor, Vim.
-The goal of Vimb is to build a completely keyboard-driven, efficient
-and pleasurable browsing-experience.
-.SH OPTIONS
-If no \fIURI\fP or \fIfile\fP is given, Vimb will open the configured
-home-page.
-If \fIURI\fP is '-', Vimb reads the HTML to display from stdin.
-.PP
-Mandatory arguments to long options are mandatory for short options too.
-.TP
-.BI "\-C, \-\-cmd " "CMD"
-Run \fICMD\fP as ex command line right before the first page is loaded.
-If the flag is used more than one time, the ordering is preserved when
-\fICMD\fP are executed.
-You could also pass several ex commands in one \fICMD\fP,
-if they are separated by "|".
-.sp
-Example:
-.EX
-vimb --cmd "set cookie-accept=origin|set header=Referer,DNT=1"
-.EE
-.TP
-.BI "\-c, \-\-config " "CONFIG-FILE"
-Use custom configuration given as \fICONFIG-FILE\fP.
-This will also be applied on new spawned instances.
-.TP
-.BI "\-p, \-\-profile " "PROFILE-NAME"
-Create or open specified configuration profile. Configuration data for the profile is stored in a directory named \fIPROFILE-NAME\fP under default directory for configuration data.
-.TP
-.BI "\-e, \-\-embed " "WINID"
-.I WINID
-of an XEmbed-aware application, that Vimb will use as its parent.
-.TP
-.B \-d, \-\-dump
-Dump the current used socket path to stdout in case Vimb is started with \-s
-option.
-.sp
-Example:
-.EX
-sh -c "./vimb -s -d > ~/vimb.socket" &
-echo ":o github.com<CR>" | socat - unix-connect:$(< ~/vimb.socket)
-.EE
-.TP
-.B "\-h, \-\-help"
-Show help options.
-.TP
-.B \-k, \-\-kiosk
-Run Vimb in kiosk mode with nearly no keybindings, not inputbox and no context
-menu.
-.TP
-.B \-s, \-\-socket
-If given Vimb will create a control socket in the user runtime directory.
-.TP
-.B "\-v, \-\-version"
-Print build and version information.
-.SH MODES
-Vimb is modal and has the following main modes:
-.TP
-.B Normal Mode
-The default mode.
-Pressing Escape always enter normal mode.
-.TP
-.B Input Mode
-Used for editing text elements in a webpage.
-.TP
-.B Command Mode
-Execute `ex` commands from the builtin inputbox (commandline).
-.TP
-.B Pass-Through Mode
-In Pass-Through mode only the `<Esc>` and `<C-[>` keybindings are interpreted
-by Vimb, all other keystrokes are given to the webview to handle them.
-This allows the use of a website's configured keybindings, that might otherwise
-be swallowed by Vimb.
-.SH NORMAL MODE COMMANDS
-Some of the Normal Model Commands can have a numeric count to multiply the
-effect of the command.
-If a command supports the count this is shown as \fB[N]\fP.
-.SS General
-.TP
-.B :
-Start Command Mode and print `:' to the input box.
-.TP
-.B gi
-Set cursor to the first editable element in the page and switch to Input
-Mode.
-.TP
-.B CTRL\-Z
-Switch Vimb into Pass-Through Mode.
-.TP
-.B gf
-Toggle show HTML source of the current page.
-.TP
-.B gF
-Open the Web Inspector for the current page.
-.TP
-.B CTRL\-V
-Pass the next key press directly to GTK.
-.TP
-.B CTRL\-Q
-Quit the browser if there are no running downloads.
-.SS Navigation
-.TP
-.B o
-Start Command Mode and print `:open ' to the input box.
-.TP
-.B O
-Start Command Mode and print `:open URI' to the input box.
-.TP
-.B t
-Start Command Mode and print `:tabopen ' to the input box.
-.TP
-.B T
-Start Command Mode and print `:tabopen URI' to the input box.
-.TP
-.B gh
-Open the configured home-page.
-.TP
-.B gH
-Open the configured home-page in a new window.
-.TP
-.B u
-Open the last closed page.
-.TP
-.B U
-Open the last closed page in a new window.
-.TP
-.B CTRL\-P
-Open the oldest entry from the Read It Later queue in the current browser window (only if
-Vimb has been compiled with QUEUE feature).
-.TP
-.BI [ \(dqx ]p
-Open the URI out of the register \fIx\fP or, if not given, from the clipboard.
-.TP
-.BI [ \(dqx ]P
-Open the URI out of the register \fIx\fP or, if not given, from the clipboard in a
-new window.
-.TP
-.BI [ N ]CTRL\-O
-Go back \fIN\fP steps in the browser history.
-.TP
-.BI [ N ]CTRL\-I
-Go forward \fIN\fP steps in the browser history.
-.TP
-.BI [ N ]gu
-Go to the \fIN\fPth descendent directory of the current opened URI.
-.TP
-.B gU
-Go to the domain of the current opened page.
-.TP
-.BI [ N ]CTRL\-A
-Increments the last number in URL by 1, or by \fIN\fP if given.
-.TP
-.BI [ N ]CTRL\-X
-Decrements the last number in URL by 1, or by \fIN\fP if given.
-Negative numbers are not supported as trailing numbers in URLs
-are often preceded by hyphens.
-.TP
-.B r
-Reload the website.
-.TP
-.B R
-Reload the website without using caches.
-.TP
-.B CTRL\-C
-Stop loading the current page.
-.SS Motion
-.TP
-.BI [ N ]CTRL\-F
-Scroll \fIN\fP pages down.
-.TP
-.BI [ N ]CTRL\-B
-Scroll \fIN\fP pages up.
-.TP
-.BI [ N ]CTRL\-D
-Scroll \fIN\fP half pages down.
-.TP
-.BI [ N ]CTRL\-U
-Scroll \fIN\fP half pages up.
-.TP
-.BI [ N ]gg
-Scroll to the top of the current page.
-Or if \fIN\fP is given to \fIN\fP% of the page.
-.TP
-.BI [ N ]G
-Scroll to the bottom of the current page.
-Or if \fIN\fP is given to \fIN\fP% of the page.
-.TP
-.B 0, ^
-Scroll to the absolute left of the document.
-Unlike in Vim, 0 and ^ work exactly the same way.
-.TP
-.B $
-Scroll to the absolute right of the document.
-.TP
-.BI [ N ]h
-Scroll \fIN\fP steps to the left of page.
-.TP
-.BI [ N ]l
-Scroll \fIN\fP steps to the right of page.
-.TP
-.BI [ N ]j
-Scroll page \fIN\fP steps down.
-.TP
-.BI [ N ]k
-Scroll page \fIN\fP steps up.
-.TP
-.BI [ N ]]]
-Follow the last \fIN\fPth link matching `nextpattern'.
-.TP
-.BI [ N ][[
-Follow the last \fIN\fPth link matching `previouspattern'.
-.TP
-.BI m{ a-z }
-Set a page mark {\fIa-z\fP} at the current position on the page.
-Such set marks are only available on the current page;
-if the page is left, all marks will be removed.
-.TP
-.BI '{ a-z }
-Jump to the mark {\fIa-z\fP} on the current page.
-.TP
-.B ''
-Jumps to the position before the latest jump, or where the last "m'" command
-was given.
-.SS Hinting
-Hinting in Vimb is how you accomplish the tasks that you would do with the
-mouse in common mouse-driven browsers: open a URI, yank a URI, save a page and
-so on. When hinting is started, the relevant elements on the page will
-be marked by labels generated from configured `hintkeys'.
-Hints can be selected by using <Tab>, <C-I> or <C-Tab>, <C-O>,
-by typing the chars of the label, or filtering the elements by some text
-that is part of the hinted element (like URI, link text, button label)
-or any combination of these methods.
-If <enter> is pressed, the current active hint will be fired.
-If only one possible hint remains, this will be fired automatically.
-.PP
-.BI Syntax: " ;{mode}{hint}"
-.PP
-Start Hints mode.
-Different elements depending on \fImode\fP are highlighted and `numbered'.
-Elements can be selected either by typing their label, or by typing part
-of their text (\fIhint\fP) to narrow down the result.
-When an element has been selected, it is automatically clicked
-or used (depending on \fImode\fP) and hint mode ends.
-.PP
-The filtering of hints by text splits the query at ' ' and use the single parts
-as separate queries to filter the hints.
-This is useful for hints that have a lot of filterable chars in common
-and many chars are required to make a distinct selection.
-For example ';over tw' will easily select the second hint out of
-{'very long link text one', 'very long link text two'}.
-.PP
-The following keys have special meanings in Hints modes:
-.PD 0
-.IP \fB<CR>\fP
-Selects the first highlighted element, or the current focused.
-.IP "\fB<Tab>\fP"
-Moves the focus to the next hint element.
-.IP "\fB<S-Tab>\fP"
-Moves the focus to the previous hint element.
-.IP "\fB<Esc>, CTRL\-C, CTRL\-[\fP"
-Exits Hints mode without selecting an element.
-.PD
-.TP
-.B Hint modes:
-.RS
-.PD 0
-.TP
-.B f
-Is an alias for the \fB;o\fP hint mode.
-.TP
-.B F
-Is an alias for the \fB;t\fP hint mode.
-.TP
-.B ;o
-Open hint's location in the current window.
-.TP
-.B ;t
-Open hint's location in a new window.
-.TP
-.B ;s
-Saves the hint's destination under the configured `download-path'.
-.TP
-.B ;O
-Generate an `:open' prompt with hint's URI.
-.TP
-.B ;T
-Generate an `:tabopen' prompt with hint's URI.
-.TP
-.B ;e
-Open the configured $EDITOR (`editor-command') with the hinted form element's
-content.
-If the file in $EDITOR is saved and the $EDITOR is closed, the file
-content will be put back in the form field.
-.TP
-.B ;i
-Open hinted image in the current window.
-.TP
-.B ;I
-Open hinted image in a new window.
-.TP
-.B ;p
-Push the hint's URI to the end of the Read It Later queue like the `:qpush'
-command.
-This is only available if Vimb was compiled with the QUEUE feature.
-.TP
-.B ;P
-Push the hint's URI to the beginning of the Read It Later queue like the
-`:qunshift' command.
-This is only available if Vimb was compiled with the QUEUE feature.
-.TP
-.B ;x
-Hints like ;o, but instead of opening the hinted URI, the
-`x-hint-command' is run in Vimb.
-.TP
-.BI [ \(dqx ];y
-Yank hint's destination location into primary and secondary clipboard and into
-the register \fIx\fP.
-.TP
-.BI [ \(dqx ];Y
-Yank hint's text description or form text into primary and secondary clipboard
-and into the register \fIx\fP.
-.PD
-.RE
-.TP
-.BI Syntax: " g;{mode}{hint}"
-Start an extended hints mode and stay there until <Esc> is pressed.
-Like normal hinting, except that after a hint is selected, hints
-remain visible so that another one can be selected with the same action
-as the first.
-Note that the extended hint mode can only be combined with the following
-hint modes \fII p P s t y Y\fP.
-.SS Searching
-.TP
-.BI / QUERY ", ?" QUERY
-Start searching for \fIQUERY\fP in the current page.
-\fI/\fP start search forward, \fI?\fP in backward direction.
-.TP
-.B *, #
-Start searching for the current selected text, or if no text is selected for
-the content of the primary or secondary clipboard.
-\fI*\fP start the search in forward direction and \fI#\fP in backward
-direction.
-.sp
-Note that these commands will yank the text selection into the clipboard and
-may remove other content from there!
-.TP
-.BI [ N ]n
-Search for \fIN\fPnth next search result depending on current search
-direction.
-.TP
-.BI [ N ]N
-Search for \fIN\fPnth previous search result depending on current search
-direction.
-.SS Zooming
-.TP
-.BI [ N ]zi
-Zoom-In the text of the page by \fIN\fP steps.
-.TP
-.BI [ N ]zo
-Zoom-Out the text of the page by \fIN\fP steps.
-.TP
-.BI [ N ]zI
-Full-Content Zoom-In the page by \fIN\fP steps.
-.TP
-.BI [ N ]zO
-Full-Content Zoom-Out the page by \fIN\fP steps.
-.TP
-.B zz
-Reset Zoom.
-.SS Yank
-.TP
-.BI [ \(dqx ]y
-Yank the URI or current page into register \fIx\fP and clipboard.
-.TP
-.BI [ \(dqx ]Y
-Yank the current selection into register \fIx\fP and clipboard.
-.SH COMMAND MODE
-Commands that are listed below are ex-commands like in Vim, that are typed
-into the inputbox (the command line of vimb).
-The commands may vary in their syntax or in the parts they allow,
-but in general they follow a simple syntax.
-.PP
-.BI Syntax: " :[:| ][N]cmd[name][!][ lhs][ rhs]"
-.sp
-Where \fIlhs\fP (left hand side) must not contain any unescaped space.
-The syntax of the rhs (right hand side) if this is available depends on the
-command.
-At the moment the count parts [N] of commands is parsed, but currently there is
-no command that uses the count.
-.sp
-Commands that are typed interactivly (from the inputbox or from socket) are
-normally recorded into command history and register.
-To avoid this, the commands can be prefixed by one or more additional `:' or
-whitespace.
-.PP
-Multiple commands, separated by a `|' can be given in a single command line
-and will be executed consecutively.
-The pipe can be included as an argument to a command by escaping it with a
-backslash.
-.br
-Following commands process the entire command-line string literally.
-These commands will include any `|' as part of their argument string and so
-cannot be followed by another command.
-.PP
-.PD 0
-.IP - 2
-autocmd
-.IP -
-cmap, cnoremap, imap, inoremap, nmap, nnoremap
-.IP -
-eval
-.IP -
-normal
-.IP -
-open, tabopen
-.IP -
-shellcmd
-.PD
-.SS Command Line Editing
-.TP
-.B <Esc>, CTRL\-[, CTRL-C
-Ignore all typed content and switch back to normal mode.
-.TP
-.B <CR>
-Submit the entered `ex` command or search query to run it.
-.TP
-.B CTRL\-H
-Deletes the char before the cursor.
-.TP
-.B CTRL\-W
-Deletes the last word before the cursor.
-.TP
-.B CTRL\-U
-Remove everything between cursor and prompt.
-.TP
-.B CTRL\-B
-Moves the cursor directly behind the prompt `:'.
-.TP
-.B CTRL\-E
-Moves the cursor after the char in inputbox.
-.TP
-.B CTRL\-V
-Pass the next key press directly to GTK.
-.TP
-.B CTRL\-R {a-z"%:/;}
-Insert the content of given register at cursor position.
-See also section about `:reg[ister]' command.
-.SS Command Line History
-.TP
-.B <Tab>
-Start completion of the content in the inputbox in forward direction.
-.TP
-.B <S-Tab>
-Start completion of the content in the inputbox in backward direction.
-.TP
-.B <Up>
-Step backward in the command history.
-.TP
-.B <Down>
-Step forward in the command history.
-.SS Open
-.TP
-.BI ":o[pen] [" URI ]
-Open the give \fIURI\fP in the current window.
-If \fIURI\fP is empty, the configured 'home-page' is opened.
-.TP
-.BI ":t[abopen] [" URI ]
-Open the give \fIURI\fP in a new window.
-If \fIURI\fP is empty, the configured 'home-page' is opened.
-.SS Key Mapping
-Key mappings allow users to alter the actions of key presses.
-Each key mapping is associated with a mode and only has effect
-when the mode is active.
-The following commands allow the user to substitute one sequence
-of key presses by another.
-.PP
-.BI Syntax: " :{m}map {lhs} {rhs}"
-.PP
-Note that the \fIlhs\fP ends with the first found space.
-If you want to use space also in the {lhs} you have to escape this
-with a single `\\', as shown in the examples.
-.sp
-The \fIrhs\fP starts with the first non-space char. If you want a \fIrhs\fP
-that starts with a space, you have to use "<Space>".
-.PP
-Standard key mapping commands are provided for these modes \fIm\fP:
-.PD 0
-.IP \fBn\fP
-Normal mode: when browsing normally.
-.IP \fBi\fP
-Insert mode: when interacting with text fields on a website.
-.IP \fBc\fP
-Command Line mode: when typing into Vimb's command line.
-.PD
-.PP
-Most keys in key sequences are represented simply by the character that you
-see on the screen when you type them.
-However, as a number of these characters have special meanings, and a
-number of keys have no visual representation, a special notation is required.
-.PP
-As special key names have the format \fI<...>\fP.
-The following special keys can be used: <Left>, <Up>, <Right>, <Down>
-for the cursor keys, <Tab>, <Esc>, <CR>, <Space>, <BS>, <F1>-<F12> and <C-A>-<C-Z>.
-.TP
-.BI ":nm[ap] {" lhs "} {" rhs }
-.TP
-.BI ":im[ap] {" lhs "} {" rhs }
-.TP
-.BI ":cm[ap] {" lhs "} {" rhs }
-Map the key sequence \fIlhs\fP to \fIrhs\fP for the modes where the map
-command applies.
-The result, including \fIrhs\fP, is then further scanned for mappings.
-This allows for nested and recursive use of mappings.
-.RS
-.P
-Examples:
-.PD 0
-.IP ":cmap <C-G>h /home/user/downloads/"
-Adds a keybind to insert a file path into the input box.
-This could be useful for the `:save' command
-that could be used as ":save ^Gh".
-.IP ":nmap <F1> :set scripts=on<CR>:open !glib<Tab><CR>"
-This will enable scripts and lookup the first bookmarked URI with the tag
-`glib' and open it immediately if F1 key is pressed.
-.IP ":nmap \\\\\ \\\\\ 50G;o"
-Example which maps two spaces to go to 50% of the page, and start hinting mode.
-.PD
-.RE
-.TP
-.BI ":nn[oremap] {" lhs "} {" rhs }
-.TP
-.BI ":ino[remap] {" lhs "} {" rhs }
-.TP
-.BI ":cno[remap] {" lhs "} {" rhs }
-Map the key sequence \fIlhs\fP to \fIrhs\fP for the mode where the map command
-applies.
-Disallow mapping of \fIrhs\fP, to avoid nested and recursive mappings.
-Often used to redefine a command.
-.TP
-.BI ":nu[nmap] {" lhs }
-.TP
-.BI ":iu[nmap] {" lhs }
-.TP
-.BI ":cu[nmap] {" lhs }
-Remove the mapping of \fIlhs\fP for the applicable mode.
-.SS Bookmarks
-.TP
-.BI ":bma [" tags ]
-Save the current opened URI with \fItags\fP to the bookmark file.
-.TP
-.BI ":bmr [" URI ]
-Removes all bookmarks for given \fIURI\fP or, if not given, the current opened
-page.
-.SS Handlers
-Handlers allow specifying external scripts to handle alternative URI methods.
-.TP
-.BI ":handler-add " "handler" "=" "cmd"
-Adds a handler to direct \fIhandler\fP links to the external \fIcmd\fP.
-The \fIcmd\fP can contain one placeholder `%s` that will be filled by the
-full URI given when the command is called.
-.RS
-.P
-Examples:
-.PD 0
-.IP ":handler-add magnet=xdg-open %s"
-to open magnet links with xdg-open.
-.IP ":handler-add magnet=transmission-gtk %s"
-to open magnet links directly with Transmission.
-.IP ":handler-add irc=irc-handler.sh %s"
-to direct irc://<host>:<port>/<channel> links to a wrapper for your IRC client.
-.PD
-.RE
-.TP
-.BI ":handler-remove " "handler"
-Remove the handler for the given URI \fIhandler\fP.
-.SS Shortcuts
-Shortcuts allow the opening of an URI built up from a named template with additional
-parameters.
-If a shortcut named 'dd' is defined, you can use it with `:open dd
-list of parameters' to open the generated URI.
-.PP
-Shortcuts are convenient to use with search engines where the URI is standardised
-and a single parameter is user defined.
-.TP
-.BI ":shortcut-add " "shortcut" "=" "URI"
-Adds a shortcut with the \fIshortcut\fP and \fIURI\fP template.
-The \fIURI\fP can contain multiple placeholders $0-$9 that will be
-filled by the parameters given when the shortcut is called.
-The parameters given when the shortcut is called will be split
-into as many parameters like the highest used placeholder.
-.sp
-To use spaces within the parameters, the parameters can be grouped by
-surrounding them with single-or double quotes-as shown in example shortcut
-`map'.
-.RS
-.P
-Examples:
-.PD 0
-.IP ":shortcut-add dl=https://duckduckgo.com/lite/?q=$0"
-to setup a search engine.
-Can be called by `:open dl my search phrase'.
-.IP ":shortcut-add gh=https://github.com/$0/$1"
-to build URIs from given parameters.
-Can be called `:open gh fanglingsu vimb'.
-.IP ":shortcut-add map=https://maps.google.com/maps?saddr=$0&daddr=$1"
-to search for a route, all but the last parameter must be quoted if they
-contain spaces like `:open map "city hall, London" railway station, London'
-.PD
-.RE
-.TP
-.BI ":shortcut-remove " "shortcut"
-Remove the search engine to the given \fIshortcut\fP.
-.TP
-.BI ":shortcut-default " "shortcut"
-Set the shortcut for given \fIshortcut\fP as the default.
-It doesn't matter if the \fIshortcut\fP is already in use or not
-to be able to set it.
-.SS Settings
-.TP
-.BI ":se[t] " var = value
-Set configuration values named by \fIvar\fP.
-To set boolean variable you should use 'on', 'off' or 'true' and 'false'.
-Colors are given as hexadecimal value like '#f57700'.
-.TP
-.BI ":se[t] " var += value
-Add the \fIvalue\fP to a number option, or append the \fIvalue\fP to a string
-option.
-When the option is a comma separated list, a comma is added, unless
-the value was empty.
-.TP
-.BI ":se[t] " var ^= value
-Multiply the \fIvalue\fP to a number option, or prepend the \fIvalue\fP to a
-string option.
-When the option is a comma separated list, a comma is added,
-unless the value was empty.
-.TP
-.BI ":se[t] " var -= value
-Subtract the \fIvalue\fP from a number option, or remove the \fIvalue\fP from
-a string option, if it is there.
-When the option is a comma separated list, a
-comma is deleted, unless the option becomes empty.
-.TP
-.BI ":se[t] " var ?
-Show the current set value of variable.
-.IR VAR .
-.TP
-.BI ":se[t] " var !
-Toggle the value of boolean variable \fIvar\fP and display the new set value.
-.SS Queue
-The queue allows the marking of URIs for later reading (something like a Read It Later
-list).
-This list is shared between the single instances of Vimb.
-Only available if Vimb has been compiled with the QUEUE feature.
-.TP
-.BI ":qpu[sh] [" URI ]
-Push \fIURI\fP or, if not given, the current URI to the end of the queue.
-.TP
-.BI ":qun[shift] [" URI ]
-Push \fIURI\fP or, if not given, the current URI to the beginning of the queue.
-.TP
-.B :qp[op]
-Open the oldest queue entry in the current browser window and remove it from the
-queue.
-.TP
-.B :qc[lear]
-Removes all entries from queue.
-.SS Automatic commands
-An autocommand is a command that is executed automatically in response to some
-event, such as a URI being opened.
-Autocommands are very powerful.
-Use them with care and they will help you avoid typing many commands.
-.PP
-Autocommands are built with following properties.
-.TP
-.I group
-When the [\fIgroup\fP] argument is not given, Vimb uses the current group as
-defined with ':augroup', otherwise, Vimb uses the group defined with
-[\fIgroup\fP].
-Groups are useful to remove multiple grouped autocommands.
-.TP
-.I event
-You can specify a comma separated list of event names.
-No white space can be used in this list.
-.RS
-.PP
-.PD 0
-Events:
-.TP
-.B LoadProvisional
-Fired if a new page is going to be opened.
-No data has been received yet, the load may still fail for transport issues.
-.TP
-.B LoadCommited
-Fired if first data chunk has arrived, meaning that the necessary transport
-requirements are established, and the load is being performed.
-This is the right event to toggle content related setting
-like 'scripts', 'plugins' and such things.
-.TP
-.B LoadFirstLayout
-fired if the first layout with actual visible content is shown.
-.TP
-.B LoadFinished
-Fires when everything that was required to display on the page has been loaded.
-.TP
-.B LoadFailed
-Fired when some error occurred during the page load that prevented it from
-being completed.
-.TP
-.B DownloadStart
-Fired right before a download is started.
-This is fired for Vimb downloads as well as external downloads
-if 'download-use-external' is enabled.
-.TP
-.B DownloadFinished
-Fired if a Vimb managed download is finished.
-For external download this event is not available.
-.TP
-.B DownloadFailed
-Fired if a Vimb managed download failed.
-For external download this event is not available.
-.PD
-.RE
-.TP
-.I pat
-Comma separated list of patterns, matches in order to check if a autocommand
-applies to the URI associated to an event.
-To use ',' within the single patterns this must be escaped as '\e,'.
-.RS
-.PP
-.PD 0
-Patterns:
-.IP "\fB*\fP"
-Matches any sequence of characters.
-This includes also '/' in contrast to shell patterns.
-.IP "\fB?\fP"
-Matches any single character except of '/'.
-.IP "\fB{one,two}\fP"
-Matches 'one' or 'two'.
-Any '{', ',' and '}' within this pattern must be escaped by a '\\'.
-\&'*' and '?' have no special meaning within the curly braces.
-.IP "\fB\e\fP"
-Use backslash to escape the special meaning of '?*{},' in the pattern or
-pattern list.
-.PD
-.RE
-.TP
-.I cmd
-Any `ex` command vimb understands.
-The leading ':' is not required.
-Multiple commands can be separated by '|'.
-.TP
-.BI ":au[tocmd] [" group "] {" event "} {" pat "} {" cmd "}"
-Add \fIcmd\fP to the list of commands that Vimb will execute automatically on
-\fIevent\fP for a URI matching \fIpat\fP autocmd-patterns.
-Vimb always adds the \fIcmd\fP after existing autocommands, so that the
-autocommands are executed in the order in which they were given.
-.TP
-.BI ":au[tocmd]! [" group "] {" event "} {" pat "} {" cmd "}"
-Remove all autocommands associated with \fIevent\fP and which pattern match
-\fIpat\fP, and add the command \fIcmd\fP.
-Note that the pattern is not matches literally to find autocommands
-to remove, like Vim does.
-Vimb matches the autocommand pattern with \fIpat\fP.
-If [\fIgroup\fP] is not given, deletes autocommands in current group,
-as noted above.
-.TP
-.BI ":au[tocmd]! [" group "] {" event "} {" pat "}"
-Remove all autocommands associated with \fIevent\fP and which pattern matches
-\fIpat\fP in given group (current group by default).
-.TP
-.BI ":au[tocmd]! [" group "] * {" pat "}"
-Remove all autocommands with patterns matching \fIpat\fP for all events
-in given group (current group by default).
-.TP
-.BI ":au[tocmd]! [" group "] {" event "}"
-Remove all autocommands for \fIevent\fP in given group (current group
-by default).
-.TP
-.BI ":au[tocmd]! [" group "]"
-Remove all autocommands in given group (current group by default).
-.TP
-.BI ":aug[roup] {" name "}"
-Define the autocmd group \fIname\fP for the following ":autocmd" commands.
-The name "end" selects the default group.
-.TP
-.BI ":aug[roup]! {" name "}"
-Delete the autocmd group \fIname\fP.
-.PP
-Example:
-.EX
-:aug github
-: au LoadCommited * set scripts=off|set cookie-accept=never
-: au LoadCommited http{s,}://github.com/* set scripts=on
-:aug end
-.EE
-.SS Misc
-.TP
-.BI ":sh[ellcmd] " cmd
-Runs the given shell \fIcmd\fP syncron and print the output into inputbox.
-The following patterns in \fIcmd\fP are expanded: '~username', '~/', '$VAR'
-and '${VAR}'.
-A '\\' before these patterns disables the expansion.
-.PP
-.RS
-.PP
-.PD 0
-The following environment variables are set for called shell commands.
-.TP
-.B VIMB_URI
-This variable is set by Vimb everytime a new page is opened to the URI of the
-page.
-.TP
-.B VIMB_TITLE
-Contains the title of the current opened page.
-.TP
-.B VIMB_PID
-Contains the pid of the running Vimb instance.
-.TP
-.B VIMB_SOCKET
-Holds the full path to the control socket, if Vimb is compiled with SOCKET
-feature and started with `--socket' option.
-.TP
-.B VIMB_XID
-Holds the X-Window id of the Vimb window or of the embedding window if Vimb is
-started with the -e option.
-.PD
-.PP
-Example:
-.EX
-:sh ls -l $HOME
-.EE
-.RE
-.TP
-.BI ":sh[ellcmd]! " cmd
-Like :sh[ellcmd], but asyncron.
-.sp
-Example:
-.EX
-:sh! /bin/sh -c 'echo "`date` $VIMB_URI" >> myhistory.txt'
-.EE
-.TP
-.BI ":s[ave] [" path "]"
-Download current opened page into configured download directory.
-If \fIpath\fP is given, download under this file name or path.
-\fIpath\fP is expanded and can therefore contain '~/', '${ENV}'
-and '~user' pattern.
-.TP
-.BI ":so[urce] [" file "]"
-Read ex commands from \fIfile\fP.
-.TP
-.B :q[uit]
-Close the browser.
-This will be refused if there are running downloads.
-.TP
-.B :q[uit]!
-Close the browser independent from an running download.
-.TP
-.B :reg[ister]
-Display the contents of all registers.
-.RS
-.PP
-.PD 0
-Registers:
-.TP
-.BR \(dqa " - " \(dqz
-26 named registers "a to "z.
-Vimb fills these registers only when you say so.
-.TP
-.B \(dq:
-Last executed `ex` command.
-.TP
-.B \(dq"
-Last yanked content.
-.TP
-.B \(dq%
-Curent opened URI.
-.TP
-.B \(dq/
-Last search phrase.
-.TP
-.B \(dq;
-Contains the last hinted URL.
-This can be used in `x-hint-command' to get the URL of the hint.
-.PD
-.RE
-.TP
-.BI :e[val] " javascript"
-Runs the given \fIjavascript\fP in the current page and display the evaluated
-value.
-.sp
-Example: :eval document.cookie
-.TP
-.BI :e[val]! " javascript"
-Like :eval, but there is nothing print to the input box.
-.TP
-.BI ":no[rmal] [" cmds ]
-Execute normal mode commands \fIcmds\fP.
-This makes it possible to execute normal mode commands typed on the input box.
-.sp
-\fIcmds\fP cannot start with a space.
-Put a count of 1 (one) before it, "1 " is one space.
-.sp
-Example: :set scripts!|no! R
-.TP
-.BI ":no[rmal]! [" cmds ]
-Like :normal, but no mapping is applied to \fIcmds\fP.
-.TP
-.B :ha[rdcopy]
-Print current document.
-Open a GUI dialog where you can select the printer,
-number of copies, orientation, etc.
-.SH INPUT MODE
-.TP
-.B <Esc>, CTRL\-[
-Switch back to normal mode.
-.TP
-.B CTRL\-O
-Executes the next command as normal mode command and return to input mode.
-.TP
-.B CTRL\-T
-Open configured $EDITOR with content of current form field.
-.TP
-.B CTRL\-V
-Pass the next key press directly to GTK.
-.TP
-.B CTRL\-Z
-Enter the pass-through mode.
-.SH COMPLETIONS
-The completions are triggered by pressing `<Tab>` or `<S-Tab>` in the
-activated inputbox.
-Depending of the current inserted content different completions are started.
-The completion takes additional typed chars to filter
-the completion list that is shown.
-.TP
-.B commands
-The completion for commands are started when at least `:` is shown in the
-inputbox.
-If initial chars are passed, the completion will lookup those
-commands that begin with the given chars.
-.TP
-.B settings
-The setting name completion is started if at least `:set ` is shown in
-inputbox and does also match settings that begins with already typed setting
-prefix.
-.TP
-.B history
-The history of URIs is shown for the `:open ` and `:tabopen ` commands.
-This completion looks up every given word in the history URI and titles.
-Only those history items are shown, where the title or URI contains all tags.
-.sp
-Example:
-.RS
-.PD 0
-.IP ":open foo bar<Tab>"
-will complete only URIs that contain the words foo and bar.
-.PD
-.RE
-.TP
-.B bookmarks
-The bookmark completion is similar to the history completion, but does match
-only the tags of the bookmarks.
-The bookmark completion ist started by `:open \fB!\fP`
-or `:tabopen \fB!\fP` and does a prefix search for all given words in
-the bookmark tags.
-.sp
-Example:
-.RS
-.PD 0
-.IP ":open \fB!\fPfoo ba"
-will match all bookmarks that have tags starting with "foo" and "ba".
-If the bookmark does not have any tags set, the URL is split on `.' and `/'
-into tags.
-.PD
-.RE
-.TP
-.B boomark tags
-The boomark tag completion allows the insertion of already used bookmarks for the
-`:bma ` commands.
-.TP
-.B search
-The search completion allows a filtered list of already done searches.
-This completion starts by `/` or `?` in inputbox and performs a prefix
-comparison for further typed chars.
-.SH SETTINGS
-All settings listed below can be set with the `:set' command.
-.SS WebKit-Settings
-.TP
-.B accelerated-compositing (bool)
-Enable or disable support for accelerated compositing on pages.
-Accelerated compositing uses the GPU to render animations on pages
-smoothly and also allows proper rendering of 3D CSS transforms.
-.TP
-.B auto-load-images (bool)
-Load images automatically.
-.TP
-.B auto-resize-window (bool)
-Indicates if Vimb will honor size and position changes of the window by various
-DOM methods.
-.TP
-.B auto-shrink-images (bool)
-Automatically shrink standalone images to fit.
-.TP
-.B caret (bool)
-Whether to enable accessibility enhanced keyboard navigation.
-.TP
-.B closed-max-items (int)
-Maximum number of stored last closed browser windows. If closed-max-items is
-set to 0, closed browser windows will not be stored.
-.TP
-.B cursivfont (string)
-The font family used as the default for content using cursive font.
-.TP
-.B defaultencoding (string)
-The default text charset used when interpreting content with an unspecified
-charset.
-.TP
-.B defaultfont (string)
-The font family to use as the default for content that does not specify a
-font.
-.TP
-.B dns-prefetching (bool)
-Indicates if Vimb prefetches domain names.
-.TP
-.B dom-paste (bool)
-Whether to enable DOM paste.
-If set to TRUE, document.execCommand("Paste")
-will correctly execute and paste content of the clipboard.
-.TP
-.B file-access-from-file-uris (bool)
-Boolean property to control file access for file:// URIs.
-If this option is enabled every file:// will have its own security
-unique domain.
-.TP
-.B fontsize (int)
-The default font size used to display text.
-.TP
-.B frame-flattening (bool)
-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.
-.TP
-.B html5-database (bool)
-Whether to enable HTML5 client-side SQL database support.
-Client-side SQL database allows web pages to store structured data
-and be able to use SQL to manipulate that data asynchronously.
-.TP
-.B html5-local-storage (bool)
-Whether to enable HTML5 localStorage support.
-localStorage provides simple synchronous storage access.
-.TP
-.B hyperlink-auditing (bool)
-Enable or disable support for <a ping>.
-.TP
-.B images (bool)
-Determines whether images should be automatically loaded or not.
-.TP
-.B insecure-content-show (bool)
-Whether pages loaded via HTTPS should load subresources such as images and
-frames from non-HTTPS URIs.
-Only for webkit>=2.0.
-.TP
-.B insecure-content-run (bool)
-Whether pages loaded via HTTPS should run subresources such as CSS, scripts,
-and plugins from non-HTTPS URIs.
-Only for webkit>=2.0.
-.TP
-.B java-applet (bool)
-Enable or disable support for the Java <applet> tag.
-Keep in mind that Java content can be still shown in the page
-through <object> or <embed>, which are the preferred tags for this task.
-.TP
-.B javascript-can-access-clipboard (bool)
-Whether JavaScript can access the clipboard.
-.TP
-.B javascript-can-open-windows-automatically (bool)
-Whether JavaScript can open popup windows automatically without user
-intervention.
-.TP
-.B media-playback-allows-inline (bool)
-Whether media playback is full-screen only or inline playback is allowed.
-Setting it to false allows specifying that media playback should be always
-fullscreen.
-.TP
-.B media-playback-requires-user-gesture (bool)
-Whether a user gesture (such as clicking the play button) would be required to
-start media playback or load media.
-Setting it on requires a gesture by the
-user to start playback, or to load the media.
-.TP
-.B media-stream (bool)
-Enable or disable support for MediaSource on pages.
-MediaSource is an experimental proposal which extends HTMLMediaElement
-to allow JavaScript to generate media streams for playback.
-.TP
-.B mediasource (bool)
-Enable or disable support for MediaSource on pages.
-MediaSource is an experimental proposal which extends HTMLMediaElement
-to allow JavaScript to generate media streams for playback.
-.TP
-.B minimumfontsize (int)
-The minimum font size used to display text.
-.TP
-.B monofont (string)
-The font family used as the default for content using monospace font.
-.TP
-.B monofontsize (int)
-Default font size for the monospace font.
-.TP
-.B offlinecache (bool)
-Whether to enable HTML5 offline web application cache support.
-Offline web application cache allows web applications to run even
-when the user is not connected to the network.
-.TP
-.B pagecache (bool)
-Enable or disable the page cache.
-Disabling the page cache is generally only useful for special
-circumstances like low-memory scenarios or special purpose
-applications like static HTML viewers.
-.TP
-.B print-backgrounds (bool)
-Whether background images should be printed.
-.TP
-.B private-browsing (bool)
-Whether to enable private browsing mode.
-This suppresses printing of messages into JavaScript Console.
-At the time this is the only way to force WebKit to
-not allow a page to store data in the windows sessionStorage.
-.TP
-.B plugins (bool)
-Determines whether or not plugins on the page are enabled.
-.TP
-.B print-backgrounds (bool)
-Whether background images should be drawn during printing.
-.TP
-.B resizable-text-areas (bool)
-Whether text areas are resizable.
-.TP
-.B respect-image-orientation (bool)
-Whether Vimb should respect image orientation.
-.TP
-.B sansfont (string)
-The font family used as the default for content using sans-serif font.
-.TP
-.B scripts (bool)
-Determines whether or not JavaScript executes within a page.
-.TP
-.B seriffont (string)
-The font family used as the default for content using serif font.
-.TP
-.B site-specific-quirks (bool)
-Enables the site-specific compatibility workarounds.
-.TP
-.B smooth-scrolling (bool)
-Enable or disable support for smooth scrolling.
-.TP
-.B spacial-navigation (bool)
-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.
-For example, if
-a user presses the Right key, heuristics determine whether there is an
-element they might be trying to reach towards the right, and if there are
-multiple elements, which element they probably want.
-.TP
-.B spell-checking (bool)
-Whether to enable spell checking while typing.
-.TP
-.B spell-checking-languages (string)
-The languages to be used for spell checking, separated by commas.
-.sp
-The locale string typically is in the form lang_COUNTRY, where lang is an
-ISO-639 language code, and COUNTRY is an ISO-3166 country code.
-For instance, sv_FI for Swedish as written in Finland or pt_BR
-for Portuguese as written in Brazil.
-.sp
-If no value is specified the default value for GTK is used.
-.TP
-.B tab-key-cycles-through-elements (bool)
-Whether the Tab key cycles through elements on the page.
-.sp
-If true, pressing the Tab key will focus the next element in the web view.
-Otherwise, the web view will interpret Tab key presses as normal key presses.
-If the selected element is editable, the Tab key will cause the insertion
-of a Tab character.
-.TP
-.B universal-access-from-file-uris (bool)
-Whether to allow files loaded through file:// URIs universal access to all
-pages.
-.TP
-.B useragent (string)
-The user-agent string used by WebKit.
-.TP
-.B webaudio (bool)
-Enable or disable support for WebAudio on pages.
-WebAudio is an experimental proposal for allowing web pages
-to generate Audio WAVE data from JavaScript.
-.TP
-.B webgl (bool)
-Enable or disable support for WebGL on pages.
-.TP
-.B webinspector (bool)
-Determines whether or not developer tools, such as the Web Inspector, are
-enabled.
-.TP
-.B xssauditor (bool)
-Whether to enable the XSS auditor.
-This feature filters some kinds of reflective XSS attacks
-on vulnerable web sites.
-.SS Vimb-Settings
-.TP
-.B auto-response-header (list)
-Prepend HTTP-Header to responses received from server, based on pattern
-matching.
-The purpose of this setting is to enforce some security setting in the client.
-For example, you could set Content-Security-Policy (see
-`http://www.w3.org/TR/CSP/') for implement a whitelist policy, or set
-Strict-Transport-Security for server that don't provide this header whereas
-they propose https website.
-.sp
-Note that this setting will not replace existing headers, but add a new one.
-If multiple patterns match a requested URI, the last matched rule will be
-applied.
-You could also specified differents headers for the same pattern.
-.sp
-The format is a list of `pattern header-list`.
-If `header-list` has not than one element, enclosing with QUOTE
-is mandatory: `"pattern header-list"`.
-The header-list format is the same as `header` setting.
-.RS
-.PP
-Example:
-.PD 0
-.IP ":set auto-response-header=* Content-security-policy=default-src 'self' 'unsafe-inline' 'unsafe-eval'; script-src 'none'"
-.IP ":set auto-response-header+=https://example.com/* Content-security-policy=default-src 'self' https://*.example.com/"
-.IP ":set auto-response-header+=https://example.com/* Strict-Transport-Security=max-age=31536000"
-.IP ":set auto-response-header+=""https://*.example.org/sub/* Content-security-policy,X-Test=ok"""
-.PD
-.RE
-.TP
-.B ca-bundle (string)
-The path to the .crt file for the certificate validation.
-The given path is expanded with standard file expansion.
-.TP
-.B completion-bg-active (color)
-Background color for selected completion item.
-.TP
-.B completion-bg-normal (color)
-Background color for non-selected completion items.
-.TP
-.B completion-fg-active (color)
-Foreground color for the selected completion item.
-.TP
-.B completion-fg-normal (color)
-Foreground color for the non-selected completion items.
-.TP
-.B completion-font (string)
-Font used for the completion items.
-.TP
-.B cookie-accept (string)
-Cookie accept policy {`always', `never', `origin' (accept all non-third-party
-cookies)}.
-.TP
-.B cookie-timeout (int)
-Cookie timeout in seconds.
-.TP
-.B cookie-expire-time (int)
-Enforce expire-time on cookies.
-The default value `-1' keep expire-time as defined by server side.
-The value `0' convert all cookies as session-only cookies
-(`cookie-timeout' setting is used as for any other session-cookie).
-Any other value enforce the expire-time (the expire-time value will be the
-lower between server-side request and time defined with `cookie-expire-time').
-.TP
-.B download-command (string)
-A command with placeholder '%s' that will be invoked to download a URI.
-.RS
-.TP
-The following additional environment variable are available:
-.PD 0
-.TP
-.B $VIMB_URI
-The URI of the current opened page, normally the page where the download was
-started from, also known as referer.
-.TP
-.B $VIMB_FILE
-The target file that is calculated by Vimb according to the `download-path'.
-Note that this file might already exists, so it's strongly recommended to
-check the path in this variable before usage.
-.TP
-.B $VIMB_COOKIES
-Path to the cookie file Vimb uses.
-This is only available if Vimb is compiled with the COOKIE feature.
-.TP
-.B $VIMB_USER_AGENT
-Holds the user agent string that Vimb uses.
-.TP
-.B $VIMB_MIME_TYPE
-The mime-type of the download.
-This variable is only available when the server sent the mime-type header
-with the response and only if the download was not start by the `:save'
-command or the `;s' hinting.
-.TP
-.B $VIMB_USE_PROXY
-Indicates if the proxy is enabled in Vimb.
-If enable this variable is `1', otherwise `0'.
-Note that this variable gives no hint if the proxy settings
-apply to the URL to be downloaded, only if proxy is enabled in general.
-.PD
-.PP
-Example:
-.PD 0
-.IP ":set download-command=/bin/sh -c\
- ""wget -c %s -O $VIMB_FILE --load-cookies $VIMB_COOKIES"""
-.PD
-.RE
-.TP
-.B download-path (string)
-Path to the default download directory.
-If the directory is not set download will be written into current directory.
-The following pattern will be expanded if the download
-is started '~/', '~user', '$VAR' and '${VAR}'.
-.TP
-.B download-use-external (bool)
-Indicates if the external download tool set as `download-command' should be
-used to handle downloads.
-If this is disabled Vimb will handle the download.
-.TP
-.B editor-command (string)
-Command with placeholder '%s' called if form filler is opened with $EDITOR to
-spawn the editor-like `x-terminal-emulator -e vi %s'.
-To use Gvim as the editor, it's necessary to call it with `-f' to run it
-in the foreground.
-.TP
-.B fullscreen (bool)
-Show the current window full-screen.
-.TP
-.B header (list)
-Comma separated list of headers that replaces default header sent by WebKit or
-new headers.
-The format for the header list elements is `name[=[value]]'.
-.sp
-Note that these headers will replace already existing headers.
-If there is no '=' after the header name, then the complete header
-will be removed from the request, if the '=' is present means that
-the header value is set to empty value.
-.sp
-To use '=' within a header value the value must be quoted like shown in
-Example for the Cookie header.
-.RS
-.PP
-Example:
-.PD 0
-.IP ":set header=DNT=1,User-Agent,Cookie='name=value'"
-Send the 'Do Not Track' header with each request and remove the User-Agent
-Header completely from request.
-.PD
-.RE
-.TP
-.B hint-follow-last (bool)
-If on, vimb automatically follows the last remaining hint on the page.
-If off hints are fired only if enter is pressed.
-.TP
-.B hint-number-same-length (bool)
-If on, all hint numbers will have the same length, so no hints will be
-ambiguous.
-.TP
-.B hint-timeout (int)
-Timeout before automatically following a non-unique numerical hint.
-To disable auto fire of hints, set this value to 0.
-.TP
-.B hintkeys (string)
-The keys used to label and select hints.
-With its default value, each hint has a unique number which can be typed
-to select it, while all other characters are used to filter hints based
-on their text.
-With a value such as asdfg;lkjh,
-each hint is `numbered' based on the characters of the home row.
-Note that the hint matching by label built of hintkeys is case sensitive.
-In this vimb differs from some other browsers that show hint labels in upper
-case, but match them lowercase.
-.RS
-To have upper case hint labels, it's possible to add following css to the
-`style.css' file in vimb's configuration directory.
-.IP "._hintLabel {text-transform: uppercase !important;}"
-.RE
-.TP
-.B history-max-items (int)
-Maximum number of unique items stored in search-, command or URI history.
-If history-max-items is set to 0, the history file will not be changed.
-.TP
-.B home-page (string)
-Homepage that vimb opens if started without a URI.
-.TP
-.B hsts (bool)
-Enable or disables the HSTS (HTTP Strict Transport Security) feature.
-.TP
-.B input-autohide (bool)
-If enabled the inputbox will be hidden whenever it contains no text.
-.TP
-.B input-bg-error (color)
-Background color for the inputbox if error is shown.
-.TP
-.B input-bg-normal (color)
-Background color of the inputbox.
-.TP
-.B input-fg-error (color)
-Foreground color of inputbox if error is shown.
-.TP
-.B input-fg-normal (color)
-Foreground color of inputbox.
-.TP
-.B input-font-error (string)
-Font user in inputbox if error is shown.
-.TP
-.B input-font-normal (string)
-Font used for inputbox.
-.TP
-.B nextpattern (list)
-Patterns to use when guessing the next page in a document.
-Each pattern is successively tested against each link in the page
-beginning from the last link.
-Default
-"/\\bnext\\b/i,/^(>|>>|»)$/,/^(>|>>|»)/,/(>|>>|»)$/,/\\bmore\\b/i".
-Note that you have to escape the '|' as '\\|' else the '|' will terminate
-the :set command and start a new command.
-.TP
-.B maximum-cache-size (int)
-Size in kB used to cache various page data.
-This caching is independent from `pagecache' or `offlinecache'.
-To disable caching, the size could be set to '0'.
-.TP
-.B previouspattern (list)
-Patterns to use when guessing the previous page in a document.
-Each pattern is successively tested against each link in the page
-beginning from the last link.
-Default "/\\bnext\\b/i,/^(>|>>|»)$/,/^(>|>>|»)/,/(>|>>|»)$/,/\\bmore\\b/i"
-.TP
-.B proxy (bool)
-Indicates if the environment variable `http_proxy' is evaluated.
-.TP
-.B scrollstep (int)
-Number of pixel vimb scrolls if 'j' or 'k' is used.
-.TP
-.B statusbar (bool)
-Indicates if the statusbar should be shown.
-.TP
-.B status-color-bg (color)
-Background color of the statusbar.
-.TP
-.B status-color-fg (color)
-Foreground color of the statusbar.
-.TP
-.B status-font (string)
-Font used in statusbar.
-.TP
-.B status-ssl-color-bg (color)
-Background color of statusbar if current page uses trusted https certificate.
-.TP
-.B status-ssl-color-fg (color)
-Foreground color for statusbar for https pages.
-.TP
-.B status-ssl-font (string)
-Statusbar font for https pages.
-.TP
-.B status-sslinvalid-color-bg (color)
-Background color of the statusbar if the certificate if the https page isn't
-trusted.
-.TP
-.B status-sslinvalid-color-fg (color)
-Foreground of statusbar for untrusted https pages.
-.TP
-.B status-sslinvalid-font (string)
-Statusbar font for untrusted https pages.
-.TP
-.B strict-focus (bool)
-Vimb checks if an editable element is focused and switch to input mode.
-If strict-focus is enabled, this isn't done for focused element on page load
-(without user interaction), instead the focus is removed from the focused
-element.
-Focus changed that appear after the page was completely loaded are
-not affected by this setting.
-.TP
-.B strict-ssl (bool)
-If 'on', vimb will not load a untrusted https site.
-.TP
-.B stylesheet (bool)
-If 'on' the user defined styles-sheet is used.
-.TP
-.B timeoutlen (int)
-The time in milliseconds that is waited for a key code or mapped key sequence
-to complete.
-.TP
-.B x-hint-command (string)
-Command used if hint mode ;x is fired.
-The command can be any vimb command string.
-Note that the command is run through the mapping mechanism of vimb so
-it might change the behaviour by adding or changing mappings.
-.RS
-.P
-.PD 0
-.IP ":set x-hint-command=50G"
-Not really useful.
-If the hint is fired, scroll to the middle of the page.
-.IP ":set x-hint-command=:sh! curl -e <C-R>% <C-R>;"
-This fills the inputbox with the prefilled download command and replaces
-`<C-R>%' with the current URI and `<C-R>;' with the URI of the hinted element.
-.PD
-.RE
-.SH FILES
-.TP
-.I $XDG_CONFIG_HOME/vimb/
-Default directory for configuration data.
-.RS
-.PD 0
-.TP
-.I config
-Configuration file to set WebKit setting, some GUI styles and keybindings.
-.TP
-.I cookies
-Cookie store file.
-.TP
-.I closed
-Holds the URI of last closed browser windows.
-.TP
-.I history
-This file holds the history of unique opened URIs.
-.TP
-.I command
-This file holds the history of commands and search queries performed via input
-box.
-.TP
-.I search
-This file holds the history of search queries.
-.TP
-.I bookmark
-Holds the bookmarks saved with command `bma'.
-The records are stored there as
-.br
-`URI<tab>title<tab>space separated tags' or as
-.br
-`URI<tab><tab>tags` if there is no title.
-.TP
-.I queue
-Holds the Read It Later queue filled by `qpush' if
-Vimb has been compiled with QUEUE feature.
-.TP
-.I hsts
-Holds the known hosts hosts if Vimb is compiled with HTTP strict transport
-security feature.
-.TP
-.I scripts.js
-This file can be used to run user scripts, that are injected into every paged
-that is opened.
-.TP
-.I style.css
-File for userdefined CSS styles.
-These file is used if the config variable `stylesheet' is enabled.
-.PD
-.RE
-.TP
-.I $XDG_CONFIG_HOME/vimb/PROFILE-NAME
-Directory for configuration data if executed with \fB-p \fIPROFILE-NAME\fR parameter. It has same structure as default directory for configuration data.
-.TP
-.I $XDG_CACHE_HOME/vimb/
-Default directory for cache data.
-.TP
-.I $XDG_CACHE_HOME/vimb/PROFILE-NAME
-Directory for cache data if executed with \fB-p \fIPROFILE-NAME\fR parameter.
-.TP
-.I $XDG_RUNTIME_DIR/vimb/socket/
-Directory where the control sockets are placed.
-.TP
-.I $XDG_RUNTIME_DIR/vimb/PROFILE-NAME/socket/
-Directory where the control sockets are placed if executed with \fB-p \fIPROFILE-NAME\fR parameter.
-.PP
-There are also some sample scripts installed together with Vimb under
-PREFIX/share/vimb/examples.
-.SH ENVIRONMENT
-.TP
-.B http_proxy
-If this variable is set to an non-empty value, and the configuration option
-`proxy' is enabled, this will be used as HTTP proxy.
-If the proxy URL has no scheme set, HTTP is assumed.
-.TP
-.B no_proxy
-A comma separated list of domains and/or IPs which should not be proxied.
-Note that an IPv6 address must appear in brackets if used with a port,
-for example "[::1]:443".
-.IP
-Example: "localhost,127.0.0.1,::1,fc00::/7,example.com:8080"
-.SH "REPORTING BUGS"
-Report bugs to the main project page on https://github.com/fanglingsu/vimb/issues
-.br
-or on the mailing list https://lists.sourceforge.net/lists/listinfo/vimb-users.
-.SH AUTHOR
-Daniel Carl
diff --git a/examples/formfiller/formfiller b/examples/formfiller/formfiller
deleted file mode 100755
index 05edd49..0000000
--- a/examples/formfiller/formfiller
+++ /dev/null
@@ -1,78 +0,0 @@
-#!/usr/bin/env bash
-# Formfiller that reads credentials from file and let vimb fill execute a
-# JavaScript method to fill in the form data. Call this from vimb by ':sh!
-# formfiller %'
-#
-# The form data are stored in $VIMB_KEY_DIR or as fallback
-# $XDG_CONFIG_HOME/vimb/keys. The files must be names as
-# [prefix]{domain}.gpg or [prefix]{domain}. The files must contain a valid
-# JavaScript array that can be used for the _vbform.fill() method.
-#
-# A unencrypted sample file could look like this:
-# ["input[name='user']:daniel", "input[name='password']:p45w0rD"]
-
-# dmenu command use in case multiple files are found for current domain
-DMENU="dmenu -l 7"
-
-if [[ -z "$XDG_CONFIG_HOME" ]]; then
- XDG_CONFIG_HOME=$HOME/.config
-fi
-
-VIMB_KEY_DIR=${VIMB_KEY_DIR:-"$XDG_CONFIG_HOME/vimb/keys"}
-uri=$1
-
-die() {
- echo "$1" >&2
- exit 1
-}
-
-fillform() {
- local path=$1
- local data=""
- case "$path" in
- *.gpg )
- # this requires the gpg-agent to contains already the key
- data=$(gpg --batch -qd "$path")
- # abort here if the file could not be decrypted
- if [ $? -gt 0 ]; then
- exit 1
- fi
- ;;
- * )
- data=$(cat "$path")
- ;;
- esac
- # make sure we are in normal mode and fill in the form data
- # use :: to not save the secrets into vimb command history or into the
- # last ex command register ":
- echo "<Esc>::e! _vbform.fill($data);<CR>" | socat - UNIX-CONNECT:$VIMB_SOCKET
-}
-
-# check if uri is given
-if [ -z "$uri" ]; then
- die 'No URI given'
-fi
-# check if the script is run from vimb with socket support enabled
-if [ -z "$VIMB_SOCKET" ] || [ ! -S "$VIMB_SOCKET" ]; then
- die 'This script must be run from vimb with socket support'
-fi
-
-# extract the domain part without ports from given uri
-domain=$(echo "$uri" | sed -r 's@https?://([^:/]+).*@\1@')
-
-# find matching data files prefix${domain}{,.gpg}
-files=($(find "$VIMB_KEY_DIR" -name "*$domain" -o -name "*${domain}.gpg"))
-# strip of the key dir
-files=("${files[@]#"$VIMB_KEY_DIR"/}")
-
-# if only one matchin data file found - use this direct
-if [ ${#files[@]} -eq 1 ]; then
- fillform "$VIMB_KEY_DIR/${files[0]}"
- exit 1
-else
- # else allow to select the right one via dmenu
- match=$(printf '%s\n' "${files[@]}" | sort | $DMENU)
- if [ -n $match ]; then
- fillform "$VIMB_KEY_DIR/$match"
- fi
-fi
diff --git a/examples/formfiller/scripts.js b/examples/formfiller/scripts.js
deleted file mode 100644
index 8357409..0000000
--- a/examples/formfiller/scripts.js
+++ /dev/null
@@ -1,50 +0,0 @@
-/* Script to insert various data into form fields.
- * Given data is an array of "Selector:Value" tupel.
- * ["selector:value","...:..."]
- * Example call from within vimb:
- * ::e! _vbform.fill(["input[name='login']:daniel","input[name='password']:p45w0rD"]);
- *
- * Note the double ':' in front, this tells vimb not to write the command into
- * history or the last excmd register ":. */
-"use strict"
-var _vbform = {
- fill: function(data) {
- data = data||[];
- var e, i, k, s;
-
- // iterate over data array and try to find the elements
- for (i = 0; i < data.length; i++) {
- // split into selector and value part
- s = data[i].split(":");
- e = document.querySelectorAll(s[0]);
- for (k = 0; k < e.length; k++) {
- // fill the form fields
- this.set(e[k], s[1]);
- }
- }
- },
-
- // set the value for the form element
- set: function(e, v) {
- var i, t, n = e.nodeName.toLowerCase();
-
- if (n == "input") {
- t = e.type;
- if (t == "checkbox" || t == "radio") {
- e.checked = ("1" == v);
- } else if (t == "submit") {
- e.click();
- } else {
- e.value = v;
- }
- } else if (n == "textarea") {
- e.value = v;
- } else if (n == "select") {
- for (i = 0; i < e.options.length; i++) {
- if (e.options[i].value == v) {
- e.options[i].selected = "selected";
- }
- }
- }
- }
-};
diff --git a/src/.gitignore b/src/.gitignore
new file mode 100644
index 0000000..ca46d8a
--- /dev/null
+++ b/src/.gitignore
@@ -0,0 +1,2 @@
+config.h
+vimb
diff --git a/src/Makefile b/src/Makefile
index b72d7c9..e4e2fae 100644
--- a/src/Makefile
+++ b/src/Makefile
@@ -1,63 +1,27 @@
BASEDIR=..
include $(BASEDIR)/config.mk
-OBJ = $(patsubst %.c, %.o, $(wildcard *.c))
-LOBJ = $(patsubst %.c, %.lo, $(wildcard *.c))
+OBJ = $(patsubst %.c, %.o, $(wildcard *.c))
-all: $(TARGET)
+all: vimb
-clean: clean-lib
- $(RM) $(TARGET) *.o *.lo hints.js.h
+clean:
+ $(RM) vimb *.o
-clean-lib:
- $(RM) $(LIBTARGET)
-
-hints.o: hints.js.h
-hints.lo: hints.js.h
-
-hints.js.h: hints.js
- @echo "minify $<"
- @cat $< | ./js2h.sh > $@
-
-$(OBJ): config.h $(BASEDIR)/config.mk
-$(LOBJ): config.h $(BASEDIR)/config.mk
-
-$(TARGET): $(OBJ)
-ifeq ($(VERBOSE),0)
+vimb: $(OBJ)
@echo "$(CC) $@"
- @$(CC) $(OBJ) -o $@ $(LDFLAGS)
-else
- $(CC) $(OBJ) -o $@ $(LDFLAGS)
-endif
+ @$(CC) $(LDFLAGS) $(OBJ) -o $@
-$(LIBTARGET): $(LOBJ)
-ifeq ($(VERBOSE),0)
- @echo "$(CC) $@"
- @$(CC) -shared ${LOBJ} -o $@ $(LDFLAGS)
-else
- $(CC) -shared ${LOBJ} -o $@ $(LDFLAGS)
-endif
+$(OBJ): config.h $(BASEDIR)/config.mk
+
+-include $(OBJ:.o=.d)
config.h:
@echo create $@ from config.def.h
@cp config.def.h $@
-%.o: %.c %.h
-ifeq ($(VERBOSE),0)
+%.o: %.c
@echo "${CC} $@"
@$(CC) $(CFLAGS) -c -o $@ $<
-else
- $(CC) $(CFLAGS) -c -o $@ $<
-endif
-
-%.lo: %.c %.h
-ifeq ($(VERBOSE),0)
- @echo "${CC} $@"
- @$(CC) -DTESTLIB $(CFLAGS) -fPIC -c -o $@ $<
-else
- $(CC) -DTESTLIB $(CFLAGS) -fPIC -c -o $@ $<
-endif
-
--include $(OBJ:.o=.d)
-.PHONY: all clean clean-lib
+.PHONY: all clean
diff --git a/src/arh.c b/src/arh.c
deleted file mode 100644
index 6fd0f8e..0000000
--- a/src/arh.c
+++ /dev/null
@@ -1,199 +0,0 @@
-/**
- * vimb - a webkit based vim like browser.
- *
- * Copyright (C) 2012-2015 Daniel Carl
- * Copyright (C) 2014 Sébastien Marie
- *
- * 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, see http://www.gnu.org/licenses/.
- */
-
-#include "config.h"
-#ifdef FEATURE_ARH
-#include "ascii.h"
-#include "arh.h"
-#include "util.h"
-
-typedef struct {
- char *pattern; /* pattern the uri is matched against */
- GHashTable *headers; /* header list */
-} MatchARH;
-
-static void marh_free(MatchARH *);
-static char *read_pattern(char **);
-
-
-/**
- * parse the data string to a list of MatchARH
- *
- * pattern name=value[,...]
- */
-GSList *arh_parse(const char *data, const char **error)
-{
- GSList *parsed = NULL;
- GSList *data_list = NULL;
-
- /* parse data as comma separated list
- * of "pattern1 HEADERS-GROUP1","pattern2 HEADERS-GROUP2",... */
- data_list = soup_header_parse_list(data);
-
- /* iter the list for parsing each elements */
- for (GSList *l = data_list; l; l = g_slist_next(l)) {
- char *one_data = (char *)l->data;
- char *pattern;
- GHashTable *headers;
-
- /* remove QUOTE around one_data if any */
- if (one_data && *one_data == '"') {
- int last = strlen(one_data) - 1;
- if (last >= 0 && one_data[last] == '"') {
- one_data[last] = '\0';
- one_data++;
- }
- }
-
- /* read pattern and parse headers */
- pattern = read_pattern(&one_data);
- headers = soup_header_parse_param_list(one_data);
-
- /* check result (need a pattern and at least one header) */
- if (pattern && g_hash_table_size(headers)) {
- MatchARH *marh = g_slice_new0(MatchARH);
- marh->pattern = g_strdup(pattern);
- marh->headers = headers;
-
- parsed = g_slist_append(parsed, marh);
-
-#ifdef DEBUG
- PRINT_DEBUG("append pattern='%s' headers[%d]='0x%lx'",
- marh->pattern, g_hash_table_size(marh->headers), (long)marh->headers);
- GHashTableIter iterHeaders;
- const char *name, *value;
- g_hash_table_iter_init(&iterHeaders, headers);
- while (g_hash_table_iter_next(&iterHeaders, (gpointer)&name, (gpointer)&value)) {
- PRINT_DEBUG(" %s=%s", name, value);
- }
-#endif
- } else {
- /* an error occurs: cleanup */
- soup_header_free_param_list(headers);
- soup_header_free_list(data_list);
- arh_free(parsed);
-
- /* set error if asked */
- if (error != NULL) {
- *error = "syntax error";
- }
-
- return NULL;
- }
- }
-
- soup_header_free_list(data_list);
-
- return parsed;
-}
-
-/**
- * free the list of MatchARH
- */
-void arh_free(GSList *list)
-{
- g_slist_free_full(list, (GDestroyNotify)marh_free);
-}
-
-/**
- * append to reponse-header of SoupMessage,
- * the header that match the specified uri
- */
-void arh_run(GSList *list, const char *uri, SoupMessage *msg)
-{
- PRINT_DEBUG("uri: %s", uri);
-
- /* walk thought the list */
- for (GSList *l=list; l; l = g_slist_next(l)) {
- MatchARH *marh = (MatchARH *)l->data;
-
- if (util_wildmatch(marh->pattern, uri)) {
- GHashTableIter iter;
- const char *name = NULL;
- const char *value = NULL;
-
- g_hash_table_iter_init(&iter, marh->headers);
- while (g_hash_table_iter_next(&iter, (gpointer)&name, (gpointer)&value)) {
- if (value) {
- /* the pattern match, so replace headers
- * as side-effect, for one header the last matched will be keeped */
- soup_message_headers_replace(msg->response_headers, name, value);
-
- PRINT_DEBUG(" header added: %s: %s", name, value);
- } else {
- /* remove a previously setted auto-reponse-header */
- soup_message_headers_remove(msg->response_headers, name);
-
- PRINT_DEBUG(" header removed: %s", name);
- }
- }
- }
- }
-}
-
-/**
- * free a MatchARH
- */
-static void marh_free(MatchARH *marh)
-{
- if (marh) {
- g_free(marh->pattern);
- soup_header_free_param_list(marh->headers);
-
- g_slice_free(MatchARH, marh);
- }
-}
-
-/**
- * read until ' ' (or any other SPACE)
- */
-static char *read_pattern(char **line)
-{
- char *pattern;
-
- if (!*line || !**line) {
- return NULL;
- }
-
- /* remember where the pattern starts */
- pattern = *line;
-
- /* move pointer to the end of the pattern (or end-of-line) */
- while (**line && !VB_IS_SPACE(**line)) {
- (*line)++;
- }
-
- if (**line) {
- /* end the pattern */
- *(*line)++ = '\0';
-
- /* skip trailing whitespace */
- while (VB_IS_SPACE(**line)) {
- (*line)++;
- }
-
- return pattern;
-
- } else {
- /* end-of-line was encounter */
- return NULL;
- }
-}
-#endif
diff --git a/src/ascii.h b/src/ascii.h
index a5234e1..f375a30 100644
--- a/src/ascii.h
+++ b/src/ascii.h
@@ -73,11 +73,11 @@ static const unsigned char chartable[256] = {
/* CSI (control sequence introducer) is the first byte of a control sequence
* and is always followed by two bytes. */
-#define CSI 0x80
-#define CSI_STR "\x80"
+#define CSI 0x80
+#define CSI_STR "\x80"
/* get internal representation for conrol character ^C */
-#define CTRL(c) ((c) ^ 0x40)
+#define CTRL(c) ((c) ^ 0x40)
#define IS_SPECIAL(c) (c < 0)
@@ -95,7 +95,6 @@ static const unsigned char chartable[256] = {
#define KEY_DOWN TERMCAP2KEY('k', 'd')
#define KEY_LEFT TERMCAP2KEY('k', 'l')
#define KEY_RIGHT TERMCAP2KEY('k', 'r')
-
#define KEY_F1 TERMCAP2KEY('k', '1')
#define KEY_F2 TERMCAP2KEY('k', '2')
#define KEY_F3 TERMCAP2KEY('k', '3')
diff --git a/src/autocmd.c b/src/autocmd.c
deleted file mode 100644
index e856a4c..0000000
--- a/src/autocmd.c
+++ /dev/null
@@ -1,488 +0,0 @@
-/**
- * vimb - a webkit based vim like browser.
- *
- * Copyright (C) 2012-2015 Daniel Carl
- *
- * 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, see http://www.gnu.org/licenses/.
- */
-
-#include "config.h"
-#ifdef FEATURE_AUTOCMD
-#include "autocmd.h"
-#include "ascii.h"
-#include "ex.h"
-#include "util.h"
-#include "completion.h"
-
-typedef struct {
- guint bits; /* the bits identify the events the command applies to */
- char *excmd; /* ex command string to be run on matches event */
- char *pattern; /* list of patterns the uri is matched agains */
-} AutoCmd;
-
-typedef struct {
- char *name;
- GSList *cmds;
-} AuGroup;
-
-static struct {
- const char *name;
- guint bits;
-} events[] = {
- {"*", 0x00ff},
- {"LoadProvisional", 0x0001},
- {"LoadCommited", 0x0002},
- {"LoadFirstLayout", 0x0004},
- {"LoadFinished", 0x0008},
- {"LoadFailed", 0x0010},
- {"DownloadStart", 0x0020},
- {"DownloadFinished", 0x0040},
- {"DownloadFailed", 0x0080},
-};
-
-extern VbCore vb;
-
-static AuGroup *curgroup = NULL;
-static GSList *groups = NULL;
-static guint usedbits = 0; /* holds all used event bits */
-
-static GSList *get_group(const char *name);
-static guint get_event_bits(const char *name);
-static void rebuild_used_bits(void);
-static char *get_next_word(char **line);
-static AuGroup *new_group(const char *name);
-static void free_group(AuGroup *group);
-static AutoCmd *new_autocmd(const char *excmd, const char *pattern);
-static void free_autocmd(AutoCmd *cmd);
-
-
-void autocmd_init(void)
-{
- curgroup = new_group("end");
- groups = g_slist_prepend(groups, curgroup);
-}
-
-void autocmd_cleanup(void)
-{
- if (groups) {
- g_slist_free_full(groups, (GDestroyNotify)free_group);
- }
-}
-
-/**
- * Handle the :augroup {group} ex command.
- */
-gboolean autocmd_augroup(char *name, gboolean delete)
-{
- GSList *item;
-
- if (!*name) {
- return false;
- }
-
- /* check for group "end" that marks the default group */
- if (!strcmp(name, "end")) {
- curgroup = (AuGroup*)groups->data;
- return true;
- }
-
- item = get_group(name);
-
- /* check if the group is going to be removed */
- if (delete) {
- /* group does not exist - so do nothing */
- if (!item) {
- return true;
- }
- if (curgroup == (AuGroup*)item->data) {
- /* if the group to delete is the current - switch the the default
- * group after removing it */
- curgroup = (AuGroup*)groups->data;
- }
-
- /* now remove the group */
- free_group((AuGroup*)item->data);
- groups = g_slist_delete_link(groups, item);
-
- /* there where autocmds remove - so recreate the usedbits */
- rebuild_used_bits();
-
- return true;
- }
-
- /* check if the group does already exists */
- if (item) {
- /* if the group is found in the known groups use it as current */
- curgroup = (AuGroup*)item->data;
-
- return true;
- }
-
- /* create a new group and use it as current */
- curgroup = new_group(name);
-
- /* append it to known groups */
- groups = g_slist_prepend(groups, curgroup);
-
- return true;
-}
-
-/**
- * Add or delete auto commands.
- *
- * :au[tocmd]! [group] {event} {pat} [nested] {cmd}
- * group and nested flag are not supported at the moment.
- */
-gboolean autocmd_add(char *name, gboolean delete)
-{
- guint bits;
- char *parse, *word, *pattern, *excmd;
- GSList *item;
- AuGroup *grp = NULL;
-
- parse = name;
-
- /* parse group name if it's there */
- word = get_next_word(&parse);
- if (word) {
- /* check if the word is a known group name */
- item = get_group(word);
- if (item) {
- grp = (AuGroup*)item->data;
-
- /* group is found - get the next word */
- word = get_next_word(&parse);
- }
- }
- if (!grp) {
- /* no group found - use the current one */
- grp = curgroup;
- }
-
- /* parse event name - if none was matched run it for all events */
- if (word) {
- bits = get_event_bits(word);
- if (!bits) {
- return false;
- }
- word = get_next_word(&parse);
- } else {
- bits = events[AU_ALL].bits;
- }
-
- /* last word is the pattern - if not found use '*' */
- pattern = word ? word : "*";
-
- /* the rest of the line becoes the ex command to run */
- if (parse && !*parse) {
- parse = NULL;
- }
- excmd = parse;
-
- /* delete the autocmd if bang was given */
- if (delete) {
- GSList *lc;
- AutoCmd *cmd;
- gboolean removed = false;
-
- /* check if the group does already exists */
- for (lc = grp->cmds; lc; lc = lc->next) {
- cmd = (AutoCmd*)lc->data;
- /* if not bits match - skip the command */
- if (!(cmd->bits & bits)) {
- continue;
- }
- /* skip if pattern does not match - we check the pattern against
- * another pattern */
- if (!util_wildmatch(pattern, cmd->pattern)) {
- continue;
- }
- /* remove the bits from the item */
- cmd->bits &= ~bits;
-
- /* if the command has no matching events - remove it */
- grp->cmds = g_slist_delete_link(grp->cmds, lc);
- free_autocmd(cmd);
-
- removed = true;
- }
-
- /* if ther was at least one command removed - rebuilt the used bits */
- if (removed) {
- rebuild_used_bits();
- }
-
- return true;
- }
-
- /* add the new autocmd */
- if (excmd && grp) {
- AutoCmd *cmd = new_autocmd(excmd, pattern);
- cmd->bits = bits;
-
- /* add the new autocmd to the group */
- grp->cmds = g_slist_append(grp->cmds, cmd);
-
- /* merge the autocmd bits into the used bits */
- usedbits |= cmd->bits;
- }
-
- return true;
-}
-
-/**
- * Run named auto command.
- */
-gboolean autocmd_run(AuEvent event, const char *uri, const char *group)
-{
- GSList *lg, *lc;
- AuGroup *grp;
- AutoCmd *cmd;
- guint bits = events[event].bits;
-
- /* if there is no autocmd for this event - skip here */
- if (!(usedbits & bits)) {
- return true;
- }
-
- /* loop over the groups and find matching commands */
- for (lg = groups; lg; lg = lg->next) {
- grp = lg->data;
- /* if a group was given - skip all none matching groupes */
- if (group && strcmp(group, grp->name)) {
- continue;
- }
- /* test each command in group */
- for (lc = grp->cmds; lc; lc = lc->next) {
- cmd = lc->data;
- /* skip if this dos not match the event bits */
- if (!(bits & cmd->bits)) {
- continue;
- }
- /* check pattern only if uri was given */
- /* skip if pattern does not match */
- if (uri && !util_wildmatch(cmd->pattern, uri)) {
- continue;
- }
- /* run the command */
- /* TODO shoult the result be tested for RESULT_COMPLETE? */
- /* run command and make sure it's not writte to command history */
- ex_run_string(cmd->excmd, false);
- }
- }
-
- return true;
-}
-
-gboolean autocmd_fill_group_completion(GtkListStore *store, const char *input)
-{
- GSList *lg;
- gboolean found = false;
- GtkTreeIter iter;
-
- if (!input || !*input) {
- for (lg = groups; lg; lg = lg->next) {
- gtk_list_store_append(store, &iter);
- gtk_list_store_set(store, &iter, COMPLETION_STORE_FIRST, ((AuGroup*)lg->data)->name, -1);
- found = true;
- }
- } else {
- for (lg = groups; lg; lg = lg->next) {
- char *value = ((AuGroup*)lg->data)->name;
- if (g_str_has_prefix(value, input)) {
- gtk_list_store_append(store, &iter);
- gtk_list_store_set(store, &iter, COMPLETION_STORE_FIRST, value, -1);
- found = true;
- }
- }
- }
-
- return found;
-}
-
-gboolean autocmd_fill_event_completion(GtkListStore *store, const char *input)
-{
- int i;
- const char *value;
- gboolean found = false;
- GtkTreeIter iter;
-
- if (!input || !*input) {
- for (i = 0; i < LENGTH(events); i++) {
- gtk_list_store_append(store, &iter);
- gtk_list_store_set(store, &iter, COMPLETION_STORE_FIRST, events[i].name, -1);
- found = true;
- }
- } else {
- for (i = 0; i < LENGTH(events); i++) {
- value = events[i].name;
- if (g_str_has_prefix(value, input)) {
- gtk_list_store_append(store, &iter);
- gtk_list_store_set(store, &iter, COMPLETION_STORE_FIRST, value, -1);
- found = true;
- }
- }
- }
-
- return found;
-}
-
-/**
- * Get the augroup by it's name.
- */
-static GSList *get_group(const char *name)
-{
- GSList *lg;
- AuGroup *grp;
-
- for (lg = groups; lg; lg = lg->next) {
- grp = lg->data;
- if (!strcmp(grp->name, name)) {
- return lg;
- }
- }
-
- return NULL;
-}
-
-static guint get_event_bits(const char *name)
-{
- int result = 0;
-
- while (*name) {
- int i, len;
- for (i = 0; i < LENGTH(events); i++) {
- /* we count the chars that given name has in common with the
- * current processed event */
- len = 0;
- while (name[len] && events[i].name[len] && name[len] == events[i].name[len]) {
- len++;
- }
-
- /* check if the matching chars built a full word match */
- if (events[i].name[len] == '\0'
- && (name[len] == '\0' || name[len] == ',')
- ) {
- /* add the bits to the result */
- result |= events[i].bits;
-
- /* move pointer after the match and skip possible ',' */
- name += len;
- if (*name == ',') {
- name++;
- }
- break;
- }
- }
-
- /* check if the end was reached without a match */
- if (i >= LENGTH(events)) {
- /* is this the right place to write the error */
- vb_echo(VB_MSG_ERROR, true, "Bad autocmd event name: %s", name);
- return 0;
- }
- }
-
- return result;
-}
-
-/**
- * Rebuild the usedbits from scratch.
- * Save all used autocmd event bits in the bitmap.
- */
-static void rebuild_used_bits(void)
-{
- GSList *lc, *lg;
- AuGroup *grp;
-
- /* clear the current set bits */
- usedbits = 0;
- /* loop over the groups */
- for (lg = groups; lg; lg = lg->next) {
- grp = (AuGroup*)lg->data;
-
- /* merge the used event bints into the bitmap */
- for (lc = grp->cmds; lc; lc = lc->next) {
- usedbits |= ((AutoCmd*)lc->data)->bits;
- }
- }
-}
-
-/**
- * Get the next word from given line.
- * Given line pointer is set past the word and and a 0-byte is added there.
- */
-static char *get_next_word(char **line)
-{
- char *word;
-
- if (!*line || !**line) {
- return NULL;
- }
-
- /* remember where the word starts */
- word = *line;
-
- /* move pointer to the end of the word or of the line */
- while (**line && !VB_IS_SPACE(**line)) {
- (*line)++;
- }
-
- /* end the word */
- if (**line) {
- *(*line)++ = '\0';
- }
-
- /* skip trailing whitespace */
- while (VB_IS_SPACE(**line)) {
- (*line)++;
- }
-
- return word;
-}
-
-static AuGroup *new_group(const char *name)
-{
- AuGroup *new = g_slice_new(AuGroup);
- new->name = g_strdup(name);
- new->cmds = NULL;
-
- return new;
-}
-
-static void free_group(AuGroup *group)
-{
- g_free(group->name);
- if (group->cmds) {
- g_slist_free_full(group->cmds, (GDestroyNotify)free_autocmd);
- }
- g_slice_free(AuGroup, group);
-}
-
-static AutoCmd *new_autocmd(const char *excmd, const char *pattern)
-{
- AutoCmd *new = g_slice_new(AutoCmd);
- new->excmd = g_strdup(excmd);
- new->pattern = g_strdup(pattern);
- return new;
-}
-
-static void free_autocmd(AutoCmd *cmd)
-{
- g_free(cmd->excmd);
- g_free(cmd->pattern);
- g_slice_free(AutoCmd, cmd);
-}
-
-#endif
diff --git a/src/autocmd.h b/src/autocmd.h
deleted file mode 100644
index aef09a2..0000000
--- a/src/autocmd.h
+++ /dev/null
@@ -1,50 +0,0 @@
-/**
- * vimb - a webkit based vim like browser.
- *
- * Copyright (C) 2012-2015 Daniel Carl
- *
- * 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, see http://www.gnu.org/licenses/.
- */
-
-#include "config.h"
-#ifdef FEATURE_AUTOCMD
-
-#ifndef _AUTOCMD_H
-#define _AUTOCMD_H
-
-#include "main.h"
-
-/* this values correspond to indices in events[] array in autocmd.c */
-typedef enum {
- AU_ALL,
- AU_LOAD_PROVISIONAL,
- AU_LOAD_COMMITED,
- AU_LOAD_FIRST_LAYOUT,
- AU_LOAD_FINISHED,
- AU_LOAD_FAILED,
- AU_DOWNLOAD_START,
- AU_DOWNLOAD_FINISHED,
- AU_DOWNLOAD_FAILED,
-} AuEvent;
-
-void autocmd_init(void);
-void autocmd_cleanup(void);
-gboolean autocmd_augroup(char *name, gboolean delete);
-gboolean autocmd_add(char *name, gboolean delete);
-gboolean autocmd_run(AuEvent event, const char *uri, const char *group);
-gboolean autocmd_fill_group_completion(GtkListStore *store, const char *input);
-gboolean autocmd_fill_event_completion(GtkListStore *store, const char *input);
-
-#endif /* end of include guard: _AUTOCMD_H */
-#endif
diff --git a/src/bookmark.c b/src/bookmark.c
deleted file mode 100644
index adc2e03..0000000
--- a/src/bookmark.c
+++ /dev/null
@@ -1,326 +0,0 @@
-/**
- * vimb - a webkit based vim like browser.
- *
- * Copyright (C) 2012-2015 Daniel Carl
- *
- * 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, see http://www.gnu.org/licenses/.
- */
-
-#include "config.h"
-#include "main.h"
-#include "bookmark.h"
-#include "util.h"
-#include "completion.h"
-
-extern VbCore vb;
-
-typedef struct {
- char *uri;
- char *title;
- char *tags;
-} Bookmark;
-
-static GList *load(const char *file);
-static gboolean bookmark_contains_all_tags(Bookmark *bm, char **query,
- unsigned int qlen);
-static Bookmark *line_to_bookmark(const char *uri, const char *data);
-static void free_bookmark(Bookmark *bm);
-
-/**
- * Write a new bookmark entry to the end of bookmark file.
- */
-gboolean bookmark_add(const char *uri, const char *title, const char *tags)
-{
- const char *file = vb.files[FILES_BOOKMARK];
- if (tags) {
- return util_file_append(file, "%s\t%s\t%s\n", uri, title ? title : "", tags);
- }
- if (title) {
- return util_file_append(file, "%s\t%s\n", uri, title);
- }
- return util_file_append(file, "%s\n", uri);
-}
-
-gboolean bookmark_remove(const char *uri)
-{
- char **lines, *line, *p;
- int len, i;
- GString *new;
- gboolean removed = false;
-
- if (!uri) {
- return false;
- }
-
- lines = util_get_lines(vb.files[FILES_BOOKMARK]);
- if (lines) {
- new = g_string_new(NULL);
- len = g_strv_length(lines) - 1;
- for (i = 0; i < len; i++) {
- line = lines[i];
- g_strstrip(line);
- /* ignore the title or bookmark tags and test only the uri */
- if ((p = strchr(line, '\t'))) {
- *p = '\0';
- if (!strcmp(uri, line)) {
- removed = true;
- continue;
- } else {
- /* reappend the tags */
- *p = '\t';
- }
- }
- if (!strcmp(uri, line)) {
- removed = true;
- continue;
- }
- g_string_append_printf(new, "%s\n", line);
- }
- g_strfreev(lines);
- g_file_set_contents(vb.files[FILES_BOOKMARK], new->str, -1, NULL);
- g_string_free(new, true);
- }
-
- return removed;
-}
-
-gboolean bookmark_fill_completion(GtkListStore *store, const char *input)
-{
- gboolean found = false;
- char **parts;
- unsigned int len;
- GtkTreeIter iter;
- GList *src = NULL;
- Bookmark *bm;
-
- src = load(vb.files[FILES_BOOKMARK]);
- src = g_list_reverse(src);
- if (!input || !*input) {
- /* without any tags return all bookmarked items */
- for (GList *l = src; l; l = l->next) {
- bm = (Bookmark*)l->data;
- gtk_list_store_append(store, &iter);
- gtk_list_store_set(
- store, &iter,
- COMPLETION_STORE_FIRST, bm->uri,
-#ifdef FEATURE_TITLE_IN_COMPLETION
- COMPLETION_STORE_SECOND, bm->title,
-#endif
- -1
- );
- found = true;
- }
- } else {
- parts = g_strsplit(input, " ", 0);
- len = g_strv_length(parts);
-
- for (GList *l = src; l; l = l->next) {
- bm = (Bookmark*)l->data;
- if (bookmark_contains_all_tags(bm, parts, len)) {
- gtk_list_store_append(store, &iter);
- gtk_list_store_set(
- store, &iter,
- COMPLETION_STORE_FIRST, bm->uri,
-#ifdef FEATURE_TITLE_IN_COMPLETION
- COMPLETION_STORE_SECOND, bm->title,
-#endif
- -1
- );
- found = true;
- }
- }
- g_strfreev(parts);
- }
-
- g_list_free_full(src, (GDestroyNotify)free_bookmark);
-
- return found;
-}
-
-gboolean bookmark_fill_tag_completion(GtkListStore *store, const char *input)
-{
- gboolean found;
- unsigned int len, i;
- char **tags, *tag;
- GList *src = NULL, *taglist = NULL;
- Bookmark *bm;
-
- /* get all distinct tags from bookmark file */
- src = load(vb.files[FILES_BOOKMARK]);
- for (GList *l = src; l; l = l->next) {
- bm = (Bookmark*)l->data;
- /* if bookmark contains no tags we can go to the next bookmark */
- if (!bm->tags) {
- continue;
- }
-
- tags = g_strsplit(bm->tags, " ", -1);
- len = g_strv_length(tags);
- for (i = 0; i < len; i++) {
- tag = tags[i];
- /* add tag only if it isn't already in the list */
- if (!g_list_find_custom(taglist, tag, (GCompareFunc)strcmp)) {
- taglist = g_list_prepend(taglist, g_strdup(tag));
- }
- }
- g_strfreev(tags);
- }
-
- /* generate the completion with the found tags */
- found = util_fill_completion(store, input, taglist);
-
- g_list_free_full(src, (GDestroyNotify)free_bookmark);
- g_list_free_full(taglist, (GDestroyNotify)g_free);
-
- return found;
-}
-
-#ifdef FEATURE_QUEUE
-/**
- * Push a uri to the end of the queue.
- *
- * @uri: URI to put into the queue
- */
-gboolean bookmark_queue_push(const char *uri)
-{
- return util_file_append(vb.files[FILES_QUEUE], "%s\n", uri);
-}
-
-/**
- * Push a uri to the beginning of the queue.
- *
- * @uri: URI to put into the queue
- */
-gboolean bookmark_queue_unshift(const char *uri)
-{
- return util_file_prepend(vb.files[FILES_QUEUE], "%s\n", uri);
-}
-
-/**
- * Retrieves the oldest entry from queue.
- *
- * @item_count: will be filled with the number of remaining items in queue.
- * Returned uri must be freed with g_free.
- */
-char *bookmark_queue_pop(int *item_count)
-{
- return util_file_pop_line(vb.files[FILES_QUEUE], item_count);
-}
-
-/**
- * Removes all contents from the queue file.
- */
-gboolean bookmark_queue_clear(void)
-{
- FILE *f;
- if ((f = fopen(vb.files[FILES_QUEUE], "w"))) {
- fclose(f);
- return true;
- }
- return false;
-}
-#endif /* FEATURE_QUEUE */
-
-static GList *load(const char *file)
-{
- return util_file_to_unique_list(file, (Util_Content_Func)line_to_bookmark, 0);
-}
-
-/**
- * Checks if the given bookmark matches all given query strings as prefix. If
- * the bookmark has no tags, the matching is done on the '/' splited URL.
- *
- * @bm: bookmark to test if it matches
- * @query: char array with tags to search for
- * @qlen: length of given query char array
- *
- * Return: true if the bookmark contained all tags
- */
-static gboolean bookmark_contains_all_tags(Bookmark *bm, char **query,
- unsigned int qlen)
-{
- const char *separators;
- char *cursor;
- unsigned int i;
- gboolean found;
-
- if (!qlen) {
- return true;
- }
-
- if (bm->tags) {
- /* If there are tags - use them for matching. */
- separators = " ";
- cursor = bm->tags;
- } else {
- /* No tags available - matching is based on the path parts of the URL. */
- separators = "./";
- cursor = bm->uri;
- }
-
- /* iterate over all query parts */
- for (i = 0; i < qlen; i++) {
- found = false;
-
- /* we want to do a prefix match on all bookmark tags - so we check for
- * a match on string begin - if this fails we move the cursor to the
- * next space and do the test again */
- while (cursor && *cursor) {
- /* match was not found at current cursor position */
- if (g_str_has_prefix(cursor, query[i])) {
- found = true;
- break;
- }
- /* If match was not found at the cursor position - move cursor
- * behind the next separator char. */
- if ((cursor = strpbrk(cursor, separators))) {
- cursor++;
- }
- }
-
- if (!found) {
- return false;
- }
- }
-
- return true;
-}
-
-static Bookmark *line_to_bookmark(const char *uri, const char *data)
-{
- char *p;
- Bookmark *bm;
-
- /* data part may consist of title or title<tab>tags */
- bm = g_slice_new(Bookmark);
- bm->uri = g_strdup(uri);
- if (data && (p = strchr(data, '\t'))) {
- *p = '\0';
- bm->title = g_strdup(data);
- bm->tags = g_strdup(p + 1);
- } else {
- bm->title = g_strdup(data);
- bm->tags = NULL;
- }
-
- return bm;
-}
-
-static void free_bookmark(Bookmark *bm)
-{
- g_free(bm->uri);
- g_free(bm->title);
- g_free(bm->tags);
- g_slice_free(Bookmark, bm);
-}
diff --git a/src/bookmark.h b/src/bookmark.h
deleted file mode 100644
index 32aaba4..0000000
--- a/src/bookmark.h
+++ /dev/null
@@ -1,34 +0,0 @@
-/**
- * vimb - a webkit based vim like browser.
- *
- * Copyright (C) 2012-2015 Daniel Carl
- *
- * 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, see http://www.gnu.org/licenses/.
- */
-
-#ifndef _BOOKMARK_H
-#define _BOOKMARK_H
-
-gboolean bookmark_add(const char *uri, const char *title, const char *tags);
-gboolean bookmark_remove(const char *uri);
-gboolean bookmark_fill_completion(GtkListStore *store, const char *input);
-gboolean bookmark_fill_tag_completion(GtkListStore *store, const char *input);
-#ifdef FEATURE_QUEUE
-gboolean bookmark_queue_push(const char *uri);
-gboolean bookmark_queue_unshift(const char *uri);
-char *bookmark_queue_pop(int *item_count);
-gboolean bookmark_queue_clear(void);
-#endif
-
-#endif /* end of include guard: _BOOKMARK_H */
diff --git a/src/command.c b/src/command.c
index a5bb9f2..c957c46 100644
--- a/src/command.c
+++ b/src/command.c
@@ -21,128 +21,86 @@
* This file contains functions that are used by normal mode and command mode
* together.
*/
-#include "config.h"
-#include "main.h"
#include "command.h"
+#include "config.h"
#include "history.h"
-#include "bookmark.h"
+#include "main.h"
+#include <stdlib.h>
-extern VbCore vb;
+extern struct Vimb vb;
-gboolean command_search(const Arg *arg)
+gboolean command_search(Client *c, const Arg *arg)
{
- static short dir; /* last direction 1 forward, -1 backward*/
const char *query;
- static gboolean newsearch = true;
gboolean forward;
+ WebKitFindController *fc;
+ fc = webkit_web_view_get_find_controller(c->webview);
if (arg->i == 0) {
-#ifdef FEATURE_SEARCH_HIGHLIGHT
- webkit_web_view_unmark_text_matches(vb.gui.webview);
- vb.state.search_matches = 0;
- vb_update_statusbar();
-#endif
- newsearch = true;
- return true;
+ webkit_find_controller_search_finish(fc);
+ c->state.search.matches = 0;
+ c->state.search.active = FALSE;
+ vb_statusbar_update(c);
+ return TRUE;
}
/* copy search query for later use */
if (arg->s) {
/* set search direction only when the searching is started */
- dir = arg->i > 0 ? 1 : -1;
+ c->state.search.direction = arg->i > 0 ? 1 : -1;
query = arg->s;
/* add new search query to history and search register */
- vb_register_add('/', query);
- history_add(HISTORY_SEARCH, query, NULL);
+ vb_register_add(c, '/', query);
+ history_add(c, HISTORY_SEARCH, query, NULL);
} else {
/* no search phrase given - continue a previous search */
- query = vb_register_get('/');
+ query = vb_register_get(c, '/');
}
- forward = (arg->i * dir) > 0;
+ forward = (arg->i * c->state.search.direction) > 0;
if (query) {
- unsigned int count = abs(arg->i);
- if (newsearch) {
-#ifdef FEATURE_SEARCH_HIGHLIGHT
- /* highlight matches if the search is started new or continued
- * after switch to normal mode which calls this function with
- * COMMAND_SEARCH_OFF */
- vb.state.search_matches = webkit_web_view_mark_text_matches(vb.gui.webview, query, false, 0);
- webkit_web_view_set_highlight_text_matches(vb.gui.webview, true);
- vb_update_statusbar();
-#endif
- newsearch = false;
- /* skip first search because this is done during typing in ex
- * mode, else the search will mark the next match as active */
- if (count) {
- count -= 1;
- }
+ guint count = abs(arg->i);
+
+ if (!c->state.search.active) {
+ webkit_find_controller_search(fc, query,
+ WEBKIT_FIND_OPTIONS_CASE_INSENSITIVE |
+ WEBKIT_FIND_OPTIONS_WRAP_AROUND |
+ (forward ? WEBKIT_FIND_OPTIONS_NONE : WEBKIT_FIND_OPTIONS_BACKWARDS),
+ G_MAXUINT);
+ c->state.search.active = TRUE;
+ /* Skip first search because the first match is already
+ * highlighted on search start. */
+ count -= 1;
}
- while (count--) {
- if (!webkit_web_view_search_text(vb.gui.webview, query, false, forward, true)) {
- break;
- }
- };
+ if (forward) {
+ while (count--) {
+ webkit_find_controller_search_next(fc);
+ };
+ } else {
+ while (count--) {
+ webkit_find_controller_search_previous(fc);
+ };
+ }
}
- return true;
+ return TRUE;
}
-gboolean command_yank(const Arg *arg, char buf)
+gboolean command_yank(Client *c, const Arg *arg, char buf)
{
- static char *tmpl = "Yanked: %s";
-
- if (arg->i == COMMAND_YANK_SELECTION) {
- char *text = NULL;
- /* copy current selection to clipboard */
- webkit_web_view_copy_clipboard(vb.gui.webview);
- text = gtk_clipboard_wait_for_text(PRIMARY_CLIPBOARD());
- if (!text) {
- text = gtk_clipboard_wait_for_text(SECONDARY_CLIPBOARD());
- }
- if (text) {
- /* save in given register and default "" register */
- vb_register_add(buf, text);
- vb_register_add('"', text);
- vb_echo(VB_MSG_NORMAL, false, tmpl, text);
- g_free(text);
-
- return true;
- }
-
- return false;
- }
-
- Arg a = {VB_CLIPBOARD_PRIMARY|VB_CLIPBOARD_SECONDARY};
- if (arg->i == COMMAND_YANK_URI) {
- /* yank current uri */
- a.s = vb.state.uri;
- } else {
- /* use current arg.s as new clipboard content */
- a.s = arg->s;
- }
- if (a.s) {
- vb_set_clipboard(&a);
- /* save in given register and default "" register */
- vb_register_add(buf, a.s);
- vb_register_add('"', a.s);
- vb_echo(VB_MSG_NORMAL, false, tmpl, a.s);
-
- return true;
- }
-
- return false;
+ /* TODO no implemented yet */
+ return TRUE;
}
-gboolean command_save(const Arg *arg)
+gboolean command_save(Client *c, const Arg *arg)
{
- WebKitDownload *download;
+#if 0
const char *uri, *path = NULL;
if (arg->i == COMMAND_SAVE_CURRENT) {
- uri = vb.state.uri;
+ uri = c->state.uri;
/* given string is the path to save the download to */
if (arg->s && *(arg->s) != '\0') {
path = arg->s;
@@ -152,52 +110,18 @@ gboolean command_save(const Arg *arg)
}
if (!uri || !*uri) {
- return false;
+ return FALSE;
}
+#endif
- download = webkit_download_new(webkit_network_request_new(uri));
- vb_download(vb.gui.webview, download, path);
-
- return true;
+ /* TODO start the download to given path here */
+ return TRUE;
}
#ifdef FEATURE_QUEUE
-gboolean command_queue(const Arg *arg)
+gboolean command_queue(Client *c, const Arg *arg)
{
- gboolean res = false;
- int count = 0;
- char *uri;
-
- switch (arg->i) {
- case COMMAND_QUEUE_POP:
- if ((uri = bookmark_queue_pop(&count))) {
- res = vb_load_uri(&(Arg){VB_TARGET_CURRENT, uri});
- g_free(uri);
- }
- vb_echo(VB_MSG_NORMAL, false, "Queue length %d", count);
- break;
-
- case COMMAND_QUEUE_PUSH:
- res = bookmark_queue_push(arg->s ? arg->s : vb.state.uri);
- if (res) {
- vb_echo(VB_MSG_NORMAL, false, "Pushed to queue");
- }
- break;
-
- case COMMAND_QUEUE_UNSHIFT:
- res = bookmark_queue_unshift(arg->s ? arg->s : vb.state.uri);
- if (res) {
- vb_echo(VB_MSG_NORMAL, false, "Pushed to queue");
- }
- break;
-
- case COMMAND_QUEUE_CLEAR:
- if (bookmark_queue_clear()) {
- vb_echo(VB_MSG_NORMAL, false, "Queue cleared");
- }
- break;
- }
-
- return res;
+ /* TODO no implemented yet */
+ return TRUE;
}
#endif
diff --git a/src/command.h b/src/command.h
index 68c8d85..92cf494 100644
--- a/src/command.h
+++ b/src/command.h
@@ -20,6 +20,9 @@
#ifndef _COMMAND_H
#define _COMMAND_H
+#include <gtk/gtk.h>
+#include "main.h"
+
enum {
COMMAND_YANK_ARG,
COMMAND_YANK_URI,
@@ -40,11 +43,11 @@ enum {
};
#endif
-gboolean command_search(const Arg *arg);
-gboolean command_yank(const Arg *arg, char buf);
-gboolean command_save(const Arg *arg);
+gboolean command_search(Client *c, const Arg *arg);
+gboolean command_yank(Client *c, const Arg *arg, char buf);
+gboolean command_save(Client *c, const Arg *arg);
#ifdef FEATURE_QUEUE
-gboolean command_queue(const Arg *arg);
+gboolean command_queue(Client *c, const Arg *arg);
#endif
#endif /* end of include guard: _COMMAND_H */
diff --git a/src/completion.c b/src/completion.c
index a15b081..8bfb9b0 100644
--- a/src/completion.c
+++ b/src/completion.c
@@ -17,25 +17,54 @@
* along with this program. If not, see http://www.gnu.org/licenses/.
*/
+#include "completion.h"
#include "config.h"
#include "main.h"
-#include "completion.h"
-
-extern VbCore vb;
-static struct {
- GtkWidget *win;
- GtkWidget *tree;
- int active; /* number of the current active tree item */
- CompletionSelectFunc selfunc;
-} comp;
+typedef struct {
+ GtkWidget *win, *tree;
+ int active; /* number of the current active tree item */
+ CompletionSelectFunc selfunc;
+} Completion;
static gboolean tree_selection_func(GtkTreeSelection *selection,
GtkTreeModel *model, GtkTreePath *path, gboolean selected, gpointer data);
+extern struct Vimb vb;
-gboolean completion_create(GtkTreeModel *model, CompletionSelectFunc selfunc,
- gboolean back)
+
+/**
+ * Stop the completion and reset temporary used data.
+ */
+void completion_clean(Client *c)
+{
+ Completion *comp = (Completion*)c->comp;
+ c->mode->flags &= ~FLAG_COMPLETION;
+
+ if (comp->win) {
+ gtk_widget_destroy(comp->win);
+ comp->win = NULL;
+ comp->tree = NULL;
+ }
+}
+
+/**
+ * Free the memory of the completion set on the client.
+ */
+void completion_cleanup(Client *c)
+{
+ if (c->comp) {
+ g_slice_free(Completion, c->comp);
+ c->comp = NULL;
+ }
+}
+
+/**
+ * Start the completion by creating the required widgets and setting a select
+ * function.
+ */
+gboolean completion_create(Client *c, GtkTreeModel *model,
+ CompletionSelectFunc selfunc, gboolean back)
{
GtkCellRenderer *renderer;
GtkTreeSelection *selection;
@@ -44,6 +73,7 @@ gboolean completion_create(GtkTreeModel *model, CompletionSelectFunc selfunc,
GtkTreePath *path;
GtkTreeIter iter;
int height, width;
+ Completion *comp = (Completion*)c->comp;
/* if there is only one match - don't build the tree view */
if (gtk_tree_model_iter_n_children(model, NULL) == 1) {
@@ -53,59 +83,56 @@ gboolean completion_create(GtkTreeModel *model, CompletionSelectFunc selfunc,
gtk_tree_model_get(model, &iter, COMPLETION_STORE_FIRST, &value, -1);
/* call the select function */
- selfunc(value);
+ selfunc(c, value);
g_free(value);
g_object_unref(model);
- return false;
+ return FALSE;
}
}
- comp.selfunc = selfunc;
+ comp->selfunc = selfunc;
/* prepare the tree view */
- comp.win = gtk_scrolled_window_new(NULL, NULL);
- comp.tree = gtk_tree_view_new();
-#ifndef HAS_GTK3
- gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(comp.win), GTK_POLICY_NEVER, GTK_POLICY_NEVER);
-#endif
- gtk_box_pack_end(GTK_BOX(vb.gui.box), comp.win, false, false, 0);
- gtk_container_add(GTK_CONTAINER(comp.win), comp.tree);
+ comp->win = gtk_scrolled_window_new(NULL, NULL);
+ comp->tree = gtk_tree_view_new();
+
+ GtkCssProvider* provider = gtk_css_provider_get_default();
+ gtk_css_provider_load_from_data(provider, GUI_STYLE, -1, NULL);
+ gtk_style_context_add_provider(gtk_widget_get_style_context(comp->tree),
+ GTK_STYLE_PROVIDER(provider),
+ GTK_STYLE_PROVIDER_PRIORITY_APPLICATION);
- gtk_tree_view_set_headers_visible(GTK_TREE_VIEW(comp.tree), false);
+ gtk_box_pack_end(GTK_BOX(gtk_widget_get_parent(GTK_WIDGET(c->statusbar.box))), comp->win, FALSE, FALSE, 0);
+ gtk_container_add(GTK_CONTAINER(comp->win), comp->tree);
+
+ gtk_tree_view_set_headers_visible(GTK_TREE_VIEW(comp->tree), FALSE);
/* we have only on line per item so we can use the faster fixed heigh mode */
- gtk_tree_view_set_fixed_height_mode(GTK_TREE_VIEW(comp.tree), true);
- gtk_tree_view_set_model(GTK_TREE_VIEW(comp.tree), model);
+ gtk_tree_view_set_fixed_height_mode(GTK_TREE_VIEW(comp->tree), TRUE);
+ gtk_tree_view_set_model(GTK_TREE_VIEW(comp->tree), model);
g_object_unref(model);
- VB_WIDGET_OVERRIDE_TEXT(comp.tree, VB_GTK_STATE_NORMAL, &vb.style.comp_fg[VB_COMP_NORMAL]);
- VB_WIDGET_OVERRIDE_BASE(comp.tree, VB_GTK_STATE_NORMAL, &vb.style.comp_bg[VB_COMP_NORMAL]);
- VB_WIDGET_OVERRIDE_TEXT(comp.tree, VB_GTK_STATE_SELECTED, &vb.style.comp_fg[VB_COMP_ACTIVE]);
- VB_WIDGET_OVERRIDE_BASE(comp.tree, VB_GTK_STATE_SELECTED, &vb.style.comp_bg[VB_COMP_ACTIVE]);
- VB_WIDGET_OVERRIDE_TEXT(comp.tree, VB_GTK_STATE_ACTIVE, &vb.style.comp_fg[VB_COMP_ACTIVE]);
- VB_WIDGET_OVERRIDE_BASE(comp.tree, VB_GTK_STATE_ACTIVE, &vb.style.comp_bg[VB_COMP_ACTIVE]);
-
/* prepare the selection */
- selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(comp.tree));
+ selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(comp->tree));
gtk_tree_selection_set_mode(selection, GTK_SELECTION_BROWSE);
- gtk_tree_selection_set_select_function(selection, tree_selection_func, NULL, NULL);
+ gtk_tree_selection_set_select_function(selection, tree_selection_func, c, NULL);
/* get window dimension */
- gtk_window_get_size(GTK_WINDOW(vb.gui.window), &width, &height);
+ gtk_window_get_size(GTK_WINDOW(c->window), &width, &height);
/* prepare first column */
column = gtk_tree_view_column_new();
gtk_tree_view_column_set_sizing(column, GTK_TREE_VIEW_COLUMN_FIXED);
- gtk_tree_view_append_column(GTK_TREE_VIEW(comp.tree), column);
+ gtk_tree_view_append_column(GTK_TREE_VIEW(comp->tree), column);
renderer = gtk_cell_renderer_text_new();
g_object_set(renderer,
- "font-desc", vb.style.comp_font,
+ "font-desc", c->config.comp_font,
"ellipsize", PANGO_ELLIPSIZE_MIDDLE,
NULL
);
- gtk_tree_view_column_pack_start(column, renderer, true);
+ gtk_tree_view_column_pack_start(column, renderer, TRUE);
gtk_tree_view_column_add_attribute(column, renderer, "text", COMPLETION_STORE_FIRST);
gtk_tree_view_column_set_min_width(column, 2 * width/3);
@@ -113,20 +140,20 @@ gboolean completion_create(GtkTreeModel *model, CompletionSelectFunc selfunc,
#ifdef FEATURE_TITLE_IN_COMPLETION
column = gtk_tree_view_column_new();
gtk_tree_view_column_set_sizing(column, GTK_TREE_VIEW_COLUMN_FIXED);
- gtk_tree_view_append_column(GTK_TREE_VIEW(comp.tree), column);
+ gtk_tree_view_append_column(GTK_TREE_VIEW(comp->tree), column);
renderer = gtk_cell_renderer_text_new();
g_object_set(renderer,
- "font-desc", vb.style.comp_font,
+ "font-desc", c->config.comp_font,
"ellipsize", PANGO_ELLIPSIZE_END,
NULL
);
- gtk_tree_view_column_pack_start(column, renderer, true);
+ gtk_tree_view_column_pack_start(column, renderer, TRUE);
gtk_tree_view_column_add_attribute(column, renderer, "text", COMPLETION_STORE_SECOND);
#endif
/* to set the height for the treeview the tree must be realized first */
- gtk_widget_show(comp.tree);
+ gtk_widget_show(comp->tree);
/* this prevents the first item to be placed out of view if the completion
* is shown */
@@ -135,30 +162,31 @@ gboolean completion_create(GtkTreeModel *model, CompletionSelectFunc selfunc,
}
/* use max 1/3 of window height for the completion */
-#ifdef HAS_GTK3
- gtk_widget_get_preferred_size(comp.tree, NULL, &size);
+ gtk_widget_get_preferred_size(comp->tree, NULL, &size);
height /= 3;
gtk_scrolled_window_set_min_content_height(
- GTK_SCROLLED_WINDOW(comp.win),
+ GTK_SCROLLED_WINDOW(comp->win),
size.height > height ? height : size.height
);
-#else
- gtk_widget_size_request(comp.tree, &size);
- height /= 3;
- if (size.height > height) {
- gtk_widget_set_size_request(comp.win, -1, height);
- }
-#endif
- vb.mode->flags |= FLAG_COMPLETION;
+ c->mode->flags |= FLAG_COMPLETION;
/* set to -1 to have the cursor on first or last item set in move_cursor */
- comp.active = -1;
- completion_next(back);
+ comp->active = -1;
+ completion_next(c, back);
- gtk_widget_show(comp.win);
+ gtk_widget_show(comp->win);
- return true;
+ return TRUE;
+}
+
+/**
+ * Initialize the completion system for given client.
+ */
+void completion_init(Client *c)
+{
+ /* Allocate memory for the completion struct and save it on the client. */
+ c->comp = g_slice_new0(Completion);
}
/**
@@ -166,52 +194,78 @@ gboolean completion_create(GtkTreeModel *model, CompletionSelectFunc selfunc,
* If the end/beginning is reached return false and start on the opposite end
* on the next call.
*/
-gboolean completion_next(gboolean back)
+gboolean completion_next(Client *c, gboolean back)
{
int rows;
GtkTreePath *path;
- GtkTreeView *tree = GTK_TREE_VIEW(comp.tree);
+ GtkTreeView *tree = GTK_TREE_VIEW(((Completion*)c->comp)->tree);
+ Completion *comp = (Completion*)c->comp;
rows = gtk_tree_model_iter_n_children(gtk_tree_view_get_model(tree), NULL);
if (back) {
- comp.active--;
+ comp->active--;
/* Step back over the beginning. */
- if (comp.active == -1) {
+ if (comp->active == -1) {
/* Unselect the current item to show the user that the shown
* content is the initial typed content. */
- gtk_tree_selection_unselect_all(gtk_tree_view_get_selection(GTK_TREE_VIEW(comp.tree)));
+ gtk_tree_selection_unselect_all(gtk_tree_view_get_selection(GTK_TREE_VIEW(comp->tree)));
- return false;
- } else if (comp.active < -1) {
- comp.active = rows - 1;
+ return FALSE;
+ }
+ if (comp->active < -1) {
+ comp->active = rows - 1;
}
} else {
- comp.active++;
+ comp->active++;
/* Step over the end. */
- if (comp.active == rows) {
- gtk_tree_selection_unselect_all(gtk_tree_view_get_selection(GTK_TREE_VIEW(comp.tree)));
+ if (comp->active == rows) {
+ gtk_tree_selection_unselect_all(gtk_tree_view_get_selection(GTK_TREE_VIEW(comp->tree)));
- return false;
- } else if (comp.active >= rows) {
- comp.active = 0;
+ return FALSE;
+ }
+ if (comp->active >= rows) {
+ comp->active = 0;
}
}
/* get new path and move cursor to it */
- path = gtk_tree_path_new_from_indices(comp.active, -1);
- gtk_tree_view_set_cursor(tree, path, NULL, false);
+ path = gtk_tree_path_new_from_indices(comp->active, -1);
+ gtk_tree_view_set_cursor(tree, path, NULL, FALSE);
gtk_tree_path_free(path);
- return true;
+ return TRUE;
}
-void completion_clean(void)
+/**
+ * Fills the given list store by matching data of also given src list.
+ */
+gboolean completion_fill(GtkListStore *store, const char *input, GList *src)
{
- vb.mode->flags &= ~FLAG_COMPLETION;
- if (comp.win) {
- gtk_widget_destroy(comp.win);
- comp.win = comp.tree = NULL;
+ gboolean found = FALSE;
+ GtkTreeIter iter;
+
+ /* If no filter input given - copy all entries into the data store. */
+ if (!input || !*input) {
+ for (GList *l = src; l; l = l->next) {
+ gtk_list_store_append(store, &iter);
+ gtk_list_store_set(store, &iter, COMPLETION_STORE_FIRST, l->data, -1);
+ found = TRUE;
+ }
+ return found;
}
+
+ /* If filter input is given - copy matching list entires into data store.
+ * Strings are compared by prefix matching. */
+ for (GList *l = src; l; l = l->next) {
+ char *value = (char*)l->data;
+ if (g_str_has_prefix(value, input)) {
+ gtk_list_store_append(store, &iter);
+ gtk_list_store_set(store, &iter, COMPLETION_STORE_FIRST, l->data, -1);
+ found = TRUE;
+ }
+ }
+
+ return found;
}
static gboolean tree_selection_func(GtkTreeSelection *selection,
@@ -219,16 +273,19 @@ static gboolean tree_selection_func(GtkTreeSelection *selection,
{
char *value;
GtkTreeIter iter;
+ Completion *comp = (Completion*)((Client*)data)->comp;
/* if not selected means the item is going to be selected which we are
* interested in */
if (!selected && gtk_tree_model_get_iter(model, &iter, path)) {
gtk_tree_model_get(model, &iter, COMPLETION_STORE_FIRST, &value, -1);
- comp.selfunc(value);
+ comp->selfunc((Client*)data, value);
g_free(value);
+ /* TODO update comp->active on select by mouse to continue with <Tab>
+ * or <S-Tab> from selected item on. */
}
- return true;
+ return TRUE;
}
diff --git a/src/completion.h b/src/completion.h
index 26b057d..e353ecb 100644
--- a/src/completion.h
+++ b/src/completion.h
@@ -20,8 +20,12 @@
#ifndef _COMPLETION_H
#define _COMPLETION_H
+#include <glib.h>
+
#include "main.h"
+typedef void (*CompletionSelectFunc) (Client *c, char *match);
+
enum {
COMPLETION_STORE_FIRST,
#ifdef FEATURE_TITLE_IN_COMPLETION
@@ -30,11 +34,13 @@ enum {
COMPLETION_STORE_NUM
};
-typedef void (*CompletionSelectFunc) (char *match);
-gboolean completion_create(GtkTreeModel *model, CompletionSelectFunc selfunc,
- gboolean back);
-void completion_clean(void);
-gboolean completion_next(gboolean back);
+void completion_clean(Client *c);
+void completion_cleanup(Client *c);
+gboolean completion_create(Client *c, GtkTreeModel *model,
+ CompletionSelectFunc selfunc, gboolean back);
+void completion_init(Client *c);
+gboolean completion_next(Client *c, gboolean back);
+gboolean completion_fill(GtkListStore *store, const char *input, GList *src);
#endif /* end of include guard: _COMPLETION_H */
diff --git a/src/config.def.h b/src/config.def.h
index 97531bf..da33cc7 100644
--- a/src/config.def.h
+++ b/src/config.def.h
@@ -17,101 +17,35 @@
* along with this program. If not, see http://www.gnu.org/licenses/.
*/
-#ifndef _CONFIG_H
-#define _CONFIG_H
-
-
/* features */
-/* enable cookie support */
-#define FEATURE_COOKIE
-/* highlight search results */
-#define FEATURE_SEARCH_HIGHLIGHT
-/* disable scrollbars */
-#define FEATURE_NO_SCROLLBARS
-/* show page title in url completions */
-#define FEATURE_TITLE_IN_COMPLETION
-/* enable the read it later queue */
-#define FEATURE_QUEUE
-/* show load progress in window title */
-#define FEATURE_TITLE_PROGRESS
/* should the history indicator [+-] be shown in status bar after url */
#define FEATURE_HISTORY_INDICATOR
-/* should the profile name be shown before url in url bar */
-#define FEATURE_PROFILE_INDICATOR
/* show wget style progressbar in status bar */
#define FEATURE_WGET_PROGRESS_BAR
-#ifdef HAS_GTK3
-/* enables workaround for hight dpi displays */
-/* eventually the environment variable GDK_DPI_SCALE=2.0 must be set */
-/* to get the hack working */
-/* #define FEATURE_HIGH_DPI */
+#ifdef FEATURE_WGET_PROGRESS_BAR
+/* chars to use for the progressbar */
+#define PROGRESS_BAR "=> "
+#define PROGRESS_BAR_LEN 20
#endif
-/* enable HTTP Strict-Transport-Security*/
-#define FEATURE_HSTS
-/* enable soup caching - size can be configure by maximum-cache-size setting */
-#define FEATURE_SOUP_CACHE
-/* enable the :autocmd feature */
-#define FEATURE_AUTOCMD
-/* enable the :auto-response-header feature */
-#define FEATURE_ARH
-/* allow to use socket to remote control vimb */
-#define FEATURE_SOCKET
+/* show page title in url completions */
+#define FEATURE_TITLE_IN_COMPLETION
/* time in seconds after that message will be removed from inputbox if the
* message where only temporary */
-#define MESSAGE_TIMEOUT 5
+#define MESSAGE_TIMEOUT 5
-/* number of chars to be shown for ambiguous commands */
+/* number of chars to be shown in statusbar for ambiguous commands */
#define SHOWCMD_LEN 10
+/* css applied to the gui elements of the borwser window */
+#define GUI_STYLE "GtkBox#statusbar{color:#fff;background-color:#000;font:monospace bold 10;} \
+GtkBox#statusbar.secure{background-color:#95e454;color:#000;} \
+GtkBox#statusbar.insecure{background-color:#f77;color:#000;} \
+GtkTextView{background-color:#fff;color:#000;font:monospace 10;} \
+GtkTextView.error{background-color:#f77;font-weight:bold;} \
+GtkTreeView{color:#fff;background-color:#656565;font:monospace;} \
+GtkTreeView:hover{background-color:#777;} \
+GtkTreeView:selected{color:#f6f3e8;background-color:#888;}"
-/* parh to crt file for the certificate validation */
-#define SETTING_CA_BUNDLE "/etc/ssl/certs/ca-certificates.crt"
-#define SETTING_MAX_CONNS 25
-#define SETTING_MAX_CONNS_PER_HOST 5
/* default font size for fonts in webview */
#define SETTING_DEFAULT_FONT_SIZE 10
-#define SETTING_GUI_FONT_NORMAL "monospace normal 10"
-#define SETTING_GUI_FONT_EMPH "monospace bold 10"
-#define SETTING_HOME_PAGE "http://fanglingsu.github.io/vimb/"
-
-#define MAXIMUM_HINTS 500
-
-#define WIN_WIDTH 800
-#define WIN_HEIGHT 600
-
-#ifdef FEATURE_WGET_PROGRESS_BAR
-/* chars to use for the progressbar */
-#define PROGRESS_BAR "=> "
-#define PROGRESS_BAR_LEN 20
-#endif
-
-/* CSS style use on creating hints. This might also be averrules by css out of
- * $XDG_CONFIG_HOME/vimb/style.css file. */
-#define HINT_CSS "#_hintContainer{\
-position:static\
-}\
-._hintLabel{\
--webkit-transform:translate(-4px,-4px);\
-position:absolute;\
-z-index:100000;\
-font:bold .8em monospace;\
-color:#000;\
-background-color:#fff;\
-margin:0;\
-padding:0px 1px;\
-border:1px solid #444;\
-opacity:0.7\
-}\
-._hintElem{\
-background-color:#ff0 !important;\
-color:#000 !important\
-}\
-._hintElem._hintFocus{\
-background-color:#8f0 !important\
-}\
-._hintLabel._hintFocus{\
-z-index:100001;\
-opacity:1\
-}"
-
-#endif /* end of include guard: _CONFIG_H */
+#define SETTING_HOME_PAGE "about:blank"
diff --git a/src/cookiejar.c b/src/cookiejar.c
deleted file mode 100644
index a16392f..0000000
--- a/src/cookiejar.c
+++ /dev/null
@@ -1,105 +0,0 @@
-/**
- * vimb - a webkit based vim like browser.
- *
- * Copyright (C) 2012-2015 Daniel Carl
- *
- * 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, see http://www.gnu.org/licenses/.
- */
-
-#include "config.h"
-
-#ifdef FEATURE_COOKIE
-#include <fcntl.h>
-#include <sys/file.h>
-#include "main.h"
-#include "cookiejar.h"
-
-G_DEFINE_TYPE(CookieJar, cookiejar, SOUP_TYPE_COOKIE_JAR_TEXT)
-
-static void cookiejar_changed(SoupCookieJar *self, SoupCookie *old, SoupCookie *new);
-static void cookiejar_class_init(CookieJarClass *klass);
-static void cookiejar_finalize(GObject *self);
-static void cookiejar_init(CookieJar *self);
-static void cookiejar_set_property(GObject *self, guint prop_id,
- const GValue *value, GParamSpec *pspec);
-
-extern VbCore vb;
-
-
-SoupCookieJar *cookiejar_new(const char *file, gboolean ro)
-{
- return g_object_new(
- COOKIEJAR_TYPE,
- SOUP_COOKIE_JAR_TEXT_FILENAME, file,
- SOUP_COOKIE_JAR_READ_ONLY, ro,
- NULL
- );
-}
-
-static void cookiejar_changed(SoupCookieJar *self, SoupCookie *old_cookie, SoupCookie *new_cookie)
-{
- flock(COOKIEJAR(self)->lock, LOCK_EX);
- SoupDate *expire;
- if (new_cookie) {
- /* session-expire-time handling */
- if (vb.config.cookie_expire_time == 0) {
- soup_cookie_set_expires(new_cookie, NULL);
-
- } else if (vb.config.cookie_expire_time > 0 && new_cookie->expires) {
- expire = soup_date_new_from_now(vb.config.cookie_expire_time);
- if (soup_date_to_time_t(expire) < soup_date_to_time_t(new_cookie->expires)) {
- soup_cookie_set_expires(new_cookie, expire);
- }
- soup_date_free(expire);
- }
-
- /* session-cookie handling */
- if (!new_cookie->expires && vb.config.cookie_timeout) {
- expire = soup_date_new_from_now(vb.config.cookie_timeout);
- soup_cookie_set_expires(new_cookie, expire);
- soup_date_free(expire);
- }
- }
- SOUP_COOKIE_JAR_CLASS(cookiejar_parent_class)->changed(self, old_cookie, new_cookie);
- flock(COOKIEJAR(self)->lock, LOCK_UN);
-}
-
-static void cookiejar_class_init(CookieJarClass *klass)
-{
- SOUP_COOKIE_JAR_CLASS(klass)->changed = cookiejar_changed;
- G_OBJECT_CLASS(klass)->get_property = G_OBJECT_CLASS(cookiejar_parent_class)->get_property;
- G_OBJECT_CLASS(klass)->set_property = cookiejar_set_property;
- G_OBJECT_CLASS(klass)->finalize = cookiejar_finalize;
- g_object_class_override_property(G_OBJECT_CLASS(klass), 1, "filename");
-}
-
-static void cookiejar_finalize(GObject *self)
-{
- close(COOKIEJAR(self)->lock);
- G_OBJECT_CLASS(cookiejar_parent_class)->finalize(self);
-}
-
-static void cookiejar_init(CookieJar *self)
-{
- self->lock = open(vb.files[FILES_COOKIE], O_RDWR);
-}
-
-static void cookiejar_set_property(GObject *self, guint prop_id, const
- GValue *value, GParamSpec *pspec)
-{
- flock(COOKIEJAR(self)->lock, LOCK_SH);
- G_OBJECT_CLASS(cookiejar_parent_class)->set_property(self, prop_id, value, pspec);
- flock(COOKIEJAR(self)->lock, LOCK_UN);
-}
-#endif
diff --git a/src/cookiejar.h b/src/cookiejar.h
deleted file mode 100644
index bca9758..0000000
--- a/src/cookiejar.h
+++ /dev/null
@@ -1,43 +0,0 @@
-/**
- * vimb - a webkit based vim like browser.
- *
- * Copyright (C) 2012-2015 Daniel Carl
- *
- * 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, see http://www.gnu.org/licenses/.
- */
-
-#include "config.h"
-#ifdef FEATURE_COOKIE
-
-#ifndef _COOKIEJAR_H
-#define _COOKIEJAR_H
-
-#define COOKIEJAR_TYPE (cookiejar_get_type())
-#define COOKIEJAR(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), COOKIEJAR_TYPE, CookieJar))
-
-
-typedef struct {
- SoupCookieJarText parent_instance;
- int lock;
-} CookieJar;
-
-typedef struct {
- SoupCookieJarTextClass parent_class;
-} CookieJarClass;
-
-GType cookiejar_get_type(void);
-SoupCookieJar *cookiejar_new(const char *file, gboolean ro);
-
-#endif /* end of include guard: _COOKIEJAR_H */
-#endif
diff --git a/src/dom.c b/src/dom.c
deleted file mode 100644
index 32b6bea..0000000
--- a/src/dom.c
+++ /dev/null
@@ -1,330 +0,0 @@
-/**
- * vimb - a webkit based vim like browser.
- *
- * Copyright (C) 2012-2015 Daniel Carl
- *
- * 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, see http://www.gnu.org/licenses/.
- */
-
-#include "config.h"
-#include "main.h"
-#include "dom.h"
-
-extern VbCore vb;
-
-static gboolean element_is_visible(WebKitDOMDOMWindow* win, WebKitDOMElement* element);
-static gboolean auto_insert(Element *element);
-static gboolean editable_blur_cb(Element *element, Event *event);
-static gboolean editable_focus_cb(Element *element, Event *event);
-static Element *get_active_element(Document *doc);
-
-
-void dom_install_focus_blur_callbacks(Document *doc)
-{
- HtmlElement *element = webkit_dom_document_get_body(doc);
-
- if (!element) {
- element = WEBKIT_DOM_HTML_ELEMENT(webkit_dom_document_get_document_element(doc));
- }
- if (element) {
- webkit_dom_event_target_add_event_listener(
- WEBKIT_DOM_EVENT_TARGET(element), "blur", G_CALLBACK(editable_blur_cb), true, NULL
- );
- webkit_dom_event_target_add_event_listener(
- WEBKIT_DOM_EVENT_TARGET(element), "focus", G_CALLBACK(editable_focus_cb), true, NULL
- );
- }
-}
-
-void dom_check_auto_insert(Document *doc)
-{
- Element *active = webkit_dom_html_document_get_active_element(WEBKIT_DOM_HTML_DOCUMENT(doc));
-
- if (active) {
- if (!vb.config.strict_focus) {
- auto_insert(active);
- } else if (vb.mode->id != 'i') {
- /* If strict-focus is enabled and the editable element becomes
- * focus, we explicitely remove the focus. But only if vimb isn't
- * in input mode at the time. This prevents from leaving input
- * mode that was started by user interaction like click to
- * editable element, or the 'gi' normal mode command. */
- webkit_dom_element_blur(active);
- }
- }
- dom_install_focus_blur_callbacks(doc);
-}
-
-/**
- * Remove focus from active and editable elements.
- */
-void dom_clear_focus(WebKitWebView *view)
-{
- Element *active = dom_get_active_element(view);
- if (active) {
- webkit_dom_element_blur(active);
- }
-}
-
-/**
- * Give the focus to element.
- */
-void dom_give_focus(Element *element)
-{
- webkit_dom_element_focus(element);
-}
-
-/**
- * Find the first editable element and set the focus on it and enter input
- * mode.
- * Returns true if there was an editable element focused.
- */
-gboolean dom_focus_input(Document *doc)
-{
- WebKitDOMNode *html, *node;
- WebKitDOMDOMWindow *win;
- WebKitDOMNodeList *list;
- WebKitDOMXPathNSResolver *resolver;
- WebKitDOMXPathResult* result;
- Document *frame_doc;
- guint i, len;
-
- win = webkit_dom_document_get_default_view(doc);
- list = webkit_dom_document_get_elements_by_tag_name(doc, "html");
- if (!list) {
- return false;
- }
-
- html = webkit_dom_node_list_item(list, 0);
- g_object_unref(list);
-
- resolver = webkit_dom_document_create_ns_resolver(doc, html);
- if (!resolver) {
- return false;
- }
-
- /* Use translate to match xpath expression case insensitive so that also
- * intput filed of type="TEXT" are matched. */
- result = webkit_dom_document_evaluate(
- doc, "//input[not(@type) "
- "or translate(@type,'ETX','etx')='text' "
- "or translate(@type,'ADOPRSW','adoprsw')='password' "
- "or translate(@type,'CLOR','clor')='color' "
- "or translate(@type,'ADET','adet')='date' "
- "or translate(@type,'ADEIMT','adeimt')='datetime' "
- "or translate(@type,'ACDEILMOT','acdeilmot')='datetime-local' "
- "or translate(@type,'AEILM','aeilm')='email' "
- "or translate(@type,'HMNOT','hmnot')='month' "
- "or translate(@type,'BEMNRU','bemnru')='number' "
- "or translate(@type,'ACEHRS','acehrs')='search' "
- "or translate(@type,'ELT','elt')='tel' "
- "or translate(@type,'EIMT','eimt')='time' "
- "or translate(@type,'LRU','lru')='url' "
- "or translate(@type,'EKW','ekw')='week' "
- "]|//textarea",
- html, resolver, 5, NULL, NULL
- );
- if (!result) {
- return false;
- }
- while ((node = webkit_dom_xpath_result_iterate_next(result, NULL))) {
- if (element_is_visible(win, WEBKIT_DOM_ELEMENT(node))) {
- vb_enter('i');
- webkit_dom_element_focus(WEBKIT_DOM_ELEMENT(node));
- return true;
- }
- }
-
- /* Look for editable elements in frames too. */
- list = webkit_dom_document_get_elements_by_tag_name(doc, "iframe");
- len = webkit_dom_node_list_get_length(list);
-
- for (i = 0; i < len; i++) {
- node = webkit_dom_node_list_item(list, i);
- frame_doc = webkit_dom_html_iframe_element_get_content_document(WEBKIT_DOM_HTML_IFRAME_ELEMENT(node));
- /* Stop on first frame with focused element. */
- if (dom_focus_input(frame_doc)) {
- g_object_unref(list);
- return true;
- }
- }
- g_object_unref(list);
-
- return false;
-}
-
-/**
- * Indicates if the given dom element is an editable element like text input,
- * password or textarea.
- */
-gboolean dom_is_editable(Element *element)
-{
- gboolean result = false;
- char *tagname, *type, *editable;
-
- if (!element) {
- return result;
- }
-
- tagname = webkit_dom_element_get_tag_name(element);
- type = webkit_dom_element_get_attribute(element, "type");
- editable = webkit_dom_element_get_attribute(element, "contenteditable");
- /* element is editable if it's a text area or input with no type, text or
- * pasword */
- if (!g_ascii_strcasecmp(tagname, "textarea")) {
- result = true;
- } else if (!g_ascii_strcasecmp(tagname, "input")
- && (!*type
- || !g_ascii_strcasecmp(type, "text")
- || !g_ascii_strcasecmp(type, "password")
- || !g_ascii_strcasecmp(type, "color")
- || !g_ascii_strcasecmp(type, "date")
- || !g_ascii_strcasecmp(type, "datetime")
- || !g_ascii_strcasecmp(type, "datetime-local")
- || !g_ascii_strcasecmp(type, "email")
- || !g_ascii_strcasecmp(type, "month")
- || !g_ascii_strcasecmp(type, "number")
- || !g_ascii_strcasecmp(type, "search")
- || !g_ascii_strcasecmp(type, "tel")
- || !g_ascii_strcasecmp(type, "time")
- || !g_ascii_strcasecmp(type, "url")
- || !g_ascii_strcasecmp(type, "week"))
- ) {
- result = true;
- } else if (!g_ascii_strcasecmp(editable, "true")) {
- result = true;
- } else {
- result = false;
- }
- g_free(tagname);
- g_free(type);
- g_free(editable);
-
- return result;
-}
-
-Element *dom_get_active_element(WebKitWebView *view)
-{
- return get_active_element(webkit_web_view_get_dom_document(view));
-}
-
-const char *dom_editable_element_get_value(Element *element)
-{
- const char *value = NULL;
-
- if (WEBKIT_DOM_IS_HTML_INPUT_ELEMENT((HtmlInputElement*)element)) {
- value = webkit_dom_html_input_element_get_value((HtmlInputElement*)element);
- } else {
- /* we should check WEBKIT_DOM_IS_HTML_TEXT_AREA_ELEMENT, but this
- * seems to return alway false */
- value = webkit_dom_html_text_area_element_get_value((HtmlTextareaElement*)element);
- }
-
- return value;
-}
-
-void dom_editable_element_set_value(Element *element, const char *value)
-{
- if (WEBKIT_DOM_IS_HTML_INPUT_ELEMENT(element)) {
- webkit_dom_html_input_element_set_value((HtmlInputElement*)element, value);
- } else {
- webkit_dom_html_text_area_element_set_value((HtmlTextareaElement*)element, value);
- }
-}
-
-void dom_editable_element_set_disable(Element *element, gboolean value)
-{
- if (WEBKIT_DOM_IS_HTML_INPUT_ELEMENT(element)) {
- webkit_dom_html_input_element_set_disabled((HtmlInputElement*)element, value);
- } else {
- webkit_dom_html_text_area_element_set_disabled((HtmlTextareaElement*)element, value);
- }
-}
-
-static gboolean element_is_visible(WebKitDOMDOMWindow* win, WebKitDOMElement* element)
-{
- gchar* value = NULL;
-
- WebKitDOMCSSStyleDeclaration* style = webkit_dom_dom_window_get_computed_style(win, element, "");
- value = webkit_dom_css_style_declaration_get_property_value(style, "visibility");
- if (value && g_ascii_strcasecmp(value, "hidden") == 0) {
- return false;
- }
- value = webkit_dom_css_style_declaration_get_property_value(style, "display");
- if (value && g_ascii_strcasecmp(value, "none") == 0) {
- return false;
- }
-
- return true;
-}
-
-static gboolean auto_insert(Element *element)
-{
- /* Change only the mode if we are in normal mode - passthrough should not
- * be disturbed by this and if the user iy typing into inputbox we don't
- * want to remove the content and force a switch to input mode. And to
- * switch to input mode when this is already active makes no sense. */
- if (vb.mode->id == 'n' && dom_is_editable(element)) {
- vb_enter('i');
-
- return true;
- }
- return false;
-}
-
-static gboolean editable_blur_cb(Element *element, Event *event)
-{
- if (vb.state.window_has_focus && vb.mode->id == 'i') {
- vb_enter('n');
- }
-
- return false;
-}
-
-static gboolean editable_focus_cb(Element *element, Event *event)
-{
- if (vb.state.done_loading_page || !vb.config.strict_focus) {
- auto_insert((Element*)webkit_dom_event_get_target(event));
- }
-
- return false;
-}
-
-static Element *get_active_element(Document *doc)
-{
- char *tagname;
- Document *d = NULL;
- Element *active, *result = NULL;
-
- active = webkit_dom_html_document_get_active_element((void*)doc);
- if (!active) {
- return result;
- }
- tagname = webkit_dom_element_get_tag_name(active);
-
- if (!g_strcmp0(tagname, "FRAME")) {
- d = webkit_dom_html_frame_element_get_content_document(WEBKIT_DOM_HTML_FRAME_ELEMENT(active));
- result = get_active_element(d);
- } else if (!g_strcmp0(tagname, "IFRAME")) {
- d = webkit_dom_html_iframe_element_get_content_document(WEBKIT_DOM_HTML_IFRAME_ELEMENT(active));
- result = get_active_element(d);
- }
- g_free(tagname);
-
- if (result) {
- return result;
- }
-
- return active;
-}
diff --git a/src/dom.h b/src/dom.h
deleted file mode 100644
index 03eaf37..0000000
--- a/src/dom.h
+++ /dev/null
@@ -1,46 +0,0 @@
-/**
- * vimb - a webkit based vim like browser.
- *
- * Copyright (C) 2012-2015 Daniel Carl
- *
- * 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, see http://www.gnu.org/licenses/.
- */
-
-#ifndef _DOM_H
-#define _DOM_H
-
-#include <webkit/webkit.h>
-
-/* Types */
-#define Document WebKitDOMDocument
-#define HtmlElement WebKitDOMHTMLElement
-#define Element WebKitDOMElement
-#define Node WebKitDOMNode
-#define Event WebKitDOMEvent
-#define EventTarget WebKitDOMEventTarget
-#define HtmlInputElement WebKitDOMHTMLInputElement
-#define HtmlTextareaElement WebKitDOMHTMLTextAreaElement
-
-void dom_install_focus_blur_callbacks(Document *doc);
-void dom_check_auto_insert(Document *doc);
-void dom_clear_focus(WebKitWebView *view);
-void dom_give_focus(Element *element);
-gboolean dom_focus_input(Document *doc);
-gboolean dom_is_editable(Element *element);
-Element *dom_get_active_element(WebKitWebView *view);
-const char *dom_editable_element_get_value(Element *element);
-void dom_editable_element_set_value(Element *element, const char *value);
-void dom_editable_element_set_disable(Element *element, gboolean value);
-
-#endif /* end of include guard: _DOM_H */
diff --git a/src/ex.c b/src/ex.c
index bfbe418..914a554 100644
--- a/src/ex.c
+++ b/src/ex.c
@@ -21,32 +21,23 @@
* This file contains function to handle input editing, parsing of called ex
* commands from inputbox and the ex commands.
*/
-#include "config.h"
+
+#include <string.h>
#include <sys/wait.h>
-#include "main.h"
-#include "ex.h"
+
#include "ascii.h"
-#include "completion.h"
-#include "hints.h"
#include "command.h"
+#include "completion.h"
+#include "config.h"
+#include "ex.h"
#include "history.h"
-#include "dom.h"
+#include "main.h"
+#include "map.h"
#include "setting.h"
#include "util.h"
-#include "bookmark.h"
-#include "shortcut.h"
-#include "handlers.h"
-#include "map.h"
-#include "js.h"
-#ifdef FEATURE_AUTOCMD
-#include "autocmd.h"
-#endif
typedef enum {
-#ifdef FEATURE_AUTOCMD
- EX_AUTOCMD,
- EX_AUGROUP,
-#endif
+ /* TODO add feature autocmd */
EX_BMA,
EX_BMR,
EX_EVAL,
@@ -78,7 +69,6 @@ typedef enum {
EX_SCR,
EX_SET,
EX_SHELLCMD,
- EX_SOURCE,
EX_TABOPEN,
} ExCode;
@@ -98,7 +88,7 @@ typedef struct {
int flags; /* flags for the already parsed command */
} ExArg;
-typedef VbCmdResult (*ExFunc)(const ExArg *arg);
+typedef VbCmdResult (*ExFunc)(Client *c, const ExArg *arg);
typedef struct {
const char *name; /* full name of the command even if called abbreviated */
@@ -118,43 +108,38 @@ static struct {
Phase phase; /* current parsing phase */
} info = {'\0', PHASE_START};
-static void input_activate(void);
-static gboolean parse(const char **input, ExArg *arg, gboolean *nohist);
+static void input_activate(Client *c);
+static gboolean parse(Client *c, const char **input, ExArg *arg, gboolean *nohist);
static gboolean parse_count(const char **input, ExArg *arg);
-static gboolean parse_command_name(const char **input, ExArg *arg);
+static gboolean parse_command_name(Client *c, const char **input, ExArg *arg);
static gboolean parse_bang(const char **input, ExArg *arg);
static gboolean parse_lhs(const char **input, ExArg *arg);
-static gboolean parse_rhs(const char **input, ExArg *arg);
+static gboolean parse_rhs(Client *c, const char **input, ExArg *arg);
static void skip_whitespace(const char **input);
static void free_cmdarg(ExArg *arg);
-static VbCmdResult execute(const ExArg *arg);
-
-#ifdef FEATURE_AUTOCMD
-static VbCmdResult ex_augroup(const ExArg *arg);
-static VbCmdResult ex_autocmd(const ExArg *arg);
-#endif
-static VbCmdResult ex_bookmark(const ExArg *arg);
-static VbCmdResult ex_eval(const ExArg *arg);
-static VbCmdResult ex_hardcopy(const ExArg *arg);
-static VbCmdResult ex_map(const ExArg *arg);
-static VbCmdResult ex_unmap(const ExArg *arg);
-static VbCmdResult ex_normal(const ExArg *arg);
-static VbCmdResult ex_open(const ExArg *arg);
+static VbCmdResult execute(Client *c, const ExArg *arg);
+
+static VbCmdResult ex_bookmark(Client *c, const ExArg *arg);
+static VbCmdResult ex_eval(Client *c, const ExArg *arg);
+static VbCmdResult ex_hardcopy(Client *c, const ExArg *arg);
+static VbCmdResult ex_map(Client *c, const ExArg *arg);
+static VbCmdResult ex_unmap(Client *c, const ExArg *arg);
+static VbCmdResult ex_normal(Client *c, const ExArg *arg);
+static VbCmdResult ex_open(Client *c, const ExArg *arg);
#ifdef FEATURE_QUEUE
-static VbCmdResult ex_queue(const ExArg *arg);
+static VbCmdResult ex_queue(Client *c, const ExArg *arg);
#endif
-static VbCmdResult ex_register(const ExArg *arg);
-static VbCmdResult ex_quit(const ExArg *arg);
-static VbCmdResult ex_save(const ExArg *arg);
-static VbCmdResult ex_set(const ExArg *arg);
-static VbCmdResult ex_shellcmd(const ExArg *arg);
-static VbCmdResult ex_shortcut(const ExArg *arg);
-static VbCmdResult ex_source(const ExArg *arg);
-static VbCmdResult ex_handlers(const ExArg *arg);
-
-static gboolean complete(short direction);
-static void completion_select(char *match);
-static gboolean history(gboolean prev);
+static VbCmdResult ex_register(Client *c, const ExArg *arg);
+static VbCmdResult ex_quit(Client *c, const ExArg *arg);
+static VbCmdResult ex_save(Client *c, const ExArg *arg);
+static VbCmdResult ex_set(Client *c, const ExArg *arg);
+static VbCmdResult ex_shellcmd(Client *c, const ExArg *arg);
+static VbCmdResult ex_shortcut(Client *c, const ExArg *arg);
+static VbCmdResult ex_handlers(Client *c, const ExArg *arg);
+
+static gboolean complete(Client *c, short direction);
+static void completion_select(Client *c, char *match);
+static gboolean history(Client *c, gboolean prev);
static void history_rewind(void);
/* The order of following command names is significant. If there exists
@@ -165,10 +150,6 @@ static void history_rewind(void);
* match. */
static ExInfo commands[] = {
/* command code func flags */
-#ifdef FEATURE_AUTOCMD
- {"autocmd", EX_AUTOCMD, ex_autocmd, EX_FLAG_CMD|EX_FLAG_BANG},
- {"augroup", EX_AUGROUP, ex_augroup, EX_FLAG_LHS|EX_FLAG_BANG},
-#endif
{"bma", EX_BMA, ex_bookmark, EX_FLAG_RHS},
{"bmr", EX_BMR, ex_bookmark, EX_FLAG_RHS},
{"cmap", EX_CMAP, ex_map, EX_FLAG_LHS|EX_FLAG_CMD},
@@ -200,7 +181,6 @@ static ExInfo commands[] = {
{"shortcut-add", EX_SCA, ex_shortcut, EX_FLAG_RHS},
{"shortcut-default", EX_SCD, ex_shortcut, EX_FLAG_RHS},
{"shortcut-remove", EX_SCR, ex_shortcut, EX_FLAG_RHS},
- {"source", EX_SOURCE, ex_source, EX_FLAG_RHS|EX_FLAG_EXP},
{"tabopen", EX_TABOPEN, ex_open, EX_FLAG_CMD},
};
@@ -217,45 +197,43 @@ static struct {
GList *active;
} exhist;
-extern VbCore vb;
-
+extern struct Vimb vb;
/**
* Function called when vimb enters the command mode.
*/
-void ex_enter(void)
+void ex_enter(Client *c)
{
- gtk_widget_grab_focus(GTK_WIDGET(vb.gui.input));
- dom_clear_focus(vb.gui.webview);
+ gtk_widget_grab_focus(GTK_WIDGET(c->input));
+#if 0
+ dom_clear_focus(c->webview);
+#endif
}
/**
* Called when the command mode is left.
*/
-void ex_leave(void)
+void ex_leave(Client *c)
{
- completion_clean();
+ completion_clean(c);
+#if 0
hints_clear();
+#endif
}
/**
* Handles the keypress events from webview and inputbox.
*/
-VbResult ex_keypress(int key)
+VbResult ex_keypress(Client *c, int key)
{
GtkTextIter start, end;
- gboolean check_empty = false;
- GtkTextBuffer *buffer = vb.gui.buffer;
+ gboolean check_empty = FALSE;
+ GtkTextBuffer *buffer = c->buffer;
GtkTextMark *mark;
VbResult res;
const char *text;
- /* delegate call to hint mode if this is active */
- if (vb.mode->flags & FLAG_HINTING
- && RESULT_COMPLETE == hints_keypress(key)) {
-
- return RESULT_COMPLETE;
- }
+ /* TODO delegate call to hint mode if this is active */
/* process the register */
if (info.phase == PHASE_REG) {
@@ -263,7 +241,7 @@ VbResult ex_keypress(int key)
info.phase = PHASE_REG;
/* insert the register text at cursor position */
- text = vb_register_get((char)key);
+ text = vb_register_get(c, (char)key);
if (text) {
gtk_text_buffer_insert_at_cursor(buffer, text, strlen(text));
}
@@ -273,29 +251,29 @@ VbResult ex_keypress(int key)
res = RESULT_COMPLETE;
switch (key) {
case KEY_TAB:
- complete(1);
+ complete(c, 1);
break;
case KEY_SHIFT_TAB:
- complete(-1);
+ complete(c, -1);
break;
- case CTRL('['):
- case CTRL('C'):
- vb_enter('n');
- vb_set_input_text("");
+ case KEY_UP:
+ history(c, TRUE);
break;
- case KEY_CR:
- input_activate();
+ case KEY_DOWN:
+ history(c, FALSE);
break;
- case KEY_UP:
- history(true);
+ case KEY_CR:
+ input_activate(c);
break;
- case KEY_DOWN:
- history(false);
+ case CTRL('['):
+ case CTRL('C'):
+ vb_enter(c, 'n');
+ vb_input_set_text(c, "");
break;
/* basic command line editing */
@@ -303,8 +281,8 @@ VbResult ex_keypress(int key)
/* delete the last char before the cursor */
mark = gtk_text_buffer_get_insert(buffer);
gtk_text_buffer_get_iter_at_mark(buffer, &start, mark);
- gtk_text_buffer_backspace(buffer, &start, true, true);
- check_empty = true;
+ gtk_text_buffer_backspace(buffer, &start, TRUE, TRUE);
+ check_empty = TRUE;
break;
case CTRL('W'):
@@ -319,12 +297,12 @@ VbResult ex_keypress(int key)
if (gtk_text_iter_backward_word_start(&start)) {
gtk_text_buffer_delete(buffer, &start, &end);
}
- check_empty = true;
+ check_empty = TRUE;
break;
case CTRL('B'):
/* move the cursor direct behind the prompt */
- gtk_text_buffer_get_iter_at_offset(buffer, &start, strlen(vb.state.prompt));
+ gtk_text_buffer_get_iter_at_offset(buffer, &start, strlen(c->state.prompt));
gtk_text_buffer_place_cursor(buffer, &start);
break;
@@ -338,13 +316,13 @@ VbResult ex_keypress(int key)
/* remove everything between cursor and prompt */
mark = gtk_text_buffer_get_insert(buffer);
gtk_text_buffer_get_iter_at_mark(buffer, &end, mark);
- gtk_text_buffer_get_iter_at_offset(buffer, &start, strlen(vb.state.prompt));
+ gtk_text_buffer_get_iter_at_offset(buffer, &start, strlen(c->state.prompt));
gtk_text_buffer_delete(buffer, &start, &end);
break;
case CTRL('R'):
info.phase = PHASE_REG;
- vb.mode->flags |= FLAG_NOMAP;
+ c->mode->flags |= FLAG_NOMAP;
res = RESULT_MORE;
break;
@@ -354,7 +332,7 @@ VbResult ex_keypress(int key)
if (key >= 0x20 && key <= 0x7e) {
gtk_text_buffer_insert_at_cursor(buffer, (char[2]){key, 0}, 1);
} else {
- vb.state.processed_key = false;
+ c->state.processed_key = FALSE;
}
}
}
@@ -364,8 +342,8 @@ VbResult ex_keypress(int key)
if (check_empty) {
gtk_text_buffer_get_bounds(buffer, &start, &end);
if (gtk_text_iter_equal(&start, &end)) {
- vb_enter('n');
- vb_set_input_text("");
+ vb_enter(c, 'n');
+ vb_input_set_text(c, "");
}
}
@@ -380,11 +358,10 @@ VbResult ex_keypress(int key)
/**
* Handles changes in the inputbox.
*/
-void ex_input_changed(const char *text)
+void ex_input_changed(Client *c, const char *text)
{
- gboolean forward = false;
GtkTextIter start, end;
- GtkTextBuffer *buffer = vb.gui.buffer;
+ GtkTextBuffer *buffer = c->buffer;
/* don't add line breaks if content is pasted from clipboard into inputbox */
if (gtk_text_buffer_get_line_count(buffer) > 1) {
@@ -399,15 +376,7 @@ void ex_input_changed(const char *text)
switch (*text) {
case ';': /* fall through - the modes are handled by hints_create */
case 'g':
- hints_create(text);
- break;
-
- case '/': forward = true; /* fall through */
- case '?':
-#ifdef FEATURE_SEARCH_HIGHLIGHT
- webkit_web_view_unmark_text_matches(vb.gui.webview);
-#endif
- webkit_web_view_search_text(vb.gui.webview, &text[1], false, forward, false);
+ /* TODO create hints */
break;
}
}
@@ -416,14 +385,14 @@ gboolean ex_fill_completion(GtkListStore *store, const char *input)
{
GtkTreeIter iter;
ExInfo *cmd;
- gboolean found = false;
+ gboolean found = FALSE;
if (!input || *input == '\0') {
for (int i = 0; i < LENGTH(commands); i++) {
cmd = &commands[i];
gtk_list_store_append(store, &iter);
gtk_list_store_set(store, &iter, COMPLETION_STORE_FIRST, cmd->name, -1);
- found = true;
+ found = TRUE;
}
} else {
for (int i = 0; i < LENGTH(commands); i++) {
@@ -431,7 +400,7 @@ gboolean ex_fill_completion(GtkListStore *store, const char *input)
if (g_str_has_prefix(cmd->name, input)) {
gtk_list_store_append(store, &iter);
gtk_list_store_set(store, &iter, COMPLETION_STORE_FIRST, cmd->name, -1);
- found = true;
+ found = TRUE;
}
}
}
@@ -442,33 +411,34 @@ gboolean ex_fill_completion(GtkListStore *store, const char *input)
/**
* This is called if the user typed <nl> or <cr> into the inputbox.
*/
-static void input_activate(void)
+static void input_activate(Client *c)
{
int count = -1;
char *text, *cmd;
VbCmdResult res;
- text = vb_get_input_text();
+
+ text = vb_input_get_text(c);
/* skip leading prompt char like ':' or '/' */
cmd = text + 1;
switch (*text) {
case '/': count = 1; /* fall through */
case '?':
- vb_enter('n');
- command_search(&((Arg){count, cmd}));
+ vb_enter(c, 'n');
+ command_search(c, &((Arg){count, cmd}));
break;
case ';': /* fall through */
case 'g':
- hints_fire();
+ /* TODO fire hints */
break;
case ':':
- vb_enter('n');
- res = ex_run_string(cmd, true);
- if (!(res & VB_CMD_KEEPINPUT)) {
+ vb_enter(c, 'n');
+ res = ex_run_string(c, cmd, TRUE);
+ if (!(res & CMD_KEEPINPUT)) {
/* clear input on success if this is not explicit ommited */
- vb_set_input_text("");
+ vb_input_set_text(c, "");
}
break;
@@ -476,25 +446,25 @@ static void input_activate(void)
g_free(text);
}
-VbCmdResult ex_run_string(const char *input, gboolean enable_history)
+VbCmdResult ex_run_string(Client *c, const char *input, gboolean enable_history)
{
/* copy to have original command for history */
const char *in = input;
- gboolean nohist = false;
- VbCmdResult res = VB_CMD_ERROR | VB_CMD_KEEPINPUT;
+ gboolean nohist = FALSE;
+ VbCmdResult res = CMD_ERROR | CMD_KEEPINPUT;
ExArg *arg = g_slice_new0(ExArg);
arg->lhs = g_string_new("");
arg->rhs = g_string_new("");
while (in && *in) {
- if (!parse(&in, arg, &nohist) || !(res = execute(arg))) {
+ if (!parse(c, &in, arg, &nohist) || !(res = execute(c, arg))) {
break;
}
}
if (enable_history && !nohist) {
- history_add(HISTORY_COMMAND, input, NULL);
- vb_register_add(':', input);
+ history_add(c, HISTORY_COMMAND, input, NULL);
+ vb_register_add(c, ':', input);
}
free_cmdarg(arg);
@@ -503,43 +473,12 @@ VbCmdResult ex_run_string(const char *input, gboolean enable_history)
}
/**
- * Run all ex commands in a file.
- */
-VbCmdResult ex_run_file(const char *filename)
-{
- char *line, **lines;
- VbCmdResult res = VB_CMD_SUCCESS;
-
- lines = util_get_lines(filename);
-
- if (!lines) {
- return res;
- }
-
- int length = g_strv_length(lines) - 1;
- for (int i = 0; i < length; i++) {
- line = lines[i];
- /* skip commented or empty lines */
- if (*line == '#' || !*line) {
- continue;
- }
- if ((ex_run_string(line, false) & ~VB_CMD_KEEPINPUT) == VB_CMD_ERROR) {
- res = VB_CMD_ERROR | VB_CMD_KEEPINPUT;
- g_warning("Invalid command in %s: '%s'", filename, line);
- }
- }
- g_strfreev(lines);
-
- return res;
-}
-
-/**
* Parses given input string into given ExArg pointer.
*/
-static gboolean parse(const char **input, ExArg *arg, gboolean *nohist)
+static gboolean parse(Client *c, const char **input, ExArg *arg, gboolean *nohist)
{
if (!*input || !**input) {
- return false;
+ return FALSE;
}
/* truncate string from potentially previous run */
@@ -551,13 +490,13 @@ static gboolean parse(const char **input, ExArg *arg, gboolean *nohist)
(*input)++;
/* Command started with additional ':' or whitespce - don't record it
* in history or registry. */
- *nohist = true;
+ *nohist = TRUE;
}
parse_count(input, arg);
skip_whitespace(input);
- if (!parse_command_name(input, arg)) {
- return false;
+ if (!parse_command_name(c, input, arg)) {
+ return FALSE;
}
/* parse the bang if this is allowed */
@@ -572,13 +511,13 @@ static gboolean parse(const char **input, ExArg *arg, gboolean *nohist)
}
/* parse the rhs if this is available */
skip_whitespace(input);
- parse_rhs(input, arg);
+ parse_rhs(c, input, arg);
if (**input) {
(*input)++;
}
- return true;
+ return TRUE;
}
/**
@@ -594,13 +533,13 @@ static gboolean parse_count(const char **input, ExArg *arg)
(*input)++;
} while (VB_IS_DIGIT(**input));
}
- return true;
+ return TRUE;
}
/**
* Parse the command name from given input.
*/
-static gboolean parse_command_name(const char **input, ExArg *arg)
+static gboolean parse_command_name(Client *c, const char **input, ExArg *arg)
{
int len = 0;
int first = 0; /* number of first found command */
@@ -638,8 +577,8 @@ static gboolean parse_command_name(const char **input, ExArg *arg)
}
cmd[len] = '\0';
- vb_echo(VB_MSG_ERROR, true, "Unknown command: %s", cmd);
- return false;
+ vb_echo(c, MSG_ERROR, TRUE, "Unknown command: %s", cmd);
+ return FALSE;
}
arg->idx = first;
@@ -647,7 +586,7 @@ static gboolean parse_command_name(const char **input, ExArg *arg)
arg->name = commands[first].name;
arg->flags = commands[first].flags;
- return true;
+ return TRUE;
}
/**
@@ -656,10 +595,10 @@ static gboolean parse_command_name(const char **input, ExArg *arg)
static gboolean parse_bang(const char **input, ExArg *arg)
{
if (*input && **input == '!') {
- arg->bang = true;
+ arg->bang = TRUE;
(*input)++;
}
- return true;
+ return TRUE;
}
/**
@@ -670,7 +609,7 @@ static gboolean parse_lhs(const char **input, ExArg *arg)
char quote = '\\';
if (!*input || !**input) {
- return false;
+ return FALSE;
}
/* get the char until the next none escaped whitespace and save it into
@@ -683,9 +622,8 @@ static gboolean parse_lhs(const char **input, ExArg *arg)
if (!*input) {
/* if input ends here - use only the backslash */
g_string_append_c(arg->lhs, quote);
- } else if (**input == ' ' || **input == quote) {
- /* Escaped whitespace becomes only whitespace and escaped '\'
- * becomes '\' */
+ } else if (**input == ' ') {
+ /* escaped whitespace becomes only whitespace */
g_string_append_c(arg->lhs, **input);
} else {
/* put escape char and next char into the result string */
@@ -698,7 +636,7 @@ static gboolean parse_lhs(const char **input, ExArg *arg)
}
(*input)++;
}
- return true;
+ return TRUE;
}
/**
@@ -706,7 +644,7 @@ static gboolean parse_lhs(const char **input, ExArg *arg)
* command can contain any char accept of the newline, else the right hand
* side end on the first none escaped | or newline.
*/
-static gboolean parse_rhs(const char **input, ExArg *arg)
+static gboolean parse_rhs(Client *c, const char **input, ExArg *arg)
{
int expflags, flags;
gboolean cmdlist;
@@ -716,7 +654,7 @@ static gboolean parse_rhs(const char **input, ExArg *arg)
if ((arg->flags & (EX_FLAG_RHS|EX_FLAG_CMD)) == 0
|| !*input || !**input
) {
- return false;
+ return FALSE;
}
cmdlist = (arg->flags & EX_FLAG_CMD) != 0;
@@ -729,7 +667,7 @@ static gboolean parse_rhs(const char **input, ExArg *arg)
* EX_FLAG_CMD is not set also on | */
while (**input && **input != '\n' && (cmdlist || **input != '|')) {
/* check for expansion placeholder */
- util_parse_expansion(input, arg->rhs, flags, "|\\");
+ util_parse_expansion(c, input, arg->rhs, flags, "|\\");
if (VB_IS_SEPARATOR(**input)) {
/* add tilde expansion for next loop needs to be first char or to
@@ -741,15 +679,15 @@ static gboolean parse_rhs(const char **input, ExArg *arg)
}
(*input)++;
}
- return true;
+ return TRUE;
}
/**
* Executes the command given by ExArg.
*/
-static VbCmdResult execute(const ExArg *arg)
+static VbCmdResult execute(Client *c, const ExArg *arg)
{
- return (commands[arg->idx].func)(arg);
+ return (commands[arg->idx].func)(c, arg);
}
static void skip_whitespace(const char **input)
@@ -762,210 +700,136 @@ static void skip_whitespace(const char **input)
static void free_cmdarg(ExArg *arg)
{
if (arg->lhs) {
- g_string_free(arg->lhs, true);
+ g_string_free(arg->lhs, TRUE);
}
if (arg->rhs) {
- g_string_free(arg->rhs, true);
+ g_string_free(arg->rhs, TRUE);
}
g_slice_free(ExArg, arg);
}
-#ifdef FEATURE_AUTOCMD
-static VbCmdResult ex_augroup(const ExArg *arg)
-{
- return autocmd_augroup(arg->lhs->str, arg->bang) ? VB_CMD_SUCCESS : VB_CMD_ERROR;
-}
-
-static VbCmdResult ex_autocmd(const ExArg *arg)
-{
- return autocmd_add(arg->rhs->str, arg->bang) ? VB_CMD_SUCCESS : VB_CMD_ERROR;
-}
-#endif
-
-static VbCmdResult ex_bookmark(const ExArg *arg)
+static VbCmdResult ex_bookmark(Client *c, const ExArg *arg)
{
- if (arg->code == EX_BMR) {
- if (bookmark_remove(*arg->rhs->str ? arg->rhs->str : vb.state.uri)) {
- vb_echo_force(VB_MSG_NORMAL, true, " Bookmark removed");
-
- return VB_CMD_SUCCESS | VB_CMD_KEEPINPUT;
- }
- } else if (bookmark_add(vb.state.uri, webkit_web_view_get_title(vb.gui.webview), arg->rhs->str)) {
- vb_echo_force(VB_MSG_NORMAL, true, " Bookmark added");
-
- return VB_CMD_SUCCESS | VB_CMD_KEEPINPUT;
- }
-
- return VB_CMD_ERROR;
+ /* TODO no implemented yet */
+ return CMD_SUCCESS;
}
-static VbCmdResult ex_eval(const ExArg *arg)
+static VbCmdResult ex_eval(Client *c, const ExArg *arg)
{
- gboolean success;
- char *value = NULL;
- VbCmdResult res = VB_CMD_SUCCESS;
-
- if (!arg->rhs->len) {
- return false;
- }
-
- success = js_eval(
- webkit_web_frame_get_global_context(webkit_web_view_get_main_frame(vb.gui.webview)),
- arg->rhs->str, NULL, &value
- );
- if (!arg->bang) {
- if (success) {
- vb_echo(VB_MSG_NORMAL, false, "%s", value);
- res = VB_CMD_SUCCESS | VB_CMD_KEEPINPUT;
- } else {
- vb_echo(VB_MSG_ERROR, true, "%s", value);
- res = VB_CMD_ERROR | VB_CMD_KEEPINPUT;
- }
- }
- g_free(value);
-
- return res;
+ /* TODO allow to get the return value and possible errors. */
+ webkit_web_view_run_javascript(c->webview, arg->rhs->str, NULL, NULL, NULL);
+ return CMD_SUCCESS;
}
-static VbCmdResult ex_hardcopy(const ExArg *arg)
+static VbCmdResult ex_hardcopy(Client *c, const ExArg *arg)
{
- webkit_web_frame_print(webkit_web_view_get_main_frame(vb.gui.webview));
- return VB_CMD_SUCCESS;
+ /* TODO no implemented yet */
+ return CMD_SUCCESS;
}
-static VbCmdResult ex_map(const ExArg *arg)
+static VbCmdResult ex_map(Client *c, const ExArg *arg)
{
if (!arg->lhs->len || !arg->rhs->len) {
- return VB_CMD_ERROR;
+ return CMD_ERROR;
}
/* instead of using the EX_XMAP constants we use the first char of the
* command name as mode and the second to determine if noremap is used */
- map_insert(arg->lhs->str, arg->rhs->str, arg->name[0], arg->name[1] != 'n');
+ map_insert(c, arg->lhs->str, arg->rhs->str, arg->name[0], arg->name[1] != 'n');
- return VB_CMD_SUCCESS;
+ return CMD_SUCCESS;
}
-static VbCmdResult ex_unmap(const ExArg *arg)
+static VbCmdResult ex_unmap(Client *c, const ExArg *arg)
{
char *lhs;
if (!arg->lhs->len) {
- return VB_CMD_ERROR;
+ return CMD_ERROR;
}
lhs = arg->lhs->str;
if (arg->code == EX_NUNMAP) {
- map_delete(lhs, 'n');
+ map_delete(c, lhs, 'n');
} else if (arg->code == EX_CUNMAP) {
- map_delete(lhs, 'c');
+ map_delete(c, lhs, 'c');
} else {
- map_delete(lhs, 'i');
+ map_delete(c, lhs, 'i');
}
- return VB_CMD_SUCCESS;
+ return CMD_SUCCESS;
}
-static VbCmdResult ex_normal(const ExArg *arg)
+static VbCmdResult ex_normal(Client *c, const ExArg *arg)
{
- vb_enter('n');
+ vb_enter(c, 'n');
/* if called with bang - don't apply mapping */
- map_handle_string(arg->rhs->str, !arg->bang);
+ map_handle_string(c, arg->rhs->str, !arg->bang);
- return VB_CMD_SUCCESS | VB_CMD_KEEPINPUT;
+ return CMD_SUCCESS | CMD_KEEPINPUT;
}
-static VbCmdResult ex_open(const ExArg *arg)
+static VbCmdResult ex_open(Client *c, const ExArg *arg)
{
if (arg->code == EX_TABOPEN) {
- return vb_load_uri(&((Arg){VB_TARGET_NEW, arg->rhs->str})) ? VB_CMD_SUCCESS : VB_CMD_ERROR;
+ return vb_load_uri(c, &((Arg){TARGET_NEW, arg->rhs->str})) ? CMD_SUCCESS : CMD_ERROR;
}
- return vb_load_uri(&((Arg){VB_TARGET_CURRENT, arg->rhs->str})) ? VB_CMD_SUCCESS :VB_CMD_ERROR;
+ return vb_load_uri(c, &((Arg){TARGET_CURRENT, arg->rhs->str})) ? CMD_SUCCESS :CMD_ERROR;
}
#ifdef FEATURE_QUEUE
-static VbCmdResult ex_queue(const ExArg *arg)
+static VbCmdResult ex_queue(Client *c, const ExArg *arg)
{
- Arg a = {0};
-
- switch (arg->code) {
- case EX_QPUSH:
- a.i = COMMAND_QUEUE_PUSH;
- break;
-
- case EX_QUNSHIFT:
- a.i = COMMAND_QUEUE_UNSHIFT;
- break;
-
- case EX_QPOP:
- a.i = COMMAND_QUEUE_POP;
- break;
-
- case EX_QCLEAR:
- a.i = COMMAND_QUEUE_CLEAR;
- break;
-
- default:
- return VB_CMD_ERROR;
- }
-
- /* if no argument is found in rhs, keep the uri in arg null to force
- * command_queue() to use current URI */
- if (arg->rhs->len) {
- a.s = arg->rhs->str;
- }
-
- return command_queue(&a)
- ? VB_CMD_SUCCESS | VB_CMD_KEEPINPUT
- : VB_CMD_ERROR | VB_CMD_KEEPINPUT;
+ /* TODO no implemented yet */
+ return CMD_SUCCESS;
}
#endif
/**
* Show the contents of the registers :reg.
*/
-static VbCmdResult ex_register(const ExArg *arg)
+static VbCmdResult ex_register(Client *c, const ExArg *arg)
{
int idx;
char *reg;
- const char *regchars = VB_REG_CHARS;
+ const char *regchars = REG_CHARS;
GString *str = g_string_new("-- Register --");
- for (idx = 0; idx < VB_REG_SIZE; idx++) {
+ for (idx = 0; idx < REG_SIZE; idx++) {
/* show only filled registers */
- if (vb.state.reg[idx]) {
+ if (c->state.reg[idx]) {
/* replace all newlines */
- reg = util_str_replace("\n", "^J", vb.state.reg[idx]);
+ reg = util_str_replace("\n", "^J", c->state.reg[idx]);
g_string_append_printf(str, "\n\"%c %s", regchars[idx], reg);
g_free(reg);
}
}
- vb_echo(VB_MSG_NORMAL, false, "%s", str->str);
- g_string_free(str, true);
+ vb_echo(c, MSG_NORMAL, FALSE, "%s", str->str);
+ g_string_free(str, TRUE);
- return VB_CMD_SUCCESS | VB_CMD_KEEPINPUT;
+ return CMD_SUCCESS | CMD_KEEPINPUT;
}
-static VbCmdResult ex_quit(const ExArg *arg)
+static VbCmdResult ex_quit(Client *c, const ExArg *arg)
{
- vb_quit(arg->bang);
- return VB_CMD_SUCCESS;
+ vb_quit(c, arg->bang);
+ return CMD_SUCCESS;
}
-static VbCmdResult ex_save(const ExArg *arg)
+static VbCmdResult ex_save(Client *c, const ExArg *arg)
{
- return command_save(&((Arg){COMMAND_SAVE_CURRENT, arg->rhs->str}))
- ? VB_CMD_SUCCESS | VB_CMD_KEEPINPUT
- : VB_CMD_ERROR | VB_CMD_KEEPINPUT;
+ return command_save(c, &((Arg){COMMAND_SAVE_CURRENT, arg->rhs->str}))
+ ? CMD_SUCCESS | CMD_KEEPINPUT
+ : CMD_ERROR | CMD_KEEPINPUT;
}
-static VbCmdResult ex_set(const ExArg *arg)
+static VbCmdResult ex_set(Client *c, const ExArg *arg)
{
char *param = NULL;
if (!arg->rhs->len) {
- return false;
+ return FALSE;
}
/* split the input string into parameter and value part */
@@ -974,13 +838,13 @@ static VbCmdResult ex_set(const ExArg *arg)
g_strstrip(arg->rhs->str);
g_strstrip(param);
- return setting_run(arg->rhs->str, param);
+ return setting_run(c, arg->rhs->str, param);
}
- return setting_run(arg->rhs->str, NULL);
+ return setting_run(c, arg->rhs->str, NULL);
}
-static VbCmdResult ex_shellcmd(const ExArg *arg)
+static VbCmdResult ex_shellcmd(Client *c, const ExArg *arg)
{
int status;
char *stdOut = NULL, *stdErr = NULL;
@@ -988,94 +852,48 @@ static VbCmdResult ex_shellcmd(const ExArg *arg)
GError *error = NULL;
if (!*arg->rhs->str) {
- return VB_CMD_ERROR;
+ return CMD_ERROR;
}
if (arg->bang) {
if (!g_spawn_command_line_async(arg->rhs->str, &error)) {
g_warning("Can't run '%s': %s", arg->rhs->str, error->message);
g_clear_error(&error);
- res = VB_CMD_ERROR | VB_CMD_KEEPINPUT;
+ res = CMD_ERROR | CMD_KEEPINPUT;
} else {
- res = VB_CMD_SUCCESS;
+ res = CMD_SUCCESS;
}
} else {
if (!g_spawn_command_line_sync(arg->rhs->str, &stdOut, &stdErr, &status, &error)) {
g_warning("Can't run '%s': %s", arg->rhs->str, error->message);
g_clear_error(&error);
- res = VB_CMD_ERROR | VB_CMD_KEEPINPUT;
+ res = CMD_ERROR | CMD_KEEPINPUT;
} else {
/* the commands success depends not on the return code of the
* called shell command, so we know the result already here */
- res = VB_CMD_SUCCESS | VB_CMD_KEEPINPUT;
+ res = CMD_SUCCESS | CMD_KEEPINPUT;
}
if (WIFEXITED(status) && WEXITSTATUS(status) == 0) {
- vb_echo(VB_MSG_NORMAL, false, "%s", stdOut);
+ vb_echo(c, MSG_NORMAL, FALSE, "%s", stdOut);
} else {
- vb_echo(VB_MSG_ERROR, true, "[%d] %s", WEXITSTATUS(status), stdErr);
+ vb_echo(c, MSG_ERROR, TRUE, "[%d] %s", WEXITSTATUS(status), stdErr);
}
}
return res;
}
-static VbCmdResult ex_source(const ExArg *arg)
+static VbCmdResult ex_handlers(Client *c, const ExArg *arg)
{
- return ex_run_file(arg->rhs->str);
+ /* TODO no implemented yet */
+ return CMD_SUCCESS;
}
-static VbCmdResult ex_handlers(const ExArg *arg)
+static VbCmdResult ex_shortcut(Client *c, const ExArg *arg)
{
- char *p;
- gboolean success = false;
-
- switch (arg->code) {
- case EX_HANDADD:
- if (arg->rhs->len && (p = strchr(arg->rhs->str, '='))) {
- *p++ = '\0';
- success = handler_add(arg->rhs->str, p);
- }
- break;
-
- case EX_HANDREM:
- success = handler_remove(arg->rhs->str);
- break;
-
- default:
- break;
- }
-
- return success ? VB_CMD_SUCCESS : VB_CMD_ERROR;
-}
-
-static VbCmdResult ex_shortcut(const ExArg *arg)
-{
- char *p;
- gboolean success = false;
-
- /* TODO allow to set shortcuts with set command like ':set
- * shortcut[name]=http://donain.tld/?q=$0' */
- switch (arg->code) {
- case EX_SCA:
- if (arg->rhs->len && (p = strchr(arg->rhs->str, '='))) {
- *p++ = '\0';
- success = shortcut_add(arg->rhs->str, p);
- }
- break;
-
- case EX_SCR:
- success = shortcut_remove(arg->rhs->str);
- break;
-
- case EX_SCD:
- success = shortcut_set_default(arg->rhs->str);
- break;
-
- default:
- break;
- }
- return success ? VB_CMD_SUCCESS : VB_CMD_ERROR;
+ /* TODO no implemented yet */
+ return CMD_SUCCESS;
}
/**
@@ -1084,38 +902,38 @@ static VbCmdResult ex_shortcut(const ExArg *arg)
* put hte matched data back to inputbox, and prepares the tree list store
* model containing matched values.
*/
-static gboolean complete(short direction)
+static gboolean complete(Client *c, short direction)
{
char *input; /* input read from inputbox */
const char *in; /* pointer to input that we move */
- gboolean found = false;
- gboolean sort = true;
+ gboolean found = FALSE;
+ gboolean sort = TRUE;
GtkListStore *store;
/* if direction is 0 stop the completion */
if (!direction) {
- completion_clean();
+ completion_clean(c);
- return true;
+ return TRUE;
}
- input = vb_get_input_text();
+ input = vb_input_get_text(c);
/* if completion was already started move to the next/prev item */
- if (vb.mode->flags & FLAG_COMPLETION) {
+ if (c->mode->flags & FLAG_COMPLETION) {
if (excomp.current && !strcmp(input, excomp.current)) {
/* Step through the next/prev completion item. */
- if (!completion_next(direction < 0)) {
+ if (!completion_next(c, direction < 0)) {
/* If we stepped over the last/first item - put the initial content in */
- completion_select(excomp.token);
+ completion_select(c, excomp.token);
}
g_free(input);
- return true;
+ return TRUE;
}
/* if current input isn't the content of the completion item, stop
* completion and start it after that again */
- completion_clean();
+ completion_clean(c);
}
store = gtk_list_store_new(COMPLETION_STORE_NUM, G_TYPE_STRING, G_TYPE_STRING);
@@ -1137,7 +955,7 @@ static gboolean complete(short direction)
/* Do ex command specific completion if the comman is recognized and
* there is a space after the command and the optional '!' bang. */
- if (parse_command_name(&in, arg) && parse_bang(&in, arg) && VB_IS_SPACE(*in)) {
+ if (parse_command_name(c, &in, arg) && parse_bang(&in, arg) && VB_IS_SPACE(*in)) {
const char *token;
/* Get only the last word of input string for the completion for
* bookmark tag completion. */
@@ -1165,43 +983,33 @@ static gboolean complete(short direction)
switch (arg->code) {
case EX_OPEN:
case EX_TABOPEN:
- if (*token == '!') {
- found = bookmark_fill_completion(store, token + 1);
- } else {
- found = history_fill_completion(store, HISTORY_URL, token);
- }
- sort = false;
+ /* TODO add bookmark completion if *token == '!' */
+ found = history_fill_completion(store, HISTORY_URL, token);
break;
case EX_SET:
- found = setting_fill_completion(store, token);
+ sort = TRUE;
+ found = setting_fill_completion(c, store, token);
break;
case EX_BMA:
- found = bookmark_fill_tag_completion(store, token);
+ sort = TRUE;
+ /* TODO fill bookmark completion */
break;
case EX_SCR:
- found = shortcut_fill_completion(store, token);
+ sort = TRUE;
+ /* TODO fill shortcut completion */
break;
case EX_HANDREM:
- found = handler_fill_completion(store, token);
- break;
-
-#ifdef FEATURE_AUTOCMD
- case EX_AUTOCMD:
- found = autocmd_fill_event_completion(store, token);
+ sort = TRUE;
+ /* TODO fill handler completion */
break;
- case EX_AUGROUP:
- found = autocmd_fill_group_completion(store, token);
- break;
-#endif
-
case EX_SAVE:
- case EX_SOURCE:
- found = util_filename_fill_completion(store, token);
+ sort = TRUE;
+ found = util_filename_fill_completion(c, store, token);
break;
default:
@@ -1218,8 +1026,8 @@ static gboolean complete(short direction)
if (ex_fill_completion(store, in)) {
OVERWRITE_STRING(excomp.prefix, ":");
- found = true;
- sort = false;
+ found = TRUE;
+ sort = FALSE;
}
}
free_cmdarg(arg);
@@ -1227,7 +1035,7 @@ static gboolean complete(short direction)
if (history_fill_completion(store, HISTORY_SEARCH, in + 1)) {
OVERWRITE_STRING(excomp.token, in + 1);
OVERWRITE_NSTRING(excomp.prefix, in, 1);
- found = true;
+ found = TRUE;
}
}
@@ -1239,11 +1047,11 @@ static gboolean complete(short direction)
}
if (found) {
- completion_create(GTK_TREE_MODEL(store), completion_select, direction < 0);
+ completion_create(c, GTK_TREE_MODEL(store), completion_select, direction < 0);
}
g_free(input);
- return true;
+ return TRUE;
}
/**
@@ -1251,7 +1059,7 @@ static gboolean complete(short direction)
* matched item according with previously saved prefix and command name to the
* inputbox.
*/
-static void completion_select(char *match)
+static void completion_select(Client *c, char *match)
{
OVERWRITE_STRING(excomp.current, NULL);
@@ -1260,15 +1068,15 @@ static void completion_select(char *match)
} else {
excomp.current = g_strconcat(excomp.prefix, match, NULL);
}
- vb_set_input_text(excomp.current);
+ vb_input_set_text(c, excomp.current);
}
-static gboolean history(gboolean prev)
+static gboolean history(Client *c, gboolean prev)
{
char *input;
GList *new = NULL;
- input = vb_get_input_text();
+ input = vb_input_get_text(c);
if (exhist.active) {
/* calculate the actual content of the inpubox from history data, if
* the theoretical content and the actual given input are different
@@ -1293,11 +1101,11 @@ static gboolean history(gboolean prev)
/* check which type of history we should use */
if (*in == ':') {
- type = VB_INPUT_COMMAND;
+ type = INPUT_COMMAND;
} else if (*in == '/' || *in == '?') {
/* the history does not distinguish between forward and backward
* search, so we don't need the backward search here too */
- type = VB_INPUT_SEARCH_FORWARD;
+ type = INPUT_SEARCH_FORWARD;
} else {
goto failed;
}
@@ -1317,14 +1125,14 @@ static gboolean history(gboolean prev)
exhist.active = new;
}
- vb_echo_force(VB_MSG_NORMAL, false, "%s%s", exhist.prefix, (char*)exhist.active->data);
+ vb_echo_force(c, MSG_NORMAL, FALSE, "%s%s", exhist.prefix, (char*)exhist.active->data);
g_free(input);
- return true;
+ return TRUE;
failed:
g_free(input);
- return false;
+ return FALSE;
}
static void history_rewind(void)
diff --git a/src/ex.h b/src/ex.h
index cbd1281..1173d90 100644
--- a/src/ex.h
+++ b/src/ex.h
@@ -23,12 +23,11 @@
#include "config.h"
#include "main.h"
-void ex_enter(void);
-void ex_leave(void);
-VbResult ex_keypress(int key);
-void ex_input_changed(const char *text);
+void ex_enter(Client *c);
+void ex_leave(Client *c);
+VbResult ex_keypress(Client *c, int key);
+void ex_input_changed(Client *c, const char *text);
gboolean ex_fill_completion(GtkListStore *store, const char *input);
-VbCmdResult ex_run_string(const char *input, gboolean enable_history);
-VbCmdResult ex_run_file(const char *filename);
+VbCmdResult ex_run_string(Client *c, const char *input, gboolean enable_history);
#endif /* end of include guard: _EX_H */
diff --git a/src/ext-proxy.c b/src/ext-proxy.c
new file mode 100644
index 0000000..75ccbd7
--- /dev/null
+++ b/src/ext-proxy.c
@@ -0,0 +1,214 @@
+/**
+ * vimb - a webkit based vim like browser.
+ *
+ * Copyright (C) 2012-2015 Daniel Carl
+ *
+ * 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, see http://www.gnu.org/licenses/.
+ */
+
+#include <gio/gio.h>
+#include <glib.h>
+
+#include "ext-proxy.h"
+#include "main.h"
+#include "webextension/ext-main.h"
+
+static void dbus_call(Client *c, const char *method, GVariant *param,
+ GAsyncReadyCallback callback);
+static void on_editable_change_focus(GDBusConnection *connection,
+ const char *sender_name, const char *object_path,
+ const char *interface_name, const char *signal_name,
+ GVariant *parameters, gpointer data);
+static void on_name_appeared(GDBusConnection *connection, const char *name,
+ const char *owner, gpointer data);
+static void on_proxy_created(GDBusProxy *new_proxy, GAsyncResult *result,
+ gpointer data);
+static void on_web_extension_page_created(GDBusConnection *connection,
+ const char *sender_name, const char *object_path,
+ const char *interface_name, const char *signal_name,
+ GVariant *parameters, gpointer data);
+
+/* TODO we need potentially multiple proxies. Because a single instance of
+ * vimb may hold multiple clients which may use more than one webprocess and
+ * therefore multiple webextension instances. */
+extern struct Vimb vb;
+
+
+/**
+ * Request the web extension to focus first editable element.
+ * Returns whether an focusable element was found or not.
+ */
+void ext_proxy_focus_input(Client *c)
+{
+ dbus_call(c, "FocusInput", NULL, NULL);
+}
+
+/**
+ * Initialize the dbus proxy by watching for appearing dbus name.
+ */
+void ext_proxy_init(const char *id)
+{
+ char *service_name;
+
+ service_name = g_strdup_printf("%s-%s", VB_WEBEXTENSION_SERVICE_NAME, id);
+ g_bus_watch_name(
+ G_BUS_TYPE_SESSION,
+ service_name,
+ G_BUS_NAME_WATCHER_FLAGS_NONE,
+ (GBusNameAppearedCallback)on_name_appeared,
+ NULL,
+ NULL,
+ NULL);
+ g_free(service_name);
+}
+
+/**
+ * Send the headers string to the webextension.
+ */
+void ext_proxy_set_header(Client *c, const char *headers)
+{
+ dbus_call(c, "SetHeaderSetting", g_variant_new("(s)", headers), NULL);
+}
+
+/**
+ * Call a dbus method.
+ */
+static void dbus_call(Client *c, const char *method, GVariant *param,
+ GAsyncReadyCallback callback)
+{
+ /* TODO add function to queue calls until the proxy connection is
+ * established */
+ if (!c->dbusproxy) {
+ return;
+ }
+ g_dbus_proxy_call(c->dbusproxy, method, param, G_DBUS_CALL_FLAGS_NONE, -1, NULL, callback, c);
+}
+
+/**
+ * Callback called if a editable element changes it's focus state.
+ */
+static void on_editable_change_focus(GDBusConnection *connection,
+ const char *sender_name, const char *object_path,
+ const char *interface_name, const char *signal_name,
+ GVariant *parameters, gpointer data)
+{
+ gboolean is_focused;
+ Client *c = (Client*)data;
+ g_variant_get(parameters, "(b)", &is_focused);
+
+ /* Don't change the mode if we are in pass through mode. */
+ if (c->mode->id == 'n' && is_focused) {
+ vb_enter(c, 'i');
+ } else if (c->mode->id == 'i' && !is_focused) {
+ vb_enter(c, 'n');
+ }
+ /* TODO allo strict-focus to ignore focus event for initial set focus */
+}
+
+/**
+ * Called when the name of the webextension appeared on the dbus session bus.
+ */
+static void on_name_appeared(GDBusConnection *connection, const char *name,
+ const char *owner, gpointer data)
+{
+ int flags = G_DBUS_PROXY_FLAGS_DO_NOT_AUTO_START
+ | G_DBUS_PROXY_FLAGS_DO_NOT_LOAD_PROPERTIES
+ | G_DBUS_PROXY_FLAGS_DO_NOT_CONNECT_SIGNALS;
+
+ /* Create the proxy to communicate over dbus. */
+ g_dbus_proxy_new(connection, flags, NULL, name,
+ VB_WEBEXTENSION_OBJECT_PATH, VB_WEBEXTENSION_INTERFACE, NULL,
+ (GAsyncReadyCallback)on_proxy_created, NULL);
+}
+
+/**
+ * Callback called when the dbus proxy is created.
+ */
+static void on_proxy_created(GDBusProxy *new_proxy, GAsyncResult *result, gpointer data)
+{
+ GDBusConnection *connection;
+ GDBusProxy *proxy;
+ GError *error = NULL;
+
+ proxy = g_dbus_proxy_new_finish(result, &error);
+ connection = g_dbus_proxy_get_connection(proxy);
+
+ if (!proxy) {
+ g_warning("Error creating web extension proxy: %s", error->message);
+ g_error_free(error);
+ return;
+ }
+ g_dbus_proxy_set_default_timeout(proxy, 100);
+ g_dbus_connection_signal_subscribe(
+ connection,
+ NULL,
+ VB_WEBEXTENSION_INTERFACE,
+ "PageCreated",
+ VB_WEBEXTENSION_OBJECT_PATH,
+ NULL,
+ G_DBUS_SIGNAL_FLAGS_NONE,
+ (GDBusSignalCallback)on_web_extension_page_created,
+ proxy,
+ NULL);
+}
+
+/**
+ * Listen to the VerticalScroll signal of the webextension and set the scroll
+ * percent value on the client to update the statusbar.
+ */
+static void on_vertical_scroll(GDBusConnection *connection,
+ const char *sender_name, const char *object_path,
+ const char *interface_name, const char *signal_name,
+ GVariant *parameters, gpointer data)
+{
+ Client *c = (Client*)data;
+ g_variant_get(parameters, "(tt)", &c->state.scroll_max, &c->state.scroll_percent);
+
+ vb_statusbar_update(c);
+}
+
+/**
+ * Called when the web context created the page.
+ *
+ * Find the right client to the page id returned from the webextension.
+ * Add the proxy connection to the client for later calls.
+ */
+static void on_web_extension_page_created(GDBusConnection *connection,
+ const char *sender_name, const char *object_path,
+ const char *interface_name, const char *signal_name,
+ GVariant *parameters, gpointer data)
+{
+ Client *p;
+ guint64 page_id;
+
+ g_variant_get(parameters, "(t)", &page_id);
+
+ /* Search for the client with the same page id as returned by the
+ * webextension. */
+ for (p = vb.clients; p && p->page_id != page_id; p = p->next);
+
+ if (p) {
+ /* Set the dbus proxy on the right client based on page id. */
+ p->dbusproxy = data;
+
+ g_dbus_connection_signal_subscribe(connection, NULL,
+ VB_WEBEXTENSION_INTERFACE, "VerticalScroll",
+ VB_WEBEXTENSION_OBJECT_PATH, NULL, G_DBUS_SIGNAL_FLAGS_NONE,
+ (GDBusSignalCallback)on_vertical_scroll, p, NULL);
+ g_dbus_connection_signal_subscribe(connection, NULL,
+ VB_WEBEXTENSION_INTERFACE, "EditableChangeFocus",
+ VB_WEBEXTENSION_OBJECT_PATH, NULL, G_DBUS_SIGNAL_FLAGS_NONE,
+ (GDBusSignalCallback)on_editable_change_focus, p, NULL);
+ }
+}
diff --git a/src/arh.h b/src/ext-proxy.h
index d235b36..b5b33a1 100644
--- a/src/arh.h
+++ b/src/ext-proxy.h
@@ -2,7 +2,6 @@
* vimb - a webkit based vim like browser.
*
* Copyright (C) 2012-2015 Daniel Carl
- * Copyright (C) 2014 Sébastien Marie
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -18,17 +17,13 @@
* along with this program. If not, see http://www.gnu.org/licenses/.
*/
-#include "config.h"
-#ifdef FEATURE_ARH
-
-#ifndef _ARH_H
-#define _ARH_H
+#ifndef _EXT_PROXY_H
+#define _EXT_PROXY_H
#include "main.h"
-GSList *arh_parse(const char *, const char **);
-void arh_free(GSList *);
-void arh_run(GSList *, const char *, SoupMessage *);
+void ext_proxy_focus_input(Client *c);
+void ext_proxy_init(const char *id);
+void ext_proxy_set_header(Client *c, const char *headers);
-#endif /* end of include guard: _ARH_H */
-#endif
+#endif /* end of include guard: _EXT_PROXY_H */
diff --git a/src/handlers.c b/src/handlers.c
deleted file mode 100644
index 66625bf..0000000
--- a/src/handlers.c
+++ /dev/null
@@ -1,96 +0,0 @@
-/**
- * vimb - a webkit based vim like browser.
- *
- * Copyright (C) 2012-2015 Daniel Carl
- *
- * 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, see http://www.gnu.org/licenses/.
- */
-
-#include "main.h"
-#include "handlers.h"
-#include "util.h"
-
-static GHashTable *handlers = NULL;
-
-static char *handler_lookup(const char *uri);
-
-
-void handlers_init(void)
-{
- handlers = g_hash_table_new_full(g_str_hash, g_str_equal, g_free, g_free);
-}
-
-void handlers_cleanup(void)
-{
- if (handlers) {
- g_hash_table_destroy(handlers);
- }
-}
-
-gboolean handler_add(const char *key, const char *cmd)
-{
- g_hash_table_insert(handlers, g_strdup(key), g_strdup(cmd));
-
- return true;
-}
-
-gboolean handler_remove(const char *key)
-{
- return g_hash_table_remove(handlers, key);
-}
-
-gboolean handle_uri(const char *uri)
-{
- char *handler, *cmd;
- GError *error = NULL;
- gboolean result;
-
- if (!(handler = handler_lookup(uri))) {
- return false;
- }
-
- cmd = g_strdup_printf(handler, uri);
- if (!g_spawn_command_line_async(cmd, &error)) {
- g_warning("Can't run '%s': %s", cmd, error->message);
- g_clear_error(&error);
- result = false;
- } else {
- result = true;
- }
-
- g_free(cmd);
- return result;
-}
-
-gboolean handler_fill_completion(GtkListStore *store, const char *input)
-{
- GList *src = g_hash_table_get_keys(handlers);
- gboolean found = util_fill_completion(store, input, src);
- g_list_free(src);
-
- return found;
-}
-
-static char *handler_lookup(const char *uri)
-{
- char *p, *schema, *handler = NULL;
-
- if ((p = strchr(uri, ':'))) {
- schema = g_strndup(uri, p - uri);
- handler = g_hash_table_lookup(handlers, schema);
- g_free(schema);
- }
-
- return handler;
-}
diff --git a/src/hints.c b/src/hints.c
deleted file mode 100644
index 91bb869..0000000
--- a/src/hints.c
+++ /dev/null
@@ -1,398 +0,0 @@
-/**
- * vimb - a webkit based vim like browser.
- *
- * Copyright (C) 2012-2015 Daniel Carl
- *
- * 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, see http://www.gnu.org/licenses/.
- */
-
-#include "config.h"
-#include <gdk/gdkkeysyms.h>
-#include <gdk/gdkkeysyms-compat.h>
-#include "hints.h"
-#include "main.h"
-#include "ascii.h"
-#include "dom.h"
-#include "command.h"
-#include "hints.js.h"
-#include "input.h"
-#include "map.h"
-#include "js.h"
-
-#define HINT_FILE "hints.js"
-
-static struct {
- JSObjectRef obj; /* the js object */
- char mode; /* mode identifying char - that last char of the hint prompt */
- int promptlen; /* length of the hint prompt chars 2 or 3 */
- gboolean gmode; /* indicate if the hints 'g' mode is used */
- JSContextRef ctx;
-#if WEBKIT_CHECK_VERSION(2, 0, 0)
- /* holds the setting if JavaScript can open windows automatically that we
- * have to change to open windows via hinting */
- gboolean allow_open_win;
-#endif
- guint timeout_id;
-} hints;
-
-extern VbCore vb;
-
-static gboolean call_hints_function(const char *func, int count, JSValueRef params[]);
-static void fire_timeout(gboolean on);
-static gboolean fire_cb(gpointer data);
-
-
-void hints_init(WebKitWebFrame *frame)
-{
- if (hints.obj) {
- JSValueUnprotect(hints.ctx, hints.obj);
- hints.obj = NULL;
- }
- if (!hints.obj) {
- hints.ctx = webkit_web_frame_get_global_context(frame);
- hints.obj = js_create_object(hints.ctx, HINTS_JS);
- }
-}
-
-VbResult hints_keypress(int key)
-{
- JSValueRef arguments[1];
-
- if (key == KEY_CR) {
- hints_fire();
-
- return RESULT_COMPLETE;
- } else if (key == CTRL('H')) {
- fire_timeout(false);
- arguments[0] = JSValueMakeNull(hints.ctx);
- if (call_hints_function("update", 1, arguments)) {
- return RESULT_COMPLETE;
- }
- } else if (key == KEY_TAB) {
- fire_timeout(false);
- hints_focus_next(false);
-
- return RESULT_COMPLETE;
- } else if (key == KEY_SHIFT_TAB) {
- fire_timeout(false);
- hints_focus_next(true);
-
- return RESULT_COMPLETE;
- } else {
- fire_timeout(true);
- /* try to handle the key by the javascript */
- arguments[0] = js_string_to_ref(hints.ctx, (char[]){key, '\0'});
- if (call_hints_function("update", 1, arguments)) {
- return RESULT_COMPLETE;
- }
- }
-
- fire_timeout(false);
- return RESULT_ERROR;
-}
-
-void hints_clear(void)
-{
- if (vb.mode->flags & FLAG_HINTING) {
- vb.mode->flags &= ~FLAG_HINTING;
- vb_set_input_text("");
-
- call_hints_function("clear", 0, NULL);
-
- g_signal_emit_by_name(vb.gui.webview, "hovering-over-link", NULL, NULL);
-
-#if WEBKIT_CHECK_VERSION(2, 0, 0)
- /* if open window was not allowed for JavaScript, restore this */
- if (!hints.allow_open_win) {
- WebKitWebSettings *setting = webkit_web_view_get_settings(vb.gui.webview);
- g_object_set(G_OBJECT(setting), "javascript-can-open-windows-automatically", hints.allow_open_win, NULL);
- }
-#endif
- }
-}
-
-void hints_create(const char *input)
-{
- /* don't start hinting if the hinting object isn't created - for example
- * if hinting is started before the first data of page are received */
- if (!hints.obj) {
- return;
- }
-
- /* check if the input contains a valid hinting prompt */
- if (!hints_parse_prompt(input, &hints.mode, &hints.gmode)) {
- /* if input is not valid, clear possible previous hint mode */
- if (vb.mode->flags & FLAG_HINTING) {
- vb_enter('n');
- }
- return;
- }
-
- if (!(vb.mode->flags & FLAG_HINTING)) {
- vb.mode->flags |= FLAG_HINTING;
-
-#if WEBKIT_CHECK_VERSION(2, 0, 0)
- WebKitWebSettings *setting = webkit_web_view_get_settings(vb.gui.webview);
-
- /* before we enable JavaScript to open new windows, we save the actual
- * value to be able restore it after hints where fired */
- g_object_get(G_OBJECT(setting), "javascript-can-open-windows-automatically", &(hints.allow_open_win), NULL);
-
- /* if window open is already allowed there's no need to allow it again */
- if (!hints.allow_open_win) {
- g_object_set(G_OBJECT(setting), "javascript-can-open-windows-automatically", true, NULL);
- }
-#endif
-
- hints.promptlen = hints.gmode ? 3 : 2;
-
- JSValueRef arguments[] = {
- js_string_to_ref(hints.ctx, (char[]){hints.mode, '\0'}),
- JSValueMakeBoolean(hints.ctx, hints.gmode),
- JSValueMakeNumber(hints.ctx, MAXIMUM_HINTS),
- js_string_to_ref(hints.ctx, GET_CHAR("hintkeys")),
- JSValueMakeBoolean(hints.ctx, GET_BOOL("hint-follow-last")),
- JSValueMakeBoolean(hints.ctx, GET_BOOL("hint-number-same-length"))
- };
- call_hints_function("init", 6, arguments);
-
- /* if hinting is started there won't be any additional filter given and
- * we can go out of this function */
- return;
- }
-
- JSValueRef arguments[] = {js_string_to_ref(hints.ctx, *(input + hints.promptlen) ? input + hints.promptlen : "")};
- call_hints_function("filter", 1, arguments);
-}
-
-void hints_focus_next(const gboolean back)
-{
- JSValueRef arguments[] = {
- JSValueMakeNumber(hints.ctx, back)
- };
- call_hints_function("focus", 1, arguments);
-}
-
-void hints_fire(void)
-{
- call_hints_function("fire", 0, NULL);
-}
-
-void hints_follow_link(const gboolean back, int count)
-{
- char *json = g_strdup_printf(
- "[%s]",
- back ? vb.config.prevpattern : vb.config.nextpattern
- );
-
- JSValueRef arguments[] = {
- js_string_to_ref(hints.ctx, back ? "prev" : "next"),
- js_object_to_ref(hints.ctx, json),
- JSValueMakeNumber(hints.ctx, count)
- };
- g_free(json);
-
- call_hints_function("followLink", 3, arguments);
-}
-
-void hints_increment_uri(int count)
-{
- JSValueRef arguments[] = {
- JSValueMakeNumber(hints.ctx, count)
- };
-
- call_hints_function("incrementUri", 1, arguments);
-}
-
-/**
- * Checks if the given hint prompt belong to a known and valid hints mode and
- * parses the mode and is_gmode into given pointers.
- *
- * The given prompt sting may also contain additional chars after the prompt.
- *
- * @prompt: String to be parsed as prompt. The Prompt can be followed by
- * additional characters.
- * @mode: Pointer to char that will be filled with mode char if prompt was
- * valid and given pointer is not NULL.
- * @is_gmode: Pointer to gboolean to be filled with the flag to indicate gmode
- * hinting.
- */
-gboolean hints_parse_prompt(const char *prompt, char *mode, gboolean *is_gmode)
-{
- gboolean res;
- char pmode = '\0';
-#ifdef FEATURE_QUEUE
- static char *modes = "eiIoOpPstTxyY";
- static char *g_modes = "IpPstyY";
-#else
- static char *modes = "eiIoOstTxyY";
- static char *g_modes = "IstyY";
-#endif
-
- if (!prompt) {
- return false;
- }
-
- /* get the mode identifying char from prompt */
- if (*prompt == ';') {
- pmode = prompt[1];
- } else if (*prompt == 'g' && strlen(prompt) >= 3) {
- /* get mode for g;X hint modes */
- pmode = prompt[2];
- }
-
- /* no mode found in prompt */
- if (!pmode) {
- return false;
- }
-
- res = *prompt == 'g'
- ? strchr(g_modes, pmode) != NULL
- : strchr(modes, pmode) != NULL;
-
- /* fill pointer only if the prompt was valid */
- if (res) {
- if (mode != NULL) {
- *mode = pmode;
- }
- if (is_gmode != NULL) {
- *is_gmode = *prompt == 'g';
- }
- }
-
- return res;
-}
-
-static gboolean call_hints_function(const char *func, int count, JSValueRef params[])
-{
- char *value = js_object_call_function(hints.ctx, hints.obj, func, count, params);
-
- g_return_val_if_fail(value != NULL, false);
-
- if (!strncmp(value, "ERROR:", 6)) {
- g_free(value);
- return false;
- }
-
- if (!strncmp(value, "OVER:", 5)) {
- g_signal_emit_by_name(
- vb.gui.webview, "hovering-over-link", NULL, *(value + 5) == '\0' ? NULL : (value + 5)
- );
- g_free(value);
-
- return true;
- }
-
- /* following return values mark fired hints */
- if (!strncmp(value, "DONE:", 5)) {
- fire_timeout(false);
- /* Change to normal mode only if we are currently in command mode and
- * we are not in g-mode hinting. This is required to not switch to
- * normal mode when the hinting triggered a click that set focus on
- * editable element that lead vimb to switch to input mode. */
- if (!hints.gmode && vb.mode->id == 'c') {
- vb_enter('n');
- }
- } else if (!strncmp(value, "INSERT:", 7)) {
- fire_timeout(false);
- vb_enter('i');
- if (hints.mode == 'e') {
- input_open_editor();
- }
- } else if (!strncmp(value, "DATA:", 5)) {
- fire_timeout(false);
- /* switch first to normal mode - else we would clear the inputbox
- * on switching mode also if we want to show yanked data */
- if (!hints.gmode) {
- vb_enter('n');
- }
-
- char *v = (value + 5);
- Arg a = {0};
- /* put the hinted value into register "; */
- vb_register_add(';', v);
- switch (hints.mode) {
- /* used if images should be opened */
- case 'i':
- case 'I':
- a.s = v;
- a.i = (hints.mode == 'I') ? VB_TARGET_NEW : VB_TARGET_CURRENT;
- vb_load_uri(&a);
- break;
-
- case 'O':
- case 'T':
- vb_echo(VB_MSG_NORMAL, false, "%s %s", (hints.mode == 'T') ? ":tabopen" : ":open", v);
- if (!hints.gmode) {
- vb_enter('c');
- }
- break;
-
- case 's':
- a.s = v;
- a.i = COMMAND_SAVE_URI;
- command_save(&a);
- break;
-
- case 'x':
- map_handle_string(GET_CHAR("x-hint-command"), true);
- break;
-
- case 'y':
- case 'Y':
- a.i = COMMAND_YANK_ARG;
- a.s = v;
- command_yank(&a, vb.state.current_register);
- break;
-
-#ifdef FEATURE_QUEUE
- case 'p':
- case 'P':
- a.s = v;
- a.i = (hints.mode == 'P') ? COMMAND_QUEUE_UNSHIFT : COMMAND_QUEUE_PUSH;
- command_queue(&a);
- break;
-#endif
- }
- }
- g_free(value);
- return true;
-}
-
-static void fire_timeout(gboolean on)
-{
- int millis;
- /* remove possible timeout function */
- if (hints.timeout_id) {
- g_source_remove(hints.timeout_id);
- hints.timeout_id = 0;
- }
-
- if (on) {
- millis = GET_INT("hint-timeout");
- if (millis) {
- hints.timeout_id = g_timeout_add(millis, (GSourceFunc)fire_cb, NULL);
- }
- }
-}
-
-static gboolean fire_cb(gpointer data)
-{
- hints_fire();
-
- /* remove timeout id for the timeout that is removed by return value of
- * false automatic */
- hints.timeout_id = 0;
- return false;
-}
diff --git a/src/hints.js b/src/hints.js
deleted file mode 100644
index 458d85c..0000000
--- a/src/hints.js
+++ /dev/null
@@ -1,611 +0,0 @@
-Object.freeze((function(){
- 'use strict';
-
- var hints = [], /* holds all hint data (hinted element, label, number) in view port */
- docs = [], /* hold the affected document with the start and end index of the hints */
- validHints = [], /* holds the valid hinted elements matching the filter condition */
- activeHint, /* holds the active hint object */
- filterText = "", /* holds the typed filter text */
- filterNum = 0, /* holds the numeric filter */
- /* TODO remove these classes and use the 'vimbhint' attribute for */
- /* styling the hints and labels - but this might break user */
- /* stylesheets that use the classes for styling */
- cId = "_hintContainer", /* id of the container holding the hint labels */
- lClass = "_hintLabel", /* class used on the hint labels with the hint numbers */
- hClass = "_hintElem", /* marks hinted elements */
- fClass = "_hintFocus", /* marks focused element and focussed hint */
- config;
- /* the hint class used to maintain hinted element and labels */
- function Hint() {
- /* hide hint label and remove coloring from hinted element */
- this.hide = function() {
- /* remove hint labels from no more visible hints */
- this.label.style.display = "none";
- this.e.classList.remove(fClass);
- this.e.classList.remove(hClass);
- };
-
- /* show the hint element colored with the hint label */
- this.show = function() {
- this.label.style.display = "";
- this.e.classList.add(hClass);
-
- /* create the label with the hint number */
- var text = [];
- if (this.e instanceof HTMLInputElement) {
- var type = this.e.type;
- if (type === "checkbox") {
- text.push(this.e.checked ? "☑" : "☐");
- } else if (type === "radio") {
- text.push(this.e.checked ? "⊙" : "○");
- }
- }
- if (this.showText && this.text) {
- text.push(this.text.substr(0, 20));
- }
- /* use \x20 instead of ' ' to keep this space during js2h.sh processing */
- this.label.innerText = this.num + (text.length ? ":\x20" + text.join("\x20") : "");
- };
- }
-
- function clear() {
- var i, j, doc, e;
- for (i = 0; i < docs.length; i++) {
- doc = docs[i];
- /* find all hinted elements vimbhint 'hint' */
- var res = xpath(doc.doc, "//*[contains(@vimbhint, 'hint')]");
- for (j = 0; j < res.snapshotLength; j++) {
- e = res.snapshotItem(j);
- e.removeAttribute("vimbhint");
- e.classList.remove(fClass);
- e.classList.remove(hClass);
- }
- doc.div.parentNode.removeChild(doc.div);
- }
- docs = [];
- hints = [];
- validHints = [];
- filterText = "";
- filterNum = 0;
- }
-
- function create() {
- var count = 0;
-
- function helper(win, offsets) {
- /* document may be undefined for frames out of the same origin */
- /* policy and will break the whole code - so we check this before */
- if (typeof win.document == "undefined") {
- return;
- }
-
- offsets = offsets || {left: 0, right: 0, top: 0, bottom: 0};
- offsets.right = win.innerWidth - offsets.right;
- offsets.bottom = win.innerHeight - offsets.bottom;
-
- /* checks if given elemente is in viewport and visible */
- function isVisible(e) {
- if (typeof e == "undefined") {
- return false;
- }
- var rect = e.getBoundingClientRect();
- if (!rect ||
- rect.top > offsets.bottom || rect.bottom < offsets.top ||
- rect.left > offsets.right || rect.right < offsets.left
- ) {
- return false;
- }
-
- if ((!rect.width || !rect.height) && (e.textContent || !e.name)) {
- var arr = Array.prototype.slice.call(e.childNodes);
- var check = function(e) {
- return e instanceof Element
- && e.style.float != "none"
- && isVisible(e);
- };
- if (!arr.some(check)) {
- return false;
- }
- }
-
- var s = win.getComputedStyle(e, null);
- return s.display !== "none" && s.visibility == "visible";
- }
-
- var doc = win.document,
- res = xpath(doc, config.xpath),
- /* generate basic hint element which will be cloned and updated later */
- labelTmpl = doc.createElement("span"),
- e, i;
-
- labelTmpl.className = lClass;
- labelTmpl.setAttribute("vimbhint", "label");
-
- var containerOffsets = getOffsets(doc),
- offsetX = containerOffsets[0],
- offsetY = containerOffsets[1],
- fragment = doc.createDocumentFragment(),
- rect, label, text, showText, start = hints.length;
-
- /* collect all visible elements in hints array */
- for (i = 0; i < res.snapshotLength; i++) {
- e = res.snapshotItem(i);
- if (!isVisible(e)) {
- continue;
- }
-
- count++;
-
- /* create the hint label with number */
- rect = e.getBoundingClientRect();
- label = labelTmpl.cloneNode(false);
- label.setAttribute(
- "style", [
- "display:none;",
- "left:", Math.max((rect.left + offsetX), offsetX), "px;",
- "top:", Math.max((rect.top + offsetY), offsetY), "px;"
- ].join("")
- );
-
- /* if hinted element is an image - show title or alt of the image in hint label */
- /* this allows to see how to filter for the image */
- text = "";
- showText = false;
- if (e instanceof HTMLImageElement) {
- text = e.title || e.alt;
- showText = true;
- } else if (e.firstElementChild instanceof HTMLImageElement && /^\s*$/.test(e.textContent)) {
- text = e.firstElementChild.title || e.firstElementChild.alt;
- showText = true;
- } else if (e instanceof HTMLInputElement) {
- var type = e.type;
- if (type === "image") {
- text = e.alt || "";
- } else if (e.value && type !== "password") {
- text = e.value;
- showText = (type === "radio" || type === "checkbox");
- }
- } else if (e instanceof HTMLSelectElement) {
- if (e.selectedIndex >= 0) {
- text = e.item(e.selectedIndex).text;
- }
- } else {
- text = e.textContent;
- }
- /* add the hint class to the hinted element */
- fragment.appendChild(label);
- e.setAttribute("vimbhint", "hint");
-
- hints.push({
- e: e,
- label: label,
- text: text,
- showText: showText,
- __proto__: new Hint
- });
-
- if (count >= config.maxHints) {
- break;
- }
- }
-
- /* append the fragment to the document */
- var hDiv = doc.createElement("div");
- hDiv.id = cId;
- hDiv.setAttribute("vimbhint", "container");
- hDiv.appendChild(fragment);
- if (doc.body) {
- doc.body.appendChild(hDiv);
- }
- /* create the default style sheet */
- createStyle(doc);
-
- docs.push({
- doc: doc,
- start: start,
- end: hints.length - 1,
- div: hDiv
- });
-
- /* recurse into any iframe or frame element */
- for (i = 0; i < win.frames.length; i++) {
- var rect,
- f = win.frames[i],
- e = f.frameElement;
-
- if (isVisible(e)) {
- rect = e.getBoundingClientRect();
- helper(f, {
- left: Math.max(offsets.left - rect.left, 0),
- right: Math.max(rect.right - offsets.right, 0),
- top: Math.max(offsets.top - rect.top, 0),
- bottom: Math.max(rect.bottom - offsets.bottom, 0)
- });
- }
- }
- }
-
- helper(window);
- }
-
- function show(fireLast) {
- var i, hint, newIdx,
- n = 1,
- matcher = getMatcher(filterText),
- str = getHintString(filterNum);
-
- if (config.hintNumSameLength) {
- /* get number of hints to be shown */
- var hintCount = 0;
- for (i = 0; i < hints.length; i++) {
- if (matcher(hints[i].text)) {
- hintCount++;
- }
- }
- /* increase starting point of hint numbers until there are */
- /* enough available numbers */
- var len = config.hintKeys.length;
- while (n * (len - 1) < hintCount) {
- n *= len;
- }
- }
-
- /* clear the array of valid hints */
- validHints = [];
- for (i = 0; i < hints.length; i++) {
- hint = hints[i];
- /* hide hints not matching the filter text */
- if (!matcher(hint.text)) {
- hint.hide();
- } else {
- /* assign the new hint number/letters as label to the hint */
- hint.num = getHintString(n++);
- /* check for number filter */
- if (!filterNum || 0 === hint.num.indexOf(str)) {
- hint.show();
- validHints.push(hint);
- } else {
- hint.hide();
- }
- }
- }
- if (fireLast && config.followLast && validHints.length <= 1) {
- focusHint(0);
- return fire();
- }
-
- /* if the previous active hint isn't valid set focus to first */
- if (!activeHint || validHints.indexOf(activeHint) < 0) {
- return focusHint(0);
- }
- }
-
- /* Returns a validator method to check if the hint elements text matches */
- /* the given filter text. */
- function getMatcher(text) {
- var tokens = text.toLowerCase().split(/\s+/);
- return function (itemText) {
- itemText = itemText.toLowerCase();
- return tokens.every(function (token) {
- return 0 <= itemText.indexOf(token);
- });
- };
- }
-
- /* Retrun the hint string for a given number based on configured hintkeys */
- function getHintString(n) {
- var res = [],
- len = config.hintKeys.length;
- do {
- res.push(config.hintKeys[n % len]);
- n = Math.floor(n / len);
- } while (n > 0);
-
- return res.reverse().join("");
- }
-
- function getOffsets(doc) {
- var body = doc.body || doc.documentElement,
- style = body.style,
- rect;
-
- if (style && /^(absolute|fixed|relative)$/.test(style.position)) {
- rect = body.getClientRects()[0];
- return [-rect.left, -rect.top];
- }
- return [doc.defaultView.scrollX, doc.defaultView.scrollY];
- }
-
- function createStyle(doc) {
- if (doc.hasStyle) {
- return;
- }
- var e = doc.createElement("style");
- /* HINT_CSS is replaces by the contents of the HINT_CSS constant from config.h */
- e.innerHTML = "HINT_CSS";
- doc.head.appendChild(e);
- /* prevent us from adding the style multiple times */
- doc.hasStyle = true;
- }
-
- function focus(back) {
- var idx = validHints.indexOf(activeHint);
- /* previous active hint not found */
- if (idx < 0) {
- idx = 0;
- }
-
- if (back) {
- if (--idx < 0) {
- idx = validHints.length - 1;
- }
- } else {
- if (++idx >= validHints.length) {
- idx = 0;
- }
- }
- return focusHint(idx);
- }
-
- function fire() {
- if (!activeHint) {
- return "ERROR:";
- }
-
- var e = activeHint.e,
- res;
-
- /* process form actions like focus toggling inputs */
- if (config.handleForm) {
- res = handleForm(e);
- }
-
- if (config.keepOpen) {
- /* reset the filter number */
- filterNum = 0;
- show(false);
- } else {
- clear();
- }
-
- return res || config.action(e);
- }
-
- /* focus or toggle form fields */
- function handleForm(e) {
- var tag = e.nodeName.toLowerCase(),
- type = e.type || "";
-
- if (tag === "input" || tag === "textarea" || tag === "select") {
- if (type === "radio" || type === "checkbox") {
- e.focus();
- click(e);
- return "DONE:";
- }
- if (type === "submit" || type === "reset" || type === "button" || type === "image") {
- click(e);
- return "DONE:";
- }
- e.focus();
- return "INSERT:";
- }
- if (tag === "iframe" || tag === "frame") {
- e.focus();
- return "DONE:";
- }
- }
-
- /* internal used methods */
- function open(e, newWin) {
- var oldTarget = e.target;
- if (newWin) {
- /* set target to open in new window */
- e.target = "_blank";
- } else if (e.target === "_blank") {
- e.removeAttribute("target");
- }
- /* to open links in new window the mouse events are fired with ctrl */
- /* key - otherwise some ugly pages will ignore this attribute in their */
- /* mouse event observers like duckduckgo */
- click(e, newWin);
- e.target = oldTarget;
- }
-
- /* set focus on hint with given index valid hints array */
- function focusHint(newIdx) {
- /* reset previous focused hint */
- if (activeHint) {
- activeHint.e.classList.remove(fClass);
- activeHint.label.classList.remove(fClass);
- mouseEvent(activeHint.e, "mouseout");
- }
- /* get the new active hint */
- if ((activeHint = validHints[newIdx])) {
- activeHint.e.classList.add(fClass);
- activeHint.label.classList.add(fClass);
- mouseEvent(activeHint.e, "mouseover");
-
- return "OVER:" + getSrc(activeHint.e);;
- }
- }
-
- function click(e, ctrl) {
- mouseEvent(e, "mouseover", ctrl);
- mouseEvent(e, "mousedown", ctrl);
- mouseEvent(e, "mouseup", ctrl);
- mouseEvent(e, "click", ctrl);
- }
-
- function mouseEvent(e, name, ctrl) {
- var evObj = e.ownerDocument.createEvent("MouseEvents");
- evObj.initMouseEvent(
- name, true, true, e.ownerDocument.defaultView,
- 0, 0, 0, 0, 0,
- (typeof ctrl != "undefined") ? ctrl : false, false, false, false, 0, null
- );
- e.dispatchEvent(evObj);
- }
-
- /* retrieves the url of given element */
- function getSrc(e) {
- return e.href || e.src || "";
- }
-
- function xpath(doc, expr) {
- return doc.evaluate(
- expr, doc, function (p) {return "http://www.w3.org/1999/xhtml";},
- XPathResult.ORDERED_NODE_SNAPSHOT_TYPE, null
- );
- }
-
- /* follow the count last link on pagematching the given regex list */
- function followLink(rel, patterns, count) {
- /* returns array of matching elements */
- function followFrame(frame) {
- var i, p, reg, res = [],
- doc = frame.document,
- elems = [],
- all = doc.getElementsByTagName("a");
-
- /* first match links by rel attribute */
- for (i = all.length - 1; i >= 0; i--) {
- /* collect visible elements */
- var s = doc.defaultView.getComputedStyle(all[i], null);
- if (s.display !== "none" && s.visibility === "visible") {
- /* if there are rel attributes elements, put them in the result */
- if (all[i].rel.toLowerCase() === rel) {
- res.push(all[i]);
- } else {
- /* save to match them later */
- elems.push(all[i]);
- }
- }
- }
- /* match each pattern successively against each link in the page */
- for (p = 0; p < patterns.length; p++) {
- reg = patterns[p];
- /* begin with the last link on page */
- for (i = elems.length - 1; i >= 0; i--) {
- if (elems[i].innerText.match(reg)) {
- res.push(elems[i]);
- }
- }
- }
- return res;
- }
- var i, j, elems, frames = allFrames(window);
- for (i = 0; i < frames.length; i++) {
- elems = followFrame(frames[i]);
- for (j = 0; j < elems.length; j++) {
- if (--count == 0) {
- open(elems[j], false);
- return "DONE:";
- }
- }
- }
- return "ERROR:";
- }
-
- function incrementUri(count) {
- var oldnum, newnum, matches = location.href.match(/(.*?)(\d+)(\D*)$/);
- if (matches) {
- oldnum = matches[2];
- newnum = String(Math.max(parseInt(oldnum) + count, 0));
- /* keep prepending zeros */
- if (/^0/.test(oldnum)) {
- while (newnum.length < oldnum.length) {
- newnum = "0" + newnum;
- }
- }
- matches[2] = newnum;
-
- location.href = matches.slice(1).join("");
-
- return "DONE:";
- }
- return "ERROR:";
- }
-
- function allFrames(win) {
- var i, f, frames = [win];
- for (i = 0; i < win.frames.length; i++) {
- frames.push(win.frames[i].frameElement);
- }
- return frames;
- }
-
- /* the api */
- return {
- init: function init(mode, keepOpen, maxHints, hintKeys, followLast, hintNumSameLength) {
- var prop,
- /* holds the xpaths for the different modes */
- xpathmap = {
- otY: "//*[@href] | //*[@onclick or @tabindex or @class='lk' or @role='link' or @role='button'] | //input[not(@type='hidden' or @disabled or @readonly)] | //textarea[not(@disabled or @readonly)] | //button | //select",
- e: "//input[not(@type) or @type='text'] | //textarea",
- iI: "//img[@src]",
- OpPsTxy: "//*[@href] | //img[@src and not(ancestor::a)] | //iframe[@src]"
- },
- /* holds the actions to perform on hint fire */
- actionmap = {
- o: function(e) {open(e, false); return "DONE:";},
- t: function(e) {open(e, true); return "DONE:";},
- eiIOpPsTxy: function(e) {return "DATA:" + getSrc(e);},
- Y: function(e) {return "DATA:" + (e.textContent || "");}
- };
-
- config = {
- maxHints: maxHints,
- keepOpen: keepOpen,
- /* handle forms only useful when there are form fields in xpath */
- /* don't handle form for Y to allow to yank form filed content */
- /* instead of switching to input mode */
- handleForm: ("eot".indexOf(mode) >= 0),
- hintKeys: hintKeys,
- followLast: followLast,
- hintNumSameLength: hintNumSameLength,
- };
- for (prop in xpathmap) {
- if (prop.indexOf(mode) >= 0) {
- config["xpath"] = xpathmap[prop];
- break;
- }
- }
- for (prop in actionmap) {
- if (prop.indexOf(mode) >= 0) {
- config["action"] = actionmap[prop];
- break;
- }
- }
-
- create();
- return show(true);
- },
- filter: function filter(text) {
- /* remove previously set number filters to make the filter */
- /* easier to understand for the users */
- filterNum = 0;
- filterText = text || "";
- return show(true);
- },
- update: function update(n) {
- var pos,
- keys = config.hintKeys;
- /* delete last filter number digit */
- if (null === n && filterNum) {
- filterNum = Math.floor(filterNum / keys.length);
- return show(false);
- }
- if ((pos = keys.indexOf(n)) >= 0) {
- filterNum = filterNum * keys.length + pos;
- return show(true);
- }
- return "ERROR:";
- },
- clear: clear,
- fire: fire,
- focus: focus,
- /* not really hintings but uses similar logic */
- followLink: followLink,
- incrementUri: incrementUri,
- };
-})());
diff --git a/src/hints.js.h b/src/hints.js.h
new file mode 100644
index 0000000..102d9c6
--- /dev/null
+++ b/src/hints.js.h
@@ -0,0 +1 @@
+#define HINTS_JS "Object.freeze((function(){'use strict';var hints=[],docs=[],validHints=[],activeHint,filterText=\"\",filterNum=0,cId=\"_hintContainer\",lClass=\"_hintLabel\",hClass=\"_hintElem\",fClass=\"_hintFocus\",config;function Hint(){this.hide=function(){this.label.style.display=\"none\";this.e.classList.remove(fClass);this.e.classList.remove(hClass);};this.show=function(){this.label.style.display=\"\";this.e.classList.add(hClass);var text=[];if(this.e instanceof HTMLInputElement){var type=this.e.type;if(type===\"checkbox\"){text.push(this.e.checked?\"☑\":\"☐\");}else if(type===\"radio\"){text.push(this.e.checked?\"⊙\":\"○\");}}if(this.showText&&this.text){text.push(this.text.substr(0,20));}this.label.innerText=this.num+(text.length?\": \"+text.join(\" \"):\"\");};}function clear(){var i,j,doc,e;for(i=0;i<docs.length;i++){doc=docs[i];var res=xpath(doc.doc,\"//*[contains(@vimbhint,'hint')]\");for(j=0;j<res.snapshotLength;j++){e=res.snapshotItem(j);e.removeAttribute(\"vimbhint\");e.classList.remove(fClass);e.classList.remove(hClass);}doc.div.parentNode.removeChild(doc.div);}docs=[];hints=[];validHints=[];filterText=\"\";filterNum=0;}function create(){var count=0;function helper(win,offsets){if(typeof win.document==\"undefined\"){return;}offsets=offsets||{left:0,right:0,top:0,bottom:0};offsets.right=win.innerWidth-offsets.right;offsets.bottom=win.innerHeight-offsets.bottom;function isVisible(e){if(typeof e==\"undefined\"){return false;}var rect=e.getBoundingClientRect();if(!rect||rect.top>offsets.bottom||rect.bottom<offsets.top||rect.left>offsets.right||rect.right<offsets.left){return false;}if((!rect.width||!rect.height)&&(e.textContent||!e.name)){var arr=Array.prototype.slice.call(e.childNodes);var check=function(e){return e instanceof Element&&e.style.float!=\"none\"&&isVisible(e);};if(!arr.some(check)){return false;}}var s=win.getComputedStyle(e,null);return s.display!==\"none\"&&s.visibility==\"visible\";}var doc=win.document,res=xpath(doc,config.xpath),labelTmpl=doc.createElement(\"span\"),e,i;labelTmpl.className=lClass;labelTmpl.setAttribute(\"vimbhint\",\"label\");var containerOffsets=getOffsets(doc),offsetX=containerOffsets[0],offsetY=containerOffsets[1],fragment=doc.createDocumentFragment(),rect,label,text,showText,start=hints.length;for(i=0;i<res.snapshotLength;i++){e=res.snapshotItem(i);if(!isVisible(e)){continue;}count++;rect=e.getBoundingClientRect();label=labelTmpl.cloneNode(false);label.setAttribute(\"style\",[\"display:none;\",\"left:\",Math.max((rect.left+offsetX),offsetX),\"px;\",\"top:\",Math.max((rect.top+offsetY),offsetY),\"px;\"].join(\"\"));text=\"\";showText=false;if(e instanceof HTMLImageElement){text=e.title||e.alt;showText=true;}else if(e.firstElementChild instanceof HTMLImageElement&&/^\\s*$/.test(e.textContent)){text=e.firstElementChild.title||e.firstElementChild.alt;showText=true;}else if(e instanceof HTMLInputElement){var type=e.type;if(type===\"image\"){text=e.alt||\"\";}else if(e.value&&type!==\"password\"){text=e.value;showText=(type===\"radio\"||type===\"checkbox\");}}else if(e instanceof HTMLSelectElement){if(e.selectedIndex>=0){text=e.item(e.selectedIndex).text;}}else{text=e.textContent;}fragment.appendChild(label);e.setAttribute(\"vimbhint\",\"hint\");hints.push({e:e,label:label,text:text,showText:showText,__proto__:new Hint});if(count>=config.maxHints){break;}}var hDiv=doc.createElement(\"div\");hDiv.id=cId;hDiv.setAttribute(\"vimbhint\",\"container\");hDiv.appendChild(fragment);if(doc.body){doc.body.appendChild(hDiv);}createStyle(doc);docs.push({doc:doc,start:start,end:hints.length-1,div:hDiv});for(i=0;i<win.frames.length;i++){var rect,f=win.frames[i],e=f.frameElement;if(isVisible(e)){rect=e.getBoundingClientRect();helper(f,{left:Math.max(offsets.left-rect.left,0),right:Math.max(rect.right-offsets.right,0),top:Math.max(offsets.top-rect.top,0),bottom:Math.max(rect.bottom-offsets.bottom,0)});}}}helper(window);}function show(fireLast){var i,hint,newIdx,n=1,matcher=getMatcher(filterText),str=getHintString(filterNum);if(config.hintNumSameLength){var hintCount=0;for(i=0;i<hints.length;i++){if(matcher(hints[i].text)){hintCount++;}}var len=config.hintKeys.length;while(n *(len-1)<hintCount){n *=len;}}validHints=[];for(i=0;i<hints.length;i++){hint=hints[i];if(!matcher(hint.text)){hint.hide();}else{hint.num=getHintString(n++);if(!filterNum||0===hint.num.indexOf(str)){hint.show();validHints.push(hint);}else{hint.hide();}}}if(fireLast&&config.followLast&&validHints.length<=1){focusHint(0);return fire();}if(!activeHint||validHints.indexOf(activeHint)<0){return focusHint(0);}}function getMatcher(text){var tokens=text.toLowerCase().split(/\\s+/);return function(itemText){itemText=itemText.toLowerCase();return tokens.every(function(token){return 0<=itemText.indexOf(token);});};}function getHintString(n){var res=[],len=config.hintKeys.length;do{res.push(config.hintKeys[n % len]);n=Math.floor(n / len);}while(n>0);return res.reverse().join(\"\");}function getOffsets(doc){var body=doc.body||doc.documentElement,style=body.style,rect;if(style&&/^(absolute|fixed|relative)$/.test(style.position)){rect=body.getClientRects()[0];return [-rect.left,-rect.top];}return [doc.defaultView.scrollX,doc.defaultView.scrollY];}function createStyle(doc){if(doc.hasStyle){return;}var e=doc.createElement(\"style\");e.innerHTML=\"" HINT_CSS "\";doc.head.appendChild(e);doc.hasStyle=true;}function focus(back){var idx=validHints.indexOf(activeHint);if(idx<0){idx=0;}if(back){if(--idx<0){idx=validHints.length-1;}}else{if(++idx>=validHints.length){idx=0;}}return focusHint(idx);}function fire(){if(!activeHint){return\"ERROR:\";}var e=activeHint.e,res;if(config.handleForm){res=handleForm(e);}if(config.keepOpen){filterNum=0;show(false);}else{clear();}return res||config.action(e);}function handleForm(e){var tag=e.nodeName.toLowerCase(),type=e.type||\"\";if(tag===\"input\"||tag===\"textarea\"||tag===\"select\"){if(type===\"radio\"||type===\"checkbox\"){e.focus();click(e);return\"DONE:\";}if(type===\"submit\"||type===\"reset\"||type===\"button\"||type===\"image\"){click(e);return\"DONE:\";}e.focus();return\"INSERT:\";}if(tag===\"iframe\"||tag===\"frame\"){e.focus();return\"DONE:\";}}function open(e,newWin){var oldTarget=e.target;if(newWin){e.target=\"_blank\";}else if(e.target===\"_blank\"){e.removeAttribute(\"target\");}click(e,newWin);e.target=oldTarget;}function focusHint(newIdx){if(activeHint){activeHint.e.classList.remove(fClass);activeHint.label.classList.remove(fClass);mouseEvent(activeHint.e,\"mouseout\");}if((activeHint=validHints[newIdx])){activeHint.e.classList.add(fClass);activeHint.label.classList.add(fClass);mouseEvent(activeHint.e,\"mouseover\");return\"OVER:\"+getSrc(activeHint.e);;}}function click(e,ctrl){mouseEvent(e,\"mouseover\",ctrl);mouseEvent(e,\"mousedown\",ctrl);mouseEvent(e,\"mouseup\",ctrl);mouseEvent(e,\"click\",ctrl);}function mouseEvent(e,name,ctrl){var evObj=e.ownerDocument.createEvent(\"MouseEvents\");evObj.initMouseEvent(name,true,true,e.ownerDocument.defaultView,0,0,0,0,0,(typeof ctrl!=\"undefined\")?ctrl:false,false,false,false,0,null);e.dispatchEvent(evObj);}function getSrc(e){return e.href||e.src||\"\";}function xpath(doc,expr){return doc.evaluate(expr,doc,function(p){return\"http://www.w3.org/1999/xhtml\";},XPathResult.ORDERED_NODE_SNAPSHOT_TYPE,null);}function followLink(rel,patterns,count){function followFrame(frame){var i,p,reg,res=[],doc=frame.document,elems=[],all=doc.getElementsByTagName(\"a\");for(i=all.length-1;i>=0;i--){var s=doc.defaultView.getComputedStyle(all[i],null);if(s.display!==\"none\"&&s.visibility===\"visible\"){if(all[i].rel.toLowerCase()===rel){res.push(all[i]);}else{elems.push(all[i]);}}}for(p=0;p<patterns.length;p++){reg=patterns[p];for(i=elems.length-1;i>=0;i--){if(elems[i].innerText.match(reg)){res.push(elems[i]);}}}return res;}var i,j,elems,frames=allFrames(window);for(i=0;i<frames.length;i++){elems=followFrame(frames[i]);for(j=0;j<elems.length;j++){if(--count==0){open(elems[j],false);return\"DONE:\";}}}return\"ERROR:\";}function incrementUri(count){var oldnum,newnum,matches=location.href.match(/(.*?)(\\d+)(\\D*)$/);if(matches){oldnum=matches[2];newnum=String(Math.max(parseInt(oldnum)+count,0));if(/^0/.test(oldnum)){while(newnum.length<oldnum.length){newnum=\"0\"+newnum;}}matches[2]=newnum;location.href=matches.slice(1).join(\"\");return\"DONE:\";}return\"ERROR:\";}function allFrames(win){var i,f,frames=[win];for(i=0;i<win.frames.length;i++){frames.push(win.frames[i].frameElement);}return frames;}return{init:function init(mode,keepOpen,maxHints,hintKeys,followLast,hintNumSameLength){var prop,xpathmap={otY:\"//*[@href]|//*[@onclick or @tabindex or @class='lk'or @role='link'or @role='button']|//input[not(@type='hidden'or @disabled or @readonly)]|//textarea[not(@disabled or @readonly)]|//button|//select\",e:\"//input[not(@type)or @type='text']|//textarea\",iI:\"//img[@src]\",OpPsTxy:\"//*[@href]|//img[@src and not(ancestor::a)]|//iframe[@src]\"},actionmap={o:function(e){open(e,false);return\"DONE:\";},t:function(e){open(e,true);return\"DONE:\";},eiIOpPsTxy:function(e){return\"DATA:\"+getSrc(e);},Y:function(e){return\"DATA:\"+(e.textContent||\"\");}};config={maxHints:maxHints,keepOpen:keepOpen,handleForm:(\"eot\".indexOf(mode)>=0),hintKeys:hintKeys,followLast:followLast,hintNumSameLength:hintNumSameLength,};for(prop in xpathmap){if(prop.indexOf(mode)>=0){config[\"xpath\"]=xpathmap[prop];break;}}for(prop in actionmap){if(prop.indexOf(mode)>=0){config[\"action\"]=actionmap[prop];break;}}create();return show(true);},filter:function filter(text){filterNum=0;filterText=text||\"\";return show(true);},update:function update(n){var pos,keys=config.hintKeys;if(null===n&&filterNum){filterNum=Math.floor(filterNum / keys.length);return show(false);}if((pos=keys.indexOf(n))>=0){filterNum=filterNum * keys.length+pos;return show(true);}return\"ERROR:\";},clear:clear,fire:fire,focus:focus,followLink:followLink,incrementUri:incrementUri,};})());"
diff --git a/src/history.c b/src/history.c
index ceeb5e0..fcd89fc 100644
--- a/src/history.c
+++ b/src/history.c
@@ -17,78 +17,79 @@
* along with this program. If not, see http://www.gnu.org/licenses/.
*/
-#include "config.h"
#include <fcntl.h>
+#include <glib.h>
#include <sys/file.h>
-#include "main.h"
+
+#include "ascii.h"
+#include "completion.h"
+#include "config.h"
#include "history.h"
+#include "main.h"
#include "util.h"
-#include "completion.h"
-#include "ascii.h"
-
-extern VbCore vb;
#define HIST_FILE(t) (vb.files[file_map[t]])
-/* map history types to files */
-static const VbFile file_map[HISTORY_LAST] = {
- FILES_COMMAND,
- FILES_SEARCH,
- FILES_HISTORY
-};
-
typedef struct {
char *first;
char *second;
} History;
+static gboolean history_item_contains_all_tags(History *item, char **query, guint qlen);
+static void free_history(History *item);
+static History *line_to_history(const char *uri, const char *title);
static GList *load(const char *file);
static void write_to_file(GList *list, const char *file);
-static gboolean history_item_contains_all_tags(History *item, char **query,
- unsigned int qlen);
-static History *line_to_history(const char *uri, const char *title);
-static void free_history(History *item);
+/* map history types to files */
+static const int file_map[HISTORY_LAST] = {
+ FILES_COMMAND,
+ FILES_SEARCH,
+ FILES_HISTORY
+};
+extern struct Vimb vb;
/**
- * Makes all history items unique and force them to fit the maximum history
- * size and writes all entries of the different history types to file.
+ * Write a new history entry to the end of history file.
*/
-void history_cleanup(void)
+void history_add(Client *c, HistoryType type, const char *value, const char *additional)
{
const char *file;
- GList *list;
- /* don't cleanup the history file if history max size is 0 */
- if (!vb.config.history_max) {
+#if 0
+ /* Don't write a history entry if the history max size is set to 0. Else
+ * skip command history in case the command was not typed by the user. */
+ if (!vb.config.history_max || (!vb.state.typed && type == HISTORY_COMMAND)) {
return;
}
+#endif
- for (HistoryType i = HISTORY_FIRST; i < HISTORY_LAST; i++) {
- file = HIST_FILE(i);
- list = load(file);
- write_to_file(list, file);
- g_list_free_full(list, (GDestroyNotify)free_history);
+ file = HIST_FILE(type);
+ if (additional) {
+ util_file_append(file, "%s\t%s\n", value, additional);
+ } else {
+ util_file_append(file, "%s\n", value);
}
}
/**
- * Write a new history entry to the end of history file.
+ * Makes all history items unique and force them to fit the maximum history
+ * size and writes all entries of the different history types to file.
*/
-void history_add(HistoryType type, const char *value, const char *additional)
+void history_cleanup(void)
{
const char *file;
+ GList *list;
- /* Don't write a history entry if the history max size is set to 0. Else
- * skip command history in case the command was not typed by the user. */
- if (!vb.config.history_max || (!vb.state.typed && type == HISTORY_COMMAND)) {
+ /* don't cleanup the history file if history max size is 0 */
+ if (!vb.config.history_max) {
return;
}
- file = HIST_FILE(type);
- if (additional) {
- util_file_append(file, "%s\t%s\n", value, additional);
- } else {
- util_file_append(file, "%s\n", value);
+ for (HistoryType i = HISTORY_FIRST; i < HISTORY_LAST; i++) {
+ file = HIST_FILE(i);
+ list = load(file);
+ write_to_file(list, file);
+ g_list_free_full(list, (GDestroyNotify)free_history);
}
}
@@ -96,7 +97,7 @@ gboolean history_fill_completion(GtkListStore *store, HistoryType type, const ch
{
char **parts;
unsigned int len;
- gboolean found = false;
+ gboolean found = FALSE;
GList *src = NULL;
GtkTreeIter iter;
History *item;
@@ -116,7 +117,7 @@ gboolean history_fill_completion(GtkListStore *store, HistoryType type, const ch
#endif
-1
);
- found = true;
+ found = TRUE;
}
} else if (HISTORY_URL == type) {
parts = g_strsplit(input, " ", 0);
@@ -134,7 +135,7 @@ gboolean history_fill_completion(GtkListStore *store, HistoryType type, const ch
#endif
-1
);
- found = true;
+ found = TRUE;
}
}
g_strfreev(parts);
@@ -151,7 +152,7 @@ gboolean history_fill_completion(GtkListStore *store, HistoryType type, const ch
#endif
-1
);
- found = true;
+ found = TRUE;
}
}
}
@@ -169,12 +170,12 @@ GList *history_get_list(VbInputType type, const char *query)
GList *result = NULL, *src = NULL;
switch (type) {
- case VB_INPUT_COMMAND:
+ case INPUT_COMMAND:
src = load(HIST_FILE(HISTORY_COMMAND));
break;
- case VB_INPUT_SEARCH_FORWARD:
- case VB_INPUT_SEARCH_BACKWARD:
+ case INPUT_SEARCH_FORWARD:
+ case INPUT_SEARCH_BACKWARD:
src = load(HIST_FILE(HISTORY_SEARCH));
break;
@@ -200,7 +201,46 @@ GList *history_get_list(VbInputType type, const char *query)
}
/**
- * Loads history items form file but eleminate duplicates in FIFO order.
+ * Checks if the given array of tags are all found in history item.
+ */
+static gboolean history_item_contains_all_tags(History *item, char **query, guint qlen)
+{
+ unsigned int i;
+ if (!qlen) {
+ return TRUE;
+ }
+
+ /* iterate over all query parts */
+ for (i = 0; i < qlen; i++) {
+ if (!(util_strcasestr(item->first, query[i])
+ || (item->second && util_strcasestr(item->second, query[i])))
+ ) {
+ return FALSE;
+ }
+ }
+
+ return TRUE;
+}
+
+static void free_history(History *item)
+{
+ g_free(item->first);
+ g_free(item->second);
+ g_slice_free(History, item);
+}
+
+static History *line_to_history(const char *uri, const char *title)
+{
+ History *item = g_slice_new0(History);
+
+ item->first = g_strdup(uri);
+ item->second = g_strdup(title);
+
+ return item;
+}
+
+/**
+ * Loads history items form file but eliminate duplicates in FIFO order.
*
* Returned list must be freed with (GDestroyNotify)free_history.
*/
@@ -234,43 +274,3 @@ static void write_to_file(GList *list, const char *file)
fclose(f);
}
}
-
-/**
- * Checks if the given array of tags are all found in history item.
- */
-static gboolean history_item_contains_all_tags(History *item, char **query,
- unsigned int qlen)
-{
- unsigned int i;
- if (!qlen) {
- return true;
- }
-
- /* iterate over all query parts */
- for (i = 0; i < qlen; i++) {
- if (!(util_strcasestr(item->first, query[i])
- || (item->second && util_strcasestr(item->second, query[i])))
- ) {
- return false;
- }
- }
-
- return true;
-}
-
-static History *line_to_history(const char *uri, const char *title)
-{
- History *item = g_slice_new0(History);
-
- item->first = g_strdup(uri);
- item->second = g_strdup(title);
-
- return item;
-}
-
-static void free_history(History *item)
-{
- g_free(item->first);
- g_free(item->second);
- g_slice_free(History, item);
-}
diff --git a/src/history.h b/src/history.h
index a686285..8709f5d 100644
--- a/src/history.h
+++ b/src/history.h
@@ -20,6 +20,10 @@
#ifndef _HISTORY_H
#define _HISTORY_H
+#include <glib.h>
+
+#include "main.h"
+
typedef enum {
HISTORY_FIRST = 0,
HISTORY_COMMAND = 0,
@@ -28,8 +32,8 @@ typedef enum {
HISTORY_LAST
} HistoryType;
+void history_add(Client *c, HistoryType type, const char *value, const char *additional);
void history_cleanup(void);
-void history_add(HistoryType type, const char *value, const char *additional);
gboolean history_fill_completion(GtkListStore *store, HistoryType type, const char *input);
GList *history_get_list(VbInputType type, const char *query);
diff --git a/src/hsts.c b/src/hsts.c
deleted file mode 100644
index 00b25a1..0000000
--- a/src/hsts.c
+++ /dev/null
@@ -1,458 +0,0 @@
-/**
- * vimb - a webkit based vim like browser.
- *
- * Copyright (C) 2012-2015 Daniel Carl
- *
- * 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, see http://www.gnu.org/licenses/.
- */
-
-#include "config.h"
-#ifdef FEATURE_HSTS
-#include "hsts.h"
-#include "util.h"
-#include "main.h"
-#include <fcntl.h>
-#include <sys/file.h>
-#include <string.h>
-#include <glib-object.h>
-#include <libsoup/soup.h>
-
-#define HSTS_HEADER_NAME "Strict-Transport-Security"
-#define HSTS_FILE_FORMAT "%s\t%s\t%c\n"
-#define HSTS_PROVIDER_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE((o), HSTS_TYPE_PROVIDER, HSTSProviderPrivate))
-
-extern VbCore vb;
-
-/* private interface of the provider */
-typedef struct _HSTSProviderPrivate {
- GHashTable* whitelist;
-} HSTSProviderPrivate;
-
-typedef struct {
- SoupDate *expires_at;
- gboolean include_sub_domains;
-} HSTSEntry;
-
-static void hsts_provider_class_init(HSTSProviderClass *klass);
-static void hsts_provider_init(HSTSProvider *self);
-static void hsts_provider_finalize(GObject* obj);
-static inline gboolean should_secure_host(HSTSProvider *provider,
- const char *host);
-static void process_hsts_header(SoupMessage *msg, gpointer data);
-static void parse_hsts_header(HSTSProvider *provider,
- const char *host, const char *header);
-static void free_entry(HSTSEntry *entry);
-static void add_host_entry(HSTSProvider *provider, const char *host,
- HSTSEntry *entry);
-static void add_host_entry_to_file(HSTSProvider *provider, const char *host,
- HSTSEntry *entry);
-static void remove_host_entry(HSTSProvider *provider, const char *host);
-/* session feature related functions */
-static void session_feature_init(
- SoupSessionFeatureInterface *inteface, gpointer data);
-static void request_queued(SoupSessionFeature *feature,
- SoupSession *session, SoupMessage *msg);
-static void request_started(SoupSessionFeature *feature,
- SoupSession *session, SoupMessage *msg, SoupSocket *socket);
-static void request_unqueued(SoupSessionFeature *feature,
- SoupSession *session, SoupMessage *msg);
-/* caching related functions */
-static void load_entries(HSTSProvider *provider, const char *file);
-static void save_entries(HSTSProvider *provider, const char *file);
-
-/**
- * Change scheme and port of soup messages uri if the host is a known and
- * valid hsts host.
- *
- * This logic should be implemented in request_queued function but the changes
- * that are done there to the uri do not appear in webkit_web_view_get_uri().
- * If a valid hsts host is requested via http and the url is changed to https
- * vimb would still show the http uri in url bar. This seems to be a
- * missbehaviour in webkit, but for now we provide this function to put in the
- * logic in the scope of the navigation-policy-decision-requested event of the
- * webview.
- *
- * Returns newly allocated string with new URI if the URI was change to
- * fullfill HSTS, else NULL.
- */
-char *hsts_get_changed_uri(SoupSession* session, SoupMessage *msg)
-{
- SoupSessionFeature *feature;
- HSTSProvider *provider;
- SoupURI *uri;
-
- if (!msg) {
- return NULL;
- }
-
- feature = soup_session_get_feature_for_message(session, HSTS_TYPE_PROVIDER, msg);
- uri = soup_message_get_uri(msg);
- if (!feature || !uri) {
- return NULL;
- }
-
- provider = HSTS_PROVIDER(feature);
- /* if URI uses still https we don't nee to rewrite it */
- if (uri->scheme != SOUP_URI_SCHEME_HTTPS
- && should_secure_host(provider, uri->host)
- ) {
- /* the ports is set by soup uri if scheme is changed */
- soup_uri_set_scheme(uri, SOUP_URI_SCHEME_HTTPS);
- return soup_uri_to_string(uri, false);
- }
- return NULL;
-}
-
-/**
- * Generates a new hsts provider instance.
- * Unref the instance with g_object_unref if no more used.
- */
-HSTSProvider *hsts_provider_new(void)
-{
- return g_object_new(HSTS_TYPE_PROVIDER, NULL);
-}
-
-G_DEFINE_TYPE_WITH_CODE(
- HSTSProvider, hsts_provider, G_TYPE_OBJECT,
- G_IMPLEMENT_INTERFACE(SOUP_TYPE_SESSION_FEATURE, session_feature_init)
-)
-
-static void hsts_provider_class_init(HSTSProviderClass *klass)
-{
- GObjectClass *object_class = G_OBJECT_CLASS(klass);
- hsts_provider_parent_class = g_type_class_peek_parent(klass);
- g_type_class_add_private(klass, sizeof(HSTSProviderPrivate));
- object_class->finalize = hsts_provider_finalize;
-}
-
-static void hsts_provider_init(HSTSProvider *self)
-{
- /* initialize private fields */
- HSTSProviderPrivate *priv = HSTS_PROVIDER_GET_PRIVATE(self);
- priv->whitelist = g_hash_table_new_full(g_str_hash, g_str_equal, g_free, (GDestroyNotify)free_entry);
-
- /* load entries from hsts file */
- load_entries(self, vb.files[FILES_HSTS]);
-}
-
-static void hsts_provider_finalize(GObject* obj)
-{
- HSTSProviderPrivate *priv = HSTS_PROVIDER_GET_PRIVATE (obj);
-
- /* save all the entries in hsts file */
- save_entries(HSTS_PROVIDER(obj), vb.files[FILES_HSTS]);
-
- g_hash_table_destroy(priv->whitelist);
- G_OBJECT_CLASS(hsts_provider_parent_class)->finalize(obj);
-}
-
-/**
- * Checks if given host is a known https host according to RFC 6797 8.2f
- */
-static inline gboolean should_secure_host(HSTSProvider *provider,
- const char *host)
-{
- HSTSProviderPrivate *priv = HSTS_PROVIDER_GET_PRIVATE(provider);
- HSTSEntry *entry;
- char *canonical, *p;
- gboolean result = false, is_subdomain = false;
-
- /* ip is not allowed for hsts */
- if (g_hostname_is_ip_address(host)) {
- return false;
- }
-
- canonical = g_hostname_to_ascii(host);
- /* don't match empty host */
- if (*canonical) {
- p = canonical;
- /* Try to find the whole congruent matching host in hash table - if
- * not found strip of the first label and try to find a superdomain
- * match. Specified is a from right to left comparison 8.3, but in the
- * end this should be lead to the same result. */
- while (p != NULL) {
- entry = g_hash_table_lookup(priv->whitelist, p);
- if (entry != NULL) {
- /* remove expired entries RFC 6797 8.1.1 */
- if (soup_date_is_past(entry->expires_at)) {
- remove_host_entry(provider, p);
- } else if(!is_subdomain || entry->include_sub_domains) {
- result = true;
- break;
- }
- }
-
- is_subdomain = true;
- /* test without the first domain part */
- if ((p = strchr(p, '.'))) {
- p++;
- }
- }
- }
- g_free(canonical);
-
- return result;
-}
-
-static void process_hsts_header(SoupMessage *msg, gpointer data)
-{
- HSTSProvider *provider = (HSTSProvider*)data;
- SoupURI *uri = soup_message_get_uri(msg);
- SoupMessageHeaders *hdrs;
- const char *header;
-
- if (!g_hostname_is_ip_address(uri->host)
- && (soup_message_get_flags(msg) & SOUP_MESSAGE_CERTIFICATE_TRUSTED)
- ){
- g_object_get(G_OBJECT(msg), SOUP_MESSAGE_RESPONSE_HEADERS, &hdrs, NULL);
-
- /* TODO according to RFC 6797 8.1 we must only use the first header */
- header = soup_message_headers_get_one(hdrs, HSTS_HEADER_NAME);
- if (header) {
- parse_hsts_header(provider, uri->host, header);
- }
- }
-}
-
-/**
- * Parses the hsts directives from given header like specified in RFC 6797 6.1
- */
-static void parse_hsts_header(HSTSProvider *provider,
- const char *host, const char *header)
-{
- GHashTable *directives = soup_header_parse_semi_param_list(header);
- HSTSEntry *entry;
- int max_age = G_MAXINT;
- gboolean include_sub_domains = false;
- GHashTableIter iter;
- gpointer key, value;
- gboolean success = true;
-
- HSTSProviderClass *klass = g_type_class_ref(HSTS_TYPE_PROVIDER);
-
- g_hash_table_iter_init(&iter, directives);
- while (g_hash_table_iter_next(&iter, &key, &value)) {
- /* parse the max-age directive */
- if (!g_ascii_strncasecmp(key, "max-age", 7)) {
- /* max age needs a value */
- if (value) {
- max_age = g_ascii_strtoll(value, NULL, 10);
- if (max_age < 0) {
- success = false;
- break;
- }
- } else {
- success = false;
- break;
- }
- } else if (g_ascii_strncasecmp(key, "includeSubDomains", 17)) {
- /* includeSubDomains must not have a value */
- if (!value) {
- include_sub_domains = true;
- } else {
- success = false;
- break;
- }
- }
- }
- soup_header_free_param_list(directives);
- g_type_class_unref(klass);
-
- if (success) {
- /* remove host if max-age = 0 RFC 6797 6.1.1 */
- if (max_age == 0) {
- remove_host_entry(provider, host);
- } else {
- entry = g_slice_new(HSTSEntry);
- entry->expires_at = soup_date_new_from_now(max_age);
- entry->include_sub_domains = include_sub_domains;
-
- add_host_entry(provider, host, entry);
- add_host_entry_to_file(provider, host, entry);
- }
- }
-}
-
-static void free_entry(HSTSEntry *entry)
-{
- soup_date_free(entry->expires_at);
- g_slice_free(HSTSEntry, entry);
-}
-
-/**
- * Adds the host to the known host, if it already exists it replaces it with
- * the information contained in entry according to RFC 6797 8.1.
- */
-static void add_host_entry(HSTSProvider *provider, const char *host,
- HSTSEntry *entry)
-{
- HSTSProviderPrivate *priv = HSTS_PROVIDER_GET_PRIVATE(provider);
- g_hash_table_replace(priv->whitelist, g_hostname_to_unicode(host), entry);
-}
-
-static void add_host_entry_to_file(HSTSProvider *provider, const char *host,
- HSTSEntry *entry)
-{
- char *date = soup_date_to_string(entry->expires_at, SOUP_DATE_ISO8601_FULL);
-
- util_file_append(
- vb.files[FILES_HSTS], HSTS_FILE_FORMAT, host, date, entry->include_sub_domains ? 'y' : 'n'
- );
- g_free(date);
-}
-
-/**
- * Removes stored entry for given host.
- */
-static void remove_host_entry(HSTSProvider *provider, const char *host)
-{
- HSTSProviderPrivate *priv = HSTS_PROVIDER_GET_PRIVATE(provider);
- char *canonical = g_hostname_to_unicode(host);
-
- g_hash_table_remove(priv->whitelist, canonical);
- g_free(canonical);
-}
-
-/**
- * Initialise the SoupSessionFeature interface.
- */
-static void session_feature_init(
- SoupSessionFeatureInterface *inteface, gpointer data)
-{
- inteface->request_queued = request_queued;
- inteface->request_started = request_started;
- inteface->request_unqueued = request_unqueued;
-}
-
-/**
- * Check if the host is known and switch the URI scheme to https.
- */
-static void request_queued(SoupSessionFeature *feature,
- SoupSession *session, SoupMessage *msg)
-{
- SoupURI *uri = soup_message_get_uri(msg);
- HSTSProvider *provider = HSTS_PROVIDER(feature);
-
- /* only look for HSTS headers sent over https RFC 6797 7.2*/
- if (uri->scheme == SOUP_URI_SCHEME_HTTPS) {
- soup_message_add_header_handler(
- msg, "got-headers", HSTS_HEADER_NAME, G_CALLBACK(process_hsts_header), feature
- );
- } else if (should_secure_host(provider, uri->host)) {
- /* the ports is set by soup uri if scheme is changed */
- soup_uri_set_scheme(uri, SOUP_URI_SCHEME_HTTPS);
- soup_session_requeue_message(session, msg);
- }
-}
-
-static void request_started(SoupSessionFeature *feature,
- SoupSession *session, SoupMessage *msg, SoupSocket *socket)
-{
- HSTSProvider *provider = HSTS_PROVIDER(feature);
- SoupURI *uri = soup_message_get_uri(msg);
- GTlsCertificate *certificate;
- GTlsCertificateFlags errors;
-
- if (should_secure_host(provider, uri->host)) {
- if (uri->scheme != SOUP_URI_SCHEME_HTTPS
- || (soup_message_get_https_status(msg, &certificate, &errors) && errors)
- ) {
- soup_session_cancel_message(session, msg, SOUP_STATUS_SSL_FAILED);
- g_warning("cancel invalid hsts request to %s://%s", uri->scheme, uri->host);
- }
- }
-}
-
-static void request_unqueued(SoupSessionFeature *feature,
- SoupSession *session, SoupMessage *msg)
-{
- g_signal_handlers_disconnect_by_func(msg, process_hsts_header, feature);
-}
-
-/**
- * Reads the entries save in given file and store them in the whitelist.
- */
-static void load_entries(HSTSProvider *provider, const char *file)
-{
- char **lines, **parts, *host, *line;
- int i, len, partlen;
- gboolean include_sub_domains;
- SoupDate *date;
- HSTSEntry *entry;
-
- lines = util_get_lines(file);
- if (!(len = g_strv_length(lines))) {
- return;
- }
-
- for (i = len - 1; i >= 0; i--) {
- line = lines[i];
- /* skip empty or commented lines */
- if (!*line || *line == '#') {
- continue;
- }
-
- parts = g_strsplit(line, "\t", 3);
- partlen = g_strv_length(parts);
- if (partlen == 3) {
- host = parts[0];
- if (g_hostname_is_ip_address(host)) {
- continue;
- }
- date = soup_date_new_from_string(parts[1]);
- if (!date) {
- continue;
- }
- include_sub_domains = (*parts[2] == 'y') ? true : false;
-
- /* built the new entry to add */
- entry = g_slice_new(HSTSEntry);
- entry->expires_at = soup_date_new_from_string(parts[1]);
- entry->include_sub_domains = include_sub_domains;
-
- add_host_entry(provider, host, entry);
- } else {
- g_warning("could not parse hsts line '%s'", line);
- }
- g_strfreev(parts);
- }
- g_strfreev(lines);
-}
-
-/**
- * Saves all entries of given provider in given file.
- */
-static void save_entries(HSTSProvider *provider, const char *file)
-{
- GHashTableIter iter;
- char *host, *date;
- HSTSEntry *entry;
- FILE *f;
- HSTSProviderPrivate *priv = HSTS_PROVIDER_GET_PRIVATE(provider);
-
- if ((f = fopen(file, "w"))) {
- flock(fileno(f), LOCK_EX);
-
- g_hash_table_iter_init(&iter, priv->whitelist);
- while (g_hash_table_iter_next (&iter, (gpointer)&host, (gpointer)&entry)) {
- date = soup_date_to_string(entry->expires_at, SOUP_DATE_ISO8601_FULL);
- fprintf(f, HSTS_FILE_FORMAT, host, date, entry->include_sub_domains ? 'y' : 'n');
- g_free(date);
- }
-
- flock(fileno(f), LOCK_UN);
- fclose(f);
- }
-}
-#endif
diff --git a/src/hsts.h b/src/hsts.h
deleted file mode 100644
index c56b2c7..0000000
--- a/src/hsts.h
+++ /dev/null
@@ -1,52 +0,0 @@
-/**
- * vimb - a webkit based vim like browser.
- *
- * Copyright (C) 2012-2015 Daniel Carl
- *
- * 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, see http://www.gnu.org/licenses/.
- */
-
-#include "config.h"
-#ifdef FEATURE_HSTS
-
-#ifndef _HSTS_H
-#define _HSTS_H
-
-#include <glib-object.h>
-#include <libsoup/soup.h>
-
-#define HSTS_TYPE_PROVIDER (hsts_provider_get_type())
-#define HSTS_PROVIDER(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), HSTS_TYPE_PROVIDER, HSTSProvider))
-#define HSTS_PROVIDER_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass), HSTS_TYPE_PROVIDER, HSTSProviderClass))
-#define HSTS_IS_PROVIDER(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), HSTS_TYPE_PROVIDER))
-#define HSTS_IS_PROVIDER_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass), HSTS_TYPE_PROVIDER))
-#define HSTS_PROVIDER_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS((obj), HSTS_TYPE_PROVIDER, HSTSProviderClass))
-
-/* public interface of the provider */
-typedef struct {
- GObject parent_instance;
-} HSTSProvider;
-
-/* class members of the provider */
-typedef struct {
- GObjectClass parent_class;
-} HSTSProviderClass;
-
-
-char *hsts_get_changed_uri(SoupSession* session, SoupMessage *msg);
-GType hsts_provider_get_type(void);
-HSTSProvider *hsts_provider_new(void);
-
-#endif /* end of include guard: _HSTS_H */
-#endif
diff --git a/src/input.c b/src/input.c
index 5292b4e..b5381ff 100644
--- a/src/input.c
+++ b/src/input.c
@@ -17,62 +17,57 @@
* along with this program. If not, see http://www.gnu.org/licenses/.
*/
-#include "config.h"
+#include <glib.h>
#include <glib/gstdio.h>
-#include "main.h"
-#include "input.h"
-#include "dom.h"
-#include "util.h"
+
#include "ascii.h"
+#include "config.h"
+#include "input.h"
+#include "main.h"
#include "normal.h"
+#include "util.h"
+#include "ext-proxy.h"
-typedef struct {
- char *file;
- Element *element;
-} EditorData;
-
-static void resume_editor(GPid pid, int status, EditorData *data);
-
-extern VbCore vb;
/**
* Function called when vimb enters the input mode.
*/
-void input_enter(void)
+void input_enter(Client *c)
{
/* switch focus first to make sure we can write to the inputbox without
* disturbing the user */
- gtk_widget_grab_focus(GTK_WIDGET(vb.gui.webview));
- vb_update_mode_label("-- INPUT --");
+ gtk_widget_grab_focus(GTK_WIDGET(c->webview));
+ vb_modelabel_update(c, "-- INPUT --");
}
/**
* Called when the input mode is left.
*/
-void input_leave(void)
+void input_leave(Client *c)
{
- vb_update_mode_label("");
+ webkit_web_view_run_javascript(c->webview, "document.activeElement.blur();", NULL, NULL, NULL);
+ vb_modelabel_update(c, "");
}
/**
* Handles the keypress events from webview and inputbox.
*/
-VbResult input_keypress(int key)
+VbResult input_keypress(Client *c, int key)
{
- static gboolean ctrlo = false;
+ static gboolean ctrlo = FALSE;
if (ctrlo) {
/* if we are in ctrl-O mode perform the next keys as normal mode
* commands until the command is complete or error */
- VbResult res = normal_keypress(key);
+ VbResult res = normal_keypress(c, key);
if (res != RESULT_MORE) {
- ctrlo = false;
+ ctrlo = FALSE;
/* Don't overwrite the mode label in case we landed in another
* mode. This might occurre by CTRL-0 CTRL-Z or after running ex
* command, where we mainly end up in normal mode. */
- if (vb.mode->id == 'i') {
+ if (c->mode->id == 'i') {
/* reenter the input mode */
- input_enter();
+ input_enter(c);
}
}
return res;
@@ -80,106 +75,31 @@ VbResult input_keypress(int key)
switch (key) {
case CTRL('['): /* esc */
- vb_enter('n');
+ vb_enter(c, 'n');
return RESULT_COMPLETE;
case CTRL('O'):
/* enter CTRL-0 mode to execute next command in normal mode */
- ctrlo = true;
- vb.mode->flags |= FLAG_NOMAP;
- vb_update_mode_label("-- (input) --");
+ ctrlo = TRUE;
+ c->mode->flags |= FLAG_NOMAP;
+ vb_modelabel_update(c, "-- (input) --");
return RESULT_MORE;
case CTRL('T'):
- return input_open_editor();
+ return input_open_editor(c);
case CTRL('Z'):
- vb_enter('p');
+ vb_enter(c, 'p');
return RESULT_COMPLETE;
}
- vb.state.processed_key = false;
+ c->state.processed_key = FALSE;
return RESULT_ERROR;
}
-VbResult input_open_editor(void)
+VbResult input_open_editor(Client *c)
{
- char **argv, *file_path = NULL;
- const char *text, *editor_command;
- int argc;
- GPid pid;
- gboolean success;
-
- editor_command = GET_CHAR("editor-command");
- if (!editor_command || !*editor_command) {
- vb_echo(VB_MSG_ERROR, true, "No editor-command configured");
- return RESULT_ERROR;
- }
- Element* active = dom_get_active_element(vb.gui.webview);
-
- /* check if element is suitable for editing */
- if (!active || !dom_is_editable(active)) {
- return RESULT_ERROR;
- }
-
- text = dom_editable_element_get_value(active);
- if (!text) {
- return RESULT_ERROR;
- }
-
- if (!util_create_tmp_file(text, &file_path)) {
- return RESULT_ERROR;
- }
-
- /* spawn editor */
- char* command = g_strdup_printf(editor_command, file_path);
- if (!g_shell_parse_argv(command, &argc, &argv, NULL)) {
- g_critical("Could not parse editor-command '%s'", command);
- g_free(command);
- return RESULT_ERROR;
- }
- g_free(command);
-
- success = g_spawn_async(
- NULL, argv, NULL, G_SPAWN_SEARCH_PATH | G_SPAWN_DO_NOT_REAP_CHILD,
- NULL, NULL, &pid, NULL
- );
- g_strfreev(argv);
-
- if (!success) {
- unlink(file_path);
- g_free(file_path);
- g_warning("Could not spawn editor-command");
- return RESULT_ERROR;
- }
-
- /* disable the active element */
- dom_editable_element_set_disable(active, true);
-
- EditorData *data = g_slice_new0(EditorData);
- data->file = file_path;
- data->element = active;
-
- g_child_watch_add(pid, (GChildWatchFunc)resume_editor, data);
-
+ /* TODO should the editor be opened by the webextension or by the
+ * application? */
return RESULT_COMPLETE;
}
-
-static void resume_editor(GPid pid, int status, EditorData *data)
-{
- char *text;
- if (status == 0) {
- text = util_get_file_contents(data->file, NULL);
- if (text) {
- dom_editable_element_set_value(data->element, text);
- }
- g_free(text);
- }
- dom_editable_element_set_disable(data->element, false);
- dom_give_focus(data->element);
-
- g_unlink(data->file);
- g_free(data->file);
- g_slice_free(EditorData, data);
- g_spawn_close_pid(pid);
-}
diff --git a/src/input.h b/src/input.h
index 8887abc..64d1d5c 100644
--- a/src/input.h
+++ b/src/input.h
@@ -23,9 +23,9 @@
#include "config.h"
#include "main.h"
-void input_enter(void);
-void input_leave(void);
-VbResult input_keypress(int key);
-VbResult input_open_editor(void);
+void input_enter(Client *c);
+void input_leave(Client *c);
+VbResult input_keypress(Client *c, int key);
+VbResult input_open_editor(Client *c);
#endif /* end of include guard: _INPUT_H */
diff --git a/src/io.c b/src/io.c
deleted file mode 100644
index 0abac30..0000000
--- a/src/io.c
+++ /dev/null
@@ -1,170 +0,0 @@
-/**
- * vimb - a webkit based vim like browser.
- *
- * Copyright (C) 2012-2015 Daniel Carl
- *
- * 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, see http://www.gnu.org/licenses/.
- */
-
-#include "config.h"
-#ifdef FEATURE_SOCKET
-#include "io.h"
-#include "main.h"
-#include "map.h"
-#include "util.h"
-#include <unistd.h>
-#include <sys/types.h>
-#include <sys/stat.h>
-#include <sys/socket.h>
-#include <sys/un.h>
-#include <errno.h>
-
-extern VbCore vb;
-
-static gboolean socket_accept(GIOChannel *chan);
-static gboolean socket_watch(GIOChannel *chan);
-
-
-gboolean io_init_socket(const char *name)
-{
- char *dir, *path;
- int sock;
- struct sockaddr_un local;
-
- /* create socket in runtime directory */
- dir = g_build_filename(util_get_runtime_dir(vb.config.profile), PROJECT, "socket", NULL);
- util_create_dir_if_not_exists(dir);
- path = g_build_filename(dir, name, NULL);
- g_free(dir);
-
- /* if the file already exists - remove this first */
- if (g_file_test(path, G_FILE_TEST_IS_REGULAR)) {
- unlink(path);
- }
-
- sock = socket(AF_UNIX, SOCK_STREAM, 0);
- if (sock < 0) {
- g_warning("Can't create socket %s", path);
- }
-
- /* prepare socket address */
- local.sun_family = AF_UNIX;
- strcpy(local.sun_path, path);
-
- if (bind(sock, (struct sockaddr*)&local, sizeof(local)) != -1
- && listen(sock, 5) >= 0
- ) {
- GIOChannel *chan = g_io_channel_unix_new(sock);
- if (chan) {
- g_io_channel_set_encoding(chan, NULL, NULL);
- g_io_channel_set_buffered(chan, false);
- g_io_add_watch(chan, G_IO_IN|G_IO_HUP, (GIOFunc)socket_accept, chan);
- /* don't free path - because we want to keep the value in
- * vb.state.socket_path still accessible */
- vb.state.socket_path = path;
- g_setenv("VIMB_SOCKET", path, true);
-
- return true;
- }
- } else {
- g_warning("no bind");
- }
-
- g_warning("Could not listen on %s: %s", path, strerror(errno));
- g_free(path);
-
- return false;
-}
-
-void io_cleanup(void)
-{
- if (vb.state.socket_path) {
- if (unlink(vb.state.socket_path) == -1) {
- g_warning("Can't remove socket %s", vb.state.socket_path);
- }
- g_free(vb.state.socket_path);
- vb.state.socket_path = NULL;
- }
-}
-
-static gboolean socket_accept(GIOChannel *chan)
-{
- struct sockaddr_un remote;
- guint size = sizeof(remote);
- GIOChannel *iochan;
- int clientsock;
-
- clientsock = accept(g_io_channel_unix_get_fd(chan), (struct sockaddr *)&remote, &size);
-
- if ((iochan = g_io_channel_unix_new(clientsock))) {
- g_io_channel_set_encoding(iochan, NULL, NULL);
- g_io_add_watch(iochan, G_IO_IN|G_IO_HUP, (GIOFunc)socket_watch, iochan);
- }
- return true;
-}
-
-static gboolean socket_watch(GIOChannel *chan)
-{
- GIOStatus ret;
- GError *error = NULL;
- char *line, *inputtext;
- gsize len;
-
- ret = g_io_channel_read_line(chan, &line, &len, NULL, &error);
- if (ret == G_IO_STATUS_ERROR || ret == G_IO_STATUS_EOF) {
- if (ret == G_IO_STATUS_ERROR) {
- g_warning("Error reading: %s", error->message);
- g_error_free(error);
- }
-
- /* shutdown and remove the client channel */
- ret = g_io_channel_shutdown(chan, true, &error);
- g_io_channel_unref(chan);
-
- if (ret == G_IO_STATUS_ERROR) {
- g_warning("Error closing: %s", error->message);
- g_error_free(error);
- }
- return false;
- }
-
- /* simulate the typed flag to allow to record the commands in history */
- vb.state.typed = true;
-
- /* run the commands */
- map_handle_string(line, true);
- g_free(line);
-
- /* unset typed flag */
- vb.state.typed = false;
-
- /* We assume that the commands result is still available in the inputbox,
- * so the whole inputbox content is written to the socket. */
- inputtext = vb_get_input_text();
- ret = g_io_channel_write_chars(chan, inputtext, -1, &len, &error);
- if (ret == G_IO_STATUS_ERROR) {
- g_warning("Error writing: %s", error->message);
- g_error_free(error);
- }
- if (g_io_channel_flush(chan, &error) == G_IO_STATUS_ERROR) {
- g_warning("Error flushing: %s", error->message);
- g_error_free(error);
- }
-
- g_free(inputtext);
-
- return true;
-}
-
-#endif
diff --git a/src/js.c b/src/js.c
index fb40236..e6f467e 100644
--- a/src/js.c
+++ b/src/js.c
@@ -17,175 +17,36 @@
* along with this program. If not, see http://www.gnu.org/licenses/.
*/
-#include "config.h"
-#include "js.h"
-
-
-static gboolean evaluate_string(JSContextRef ctx, const char *script,
- const char *file, JSValueRef *result);
-
-/**
- * Run scripts out of given file in the given frame.
- */
-gboolean js_eval_file(JSContextRef ctx, const char *file)
-{
- char *js = NULL, *value = NULL;
-
- if (g_file_test(file, G_FILE_TEST_IS_REGULAR)
- && g_file_get_contents(file, &js, NULL, NULL)
- ) {
- gboolean success = js_eval(ctx, js, file, &value);
- if (!success) {
- g_warning("JavaScript error in %s: %s", file, value);
- }
- g_free(value);
- g_free(js);
-
- return success;
- }
-
- return false;
-}
-
-/**
- * Evaluates given string as script and return if this call succeed or not.
- * On success the given **value pointer is filled with the returned string,
- * else with the exception message. In both cases this must be freed by the
- * caller if no longer used.
- */
-gboolean js_eval(JSContextRef ctx, const char *script, const char *file,
- char **value)
-{
- gboolean success;
- JSValueRef result = NULL;
-
- success = evaluate_string(ctx, script, file, &result);
- *value = js_ref_to_string(ctx, result);
-
- return success;
-}
-
-/**
- * Creates a JavaScript object in context of given frame.
- */
-JSObjectRef js_create_object(JSContextRef ctx, const char *script)
-{
- JSValueRef result = NULL, exc = NULL;
- JSObjectRef object;
- if (!evaluate_string(ctx, script, NULL, &result)) {
- return NULL;
- }
-
- object = JSValueToObject(ctx, result, &exc);
- if (exc) {
- return NULL;
- }
- JSValueProtect(ctx, result);
-
- return object;
-}
-
-/**
- * Calls a function on object and returns the result as newly allocates
- * string.
- * Returned string must be freed after use.
- */
-char* js_object_call_function(JSContextRef ctx, JSObjectRef obj,
- const char *func, int count, JSValueRef params[])
-{
- JSValueRef js_ret, function;
- JSObjectRef function_object;
- JSStringRef js_func = NULL;
- char *value;
-
- g_return_val_if_fail(obj != NULL, NULL);
-
- js_func = JSStringCreateWithUTF8CString(func);
- if (!JSObjectHasProperty(ctx, obj, js_func)) {
- JSStringRelease(js_func);
-
- return NULL;
- }
-
- function = JSObjectGetProperty(ctx, obj, js_func, NULL);
- function_object = JSValueToObject(ctx, function, NULL);
- js_ret = JSObjectCallAsFunction(ctx, function_object, NULL, count, params, NULL);
- JSStringRelease(js_func);
-
- value = js_ref_to_string(ctx, js_ret);
+#include <JavaScriptCore/JavaScript.h>
+#include <glib.h>
+#include <webkit2/webkit2.h>
- return value;
-}
+#include "js.h"
+#include "config.h"
/**
- * Returns a new allocates string for given value reference.
+ * Returns a new allocates string for given value javascript result.
* String must be freed if not used anymore.
*/
-char* js_ref_to_string(JSContextRef ctx, JSValueRef ref)
+char *js_result_as_string(WebKitJavascriptResult *res)
{
- char *string;
- size_t len;
- JSStringRef str_ref;
-
- g_return_val_if_fail(ref != NULL, NULL);
+ JSGlobalContextRef cr;
+ JSStringRef jsstring;
+ JSValueRef jsvalue;
+ gsize max;
- str_ref = JSValueToStringCopy(ctx, ref, NULL);
- len = JSStringGetMaximumUTF8CStringSize(str_ref);
+ g_return_val_if_fail(res != NULL, NULL);
- string = g_new0(char, len);
- JSStringGetUTF8CString(str_ref, string, len);
- JSStringRelease(str_ref);
+ jsvalue = webkit_javascript_result_get_value(res);
+ cr = webkit_javascript_result_get_global_context(res);
+ jsstring = JSValueToStringCopy(cr, jsvalue, NULL);
+ max = JSStringGetMaximumUTF8CStringSize(jsstring);
+ if (max > 0) {
+ char *string = g_new(char, max);
+ JSStringGetUTF8CString(jsstring, string, max);
- return string;
-}
-
-/**
- * Retrieves a values reference for given string.
- */
-JSValueRef js_string_to_ref(JSContextRef ctx, const char *string)
-{
- JSStringRef js = JSStringCreateWithUTF8CString(string);
- JSValueRef ref = JSValueMakeString(ctx, js);
- JSStringRelease(js);
- return ref;
-}
-
-/**
- * Retrieves a values reference for given json or array string string.
- */
-JSValueRef js_object_to_ref(JSContextRef ctx, const char *json)
-{
- JSValueRef ref = NULL;
- if (evaluate_string(ctx, json, NULL, &ref)) {
- return ref;
+ return string;
}
- g_warning("Could not parse %s", json);
return NULL;
}
-/**
- * Runs a string as JavaScript and returns if the call succeed.
- * In case the call succeed, the given *result is filled with the result
- * value, else with the value reference of the exception.
- */
-static gboolean evaluate_string(JSContextRef ctx, const char *script,
- const char *file, JSValueRef *result)
-{
- JSStringRef js_str, js_file;
- JSValueRef exc = NULL, res = NULL;
-
- js_str = JSStringCreateWithUTF8CString(script);
- js_file = JSStringCreateWithUTF8CString(file);
-
- res = JSEvaluateScript(ctx, js_str, JSContextGetGlobalObject(ctx), js_file, 0, &exc);
- JSStringRelease(js_file);
- JSStringRelease(js_str);
-
- if (exc) {
- *result = exc;
- return false;
- }
-
- *result = res;
- return true;
-}
diff --git a/src/js.h b/src/js.h
index 5081bf9..1a63d0a 100644
--- a/src/js.h
+++ b/src/js.h
@@ -20,16 +20,8 @@
#ifndef _JS_H
#define _JS_H
-#include "main.h"
+#include <webkit2/webkit2.h>
-gboolean js_eval_file(JSContextRef ctx, const char *file);
-gboolean js_eval(JSContextRef ctx, const char *script, const char *file,
- char **value);
-JSObjectRef js_create_object(JSContextRef ctx, const char *script);
-char* js_object_call_function(JSContextRef ctx, JSObjectRef obj,
- const char *func, int count, JSValueRef params[]);
-char *js_ref_to_string(JSContextRef ctx, JSValueRef ref);
-JSValueRef js_string_to_ref(JSContextRef ctx, const char *string);
-JSValueRef js_object_to_ref(JSContextRef ctx, const char *json);
+char *js_result_as_string(WebKitJavascriptResult *res);
-#endif /* end of include guard: _JS_H */
+#endif
diff --git a/src/js2h.sh b/src/js2h.sh
deleted file mode 100755
index f849e85..0000000
--- a/src/js2h.sh
+++ /dev/null
@@ -1,15 +0,0 @@
-#!/bin/sh
-
-echo '#define HINTS_JS "' | tr -d '\n'
-cat $1 | \
- tr '\n\r\t' ' ' | \
- sed -e 's:/\*[^*]*\*/::g' \
- -e 's|[ ]\{2,\}| |g' \
- -e "s|[ ]\{0,\}\([-!?<>:=(){};+\&\"',\|]\)[ ]\{0,\}|\1|g" \
- -e 's|"+"||g' \
- -e 's|\\x20| |g' \
- -e 's|\\|\\\\|g' \
- -e 's|"|\\"|g' \
- -e 's|HINT_CSS|" HINT_CSS "|' \
- -e '$s/$/"/'
-echo ""
diff --git a/src/main.c b/src/main.c
index 3b379fc..a8c9f74 100644
--- a/src/main.c
+++ b/src/main.c
@@ -17,138 +17,76 @@
* along with this program. If not, see http://www.gnu.org/licenses/.
*/
-#include "config.h"
-#include <stdio.h>
+#include <gdk/gdkx.h>
+#include <gtk/gtk.h>
+#include <gtk/gtkx.h>
+#include <limits.h>
+#include <stdlib.h>
+#include <string.h>
#include <sys/stat.h>
#include <unistd.h>
-#include <gdk/gdkx.h>
-#include "main.h"
-#include "util.h"
-#include "command.h"
-#include "setting.h"
+#include <webkit2/webkit2.h>
+
+#include "ascii.h"
#include "completion.h"
-#include "dom.h"
-#include "hints.h"
-#include "shortcut.h"
-#include "handlers.h"
-#include "history.h"
-#include "cookiejar.h"
-#include "hsts.h"
-#include "normal.h"
+#include "config.h"
#include "ex.h"
+#include "ext-proxy.h"
#include "input.h"
-#include "map.h"
-#include "bookmark.h"
#include "js.h"
-#include "autocmd.h"
-#include "arh.h"
-#include "io.h"
-#include "ascii.h"
-
-/* variables */
-static char *argv0;
-VbCore vb;
-
-/* callbacks */
+#include "main.h"
+#include "map.h"
+#include "normal.h"
+#include "scripts/scripts.h"
+#include "setting.h"
+#include "shortcut.h"
+#include "util.h"
-static void buffer_changed_cb(GtkTextBuffer* buffer, gpointer data);
-#if WEBKIT_CHECK_VERSION(1, 10, 0)
-static gboolean context_menu_cb(WebKitWebView *view, GtkWidget *menu,
- WebKitHitTestResult *hitTestResult, gboolean keyboard, gpointer data);
-#else
-static void context_menu_cb(WebKitWebView *view, GtkMenu *menu, gpointer data);
-#endif
-static void context_menu_activate_cb(GtkMenuItem *item, gpointer data);
-static void uri_change_cb(WebKitWebView *view, GParamSpec param_spec);
-static void webview_progress_cb(WebKitWebView *view, GParamSpec *pspec);
-static void webview_download_progress_cb(WebKitWebView *view, GParamSpec *pspec);
-static void webview_load_status_cb(WebKitWebView *view, GParamSpec *pspec);
-static void webview_request_starting_cb(WebKitWebView *view,
- WebKitWebFrame *frame, WebKitWebResource *res, WebKitNetworkRequest *req,
- WebKitNetworkResponse *resp, gpointer data);
-static gboolean focus_out_event_cb(GtkWidget *widget, GdkEvent *event, gpointer user_data);
-static gboolean focus_in_event_cb(GtkWidget *widget, GdkEvent *event, gpointer user_data);
-static void destroy_window_cb(GtkWidget *widget);
-static void scroll_cb(GtkAdjustment *adjustment);
-static gboolean input_focus_in_cb(GtkWidget *widget, GdkEventFocus *event,
- gpointer data);
-static WebKitWebView *inspector_new(WebKitWebInspector *inspector, WebKitWebView *webview);
-static gboolean inspector_show(WebKitWebInspector *inspector);
-static gboolean inspector_close(WebKitWebInspector *inspector);
-static void inspector_finished(WebKitWebInspector *inspector);
-static gboolean button_relase_cb(WebKitWebView *webview, GdkEventButton *event);
-static gboolean new_window_policy_cb(
- WebKitWebView *view, WebKitWebFrame *frame, WebKitNetworkRequest *request,
- WebKitWebNavigationAction *navig, WebKitWebPolicyDecision *policy);
-static WebKitWebView *create_web_view_cb(WebKitWebView *view, WebKitWebFrame *frame);
-static gboolean create_web_view_received_uri_cb(WebKitWebView *view,
- WebKitWebFrame *frame, WebKitNetworkRequest *request,
- WebKitWebNavigationAction *action, WebKitWebPolicyDecision *policy,
- gpointer data);
-static gboolean navigation_decision_requested_cb(WebKitWebView *view,
- WebKitWebFrame *frame, WebKitNetworkRequest *request,
- WebKitWebNavigationAction *action, WebKitWebPolicyDecision *policy,
- gpointer data);
-static void onload_event_cb(WebKitWebView *view, WebKitWebFrame *frame,
- gpointer user_data);
-static void hover_link_cb(WebKitWebView *webview, const char *title, const char *link);
-static void title_changed_cb(WebKitWebView *webview, WebKitWebFrame *frame, const char *title);
-static gboolean mimetype_decision_cb(WebKitWebView *webview,
- WebKitWebFrame *frame, WebKitNetworkRequest *request, char*
- mime_type, WebKitWebPolicyDecision *decision);
-gboolean vb_download(WebKitWebView *view, WebKitDownload *download, const char *path);
-void vb_download_internal(WebKitWebView *view, WebKitDownload *download, const char *file);
-void vb_download_external(WebKitWebView *view, WebKitDownload *download, const char *file);
-static void download_progress_cp(WebKitDownload *download, GParamSpec *pspec);
-static void read_from_stdin(void);
-#ifdef FEATURE_ARH
-static void session_request_queued_cb(SoupSession *session, SoupMessage *msg, gpointer data);
+static void client_destroy(Client *c);
+static Client *client_new(WebKitWebView *webview);
+static gboolean input_clear(Client *c);
+static void input_print(Client *c, gboolean force, MessageType type,
+ gboolean hide, const char *message);
+static void marks_clear(Client *c);
+static void mode_free(Mode *mode);
+static void on_webctx_init_web_extension(WebKitWebContext *webctx, gpointer data);
+static void on_webview_close(WebKitWebView *webview, Client *c);
+static WebKitWebView *on_webview_create(WebKitWebView *webview,
+ WebKitNavigationAction *navact, Client *c);
+static gboolean on_webview_decide_policy(WebKitWebView *webview,
+ WebKitPolicyDecision *dec, WebKitPolicyDecisionType type, Client *c);
+static void on_webview_load_changed(WebKitWebView *webview,
+ WebKitLoadEvent event, Client *c);
+static void on_webview_mouse_target_changed(WebKitWebView *webview,
+ WebKitHitTestResult *result, guint modifiers, Client *c);
+static void on_webview_notify_estimated_load_progress(WebKitWebView *webview,
+ GParamSpec *spec, Client *c);
+static void on_webview_notify_title(WebKitWebView *webview, GParamSpec *pspec,
+ Client *c);
+static void on_webview_notify_uri(WebKitWebView *webview, GParamSpec *pspec,
+ Client *c);
+static void on_webview_ready_to_show(WebKitWebView *webview, Client *c);
+static gboolean on_webview_web_process_crashed(WebKitWebView *webview, Client *c);
+static void on_window_destroy(GtkWidget *window, Client *c);
+static gboolean quit(Client *c);
+static void register_cleanup(Client *c);
+static void update_urlbar(Client *c);
+static void set_statusbar_style(Client *c, StatusType type);
+static void set_title(Client *c, const char *title);
+static void spawn_new_instance(const char *uri, gboolean embed);
+#ifdef FREE_ON_QUIT
+static void vimb_cleanup(void);
#endif
+static void vimb_setup(void);
+static WebKitWebView *webview_new(Client *c, WebKitWebView *webview);
+
+struct Vimb vb;
-/* functions */
-#ifdef FEATURE_WGET_PROGRESS_BAR
-static void wget_bar(int len, int progress, char *string);
-#endif
-static void update_title(void);
-static void set_uri(const char *uri);
-static void set_title(const char *title);
-static void init_core(void);
-static void marks_clear(void);
-static void setup_signals();
-static void init_files(void);
-static void session_init(void);
-static void session_cleanup(void);
-static void register_init(void);
-static void register_cleanup(void);
-static gboolean hide_message();
-static void set_status(const StatusType status);
-static void input_print(gboolean force, const MessageType type, gboolean hide, const char *message);
-static void vb_cleanup(void);
-static void cleanup_modes(void);
-static void free_mode(Mode *mode);
/**
- * Creates a new mode with given callback functions.
+ * Write text to the inpubox if this isn't focused.
*/
-void vb_add_mode(char id, ModeTransitionFunc enter, ModeTransitionFunc leave,
- ModeKeyFunc keypress, ModeInputChangedFunc input_changed)
-{
- Mode *new = g_slice_new(Mode);
- new->id = id;
- new->enter = enter;
- new->leave = leave;
- new->keypress = keypress;
- new->input_changed = input_changed;
- new->flags = 0;
-
- /* Initialize the hashmap if this was not done before */
- if (!vb.modes) {
- vb.modes = g_hash_table_new_full(g_direct_hash, g_direct_equal, NULL, (GDestroyNotify)free_mode);
- }
- g_hash_table_insert(vb.modes, GINT_TO_POINTER(id), new);
-}
-
-void vb_echo_force(const MessageType type, gboolean hide, const char *error, ...)
+void vb_echo(Client *c, MessageType type, gboolean hide, const char *error, ...)
{
char *buffer;
va_list args;
@@ -157,11 +95,15 @@ void vb_echo_force(const MessageType type, gboolean hide, const char *error, ...
buffer = g_strdup_vprintf(error, args);
va_end(args);
- input_print(true, type, hide, buffer);
+ input_print(c, FALSE, type, hide, buffer);
g_free(buffer);
}
-void vb_echo(const MessageType type, gboolean hide, const char *error, ...)
+/**
+ * Write text to the inpubox independent if this is focused or not.
+ * Note that this could disturb the user during typing into inputbox.
+ */
+void vb_echo_force(Client *c, MessageType type, gboolean hide, const char *error, ...)
{
char *buffer;
va_list args;
@@ -170,28 +112,28 @@ void vb_echo(const MessageType type, gboolean hide, const char *error, ...)
buffer = g_strdup_vprintf(error, args);
va_end(args);
- input_print(false, type, hide, buffer);
+ input_print(c, TRUE, type, hide, buffer);
g_free(buffer);
}
/**
* Enter into the new given mode and leave possible active current mode.
*/
-void vb_enter(char id)
+void vb_enter(Client *c, char id)
{
Mode *new = g_hash_table_lookup(vb.modes, GINT_TO_POINTER(id));
g_return_if_fail(new != NULL);
- if (vb.mode) {
+ if (c->mode) {
/* don't do anything if the mode isn't a new one */
- if (vb.mode == new) {
+ if (c->mode == new) {
return;
}
/* if there is a active mode, leave this first */
- if (vb.mode->leave) {
- vb.mode->leave();
+ if (c->mode->leave) {
+ c->mode->leave(c);
}
}
@@ -199,14 +141,14 @@ void vb_enter(char id)
new->flags = 0;
/* set the new mode so that it is available also in enter function */
- vb.mode = new;
+ c->mode = new;
/* call enter only if the new mode isn't the current mode */
if (new->enter) {
- new->enter();
+ new->enter(c);
}
#ifndef TESTLIB
- vb_update_statusbar();
+ vb_statusbar_update(c);
#endif
}
@@ -218,111 +160,69 @@ void vb_enter(char id)
* @print_prompt: Indicates if the new set prompt should be put into inputbox
* after switching the mode.
*/
-void vb_enter_prompt(char id, const char *prompt, gboolean print_prompt)
+void vb_enter_prompt(Client *c, char id, const char *prompt, gboolean print_prompt)
{
/* set the prompt to be accessible in vb_enter */
- strncpy(vb.state.prompt, prompt, PROMPT_SIZE - 1);
- vb.state.prompt[PROMPT_SIZE - 1] = '\0';
+ strncpy(c->state.prompt, prompt, PROMPT_SIZE - 1);
+ c->state.prompt[PROMPT_SIZE - 1] = '\0';
- vb_enter(id);
+ vb_enter(c, id);
if (print_prompt) {
/* set it after the mode was entered so that the modes input change
* event listener could grep the new prompt */
- vb_echo_force(VB_MSG_NORMAL, false, vb.state.prompt);
+ vb_echo_force(c, MSG_NORMAL, FALSE, c->state.prompt);
}
}
-VbResult vb_handle_key(int key)
+/**
+ * Retrieves the content of the command line.
+ * Returned string must be freed with g_free.
+ */
+char *vb_input_get_text(Client *c)
{
- VbResult res;
- static gboolean ctrl_v = false;
-
- if (ctrl_v) {
- vb.state.processed_key = false;
- ctrl_v = false;
-
- return RESULT_COMPLETE;
- }
- if (vb.mode->id != 'p' && key == CTRL('V')) {
- vb.mode->flags |= FLAG_NOMAP;
- ctrl_v = true;
-
- return RESULT_MORE;
- }
+ GtkTextIter start, end;
- if (vb.mode && vb.mode->keypress) {
-#ifdef DEBUG
- int flags = vb.mode->flags;
- int id = vb.mode->id;
- res = vb.mode->keypress(key);
- if (vb.mode) {
- PRINT_DEBUG(
- "%c[%d]: %#.2x '%c' -> %c[%d]",
- id - ' ', flags, key, (key >= 0x20 && key <= 0x7e) ? key : ' ',
- vb.mode->id - ' ', vb.mode->flags
- );
- }
-#else
- res = vb.mode->keypress(key);
-#endif
- return res;
- }
- return RESULT_ERROR;
-}
-
-static void input_print(gboolean force, const MessageType type, gboolean hide,
- const char *message)
-{
- static guint timer = 0;
-
- /* don't print message if the input is focussed */
- if (!force && gtk_widget_is_focus(GTK_WIDGET(vb.gui.input))) {
- return;
- }
-
- /* apply input style only if the message type was changed */
- if (type != vb.state.input_type) {
- vb.state.input_type = type;
- vb_update_input_style();
- }
- vb_set_input_text(message);
- if (hide) {
- /* add timeout function */
- timer = g_timeout_add_seconds(MESSAGE_TIMEOUT, (GSourceFunc)hide_message, NULL);
- } else if (timer > 0) {
- /* If there is already a timeout function but the input box content is
- * changed - remove the timeout. Seems the user started another
- * command or typed into inputbox. */
- g_source_remove(timer);
- timer = 0;
- }
+ gtk_text_buffer_get_bounds(c->buffer, &start, &end);
+ return gtk_text_buffer_get_text(c->buffer, &start, &end, FALSE);
}
/**
* Writes given text into the command line.
*/
-void vb_set_input_text(const char *text)
+void vb_input_set_text(Client *c, const char *text)
{
- gtk_text_buffer_set_text(vb.gui.buffer, text, -1);
- if (vb.config.input_autohide) {
- gtk_widget_set_visible(GTK_WIDGET(vb.gui.input), *text != '\0');
+ gtk_text_buffer_set_text(c->buffer, text, -1);
+ if (c->config.input_autohide) {
+ gtk_widget_set_visible(GTK_WIDGET(c->input), *text != '\0');
}
}
/**
- * Retrieves the content of the command line.
- * Returned string must be freed with g_free.
+ * Set the style of the inputbox according to current input type (normal or
+ * error).
*/
-char *vb_get_input_text(void)
+void vb_input_update_style(Client *c)
{
- GtkTextIter start, end;
+ MessageType type = c->state.input_type;
- gtk_text_buffer_get_bounds(vb.gui.buffer, &start, &end);
- return gtk_text_buffer_get_text(vb.gui.buffer, &start, &end, false);
+ if (type == MSG_ERROR) {
+ gtk_style_context_add_class(gtk_widget_get_style_context(c->input), "error");
+ } else {
+ gtk_style_context_remove_class(gtk_widget_get_style_context(c->input), "error");
+ }
}
-gboolean vb_load_uri(const Arg *arg)
+/**
+ * Load the a uri given in Arg. This function handles also shortcuts and local
+ * file paths.
+ *
+ * If arg.i = TARGET_CURRENT, the url is opened into the current webview.
+ * TARGET_RELATED causes the generation of a new window within the current
+ * instance of vimb with a own, but related webview. And TARGET_NEW spawns a
+ * new instance of vimb with the given uri.
+ */
+gboolean vb_load_uri(Client *c, const Arg *arg)
{
char *uri = NULL, *rp, *path = NULL;
struct stat st;
@@ -331,7 +231,7 @@ gboolean vb_load_uri(const Arg *arg)
path = g_strstrip(arg->s);
}
if (!path || !*path) {
- path = GET_CHAR("home-page");
+ path = GET_CHAR(c, "home-page");
}
/* If path contains :// but no space we open it direct. This is required
@@ -345,1548 +245,964 @@ gboolean vb_load_uri(const Arg *arg)
free(rp);
} else if (strchr(path, ' ') || !strchr(path, '.')) {
/* use a shortcut if path contains spaces or no dot */
- uri = shortcut_get_uri(path);
+ uri = shortcut_get_uri(c, path);
}
if (!uri) {
uri = g_strconcat("http://", path, NULL);
}
- if (arg->i == VB_TARGET_NEW) {
- guint i = 0;
-
- /* memory allocation */
- char **cmd = g_malloc_n(
- 3 /* basename + uri + ending NULL */
- + (vb.embed ? 2 : 0)
- + (vb.config.file ? 2 : 0)
- + (vb.config.profile ? 2 : 0)
- + (vb.config.kioskmode ? 1 : 0)
-#ifdef FEATURE_SOCKET
- + (vb.config.socket ? 1 : 0)
-#endif
- + g_slist_length(vb.config.cmdargs) * 2,
- sizeof(char *)
- );
-
- /* build commandline */
- cmd[i++] = argv0;
- if (vb.embed) {
- char xid[64];
- snprintf(xid, LENGTH(xid), "%u", (int)vb.embed);
- cmd[i++] = "-e";
- cmd[i++] = xid;
- }
- if (vb.config.file) {
- cmd[i++] = "-c";
- cmd[i++] = vb.config.file;
- }
- if (vb.config.profile) {
- cmd[i++] = "-p";
- cmd[i++] = vb.config.profile;
- }
- for (GSList *l = vb.config.cmdargs; l; l = l->next) {
- cmd[i++] = "-C";
- cmd[i++] = l->data;
- }
- if (vb.config.kioskmode) {
- cmd[i++] = "-k";
- }
-#ifdef FEATURE_SOCKET
- if (vb.config.socket) {
- cmd[i++] = "-s";
- }
-#endif
- cmd[i++] = uri;
- cmd[i++] = NULL;
-
- /* spawn a new browser instance */
- g_spawn_async(NULL, cmd, NULL, G_SPAWN_SEARCH_PATH, NULL, NULL, NULL, NULL);
-
- /* free commandline */
- g_free(cmd);
- } else {
- /* Load a web page into the browser instance */
- webkit_web_view_load_uri(vb.gui.webview, uri);
- /* show the url to be opened in the window title until we receive the
- * page title */
- set_title(uri);
+ if (arg->i == TARGET_CURRENT) {
+ /* Load the uri into the browser instance. */
+ webkit_web_view_load_uri(c->webview, uri);
+ set_title(c, uri);
+ } else if (arg->i == TARGET_NEW) {
+ spawn_new_instance(uri, TRUE);
+ } else { /* TARGET_RELATET */
+ Client *newclient = client_new(c->webview);
+ /* Load the uri into the new client. */
+ webkit_web_view_load_uri(newclient->webview, uri);
+ set_title(c, uri);
}
g_free(uri);
- return true;
-}
-
-gboolean vb_set_clipboard(const Arg *arg)
-{
- gboolean result = false;
- if (!arg->s) {
- return result;
- }
-
- if (arg->i & VB_CLIPBOARD_PRIMARY) {
- gtk_clipboard_set_text(PRIMARY_CLIPBOARD(), arg->s, -1);
- result = true;
- }
- if (arg->i & VB_CLIPBOARD_SECONDARY) {
- gtk_clipboard_set_text(SECONDARY_CLIPBOARD(), arg->s, -1);
- result = true;
- }
-
- return result;
-}
-
-void vb_set_widget_font(GtkWidget *widget, const VbColor *fg, const VbColor *bg, PangoFontDescription *font)
-{
- VB_WIDGET_OVERRIDE_FONT(widget, font);
- VB_WIDGET_OVERRIDE_TEXT(widget, VB_GTK_STATE_NORMAL, fg);
- VB_WIDGET_OVERRIDE_COLOR(widget, VB_GTK_STATE_NORMAL, fg);
- VB_WIDGET_OVERRIDE_BASE(widget, VB_GTK_STATE_NORMAL, bg);
- VB_WIDGET_OVERRIDE_BACKGROUND(widget, VB_GTK_STATE_NORMAL, bg);
+ return TRUE;
}
-#ifdef FEATURE_WGET_PROGRESS_BAR
-static void wget_bar(int len, int progress, char *string)
+/**
+ * Creates and add a new mode with given callback functions.
+ */
+void vb_mode_add(char id, ModeTransitionFunc enter, ModeTransitionFunc leave,
+ ModeKeyFunc keypress, ModeInputChangedFunc input_changed)
{
- int i, state;
+ Mode *new = g_slice_new(Mode);
+ new->id = id;
+ new->enter = enter;
+ new->leave = leave;
+ new->keypress = keypress;
+ new->input_changed = input_changed;
+ new->flags = 0;
- state = progress * len / 100;
- for (i = 0; i < state; i++) {
- string[i] = PROGRESS_BAR[0];
- }
- string[i++] = PROGRESS_BAR[1];
- for (; i < len; i++) {
- string[i] = PROGRESS_BAR[2];
+ /* Initialize the hashmap if this was not done before */
+ if (!vb.modes) {
+ vb.modes = g_hash_table_new_full(g_direct_hash, g_direct_equal, NULL, (GDestroyNotify)mode_free);
}
- string[i] = '\0';
+ g_hash_table_insert(vb.modes, GINT_TO_POINTER(id), new);
}
-#endif
-void vb_update_statusbar()
+VbResult vb_mode_handle_key(Client *c, int key)
{
- int max, val, num;
- GString *status;
+ VbResult res;
- if (!gtk_widget_get_visible(GTK_WIDGET(vb.gui.statusbar.box))) {
- return;
- }
+ if (c->state.ctrlv) {
+ c->state.processed_key = FALSE;
+ c->state.ctrlv = FALSE;
- status = g_string_new("");
- /* show the active downloads */
- if (vb.state.downloads) {
- num = g_list_length(vb.state.downloads);
- g_string_append_printf(status, " %d %s", num, num == 1 ? "download" : "downloads");
+ return RESULT_COMPLETE;
}
+ if (c->mode->id != 'p' && key == CTRL('V')) {
+ c->mode->flags |= FLAG_NOMAP;
+ c->state.ctrlv = TRUE;
-#ifdef FEATURE_SEARCH_HIGHLIGHT
- /* show the number of matches search results */
- if (vb.state.search_matches) {
- g_string_append_printf(status, " (%d)", vb.state.search_matches);
+ return RESULT_MORE;
}
-#endif
- /* show load status of page or the downloads */
- if (vb.state.progress != 100) {
-#ifdef FEATURE_WGET_PROGRESS_BAR
- char bar[PROGRESS_BAR_LEN + 1];
- wget_bar(PROGRESS_BAR_LEN, vb.state.progress, bar);
- g_string_append_printf(status, " [%s]", bar);
+ if (c->mode && c->mode->keypress) {
+#ifdef DEBUGDISABLED
+ int flags = c->mode->flags;
+ int id = c->mode->id;
+ res = c->mode->keypress(c, key);
+ if (c->mode) {
+ PRINT_DEBUG(
+ "%c[%d]: %#.2x '%c' -> %c[%d]",
+ id - ' ', flags, key, (key >= 0x20 && key <= 0x7e) ? key : ' ',
+ c->mode->id - ' ', c->mode->flags
+ );
+ }
#else
- g_string_append_printf(status, " [%i%%]", vb.state.progress);
-#endif
- }
-
- /* show the scroll status */
- max = gtk_adjustment_get_upper(vb.gui.adjust_v) - gtk_adjustment_get_page_size(vb.gui.adjust_v);
- val = (int)(0.5 + (gtk_adjustment_get_value(vb.gui.adjust_v) / max * 100));
-
- if (max == 0) {
- g_string_append(status, " All");
- } else if (val == 0) {
- g_string_append(status, " Top");
- } else if (val >= 100) {
- g_string_append(status, " Bot");
- } else {
- g_string_append_printf(status, " %d%%", val);
- }
-
- gtk_label_set_text(GTK_LABEL(vb.gui.statusbar.right), status->str);
- g_string_free(status, true);
-}
-
-void vb_update_status_style(void)
-{
- StatusType type = vb.state.status_type;
- vb_set_widget_font(
- vb.gui.eventbox, &vb.style.status_fg[type], &vb.style.status_bg[type], vb.style.status_font[type]
- );
-#ifndef HAS_GTK3
- vb_set_widget_font(
- vb.gui.statusbar.mode, &vb.style.status_fg[type], &vb.style.status_bg[type], vb.style.status_font[type]
- );
- vb_set_widget_font(
- vb.gui.statusbar.left, &vb.style.status_fg[type], &vb.style.status_bg[type], vb.style.status_font[type]
- );
- vb_set_widget_font(
- vb.gui.statusbar.right, &vb.style.status_fg[type], &vb.style.status_bg[type], vb.style.status_font[type]
- );
- vb_set_widget_font(
- vb.gui.statusbar.cmd, &vb.style.status_fg[type], &vb.style.status_bg[type], vb.style.status_font[type]
- );
+ res = c->mode->keypress(c, key);
#endif
-}
-
-void vb_update_input_style(void)
-{
- MessageType type = vb.state.input_type;
- vb_set_widget_font(
- vb.gui.input, &vb.style.input_fg[type], &vb.style.input_bg[type], vb.style.input_font[type]
- );
-}
-
-void vb_update_urlbar(const char *uri)
-{
- Gui *gui = &vb.gui;
-#if !defined(FEATURE_HISTORY_INDICATOR) && !defined(FEATURE_PROFILE_INDICATOR)
- /* if only the uri is shown - write it like it is on the label */
- gtk_label_set_text(GTK_LABEL(gui->statusbar.left), uri);
-#else
- GString *str = g_string_new("");
-#ifdef FEATURE_PROFILE_INDICATOR
- if (vb.config.profile) {
- g_string_append_printf(str, "[%s] ", vb.config.profile);
- }
-#endif /* FEATURE_PROFILE_INDICATOR */
-
- g_string_append_printf(str, "%s", uri);
-
-#ifdef FEATURE_HISTORY_INDICATOR
- gboolean back, fwd;
-
- back = webkit_web_view_can_go_back(gui->webview);
- fwd = webkit_web_view_can_go_forward(gui->webview);
-
- /* show history indicator only if there is something to show */
- if (back || fwd) {
- g_string_append_printf(str, " [%s]", back ? (fwd ? "-+" : "-") : "+");
+ return res;
}
-#endif /* FEATURE_HISTORY_INDICATOR */
-
- gtk_label_set_text(GTK_LABEL(gui->statusbar.left), str->str);
- g_string_free(str, true);
-#endif /* !defined(FEATURE_HISTORY_INDICATOR) && !defined(FEATURE_PROFILE_INDICATOR) */
+ return RESULT_ERROR;
}
-void vb_update_mode_label(const char *label)
+/**
+ * Change the label for the current mode in inputbox or on the left of
+ * statusbar if inputbox is in autohide mode.
+ */
+void vb_modelabel_update(Client *c, const char *label)
{
- if (GET_BOOL("input-autohide")) {
+ if (c->config.input_autohide) {
/* if the inputbox is potentially not shown write mode into statusbar */
- gtk_label_set_text(GTK_LABEL(vb.gui.statusbar.mode), label);
+ gtk_label_set_text(GTK_LABEL(c->statusbar.mode), label);
} else {
- vb_echo(VB_MSG_NORMAL, false, "%s", label);
+ vb_echo(c, MSG_NORMAL, FALSE, "%s", label);
}
+ gtk_label_set_text(GTK_LABEL(c->statusbar.mode), label);
}
-void vb_quit(gboolean force)
+/**
+ * Close the given client instances window.
+ */
+void vb_quit(Client *c, gboolean force)
{
+#if 0 /* TODO don't quit on running downloads */
/* if not forced quit - don't quit if there are still running downloads */
- if (!force && vb.state.downloads) {
- vb_echo_force(VB_MSG_ERROR, true, "Can't quit: there are running downloads");
+ if (!force && c->state.downloads) {
+ vb_echo_force(c, VB_MSG_ERROR, TRUE, "Can't quit: there are running downloads");
return;
}
-
- webkit_web_view_stop_loading(vb.gui.webview);
-
- /* write last URL into file for recreation */
- if (vb.state.uri && vb.config.closed_max) {
- char **lines = util_get_lines(vb.files[FILES_CLOSED]);
- GString *new = g_string_new(vb.state.uri);
- g_string_append(new, "\n");
- if (lines) {
- int len = g_strv_length(lines);
- int i;
- for (i = 0; i < len - 1 && i < vb.config.closed_max - 1; i++) {
- g_string_append_printf(new, "%s\n", lines[i]);
- }
- g_strfreev(lines);
- }
- g_file_set_contents(vb.files[FILES_CLOSED], new->str, -1, NULL);
- g_string_free(new, true);
- }
-
- gtk_main_quit();
-}
-
-static gboolean hide_message()
-{
- input_print(false, VB_MSG_NORMAL, false, "");
-
- return false;
+#endif
+ /* Don't run the quit synchronously, because this could lead to access of
+ * no more existing widget where some command response is written. */
+ g_idle_add((GSourceFunc)quit, c);
}
/**
- * Process input changed event on current active mode.
+ * Adds content to a named register.
*/
-static void buffer_changed_cb(GtkTextBuffer* buffer, gpointer data)
+void vb_register_add(Client *c, char buf, const char *value)
{
- char *text;
- GtkTextIter start, end;
- /* don't observe changes in completion mode */
- if (vb.mode->flags & FLAG_COMPLETION) {
+ char *mark;
+ int idx;
+
+ if (!c->state.enable_register || !buf) {
return;
}
- /* don't process changes not typed by the user */
- if (gtk_widget_is_focus(vb.gui.input) && vb.mode && vb.mode->input_changed) {
- gtk_text_buffer_get_bounds(buffer, &start, &end);
- text = gtk_text_buffer_get_text(buffer, &start, &end, false);
- vb.mode->input_changed(text);
+ /* make sure the mark is a valid mark char */
+ if ((mark = strchr(REG_CHARS, buf))) {
+ /* get the index of the mark char */
+ idx = mark - REG_CHARS;
- g_free(text);
+ OVERWRITE_STRING(c->state.reg[idx], value);
}
}
-#if WEBKIT_CHECK_VERSION(1, 10, 0)
-static gboolean context_menu_cb(WebKitWebView *view, GtkWidget *menu,
- WebKitHitTestResult *hitTestResult, gboolean keyboard, gpointer data)
-{
- GList *items = gtk_container_get_children(GTK_CONTAINER(GTK_MENU(menu)));
- for (GList *l = items; l; l = l->next) {
- g_signal_connect(l->data, "activate", G_CALLBACK(context_menu_activate_cb), NULL);
- }
- g_list_free(items);
-
- return false;
-}
-#else
-static void context_menu_cb(WebKitWebView *view, GtkMenu *menu, gpointer data)
+/**
+ * Lookup register entry by it's name.
+ */
+const char *vb_register_get(Client *c, char buf)
{
- GList *items = gtk_container_get_children(GTK_CONTAINER(GTK_MENU(menu)));
- for (GList *l = items; l; l = l->next) {
- g_signal_connect(l->data, "activate", G_CALLBACK(context_menu_activate_cb), NULL);
- }
- g_list_free(items);
-}
-#endif
+ char *mark;
+ int idx;
-static void context_menu_activate_cb(GtkMenuItem *item, gpointer data)
-{
-#if WEBKIT_CHECK_VERSION(1, 10, 0)
- WebKitContextMenuAction action = webkit_context_menu_item_get_action(item);
- if (action == WEBKIT_CONTEXT_MENU_ACTION_COPY_LINK_TO_CLIPBOARD) {
- vb_set_clipboard(
- &((Arg){VB_CLIPBOARD_PRIMARY|VB_CLIPBOARD_SECONDARY, vb.state.linkhover})
- );
- }
-#else
- const char *name;
- GtkAction *action = gtk_activatable_get_related_action(GTK_ACTIVATABLE(item));
+ /* make sure the mark is a valid mark char */
+ if ((mark = strchr(REG_CHARS, buf))) {
+ /* get the index of the mark char */
+ idx = mark - REG_CHARS;
- if (!action) {
- return;
+ return c->state.reg[idx];
}
- name = gtk_action_get_name(action);
- /* context-menu-action-3 copy link location */
- if (!g_strcmp0(name, "context-menu-action-3")) {
- vb_set_clipboard(
- &((Arg){VB_CLIPBOARD_PRIMARY|VB_CLIPBOARD_SECONDARY,vb.state.linkhover})
- );
- }
-#endif
-}
-
-static void uri_change_cb(WebKitWebView *view, GParamSpec param_spec)
-{
- set_uri(webkit_web_view_get_uri(view));
-}
-
-static void webview_progress_cb(WebKitWebView *view, GParamSpec *pspec)
-{
- vb.state.progress = webkit_web_view_get_progress(view) * 100;
- vb_update_statusbar();
- update_title();
-}
-
-static void webview_download_progress_cb(WebKitWebView *view, GParamSpec *pspec)
-{
- if (vb.state.downloads) {
- vb.state.progress = 0;
- GList *ptr;
- for (ptr = vb.state.downloads; ptr; ptr = g_list_next(ptr)) {
- vb.state.progress += 100 * webkit_download_get_progress(ptr->data);
- }
- vb.state.progress /= g_list_length(vb.state.downloads);
- }
- vb_update_statusbar();
- update_title();
+ return NULL;
}
-static void webview_load_status_cb(WebKitWebView *view, GParamSpec *pspec)
+void vb_statusbar_update(Client *c)
{
- const char *uri;
- WebKitWebFrame *frame = webkit_web_view_get_main_frame(view);
-
- switch (webkit_web_view_get_load_status(view)) {
- case WEBKIT_LOAD_PROVISIONAL:
-#ifdef FEATURE_AUTOCMD
- {
- WebKitWebDataSource *src = webkit_web_frame_get_provisional_data_source(frame);
- WebKitNetworkRequest *req = webkit_web_data_source_get_initial_request(src);
- uri = webkit_network_request_get_uri(req);
- autocmd_run(AU_LOAD_PROVISIONAL, uri, NULL);
- }
-#endif
- /* update load progress in statusbar */
- vb.state.progress = 0;
- vb_update_statusbar();
- update_title();
- break;
-
- case WEBKIT_LOAD_COMMITTED:
- uri = webkit_web_view_get_uri(view);
-#ifdef FEATURE_AUTOCMD
- autocmd_run(AU_LOAD_COMMITED, uri, NULL);
-#endif
- {
- JSContextRef ctx;
- /* set the status */
- if (g_str_has_prefix(uri, "https://")) {
- WebKitWebDataSource *src = webkit_web_frame_get_data_source(frame);
- WebKitNetworkRequest *request = webkit_web_data_source_get_request(src);
- SoupMessage *msg = webkit_network_request_get_message(request);
- SoupMessageFlags flags = soup_message_get_flags(msg);
- set_status(
- (flags & SOUP_MESSAGE_CERTIFICATE_TRUSTED) ? VB_STATUS_SSL_VALID : VB_STATUS_SSL_INVALID
- );
- } else {
- set_status(VB_STATUS_NORMAL);
- }
-
- /* inject the hinting javascript */
- hints_init(frame);
-
- /* run user script file */
- ctx = webkit_web_frame_get_global_context(frame);
- js_eval_file(ctx, vb.files[FILES_SCRIPT]);
- }
-
- vb_update_statusbar();
- set_uri(uri);
- set_title(uri);
- /* save the current URI in register % */
- vb_register_add('%', uri);
-
- /* clear possible set marks */
- marks_clear();
-
- break;
-
- case WEBKIT_LOAD_FIRST_VISUALLY_NON_EMPTY_LAYOUT:
-#ifdef FEATURE_AUTOCMD
- uri = webkit_web_view_get_uri(view);
- autocmd_run(AU_LOAD_FIRST_LAYOUT, uri, NULL);
-#endif
- /* if we load a page from a submitted form, leave the insert mode */
- if (vb.mode->id == 'i') {
- vb_enter('n');
- }
-
- dom_install_focus_blur_callbacks(webkit_web_frame_get_dom_document(frame));
- vb.state.done_loading_page = false;
-
- break;
-
- case WEBKIT_LOAD_FINISHED:
- dom_install_focus_blur_callbacks(webkit_web_frame_get_dom_document(frame));
- uri = webkit_web_view_get_uri(view);
-#ifdef FEATURE_AUTOCMD
- autocmd_run(AU_LOAD_FINISHED, uri, NULL);
-#endif
- /* update load progress in statusbar */
- vb.state.progress = 100;
- vb_update_statusbar();
- update_title();
-
- if (strncmp(uri, "about:", 6)) {
- history_add(HISTORY_URL, uri, webkit_web_view_get_title(view));
- }
- break;
-
- case WEBKIT_LOAD_FAILED:
- {
- /* In case the requested uri could not be loaded the Current
- * uri of the Webview would still be the PRevious one. So We
- * use the provisional uri here. */
- WebKitWebDataSource *src = webkit_web_frame_get_provisional_data_source(frame);
- if (src) {
- WebKitNetworkRequest *req = webkit_web_data_source_get_initial_request(src);
- uri = webkit_network_request_get_uri(req);
- } else {
- uri = webkit_web_view_get_uri(view);
- }
- set_uri(uri);
- /* Show the failed uri as title. */
- set_title(uri);
-#ifdef FEATURE_AUTOCMD
- autocmd_run(AU_LOAD_FAILED, uri, NULL);
-#endif
- }
- break;
- }
-}
+ int num;
+ GString *status;
-static void webview_request_starting_cb(WebKitWebView *view,
- WebKitWebFrame *frame, WebKitWebResource *res, WebKitNetworkRequest *req,
- WebKitNetworkResponse *resp, gpointer data)
-{
- char *name, *value;
- GHashTableIter iter;
- SoupMessage *msg;
-
- /* don't try to load favicon */
- const char *uri = webkit_network_request_get_uri(req);
- if (g_str_has_suffix(uri, "/favicon.ico")) {
- webkit_network_request_set_uri(req, "about:blank");
+ if (!gtk_widget_get_visible(GTK_WIDGET(c->statusbar.box))) {
return;
}
- msg = webkit_network_request_get_message(req);
- if (!msg) {
- return;
+ status = g_string_new("");
+ /* show the active downloads */
+ if (c->state.downloads) {
+ num = g_list_length(c->state.downloads);
+ g_string_append_printf(status, " %d %s", num, num == 1 ? "download" : "downloads");
}
- if (!vb.config.headers) {
- return;
+ /* show the number of matches search results */
+ if (c->state.search.matches) {
+ g_string_append_printf(status, " (%d)", c->state.search.matches);
}
- /* set/remove/change user defined headers */
- g_hash_table_iter_init(&iter, vb.config.headers);
- while (g_hash_table_iter_next(&iter, (gpointer*)&name, (gpointer*)&value)) {
- /* allow to remove header with null value */
- if (value == NULL) {
- soup_message_headers_remove(msg->request_headers, name);
- } else {
- soup_message_headers_replace(msg->request_headers, name, value);
+ /* show load status of page or the downloads */
+ if (c->state.progress != 100) {
+#ifdef FEATURE_WGET_PROGRESS_BAR
+ char bar[PROGRESS_BAR_LEN + 1];
+ int i, state;
+
+ state = c->state.progress * PROGRESS_BAR_LEN / 100;
+ for (i = 0; i < state; i++) {
+ bar[i] = PROGRESS_BAR[0];
}
+ bar[i++] = PROGRESS_BAR[1];
+ for (; i < PROGRESS_BAR_LEN; i++) {
+ bar[i] = PROGRESS_BAR[2];
+ }
+ bar[i] = '\0';
+ g_string_append_printf(status, " [%s]", bar);
+#else
+ g_string_append_printf(status, " [%i%%]", c->state.progress);
+#endif
}
-}
-
-static gboolean focus_out_event_cb(GtkWidget *widget, GdkEvent *event,
- gpointer user_data)
-{
- vb.state.window_has_focus = false;
- return false;
-}
-
-static gboolean focus_in_event_cb(GtkWidget *widget, GdkEvent *event,
- gpointer user_data)
-{
- vb.state.window_has_focus = true;
- return false;
-}
-
-static void destroy_window_cb(GtkWidget *widget)
-{
- vb_quit(true);
-}
-static void scroll_cb(GtkAdjustment *adjustment)
-{
- vb_update_statusbar();
-}
-
-static gboolean input_focus_in_cb(GtkWidget *widget, GdkEventFocus *event,
- gpointer data)
-{
- /* enter the command mode if the focus is on inputbox */
- vb_enter('c');
-
- return false;
-}
-
-static WebKitWebView *inspector_new(WebKitWebInspector *inspector, WebKitWebView *webview)
-{
- return WEBKIT_WEB_VIEW(webkit_web_view_new());
-}
-
-static gboolean inspector_show(WebKitWebInspector *inspector)
-{
- WebKitWebView *webview;
- int height;
-
- if (vb.state.is_inspecting) {
- return false;
+ /* show the scroll status */
+ if (c->state.scroll_max == 0) {
+ g_string_append(status, " All");
+ } else if (c->state.scroll_percent == 0) {
+ g_string_append(status, " Top");
+ } else if (c->state.scroll_percent == 100) {
+ g_string_append(status, " Bot");
+ } else {
+ g_string_append_printf(status, " %d%%", c->state.scroll_percent);
}
- webview = webkit_web_inspector_get_web_view(inspector);
-
- /* use about 1/3 of window height for the inspector */
- gtk_window_get_size(GTK_WINDOW(vb.gui.window), NULL, &height);
- gtk_paned_set_position(GTK_PANED(vb.gui.pane), 2 * height / 3);
-
- gtk_paned_pack2(GTK_PANED(vb.gui.pane), GTK_WIDGET(webview), true, true);
- gtk_widget_show(GTK_WIDGET(webview));
-
- vb.state.is_inspecting = true;
-
- return true;
+ gtk_label_set_text(GTK_LABEL(c->statusbar.right), status->str);
+ g_string_free(status, TRUE);
}
-static gboolean inspector_close(WebKitWebInspector *inspector)
+/**
+ * Destroys given client and removed it from client queue. If no client is
+ * there in queue, quit the gtk main loop.
+ */
+static void client_destroy(Client *c)
{
- WebKitWebView *webview;
+ Client *p;
+ webkit_web_view_stop_loading(c->webview);
+ gtk_widget_destroy(c->window);
- if (!vb.state.is_inspecting) {
- return false;
+ /* Look for the client in the list, if we searched through the list and
+ * didn't find it the client must be the first item. */
+ for (p = vb.clients; p && p->next != c; p = p->next);
+ if (p) {
+ p->next = c->next;
+ } else {
+ vb.clients = c->next;
}
- webview = webkit_web_inspector_get_web_view(inspector);
- gtk_widget_hide(GTK_WIDGET(webview));
- gtk_widget_destroy(GTK_WIDGET(webview));
- vb.state.is_inspecting = false;
+ completion_cleanup(c);
+ map_cleanup(c);
+ register_cleanup(c);
- return true;
-}
+ g_slice_free(Client, c);
-static void inspector_finished(WebKitWebInspector *inspector)
-{
- g_free(vb.gui.inspector);
-}
-
-static void set_status(const StatusType status)
-{
- if (vb.state.status_type != status) {
- vb.state.status_type = status;
- /* update the statusbar style only if the status changed */
- vb_update_status_style();
+ /* if there are no clients - quit the main loop */
+ if (!vb.clients) {
+ gtk_main_quit();
}
}
-static void init_core(void)
+/**
+ * Creates a new client instance with it's own window.
+ *
+ * @webview: Related webview or NULL if a client with an independent
+ * webview shoudl be created.
+ */
+static Client *client_new(WebKitWebView *webview)
{
- Gui *gui = &vb.gui;
+ Client *c;
char *xid;
+ GtkWidget *box;
+
+ /* create the client */
+ c = g_slice_new0(Client);
+ c->state.progress = 100;
if (vb.embed) {
- gui->window = gtk_plug_new(vb.embed);
- xid = g_strdup_printf("%u", (int)vb.embed);
+ c->window = gtk_plug_new(vb.embed);
+ xid = g_strdup_printf("%d", (int)vb.embed);
} else {
- gui->window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
- gtk_window_set_role(GTK_WINDOW(gui->window), PROJECT_UCFIRST);
-
- gtk_widget_realize(GTK_WIDGET(gui->window));
+ c->window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
+ gtk_window_set_role(GTK_WINDOW(c->window), PROJECT_UCFIRST);
+ gtk_widget_realize(GTK_WIDGET(c->window));
- /* set the x window id to env */
- xid = g_strdup_printf("%d", (int)GDK_WINDOW_XID(gtk_widget_get_window(GTK_WIDGET(gui->window))));
+ xid = g_strdup_printf("%d",
+ (int)GDK_WINDOW_XID(gtk_widget_get_window(GTK_WIDGET(c->window))));
}
- g_setenv("VIMB_XID", xid, true);
- g_free(xid);
-
- GdkGeometry hints = {10, 10};
- gtk_window_set_default_size(GTK_WINDOW(gui->window), WIN_WIDTH, WIN_HEIGHT);
- gtk_window_set_title(GTK_WINDOW(gui->window), PROJECT "/" VERSION);
- gtk_window_set_geometry_hints(GTK_WINDOW(gui->window), NULL, &hints, GDK_HINT_MIN_SIZE);
- gtk_window_set_icon(GTK_WINDOW(gui->window), NULL);
- gtk_widget_set_name(GTK_WIDGET(gui->window), PROJECT);
-
- /* Create a browser instance */
- gui->webview = WEBKIT_WEB_VIEW(webkit_web_view_new());
- gui->inspector = webkit_web_view_get_inspector(gui->webview);
-
- /* Create a scrollable area */
- GtkWidget *scroll = gtk_scrolled_window_new(NULL, NULL);
- gui->adjust_h = gtk_scrolled_window_get_hadjustment(GTK_SCROLLED_WINDOW(scroll));
- gui->adjust_v = gtk_scrolled_window_get_vadjustment(GTK_SCROLLED_WINDOW(scroll));
-
-#ifdef FEATURE_NO_SCROLLBARS
-#ifdef HAS_GTK3
- /* set the default style for the application - this can be overwritten by
- * the users style in gtk-3.0/gtk.css */
- const char *style = "GtkScrollbar{-GtkRange-slider-width:0;-GtkRange-trough-border:0;}\
- GtkScrolledWindow{-GtkScrolledWindow-scrollbar-spacing:0;}";
- GtkCssProvider *provider = gtk_css_provider_get_default();
- gtk_css_provider_load_from_data(provider, style, -1, NULL);
- gtk_style_context_add_provider_for_screen(
- gdk_screen_get_default(),
- GTK_STYLE_PROVIDER(provider),
- GTK_STYLE_PROVIDER_PRIORITY_APPLICATION
- );
-#else /* no GTK3 */
- /* GTK_POLICY_NEVER with gtk3 disallows window resizing and scrolling */
- gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(scroll), GTK_POLICY_NEVER, GTK_POLICY_NEVER);
-#endif
-#endif
-
- /* Prepare the command line */
- gui->input = gtk_text_view_new();
- gui->buffer = gtk_text_view_get_buffer(GTK_TEXT_VIEW(gui->input));
-
-#ifdef HAS_GTK3
- gui->pane = gtk_paned_new(GTK_ORIENTATION_VERTICAL);
- gui->box = GTK_BOX(gtk_box_new(GTK_ORIENTATION_VERTICAL, 0));
- gui->statusbar.box = GTK_BOX(gtk_box_new(GTK_ORIENTATION_HORIZONTAL, 0));
-#else
- gui->pane = gtk_vpaned_new();
- gui->box = GTK_BOX(gtk_vbox_new(false, 0));
- gui->statusbar.box = GTK_BOX(gtk_hbox_new(false, 0));
-#endif
- gui->statusbar.mode = gtk_label_new(NULL);
- gui->statusbar.left = gtk_label_new(NULL);
- gui->statusbar.right = gtk_label_new(NULL);
- gui->statusbar.cmd = gtk_label_new(NULL);
-
- /* Prepare the event box */
- gui->eventbox = gtk_event_box_new();
-
- gtk_paned_pack1(GTK_PANED(gui->pane), GTK_WIDGET(gui->box), true, true);
-
- /* Put all part together */
- gtk_container_add(GTK_CONTAINER(scroll), GTK_WIDGET(gui->webview));
- gtk_container_add(GTK_CONTAINER(gui->eventbox), GTK_WIDGET(gui->statusbar.box));
- gtk_container_add(GTK_CONTAINER(gui->window), GTK_WIDGET(gui->pane));
-#ifdef HAS_GTK3
- gtk_widget_set_halign(gui->statusbar.mode, GTK_ALIGN_START);
- gtk_widget_set_halign(gui->statusbar.left, GTK_ALIGN_START);
-#else
- gtk_misc_set_alignment(GTK_MISC(gui->statusbar.mode), 0.0, 0.0);
- gtk_misc_set_alignment(GTK_MISC(gui->statusbar.left), 0.0, 0.0);
-#endif
- gtk_label_set_ellipsize(GTK_LABEL(gui->statusbar.left), PANGO_ELLIPSIZE_MIDDLE);
- gtk_box_pack_start(gui->statusbar.box, gui->statusbar.mode, false, true, 0);
- gtk_box_pack_start(gui->statusbar.box, gui->statusbar.left, true, true, 2);
- gtk_box_pack_start(gui->statusbar.box, gui->statusbar.cmd, false, false, 0);
- gtk_box_pack_start(gui->statusbar.box, gui->statusbar.right, false, false, 2);
-
- gtk_box_pack_start(gui->box, scroll, true, true, 0);
- gtk_box_pack_start(gui->box, gui->eventbox, false, false, 0);
-
-#ifdef HAS_GTK3
- /* use a scrolled window to hide overflowing text in inputbox like GTK2 */
- GtkWidget *inputscroll = gtk_scrolled_window_new(NULL, NULL);
- gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(inputscroll), GTK_POLICY_AUTOMATIC, GTK_POLICY_NEVER);
- gtk_container_add(GTK_CONTAINER(inputscroll), gui->input);
-
- gtk_box_pack_end(gui->box, inputscroll, false, false, 0);
-#else
- gtk_box_pack_end(gui->box, gui->input, false, false, 0);
-#endif
+ completion_init(c);
+ map_init(c);
- /* initialize the modes */
- vb_add_mode('n', normal_enter, normal_leave, normal_keypress, NULL);
- vb_add_mode('c', ex_enter, ex_leave, ex_keypress, ex_input_changed);
- vb_add_mode('i', input_enter, input_leave, input_keypress, NULL);
- vb_add_mode('p', pass_enter, pass_leave, pass_keypress, NULL);
-
- /* initialize the marks with empty values */
- marks_clear();
-
- init_files();
- session_init();
- setting_init();
- register_init();
-#ifdef FEATURE_AUTOCMD
- autocmd_init();
-#endif
- map_init();
+ g_object_connect(
+ G_OBJECT(c->window),
+ "signal::destroy", G_CALLBACK(on_window_destroy), c,
+ "signal::key-press-event", G_CALLBACK(on_map_keypress), c,
+ NULL);
+
+ /* statusbar */
+ c->statusbar.box = GTK_BOX(gtk_box_new(GTK_ORIENTATION_HORIZONTAL, 0));
+ c->statusbar.mode = gtk_label_new(NULL);
+ c->statusbar.left = gtk_label_new(NULL);
+ c->statusbar.right = gtk_label_new(NULL);
+ c->statusbar.cmd = gtk_label_new(NULL);
+ gtk_widget_set_name(GTK_WIDGET(c->statusbar.box), "statusbar");
+ gtk_label_set_ellipsize(GTK_LABEL(c->statusbar.left), PANGO_ELLIPSIZE_MIDDLE);
+ gtk_widget_set_halign(c->statusbar.left, GTK_ALIGN_START);
+ gtk_widget_set_halign(c->statusbar.mode, GTK_ALIGN_START);
+
+ gtk_box_pack_start(c->statusbar.box, c->statusbar.mode, FALSE, TRUE, 0);
+ gtk_box_pack_start(c->statusbar.box, c->statusbar.left, TRUE, TRUE, 2);
+ gtk_box_pack_start(c->statusbar.box, c->statusbar.cmd, FALSE, FALSE, 0);
+ gtk_box_pack_start(c->statusbar.box, c->statusbar.right, FALSE, FALSE, 2);
+
+ /* webview */
+ c->webview = webview_new(c, webview);
+ c->page_id = webkit_web_view_get_page_id(c->webview);
+
+ /* inputbox */
+ c->input = gtk_text_view_new();
+ gtk_widget_set_name(c->input, "input");
+ c->buffer = gtk_text_view_get_buffer(GTK_TEXT_VIEW(c->input));
+ /* Make sure the user can see the typed text. */
+ gtk_text_view_set_wrap_mode(GTK_TEXT_VIEW(c->input), GTK_WRAP_WORD_CHAR);
+
+ /* pack the parts together */
+ box = gtk_box_new(GTK_ORIENTATION_VERTICAL, 0);
+ gtk_container_add(GTK_CONTAINER(c->window), box);
+ gtk_box_pack_start(GTK_BOX(box), GTK_WIDGET(c->webview), TRUE, TRUE, 0);
+ gtk_box_pack_start(GTK_BOX(box), GTK_WIDGET(c->statusbar.box), FALSE, FALSE, 0);
+ gtk_box_pack_end(GTK_BOX(box), GTK_WIDGET(c->input), FALSE, FALSE, 0);
+
+ /* Set the default style for statusbar and inputbox. */
+ GtkCssProvider* provider = gtk_css_provider_get_default();
+ gtk_css_provider_load_from_data(provider, GUI_STYLE, -1, NULL);
+ gtk_style_context_add_provider(gtk_widget_get_style_context(GTK_WIDGET(c->statusbar.box)),
+ GTK_STYLE_PROVIDER(provider),
+ GTK_STYLE_PROVIDER_PRIORITY_APPLICATION);
+ gtk_style_context_add_provider(gtk_widget_get_style_context(c->input),
+ GTK_STYLE_PROVIDER(provider),
+ GTK_STYLE_PROVIDER_PRIORITY_APPLICATION);
+
+ /* set the x window id to env */
+ g_setenv("VIMB_XID", xid, TRUE);
+ g_free(xid);
- setup_signals();
+ /* initialize the settings */
+ setting_init(c);
- /* enter normal mode */
- vb_enter('n');
+ /* start client in normal mode */
+ vb_enter(c, 'n');
- /* make sure the main window and all its contents are visible */
- gtk_widget_show_all(gui->window);
+ gtk_widget_show_all(c->window);
- /* read the config file */
- ex_run_file(vb.files[FILES_CONFIG]);
+ /* Prepend the new client to the queue of clients. */
+ c->next = vb.clients;
+ vb.clients = c;
- /* initially apply input style */
- vb_update_input_style();
+ return c;
+}
- if (vb.config.kioskmode) {
- WebKitWebSettings *setting = webkit_web_view_get_settings(gui->webview);
+/**
+ * Callback that clear the input box after a timeout if this was set on
+ * input_print.
+ */
+static gboolean input_clear(Client *c)
+{
+ input_print(c, FALSE, MSG_NORMAL, FALSE, "");
- /* hide input box - to not create it would be better, but this needs a
- * lot of changes in the code where the input is used */
- gtk_widget_hide(vb.gui.input);
+ return FALSE;
+}
- /* disable context menu */
- g_object_set(G_OBJECT(setting), "enable-default-context-menu", false, NULL);
+/**
+ * Print a message to the input box.
+ *
+ * @force: If TRUE the message is also written when the inputbox is already
+ * focused, might be the case when the user types text into it.
+ * @type: Type of message normal or error
+ * @hide: If TRUE the inputbox is cleared after a short timeout.
+ * @message: The message to print.
+ */
+static void input_print(Client *c, gboolean force, MessageType type,
+ gboolean hide, const char *message)
+{
+ /* don't print message if the input is focussed */
+ if (!force && gtk_widget_is_focus(GTK_WIDGET(c->input))) {
+ return;
}
- vb.config.default_zoom = 1.0;
-
-#ifdef FEATURE_HIGH_DPI
- /* fix for high dpi displays */
- GdkScreen *screen = gdk_window_get_screen(gtk_widget_get_window(vb.gui.window));
- gdouble dpi = gdk_screen_get_resolution(screen);
- if (dpi != -1) {
- WebKitWebSettings *setting = webkit_web_view_get_settings(gui->webview);
- webkit_web_view_set_full_content_zoom(gui->webview, true);
- g_object_set(G_OBJECT(setting), "enforce-96-dpi", true, NULL);
-
- /* calculate the zoom level based on 96 dpi */
- vb.config.default_zoom = dpi/96;
-
- webkit_web_view_set_zoom_level(gui->webview, vb.config.default_zoom);
+ /* apply input style only if the message type was changed */
+ if (type != c->state.input_type) {
+ c->state.input_type = type;
+ }
+ vb_input_set_text(c, message);
+ if (hide) {
+ /* add timeout function */
+ c->state.input_timer = g_timeout_add_seconds(MESSAGE_TIMEOUT, (GSourceFunc)input_clear, c);
+ } else if (c->state.input_timer > 0) {
+ /* If there is already a timeout function but the input box content is
+ * changed - remove the timeout. Seems the user started another
+ * command or typed into inputbox. */
+ g_source_remove(c->state.input_timer);
+ c->state.input_timer = 0;
}
-#endif
}
-static void marks_clear(void)
+/**
+ * Reinitializes or clears the set page marks.
+ */
+static void marks_clear(Client *c)
{
int i;
/* init empty marks array */
- for (i = 0; i < VB_MARK_SIZE; i++) {
- vb.state.marks[i] = -1;
+ for (i = 0; i < MARK_SIZE; i++) {
+ c->state.marks[i] = -1;
}
}
-static void setup_signals()
+/**
+ * Free the memory of given mode. This is used as destroy function of the
+ * modes hashmap.
+ */
+static void mode_free(Mode *mode)
{
- /* Set up callbacks so that if either the main window or the browser
- * instance is closed, the program will exit */
- g_signal_connect(vb.gui.window, "destroy", G_CALLBACK(destroy_window_cb), NULL);
- g_object_connect(
- G_OBJECT(vb.gui.webview),
-#if WEBKIT_CHECK_VERSION(1, 10, 0)
- "signal::context-menu", G_CALLBACK(context_menu_cb), NULL,
-#else
- "signal::populate-popup", G_CALLBACK(context_menu_cb), NULL,
-#endif
- "signal::notify::uri", G_CALLBACK(uri_change_cb), NULL,
- "signal::notify::progress", G_CALLBACK(webview_progress_cb), NULL,
- "signal::notify::load-status", G_CALLBACK(webview_load_status_cb), NULL,
- "signal::button-release-event", G_CALLBACK(button_relase_cb), NULL,
- "signal::new-window-policy-decision-requested", G_CALLBACK(new_window_policy_cb), NULL,
- "signal::create-web-view", G_CALLBACK(create_web_view_cb), NULL,
- "signal::hovering-over-link", G_CALLBACK(hover_link_cb), NULL,
- "signal::title-changed", G_CALLBACK(title_changed_cb), NULL,
- "signal::mime-type-policy-decision-requested", G_CALLBACK(mimetype_decision_cb), NULL,
- "signal::download-requested", G_CALLBACK(vb_download), NULL,
- "signal::should-show-delete-interface-for-element", G_CALLBACK(gtk_false), NULL,
- "signal::resource-request-starting", G_CALLBACK(webview_request_starting_cb), NULL,
- "signal::navigation-policy-decision-requested", G_CALLBACK(navigation_decision_requested_cb), NULL,
- "signal::onload-event", G_CALLBACK(onload_event_cb), NULL,
- NULL
- );
- g_signal_connect(vb.gui.window, "focus-in-event", G_CALLBACK(focus_in_event_cb), NULL);
- g_signal_connect(vb.gui.window, "focus-out-event", G_CALLBACK(focus_out_event_cb), NULL);
-#ifdef FEATURE_ARH
- g_signal_connect(vb.session, "request-queued", G_CALLBACK(session_request_queued_cb), NULL);
-#endif
-
-#ifdef FEATURE_NO_SCROLLBARS
- WebKitWebFrame *frame = webkit_web_view_get_main_frame(vb.gui.webview);
- g_signal_connect(G_OBJECT(frame), "scrollbars-policy-changed", G_CALLBACK(gtk_true), NULL);
-#endif
-
- if (!vb.config.kioskmode) {
- g_signal_connect(
- G_OBJECT(vb.gui.window), "key-press-event", G_CALLBACK(map_keypress), NULL
- );
- g_signal_connect(
- G_OBJECT(vb.gui.input), "focus-in-event", G_CALLBACK(input_focus_in_cb), NULL
- );
-
- /* inspector */
- g_object_connect(
- G_OBJECT(vb.gui.inspector),
- "signal::inspect-web-view", G_CALLBACK(inspector_new), NULL,
- "signal::show-window", G_CALLBACK(inspector_show), NULL,
- "signal::close-window", G_CALLBACK(inspector_close), NULL,
- "signal::finished", G_CALLBACK(inspector_finished), NULL,
- NULL
- );
- }
- /* There is no inputbox in kioskmode - but the contents may be changed in
- * case vimb is controlled via socket. To track inputbox changes is
- * required for the hinting to work. */
- g_signal_connect(G_OBJECT(vb.gui.buffer), "changed", G_CALLBACK(buffer_changed_cb), NULL);
-
- /* webview adjustment */
- g_signal_connect(G_OBJECT(vb.gui.adjust_v), "value-changed", G_CALLBACK(scroll_cb), NULL);
+ g_slice_free(Mode, mode);
}
-static void init_files(void)
+/**
+ * Set the style of the statusbar.
+ */
+static void set_statusbar_style(Client *c, StatusType type)
{
- char *path = util_get_config_dir(vb.config.profile);
+ GtkStyleContext *ctx;
+ /* Do nothing if the new to set style is the same as the current. */
+ if (type == c->state.status_type) {
+ return;
+ }
- if (vb.config.file) {
- char *rp = realpath(vb.config.file, NULL);
- vb.files[FILES_CONFIG] = g_strdup(rp);
- free(rp);
+ ctx = gtk_widget_get_style_context(GTK_WIDGET(c->statusbar.box));
+
+ if (type == STATUS_SSL_VALID) {
+ gtk_style_context_remove_class(ctx, "unsecure");
+ gtk_style_context_add_class(ctx, "secure");
+ } else if (type == STATUS_SSL_INVALID) {
+ gtk_style_context_remove_class(ctx, "secure");
+ gtk_style_context_add_class(ctx, "unsecure");
} else {
- vb.files[FILES_CONFIG] = g_build_filename(path, "config", NULL);
- util_create_file_if_not_exists(vb.files[FILES_CONFIG]);
+ gtk_style_context_remove_class(ctx, "secure");
+ gtk_style_context_remove_class(ctx, "unsecure");
}
+ c->state.status_type = type;
+}
-#ifdef FEATURE_COOKIE
- vb.files[FILES_COOKIE] = g_build_filename(path, "cookies", NULL);
- util_create_file_if_not_exists(vb.files[FILES_COOKIE]);
-#endif
+/**
+ * Update the window title of the main window.
+ */
+static void set_title(Client *c, const char *title)
+{
+ gtk_window_set_title(GTK_WINDOW(c->window), title);
+}
- vb.files[FILES_CLOSED] = g_build_filename(path, "closed", NULL);
- util_create_file_if_not_exists(vb.files[FILES_CLOSED]);
+/**
+ * Spawns a new browser instance for given uri.
+ *
+ * @uri: URI used for the new instance.
+ * @embed: If FALSE, the new instance is not embedded, independent from
+ * current set -e option.
+ */
+static void spawn_new_instance(const char *uri, gboolean embed)
+{
+ guint i = 0;
+ char xid[64];
+ char *cmd[5];
- vb.files[FILES_HISTORY] = g_build_filename(path, "history", NULL);
- util_create_file_if_not_exists(vb.files[FILES_HISTORY]);
+ cmd[i++] = vb.argv0;
- vb.files[FILES_COMMAND] = g_build_filename(path, "command", NULL);
- util_create_file_if_not_exists(vb.files[FILES_COMMAND]);
+ if (vb.embed && embed) {
+ cmd[i++] = "-e";
+ snprintf(xid, LENGTH(xid), "%d", (int)vb.embed);
+ cmd[i++] = xid;
+ }
+ cmd[i++] = (char*)uri;
+ cmd[i++] = NULL;
- vb.files[FILES_SEARCH] = g_build_filename(path, "search", NULL);
- util_create_file_if_not_exists(vb.files[FILES_SEARCH]);
+ /* spawn a new browser instance */
+ g_spawn_async(NULL, cmd, NULL, G_SPAWN_SEARCH_PATH, NULL, NULL, NULL, NULL);
+}
- vb.files[FILES_BOOKMARK] = g_build_filename(path, "bookmark", NULL);
- util_create_file_if_not_exists(vb.files[FILES_BOOKMARK]);
+/**
+ * Callback for the web contexts initialize-web-extensions signal.
+ */
+static void on_webctx_init_web_extension(WebKitWebContext *webctx, gpointer data)
+{
+ char *name;
+ static guint ext_count = 0;
+ GVariant *vdata;
-#ifdef FEATURE_QUEUE
- vb.files[FILES_QUEUE] = g_build_filename(path, "queue", NULL);
- util_create_file_if_not_exists(vb.files[FILES_QUEUE]);
-#endif
-#ifdef FEATURE_HSTS
- vb.files[FILES_HSTS] = g_build_filename(path, "hsts", NULL);
- util_create_file_if_not_exists(vb.files[FILES_HSTS]);
-#endif
+ /* Setup the extension directory. */
+ webkit_web_context_set_web_extensions_directory(webctx, EXTPREFIX);
- vb.files[FILES_SCRIPT] = g_build_filename(path, "scripts.js", NULL);
+ name = g_strdup_printf("%u-%u", getpid(), ++ext_count);
+ ext_proxy_init(name);
- vb.files[FILES_USER_STYLE] = g_build_filename(path, "style.css", NULL);
+ vdata = g_variant_new("(s)", name);
+ webkit_web_context_set_web_extensions_initialization_user_data(webctx, vdata);
- g_free(path);
+ g_free(name);
}
-static void session_init(void)
+/**
+ * Callback for the webview close signal.
+ */
+static void on_webview_close(WebKitWebView *webview, Client *c)
{
- /* init soup session */
- vb.session = webkit_get_default_session();
- g_object_set(vb.session, "max-conns", SETTING_MAX_CONNS , NULL);
- g_object_set(vb.session, "max-conns-per-host", SETTING_MAX_CONNS_PER_HOST, NULL);
- g_object_set(vb.session, "accept-language-auto", true, NULL);
-
-#ifdef FEATURE_COOKIE
- SoupCookieJar *cookie = cookiejar_new(vb.files[FILES_COOKIE], false);
- soup_session_add_feature(vb.session, SOUP_SESSION_FEATURE(cookie));
- g_object_unref(cookie);
-#endif
-#ifdef FEATURE_HSTS
- /* create only the session feature - the feature is added in setting.c
- * when the setting hsts=on */
- vb.config.hsts_provider = hsts_provider_new();
-#endif
-#ifdef FEATURE_SOUP_CACHE
- /* setup the soup cache but without setting the cache size - this is done in setting.c */
- char *cache_dir = util_get_cache_dir(vb.config.profile);
- vb.config.soup_cache = soup_cache_new(cache_dir, SOUP_CACHE_SINGLE_USER);
- soup_session_add_feature(vb.session, SOUP_SESSION_FEATURE(vb.config.soup_cache));
- soup_cache_load(vb.config.soup_cache);
- g_free(cache_dir);
-#endif
+ client_destroy(c);
}
-static void session_cleanup(void)
+/**
+ * Callback for the webview create signal.
+ * This creates a new client - with it's own window with a related webview.
+ */
+static WebKitWebView *on_webview_create(WebKitWebView *webview,
+ WebKitNavigationAction *navact, Client *c)
{
-#ifdef FEATURE_HSTS
- /* remove feature from session and unref the feature to make sure the
- * feature is finalized */
- g_object_unref(vb.config.hsts_provider);
- soup_session_remove_feature_by_type(vb.session, HSTS_TYPE_PROVIDER);
-#endif
-#ifdef FEATURE_SOUP_CACHE
- /* commit all cache writes */
- soup_cache_flush(vb.config.soup_cache);
- /* make sure that the cache will be kept on next browser start */
- soup_cache_dump(vb.config.soup_cache);
-#endif
-}
+ Client *new = client_new(webview);
-static void register_init(void)
-{
- memset(vb.state.reg, 0, sizeof(char*));
+ return new->webview;
}
-void vb_register_add(char buf, const char *value)
-{
- char *mark;
- int idx;
-
- if (!vb.state.enable_register || !buf) {
- return;
- }
+/**
+ * Callback for the webview decide-policy signal.
+ * Checks the reasons for some navigation actions and decides if the action is
+ * allowed, or should go into a new instance of vimb.
+ */
+static gboolean on_webview_decide_policy(WebKitWebView *webview,
+ WebKitPolicyDecision *dec, WebKitPolicyDecisionType type, Client *c)
+{
+ guint status;
+ WebKitNavigationAction *a;
+ WebKitURIRequest *req;
+ WebKitURIResponse *res;
+
+ switch (type) {
+ case WEBKIT_POLICY_DECISION_TYPE_NAVIGATION_ACTION:
+ a = webkit_navigation_policy_decision_get_navigation_action(WEBKIT_NAVIGATION_POLICY_DECISION(dec));
+ req = webkit_navigation_action_get_request(a);
+
+ if (webkit_navigation_action_get_navigation_type(a) == WEBKIT_NAVIGATION_TYPE_LINK_CLICKED) {
+ if (webkit_navigation_action_get_mouse_button(a) == 2
+ || (webkit_navigation_action_get_mouse_button(a) == 1
+ && webkit_navigation_action_get_modifiers(a) & GDK_CONTROL_MASK)) {
+ webkit_policy_decision_ignore(dec);
+ spawn_new_instance(webkit_uri_request_get_uri(req), TRUE);
+ return TRUE;
+ }
+ }
+ return FALSE;
- /* make sure the mark is a valid mark char */
- if ((mark = strchr(VB_REG_CHARS, buf))) {
- /* get the index of the mark char */
- idx = mark - VB_REG_CHARS;
+ case WEBKIT_POLICY_DECISION_TYPE_NEW_WINDOW_ACTION:
+ a = webkit_navigation_policy_decision_get_navigation_action(WEBKIT_NAVIGATION_POLICY_DECISION(dec));
+ req = webkit_navigation_action_get_request(a);
- OVERWRITE_STRING(vb.state.reg[idx], value);
- }
-}
+ /* Ignore opening new window if this was started without user gesture. */
+ if (!webkit_navigation_action_is_user_gesture(a)) {
+ webkit_policy_decision_ignore(dec);
+ return TRUE;
+ }
-const char *vb_register_get(char buf)
-{
- char *mark;
- int idx;
+ if (webkit_navigation_action_get_navigation_type(a) == WEBKIT_NAVIGATION_TYPE_LINK_CLICKED) {
+ webkit_policy_decision_ignore(dec);
+ /* This is triggered on link click for links with *
+ * target="_blank". Maybe it should be configurable if the
+ * page is opened as tabe or a new instance. */
+ spawn_new_instance(webkit_uri_request_get_uri(req), TRUE);
+ return TRUE;
+ }
+ return FALSE;
- /* make sure the mark is a valid mark char */
- if ((mark = strchr(VB_REG_CHARS, buf))) {
- /* get the index of the mark char */
- idx = mark - VB_REG_CHARS;
+ case WEBKIT_POLICY_DECISION_TYPE_RESPONSE:
+ req = webkit_response_policy_decision_get_request(WEBKIT_RESPONSE_POLICY_DECISION(dec));
+ res = webkit_response_policy_decision_get_response(WEBKIT_RESPONSE_POLICY_DECISION(dec));
+ status = webkit_uri_response_get_status_code(res);
- return vb.state.reg[idx];
- }
+ if (!webkit_response_policy_decision_is_mime_type_supported(WEBKIT_RESPONSE_POLICY_DECISION(dec))
+ && (SOUP_STATUS_IS_SUCCESSFUL(status) || status == SOUP_STATUS_NONE)) {
- return NULL;
-}
+ webkit_policy_decision_download(dec);
-static void register_cleanup(void)
-{
- int i;
- for (i = 0; i < VB_REG_SIZE; i++) {
- if (vb.state.reg[i]) {
- g_free(vb.state.reg[i]);
- }
- }
-}
+ return TRUE;
+ }
+ return FALSE;
-static gboolean button_relase_cb(WebKitWebView *webview, GdkEventButton *event)
-{
- /* let webkit handle the click - for example on a link */
- gboolean nopropagate = false;
- WebKitHitTestResultContext context;
-
- WebKitHitTestResult *result = webkit_web_view_get_hit_test_result(webview, event);
-
- g_object_get(result, "context", &context, NULL);
- /* ctrl click or middle mouse click onto link */
- if (context & WEBKIT_HIT_TEST_RESULT_CONTEXT_LINK
- && (event->button == 2 || (event->button == 1 && event->state & GDK_CONTROL_MASK))
- ) {
- Arg a = {VB_TARGET_NEW};
- g_object_get(result, "link-uri", &a.s, NULL);
- vb_load_uri(&a);
-
- nopropagate = true;
+ default:
+ return FALSE;
}
- g_object_unref(result);
-
- return nopropagate;
}
-static gboolean new_window_policy_cb(
- WebKitWebView *view, WebKitWebFrame *frame, WebKitNetworkRequest *request,
- WebKitWebNavigationAction *navig, WebKitWebPolicyDecision *policy)
+static void on_webview_load_changed(WebKitWebView *webview,
+ WebKitLoadEvent event, Client *c)
{
- if (webkit_web_navigation_action_get_reason(navig) == WEBKIT_WEB_NAVIGATION_REASON_LINK_CLICKED) {
- webkit_web_policy_decision_ignore(policy);
- /* open in a new window */
- Arg a = {VB_TARGET_NEW, (char*)webkit_network_request_get_uri(request)};
- vb_load_uri(&a);
- return true;
- }
- return false;
-}
+ GTlsCertificateFlags tlsflags;
+ const char *uri;
-static WebKitWebView *create_web_view_cb(WebKitWebView *view, WebKitWebFrame *frame)
-{
- WebKitWebView *new = WEBKIT_WEB_VIEW(webkit_web_view_new());
+ switch (event) {
+ case WEBKIT_LOAD_STARTED:
+ /* update load progress in statusbar */
+ c->state.progress = 0;
+ vb_statusbar_update(c);
+ set_title(c, webkit_web_view_get_uri(webview));
+ break;
- /* wait until the new webview receives its new URI */
- g_signal_connect(new, "navigation-policy-decision-requested", G_CALLBACK(create_web_view_received_uri_cb), NULL);
+ case WEBKIT_LOAD_REDIRECTED:
+ break;
- return new;
-}
+ case WEBKIT_LOAD_COMMITTED:
+ uri = webkit_web_view_get_uri(webview);
+ /* save the current URI in register % */
+ vb_register_add(c, '%', uri);
+ /* check if tls is on and the page is trusted */
+ if (g_str_has_prefix(uri, "https://")) {
+ if (webkit_web_view_get_tls_info(webview, NULL, &tlsflags) && tlsflags) {
+ set_statusbar_style(c, STATUS_SSL_INVALID);
+ } else {
+ set_statusbar_style(c, STATUS_SSL_VALID);
+ }
+ } else {
+ set_statusbar_style(c, STATUS_NORMAL);
+ }
-static gboolean create_web_view_received_uri_cb(WebKitWebView *view,
- WebKitWebFrame *frame, WebKitNetworkRequest *request,
- WebKitWebNavigationAction *action, WebKitWebPolicyDecision *policy,
- gpointer data)
-{
- Arg a = {VB_TARGET_NEW, (char*)webkit_network_request_get_uri(request)};
- vb_load_uri(&a);
+ /* clear possible set marks */
+ marks_clear(c);
- /* destroy temporary webview */
- gtk_widget_destroy(GTK_WIDGET(view));
+ break;
- /* mark that we handled the signal */
- return true;
+ case WEBKIT_LOAD_FINISHED:
+ c->state.progress = 100;
+ break;
+ }
}
-static gboolean navigation_decision_requested_cb(WebKitWebView *view,
- WebKitWebFrame *frame, WebKitNetworkRequest *request,
- WebKitWebNavigationAction *action, WebKitWebPolicyDecision *policy,
- gpointer data)
+/**
+ * Callback for the webview mouse-target-changed signal.
+ * This is used to print the uri too statusbar if the user hovers over links
+ * or images.
+ */
+static void on_webview_mouse_target_changed(WebKitWebView *webview,
+ WebKitHitTestResult *result, guint modifiers, Client *c)
{
-#ifdef FEATURE_HSTS
- char *uri;
- SoupMessage *msg = webkit_network_request_get_message(request);
-
- /* manually reload the page for HSTS only when it occurs in
- * the main-frame. the others cases are covered by requeueing. */
- if (webkit_web_view_get_main_frame(view) == frame) {
- uri = hsts_get_changed_uri(vb.session, msg);
- if (uri) {
- webkit_web_frame_load_uri(frame, uri);
- webkit_web_policy_decision_ignore(policy);
-
- g_free(uri);
- /* mark the request as handled */
- return true;
- }
- }
-#endif
-
- /* try to find a protocol handler to open the uri */
- if (handle_uri(webkit_network_request_get_uri(request))) {
- webkit_web_policy_decision_ignore(policy);
+ char *msg;
+ const char *uri;
- return true;
+ /* Save the hitTestResult to have this later available for events that
+ * don't support this. */
+ if (c->state.hit_test_result) {
+ g_object_unref(c->state.hit_test_result);
+ }
+ c->state.hit_test_result = g_object_ref(result);
+
+ if (webkit_hit_test_result_context_is_link(result)) {
+ uri = webkit_hit_test_result_get_link_uri(result);
+ msg = g_strconcat("Link: ", uri, NULL);
+ gtk_label_set_text(GTK_LABEL(c->statusbar.left), msg);
+ g_free(msg);
+ } else if (webkit_hit_test_result_context_is_image(result)) {
+ uri = webkit_hit_test_result_get_image_uri(result);
+ msg = g_strconcat("Image: ", uri, NULL);
+ gtk_label_set_text(GTK_LABEL(c->statusbar.left), msg);
+ g_free(msg);
+ } else {
+ /* No link under cursor - show the current URI. */
+ update_urlbar(c);
}
- return false;
}
-static void onload_event_cb(WebKitWebView *view, WebKitWebFrame *frame,
- gpointer user_data)
+/**
+ * Called on webviews notify::estimated-load-progress event. This writes the
+ * esitamted load progress in percent in a variable and updates the statusbar
+ * to make the changes visible.
+ */
+static void on_webview_notify_estimated_load_progress(WebKitWebView *webview,
+ GParamSpec *spec, Client *c)
{
- Document *doc = webkit_web_frame_get_dom_document(frame);
- dom_check_auto_insert(doc);
- vb.state.done_loading_page = true;
+ c->state.progress = webkit_web_view_get_estimated_load_progress(webview) * 100;
+ vb_statusbar_update(c);
}
-static void hover_link_cb(WebKitWebView *webview, const char *title, const char *link)
+/**
+ * Callback for the webview notify::title signal.
+ * Changes the window title according to the title of the current page.
+ */
+static void on_webview_notify_title(WebKitWebView *webview, GParamSpec *pspec, Client *c)
{
- char *message;
- if (link) {
- /* save the uri to have this if the user want's to copy the link
- * location via context menu */
- OVERWRITE_STRING(vb.state.linkhover, link);
-
- message = g_strconcat("Link: ", link, NULL);
- gtk_label_set_text(GTK_LABEL(vb.gui.statusbar.left), message);
- g_free(message);
- } else if (vb.state.uri) {
- /* Use previous url in case of hover out of a link. */
- vb_update_urlbar(vb.state.uri);
- } else {
- /* If there is no previous uri use the current uri from webview. */
- set_uri(webkit_web_view_get_uri(webview));
- }
+ set_title(c, webkit_web_view_get_title(webview));
}
-static void title_changed_cb(WebKitWebView *webview, WebKitWebFrame *frame, const char *title)
+/**
+ * Callback for the webview notify::uri signal.
+ * Changes the current uri shown on left of statusbar.
+ */
+static void on_webview_notify_uri(WebKitWebView *webview, GParamSpec *pspec, Client *c)
{
- set_title(title);
+ OVERWRITE_STRING(c->state.uri, webkit_web_view_get_uri(c->webview));
+ update_urlbar(c);
+ g_setenv("VIMB_URI", c->state.uri, TRUE);
}
-static void update_title(void)
+/**
+ * Callback for the webview ready-to-show signal.
+ * Show the webview only if it's ready to be shown.
+ */
+static void on_webview_ready_to_show(WebKitWebView *webview, Client *c)
{
-#ifdef FEATURE_TITLE_PROGRESS
- /* show load status of page or the downloads */
- if (vb.state.progress != 100) {
- char *title = g_strdup_printf(
- "[%i%%] %s",
- vb.state.progress,
- vb.state.title ? vb.state.title : ""
- );
- gtk_window_set_title(GTK_WINDOW(vb.gui.window), title);
- g_free(title);
- return;
- }
-#endif
- if (vb.state.title) {
- gtk_window_set_title(GTK_WINDOW(vb.gui.window), vb.state.title);
- }
+ gtk_widget_show(GTK_WIDGET(webview));
}
-static void set_uri(const char *uri)
+/**
+ * Callback for the webview web-process-crashed signal.
+ */
+static gboolean on_webview_web_process_crashed(WebKitWebView *webview, Client *c)
{
- OVERWRITE_STRING(vb.state.uri, uri);
- g_setenv("VIMB_URI", uri, true);
- vb_update_urlbar(uri);
+ g_warning("Webview Crashed on %s", webkit_web_view_get_uri(webview));
+ return TRUE;
}
-static void set_title(const char *title)
+/**
+ * Callback for the window destroy signal.
+ * Destroys the client that is associated to the window.
+ */
+static void on_window_destroy(GtkWidget *window, Client *c)
{
- OVERWRITE_STRING(vb.state.title, title);
- update_title();
- g_setenv("VIMB_TITLE", title ? title : "", true);
+ client_destroy(c);
}
-static gboolean mimetype_decision_cb(WebKitWebView *webview,
- WebKitWebFrame *frame, WebKitNetworkRequest *request, char *mime_type,
- WebKitWebPolicyDecision *decision)
+/**
+ * Callback for to quit given client as idle event source.
+ */
+static gboolean quit(Client *c)
{
- SoupMessage *msg;
- /* don't start download if request failed or stopped by proxy or can be
- * displayed in the webview */
- if (!mime_type || *mime_type == '\0'
- || webkit_web_view_can_show_mime_type(webview, mime_type)) {
+ /* Destroy the main window to tirgger the destruction of the client. */
+ gtk_widget_destroy(c->window);
- return false;
- }
-
- /* Don't start a download when the response has no 2xx status code. Or the
- * message was not sent before - this seems to be the case when the server
- * responds with a Accept-Ranges header. */
- msg = webkit_network_request_get_message(request);
- if (SOUP_STATUS_IS_SUCCESSFUL(msg->status_code)
- || msg->status_code == SOUP_STATUS_NONE
- ) {
- webkit_web_policy_decision_download(decision);
- return true;
- }
- return false;
+ /* Remove this from the list of event sources. */
+ return FALSE;
}
-gboolean vb_download(WebKitWebView *view, WebKitDownload *download, const char *path)
+/**
+ * Free the register contents memory.
+ */
+static void register_cleanup(Client *c)
{
- char *file, *dir;
- const char *download_cmd = GET_CHAR("download-command");
- gboolean use_external = GET_BOOL("download-use-external");
-
- /* prepare the path to save the download */
- if (path) {
- file = util_build_path(path, vb.config.download_dir);
-
- /* if file is an directory append a file name */
- if (g_file_test(file, (G_FILE_TEST_IS_DIR))) {
- dir = file;
- file = g_build_filename(dir, PROJECT "-download", NULL);
- g_free(dir);
- }
- } else {
- /* if there was no path given where to download the file, used
- * suggested file name or a static one */
- path = webkit_download_get_suggested_filename(download);
- if (!path || *path == '\0') {
- path = PROJECT "-download";
+ int i;
+ for (i = 0; i < REG_SIZE; i++) {
+ if (c->state.reg[i]) {
+ g_free(c->state.reg[i]);
}
- file = util_build_path(path, vb.config.download_dir);
- }
-
-#ifdef FEATURE_AUTOCMD
- autocmd_run(AU_DOWNLOAD_START, webkit_download_get_uri(download), NULL);
-#endif
- if (use_external && *download_cmd) {
- /* run download with external program */
- vb_download_external(view, download, file);
- g_free(file);
-
- /* signalize that we handle the download ourself */
- return false;
- } else {
- /* use webkit download helpr to download the uri */
- vb_download_internal(view, download, file);
- g_free(file);
-
- return true;
}
}
-void vb_download_internal(WebKitWebView *view, WebKitDownload *download, const char *file)
+/**
+ * Update the contents of the url bar on the left of the statu bar according
+ * to current opened url and position in back forward history.
+ */
+static void update_urlbar(Client *c)
{
- char *uri;
- guint64 size;
- WebKitDownloadStatus status;
+#if !defined(FEATURE_HISTORY_INDICATOR)
+ /* if only the uri is shown - write it like it is on the label */
+ gtk_label_set_text(GTK_LABEL(c->statusbar.left), c->state.uri);
+#else
+ GString *str = g_string_new(c->state.uri);
- /* build the file uri from file path */
- uri = g_filename_to_uri(file, NULL, NULL);
- webkit_download_set_destination_uri(download, uri);
- g_free(uri);
+#ifdef FEATURE_HISTORY_INDICATOR
+ gboolean back, fwd;
- size = webkit_download_get_total_size(download);
- if (size > 0) {
- vb_echo(VB_MSG_NORMAL, false, "Download %s [%uB] started ...", file, size);
- } else {
- vb_echo(VB_MSG_NORMAL, false, "Download %s started ...", file);
- }
+ back = webkit_web_view_can_go_back(c->webview);
+ fwd = webkit_web_view_can_go_forward(c->webview);
- status = webkit_download_get_status(download);
- if (status == WEBKIT_DOWNLOAD_STATUS_CREATED) {
- webkit_download_start(download);
+ /* show history indicator only if there is something to show */
+ if (back || fwd) {
+ g_string_append_printf(str, " [%s]", back ? (fwd ? "-+" : "-") : "+");
}
+#endif /* FEATURE_HISTORY_INDICATOR */
- /* prepend the download to the download list */
- vb.state.downloads = g_list_prepend(vb.state.downloads, download);
-
- /* connect signal handler to check if the download is done */
- g_signal_connect(download, "notify::status", G_CALLBACK(download_progress_cp), NULL);
- g_signal_connect(download, "notify::progress", G_CALLBACK(webview_download_progress_cb), NULL);
-
- vb_update_statusbar();
+ gtk_label_set_text(GTK_LABEL(c->statusbar.left), str->str);
+ g_string_free(str, TRUE);
+#endif /* !defined(FEATURE_HISTORY_INDICATOR) */
}
-void vb_download_external(WebKitWebView *view, WebKitDownload *download, const char *file)
+#ifdef FREE_ON_QUIT
+/**
+ * Free memory of the whole application.
+ */
+static void vimb_cleanup(void)
{
- const char *user_agent = NULL, *mimetype = NULL, *download_cmd;
- char **argv, **envp;
- char *cmd;
- int argc;
- guint64 size;
- SoupMessage *msg;
- WebKitNetworkRequest *request;
- GError *error = NULL;
-
- request = webkit_download_get_network_request(download);
- msg = webkit_network_request_get_message(request);
- /* if the download is started by the :save command or hinting we get no
- * message here */
- if (msg) {
- user_agent = soup_message_headers_get_one(msg->request_headers, "User-Agent");
- mimetype = soup_message_headers_get_one(msg->request_headers, "Content-Type");
- }
-
- /* set the required download information as environment */
- envp = g_get_environ();
- envp = g_environ_setenv(envp, "VIMB_FILE", file, true);
- envp = g_environ_setenv(envp, "VIMB_USE_PROXY", GET_BOOL("proxy") ? "1" : "0", true);
-#ifdef FEATURE_COOKIE
- envp = g_environ_setenv(envp, "VIMB_COOKIES", vb.files[FILES_COOKIE], true);
-#endif
- if (mimetype) {
- envp = g_environ_setenv(envp, "VIMB_MIME_TYPE", mimetype, true);
- }
+ int i;
- if (!user_agent) {
- WebKitWebSettings *setting = webkit_web_view_get_settings(view);
- g_object_get(G_OBJECT(setting), "user-agent", &user_agent, NULL);
+ while (vb.clients) {
+ client_destroy(vb.clients);
}
- envp = g_environ_setenv(envp, "VIMB_USER_AGENT", user_agent, true);
- download_cmd = GET_CHAR("download-command");
- cmd = g_strdup_printf(download_cmd, webkit_download_get_uri(download));
- if (!g_shell_parse_argv(cmd, &argc, &argv, &error)) {
- g_warning("Could not parse download-command '%s': %s", download_cmd, error->message);
- g_error_free(error);
- g_free(cmd);
+ /* free memory of other components */
+ util_cleanup();
- return;
- }
- g_free(cmd);
-
- if (g_spawn_async(NULL, argv, envp, G_SPAWN_SEARCH_PATH, NULL, NULL, NULL, &error)) {
- size = webkit_download_get_total_size(download);
- if (size > 0) {
- vb_echo(VB_MSG_NORMAL, true, "Download of %uB started", size);
- } else {
- vb_echo(VB_MSG_NORMAL, true, "Download started");
+ for (i = 0; i < FILES_LAST; i++) {
+ if (vb.files[i]) {
+ g_free(vb.files[i]);
}
- } else {
- g_warning("%s", error->message);
- g_clear_error(&error);
- vb_echo(VB_MSG_ERROR, true, "Could not start download");
}
- g_strfreev(argv);
- g_strfreev(envp);
}
+#endif
-static void download_progress_cp(WebKitDownload *download, GParamSpec *pspec)
+/**
+ * Setup resources used on application scope.
+ */
+static void vimb_setup(void)
{
- WebKitDownloadStatus status = webkit_download_get_status(download);
+ WebKitWebContext *ctx;
+ WebKitCookieManager *cm;
+ char *path;
- if (status == WEBKIT_DOWNLOAD_STATUS_STARTED || status == WEBKIT_DOWNLOAD_STATUS_CREATED) {
- return;
- }
+ /* prepare the file pathes */
+ path = util_get_config_dir();
- const char *file = webkit_download_get_destination_uri(download);
- /* skip the file protocol for the display */
- if (!strncmp(file, "file://", 7)) {
- file += 7;
- }
- if (status != WEBKIT_DOWNLOAD_STATUS_FINISHED) {
-#ifdef FEATURE_AUTOCMD
- autocmd_run(AU_DOWNLOAD_FAILED, webkit_download_get_uri(download), NULL);
-#endif
- vb_echo(VB_MSG_ERROR, false, "Error downloading %s", file);
+ if (vb.configfile) {
+ char *rp = realpath(vb.configfile, NULL);
+ vb.files[FILES_CONFIG] = g_strdup(rp);
+ free(rp);
} else {
-#ifdef FEATURE_AUTOCMD
- autocmd_run(AU_DOWNLOAD_FINISHED, webkit_download_get_uri(download), NULL);
-#endif
- vb_echo(VB_MSG_NORMAL, false, "Download %s finished", file);
- }
+ vb.files[FILES_CONFIG] = util_get_filepath(path, "config", FALSE);
+ }
+
+ /* Setup those files that are use multiple time during runtime */
+ vb.files[FILES_CLOSED] = util_get_filepath(path, "closed", FALSE);
+ vb.files[FILES_COOKIE] = util_get_filepath(path, "cookies", FALSE);
+ vb.files[FILES_USER_STYLE] = util_get_filepath(path, "style.css", FALSE);
+ vb.files[FILES_SCRIPT] = util_get_filepath(path, "scripts.js", FALSE);
+ vb.files[FILES_HISTORY] = util_get_filepath(path, "history", FALSE);
+ vb.files[FILES_COMMAND] = util_get_filepath(path, "command", FALSE);
+ vb.files[FILES_HSTS] = util_get_filepath(path, "hsts", FALSE);
+ vb.files[FILES_BOOKMARK] = util_get_filepath(path, "bookmark", FALSE);
+ vb.files[FILES_QUEUE] = util_get_filepath(path, "queue", FALSE);
+ vb.files[FILES_SEARCH] = util_get_filepath(path, "search", FALSE);
+ g_free(path);
- /* remove the download from the list */
- vb.state.downloads = g_list_remove(vb.state.downloads, download);
+ /* Use seperate rendering processed for the webview of the clients in the
+ * current instance. This must be called as soon as possible according to
+ * the documentation. */
+ ctx = webkit_web_context_get_default();
+ webkit_web_context_set_process_model(ctx, WEBKIT_PROCESS_MODEL_MULTIPLE_SECONDARY_PROCESSES);
+ webkit_web_context_set_cache_model(ctx, WEBKIT_CACHE_MODEL_WEB_BROWSER);
- vb_update_statusbar();
-}
+ g_signal_connect(ctx, "initialize-web-extensions", G_CALLBACK(on_webctx_init_web_extension), NULL);
-static void read_from_stdin(void)
-{
- /* read content from stdin */
- GIOChannel *ch = g_io_channel_unix_new(fileno(stdin));
- gchar *buf = NULL;
- GError *err = NULL;
- gsize len;
-
- g_io_channel_read_to_end(ch, &buf, &len, &err);
- g_io_channel_unref(ch);
- if (err) {
- g_warning("Error loading from stdin: %s", err->message);
- g_error_free(err);
- } else {
- webkit_web_view_load_string(vb.gui.webview, buf, "text/html", NULL, "(stdin)");
+ /* Add cookie support only if the cookie file exists. */
+ if (vb.files[FILES_COOKIE]) {
+ cm = webkit_web_context_get_cookie_manager(ctx);
+ webkit_cookie_manager_set_persistent_storage(
+ cm,
+ vb.files[FILES_COOKIE],
+ WEBKIT_COOKIE_PERSISTENT_STORAGE_TEXT);
}
- g_free(buf);
-}
-
-#ifdef FEATURE_ARH
-static void session_request_queued_cb(SoupSession *session, SoupMessage *msg, gpointer data)
-{
- SoupURI *suri = soup_message_get_uri(msg);
- char *uri = soup_uri_to_string(suri, false);
- arh_run(vb.config.autoresponseheader, uri, msg);
+ /* TODO move to settings.c */
+ webkit_web_context_set_tls_errors_policy(ctx, TRUE ? WEBKIT_TLS_ERRORS_POLICY_FAIL : WEBKIT_TLS_ERRORS_POLICY_IGNORE);
- g_free(uri);
+ /* initialize the modes */
+ vb_mode_add('n', normal_enter, normal_leave, normal_keypress, NULL);
+ vb_mode_add('c', ex_enter, ex_leave, ex_keypress, ex_input_changed);
+ vb_mode_add('i', input_enter, input_leave, input_keypress, NULL);
+ vb_mode_add('p', pass_enter, pass_leave, pass_keypress, NULL);
}
-#endif
/**
- * Free some memory when vimb is quit.
+ * Factory to create a new webview.
+ *
+ * @webview: Relates webview or NULL. If given a related webview is
+ * generated.
*/
-static void vb_cleanup(void)
+static WebKitWebView *webview_new(Client *c, WebKitWebView *webview)
{
+ WebKitWebView *new;
+ WebKitUserContentManager *ucm;
+ WebKitUserScript *script;
+ char *js = NULL;
- completion_clean();
- map_cleanup();
- cleanup_modes();
- setting_cleanup();
- history_cleanup();
- session_cleanup();
- register_cleanup();
-#ifdef FEATURE_AUTOCMD
- autocmd_cleanup();
-#endif
-#ifdef FEATURE_ARH
- arh_free(vb.config.autoresponseheader);
-#endif
-#ifdef FEATURE_SOCKET
- io_cleanup();
-#endif
- g_free(vb.state.pid_str);
- g_free(vb.state.uri);
-
- g_slist_free_full(vb.config.cmdargs, g_free);
-
- for (int i = 0; i < FILES_LAST; i++) {
- g_free(vb.files[i]);
- vb.files[i] = NULL;
+ /* create a new webview */
+ if (webview) {
+ new = WEBKIT_WEB_VIEW(webkit_web_view_new_with_related_view(webview));
+ ucm = webkit_web_view_get_user_content_manager(webview);
+ } else {
+ ucm = webkit_user_content_manager_new();
+ new = WEBKIT_WEB_VIEW(webkit_web_view_new_with_user_content_manager(ucm));
}
-}
-static void cleanup_modes(void)
-{
- if (vb.modes) {
- g_hash_table_destroy(vb.modes);
- vb.modes = NULL;
- vb.mode = NULL;
+ g_object_connect(
+ G_OBJECT(new),
+ "signal::close", G_CALLBACK(on_webview_close), c,
+ "signal::create", G_CALLBACK(on_webview_create), c,
+ "signal::decide-policy", G_CALLBACK(on_webview_decide_policy), c,
+ "signal::load-changed", G_CALLBACK(on_webview_load_changed), c,
+ "signal::mouse-target-changed", G_CALLBACK(on_webview_mouse_target_changed), c,
+ "signal::notify::estimated-load-progress", G_CALLBACK(on_webview_notify_estimated_load_progress), c,
+ "signal::notify::title", G_CALLBACK(on_webview_notify_title), c,
+ "signal::notify::uri", G_CALLBACK(on_webview_notify_uri), c,
+ "signal::ready-to-show", G_CALLBACK(on_webview_ready_to_show), c,
+ "signal::web-process-crashed", G_CALLBACK(on_webview_web_process_crashed), c,
+ NULL
+ );
+
+ /* Inject the user script file. */
+ if (g_file_get_contents(vb.files[FILES_SCRIPT], &js, NULL, NULL)) {
+ script = webkit_user_script_new(js,
+ WEBKIT_USER_CONTENT_INJECT_ALL_FRAMES,
+ WEBKIT_USER_SCRIPT_INJECT_AT_DOCUMENT_END, NULL, NULL);
+ webkit_user_content_manager_add_script(ucm, script);
+ webkit_user_script_unref(script);
}
-}
-static void free_mode(Mode *mode)
-{
- g_slice_free(Mode, mode);
+ return new;
}
-static gboolean autocmdOptionArgFunc(const gchar *option_name, const gchar *value, gpointer data, GError **error)
+int main(int argc, char* argv[])
{
- vb.config.cmdargs = g_slist_append(vb.config.cmdargs, g_strdup(value));
- return TRUE;
-}
+ Client *c;
+ GError *err = NULL;
+ char *pidstr, *winid = NULL;
+ gboolean ver = FALSE;
-int main(int argc, char *argv[])
-{
- static char *winid = NULL;
- static gboolean ver = false;
-#ifdef FEATURE_SOCKET
- static gboolean dump = false;
-#endif
- static GError *err;
-
- static GOptionEntry opts[] = {
- {"cmd", 'C', 0, G_OPTION_ARG_CALLBACK, autocmdOptionArgFunc, "Ex command run before first page is loaded", NULL},
- {"config", 'c', 0, G_OPTION_ARG_FILENAME, &vb.config.file, "Custom configuration file", NULL},
- {"profile", 'p', 0, G_OPTION_ARG_STRING, &vb.config.profile, "Profile name", NULL},
- {"embed", 'e', 0, G_OPTION_ARG_STRING, &winid, "Reparents to window specified by xid", NULL},
-#ifdef FEATURE_SOCKET
- {"dump", 'd', 0, G_OPTION_ARG_NONE, &dump, "Dump the socket path to stdout", NULL},
- {"socket", 's', 0, G_OPTION_ARG_NONE, &vb.config.socket, "Create control socket", NULL},
-#endif
- {"kiosk", 'k', 0, G_OPTION_ARG_NONE, &vb.config.kioskmode, "Run in kiosk mode", NULL},
+ GOptionEntry opts[] = {
+ {"embed", 'e', 0, G_OPTION_ARG_STRING, &winid, "Reparents to window specified by xid", NULL},
+ {"config", 'c', 0, G_OPTION_ARG_FILENAME, &vb.configfile, "Custom configuration file", NULL},
{"version", 'v', 0, G_OPTION_ARG_NONE, &ver, "Print version", NULL},
{NULL}
};
- /* Initialize GTK+ */
+
+ /* initialize GTK+ */
if (!gtk_init_with_args(&argc, &argv, "[URI]", opts, NULL, &err)) {
- g_printerr("can't init gtk: %s\n", err->message);
+ fprintf(stderr, "can't init gtk: %s\n", err->message);
g_error_free(err);
return EXIT_FAILURE;
}
if (ver) {
- fprintf(stdout, "%s/%s\n", PROJECT, VERSION);
- return EXIT_SUCCESS;
- }
+ fprintf(stdout, "%s, version %s\n\n", PROJECT, VERSION);
+ fprintf(stdout, "Copyright © 2012 - 2016 Daniel Carl <danielcarl@gmx.de>\n");
+ fprintf(stdout, "License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>\n");
+ fprintf(stdout, "This is free software; you are free to change and redistribute it.\n");
+ fprintf(stdout, "There is NO WARRANTY, to the extent permitted by law.\n");
- /* save vimb basename */
- argv0 = argv[0];
-
- if (winid) {
- vb.embed = strtol(winid, NULL, 0);
+ return EXIT_SUCCESS;
}
- vb.state.pid_str = g_strdup_printf("%d", (int)getpid());
- g_setenv("VIMB_PID", vb.state.pid_str, true);
+ /* Save the base name for spawning new instances. */
+ vb.argv0 = argv[0];
- /* init some state variable */
- vb.state.enable_register = false;
- vb.state.uri = g_strdup("");
+ /* set the current pid in env */
+ pidstr = g_strdup_printf("%d", (int)getpid());
+ g_setenv("VIMB_PID", pidstr, TRUE);
- init_core();
+ vimb_setup();
- /* process the --cmd if this was given */
- for (GSList *l = vb.config.cmdargs; l; l = l->next) {
- ex_run_string(l->data, false);
+ if (winid) {
+ vb.embed = strtol(winid, NULL, 0);
}
- /* active the registers and writing of command history */
- vb.state.enable_register = true;
-
- /* open uri given as last argument */
+ c = client_new(NULL);
if (argc <= 1) {
- /* open configured home page if no uri was given */
- vb_load_uri(&(Arg){VB_TARGET_CURRENT, NULL});
- } else if (!strcmp(argv[argc - 1], "-")) {
- /* read from stdin if uri is - */
- read_from_stdin();
+ vb_load_uri(c, &(Arg){TARGET_CURRENT, NULL});
} else {
- vb_load_uri(&(Arg){VB_TARGET_CURRENT, argv[argc - 1]});
+ vb_load_uri(c, &(Arg){TARGET_CURRENT, argv[argc - 1]});
}
-#ifdef FEATURE_SOCKET
- /* setup the control socket - quit vimb if this failed */
- if (vb.config.socket && !io_init_socket(vb.state.pid_str)) {
- /* cleanup memory */
- vb_cleanup();
- return EXIT_FAILURE;
- }
- if (dump && vb.state.socket_path) {
- printf("%s\n", vb.state.socket_path);
- fflush(NULL);
- }
-#endif
-
- /* Run the main GTK+ event loop */
gtk_main();
-
- /* cleanup memory */
- vb_cleanup();
+#ifdef FREE_ON_QUIT
+ vimb_cleanup();
+#endif
return EXIT_SUCCESS;
}
diff --git a/src/main.h b/src/main.h
index 1bde3cd..f0816d0 100644
--- a/src/main.h
+++ b/src/main.h
@@ -20,31 +20,24 @@
#ifndef _MAIN_H
#define _MAIN_H
-#include <limits.h>
-#include <stdlib.h>
-#include <string.h>
-#include <webkit/webkit.h>
-#include <JavaScriptCore/JavaScript.h>
#include <fcntl.h>
-#include <stdio.h>
-#ifdef HAS_GTK3
-#include <gdk/gdkx.h>
#include <gtk/gtkx.h>
-#endif
-#include "config.h"
-#ifdef FEATURE_HSTS
-#include "hsts.h"
-#endif
+#include <stdio.h>
+#include <webkit2/webkit2.h>
-/* size of some I/O buffer */
-#define BUF_SIZE 512
+#include "config.h"
#define LENGTH(x) (sizeof x / sizeof x[0])
+#define OVERWRITE_STRING(t, s) {if (t) g_free(t); t = g_strdup(s);}
+#define OVERWRITE_NSTRING(t, s, l) {if (t) {g_free(t); t = NULL;} t = g_strndup(s, l);}
+#define GET_CHAR(c, n) (((Setting*)g_hash_table_lookup(c->config.settings, n))->value.s)
+#define GET_INT(c, n) (((Setting*)g_hash_table_lookup(c->config.settings, n))->value.i)
+#define GET_BOOL(c, n) (((Setting*)g_hash_table_lookup(c->config.settings, n))->value.b)
#ifdef DEBUG
#define PRINT_DEBUG(...) { \
- fprintf(stderr, "\n\033[31;1mDEBUG:\033[0m %s:%d:%s()\t", __FILE__, __LINE__, __func__); \
+ fprintf(stderr, "\n\033[31;1mDEBUG: \033[32;1m%s +%d %s()\033[0m\t", __FILE__, __LINE__, __func__); \
fprintf(stderr, __VA_ARGS__);\
}
#define TIMER_START GTimer *__timer; {__timer = g_timer_new(); g_timer_start(__timer);}
@@ -58,174 +51,88 @@
#define TIMER_END
#endif
-#define PRIMARY_CLIPBOARD() gtk_clipboard_get(GDK_SELECTION_PRIMARY)
-#define SECONDARY_CLIPBOARD() gtk_clipboard_get(GDK_NONE)
-
-#define OVERWRITE_STRING(t, s) {if (t) {g_free(t); t = NULL;} t = g_strdup(s);}
-#define OVERWRITE_NSTRING(t, s, l) {if (t) {g_free(t); t = NULL;} t = g_strndup(s, l);}
-
-#define GET_CHAR(n) (((Setting*)g_hash_table_lookup(vb.config.settings, n))->value.s)
-#define GET_INT(n) (((Setting*)g_hash_table_lookup(vb.config.settings, n))->value.i)
-#define GET_BOOL(n) (((Setting*)g_hash_table_lookup(vb.config.settings, n))->value.b)
-
-#ifdef HAS_GTK3
-#define VbColor GdkRGBA
-#define VB_COLOR_PARSE(color, string) (gdk_rgba_parse(color, string))
-#define VB_COLOR_TO_STRING(color) (gdk_rgba_to_string(color))
-#define VB_WIDGET_OVERRIDE_BACKGROUND(w, s, c)
-#define VB_WIDGET_OVERRIDE_BASE(w, s, c) (gtk_widget_override_background_color(w, s, c))
-#define VB_WIDGET_OVERRIDE_COLOR(w, s, c)
-#define VB_WIDGET_OVERRIDE_TEXT(w, s, c) (gtk_widget_override_color(w, s, c))
-#define VB_WIDGET_OVERRIDE_FONT(w, f) (gtk_widget_override_font(w, f))
-
-#define VB_GTK_STATE_NORMAL GTK_STATE_FLAG_NORMAL
-#define VB_GTK_STATE_ACTIVE GTK_STATE_FLAG_ACTIVE
-#define VB_GTK_STATE_SELECTED GTK_STATE_FLAG_SELECTED
-#define VB_WIDGET_SET_STATE(w, s) (gtk_widget_set_state_flags(w, s, true))
-
-#else
-
-#define VbColor GdkColor
-#define VB_COLOR_PARSE(color, string) (gdk_color_parse(string, color))
-#define VB_COLOR_TO_STRING(color) (gdk_color_to_string(color))
-#define VB_WIDGET_OVERRIDE_BACKGROUND(w, s, c) (gtk_widget_modify_bg(w, s, c))
-#define VB_WIDGET_OVERRIDE_BASE(w, s, c) (gtk_widget_modify_base(w, s, c))
-#define VB_WIDGET_OVERRIDE_COLOR(w, s, c) (gtk_widget_modify_fg(w, s, c))
-#define VB_WIDGET_OVERRIDE_TEXT(w, s, c) (gtk_widget_modify_text(w, s, c))
-#define VB_WIDGET_OVERRIDE_FONT(w, f) (gtk_widget_modify_font(w, f))
-
-#define VB_GTK_STATE_NORMAL GTK_STATE_NORMAL
-#define VB_GTK_STATE_ACTIVE GTK_STATE_ACTIVE
-#define VB_GTK_STATE_SELECTED GTK_STATE_SELECTED
-#define VB_WIDGET_SET_STATE(w, s) (gtk_widget_set_state(w, s))
-#endif
-
-#ifndef SOUP_CHECK_VERSION
-#define SOUP_CHECK_VERSION(major, minor, micro) (0)
-#endif
-
/* the special mark ' must be the first in the list for easiest lookup */
-#define VB_MARK_CHARS "'abcdefghijklmnopqrstuvwxyz"
-#define VB_MARK_TICK 0
-#define VB_MARK_SIZE (sizeof(VB_MARK_CHARS) - 1)
+#define MARK_CHARS "'abcdefghijklmnopqrstuvwxyz"
+#define MARK_TICK 0
+#define MARK_SIZE (sizeof(MARK_CHARS) - 1)
-#define VB_USER_REG "abcdefghijklmnopqrstuvwxyz"
+#define USER_REG "abcdefghijklmnopqrstuvwxyz"
/* registers in order displayed for :register command */
-#define VB_REG_CHARS "\"" VB_USER_REG ":%/;"
-#define VB_REG_SIZE (sizeof(VB_REG_CHARS) - 1)
+#define REG_CHARS "\"" USER_REG ":%/;"
+#define REG_SIZE (sizeof(REG_CHARS) - 1)
+
+#define FILE_CLOSED "closed"
+#define FILE_COOKIES "cookies"
+
+enum { TARGET_CURRENT, TARGET_RELATED, TARGET_NEW };
-/* enums */
typedef enum {
- RESULT_COMPLETE,
- RESULT_MORE,
- RESULT_ERROR
+ RESULT_COMPLETE, RESULT_MORE, RESULT_ERROR
} VbResult;
typedef enum {
- VB_INPUT_UNKNOWN,
- VB_INPUT_SET = 0x01,
- VB_INPUT_OPEN = 0x02,
- VB_INPUT_TABOPEN = 0x04,
- VB_INPUT_COMMAND = 0x08,
- VB_INPUT_SEARCH_FORWARD = 0x10,
- VB_INPUT_SEARCH_BACKWARD = 0x20,
- VB_INPUT_BOOKMARK_ADD = 0x40,
- VB_INPUT_ALL = 0xff, /* map to match all input types */
-} VbInputType;
-
-enum {
- VB_NAVIG_BACK,
- VB_NAVIG_FORWARD,
- VB_NAVIG_RELOAD,
- VB_NAVIG_RELOAD_FORCE,
- VB_NAVIG_STOP_LOADING
-};
-
-enum {
- VB_TARGET_CURRENT,
- VB_TARGET_NEW
-};
-
-enum {
- VB_INPUT_CURRENT_URI = 1
-};
+ CMD_ERROR, /* command could not be parses or executed */
+ CMD_SUCCESS = 0x01, /* command runned successfully */
+ CMD_KEEPINPUT = 0x02, /* don't clear inputbox after command run */
+} VbCmdResult;
-/*
-1 << 0: 0 = jump, 1 = scroll
-1 << 1: 0 = vertical, 1 = horizontal
-1 << 2: 0 = top/left, 1 = down/right
-1 << 3: 0 = paging/halfpage, 1 = line
-1 << 4: 0 = paging, 1 = halfpage
-*/
-enum {VB_SCROLL_TYPE_JUMP, VB_SCROLL_TYPE_SCROLL};
-enum {
- VB_SCROLL_AXIS_V,
- VB_SCROLL_AXIS_H = (1 << 1)
-};
-enum {
- VB_SCROLL_DIRECTION_TOP,
- VB_SCROLL_DIRECTION_DOWN = (1 << 2),
- VB_SCROLL_DIRECTION_LEFT = VB_SCROLL_AXIS_H,
- VB_SCROLL_DIRECTION_RIGHT = VB_SCROLL_AXIS_H | (1 << 2)
-};
-enum {
- VB_SCROLL_UNIT_PAGE,
- VB_SCROLL_UNIT_LINE = (1 << 3),
- VB_SCROLL_UNIT_HALFPAGE = (1 << 4)
-};
+typedef enum {
+ TYPE_BOOLEAN, TYPE_INTEGER, TYPE_CHAR, TYPE_COLOR, TYPE_FONT
+} DataType;
typedef enum {
- VB_MSG_NORMAL,
- VB_MSG_ERROR,
- VB_MSG_LAST
+ MSG_NORMAL, MSG_ERROR
} MessageType;
typedef enum {
- VB_STATUS_NORMAL,
- VB_STATUS_SSL_VALID,
- VB_STATUS_SSL_INVALID,
- VB_STATUS_LAST
+ STATUS_NORMAL, STATUS_SSL_VALID, STATUS_SSL_INVALID
} StatusType;
typedef enum {
- VB_CMD_ERROR, /* command could not be parses or executed */
- VB_CMD_SUCCESS = 0x01, /* command runned successfully */
- VB_CMD_KEEPINPUT = 0x02, /* don't clear inputbox after command run */
-} VbCmdResult;
+ INPUT_UNKNOWN,
+ INPUT_SET = 0x01,
+ INPUT_OPEN = 0x02,
+ INPUT_TABOPEN = 0x04,
+ INPUT_COMMAND = 0x08,
+ INPUT_SEARCH_FORWARD = 0x10,
+ INPUT_SEARCH_BACKWARD = 0x20,
+ INPUT_BOOKMARK_ADD = 0x40,
+ INPUT_ALL = 0xff, /* map to match all input types */
+} VbInputType;
-typedef enum {
- VB_COMP_NORMAL,
- VB_COMP_ACTIVE,
- VB_COMP_LAST
-} CompletionStyle;
+enum {
+ COMP_NORMAL, COMP_ACTIVE, COMP_LAST
+};
-typedef enum {
+enum {
+ FILES_BOOKMARK,
+ FILES_CLOSED,
+ FILES_COMMAND,
FILES_CONFIG,
-#ifdef FEATURE_COOKIE
FILES_COOKIE,
-#endif
- FILES_CLOSED,
- FILES_SCRIPT,
FILES_HISTORY,
- FILES_COMMAND,
- FILES_SEARCH,
- FILES_BOOKMARK,
-#ifdef FEATURE_QUEUE
+ FILES_HSTS,
FILES_QUEUE,
-#endif
+ FILES_SCRIPT,
+ FILES_SEARCH,
FILES_USER_STYLE,
-#ifdef FEATURE_HSTS
- FILES_HSTS,
-#endif
FILES_LAST
-} VbFile;
+};
-enum {
- VB_CLIPBOARD_PRIMARY = (1<<1),
- VB_CLIPBOARD_SECONDARY = (1<<2)
+typedef struct Client Client;
+typedef struct Map Map;
+typedef struct Mode Mode;
+typedef struct Arg Arg;
+typedef void (*ModeTransitionFunc)(Client*);
+typedef VbResult (*ModeKeyFunc)(Client*, int);
+typedef void (*ModeInputChangedFunc)(Client*, const char*);
+
+struct Arg {
+ int i;
+ char *s;
};
-typedef int (*SettingFunction)(const char *name, int type, void *value, void *data);
+typedef int (*SettingFunction)(Client *c, const char *name, DataType type, void *value, void *data);
typedef union {
gboolean b;
int i;
@@ -241,16 +148,48 @@ typedef struct {
void *data; /* data given to the setter */
} Setting;
-/* structs */
-typedef struct {
- int i;
- char *s;
-} Arg;
+struct State {
+ char *uri;
+ gboolean typed; /* indicates if the user typed the keys */
+ gboolean processed_key; /* indicates if a key press was handled and should not bubbled up */
+ gboolean ctrlv; /* indicates if the CTRL-V temorary submode is on */
-typedef void (*ModeTransitionFunc) (void);
-typedef VbResult (*ModeKeyFunc) (int);
-typedef void (*ModeInputChangedFunc) (const char*);
-typedef struct {
+#define PROMPT_SIZE 4
+ char prompt[PROMPT_SIZE];/* current prompt ':', 'g;t', '/' including nul */
+ gdouble marks[MARK_SIZE]; /* holds marks set to page with 'm{markchar}' */
+ guint input_timer;
+ MessageType input_type;
+ StatusType status_type;
+ glong scroll_max; /* Maxmimum scrollable height of the document. */
+ guint scroll_percent; /* Current position of the viewport in document. */
+
+ char *reg[REG_SIZE]; /* holds the yank buffers */
+ /* TODO rename to reg_{enabled,current} */
+ gboolean enable_register; /* indicates if registers are filled */
+ char current_register; /* holds char for current register to be used */
+
+ GList *downloads;
+ guint progress;
+ WebKitHitTestResult *hit_test_result;
+
+ struct {
+ gboolean active; /* indicate if there is a acitve search */
+ short direction; /* last direction 1 forward, -1 backward */
+ int matches; /* number of matches search results */
+ } search;
+};
+
+struct Map {
+ char *in; /* input keys */
+ int inlen; /* length of the input keys */
+ char *mapped; /* mapped keys */
+ int mappedlen; /* length of the mapped keys string */
+ char mode; /* mode for which the map is available */
+ gboolean remap; /* if FALSE do not remap the {rhs} of this map */
+ gboolean enable_register; /* indicates if registers are filled */
+};
+
+struct Mode {
char id;
ModeTransitionFunc enter; /* is called if the mode is entered */
ModeTransitionFunc leave; /* is called if the mode is left */
@@ -261,153 +200,79 @@ typedef struct {
#define FLAG_COMPLETION 0x0004 /* marks active completion submode */
#define FLAG_PASSTHROUGH 0x0008 /* don't handle any other keybind than <esc> */
unsigned int flags;
-} Mode;
+};
-/* statusbar */
-typedef struct {
+struct Statusbar {
GtkBox *box;
- GtkWidget *mode;
- GtkWidget *left;
- GtkWidget *right;
- GtkWidget *cmd;
-} StatusBar;
-
-/* gui */
-typedef struct {
- GtkWidget *window;
- WebKitWebView *webview;
- WebKitWebInspector *inspector;
- GtkBox *box;
- GtkWidget *eventbox;
- GtkWidget *input;
- GtkTextBuffer *buffer; /* text buffer associated with the input for fast access */
- GtkWidget *pane;
- StatusBar statusbar;
- GtkAdjustment *adjust_h;
- GtkAdjustment *adjust_v;
-} Gui;
-
-/* state */
-typedef struct {
- char *uri; /* holds current uri or the new to open uri */
- guint progress;
- StatusType status_type;
- MessageType input_type;
- gboolean is_inspecting;
- GList *downloads;
- gboolean processed_key;
- char *title; /* holds the window title */
-#define PROMPT_SIZE 4
- char prompt[PROMPT_SIZE]; /* current prompt ':', 'g;t', '/' including nul */
- gdouble marks[VB_MARK_SIZE]; /* holds marks set to page with 'm{markchar}' */
- char *linkhover; /* the uri of the curret hovered link */
- char *reg[VB_REG_SIZE]; /* holds the yank buffer */
- gboolean enable_register; /* indicates if registers are filled */
- char current_register; /* holds char for current register to be used */
- gboolean typed; /* indicates if th euser type the keys processed as command */
-#ifdef FEATURE_SEARCH_HIGHLIGHT
- int search_matches; /* number of matches search results */
-#endif
- char *fifo_path; /* holds the path to the control fifo */
- char *socket_path; /* holds the path to the control socket */
- char *pid_str; /* holds the pid as string */
- gboolean done_loading_page;
- gboolean window_has_focus;
-} State;
-
-typedef struct {
-#ifdef FEATURE_COOKIE
- time_t cookie_timeout;
- int cookie_expire_time;
-#endif
- int scrollstep;
- char *download_dir;
- guint history_max;
- guint closed_max;
- guint timeoutlen; /* timeout for ambiguous mappings */
- gboolean strict_focus;
- GHashTable *headers; /* holds user defined header appended to requests */
-#ifdef FEATURE_ARH
- GSList *autoresponseheader; /* holds user defined list of auto-response-header */
-#endif
- char *nextpattern; /* regex patter nfor prev link matching */
- char *prevpattern; /* regex patter nfor next link matching */
- char *file; /* path to the custome config file */
- char *profile; /* profile name */
- GSList *cmdargs; /* list of commands given by --cmd option */
- char *cafile; /* path to the ca file */
- GTlsDatabase *tls_db; /* tls database */
- float default_zoom; /* default zoomlevel that is applied on zz zoom reset */
- gboolean kioskmode;
- gboolean input_autohide; /* indicates if the inputbox should be hidden if it's empty */
-#ifdef FEATURE_SOCKET
- gboolean socket; /* indicates if the socket is used */
-#endif
-#ifdef FEATURE_HSTS
- HSTSProvider *hsts_provider; /* the hsts session feature that is added to soup session */
-#endif
-#ifdef FEATURE_SOUP_CACHE
- SoupCache *soup_cache; /* soup caching feature model */
-#endif
- GHashTable *settings;
-} Config;
+ GtkWidget *mode, *left, *right, *cmd;
+};
-typedef struct {
- VbColor input_fg[VB_MSG_LAST];
- VbColor input_bg[VB_MSG_LAST];
- PangoFontDescription *input_font[VB_MSG_LAST];
- /* completion */
- VbColor comp_fg[VB_COMP_LAST];
- VbColor comp_bg[VB_COMP_LAST];
- PangoFontDescription *comp_font;
- /* status bar */
- VbColor status_bg[VB_STATUS_LAST];
- VbColor status_fg[VB_STATUS_LAST];
- PangoFontDescription *status_font[VB_STATUS_LAST];
-} VbStyle;
+struct Client {
+ struct Client *next;
+ struct State state;
+ struct Statusbar statusbar;
+ void *comp; /* pointer to data used in completion.c */
+ Mode *mode; /* current active browser mode */
+ WebKitWebContext *webctx;
+ GtkWidget *window, *input;
+ WebKitWebView *webview;
+ guint64 page_id; /* page id of the webview */
+ GtkTextBuffer *buffer;
+ GDBusProxy *dbusproxy;
+ struct {
+ /* TODO split in global setting definitions and set values on a per
+ * client base. */
+ GHashTable *settings;
+ guint scrollstep;
+ gboolean input_autohide;
+ /* completion */
+ GdkRGBA comp_fg[COMP_LAST];
+ GdkRGBA comp_bg[COMP_LAST];
+ PangoFontDescription *comp_font;
+ } config;
+ struct {
+ GSList *list;
+ GString *queue; /* queue holding typed keys */
+ int qlen; /* pointer to last char in queue */
+ int resolved; /* number of resolved keys (no mapping required) */
+ guint timout_id; /* source id of the timeout function */
+ char showcmd[SHOWCMD_LEN + 1]; /* buffer to show ambiguous key sequence */
+ guint timeoutlen; /* timeout for ambiguous mappings */
+ } map;
+ struct {
+ GHashTable *table;
+ char *fallback; /* default shortcut to use if none given in request */
+ } shortcut;
+};
-typedef struct {
- Gui gui;
- State state;
-
- char *files[FILES_LAST];
- Mode *mode;
- Config config;
- VbStyle style;
- SoupSession *session;
-#ifdef HAS_GTK3
- Window embed;
-#else
- GdkNativeWindow embed;
-#endif
- GHashTable *modes; /* all available browser main modes */
-} VbCore;
+struct Vimb {
+ char *argv0;
+ Client *clients;
+ Window embed;
+ GHashTable *modes; /* all available browser main modes */
+ char *configfile; /* config file given as option on startup */
+ char *files[FILES_LAST];
+ struct {
+ guint history_max;
+ } config;
+};
-/* main object */
-extern VbCore core;
-/* functions */
-void vb_add_mode(char id, ModeTransitionFunc enter, ModeTransitionFunc leave,
+void vb_echo(Client *c, MessageType type, gboolean hide, const char *error, ...);
+void vb_echo_force(Client *c, MessageType type, gboolean hide, const char *error, ...);
+void vb_enter(Client *c, char id);
+void vb_enter_prompt(Client *c, char id, const char *prompt, gboolean print_prompt);
+char *vb_input_get_text(Client *c);
+void vb_input_set_text(Client *c, const char *text);
+void vb_input_update_style(Client *c);
+gboolean vb_load_uri(Client *c, const Arg *arg);
+void vb_mode_add(char id, ModeTransitionFunc enter, ModeTransitionFunc leave,
ModeKeyFunc keypress, ModeInputChangedFunc input_changed);
-void vb_echo_force(const MessageType type,gboolean hide, const char *error, ...);
-void vb_echo(const MessageType type, gboolean hide, const char *error, ...);
-void vb_enter(char id);
-void vb_enter_prompt(char id, const char *prompt, gboolean print_prompt);
-VbResult vb_handle_key(int key);
-void vb_set_input_text(const char *text);
-char *vb_get_input_text(void);
-void vb_input_activate(void);
-gboolean vb_load_uri(const Arg *arg);
-gboolean vb_set_clipboard(const Arg *arg);
-void vb_set_widget_font(GtkWidget *widget, const VbColor *fg, const VbColor *bg, PangoFontDescription *font);
-void vb_update_statusbar(void);
-void vb_update_status_style(void);
-void vb_update_input_style(void);
-void vb_update_urlbar(const char *uri);
-void vb_update_mode_label(const char *label);
-void vb_register_add(char buf, const char *value);
-const char *vb_register_get(char buf);
-gboolean vb_download(WebKitWebView *view, WebKitDownload *download, const char *path);
-void vb_quit(gboolean force);
+VbResult vb_mode_handle_key(Client *c, int key);
+void vb_modelabel_update(Client *c, const char *label);
+void vb_quit(Client *c, gboolean force);
+void vb_register_add(Client *c, char buf, const char *value);
+const char *vb_register_get(Client *c, char buf);
+void vb_statusbar_update(Client *c);
#endif /* end of include guard: _MAIN_H */
diff --git a/src/map.c b/src/map.c
index a9fad55..5b4017a 100644
--- a/src/map.c
+++ b/src/map.c
@@ -1,4 +1,6 @@
/**
+ * vimb - a webkit based vim like browser.
+ *
* Copyright (C) 2012-2015 Daniel Carl
*
* This program is free software: you can redistribute it and/or modify
@@ -15,47 +17,37 @@
* along with this program. If not, see http://www.gnu.org/licenses/.
*/
-#include <gdk/gdkkeysyms.h>
#include <gdk/gdkkeysyms-compat.h>
+#include <gdk/gdkkeysyms.h>
+#include <string.h>
+
+#include "ascii.h"
#include "config.h"
#include "main.h"
#include "map.h"
-#include "normal.h"
-#include "ascii.h"
-
-/* convert the lower 4 bits of byte n to its hex character */
-#define NR2HEX(n) (n & 0xf) <= 9 ? (n & 0xf) + '0' : (c & 0xf) - 10 + 'a'
-
-typedef struct {
- char *in; /* input keys */
- int inlen; /* length of the input keys */
- char *mapped; /* mapped keys */
- int mappedlen; /* length of the mapped keys string */
- char mode; /* mode for which the map is available */
- gboolean remap; /* if false do not remap the {rhs} of this map */
-} Map;
-
-/* this is only to keep the variables together */
-static struct {
- GSList *list;
- GString *queue; /* queue holding typed keys */
- int qlen; /* pointer to last char in queue */
- int resolved; /* number of resolved keys (no mapping required) */
- guint timout_id; /* source id of the timeout function */
- char showcmd[SHOWCMD_LEN + 1]; /* buffer to show ambiguous key sequence */
-} map;
-
-extern VbCore vb;
+#include "util.h"
+
+struct MapInfo {
+ GSList *list;
+ GString *queue; /* queue holding typed keys */
+ int qlen; /* pointer to last char in queue */
+ int resolved; /* number of resolved keys (no mapping required) */
+ guint timout_id; /* source id of the timeout function */
+ char showcmd[SHOWCMD_LEN + 1]; /* buffer to show ambiguous key sequence */
+ guint timeoutlen; /* timeout for ambiguous mappings */
+};
-static void showcmd(int c);
-static char *transchar(int c);
-static gboolean map_delete_by_lhs(const char *lhs, int len, char mode);
-static int keyval_to_string(guint keyval, guint state, guchar *string);
-static int utf_char2bytes(guint c, guchar *buf);
-static char *convert_keys(const char *in, int inlen, int *len);
static char *convert_keylabel(const char *in, int inlen, int *len);
-static gboolean do_timeout(gpointer data);
+static char *convert_keys(const char *in, int inlen, int *len);
+static gboolean do_timeout(Client *c);
static void free_map(Map *map);
+static int keyval_to_string(guint keyval, guint state, guchar *string);
+static gboolean map_delete_by_lhs(Client *c, const char *lhs, int len, char mode);
+static void showcmd(Client *c, int ch);
+static char *transchar(int c);
+static int utf_char2bytes(guint c, guchar *buf);
+
+extern struct Vimb vb;
static struct {
guint state;
@@ -112,69 +104,21 @@ static struct {
{"<F12>", 5, CSI_STR "F2", 3},
};
-void map_init(void)
+void map_init(Client *c)
{
- map.queue = g_string_sized_new(50);
+ c->map.queue = g_string_sized_new(50);
+ /* TODO move this to settings */
+ c->map.timeoutlen = 1000;
}
-void map_cleanup(void)
+void map_cleanup(Client *c)
{
- if (map.list) {
- g_slist_free_full(map.list, (GDestroyNotify)free_map);
- }
- g_string_free(map.queue, true);
-}
-
-/**
- * Handle all key events, convert the key event into the internal used ASCII
- * representation and put this into the key queue to be mapped.
- */
-gboolean map_keypress(GtkWidget *widget, GdkEventKey* event, gpointer data)
-{
- guint state = event->state;
- guint keyval = event->keyval;
- guchar string[32];
- int len;
-
- len = keyval_to_string(keyval, state, string);
-
- /* translate iso left tab to shift tab */
- if (keyval == GDK_ISO_Left_Tab) {
- keyval = GDK_Tab;
- state |= GDK_SHIFT_MASK;
- }
-
- if (len == 0 || len == 1) {
- for (int i = 0; i < LENGTH(special_keys); i++) {
- if (special_keys[i].keyval == keyval
- && (special_keys[i].state == 0 || state & special_keys[i].state)
- ) {
- state &= ~special_keys[i].state;
- string[0] = CSI;
- string[1] = special_keys[i].one;
- string[2] = special_keys[i].two;
- len = 3;
- break;
- }
- }
+ if (c->map.list) {
+ g_slist_free_full(c->map.list, (GDestroyNotify)free_map);
}
-
- if (len == 0) {
- /* mark all unknown key events as unhandled to not break some gtk features
- * like <S-Einf> to copy clipboard content into inputbox */
- return false;
+ if (c->map.queue) {
+ g_string_free(c->map.queue, TRUE);
}
-
- /* set flag to notify that the key was typed by the user */
- vb.state.typed = true;
- vb.state.processed_key = true;
-
- map_handle_keys(string, len, true);
-
- /* reset the typed flag */
- vb.state.typed = false;
-
- return vb.state.processed_key;
}
/**
@@ -182,7 +126,7 @@ gboolean map_keypress(GtkWidget *widget, GdkEventKey* event, gpointer data)
* chars. The key sequence do not need to be NUL terminated.
* Keylen of 0 signalized a key timeout.
*/
-MapState map_handle_keys(const guchar *keys, int keylen, gboolean use_map)
+MapState map_handle_keys(Client *c, const guchar *keys, int keylen, gboolean use_map)
{
int ambiguous;
Map *match = NULL;
@@ -190,99 +134,99 @@ MapState map_handle_keys(const guchar *keys, int keylen, gboolean use_map)
static int showlen = 0; /* track the number of keys in showcmd of status bar */
/* if a previous timeout function was set remove this */
- if (map.timout_id) {
- g_source_remove(map.timout_id);
- map.timout_id = 0;
+ if (c->map.timout_id) {
+ g_source_remove(c->map.timout_id);
+ c->map.timout_id = 0;
}
/* don't set the timeout function if the timeout is processed now */
if (!timeout) {
- map.timout_id = g_timeout_add(vb.config.timeoutlen, (GSourceFunc)do_timeout, NULL);
+ c->map.timout_id = g_timeout_add(c->map.timeoutlen, (GSourceFunc)do_timeout, c);
}
/* copy the keys onto the end of queue */
if (keylen > 0) {
- g_string_overwrite_len(map.queue, map.qlen, (char*)keys, keylen);
- map.qlen += keylen;
+ g_string_overwrite_len(c->map.queue, c->map.qlen, (char*)keys, keylen);
+ c->map.qlen += keylen;
}
/* try to resolve keys against the map */
- while (true) {
+ while (TRUE) {
/* send any resolved key to the parser */
- while (map.resolved > 0) {
+ while (c->map.resolved > 0) {
int qk;
/* skip csi indicator and the next 2 chars - if the csi sequence
* isn't part of a mapped command we let gtk handle the key - this
* is required allow to move cursor in inputbox with <Left> and
* <Right> keys */
- if ((map.queue->str[0] & 0xff) == CSI && map.qlen >= 3) {
+ if ((c->map.queue->str[0] & 0xff) == CSI && c->map.qlen >= 3) {
/* get next 2 chars to build the termcap key */
- qk = TERMCAP2KEY(map.queue->str[1], map.queue->str[2]);
+ qk = TERMCAP2KEY(c->map.queue->str[1], c->map.queue->str[2]);
- map.resolved -= 3;
- map.qlen -= 3;
+ c->map.resolved -= 3;
+ c->map.qlen -= 3;
/* move all other queue entries three steps to the left */
- memmove(map.queue->str, map.queue->str + 3, map.qlen);
+ memmove(c->map.queue->str, c->map.queue->str + 3, c->map.qlen);
} else {
/* get first char of queue */
- qk = map.queue->str[0];
+ qk = c->map.queue->str[0];
- map.resolved--;
- map.qlen--;
+ c->map.resolved--;
+ c->map.qlen--;
/* move all other queue entries one step to the left */
- memmove(map.queue->str, map.queue->str + 1, map.qlen);
+ memmove(c->map.queue->str, c->map.queue->str + 1, c->map.qlen);
}
/* remove the no-map flag */
- vb.mode->flags &= ~FLAG_NOMAP;
+ c->mode->flags &= ~FLAG_NOMAP;
/* send the key to the parser */
- if (RESULT_MORE != vb_handle_key((int)qk)) {
- showcmd(0);
+ if (RESULT_MORE != vb_mode_handle_key(c, (int)qk)) {
+ showcmd(c, 0);
showlen = 0;
} else if (showlen > 0) {
showlen--;
} else {
- showcmd(qk);
+ showcmd(c, qk);
}
}
/* if all keys where processed return MAP_DONE */
- if (map.qlen == 0) {
- map.resolved = 0;
+ if (c->map.qlen == 0) {
+ c->map.resolved = 0;
return match ? MAP_DONE : MAP_NOMATCH;
}
/* try to find matching maps */
match = NULL;
ambiguous = 0;
- if (use_map && !(vb.mode->flags & FLAG_NOMAP)) {
- for (GSList *l = map.list; l != NULL; l = l->next) {
+ if (use_map && !(c->mode->flags & FLAG_NOMAP)) {
+ for (GSList *l = c->map.list; l != NULL; l = l->next) {
Map *m = (Map*)l->data;
/* ignore maps for other modes */
- if (m->mode != vb.mode->id) {
+ if (m->mode != c->mode->id) {
continue;
}
/* find ambiguous matches */
- if (!timeout && m->inlen > map.qlen && !strncmp(m->in, map.queue->str, map.qlen)) {
+ if (!timeout && m->inlen > c->map.qlen && !strncmp(m->in, c->map.queue->str, c->map.qlen)) {
if (ambiguous == 0) {
/* show command chars for the ambiguous commands */
- int i = map.qlen > SHOWCMD_LEN ? map.qlen - SHOWCMD_LEN : 0;
+ int i = c->map.qlen > SHOWCMD_LEN ? c->map.qlen - SHOWCMD_LEN : 0;
/* appen only those chars that are not already in showcmd */
i += showlen;
- while (i < map.qlen) {
- showcmd(map.queue->str[i++]);
+ while (i < c->map.qlen) {
+ showcmd(c, c->map.queue->str[i++]);
showlen++;
}
}
ambiguous++;
}
/* complete match or better/longer match than previous found */
- if (m->inlen <= map.qlen
- && !strncmp(m->in, map.queue->str, m->inlen)
+ if (m->inlen <= c->map.qlen
+ && !strncmp(m->in, c->map.queue->str, m->inlen)
&& (!match || match->inlen < m->inlen)
) {
/* backup this found possible match */
@@ -290,7 +234,7 @@ MapState map_handle_keys(const guchar *keys, int keylen, gboolean use_map)
}
}
- /* if there are ambiguous matches return MAP_KEY and flush queue
+ /* if there are ambiguous matches return MAP_AMBIGUOUS and flush queue
* after a timeout if the user do not type more keys */
if (ambiguous) {
return MAP_AMBIGUOUS;
@@ -303,7 +247,7 @@ MapState map_handle_keys(const guchar *keys, int keylen, gboolean use_map)
/* Flush the show command to make room for possible mapped command
* chars to show. For example if :nmap foo 12g is use we want to
* display the incomplete 12g command. */
- showcmd(0);
+ showcmd(c, 0);
showlen = 0;
/* Replace the matching input chars by the mapped chars. */
@@ -312,30 +256,30 @@ MapState map_handle_keys(const guchar *keys, int keylen, gboolean use_map)
* chars with the mapped chars. This case could also be
* handled by the later string erase and prepend, but handling
* it special avoids unneded function call. */
- g_string_overwrite_len(map.queue, 0, match->mapped, match->mappedlen);
+ g_string_overwrite_len(c->map.queue, 0, match->mapped, match->mappedlen);
} else {
/* Remove all the chars that where matched and prepend the
* mapped chars to the queue. */
- g_string_erase(map.queue, 0, match->inlen);
- g_string_prepend_len(map.queue, match->mapped, match->mappedlen);
+ g_string_erase(c->map.queue, 0, match->inlen);
+ g_string_prepend_len(c->map.queue, match->mapped, match->mappedlen);
}
- map.qlen += match->mappedlen - match->inlen;
+ c->map.qlen += match->mappedlen - match->inlen;
/* without remap the mapped chars are resolved now */
if (!match->remap) {
- map.resolved = match->mappedlen;
+ c->map.resolved = match->mappedlen;
} else if (match->inlen <= match->mappedlen
&& !strncmp(match->in, match->mapped, match->inlen)
) {
- map.resolved = match->inlen;
+ c->map.resolved = match->inlen;
}
/* Unset the typed flag - if there where keys replaced by a
* mapping the resulting key string is considered as not typed by
* the user. */
- vb.state.typed = false;
+ c->state.typed = FALSE;
} else {
/* first char is not mapped but resolved */
- map.resolved = 1;
+ c->map.resolved = 1;
}
}
@@ -346,21 +290,21 @@ MapState map_handle_keys(const guchar *keys, int keylen, gboolean use_map)
* Like map_handle_keys but use a null terminates string with untranslated
* keys like <C-T> that are converted here before calling map_handle_keys.
*/
-void map_handle_string(const char *str, gboolean use_map)
+void map_handle_string(Client *c, const char *str, gboolean use_map)
{
int len;
char *keys = convert_keys(str, strlen(str), &len);
- map_handle_keys((guchar*)keys, len, use_map);
+ map_handle_keys(c, (guchar*)keys, len, use_map);
}
-void map_insert(const char *in, const char *mapped, char mode, gboolean remap)
+void map_insert(Client *c, const char *in, const char *mapped, char mode, gboolean remap)
{
int inlen, mappedlen;
char *lhs = convert_keys(in, strlen(in), &inlen);
char *rhs = convert_keys(mapped, strlen(mapped), &mappedlen);
/* if lhs was already mapped, remove this first */
- map_delete_by_lhs(lhs, inlen, mode);
+ map_delete_by_lhs(c, lhs, inlen, mode);
Map *new = g_slice_new(Map);
new->in = lhs;
@@ -370,81 +314,186 @@ void map_insert(const char *in, const char *mapped, char mode, gboolean remap)
new->mode = mode;
new->remap = remap;
- map.list = g_slist_prepend(map.list, new);
+ c->map.list = g_slist_prepend(c->map.list, new);
}
-gboolean map_delete(const char *in, char mode)
+gboolean map_delete(Client *c, const char *in, char mode)
{
int len;
char *lhs = convert_keys(in, strlen(in), &len);
- return map_delete_by_lhs(lhs, len, mode);
+ return map_delete_by_lhs(c, lhs, len, mode);
}
/**
- * Put the given char onto the show command buffer.
+ * Handle all key events, convert the key event into the internal used ASCII
+ * representation and put this into the key queue to be mapped.
*/
-static void showcmd(int c)
+gboolean on_map_keypress(GtkWidget *widget, GdkEventKey* event, Client *c)
{
- char *translated;
- int old, extra, overflow;
+ guint state = event->state;
+ guint keyval = event->keyval;
+ guchar string[32];
+ int len;
- if (c) {
- translated = transchar(c);
- old = strlen(map.showcmd);
- extra = strlen(translated);
- overflow = old + extra - SHOWCMD_LEN;
- if (overflow > 0) {
- memmove(map.showcmd, map.showcmd + overflow, old - overflow + 1);
+ len = keyval_to_string(keyval, state, string);
+
+ /* translate iso left tab to shift tab */
+ if (keyval == GDK_ISO_Left_Tab) {
+ keyval = GDK_Tab;
+ state |= GDK_SHIFT_MASK;
+ }
+
+ if (len == 0 || len == 1) {
+ for (int i = 0; i < LENGTH(special_keys); i++) {
+ if (special_keys[i].keyval == keyval
+ && (special_keys[i].state == 0 || state & special_keys[i].state)
+ ) {
+ state &= ~special_keys[i].state;
+ string[0] = CSI;
+ string[1] = special_keys[i].one;
+ string[2] = special_keys[i].two;
+ len = 3;
+ break;
+ }
}
- strcat(map.showcmd, translated);
- } else {
- map.showcmd[0] = '\0';
}
-#ifndef TESTLIB
- /* show the typed keys */
- gtk_label_set_text(GTK_LABEL(vb.gui.statusbar.cmd), map.showcmd);
-#endif
+
+ if (len == 0) {
+ /* mark all unknown key events as unhandled to not break some gtk features
+ * like <S-Einf> to copy clipboard content into inputbox */
+ return FALSE;
+ }
+
+ /* set flag to notify that the key was typed by the user */
+ c->state.typed = TRUE;
+ c->state.processed_key = TRUE;
+
+ map_handle_keys(c, string, len, TRUE);
+
+ /* reset the typed flag */
+ c->state.typed = FALSE;
+
+ return c->state.processed_key;
}
/**
- * Translate a singe char into a readable representation to be show to the
- * user in status bar.
+ * Translate given key string into a internal representation <cr> -> \n.
+ * The len of the translated key sequence is put into given *len pointer.
*/
-static char *transchar(int c)
+static char *convert_keylabel(const char *in, int inlen, int *len)
{
- static char trans[5];
- int i = 0;
- if (VB_IS_CTRL(c)) {
- trans[i++] = '^';
- trans[i++] = CTRL(c);
- } else if ((unsigned)c >= 0x80) {
- trans[i++] = '<';
- trans[i++] = NR2HEX((unsigned)c >> 4);
- trans[i++] = NR2HEX((unsigned)c);
- trans[i++] = '>';
- } else {
- trans[i++] = c;
+ for (int i = 0; i < LENGTH(key_labels); i++) {
+ if (inlen == key_labels[i].len
+ && !strncmp(key_labels[i].label, in, inlen)
+ ) {
+ *len = key_labels[i].chlen;
+ return key_labels[i].ch;
+ }
}
- trans[i++] = '\0';
+ *len = 0;
- return trans;
+ return NULL;
}
-static gboolean map_delete_by_lhs(const char *lhs, int len, char mode)
+/**
+ * Converts a keysequence into a internal raw keysequence.
+ * Returned keyseqence must be freed if not used anymore.
+ */
+static char *convert_keys(const char *in, int inlen, int *len)
{
- for (GSList *l = map.list; l != NULL; l = l->next) {
- Map *m = (Map*)l->data;
+ int symlen, rawlen;
+ char *dest;
+ char ch[1];
+ const char *p, *raw;
+ GString *str = g_string_new("");
- /* remove only if the map's lhs matches the given key sequence */
- if (m->mode == mode && m->inlen == len && !strcmp(m->in, lhs)) {
- /* remove the found list item */
- map.list = g_slist_delete_link(map.list, l);
- free_map(m);
- return true;
+ *len = 0;
+ for (p = in; p < &in[inlen]; p++) {
+ /* if it starts not with < we can add it literally */
+ if (*p != '<') {
+ g_string_append_len(str, p, 1);
+ *len += 1;
+ continue;
}
+
+ /* search matching > of symbolic name */
+ symlen = 1;
+ do {
+ if (&p[symlen] == &in[inlen]
+ || p[symlen] == '<'
+ || p[symlen] == ' '
+ ) {
+ break;
+ }
+ } while (p[symlen++] != '>');
+
+ raw = NULL;
+ rawlen = 0;
+ /* check if we found a real keylabel */
+ if (p[symlen - 1] == '>') {
+ if (symlen == 5 && p[2] == '-') {
+ /* is it a <C-X> */
+ if (p[1] == 'C') {
+ if (VB_IS_UPPER(p[3])) {
+ ch[0] = p[3] - 0x40;
+ raw = ch;
+ rawlen = 1;
+ } else if (VB_IS_LOWER(p[3])) {
+ ch[0] = p[3] - 0x60;
+ raw = ch;
+ rawlen = 1;
+ }
+ }
+ }
+
+ /* if we could not convert it jet - try to translate the label */
+ if (!rawlen) {
+ raw = convert_keylabel(p, symlen, &rawlen);
+ }
+ }
+
+ /* we found no known keylabel - so use the chars literally */
+ if (!rawlen) {
+ rawlen = symlen;
+ raw = p;
+ }
+
+ /* write the converted keylabel into the buffer */
+ g_string_append_len(str, raw, rawlen);
+
+ /* move p after the keylabel */
+ p += symlen - 1;
+
+ *len += rawlen;
}
- return false;
+ dest = str->str;
+
+ /* don't free the character data of the GString */
+ g_string_free(str, FALSE);
+
+ return dest;
+}
+
+/**
+ * Timeout function to signalize a key timeout to the map.
+ */
+static gboolean do_timeout(Client *c)
+{
+ /* signalize the timeout to the key handler */
+ map_handle_keys(c, (guchar*)"", 0, TRUE);
+
+ /* we return TRUE to not automatically remove the resource - this is
+ * required to prevent critical error when we remove the source in
+ * map_handle_keys where we don't know if the timeout was called or not */
+ return TRUE;
+}
+
+static void free_map(Map *map)
+{
+ g_free(map->in);
+ g_free(map->mapped);
+ g_slice_free(Map, map);
}
/**
@@ -505,6 +554,76 @@ static int keyval_to_string(guint keyval, guint state, guchar *string)
return len;
}
+static gboolean map_delete_by_lhs(Client *c, const char *lhs, int len, char mode)
+{
+ for (GSList *l = c->map.list; l != NULL; l = l->next) {
+ Map *m = (Map*)l->data;
+
+ /* remove only if the map's lhs matches the given key sequence */
+ if (m->mode == mode && m->inlen == len && !strcmp(m->in, lhs)) {
+ /* remove the found list item */
+ c->map.list = g_slist_delete_link(c->map.list, l);
+ free_map(m);
+ return TRUE;
+ }
+ }
+ return FALSE;
+}
+
+/**
+ * Put the given char onto the show command buffer.
+ */
+static void showcmd(Client *c, int ch)
+{
+ char *translated;
+ int old, extra, overflow;
+
+ if (ch) {
+ translated = transchar(ch);
+ old = strlen(c->map.showcmd);
+ extra = strlen(translated);
+ overflow = old + extra - SHOWCMD_LEN;
+ if (overflow > 0) {
+ memmove(c->map.showcmd, c->map.showcmd + overflow, old - overflow + 1);
+ }
+ strcat(c->map.showcmd, translated);
+ } else {
+ c->map.showcmd[0] = '\0';
+ }
+#ifndef TESTLIB
+ /* show the typed keys */
+ gtk_label_set_text(GTK_LABEL(c->statusbar.cmd), c->map.showcmd);
+#endif
+}
+
+/**
+ * Translate a singe char into a readable representation to be show to the
+ * user in status bar.
+ */
+static char *transchar(int c)
+{
+ static char trans[5];
+ int i = 0;
+
+ if (VB_IS_CTRL(c)) {
+ trans[i++] = '^';
+ trans[i++] = CTRL(c);
+ } else if ((unsigned)c >= 0x80) {
+/* convert the lower 4 bits of byte n to its hex character */
+#define NR2HEX(n) (n & 0xf) <= 9 ? (n & 0xf) + '0' : (c & 0xf) - 10 + 'a'
+ trans[i++] = '<';
+ trans[i++] = NR2HEX((unsigned)c >> 4);
+ trans[i++] = NR2HEX((unsigned)c);
+ trans[i++] = '>';
+#undef NR2HEX
+ } else {
+ trans[i++] = c;
+ }
+ trans[i++] = '\0';
+
+ return trans;
+}
+
static int utf_char2bytes(guint c, guchar *buf)
{
if (c < 0x80) {
@@ -545,122 +664,3 @@ static int utf_char2bytes(guint c, guchar *buf)
buf[5] = 0x80 + (c & 0x3f);
return 6;
}
-
-/**
- * Converts a keysequence into a internal raw keysequence.
- * Returned keyseqence must be freed if not used anymore.
- */
-static char *convert_keys(const char *in, int inlen, int *len)
-{
- int symlen, rawlen;
- char *dest;
- char ch[1];
- const char *p, *raw;
- GString *str = g_string_new("");
-
- *len = 0;
- for (p = in; p < &in[inlen]; p++) {
- /* if it starts not with < we can add it literally */
- if (*p != '<') {
- g_string_append_len(str, p, 1);
- *len += 1;
- continue;
- }
-
- /* search matching > of symbolic name */
- symlen = 1;
- do {
- if (&p[symlen] == &in[inlen]
- || p[symlen] == '<'
- || p[symlen] == ' '
- ) {
- break;
- }
- } while (p[symlen++] != '>');
-
- raw = NULL;
- rawlen = 0;
- /* check if we found a real keylabel */
- if (p[symlen - 1] == '>') {
- if (symlen == 5 && p[2] == '-') {
- /* is it a <C-X> */
- if (p[1] == 'C') {
- if (VB_IS_UPPER(p[3])) {
- ch[0] = p[3] - 0x40;
- raw = ch;
- rawlen = 1;
- } else if (VB_IS_LOWER(p[3])) {
- ch[0] = p[3] - 0x60;
- raw = ch;
- rawlen = 1;
- }
- }
- }
-
- /* if we could not convert it jet - try to translate the label */
- if (!rawlen) {
- raw = convert_keylabel(p, symlen, &rawlen);
- }
- }
-
- /* we found no known keylabel - so use the chars literally */
- if (!rawlen) {
- rawlen = symlen;
- raw = p;
- }
-
- /* write the converted keylabel into the buffer */
- g_string_append_len(str, raw, rawlen);
-
- /* move p after the keylabel */
- p += symlen - 1;
-
- *len += rawlen;
- }
- dest = str->str;
-
- /* don't free the character data of the GString */
- g_string_free(str, false);
-
- return dest;
-}
-
-/**
- * Translate given key string into a internal representation <cr> -> \n.
- * The len of the translated key sequence is put into given *len pointer.
- */
-static char *convert_keylabel(const char *in, int inlen, int *len)
-{
- for (int i = 0; i < LENGTH(key_labels); i++) {
- if (inlen == key_labels[i].len
- && !strncmp(key_labels[i].label, in, inlen)
- ) {
- *len = key_labels[i].chlen;
- return key_labels[i].ch;
- }
- }
- *len = 0;
-
- return NULL;
-}
-
-/**
- * Timeout function to signalize a key timeout to the map.
- */
-static gboolean do_timeout(gpointer data)
-{
- /* signalize the timeout to the key handler */
- map_handle_keys((guchar*)"", 0, true);
-
- /* we return true to not automatically remove the resource - this is
- * required to prevent critical error when we remove the source in
- * map_handle_keys where we don't know if the timeout was called or not */
- return true;
-}
-
-static void free_map(Map *map)
-{
- g_free(map->in);
- g_free(map->mapped);
- g_slice_free(Map, map);
-}
diff --git a/src/map.h b/src/map.h
index 0336666..4d5308a 100644
--- a/src/map.h
+++ b/src/map.h
@@ -26,12 +26,12 @@ typedef enum {
MAP_NOMATCH
} MapState;
-void map_init(void);
-void map_cleanup(void);
-gboolean map_keypress(GtkWidget *widget, GdkEventKey* event, gpointer data);
-MapState map_handle_keys(const guchar *keys, int keylen, gboolean use_map);
-void map_handle_string(const char *str, gboolean use_map);
-void map_insert(const char *in, const char *mapped, char mode, gboolean remap);
-gboolean map_delete(const char *in, char mode);
+void map_init(Client *c);
+void map_cleanup(Client *c);
+MapState map_handle_keys(Client *c, const guchar *keys, int keylen, gboolean use_map);
+void map_handle_string(Client *c, const char *str, gboolean use_map);
+void map_insert(Client *c, const char *in, const char *mapped, char mode, gboolean remap);
+gboolean map_delete(Client *c, const char *in, char mode);
+gboolean on_map_keypress(GtkWidget *widget, GdkEventKey* event, Client *c);
#endif /* end of include guard: _MAP_H */
diff --git a/src/normal.c b/src/normal.c
index 54548a1..2980ecf 100644
--- a/src/normal.c
+++ b/src/normal.c
@@ -18,14 +18,15 @@
*/
#include <gdk/gdkkeysyms.h>
+#include <string.h>
+
+#include "ascii.h"
+#include "command.h"
#include "config.h"
+#include "ext-proxy.h"
#include "main.h"
#include "normal.h"
-#include "ascii.h"
-#include "command.h"
-#include "hints.h"
-#include "dom.h"
-#include "history.h"
+#include "scripts/scripts.h"
#include "util.h"
typedef enum {
@@ -47,32 +48,31 @@ typedef struct NormalCmdInfo_s {
static NormalCmdInfo info = {0, '\0', '\0', PHASE_START};
-typedef VbResult (*NormalCommand)(const NormalCmdInfo *info);
-
-static VbResult normal_clear_input(const NormalCmdInfo *info);
-static VbResult normal_descent(const NormalCmdInfo *info);
-static VbResult normal_ex(const NormalCmdInfo *info);
-static VbResult normal_focus_input(const NormalCmdInfo *info);
-static VbResult normal_g_cmd(const NormalCmdInfo *info);
-static VbResult normal_hint(const NormalCmdInfo *info);
-static VbResult normal_do_hint(const char *prompt);
-static VbResult normal_increment_decrement(const NormalCmdInfo *info);
-static VbResult normal_input_open(const NormalCmdInfo *info);
-static VbResult normal_mark(const NormalCmdInfo *info);
-static VbResult normal_navigate(const NormalCmdInfo *info);
-static VbResult normal_open_clipboard(const NormalCmdInfo *info);
-static VbResult normal_open(const NormalCmdInfo *info);
-static VbResult normal_pass(const NormalCmdInfo *info);
-static VbResult normal_prevnext(const NormalCmdInfo *info);
-static VbResult normal_queue(const NormalCmdInfo *info);
-static VbResult normal_quit(const NormalCmdInfo *info);
-static VbResult normal_scroll(const NormalCmdInfo *info);
-static VbResult normal_search(const NormalCmdInfo *info);
-static VbResult normal_search_selection(const NormalCmdInfo *info);
-static VbResult normal_view_inspector(const NormalCmdInfo *info);
-static VbResult normal_view_source(const NormalCmdInfo *info);
-static VbResult normal_yank(const NormalCmdInfo *info);
-static VbResult normal_zoom(const NormalCmdInfo *info);
+typedef VbResult (*NormalCommand)(Client *c, const NormalCmdInfo *info);
+
+static VbResult normal_clear_input(Client *c, const NormalCmdInfo *info);
+static VbResult normal_descent(Client *c, const NormalCmdInfo *info);
+static VbResult normal_ex(Client *c, const NormalCmdInfo *info);
+static VbResult normal_g_cmd(Client *c, const NormalCmdInfo *info);
+static VbResult normal_hint(Client *c, const NormalCmdInfo *info);
+static VbResult normal_do_hint(Client *c, const char *prompt);
+static VbResult normal_increment_decrement(Client *c, const NormalCmdInfo *info);
+static VbResult normal_input_open(Client *c, const NormalCmdInfo *info);
+static VbResult normal_mark(Client *c, const NormalCmdInfo *info);
+static VbResult normal_navigate(Client *c, const NormalCmdInfo *info);
+static VbResult normal_open_clipboard(Client *c, const NormalCmdInfo *info);
+static VbResult normal_open(Client *c, const NormalCmdInfo *info);
+static VbResult normal_pass(Client *c, const NormalCmdInfo *info);
+static VbResult normal_prevnext(Client *c, const NormalCmdInfo *info);
+static VbResult normal_queue(Client *c, const NormalCmdInfo *info);
+static VbResult normal_quit(Client *c, const NormalCmdInfo *info);
+static VbResult normal_scroll(Client *c, const NormalCmdInfo *info);
+static VbResult normal_search(Client *c, const NormalCmdInfo *info);
+static VbResult normal_search_selection(Client *c, const NormalCmdInfo *info);
+static VbResult normal_view_inspector(Client *c, const NormalCmdInfo *info);
+static VbResult normal_view_source(Client *c, const NormalCmdInfo *info);
+static VbResult normal_yank(Client *c, const NormalCmdInfo *info);
+static VbResult normal_zoom(Client *c, const NormalCmdInfo *info);
static struct {
NormalCommand func;
@@ -171,7 +171,7 @@ static struct {
/* [ 0x5b */ {normal_prevnext},
/* \ 0x5c */ {NULL},
/* ] 0x5d */ {normal_prevnext},
-/* ^ 0x5e */ {normal_scroll},
+/* ^ 0x5e */ {NULL},
/* _ 0x5f */ {NULL},
/* ` 0x60 */ {NULL},
/* a 0x61 */ {NULL},
@@ -207,34 +207,33 @@ static struct {
/* DEL 0x7f */ {NULL},
};
-extern VbCore vb;
+extern struct Vimb vb;
/**
* Function called when vimb enters the normal mode.
*/
-void normal_enter(void)
+void normal_enter(Client *c)
{
- dom_clear_focus(vb.gui.webview);
+ webkit_web_view_run_javascript(c->webview, "document.activeElement.blur();", NULL, NULL, NULL);
/* Make sure that when the browser area becomes visible, it will get mouse
* and keyboard events */
- gtk_widget_grab_focus(GTK_WIDGET(vb.gui.webview));
- hints_clear();
+ gtk_widget_grab_focus(GTK_WIDGET(c->webview));
+ /* TODO clear possible active hints */
}
/**
* Called when the normal mode is left.
*/
-void normal_leave(void)
+void normal_leave(Client *c)
{
- command_search(&((Arg){0}));
+ command_search(c, &((Arg){0}));
}
/**
* Handles the keypress events from webview and inputbox.
*/
-VbResult normal_keypress(int key)
+VbResult normal_keypress(Client *c, int key)
{
- State *s = &vb.state;
VbResult res;
switch (info.phase) {
@@ -248,10 +247,10 @@ VbResult normal_keypress(int key)
/* handle commands that needs additional char */
info.phase = PHASE_KEY2;
info.key = key;
- vb.mode->flags |= FLAG_NOMAP;
+ c->mode->flags |= FLAG_NOMAP;
} else if (key == '"') {
info.phase = PHASE_REG;
- vb.mode->flags |= FLAG_NOMAP;
+ c->mode->flags |= FLAG_NOMAP;
} else {
info.key = key;
info.phase = PHASE_COMPLETE;
@@ -264,7 +263,7 @@ VbResult normal_keypress(int key)
/* hinting g; mode requires a third key */
if (info.key == 'g' && info.key2 == ';') {
info.phase = PHASE_KEY3;
- vb.mode->flags |= FLAG_NOMAP;
+ c->mode->flags |= FLAG_NOMAP;
} else {
info.phase = PHASE_COMPLETE;
}
@@ -276,7 +275,7 @@ VbResult normal_keypress(int key)
break;
case PHASE_REG:
- if (strchr(VB_REG_CHARS, key)) {
+ if (strchr(REG_CHARS, key)) {
info.reg = key;
info.phase = PHASE_START;
} else {
@@ -292,10 +291,10 @@ VbResult normal_keypress(int key)
/* TODO allow more commands - some that are looked up via command key
* direct and those that are searched via binary search */
if ((guchar)info.key <= LENGTH(commands) && commands[(guchar)info.key].func) {
- res = commands[(guchar)info.key].func(&info);
+ res = commands[(guchar)info.key].func(c, &info);
} else {
/* let gtk handle the keyevent if we have no command attached to it */
- s->processed_key = false;
+ c->state.processed_key = FALSE;
res = RESULT_COMPLETE;
}
@@ -312,51 +311,48 @@ VbResult normal_keypress(int key)
/**
* Function called when vimb enters the passthrough mode.
*/
-void pass_enter(void)
+void pass_enter(Client *c)
{
- vb_update_mode_label("-- PASS THROUGH --");
+ vb_modelabel_update(c, "-- PASS THROUGH --");
}
/**
* Called when passthrough mode is left.
*/
-void pass_leave(void)
+void pass_leave(Client *c)
{
- vb_update_mode_label("");
+ vb_modelabel_update(c, "");
}
-VbResult pass_keypress(int key)
+VbResult pass_keypress(Client *c, int key)
{
if (key == CTRL('[')) { /* esc */
- vb_enter('n');
+ vb_enter(c, 'n');
}
- vb.state.processed_key = false;
+ c->state.processed_key = FALSE;
return RESULT_COMPLETE;
}
-static VbResult normal_clear_input(const NormalCmdInfo *info)
+static VbResult normal_clear_input(Client *c, const NormalCmdInfo *info)
{
- /* if there's a text selection, deselect it */
- char *clipboard_text = gtk_clipboard_wait_for_text(PRIMARY_CLIPBOARD());
- gtk_clipboard_clear(PRIMARY_CLIPBOARD());
- if (clipboard_text) {
- gtk_clipboard_set_text(PRIMARY_CLIPBOARD(), clipboard_text, -1);
- }
- g_free(clipboard_text);
+ gtk_widget_grab_focus(GTK_WIDGET(c->webview));
- gtk_widget_grab_focus(GTK_WIDGET(vb.gui.webview));
- vb_echo(VB_MSG_NORMAL, false, "");
- command_search(&((Arg){0}));
+ /* Clear the inputbox and change the style to normal to reset also the
+ * possible colored error background. */
+ vb_echo(c, MSG_NORMAL, FALSE, "");
+
+ /* Unset search highlightning. */
+ command_search(c, &((Arg){0}));
return RESULT_COMPLETE;
}
-static VbResult normal_descent(const NormalCmdInfo *info)
+static VbResult normal_descent(Client *c, const NormalCmdInfo *info)
{
int count = info->count ? info->count : 1;
const char *uri, *p = NULL, *domain = NULL;
- uri = vb.state.uri;
+ uri = c->state.uri;
/* get domain part */
if (!uri || !*uri
@@ -396,73 +392,68 @@ static VbResult normal_descent(const NormalCmdInfo *info)
p = domain;
}
- Arg a = {VB_TARGET_CURRENT};
+ Arg a = {TARGET_CURRENT};
a.s = g_strndup(uri, p - uri + 1);
- vb_load_uri(&a);
+ vb_load_uri(c, &a);
g_free(a.s);
return RESULT_COMPLETE;
}
-static VbResult normal_ex(const NormalCmdInfo *info)
+static VbResult normal_ex(Client *c, const NormalCmdInfo *info)
{
if (info->key == 'F') {
- vb_enter_prompt('c', ";t", true);
+ vb_enter_prompt(c, 'c', ";t", TRUE);
} else if (info->key == 'f') {
- vb_enter_prompt('c', ";o", true);
+ vb_enter_prompt(c, 'c', ";o", TRUE);
} else {
char prompt[2] = {info->key, '\0'};
- vb_enter_prompt('c', prompt, true);
+ vb_enter_prompt(c, 'c', prompt, TRUE);
}
return RESULT_COMPLETE;
}
-static VbResult normal_focus_input(const NormalCmdInfo *info)
-{
- dom_focus_input(webkit_web_view_get_dom_document(vb.gui.webview));
- return RESULT_COMPLETE;
-}
-
-static VbResult normal_g_cmd(const NormalCmdInfo *info)
+static VbResult normal_g_cmd(Client *c, const NormalCmdInfo *info)
{
Arg a;
switch (info->key2) {
case ';': {
const char prompt[4] = {'g', ';', info->key3, 0};
- return normal_do_hint(prompt);
+ return normal_do_hint(c, prompt);
}
case 'F':
- return normal_view_inspector(info);
+ return normal_view_inspector(c, info);
case 'f':
- normal_view_source(info);
+ normal_view_source(c, info);
case 'g':
- return normal_scroll(info);
+ return normal_scroll(c, info);
case 'H':
case 'h':
- a.i = info->key2 == 'H' ? VB_TARGET_NEW : VB_TARGET_CURRENT;
+ a.i = info->key2 == 'H' ? TARGET_NEW : TARGET_CURRENT;
a.s = NULL;
- vb_load_uri(&a);
+ vb_load_uri(c, &a);
return RESULT_COMPLETE;
case 'i':
- return normal_focus_input(info);
+ ext_proxy_focus_input(c);
+ return RESULT_COMPLETE;
case 'U':
case 'u':
- return normal_descent(info);
+ return normal_descent(c, info);
}
return RESULT_ERROR;
}
-static VbResult normal_hint(const NormalCmdInfo *info)
+static VbResult normal_hint(Client *c, const NormalCmdInfo *info)
{
const char prompt[3] = {info->key, info->key2, 0};
@@ -471,92 +462,75 @@ static VbResult normal_hint(const NormalCmdInfo *info)
* somewhere else - it's only use is for hinting. It might be better to
* allow to set various data to the mode itself to avoid toggling
* variables in global skope. */
- vb.state.current_register = info->reg;
- return normal_do_hint(prompt);
+ c->state.current_register = info->reg;
+ return normal_do_hint(c, prompt);
}
-static VbResult normal_do_hint(const char *prompt)
+static VbResult normal_do_hint(Client *c, const char *prompt)
{
- /* check if this is a valid hint mode */
- if (!hints_parse_prompt(prompt, NULL, NULL)) {
- return RESULT_ERROR;
- }
+ /* TODO check if the prompt is of a valid hint mode */
- vb_enter_prompt('c', prompt, true);
+ vb_enter_prompt(c, 'c', prompt, TRUE);
return RESULT_COMPLETE;
}
-static VbResult normal_increment_decrement(const NormalCmdInfo *info)
+static VbResult normal_increment_decrement(Client *c, const NormalCmdInfo *info)
{
+ char *js;
int count = info->count ? info->count : 1;
- hints_increment_uri(info->key == CTRL('A') ? count : -count);
+
+ js = g_strdup_printf(INCREMENT_URI_NUMBER, info->key == CTRL('A') ? count : -count);
+ webkit_web_view_run_javascript(c->webview, js, NULL, NULL, NULL);
+ g_free(js);
return RESULT_COMPLETE;
}
-static VbResult normal_input_open(const NormalCmdInfo *info)
+static VbResult normal_input_open(Client *c, const NormalCmdInfo *info)
{
if (strchr("ot", info->key)) {
- vb_set_input_text(info->key == 't' ? ":tabopen " : ":open ");
+ vb_input_set_text(c, info->key == 't' ? ":tabopen " : ":open ");
} else {
- vb_echo(
- VB_MSG_NORMAL, false,
- ":%s %s", info->key == 'T' ? "tabopen" : "open", vb.state.uri
- );
+ vb_echo(c, MSG_NORMAL, FALSE,
+ ":%s %s", info->key == 'T' ? "tabopen" : "open", c->state.uri);
}
/* switch mode after setting the input text to not trigger the
* commands modes input change handler */
- vb_enter_prompt('c', ":", false);
+ vb_enter_prompt(c, 'c', ":", FALSE);
return RESULT_COMPLETE;
}
-static VbResult normal_mark(const NormalCmdInfo *info)
+static VbResult normal_mark(Client *c, const NormalCmdInfo *info)
{
- gdouble current;
- char *mark;
- int idx;
-
- /* check if the second char is a valid mark char */
- if (!(mark = strchr(VB_MARK_CHARS, info->key2))) {
- return RESULT_ERROR;
- }
-
- /* get the index of the mark char */
- idx = mark - VB_MARK_CHARS;
-
- if ('m' == info->key) {
- vb.state.marks[idx] = gtk_adjustment_get_value(vb.gui.adjust_v);
- } else {
- /* check if the mark was set */
- if ((int)(vb.state.marks[idx] - .5) < 0) {
- return RESULT_ERROR;
- }
-
- current = gtk_adjustment_get_value(vb.gui.adjust_v);
-
- /* jump to the location */
- gtk_adjustment_set_value(vb.gui.adjust_v, vb.state.marks[idx]);
-
- /* save previous adjust as last position */
- vb.state.marks[VB_MARK_TICK] = current;
- }
+ /* TODO implement setting of marks - we need to get the position in the pagee from the Webextension */
return RESULT_COMPLETE;
}
-static VbResult normal_navigate(const NormalCmdInfo *info)
+static VbResult normal_navigate(Client *c, const NormalCmdInfo *info)
{
int count;
+ WebKitBackForwardList *list;
+ WebKitBackForwardListItem *item;
- WebKitWebView *view = vb.gui.webview;
+ WebKitWebView *view = c->webview;
switch (info->key) {
case CTRL('I'): /* fall through */
case CTRL('O'):
count = info->count ? info->count : 1;
if (info->key == CTRL('O')) {
- count *= -1;
+ if (webkit_web_view_can_go_back(view)) {
+ list = webkit_web_view_get_back_forward_list(view);
+ item = webkit_back_forward_list_get_nth_item(list, -1 * count);
+ webkit_web_view_go_to_back_forward_list_item(view, item);
+ }
+ } else {
+ if (webkit_web_view_can_go_forward(view)) {
+ list = webkit_web_view_get_back_forward_list(view);
+ item = webkit_back_forward_list_get_nth_item(list, count);
+ webkit_web_view_go_to_back_forward_list_item(view, item);
+ }
}
- webkit_web_view_go_back_or_forward(view, count);
break;
case 'r':
@@ -575,23 +549,23 @@ static VbResult normal_navigate(const NormalCmdInfo *info)
return RESULT_COMPLETE;
}
-static VbResult normal_open_clipboard(const NormalCmdInfo *info)
+static VbResult normal_open_clipboard(Client *c, const NormalCmdInfo *info)
{
- Arg a = {info->key == 'P' ? VB_TARGET_NEW : VB_TARGET_CURRENT};
+ Arg a = {info->key == 'P' ? TARGET_NEW : TARGET_CURRENT};
/* if register is not the default - read out of the internal register */
if (info->reg) {
- a.s = g_strdup(vb_register_get(info->reg));
+ a.s = g_strdup(vb_register_get(c, info->reg));
} else {
/* if no register is given use the system clipboard */
- a.s = gtk_clipboard_wait_for_text(PRIMARY_CLIPBOARD());
+ a.s = gtk_clipboard_wait_for_text(gtk_clipboard_get(GDK_SELECTION_PRIMARY));
if (!a.s) {
- a.s = gtk_clipboard_wait_for_text(SECONDARY_CLIPBOARD());
+ a.s = gtk_clipboard_wait_for_text(gtk_clipboard_get(GDK_NONE));
}
}
if (a.s) {
- vb_load_uri(&a);
+ vb_load_uri(c, &a);
g_free(a.s);
return RESULT_COMPLETE;
@@ -600,155 +574,155 @@ static VbResult normal_open_clipboard(const NormalCmdInfo *info)
return RESULT_ERROR;
}
-static VbResult normal_open(const NormalCmdInfo *info)
+/**
+ * Open the last closed page.
+ */
+static VbResult normal_open(Client *c, const NormalCmdInfo *info)
{
- char *uri;
Arg a;
+ char *file;
- uri = util_file_pop_line(vb.files[FILES_CLOSED], NULL);
- if (!uri) {
- return RESULT_ERROR;
- }
+ file = g_build_filename(util_get_config_dir(), FILE_CLOSED, NULL);
+ a.i = info->key == 'U' ? TARGET_NEW : TARGET_CURRENT;
+ a.s = util_get_file_contents(file, NULL);
+ g_free(file);
- /* open last closed */
- a.i = info->key == 'U' ? VB_TARGET_NEW : VB_TARGET_CURRENT;
- a.s = uri;
- vb_load_uri(&a);
- g_free(uri);
+ vb_load_uri(c, &a);
+ g_free(a.s);
return RESULT_COMPLETE;
}
-static VbResult normal_pass(const NormalCmdInfo *info)
+static VbResult normal_pass(Client *c, const NormalCmdInfo *info)
{
- vb_enter('p');
+ vb_enter(c, 'p');
return RESULT_COMPLETE;
}
-static VbResult normal_prevnext(const NormalCmdInfo *info)
+static VbResult normal_prevnext(Client *c, const NormalCmdInfo *info)
{
+#if 0 /* TODO need hinting to be available */
int count = info->count ? info->count : 1;
if (info->key2 == ']') {
- hints_follow_link(false, count);
+ hints_follow_link(FALSE, count);
} else if (info->key2 == '[') {
- hints_follow_link(true, count);
+ hints_follow_link(TRUE, count);
} else {
return RESULT_ERROR;
}
+#endif
return RESULT_COMPLETE;
}
-static VbResult normal_queue(const NormalCmdInfo *info)
+static VbResult normal_queue(Client *c, const NormalCmdInfo *info)
{
-#ifdef FEATURE_QUEUE
- command_queue(&((Arg){COMMAND_QUEUE_POP}));
-#endif
+ /* TODO run next uri from queu and remove it from */
return RESULT_COMPLETE;
}
-static VbResult normal_quit(const NormalCmdInfo *info)
+static VbResult normal_quit(Client *c, const NormalCmdInfo *info)
{
- vb_quit(false);
+ vb_quit(c, FALSE);
return RESULT_COMPLETE;
}
-static VbResult normal_scroll(const NormalCmdInfo *info)
+static VbResult normal_scroll(Client *c, const NormalCmdInfo *info)
{
- GtkAdjustment *adjust;
- gdouble value, max, new;
- int count = info->count ? info->count : 1;
+ int x = 0, y = 0, page_height = 0, count = info->count ? info->count : 1;
+ char *js;
+ GtkAllocation alloc;
+
+ /* The overall page height is only required for the <C-*> commands. */
+ if (VB_IS_CTRL(info->key)) {
+ gtk_widget_get_allocation(GTK_WIDGET(c->webview), &alloc);
+ page_height = (int)alloc.height;
+ }
- /* TODO split this into more functions - reduce similar code */
switch (info->key) {
- case 'h':
- adjust = vb.gui.adjust_h;
- value = vb.config.scrollstep;
- new = gtk_adjustment_get_value(adjust) - value * count;
- break;
case 'j':
- adjust = vb.gui.adjust_v;
- value = vb.config.scrollstep;
- new = gtk_adjustment_get_value(adjust) + value * count;
+ y = count * c->config.scrollstep;
+ break;
+ case 'h':
+ x = -count * c->config.scrollstep;
break;
case 'k':
- adjust = vb.gui.adjust_v;
- value = vb.config.scrollstep;
- new = gtk_adjustment_get_value(adjust) - value * count;
+ y = -count * c->config.scrollstep;
break;
case 'l':
- adjust = vb.gui.adjust_h;
- value = vb.config.scrollstep;
- new = gtk_adjustment_get_value(adjust) + value * count;
+ x = count * c->config.scrollstep;
break;
case CTRL('D'):
- adjust = vb.gui.adjust_v;
- value = gtk_adjustment_get_page_size(adjust) / 2;
- new = gtk_adjustment_get_value(adjust) + value * count;
+ y = count * page_height / 2;
break;
case CTRL('U'):
- adjust = vb.gui.adjust_v;
- value = gtk_adjustment_get_page_size(adjust) / 2;
- new = gtk_adjustment_get_value(adjust) - value * count;
+ y = -count * page_height / 2;
break;
case CTRL('F'):
- adjust = vb.gui.adjust_v;
- value = gtk_adjustment_get_page_size(adjust);
- new = gtk_adjustment_get_value(adjust) + value * count;
+ y = count * page_height;
break;
case CTRL('B'):
- adjust = vb.gui.adjust_v;
- value = gtk_adjustment_get_page_size(adjust);
- new = gtk_adjustment_get_value(adjust) - value * count;
+ y = -count * page_height;
break;
case 'G':
- adjust = vb.gui.adjust_v;
- max = gtk_adjustment_get_upper(adjust) - gtk_adjustment_get_page_size(adjust);
- new = info->count ? (max * info->count / 100) : gtk_adjustment_get_upper(adjust);
- /* save the position to mark ' */
- vb.state.marks[VB_MARK_TICK] = gtk_adjustment_get_value(adjust);
- break;
- case '0': /* fall through */
- case '^':
- adjust = vb.gui.adjust_h;
- new = gtk_adjustment_get_lower(adjust);
- break;
- case '$':
- adjust = vb.gui.adjust_h;
- new = gtk_adjustment_get_upper(adjust);
- break;
+ if (info->count) {
+ js = g_strdup_printf(
+ "window.scroll(window.scrollX, %d * (1 + (document.height - window.innerHeight) / 100));",
+ info->count);
+ webkit_web_view_run_javascript(c->webview, js, NULL, NULL, NULL);
+ g_free(js);
+ return RESULT_COMPLETE;
+ }
+ /* Without count scroll to the end of the page. */
+ webkit_web_view_run_javascript(c->webview, "window.scroll(window.scrollX, document.body.scrollHeight);", NULL, NULL, NULL);
+ return RESULT_COMPLETE;
+ case '0':
+ webkit_web_view_run_javascript(c->webview, "window.scroll(0, window.scrollY);", NULL, NULL, NULL);
+ return RESULT_COMPLETE;
+ case '$':
+ webkit_web_view_run_javascript(c->webview, "window.scroll(document.body.scrollWidth, window.scrollY);", NULL, NULL, NULL);
+ return RESULT_COMPLETE;
default:
if (info->key2 == 'g') {
- adjust = vb.gui.adjust_v;
- max = gtk_adjustment_get_upper(adjust) - gtk_adjustment_get_page_size(adjust);
- new = info->count ? (max * info->count / 100) : gtk_adjustment_get_lower(adjust);
- break;
+ if (info->count) {
+ js = g_strdup_printf(
+ "window.scroll(window.scrollX, %d * (1 + (document.height - window.innerHeight) / 100));",
+ info->count);
+ webkit_web_view_run_javascript(c->webview, js, NULL, NULL, NULL);
+ g_free(js);
+ return RESULT_COMPLETE;
+ }
+ /* Without count gg scrolls to the top of the page. */
+ webkit_web_view_run_javascript(c->webview, "window.scroll(window.scrollX, 0);", NULL, NULL, NULL);
+ return RESULT_COMPLETE;
}
return RESULT_ERROR;
}
- max = gtk_adjustment_get_upper(adjust) - gtk_adjustment_get_page_size(adjust);
- gtk_adjustment_set_value(adjust, new > max ? max : new);
+ js = g_strdup_printf("window.scrollBy(%d,%d);", x, y);
+ webkit_web_view_run_javascript(c->webview, js, NULL, NULL, NULL);
+ g_free(js);
return RESULT_COMPLETE;
}
-static VbResult normal_search(const NormalCmdInfo *info)
+static VbResult normal_search(Client *c, const NormalCmdInfo *info)
{
int count = (info->count > 0) ? info->count : 1;
- command_search(&((Arg){info->key == 'n' ? count : -count}));
+ command_search(c, &((Arg){info->key == 'n' ? count : -count}));
+
return RESULT_COMPLETE;
}
-static VbResult normal_search_selection(const NormalCmdInfo *info)
+static VbResult normal_search_selection(Client *c, const NormalCmdInfo *info)
{
int count;
char *query;
/* there is no function to get the selected text so we copy current
* selection to clipboard */
- webkit_web_view_copy_clipboard(vb.gui.webview);
- query = gtk_clipboard_wait_for_text(PRIMARY_CLIPBOARD());
+ webkit_web_view_execute_editing_command(c->webview, WEBKIT_EDITING_COMMAND_COPY);
+ query = gtk_clipboard_wait_for_text(gtk_clipboard_get(GDK_SELECTION_PRIMARY));
if (!query) {
return RESULT_ERROR;
}
@@ -756,52 +730,54 @@ static VbResult normal_search_selection(const NormalCmdInfo *info)
/* stopp possible existing search and the search highlights before
* starting the new search query */
- command_search(&((Arg){0}));
- command_search(&((Arg){info->key == '*' ? count : -count, query}));
+ command_search(c, &((Arg){0}));
+ command_search(c, &((Arg){info->key == '*' ? count : -count, query}));
g_free(query);
return RESULT_COMPLETE;
}
-static VbResult normal_view_inspector(const NormalCmdInfo *info)
+static VbResult normal_view_inspector(Client *c, const NormalCmdInfo *info)
{
- gboolean enabled;
- WebKitWebSettings *settings = webkit_web_view_get_settings(vb.gui.webview);
+ WebKitWebInspector *inspector;
+ WebKitSettings *settings;
+
+ settings = webkit_web_view_get_settings(c->webview);
+ inspector = webkit_web_view_get_inspector(c->webview);
+
+ /* Try to get the inspected uri to identify if the inspector is shown at
+ * the time or not. */
+ if (webkit_web_inspector_get_inspected_uri(inspector)) {
+ webkit_web_inspector_close(inspector);
+ } else if (webkit_settings_get_enable_developer_extras(settings)) {
+ webkit_web_inspector_show(inspector);
+ } else {
+ /* Inform the user on attempt to enable webinspector when the
+ * developer extra are not enabled. */
+ vb_echo(c, MSG_ERROR, TRUE, "webinspector is not enabled");
- g_object_get(G_OBJECT(settings), "enable-developer-extras", &enabled, NULL);
- if (enabled) {
- if (vb.state.is_inspecting) {
- webkit_web_inspector_close(vb.gui.inspector);
- } else {
- webkit_web_inspector_show(vb.gui.inspector);
- }
- return RESULT_COMPLETE;
+ return RESULT_ERROR;
}
-
- vb_echo(VB_MSG_ERROR, true, "webinspector is not enabled");
- return RESULT_ERROR;
+ return RESULT_COMPLETE;
}
-static VbResult normal_view_source(const NormalCmdInfo *info)
+static VbResult normal_view_source(Client *c, const NormalCmdInfo *info)
{
- gboolean mode = webkit_web_view_get_view_source_mode(vb.gui.webview);
- webkit_web_view_set_view_source_mode(vb.gui.webview, !mode);
- webkit_web_view_reload(vb.gui.webview);
+ /* TODO the source mode isn't supported anymore use external editor for this */
return RESULT_COMPLETE;
}
-static VbResult normal_yank(const NormalCmdInfo *info)
+static VbResult normal_yank(Client *c, const NormalCmdInfo *info)
{
Arg a = {info->key == 'Y' ? COMMAND_YANK_SELECTION : COMMAND_YANK_URI};
- return command_yank(&a, info->reg) ? RESULT_COMPLETE : RESULT_ERROR;
+ return command_yank(c, &a, info->reg) ? RESULT_COMPLETE : RESULT_ERROR;
}
-static VbResult normal_zoom(const NormalCmdInfo *info)
+static VbResult normal_zoom(Client *c, const NormalCmdInfo *info)
{
- float step, level, count;
- WebKitWebSettings *setting;
- WebKitWebView *view = vb.gui.webview;
+ float step = 0.1, level, count;
+ WebKitWebView *view = c->webview;
/* check if the second key is allowed */
if (!strchr("iIoOz", info->key2)) {
@@ -811,20 +787,12 @@ static VbResult normal_zoom(const NormalCmdInfo *info)
count = info->count ? (float)info->count : 1.0;
if (info->key2 == 'z') { /* zz reset zoom */
-#ifdef FEATURE_HIGH_DPI
- /* to set the zoom for high dpi displays we need full content zoom */
- webkit_web_view_set_full_content_zoom(view, true);
-#endif
- webkit_web_view_set_zoom_level(view, vb.config.default_zoom);
+ webkit_web_view_set_zoom_level(view, 1.0);
return RESULT_COMPLETE;
}
- level = webkit_web_view_get_zoom_level(view);
- setting = webkit_web_view_get_settings(view);
- g_object_get(G_OBJECT(setting), "zoom-step", &step, NULL);
-
- webkit_web_view_set_full_content_zoom(view, VB_IS_UPPER(info->key2));
+ level= webkit_web_view_get_zoom_level(view);
/* calculate the new zoom level */
if (info->key2 == 'i' || info->key2 == 'I') {
@@ -834,6 +802,7 @@ static VbResult normal_zoom(const NormalCmdInfo *info)
}
/* apply the new zoom level */
+ webkit_settings_set_zoom_text_only(webkit_web_view_get_settings(view), VB_IS_LOWER(info->key2));
webkit_web_view_set_zoom_level(view, level);
return RESULT_COMPLETE;
diff --git a/src/normal.h b/src/normal.h
index 710a553..e4f626c 100644
--- a/src/normal.h
+++ b/src/normal.h
@@ -23,11 +23,11 @@
#include "config.h"
#include "main.h"
-void normal_enter(void);
-void normal_leave(void);
-VbResult normal_keypress(int key);
-void pass_enter(void);
-void pass_leave(void);
-VbResult pass_keypress(int key);
+void normal_enter(Client *c);
+void normal_leave(Client *c);
+VbResult normal_keypress(Client *c, int key);
+void pass_enter(Client *c);
+void pass_leave(Client *c);
+VbResult pass_keypress(Client *c, int key);
#endif /* end of include guard: _NORMAL_H */
diff --git a/src/scripts/.gitignore b/src/scripts/.gitignore
new file mode 100644
index 0000000..763376e
--- /dev/null
+++ b/src/scripts/.gitignore
@@ -0,0 +1 @@
+scripts.h
diff --git a/src/scripts/Makefile b/src/scripts/Makefile
new file mode 100644
index 0000000..32af191
--- /dev/null
+++ b/src/scripts/Makefile
@@ -0,0 +1,19 @@
+BASEDIR=../..
+include $(BASEDIR)/config.mk
+
+JSFILES = $(wildcard *.js)
+
+all: scripts.h
+
+clean:
+ $(RM) scripts.h
+
+scripts.h: $(JSFILES)
+ @echo "create $@ from *.js"
+ @echo > $@
+ @for file in $(JSFILES); do \
+ ./js2h.sh $$file >> $@; \
+ done
+
+.PHONY: all clean
+
diff --git a/src/scripts/increment_uri_number.js b/src/scripts/increment_uri_number.js
new file mode 100644
index 0000000..d90adfb
--- /dev/null
+++ b/src/scripts/increment_uri_number.js
@@ -0,0 +1,16 @@
+/* TODO maybe it's better to inject this in the webview as method */
+/* and to call it if needed */
+var c = %d, on, nn, m = location.href.match(/(.*?)(\d+)(\D*)$/);
+if (m) {
+ on = m[2];
+ nn = String(Math.max(parseInt(on) + c, 0));
+ /* keep prepending zeros */
+ if (/^0/.test(on)) {
+ while (nn.length < on.length) {
+ nn = "0" + nn;
+ }
+ }
+ m[2] = nn;
+
+ location.href = m.slice(1).join("");
+}
diff --git a/src/scripts/js2h.sh b/src/scripts/js2h.sh
new file mode 100755
index 0000000..b177085
--- /dev/null
+++ b/src/scripts/js2h.sh
@@ -0,0 +1,38 @@
+#!/bin/sh
+#
+# Defined a constant for given JavaScript file. The file name is used to get
+# the constant name and the contents are minifed and escaped as the value.
+# ./js.h do_fancy_stuff.js creates somethings like
+# #define DO_FANCY_STUFF "Escaped JavaScriptCode"
+
+FILE="$1"
+
+# Check if the file exists.
+if [ ! -r "$FILE" ]; then
+ echo "File $FILE does not exist or is not readable" >&2
+ exit 1
+fi
+
+# Remove the .js file extension and turn all chars to upper case to get the
+# constant name.
+CONSTANT=$(echo "$FILE" | sed 's:.js$::g' | tr a-z A-Z)
+
+# minify the script
+cat $FILE | \
+# removove single line comments
+sed -e 's|^//.*$||g' | \
+# remove linebreaks
+tr '\n\r' ' ' | \
+# remove unneeded whitespace
+sed -e 's:/\*[^*]*\*/::g' \
+ -e 's|[ ]\{2,\}| |g' \
+ -e 's|^ ||g' \
+ -e "s|[ ]\{0,\}\([-!?<>:=(){};+\&\"',\|]\)[ ]\{0,\}|\1|g" \
+ -e 's|"+"||g' | \
+# ecaspe
+sed -e 's|\\x20| |g' \
+ -e 's|\\|\\\\|g' \
+ -e 's|"|\\"|g' | \
+# write opener with the starting and ending quote char
+sed -e "1s/^/#define $CONSTANT \"/" \
+ -e '$s/$/"\n/'
diff --git a/src/setting.c b/src/setting.c
index 9c0492f..79d3ebb 100644
--- a/src/setting.c
+++ b/src/setting.c
@@ -17,27 +17,15 @@
* along with this program. If not, see http://www.gnu.org/licenses/.
*/
-#include "config.h"
+#include <glib.h>
#include <string.h>
+
+#include "completion.h"
+#include "config.h"
+#include "ext-proxy.h"
#include "main.h"
#include "setting.h"
#include "shortcut.h"
-#include "handlers.h"
-#include "util.h"
-#include "completion.h"
-#include "js.h"
-#ifdef FEATURE_HSTS
-#include "hsts.h"
-#endif
-#include "arh.h"
-
-typedef enum {
- TYPE_BOOLEAN,
- TYPE_INTEGER,
- TYPE_CHAR,
- TYPE_COLOR,
- TYPE_FONT,
-} Type;
typedef enum {
SETTING_SET, /* :set option=value */
@@ -53,194 +41,111 @@ enum {
FLAG_NODUP = (1<<2), /* don't allow duplicate strings within list values */
};
-extern VbCore vb;
-
-static int setting_set_value(Setting *prop, void *value, SettingType type);
+static int setting_set_value(Client *c, Setting *prop, void *value, SettingType type);
static gboolean prepare_setting_value(Setting *prop, void *value, SettingType type, void **newvalue);
-static gboolean setting_add(const char *name, int type, void *value,
+static gboolean setting_add(Client *c, const char *name, DataType type, void *value,
SettingFunction setter, int flags, void *data);
-static void setting_print(Setting *s);
+static void setting_print(Client *c, Setting *s);
static void setting_free(Setting *s);
-static int webkit(const char *name, int type, void *value, void *data);
-static int pagecache(const char *name, int type, void *value, void *data);
-static int soup(const char *name, int type, void *value, void *data);
-static int internal(const char *name, int type, void *value, void *data);
-static int input_autohide(const char *name, int type, void *value, void *data);
-static int input_color(const char *name, int type, void *value, void *data);
-static int statusbar(const char *name, int type, void *value, void *data);
-static int status_color(const char *name, int type, void *value, void *data);
-static int input_font(const char *name, int type, void *value, void *data);
-static int status_font(const char *name, int type, void *value, void *data);
-gboolean setting_fill_completion(GtkListStore *store, const char *input);
-#ifdef FEATURE_COOKIE
-static int cookie_accept(const char *name, int type, void *value, void *data);
-#endif
-static int ca_bundle(const char *name, int type, void *value, void *data);
-static int proxy(const char *name, int type, void *value, void *data);
-static int user_style(const char *name, int type, void *value, void *data);
-static int headers(const char *name, int type, void *value, void *data);
-#ifdef FEATURE_ARH
-static int autoresponseheader(const char *name, int type, void *value, void *data);
-#endif
-static int prevnext(const char *name, int type, void *value, void *data);
-static int fullscreen(const char *name, int type, void *value, void *data);
-#ifdef FEATURE_HSTS
-static int hsts(const char *name, int type, void *value, void *data);
-#endif
-#ifdef FEATURE_SOUP_CACHE
-static int soup_cache(const char *name, int type, void *value, void *data);
-#endif
-static gboolean validate_js_regexp_list(const char *pattern);
-void setting_init()
+static int cookie_accept(Client *c, const char *name, DataType type, void *value, void *data);
+static int fullscreen(Client *c, const char *name, DataType type, void *value, void *data);
+static int input_autohide(Client *c, const char *name, DataType type, void *value, void *data);
+static int internal(Client *c, const char *name, DataType type, void *value, void *data);
+static int headers(Client *c, const char *name, DataType type, void *value, void *data);
+static int user_scripts(Client *c, const char *name, DataType type, void *value, void *data);
+static int user_style(Client *c, const char *name, DataType type, void *value, void *data);
+static int statusbar(Client *c, const char *name, DataType type, void *value, void *data);
+static int tls_policy(Client *c, const char *name, DataType type, void *value, void *data);
+static int webkit(Client *c, const char *name, DataType type, void *value, void *data);
+
+extern struct Vimb vb;
+
+
+void setting_init(Client *c)
{
int i;
- gboolean on = true, off = false;
-
- vb.config.settings = g_hash_table_new_full(g_str_hash, g_str_equal, NULL, (GDestroyNotify)setting_free);
-#if WEBKIT_CHECK_VERSION(1, 7, 5)
- setting_add("accelerated-compositing", TYPE_BOOLEAN, &off, webkit, 0, "enable-accelerated-compositing");
-#endif
- setting_add("auto-resize-window", TYPE_BOOLEAN, &off, webkit, 0, "auto-resize-window");
- setting_add("auto-shrink-images", TYPE_BOOLEAN, &on, webkit, 0, "auto-shrink-images");
- setting_add("caret", TYPE_BOOLEAN, &off, webkit, 0, "enable-caret-browsing");
- setting_add("cursivfont", TYPE_CHAR, &"serif", webkit, 0, "cursive-font-family");
- setting_add("defaultencoding", TYPE_CHAR, &"utf-8", webkit, 0, "default-encoding");
- setting_add("defaultfont", TYPE_CHAR, &"sans-serif", webkit, 0, "default-font-family");
- setting_add("dns-prefetching", TYPE_BOOLEAN, &on, webkit, 0, "enable-dns-prefetching");
- setting_add("dom-paste", TYPE_BOOLEAN, &off, webkit, 0, "enable-dom-paste");
- setting_add("file-access-from-file-uris", TYPE_BOOLEAN, &off, webkit, 0, "enable-file-access-from-file-uris");
+ gboolean on = TRUE, off = FALSE;
+
+ /* TODO put the setting definitions into config.def.h and save them on vb
+ * struct. Use a hash table for fast name to key processing on the client.
+ * Separate the setting definition from the data.
+ * Don't set the webkit settings if they are the default on startup. */
+ c->config.settings = g_hash_table_new_full(g_str_hash, g_str_equal, NULL, (GDestroyNotify)setting_free);
+ setting_add(c, "useragent", TYPE_CHAR, &"Mozilla/5.0 (X11; Linux i686) AppleWebKit/538.15+ (KHTML, like Gecko) " PROJECT "/" VERSION " Version/8.0 Safari/538.15", webkit, 0, "user-agent");
+ /* TODO use the real names for webkit settings */
+ i = 14;
+ setting_add(c, "fontsize", TYPE_INTEGER, &i, webkit, 0, "default-font-size");
+ setting_add(c, "caret", TYPE_BOOLEAN, &off, webkit, 0, "enable-caret-browsing");
+ setting_add(c, "cursivfont", TYPE_CHAR, &"serif", webkit, 0, "cursive-font-family");
+ setting_add(c, "default-charset", TYPE_CHAR, &"utf-8", webkit, 0, "default-charset");
+ setting_add(c, "defaultfont", TYPE_CHAR, &"sans-serif", webkit, 0, "default-font-family");
+ setting_add(c, "dns-prefetching", TYPE_BOOLEAN, &on, webkit, 0, "enable-dns-prefetching");
i = SETTING_DEFAULT_FONT_SIZE;
- setting_add("fontsize", TYPE_INTEGER, &i, webkit, 0, "default-font-size");
- setting_add("frame-flattening", TYPE_BOOLEAN, &off, webkit, 0, "enable-frame-flattening");
- setting_add("html5-database", TYPE_BOOLEAN, &on, webkit, 0, "enable-html5-database");
- setting_add("html5-local-storage", TYPE_BOOLEAN, &on, webkit, 0, "enable-html5-local-storage");
- setting_add("hyperlink-auditing", TYPE_BOOLEAN, &off, webkit, 0, "enable-hyperlink-auditing");
- setting_add("images", TYPE_BOOLEAN, &on, webkit, 0, "auto-load-images");
-#if WEBKIT_CHECK_VERSION(2, 0, 0)
- setting_add("insecure-content-show", TYPE_BOOLEAN, &off, webkit, 0, "enable-display-of-insecure-content");
- setting_add("insecure-content-run", TYPE_BOOLEAN, &off, webkit, 0, "enable-running-of-insecure-content");
-#endif
- setting_add("java-applet", TYPE_BOOLEAN, &on, webkit, 0, "enable-java-applet");
- setting_add("javascript-can-access-clipboard", TYPE_BOOLEAN, &off, webkit, 0, "javascript-can-access-clipboard");
- setting_add("javascript-can-open-windows-automatically", TYPE_BOOLEAN, &off, webkit, 0, "javascript-can-open-windows-automatically");
- setting_add("media-playback-allows-inline", TYPE_BOOLEAN, &on, webkit, 0, "media-playback-allows-inline");
- setting_add("media-playback-requires-user-gesture", TYPE_BOOLEAN, &off, webkit, 0, "media-playback-requires-user-gesture");
+ setting_add(c, "fontsize", TYPE_INTEGER, &i, webkit, 0, "default-font-size");
+ setting_add(c, "frame-flattening", TYPE_BOOLEAN, &off, webkit, 0, "enable-frame-flattening");
+ setting_add(c, "header", TYPE_CHAR, &"", headers, FLAG_LIST|FLAG_NODUP, "header");
+ setting_add(c, "html5-database", TYPE_BOOLEAN, &on, webkit, 0, "enable-html5-database");
+ setting_add(c, "html5-local-storage", TYPE_BOOLEAN, &on, webkit, 0, "enable-html5-local-storage");
+ setting_add(c, "hyperlink-auditing", TYPE_BOOLEAN, &off, webkit, 0, "enable-hyperlink-auditing");
+ setting_add(c, "images", TYPE_BOOLEAN, &on, webkit, 0, "auto-load-images");
+ setting_add(c, "javascript-can-access-clipboard", TYPE_BOOLEAN, &off, webkit, 0, "javascript-can-access-clipboard");
+ setting_add(c, "javascript-can-open-windows-automatically", TYPE_BOOLEAN, &off, webkit, 0, "javascript-can-open-windows-automatically");
+ setting_add(c, "media-playback-allows-inline", TYPE_BOOLEAN, &on, webkit, 0, "media-playback-allows-inline");
+ setting_add(c, "media-playback-requires-user-gesture", TYPE_BOOLEAN, &off, webkit, 0, "media-playback-requires-user-gesture");
#if WEBKIT_CHECK_VERSION(2, 4, 0)
- setting_add("media-stream", TYPE_BOOLEAN, &off, webkit, 0, "enable-media-stream");
- setting_add("mediasource", TYPE_BOOLEAN, &off, webkit, 0, "enable-mediasource");
+ setting_add(c, "media-stream", TYPE_BOOLEAN, &off, webkit, 0, "enable-media-stream");
+ setting_add(c, "mediasource", TYPE_BOOLEAN, &off, webkit, 0, "enable-mediasource");
#endif
i = 5;
- setting_add("minimumfontsize", TYPE_INTEGER, &i, webkit, 0, "minimum-font-size");
- setting_add("monofont", TYPE_CHAR, &"monospace", webkit, 0, "monospace-font-family");
+ setting_add(c, "minimumfontsize", TYPE_INTEGER, &i, webkit, 0, "minimum-font-size");
+ setting_add(c, "monofont", TYPE_CHAR, &"monospace", webkit, 0, "monospace-font-family");
i = SETTING_DEFAULT_FONT_SIZE;
- setting_add("monofontsize", TYPE_INTEGER, &i, webkit, 0, "default-monospace-font-size");
- setting_add("offlinecache", TYPE_BOOLEAN, &on, webkit, 0, "enable-offline-web-application-cache");
- setting_add("pagecache", TYPE_BOOLEAN, &on, pagecache, 0, "enable-page-cache");
- setting_add("plugins", TYPE_BOOLEAN, &on, webkit, 0, "enable-plugins");
- setting_add("print-backgrounds", TYPE_BOOLEAN, &on, webkit, 0, "print-backgrounds");
- setting_add("private-browsing", TYPE_BOOLEAN, &off, webkit, 0, "enable-private-browsing");
- setting_add("resizable-text-areas", TYPE_BOOLEAN, &on, webkit, 0, "resizable-text-areas");
- setting_add("respect-image-orientation", TYPE_BOOLEAN, &off, webkit, 0, "respect-image-orientation");
- setting_add("sansfont", TYPE_CHAR, &"sans-serif", webkit, 0, "sans-serif-font-family");
- setting_add("scripts", TYPE_BOOLEAN, &on, webkit, 0, "enable-scripts");
- setting_add("seriffont", TYPE_CHAR, &"serif", webkit, 0, "serif-font-family");
- setting_add("site-specific-quirks", TYPE_BOOLEAN, &off, webkit, 0, "enable-site-specific-quirks");
+ setting_add(c, "monofontsize", TYPE_INTEGER, &i, webkit, 0, "default-monospace-font-size");
+ setting_add(c, "offlinecache", TYPE_BOOLEAN, &on, webkit, 0, "enable-offline-web-application-cache");
+ setting_add(c, "plugins", TYPE_BOOLEAN, &on, webkit, 0, "enable-plugins");
+ setting_add(c, "print-backgrounds", TYPE_BOOLEAN, &on, webkit, 0, "print-backgrounds");
+ setting_add(c, "private-browsing", TYPE_BOOLEAN, &off, webkit, 0, "enable-private-browsing");
+ setting_add(c, "sansfont", TYPE_CHAR, &"sans-serif", webkit, 0, "sans-serif-font-family");
+ setting_add(c, "scripts", TYPE_BOOLEAN, &on, webkit, 0, "enable-javascript");
+ setting_add(c, "seriffont", TYPE_CHAR, &"serif", webkit, 0, "serif-font-family");
+ setting_add(c, "site-specific-quirks", TYPE_BOOLEAN, &off, webkit, 0, "enable-site-specific-quirks");
#if WEBKIT_CHECK_VERSION(1, 9, 0)
- setting_add("smooth-scrolling", TYPE_BOOLEAN, &off, webkit, 0, "enable-smooth-scrolling");
+ setting_add(c, "smooth-scrolling", TYPE_BOOLEAN, &off, webkit, 0, "enable-smooth-scrolling");
#endif
- setting_add("spacial-navigation", TYPE_BOOLEAN, &off, webkit, 0, "enable-spatial-navigation");
- setting_add("spell-checking", TYPE_BOOLEAN, &off, webkit, 0, "enable-spell-checking");
- setting_add("spell-checking-languages", TYPE_CHAR, NULL, webkit, 0, "spell-checking-languages");
- setting_add("tab-key-cycles-through-elements", TYPE_BOOLEAN, &on, webkit, 0, "tab-key-cycles-through-elements");
- setting_add("universal-access-from-file-uris", TYPE_BOOLEAN, &off, webkit, 0, "enable-universal-access-from-file-uris");
- setting_add("useragent", TYPE_CHAR, &"Mozilla/5.0 (X11; Linux i686) AppleWebKit/538.15+ (KHTML, like Gecko) " PROJECT "/" VERSION " Version/8.0 Safari/538.15", webkit, 0, "user-agent");
- setting_add("webaudio", TYPE_BOOLEAN, &off, webkit, 0, "enable-webaudio");
- setting_add("webgl", TYPE_BOOLEAN, &off, webkit, 0, "enable-webgl");
- setting_add("webinspector", TYPE_BOOLEAN, &off, webkit, 0, "enable-developer-extras");
- setting_add("xssauditor", TYPE_BOOLEAN, &on, webkit, 0, "enable-xss-auditor");
+ setting_add(c, "spacial-navigation", TYPE_BOOLEAN, &off, webkit, 0, "enable-spatial-navigation");
+ setting_add(c, "enable-tabs-to-links", TYPE_BOOLEAN, &on, webkit, 0, "enable-tabs-to-links");
+ setting_add(c, "webaudio", TYPE_BOOLEAN, &off, webkit, 0, "enable-webaudio");
+ setting_add(c, "webgl", TYPE_BOOLEAN, &off, webkit, 0, "enable-webgl");
+ setting_add(c, "webinspector", TYPE_BOOLEAN, &on, webkit, 0, "enable-developer-extras");
+ setting_add(c, "xssauditor", TYPE_BOOLEAN, &on, webkit, 0, "enable-xss-auditor");
/* internal variables */
- setting_add("stylesheet", TYPE_BOOLEAN, &on, user_style, 0, NULL);
- setting_add("proxy", TYPE_BOOLEAN, &on, proxy, 0, NULL);
-#ifdef FEATURE_COOKIE
- setting_add("cookie-accept", TYPE_CHAR, &"always", cookie_accept, 0, NULL);
- i = 4800;
- setting_add("cookie-timeout", TYPE_INTEGER, &i, internal, 0, &vb.config.cookie_timeout);
- i = -1;
- setting_add("cookie-expire-time", TYPE_INTEGER, &i, internal, 0, &vb.config.cookie_expire_time);
-#endif
- setting_add("strict-ssl", TYPE_BOOLEAN, &on, soup, 0, "ssl-strict");
- setting_add("strict-focus", TYPE_BOOLEAN, &off, internal, 0, &vb.config.strict_focus);
+ setting_add(c, "stylesheet", TYPE_BOOLEAN, &on, user_style, 0, NULL);
+ setting_add(c, "userscripts", TYPE_BOOLEAN, &on, user_scripts, 0, NULL);
+ setting_add(c, "cookie-accept", TYPE_CHAR, &"always", cookie_accept, 0, NULL);
i = 40;
- setting_add("scrollstep", TYPE_INTEGER, &i, internal, 0, &vb.config.scrollstep);
- setting_add("statusbar", TYPE_BOOLEAN, &on, statusbar, 0, NULL);
- setting_add("status-color-bg", TYPE_COLOR, &"#000000", status_color, 0, &vb.style.status_bg[VB_STATUS_NORMAL]);
- setting_add("status-color-fg", TYPE_COLOR, &"#ffffff", status_color, 0, &vb.style.status_fg[VB_STATUS_NORMAL]);
- setting_add("status-font", TYPE_FONT, &SETTING_GUI_FONT_EMPH, status_font, 0, &vb.style.status_font[VB_STATUS_NORMAL]);
- setting_add("status-ssl-color-bg", TYPE_COLOR, &"#95e454", status_color, 0, &vb.style.status_bg[VB_STATUS_SSL_VALID]);
- setting_add("status-ssl-color-fg", TYPE_COLOR, &"#000000", status_color, 0, &vb.style.status_fg[VB_STATUS_SSL_VALID]);
- setting_add("status-ssl-font", TYPE_FONT, &SETTING_GUI_FONT_EMPH, status_font, 0, &vb.style.status_font[VB_STATUS_SSL_VALID]);
- setting_add("status-sslinvalid-color-bg", TYPE_COLOR, &"#ff7777", status_color, 0, &vb.style.status_bg[VB_STATUS_SSL_INVALID]);
- setting_add("status-sslinvalid-color-fg", TYPE_COLOR, &"#000000", status_color, 0, &vb.style.status_fg[VB_STATUS_SSL_INVALID]);
- setting_add("status-sslinvalid-font", TYPE_FONT, &SETTING_GUI_FONT_EMPH, status_font, 0, &vb.style.status_font[VB_STATUS_SSL_INVALID]);
- i = 1000;
- setting_add("timeoutlen", TYPE_INTEGER, &i, internal, 0, &vb.config.timeoutlen);
- setting_add("input-autohide", TYPE_BOOLEAN, &off, input_autohide, 0, &vb.config.input_autohide);
- setting_add("input-bg-normal", TYPE_COLOR, &"#ffffff", input_color, 0, &vb.style.input_bg[VB_MSG_NORMAL]);
- setting_add("input-bg-error", TYPE_COLOR, &"#ff7777", input_color, 0, &vb.style.input_bg[VB_MSG_ERROR]);
- setting_add("input-fg-normal", TYPE_COLOR, &"#000000", input_color, 0, &vb.style.input_fg[VB_MSG_NORMAL]);
- setting_add("input-fg-error", TYPE_COLOR, &"#000000", input_color, 0, &vb.style.input_fg[VB_MSG_ERROR]);
- setting_add("input-font-normal", TYPE_FONT, &SETTING_GUI_FONT_NORMAL, input_font, 0, &vb.style.input_font[VB_MSG_NORMAL]);
- setting_add("input-font-error", TYPE_FONT, &SETTING_GUI_FONT_EMPH, input_font, 0, &vb.style.input_font[VB_MSG_ERROR]);
- setting_add("completion-font", TYPE_FONT, &SETTING_GUI_FONT_NORMAL, input_font, 0, &vb.style.comp_font);
- setting_add("completion-fg-normal", TYPE_COLOR, &"#f6f3e8", input_color, 0, &vb.style.comp_fg[VB_COMP_NORMAL]);
- setting_add("completion-fg-active", TYPE_COLOR, &"#ffffff", input_color, 0, &vb.style.comp_fg[VB_COMP_ACTIVE]);
- setting_add("completion-bg-normal", TYPE_COLOR, &"#656565", input_color, 0, &vb.style.comp_bg[VB_COMP_NORMAL]);
- setting_add("completion-bg-active", TYPE_COLOR, &"#777777", input_color, 0, &vb.style.comp_bg[VB_COMP_ACTIVE]);
- setting_add("ca-bundle", TYPE_CHAR, &SETTING_CA_BUNDLE, ca_bundle, 0, NULL);
- setting_add("home-page", TYPE_CHAR, &SETTING_HOME_PAGE, NULL, 0, NULL);
- i = 1000;
- setting_add("hint-timeout", TYPE_INTEGER, &i, NULL, 0, NULL);
- setting_add("hintkeys", TYPE_CHAR, &"0123456789", NULL, 0, NULL);
- setting_add("hint-follow-last", TYPE_BOOLEAN, &on, NULL, 0, NULL);
- setting_add("hint-number-same-length", TYPE_BOOLEAN, &off, NULL, 0, NULL);
- setting_add("download-path", TYPE_CHAR, &"", internal, 0, &vb.config.download_dir);
- i = 2000;
- setting_add("history-max-items", TYPE_INTEGER, &i, internal, 0, &vb.config.history_max);
- i = 10;
- setting_add("closed-max-items", TYPE_INTEGER, &i, internal, 0, &vb.config.closed_max);
- setting_add("editor-command", TYPE_CHAR, &"x-terminal-emulator -e -vi '%s'", NULL, 0, NULL);
- setting_add("header", TYPE_CHAR, &"", headers, FLAG_LIST|FLAG_NODUP, NULL);
-#ifdef FEATURE_ARH
- setting_add("auto-response-header", TYPE_CHAR, &"", autoresponseheader, FLAG_LIST|FLAG_NODUP, NULL);
-#endif
- setting_add("nextpattern", TYPE_CHAR, &"/\\bnext\\b/i,/^(>\\|>>\\|»)$/,/^(>\\|>>\\|»)/,/(>\\|>>\\|»)$/,/\\bmore\\b/i", prevnext, FLAG_LIST|FLAG_NODUP, NULL);
- setting_add("previouspattern", TYPE_CHAR, &"/\\bprev\\|previous\\b/i,/^(<\\|<<\\|«)$/,/^(<\\|<<\\|«)/,/(<\\|<<\\|«)$/", prevnext, FLAG_LIST|FLAG_NODUP, NULL);
- setting_add("fullscreen", TYPE_BOOLEAN, &off, fullscreen, 0, NULL);
- setting_add("download-command", TYPE_CHAR, &"/bin/sh -c \"curl -sLJOC - -A '$VIMB_USER_AGENT' -e '$VIMB_URI' -b '$VIMB_COOKIES' '%s'\"", NULL, 0, NULL);
- setting_add("download-use-external", TYPE_BOOLEAN, &off, NULL, 0, NULL);
-#ifdef FEATURE_HSTS
- setting_add("hsts", TYPE_BOOLEAN, &on, hsts, 0, NULL);
-#endif
-#ifdef FEATURE_SOUP_CACHE
+ setting_add(c, "scrollstep", TYPE_INTEGER, &i, internal, 0, &c->config.scrollstep);
+ setting_add(c, "home-page", TYPE_CHAR, &SETTING_HOME_PAGE, NULL, 0, NULL);
i = 2000;
- setting_add("maximum-cache-size", TYPE_INTEGER, &i, soup_cache, 0, NULL);
-#endif
- setting_add("x-hint-command", TYPE_CHAR, &":o <C-R>;", NULL, 0, NULL);
+ /* TODO should be global and not overwritten by a new client */
+ setting_add(c, "history-max-items", TYPE_INTEGER, &i, internal, 0, &vb.config.history_max);
+ setting_add(c, "editor-command", TYPE_CHAR, &"x-terminal-emulator -e -vi '%s'", NULL, 0, NULL);
+ setting_add(c, "strict-ssl", TYPE_BOOLEAN, &on, tls_policy, 0, NULL);
+ setting_add(c, "statusbar", TYPE_BOOLEAN, &on, statusbar, 0, NULL);
+ i = 1000;
+ setting_add(c, "timeoutlen", TYPE_INTEGER, &i, internal, 0, &c->map.timeoutlen);
+ setting_add(c, "input-autohide", TYPE_BOOLEAN, &off, input_autohide, 0, &c->config.input_autohide);
+ setting_add(c, "fullscreen", TYPE_BOOLEAN, &off, fullscreen, 0, NULL);
/* initialize the shortcuts and set the default shortcuts */
- shortcut_init();
- shortcut_add("dl", "https://duckduckgo.com/html/?q=$0");
- shortcut_add("dd", "https://duckduckgo.com/?q=$0");
- shortcut_set_default("dl");
-
- /* initialize the handlers */
- handlers_init();
- handler_add("magnet", "xdg-open '%s'");
+ shortcut_init(c);
+ shortcut_add(c, "dl", "https://duckduckgo.com/html/?q=$0");
+ shortcut_add(c, "dd", "https://duckduckgo.com/?q=$0");
+ shortcut_set_default(c, "dl");
}
-VbCmdResult setting_run(char *name, const char *param)
+VbCmdResult setting_run(Client *c, char *name, const char *param)
{
SettingType type = SETTING_SET;
char modifier;
@@ -269,34 +174,34 @@ VbCmdResult setting_run(char *name, const char *param)
}
/* lookup a matching setting */
- Setting *s = g_hash_table_lookup(vb.config.settings, name);
+ Setting *s = g_hash_table_lookup(c->config.settings, name);
if (!s) {
- vb_echo(VB_MSG_ERROR, true, "Config '%s' not found", name);
- return VB_CMD_ERROR | VB_CMD_KEEPINPUT;
+ vb_echo(c, MSG_ERROR, TRUE, "Config '%s' not found", name);
+ return CMD_ERROR | CMD_KEEPINPUT;
}
if (type == SETTING_GET) {
- setting_print(s);
- return VB_CMD_SUCCESS | VB_CMD_KEEPINPUT;
+ setting_print(c, s);
+ return CMD_SUCCESS | CMD_KEEPINPUT;
}
if (type == SETTING_TOGGLE) {
if (s->type != TYPE_BOOLEAN) {
- vb_echo(VB_MSG_ERROR, true, "Could not toggle none boolean %s", s->name);
+ vb_echo(c, MSG_ERROR, TRUE, "Could not toggle none boolean %s", s->name);
- return VB_CMD_ERROR | VB_CMD_KEEPINPUT;
+ return CMD_ERROR | CMD_KEEPINPUT;
}
gboolean value = !s->value.b;
- res = setting_set_value(s, &value, SETTING_SET);
- setting_print(s);
+ res = setting_set_value(c, s, &value, SETTING_SET);
+ setting_print(c, s);
/* make sure the new value set by the toggle keep visible */
- res |= VB_CMD_KEEPINPUT;
+ res |= CMD_KEEPINPUT;
} else {
if (!param) {
- vb_echo(VB_MSG_ERROR, true, "No valid value");
+ vb_echo(c, MSG_ERROR, TRUE, "No valid value");
- return VB_CMD_ERROR | VB_CMD_KEEPINPUT;
+ return CMD_ERROR | CMD_KEEPINPUT;
}
/* convert sting value into internal used data type */
@@ -306,49 +211,49 @@ VbCmdResult setting_run(char *name, const char *param)
case TYPE_BOOLEAN:
boolvar = g_ascii_strncasecmp(param, "true", 4) == 0
|| g_ascii_strncasecmp(param, "on", 2) == 0;
- res = setting_set_value(s, &boolvar, type);
+ res = setting_set_value(c, s, &boolvar, type);
break;
case TYPE_INTEGER:
intvar = g_ascii_strtoull(param, (char**)NULL, 10);
- res = setting_set_value(s, &intvar, type);
+ res = setting_set_value(c, s, &intvar, type);
break;
default:
- res = setting_set_value(s, (void*)param, type);
+ res = setting_set_value(c, s, (void*)param, type);
break;
}
}
- if (res & (VB_CMD_SUCCESS | VB_CMD_KEEPINPUT)) {
+ if (res & (CMD_SUCCESS | CMD_KEEPINPUT)) {
return res;
}
- vb_echo(VB_MSG_ERROR, true, "Could not set %s", s->name);
- return VB_CMD_ERROR | VB_CMD_KEEPINPUT;
+ vb_echo(c, MSG_ERROR, TRUE, "Could not set %s", s->name);
+ return CMD_ERROR | CMD_KEEPINPUT;
}
-gboolean setting_fill_completion(GtkListStore *store, const char *input)
+gboolean setting_fill_completion(Client *c, GtkListStore *store, const char *input)
{
- GList *src = g_hash_table_get_keys(vb.config.settings);
- gboolean found = util_fill_completion(store, input, src);
+ GList *src = g_hash_table_get_keys(c->config.settings);
+ gboolean found = completion_fill(store, input, src);
g_list_free(src);
return found;
}
-void setting_cleanup(void)
+void setting_cleanup(Client *c)
{
- if (vb.config.settings) {
- g_hash_table_destroy(vb.config.settings);
+ if (c->config.settings) {
+ g_hash_table_destroy(c->config.settings);
+ c->config.settings = NULL;
}
- shortcut_cleanup();
- handlers_cleanup();
+ shortcut_cleanup(c);
}
-static int setting_set_value(Setting *prop, void *value, SettingType type)
+static int setting_set_value(Client *c, Setting *prop, void *value, SettingType type)
{
- int res = VB_CMD_SUCCESS;
+ int res = CMD_SUCCESS;
/* by default given value is also the new value */
void *newvalue = NULL;
gboolean free_newvalue;
@@ -359,9 +264,9 @@ static int setting_set_value(Setting *prop, void *value, SettingType type)
/* if there is a setter defined - call this first to check if the value is
* accepted */
if (prop->setter) {
- res = prop->setter(prop->name, prop->type, newvalue, prop->data);
+ res = prop->setter(c, prop->name, prop->type, newvalue, prop->data);
/* break here on error and don't change the setting */
- if (res & VB_CMD_ERROR) {
+ if (res & CMD_ERROR) {
goto free;
}
}
@@ -390,12 +295,12 @@ free:
/**
* Prepares the value for the setting for the different setting types.
- * Return value true indicates that the memory of newvalue must be freed by
+ * Return value TRUE indicates that the memory of newvalue must be freed by
* the caller.
*/
static gboolean prepare_setting_value(Setting *prop, void *value, SettingType type, void **newvalue)
{
- gboolean islist, res = false;
+ gboolean islist, res = FALSE;
int vlen, i = 0;
char *p = NULL;
@@ -410,7 +315,7 @@ static gboolean prepare_setting_value(Setting *prop, void *value, SettingType ty
/* perform arithmetic operation for integer values */
if (prop->type == TYPE_INTEGER) {
int *newint = g_malloc(sizeof(int));
- res = true;
+ res = TRUE;
if (type == SETTING_APPEND) {
*newint = prop->value.i + *((int*)value);
} else if (type == SETTING_PREPEND) {
@@ -473,7 +378,7 @@ static gboolean prepare_setting_value(Setting *prop, void *value, SettingType ty
} else {
*newvalue = g_strconcat(prop->value.s, value, NULL);
}
- res = true;
+ res = TRUE;
} else if (type == SETTING_PREPEND) {
if (islist && *(char*)value) {
/* don't prepend a comma if the value is empty */
@@ -481,7 +386,7 @@ static gboolean prepare_setting_value(Setting *prop, void *value, SettingType ty
} else {
*newvalue = g_strconcat(value, prop->value.s, NULL);
}
- res = true;
+ res = TRUE;
} else if (type == SETTING_REMOVE && p) {
char *copy = g_strdup(prop->value.s);
/* make p to point to the same position in the copy */
@@ -489,14 +394,14 @@ static gboolean prepare_setting_value(Setting *prop, void *value, SettingType ty
memmove(p, p + i, 1 + strlen(p + vlen));
*newvalue = copy;
- res = true;
+ res = TRUE;
}
return res;
}
-static gboolean setting_add(const char *name, int type, void *value,
- SettingFunction setter, int flags, void *data)
+static gboolean setting_add(Client *c, const char *name, DataType type, void *value,
+ SettingFunction setter, int flags, void *data)
{
Setting *prop = g_slice_new0(Setting);
prop->name = name;
@@ -505,25 +410,25 @@ static gboolean setting_add(const char *name, int type, void *value,
prop->flags = flags;
prop->data = data;
- setting_set_value(prop, value, SETTING_SET);
+ setting_set_value(c, prop, value, SETTING_SET);
- g_hash_table_insert(vb.config.settings, (char*)name, prop);
- return true;
+ g_hash_table_insert(c->config.settings, (char*)name, prop);
+ return TRUE;
}
-static void setting_print(Setting *s)
+static void setting_print(Client *c, Setting *s)
{
switch (s->type) {
case TYPE_BOOLEAN:
- vb_echo(VB_MSG_NORMAL, false, " %s=%s", s->name, s->value.b ? "true" : "false");
+ vb_echo(c, MSG_NORMAL, FALSE, " %s=%s", s->name, s->value.b ? "true" : "false");
break;
case TYPE_INTEGER:
- vb_echo(VB_MSG_NORMAL, false, " %s=%d", s->name, s->value.i);
+ vb_echo(c, MSG_NORMAL, FALSE, " %s=%d", s->name, s->value.i);
break;
default:
- vb_echo(VB_MSG_NORMAL, false, " %s=%s", s->name, s->value.s);
+ vb_echo(c, MSG_NORMAL, FALSE, " %s=%s", s->name, s->value.s);
break;
}
}
@@ -536,392 +441,192 @@ static void setting_free(Setting *s)
g_slice_free(Setting, s);
}
-static int webkit(const char *name, int type, void *value, void *data)
+static int cookie_accept(Client *c, const char *name, DataType type, void *value, void *data)
{
- const char *property = (const char*)data;
- WebKitWebSettings *web_setting = webkit_web_view_get_settings(vb.gui.webview);
-
- switch (type) {
- case TYPE_BOOLEAN:
- g_object_set(G_OBJECT(web_setting), property, *((gboolean*)value), NULL);
- break;
+ WebKitWebContext *ctx;
+ WebKitCookieManager *cm;
+ char *policy = (char*)value;
- case TYPE_INTEGER:
- g_object_set(G_OBJECT(web_setting), property, *((int*)value), NULL);
- break;
+ ctx = webkit_web_view_get_context(c->webview);
+ cm = webkit_web_context_get_cookie_manager(ctx);
+ if (strcmp("always", policy) == 0) {
+ webkit_cookie_manager_set_accept_policy(cm, WEBKIT_COOKIE_POLICY_ACCEPT_ALWAYS);
+ } else if (strcmp("origin", policy) == 0) {
+ webkit_cookie_manager_set_accept_policy(cm, WEBKIT_COOKIE_POLICY_ACCEPT_NO_THIRD_PARTY);
+ } else if (strcmp("never", policy) == 0) {
+ webkit_cookie_manager_set_accept_policy(cm, WEBKIT_COOKIE_POLICY_ACCEPT_NEVER);
+ } else {
+ vb_echo(c, MSG_ERROR, TRUE, "%s must be in [always, origin, never]", name);
- default:
- g_object_set(G_OBJECT(web_setting), property, (char*)value, NULL);
- break;
+ return CMD_ERROR | CMD_KEEPINPUT;
}
- return VB_CMD_SUCCESS;
+
+ return CMD_SUCCESS;
}
-static int pagecache(const char *name, int type, void *value, void *data)
+static int fullscreen(Client *c, const char *name, DataType type, void *value, void *data)
{
- int res;
- gboolean on = *((gboolean*)value);
-
- /* first set the setting on the web settings */
- res = webkit(name, type, value, data);
-
- if (res == VB_CMD_SUCCESS && on) {
- webkit_set_cache_model(WEBKIT_CACHE_MODEL_WEB_BROWSER);
+ if (*(gboolean*)value) {
+ gtk_window_fullscreen(GTK_WINDOW(c->window));
} else {
- /* reduce memory usage if caching is not used */
- webkit_set_cache_model(WEBKIT_CACHE_MODEL_DOCUMENT_VIEWER);
+ gtk_window_unfullscreen(GTK_WINDOW(c->window));
}
- return res;
-}
-
-static int soup(const char *name, int type, void *value, void *data)
-{
- const char *property = (const char*)data;
- switch (type) {
- case TYPE_BOOLEAN:
- g_object_set(G_OBJECT(vb.session), property, *((gboolean*)value), NULL);
- break;
-
- case TYPE_INTEGER:
- g_object_set(G_OBJECT(vb.session), property, *((int*)value), NULL);
- break;
-
- default:
- g_object_set(G_OBJECT(vb.session), property, (char*)value, NULL);
- break;
- }
- return VB_CMD_SUCCESS;
+ return CMD_SUCCESS;
}
-static int internal(const char *name, int type, void *value, void *data)
+/**
+ * Allow to set user defined http headers.
+ *
+ * :set header=NAME1=VALUE!,NAME2=,NAME3
+ *
+ * Note that these headers will replace already existing headers. If there is
+ * no '=' after the header name, than the complete header will be removed from
+ * the request (NAME3), if the '=' is present means that the header value is
+ * set to empty value.
+ */
+static int headers(Client *c, const char *name, DataType type, void *value, void *data)
{
- char **str;
- switch (type) {
- case TYPE_BOOLEAN:
- *(gboolean*)data = *(gboolean*)value;
- break;
-
- case TYPE_INTEGER:
- *(int*)data = *(int*)value;
- break;
+ ext_proxy_set_header(c, (char*)value);
- default:
- str = (char**)data;
- OVERWRITE_STRING(*str, (char*)value);
- break;
- }
- return VB_CMD_SUCCESS;
+ return CMD_SUCCESS;
}
-static int input_autohide(const char *name, int type, void *value, void *data)
+static int input_autohide(Client *c, const char *name, DataType type, void *value, void *data)
{
char *text;
+
/* save selected value in internal variable */
*(gboolean*)data = *(gboolean*)value;
/* if autohide is on and inputbox contains no text - hide it now */
if (*(gboolean*)value) {
- text = vb_get_input_text();
+ text = vb_input_get_text(c);
if (!*text) {
- gtk_widget_set_visible(GTK_WIDGET(vb.gui.input), false);
+ gtk_widget_set_visible(GTK_WIDGET(c->input), FALSE);
}
g_free(text);
} else {
/* autohide is off - make sure the input box is shown */
- gtk_widget_set_visible(GTK_WIDGET(vb.gui.input), true);
- }
-
- return VB_CMD_SUCCESS;
-}
-
-static int input_color(const char *name, int type, void *value, void *data)
-{
- VB_COLOR_PARSE((VbColor*)data, (char*)value);
- vb_update_input_style();
-
- return VB_CMD_SUCCESS;
-}
-
-static int statusbar(const char *name, int type, void *value, void *data)
-{
- gtk_widget_set_visible(GTK_WIDGET(vb.gui.statusbar.box), *(gboolean*)value);
-
- return VB_CMD_SUCCESS;
-}
-
-static int status_color(const char *name, int type, void *value, void *data)
-{
- VB_COLOR_PARSE((VbColor*)data, (char*)value);
- vb_update_status_style();
-
- return VB_CMD_SUCCESS;
-}
-
-static int input_font(const char *name, int type, void *value, void *data)
-{
- PangoFontDescription **font = (PangoFontDescription**)data;
- if (*font) {
- /* free previous font description */
- pango_font_description_free(*font);
+ gtk_widget_set_visible(GTK_WIDGET(c->input), TRUE);
}
- *font = pango_font_description_from_string((char*)value);
- vb_update_input_style();
- return VB_CMD_SUCCESS;
+ return CMD_SUCCESS;
}
-static int status_font(const char *name, int type, void *value, void *data)
+static int internal(Client *c, const char *name, DataType type, void *value, void *data)
{
- PangoFontDescription **font = (PangoFontDescription**)data;
- if (*font) {
- /* free previous font description */
- pango_font_description_free(*font);
- }
- *font = pango_font_description_from_string((char*)value);
- vb_update_status_style();
+ char **str;
+ switch (type) {
+ case TYPE_BOOLEAN:
+ *(gboolean*)data = *(gboolean*)value;
+ break;
- return VB_CMD_SUCCESS;
-}
+ case TYPE_INTEGER:
+ *(int*)data = *(int*)value;
+ break;
-#ifdef FEATURE_COOKIE
-static int cookie_accept(const char *name, int type, void *value, void *data)
-{
- char *policy = (char*)value;
- int i;
- SoupCookieJar *jar;
- static struct {
- SoupCookieJarAcceptPolicy policy;
- char* name;
- } map[] = {
- {SOUP_COOKIE_JAR_ACCEPT_ALWAYS, "always"},
- {SOUP_COOKIE_JAR_ACCEPT_NEVER, "never"},
- {SOUP_COOKIE_JAR_ACCEPT_NO_THIRD_PARTY, "origin"},
- };
-
- jar = (SoupCookieJar*)soup_session_get_feature(vb.session, SOUP_TYPE_COOKIE_JAR);
-
- for (i = 0; i < LENGTH(map); i++) {
- if (!strcmp(map[i].name, policy)) {
- g_object_set(jar, SOUP_COOKIE_JAR_ACCEPT_POLICY, map[i].policy, NULL);
-
- return VB_CMD_SUCCESS;
- }
+ default:
+ str = (char**)data;
+ OVERWRITE_STRING(*str, (char*)value);
+ break;
}
- vb_echo(VB_MSG_ERROR, true, "%s must be in [always, origin, never]", name);
-
- return VB_CMD_ERROR | VB_CMD_KEEPINPUT;
+ return CMD_SUCCESS;
}
-#endif
-static int ca_bundle(const char *name, int type, void *value, void *data)
+static int user_scripts(Client *c, const char *name, DataType type, void *value, void *data)
{
- char *expanded;
- GError *error = NULL;
- /* expand the given file and set it to the file database */
- expanded = util_expand((char*)value, UTIL_EXP_TILDE|UTIL_EXP_DOLLAR);
- vb.config.tls_db = g_tls_file_database_new(expanded, &error);
- g_free(expanded);
- if (error) {
- g_warning("Could not load ssl database '%s': %s", (char*)value, error->message);
- g_error_free(error);
-
- return VB_CMD_ERROR;
- }
+ WebKitUserContentManager *ucm;
+ WebKitUserScript *script;
+ gchar *source;
- /* there is no function to get the file back from tls file database so
- * it's saved as separate configuration */
- g_object_set(vb.session, "tls-database", vb.config.tls_db, NULL);
-
- return VB_CMD_SUCCESS;
-}
-
-
-static int proxy(const char *name, int type, void *value, void *data)
-{
gboolean enabled = *(gboolean*)value;
-#if SOUP_CHECK_VERSION(2, 42, 2)
- GProxyResolver *proxy = NULL;
-#else
- SoupURI *proxy = NULL;
-#endif
-
- if (enabled) {
- const char *http_proxy = g_getenv("http_proxy");
-
- if (http_proxy != NULL && *http_proxy != '\0') {
- char *proxy_new = strstr(http_proxy, "://")
- ? g_strdup(http_proxy)
- : g_strconcat("http://", http_proxy, NULL);
-
-#if SOUP_CHECK_VERSION(2, 42, 2)
- const char *no_proxy;
- char **ignored_hosts = NULL;
- /* check for no_proxy environment variable that contains comma
- * separated domains or ip addresses to skip from proxy */
- if ((no_proxy = g_getenv("no_proxy"))) {
- ignored_hosts = g_strsplit(no_proxy, ",", 0);
- }
-
- proxy = g_simple_proxy_resolver_new(proxy_new, ignored_hosts);
- if (proxy) {
- g_object_set(vb.session, "proxy-resolver", proxy, NULL);
- }
- g_strfreev(ignored_hosts);
- g_object_unref(proxy);
-#else
- proxy = soup_uri_new(proxy_new);
- if (proxy && SOUP_URI_VALID_FOR_HTTP(proxy)) {
- g_object_set(vb.session, "proxy-uri", proxy, NULL);
- }
- soup_uri_free(proxy);
-#endif
- g_free(proxy_new);
- }
- } else {
- /* disable the proxy */
-#if SOUP_CHECK_VERSION(2, 42, 2)
- g_object_set(vb.session, "proxy-resolver", NULL, NULL);
-#else
- g_object_set(vb.session, "proxy-uri", NULL, NULL);
-#endif
- }
-
- return VB_CMD_SUCCESS;
-}
-static int user_style(const char *name, int type, void *value, void *data)
-{
- gboolean enabled = *(gboolean*)value;
- WebKitWebSettings *web_setting = webkit_web_view_get_settings(vb.gui.webview);
+ ucm = webkit_web_view_get_user_content_manager(c->webview);
if (enabled) {
- char *uri = g_strconcat("file://", vb.files[FILES_USER_STYLE], NULL);
- g_object_set(web_setting, "user-stylesheet-uri", uri, NULL);
- g_free(uri);
+ if (g_file_get_contents(vb.files[FILES_SCRIPT], &source, NULL, NULL)) {
+ script = webkit_user_script_new(
+ source, WEBKIT_USER_CONTENT_INJECT_ALL_FRAMES,
+ WEBKIT_USER_SCRIPT_INJECT_AT_DOCUMENT_END, NULL, NULL
+ );
+
+ webkit_user_content_manager_add_script(ucm, script);
+ webkit_user_script_unref(script);
+ g_free(source);
+ }
} else {
- g_object_set(web_setting, "user-stylesheet-uri", NULL, NULL);
- }
-
- return VB_CMD_SUCCESS;
-}
-
-
-/**
- * Allow to set user defined http headers.
- *
- * :set header=NAME1=VALUE!,NAME2=,NAME3
- *
- * Note that these headers will replace already existing headers. If there is
- * no '=' after the header name, than the complete header will be removed from
- * the request (NAME3), if the '=' is present means that the header value is
- * set to empty value.
- */
-static int headers(const char *name, int type, void *value, void *data)
-{
- /* remove previous parsed headers */
- if (vb.config.headers) {
- soup_header_free_param_list(vb.config.headers);
- vb.config.headers = NULL;
+ webkit_user_content_manager_remove_all_scripts(ucm);
}
- vb.config.headers = soup_header_parse_param_list((char*)value);
- return VB_CMD_SUCCESS;
+ return CMD_SUCCESS;
}
-#ifdef FEATURE_ARH
-static int autoresponseheader(const char *name, int type, void *value, void *data)
+static int user_style(Client *c, const char *name, DataType type, void *value, void *data)
{
- const char *error = NULL;
-
- GSList *new = arh_parse((char *)value, &error);
-
- if (! error) {
- /* remove previous parsed headers */
- arh_free(vb.config.autoresponseheader);
+ WebKitUserContentManager *ucm;
+ WebKitUserStyleSheet *style;
+ gchar *source;
- /* add the new one */
- vb.config.autoresponseheader = new;
+ gboolean enabled = *(gboolean*)value;
- return VB_CMD_SUCCESS;
+ ucm = webkit_web_view_get_user_content_manager(c->webview);
- } else {
- vb_echo(VB_MSG_ERROR, true, "auto-response-header: %s", error);
- return VB_CMD_ERROR | VB_CMD_KEEPINPUT;
- }
-}
-#endif
+ if (enabled && vb.files[FILES_USER_STYLE]) {
+ if (g_file_get_contents(vb.files[FILES_USER_STYLE], &source, NULL, NULL)) {
+ style = webkit_user_style_sheet_new(
+ source, WEBKIT_USER_CONTENT_INJECT_ALL_FRAMES,
+ WEBKIT_USER_STYLE_LEVEL_USER, NULL, NULL
+ );
-static int prevnext(const char *name, int type, void *value, void *data)
-{
- if (validate_js_regexp_list((char*)value)) {
- if (*name == 'n') {
- OVERWRITE_STRING(vb.config.nextpattern, (char*)value);
+ webkit_user_content_manager_add_style_sheet(ucm, style);
+ webkit_user_style_sheet_unref(style);
+ g_free(source);
} else {
- OVERWRITE_STRING(vb.config.prevpattern, (char*)value);
+ g_warning("Could not reed style file: %s", vb.files[FILES_USER_STYLE]);
}
- return VB_CMD_SUCCESS;
- }
-
- return VB_CMD_ERROR | VB_CMD_KEEPINPUT;
-}
-
-static int fullscreen(const char *name, int type, void *value, void *data)
-{
- if (*(gboolean*)value) {
- gtk_window_fullscreen(GTK_WINDOW(vb.gui.window));
} else {
- gtk_window_unfullscreen(GTK_WINDOW(vb.gui.window));
+ webkit_user_content_manager_remove_all_style_sheets(ucm);
}
- return VB_CMD_SUCCESS;
+ return CMD_SUCCESS;
}
-#ifdef FEATURE_HSTS
-static int hsts(const char *name, int type, void *value, void *data)
+static int statusbar(Client *c, const char *name, DataType type, void *value, void *data)
{
- if (*(gboolean*)value) {
- soup_session_add_feature(vb.session, SOUP_SESSION_FEATURE(vb.config.hsts_provider));
- } else {
- soup_session_remove_feature(vb.session, SOUP_SESSION_FEATURE(vb.config.hsts_provider));
- }
- return VB_CMD_SUCCESS;
+ gtk_widget_set_visible(GTK_WIDGET(c->statusbar.box), *(gboolean*)value);
+
+ return CMD_SUCCESS;
}
-#endif
-#ifdef FEATURE_SOUP_CACHE
-static int soup_cache(const char *name, int type, void *value, void *data)
+static int tls_policy(Client *c, const char *name, DataType type, void *value, void *data)
{
- int kilobytes = *(int*)value;
+ gboolean strict = *((gboolean*)value);
- soup_cache_set_max_size(vb.config.soup_cache, kilobytes * 1000);
+ webkit_web_context_set_tls_errors_policy(
+ webkit_web_context_get_default(),
+ strict ? WEBKIT_TLS_ERRORS_POLICY_FAIL : WEBKIT_TLS_ERRORS_POLICY_IGNORE);
- /* clear the cache if maximum-cache-size is set to zero - note that this
- * will also effect other vimb instances */
- if (!kilobytes) {
- soup_cache_clear(vb.config.soup_cache);
- }
- return VB_CMD_SUCCESS;
+ return CMD_SUCCESS;
}
-#endif
-/**
- * Validated syntax given list of JavaScript RegExp patterns.
- * If validation fails, the error is shown to the user.
- */
-static gboolean validate_js_regexp_list(const char *pattern)
+static int webkit(Client *c, const char *name, DataType type, void *value, void *data)
{
- gboolean result;
- char *js, *value = NULL;
- WebKitWebFrame *frame = webkit_web_view_get_main_frame(vb.gui.webview);
+ const char *property = (const char*)data;
+ WebKitSettings *web_setting = webkit_web_view_get_settings(c->webview);
+
+ switch (type) {
+ case TYPE_BOOLEAN:
+ g_object_set(G_OBJECT(web_setting), property, *((gboolean*)value), NULL);
+ break;
- js = g_strdup_printf("var i;for(i=0;i<[%s].length;i++);", pattern);
- result = js_eval(webkit_web_frame_get_global_context(frame), js, NULL, &value);
- g_free(js);
+ case TYPE_INTEGER:
+ g_object_set(G_OBJECT(web_setting), property, *((int*)value), NULL);
+ break;
- if (!result) {
- vb_echo(VB_MSG_ERROR, true, "%s", value);
+ default:
+ g_object_set(G_OBJECT(web_setting), property, (char*)value, NULL);
+ break;
}
- g_free(value);
- return result;
+ return CMD_SUCCESS;
}
diff --git a/src/setting.h b/src/setting.h
index 9631920..cd1d8d5 100644
--- a/src/setting.h
+++ b/src/setting.h
@@ -20,11 +20,13 @@
#ifndef _SETTING_H
#define _SETTING_H
+#include <gtk/gtk.h>
+
#include "main.h"
-void setting_init(void);
-void setting_cleanup(void);
-VbCmdResult setting_run(char* name, const char* param);
-gboolean setting_fill_completion(GtkListStore *store, const char *input);
+void setting_init(Client *c);
+void setting_cleanup(Client *c);
+VbCmdResult setting_run(Client *c, char *name, const char *param);
+gboolean setting_fill_completion(Client *c, GtkListStore *store, const char *input);
#endif /* end of include guard: _SETTING_H */
diff --git a/src/shortcut.c b/src/shortcut.c
index 37b083f..0663b9f 100644
--- a/src/shortcut.c
+++ b/src/shortcut.c
@@ -17,65 +17,66 @@
* along with this program. If not, see http://www.gnu.org/licenses/.
*/
+#include <glib.h>
+#include <string.h>
+
+#include "ascii.h"
#include "main.h"
#include "shortcut.h"
#include "util.h"
-#include "ascii.h"
-
-extern VbCore vb;
-static GHashTable *shortcuts = NULL;
-static char *default_key = NULL;
+extern struct Vimb vb;
static int get_max_placeholder(const char *str);
-static const char *shortcut_lookup(const char *string, const char **query);
+static const char *shortcut_lookup(Client *c, const char *string, const char **query);
-void shortcut_init(void)
+void shortcut_init(Client *c)
{
- shortcuts = g_hash_table_new_full(g_str_hash, g_str_equal, g_free, g_free);
+ c->shortcut.table = g_hash_table_new_full(g_str_hash, g_str_equal, g_free, g_free);
+ c->shortcut.fallback = NULL;
}
-void shortcut_cleanup(void)
+void shortcut_cleanup(Client *c)
{
- if (shortcuts) {
- g_hash_table_destroy(shortcuts);
+ if (c->shortcut.table) {
+ g_hash_table_destroy(c->shortcut.table);
}
}
-gboolean shortcut_add(const char *key, const char *uri)
+gboolean shortcut_add(Client *c, const char *key, const char *uri)
{
- g_hash_table_insert(shortcuts, g_strdup(key), g_strdup(uri));
+ g_hash_table_insert(c->shortcut.table, g_strdup(key), g_strdup(uri));
- return true;
+ return TRUE;
}
-gboolean shortcut_remove(const char *key)
+gboolean shortcut_remove(Client *c, const char *key)
{
- return g_hash_table_remove(shortcuts, key);
+ return g_hash_table_remove(c->shortcut.table, key);
}
-gboolean shortcut_set_default(const char *key)
+gboolean shortcut_set_default(Client *c, const char *key)
{
/* do not check if the shortcut exists to be able to set the default
* before defining the shortcut */
- OVERWRITE_STRING(default_key, key);
+ OVERWRITE_STRING(c->shortcut.fallback, key);
- return true;
+ return TRUE;
}
/**
* Retrieves the uri for given query string. Not that the memory of the
* returned uri must be freed.
*/
-char *shortcut_get_uri(const char *string)
+char *shortcut_get_uri(Client *c, const char *string)
{
const char *tmpl, *query = NULL;
char *uri, *quoted_param;
int max_num, current_num;
GString *token;
- tmpl = shortcut_lookup(string, &query);
+ tmpl = shortcut_lookup(c, string, &query);
if (!tmpl) {
return NULL;
}
@@ -151,19 +152,21 @@ char *shortcut_get_uri(const char *string)
}
current_num++;
}
- g_string_free(token, true);
+ g_string_free(token, TRUE);
return uri;
}
+#if 0
gboolean shortcut_fill_completion(GtkListStore *store, const char *input)
{
- GList *src = g_hash_table_get_keys(shortcuts);
+ GList *src = g_hash_table_get_keys(c->shortcut.table);
gboolean found = util_fill_completion(store, input, src);
g_list_free(src);
return found;
}
+#endif
/**
* Retrieves th highest placeholder number used in given string.
@@ -190,20 +193,21 @@ static int get_max_placeholder(const char *str)
* pointer with the query part of the given string (everything except of the
* shortcut identifier).
*/
-static const char *shortcut_lookup(const char *string, const char **query)
+static const char *shortcut_lookup(Client *c, const char *string, const char **query)
{
char *p, *uri = NULL;
if ((p = strchr(string, ' '))) {
char *key = g_strndup(string, p - string);
/* is the first word might be a shortcut */
- if ((uri = g_hash_table_lookup(shortcuts, key))) {
+ if ((uri = g_hash_table_lookup(c->shortcut.table, key))) {
*query = p + 1;
}
g_free(key);
}
- if (!uri && default_key && (uri = g_hash_table_lookup(shortcuts, default_key))) {
+ if (!uri && c->shortcut.fallback
+ && (uri = g_hash_table_lookup(c->shortcut.table, c->shortcut.fallback))) {
*query = string;
}
diff --git a/src/shortcut.h b/src/shortcut.h
index c521984..f932abf 100644
--- a/src/shortcut.h
+++ b/src/shortcut.h
@@ -20,12 +20,13 @@
#ifndef _SHORTCUT_H
#define _SHORTCUT_H
-void shortcut_init(void);
-void shortcut_cleanup(void);
-gboolean shortcut_add(const char *key, const char *uri);
-gboolean shortcut_remove(const char *key);
-gboolean shortcut_set_default(const char *key);
-char *shortcut_get_uri(const char *key);
-gboolean shortcut_fill_completion(GtkListStore *store, const char *input);
+void shortcut_init(Client *c);
+void shortcut_cleanup(Client *c);
+gboolean shortcut_add(Client *c, const char *key, const char *uri);
+gboolean shortcut_remove(Client *c, const char *key);
+gboolean shortcut_set_default(Client *c, const char *key);
+char *shortcut_get_uri(Client *c, const char *key);
+/*gboolean shortcut_fill_completion(Client *c, GtkListStore *store, const char *input);*/
#endif /* end of include guard: _SHORTCUT_H */
+
diff --git a/src/util.c b/src/util.c
index 4207598..9670b84 100644
--- a/src/util.c
+++ b/src/util.c
@@ -17,109 +17,156 @@
* along with this program. If not, see http://www.gnu.org/licenses/.
*/
-#include "config.h"
+#include <ctype.h>
#include <fcntl.h>
-#include <sys/file.h>
-#include <stdio.h>
+#include <glib.h>
#include <pwd.h>
-#include <ctype.h>
-#include "main.h"
-#include "util.h"
+#include <stdio.h>
+#include <string.h>
+#include <sys/file.h>
+
#include "ascii.h"
#include "completion.h"
+#include "util.h"
-extern VbCore vb;
+static struct {
+ char *config_dir;
+} util;
+
+static void create_dir_if_not_exists(const char *dirpath);
-static gboolean match(const char *pattern, int patlen, const char *subject);
-static gboolean match_list(const char *pattern, int patlen, const char *subject);
/**
- * Retrieves newly allocated string with vimb config directory with profilename.
- * If profilename is NULL, path to default directory is returned.
- * Returned string must be freed.
+ * Free memory for allocated path strings.
*/
-char *util_get_config_dir(const char *profilename)
+void util_cleanup(void)
{
- char *path = g_build_filename(g_get_user_config_dir(), PROJECT, G_DIR_SEPARATOR_S, profilename, NULL);
- util_create_dir_if_not_exists(path);
-
- return path;
+ if (util.config_dir) {
+ g_free(util.config_dir);
+ }
}
/**
- * Retrieves the path to the cache dir with profilename
- * If profilename is NULL, path to default directory is returned.
- * Returned string must be freed.
+ * Expand ~user, ~/, $ENV and ${ENV} for given string into new allocated
+ * string.
+ *
+ * Returned path must be g_freed.
*/
-char *util_get_cache_dir(const char *profilename)
+char *util_expand(Client *c, const char *src, int expflags)
{
- char *path = g_build_filename(g_get_user_cache_dir(), PROJECT, G_DIR_SEPARATOR_S, profilename, NULL);
- util_create_dir_if_not_exists(path);
+ const char **input = &src;
+ char *result;
+ GString *dst = g_string_new("");
+ int flags = expflags;
- return path;
-}
+ while (**input) {
+ util_parse_expansion(c, input, dst, flags, "\\");
+ if (VB_IS_SEPARATOR(**input)) {
+ /* after space the tilde expansion is allowed */
+ flags = expflags;
+ } else {
+ /* remove tile expansion for next loop */
+ flags &= ~UTIL_EXP_TILDE;
+ }
+ /* move pointer to the next char */
+ (*input)++;
+ }
-/**
- * Retrieves the path to the socket dir with profilename
- * If profilename is NULL, path to default directory is returned.
- * Returned string must be freed.
- */
-char *util_get_runtime_dir(const char *profilename)
-{
- char *path = g_build_filename(g_get_user_runtime_dir(), PROJECT, G_DIR_SEPARATOR_S, profilename, NULL);
- util_create_dir_if_not_exists(path);
+ result = dst->str;
+ g_string_free(dst, FALSE);
- return path;
+ return result;
}
/**
- * Retrieves the users home directory.
+ * Append new data to file.
+ *
+ * @file: File to append the data
+ * @format: Format string used to process va_list
*/
-const char *util_get_home_dir(void)
+gboolean util_file_append(const char *file, const char *format, ...)
{
- const char *dir = g_getenv("HOME");
+ va_list args;
+ FILE *f;
- if (!dir) {
- dir = g_get_home_dir();
- }
+ if ((f = fopen(file, "a+"))) {
+ flock(fileno(f), LOCK_EX);
- return dir;
-}
+ va_start(args, format);
+ vfprintf(f, format, args);
+ va_end(args);
-void util_create_dir_if_not_exists(const char *dirpath)
-{
- if (!g_file_test(dirpath, G_FILE_TEST_IS_DIR)) {
- g_mkdir_with_parents(dirpath, 0755);
+ flock(fileno(f), LOCK_UN);
+ fclose(f);
+
+ return TRUE;
}
+ return FALSE;
}
-void util_create_file_if_not_exists(const char *filename)
+/**
+ * Retrieves the config directory path.
+ * Returnes string must be freed.
+ */
+char *util_get_config_dir(void)
{
- if (!g_file_test(filename, G_FILE_TEST_IS_REGULAR)) {
- FILE *f = fopen(filename, "a");
- fclose(f);
- }
+ char *path = g_build_filename(g_get_user_config_dir(), PROJECT, NULL);
+ create_dir_if_not_exists(path);
+
+ return path;
}
/**
* Retrieves the length bytes from given file.
*
- * The memory of returned string have to be freed!
+ * The memory of returned string have to be freed with g_free().
*/
char *util_get_file_contents(const char *filename, gsize *length)
{
- GError *error = NULL;
+ GError *error = NULL;
char *content = NULL;
- if (!(g_file_test(filename, G_FILE_TEST_IS_REGULAR)
- && g_file_get_contents(filename, &content, length, &error))
- ) {
- g_warning("Cannot open %s: %s", filename, error ? error->message : "file not found");
- g_clear_error(&error);
+
+ if (!g_file_get_contents(filename, &content, length, &error)) {
+ g_warning("Cannot open %s: %s", filename, error->message);
+ g_error_free(error);
}
return content;
}
/**
+ * Buil the path from given directory and filename and checks if the file
+ * exists. If the file does not exists and the create option is not set, this
+ * function returns NULL.
+ * If the file exists or the create option was given the full generated path
+ * is returned as newly allocated string.
+ *
+ * The return value must be freed with g_free.
+ *
+ * @dir: Directory in which the file is searched.
+ * @filename: Filename to built the absolute path with.
+ * @create: If TRUE, the file is created if it does not already exist.
+ */
+char *util_get_filepath(const char *dir, const char *filename, gboolean create)
+{
+ char *fullpath;
+
+ /* Built the full path out of config dir and given file name. */
+ fullpath = g_build_filename(util_get_config_dir(), filename, NULL);
+
+ if (g_file_test(fullpath, G_FILE_TEST_IS_REGULAR)) {
+ return fullpath;
+ } else if (create) {
+ /* If create option was given - create the file. */
+ fclose(fopen(fullpath, "a"));
+ return fullpath;
+ }
+
+ g_free(fullpath);
+ return NULL;
+}
+
+
+/**
* Retrieves the file content as lines.
*
* The result have to be freed by g_strfreev().
@@ -147,7 +194,7 @@ char **util_get_lines(const char *filename)
* unlimited items
*/
GList *util_file_to_unique_list(const char *filename, Util_Content_Func func,
- guint max_items)
+ guint max_items)
{
char *line, **lines;
int i, len;
@@ -213,247 +260,57 @@ GList *util_file_to_unique_list(const char *filename, Util_Content_Func func,
}
/**
- * Append new data to file.
- *
- * @file: File to append the data
- * @format: Format string used to process va_list
- */
-gboolean util_file_append(const char *file, const char *format, ...)
-{
- va_list args;
- FILE *f;
-
- if ((f = fopen(file, "a+"))) {
- flock(fileno(f), LOCK_EX);
-
- va_start(args, format);
- vfprintf(f, format, args);
- va_end(args);
-
- flock(fileno(f), LOCK_UN);
- fclose(f);
-
- return true;
- }
- return false;
-}
-
-/**
- * Prepend new data to file.
- *
- * @file: File to prepend the data
- * @format: Format string used to process va_list
- */
-gboolean util_file_prepend(const char *file, const char *format, ...)
-{
- gboolean res = false;
- va_list args;
- char *content;
- FILE *f;
-
- content = util_get_file_contents(file, NULL);
- if ((f = fopen(file, "w"))) {
- flock(fileno(f), LOCK_EX);
-
- va_start(args, format);
- /* write new content to the file */
- vfprintf(f, format, args);
- va_end(args);
-
- /* append previous file content */
- fputs(content, f);
-
- flock(fileno(f), LOCK_UN);
- fclose(f);
-
- res = true;
- }
- g_free(content);
-
- return res;
-}
-
-/**
- * Retrieves the first line from file and delete it from file.
- *
- * @file: file to read from
- * @item_count: will be filled with the number of remaining lines in file if it
- * is not NULL.
- *
- * Returned string must be freed with g_free.
- */
-char *util_file_pop_line(const char *file, int *item_count)
-{
- char **lines = util_get_lines(file);
- char *line = NULL;
- int count = 0;
-
- if (lines) {
- int len = g_strv_length(lines);
- if (len) {
- line = g_strdup(lines[0]);
- /* minus one for last empty item and one for popped item */
- count = len - 2;
- char *new = g_strjoinv("\n", lines + 1);
- g_file_set_contents(file, new, -1, NULL);
- g_free(new);
- }
- g_strfreev(lines);
- }
-
- if (item_count) {
- *item_count = count;
- }
- return line;
-}
-
-char *util_strcasestr(const char *haystack, const char *needle)
-{
- guchar c1, c2;
- int i, j;
- int nlen = strlen(needle);
- int hlen = strlen(haystack) - nlen + 1;
-
- for (i = 0; i < hlen; i++) {
- for (j = 0; j < nlen; j++) {
- c1 = haystack[i + j];
- c2 = needle[j];
- if (toupper(c1) != toupper(c2)) {
- goto next;
- }
- }
- return (char*)haystack + i;
-next:
- ;
- }
- return NULL;
-}
-
-/**
- * Replaces appearances of search in string by given replace.
- * Returns a new allocated string if search was found.
- */
-char *util_str_replace(const char* search, const char* replace, const char* string)
-{
- if (!string) {
- return NULL;
- }
-
- char **buf = g_strsplit(string, search, -1);
- char *ret = g_strjoinv(replace, buf);
- g_strfreev(buf);
-
- return ret;
-}
-
-/**
- * Creates a temporary file with given content.
- *
- * Upon success, and if file is non-NULL, the actual file path used is
- * returned in file. This string should be freed with g_free() when not
- * needed any longer.
+ * Fills file path completion entries into given list store for also given
+ * input.
*/
-gboolean util_create_tmp_file(const char *content, char **file)
+gboolean util_filename_fill_completion(Client *c, GtkListStore *store, const char *input)
{
- int fp;
- ssize_t bytes, len;
-
- fp = g_file_open_tmp(PROJECT "-XXXXXX", file, NULL);
- if (fp == -1) {
- g_critical("Could not create temp file %s", *file);
- g_free(*file);
- return false;
- }
-
- len = strlen(content);
-
- /* write content into temporary file */
- bytes = write(fp, content, len);
- if (bytes < len) {
- close(fp);
- unlink(*file);
- g_critical("Could not write temp file %s", *file);
- g_free(*file);
-
- return false;
- }
- close(fp);
+ gboolean found = FALSE;
+ GError *error = NULL;
+ char *input_dirname, *real_dirname;
+ const char *last_slash, *input_basename;
+ GDir *dir;
+
+ last_slash = strrchr(input, '/');
+ input_basename = last_slash ? last_slash + 1 : input;
+ input_dirname = g_strndup(input, input_basename - input);
+ real_dirname = util_expand(
+ c,
+ *input_dirname ? input_dirname : ".",
+ UTIL_EXP_TILDE|UTIL_EXP_DOLLAR|UTIL_EXP_SPECIAL
+ );
- return true;
-}
+ dir = g_dir_open(real_dirname, 0, &error);
+ if (error) {
+ /* Can't open directory, likely bad user input */
+ g_error_free(error);
+ } else {
+ GtkTreeIter iter;
+ const char *filename;
+ char *fullpath, *result;
-/**
- * Build the absolute file path of given path and possible given directory.
- *
- * Returned path must be freed.
- */
-char *util_build_path(const char *path, const char *dir)
-{
- char *fullPath = NULL, *fexp, *dexp, *p;
- int expflags = UTIL_EXP_TILDE|UTIL_EXP_DOLLAR;
-
- /* if the path could be expanded */
- if ((fexp = util_expand(path, expflags))) {
- if (*fexp == '/') {
- /* path is already absolute, no need to use given dir - there is
- * no need to free fexp, bacuse this should be done by the caller
- * on fullPath later */
- fullPath = fexp;
- } else if (dir && *dir) {
- /* try to expand also the dir given - this may be ~/path */
- if ((dexp = util_expand(dir, expflags))) {
- /* use expanded dir and append expanded path */
- fullPath = g_build_filename(dexp, fexp, NULL);
- g_free(dexp);
+ while ((filename = g_dir_read_name(dir))) {
+ if (g_str_has_prefix(filename, input_basename)) {
+ fullpath = g_build_filename(real_dirname, filename, NULL);
+ if (g_file_test(fullpath, G_FILE_TEST_IS_DIR)) {
+ result = g_strconcat(input_dirname, filename, "/", NULL);
+ } else {
+ result = g_strconcat(input_dirname, filename, NULL);
+ }
+ g_free(fullpath);
+ gtk_list_store_append(store, &iter);
+ gtk_list_store_set(store, &iter, COMPLETION_STORE_FIRST, result, -1);
+ g_free(result);
+ found = TRUE;
}
- g_free(fexp);
- }
- }
-
- /* if full path not found use current dir */
- if (!fullPath) {
- fullPath = g_build_filename(g_get_current_dir(), path, NULL);
- }
-
- if ((p = strrchr(fullPath, '/'))) {
- *p = '\0';
- util_create_dir_if_not_exists(fullPath);
- *p = '/';
- }
-
- return fullPath;
-}
-
-/**
- * Expand ~user, ~/, $ENV and ${ENV} for given string into new allocated
- * string.
- *
- * Returned path must be g_freed.
- */
-char *util_expand(const char *src, int expflags)
-{
- const char **input = &src;
- char *result;
- GString *dst = g_string_new("");
- int flags = expflags;
-
- while (**input) {
- util_parse_expansion(input, dst, flags, "\\");
- if (VB_IS_SEPARATOR(**input)) {
- /* after space the tilde expansion is allowed */
- flags = expflags;
- } else {
- /* remove tile expansion for next loop */
- flags &= ~UTIL_EXP_TILDE;
}
- /* move pointer to the next char */
- (*input)++;
+ g_dir_close(dir);
}
- result = dst->str;
- g_string_free(dst, false);
+ g_free(input_dirname);
+ g_free(real_dirname);
- return result;
+ return found;
}
/**
@@ -462,19 +319,19 @@ char *util_expand(const char *src, int expflags)
* not expanded char. If no expansion pattern was found, the first char is
* appended to given GString.
*
- * @input: String pointer with the content to be parsed.
- * @str: GString that will be filled with expanded content.
- * @flags Flags that determine which expansion are processed.
- * @quoteable String of chars that are additionally escapable by \.
- * Returns true if input started with expandable pattern.
+ * @input: String pointer with the content to be parsed.
+ * @str: GString that will be filled with expanded content.
+ * @flags Flags that determine which expansion are processed.
+ * @quoteable: String of chars that are additionally escapable by \.
+ * Returns TRUE if input started with expandable pattern.
*/
-gboolean util_parse_expansion(const char **input, GString *str, int flags,
- const char *quoteable)
+gboolean util_parse_expansion(Client *c, const char **input, GString *str,
+ int flags, const char *quoteable)
{
GString *name;
const char *env, *prev, quote = '\\';
struct passwd *pwd;
- gboolean expanded = false;
+ gboolean expanded = FALSE;
prev = *input;
if (flags & UTIL_EXP_TILDE && **input == '~') {
@@ -482,8 +339,8 @@ gboolean util_parse_expansion(const char **input, GString *str, int flags,
(*input)++;
if (**input == '/') {
- g_string_append(str, util_get_home_dir());
- expanded = true;
+ g_string_append(str, g_get_home_dir());
+ expanded = TRUE;
/* if there is no char or space after ~/ skip the / to get
* /home/user instead of /home/user/ */
if (!*(*input + 1) || VB_IS_SPACE(*(*input + 1))) {
@@ -501,9 +358,9 @@ gboolean util_parse_expansion(const char **input, GString *str, int flags,
/* append the name to the destination string */
if ((pwd = getpwnam(name->str))) {
g_string_append(str, pwd->pw_dir);
- expanded = true;
+ expanded = TRUE;
}
- g_string_free(name, true);
+ g_string_free(name, TRUE);
}
/* move pointer back to last expanded char */
(*input)--;
@@ -540,13 +397,13 @@ gboolean util_parse_expansion(const char **input, GString *str, int flags,
/* move pointer back to last expanded char */
(*input)--;
/* variable are expanded even if they do not exists */
- expanded = true;
- g_string_free(name, true);
+ expanded = TRUE;
+ g_string_free(name, TRUE);
} else if (flags & UTIL_EXP_SPECIAL && **input == '%') {
- if (*vb.state.uri) {
+ if (*c->state.uri) {
/* TODO check for modifiers like :h:t:r:e */
- g_string_append(str, vb.state.uri);
- expanded = true;
+ g_string_append(str, c->state.uri);
+ expanded = TRUE;
}
}
@@ -583,275 +440,48 @@ gboolean util_parse_expansion(const char **input, GString *str, int flags,
return expanded;
}
-/**
- * Compares given string against also given list of patterns.
- *
- * * Matches any sequence of characters.
- * ? Matches any single character except of '/'.
- * {foo,bar} Matches foo or bar - '{', ',' and '}' within this pattern must be
- * escaped by '\'. '*' and '?' have no special meaning within the
- * curly braces.
- * *?{} these chars must always be escaped by '\' to match them literally
- */
-gboolean util_wildmatch(const char *pattern, const char *subject)
-{
- const char *end;
- int braces, patlen, count;
-
- /* loop through all pattens */
- for (count = 0; *pattern; pattern = (*end == ',' ? end + 1 : end), count++) {
- /* find end of the pattern - but be careful with comma in curly braces */
- braces = 0;
- for (end = pattern; *end && (*end != ',' || braces || *(end - 1) == '\\'); ++end) {
- if (*end == '{') {
- braces++;
- } else if (*end == '}') {
- braces--;
- }
- }
- /* ignore single comma */
- if (*pattern == *end) {
- continue;
- }
- /* calculate the length of the pattern */
- patlen = end - pattern;
-
- /* if this pattern matches - return */
- if (match(pattern, patlen, subject)) {
- return true;
- }
- }
-
- if (!count) {
- /* empty pattern matches only on empty subject */
- return !*subject;
- }
- /* there where one or more patterns but none of them matched */
- return false;
-}
-
-/**
- * Compares given subject string against the given pattern.
- * The pattern needs not to bee NUL terminated.
- */
-static gboolean match(const char *pattern, int patlen, const char *subject)
+char *util_strcasestr(const char *haystack, const char *needle)
{
- int i;
- char sl, pl;
-
- while (patlen > 0) {
- switch (*pattern) {
- case '?':
- /* '?' matches a single char except of / and subject end */
- if (*subject == '/' || !*subject) {
- return false;
- }
- break;
-
- case '*':
- /* easiest case - the '*' ist the last char in pattern - this
- * will always match */
- if (patlen == 1) {
- return true;
- }
- /* Try to match as much as possible. Try to match the complete
- * uri, if that fails move forward in uri and check for a
- * match. */
- i = strlen(subject);
- while (i >= 0 && !match(pattern + 1, patlen - 1, subject + i)) {
- i--;
- }
- return i >= 0;
-
- case '}':
- /* spurious '}' in pattern */
- return false;
-
- case '{':
- /* possible {foo,bar} pattern */
- return match_list(pattern, patlen, subject);
-
- case '\\':
- /* '\' escapes next special char */
- if (strchr("*?{}", pattern[1])) {
- pattern++;
- patlen--;
- if (*pattern != *subject) {
- return false;
- }
- }
- break;
+ guchar c1, c2;
+ int i, j;
+ int nlen = strlen(needle);
+ int hlen = strlen(haystack) - nlen + 1;
- default:
- /* compare case insensitive */
- sl = *subject;
- if (VB_IS_UPPER(sl)) {
- sl += 'a' - 'A';
- }
- pl = *pattern;
- if (VB_IS_UPPER(pl)) {
- pl += 'a' - 'A';
- }
- if (sl != pl) {
- return false;
- }
- break;
+ for (i = 0; i < hlen; i++) {
+ for (j = 0; j < nlen; j++) {
+ c1 = haystack[i + j];
+ c2 = needle[j];
+ if (toupper(c1) != toupper(c2)) {
+ goto next;
+ }
}
- /* do another loop run with next pattern and subject char */
- pattern++;
- patlen--;
- subject++;
+ return (char*)haystack + i;
+next:
+ ;
}
-
- /* on end of pattern only a also ended subject is a match */
- return !*subject;
+ return NULL;
}
/**
- * Matches pattern starting with '{'.
- * This function can process also on none null terminated pattern.
+ * Replaces appearances of search in string by given replace.
+ * Returns a new allocated string if search was found.
*/
-static gboolean match_list(const char *pattern, int patlen, const char *subject)
+char *util_str_replace(const char* search, const char* replace, const char* string)
{
- int endlen;
- const char *end, *s;
-
- /* finde the next none escaped '}' */
- for (end = pattern, endlen = patlen; endlen > 0 && *end != '}'; end++, endlen--) {
- /* if escape char - move pointer one additional step */
- if (*end == '\\') {
- end++;
- endlen--;
- }
- }
-
- if (!*end) {
- /* unterminated '{' in pattern */
- return false;
- }
-
- s = subject;
- end++; /* skip over } */
- endlen--;
- pattern++; /* skip over { */
- patlen--;
- while (true) {
- switch (*pattern) {
- case ',':
- if (match(end, endlen, s)) {
- return true;
- }
- s = subject;
- pattern++;
- patlen--;
- break;
-
- case '}':
- return match(end, endlen, s);
-
- case '\\':
- if (pattern[1] == ',' || pattern[1] == '}' || pattern[1] == '{') {
- pattern++;
- patlen--;
- }
- /* fall through */
-
- default:
- if (*pattern == *s) {
- pattern++;
- patlen--;
- s++;
- } else {
- /* this item of the list does not match - move forward to
- * the next none escaped ',' or '}' */
- s = subject;
- for (s = subject; *pattern != ',' && *pattern != '}'; pattern++, patlen--) {
- /* if escape char is found - skip next char */
- if (*pattern == '\\') {
- pattern++;
- patlen--;
- }
- }
- /* found ',' skip over it to check the next list item */
- if (*pattern == ',') {
- pattern++;
- patlen--;
- }
- }
- }
+ if (!string) {
+ return NULL;
}
-}
-
-/**
- * Fills the given list store by matching data of also given src list.
- */
-gboolean util_fill_completion(GtkListStore *store, const char *input, GList *src)
-{
- gboolean found = false;
- GtkTreeIter iter;
-
- if (!input || !*input) {
- for (GList *l = src; l; l = l->next) {
- gtk_list_store_append(store, &iter);
- gtk_list_store_set(store, &iter, COMPLETION_STORE_FIRST, l->data, -1);
- found = true;
- }
- } else {
- for (GList *l = src; l; l = l->next) {
- char *value = (char*)l->data;
- if (g_str_has_prefix(value, input)) {
- gtk_list_store_append(store, &iter);
- gtk_list_store_set(store, &iter, COMPLETION_STORE_FIRST, l->data, -1);
- found = true;
- }
- }
- }
+ char **buf = g_strsplit(string, search, -1);
+ char *ret = g_strjoinv(replace, buf);
+ g_strfreev(buf);
- return found;
+ return ret;
}
-gboolean util_filename_fill_completion(GtkListStore *store, const char *input)
+static void create_dir_if_not_exists(const char *dirpath)
{
- gboolean found = false;
-
- const char *last_slash = strrchr(input, '/');
- const char *input_basename = last_slash ? last_slash + 1 : input;
- char *input_dirname = g_strndup(input, input_basename - input);
- char *real_dirname = util_expand(
- *input_dirname ? input_dirname : ".",
- UTIL_EXP_TILDE|UTIL_EXP_DOLLAR|UTIL_EXP_SPECIAL
- );
-
- GError *error = NULL;
- GDir *dir = g_dir_open(real_dirname, 0, &error);
- if (error) {
- /* Can't open directory, likely bad user input */
- g_error_free(error);
- } else {
- const char *filename;
- GtkTreeIter iter;
- while ((filename = g_dir_read_name(dir))) {
- if (g_str_has_prefix(filename, input_basename)) {
- char *fullpath = g_build_filename(real_dirname, filename, NULL);
- char *result;
- if (g_file_test(fullpath, G_FILE_TEST_IS_DIR)) {
- result = g_strconcat(input_dirname, filename, "/", NULL);
- } else {
- result = g_strconcat(input_dirname, filename, NULL);
- }
- g_free(fullpath);
- gtk_list_store_append(store, &iter);
- gtk_list_store_set(store, &iter, COMPLETION_STORE_FIRST, result, -1);
- g_free(result);
- found = true;
- }
- }
- g_dir_close(dir);
+ if (!g_file_test(dirpath, G_FILE_TEST_IS_DIR)) {
+ g_mkdir_with_parents(dirpath, 0755);
}
-
- g_free(input_dirname);
- g_free(real_dirname);
-
- return found;
}
diff --git a/src/util.h b/src/util.h
index 9ed1236..c09b098 100644
--- a/src/util.h
+++ b/src/util.h
@@ -20,6 +20,7 @@
#ifndef _UTIL_H
#define _UTIL_H
+#include <glib.h>
#include "main.h"
enum {
@@ -27,31 +28,21 @@ enum {
UTIL_EXP_DOLLAR = 0x02, /* $ENV and ${ENV} expansion */
UTIL_EXP_SPECIAL = 0x04, /* expand % to current URI */
};
-
typedef void *(*Util_Content_Func)(const char*, const char*);
-char* util_get_config_dir(const char* profilename);
-char* util_get_cache_dir(const char* profilename);
-char* util_get_runtime_dir(const char* profilename);
-const char* util_get_home_dir(void);
-void util_create_dir_if_not_exists(const char* dirpath);
-void util_create_file_if_not_exists(const char* filename);
-char* util_get_file_contents(const char* filename, gsize* length);
-char** util_get_lines(const char* filename);
-GList *util_file_to_unique_list(const char *filename, Util_Content_Func func,
- guint max_items);
+void util_cleanup(void);
+char *util_expand(Client *c, const char *src, int expflags);
gboolean util_file_append(const char *file, const char *format, ...);
-gboolean util_file_prepend(const char *file, const char *format, ...);
-char *util_file_pop_line(const char *file, int *item_count);
-char* util_strcasestr(const char* haystack, const char* needle);
+char *util_get_config_dir(void);
+char *util_get_file_contents(const char *filename, gsize *length);
+char *util_get_filepath(const char *dir, const char *filename, gboolean create);
+char **util_get_lines(const char *filename);
+GList *util_file_to_unique_list(const char *filename, Util_Content_Func func,
+ guint max_items);
+gboolean util_filename_fill_completion(Client *c, GtkListStore *store, const char *input);
+gboolean util_parse_expansion(Client *c, const char **input, GString *str,
+ int flags, const char *quoteable);
char *util_str_replace(const char* search, const char* replace, const char* string);
-gboolean util_create_tmp_file(const char *content, char **file);
-char *util_build_path(const char *path, const char *dir);
-char *util_expand(const char *src, int expflags);
-gboolean util_parse_expansion(const char **input, GString *str, int flags,
- const char *quoteable);
-gboolean util_wildmatch(const char *pattern, const char *subject);
-gboolean util_fill_completion(GtkListStore *store, const char *input, GList *src);
-gboolean util_filename_fill_completion(GtkListStore *store, const char *input);
+char *util_strcasestr(const char *haystack, const char *needle);
#endif /* end of include guard: _UTIL_H */
diff --git a/src/webextension/Makefile b/src/webextension/Makefile
new file mode 100644
index 0000000..671c23f
--- /dev/null
+++ b/src/webextension/Makefile
@@ -0,0 +1,19 @@
+BASEDIR=../..
+include $(BASEDIR)/config.mk
+
+OBJ = $(patsubst %.c, %.lo, $(wildcard *.c))
+
+all: $(EXTTARGET)
+
+clean:
+ $(RM) -f $(EXTTARGET) *.lo
+
+$(EXTTARGET): $(OBJ)
+ @echo "$(CC) $@"
+ @$(CC) $(EXTLDFLAGS) ${OBJ} -o $@
+
+%.lo: %.c
+ @echo "${CC} $@"
+ @$(CC) $(EXTCFLAGS) -fPIC -c -o $@ $<
+
+.PHONY: all clean
diff --git a/src/webextension/ext-dom.c b/src/webextension/ext-dom.c
new file mode 100644
index 0000000..26aeaf0
--- /dev/null
+++ b/src/webextension/ext-dom.c
@@ -0,0 +1,179 @@
+/**
+ * vimb - a webkit based vim like browser.
+ *
+ * Copyright (C) 2012-2015 Daniel Carl
+ *
+ * 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, see http://www.gnu.org/licenses/.
+ */
+
+#include <glib.h>
+#include <webkitdom/webkitdom.h>
+
+#include "ext-main.h"
+#include "ext-dom.h"
+
+static gboolean is_element_visible(WebKitDOMHTMLElement *element);
+
+
+/**
+ * Checks if given dom element is an editable element.
+ */
+gboolean ext_dom_is_editable(WebKitDOMElement *element)
+{
+ char *type;
+ gboolean result = FALSE;
+
+ if (!element) {
+ return FALSE;
+ }
+
+ /* element is editable if it's a text area or input with no type, text or
+ * password */
+ if (webkit_dom_html_element_get_is_content_editable(WEBKIT_DOM_HTML_ELEMENT(element))
+ || WEBKIT_DOM_IS_HTML_TEXT_AREA_ELEMENT(element)) {
+ return TRUE;
+ }
+
+ if (WEBKIT_DOM_IS_HTML_INPUT_ELEMENT(element)) {
+ type = webkit_dom_html_input_element_get_input_type(WEBKIT_DOM_HTML_INPUT_ELEMENT(element));
+ /* Input element without type attribute are rendered and behave like
+ * type = text and there are a lot of pages in the wild using input
+ * field without type attribute. */
+ if (!*type
+ || !g_ascii_strcasecmp(type, "text")
+ || !g_ascii_strcasecmp(type, "password")
+ || !g_ascii_strcasecmp(type, "color")
+ || !g_ascii_strcasecmp(type, "date")
+ || !g_ascii_strcasecmp(type, "datetime")
+ || !g_ascii_strcasecmp(type, "datetime-local")
+ || !g_ascii_strcasecmp(type, "email")
+ || !g_ascii_strcasecmp(type, "month")
+ || !g_ascii_strcasecmp(type, "number")
+ || !g_ascii_strcasecmp(type, "search")
+ || !g_ascii_strcasecmp(type, "tel")
+ || !g_ascii_strcasecmp(type, "time")
+ || !g_ascii_strcasecmp(type, "url")
+ || !g_ascii_strcasecmp(type, "week"))
+ {
+ result = TRUE;
+ }
+
+ g_free(type);
+ }
+
+ return result;
+}
+
+/**
+ * Find the first editable element and set the focus on it and enter input
+ * mode.
+ * Returns true if there was an editable element focused.
+ */
+gboolean ext_dom_focus_input(WebKitDOMDocument *doc)
+{
+ WebKitDOMNode *html, *node;
+ WebKitDOMNodeList *list;
+ WebKitDOMXPathNSResolver *resolver;
+ WebKitDOMXPathResult* result;
+ WebKitDOMDocument *frame_doc;
+ guint i, len;
+
+ list = webkit_dom_document_get_elements_by_tag_name(doc, "html");
+ if (!list) {
+ return FALSE;
+ }
+
+ html = webkit_dom_node_list_item(list, 0);
+ g_object_unref(list);
+
+ resolver = webkit_dom_document_create_ns_resolver(doc, html);
+ if (!resolver) {
+ return FALSE;
+ }
+
+ /* Use translate to match xpath expression case insensitive so that also
+ * intput filed of type="TEXT" are matched. */
+ result = webkit_dom_document_evaluate(
+ doc, "//input[not(@type) "
+ "or translate(@type,'ETX','etx')='text' "
+ "or translate(@type,'ADOPRSW','adoprsw')='password' "
+ "or translate(@type,'CLOR','clor')='color' "
+ "or translate(@type,'ADET','adet')='date' "
+ "or translate(@type,'ADEIMT','adeimt')='datetime' "
+ "or translate(@type,'ACDEILMOT','acdeilmot')='datetime-local' "
+ "or translate(@type,'AEILM','aeilm')='email' "
+ "or translate(@type,'HMNOT','hmnot')='month' "
+ "or translate(@type,'BEMNRU','bemnru')='number' "
+ "or translate(@type,'ACEHRS','acehrs')='search' "
+ "or translate(@type,'ELT','elt')='tel' "
+ "or translate(@type,'EIMT','eimt')='time' "
+ "or translate(@type,'LRU','lru')='url' "
+ "or translate(@type,'EKW','ekw')='week' "
+ "]|//textarea",
+ html, resolver, 5, NULL, NULL
+ );
+ if (!result) {
+ return FALSE;
+ }
+ while ((node = webkit_dom_xpath_result_iterate_next(result, NULL))) {
+ if (is_element_visible(WEBKIT_DOM_HTML_ELEMENT(node))) {
+ webkit_dom_element_focus(WEBKIT_DOM_ELEMENT(node));
+ return TRUE;
+ }
+ }
+
+ /* Look for editable elements in frames too. */
+ list = webkit_dom_document_get_elements_by_tag_name(doc, "iframe");
+ len = webkit_dom_node_list_get_length(list);
+
+ for (i = 0; i < len; i++) {
+ node = webkit_dom_node_list_item(list, i);
+ frame_doc = webkit_dom_html_iframe_element_get_content_document(WEBKIT_DOM_HTML_IFRAME_ELEMENT(node));
+ /* Stop on first frame with focused element. */
+ if (ext_dom_focus_input(frame_doc)) {
+ g_object_unref(list);
+ return TRUE;
+ }
+ }
+ g_object_unref(list);
+
+ return FALSE;
+}
+
+/**
+ * Retrieves the content of given editable element.
+ * Not that the returned value must be freed.
+ */
+char *ext_dom_editable_get_value(WebKitDOMElement *element)
+{
+ char *value = NULL;
+
+ if ((webkit_dom_html_element_get_is_content_editable(WEBKIT_DOM_HTML_ELEMENT(element)))) {
+ value = webkit_dom_html_element_get_inner_text(WEBKIT_DOM_HTML_ELEMENT(element));
+ } else if (WEBKIT_DOM_IS_HTML_INPUT_ELEMENT(WEBKIT_DOM_HTML_INPUT_ELEMENT(element))) {
+ value = webkit_dom_html_input_element_get_value(WEBKIT_DOM_HTML_INPUT_ELEMENT(element));
+ } else {
+ value = webkit_dom_html_text_area_element_get_value(WEBKIT_DOM_HTML_TEXT_AREA_ELEMENT(element));
+ }
+
+ return value;
+}
+
+/**
+ * Indicates if the give nelement is visible.
+ */
+static gboolean is_element_visible(WebKitDOMHTMLElement *element)
+{
+ return TRUE;
+}
diff --git a/src/handlers.h b/src/webextension/ext-dom.h
index a38d9e1..657821d 100644
--- a/src/handlers.h
+++ b/src/webextension/ext-dom.h
@@ -17,14 +17,14 @@
* along with this program. If not, see http://www.gnu.org/licenses/.
*/
-#ifndef _HANDLERS_H
-#define _HANDLERS_H
+#ifndef _EXT_DOM_H
+#define _EXT_DOM_H
-void handlers_init(void);
-void handlers_cleanup(void);
-gboolean handler_add(const char *key, const char *cmd);
-gboolean handler_remove(const char *key);
-gboolean handle_uri(const char *uri);
-gboolean handler_fill_completion(GtkListStore *store, const char *input);
+#include <glib.h>
+#include <webkitdom/webkitdom.h>
-#endif /* end of include guard: _HANDLERS_H */
+gboolean ext_dom_is_editable(WebKitDOMElement *element);
+gboolean ext_dom_focus_input(WebKitDOMDocument *doc);
+char *ext_dom_editable_get_value(WebKitDOMElement *element);
+
+#endif /* end of include guard: _EXT-DOM_H */
diff --git a/src/webextension/ext-main.c b/src/webextension/ext-main.c
new file mode 100644
index 0000000..669fd7d
--- /dev/null
+++ b/src/webextension/ext-main.c
@@ -0,0 +1,360 @@
+/**
+ * vimb - a webkit based vim like browser.
+ *
+ * Copyright (C) 2012-2015 Daniel Carl
+ *
+ * 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, see http://www.gnu.org/licenses/.
+ */
+
+#include <JavaScriptCore/JavaScript.h>
+#include <gio/gio.h>
+#include <glib.h>
+#include <libsoup/soup.h>
+#include <webkit2/webkit-web-extension.h>
+
+#include "ext-main.h"
+#include "ext-dom.h"
+#include "ext-util.h"
+
+static void add_onload_event_observers(WebKitDOMDocument *doc);
+static void dbus_emit_signal(const char *name, GVariant *data);
+static void dbus_handle_method_call(GDBusConnection *conn, const char *sender,
+ const char *object_path, const char *interface_name, const char *method,
+ GVariant *parameters, GDBusMethodInvocation *invocation, gpointer data);
+static gboolean dbus_own_name_sync(GDBusConnection *connection, const char *name,
+ GBusNameOwnerFlags flags);
+static void on_dbus_name_acquire(GDBusConnection *connection, const char *name, gpointer data);
+static void on_editable_change_focus(WebKitDOMEventTarget *target, WebKitDOMEvent *event);
+static void on_page_created(WebKitWebExtension *ext, WebKitWebPage *page, gpointer data);
+static void on_web_page_document_loaded(WebKitWebPage *page, gpointer data);
+static gboolean on_web_page_send_request(WebKitWebPage *page, WebKitURIRequest *request,
+ WebKitURIResponse *response, gpointer data);
+
+static const GDBusInterfaceVTable interface_vtable = {
+ dbus_handle_method_call,
+ NULL,
+ NULL
+};
+
+static const char introspection_xml[] =
+ "<node>"
+ " <interface name='" VB_WEBEXTENSION_INTERFACE "'>"
+ " <signal name='EditableChangeFocus'>"
+ " <arg type='b' name='focused' direction='out'/>"
+ " </signal>"
+ " <method name='FocusInput'>"
+ " </method>"
+ " <signal name='PageCreated'>"
+ " <arg type='t' name='page_id' direction='out'/>"
+ " </signal>"
+ " <method name='SetHeaderSetting'>"
+ " <arg type='s' name='headers' direction='in'/>"
+ " </method>"
+ " </interface>"
+ "</node>";
+
+/* Global struct to hold internal used variables. */
+struct Ext {
+ guint regid;
+ GDBusConnection *connection;
+ WebKitWebPage *webpage;
+ WebKitDOMElement *active;
+ GHashTable *headers;
+ GHashTable *documents;
+ gboolean input_focus;
+};
+struct Ext ext = {0};
+
+
+/**
+ * Webextension entry point.
+ */
+G_MODULE_EXPORT
+void webkit_web_extension_initialize_with_user_data(WebKitWebExtension *extension, GVariant *data)
+{
+ char *extid, *service_name;
+ g_variant_get(data, "(s)", &extid);
+
+ /* Get the DBus connection for the bus type. It would be a better to use
+ * the async g_bus_own_name for this, but this leads to cases where pages
+ * are created and documents are loaded before we get a name and are able
+ * to call to the UI process. */
+ ext.connection = g_bus_get_sync(G_BUS_TYPE_SESSION, NULL, NULL);
+
+ service_name = g_strdup_printf("%s-%s", VB_WEBEXTENSION_SERVICE_NAME, extid);
+
+ /* Try to own name synchronously. */
+ if (ext.connection && dbus_own_name_sync(ext.connection, service_name, G_BUS_NAME_OWNER_FLAGS_NONE)) {
+ on_dbus_name_acquire(ext.connection, service_name, extension);
+ }
+
+ g_free(service_name);
+
+ g_signal_connect(extension, "page-created", G_CALLBACK(on_page_created), NULL);
+}
+
+/**
+ * Add observers to doc event for given document and all the contained iframes
+ * too.
+ */
+static void add_onload_event_observers(WebKitDOMDocument *doc)
+{
+ WebKitDOMEventTarget *target;
+
+ /* Add the document to the table of known documents or if already exists
+ * return to not apply observers multiple times. */
+ if (!g_hash_table_add(ext.documents, doc)) {
+ return;
+ }
+
+ /* We have to use default view instead of the document itself in case this
+ * function is called with content document of an iframe. Else the event
+ * observing does not work. */
+ target = WEBKIT_DOM_EVENT_TARGET(webkit_dom_document_get_default_view(doc));
+
+ webkit_dom_event_target_add_event_listener(target, "focus",
+ G_CALLBACK(on_editable_change_focus), TRUE, NULL);
+ webkit_dom_event_target_add_event_listener(target, "blur",
+ G_CALLBACK(on_editable_change_focus), TRUE, NULL);
+ /* Check for focused editable elements also if they where focused before
+ * the event observer where set up. */
+ /* TODO this is not needed for strict-focus=on */
+ on_editable_change_focus(target, NULL);
+}
+
+/**
+ * Emits a signal over dbus.
+ *
+ * @name: Signal name to emit.
+ * @data: GVariant value used as value for the signal or NULL.
+ */
+static void dbus_emit_signal(const char *name, GVariant *data)
+{
+ GError *error = NULL;
+
+ /* Don't do anythings if the dbus connection was not established. */
+ if (!ext.connection) {
+ return;
+ }
+
+ /* propagate the signal over dbus */
+ g_dbus_connection_emit_signal(ext.connection, NULL,
+ VB_WEBEXTENSION_OBJECT_PATH, VB_WEBEXTENSION_INTERFACE, name,
+ data, &error);
+
+ /* check for error */
+ if (error) {
+ g_warning("Failed to emit signal '%s': %s", name, error->message);
+ g_error_free(error);
+ }
+}
+
+/**
+ * Handle dbus method calls.
+ */
+static void dbus_handle_method_call(GDBusConnection *conn, const char *sender,
+ const char *object_path, const char *interface_name, const char *method,
+ GVariant *parameters, GDBusMethodInvocation *invocation, gpointer data)
+{
+ char *value;
+
+ if (!g_strcmp0(method, "FocusInput")) {
+ ext_dom_focus_input(webkit_web_page_get_dom_document(ext.webpage));
+ g_dbus_method_invocation_return_value(invocation, NULL);
+ } else if (!g_strcmp0(method, "SetHeaderSetting")) {
+ g_variant_get(parameters, "(s)", &value);
+
+ if (ext.headers) {
+ soup_header_free_param_list(ext.headers);
+ ext.headers = NULL;
+ }
+ ext.headers = soup_header_parse_param_list(value);
+ g_dbus_method_invocation_return_value(invocation, NULL);
+ }
+}
+
+/**
+ * The synchronous and blocking pendent to the g_bus_own_name().
+ *
+ * @bus_type: The type of bus to own a name on.
+ * @name: The well-known name to own.
+ * @flags: A set of flags from the #GBusNameOwnerFlags enumeration.
+ */
+static gboolean dbus_own_name_sync(GDBusConnection *connection, const char *name,
+ GBusNameOwnerFlags flags)
+{
+ GError *error = NULL;
+ guint32 request_name_reply = 0;
+ GVariant *result;
+
+ result = g_dbus_connection_call_sync(
+ connection,
+ "org.freedesktop.DBus",
+ "/org/freedesktop/DBus",
+ "org.freedesktop.DBus",
+ "RequestName",
+ g_variant_new("(su)", name, flags),
+ G_VARIANT_TYPE("(u)"),
+ G_DBUS_CALL_FLAGS_NONE,
+ -1,
+ NULL,
+ &error);
+
+ if (result) {
+ g_variant_get(result, "(u)", &request_name_reply);
+ g_variant_unref(result);
+
+ if (1 == request_name_reply) {
+ return TRUE;
+ }
+ } else {
+ g_warning("Failed to acquire DBus name: %s", error->message);
+ g_error_free(error);
+ }
+ return FALSE;
+}
+
+/**
+ * Called when the dbus name is aquired and registers our object.
+ */
+static void on_dbus_name_acquire(GDBusConnection *connection, const char *name, gpointer data)
+{
+ GError *error = NULL;
+ static GDBusNodeInfo *node_info = NULL;
+
+ g_return_if_fail(G_IS_DBUS_CONNECTION(connection));
+
+ if (!node_info) {
+ node_info = g_dbus_node_info_new_for_xml(introspection_xml, NULL);
+ }
+
+ /* register the webextension object */
+ ext.connection = connection;
+ ext.regid = g_dbus_connection_register_object(
+ connection,
+ VB_WEBEXTENSION_OBJECT_PATH,
+ node_info->interfaces[0],
+ &interface_vtable,
+ WEBKIT_WEB_EXTENSION(data),
+ NULL,
+ &error);
+
+ if (!ext.regid) {
+ g_warning("Failed to register web extension object: %s", error->message);
+ g_error_free(error);
+ }
+}
+
+/**
+ * Callback called if a editable element changes it focus state.
+ * Event target may be a WebKitDOMDocument (in case of iframe) or a
+ * WebKitDOMDOMWindow.
+ */
+static void on_editable_change_focus(WebKitDOMEventTarget *target, WebKitDOMEvent *event)
+{
+ gboolean input_focus;
+ WebKitDOMDocument *doc;
+ WebKitDOMElement *active;
+
+ if (WEBKIT_DOM_IS_DOM_WINDOW(target)) {
+ g_object_get(target, "document", &doc, NULL);
+ } else {
+ /* target is a doc document */
+ doc = WEBKIT_DOM_DOCUMENT(target);
+ }
+ active = webkit_dom_document_get_active_element(doc);
+ /* Don't do anything if there is no active element or the active element
+ * is the same as before. */
+ if (!active || active == ext.active) {
+ return;
+ }
+ if (WEBKIT_DOM_IS_HTML_IFRAME_ELEMENT(active)) {
+ WebKitDOMHTMLIFrameElement *iframe;
+ WebKitDOMDocument *subdoc;
+
+ iframe = WEBKIT_DOM_HTML_IFRAME_ELEMENT(active);
+ subdoc = webkit_dom_html_iframe_element_get_content_document(iframe);
+ add_onload_event_observers(subdoc);
+ return;
+ }
+
+ ext.active = active;
+
+ /* Check if the active element is an editable element. */
+ input_focus = ext_dom_is_editable(active);
+ if (input_focus != ext.input_focus) {
+ ext.input_focus = input_focus;
+
+ dbus_emit_signal("EditableChangeFocus", g_variant_new("(b)", input_focus));
+ }
+}
+
+/**
+ * Callback for web extensions page-created signal.
+ */
+static void on_page_created(WebKitWebExtension *extension, WebKitWebPage *page, gpointer data)
+{
+ /* Save the new created page in the extension data for later use. */
+ ext.webpage = page;
+
+ g_object_connect(page,
+ "signal::send-request", G_CALLBACK(on_web_page_send_request), NULL,
+ "signal::document-loaded", G_CALLBACK(on_web_page_document_loaded), NULL,
+ NULL);
+
+ dbus_emit_signal("PageCreated", g_variant_new("(t)", webkit_web_page_get_id(page)));
+}
+
+/**
+ * Callback for web pages document-loaded signal.
+ */
+static void on_web_page_document_loaded(WebKitWebPage *page, gpointer data)
+{
+ /* If there is a hashtable of known document - detroy this and create a
+ * new hashtable. */
+ if (ext.documents) {
+ g_hash_table_unref(ext.documents);
+ }
+ ext.documents = g_hash_table_new(g_direct_hash, g_direct_equal);
+
+ add_onload_event_observers(webkit_web_page_get_dom_document(page));
+}
+
+/**
+ * Callback for web pages send-request signal.
+ */
+static gboolean on_web_page_send_request(WebKitWebPage *page, WebKitURIRequest *request,
+ WebKitURIResponse *response, gpointer data)
+{
+ /* Change request headers according to the users preferences. */
+ if (ext.headers) {
+ char *name, *value;
+ SoupMessageHeaders *headers;
+ GHashTableIter iter;
+
+ headers = webkit_uri_request_get_http_headers(request);
+ g_hash_table_iter_init(&iter, ext.headers);
+ while (g_hash_table_iter_next(&iter, (gpointer*)&name, (gpointer*)&value)) {
+ /* Null value is used to indicate that the header should be
+ * removed completely. */
+ if (value == NULL) {
+ soup_message_headers_remove(headers, name);
+ } else {
+ soup_message_headers_replace(headers, name, value);
+ }
+ }
+ }
+
+ return FALSE;
+}
diff --git a/src/hints.h b/src/webextension/ext-main.h
index 4ced9d8..6178800 100644
--- a/src/hints.h
+++ b/src/webextension/ext-main.h
@@ -17,19 +17,11 @@
* along with this program. If not, see http://www.gnu.org/licenses/.
*/
-#ifndef _HINTS_H
-#define _HINTS_H
+#ifndef _EXT_MAIN_H
+#define _EXT_MAIN_H
-#include "main.h"
+#define VB_WEBEXTENSION_SERVICE_NAME "org.vimb.browser.WebExtension"
+#define VB_WEBEXTENSION_OBJECT_PATH "/org/vimb/browser/WebExtension"
+#define VB_WEBEXTENSION_INTERFACE "org.vimb.browser.WebExtension"
-void hints_init(WebKitWebFrame *frame);
-VbResult hints_keypress(int key);
-void hints_create(const char *input);
-void hints_fire(void);
-void hints_follow_link(const gboolean back, int count);
-void hints_increment_uri(int count);
-gboolean hints_parse_prompt(const char *prompt, char *mode, gboolean *is_gmode);
-void hints_clear(void);
-void hints_focus_next(const gboolean back);
-
-#endif /* end of include guard: _HINTS_H */
+#endif /* end of include guard: _EXT_MAIN_H */
diff --git a/src/webextension/ext-util.c b/src/webextension/ext-util.c
new file mode 100644
index 0000000..0bb40e4
--- /dev/null
+++ b/src/webextension/ext-util.c
@@ -0,0 +1,60 @@
+/**
+ * vimb - a webkit based vim like browser.
+ *
+ * Copyright (C) 2012-2015 Daniel Carl
+ *
+ * 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, see http://www.gnu.org/licenses/.
+ */
+
+#include <glib.h>
+#include <string.h>
+#include <unistd.h>
+#include "../config.h"
+#include "ext-util.h"
+
+/**
+ * Creates a temporary file with given content.
+ *
+ * Upon success, and if file is non-NULL, the actual file path used is
+ * returned in file. This string should be freed with g_free() when not
+ * needed any longer.
+ */
+gboolean ext_util_create_tmp_file(const char *content, char **file)
+{
+ int fp;
+ ssize_t bytes, len;
+
+ fp = g_file_open_tmp(PROJECT "-XXXXXX", file, NULL);
+ if (fp == -1) {
+ g_critical("Could not create temp file %s", *file);
+ g_free(*file);
+ return FALSE;
+ }
+
+ len = strlen(content);
+
+ /* write content into temporary file */
+ bytes = write(fp, content, len);
+ if (bytes < len) {
+ close(fp);
+ unlink(*file);
+ g_critical("Could not write temp file %s", *file);
+ g_free(*file);
+
+ return FALSE;
+ }
+ close(fp);
+
+ return TRUE;
+}
diff --git a/src/io.h b/src/webextension/ext-util.h
index 7fa894b..452c427 100644
--- a/src/io.h
+++ b/src/webextension/ext-util.h
@@ -17,16 +17,11 @@
* along with this program. If not, see http://www.gnu.org/licenses/.
*/
-#include "config.h"
-#ifdef FEATURE_SOCKET
-
-#ifndef _IO_H
-#define _IO_H
+#ifndef _EXT_UTIL_H
+#define _EXT_UTIL_H
#include <glib.h>
-gboolean io_init_socket(const char *name);
-void io_cleanup(void);
+gboolean ext_util_create_tmp_file(const char *content, char **file);
-#endif /* end of include guard: _IO_H */
-#endif
+#endif /* end of include guard: _EXT_UTIL_H */
diff --git a/tests/Makefile b/tests/Makefile
deleted file mode 100644
index 766f66e..0000000
--- a/tests/Makefile
+++ /dev/null
@@ -1,19 +0,0 @@
-BASEDIR=..
-SRCDIR=$(BASEDIR)/src
-include $(BASEDIR)/config.mk
-
-CPPFLAGS += -I $(BASEDIR)/
-CFLAGS += -fPIC -pedantic
-
-TEST_PROGS = test-handlers \
- test-map \
- test-shortcut \
- test-util
-
-all: $(TEST_PROGS)
- LD_LIBRARY_PATH="$(LD_LIBRARY_PATH):." gtester --verbose $(TEST_PROGS)
-
-${TEST_PROGS}: $(SRCDIR)/$(LIBTARGET)
-
-clean:
- $(RM) -f $(TEST_PROGS)
diff --git a/tests/manual/112-editable-focus.html b/tests/manual/112-editable-focus.html
deleted file mode 100644
index 3accc37..0000000
--- a/tests/manual/112-editable-focus.html
+++ /dev/null
@@ -1,39 +0,0 @@
-<html>
-<head>
-<title>Input mode Switching (#112 #237)</title>
-<script type="text/javascript">
-//<![CDATA[
-function setFocus() {
- document.getElementById("text").focus();
-}
-//]]>
-</script>
-</head>
-<body onload="setFocus();">
- <p>
- Run with <code>scripts=on</code> and <code>strict-focus=off</code>
- <ol>
- <li>If page is loade, vimb should be in input mode.</li>
- <li>Set <code>strict-focus=on</code> and reload page. Vimb should keep
- in normal mode</li>
- <li>Independent from the <code>strict-focus</code> should vimb switch
- to input mode if the button is clicked</li>
- </ol>
- </p>
- <form action="#">
- <div>
- <textarea name="text" id="text" rows="11" cols="50"></textarea><br/>
- <input type="button" value="Focus Textarea" onclick="document.getElementById('text').focus();"/>
- </div>
- </form>
- <p>
- Also the following element using <code>contenteditable="true"</code>
- should switch vimb into input mode on click.
- </p>
- <div contenteditable="true" style="width:50%;height:3em;border:1px solid #000">
- Clicking this element using contenteditable="true" should
- switch vimb into input mode too.
- </div>
-</body>
-</html>
-
diff --git a/tests/manual/146-hsts-iframe.html b/tests/manual/146-hsts-iframe.html
deleted file mode 100644
index 7775b75..0000000
--- a/tests/manual/146-hsts-iframe.html
+++ /dev/null
@@ -1,14 +0,0 @@
-<html>
-<head>
-<title>iFrame URI change by HSTS (#146)</title>
-</head>
-<body>
- <p>
- The hsts domain used in iFrame with http must not lead to load the
- iframe content as page.
- </p>
- <iframe src="http://github.com/fanglingsu/vimb" width="600" height="400">
- Github
- </iframe>
-</body>
-</html>
diff --git a/tests/manual/201-editable-focus-in-iframes.html b/tests/manual/201-editable-focus-in-iframes.html
deleted file mode 100644
index d02c0fb..0000000
--- a/tests/manual/201-editable-focus-in-iframes.html
+++ /dev/null
@@ -1,9 +0,0 @@
-<html>
-<head>
-<title>Track Focu/Blur also within iFrames</title>
-</head>
-<body>
-<iframe style="border: 1px solid #000; width: 500px; height: 500px;" src="./112-editable-focus.html"></iframe>
-</body>
-</html>
-
diff --git a/tests/test-handlers.c b/tests/test-handlers.c
deleted file mode 100644
index 8cff0b1..0000000
--- a/tests/test-handlers.c
+++ /dev/null
@@ -1,80 +0,0 @@
-/**
- * vimb - a webkit based vim like browser.
- *
- * Copyright (C) 2012-2015 Daniel Carl
- *
- * 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, see http://www.gnu.org/licenses/.
- */
-
-#include <gtk/gtk.h>
-#include <src/handlers.h>
-
-#define TEST_URI "http://fanglingsu.github.io/vimb/"
-
-static void test_handler_add(void)
-{
- /* check none handled http first */
- g_assert_true(handler_add("http", "echo -n 'handled uri %s'"));
-}
-
-static void test_handler_remove(void)
-{
- handler_add("http", "e");
-
- g_assert_true(handler_remove("http"));
- g_assert_false(handler_remove("http"));
-}
-
-static void test_handler_run_success(void)
-{
- if (g_test_subprocess()) {
- handler_add("http", "echo -n 'handled uri %s'");
- handle_uri(TEST_URI);
- return;
- }
- g_test_trap_subprocess(NULL, 0, 0);
- g_test_trap_assert_passed();
- g_test_trap_assert_stdout("handled uri " TEST_URI);
-}
-
-static void test_handler_run_failed(void)
-{
- if (g_test_subprocess()) {
- handler_add("http", "unknown-program %s");
- handle_uri(TEST_URI);
- return;
- }
- g_test_trap_subprocess(NULL, 0, 0);
- g_test_trap_assert_failed();
- g_test_trap_assert_stderr("*Can't run *unknown-program*");
-}
-
-int main(int argc, char *argv[])
-{
- int result;
- handlers_init();
-
- g_test_init(&argc, &argv, NULL);
-
- g_test_add_func("/test-handlers/add", test_handler_add);
- g_test_add_func("/test-handlers/remove", test_handler_remove);
- g_test_add_func("/test-handlers/handle_uri/success", test_handler_run_success);
- g_test_add_func("/test-handlers/handle_uri/failed", test_handler_run_failed);
-
- result = g_test_run();
-
- handlers_cleanup();
-
- return result;
-}
diff --git a/tests/test-map.c b/tests/test-map.c
deleted file mode 100644
index 8fe5ace..0000000
--- a/tests/test-map.c
+++ /dev/null
@@ -1,176 +0,0 @@
-/**
- * vimb - a webkit based vim like browser.
- *
- * Copyright (C) 2012-2015 Daniel Carl
- *
- * 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, see http://www.gnu.org/licenses/.
- */
-
-#include <gtk/gtk.h>
-#include <gdk/gdkkeysyms.h>
-#include <gdk/gdkkeysyms-compat.h>
-#include <src/map.h>
-#include <src/main.h>
-
-static char queue[20]; /* receives the keypresses */
-static int qpos = 0; /* points to the queue entry for the next keypress */
-
-#define QUEUE_APPEND(c) { \
- queue[qpos++] = (char)c; \
- queue[qpos] = '\0'; \
-}
-#define QUEUE_CLEAR() {queue[(qpos = 0)] = '\0';}
-#define ASSERT_MAPPING(s, e) { \
- QUEUE_CLEAR(); \
- map_handle_string(s, true); \
- g_assert_cmpstr(queue, ==, e); \
-}
-
-typedef struct {
- guint state;
- guint keyval;
-} TestKeypress;
-
-VbResult keypress(int key)
-{
- /* put the key into the queue */
- QUEUE_APPEND(key);
-
- return RESULT_COMPLETE;
-}
-
-static void test_handle_string_simple(void)
-{
- /* test simple mappings */
- ASSERT_MAPPING("a", "[a]");
- ASSERT_MAPPING("b", "[b]");
- ASSERT_MAPPING("[c]", "c");
- ASSERT_MAPPING("d", " [d]");
- ASSERT_MAPPING("<Tab>", "[tab]");
- ASSERT_MAPPING("<S-Tab>", "[shift-tab]");
- ASSERT_MAPPING("<C-F>", "[ctrl-f]");
- ASSERT_MAPPING("<C-f>", "[ctrl-f]");
- ASSERT_MAPPING("<CR>", "[cr]");
- ASSERT_MAPPING("foobar", "[baz]");
-
- /* key sequences that are not changed by mappings */
- ASSERT_MAPPING("fghi", "fghi");
-}
-
-static void test_handle_string_alias(void)
-{
- /* CTRL-I is the same like <Tab> and CTRL-M like <CR> */
- ASSERT_MAPPING("<C-I>", "[tab]");
- ASSERT_MAPPING("<C-M>", "[cr]");
-}
-
-static void test_handle_string_remapped(void)
-{
- /* test multiple mappings together */
- ASSERT_MAPPING("ba", "[b][a]");
- ASSERT_MAPPING("ab12345[c]", "[a][b]12345c");
-
- /* incomplete ambiguous sequences are not matched jet */
- ASSERT_MAPPING("foob", "");
- ASSERT_MAPPING("ar", "[baz]");
-
- /* test remapping */
- map_insert("c", "baza", 't', true);
- ASSERT_MAPPING("c", "[b][a]z[a]");
- map_insert("d", "cki", 't', true);
- ASSERT_MAPPING("d", "[b][a]z[a]ki");
-
- /* remove the no more needed mappings */
- map_delete("c", 't');
- map_delete("d", 't');
-}
-
-static void test_handle_string_overrule(void)
-{
- /* add another map for 'a' and check if this overrules the previous set */
- map_insert("a", "overruled", 't', false);
- ASSERT_MAPPING("a", "overruled");
-}
-
-static void test_remove(void)
-{
- map_insert("x", "[x]", 't', false);
- /* make sure that the mapping works */
- ASSERT_MAPPING("x", "[x]");
-
- map_delete("x", 't');
-
- /* make sure the mapping removed */
- ASSERT_MAPPING("x", "x");
-}
-
-static void test_keypress_single(void)
-{
- QUEUE_CLEAR();
-
- map_keypress(NULL, &((GdkEventKey){.keyval = GDK_Tab, .state = GDK_SHIFT_MASK}), NULL);
- g_assert_cmpstr(queue, ==, "[shift-tab]");
-}
-
-static void test_keypress_sequence(void)
-{
- QUEUE_CLEAR();
-
- map_keypress(NULL, &((GdkEventKey){.keyval = GDK_f}), NULL);
- g_assert_cmpstr(queue, ==, "");
- map_keypress(NULL, &((GdkEventKey){.keyval = GDK_o}), NULL);
- g_assert_cmpstr(queue, ==, "");
- map_keypress(NULL, &((GdkEventKey){.keyval = GDK_o}), NULL);
- g_assert_cmpstr(queue, ==, "");
- map_keypress(NULL, &((GdkEventKey){.keyval = GDK_b}), NULL);
- g_assert_cmpstr(queue, ==, "");
- map_keypress(NULL, &((GdkEventKey){.keyval = GDK_a}), NULL);
- g_assert_cmpstr(queue, ==, "");
- map_keypress(NULL, &((GdkEventKey){.keyval = GDK_r}), NULL);
- g_assert_cmpstr(queue, ==, "[baz]");
-}
-
-int main(int argc, char *argv[])
-{
- int result;
- g_test_init(&argc, &argv, NULL);
-
- /* add a test mode to handle the maped sequences */
- vb_add_mode('t', NULL, NULL, keypress, NULL);
- vb_enter('t');
- map_init();
-
- g_test_add_func("/test-map/handle_string/simple", test_handle_string_simple);
- g_test_add_func("/test-map/handle_string/alias", test_handle_string_alias);
- g_test_add_func("/test-map/handle_string/remapped", test_handle_string_remapped);
- g_test_add_func("/test-map/handle_string/overrule", test_handle_string_overrule);
- g_test_add_func("/test-map/remove", test_remove);
- g_test_add_func("/test-map/keypress/single-char", test_keypress_single);
- g_test_add_func("/test-map/keypress/sequence", test_keypress_sequence);
-
- /* add some mappings to test */
- map_insert("a", "[a]", 't', false); /* inlen < mappedlen */
- map_insert("b", "[b]", 't', false);
- map_insert("d", "<Space>[d]", 't', false);
- map_insert("[c]", "c", 't', false); /* inlen > mappedlen */
- map_insert("foobar", "[baz]", 't', false);
- map_insert("<Tab>", "[tab]", 't', false);
- map_insert("<S-Tab>", "[shift-tab]", 't', false);
- map_insert("<C-F>", "[ctrl-f]", 't', false);
- map_insert("<CR>", "[cr]", 't', false);
-
- result = g_test_run();
- map_cleanup();
- return result;
-}
diff --git a/tests/test-shortcut.c b/tests/test-shortcut.c
deleted file mode 100644
index 697a04d..0000000
--- a/tests/test-shortcut.c
+++ /dev/null
@@ -1,142 +0,0 @@
-/**
- * vimb - a webkit based vim like browser.
- *
- * Copyright (C) 2012-2015 Daniel Carl
- *
- * 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, see http://www.gnu.org/licenses/.
- */
-
-#include <gtk/gtk.h>
-#include <src/shortcut.h>
-
-static void test_shortcut_single(void)
-{
- char *uri;
-
- /* call with shortcut identifier */
- uri = shortcut_get_uri("_vimb1_ zero one");
- g_assert_cmpstr(uri, ==, "only-zero:zero%20one");
- g_free(uri);
-
- /* don't fail on unmatches quotes if there are only $0 placeholders */
- uri = shortcut_get_uri("_vimb1_ 'unmatched quote");
- g_assert_cmpstr(uri, ==, "only-zero:'unmatched%20quote");
- g_free(uri);
-
- /* check if all placeholders $0 are replaces */
- uri = shortcut_get_uri("_vimb5_ one two");
- g_assert_cmpstr(uri, ==, "double-zero:one%20two-one%20two");
- g_free(uri);
-}
-
-static void test_shortcut_default(void)
-{
- char *uri;
-
- /* call without shortcut identifier and if the last placeholder become the
- * none matched query words */
- uri = shortcut_get_uri("zero one two three");
- g_assert_cmpstr(uri, ==, "default:zero-two%20three");
- g_free(uri);
-}
-
-static void test_shortcut_keep_unmatched(void)
-{
- char *uri;
-
- /* don't remove non matched placeholders */
- uri = shortcut_get_uri("zero");
- g_assert_cmpstr(uri, ==, "default:zero-$2");
- g_free(uri);
-}
-
-static void test_shortcut_fullrange(void)
-{
- char *uri;
-
- /* check if all placeholders $0-$9 are replaced */
- uri = shortcut_get_uri("_vimb3_ zero one two three four five six seven eight nine");
- g_assert_cmpstr(uri, ==, "fullrange:zero-one-nine");
- g_free(uri);
-}
-
-static void test_shortcut_shell_param(void)
-{
- char *uri;
-
- /* double quotes */
- uri = shortcut_get_uri("_vimb6_ \"rail station\" city hall");
- g_assert_cmpstr(uri, ==, "shell:rail%20station-city%20hall");
- g_free(uri);
-
- /* single quotes */
- uri = shortcut_get_uri("_vimb6_ 'rail station' 'city hall'");
- g_assert_cmpstr(uri, ==, "shell:rail%20station-city%20hall");
- g_free(uri);
-
- /* ignore none matching quote errors */
- uri = shortcut_get_uri("_vimb6_ \"rail station\" \"city hall");
- g_assert_cmpstr(uri, ==, "shell:rail%20station-city%20hall");
- g_free(uri);
-
- /* don't fill up quoted param with unquoted stuff */
- uri = shortcut_get_uri("_vimb6_ \"param 1\" \"param 2\" ignored params");
- g_assert_cmpstr(uri, ==, "shell:param%201-param%202");
- g_free(uri);
-
- /* allo quotes within tha last parameter */
- uri = shortcut_get_uri("_vimb6_ param1 param2 \"containing quotes\"");
- g_assert_cmpstr(uri, ==, "shell:param1-param2%20%22containing%20quotes%22");
- g_free(uri);
-}
-
-static void test_shortcut_remove(void)
-{
- char *uri;
-
- g_assert_true(shortcut_remove("_vimb4_"));
-
- /* check if the shortcut is really no used */
- uri = shortcut_get_uri("_vimb4_ test");
- g_assert_cmpstr(uri, ==, "default:_vimb4_-$2");
-}
-
-int main(int argc, char *argv[])
-{
- int result;
- shortcut_init();
-
- g_assert_true(shortcut_add("_vimb1_", "only-zero:$0"));
- g_assert_true(shortcut_add("_vimb2_", "default:$0-$2"));
- g_assert_true(shortcut_add("_vimb3_", "fullrange:$0-$1-$9"));
- g_assert_true(shortcut_add("_vimb4_", "for-remove:$0"));
- g_assert_true(shortcut_add("_vimb5_", "double-zero:$0-$0"));
- g_assert_true(shortcut_add("_vimb6_", "shell:$0-$1"));
- g_assert_true(shortcut_set_default("_vimb2_"));
-
- g_test_init(&argc, &argv, NULL);
-
- g_test_add_func("/test-shortcut/get_uri/single", test_shortcut_single);
- g_test_add_func("/test-shortcut/get_uri/default", test_shortcut_default);
- g_test_add_func("/test-shortcut/get_uri/keep-unmatched", test_shortcut_keep_unmatched);
- g_test_add_func("/test-shortcut/get_uri/fullrange", test_shortcut_fullrange);
- g_test_add_func("/test-shortcut/get_uri/shell-param", test_shortcut_shell_param);
- g_test_add_func("/test-shortcut/remove", test_shortcut_remove);
-
- result = g_test_run();
-
- shortcut_cleanup();
-
- return result;
-}
diff --git a/tests/test-util.c b/tests/test-util.c
deleted file mode 100644
index 67b1954..0000000
--- a/tests/test-util.c
+++ /dev/null
@@ -1,285 +0,0 @@
-/**
- * vimb - a webkit based vim like browser.
- *
- * Copyright (C) 2012-2015 Daniel Carl
- *
- * 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, see http://www.gnu.org/licenses/.
- */
-
-#include <gtk/gtk.h>
-#include <src/util.h>
-
-extern VbCore vb;
-
-static void check_expand(const char *str, const char *expected)
-{
- char *result = util_expand(str, UTIL_EXP_DOLLAR|UTIL_EXP_TILDE|UTIL_EXP_SPECIAL);
- g_assert_cmpstr(result, ==, expected);
- g_free(result);
-}
-
-static void test_expand_evn(void)
-{
- /* set environment var for testing expansion */
- g_setenv("VIMB_VAR", "value", true);
-
- check_expand("$VIMB_VAR", "value");
- check_expand("$VIMB_VAR", "value");
- check_expand("$VIMB_VAR$VIMB_VAR", "valuevalue");
- check_expand("${VIMB_VAR}", "value");
- check_expand("my$VIMB_VAR", "myvalue");
- check_expand("'$VIMB_VAR'", "'value'");
- check_expand("${VIMB_VAR}s ", "values ");
-
- g_unsetenv("UNKNOWN");
-
- check_expand("$UNKNOWN", "");
- check_expand("${UNKNOWN}", "");
- check_expand("'$UNKNOWN'", "''");
-}
-
-static void test_expand_escaped(void)
-{
- g_setenv("VIMB_VAR", "value", true);
-
- check_expand("\\$VIMB_VAR", "$VIMB_VAR");
- check_expand("\\${VIMB_VAR}", "${VIMB_VAR}");
-
- check_expand("\\~/", "~/");
- check_expand("\\~/vimb", "~/vimb");
- check_expand("\\~root", "~root");
-
- check_expand("\\%", "%");
-
- check_expand("\\\\$VIMB_VAR", "\\value"); /* \\$VAR becomes \ExpandedVar */
- check_expand("\\\\\\$VIMB_VAR", "\\$VIMB_VAR"); /* \\\$VAR becomes \$VAR */
-}
-
-static void test_expand_tilde_home(void)
-{
- char *dir;
- const char *home = util_get_home_dir();
-
- check_expand("~", "~");
- check_expand("~/", home);
- check_expand("foo~/bar", "foo~/bar");
- check_expand("~/foo", (dir = g_strdup_printf("%s/foo", home)));
- g_free(dir);
-
- check_expand("foo ~/bar", (dir = g_strdup_printf("foo %s/bar", home)));
- g_free(dir);
-
- check_expand("~/~", (dir = g_strdup_printf("%s/~", home)));
- g_free(dir);
-
- check_expand("~/~/", (dir = g_strdup_printf("%s/~/", home)));
- g_free(dir);
-}
-
-static void test_expand_tilde_user(void)
-{
- const char *home = util_get_home_dir();
- const char *user = g_get_user_name();
- char *in, *out;
-
- /* don't expand within words */
- in = g_strdup_printf("foo~%s/bar", user);
- check_expand(in, in);
- g_free(in);
-
- check_expand((in = g_strdup_printf("foo ~%s", user)), (out = g_strdup_printf("foo %s", home)));
- g_free(in);
- g_free(out);
-
- check_expand((in = g_strdup_printf("~%s", user)), home);
- g_free(in);
-
- check_expand((in = g_strdup_printf("~%s/bar", user)), (out = g_strdup_printf("%s/bar", home)));
- g_free(in);
- g_free(out);
-}
-
-static void test_expand_speacial(void)
-{
- vb.state.uri = "http://fanglingsu.github.io/vimb/";
-
- check_expand("%", "http://fanglingsu.github.io/vimb/");
- check_expand("'%'", "'http://fanglingsu.github.io/vimb/'");
-}
-
-static void test_strcasestr(void)
-{
- g_assert_nonnull(util_strcasestr("Vim like Browser", "browser"));
- g_assert_nonnull(util_strcasestr("Vim like Browser", "vim LIKE"));
-}
-
-static void test_str_replace(void)
-{
- char *value;
-
- value = util_str_replace("a", "uu", "foo bar baz");
- g_assert_cmpstr(value, ==, "foo buur buuz");
- g_free(value);
-
- value = util_str_replace("$1", "placeholder", "string with $1");
- g_assert_cmpstr(value, ==, "string with placeholder");
- g_free(value);
-}
-
-static void test_wildmatch_simple(void)
-{
- g_assert_true(util_wildmatch("", ""));
- g_assert_true(util_wildmatch("w", "w"));
- g_assert_true(util_wildmatch(".", "."));
- g_assert_true(util_wildmatch("~", "~"));
- g_assert_true(util_wildmatch("wildmatch", "WildMatch"));
- g_assert_true(util_wildmatch("wild\\match", "wild\\match"));
-
- /* no special meaning of . and ~ in pattern */
- g_assert_false(util_wildmatch(".", "w"));
- g_assert_false(util_wildmatch("~", "w"));
- g_assert_false(util_wildmatch("wild", "wild "));
- g_assert_false(util_wildmatch("wild", " wild"));
- g_assert_false(util_wildmatch("wild", "\\ wild"));
- g_assert_false(util_wildmatch("wild", "\\wild"));
- g_assert_false(util_wildmatch("wild", "wild\\"));
- g_assert_false(util_wildmatch("wild\\1", "wild\\2"));
-}
-
-static void test_wildmatch_questionmark(void)
-{
- g_assert_true(util_wildmatch("wild?atch", "wildmatch"));
- g_assert_true(util_wildmatch("wild?atch", "wildBatch"));
- g_assert_true(util_wildmatch("wild?atch", "wild?atch"));
- g_assert_true(util_wildmatch("?ild?atch", "MildBatch"));
- g_assert_true(util_wildmatch("foo\\?bar", "foo?bar"));
- g_assert_true(util_wildmatch("???", "foo"));
- g_assert_true(util_wildmatch("???", "bar"));
-
- g_assert_false(util_wildmatch("foo\\?bar", "foorbar"));
- g_assert_false(util_wildmatch("?", ""));
- g_assert_false(util_wildmatch("b??r", "bar"));
- /* ? does not match / in contrast to * which does */
- g_assert_false(util_wildmatch("user?share", "user/share"));
-}
-
-static void test_wildmatch_wildcard(void)
-{
- g_assert_true(util_wildmatch("*", ""));
- g_assert_true(util_wildmatch("*", "Match as much as possible"));
- g_assert_true(util_wildmatch("*match", "prefix match"));
- g_assert_true(util_wildmatch("match*", "match suffix"));
- g_assert_true(util_wildmatch("match*", "match*"));
- g_assert_true(util_wildmatch("match\\*", "match*"));
- g_assert_true(util_wildmatch("match\\\\*", "match\\*"));
- g_assert_true(util_wildmatch("do * match", "do a infix match"));
- /* '*' matches also / in contrast to other implementations */
- g_assert_true(util_wildmatch("start*end", "start/something/end"));
- g_assert_true(util_wildmatch("*://*.io/*", "http://fanglingsu.github.io/vimb/"));
- /* multiple * should act like a single one */
- g_assert_true(util_wildmatch("**", ""));
- g_assert_true(util_wildmatch("match **", "Match as much as possible"));
- g_assert_true(util_wildmatch("f***u", "fu"));
-
- g_assert_false(util_wildmatch("match\\*", "match fail"));
- g_assert_false(util_wildmatch("f***u", "full"));
-}
-
-static void test_wildmatch_curlybraces(void)
-{
- g_assert_true(util_wildmatch("{foo}", "foo"));
- g_assert_true(util_wildmatch("{foo,bar}", "foo"));
- g_assert_true(util_wildmatch("{foo,bar}", "bar"));
- g_assert_true(util_wildmatch("foo{lish,t}bar", "foolishbar"));
- g_assert_true(util_wildmatch("foo{lish,t}bar", "footbar"));
- /* esacped special chars */
- g_assert_true(util_wildmatch("foo\\{l\\}bar", "foo{l}bar"));
- g_assert_true(util_wildmatch("ba{r,z\\{\\}}", "bar"));
- g_assert_true(util_wildmatch("ba{r,z\\{\\}}", "baz{}"));
- g_assert_true(util_wildmatch("test{one\\,two,three}", "testone,two"));
- g_assert_true(util_wildmatch("test{one\\,two,three}", "testthree"));
- /* backslash before none special char is a normal char */
- g_assert_true(util_wildmatch("back{\\slash,}", "back\\slash"));
- g_assert_true(util_wildmatch("one\\two", "one\\two"));
- g_assert_true(util_wildmatch("\\}match", "}match"));
- g_assert_true(util_wildmatch("\\{", "{"));
- /* empty list parts */
- g_assert_true(util_wildmatch("{}", ""));
- g_assert_true(util_wildmatch("{,}", ""));
- g_assert_true(util_wildmatch("{,foo}", ""));
- g_assert_true(util_wildmatch("{,foo}", "foo"));
- g_assert_true(util_wildmatch("{bar,}", ""));
- g_assert_true(util_wildmatch("{bar,}", "bar"));
- /* no special meaning of ? and * in curly braces */
- g_assert_true(util_wildmatch("ab{*,cd}ef", "ab*ef"));
- g_assert_true(util_wildmatch("ab{d,?}ef", "ab?ef"));
-
- g_assert_false(util_wildmatch("{foo,bar}", "foo,bar"));
- g_assert_false(util_wildmatch("}match{ it", "}match{ anything"));
- /* don't match single parts that are seperated by escaped ',' */
- g_assert_false(util_wildmatch("{a,b\\,c,d}", "b"));
- g_assert_false(util_wildmatch("{a,b\\,c,d}", "c"));
- /* lonesome braces - this is a syntax error and will always be false */
- g_assert_false(util_wildmatch("}", "}"));
- g_assert_false(util_wildmatch("}", ""));
- g_assert_false(util_wildmatch("}suffix", "}suffux"));
- g_assert_false(util_wildmatch("}suffix", "suffux"));
- g_assert_false(util_wildmatch("{", "{"));
- g_assert_false(util_wildmatch("{", ""));
- g_assert_false(util_wildmatch("{foo", "{foo"));
- g_assert_false(util_wildmatch("{foo", "foo"));
- g_assert_false(util_wildmatch("foo{bar", "foo{bar"));
-}
-
-static void test_wildmatch_complete(void)
-{
- g_assert_true(util_wildmatch("http{s,}://{fanglingsu.,}github.{io,com}/*vimb/", "http://fanglingsu.github.io/vimb/"));
- g_assert_true(util_wildmatch("http{s,}://{fanglingsu.,}github.{io,com}/*vimb/", "https://github.com/fanglingsu/vimb/"));
-}
-
-static void test_wildmatch_multi(void)
-{
- g_assert_true(util_wildmatch("foo,?", "foo"));
- g_assert_true(util_wildmatch("foo,?", "f"));
- g_assert_true(util_wildmatch("foo,b{a,o,}r,ba?", "foo"));
- g_assert_true(util_wildmatch("foo,b{a,o,}r,ba?", "bar"));
- g_assert_true(util_wildmatch("foo,b{a,o,}r,ba?", "bor"));
- g_assert_true(util_wildmatch("foo,b{a,o,}r,ba?", "br"));
- g_assert_true(util_wildmatch("foo,b{a,o,}r,ba?", "baz"));
- g_assert_true(util_wildmatch("foo,b{a,o,}r,ba?", "bat"));
-
- g_assert_false(util_wildmatch("foo,b{a,o,}r,ba?", "foo,"));
- g_assert_false(util_wildmatch("foo,?", "fo"));
-}
-
-int main(int argc, char *argv[])
-{
- g_test_init(&argc, &argv, NULL);
-
- g_test_add_func("/test-util/expand-env", test_expand_evn);
- g_test_add_func("/test-util/expand-escaped", test_expand_escaped);
- g_test_add_func("/test-util/expand-tilde-home", test_expand_tilde_home);
- g_test_add_func("/test-util/expand-tilde-user", test_expand_tilde_user);
- g_test_add_func("/test-util/expand-spacial", test_expand_speacial);
- g_test_add_func("/test-util/strcasestr", test_strcasestr);
- g_test_add_func("/test-util/str_replace", test_str_replace);
- g_test_add_func("/test-util/wildmatch-simple", test_wildmatch_simple);
- g_test_add_func("/test-util/wildmatch-questionmark", test_wildmatch_questionmark);
- g_test_add_func("/test-util/wildmatch-wildcard", test_wildmatch_wildcard);
- g_test_add_func("/test-util/wildmatch-curlybraces", test_wildmatch_curlybraces);
- g_test_add_func("/test-util/wildmatch-complete", test_wildmatch_complete);
- g_test_add_func("/test-util/wildmatch-multi", test_wildmatch_multi);
-
- return g_test_run();
-}