Merge branch 'main' into docker

This commit is contained in:
Wayne Heaney 2024-07-18 17:37:41 -07:00 committed by GitHub
commit c0a04e29f7
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
9 changed files with 142 additions and 28 deletions

View File

@ -16,11 +16,17 @@ There are two installations at the moment. **Note: Only install one of these at
Breezy GNOME is a virtual workspace solution for Linux desktops that use the GNOME desktop environment (requires GNOME 45+ on an x86_64 system); see [non-GNOME setup](#non-gnome-setup) if you want to try it without a GNOME desktop environment. It currently supports one virtual monitor and multiple physical monitors, but it will soon support multiple virtual monitors. See [upcoming features](#upcoming-features) for more improvements on the horizon. Breezy GNOME is a virtual workspace solution for Linux desktops that use the GNOME desktop environment (requires GNOME 45+ on an x86_64 system); see [non-GNOME setup](#non-gnome-setup) if you want to try it without a GNOME desktop environment. It currently supports one virtual monitor and multiple physical monitors, but it will soon support multiple virtual monitors. See [upcoming features](#upcoming-features) for more improvements on the horizon.
### GNOME Setup ### GNOME Setup
1. Ensure you have the latest graphics drivers installed for your distro.
2. Download the Breezy GNOME [setup script](https://github.com/wheaney/breezy-desktop/releases/latest/download/breezy_gnome_setup) and set the execute flag (e.g. from the terminal: `chmod +x ~/Downloads/breezy_gnome_setup`) For the best performance, ensure you have the latest graphics drivers installed for your distro.
3. Run the setup script (e.g. `~/Downloads/breezy_gnome_setup`)
4. You'll have an application called `Breezy Desktop` installed. Launch that and follow any instructions. You will need to log out and back in at least once to get the GNOME extension working. #### Arch Linux
5. For a double-wide screen, enable "widescreen mode" using the toggle in the Breezy Desktop application. **Note: this can be significantly more resource intensive than non-widescreen, you may notice performance dips on older hardware**
Breezy GNOME is in AUR (but not pacman, yet). To install: `yay -S breezy-desktop-gnome-git`
#### All other distros
1. Download the Breezy GNOME [setup script](https://github.com/wheaney/breezy-desktop/releases/latest/download/breezy_gnome_setup) and set the execute flag (e.g. from the terminal: `chmod +x ~/Downloads/breezy_gnome_setup`)
2. Run the setup script (e.g. `~/Downloads/breezy_gnome_setup`)
### Non-GNOME Setup ### Non-GNOME Setup
A workable solution (with some [QoL improvements needed](#upcoming-features)) is to use your preferred desktop environment with a GNOME window open in nested mode. To do this: A workable solution (with some [QoL improvements needed](#upcoming-features)) is to use your preferred desktop environment with a GNOME window open in nested mode. To do this:
@ -29,7 +35,10 @@ A workable solution (with some [QoL improvements needed](#upcoming-features)) is
3. Launch the nested GNOME Shell using `MUTTER_DEBUG_DUMMY_MODE_SPECS="1920x1080@60" dbus-run-session -- gnome-shell --nested` 3. Launch the nested GNOME Shell using `MUTTER_DEBUG_DUMMY_MODE_SPECS="1920x1080@60" dbus-run-session -- gnome-shell --nested`
### Breezy GNOME Usage ### Breezy GNOME Usage
All controls are provided through the Breezy Desktop application. You can also configure keyboard shortcuts for the most common toggle actions. The Breezy Desktop app doesn't have to be running to use the virtual desktop or the keyboard shortcuts once you've configured everything to your liking.
After setup, you'll have an application called `Breezy Desktop` installed. Launch that and follow any instructions. You will need to log out and back in at least once to get the GNOME extension working. You can also configure keyboard shortcuts for the most common toggle actions. The Breezy Desktop app doesn't have to be running to use the virtual desktop or the keyboard shortcuts once you've configured everything to your liking.
For a double-wide screen, enable "widescreen mode" using the toggle in the Breezy Desktop application. **Note: this can be significantly more resource intensive than non-widescreen, you may notice performance dips on older hardware.**
### Upcoming Features ### Upcoming Features
1. Port to GNOME 43/44 1. Port to GNOME 43/44

View File

@ -1,5 +1,4 @@
import Clutter from 'gi://Clutter'; import Clutter from 'gi://Clutter';
import GLib from 'gi://GLib';
import Meta from 'gi://Meta'; import Meta from 'gi://Meta';
import * as PointerWatcher from 'resource:///org/gnome/shell/ui/pointerWatcher.js'; import * as PointerWatcher from 'resource:///org/gnome/shell/ui/pointerWatcher.js';
import { MouseSpriteContent } from './cursor.js'; import { MouseSpriteContent } from './cursor.js';

View File

@ -71,6 +71,7 @@ export default class BreezyDesktopExtension extends Extension {
this._monitor_manager = new MonitorManager({ this._monitor_manager = new MonitorManager({
use_optimal_monitor_config: this.settings.get_boolean('use-optimal-monitor-config'), use_optimal_monitor_config: this.settings.get_boolean('use-optimal-monitor-config'),
headset_as_primary: this.settings.get_boolean('headset-as-primary'), headset_as_primary: this.settings.get_boolean('headset-as-primary'),
use_highest_refresh_rate: this.settings.get_boolean('use-highest-refresh-rate'),
extension_path: this.path extension_path: this.path
}); });
this._monitor_manager.setChangeHook(this._handle_monitor_change.bind(this)); this._monitor_manager.setChangeHook(this._handle_monitor_change.bind(this));
@ -120,7 +121,7 @@ export default class BreezyDesktopExtension extends Extension {
const target_monitor = this._monitor_manager.getMonitorPropertiesList()?.find( const target_monitor = this._monitor_manager.getMonitorPropertiesList()?.find(
monitor => SUPPORTED_MONITOR_PRODUCTS.includes(monitor.product)); monitor => SUPPORTED_MONITOR_PRODUCTS.includes(monitor.product));
if (target_monitor !== undefined) { if (target_monitor !== undefined) {
Globals.logger.log_debug(`BreezyDesktopExtension _find_supported_monitor - Identified supported monitor: ${target_monitor.connector}`); Globals.logger.log(`Identified supported monitor: ${target_monitor.product} on ${target_monitor.connector}`);
return { return {
monitor: this._monitor_manager.getMonitors()[target_monitor.index], monitor: this._monitor_manager.getMonitors()[target_monitor.index],
connector: target_monitor.connector, connector: target_monitor.connector,
@ -151,8 +152,11 @@ export default class BreezyDesktopExtension extends Extension {
// A false result means we'll expect _handle_monitor_change to be triggered, so active polling // A false result means we'll expect _handle_monitor_change to be triggered, so active polling
// can be disabled. // can be disabled.
_target_monitor_ready(target_monitor) { _target_monitor_ready(target_monitor) {
return target_monitor.is_dummy || if (target_monitor.is_dummy) return true;
!this._monitor_manager.needsOptimalModeCheck(target_monitor.connector);
const needs_sbs_mode_switch = this.settings.get_boolean('fast-sbs-mode-switching') &&
this._needs_widescreen_monitor_update();
return !needs_sbs_mode_switch && !this._monitor_manager.needsOptimalModeCheck(target_monitor.connector);
} }
_setup() { _setup() {
@ -213,7 +217,7 @@ export default class BreezyDesktopExtension extends Extension {
const widescreen_setting_enabled = this.settings.get_boolean('widescreen-mode'); const widescreen_setting_enabled = this.settings.get_boolean('widescreen-mode');
if (widescreen_setting_enabled !== sbs_enabled) { if (widescreen_setting_enabled !== sbs_enabled) {
Globals.logger.log_debug('BreezyDesktopExtension _needs_widescreen_monitor_update - true'); Globals.logger.log_debug('BreezyDesktopExtension _needs_widescreen_monitor_update - true');
this._write_control('sbs_mode', widescreen_setting_enabled ? 'enable' : 'disable'); this._request_sbs_mode_change(widescreen_setting_enabled);
return true; return true;
} }
@ -259,7 +263,10 @@ export default class BreezyDesktopExtension extends Extension {
}); });
this._update_follow_threshold(this.settings); this._update_follow_threshold(this.settings);
this._update_widescreen_mode_from_settings(this.settings);
// this gets triggered before _effect_enable if in fast-sbs-mode-switching mode
if (!this.settings.get_boolean('fast-sbs-mode-switching'))
this._update_widescreen_mode_from_settings(this.settings);
this._widescreen_mode_effect_state_connection = this._xr_effect.connect('notify::widescreen-mode-state', this._update_widescreen_mode_from_state.bind(this)); this._widescreen_mode_effect_state_connection = this._xr_effect.connect('notify::widescreen-mode-state', this._update_widescreen_mode_from_state.bind(this));
this._supported_device_detected_connected = this._xr_effect.connect('notify::supported-device-detected', this._handle_supported_device_change.bind(this)); this._supported_device_detected_connected = this._xr_effect.connect('notify::supported-device-detected', this._handle_supported_device_change.bind(this));
@ -362,16 +369,41 @@ export default class BreezyDesktopExtension extends Extension {
if (value !== undefined) this._write_control('breezy_desktop_follow_threshold', value); if (value !== undefined) this._write_control('breezy_desktop_follow_threshold', value);
} }
// requests sbs_mode change and monitors to ensure the state reflects the setting
_request_sbs_mode_change(value) {
this._write_control('sbs_mode', value ? 'enable' : 'disable');
if (!this._sbs_mode_update_timeout) {
var attempts = 0;
this._sbs_mode_update_timeout = GLib.timeout_add(GLib.PRIORITY_DEFAULT, 10000, (() => {
if (attempts++ < 3) {
this._write_control('sbs_mode', value ? 'enable' : 'disable');
return GLib.SOURCE_CONTINUE;
}
// the state never updated to reflect our request, revert the setting
this.settings.set_boolean('widescreen-mode', !value);
this._sbs_mode_update_timeout = undefined;
return GLib.SOURCE_REMOVE;
}).bind(this));
}
}
_update_widescreen_mode_from_settings(settings, event) { _update_widescreen_mode_from_settings(settings, event) {
const value = settings.get_boolean('widescreen-mode'); const value = settings.get_boolean('widescreen-mode');
Globals.logger.log_debug(`BreezyDesktopExtension _update_widescreen_mode_from_settings ${value}`); Globals.logger.log_debug(`BreezyDesktopExtension _update_widescreen_mode_from_settings ${value}`);
if (value !== undefined && value !== this._xr_effect.widescreen_mode_state) if (value !== undefined && value !== this._xr_effect.widescreen_mode_state) {
this._write_control('sbs_mode', value ? 'enable' : 'disable'); this._request_sbs_mode_change(value);
else } else
Globals.logger.log_debug('effect.widescreen_mode_state already matched setting'); Globals.logger.log_debug('effect.widescreen_mode_state already matched setting');
} }
_update_widescreen_mode_from_state(effect, _pspec) { _update_widescreen_mode_from_state(effect, _pspec) {
// kill our state checker if it's running
if (this._sbs_mode_update_timeout) {
GLib.source_remove(this._sbs_mode_update_timeout);
this._sbs_mode_update_timeout = undefined;
}
const value = effect.widescreen_mode_state; const value = effect.widescreen_mode_state;
Globals.logger.log_debug(`BreezyDesktopExtension _update_widescreen_mode_from_state ${value}`); Globals.logger.log_debug(`BreezyDesktopExtension _update_widescreen_mode_from_state ${value}`);
if (value !== this.settings.get_boolean('widescreen-mode')) if (value !== this.settings.get_boolean('widescreen-mode'))

View File

@ -86,7 +86,7 @@ function getMonitorConfig(displayConfigProxy, callback) {
} }
// triggers callback with true result if an an async monitor config change was triggered, false if no config change needed // triggers callback with true result if an an async monitor config change was triggered, false if no config change needed
function performOptimalModeCheck(displayConfigProxy, connectorName, headsetAsPrimary, callback) { function performOptimalModeCheck(displayConfigProxy, connectorName, headsetAsPrimary, useHighestRefreshRate, callback) {
Globals.logger.log_debug(`monitormanager.js performOptimalModeCheck for ${connectorName}`); Globals.logger.log_debug(`monitormanager.js performOptimalModeCheck for ${connectorName}`);
displayConfigProxy.GetCurrentStateRemote((result, error) => { displayConfigProxy.GetCurrentStateRemote((result, error) => {
if (error) { if (error) {
@ -101,10 +101,19 @@ function performOptimalModeCheck(displayConfigProxy, connectorName, headsetAsPri
let monitorToModeIdMap = {}; let monitorToModeIdMap = {};
let bestFitMode = undefined; let bestFitMode = undefined;
for (let monitor of monitors) { for (let monitor of monitors) {
const [details, modes, monProperties] = monitor; const [details, availableModes, monProperties] = monitor;
const [connector, vendor, product, monitorSerial] = details; const [connector, vendor, product, monitorSerial] = details;
const isOurMonitor = connector == connectorName; const isOurMonitor = connector == connectorName;
if (isOurMonitor) ourMonitor = monitor; let modes = availableModes;
if (isOurMonitor) {
ourMonitor = monitor;
if (!useHighestRefreshRate) {
const currentMode = modes.find((mode) => !!mode[6]['is-current']);
// filter modes to only include the current refresh rate
modes = availableModes.filter((mode) => mode[3] === currentMode[3]);
}
}
for (let mode of modes) { for (let mode of modes) {
const [modeId, width, height, refreshRate, preferredScale, supportedScales, modeProperites] = mode; const [modeId, width, height, refreshRate, preferredScale, supportedScales, modeProperites] = mode;
@ -199,6 +208,13 @@ export const MonitorManager = GObject.registerClass({
GObject.ParamFlags.READWRITE, GObject.ParamFlags.READWRITE,
true true
), ),
'use-highest-refresh-rate': GObject.ParamSpec.boolean(
'use-highest-refresh-rate',
'Use highest refresh rate',
'Set the highest refresh rate which choosing optimal configs',
GObject.ParamFlags.READWRITE,
true
),
'headset-as-primary': GObject.ParamSpec.boolean( 'headset-as-primary': GObject.ParamSpec.boolean(
'headset-as-primary', 'headset-as-primary',
'Use headset as primary monitor', 'Use headset as primary monitor',
@ -272,7 +288,7 @@ export const MonitorManager = GObject.registerClass({
} }
if (this._needsConfigCheck) { if (this._needsConfigCheck) {
performOptimalModeCheck(this._displayConfigProxy, monitorConnector, this.headset_as_primary, ((configChanged, error) => { performOptimalModeCheck(this._displayConfigProxy, monitorConnector, this.headset_as_primary, this.use_highest_refresh_rate, ((configChanged, error) => {
this._needsConfigCheck = false; this._needsConfigCheck = false;
if (error) { if (error) {
Globals.logger.log(`Failed to switch to optimal mode for monitor ${monitorConnector}: ${error}`); Globals.logger.log(`Failed to switch to optimal mode for monitor ${monitorConnector}: ${error}`);
@ -309,7 +325,7 @@ export const MonitorManager = GObject.registerClass({
for (let i = 0; i < result.length; i++) { for (let i = 0; i < result.length; i++) {
const [monitorName, connectorName, vendor, product, serial, refreshRate] = result[i]; const [monitorName, connectorName, vendor, product, serial, refreshRate] = result[i];
const monitorIndex = this._backendManager.get_monitor_for_connector(connectorName); const monitorIndex = this._backendManager.get_monitor_for_connector(connectorName);
Globals.logger.log(`Found monitor ${monitorName}, vendor ${vendor}, product ${product}, serial ${serial}, connector ${connectorName}, index ${monitorIndex}`); Globals.logger.log_debug(`Found monitor ${monitorName}, vendor ${vendor}, product ${product}, serial ${serial}, connector ${connectorName}, index ${monitorIndex}`);
if (monitorIndex >= 0) { if (monitorIndex >= 0) {
monitorProperties[monitorIndex] = { monitorProperties[monitorIndex] = {
index: monitorIndex, index: monitorIndex,

View File

@ -118,6 +118,24 @@
Automatically set the headset as the primary display upon connection Automatically set the headset as the primary display upon connection
</description> </description>
</key> </key>
<key name="use-highest-refresh-rate" type="b">
<default>
true
</default>
<summary>Use highest refresh rate</summary>
<description>
Automatically set the highest refresh rate upon connection
</description>
</key>
<key name="fast-sbs-mode-switching" type="b">
<default>
true
</default>
<summary>Fast SBS mode switching</summary>
<description>
Enable fast SBS mode switching
</description>
</key>
<key name="disable-anti-aliasing" type="b"> <key name="disable-anti-aliasing" type="b">
<default> <default>
false false

View File

@ -31,6 +31,8 @@ class ConnectedDevice(Gtk.Box):
toggle_follow_shortcut_label = Gtk.Template.Child() toggle_follow_shortcut_label = Gtk.Template.Child()
headset_as_primary_switch = Gtk.Template.Child() headset_as_primary_switch = Gtk.Template.Child()
use_optimal_monitor_config_switch = Gtk.Template.Child() use_optimal_monitor_config_switch = Gtk.Template.Child()
use_highest_refresh_rate_switch = Gtk.Template.Child()
fast_sbs_mode_switch = Gtk.Template.Child()
movement_look_ahead_scale = Gtk.Template.Child() movement_look_ahead_scale = Gtk.Template.Child()
movement_look_ahead_adjustment = Gtk.Template.Child() movement_look_ahead_adjustment = Gtk.Template.Child()
@ -52,6 +54,8 @@ class ConnectedDevice(Gtk.Box):
self.reassign_toggle_follow_shortcut_button, self.reassign_toggle_follow_shortcut_button,
self.headset_as_primary_switch, self.headset_as_primary_switch,
self.use_optimal_monitor_config_switch, self.use_optimal_monitor_config_switch,
self.use_highest_refresh_rate_switch,
self.fast_sbs_mode_switch,
self.movement_look_ahead_scale self.movement_look_ahead_scale
] ]
@ -66,6 +70,8 @@ class ConnectedDevice(Gtk.Box):
self.settings.bind('curved-display', self.curved_display_switch, 'active', Gio.SettingsBindFlags.DEFAULT) self.settings.bind('curved-display', self.curved_display_switch, 'active', Gio.SettingsBindFlags.DEFAULT)
self.settings.bind('headset-as-primary', self.headset_as_primary_switch, 'active', Gio.SettingsBindFlags.DEFAULT) self.settings.bind('headset-as-primary', self.headset_as_primary_switch, 'active', Gio.SettingsBindFlags.DEFAULT)
self.settings.bind('use-optimal-monitor-config', self.use_optimal_monitor_config_switch, 'active', Gio.SettingsBindFlags.DEFAULT) self.settings.bind('use-optimal-monitor-config', self.use_optimal_monitor_config_switch, 'active', Gio.SettingsBindFlags.DEFAULT)
self.settings.bind('use-highest-refresh-rate', self.use_highest_refresh_rate_switch, 'active', Gio.SettingsBindFlags.DEFAULT)
self.settings.bind('fast-sbs-mode-switching', self.fast_sbs_mode_switch, 'active', Gio.SettingsBindFlags.DEFAULT)
self.settings.bind('look-ahead-override', self.movement_look_ahead_adjustment, 'value', Gio.SettingsBindFlags.DEFAULT) self.settings.bind('look-ahead-override', self.movement_look_ahead_adjustment, 'value', Gio.SettingsBindFlags.DEFAULT)
bind_shortcut_settings(self.get_parent(), [ bind_shortcut_settings(self.get_parent(), [
@ -136,8 +142,10 @@ class ConnectedDevice(Gtk.Box):
def _refresh_use_optimal_monitor_config(self, switch, param): def _refresh_use_optimal_monitor_config(self, switch, param):
self.headset_as_primary_switch.set_sensitive(switch.get_active()) self.headset_as_primary_switch.set_sensitive(switch.get_active())
self.use_highest_refresh_rate_switch.set_sensitive(switch.get_active())
if not switch.get_active(): if not switch.get_active():
self.headset_as_primary_switch.set_active(False) self.headset_as_primary_switch.set_active(False)
self.use_highest_refresh_rate_switch.set_active(False)
def set_device_name(self, name): def set_device_name(self, name):
self.device_label.set_markup(f"<b>{name}</b>") self.device_label.set_markup(f"<b>{name}</b>")

View File

@ -328,6 +328,17 @@
</child> </child>
</object> </object>
</child> </child>
<child>
<object class="AdwActionRow">
<property name="title" translatable="true">Use highest refresh rate</property>
<property name="subtitle" translatable="true">Refresh rate may affect performance, disable this to set it manually.</property>
<child>
<object class="GtkSwitch" id="use_highest_refresh_rate_switch">
<property name="valign">3</property>
</object>
</child>
</object>
</child>
<child> <child>
<object class="AdwActionRow"> <object class="AdwActionRow">
<property name="title" translatable="true">Always primary display</property> <property name="title" translatable="true">Always primary display</property>
@ -339,6 +350,17 @@
</child> </child>
</object> </object>
</child> </child>
<child>
<object class="AdwActionRow">
<property name="title" translatable="true">Fast SBS mode switching</property>
<property name="subtitle" translatable="true">Switches glasses to SBS mode immediately when plugged in, if widescreen mode is on. May cause instability.</property>
<child>
<object class="GtkSwitch" id="fast_sbs_mode_switch">
<property name="valign">3</property>
</object>
</child>
</object>
</child>
<child> <child>
<object class="AdwActionRow"> <object class="AdwActionRow">
<property name="title" translatable="true">Movement look-ahead</property> <property name="title" translatable="true">Movement look-ahead</property>

View File

@ -21,6 +21,7 @@ import gi
import logging import logging
import os import os
import sys import sys
import argparse
from logging.handlers import TimedRotatingFileHandler from logging.handlers import TimedRotatingFileHandler
@ -58,13 +59,14 @@ XRDriverIPC.set_instance(XRDriverIPC(logger))
class BreezydesktopApplication(Adw.Application): class BreezydesktopApplication(Adw.Application):
"""The main application singleton class.""" """The main application singleton class."""
def __init__(self): def __init__(self, skip_verification):
super().__init__(application_id='com.xronlinux.BreezyDesktop', super().__init__(application_id='com.xronlinux.BreezyDesktop',
flags=Gio.ApplicationFlags.DEFAULT_FLAGS) flags=Gio.ApplicationFlags.DEFAULT_FLAGS)
self.create_action('quit', self.on_quit_action, ['<primary>q']) self.create_action('quit', self.on_quit_action, ['<primary>q'])
self.create_action('about', self.on_about_action) self.create_action('about', self.on_about_action)
self.create_action('license', self.on_license_action) self.create_action('license', self.on_license_action)
self.create_action('reset_driver', self.on_reset_driver_action) self.create_action('reset_driver', self.on_reset_driver_action)
self._skip_verification = skip_verification
def do_activate(self): def do_activate(self):
"""Called when the application is activated. """Called when the application is activated.
@ -74,7 +76,7 @@ class BreezydesktopApplication(Adw.Application):
""" """
win = self.props.active_window win = self.props.active_window
if not win: if not win:
win = BreezydesktopWindow(application=self) win = BreezydesktopWindow(self._skip_verification, application=self)
win.connect('close-request', lambda *_: self.on_quit_action()) win.connect('close-request', lambda *_: self.on_quit_action())
win.connect('destroy', lambda *_: self.on_quit_action()) win.connect('destroy', lambda *_: self.on_quit_action())
win.present() win.present()
@ -125,5 +127,9 @@ class BreezydesktopApplication(Adw.Application):
def main(version): def main(version):
app = BreezydesktopApplication() parser = argparse.ArgumentParser()
return app.run(sys.argv) parser.add_argument("-sv", "--skip-verification", action="store_true")
args = parser.parse_args()
app = BreezydesktopApplication(args.skip_verification)
return app.run(None)

View File

@ -37,7 +37,7 @@ class BreezydesktopWindow(Gtk.ApplicationWindow):
license_action_needed_banner = Gtk.Template.Child() license_action_needed_banner = Gtk.Template.Child()
missing_breezy_features_banner = Gtk.Template.Child() missing_breezy_features_banner = Gtk.Template.Child()
def __init__(self, **kwargs): def __init__(self, skip_verification, **kwargs):
super().__init__(**kwargs) super().__init__(**kwargs)
self.state_manager = StateManager.get_instance() self.state_manager = StateManager.get_instance()
@ -57,6 +57,8 @@ class BreezydesktopWindow(Gtk.ApplicationWindow):
self._handle_state_update(self.state_manager, None) self._handle_state_update(self.state_manager, None)
self._skip_verification = skip_verification
self.connect("destroy", self._on_window_destroy) self.connect("destroy", self._on_window_destroy)
def _handle_state_update(self, state_manager, val): def _handle_state_update(self, state_manager, val):
@ -71,9 +73,11 @@ class BreezydesktopWindow(Gtk.ApplicationWindow):
for child in self.main_content: for child in self.main_content:
self.main_content.remove(child) self.main_content.remove(child)
if not verify_installation(): if not self._skip_verification:
self.main_content.append(self.failed_verification) if not verify_installation():
elif not self.state_manager.get_property('license-present'): self.main_content.append(self.failed_verification)
if not self.state_manager.get_property('license-present'):
self.main_content.append(self.no_license) self.main_content.append(self.no_license)
elif not ExtensionsManager.get_instance().is_installed(): elif not ExtensionsManager.get_instance().is_installed():
self.main_content.append(self.no_extension) self.main_content.append(self.no_extension)