Merge branch 'main' into gnome-44-max
This commit is contained in:
commit
3393317016
|
|
@ -13,7 +13,7 @@ There are two installations at the moment. **Note: Only install one of these at
|
||||||
* [Breezy Vulkan](#breezy-vulkan) primarily for gaming but would work with pretty much any application that uses Vulkan rendering.
|
* [Breezy Vulkan](#breezy-vulkan) primarily for gaming but would work with pretty much any application that uses Vulkan rendering.
|
||||||
|
|
||||||
## Breezy GNOME
|
## Breezy GNOME
|
||||||
Breezy GNOME is a virtual workspace solution for Linux desktops that use the GNOME desktop environment (supports GNOME versions 42-46 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 supports GNOME versions 42-46; 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
|
||||||
|
|
||||||
|
|
@ -31,7 +31,7 @@ Breezy GNOME is in AUR (but not pacman, yet). To install, run these commands fro
|
||||||
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`)
|
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:
|
2. Run the setup script:
|
||||||
* For **GNOME 45+**: `~/Downloads/breezy_gnome_setup`
|
* For **GNOME 45+**: `~/Downloads/breezy_gnome_setup`
|
||||||
* For **GNOME 42-44**: `~/Downloads/breezy_gnome_setup --tag gnome-44-max-beta-2`
|
* For **GNOME 42-44**: `~/Downloads/breezy_gnome_setup --tag gnome-44-max`
|
||||||
|
|
||||||
### 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:
|
||||||
|
|
|
||||||
|
|
@ -102,8 +102,7 @@ class BreezyDesktopExtension {
|
||||||
return GLib.SOURCE_REMOVE;
|
return GLib.SOURCE_REMOVE;
|
||||||
}
|
}
|
||||||
|
|
||||||
const is_driver_running = this._check_driver_running();
|
if (this._check_driver_running() && target_monitor) {
|
||||||
if (is_driver_running && target_monitor) {
|
|
||||||
// Don't enable the effect yet if monitor updates are needed.
|
// Don't enable the effect yet if monitor updates are needed.
|
||||||
// _setup will be triggered again since a !ready result means it will trigger monitor changes,
|
// _setup will be triggered again since a !ready result means it will trigger monitor changes,
|
||||||
// so we can remove this timeout_add no matter what.
|
// so we can remove this timeout_add no matter what.
|
||||||
|
|
@ -222,7 +221,7 @@ class BreezyDesktopExtension {
|
||||||
|
|
||||||
_needs_widescreen_monitor_update() {
|
_needs_widescreen_monitor_update() {
|
||||||
Globals.logger.log_debug('BreezyDesktopExtension _needs_widescreen_monitor_update');
|
Globals.logger.log_debug('BreezyDesktopExtension _needs_widescreen_monitor_update');
|
||||||
const state = this._read_state(['sbs_mode_enabled']);
|
const state = this._read_state();
|
||||||
const sbs_enabled = state['sbs_mode_enabled'] === 'true';
|
const sbs_enabled = state['sbs_mode_enabled'] === 'true';
|
||||||
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) {
|
||||||
|
|
@ -250,6 +249,8 @@ class BreezyDesktopExtension {
|
||||||
this._overlay.opacity = 255;
|
this._overlay.opacity = 255;
|
||||||
this._overlay.set_position(targetMonitor.x, targetMonitor.y);
|
this._overlay.set_position(targetMonitor.x, targetMonitor.y);
|
||||||
this._overlay.set_size(targetMonitor.width, targetMonitor.height);
|
this._overlay.set_size(targetMonitor.width, targetMonitor.height);
|
||||||
|
Globals.logger.log_debug(`BreezyDesktopExtension _effect_enable overlay size: \
|
||||||
|
${targetMonitor.width}x${targetMonitor.height} at ${targetMonitor.x},${targetMonitor.y}`);
|
||||||
|
|
||||||
const overlayContent = new Clutter.Actor({clip_to_allocation: true});
|
const overlayContent = new Clutter.Actor({clip_to_allocation: true});
|
||||||
const uiClone = new Clutter.Clone({ source: Main.layoutManager.uiGroup, clip_to_allocation: true });
|
const uiClone = new Clutter.Clone({ source: Main.layoutManager.uiGroup, clip_to_allocation: true });
|
||||||
|
|
@ -350,7 +351,7 @@ class BreezyDesktopExtension {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
_read_state(keys) {
|
_read_state() {
|
||||||
const state = {};
|
const state = {};
|
||||||
try {
|
try {
|
||||||
const file = Gio.file_new_for_path('/dev/shm/xr_driver_state');
|
const file = Gio.file_new_for_path('/dev/shm/xr_driver_state');
|
||||||
|
|
@ -365,7 +366,7 @@ class BreezyDesktopExtension {
|
||||||
const lines = contents.split('\n');
|
const lines = contents.split('\n');
|
||||||
for (const line of lines) {
|
for (const line of lines) {
|
||||||
const [k, v] = line.split('=');
|
const [k, v] = line.split('=');
|
||||||
if (keys.includes(k)) state[k] = v;
|
state[k] = v;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -389,10 +390,25 @@ class BreezyDesktopExtension {
|
||||||
|
|
||||||
// requests sbs_mode change and monitors to ensure the state reflects the setting
|
// requests sbs_mode change and monitors to ensure the state reflects the setting
|
||||||
_request_sbs_mode_change(value) {
|
_request_sbs_mode_change(value) {
|
||||||
|
Globals.logger.log_debug(`BreezyDesktopExtension _request_sbs_mode_change ${value}`);
|
||||||
this._write_control('sbs_mode', value ? 'enable' : 'disable');
|
this._write_control('sbs_mode', value ? 'enable' : 'disable');
|
||||||
if (!this._sbs_mode_update_timeout) {
|
if (!this._sbs_mode_update_timeout) {
|
||||||
var attempts = 0;
|
var attempts = 0;
|
||||||
this._sbs_mode_update_timeout = GLib.timeout_add(GLib.PRIORITY_DEFAULT, 3000, (() => {
|
this._sbs_mode_update_timeout = GLib.timeout_add(GLib.PRIORITY_DEFAULT, 3000, (() => {
|
||||||
|
const state = this._read_state();
|
||||||
|
const sbs_enabled = state['sbs_mode_enabled'] === 'true';
|
||||||
|
if (sbs_enabled === value) {
|
||||||
|
Globals.logger.log_debug('BreezyDesktopExtension _request_sbs_mode_change - successfully updated');
|
||||||
|
this._sbs_mode_update_timeout = undefined;
|
||||||
|
|
||||||
|
if (this.settings.get_boolean('fast-sbs-mode-switching')) {
|
||||||
|
// setup and polling were halted if this is enabled, so we have to re-trigger setup
|
||||||
|
this._setup();
|
||||||
|
}
|
||||||
|
|
||||||
|
return GLib.SOURCE_REMOVE;
|
||||||
|
}
|
||||||
|
|
||||||
if (attempts++ < 3) {
|
if (attempts++ < 3) {
|
||||||
this._write_control('sbs_mode', value ? 'enable' : 'disable');
|
this._write_control('sbs_mode', value ? 'enable' : 'disable');
|
||||||
return GLib.SOURCE_CONTINUE;
|
return GLib.SOURCE_CONTINUE;
|
||||||
|
|
|
||||||
|
|
@ -110,7 +110,7 @@ function performOptimalModeCheck(displayConfigProxy, connectorName, headsetAsPri
|
||||||
// iterate over all monitors at least once, collecting the best fit mode for our monitor, and mode information
|
// iterate over all monitors at least once, collecting the best fit mode for our monitor, and mode information
|
||||||
// for each monitor
|
// for each monitor
|
||||||
let ourMonitor = undefined;
|
let ourMonitor = undefined;
|
||||||
let monitorToModeIdMap = {};
|
let monitorToCurrentModeMap = {};
|
||||||
let bestFitMode = undefined;
|
let bestFitMode = undefined;
|
||||||
const skipScaleUpdate = !!properties['global-scale-required'];
|
const skipScaleUpdate = !!properties['global-scale-required'];
|
||||||
for (let monitor of monitors) {
|
for (let monitor of monitors) {
|
||||||
|
|
@ -131,7 +131,7 @@ function performOptimalModeCheck(displayConfigProxy, connectorName, headsetAsPri
|
||||||
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;
|
||||||
const isCurrent = !!modeProperites['is-current'];
|
const isCurrent = !!modeProperites['is-current'];
|
||||||
if (isCurrent) monitorToModeIdMap[connector] = modeId;
|
if (isCurrent) monitorToCurrentModeMap[connector] = mode;
|
||||||
|
|
||||||
if (isOurMonitor && (!bestFitMode || (
|
if (isOurMonitor && (!bestFitMode || (
|
||||||
width >= bestFitMode.width &&
|
width >= bestFitMode.width &&
|
||||||
|
|
@ -147,8 +147,7 @@ function performOptimalModeCheck(displayConfigProxy, connectorName, headsetAsPri
|
||||||
width,
|
width,
|
||||||
height,
|
height,
|
||||||
refreshRate,
|
refreshRate,
|
||||||
bestScale,
|
bestScale
|
||||||
isCurrent
|
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -157,6 +156,14 @@ function performOptimalModeCheck(displayConfigProxy, connectorName, headsetAsPri
|
||||||
if (!!ourMonitor) {
|
if (!!ourMonitor) {
|
||||||
let anyMonitorsChanged = false;
|
let anyMonitorsChanged = false;
|
||||||
if (!!bestFitMode) {
|
if (!!bestFitMode) {
|
||||||
|
// this will hold how much the width of the monitor has changed,
|
||||||
|
// and what range of y values is affected
|
||||||
|
let deltaX = 0;
|
||||||
|
let rangeY = [0, 0];
|
||||||
|
|
||||||
|
// sort logicalMonitors by x ascending, so we can tell if any are affected by a width change
|
||||||
|
logicalMonitors.sort((a, b) => a[0] - b[0]);
|
||||||
|
|
||||||
// map from original logical monitors schema to a(iiduba(ssa{sv})) for ApplyMonitorsConfig call
|
// map from original logical monitors schema to a(iiduba(ssa{sv})) for ApplyMonitorsConfig call
|
||||||
const updatedLogicalMonitors = logicalMonitors.map((logicalMonitor) => {
|
const updatedLogicalMonitors = logicalMonitors.map((logicalMonitor) => {
|
||||||
const [x, y, scale, transform, primary, monitors, logMonProperties] = logicalMonitor;
|
const [x, y, scale, transform, primary, monitors, logMonProperties] = logicalMonitor;
|
||||||
|
|
@ -167,8 +174,29 @@ function performOptimalModeCheck(displayConfigProxy, connectorName, headsetAsPri
|
||||||
// there can only be one primary monitor, so we need to set all other monitors to not primary and glasses to primary,
|
// there can only be one primary monitor, so we need to set all other monitors to not primary and glasses to primary,
|
||||||
// if headsetAsPrimary is true
|
// if headsetAsPrimary is true
|
||||||
anyMonitorsChanged |= headsetAsPrimary && ((hasOurMonitor && !primary) || (!hasOurMonitor && primary));
|
anyMonitorsChanged |= headsetAsPrimary && ((hasOurMonitor && !primary) || (!hasOurMonitor && primary));
|
||||||
|
|
||||||
|
// we need to figure out if the deltaX applies to this logical monitor,
|
||||||
|
// i.e. if it is within the same row as our monitor and to the right of it
|
||||||
|
let thisDeltaX = deltaX;
|
||||||
|
if (thisDeltaX !== 0) {
|
||||||
|
// find the monitor with the largest height
|
||||||
|
const maxMonitorHeight = monitors.reduce((maxHeight, monitor) => {
|
||||||
|
const monitorConnector = monitor[0];
|
||||||
|
const currentMode = monitorToCurrentModeMap[monitorConnector];
|
||||||
|
const currentHeight = currentMode[2];
|
||||||
|
return Math.max(maxHeight, currentHeight);
|
||||||
|
}, 0);
|
||||||
|
|
||||||
|
if (y >= rangeY[1] || y + maxMonitorHeight <= rangeY[0]) {
|
||||||
|
// monitors outside the y range are not affected by the width change
|
||||||
|
thisDeltaX = 0;
|
||||||
|
} else {
|
||||||
|
anyMonitorsChanged = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return [
|
return [
|
||||||
x,
|
x + thisDeltaX,
|
||||||
y,
|
y,
|
||||||
newScale,
|
newScale,
|
||||||
transform,
|
transform,
|
||||||
|
|
@ -176,10 +204,15 @@ function performOptimalModeCheck(displayConfigProxy, connectorName, headsetAsPri
|
||||||
monitors.map((monitor) => {
|
monitors.map((monitor) => {
|
||||||
const monitorConnector = monitor[0];
|
const monitorConnector = monitor[0];
|
||||||
const isOurMonitor = monitorConnector === connectorName;
|
const isOurMonitor = monitorConnector === connectorName;
|
||||||
anyMonitorsChanged |= isOurMonitor && !bestFitMode.isCurrent;
|
const [currentModeId, currentWidth, currentHeight] = monitorToCurrentModeMap[monitorConnector];
|
||||||
|
if (isOurMonitor) {
|
||||||
|
deltaX = bestFitMode.width - currentWidth;
|
||||||
|
rangeY = [y, y + currentHeight];
|
||||||
|
}
|
||||||
|
anyMonitorsChanged |= isOurMonitor && bestFitMode.modeId !== currentModeId;
|
||||||
return [
|
return [
|
||||||
monitorConnector,
|
monitorConnector,
|
||||||
isOurMonitor ? bestFitMode.modeId : monitorToModeIdMap[monitorConnector],
|
isOurMonitor ? bestFitMode.modeId : currentModeId,
|
||||||
{} // properties
|
{} // properties
|
||||||
];
|
];
|
||||||
})
|
})
|
||||||
|
|
|
||||||
|
|
@ -1 +1 @@
|
||||||
Subproject commit 4ce360a936937e8dd0ebd54a337fec54bb38f497
|
Subproject commit 64421876bf080ebf36598fe9a044ad77892f5880
|
||||||
Loading…
Reference in New Issue