[X2Go-Commits] python-x2go.git - release/0.4.0.x (branch) updated: 0.1.1.4-130-g0eff893

X2Go dev team git-admin at x2go.org
Tue Jan 7 16:17:42 CET 2014


The branch, release/0.4.0.x has been updated
       via  0eff893ffaa6c3358e4ca2184bebe5b471d529f0 (commit)
      from  f2e8361dc164f7ae5215745fe7d56ac9cf25fca0 (commit)

Those revisions listed above that are new to this repository have
not appeared on any other notification email; so we list those
revisions in full, below.

- Log -----------------------------------------------------------------
-----------------------------------------------------------------------

Summary of changes:
 debian/changelog                  |    1 +
 x2go/backends/control/_stdout.py  |   43 +++++++++++++++-
 x2go/backends/info/_stdout.py     |    5 ++
 x2go/backends/terminal/_stdout.py |  103 ++++++++++++++++++++++++++++++-------
 x2go/client.py                    |   56 +++++++++++++++++++-
 x2go/defaults.py                  |    3 +-
 x2go/registry.py                  |   35 ++++++++++++-
 x2go/session.py                   |   94 ++++++++++++++++++++++++++++++---
 x2go/utils.py                     |   10 ++--
 9 files changed, 313 insertions(+), 37 deletions(-)

The diff of changes is:
diff --git a/debian/changelog b/debian/changelog
index 65571f2..8097dc9 100644
--- a/debian/changelog
+++ b/debian/changelog
@@ -39,6 +39,7 @@ python-x2go (0.1.2.0-0~x2go1) UNRELEASED; urgency=low
     - Amend list of default session options.
     - Update list of unsupported session options.
     - Retrieve feature list from X2Go server per session.
+    - Add published applications support.
   * Depend on python-xlib.
 
  -- Mike Gabriel <mike.gabriel at das-netzwerkteam.de>  Sat, 28 Sep 2012 01:44:21 +0100
diff --git a/x2go/backends/control/_stdout.py b/x2go/backends/control/_stdout.py
index fc345d9..6b3dd1f 100644
--- a/x2go/backends/control/_stdout.py
+++ b/x2go/backends/control/_stdout.py
@@ -141,6 +141,8 @@ class X2goControlSessionSTDOUT(paramiko.SSHClient):
         self.sessions_rootdir = sessions_rootdir
         self.ssh_rootdir = ssh_rootdir
 
+        self._published_applications_menu = None
+
         paramiko.SSHClient.__init__(self, *args, **kwargs)
         if self.add_to_known_hosts:
             self.set_missing_host_key_policy(paramiko.AutoAddPolicy())
@@ -591,6 +593,39 @@ class X2goControlSessionSTDOUT(paramiko.SSHClient):
             return True
         return False
 
+    def get_published_applications(self):
+        """\
+        Retrieve the menu tree of published applications from X2Go server.
+
+        """
+        if 'X2GO_PUBLISHED_APPLICATIONS' in self._x2go_server_features:
+            if self._published_applications_menu is None:
+                self.logger('querying server (%s) for list of published applications' % self.profile_name, loglevel=log.loglevel_NOTICE)
+                (stdin, stdout, stderr) = self._x2go_exec_command('which x2gogetapps >/dev/null && x2gogetapps')
+                _raw_menu_items = stdout.read().split('</desktop>\n')
+                _raw_menu_items = [ i.replace('<desktop>\n', '') for i in _raw_menu_items ]
+                _menu = []
+                for _raw_menu_item in _raw_menu_items:
+                    if '<icon>\n' in _raw_menu_item and '</icon>' in _raw_menu_item:
+                        _menu_item = _raw_menu_item.split('<icon>\n')[0] + _raw_menu_item.split('</icon>\n')[1]
+                        _icon_base64 = _raw_menu_item.split('<icon>\n')[1].split('</icon>\n')[0].replace('\n', '')
+                    else:
+                        _menu_item = _raw_menu_item
+                        _icon_base64 = None
+                    if _menu_item:
+                        _menu.append({ 'desktop': _menu_item, 'icon': _icon_base64, })
+                        _menu_item = None
+                        _icon_base64 = None
+
+                self._published_applications_menu = _menu
+                self.logger('published applications query for %s finished' % self.profile_name, loglevel=log.loglevel_NOTICE)
+                return self._published_applications_menu
+            else:
+                return self._published_applications_menu
+        else:
+            # FIXME: ignoring the absence of the published applications feature for now, handle it appropriately later
+            pass
+
     def start(self, **kwargs):
         """\
         Start a new X2Go session. 
@@ -826,14 +861,18 @@ class X2goControlSessionSTDOUT(paramiko.SSHClient):
 
             return _listsessions
 
-    def clean_sessions(self, destroy_terminals=True):
+    def clean_sessions(self, destroy_terminals=True, published_applications=False):
         """\
         Find X2Go terminals that have previously been started by the
         connected user on the remote X2Go server and terminate them.
 
         """
         session_list = self.list_sessions()
-        for session_name in session_list.keys():
+        if published_applications:
+            session_names = session_list.keys()
+        else:
+            session_names = [ _sn for _sn in session_list.keys() if not session_list[_sn].is_published_applications_provider() ]
+        for session_name in session_names:
             self.terminate(session_name=session_name, destroy_terminals=destroy_terminals)
 
     def is_connected(self):
diff --git a/x2go/backends/info/_stdout.py b/x2go/backends/info/_stdout.py
index ae6046c..c316ec7 100644
--- a/x2go/backends/info/_stdout.py
+++ b/x2go/backends/info/_stdout.py
@@ -30,6 +30,7 @@ __NAME__ = 'x2goserversessioninfo-pylib'
 
 # modules
 import types
+import re
 
 
 class X2goServerSessionInfoSTDOUT(object):
@@ -83,6 +84,10 @@ class X2goServerSessionInfoSTDOUT(object):
             print x2go_output
             raise e
 
+    def is_published_applications_provider(self):
+
+        return re.match('.*_stRPUBLISHED_.*', self.name)
+
     def is_running(self):
 
         return self.status == 'R'
diff --git a/x2go/backends/terminal/_stdout.py b/x2go/backends/terminal/_stdout.py
index 5179bdc..aee28b0 100644
--- a/x2go/backends/terminal/_stdout.py
+++ b/x2go/backends/terminal/_stdout.py
@@ -77,6 +77,10 @@ def _rewrite_cmd(cmd, params=None):
     # place quot marks around cmd if not empty string
     if cmd:
         cmd = '"%s"' % cmd
+
+    if ((type(params) == X2goSessionParams) and params.published_applications and cmd == ''):
+        cmd = 'PUBLISHED'
+
     return cmd
 
 
@@ -108,24 +112,33 @@ class X2goSessionParams(object):
 
         """
         cmd = self.cmd
+        published = self.published_applications
 
-        if cmd == 'RDP':
-            self.session_type = 'R'
-        elif cmd.startswith('rdesktop'):
-            self.session_type = 'R'
-        elif cmd == 'XDMCP':
-            self.session_type = 'D'
-        elif cmd in defaults.X2GO_DESKTOPSESSIONS.keys():
-            self.session_type = 'D'
-        elif os.path.basename(cmd) in defaults.X2GO_DESKTOPSESSIONS.values():
-            self.session_type = 'D'
-        elif self.session_type not in ("S", "shared", "shadow"):
-            self.session_type = 'R'
+        if published and self.cmd in ('', 'PUBLISHED'):
+            self.session_type = 'P'
+            self.cmd = 'PUBLISHED'
+        else:
+            if cmd == 'RDP':
+                self.session_type = 'R'
+            elif cmd.startswith('rdesktop'):
+                self.session_type = 'R'
+            elif cmd == 'XDMCP':
+                self.session_type = 'D'
+            elif cmd in defaults.X2GO_DESKTOPSESSIONS.keys():
+                self.session_type = 'D'
+            elif os.path.basename(cmd) in defaults.X2GO_DESKTOPSESSIONS.values():
+                self.session_type = 'D'
+            elif self.session_type not in ("S", "shared", "shadow"):
+                self.session_type = 'R'
 
         if self.session_type in ("D", "desktop"):
             self.session_type = 'D'
         elif self.session_type in ("S", "shared", "shadow"):
             self.session_type = 'S'
+        elif self.session_type in ("R", "rootless"):
+            self.session_type = 'R'
+        elif self.session_type in ("P", "published", "published_applications"):
+            self.session_type = 'P'
 
     def update(self, properties_to_be_updated={}):
         """\
@@ -174,6 +187,7 @@ class X2goTerminalSessionSTDOUT(object):
                  cache_type="unix-kde", 
                  keyboard='', kblayout='null', kbtype='null/null',
                  session_type="application", snd_system='pulse', snd_port=4713, cmd=None,
+                 published_applications=False,
                  set_session_title=False, session_title="", applications=[],
                  rdp_server=None, rdp_options=None,
                  xdmcp_server=None,
@@ -280,6 +294,9 @@ class X2goTerminalSessionSTDOUT(object):
         self.params.cmd = str(cmd)
         self.params.depth = str(depth)
 
+        self.params.published_applications = published_applications
+        self.published_applications = published_applications
+
         self.params.rdp_server = str(rdp_server)
         self.params.rdp_options = str(rdp_options)
         self.params.xdmcp_server = str(xdmcp_server)
@@ -375,6 +392,13 @@ class X2goTerminalSessionSTDOUT(object):
         """
         return self.session_info.name
 
+    def get_session_cmd(self):
+        """\
+        STILL UNDOCUMENTED
+
+        """
+        return self.params.cmd
+
     def start_sound(self):
         """\
         Initialize Paramiko/SSH reverse forwarding tunnel for X2Go sound.
@@ -870,6 +894,8 @@ class X2goTerminalSessionSTDOUT(object):
             return True
         elif 'XSHAD' in cmd:
             return True
+        elif 'PUBLISHED' in cmd and 'X2GO_PUBLISHED_APPLICATIONS' in self.control_session.get_server_features():
+            return True
         elif cmd and cmd.startswith('/'):
             # check if full path is correct _and_ if application is in server path
             test_cmd = 'test -x %s && which %s && echo OK' % (cmd, os.path.basename(cmd.split()[0]))
@@ -900,7 +926,7 @@ class X2goTerminalSessionSTDOUT(object):
         @rtype: tuple of str
 
         """
-        if not self.has_command(_rewrite_cmd(self.params.cmd)):
+        if not self.has_command(_rewrite_cmd(self.params.cmd, params=self.params)):
             if self.client_instance:
                 self.client_instance.HOOK_no_such_command(profile_name=self.profile_name, session_name=self.session_info.name, cmd=self.params.cmd)
             return False
@@ -947,6 +973,32 @@ class X2goTerminalSessionSTDOUT(object):
 
         return stdout.read(), stderr.read()
 
+    def is_published_applications_provider(self):
+        """\
+        Returns true if this session runs in published applications mode.
+
+        @return: Returns C{True} is this session is a provider session for published applications.
+        @rtype: C{bool}
+
+        """
+        if self.session_info and self.is_running():
+            return self.session_info.is_published_applications_provider()
+        return False
+
+    def exec_published_application(self, exec_name):
+        """\
+        Executed a published application.
+
+        @param exec_name: application to be executed
+        @type exec_name: C{str}
+        """
+        cmd_line = [ "export DISPLAY=:%s && " % str(self.session_info.display),
+                     "setsid %s" % exec_name, 
+                     "&> /dev/null & exit",
+                   ]
+        self.logger('executing published application %s for %s with command line: %s' % (exec_name, self.profile_name, cmd_line), loglevel=log.loglevel_NOTICE)
+        (stdin, stdout, stderr) = self.control_session._x2go_exec_command(cmd_line)
+
     def ok(self):
         """\
         Returns C{True} if this X2Go session is up and running, 
@@ -999,7 +1051,9 @@ class X2goTerminalSessionSTDOUT(object):
         that can be passed to the class constructor.
 
         """
-        if not self.has_command(_rewrite_cmd(self.params.cmd)):
+        self.params.rewrite_session_type()
+
+        if not self.has_command(_rewrite_cmd(self.params.cmd, params=self.params)):
             if self.client_instance:
                 self.client_instance.HOOK_no_such_command(profile_name=self.profile_name, session_name=self.session_info.name, cmd=self.params.cmd)
             return False
@@ -1069,9 +1123,13 @@ class X2goTerminalSessionSTDOUT(object):
         self.proxy_subprocess = self.proxy.start_proxy()
         self.active_threads.append(self.proxy)
 
-        self.find_session_window()
-        self.auto_session_window_title()
-        #self.raise_session_window()
+        if self.params.session_type in ('D', 'S'):
+            self.find_session_window()
+            self.auto_session_window_title()
+            #self.raise_session_window()
+
+        if self.params.published_applications:
+            self.control_session.get_published_applications()
 
         return self.ok()
 
@@ -1145,9 +1203,14 @@ class X2goTerminalSessionSTDOUT(object):
         # on a session resume the user name comes in as a user ID. We have to translate this...
         self.session_info.username = self.control_session.remote_username()
 
-        self.find_session_window()
-        self.auto_session_window_title()
-        #self.raise_session_window()
+        if self.params.session_type in ('D', 'S'):
+            self.find_session_window()
+            self.auto_session_window_title()
+            #self.raise_session_window()
+
+        if self.is_published_applications_provider():
+            self.control_session.get_published_applications()
+            self.published_applications = True
 
         return self.ok()
 
diff --git a/x2go/client.py b/x2go/client.py
index 4adfb01..4ff1e26 100644
--- a/x2go/client.py
+++ b/x2go/client.py
@@ -1991,6 +1991,55 @@ class X2goClient(object):
         return self.session_registry.associated_sessions_of_profile_name(profile_name, return_objects=return_objects, return_session_names=return_session_names)
     __client_associated_sessions_of_profile_name = client_associated_sessions_of_profile_name
 
+    def client_pubapp_sessions_of_profile_name(self, profile_name, return_objects=False, return_session_names=False):
+        """\
+        Retrieve X2Go sessions of profile name <profile_name> that provide published applications .
+
+        @param profile_name: profile name
+        @type profile_name: C{str}
+        @param return_objects: return as list of X2Go session objects
+        @type return_objects: C{bool}
+        @param return_session_names: return as list of session names
+        @type return_session_names: C{bool}
+        @return: list of application publishing sessions of profile name
+        @rtype: C{list}
+        """
+        return self.session_registry.pubapp_sessions_of_profile_name(profile_name, return_objects=return_objects, return_session_names=return_session_names)
+    __client_pubapp_sessions_of_profile_name = client_pubapp_sessions_of_profile_name
+
+
+    def client_running_sessions_of_profile_name(self, profile_name, return_objects=False, return_session_names=False):
+        """\
+        Retrieve running X2Go sessions of profile name <profile_name>.
+
+        @param profile_name: profile name
+        @type profile_name: C{str}
+        @param return_objects: return as list of X2Go session objects
+        @type return_objects: C{bool}
+        @param return_session_names: return as list of session names
+        @type return_session_names: C{bool}
+        @return: list of running sessions of profile name
+        @rtype: C{list}
+        """
+        return self.session_registry.running_sessions_of_profile_name(profile_name, return_objects=return_objects, return_session_names=return_session_names)
+    __client_running_sessions_of_profile_name = client_running_sessions_of_profile_name
+
+    def client_suspended_sessions_of_profile_name(self, profile_name, return_objects=False, return_session_names=False):
+        """\
+        Retrieve suspended X2Go sessions of profile name <profile_name>.
+
+        @param profile_name: profile name
+        @type profile_name: C{str}
+        @param return_objects: return as list of X2Go session objects
+        @type return_objects: C{bool}
+        @param return_session_names: return as list of session names
+        @type return_session_names: C{bool}
+        @return: list of suspended sessions of profile name
+        @rtype: C{list}
+        """
+        return self.session_registry.suspended_sessions_of_profile_name(profile_name, return_objects=return_objects, return_session_names=return_session_names)
+    __client_suspended_sessions_of_profile_name = client_suspended_sessions_of_profile_name
+
     ###
     ### Provide access to the X2Go server's sessions DB
     ### 
@@ -2131,7 +2180,7 @@ class X2goClient(object):
     ### CLIENT OPERATIONS ON SESSIONS (listing sessions, terminating non-associated sessions etc.)
     ###
 
-    def clean_sessions(self, session_uuid):
+    def clean_sessions(self, session_uuid, published_applications=None):
         """\
         Find running X2Go sessions that have previously been started by the
         connected user on the remote X2Go server and terminate them.
@@ -2147,7 +2196,10 @@ class X2goClient(object):
         """
         _destroy_terminals = not ( self.auto_update_sessionregistry == True)
         session = self.session_registry(session_uuid)
-        session.clean_sessions(destroy_terminals=_destroy_terminals)
+        profile_name = session.get_profile_name()
+        if published_applications is None:
+            published_applications = self.session_profiles.get_profile_config(profile_name)['published']
+        session.clean_sessions(destroy_terminals=_destroy_terminals, published_applications=published_applications)
     __clean_sessions = clean_sessions
 
     def list_sessions(self, session_uuid=None, 
diff --git a/x2go/defaults.py b/x2go/defaults.py
index 57e30a3..ce9190f 100644
--- a/x2go/defaults.py
+++ b/x2go/defaults.py
@@ -283,7 +283,7 @@ X2GO_SESSIONPROFILE_DEFAULTS = {
     'sound': False, 'soundsystem': 'pulse', 'startsoundsystem': False, 'soundtunnel':True, 'defsndport':True, 'sndport':4713,
     'name': 'NEW_PROFILE', 'icon': ':icons/128x128/x2gosession.png',
     'host': '', 'user': CURRENT_LOCAL_USER, 'key': '', 'sshport': 22, 'krblogin': False,
-    'rootless': True, 'applications': X2GO_GENERIC_APPLICATIONS, 'command':'TERMINAL',
+    'rootless': True, 'applications': X2GO_GENERIC_APPLICATIONS, 'command':'TERMINAL', 'published': False,
     'rdpoptions': '-u X2GO_USER -p X2GO_PASSWORD', 'rdpserver': '',
     'print': False,
     'xdmcpserver': 'localhost',
@@ -406,3 +406,4 @@ X2GO_MIMEBOX_EXTENSIONS_BLACKLIST = [
 # X2Go desktop sharing
 X2GO_SHARE_VIEWONLY=0
 X2GO_SHARE_FULLACCESS=1
+
diff --git a/x2go/registry.py b/x2go/registry.py
index 4fe08a0..0d06a03 100644
--- a/x2go/registry.py
+++ b/x2go/registry.py
@@ -283,6 +283,11 @@ class X2goSessionRegistry(object):
                             self.master_sessions[_profile_name] = self(_session_uuid)
                             self(_session_uuid).set_master_session()
 
+                        elif self(_session_uuid).published_applications:
+                            self(self.master_sessions[_profile_name]()).unset_master_session()
+                            self.master_sessions[_profile_name] = self(_session_uuid)
+                            self(_session_uuid).set_master_session()
+
                         if _last_status['suspended']:
                             # from a suspended state
                             self.client_instance.HOOK_on_session_has_resumed_by_me(session_uuid=_session_uuid, profile_name=_profile_name, session_name=_session_name)
@@ -327,9 +332,13 @@ class X2goSessionRegistry(object):
                 if len(self.virgin_sessions_of_profile_name(profile_name)) > 1:
                     self.forget(_session_uuid)
 
-        for _profile_name in self.connected_profiles(return_profile_names=True):
+        for _profile_name in [ p for p in self.connected_profiles(return_profile_names=True) if p not in self.master_sessions.keys() ]:
             _running_sessions = self.running_sessions_of_profile_name(_profile_name)
-            if _profile_name not in self.master_sessions.keys() and _running_sessions:
+            _pubapp_sessions = [ _s for _s in self.pubapp_sessions_of_profile_name(_profile_name) if _s in _running_sessions ]
+            if _pubapp_sessions:
+                self.master_sessions[_profile_name] = _pubapp_sessions[0]
+                _pubapp_sessions[0].set_master_session()
+            elif _running_sessions:
                 self.master_sessions[_profile_name] = _running_sessions[0]
                 _running_sessions[0].set_master_session()
 
@@ -805,6 +814,28 @@ class X2goSessionRegistry(object):
         else:
             return self.associated_sessions() and [ s.get_uuid() for s in self.associated_sessions() if s.profile_name == profile_name ]
 
+    def pubapp_sessions_of_profile_name(self, profile_name, return_objects=True, return_session_names=False):
+        """\
+        For a given session profile name retrieve a list of sessions that can be providers for published application list.
+        If none of the C{return_*} options is specified a list of session UUID hashes will be returned.
+
+        @param profile_name: session profile name
+        @type profile_name: C{str}
+        @param return_objects: return as list of L{X2goSession} instances
+        @type return_objects: C{bool}
+        @param return_session_names: return as list of X2Go session names
+        @type return_session_names: C{bool}
+        @return: a session list (as UUID hashes, objects or session names)
+        @rtype: C{list}
+
+        """
+        if return_objects:
+            return self.associated_sessions() and [ s for s in self.associated_sessions() if s.published_applications ]
+        elif return_session_names:
+            return self.associated_sessions() and [ s.session_name for s in self.associated_sessions() if s.published_applications ]
+        else:
+            return self.associated_sessions() and [ s.get_uuid() for s in self.associated_sessions() if s.published_applications ]
+
     def registered_sessions_of_profile_name(self, profile_name, return_objects=True, return_session_names=False):
         """\
         For a given session profile name retrieve a list of sessions that are currently registered with this L{X2goClient} instance.
diff --git a/x2go/session.py b/x2go/session.py
index 4fe945c..fa83111 100644
--- a/x2go/session.py
+++ b/x2go/session.py
@@ -34,6 +34,7 @@ import types
 import uuid
 import time
 import gevent
+import re
 
 # Python X2Go modules
 import log
@@ -66,7 +67,7 @@ _X2GO_SESSION_PARAMS = ('geometry', 'depth', 'link', 'pack',
                         'rootdir', 'loglevel', 'profile_name', 'profile_id',
                         'print_action', 'print_action_args',
                         'convert_encoding', 'client_encoding', 'server_encoding',
-                        'proxy_options', 
+                        'proxy_options', 'published_applications',
                         'logger',
                         'control_backend', 'terminal_backend', 'proxy_backend',
                         'profiles_backend', 'settings_backend', 'printing_backend',
@@ -230,6 +231,21 @@ class X2goSession(object):
         self.ssh_rootdir = ssh_rootdir
         self.control_session = control_session
 
+        if params.has_key('published_applications'):
+            self.published_applications = params['published_applications']
+            if self.published_applications:
+                params['cmd'] = 'PUBLISHED'
+        else:
+            self.published_applications = params['published_applications'] = False
+
+        if params.has_key('cmd') and params['cmd'] != 'PUBLISHED':
+            self.published_applications = params['published_applications'] = False
+        self.published_applications_menu = None
+
+        if self.session_name:
+            if not re.match('.*_stRPUBLISHED_.*',self.session_name):
+                self.published_applications = params['published_applications'] = False
+
         self.control_params = {}
         self.terminal_params = {}
         self.sshproxy_params = {}
@@ -279,6 +295,10 @@ class X2goSession(object):
         self.init_control_session()
         self.terminal_session = None
 
+        if self.is_connected():
+            self.retrieve_server_features()
+
+
     def HOOK_session_startup_failed(self):
         """\
         HOOK method: called if the startup of a session failed.
@@ -683,6 +703,8 @@ class X2goSession(object):
         @rtype: C{str}
 
         """
+        if self.has_terminal_session():
+            return self.terminal_session.get_session_cmd()
         if self.terminal_params.has_key('cmd'):
             return self.terminal_params['cmd']
         return None
@@ -954,6 +976,18 @@ class X2goSession(object):
         """
         return self.server_features
 
+    def has_server_feature(self, feature):
+        """\
+        Check if C{feature} is a present feature of the connected X2Go server.
+
+        @param feature: an X2Go server feature as found in C{$SHAREDIR/x2go/feature.d/*}
+        @type feature: C{str}
+        @return: C{True} if the feature is presend
+        @rtype: C{bool}
+
+        """
+        return feature in self.get_server_features()
+
     def set_session_window_title(self, title=''):
         """\
         Modify session window title. If the session ID does not occur in the
@@ -1011,7 +1045,7 @@ class X2goSession(object):
         return self.connected
     __is_alive = is_alive
 
-    def clean_sessions(self, destroy_terminals=True):
+    def clean_sessions(self, destroy_terminals=True, published_applications=False):
         """\
         Clean all running sessions for the authenticated user on the remote X2Go server.
 
@@ -1024,7 +1058,7 @@ class X2goSession(object):
             except x2go_exceptions.X2goSessionException:
                 pass
 
-            self.control_session.clean_sessions(destroy_terminals=destroy_terminals)
+            self.control_session.clean_sessions(destroy_terminals=destroy_terminals, published_applications=published_applications)
         else:
             self._X2goSession__disconnect()
     __clean_sessions = clean_sessions
@@ -1138,14 +1172,13 @@ class X2goSession(object):
                     self.terminated = not (self.running or self.suspended)
                 else:
                     self.terminated = None
-            except KeyError:
+            except KeyError, e:
                 self.running = False
                 self.suspended = False
                 if not self.virgin:
                     self.terminated = True
             self.faulty = not (self.running or self.suspended or self.terminated or self.virgin)
 
-
         self._current_status = {
             'timestamp': time.time(),
             'server': self.server,
@@ -1161,9 +1194,46 @@ class X2goSession(object):
             raise e
 
         return True
-
     __update_status = update_status
 
+    def is_published_applications_provider(self):
+        """\
+        Returns true if this session runs in published applications mode.
+
+        @return: Returns C{True} is this session is a provider session for published applications.
+        @rtype: C{bool}
+
+        """
+        if self.is_running() and self.has_terminal_session():
+            return self.terminal_session.is_published_applications_provider()
+        return False
+
+    def get_published_applications(self):
+        """\
+        Return a list of published menu items from the X2Go server
+        for session type published applications.
+
+        @return: A C{list} of C{dict} elements. Each C{dict} elements has a 
+            C{desktop} key containing the text output of a .desktop file and
+            an C{icon} key which contains the desktop icon data base64 encoded 
+        @rtype: C{list}
+
+        """
+        return self.control_session.get_published_applications()
+
+    def exec_published_application(self, exec_name):
+        """\
+        Execute an application while in published application mode.
+
+        @param exec_name: command to execute on server
+        @type exec_name: C{str}
+
+        """
+        if self.terminal_session is not None:
+            self.logger('for %s executing published application: %s' % (self.profile_name, exec_name), loglevel=log.loglevel_NOTICE)
+            self.terminal_session.exec_published_application(exec_name)
+    __exec_published_application = exec_published_application
+
     def resume(self, session_name=None):
         """\
         Resume or continue a suspended / running X2Go session on the
@@ -1189,7 +1259,14 @@ class X2goSession(object):
             # sockets, thus  we plainly have to wait a while
             if self.is_running():
                 self.suspend()
-                gevent.sleep(10)
+                gevent.sleep(5)
+
+            try:
+                if self.published_applications:
+                    self.published_applications_menu = self.get_published_applications()
+            except:
+                # FIXME: test the code to see what exceptions may occur here...
+                raise
 
             self.terminal_session = _control.resume(session_name=self.session_name,
                                                     session_instance=self,
@@ -1209,6 +1286,9 @@ class X2goSession(object):
                 if _new_session:
                     self.terminal_session.run_command(env=self.session_environment)
 
+                if self.get_session_cmd() != 'PUBLISHED':
+                    self.published_applications = False
+
                 if self._SUPPORTED_SOUND and self.terminal_session.params.snd_system is not 'none':
                     self.terminal_session and not self.faulty and self.terminal_session.start_sound()
                 else:
diff --git a/x2go/utils.py b/x2go/utils.py
index 8bec574..1b23cdc 100644
--- a/x2go/utils.py
+++ b/x2go/utils.py
@@ -166,6 +166,7 @@ def _convert_SessionProfileOptions_2_SessionParams(_options):
             'sshproxytunnel': 'sshproxy_tunnel',
             'sessiontitle': 'session_title',
             'setsessiontitle': 'set_session_title',
+            'published': 'published_applications',
     }
     _speed_dict = {
             '0': 'modem',
@@ -505,9 +506,12 @@ def set_session_window_title(session_window, session_title):
 
     """
     if _X2GOCLIENT_OS != 'Windows':
-        session_window.set_wm_name(str(session_title))
-        session_window.set_wm_icon_name(str(session_title))
-        _X_DISPLAY.sync()
+        try:
+            session_window.set_wm_name(str(session_title))
+            session_window.set_wm_icon_name(str(session_title))
+            _X_DISPLAY.sync()
+        except Xlib.error.BadWindow:
+            pass
 
 def raise_session_window(session_window):
     """\


hooks/post-receive
-- 
python-x2go.git (Python X2Go Client API)

This is an automated email from the git hooks/post-receive script. It was
generated because a ref change was pushed to the repository containing
the project "python-x2go.git" (Python X2Go Client API).




More information about the x2go-commits mailing list