Esempio n. 1
0
    def register_qt_recv_signal(self, rxMsgSignal, recvMatch=None):
        """The client is a Qt app, and wants to receive the messages specified in recvMatch
         via the rxMsgSignal
        """
        self.rxMsgSignal = rxMsgSignal
        self.recvMatch = recvMatch

        if self.mavfile:
            if isinstance(self.mavfile, mavutil.mavmmaplog):
                self.thread = QThread()
                self.recvWorker = UqtMavFileRecvWorker(self.mavfile, self.rxMsgSignal, self.recvMatch)
                self.recvWorker.moveToThread(self.thread)
                self.recvWorker.finished.connect(self.thread.quit)                
                self.thread.started.connect(self.recvWorker.worker)
                self.thread.start()

            elif type(self.mavfile) in [ mavutil.mavserial ]:
                fd = self.get_file_descriptor()
                if fd >= 0:
                    self.notifier = QSocketNotifier(fd, QSocketNotifier.Read)
                    self.notifier.activated.connect(self.can_read)

            elif type(self.mavfile) in [ mavutil.mavudp, mavutil.mavtcp, mavutil.mavtcpin,
                                         mavutil.mavmcast, mavutil.mavlogfile, mavutil.mavlogfile ]:
                fd = self.get_file_descriptor()
                if fd:
                    self.notifier = QSocketNotifier(fd.fileno(), QSocketNotifier.Read)
                    self.notifier.activated.connect(self.can_read)
            elif isinstance(self.mavfile, mavutil.mavchildexec):
                pass
Esempio n. 2
0
    def activate(self):
        """Set up signal handlers.

        On Windows this uses a QTimer to periodically hand control over to
        Python so it can handle signals.

        On Unix, it uses a QSocketNotifier with os.set_wakeup_fd to get
        notified.
        """
        self._orig_handlers[signal.SIGINT] = signal.signal(
            signal.SIGINT, self.interrupt)
        self._orig_handlers[signal.SIGTERM] = signal.signal(
            signal.SIGTERM, self.interrupt)

        if os.name == 'posix' and hasattr(signal, 'set_wakeup_fd'):
            # pylint: disable=import-error,no-member
            import fcntl
            read_fd, write_fd = os.pipe()
            for fd in (read_fd, write_fd):
                flags = fcntl.fcntl(fd, fcntl.F_GETFL)
                fcntl.fcntl(fd, fcntl.F_SETFL, flags | os.O_NONBLOCK)
            self._notifier = QSocketNotifier(read_fd, QSocketNotifier.Read,
                                             self)
            self._notifier.activated.connect(self.handle_signal_wakeup)
            self._orig_wakeup_fd = signal.set_wakeup_fd(write_fd)
        else:
            self._timer.start(1000)
            self._timer.timeout.connect(lambda: None)
        self._activated = True
Esempio n. 3
0
    def setup(self,
              db_widget,
              sock,
              width=960,
              ffmly='Fantasque Sans Mono',
              fscale=1.0):
        """Initialization routine for GUI dashboard widget: Call
           the base-class initialization routine, then establish a
           callback to receive messages over the socket.
        """

        self.db_widget, self.sock = db_widget, sock
        self.setupUi(db_widget, width=width, ffmly=ffmly, fscale=fscale)
        """ tabulate distinct fonts in widget for subsequent use in rescaling, etc. """
        self.font_set = set()

        def find_fonts(w):
            if hasattr(w, 'font'):
                self.font_set.add(w.font())
            for child in w.children():
                find_fonts(child)

        find_fonts(self.db_widget)
        log('Found {} fonts:'.format(len(self.font_set)))
        for font in self.font_set:
            log('  {}'.format(font.toString()))
        """ arrange for read_input to be called whenever data is available on the socket"""
        self.sock.setblocking(False)
        self.notifier = QSocketNotifier(sock.fileno(), QSocketNotifier.Read,
                                        db_widget)
        self.notifier.setEnabled(True)
        self.notifier.activated.connect(self.read_input)
Esempio n. 4
0
class QTZOCPNode(QWidget):
    def __init__(self):
        super(QTZOCPNode, self).__init__()
        self.qle = QTextEdit(self)
        self.qle.move(1, 1)
        self.qle.resize(640, 480)
        self.init_zocp()
        self.show()

    def init_zocp(self):
        self.z = ZOCP("QT UI TEST")
        self.z.register_float("myFloat", 2.3, 'rw', 0, 5.0, 0.1)
        self.notifier = QSocketNotifier(self.z.inbox.getsockopt(zmq.FD),
                                        QSocketNotifier.Read)
        self.notifier.setEnabled(True)
        self.notifier.activated.connect(self.zocp_event)
        self.z.on_modified = self.on_modified
        self.z.start()

    def zocp_event(self):
        print("ZOCP EVENT START")
        self.z.run_once(0)
        print("ZOCP EVENT END")

    def on_modified(self, peer, name, data, *args, **kwargs):
        t = self.qle.toPlainText()
        t = "{0}\n{1}".format(data, t)
        self.qle.setPlainText(t)

    def closeEvent(self, *args):
        print(args)
        self.z.stop()
        del self.z
Esempio n. 5
0
    def __init__(self, parent=None):
        super().__init__(parent)
        self._context = zmq.Context()

        self._sub_socket = self._context.socket(zmq.SUB)
        self._sub_socket.bind('tcp://*:3901')
        self._sub_socket.setsockopt(zmq.SUBSCRIBE, b'')

        self._pub_socket = self._context.socket(zmq.PUB)
        self._pub_socket.bind('tcp://*:3902')

        self._notifier = QSocketNotifier(self._sub_socket.getsockopt(zmq.FD),
                                         QSocketNotifier.Read, self)
        self._notifier.activated.connect(self._on_sub_socket_event)

        self._config_status = 0
        self._score = 0
        self._heartbeat = 0
        self._match_timer = 0
        self._side = 0
        self._match_state = 0
        self._odrive_state = '00'
        self._odrive_error = False
        self._tirette = False
        self._emergency_stop = False
Esempio n. 6
0
    def activate(self):
        """Set up signal handlers.

        On Windows this uses a QTimer to periodically hand control over to
        Python so it can handle signals.

        On Unix, it uses a QSocketNotifier with os.set_wakeup_fd to get
        notified.
        """
        self._orig_handlers[signal.SIGINT] = signal.signal(
            signal.SIGINT, self.interrupt)
        self._orig_handlers[signal.SIGTERM] = signal.signal(
            signal.SIGTERM, self.interrupt)

        if utils.is_posix and hasattr(signal, 'set_wakeup_fd'):
            # pylint: disable=import-error,no-member,useless-suppression
            import fcntl
            read_fd, write_fd = os.pipe()
            for fd in [read_fd, write_fd]:
                flags = fcntl.fcntl(fd, fcntl.F_GETFL)
                fcntl.fcntl(fd, fcntl.F_SETFL, flags | os.O_NONBLOCK)
            self._notifier = QSocketNotifier(typing.cast(sip.voidptr, read_fd),
                                             QSocketNotifier.Read,
                                             self)
            self._notifier.activated.connect(  # type: ignore[attr-defined]
                self.handle_signal_wakeup)
            self._orig_wakeup_fd = signal.set_wakeup_fd(write_fd)
            # pylint: enable=import-error,no-member,useless-suppression
        else:
            self._timer.start(1000)
            self._timer.timeout.connect(lambda: None)
        self._activated = True
Esempio n. 7
0
class Signal(QObject):
    signal = pyqtSignal(int)
    fds = {}

    def __init__(self, signum, parent):
        super(Signal, self).__init__(parent)
        self.signum = signum
        self.sn = None
        self.fd = [None, None]
        if self.setupHandler() < 0:
            return

        self.sn = QSocketNotifier(self.fd[1].fileno(), QSocketNotifier.Read,
                                  parent)
        self.sn.activated.connect(self.handleSignal)

    def __del__(self):
        #signal.signal( self.signum, signal.SIG_DFL)
        if self.signum in Signal.fds:
            Signal.fds.pop(self.signum)
        if self.fd[0] is not None:
            self.fd[0].close()
        if self.fd[1] is not None:
            self.fd[1].close()
        #super(Signal,self).__del__()

    @staticmethod
    def create(signum, parent):
        syslog.syslog(syslog.LOG_DEBUG,
                      "DEBUG  creating Signal instance for %d" % signum)
        if signum in Signal.fds:
            if Signal.fds[signum].sn:
                Signal.fds[signum].sn.deleteLater()
            del (Signal.fds[signum])
        return Signal(signum, parent)

    def handleSignal(self):
        syslog.syslog(syslog.LOG_DEBUG,
                      "DEBUG  handling signal %d" % self.signum)
        self.sn.setEnabled(False)
        self.fd[1].recv(1)
        self.signal.emit(self.signum)
        self.sn.setEnabled(True)

    def setupHandler(self):
        syslog.syslog(syslog.LOG_DEBUG,
                      "DEBUG  setting up handler for signal %d" % self.signum)
        self.fd = socket.socketpair(socket.AF_UNIX, socket.SOCK_STREAM, 0)
        if not self.fd:
            return -1
        Signal.fds[self.signum] = self
        signal.signal(self.signum, self.handler)
        signal.siginterrupt(self.signum, False)
        return 0

    @staticmethod
    def handler(signum, frame):
        syslog.syslog(syslog.LOG_DEBUG, "DEBUG  handling signal %d" % signum)
        Signal.fds[signum].fd[0].send(bytes([1]))
Esempio n. 8
0
class ServerSocket(QObject):
    """
    This class is acts a bridge between a server socket and the Qt event loop.
    See the ClientSocket class for a more detailed explanation.
    """

    def __init__(self, logger, parent=None):
        QObject.__init__(self, parent)
        self._logger = logger
        self._socket = None
        self._connected = False
        self._accept_notifier = None

    @property
    def connected(self):
        """Is the underlying socket connected?"""
        return self._connected

    def connect(self, sock):
        """Sets the underlying socket to utilize."""
        self._accept_notifier = QSocketNotifier(
            sock.fileno(), QSocketNotifier.Read, self
        )
        self._accept_notifier.activated.connect(self._notify_accept)
        self._accept_notifier.setEnabled(True)

        self._socket = sock
        self._connected = True

    def disconnect(self, err=None):
        """Terminates the current connection."""
        if not self._socket:
            return
        if err:
            self._logger.warning("Connection lost")
            self._logger.exception(err)
        self._accept_notifier.setEnabled(False)
        try:
            self._socket.close()
        except socket.error:
            pass
        self._socket = None
        self._connected = False

    def _notify_accept(self):
        """Callback called when a client is connecting."""
        while True:
            try:
                sock, address = self._socket.accept()
            except socket.error as e:
                if e.errno in (errno.EAGAIN, errno.EWOULDBLOCK):
                    break
                self.disconnect(e)
                break
            self._accept(sock)

    def _accept(self, socket):
        """Handles the client who newly connected."""
        raise NotImplementedError("accept() is not implemented")
Esempio n. 9
0
class FileListStream(QObject):
    """FileListStream represents a stream of filenames read from stdin or
    from other sources that is visualized in the FileView.
    """

    sig_file_added = pyqtSignal(FileInfo)
    sig_end_of_stream = pyqtSignal()
    sig_error = pyqtSignal()

    @staticmethod
    def from_location(app, linesep, location):
        if location.get_path() in ["/stdin", "stdin"]:
            tee_fd, stream_id = app.stream_manager.get_stdin()
        else:
            raise Exception("FileListStream: unknown location: %s", location)

        return FileListStream(app.vfs, tee_fd, linesep)

    @property
    def sig_finished(self):
        return self.sig_end_of_stream

    def __init__(self, vfs: 'VirtualFilesystem',
                 fp: IO, linesep: str = "\n") -> None:
        super().__init__()

        self.vfs = vfs
        self.fp = fp
        self.linesep = linesep

        self.readliner = None
        self.socket_notifier: Optional[QSocketNotifier] = None

    def close(self):
        self.fp.close()

    def start(self):
        self.readliner = non_blocking_readline(self.fp, self.linesep)

        self.socket_notifier = QSocketNotifier(self.fp.fileno(), QSocketNotifier.Read)
        self.socket_notifier.activated.connect(self._on_activated)

    def _on_activated(self, fd: int) -> None:
        while True:
            try:
                filename: str = next(self.readliner)
            except StopIteration:
                self.socket_notifier.setEnabled(False)
                self.socket_notifier = None
                self.sig_end_of_stream.emit()
                return
            else:
                if filename is not None:
                    location = Location.from_path(filename)
                    self.sig_file_added.emit(self.vfs.get_fileinfo(location))
                else:
                    return
Esempio n. 10
0
 def init_zocp(self):
     self.z = ZOCP("QT UI TEST")
     self.z.register_float("myFloat", 2.3, 'rw', 0, 5.0, 0.1)
     self.notifier = QSocketNotifier(self.z.inbox.getsockopt(zmq.FD),
                                     QSocketNotifier.Read)
     self.notifier.setEnabled(True)
     self.notifier.activated.connect(self.zocp_event)
     self.z.on_modified = self.on_modified
     self.z.start()
Esempio n. 11
0
    def connect(self, sock):
        """Sets the underlying socket to utilize."""
        self._accept_notifier = QSocketNotifier(sock.fileno(),
                                                QSocketNotifier.Read, self)
        self._accept_notifier.activated.connect(self._notify_accept)
        self._accept_notifier.setEnabled(True)

        self._socket = sock
        self._connected = True
Esempio n. 12
0
    def init_connect_zmq(self, on_poll, uri, topicfilter):
        logger.debug('QWZMQListener.init_connect_zmq uri=%s' % uri)
        self.zmq_context = zmq.Context(1)
        self.zmq_socket = self.zmq_context.socket(zmq.SUB)
        self.zmq_socket.connect(uri)
        self.zmq_socket.setsockopt(zmq.SUBSCRIBE, topicfilter)

        self.zmq_notifier = QSocketNotifier(self.zmq_socket.getsockopt(zmq.FD), QSocketNotifier.Read, self)
        self.zmq_notifier.activated.connect(on_poll)
Esempio n. 13
0
class QWZMQListener(QWidget):
    def __init__(self, **kwargs):
        QWidget.__init__(self, parent=None)
        #logger.debug('In QWZMQListener.__init__')

        self.timeout = kwargs.get('timeout', 1000)
        _is_normal   = kwargs.get('is_normal', True)
        _on_poll     = kwargs.get('on_poll', self.on_zmq_poll)
        _host        = kwargs.get('host', 'localhost')
        _platform    = kwargs.get('platform', 6)
        _topicfilter = kwargs.get('topicfilter', b'') # b'10001'
        _uri         = 'tcp://%s:%d' % (_host, front_pub_port(_platform)) # 'tcp://localhost:30016'

        if _is_normal : self.init_connect_zmq(_on_poll, _uri, _topicfilter)


    def init_connect_zmq(self, on_poll, uri, topicfilter):
        logger.debug('QWZMQListener.init_connect_zmq uri=%s' % uri)
        self.zmq_context = zmq.Context(1)
        self.zmq_socket = self.zmq_context.socket(zmq.SUB)
        self.zmq_socket.connect(uri)
        self.zmq_socket.setsockopt(zmq.SUBSCRIBE, topicfilter)

        self.zmq_notifier = QSocketNotifier(self.zmq_socket.getsockopt(zmq.FD), QSocketNotifier.Read, self)
        self.zmq_notifier.activated.connect(on_poll)


    def on_zmq_poll(self):
        """Needs to be re-implemented to do real work with messages from zmq.
        """
        self.zmq_notifier.setEnabled(False)
        flags = self.zmq_socket.getsockopt(zmq.EVENTS)
        flag = 'UNKNOWN'
        msg = ''
        if flags & zmq.POLLIN :
            flag = 'POLLIN'
            msg = self.zmq_socket.recv_multipart()
            self.setWindowTitle(str(msg))
        elif flags & zmq.POLLOUT : flag = 'POLLOUT'
        elif flags & zmq.POLLERR : flag = 'POLLERR'
        else : pass
        print("Flag zmq.%s in %d msg: %s" % (flag, flags, msg))

        self.zmq_notifier.setEnabled(True)
        self.kick_zmq() # WITHOUT THIS LINE IT WOULD NOT CALL on_read_msg AGAIN!


    def kick_zmq(self):
        """ WITHOUT THIS LINE IT WOULD NOT CALL on_read_msg AGAIN!
        """
        _flags = self.zmq_socket.getsockopt(zmq.EVENTS)


    def closeEvent(self, e) :
        logger.debug('%s.closeEvent' % self._name)
        QWidget.closeEvent(self, e)
Esempio n. 14
0
 def __init__(self, reactor, watcher, type):
     QSocketNotifier.__init__(self, watcher.fileno(), type)
     self.reactor = reactor
     self.watcher = watcher
     self.fn = None
     if type == QSocketNotifier.Read:
         self.fn = self.read
     elif type == QSocketNotifier.Write:
         self.fn = self.write
     QObject.connect(self, SIGNAL("activated(int)"), self.fn)
Esempio n. 15
0
    def __init__(self, signum, parent):
        super(Signal, self).__init__(parent)
        self.signum = signum
        self.sn = None
        self.fd = [None, None]
        if self.setupHandler() < 0:
            return

        self.sn = QSocketNotifier(self.fd[1].fileno(), QSocketNotifier.Read,
                                  parent)
        self.sn.activated.connect(self.handleSignal)
Esempio n. 16
0
 def __init__(self, filepath, parent=None):
     super().__init__(parent)
     self._filepath = filepath
     # We open as R/W so we never get EOF and have to reopen the pipe.
     # See http://www.outflux.net/blog/archives/2008/03/09/using-select-on-a-fifo/
     # We also use os.open and os.fdopen rather than built-in open so we
     # can add O_NONBLOCK.
     fd = os.open(filepath, os.O_RDWR | os.O_NONBLOCK)  # pylint: disable=no-member
     self.fifo = os.fdopen(fd, 'r')
     self._notifier = QSocketNotifier(fd, QSocketNotifier.Read, self)
     self._notifier.activated.connect(self.read_line)
Esempio n. 17
0
 def __init__(self, parent, reactor, watcher, socketType):
     QObject.__init__(self, parent)
     self.reactor = reactor
     self.watcher = watcher
     fd = watcher.fileno()
     self.notifier = QSocketNotifier(fd, socketType, parent)
     self.notifier.setEnabled(True)
     if socketType == QSocketNotifier.Read:
         self.fn = self.read
     else:
         self.fn = self.write
     self.notifier.activated.connect(self.fn)
Esempio n. 18
0
 def _SH_ThreadStarted(self):
     self.started.emit()
     notification_center = NotificationCenter()
     notification_center.post_notification('VNCClientWillStart', sender=self)
     self.rfb_client = RFBClient(parent=self)
     try:
         self.rfb_client.connect()
     except RFBClientError:
         self.thread.quit()
     else:
         self.socket_notifier = QSocketNotifier(self.rfb_client.socket, QSocketNotifier.Read, self)
         self.socket_notifier.activated.connect(self._SH_SocketNotifierActivated)
         notification_center.post_notification('VNCClientDidStart', sender=self)
Esempio n. 19
0
    def connect(self, sock):
        """
        Wraps the socket with the current object.

        :param sock: the socket
        """
        self._accept_notifier = QSocketNotifier(sock.fileno(),
                                                QSocketNotifier.Read, self)
        self._accept_notifier.activated.connect(self._notify_accept)
        self._accept_notifier.setEnabled(True)

        self._socket = sock
        self._connected = True
Esempio n. 20
0
    def __init__(self, xmms):
        QObject.__init__(self)
        fd = xmms.get_fd()
        self.xmms = xmms
        self.xmms.set_need_out_fun(self.checkWrite)

        self.rSock = QSocketNotifier(fd, QSocketNotifier.Read, self)
        self.rSock.activated.connect(self.handleRead)
        self.rSock.setEnabled(True)

        self.wSock = QSocketNotifier(fd, QSocketNotifier.Write, self)
        self.wSock.activated.connect(self.handleWrite)
        self.wSock.setEnabled(False)
Esempio n. 21
0
    def wrap_socket(self, sock):
        """Sets the underlying socket to use."""
        self._read_notifier = QSocketNotifier(sock.fileno(),
                                              QSocketNotifier.Read, self)
        self._read_notifier.activated.connect(self._notify_read)
        self._read_notifier.setEnabled(True)

        self._write_notifier = QSocketNotifier(sock.fileno(),
                                               QSocketNotifier.Write, self)
        self._write_notifier.activated.connect(self._notify_write)
        self._write_notifier.setEnabled(True)

        self._socket = sock
Esempio n. 22
0
    def start(self):
        self._logger.debug("Starting servers discovery....")
        self._socket = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
        self._socket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
        self._socket.bind(("", 31013))
        self._socket.settimeout(0)
        self._socket.setblocking(0)

        self._read_notifier = QSocketNotifier(self._socket.fileno(),
                                              QSocketNotifier.Read, self)
        self._read_notifier.activated.connect(self._notify_read)
        self._read_notifier.setEnabled(True)
        self._started = True
        self._timer.start()
Esempio n. 23
0
class XMMSConnector(QObject):

    def __init__(self, xmms):
        QObject.__init__(self)
        fd = xmms.get_fd()
        self.xmms = xmms
        self.xmms.set_need_out_fun(self.checkWrite)

        self.rSock = QSocketNotifier(fd, QSocketNotifier.Read, self)
        self.rSock.activated.connect(self.handleRead)
        self.rSock.setEnabled(True)

        self.wSock = QSocketNotifier(fd, QSocketNotifier.Write, self)
        self.wSock.activated.connect(self.handleWrite)
        self.wSock.setEnabled(False)

    def checkWrite(self, i):
        if self.xmms.want_ioout():
            self.toggleWrite(True)
        else:
            self.toggleWrite(False)

    def toggleRead(self, bool_val):
        self.rSock.setEnabled(bool_val)

    def toggleWrite(self, bool_val):
        self.wSock.setEnabled(bool_val)

    def handleRead(self, i):
        self.xmms.ioin()

    def handleWrite(self, i):
        self.xmms.ioout()
Esempio n. 24
0
 def start_server(self):
     self._server = Server()
     ret = self._server.start(self.address_text.text())
     if ret is not True:
         self._log("[ZMQError]: " + repr(ret))
         return
     socket = self._server.socket
     self._notifier = QSocketNotifier(socket.getsockopt(zmq.FD),
                                      QSocketNotifier.Read, self)
     self._notifier.activated.connect(self._socket_activity)
     self._notifier.setEnabled(True)
     self.connect_button.clicked.disconnect()
     self.connect_button.clicked.connect(self.stop_server)
     self.connect_button.setText('Stop server')
     self._log("[Socket] Start server")
Esempio n. 25
0
    def initialize_socket(self, sock):
        self._recv_notifier = QSocketNotifier(sock.fileno(),
                                              QSocketNotifier.Read, self)
        self._recv_notifier.activated.connect(self._handle_recv_ready)
        self._recv_notifier.setEnabled(True)

        self._send_notifier = QSocketNotifier(sock.fileno(),
                                              QSocketNotifier.Write, self)
        self._send_notifier.activated.connect(self._handle_send_ready)
        self._send_notifier.setEnabled(True)

        self._socket = sock
        self._connected = True
        self._incoming = []
        self._outgoing = []
Esempio n. 26
0
    def __init__(self):
        super(QObject, self).__init__()

        conn_parent, conn_child = socketpair()

        # TODO: figure out which of the two sockets should be set to 
        #       inheritable and which should be passed to the child
        if hasattr(conn_child, 'set_inheritable'):
            conn_child.set_inheritable(True)

        # Use a local variable for child so that we can talk to the child in
        # on_finalize without needing a reference to self
        child = mp.Process(target=_converter_process_func, args=(conn_parent, conn_child))
        child.daemon = True
        child.start()
        self.child = child

        conn_child.close()
        self.conn = conn_parent

        self.busy = False
        self.notificationPending = False
        self.conversionNotifier = QSocketNotifier(self.conn.fileno(),
                                                  QSocketNotifier.Read)
        self.conversionNotifier.activated.connect(self._conversionNotifierActivated)

        def on_finalize(conn):
            sendObject(conn_parent, {'command':'quit'})
            conn_parent.close()
            child.join()

        weakref.finalize(self, on_finalize, conn_parent)
Esempio n. 27
0
    def __init__(self):
        super().__init__()

        self.inotify = INotify()
        self.qnotifier = QSocketNotifier(self.inotify.fd, QSocketNotifier.Read)
        self.qnotifier.activated.connect(self._on_activated)
        self.wd = None
Esempio n. 28
0
    def _setup_signals(self):
        """Set up signal handlers.

        On Windows this uses a QTimer to periodically hand control over to
        Python so it can handle signals.

        On Unix, it uses a QSocketNotifier with os.set_wakeup_fd to get
        notified.
        """
        signal.signal(signal.SIGINT, self.interrupt)
        signal.signal(signal.SIGTERM, self.interrupt)

        if os.name == 'posix' and hasattr(signal, 'set_wakeup_fd'):
            import fcntl
            read_fd, write_fd = os.pipe()
            for fd in (read_fd, write_fd):
                flags = fcntl.fcntl(fd, fcntl.F_GETFL)
                fcntl.fcntl(fd, fcntl.F_SETFL, flags | os.O_NONBLOCK)
            self._signal_notifier = QSocketNotifier(
                read_fd, QSocketNotifier.Read, self)
            self._signal_notifier.activated.connect(self._handle_signal_wakeup)
            signal.set_wakeup_fd(write_fd)
        else:
            self._signal_timer = usertypes.Timer(self, 'python_hacks')
            self._signal_timer.start(1000)
            self._signal_timer.timeout.connect(lambda: None)
Esempio n. 29
0
    def activate(self):
        """Set up signal handlers.

        On Windows this uses a QTimer to periodically hand control over to
        Python so it can handle signals.

        On Unix, it uses a QSocketNotifier with os.set_wakeup_fd to get
        notified.
        """
        self._orig_handlers[signal.SIGINT] = signal.signal(
            signal.SIGINT, self.interrupt)
        self._orig_handlers[signal.SIGTERM] = signal.signal(
            signal.SIGTERM, self.interrupt)

        if os.name == 'posix' and hasattr(signal, 'set_wakeup_fd'):
            # pylint: disable=import-error,no-member,useless-suppression
            import fcntl
            read_fd, write_fd = os.pipe()
            for fd in [read_fd, write_fd]:
                flags = fcntl.fcntl(fd, fcntl.F_GETFL)
                fcntl.fcntl(fd, fcntl.F_SETFL, flags | os.O_NONBLOCK)
            self._notifier = QSocketNotifier(read_fd, QSocketNotifier.Read,
                                             self)
            self._notifier.activated.connect(self.handle_signal_wakeup)
            self._orig_wakeup_fd = signal.set_wakeup_fd(write_fd)
        else:
            self._timer.start(1000)
            self._timer.timeout.connect(lambda: None)
        self._activated = True
Esempio n. 30
0
    def __init__(self, parent: Optional[QObject] = None) -> None:
        super().__init__(parent)

        self.inotify = INotify()
        self.qnotifier = QSocketNotifier(self.inotify.fd, QSocketNotifier.Read)
        self.qnotifier.activated.connect(self._on_activated)
        self.wd = None
Esempio n. 31
0
    def __init__(self):
        conn_parent, conn_child = mp.Pipe()

        # Use a local variable for child so that we can talk to the child in
        # on_finalize without needing a reference to self
        child = mp.Process(target=_converter_process_func,
                           args=(conn_parent, conn_child))
        child.daemon = True
        child.start()
        self.child = child

        conn_child.close()
        self.conn = conn_parent

        self.busy = False
        self.conversionNotifier = QSocketNotifier(self.conn.fileno(),
                                                  QSocketNotifier.Read)

        # assign the activated signal of the notifier to a conversionDone
        # member to get a more meaningful signal name for others to connect to
        self.conversionDone = self.conversionNotifier.activated

        def on_finalize(conn):
            conn_parent.send({'command': 'quit'})
            conn_parent.close()
            child.join()

        weakref.finalize(self, on_finalize, conn_parent)
Esempio n. 32
0
    def start(self, host, port, ssl):
        self._logger.debug("Starting clients discovery...")
        self._info = "%s %d %s" % (host, port, ssl)

        self._socket = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
        self._socket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
        self._socket.setsockopt(socket.SOL_SOCKET, socket.SO_BROADCAST, 1)
        self._socket.settimeout(0)
        self._socket.setblocking(0)

        self._read_notifier = QSocketNotifier(self._socket.fileno(),
                                              QSocketNotifier.Read, self)
        self._read_notifier.activated.connect(self._notify_read)
        self._read_notifier.setEnabled(True)
        self._started = True
        self._timer.start()
        self._send_request()
Esempio n. 33
0
    def register_io(self, fd, callback, mode, *args, **kwargs):
        handler = six.next(self._handlers)
        notifier = QSocketNotifier(self.fd_number(fd), self.constants[mode])
        with self._mutex:
            self._io_handlers[handler] = notifier

        def _io_cb(*_):
            if not self._safe_callback(callback, fd, *args, **kwargs):
                self.unregister_io(handler)

        with self._mutex:
            # we need to store the closure callback to avoid the garbage collector
            # from collecting the closure
            self._io_handlers[handler] = (notifier, _io_cb)

        notifier.setEnabled(True)
        notifier.activated.connect(_io_cb)
Esempio n. 34
0
    def register_io(self, fd, callback, mode, *args, **kwargs):
        handler = six.next(self._handlers)
        notifier = QSocketNotifier(self.fd_number(fd), self.constants[mode])
        with self._mutex:
            self._io_handlers[handler] = notifier

        def _io_cb(*_):
            if not self._safe_callback(callback, fd, *args, **kwargs):
                self.unregister_io(handler)

        with self._mutex:
            # we need to store the closure callback to avoid the garbage collector
            # from collecting the closure
            self._io_handlers[handler] = (notifier, _io_cb)

        notifier.setEnabled(True)
        notifier.activated.connect(_io_cb)
Esempio n. 35
0
    def start(self, host, port, ssl):
        """Start the discovery process and broadcast the given information."""
        self._logger.debug("Starting clients discovery")
        self._info = "%s %d %s" % (host, port, ssl)
        # Create a datagram socket capable of broadcasting
        self._socket = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
        self._socket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
        self._socket.setsockopt(socket.SOL_SOCKET, socket.SO_BROADCAST, 1)
        self._socket.settimeout(0)  # No timeout
        self._socket.setblocking(0)  # No blocking

        self._read_notifier = QSocketNotifier(self._socket.fileno(),
                                              QSocketNotifier.Read, self)
        self._read_notifier.activated.connect(self._notify_read)
        self._read_notifier.setEnabled(True)
        self._started = True
        self._timer.start()
        self._send_request()
Esempio n. 36
0
 def init_zocp(self):
     self.z = ZOCP("QT UI TEST")
     self.z.register_float("myFloat", 2.3, 'rw', 0, 5.0, 0.1)
     self.notifier = QSocketNotifier(
             self.z.inbox.getsockopt(zmq.FD), 
             QSocketNotifier.Read
             )
     self.notifier.setEnabled(True)
     self.notifier.activated.connect(self.zocp_event)
     self.z.on_modified = self.on_modified
     self.z.start()
Esempio n. 37
0
 def __init__(self, filepath, parent=None):
     super().__init__(parent)
     self._filepath = filepath
     # We open as R/W so we never get EOF and have to reopen the pipe.
     # See http://www.outflux.net/blog/archives/2008/03/09/using-select-on-a-fifo/
     # We also use os.open and os.fdopen rather than built-in open so we
     # can add O_NONBLOCK.
     fd = os.open(filepath, os.O_RDWR | os.O_NONBLOCK)  # pylint: disable=no-member
     self.fifo = os.fdopen(fd, "r")
     self._notifier = QSocketNotifier(fd, QSocketNotifier.Read, self)
     self._notifier.activated.connect(self.read_line)
Esempio n. 38
0
 def __init__(self, parent, reactor, watcher, socketType):
     QObject.__init__(self, parent)
     self.reactor = reactor
     self.watcher = watcher
     fd = watcher.fileno()
     self.notifier = QSocketNotifier(fd, socketType, parent)
     self.notifier.setEnabled(True)
     if socketType == QSocketNotifier.Read:
         self.fn = self.read
     else:
         self.fn = self.write
     self.notifier.activated.connect(self.fn)
Esempio n. 39
0
class _QtFIFOReader(QObject):

    """A FIFO reader based on a QSocketNotifier."""

    got_line = pyqtSignal(str)

    def __init__(self, filepath, parent=None):
        super().__init__(parent)
        self._filepath = filepath
        # We open as R/W so we never get EOF and have to reopen the pipe.
        # See http://www.outflux.net/blog/archives/2008/03/09/using-select-on-a-fifo/
        # We also use os.open and os.fdopen rather than built-in open so we
        # can add O_NONBLOCK.
        # pylint: disable=no-member,useless-suppression
        fd = os.open(filepath, os.O_RDWR | os.O_NONBLOCK)
        self.fifo = os.fdopen(fd, 'r')
        self._notifier = QSocketNotifier(fd, QSocketNotifier.Read, self)
        self._notifier.activated.connect(self.read_line)

    @pyqtSlot()
    def read_line(self):
        """(Try to) read a line from the FIFO."""
        log.procs.debug("QSocketNotifier triggered!")
        self._notifier.setEnabled(False)
        for line in self.fifo:
            self.got_line.emit(line.rstrip('\r\n'))
        self._notifier.setEnabled(True)

    def cleanup(self):
        """Clean up so the FIFO can be closed."""
        self._notifier.setEnabled(False)
Esempio n. 40
0
class QTZOCPNode(QWidget):

    def __init__(self):
        super(QTZOCPNode, self).__init__()
        self.qle = QTextEdit(self)
        self.qle.move(1, 1)
        self.qle.resize(640,480)
        self.init_zocp()
        self.show()

    def init_zocp(self):
        self.z = ZOCP("QT UI TEST")
        self.z.register_float("myFloat", 2.3, 'rw', 0, 5.0, 0.1)
        self.notifier = QSocketNotifier(
                self.z.inbox.getsockopt(zmq.FD), 
                QSocketNotifier.Read
                )
        self.notifier.setEnabled(True)
        self.notifier.activated.connect(self.zocp_event)
        self.z.on_modified = self.on_modified
        self.z.start()

    def zocp_event(self):
        print("ZOCP EVENT START")
        self.z.run_once(0)
        print("ZOCP EVENT END")

    def on_modified(self, peer, name, data, *args, **kwargs):
        t = self.qle.toPlainText()
        t = "{0}\n{1}".format(data, t)
        self.qle.setPlainText(t)

    def closeEvent(self, *args):
        print(args)
        self.z.stop()
        del self.z
Esempio n. 41
0
class _QtFIFOReader(QObject):

    """A FIFO reader based on a QSocketNotifier.

    Attributes:
        _filepath: The path to the opened FIFO.
        _fifo: The Python file object for the FIFO.
        _notifier: The QSocketNotifier used.

    Signals:
        got_line: Emitted when a whole line arrived.
    """

    got_line = pyqtSignal(str)

    def __init__(self, filepath, parent=None):
        super().__init__(parent)
        self._filepath = filepath
        # We open as R/W so we never get EOF and have to reopen the pipe.
        # See http://www.outflux.net/blog/archives/2008/03/09/using-select-on-a-fifo/
        # We also use os.open and os.fdopen rather than built-in open so we
        # can add O_NONBLOCK.
        # pylint: disable=no-member,useless-suppression
        fd = os.open(filepath, os.O_RDWR | os.O_NONBLOCK)
        # pylint: enable=no-member,useless-suppression
        self._fifo = os.fdopen(fd, 'r')
        self._notifier = QSocketNotifier(fd, QSocketNotifier.Read, self)
        self._notifier.activated.connect(self.read_line)

    @pyqtSlot()
    def read_line(self):
        """(Try to) read a line from the FIFO."""
        log.procs.debug("QSocketNotifier triggered!")
        try:
            self._notifier.setEnabled(False)
            try:
                for line in self._fifo:
                    self.got_line.emit(line.rstrip('\r\n'))
                    self._notifier.setEnabled(True)
            except UnicodeDecodeError as e:
                log.misc.error("Invalid unicode in userscript output: {}"
                               .format(e))
        except RuntimeError as e:
            # For unknown reasons, read_line can still get called after the
            # QSocketNotifier was already deleted...
            log.procs.debug("While reading userscript output: {}".format(e))

    def cleanup(self):
        """Clean up so the FIFO can be closed."""
        self._notifier.setEnabled(False)
        for line in self._fifo:
            self.got_line.emit(line.rstrip('\r\n'))
        self._fifo.close()
Esempio n. 42
0
class Application(QApplication):

    """Main application instance.

    Attributes:
        _args: ArgumentParser instance.
        _shutting_down: True if we're currently shutting down.
        _quit_status: The current quitting status.
        _crashdlg: The crash dialog currently open.
        _crashlogfile: A file handler to the fatal crash logfile.
        _event_filter: The EventFilter for the application.
        _signal_notifier: A QSocketNotifier used for signals on Unix.
        _signal_timer: A QTimer used to poll for signals on Windows.
        geometry: The geometry of the last closed main window.
    """

    def __init__(self, args):
        """Constructor.

        Args:
            Argument namespace from argparse.
        """
        # pylint: disable=too-many-statements
        self._quit_status = {
            'crash': True,
            'tabs': False,
            'main': False,
        }
        self.geometry = None
        self._shutting_down = False
        self._crashdlg = None
        self._crashlogfile = None

        qt_args = qtutils.get_args(args)
        log.init.debug("Qt arguments: {}, based on {}".format(qt_args, args))
        super().__init__(qt_args)
        sys.excepthook = self._exception_hook

        self._args = args
        objreg.register('args', args)

        objreg.register('app', self)

        if self._args.version:
            print(version.version())
            print()
            print()
            print(qutebrowser.__copyright__)
            print()
            print(version.GPL_BOILERPLATE.strip())
            sys.exit(0)

        try:
            sent = ipc.send_to_running_instance(self._args.command)
            if sent:
                sys.exit(0)
            log.init.debug("Starting IPC server...")
            ipc.init()
        except ipc.IPCError as e:
            text = ('{}\n\nMaybe another instance is running but '
                    'frozen?'.format(e))
            msgbox = QMessageBox(QMessageBox.Critical, "Error while "
                                 "connecting to running instance!", text)
            msgbox.exec_()
            # We didn't really initialize much so far, so we just quit hard.
            sys.exit(1)

        log.init.debug("Starting init...")
        self.setQuitOnLastWindowClosed(False)
        self.setOrganizationName("qutebrowser")
        self.setApplicationName("qutebrowser")
        self.setApplicationVersion(qutebrowser.__version__)
        self._init_icon()
        utils.actute_warning()
        try:
            self._init_modules()
        except (OSError, UnicodeDecodeError) as e:
            msgbox = QMessageBox(
                QMessageBox.Critical, "Error while initializing!",
                "Error while initializing: {}".format(e))
            msgbox.exec_()
            sys.exit(1)
        QTimer.singleShot(0, self._process_args)

        log.init.debug("Initializing eventfilter...")
        self._event_filter = modeman.EventFilter(self)
        self.installEventFilter(self._event_filter)

        log.init.debug("Connecting signals...")
        self._connect_signals()

        log.init.debug("Setting up signal handlers...")
        self._setup_signals()

        QDesktopServices.setUrlHandler('http', self.open_desktopservices_url)
        QDesktopServices.setUrlHandler('https', self.open_desktopservices_url)
        QDesktopServices.setUrlHandler('qute', self.open_desktopservices_url)

        log.init.debug("Init done!")

        if self._crashdlg is not None:
            self._crashdlg.raise_()

    def __repr__(self):
        return utils.get_repr(self)

    def _init_modules(self):
        """Initialize all 'modules' which need to be initialized."""
        # pylint: disable=too-many-statements
        log.init.debug("Initializing save manager...")
        save_manager = savemanager.SaveManager(self)
        objreg.register('save-manager', save_manager)
        save_manager.add_saveable('window-geometry', self._save_geometry)
        save_manager.add_saveable('version', self._save_version)
        log.init.debug("Initializing network...")
        networkmanager.init()
        log.init.debug("Initializing readline-bridge...")
        readline_bridge = readline.ReadlineBridge()
        objreg.register('readline-bridge', readline_bridge)
        log.init.debug("Initializing directories...")
        standarddir.init(self._args)
        log.init.debug("Initializing config...")
        config.init()
        save_manager.init_autosave()
        log.init.debug("Initializing web history...")
        history.init()
        log.init.debug("Initializing crashlog...")
        self._handle_segfault()
        log.init.debug("Initializing sessions...")
        session_manager = sessions.SessionManager(self)
        objreg.register('session-manager', session_manager)
        log.init.debug("Initializing js-bridge...")
        js_bridge = qutescheme.JSBridge(self)
        objreg.register('js-bridge', js_bridge)
        log.init.debug("Initializing websettings...")
        websettings.init()
        log.init.debug("Initializing adblock...")
        host_blocker = adblock.HostBlocker()
        host_blocker.read_hosts()
        objreg.register('host-blocker', host_blocker)
        log.init.debug("Initializing quickmarks...")
        quickmark_manager = quickmarks.QuickmarkManager()
        objreg.register('quickmark-manager', quickmark_manager)
        log.init.debug("Initializing proxy...")
        proxy.init()
        log.init.debug("Initializing cookies...")
        cookie_jar = cookies.CookieJar(self)
        objreg.register('cookie-jar', cookie_jar)
        log.init.debug("Initializing cache...")
        diskcache = cache.DiskCache(self)
        objreg.register('cache', diskcache)
        log.init.debug("Initializing completions...")
        completionmodels.init()

    def _init_icon(self):
        """Initialize the icon of qutebrowser."""
        icon = QIcon()
        for size in (16, 24, 32, 48, 64, 96, 128, 256, 512):
            filename = ':/icons/qutebrowser-{}x{}.png'.format(size, size)
            pixmap = QPixmap(filename)
            qtutils.ensure_not_null(pixmap)
            icon.addPixmap(pixmap)
        qtutils.ensure_not_null(icon)
        self.setWindowIcon(icon)

    def _handle_segfault(self):
        """Handle a segfault from a previous run."""
        logname = os.path.join(standarddir.data(), 'crash.log')
        try:
            # First check if an old logfile exists.
            if os.path.exists(logname):
                with open(logname, 'r', encoding='ascii') as f:
                    data = f.read()
                os.remove(logname)
                self._init_crashlogfile()
                if data:
                    # Crashlog exists and has data in it, so something crashed
                    # previously.
                    self._crashdlg = crashdialog.get_fatal_crash_dialog(
                        self._args.debug, data)
                    self._crashdlg.show()
            else:
                # There's no log file, so we can use this to display crashes to
                # the user on the next start.
                self._init_crashlogfile()
        except OSError:
            log.init.exception("Error while handling crash log file!")
            self._init_crashlogfile()

    def _init_crashlogfile(self):
        """Start a new logfile and redirect faulthandler to it."""
        logname = os.path.join(standarddir.data(), 'crash.log')
        try:
            self._crashlogfile = open(logname, 'w', encoding='ascii')
        except OSError:
            log.init.exception("Error while opening crash log file!")
        else:
            earlyinit.init_faulthandler(self._crashlogfile)

    def _process_args(self):
        """Open startpage etc. and process commandline args."""
        config_obj = objreg.get('config')
        for sect, opt, val in self._args.temp_settings:
            try:
                config_obj.set('temp', sect, opt, val)
            except (configexc.Error, configparser.Error) as e:
                message.error('current', "set: {} - {}".format(
                    e.__class__.__name__, e))

        if not self._args.override_restore:
            self._load_session(self._args.session)
        session_manager = objreg.get('session-manager')
        if not session_manager.did_load:
            log.init.debug("Initializing main window...")
            window = mainwindow.MainWindow()
            if not self._args.nowindow:
                window.show()
            self.setActiveWindow(window)

        self.process_pos_args(self._args.command)
        self._open_startpage()
        self._open_quickstart()

    def _load_session(self, name):
        """Load the default session.

        Args:
            name: The name of the session to load, or None to read state file.
        """
        state_config = objreg.get('state-config')
        if name is None:
            try:
                name = state_config['general']['session']
            except KeyError:
                # No session given as argument and none in the session file ->
                # start without loading a session
                return
        session_manager = objreg.get('session-manager')
        try:
            session_manager.load(name)
        except sessions.SessionNotFoundError:
            message.error('current', "Session {} not found!".format(name))
        except sessions.SessionError as e:
            message.error('current', "Failed to load session {}: {}".format(
                name, e))
        try:
            del state_config['general']['session']
        except KeyError:
            pass
        # If this was a _restart session, delete it.
        if name == '_restart':
            session_manager.delete('_restart')

    def _get_window(self, via_ipc, force_window=False, force_tab=False):
        """Helper function for process_pos_args to get a window id.

        Args:
            via_ipc: Whether the request was made via IPC.
            force_window: Whether to force opening in a window.
            force_tab: Whether to force opening in a tab.
        """
        if force_window and force_tab:
            raise ValueError("force_window and force_tab are mutually "
                             "exclusive!")
        if not via_ipc:
            # Initial main window
            return 0
        window_to_raise = None
        open_target = config.get('general', 'new-instance-open-target')
        if (open_target == 'window' or force_window) and not force_tab:
            window = mainwindow.MainWindow()
            window.show()
            win_id = window.win_id
            window_to_raise = window
        else:
            try:
                window = objreg.last_window()
            except objreg.NoWindow:
                # There is no window left, so we open a new one
                window = mainwindow.MainWindow()
                window.show()
                win_id = window.win_id
                window_to_raise = window
            win_id = window.win_id
            if open_target != 'tab-silent':
                window_to_raise = window
        if window_to_raise is not None:
            window_to_raise.setWindowState(window.windowState() &
                                           ~Qt.WindowMinimized |
                                           Qt.WindowActive)
            window_to_raise.raise_()
            window_to_raise.activateWindow()
            self.alert(window_to_raise)
        return win_id

    def process_pos_args(self, args, via_ipc=False, cwd=None):
        """Process positional commandline args.

        URLs to open have no prefix, commands to execute begin with a colon.

        Args:
            args: A list of arguments to process.
            via_ipc: Whether the arguments were transmitted over IPC.
            cwd: The cwd to use for fuzzy_url.
        """
        if via_ipc and not args:
            win_id = self._get_window(via_ipc, force_window=True)
            self._open_startpage(win_id)
            return
        win_id = None
        for cmd in args:
            if cmd.startswith(':'):
                if win_id is None:
                    win_id = self._get_window(via_ipc, force_tab=True)
                log.init.debug("Startup cmd {}".format(cmd))
                commandrunner = runners.CommandRunner(win_id)
                commandrunner.run_safely_init(cmd[1:])
            elif not cmd:
                log.init.debug("Empty argument")
                win_id = self._get_window(via_ipc, force_window=True)
            else:
                win_id = self._get_window(via_ipc)
                tabbed_browser = objreg.get('tabbed-browser', scope='window',
                                            window=win_id)
                log.init.debug("Startup URL {}".format(cmd))
                try:
                    url = urlutils.fuzzy_url(cmd, cwd, relative=True)
                except urlutils.FuzzyUrlError as e:
                    message.error(0, "Error in startup argument '{}': "
                                     "{}".format(cmd, e))
                else:
                    tabbed_browser.tabopen(url, background=False)

    def _open_startpage(self, win_id=None):
        """Open startpage.

        The startpage is never opened if the given windows are not empty.

        Args:
            win_id: If None, open startpage in all empty windows.
                    If set, open the startpage in the given window.
        """
        if win_id is not None:
            window_ids = [win_id]
        else:
            window_ids = objreg.window_registry
        for cur_win_id in window_ids:
            tabbed_browser = objreg.get('tabbed-browser', scope='window',
                                        window=cur_win_id)
            if tabbed_browser.count() == 0:
                log.init.debug("Opening startpage")
                for urlstr in config.get('general', 'startpage'):
                    try:
                        url = urlutils.fuzzy_url(urlstr, do_search=False)
                    except urlutils.FuzzyUrlError as e:
                        message.error(0, "Error when opening startpage: "
                                         "{}".format(e))
                        tabbed_browser.tabopen(QUrl('about:blank'))
                    else:
                        tabbed_browser.tabopen(url)

    def _open_quickstart(self):
        """Open quickstart if it's the first start."""
        state_config = objreg.get('state-config')
        try:
            quickstart_done = state_config['general']['quickstart-done'] == '1'
        except KeyError:
            quickstart_done = False
        if not quickstart_done:
            tabbed_browser = objreg.get('tabbed-browser', scope='window',
                                        window='last-focused')
            tabbed_browser.tabopen(
                QUrl('http://www.qutebrowser.org/quickstart.html'))
            state_config['general']['quickstart-done'] = '1'

    def _setup_signals(self):
        """Set up signal handlers.

        On Windows this uses a QTimer to periodically hand control over to
        Python so it can handle signals.

        On Unix, it uses a QSocketNotifier with os.set_wakeup_fd to get
        notified.
        """
        signal.signal(signal.SIGINT, self.interrupt)
        signal.signal(signal.SIGTERM, self.interrupt)

        if os.name == 'posix' and hasattr(signal, 'set_wakeup_fd'):
            import fcntl
            read_fd, write_fd = os.pipe()
            for fd in (read_fd, write_fd):
                flags = fcntl.fcntl(fd, fcntl.F_GETFL)
                fcntl.fcntl(fd, fcntl.F_SETFL, flags | os.O_NONBLOCK)
            self._signal_notifier = QSocketNotifier(
                read_fd, QSocketNotifier.Read, self)
            self._signal_notifier.activated.connect(self._handle_signal_wakeup)
            signal.set_wakeup_fd(write_fd)
        else:
            self._signal_timer = usertypes.Timer(self, 'python_hacks')
            self._signal_timer.start(1000)
            self._signal_timer.timeout.connect(lambda: None)

    @pyqtSlot()
    def _handle_signal_wakeup(self):
        """Handle a newly arrived signal.

        This gets called via self._signal_notifier when there's a signal.

        Python will get control here, so the signal will get handled.
        """
        log.destroy.debug("Handling signal wakeup!")
        self._signal_notifier.setEnabled(False)
        read_fd = self._signal_notifier.socket()
        try:
            os.read(read_fd, 1)
        except OSError:
            log.destroy.exception("Failed to read wakeup fd.")
        self._signal_notifier.setEnabled(True)

    def _connect_signals(self):
        """Connect all signals to their slots."""
        config_obj = objreg.get('config')
        self.lastWindowClosed.connect(self.on_last_window_closed)
        config_obj.style_changed.connect(style.get_stylesheet.cache_clear)
        self.focusChanged.connect(self.on_focus_changed)
        self.focusChanged.connect(message.on_focus_changed)

    def _get_widgets(self):
        """Get a string list of all widgets."""
        widgets = self.allWidgets()
        widgets.sort(key=repr)
        return [repr(w) for w in widgets]

    def _get_pyqt_objects(self, lines, obj, depth=0):
        """Recursive method for get_all_objects to get Qt objects."""
        for kid in obj.findChildren(QObject):
            lines.append('    ' * depth + repr(kid))
            self._get_pyqt_objects(lines, kid, depth + 1)

    def get_all_objects(self):
        """Get all children of an object recursively as a string."""
        output = ['']
        widget_lines = self._get_widgets()
        widget_lines = ['    ' + e for e in widget_lines]
        widget_lines.insert(0, "Qt widgets - {} objects".format(
            len(widget_lines)))
        output += widget_lines
        pyqt_lines = []
        self._get_pyqt_objects(pyqt_lines, self)
        pyqt_lines = ['    ' + e for e in pyqt_lines]
        pyqt_lines.insert(0, 'Qt objects - {} objects:'.format(
            len(pyqt_lines)))
        output += pyqt_lines
        output += ['']
        output += objreg.dump_objects()
        return '\n'.join(output)

    def _recover_pages(self, forgiving=False):
        """Try to recover all open pages.

        Called from _exception_hook, so as forgiving as possible.

        Args:
            forgiving: Whether to ignore exceptions.

        Return:
            A list containing a list for each window, which in turn contain the
            opened URLs.
        """
        pages = []
        for win_id in objreg.window_registry:
            win_pages = []
            tabbed_browser = objreg.get('tabbed-browser', scope='window',
                                        window=win_id)
            for tab in tabbed_browser.widgets():
                try:
                    urlstr = tab.cur_url.toString(
                        QUrl.RemovePassword | QUrl.FullyEncoded)
                    if urlstr:
                        win_pages.append(urlstr)
                except Exception:
                    if forgiving:
                        log.destroy.exception("Error while recovering tab")
                    else:
                        raise
            pages.append(win_pages)
        return pages

    def _save_geometry(self):
        """Save the window geometry to the state config."""
        if self.geometry is not None:
            state_config = objreg.get('state-config')
            geom = base64.b64encode(self.geometry).decode('ASCII')
            state_config['geometry']['mainwindow'] = geom

    def _save_version(self):
        """Save the current version to the state config."""
        state_config = objreg.get('state-config')
        state_config['general']['version'] = qutebrowser.__version__

    def _destroy_crashlogfile(self):
        """Clean up the crash log file and delete it."""
        if self._crashlogfile is None:
            return
        # We use sys.__stderr__ instead of sys.stderr here so this will still
        # work when sys.stderr got replaced, e.g. by "Python Tools for Visual
        # Studio".
        if sys.__stderr__ is not None:
            faulthandler.enable(sys.__stderr__)
        else:
            faulthandler.disable()
        try:
            self._crashlogfile.close()
            os.remove(self._crashlogfile.name)
        except OSError:
            log.destroy.exception("Could not remove crash log!")

    def _exception_hook(self, exctype, excvalue, tb):  # noqa
        """Handle uncaught python exceptions.

        It'll try very hard to write all open tabs to a file, and then exit
        gracefully.
        """
        exc = (exctype, excvalue, tb)

        if not self._quit_status['crash']:
            log.misc.error("ARGH, there was an exception while the crash "
                           "dialog is already shown:", exc_info=exc)
            return

        log.misc.error("Uncaught exception", exc_info=exc)

        is_ignored_exception = (exctype is bdb.BdbQuit or
                                not issubclass(exctype, Exception))

        if self._args.pdb_postmortem:
            pdb.post_mortem(tb)

        if (is_ignored_exception or self._args.no_crash_dialog or
                self._args.pdb_postmortem):
            # pdb exit, KeyboardInterrupt, ...
            status = 0 if is_ignored_exception else 2
            try:
                self.shutdown(status)
                return
            except Exception:
                log.init.exception("Error while shutting down")
                self.quit()
                return

        self._quit_status['crash'] = False

        try:
            pages = self._recover_pages(forgiving=True)
        except Exception:
            log.destroy.exception("Error while recovering pages")
            pages = []

        try:
            cmd_history = objreg.get('command-history')[-5:]
        except Exception:
            log.destroy.exception("Error while getting history: {}")
            cmd_history = []

        try:
            objects = self.get_all_objects()
        except Exception:
            log.destroy.exception("Error while getting objects")
            objects = ""

        try:
            objreg.get('ipc-server').ignored = True
        except Exception:
            log.destroy.exception("Error while ignoring ipc")

        try:
            self.lastWindowClosed.disconnect(self.on_last_window_closed)
        except TypeError:
            log.destroy.exception("Error while preventing shutdown")
        QApplication.closeAllWindows()
        self._crashdlg = crashdialog.ExceptionCrashDialog(
            self._args.debug, pages, cmd_history, exc, objects)
        ret = self._crashdlg.exec_()
        if ret == QDialog.Accepted:  # restore
            self._do_restart(pages)

        # We might risk a segfault here, but that's better than continuing to
        # run in some undefined state, so we only do the most needed shutdown
        # here.
        qInstallMessageHandler(None)
        self._destroy_crashlogfile()
        sys.exit(1)

    def _get_restart_args(self, pages=(), session=None):
        """Get the current working directory and args to relaunch qutebrowser.

        Args:
            pages: The pages to re-open.
            session: The session to load, or None.

        Return:
            An (args, cwd) tuple.
                args: The commandline as a list of strings.
                cwd: The current working directory as a string.
        """
        if os.path.basename(sys.argv[0]) == 'qutebrowser':
            # Launched via launcher script
            args = [sys.argv[0]]
            cwd = None
        elif hasattr(sys, 'frozen'):
            args = [sys.executable]
            cwd = os.path.abspath(os.path.dirname(sys.executable))
        else:
            args = [sys.executable, '-m', 'qutebrowser']
            cwd = os.path.join(os.path.abspath(os.path.dirname(
                               qutebrowser.__file__)), '..')
            if not os.path.isdir(cwd):
                # Probably running from an python egg. Let's fallback to
                # cwd=None and see if that works out.
                # See https://github.com/The-Compiler/qutebrowser/issues/323
                cwd = None

        # Add all open pages so they get reopened.
        page_args = []
        for win in pages:
            page_args.extend(win)
            page_args.append('')

        # Serialize the argparse namespace into json and pass that to the new
        # process via --json-args.
        # We do this as there's no way to "unparse" the namespace while
        # ignoring some arguments.
        argdict = vars(self._args)
        argdict['session'] = None
        argdict['url'] = []
        argdict['command'] = page_args[:-1]
        argdict['json_args'] = None
        # Ensure the given session (or none at all) gets opened.
        if session is None:
            argdict['session'] = None
            argdict['override_restore'] = True
        else:
            argdict['session'] = session
            argdict['override_restore'] = False
        # Dump the data
        data = json.dumps(argdict)
        args += ['--json-args', data]

        log.destroy.debug("args: {}".format(args))
        log.destroy.debug("cwd: {}".format(cwd))

        return args, cwd

    @cmdutils.register(instance='app')
    def restart(self):
        """Restart qutebrowser while keeping existing tabs open."""
        ok = self._do_restart(session='_restart')
        if ok:
            self.shutdown()

    def _do_restart(self, pages=(), session=None):
        """Inner logic to restart qutebrowser.

        The "better" way to restart is to pass a session (_restart usually) as
        that'll save the complete state.

        However we don't do that (and pass a list of pages instead) when we
        restart because of an exception, as that's a lot simpler and we don't
        want to risk anything going wrong.

        Args:
            pages: A list of URLs to open.
            session: The session to load, or None.

        Return:
            True if the restart succeeded, False otherwise.
        """
        log.destroy.debug("sys.executable: {}".format(sys.executable))
        log.destroy.debug("sys.path: {}".format(sys.path))
        log.destroy.debug("sys.argv: {}".format(sys.argv))
        log.destroy.debug("frozen: {}".format(hasattr(sys, 'frozen')))
        # Save the session if one is given.
        if session is not None:
            session_manager = objreg.get('session-manager')
            session_manager.save(session)
        # Open a new process and immediately shutdown the existing one
        try:
            args, cwd = self._get_restart_args(pages, session)
            if cwd is None:
                subprocess.Popen(args)
            else:
                subprocess.Popen(args, cwd=cwd)
        except OSError:
            log.destroy.exception("Failed to restart")
            return False
        else:
            return True

    @cmdutils.register(instance='app', maxsplit=0, debug=True)
    def debug_pyeval(self, s):
        """Evaluate a python string and display the results as a web page.

        //

        We have this here rather in utils.debug so the context of eval makes
        more sense and because we don't want to import much stuff in the utils.

        Args:
            s: The string to evaluate.
        """
        try:
            r = eval(s)
            out = repr(r)
        except Exception:
            out = traceback.format_exc()
        qutescheme.pyeval_output = out
        tabbed_browser = objreg.get('tabbed-browser', scope='window',
                                    window='last-focused')
        tabbed_browser.openurl(QUrl('qute:pyeval'), newtab=True)

    @cmdutils.register(instance='app')
    def report(self):
        """Report a bug in qutebrowser."""
        pages = self._recover_pages()
        cmd_history = objreg.get('command-history')[-5:]
        objects = self.get_all_objects()
        self._crashdlg = crashdialog.ReportDialog(pages, cmd_history, objects)
        self._crashdlg.show()

    def interrupt(self, signum, _frame):
        """Handler for signals to gracefully shutdown (SIGINT/SIGTERM).

        This calls self.shutdown and remaps the signal to call
        self.interrupt_forcefully the next time.
        """
        log.destroy.info("SIGINT/SIGTERM received, shutting down!")
        log.destroy.info("Do the same again to forcefully quit.")
        signal.signal(signal.SIGINT, self.interrupt_forcefully)
        signal.signal(signal.SIGTERM, self.interrupt_forcefully)
        # If we call shutdown directly here, we get a segfault.
        QTimer.singleShot(0, functools.partial(self.shutdown, 128 + signum))

    def interrupt_forcefully(self, signum, _frame):
        """Interrupt forcefully on the second SIGINT/SIGTERM request.

        This skips our shutdown routine and calls QApplication:exit instead.
        It then remaps the signals to call self.interrupt_really_forcefully the
        next time.
        """
        log.destroy.info("Forceful quit requested, goodbye cruel world!")
        log.destroy.info("Do the same again to quit with even more force.")
        signal.signal(signal.SIGINT, self.interrupt_really_forcefully)
        signal.signal(signal.SIGTERM, self.interrupt_really_forcefully)
        # This *should* work without a QTimer, but because of the trouble in
        # self.interrupt we're better safe than sorry.
        QTimer.singleShot(0, functools.partial(self.exit, 128 + signum))

    def interrupt_really_forcefully(self, signum, _frame):
        """Interrupt with even more force on the third SIGINT/SIGTERM request.

        This doesn't run *any* Qt cleanup and simply exits via Python.
        It will most likely lead to a segfault.
        """
        log.destroy.info("WHY ARE YOU DOING THIS TO ME? :(")
        sys.exit(128 + signum)

    @cmdutils.register(instance='app', name='wq',
                       completion=[usertypes.Completion.sessions])
    def save_and_quit(self, name='default'):
        """Save open pages and quit.

        Args:
            name: The name of the session.
        """
        self.shutdown(session=name)

    @pyqtSlot()
    def on_last_window_closed(self):
        """Slot which gets invoked when the last window was closed."""
        self.shutdown(last_window=True)

    @cmdutils.register(instance='app', name=['quit', 'q'], ignore_args=True)
    def shutdown(self, status=0, session=None, last_window=False):
        """Quit qutebrowser.

        Args:
            status: The status code to exit with.
            session: A session name if saving should be forced.
            last_window: If the shutdown was triggered due to the last window
                         closing.
        """
        if self._shutting_down:
            return
        self._shutting_down = True
        log.destroy.debug("Shutting down with status {}, session {}..."
                          .format(status, session))

        session_manager = objreg.get('session-manager')
        if session is not None:
            session_manager.save(session, last_window=last_window,
                                 load_next_time=True)
        elif config.get('general', 'save-session'):
            session_manager.save('default', last_window=last_window,
                                 load_next_time=True)

        deferrer = False
        for win_id in objreg.window_registry:
            prompter = objreg.get('prompter', None, scope='window',
                                  window=win_id)
            if prompter is not None and prompter.shutdown():
                deferrer = True
        if deferrer:
            # If shutdown was called while we were asking a question, we're in
            # a still sub-eventloop (which gets quit now) and not in the main
            # one.
            # This means we need to defer the real shutdown to when we're back
            # in the real main event loop, or we'll get a segfault.
            log.destroy.debug("Deferring real shutdown because question was "
                              "active.")
            QTimer.singleShot(0, functools.partial(self._shutdown, status))
        else:
            # If we have no questions to shut down, we are already in the real
            # event loop, so we can shut down immediately.
            self._shutdown(status)

    def _shutdown(self, status):  # noqa
        """Second stage of shutdown."""
        log.destroy.debug("Stage 2 of shutting down...")
        # Remove eventfilter
        try:
            log.destroy.debug("Removing eventfilter...")
            self.removeEventFilter(self._event_filter)
        except AttributeError:
            pass
        # Close all windows
        QApplication.closeAllWindows()
        # Shut down IPC
        try:
            objreg.get('ipc-server').shutdown()
        except KeyError:
            pass
        # Save everything
        try:
            save_manager = objreg.get('save-manager')
        except KeyError:
            log.destroy.debug("Save manager not initialized yet, so not "
                              "saving anything.")
        else:
            for key in save_manager.saveables:
                try:
                    save_manager.save(key, is_exit=True)
                except OSError as e:
                    msgbox = QMessageBox(
                        QMessageBox.Critical, "Error while saving!",
                        "Error while saving {}: {}".format(key, e))
                    msgbox.exec_()
        # Re-enable faulthandler to stdout, then remove crash log
        log.destroy.debug("Deactiving crash log...")
        self._destroy_crashlogfile()
        # If we don't kill our custom handler here we might get segfaults
        log.destroy.debug("Deactiving message handler...")
        qInstallMessageHandler(None)
        # Now we can hopefully quit without segfaults
        log.destroy.debug("Deferring QApplication::exit...")
        # We use a singleshot timer to exit here to minimize the likelihood of
        # segfaults.
        QTimer.singleShot(0, functools.partial(self.exit, status))

    def on_focus_changed(self, _old, new):
        """Register currently focused main window in the object registry."""
        if new is None:
            window = None
        else:
            window = new.window()
        if window is None or not isinstance(window, mainwindow.MainWindow):
            try:
                objreg.delete('last-focused-main-window')
            except KeyError:
                pass
        else:
            objreg.register('last-focused-main-window', window, update=True)

    @pyqtSlot(QUrl)
    def open_desktopservices_url(self, url):
        """Handler to open an URL via QDesktopServices."""
        win_id = self._get_window(via_ipc=True, force_window=False)
        tabbed_browser = objreg.get('tabbed-browser', scope='window',
                                    window=win_id)
        tabbed_browser.tabopen(url)

    def exit(self, status):
        """Extend QApplication::exit to log the event."""
        log.destroy.debug("Now calling QApplication::exit.")
        if self._args.debug_exit:
            if hunter is None:
                print("Not logging late shutdown because hunter could not be "
                      "imported!", file=sys.stderr)
            else:
                print("Now logging late shutdown.", file=sys.stderr)
                hunter.trace()
        super().exit(status)
Esempio n. 43
0
class SignalHandler(QObject):

    """Handler responsible for handling OS signals (SIGINT, SIGTERM, etc.).

    Attributes:
        _app: The QApplication instance.
        _quitter: The Quitter instance.
        _activated: Whether activate() was called.
        _notifier: A QSocketNotifier used for signals on Unix.
        _timer: A QTimer used to poll for signals on Windows.
        _orig_handlers: A {signal: handler} dict of original signal handlers.
        _orig_wakeup_fd: The original wakeup filedescriptor.
    """

    def __init__(self, *, app, quitter, parent=None):
        super().__init__(parent)
        self._app = app
        self._quitter = quitter
        self._notifier = None
        self._timer = usertypes.Timer(self, 'python_hacks')
        self._orig_handlers = {}
        self._activated = False
        self._orig_wakeup_fd = None

    def activate(self):
        """Set up signal handlers.

        On Windows this uses a QTimer to periodically hand control over to
        Python so it can handle signals.

        On Unix, it uses a QSocketNotifier with os.set_wakeup_fd to get
        notified.
        """
        self._orig_handlers[signal.SIGINT] = signal.signal(
            signal.SIGINT, self.interrupt)
        self._orig_handlers[signal.SIGTERM] = signal.signal(
            signal.SIGTERM, self.interrupt)

        if os.name == 'posix' and hasattr(signal, 'set_wakeup_fd'):
            # pylint: disable=import-error,no-member,useless-suppression
            import fcntl
            read_fd, write_fd = os.pipe()
            for fd in [read_fd, write_fd]:
                flags = fcntl.fcntl(fd, fcntl.F_GETFL)
                fcntl.fcntl(fd, fcntl.F_SETFL, flags | os.O_NONBLOCK)
            self._notifier = QSocketNotifier(read_fd, QSocketNotifier.Read,
                                             self)
            self._notifier.activated.connect(self.handle_signal_wakeup)
            self._orig_wakeup_fd = signal.set_wakeup_fd(write_fd)
        else:
            self._timer.start(1000)
            self._timer.timeout.connect(lambda: None)
        self._activated = True

    def deactivate(self):
        """Deactivate all signal handlers."""
        if not self._activated:
            return
        if self._notifier is not None:
            self._notifier.setEnabled(False)
            rfd = self._notifier.socket()
            wfd = signal.set_wakeup_fd(self._orig_wakeup_fd)
            os.close(rfd)
            os.close(wfd)
        for sig, handler in self._orig_handlers.items():
            signal.signal(sig, handler)
        self._timer.stop()
        self._activated = False

    @pyqtSlot()
    def handle_signal_wakeup(self):
        """Handle a newly arrived signal.

        This gets called via self._notifier when there's a signal.

        Python will get control here, so the signal will get handled.
        """
        log.destroy.debug("Handling signal wakeup!")
        self._notifier.setEnabled(False)
        read_fd = self._notifier.socket()
        try:
            os.read(read_fd, 1)
        except OSError:
            log.destroy.exception("Failed to read wakeup fd.")
        self._notifier.setEnabled(True)

    def _log_later(self, *lines):
        """Log the given text line-wise with a QTimer."""
        for line in lines:
            QTimer.singleShot(0, functools.partial(log.destroy.info, line))

    def interrupt(self, signum, _frame):
        """Handler for signals to gracefully shutdown (SIGINT/SIGTERM).

        This calls shutdown and remaps the signal to call
        interrupt_forcefully the next time.
        """
        signal.signal(signal.SIGINT, self.interrupt_forcefully)
        signal.signal(signal.SIGTERM, self.interrupt_forcefully)
        # Signals can arrive anywhere, so we do this in the main thread
        self._log_later("SIGINT/SIGTERM received, shutting down!",
                        "Do the same again to forcefully quit.")
        QTimer.singleShot(0, functools.partial(
            self._quitter.shutdown, 128 + signum))

    def interrupt_forcefully(self, signum, _frame):
        """Interrupt forcefully on the second SIGINT/SIGTERM request.

        This skips our shutdown routine and calls QApplication:exit instead.
        It then remaps the signals to call self.interrupt_really_forcefully the
        next time.
        """
        signal.signal(signal.SIGINT, self.interrupt_really_forcefully)
        signal.signal(signal.SIGTERM, self.interrupt_really_forcefully)
        # Signals can arrive anywhere, so we do this in the main thread
        self._log_later("Forceful quit requested, goodbye cruel world!",
                        "Do the same again to quit with even more force.")
        QTimer.singleShot(0, functools.partial(self._app.exit, 128 + signum))

    def interrupt_really_forcefully(self, signum, _frame):
        """Interrupt with even more force on the third SIGINT/SIGTERM request.

        This doesn't run *any* Qt cleanup and simply exits via Python.
        It will most likely lead to a segfault.
        """
        print("WHY ARE YOU DOING THIS TO ME? :(")
        sys.exit(128 + signum)
Esempio n. 44
0
    def start(self):
        self.readliner = non_blocking_readline(self.fp, self.linesep)

        self.socket_notifier = QSocketNotifier(self.fp.fileno(), QSocketNotifier.Read)
        self.socket_notifier.activated.connect(self._on_activated)
Esempio n. 45
0
class TwistedSocketNotifier(QObject):

    """
    Connection between an fd event and reader/writer callbacks.
    """

    activated = pyqtSignal(int)

    def __init__(self, parent, reactor, watcher, socketType):
        QObject.__init__(self, parent)
        self.reactor = reactor
        self.watcher = watcher
        fd = watcher.fileno()
        self.notifier = QSocketNotifier(fd, socketType, parent)
        self.notifier.setEnabled(True)
        if socketType == QSocketNotifier.Read:
            self.fn = self.read
        else:
            self.fn = self.write
        self.notifier.activated.connect(self.fn)

    def shutdown(self):
        self.notifier.setEnabled(False)
        self.notifier.activated.disconnect(self.fn)
        self.fn = self.watcher = None
        self.notifier.deleteLater()
        self.deleteLater()

    def read(self, fd):
        if not self.watcher:
            return
        w = self.watcher
        # doRead can cause self.shutdown to be called so keep
        # a reference to self.watcher

        def _read():
            #Don't call me again, until the data has been read
            self.notifier.setEnabled(False)
            why = None
            try:
                why = w.doRead()
                inRead = True
            except:
                inRead = False
                log.err()
                why = sys.exc_info()[1]
            if why:
                self.reactor._disconnectSelectable(w, why, inRead)
            elif self.watcher:
                self.notifier.setEnabled(True)
                # Re enable notification following sucessfull read
            self.reactor._iterate(fromqt=True)
        log.callWithLogger(w, _read)

    def write(self, sock):
        if not self.watcher:
            return
        w = self.watcher

        def _write():
            why = None
            self.notifier.setEnabled(False)

            try:
                why = w.doWrite()
            except:
                log.err()
                why = sys.exc_info()[1]
            if why:
                self.reactor._disconnectSelectable(w, why, False)
            elif self.watcher:
                self.notifier.setEnabled(True)
            self.reactor._iterate(fromqt=True)
        log.callWithLogger(w, _write)