File: __init__.py

package info (click to toggle)
frescobaldi 3.3.0%2Bds1-2
  • links: PTS, VCS
  • area: main
  • in suites: bookworm
  • size: 24,212 kB
  • sloc: python: 39,014; javascript: 263; sh: 238; makefile: 80
file content (138 lines) | stat: -rw-r--r-- 3,654 bytes parent folder | download | duplicates (3)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
# This file is part of the Frescobaldi project, http://www.frescobaldi.org/
#
# Copyright (c) 2012 - 2014 by Wilbert Berendsen
#
# 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 St, Fifth Floor, Boston, MA  02110-1301  USA
# See http://www.gnu.org/licenses/ for more information.

"""
Inter-Process Communication with already running Frescobaldi instances.
"""


import os
import sys

from PyQt5.QtCore import QSettings
from PyQt5.QtNetwork import QLocalServer, QLocalSocket

import app
import appinfo


_server = None


def get():
    """Return a remote Frescobaldi, or None if not available."""
    socket = QLocalSocket()
    name = os.environ.get("FRESCOBALDI_SOCKET")
    for name in (name,) if name else ids():
        socket.connectToServer(name)
        if socket.waitForConnected(5000):
            from . import api
            return api.Remote(socket)


def init():
    """Start listening to incoming connections."""
    global _server
    if _server is not None:
        return

    server = QLocalServer(None)

    # find a free socket name to use
    for name in ids():
        if server.listen(name):
            break
    else:
        # all names failed, try to contact and remove stale file if that fails
        socket = QLocalSocket()
        for name in ids():
            socket.connectToServer(name)
            if not socket.waitForConnected(10000):
                QLocalServer.removeServer(name)
                if server.listen(name):
                    break
            else:
                socket.disconnectFromServer()
        else:
            # no ids left, don't listen
            return
    app.aboutToQuit.connect(server.close)
    server.newConnection.connect(slot_new_connection)
    os.environ["FRESCOBALDI_SOCKET"] = name
    _server = server


def quit():
    """Stop listening to incoming connections."""
    global _server
    if _server is not None:
        _server.close()
        _server = None


def slot_new_connection():
    """Called when someone connects to the server socket."""
    from . import api
    api.Incoming(_server.nextPendingConnection())


def ids(count=3):
    """Yield at most count (default 3) names to use for the IPC socket."""
    i = generate_id()
    yield i
    for c in range(1, count):
        yield '{0}#{1}'.format(i, c)


def generate_id():
    """Generate a name for the IPC socket.

    The name is unique for the application, the user id and the DISPLAY
    on X11.

    """
    name = [appinfo.name]

    try:
        name.append(format(os.getuid()))
    except AttributeError:
        pass

    display = os.environ.get("DISPLAY")
    if display:
        name.append(display.replace(':', '_').replace('/', '_'))

    return '-'.join(name)


def enabled():
    """Return whether remote support is enabled.

    By default it is enabled.

    """
    return QSettings().value('allow_remote', True, bool)


def setup():
    """Enable or disable the remote server according to settings."""
    init() if enabled() else quit()

app.settingsChanged.connect(setup)