gajim.py 4.49 KB
Newer Older
Philipp Hörist's avatar
Philipp Hörist committed
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
# Copyright (C) 2018 Philipp Hörist <philipp AT hoerist.com>
#
# This file is part of Gajim.
#
# Gajim 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.
#
# Gajim 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 Gajim. If not, see <http://www.gnu.org/licenses/>.

18

19
import os
Philipp Hörist's avatar
Philipp Hörist committed
20
import sys
21
import signal
Philipp Hörist's avatar
Philipp Hörist committed
22 23 24
import platform
from ctypes import CDLL, byref, create_string_buffer
from ctypes.util import find_library
25
from packaging.version import Version as V
26

André's avatar
André committed
27
from gajim.common import i18n
28

Philipp Hörist's avatar
Philipp Hörist committed
29
_MIN_NBXMPP_VER = '1.0.1'
Philipp Hörist's avatar
Philipp Hörist committed
30
_MIN_GTK_VER = '3.22.27'
André's avatar
André committed
31
_MIN_CAIRO_VER = '1.16.0'
Philipp Hörist's avatar
Philipp Hörist committed
32
_MIN_PYGOBJECT_VER = '3.32.0'
Philipp Hörist's avatar
Philipp Hörist committed
33
_MIN_GLIB_VER = '2.60.0'
34 35


Philipp Hörist's avatar
Philipp Hörist committed
36 37
def check_version(dep_name, current_ver, min_ver):
    if V(current_ver) < V(min_ver):
Philipp Hörist's avatar
Philipp Hörist committed
38 39
        sys.exit('Gajim needs %s >= %s (found %s) to run. '
                 'Quitting...' % (dep_name, min_ver, current_ver))
Philipp Hörist's avatar
Philipp Hörist committed
40 41


Philipp Hörist's avatar
Philipp Hörist committed
42
def _check_required_deps():
43
    error_message = 'Gajim needs %s to run. Quitting… (Error: %s)'
Philipp Hörist's avatar
Philipp Hörist committed
44

Philipp Hörist's avatar
Philipp Hörist committed
45 46
    try:
        import nbxmpp
47 48
    except ImportError as error:
        sys.exit(error_message % ('python-nbxmpp', error))
49

50 51
    try:
        import gi
52 53
    except ImportError as error:
        sys.exit(error_message % ('pygobject', error))
54

Philipp Hörist's avatar
Philipp Hörist committed
55 56 57 58 59 60 61 62 63
    try:
        gi.require_versions({'GLib': '2.0',
                             'Gio': '2.0',
                             'Gtk': '3.0',
                             'GObject': '2.0',
                             'Pango': '1.0',
                             'Soup': '2.4'})
    except ValueError as error:
        sys.exit('Missing dependency: %s' % error)
64

65 66
    try:
        import cairo
67 68
    except ImportError as error:
        sys.exit(error_message % ('python-cairo', error))
69

Philipp Hörist's avatar
Philipp Hörist committed
70 71 72 73
    from gi.repository import Gtk
    gtk_ver = '%s.%s.%s' % (Gtk.get_major_version(),
                            Gtk.get_minor_version(),
                            Gtk.get_micro_version())
74

Philipp Hörist's avatar
Philipp Hörist committed
75 76 77 78 79
    from gi.repository import GLib
    glib_ver = '.'.join(map(str, [GLib.MAJOR_VERSION,
                                  GLib.MINOR_VERSION,
                                  GLib.MICRO_VERSION]))

Philipp Hörist's avatar
Philipp Hörist committed
80 81 82 83 84
    check_version('python-nbxmpp', nbxmpp.__version__, _MIN_NBXMPP_VER)
    check_version('pygobject', gi.__version__, _MIN_PYGOBJECT_VER)
    check_version('libcairo', cairo.cairo_version_string(), _MIN_CAIRO_VER)
    check_version('python-cairo', cairo.version, _MIN_CAIRO_VER)
    check_version('gtk3', gtk_ver, _MIN_GTK_VER)
Philipp Hörist's avatar
Philipp Hörist committed
85
    check_version('glib', glib_ver, _MIN_GLIB_VER)
86

87

Philipp Hörist's avatar
Philipp Hörist committed
88 89 90
def _init_gui(gui):
    if gui == 'GTK':
        _init_gtk()
91

92

93
def _disable_csd():
94
    if sys.platform != 'win32':
95 96 97 98 99 100
        return

    if 'GTK_OSD' in os.environ:
        # Respect user settings
        return

Philipp Hörist's avatar
Philipp Hörist committed
101
    os.environ['GTK_CSD'] = '0'
102 103


Philipp Hörist's avatar
Philipp Hörist committed
104
def _init_gtk():
Philipp Hörist's avatar
Philipp Hörist committed
105 106
    from gajim.gtk import exception
    exception.init()
107

Philipp Hörist's avatar
Philipp Hörist committed
108
    i18n.initialize_direction_mark()
109

Philipp Hörist's avatar
Philipp Hörist committed
110
    from gajim.application import GajimApplication
111

Philipp Hörist's avatar
Philipp Hörist committed
112
    application = GajimApplication()
113
    _install_sginal_handlers(application)
Philipp Hörist's avatar
Philipp Hörist committed
114
    application.run(sys.argv)
115

116

Philipp Hörist's avatar
Philipp Hörist committed
117 118 119 120
def _set_proc_title():
    sysname = platform.system()
    if sysname in ('Linux', 'FreeBSD', 'OpenBSD', 'NetBSD'):
        libc = CDLL(find_library('c'))
121

Philipp Hörist's avatar
Philipp Hörist committed
122 123 124
        # The constant defined in <linux/prctl.h> which is used to set the name
        # of the process.
        PR_SET_NAME = 15
125

Philipp Hörist's avatar
Philipp Hörist committed
126 127 128 129 130 131 132
        if sysname == 'Linux':
            proc_name = b'gajim'
            buff = create_string_buffer(len(proc_name)+1)
            buff.value = proc_name
            libc.prctl(PR_SET_NAME, byref(buff), 0, 0, 0)
        elif sysname in ('FreeBSD', 'OpenBSD', 'NetBSD'):
            libc.setproctitle('gajim')
Philipp Hörist's avatar
Philipp Hörist committed
133 134


135
def _install_sginal_handlers(application):
Philipp Hörist's avatar
Philipp Hörist committed
136 137 138 139 140 141
    def sigint_cb(num, stack):
        print('SIGINT/SIGTERM received')
        application.quit()
    # ^C exits the application normally
    signal.signal(signal.SIGINT, sigint_cb)
    signal.signal(signal.SIGTERM, sigint_cb)
142
    if sys.platform != 'win32':
143
        signal.signal(signal.SIGPIPE, signal.SIG_DFL)
144

145

146 147 148
def main():
    if sys.platform != 'win32':
        if os.geteuid() == 0:
Philipp Hörist's avatar
Philipp Hörist committed
149
            sys.exit('You must not launch gajim as root, it is insecure.')
150

Philipp Hörist's avatar
Philipp Hörist committed
151 152
    _check_required_deps()
    _set_proc_title()
153
    _disable_csd()
Philipp Hörist's avatar
Philipp Hörist committed
154
    _init_gui('GTK')