[gnome-boxes/fallback-to-vnc] Make Boxes use Vnc when SPICE is not available




commit c2a5bfed1ce507c4ae44cd962bc890ce4265add6
Author: Felipe Borges <felipeborges gnome org>
Date:   Wed Jul 7 15:52:57 2021 +0200

    Make Boxes use Vnc when SPICE is not available
    
    This is a fallback codepath for when SPICE is not available. This
    makes Boxes regress in tons of features that SPICE provides which
    don't have (yet) a Vnc counterpart.

 src/app.vala                        |  2 ++
 src/display-page.vala               |  6 ++++
 src/libvirt-machine-properties.vala |  3 +-
 src/libvirt-machine.vala            |  8 +++++
 src/meson.build                     | 21 ++++++++++----
 src/remote-machine.vala             |  2 ++
 src/vm-configurator.vala            | 58 +++++++++++++++++++++++--------------
 7 files changed, 72 insertions(+), 28 deletions(-)
---
diff --git a/src/app.vala b/src/app.vala
index ce8b49b6..4764932b 100644
--- a/src/app.vala
+++ b/src/app.vala
@@ -207,7 +207,9 @@ public override int command_line (GLib.ApplicationCommandLine cmdline) {
         var parameter_string = _("— A simple application to access virtual machines");
         var opt_context = new OptionContext (parameter_string);
         opt_context.add_main_entries (options, null);
+#if HAS_SPICE
         opt_context.add_group (Spice.get_option_group ());
+#endif
         opt_context.add_group (Vnc.Display.get_option_group ());
         opt_context.add_group (Gtk.get_option_group (true));
         opt_context.set_help_enabled (false);
diff --git a/src/display-page.vala b/src/display-page.vala
index 1fc1b4a1..d30d898e 100644
--- a/src/display-page.vala
+++ b/src/display-page.vala
@@ -20,7 +20,9 @@
     private unowned DisplayToolbar overlay_toolbar;
     [GtkChild]
     private unowned EventBox overlay_toolbar_box;
+#if HAS_SPICE
     public Boxes.TransferPopover transfer_popover;
+#endif
     private uint toolbar_hide_id;
     private uint toolbar_show_id;
     private ulong cursor_id;
@@ -79,7 +81,9 @@ public void setup_ui (AppWindow window) {
         target_list += urilist_entry;
 
         drag_dest_set (transfer_message_box, Gtk.DestDefaults.DROP, target_list, DragAction.ASK);
+#if HAS_SPICE
         transfer_popover = new Boxes.TransferPopover (window.topbar.display_toolbar);
+#endif
     }
 
      private void update_toolbar_visible() {
@@ -92,7 +96,9 @@ private void update_toolbar_visible() {
      }
 
      public void add_transfer (Object transfer_task) {
+#if HAS_SPICE
         transfer_popover.add_transfer (transfer_task);
+#endif
      }
 
      private void set_overlay_toolbar_visible(bool visible) {
diff --git a/src/libvirt-machine-properties.vala b/src/libvirt-machine-properties.vala
index 1ff52fb1..117bbf0f 100644
--- a/src/libvirt-machine-properties.vala
+++ b/src/libvirt-machine-properties.vala
@@ -115,8 +115,9 @@ public string collect_logs () {
                     // Translators: This is the URL to connect to the display/desktop. e.g 
spice://somehost:5051.
                     add_string_property (ref list, _("Display URL"), machine.display.uri);
             }
-
+#if HAVE_SPICE
             add_3d_acceleration_property (ref list);
+#endif
 
             break;
 
diff --git a/src/libvirt-machine.vala b/src/libvirt-machine.vala
index 8b0513df..144e8407 100644
--- a/src/libvirt-machine.vala
+++ b/src/libvirt-machine.vala
@@ -53,12 +53,17 @@
     private bool _acceleration_3d;
     public bool acceleration_3d {
         get {
+#if HAS_SPICE
             return _acceleration_3d;
+#else
+            return false;
+#endif
         }
 
         set {
             _acceleration_3d = value;
 
+#if HAS_SPICE
             GLib.List<GVirConfig.DomainDevice> devices = null;
             foreach (var device in domain_config.get_devices ()) {
                 if (device is GVirConfig.DomainGraphicsSpice) {
@@ -83,6 +88,7 @@
             } catch (GLib.Error error) {
                 warning ("Failed to disable 3D Acceleration");
             }
+#endif
         }
     }
 
@@ -463,11 +469,13 @@ public bool update_display () throws GLib.Error {
             host = "localhost";
 
         switch (type) {
+#if HAS_SPICE
         case "spice":
             if (port > 0)
                 return new SpiceDisplay (this, config, host, port);
             else
                 return new SpiceDisplay.priv (this, config);
+#endif
 
         case "vnc":
             return new VncDisplay (config, host, port);
diff --git a/src/meson.build b/src/meson.build
index 8577d643..5f546576 100644
--- a/src/meson.build
+++ b/src/meson.build
@@ -89,10 +89,8 @@ vala_sources = [
   'selectionbar.vala',
   'selection-toolbar.vala',
   'shared-folders.vala',
-  'spice-display.vala',
   'config-editor.vala',
   'transfer-info-row.vala',
-  'transfer-popover.vala',
   'troubleshoot-view.vala',
   'topbar.vala',
   'ui.vala',
@@ -103,9 +101,9 @@ vala_sources = [
   'vm-configurator.vala',
   'vm-creator.vala',
   'vm-importer.vala',
+  'vnc-display.vala',
   'libvirt-vm-cloner.vala',
   'libvirt-vm-importer.vala',
-  'vnc-display.vala',
   'welcome-tutorial.vala',
   'welcome-tutorial-page.vala',
   'downloader.vala',
@@ -134,16 +132,29 @@ dependencies = [
   dependency ('libvirt-gconfig-1.0', version: '>= 4.0.0'),
   dependency ('libvirt-gobject-1.0', version: '>= 4.0.0'),
   dependency ('libxml-2.0', version: '>= 2.7.8'),
-  dependency ('spice-client-gtk-3.0', version: '>= 0.32'),
   dependency ('tracker-sparql-3.0'),
   dependency ('webkit2gtk-4.0', version: '>= 2.26.0'),
   cc.find_library('m', required : false),
   valac.find_library ('gio-2.0-workaround', dirs: vapi_dir),
   valac.find_library ('linux'),
   valac.find_library ('posix'),
-  valac.find_library ('spice-client-gtk-3.0'),
 ]
 
+spice = dependency ('spice-client-gtk-3.0', version: '>= 0.32')
+if spice.found ()
+  vala_args += '--define=HAS_SPICE'
+
+  dependencies += [
+    spice,
+    valac.find_library ('spice-client-gtk-3.0')
+  ]
+
+  vala_sources += [
+    'spice-display.vala',
+    'transfer-popover.vala'
+  ]
+endif
+
 libhandy = dependency ('libhandy-1', version: '>= 1.0.0', required: false)
 if not libhandy.found()
   libhandy = subproject(
diff --git a/src/remote-machine.vala b/src/remote-machine.vala
index 54c1a2b7..76705191 100644
--- a/src/remote-machine.vala
+++ b/src/remote-machine.vala
@@ -30,8 +30,10 @@ public RemoteMachine (CollectionSource source) throws Boxes.Error {
         var type = source.source_type;
 
         switch (type) {
+#if HAS_SPICE
         case "spice":
             return new SpiceDisplay.with_uri (this, config, source.uri);
+#endif
 
         case "vnc":
             return new VncDisplay.with_uri (config, source.uri);
diff --git a/src/vm-configurator.vala b/src/vm-configurator.vala
index 28b8e36b..02b01758 100644
--- a/src/vm-configurator.vala
+++ b/src/vm-configurator.vala
@@ -13,6 +13,7 @@
        future, but this is effectively part of boxes XML API */
     private const string BOXES_NS_URI = "https://wiki.gnome.org/Apps/Boxes";;
     private const string BOXES_OLD_NS_URI = "http://live.gnome.org/Boxes/";;
+    private const string SPICE_AGENT_CHANNEL = "com.redhat.spice.0";
     private const string WEBDAV_CHANNEL_URI = "org.spice-space.webdav.0";
     private const string BOXES_XML = "<gnome-boxes>%s</gnome-boxes>";
     private const string LIVE_STATE = "live";
@@ -38,6 +39,13 @@
     private const string LIBOSINFO_XML = "<libosinfo>%s</libosinfo>";
     private const string LIBOSINFO_OS_ID_XML = "<os id=\"%s\"/>";
 
+    private const bool SPICE_AVAILABLE =
+#if HAS_SPICE
+        true;
+#else
+        false;
+#endif
+
     public static Domain create_domain_config (InstallerMedia install_media, string target_path, 
Capabilities caps, DomainCapabilities domain_caps)
                                         throws VMConfiguratorError {
         var domain = new Domain ();
@@ -86,21 +94,6 @@ public static Domain create_domain_config (InstallerMedia install_media, string
         set_target_media_config (domain, target_path, install_media);
         install_media.setup_domain_config (domain);
 
-        var graphics = create_graphics_device ();
-        domain.add_device (graphics);
-
-        // SPICE agent channel. This is needed for features like copy and paste between host and guest etc 
to work.
-        var channel = new DomainChannel ();
-        channel.set_target_type (DomainChannelTargetType.VIRTIO);
-        channel.set_target_name ("com.redhat.spice.0");
-        var vmc = new DomainChardevSourceSpiceVmc ();
-        channel.set_source (vmc);
-        domain.add_device (channel);
-
-        // Webdav channel. This is needed for the shared folder feature to work.
-        var webdav_channel = create_webdav_channel ();
-        domain.add_device (webdav_channel);
-
         add_usb_support (domain, install_media);
 #if !FLATPAK
         add_smartcard_support (domain);
@@ -273,16 +266,21 @@ public static async void update_existing_domain (Domain          domain,
 
         GLib.List<GVirConfig.DomainDevice> devices = null;
         DomainInterface iface = null;
-        DomainChannel channel_webdav = null;
         bool supports_alternative_boot_device = false;
         foreach (var device in domain.get_devices ()) {
+            // Let's always re-create the graphics device, so we can switch from SPICE
+            // to VNC and back according to SPICE's availability in the build.
+            if (device is DomainGraphics)
+                continue;
+
             if (device is DomainInterface)
                 iface = device as DomainInterface;
             else if (device is DomainChannel) {
                 var device_channel = device as DomainChannel;
                 if (device_channel.get_target_name () == WEBDAV_CHANNEL_URI)
-                    channel_webdav = device_channel;
-                devices.prepend (device);
+                    continue;
+                else if (device_channel.get_target_name () == SPICE_AGENT_CHANNEL)
+                    continue;
             }
             else if (device is DomainDisk) {
                 var domain_disk = device as DomainDisk;
@@ -304,6 +302,14 @@ else if (device is DomainDisk) {
                 devices.prepend (device);
         }
 
+        if (SPICE_AVAILABLE) {
+            devices.prepend (create_spice_webdav_channel ());
+            devices.prepend (create_spice_agent_channel ());
+            devices.prepend (create_graphics_device ());
+        } else {
+            devices.prepend (new DomainGraphicsVnc ());
+        }
+
         // If user interface device was found and it needs to be bridged
         if (iface != null) {
             var bridge = is_libvirt_bridge_net_available ();
@@ -318,9 +324,6 @@ else if (device is DomainDisk) {
 
         enable_boot_menu (domain, supports_alternative_boot_device);
 
-        if (channel_webdav == null)
-            devices.prepend (create_webdav_channel ());
-
         devices.reverse ();
         domain.set_devices (devices);
     }
@@ -700,6 +703,17 @@ public static DomainInterface create_network_interface (Domain domain, bool brid
         return iface;
     }
 
+    private static DomainChannel create_spice_agent_channel () {
+        // SPICE agent channel. This is needed for features like copy and paste between host and guest etc 
to work.
+        var channel = new DomainChannel ();
+        channel.set_target_type (DomainChannelTargetType.VIRTIO);
+        channel.set_target_name (SPICE_AGENT_CHANNEL);
+        var vmc = new DomainChardevSourceSpiceVmc ();
+        channel.set_source (vmc);
+
+        return channel;
+    }
+
     public static DomainGraphicsSpice create_graphics_device (bool accel3d = false) {
         var graphics = new DomainGraphicsSpice ();
         graphics.set_autoport (false);
@@ -709,7 +723,7 @@ public static DomainGraphicsSpice create_graphics_device (bool accel3d = false)
         return graphics;
     }
 
-    public static DomainChannel create_webdav_channel () {
+    public static DomainChannel create_spice_webdav_channel () {
         var channel_webdav = new DomainChannel ();
         channel_webdav.set_target_type (DomainChannelTargetType.VIRTIO);
         channel_webdav.set_target_name (WEBDAV_CHANNEL_URI);


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]