Move startup code into Gtk.Application()
This commit is contained in:
		
							parent
							
								
									9d2223ea3b
								
							
						
					
					
						commit
						e7812cbd85
					
				
					 4 changed files with 372 additions and 380 deletions
				
			
		|  | @ -18,8 +18,16 @@ | |||
| ## along with Gajim. If not, see <http://www.gnu.org/licenses/>. | ||||
| ## | ||||
| 
 | ||||
| import sys | ||||
| import os | ||||
| import warnings | ||||
| import logging | ||||
| from gi.repository import GLib, Gio, Gtk | ||||
| from common import i18n | ||||
| from common import logging_helpers | ||||
| logging_helpers.init(sys.stderr.isatty()) | ||||
| 
 | ||||
| log = logging.getLogger('gajim.gajim') | ||||
| 
 | ||||
| 
 | ||||
| class GajimApplication(Gtk.Application): | ||||
|  | @ -63,6 +71,363 @@ class GajimApplication(Gtk.Application): | |||
|     def do_activate(self): | ||||
|         Gtk.Application.do_activate(self) | ||||
| 
 | ||||
|         if os.name == 'nt': | ||||
|             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, '') | ||||
|         #    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') | ||||
| 
 | ||||
|         if os.name == 'nt': | ||||
|             # needed for docutils | ||||
|             sys.path.append('.') | ||||
| 
 | ||||
|         import locale | ||||
| 
 | ||||
|         import common.configpaths | ||||
|         common.configpaths.gajimpaths.init( | ||||
|             self.config_path, self.profile, self.profile_separation) | ||||
| 
 | ||||
|         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') | ||||
|         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 | ||||
| 
 | ||||
|         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(self) | ||||
| 
 | ||||
| 
 | ||||
|     def do_command_line(self, command_line: Gio.ApplicationCommandLine) -> int: | ||||
|         Gtk.Application.do_command_line(self, command_line) | ||||
|         options = command_line.get_options_dict() | ||||
|  |  | |||
							
								
								
									
										375
									
								
								src/gajim.py
									
										
									
									
									
								
							
							
						
						
									
										375
									
								
								src/gajim.py
									
										
									
									
									
								
							|  | @ -44,7 +44,6 @@ if '--version' in sys.argv or '-V' in sys.argv: | |||
| 
 | ||||
| import os | ||||
| import warnings | ||||
| import OpenSSL | ||||
| 
 | ||||
| if os.name == 'nt': | ||||
|     log_path = os.path.join(os.environ['APPDATA'], 'Gajim') | ||||
|  | @ -80,381 +79,7 @@ if V(nbxmpp.__version__) < V(MIN_NBXMPP_VER): | |||
|     print('Gajim needs python-nbxmpp >= %s to run. Quiting...' % MIN_NBXMPP_VER) | ||||
|     sys.exit(1) | ||||
| 
 | ||||
| if os.name == 'nt': | ||||
|     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, '') | ||||
| #    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') | ||||
| 
 | ||||
| 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') | ||||
| 
 | ||||
| 
 | ||||
| from common import i18n | ||||
| import locale | ||||
| from application import GajimApplication | ||||
| 
 | ||||
| app = GajimApplication() | ||||
| app.run(sys.argv) | ||||
| 
 | ||||
| import common.configpaths | ||||
| common.configpaths.gajimpaths.init( | ||||
|     app.config_path, app.profile, app.profile_separation) | ||||
| 
 | ||||
| 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}) | ||||
|         gajim.ipython_window = window | ||||
| 
 | ||||
|     def run(self): | ||||
|     def run(self, app): | ||||
|         if gajim.config.get('trayicon') != 'never': | ||||
|             self.show_systray() | ||||
| 
 | ||||
|         self.roster = roster_window.RosterWindow() | ||||
|         self.roster = roster_window.RosterWindow(app) | ||||
|         if self.msg_win_mgr.mode == \ | ||||
|         MessageWindowMgr.ONE_MSG_WINDOW_ALWAYS_WITH_ROSTER: | ||||
|             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) | ||||
| 
 | ||||
| 
 | ||||
| class RosterWindow: | ||||
| class RosterWindow(Gtk.ApplicationWindow): | ||||
|     """ | ||||
|     Class for main window of the GTK+ interface | ||||
|     """ | ||||
|  | @ -2479,7 +2479,7 @@ class RosterWindow: | |||
|         When we quit the gtk interface - exit gtk | ||||
|         """ | ||||
|         self.prepare_quit() | ||||
|         Gtk.main_quit() | ||||
|         self.application.quit() | ||||
| 
 | ||||
|     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.starting = False | ||||
|         self.starting_filtering = False | ||||
|  | @ -6195,6 +6196,7 @@ class RosterWindow: | |||
|         self.xml = gtkgui_helpers.get_gtk_builder('roster_window.ui') | ||||
|         self.window = self.xml.get_object('roster_window') | ||||
|         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.connect('window-delete', | ||||
|             self.on_message_window_delete) | ||||
|  |  | |||
		Loading…
	
	Add table
		
		Reference in a new issue