This is an automated email from the git hooks/post-receive script. x2go pushed a commit to branch brokerclient in repository pyhoca-gui. commit 7bd3d3ac9e41d4b43a6b9073297611f2b77969fd Author: Mike Gabriel <mike.gabriel@das-netzwerkteam.de> Date: Wed Feb 5 09:32:54 2014 +0100 Move most code of the pyhoca-gui executable into a dedicated class named PyHocaGUI_Launcher. --- debian/changelog | 2 + pyhoca-gui | 403 ++-------------------------------------------- pyhoca/wxgui/__init__.py | 1 + pyhoca/wxgui/launcher.py | 335 ++++++++++++++++++++++++++++++++++++++ pyhoca/wxgui/options.py | 109 +++++++++++++ 5 files changed, 457 insertions(+), 393 deletions(-) diff --git a/debian/changelog b/debian/changelog index 9f1bbaf..86beb5d 100644 --- a/debian/changelog +++ b/debian/changelog @@ -1,6 +1,8 @@ pyhoca-gui (0.5.0.0-0x2go1) UNRELEASED; urgency=low * Adapt to new backend concept found in Python X2Go (>= 0.5.0.0). + * Move most code of the pyhoca-gui executable into a dedicated class + named PyHocaGUI_Launcher. -- Mike Gabriel <mike.gabriel@das-netzwerkteam.de> Wed, 08 Jan 2014 21:28:37 +0100 diff --git a/pyhoca-gui b/pyhoca-gui index e22fd18..cd6bcf4 100755 --- a/pyhoca-gui +++ b/pyhoca-gui @@ -19,403 +19,20 @@ # Free Software Foundation, Inc., # 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. -modules ={} - -import sys import os -import re -import shutil -PROG_NAME = os.path.basename(sys.argv[0]).replace('.exe', '') -PROG_PID = os.getpid() - -if hasattr(sys, 'frozen') and str(sys.frozen) in ("windows_exe", "console_exe", "1", ): - class Win32_Logging(object): - - softspace = 0 - _fname = os.path.join(os.environ['AppData'], PROG_NAME, '%s.log' % PROG_NAME) - _file = None - - def __init__(self, filemode='a'): - self._filemode = filemode - if os.path.isfile(self._fname) and self._filemode == "w+": - os.remove(self._fname) - - def write(self, text, **kwargs): - if self._file is None: - try: - try: - os.mkdir(os.path.dirname(self._fname)) - except: - pass - self._file = open(self._fname, self._filemode) - except: - pass - else: - self._file.write(text) - self._file.flush() - - def flush(self): - if self._file is not None: - self._file.flush() - - sys.stdout = Win32_Logging(filemode='w+') - sys.stderr = Win32_Logging(filemode='a') - del Win32_Logging - -import gevent -import gevent.monkey -gevent.monkey.patch_all() - -import subprocess - -try: - import wxversion - wxversion.select('2.9') -except: pass -try: - import wxversion - wxversion.select('2.8') -except: pass - -import argparse -import os -import exceptions -import locale -import gettext -import wx - -from x2go import X2GOCLIENT_OS as _X2GOCLIENT_OS - -if _X2GOCLIENT_OS in ('Linux', 'Mac'): - import setproctitle - setproctitle.setproctitle(PROG_NAME) - -if sys.argv[0].startswith('./') or sys.argv[0].startswith('python'): - sys.path.insert(0, os.getcwd()) - os.environ['PYHOCAGUI_DEVELOPMENT'] = '1' - print '### %s running in development mode ###' % PROG_NAME - -from pyhoca.wxgui.basepath import locale_basepath - -# Python X2Go modules -from x2go import CURRENT_LOCAL_USER as _CURRENT_LOCAL_USER -if _X2GOCLIENT_OS == 'Windows': - from x2go import X2GoClientXConfig as _X2GoClientXConfig -from x2go import X2GoLogger as _X2GoLogger -from x2go import x2go_cleanup as _x2go_cleanup - -# X2Go backends -from x2go.defaults import BACKENDS as _BACKENDS - -from pyhoca.wxgui import __VERSION__ as _version -from pyhoca.wxgui import messages -from pyhoca.wxgui import PyHocaGUI +import sys -if _X2GOCLIENT_OS == 'Windows': - from pyhoca.wxgui.basepath import nxproxy_binary - os.environ.update({'NXPROXY_BINARY': nxproxy_binary, }) +from pyhoca.wxgui import * +from pyhoca.wxgui import __VERSION__ __author__ = "Mike Gabriel, Dick Kniep" -__version__ = _version - -# version information -VERSION=_version -VERSION_TEXT=""" -%s[%s] - an X2Go GUI client written in Python ----------------------------------------------------------------------- -developed by Mike Gabriel <mike.gabriel@das-netzwerkteam.de> -sponsored by Dick Kniep <dick.kniep@lindix.nl> (2010-2013) - -VERSION: %s - -""" % (PROG_NAME, PROG_PID, VERSION) - -def check_running(): - if _X2GOCLIENT_OS in ('Linux', 'Mac'): - - p = subprocess.Popen(['ps', '-U', _CURRENT_LOCAL_USER, '-u', _CURRENT_LOCAL_USER], stdout=subprocess.PIPE) - psA_out = p.communicate() - if psA_out[0].count(PROG_NAME) <= 1: - - if os.path.isdir(os.path.expanduser("~/.x2go/pyhoca-gui/")): - shutil.rmtree(os.path.expanduser("~/.x2go/pyhoca-gui/")) - - my_pid = str(os.getpid()) - if not os.path.exists(os.path.expanduser("~/.x2go/pyhoca-gui/")): - os.makedirs(os.path.expanduser("~/.x2go/pyhoca-gui/")) - my_pidfile = os.path.expanduser("~/.x2go/pyhoca-gui/display.{pid}".format(pid=my_pid)) - - my_display = os.environ['DISPLAY'] - open(my_pidfile, 'w').write(my_display) - - already_running_for_this_display = False - for pidfile in os.listdir(os.path.expanduser("~/.x2go/pyhoca-gui/")): - - # this is our own pid file... - if my_pidfile.endswith(pidfile): - continue - - display = open(os.path.expanduser("~/.x2go/pyhoca-gui/") + pidfile, 'r').read() - - if display.split('.')[0] == my_display.split('.')[0]: - other_pid = pidfile.split('.')[1] - print - print('One instance of PyHoca-GUI (PID: {other_pid}) is already running for this $DISPLAY {display}'.format(other_pid=other_pid, display=my_display)) - - return True - - return False - - elif _X2GOCLIENT_OS == 'Windows': - import wmi - w = wmi.WMI() - _p_names = [] - for process in w.Win32_Process(): - _p_names.append(process.Name) - return len([ _p_name for _p_name in _p_names if _p_name == PROG_NAME]) > 1 - - -def version(): - # print version text and exit - sys.stderr.write ("%s\n" % VERSION_TEXT) - remove_pidfile() - - sys.exit(0) - - -# sometimes we have to fail... -def runtime_error(m, parser=None, exitcode=-1): - """\ - STILL UNDOCUMENTED - """ - if parser is not None: - parser.print_usage() - sys.stderr.write ("%s: error: %s\n" % (PROG_NAME, m)) +__version__ = __VERSION__ - remove_pidfile() - sys.exit(exitcode) - - -if _X2GOCLIENT_OS == 'Windows': - _x = _X2GoClientXConfig() - _known_xservers = _x.known_xservers - _installed_xservers = _x.installed_xservers - -if _X2GOCLIENT_OS == 'Windows': - _config_backends = ('FILE', 'WINREG') -elif _X2GOCLIENT_OS == 'Linux': - _config_backends = ('FILE', 'GCONF') -else: - _config_backends = ('FILE') - -_profiles_backend_default = _BACKENDS['X2GoSessionProfiles']['default'] -_settings_backend_default = _BACKENDS['X2GoClientSettings']['default'] -_printing_backend_default = _BACKENDS['X2GoClientPrinting']['default'] - -# debug options... -debug_options = [ - {'args':['-d','--debug'], 'default': False, 'action': 'store_true', 'help': 'enable application debugging code', }, - {'args':['--quiet'], 'default': False, 'action': 'store_true', 'help': 'disable any kind of log output', }, - {'args':['--libdebug'], 'default': False, 'action': 'store_true', 'help': 'enable debugging code of the underlying Python X2Go module', }, - {'args':['--libdebug-sftpxfer'], 'default': False, 'action': 'store_true', 'help': 'enable debugging code of Python X2Go\'s sFTP server code (very verbose, and even promiscuous)', }, - {'args':['-V', '--version'], 'default': False, 'action': 'store_true', 'help': 'print version number and exit', }, - ] -x2go_gui_options = [ - {'args':['-P','--session-profile'], 'default': None, 'metavar': '<profile-name>', 'help': 'directly connect to a session profile', }, - {'args':['--remember-username'], 'default': False, 'action': 'store_true', 'help': 'for profiles with interactive authentication, remember the last-used username', }, - {'args':['--non-interactive'], 'default': False, 'action': 'store_true', 'help': 'run the session manager in non-interactive mode, this option sets the following options to true: --restricted-trayicon, --single_session_profile, --start-on-connect, --resume-all-on-connect, --exit-on-disconnect, --disconnect-on-suspend and --disconnect-on-terminate', }, - {'args':['--auto-connect'], 'default': False, 'action': 'store_true', 'help': 'connect sessions via SSH pubkey authentication if possible', }, - {'args':['--show-profile-metatypes'], 'default': False, 'action': 'store_true', 'help': 'show descriptive meta information on session profiles in menus (NOTE: this makes menus appear a bit more sluggish, use it mostly for debugging)', }, - {'args':['--single-session-profile'], 'default': False, 'action': 'store_true', 'help': 'disable support of handling multiple session profiles', }, - {'args':['--tray-icon'], 'default': None, 'metavar': '<your-logo>', 'help': 'define an alternative system tray icon file (PNG files only, leave out file extension here, size 22x22 on Linux, 16x16 on Windows)', }, - {'args':['--tray-icon-connecting'], 'default': None, 'metavar': '<your-logo-while-connecting>', 'help': 'define an alternative system tray icon file while connecting to a server (PNG files only, leave out file extension here, size 22x22 on Linux, 16x16 on Windows)', }, - {'args':['--restricted-trayicon'], 'default': False, 'action': 'store_true', 'help': 'restricts session manager\'s main icon functionality to information window and application exit; on left-click only a minimal session menu is shown', }, - {'args':['--add-to-known-hosts'], 'default': False, 'action': 'store_true', 'help': 'automatically add SSH host keys to the known_hosts files of the client-side user', }, - {'args':['--start-on-connect'], 'default': False, 'action': 'store_true', 'help': 'This is now the hard-coded default. start a session directly after authentication if no session is currently running/suspended', }, - {'args':['--exit-on-disconnect'], 'default': False, 'action': 'store_true', 'help': 'exit the session manager after a server connection has died', }, - {'args':['--resume-newest-on-connect', '--resume-on-connect'], 'default': False, 'action': 'store_true', 'help': 'This is now the hard-coded default. On connect auto-resume the newest suspended session', }, - {'args':['--resume-oldest-on-connect'], 'default': False, 'action': 'store_true', 'help': 'on connect auto-resume the oldest suspended session', }, - {'args':['--resume-all-on-connect'], 'default': False, 'action': 'store_true', 'help': 'auto-resume all suspended sessions on connect', }, - {'args':['--disconnect-on-suspend'], 'default': False, 'action': 'store_true', 'help': 'disconnect a server if a session has been suspended', }, - {'args':['--disconnect-on-terminate'], 'default': False, 'action': 'store_true', 'help': 'disconnect a server if a session has been terminated', }, - {'args':['--splash-image'], 'default': None, 'metavar': '<your-splash-image>', 'help': 'define an alternative splash image that gets shown on application startup (PNG files only, full path or filename as found in <share>/img)', }, - {'args':['--about-image'], 'default': None, 'metavar': '<your-about-window-image>', 'help': 'define an alternative image for the application\'s ,,About\'\' window (PNG files only, full path or filename as found in <share>/img)', }, - {'args':['--disable-splash'], 'default': False, 'action': 'store_true', 'help': 'disable the applications splash screen', }, - {'args':['--disable-options'], 'default': False, 'action': 'store_true', 'help': 'disable the client options configuration window', }, - {'args':['--disable-printingprefs'], 'default': False, 'action': 'store_true', 'help': 'disable the client\'s printing preferences window', }, - {'args':['--disable-profilemanager'], 'default': False, 'action': 'store_true', 'help': 'disable the session profile manager window', }, - {'args':['--disable-notifications'], 'default': False, 'action': 'store_true', 'help': 'disable all applet notifications', }, - {'args':['--display'], 'default': None, 'metavar': '<hostname>:<screennumber>', 'help': 'set the DISPLAY environment variable to <hostname>:<screennumber>', }, - {'args':['--logon-window-position'], 'default': None, 'metavar': '<x-pos>x<y-pos>', 'help': 'give a custom position for the logon window, use negative values to position relative to right/bottom border', }, - {'args':['--published-applications-no-submenus'], 'default': 10, 'metavar': '<number>', 'help': 'the number of published applications that will be rendered without submenus', }, - ] -if _X2GOCLIENT_OS == 'Windows': - x2go_gui_options.append( - {'args':['--lang'], 'default': None, 'metavar': 'LANGUAGE', 'help': 'set the GUI language (currently available: en, de, nl, es)', }, - ) - -backend_options = [ - {'args':['--backend-controlsession'], 'default': None, 'metavar': '<CONTROLSESSION_BACKEND>', 'choices': _BACKENDS['X2GoControlSession'].keys(), 'help': 'force usage of a certain CONTROLSESSION_BACKEND (do not use this unless you know exactly what you are doing)', }, - {'args':['--backend-terminalsession'], 'default': None, 'metavar': '<TERMINALSESSION_BACKEND>', 'choices': _BACKENDS['X2GoTerminalSession'].keys(), 'help': 'force usage of a certain TERMINALSESSION_BACKEND (do not use this unless you know exactly what you are doing)', }, - {'args':['--backend-serversessioninfo'], 'default': None, 'metavar': '<SERVERSESSIONINFO_BACKEND>', 'choices': _BACKENDS['X2GoServerSessionInfo'].keys(), 'help': 'force usage of a certain SERVERSESSIONINFO_BACKEND (do not use this unless you know exactly what you are doing)', }, - {'args':['--backend-serversessionlist'], 'default': None, 'metavar': '<SERVERSESSIONLIST_BACKEND>', 'choices': _BACKENDS['X2GoServerSessionList'].keys(), 'help': 'force usage of a certain SERVERSESSIONLIST_BACKEND (do not use this unless you know exactly what you are doing)', }, - {'args':['--backend-proxy'], 'default': None, 'metavar': '<PROXY_BACKEND>', 'choices': _BACKENDS['X2GoProxy'].keys(), 'help': 'force usage of a certain PROXY_BACKEND (do not use this unless you know exactly what you are doing)', }, - {'args':['--backend-sessionprofiles'], 'default': None, 'metavar': '<SESSIONPROFILES_BACKEND>', 'choices': _config_backends, 'help': 'use given backend for accessing session profiles, available backends on your system: %s (default: %s)' % (', '.join(_config_backends), _profiles_backend_default), }, - {'args':['--backend-clientsettings'], 'default': None, 'metavar': '<CLIENTSETTINGS_BACKEND>', 'choices': _config_backends, 'help': 'use given backend for accessing the client settings configuration, available backends on your system: %s (default: %s)' % (', '.join(_config_backends), _settings_backend_default), }, - {'args':['--backend-clientprinting'], 'default': None, 'metavar': '<CLIENTPRINTING_BACKEND>', 'choices': _config_backends, 'help': 'use given backend for accessing the client printing configuration, available backends on your system: %s (default: %s)' % (', '.join(_config_backends), _printing_backend_default), }, - ] - -if _X2GOCLIENT_OS == 'Windows': - contrib_options = [ - {'args':['--start-xserver'], 'default': False, 'action': 'store_true', 'help': 'start the XServer before starting the session manager application, detect best XServer automatically, if more than one XServer is installed on your system', }, - {'args':['-X', '--preferred-xserver'], 'default': None, 'metavar': '<XSERVER>', 'choices': _known_xservers, 'help': 'start either of the currently supported XServers: %s -- make sure your preferred XServer is installed on your system' % _known_xservers, }, - {'args':['--start-pulseaudio'], 'default': False, 'action': 'store_true', 'help': 'start the PulseAudio server before starting the session manager application', }, - ] - -portable_options = [ - {'args':['--client-rootdir'], 'default': None, 'metavar': '</path/to/.x2goclient/dir>', 'help': 'define an alternative location where to find plain text config files (default: <HOME>/.x2goclient). This option will set ,,--backend-profiles FILE\'\', ,,--backend-clientsettings FILE\'\' and ,,--backend-clientprinting FILE\'\'', }, - {'args':['--sessions-rootdir'], 'default': None, 'metavar': '</path/to/.x2go/dir>', 'help': 'define an alternative location for session runtime files'}, - {'args':['--ssh-rootdir'], 'default': None, 'metavar': '</path/to/.ssh/dir>', 'help': 'define an alternative location for SSH files', }, - ] - - -def remove_pidfile(): - - if _X2GOCLIENT_OS in ('Linux', 'Mac'): - my_pid = str(os.getpid()) - if os.path.exists(os.path.expanduser("~/.x2go/pyhoca-gui/display.{pid}".format(pid=my_pid))): - os.remove(os.path.expanduser("~/.x2go/pyhoca-gui/display.{pid}".format(pid=my_pid))) - - -def parseargs(): - - global DEBUG - global print_action_args - - p = argparse.ArgumentParser(description='Graphical X2Go client implemented in (wx)Python.',\ - formatter_class=argparse.RawDescriptionHelpFormatter, \ - add_help=True, argument_default=None) - p_debugopts = p.add_argument_group('Debug options') - p_guiopts = p.add_argument_group('%s options' % PROG_NAME) - p_portableopts = p.add_argument_group('Portable application support') - p_backendopts = p.add_argument_group('Python X2Go backend options (for experts only)') - - if _X2GOCLIENT_OS == 'Windows': - p_contribopts = p.add_argument_group('XServer options (MS Windows only)') - p_portableopts = p.add_argument_group('File locations for portable setups (MS Windows only)') - _option_groups = ((p_guiopts, x2go_gui_options), (p_debugopts, debug_options), (p_contribopts, contrib_options), (p_portableopts, portable_options), (p_backendopts, backend_options), ) - else: - _option_groups = ((p_guiopts, x2go_gui_options), (p_debugopts, debug_options), (p_portableopts, portable_options), (p_backendopts, backend_options), ) - for (p_group, opts) in _option_groups: - required = False - for opt in opts: - - args = opt['args'] - del opt['args'] - p_group.add_argument(*args, **opt) - - a = p.parse_args() - - logger = _X2GoLogger(tag=PROG_NAME) - liblogger = _X2GoLogger() - - if a.debug: - logger.set_loglevel_debug() - - if a.libdebug: - liblogger.set_loglevel_debug() - - if a.quiet: - logger.set_loglevel_quiet() - liblogger.set_loglevel_quiet() - - if a.libdebug_sftpxfer: - liblogger.enable_debug_sftpxfer() - - if a.version: - version() - - if a.single_session_profile and a.session_profile is None: - runtime_error('The --single-session-profile option requires naming of a specific session profile!', parser=p) - - if a.non_interactive: - if a.session_profile is None: - runtime_error('In non-interactive mode you have to use the --session-profile option (or -P) to specify a certain session profile name!', parser=p) - a.restricted_trayicon = True - a.auto_connect = True - a.start_on_connect = True - a.resume_all_on_connect = True - a.exit_on_disconnect = True - a.disconnect_on_suspend = True - a.disconnect_on_terminate = True - a.single_session_profile = True - - if a.non_interactive and (a.resume_newest_on_connect or a.resume_oldest_on_connect): - # allow override... - a.resume_all_on_connect = False - - if _X2GOCLIENT_OS == 'Windows' and a.preferred_xserver: - if a.preferred_xserver not in _installed_xservers: - runtime_error('Xserver ,,%s\'\' is not installed on your Windows system' % a.preferred_xserver, parser=p) - a.start_xserver = a.preferred_xserver - - if _X2GOCLIENT_OS == 'Windows' and a.start_xserver and a.display: - runtime_error('You can tell %s to handle XServer startup and then specify a DISPLAY environment variable!' % PROG_NAME, parser=p) - - if a.display: - os.environ.update({'DISPLAY': a.display}) - else: - if _X2GOCLIENT_OS == 'Windows' and not a.start_xserver: - os.environ.update({'DISPLAY': 'localhost:0'}) - - if a.client_rootdir: - a.client_rootdir = os.path.expanduser(a.client_rootdir) - - if a.sessions_rootdir: - a.sessions_rootdir = os.path.expanduser(a.sessions_rootdir) - - if a.ssh_rootdir: - a.ssh_rootdir = os.path.expanduser(a.ssh_rootdir) - - if a.client_rootdir: - a.backend_sessionprofiles='FILE' - a.backend_clientsettings='FILE' - a.backend_clientprinting='FILE' - - return a, logger, liblogger - -def main(): - args, logger, liblogger = parseargs() - if _X2GOCLIENT_OS == 'Windows': - if args.lang: - lang = gettext.translation('PyHoca-GUI', localedir=locale_basepath, languages=[args.lang], ) - else: - lang = gettext.translation('PyHoca-GUI', localedir=locale_basepath, languages=['en'], ) - lang.install(unicode=True) - else: - gettext.install('PyHoca-GUI', localedir=locale_basepath, unicode=True) - - if check_running(): - sys.stderr.write("\n###############################\n### %s: already running for user %s\n###############################\n" % (PROG_NAME, _CURRENT_LOCAL_USER)) - m = messages.PyHoca_MessageWindow_Ok(wx.App(), shortmsg='ALREADY_RUNNING', title=u'%s (%s)...' % (PROG_NAME, VERSION), icon='pyhoca-trayicon') - m.ShowModal() - version() - - thisPyHocaGUI = None - try: - thisPyHocaGUI = PyHocaGUI(args, logger, liblogger, appname=PROG_NAME, version=VERSION) - thisPyHocaGUI.MainLoop() - except KeyboardInterrupt: - if thisPyHocaGUI is not None: - thisPyHocaGUI.WakeUpIdle() - thisPyHocaGUI.ExitMainLoop() - except SystemExit: - if thisPyHocaGUI is not None: - thisPyHocaGUI.WakeUpIdle() - thisPyHocaGUI.ExitMainLoop() - - remove_pidfile() if __name__ == '__main__': - main() - + app = PyHocaGUI_Launcher() + #app.setup_progname('MyProgramme') + app.setup_consolelog() + app.setup_process() + app.setup_devmode() + app.main() diff --git a/pyhoca/wxgui/__init__.py b/pyhoca/wxgui/__init__.py index a0ea0fa..89a1d1f 100644 --- a/pyhoca/wxgui/__init__.py +++ b/pyhoca/wxgui/__init__.py @@ -21,3 +21,4 @@ __VERSION__ = '0.5.0.0' from frontend import * +from launcher import * \ No newline at end of file diff --git a/pyhoca/wxgui/launcher.py b/pyhoca/wxgui/launcher.py new file mode 100644 index 0000000..5d43a4d --- /dev/null +++ b/pyhoca/wxgui/launcher.py @@ -0,0 +1,335 @@ +# -*- coding: utf-8 -*- + +# Copyright (C) 2010-2014 by Mike Gabriel <mike.gabriel@das-netzwerkteam.de> +# Copyright (C) 2010-2014 by Dick Kniep <dick.kniep@lindix.nl> +# +# PyHoca GUI is free software; you can redistribute it and/or modify +# it under the terms of the GNU Affero General Public License as published by +# the Free Software Foundation; either version 3 of the License, or +# (at your option) any later version. +# +# PyHoca GUI 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 Affero General Public License for more details. +# +# You should have received a copy of the GNU Affero General Public License +# along with this program; if not, write to the +# Free Software Foundation, Inc., +# 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. + +modules ={} + +import sys +import os +import re +import shutil +import argparse +import gettext +import subprocess + +import gevent.monkey +gevent.monkey.patch_all() + +try: + import wxversion + wxversion.select('2.9') +except: pass + +try: + import wxversion + wxversion.select('2.8') +except: pass + + +from x2go import X2GOCLIENT_OS +from x2go import CURRENT_LOCAL_USER +from x2go import X2GoLogger +from pyhoca.wxgui import PyHocaGUI, __VERSION__ +from options import * +from basepath import * +from messages import PyHoca_MessageWindow_Ok +import wx + +class PyHocaGUI_Launcher(object): + + def __init__(self): + self.PROG_NAME = os.path.basename(sys.argv[0]).replace('.exe', '') + self.PROG_PID = os.getpid() + self.VERSION=__VERSION__ + self.VERSION_TEXT=""" +%s[%s] - an X2Go GUI client written in Python +---------------------------------------------------------------------- +developed by Mike Gabriel <mike.gabriel@das-netzwerkteam.de> +sponsored by Dick Kniep <dick.kniep@lindix.nl> (2010-2013) + +VERSION: %s + +""" % (self.PROG_NAME, self.PROG_PID, self.VERSION) + + def setup_progname(self, pname): + self.PROG_NAME = pname + + def setup_version(self, v): + self.VERSION = v + + def setup_version_text(self, text): + self.VERSION_TEXT = text + + def setup_process(self): + if X2GOCLIENT_OS in ('Linux', 'Mac'): + import setproctitle + setproctitle.setproctitle(self.PROG_NAME) + + if X2GOCLIENT_OS == 'Windows': + from pyhoca.wxgui.basepath import nxproxy_binary + os.environ.update({'NXPROXY_BINARY': nxproxy_binary, }) + + def setup_devmode(self): + if sys.argv[0].startswith('./') or sys.argv[0].startswith('python'): + sys.path.insert(0, os.getcwd()) + os.environ['PYHOCAGUI_DEVELOPMENT'] = '1' + print '### %s running in development mode ###' % self.PROG_NAME + + + def setup_consolelog(self): + if hasattr(sys, 'frozen') and str(sys.frozen) in ("windows_exe", "console_exe", "1", ): + class Win32_Logging(object): + + softspace = 0 + _fname = os.path.join(os.environ['AppData'], self.PROG_NAME, '%s.log' % self.PROG_NAME) + _file = None + + def __init__(self, filemode='a'): + self._filemode = filemode + if os.path.isfile(self._fname) and self._filemode == "w+": + os.remove(self._fname) + + def write(self, text, **kwargs): + if self._file is None: + try: + try: + os.mkdir(os.path.dirname(self._fname)) + except: + pass + self._file = open(self._fname, self._filemode) + except: + pass + else: + self._file.write(text) + self._file.flush() + + def flush(self): + if self._file is not None: + self._file.flush() + + sys.stdout = Win32_Logging(filemode='w+') + sys.stderr = Win32_Logging(filemode='a') + del Win32_Logging + + + def check_running(self): + if X2GOCLIENT_OS in ('Linux', 'Mac'): + + p = subprocess.Popen(['ps', '-U', CURRENT_LOCAL_USER, '-u', CURRENT_LOCAL_USER], stdout=subprocess.PIPE) + psA_out = p.communicate() + if psA_out[0].count(self.PROG_NAME) <= 1: + + if os.path.isdir(os.path.expanduser("~/.x2go/pyhoca-gui/")): + shutil.rmtree(os.path.expanduser("~/.x2go/pyhoca-gui/")) + + my_pid = str(os.getpid()) + if not os.path.exists(os.path.expanduser("~/.x2go/pyhoca-gui/")): + os.makedirs(os.path.expanduser("~/.x2go/pyhoca-gui/")) + my_pidfile = os.path.expanduser("~/.x2go/pyhoca-gui/display.{pid}".format(pid=my_pid)) + + my_display = os.environ['DISPLAY'] + open(my_pidfile, 'w').write(my_display) + + already_running_for_this_display = False + for pidfile in os.listdir(os.path.expanduser("~/.x2go/pyhoca-gui/")): + + # this is our own pid file... + if my_pidfile.endswith(pidfile): + continue + + display = open(os.path.expanduser("~/.x2go/pyhoca-gui/") + pidfile, 'r').read() + + if display.split('.')[0] == my_display.split('.')[0]: + other_pid = pidfile.split('.')[1] + print + print('One instance of PyHoca-GUI (PID: {other_pid}) is already running for this $DISPLAY {display}'.format(other_pid=other_pid, display=my_display)) + + return True + + return False + + elif X2GOCLIENT_OS == 'Windows': + import wmi + w = wmi.WMI() + _p_names = [] + for process in w.Win32_Process(): + _p_names.append(process.Name) + return len([ _p_name for _p_name in _p_names if _p_name == self.PROG_NAME]) > 1 + + + def version(self): + # version information + + # print version text and exit + sys.stderr.write ("%s\n" % self.VERSION_TEXT) + self.remove_pidfile() + + sys.exit(0) + + + # sometimes we have to fail... + def runtime_error(m, parser=None, exitcode=-1): + """\ + STILL UNDOCUMENTED + """ + if parser is not None: + parser.print_usage() + sys.stderr.write ("%s: error: %s\n" % (self.PROG_NAME, m)) + + self.remove_pidfile() + sys.exit(exitcode) + + + def remove_pidfile(self): + + if X2GOCLIENT_OS in ('Linux', 'Mac'): + my_pid = str(os.getpid()) + if os.path.exists(os.path.expanduser("~/.x2go/pyhoca-gui/display.{pid}".format(pid=my_pid))): + os.remove(os.path.expanduser("~/.x2go/pyhoca-gui/display.{pid}".format(pid=my_pid))) + + + def parseargs(self): + + global DEBUG + global print_action_args + + p = argparse.ArgumentParser(description='Graphical X2Go client implemented in (wx)Python.',\ + formatter_class=argparse.RawDescriptionHelpFormatter, \ + add_help=True, argument_default=None) + p_debugopts = p.add_argument_group('Debug options') + p_guiopts = p.add_argument_group('%s options' % self.PROG_NAME) + p_portableopts = p.add_argument_group('Portable application support') + p_backendopts = p.add_argument_group('Python X2Go backend options (for experts only)') + + if X2GOCLIENT_OS == 'Windows': + p_contribopts = p.add_argument_group('XServer options (MS Windows only)') + p_portableopts = p.add_argument_group('File locations for portable setups (MS Windows only)') + _option_groups = ((p_guiopts, x2go_gui_options), (p_debugopts, debug_options), (p_contribopts, contrib_options), (p_portableopts, portable_options), (p_backendopts, backend_options), ) + else: + _option_groups = ((p_guiopts, x2go_gui_options), (p_debugopts, debug_options), (p_portableopts, portable_options), (p_backendopts, backend_options), ) + for (p_group, opts) in _option_groups: + required = False + for opt in opts: + + args = opt['args'] + del opt['args'] + p_group.add_argument(*args, **opt) + + a = p.parse_args() + + logger = X2GoLogger(tag=self.PROG_NAME) + liblogger = X2GoLogger() + + if a.debug: + logger.set_loglevel_debug() + + if a.libdebug: + liblogger.set_loglevel_debug() + + if a.quiet: + logger.set_loglevel_quiet() + liblogger.set_loglevel_quiet() + + if a.libdebug_sftpxfer: + liblogger.enable_debug_sftpxfer() + + if a.version: + self.version() + + if a.single_session_profile and a.session_profile is None: + self.runtime_error('The --single-session-profile option requires naming of a specific session profile!', parser=p) + + if a.non_interactive: + if a.session_profile is None: + self.runtime_error('In non-interactive mode you have to use the --session-profile option (or -P) to specify a certain session profile name!', parser=p) + a.restricted_trayicon = True + a.auto_connect = True + a.start_on_connect = True + a.resume_all_on_connect = True + a.exit_on_disconnect = True + a.disconnect_on_suspend = True + a.disconnect_on_terminate = True + a.single_session_profile = True + + if a.non_interactive and (a.resume_newest_on_connect or a.resume_oldest_on_connect): + # allow override... + a.resume_all_on_connect = False + + if X2GOCLIENT_OS == 'Windows' and a.preferred_xserver: + if a.preferred_xserver not in _installed_xservers: + self.runtime_error('Xserver ,,%s\'\' is not installed on your Windows system' % a.preferred_xserver, parser=p) + a.start_xserver = a.preferred_xserver + + if X2GOCLIENT_OS == 'Windows' and a.start_xserver and a.display: + self.runtime_error('You can tell %s to handle XServer startup and then specify a DISPLAY environment variable!' % self.PROG_NAME, parser=p) + + if a.display: + os.environ.update({'DISPLAY': a.display}) + else: + if X2GOCLIENT_OS == 'Windows' and not a.start_xserver: + os.environ.update({'DISPLAY': 'localhost:0'}) + + if a.client_rootdir: + a.client_rootdir = os.path.expanduser(a.client_rootdir) + + if a.sessions_rootdir: + a.sessions_rootdir = os.path.expanduser(a.sessions_rootdir) + + if a.ssh_rootdir: + a.ssh_rootdir = os.path.expanduser(a.ssh_rootdir) + + if a.client_rootdir: + a.backend_sessionprofiles='FILE' + a.backend_clientsettings='FILE' + a.backend_clientprinting='FILE' + + return a, logger, liblogger + + + def main(self): + args, logger, liblogger = self.parseargs() + if X2GOCLIENT_OS == 'Windows': + if args.lang: + lang = gettext.translation('PyHoca-GUI', localedir=locale_basepath, languages=[args.lang], ) + else: + lang = gettext.translation('PyHoca-GUI', localedir=locale_basepath, languages=['en'], ) + lang.install(unicode=True) + else: + gettext.install('PyHoca-GUI', localedir=locale_basepath, unicode=True) + + if self.check_running(): + sys.stderr.write("\n###############################\n### %s: already running for user %s\n###############################\n" % (self.PROG_NAME, CURRENT_LOCAL_USER)) + m = PyHoca_MessageWindow_Ok(wx.App(), shortmsg='ALREADY_RUNNING', title=u'%s (%s)...' % (self.PROG_NAME, self.VERSION), icon='pyhoca-trayicon') + m.ShowModal() + version() + + thisPyHocaGUI = None + try: + thisPyHocaGUI = PyHocaGUI(args, logger, liblogger, appname=self.PROG_NAME, version=self.VERSION) + thisPyHocaGUI.MainLoop() + except KeyboardInterrupt: + if thisPyHocaGUI is not None: + thisPyHocaGUI.WakeUpIdle() + thisPyHocaGUI.ExitMainLoop() + except SystemExit: + if thisPyHocaGUI is not None: + thisPyHocaGUI.WakeUpIdle() + thisPyHocaGUI.ExitMainLoop() + + self.remove_pidfile() diff --git a/pyhoca/wxgui/options.py b/pyhoca/wxgui/options.py new file mode 100644 index 0000000..3a79cce --- /dev/null +++ b/pyhoca/wxgui/options.py @@ -0,0 +1,109 @@ +#!/usr/bin/env python +# -*- coding: utf-8 -*- + +# Copyright (C) 2010-2013 by Mike Gabriel <mike.gabriel@das-netzwerkteam.de> +# Copyright (C) 2010-2013 by Dick Kniep <dick.kniep@lindix.nl> +# +# PyHoca GUI is free software; you can redistribute it and/or modify +# it under the terms of the GNU Affero General Public License as published by +# the Free Software Foundation; either version 3 of the License, or +# (at your option) any later version. +# +# PyHoca GUI 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 Affero General Public License for more details. +# +# You should have received a copy of the GNU Affero General Public License +# along with this program; if not, write to the +# Free Software Foundation, Inc., +# 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. + +from x2go import X2GOCLIENT_OS +from x2go import BACKENDS + +_profiles_backend_default = BACKENDS['X2GoSessionProfiles']['default'] +_settings_backend_default = BACKENDS['X2GoClientSettings']['default'] +_printing_backend_default = BACKENDS['X2GoClientPrinting']['default'] + +if X2GOCLIENT_OS == 'Windows': + from x2go import X2GoClientXConfig + _x = X2GoClientXConfig() + _known_xservers = _x.known_xservers + _installed_xservers = _x.installed_xservers + +if X2GOCLIENT_OS == 'Windows': + _config_backends = ('FILE', 'WINREG') +elif X2GOCLIENT_OS == 'Linux': + _config_backends = ('FILE', 'GCONF') +else: + _config_backends = ('FILE') + + +# debug options... +debug_options = [ + {'args':['-d','--debug'], 'default': False, 'action': 'store_true', 'help': 'enable application debugging code', }, + {'args':['--quiet'], 'default': False, 'action': 'store_true', 'help': 'disable any kind of log output', }, + {'args':['--libdebug'], 'default': False, 'action': 'store_true', 'help': 'enable debugging code of the underlying Python X2Go module', }, + {'args':['--libdebug-sftpxfer'], 'default': False, 'action': 'store_true', 'help': 'enable debugging code of Python X2Go\'s sFTP server code (very verbose, and even promiscuous)', }, + {'args':['-V', '--version'], 'default': False, 'action': 'store_true', 'help': 'print version number and exit', }, + ] +x2go_gui_options = [ + {'args':['-P','--session-profile'], 'default': None, 'metavar': '<profile-name>', 'help': 'directly connect to a session profile', }, + {'args':['--remember-username'], 'default': False, 'action': 'store_true', 'help': 'for profiles with interactive authentication, remember the last-used username', }, + {'args':['--non-interactive'], 'default': False, 'action': 'store_true', 'help': 'run the session manager in non-interactive mode, this option sets the following options to true: --restricted-trayicon, --single_session_profile, --start-on-connect, --resume-all-on-connect, --exit-on-disconnect, --disconnect-on-suspend and --disconnect-on-terminate', }, + {'args':['--auto-connect'], 'default': False, 'action': 'store_true', 'help': 'connect sessions via SSH pubkey authentication if possible', }, + {'args':['--show-profile-metatypes'], 'default': False, 'action': 'store_true', 'help': 'show descriptive meta information on session profiles in menus (NOTE: this makes menus appear a bit more sluggish, use it mostly for debugging)', }, + {'args':['--single-session-profile'], 'default': False, 'action': 'store_true', 'help': 'disable support of handling multiple session profiles', }, + {'args':['--tray-icon'], 'default': None, 'metavar': '<your-logo>', 'help': 'define an alternative system tray icon file (PNG files only, leave out file extension here, size 22x22 on Linux, 16x16 on Windows)', }, + {'args':['--tray-icon-connecting'], 'default': None, 'metavar': '<your-logo-while-connecting>', 'help': 'define an alternative system tray icon file while connecting to a server (PNG files only, leave out file extension here, size 22x22 on Linux, 16x16 on Windows)', }, + {'args':['--restricted-trayicon'], 'default': False, 'action': 'store_true', 'help': 'restricts session manager\'s main icon functionality to information window and application exit; on left-click only a minimal session menu is shown', }, + {'args':['--add-to-known-hosts'], 'default': False, 'action': 'store_true', 'help': 'automatically add SSH host keys to the known_hosts files of the client-side user', }, + {'args':['--start-on-connect'], 'default': False, 'action': 'store_true', 'help': 'This is now the hard-coded default. start a session directly after authentication if no session is currently running/suspended', }, + {'args':['--exit-on-disconnect'], 'default': False, 'action': 'store_true', 'help': 'exit the session manager after a server connection has died', }, + {'args':['--resume-newest-on-connect', '--resume-on-connect'], 'default': False, 'action': 'store_true', 'help': 'This is now the hard-coded default. On connect auto-resume the newest suspended session', }, + {'args':['--resume-oldest-on-connect'], 'default': False, 'action': 'store_true', 'help': 'on connect auto-resume the oldest suspended session', }, + {'args':['--resume-all-on-connect'], 'default': False, 'action': 'store_true', 'help': 'auto-resume all suspended sessions on connect', }, + {'args':['--disconnect-on-suspend'], 'default': False, 'action': 'store_true', 'help': 'disconnect a server if a session has been suspended', }, + {'args':['--disconnect-on-terminate'], 'default': False, 'action': 'store_true', 'help': 'disconnect a server if a session has been terminated', }, + {'args':['--splash-image'], 'default': None, 'metavar': '<your-splash-image>', 'help': 'define an alternative splash image that gets shown on application startup (PNG files only, full path or filename as found in <share>/img)', }, + {'args':['--about-image'], 'default': None, 'metavar': '<your-about-window-image>', 'help': 'define an alternative image for the application\'s ,,About\'\' window (PNG files only, full path or filename as found in <share>/img)', }, + {'args':['--disable-splash'], 'default': False, 'action': 'store_true', 'help': 'disable the applications splash screen', }, + {'args':['--disable-options'], 'default': False, 'action': 'store_true', 'help': 'disable the client options configuration window', }, + {'args':['--disable-printingprefs'], 'default': False, 'action': 'store_true', 'help': 'disable the client\'s printing preferences window', }, + {'args':['--disable-profilemanager'], 'default': False, 'action': 'store_true', 'help': 'disable the session profile manager window', }, + {'args':['--disable-notifications'], 'default': False, 'action': 'store_true', 'help': 'disable all applet notifications', }, + {'args':['--display'], 'default': None, 'metavar': '<hostname>:<screennumber>', 'help': 'set the DISPLAY environment variable to <hostname>:<screennumber>', }, + {'args':['--logon-window-position'], 'default': None, 'metavar': '<x-pos>x<y-pos>', 'help': 'give a custom position for the logon window, use negative values to position relative to right/bottom border', }, + {'args':['--published-applications-no-submenus'], 'default': 10, 'metavar': '<number>', 'help': 'the number of published applications that will be rendered without submenus', }, + ] +if X2GOCLIENT_OS == 'Windows': + x2go_gui_options.append( + {'args':['--lang'], 'default': None, 'metavar': 'LANGUAGE', 'help': 'set the GUI language (currently available: en, de, nl, es)', }, + ) + +backend_options = [ + {'args':['--backend-controlsession'], 'default': None, 'metavar': '<CONTROLSESSION_BACKEND>', 'choices': BACKENDS['X2GoControlSession'].keys(), 'help': 'force usage of a certain CONTROLSESSION_BACKEND (do not use this unless you know exactly what you are doing)', }, + {'args':['--backend-terminalsession'], 'default': None, 'metavar': '<TERMINALSESSION_BACKEND>', 'choices': BACKENDS['X2GoTerminalSession'].keys(), 'help': 'force usage of a certain TERMINALSESSION_BACKEND (do not use this unless you know exactly what you are doing)', }, + {'args':['--backend-serversessioninfo'], 'default': None, 'metavar': '<SERVERSESSIONINFO_BACKEND>', 'choices': BACKENDS['X2GoServerSessionInfo'].keys(), 'help': 'force usage of a certain SERVERSESSIONINFO_BACKEND (do not use this unless you know exactly what you are doing)', }, + {'args':['--backend-serversessionlist'], 'default': None, 'metavar': '<SERVERSESSIONLIST_BACKEND>', 'choices': BACKENDS['X2GoServerSessionList'].keys(), 'help': 'force usage of a certain SERVERSESSIONLIST_BACKEND (do not use this unless you know exactly what you are doing)', }, + {'args':['--backend-proxy'], 'default': None, 'metavar': '<PROXY_BACKEND>', 'choices': BACKENDS['X2GoProxy'].keys(), 'help': 'force usage of a certain PROXY_BACKEND (do not use this unless you know exactly what you are doing)', }, + {'args':['--backend-sessionprofiles'], 'default': None, 'metavar': '<SESSIONPROFILES_BACKEND>', 'choices': _config_backends, 'help': 'use given backend for accessing session profiles, available backends on your system: %s (default: %s)' % (', '.join(_config_backends), _profiles_backend_default), }, + {'args':['--backend-clientsettings'], 'default': None, 'metavar': '<CLIENTSETTINGS_BACKEND>', 'choices': _config_backends, 'help': 'use given backend for accessing the client settings configuration, available backends on your system: %s (default: %s)' % (', '.join(_config_backends), _settings_backend_default), }, + {'args':['--backend-clientprinting'], 'default': None, 'metavar': '<CLIENTPRINTING_BACKEND>', 'choices': _config_backends, 'help': 'use given backend for accessing the client printing configuration, available backends on your system: %s (default: %s)' % (', '.join(_config_backends), _printing_backend_default), }, + ] + +if X2GOCLIENT_OS == 'Windows': + contrib_options = [ + {'args':['--start-xserver'], 'default': False, 'action': 'store_true', 'help': 'start the XServer before starting the session manager application, detect best XServer automatically, if more than one XServer is installed on your system', }, + {'args':['-X', '--preferred-xserver'], 'default': None, 'metavar': '<XSERVER>', 'choices': _known_xservers, 'help': 'start either of the currently supported XServers: %s -- make sure your preferred XServer is installed on your system' % _known_xservers, }, + {'args':['--start-pulseaudio'], 'default': False, 'action': 'store_true', 'help': 'start the PulseAudio server before starting the session manager application', }, + ] + +portable_options = [ + {'args':['--client-rootdir'], 'default': None, 'metavar': '</path/to/.x2goclient/dir>', 'help': 'define an alternative location where to find plain text config files (default: <HOME>/.x2goclient). This option will set ,,--backend-profiles FILE\'\', ,,--backend-clientsettings FILE\'\' and ,,--backend-clientprinting FILE\'\'', }, + {'args':['--sessions-rootdir'], 'default': None, 'metavar': '</path/to/.x2go/dir>', 'help': 'define an alternative location for session runtime files'}, + {'args':['--ssh-rootdir'], 'default': None, 'metavar': '</path/to/.ssh/dir>', 'help': 'define an alternative location for SSH files', }, + ] + + -- Alioth's /srv/git/_hooks_/post-receive-email on /srv/git/code.x2go.org/pyhoca-gui.git