diff --git a/qutebrowser/app.py b/qutebrowser/app.py index 065596283..c03dd5fef 100644 --- a/qutebrowser/app.py +++ b/qutebrowser/app.py @@ -21,11 +21,9 @@ import os import sys -import json import subprocess import faulthandler import configparser -import getpass import signal import warnings import bdb @@ -36,7 +34,6 @@ import traceback from PyQt5.QtWidgets import QApplication, QDialog from PyQt5.QtCore import (pyqtSlot, qInstallMessageHandler, QTimer, QUrl, QStandardPaths, QObject) -from PyQt5.QtNetwork import QLocalSocket, QLocalServer import qutebrowser from qutebrowser.commands import cmdutils, runners @@ -46,7 +43,8 @@ from qutebrowser.browser import quickmarks, cookies, downloads, cache from qutebrowser.widgets import mainwindow, crash from qutebrowser.keyinput import modeman from qutebrowser.utils import (log, version, message, readline, utils, qtutils, - urlutils, debug, objreg, usertypes, standarddir) + urlutils, debug, objreg, usertypes, standarddir, + ipc) # We import utilcmds to run the cmdutils.register decorators. from qutebrowser.utils import utilcmds # pylint: disable=unused-import @@ -105,29 +103,10 @@ class Application(QApplication): print(version.GPL_BOILERPLATE.strip()) sys.exit(0) - socketname = 'qutebrowser-{}'.format(getpass.getuser()) - - self.socket = QLocalSocket(self) - self.socket.connectToServer(socketname) - is_running = self.socket.waitForConnected(100) - if is_running: - log.init.info("Opening in existing instance") - line = json.dumps(self._args.command) + '\n' - self.socket.writeData(line.encode('utf-8')) + sent = ipc.send_to_running_instance(self._args.command) + if sent: sys.exit(0) - self.server = QLocalServer() - ok = QLocalServer.removeServer(socketname) - if not ok: - # FIXME - raise Exception - ok = self.server.listen(socketname) - if not ok: - # FIXME - raise Exception("Error while listening to local socket: {}".format( - self.server.errorString())) - self.server.newConnection.connect(self.on_localsocket_connection) - log.init.debug("Starting init...") self.setQuitOnLastWindowClosed(False) self.setOrganizationName("qutebrowser") @@ -155,16 +134,6 @@ class Application(QApplication): def __repr__(self): return utils.get_repr(self) - def on_localsocket_connection(self): - socket = self.server.nextPendingConnection() - # FIXME timeout: - while not socket.canReadLine(): - socket.waitForReadyRead() - data = bytes(socket.readLine()) - args = json.loads(data.decode('utf-8')) - self._process_args(args) - socket.deleteLater() - def _init_modules(self): """Initialize all 'modules' which need to be initialized.""" log.init.debug("Initializing readline-bridge...") @@ -254,11 +223,11 @@ class Application(QApplication): def _open_pages(self): """Open startpage etc. and process commandline args.""" - self._process_args(self._args.command) + self.process_args(self._args.command) self._open_startpage() self._open_quickstart() - def _process_args(self, args): + def process_args(self, args): """Process commandline args. URLs to open have no prefix, commands to execute begin with a colon. diff --git a/qutebrowser/utils/ipc.py b/qutebrowser/utils/ipc.py new file mode 100644 index 000000000..5c0b262c8 --- /dev/null +++ b/qutebrowser/utils/ipc.py @@ -0,0 +1,83 @@ +# vim: ft=python fileencoding=utf-8 sts=4 sw=4 et: + +# Copyright 2014 Florian Bruhin (The Compiler) +# +# This file is part of qutebrowser. +# +# qutebrowser 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. +# +# qutebrowser 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 qutebrowser. If not, see . + +"""Utilities for IPC with existing instances.""" + +import json +import getpass + +from PyQt5.QtNetwork import QLocalSocket, QLocalServer + +from qutebrowser.utils import log, objreg + + +SOCKETNAME = 'qutebrowser-{}'.format(getpass.getuser()) +CONNECT_TIMEOUT = 100 + +server = None + + +def send_to_running_instance(cmdlist): + """Try to send a commandline to a running instance. + + Blocks for CONNECT_TIMEOUT ms. + + Args: + cmdlist: A list to send (URLs/commands) + + Return: + True if connecting was successful, False if no connection was made. + """ + socket = QLocalSocket() + socket.connectToServer(SOCKETNAME) + connected = socket.waitForConnected(100) + if connected: + log.init.info("Opening in existing instance") + line = json.dumps(cmdlist) + '\n' + socket.writeData(line.encode('utf-8')) + else: + return False + + + +def init_server(): + global server + server = QLocalServer() + ok = QLocalServer.removeServer(SOCKETNAME) + if not ok: + # FIXME + raise Exception + ok = server.listen(SOCKETNAME) + if not ok: + # FIXME + raise Exception("Error while listening to local socket: {}".format( + server.errorString())) + server.newConnection.connect(on_localsocket_connection) + + +def on_localsocket_connection(self): + socket = self.server.nextPendingConnection() + # FIXME timeout: + while not socket.canReadLine(): + socket.waitForReadyRead() + data = bytes(socket.readLine()) + args = json.loads(data.decode('utf-8')) + app = objreg.get('app') + app.process_args(args) + socket.deleteLater()