#!/usr/bin/python # browser-proxy.py # version 2.1 by steven676 and xiojason # (see http://talk.maemo.org/showpost.php?p=304298&postcount=566) # simple python-dbus service that proxies osso_browser events to Tear # based on code from http://paste.lisp.org/display/45824 # installation: # 0. ensure the needed python packages are installed: # python2.5, python2.5-dbus, and python2.5-gtk2 # 1. place this file in /home/user as browser-proxy.py # 2. make executable (chmod +x browser-proxy.py) # 3. change /usr/share/dbus-1/services/com.nokia.osso_browser.service to read: # [D-BUS Service] # Name=com.nokia.osso_browser # Exec=/home/user/browser-proxy.py # 4. disable tablet-browser-service (aka browserd) (optional, saves memory) # 5. you may wish to reboot. # notes: # - opening urls will be a bit slow. it takes some time to relay the messages to Tear # - modifications to the script may require the killing of an already-running # browser-proxy.py process -- just use 'kill' to stop it. # - modifying the osso_browser.service file prevents MicroB/browserd from working. # if you wish to restore MicroB/browserd, change the service file's contents back to: # [D-BUS Service] # Name=com.nokia.osso_browser # Exec=/usr/bin/browser # and re-enable tablet-browser-service again. # revision history: # 1.0 # 1.1 -> fixed wrong capitalization in dbus message # 1.2 -> removed return values, added osso_browser/request namespace (fixes Pidgin) # 1.3 -> sniff for local paths, prefix with file:// (fixes feedcircuit) # 1.4 -> can now manually launch MicroB/browser -- while open, it will be used instead # -- without --print-reply, the initial launching message seems to get lost # 1.5 -> added mime_open method used by File manager to open .html files # 2.0 -> several patches contributed by steven676: # -- only launch one window if Tear isn't already running # -- use gobject instead of gtk+ for main loop, uses less memory # -- use python dbus interface instead of shelling out for dbus-send # -- add 'continuous mode' option to keep proxy running (faster response) # -- kill browserd on exit if launched from the script # -- add option to use MicroB by default # 2.1 -> steven676 is now the primary maintainer # -- use a config file, /home/user/.config/browser-proxy, if available # -- add support for launching Fennec and Midori out of the box # -- introduce a config option default_browser for selecting the default browser ("tear", "microb", "fennec", "midori", "other") # -- add support for launching an arbitrary browser using the other_browser_cmd config option # -- run maemo-invoker directly instead of /usr/bin/browser to avoid a loop when /usr/bin/browser is a wrapper invoking this script # -- add a new, private D-Bus method for a /usr/bin/browser wrapper to use to launch MicroB with a URI # 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-proxy 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" default_browser = "tear" # 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 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-proxy", globals()) launcher.UpdateDefaultBrowser() except: # No valid config file available pass 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()