Signed-off-by: Hans de Goede <hdegoede@xxxxxxxxxx> --- doc/reference/spice-gtk-sections.txt | 2 + gtk/map-file | 2 + gtk/usb-device-manager.c | 130 ++++++++++++++++++++++++++++++++-- gtk/usb-device-manager.h | 5 ++ 4 files changed, 132 insertions(+), 7 deletions(-) diff --git a/doc/reference/spice-gtk-sections.txt b/doc/reference/spice-gtk-sections.txt index a339d32..7eea1fb 100644 --- a/doc/reference/spice-gtk-sections.txt +++ b/doc/reference/spice-gtk-sections.txt @@ -293,6 +293,8 @@ spice_usb_device_manager_disconnect_device spice_usb_device_manager_can_redirect_device spice_usb_device_manager_connect_device_async spice_usb_device_manager_connect_device_finish +spice_usb_device_manager_disable_automounting +spice_usb_device_manager_restore_automounting <SUBSECTION> SpiceUsbDevice spice_usb_device_get_description diff --git a/gtk/map-file b/gtk/map-file index 32ead37..dd3495c 100644 --- a/gtk/map-file +++ b/gtk/map-file @@ -89,11 +89,13 @@ spice_usb_device_get_type; spice_usb_device_manager_can_redirect_device; spice_usb_device_manager_connect_device_async; spice_usb_device_manager_connect_device_finish; +spice_usb_device_manager_disable_automounting; spice_usb_device_manager_disconnect_device; spice_usb_device_manager_get; spice_usb_device_manager_get_devices; spice_usb_device_manager_get_type; spice_usb_device_manager_is_device_connected; +spice_usb_device_manager_restore_automounting; spice_usb_device_widget_get_type; spice_usb_device_widget_new; spice_usbredir_channel_get_type; diff --git a/gtk/usb-device-manager.c b/gtk/usb-device-manager.c index 25cb14a..bf08b95 100644 --- a/gtk/usb-device-manager.c +++ b/gtk/usb-device-manager.c @@ -34,6 +34,7 @@ #include "usbutil.h" #endif +#include "desktop-integration.h" #include "spice-session-priv.h" #include "spice-client.h" #include "spice-marshal.h" @@ -96,6 +97,8 @@ struct _SpiceUsbDeviceManagerPrivate { libusb_device **coldplug_list; /* Avoid needless reprobing during init */ struct usbredirfilter_rule *auto_conn_filter_rules; int auto_conn_filter_rules_count; + int disable_automount; + guint update_automount_id; #endif GPtrArray *devices; GPtrArray *channels; @@ -284,9 +287,17 @@ static void spice_usb_device_manager_set_property(GObject *gobject, case PROP_SESSION: priv->session = g_value_get_object(value); break; - case PROP_AUTO_CONNECT: - priv->auto_connect = g_value_get_boolean(value); + case PROP_AUTO_CONNECT: { + gboolean new_val = g_value_get_boolean(value); + if (priv->auto_connect != new_val) { + priv->auto_connect = new_val; + if (priv->auto_connect) + spice_usb_device_manager_disable_automounting(self); + else + spice_usb_device_manager_restore_automounting(self); + } break; + } case PROP_AUTO_CONNECT_FILTER: { const gchar *filter = g_value_get_string(value); #ifdef USE_USBREDIR @@ -341,6 +352,15 @@ static void spice_usb_device_manager_class_init(SpiceUsbDeviceManagerClass *klas /** * SpiceUsbDeviceManager:auto-connect: + * + * Set this to TRUE to automatically redirect newly plugged in device. + * + * When this property changes from FALSE to TRUE, #SpiceUsbDeviceManager + * calls spice_usb_device_manager_disable_automounting() once, and on TRUE + * to FALSE it calls spice_usb_device_manager_restore_automounting(). + * + * Note when #SpiceGtkSession's auto-usbredir property is TRUE, this + * property is controlled by #SpiceGtkSession. */ pspec = g_param_spec_boolean("auto-connect", "Auto Connect", "Auto connect plugged in USB devices", @@ -642,19 +662,33 @@ static void spice_usb_device_manager_uevent_cb(GUdevClient *client, spice_usb_device_manager_remove_dev(self, udevice); } +struct channel_connect_cb_data { + GSimpleAsyncResult *result; + gboolean restore_automount; +}; + static void spice_usb_device_manager_channel_connect_cb( GObject *gobject, GAsyncResult *channel_res, gpointer user_data) { SpiceUsbredirChannel *channel = SPICE_USBREDIR_CHANNEL(gobject); - GSimpleAsyncResult *result = G_SIMPLE_ASYNC_RESULT(user_data); + struct channel_connect_cb_data *data = user_data; + SpiceUsbDeviceManager *self; GError *err = NULL; spice_usbredir_channel_connect_device_finish(channel, channel_res, &err); if (err) { - g_simple_async_result_take_error(result, err); + g_simple_async_result_take_error(data->result, err); } - g_simple_async_result_complete(result); - g_object_unref(result); + + if (data->restore_automount) { + self = SPICE_USB_DEVICE_MANAGER(g_async_result_get_source_object( + G_ASYNC_RESULT(data->result))); + spice_usb_device_manager_restore_automounting(self); + } + + g_simple_async_result_complete(data->result); + g_object_unref(data->result); + g_free(data); } /* ------------------------------------------------------------------ */ @@ -848,6 +882,7 @@ void spice_usb_device_manager_connect_device_async(SpiceUsbDeviceManager *self, #ifdef USE_USBREDIR SpiceUsbDeviceManagerPrivate *priv = self->priv; + struct channel_connect_cb_data *data; guint i; if (spice_usb_device_manager_is_device_connected(self, device)) { @@ -863,11 +898,18 @@ void spice_usb_device_manager_connect_device_async(SpiceUsbDeviceManager *self, if (spice_usbredir_channel_get_device(channel)) continue; /* Skip already used channels */ + data = g_new0(struct channel_connect_cb_data, 1); + data->result = result; + /* If automount is disabled, ensure it stays disabled while we run */ + if (priv->disable_automount) { + spice_usb_device_manager_disable_automounting(self); + data->restore_automount = TRUE; + } spice_usbredir_channel_connect_device_async(channel, (libusb_device *)device, cancellable, spice_usb_device_manager_channel_connect_cb, - result); + data); return; } #endif @@ -1047,3 +1089,77 @@ gchar *spice_usb_device_get_description(SpiceUsbDevice *_device, const gchar *fo return NULL; #endif } + +/* ------------------------------------------------------------------ */ +/* Automount disable helper functions */ + +static gboolean spice_usb_device_manager_update_automount(gpointer user_data) +{ + SpiceUsbDeviceManager *self = SPICE_USB_DEVICE_MANAGER(user_data); + SpiceUsbDeviceManagerPrivate *priv = self->priv; + SpiceDesktopIntegration *di = spice_desktop_integration_get(priv->session); + + if (priv->disable_automount == 0) + spice_desktop_integration_restore_automount(di); + + priv->update_automount_id = 0; + return FALSE; +} + +/** + * spice_usb_device_manager_disable_automounting: + * @manager: the #SpiceUsbDeviceManager manager + * + * Disables automounting of newly plugged in devices by the client OS, to avoid + * newly plugged in devices getting mounted by the client OS, before they can + * be redirected. + * + * When this function gets called multiple times, + * spice_usb_device_manager_restore_automounting() must be called the same + * amount of times, before automounting gets restored. + */ +void spice_usb_device_manager_disable_automounting(SpiceUsbDeviceManager *self) +{ +#ifdef USE_USBREDIR + SpiceUsbDeviceManagerPrivate *priv = self->priv; + SpiceDesktopIntegration *di = spice_desktop_integration_get(priv->session); + + priv->disable_automount++; + if (priv->disable_automount == 1) + spice_desktop_integration_disable_automount(di); +#endif +} + +/** + * spice_usb_device_manager_restore_automounting: + * @manager: the #SpiceUsbDeviceManager manager + * + * Restores automounting of newly plugged in devices by the client OS, to its + * original state. If it was disabled already before calling + * spice_usb_device_manager_disable_automounting() this is a no-op. + * + * If spice_usb_device_manager_disable_automounting() has been called multiple + * times, this function will not restore automounting until it has been called + * the same amount of times. + */ +void spice_usb_device_manager_restore_automounting(SpiceUsbDeviceManager *self) +{ +#ifdef USE_USBREDIR + SpiceUsbDeviceManagerPrivate *priv = self->priv; + + g_return_if_fail(priv->disable_automount > 0); + + priv->disable_automount--; + if (priv->disable_automount) + return; + + /* + * Re-enable automount from a timer, to avoid unnecessary ping-ponging + * automount when switching between the windows of a multi monitor vm. + */ + if (priv->update_automount_id) + g_source_remove(priv->update_automount_id); + priv->update_automount_id = + g_timeout_add(50, spice_usb_device_manager_update_automount, self); +#endif +} diff --git a/gtk/usb-device-manager.h b/gtk/usb-device-manager.h index df138ee..b01fe98 100644 --- a/gtk/usb-device-manager.h +++ b/gtk/usb-device-manager.h @@ -114,6 +114,11 @@ spice_usb_device_manager_can_redirect_device(SpiceUsbDeviceManager *self, SpiceUsbDevice *device, GError **err); +void spice_usb_device_manager_disable_automounting( + SpiceUsbDeviceManager *manager); +void spice_usb_device_manager_restore_automounting( + SpiceUsbDeviceManager *manager); + G_END_DECLS #endif /* __SPICE_USB_DEVICE_MANAGER_H__ */ -- 1.7.10.2 _______________________________________________ Spice-devel mailing list Spice-devel@xxxxxxxxxxxxxxxxxxxxx http://lists.freedesktop.org/mailman/listinfo/spice-devel