From f6fd0e88b1f18ae22c2160552a97b6a1f7890549 Mon Sep 17 00:00:00 2001 From: Mason Larobina Date: Mon, 29 Jun 2009 03:40:28 +0800 Subject: uzbl_tabbed.py re-write. Re-written the uzbl_tabbed.py script to use a fifo control interface and inherit configuration options from the users uzbl configuration file (if it exists). --- examples/data/uzbl/scripts/uzbl_tabbed.py | 764 ++++++++++++++++++++++++++++-- 1 file changed, 737 insertions(+), 27 deletions(-) (limited to 'examples') diff --git a/examples/data/uzbl/scripts/uzbl_tabbed.py b/examples/data/uzbl/scripts/uzbl_tabbed.py index 4c3a934..d10105b 100755 --- a/examples/data/uzbl/scripts/uzbl_tabbed.py +++ b/examples/data/uzbl/scripts/uzbl_tabbed.py @@ -1,41 +1,751 @@ #!/usr/bin/python -import string, pygtk, gtk, sys, subprocess +# Uzbl tabbing wrapper using a fifo socket interface +# Copywrite (c) 2009, Tom Adams +# Copywrite (c) 2009, quigybo +# Copywrite (c) 2009, Mason Larobina +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see . + + +# Author(s): +# Tom Adams +# Wrote the original uzbl_tabbed.py as a proof of concept. +# +# quigybo +# Made signifigant headway on the uzbl_tabbing.py script on the +# uzbl wiki +# +# Mason Larobina +# Rewrite of the uzbl_tabbing.py script to use a fifo socket interface +# and inherit configuration options from the user's uzbl config. +# +# Contributor(s): +# (None yet) + + +# Issues: +# - status_background colour is not honoured (reverts to gtk default). +# - new windows are not caught and opened in a new tab. +# - need an easier way to read a uzbl instances window title instead of +# spawning a shell to spawn uzblctrl to communicate to the uzbl +# instance via socket to dump the window title to then pipe it to +# the tabbing managers fifo socket. +# - probably missing some os.path.expandvars somewhere. + + +# Todo: +# - add command line options to use a different session file, not use a +# session file and or open a uri on starup. +# - ellipsize individual tab titles when the tab-list becomes over-crowded +# - add "<" & ">" arrows to tablist to indicate that only a subset of the +# currently open tabs are being displayed on the tablist. +# - probably missing some os.path.expandvars somewhere and other +# user-friendly.. things, this is still a very early version. +# - fix status_background issues & style tablist. +# - add the small tab-list display when both gtk tabs and text vim-like +# tablist are hidden (I.e. [ 1 2 3 4 5 ]) +# - check spelling. + + +import pygtk +import gtk +import subprocess +import os +import re +import time +import getopt +import pango +import select +import sys +import gobject + pygtk.require('2.0') -def new_tab(nothing): - socket = gtk.Socket() - socket.show() - notebook.append_page(socket, gtk.Label('title goes here')) - sid = socket.get_id() - subprocess.call(['sh', '-c', 'uzbl -s %s &'%sid]) +def error(msg): + sys.stderr.write("%s\n"%msg) + +if 'XDG_DATA_HOME' in os.environ.keys() and os.environ['XDG_DATA_HOME']: + data_dir = os.path.join(os.environ['XDG_DATA_HOME'], 'uzbl/') + +else: + data_dir = os.path.join(os.environ['HOME'], '.local/share/uzbl/') + +# === Default Configuration ==================================================== + +# Location of your uzbl configuration file. +uzbl_config = os.path.join(os.environ['HOME'],'.config/uzbl/config') + +# All of these settings can be inherited from your uzbl config file. +config = {'show_tabs': True, + 'show_gtk_tabs': False, + 'switch_to_new_tabs': True, + 'save_session': True, + 'fifo_dir': '/tmp', + 'icon_path': os.path.join(data_dir, 'uzbl.png'), + 'session_file': os.path.join(data_dir, 'session'), + 'tab_colours': 'foreground = "#000000"', + 'selected_tab': 'foreground = "#000000" background="#bbbbbb"', + 'window_size': "800,800", + 'monospace_size': 10, + 'bind_new_tab': 'gn', + 'bind_tab_from_clipboard': 'gY', + 'bind_close_tab': 'gC', + 'bind_next_tab': 'gt', + 'bind_prev_tab': 'gT', + 'bind_goto_tab': 'gi_', + 'bind_goto_first': 'g<', + 'bind_goto_last':'g>'} + +# === End Configuration ======================================================= + +def readconfig(uzbl_config, config): + '''Loads relevant config from the users uzbl config file into the global + config dictionary.''' + + if not os.path.exists(uzbl_config): + error("Unable to load config %r" % uzbl_config) + return None + + # Define parsing regular expressions + isint = re.compile("^[0-9]+$").match + findsets = re.compile("^set\s+([^\=]+)\s*\=\s*(.+)$",\ + re.MULTILINE).findall + + h = open(os.path.expandvars(uzbl_config), 'r') + rawconfig = h.read() + h.close() + + for (key, value) in findsets(rawconfig): + key = key.strip() + if key not in config.keys(): continue + if isint(value): value = int(value) + config[key] = value + + +def rmkdir(path): + '''Recursively make directories. + I.e. `mkdir -p /some/nonexistant/path/`''' + + path, sep = os.path.realpath(path), os.path.sep + dirs = path.split(sep) + for i in range(2,len(dirs)+1): + dir = os.path.join(sep,sep.join(dirs[:i])) + if not os.path.exists(dir): + os.mkdir(dir) + + +def counter(): + '''To infinity and beyond!''' + + i = 0 + while True: + i += 1 + yield i + + +class UzblTabbed: + '''A tabbed version of uzbl using gtk.Notebook''' + + TIMEOUT = 100 # Millisecond interval between timeouts + + class UzblInstance: + '''Uzbl instance meta-data/meta-action object.''' + + def __init__(self, parent, socket, fifo, pid, url='', switch=True): + self.parent = parent + self.socket = socket # the gtk socket + self.fifo = fifo + self.pid = pid + self.title = "New tab" + self.url = url + self.timers = {} + self._lastprobe = 0 + self._switch_on_config = switch + self._outgoing = [] + self._configured = False + + # When notebook tab deleted the kill switch is raised. + self._kill = False + + # Queue binds for uzbl child + self.parent.config_uzbl(self) + + + def flush(self, timer_call=False): + '''Flush messages from the queue.''' + + if self._kill: + error("Flush called on dead page.") + return False + + if os.path.exists(self.fifo): + h = open(self.fifo, 'w') + while len(self._outgoing): + msg = self._outgoing.pop(0) + h.write("%s\n" % msg) + h.close() + + elif not timer_call and self._configured: + # TODO: I dont know what to do here. A previously thought + # alright uzbl client fifo socket has now gone missing. + # I think this should be fatal (at least for the page in + # question). I'll wait until this error appears in the wild. + error("Error: fifo %r lost in action." % self.fifo) + + if not len(self._outgoing) and timer_call: + self._configured = True + + if timer_call in self.timers.keys(): + gobject.source_remove(self.timers[timer_call]) + del self.timers[timer_call] + + if self._switch_on_config: + notebook = list(self.parent.notebook) + try: + tabid = notebook.index(self.socket) + self.parent.goto_tab(tabid) + + except ValueError: + pass + + return len(self._outgoing) + + + def probe(self): + '''Probes the client for information about its self.''' + + # Ugly way of getting the socket path. Screwed if fifo is in any + # other part of the fifo socket path. + + socket = 'socket'.join(self.fifo.split('fifo')) + + # I feel so dirty + subcmd = 'print title %s @@' % self.pid + cmd = 'uzblctrl -s "%s" -c "%s" > "%s" &' % (socket, subcmd, \ + self.parent.fifo_socket) + + subprocess.Popen([cmd], shell=True) + + self._lastprobe = time.time() + + + def send(self, msg): + '''Child fifo write function.''' + + self._outgoing.append(msg) + # Flush messages from the queue if able. + return self.flush() + + + def __init__(self): + '''Create tablist, window and notebook.''' + + self.pages = {} + self._pidcounter = counter() + self.next_pid = self._pidcounter.next + self._watchers = {} + self._timers = {} + self._buffer = "" + + # Create main window + self.window = gtk.Window() + try: + window_size = map(int, config['window_size'].split(',')) + self.window.set_default_size(*window_size) + + except: + error("Invalid value for default_size in config file.") + + self.window.set_title("Uzbl Browser") + self.window.set_border_width(0) + + # Set main window icon + icon_path = config['icon_path'] + if os.path.exists(icon_path): + self.window.set_icon(gtk.gdk.pixbuf_new_from_file(icon_path)) + + else: + icon_path = '/usr/share/uzbl/examples/data/uzbl/uzbl.png' + if os.path.exists(icon_path): + self.window.set_icon(gtk.gdk.pixbuf_new_from_file(icon_path)) + + # Attach main window event handlers + self.window.connect("delete-event", self.quit) + + # Create tab list + if config['show_tabs']: + vbox = gtk.VBox() + self.window.add(vbox) + + self.tablist = gtk.Label() + self.tablist.set_use_markup(True) + self.tablist.set_justify(gtk.JUSTIFY_LEFT) + self.tablist.set_line_wrap(False) + self.tablist.set_selectable(False) + self.tablist.set_padding(2,2) + self.tablist.set_alignment(0,0) + self.tablist.set_ellipsize(pango.ELLIPSIZE_END) + self.tablist.set_text(" ") + self.tablist.show() + vbox.pack_start(self.tablist, False, False, 0) + + # Create notebook + self.notebook = gtk.Notebook() + self.notebook.set_show_tabs(config['show_gtk_tabs']) + self.notebook.set_show_border(False) + self.notebook.connect("page-removed", self.tab_closed) + self.notebook.connect("switch-page", self.tab_changed) + self.notebook.show() + if config['show_tabs']: + vbox.pack_end(self.notebook, True, True, 0) + vbox.show() + else: + self.window.add(self.notebook) + + self.window.show() + self.wid = self.notebook.window.xid + # Fifo socket definition + self._refindfifos = re.compile('^uzbl_fifo_%s_[0-9]+$' % self.wid) + fifo_filename = 'uzbltabbed_%d' % os.getpid() + self.fifo_socket = os.path.join(config['fifo_dir'], fifo_filename) + + self._watchers = {} + self._buffer = "" + self._create_fifo_socket(self.fifo_socket) + self._setup_fifo_watcher(self.fifo_socket) + + + def run(self): + + # Update tablist timer + timer = "update-tablist" + timerid = gobject.timeout_add(500, self.update_tablist,timer) + self._timers[timer] = timerid + + # Due to the hackish way in which the window titles are read + # too many window will cause the application to slow down insanely + timer = "probe-clients" + timerid = gobject.timeout_add(1000, self.probe_clients, timer) + self._timers[timer] = timerid + + gtk.main() + + + def _find_fifos(self, fifo_dir): + '''Find all child fifo sockets in fifo_dir.''' + + dirlist = '\n'.join(os.listdir(fifo_dir)) + allfifos = self._refindfifos.findall(dirlist) + return sorted(allfifos) + + + def _create_fifo_socket(self, fifo_socket): + '''Create interprocess communication fifo socket.''' + + if os.path.exists(fifo_socket): + if not os.access(fifo_socket, os.F_OK | os.R_OK | os.W_OK): + os.mkfifo(fifo_socket) + + else: + basedir = os.path.dirname(self.fifo_socket) + if not os.path.exists(basedir): + rmkdir(basedir) + os.mkfifo(self.fifo_socket) + + print "Listening on %s" % self.fifo_socket + + + def _setup_fifo_watcher(self, fifo_socket, fd=None): + '''Open fifo socket fd and setup gobject IO_IN & IO_HUP watchers. + Also log the creation of a fd and store the the internal + self._watchers dictionary along with the filename of the fd.''' + + #TODO: Convert current self._watcher dict manipulation to the better + # IMHO self._timers handling by using "timer-keys" as the keys instead + # of the fifo fd's as keys. + + if fd: + os.close(fd) + if fd in self._watchers.keys(): + d = self._watchers[fd] + watchers = d['watchers'] + for watcher in list(watchers): + gobject.source_remove(watcher) + watchers.remove(watcher) + del self._watchers[fd] + + fd = os.open(fifo_socket, os.O_RDONLY | os.O_NONBLOCK) + self._watchers[fd] = {'watchers': [], 'filename': fifo_socket} + + watcher = self._watchers[fd]['watchers'].append + watcher(gobject.io_add_watch(fd, gobject.IO_IN, self.read_fifo)) + watcher(gobject.io_add_watch(fd, gobject.IO_HUP, self.fifo_hangup)) + + + def probe_clients(self, timer_call): + '''Load balance probe all uzbl clients for up-to-date window titles + and uri's.''' + + p = self.pages + probetimes = [(s, p[s]._lastprobe) for s in p.keys()] + socket, lasttime = sorted(probetimes, key=lambda t: t[1])[0] + + if (time.time()-lasttime) > 5: + # Probe a uzbl instance at most once every 10 seconds + self.pages[socket].probe() + + return True + + + def fifo_hangup(self, fd, cb_condition): + '''Handle fifo socket hangups.''' + + # Close fd, re-open fifo_socket and watch. + self._setup_fifo_watcher(self.fifo_socket, fd) + + # And to kill any gobject event handlers calling this function: + return False + + + def read_fifo(self, fd, cb_condition): + '''Read from fifo socket and handle fifo socket hangups.''' + + self._buffer = os.read(fd, 1024) + temp = self._buffer.split("\n") + self._buffer = temp.pop() + + for cmd in [s.strip().split() for s in temp if len(s.strip())]: + try: + #print cmd + self.parse_command(cmd) + + except: + #raise + error("Invalid command: %s" % ' '.join(cmd)) + + 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. + # 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. + # url {pid} {document-location} + + # WARNING SOME OF THESE COMMANDS MIGHT NOT BE WORKING YET OR FAIL. + + if cmd[0] == "new": + if len(cmd) == 2: + self.new_tab(cmd[1]) + + else: + self.new_tab() + + elif cmd[0] == "newfromclip": + url = subprocess.Popen(['xclip','-selection','clipboard','-o'],\ + stdout=subprocess.PIPE).communicate()[0] + if url: + self.new_tab(url) + + 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[0] == "prev": + if len(cmd) == 2: + self.prev_tab(int(cmd[1])) + + 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", "url"]: + if len(cmd) > 2: + uzbl = self.get_uzbl_by_pid(int(cmd[1])) + if uzbl: + setattr(uzbl, cmd[0], ' '.join(cmd[2:])) + else: + error("Cannot find uzbl instance with pid %r" % int(cmd[1])) + else: + error("Unknown command: %s" % ' '.join(cmd)) + + + def get_uzbl_by_pid(self, pid): + '''Return uzbl instance by pid.''' + + for socket in self.pages.keys(): + if self.pages[socket].pid == pid: + return self.pages[socket] + return False + + + def new_tab(self,url='', switch=True): + '''Add a new tab to the notebook and start a new instance of uzbl. + Use the switch option to negate config['switch_to_new_tabs'] option + when you need to load multiple tabs at a time (I.e. like when + restoring a session from a file).''' + + pid = self.next_pid() + socket = gtk.Socket() + socket.show() + self.notebook.append_page(socket) + sid = socket.get_id() + + if url: + url = '--uri %s' % url + + fifo_filename = 'uzbl_fifo_%s_%0.2d' % (self.wid, pid) + fifo_socket = os.path.join(config['fifo_dir'], fifo_filename) + uzbl = self.UzblInstance(self, socket, fifo_socket, pid,\ + url=url, switch=switch) + self.pages[socket] = uzbl + cmd = 'uzbl -s %s -n %s_%0.2d %s &' % (sid, self.wid, pid, url) + subprocess.Popen([cmd], shell=True) + + # Add gobject timer to make sure the config is pushed when fifo socket + # has been created. + timerid = gobject.timeout_add(100, uzbl.flush, "flush-initial-config") + uzbl.timers['flush-initial-config'] = timerid + + + def config_uzbl(self, uzbl): + '''Send bind commands for tab new/close/next/prev to a uzbl + instance.''' + + binds = [] + bind_format = 'bind %s = sh "echo \\\"%s\\\" > \\\"%s\\\""' + bind = lambda key, action: binds.append(bind_format % (key, action, \ + self.fifo_socket)) + + # Keys are defined in the config section + # bind ( key , command back to fifo ) + bind(config['bind_new_tab'], 'new') + bind(config['bind_tab_from_clipboard'], 'newfromclip') + bind(config['bind_close_tab'], 'close') + bind(config['bind_next_tab'], 'next') + bind(config['bind_prev_tab'], 'prev') + bind(config['bind_goto_tab'], 'goto %s') + bind(config['bind_goto_first'], 'goto 0') + bind(config['bind_goto_last'], 'goto -1') + + uzbl.send("\n".join(binds)) + + + def goto_tab(self, n): + '''Goto tab n (supports negative indexing).''' + + notebook = list(self.notebook) + + try: + page = notebook[n] + i = notebook.index(page) + self.notebook.set_current_page(i) + + except IndexError: + pass + + + def next_tab(self, n=1): + '''Switch to next tab or n tabs right.''' + + if n >= 1: + numofpages = self.notebook.get_n_pages() + pagen = self.notebook.get_current_page() + n + self.notebook.set_current_page( pagen % numofpages ) + + + def prev_tab(self, n=1): + '''Switch to prev tab or n tabs left.''' + + if n >= 1: + numofpages = self.notebook.get_n_pages() + pagen = self.notebook.get_current_page() - n + while pagen < 0: + pagen += numofpages + self.notebook.set_current_page(pagen) + + + def close_tab(self, tabid=None): + '''Closes current tab. Supports negative indexing.''' + + if not tabid: + tabid = self.notebook.get_current_page() + + try: + socket = list(self.notebook)[tabid] + + except IndexError: + error("Invalid index. Cannot close tab.") + return False + + uzbl = self.pages[socket] + # Kill timers: + for timer in uzbl.timers.keys(): + error("Removing timer %r %r" % (timer, uzbl.timers[timer])) + gobject.source_remove(uzbl.timers[timer]) + + uzbl._outgoing = [] + uzbl._kill = True + del self.pages[socket] + self.notebook.remove_page(tabid) + + + def tab_closed(self, notebook, socket, page_num): + '''Close the window if no tabs are left. Called by page-removed + signal.''' + + if socket in self.pages.keys(): + uzbl = self.pages[socket] + for timer in uzbl.timers.keys(): + error("Removing timer %r %r" % (timer, uzbl.timers[timer])) + gobject.source_remove(uzbl.timers[timer]) + + uzbl._outgoing = [] + uzbl._kill = True + del self.pages[socket] + + if self.notebook.get_n_pages() == 0: + gtk.main_quit() + + + def tab_changed(self, notebook, page, page_num): + '''Refresh tab list. Called by switch-page signal.''' + + self.tablist.set_text(str(list(self.notebook))) + + self.update_tablist() + + + def update_tablist(self, timer_call=None): + '''Upate tablist status bar.''' + + pango = "" + + normal, selected = config['tab_colours'], config['selected_tab'] + tab_format = " [ %d %s ] " + + uzblkeys = self.pages.keys() + curpage = self.notebook.get_current_page() + + for index, socket in enumerate(self.notebook): + if socket not in uzblkeys: + #error("Theres a socket in the notebook that I have no uzbl "\ + # "record of.") + continue + uzbl = self.pages[socket] + + if index == curpage: + colours = selected + else: + colours = normal + + pango += tab_format % (colours, index, uzbl.title) + + self.tablist.set_markup(pango) + + return True + + + def quit(self, window, event): + '''Cleanup the application and quit. Called by delete-event signal.''' + for fd in self._watchers.keys(): + d = self._watchers[fd] + watchers = d['watchers'] + for watcher in list(watchers): + gobject.source_remove(watcher) + + for timer in self._timers.keys(): + gobject.source_remove(self._timers[timer]) -window = gtk.Window() -window.show() + if os.path.exists(self.fifo_socket): + os.unlink(self.fifo_socket) + print "Unlinked %s" % self.fifo_socket + + if config['save_session']: + session_file = os.path.expandvars(config['session_file']) + if not os.path.isfile(session_file): + dirname = os.path.dirname(session_file) + rmkdir(dirname) + h = open(session_file, 'w') + h.write('current = %s\n' % self.notebook.get_current_page()) + h.close() + for socket in list(self.notebook): + if socket not in self.pages.keys(): continue + uzbl = self.pages[socket] + uzbl.send('sh "echo $6 >> %s"' % session_file) + time.sleep(0.05) -vbox = gtk.VBox() -vbox.show() -window.add(vbox) + gtk.main_quit() -button = gtk.Button(stock=gtk.STOCK_ADD) -button.connect('clicked', new_tab) -button.show() -vbox.add(button) -notebook = gtk.Notebook() -vbox.add(notebook) -notebook.show() -window.connect("destroy", lambda w: gtk.main_quit()) -#def plugged_event(widget): -# print "I (", widget, ") have just had a plug inserted!" +if __name__ == "__main__": + + # Read from the uzbl config into the global config dictionary. + readconfig(uzbl_config, config) + + uzbl = UzblTabbed() + + if os.path.isfile(os.path.expandvars(config['session_file'])): + h = open(os.path.expandvars(config['session_file']),'r') + urls = [s.strip() for s in h.readlines()] + h.close() + current = 0 + for url in urls: + if url.startswith("current"): + current = int(url.split()[-1]) + else: + uzbl.new_tab(url, False) + else: + uzbl.new_tab() -#socket.connect("plug-added", plugged_event) -#socket.connect("plug-removed", plugged_event) + uzbl.run() -if len(sys.argv) == 2: - socket.add_id(long(sys.argv[1])) -gtk.main() \ No newline at end of file -- cgit v1.2.3 From 74e67a7aae087c0ab8429c0b0e9bacea8378c335 Mon Sep 17 00:00:00 2001 From: Mason Larobina Date: Mon, 29 Jun 2009 03:51:58 +0800 Subject: Removed redundant timeout variable (minor edit) --- examples/data/uzbl/scripts/uzbl_tabbed.py | 2 -- 1 file changed, 2 deletions(-) (limited to 'examples') diff --git a/examples/data/uzbl/scripts/uzbl_tabbed.py b/examples/data/uzbl/scripts/uzbl_tabbed.py index d10105b..a0500e7 100755 --- a/examples/data/uzbl/scripts/uzbl_tabbed.py +++ b/examples/data/uzbl/scripts/uzbl_tabbed.py @@ -158,8 +158,6 @@ def counter(): class UzblTabbed: '''A tabbed version of uzbl using gtk.Notebook''' - TIMEOUT = 100 # Millisecond interval between timeouts - class UzblInstance: '''Uzbl instance meta-data/meta-action object.''' -- cgit v1.2.3 From 5748f64c214b610eddb581ae0709b3d1257350d5 Mon Sep 17 00:00:00 2001 From: Mason Larobina Date: Mon, 29 Jun 2009 14:04:27 +0800 Subject: Reduced tablist update delay. By calling self.update_tablist() manually after any notebook tab manipulation. --- examples/data/uzbl/scripts/uzbl_tabbed.py | 18 ++++++++++++++---- 1 file changed, 14 insertions(+), 4 deletions(-) (limited to 'examples') diff --git a/examples/data/uzbl/scripts/uzbl_tabbed.py b/examples/data/uzbl/scripts/uzbl_tabbed.py index a0500e7..6fc23d2 100755 --- a/examples/data/uzbl/scripts/uzbl_tabbed.py +++ b/examples/data/uzbl/scripts/uzbl_tabbed.py @@ -549,7 +549,9 @@ class UzblTabbed: # has been created. timerid = gobject.timeout_add(100, uzbl.flush, "flush-initial-config") uzbl.timers['flush-initial-config'] = timerid - + + self.update_tablist() + def config_uzbl(self, uzbl): '''Send bind commands for tab new/close/next/prev to a uzbl @@ -583,10 +585,12 @@ class UzblTabbed: page = notebook[n] i = notebook.index(page) self.notebook.set_current_page(i) - + except IndexError: pass + self.update_tablist() + def next_tab(self, n=1): '''Switch to next tab or n tabs right.''' @@ -596,6 +600,8 @@ class UzblTabbed: pagen = self.notebook.get_current_page() + n self.notebook.set_current_page( pagen % numofpages ) + self.update_tablist() + def prev_tab(self, n=1): '''Switch to prev tab or n tabs left.''' @@ -607,6 +613,8 @@ class UzblTabbed: pagen += numofpages self.notebook.set_current_page(pagen) + self.update_tablist() + def close_tab(self, tabid=None): '''Closes current tab. Supports negative indexing.''' @@ -632,6 +640,8 @@ class UzblTabbed: del self.pages[socket] self.notebook.remove_page(tabid) + self.update_tablist() + def tab_closed(self, notebook, socket, page_num): '''Close the window if no tabs are left. Called by page-removed @@ -650,12 +660,12 @@ class UzblTabbed: if self.notebook.get_n_pages() == 0: gtk.main_quit() + self.update_tablist() + def tab_changed(self, notebook, page, page_num): '''Refresh tab list. Called by switch-page signal.''' - self.tablist.set_text(str(list(self.notebook))) - self.update_tablist() -- cgit v1.2.3 From 1202432f4d336aff88ad5013413bf258fba68ff2 Mon Sep 17 00:00:00 2001 From: Mason Larobina Date: Mon, 29 Jun 2009 14:15:34 +0800 Subject: Delete session file when empty. --- examples/data/uzbl/scripts/uzbl_tabbed.py | 38 +++++++++++++++++++------------ 1 file changed, 23 insertions(+), 15 deletions(-) (limited to 'examples') diff --git a/examples/data/uzbl/scripts/uzbl_tabbed.py b/examples/data/uzbl/scripts/uzbl_tabbed.py index 6fc23d2..0069859 100755 --- a/examples/data/uzbl/scripts/uzbl_tabbed.py +++ b/examples/data/uzbl/scripts/uzbl_tabbed.py @@ -658,7 +658,7 @@ class UzblTabbed: del self.pages[socket] if self.notebook.get_n_pages() == 0: - gtk.main_quit() + self.quit() self.update_tablist() @@ -699,7 +699,8 @@ class UzblTabbed: return True - def quit(self, window, event): + #def quit(self, window, event): + def quit(self, *args): '''Cleanup the application and quit. Called by delete-event signal.''' for fd in self._watchers.keys(): @@ -717,21 +718,28 @@ class UzblTabbed: if config['save_session']: session_file = os.path.expandvars(config['session_file']) - if not os.path.isfile(session_file): - dirname = os.path.dirname(session_file) - rmkdir(dirname) - h = open(session_file, 'w') - h.write('current = %s\n' % self.notebook.get_current_page()) - h.close() - for socket in list(self.notebook): - if socket not in self.pages.keys(): continue - uzbl = self.pages[socket] - uzbl.send('sh "echo $6 >> %s"' % session_file) - time.sleep(0.05) - - gtk.main_quit() + if self.notebook.get_n_pages(): + if not os.path.isfile(session_file): + dirname = os.path.dirname(session_file) + if not os.path.isdir(dirname): + rmkdir(dirname) + + h = open(session_file, 'w') + h.write('current = %s\n' % self.notebook.get_current_page()) + h.close() + for socket in list(self.notebook): + if socket not in self.pages.keys(): continue + uzbl = self.pages[socket] + uzbl.send('sh "echo $6 >> %s"' % session_file) + time.sleep(0.05) + else: + # Notebook has no pages so delete session file if it exists. + # Its better to not exist than be blank IMO. + if os.path.isfile(session_file): + os.remove(session_file) + gtk.main_quit() if __name__ == "__main__": -- cgit v1.2.3 From eda9f14939e500b18a4c0601a625df440ef6e742 Mon Sep 17 00:00:00 2001 From: Mason Larobina Date: Mon, 29 Jun 2009 15:14:30 +0800 Subject: Style tablist text & update window title. --- examples/data/uzbl/scripts/uzbl_tabbed.py | 20 ++++++++++++++------ 1 file changed, 14 insertions(+), 6 deletions(-) (limited to 'examples') diff --git a/examples/data/uzbl/scripts/uzbl_tabbed.py b/examples/data/uzbl/scripts/uzbl_tabbed.py index 0069859..60d2495 100755 --- a/examples/data/uzbl/scripts/uzbl_tabbed.py +++ b/examples/data/uzbl/scripts/uzbl_tabbed.py @@ -95,8 +95,10 @@ config = {'show_tabs': True, 'fifo_dir': '/tmp', 'icon_path': os.path.join(data_dir, 'uzbl.png'), 'session_file': os.path.join(data_dir, 'session'), - 'tab_colours': 'foreground = "#000000"', - 'selected_tab': 'foreground = "#000000" background="#bbbbbb"', + 'tab_colours': 'foreground = "#999"', + 'tab_text_colours': 'foreground = "#444"', + 'selected_tab': 'foreground = "#aaa" background="#303030"', + 'selected_tab_text': 'foreground = "green"', 'window_size': "800,800", 'monospace_size': 10, 'bind_new_tab': 'gn', @@ -292,7 +294,7 @@ class UzblTabbed: self.tablist.set_justify(gtk.JUSTIFY_LEFT) self.tablist.set_line_wrap(False) self.tablist.set_selectable(False) - self.tablist.set_padding(2,2) + self.tablist.set_padding(0,2) self.tablist.set_alignment(0,0) self.tablist.set_ellipsize(pango.ELLIPSIZE_END) self.tablist.set_text(" ") @@ -674,9 +676,13 @@ class UzblTabbed: pango = "" - normal, selected = config['tab_colours'], config['selected_tab'] - tab_format = " [ %d %s ] " + normal = (config['tab_colours'], config['tab_text_colours']) + selected = (config['selected_tab'], config['selected_tab_text']) + tab_format = " [ %d %s ] " + + title_format = "%s - Uzbl Browser" + uzblkeys = self.pages.keys() curpage = self.notebook.get_current_page() @@ -689,10 +695,12 @@ class UzblTabbed: if index == curpage: colours = selected + self.window.set_title(title_format % uzbl.title) + else: colours = normal - pango += tab_format % (colours, index, uzbl.title) + pango += tab_format % (colours[0], index, colours[1], uzbl.title) self.tablist.set_markup(pango) -- cgit v1.2.3 From 7d864e7411ca1660db85e284fb65b112bd2825ab Mon Sep 17 00:00:00 2001 From: Mason Larobina Date: Mon, 29 Jun 2009 15:44:37 +0800 Subject: Fix spelling. --- examples/data/uzbl/scripts/uzbl_tabbed.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'examples') diff --git a/examples/data/uzbl/scripts/uzbl_tabbed.py b/examples/data/uzbl/scripts/uzbl_tabbed.py index 60d2495..5fff98f 100755 --- a/examples/data/uzbl/scripts/uzbl_tabbed.py +++ b/examples/data/uzbl/scripts/uzbl_tabbed.py @@ -1,9 +1,9 @@ #!/usr/bin/python # Uzbl tabbing wrapper using a fifo socket interface -# Copywrite (c) 2009, Tom Adams -# Copywrite (c) 2009, quigybo -# Copywrite (c) 2009, Mason Larobina +# Copyrite (c) 2009, Tom Adams +# Copyrite (c) 2009, quigybo +# Copyrite (c) 2009, Mason Larobina # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by -- cgit v1.2.3 From d6d1485b3dc7e49f0c460062bf631c7f6e66228b Mon Sep 17 00:00:00 2001 From: Mason Larobina Date: Mon, 29 Jun 2009 18:40:39 +0800 Subject: Added static probe cmds to uzbl instance class --- examples/data/uzbl/scripts/uzbl_tabbed.py | 30 ++++++++++++++++++++++-------- 1 file changed, 22 insertions(+), 8 deletions(-) (limited to 'examples') diff --git a/examples/data/uzbl/scripts/uzbl_tabbed.py b/examples/data/uzbl/scripts/uzbl_tabbed.py index 5fff98f..26f9fc3 100755 --- a/examples/data/uzbl/scripts/uzbl_tabbed.py +++ b/examples/data/uzbl/scripts/uzbl_tabbed.py @@ -176,9 +176,18 @@ class UzblTabbed: self._outgoing = [] self._configured = False + # Probe commands + self._probeurl = 'sh \'echo "url %s $6" > "%s"\'' % (self.pid,\ + self.parent.fifo_socket) + + # As soon as the variable expansion bug is fixed in uzbl + # I can start using this command to fetch the winow title + self._probetitle = 'sh \'echo "title %s @window_title" > "%s"\'' \ + % (self.pid, self.parent.fifo_socket) + # When notebook tab deleted the kill switch is raised. self._kill = False - + # Queue binds for uzbl child self.parent.config_uzbl(self) @@ -228,19 +237,20 @@ class UzblTabbed: # Ugly way of getting the socket path. Screwed if fifo is in any # other part of the fifo socket path. - socket = 'socket'.join(self.fifo.split('fifo')) - - # I feel so dirty + # Hackish & wasteful way of getting the window title. subcmd = 'print title %s @@' % self.pid cmd = 'uzblctrl -s "%s" -c "%s" > "%s" &' % (socket, subcmd, \ self.parent.fifo_socket) - subprocess.Popen([cmd], shell=True) + self.send(self._probeurl) + + # Wont work yet. + #self.send(self._probetitle) self._lastprobe = time.time() - - + + def send(self, msg): '''Child fifo write function.''' @@ -508,7 +518,11 @@ class UzblTabbed: if len(cmd) > 2: uzbl = self.get_uzbl_by_pid(int(cmd[1])) if uzbl: - setattr(uzbl, cmd[0], ' '.join(cmd[2:])) + old = getattr(uzbl, cmd[0]) + new = ' '.join(cmd[2:]) + setattr(uzbl, cmd[0], new) + if old != new: + self.update_tablist() else: error("Cannot find uzbl instance with pid %r" % int(cmd[1])) else: -- cgit v1.2.3 From 858000db7ff7a2c84054e1b165b4613939a5d675 Mon Sep 17 00:00:00 2001 From: Mason Larobina Date: Mon, 29 Jun 2009 19:20:17 +0800 Subject: uzbl_config path now respects XDG_CONFIG_HOME --- examples/data/uzbl/scripts/uzbl_tabbed.py | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) (limited to 'examples') diff --git a/examples/data/uzbl/scripts/uzbl_tabbed.py b/examples/data/uzbl/scripts/uzbl_tabbed.py index 26f9fc3..fa428b2 100755 --- a/examples/data/uzbl/scripts/uzbl_tabbed.py +++ b/examples/data/uzbl/scripts/uzbl_tabbed.py @@ -85,7 +85,10 @@ else: # === Default Configuration ==================================================== # Location of your uzbl configuration file. -uzbl_config = os.path.join(os.environ['HOME'],'.config/uzbl/config') +if 'XDG_CONFIG_HOME' in os.environ.keys() and os.environ['XDG_CONFIG_HOME']: + uzbl_config = os.path.join(os.environ['XDG_CONFIG_HOME'], 'uzbl/config') +else: + uzbl_config = os.path.join(os.environ['HOME'],'.config/uzbl/config') # All of these settings can be inherited from your uzbl config file. config = {'show_tabs': True, -- cgit v1.2.3 From c138928fc694a611ab45e5ac65416e34a53c8a5b Mon Sep 17 00:00:00 2001 From: Mason Larobina Date: Mon, 29 Jun 2009 19:26:56 +0800 Subject: Added mxey to uzbl_tabbed contributors section. --- examples/data/uzbl/scripts/uzbl_tabbed.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'examples') diff --git a/examples/data/uzbl/scripts/uzbl_tabbed.py b/examples/data/uzbl/scripts/uzbl_tabbed.py index fa428b2..1dfd6b6 100755 --- a/examples/data/uzbl/scripts/uzbl_tabbed.py +++ b/examples/data/uzbl/scripts/uzbl_tabbed.py @@ -32,7 +32,8 @@ # and inherit configuration options from the user's uzbl config. # # Contributor(s): -# (None yet) +# mxey +# uzbl_config path now honors XDG_CONFIG_HOME if it exists. # Issues: -- cgit v1.2.3 From af592bb6578c7e7ce5da3cb1b4905d56c011d581 Mon Sep 17 00:00:00 2001 From: Mason Larobina Date: Mon, 29 Jun 2009 19:32:35 +0800 Subject: Spelleng fix. --- examples/data/uzbl/scripts/uzbl_tabbed.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'examples') diff --git a/examples/data/uzbl/scripts/uzbl_tabbed.py b/examples/data/uzbl/scripts/uzbl_tabbed.py index 1dfd6b6..485adcc 100755 --- a/examples/data/uzbl/scripts/uzbl_tabbed.py +++ b/examples/data/uzbl/scripts/uzbl_tabbed.py @@ -1,9 +1,9 @@ #!/usr/bin/python # Uzbl tabbing wrapper using a fifo socket interface -# Copyrite (c) 2009, Tom Adams -# Copyrite (c) 2009, quigybo -# Copyrite (c) 2009, Mason Larobina +# Copyright (c) 2009, Tom Adams +# Copyright (c) 2009, quigybo +# Copyright (c) 2009, Mason Larobina # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by -- cgit v1.2.3 From 820826cde67d99812e22b02d70cbcd667da08b17 Mon Sep 17 00:00:00 2001 From: Mason Larobina Date: Mon, 29 Jun 2009 20:42:10 +0800 Subject: Resolved status bar styling issue and added help text in file. --- examples/data/uzbl/scripts/uzbl_tabbed.py | 57 +++++++++++++++++++++++++------ 1 file changed, 47 insertions(+), 10 deletions(-) (limited to 'examples') diff --git a/examples/data/uzbl/scripts/uzbl_tabbed.py b/examples/data/uzbl/scripts/uzbl_tabbed.py index 485adcc..77f4bc5 100755 --- a/examples/data/uzbl/scripts/uzbl_tabbed.py +++ b/examples/data/uzbl/scripts/uzbl_tabbed.py @@ -36,8 +36,40 @@ # uzbl_config path now honors XDG_CONFIG_HOME if it exists. +# Configuration: +# Because this version of uzbl_tabbed is able to inherit options from your main +# uzbl configuration file you may wish to configure uzbl tabbed from there. +# Here is a list of configuration options that can be customised and some +# example values for each: +# +# set show_tabs = 1 +# set show_gtk_tabs = 0 +# set switch_to_new_tabs = 1 +# set save_session = 1 +# set status_background = #303030 +# set session_file = $HOME/.local/share/session +# set tab_colours = foreground = "#999" +# set tab_text_colours = foreground = "#444" +# set selected_tab = foreground = "#aaa" background="#303030" +# set selected_tab_text = foreground = "green" +# set window_size = 800,800 +# +# And the keybindings: +# +# set bind_new_tab = gn +# set bind_tab_from_clip = gY +# set bind_close_tab = gC +# set bind_next_tab = gt +# set bind_prev_tab = gT +# set bind_goto_tab = gi_ +# set bind_goto_first = g< +# set bind_goto_last = g> +# +# And uzbl_tabbed.py takes care of the actual binding of the commands via each +# instances fifo socket. + + # Issues: -# - status_background colour is not honoured (reverts to gtk default). # - new windows are not caught and opened in a new tab. # - need an easier way to read a uzbl instances window title instead of # spawning a shell to spawn uzblctrl to communicate to the uzbl @@ -99,14 +131,15 @@ config = {'show_tabs': True, 'fifo_dir': '/tmp', 'icon_path': os.path.join(data_dir, 'uzbl.png'), 'session_file': os.path.join(data_dir, 'session'), - 'tab_colours': 'foreground = "#999"', - 'tab_text_colours': 'foreground = "#444"', - 'selected_tab': 'foreground = "#aaa" background="#303030"', - 'selected_tab_text': 'foreground = "green"', + 'status_background': "#303030", + 'tab_colours': 'foreground = "#888"', + 'tab_text_colours': 'foreground = "#bbb"', + 'selected_tab': 'foreground = "#fff" background = "#303030"', + 'selected_tab_text': 'foreground = "#99FF66"', 'window_size': "800,800", 'monospace_size': 10, 'bind_new_tab': 'gn', - 'bind_tab_from_clipboard': 'gY', + 'bind_tab_from_clip': 'gY', 'bind_close_tab': 'gC', 'bind_next_tab': 'gt', 'bind_prev_tab': 'gT', @@ -302,18 +335,22 @@ class UzblTabbed: if config['show_tabs']: vbox = gtk.VBox() self.window.add(vbox) - + ebox = gtk.EventBox() self.tablist = gtk.Label() self.tablist.set_use_markup(True) self.tablist.set_justify(gtk.JUSTIFY_LEFT) self.tablist.set_line_wrap(False) self.tablist.set_selectable(False) - self.tablist.set_padding(0,2) + self.tablist.set_padding(2,2) self.tablist.set_alignment(0,0) self.tablist.set_ellipsize(pango.ELLIPSIZE_END) self.tablist.set_text(" ") self.tablist.show() - vbox.pack_start(self.tablist, False, False, 0) + ebox.add(self.tablist) + ebox.show() + bgcolor = gtk.gdk.color_parse(config['status_background']) + ebox.modify_bg(gtk.STATE_NORMAL, bgcolor) + vbox.pack_start(ebox, False, False, 0) # Create notebook self.notebook = gtk.Notebook() @@ -585,7 +622,7 @@ class UzblTabbed: # Keys are defined in the config section # bind ( key , command back to fifo ) bind(config['bind_new_tab'], 'new') - bind(config['bind_tab_from_clipboard'], 'newfromclip') + bind(config['bind_tab_from_clip'], 'newfromclip') bind(config['bind_close_tab'], 'close') bind(config['bind_next_tab'], 'next') bind(config['bind_prev_tab'], 'prev') -- cgit v1.2.3 From ac6c7b6946b5bd492f7ec5497ed1de09c8127428 Mon Sep 17 00:00:00 2001 From: Mason Larobina Date: Tue, 30 Jun 2009 00:52:21 +0800 Subject: uzbl_tabbed refactor, huge internal changes. --- examples/data/uzbl/scripts/uzbl_tabbed.py | 507 ++++++++++++++++-------------- 1 file changed, 269 insertions(+), 238 deletions(-) (limited to 'examples') diff --git a/examples/data/uzbl/scripts/uzbl_tabbed.py b/examples/data/uzbl/scripts/uzbl_tabbed.py index 77f4bc5..9ecfb09 100755 --- a/examples/data/uzbl/scripts/uzbl_tabbed.py +++ b/examples/data/uzbl/scripts/uzbl_tabbed.py @@ -46,6 +46,7 @@ # set show_gtk_tabs = 0 # set switch_to_new_tabs = 1 # set save_session = 1 +# set new_tab_title = New tab # set status_background = #303030 # set session_file = $HOME/.local/share/session # set tab_colours = foreground = "#999" @@ -103,6 +104,7 @@ import pango import select import sys import gobject +import socket pygtk.require('2.0') @@ -129,6 +131,8 @@ config = {'show_tabs': True, 'switch_to_new_tabs': True, 'save_session': True, 'fifo_dir': '/tmp', + 'socket_dir': '/tmp', + 'new_tab_title': 'New tab', 'icon_path': os.path.join(data_dir, 'uzbl.png'), 'session_file': os.path.join(data_dir, 'session'), 'status_background': "#303030", @@ -197,115 +201,126 @@ def counter(): class UzblTabbed: '''A tabbed version of uzbl using gtk.Notebook''' - class UzblInstance: + class UzblInstance: '''Uzbl instance meta-data/meta-action object.''' - def __init__(self, parent, socket, fifo, pid, url='', switch=True): + def __init__(self, parent, tab, fifo_socket, socket_file, pid,\ + uri, switch): + self.parent = parent - self.socket = socket # the gtk socket - self.fifo = fifo + self.tab = tab + self.fifo_socket = fifo_socket + self.socket_file = socket_file self.pid = pid - self.title = "New tab" - self.url = url + self.title = config['new_tab_title'] + self.uri = uri self.timers = {} self._lastprobe = 0 - self._switch_on_config = switch - self._outgoing = [] - self._configured = False - - # Probe commands - self._probeurl = 'sh \'echo "url %s $6" > "%s"\'' % (self.pid,\ - self.parent.fifo_socket) - - # As soon as the variable expansion bug is fixed in uzbl - # I can start using this command to fetch the winow title - self._probetitle = 'sh \'echo "title %s @window_title" > "%s"\'' \ - % (self.pid, self.parent.fifo_socket) - - # When notebook tab deleted the kill switch is raised. + self._fifoout = [] + self._socketout = [] + self._socket = None + self._buffer = "" + # Switch to tab after connection + self._switch = switch + # fifo/socket files exists and socket connected. + self._connected = False + # The kill switch self._kill = False + + # Gen probe commands string + probes = [] + probe = probes.append + probe('print uri %d @uri' % self.pid) + probe('print title %d @@' % self.pid) + self._probecmds = '\n'.join(probes) - # Queue binds for uzbl child + # Enqueue keybinding config for child uzbl instance self.parent.config_uzbl(self) def flush(self, timer_call=False): - '''Flush messages from the queue.''' + '''Flush messages from the socket-out and fifo-out queues.''' if self._kill: - error("Flush called on dead page.") - return False + if self._socket: + self._socket.close() + self._socket = None - if os.path.exists(self.fifo): - h = open(self.fifo, 'w') - while len(self._outgoing): - msg = self._outgoing.pop(0) - h.write("%s\n" % msg) - h.close() + error("Flush called on dead tab.") + return False - elif not timer_call and self._configured: - # TODO: I dont know what to do here. A previously thought - # alright uzbl client fifo socket has now gone missing. - # I think this should be fatal (at least for the page in - # question). I'll wait until this error appears in the wild. - error("Error: fifo %r lost in action." % self.fifo) + if len(self._fifoout): + if os.path.exists(self.fifo_socket): + h = open(self.fifo_socket, 'w') + while len(self._fifoout): + msg = self._fifoout.pop(0) + h.write("%s\n"%msg) + h.close() - if not len(self._outgoing) and timer_call: - self._configured = True - - if timer_call in self.timers.keys(): - gobject.source_remove(self.timers[timer_call]) - del self.timers[timer_call] - - if self._switch_on_config: - notebook = list(self.parent.notebook) - try: - tabid = notebook.index(self.socket) + if len(self._socketout): + if not self._socket and os.path.exists(self.socket_file): + sock = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM) + sock.connect(self.socket_file) + self._socket = sock + + if self._socket: + while len(self._socketout): + msg = self._socketout.pop(0) + self._socket.send("%s\n"%msg) + + if not self._connected and timer_call: + if not len(self._fifoout + self._socketout): + self._connected = True + + if timer_call in self.timers.keys(): + gobject.source_remove(self.timers[timer_call]) + del self.timers[timer_call] + + if self._switch: + tabs = list(self.parent.notebook) + tabid = tabs.index(self.tab) self.parent.goto_tab(tabid) - - except ValueError: - pass - return len(self._outgoing) + return len(self._fifoout + self._socketout) def probe(self): '''Probes the client for information about its self.''' - # Ugly way of getting the socket path. Screwed if fifo is in any - # other part of the fifo socket path. - socket = 'socket'.join(self.fifo.split('fifo')) - # Hackish & wasteful way of getting the window title. - subcmd = 'print title %s @@' % self.pid - cmd = 'uzblctrl -s "%s" -c "%s" > "%s" &' % (socket, subcmd, \ - self.parent.fifo_socket) - subprocess.Popen([cmd], shell=True) - self.send(self._probeurl) - - # Wont work yet. - #self.send(self._probetitle) - - self._lastprobe = time.time() + if self._connected: + self.send(self._probecmds) + self._lastprobe = time.time() - def send(self, msg): + def write(self, msg): '''Child fifo write function.''' - self._outgoing.append(msg) + self._fifoout.append(msg) # Flush messages from the queue if able. return self.flush() + def send(self, msg): + '''Child socket send function.''' + + self._socketout.append(msg) + # Flush messages from queue if able. + return self.flush() + + def __init__(self): '''Create tablist, window and notebook.''' - self.pages = {} - self._pidcounter = counter() - self.next_pid = self._pidcounter.next - self._watchers = {} + self._fifos = {} self._timers = {} self._buffer = "" - + + # Holds metadata on the uzbl childen open. + self.tabs = {} + + # Generates a unique id for uzbl socket filenames. + self.next_pid = counter().next + # Create main window self.window = gtk.Window() try: @@ -367,41 +382,14 @@ class UzblTabbed: self.window.show() self.wid = self.notebook.window.xid - # Fifo socket definition - self._refindfifos = re.compile('^uzbl_fifo_%s_[0-9]+$' % self.wid) + + # Create the uzbl_tabbed fifo fifo_filename = 'uzbltabbed_%d' % os.getpid() self.fifo_socket = os.path.join(config['fifo_dir'], fifo_filename) - - self._watchers = {} - self._buffer = "" self._create_fifo_socket(self.fifo_socket) self._setup_fifo_watcher(self.fifo_socket) - def run(self): - - # Update tablist timer - timer = "update-tablist" - timerid = gobject.timeout_add(500, self.update_tablist,timer) - self._timers[timer] = timerid - - # Due to the hackish way in which the window titles are read - # too many window will cause the application to slow down insanely - timer = "probe-clients" - timerid = gobject.timeout_add(1000, self.probe_clients, timer) - self._timers[timer] = timerid - - gtk.main() - - - def _find_fifos(self, fifo_dir): - '''Find all child fifo sockets in fifo_dir.''' - - dirlist = '\n'.join(os.listdir(fifo_dir)) - allfifos = self._refindfifos.findall(dirlist) - return sorted(allfifos) - - def _create_fifo_socket(self, fifo_socket): '''Create interprocess communication fifo socket.''' @@ -418,76 +406,113 @@ class UzblTabbed: print "Listening on %s" % self.fifo_socket - def _setup_fifo_watcher(self, fifo_socket, fd=None): + def _setup_fifo_watcher(self, fifo_socket): '''Open fifo socket fd and setup gobject IO_IN & IO_HUP watchers. Also log the creation of a fd and store the the internal self._watchers dictionary along with the filename of the fd.''' - - #TODO: Convert current self._watcher dict manipulation to the better - # IMHO self._timers handling by using "timer-keys" as the keys instead - # of the fifo fd's as keys. - if fd: + if fifo_socket in self._fifos.keys(): + fd, watchers = self._fifos[fifo_socket] os.close(fd) - if fd in self._watchers.keys(): - d = self._watchers[fd] - watchers = d['watchers'] - for watcher in list(watchers): - gobject.source_remove(watcher) - watchers.remove(watcher) - del self._watchers[fd] + for watcherid in watchers.keys(): + gobject.source_remove(watchers[watcherid]) + del watchers[watcherid] + + del self._fifos[fifo_socket] + # Re-open fifo and add listeners. fd = os.open(fifo_socket, os.O_RDONLY | os.O_NONBLOCK) - self._watchers[fd] = {'watchers': [], 'filename': fifo_socket} - - watcher = self._watchers[fd]['watchers'].append - watcher(gobject.io_add_watch(fd, gobject.IO_IN, self.read_fifo)) - watcher(gobject.io_add_watch(fd, gobject.IO_HUP, self.fifo_hangup)) + watchers = {} + self._fifos[fifo_socket] = (fd, watchers) + watcher = lambda key, id: watchers.__setitem__(key, id) + + # Watch for incoming data. + gid = gobject.io_add_watch(fd, gobject.IO_IN, self.main_fifo_read) + watcher('main-fifo-read', gid) + + # Watch for fifo hangups. + gid = gobject.io_add_watch(fd, gobject.IO_HUP, self.main_fifo_hangup) + watcher('main-fifo-hangup', gid) - def probe_clients(self, timer_call): - '''Load balance probe all uzbl clients for up-to-date window titles - and uri's.''' + def run(self): + '''UzblTabbed main function that calls the gtk loop.''' + + # Update tablist timer + #timer = "update-tablist" + #timerid = gobject.timeout_add(500, self.update_tablist,timer) + #self._timers[timer] = timerid - p = self.pages - probetimes = [(s, p[s]._lastprobe) for s in p.keys()] - socket, lasttime = sorted(probetimes, key=lambda t: t[1])[0] + # Probe clients every second for window titles and location + timer = "probe-clients" + timerid = gobject.timeout_add(1000, self.probe_clients, timer) + self._timers[timer] = timerid + + gtk.main() - if (time.time()-lasttime) > 5: - # Probe a uzbl instance at most once every 10 seconds - self.pages[socket].probe() + + def probe_clients(self, timer_call): + '''Probe all uzbl clients for up-to-date window titles and uri's.''' + + sockd = {} + + for tab in self.tabs.keys(): + uzbl = self.tabs[tab] + uzbl.probe() + if uzbl._socket: + sockd[uzbl._socket] = uzbl + + sockets = sockd.keys() + (reading, _, errors) = select.select(sockets, [], sockets, 0) + + for sock in reading: + uzbl = sockd[sock] + uzbl._buffer = sock.recv(1024) + temp = uzbl._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: + error("parse_command: invalid command %s" % ' '.join(cmd)) + raise return True - def fifo_hangup(self, fd, cb_condition): - '''Handle fifo socket hangups.''' + def main_fifo_hangup(self, fd, cb_condition): + '''Handle main fifo socket hangups.''' # Close fd, re-open fifo_socket and watch. - self._setup_fifo_watcher(self.fifo_socket, fd) + self._setup_fifo_watcher(self.fifo_socket) # And to kill any gobject event handlers calling this function: return False - def read_fifo(self, fd, cb_condition): - '''Read from fifo socket and handle fifo socket hangups.''' + 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 [s.strip().split() for s in temp if len(s.strip())]: + for cmd in cmds: try: - #print cmd + print cmd self.parse_command(cmd) except: - #raise - error("Invalid command: %s" % ' '.join(cmd)) + error("parse_command: invalid command %s" % ' '.join(cmd)) + raise return True + def parse_command(self, cmd): '''Parse instructions from uzbl child processes.''' @@ -508,9 +533,7 @@ class UzblTabbed: # goto last tab. # title {pid} {document-title} # updates tablist title. - # url {pid} {document-location} - - # WARNING SOME OF THESE COMMANDS MIGHT NOT BE WORKING YET OR FAIL. + # uri {pid} {document-location} if cmd[0] == "new": if len(cmd) == 2: @@ -520,10 +543,10 @@ class UzblTabbed: self.new_tab() elif cmd[0] == "newfromclip": - url = subprocess.Popen(['xclip','-selection','clipboard','-o'],\ + uri = subprocess.Popen(['xclip','-selection','clipboard','-o'],\ stdout=subprocess.PIPE).communicate()[0] - if url: - self.new_tab(url) + if uri: + self.new_tab(uri) elif cmd[0] == "close": if len(cmd) == 2: @@ -555,9 +578,9 @@ class UzblTabbed: elif cmd[0] == "last": self.goto_tab(-1) - elif cmd[0] in ["title", "url"]: + elif cmd[0] in ["title", "uri"]: if len(cmd) > 2: - uzbl = self.get_uzbl_by_pid(int(cmd[1])) + uzbl = self.get_tab_by_pid(int(cmd[1])) if uzbl: old = getattr(uzbl, cmd[0]) new = ' '.join(cmd[2:]) @@ -565,42 +588,45 @@ class UzblTabbed: if old != new: self.update_tablist() else: - error("Cannot find uzbl instance with pid %r" % int(cmd[1])) + error("parse_command: no uzbl with pid %r" % int(cmd[1])) else: - error("Unknown command: %s" % ' '.join(cmd)) + error("parse_command: unknown command %r" % ' '.join(cmd)) - def get_uzbl_by_pid(self, pid): + def get_tab_by_pid(self, pid): '''Return uzbl instance by pid.''' - for socket in self.pages.keys(): - if self.pages[socket].pid == pid: - return self.pages[socket] + for tab in self.tabs.keys(): + if self.tabs[tab].pid == pid: + return self.tabs[tab] + return False - def new_tab(self,url='', switch=True): + def new_tab(self, uri='', switch=True): '''Add a new tab to the notebook and start a new instance of uzbl. Use the switch option to negate config['switch_to_new_tabs'] option when you need to load multiple tabs at a time (I.e. like when restoring a session from a file).''' pid = self.next_pid() - socket = gtk.Socket() - socket.show() - self.notebook.append_page(socket) - sid = socket.get_id() - - if url: - url = '--uri %s' % url + tab = gtk.Socket() + tab.show() + self.notebook.append_page(tab) + sid = tab.get_id() fifo_filename = 'uzbl_fifo_%s_%0.2d' % (self.wid, pid) fifo_socket = os.path.join(config['fifo_dir'], fifo_filename) - uzbl = self.UzblInstance(self, socket, fifo_socket, pid,\ - url=url, switch=switch) - self.pages[socket] = uzbl - cmd = 'uzbl -s %s -n %s_%0.2d %s &' % (sid, self.wid, pid, url) - subprocess.Popen([cmd], shell=True) + socket_filename = 'uzbl_socket_%s_%0.2d' % (self.wid, pid) + socket_file = os.path.join(config['socket_dir'], socket_filename) + + # Create meta-instance and spawn child + if uri: uri = '--uri %s' % uri + uzbl = self.UzblInstance(self, tab, fifo_socket, socket_file, pid,\ + uri, switch) + self.tabs[tab] = uzbl + cmd = 'uzbl -s %s -n %s_%0.2d %s &' % (sid, self.wid, pid, uri) + subprocess.Popen([cmd], shell=True) # TODO: do i need close_fds=True ? # Add gobject timer to make sure the config is pushed when fifo socket # has been created. @@ -630,89 +656,91 @@ class UzblTabbed: bind(config['bind_goto_first'], 'goto 0') bind(config['bind_goto_last'], 'goto -1') + # uzbl.send via socket or uzbl.write via fifo, I'll try send. uzbl.send("\n".join(binds)) def goto_tab(self, n): '''Goto tab n (supports negative indexing).''' - notebook = list(self.notebook) - + if 0 <= n < self.notebook.get_n_pages(): + self.notebook.set_current_page(n) + self.update_tablist() + return None + try: - page = notebook[n] - i = notebook.index(page) + tabs = list(self.notebook) + tab = tabs[n] + i = tabs.index(tab) self.notebook.set_current_page(i) + self.update_tablist() except IndexError: pass - self.update_tablist() - - def next_tab(self, n=1): + def next_tab(self, step=1): '''Switch to next tab or n tabs right.''' - if n >= 1: - numofpages = self.notebook.get_n_pages() - pagen = self.notebook.get_current_page() + n - self.notebook.set_current_page( pagen % numofpages ) - + if step < 1: + error("next_tab: invalid step %r" % step) + return None + + ntabs = self.notebook.get_n_pages() + tabn = self.notebook.get_current_page() + step + self.notebook.set_current_page(tabn % ntabs) self.update_tablist() - def prev_tab(self, n=1): + def prev_tab(self, step=1): '''Switch to prev tab or n tabs left.''' - if n >= 1: - numofpages = self.notebook.get_n_pages() - pagen = self.notebook.get_current_page() - n - while pagen < 0: - pagen += numofpages - self.notebook.set_current_page(pagen) + if step < 1: + error("prev_tab: invalid step %r" % step) + return None + ntabs = self.notebook.get_n_pages() + tabn = self.notebook.get_current_page() - step + while tabn < 0: tabn += ntabs + self.notebook.set_current_page(tabn) self.update_tablist() - def close_tab(self, tabid=None): + def close_tab(self, tabn=None): '''Closes current tab. Supports negative indexing.''' - if not tabid: - tabid = self.notebook.get_current_page() + if tabn is None: + tabn = self.notebook.get_current_page() try: - socket = list(self.notebook)[tabid] + tab = list(self.notebook)[tabn] + except IndexError: - error("Invalid index. Cannot close tab.") - return False - - uzbl = self.pages[socket] - # Kill timers: - for timer in uzbl.timers.keys(): - error("Removing timer %r %r" % (timer, uzbl.timers[timer])) - gobject.source_remove(uzbl.timers[timer]) + error("close_tab: invalid index %r" % tabn) + return None - uzbl._outgoing = [] - uzbl._kill = True - del self.pages[socket] - self.notebook.remove_page(tabid) + self.notebook.remove_page(tabn) - self.update_tablist() - - def tab_closed(self, notebook, socket, page_num): + def tab_closed(self, notebook, tab, page_num): '''Close the window if no tabs are left. Called by page-removed signal.''' - if socket in self.pages.keys(): - uzbl = self.pages[socket] + if tab in self.tabs.keys(): + uzbl = self.tabs[tab] for timer in uzbl.timers.keys(): - error("Removing timer %r %r" % (timer, uzbl.timers[timer])) + error("tab_closed: removing timer %r" % timer) gobject.source_remove(uzbl.timers[timer]) + + if uzbl._socket: + uzbl._socket.close() + uzbl._socket = None - uzbl._outgoing = [] + uzbl._fifoout = [] + uzbl._socketout = [] uzbl._kill = True - del self.pages[socket] + del self.tabs[tab] if self.notebook.get_n_pages() == 0: self.quit() @@ -726,7 +754,7 @@ class UzblTabbed: self.update_tablist() - def update_tablist(self, timer_call=None): + def update_tablist(self): '''Upate tablist status bar.''' pango = "" @@ -735,21 +763,17 @@ class UzblTabbed: selected = (config['selected_tab'], config['selected_tab_text']) tab_format = " [ %d %s ] " - title_format = "%s - Uzbl Browser" - uzblkeys = self.pages.keys() + tabs = self.tabs.keys() curpage = self.notebook.get_current_page() - for index, socket in enumerate(self.notebook): - if socket not in uzblkeys: - #error("Theres a socket in the notebook that I have no uzbl "\ - # "record of.") - continue - uzbl = self.pages[socket] + for index, tab in enumerate(self.notebook): + if tab not in tabs: continue + uzbl = self.tabs[tab] if index == curpage: - colours = selected + colours = selected self.window.set_title(title_format % uzbl.title) else: @@ -762,23 +786,26 @@ class UzblTabbed: return True - #def quit(self, window, event): def quit(self, *args): '''Cleanup the application and quit. Called by delete-event signal.''' + + for fifo_socket in self._fifos.keys(): + fd, watchers = self._fifos[fifo_socket] + os.close(fd) + for watcherid in watchers.keys(): + gobject.source_remove(watchers[watcherid]) + del watchers[watcherid] - for fd in self._watchers.keys(): - d = self._watchers[fd] - watchers = d['watchers'] - for watcher in list(watchers): - gobject.source_remove(watcher) + del self._fifos[fifo_socket] - for timer in self._timers.keys(): - gobject.source_remove(self._timers[timer]) + for timerid in self._timers.keys(): + gobject.source_remove(self._timers[timerid]) + del self._timers[timerid] if os.path.exists(self.fifo_socket): os.unlink(self.fifo_socket) print "Unlinked %s" % self.fifo_socket - + if config['save_session']: session_file = os.path.expandvars(config['session_file']) if self.notebook.get_n_pages(): @@ -789,16 +816,15 @@ class UzblTabbed: h = open(session_file, 'w') h.write('current = %s\n' % self.notebook.get_current_page()) + tabs = self.tabs.keys() + for tab in list(self.notebook): + if tab not in tabs: continue + uzbl = self.tabs[tab] + h.write("%s\n" % uzbl.uri) h.close() - for socket in list(self.notebook): - if socket not in self.pages.keys(): continue - uzbl = self.pages[socket] - uzbl.send('sh "echo $6 >> %s"' % session_file) - time.sleep(0.05) - + else: # Notebook has no pages so delete session file if it exists. - # Its better to not exist than be blank IMO. if os.path.isfile(session_file): os.remove(session_file) @@ -814,14 +840,19 @@ if __name__ == "__main__": if os.path.isfile(os.path.expandvars(config['session_file'])): h = open(os.path.expandvars(config['session_file']),'r') - urls = [s.strip() for s in h.readlines()] + lines = [line.strip() for line in h.readlines()] h.close() current = 0 - for url in urls: - if url.startswith("current"): - current = int(url.split()[-1]) + for line in lines: + if line.startswith("current"): + current = int(line.split()[-1]) + else: - uzbl.new_tab(url, False) + uzbl.new_tab(line, False) + + if not len(lines): + self.new_tab() + else: uzbl.new_tab() -- cgit v1.2.3 From f4fa6569bf24d8a94b9bfffc105d17ff46767cd5 Mon Sep 17 00:00:00 2001 From: Mason Larobina Date: Tue, 30 Jun 2009 00:58:32 +0800 Subject: Update todo list. --- examples/data/uzbl/scripts/uzbl_tabbed.py | 4 ---- 1 file changed, 4 deletions(-) (limited to 'examples') diff --git a/examples/data/uzbl/scripts/uzbl_tabbed.py b/examples/data/uzbl/scripts/uzbl_tabbed.py index 9ecfb09..31c9416 100755 --- a/examples/data/uzbl/scripts/uzbl_tabbed.py +++ b/examples/data/uzbl/scripts/uzbl_tabbed.py @@ -72,10 +72,6 @@ # Issues: # - new windows are not caught and opened in a new tab. -# - need an easier way to read a uzbl instances window title instead of -# spawning a shell to spawn uzblctrl to communicate to the uzbl -# instance via socket to dump the window title to then pipe it to -# the tabbing managers fifo socket. # - probably missing some os.path.expandvars somewhere. -- cgit v1.2.3 From 490abcb73515e667acef6a8c2d9135aa71413c1b Mon Sep 17 00:00:00 2001 From: Mason Larobina Date: Tue, 30 Jun 2009 22:19:19 +0800 Subject: Added tablist style policy handler, updated author info & bug fixes. --- examples/data/uzbl/scripts/uzbl_tabbed.py | 130 ++++++++++++++++++++++-------- 1 file changed, 97 insertions(+), 33 deletions(-) (limited to 'examples') diff --git a/examples/data/uzbl/scripts/uzbl_tabbed.py b/examples/data/uzbl/scripts/uzbl_tabbed.py index 31c9416..932d4f6 100755 --- a/examples/data/uzbl/scripts/uzbl_tabbed.py +++ b/examples/data/uzbl/scripts/uzbl_tabbed.py @@ -2,7 +2,7 @@ # Uzbl tabbing wrapper using a fifo socket interface # Copyright (c) 2009, Tom Adams -# Copyright (c) 2009, quigybo +# Copyright (c) 2009, Chris van Dijk # Copyright (c) 2009, Mason Larobina # # This program is free software: you can redistribute it and/or modify @@ -23,8 +23,8 @@ # Tom Adams # Wrote the original uzbl_tabbed.py as a proof of concept. # -# quigybo -# Made signifigant headway on the uzbl_tabbing.py script on the +# Chris van Dijk (quigybo) +# Made signifigant headway on the old uzbl_tabbing.py script on the # uzbl wiki # # Mason Larobina @@ -42,7 +42,7 @@ # Here is a list of configuration options that can be customised and some # example values for each: # -# set show_tabs = 1 +# set show_tablist = 1 # set show_gtk_tabs = 0 # set switch_to_new_tabs = 1 # set save_session = 1 @@ -83,7 +83,6 @@ # currently open tabs are being displayed on the tablist. # - probably missing some os.path.expandvars somewhere and other # user-friendly.. things, this is still a very early version. -# - fix status_background issues & style tablist. # - add the small tab-list display when both gtk tabs and text vim-like # tablist are hidden (I.e. [ 1 2 3 4 5 ]) # - check spelling. @@ -113,8 +112,10 @@ if 'XDG_DATA_HOME' in os.environ.keys() and os.environ['XDG_DATA_HOME']: else: data_dir = os.path.join(os.environ['HOME'], '.local/share/uzbl/') + # === Default Configuration ==================================================== + # Location of your uzbl configuration file. if 'XDG_CONFIG_HOME' in os.environ.keys() and os.environ['XDG_CONFIG_HOME']: uzbl_config = os.path.join(os.environ['XDG_CONFIG_HOME'], 'uzbl/config') @@ -122,22 +123,21 @@ else: uzbl_config = os.path.join(os.environ['HOME'],'.config/uzbl/config') # All of these settings can be inherited from your uzbl config file. -config = {'show_tabs': True, +config = {'show_tablist': True, 'show_gtk_tabs': False, 'switch_to_new_tabs': True, 'save_session': True, 'fifo_dir': '/tmp', 'socket_dir': '/tmp', 'new_tab_title': 'New tab', + 'tablist_top': True, 'icon_path': os.path.join(data_dir, 'uzbl.png'), 'session_file': os.path.join(data_dir, 'session'), 'status_background': "#303030", - 'tab_colours': 'foreground = "#888"', - 'tab_text_colours': 'foreground = "#bbb"', - 'selected_tab': 'foreground = "#fff" background = "#303030"', - 'selected_tab_text': 'foreground = "#99FF66"', 'window_size': "800,800", 'monospace_size': 10, + + # Key binding options. 'bind_new_tab': 'gn', 'bind_tab_from_clip': 'gY', 'bind_close_tab': 'gC', @@ -145,10 +145,56 @@ config = {'show_tabs': True, 'bind_prev_tab': 'gT', 'bind_goto_tab': 'gi_', 'bind_goto_first': 'g<', - 'bind_goto_last':'g>'} + 'bind_goto_last':'g>', + + # Add custom tab style definitions to be used by the tab colour policy + # handler here. Because these are added to the config dictionary like + # any other uzbl_tabbed configuration option remember that they can + # be superseeded from your main uzbl config file. + 'tab_colours': 'foreground = "#888"', + 'tab_text_colours': 'foreground = "#bbb"', + 'selected_tab': 'foreground = "#fff"', + 'selected_tab_text': 'foreground = "green"', + 'tab_indicate_https': True, + 'https_colours': 'foreground = "#888"', + 'https_text_colours': 'foreground = "#9c8e2d"', + 'selected_https': 'foreground = "#fff"', + 'selected_https_text': 'foreground = "gold"',} + +# This is the tab style policy handler. Every time the tablist is updated +# this function is called to determine how to colourise that specific tab +# according the simple/complex rules as defined here. You may even wish to +# move this function into another python script and import it using: +# from mycustomtabbingconfig import colour_selector +# Remember to rename, delete or comment out this function if you do that. + +def colour_selector(tabindex, currentpage, uzbl): + '''Tablist styling policy handler. This function must return a tuple of + the form (tab style, text style).''' + + # Just as an example: + # if 'error' in uzbl.title: + # if tabindex == currentpage: + # return ('foreground="#fff"', 'foreground="red"') + # return ('foreground="#888"', 'foreground="red"') + + # Style tabs to indicate connected via https. + if config['tab_indicate_https'] and uzbl.uri.startswith("https://"): + if tabindex == currentpage: + return (config['selected_https'], config['selected_https_text']) + return (config['https_colours'], config['https_text_colours']) + + # Style to indicate selected. + if tabindex == currentpage: + return (config['selected_tab'], config['selected_tab_text']) + + # Default tab style. + return (config['tab_colours'], config['tab_text_colours']) + # === End Configuration ======================================================= + def readconfig(uzbl_config, config): '''Loads relevant config from the users uzbl config file into the global config dictionary.''' @@ -158,7 +204,7 @@ def readconfig(uzbl_config, config): return None # Define parsing regular expressions - isint = re.compile("^[0-9]+$").match + isint = re.compile("^(\-|)[0-9]+$").match findsets = re.compile("^set\s+([^\=]+)\s*\=\s*(.+)$",\ re.MULTILINE).findall @@ -167,7 +213,7 @@ def readconfig(uzbl_config, config): h.close() for (key, value) in findsets(rawconfig): - key = key.strip() + key, value = key.strip(), value.strip() if key not in config.keys(): continue if isint(value): value = int(value) config[key] = value @@ -343,7 +389,7 @@ class UzblTabbed: self.window.connect("delete-event", self.quit) # Create tab list - if config['show_tabs']: + if config['show_tablist']: vbox = gtk.VBox() self.window.add(vbox) ebox = gtk.EventBox() @@ -361,7 +407,6 @@ class UzblTabbed: ebox.show() bgcolor = gtk.gdk.color_parse(config['status_background']) ebox.modify_bg(gtk.STATE_NORMAL, bgcolor) - vbox.pack_start(ebox, False, False, 0) # Create notebook self.notebook = gtk.Notebook() @@ -370,9 +415,17 @@ class UzblTabbed: self.notebook.connect("page-removed", self.tab_closed) self.notebook.connect("switch-page", self.tab_changed) self.notebook.show() - if config['show_tabs']: - vbox.pack_end(self.notebook, True, True, 0) + if config['show_tablist']: + if config['tablist_top']: + vbox.pack_start(ebox, False, False, 0) + vbox.pack_end(self.notebook, True, True, 0) + + else: + vbox.pack_start(self.notebook, True, True, 0) + vbox.pack_end(ebox, False, False, 0) + vbox.show() + else: self.window.add(self.notebook) @@ -469,7 +522,7 @@ class UzblTabbed: cmds = [s.strip().split() for s in temp if len(s.strip())] for cmd in cmds: try: - print cmd + #print cmd self.parse_command(cmd) except: @@ -499,7 +552,7 @@ class UzblTabbed: for cmd in cmds: try: - print cmd + #print cmd self.parse_command(cmd) except: @@ -752,32 +805,43 @@ class UzblTabbed: def update_tablist(self): '''Upate tablist status bar.''' - - pango = "" - - normal = (config['tab_colours'], config['tab_text_colours']) - selected = (config['selected_tab'], config['selected_tab_text']) - - tab_format = " [ %d %s ] " - title_format = "%s - Uzbl Browser" + + show_tablist = config['show_tablist'] + show_gtk_tabs = config['show_gtk_tabs'] + if not show_tablist and not show_gtk_tabs: + return True tabs = self.tabs.keys() curpage = self.notebook.get_current_page() + title_format = "%s - Uzbl Browser" + + if show_tablist: + pango = "" + normal = (config['tab_colours'], config['tab_text_colours']) + selected = (config['selected_tab'], config['selected_tab_text']) + tab_format = " [ %d %s ] " + + if show_gtk_tabs: + gtk_tab_format = "%d %s" for index, tab in enumerate(self.notebook): if tab not in tabs: continue uzbl = self.tabs[tab] if index == curpage: - colours = selected self.window.set_title(title_format % uzbl.title) - else: - colours = normal - - pango += tab_format % (colours[0], index, colours[1], uzbl.title) + if show_gtk_tabs: + self.notebook.set_tab_label_text(tab, \ + gtk_tab_format % (index, uzbl.title)) - self.tablist.set_markup(pango) + if show_tablist: + style = colour_selector(index, curpage, uzbl) + (tabc, textc) = style + pango += tab_format % (tabc, index, textc, uzbl.title) + + if show_tablist: + self.tablist.set_markup(pango) return True -- cgit v1.2.3 From 80e271cabfc4b34a9883353e2d48344d6f33523b Mon Sep 17 00:00:00 2001 From: Mason Larobina Date: Wed, 1 Jul 2009 00:32:02 +0800 Subject: Feature requests, gtk_title_pos tab_titles max_title_len --- examples/data/uzbl/scripts/uzbl_tabbed.py | 32 +++++++++++++++++++++++++++---- 1 file changed, 28 insertions(+), 4 deletions(-) (limited to 'examples') diff --git a/examples/data/uzbl/scripts/uzbl_tabbed.py b/examples/data/uzbl/scripts/uzbl_tabbed.py index 932d4f6..019b235 100755 --- a/examples/data/uzbl/scripts/uzbl_tabbed.py +++ b/examples/data/uzbl/scripts/uzbl_tabbed.py @@ -46,6 +46,8 @@ # set show_gtk_tabs = 0 # set switch_to_new_tabs = 1 # set save_session = 1 +# set gtk_tab_pos = (left|bottom|top|right) +# set max_title_len = 50 # set new_tab_title = New tab # set status_background = #303030 # set session_file = $HOME/.local/share/session @@ -125,11 +127,14 @@ else: # All of these settings can be inherited from your uzbl config file. config = {'show_tablist': True, 'show_gtk_tabs': False, + 'gtk_tab_pos': "top", # top left bottom right 'switch_to_new_tabs': True, 'save_session': True, 'fifo_dir': '/tmp', + 'tab_titles': True, 'socket_dir': '/tmp', 'new_tab_title': 'New tab', + 'max_title_len': 50, 'tablist_top': True, 'icon_path': os.path.join(data_dir, 'uzbl.png'), 'session_file': os.path.join(data_dir, 'session'), @@ -411,6 +416,13 @@ class UzblTabbed: # Create notebook self.notebook = gtk.Notebook() self.notebook.set_show_tabs(config['show_gtk_tabs']) + + # Set tab position + allposes = {'left': gtk.POS_LEFT, 'right':gtk.POS_RIGHT, + 'top':gtk.POS_TOP, 'bottom':gtk.POS_BOTTOM} + if config['gtk_tab_pos'] in allposes.keys(): + self.notebook.set_tab_pos(allposes[config['gtk_tab_pos']]) + self.notebook.set_show_border(False) self.notebook.connect("page-removed", self.tab_closed) self.notebook.connect("switch-page", self.tab_changed) @@ -808,18 +820,23 @@ class UzblTabbed: show_tablist = config['show_tablist'] show_gtk_tabs = config['show_gtk_tabs'] + tab_titles = config['tab_titles'] if not show_tablist and not show_gtk_tabs: return True tabs = self.tabs.keys() curpage = self.notebook.get_current_page() title_format = "%s - Uzbl Browser" + max_title_len = config['max_title_len'] if show_tablist: pango = "" normal = (config['tab_colours'], config['tab_text_colours']) selected = (config['selected_tab'], config['selected_tab_text']) - tab_format = " [ %d %s ] " + if tab_titles: + tab_format = " [ %d %s ] " + else: + tab_format = " [ %d ] " if show_gtk_tabs: gtk_tab_format = "%d %s" @@ -832,13 +849,20 @@ class UzblTabbed: self.window.set_title(title_format % uzbl.title) if show_gtk_tabs: - self.notebook.set_tab_label_text(tab, \ - gtk_tab_format % (index, uzbl.title)) + if tab_titles: + self.notebook.set_tab_label_text(tab, \ + gtk_tab_format % (index, uzbl.title[:max_title_len])) + else: + self.notebook.set_tab_label_text(tab, str(index)) if show_tablist: style = colour_selector(index, curpage, uzbl) (tabc, textc) = style - pango += tab_format % (tabc, index, textc, uzbl.title) + if tab_titles: + pango += tab_format % (tabc, index, textc,\ + uzbl.title[:max_title_len]) + else: + pango += tab_format % (tabc, textc, index) if show_tablist: self.tablist.set_markup(pango) -- cgit v1.2.3 From 84d7728bf5da12cbda3da5c13887d5cf8d52c122 Mon Sep 17 00:00:00 2001 From: Sylvester Johansson Date: Tue, 30 Jun 2009 20:57:23 +0200 Subject: typos --- examples/config/uzbl/config | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'examples') diff --git a/examples/config/uzbl/config b/examples/config/uzbl/config index e7c03dc..a4a5f45 100644 --- a/examples/config/uzbl/config +++ b/examples/config/uzbl/config @@ -32,13 +32,13 @@ set font_size = 11 #set enable_spellcheck = 1 ## Private browsing -#set enbale_private = 0 +#set enable_private = 0 ## The URI of a stylesheet that is applied to every page #set stylesheet_uri = http://www.user.com/mystylelesheet.css ## enable/disable JavaScript -#set disbale_scripts = 1 +#set disable_scripts = 1 ## Whether text areas are resizable #set resizeable_text_areas = 1 -- cgit v1.2.3 From 439d787699e5eb5e49cb4fe4b7cdd4ed4fd80dee Mon Sep 17 00:00:00 2001 From: Mason Larobina Date: Wed, 1 Jul 2009 21:22:18 +0800 Subject: Missing os.path.expandvars functions & use markers for message termination --- examples/data/uzbl/scripts/uzbl_tabbed.py | 128 ++++++++++++++++++------------ 1 file changed, 79 insertions(+), 49 deletions(-) (limited to 'examples') diff --git a/examples/data/uzbl/scripts/uzbl_tabbed.py b/examples/data/uzbl/scripts/uzbl_tabbed.py index 019b235..4e9e1fb 100755 --- a/examples/data/uzbl/scripts/uzbl_tabbed.py +++ b/examples/data/uzbl/scripts/uzbl_tabbed.py @@ -74,7 +74,7 @@ # Issues: # - new windows are not caught and opened in a new tab. -# - probably missing some os.path.expandvars somewhere. +# - when uzbl_tabbed.py crashes it takes all the children with it. # Todo: @@ -83,11 +83,11 @@ # - ellipsize individual tab titles when the tab-list becomes over-crowded # - add "<" & ">" arrows to tablist to indicate that only a subset of the # currently open tabs are being displayed on the tablist. -# - probably missing some os.path.expandvars somewhere and other -# user-friendly.. things, this is still a very early version. # - add the small tab-list display when both gtk tabs and text vim-like # tablist are hidden (I.e. [ 1 2 3 4 5 ]) # - check spelling. +# - pass a uzbl socketid to uzbl_tabbed.py and have it assimilated into +# the collective. Resistance is futile! import pygtk @@ -102,69 +102,82 @@ import select import sys import gobject import socket +import random +import hashlib pygtk.require('2.0') def error(msg): sys.stderr.write("%s\n"%msg) + +# ============================================================================ +# ::: Default configuration section :::::::::::::::::::::::::::::::::::::::::: +# ============================================================================ + +# Location of your uzbl data directory. if 'XDG_DATA_HOME' in os.environ.keys() and os.environ['XDG_DATA_HOME']: data_dir = os.path.join(os.environ['XDG_DATA_HOME'], 'uzbl/') - else: data_dir = os.path.join(os.environ['HOME'], '.local/share/uzbl/') - - -# === Default Configuration ==================================================== - +if not os.path.exists(data_dir): + error("Warning: uzbl data_dir does not exist: %r" % data_dir) # Location of your uzbl configuration file. if 'XDG_CONFIG_HOME' in os.environ.keys() and os.environ['XDG_CONFIG_HOME']: uzbl_config = os.path.join(os.environ['XDG_CONFIG_HOME'], 'uzbl/config') else: uzbl_config = os.path.join(os.environ['HOME'],'.config/uzbl/config') +if not os.path.exists(uzbl_config): + error("Warning: Cannot locate your uzbl_config file %r" % uzbl_config) # All of these settings can be inherited from your uzbl config file. -config = {'show_tablist': True, - 'show_gtk_tabs': False, - 'gtk_tab_pos': "top", # top left bottom right - 'switch_to_new_tabs': True, - 'save_session': True, - 'fifo_dir': '/tmp', - 'tab_titles': True, - 'socket_dir': '/tmp', - 'new_tab_title': 'New tab', - 'max_title_len': 50, - 'tablist_top': True, - 'icon_path': os.path.join(data_dir, 'uzbl.png'), - 'session_file': os.path.join(data_dir, 'session'), - 'status_background': "#303030", - 'window_size': "800,800", - 'monospace_size': 10, +config = { + # Tab options + 'show_tablist': True, + 'show_gtk_tabs': False, + 'max_title_len': 50, + 'tablist_top': True, + 'tab_titles': True, + 'gtk_tab_pos': 'top', # (top|left|bottom|right) + 'new_tab_title': 'New tab', + 'switch_to_new_tabs': True, + + # uzbl options + 'save_session': True, + 'fifo_dir': '/tmp', + 'socket_dir': '/tmp', + 'icon_path': os.path.join(data_dir, 'uzbl.png'), + 'session_file': os.path.join(data_dir, 'session'), + 'status_background': "#303030", + 'window_size': "800,800", # in pixels + 'monospace_size': 10, - # Key binding options. - 'bind_new_tab': 'gn', - 'bind_tab_from_clip': 'gY', - 'bind_close_tab': 'gC', - 'bind_next_tab': 'gt', - 'bind_prev_tab': 'gT', - 'bind_goto_tab': 'gi_', - 'bind_goto_first': 'g<', - 'bind_goto_last':'g>', + # Key bindings. + 'bind_new_tab': 'gn', + 'bind_tab_from_clip': 'gY', + 'bind_close_tab': 'gC', + 'bind_next_tab': 'gt', + 'bind_prev_tab': 'gT', + 'bind_goto_tab': 'gi_', + 'bind_goto_first': 'g<', + 'bind_goto_last': 'g>', # Add custom tab style definitions to be used by the tab colour policy # handler here. Because these are added to the config dictionary like # any other uzbl_tabbed configuration option remember that they can # be superseeded from your main uzbl config file. - 'tab_colours': 'foreground = "#888"', - 'tab_text_colours': 'foreground = "#bbb"', - 'selected_tab': 'foreground = "#fff"', - 'selected_tab_text': 'foreground = "green"', - 'tab_indicate_https': True, - 'https_colours': 'foreground = "#888"', - 'https_text_colours': 'foreground = "#9c8e2d"', - 'selected_https': 'foreground = "#fff"', - 'selected_https_text': 'foreground = "gold"',} + 'tab_colours': 'foreground = "#888" background = "#303030"', + 'tab_text_colours': 'foreground = "#bbb"', + 'selected_tab': 'foreground = "#fff"', + 'selected_tab_text': 'foreground = "green"', + 'tab_indicate_https': True, + 'https_colours': 'foreground = "#888"', + 'https_text_colours': 'foreground = "#9c8e2d"', + 'selected_https': 'foreground = "#fff"', + 'selected_https_text': 'foreground = "gold"', + + } # End of config dict. # This is the tab style policy handler. Every time the tablist is updated # this function is called to determine how to colourise that specific tab @@ -197,7 +210,9 @@ def colour_selector(tabindex, currentpage, uzbl): return (config['tab_colours'], config['tab_text_colours']) -# === End Configuration ======================================================= +# ============================================================================ +# ::: End of configuration section ::::::::::::::::::::::::::::::::::::::::::: +# ============================================================================ def readconfig(uzbl_config, config): @@ -212,7 +227,7 @@ def readconfig(uzbl_config, config): isint = re.compile("^(\-|)[0-9]+$").match findsets = re.compile("^set\s+([^\=]+)\s*\=\s*(.+)$",\ re.MULTILINE).findall - + h = open(os.path.expandvars(uzbl_config), 'r') rawconfig = h.read() h.close() @@ -222,6 +237,11 @@ def readconfig(uzbl_config, config): if key not in config.keys(): continue if isint(value): value = int(value) config[key] = value + + # Ensure that config keys that relate to paths are expanded. + expand = ['fifo_dir', 'socket_dir', 'session_file', 'icon_path'] + for key in expand: + config[key] = os.path.expandvars(config[key]) def rmkdir(path): @@ -245,6 +265,12 @@ def counter(): yield i +def gen_endmarker(): + '''Generates a random md5 for socket message-termination endmarkers.''' + + return hashlib.md5(str(random.random()*time.time())).hexdigest() + + class UzblTabbed: '''A tabbed version of uzbl using gtk.Notebook''' @@ -273,12 +299,16 @@ class UzblTabbed: self._connected = False # The kill switch self._kill = False - + + # Message termination endmarker. + self._marker = gen_endmarker() + # Gen probe commands string probes = [] probe = probes.append - probe('print uri %d @uri' % self.pid) - probe('print title %d @@' % self.pid) + probe('print uri %d @uri %s' % (self.pid, self._marker)) + probe('print title %d @@ %s' % (self.pid,\ + self._marker)) self._probecmds = '\n'.join(probes) # Enqueue keybinding config for child uzbl instance @@ -528,8 +558,8 @@ class UzblTabbed: for sock in reading: uzbl = sockd[sock] - uzbl._buffer = sock.recv(1024) - temp = uzbl._buffer.split("\n") + uzbl._buffer = sock.recv(1024).replace('\n',' ') + temp = uzbl._buffer.split(uzbl._marker) self._buffer = temp.pop() cmds = [s.strip().split() for s in temp if len(s.strip())] for cmd in cmds: -- cgit v1.2.3 From ea2f26a2c194fece493856b22a9c0ca145c3c6b5 Mon Sep 17 00:00:00 2001 From: Mason Larobina Date: Thu, 2 Jul 2009 23:01:21 +0800 Subject: Fix cookies.py for XDG_DATA_HOME users. --- examples/data/uzbl/scripts/cookies.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'examples') diff --git a/examples/data/uzbl/scripts/cookies.py b/examples/data/uzbl/scripts/cookies.py index 4f80359..bf2d2e6 100755 --- a/examples/data/uzbl/scripts/cookies.py +++ b/examples/data/uzbl/scripts/cookies.py @@ -63,7 +63,7 @@ class FakeResponse: if __name__ == '__main__': if 'XDG_DATA_HOME' in os.environ.keys() and os.environ['XDG_DATA_HOME']: jar = cookielib.MozillaCookieJar(\ - os.path.join(os.environ['XDG_DATA_HOME'],'/uzbl/cookies.txt')) + os.path.join(os.environ['XDG_DATA_HOME'],'uzbl/cookies.txt')) else: jar = cookielib.MozillaCookieJar(\ os.path.join(os.environ['HOME'],'.local/share/uzbl/cookies.txt')) -- cgit v1.2.3 From dd78febd4d7f063bf42e5c80d852540a61ab1adf Mon Sep 17 00:00:00 2001 From: Mason Larobina Date: Fri, 3 Jul 2009 23:16:31 +0800 Subject: Bug fixes, added "open-tab-from-clipboard" binding --- examples/data/uzbl/scripts/uzbl_tabbed.py | 206 ++++++++++++++++++++---------- 1 file changed, 139 insertions(+), 67 deletions(-) (limited to 'examples') diff --git a/examples/data/uzbl/scripts/uzbl_tabbed.py b/examples/data/uzbl/scripts/uzbl_tabbed.py index 4e9e1fb..93592da 100755 --- a/examples/data/uzbl/scripts/uzbl_tabbed.py +++ b/examples/data/uzbl/scripts/uzbl_tabbed.py @@ -75,6 +75,10 @@ # Issues: # - new windows are not caught and opened in a new tab. # - when uzbl_tabbed.py crashes it takes all the children with it. +# - when a new tab is opened when using gtk tabs the tab button itself +# grabs focus from its child for a few seconds. +# - when switch_to_new_tabs is not selected the notebook page is +# maintained but the new window grabs focus (try as I might to stop it). # Todo: @@ -134,34 +138,39 @@ if not os.path.exists(uzbl_config): # All of these settings can be inherited from your uzbl config file. config = { # Tab options - 'show_tablist': True, - 'show_gtk_tabs': False, - 'max_title_len': 50, - 'tablist_top': True, - 'tab_titles': True, - 'gtk_tab_pos': 'top', # (top|left|bottom|right) - 'new_tab_title': 'New tab', - 'switch_to_new_tabs': True, + 'show_tablist': True, # Show text uzbl like statusbar tab-list + 'show_gtk_tabs': False, # Show gtk notebook tabs + 'tablist_top': True, # Display tab-list at top of window + 'gtk_tab_pos': 'top', # Gtk tab position (top|left|bottom|right) + 'switch_to_new_tabs': True, # Upon opening a new tab switch to it - # uzbl options - 'save_session': True, - 'fifo_dir': '/tmp', - 'socket_dir': '/tmp', + # Tab title options + 'tab_titles': True, # Display tab titles (else only tab-nums) + 'new_tab_title': 'Loading', # New tab title + 'max_title_len': 50, # Truncate title at n characters + 'show_ellipsis': True, # Show ellipsis when truncating titles + + # Core options + 'save_session': True, # Save session in file when quit + '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'), 'session_file': os.path.join(data_dir, 'session'), - 'status_background': "#303030", - 'window_size': "800,800", # in pixels - 'monospace_size': 10, + + # Window options + 'status_background': "#303030", # Default background for all panels + 'window_size': "800,800", # width,height in pixels # Key bindings. - 'bind_new_tab': 'gn', - 'bind_tab_from_clip': 'gY', - 'bind_close_tab': 'gC', - 'bind_next_tab': 'gt', - 'bind_prev_tab': 'gT', - 'bind_goto_tab': 'gi_', - 'bind_goto_first': 'g<', - 'bind_goto_last': 'g>', + 'bind_new_tab': 'gn', # Open new tab. + 'bind_tab_from_clip': 'gY', # Open tab from clipboard. + 'bind_tab_from_uri': 'go _', # Open new tab and goto entered uri. + 'bind_close_tab': 'gC', # Close tab. + 'bind_next_tab': 'gt', # Next tab. + 'bind_prev_tab': 'gT', # Prev tab. + 'bind_goto_tab': 'gi_', # Goto tab by tab-number (in title) + 'bind_goto_first': 'g<', # Goto first tab + 'bind_goto_last': 'g>', # Goto last tab # Add custom tab style definitions to be used by the tab colour policy # handler here. Because these are added to the config dictionary like @@ -293,7 +302,7 @@ class UzblTabbed: self._socketout = [] self._socket = None self._buffer = "" - # Switch to tab after connection + # Switch to tab after loading self._switch = switch # fifo/socket files exists and socket connected. self._connected = False @@ -354,12 +363,18 @@ class UzblTabbed: del self.timers[timer_call] if self._switch: - tabs = list(self.parent.notebook) - tabid = tabs.index(self.tab) - self.parent.goto_tab(tabid) - + self.grabfocus() + return len(self._fifoout + self._socketout) + + def grabfocus(self): + '''Steal parent focus and switch the notebook to my own tab.''' + + tabs = list(self.parent.notebook) + tabid = tabs.index(self.tab) + self.parent.goto_tab(tabid) + def probe(self): '''Probes the client for information about its self.''' @@ -392,6 +407,12 @@ class UzblTabbed: self._timers = {} self._buffer = "" + # Once a second is updated with the latest tabs' uris so that when the + # window is killed the session is saved. + self._tabsuris = [] + # And index of current page in self._tabsuris + self._curpage = 0 + # Holds metadata on the uzbl childen open. self.tabs = {} @@ -454,8 +475,13 @@ class UzblTabbed: self.notebook.set_tab_pos(allposes[config['gtk_tab_pos']]) self.notebook.set_show_border(False) + self.notebook.set_scrollable(True) + self.notebook.set_border_width(0) + self.notebook.connect("page-removed", self.tab_closed) self.notebook.connect("switch-page", self.tab_changed) + self.notebook.connect("page-added", self.tab_opened) + self.notebook.show() if config['show_tablist']: if config['tablist_top']: @@ -525,7 +551,7 @@ class UzblTabbed: gid = gobject.io_add_watch(fd, gobject.IO_HUP, self.main_fifo_hangup) watcher('main-fifo-hangup', gid) - + def run(self): '''UzblTabbed main function that calls the gtk loop.''' @@ -546,13 +572,21 @@ class UzblTabbed: '''Probe all uzbl clients for up-to-date window titles and uri's.''' sockd = {} + uriinventory = [] + tabskeys = self.tabs.keys() + notebooklist = list(self.notebook) - for tab in self.tabs.keys(): + for tab in notebooklist: + if tab not in tabskeys: continue uzbl = self.tabs[tab] + uriinventory.append(uzbl.uri) uzbl.probe() if uzbl._socket: sockd[uzbl._socket] = uzbl + self._tabsuris = uriinventory + self._curpage = self.notebook.get_current_page() + sockets = sockd.keys() (reading, _, errors) = select.select(sockets, [], sockets, 0) @@ -694,7 +728,7 @@ class UzblTabbed: return False - def new_tab(self, uri='', switch=True): + def new_tab(self, uri='', switch=None): '''Add a new tab to the notebook and start a new instance of uzbl. Use the switch option to negate config['switch_to_new_tabs'] option when you need to load multiple tabs at a time (I.e. like when @@ -711,8 +745,14 @@ class UzblTabbed: socket_filename = 'uzbl_socket_%s_%0.2d' % (self.wid, pid) socket_file = os.path.join(config['socket_dir'], socket_filename) + if switch is None: + switch = config['switch_to_new_tabs'] + + # Create meta-instance and spawn child - if uri: uri = '--uri %s' % uri + if len(uri.strip()): + uri = '--uri %s' % uri + uzbl = self.UzblInstance(self, tab, fifo_socket, socket_file, pid,\ uri, switch) self.tabs[tab] = uzbl @@ -740,6 +780,7 @@ class UzblTabbed: # bind ( key , command back to fifo ) bind(config['bind_new_tab'], 'new') bind(config['bind_tab_from_clip'], 'newfromclip') + bind(config['bind_tab_from_uri'], 'new %s') bind(config['bind_close_tab'], 'close') bind(config['bind_next_tab'], 'next') bind(config['bind_prev_tab'], 'prev') @@ -751,19 +792,21 @@ class UzblTabbed: uzbl.send("\n".join(binds)) - def goto_tab(self, n): + def goto_tab(self, index): '''Goto tab n (supports negative indexing).''' - if 0 <= n < self.notebook.get_n_pages(): - self.notebook.set_current_page(n) + tabs = list(self.notebook) + if 0 <= index < len(tabs): + self.notebook.set_current_page(index) self.update_tablist() return None try: - tabs = list(self.notebook) - tab = tabs[n] - i = tabs.index(tab) - self.notebook.set_current_page(i) + tab = tabs[index] + # Update index because index might have previously been a + # negative index. + index = tabs.index(tab) + self.notebook.set_current_page(index) self.update_tablist() except IndexError: @@ -778,8 +821,8 @@ class UzblTabbed: return None ntabs = self.notebook.get_n_pages() - tabn = self.notebook.get_current_page() + step - self.notebook.set_current_page(tabn % ntabs) + tabn = (self.notebook.get_current_page() + step) % ntabs + self.notebook.set_current_page(tabn) self.update_tablist() @@ -803,18 +846,30 @@ class UzblTabbed: if tabn is None: tabn = self.notebook.get_current_page() - try: - tab = list(self.notebook)[tabn] + else: + try: + tab = list(self.notebook)[tabn] - - except IndexError: - error("close_tab: invalid index %r" % tabn) - return None + except IndexError: + error("close_tab: invalid index %r" % tabn) + return None self.notebook.remove_page(tabn) + + def tab_opened(self, notebook, tab, index): + '''Called upon tab creation. Called by page-added signal.''' + + if config['switch_to_new_tabs']: + self.notebook.set_focus_child(tab) + + else: + oldindex = self.notebook.get_current_page() + oldtab = self.notebook.get_nth_page(oldindex) + self.notebook.set_focus_child(oldtab) + - def tab_closed(self, notebook, tab, page_num): + def tab_closed(self, notebook, tab, index): '''Close the window if no tabs are left. Called by page-removed signal.''' @@ -838,24 +893,32 @@ class UzblTabbed: self.update_tablist() + return True - def tab_changed(self, notebook, page, page_num): - '''Refresh tab list. Called by switch-page signal.''' - self.update_tablist() + def tab_changed(self, notebook, page, index): + '''Refresh tab list. Called by switch-page signal.''' + + tab = self.notebook.get_nth_page(index) + self.notebook.set_focus_child(tab) + self.update_tablist(index) + return True - def update_tablist(self): + def update_tablist(self, curpage=None): '''Upate tablist status bar.''' show_tablist = config['show_tablist'] show_gtk_tabs = config['show_gtk_tabs'] tab_titles = config['tab_titles'] + show_ellipsis = config['show_ellipsis'] if not show_tablist and not show_gtk_tabs: return True tabs = self.tabs.keys() - curpage = self.notebook.get_current_page() + if curpage is None: + curpage = self.notebook.get_current_page() + title_format = "%s - Uzbl Browser" max_title_len = config['max_title_len'] @@ -877,20 +940,24 @@ class UzblTabbed: if index == curpage: self.window.set_title(title_format % uzbl.title) + + tabtitle = uzbl.title[:max_title_len] + if show_ellipsis and len(tabtitle) != len(uzbl.title): + tabtitle = "%s\xe2\x80\xa6" % tabtitle[:-1] # Show Ellipsis if show_gtk_tabs: if tab_titles: - self.notebook.set_tab_label_text(tab, \ - gtk_tab_format % (index, uzbl.title[:max_title_len])) + self.notebook.set_tab_label_text(tab,\ + gtk_tab_format % (index, tabtitle)) else: self.notebook.set_tab_label_text(tab, str(index)) if show_tablist: style = colour_selector(index, curpage, uzbl) (tabc, textc) = style + if tab_titles: - pango += tab_format % (tabc, index, textc,\ - uzbl.title[:max_title_len]) + pango += tab_format % (tabc, index, textc, tabtitle) else: pango += tab_format % (tabc, textc, index) @@ -921,20 +988,17 @@ class UzblTabbed: print "Unlinked %s" % self.fifo_socket if config['save_session']: - session_file = os.path.expandvars(config['session_file']) - if self.notebook.get_n_pages(): + session_file = config['session_file'] + if len(self._tabsuris): if not os.path.isfile(session_file): dirname = os.path.dirname(session_file) if not os.path.isdir(dirname): + # Recursive mkdir not rmdir. rmkdir(dirname) - + + sessionstr = '\n'.join(self._tabsuris) h = open(session_file, 'w') - h.write('current = %s\n' % self.notebook.get_current_page()) - tabs = self.tabs.keys() - for tab in list(self.notebook): - if tab not in tabs: continue - uzbl = self.tabs[tab] - h.write("%s\n" % uzbl.uri) + h.write('current = %s\n%s' % (self._curpage, sessionstr)) h.close() else: @@ -957,14 +1021,22 @@ if __name__ == "__main__": lines = [line.strip() for line in h.readlines()] h.close() current = 0 + urls = [] for line in lines: if line.startswith("current"): current = int(line.split()[-1]) else: + urls.append(line.strip()) + + for (index, url) in enumerate(urls): + if current == index: + uzbl.new_tab(line, True) + + else: uzbl.new_tab(line, False) - if not len(lines): + if not len(urls): self.new_tab() else: -- cgit v1.2.3 From 14185edd46e52478907eacc1bd95e2a18c469e1b Mon Sep 17 00:00:00 2001 From: Mason Larobina Date: Sat, 4 Jul 2009 19:55:08 +0800 Subject: Update configuration section at the head of uzbl_tabbed.py --- examples/data/uzbl/scripts/uzbl_tabbed.py | 73 +++++++++++++++++++++---------- 1 file changed, 50 insertions(+), 23 deletions(-) (limited to 'examples') diff --git a/examples/data/uzbl/scripts/uzbl_tabbed.py b/examples/data/uzbl/scripts/uzbl_tabbed.py index 93592da..6ed902d 100755 --- a/examples/data/uzbl/scripts/uzbl_tabbed.py +++ b/examples/data/uzbl/scripts/uzbl_tabbed.py @@ -42,34 +42,60 @@ # Here is a list of configuration options that can be customised and some # example values for each: # -# set show_tablist = 1 -# set show_gtk_tabs = 0 -# set switch_to_new_tabs = 1 -# set save_session = 1 -# set gtk_tab_pos = (left|bottom|top|right) -# set max_title_len = 50 -# set new_tab_title = New tab -# set status_background = #303030 -# set session_file = $HOME/.local/share/session -# set tab_colours = foreground = "#999" -# set tab_text_colours = foreground = "#444" -# set selected_tab = foreground = "#aaa" background="#303030" -# set selected_tab_text = foreground = "green" -# set window_size = 800,800 +# General tabbing options: +# show_tablist = 1 +# show_gtk_tabs = 0 +# tablist_top = 1 +# gtk_tab_pos = (top|left|bottom|right) +# switch_to_new_tabs = 1 +# +# Tab title options: +# tab_titles = 1 +# new_tab_title = Loading +# max_title_len = 50 +# show_ellipsis = 1 # -# And the keybindings: +# Core options: +# save_session = 1 +# fifo_dir = /tmp +# socket_dir = /tmp +# icon_path = $HOME/.local/share/uzbl/uzbl.png +# session_file = $HOME/.local/share/uzbl/session # -# set bind_new_tab = gn -# set bind_tab_from_clip = gY -# set bind_close_tab = gC -# set bind_next_tab = gt -# set bind_prev_tab = gT -# set bind_goto_tab = gi_ -# set bind_goto_first = g< -# set bind_goto_last = g> +# Window options: +# status_background = #303030 +# window_size = 800,800 +# +# And the key bindings: +# bind_new_tab = gn +# bind_tab_from_clip = gY +# bind_tab_from_uri = go _ +# bind_close_tab = gC +# bind_next_tab = gt +# bind_prev_tab = gT +# bind_goto_tab = gi_ +# bind_goto_first = g< +# bind_goto_last = g> # # And uzbl_tabbed.py takes care of the actual binding of the commands via each # instances fifo socket. +# +# Custom tab styling: +# tab_colours = foreground = "#888" background = "#303030" +# tab_text_colours = foreground = "#bbb" +# selected_tab = foreground = "#fff" +# selected_tab_text = foreground = "green" +# tab_indicate_https = 1 +# https_colours = foreground = "#888" +# https_text_colours = foreground = "#9c8e2d" +# selected_https = foreground = "#fff" +# selected_https_text = foreground = "gold" +# +# How these styling values are used are soley defined by the syling policy +# handler below (the function in the config section). So you can for example +# turn the tab text colour Firetruck-Red in the event "error" appears in the +# tab title or some other arbitrary event. You may wish to make a trusted +# hosts file and turn tab titles of tabs visiting trusted hosts purple. # Issues: @@ -92,6 +118,7 @@ # - check spelling. # - pass a uzbl socketid to uzbl_tabbed.py and have it assimilated into # the collective. Resistance is futile! +# - on demand store the session to file (need binding & command for that) import pygtk -- cgit v1.2.3 From 8ddfa7f1b80c910525570eb33254a540a24ab75f Mon Sep 17 00:00:00 2001 From: Tom Adams Date: Sat, 27 Jun 2009 11:17:15 +0100 Subject: Don't need backslashes here. --- examples/data/uzbl/scripts/cookies.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'examples') diff --git a/examples/data/uzbl/scripts/cookies.py b/examples/data/uzbl/scripts/cookies.py index bf2d2e6..c8cf8c0 100755 --- a/examples/data/uzbl/scripts/cookies.py +++ b/examples/data/uzbl/scripts/cookies.py @@ -62,10 +62,10 @@ class FakeResponse: if __name__ == '__main__': if 'XDG_DATA_HOME' in os.environ.keys() and os.environ['XDG_DATA_HOME']: - jar = cookielib.MozillaCookieJar(\ + jar = cookielib.MozillaCookieJar( os.path.join(os.environ['XDG_DATA_HOME'],'uzbl/cookies.txt')) else: - jar = cookielib.MozillaCookieJar(\ + jar = cookielib.MozillaCookieJar( os.path.join(os.environ['HOME'],'.local/share/uzbl/cookies.txt')) try: jar.load() -- cgit v1.2.3 From 14a53251bbedb94ff0d78321276d5b0de9504f9a Mon Sep 17 00:00:00 2001 From: Tom Adams Date: Sat, 11 Jul 2009 12:11:13 +0100 Subject: Added new_window handler. --- examples/config/uzbl/config | 4 ++++ uzbl.c | 20 ++++++++++++++++++++ uzbl.h | 4 ++++ 3 files changed, 28 insertions(+) (limited to 'examples') diff --git a/examples/config/uzbl/config b/examples/config/uzbl/config index a4a5f45..3c2b7bf 100644 --- a/examples/config/uzbl/config +++ b/examples/config/uzbl/config @@ -11,6 +11,10 @@ set history_handler = spawn $XDG_DATA_HOME/uzbl/scripts/history.sh set download_handler = spawn $XDG_DATA_HOME/uzbl/scripts/download.sh set cookie_handler = spawn $XDG_DATA_HOME/uzbl/scripts/cookies.py +# Control how new windows should open +#set new_window = sh 'uzbl -u $8' # equivalent to the default behaviour +#set new_window = sh 'echo uri "$8" > $4' # open in same window + # You can bind whatever things (spawn , script ,..) to some events TODO: make events system more generic set load_start_handler = set status_message = wait set load_commit_handler = set status_message = recv diff --git a/uzbl.c b/uzbl.c index a998b91..a5d78f5 100644 --- a/uzbl.c +++ b/uzbl.c @@ -129,6 +129,7 @@ const struct { { "history_handler", PTR(uzbl.behave.history_handler, STR, 1, NULL)}, { "download_handler", PTR(uzbl.behave.download_handler, STR, 1, NULL)}, { "cookie_handler", PTR(uzbl.behave.cookie_handler, STR, 1, cmd_cookie_handler)}, + { "new_window", PTR(uzbl.behave.new_window, STR, 1, cmd_new_window)}, { "fifo_dir", PTR(uzbl.behave.fifo_dir, STR, 1, cmd_fifo_dir)}, { "socket_dir", PTR(uzbl.behave.socket_dir, STR, 1, cmd_socket_dir)}, { "http_debug", PTR(uzbl.behave.http_debug, INT, 1, cmd_http_debug)}, @@ -1049,6 +1050,12 @@ dehilight (WebKitWebView *page, GArray *argv, GString *result) { static void new_window_load_uri (const gchar * uri) { + if (uzbl.behave.new_window) { + GString *s = g_string_new (""); + g_string_printf(s, "'%s'", uri); + run_handler(uzbl.behave.new_window, s->str); + return; + } GString* to_execute = g_string_new (""); g_string_append_printf (to_execute, "%s --uri '%s'", uzbl.state.executable_path, uri); int i; @@ -1723,6 +1730,19 @@ cmd_cookie_handler() { g_strfreev (split); } +static void +cmd_new_window() { + gchar **split = g_strsplit(uzbl.behave.new_window, " ", 2); + /* pitfall: doesn't handle chain actions; must the sync_ action manually */ + if ((g_strcmp0(split[0], "sh") == 0) || + (g_strcmp0(split[0], "spawn") == 0)) { + g_free (uzbl.behave.new_window); + uzbl.behave.new_window = + g_strdup_printf("%s %s", split[0], split[1]); + } + g_strfreev (split); +} + static void cmd_fifo_dir() { uzbl.behave.fifo_dir = init_fifo(uzbl.behave.fifo_dir); diff --git a/uzbl.h b/uzbl.h index 9a7ccd2..d67a84e 100644 --- a/uzbl.h +++ b/uzbl.h @@ -137,6 +137,7 @@ typedef struct { gchar* socket_dir; gchar* download_handler; gchar* cookie_handler; + gchar* new_window; gboolean always_insert_mode; gboolean show_status; gboolean insert_mode; @@ -493,6 +494,9 @@ set_icon(); static void cmd_cookie_handler(); +static void +cmd_new_window(); + static void move_statusbar(); -- cgit v1.2.3