#!/usr/bin/python # browser-switchboard # version 2.2 by steven676 and xiojason # simple python-dbus service that proxies osso_browser events to Tear # based on code from http://paste.lisp.org/display/45824 # Copyright (C) 2009 Jason Simpson # Copyright (C) 2009 Steven Luo # 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 2 # of the License, or (at your option) any later version. # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # You should have received a copy of the GNU General Public License # along with this program; if not, write to the Free Software # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. # On Maemo systems, a copy of the GPL can be found in # /usr/share/common-licenses/GPL . import os import gobject import dbus import dbus.service import dbus.glib # Set default configuration values # These can be overriden by the config file $HOME/.config/browser-switchboard def setconfigdefaults(): global continuous_mode, default_browser, other_browser_cmd # continuous_mode: 0 -- close after handling a request; 1 -- run # continuously in the background continuous_mode = 0 # default_browser: "tear", "microb", "fennec", "midori", or "other" # empty string is handled specially -- see below default_browser = "" # If default browser is "other", what program to run (%s will be replaced # by URI) other_browser_cmd = "" class BrowserLauncher: def LaunchTear(self, uri): # We should be able to just call the D-Bus service to open Tear ... # but if Tear's not open, that causes D-Bus to start Tear and then # pass it the OpenAddress call, which results in two browser windows. # Properly fixing this probably requires Tear to provide a D-Bus method # that opens an address in an existing window, but for now work around # by just opening Tear via the command line if it's not running. if os.system("pidof tear > /dev/null") == 0: dbus.SessionBus().get_object('com.nokia.tear', '/com/nokia/tear').OpenAddress(uri, dbus_interface='com.nokia.Tear') if continuous_mode == 0: quit() else: if continuous_mode: if os.fork() != 0: # parent process doesn't need to do anything return # child process os.setsid() os.execl('/usr/bin/tear', '/usr/bin/tear', uri) def LaunchMicroB(self, uri): if os.system("pidof /usr/sbin/browserd > /dev/null") != 0: kill_browserd = 1 os.system("/usr/sbin/browserd -d") else: kill_browserd = 0 dbus.SessionBus().release_name("com.nokia.osso_browser") if uri == "new_window": # exec maemo-invoker directly instead of relying on the # /usr/bin/browser symlink, since /usr/bin/browser may have been # replaced with a shell script calling us via D-Bus os.spawnl(os.P_WAIT, '/usr/bin/maemo-invoker', '/usr/bin/browser') else: os.spawnl(os.P_WAIT, '/usr/bin/maemo-invoker', '/usr/bin/browser', '--url', uri) if kill_browserd: os.system("kill `pidof /usr/sbin/browserd`") if continuous_mode: dbus.SessionBus().request_name("com.nokia.osso_browser") else: quit() def LaunchOtherBrowser(self, uri): if uri == "new_window": uri = "" try: # URI must be quoted and quotes in the URI must be URL-escaped # to prevent the shell from interpreting any part of the URI command = other_browser_cmd % "'%s'" % uri.replace("'", "%27") except TypeError: # Couldn't substitute URI in, just launch the browser print "other_browser_cmd should have a %s placeholder for the URI" command = other_browser_cmd import subprocess subprocess.Popen(command, shell=True) if continuous_mode == 0: quit() def UpdateDefaultBrowser(self): global other_browser_cmd if default_browser == "tear": self.LaunchBrowser = self.LaunchTear elif default_browser == "microb": self.LaunchBrowser = self.LaunchMicroB elif default_browser == "fennec": # Cheat and reuse LaunchOtherBrowser, since we don't appear to # need to do anything special # TODO: does Fennec have a D-Bus API or signaling mechanism? # Invoking the fennec binary appears to be somewhat expensive other_browser_cmd = "fennec '%s'" self.LaunchBrowser = self.LaunchOtherBrowser elif default_browser == "midori": other_browser_cmd = "midori '%s'" self.LaunchBrowser = self.LaunchOtherBrowser elif default_browser == "other": if other_browser_cmd != "": self.LaunchBrowser = self.LaunchOtherBrowser else: print "default_browser is 'other', but no other_browser_cmd set -- using default" self.LaunchBrowser = self.LaunchTear elif default_browser == "": # If default_browser is empty, use Tear as the default if # installed, otherwise use MicroB if os.access("/usr/bin/tear", os.X_OK): self.LaunchBrowser = self.LaunchTear else: self.LaunchBrowser = self.LaunchMicroB else: print "Unknown default_browser %s, using default" % default_browser self.LaunchBrowser = self.LaunchTear def __init__(self): self.UpdateDefaultBrowser() class ProxyBrowserService(dbus.service.Object): def __init__(self): bus_name = dbus.service.BusName('com.nokia.osso_browser', bus=dbus.SessionBus()) dbus.service.Object.__init__(self, bus_name, '/com/nokia/osso_browser') dbus.service.Object.__init__(self, bus_name, '/com/nokia/osso_browser/request') def OpenAddress(self, uri): print uri if uri[0] == '/': print "prefixing apparent local path with file://" uri = "file://" + uri launcher.LaunchBrowser(uri) @dbus.service.method(dbus_interface='com.nokia.osso_browser', in_signature='s') def load_url(self, uri): print "load_url" self.OpenAddress(uri) @dbus.service.method(dbus_interface='com.nokia.osso_browser', in_signature='s') def mime_open(self, uri): print "mime_open" self.OpenAddress(uri) @dbus.service.method(dbus_interface='com.nokia.osso_browser', in_signature='s') def open_new_window(self, uri): print "open_new_window" self.OpenAddress(uri) @dbus.service.method(dbus_interface='com.nokia.osso_browser') def top_application(self): print "top_application" launcher.LaunchMicroB("new_window") # This method is an "undocumented", non-standard extension to the # osso_browser D-Bus API, intended solely to allow a wrapper script # replacing /usr/bin/browser to implement --url @dbus.service.method(dbus_interface='com.nokia.osso_browser') def switchboard_launch_microb(self, uri="new_window"): print "switchboard_launch_microb" launcher.LaunchMicroB(uri) def readconfigfile(signalnum=None, frame=None): # reset configuration to defaults setconfigdefaults() # read configuration from the config file, if available try: execfile(os.getenv("HOME", "/home/user") + "/.config/browser-switchboard", globals()) except: # Try the legacy config file location try: execfile(os.getenv("HOME", "/home/user") + "/.config/browser-proxy", globals()) except: # No valid config file available pass launcher.UpdateDefaultBrowser() setconfigdefaults() launcher = BrowserLauncher() pbrowser = ProxyBrowserService() readconfigfile() if continuous_mode: import signal def waitforzombies(signalnum, frame): try: while os.waitpid(-1, os.WNOHANG) != (0, 0): continue except OSError: pass signal.signal(signal.SIGCHLD, waitforzombies) signal.signal(signal.SIGHUP, readconfigfile) loop = gobject.MainLoop() loop.run()