aboutsummaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
authorGravatar keis <keijser@gmail.com>2011-07-28 22:31:30 +0200
committerGravatar keis <keijser@gmail.com>2011-07-28 22:31:30 +0200
commitdb61f092140205e71f40fb14dc98a1e650c7e527 (patch)
tree6a2459ae08c6baa4875b1db226dc7eb615a3cd3c
parent1e20430333aee952f55f6caec4d55238a0160bf9 (diff)
parente035f6f991fdbe9862a72fba6e8d348dcc25532f (diff)
Merge branch 'experimental' of git://github.com/Dieterbe/uzbl into mouse-events
-rw-r--r--Makefile46
-rw-r--r--README20
-rwxr-xr-xbin/uzbl-event-manager300
-rwxr-xr-xbin/uzbl-tabbed564
-rw-r--r--docs/FAQ201
-rw-r--r--examples/config/config20
-rw-r--r--examples/data/scripts/follow.js40
-rwxr-xr-xexamples/data/scripts/follow.sh22
-rw-r--r--examples/data/scripts/formfiller.js35
-rwxr-xr-xexamples/data/scripts/formfiller.sh16
-rw-r--r--examples/data/scripts/util/uzbl-dir.sh14
-rwxr-xr-xmisc/hash.sh18
-rw-r--r--src/callbacks.c520
-rw-r--r--src/callbacks.h159
-rw-r--r--src/commands.c452
-rw-r--r--src/commands.h68
-rw-r--r--src/cookie-jar.c3
-rw-r--r--src/events.c9
-rw-r--r--src/events.h1
-rw-r--r--src/inspector.c4
-rw-r--r--src/io.c1
-rw-r--r--src/menu.h8
-rw-r--r--src/status-bar.c117
-rw-r--r--src/status-bar.h36
-rw-r--r--src/type.h24
-rw-r--r--src/util.c2
-rw-r--r--src/uzbl-core.c961
-rw-r--r--src/uzbl-core.h115
-rw-r--r--src/variables.c618
-rw-r--r--src/variables.h21
-rw-r--r--tests/Makefile15
-rw-r--r--tests/test-command.c9
-rw-r--r--tests/test-expand.c1
33 files changed, 2182 insertions, 2258 deletions
diff --git a/Makefile b/Makefile
index dad7e61..fa765a5 100644
--- a/Makefile
+++ b/Makefile
@@ -1,5 +1,3 @@
-# first entries are for gnu make, 2nd for BSD make. see http://lists.uzbl.org/pipermail/uzbl-dev-uzbl.org/2009-July/000177.html
-
# packagers, set DESTDIR to your "package directory" and PREFIX to the prefix you want to have on the end-user system
# end-users who build from source: don't care about DESTDIR, update PREFIX if you want to
# RUN_PREFIX : what the prefix is when the software is run. usually the same as PREFIX
@@ -8,31 +6,30 @@ INSTALLDIR?=$(DESTDIR)$(PREFIX)
DOCDIR?=$(INSTALLDIR)/share/uzbl/docs
RUN_PREFIX?=$(PREFIX)
-# gtk2
-REQ_PKGS += gtk+-2.0 webkit-1.0
-CPPFLAGS =
+# use GTK3-based webkit when it is available
+USE_GTK3 = $(shell pkg-config --exists gtk+-3.0 webkitgtk-3.0 && echo 1)
-# gtk3
-#REQ_PKGS += gtk+-3.0 webkitgtk-3.0
-#CPPFLAGS = -DG_DISABLE_DEPRECATED -DGTK_DISABLE_DEPRECATED
+ifeq ($(USE_GTK3),1)
+ REQ_PKGS += gtk+-3.0 webkitgtk-3.0
+ CPPFLAGS = -DG_DISABLE_DEPRECATED -DGTK_DISABLE_DEPRECATED
+else
+ REQ_PKGS += gtk+-2.0 webkit-1.0
+ CPPFLAGS =
+endif
# --- configuration ends here ---
REQ_PKGS += libsoup-2.4 gthread-2.0 glib-2.0
ARCH:=$(shell uname -m)
-ARCH!=echo `uname -m`
COMMIT_HASH:=$(shell ./misc/hash.sh)
-COMMIT_HASH!=echo `./misc/hash.sh`
CPPFLAGS += -DARCH=\"$(ARCH)\" -DCOMMIT=\"$(COMMIT_HASH)\"
PKG_CFLAGS:=$(shell pkg-config --cflags $(REQ_PKGS))
-PKG_CFLAGS!=echo pkg-config --cflags $(REQ_PKGS)
LDLIBS:=$(shell pkg-config --libs $(REQ_PKGS) x11)
-LDLIBS!=echo pkg-config --libs $(REQ_PKGS) x11
CFLAGS += -std=c99 $(PKG_CFLAGS) -ggdb -W -Wall -Wextra -pedantic -pthread
@@ -79,7 +76,6 @@ test-uzbl-core-sandbox: uzbl-core
rm -rf ./sandbox/usr
test-uzbl-browser-sandbox: uzbl-browser
- make DESTDIR=./sandbox RUN_PREFIX=`pwd`/sandbox/usr/local install-uzbl-core
make DESTDIR=./sandbox RUN_PREFIX=`pwd`/sandbox/usr/local install-uzbl-browser
make DESTDIR=./sandbox RUN_PREFIX=`pwd`/sandbox/usr/local install-example-data
cp -np ./misc/env.sh ./sandbox/env.sh
@@ -90,7 +86,6 @@ test-uzbl-browser-sandbox: uzbl-browser
rm -rf ./sandbox/usr
test-uzbl-tabbed-sandbox: uzbl-browser
- make DESTDIR=./sandbox RUN_PREFIX=`pwd`/sandbox/usr/local install-uzbl-core
make DESTDIR=./sandbox RUN_PREFIX=`pwd`/sandbox/usr/local install-uzbl-browser
make DESTDIR=./sandbox RUN_PREFIX=`pwd`/sandbox/usr/local install-uzbl-tabbed
make DESTDIR=./sandbox RUN_PREFIX=`pwd`/sandbox/usr/local install-example-data
@@ -109,6 +104,11 @@ clean:
rm -f inspector.o
rm -f cookie-jar.o
rm -f util.o
+ rm -f commands.o
+ rm -f io.o
+ rm -f menu.o
+ rm -f status-bar.o
+ rm -f variables.o
find ./examples/ -name "*.pyc" -delete
cd ./tests/; $(MAKE) clean
rm -rf ./sandbox/
@@ -130,22 +130,24 @@ install-uzbl-core: all install-dirs
install -m644 src/config.h $(DOCDIR)/
install -m644 README $(DOCDIR)/
install -m644 AUTHORS $(DOCDIR)/
- cp -r examples $(INSTALLDIR)/share/uzbl/
- chmod 755 $(INSTALLDIR)/share/uzbl/examples/data/scripts/*
install -m755 uzbl-core $(INSTALLDIR)/bin/uzbl-core
-install-uzbl-browser: install-dirs
- install -m755 bin/uzbl-browser $(INSTALLDIR)/bin/uzbl-browser
+install-event-manager: install-dirs
install -m755 bin/uzbl-event-manager $(INSTALLDIR)/bin/uzbl-event-manager
- mv $(INSTALLDIR)/bin/uzbl-browser $(INSTALLDIR)/bin/uzbl-browser.bak
- sed 's#^PREFIX=.*#PREFIX=$(RUN_PREFIX)#' < $(INSTALLDIR)/bin/uzbl-browser.bak > $(INSTALLDIR)/bin/uzbl-browser
- chmod 755 $(INSTALLDIR)/bin/uzbl-browser
- rm $(INSTALLDIR)/bin/uzbl-browser.bak
mv $(INSTALLDIR)/bin/uzbl-event-manager $(INSTALLDIR)/bin/uzbl-event-manager.bak
sed "s#^PREFIX = .*#PREFIX = '$(RUN_PREFIX)'#" < $(INSTALLDIR)/bin/uzbl-event-manager.bak > $(INSTALLDIR)/bin/uzbl-event-manager
chmod 755 $(INSTALLDIR)/bin/uzbl-event-manager
rm $(INSTALLDIR)/bin/uzbl-event-manager.bak
+install-uzbl-browser: install-dirs install-uzbl-core install-event-manager
+ install -m755 bin/uzbl-browser $(INSTALLDIR)/bin/uzbl-browser
+ mv $(INSTALLDIR)/bin/uzbl-browser $(INSTALLDIR)/bin/uzbl-browser.bak
+ sed 's#^PREFIX=.*#PREFIX=$(RUN_PREFIX)#' < $(INSTALLDIR)/bin/uzbl-browser.bak > $(INSTALLDIR)/bin/uzbl-browser
+ chmod 755 $(INSTALLDIR)/bin/uzbl-browser
+ rm $(INSTALLDIR)/bin/uzbl-browser.bak
+ cp -r examples $(INSTALLDIR)/share/uzbl/
+ chmod 755 $(INSTALLDIR)/share/uzbl/examples/data/scripts/*
+
install-uzbl-tabbed: install-dirs
install -m755 bin/uzbl-tabbed $(INSTALLDIR)/bin/uzbl-tabbed
diff --git a/README b/README
index 08c6356..0d65084 100644
--- a/README
+++ b/README
@@ -300,6 +300,7 @@ file).
expanded).
* `title_format_short`: titlebar string when statusbar shown (will be expanded).
* `icon`: path to icon for Gtk.
+* `window_role`: Window role string. By default there is no role.
* `forward_keys`: Whether `uzbl-core` should send key events to the webkit view.
* `cookie_handler`: Handler called when the page requests a cookie to be
retrieved or set. Appends the following arguments to the standard handler
@@ -318,8 +319,6 @@ file).
* `fifo_dir`: location to store FIFOs.
* `socket_dir`: location to store sockets.
* `http_debug`: HTTP debug mode (value 0-3).
-* `scrollbars_visible`: set to 1 to have GTK scrollbars if the document
- doesn't fit into the window (defaults to 0)
* `javascript_windows`: Whether javascript can open windows automatically
* `shell_cmd`: Alias which will be expanded to use shell commands (eg `sh -c`).
* `print_events`: show events on stdout
@@ -609,6 +608,21 @@ This script tries to authenticate as user alice with password wonderland once
and never retries authentication.
See examples for more sofisticated, interactive authentication handler.
+### WINDOW MANAGER INTEGRATION
+
+As mentined before, the contents of the window title can be customized by
+setting the `title_format_short` variable and the `title_format_long` variable
+(see above to figure out when each of them is used). You can also set `icon`
+variable to path of the icon file. Some advanced window managers can also take
+`WM_WINDOW_ROLE` in account, which can be set by modifying `window_role`
+variable.
+
+There is currently no support of updating window icon automatically to site's
+favicon, but there are some scripts for that at wiki pages.
+
+Uzbl sets special X window property UZBL_URI which is always the uri of the
+page loaded into uzbl, except for web inspector windows which has no UZBL_URI.
+
### EVENTS
Unlike commands, events are not handled in `uzbl` itself, but are propagated
@@ -625,7 +639,7 @@ The EM allows:
* Many fine-grained events (`hover_over_link`, `key_press`, `key_release`,..)
* See example `uzbl-event-manager`.
-**Note**: Cookie events are sent in addition to (optionally) being handled by
+**Note**: Cookie events are sent in addition to (optionally) being handled by
the cookie handler (set by the cookie_handler var). If using a handler it will
take precedence before the internal state configured by (add|delete)_cookie
commands.
diff --git a/bin/uzbl-event-manager b/bin/uzbl-event-manager
index cb462c7..64a1354 100755
--- a/bin/uzbl-event-manager
+++ b/bin/uzbl-event-manager
@@ -30,21 +30,22 @@ import atexit
import imp
import logging
import os
-import socket
import sys
import time
import weakref
import re
+import errno
from collections import defaultdict
from functools import partial
from glob import glob
from itertools import count
from optparse import OptionParser
from select import select
-from signal import signal, SIGTERM, SIGINT
+from signal import signal, SIGTERM, SIGINT, SIGKILL
from socket import socket, AF_UNIX, SOCK_STREAM
from traceback import format_exc
+
def xdghome(key, default):
'''Attempts to use the environ XDG_*_HOME paths if they exist otherwise
use $HOME and the default path.'''
@@ -65,14 +66,19 @@ CACHE_DIR = os.path.join(xdghome('CACHE', '.cache/'), 'uzbl/')
# Define some globals.
SCRIPTNAME = os.path.basename(sys.argv[0])
+logger = logging.getLogger(SCRIPTNAME)
+
+
def get_exc():
'''Format `format_exc` for logging.'''
return "\n%s" % format_exc().rstrip()
+
def expandpath(path):
'''Expand and realpath paths.'''
return os.path.realpath(os.path.expandvars(path))
+
def ascii(u):
'''Convert unicode strings into ascii for transmission over
ascii-only streams/sockets/devices.'''
@@ -89,7 +95,7 @@ def daemonize():
os._exit(0)
except OSError:
- logger.critical(get_exc())
+ logger.critical('failed to daemonize', exc_info=True)
sys.exit(1)
os.chdir('/')
@@ -101,7 +107,7 @@ def daemonize():
os._exit(0)
except OSError:
- logger.critical(get_exc())
+ logger.critical('failed to daemonize', exc_info=True)
sys.exit(1)
if sys.stdout.isatty():
@@ -126,11 +132,11 @@ def make_dirs(path):
try:
dirname = os.path.dirname(path)
if not os.path.isdir(dirname):
- logger.debug('creating directories %r' % dirname)
+ logger.debug('creating directories %r', dirname)
os.makedirs(dirname)
except OSError:
- logger.error(get_exc())
+ logger.error('failed to create directories', exc_info=True)
class EventHandler(object):
@@ -147,7 +153,6 @@ class EventHandler(object):
self.args = args
self.kwargs = kwargs
-
def __repr__(self):
elems = ['id=%d' % self.id, 'event=%s' % self.event,
'callback=%r' % self.callback]
@@ -161,7 +166,6 @@ class EventHandler(object):
elems.append('plugin=%s' % self.plugin.name)
return u'<handler(%s)>' % ', '.join(elems)
-
def call(self, uzbl, *args, **kwargs):
'''Execute the handler function and merge argument lists.'''
@@ -170,9 +174,6 @@ class EventHandler(object):
self.callback(uzbl, *args, **kwargs)
-
-
-
class Plugin(object):
'''Plugin module wrapper object.'''
@@ -181,13 +182,12 @@ class Plugin(object):
special_functions = ['require', 'export', 'export_dict', 'connect',
'connect_dict', 'logger', 'unquote', 'splitquoted']
-
def __init__(self, parent, name, path, plugin):
self.parent = parent
self.name = name
self.path = path
self.plugin = plugin
- self.logger = get_logger('plugin.%s' % name)
+ self.logger = logging.getLogger('plugin.%s' % name)
# Weakrefs to all handlers created by this plugin
self.handlers = set([])
@@ -210,13 +210,11 @@ class Plugin(object):
for attr in self.special_functions:
plugin.__dict__[attr] = getattr(self, attr)
-
def __repr__(self):
return u'<plugin(%r)>' % self.plugin
-
- def export(self, uzbl, attr, object, prepend=True):
- '''Attach `object` to `uzbl` instance. This is the preferred method
+ def export(self, uzbl, attr, obj, prepend=True):
+ '''Attach `obj` to `uzbl` instance. This is the preferred method
of sharing functionality, functions, data and objects between
plugins.
@@ -228,18 +226,16 @@ class Plugin(object):
assert attr not in uzbl.exports, "attr %r already exported by %r" %\
(attr, uzbl.exports[attr][0])
- prepend = True if prepend and callable(object) else False
- uzbl.__dict__[attr] = partial(object, uzbl) if prepend else object
- uzbl.exports[attr] = (self, object, prepend)
- uzbl.logger.info('exported %r to %r by plugin %r, prepended %r'
- % (object, 'uzbl.%s' % attr, self.name, prepend))
-
+ prepend = True if prepend and callable(obj) else False
+ uzbl.__dict__[attr] = partial(obj, uzbl) if prepend else obj
+ uzbl.exports[attr] = (self, obj, prepend)
+ uzbl.logger.info('exported %r to %r by plugin %r, prepended %r',
+ obj, 'uzbl.%s' % attr, self.name, prepend)
def export_dict(self, uzbl, exports):
for (attr, object) in exports.items():
self.export(uzbl, attr, object)
-
def find_handler(self, event, callback, args, kwargs):
'''Check if a handler with the identical callback and arguments
exists and return it.'''
@@ -253,7 +249,6 @@ class Plugin(object):
and handler.args == args and handler.kwargs == kwargs:
return handler
-
def connect(self, uzbl, event, callback, *args, **kwargs):
'''Create an event handler object which handles `event` events.
@@ -276,24 +271,22 @@ class Plugin(object):
# Create a new handler
handler = EventHandler(self, event, callback, args, kwargs)
self.handlers.add(weakref.ref(handler))
- self.logger.info('new %r' % handler)
+ self.logger.info('new %r', handler)
uzbl.handlers[event].append(handler)
- uzbl.logger.info('connected %r' % handler)
+ uzbl.logger.info('connected %r', handler)
return handler
-
def connect_dict(self, uzbl, connects):
for (event, callback) in connects.items():
self.connect(uzbl, event, callback)
-
def require(self, plugin):
'''Check that plugin with name `plugin` has been loaded. Use this to
ensure that your plugins dependencies have been met.'''
assert plugin in self.parent.plugins, self.logger.critical(
- 'plugin %r required by plugin %r' (plugin, self.name))
+ 'plugin %r required by plugin %r', plugin, self.name)
@classmethod
def unquote(cls, s):
@@ -304,10 +297,12 @@ class Plugin(object):
return s.encode('utf-8').decode('string_escape').decode('utf-8')
_splitquoted = re.compile("( |\"(?:\\\\.|[^\"])*?\"|'(?:\\\\.|[^'])*?')")
+
@classmethod
def splitquoted(cls, text):
'''Splits string on whitespace while respecting quotations'''
- return [cls.unquote(p) for p in cls._splitquoted.split(text) if p.strip()]
+ parts = cls._splitquoted.split(text)
+ return [cls.unquote(p) for p in parts if p.strip()]
class Uzbl(object):
@@ -315,6 +310,7 @@ class Uzbl(object):
self.opts = opts
self.parent = parent
self.child_socket = child_socket
+ self.child_buffer = []
self.time = time.time()
self.pid = None
self.name = None
@@ -323,7 +319,7 @@ class Uzbl(object):
self.instance_start = False
# Use name "unknown" until name is discovered.
- self.logger = get_logger('uzbl-instance[]')
+ self.logger = logging.getLogger('uzbl-instance[]')
# Track plugin event handlers and exported functions.
self.exports = {}
@@ -333,16 +329,14 @@ class Uzbl(object):
self._depth = 0
self._buffer = ''
-
def __repr__(self):
return '<uzbl(%s)>' % ', '.join([
'pid=%s' % (self.pid if self.pid else "Unknown"),
'name=%s' % ('%r' % self.name if self.name else "Unknown"),
- 'uptime=%f' % (time.time()-self.time),
+ 'uptime=%f' % (time.time() - self.time),
'%d exports' % len(self.exports.keys()),
'%d handlers' % sum([len(l) for l in self.handlers.values()])])
-
def init_plugins(self):
'''Call the init and after hooks in all loaded plugins for this
instance.'''
@@ -350,17 +344,16 @@ class Uzbl(object):
# Initialise each plugin with the current uzbl instance.
for plugin in self.parent.plugins.values():
if plugin.init:
- self.logger.debug('calling %r plugin init hook' % plugin.name)
+ self.logger.debug('calling %r plugin init hook', plugin.name)
plugin.init(self)
# Allow plugins to use exported features of other plugins by calling an
# optional `after` function in the plugins namespace.
for plugin in self.parent.plugins.values():
if plugin.after:
- self.logger.debug('calling %r plugin after hook'%plugin.name)
+ self.logger.debug('calling %r plugin after hook', plugin.name)
plugin.after(self)
-
def send(self, msg):
'''Send a command to the uzbl instance via the child socket
instance.'''
@@ -371,8 +364,27 @@ class Uzbl(object):
if opts.print_events:
print ascii(u'%s<-- %s' % (' ' * self._depth, msg))
- self.child_socket.send(ascii("%s\n" % msg))
+ self.child_buffer.append(ascii("%s\n" % msg))
+ def do_send(self):
+ data = ''.join(self.child_buffer)
+ try:
+ bsent = self.child_socket.send(data)
+ except socket.error as e:
+ if e.errno in (errno.EAGAIN, errno.EINTR):
+ self.child_buffer = [data]
+ return
+ else:
+ self.logger.error('failed to send', exc_info=True)
+ return self.close()
+ else:
+ if bsent == 0:
+ self.logger.debug('write end of connection closed')
+ self.close()
+ elif bsent < len(data):
+ self.child_buffer = [data[bsent:]]
+ else:
+ del self.child_buffer[:]
def read(self):
'''Read data from the child socket and pass lines to the parse_msg
@@ -385,7 +397,7 @@ class Uzbl(object):
return self.close()
except:
- self.logger.error(get_exc())
+ self.logger.error('failed to read', exc_info=True)
return self.close()
lines = (self._buffer + raw).split('\n')
@@ -399,17 +411,16 @@ class Uzbl(object):
self.logger.error(get_exc())
self.logger.error('erroneous event: %r' % line)
-
def parse_msg(self, line):
'''Parse an incoming message from a uzbl instance. Event strings
will be parsed into `self.event(event, args)`.'''
# Split by spaces (and fill missing with nulls)
- elems = (line.split(' ', 3) + ['',]*3)[:4]
+ elems = (line.split(' ', 3) + [''] * 3)[:4]
# Ignore non-event messages.
if elems[0] != 'EVENT':
- logger.info('non-event message: %r' % line)
+ logger.info('non-event message: %r', line)
if opts.print_events:
print '--- %s' % ascii(line)
return
@@ -419,31 +430,32 @@ class Uzbl(object):
assert name and event, 'event string missing elements'
if not self.name:
self.name = name
- self.logger = get_logger('uzbl-instance%s' % name)
- self.logger.info('found instance name %r' % name)
+ self.logger = logging.getLogger('uzbl-instance%s' % name)
+ self.logger.info('found instance name %r', name)
assert self.name == name, 'instance name mismatch'
# Handle the event with the event handlers through the event method
self.event(event, args)
-
def event(self, event, *args, **kargs):
'''Raise an event.'''
event = event.upper()
if not opts.daemon_mode and opts.print_events:
- elems = [event,]
- if args: elems.append(unicode(args))
- if kargs: elems.append(unicode(kargs))
+ elems = [event]
+ if args:
+ elems.append(unicode(args))
+ if kargs:
+ elems.append(unicode(kargs))
print ascii(u'%s--> %s' % (' ' * self._depth, ' '.join(elems)))
if event == "INSTANCE_START" and args:
assert not self.instance_start, 'instance already started'
self.pid = int(args[0])
- self.logger.info('found instance pid %r' % self.pid)
+ self.logger.info('found instance pid %r', self.pid)
self.init_plugins()
@@ -460,16 +472,14 @@ class Uzbl(object):
handler.call(self, *args, **kargs)
except:
- self.logger.error(get_exc())
+ self.logger.error('error in handler', exc_info=True)
self._depth -= 1
-
def close_connection(self, child_socket):
'''Close child socket and delete the uzbl instance created for that
child socket connection.'''
-
def close(self):
'''Close the client socket and call the plugin cleanup hooks.'''
@@ -486,7 +496,7 @@ class Uzbl(object):
self.child_socket.close()
except:
- self.logger.error(get_exc())
+ self.logger.error('failed to close socket', exc_info=True)
finally:
self.child_socket = None
@@ -494,11 +504,11 @@ class Uzbl(object):
# Call plugins cleanup hooks.
for plugin in self.parent.plugins.values():
if plugin.cleanup:
- self.logger.debug('calling %r plugin cleanup hook'
- % plugin.name)
+ self.logger.debug('calling %r plugin cleanup hook',
+ plugin.name)
plugin.cleanup(self)
- logger.info('removed %r' % self)
+ logger.info('removed %r', self)
class UzblEventDaemon(object):
@@ -529,16 +539,15 @@ class UzblEventDaemon(object):
# Load plugins into self.plugins
self.load_plugins(opts.plugins)
-
def load_plugins(self, plugins):
'''Load event manager plugins.'''
for path in plugins:
- logger.debug('loading plugin %r' % path)
+ logger.debug('loading plugin %r', path)
(dir, file) = os.path.split(path)
name = file[:-3] if file.lower().endswith('.py') else file
- info = imp.find_module(name, [dir,])
+ info = imp.find_module(name, [dir])
module = imp.load_module(name, *info)
# Check if the plugin has a callable hook.
@@ -546,11 +555,10 @@ class UzblEventDaemon(object):
for attr in ['init', 'after', 'cleanup']])
assert hooks, "no hooks in plugin %r" % module
- logger.debug('creating plugin instance for %r plugin' % name)
+ logger.debug('creating plugin instance for %r plugin', name)
plugin = Plugin(self, name, path, module)
self.plugins[name] = plugin
- logger.info('new %r' % plugin)
-
+ logger.info('new %r', plugin)
def create_server_socket(self):
'''Create the event manager daemon socket for uzbl instance duplex
@@ -564,8 +572,7 @@ class UzblEventDaemon(object):
sock.listen(5)
self.server_socket = sock
- logger.debug('bound server socket to %r' % opts.server_socket)
-
+ logger.debug('bound server socket to %r', opts.server_socket)
def run(self):
'''Main event daemon loop.'''
@@ -588,35 +595,39 @@ class UzblEventDaemon(object):
except:
if not self._quit:
- logger.critical(get_exc())
+ logger.critical('failed to listen', exc_info=True)
# Clean up and exit
self.quit()
logger.debug('exiting main loop')
-
def listen(self):
'''Accept incoming connections and constantly poll instance sockets
for incoming data.'''
- logger.info('listening on %r' % opts.server_socket)
+ logger.info('listening on %r', opts.server_socket)
# Count accepted connections
connections = 0
while (self.uzbls or not connections) or (not opts.auto_close):
socks = [self.server_socket] + self.uzbls.keys()
- reads, _, errors = select(socks, [], socks, 1)
+ wsocks = [k for k, v in self.uzbls.items() if v.child_buffer]
+ reads, writes, errors = select(socks, wsocks, socks, 1)
if self.server_socket in reads:
reads.remove(self.server_socket)
# Accept connection and create uzbl instance.
child_socket = self.server_socket.accept()[0]
+ child_socket.setblocking(False)
self.uzbls[child_socket] = Uzbl(self, child_socket)
connections += 1
+ for uzbl in [self.uzbls[s] for s in writes]:
+ uzbl.do_send()
+
for uzbl in [self.uzbls[s] for s in reads]:
uzbl.read()
@@ -626,7 +637,6 @@ class UzblEventDaemon(object):
logger.info('auto closing')
-
def close_server_socket(self):
'''Close and delete the server socket.'''
@@ -637,12 +647,11 @@ class UzblEventDaemon(object):
self.server_socket = None
if os.path.exists(opts.server_socket):
- logger.info('unlinking %r' % opts.server_socket)
+ logger.info('unlinking %r', opts.server_socket)
os.unlink(opts.server_socket)
except:
- logger.error(get_exc())
-
+ logger.error('failed to close server socket', exc_info=True)
def quit(self, sigint=None, *args):
'''Close all instance socket objects, server socket and delete the
@@ -673,16 +682,16 @@ def make_pid_file(pid_file):
'''Creates a pid file at `pid_file`, fails silently.'''
try:
- logger.debug('creating pid file %r' % pid_file)
+ logger.debug('creating pid file %r', pid_file)
make_dirs(pid_file)
pid = os.getpid()
fileobj = open(pid_file, 'w')
fileobj.write('%d' % pid)
fileobj.close()
- logger.info('created pid file %r with pid %d' % (pid_file, pid))
+ logger.info('created pid file %r with pid %d', pid_file, pid)
except:
- logger.error(get_exc())
+ logger.error('failed to create pid file', exc_info=True)
def del_pid_file(pid_file):
@@ -690,27 +699,27 @@ def del_pid_file(pid_file):
if os.path.isfile(pid_file):
try:
- logger.debug('deleting pid file %r' % pid_file)
+ logger.debug('deleting pid file %r', pid_file)
os.remove(pid_file)
- logger.info('deleted pid file %r' % pid_file)
+ logger.info('deleted pid file %r', pid_file)
except:
- logger.error(get_exc())
+ logger.error('failed to delete pid file', exc_info=True)
def get_pid(pid_file):
'''Reads a pid from pid file `pid_file`, fails None.'''
try:
- logger.debug('reading pid file %r' % pid_file)
+ logger.debug('reading pid file %r', pid_file)
fileobj = open(pid_file, 'r')
pid = int(fileobj.read())
fileobj.close()
- logger.info('read pid %d from pid file %r' % (pid, pid_file))
+ logger.info('read pid %d from pid file %r', pid, pid_file)
return pid
except (IOError, ValueError):
- logger.error(get_exc())
+ logger.error('failed to read pid', exc_info=True)
return None
@@ -729,30 +738,30 @@ def term_process(pid):
'''Asks nicely then forces process with pid `pid` to exit.'''
try:
- logger.info('sending SIGTERM to process with pid %r' % pid)
+ logger.info('sending SIGTERM to process with pid %r', pid)
os.kill(pid, SIGTERM)
except OSError:
logger.error(get_exc())
- logger.debug('waiting for process with pid %r to exit' % pid)
+ logger.debug('waiting for process with pid %r to exit', pid)
start = time.time()
while True:
if not pid_running(pid):
- logger.debug('process with pid %d exit' % pid)
+ logger.debug('process with pid %d exit', pid)
return True
- if (time.time()-start) > 5:
- logger.warning('process with pid %d failed to exit' % pid)
- logger.info('sending SIGKILL to process with pid %d' % pid)
+ if (time.time() - start) > 5:
+ logger.warning('process with pid %d failed to exit', pid)
+ logger.info('sending SIGKILL to process with pid %d', pid)
try:
os.kill(pid, SIGKILL)
except:
- logger.critical(get_exc())
+ logger.critical('failed to kill %d', pid, exc_info=True)
raise
- if (time.time()-start) > 10:
- logger.critical('unable to kill process with pid %d' % pid)
+ if (time.time() - start) > 10:
+ logger.critical('unable to kill process with pid %d', pid)
raise OSError
time.sleep(0.25)
@@ -763,20 +772,20 @@ def stop_action():
pid_file = opts.pid_file
if not os.path.isfile(pid_file):
- logger.error('could not find running event manager with pid file %r'
- % opts.pid_file)
+ logger.error('could not find running event manager with pid file %r',
+ pid_file)
return
pid = get_pid(pid_file)
if not pid_running(pid):
- logger.debug('no process with pid %r' % pid)
+ logger.debug('no process with pid %r', pid)
del_pid_file(pid_file)
return
- logger.debug('terminating process with pid %r' % pid)
+ logger.debug('terminating process with pid %r', pid)
term_process(pid)
del_pid_file(pid_file)
- logger.info('stopped event manager process with pid %d' % pid)
+ logger.info('stopped event manager process with pid %d', pid)
def start_action():
@@ -786,10 +795,10 @@ def start_action():
if os.path.isfile(pid_file):
pid = get_pid(pid_file)
if pid_running(pid):
- logger.error('event manager already started with pid %d' % pid)
+ logger.error('event manager already started with pid %d', pid)
return
- logger.info('no process with pid %d' % pid)
+ logger.info('no process with pid %d', pid)
del_pid_file(pid_file)
UzblEventDaemon().run()
@@ -816,7 +825,7 @@ def list_action():
print plugin
-if __name__ == "__main__":
+def make_parser():
parser = OptionParser('usage: %prog [options] {start|stop|restart|list}')
add = parser.add_option
@@ -833,6 +842,7 @@ if __name__ == "__main__":
help='load plugin, loads before plugins in search dirs')
socket_location = os.path.join(CACHE_DIR, 'event_daemon')
+
add('-s', '--server-socket',
dest='server_socket', metavar="SOCKET", default=socket_location,
help='server AF_UNIX socket location')
@@ -862,6 +872,34 @@ if __name__ == "__main__":
dest='print_events', action="store_false", default=True,
help="silence the printing of events to stdout")
+ return parser
+
+
+def init_logger():
+ log_level = logging.CRITICAL - opts.verbose * 10
+ logger = logging.getLogger()
+ logger.setLevel(max(log_level, 10))
+
+ # Console
+ handler = logging.StreamHandler()
+ handler.setLevel(max(log_level + 10, 10))
+ handler.setFormatter(logging.Formatter(
+ '%(name)s: %(levelname)s: %(message)s'))
+ logger.addHandler(handler)
+
+ # Logfile
+ handler = logging.FileHandler(opts.log_file, 'w', 'utf-8', 1)
+ handler.setLevel(max(log_level, 10))
+ handler.setFormatter(logging.Formatter(
+ '[%(created)f] %(name)s: %(levelname)s: %(message)s'))
+ logger.addHandler(handler)
+
+
+def main():
+ global opts
+
+ parser = make_parser()
+
(opts, args) = parser.parse_args()
opts.server_socket = expandpath(opts.server_socket)
@@ -881,35 +919,8 @@ if __name__ == "__main__":
opts.log_file = expandpath(opts.log_file)
# Logging setup
- log_level = logging.CRITICAL - opts.verbose*10
-
- # Console logging handler
- ch = logging.StreamHandler()
- ch.setLevel(max(log_level+10, 10))
- ch.setFormatter(logging.Formatter(
- '%(name)s: %(levelname)s: %(message)s'))
-
- # File logging handler
- fh = logging.FileHandler(opts.log_file, 'w', 'utf-8', 1)
- fh.setLevel(max(log_level, 10))
- fh.setFormatter(logging.Formatter(
- '[%(created)f] %(name)s: %(levelname)s: %(message)s'))
-
- # logging.getLogger wrapper which sets the levels and adds the
- # file and console handlers automagically
- def get_logger(name):
- handlers = [ch, fh]
- level = [max(log_level, 10),]
- logger = logging.getLogger(name)
- logger.setLevel(level[0])
- for handler in handlers:
- logger.addHandler(handler)
-
- return logger
-
- # Get main logger
- logger = get_logger(SCRIPTNAME)
- logger.info('logging to %r' % opts.log_file)
+ init_logger()
+ logger.info('logging to %r', opts.log_file)
plugins = {}
@@ -923,11 +934,11 @@ if __name__ == "__main__":
for plugin in matches:
(head, tail) = os.path.split(plugin)
if tail not in plugins:
- logger.debug('found plugin: %r' % plugin)
+ logger.debug('found plugin: %r', plugin)
plugins[tail] = plugin
else:
- logger.debug('ignoring plugin: %r' % plugin)
+ logger.debug('ignoring plugin: %r', plugin)
# Add default plugin locations
if opts.default_dirs:
@@ -941,15 +952,15 @@ if __name__ == "__main__":
# Load all plugins in `opts.plugin_dirs` into the plugins list
for dir in opts.plugin_dirs:
dir = expandpath(dir)
- logger.debug('searching plugin dir: %r' % dir)
+ logger.debug('searching plugin dir: %r', dir)
for plugin in glob(os.path.join(dir, '*.py')):
(head, tail) = os.path.split(plugin)
if tail not in plugins:
- logger.debug('found plugin: %r' % plugin)
+ logger.debug('found plugin: %r', plugin)
plugins[tail] = plugin
else:
- logger.debug('ignoring plugin: %r' % plugin)
+ logger.debug('ignoring plugin: %r', plugin)
plugins = plugins.values()
@@ -958,11 +969,15 @@ if __name__ == "__main__":
if not os.path.isfile(plugin):
parser.error('plugin not a file: %r' % plugin)
- if opts.auto_close: logger.debug('will auto close')
- else: logger.debug('will not auto close')
+ if opts.auto_close:
+ logger.debug('will auto close')
+ else:
+ logger.debug('will not auto close')
- if opts.daemon_mode: logger.debug('will daemonize')
- else: logger.debug('will not daemonize')
+ if opts.daemon_mode:
+ logger.debug('will daemonize')
+ else:
+ logger.debug('will not daemonize')
opts.plugins = plugins
@@ -976,16 +991,21 @@ if __name__ == "__main__":
parser.error('invalid action: %r' % action)
elif not args:
- logger.warning('no daemon action given, assuming %r' % 'start')
action = 'start'
+ logger.warning('no daemon action given, assuming %r', action)
else:
parser.error('invalid action argument: %r' % args)
- logger.info('daemon action %r' % action)
+ logger.info('daemon action %r', action)
# Do action
daemon_actions[action]()
- logger.debug('process CPU time: %f' % time.clock())
+ logger.debug('process CPU time: %f', time.clock())
+
+
+if __name__ == "__main__":
+ main()
+
# vi: set et ts=4:
diff --git a/bin/uzbl-tabbed b/bin/uzbl-tabbed
index a15967a..1a65788 100755
--- a/bin/uzbl-tabbed
+++ b/bin/uzbl-tabbed
@@ -72,7 +72,6 @@
# gtk_tab_pos = (top|left|bottom|right)
# gtk_refresh = 1000
# switch_to_new_tabs = 1
-# capture_new_windows = 1
# multiline_tabs = 1
#
# Tab title options:
@@ -88,8 +87,6 @@
# session_file = $HOME/.local/share/uzbl/session
#
# Inherited uzbl options:
-# fifo_dir = /tmp
-# socket_dir = /tmp
# icon_path = $HOME/.local/share/uzbl/uzbl.png
# status_background = #303030
#
@@ -199,7 +196,6 @@ config = {
'gtk_tab_pos': 'top', # Gtk tab position (top|left|bottom|right)
'gtk_refresh': 1000, # Tablist refresh millisecond interval
'switch_to_new_tabs': True, # Upon opening a new tab switch to it
- 'capture_new_windows': True, # Use uzbl_tabbed to catch new windows
'multiline_tabs': True, # Tabs overflow onto new tablist lines.
# Tab title options
@@ -215,8 +211,6 @@ config = {
'session_file': os.path.join(DATA_DIR, 'session'),
# Inherited uzbl options
- 'fifo_dir': '/tmp', # Path to look for uzbl fifo.
- 'socket_dir': '/tmp', # Path to look for uzbl socket.
'icon_path': os.path.join(DATA_DIR, 'uzbl.png'),
'status_background': "#303030", # Default background for all panels.
@@ -298,17 +292,20 @@ def escape(s):
return s
class SocketClient:
- '''Represents a Uzbl instance, which is not necessarly linked with a UzblInstance'''
+ '''Represents a connection to the uzbl-tabbed socket.'''
# List of UzblInstance objects not already linked with a SocketClient
instances_queue = {}
- def __init__(self, socket):
+ def __init__(self, socket, uzbl_tabbed):
self._buffer = ""
self._socket = socket
self._watchers = [io_add_watch(socket, IO_IN, self._socket_recv),\
io_add_watch(socket, IO_HUP, self._socket_closed)]
+
self.uzbl = None
+ self.uzbl_tabbed = uzbl_tabbed
+ self.dispatcher = GlobalEventDispatcher(uzbl_tabbed)
def _socket_recv(self, fd, condition):
@@ -328,26 +325,44 @@ class SocketClient:
'''An Uzbl instance sent some data, parse it'''
self._buffer += data
- if self.uzbl:
- if "\n" in self._buffer:
- cmds = self._buffer.split("\n")
- if cmds[-1]: # Last command has been received incomplete, don't process it
- self._buffer, cmds = cmds[-1], cmds[:-1]
- else:
- self._buffer = ""
+ if "\n" in self._buffer:
+ cmds = self._buffer.split("\n")
- for cmd in cmds:
- if cmd:
- self.uzbl.parse_command(cmd)
- else:
- name = re.findall('^EVENT \[(\d+-\d+)\] INSTANCE_START \d+$', self._buffer, re.M)
- uzbl = self.instances_queue.get(name[0])
+ if cmds[-1]: # Last command has been received incomplete, don't process it
+ self._buffer, cmds = cmds[-1], cmds[:-1]
+ else:
+ self._buffer = ""
+
+ for cmd in cmds:
+ if cmd:
+ self.handle_event(cmd)
+
+ def handle_event(self, cmd):
+ cmd = parse_event(cmd)
+ message, instance_name, message_type = cmd[0:3]
+ args = cmd[3:]
+
+ if not message == "EVENT":
+ return
+
+ # strip the surrounding []
+ instance_name = instance_name[1:-1]
+
+ if self.uzbl:
+ if not self.dispatcher.dispatch(message_type, args):
+ self.uzbl.dispatcher.dispatch(message_type, args)
+ elif message_type == 'INSTANCE_START':
+ uzbl = self.instances_queue.get(instance_name)
if uzbl:
- del self.instances_queue[name[0]]
- self.uzbl = uzbl
- self.uzbl.got_socket(self)
- self._feed("")
+ # we've found the uzbl we were waiting for
+ del self.instances_queue[instance_name]
+ else:
+ # an unsolicited uzbl has connected, how exciting!
+ uzbl = UzblInstance(self.uzbl_tabbed, None, '', '', False)
+ self.uzbl = uzbl
+ self.uzbl.got_socket(self)
+ self._feed("")
def send(self, data):
'''Child socket send function.'''
@@ -363,18 +378,84 @@ class SocketClient:
map(source_remove, self._watchers)
self._watchers = []
-class EventDispatcher:
- def __init__(self, uzbl):
- self.uzbl = uzbl
- self.parent = self.uzbl.parent
+def unquote(s):
+ '''Removes quotation marks around strings if any and interprets
+ \\-escape sequences using `string_escape`'''
+ if s and s[0] == s[-1] and s[0] in ['"', "'"]:
+ s = s[1:-1]
+ return s.encode('utf-8').decode('string_escape').decode('utf-8')
+
+_splitquoted = re.compile("( |\"(?:\\\\.|[^\"])*?\"|'(?:\\\\.|[^'])*?')")
+def parse_event(text):
+ '''Splits string on whitespace while respecting quotations'''
+ return [unquote(p) for p in _splitquoted.split(text) if p.strip()]
+
+class EventDispatcher:
def dispatch(self, message_type, args):
+ '''Returns True if the message was handled, False otherwise.'''
+
method = getattr(self, message_type.lower(), None)
if method is None:
- return
+ return False
+
+ method(*args)
+ return True
+
+class GlobalEventDispatcher(EventDispatcher):
+ def __init__(self, uzbl_tabbed):
+ self.uzbl_tabbed = uzbl_tabbed
+
+ def new_tab(self, uri = ''):
+ self.uzbl_tabbed.new_tab(uri)
+
+ def new_tab_bg(self, uri = ''):
+ self.uzbl_tabbed.new_tab(uri, switch = False)
- return method(*args)
+ def new_tab_next(self, uri = ''):
+ self.uzbl_tabbed.new_tab(uri, next=True)
+
+ def new_bg_tab_next(self, uri = ''):
+ self.uzbl_tabbed.new_tab(uri, switch = False, next = True)
+
+ def next_tab(self, step = 1):
+ self.uzbl_tabbed.next_tab(int(step))
+
+ def prev_tab(self, step = 1):
+ self.uzbl_tabbed.prev_tab(int(step))
+
+ def goto_tab(self, index):
+ self.uzbl_tabbed.goto_tab(int(index))
+
+ def first_tab(self):
+ self.uzbl_tabbed.goto_tab(0)
+
+ def last_tab(self):
+ self.uzbl_tabbed.goto_tab(-1)
+
+ def preset_tabs(self, *args):
+ self.uzbl_tabbed.run_preset_command(*args)
+
+ def bring_to_front(self):
+ self.uzbl_tabbed.window.present()
+
+ def clean_tabs(self):
+ self.uzbl_tabbed.clean_slate()
+
+ def exit_all_tabs(self):
+ self.uzbl_tabbed.quitrequest()
+
+class InstanceEventDispatcher(EventDispatcher):
+ def __init__(self, uzbl):
+ self.uzbl = uzbl
+ self.parent = self.uzbl.parent
+
+ def plug_created(self, plug_id):
+ if not self.uzbl.tab:
+ tab = self.parent.create_tab()
+ tab.add_id(int(plug_id))
+ self.uzbl.set_tab(tab)
def title_changed(self, title):
self.uzbl.title = title.strip()
@@ -417,71 +498,14 @@ class EventDispatcher:
def load_commit(self, uri):
self.uzbl.uri = uri
- def new_tab(self, uri = None):
- if uri:
- self.parent.new_tab(uri)
- else:
- self.parent.new_tab()
-
- def new_tab_bg(self, uri = None):
- if uri:
- self.parent.new_tab(uri, switch = False)
- else:
- self.parent.new_tab(switch = False)
-
- def new_tab_next(self, uri = None):
- if uri:
- self.parent.new_tab(uri, next=True)
- else:
- self.parent.new_tab(next=True)
-
- def new_bg_tab_next(self, uri = None):
- if uri:
- self.parent.new_tab(uri, switch = False, next = True)
- else:
- self.parent.new_tab(switch = False, next = True)
-
- def next_tab(self, step = None):
- if step:
- self.parent.next_tab(int(step))
- else:
- self.parent.next_tab()
-
- def prev_tab(self, step = None):
- if step:
- self.parent.prev_tab(int(step))
- else:
- self.parent.prev_tab()
-
- def goto_tab(self, index):
- self.parent.goto_tab(int(index))
-
- def first_tab(self):
- self.parent.goto_tab(0)
-
- def last_tab(self):
- self.parent.goto_tab(-1)
-
- def preset_tabs(self, *args):
- self.parent.parse_command(["preset"] + [ a for a in args ])
-
- def bring_to_front(self):
- self.parent.window.present()
-
- def clean_tabs(self):
- self.parent.clean_slate()
-
- def exit_all_tabs(self):
- self.parent.quitrequest()
-
class UzblInstance:
'''Uzbl instance meta-data/meta-action object.'''
- def __init__(self, parent, tab, name, uri, title, switch):
+ def __init__(self, parent, name, uri, title, switch):
self.parent = parent
- self.tab = tab
- self.dispatcher = EventDispatcher(self)
+ self.tab = None
+ self.dispatcher = InstanceEventDispatcher(self)
self.name = name
self.title = title
@@ -490,8 +514,11 @@ class UzblInstance:
self._client = None
self._switch = switch # Switch to tab after loading ?
- self.title_changed()
+ def set_tab(self, tab):
+ self.tab = tab
+ self.title_changed()
+ self.parent.tabs[self.tab] = self
def got_socket(self, client):
'''Uzbl instance is now connected'''
@@ -506,6 +533,9 @@ class UzblInstance:
def title_changed(self, gtk_only = True): # GTK-only is for indexes
'''self.title has changed, update the tabs list'''
+ if not self.tab:
+ return
+
tab_titles = config['tab_titles']
tab_indexes = config['tab_indexes']
show_ellipsis = config['show_ellipsis']
@@ -546,7 +576,8 @@ class UzblInstance:
''' Send the SET command to Uzbl '''
if self._client:
- self._client.send('set %s = %s') #TODO: escape chars ?
+ line = 'set %s = %s' % (key, val) #TODO: escape chars ?
+ self._client.send(line)
def exit(self):
@@ -555,27 +586,6 @@ class UzblInstance:
if self._client:
self._client.send('exit')
- def unquote(self, s):
- '''Removes quotation marks around strings if any and interprets
- \\-escape sequences using `string_escape`'''
- if s and s[0] == s[-1] and s[0] in ['"', "'"]:
- s = s[1:-1]
- return s.encode('utf-8').decode('string_escape').decode('utf-8')
-
- _splitquoted = re.compile("( |\"(?:\\\\.|[^\"])*?\"|'(?:\\\\.|[^'])*?')")
- def parse_event(self, text):
- '''Splits string on whitespace while respecting quotations'''
- return [self.unquote(p) for p in self._splitquoted.split(text) if p.strip()]
-
- def parse_command(self, cmd):
- ''' Parse event givent by the Uzbl instance '''
-
- cmd = self.parse_event(cmd)
- message, message_type, args = cmd[0], cmd[2], cmd[3:]
-
- if message == "EVENT":
- self.dispatcher.dispatch(message_type, args)
-
def close(self):
'''The remote instance exited'''
@@ -606,6 +616,13 @@ class UzblTabbed:
# Generates a unique id for uzbl socket filenames.
self.next_pid = counter().next
+ # Whether to reconfigure new uzbl instances
+ self.force_socket_dir = False
+ self.force_fifo_dir = False
+
+ self.fifo_dir = '/tmp' # Path to look for uzbl fifo.
+ self.socket_dir = '/tmp' # Path to look for uzbl socket.
+
# Create main window
self.window = gtk.Window()
try:
@@ -684,16 +701,12 @@ class UzblTabbed:
self.window.show()
self.wid = self.notebook.window.xid
- # Store information about the applications fifo and socket.
- fifo_filename = 'uzbltabbed_%d.fifo' % os.getpid()
+ # Store information about the application's socket.
socket_filename = 'uzbltabbed_%d.socket' % os.getpid()
- self._fifo = None
self._socket = None
- self.fifo_path = os.path.join(config['fifo_dir'], fifo_filename)
- self.socket_path = os.path.join(config['socket_dir'], socket_filename)
+ self.socket_path = os.path.join(self.socket_dir, socket_filename)
- # Now initialise the fifo and the socket
- self.init_fifo()
+ # Now initialise the the socket
self.init_socket()
# If we are using sessions then load the last one if it exists.
@@ -724,8 +737,7 @@ class UzblTabbed:
print_exc()
error("encounted error %r" % sys.exc_info()[1])
- # Unlink fifo socket
- self.unlink_fifo()
+ # Unlink socket
self.close_socket()
# Attempt to close all uzbl instances nicely.
@@ -763,7 +775,7 @@ class UzblTabbed:
'''A new uzbl instance was created'''
client, _ = sock.accept()
- self.clients[client] = SocketClient(client)
+ self.clients[client] = SocketClient(client, self)
return True
@@ -791,249 +803,45 @@ class UzblTabbed:
self._socket = None
- def init_fifo(self):
- '''Create interprocess communication fifo.'''
-
- if os.path.exists(self.fifo_path):
- if not os.access(self.fifo_path, os.F_OK | os.R_OK | os.W_OK):
- os.mkfifo(self.fifo_path)
-
- else:
- basedir = os.path.dirname(self.fifo_path)
- if not os.path.exists(basedir):
- os.makedirs(basedir)
-
- os.mkfifo(self.fifo_path)
-
- # Add event handlers for IO_IN & IO_HUP events.
- self.setup_fifo_watchers()
-
- echo("[fifo] listening at %r" % self.fifo_path)
-
- # Add atexit register to destroy the fifo on program termination.
- atexit.register(self.unlink_fifo)
-
-
- def unlink_fifo(self):
- '''Unlink the fifo socket. Note: This function is called automatically
- on exit by an atexit register.'''
-
- # Make sure the fifo fd is closed.
- self.close_fifo()
-
- # And unlink if the real fifo exists.
- if os.path.exists(self.fifo_path):
- os.unlink(self.fifo_path)
- echo("unlinked %r" % self.fifo_path)
-
-
- def close_fifo(self):
- '''Remove all event handlers watching the fifo and close the fd.'''
-
- # Already closed
- if self._fifo is None: return
-
- (fd, watchers) = self._fifo
- os.close(fd)
-
- # Stop all gobject io watchers watching the fifo.
- for gid in watchers:
- source_remove(gid)
-
- self._fifo = None
-
-
- def setup_fifo_watchers(self):
- '''Open fifo socket fd and setup gobject IO_IN & IO_HUP event
- handlers.'''
-
- # Close currently open fifo fd and kill all watchers
- self.close_fifo()
-
- fd = os.open(self.fifo_path, os.O_RDONLY | os.O_NONBLOCK)
-
- # Add gobject io event handlers to the fifo socket.
- watchers = [io_add_watch(fd, IO_IN, self.main_fifo_read),\
- io_add_watch(fd, IO_HUP, self.main_fifo_hangup)]
-
- self._fifo = (fd, watchers)
-
-
- def main_fifo_hangup(self, fd, cb_condition):
- '''Handle main fifo socket hangups.'''
-
- # Close old fd, open new fifo socket and add io event handlers.
- self.setup_fifo_watchers()
-
- # Kill the gobject event handler calling this handler function.
- return False
-
-
- def main_fifo_read(self, fd, cb_condition):
- '''Read from main fifo socket.'''
-
- self._buffer = os.read(fd, 1024)
- temp = self._buffer.split("\n")
- self._buffer = temp.pop()
- cmds = [s.strip().split() for s in temp if len(s.strip())]
-
- for cmd in cmds:
- try:
- #print cmd
- self.parse_command(cmd)
-
- except:
- print_exc()
- error("parse_command: invalid command %s" % ' '.join(cmd))
- raise
-
- return True
-
-
- def parse_command(self, cmd):
- '''Parse instructions from uzbl child processes.'''
-
- # Commands ( [] = optional, {} = required )
- # new [uri]
- # open new tab and head to optional uri.
- # newbg [uri]
- # open a new tab in the background
- # close [tab-num]
- # close current tab or close via tab id.
- # next [n-tabs]
- # open next tab or n tabs down. Supports negative indexing.
- # prev [n-tabs]
- # open prev tab or n tabs down. Supports negative indexing.
- # goto {tab-n}
- # goto tab n.
- # first
- # goto first tab.
- # last
- # goto last tab.
- # title {pid} {document-title}
- # updates tablist title.
- # uri {pid} {document-location}
- # updates tablist uri
- # bring_to_front
- # brings the gtk window to focus.
- # exit
- # exits uzbl_tabbed.py
-
- if cmd[0] == "new":
- if len(cmd) == 2:
- self.new_tab(cmd[1])
-
- else:
- self.new_tab()
-
- elif cmd[0] == "newbg":
- if len(cmd) == 2:
- self.new_tab(cmd[1], switch=False)
- else:
- self.new_tab(switch=False)
-
- elif cmd[0] == "newfromclip":
- uri = subprocess.Popen(['xclip','-selection','clipboard','-o'],\
- stdout=subprocess.PIPE).communicate()[0]
- if uri:
- self.new_tab(uri)
+ def run_preset_command(self, cmd, *args):
+ if len(args) < 1:
+ error("parse_command: invalid preset command")
- elif cmd[0] == "close":
- if len(cmd) == 2:
- self.close_tab(int(cmd[1]))
-
- else:
- self.close_tab()
-
- elif cmd[0] == "next":
- if len(cmd) == 2:
- self.next_tab(int(cmd[1]))
-
- else:
- self.next_tab()
+ elif cmd == "save":
+ path = os.path.join(config['saved_sessions_dir'], args[0])
+ self.save_session(path)
- elif cmd[0] == "prev":
- if len(cmd) == 2:
- self.prev_tab(int(cmd[1]))
+ elif cmd == "load":
+ path = os.path.join(config['saved_sessions_dir'], args[0])
+ self.load_session(path)
+ elif cmd == "del":
+ path = os.path.join(config['saved_sessions_dir'], args[0])
+ if os.path.isfile(path):
+ os.remove(path)
else:
- self.prev_tab()
-
- elif cmd[0] == "goto":
- self.goto_tab(int(cmd[1]))
-
- elif cmd[0] == "first":
- self.goto_tab(0)
-
- elif cmd[0] == "last":
- self.goto_tab(-1)
-
- elif cmd[0] in ["title", "uri"]:
- if len(cmd) > 2:
- uzbl = self.get_tab_by_name(int(cmd[1]))
- if uzbl:
- old = getattr(uzbl, cmd[0])
- new = ' '.join(cmd[2:])
- setattr(uzbl, cmd[0], new)
- if old != new:
- self.update_tablist()
-
- else:
- error("parse_command: no uzbl with name %r" % int(cmd[1]))
-
- elif cmd[0] == "preset":
- if len(cmd) < 3:
- error("parse_command: invalid preset command")
-
- elif cmd[1] == "save":
- path = os.path.join(config['saved_sessions_dir'], cmd[2])
- self.save_session(path)
-
- elif cmd[1] == "load":
- path = os.path.join(config['saved_sessions_dir'], cmd[2])
- self.load_session(path)
-
- elif cmd[1] == "del":
- path = os.path.join(config['saved_sessions_dir'], cmd[2])
- if os.path.isfile(path):
- os.remove(path)
+ error("parse_command: preset %r does not exist." % path)
- else:
- error("parse_command: preset %r does not exist." % path)
-
- elif cmd[1] == "list":
- # FIXME: what argument is this supposed to be passed,
- # and why?
- uzbl = self.get_tab_by_name(int(cmd[2]))
- if uzbl:
- if not os.path.isdir(config['saved_sessions_dir']):
- js = "js alert('No saved presets.');"
- uzbl._client.send(js)
-
- else:
- listdir = os.listdir(config['saved_sessions_dir'])
- listdir = "\\n".join(listdir)
- js = "js alert('Session presets:\\n\\n%s');" % listdir
- uzbl._client.send(js)
+ elif cmd == "list":
+ # FIXME: what argument is this supposed to be passed,
+ # and why?
+ uzbl = self.get_tab_by_name(int(args[0]))
+ if uzbl:
+ if not os.path.isdir(config['saved_sessions_dir']):
+ js = "js alert('No saved presets.');"
+ uzbl._client.send(js)
else:
- error("parse_command: unknown tab name.")
+ listdir = os.listdir(config['saved_sessions_dir'])
+ listdir = "\\n".join(listdir)
+ js = "js alert('Session presets:\\n\\n%s');" % listdir
+ uzbl._client.send(js)
else:
- error("parse_command: unknown parse command %r"\
- % ' '.join(cmd))
-
- elif cmd[0] == "bring_to_front":
- self.window.present()
-
- elif cmd[0] == "clean":
- self.clean_slate()
-
- elif cmd[0] == "exit":
- self.quitrequest()
+ error("parse_command: unknown tab name.")
else:
- error("parse_command: unknown command %r" % ' '.join(cmd))
+ error("parse_command: unknown parse command %r" % cmd)
def get_tab_by_name(self, name):
@@ -1045,6 +853,18 @@ class UzblTabbed:
return False
+ def create_tab(self, beside = False):
+ tab = gtk.Socket()
+ tab.show()
+
+ if beside:
+ pos = self.notebook.get_current_page() + 1
+ self.notebook.insert_page(tab, position=pos)
+ else:
+ self.notebook.append_page(tab)
+
+ self.notebook.set_tab_reorderable(tab, True)
+ return tab
def new_tab(self, uri='', title='', switch=None, next=False):
'''Add a new tab to the notebook and start a new instance of uzbl.
@@ -1052,10 +872,7 @@ class UzblTabbed:
when you need to load multiple tabs at a time (I.e. like when
restoring a session from a file).'''
- tab = gtk.Socket()
- tab.show()
- self.notebook.insert_page(tab, position=next and self.notebook.get_current_page() + 1 or -1)
- self.notebook.set_tab_reorderable(tab, True)
+ tab = self.create_tab(next)
sid = tab.get_id()
uri = uri.strip()
name = "%d-%d" % (os.getpid(), self.next_pid())
@@ -1070,9 +887,10 @@ class UzblTabbed:
'--connect-socket', self.socket_path, '--uri', str(uri)]
gobject.spawn_async(cmd, flags=gobject.SPAWN_SEARCH_PATH)
- uzbl = UzblInstance(self, tab, name, uri, title, switch)
+ uzbl = UzblInstance(self, name, uri, title, switch)
+ uzbl.set_tab(tab)
+
SocketClient.instances_queue[name] = uzbl
- self.tabs[tab] = uzbl
def clean_slate(self):
@@ -1085,16 +903,15 @@ class UzblTabbed:
uzbl = self.tabs[tab]
uzbl.exit()
-
def config_uzbl(self, uzbl):
'''Send bind commands for tab new/close/next/prev to a uzbl
instance.'''
- # Set definitions here
- # set(key, command back to fifo)
- if config['capture_new_windows']:
- uzbl.set("new_window", r'new $8')
+ if self.force_socket_dir:
+ uzbl.set("socket_dir", self.socket_dir)
+ if self.force_fifo_dir:
+ uzbl.set("fifo_dir", self.fifo_dir)
def goto_tab(self, index):
'''Goto tab n (supports negative indexing).'''
@@ -1411,9 +1228,8 @@ class UzblTabbed:
def quit(self, *args):
'''Cleanup and quit. Called by delete-event signal.'''
- # Close the fifo socket, remove any gobject io event handlers and
+ # Close the socket, remove any gobject io event handlers and
# delete socket.
- self.unlink_fifo()
self.close_socket()
# Remove all gobject timers that are still ticking.
@@ -1455,13 +1271,15 @@ if __name__ == "__main__":
import pprint
sys.stderr.write("%s\n" % pprint.pformat(config))
+ uzbl = UzblTabbed()
+
if options.socketdir:
- config['socket_dir'] = options.socketdir
+ uzbl.socket_dir = options.socketdir
+ uzbl.force_socket_dir = True
if options.fifodir:
- config['fifo_dir'] = options.fifodir
-
- uzbl = UzblTabbed()
+ uzbl.fifo_dir = options.fifodir
+ uzbl.force_fifo_dir = True
# All extra arguments given to uzbl_tabbed.py are interpreted as
# web-locations to opened in new tabs.
diff --git a/docs/FAQ b/docs/FAQ
index 7587d70..d5245b4 100644
--- a/docs/FAQ
+++ b/docs/FAQ
@@ -1,52 +1,51 @@
FAQ
---
-### Uzbl crashes immediately (segfaults). WTF ?
-You are using a libwebkit version (usually 1.1.15.*) that uses enchant which
-is compiled with zemberek support built-in. Compile enchant with
---disable-zemberek or ask your package maintainer.
-See also:
+### Help, Uzbl isn't responding to any of my keyboard commands!
+If the left side of the status bar says `[]` instead of `[Cmd]` when you start
+`uzbl-browser`, then the event manager isn't starting or its plugins aren't
+loading.
- * https://bugs.webkit.org/show_bug.cgi?id=30860
- * http://bugzilla.abisource.com/show_bug.cgi?id=12413
- * http://bugzilla.abisource.com/show_bug.cgi?id=12529
- * http://bugs.archlinux.org/task/17401
- * http://www.uzbl.org/news.php?id=17
+If you're an Arch user, you should edit `/usr/bin/uzbl-{event-manager,tabbed}`
+and change the first line of each to `#!/usr/bin/env python2`.
+If you're trying to run uzbl without installing it, you should launch
+`uzbl-event-manager` yourself with the `--plugin-dir=DIR` option pointing to the
+location of the event manager plugins (they're in examples/data/plugins/)
### I just installed uzbl but it doesn't do much. What now?
-"Uzbl" is the name for the umbrella project that has several subprojects.
-You probably want `uzbl-browser` or any of the other projects.
-The main program (uzbl-core) is a program meant for integration with other
-tools and scripts, by itself doesn't do many usefull things. See README.
-
-### Where are the widgets (forward, back,.. button etc)
-The layout of uzbl (and derivatives) only contains what you really need to see. we only have a statusbar, which even can also be disabled. There are no buttons, but we do
-have lots of keybinding possibilities.
-
-### Why can uzbl-core/uzbl-browser only show one page?
-It is nearly unanimously agreed that one page per uzbl-core is best.
-It allows a simple implementation of both uzbl-core and
-uzbl-browser, and it makes things more robust.
-But read the next entry...
-
-### How to have multiple pages in one window?
-So, given that uzbl-core and uzbl-browser only deal with one page at a time (see
+There's no "uzbl" command, that's just the name for the whole collection of
+tools. The command you're looking for is `uzbl-browser` or `uzbl-tabbed`.
+
+The central program `uzbl-core` doesn't do many useful things by itself,
+it's meant for integration with other tools and scripts. See README.
+
+### Where are the widgets (forward button, back button, search bar, etc)?
+There are none. What we do have is a powerful statusbar and lots of keybinding
+possibilities.
+
+### Why can each `uzbl-core`/`uzbl-browser` process only show one page?
+This allows a simple implementation of both `uzbl-core` and `uzbl-browser`, and it
+makes things more robust. But read the next entry...
+
+### How can I have multiple pages in one window?
+So, given that `uzbl-core` and `uzbl-browser` only deal with one page at a time (see
above), how can you have a window with multiple pages?
-Basically this is involves concerns on two sides:
+Basically this involves concerns on two sides:
* window management
- - can I keep all pages together in 1 X window so that I can move all at once to a different workspace
- - can I "split off" pages into separate windows (i.e. move only one specific page/window to a different desktop)
- or merge windows together?
- - can I integrate uzbl pages/windows into WM features? (alt-tab, tiling layouts, taskbar, ...)
- - ...
+ - can I keep all pages together in 1 X window so that I can move all of them
+ to a different workspace at once
+ - can I "split off" pages into separate windows (i.e. move only one specific
+ page/window to a different desktop) or merge windows together?
+ - can I integrate uzbl pages/windows into WM features? (alt-tab, tiling
+ layouts, taskbar, ...)
* application-level
- realtime overview of all page titles of all uzbl instances
- - representation styles which are tightly coupled to the application such as treeviews that show from which you page you opened
- others, or page state (loading etc)
- - ...
+ - representation styles which are tightly coupled to the application such as
+ treeviews that show from which you page you opened others, or page state
+ (loading etc)
Uzbl itself can hardly be a limiting factor, as it supports/has:
@@ -60,18 +59,21 @@ side.
There are multiple approaches, each with pros and cons.
-* Tabbing in the WM: Xmonads tabbed layout, Wmii's stacked layout, fluxbox or kwin tabs and so on.
-* Visual overview in the WM: commonly used with dwm or Awesome's tiling layouts with master/slave areas.
- The [dynamic zoom script](http://www.uzbl.org/wiki/dynamic_zooming) is useful here.
-* A container application whih embeds multiple uzbl-browsers and provide tablists, tree views, and more.
- Examples:
- - [uzbl-tabbed](http://www.uzbl.org/wiki/uzbl_tabbed) (officially supported)
- - [uzbltreetab](http://www.uzbl.org/wiki/uzbltreetab)
- - [uzbltab](http://www.uzbl.org/wiki/uzbltab)
- - [suckless tabbed](http://tools.suckless.org/tabbed)
+* Tabbing in the WM: Xmonads tabbed layout, Wmii's stacked layout, fluxbox or
+ kwin tabs and so on.
+* Visual overview in the WM: commonly used with dwm or Awesome's tiling layouts
+ with master/slave areas.
+ The [dynamic zoom script][] is useful here.
+* A container application which embeds multiple uzbl-browsers and provide
+ tablists, tree views, and more. Examples:
+ - [uzbl-tabbed][] (officially supported)
+ - [uzbltreetab][]
+ - [uzbltab][]
+ - [suckless tabbed][]
* An application to mimic tabbing independently of WM support.
The only thing you need to do is focus/maximize the instance you want,
- keep the others out of sight and use tools like dmenu/xbindkeys and wmctrl to switch instances.
+ keep the others out of sight and use tools like dmenu/xbindkeys and wmctrl to
+ switch instances.
This allows you to use application-specific properties (such as uzbl tag, name etc).
For more ideas on such an approach, see docs/multiple-instances-management.
Examples:
@@ -80,67 +82,96 @@ There are multiple approaches, each with pros and cons.
There are really a lot of options. You need to think about what you need,
what you want and what you don't care about.
+
On the wiki you'll find a lot of related scripts, some of them providing new
-workflows (do you really need open windows for all pages you intend to read, or is a list enough?
-[articlecue](http://www.uzbl.org/wiki/article_queue.py)), some providing integration with WM's such as
-[awesome](http://www.uzbl.org/wiki/awesome), and more.
+workflows (do you really need open windows for all pages you intend to read, or
+is a list enough? [articlequeue](http://www.uzbl.org/wiki/article_queue.py)),
+some providing integration with WMs such as [awesome](http://www.uzbl.org/wiki/awesome),
+and more.
### Okay, what can I actually do? What commands are there? How do I get more information?
- * Commands and other features are documented in README. Read it.
- * You should also peek into the sampleconfigs to see how commands are used in practice.
- * The wiki is also a great resource.
-
-### Why can't I type anything in forms? How does the keybinding work?
-You are in command mode, not in insert mode.
+Commands and other features are documented in README. Read it.
-* command mode: you can trigger actions inside uzbl with minimum amount of keypresses (eg 'b' to go back, 'ZZ' to quit etc) (see config examples), but not to type actual text into forms, because all your keypresses are interpreted.
-* insert mode: after going into insert mode (by default this is the 'i' binding from inside command mode), your keypresses are not interpreted but passed on, so you can enter text into forms. Press Esc to go out of insert mode.
+Other great resources are the example config (~/.uzbl/config/config), the
+scripts included with uzbl, and the wiki.
-The above method is called "modal" as inspired on VI. If you don't like this you can easily change this.
+### Why can't I type anything in forms?
+By default uzbl is modal (like `vi`). It starts in command mode, not in insert
+mode. If you don't like this you can easily change it.
-This method is how many applications work.
-TODO: you can call things from inside insert mode by using modkeys, right?
+When you are in command mode, the left side of the status bar should say `[Cmd]`.
+In command mode you can trigger actions inside uzbl with the minimum amount of
+keypresses, but webpages won't see your keypresses, because they're all being
+interpreted by uzbl.
-
-### Why do you depend on gtk?
-Uzbl itself doesn't use much gtk stuff (only the statusbar) so we could do without gtk. But Webkit needs a widget toolkit to create widgets (think javascript popups, html forms etc).
-Officially, webkit also supportss Qt and wxwigdets. There are also some unofficial patchsets floating on the interwebs for the EFL and FLTK toolkits. One could argue we don't need no popups or fancy form widgets and you could have a point, but
-we prefer being reasonably assured that things work as they are supposed to rather then using some obscure patchset which may be incomplete, broken and/or badly designed, or wasting time ourselves in what is not our core objective.
-That's why we picked the Gtk variant of Webkit.
-Note that we do *not* depend on any Gnome libraries such as gconf. _That_ would be something worth complaining about :)
+After going into insert mode (by default this is the 'i' binding), the status
+bar should say `[Ins]`. Your keypresses are not interpreted but passed on, so
+you can enter text into forms or use keybindings that are interpreted by the
+page's javascript. Press Esc to go out of insert mode.
### Do you support flash? javascript? Ajax? Recent html/css/.. standards? Java/media plugins?
-Yes, Webkit takes care of all of that. Not that we like all of these, but you can use them if you want.
+Yes, Webkit takes care of all of that. Not that we like all of these, but you
+can use them if you want.
+
We use the NPAPI plugin architecture (just like mozilla, opera, etc) so just
install the plugins normally, and things should work.
+### How can I send commands to uzbl from an external script?
+Every uzbl-core process creates a fifo and a socket on the filesystem that you
+can use to communicate with it. By default these are located at
+`/tmp/uzbl_fifo_[name]` and `/tmp/uzbl_socket_[name]`.
+
+The example scripts and keybindings have many examples of this.
+
### What's the difference between the socket file and the fifo?
-They both have advantages and disadvantages:
+Fifos are easy to work with. You can write commands to them like any other file
+into them, but they are unidirectional (you can send uzbl commands, but you
+can't receive responses back from it).
+
+Sockets are bidirectional but more complex. In shell scripts you can use `socat`
+to work with sockets. Other languages have their own ways of connecting and
+writing to sockets.
+
+When writing scripts fifos are usually the fastest method (because you do not need to fork another process), so fifo is preferred unless you need a response.
- * fifo's are _very_ easy to work with. You can write just plaintext commands into them, but they are unidirectional (you can only communicate in one direction)
- * Sockets are bidirectional but more complex. You cannot just write a plaintext string into them. In shellscripts you can use socat to work with sockets, when programming you need to use library functions.
+### Uzbl uses too much memory, especially when multiple windows are open
+It's not as bad as its looks! Linux (and other systems) report memory usage in a confusing way.
-So, when writing scripts, using fifo's is usually the fastest method (because you do not need to fork another process), so fifo is preferred unless you need a response.
+You need to be aware of the difference between RSS and VSS. See
+[this page](http://virtualthreads.blogspot.com/2006/02/understanding-memory-usage-on-linux.html)
+for a good explanation.
-### Uzbl uses too much memory! Especially when having multiple windows (i.e. with uzbl-tabbed)
-Don't be fooled with how memory usage is measured and reported on Linux. (or other systems)
-You need to be aware of the difference between RSS and VSS.
-And dynamic libraries (libwebkit, libgtk, etc) that are used by multiple processes are only stored in RAM once.
-See [this page](http://virtualthreads.blogspot.com/2006/02/understanding-memory-usage-on-linux.html) for a good explanation.
+Dynamic libraries (libwebkit, libgtk, etc) that are used by multiple processes are only stored in RAM once.
### What the hell is this 'XDG' stuff??
-You'll notice our example/default scripts and configs use variables such as `$XDG_CONFIG_HOME` and `$XDG_DATA_HOME`.
-Most of us really like the [xdg basedir spec](http://standards.freedesktop.org/basedir-spec/basedir-spec-latest.html).
-Basically it helps you keeping a clean `$HOME` and it separates config, data and cache.
-If these variables are not defined on your system, it could be that you need to install an xdg package.
-If you don't like this, no one is stopping you from changing the scripts and configs to point to a single `$HOME/.uzbl` directory or whatever you want.
+You'll notice our example/default scripts and configs use variables such as
+`$XDG_CONFIG_HOME` and `$XDG_DATA_HOME`. The are part of the
+[xdg basedir spec][]. The idea is that it keeps your `$HOME` clean and separates
+config, data and cache.
+If these variables are not defined on your system, it could be that you need to
+install an xdg package.
+
+If you don't like this, no one is stopping you from changing the scripts and
+configs to point to a single `$HOME/.uzbl` directory or whatever you want.
### Does the world really need another browser?
We did try a lot of browsers, and we do not suffer [NIH](http://en.wikipedia.org/wiki/Not_Invented_Here).
-We believe that the approach taken by way too many browsers is wrong. We do not want browsers that try to do everything,
-instead we prefer a system where different applications work together, which gives plenty of advantages.
-We also like open source. We take a lot of things from other projects and we also try to contribute to other projects.
+
+We believe that the approach taken by way too many browsers is wrong. We do not
+want browsers that try to do everything, instead we prefer a system where
+different applications work together. We also like having a browser that is
+extensible in whatever language you're most comfortable with.
+
+We also like open source. We take a lot of things from other projects and we
+also try to contribute to other projects.
### What? You call all of this user-friendly?
Yes. If you don't agree, don't use it :)
+
+[dynamic zoom script]: http://www.uzbl.org/wiki/dynamic_zooming
+[uzbl-tabbed]: http://www.uzbl.org/wiki/uzbl_tabbed
+[uzbltreetab]: http://www.uzbl.org/wiki/uzbltreetab
+[uzbltab]: http://www.uzbl.org/wiki/uzbltab
+[suckless tabbed]: http://tools.suckless.org/tabbed
+[xdg basedir spec]: http://standards.freedesktop.org/basedir-spec/basedir-spec-latest.html
diff --git a/examples/config/config b/examples/config/config
index 8c706df..385a60b 100644
--- a/examples/config/config
+++ b/examples/config/config
@@ -83,7 +83,7 @@ set download_handler = sync_spawn @scripts_dir/download.sh
@on_event LOAD_FINISH spawn @scripts_dir/history.sh
# Switch to insert mode if a (editable) html form is clicked
-@on_event FORM_ACTIVE @set_mode insert
+@on_event FOCUS_ELEMENT sh 'if [ "$1" = INPUT -o "$1" = TEXTAREA -o "$1" = SELECT ]; then echo "@set_mode insert" > $UZBL_FIFO; fi' %s
# Switch to command mode if anything else is clicked
@on_event ROOT_ACTIVE @set_mode command
@@ -91,7 +91,7 @@ set download_handler = sync_spawn @scripts_dir/download.sh
#@on_event CONFIG_CHANGED print Config changed: %1 = %2
# Scroll percentage calculation
-@on_event SCROLL_VERT set scroll_message = \@<(function(){var p='--';if(%3<=%4){p=(%1/(%3-%4));p=Math.round(10000*p)/100;};return p+'%';})()>\@
+@on_event SCROLL_VERT set scroll_message = \@<(function(curr, min, max, size){if(max == size) return '--'; var p=(curr/(max - size)); return Math.round(10000*p)/100;})(%1,%2,%3,%4)>\@%
# === Behaviour and appearance ===============================================
@@ -265,8 +265,8 @@ set ebind = @mode_bind global,-insert
@cbind n = search
@cbind N = search_reverse
-# Print pages to a printer
-@cbind  <Ctrl>p = hardcopy
+# Print pages to a printer
+@cbind <Ctrl>p = hardcopy
# Web searching binds
@cbind gg<Google:>_ = uri http://www.google.com/search?q=\@<encodeURIComponent(%r)>\@
@@ -310,7 +310,7 @@ set ebind = @mode_bind global,-insert
# Yanking & pasting binds
@cbind yu = sh 'echo -n "$UZBL_URI" | xclip'
-@cbind yU = sh 'echo -n "$1" | xclip' \@SELECTED_URI
+@cbind yU = sh 'echo -n "$1" | xclip' '\@SELECTED_URI'
@cbind yy = sh 'echo -n "$UZBL_TITLE" | xclip'
# Clone current window
@@ -325,9 +325,9 @@ set ebind = @mode_bind global,-insert
@bind <Shift><Insert> = sh 'echo "event INJECT_KEYCMD $(xclip -o | sed s/\\\@/%40/g)" > "$UZBL_FIFO"'
# Bookmark inserting binds
-@cbind <Ctrl>b<tags:>_ = sh 'echo `printf "$UZBL_URI %s"` >> "$XDG_DATA_HOME"/uzbl/bookmarks'
+@cbind <Ctrl>m<tags:>_ = sh 'echo "$UZBL_URI $1" >> "$XDG_DATA_HOME"/uzbl/bookmarks' '%s'
# Or use a script to insert a bookmark.
-@cbind B = spawn @scripts_dir/insert_bookmark.sh
+@cbind M = spawn @scripts_dir/insert_bookmark.sh
# Bookmark/history loading
@cbind U = spawn @scripts_dir/load_url_from_history.sh
@@ -343,8 +343,10 @@ set follow_hint_keys = 0123456789
#set follow_hint_keys = qwerty
#set follow_hint_keys = asdfghjkl;
#set follow_hint_keys = thsnd-rcgmvwb/;789aefijkopquxyz234
-@cbind fl* = spawn @scripts_dir/follow.sh \@< uzbl.follow("\@follow_hint_keys", "%s", 0) >\@
-@cbind Fl* = spawn @scripts_dir/follow.sh \@< uzbl.follow("\@follow_hint_keys", "%s", 1) >\@
+@cbind fl* = spawn @scripts_dir/follow.sh \@< uzbl.follow("\@follow_hint_keys", "%s", 'click') >\@
+@cbind Fl* = spawn @scripts_dir/follow.sh \@< uzbl.follow("\@follow_hint_keys", "%s", 'newwindow') >\@
+@cbind fL* = spawn @scripts_dir/follow.sh \@< uzbl.follow("\@follow_hint_keys", "%s", 'returnuri') >\@ set
+@cbind FL* = spawn @scripts_dir/follow.sh \@< uzbl.follow("\@follow_hint_keys", "%s", 'returnuri') >\@ clipboard
@cbind fi = spawn @scripts_dir/go_input.sh
# Form filler binds
diff --git a/examples/data/scripts/follow.js b/examples/data/scripts/follow.js
index b7b0d82..5ecdcef 100644
--- a/examples/data/scripts/follow.js
+++ b/examples/data/scripts/follow.js
@@ -16,7 +16,16 @@ uzbldivid = 'uzbl_link_hints';
uzbl.follow = function() {
// Export
charset = arguments[0];
- newwindow = arguments[2];
+ if (arguments[2] == 0 || arguments[2] == 'click') {
+ newwindow = false;
+ returnuri = false;
+ } else if (arguments[2] == 1 || arguments[2] == 'newwindow') {
+ newwindow = true;
+ returnuri = false;
+ } else if (arguments[2] == 'returnuri') {
+ newwindow = false;
+ returnuri = true;
+ }
var keypress = arguments[1];
return arguments.callee.followLinks(keypress);
@@ -126,19 +135,19 @@ uzbl.follow.generateHint = function(doc, el, label, top, left) {
// but at least set the href of the link. (needs some improvements)
uzbl.follow.clickElem = function(item) {
if(!item) return;
- var name = item.tagName;
- if (name == 'INPUT') {
- var type = item.getAttribute('type').toUpperCase();
- if (type == 'TEXT' || type == 'FILE' || type == 'PASSWORD') {
+ if (item instanceof HTMLInputElement) {
+ var type = item.type;
+ if (type == 'text' || type == 'file' || type == 'password') {
item.focus();
item.select();
return "XXXEMIT_FORM_ACTIVEXXX";
}
// otherwise fall through to a simulated mouseclick.
- } else if (name == 'TEXTAREA' || name == 'SELECT') {
+ } else if (item instanceof HTMLTextAreaElement || item instanceof HTMLSelectElement) {
item.focus();
- item.select();
+ if(typeof item.select != 'undefined')
+ item.select();
return "XXXEMIT_FORM_ACTIVEXXX";
}
@@ -169,9 +178,13 @@ uzbl.follow.reDrawHints = function(elems, chars) {
elements.forEach(function(el, i) {
var label = labels[i];
var pos = positions[i];
- var doc = uzbl.follow.getDocument(el);
- var h = uzbl.follow.generateHint(doc, el, label, pos[0], pos[1]);
- doc.hintdiv.appendChild(h);
+ try {
+ var doc = uzbl.follow.getDocument(el);
+ var h = uzbl.follow.generateHint(doc, el, label, pos[0], pos[1]);
+ doc.hintdiv.appendChild(h);
+ } catch (err) {
+ // Unable to attach label -> shrug it off and continue
+ }
});
}
@@ -222,7 +235,7 @@ uzbl.follow.followLinks = function(follow) {
//var desc = '*[title], img[alt], applet[alt], area[alt], input[alt]';
//var image = 'img, input[type=image]';
- if(newwindow)
+ if(newwindow || returnuri)
var res = this.query(uri);
else
var res = this.query(followable);
@@ -237,6 +250,11 @@ uzbl.follow.followLinks = function(follow) {
// clear all of our hints
this.clearHints();
+ if (returnuri) {
+ var uri = el.src || el.href;
+ return "XXXRETURNED_URIXXX" + uri
+ }
+
if (newwindow) {
// we're opening a new window using the URL attached to this element
var uri = el.src || el.href;
diff --git a/examples/data/scripts/follow.sh b/examples/data/scripts/follow.sh
index 014793e..30d3775 100755
--- a/examples/data/scripts/follow.sh
+++ b/examples/data/scripts/follow.sh
@@ -1,13 +1,31 @@
#!/bin/sh
# This scripts acts on the return value of followLinks in follow.js
-case "$1" in
+result=$1
+shift
+
+uriaction=$1
+shift
+
+case "$result" in
XXXEMIT_FORM_ACTIVEXXX)
# a form element was selected
- printf 'event FORM_ACTIVE\nevent KEYCMD_CLEAR\n' > "$UZBL_FIFO"
+ printf 'event KEYCMD_CLEAR\n' > "$UZBL_FIFO"
;;
XXXRESET_MODEXXX)
# a link was selected, reset uzbl's input mode
printf 'set mode=\nevent KEYCMD_CLEAR\n' > "$UZBL_FIFO"
;;
+ XXXRETURNED_URIXXX*)
+ uri=${result#XXXRETURNED_URIXXX}
+
+ case "$uriaction" in
+ set)
+ printf 'uri '"$uri"'\n' | sed -e 's/@/\\@/' > "$UZBL_FIFO"
+ ;;
+ clipboard)
+ printf "$uri" | xclip
+ ;;
+ esac
+ printf 'set mode=\nevent KEYCMD_CLEAR\n' > "$UZBL_FIFO"
esac
diff --git a/examples/data/scripts/formfiller.js b/examples/data/scripts/formfiller.js
index abf0162..a5fc9ee 100644
--- a/examples/data/scripts/formfiller.js
+++ b/examples/data/scripts/formfiller.js
@@ -1,24 +1,37 @@
uzbl.formfiller = {
+ inputTypeIsText: function(type) {
+ var types = [ 'text', 'password', 'search', 'email', 'url',
+ 'number', 'range', 'color', 'date', 'month',
+ 'week', 'time', 'datetime', 'datetime-local' ];
+
+ for(var i = 0; i < types.length; ++i)
+ if(types[i] == type) return true;
+
+ return false;
+ }
+
+ ,
+
dump: function() {
var rv = '';
var allFrames = new Array(window);
- for ( f=0; f<window.frames.length; ++f ) {
+
+ for ( var f = 0; f < window.frames.length; ++f ) {
allFrames.push(window.frames[f]);
}
- for ( j=0; j<allFrames.length; ++j ) {
+
+ for ( var j = 0; j < allFrames.length; ++j ) {
try {
var xp_res = allFrames[j].document.evaluate(
'//input', allFrames[j].document.documentElement, null, XPathResult.ANY_TYPE,null
);
var input;
while ( input = xp_res.iterateNext() ) {
- var type = (input.type?input.type:text);
- if ( type == 'text' || type == 'password' || type == 'search' ) {
- rv += '%' + escape(input.name) + '(' + type + '):' + input.value + '\n';
- }
- else if ( type == 'checkbox' || type == 'radio' ) {
- rv += '%' + escape(input.name) + '(' + type + '){' + escape(input.value) + '}:' + (input.checked?'1':'0') + '\n';
+ if ( inputTypeIsText(input.type) ) {
+ rv += '%' + escape(input.name) + '(' + input.type + '):' + input.value + '\n';
+ } else if ( input.type == 'checkbox' || input.type == 'radio' ) {
+ rv += '%' + escape(input.name) + '(' + input.type + '){' + escape(input.value) + '}:' + (input.checked?'1':'0') + '\n';
}
}
xp_res = allFrames[j].document.evaluate(
@@ -39,12 +52,12 @@ uzbl.formfiller = {
insert: function(fname, ftype, fvalue, fchecked) {
fname = unescape(fname);
var allFrames = new Array(window);
- for ( f=0; f<window.frames.length; ++f ) {
+ for ( var f = 0; f < window.frames.length; ++f ) {
allFrames.push(window.frames[f]);
}
- for ( j=0; j<allFrames.length; ++j ) {
+ for ( var j = 0; j < allFrames.length; ++j ) {
try {
- if ( ftype == 'text' || ftype == 'password' || ftype == 'search' || ftype == 'textarea' ) {
+ if ( uzbl.formfiller.inputTypeIsText(ftype) || ftype == 'textarea' ) {
allFrames[j].document.getElementsByName(fname)[0].value = fvalue;
}
else if ( ftype == 'checkbox' ) {
diff --git a/examples/data/scripts/formfiller.sh b/examples/data/scripts/formfiller.sh
index c1171a0..394bfbd 100755
--- a/examples/data/scripts/formfiller.sh
+++ b/examples/data/scripts/formfiller.sh
@@ -39,7 +39,10 @@ GenForm ()
GetOption ()
{
DMENU_SCHEME=formfiller
- DMENU_PROMPT="choose profile"
+
+ # util/dmenu.sh doesn't handle spaces in DMENU_PROMPT. a proper fix will be
+ # tricky.
+ DMENU_PROMPT="choose_profile"
DMENU_LINES=4
. "$UZBL_UTIL_DIR/dmenu.sh"
@@ -66,11 +69,7 @@ ParseFields ()
field = $0
sub ( /[^:]*:/, "", field )
- if ( parts[2] ~ /^(text|password|search)$/ )
- printf( "js uzbl.formfiller.insert(\"%s\",\"%s\",\"%s\",0);\n",
- parts[1], parts[2], field )
-
- else if ( parts[2] ~ /^(checkbox|radio)$/ )
+ if ( parts[2] ~ /^(checkbox|radio)$/ )
printf( "js uzbl.formfiller.insert(\"%s\",\"%s\",\"%s\",%s);\n",
parts[1], parts[2], parts[3], field )
@@ -87,6 +86,11 @@ ParseFields ()
parts[1], parts[2], field )
}
+ else
+ printf( "js uzbl.formfiller.insert(\"%s\",\"%s\",\"%s\",0);\n",
+ parts[1], parts[2], field )
+
+
}'
}
diff --git a/examples/data/scripts/util/uzbl-dir.sh b/examples/data/scripts/util/uzbl-dir.sh
index 82510d8..76a7055 100644
--- a/examples/data/scripts/util/uzbl-dir.sh
+++ b/examples/data/scripts/util/uzbl-dir.sh
@@ -9,12 +9,12 @@ UZBL_SOCKET_DIR=/tmp
# Directories
UZBL_DOWNLOAD_DIR="${XDG_DOWNLOAD_DIR:-$HOME}"
-UZBL_FORMS_DIR="$UZBL_DATA_DIR/dforms"
+UZBL_FORMS_DIR="${UZBL_FORMS_DIR:-$UZBL_DATA_DIR/dforms}"
# Data files
-UZBL_CONFIG_FILE="$UZBL_CONFIG_DIR/config"
-UZBL_COOKIE_FILE="$UZBL_DATA_DIR/cookies.txt"
-UZBL_BOOKMARKS_FILE="$UZBL_DATA_DIR/bookmarks"
-UZBL_TEMPS_FILE="$UZBL_DATA_DIR/temps"
-UZBL_HISTORY_FILE="$UZBL_DATA_DIR/history"
-UZBL_SESSION_FILE="$UZBL_DATA_DIR/browser-session"
+UZBL_CONFIG_FILE="${UZBL_CONFIG_FILE:-$UZBL_CONFIG_DIR/config}"
+UZBL_COOKIE_FILE="${UZBL_COOKIE_FILE:-$UZBL_DATA_DIR/cookies.txt}"
+UZBL_BOOKMARKS_FILE="${UZBL_BOOKMARKS_FILE:-$UZBL_DATA_DIR/bookmarks}"
+UZBL_TEMPS_FILE="${UZBL_TEMPS_FILE:-$UZBL_DATA_DIR/temps}"
+UZBL_HISTORY_FILE="${UZBL_HISTORY_FILE:-$UZBL_DATA_DIR/history}"
+UZBL_SESSION_FILE="${UZBL_SESSION_FILE:-$UZBL_DATA_DIR/browser-session}"
diff --git a/misc/hash.sh b/misc/hash.sh
index 0c97722..3590981 100755
--- a/misc/hash.sh
+++ b/misc/hash.sh
@@ -1,20 +1,18 @@
#!/bin/sh
-# script to determine git hash of current source tree
+# script to determine git hash and latest tag of current source tree
-# set a variable when running `git --archive <hash/tag>` (this is what github does)
+# set a variable when running `git archive <hash/tag>` (this is what github does)
# alternatively, you could also git get-tar-commit-id < tarball (but that's a bit dirtier)
-FROM_ARCHIVE=$Format:%H$
+
+# the `%` expansions possible here are described in `man git-log`
+FROM_ARCHIVE=$Format:%h$
# ... but try to use whatever git tells us if there is a .git folder
if [ -d .git -a -r .git ]
then
- hash=$(git log 2>/dev/null | head -n1 2>/dev/null | sed "s/.* //" 2>/dev/null)
-fi
-
-if [ x"$hash" != x ]
-then
- echo $hash
-elif [ "$FROM_ARCHIVE" != ':%H$' ]
+ hash=$(git describe --tags)
+ echo $hash
+elif [ "$FROM_ARCHIVE" != ':%h$' ]
then
echo $FROM_ARCHIVE
else
diff --git a/src/callbacks.c b/src/callbacks.c
index 3f7e27d..446e868 100644
--- a/src/callbacks.c
+++ b/src/callbacks.c
@@ -6,429 +6,30 @@
#include "uzbl-core.h"
#include "callbacks.h"
#include "events.h"
-#include "util.h"
-#include "io.h"
-
-
-void
-set_proxy_url() {
- SoupURI *suri;
-
- if (uzbl.net.proxy_url == NULL || *uzbl.net.proxy_url == ' ') {
- soup_session_remove_feature_by_type(uzbl.net.soup_session,
- (GType) SOUP_SESSION_PROXY_URI);
- }
- else {
- suri = soup_uri_new(uzbl.net.proxy_url);
- g_object_set(G_OBJECT(uzbl.net.soup_session),
- SOUP_SESSION_PROXY_URI,
- suri, NULL);
- soup_uri_free(suri);
- }
-
- return;
-}
-
-
-void
-set_authentication_handler() {
- /* Check if WEBKIT_TYPE_SOUP_AUTH_DIALOG feature is set */
- GSList *flist = soup_session_get_features (uzbl.net.soup_session, (GType) WEBKIT_TYPE_SOUP_AUTH_DIALOG);
- guint feature_is_set = g_slist_length(flist);
- g_slist_free(flist);
-
- if (uzbl.behave.authentication_handler == NULL || *uzbl.behave.authentication_handler == 0) {
- if (!feature_is_set)
- soup_session_add_feature_by_type
- (uzbl.net.soup_session, (GType) WEBKIT_TYPE_SOUP_AUTH_DIALOG);
- } else {
- if (feature_is_set)
- soup_session_remove_feature_by_type
- (uzbl.net.soup_session, (GType) WEBKIT_TYPE_SOUP_AUTH_DIALOG);
- }
- return;
-}
-
-
-void
-set_status_background() {
- /* labels and hboxes do not draw their own background. applying this
- * on the vbox/main_window is ok as the statusbar is the only affected
- * widget. (if not, we could also use GtkEventBox) */
- GtkWidget* widget = uzbl.gui.main_window ? uzbl.gui.main_window : GTK_WIDGET (uzbl.gui.plug);
-
-#if GTK_CHECK_VERSION(2,91,0)
- GdkRGBA color;
- gdk_rgba_parse (&color, uzbl.behave.status_background);
- gtk_widget_override_background_color (widget, GTK_STATE_NORMAL, &color);
-#else
- GdkColor color;
- gdk_color_parse (uzbl.behave.status_background, &color);
- gtk_widget_modify_bg (widget, GTK_STATE_NORMAL, &color);
-#endif
-}
-
-
-void
-set_icon() {
- if(file_exists(uzbl.gui.icon)) {
- if (uzbl.gui.main_window)
- gtk_window_set_icon_from_file (GTK_WINDOW (uzbl.gui.main_window), uzbl.gui.icon, NULL);
- } else {
- g_printerr ("Icon \"%s\" not found. ignoring.\n", uzbl.gui.icon);
- }
-}
-
-void
-cmd_set_geometry() {
- int ret=0, x=0, y=0;
- unsigned int w=0, h=0;
- if(uzbl.gui.geometry) {
- if(uzbl.gui.geometry[0] == 'm') { /* m/maximize/maximized */
- gtk_window_maximize((GtkWindow *)(uzbl.gui.main_window));
- } else {
- /* we used to use gtk_window_parse_geometry() but that didn't work how it was supposed to */
- ret = XParseGeometry(uzbl.gui.geometry, &x, &y, &w, &h);
- if(ret & XValue)
- gtk_window_move((GtkWindow *)uzbl.gui.main_window, x, y);
- if(ret & WidthValue)
- gtk_window_resize((GtkWindow *)uzbl.gui.main_window, w, h);
- }
- }
-
- /* update geometry var with the actual geometry
- this is necessary as some WMs don't seem to honour
- the above setting and we don't want to end up with
- wrong geometry information
- */
- retrieve_geometry();
-}
-
-void
-cmd_set_status() {
- if (!uzbl.behave.show_status) {
- gtk_widget_hide(uzbl.gui.mainbar);
- } else {
- gtk_widget_show(uzbl.gui.mainbar);
- }
- update_title();
-}
-
-void
-cmd_load_uri() {
- load_uri_imp (uzbl.state.uri);
-}
-
-void
-cmd_max_conns() {
- g_object_set(G_OBJECT(uzbl.net.soup_session),
- SOUP_SESSION_MAX_CONNS, uzbl.net.max_conns, NULL);
-}
-
-void
-cmd_max_conns_host() {
- g_object_set(G_OBJECT(uzbl.net.soup_session),
- SOUP_SESSION_MAX_CONNS_PER_HOST, uzbl.net.max_conns_host, NULL);
-}
-
-void
-cmd_http_debug() {
- soup_session_remove_feature
- (uzbl.net.soup_session, SOUP_SESSION_FEATURE(uzbl.net.soup_logger));
- /* do we leak if this doesn't get freed? why does it occasionally crash if freed? */
- /*g_free(uzbl.net.soup_logger);*/
-
- uzbl.net.soup_logger = soup_logger_new(uzbl.behave.http_debug, -1);
- soup_session_add_feature(uzbl.net.soup_session,
- SOUP_SESSION_FEATURE(uzbl.net.soup_logger));
-}
-
-WebKitWebSettings*
-view_settings() {
- return webkit_web_view_get_settings(uzbl.gui.web_view);
-}
-
-void
-cmd_font_size() {
- WebKitWebSettings *ws = view_settings();
- if (uzbl.behave.font_size > 0) {
- g_object_set (G_OBJECT(ws), "default-font-size", uzbl.behave.font_size, NULL);
- }
-
- if (uzbl.behave.monospace_size > 0) {
- g_object_set (G_OBJECT(ws), "default-monospace-font-size",
- uzbl.behave.monospace_size, NULL);
- } else {
- g_object_set (G_OBJECT(ws), "default-monospace-font-size",
- uzbl.behave.font_size, NULL);
- }
-}
-
-void
-cmd_default_font_family() {
- g_object_set (G_OBJECT(view_settings()), "default-font-family",
- uzbl.behave.default_font_family, NULL);
-}
-
-void
-cmd_monospace_font_family() {
- g_object_set (G_OBJECT(view_settings()), "monospace-font-family",
- uzbl.behave.monospace_font_family, NULL);
-}
-
-void
-cmd_sans_serif_font_family() {
- g_object_set (G_OBJECT(view_settings()), "sans_serif-font-family",
- uzbl.behave.sans_serif_font_family, NULL);
-}
-
-void
-cmd_serif_font_family() {
- g_object_set (G_OBJECT(view_settings()), "serif-font-family",
- uzbl.behave.serif_font_family, NULL);
-}
-
-void
-cmd_cursive_font_family() {
- g_object_set (G_OBJECT(view_settings()), "cursive-font-family",
- uzbl.behave.cursive_font_family, NULL);
-}
-
-void
-cmd_fantasy_font_family() {
- g_object_set (G_OBJECT(view_settings()), "fantasy-font-family",
- uzbl.behave.fantasy_font_family, NULL);
-}
-
-void
-cmd_zoom_level() {
- webkit_web_view_set_zoom_level (uzbl.gui.web_view, uzbl.behave.zoom_level);
-}
-
-void
-cmd_enable_pagecache() {
- g_object_set (G_OBJECT(view_settings()), "enable-page-cache",
- uzbl.behave.enable_pagecache, NULL);
-}
-
-void
-cmd_disable_plugins() {
- g_object_set (G_OBJECT(view_settings()), "enable-plugins",
- !uzbl.behave.disable_plugins, NULL);
-}
-
-void
-cmd_disable_scripts() {
- g_object_set (G_OBJECT(view_settings()), "enable-scripts",
- !uzbl.behave.disable_scripts, NULL);
-}
-
-void
-cmd_minimum_font_size() {
- g_object_set (G_OBJECT(view_settings()), "minimum-font-size",
- uzbl.behave.minimum_font_size, NULL);
-}
-void
-cmd_autoload_img() {
- g_object_set (G_OBJECT(view_settings()), "auto-load-images",
- uzbl.behave.autoload_img, NULL);
-}
-
-
-void
-cmd_autoshrink_img() {
- g_object_set (G_OBJECT(view_settings()), "auto-shrink-images",
- uzbl.behave.autoshrink_img, NULL);
-}
-
-
-void
-cmd_enable_spellcheck() {
- g_object_set (G_OBJECT(view_settings()), "enable-spell-checking",
- uzbl.behave.enable_spellcheck, NULL);
-}
-
-void
-cmd_enable_private() {
- g_object_set (G_OBJECT(view_settings()), "enable-private-browsing",
- uzbl.behave.enable_private, NULL);
-}
-
-void
-cmd_print_bg() {
- g_object_set (G_OBJECT(view_settings()), "print-backgrounds",
- uzbl.behave.print_bg, NULL);
-}
-
-void
-cmd_style_uri() {
- g_object_set (G_OBJECT(view_settings()), "user-stylesheet-uri",
- uzbl.behave.style_uri, NULL);
-}
-
-void
-cmd_resizable_txt() {
- g_object_set (G_OBJECT(view_settings()), "resizable-text-areas",
- uzbl.behave.resizable_txt, NULL);
-}
+#include "menu.h"
+#include "type.h"
void
-cmd_default_encoding() {
- g_object_set (G_OBJECT(view_settings()), "default-encoding",
- uzbl.behave.default_encoding, NULL);
-}
-
-void
-cmd_enforce_96dpi() {
- g_object_set (G_OBJECT(view_settings()), "enforce-96-dpi",
- uzbl.behave.enforce_96dpi, NULL);
-}
-
-void
-cmd_caret_browsing() {
- g_object_set (G_OBJECT(view_settings()), "enable-caret-browsing",
- uzbl.behave.caret_browsing, NULL);
-}
-
-void
-set_current_encoding() {
- gchar *encoding = uzbl.behave.current_encoding;
- if(strlen(encoding) == 0)
- encoding = NULL;
-
- webkit_web_view_set_custom_encoding(uzbl.gui.web_view, encoding);
-}
-
-
-void
-cmd_fifo_dir() {
- uzbl.behave.fifo_dir = init_fifo(uzbl.behave.fifo_dir);
-}
-
-void
-cmd_socket_dir() {
- uzbl.behave.socket_dir = init_socket(uzbl.behave.socket_dir);
-}
-
-void
-cmd_inject_html() {
- if(uzbl.behave.inject_html) {
- webkit_web_view_load_html_string (uzbl.gui.web_view,
- uzbl.behave.inject_html, NULL);
- }
-}
-
-void
-cmd_useragent() {
- if (*uzbl.net.useragent == ' ') {
- g_free (uzbl.net.useragent);
- uzbl.net.useragent = NULL;
- } else {
- g_object_set(G_OBJECT(uzbl.net.soup_session), SOUP_SESSION_USER_AGENT,
- uzbl.net.useragent, NULL);
- }
-}
-
-void
-set_accept_languages() {
- if (*uzbl.net.accept_languages == ' ') {
- g_free (uzbl.net.accept_languages);
- uzbl.net.accept_languages = NULL;
- } else {
- g_object_set(G_OBJECT(uzbl.net.soup_session),
- SOUP_SESSION_ACCEPT_LANGUAGE, uzbl.net.accept_languages, NULL);
- }
-}
-
-void
-cmd_javascript_windows() {
- g_object_set (G_OBJECT(view_settings()), "javascript-can-open-windows-automatically",
- uzbl.behave.javascript_windows, NULL);
-}
-
-void
-cmd_scrollbars_visibility() {
- if(uzbl.gui.scrollbars_visible) {
- uzbl.gui.bar_h = gtk_scrolled_window_get_hadjustment (GTK_SCROLLED_WINDOW (uzbl.gui.scrolled_win));
- uzbl.gui.bar_v = gtk_scrolled_window_get_vadjustment (GTK_SCROLLED_WINDOW (uzbl.gui.scrolled_win));
- }
- else {
- uzbl.gui.bar_v = gtk_range_get_adjustment (GTK_RANGE (uzbl.gui.scbar_v));
- uzbl.gui.bar_h = gtk_range_get_adjustment (GTK_RANGE (uzbl.gui.scbar_h));
- }
-
- set_webview_scroll_adjustments();
-}
-
-/* requires webkit >=1.1.14 */
-void
-cmd_view_source() {
- webkit_web_view_set_view_source_mode(uzbl.gui.web_view,
- (gboolean) uzbl.behave.view_source);
-}
-
-void
-cmd_set_zoom_type () {
- if(uzbl.behave.zoom_type)
- webkit_web_view_set_full_content_zoom (uzbl.gui.web_view, TRUE);
- else
- webkit_web_view_set_full_content_zoom (uzbl.gui.web_view, FALSE);
-}
-
-void
-toggle_zoom_type (WebKitWebView* page, GArray *argv, GString *result) {
- (void)argv;
- (void)result;
-
- webkit_web_view_set_full_content_zoom (page, !webkit_web_view_get_full_content_zoom (page));
-}
-
-void
-toggle_status_cb (WebKitWebView* page, GArray *argv, GString *result) {
- (void)page;
- (void)argv;
- (void)result;
-
- if (uzbl.behave.show_status) {
- gtk_widget_hide(uzbl.gui.mainbar);
- } else {
- gtk_widget_show(uzbl.gui.mainbar);
- }
- uzbl.behave.show_status = !uzbl.behave.show_status;
- update_title();
-}
-
-void
-link_hover_cb (WebKitWebView* page, const gchar* title, const gchar* link, gpointer data) {
- (void) page;
- (void) title;
- (void) data;
+link_hover_cb (WebKitWebView *page, const gchar *title, const gchar *link, gpointer data) {
+ (void) page; (void) title; (void) data;
State *s = &uzbl.state;
+ if(s->last_selected_url)
+ g_free(s->last_selected_url);
+
if(s->selected_url) {
- if(s->last_selected_url)
- g_free(s->last_selected_url);
s->last_selected_url = g_strdup(s->selected_url);
- }
- else {
- if(s->last_selected_url) g_free(s->last_selected_url);
+ g_free(s->selected_url);
+ s->selected_url = NULL;
+ } else
s->last_selected_url = NULL;
- }
- g_free(s->selected_url);
- s->selected_url = NULL;
+ if(s->last_selected_url && g_strcmp0(link, s->last_selected_url))
+ send_event(LINK_UNHOVER, NULL, TYPE_STR, s->last_selected_url, NULL);
if (link) {
s->selected_url = g_strdup(link);
-
- if(s->last_selected_url &&
- g_strcmp0(s->selected_url, s->last_selected_url))
- send_event(LINK_UNHOVER, NULL, TYPE_STR, s->last_selected_url, NULL);
-
- send_event(LINK_HOVER, NULL, TYPE_STR, s->selected_url, NULL);
- }
- else if(s->last_selected_url) {
- send_event(LINK_UNHOVER, NULL, TYPE_STR, s->last_selected_url, NULL);
+ send_event(LINK_HOVER, NULL, TYPE_STR, s->selected_url, NULL);
}
update_title();
@@ -478,7 +79,7 @@ load_status_change_cb (WebKitWebView* web_view, GParamSpec param_spec) {
}
}
-void
+gboolean
load_error_cb (WebKitWebView* page, WebKitWebFrame* frame, gchar *uri, gpointer web_err, gpointer ud) {
(void) page; (void) frame; (void) ud;
GError *err = web_err;
@@ -488,15 +89,8 @@ load_error_cb (WebKitWebView* page, WebKitWebFrame* frame, gchar *uri, gpointer
TYPE_INT, err->code,
TYPE_STR, err->message,
NULL);
-}
-
-void
-uri_change_cb (WebKitWebView *web_view, GParamSpec param_spec) {
- (void) param_spec;
- g_free (uzbl.state.uri);
- g_object_get (web_view, "uri", &uzbl.state.uri, NULL);
- g_setenv("UZBL_URI", uzbl.state.uri, TRUE);
+ return FALSE;
}
void
@@ -767,10 +361,11 @@ request_starting_cb(WebKitWebView *web_view, WebKitWebFrame *frame, WebKitWebRes
}
void
-create_web_view_js2_cb (WebKitWebView* web_view, GParamSpec param_spec) {
+create_web_view_js_cb (WebKitWebView* web_view, GParamSpec param_spec) {
(void) web_view;
(void) param_spec;
+ webkit_web_view_stop_loading(web_view);
const gchar* uri = webkit_web_view_get_uri(web_view);
if (strncmp(uri, "javascript:", strlen("javascript:")) == 0) {
@@ -781,18 +376,6 @@ create_web_view_js2_cb (WebKitWebView* web_view, GParamSpec param_spec) {
send_event(NEW_WINDOW, NULL, TYPE_STR, uri, NULL);
}
-
-gboolean
-create_web_view_js_cb (WebKitWebView* web_view, gpointer user_data) {
- (void) web_view;
- (void) user_data;
-
- g_object_connect (web_view, "signal::notify::uri",
- G_CALLBACK(create_web_view_js2_cb), NULL, NULL);
- return TRUE;
-}
-
-
/*@null@*/ WebKitWebView*
create_web_view_cb (WebKitWebView *web_view, WebKitWebFrame *frame, gpointer user_data) {
(void) web_view;
@@ -804,8 +387,8 @@ create_web_view_cb (WebKitWebView *web_view, WebKitWebFrame *frame, gpointer us
WebKitWebView* new_view = WEBKIT_WEB_VIEW(webkit_web_view_new());
- g_signal_connect (new_view, "web-view-ready",
- G_CALLBACK(create_web_view_js_cb), NULL);
+ g_object_connect (new_view, "signal::notify::uri",
+ G_CALLBACK(create_web_view_js_cb), NULL, NULL);
return new_view;
}
@@ -953,43 +536,32 @@ download_cb(WebKitWebView *web_view, WebKitDownload *download, gpointer user_dat
return TRUE;
}
-gboolean
-scroll_vert_cb(GtkAdjustment *adjust, void *w)
-{
- (void) w;
-
+void
+send_scroll_event(int type, GtkAdjustment *adjust) {
gdouble value = gtk_adjustment_get_value(adjust);
gdouble min = gtk_adjustment_get_lower(adjust);
gdouble max = gtk_adjustment_get_upper(adjust);
gdouble page = gtk_adjustment_get_page_size(adjust);
- send_event (SCROLL_VERT, NULL,
+ send_event (type, NULL,
TYPE_FLOAT, value,
TYPE_FLOAT, min,
TYPE_FLOAT, max,
TYPE_FLOAT, page,
NULL);
+}
+gboolean
+scroll_vert_cb(GtkAdjustment *adjust, void *w) {
+ (void) w;
+ send_scroll_event(SCROLL_VERT, adjust);
return (FALSE);
}
gboolean
-scroll_horiz_cb(GtkAdjustment *adjust, void *w)
-{
+scroll_horiz_cb(GtkAdjustment *adjust, void *w) {
(void) w;
-
- gdouble value = gtk_adjustment_get_value(adjust);
- gdouble min = gtk_adjustment_get_lower(adjust);
- gdouble max = gtk_adjustment_get_upper(adjust);
- gdouble page = gtk_adjustment_get_page_size(adjust);
-
- send_event (SCROLL_HORIZ, NULL,
- TYPE_FLOAT, value,
- TYPE_FLOAT, min,
- TYPE_FLOAT, max,
- TYPE_FLOAT, page,
- NULL);
-
+ send_scroll_event(SCROLL_HORIZ, adjust);
return (FALSE);
}
@@ -1079,4 +651,38 @@ populate_popup_cb(WebKitWebView *v, GtkMenu *m, void *c) {
}
}
+void
+window_object_cleared_cb(WebKitWebView *webview, WebKitWebFrame *frame,
+ JSGlobalContextRef *context, JSObjectRef *object) {
+ (void) frame; (void) context; (void) object;
+#if WEBKIT_CHECK_VERSION (1, 3, 13)
+ // Take this opportunity to set some callbacks on the DOM
+ WebKitDOMDocument *document = webkit_web_view_get_dom_document (webview);
+ webkit_dom_event_target_add_event_listener (WEBKIT_DOM_EVENT_TARGET (document),
+ "focus", G_CALLBACK(dom_focus_cb), TRUE, NULL);
+ webkit_dom_event_target_add_event_listener (WEBKIT_DOM_EVENT_TARGET (document),
+ "blur", G_CALLBACK(dom_focus_cb), TRUE, NULL);
+#else
+ (void) webview;
+#endif
+}
+
+#if WEBKIT_CHECK_VERSION (1, 3, 13)
+void
+dom_focus_cb(WebKitDOMEventTarget *target, WebKitDOMEvent *event, gpointer user_data) {
+ (void) target; (void) user_data;
+ WebKitDOMEventTarget *etarget = webkit_dom_event_get_target (event);
+ gchar* name = webkit_dom_node_get_node_name (WEBKIT_DOM_NODE (etarget));
+ send_event (FOCUS_ELEMENT, NULL, TYPE_STR, name, NULL);
+}
+
+void
+dom_blur_cb(WebKitDOMEventTarget *target, WebKitDOMEvent *event, gpointer user_data) {
+ (void) target; (void) user_data;
+ WebKitDOMEventTarget *etarget = webkit_dom_event_get_target (event);
+ gchar* name = webkit_dom_node_get_node_name (WEBKIT_DOM_NODE (etarget));
+ send_event (BLUR_ELEMENT, NULL, TYPE_STR, name, NULL);
+}
+#endif
+
/* vi: set et ts=4: */
diff --git a/src/callbacks.h b/src/callbacks.h
index d34b9fa..e9240b5 100644
--- a/src/callbacks.h
+++ b/src/callbacks.h
@@ -4,148 +4,6 @@
*/
void
-cmd_load_uri();
-
-void
-cmd_set_status();
-
-void
-set_proxy_url();
-
-void
-set_authentication_handler();
-
-void
-set_status_background();
-
-void
-set_icon();
-
-void
-move_statusbar();
-
-void
-cmd_http_debug();
-
-void
-cmd_max_conns();
-
-void
-cmd_max_conns_host();
-
-/* exported WebKitWebSettings properties */
-void
-cmd_font_size();
-
-void
-cmd_default_font_family();
-
-void
-cmd_monospace_font_family();
-
-void
-cmd_sans_serif_font_family();
-
-void
-cmd_serif_font_family();
-
-void
-cmd_cursive_font_family();
-
-void
-cmd_fantasy_font_family();
-
-void
-cmd_zoom_level();
-
-void
-cmd_set_zoom_type();
-
-void
-cmd_enable_pagecache();
-
-void
-cmd_disable_plugins();
-
-void
-cmd_disable_scripts();
-
-void
-cmd_minimum_font_size();
-
-void
-cmd_fifo_dir();
-
-void
-cmd_socket_dir();
-
-void
-cmd_useragent() ;
-
-void
-set_accept_languages();
-
-void
-cmd_autoload_img();
-
-void
-cmd_autoshrink_img();
-
-void
-cmd_enable_spellcheck();
-
-void
-cmd_enable_private();
-
-void
-cmd_print_bg();
-
-void
-cmd_style_uri();
-
-void
-cmd_resizable_txt();
-
-void
-cmd_default_encoding();
-
-void
-set_current_encoding();
-
-void
-cmd_enforce_96dpi();
-
-void
-cmd_inject_html();
-
-void
-cmd_caret_browsing();
-
-void
-cmd_javascript_windows();
-
-void
-cmd_set_geometry();
-
-void
-cmd_view_source();
-
-void
-cmd_scrollbars_visibility();
-
-void
-cmd_load_start();
-
-WebKitWebSettings*
-view_settings();
-
-void
-toggle_zoom_type (WebKitWebView* page, GArray *argv, GString *result);
-
-void
-toggle_status_cb (WebKitWebView* page, GArray *argv, GString *result);
-
-void
link_hover_cb (WebKitWebView* page, const gchar* title, const gchar* link, gpointer data);
void
@@ -157,13 +15,10 @@ progress_change_cb (WebKitWebView* web_view, GParamSpec param_spec);
void
load_status_change_cb (WebKitWebView* web_view, GParamSpec param_spec);
-void
+gboolean
load_error_cb (WebKitWebView* page, WebKitWebFrame* frame, gchar *uri, gpointer web_err, gpointer ud);
void
-uri_change_cb (WebKitWebView *web_view, GParamSpec param_spec);
-
-void
selection_changed_cb(WebKitWebView *webkitwebview, gpointer ud);
void
@@ -222,3 +77,15 @@ scroll_vert_cb(GtkAdjustment *adjust, void *w);
gboolean
scroll_horiz_cb(GtkAdjustment *adjust, void *w);
+
+void
+window_object_cleared_cb(WebKitWebView *webview, WebKitWebFrame *frame,
+ JSGlobalContextRef *context, JSObjectRef *object);
+
+#if WEBKIT_CHECK_VERSION (1, 3, 13)
+void
+dom_focus_cb(WebKitDOMEventTarget *target, WebKitDOMEvent *event, gpointer user_data);
+
+void
+dom_blur_cb(WebKitDOMEventTarget *target, WebKitDOMEvent *event, gpointer user_data);
+#endif
diff --git a/src/commands.c b/src/commands.c
new file mode 100644
index 0000000..cd1f872
--- /dev/null
+++ b/src/commands.c
@@ -0,0 +1,452 @@
+#include "commands.h"
+#include "uzbl-core.h"
+#include "events.h"
+#include "util.h"
+#include "menu.h"
+#include "callbacks.h"
+#include "variables.h"
+#include "type.h"
+
+/* -- command to callback/function map for things we cannot attach to any signals */
+CommandInfo cmdlist[] =
+{ /* key function no_split */
+ { "back", view_go_back, 0 },
+ { "forward", view_go_forward, 0 },
+ { "scroll", scroll_cmd, 0 },
+ { "reload", view_reload, 0 },
+ { "reload_ign_cache", view_reload_bypass_cache, 0 },
+ { "stop", view_stop_loading, 0 },
+ { "zoom_in", view_zoom_in, 0 }, //Can crash (when max zoom reached?).
+ { "zoom_out", view_zoom_out, 0 },
+ { "toggle_zoom_type", toggle_zoom_type, 0 },
+ { "uri", load_uri, TRUE },
+ { "js", run_js, TRUE },
+ { "script", run_external_js, 0 },
+ { "toggle_status", toggle_status, 0 },
+ { "spawn", spawn_async, 0 },
+ { "sync_spawn", spawn_sync, 0 },
+ { "sync_spawn_exec", spawn_sync_exec, 0 }, // needed for load_cookies.sh :(
+ { "sh", spawn_sh_async, 0 },
+ { "sync_sh", spawn_sh_sync, 0 },
+ { "exit", close_uzbl, 0 },
+ { "search", search_forward_text, TRUE },
+ { "search_reverse", search_reverse_text, TRUE },
+ { "search_clear", search_clear, TRUE },
+ { "dehilight", dehilight, 0 },
+ { "set", set_var, TRUE },
+ { "dump_config", act_dump_config, 0 },
+ { "dump_config_as_events", act_dump_config_as_events, 0 },
+ { "chain", chain, 0 },
+ { "print", print, TRUE },
+ { "event", event, TRUE },
+ { "request", event, TRUE },
+ { "menu_add", menu_add, TRUE },
+ { "menu_link_add", menu_add_link, TRUE },
+ { "menu_image_add", menu_add_image, TRUE },
+ { "menu_editable_add", menu_add_edit, TRUE },
+ { "menu_separator", menu_add_separator, TRUE },
+ { "menu_link_separator", menu_add_separator_link, TRUE },
+ { "menu_image_separator", menu_add_separator_image, TRUE },
+ { "menu_editable_separator", menu_add_separator_edit, TRUE },
+ { "menu_remove", menu_remove, TRUE },
+ { "menu_link_remove", menu_remove_link, TRUE },
+ { "menu_image_remove", menu_remove_image, TRUE },
+ { "menu_editable_remove", menu_remove_edit, TRUE },
+ { "hardcopy", hardcopy, TRUE },
+ { "include", include, TRUE },
+ { "show_inspector", show_inspector, 0 },
+ { "add_cookie", add_cookie, 0 },
+ { "delete_cookie", delete_cookie, 0 },
+ { "clear_cookies", clear_cookies, 0 },
+ { "download", download, 0 }
+};
+
+void
+commands_hash() {
+ unsigned int i;
+ uzbl.behave.commands = g_hash_table_new(g_str_hash, g_str_equal);
+
+ for (i = 0; i < LENGTH(cmdlist); i++)
+ g_hash_table_insert(uzbl.behave.commands, (gpointer) cmdlist[i].key, &cmdlist[i]);
+}
+
+void
+builtins() {
+ unsigned int i;
+ unsigned int len = LENGTH(cmdlist);
+ GString* command_list = g_string_new("");
+
+ for (i = 0; i < len; i++) {
+ g_string_append(command_list, cmdlist[i].key);
+ g_string_append_c(command_list, ' ');
+ }
+
+ send_event(BUILTINS, NULL, TYPE_STR, command_list->str, NULL);
+ g_string_free(command_list, TRUE);
+}
+
+/* VIEW funcs (little webkit wrappers) */
+#define VIEWFUNC(name) void view_##name(WebKitWebView *page, GArray *argv, GString *result){(void)argv; (void)result; webkit_web_view_##name(page);}
+VIEWFUNC(reload)
+VIEWFUNC(reload_bypass_cache)
+VIEWFUNC(stop_loading)
+VIEWFUNC(zoom_in)
+VIEWFUNC(zoom_out)
+VIEWFUNC(go_back)
+VIEWFUNC(go_forward)
+#undef VIEWFUNC
+
+void
+toggle_zoom_type (WebKitWebView* page, GArray *argv, GString *result) {
+ (void)argv; (void)result;
+ webkit_web_view_set_full_content_zoom (page, !webkit_web_view_get_full_content_zoom (page));
+}
+
+void
+toggle_status (WebKitWebView* page, GArray *argv, GString *result) {
+ (void)page; (void)argv; (void)result;
+
+ uzbl.behave.show_status = !uzbl.behave.show_status;
+
+ set_show_status();
+}
+
+/*
+ * scroll vertical 20
+ * scroll vertical 20%
+ * scroll vertical -40
+ * scroll vertical begin
+ * scroll vertical end
+ * scroll horizontal 10
+ * scroll horizontal -500
+ * scroll horizontal begin
+ * scroll horizontal end
+ */
+void
+scroll_cmd(WebKitWebView* page, GArray *argv, GString *result) {
+ (void) page; (void) result;
+ gchar *direction = g_array_index(argv, gchar*, 0);
+ gchar *argv1 = g_array_index(argv, gchar*, 1);
+ GtkAdjustment *bar = NULL;
+
+ if (g_strcmp0(direction, "horizontal") == 0)
+ bar = uzbl.gui.bar_h;
+ else if (g_strcmp0(direction, "vertical") == 0)
+ bar = uzbl.gui.bar_v;
+ else {
+ if(uzbl.state.verbose)
+ puts("Unrecognized scroll format");
+ return;
+ }
+
+ if (g_strcmp0(argv1, "begin") == 0)
+ gtk_adjustment_set_value(bar, gtk_adjustment_get_lower(bar));
+ else if (g_strcmp0(argv1, "end") == 0)
+ gtk_adjustment_set_value (bar, gtk_adjustment_get_upper(bar) -
+ gtk_adjustment_get_page_size(bar));
+ else
+ scroll(bar, argv1);
+}
+
+void
+set_var(WebKitWebView *page, GArray *argv, GString *result) {
+ (void) page; (void) result;
+
+ if(!argv_idx(argv, 0))
+ return;
+
+ gchar **split = g_strsplit(argv_idx(argv, 0), "=", 2);
+ if (split[0] != NULL) {
+ gchar *value = split[1] ? g_strchug(split[1]) : " ";
+ set_var_value(g_strstrip(split[0]), value);
+ }
+ g_strfreev(split);
+}
+
+
+void
+event(WebKitWebView *page, GArray *argv, GString *result) {
+ (void) page; (void) result;
+ GString *event_name;
+ gchar **split = NULL;
+
+ if(!argv_idx(argv, 0))
+ return;
+
+ split = g_strsplit(argv_idx(argv, 0), " ", 2);
+ if(split[0])
+ event_name = g_string_ascii_up(g_string_new(split[0]));
+ else
+ return;
+
+ send_event(0, event_name->str, TYPE_FORMATTEDSTR, split[1] ? split[1] : "", NULL);
+
+ g_string_free(event_name, TRUE);
+ g_strfreev(split);
+}
+
+void
+print(WebKitWebView *page, GArray *argv, GString *result) {
+ (void) page; (void) result;
+ gchar* buf;
+
+ if(!result)
+ return;
+
+ buf = expand(argv_idx(argv, 0), 0);
+ g_string_assign(result, buf);
+ g_free(buf);
+}
+
+void
+hardcopy(WebKitWebView *page, GArray *argv, GString *result) {
+ (void) argv; (void) result;
+ webkit_web_frame_print(webkit_web_view_get_main_frame(page));
+}
+
+void
+include(WebKitWebView *page, GArray *argv, GString *result) {
+ (void) page; (void) result;
+ gchar *path = argv_idx(argv, 0);
+
+ if(!path)
+ return;
+
+ if((path = find_existing_file(path))) {
+ run_command_file(path);
+ send_event(FILE_INCLUDED, NULL, TYPE_STR, path, NULL);
+ g_free(path);
+ }
+}
+
+void
+show_inspector(WebKitWebView *page, GArray *argv, GString *result) {
+ (void) page; (void) argv; (void) result;
+
+ webkit_web_inspector_show(uzbl.gui.inspector);
+}
+
+void
+add_cookie(WebKitWebView *page, GArray *argv, GString *result) {
+ (void) page; (void) result;
+ gchar *host, *path, *name, *value;
+ gboolean secure = 0;
+ SoupDate *expires = NULL;
+
+ if(argv->len != 6)
+ return;
+
+ // Parse with same syntax as ADD_COOKIE event
+ host = argv_idx (argv, 0);
+ path = argv_idx (argv, 1);
+ name = argv_idx (argv, 2);
+ value = argv_idx (argv, 3);
+ secure = strcmp (argv_idx (argv, 4), "https") == 0;
+ if (strlen (argv_idx (argv, 5)) != 0)
+ expires = soup_date_new_from_time_t (
+ strtoul (argv_idx (argv, 5), NULL, 10));
+
+ // Create new cookie
+ SoupCookie * cookie = soup_cookie_new (name, value, host, path, -1);
+ soup_cookie_set_secure (cookie, secure);
+ if (expires)
+ soup_cookie_set_expires (cookie, expires);
+
+ // Add cookie to jar
+ uzbl.net.soup_cookie_jar->in_manual_add = 1;
+ soup_cookie_jar_add_cookie (SOUP_COOKIE_JAR (uzbl.net.soup_cookie_jar), cookie);
+ uzbl.net.soup_cookie_jar->in_manual_add = 0;
+}
+
+void
+delete_cookie(WebKitWebView *page, GArray *argv, GString *result) {
+ (void) page; (void) result;
+
+ if(argv->len < 4)
+ return;
+
+ SoupCookie * cookie = soup_cookie_new (
+ argv_idx (argv, 2),
+ argv_idx (argv, 3),
+ argv_idx (argv, 0),
+ argv_idx (argv, 1),
+ 0);
+
+ uzbl.net.soup_cookie_jar->in_manual_add = 1;
+ soup_cookie_jar_delete_cookie (SOUP_COOKIE_JAR (uzbl.net.soup_cookie_jar), cookie);
+ uzbl.net.soup_cookie_jar->in_manual_add = 0;
+}
+
+void
+clear_cookies(WebKitWebView *page, GArray *argv, GString *result) {
+ (void) page; (void) argv; (void) result;
+
+ // Replace the current cookie jar with a new empty jar
+ soup_session_remove_feature (uzbl.net.soup_session,
+ SOUP_SESSION_FEATURE (uzbl.net.soup_cookie_jar));
+ g_object_unref (G_OBJECT (uzbl.net.soup_cookie_jar));
+ uzbl.net.soup_cookie_jar = uzbl_cookie_jar_new ();
+ soup_session_add_feature(uzbl.net.soup_session,
+ SOUP_SESSION_FEATURE (uzbl.net.soup_cookie_jar));
+}
+
+void
+download(WebKitWebView *web_view, GArray *argv, GString *result) {
+ (void) result;
+
+ const gchar *uri = argv_idx(argv, 0);
+ const gchar *destination = NULL;
+ if(argv->len > 1)
+ destination = argv_idx(argv, 1);
+
+ WebKitNetworkRequest *req = webkit_network_request_new(uri);
+ WebKitDownload *download = webkit_download_new(req);
+
+ download_cb(web_view, download, (gpointer)destination);
+
+ if(webkit_download_get_destination_uri(download))
+ webkit_download_start(download);
+ else
+ g_object_unref(download);
+
+ g_object_unref(req);
+}
+
+void
+load_uri(WebKitWebView *web_view, GArray *argv, GString *result) {
+ (void) web_view; (void) result;
+ gchar * uri = argv_idx(argv, 0);
+ set_var_value("uri", uri ? uri : "");
+}
+
+void
+run_js (WebKitWebView * web_view, GArray *argv, GString *result) {
+ if (argv_idx(argv, 0))
+ eval_js(web_view, argv_idx(argv, 0), result, "(command)");
+}
+
+void
+run_external_js (WebKitWebView * web_view, GArray *argv, GString *result) {
+ (void) result;
+ gchar *path = NULL;
+
+ if (argv_idx(argv, 0) &&
+ ((path = find_existing_file(argv_idx(argv, 0)))) ) {
+ gchar *file_contents = NULL;
+
+ GIOChannel *chan = g_io_channel_new_file(path, "r", NULL);
+ if (chan) {
+ gsize len;
+ g_io_channel_read_to_end(chan, &file_contents, &len, NULL);
+ g_io_channel_unref (chan);
+ }
+
+ if (uzbl.state.verbose)
+ printf ("External JavaScript file %s loaded\n", argv_idx(argv, 0));
+
+ gchar *js = str_replace("%s", argv_idx (argv, 1) ? argv_idx (argv, 1) : "", file_contents);
+ g_free (file_contents);
+
+ eval_js (web_view, js, result, path);
+ g_free (js);
+ g_free(path);
+ }
+}
+
+void
+search_clear(WebKitWebView *page, GArray *argv, GString *result) {
+ (void) argv; (void) result;
+ webkit_web_view_unmark_text_matches (page);
+ g_free(uzbl.state.searchtx);
+ uzbl.state.searchtx = NULL;
+}
+
+void
+search_forward_text (WebKitWebView *page, GArray *argv, GString *result) {
+ (void) result;
+ search_text(page, argv_idx(argv, 0), TRUE);
+}
+
+void
+search_reverse_text(WebKitWebView *page, GArray *argv, GString *result) {
+ (void) result;
+ search_text(page, argv_idx(argv, 0), FALSE);
+}
+
+void
+dehilight(WebKitWebView *page, GArray *argv, GString *result) {
+ (void) argv; (void) result;
+ webkit_web_view_set_highlight_text_matches (page, FALSE);
+}
+
+void
+chain(WebKitWebView *page, GArray *argv, GString *result) {
+ (void) page;
+ guint i = 0;
+ const gchar *cmd;
+ GString *r = g_string_new ("");
+ while ((cmd = argv_idx(argv, i++))) {
+ GArray *a = g_array_new (TRUE, FALSE, sizeof(gchar*));
+ const CommandInfo *c = parse_command_parts(cmd, a);
+ if (c)
+ run_parsed_command(c, a, r);
+ g_array_free (a, TRUE);
+ }
+ if(result)
+ g_string_assign (result, r->str);
+
+ g_string_free(r, TRUE);
+}
+
+void
+close_uzbl (WebKitWebView *page, GArray *argv, GString *result) {
+ (void)page; (void)argv; (void)result;
+ gtk_main_quit ();
+}
+
+void
+spawn_async(WebKitWebView *web_view, GArray *argv, GString *result) {
+ (void)web_view; (void)result;
+ spawn(argv, NULL, FALSE);
+}
+
+void
+spawn_sync(WebKitWebView *web_view, GArray *argv, GString *result) {
+ (void)web_view;
+ spawn(argv, result, FALSE);
+}
+
+void
+spawn_sync_exec(WebKitWebView *web_view, GArray *argv, GString *result) {
+ (void)web_view;
+ if(!result) {
+ GString *force_result = g_string_new("");
+ spawn(argv, force_result, TRUE);
+ g_string_free (force_result, TRUE);
+ } else
+ spawn(argv, result, TRUE);
+}
+
+void
+spawn_sh_async(WebKitWebView *web_view, GArray *argv, GString *result) {
+ (void)web_view; (void)result;
+ spawn_sh(argv, NULL);
+}
+
+void
+spawn_sh_sync(WebKitWebView *web_view, GArray *argv, GString *result) {
+ (void)web_view; (void)result;
+ spawn_sh(argv, result);
+}
+
+void
+act_dump_config(WebKitWebView *web_view, GArray *argv, GString *result) {
+ (void)web_view; (void) argv; (void)result;
+ dump_config();
+}
+
+void
+act_dump_config_as_events(WebKitWebView *web_view, GArray *argv, GString *result) {
+ (void)web_view; (void) argv; (void)result;
+ dump_config_as_events();
+}
diff --git a/src/commands.h b/src/commands.h
new file mode 100644
index 0000000..b8cf095
--- /dev/null
+++ b/src/commands.h
@@ -0,0 +1,68 @@
+/*
+ * Uzbl Commands
+ */
+#ifndef __COMMANDS__
+#define __COMMANDS__
+
+#include <webkit/webkit.h>
+
+typedef void (*Command)(WebKitWebView*, GArray *argv, GString *result);
+
+typedef struct {
+ const gchar *key;
+ Command function;
+ gboolean no_split;
+} CommandInfo;
+
+/**
+ * Initialises the hash table uzbl.behave.commands with the available commands.
+ */
+void
+commands_hash();
+
+/**
+ * Sends the BUILTINS events with the available commands.
+ */
+void
+builtins();
+
+
+void view_reload(WebKitWebView *page, GArray *argv, GString *result);
+void view_reload_bypass_cache(WebKitWebView *page, GArray *argv, GString *result);
+void view_stop_loading(WebKitWebView *page, GArray *argv, GString *result);
+void view_zoom_in(WebKitWebView *page, GArray *argv, GString *result);
+void view_zoom_out(WebKitWebView *page, GArray *argv, GString *result);
+void view_go_back(WebKitWebView *page, GArray *argv, GString *result);
+void view_go_forward(WebKitWebView *page, GArray *argv, GString *result);
+void toggle_zoom_type (WebKitWebView* page, GArray *argv, GString *result);
+void scroll_cmd(WebKitWebView* page, GArray *argv, GString *result);
+void print(WebKitWebView *page, GArray *argv, GString *result);
+void event(WebKitWebView *page, GArray *argv, GString *result);
+void load_uri(WebKitWebView * web_view, GArray *argv, GString *result);
+void chain(WebKitWebView *page, GArray *argv, GString *result);
+void close_uzbl(WebKitWebView *page, GArray *argv, GString *result);
+void spawn_async(WebKitWebView *web_view, GArray *argv, GString *result);
+void spawn_sh_async(WebKitWebView *web_view, GArray *argv, GString *result);
+void spawn_sync(WebKitWebView *web_view, GArray *argv, GString *result);
+void spawn_sh_sync(WebKitWebView *web_view, GArray *argv, GString *result);
+void spawn_sync_exec(WebKitWebView *web_view, GArray *argv, GString *result);
+void search_forward_text (WebKitWebView *page, GArray *argv, GString *result);
+void search_reverse_text (WebKitWebView *page, GArray *argv, GString *result);
+void search_clear(WebKitWebView *page, GArray *argv, GString *result);
+void dehilight (WebKitWebView *page, GArray *argv, GString *result);
+void hardcopy(WebKitWebView *page, GArray *argv, GString *result);
+void include(WebKitWebView *page, GArray *argv, GString *result);
+void show_inspector(WebKitWebView *page, GArray *argv, GString *result);
+void add_cookie(WebKitWebView *page, GArray *argv, GString *result);
+void delete_cookie(WebKitWebView *page, GArray *argv, GString *result);
+void clear_cookies(WebKitWebView *pag, GArray *argv, GString *result);
+void download(WebKitWebView *pag, GArray *argv, GString *result);
+void set_var(WebKitWebView *page, GArray *argv, GString *result);
+void run_js (WebKitWebView * web_view, GArray *argv, GString *result);
+void run_external_js (WebKitWebView * web_view, GArray *argv, GString *result);
+void toggle_zoom_type (WebKitWebView* page, GArray *argv, GString *result);
+void toggle_status (WebKitWebView* page, GArray *argv, GString *result);
+void act_dump_config(WebKitWebView* page, GArray *argv, GString *result);
+void act_dump_config_as_events(WebKitWebView* page, GArray *argv, GString *result);
+
+#endif
diff --git a/src/cookie-jar.c b/src/cookie-jar.c
index bc7d022..dd9585b 100644
--- a/src/cookie-jar.c
+++ b/src/cookie-jar.c
@@ -3,6 +3,7 @@
#include "cookie-jar.h"
#include "uzbl-core.h"
#include "events.h"
+#include "type.h"
G_DEFINE_TYPE (UzblCookieJar, soup_cookie_jar_socket, SOUP_TYPE_COOKIE_JAR)
@@ -43,7 +44,7 @@ changed(SoupCookieJar *jar, SoupCookie *old_cookie, SoupCookie *new_cookie) {
gchar *expires = NULL;
if(cookie->expires)
- expires = g_strdup_printf ("%d", soup_date_to_time_t (cookie->expires));
+ expires = g_strdup_printf ("%ld", (long)soup_date_to_time_t (cookie->expires));
send_event (new_cookie ? ADD_COOKIE : DELETE_COOKIE, NULL,
TYPE_STR, cookie->domain,
diff --git a/src/events.c b/src/events.c
index 2da3e38..45140c0 100644
--- a/src/events.c
+++ b/src/events.c
@@ -6,8 +6,7 @@
#include "uzbl-core.h"
#include "events.h"
#include "util.h"
-
-UzblCore uzbl;
+#include "type.h"
/* Event id to name mapping
* Event names must be in the same
@@ -54,7 +53,9 @@ const char *event_table[LAST_EVENT] = {
"DOWNLOAD_PROGRESS",
"DOWNLOAD_COMPLETE",
"ADD_COOKIE" ,
- "DELETE_COOKIE"
+ "DELETE_COOKIE" ,
+ "FOCUS_ELEMENT" ,
+ "BLUR_ELEMENT"
};
void
@@ -217,8 +218,10 @@ get_modifier_mask(guint state) {
g_string_append(modifiers, "Ctrl|");
if(state & GDK_MOD1_MASK)
g_string_append(modifiers,"Mod1|");
+ /* Mod2 is usually Num_Luck. Ignore it as it messes up keybindings.
if(state & GDK_MOD2_MASK)
g_string_append(modifiers,"Mod2|");
+ */
if(state & GDK_MOD3_MASK)
g_string_append(modifiers,"Mod3|");
if(state & GDK_MOD4_MASK)
diff --git a/src/events.h b/src/events.h
index dbe0244..8e89899 100644
--- a/src/events.h
+++ b/src/events.h
@@ -25,6 +25,7 @@ enum event_type {
PTR_MOVE, SCROLL_VERT, SCROLL_HORIZ,
DOWNLOAD_STARTED, DOWNLOAD_PROGRESS, DOWNLOAD_COMPLETE,
ADD_COOKIE, DELETE_COOKIE,
+ FOCUS_ELEMENT, BLUR_ELEMENT,
/* must be last entry */
LAST_EVENT
diff --git a/src/inspector.c b/src/inspector.c
index 4c8c890..d0d86b9 100644
--- a/src/inspector.c
+++ b/src/inspector.c
@@ -6,7 +6,7 @@
#include "uzbl-core.h"
#include "events.h"
#include "callbacks.h"
-
+#include "type.h"
void
hide_window_cb(GtkWidget *widget, gpointer data) {
@@ -88,7 +88,7 @@ inspector_inspector_destroyed_cb (WebKitWebInspector* inspector){
void
set_up_inspector() {
GUI *g = &uzbl.gui;
- WebKitWebSettings *settings = view_settings();
+ WebKitWebSettings *settings = webkit_web_view_get_settings(g->web_view);
g_object_set(G_OBJECT(settings), "enable-developer-extras", TRUE, NULL);
uzbl.gui.inspector = webkit_web_view_get_inspector(uzbl.gui.web_view);
diff --git a/src/io.c b/src/io.c
index 3f8fa2f..062a853 100644
--- a/src/io.c
+++ b/src/io.c
@@ -6,6 +6,7 @@
#include "io.h"
#include "util.h"
#include "uzbl-core.h"
+#include "type.h"
/*@null@*/ gchar*
build_stream_name(int type, const gchar* dir) {
diff --git a/src/menu.h b/src/menu.h
index 8b89f2f..03055e5 100644
--- a/src/menu.h
+++ b/src/menu.h
@@ -3,6 +3,14 @@
#include <webkit/webkit.h>
+typedef struct {
+ gchar* name;
+ gchar* cmd;
+ gboolean issep;
+ guint context;
+ WebKitHitTestResult* hittest;
+} MenuItem;
+
void menu_add(WebKitWebView *page, GArray *argv, GString *result);
void menu_add_link(WebKitWebView *page, GArray *argv, GString *result);
void menu_add_image(WebKitWebView *page, GArray *argv, GString *result);
diff --git a/src/status-bar.c b/src/status-bar.c
new file mode 100644
index 0000000..6d4541b
--- /dev/null
+++ b/src/status-bar.c
@@ -0,0 +1,117 @@
+#include "status-bar.h"
+
+G_DEFINE_TYPE (UzblStatusBar, uzbl_status_bar, GTK_TYPE_HBOX)
+
+static void uzbl_status_bar_size_allocate (GtkWidget *widget,
+ GtkAllocation *allocation);
+
+static void
+uzbl_status_bar_class_init (UzblStatusBarClass *class) {
+ GtkWidgetClass *widget_class;
+
+ widget_class = (GtkWidgetClass*) class;
+
+ /* override the size_allocate method */
+ widget_class->size_allocate = uzbl_status_bar_size_allocate;
+}
+
+static void
+uzbl_status_bar_init (UzblStatusBar *status_bar) {
+ gtk_box_set_homogeneous (GTK_BOX(status_bar), FALSE);
+ gtk_box_set_spacing (GTK_BOX(status_bar), 0);
+
+ /* create left panel */
+ status_bar->left_label = gtk_label_new ("");
+ gtk_label_set_selectable (GTK_LABEL(status_bar->left_label), TRUE);
+ gtk_misc_set_alignment (GTK_MISC(status_bar->left_label), 0, 0);
+ gtk_misc_set_padding (GTK_MISC(status_bar->left_label), 2, 2);
+ gtk_label_set_ellipsize(GTK_LABEL(status_bar->left_label), PANGO_ELLIPSIZE_END);
+
+ /* create right panel */
+ status_bar->right_label = gtk_label_new ("");
+ gtk_label_set_selectable(GTK_LABEL(status_bar->right_label), TRUE);
+ gtk_misc_set_alignment (GTK_MISC(status_bar->right_label), 1, 0);
+ gtk_misc_set_padding (GTK_MISC(status_bar->right_label), 2, 2);
+ gtk_label_set_ellipsize(GTK_LABEL(status_bar->right_label), PANGO_ELLIPSIZE_START);
+
+ /* add the labels to the status bar */
+ gtk_box_pack_start (GTK_BOX (status_bar), status_bar->left_label, FALSE, FALSE, 0);
+ gtk_box_pack_start (GTK_BOX (status_bar), status_bar->right_label, TRUE, TRUE, 0);
+}
+
+static void
+uzbl_status_bar_size_allocate (GtkWidget *widget,
+ GtkAllocation *allocation) {
+ GtkRequisition left_requisition, right_requisition;
+ GtkAllocation left_allocation, right_allocation;
+ UzblStatusBar *status_bar = UZBL_STATUS_BAR(widget);
+
+ int left_natural_width;
+
+#if GTK_CHECK_VERSION(3,0,0)
+ GtkRequisition left_requisition_nat;
+
+ gtk_widget_get_preferred_size (status_bar->left_label, &left_requisition, &left_requisition_nat);
+ gtk_widget_get_preferred_size (status_bar->right_label, &right_requisition, NULL);
+
+ left_natural_width = left_requisition_nat.width;
+#else
+ gtk_widget_size_request(status_bar->left_label, &left_requisition);
+ gtk_widget_size_request(status_bar->right_label, &right_requisition);
+
+ PangoLayout *left_layout = gtk_label_get_layout(GTK_LABEL(status_bar->left_label));
+ pango_layout_get_pixel_size(left_layout, &left_natural_width, NULL);
+
+ /* some kind of fudge factor seems to be needed here */
+ left_natural_width += 16;
+#endif
+
+ gtk_widget_set_allocation (widget, allocation);
+
+ /* the entire allocation, minus the space needed for the right label's ellipsis */
+ int left_max_width = allocation->width - right_requisition.width;
+
+ /* the left label gets max(as much space as it needs, the status bar's allocation) */
+ left_allocation.width = (left_max_width > left_natural_width) ? left_natural_width : left_max_width;
+
+ /* the right label gets whatever is left over. it gets at least enough space
+ * for an ellipsis, it seems that it will just display everything if you give
+ * it 0. */
+ right_allocation.width = allocation->width - left_allocation.width;
+
+ /* don't fight guys, you can both have as much vertical space as you want! */
+ left_allocation.height = right_allocation.height = allocation->height;
+
+ left_allocation.x = 0;
+ right_allocation.x = left_allocation.width;
+
+ left_allocation.y = right_allocation.y = allocation->y;
+
+ gtk_widget_size_allocate (status_bar->left_label, &left_allocation);
+ gtk_widget_size_allocate (status_bar->right_label, &right_allocation);
+}
+
+void
+uzbl_status_bar_update_left(GtkWidget *widget, const gchar *format) {
+ UzblStatusBar *status_bar = UZBL_STATUS_BAR(widget);
+
+ if(!format || !GTK_IS_LABEL(status_bar->left_label))
+ return;
+
+ gtk_label_set_markup(GTK_LABEL(status_bar->left_label), format);
+}
+
+void
+uzbl_status_bar_update_right(GtkWidget *widget, const gchar *format) {
+ UzblStatusBar *status_bar = UZBL_STATUS_BAR(widget);
+
+ if(!format || !GTK_IS_LABEL(status_bar->right_label))
+ return;
+
+ gtk_label_set_markup(GTK_LABEL(status_bar->right_label), format);
+}
+
+GtkWidget *
+uzbl_status_bar_new() {
+ return g_object_new (UZBL_TYPE_STATUS_BAR, NULL);
+}
diff --git a/src/status-bar.h b/src/status-bar.h
new file mode 100644
index 0000000..e972701
--- /dev/null
+++ b/src/status-bar.h
@@ -0,0 +1,36 @@
+#ifndef __UZBL_STATUS_BAR_H__
+#define __UZBL_STATUS_BAR_H__
+
+#include <gtk/gtk.h>
+
+#define UZBL_TYPE_STATUS_BAR (uzbl_status_bar_get_type ())
+#define UZBL_STATUS_BAR(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), UZBL_TYPE_STATUS_BAR, UzblStatusBar))
+#define UZBL_STATUS_BAR_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), UZBL_TYPE_STATUS_BAR, UZblStatusBarClass))
+#define UZBL_IS_STATUS_BAR(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), UZBL_TYPE_STATUS_BAR))
+#define UZBL_IS_STATUS_BAR_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), UZBL_TYPE_STATUS_BAR))
+#define UZBL_STATUS_BAR_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), UZBL_TYPE_STATUS_BAR, UzblStatusBarClass))
+
+typedef struct _UzblStatusBar UzblStatusBar;
+typedef struct _UzblStatusBarClass UzblStatusBarClass;
+
+struct _UzblStatusBar {
+ GtkHBox hbox;
+
+ GtkWidget *left_label;
+ GtkWidget *right_label;
+};
+
+struct _UzblStatusBarClass {
+ GtkHBoxClass parent_class;
+};
+
+GType uzbl_status_bar_get_type (void) G_GNUC_CONST;
+GtkWidget * uzbl_status_bar_new ();
+
+void
+uzbl_status_bar_update_left(GtkWidget *widget, const gchar *format);
+
+void
+uzbl_status_bar_update_right(GtkWidget *widget, const gchar *format);
+
+#endif
diff --git a/src/type.h b/src/type.h
new file mode 100644
index 0000000..24fc97f
--- /dev/null
+++ b/src/type.h
@@ -0,0 +1,24 @@
+/*
+ * Uzbl Types
+ */
+
+enum ptr_type {
+ TYPE_INT = 1,
+ TYPE_STR,
+ TYPE_FLOAT,
+ TYPE_NAME,
+ TYPE_FORMATTEDSTR // used by send_event
+};
+
+typedef struct {
+ enum ptr_type type;
+ union {
+ int *i;
+ float *f;
+ gchar **s;
+ } ptr;
+ int dump;
+ int writeable;
+ /*@null@*/ void (*func)(void);
+} uzbl_cmdprop;
+
diff --git a/src/util.c b/src/util.c
index 8f6c349..42ae39e 100644
--- a/src/util.c
+++ b/src/util.c
@@ -134,7 +134,7 @@ find_existing_file(const gchar* path_list) {
char *basename = strrchr(path_list_dup, ':');
if(!basename)
- return path_list_dup;
+ return file_exists(path_list_dup) ? path_list_dup : NULL;
basename[0] = '\0';
basename++;
diff --git a/src/uzbl-core.c b/src/uzbl-core.c
index c095a7f..af60767 100644
--- a/src/uzbl-core.c
+++ b/src/uzbl-core.c
@@ -37,6 +37,8 @@
#include "util.h"
#include "menu.h"
#include "io.h"
+#include "variables.h"
+#include "type.h"
UzblCore uzbl;
@@ -51,8 +53,11 @@ GOptionEntry entries[] = {
"Name of the current instance (defaults to Xorg window id or random for GtkSocket mode)", "NAME" },
{ "config", 'c', 0, G_OPTION_ARG_STRING, &uzbl.state.config_file,
"Path to config file or '-' for stdin", "FILE" },
+ /* TODO: explain the difference between these two options */
{ "socket", 's', 0, G_OPTION_ARG_INT, &uzbl.state.socket_id,
- "Xembed Socket ID", "SOCKET" },
+ "Xembed socket ID, this window should embed itself", "SOCKET" },
+ { "embed", 'e', 0, G_OPTION_ARG_NONE, &uzbl.state.embed,
+ "Whether this window should expect to be embedded", NULL },
{ "connect-socket", 0, 0, G_OPTION_ARG_STRING_ARRAY, &uzbl.state.connect_socket_names,
"Connect to server socket for event managing", "CSOCKET" },
{ "print-events", 'p', 0, G_OPTION_ARG_NONE, &uzbl.state.events_stdout,
@@ -64,107 +69,6 @@ GOptionEntry entries[] = {
{ NULL, 0, 0, 0, NULL, NULL, NULL }
};
-/* abbreviations to help keep the table's width humane */
-#define PTR_V_STR(var, d, fun) { .ptr.s = &(var), .type = TYPE_STR, .dump = d, .writeable = 1, .func = fun }
-#define PTR_V_INT(var, d, fun) { .ptr.i = (int*)&(var), .type = TYPE_INT, .dump = d, .writeable = 1, .func = fun }
-#define PTR_V_FLOAT(var, d, fun) { .ptr.f = &(var), .type = TYPE_FLOAT, .dump = d, .writeable = 1, .func = fun }
-#define PTR_C_STR(var, fun) { .ptr.s = &(var), .type = TYPE_STR, .dump = 0, .writeable = 0, .func = fun }
-#define PTR_C_INT(var, fun) { .ptr.i = (int*)&(var), .type = TYPE_INT, .dump = 0, .writeable = 0, .func = fun }
-#define PTR_C_FLOAT(var, fun) { .ptr.f = &(var), .type = TYPE_FLOAT, .dump = 0, .writeable = 0, .func = fun }
-
-const struct var_name_to_ptr_t {
- const char *name;
- uzbl_cmdprop cp;
-} var_name_to_ptr[] = {
-/* variable name pointer to variable in code dump callback function */
-/* ---------------------------------------------------------------------------------------------- */
- { "uri", PTR_V_STR(uzbl.state.uri, 1, cmd_load_uri)},
- { "verbose", PTR_V_INT(uzbl.state.verbose, 1, NULL)},
- { "print_events", PTR_V_INT(uzbl.state.events_stdout, 1, NULL)},
- { "inject_html", PTR_V_STR(uzbl.behave.inject_html, 0, cmd_inject_html)},
- { "geometry", PTR_V_STR(uzbl.gui.geometry, 1, cmd_set_geometry)},
- { "show_status", PTR_V_INT(uzbl.behave.show_status, 1, cmd_set_status)},
- { "status_top", PTR_V_INT(uzbl.behave.status_top, 1, move_statusbar)},
- { "status_format", PTR_V_STR(uzbl.behave.status_format, 1, NULL)},
- { "status_format_right", PTR_V_STR(uzbl.behave.status_format_right, 1, NULL)},
- { "status_background", PTR_V_STR(uzbl.behave.status_background, 1, set_status_background)},
- { "title_format_long", PTR_V_STR(uzbl.behave.title_format_long, 1, NULL)},
- { "title_format_short", PTR_V_STR(uzbl.behave.title_format_short, 1, NULL)},
- { "icon", PTR_V_STR(uzbl.gui.icon, 1, set_icon)},
- { "forward_keys", PTR_V_INT(uzbl.behave.forward_keys, 1, NULL)},
- { "authentication_handler", PTR_V_STR(uzbl.behave.authentication_handler, 1, set_authentication_handler)},
- { "scheme_handler", PTR_V_STR(uzbl.behave.scheme_handler, 1, NULL)},
- { "download_handler", PTR_V_STR(uzbl.behave.download_handler, 1, NULL)},
- { "fifo_dir", PTR_V_STR(uzbl.behave.fifo_dir, 1, cmd_fifo_dir)},
- { "socket_dir", PTR_V_STR(uzbl.behave.socket_dir, 1, cmd_socket_dir)},
- { "http_debug", PTR_V_INT(uzbl.behave.http_debug, 1, cmd_http_debug)},
- { "shell_cmd", PTR_V_STR(uzbl.behave.shell_cmd, 1, NULL)},
- { "proxy_url", PTR_V_STR(uzbl.net.proxy_url, 1, set_proxy_url)},
- { "max_conns", PTR_V_INT(uzbl.net.max_conns, 1, cmd_max_conns)},
- { "max_conns_host", PTR_V_INT(uzbl.net.max_conns_host, 1, cmd_max_conns_host)},
- { "useragent", PTR_V_STR(uzbl.net.useragent, 1, cmd_useragent)},
- { "accept_languages", PTR_V_STR(uzbl.net.accept_languages, 1, set_accept_languages)},
- { "javascript_windows", PTR_V_INT(uzbl.behave.javascript_windows, 1, cmd_javascript_windows)},
- /* requires webkit >=1.1.14 */
- { "view_source", PTR_V_INT(uzbl.behave.view_source, 0, cmd_view_source)},
-
- /* exported WebKitWebSettings properties */
- { "zoom_level", PTR_V_FLOAT(uzbl.behave.zoom_level, 1, cmd_zoom_level)},
- { "zoom_type", PTR_V_INT(uzbl.behave.zoom_type, 1, cmd_set_zoom_type)},
- { "font_size", PTR_V_INT(uzbl.behave.font_size, 1, cmd_font_size)},
- { "default_font_family", PTR_V_STR(uzbl.behave.default_font_family, 1, cmd_default_font_family)},
- { "monospace_font_family", PTR_V_STR(uzbl.behave.monospace_font_family, 1, cmd_monospace_font_family)},
- { "cursive_font_family", PTR_V_STR(uzbl.behave.cursive_font_family, 1, cmd_cursive_font_family)},
- { "sans_serif_font_family", PTR_V_STR(uzbl.behave.sans_serif_font_family, 1, cmd_sans_serif_font_family)},
- { "serif_font_family", PTR_V_STR(uzbl.behave.serif_font_family, 1, cmd_serif_font_family)},
- { "fantasy_font_family", PTR_V_STR(uzbl.behave.fantasy_font_family, 1, cmd_fantasy_font_family)},
- { "monospace_size", PTR_V_INT(uzbl.behave.monospace_size, 1, cmd_font_size)},
- { "minimum_font_size", PTR_V_INT(uzbl.behave.minimum_font_size, 1, cmd_minimum_font_size)},
- { "enable_pagecache", PTR_V_INT(uzbl.behave.enable_pagecache, 1, cmd_enable_pagecache)},
- { "disable_plugins", PTR_V_INT(uzbl.behave.disable_plugins, 1, cmd_disable_plugins)},
- { "disable_scripts", PTR_V_INT(uzbl.behave.disable_scripts, 1, cmd_disable_scripts)},
- { "autoload_images", PTR_V_INT(uzbl.behave.autoload_img, 1, cmd_autoload_img)},
- { "autoshrink_images", PTR_V_INT(uzbl.behave.autoshrink_img, 1, cmd_autoshrink_img)},
- { "enable_spellcheck", PTR_V_INT(uzbl.behave.enable_spellcheck, 1, cmd_enable_spellcheck)},
- { "enable_private", PTR_V_INT(uzbl.behave.enable_private, 1, cmd_enable_private)},
- { "print_backgrounds", PTR_V_INT(uzbl.behave.print_bg, 1, cmd_print_bg)},
- { "stylesheet_uri", PTR_V_STR(uzbl.behave.style_uri, 1, cmd_style_uri)},
- { "resizable_text_areas", PTR_V_INT(uzbl.behave.resizable_txt, 1, cmd_resizable_txt)},
- { "default_encoding", PTR_V_STR(uzbl.behave.default_encoding, 1, cmd_default_encoding)},
- { "current_encoding", PTR_V_STR(uzbl.behave.current_encoding, 1, set_current_encoding)},
- { "enforce_96_dpi", PTR_V_INT(uzbl.behave.enforce_96dpi, 1, cmd_enforce_96dpi)},
- { "caret_browsing", PTR_V_INT(uzbl.behave.caret_browsing, 1, cmd_caret_browsing)},
- { "scrollbars_visible", PTR_V_INT(uzbl.gui.scrollbars_visible, 1, cmd_scrollbars_visibility)},
-
- /* constants (not dumpable or writeable) */
- { "WEBKIT_MAJOR", PTR_C_INT(uzbl.info.webkit_major, NULL)},
- { "WEBKIT_MINOR", PTR_C_INT(uzbl.info.webkit_minor, NULL)},
- { "WEBKIT_MICRO", PTR_C_INT(uzbl.info.webkit_micro, NULL)},
- { "ARCH_UZBL", PTR_C_STR(uzbl.info.arch, NULL)},
- { "COMMIT", PTR_C_STR(uzbl.info.commit, NULL)},
- { "TITLE", PTR_C_STR(uzbl.gui.main_title, NULL)},
- { "SELECTED_URI", PTR_C_STR(uzbl.state.selected_url, NULL)},
- { "NAME", PTR_C_STR(uzbl.state.instance_name, NULL)},
- { "PID", PTR_C_STR(uzbl.info.pid_str, NULL)},
- { "_", PTR_C_STR(uzbl.state.last_result, NULL)},
-
- { NULL, {.ptr.s = NULL, .type = TYPE_INT, .dump = 0, .writeable = 0, .func = NULL}}
-};
-
-/* construct a hash from the var_name_to_ptr array for quick access */
-void
-create_var_to_name_hash() {
- const struct var_name_to_ptr_t *n2v_p = var_name_to_ptr;
- uzbl.comm.proto_var = g_hash_table_new(g_str_hash, g_str_equal);
- while(n2v_p->name) {
- g_hash_table_insert(uzbl.comm.proto_var,
- (gpointer) n2v_p->name,
- (gpointer) &n2v_p->cp);
- n2v_p++;
- }
-}
-
-
/* --- UTILITY FUNCTIONS --- */
enum exp_type {
EXP_ERR, EXP_SIMPLE_VAR, EXP_BRACED_VAR, EXP_EXPR, EXP_JS, EXP_ESCAPE
@@ -187,7 +91,6 @@ get_exp_type(const gchar *s) {
*/
gchar*
expand(const char* s, guint recurse) {
- uzbl_cmdprop* c;
enum exp_type etype;
char* end_simple_var = "\t^°!\"§$%&/()=?'`'+~*'#-:,;@<>| \\{}[]¹²³¼½";
char* ret = NULL;
@@ -244,17 +147,8 @@ expand(const char* s, guint recurse) {
if(etype == EXP_SIMPLE_VAR ||
etype == EXP_BRACED_VAR) {
- if( (c = g_hash_table_lookup(uzbl.comm.proto_var, ret)) ) {
- if(c->type == TYPE_STR && *c->ptr.s != NULL) {
- g_string_append(buf, (gchar *)*c->ptr.s);
- }
- else if(c->type == TYPE_INT) {
- g_string_append_printf(buf, "%d", *c->ptr.i);
- }
- else if(c->type == TYPE_FLOAT) {
- g_string_append_printf(buf, "%f", *c->ptr.f);
- }
- }
+
+ expand_variable(buf, ret);
if(etype == EXP_SIMPLE_VAR)
s = vend;
@@ -448,199 +342,8 @@ scroll(GtkAdjustment* bar, gchar *amount_str) {
gtk_adjustment_set_value (bar, value);
}
-/*
- * scroll vertical 20
- * scroll vertical 20%
- * scroll vertical -40
- * scroll vertical begin
- * scroll vertical end
- * scroll horizontal 10
- * scroll horizontal -500
- * scroll horizontal begin
- * scroll horizontal end
- */
-void
-scroll_cmd(WebKitWebView* page, GArray *argv, GString *result) {
- (void) page; (void) result;
- gchar *direction = g_array_index(argv, gchar*, 0);
- gchar *argv1 = g_array_index(argv, gchar*, 1);
-
- if (g_strcmp0(direction, "horizontal") == 0)
- {
- if (g_strcmp0(argv1, "begin") == 0)
- gtk_adjustment_set_value(uzbl.gui.bar_h, gtk_adjustment_get_lower(uzbl.gui.bar_h));
- else if (g_strcmp0(argv1, "end") == 0)
- gtk_adjustment_set_value (uzbl.gui.bar_h, gtk_adjustment_get_upper(uzbl.gui.bar_h) -
- gtk_adjustment_get_page_size(uzbl.gui.bar_h));
- else
- scroll(uzbl.gui.bar_h, argv1);
- }
- else if (g_strcmp0(direction, "vertical") == 0)
- {
- if (g_strcmp0(argv1, "begin") == 0)
- gtk_adjustment_set_value(uzbl.gui.bar_v, gtk_adjustment_get_lower(uzbl.gui.bar_v));
- else if (g_strcmp0(argv1, "end") == 0)
- gtk_adjustment_set_value (uzbl.gui.bar_v, gtk_adjustment_get_upper(uzbl.gui.bar_v) -
- gtk_adjustment_get_page_size(uzbl.gui.bar_v));
- else
- scroll(uzbl.gui.bar_v, argv1);
- }
- else
- if(uzbl.state.verbose)
- puts("Unrecognized scroll format");
-}
-
-
-/* VIEW funcs (little webkit wrappers) */
-#define VIEWFUNC(name) void view_##name(WebKitWebView *page, GArray *argv, GString *result){(void)argv; (void)result; webkit_web_view_##name(page);}
-VIEWFUNC(reload)
-VIEWFUNC(reload_bypass_cache)
-VIEWFUNC(stop_loading)
-VIEWFUNC(zoom_in)
-VIEWFUNC(zoom_out)
-VIEWFUNC(go_back)
-VIEWFUNC(go_forward)
-#undef VIEWFUNC
-
-/* -- command to callback/function map for things we cannot attach to any signals */
-CommandInfo cmdlist[] =
-{ /* key function no_split */
- { "back", view_go_back, 0 },
- { "forward", view_go_forward, 0 },
- { "scroll", scroll_cmd, 0 },
- { "reload", view_reload, 0 },
- { "reload_ign_cache", view_reload_bypass_cache, 0 },
- { "stop", view_stop_loading, 0 },
- { "zoom_in", view_zoom_in, 0 }, //Can crash (when max zoom reached?).
- { "zoom_out", view_zoom_out, 0 },
- { "toggle_zoom_type", toggle_zoom_type, 0 },
- { "uri", load_uri, TRUE },
- { "js", run_js, TRUE },
- { "script", run_external_js, 0 },
- { "toggle_status", toggle_status_cb, 0 },
- { "spawn", spawn_async, 0 },
- { "sync_spawn", spawn_sync, 0 },
- { "sync_spawn_exec", spawn_sync_exec, 0 }, // needed for load_cookies.sh :(
- { "sh", spawn_sh_async, 0 },
- { "sync_sh", spawn_sh_sync, 0 },
- { "exit", close_uzbl, 0 },
- { "search", search_forward_text, TRUE },
- { "search_reverse", search_reverse_text, TRUE },
- { "search_clear", search_clear, TRUE },
- { "dehilight", dehilight, 0 },
- { "set", set_var, TRUE },
- { "dump_config", act_dump_config, 0 },
- { "dump_config_as_events", act_dump_config_as_events, 0 },
- { "chain", chain, 0 },
- { "print", print, TRUE },
- { "event", event, TRUE },
- { "request", event, TRUE },
- { "menu_add", menu_add, TRUE },
- { "menu_link_add", menu_add_link, TRUE },
- { "menu_image_add", menu_add_image, TRUE },
- { "menu_editable_add", menu_add_edit, TRUE },
- { "menu_separator", menu_add_separator, TRUE },
- { "menu_link_separator", menu_add_separator_link, TRUE },
- { "menu_image_separator", menu_add_separator_image, TRUE },
- { "menu_editable_separator", menu_add_separator_edit, TRUE },
- { "menu_remove", menu_remove, TRUE },
- { "menu_link_remove", menu_remove_link, TRUE },
- { "menu_image_remove", menu_remove_image, TRUE },
- { "menu_editable_remove", menu_remove_edit, TRUE },
- { "hardcopy", hardcopy, TRUE },
- { "include", include, TRUE },
- { "show_inspector", show_inspector, 0 },
- { "add_cookie", add_cookie, 0 },
- { "delete_cookie", delete_cookie, 0 },
- { "clear_cookies", clear_cookies, 0 },
- { "download", download, 0 }
-};
-
-void
-commands_hash(void) {
- unsigned int i;
- uzbl.behave.commands = g_hash_table_new(g_str_hash, g_str_equal);
-
- for (i = 0; i < LENGTH(cmdlist); i++)
- g_hash_table_insert(uzbl.behave.commands, (gpointer) cmdlist[i].key, &cmdlist[i]);
-}
-
-
-void
-builtins() {
- unsigned int i;
- unsigned int len = LENGTH(cmdlist);
- GString* command_list = g_string_new("");
-
- for (i = 0; i < len; i++) {
- g_string_append(command_list, cmdlist[i].key);
- g_string_append_c(command_list, ' ');
- }
-
- send_event(BUILTINS, NULL, TYPE_STR, command_list->str, NULL);
- g_string_free(command_list, TRUE);
-}
-
/* -- CORE FUNCTIONS -- */
-void
-set_var(WebKitWebView *page, GArray *argv, GString *result) {
- (void) page; (void) result;
-
- if(!argv_idx(argv, 0))
- return;
-
- gchar **split = g_strsplit(argv_idx(argv, 0), "=", 2);
- if (split[0] != NULL) {
- gchar *value = split[1] ? g_strchug(split[1]) : " ";
- set_var_value(g_strstrip(split[0]), value);
- }
- g_strfreev(split);
-}
-
-
-void
-event(WebKitWebView *page, GArray *argv, GString *result) {
- (void) page; (void) result;
- GString *event_name;
- gchar **split = NULL;
-
- if(!argv_idx(argv, 0))
- return;
-
- split = g_strsplit(argv_idx(argv, 0), " ", 2);
- if(split[0])
- event_name = g_string_ascii_up(g_string_new(split[0]));
- else
- return;
-
- send_event(0, event_name->str, TYPE_FORMATTEDSTR, split[1] ? split[1] : "", NULL);
-
- g_string_free(event_name, TRUE);
- g_strfreev(split);
-}
-
-void
-print(WebKitWebView *page, GArray *argv, GString *result) {
- (void) page; (void) result;
- gchar* buf;
-
- if(!result)
- return;
-
- buf = expand(argv_idx(argv, 0), 0);
- g_string_assign(result, buf);
- g_free(buf);
-}
-
-void
-hardcopy(WebKitWebView *page, GArray *argv, GString *result) {
- (void) argv;
- (void) result;
-
- webkit_web_frame_print(webkit_web_view_get_main_frame(page));
-}
-
/* just a wrapper so parse_cmd_line can be used with for_each_line_in_file */
static void
parse_cmd_line_cb(const char *line, void *user_data) {
@@ -649,140 +352,17 @@ parse_cmd_line_cb(const char *line, void *user_data) {
}
void
-include(WebKitWebView *page, GArray *argv, GString *result) {
- (void) page;
- (void) result;
- gchar *path = argv_idx(argv, 0);
-
- if(!path)
- return;
-
- if((path = find_existing_file(path))) {
- if(!for_each_line_in_file(path, parse_cmd_line_cb, NULL)) {
- gchar *tmp = g_strdup_printf("File %s can not be read.", path);
- send_event(COMMAND_ERROR, NULL, TYPE_STR, tmp, NULL);
- g_free(tmp);
- }
-
- send_event(FILE_INCLUDED, NULL, TYPE_STR, path, NULL);
- g_free(path);
- }
-}
-
-void
-show_inspector(WebKitWebView *page, GArray *argv, GString *result) {
- (void) page; (void) argv; (void) result;
-
- webkit_web_inspector_show(uzbl.gui.inspector);
-}
-
-void
-add_cookie(WebKitWebView *page, GArray *argv, GString *result) {
- (void) page; (void) result;
- gchar *host, *path, *name, *value;
- gboolean secure = 0;
- SoupDate *expires = NULL;
-
- if(argv->len != 6)
- return;
-
- // Parse with same syntax as ADD_COOKIE event
- host = argv_idx (argv, 0);
- path = argv_idx (argv, 1);
- name = argv_idx (argv, 2);
- value = argv_idx (argv, 3);
- secure = strcmp (argv_idx (argv, 4), "https") == 0;
- if (strlen (argv_idx (argv, 5)) != 0)
- expires = soup_date_new_from_time_t (
- strtoul (argv_idx (argv, 5), NULL, 10));
-
- // Create new cookie
- SoupCookie * cookie = soup_cookie_new (name, value, host, path, -1);
- soup_cookie_set_secure (cookie, secure);
- if (expires)
- soup_cookie_set_expires (cookie, expires);
-
- // Add cookie to jar
- uzbl.net.soup_cookie_jar->in_manual_add = 1;
- soup_cookie_jar_add_cookie (SOUP_COOKIE_JAR (uzbl.net.soup_cookie_jar), cookie);
- uzbl.net.soup_cookie_jar->in_manual_add = 0;
-}
-
-void
-delete_cookie(WebKitWebView *page, GArray *argv, GString *result) {
- (void) page; (void) result;
-
- if(argv->len < 4)
- return;
-
- SoupCookie * cookie = soup_cookie_new (
- argv_idx (argv, 2),
- argv_idx (argv, 3),
- argv_idx (argv, 0),
- argv_idx (argv, 1),
- 0);
-
- uzbl.net.soup_cookie_jar->in_manual_add = 1;
- soup_cookie_jar_delete_cookie (SOUP_COOKIE_JAR (uzbl.net.soup_cookie_jar), cookie);
- uzbl.net.soup_cookie_jar->in_manual_add = 0;
-}
-
-
-void
-clear_cookies(WebKitWebView *page, GArray *argv, GString *result) {
- (void) page; (void) argv; (void) result;
-
- // Replace the current cookie jar with a new empty jar
- soup_session_remove_feature (uzbl.net.soup_session,
- SOUP_SESSION_FEATURE (uzbl.net.soup_cookie_jar));
- g_object_unref (G_OBJECT (uzbl.net.soup_cookie_jar));
- uzbl.net.soup_cookie_jar = uzbl_cookie_jar_new ();
- soup_session_add_feature(uzbl.net.soup_session,
- SOUP_SESSION_FEATURE (uzbl.net.soup_cookie_jar));
-}
-
-void
-download(WebKitWebView *web_view, GArray *argv, GString *result) {
- (void) result;
-
- const gchar *uri = argv_idx(argv, 0);
- const gchar *destination = NULL;
- if(argv->len > 1)
- destination = argv_idx(argv, 1);
-
- WebKitNetworkRequest *req = webkit_network_request_new(uri);
- WebKitDownload *download = webkit_download_new(req);
-
- download_cb(web_view, download, destination);
-
- if(webkit_download_get_destination_uri(download))
- webkit_download_start(download);
- else
- g_object_unref(download);
-
- g_object_unref(req);
-}
-
-void
-act_dump_config() {
- dump_config();
-}
-
-void
-act_dump_config_as_events() {
- dump_config_as_events();
-}
-
-void
-load_uri(WebKitWebView *web_view, GArray *argv, GString *result) {
- (void) web_view; (void) result;
- gchar * uri = argv_idx(argv, 0);
- set_var_value("uri", uri ? uri : "");
+run_command_file(const gchar *path) {
+ if(!for_each_line_in_file(path, parse_cmd_line_cb, NULL)) {
+ gchar *tmp = g_strdup_printf("File %s can not be read.", path);
+ send_event(COMMAND_ERROR, NULL, TYPE_STR, tmp, NULL);
+ g_free(tmp);
+ }
}
/* Javascript*/
void
-eval_js(WebKitWebView * web_view, gchar *script, GString *result, const char *file) {
+eval_js(WebKitWebView * web_view, const gchar *script, GString *result, const char *file) {
WebKitWebFrame *frame;
JSGlobalContextRef context;
JSObjectRef globalobject;
@@ -861,51 +441,16 @@ eval_js(WebKitWebView * web_view, gchar *script, GString *result, const char *fi
}
void
-run_js (WebKitWebView * web_view, GArray *argv, GString *result) {
- if (argv_idx(argv, 0))
- eval_js(web_view, argv_idx(argv, 0), result, "(command)");
-}
-
-void
-run_external_js (WebKitWebView * web_view, GArray *argv, GString *result) {
- (void) result;
- gchar *path = NULL;
-
- if (argv_idx(argv, 0) &&
- ((path = find_existing_file(argv_idx(argv, 0)))) ) {
- gchar *file_contents = NULL;
-
- GIOChannel *chan = g_io_channel_new_file(path, "r", NULL);
- if (chan) {
- gsize len;
- g_io_channel_read_to_end(chan, &file_contents, &len, NULL);
- g_io_channel_unref (chan);
- }
-
- if (uzbl.state.verbose)
- printf ("External JavaScript file %s loaded\n", argv_idx(argv, 0));
-
- gchar *js = str_replace("%s", argv_idx (argv, 1) ? argv_idx (argv, 1) : "", file_contents);
- g_free (file_contents);
-
- eval_js (web_view, js, result, path);
- g_free (js);
- g_free(path);
- }
-}
-
-void
-search_text (WebKitWebView *page, GArray *argv, const gboolean forward) {
- if (argv_idx(argv, 0) && (*argv_idx(argv, 0) != '\0')) {
- if (g_strcmp0 (uzbl.state.searchtx, argv_idx(argv, 0)) != 0) {
+search_text (WebKitWebView *page, const gchar *key, const gboolean forward) {
+ if (key && (*key != '\0')) {
+ if (g_strcmp0 (uzbl.state.searchtx, key) != 0) {
webkit_web_view_unmark_text_matches (page);
- webkit_web_view_mark_text_matches (page, argv_idx(argv, 0), FALSE, 0);
+ webkit_web_view_mark_text_matches (page, key, FALSE, 0);
g_free (uzbl.state.searchtx);
- uzbl.state.searchtx = g_strdup(argv_idx(argv, 0));
+ uzbl.state.searchtx = g_strdup (key);
}
}
-
if (uzbl.state.searchtx) {
if (uzbl.state.verbose)
printf ("Searching: %s\n", uzbl.state.searchtx);
@@ -915,61 +460,6 @@ search_text (WebKitWebView *page, GArray *argv, const gboolean forward) {
}
void
-search_clear(WebKitWebView *page, GArray *argv, GString *result) {
- (void) argv;
- (void) result;
-
- webkit_web_view_unmark_text_matches (page);
- g_free(uzbl.state.searchtx);
- uzbl.state.searchtx = NULL;
-}
-
-void
-search_forward_text (WebKitWebView *page, GArray *argv, GString *result) {
- (void) result;
- search_text(page, argv, TRUE);
-}
-
-void
-search_reverse_text(WebKitWebView *page, GArray *argv, GString *result) {
- (void) result;
- search_text(page, argv, FALSE);
-}
-
-void
-dehilight(WebKitWebView *page, GArray *argv, GString *result) {
- (void) argv; (void) result;
- webkit_web_view_set_highlight_text_matches (page, FALSE);
-}
-
-void
-chain(WebKitWebView *page, GArray *argv, GString *result) {
- (void) page;
- guint i = 0;
- const gchar *cmd;
- GString *r = g_string_new ("");
- while ((cmd = argv_idx(argv, i++))) {
- GArray *a = g_array_new (TRUE, FALSE, sizeof(gchar*));
- const CommandInfo *c = parse_command_parts(cmd, a);
- if (c)
- run_parsed_command(c, a, r);
- g_array_free (a, TRUE);
- }
- if(result)
- g_string_assign (result, r->str);
-
- g_string_free(r, TRUE);
-}
-
-void
-close_uzbl (WebKitWebView *page, GArray *argv, GString *result) {
- (void)page;
- (void)argv;
- (void)result;
- gtk_main_quit ();
-}
-
-void
sharg_append(GArray *a, const gchar *str) {
const gchar *s = (str ? str : "");
g_array_append_val(a, s);
@@ -1063,12 +553,16 @@ split_quoted(const gchar* src, const gboolean unquote) {
void
spawn(GArray *argv, GString *result, gboolean exec) {
gchar *path = NULL;
- gchar *arg_car = argv_idx(argv, 0);
- const gchar **arg_cdr = &g_array_index(argv, const gchar *, 1);
- if (arg_car && (path = find_existing_file(arg_car))) {
+ if (!argv_idx(argv, 0))
+ return;
+
+ const gchar **args = &g_array_index(argv, const gchar *, 1);
+
+ path = find_existing_file(argv_idx(argv, 0));
+ if(path) {
gchar *r = NULL;
- run_command(path, arg_cdr, result != NULL, result ? &r : NULL);
+ run_command(path, args, result != NULL, result ? &r : NULL);
if(result) {
g_string_assign(result, r);
// run each line of output from the program as a command
@@ -1084,33 +578,12 @@ spawn(GArray *argv, GString *result, gboolean exec) {
}
g_free(r);
g_free(path);
+ } else {
+ g_printerr ("Failed to spawn child process: %s not found\n", argv_idx(argv, 0));
}
}
void
-spawn_async(WebKitWebView *web_view, GArray *argv, GString *result) {
- (void)web_view; (void)result;
- spawn(argv, NULL, FALSE);
-}
-
-void
-spawn_sync(WebKitWebView *web_view, GArray *argv, GString *result) {
- (void)web_view;
- spawn(argv, result, FALSE);
-}
-
-void
-spawn_sync_exec(WebKitWebView *web_view, GArray *argv, GString *result) {
- (void)web_view;
- if(!result) {
- GString *force_result = g_string_new("");
- spawn(argv, force_result, TRUE);
- g_string_free (force_result, TRUE);
- } else
- spawn(argv, result, TRUE);
-}
-
-void
spawn_sh(GArray *argv, GString *result) {
if (!uzbl.behave.shell_cmd) {
g_printerr ("spawn_sh: shell_cmd is not set!\n");
@@ -1141,18 +614,6 @@ spawn_sh(GArray *argv, GString *result) {
}
void
-spawn_sh_async(WebKitWebView *web_view, GArray *argv, GString *result) {
- (void)web_view; (void)result;
- spawn_sh(argv, NULL);
-}
-
-void
-spawn_sh_sync(WebKitWebView *web_view, GArray *argv, GString *result) {
- (void)web_view; (void)result;
- spawn_sh(argv, result);
-}
-
-void
run_parsed_command(const CommandInfo *c, GArray *a, GString *result) {
/* send the COMMAND_EXECUTED event, except for set and event/request commands */
if(strcmp("set", c->key) &&
@@ -1253,33 +714,6 @@ parse_command(const char *cmd, const char *params, GString *result) {
}
}
-
-void
-move_statusbar() {
- if (!uzbl.gui.scrolled_win &&
- !uzbl.gui.mainbar)
- return;
-
- g_object_ref(uzbl.gui.scrolled_win);
- g_object_ref(uzbl.gui.mainbar);
- gtk_container_remove(GTK_CONTAINER(uzbl.gui.vbox), uzbl.gui.scrolled_win);
- gtk_container_remove(GTK_CONTAINER(uzbl.gui.vbox), uzbl.gui.mainbar);
-
- if(uzbl.behave.status_top) {
- gtk_box_pack_start (GTK_BOX (uzbl.gui.vbox), uzbl.gui.mainbar, FALSE, TRUE, 0);
- gtk_box_pack_start (GTK_BOX (uzbl.gui.vbox), uzbl.gui.scrolled_win, TRUE, TRUE, 0);
- }
- else {
- gtk_box_pack_start (GTK_BOX (uzbl.gui.vbox), uzbl.gui.scrolled_win, TRUE, TRUE, 0);
- gtk_box_pack_start (GTK_BOX (uzbl.gui.vbox), uzbl.gui.mainbar, FALSE, TRUE, 0);
- }
- g_object_unref(uzbl.gui.scrolled_win);
- g_object_unref(uzbl.gui.mainbar);
- if (!uzbl.state.plug_mode)
- gtk_widget_grab_focus (GTK_WIDGET (uzbl.gui.web_view));
- return;
-}
-
gboolean
valid_name(const gchar* name) {
char *invalid_chars = "\t^°!\"§$%&/()=?'`'+~*'#-:,;@<>| \\{}[]¹²³¼½";
@@ -1287,97 +721,6 @@ valid_name(const gchar* name) {
}
void
-send_set_var_event(const char *name, const uzbl_cmdprop *c) {
- /* check for the variable type */
- switch(c->type) {
- case TYPE_STR:
- send_event (VARIABLE_SET, NULL,
- TYPE_NAME, name,
- TYPE_NAME, "str",
- TYPE_STR, *c->ptr.s ? *c->ptr.s : " ",
- NULL);
- break;
- case TYPE_INT:
- send_event (VARIABLE_SET, NULL,
- TYPE_NAME, name,
- TYPE_NAME, "int",
- TYPE_INT, *c->ptr.i,
- NULL);
- break;
- case TYPE_FLOAT:
- send_event (VARIABLE_SET, NULL,
- TYPE_NAME, name,
- TYPE_NAME, "float",
- TYPE_FLOAT, *c->ptr.f,
- NULL);
- break;
- default:
- g_assert_not_reached();
- }
-}
-
-gboolean
-set_var_value(const gchar *name, gchar *val) {
- uzbl_cmdprop *c = NULL;
- char *endp = NULL;
- char *buf = NULL;
-
- g_assert(val != NULL);
-
- if( (c = g_hash_table_lookup(uzbl.comm.proto_var, name)) ) {
- if(!c->writeable) return FALSE;
-
- switch(c->type) {
- case TYPE_STR:
- buf = g_strdup(val);
- g_free(*c->ptr.s);
- *c->ptr.s = buf;
- break;
- case TYPE_INT:
- *c->ptr.i = (int)strtoul(val, &endp, 10);
- break;
- case TYPE_FLOAT:
- *c->ptr.f = strtod(val, &endp);
- break;
- default:
- g_assert_not_reached();
- }
-
- send_set_var_event(name, c);
-
- /* invoke a command specific function */
- if(c->func) c->func();
- } else {
- /* check wether name violates our naming scheme */
- if(!valid_name(name)) {
- if (uzbl.state.verbose)
- printf("Invalid variable name: %s\n", name);
- return FALSE;
- }
-
- /* custom vars */
- c = g_malloc(sizeof(uzbl_cmdprop));
- c->type = TYPE_STR;
- c->dump = 0;
- c->func = NULL;
- c->writeable = 1;
- buf = g_strdup(val);
- c->ptr.s = g_malloc(sizeof(char *));
- *c->ptr.s = buf;
- g_hash_table_insert(uzbl.comm.proto_var,
- g_strdup(name), (gpointer) c);
-
- send_event (VARIABLE_SET, NULL,
- TYPE_NAME, name,
- TYPE_NAME, "str",
- TYPE_STR, buf,
- NULL);
- }
- update_title();
- return TRUE;
-}
-
-void
parse_cmd_line(const char *ctl_line, GString *result) {
gchar *work_string = g_strdup(ctl_line);
@@ -1407,19 +750,13 @@ update_title(void) {
if (b->show_status) {
title_format = b->title_format_short;
- /* Left side */
- if (b->status_format && GTK_IS_LABEL(uzbl.gui.mainbar_label_left)) {
- gchar *parsed = expand(b->status_format, 0);
- gtk_label_set_markup(GTK_LABEL(uzbl.gui.mainbar_label_left), parsed);
- g_free(parsed);
- }
+ gchar *parsed = expand(b->status_format, 0);
+ uzbl_status_bar_update_left(uzbl.gui.status_bar, parsed);
+ g_free(parsed);
- /* Right side */
- if (b->status_format_right && GTK_IS_LABEL(uzbl.gui.mainbar_label_right)) {
- gchar *parsed = expand(b->status_format_right, 0);
- gtk_label_set_markup(GTK_LABEL(uzbl.gui.mainbar_label_right), parsed);
- g_free(parsed);
- }
+ parsed = expand(b->status_format_right, 0);
+ uzbl_status_bar_update_right(uzbl.gui.status_bar, parsed);
+ g_free(parsed);
}
/* Update window title */
@@ -1443,12 +780,6 @@ create_scrolled_win() {
g->web_view = WEBKIT_WEB_VIEW(webkit_web_view_new());
g->scrolled_win = gtk_scrolled_window_new(NULL, NULL);
- gtk_scrolled_window_set_policy(
- GTK_SCROLLED_WINDOW(g->scrolled_win),
- GTK_POLICY_NEVER,
- GTK_POLICY_NEVER
- );
-
gtk_container_add(
GTK_CONTAINER(g->scrolled_win),
GTK_WIDGET(g->web_view)
@@ -1476,61 +807,23 @@ create_scrolled_win() {
"signal::populate-popup", (GCallback)populate_popup_cb, NULL,
"signal::focus-in-event", (GCallback)focus_cb, NULL,
"signal::focus-out-event", (GCallback)focus_cb, NULL,
+ "signal::window-object-cleared", (GCallback)window_object_cleared_cb,NULL,
NULL);
}
GtkWidget*
-create_mainbar() {
- GUI *g = &uzbl.gui;
-
- g->mainbar = gtk_hbox_new (FALSE, 0);
-
- /* Left panel */
- g->mainbar_label_left = gtk_label_new ("");
- gtk_label_set_selectable(GTK_LABEL(g->mainbar_label_left), TRUE);
- gtk_misc_set_alignment (GTK_MISC(g->mainbar_label_left), 0, 0);
- gtk_misc_set_padding (GTK_MISC(g->mainbar_label_left), 2, 2);
-
- gtk_box_pack_start (GTK_BOX (g->mainbar), g->mainbar_label_left, FALSE, FALSE, 0);
-
- /* Right panel */
- g->mainbar_label_right = gtk_label_new ("");
- gtk_label_set_selectable(GTK_LABEL(g->mainbar_label_right), TRUE);
- gtk_misc_set_alignment (GTK_MISC(g->mainbar_label_right), 1, 0);
- gtk_misc_set_padding (GTK_MISC(g->mainbar_label_right), 2, 2);
- gtk_label_set_ellipsize(GTK_LABEL(g->mainbar_label_right), PANGO_ELLIPSIZE_START);
-
- gtk_box_pack_start (GTK_BOX (g->mainbar), g->mainbar_label_right, TRUE, TRUE, 0);
-
- g_object_connect((GObject*)g->mainbar,
- "signal::key-press-event", (GCallback)key_press_cb, NULL,
- "signal::key-release-event", (GCallback)key_release_cb, NULL,
- NULL);
-
- return g->mainbar;
-}
-
-
-GtkWidget*
create_window() {
GtkWidget* window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
gtk_window_set_default_size (GTK_WINDOW (window), 800, 600);
- gtk_widget_set_name (window, "Uzbl browser");
- gtk_window_set_title(GTK_WINDOW(window), "Uzbl browser");
+ gtk_widget_set_name (window, "Uzbl");
+ gtk_window_set_title(GTK_WINDOW(window), "Uzbl");
#if GTK_CHECK_VERSION(3,0,0)
- gtk_window_set_has_resize_grip (window, FALSE);
+ gtk_window_set_has_resize_grip (GTK_WINDOW (window), FALSE);
#endif
- /* if the window has been made small, it shouldn't try to resize itself due
- * to a long statusbar. */
- GdkGeometry hints;
- hints.min_height = -1;
- hints.min_width = 1;
- gtk_window_set_geometry_hints (GTK_WINDOW (window), window, &hints, GDK_HINT_MIN_SIZE);
-
g_signal_connect (G_OBJECT (window), "destroy", G_CALLBACK (destroy_cb), NULL);
g_signal_connect (G_OBJECT (window), "configure-event", G_CALLBACK (configure_event_cb), NULL);
@@ -1540,6 +833,7 @@ create_window() {
GtkPlug*
create_plug() {
+ if(uzbl.state.embed) uzbl.state.socket_id = 0;
GtkPlug* plug = GTK_PLUG (gtk_plug_new (uzbl.state.socket_id));
g_signal_connect (G_OBJECT (plug), "destroy", G_CALLBACK (destroy_cb), NULL);
g_signal_connect (G_OBJECT (plug), "key-press-event", G_CALLBACK (key_press_cb), NULL);
@@ -1553,7 +847,7 @@ settings_init () {
State* s = &uzbl.state;
Network* n = &uzbl.net;
int i;
-
+
/* Load default config */
for (i = 0; default_config[i].command != NULL; i++) {
parse_cmd_line(default_config[i].command, NULL);
@@ -1570,11 +864,7 @@ settings_init () {
/* Load config file, if any */
if (s->config_file) {
- if (!for_each_line_in_file(s->config_file, parse_cmd_line_cb, NULL)) {
- gchar *tmp = g_strdup_printf("File %s can not be read.", s->config_file);
- send_event(COMMAND_ERROR, NULL, TYPE_STR, tmp, NULL);
- g_free(tmp);
- }
+ run_command_file(s->config_file);
g_setenv("UZBL_CONFIG", s->config_file, TRUE);
} else if (uzbl.state.verbose)
printf ("No configuration file loaded.\n");
@@ -1641,41 +931,6 @@ void handle_authentication (SoupSession *session, SoupMessage *msg, SoupAuth *au
}
void
-dump_var_hash(gpointer k, gpointer v, gpointer ud) {
- (void) ud;
- uzbl_cmdprop *c = v;
-
- if(!c->dump)
- return;
-
- if(c->type == TYPE_STR)
- printf("set %s = %s\n", (char *)k, *c->ptr.s ? *c->ptr.s : " ");
- else if(c->type == TYPE_INT)
- printf("set %s = %d\n", (char *)k, *c->ptr.i);
- else if(c->type == TYPE_FLOAT)
- printf("set %s = %f\n", (char *)k, *c->ptr.f);
-}
-
-void
-dump_config() {
- g_hash_table_foreach(uzbl.comm.proto_var, dump_var_hash, NULL);
-}
-
-void
-dump_var_hash_as_event(gpointer k, gpointer v, gpointer ud) {
- (void) ud;
- uzbl_cmdprop *c = v;
-
- if(c->dump)
- send_set_var_event(k, c);
-}
-
-void
-dump_config_as_events() {
- g_hash_table_foreach(uzbl.comm.proto_var, dump_var_hash_as_event, NULL);
-}
-
-void
retrieve_geometry() {
int w, h, x, y;
GString *buf = g_string_new("");
@@ -1690,28 +945,6 @@ retrieve_geometry() {
uzbl.gui.geometry = g_string_free(buf, FALSE);
}
-void
-set_webview_scroll_adjustments() {
-#if GTK_CHECK_VERSION(2,91,0)
- gtk_scrollable_set_hadjustment (GTK_SCROLLABLE(uzbl.gui.web_view), uzbl.gui.bar_h);
- gtk_scrollable_set_vadjustment (GTK_SCROLLABLE(uzbl.gui.web_view), uzbl.gui.bar_v);
-#else
- gtk_widget_set_scroll_adjustments (GTK_WIDGET (uzbl.gui.web_view),
- uzbl.gui.bar_h, uzbl.gui.bar_v);
-#endif
-
- g_object_connect((GObject*)uzbl.gui.bar_v,
- "signal::value-changed", (GCallback)scroll_vert_cb, NULL,
- "signal::changed", (GCallback)scroll_vert_cb, NULL,
- NULL);
-
- g_object_connect((GObject*)uzbl.gui.bar_h,
- "signal::value-changed", (GCallback)scroll_horiz_cb, NULL,
- "signal::changed", (GCallback)scroll_horiz_cb, NULL,
- NULL);
-}
-
-
/* Set up gtk, gobject, variable defaults and other things that tests and other
* external applications need to do anyhow */
void
@@ -1746,7 +979,7 @@ initialize(int argc, char** argv) {
}
/* Embedded mode */
- if (uzbl.state.socket_id)
+ if (uzbl.state.socket_id || uzbl.state.embed)
uzbl.state.plug_mode = TRUE;
if (!g_thread_supported())
@@ -1759,68 +992,47 @@ initialize(int argc, char** argv) {
fprintf(stderr, "uzbl: error hooking %d: %s\n", SIGALRM, strerror(errno));
event_buffer_timeout(10);
-
/* HTTP client */
uzbl.net.soup_session = webkit_get_default_session();
uzbl.net.soup_cookie_jar = uzbl_cookie_jar_new();
soup_session_add_feature(uzbl.net.soup_session, SOUP_SESSION_FEATURE(uzbl.net.soup_cookie_jar));
-
commands_hash();
- create_var_to_name_hash();
+ variables_hash();
/* GUI */
gtk_init(&argc, &argv);
- create_mainbar();
- create_scrolled_win();
- uzbl.gui.vbox = gtk_vbox_new(FALSE, 0);
- gtk_box_pack_start(GTK_BOX(uzbl.gui.vbox), uzbl.gui.scrolled_win, TRUE, TRUE, 0);
- gtk_box_pack_start(GTK_BOX(uzbl.gui.vbox), uzbl.gui.mainbar, FALSE, TRUE, 0);
-}
+ /* set up the status bar */
+ uzbl.gui.status_bar = uzbl_status_bar_new();
+ /* set up signal handlers (it's not great to have this here...) */
+ g_object_connect((GObject*)uzbl.gui.status_bar,
+ "signal::key-press-event", (GCallback)key_press_cb, NULL,
+ "signal::key-release-event", (GCallback)key_release_cb, NULL,
+ NULL);
-void
-load_uri_imp(gchar *uri) {
- GString* newuri;
- SoupURI* soup_uri;
-
- /* Strip leading whitespaces */
- while (*uri) {
- if (!isspace(*uri)) break;
- uri++;
- }
+ /*
+ g_object_connect((GObject*)UZBL_STATUS_BAR(uzbl.gui.status_bar)->label_left,
+ "signal::key-press-event", (GCallback)key_press_cb, NULL,
+ "signal::key-release-event", (GCallback)key_release_cb, NULL,
+ NULL);
- if (g_strstr_len (uri, 11, "javascript:") != NULL) {
- eval_js(uzbl.gui.web_view, uri, NULL, "javascript:");
- return;
- }
+ g_object_connect((GObject*)(UZBL_STATUS_BAR(uzbl.gui.status_bar)->label_right),
+ "signal::key-press-event", (GCallback)key_press_cb, NULL,
+ "signal::key-release-event", (GCallback)key_release_cb, NULL,
+ NULL);
+ */
- newuri = g_string_new (uri);
- soup_uri = soup_uri_new(uri);
-
- if (!soup_uri) {
- gchar* fullpath;
- if (g_path_is_absolute (newuri->str))
- fullpath = newuri->str;
- else {
- gchar* wd = g_get_current_dir ();
- fullpath = g_build_filename (wd, newuri->str, NULL);
- g_free(wd);
- }
- struct stat stat_result;
- if (! g_stat(fullpath, &stat_result))
- g_string_printf (newuri, "file://%s", fullpath);
- else
- g_string_prepend (newuri, "http://");
- } else {
- soup_uri_free(soup_uri);
- }
+ /* create the main window itself */
+ create_scrolled_win();
+
+ /* pack the window and the status bar */
+ uzbl.gui.vbox = gtk_vbox_new(FALSE, 0);
- /* if we do handle cookies, ask our handler for them */
- webkit_web_view_load_uri (uzbl.gui.web_view, newuri->str);
- g_string_free (newuri, TRUE);
+ gtk_box_pack_start(GTK_BOX(uzbl.gui.vbox), uzbl.gui.scrolled_win, TRUE, TRUE, 0);
+ gtk_box_pack_start(GTK_BOX(uzbl.gui.vbox), uzbl.gui.status_bar, FALSE, TRUE, 0);
}
@@ -1834,7 +1046,6 @@ main (int argc, char* argv[]) {
if (uzbl.state.plug_mode) {
uzbl.gui.plug = create_plug();
gtk_container_add (GTK_CONTAINER (uzbl.gui.plug), uzbl.gui.vbox);
- gtk_widget_show_all (GTK_WIDGET (uzbl.gui.plug));
/* in xembed mode the window has no unique id and thus
* socket/fifo names aren't unique either.
* we use a custom randomizer to create a random id
@@ -1844,12 +1055,13 @@ main (int argc, char* argv[]) {
srand((unsigned int)tv.tv_sec*tv.tv_usec);
uzbl.xwin = rand();
}
-
+
/* Windowed mode */
else {
uzbl.gui.main_window = create_window();
gtk_container_add (GTK_CONTAINER (uzbl.gui.main_window), uzbl.gui.vbox);
- gtk_widget_show_all (uzbl.gui.main_window);
+ /* We need to ensure there is a window, before we can get XID */
+ gtk_widget_realize (GTK_WIDGET (uzbl.gui.main_window));
uzbl.xwin = GDK_WINDOW_XID (gtk_widget_get_window (GTK_WIDGET (uzbl.gui.main_window)));
@@ -1857,12 +1069,18 @@ main (int argc, char* argv[]) {
}
/* Scrolling */
- uzbl.gui.scbar_v = (GtkScrollbar*) gtk_vscrollbar_new (NULL);
- uzbl.gui.bar_v = gtk_range_get_adjustment((GtkRange*) uzbl.gui.scbar_v);
- uzbl.gui.scbar_h = (GtkScrollbar*) gtk_hscrollbar_new (NULL);
- uzbl.gui.bar_h = gtk_range_get_adjustment((GtkRange*) uzbl.gui.scbar_h);
+ uzbl.gui.bar_h = gtk_scrolled_window_get_hadjustment (GTK_SCROLLED_WINDOW (uzbl.gui.scrolled_win));
+ uzbl.gui.bar_v = gtk_scrolled_window_get_vadjustment (GTK_SCROLLED_WINDOW (uzbl.gui.scrolled_win));
- set_webview_scroll_adjustments();
+ g_object_connect(G_OBJECT (uzbl.gui.bar_v),
+ "signal::value-changed", (GCallback)scroll_vert_cb, NULL,
+ "signal::changed", (GCallback)scroll_vert_cb, NULL,
+ NULL);
+
+ g_object_connect(G_OBJECT (uzbl.gui.bar_h),
+ "signal::value-changed", (GCallback)scroll_horiz_cb, NULL,
+ "signal::changed", (GCallback)scroll_horiz_cb, NULL,
+ NULL);
gchar *xwin = g_strdup_printf("%d", (int)uzbl.xwin);
g_setenv("UZBL_XID", xwin, TRUE);
@@ -1886,7 +1104,7 @@ main (int argc, char* argv[]) {
/* Check uzbl is in window mode before getting/setting geometry */
if (uzbl.gui.main_window) {
if (uzbl.gui.geometry)
- cmd_set_geometry();
+ set_geometry();
else
retrieve_geometry();
}
@@ -1902,7 +1120,7 @@ main (int argc, char* argv[]) {
/* Update status bar */
if (!uzbl.behave.show_status)
- gtk_widget_hide(uzbl.gui.mainbar);
+ gtk_widget_hide(uzbl.gui.status_bar);
else
update_title();
@@ -1918,11 +1136,18 @@ main (int argc, char* argv[]) {
g_free(uri_override);
}
+ /* Finally show the window */
+ if (uzbl.gui.main_window) {
+ gtk_widget_show_all (uzbl.gui.main_window);
+ } else {
+ gtk_widget_show_all (GTK_WIDGET (uzbl.gui.plug));
+ }
+
/* Verbose feedback */
if (uzbl.state.verbose) {
printf("Uzbl start location: %s\n", argv[0]);
if (uzbl.state.socket_id)
- printf("plug_id %i\n", gtk_plug_get_id(uzbl.gui.plug));
+ printf("plug_id %i\n", (int)gtk_plug_get_id(uzbl.gui.plug));
else
printf("window_id %i\n",(int) uzbl.xwin);
printf("pid %i\n", getpid ());
diff --git a/src/uzbl-core.h b/src/uzbl-core.h
index be8fccd..c84380e 100644
--- a/src/uzbl-core.h
+++ b/src/uzbl-core.h
@@ -48,6 +48,8 @@
#endif
#include "cookie-jar.h"
+#include "commands.h"
+#include "status-bar.h"
#define LENGTH(x) (sizeof x / sizeof x[0])
@@ -62,21 +64,17 @@ typedef struct {
GtkWidget* vbox;
/* Mainbar */
- GtkWidget* mainbar;
- GtkWidget* mainbar_label_left;
- GtkWidget* mainbar_label_right;
+ GtkWidget* status_bar;
/* Scrolling */
- GtkScrollbar* scbar_v; /* Horizontal and Vertical Scrollbar */
- GtkScrollbar* scbar_h; /* (These are still hidden) */
GtkAdjustment* bar_v; /* Information about document length */
GtkAdjustment* bar_h; /* and scrolling position */
- int scrollbars_visible;
/* Web page */
WebKitWebView* web_view;
gchar* main_title;
gchar* icon;
+ gchar* window_role;
/* WebInspector */
GtkWidget* inspector_window;
@@ -92,7 +90,6 @@ enum { FIFO, SOCKET};
typedef struct {
gchar *fifo_path;
gchar *socket_path;
- GHashTable *proto_var; /* stores (key)"variable name" -> (value)"pointer to var */
GPtrArray *connect_chan;
GPtrArray *client_chan;
@@ -109,6 +106,7 @@ typedef struct {
gchar* executable_path;
gchar* searchtx;
gboolean verbose;
+ gboolean embed;
GdkEventButton* last_button;
gchar* last_result;
gboolean plug_mode;
@@ -181,6 +179,7 @@ typedef struct {
guint autoload_img;
guint autoshrink_img;
guint enable_spellcheck;
+ gchar* spellcheck_languages;
guint enable_private;
guint print_bg;
gchar* style_uri;
@@ -195,9 +194,8 @@ typedef struct {
/* command list: (key)name -> (value)Command */
GHashTable* commands;
-
- /* event lookup: (key)event_id -> (value)event_name */
- GHashTable *event_lookup;
+ /* variables: (key)name -> (value)uzbl_cmdprop */
+ GHashTable *proto_var;
} Behaviour;
@@ -229,22 +227,6 @@ extern UzblCore uzbl; /* Main Uzbl object */
typedef void sigfunc(int);
-/* Uzbl variables */
-enum ptr_type {TYPE_INT = 1, TYPE_STR, TYPE_FLOAT,
- TYPE_NAME, TYPE_FORMATTEDSTR // used by send_event
-};
-typedef struct {
- enum ptr_type type;
- union {
- int *i;
- float *f;
- gchar **s;
- } ptr;
- int dump;
- int writeable;
- /*@null@*/ void (*func)(void);
-} uzbl_cmdprop;
-
/* Functions */
void clean_up(void);
void update_title(void);
@@ -253,24 +235,24 @@ void update_title(void);
void catch_sigterm(int s);
sigfunc* setup_signal(int signe, sigfunc *shandler);
-gboolean set_var_value(const gchar *name, gchar *val);
-void load_uri_imp(gchar *uri);
-void print(WebKitWebView *page, GArray *argv, GString *result);
-void commands_hash(void);
-void load_uri(WebKitWebView * web_view, GArray *argv, GString *result);
-void chain(WebKitWebView *page, GArray *argv, GString *result);
-void close_uzbl(WebKitWebView *page, GArray *argv, GString *result);
+/* Subprocess spawning */
+void spawn(GArray *argv, GString *result, gboolean exec);
+void spawn_sh(GArray *argv, GString *result);
+
+/* Configuration variables */
+gboolean valid_name(const gchar* name);
/* Running commands */
+gchar* expand(const char* s, guint recurse);
gboolean run_command(const gchar *command, const gchar **args, const gboolean sync,
char **output_stdout);
-void spawn_async(WebKitWebView *web_view, GArray *argv, GString *result);
-void spawn_sh_async(WebKitWebView *web_view, GArray *argv, GString *result);
-void spawn_sync(WebKitWebView *web_view, GArray *argv, GString *result);
-void spawn_sh_sync(WebKitWebView *web_view, GArray *argv, GString *result);
-void spawn_sync_exec(WebKitWebView *web_view, GArray *argv, GString *result);
+void run_command_file(const gchar *path);
void parse_command(const char *cmd, const char *param, GString *result);
void parse_cmd_line(const char *ctl_line, GString *result);
+const CommandInfo *
+ parse_command_parts(const gchar *line, GArray *a);
+void parse_command_arguments(const gchar *p, GArray *a, gboolean no_split);
+void run_parsed_command(const CommandInfo *c, GArray *a, GString *result);
/* Keyboard events functions */
gboolean key_press_cb(GtkWidget* window, GdkEventKey* event);
@@ -282,20 +264,13 @@ void create_scrolled_win();
GtkWidget* create_mainbar();
GtkWidget* create_window();
GtkPlug* create_plug();
-void run_handler(const gchar *act, const gchar *args);
void settings_init();
/* Search functions */
-void search_text (WebKitWebView *page, GArray *argv, const gboolean forward);
-void search_forward_text (WebKitWebView *page, GArray *argv, GString *result);
-void search_reverse_text (WebKitWebView *page, GArray *argv, GString *result);
-void search_clear(WebKitWebView *page, GArray *argv, GString *result);
-void dehilight (WebKitWebView *page, GArray *argv, GString *result);
+void search_text (WebKitWebView *page, const gchar *key, const gboolean forward);
/* Javascript functions */
-void run_js (WebKitWebView * web_view, GArray *argv, GString *result);
-void run_external_js (WebKitWebView * web_view, GArray *argv, GString *result);
-void eval_js(WebKitWebView * web_view, gchar *script, GString *result, const gchar *script_file);
+void eval_js(WebKitWebView *web_view, const gchar *script, GString *result, const gchar *script_file);
/* Network functions */
void handle_authentication (SoupSession *session,
@@ -303,55 +278,15 @@ void handle_authentication (SoupSession *session,
SoupAuth *auth,
gboolean retrying,
gpointer user_data);
-gboolean valid_name(const gchar* name);
-void set_var(WebKitWebView *page, GArray *argv, GString *result);
-void act_dump_config();
-void act_dump_config_as_events();
-void dump_var_hash(gpointer k, gpointer v, gpointer ud);
-void dump_key_hash(gpointer k, gpointer v, gpointer ud);
-void dump_config();
-void dump_config_as_events();
-void retrieve_geometry();
-void set_webview_scroll_adjustments();
-void event(WebKitWebView *page, GArray *argv, GString *result);
void init_connect_socket();
gboolean remove_socket_from_array(GIOChannel *chan);
+/* Window */
+void retrieve_geometry();
+void scroll(GtkAdjustment* bar, gchar *amount_str);
gint get_click_context();
-void hardcopy(WebKitWebView *page, GArray *argv, GString *result);
-void include(WebKitWebView *page, GArray *argv, GString *result);
-void show_inspector(WebKitWebView *page, GArray *argv, GString *result);
-void add_cookie(WebKitWebView *page, GArray *argv, GString *result);
-void delete_cookie(WebKitWebView *page, GArray *argv, GString *result);
-void clear_cookies(WebKitWebView *pag, GArray *argv, GString *result);
-void download(WebKitWebView *pag, GArray *argv, GString *result);
-void builtins();
-typedef void (*Command)(WebKitWebView*, GArray *argv, GString *result);
-
-typedef struct {
- const gchar *key;
- Command function;
- gboolean no_split;
-} CommandInfo;
-
-const CommandInfo *
-parse_command_parts(const gchar *line, GArray *a);
-
-void
-parse_command_arguments(const gchar *p, GArray *a, gboolean no_split);
-
-void
-run_parsed_command(const CommandInfo *c, GArray *a, GString *result);
-
-typedef struct {
- gchar* name;
- gchar* cmd;
- gboolean issep;
- guint context;
- WebKitHitTestResult* hittest;
-} MenuItem;
#endif
/* vi: set et ts=4: */
diff --git a/src/variables.c b/src/variables.c
new file mode 100644
index 0000000..b72c4b0
--- /dev/null
+++ b/src/variables.c
@@ -0,0 +1,618 @@
+#include "variables.h"
+#include "uzbl-core.h"
+#include "callbacks.h"
+#include "events.h"
+#include "io.h"
+#include "util.h"
+#include "type.h"
+
+void
+send_set_var_event(const char *name, const uzbl_cmdprop *c) {
+ /* check for the variable type */
+ switch(c->type) {
+ case TYPE_STR:
+ send_event (VARIABLE_SET, NULL,
+ TYPE_NAME, name,
+ TYPE_NAME, "str",
+ TYPE_STR, *c->ptr.s ? *c->ptr.s : " ",
+ NULL);
+ break;
+ case TYPE_INT:
+ send_event (VARIABLE_SET, NULL,
+ TYPE_NAME, name,
+ TYPE_NAME, "int",
+ TYPE_INT, *c->ptr.i,
+ NULL);
+ break;
+ case TYPE_FLOAT:
+ send_event (VARIABLE_SET, NULL,
+ TYPE_NAME, name,
+ TYPE_NAME, "float",
+ TYPE_FLOAT, *c->ptr.f,
+ NULL);
+ break;
+ default:
+ g_assert_not_reached();
+ }
+}
+
+void
+expand_variable(GString *buf, const gchar *name) {
+ uzbl_cmdprop* c;
+ if((c = g_hash_table_lookup(uzbl.behave.proto_var, name))) {
+ if(c->type == TYPE_STR && *c->ptr.s != NULL) {
+ g_string_append(buf, (gchar *)*c->ptr.s);
+ }
+ else if(c->type == TYPE_INT) {
+ g_string_append_printf(buf, "%d", *c->ptr.i);
+ }
+ else if(c->type == TYPE_FLOAT) {
+ g_string_append_printf(buf, "%f", *c->ptr.f);
+ }
+ }
+}
+
+gboolean
+set_var_value(const gchar *name, gchar *val) {
+ uzbl_cmdprop *c = NULL;
+ char *endp = NULL;
+ char *buf = NULL;
+
+ g_assert(val != NULL);
+
+ if( (c = g_hash_table_lookup(uzbl.behave.proto_var, name)) ) {
+ if(!c->writeable) return FALSE;
+
+ switch(c->type) {
+ case TYPE_STR:
+ buf = g_strdup(val);
+ g_free(*c->ptr.s);
+ *c->ptr.s = buf;
+ break;
+ case TYPE_INT:
+ *c->ptr.i = (int)strtoul(val, &endp, 10);
+ break;
+ case TYPE_FLOAT:
+ *c->ptr.f = strtod(val, &endp);
+ break;
+ default:
+ g_assert_not_reached();
+ }
+
+ send_set_var_event(name, c);
+
+ /* invoke a command specific function */
+ if(c->func) c->func();
+ } else {
+ /* check wether name violates our naming scheme */
+ if(!valid_name(name)) {
+ if (uzbl.state.verbose)
+ printf("Invalid variable name: %s\n", name);
+ return FALSE;
+ }
+
+ /* custom vars */
+ c = g_malloc(sizeof(uzbl_cmdprop));
+ c->type = TYPE_STR;
+ c->dump = 0;
+ c->func = NULL;
+ c->writeable = 1;
+ buf = g_strdup(val);
+ c->ptr.s = g_malloc(sizeof(char *));
+ *c->ptr.s = buf;
+ g_hash_table_insert(uzbl.behave.proto_var,
+ g_strdup(name), (gpointer) c);
+
+ send_event (VARIABLE_SET, NULL,
+ TYPE_NAME, name,
+ TYPE_NAME, "str",
+ TYPE_STR, buf,
+ NULL);
+ }
+ update_title();
+ return TRUE;
+}
+
+void
+dump_var_hash(gpointer k, gpointer v, gpointer ud) {
+ (void) ud;
+ uzbl_cmdprop *c = v;
+
+ if(!c->dump)
+ return;
+
+ if(c->type == TYPE_STR)
+ printf("set %s = %s\n", (char *)k, *c->ptr.s ? *c->ptr.s : " ");
+ else if(c->type == TYPE_INT)
+ printf("set %s = %d\n", (char *)k, *c->ptr.i);
+ else if(c->type == TYPE_FLOAT)
+ printf("set %s = %f\n", (char *)k, *c->ptr.f);
+}
+
+void
+dump_config() {
+ g_hash_table_foreach(uzbl.behave.proto_var, dump_var_hash, NULL);
+}
+
+void
+dump_var_hash_as_event(gpointer k, gpointer v, gpointer ud) {
+ (void) ud;
+ uzbl_cmdprop *c = v;
+
+ if(c->dump)
+ send_set_var_event(k, c);
+}
+
+void
+dump_config_as_events() {
+ g_hash_table_foreach(uzbl.behave.proto_var, dump_var_hash_as_event, NULL);
+}
+
+/* is the given string made up entirely of decimal digits? */
+gboolean
+string_is_integer(const char *s) {
+ return (strspn(s, "0123456789") == strlen(s));
+}
+
+
+GObject*
+view_settings() {
+ return G_OBJECT(webkit_web_view_get_settings(uzbl.gui.web_view));
+}
+
+void
+uri_change_cb (WebKitWebView *web_view, GParamSpec param_spec) {
+ (void) param_spec;
+
+ g_free (uzbl.state.uri);
+ g_object_get (web_view, "uri", &uzbl.state.uri, NULL);
+ g_setenv("UZBL_URI", uzbl.state.uri, TRUE);
+
+ if(GTK_IS_WIDGET(uzbl.gui.main_window)) {
+ gdk_property_change(
+ gtk_widget_get_window (GTK_WIDGET (uzbl.gui.main_window)),
+ gdk_atom_intern_static_string("UZBL_URI"),
+ gdk_atom_intern_static_string("STRING"),
+ 8,
+ GDK_PROP_MODE_REPLACE,
+ (unsigned char *)uzbl.state.uri,
+ strlen(uzbl.state.uri));
+ }
+}
+
+void
+cmd_load_uri() {
+ const gchar *uri = uzbl.state.uri;
+
+ gchar *newuri;
+ SoupURI *soup_uri;
+
+ /* Strip leading whitespaces */
+ while (*uri && isspace(*uri))
+ uri++;
+
+ /* evaluate javascript: URIs */
+ if (!strncmp (uri, "javascript:", 11)) {
+ eval_js(uzbl.gui.web_view, uri, NULL, "javascript:");
+ return;
+ }
+
+ /* attempt to parse the URI */
+ soup_uri = soup_uri_new(uri);
+
+ if (!soup_uri) {
+ /* it's not a valid URI, maybe it's a path on the filesystem. */
+ const gchar *fullpath;
+ if (g_path_is_absolute (uri))
+ fullpath = uri;
+ else {
+ gchar *wd = g_get_current_dir ();
+ fullpath = g_build_filename (wd, uri, NULL);
+ g_free(wd);
+ }
+
+ struct stat stat_result;
+ if (! g_stat(fullpath, &stat_result))
+ newuri = g_strconcat("file://", fullpath, NULL);
+ else
+ newuri = g_strconcat("http://", uri, NULL);
+ } else {
+ if(soup_uri->host == NULL && string_is_integer(soup_uri->path))
+ /* the user probably typed in a host:port without a scheme */
+ newuri = g_strconcat("http://", uri, NULL);
+ else
+ newuri = g_strdup(uri);
+
+ soup_uri_free(soup_uri);
+ }
+
+ if(GTK_IS_WIDGET(uzbl.gui.main_window)) {
+ gdk_property_change(
+ gtk_widget_get_window (GTK_WIDGET (uzbl.gui.main_window)),
+ gdk_atom_intern_static_string("UZBL_URI"),
+ gdk_atom_intern_static_string("STRING"),
+ 8,
+ GDK_PROP_MODE_REPLACE,
+ (unsigned char *)newuri,
+ strlen(newuri));
+ }
+
+ webkit_web_view_load_uri (uzbl.gui.web_view, newuri);
+ g_free (newuri);
+}
+
+void
+cmd_max_conns() {
+ g_object_set(G_OBJECT(uzbl.net.soup_session),
+ SOUP_SESSION_MAX_CONNS, uzbl.net.max_conns, NULL);
+}
+
+void
+cmd_max_conns_host() {
+ g_object_set(G_OBJECT(uzbl.net.soup_session),
+ SOUP_SESSION_MAX_CONNS_PER_HOST, uzbl.net.max_conns_host, NULL);
+}
+
+void
+cmd_http_debug() {
+ if(uzbl.net.soup_logger) {
+ soup_session_remove_feature
+ (uzbl.net.soup_session, SOUP_SESSION_FEATURE(uzbl.net.soup_logger));
+ g_object_unref (uzbl.net.soup_logger);
+ }
+
+ uzbl.net.soup_logger = soup_logger_new(uzbl.behave.http_debug, -1);
+ soup_session_add_feature(uzbl.net.soup_session,
+ SOUP_SESSION_FEATURE(uzbl.net.soup_logger));
+}
+
+void
+cmd_font_size() {
+ GObject *ws = view_settings();
+ if (uzbl.behave.font_size > 0) {
+ g_object_set (ws, "default-font-size", uzbl.behave.font_size, NULL);
+ }
+
+ if (uzbl.behave.monospace_size > 0) {
+ g_object_set (ws, "default-monospace-font-size",
+ uzbl.behave.monospace_size, NULL);
+ } else {
+ g_object_set (ws, "default-monospace-font-size",
+ uzbl.behave.font_size, NULL);
+ }
+}
+
+void
+cmd_zoom_level() {
+ webkit_web_view_set_zoom_level (uzbl.gui.web_view, uzbl.behave.zoom_level);
+}
+
+#define EXPOSE_WEBKIT_VIEW_SETTINGS(SYM, STORAGE, PROPERTY) void cmd_##SYM() { \
+ g_object_set(view_settings(), (PROPERTY), (STORAGE), NULL); \
+}
+
+EXPOSE_WEBKIT_VIEW_SETTINGS(default_font_family, uzbl.behave.default_font_family, "default-font-family")
+EXPOSE_WEBKIT_VIEW_SETTINGS(monospace_font_family, uzbl.behave.monospace_font_family, "monospace-font-family")
+EXPOSE_WEBKIT_VIEW_SETTINGS(sans_serif_font_family, uzbl.behave.sans_serif_font_family, "sans_serif-font-family")
+EXPOSE_WEBKIT_VIEW_SETTINGS(serif_font_family, uzbl.behave.serif_font_family, "serif-font-family")
+EXPOSE_WEBKIT_VIEW_SETTINGS(cursive_font_family, uzbl.behave.cursive_font_family, "cursive-font-family")
+EXPOSE_WEBKIT_VIEW_SETTINGS(fantasy_font_family, uzbl.behave.fantasy_font_family, "fantasy-font-family")
+
+EXPOSE_WEBKIT_VIEW_SETTINGS(minimum_font_size, uzbl.behave.minimum_font_size, "minimum_font_size")
+
+EXPOSE_WEBKIT_VIEW_SETTINGS(disable_plugins, !uzbl.behave.disable_plugins, "enable-plugins")
+EXPOSE_WEBKIT_VIEW_SETTINGS(disable_scripts, !uzbl.behave.disable_scripts, "enable-scripts")
+
+EXPOSE_WEBKIT_VIEW_SETTINGS(javascript_windows, uzbl.behave.javascript_windows, "javascript-can-open-windows-automatically")
+
+EXPOSE_WEBKIT_VIEW_SETTINGS(autoload_img, uzbl.behave.autoload_img, "auto-load-images")
+EXPOSE_WEBKIT_VIEW_SETTINGS(autoshrink_img, uzbl.behave.autoshrink_img, "auto-shrink-images")
+
+EXPOSE_WEBKIT_VIEW_SETTINGS(enable_pagecache, uzbl.behave.enable_pagecache, "enable-page-cache")
+EXPOSE_WEBKIT_VIEW_SETTINGS(enable_private, uzbl.behave.enable_private, "enable-private-browsing")
+
+EXPOSE_WEBKIT_VIEW_SETTINGS(enable_spellcheck, uzbl.behave.enable_spellcheck, "enable-spell-checking")
+EXPOSE_WEBKIT_VIEW_SETTINGS(spellcheck_languages, uzbl.behave.spellcheck_languages, "spell-checking-languages")
+EXPOSE_WEBKIT_VIEW_SETTINGS(resizable_txt, uzbl.behave.resizable_txt, "resizable-text-areas")
+
+EXPOSE_WEBKIT_VIEW_SETTINGS(style_uri, uzbl.behave.style_uri, "user-stylesheet-uri")
+EXPOSE_WEBKIT_VIEW_SETTINGS(print_bg, uzbl.behave.print_bg, "print-backgrounds")
+EXPOSE_WEBKIT_VIEW_SETTINGS(enforce_96dpi, uzbl.behave.enforce_96dpi, "enforce-96-dpi")
+
+EXPOSE_WEBKIT_VIEW_SETTINGS(caret_browsing, uzbl.behave.caret_browsing, "enable-caret-browsing")
+
+EXPOSE_WEBKIT_VIEW_SETTINGS(default_encoding, uzbl.behave.default_encoding, "default-encoding")
+
+void
+set_proxy_url() {
+ const gchar *url = uzbl.net.proxy_url;
+ SoupSession *session = uzbl.net.soup_session;
+ SoupURI *soup_uri = NULL;
+
+ if (url != NULL || *url != 0 || *url != ' ')
+ soup_uri = soup_uri_new(url);
+
+ g_object_set(G_OBJECT(session), SOUP_SESSION_PROXY_URI, soup_uri, NULL);
+
+ if(soup_uri)
+ soup_uri_free(soup_uri);
+}
+
+
+void
+set_authentication_handler() {
+ /* Check if WEBKIT_TYPE_SOUP_AUTH_DIALOG feature is set */
+ GSList *flist = soup_session_get_features (uzbl.net.soup_session, (GType) WEBKIT_TYPE_SOUP_AUTH_DIALOG);
+ guint feature_is_set = g_slist_length(flist);
+ g_slist_free(flist);
+
+ if (uzbl.behave.authentication_handler == NULL || *uzbl.behave.authentication_handler == 0) {
+ if (!feature_is_set)
+ soup_session_add_feature_by_type
+ (uzbl.net.soup_session, (GType) WEBKIT_TYPE_SOUP_AUTH_DIALOG);
+ } else {
+ if (feature_is_set)
+ soup_session_remove_feature_by_type
+ (uzbl.net.soup_session, (GType) WEBKIT_TYPE_SOUP_AUTH_DIALOG);
+ }
+ return;
+}
+
+void
+set_status_background() {
+ /* labels and hboxes do not draw their own background. applying this
+ * on the vbox/main_window is ok as the statusbar is the only affected
+ * widget. (if not, we could also use GtkEventBox) */
+ GtkWidget* widget = uzbl.gui.main_window ? uzbl.gui.main_window : GTK_WIDGET (uzbl.gui.plug);
+
+#if GTK_CHECK_VERSION(2,91,0)
+ GdkRGBA color;
+ gdk_rgba_parse (&color, uzbl.behave.status_background);
+ gtk_widget_override_background_color (widget, GTK_STATE_NORMAL, &color);
+#else
+ GdkColor color;
+ gdk_color_parse (uzbl.behave.status_background, &color);
+ gtk_widget_modify_bg (widget, GTK_STATE_NORMAL, &color);
+#endif
+}
+
+void
+set_icon() {
+ if(file_exists(uzbl.gui.icon)) {
+ if (uzbl.gui.main_window)
+ gtk_window_set_icon_from_file (GTK_WINDOW (uzbl.gui.main_window), uzbl.gui.icon, NULL);
+ } else {
+ g_printerr ("Icon \"%s\" not found. ignoring.\n", uzbl.gui.icon);
+ }
+}
+
+void
+set_window_role() {
+ if (uzbl.gui.main_window)
+ gtk_window_set_role(GTK_WINDOW (uzbl.gui.main_window), uzbl.gui.window_role);
+}
+
+void
+set_geometry() {
+ int ret=0, x=0, y=0;
+ unsigned int w=0, h=0;
+ if(uzbl.gui.geometry) {
+ if(uzbl.gui.geometry[0] == 'm') { /* m/maximize/maximized */
+ gtk_window_maximize((GtkWindow *)(uzbl.gui.main_window));
+ } else {
+ /* we used to use gtk_window_parse_geometry() but that didn't work how it was supposed to */
+ ret = XParseGeometry(uzbl.gui.geometry, &x, &y, &w, &h);
+ if(ret & XValue)
+ gtk_window_move((GtkWindow *)uzbl.gui.main_window, x, y);
+ if(ret & WidthValue)
+ gtk_window_resize((GtkWindow *)uzbl.gui.main_window, w, h);
+ }
+ }
+
+ /* update geometry var with the actual geometry
+ this is necessary as some WMs don't seem to honour
+ the above setting and we don't want to end up with
+ wrong geometry information
+ */
+ retrieve_geometry();
+}
+
+void
+set_show_status() {
+ if (!uzbl.behave.show_status)
+ gtk_widget_hide(uzbl.gui.status_bar);
+ else
+ gtk_widget_show(uzbl.gui.status_bar);
+
+ update_title();
+}
+
+void
+set_status_top() {
+ if (!uzbl.gui.scrolled_win && !uzbl.gui.status_bar)
+ return;
+
+ g_object_ref(uzbl.gui.scrolled_win);
+ g_object_ref(uzbl.gui.status_bar);
+ gtk_container_remove(GTK_CONTAINER(uzbl.gui.vbox), uzbl.gui.scrolled_win);
+ gtk_container_remove(GTK_CONTAINER(uzbl.gui.vbox), uzbl.gui.status_bar);
+
+ if(uzbl.behave.status_top) {
+ gtk_box_pack_start (GTK_BOX (uzbl.gui.vbox), uzbl.gui.status_bar, FALSE, TRUE, 0);
+ gtk_box_pack_start (GTK_BOX (uzbl.gui.vbox), uzbl.gui.scrolled_win, TRUE, TRUE, 0);
+ } else {
+ gtk_box_pack_start (GTK_BOX (uzbl.gui.vbox), uzbl.gui.scrolled_win, TRUE, TRUE, 0);
+ gtk_box_pack_start (GTK_BOX (uzbl.gui.vbox), uzbl.gui.status_bar, FALSE, TRUE, 0);
+ }
+
+ g_object_unref(uzbl.gui.scrolled_win);
+ g_object_unref(uzbl.gui.status_bar);
+
+ if (!uzbl.state.plug_mode)
+ gtk_widget_grab_focus (GTK_WIDGET (uzbl.gui.web_view));
+}
+
+void
+set_current_encoding() {
+ gchar *encoding = uzbl.behave.current_encoding;
+ if(strlen(encoding) == 0)
+ encoding = NULL;
+
+ webkit_web_view_set_custom_encoding(uzbl.gui.web_view, encoding);
+}
+
+void
+cmd_fifo_dir() {
+ uzbl.behave.fifo_dir = init_fifo(uzbl.behave.fifo_dir);
+}
+
+void
+cmd_socket_dir() {
+ uzbl.behave.socket_dir = init_socket(uzbl.behave.socket_dir);
+}
+
+void
+cmd_inject_html() {
+ if(uzbl.behave.inject_html) {
+ webkit_web_view_load_html_string (uzbl.gui.web_view,
+ uzbl.behave.inject_html, NULL);
+ }
+}
+
+void
+cmd_useragent() {
+ if (*uzbl.net.useragent == ' ') {
+ g_free (uzbl.net.useragent);
+ uzbl.net.useragent = NULL;
+ } else {
+ g_object_set(G_OBJECT(uzbl.net.soup_session), SOUP_SESSION_USER_AGENT,
+ uzbl.net.useragent, NULL);
+ }
+}
+
+void
+set_accept_languages() {
+ if (*uzbl.net.accept_languages == ' ') {
+ g_free (uzbl.net.accept_languages);
+ uzbl.net.accept_languages = NULL;
+ } else {
+ g_object_set(G_OBJECT(uzbl.net.soup_session),
+ SOUP_SESSION_ACCEPT_LANGUAGE, uzbl.net.accept_languages, NULL);
+ }
+}
+
+/* requires webkit >=1.1.14 */
+void
+cmd_view_source() {
+ webkit_web_view_set_view_source_mode(uzbl.gui.web_view,
+ (gboolean) uzbl.behave.view_source);
+}
+
+void
+cmd_set_zoom_type () {
+ if(uzbl.behave.zoom_type)
+ webkit_web_view_set_full_content_zoom (uzbl.gui.web_view, TRUE);
+ else
+ webkit_web_view_set_full_content_zoom (uzbl.gui.web_view, FALSE);
+}
+
+/* abbreviations to help keep the table's width humane */
+#define PTR_V_STR(var, d, fun) { .ptr.s = &(var), .type = TYPE_STR, .dump = d, .writeable = 1, .func = fun }
+#define PTR_V_INT(var, d, fun) { .ptr.i = (int*)&(var), .type = TYPE_INT, .dump = d, .writeable = 1, .func = fun }
+#define PTR_V_FLOAT(var, d, fun) { .ptr.f = &(var), .type = TYPE_FLOAT, .dump = d, .writeable = 1, .func = fun }
+#define PTR_C_STR(var, fun) { .ptr.s = &(var), .type = TYPE_STR, .dump = 0, .writeable = 0, .func = fun }
+#define PTR_C_INT(var, fun) { .ptr.i = (int*)&(var), .type = TYPE_INT, .dump = 0, .writeable = 0, .func = fun }
+#define PTR_C_FLOAT(var, fun) { .ptr.f = &(var), .type = TYPE_FLOAT, .dump = 0, .writeable = 0, .func = fun }
+
+const struct var_name_to_ptr_t {
+ const char *name;
+ uzbl_cmdprop cp;
+} var_name_to_ptr[] = {
+/* variable name pointer to variable in code dump callback function */
+/* ---------------------------------------------------------------------------------------------- */
+ { "uri", PTR_V_STR(uzbl.state.uri, 1, cmd_load_uri)},
+ { "verbose", PTR_V_INT(uzbl.state.verbose, 1, NULL)},
+ { "print_events", PTR_V_INT(uzbl.state.events_stdout, 1, NULL)},
+ { "inject_html", PTR_V_STR(uzbl.behave.inject_html, 0, cmd_inject_html)},
+ { "geometry", PTR_V_STR(uzbl.gui.geometry, 1, set_geometry)},
+ { "show_status", PTR_V_INT(uzbl.behave.show_status, 1, set_show_status)},
+ { "status_top", PTR_V_INT(uzbl.behave.status_top, 1, set_status_top)},
+ { "status_format", PTR_V_STR(uzbl.behave.status_format, 1, NULL)},
+ { "status_format_right", PTR_V_STR(uzbl.behave.status_format_right, 1, NULL)},
+ { "status_background", PTR_V_STR(uzbl.behave.status_background, 1, set_status_background)},
+ { "title_format_long", PTR_V_STR(uzbl.behave.title_format_long, 1, NULL)},
+ { "title_format_short", PTR_V_STR(uzbl.behave.title_format_short, 1, NULL)},
+ { "icon", PTR_V_STR(uzbl.gui.icon, 1, set_icon)},
+ { "window_role", PTR_V_STR(uzbl.gui.window_role, 1, set_window_role)},
+ { "forward_keys", PTR_V_INT(uzbl.behave.forward_keys, 1, NULL)},
+ { "authentication_handler", PTR_V_STR(uzbl.behave.authentication_handler, 1, set_authentication_handler)},
+ { "scheme_handler", PTR_V_STR(uzbl.behave.scheme_handler, 1, NULL)},
+ { "download_handler", PTR_V_STR(uzbl.behave.download_handler, 1, NULL)},
+ { "fifo_dir", PTR_V_STR(uzbl.behave.fifo_dir, 1, cmd_fifo_dir)},
+ { "socket_dir", PTR_V_STR(uzbl.behave.socket_dir, 1, cmd_socket_dir)},
+ { "http_debug", PTR_V_INT(uzbl.behave.http_debug, 1, cmd_http_debug)},
+ { "shell_cmd", PTR_V_STR(uzbl.behave.shell_cmd, 1, NULL)},
+ { "proxy_url", PTR_V_STR(uzbl.net.proxy_url, 1, set_proxy_url)},
+ { "max_conns", PTR_V_INT(uzbl.net.max_conns, 1, cmd_max_conns)},
+ { "max_conns_host", PTR_V_INT(uzbl.net.max_conns_host, 1, cmd_max_conns_host)},
+ { "useragent", PTR_V_STR(uzbl.net.useragent, 1, cmd_useragent)},
+ { "accept_languages", PTR_V_STR(uzbl.net.accept_languages, 1, set_accept_languages)},
+ { "javascript_windows", PTR_V_INT(uzbl.behave.javascript_windows, 1, cmd_javascript_windows)},
+ /* requires webkit >=1.1.14 */
+ { "view_source", PTR_V_INT(uzbl.behave.view_source, 0, cmd_view_source)},
+
+ /* exported WebKitWebSettings properties */
+ { "zoom_level", PTR_V_FLOAT(uzbl.behave.zoom_level, 1, cmd_zoom_level)},
+ { "zoom_type", PTR_V_INT(uzbl.behave.zoom_type, 1, cmd_set_zoom_type)},
+ { "font_size", PTR_V_INT(uzbl.behave.font_size, 1, cmd_font_size)},
+ { "default_font_family", PTR_V_STR(uzbl.behave.default_font_family, 1, cmd_default_font_family)},
+ { "monospace_font_family", PTR_V_STR(uzbl.behave.monospace_font_family, 1, cmd_monospace_font_family)},
+ { "cursive_font_family", PTR_V_STR(uzbl.behave.cursive_font_family, 1, cmd_cursive_font_family)},
+ { "sans_serif_font_family", PTR_V_STR(uzbl.behave.sans_serif_font_family, 1, cmd_sans_serif_font_family)},
+ { "serif_font_family", PTR_V_STR(uzbl.behave.serif_font_family, 1, cmd_serif_font_family)},
+ { "fantasy_font_family", PTR_V_STR(uzbl.behave.fantasy_font_family, 1, cmd_fantasy_font_family)},
+ { "monospace_size", PTR_V_INT(uzbl.behave.monospace_size, 1, cmd_font_size)},
+ { "minimum_font_size", PTR_V_INT(uzbl.behave.minimum_font_size, 1, cmd_minimum_font_size)},
+ { "enable_pagecache", PTR_V_INT(uzbl.behave.enable_pagecache, 1, cmd_enable_pagecache)},
+ { "disable_plugins", PTR_V_INT(uzbl.behave.disable_plugins, 1, cmd_disable_plugins)},
+ { "disable_scripts", PTR_V_INT(uzbl.behave.disable_scripts, 1, cmd_disable_scripts)},
+ { "autoload_images", PTR_V_INT(uzbl.behave.autoload_img, 1, cmd_autoload_img)},
+ { "autoshrink_images", PTR_V_INT(uzbl.behave.autoshrink_img, 1, cmd_autoshrink_img)},
+ { "enable_spellcheck", PTR_V_INT(uzbl.behave.enable_spellcheck, 1, cmd_enable_spellcheck)},
+ { "spellcheck_languages", PTR_V_STR(uzbl.behave.spellcheck_languages, 1, cmd_spellcheck_languages)},
+ { "enable_private", PTR_V_INT(uzbl.behave.enable_private, 1, cmd_enable_private)},
+ { "print_backgrounds", PTR_V_INT(uzbl.behave.print_bg, 1, cmd_print_bg)},
+ { "stylesheet_uri", PTR_V_STR(uzbl.behave.style_uri, 1, cmd_style_uri)},
+ { "resizable_text_areas", PTR_V_INT(uzbl.behave.resizable_txt, 1, cmd_resizable_txt)},
+ { "default_encoding", PTR_V_STR(uzbl.behave.default_encoding, 1, cmd_default_encoding)},
+ { "current_encoding", PTR_V_STR(uzbl.behave.current_encoding, 1, set_current_encoding)},
+ { "enforce_96_dpi", PTR_V_INT(uzbl.behave.enforce_96dpi, 1, cmd_enforce_96dpi)},
+ { "caret_browsing", PTR_V_INT(uzbl.behave.caret_browsing, 1, cmd_caret_browsing)},
+
+ /* constants (not dumpable or writeable) */
+ { "WEBKIT_MAJOR", PTR_C_INT(uzbl.info.webkit_major, NULL)},
+ { "WEBKIT_MINOR", PTR_C_INT(uzbl.info.webkit_minor, NULL)},
+ { "WEBKIT_MICRO", PTR_C_INT(uzbl.info.webkit_micro, NULL)},
+ { "ARCH_UZBL", PTR_C_STR(uzbl.info.arch, NULL)},
+ { "COMMIT", PTR_C_STR(uzbl.info.commit, NULL)},
+ { "TITLE", PTR_C_STR(uzbl.gui.main_title, NULL)},
+ { "SELECTED_URI", PTR_C_STR(uzbl.state.selected_url, NULL)},
+ { "NAME", PTR_C_STR(uzbl.state.instance_name, NULL)},
+ { "PID", PTR_C_STR(uzbl.info.pid_str, NULL)},
+ { "_", PTR_C_STR(uzbl.state.last_result, NULL)},
+
+ { NULL, {.ptr.s = NULL, .type = TYPE_INT, .dump = 0, .writeable = 0, .func = NULL}}
+};
+
+/* construct a hash from the var_name_to_ptr array for quick access */
+void
+variables_hash() {
+ const struct var_name_to_ptr_t *n2v_p = var_name_to_ptr;
+ uzbl.behave.proto_var = g_hash_table_new(g_str_hash, g_str_equal);
+ while(n2v_p->name) {
+ g_hash_table_insert(uzbl.behave.proto_var,
+ (gpointer) n2v_p->name,
+ (gpointer) &n2v_p->cp);
+ n2v_p++;
+ }
+}
diff --git a/src/variables.h b/src/variables.h
new file mode 100644
index 0000000..6aa0ab0
--- /dev/null
+++ b/src/variables.h
@@ -0,0 +1,21 @@
+/*
+ * Uzbl Variables
+ */
+
+#ifndef __VARIABLES__
+#define __VARIABLES__
+
+#include <glib.h>
+#include <webkit/webkit.h>
+
+gboolean set_var_value(const gchar *name, gchar *val);
+void expand_variable(GString *buf, const gchar *name);
+void variables_hash();
+void dump_config();
+void dump_config_as_events();
+
+void uri_change_cb (WebKitWebView *web_view, GParamSpec param_spec);
+void set_show_status();
+void set_geometry();
+
+#endif
diff --git a/tests/Makefile b/tests/Makefile
index 2a5e2b6..eceb7fb 100644
--- a/tests/Makefile
+++ b/tests/Makefile
@@ -1,12 +1,15 @@
-# gtk2
-REQ_PKGS += gtk+-2.0 webkit-1.0
CPPFLAGS = -I ../ -DERRORCHECK_MUTEXES
-# gtk3
-#REQ_PKGS += gtk+-3.0 webkitgtk-3.0
-#CPPFLAGS = -I ../ -DERRORCHECK_MUTEXES -DG_DISABLE_DEPRECATED -DGTK_DISABLE_DEPRECATED
+# use GTK3-based webkit when it is available
+USE_GTK3 = $(shell pkg-config --exists gtk+-3.0 webkitgtk-3.0 && echo 1)
-# --- configuration ends here ---
+ifeq ($(USE_GTK3),1)
+ REQ_PKGS += gtk+-3.0 webkitgtk-3.0
+ CPPFLAGS += -DG_DISABLE_DEPRECATED -DGTK_DISABLE_DEPRECATED
+else
+ REQ_PKGS += gtk+-2.0 webkit-1.0
+ CPPFLAGS +=
+endif
REQ_PKGS += libsoup-2.4 gthread-2.0 glib-2.0
diff --git a/tests/test-command.c b/tests/test-command.c
index 6b55fb3..0f0f3c1 100644
--- a/tests/test-command.c
+++ b/tests/test-command.c
@@ -24,6 +24,7 @@
#include <src/uzbl-core.h>
#include <src/config.h>
+#include <src/type.h>
extern UzblCore uzbl;
@@ -189,13 +190,13 @@ test_set_variable (struct EventFixture *ef, const void *data) {
/* set a custom variable */
parse_cmd_line("set nonexistant_variable = Some Value", NULL);
ASSERT_EVENT(ef, "VARIABLE_SET nonexistant_variable str 'Some Value'");
- uzbl_cmdprop *c = g_hash_table_lookup(uzbl.comm.proto_var, "nonexistant_variable");
+ uzbl_cmdprop *c = g_hash_table_lookup(uzbl.behave.proto_var, "nonexistant_variable");
g_assert_cmpstr("Some Value", ==, *c->ptr.s);
/* set a custom variable with expansion */
parse_cmd_line("set an_expanded_variable = Test @(echo expansion)@", NULL);
ASSERT_EVENT(ef, "VARIABLE_SET an_expanded_variable str 'Test expansion'");
- c = g_hash_table_lookup(uzbl.comm.proto_var, "an_expanded_variable");
+ c = g_hash_table_lookup(uzbl.behave.proto_var, "an_expanded_variable");
g_assert_cmpstr("Test expansion", ==, *c->ptr.s);
}
@@ -216,8 +217,8 @@ test_print (void) {
void
test_scroll (void) {
- uzbl.gui.scbar_v = (GtkScrollbar*) gtk_vscrollbar_new (NULL);
- uzbl.gui.bar_v = gtk_range_get_adjustment((GtkRange*) uzbl.gui.scbar_v);
+ GtkScrollbar *scbar_v = (GtkScrollbar*) gtk_vscrollbar_new (NULL);
+ uzbl.gui.bar_v = gtk_range_get_adjustment((GtkRange*) scbar_v);
gtk_adjustment_set_lower(uzbl.gui.bar_v, 0);
gtk_adjustment_set_upper(uzbl.gui.bar_v, 100);
diff --git a/tests/test-expand.c b/tests/test-expand.c
index d823cfa..cfcfaed 100644
--- a/tests/test-expand.c
+++ b/tests/test-expand.c
@@ -28,7 +28,6 @@
extern UzblCore uzbl;
-extern gchar* expand(char*, guint);
extern void make_var_to_name_hash(void);
void