WIP - Apply optimal monitor configs, if needed
This commit is contained in:
parent
88e3692cca
commit
23b36b93e3
|
|
@ -82,8 +82,12 @@ export default class BreezyDesktopExtension extends Extension {
|
||||||
|
|
||||||
const is_driver_running = this._check_driver_running();
|
const is_driver_running = this._check_driver_running();
|
||||||
if (is_driver_running && target_monitor) {
|
if (is_driver_running && target_monitor) {
|
||||||
Globals.logger.log('Driver is running, supported monitor connected. Enabling XR effect.');
|
// don't enable the effect yet if an async optimal mode check is needed,
|
||||||
this._effect_enable();
|
// _setup will be triggered after a mode change so we can remove this timeout_add
|
||||||
|
if (target_monitor.is_dummy || !this._monitor_manager.checkOptimalMode(target_monitor.connector)) {
|
||||||
|
Globals.logger.log('Driver is running, supported monitor connected. Enabling XR effect.');
|
||||||
|
this._effect_enable();
|
||||||
|
}
|
||||||
return GLib.SOURCE_REMOVE;
|
return GLib.SOURCE_REMOVE;
|
||||||
} else {
|
} else {
|
||||||
return GLib.SOURCE_CONTINUE;
|
return GLib.SOURCE_CONTINUE;
|
||||||
|
|
@ -99,7 +103,8 @@ export default class BreezyDesktopExtension extends Extension {
|
||||||
if (target_monitor !== undefined) {
|
if (target_monitor !== undefined) {
|
||||||
return {
|
return {
|
||||||
monitor: this._monitor_manager.getMonitors()[target_monitor.index],
|
monitor: this._monitor_manager.getMonitors()[target_monitor.index],
|
||||||
refreshRate: target_monitor.refreshRate,
|
connector: target_monitor.connector,
|
||||||
|
refreshRate: target_monitor.refreshRate
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -107,7 +112,9 @@ export default class BreezyDesktopExtension extends Extension {
|
||||||
// allow testing XR devices with just USB, no video needed
|
// allow testing XR devices with just USB, no video needed
|
||||||
return {
|
return {
|
||||||
monitor: this._monitor_manager.getMonitors()[0],
|
monitor: this._monitor_manager.getMonitors()[0],
|
||||||
|
connector: 'dummy',
|
||||||
refreshRate: 60,
|
refreshRate: 60,
|
||||||
|
is_dummy: true
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -132,8 +139,12 @@ export default class BreezyDesktopExtension extends Extension {
|
||||||
this._refresh_rate = target_monitor.refreshRate;
|
this._refresh_rate = target_monitor.refreshRate;
|
||||||
|
|
||||||
if (this._check_driver_running()) {
|
if (this._check_driver_running()) {
|
||||||
Globals.logger.log('Ready, enabling XR effect');
|
// don't enable the effect yet if an async optimal mode check is needed,
|
||||||
this._effect_enable();
|
// _setup will be triggered again after a mode change
|
||||||
|
if (target_monitor.is_dummy || !this._monitor_manager.checkOptimalMode(target_monitor.connector)) {
|
||||||
|
Globals.logger.log('Ready, enabling XR effect');
|
||||||
|
this._effect_enable();
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
this._poll_for_ready();
|
this._poll_for_ready();
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -52,10 +52,10 @@ export function newDisplayConfig(extPath, callback) {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
export function getMonitorConfig(displayConfigProxy, callback) {
|
function getMonitorConfig(displayConfigProxy, callback) {
|
||||||
displayConfigProxy.GetResourcesRemote((result) => {
|
displayConfigProxy.GetResourcesRemote((result, error) => {
|
||||||
if (result.length <= 2) {
|
if (error) {
|
||||||
callback(null, 'Cannot get DisplayConfig: No outputs in GetResources()');
|
callback(null, `GetResourcesRemote failed: ${error}`);
|
||||||
} else {
|
} else {
|
||||||
const monitors = [];
|
const monitors = [];
|
||||||
for (let i = 0; i < result[2].length; i++) {
|
for (let i = 0; i < result[2].length; i++) {
|
||||||
|
|
@ -84,6 +84,106 @@ export function getMonitorConfig(displayConfigProxy, callback) {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// triggers callback with true result if an an async monitor config change was triggered, false if no config change needed
|
||||||
|
function performOptimalModeCheck(displayConfigProxy, connectorName, callback) {
|
||||||
|
Globals.logger.log_debug(`monitormanager.js performOptimalModeCheck for ${connectorName}`);
|
||||||
|
displayConfigProxy.GetCurrentStateRemote((result, error) => {
|
||||||
|
if (error) {
|
||||||
|
callback(null, `GetCurrentState failed: ${error}`);
|
||||||
|
} else {
|
||||||
|
Globals.logger.log_debug(`monitormanager.js performOptimalModeCheck GetCurrentState result: ${JSON.stringify(result)}`);
|
||||||
|
const [serial, monitors, logicalMonitors, properties] = result;
|
||||||
|
|
||||||
|
// iterate over all monitors at least once, collecting the best fit mode for our monitor, and mode information
|
||||||
|
// for each monitor
|
||||||
|
let ourMonitor = undefined;
|
||||||
|
let monitorToModeIdMap = {};
|
||||||
|
let bestFitMode = undefined;
|
||||||
|
for (let monitor of monitors) {
|
||||||
|
const [details, modes, monProperties] = monitor;
|
||||||
|
const [connector, vendor, product, monitorSerial] = details;
|
||||||
|
const isOurMonitor = connector == connectorName;
|
||||||
|
if (isOurMonitor) ourMonitor = monitor;
|
||||||
|
|
||||||
|
for (let mode of modes) {
|
||||||
|
const [modeId, width, height, refreshRate, preferredScale, supportedScales, modeProperites] = mode;
|
||||||
|
const isCurrent = !!modeProperites['is-current'];
|
||||||
|
if (isCurrent) monitorToModeIdMap[connector] = modeId;
|
||||||
|
|
||||||
|
if (isOurMonitor && (!bestFitMode || (
|
||||||
|
width >= bestFitMode.width &&
|
||||||
|
height >= bestFitMode.height &&
|
||||||
|
refreshRate >= bestFitMode.refreshRate))) {
|
||||||
|
// find the scale that is closest to 1.0
|
||||||
|
const bestScale = supportedScales.reduce((prev, curr) => {
|
||||||
|
return Math.abs(curr - 1.0) < Math.abs(prev - 1.0) ? curr : prev;
|
||||||
|
});
|
||||||
|
|
||||||
|
bestFitMode = {
|
||||||
|
modeId,
|
||||||
|
width,
|
||||||
|
height,
|
||||||
|
refreshRate,
|
||||||
|
bestScale,
|
||||||
|
isCurrent
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!!ourMonitor) {
|
||||||
|
let anyMonitorsChanged = false;
|
||||||
|
if (!!bestFitMode) {
|
||||||
|
// map from original logical monitors schema to a(iiduba(ssa{sv})) for ApplyMonitorsConfig call
|
||||||
|
const updatedLogicalMonitors = logicalMonitors.map((logicalMonitor) => {
|
||||||
|
const [x, y, scale, transform, primary, monitors, logMonProperties] = logicalMonitor;
|
||||||
|
const hasOurMonitor = !!monitors.some((monitor) => monitor[0] === connectorName);
|
||||||
|
anyMonitorsChanged |= hasOurMonitor && bestFitMode.bestScale !== scale;
|
||||||
|
return [
|
||||||
|
x,
|
||||||
|
y,
|
||||||
|
hasOurMonitor ? bestFitMode.bestScale : scale,
|
||||||
|
transform,
|
||||||
|
primary, // TODO - user setting should dictate if we want to set ours primary
|
||||||
|
monitors.map((monitor) => {
|
||||||
|
const monitorConnector = monitor[0];
|
||||||
|
const isOurMonitor = monitorConnector === connectorName;
|
||||||
|
anyMonitorsChanged |= isOurMonitor && !bestFitMode.isCurrent;
|
||||||
|
return [
|
||||||
|
monitorConnector,
|
||||||
|
isOurMonitor ? bestFitMode.modeId : monitorToModeIdMap[monitorConnector],
|
||||||
|
{} // properties
|
||||||
|
];
|
||||||
|
})
|
||||||
|
];
|
||||||
|
});
|
||||||
|
|
||||||
|
// if our monitor is already properly configured, we can skip the ApplyMonitorsConfig call
|
||||||
|
if (anyMonitorsChanged) {
|
||||||
|
Globals.logger.log_debug(`monitormanager.js performOptimalModeCheck updatedLogicalMonitors: ${JSON.stringify(updatedLogicalMonitors)}`);
|
||||||
|
displayConfigProxy.ApplyMonitorsConfigRemote(
|
||||||
|
serial,
|
||||||
|
1, // "temporary" config -- "permanent" might be pointless since we always do this check
|
||||||
|
updatedLogicalMonitors,
|
||||||
|
{}, // properties
|
||||||
|
(_result, error) => {
|
||||||
|
if (error) {
|
||||||
|
callback(null, `ApplyMonitorsConfig failed: ${error}`);
|
||||||
|
} else {
|
||||||
|
callback(true, null);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (!anyMonitorsChanged) callback(false, null);
|
||||||
|
} else {
|
||||||
|
callback(null, `Monitor ${connectorName} not found in GetCurrentState result`);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
// Monitor change handling
|
// Monitor change handling
|
||||||
export default class MonitorManager {
|
export default class MonitorManager {
|
||||||
constructor(extPath) {
|
constructor(extPath) {
|
||||||
|
|
@ -94,22 +194,25 @@ export default class MonitorManager {
|
||||||
this._backendManager = null;
|
this._backendManager = null;
|
||||||
this._monitorProperties = null;
|
this._monitorProperties = null;
|
||||||
this._changeHookFn = null;
|
this._changeHookFn = null;
|
||||||
|
this._needsConfigCheck = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
enable() {
|
enable() {
|
||||||
|
Globals.logger.log_debug('MonitorManager enable');
|
||||||
this._backendManager = global.backend.get_monitor_manager();
|
this._backendManager = global.backend.get_monitor_manager();
|
||||||
newDisplayConfig(this._extPath, (proxy, error) => {
|
newDisplayConfig(this._extPath, ((proxy, error) => {
|
||||||
if (error) {
|
if (error) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
this._displayConfigProxy = proxy;
|
this._displayConfigProxy = proxy;
|
||||||
this._on_monitors_change();
|
this._on_monitors_change();
|
||||||
});
|
}).bind(this));
|
||||||
|
|
||||||
this._monitorsChangedConnection = Main.layoutManager.connect('monitors-changed', this._on_monitors_change.bind(this));
|
this._monitorsChangedConnection = Main.layoutManager.connect('monitors-changed', this._on_monitors_change.bind(this));
|
||||||
}
|
}
|
||||||
|
|
||||||
disable() {
|
disable() {
|
||||||
|
Globals.logger.log_debug('MonitorManager disable');
|
||||||
Main.layoutManager.disconnect(this._monitorsChangedConnection);
|
Main.layoutManager.disconnect(this._monitorsChangedConnection);
|
||||||
|
|
||||||
this._monitorsChangedConnection = null;
|
this._monitorsChangedConnection = null;
|
||||||
|
|
@ -123,10 +226,6 @@ export default class MonitorManager {
|
||||||
this._changeHookFn = fn;
|
this._changeHookFn = fn;
|
||||||
}
|
}
|
||||||
|
|
||||||
setPostCallback(callback) {
|
|
||||||
this._postCallback = callback;
|
|
||||||
}
|
|
||||||
|
|
||||||
getMonitors() {
|
getMonitors() {
|
||||||
return Main.layoutManager.monitors;
|
return Main.layoutManager.monitors;
|
||||||
}
|
}
|
||||||
|
|
@ -135,11 +234,41 @@ export default class MonitorManager {
|
||||||
return this._monitorProperties;
|
return this._monitorProperties;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// returns true if a check is needed, caller should wait for the next change hook call
|
||||||
|
checkOptimalMode(monitorConnector) {
|
||||||
|
Globals.logger.log_debug(`MonitorManager checkOptimalMode: ${monitorConnector}`);
|
||||||
|
if (this._displayConfigProxy == null) {
|
||||||
|
Globals.logger.log('MonitorManager checkOptimalMode: _displayConfigProxy not set!');
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (this._needsConfigCheck) {
|
||||||
|
performOptimalModeCheck(this._displayConfigProxy, monitorConnector, ((configChanged, error) => {
|
||||||
|
this._needsConfigCheck = false;
|
||||||
|
if (error) {
|
||||||
|
Globals.logger.log(`Failed to switch to optimal mode for monitor ${monitorConnector}: ${error}`);
|
||||||
|
} else {
|
||||||
|
if (configChanged) {
|
||||||
|
Globals.logger.log(`Switched to optimal mode for monitor ${monitorConnector}`);
|
||||||
|
} else if (this._changeHookFn !== null) {
|
||||||
|
// no config change means this won't be triggered automatically, so trigger it manually
|
||||||
|
this._changeHookFn();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}).bind(this));
|
||||||
|
} else {
|
||||||
|
Globals.logger.log_debug('MonitorManager checkOptimalMode: skipping config check');
|
||||||
|
}
|
||||||
|
return this._needsConfigCheck;
|
||||||
|
}
|
||||||
|
|
||||||
_on_monitors_change() {
|
_on_monitors_change() {
|
||||||
|
Globals.logger.log_debug('MonitorManager _on_monitors_change');
|
||||||
if (this._displayConfigProxy == null) {
|
if (this._displayConfigProxy == null) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
getMonitorConfig(this._displayConfigProxy, (result, error) => {
|
this._needsConfigCheck = true;
|
||||||
|
getMonitorConfig(this._displayConfigProxy, ((result, error) => {
|
||||||
if (error) {
|
if (error) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
@ -164,6 +293,6 @@ export default class MonitorManager {
|
||||||
if (this._changeHookFn !== null) {
|
if (this._changeHookFn !== null) {
|
||||||
this._changeHookFn();
|
this._changeHookFn();
|
||||||
}
|
}
|
||||||
});
|
}).bind(this));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Loading…
Reference in New Issue