Merge branch 'dev' into 'master'
Switch to GtkApplication and clean up of Startup code See merge request !16
This commit is contained in:
commit
2b1b461e90
8 changed files with 310 additions and 507 deletions
237
src/application.py
Normal file
237
src/application.py
Normal file
|
@ -0,0 +1,237 @@
|
||||||
|
# -*- coding:utf-8 -*-
|
||||||
|
## src/application.py
|
||||||
|
##
|
||||||
|
## Copyright (C) 2016 Emmanuel Gil Peyrot <linkmauve AT linkmauve.fr>
|
||||||
|
##
|
||||||
|
## 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; version 3 only.
|
||||||
|
##
|
||||||
|
## 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/>.
|
||||||
|
##
|
||||||
|
|
||||||
|
import sys
|
||||||
|
import os
|
||||||
|
import logging
|
||||||
|
import signal
|
||||||
|
import locale
|
||||||
|
from gi.repository import GLib, Gio, Gtk
|
||||||
|
from common import i18n
|
||||||
|
from common import logging_helpers
|
||||||
|
from common import crypto
|
||||||
|
try:
|
||||||
|
PYOPENSSL_PRNG_PRESENT = True
|
||||||
|
import OpenSSL.rand
|
||||||
|
except ImportError:
|
||||||
|
print('PyOpenSSL not available, impossible to generate entropy', file=sys.stderr)
|
||||||
|
PYOPENSSL_PRNG_PRESENT = False
|
||||||
|
|
||||||
|
logging_helpers.init(sys.stderr.isatty())
|
||||||
|
log = logging.getLogger('gajim.gajim')
|
||||||
|
|
||||||
|
|
||||||
|
class GajimApplication(Gtk.Application):
|
||||||
|
'''Main class handling activation and command line.'''
|
||||||
|
|
||||||
|
def __init__(self):
|
||||||
|
Gtk.Application.__init__(self, application_id='org.gajim.Gajim',
|
||||||
|
flags=Gio.ApplicationFlags.HANDLES_COMMAND_LINE)
|
||||||
|
self.add_main_option('version', ord('V'), GLib.OptionFlags.NONE,
|
||||||
|
GLib.OptionArg.NONE,
|
||||||
|
_('Show the application\'s version'))
|
||||||
|
self.add_main_option('quiet', ord('q'), GLib.OptionFlags.NONE,
|
||||||
|
GLib.OptionArg.NONE,
|
||||||
|
_('Show only critical errors'))
|
||||||
|
self.add_main_option('separate', ord('s'), GLib.OptionFlags.NONE,
|
||||||
|
GLib.OptionArg.NONE,
|
||||||
|
_('Separate profile files completely (even '
|
||||||
|
'history db and plugins)'))
|
||||||
|
self.add_main_option('verbose', ord('v'), GLib.OptionFlags.NONE,
|
||||||
|
GLib.OptionArg.NONE,
|
||||||
|
_('Print xml stanzas and other debug '
|
||||||
|
'information'))
|
||||||
|
self.add_main_option('windev', ord('w'), GLib.OptionFlags.NONE,
|
||||||
|
GLib.OptionArg.NONE,
|
||||||
|
_('Print stdout/stderr to the console '
|
||||||
|
'on Windows'))
|
||||||
|
self.add_main_option('profile', ord('p'), GLib.OptionFlags.NONE,
|
||||||
|
GLib.OptionArg.STRING,
|
||||||
|
_('Use defined profile in configuration '
|
||||||
|
'directory'), 'NAME')
|
||||||
|
self.add_main_option('config-path', ord('c'), GLib.OptionFlags.NONE,
|
||||||
|
GLib.OptionArg.STRING,
|
||||||
|
_('Set configuration directory'), 'PATH')
|
||||||
|
self.add_main_option('loglevel', ord('l'), GLib.OptionFlags.NONE,
|
||||||
|
GLib.OptionArg.STRING,
|
||||||
|
_('Configure logging system'), 'LEVEL')
|
||||||
|
|
||||||
|
self.profile = ''
|
||||||
|
self.config_path = None
|
||||||
|
self.profile_separation = False
|
||||||
|
self.interface = None
|
||||||
|
self.rng_seed = None
|
||||||
|
|
||||||
|
GLib.set_prgname('gajim')
|
||||||
|
GLib.set_application_name('Gajim')
|
||||||
|
|
||||||
|
def do_startup(self):
|
||||||
|
Gtk.Application.do_startup(self)
|
||||||
|
|
||||||
|
def do_activate(self):
|
||||||
|
# If a second instance starts do_activate() is called
|
||||||
|
# We bringt the Roster window to the front, GTK exits afterwards.
|
||||||
|
if self.interface:
|
||||||
|
self.interface.roster.window.present()
|
||||||
|
return
|
||||||
|
|
||||||
|
Gtk.Application.do_activate(self)
|
||||||
|
|
||||||
|
# Create and initialize Application Paths & Databases
|
||||||
|
import common.configpaths
|
||||||
|
common.configpaths.gajimpaths.init(
|
||||||
|
self.config_path, self.profile, self.profile_separation)
|
||||||
|
from common import gajim
|
||||||
|
from common import check_paths
|
||||||
|
from common import exceptions
|
||||||
|
from common import logger
|
||||||
|
from common import caps_cache
|
||||||
|
try:
|
||||||
|
gajim.logger = logger.Logger()
|
||||||
|
caps_cache.initialize(gajim.logger)
|
||||||
|
check_paths.check_and_possibly_create_paths()
|
||||||
|
except exceptions.DatabaseMalformed:
|
||||||
|
dlg = Gtk.MessageDialog(
|
||||||
|
None,
|
||||||
|
Gtk.DialogFlags.DESTROY_WITH_PARENT | Gtk.DialogFlags.MODAL,
|
||||||
|
Gtk.MessageType.ERROR,
|
||||||
|
Gtk.ButtonsType.OK,
|
||||||
|
_('Database Error'))
|
||||||
|
dlg.format_secondary_text(
|
||||||
|
_('The database file (%s) cannot be read. Try to repair it '
|
||||||
|
'(see http://trac.gajim.org/wiki/DatabaseBackup) or remove it '
|
||||||
|
'(all history will be lost).') % gajim.gajimpaths['LOG_DB'])
|
||||||
|
dlg.run()
|
||||||
|
dlg.destroy()
|
||||||
|
sys.exit()
|
||||||
|
|
||||||
|
if os.name == 'nt':
|
||||||
|
import gettext
|
||||||
|
# needed for docutils
|
||||||
|
sys.path.append('.')
|
||||||
|
APP = 'gajim'
|
||||||
|
DIR = '../po'
|
||||||
|
lang, enc = locale.getdefaultlocale()
|
||||||
|
os.environ['LANG'] = lang
|
||||||
|
gettext.bindtextdomain(APP, DIR)
|
||||||
|
gettext.textdomain(APP)
|
||||||
|
gettext.install(APP, DIR)
|
||||||
|
|
||||||
|
# This is for Windows translation which is currently not
|
||||||
|
# working on GTK 3.18.9
|
||||||
|
# locale.setlocale(locale.LC_ALL, '')
|
||||||
|
# import ctypes
|
||||||
|
# import ctypes.util
|
||||||
|
# libintl_path = ctypes.util.find_library('intl')
|
||||||
|
# if libintl_path == None:
|
||||||
|
# local_intl = os.path.join('gtk', 'bin', 'intl.dll')
|
||||||
|
# if os.path.exists(local_intl):
|
||||||
|
# libintl_path = local_intl
|
||||||
|
# if libintl_path == None:
|
||||||
|
# raise ImportError('intl.dll library not found')
|
||||||
|
# libintl = ctypes.cdll.LoadLibrary(libintl_path)
|
||||||
|
# libintl.bindtextdomain(APP, DIR)
|
||||||
|
# libintl.bind_textdomain_codeset(APP, 'UTF-8')
|
||||||
|
# plugins_locale_dir = os.path.join(common.configpaths.gajimpaths[
|
||||||
|
# 'PLUGINS_USER'], 'locale').encode(locale.getpreferredencoding())
|
||||||
|
# libintl.bindtextdomain('gajim_plugins', plugins_locale_dir)
|
||||||
|
# libintl.bind_textdomain_codeset('gajim_plugins', 'UTF-8')
|
||||||
|
|
||||||
|
if Gtk.Widget.get_default_direction() == Gtk.TextDirection.RTL:
|
||||||
|
i18n.direction_mark = '\u200F'
|
||||||
|
|
||||||
|
from ctypes import CDLL
|
||||||
|
from ctypes.util import find_library
|
||||||
|
import platform
|
||||||
|
|
||||||
|
sysname = platform.system()
|
||||||
|
if sysname in ('Linux', 'FreeBSD', 'OpenBSD', 'NetBSD'):
|
||||||
|
libc = CDLL(find_library('c'))
|
||||||
|
|
||||||
|
# The constant defined in <linux/prctl.h> which is used to set the name
|
||||||
|
# of the process.
|
||||||
|
PR_SET_NAME = 15
|
||||||
|
|
||||||
|
if sysname == 'Linux':
|
||||||
|
libc.prctl(PR_SET_NAME, 'gajim')
|
||||||
|
elif sysname in ('FreeBSD', 'OpenBSD', 'NetBSD'):
|
||||||
|
libc.setproctitle('gajim')
|
||||||
|
|
||||||
|
# Seed the OpenSSL pseudo random number generator from file and initialize
|
||||||
|
if PYOPENSSL_PRNG_PRESENT:
|
||||||
|
self.rng_seed = gajim.gajimpaths['RNG_SEED']
|
||||||
|
# Seed from file
|
||||||
|
try:
|
||||||
|
OpenSSL.rand.load_file(self.rng_seed)
|
||||||
|
except TypeError:
|
||||||
|
OpenSSL.rand.load_file(self.rng_seed.encode('utf-8'))
|
||||||
|
crypto.add_entropy_sources_OpenSSL()
|
||||||
|
try:
|
||||||
|
OpenSSL.rand.write_file(self.rng_seed)
|
||||||
|
except TypeError:
|
||||||
|
OpenSSL.rand.write_file(self.rng_seed.encode('utf-8'))
|
||||||
|
|
||||||
|
def sigint_cb(num, stack):
|
||||||
|
print('SIGINT/SIGTERM received')
|
||||||
|
self.quit()
|
||||||
|
# ^C exits the application normally
|
||||||
|
signal.signal(signal.SIGINT, sigint_cb)
|
||||||
|
signal.signal(signal.SIGTERM, sigint_cb)
|
||||||
|
|
||||||
|
log.info("Encodings: d:%s, fs:%s, p:%s", sys.getdefaultencoding(),
|
||||||
|
sys.getfilesystemencoding(), locale.getpreferredencoding())
|
||||||
|
|
||||||
|
from gui_interface import Interface
|
||||||
|
self.interface = Interface()
|
||||||
|
self.interface.run(self)
|
||||||
|
|
||||||
|
def do_shutdown(self, *args):
|
||||||
|
Gtk.Application.do_shutdown(self)
|
||||||
|
# Save the entropy from OpenSSL PRNG
|
||||||
|
if PYOPENSSL_PRNG_PRESENT and self.rng_seed:
|
||||||
|
try:
|
||||||
|
OpenSSL.rand.write_file(self.rng_seed)
|
||||||
|
except TypeError:
|
||||||
|
OpenSSL.rand.write_file(self.rng_seed.encode('utf-8'))
|
||||||
|
# Shutdown GUI and save config
|
||||||
|
if hasattr(self.interface, 'roster') and self.interface.roster:
|
||||||
|
self.interface.roster.prepare_quit()
|
||||||
|
|
||||||
|
def do_command_line(self, command_line: Gio.ApplicationCommandLine) -> int:
|
||||||
|
Gtk.Application.do_command_line(self, command_line)
|
||||||
|
options = command_line.get_options_dict()
|
||||||
|
if options.contains('quiet'):
|
||||||
|
logging_helpers.set_quiet()
|
||||||
|
if options.contains('separate'):
|
||||||
|
self.profile_separation = True
|
||||||
|
if options.contains('verbose'):
|
||||||
|
logging_helpers.set_verbose()
|
||||||
|
if options.contains('profile'):
|
||||||
|
variant = options.lookup_value('profile')
|
||||||
|
self.profile = variant.get_string()
|
||||||
|
if options.contains('loglevel'):
|
||||||
|
variant = options.lookup_value('loglevel')
|
||||||
|
string = variant.get_string()
|
||||||
|
logging_helpers.set_loglevels(string)
|
||||||
|
if options.contains('config-path'):
|
||||||
|
variant = options.lookup_value('config-path')
|
||||||
|
self.config_path = variant.get_string()
|
||||||
|
self.activate()
|
||||||
|
return 0
|
|
@ -180,7 +180,6 @@ class ConfigPaths:
|
||||||
|
|
||||||
def init_profile(self, profile):
|
def init_profile(self, profile):
|
||||||
conffile = windowsify('config')
|
conffile = windowsify('config')
|
||||||
pidfile = windowsify('gajim')
|
|
||||||
secretsfile = windowsify('secrets')
|
secretsfile = windowsify('secrets')
|
||||||
pluginsconfdir = windowsify('pluginsconfig')
|
pluginsconfdir = windowsify('pluginsconfig')
|
||||||
certsdir = windowsify(u'certs')
|
certsdir = windowsify(u'certs')
|
||||||
|
@ -188,16 +187,13 @@ class ConfigPaths:
|
||||||
|
|
||||||
if len(profile) > 0:
|
if len(profile) > 0:
|
||||||
conffile += '.' + profile
|
conffile += '.' + profile
|
||||||
pidfile += '.' + profile
|
|
||||||
secretsfile += '.' + profile
|
secretsfile += '.' + profile
|
||||||
pluginsconfdir += '.' + profile
|
pluginsconfdir += '.' + profile
|
||||||
certsdir += u'.' + profile
|
certsdir += u'.' + profile
|
||||||
localcertsdir += u'.' + profile
|
localcertsdir += u'.' + profile
|
||||||
|
|
||||||
pidfile += '.pid'
|
|
||||||
self.add('SECRETS_FILE', TYPE_DATA, secretsfile)
|
self.add('SECRETS_FILE', TYPE_DATA, secretsfile)
|
||||||
self.add('MY_PEER_CERTS', TYPE_DATA, certsdir)
|
self.add('MY_PEER_CERTS', TYPE_DATA, certsdir)
|
||||||
self.add('PID_FILE', TYPE_CACHE, pidfile)
|
|
||||||
self.add('CONFIG_FILE', TYPE_CONFIG, conffile)
|
self.add('CONFIG_FILE', TYPE_CONFIG, conffile)
|
||||||
self.add('PLUGINS_CONFIG_DIR', TYPE_CONFIG, pluginsconfdir)
|
self.add('PLUGINS_CONFIG_DIR', TYPE_CONFIG, pluginsconfdir)
|
||||||
self.add('MY_CERT', TYPE_CONFIG, localcertsdir)
|
self.add('MY_CERT', TYPE_CONFIG, localcertsdir)
|
||||||
|
|
|
@ -52,10 +52,16 @@ from string import Template
|
||||||
from common.i18n import Q_
|
from common.i18n import Q_
|
||||||
from common.i18n import ngettext
|
from common.i18n import ngettext
|
||||||
|
|
||||||
|
if os.name == 'nt':
|
||||||
|
try:
|
||||||
|
HAS_WINSOUND = True
|
||||||
|
import winsound # windows-only built-in module for playing wav
|
||||||
|
except ImportError:
|
||||||
|
HAS_WINSOUND = False
|
||||||
|
print('Gajim is not able to playback sound because'
|
||||||
|
'pywin32 is missing', file=sys.stderr)
|
||||||
|
|
||||||
try:
|
try:
|
||||||
import winsound # windows-only built-in module for playing wav
|
|
||||||
import win32api
|
|
||||||
import win32con
|
|
||||||
import wave # posix-only fallback wav playback
|
import wave # posix-only fallback wav playback
|
||||||
import ossaudiodev as oss
|
import ossaudiodev as oss
|
||||||
except Exception:
|
except Exception:
|
||||||
|
@ -462,52 +468,6 @@ def get_output_of_command(command):
|
||||||
|
|
||||||
return output
|
return output
|
||||||
|
|
||||||
def get_windows_reg_env(varname, default=''):
|
|
||||||
r"""
|
|
||||||
Ask for paths commonly used but not exposed as ENVs in english Windows 2003
|
|
||||||
those are:
|
|
||||||
'AppData' = %USERPROFILE%\Application Data (also an ENV)
|
|
||||||
'Desktop' = %USERPROFILE%\Desktop
|
|
||||||
'Favorites' = %USERPROFILE%\Favorites
|
|
||||||
'NetHood' = %USERPROFILE%\ NetHood
|
|
||||||
'Personal' = D:\My Documents (PATH TO MY DOCUMENTS)
|
|
||||||
'PrintHood' = %USERPROFILE%\PrintHood
|
|
||||||
'Programs' = %USERPROFILE%\Start Menu\Programs
|
|
||||||
'Recent' = %USERPROFILE%\Recent
|
|
||||||
'SendTo' = %USERPROFILE%\SendTo
|
|
||||||
'Start Menu' = %USERPROFILE%\Start Menu
|
|
||||||
'Startup' = %USERPROFILE%\Start Menu\Programs\Startup
|
|
||||||
'Templates' = %USERPROFILE%\Templates
|
|
||||||
'My Pictures' = D:\My Documents\My Pictures
|
|
||||||
'Local Settings' = %USERPROFILE%\Local Settings
|
|
||||||
'Local AppData' = %USERPROFILE%\Local Settings\Application Data
|
|
||||||
'Cache' = %USERPROFILE%\Local Settings\Temporary Internet Files
|
|
||||||
'Cookies' = %USERPROFILE%\Cookies
|
|
||||||
'History' = %USERPROFILE%\Local Settings\History
|
|
||||||
"""
|
|
||||||
if os.name != 'nt':
|
|
||||||
return ''
|
|
||||||
|
|
||||||
val = default
|
|
||||||
try:
|
|
||||||
rkey = win32api.RegOpenKey(win32con.HKEY_CURRENT_USER,
|
|
||||||
r'Software\Microsoft\Windows\CurrentVersion\Explorer\User Shell Folders')
|
|
||||||
try:
|
|
||||||
val = str(win32api.RegQueryValueEx(rkey, varname)[0])
|
|
||||||
val = win32api.ExpandEnvironmentStrings(val) # expand using environ
|
|
||||||
except Exception:
|
|
||||||
pass
|
|
||||||
finally:
|
|
||||||
win32api.RegCloseKey(rkey)
|
|
||||||
return val
|
|
||||||
|
|
||||||
def get_documents_path():
|
|
||||||
if os.name == 'nt':
|
|
||||||
path = get_windows_reg_env('Personal')
|
|
||||||
else:
|
|
||||||
path = os.path.expanduser('~')
|
|
||||||
return path
|
|
||||||
|
|
||||||
def sanitize_filename(filename):
|
def sanitize_filename(filename):
|
||||||
"""
|
"""
|
||||||
Make sure the filename we will write does contain only acceptable and latin
|
Make sure the filename we will write does contain only acceptable and latin
|
||||||
|
@ -787,12 +747,12 @@ def play_sound_file(path_to_soundfile):
|
||||||
path_to_soundfile = check_soundfile_path(path_to_soundfile)
|
path_to_soundfile = check_soundfile_path(path_to_soundfile)
|
||||||
if path_to_soundfile is None:
|
if path_to_soundfile is None:
|
||||||
return
|
return
|
||||||
elif os.name == 'nt':
|
elif os.name == 'nt' and HAS_WINSOUND:
|
||||||
try:
|
try:
|
||||||
winsound.PlaySound(path_to_soundfile,
|
winsound.PlaySound(path_to_soundfile,
|
||||||
winsound.SND_FILENAME|winsound.SND_ASYNC)
|
winsound.SND_FILENAME|winsound.SND_ASYNC)
|
||||||
except Exception:
|
except Exception:
|
||||||
pass
|
log.exception('Sound Playback Error')
|
||||||
elif os.name == 'posix':
|
elif os.name == 'posix':
|
||||||
if gajim.config.get('soundplayer') == '':
|
if gajim.config.get('soundplayer') == '':
|
||||||
def _oss_play():
|
def _oss_play():
|
||||||
|
|
|
@ -43,10 +43,9 @@ from common import ged
|
||||||
|
|
||||||
import sqlite3 as sqlite
|
import sqlite3 as sqlite
|
||||||
|
|
||||||
from common import configpaths
|
LOG_DB_PATH = gajim.gajimpaths['LOG_DB']
|
||||||
LOG_DB_PATH = configpaths.gajimpaths['LOG_DB']
|
|
||||||
LOG_DB_FOLDER, LOG_DB_FILE = os.path.split(LOG_DB_PATH)
|
LOG_DB_FOLDER, LOG_DB_FILE = os.path.split(LOG_DB_PATH)
|
||||||
CACHE_DB_PATH = configpaths.gajimpaths['CACHE_DB']
|
CACHE_DB_PATH = gajim.gajimpaths['CACHE_DB']
|
||||||
|
|
||||||
import logging
|
import logging
|
||||||
log = logging.getLogger('gajim.c.logger')
|
log = logging.getLogger('gajim.c.logger')
|
||||||
|
|
|
@ -1495,7 +1495,7 @@ class FileChooserDialog(Gtk.FileChooserDialog):
|
||||||
if current_folder and os.path.isdir(current_folder):
|
if current_folder and os.path.isdir(current_folder):
|
||||||
self.set_current_folder(current_folder)
|
self.set_current_folder(current_folder)
|
||||||
else:
|
else:
|
||||||
self.set_current_folder(helpers.get_documents_path())
|
self.set_current_folder(os.path.expanduser('~'))
|
||||||
self.response_ok, self.response_cancel = \
|
self.response_ok, self.response_cancel = \
|
||||||
on_response_ok, on_response_cancel
|
on_response_ok, on_response_cancel
|
||||||
# in gtk+-2.10 clicked signal on some of the buttons in a dialog
|
# in gtk+-2.10 clicked signal on some of the buttons in a dialog
|
||||||
|
@ -5047,7 +5047,7 @@ class ArchiveChooserDialog(FileChooserDialog):
|
||||||
callback(path_to_file)
|
callback(path_to_file)
|
||||||
self.destroy()
|
self.destroy()
|
||||||
|
|
||||||
path = helpers.get_documents_path()
|
path = os.path.expanduser('~')
|
||||||
|
|
||||||
FileChooserDialog.__init__(self,
|
FileChooserDialog.__init__(self,
|
||||||
title_text=_('Choose Archive'),
|
title_text=_('Choose Archive'),
|
||||||
|
|
493
src/gajim.py
493
src/gajim.py
|
@ -35,24 +35,64 @@
|
||||||
## along with Gajim. If not, see <http://www.gnu.org/licenses/>.
|
## along with Gajim. If not, see <http://www.gnu.org/licenses/>.
|
||||||
##
|
##
|
||||||
|
|
||||||
import os
|
|
||||||
import sys
|
import sys
|
||||||
import warnings
|
import os
|
||||||
import OpenSSL
|
|
||||||
|
|
||||||
if os.name == 'nt':
|
if '--version' in sys.argv or '-V' in sys.argv:
|
||||||
|
from common.defs import version
|
||||||
|
print(version)
|
||||||
|
sys.exit(0)
|
||||||
|
|
||||||
|
WINDEV = False
|
||||||
|
if '--windev' in sys.argv or '-w' in sys.argv:
|
||||||
|
WINDEV = True
|
||||||
|
|
||||||
|
if os.name == 'nt' and not WINDEV:
|
||||||
|
import warnings
|
||||||
log_path = os.path.join(os.environ['APPDATA'], 'Gajim')
|
log_path = os.path.join(os.environ['APPDATA'], 'Gajim')
|
||||||
if not os.path.exists(log_path):
|
if not os.path.exists(log_path):
|
||||||
os.mkdir(log_path, 0o700)
|
os.mkdir(log_path, 0o700)
|
||||||
log_file = os.path.join(log_path, 'gajim.log')
|
log_file = os.path.join(log_path, 'gajim.log')
|
||||||
fout = open(log_file, 'a')
|
|
||||||
sys.stdout = fout
|
|
||||||
sys.stderr = fout
|
|
||||||
|
|
||||||
|
class MyStd(object):
|
||||||
|
_file = None
|
||||||
|
_error = None
|
||||||
|
|
||||||
|
def write(self, text):
|
||||||
|
if self._file is None and self._error is None:
|
||||||
|
try:
|
||||||
|
self._file = open(log_file, 'a')
|
||||||
|
except Exception as details:
|
||||||
|
self._error = details
|
||||||
|
if self._file is not None:
|
||||||
|
self._file.write(text)
|
||||||
|
self._file.flush()
|
||||||
|
|
||||||
|
def flush(self):
|
||||||
|
if self._file is not None:
|
||||||
|
self._file.flush()
|
||||||
|
|
||||||
|
def isatty(self):
|
||||||
|
return False
|
||||||
|
|
||||||
|
outerr = MyStd()
|
||||||
|
sys.stdout = outerr
|
||||||
|
sys.stderr = outerr
|
||||||
warnings.filterwarnings(action='ignore')
|
warnings.filterwarnings(action='ignore')
|
||||||
|
|
||||||
|
|
||||||
|
# Test here for all required versions so we dont have to
|
||||||
|
# test multiple times in every module. nbxmpp also needs GLib.
|
||||||
|
import gi
|
||||||
|
gi.require_version('GLib', '2.0')
|
||||||
|
gi.require_version('Gio', '2.0')
|
||||||
|
gi.require_version('Gtk', '3.0')
|
||||||
|
gi.require_version('Gdk', '3.0')
|
||||||
|
gi.require_version('GObject', '2.0')
|
||||||
|
gi.require_version('Pango', '1.0')
|
||||||
|
|
||||||
MIN_NBXMPP_VER = "0.5.3"
|
MIN_NBXMPP_VER = "0.5.3"
|
||||||
from gi.repository import GLib
|
|
||||||
try:
|
try:
|
||||||
import nbxmpp
|
import nbxmpp
|
||||||
except ImportError:
|
except ImportError:
|
||||||
|
@ -64,438 +104,7 @@ if V(nbxmpp.__version__) < V(MIN_NBXMPP_VER):
|
||||||
print('Gajim needs python-nbxmpp >= %s to run. Quiting...' % MIN_NBXMPP_VER)
|
print('Gajim needs python-nbxmpp >= %s to run. Quiting...' % MIN_NBXMPP_VER)
|
||||||
sys.exit(1)
|
sys.exit(1)
|
||||||
|
|
||||||
if os.name == 'nt':
|
from application import GajimApplication
|
||||||
import locale
|
|
||||||
import gettext
|
|
||||||
APP = 'gajim'
|
|
||||||
DIR = '../po'
|
|
||||||
lang, enc = locale.getdefaultlocale()
|
|
||||||
os.environ['LANG'] = lang
|
|
||||||
gettext.bindtextdomain(APP, DIR)
|
|
||||||
gettext.textdomain(APP)
|
|
||||||
gettext.install(APP, DIR)
|
|
||||||
|
|
||||||
# locale.setlocale(locale.LC_ALL, '')
|
app = GajimApplication()
|
||||||
# import ctypes
|
app.run(sys.argv)
|
||||||
# import ctypes.util
|
|
||||||
# libintl_path = ctypes.util.find_library('intl')
|
|
||||||
# if libintl_path == None:
|
|
||||||
# local_intl = os.path.join('gtk', 'bin', 'intl.dll')
|
|
||||||
# if os.path.exists(local_intl):
|
|
||||||
# libintl_path = local_intl
|
|
||||||
# if libintl_path == None:
|
|
||||||
# raise ImportError('intl.dll library not found')
|
|
||||||
# libintl = ctypes.cdll.LoadLibrary(libintl_path)
|
|
||||||
# libintl.bindtextdomain(APP, DIR)
|
|
||||||
# libintl.bind_textdomain_codeset(APP, 'UTF-8')
|
|
||||||
|
|
||||||
if os.name == 'nt':
|
|
||||||
# needed for docutils
|
|
||||||
sys.path.append('.')
|
|
||||||
|
|
||||||
from common import logging_helpers
|
|
||||||
logging_helpers.init(sys.stderr.isatty())
|
|
||||||
|
|
||||||
import logging
|
|
||||||
# gajim.gui or gajim.gtk more appropriate ?
|
|
||||||
log = logging.getLogger('gajim.gajim')
|
|
||||||
|
|
||||||
import gi
|
|
||||||
gi.require_version('Gtk', '3.0')
|
|
||||||
gi.require_version('Gdk', '3.0')
|
|
||||||
gi.require_version('GObject', '2.0')
|
|
||||||
gi.require_version('Pango', '1.0')
|
|
||||||
|
|
||||||
import getopt
|
|
||||||
from common import i18n
|
|
||||||
|
|
||||||
def parseOpts():
|
|
||||||
profile_ = ''
|
|
||||||
config_path_ = None
|
|
||||||
profile_separation_ = False
|
|
||||||
|
|
||||||
try:
|
|
||||||
shortargs = 'hqsvl:p:c:'
|
|
||||||
# add gtk/gnome session option as gtk_get_option_group is not wrapped
|
|
||||||
longargs = 'help quiet separate verbose loglevel= profile= config-path='
|
|
||||||
longargs += ' class= name= screen= gtk-module= sync g-fatal-warnings'
|
|
||||||
longargs += ' sm-client-id= sm-client-state-file= sm-disable'
|
|
||||||
opts = getopt.getopt(sys.argv[1:], shortargs, longargs.split())[0]
|
|
||||||
except getopt.error as msg1:
|
|
||||||
print(str(msg1))
|
|
||||||
print('for help use --help')
|
|
||||||
sys.exit(2)
|
|
||||||
for o, a in opts:
|
|
||||||
if o in ('-h', '--help'):
|
|
||||||
out = _('Usage:') + \
|
|
||||||
'\n gajim [options] filename\n\n' + \
|
|
||||||
_('Options:') + \
|
|
||||||
'\n -h, --help ' + \
|
|
||||||
_('Show this help message and exit') + \
|
|
||||||
'\n -q, --quiet ' + \
|
|
||||||
_('Show only critical errors') + \
|
|
||||||
'\n -s, --separate ' + \
|
|
||||||
_('Separate profile files completely (even history db and plugins)') + \
|
|
||||||
'\n -v, --verbose ' + \
|
|
||||||
_('Print xml stanzas and other debug information') + \
|
|
||||||
'\n -p, --profile ' + \
|
|
||||||
_('Use defined profile in configuration directory') + \
|
|
||||||
'\n -c, --config-path ' + \
|
|
||||||
_('Set configuration directory') + \
|
|
||||||
'\n -l, --loglevel ' + \
|
|
||||||
_('Configure logging system') + '\n'
|
|
||||||
print(out)
|
|
||||||
sys.exit()
|
|
||||||
elif o in ('-q', '--quiet'):
|
|
||||||
logging_helpers.set_quiet()
|
|
||||||
elif o in ('-s', '--separate'):
|
|
||||||
profile_separation_ = True
|
|
||||||
elif o in ('-v', '--verbose'):
|
|
||||||
logging_helpers.set_verbose()
|
|
||||||
elif o in ('-p', '--profile'): # gajim --profile name
|
|
||||||
profile_ = a
|
|
||||||
elif o in ('-l', '--loglevel'):
|
|
||||||
logging_helpers.set_loglevels(a)
|
|
||||||
elif o in ('-c', '--config-path'):
|
|
||||||
config_path_ = a
|
|
||||||
return profile_, config_path_, profile_separation_
|
|
||||||
|
|
||||||
import locale
|
|
||||||
profile, config_path, profile_separation = parseOpts()
|
|
||||||
del parseOpts
|
|
||||||
|
|
||||||
import common.configpaths
|
|
||||||
common.configpaths.gajimpaths.init(config_path, profile, profile_separation)
|
|
||||||
del config_path
|
|
||||||
del profile
|
|
||||||
|
|
||||||
if os.name == 'nt':
|
|
||||||
plugins_locale_dir = os.path.join(common.configpaths.gajimpaths[
|
|
||||||
'PLUGINS_USER'], 'locale').encode(locale.getpreferredencoding())
|
|
||||||
# libintl.bindtextdomain('gajim_plugins', plugins_locale_dir)
|
|
||||||
# libintl.bind_textdomain_codeset('gajim_plugins', 'UTF-8')
|
|
||||||
|
|
||||||
class MyStderr(object):
|
|
||||||
_file = None
|
|
||||||
_error = None
|
|
||||||
def write(self, text):
|
|
||||||
fname = os.path.join(common.configpaths.gajimpaths.cache_root,
|
|
||||||
os.path.split(sys.executable)[1]+'.log')
|
|
||||||
if self._file is None and self._error is None:
|
|
||||||
try:
|
|
||||||
self._file = open(fname, 'a')
|
|
||||||
except Exception as details:
|
|
||||||
self._error = details
|
|
||||||
if self._file is not None:
|
|
||||||
self._file.write(text)
|
|
||||||
self._file.flush()
|
|
||||||
def flush(self):
|
|
||||||
if self._file is not None:
|
|
||||||
self._file.flush()
|
|
||||||
|
|
||||||
sys.stderr = MyStderr()
|
|
||||||
|
|
||||||
# PyGTK2.10+ only throws a warning
|
|
||||||
warnings.filterwarnings('error', module='Gtk')
|
|
||||||
try:
|
|
||||||
from gi.repository import GObject
|
|
||||||
GObject.set_prgname('gajim')
|
|
||||||
from gi.repository import Gtk
|
|
||||||
from gi.repository import Gdk
|
|
||||||
from gi.repository import GLib
|
|
||||||
except Warning as msg2:
|
|
||||||
if str(msg2) == 'could not open display':
|
|
||||||
print(_('Gajim needs X server to run. Quiting...'), file=sys.stderr)
|
|
||||||
else:
|
|
||||||
print(_('importing PyGTK failed: %s') % str(msg2), file=sys.stderr)
|
|
||||||
sys.exit()
|
|
||||||
warnings.resetwarnings()
|
|
||||||
|
|
||||||
|
|
||||||
if os.name == 'nt':
|
|
||||||
warnings.filterwarnings(action='ignore')
|
|
||||||
|
|
||||||
if Gtk.Widget.get_default_direction() == Gtk.TextDirection.RTL:
|
|
||||||
i18n.direction_mark = '\u200F'
|
|
||||||
pritext = ''
|
|
||||||
|
|
||||||
from common import exceptions
|
|
||||||
try:
|
|
||||||
from common import gajim
|
|
||||||
except exceptions.DatabaseMalformed:
|
|
||||||
pritext = _('Database Error')
|
|
||||||
sectext = _('The database file (%s) cannot be read. Try to repair it (see '
|
|
||||||
'http://trac.gajim.org/wiki/DatabaseBackup) or remove it (all history '
|
|
||||||
'will be lost).') % common.logger.LOG_DB_PATH
|
|
||||||
else:
|
|
||||||
from common import logger
|
|
||||||
gajim.logger = logger.Logger()
|
|
||||||
from common import caps_cache
|
|
||||||
caps_cache.initialize(gajim.logger)
|
|
||||||
from common import dbus_support
|
|
||||||
if dbus_support.supported:
|
|
||||||
from music_track_listener import MusicTrackListener
|
|
||||||
|
|
||||||
from ctypes import CDLL
|
|
||||||
from ctypes.util import find_library
|
|
||||||
import platform
|
|
||||||
|
|
||||||
sysname = platform.system()
|
|
||||||
if sysname in ('Linux', 'FreeBSD', 'OpenBSD', 'NetBSD'):
|
|
||||||
libc = CDLL(find_library('c'))
|
|
||||||
|
|
||||||
# The constant defined in <linux/prctl.h> which is used to set the name
|
|
||||||
# of the process.
|
|
||||||
PR_SET_NAME = 15
|
|
||||||
|
|
||||||
if sysname == 'Linux':
|
|
||||||
libc.prctl(PR_SET_NAME, 'gajim')
|
|
||||||
elif sysname in ('FreeBSD', 'OpenBSD', 'NetBSD'):
|
|
||||||
libc.setproctitle('gajim')
|
|
||||||
|
|
||||||
# if Gtk.pygtk_version < (2, 22, 0):
|
|
||||||
# pritext = _('Gajim needs PyGTK 2.22 or above')
|
|
||||||
# sectext = _('Gajim needs PyGTK 2.22 or above to run. Quiting...')
|
|
||||||
# elif Gtk.gtk_version < (2, 22, 0):
|
|
||||||
# if (Gtk.get_major_version(), Gtk.get_minor_version(),
|
|
||||||
# Gtk.get_micro_version()) < (2, 22, 0):
|
|
||||||
# pritext = _('Gajim needs GTK 2.22 or above')
|
|
||||||
# sectext = _('Gajim needs GTK 2.22 or above to run. Quiting...')
|
|
||||||
|
|
||||||
from common import check_paths
|
|
||||||
|
|
||||||
if os.name == 'nt':
|
|
||||||
try:
|
|
||||||
import winsound # windows-only built-in module for playing wav
|
|
||||||
import win32api # do NOT remove. we req this module
|
|
||||||
except Exception:
|
|
||||||
pritext = _('Gajim needs pywin32 to run')
|
|
||||||
sectext = _('Please make sure that Pywin32 is installed on your '
|
|
||||||
'system. You can get it at %s') % \
|
|
||||||
'http://sourceforge.net/project/showfiles.php?group_id=78018'
|
|
||||||
|
|
||||||
if pritext:
|
|
||||||
dlg = Gtk.MessageDialog(None,
|
|
||||||
Gtk.DialogFlags.DESTROY_WITH_PARENT | Gtk.DialogFlags.MODAL,
|
|
||||||
Gtk.MessageType.ERROR, Gtk.ButtonsType.OK, message_format = pritext)
|
|
||||||
|
|
||||||
dlg.format_secondary_text(sectext)
|
|
||||||
dlg.run()
|
|
||||||
dlg.destroy()
|
|
||||||
sys.exit()
|
|
||||||
|
|
||||||
del pritext
|
|
||||||
|
|
||||||
#import gtkexcepthook
|
|
||||||
|
|
||||||
import signal
|
|
||||||
import gtkgui_helpers
|
|
||||||
|
|
||||||
gajimpaths = common.configpaths.gajimpaths
|
|
||||||
|
|
||||||
pid_filename = gajimpaths['PID_FILE']
|
|
||||||
config_filename = gajimpaths['CONFIG_FILE']
|
|
||||||
|
|
||||||
# Seed the OpenSSL pseudo random number generator from file and initialize
|
|
||||||
RNG_SEED = gajimpaths['RNG_SEED']
|
|
||||||
PYOPENSSL_PRNG_PRESENT = False
|
|
||||||
try:
|
|
||||||
import OpenSSL.rand
|
|
||||||
from common import crypto
|
|
||||||
PYOPENSSL_PRNG_PRESENT = True
|
|
||||||
# Seed from file
|
|
||||||
try:
|
|
||||||
OpenSSL.rand.load_file(RNG_SEED)
|
|
||||||
except TypeError:
|
|
||||||
OpenSSL.rand.load_file(RNG_SEED.encode('utf-8'))
|
|
||||||
crypto.add_entropy_sources_OpenSSL()
|
|
||||||
try:
|
|
||||||
OpenSSL.rand.write_file(RNG_SEED)
|
|
||||||
except TypeError:
|
|
||||||
OpenSSL.rand.write_file(RNG_SEED.encode('utf-8'))
|
|
||||||
except ImportError:
|
|
||||||
log.info("PyOpenSSL PRNG not available")
|
|
||||||
|
|
||||||
import traceback
|
|
||||||
import errno
|
|
||||||
import dialogs
|
|
||||||
|
|
||||||
def pid_alive():
|
|
||||||
try:
|
|
||||||
pf = open(pid_filename)
|
|
||||||
except IOError:
|
|
||||||
# probably file not found
|
|
||||||
return False
|
|
||||||
|
|
||||||
try:
|
|
||||||
pid = int(pf.read().strip())
|
|
||||||
pf.close()
|
|
||||||
except Exception:
|
|
||||||
traceback.print_exc()
|
|
||||||
# PID file exists, but something happened trying to read PID
|
|
||||||
# Could be 0.10 style empty PID file, so assume Gajim is running
|
|
||||||
return True
|
|
||||||
|
|
||||||
if os.name == 'nt':
|
|
||||||
try:
|
|
||||||
from ctypes import (windll, c_ulong, c_int, Structure, c_char)
|
|
||||||
from ctypes import (POINTER, pointer, sizeof)
|
|
||||||
except Exception:
|
|
||||||
return True
|
|
||||||
|
|
||||||
class PROCESSENTRY32(Structure):
|
|
||||||
_fields_ = [
|
|
||||||
('dwSize', c_ulong, ),
|
|
||||||
('cntUsage', c_ulong, ),
|
|
||||||
('th32ProcessID', c_ulong, ),
|
|
||||||
('th32DefaultHeapID', c_ulong, ),
|
|
||||||
('th32ModuleID', c_ulong, ),
|
|
||||||
('cntThreads', c_ulong, ),
|
|
||||||
('th32ParentProcessID', c_ulong, ),
|
|
||||||
('pcPriClassBase', c_ulong, ),
|
|
||||||
('dwFlags', c_ulong, ),
|
|
||||||
('szExeFile', c_char*512, ),
|
|
||||||
]
|
|
||||||
|
|
||||||
kernel = windll.kernel32
|
|
||||||
kernel.CreateToolhelp32Snapshot.argtypes = c_ulong, c_ulong,
|
|
||||||
kernel.CreateToolhelp32Snapshot.restype = c_int
|
|
||||||
kernel.Process32First.argtypes = c_int, POINTER(PROCESSENTRY32),
|
|
||||||
kernel.Process32First.restype = c_int
|
|
||||||
kernel.Process32Next.argtypes = c_int, POINTER(PROCESSENTRY32),
|
|
||||||
kernel.Process32Next.restype = c_int
|
|
||||||
|
|
||||||
def get_p(pid_):
|
|
||||||
TH32CS_SNAPPROCESS = 2
|
|
||||||
CreateToolhelp32Snapshot = kernel.CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0)
|
|
||||||
assert CreateToolhelp32Snapshot > 0, 'CreateToolhelp32Snapshot failed'
|
|
||||||
pe32 = PROCESSENTRY32()
|
|
||||||
pe32.dwSize = sizeof( PROCESSENTRY32 )
|
|
||||||
f3 = kernel.Process32First(CreateToolhelp32Snapshot, pointer(pe32))
|
|
||||||
while f3:
|
|
||||||
if pe32.th32ProcessID == pid_:
|
|
||||||
return pe32.szExeFile
|
|
||||||
f3 = kernel.Process32Next(CreateToolhelp32Snapshot, pointer(pe32))
|
|
||||||
|
|
||||||
if get_p(pid) in ('python.exe', 'gajim.exe'):
|
|
||||||
return True
|
|
||||||
return False
|
|
||||||
try:
|
|
||||||
if not os.path.exists('/proc'):
|
|
||||||
return True # no /proc, assume Gajim is running
|
|
||||||
|
|
||||||
try:
|
|
||||||
f1 = open('/proc/%d/cmdline'% pid)
|
|
||||||
except IOError as e1:
|
|
||||||
if e1.errno == errno.ENOENT:
|
|
||||||
return False # file/pid does not exist
|
|
||||||
raise
|
|
||||||
|
|
||||||
n = f1.read().lower()
|
|
||||||
f1.close()
|
|
||||||
if n.find('gajim') < 0:
|
|
||||||
return False
|
|
||||||
return True # Running Gajim found at pid
|
|
||||||
except Exception:
|
|
||||||
traceback.print_exc()
|
|
||||||
|
|
||||||
# If we are here, pidfile exists, but some unexpected error occured.
|
|
||||||
# Assume Gajim is running.
|
|
||||||
return True
|
|
||||||
|
|
||||||
def show_remote_gajim_roster():
|
|
||||||
try:
|
|
||||||
import dbus
|
|
||||||
|
|
||||||
OBJ_PATH = '/org/gajim/dbus/RemoteObject'
|
|
||||||
INTERFACE = 'org.gajim.dbus.RemoteInterface'
|
|
||||||
SERVICE = 'org.gajim.dbus'
|
|
||||||
|
|
||||||
# Attempt to call show_roster
|
|
||||||
dbus.Interface(dbus.SessionBus().get_object(SERVICE, OBJ_PATH), INTERFACE).__getattr__("show_roster")()
|
|
||||||
|
|
||||||
return True
|
|
||||||
except Exception:
|
|
||||||
return False
|
|
||||||
|
|
||||||
if pid_alive():
|
|
||||||
if (show_remote_gajim_roster()):
|
|
||||||
print("Gajim is already running, bringing the roster to front...")
|
|
||||||
sys.exit(0)
|
|
||||||
pixs = []
|
|
||||||
for size in (16, 32, 48, 64, 128):
|
|
||||||
pix = gtkgui_helpers.get_icon_pixmap('gajim', size)
|
|
||||||
if pix:
|
|
||||||
pixs.append(pix)
|
|
||||||
if pixs:
|
|
||||||
# set the icon to all windows
|
|
||||||
Gtk.Window.set_default_icon_list(pixs)
|
|
||||||
pritext = _('Gajim is already running')
|
|
||||||
sectext = _('Another instance of Gajim seems to be running\nRun anyway?')
|
|
||||||
dialog = dialogs.YesNoDialog(pritext, sectext)
|
|
||||||
dialog.popup()
|
|
||||||
if dialog.run() != Gtk.ResponseType.YES:
|
|
||||||
sys.exit(3)
|
|
||||||
dialog.destroy()
|
|
||||||
# run anyway, delete pid and useless global vars
|
|
||||||
if os.path.exists(pid_filename):
|
|
||||||
os.remove(pid_filename)
|
|
||||||
del pix
|
|
||||||
del pritext
|
|
||||||
del sectext
|
|
||||||
dialog.destroy()
|
|
||||||
|
|
||||||
# Create .gajim dir
|
|
||||||
pid_dir = os.path.dirname(pid_filename)
|
|
||||||
if not os.path.exists(pid_dir):
|
|
||||||
check_paths.create_path(pid_dir)
|
|
||||||
# Create pid file
|
|
||||||
try:
|
|
||||||
f2 = open(pid_filename, 'w')
|
|
||||||
f2.write(str(os.getpid()))
|
|
||||||
f2.close()
|
|
||||||
except IOError as e2:
|
|
||||||
dlg = dialogs.ErrorDialog(_('Disk Write Error'), str(e2))
|
|
||||||
dlg.run()
|
|
||||||
dlg.destroy()
|
|
||||||
sys.exit()
|
|
||||||
del pid_dir
|
|
||||||
|
|
||||||
def on_exit():
|
|
||||||
# Save the entropy from OpenSSL PRNG
|
|
||||||
if PYOPENSSL_PRNG_PRESENT:
|
|
||||||
try:
|
|
||||||
OpenSSL.rand.write_file(RNG_SEED)
|
|
||||||
except TypeError:
|
|
||||||
OpenSSL.rand.write_file(RNG_SEED.encode('utf-8'))
|
|
||||||
# delete pid file on normal exit
|
|
||||||
if os.path.exists(pid_filename):
|
|
||||||
os.remove(pid_filename)
|
|
||||||
# Shutdown GUI and save config
|
|
||||||
if hasattr(gajim.interface, 'roster') and gajim.interface.roster:
|
|
||||||
gajim.interface.roster.prepare_quit()
|
|
||||||
|
|
||||||
import atexit
|
|
||||||
atexit.register(on_exit)
|
|
||||||
|
|
||||||
from gui_interface import Interface
|
|
||||||
|
|
||||||
if __name__.endswith('__main__'):
|
|
||||||
def sigint_cb(num, stack):
|
|
||||||
sys.exit(5)
|
|
||||||
# ^C exits the application normally to delete pid file
|
|
||||||
signal.signal(signal.SIGINT, sigint_cb)
|
|
||||||
signal.signal(signal.SIGTERM, sigint_cb)
|
|
||||||
|
|
||||||
log.info("Encodings: d:%s, fs:%s, p:%s", sys.getdefaultencoding(), \
|
|
||||||
sys.getfilesystemencoding(), locale.getpreferredencoding())
|
|
||||||
|
|
||||||
check_paths.check_and_possibly_create_paths()
|
|
||||||
|
|
||||||
interface = Interface()
|
|
||||||
interface.run()
|
|
||||||
|
|
||||||
try:
|
|
||||||
Gtk.main()
|
|
||||||
except KeyboardInterrupt:
|
|
||||||
print('KeyboardInterrupt', file=sys.stderr)
|
|
||||||
|
|
|
@ -2719,11 +2719,11 @@ class Interface:
|
||||||
view.updateNamespace({'gajim': gajim})
|
view.updateNamespace({'gajim': gajim})
|
||||||
gajim.ipython_window = window
|
gajim.ipython_window = window
|
||||||
|
|
||||||
def run(self):
|
def run(self, app):
|
||||||
if gajim.config.get('trayicon') != 'never':
|
if gajim.config.get('trayicon') != 'never':
|
||||||
self.show_systray()
|
self.show_systray()
|
||||||
|
|
||||||
self.roster = roster_window.RosterWindow()
|
self.roster = roster_window.RosterWindow(app)
|
||||||
if self.msg_win_mgr.mode == \
|
if self.msg_win_mgr.mode == \
|
||||||
MessageWindowMgr.ONE_MSG_WINDOW_ALWAYS_WITH_ROSTER:
|
MessageWindowMgr.ONE_MSG_WINDOW_ALWAYS_WITH_ROSTER:
|
||||||
self.msg_win_mgr.create_window(None, None, None)
|
self.msg_win_mgr.create_window(None, None, None)
|
||||||
|
|
|
@ -94,7 +94,7 @@ empty_pixbuf = GdkPixbuf.Pixbuf.new(GdkPixbuf.Colorspace.RGB, True, 8, 1, 1)
|
||||||
empty_pixbuf.fill(0xffffff00)
|
empty_pixbuf.fill(0xffffff00)
|
||||||
|
|
||||||
|
|
||||||
class RosterWindow:
|
class RosterWindow(Gtk.ApplicationWindow):
|
||||||
"""
|
"""
|
||||||
Class for main window of the GTK+ interface
|
Class for main window of the GTK+ interface
|
||||||
"""
|
"""
|
||||||
|
@ -2479,7 +2479,7 @@ class RosterWindow:
|
||||||
When we quit the gtk interface - exit gtk
|
When we quit the gtk interface - exit gtk
|
||||||
"""
|
"""
|
||||||
self.prepare_quit()
|
self.prepare_quit()
|
||||||
Gtk.main_quit()
|
self.application.quit()
|
||||||
|
|
||||||
def on_quit_request(self, widget=None):
|
def on_quit_request(self, widget=None):
|
||||||
"""
|
"""
|
||||||
|
@ -6178,7 +6178,8 @@ class RosterWindow:
|
||||||
###
|
###
|
||||||
################################################################################
|
################################################################################
|
||||||
|
|
||||||
def __init__(self):
|
def __init__(self, app):
|
||||||
|
self.application = app
|
||||||
self.filtering = False
|
self.filtering = False
|
||||||
self.starting = False
|
self.starting = False
|
||||||
self.starting_filtering = False
|
self.starting_filtering = False
|
||||||
|
@ -6195,6 +6196,7 @@ class RosterWindow:
|
||||||
self.xml = gtkgui_helpers.get_gtk_builder('roster_window.ui')
|
self.xml = gtkgui_helpers.get_gtk_builder('roster_window.ui')
|
||||||
self.window = self.xml.get_object('roster_window')
|
self.window = self.xml.get_object('roster_window')
|
||||||
self.hpaned = self.xml.get_object('roster_hpaned')
|
self.hpaned = self.xml.get_object('roster_hpaned')
|
||||||
|
self.window.set_application(app)
|
||||||
gajim.interface.msg_win_mgr = MessageWindowMgr(self.window, self.hpaned)
|
gajim.interface.msg_win_mgr = MessageWindowMgr(self.window, self.hpaned)
|
||||||
gajim.interface.msg_win_mgr.connect('window-delete',
|
gajim.interface.msg_win_mgr.connect('window-delete',
|
||||||
self.on_message_window_delete)
|
self.on_message_window_delete)
|
||||||
|
|
Loading…
Add table
Reference in a new issue