Add new UI controls and hook up settings
This commit is contained in:
parent
146611ca6f
commit
5f66019580
|
|
@ -80,7 +80,7 @@ export const DeviceDataStream = GObject.registerClass({
|
|||
this.breezy_desktop_running = false;
|
||||
this._ipc_file = Gio.file_new_for_path(IPC_FILE_PATH);
|
||||
this._running = false;
|
||||
this._device_data = null;
|
||||
this.device_data = null;
|
||||
}
|
||||
|
||||
start() {
|
||||
|
|
@ -105,9 +105,9 @@ export const DeviceDataStream = GObject.registerClass({
|
|||
// hasn't been checked within KEEPALIVE_REFRESH_INTERVAL_SEC.
|
||||
refresh_data(keepalive_only = false) {
|
||||
if (this._ipc_file.query_exists(null) && (
|
||||
!this._device_data?.imuData ||
|
||||
!this.device_data?.imuData ||
|
||||
!keepalive_only ||
|
||||
getEpochSec() - toSec(this._device_data?.imuDateMs ?? 0) > KEEPALIVE_REFRESH_INTERVAL_SEC
|
||||
getEpochSec() - toSec(this.device_data?.imuDateMs ?? 0) > KEEPALIVE_REFRESH_INTERVAL_SEC
|
||||
)) {
|
||||
let data = this._ipc_file.load_contents(null);
|
||||
if (data[0]) {
|
||||
|
|
@ -125,8 +125,8 @@ export const DeviceDataStream = GObject.registerClass({
|
|||
// update the widescreen property if the state changes while still enabled, trigger "notify::" events
|
||||
if (enabled && this.widescreen_mode_state !== sbsEnabled) this.widescreen_mode_state = sbsEnabled;
|
||||
|
||||
if (!this._device_data) {
|
||||
this._device_data = {
|
||||
if (!this.device_data) {
|
||||
this.device_data = {
|
||||
version,
|
||||
enabled,
|
||||
imuResetState,
|
||||
|
|
@ -142,8 +142,8 @@ export const DeviceDataStream = GObject.registerClass({
|
|||
while (!success && attempts < 3) {
|
||||
if (dataView.byteLength === DATA_VIEW_LENGTH) {
|
||||
if (checkParityByte(dataView)) {
|
||||
this._device_data.imuData = imuData;
|
||||
this._device_data.imuDateMs = imuDateMs;
|
||||
this.device_data.imuData = imuData;
|
||||
this.device_data.imuDateMs = imuDateMs;
|
||||
this.imu_snapshots = {
|
||||
imu_data: imuData,
|
||||
timestamp_ms: imuDateMs
|
||||
|
|
|
|||
|
|
@ -48,6 +48,9 @@ export default class BreezyDesktopExtension extends Extension {
|
|||
this._target_monitor = null;
|
||||
this._is_effect_running = false;
|
||||
this._distance_binding = null;
|
||||
this._monitor_wrapping_scheme_binding = null;
|
||||
this._viewport_offset_x_binding = null;
|
||||
this._viewport_offset_y_binding = null;
|
||||
this._distance_connection = null;
|
||||
this._follow_threshold_connection = null;
|
||||
this._widescreen_mode_settings_connection = null;
|
||||
|
|
@ -139,7 +142,7 @@ export default class BreezyDesktopExtension extends Extension {
|
|||
this._running_poller_id = undefined;
|
||||
return GLib.SOURCE_REMOVE;
|
||||
} else {
|
||||
Globals.logger.log_debug(`BreezyDesktopExtension _poll_for_ready - device connected: ${Globals.data_stream.breezy_desktop_running}, target_monitor: ${!!target_monitor}`);
|
||||
Globals.logger.log_debug(`BreezyDesktopExtension _poll_for_ready - breezy enabled: ${Globals.data_stream.breezy_desktop_running}, target_monitor: ${!!target_monitor}`);
|
||||
return GLib.SOURCE_CONTINUE;
|
||||
}
|
||||
} catch (e) {
|
||||
|
|
@ -175,31 +178,30 @@ export default class BreezyDesktopExtension extends Extension {
|
|||
|
||||
try {
|
||||
Globals.logger.log_debug('BreezyDesktopExtension _find_supported_monitor');
|
||||
const target_monitor = this._monitor_manager.getMonitorPropertiesList()?.find(
|
||||
let target_monitor = this._monitor_manager.getMonitorPropertiesList()?.find(
|
||||
monitor => monitor && (SUPPORTED_MONITOR_PRODUCTS.includes(monitor.product) ||
|
||||
this.settings.get_string('custom-monitor-product') === monitor.product));
|
||||
let is_dummy = target_monitor?.product === NESTED_MONITOR_PRODUCT;
|
||||
|
||||
if (target_monitor === undefined && this.settings.get_boolean('developer-mode')) {
|
||||
Globals.logger.log_debug('BreezyDesktopExtension _find_supported_monitor - Using dummy monitor');
|
||||
// find the first of the physical monitors
|
||||
target_monitor = this._monitor_manager.getMonitorPropertiesList()?.find(
|
||||
monitor => monitor && monitor.product !== VIRTUAL_MONITOR_PRODUCT);
|
||||
is_dummy = true;
|
||||
}
|
||||
|
||||
if (target_monitor !== undefined) {
|
||||
Globals.logger.log(`Identified supported monitor: ${target_monitor.product} on ${target_monitor.connector}`);
|
||||
return {
|
||||
monitor: this._monitor_manager.getMonitors()[target_monitor.index],
|
||||
connector: target_monitor.connector,
|
||||
refreshRate: target_monitor.refreshRate,
|
||||
is_dummy: target_monitor.product === NESTED_MONITOR_PRODUCT,
|
||||
is_dummy: is_dummy,
|
||||
is_virtual: target_monitor.product === VIRTUAL_MONITOR_PRODUCT
|
||||
};
|
||||
}
|
||||
|
||||
if (this.settings.get_boolean('developer-mode')) {
|
||||
Globals.logger.log_debug('BreezyDesktopExtension _find_supported_monitor - Using dummy monitor');
|
||||
// allow testing XR devices with just USB, no video needed
|
||||
return {
|
||||
monitor: this._monitor_manager.getMonitors()[0],
|
||||
connector: 'dummy',
|
||||
refreshRate: 60,
|
||||
is_dummy: true
|
||||
};
|
||||
}
|
||||
|
||||
Globals.logger.log_debug('BreezyDesktopExtension _find_supported_monitor - No supported monitor found');
|
||||
return null;
|
||||
} catch (e) {
|
||||
|
|
@ -292,7 +294,9 @@ export default class BreezyDesktopExtension extends Extension {
|
|||
Globals.data_stream.refresh_data();
|
||||
this._overlay_content = new VirtualMonitorsActor({
|
||||
monitors: virtualMonitors,
|
||||
fov_degrees: 46.0,
|
||||
monitor_wrapping_scheme: this.settings.get_string('monitor-wrapping-scheme'),
|
||||
viewport_offset_x: this.settings.get_double('viewport-offset-x'),
|
||||
viewport_offset_y: this.settings.get_double('viewport-offset-y'),
|
||||
target_monitor: targetMonitor,
|
||||
display_distance: this.settings.get_double('display-distance'),
|
||||
toggle_display_distance_start: this.settings.get_double('toggle-display-distance-start'),
|
||||
|
|
@ -326,6 +330,9 @@ export default class BreezyDesktopExtension extends Extension {
|
|||
this._breezy_desktop_running_connection = Globals.data_stream.connect('notify::breezy-desktop-running', this._handle_breezy_desktop_running_change.bind(this));
|
||||
this._overlay_content.renderMonitors();
|
||||
|
||||
this._monitor_wrapping_scheme_binding = this.settings.bind('monitor-wrapping-scheme', this._overlay_content, 'monitor-wrapping-scheme', Gio.SettingsBindFlags.DEFAULT);
|
||||
this._viewport_offset_x_binding = this.settings.bind('viewport-offset-x', this._overlay_content, 'viewport-offset-x', Gio.SettingsBindFlags.DEFAULT);
|
||||
this._viewport_offset_y_binding = this.settings.bind('viewport-offset-y', this._overlay_content, 'viewport-offset-y', Gio.SettingsBindFlags.DEFAULT);
|
||||
this._distance_binding = this.settings.bind('display-distance', this._overlay_content, 'display-distance', Gio.SettingsBindFlags.DEFAULT);
|
||||
this._distance_connection = this.settings.connect('changed::display-distance', this._update_display_distance.bind(this));
|
||||
this._follow_threshold_connection = this.settings.connect('changed::follow-threshold', this._update_follow_threshold.bind(this));
|
||||
|
|
@ -591,6 +598,18 @@ export default class BreezyDesktopExtension extends Extension {
|
|||
this.settings.unbind(this._distance_binding);
|
||||
this._distance_binding = null;
|
||||
}
|
||||
if (this._viewport_offset_x_binding) {
|
||||
this.settings.unbind(this._viewport_offset_x_binding);
|
||||
this._viewport_offset_x_binding = null;
|
||||
}
|
||||
if (this._viewport_offset_y_binding) {
|
||||
this.settings.unbind(this._viewport_offset_y_binding);
|
||||
this._viewport_offset_y_binding = null;
|
||||
}
|
||||
if (this._monitor_wrapping_scheme_binding) {
|
||||
this.settings.unbind(this._monitor_wrapping_scheme_binding);
|
||||
this._monitor_wrapping_scheme_binding = null;
|
||||
}
|
||||
if (this._distance_connection) {
|
||||
this.settings.disconnect(this._distance_connection);
|
||||
this._distance_connection = null;
|
||||
|
|
|
|||
|
|
@ -31,7 +31,6 @@ function findClosestVector(quaternion, vectors, previousClosestIndex) {
|
|||
|
||||
const lookVector = [1.0, 0.0, 0.0]; // NWU vector pointing to the center of the screen
|
||||
const rotatedLookVector = applyQuaternionToVector(lookVector, quaternion);
|
||||
// Globals.logger.log(`\t\t\tRotated look vector: ${rotatedLookVector}`);
|
||||
|
||||
let closestIndex = -1;
|
||||
let closestDistance = Infinity;
|
||||
|
|
@ -54,8 +53,6 @@ function findClosestVector(quaternion, vectors, previousClosestIndex) {
|
|||
}
|
||||
});
|
||||
|
||||
// Globals.logger.log(`\t\t\tClosest monitor: ${closestIndex}, distance: ${closestDistance}`);
|
||||
|
||||
// only switch if the closest monitor is greater than the previous closest by 25%
|
||||
if (previousClosestIndex !== undefined && closestIndex !== previousClosestIndex && closestDistance * 1.25 > previousDistance) {
|
||||
return previousClosestIndex;
|
||||
|
|
@ -68,10 +65,6 @@ function degreesToRadians(degrees) {
|
|||
return degrees * Math.PI / 180.0;
|
||||
}
|
||||
|
||||
function radiansToDegrees(radians) {
|
||||
return radians * 180.0 / Math.PI;
|
||||
}
|
||||
|
||||
/***
|
||||
* @returns {Object} - containing `start`, `center`, and `end` radians for rotating the given monitor
|
||||
*/
|
||||
|
|
@ -247,19 +240,18 @@ export const VirtualMonitorEffect = GObject.registerClass({
|
|||
GObject.ParamFlags.READWRITE,
|
||||
0, 100, 0
|
||||
),
|
||||
'monitor-placements': GObject.ParamSpec.jsobject(
|
||||
'monitor-placements',
|
||||
'Monitor Placements',
|
||||
'Target and virtual monitor placement details, as relevant to rendering',
|
||||
GObject.ParamFlags.READWRITE
|
||||
),
|
||||
'imu-snapshots': GObject.ParamSpec.jsobject(
|
||||
'imu-snapshots',
|
||||
'IMU Snapshots',
|
||||
'Latest IMU quaternion snapshots and epoch timestamp for when it was collected',
|
||||
GObject.ParamFlags.READWRITE
|
||||
),
|
||||
'fov-degrees': GObject.ParamSpec.double(
|
||||
'fov-degrees',
|
||||
'FOV Degrees',
|
||||
'Field of view in degrees',
|
||||
GObject.ParamFlags.READWRITE,
|
||||
30.0, 100.0, 46.0
|
||||
),
|
||||
'width': GObject.ParamSpec.int(
|
||||
'width',
|
||||
'Width',
|
||||
|
|
@ -281,13 +273,6 @@ export const VirtualMonitorEffect = GObject.registerClass({
|
|||
GObject.ParamFlags.READWRITE,
|
||||
'horizontal', ['horizontal', 'vertical', 'none']
|
||||
),
|
||||
'monitor-wrapping-rotation-radians': GObject.ParamSpec.double(
|
||||
'monitor-wrapping-rotation-radians',
|
||||
'Monitor Wrapping Rotation Radians',
|
||||
'Rotation of the monitor wrapping around the viewport',
|
||||
GObject.ParamFlags.READWRITE,
|
||||
-360.0, 360.0, 0.0
|
||||
),
|
||||
'focused-monitor-index': GObject.ParamSpec.int(
|
||||
'focused-monitor-index',
|
||||
'Focused Monitor Index',
|
||||
|
|
@ -347,6 +332,8 @@ export const VirtualMonitorEffect = GObject.registerClass({
|
|||
|
||||
this.connect('notify::display-distance', this._update_display_distance.bind(this));
|
||||
this.connect('notify::focused-monitor-index', this._update_display_distance.bind(this));
|
||||
this.connect('notify::monitor-placements', this._update_display_position_uniforms.bind(this));
|
||||
this.connect('notify::monitor-wrapping-scheme', this._update_display_position_uniforms.bind(this));
|
||||
}
|
||||
|
||||
_is_focused() {
|
||||
|
|
@ -361,8 +348,6 @@ export const VirtualMonitorEffect = GObject.registerClass({
|
|||
|
||||
this._distance_ease_timeline.stop();
|
||||
}
|
||||
|
||||
const mid_distance = (this.display_distance_default + desired_distance) / 2;
|
||||
|
||||
// if we're the focused display, we'll double the timeline and wait for the first half to let other
|
||||
// displays ease out first
|
||||
|
|
@ -390,11 +375,28 @@ export const VirtualMonitorEffect = GObject.registerClass({
|
|||
|
||||
this._current_display_distance = this._distance_ease_start +
|
||||
progress * (this._distance_ease_target - this._distance_ease_start);
|
||||
this._update_display_position_uniforms();
|
||||
}).bind(this));
|
||||
|
||||
this._distance_ease_timeline.start();
|
||||
}
|
||||
|
||||
_update_display_position_uniforms() {
|
||||
// this is in NWU coordinates
|
||||
const noRotationVector = this.monitor_placements[this.monitor_index].topLeftNoRotate;
|
||||
Globals.logger.log_debug(`\t\t\tMonitor ${this.monitor_index} vectors: ${JSON.stringify(this.monitor_placements[this.monitor_index])}`);
|
||||
|
||||
// convert to CoGL's east-down-south coordinates and apply display distance
|
||||
this.set_uniform_float(this.get_uniform_location("u_display_position"), 3,
|
||||
[-noRotationVector[1], -noRotationVector[2], this._current_display_distance * -noRotationVector[0]]);
|
||||
|
||||
const rotation_radians = this.monitor_placements[this.monitor_index].rotationAngleRadians;
|
||||
this.set_uniform_float(this.get_uniform_location("u_rotation_x_radians"), 1,
|
||||
[this.monitor_wrapping_scheme === 'vertical' ? rotation_radians : 0.0]);
|
||||
this.set_uniform_float(this.get_uniform_location("u_rotation_y_radians"), 1,
|
||||
[this.monitor_wrapping_scheme === 'horizontal' ? rotation_radians : 0.0]);
|
||||
}
|
||||
|
||||
perspective(fovDiagonalRadians, aspect, near, far) {
|
||||
// compute horizontal fov given diagonal fov and aspect ratio
|
||||
const h = Math.sqrt(aspect * aspect + 1);
|
||||
|
|
@ -516,22 +518,20 @@ export const VirtualMonitorEffect = GObject.registerClass({
|
|||
if (!this._initialized) {
|
||||
const aspect = this.get_actor().width / this.get_actor().height;
|
||||
const projection_matrix = this.perspective(
|
||||
this.fov_degrees * Math.PI / 180.0,
|
||||
Globals.data_stream.device_data.displayFov * Math.PI / 180.0,
|
||||
aspect,
|
||||
0.0001,
|
||||
1000.0
|
||||
);
|
||||
this.set_uniform_matrix(this.get_uniform_location("u_projection_matrix"), false, 4, projection_matrix);
|
||||
this.set_uniform_float(this.get_uniform_location("u_rotation_x_radians"), 1, [this.monitor_wrapping_scheme === 'vertical' ? this.monitor_wrapping_rotation_radians : 0.0]);
|
||||
this.set_uniform_float(this.get_uniform_location("u_rotation_y_radians"), 1, [this.monitor_wrapping_scheme === 'horizontal' ? this.monitor_wrapping_rotation_radians : 0.0]);
|
||||
this.set_uniform_float(this.get_uniform_location("u_display_resolution"), 2, [this.get_actor().width, this.get_actor().height]);
|
||||
this.set_uniform_float(this.get_uniform_location("u_actor_to_display_ratios"), 2, this.actor_to_display_ratios);
|
||||
this.set_uniform_float(this.get_uniform_location("u_actor_to_display_offsets"), 2, this.actor_to_display_offsets);
|
||||
this._update_display_position_uniforms();
|
||||
this._initialized = true;
|
||||
}
|
||||
|
||||
this.set_uniform_float(this.get_uniform_location('u_look_ahead_ms'), 1, [lookAheadMS(this.imu_snapshots.timestamp_ms, 0)]);
|
||||
this.set_uniform_float(this.get_uniform_location("u_display_position"), 3, [this.display_position[0], this.display_position[1], this._current_display_distance * this.display_position[2]]);
|
||||
this.set_uniform_float(this.get_uniform_location('u_look_ahead_ms'), 1, [lookAheadMS(this.imu_snapshots.timestamp_ms, 5)]);
|
||||
this.set_uniform_matrix(this.get_uniform_location("u_imu_data"), false, 4, this.imu_snapshots.imu_data);
|
||||
|
||||
this.get_pipeline().set_layer_filters(
|
||||
|
|
@ -552,25 +552,45 @@ export const VirtualMonitorsActor = GObject.registerClass({
|
|||
'Array of monitor indexes',
|
||||
GObject.ParamFlags.READWRITE
|
||||
),
|
||||
'monitor-wrapping-scheme': GObject.ParamSpec.string(
|
||||
'monitor-wrapping-scheme',
|
||||
'Monitor Wrapping Scheme',
|
||||
'How the monitors are wrapped around the viewport',
|
||||
GObject.ParamFlags.READWRITE,
|
||||
'horizontal', ['horizontal', 'vertical', 'none']
|
||||
),
|
||||
'target-monitor': GObject.ParamSpec.jsobject(
|
||||
'target-monitor',
|
||||
'Target Monitor',
|
||||
'Details about the monitor being used as a viewport',
|
||||
GObject.ParamFlags.READWRITE
|
||||
),
|
||||
'viewport-offset-x': GObject.ParamSpec.double(
|
||||
'viewport-offset-x',
|
||||
'Viewport Offset x',
|
||||
'Offset to apply to the viewport',
|
||||
GObject.ParamFlags.READWRITE,
|
||||
-2.5, 2.5, 0.0
|
||||
),
|
||||
'viewport-offset-y': GObject.ParamSpec.double(
|
||||
'viewport-offset-y',
|
||||
'Viewport Offset y',
|
||||
'Offset to apply to the viewport',
|
||||
GObject.ParamFlags.READWRITE,
|
||||
-2.5, 2.5, 0.0
|
||||
),
|
||||
'monitor-placements': GObject.ParamSpec.jsobject(
|
||||
'monitor-placements',
|
||||
'Monitor Placements',
|
||||
'Target and virtual monitor placement details, as relevant to rendering',
|
||||
GObject.ParamFlags.READWRITE
|
||||
),
|
||||
'imu-snapshots': GObject.ParamSpec.jsobject(
|
||||
'imu-snapshots',
|
||||
'IMU Snapshots',
|
||||
'Latest IMU quaternion snapshots and epoch timestamp for when it was collected',
|
||||
GObject.ParamFlags.READWRITE
|
||||
),
|
||||
'fov-degrees': GObject.ParamSpec.double(
|
||||
'fov-degrees',
|
||||
'FOV Degrees',
|
||||
'Field of view in degrees',
|
||||
GObject.ParamFlags.READWRITE,
|
||||
30.0, 100.0, 46.0
|
||||
),
|
||||
'focused-monitor-index': GObject.ParamSpec.int(
|
||||
'focused-monitor-index',
|
||||
'Focused Monitor Index',
|
||||
|
|
@ -629,34 +649,16 @@ export const VirtualMonitorsActor = GObject.registerClass({
|
|||
this.width = this.target_monitor.width;
|
||||
this.height = this.target_monitor.height;
|
||||
this._frametime_ms = Math.floor(1000 / (this.target_framerate ?? 60.0));
|
||||
|
||||
this._all_monitors = [
|
||||
this.target_monitor,
|
||||
...this.monitors
|
||||
];
|
||||
]
|
||||
}
|
||||
|
||||
renderMonitors() {
|
||||
this._monitorPlacements = monitorsToPlacements(
|
||||
{
|
||||
fovDegrees: this.fov_degrees,
|
||||
widthPixels: this.width,
|
||||
heightPixels: this.height
|
||||
},
|
||||
this._all_monitors.map(monitor => ({
|
||||
x: monitor.x,
|
||||
y: monitor.y,
|
||||
width: monitor.width,
|
||||
height: monitor.height
|
||||
})),
|
||||
'horizontal'
|
||||
);
|
||||
this._update_monitor_placements();
|
||||
|
||||
// normalize the center vectors
|
||||
this._monitorsAsNormalizedVectors = this._monitorPlacements.map(monitorVectors => {
|
||||
const vector = monitorVectors.center;
|
||||
const length = Math.sqrt(vector[0] * vector[0] + vector[1] * vector[1] + vector[2] * vector[2]);
|
||||
return [vector[0] / length, vector[1] / length, vector[2] / length];
|
||||
});
|
||||
const actorToDisplayRatios = [
|
||||
global.stage.width / this.width,
|
||||
global.stage.height / this.height
|
||||
|
|
@ -673,14 +675,8 @@ export const VirtualMonitorsActor = GObject.registerClass({
|
|||
Globals.logger.log_debug(`\t\t\tActor to display ratios: ${actorToDisplayRatios}, offsets: ${actorToDisplayOffsets}`);
|
||||
|
||||
this._all_monitors.forEach(((monitor, index) => {
|
||||
// if (index === 0) return;
|
||||
Globals.logger.log(`\t\t\tMonitor ${index}: ${monitor.x}, ${monitor.y}, ${monitor.width}, ${monitor.height}`);
|
||||
|
||||
// this is in NWU coordinates
|
||||
const noRotationVector = this._monitorPlacements[index].topLeftNoRotate;
|
||||
Globals.logger.log_debug(`\t\t\tMonitor ${index} vectors: ${JSON.stringify(this._monitorPlacements[index])}`);
|
||||
|
||||
// actor coordinates are east-up-south
|
||||
const containerActor = new Clutter.Actor({
|
||||
width: this.width,
|
||||
height: this.height,
|
||||
|
|
@ -700,18 +696,18 @@ export const VirtualMonitorsActor = GObject.registerClass({
|
|||
containerActor.add_child(monitorClone);
|
||||
const effect = new VirtualMonitorEffect({
|
||||
imu_snapshots: this.imu_snapshots,
|
||||
fov_degrees: this.fov_degrees,
|
||||
monitor_index: index,
|
||||
display_position: [-noRotationVector[1], -noRotationVector[2], -noRotationVector[0]],
|
||||
monitor_placements: this.monitor_placements,
|
||||
display_distance: this.display_distance,
|
||||
display_distance_default: Math.max(this.toggle_display_distance_start, this.toggle_display_distance_end),
|
||||
monitor_wrapping_scheme: 'horizontal',
|
||||
monitor_wrapping_rotation_radians: this._monitorPlacements[index].rotationAngleRadians,
|
||||
monitor_wrapping_scheme: this.monitor_wrapping_scheme,
|
||||
actor_to_display_ratios: actorToDisplayRatios,
|
||||
actor_to_display_offsets: actorToDisplayOffsets
|
||||
});
|
||||
containerActor.add_effect_with_name('viewport-effect', effect);
|
||||
this.add_child(containerActor);
|
||||
this.bind_property('monitor-placements', effect, 'monitor-placements', GObject.BindingFlags.DEFAULT);
|
||||
this.bind_property('monitor-wrapping-scheme', effect, 'monitor-wrapping-scheme', GObject.BindingFlags.DEFAULT);
|
||||
this.bind_property('imu-snapshots', effect, 'imu-snapshots', GObject.BindingFlags.DEFAULT);
|
||||
this.bind_property('focused-monitor-index', effect, 'focused-monitor-index', GObject.BindingFlags.DEFAULT);
|
||||
this.bind_property('display-distance', effect, 'display-distance', GObject.BindingFlags.DEFAULT);
|
||||
|
|
@ -729,7 +725,6 @@ export const VirtualMonitorsActor = GObject.registerClass({
|
|||
this._monitorsAsNormalizedVectors, this.closestMonitorIndex
|
||||
);
|
||||
|
||||
// only switch if the closest monitor is greater than the previous closest by 25%
|
||||
if (closestMonitorIndex !== -1 && (this.focused_monitor_index === undefined || this.focused_monitor_index !== closestMonitorIndex)) {
|
||||
Globals.logger.log(`Switching to monitor ${closestMonitorIndex}`);
|
||||
this.focused_monitor_index = closestMonitorIndex;
|
||||
|
|
@ -756,8 +751,37 @@ export const VirtualMonitorsActor = GObject.registerClass({
|
|||
this.connect('notify::toggle-display-distance-start', this._handle_display_distance_properties_change.bind(this));
|
||||
this.connect('notify::toggle-display-distance-end', this._handle_display_distance_properties_change.bind(this));
|
||||
this.connect('notify::display-distance', this._handle_display_distance_properties_change.bind(this));
|
||||
this.connect('notify::viewport-offset-x', this._update_monitor_placements.bind(this));
|
||||
this.connect('notify::viewport-offset-y', this._update_monitor_placements.bind(this));
|
||||
this._handle_display_distance_properties_change();
|
||||
}
|
||||
|
||||
_update_monitor_placements() {
|
||||
Globals.logger.log_debug(`\t\t\tUpdating monitor placements ${this.viewport_offset_x}, ${this.viewport_offset_y} ${Globals.data_stream.device_data.displayFov}`);
|
||||
this.monitor_placements = monitorsToPlacements(
|
||||
{
|
||||
fovDegrees: Globals.data_stream.device_data.displayFov,
|
||||
widthPixels: this.width,
|
||||
heightPixels: this.height
|
||||
},
|
||||
|
||||
// shift all monitors so they center around the target monitor, then adjusted by the offsets
|
||||
this._all_monitors.map(monitor => ({
|
||||
x: monitor.x - this.target_monitor.x - this.viewport_offset_x * this.target_monitor.width,
|
||||
y: monitor.y - this.target_monitor.y - this.viewport_offset_y * this.target_monitor.height,
|
||||
width: monitor.width,
|
||||
height: monitor.height
|
||||
})),
|
||||
this.monitor_wrapping_scheme
|
||||
);
|
||||
|
||||
// normalize the center vectors
|
||||
this._monitorsAsNormalizedVectors = this.monitor_placements.map(monitorVectors => {
|
||||
const vector = monitorVectors.center;
|
||||
const length = Math.sqrt(vector[0] * vector[0] + vector[1] * vector[1] + vector[2] * vector[2]);
|
||||
return [vector[0] / length, vector[1] / length, vector[2] / length];
|
||||
});
|
||||
}
|
||||
|
||||
_handle_display_distance_properties_change() {
|
||||
const distance_from_end = Math.abs(this.display_distance - this.toggle_display_distance_end);
|
||||
|
|
|
|||
|
|
@ -91,6 +91,33 @@
|
|||
The size of the display
|
||||
</description>
|
||||
</key>
|
||||
<key name="viewport-offset-x" type="d">
|
||||
<default>
|
||||
0.0
|
||||
</default>
|
||||
<summary>Viewport offset x</summary>
|
||||
<description>
|
||||
How far to offset the viewport from the target monitor in the x direction
|
||||
</description>
|
||||
</key>
|
||||
<key name="viewport-offset-y" type="d">
|
||||
<default>
|
||||
0.0
|
||||
</default>
|
||||
<summary>Viewport offset y</summary>
|
||||
<description>
|
||||
How far to offset the viewport from the target monitor in the y direction
|
||||
</description>
|
||||
</key>
|
||||
<key name="monitor-wrapping-scheme" type="s">
|
||||
<default>
|
||||
"automatic"
|
||||
</default>
|
||||
<summary>Monitor wrapping scheme</summary>
|
||||
<description>
|
||||
How the monitors are wrapped around the viewport
|
||||
</description>
|
||||
</key>
|
||||
<key name="curved-display" type="b">
|
||||
<default>
|
||||
false
|
||||
|
|
|
|||
|
|
@ -51,6 +51,7 @@ class ConnectedDevice(Gtk.Box):
|
|||
movement_look_ahead_adjustment = Gtk.Template.Child()
|
||||
text_scaling_scale = Gtk.Template.Child()
|
||||
text_scaling_adjustment = Gtk.Template.Child()
|
||||
monitor_wrapping_scheme_menu = Gtk.Template.Child()
|
||||
|
||||
|
||||
def __init__(self):
|
||||
|
|
@ -66,7 +67,8 @@ class ConnectedDevice(Gtk.Box):
|
|||
# self.add_virtual_display_button,
|
||||
self.set_toggle_display_distance_start_button,
|
||||
self.set_toggle_display_distance_end_button,
|
||||
self.movement_look_ahead_scale
|
||||
self.movement_look_ahead_scale,
|
||||
self.monitor_wrapping_scheme_menu
|
||||
]
|
||||
|
||||
self.settings = SettingsManager.get_instance().settings
|
||||
|
|
@ -84,7 +86,10 @@ class ConnectedDevice(Gtk.Box):
|
|||
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.connect('changed::monitor-wrapping-scheme', self._handle_monitor_wrapping_scheme_setting_changed)
|
||||
self.desktop_settings.bind('text-scaling-factor', self.text_scaling_adjustment, 'value', Gio.SettingsBindFlags.DEFAULT)
|
||||
self.monitor_wrapping_scheme_menu.connect('changed', self._handle_monitor_wrapping_scheme_menu_changed)
|
||||
self._handle_monitor_wrapping_scheme_setting_changed()
|
||||
|
||||
bind_shortcut_settings(self.get_parent(), [
|
||||
[self.reassign_toggle_xr_effect_shortcut_button, self.toggle_xr_effect_shortcut_label],
|
||||
|
|
@ -121,6 +126,13 @@ class ConnectedDevice(Gtk.Box):
|
|||
|
||||
self.connect("destroy", self._on_widget_destroy)
|
||||
|
||||
def _handle_monitor_wrapping_scheme_setting_changed(self):
|
||||
current_scheme = self.settings.get_string('monitor-wrapping-scheme')
|
||||
self.monitor_wrapping_scheme_menu.set_active_id(current_scheme)
|
||||
|
||||
def _handle_monitor_wrapping_scheme_menu_changed(self, widget):
|
||||
self.settings.set_string('monitor-wrapping-scheme', widget.get_active_id())
|
||||
|
||||
def _handle_enabled_features(self, state_manager, val):
|
||||
enabled_breezy_features = [feature for feature in state_manager.get_property('enabled-features-list') if feature in BREEZY_GNOME_FEATURES]
|
||||
breezy_features_granted = len(enabled_breezy_features) > 0
|
||||
|
|
|
|||
|
|
@ -152,6 +152,30 @@
|
|||
</child>
|
||||
</object>
|
||||
</child>
|
||||
<child>
|
||||
<object class="AdwActionRow">
|
||||
<property name="title" translatable="yes"><!-- dropdown menu -->Multi-monitor wrapping</property>
|
||||
<property name="subtitle" translatable="yes">When displaying multiple monitors, choose how they should wrap around you</property>
|
||||
<property name="valign">2</property>
|
||||
<child>
|
||||
<object class="GtkBox">
|
||||
<property name="spacing">30</property>
|
||||
<property name="width-request">150</property>
|
||||
<property name="margin-start">30</property>
|
||||
<child>
|
||||
<object class="GtkComboBoxText" id="monitor_wrapping_scheme_menu">
|
||||
<items>
|
||||
<item translatable="yes" id="automatic">Automatic</item>
|
||||
<item translatable="yes" id="horizontal">Horizontal</item>
|
||||
<item translatable="yes" id="vertical">Vertical</item>
|
||||
<item translatable="yes" id="none">None</item>
|
||||
</items>
|
||||
</object>
|
||||
</child>
|
||||
</object>
|
||||
</child>
|
||||
</object>
|
||||
</child>
|
||||
</object>
|
||||
</child>
|
||||
</object>
|
||||
|
|
|
|||
Loading…
Reference in New Issue