Philipp Hörist pushed to branch master at gajim / gajim

Commits:

8 changed files:

Changes:

  • src/application.py
    1
    +# -*- coding:utf-8 -*-
    
    2
    +## src/application.py
    
    3
    +##
    
    4
    +## Copyright (C) 2016 Emmanuel Gil Peyrot <linkmauve AT linkmauve.fr>
    
    5
    +##
    
    6
    +## This file is part of Gajim.
    
    7
    +##
    
    8
    +## Gajim is free software; you can redistribute it and/or modify
    
    9
    +## it under the terms of the GNU General Public License as published
    
    10
    +## by the Free Software Foundation; version 3 only.
    
    11
    +##
    
    12
    +## Gajim is distributed in the hope that it will be useful,
    
    13
    +## but WITHOUT ANY WARRANTY; without even the implied warranty of
    
    14
    +## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
    
    15
    +## GNU General Public License for more details.
    
    16
    +##
    
    17
    +## You should have received a copy of the GNU General Public License
    
    18
    +## along with Gajim. If not, see <http://www.gnu.org/licenses/>.
    
    19
    +##
    
    20
    +
    
    21
    +import sys
    
    22
    +import os
    
    23
    +import logging
    
    24
    +import signal
    
    25
    +import locale
    
    26
    +from gi.repository import GLib, Gio, Gtk
    
    27
    +from common import i18n
    
    28
    +from common import logging_helpers
    
    29
    +from common import crypto
    
    30
    +try:
    
    31
    +    PYOPENSSL_PRNG_PRESENT = True
    
    32
    +    import OpenSSL.rand
    
    33
    +except ImportError:
    
    34
    +    print('PyOpenSSL not available, impossible to generate entropy', file=sys.stderr)
    
    35
    +    PYOPENSSL_PRNG_PRESENT = False
    
    36
    +
    
    37
    +logging_helpers.init(sys.stderr.isatty())
    
    38
    +log = logging.getLogger('gajim.gajim')
    
    39
    +
    
    40
    +
    
    41
    +class GajimApplication(Gtk.Application):
    
    42
    +    '''Main class handling activation and command line.'''
    
    43
    +
    
    44
    +    def __init__(self):
    
    45
    +        Gtk.Application.__init__(self, application_id='org.gajim.Gajim',
    
    46
    +                                 flags=Gio.ApplicationFlags.HANDLES_COMMAND_LINE)
    
    47
    +        self.add_main_option('version', ord('V'), GLib.OptionFlags.NONE,
    
    48
    +                             GLib.OptionArg.NONE,
    
    49
    +                             _('Show the application\'s version'))
    
    50
    +        self.add_main_option('quiet', ord('q'), GLib.OptionFlags.NONE,
    
    51
    +                             GLib.OptionArg.NONE,
    
    52
    +                             _('Show only critical errors'))
    
    53
    +        self.add_main_option('separate', ord('s'), GLib.OptionFlags.NONE,
    
    54
    +                             GLib.OptionArg.NONE,
    
    55
    +                             _('Separate profile files completely (even '
    
    56
    +                               'history db and plugins)'))
    
    57
    +        self.add_main_option('verbose', ord('v'), GLib.OptionFlags.NONE,
    
    58
    +                             GLib.OptionArg.NONE,
    
    59
    +                             _('Print xml stanzas and other debug '
    
    60
    +                               'information'))
    
    61
    +        self.add_main_option('windev', ord('w'), GLib.OptionFlags.NONE,
    
    62
    +                             GLib.OptionArg.NONE,
    
    63
    +                             _('Print stdout/stderr to the console '
    
    64
    +                               'on Windows'))
    
    65
    +        self.add_main_option('profile', ord('p'), GLib.OptionFlags.NONE,
    
    66
    +                             GLib.OptionArg.STRING,
    
    67
    +                             _('Use defined profile in configuration '
    
    68
    +                               'directory'), 'NAME')
    
    69
    +        self.add_main_option('config-path', ord('c'), GLib.OptionFlags.NONE,
    
    70
    +                             GLib.OptionArg.STRING,
    
    71
    +                             _('Set configuration directory'), 'PATH')
    
    72
    +        self.add_main_option('loglevel', ord('l'), GLib.OptionFlags.NONE,
    
    73
    +                             GLib.OptionArg.STRING,
    
    74
    +                             _('Configure logging system'), 'LEVEL')
    
    75
    +
    
    76
    +        self.profile = ''
    
    77
    +        self.config_path = None
    
    78
    +        self.profile_separation = False
    
    79
    +        self.interface = None
    
    80
    +        self.rng_seed = None
    
    81
    +
    
    82
    +        GLib.set_prgname('gajim')
    
    83
    +        GLib.set_application_name('Gajim')
    
    84
    +
    
    85
    +    def do_startup(self):
    
    86
    +        Gtk.Application.do_startup(self)
    
    87
    +
    
    88
    +    def do_activate(self):
    
    89
    +        # If a second instance starts do_activate() is called
    
    90
    +        # We bringt the Roster window to the front, GTK exits afterwards.
    
    91
    +        if self.interface:
    
    92
    +            self.interface.roster.window.present()
    
    93
    +            return
    
    94
    +
    
    95
    +        Gtk.Application.do_activate(self)
    
    96
    +
    
    97
    +        # Create and initialize Application Paths & Databases
    
    98
    +        import common.configpaths
    
    99
    +        common.configpaths.gajimpaths.init(
    
    100
    +            self.config_path, self.profile, self.profile_separation)
    
    101
    +        from common import gajim
    
    102
    +        from common import check_paths
    
    103
    +        from common import exceptions
    
    104
    +        from common import logger
    
    105
    +        from common import caps_cache
    
    106
    +        try:
    
    107
    +            gajim.logger = logger.Logger()
    
    108
    +            caps_cache.initialize(gajim.logger)
    
    109
    +            check_paths.check_and_possibly_create_paths()
    
    110
    +        except exceptions.DatabaseMalformed:
    
    111
    +            dlg = Gtk.MessageDialog(
    
    112
    +                None,
    
    113
    +                Gtk.DialogFlags.DESTROY_WITH_PARENT | Gtk.DialogFlags.MODAL,
    
    114
    +                Gtk.MessageType.ERROR,
    
    115
    +                Gtk.ButtonsType.OK,
    
    116
    +                _('Database Error'))
    
    117
    +            dlg.format_secondary_text(
    
    118
    +                _('The database file (%s) cannot be read. Try to repair it '
    
    119
    +                  '(see http://trac.gajim.org/wiki/DatabaseBackup) or remove it '
    
    120
    +                  '(all history will be lost).') % gajim.gajimpaths['LOG_DB'])
    
    121
    +            dlg.run()
    
    122
    +            dlg.destroy()
    
    123
    +            sys.exit()
    
    124
    +
    
    125
    +        if os.name == 'nt':
    
    126
    +            import gettext
    
    127
    +            # needed for docutils
    
    128
    +            sys.path.append('.')
    
    129
    +            APP = 'gajim'
    
    130
    +            DIR = '../po'
    
    131
    +            lang, enc = locale.getdefaultlocale()
    
    132
    +            os.environ['LANG'] = lang
    
    133
    +            gettext.bindtextdomain(APP, DIR)
    
    134
    +            gettext.textdomain(APP)
    
    135
    +            gettext.install(APP, DIR)
    
    136
    +
    
    137
    +        # This is for Windows translation which is currently not
    
    138
    +        # working on GTK 3.18.9
    
    139
    +        #    locale.setlocale(locale.LC_ALL, '')
    
    140
    +        #    import ctypes
    
    141
    +        #    import ctypes.util
    
    142
    +        #    libintl_path = ctypes.util.find_library('intl')
    
    143
    +        #    if libintl_path == None:
    
    144
    +        #        local_intl = os.path.join('gtk', 'bin', 'intl.dll')
    
    145
    +        #        if os.path.exists(local_intl):
    
    146
    +        #            libintl_path = local_intl
    
    147
    +        #    if libintl_path == None:
    
    148
    +        #        raise ImportError('intl.dll library not found')
    
    149
    +        #    libintl = ctypes.cdll.LoadLibrary(libintl_path)
    
    150
    +        #    libintl.bindtextdomain(APP, DIR)
    
    151
    +        #    libintl.bind_textdomain_codeset(APP, 'UTF-8')
    
    152
    +        #    plugins_locale_dir = os.path.join(common.configpaths.gajimpaths[
    
    153
    +        #       'PLUGINS_USER'], 'locale').encode(locale.getpreferredencoding())
    
    154
    +        #    libintl.bindtextdomain('gajim_plugins', plugins_locale_dir)
    
    155
    +        #    libintl.bind_textdomain_codeset('gajim_plugins', 'UTF-8')
    
    156
    +
    
    157
    +        if Gtk.Widget.get_default_direction() == Gtk.TextDirection.RTL:
    
    158
    +            i18n.direction_mark = '\u200F'
    
    159
    +
    
    160
    +        from ctypes import CDLL
    
    161
    +        from ctypes.util import find_library
    
    162
    +        import platform
    
    163
    +
    
    164
    +        sysname = platform.system()
    
    165
    +        if sysname in ('Linux', 'FreeBSD', 'OpenBSD', 'NetBSD'):
    
    166
    +            libc = CDLL(find_library('c'))
    
    167
    +
    
    168
    +            # The constant defined in <linux/prctl.h> which is used to set the name
    
    169
    +            # of the process.
    
    170
    +            PR_SET_NAME = 15
    
    171
    +
    
    172
    +            if sysname == 'Linux':
    
    173
    +                libc.prctl(PR_SET_NAME, 'gajim')
    
    174
    +            elif sysname in ('FreeBSD', 'OpenBSD', 'NetBSD'):
    
    175
    +                libc.setproctitle('gajim')
    
    176
    +
    
    177
    +        # Seed the OpenSSL pseudo random number generator from file and initialize
    
    178
    +        if PYOPENSSL_PRNG_PRESENT:
    
    179
    +            self.rng_seed = gajim.gajimpaths['RNG_SEED']
    
    180
    +            # Seed from file
    
    181
    +            try:
    
    182
    +                OpenSSL.rand.load_file(self.rng_seed)
    
    183
    +            except TypeError:
    
    184
    +                OpenSSL.rand.load_file(self.rng_seed.encode('utf-8'))
    
    185
    +            crypto.add_entropy_sources_OpenSSL()
    
    186
    +            try:
    
    187
    +                OpenSSL.rand.write_file(self.rng_seed)
    
    188
    +            except TypeError:
    
    189
    +                OpenSSL.rand.write_file(self.rng_seed.encode('utf-8'))
    
    190
    +
    
    191
    +        def sigint_cb(num, stack):
    
    192
    +            print('SIGINT/SIGTERM received')
    
    193
    +            self.quit()
    
    194
    +        # ^C exits the application normally
    
    195
    +        signal.signal(signal.SIGINT, sigint_cb)
    
    196
    +        signal.signal(signal.SIGTERM, sigint_cb)
    
    197
    +
    
    198
    +        log.info("Encodings: d:%s, fs:%s, p:%s", sys.getdefaultencoding(),
    
    199
    +                 sys.getfilesystemencoding(), locale.getpreferredencoding())
    
    200
    +
    
    201
    +        from gui_interface import Interface
    
    202
    +        self.interface = Interface()
    
    203
    +        self.interface.run(self)
    
    204
    +
    
    205
    +    def do_shutdown(self, *args):
    
    206
    +        Gtk.Application.do_shutdown(self)
    
    207
    +        # Save the entropy from OpenSSL PRNG
    
    208
    +        if PYOPENSSL_PRNG_PRESENT and self.rng_seed:
    
    209
    +            try:
    
    210
    +                OpenSSL.rand.write_file(self.rng_seed)
    
    211
    +            except TypeError:
    
    212
    +                OpenSSL.rand.write_file(self.rng_seed.encode('utf-8'))
    
    213
    +        # Shutdown GUI and save config
    
    214
    +        if hasattr(self.interface, 'roster') and self.interface.roster:
    
    215
    +            self.interface.roster.prepare_quit()
    
    216
    +
    
    217
    +    def do_command_line(self, command_line: Gio.ApplicationCommandLine) -> int:
    
    218
    +        Gtk.Application.do_command_line(self, command_line)
    
    219
    +        options = command_line.get_options_dict()
    
    220
    +        if options.contains('quiet'):
    
    221
    +            logging_helpers.set_quiet()
    
    222
    +        if options.contains('separate'):
    
    223
    +            self.profile_separation = True
    
    224
    +        if options.contains('verbose'):
    
    225
    +            logging_helpers.set_verbose()
    
    226
    +        if options.contains('profile'):
    
    227
    +            variant = options.lookup_value('profile')
    
    228
    +            self.profile = variant.get_string()
    
    229
    +        if options.contains('loglevel'):
    
    230
    +            variant = options.lookup_value('loglevel')
    
    231
    +            string = variant.get_string()
    
    232
    +            logging_helpers.set_loglevels(string)
    
    233
    +        if options.contains('config-path'):
    
    234
    +            variant = options.lookup_value('config-path')
    
    235
    +            self.config_path = variant.get_string()
    
    236
    +        self.activate()
    
    237
    +        return 0

  • src/common/configpaths.py
    ... ... @@ -180,7 +180,6 @@ class ConfigPaths:
    180 180
     
    
    181 181
         def init_profile(self, profile):
    
    182 182
             conffile = windowsify('config')
    
    183
    -        pidfile = windowsify('gajim')
    
    184 183
             secretsfile = windowsify('secrets')
    
    185 184
             pluginsconfdir = windowsify('pluginsconfig')
    
    186 185
             certsdir = windowsify(u'certs')
    
    ... ... @@ -188,16 +187,13 @@ class ConfigPaths:
    188 187
     
    
    189 188
             if len(profile) > 0:
    
    190 189
                 conffile += '.' + profile
    
    191
    -            pidfile += '.' + profile
    
    192 190
                 secretsfile += '.' + profile
    
    193 191
                 pluginsconfdir += '.' + profile
    
    194 192
                 certsdir += u'.' + profile
    
    195 193
                 localcertsdir += u'.' + profile
    
    196 194
     
    
    197
    -        pidfile += '.pid'
    
    198 195
             self.add('SECRETS_FILE', TYPE_DATA, secretsfile)
    
    199 196
             self.add('MY_PEER_CERTS', TYPE_DATA, certsdir)
    
    200
    -        self.add('PID_FILE', TYPE_CACHE, pidfile)
    
    201 197
             self.add('CONFIG_FILE', TYPE_CONFIG, conffile)
    
    202 198
             self.add('PLUGINS_CONFIG_DIR', TYPE_CONFIG, pluginsconfdir)
    
    203 199
             self.add('MY_CERT', TYPE_CONFIG, localcertsdir)
    

  • src/common/helpers.py
    ... ... @@ -52,10 +52,16 @@ from string import Template
    52 52
     from common.i18n import Q_
    
    53 53
     from common.i18n import ngettext
    
    54 54
     
    
    55
    +if os.name == 'nt':
    
    56
    +    try:
    
    57
    +        HAS_WINSOUND = True
    
    58
    +        import winsound  # windows-only built-in module for playing wav
    
    59
    +    except ImportError:
    
    60
    +        HAS_WINSOUND = False
    
    61
    +        print('Gajim is not able to playback sound because'
    
    62
    +              'pywin32 is missing', file=sys.stderr)
    
    63
    +
    
    55 64
     try:
    
    56
    -    import winsound # windows-only built-in module for playing wav
    
    57
    -    import win32api
    
    58
    -    import win32con
    
    59 65
         import wave     # posix-only fallback wav playback
    
    60 66
         import ossaudiodev as oss
    
    61 67
     except Exception:
    
    ... ... @@ -462,52 +468,6 @@ def get_output_of_command(command):
    462 468
     
    
    463 469
         return output
    
    464 470
     
    
    465
    -def get_windows_reg_env(varname, default=''):
    
    466
    -    r"""
    
    467
    -    Ask for paths commonly used but not exposed as ENVs in english Windows 2003
    
    468
    -    those are:
    
    469
    -            'AppData' = %USERPROFILE%\Application Data (also an ENV)
    
    470
    -            'Desktop' = %USERPROFILE%\Desktop
    
    471
    -            'Favorites' = %USERPROFILE%\Favorites
    
    472
    -            'NetHood' = %USERPROFILE%\ NetHood
    
    473
    -            'Personal' = D:\My Documents (PATH TO MY DOCUMENTS)
    
    474
    -            'PrintHood' = %USERPROFILE%\PrintHood
    
    475
    -            'Programs' = %USERPROFILE%\Start Menu\Programs
    
    476
    -            'Recent' = %USERPROFILE%\Recent
    
    477
    -            'SendTo' = %USERPROFILE%\SendTo
    
    478
    -            'Start Menu' = %USERPROFILE%\Start Menu
    
    479
    -            'Startup' = %USERPROFILE%\Start Menu\Programs\Startup
    
    480
    -            'Templates' = %USERPROFILE%\Templates
    
    481
    -            'My Pictures' = D:\My Documents\My Pictures
    
    482
    -            'Local Settings' = %USERPROFILE%\Local Settings
    
    483
    -            'Local AppData' = %USERPROFILE%\Local Settings\Application Data
    
    484
    -            'Cache' = %USERPROFILE%\Local Settings\Temporary Internet Files
    
    485
    -            'Cookies' = %USERPROFILE%\Cookies
    
    486
    -            'History' = %USERPROFILE%\Local Settings\History
    
    487
    -    """
    
    488
    -    if os.name != 'nt':
    
    489
    -        return ''
    
    490
    -
    
    491
    -    val = default
    
    492
    -    try:
    
    493
    -        rkey = win32api.RegOpenKey(win32con.HKEY_CURRENT_USER,
    
    494
    -r'Software\Microsoft\Windows\CurrentVersion\Explorer\User Shell Folders')
    
    495
    -        try:
    
    496
    -            val = str(win32api.RegQueryValueEx(rkey, varname)[0])
    
    497
    -            val = win32api.ExpandEnvironmentStrings(val) # expand using environ
    
    498
    -        except Exception:
    
    499
    -            pass
    
    500
    -    finally:
    
    501
    -        win32api.RegCloseKey(rkey)
    
    502
    -    return val
    
    503
    -
    
    504
    -def get_documents_path():
    
    505
    -    if os.name == 'nt':
    
    506
    -        path = get_windows_reg_env('Personal')
    
    507
    -    else:
    
    508
    -        path = os.path.expanduser('~')
    
    509
    -    return path
    
    510
    -
    
    511 471
     def sanitize_filename(filename):
    
    512 472
         """
    
    513 473
         Make sure the filename we will write does contain only acceptable and latin
    
    ... ... @@ -787,12 +747,12 @@ def play_sound_file(path_to_soundfile):
    787 747
         path_to_soundfile = check_soundfile_path(path_to_soundfile)
    
    788 748
         if path_to_soundfile is None:
    
    789 749
             return
    
    790
    -    elif os.name == 'nt':
    
    750
    +    elif os.name == 'nt' and HAS_WINSOUND:
    
    791 751
             try:
    
    792 752
                 winsound.PlaySound(path_to_soundfile,
    
    793 753
                         winsound.SND_FILENAME|winsound.SND_ASYNC)
    
    794 754
             except Exception:
    
    795
    -            pass
    
    755
    +            log.exception('Sound Playback Error')
    
    796 756
         elif os.name == 'posix':
    
    797 757
             if gajim.config.get('soundplayer') == '':
    
    798 758
                 def _oss_play():
    

  • src/common/logger.py
    ... ... @@ -43,10 +43,9 @@ from common import ged
    43 43
     
    
    44 44
     import sqlite3 as sqlite
    
    45 45
     
    
    46
    -from common import configpaths
    
    47
    -LOG_DB_PATH = configpaths.gajimpaths['LOG_DB']
    
    46
    +LOG_DB_PATH = gajim.gajimpaths['LOG_DB']
    
    48 47
     LOG_DB_FOLDER, LOG_DB_FILE = os.path.split(LOG_DB_PATH)
    
    49
    -CACHE_DB_PATH = configpaths.gajimpaths['CACHE_DB']
    
    48
    +CACHE_DB_PATH = gajim.gajimpaths['CACHE_DB']
    
    50 49
     
    
    51 50
     import logging
    
    52 51
     log = logging.getLogger('gajim.c.logger')
    

  • src/dialogs.py
    ... ... @@ -1495,7 +1495,7 @@ class FileChooserDialog(Gtk.FileChooserDialog):
    1495 1495
             if current_folder and os.path.isdir(current_folder):
    
    1496 1496
                 self.set_current_folder(current_folder)
    
    1497 1497
             else:
    
    1498
    -            self.set_current_folder(helpers.get_documents_path())
    
    1498
    +            self.set_current_folder(os.path.expanduser('~'))
    
    1499 1499
             self.response_ok, self.response_cancel = \
    
    1500 1500
                     on_response_ok, on_response_cancel
    
    1501 1501
             # in gtk+-2.10 clicked signal on some of the buttons in a dialog
    
    ... ... @@ -5047,7 +5047,7 @@ class ArchiveChooserDialog(FileChooserDialog):
    5047 5047
                         callback(path_to_file)
    
    5048 5048
                 self.destroy()
    
    5049 5049
     
    
    5050
    -        path = helpers.get_documents_path()
    
    5050
    +        path = os.path.expanduser('~')
    
    5051 5051
     
    
    5052 5052
             FileChooserDialog.__init__(self,
    
    5053 5053
                 title_text=_('Choose Archive'),
    

  • src/gajim.py
    ... ... @@ -35,467 +35,76 @@
    35 35
     ## along with Gajim. If not, see <http://www.gnu.org/licenses/>.
    
    36 36
     ##
    
    37 37
     
    
    38
    -import os
    
    39 38
     import sys
    
    40
    -import warnings
    
    41
    -import OpenSSL
    
    39
    +import os
    
    40
    +
    
    41
    +if '--version' in sys.argv or '-V' in sys.argv:
    
    42
    +    from common.defs import version
    
    43
    +    print(version)
    
    44
    +    sys.exit(0)
    
    42 45
     
    
    43
    -if os.name == 'nt':
    
    46
    +WINDEV = False
    
    47
    +if '--windev' in sys.argv or '-w' in sys.argv:
    
    48
    +    WINDEV = True
    
    49
    +
    
    50
    +if os.name == 'nt' and not WINDEV:
    
    51
    +    import warnings
    
    44 52
         log_path = os.path.join(os.environ['APPDATA'], 'Gajim')
    
    45 53
         if not os.path.exists(log_path):
    
    46 54
             os.mkdir(log_path, 0o700)
    
    47 55
         log_file = os.path.join(log_path, 'gajim.log')
    
    48
    -    fout = open(log_file, 'a')
    
    49
    -    sys.stdout = fout
    
    50
    -    sys.stderr = fout
    
    51
    -
    
    52
    -    warnings.filterwarnings(action='ignore')
    
    53
    -
    
    54
    -MIN_NBXMPP_VER = "0.5.3"
    
    55
    -from gi.repository import GLib
    
    56
    -try:
    
    57
    -    import nbxmpp
    
    58
    -except ImportError:
    
    59
    -    print('Gajim needs python-nbxmpp to run. Quiting...')
    
    60
    -    sys.exit(1)
    
    61
    -
    
    62
    -from distutils.version import LooseVersion as V
    
    63
    -if V(nbxmpp.__version__) < V(MIN_NBXMPP_VER):
    
    64
    -    print('Gajim needs python-nbxmpp >= %s to run. Quiting...' % MIN_NBXMPP_VER)
    
    65
    -    sys.exit(1)
    
    66
    -
    
    67
    -if os.name == 'nt':
    
    68
    -    import locale
    
    69
    -    import gettext
    
    70
    -    APP = 'gajim'
    
    71
    -    DIR = '../po'
    
    72
    -    lang, enc = locale.getdefaultlocale()
    
    73
    -    os.environ['LANG'] = lang
    
    74
    -    gettext.bindtextdomain(APP, DIR)
    
    75
    -    gettext.textdomain(APP)
    
    76
    -    gettext.install(APP, DIR)
    
    77
    -
    
    78
    -#    locale.setlocale(locale.LC_ALL, '')
    
    79
    -#    import ctypes
    
    80
    -#    import ctypes.util
    
    81
    -#    libintl_path = ctypes.util.find_library('intl')
    
    82
    -#    if libintl_path == None:
    
    83
    -#        local_intl = os.path.join('gtk', 'bin', 'intl.dll')
    
    84
    -#        if os.path.exists(local_intl):
    
    85
    -#            libintl_path = local_intl
    
    86
    -#    if libintl_path == None:
    
    87
    -#        raise ImportError('intl.dll library not found')
    
    88
    -#    libintl = ctypes.cdll.LoadLibrary(libintl_path)
    
    89
    -#    libintl.bindtextdomain(APP, DIR)
    
    90
    -#    libintl.bind_textdomain_codeset(APP, 'UTF-8')
    
    91
    -
    
    92
    -if os.name == 'nt':
    
    93
    -    # needed for docutils
    
    94
    -    sys.path.append('.')
    
    95
    -
    
    96
    -from common import logging_helpers
    
    97
    -logging_helpers.init(sys.stderr.isatty())
    
    98
    -
    
    99
    -import logging
    
    100
    -# gajim.gui or gajim.gtk more appropriate ?
    
    101
    -log = logging.getLogger('gajim.gajim')
    
    102 56
     
    
    103
    -import gi
    
    104
    -gi.require_version('Gtk', '3.0')
    
    105
    -gi.require_version('Gdk', '3.0')
    
    106
    -gi.require_version('GObject', '2.0')
    
    107
    -gi.require_version('Pango', '1.0')
    
    108
    -
    
    109
    -import getopt
    
    110
    -from common import i18n
    
    111
    -
    
    112
    -def parseOpts():
    
    113
    -    profile_ = ''
    
    114
    -    config_path_ = None
    
    115
    -    profile_separation_ = False
    
    116
    -    
    
    117
    -    try:
    
    118
    -        shortargs = 'hqsvl:p:c:'
    
    119
    -        # add gtk/gnome session option as gtk_get_option_group is not wrapped
    
    120
    -        longargs = 'help quiet separate verbose loglevel= profile= config-path='
    
    121
    -        longargs += ' class= name= screen= gtk-module= sync g-fatal-warnings'
    
    122
    -        longargs += ' sm-client-id= sm-client-state-file= sm-disable'
    
    123
    -        opts = getopt.getopt(sys.argv[1:], shortargs, longargs.split())[0]
    
    124
    -    except getopt.error as msg1:
    
    125
    -        print(str(msg1))
    
    126
    -        print('for help use --help')
    
    127
    -        sys.exit(2)
    
    128
    -    for o, a in opts:
    
    129
    -        if o in ('-h', '--help'):
    
    130
    -            out = _('Usage:') + \
    
    131
    -                '\n  gajim [options] filename\n\n' + \
    
    132
    -                _('Options:') + \
    
    133
    -                '\n  -h, --help         ' + \
    
    134
    -                    _('Show this help message and exit') + \
    
    135
    -                '\n  -q, --quiet        ' + \
    
    136
    -                    _('Show only critical errors') + \
    
    137
    -                '\n  -s, --separate     ' + \
    
    138
    -                    _('Separate profile files completely (even history db and plugins)') + \
    
    139
    -                '\n  -v, --verbose      ' + \
    
    140
    -                    _('Print xml stanzas and other debug information') + \
    
    141
    -                '\n  -p, --profile      ' + \
    
    142
    -                    _('Use defined profile in configuration directory') + \
    
    143
    -                '\n  -c, --config-path  ' + \
    
    144
    -                    _('Set configuration directory') + \
    
    145
    -                '\n  -l, --loglevel     ' + \
    
    146
    -                    _('Configure logging system') + '\n'
    
    147
    -            print(out)
    
    148
    -            sys.exit()
    
    149
    -        elif o in ('-q', '--quiet'):
    
    150
    -            logging_helpers.set_quiet()
    
    151
    -        elif o in ('-s', '--separate'):
    
    152
    -            profile_separation_ = True
    
    153
    -        elif o in ('-v', '--verbose'):
    
    154
    -            logging_helpers.set_verbose()
    
    155
    -        elif o in ('-p', '--profile'): # gajim --profile name
    
    156
    -            profile_ = a
    
    157
    -        elif o in ('-l', '--loglevel'):
    
    158
    -            logging_helpers.set_loglevels(a)
    
    159
    -        elif o in ('-c', '--config-path'):
    
    160
    -            config_path_ = a
    
    161
    -    return profile_, config_path_, profile_separation_
    
    162
    -
    
    163
    -import locale
    
    164
    -profile, config_path, profile_separation = parseOpts()
    
    165
    -del parseOpts
    
    166
    -
    
    167
    -import common.configpaths
    
    168
    -common.configpaths.gajimpaths.init(config_path, profile, profile_separation)
    
    169
    -del config_path
    
    170
    -del profile
    
    171
    -
    
    172
    -if os.name == 'nt':
    
    173
    -    plugins_locale_dir = os.path.join(common.configpaths.gajimpaths[
    
    174
    -        'PLUGINS_USER'], 'locale').encode(locale.getpreferredencoding())
    
    175
    -#    libintl.bindtextdomain('gajim_plugins', plugins_locale_dir)
    
    176
    -#    libintl.bind_textdomain_codeset('gajim_plugins', 'UTF-8')
    
    177
    -
    
    178
    -    class MyStderr(object):
    
    57
    +    class MyStd(object):
    
    179 58
             _file = None
    
    180 59
             _error = None
    
    60
    +
    
    181 61
             def write(self, text):
    
    182
    -            fname = os.path.join(common.configpaths.gajimpaths.cache_root,
    
    183
    -                os.path.split(sys.executable)[1]+'.log')
    
    184 62
                 if self._file is None and self._error is None:
    
    185 63
                     try:
    
    186
    -                    self._file = open(fname, 'a')
    
    64
    +                    self._file = open(log_file, 'a')
    
    187 65
                     except Exception as details:
    
    188 66
                         self._error = details
    
    189 67
                 if self._file is not None:
    
    190 68
                     self._file.write(text)
    
    191 69
                     self._file.flush()
    
    70
    +
    
    192 71
             def flush(self):
    
    193 72
                 if self._file is not None:
    
    194 73
                     self._file.flush()
    
    195 74
     
    
    196
    -    sys.stderr = MyStderr()
    
    197
    -
    
    198
    -# PyGTK2.10+ only throws a warning
    
    199
    -warnings.filterwarnings('error', module='Gtk')
    
    200
    -try:
    
    201
    -    from gi.repository import GObject
    
    202
    -    GObject.set_prgname('gajim')
    
    203
    -    from gi.repository import Gtk
    
    204
    -    from gi.repository import Gdk
    
    205
    -    from gi.repository import GLib
    
    206
    -except Warning as msg2:
    
    207
    -    if str(msg2) == 'could not open display':
    
    208
    -        print(_('Gajim needs X server to run. Quiting...'), file=sys.stderr)
    
    209
    -    else:
    
    210
    -        print(_('importing PyGTK failed: %s') % str(msg2), file=sys.stderr)
    
    211
    -    sys.exit()
    
    212
    -warnings.resetwarnings()
    
    213
    -
    
    75
    +        def isatty(self):
    
    76
    +            return False
    
    214 77
     
    
    215
    -if os.name == 'nt':
    
    78
    +    outerr = MyStd()
    
    79
    +    sys.stdout = outerr
    
    80
    +    sys.stderr = outerr
    
    216 81
         warnings.filterwarnings(action='ignore')
    
    217 82
     
    
    218
    -if Gtk.Widget.get_default_direction() == Gtk.TextDirection.RTL:
    
    219
    -    i18n.direction_mark = '\u200F'
    
    220
    -pritext = ''
    
    221
    -
    
    222
    -from common import exceptions
    
    223
    -try:
    
    224
    -    from common import gajim
    
    225
    -except exceptions.DatabaseMalformed:
    
    226
    -    pritext = _('Database Error')
    
    227
    -    sectext = _('The database file (%s) cannot be read. Try to repair it (see '
    
    228
    -        'http://trac.gajim.org/wiki/DatabaseBackup) or remove it (all history '
    
    229
    -        'will be lost).') % common.logger.LOG_DB_PATH
    
    230
    -else:
    
    231
    -    from common import logger
    
    232
    -    gajim.logger = logger.Logger()
    
    233
    -    from common import caps_cache
    
    234
    -    caps_cache.initialize(gajim.logger)
    
    235
    -    from common import dbus_support
    
    236
    -    if dbus_support.supported:
    
    237
    -        from music_track_listener import MusicTrackListener
    
    238
    -
    
    239
    -    from ctypes import CDLL
    
    240
    -    from ctypes.util import find_library
    
    241
    -    import platform
    
    242
    -
    
    243
    -    sysname = platform.system()
    
    244
    -    if sysname in ('Linux', 'FreeBSD', 'OpenBSD', 'NetBSD'):
    
    245
    -        libc = CDLL(find_library('c'))
    
    246
    -
    
    247
    -        # The constant defined in <linux/prctl.h> which is used to set the name
    
    248
    -        # of the process.
    
    249
    -        PR_SET_NAME = 15
    
    250
    -
    
    251
    -        if sysname == 'Linux':
    
    252
    -            libc.prctl(PR_SET_NAME, 'gajim')
    
    253
    -        elif sysname in ('FreeBSD', 'OpenBSD', 'NetBSD'):
    
    254
    -            libc.setproctitle('gajim')
    
    255 83
     
    
    256
    -#    if Gtk.pygtk_version < (2, 22, 0):
    
    257
    -#        pritext = _('Gajim needs PyGTK 2.22 or above')
    
    258
    -#        sectext = _('Gajim needs PyGTK 2.22 or above to run. Quiting...')
    
    259
    -#    elif Gtk.gtk_version < (2, 22, 0):
    
    260
    -#    if (Gtk.get_major_version(), Gtk.get_minor_version(),
    
    261
    -#    Gtk.get_micro_version()) < (2, 22, 0):
    
    262
    -#        pritext = _('Gajim needs GTK 2.22 or above')
    
    263
    -#        sectext = _('Gajim needs GTK 2.22 or above to run. Quiting...')
    
    264
    -
    
    265
    -    from common import check_paths
    
    266
    -
    
    267
    -    if os.name == 'nt':
    
    268
    -        try:
    
    269
    -            import winsound # windows-only built-in module for playing wav
    
    270
    -            import win32api # do NOT remove. we req this module
    
    271
    -        except Exception:
    
    272
    -            pritext = _('Gajim needs pywin32 to run')
    
    273
    -            sectext = _('Please make sure that Pywin32 is installed on your '
    
    274
    -                'system. You can get it at %s') % \
    
    275
    -                'http://sourceforge.net/project/showfiles.php?group_id=78018'
    
    276
    -
    
    277
    -if pritext:
    
    278
    -    dlg = Gtk.MessageDialog(None,
    
    279
    -            Gtk.DialogFlags.DESTROY_WITH_PARENT | Gtk.DialogFlags.MODAL,
    
    280
    -            Gtk.MessageType.ERROR, Gtk.ButtonsType.OK, message_format = pritext)
    
    281
    -
    
    282
    -    dlg.format_secondary_text(sectext)
    
    283
    -    dlg.run()
    
    284
    -    dlg.destroy()
    
    285
    -    sys.exit()
    
    286
    -
    
    287
    -del pritext
    
    288
    -
    
    289
    -#import gtkexcepthook
    
    290
    -
    
    291
    -import signal
    
    292
    -import gtkgui_helpers
    
    293
    -
    
    294
    -gajimpaths = common.configpaths.gajimpaths
    
    84
    +# Test here for all required versions so we dont have to
    
    85
    +# test multiple times in every module. nbxmpp also needs GLib.
    
    86
    +import gi
    
    87
    +gi.require_version('GLib', '2.0')
    
    88
    +gi.require_version('Gio', '2.0')
    
    89
    +gi.require_version('Gtk', '3.0')
    
    90
    +gi.require_version('Gdk', '3.0')
    
    91
    +gi.require_version('GObject', '2.0')
    
    92
    +gi.require_version('Pango', '1.0')
    
    295 93
     
    
    296
    -pid_filename = gajimpaths['PID_FILE']
    
    297
    -config_filename = gajimpaths['CONFIG_FILE']
    
    94
    +MIN_NBXMPP_VER = "0.5.3"
    
    298 95
     
    
    299
    -# Seed the OpenSSL pseudo random number generator from file and initialize
    
    300
    -RNG_SEED = gajimpaths['RNG_SEED']
    
    301
    -PYOPENSSL_PRNG_PRESENT = False
    
    302 96
     try:
    
    303
    -    import OpenSSL.rand
    
    304
    -    from common import crypto
    
    305
    -    PYOPENSSL_PRNG_PRESENT = True
    
    306
    -    # Seed from file
    
    307
    -    try:
    
    308
    -        OpenSSL.rand.load_file(RNG_SEED)
    
    309
    -    except TypeError:
    
    310
    -        OpenSSL.rand.load_file(RNG_SEED.encode('utf-8'))
    
    311
    -    crypto.add_entropy_sources_OpenSSL()
    
    312
    -    try:
    
    313
    -        OpenSSL.rand.write_file(RNG_SEED)
    
    314
    -    except TypeError:
    
    315
    -        OpenSSL.rand.write_file(RNG_SEED.encode('utf-8'))
    
    97
    +    import nbxmpp
    
    316 98
     except ImportError:
    
    317
    -    log.info("PyOpenSSL PRNG not available")
    
    318
    -
    
    319
    -import traceback
    
    320
    -import errno
    
    321
    -import dialogs
    
    322
    -
    
    323
    -def pid_alive():
    
    324
    -    try:
    
    325
    -        pf = open(pid_filename)
    
    326
    -    except IOError:
    
    327
    -        # probably file not found
    
    328
    -        return False
    
    329
    -
    
    330
    -    try:
    
    331
    -        pid = int(pf.read().strip())
    
    332
    -        pf.close()
    
    333
    -    except Exception:
    
    334
    -        traceback.print_exc()
    
    335
    -        # PID file exists, but something happened trying to read PID
    
    336
    -        # Could be 0.10 style empty PID file, so assume Gajim is running
    
    337
    -        return True
    
    338
    -
    
    339
    -    if os.name == 'nt':
    
    340
    -        try:
    
    341
    -            from ctypes import (windll, c_ulong, c_int, Structure, c_char)
    
    342
    -            from ctypes import (POINTER, pointer, sizeof)
    
    343
    -        except Exception:
    
    344
    -            return True
    
    345
    -
    
    346
    -        class PROCESSENTRY32(Structure):
    
    347
    -            _fields_ = [
    
    348
    -                    ('dwSize', c_ulong, ),
    
    349
    -                    ('cntUsage', c_ulong, ),
    
    350
    -                    ('th32ProcessID', c_ulong, ),
    
    351
    -                    ('th32DefaultHeapID', c_ulong, ),
    
    352
    -                    ('th32ModuleID', c_ulong, ),
    
    353
    -                    ('cntThreads', c_ulong, ),
    
    354
    -                    ('th32ParentProcessID', c_ulong, ),
    
    355
    -                    ('pcPriClassBase', c_ulong, ),
    
    356
    -                    ('dwFlags', c_ulong, ),
    
    357
    -                    ('szExeFile', c_char*512, ),
    
    358
    -                    ]
    
    359
    -
    
    360
    -        kernel = windll.kernel32
    
    361
    -        kernel.CreateToolhelp32Snapshot.argtypes = c_ulong, c_ulong,
    
    362
    -        kernel.CreateToolhelp32Snapshot.restype = c_int
    
    363
    -        kernel.Process32First.argtypes = c_int, POINTER(PROCESSENTRY32),
    
    364
    -        kernel.Process32First.restype = c_int
    
    365
    -        kernel.Process32Next.argtypes = c_int, POINTER(PROCESSENTRY32),
    
    366
    -        kernel.Process32Next.restype = c_int
    
    367
    -
    
    368
    -        def get_p(pid_):
    
    369
    -            TH32CS_SNAPPROCESS = 2
    
    370
    -            CreateToolhelp32Snapshot = kernel.CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0)
    
    371
    -            assert CreateToolhelp32Snapshot > 0, 'CreateToolhelp32Snapshot failed'
    
    372
    -            pe32 = PROCESSENTRY32()
    
    373
    -            pe32.dwSize = sizeof( PROCESSENTRY32 )
    
    374
    -            f3 = kernel.Process32First(CreateToolhelp32Snapshot, pointer(pe32))
    
    375
    -            while f3:
    
    376
    -                if pe32.th32ProcessID == pid_:
    
    377
    -                    return pe32.szExeFile
    
    378
    -                f3 = kernel.Process32Next(CreateToolhelp32Snapshot, pointer(pe32))
    
    379
    -
    
    380
    -        if get_p(pid) in ('python.exe', 'gajim.exe'):
    
    381
    -            return True
    
    382
    -        return False
    
    383
    -    try:
    
    384
    -        if not os.path.exists('/proc'):
    
    385
    -            return True # no /proc, assume Gajim is running
    
    386
    -
    
    387
    -        try:
    
    388
    -            f1 = open('/proc/%d/cmdline'% pid)
    
    389
    -        except IOError as e1:
    
    390
    -            if e1.errno == errno.ENOENT:
    
    391
    -                return False # file/pid does not exist
    
    392
    -            raise
    
    393
    -
    
    394
    -        n = f1.read().lower()
    
    395
    -        f1.close()
    
    396
    -        if n.find('gajim') < 0:
    
    397
    -            return False
    
    398
    -        return True # Running Gajim found at pid
    
    399
    -    except Exception:
    
    400
    -        traceback.print_exc()
    
    401
    -
    
    402
    -    # If we are here, pidfile exists, but some unexpected error occured.
    
    403
    -    # Assume Gajim is running.
    
    404
    -    return True
    
    405
    -
    
    406
    -def show_remote_gajim_roster():
    
    407
    -    try:
    
    408
    -        import dbus
    
    409
    -
    
    410
    -        OBJ_PATH = '/org/gajim/dbus/RemoteObject'
    
    411
    -        INTERFACE = 'org.gajim.dbus.RemoteInterface'
    
    412
    -        SERVICE = 'org.gajim.dbus'
    
    413
    -
    
    414
    -        # Attempt to call show_roster
    
    415
    -        dbus.Interface(dbus.SessionBus().get_object(SERVICE, OBJ_PATH), INTERFACE).__getattr__("show_roster")()
    
    416
    -
    
    417
    -        return True
    
    418
    -    except Exception:
    
    419
    -        return False
    
    420
    -
    
    421
    -if pid_alive():
    
    422
    -    if (show_remote_gajim_roster()):
    
    423
    -        print("Gajim is already running, bringing the roster to front...")
    
    424
    -        sys.exit(0)
    
    425
    -    pixs = []
    
    426
    -    for size in (16, 32, 48, 64, 128):
    
    427
    -        pix = gtkgui_helpers.get_icon_pixmap('gajim', size)
    
    428
    -        if pix:
    
    429
    -            pixs.append(pix)
    
    430
    -    if pixs:
    
    431
    -        # set the icon to all windows
    
    432
    -        Gtk.Window.set_default_icon_list(pixs)
    
    433
    -    pritext = _('Gajim is already running')
    
    434
    -    sectext = _('Another instance of Gajim seems to be running\nRun anyway?')
    
    435
    -    dialog = dialogs.YesNoDialog(pritext, sectext)
    
    436
    -    dialog.popup()
    
    437
    -    if dialog.run() != Gtk.ResponseType.YES:
    
    438
    -        sys.exit(3)
    
    439
    -    dialog.destroy()
    
    440
    -    # run anyway, delete pid and useless global vars
    
    441
    -    if os.path.exists(pid_filename):
    
    442
    -        os.remove(pid_filename)
    
    443
    -    del pix
    
    444
    -    del pritext
    
    445
    -    del sectext
    
    446
    -    dialog.destroy()
    
    447
    -
    
    448
    -# Create .gajim dir
    
    449
    -pid_dir =  os.path.dirname(pid_filename)
    
    450
    -if not os.path.exists(pid_dir):
    
    451
    -    check_paths.create_path(pid_dir)
    
    452
    -# Create pid file
    
    453
    -try:
    
    454
    -    f2 = open(pid_filename, 'w')
    
    455
    -    f2.write(str(os.getpid()))
    
    456
    -    f2.close()
    
    457
    -except IOError as e2:
    
    458
    -    dlg = dialogs.ErrorDialog(_('Disk Write Error'), str(e2))
    
    459
    -    dlg.run()
    
    460
    -    dlg.destroy()
    
    461
    -    sys.exit()
    
    462
    -del pid_dir
    
    463
    -
    
    464
    -def on_exit():
    
    465
    -    # Save the entropy from OpenSSL PRNG
    
    466
    -    if PYOPENSSL_PRNG_PRESENT:
    
    467
    -        try:
    
    468
    -            OpenSSL.rand.write_file(RNG_SEED)
    
    469
    -        except TypeError:
    
    470
    -            OpenSSL.rand.write_file(RNG_SEED.encode('utf-8'))
    
    471
    -    # delete pid file on normal exit
    
    472
    -    if os.path.exists(pid_filename):
    
    473
    -        os.remove(pid_filename)
    
    474
    -    # Shutdown GUI and save config
    
    475
    -    if hasattr(gajim.interface, 'roster') and gajim.interface.roster:
    
    476
    -        gajim.interface.roster.prepare_quit()
    
    477
    -
    
    478
    -import atexit
    
    479
    -atexit.register(on_exit)
    
    480
    -
    
    481
    -from gui_interface import Interface
    
    482
    -
    
    483
    -if __name__.endswith('__main__'):
    
    484
    -    def sigint_cb(num, stack):
    
    485
    -        sys.exit(5)
    
    486
    -    # ^C exits the application normally to delete pid file
    
    487
    -    signal.signal(signal.SIGINT, sigint_cb)
    
    488
    -    signal.signal(signal.SIGTERM, sigint_cb)
    
    489
    -
    
    490
    -    log.info("Encodings: d:%s, fs:%s, p:%s", sys.getdefaultencoding(), \
    
    491
    -            sys.getfilesystemencoding(), locale.getpreferredencoding())
    
    99
    +    print('Gajim needs python-nbxmpp to run. Quiting...')
    
    100
    +    sys.exit(1)
    
    492 101
     
    
    493
    -    check_paths.check_and_possibly_create_paths()
    
    102
    +from distutils.version import LooseVersion as V
    
    103
    +if V(nbxmpp.__version__) < V(MIN_NBXMPP_VER):
    
    104
    +    print('Gajim needs python-nbxmpp >= %s to run. Quiting...' % MIN_NBXMPP_VER)
    
    105
    +    sys.exit(1)
    
    494 106
     
    
    495
    -    interface = Interface()
    
    496
    -    interface.run()
    
    107
    +from application import GajimApplication
    
    497 108
     
    
    498
    -    try:
    
    499
    -        Gtk.main()
    
    500
    -    except KeyboardInterrupt:
    
    501
    -        print('KeyboardInterrupt', file=sys.stderr)
    109
    +app = GajimApplication()
    
    110
    +app.run(sys.argv)

  • src/gui_interface.py
    ... ... @@ -2719,11 +2719,11 @@ class Interface:
    2719 2719
             view.updateNamespace({'gajim': gajim})
    
    2720 2720
             gajim.ipython_window = window
    
    2721 2721
     
    
    2722
    -    def run(self):
    
    2722
    +    def run(self, app):
    
    2723 2723
             if gajim.config.get('trayicon') != 'never':
    
    2724 2724
                 self.show_systray()
    
    2725 2725
     
    
    2726
    -        self.roster = roster_window.RosterWindow()
    
    2726
    +        self.roster = roster_window.RosterWindow(app)
    
    2727 2727
             if self.msg_win_mgr.mode == \
    
    2728 2728
             MessageWindowMgr.ONE_MSG_WINDOW_ALWAYS_WITH_ROSTER:
    
    2729 2729
                 self.msg_win_mgr.create_window(None, None, None)
    

  • src/roster_window.py
    ... ... @@ -94,7 +94,7 @@ empty_pixbuf = GdkPixbuf.Pixbuf.new(GdkPixbuf.Colorspace.RGB, True, 8, 1, 1)
    94 94
     empty_pixbuf.fill(0xffffff00)
    
    95 95
     
    
    96 96
     
    
    97
    -class RosterWindow:
    
    97
    +class RosterWindow(Gtk.ApplicationWindow):
    
    98 98
         """
    
    99 99
         Class for main window of the GTK+ interface
    
    100 100
         """
    
    ... ... @@ -2479,7 +2479,7 @@ class RosterWindow:
    2479 2479
             When we quit the gtk interface - exit gtk
    
    2480 2480
             """
    
    2481 2481
             self.prepare_quit()
    
    2482
    -        Gtk.main_quit()
    
    2482
    +        self.application.quit()
    
    2483 2483
     
    
    2484 2484
         def on_quit_request(self, widget=None):
    
    2485 2485
             """
    
    ... ... @@ -6178,7 +6178,8 @@ class RosterWindow:
    6178 6178
     ###
    
    6179 6179
     ################################################################################
    
    6180 6180
     
    
    6181
    -    def __init__(self):
    
    6181
    +    def __init__(self, app):
    
    6182
    +        self.application = app
    
    6182 6183
             self.filtering = False
    
    6183 6184
             self.starting = False
    
    6184 6185
             self.starting_filtering = False
    
    ... ... @@ -6195,6 +6196,7 @@ class RosterWindow:
    6195 6196
             self.xml = gtkgui_helpers.get_gtk_builder('roster_window.ui')
    
    6196 6197
             self.window = self.xml.get_object('roster_window')
    
    6197 6198
             self.hpaned = self.xml.get_object('roster_hpaned')
    
    6199
    +        self.window.set_application(app)
    
    6198 6200
             gajim.interface.msg_win_mgr = MessageWindowMgr(self.window, self.hpaned)
    
    6199 6201
             gajim.interface.msg_win_mgr.connect('window-delete',
    
    6200 6202
                 self.on_message_window_delete)