From 529b638d7c9368e67fb6064f6849ded5a55640d0 Mon Sep 17 00:00:00 2001 From: Benjamin Gilbert Date: Fri, 23 May 2014 19:07:32 -0400 Subject: [PATCH] vmnetx.ui.view: Fix missing guest mouse cursor in some sessions We can't use channel.connect() to connect a GObject signal because SpiceChannel overrides connect() to mean "initiate a TCP connection". Instead, we were using channel.connect_object(..., channel), but this creates a reference cycle between the channel PyGObject and the underlying GObject. With connect(), the PyGObject would be destroyed after _new_channel() and recreated (pointing to the same GObject) before the _request_fd() callback. With connect_object(), the PyGObject is referenced from the signal handler closure and so is never freed. However, if the Python GC runs between _new_channel() and _request_fd(), it will detect a reference cycle and clear the PyGObject's reference to the GObject. This was happening to the cursor channel on RHEL 6; _request_fd() would receive an invalid PyGObject and then swallow the resulting TypeError. As a result, the cursor channel would never be connected, and the guest cursor (for VMs supporting a hardware cursor) would always be invisible. Use connect() instead of connect_object(), explicitly calling it through the superclass. --- vmnetx/ui/view.py | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/vmnetx/ui/view.py b/vmnetx/ui/view.py index 3336795..1b3de34 100644 --- a/vmnetx/ui/view.py +++ b/vmnetx/ui/view.py @@ -20,6 +20,7 @@ from distutils.version import LooseVersion import glib import gobject +from gobject import GObject import gtk import logging import pango @@ -285,23 +286,22 @@ def _connect_viewer(self, password): except RuntimeError: # No local PulseAudio, etc. pass - self._session.connect_object('channel-new', self._new_channel, - self._session) + GObject.connect(self._session, 'channel-new', self._new_channel) self._session.open_fd(-1) def _new_channel(self, session, channel): if session != self._session: # Stale channel; ignore return - channel.connect_object('open-fd', self._request_fd, channel) - channel.connect_object('channel-event', self._channel_event, channel) + GObject.connect(channel, 'open-fd', self._request_fd) + GObject.connect(channel, 'channel-event', self._channel_event) type = SpiceClientGtk.spice_channel_type_to_string( channel.get_property('channel-type')) if type == 'display': # Create the display but don't show it until configured by # the server - channel.connect_object('display-primary-create', - self._display_create, channel) + GObject.connect(channel, 'display-primary-create', + self._display_create) self._destroy_display() self._display_channel = channel self._display = SpiceClientGtk.Display(self._session,