Add multi-monitor support (#89)
Rewrite of Breezy Desktop to support multiple virtual displays
This commit is contained in:
parent
07bf239433
commit
8a2926890d
|
|
@ -11,3 +11,4 @@
|
|||
[submodule "ui/modules/PyXRLinuxDriverIPC"]
|
||||
path = ui/modules/PyXRLinuxDriverIPC
|
||||
url = https://github.com/wheaney/PyXRLinuxDriverIPC.git
|
||||
branch = v1.1
|
||||
|
|
|
|||
|
|
@ -7,6 +7,7 @@ if [ -z "$XDG_DATA_HOME" ]; then
|
|||
XDG_DATA_HOME="$USER_HOME/.local/share"
|
||||
fi
|
||||
DATA_DIR="$XDG_DATA_HOME/breezy_gnome"
|
||||
mkdir -p $DATA_DIR
|
||||
|
||||
# if $XDG_DATA_HOME/gnome-shell/extensions/breezydesktop@xronlinux.com exists
|
||||
extension_path="$XDG_DATA_HOME/gnome-shell/extensions/breezydesktop@xronlinux.com"
|
||||
|
|
|
|||
|
|
@ -4,11 +4,10 @@ import * as PointerWatcher from 'resource:///org/gnome/shell/ui/pointerWatcher.j
|
|||
import { MouseSpriteContent } from './cursor.js';
|
||||
import Globals from './globals.js';
|
||||
|
||||
|
||||
// Taken from https://github.com/jkitching/soft-brightness-plus
|
||||
export class CursorManager {
|
||||
constructor(overlay, refreshRate) {
|
||||
this._overlay = overlay;
|
||||
constructor(targetMonitors, refreshRate) {
|
||||
this._targetMonitors = targetMonitors;
|
||||
this._refreshRate = refreshRate;
|
||||
|
||||
// Set/destroyed by _enableCloningMouse/_disableCloningMouse
|
||||
|
|
@ -53,7 +52,7 @@ export class CursorManager {
|
|||
// and will trigger _startCloningMouse when the cursor should be shown
|
||||
_enableCloningMouse() {
|
||||
Globals.logger.log_debug('CursorManager _enableCloningMouse');
|
||||
this._cursorTracker = Meta.CursorTracker.get_for_display(global.display);
|
||||
this._cursorTracker = global.backend.get_cursor_tracker?.() ?? Meta.CursorTracker.get_for_display(global.display);
|
||||
|
||||
this._mouseSprite = new Clutter.Actor({ request_mode: Clutter.RequestMode.CONTENT_SIZE });
|
||||
this._mouseSprite.content = new MouseSpriteContent();
|
||||
|
|
@ -62,13 +61,17 @@ export class CursorManager {
|
|||
this._cursorRoot.add_child(this._mouseSprite);
|
||||
}
|
||||
|
||||
_backend() {
|
||||
return global.stage.get_context?.().get_backend() ?? Clutter.get_default_backend();
|
||||
}
|
||||
|
||||
_hideSystemCursor() {
|
||||
this._systemCursorShown = false;
|
||||
|
||||
this._cursorRoot.show();
|
||||
|
||||
if (!this._cursorUnfocusInhibited) {
|
||||
Clutter.get_default_backend().get_default_seat().inhibit_unfocus();
|
||||
this._backend().get_default_seat().inhibit_unfocus();
|
||||
this._cursorUnfocusInhibited = true;
|
||||
}
|
||||
|
||||
|
|
@ -111,20 +114,16 @@ export class CursorManager {
|
|||
// prereqs: setup in _enableCloningMouse
|
||||
_startCloningMouse() {
|
||||
Globals.logger.log_debug('CursorManager _startCloningMouse');
|
||||
this._overlay.mainActor().add_child(this._cursorRoot);
|
||||
|
||||
this._updateMouseSprite();
|
||||
this._cursorTracker.connectObject('cursor-changed', this._updateMouseSprite.bind(this), this);
|
||||
Meta.disable_unredirect_for_display(global.display);
|
||||
Meta.Compositor?.disable_unredirect?.() ?? Meta.disable_unredirect_for_display(global.display);
|
||||
|
||||
// cap the refresh rate for performance reasons
|
||||
const interval = 1000.0 / Math.min(this._refreshRate, 60);
|
||||
|
||||
this._cursorWatch = PointerWatcher.getPointerWatcher().addWatch(interval, this._updateMousePosition.bind(this));
|
||||
this._updateMousePosition();
|
||||
|
||||
const [xMouse, yMouse] = global.get_pointer();
|
||||
if (this._overlay.isWithinBounds(xMouse, yMouse)) this._hideSystemCursor();
|
||||
}
|
||||
|
||||
// After this:
|
||||
|
|
@ -142,9 +141,8 @@ export class CursorManager {
|
|||
|
||||
if (this._cursorTracker) this._cursorTracker.disconnectObject(this);
|
||||
if (this._mouseSprite?.content?.texture) this._mouseSprite.content.texture = null;
|
||||
Meta.enable_unredirect_for_display(global.display);
|
||||
Meta.Compositor?.enable_unredirect?.() ?? Meta.enable_unredirect_for_display(global.display);
|
||||
|
||||
if (this._cursorRoot) this._overlay.mainActor().remove_child(this._cursorRoot);
|
||||
if (!this._systemCursorShown) this._showSystemCursor();
|
||||
}
|
||||
|
||||
|
|
@ -154,7 +152,7 @@ export class CursorManager {
|
|||
if (this._cursorRoot) this._cursorRoot.hide();
|
||||
|
||||
if (this._cursorUnfocusInhibited) {
|
||||
Clutter.get_default_backend().get_default_seat().uninhibit_unfocus();
|
||||
this._backend().get_default_seat().uninhibit_unfocus();
|
||||
this._cursorUnfocusInhibited = false;
|
||||
}
|
||||
|
||||
|
|
@ -168,23 +166,56 @@ export class CursorManager {
|
|||
|
||||
_updateMousePosition(...args) {
|
||||
const [xMouse, yMouse] = args.length ? args : global.get_pointer();
|
||||
const inBounds = this._overlay.isWithinBounds(xMouse, yMouse);
|
||||
const [xRel, yRel] = this._overlay.getRelativePosition(xMouse, yMouse);
|
||||
let onMonitorIndex;
|
||||
let xRel;
|
||||
let yRel;
|
||||
|
||||
if (xRel === this.xMouse && yRel === this.yMouse)
|
||||
return;
|
||||
const inBoundsCheck = (monitorObj, index) => {
|
||||
const inBoundsCoordinates = this._getInBoundsCoordinates(xMouse, yMouse, monitorObj.monitor);
|
||||
if (inBoundsCoordinates) {
|
||||
onMonitorIndex = index;
|
||||
xRel = inBoundsCoordinates.xRel;
|
||||
yRel = inBoundsCoordinates.yRel;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
if (inBounds) {
|
||||
// check the previously in-bounds monitor first to avoid iterating over the whole list in the likely case that the cursor
|
||||
// is still on the same monitor
|
||||
if (this.onMonitorIndex === undefined || !inBoundsCheck(this._targetMonitors[this.onMonitorIndex], this.onMonitorIndex)) {
|
||||
for (let i = 0; i < this._targetMonitors.length; i++) {
|
||||
if (this.onMonitorIndex === i) continue;
|
||||
if (inBoundsCheck(this._targetMonitors[i], i)) break;
|
||||
}
|
||||
}
|
||||
|
||||
if (this.onMonitorIndex !== onMonitorIndex) {
|
||||
try {
|
||||
if (this.onMonitorIndex !== undefined) this._targetMonitors[this.onMonitorIndex].actor.remove_child(this._cursorRoot);
|
||||
|
||||
this.onMonitorIndex = onMonitorIndex;
|
||||
if (this.onMonitorIndex !== undefined) {
|
||||
const actor = this._targetMonitors[this.onMonitorIndex].actor;
|
||||
actor.add_child(this._cursorRoot);
|
||||
actor.set_child_above_sibling(this._cursorRoot, null);
|
||||
}
|
||||
} catch (e) {
|
||||
Globals.logger.log_debug(e);
|
||||
}
|
||||
}
|
||||
|
||||
if (this.onMonitorIndex !== undefined) {
|
||||
if (this._systemCursorShown) this._hideSystemCursor();
|
||||
this._cursorRoot.set_position(xRel, yRel);
|
||||
} else if (!this._systemCursorShown && !inBounds) {
|
||||
} else if (!this._systemCursorShown) {
|
||||
this._showSystemCursor();
|
||||
}
|
||||
|
||||
this.xMouse = xRel;
|
||||
this.yMouse = yRel;
|
||||
this.xRel = xRel;
|
||||
this.xRel = xRel;
|
||||
|
||||
const seat = Clutter.get_default_backend().get_default_seat();
|
||||
const seat = this._backend().get_default_seat();
|
||||
if (this._cursorUnfocusInhibited && !seat.is_unfocus_inhibited()) {
|
||||
Globals.logger.log_debug('reinhibiting');
|
||||
seat.inhibit_unfocus();
|
||||
|
|
@ -210,4 +241,17 @@ export class CursorManager {
|
|||
this._mouseSprite.hide();
|
||||
}
|
||||
}
|
||||
|
||||
_getInBoundsCoordinates(x, y, monitor) {
|
||||
const xRel = x - monitor.x;
|
||||
const yRel = y - monitor.y;
|
||||
if (xRel >= 0 && xRel < monitor.width && yRel >= 0 && yRel < monitor.height) {
|
||||
return {
|
||||
xRel,
|
||||
yRel,
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,316 @@
|
|||
import Gio from 'gi://Gio';
|
||||
import GObject from 'gi://GObject';
|
||||
|
||||
import Globals from './globals.js';
|
||||
import {
|
||||
dataViewEnd,
|
||||
dataViewUint8,
|
||||
dataViewBigUint,
|
||||
dataViewUint32Array,
|
||||
dataViewUint8Array,
|
||||
dataViewFloat,
|
||||
dataViewFloatArray,
|
||||
BOOL_SIZE,
|
||||
FLOAT_SIZE,
|
||||
UINT_SIZE,
|
||||
UINT8_SIZE
|
||||
} from "./ipc.js";
|
||||
import { isValidKeepAlive, getEpochSec, toSec } from "./time.js";
|
||||
|
||||
const IPC_FILE_PATH = "/dev/shm/breezy_desktop_imu";
|
||||
const KEEPALIVE_REFRESH_INTERVAL_SEC = 1;
|
||||
|
||||
// the driver should be using the same data layout version
|
||||
const DATA_LAYOUT_VERSION = 4;
|
||||
|
||||
// DataView info: [offset, size, count]
|
||||
const VERSION = [0, UINT8_SIZE, 1];
|
||||
const ENABLED = [dataViewEnd(VERSION), BOOL_SIZE, 1];
|
||||
const LOOK_AHEAD_CFG = [dataViewEnd(ENABLED), FLOAT_SIZE, 4];
|
||||
const DISPLAY_RES = [dataViewEnd(LOOK_AHEAD_CFG), UINT_SIZE, 2];
|
||||
const DISPLAY_FOV = [dataViewEnd(DISPLAY_RES), FLOAT_SIZE, 1];
|
||||
const LENS_DISTANCE_RATIO = [dataViewEnd(DISPLAY_FOV), FLOAT_SIZE, 1];
|
||||
const SBS_ENABLED = [dataViewEnd(LENS_DISTANCE_RATIO), BOOL_SIZE, 1];
|
||||
const CUSTOM_BANNER_ENABLED = [dataViewEnd(SBS_ENABLED), BOOL_SIZE, 1];
|
||||
const SMOOTH_FOLLOW_ENABLED = [dataViewEnd(CUSTOM_BANNER_ENABLED), BOOL_SIZE, 1];
|
||||
const SMOOTH_FOLLOW_ORIGIN_DATA = [dataViewEnd(SMOOTH_FOLLOW_ENABLED), FLOAT_SIZE, 16];
|
||||
const EPOCH_MS = [dataViewEnd(SMOOTH_FOLLOW_ORIGIN_DATA), UINT_SIZE, 2];
|
||||
const IMU_QUAT_DATA = [dataViewEnd(EPOCH_MS), FLOAT_SIZE, 16];
|
||||
const IMU_PARITY_BYTE = [dataViewEnd(IMU_QUAT_DATA), UINT8_SIZE, 1];
|
||||
const DATA_VIEW_LENGTH = dataViewEnd(IMU_PARITY_BYTE);
|
||||
|
||||
function checkParityByte(dataView) {
|
||||
const parityByte = dataViewUint8(dataView, IMU_PARITY_BYTE);
|
||||
let parity = 0;
|
||||
const epochUint8 = dataViewUint8Array(dataView, EPOCH_MS);
|
||||
const imuDataUint8 = dataViewUint8Array(dataView, IMU_QUAT_DATA);
|
||||
for (let i = 0; i < epochUint8.length; i++) {
|
||||
parity ^= epochUint8[i];
|
||||
}
|
||||
for (let i = 0; i < imuDataUint8.length; i++) {
|
||||
parity ^= imuDataUint8[i];
|
||||
}
|
||||
return parityByte === parity;
|
||||
}
|
||||
|
||||
const COUNTER_MAX = 300;
|
||||
function nextDebugIMUQuaternion(counter) {
|
||||
const angle = counter / COUNTER_MAX * 2 * Math.PI;
|
||||
const yaw = 10 * Math.PI / 180 * Math.cos(angle);
|
||||
const roll = 0;
|
||||
const pitch = 10 * Math.PI / 180 * Math.sin(angle);
|
||||
|
||||
const cy = Math.cos(yaw * 0.5);
|
||||
const sy = Math.sin(yaw * 0.5);
|
||||
const cp = Math.cos(pitch * 0.5);
|
||||
const sp = Math.sin(pitch * 0.5);
|
||||
const cr = Math.cos(roll * 0.5);
|
||||
const sr = Math.sin(roll * 0.5);
|
||||
|
||||
const w = cr * cp * cy + sr * sp * sy;
|
||||
const x = sr * cp * cy - cr * sp * sy;
|
||||
const y = cr * sp * cy + sr * cp * sy;
|
||||
const z = cr * cp * sy - sr * sp * cy;
|
||||
|
||||
return [x, y, z, w];
|
||||
}
|
||||
|
||||
export const DeviceDataStream = GObject.registerClass({
|
||||
Properties: {
|
||||
'breezy-desktop-running': GObject.ParamSpec.boolean(
|
||||
'breezy-desktop-running',
|
||||
'Breezy Desktop running',
|
||||
'Whether Breezy Desktop mode is enabled in xr_driver and supported glasses are connected',
|
||||
GObject.ParamFlags.READWRITE,
|
||||
false
|
||||
),
|
||||
'widescreen-mode-state': GObject.ParamSpec.boolean(
|
||||
'widescreen-mode-state',
|
||||
'Widescreen mode state',
|
||||
'The state of widescreen mode from the perspective of the driver',
|
||||
GObject.ParamFlags.READWRITE,
|
||||
false
|
||||
),
|
||||
'imu-snapshots': GObject.ParamSpec.jsobject(
|
||||
'imu-snapshots',
|
||||
'IMU Snapshots',
|
||||
'Latest IMU quaternion snapshots and epoch timestamp for when it was collected',
|
||||
GObject.ParamFlags.READWRITE
|
||||
),
|
||||
'smooth-follow-enabled': GObject.ParamSpec.boolean(
|
||||
'smooth-follow-enabled',
|
||||
'Smooth follow enabled',
|
||||
'Whether smooth follow is enabled',
|
||||
GObject.ParamFlags.READWRITE,
|
||||
false
|
||||
),
|
||||
'show-banner': GObject.ParamSpec.boolean(
|
||||
'show-banner',
|
||||
'Show banner',
|
||||
'Whether the banner should be displayed',
|
||||
GObject.ParamFlags.READWRITE,
|
||||
false
|
||||
),
|
||||
'custom-banner-enabled': GObject.ParamSpec.boolean(
|
||||
'custom-banner-enabled',
|
||||
'Custom banner enabled',
|
||||
'Whether the custom banner should be displayed',
|
||||
GObject.ParamFlags.READWRITE,
|
||||
false
|
||||
),
|
||||
'debug-no-device': GObject.ParamSpec.boolean(
|
||||
'debug-no-device',
|
||||
'Debug without device',
|
||||
'Debug mode that allows for testing with moving IMU values without a device connected',
|
||||
GObject.ParamFlags.READWRITE,
|
||||
false
|
||||
)
|
||||
}
|
||||
}, class DeviceDataStream extends GObject.Object {
|
||||
constructor(params = {}) {
|
||||
super(params);
|
||||
|
||||
// this may be set true if debug_no_device is set, so it doesn't mean a device is actually connected
|
||||
this.breezy_desktop_running = false;
|
||||
|
||||
// use this property to set whether breezy is being operated by a real device
|
||||
this.breezy_desktop_actually_running = false;
|
||||
|
||||
this._ipc_file = Gio.file_new_for_path(IPC_FILE_PATH);
|
||||
this._running = false;
|
||||
this.device_data = null;
|
||||
}
|
||||
|
||||
start() {
|
||||
this._running = true;
|
||||
this._poll();
|
||||
}
|
||||
|
||||
stop() {
|
||||
this._running = false;
|
||||
this.device_data = null;
|
||||
this.imu_snapshots = null;
|
||||
}
|
||||
|
||||
// polling is just intended to keep breezy_desktop_running current, anything needing up-to-date imu data should
|
||||
// trigger a refresh with the default flag
|
||||
_poll() {
|
||||
if (this._running) {
|
||||
this.refresh_data(true);
|
||||
setTimeout(this._poll.bind(this), 1000);
|
||||
}
|
||||
}
|
||||
|
||||
// Refresh the data from the IPC file. if keepalive_only is true, we'll only check and update breezy_desktop_running if it
|
||||
// hasn't been checked within KEEPALIVE_REFRESH_INTERVAL_SEC.
|
||||
refresh_data(keepalive_only = false) {
|
||||
if (!this.debug_no_device && this.was_debug_no_device) {
|
||||
this.was_debug_no_device = false;
|
||||
if (!this.breezy_desktop_actually_running) {
|
||||
this.device_data = null;
|
||||
this.breezy_desktop_running = false;
|
||||
this.breezy_desktop_actually_running = false;
|
||||
this.imu_snapshots = null;
|
||||
}
|
||||
}
|
||||
|
||||
if (this._ipc_file.query_exists(null) && (
|
||||
!this.device_data?.imuData ||
|
||||
!keepalive_only ||
|
||||
getEpochSec() - toSec(this.device_data?.imuDateMs ?? 0) > KEEPALIVE_REFRESH_INTERVAL_SEC
|
||||
)) {
|
||||
let data = this._ipc_file.load_contents(null);
|
||||
if (data[0]) {
|
||||
let buffer = new Uint8Array(data[1]).buffer;
|
||||
let dataView = new DataView(buffer);
|
||||
if (dataView.byteLength === DATA_VIEW_LENGTH) {
|
||||
let imuDateMs = dataViewBigUint(dataView, EPOCH_MS);
|
||||
const displayFov = dataViewFloat(dataView, DISPLAY_FOV);
|
||||
const validKeepAlive = isValidKeepAlive(toSec(imuDateMs));
|
||||
const validData = validKeepAlive && displayFov !== 0.0;
|
||||
const version = dataViewUint8(dataView, VERSION);
|
||||
const enabled = dataViewUint8(dataView, ENABLED) !== 0 && version === DATA_LAYOUT_VERSION && validData;
|
||||
let imuData = dataViewFloatArray(dataView, IMU_QUAT_DATA);
|
||||
let smoothFollowEnabled = dataViewUint8(dataView, SMOOTH_FOLLOW_ENABLED) !== 0;
|
||||
let smoothFollowOrigin = dataViewFloatArray(dataView, SMOOTH_FOLLOW_ORIGIN_DATA);
|
||||
const imuResetState = enabled && validData && imuData[0] === 0.0 && imuData[1] === 0.0 && imuData[2] === 0.0 && imuData[3] === 1.0;
|
||||
const customBannerEnabled = dataViewUint8(dataView, CUSTOM_BANNER_ENABLED) !== 0;
|
||||
const sbsEnabled = dataViewUint8(dataView, SBS_ENABLED) !== 0;
|
||||
|
||||
if (validKeepAlive && !validData) Globals.logger.log('[ERROR] Received invalid device data');
|
||||
|
||||
// trigger "notify::" events for properties we want to check on every cycle
|
||||
if (enabled && this.widescreen_mode_state !== sbsEnabled) this.widescreen_mode_state = sbsEnabled;
|
||||
if (this.show_banner !== imuResetState) this.show_banner = imuResetState;
|
||||
if (this.custom_banner_enabled !== customBannerEnabled) this.custom_banner_enabled = customBannerEnabled;
|
||||
|
||||
let success = keepalive_only;
|
||||
if (validData) {
|
||||
if (!this.device_data) {
|
||||
this.device_data = {
|
||||
version,
|
||||
enabled,
|
||||
imuResetState,
|
||||
displayRes: dataViewUint32Array(dataView, DISPLAY_RES),
|
||||
sbsEnabled,
|
||||
displayFov,
|
||||
lookAheadCfg: dataViewFloatArray(dataView, LOOK_AHEAD_CFG),
|
||||
lensDistanceRatio: dataViewFloat(dataView, LENS_DISTANCE_RATIO)
|
||||
};
|
||||
} else if (keepalive_only) {
|
||||
this.device_data = {
|
||||
...this.device_data,
|
||||
imuResetState,
|
||||
enabled,
|
||||
sbsEnabled
|
||||
}
|
||||
}
|
||||
|
||||
if (smoothFollowEnabled !== this.smooth_follow_enabled) {
|
||||
Globals.logger.log_debug(`Smooth follow enabled: ${smoothFollowEnabled}`);
|
||||
this.smooth_follow_enabled = smoothFollowEnabled;
|
||||
}
|
||||
this.imu_snapshots = {
|
||||
...(this.imu_snapshots ?? {}),
|
||||
smooth_follow_origin: smoothFollowOrigin
|
||||
}
|
||||
|
||||
let attempts = 0;
|
||||
while (!success && attempts < 2) {
|
||||
if (dataView.byteLength === DATA_VIEW_LENGTH) {
|
||||
if (checkParityByte(dataView)) {
|
||||
|
||||
this.imu_snapshots = {
|
||||
imu_data: imuData,
|
||||
timestamp_ms: imuDateMs,
|
||||
smooth_follow_origin: smoothFollowOrigin
|
||||
};
|
||||
success = true;
|
||||
}
|
||||
} else if (dataView.byteLength !== 0) {
|
||||
Globals.logger.log(`[ERROR] Invalid dataView.byteLength: ${dataView.byteLength} !== ${DATA_VIEW_LENGTH}`)
|
||||
}
|
||||
|
||||
if (!success && ++attempts < 2) {
|
||||
data = this._ipc_file.load_contents(null);
|
||||
if (data[0]) {
|
||||
buffer = new Uint8Array(data[1]).buffer;
|
||||
dataView = new DataView(buffer);
|
||||
imuDateMs = dataViewBigUint(dataView, EPOCH_MS);
|
||||
imuData = dataViewFloatArray(dataView, IMU_QUAT_DATA);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
this.breezy_desktop_actually_running = success && enabled && validData;
|
||||
} else {
|
||||
this.breezy_desktop_actually_running = false;
|
||||
}
|
||||
} else {
|
||||
this.breezy_desktop_actually_running = false;
|
||||
}
|
||||
}
|
||||
|
||||
if (this.debug_no_device && !this.breezy_desktop_actually_running) {
|
||||
if (!this.device_data || !this.was_debug_no_device) {
|
||||
this.device_data = {
|
||||
version: 1.0,
|
||||
enabled: true,
|
||||
imuResetState: false,
|
||||
displayRes: [1920.0, 1080.0],
|
||||
sbsEnabled: false,
|
||||
displayFov: 46.0,
|
||||
lookAheadCfg: [0.0, 0.0, 0.0, 0.0],
|
||||
lensDistanceRatio: 0.05
|
||||
}
|
||||
}
|
||||
this.was_debug_no_device = true;
|
||||
|
||||
if (!keepalive_only) {
|
||||
this._counter = ((this._counter ?? -1)+1)%COUNTER_MAX;
|
||||
|
||||
const imuDataFirst = nextDebugIMUQuaternion(this._counter);
|
||||
const imuData = [
|
||||
...imuDataFirst,
|
||||
...imuDataFirst,
|
||||
...imuDataFirst,
|
||||
2.0, 1.0, 0.0, 0.0
|
||||
]
|
||||
this.imu_snapshots = {
|
||||
imu_data: imuData,
|
||||
timestamp_ms: Date.now(),
|
||||
smooth_follow_origin: [0.0, 0.0, 0.0, 1.0]
|
||||
};
|
||||
}
|
||||
this.breezy_desktop_running = true;
|
||||
} else if (this.breezy_desktop_running !== this.breezy_desktop_actually_running) {
|
||||
// update the breezy_desktop_running property if the state changes to trigger "notify::" events
|
||||
this.breezy_desktop_running = this.breezy_desktop_actually_running;
|
||||
if (!this.breezy_desktop_running && keepalive_only) {
|
||||
this.device_data = null;
|
||||
this.imu_snapshots = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
|
|
@ -1,34 +1,19 @@
|
|||
import Clutter from 'gi://Clutter'
|
||||
import Gio from 'gi://Gio';
|
||||
import GLib from 'gi://GLib';
|
||||
import Meta from 'gi://Meta';
|
||||
import Shell from 'gi://Shell';
|
||||
import St from 'gi://St';
|
||||
|
||||
import { CursorManager } from './cursormanager.js';
|
||||
import { DeviceDataStream } from './devicedatastream.js';
|
||||
import Globals from './globals.js';
|
||||
import { Logger } from './logger.js';
|
||||
import { MonitorManager } from './monitormanager.js';
|
||||
import { Overlay } from './overlay.js';
|
||||
import { isValidKeepAlive } from './time.js';
|
||||
import { IPC_FILE_PATH, XREffect } from './xrEffect.js';
|
||||
import { MonitorManager, NESTED_MONITOR_PRODUCT, SUPPORTED_MONITOR_PRODUCTS, VIRTUAL_MONITOR_PRODUCT } from './monitormanager.js';
|
||||
import { VirtualDisplaysActor } from './virtualdisplaysactor.js';
|
||||
|
||||
import {Extension} from 'resource:///org/gnome/shell/extensions/extension.js';
|
||||
import * as Main from 'resource:///org/gnome/shell/ui/main.js';
|
||||
|
||||
const NESTED_MONITOR_PRODUCT = 'MetaMonitor';
|
||||
const SUPPORTED_MONITOR_PRODUCTS = [
|
||||
'VITURE',
|
||||
'nreal air',
|
||||
'Air',
|
||||
'Air 2',
|
||||
'Air 2 Pro',
|
||||
'Air 2 Ultra',
|
||||
'SmartGlasses', // TCL/RayNeo
|
||||
'Rokid Max',
|
||||
'Rokid Air',
|
||||
NESTED_MONITOR_PRODUCT
|
||||
];
|
||||
|
||||
const BIN_HOME = GLib.getenv('XDG_BIN_HOME') || GLib.build_filenamev([GLib.get_home_dir(), '.local', 'bin']);
|
||||
const XDG_CLI_PATH = GLib.build_filenamev([BIN_HOME, 'xr_driver_cli']);
|
||||
const ALT_CLI_PATH = '/usr/bin/xr_driver_cli';
|
||||
|
|
@ -42,26 +27,17 @@ export default class BreezyDesktopExtension extends Extension {
|
|||
// Set/destroyed by enable/disable
|
||||
this._cursor_manager = null;
|
||||
this._monitor_manager = null;
|
||||
this._xr_effect = null;
|
||||
this._overlay = null;
|
||||
this._virtual_displays_actor = null;
|
||||
this._virtual_displays_overlay = null;
|
||||
this._target_monitor = null;
|
||||
this._is_effect_running = false;
|
||||
this._distance_binding = null;
|
||||
this._effect_settings_bindings = [];
|
||||
this._data_stream_bindings = [];
|
||||
this._show_banner_connection = null;
|
||||
this._distance_connection = null;
|
||||
this._focused_monitor_distance_connection = null;
|
||||
this._follow_threshold_connection = null;
|
||||
this._widescreen_mode_settings_connection = null;
|
||||
this._widescreen_mode_effect_state_connection = null;
|
||||
this._supported_device_detected_connected = null;
|
||||
this._start_binding = null;
|
||||
this._end_binding = null;
|
||||
this._curved_display_binding = null;
|
||||
this._display_size_binding = null;
|
||||
this._look_ahead_override_binding = null;
|
||||
this._disable_anti_aliasing_binding = null;
|
||||
this._optimal_monitor_config_binding = null;
|
||||
this._headset_as_primary_binding = null;
|
||||
this._actor_added_connection = null;
|
||||
this._actor_removed_connection = null;
|
||||
this._breezy_desktop_running_connection = null;
|
||||
|
||||
if (!Globals.logger) {
|
||||
Globals.logger = new Logger({
|
||||
|
|
@ -70,6 +46,12 @@ export default class BreezyDesktopExtension extends Extension {
|
|||
});
|
||||
Globals.logger.logVersion();
|
||||
}
|
||||
|
||||
if (!Globals.data_stream) {
|
||||
Globals.data_stream = new DeviceDataStream({
|
||||
debug_no_device: this.settings.get_boolean('debug-no-device')
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
enable() {
|
||||
|
|
@ -77,21 +59,27 @@ export default class BreezyDesktopExtension extends Extension {
|
|||
|
||||
try {
|
||||
Globals.extension_dir = this.path;
|
||||
this.settings.bind('debug', Globals.logger, 'debug', Gio.SettingsBindFlags.DEFAULT);
|
||||
|
||||
Globals.data_stream.start();
|
||||
|
||||
this._monitor_manager = new MonitorManager({
|
||||
use_optimal_monitor_config: this.settings.get_boolean('use-optimal-monitor-config'),
|
||||
headset_as_primary: this.settings.get_boolean('headset-as-primary'),
|
||||
use_highest_refresh_rate: this.settings.get_boolean('use-highest-refresh-rate'),
|
||||
disable_physical_displays: this.settings.get_boolean('disable-physical-displays'),
|
||||
extension_path: this.path
|
||||
});
|
||||
this._monitor_manager.setChangeHook(this._handle_monitor_change.bind(this));
|
||||
this._monitor_manager.enable();
|
||||
|
||||
this._optimal_monitor_config_binding = this.settings.bind('use-optimal-monitor-config',
|
||||
this._monitor_manager, 'use-optimal-monitor-config', Gio.SettingsBindFlags.DEFAULT);
|
||||
this._headset_as_primary_binding = this.settings.bind('headset-as-primary',
|
||||
this._monitor_manager, 'headset-as-primary', Gio.SettingsBindFlags.DEFAULT);
|
||||
this.settings.bind('debug', Globals.logger, 'debug', Gio.SettingsBindFlags.DEFAULT);
|
||||
this.settings.bind('use-optimal-monitor-config',this._monitor_manager, 'use-optimal-monitor-config', Gio.SettingsBindFlags.DEFAULT);
|
||||
this.settings.bind('headset-as-primary', this._monitor_manager, 'headset-as-primary', Gio.SettingsBindFlags.DEFAULT);
|
||||
this.settings.bind('disable-physical-displays', this._monitor_manager, 'disable-physical-displays', Gio.SettingsBindFlags.DEFAULT);
|
||||
this.settings.bind('debug-no-device', Globals.data_stream, 'debug-no-device', Gio.SettingsBindFlags.DEFAULT);
|
||||
|
||||
this._breezy_desktop_running_connection = Globals.data_stream.connect('notify::breezy-desktop-running',
|
||||
this._handle_breezy_desktop_running_change.bind(this));
|
||||
|
||||
this._cli_file = Gio.file_new_for_path(XDG_CLI_PATH);
|
||||
if (!this._cli_file.query_exists(null)) {
|
||||
|
|
@ -108,62 +96,52 @@ export default class BreezyDesktopExtension extends Extension {
|
|||
}
|
||||
}
|
||||
|
||||
_poll_for_ready() {
|
||||
Globals.logger.log_debug('BreezyDesktopExtension _poll_for_ready');
|
||||
var target_monitor = this._target_monitor;
|
||||
var is_effect_running = this._is_effect_running;
|
||||
this._running_poller_id = GLib.timeout_add(GLib.PRIORITY_DEFAULT, 1000, (() => {
|
||||
try {
|
||||
if (is_effect_running) {
|
||||
this._running_poller_id = undefined;
|
||||
return GLib.SOURCE_REMOVE;
|
||||
}
|
||||
|
||||
if (this._check_driver_running() && target_monitor) {
|
||||
// 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,
|
||||
// so we can remove this timeout_add no matter what.
|
||||
if (this._target_monitor_ready(target_monitor)) {
|
||||
Globals.logger.log('Driver is running, supported monitor connected. Enabling XR effect.');
|
||||
this._effect_enable();
|
||||
}
|
||||
this._running_poller_id = undefined;
|
||||
return GLib.SOURCE_REMOVE;
|
||||
} else {
|
||||
return GLib.SOURCE_CONTINUE;
|
||||
}
|
||||
} catch (e) {
|
||||
Globals.logger.log(`[ERROR] BreezyDesktopExtension _poll_for_ready ${e.message}\n${e.stack}`);
|
||||
this._running_poller_id = undefined;
|
||||
return GLib.SOURCE_REMOVE;
|
||||
_find_virtual_monitors() {
|
||||
try {
|
||||
Globals.logger.log_debug('BreezyDesktopExtension _find_virtual_monitors');
|
||||
const virtual_monitors = this._monitor_manager.getMonitorPropertiesList()?.filter(
|
||||
monitor => monitor && monitor.product === VIRTUAL_MONITOR_PRODUCT);
|
||||
if (virtual_monitors.length > 0) {
|
||||
Globals.logger.log(`Found ${virtual_monitors.length} virtual monitors`);
|
||||
return virtual_monitors.map(monitor => {
|
||||
return this._monitor_manager.getMonitors()[monitor.index];
|
||||
});
|
||||
}
|
||||
}).bind(this));
|
||||
|
||||
Globals.logger.log_debug('BreezyDesktopExtension _find_virtual_monitors - No virtual monitors found');
|
||||
} catch (e) {
|
||||
Globals.logger.log(`[ERROR] BreezyDesktopExtension _find_virtual_monitors ${e.message}\n${e.stack}`)
|
||||
}
|
||||
|
||||
return [];
|
||||
}
|
||||
|
||||
_find_supported_monitor() {
|
||||
if (!this._monitor_manager.getMonitorPropertiesList()) return null;
|
||||
|
||||
try {
|
||||
Globals.logger.log_debug('BreezyDesktopExtension _find_supported_monitor');
|
||||
const target_monitor = this._monitor_manager.getMonitorPropertiesList()?.find(
|
||||
monitor => SUPPORTED_MONITOR_PRODUCTS.includes(monitor.product) ||
|
||||
this.settings.get_string('custom-monitor-product') === monitor.product);
|
||||
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
|
||||
};
|
||||
}
|
||||
|
||||
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
|
||||
is_dummy: is_dummy,
|
||||
is_virtual: target_monitor.product === VIRTUAL_MONITOR_PRODUCT
|
||||
};
|
||||
}
|
||||
|
||||
|
|
@ -176,8 +154,7 @@ export default class BreezyDesktopExtension extends Extension {
|
|||
}
|
||||
|
||||
// Assumes target_monitor is set, and was returned by _find_supported_monitor.
|
||||
// A false result means we'll expect _handle_monitor_change to be triggered, so active polling
|
||||
// can be disabled.
|
||||
// A false result means we'll expect _handle_monitor_change to be triggered
|
||||
_target_monitor_ready(target_monitor) {
|
||||
if (target_monitor.is_dummy) return true;
|
||||
|
||||
|
|
@ -194,49 +171,26 @@ export default class BreezyDesktopExtension extends Extension {
|
|||
Globals.logger.log('Reset triggered, disabling XR effect');
|
||||
this._effect_disable(!for_disable);
|
||||
}
|
||||
const target_monitor = this._find_supported_monitor();
|
||||
|
||||
// if target_monitor isn't set, do nothing and wait for MonitorManager to call this again
|
||||
if (target_monitor && this._running_poller_id === undefined) {
|
||||
this._target_monitor = target_monitor;
|
||||
|
||||
if (this._check_driver_running()) {
|
||||
this._target_monitor = this._find_supported_monitor();
|
||||
if (this._target_monitor) {
|
||||
if (Globals.data_stream.breezy_desktop_running) {
|
||||
// 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
|
||||
if (this._target_monitor_ready(target_monitor)) {
|
||||
if (this._target_monitor_ready(this._target_monitor)) {
|
||||
Globals.logger.log('Ready, enabling XR effect');
|
||||
this._effect_enable();
|
||||
} else {
|
||||
Globals.logger.log_debug('BreezyDesktopExtension _setup - driver running but async monitor action needed');
|
||||
Globals.logger.log_debug('BreezyDesktopExtension _setup - breezy desktop enabled, but async monitor action needed');
|
||||
}
|
||||
} else {
|
||||
Globals.logger.log_debug('BreezyDesktopExtension _setup - driver not running, starting poller');
|
||||
this._poll_for_ready();
|
||||
Globals.logger.log_debug('BreezyDesktopExtension _setup - Doing nothing, target monitor found, but device stream not being received');
|
||||
}
|
||||
} else {
|
||||
if (!target_monitor) {
|
||||
Globals.logger.log_debug(`BreezyDesktopExtension _setup - Doing nothing, no supported monitor found`);
|
||||
} else {
|
||||
Globals.logger.log_debug(`BreezyDesktopExtension _setup - Doing nothing, target monitor found, waiting for poller to pick it up`);
|
||||
}
|
||||
Globals.logger.log_debug(`BreezyDesktopExtension _setup - Doing nothing, no supported monitor found, breezy_desktop_running: ${Globals.data_stream.breezy_desktop_running}`);
|
||||
}
|
||||
}
|
||||
|
||||
_check_driver_running() {
|
||||
try {
|
||||
if (!Globals.ipc_file) Globals.ipc_file = Gio.file_new_for_path(IPC_FILE_PATH);
|
||||
if (Globals.ipc_file.query_exists(null)) {
|
||||
const file_info = Globals.ipc_file.query_info(Gio.FILE_ATTRIBUTE_TIME_MODIFIED, Gio.FileQueryInfoFlags.NONE, null);
|
||||
const file_modified_time = file_info.get_attribute_uint64(Gio.FILE_ATTRIBUTE_TIME_MODIFIED);
|
||||
return isValidKeepAlive(file_modified_time);
|
||||
}
|
||||
} catch (e) {
|
||||
Globals.logger.log(`[ERROR] BreezyDesktopExtension _check_driver_running ${e.message}\n${e.stack}`);
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
_needs_widescreen_monitor_update() {
|
||||
Globals.logger.log_debug('BreezyDesktopExtension _needs_widescreen_monitor_update');
|
||||
const state = this._read_state();
|
||||
|
|
@ -253,79 +207,105 @@ export default class BreezyDesktopExtension extends Extension {
|
|||
|
||||
_effect_enable() {
|
||||
Globals.logger.log_debug('BreezyDesktopExtension _effect_enable');
|
||||
this._running_poller_id = undefined;
|
||||
if (!this._is_effect_running) {
|
||||
this._is_effect_running = true;
|
||||
|
||||
try {
|
||||
const targetMonitor = this._target_monitor.monitor;
|
||||
const virtualMonitors = this._find_virtual_monitors();
|
||||
const refreshRate = targetMonitor.refreshRate ?? 60;
|
||||
this._overlay = new Overlay(targetMonitor);
|
||||
|
||||
this._cursor_manager = new CursorManager(this._overlay, refreshRate);
|
||||
this._cursor_manager.enable();
|
||||
// use rgba(255, 4, 144, 1) for chroma key background
|
||||
this._virtual_displays_overlay = new St.Bin({ style: 'background-color: rgba(0, 0, 0, 1);', clip_to_allocation: true });
|
||||
this._virtual_displays_overlay.opacity = 255;
|
||||
this._virtual_displays_overlay.set_position(targetMonitor.x, targetMonitor.y);
|
||||
this._virtual_displays_overlay.set_size(targetMonitor.width, targetMonitor.height);
|
||||
|
||||
// In GS 45, use of "actor" was renamed to "child".
|
||||
const clutterContainer = Clutter.Container !== undefined;
|
||||
this._actor_added_connection = global.stage.connect(
|
||||
clutterContainer ? 'actor-added' : 'child-added',
|
||||
this._handle_sibling_update.bind(this),
|
||||
);
|
||||
this._actor_removed_connection = global.stage.connect(
|
||||
clutterContainer ? 'actor-removed' : 'child-removed',
|
||||
this._handle_sibling_update.bind(this),
|
||||
);
|
||||
|
||||
this._xr_effect = new XREffect({
|
||||
Globals.data_stream.refresh_data();
|
||||
this._virtual_displays_actor = new VirtualDisplaysActor({
|
||||
width: targetMonitor.width,
|
||||
height: targetMonitor.height,
|
||||
target_monitor: targetMonitor,
|
||||
target_framerate: refreshRate,
|
||||
virtual_monitors: virtualMonitors,
|
||||
monitor_wrapping_scheme: this.settings.get_string('monitor-wrapping-scheme'),
|
||||
monitor_spacing: this.settings.get_int('monitor-spacing'),
|
||||
viewport_offset_x: this.settings.get_double('viewport-offset-x'),
|
||||
viewport_offset_y: this.settings.get_double('viewport-offset-y'),
|
||||
display_distance: this.settings.get_double('display-distance'),
|
||||
toggle_display_distance_start: this.settings.get_double('toggle-display-distance-start'),
|
||||
toggle_display_distance_end: this.settings.get_double('toggle-display-distance-end'),
|
||||
look_ahead_override: this.settings.get_int('look-ahead-override'),
|
||||
disable_anti_aliasing: this.settings.get_boolean('disable-anti-aliasing')
|
||||
framerate_cap: this.settings.get_double('framerate-cap'),
|
||||
imu_snapshots: Globals.data_stream.imu_snapshots,
|
||||
show_banner: Globals.data_stream.show_banner,
|
||||
custom_banner_enabled: Globals.data_stream.custom_banner_enabled
|
||||
});
|
||||
|
||||
this._virtual_displays_overlay.set_child(this._virtual_displays_actor);
|
||||
this._virtual_displays_actor.renderMonitors();
|
||||
|
||||
Shell.util_set_hidden_from_pick(this._virtual_displays_overlay, true);
|
||||
global.stage.add_child(this._virtual_displays_overlay);
|
||||
|
||||
const cursor_manager_monitor_objs = this._virtual_displays_actor.monitor_actors.map(monitor => {
|
||||
return {
|
||||
monitor: monitor.monitorDetails,
|
||||
actor: monitor.containerActor
|
||||
};
|
||||
});
|
||||
|
||||
this._cursor_manager = new CursorManager(cursor_manager_monitor_objs, refreshRate);
|
||||
this._cursor_manager.enable();
|
||||
|
||||
this._update_follow_threshold(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._supported_device_detected_connected = this._xr_effect.connect('notify::supported-device-detected', this._handle_supported_device_change.bind(this));
|
||||
|
||||
this._distance_binding = this.settings.bind('display-distance', this._xr_effect, '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))
|
||||
this._data_stream_bindings = [
|
||||
'show-banner',
|
||||
'custom-banner-enabled',
|
||||
'smooth-follow-enabled'
|
||||
].map(data_stream_key =>
|
||||
Globals.data_stream.bind_property(data_stream_key, this._virtual_displays_actor, data_stream_key, Gio.SettingsBindFlags.DEFAULT)
|
||||
);
|
||||
|
||||
this._widescreen_mode_settings_connection = this.settings.connect('changed::widescreen-mode', this._update_widescreen_mode_from_settings.bind(this))
|
||||
this._start_binding = this.settings.bind('toggle-display-distance-start', this._xr_effect, 'toggle-display-distance-start', Gio.SettingsBindFlags.DEFAULT)
|
||||
this._end_binding = this.settings.bind('toggle-display-distance-end', this._xr_effect, 'toggle-display-distance-end', Gio.SettingsBindFlags.DEFAULT)
|
||||
this._curved_display_binding = this.settings.bind('curved-display', this._xr_effect, 'curved-display', Gio.SettingsBindFlags.DEFAULT)
|
||||
this._display_size_binding = this.settings.bind('display-size', this._xr_effect, 'display-size', Gio.SettingsBindFlags.DEFAULT);
|
||||
this._look_ahead_override_binding = this.settings.bind('look-ahead-override', this._xr_effect, 'look-ahead-override', Gio.SettingsBindFlags.DEFAULT);
|
||||
this._disable_anti_aliasing_binding = this.settings.bind('disable-anti-aliasing', this._xr_effect, 'disable-anti-aliasing', Gio.SettingsBindFlags.DEFAULT);
|
||||
this._show_banner_connection = Globals.data_stream.connect('notify::show-banner', this._handle_show_banner_update.bind(this));
|
||||
this._was_show_banner = Globals.data_stream.show_banner;
|
||||
if (!this._was_show_banner) this._recenter_display();
|
||||
|
||||
this._overlay.mainActor().add_effect_with_name('xr-desktop', this._xr_effect);
|
||||
Meta.disable_unredirect_for_display(global.display);
|
||||
this._effect_settings_bindings = [
|
||||
'monitor-wrapping-scheme',
|
||||
'viewport-offset-x',
|
||||
'viewport-offset-y',
|
||||
'monitor-spacing',
|
||||
'display-distance',
|
||||
'toggle-display-distance-start',
|
||||
'toggle-display-distance-end',
|
||||
'display-size',
|
||||
'framerate-cap',
|
||||
'look-ahead-override',
|
||||
'disable-anti-aliasing'
|
||||
]
|
||||
this._effect_settings_bindings.forEach(settings_key =>
|
||||
this.settings.bind(settings_key, this._virtual_displays_actor, settings_key, Gio.SettingsBindFlags.DEFAULT)
|
||||
);
|
||||
|
||||
this._distance_connection = this.settings.connect('changed::display-distance', this._update_display_distance.bind(this));
|
||||
this._focused_monitor_distance_connection =
|
||||
this._virtual_displays_actor.connect('notify::focused-monitor-details', this._update_display_distance.bind(this));
|
||||
this._follow_threshold_connection = this.settings.connect('changed::follow-threshold', this._update_follow_threshold.bind(this));
|
||||
|
||||
Meta.Compositor?.disable_unredirect?.() ?? Meta.disable_unredirect_for_display(global.display);
|
||||
|
||||
this._add_settings_keybinding('toggle-xr-effect-shortcut', this._toggle_xr_effect.bind(this));
|
||||
this._add_settings_keybinding('recenter-display-shortcut', this._recenter_display.bind(this));
|
||||
this._add_settings_keybinding('toggle-display-distance-shortcut', this._xr_effect._change_distance.bind(this._xr_effect));
|
||||
this._add_settings_keybinding('toggle-display-distance-shortcut', this._virtual_displays_actor._change_distance.bind(this._virtual_displays_actor));
|
||||
this._add_settings_keybinding('toggle-follow-shortcut', this._toggle_follow_mode.bind(this));
|
||||
} catch (e) {
|
||||
Globals.logger.log(`[ERROR] BreezyDesktopExtension _effect_enable ${e.message}\n${e.stack}`);
|
||||
Globals.logger.log(`[ERROR] BreezyDesktopExtension _effect_enable ${e.message}\n${e.stack}`);
|
||||
this._effect_disable();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
_handle_sibling_update() {
|
||||
Globals.logger.log_debug('BreezyDesktopExtension _handle_sibling_update()');
|
||||
global.stage.set_child_above_sibling(this._overlay.mainActor(), null);
|
||||
}
|
||||
|
||||
_add_settings_keybinding(settings_key, bind_to_function) {
|
||||
try {
|
||||
Main.wm.addKeybinding(
|
||||
|
|
@ -361,10 +341,15 @@ export default class BreezyDesktopExtension extends Extension {
|
|||
|
||||
_write_control(key, value) {
|
||||
try {
|
||||
const file = Gio.file_new_for_path('/dev/shm/xr_driver_control');
|
||||
const stream = file.replace(null, false, Gio.FileCreateFlags.NONE, null);
|
||||
stream.write(`${key}=${value}`, null);
|
||||
stream.close(null);
|
||||
Globals.logger.log_debug(`BreezyDesktopExtension _write_control ${key} ${value}`);
|
||||
let proc = Gio.Subprocess.new(
|
||||
['bash', '-c', `echo "${key}=${value}" > /dev/shm/xr_driver_control`],
|
||||
Gio.SubprocessFlags.STDOUT_PIPE | Gio.SubprocessFlags.STDERR_PIPE
|
||||
);
|
||||
|
||||
let [success, stdout, stderr] = proc.communicate_utf8(null, null);
|
||||
if (!success || !!stderr)
|
||||
throw new Error(`Failed to write control: ${stderr}`);
|
||||
} catch (e) {
|
||||
Globals.logger.log(`[ERROR] BreezyDesktopExtension _write_control ${e.message}\n${e.stack}`);
|
||||
}
|
||||
|
|
@ -395,10 +380,19 @@ export default class BreezyDesktopExtension extends Extension {
|
|||
return state;
|
||||
}
|
||||
|
||||
_update_display_distance(settings, event) {
|
||||
const value = settings.get_double('display-distance');
|
||||
_update_display_distance(object, event) {
|
||||
const value = this.settings.get_double('display-distance');
|
||||
Globals.logger.log_debug(`BreezyDesktopExtension _update_display_distance ${value}`);
|
||||
if (value !== undefined) this._write_control('breezy_desktop_display_distance', value);
|
||||
if (value !== undefined) {
|
||||
let focusedMonitorSizeAdjustment = 1.0;
|
||||
if (this._virtual_displays_actor?.focused_monitor_details && this._target_monitor) {
|
||||
const fovMonitor = this._target_monitor.monitor;
|
||||
const focusedMonitor = this._virtual_displays_actor.focused_monitor_details;
|
||||
focusedMonitorSizeAdjustment =
|
||||
Math.max(focusedMonitor.width / fovMonitor.width, focusedMonitor.height / fovMonitor.height);
|
||||
}
|
||||
this._write_control('breezy_desktop_display_distance', value / focusedMonitorSizeAdjustment);
|
||||
}
|
||||
}
|
||||
|
||||
_update_follow_threshold(settings, event) {
|
||||
|
|
@ -421,7 +415,7 @@ export default class BreezyDesktopExtension extends Extension {
|
|||
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
|
||||
// setup was halted if this is enabled, so we have to re-trigger it now
|
||||
this._setup();
|
||||
}
|
||||
|
||||
|
|
@ -443,12 +437,12 @@ export default class BreezyDesktopExtension extends Extension {
|
|||
}
|
||||
|
||||
_update_widescreen_mode_from_settings(settings, event) {
|
||||
const value = settings.get_boolean('widescreen-mode');
|
||||
Globals.logger.log_debug(`BreezyDesktopExtension _update_widescreen_mode_from_settings ${value}`);
|
||||
if (value !== undefined && value !== this._xr_effect.widescreen_mode_state) {
|
||||
this._request_sbs_mode_change(value);
|
||||
} else
|
||||
Globals.logger.log_debug('effect.widescreen_mode_state already matched setting');
|
||||
// const value = settings.get_boolean('widescreen-mode');
|
||||
// Globals.logger.log_debug(`BreezyDesktopExtension _update_widescreen_mode_from_settings ${value}`);
|
||||
// if (value !== undefined && value !== this._xr_effect.widescreen_mode_state) {
|
||||
// this._request_sbs_mode_change(value);
|
||||
// } else
|
||||
// Globals.logger.log_debug('effect.widescreen_mode_state already matched setting');
|
||||
}
|
||||
|
||||
_update_widescreen_mode_from_state(effect, _pspec) {
|
||||
|
|
@ -472,17 +466,22 @@ export default class BreezyDesktopExtension extends Extension {
|
|||
this._setup();
|
||||
}
|
||||
|
||||
_handle_supported_device_change(effect, _pspec) {
|
||||
const device_connected = effect.supported_device_detected;
|
||||
Globals.logger.log_debug(`BreezyDesktopExtension _handle_supported_device_change ${device_connected}`);
|
||||
_handle_breezy_desktop_running_change(datastream, _pspec) {
|
||||
Globals.logger.log_debug(`BreezyDesktopExtension _handle_breezy_desktop_running_change ${datastream.breezy_desktop_running}`);
|
||||
|
||||
// this will disable the effect and begin polling for a ready state again
|
||||
if (!device_connected && this._is_effect_running) {
|
||||
Globals.logger.log('Supported device disconnected');
|
||||
this._setup(true);
|
||||
if (datastream.breezy_desktop_running !== this._is_effect_running) {
|
||||
if (!datastream.breezy_desktop_running) Globals.logger.log('Breezy desktop disabled');
|
||||
this._setup(!datastream.breezy_desktop_running);
|
||||
}
|
||||
}
|
||||
|
||||
_handle_show_banner_update(datastream, _pspec) {
|
||||
Globals.logger.log_debug(`BreezyDesktopExtension _handle_show_banner_update ${datastream.show_banner}`);
|
||||
if (this._was_show_banner && !datastream.show_banner) this._recenter_display();
|
||||
|
||||
this._was_show_banner = datastream.show_banner;
|
||||
}
|
||||
|
||||
_toggle_xr_effect() {
|
||||
if (!this._cli_file) return;
|
||||
|
||||
|
|
@ -521,6 +520,7 @@ export default class BreezyDesktopExtension extends Extension {
|
|||
|
||||
_toggle_follow_mode() {
|
||||
Globals.logger.log_debug('BreezyDesktopExtension _toggle_follow_mode');
|
||||
if (!!this._virtual_displays_actor) this._virtual_displays_actor.set_property('smooth-follow-toggle-epoch-ms', Date.now());
|
||||
this._write_control('toggle_breezy_desktop_smooth_follow', 'true');
|
||||
}
|
||||
|
||||
|
|
@ -530,85 +530,51 @@ export default class BreezyDesktopExtension extends Extension {
|
|||
Globals.logger.log_debug('BreezyDesktopExtension _effect_disable');
|
||||
this._is_effect_running = false;
|
||||
|
||||
if (this._running_poller_id) {
|
||||
const poller_id = this._running_poller_id;
|
||||
this._running_poller_id = undefined;
|
||||
GLib.source_remove(poller_id);
|
||||
}
|
||||
if (Globals.data_stream.smooth_follow_enabled) this._toggle_follow_mode();
|
||||
|
||||
Main.wm.removeKeybinding('recenter-display-shortcut');
|
||||
Main.wm.removeKeybinding('toggle-display-distance-shortcut');
|
||||
Main.wm.removeKeybinding('toggle-follow-shortcut');
|
||||
Meta.enable_unredirect_for_display(global.display);
|
||||
Meta.Compositor?.enable_unredirect?.() ?? Meta.enable_unredirect_for_display(global.display);
|
||||
|
||||
if (this._actor_added_connection) {
|
||||
global.stage.disconnect(this._actor_added_connection);
|
||||
this._actor_added_connection = null;
|
||||
for (let settings_key of this._effect_settings_bindings) {
|
||||
Gio.Settings.unbind(this.settings, settings_key);
|
||||
}
|
||||
if (this._actor_removed_connection) {
|
||||
global.stage.disconnect(this._actor_removed_connection);
|
||||
this._actor_removed_connection = null;
|
||||
}
|
||||
if (this._distance_binding) {
|
||||
this.settings.unbind(this._distance_binding);
|
||||
this._distance_binding = null;
|
||||
this._effect_settings_bindings = [];
|
||||
this._data_stream_bindings.forEach(binding => binding.unbind());
|
||||
this._data_stream_bindings = [];
|
||||
|
||||
if (this._show_banner_connection) {
|
||||
Globals.data_stream.disconnect(this._show_banner_connection);
|
||||
this._show_banner_connection = null;
|
||||
}
|
||||
if (this._distance_connection) {
|
||||
this.settings.disconnect(this._distance_connection);
|
||||
this._distance_connection = null;
|
||||
}
|
||||
if (this._focused_monitor_distance_connection) {
|
||||
this._virtual_displays_actor.disconnect(this._focused_monitor_distance_connection);
|
||||
this._focused_monitor_distance_connection = null;
|
||||
}
|
||||
if (this._follow_threshold_connection) {
|
||||
this.settings.disconnect(this._follow_threshold_connection);
|
||||
this._follow_threshold_connection = null;
|
||||
}
|
||||
if (this._widescreen_mode_settings_connection) {
|
||||
this.settings.disconnect(this._widescreen_mode_settings_connection);
|
||||
this._widescreen_mode_settings_connection = null;
|
||||
}
|
||||
if (this._start_binding) {
|
||||
this.settings.unbind(this._start_binding);
|
||||
this._start_binding = null;
|
||||
}
|
||||
if (this._end_binding) {
|
||||
this.settings.unbind(this._end_binding);
|
||||
this._end_binding = null;
|
||||
}
|
||||
if (this._curved_display_binding) {
|
||||
this.settings.unbind(this._curved_display_binding);
|
||||
this._curved_display_binding = null;
|
||||
}
|
||||
if (this._display_size_binding) {
|
||||
this.settings.unbind(this._display_size_binding);
|
||||
this._display_size_binding = null;
|
||||
}
|
||||
if (this._look_ahead_override_binding) {
|
||||
this.settings.unbind(this._look_ahead_override_binding);
|
||||
this._look_ahead_override_binding = null;
|
||||
}
|
||||
if (this._disable_anti_aliasing_binding) {
|
||||
this.settings.unbind(this._disable_anti_aliasing_binding);
|
||||
this._disable_anti_aliasing_binding = null;
|
||||
}
|
||||
if (this._xr_effect) {
|
||||
if (this._widescreen_mode_effect_state_connection) {
|
||||
this._xr_effect.disconnect(this._widescreen_mode_effect_state_connection);
|
||||
this._widescreen_mode_effect_state_connection = null;
|
||||
if (this._virtual_displays_overlay) {
|
||||
if (this._virtual_displays_actor) {
|
||||
this._virtual_displays_overlay.remove_child(this._virtual_displays_actor);
|
||||
this._virtual_displays_actor.destroy();
|
||||
this._virtual_displays_actor = null;
|
||||
}
|
||||
if (this._supported_device_detected_connected) {
|
||||
this._xr_effect.disconnect(this._supported_device_detected_connected);
|
||||
this._supported_device_detected_connected = null;
|
||||
}
|
||||
this._xr_effect.cleanup();
|
||||
this._xr_effect = null;
|
||||
|
||||
global.stage.remove_child(this._virtual_displays_overlay);
|
||||
this._virtual_displays_overlay.destroy();
|
||||
this._virtual_displays_overlay = null;
|
||||
}
|
||||
if (this._cursor_manager) {
|
||||
this._cursor_manager.disable();
|
||||
this._cursor_manager = null;
|
||||
}
|
||||
if (this._overlay) {
|
||||
this._overlay.mainActor().remove_effect_by_name('xr-desktop');
|
||||
this._overlay.destroy();
|
||||
}
|
||||
|
||||
// this should always be done at the end of this function after the widescreen settings binding is removed,
|
||||
// so it doesn't reset the setting to false
|
||||
|
|
@ -624,18 +590,22 @@ export default class BreezyDesktopExtension extends Extension {
|
|||
disable() {
|
||||
try {
|
||||
Globals.logger.log_debug('BreezyDesktopExtension disable');
|
||||
this._effect_disable();
|
||||
this._target_monitor = null;
|
||||
if (this._monitor_manager) {
|
||||
if (this._optimal_monitor_config_binding) {
|
||||
this.settings.unbind(this._optimal_monitor_config_binding);
|
||||
this._optimal_monitor_config_binding = null
|
||||
}
|
||||
if (this._headset_as_primary_binding) {
|
||||
this.settings.unbind(this._headset_as_primary_binding);
|
||||
this._headset_as_primary_binding = null;
|
||||
}
|
||||
|
||||
this._effect_disable();
|
||||
Globals.data_stream.stop();
|
||||
this._target_monitor = null;
|
||||
|
||||
if (this._breezy_desktop_running_connection) {
|
||||
Globals.data_stream.disconnect(this._breezy_desktop_running_connection);
|
||||
this._breezy_desktop_running_connection = null;
|
||||
}
|
||||
Gio.Settings.unbind(this.settings, 'debug');
|
||||
Gio.Settings.unbind(this.settings, 'use-optimal-monitor-config');
|
||||
Gio.Settings.unbind(this.settings, 'headset-as-primary');
|
||||
Gio.Settings.unbind(this.settings, 'disable-physical-displays');
|
||||
Gio.Settings.unbind(this.settings, 'debug-no-device');
|
||||
|
||||
if (this._monitor_manager) {
|
||||
this._monitor_manager.disable();
|
||||
this._monitor_manager = null;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,6 +1,7 @@
|
|||
const Globals = {
|
||||
logger: null,
|
||||
ipc_file: null, // Gio.File instance, file exists if set
|
||||
extension_dir: null // string path
|
||||
extension_dir: null, // string path
|
||||
data_stream: null, // DeviceDataStream instance
|
||||
}
|
||||
export default Globals;
|
||||
|
|
@ -1,3 +1,20 @@
|
|||
export function degreeToRadian(degree) {
|
||||
return degree * Math.PI / 180;
|
||||
}
|
||||
|
||||
// FOV in radians is spherical, so doesn't follow Pythagoras' theorem
|
||||
export function diagonalToCrossFOVs(diagonalFOVRadians, aspectRatio) {
|
||||
// first convert from a spherical FOV to a diagonal FOV on a flat plane at a generic distance of 1.0
|
||||
const flatDiagonalFOV = 2 * Math.tan(diagonalFOVRadians / 2);
|
||||
|
||||
// then convert to flat plane horizontal and vertical FOVs
|
||||
const flatVerticalFOV = flatDiagonalFOV / Math.sqrt(1 + aspectRatio * aspectRatio);
|
||||
const flatHorizontalFOV = flatVerticalFOV * aspectRatio;
|
||||
|
||||
// then convert back to spherical FOV
|
||||
return {
|
||||
diagonal: diagonalFOVRadians,
|
||||
horizontal: 2 * Math.atan(Math.tan(flatHorizontalFOV / 2)),
|
||||
vertical: 2 * Math.atan(Math.tan(flatVerticalFOV / 2))
|
||||
}
|
||||
}
|
||||
|
|
@ -23,6 +23,21 @@ import * as Main from 'resource:///org/gnome/shell/ui/main.js';
|
|||
|
||||
import Globals from './globals.js';
|
||||
|
||||
export const NESTED_MONITOR_PRODUCT = 'MetaMonitor';
|
||||
export const VIRTUAL_MONITOR_PRODUCT = 'Virtual remote monitor';
|
||||
export const SUPPORTED_MONITOR_PRODUCTS = [
|
||||
'VITURE',
|
||||
'nreal air',
|
||||
'Air',
|
||||
'Air 2',
|
||||
'Air 2 Pro',
|
||||
'Air 2 Ultra',
|
||||
'SmartGlasses', // TCL/RayNeo
|
||||
'Rokid Max',
|
||||
'Rokid Air',
|
||||
NESTED_MONITOR_PRODUCT
|
||||
];
|
||||
|
||||
let cachedDisplayConfigProxy = null;
|
||||
|
||||
function getDisplayConfigProxy(extPath) {
|
||||
|
|
@ -35,7 +50,7 @@ function getDisplayConfigProxy(extPath) {
|
|||
xml = new TextDecoder().decode(bytes);
|
||||
}
|
||||
} catch (e) {
|
||||
Globals.logger.log('ERROR: failed to load DisplayConfig interface XML');
|
||||
Globals.logger.log('[ERROR] failed to load DisplayConfig interface XML');
|
||||
throw e;
|
||||
}
|
||||
cachedDisplayConfigProxy = Gio.DBusProxy.makeProxyWrapper(xml);
|
||||
|
|
@ -54,40 +69,35 @@ export function newDisplayConfig(extPath, callback) {
|
|||
}
|
||||
|
||||
function getMonitorConfig(displayConfigProxy, callback) {
|
||||
displayConfigProxy.GetResourcesRemote((result, error) => {
|
||||
displayConfigProxy.GetCurrentStateRemote((result, error) => {
|
||||
if (error) {
|
||||
callback(null, `GetResourcesRemote failed: ${error}`);
|
||||
callback(null, `GetCurrentState failed: ${error}`);
|
||||
} else {
|
||||
const monitors = [];
|
||||
for (let i = 0; i < result[2].length; i++) {
|
||||
const output = result[2][i];
|
||||
if (output.length <= 7) {
|
||||
callback(null, 'Cannot get DisplayConfig: No properties on output #' + i);
|
||||
return;
|
||||
}
|
||||
const props = output[7];
|
||||
const displayName = props['display-name'].get_string()[0];
|
||||
const connectorName = output[4];
|
||||
if (!displayName || displayName == '') {
|
||||
const displayName = 'Monitor on output ' + connectorName;
|
||||
}
|
||||
const vendor = props['vendor'].get_string()[0];
|
||||
const product = props['product'].get_string()[0];
|
||||
const serial = props['serial'].get_string()[0];
|
||||
Globals.logger.log_debug(`monitormanager.js getMonitorConfig GetCurrentState result: ${JSON.stringify(result)}`);
|
||||
|
||||
const allMonitors = [];
|
||||
const [serial, monitors, logicalMonitors, properties] = result;
|
||||
for (let monitor of monitors) {
|
||||
const [details, modes, monProperties] = monitor;
|
||||
const [connector, vendor, product, monitorSerial] = details;
|
||||
const displayName = monProperties['display-name'].get_string()[0];
|
||||
|
||||
// grab refresh rate from the modes array
|
||||
const refreshRate = result[3][i][4];
|
||||
|
||||
monitors.push([displayName, connectorName, vendor, product, serial, refreshRate]);
|
||||
for (let mode of modes) {
|
||||
const [modeId, width, height, refreshRate, preferredScale, supportedScales, modeProperites] = mode;
|
||||
const isCurrent = !!modeProperites['is-current'];
|
||||
if (isCurrent) {
|
||||
allMonitors.push([displayName, connector, vendor, product, serial, refreshRate]);
|
||||
}
|
||||
}
|
||||
}
|
||||
callback(monitors, null);
|
||||
callback(allMonitors, null);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// 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, useHighestRefreshRate,
|
||||
callback, allowConfigUpdateFn) {
|
||||
disablePhysicalDisplays, callback, allowConfigUpdateFn) {
|
||||
Globals.logger.log_debug(`monitormanager.js performOptimalModeCheck for ${connectorName}`);
|
||||
|
||||
displayConfigProxy.GetCurrentStateRemote((result, error) => {
|
||||
|
|
@ -162,9 +172,11 @@ function performOptimalModeCheck(displayConfigProxy, connectorName, headsetAsPri
|
|||
logicalMonitors.sort((a, b) => a[0] - b[0]);
|
||||
|
||||
// map from original logical monitors schema to a(iiduba(ssa{sv})) for ApplyMonitorsConfig call
|
||||
const updatedLogicalMonitors = logicalMonitors.map((logicalMonitor) => {
|
||||
const removeMonitorIndexes = [];
|
||||
const updatedLogicalMonitors = logicalMonitors.map((logicalMonitor, index) => {
|
||||
const [x, y, scale, transform, primary, monitors, logMonProperties] = logicalMonitor;
|
||||
const hasOurMonitor = !!monitors.some((monitor) => monitor[0] === connectorName);
|
||||
const hasVirtualMonitor = monitors.some((monitor) => monitor[2] === VIRTUAL_MONITOR_PRODUCT);
|
||||
const newScale = (!skipScaleUpdate && hasOurMonitor) ? bestFitMode.bestScale : scale;
|
||||
anyMonitorsChanged |= newScale !== scale;
|
||||
|
||||
|
|
@ -172,6 +184,11 @@ function performOptimalModeCheck(displayConfigProxy, connectorName, headsetAsPri
|
|||
// if headsetAsPrimary is true
|
||||
anyMonitorsChanged |= headsetAsPrimary && ((hasOurMonitor && !primary) || (!hasOurMonitor && primary));
|
||||
|
||||
if (disablePhysicalDisplays && !hasVirtualMonitor && !hasOurMonitor) {
|
||||
removeMonitorIndexes.push(index);
|
||||
anyMonitorsChanged = true;
|
||||
}
|
||||
|
||||
// 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;
|
||||
|
|
@ -218,6 +235,112 @@ function performOptimalModeCheck(displayConfigProxy, connectorName, headsetAsPri
|
|||
|
||||
// if our monitor is already properly configured, we can skip the ApplyMonitorsConfig call
|
||||
if (anyMonitorsChanged) {
|
||||
if (removeMonitorIndexes.length > 0) {
|
||||
let removedPrimary = false;
|
||||
|
||||
// remove monitors that are not virtual or our monitor
|
||||
removeMonitorIndexes.reverse().forEach((index) => {
|
||||
const [x, y, scale, transform, primary, monitors, logMonProperties] = updatedLogicalMonitors[index];
|
||||
if (primary) removedPrimary = true;
|
||||
updatedLogicalMonitors.splice(index, 1);
|
||||
});
|
||||
|
||||
// collect sizes based on modes of attached monitors
|
||||
const logicalMonitorsWithSizes = updatedLogicalMonitors.map((logicalMonitor) => {
|
||||
const [x, y, scale, transform, primary, monitors, logMonProperties] = logicalMonitor;
|
||||
const {width, height} = monitors.reduce(({width, height}, monitor) => {
|
||||
const monitorConnector = monitor[0];
|
||||
const currentMode = monitorToCurrentModeMap[monitorConnector];
|
||||
const currentWidth = currentMode[1];
|
||||
const currentHeight = currentMode[2];
|
||||
return {
|
||||
width: Math.max(width, currentWidth),
|
||||
height: Math.max(height, currentHeight)
|
||||
};
|
||||
}, {width: 0, height: 0});
|
||||
|
||||
return {
|
||||
logicalMonitor,
|
||||
width,
|
||||
height,
|
||||
xEnd: x + width,
|
||||
yEnd: y + height
|
||||
}
|
||||
});
|
||||
logicalMonitorsWithSizes.sort((a, b) => a.x === b.x ? a.y - b.y : a.x - b.x);
|
||||
|
||||
// this array will track monitors we've already corrected, but we'll toss it out since we're modifying the
|
||||
// objects in the original array
|
||||
const processedLogicalMonitors = [];
|
||||
|
||||
// make sure all monitors have a monitor adjacent
|
||||
for (let i = 0; i < logicalMonitorsWithSizes.length; i++) {
|
||||
const thisMonitor = logicalMonitorsWithSizes[i];
|
||||
const [x, y, scale, transform, primary, monitors, logMonProperties] = thisMonitor.logicalMonitor;
|
||||
const {xEnd, yEnd} = thisMonitor;
|
||||
|
||||
const hasOurMonitor = !!monitors.some((monitor) => monitor[0] === connectorName);
|
||||
if (removedPrimary && hasOurMonitor) {
|
||||
// if we removed the primary monitor, we need to set the glasses monitor as the new primary
|
||||
thisMonitor.logicalMonitor[4] = true;
|
||||
}
|
||||
|
||||
if (logicalMonitorsWithSizes.some((monitor, index) => {
|
||||
if (index === i) return false;
|
||||
|
||||
const [monX, monY, monScale, monTransform, monPrimary, monMonitors, monLogMonProperties] = monitor.logicalMonitor;
|
||||
const monXEnd = monitor.xEnd;
|
||||
const monYEnd = monitor.yEnd;
|
||||
const xOverlap = x < monXEnd && xEnd > monX;
|
||||
const yOverlap = y < monYEnd && yEnd > monY;
|
||||
|
||||
// use top or left sides to determine if it's already adjacent
|
||||
return (x === monXEnd && yOverlap) || (y === monYEnd && xOverlap);
|
||||
})) {
|
||||
// this monitor is already adjacent to another monitor, leave it as-is
|
||||
processedLogicalMonitors.push(thisMonitor);
|
||||
} else {
|
||||
let newX = undefined;
|
||||
let newY = undefined;
|
||||
|
||||
// move the monitor left until it runs into one
|
||||
const procMonitorsByXEndDesc = [...processedLogicalMonitors].sort((a, b) => b.xEnd - a.xEnd);
|
||||
for (let j = 0; j < procMonitorsByXEndDesc.length; j++) {
|
||||
const procMonitor = procMonitorsByXEndDesc[j];
|
||||
const [procX, procY, procScale, procTransform, procPrimary, procMonitors, procLogMonProperties] = procMonitor.logicalMonitor;
|
||||
if (procMonitor.xEnd <= x && procY < yEnd && procMonitor.yEnd > y) {
|
||||
newX = procMonitor.xEnd;
|
||||
newY = y;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (newX === undefined) {
|
||||
newX = 0;
|
||||
|
||||
// we didn't find an adjacent monitor to the left, now move it up until it runs into one
|
||||
const procMonitorsByYEndDesc = [...processedLogicalMonitors].sort((a, b) => b.yEnd - a.yEnd);
|
||||
for (let j = 0; j < procMonitorsByYEndDesc.length; j++) {
|
||||
const procMonitor = procMonitorsByYEndDesc[j];
|
||||
const [procX, procY, procScale, procTransform, procPrimary, procMonitors, procLogMonProperties] = procMonitor.logicalMonitor;
|
||||
if (procMonitor.yEnd <= y && procX < thisMonitor.width && procMonitor.xEnd > 0) {
|
||||
newY = procMonitor.yEnd;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// if nothing found, put at origin
|
||||
if (newY === undefined) newY = 0;
|
||||
}
|
||||
thisMonitor.logicalMonitor[0] = newX;
|
||||
thisMonitor.logicalMonitor[1] = newY;
|
||||
thisMonitor.xEnd = newX + thisMonitor.width;
|
||||
thisMonitor.yEnd = newY + thisMonitor.height;
|
||||
processedLogicalMonitors.push(thisMonitor);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Globals.logger.log_debug(`monitormanager.js performOptimalModeCheck updatedLogicalMonitors: ${JSON.stringify(updatedLogicalMonitors)}`);
|
||||
displayConfigProxy.ApplyMonitorsConfigRemote(
|
||||
serial,
|
||||
|
|
@ -264,6 +387,13 @@ export const MonitorManager = GObject.registerClass({
|
|||
'Use headset as primary monitor',
|
||||
'Automatically set the headset as the primary display upon connection',
|
||||
GObject.ParamFlags.READWRITE,
|
||||
false
|
||||
),
|
||||
'disable-physical-displays': GObject.ParamSpec.boolean(
|
||||
'disable-physical-displays',
|
||||
'Disable physical displays',
|
||||
'Disable physical displays when a virtual display is connected',
|
||||
GObject.ParamFlags.READWRITE,
|
||||
true
|
||||
),
|
||||
'extension-path': GObject.ParamSpec.string(
|
||||
|
|
@ -282,11 +412,12 @@ export const MonitorManager = GObject.registerClass({
|
|||
this._displayConfigProxy = null;
|
||||
this._monitorProperties = null;
|
||||
this._changeHookFn = null;
|
||||
this._needsConfigCheck = this.use_optimal_monitor_config;
|
||||
this._needsConfigCheck = this.use_optimal_monitor_config || this.headset_as_primary || this.disable_physical_displays;
|
||||
|
||||
// help prevent certain actions from taking place multiple times in the event of rapid monitor updates
|
||||
this._asyncRequestsInFlight = 0;
|
||||
this._configCheckRequestsCount = 0;
|
||||
this._enabled = false;
|
||||
}
|
||||
|
||||
enable() {
|
||||
|
|
@ -300,12 +431,17 @@ export const MonitorManager = GObject.registerClass({
|
|||
}).bind(this));
|
||||
|
||||
this._monitorsChangedConnection = Main.layoutManager.connect('monitors-changed', this._on_monitors_change.bind(this));
|
||||
this._disable_physical_displays_connection = this.connect('notify::disable-physical-displays', this._on_disable_physical_displays_change.bind(this));
|
||||
this._enabled = true;
|
||||
}
|
||||
|
||||
disable() {
|
||||
Globals.logger.log_debug('MonitorManager disable');
|
||||
this.disconnect(this._disable_physical_displays_connection);
|
||||
Main.layoutManager.disconnect(this._monitorsChangedConnection);
|
||||
|
||||
this._enabled = false;
|
||||
this._disable_physical_displays_connection = null;
|
||||
this._monitorsChangedConnection = null;
|
||||
this._displayConfigProxy = null;
|
||||
this._monitorProperties = null;
|
||||
|
|
@ -343,7 +479,7 @@ export const MonitorManager = GObject.registerClass({
|
|||
return this._asyncRequestsInFlight === 1 && this._configCheckRequestsCount === configCheckCountSnapshot;
|
||||
}).bind(this);
|
||||
|
||||
performOptimalModeCheck(this._displayConfigProxy, monitorConnector, this.headset_as_primary, this.use_highest_refresh_rate, ((configChanged, error) => {
|
||||
performOptimalModeCheck(this._displayConfigProxy, monitorConnector, this.headset_as_primary, this.use_highest_refresh_rate, this.disable_physical_displays, ((configChanged, error) => {
|
||||
if (--this._asyncRequestsInFlight > 0) {
|
||||
Globals.logger.log_debug(`MonitorManager needsOptimalModeCheck: ${this._asyncRequestsInFlight} async requests still pending, skipping change hook`);
|
||||
return;
|
||||
|
|
@ -354,7 +490,7 @@ export const MonitorManager = GObject.registerClass({
|
|||
|
||||
this._needsConfigCheck = false;
|
||||
if (error) {
|
||||
Globals.logger.log(`Failed to switch to optimal mode for monitor ${monitorConnector}: ${error}`);
|
||||
Globals.logger.log(`[ERROR] Failed to switch to optimal mode for monitor ${monitorConnector}: ${error}`);
|
||||
|
||||
// tell the extension to proceed, this should result in another config check
|
||||
this._changeHookFn();
|
||||
|
|
@ -380,11 +516,13 @@ export const MonitorManager = GObject.registerClass({
|
|||
}
|
||||
|
||||
_on_monitors_change() {
|
||||
if (!this._enabled) return;
|
||||
|
||||
Globals.logger.log_debug('MonitorManager _on_monitors_change');
|
||||
if (this._displayConfigProxy == null) {
|
||||
return;
|
||||
}
|
||||
if (this.use_optimal_monitor_config) {
|
||||
if (this.use_optimal_monitor_config || this.headset_as_primary || this.disable_physical_displays) {
|
||||
this._needsConfigCheck = true;
|
||||
this._configCheckRequestsCount++;
|
||||
}
|
||||
|
|
@ -392,7 +530,7 @@ export const MonitorManager = GObject.registerClass({
|
|||
getMonitorConfig(this._displayConfigProxy, ((result, error) => {
|
||||
this._asyncRequestsInFlight--;
|
||||
if (error) {
|
||||
Globals.logger.log(error);
|
||||
Globals.logger.log(`[ERROR] Failed _on_monitors_change getMonitorConfig: ${error}`);
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
@ -425,4 +563,13 @@ export const MonitorManager = GObject.registerClass({
|
|||
}
|
||||
}).bind(this));
|
||||
}
|
||||
|
||||
_on_disable_physical_displays_change() {
|
||||
if (this._enabled && this.disable_physical_displays && !!this._changeHookFn) {
|
||||
Globals.logger.log_debug('MonitorManager _on_disable_physical_displays_change triggering change hook');
|
||||
this._needsConfigCheck = true;
|
||||
this._configCheckRequestsCount++;
|
||||
this._changeHookFn();
|
||||
}
|
||||
}
|
||||
});
|
||||
|
|
@ -1,49 +0,0 @@
|
|||
import Clutter from 'gi://Clutter'
|
||||
import Shell from 'gi://Shell';
|
||||
import St from 'gi://St';
|
||||
|
||||
import { SystemBackground } from './systembackground.js';
|
||||
import * as Main from 'resource:///org/gnome/shell/ui/main.js';
|
||||
|
||||
export class Overlay {
|
||||
constructor(targetMonitor) {
|
||||
this._overlayContent = new Clutter.Actor({clip_to_allocation: true});
|
||||
this._overlay = new St.Bin({
|
||||
child: this._overlayContent
|
||||
});
|
||||
this._overlay.set_position(targetMonitor.x, targetMonitor.y);
|
||||
this._overlay.set_size(targetMonitor.width, targetMonitor.height);
|
||||
|
||||
global.stage.add_child(this._overlay);
|
||||
Shell.util_set_hidden_from_pick(this._overlay, true);
|
||||
|
||||
this._background = new SystemBackground();
|
||||
this._overlayContent.add_child(this._background);
|
||||
|
||||
this._uiClone = new Clutter.Clone({ source: Main.layoutManager.uiGroup, clip_to_allocation: true });
|
||||
this._uiClone.x = -targetMonitor.x;
|
||||
this._uiClone.y = -targetMonitor.y;
|
||||
this._overlayContent.add_child(this._uiClone);
|
||||
|
||||
this._targetMonitor = targetMonitor;
|
||||
}
|
||||
|
||||
isWithinBounds(x, y) {
|
||||
return x >= this._targetMonitor.x && x < this._targetMonitor.x + this._targetMonitor.width &&
|
||||
y >= this._targetMonitor.y && y < this._targetMonitor.y + this._targetMonitor.height;
|
||||
}
|
||||
|
||||
getRelativePosition(x, y) {
|
||||
return [x - this._targetMonitor.x, y - this._targetMonitor.y];
|
||||
}
|
||||
|
||||
mainActor() {
|
||||
return this._overlayContent;
|
||||
}
|
||||
|
||||
destroy() {
|
||||
global.stage.remove_child(this._overlay);
|
||||
this._overlay.destroy();
|
||||
this._overlay = null;
|
||||
}
|
||||
}
|
||||
|
|
@ -1,32 +0,0 @@
|
|||
import Clutter from 'gi://Clutter';
|
||||
import Cogl from 'gi://Cogl';
|
||||
import GLib from 'gi://GLib';
|
||||
import GObject from 'gi://GObject';
|
||||
import Meta from 'gi://Meta';
|
||||
|
||||
const DEFAULT_BACKGROUND_COLOR = Clutter.Color?.from_pixel(0x2e3436ff) || new Cogl.Color({red: 40, green: 40, blue: 40, alpha: 255});
|
||||
|
||||
let _systemBackground;
|
||||
|
||||
export const SystemBackground = GObject.registerClass({
|
||||
Signals: {'loaded': {}},
|
||||
}, class SystemBackground extends Meta.BackgroundActor {
|
||||
_init() {
|
||||
if (_systemBackground == null) {
|
||||
_systemBackground = new Meta.Background({meta_display: global.display});
|
||||
_systemBackground.set_color(DEFAULT_BACKGROUND_COLOR);
|
||||
}
|
||||
|
||||
super._init({
|
||||
meta_display: global.display,
|
||||
monitor: 0,
|
||||
});
|
||||
this.content.background = _systemBackground;
|
||||
|
||||
let id = GLib.idle_add(GLib.PRIORITY_DEFAULT, () => {
|
||||
this.emit('loaded');
|
||||
return GLib.SOURCE_REMOVE;
|
||||
});
|
||||
GLib.Source.set_name_by_id(id, '[gnome-shell] SystemBackground.loaded');
|
||||
}
|
||||
});
|
||||
|
|
@ -0,0 +1,523 @@
|
|||
import Clutter from 'gi://Clutter'
|
||||
import Cogl from 'gi://Cogl';
|
||||
import GLib from 'gi://GLib';
|
||||
import GObject from 'gi://GObject';
|
||||
import Shell from 'gi://Shell';
|
||||
|
||||
import Globals from './globals.js';
|
||||
import { degreeToRadian, diagonalToCrossFOVs } from './math.js';
|
||||
|
||||
|
||||
// these need to mirror the values in XRLinuxDriver
|
||||
// https://github.com/wheaney/XRLinuxDriver/blob/main/src/plugins/smooth_follow.c#L31
|
||||
export const SMOOTH_FOLLOW_SLERP_TIMELINE_MS = 1000;
|
||||
const SMOOTH_FOLLOW_SLERP_FACTOR = Math.pow(1-0.999, 1/SMOOTH_FOLLOW_SLERP_TIMELINE_MS);
|
||||
|
||||
// this mirror's how the driver's slerp function progresses so our effect will match it
|
||||
function smoothFollowSlerpProgress(elapsedMs) {
|
||||
return 1 - Math.pow(SMOOTH_FOLLOW_SLERP_FACTOR, elapsedMs);
|
||||
}
|
||||
|
||||
// how far to look ahead is how old the IMU data is plus a constant that is either the default for this device or an override
|
||||
function lookAheadMS(imuDateMs, lookAheadCfg, override) {
|
||||
// how stale the imu data is
|
||||
const dataAge = Date.now() - imuDateMs;
|
||||
|
||||
return (override === -1 ? lookAheadCfg[0] : override) + dataAge;
|
||||
}
|
||||
|
||||
export const VirtualDisplayEffect = GObject.registerClass({
|
||||
Properties: {
|
||||
'monitor-index': GObject.ParamSpec.int(
|
||||
'monitor-index',
|
||||
'Monitor Index',
|
||||
'Index of the monitor that this effect is applied to',
|
||||
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
|
||||
),
|
||||
'target-monitor': GObject.ParamSpec.jsobject(
|
||||
'target-monitor',
|
||||
'Target Monitor',
|
||||
'Details about the monitor being used as a viewport',
|
||||
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
|
||||
),
|
||||
'smooth-follow-enabled': GObject.ParamSpec.boolean(
|
||||
'smooth-follow-enabled',
|
||||
'Smooth follow enabled',
|
||||
'Whether smooth follow is enabled',
|
||||
GObject.ParamFlags.READWRITE,
|
||||
false
|
||||
),
|
||||
'smooth-follow-toggle-epoch-ms': GObject.ParamSpec.uint64(
|
||||
'smooth-follow-toggle-epoch-ms',
|
||||
'Smooth follow toggle epoch time',
|
||||
'ms since epoch when smooth follow was toggled',
|
||||
GObject.ParamFlags.READWRITE,
|
||||
0, Number.MAX_SAFE_INTEGER, 0
|
||||
),
|
||||
'width': GObject.ParamSpec.int(
|
||||
'width',
|
||||
'Width',
|
||||
'Width of the viewport',
|
||||
GObject.ParamFlags.READWRITE,
|
||||
1, 10000, 1920
|
||||
),
|
||||
'height': GObject.ParamSpec.int(
|
||||
'height',
|
||||
'Height',
|
||||
'Height of the viewport',
|
||||
GObject.ParamFlags.READWRITE,
|
||||
1, 10000, 1080
|
||||
),
|
||||
'focused-monitor-index': GObject.ParamSpec.int(
|
||||
'focused-monitor-index',
|
||||
'Focused Monitor Index',
|
||||
'Index of the monitor that is currently focused',
|
||||
GObject.ParamFlags.READWRITE,
|
||||
-1, 100, -1
|
||||
),
|
||||
'display-zoom-on-focus': GObject.ParamSpec.boolean(
|
||||
'display-zoom-on-focus',
|
||||
'Display zoom on focus',
|
||||
'Automatically move a display closer when it becomes focused.',
|
||||
GObject.ParamFlags.READWRITE,
|
||||
true
|
||||
),
|
||||
'display-distance': GObject.ParamSpec.double(
|
||||
'display-distance',
|
||||
'Display Distance',
|
||||
'Distance of the display from the camera',
|
||||
GObject.ParamFlags.READWRITE,
|
||||
0.0,
|
||||
2.5,
|
||||
1.0
|
||||
),
|
||||
'display-distance-default': GObject.ParamSpec.double(
|
||||
'display-distance-default',
|
||||
'Display distance default',
|
||||
'Distance to use when not explicitly set, or when reset',
|
||||
GObject.ParamFlags.READWRITE,
|
||||
0.2,
|
||||
2.5,
|
||||
1.0
|
||||
),
|
||||
'show-banner': GObject.ParamSpec.boolean(
|
||||
'show-banner',
|
||||
'Show banner',
|
||||
'Whether the banner should be displayed',
|
||||
GObject.ParamFlags.READWRITE,
|
||||
false
|
||||
),
|
||||
'lens-vector': GObject.ParamSpec.jsobject(
|
||||
'lens-vector',
|
||||
'Lens Vector',
|
||||
'Vector representing the offset of the lens from the pivot point',
|
||||
GObject.ParamFlags.READWRITE
|
||||
),
|
||||
'actor-to-display-ratios': GObject.ParamSpec.jsobject(
|
||||
'actor-to-display-ratios',
|
||||
'Actor to Display Ratios',
|
||||
'Ratios to convert actor coordinates to display coordinates',
|
||||
GObject.ParamFlags.READWRITE
|
||||
),
|
||||
'actor-to-display-offsets': GObject.ParamSpec.jsobject(
|
||||
'actor-to-display-offsets',
|
||||
'Actor to Display Offsets',
|
||||
'Offsets to convert actor coordinates to display coordinates',
|
||||
GObject.ParamFlags.READWRITE
|
||||
),
|
||||
'is-closest': GObject.ParamSpec.boolean(
|
||||
'is-closest',
|
||||
'Is Closest',
|
||||
'Whether this monitor is the closest to the camera',
|
||||
GObject.ParamFlags.READWRITE,
|
||||
false
|
||||
),
|
||||
'disable-anti-aliasing': GObject.ParamSpec.boolean(
|
||||
'disable-anti-aliasing',
|
||||
'Disable anti-aliasing',
|
||||
'Disable anti-aliasing for the effect',
|
||||
GObject.ParamFlags.READWRITE,
|
||||
false
|
||||
),
|
||||
'look-ahead-override': GObject.ParamSpec.int(
|
||||
'look-ahead-override',
|
||||
'Look ahead override',
|
||||
'Override the look ahead value',
|
||||
GObject.ParamFlags.READWRITE,
|
||||
-1,
|
||||
45,
|
||||
-1
|
||||
),
|
||||
}
|
||||
}, class VirtualDisplayEffect extends Shell.GLSLEffect {
|
||||
constructor(params = {}) {
|
||||
super(params);
|
||||
|
||||
this._current_display_distance = this._is_focused() ? this.display_distance : this.display_distance_default;
|
||||
this.no_distance_ease = false;
|
||||
this._current_follow_ease_progress = 0.0;
|
||||
this._use_smooth_follow_origin = false;
|
||||
|
||||
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));
|
||||
this.connect('notify::show-banner', this._handle_banner_update.bind(this));
|
||||
this.connect('notify::smooth-follow-enabled', this._handle_smooth_follow_enabled_update.bind(this));
|
||||
}
|
||||
|
||||
_is_focused() {
|
||||
return this.focused_monitor_index === this.monitor_index;
|
||||
}
|
||||
|
||||
_update_display_distance() {
|
||||
const desired_distance = this._is_focused() ? this.display_distance : this.display_distance_default;
|
||||
if (this._distance_ease_timeline?.is_playing()) {
|
||||
// we're already easing towards the desired distance, do nothing
|
||||
if (this._distance_ease_target === desired_distance) return;
|
||||
|
||||
this._distance_ease_timeline.stop();
|
||||
}
|
||||
|
||||
if (this.no_distance_ease) {
|
||||
this._current_display_distance = desired_distance;
|
||||
this._update_display_position_uniforms();
|
||||
this.no_distance_ease = false;
|
||||
return;
|
||||
}
|
||||
|
||||
// if we're the focused display, we'll double the timeline and wait for the first half to let other
|
||||
// displays ease out first
|
||||
this._distance_ease_focus = this._is_focused();
|
||||
const ease_out_timeline_ms = 150;
|
||||
const pause_ms = 50;
|
||||
const ease_in_timeline_ms = 500; // includes ease out and pause
|
||||
const ease_in_begin_pct = (ease_out_timeline_ms + pause_ms) / ease_in_timeline_ms;
|
||||
const timeline_ms = this._distance_ease_focus ?
|
||||
ease_in_timeline_ms :
|
||||
ease_out_timeline_ms;
|
||||
|
||||
this._distance_ease_start = this._current_display_distance;
|
||||
this._distance_ease_timeline = Clutter.Timeline.new_for_actor(this.get_actor(), timeline_ms);
|
||||
|
||||
this._distance_ease_target = desired_distance;
|
||||
this._distance_ease_timeline.connect('new-frame', (() => {
|
||||
let progress = this._distance_ease_timeline.get_progress();
|
||||
if (this._distance_ease_focus) {
|
||||
// if we're the focused display, wait for the first half of the timeline to pass
|
||||
if (progress < ease_in_begin_pct) return;
|
||||
|
||||
// treat the second half of the timeline as its own full progression
|
||||
progress = (progress - ease_in_begin_pct) / (1 - ease_in_begin_pct);
|
||||
|
||||
// put this display in front as it starts to easy in
|
||||
this.is_closest = true;
|
||||
} else {
|
||||
this.is_closest = false;
|
||||
}
|
||||
|
||||
this._current_display_distance = this._distance_ease_start +
|
||||
(1 - Math.cos(progress * Math.PI)) / 2 * (this._distance_ease_target - this._distance_ease_start);
|
||||
this._update_display_position_uniforms();
|
||||
}).bind(this));
|
||||
|
||||
this._distance_ease_timeline.start();
|
||||
|
||||
if (this.smooth_follow_enabled) this._handle_smooth_follow_enabled_update();
|
||||
}
|
||||
|
||||
_handle_smooth_follow_enabled_update() {
|
||||
// we'll re-trigger this once a monitor becomes focused
|
||||
if (this.focused_monitor_index === -1) return;
|
||||
|
||||
this._use_smooth_follow_origin = false;
|
||||
|
||||
if (this._follow_ease_timeline?.is_playing()) this._follow_ease_timeline.stop();
|
||||
|
||||
const from = this._current_follow_ease_progress;
|
||||
const to = this.smooth_follow_enabled && this._is_focused() ? 1.0 : 0.0;
|
||||
const toggleTime = this.smooth_follow_toggle_epoch_ms === 0 ? Date.now() : this.smooth_follow_toggle_epoch_ms;
|
||||
|
||||
// would have been a slight delay between request and slerp actually starting
|
||||
const toggleDelayMs = (Date.now() - toggleTime) * 0.75;
|
||||
const slerpStartTime = toggleTime + toggleDelayMs;
|
||||
|
||||
if (to !== from) {
|
||||
this._follow_ease_timeline = Clutter.Timeline.new_for_actor(
|
||||
this.get_actor(),
|
||||
SMOOTH_FOLLOW_SLERP_TIMELINE_MS - toggleDelayMs
|
||||
);
|
||||
this._follow_ease_timeline.connect('new-frame', ((timeline, elapsed_ms) => {
|
||||
const toggleTimeOffsetMs = Date.now() - slerpStartTime;
|
||||
|
||||
// this relies on the slerp function tuned to reach 100% in about 1 second
|
||||
const progress = smoothFollowSlerpProgress(toggleTimeOffsetMs);
|
||||
this._current_follow_ease_progress = from + (to - from) * progress;
|
||||
this._update_display_position_uniforms();
|
||||
}).bind(this));
|
||||
|
||||
this._follow_ease_timeline.connect('completed', (() => {
|
||||
this._current_follow_ease_progress = to;
|
||||
this._use_smooth_follow_origin = false;
|
||||
this.smooth_follow_toggle_epoch_ms = 0;
|
||||
this._update_display_position_uniforms();
|
||||
}).bind(this));
|
||||
|
||||
this._follow_ease_timeline.start();
|
||||
} else if (!this.smooth_follow_enabled) {
|
||||
// smooth follow has been turned off and this screen wasn't the focus,
|
||||
// continue to use the smooth_follow_origin data for 1 more second
|
||||
this._use_smooth_follow_origin = true;
|
||||
GLib.timeout_add(
|
||||
GLib.PRIORITY_DEFAULT,
|
||||
SMOOTH_FOLLOW_SLERP_TIMELINE_MS - toggleDelayMs,
|
||||
(() => {
|
||||
this._use_smooth_follow_origin = false;
|
||||
this.smooth_follow_toggle_epoch_ms = 0;
|
||||
this._current_follow_ease_progress = to;
|
||||
return GLib.SOURCE_REMOVE;
|
||||
}).bind(this)
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
// follow_ease transitions this from a rotated display (0.0) to a centered/focused display (1.0)
|
||||
_update_display_position_uniforms() {
|
||||
// this is in NWU coordinates
|
||||
const monitorPlacement = this.monitor_placements[this.monitor_index];
|
||||
|
||||
// use the center vector with the distance applied to determine how much to move each coordinate, so they all move uniformly
|
||||
const inverseAppliedDistance = 1.0 - this._current_display_distance / this.display_distance_default;
|
||||
const distanceDelta = monitorPlacement.centerNoRotate.map(coord => coord * inverseAppliedDistance);
|
||||
const noRotationVector = monitorPlacement.topLeftNoRotate.map((coord, index) => coord - distanceDelta[index]);
|
||||
|
||||
// convert to CoGL's east-down-south coordinates and apply display distance
|
||||
const inverse_follow_ease = 1.0 - this._current_follow_ease_progress;
|
||||
if (this._current_follow_ease_progress === 0.0) {
|
||||
this.set_uniform_float(this.get_uniform_location("u_display_position"), 3,
|
||||
[-noRotationVector[1], -noRotationVector[2], -noRotationVector[0]]);
|
||||
} else {
|
||||
const focusDistanceNorth = monitorPlacement.centerOrigin[0] * inverseAppliedDistance;
|
||||
const centerOriginVector = {...monitorPlacement.centerOrigin};
|
||||
centerOriginVector[0] -= focusDistanceNorth;
|
||||
|
||||
// slerp from the rotated display to the centered display
|
||||
const followVector = noRotationVector.map((coord, index) => coord * inverse_follow_ease + centerOriginVector[index] * this._current_follow_ease_progress);
|
||||
this.set_uniform_float(this.get_uniform_location("u_display_position"), 3,
|
||||
[-followVector[1], -followVector[2], -followVector[0]]);
|
||||
}
|
||||
|
||||
const rotation_radians = this.monitor_placements[this.monitor_index].rotationAngleRadians;
|
||||
this.set_uniform_float(this.get_uniform_location("u_rotation_x_radians"), 1, [rotation_radians.x * inverse_follow_ease]);
|
||||
this.set_uniform_float(this.get_uniform_location("u_rotation_y_radians"), 1, [rotation_radians.y * inverse_follow_ease]);
|
||||
}
|
||||
|
||||
_handle_banner_update() {
|
||||
this.set_uniform_float(this.get_uniform_location("u_show_banner"), 1, [this.show_banner ? 1.0 : 0.0]);
|
||||
}
|
||||
|
||||
perspective(fovHorizontalRadians, aspect, near, far) {
|
||||
const f = 1.0 / Math.tan(fovHorizontalRadians / 2.0);
|
||||
const range = far - near;
|
||||
|
||||
return [
|
||||
f / aspect, 0, 0, 0,
|
||||
0, f, 0, 0,
|
||||
0, 0, - (far + near) / range, -1,
|
||||
0, 0, - (2.0 * near * far) / range, 0
|
||||
];
|
||||
}
|
||||
|
||||
vfunc_build_pipeline() {
|
||||
const declarations = `
|
||||
uniform bool u_show_banner;
|
||||
uniform mat4 u_imu_data;
|
||||
uniform float u_look_ahead_ms;
|
||||
uniform vec4 u_look_ahead_cfg;
|
||||
uniform mat4 u_projection_matrix;
|
||||
uniform float u_fov_vertical_radians;
|
||||
uniform vec3 u_display_position;
|
||||
uniform float u_rotation_x_radians;
|
||||
uniform float u_rotation_y_radians;
|
||||
uniform vec2 u_display_resolution;
|
||||
uniform vec3 u_lens_vector;
|
||||
|
||||
// vector positions are relative to the width and height of the entire stage
|
||||
uniform vec2 u_actor_to_display_ratios;
|
||||
uniform vec2 u_actor_to_display_offsets;
|
||||
|
||||
// discovered through trial and error, no idea the significance
|
||||
float cogl_position_mystery_factor = 29.09 * 2;
|
||||
|
||||
float look_ahead_ms_cap = 45.0;
|
||||
|
||||
vec4 quatConjugate(vec4 q) {
|
||||
return vec4(-q.xyz, q.w);
|
||||
}
|
||||
|
||||
vec3 applyQuaternionToVector(vec3 v, vec4 q) {
|
||||
vec3 t = 2.0 * cross(q.xyz, v);
|
||||
return v + q.w * t + cross(q.xyz, t);
|
||||
}
|
||||
|
||||
vec3 applyXRotationToVector(vec3 v, float angle) {
|
||||
float c = cos(angle);
|
||||
float s = sin(angle);
|
||||
return vec3(v.x, v.y * c - v.z * s, v.y * s + v.z * c);
|
||||
}
|
||||
|
||||
vec3 applyYRotationToVector(vec3 v, float angle) {
|
||||
float c = cos(angle);
|
||||
float s = sin(angle);
|
||||
return vec3(v.x * c + v.z * s, v.y, v.z * c - v.x * s);
|
||||
}
|
||||
|
||||
vec4 nwuToESU(vec4 v) {
|
||||
return vec4(-v.y, v.z, -v.x, v.w);
|
||||
}
|
||||
|
||||
// returns the rate of change between the two vectors, in same time units as delta_time
|
||||
// e.g. if delta_time is in ms, then the rate of change is "per ms"
|
||||
vec3 rateOfChange(vec3 v1, vec3 v2, float delta_time) {
|
||||
return (v1-v2) / delta_time;
|
||||
}
|
||||
|
||||
// attempt to figure out where the current position should be based on previous position and velocity.
|
||||
// velocity and time values should use the same time units (secs, ms, etc...)
|
||||
vec3 applyLookAhead(vec3 position, vec3 velocity, float look_ahead_ms) {
|
||||
return position + velocity * look_ahead_ms;
|
||||
}
|
||||
|
||||
// project the vector onto a flat surface, return it's vertical position relative to the vertical fov, where 0.0 is
|
||||
// the top and 1.0 is the bottom. vectors that project outside the vertical range of the display will have values
|
||||
// outside this range, but capped
|
||||
float vectorToScanline(float fovVerticalRadians, vec3 v) {
|
||||
return clamp(1.0 - (-v.y / (tan(fovVerticalRadians / 2.0) * v.z) + 1.0) / 2.0, -1.5, 2.5);
|
||||
}
|
||||
`;
|
||||
|
||||
const main = `
|
||||
vec4 world_pos = cogl_position_in;
|
||||
|
||||
if (!u_show_banner) {
|
||||
float aspect_ratio = u_display_resolution.x / u_display_resolution.y;
|
||||
|
||||
float cogl_position_width = cogl_position_mystery_factor * aspect_ratio / u_actor_to_display_ratios.y;
|
||||
float cogl_position_height = cogl_position_width / aspect_ratio;
|
||||
|
||||
float pos_z_factor = aspect_ratio / u_actor_to_display_ratios.y;
|
||||
vec3 pos_factors = vec3(
|
||||
cogl_position_width / u_display_resolution.x,
|
||||
cogl_position_height / u_display_resolution.y,
|
||||
cogl_position_mystery_factor * pos_z_factor / u_display_resolution.x
|
||||
);
|
||||
world_pos.x -= u_display_position.x * pos_factors.x;
|
||||
world_pos.y -= u_display_position.y * pos_factors.y;
|
||||
world_pos.z = u_display_position.z * pos_factors.z;
|
||||
|
||||
// if the perspective includes more than just our viewport actor, move vertices towards the center of the perspective so they'll be properly rotated
|
||||
world_pos.x += u_actor_to_display_offsets.x * cogl_position_width / 2;
|
||||
world_pos.y -= u_actor_to_display_offsets.y * cogl_position_height / 2;
|
||||
|
||||
vec3 complete_vector = applyXRotationToVector(world_pos.xyz, u_rotation_x_radians);
|
||||
complete_vector = applyYRotationToVector(complete_vector, u_rotation_y_radians);
|
||||
|
||||
vec4 quat_t0 = nwuToESU(quatConjugate(u_imu_data[0]));
|
||||
vec3 rotated_vector_t0 = applyQuaternionToVector(complete_vector, quat_t0);
|
||||
vec3 rotated_vector_t1 = applyQuaternionToVector(complete_vector, nwuToESU(quatConjugate(u_imu_data[1])));
|
||||
float delta_time_t0 = u_imu_data[3][0] - u_imu_data[3][1];
|
||||
vec3 velocity_t0 = rateOfChange(rotated_vector_t0, rotated_vector_t1, delta_time_t0);
|
||||
|
||||
// compute the capped look ahead with scanline adjustments
|
||||
float look_ahead_scanline_ms = u_look_ahead_ms == 0.0 ? 0.0 : vectorToScanline(u_fov_vertical_radians, rotated_vector_t0) * u_look_ahead_cfg[2];
|
||||
float effective_look_ahead_ms = min(min(u_look_ahead_ms, look_ahead_ms_cap), u_look_ahead_cfg[3]) + look_ahead_scanline_ms;
|
||||
|
||||
vec3 look_ahead_vector = applyLookAhead(rotated_vector_t0, velocity_t0, effective_look_ahead_ms);
|
||||
|
||||
vec3 adjusted_lens_vector = u_lens_vector * pos_factors;
|
||||
world_pos = vec4(look_ahead_vector - adjusted_lens_vector, world_pos.w);
|
||||
|
||||
world_pos.z /= pos_z_factor;
|
||||
|
||||
world_pos.x *= u_actor_to_display_ratios.y / u_actor_to_display_ratios.x;
|
||||
|
||||
world_pos = u_projection_matrix * world_pos;
|
||||
|
||||
// if the perspective includes more than just our viewport actor, move the vertices back to just the area we can see.
|
||||
// this needs to be done after the projection matrix multiplication so it will be projected as if centered in our vision
|
||||
world_pos.x -= (u_actor_to_display_offsets.x / u_actor_to_display_ratios.x) * world_pos.w;
|
||||
world_pos.y += (u_actor_to_display_offsets.y / u_actor_to_display_ratios.y) * world_pos.w;
|
||||
} else {
|
||||
world_pos = cogl_modelview_matrix * world_pos;
|
||||
world_pos = cogl_projection_matrix * world_pos;
|
||||
}
|
||||
|
||||
cogl_position_out = world_pos;
|
||||
cogl_tex_coord_out[0] = cogl_tex_coord_in;
|
||||
`
|
||||
|
||||
this.add_glsl_snippet(Shell.SnippetHook.VERTEX, declarations, main, false);
|
||||
}
|
||||
|
||||
vfunc_paint_target(node, paintContext) {
|
||||
if (!this._initialized) {
|
||||
const aspect = this.target_monitor.width / this.target_monitor.height;
|
||||
const fovRadians = diagonalToCrossFOVs(degreeToRadian(Globals.data_stream.device_data.displayFov), aspect);
|
||||
const projection_matrix = this.perspective(
|
||||
fovRadians.horizontal,
|
||||
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_fov_vertical_radians"), 1, [fovRadians.vertical]);
|
||||
this.set_uniform_float(this.get_uniform_location("u_display_resolution"), 2, [this.target_monitor.width, this.target_monitor.height]);
|
||||
this.set_uniform_float(this.get_uniform_location("u_look_ahead_cfg"), 4, Globals.data_stream.device_data.lookAheadCfg);
|
||||
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.set_uniform_float(this.get_uniform_location("u_lens_vector"), 3, this.lens_vector);
|
||||
this._update_display_position_uniforms();
|
||||
this._handle_banner_update();
|
||||
this._initialized = true;
|
||||
}
|
||||
|
||||
let lookAheadSet = false;
|
||||
if (!this._use_smooth_follow_origin && (!this.smooth_follow_enabled || this._is_focused() || this._current_follow_ease_progress > 0.0)) {
|
||||
if (this._current_follow_ease_progress > 0.0 && this._current_follow_ease_progress < 1.0) {
|
||||
// don't apply look-ahead while the display is slerping
|
||||
this.set_uniform_float(this.get_uniform_location('u_look_ahead_ms'), 1, [0.0]);
|
||||
lookAheadSet = true;
|
||||
}
|
||||
this.set_uniform_matrix(this.get_uniform_location("u_imu_data"), false, 4, this.imu_snapshots.imu_data);
|
||||
} else {
|
||||
this.set_uniform_matrix(this.get_uniform_location("u_imu_data"), false, 4, this.imu_snapshots.smooth_follow_origin);
|
||||
}
|
||||
if (!lookAheadSet) {
|
||||
this.set_uniform_float(this.get_uniform_location('u_look_ahead_ms'), 1, [lookAheadMS(this.imu_snapshots.timestamp_ms, Globals.data_stream.device_data.lookAheadCfg, this.look_ahead_override)]);
|
||||
}
|
||||
|
||||
if (!this.disable_anti_aliasing) {
|
||||
// improves sampling quality for smooth text and edges
|
||||
this.get_pipeline().set_layer_filters(
|
||||
0,
|
||||
Cogl.PipelineFilter.LINEAR_MIPMAP_LINEAR,
|
||||
Cogl.PipelineFilter.LINEAR
|
||||
);
|
||||
}
|
||||
|
||||
super.vfunc_paint_target(node, paintContext);
|
||||
}
|
||||
});
|
||||
|
|
@ -0,0 +1,907 @@
|
|||
import Clutter from 'gi://Clutter'
|
||||
import Cogl from 'gi://Cogl';
|
||||
import GdkPixbuf from 'gi://GdkPixbuf';
|
||||
import GLib from 'gi://GLib';
|
||||
import GObject from 'gi://GObject';
|
||||
import Mtk from 'gi://Mtk';
|
||||
import Shell from 'gi://Shell';
|
||||
import St from 'gi://St';
|
||||
|
||||
import { VirtualDisplayEffect, SMOOTH_FOLLOW_SLERP_TIMELINE_MS } from './virtualdisplayeffect.js';
|
||||
import { degreeToRadian, diagonalToCrossFOVs } from './math.js';
|
||||
|
||||
import * as Main from 'resource:///org/gnome/shell/ui/main.js';
|
||||
|
||||
import Globals from './globals.js';
|
||||
|
||||
function applyQuaternionToVector(vector, quaternion) {
|
||||
const t = [
|
||||
2.0 * (quaternion[1] * vector[2] - quaternion[2] * vector[1]),
|
||||
2.0 * (quaternion[2] * vector[0] - quaternion[0] * vector[2]),
|
||||
2.0 * (quaternion[0] * vector[1] - quaternion[1] * vector[0])
|
||||
];
|
||||
return [
|
||||
vector[0] + quaternion[3] * t[0] + quaternion[1] * t[2] - quaternion[2] * t[1],
|
||||
vector[1] + quaternion[3] * t[1] + quaternion[2] * t[0] - quaternion[0] * t[2],
|
||||
vector[2] + quaternion[3] * t[2] + quaternion[0] * t[1] - quaternion[1] * t[0]
|
||||
];
|
||||
}
|
||||
|
||||
// if nothing is in focus, take it as soon as it crosses into the monitor's bounds
|
||||
const FOCUS_THRESHOLD = 0.95 / 2.0;
|
||||
|
||||
// if we leave the monitor with some margin, unfocus even if no other monitor is in focus
|
||||
const UNFOCUS_THRESHOLD = 1.2 / 2.0;
|
||||
|
||||
/**
|
||||
* Find the vector in the array that's closest to the quaternion rotation
|
||||
*
|
||||
* @param {number[]} quaternion - Reference quaternion [x, y, z, w]
|
||||
* @param {number[][]} monitorVectors - Array of monitor vectors [x, y, z] to search from
|
||||
* @param {number} currentFocusedIndex - Index of the currently focused monitor
|
||||
* @param {number} focusedMonitorDistance - Distance to the focused monitor, < 1.0 if zoomed in
|
||||
* @param {boolean} smoothFollowEnabled - If true, always keep the current monitor in focus or choose the closest
|
||||
* @param {Object} fovDetails - Contains reference widthPixels, heightPixels, horizontal and vertical radians, and pixel distance to the center of the screen
|
||||
* @param {Object[]} monitorsDetails - Contains x, y, width, height (coordinates from top-left) for each monitor
|
||||
* @returns {number} Index of the closest vector, if it surpasses the previous closest index by a certain margin, otherwise the previous index
|
||||
*/
|
||||
function findFocusedMonitor(quaternion, monitorVectors, currentFocusedIndex, focusedMonitorDistance, smoothFollowEnabled, fovDetails, monitorsDetails) {
|
||||
const lookVector = [1.0, 0.0, 0.0]; // NWU vector pointing to the center of the screen
|
||||
const rotatedLookVector = applyQuaternionToVector(lookVector, quaternion);
|
||||
|
||||
const xzMagnitude = Math.sqrt(rotatedLookVector[0]*rotatedLookVector[0] + rotatedLookVector[2]*rotatedLookVector[2]);
|
||||
const lookUpTheta = Math.atan2(rotatedLookVector[2], rotatedLookVector[0]);
|
||||
|
||||
let closestIndex = -1;
|
||||
let closestDistance = Infinity;
|
||||
let currentFocusedDistance = Infinity;
|
||||
|
||||
// find the vector closest to the rotated look vector
|
||||
monitorVectors.forEach((vector, index) => {
|
||||
const monitor = monitorsDetails[index];
|
||||
const monitorAspectRatio = monitor.width / monitor.height;
|
||||
|
||||
// weight the rotation about the y-axis between the two vectors, by the aspect ratio
|
||||
const vectorUpTheta = Math.atan2(vector[2], vector[0]);
|
||||
const upDelta = lookUpTheta - vectorUpTheta;
|
||||
const newLookUpTheta = Math.tan(Math.max(
|
||||
-Math.PI,
|
||||
Math.min(
|
||||
Math.PI,
|
||||
upDelta * monitorAspectRatio + vectorUpTheta
|
||||
)
|
||||
));
|
||||
const weightedLookVector = [
|
||||
xzMagnitude * Math.cos(newLookUpTheta),
|
||||
rotatedLookVector[1],
|
||||
xzMagnitude * Math.sin(newLookUpTheta)
|
||||
];
|
||||
|
||||
// find the distance between the monitor vector and weighted look vector
|
||||
const distance = Math.acos(
|
||||
Math.min(1.0, Math.max(-1.0,
|
||||
vector[0] * weightedLookVector[0] +
|
||||
vector[1] * weightedLookVector[1] +
|
||||
vector[2] * weightedLookVector[2]
|
||||
))
|
||||
);
|
||||
|
||||
// TODO - this assumes the display is facing towards us, need to account for looking in the "flat" direction
|
||||
const distanceFromCenterPixels = fovDetails.completeScreenDistancePixels * Math.tan(distance);
|
||||
const distanceFromCenterSizeRatio = distanceFromCenterPixels / monitor.width;
|
||||
|
||||
if (currentFocusedIndex === index) {
|
||||
currentFocusedDistance = distanceFromCenterSizeRatio * focusedMonitorDistance;
|
||||
}
|
||||
|
||||
if (distanceFromCenterSizeRatio < closestDistance) {
|
||||
closestIndex = index;
|
||||
closestDistance = distanceFromCenterSizeRatio;
|
||||
}
|
||||
});
|
||||
|
||||
const keepCurrent = currentFocusedIndex !== -1 && (smoothFollowEnabled || currentFocusedDistance < UNFOCUS_THRESHOLD);
|
||||
if (!keepCurrent) {
|
||||
if (smoothFollowEnabled || closestDistance < FOCUS_THRESHOLD) return closestIndex;
|
||||
|
||||
// neither the current nor the closest will take focus, unfocus all displays
|
||||
return -1;
|
||||
}
|
||||
|
||||
return currentFocusedIndex;
|
||||
}
|
||||
|
||||
/***
|
||||
* @returns {Object} - containing `begin`, `center`, and `end` radians for rotating the given monitor
|
||||
*/
|
||||
function monitorWrap(cachedMonitorRadians, radiusPixels, monitorSpacingPixels, monitorBeginPixel, monitorLengthPixels) {
|
||||
let closestWrapPixel = monitorBeginPixel;
|
||||
let closestWrap = cachedMonitorRadians[monitorBeginPixel];
|
||||
if (closestWrap === undefined) {
|
||||
closestWrapPixel = Object.keys(cachedMonitorRadians).reduce((previousPixel, currentPixel) => {
|
||||
if (previousPixel === undefined) return currentPixel;
|
||||
|
||||
const currentDelta = currentPixel - monitorBeginPixel;
|
||||
const previousDelta = previousPixel - monitorBeginPixel;
|
||||
|
||||
// always prefer an exact monitor width match
|
||||
if (previousDelta % monitorLengthPixels !== 0) {
|
||||
if (currentDelta % monitorLengthPixels === 0) return currentPixel;
|
||||
|
||||
// prefer placing a monitor to the right or below, even if there's a closer placement to the left or above
|
||||
if (previousDelta < 0 && currentDelta > 0) return currentPixel;
|
||||
|
||||
// otherwise, just prefer the closest one
|
||||
if (Math.abs(currentDelta) < Math.abs(previousDelta)) return currentPixel;
|
||||
}
|
||||
|
||||
return previousPixel;
|
||||
}, undefined);
|
||||
closestWrap = cachedMonitorRadians[closestWrapPixel];
|
||||
}
|
||||
|
||||
const spacingRadians = Math.asin(monitorSpacingPixels / 2 / radiusPixels) * 2;
|
||||
if (closestWrapPixel !== monitorBeginPixel) {
|
||||
// there's a gap between the cached wrap value and this one
|
||||
const gapPixels = monitorBeginPixel - closestWrapPixel;
|
||||
const gapHalfRadians = Math.asin(gapPixels / 2 / radiusPixels);
|
||||
const gapRadians = gapHalfRadians * 2;
|
||||
|
||||
// use Math.floor so if it's negative (this monitor is to the left of or above the closest) it will always
|
||||
// compenstate for the spacing that's needed at the right/bottom
|
||||
const appliedSpacingRadians = Math.floor(gapPixels / monitorLengthPixels) * spacingRadians;
|
||||
|
||||
// update the closestWrap value and cache it
|
||||
closestWrap = closestWrap + gapRadians + appliedSpacingRadians;
|
||||
closestWrapPixel = monitorBeginPixel;
|
||||
cachedMonitorRadians[closestWrapPixel] = closestWrap;
|
||||
}
|
||||
|
||||
const monitorHalfRadians = Math.asin(monitorLengthPixels / 2 / radiusPixels);
|
||||
const centerRadians = closestWrap + monitorHalfRadians;
|
||||
const endRadians = centerRadians + monitorHalfRadians;
|
||||
|
||||
// since we're computing the end values for this monitor, cache them too in case they line up with a future monitor
|
||||
const nextMonitorPixel = monitorBeginPixel + monitorLengthPixels;
|
||||
if (cachedMonitorRadians[nextMonitorPixel] === undefined)
|
||||
cachedMonitorRadians[nextMonitorPixel] = endRadians + spacingRadians;
|
||||
|
||||
return {
|
||||
begin: closestWrap,
|
||||
center: centerRadians,
|
||||
end: endRadians
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert the given monitor details into NWU vectors describing the center of the fully placed monitor,
|
||||
* and the top-left of the partially placed monitor (minus only a single-axis rotation)
|
||||
*
|
||||
* @param {Object} fovDetails - contains reference widthPixels, heightPixels, horizontal and vertical radians,
|
||||
* and distance to the center of the screen
|
||||
* @param {Object[]} monitorDetailsList - contains x, y, width, height (coordinates from top-left)
|
||||
* @param {string} monitorWrappingScheme - horizontal, vertical, none
|
||||
* @returns {Object[]} - contains NWU vectors pointing to `topLeftNoRotate` and `center` of each monitor
|
||||
* and a `rotation` angle for the given wrapping scheme
|
||||
*/
|
||||
function monitorsToPlacements(fovDetails, monitorDetailsList, monitorWrappingScheme, monitorSpacing) {
|
||||
const monitorPlacements = [];
|
||||
const cachedMonitorRadians = {};
|
||||
|
||||
Globals.logger.log_debug(`\t\t\tFOV Details: ${JSON.stringify(fovDetails)}, Monitor Wrapping Scheme: ${monitorWrappingScheme}`);
|
||||
|
||||
if (monitorWrappingScheme === 'horizontal') {
|
||||
// monitors wrap around us horizontally
|
||||
|
||||
// distance to a horizontal edge is the hypothenuse of the triangle where the opposite side is half the width of the reference fov screen
|
||||
const sideEdgeRadius = Math.sqrt(Math.pow(fovDetails.widthPixels / 2, 2) + Math.pow(fovDetails.completeScreenDistancePixels, 2));
|
||||
const monitorSpacingPixels = monitorSpacing * fovDetails.widthPixels;
|
||||
|
||||
cachedMonitorRadians[0] = -fovDetails.defaultDistanceHorizontalRadians / 2;
|
||||
monitorDetailsList.forEach(monitorDetails => {
|
||||
const monitorWrapDetails = monitorWrap(cachedMonitorRadians, sideEdgeRadius, monitorSpacingPixels, monitorDetails.x, monitorDetails.width);
|
||||
const monitorCenterRadius = Math.sqrt(Math.pow(sideEdgeRadius, 2) - Math.pow(monitorDetails.width / 2, 2));
|
||||
const upTopPixels = monitorDetails.y + (monitorDetails.y / fovDetails.heightPixels) * monitorSpacingPixels;
|
||||
|
||||
// how to place the monitors at the origin (0, 0)
|
||||
const westCenterOriginPixels = (monitorDetails.width - fovDetails.widthPixels) / 2;
|
||||
const upCenterOriginPixels = (monitorDetails.height - fovDetails.heightPixels) / 2;
|
||||
|
||||
const upCenterPixels = upTopPixels + upCenterOriginPixels;
|
||||
|
||||
monitorPlacements.push({
|
||||
topLeftNoRotate: [
|
||||
monitorCenterRadius,
|
||||
|
||||
// west stays aligned with the origin, will apply rotationAngleRadians value during rendering
|
||||
-westCenterOriginPixels,
|
||||
|
||||
// up is flat when wrapping horizontally, apply it here as a constant, not touched by rendering
|
||||
-upTopPixels
|
||||
],
|
||||
centerNoRotate: [
|
||||
monitorCenterRadius,
|
||||
|
||||
// west centered about the FOV center
|
||||
0,
|
||||
|
||||
// up is flat when wrapping horizontally
|
||||
-upCenterPixels
|
||||
],
|
||||
centerOrigin: [
|
||||
monitorCenterRadius,
|
||||
-westCenterOriginPixels,
|
||||
upCenterOriginPixels
|
||||
],
|
||||
centerLook: [
|
||||
// north is adjacent where radius is the hypotenuse, using monitorWrapDetails.center as the radians
|
||||
monitorCenterRadius * Math.cos(monitorWrapDetails.center),
|
||||
|
||||
// west is opposite where radius is the hypotenuse, using monitorWrapDetails.center as the radians
|
||||
-monitorCenterRadius * Math.sin(monitorWrapDetails.center),
|
||||
|
||||
// up is flat when wrapping horizontally
|
||||
-upCenterPixels
|
||||
],
|
||||
rotationAngleRadians: {
|
||||
x: 0,
|
||||
y: -monitorWrapDetails.center
|
||||
}
|
||||
});
|
||||
});
|
||||
} else if (monitorWrappingScheme === 'vertical') {
|
||||
// monitors wrap around us vertically
|
||||
|
||||
// distance to the top edge is the hypothenuse of the triangle where the opposite side is half the height of the reference fov screen
|
||||
const topEdgeRadius = Math.sqrt(Math.pow(fovDetails.heightPixels / 2, 2) + Math.pow(fovDetails.completeScreenDistancePixels, 2));
|
||||
const monitorSpacingPixels = monitorSpacing * fovDetails.heightPixels;
|
||||
|
||||
cachedMonitorRadians[0] = -fovDetails.defaultDistanceVerticalRadians / 2;
|
||||
monitorDetailsList.forEach(monitorDetails => {
|
||||
const monitorWrapDetails = monitorWrap(cachedMonitorRadians, topEdgeRadius, monitorSpacingPixels, monitorDetails.y, monitorDetails.height);
|
||||
const monitorCenterRadius = Math.sqrt(Math.pow(topEdgeRadius, 2) - Math.pow(monitorDetails.height / 2, 2));
|
||||
const westPixels = monitorDetails.x + (monitorDetails.x / fovDetails.widthPixels) * monitorSpacingPixels;
|
||||
|
||||
// how to place the monitors at the origin (0, 0)
|
||||
const westCenterOriginPixels = (monitorDetails.width - fovDetails.widthPixels) / 2;
|
||||
const upCenterOriginPixels = (monitorDetails.height - fovDetails.heightPixels) / 2;
|
||||
|
||||
const westCenterPixels = westPixels + westCenterOriginPixels;
|
||||
|
||||
monitorPlacements.push({
|
||||
topLeftNoRotate: [
|
||||
monitorCenterRadius,
|
||||
|
||||
// west is flat when wrapping vertically, apply it here as a constant, not touched by rendering
|
||||
westPixels,
|
||||
|
||||
// up stays aligned with the origin, will apply rotationAngleRadians value during rendering
|
||||
upCenterOriginPixels
|
||||
],
|
||||
centerNoRotate: [
|
||||
monitorCenterRadius,
|
||||
|
||||
// west is flat when wrapping horizontally
|
||||
westCenterPixels,
|
||||
|
||||
// west centered about the FOV center
|
||||
0
|
||||
],
|
||||
centerOrigin: [
|
||||
monitorCenterRadius,
|
||||
-westCenterOriginPixels,
|
||||
upCenterOriginPixels
|
||||
],
|
||||
centerLook: [
|
||||
// north is adjacent where radius is the hypotenuse, using monitorWrapDetails.center as the radians
|
||||
monitorCenterRadius * Math.cos(monitorWrapDetails.center),
|
||||
|
||||
// west is flat when wrapping vertically
|
||||
-westCenterPixels,
|
||||
|
||||
// up is opposite where radius is the hypotenuse, using monitorWrapDetails.center as the radians
|
||||
-monitorCenterRadius * Math.sin(monitorWrapDetails.center)
|
||||
],
|
||||
rotationAngleRadians: {
|
||||
x: -monitorWrapDetails.center,
|
||||
y: 0
|
||||
}
|
||||
});
|
||||
});
|
||||
} else {
|
||||
const monitorSpacingPixels = monitorSpacing * fovDetails.widthPixels;
|
||||
|
||||
// monitors make a flat wall in front of us, no wrapping
|
||||
monitorDetailsList.forEach(monitorDetails => {
|
||||
const upPixels = monitorDetails.y + (monitorDetails.y / fovDetails.heightPixels) * monitorSpacingPixels;
|
||||
const westPixels = monitorDetails.x + (monitorDetails.x / fovDetails.widthPixels) * monitorSpacingPixels;
|
||||
|
||||
// how to place the monitors at the origin (0, 0)
|
||||
const westCenterOriginPixels = (monitorDetails.width - fovDetails.widthPixels) / 2;
|
||||
const upCenterOriginPixels = (monitorDetails.height - fovDetails.heightPixels) / 2;
|
||||
|
||||
const westCenterPixels = westPixels + westCenterOriginPixels;
|
||||
const upCenterPixels = upPixels + upCenterOriginPixels;
|
||||
|
||||
monitorPlacements.push({
|
||||
topLeftNoRotate: [
|
||||
fovDetails.completeScreenDistancePixels,
|
||||
westPixels,
|
||||
-upPixels
|
||||
],
|
||||
centerNoRotate: [
|
||||
fovDetails.completeScreenDistancePixels,
|
||||
westCenterPixels,
|
||||
-upCenterPixels
|
||||
],
|
||||
centerOrigin: [
|
||||
fovDetails.completeScreenDistancePixels,
|
||||
-westCenterOriginPixels,
|
||||
upCenterOriginPixels
|
||||
],
|
||||
centerLook: [
|
||||
fovDetails.completeScreenDistancePixels,
|
||||
-westCenterPixels,
|
||||
-upCenterPixels
|
||||
],
|
||||
rotationAngleRadians: {
|
||||
x: 0,
|
||||
y: 0
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
Globals.logger.log_debug(`\t\t\tMonitor placements: ${JSON.stringify(monitorPlacements)}, cached values: ${JSON.stringify(cachedMonitorRadians)}`);
|
||||
|
||||
return monitorPlacements;
|
||||
}
|
||||
|
||||
export const VirtualDisplaysActor = GObject.registerClass({
|
||||
Properties: {
|
||||
'target-monitor': GObject.ParamSpec.jsobject(
|
||||
'target-monitor',
|
||||
'Target Monitor',
|
||||
'Details about the monitor being used as a viewport',
|
||||
GObject.ParamFlags.READWRITE
|
||||
),
|
||||
'virtual-monitors': GObject.ParamSpec.jsobject(
|
||||
'virtual-monitors',
|
||||
'Virtual Monitors',
|
||||
'Details about the virtual monitors',
|
||||
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']
|
||||
),
|
||||
'monitor-spacing': GObject.ParamSpec.int(
|
||||
'monitor-spacing',
|
||||
'Monitor Spacing',
|
||||
'Visual spacing between monitors, units are 0.001 of the viewport width',
|
||||
GObject.ParamFlags.READWRITE,
|
||||
0, 100, 0
|
||||
),
|
||||
'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
|
||||
),
|
||||
'monitor-actors': GObject.ParamSpec.jsobject(
|
||||
'monitor-actors',
|
||||
'Monitor Actors',
|
||||
'Tracking actors and details for each monitor',
|
||||
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
|
||||
),
|
||||
'smooth-follow-enabled': GObject.ParamSpec.boolean(
|
||||
'smooth-follow-enabled',
|
||||
'Smooth follow enabled',
|
||||
'Whether smooth follow is enabled',
|
||||
GObject.ParamFlags.READWRITE,
|
||||
false
|
||||
),
|
||||
'smooth-follow-toggle-epoch-ms': GObject.ParamSpec.uint64(
|
||||
'smooth-follow-toggle-epoch-ms',
|
||||
'Smooth follow toggle epoch time',
|
||||
'ms since epoch when smooth follow was toggled',
|
||||
GObject.ParamFlags.READWRITE,
|
||||
0, Number.MAX_SAFE_INTEGER, 0
|
||||
),
|
||||
'show-banner': GObject.ParamSpec.boolean(
|
||||
'show-banner',
|
||||
'Show banner',
|
||||
'Whether the banner should be displayed',
|
||||
GObject.ParamFlags.READWRITE,
|
||||
false
|
||||
),
|
||||
'custom-banner-enabled': GObject.ParamSpec.boolean(
|
||||
'custom-banner-enabled',
|
||||
'Custom banner enabled',
|
||||
'Whether the custom banner should be displayed',
|
||||
GObject.ParamFlags.READWRITE,
|
||||
false
|
||||
),
|
||||
'focused-monitor-index': GObject.ParamSpec.int(
|
||||
'focused-monitor-index',
|
||||
'Focused Monitor Index',
|
||||
'Index of the monitor that is currently focused',
|
||||
GObject.ParamFlags.READWRITE,
|
||||
-1, 100, -1
|
||||
),
|
||||
'focused-monitor-details': GObject.ParamSpec.jsobject(
|
||||
'focused-monitor-details',
|
||||
'Focused Monitor Details',
|
||||
'Details about the monitor that is currently focused',
|
||||
GObject.ParamFlags.READWRITE
|
||||
),
|
||||
'display-size': GObject.ParamSpec.double(
|
||||
'display-size',
|
||||
'Display size',
|
||||
'Size of the display',
|
||||
GObject.ParamFlags.READWRITE,
|
||||
0.2,
|
||||
2.5,
|
||||
1.0
|
||||
),
|
||||
'display-zoom-on-focus': GObject.ParamSpec.boolean(
|
||||
'display-zoom-on-focus',
|
||||
'Display zoom on focus',
|
||||
'Automatically move a display closer when it becomes focused.',
|
||||
GObject.ParamFlags.READWRITE,
|
||||
true
|
||||
),
|
||||
'display-distance': GObject.ParamSpec.double(
|
||||
'display-distance',
|
||||
'Display Distance',
|
||||
'Distance of the display from the camera',
|
||||
GObject.ParamFlags.READWRITE,
|
||||
0.2,
|
||||
2.5,
|
||||
1.05
|
||||
),
|
||||
'lens-vector': GObject.ParamSpec.jsobject(
|
||||
'lens-vector',
|
||||
'Lens Vector',
|
||||
'Vector representing the offset of the lens from the pivot point',
|
||||
GObject.ParamFlags.READWRITE
|
||||
),
|
||||
'toggle-display-distance-start': GObject.ParamSpec.double(
|
||||
'toggle-display-distance-start',
|
||||
'Display distance start',
|
||||
'Start distance when using the "change distance" shortcut.',
|
||||
GObject.ParamFlags.READWRITE,
|
||||
0.2,
|
||||
2.5,
|
||||
1.05
|
||||
),
|
||||
'toggle-display-distance-end': GObject.ParamSpec.double(
|
||||
'toggle-display-distance-end',
|
||||
'Display distance end',
|
||||
'End distance when using the "change distance" shortcut.',
|
||||
GObject.ParamFlags.READWRITE,
|
||||
0.2,
|
||||
2.5,
|
||||
1.05
|
||||
),
|
||||
'framerate-cap': GObject.ParamSpec.double(
|
||||
'framerate-cap',
|
||||
'Framerate Cap',
|
||||
'Maximum framerate to render at',
|
||||
GObject.ParamFlags.READWRITE,
|
||||
0.0, 240.0, 0.0
|
||||
),
|
||||
'look-ahead-override': GObject.ParamSpec.int(
|
||||
'look-ahead-override',
|
||||
'Look ahead override',
|
||||
'Override the look ahead value',
|
||||
GObject.ParamFlags.READWRITE,
|
||||
-1,
|
||||
45,
|
||||
-1
|
||||
),
|
||||
'disable-anti-aliasing': GObject.ParamSpec.boolean(
|
||||
'disable-anti-aliasing',
|
||||
'Disable anti-aliasing',
|
||||
'Disable anti-aliasing for the effect',
|
||||
GObject.ParamFlags.READWRITE,
|
||||
false
|
||||
)
|
||||
}
|
||||
}, class VirtualDisplaysActor extends Clutter.Actor {
|
||||
constructor(params = {}) {
|
||||
super(params);
|
||||
|
||||
this._all_monitors = [
|
||||
this.target_monitor,
|
||||
...this.virtual_monitors
|
||||
]
|
||||
|
||||
const bannerTextureClippingRect = new Mtk.Rectangle({
|
||||
x: 0,
|
||||
y: 0,
|
||||
width: 800,
|
||||
height: 200
|
||||
});
|
||||
|
||||
const calibratingBanner = GdkPixbuf.Pixbuf.new_from_file(`${Globals.extension_dir}/textures/calibrating.png`);
|
||||
const calibratingImage = new Clutter.Image();
|
||||
calibratingImage.set_data(calibratingBanner.get_pixels(), Cogl.PixelFormat.RGB_888,
|
||||
calibratingBanner.width, calibratingBanner.height, calibratingBanner.rowstride);
|
||||
this.bannerContent = Clutter.TextureContent.new_from_texture(calibratingImage.get_texture(), bannerTextureClippingRect);
|
||||
|
||||
const customBanner = GdkPixbuf.Pixbuf.new_from_file(`${Globals.extension_dir}/textures/custom_banner.png`);
|
||||
const customBannerImage = new Clutter.Image();
|
||||
customBannerImage.set_data(customBanner.get_pixels(), Cogl.PixelFormat.RGB_888,
|
||||
customBanner.width, customBanner.height, customBanner.rowstride);
|
||||
this.customBannerContent = Clutter.TextureContent.new_from_texture(customBannerImage.get_texture(), bannerTextureClippingRect);
|
||||
|
||||
this.bannerActor = new Clutter.Actor({
|
||||
width: calibratingBanner.width,
|
||||
height: calibratingBanner.height,
|
||||
reactive: false
|
||||
});
|
||||
this.bannerActor.set_position(
|
||||
(this.target_monitor.width - this.bannerActor.width) / 2,
|
||||
this.target_monitor.height * 0.75 - this.bannerActor.height / 2
|
||||
);
|
||||
this.bannerActor.set_content(this.custom_banner_enabled ? this.customBannerContent : this.bannerContent);
|
||||
this.bannerActor.hide();
|
||||
|
||||
this.monitor_actors = [];
|
||||
}
|
||||
|
||||
renderMonitors() {
|
||||
// collect bindings and connections to clean up on dispose
|
||||
this._property_bindings = [];
|
||||
this._property_connections = [];
|
||||
|
||||
const notifyToFunction = ((property, fn) => {
|
||||
this._property_connections.push(this.connect(`notify::${property}`, fn.bind(this)));
|
||||
}).bind(this);
|
||||
|
||||
this._distance_ease_timeline = null;
|
||||
notifyToFunction('toggle-display-distance-start', this._handle_display_distance_properties_change);
|
||||
notifyToFunction('toggle-display-distance-end', this._handle_display_distance_properties_change);
|
||||
notifyToFunction('display-distance', this._handle_display_distance_properties_change);
|
||||
notifyToFunction('monitor-wrapping-scheme', this._update_monitor_placements);
|
||||
notifyToFunction('monitor-spacing', this._update_monitor_placements);
|
||||
notifyToFunction('viewport-offset-x', this._update_monitor_placements);
|
||||
notifyToFunction('viewport-offset-y', this._update_monitor_placements);
|
||||
notifyToFunction('show-banner', this._handle_banner_update);
|
||||
notifyToFunction('custom-banner-enabled', this._handle_banner_update);
|
||||
notifyToFunction('framerate-cap', this._handle_frame_rate_cap_change);
|
||||
notifyToFunction('smooth-follow-enabled', this._handle_smooth_follow_enabled_change);
|
||||
this._handle_display_distance_properties_change();
|
||||
this._handle_frame_rate_cap_change();
|
||||
|
||||
const actorToDisplayRatios = [
|
||||
global.stage.width / this.target_monitor.width,
|
||||
global.stage.height / this.target_monitor.height
|
||||
];
|
||||
|
||||
// how far this viewport actor's center is from the center of the whole stage
|
||||
const actorMidX = this.target_monitor.x + this.target_monitor.width / 2;
|
||||
const actorMidY = this.target_monitor.y + this.target_monitor.height / 2;
|
||||
const actorToDisplayOffsets = [
|
||||
(global.stage.width / 2 - (actorMidX - global.stage.x)) * 2 / this.target_monitor.width,
|
||||
(global.stage.height / 2 - (actorMidY - global.stage.y)) * 2 / this.target_monitor.height
|
||||
];
|
||||
|
||||
Globals.logger.log_debug(`\t\t\tActor to display ratios: ${actorToDisplayRatios}, offsets: ${actorToDisplayOffsets}`);
|
||||
|
||||
this._sorted_monitors.forEach(((monitor, index) => {
|
||||
Globals.logger.log_debug(`\t\t\tMonitor ${index}: ${monitor.x}, ${monitor.y}, ${monitor.width}, ${monitor.height}`);
|
||||
|
||||
const containerActor = new Clutter.Actor({
|
||||
clip_to_allocation: true
|
||||
});
|
||||
const viewport = new St.Bin({
|
||||
child: containerActor,
|
||||
width: monitor.width,
|
||||
height: monitor.height
|
||||
});
|
||||
|
||||
// Create a clone of the stage content for this monitor
|
||||
const monitorClone = new Clutter.Clone({
|
||||
source: Main.layoutManager.uiGroup,
|
||||
clip_to_allocation: true,
|
||||
x: -monitor.x,
|
||||
y: -monitor.y
|
||||
});
|
||||
|
||||
// Add the monitor actor to the scene
|
||||
containerActor.add_child(monitorClone);
|
||||
const effect = new VirtualDisplayEffect({
|
||||
focused_monitor_index: this.focused_monitor_index,
|
||||
imu_snapshots: this.imu_snapshots,
|
||||
monitor_index: index,
|
||||
monitor_placements: this.monitor_placements,
|
||||
target_monitor: this.target_monitor,
|
||||
display_distance: this.display_distance,
|
||||
display_distance_default: this._display_distance_default(),
|
||||
actor_to_display_ratios: actorToDisplayRatios,
|
||||
actor_to_display_offsets: actorToDisplayOffsets,
|
||||
lens_vector: this.lens_vector,
|
||||
show_banner: this.show_banner
|
||||
});
|
||||
viewport.add_effect_with_name('viewport-effect', effect);
|
||||
this.add_child(viewport);
|
||||
Shell.util_set_hidden_from_pick(viewport, true);
|
||||
|
||||
this.monitor_actors.push({
|
||||
viewport,
|
||||
containerActor,
|
||||
monitorClone,
|
||||
effect,
|
||||
monitorDetails: monitor
|
||||
});
|
||||
|
||||
// do this so the primary monitor is always on top at first, before the focused monitor logic comes into play
|
||||
this.set_child_below_sibling(viewport, null);
|
||||
|
||||
[
|
||||
'monitor-placements',
|
||||
'imu-snapshots',
|
||||
'smooth-follow-enabled',
|
||||
'smooth-follow-toggle-epoch-ms',
|
||||
'focused-monitor-index',
|
||||
'lens-vector',
|
||||
'look-ahead-override',
|
||||
'disable-anti-aliasing',
|
||||
'show-banner'
|
||||
].forEach((property => {
|
||||
this._property_bindings.push(this.bind_property(property, effect, property, GObject.BindingFlags.DEFAULT));
|
||||
}));
|
||||
|
||||
const updateEffectDistanceDefault = (() => {
|
||||
effect.no_distance_ease = Math.abs(this.display_distance - effect.display_distance) <= 0.05;
|
||||
effect.display_distance = this.display_distance;
|
||||
effect.display_distance_default = this._display_distance_default();
|
||||
}).bind(this);
|
||||
this._property_connections.push(this.connect('notify::display-distance', updateEffectDistanceDefault));
|
||||
this._property_connections.push(this.connect('notify::toggle-display-distance-start', updateEffectDistanceDefault));
|
||||
this._property_connections.push(this.connect('notify::toggle-display-distance-end', updateEffectDistanceDefault));
|
||||
|
||||
// in addition to rendering distance properly in the shader, the parent actor determines overlap based on child ordering
|
||||
effect.connect('notify::is-closest', ((actor, _pspec) => {
|
||||
if (!this._is_disposed && actor.is_closest) {
|
||||
this.set_child_above_sibling(viewport, null);
|
||||
if (this.show_banner) this.set_child_above_sibling(this.bannerActor, null);
|
||||
}
|
||||
}).bind(this));
|
||||
}).bind(this));
|
||||
|
||||
this.add_child(this.bannerActor);
|
||||
if (this.show_banner) {
|
||||
this.set_child_above_sibling(this.bannerActor, null);
|
||||
this.bannerActor.show();
|
||||
}
|
||||
|
||||
GLib.timeout_add(GLib.PRIORITY_DEFAULT, 250, (() => {
|
||||
if (this._is_disposed) return GLib.SOURCE_REMOVE;
|
||||
|
||||
if (this.show_banner) {
|
||||
this.focused_monitor_index = -1;
|
||||
this.focused_monitor_details = null;
|
||||
} else if (this.imu_snapshots && (!this._smooth_follow_slerping || this.focused_monitor_index === -1)) {
|
||||
// if smooth follow is enabled, use the origin IMU data to inform the initial focused monitor
|
||||
// since it reflects where the user is looking in relation to the original monitor positions
|
||||
const currentPoseQuat = this.smooth_follow_enabled ?
|
||||
this.imu_snapshots.smooth_follow_origin.splice(0, 4) :
|
||||
this.imu_snapshots.imu_data.splice(0, 4);
|
||||
|
||||
const focusedMonitorIndex = findFocusedMonitor(
|
||||
currentPoseQuat,
|
||||
this._monitorsAsNormalizedVectors,
|
||||
this.focused_monitor_index,
|
||||
this.display_distance / this._display_distance_default(),
|
||||
this.smooth_follow_enabled,
|
||||
this._fov_details(),
|
||||
this._sorted_monitors
|
||||
);
|
||||
|
||||
if (this.focused_monitor_index !== focusedMonitorIndex) {
|
||||
Globals.logger.log_debug(`Switching to monitor ${focusedMonitorIndex}`);
|
||||
this.focused_monitor_index = focusedMonitorIndex;
|
||||
this.focused_monitor_details = this._sorted_monitors[focusedMonitorIndex];
|
||||
}
|
||||
}
|
||||
|
||||
return GLib.SOURCE_CONTINUE;
|
||||
}).bind(this));
|
||||
|
||||
this._redraw_timeline = Clutter.Timeline.new_for_actor(global.stage, 1000);
|
||||
this._redraw_timeline.connect('new-frame', (() => {
|
||||
// let's try to cap the forced redraw rate
|
||||
if (this._is_disposed || this._last_redraw !== undefined && Date.now() - this._last_redraw < this._cap_frametime_ms) return;
|
||||
|
||||
Globals.data_stream.refresh_data();
|
||||
this.imu_snapshots = Globals.data_stream.imu_snapshots;
|
||||
this.monitor_actors.forEach(({ monitorClone }) => monitorClone.queue_redraw());
|
||||
this._last_redraw = Date.now();
|
||||
}).bind(this));
|
||||
this._redraw_timeline.set_repeat_count(-1);
|
||||
this._redraw_timeline.start();
|
||||
}
|
||||
|
||||
_display_distance_default() {
|
||||
return Math.max(this.display_distance, this.toggle_display_distance_start, this.toggle_display_distance_end);
|
||||
}
|
||||
|
||||
_fov_details() {
|
||||
const aspect = this.target_monitor.width / this.target_monitor.height;
|
||||
const fovRadians = diagonalToCrossFOVs(degreeToRadian(Globals.data_stream.device_data.displayFov), aspect);
|
||||
const defaultDistanceVerticalRadians = 2 * Math.atan(Math.tan(fovRadians.vertical / 2) / this._display_distance_default());
|
||||
const defaultDistanceHorizontalRadians = 2 * Math.atan(Math.tan(fovRadians.horizontal / 2) / this._display_distance_default());
|
||||
|
||||
// distance needed for the FOV-sized monitor to fill up the screen
|
||||
const fullScreenDistance = this.target_monitor.height / 2 / Math.tan(fovRadians.vertical / 2);
|
||||
const lensDistancePixels = fullScreenDistance / (1.0 - Globals.data_stream.device_data.lensDistanceRatio) - fullScreenDistance;
|
||||
|
||||
// distance of a display at the default (most zoomed out) distance, plus the lens distance constant
|
||||
const lensToScreenDistance = this.target_monitor.height / 2 / Math.tan(defaultDistanceVerticalRadians / 2);
|
||||
const completeScreenDistancePixels = lensToScreenDistance + lensDistancePixels;
|
||||
|
||||
return {
|
||||
widthPixels: this.target_monitor.width,
|
||||
heightPixels: this.target_monitor.height,
|
||||
defaultDistanceVerticalRadians,
|
||||
defaultDistanceHorizontalRadians,
|
||||
lensDistancePixels,
|
||||
completeScreenDistancePixels
|
||||
};
|
||||
}
|
||||
|
||||
_horizontal_monitor_sort() {
|
||||
return [...this._all_monitors].sort((a, b) => {
|
||||
// First compare by y-coordinate to form rows (top to bottom)
|
||||
if (a.y !== b.y) {
|
||||
return a.y - b.y;
|
||||
}
|
||||
// Then compare by x-coordinate within the same row (left to right)
|
||||
return a.x - b.x;
|
||||
});
|
||||
}
|
||||
|
||||
_vertical_monitor_sort() {
|
||||
return [...this._all_monitors].sort((a, b) => {
|
||||
// First compare by x-coordinate to form columns (left to right)
|
||||
if (a.x !== b.x) {
|
||||
return a.x - b.x;
|
||||
}
|
||||
// Then compare by y-coordinate within the same column (top to bottom)
|
||||
return a.y - b.y;
|
||||
});
|
||||
}
|
||||
|
||||
_update_monitor_placements() {
|
||||
// collect minimum and maximum x and y values of monitors
|
||||
let actualWrapScheme = this.monitor_wrapping_scheme;
|
||||
if (actualWrapScheme === 'automatic') {
|
||||
const minX = Math.min(...this._all_monitors.map(monitor => monitor.x));
|
||||
const minY = Math.min(...this._all_monitors.map(monitor => monitor.y));
|
||||
const maxX = Math.max(...this._all_monitors.map(monitor => monitor.x + monitor.width));
|
||||
const maxY = Math.max(...this._all_monitors.map(monitor => monitor.y + monitor.height));
|
||||
|
||||
// check if there are more monitors in the horizontal or vertical direction, prefer horizontal if equal
|
||||
if ((maxX - minX) / this.target_monitor.width >= (maxY - minY) / this.target_monitor.height) {
|
||||
actualWrapScheme = 'horizontal';
|
||||
} else {
|
||||
actualWrapScheme = 'vertical';
|
||||
}
|
||||
}
|
||||
|
||||
// use horizontal in all cases but vertical wrapping
|
||||
this._sorted_monitors = actualWrapScheme === 'vertical' ?
|
||||
this._vertical_monitor_sort() :
|
||||
this._horizontal_monitor_sort();
|
||||
|
||||
const fovDetails = this._fov_details();
|
||||
this.lens_vector = [0.0, 0.0, -fovDetails.lensDistancePixels];
|
||||
this.monitor_placements = monitorsToPlacements(
|
||||
fovDetails,
|
||||
|
||||
// shift all monitors so they center around the target monitor, then adjusted by the offsets
|
||||
this._sorted_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
|
||||
})),
|
||||
actualWrapScheme,
|
||||
this.monitor_spacing / 1000.0
|
||||
);
|
||||
|
||||
// normalize the center vectors
|
||||
this._monitorsAsNormalizedVectors = this.monitor_placements.map(monitorVectors => {
|
||||
const vector = monitorVectors.centerLook;
|
||||
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);
|
||||
const distance_from_start = Math.abs(this.display_distance - this.toggle_display_distance_start);
|
||||
this._is_display_distance_at_end = distance_from_end < distance_from_start;
|
||||
this._update_monitor_placements();
|
||||
}
|
||||
|
||||
_handle_banner_update() {
|
||||
if (this.show_banner) {
|
||||
this.bannerActor.set_content(this.custom_banner_enabled ? this.customBannerContent : this.bannerContent);
|
||||
this.bannerActor.show();
|
||||
} else {
|
||||
this.bannerActor.hide();
|
||||
}
|
||||
}
|
||||
|
||||
_handle_frame_rate_cap_change() {
|
||||
// add a margin to the cap time so we don't cut off frames that come in close
|
||||
const frametime_margin = 0.75;
|
||||
this._cap_frametime_ms = this.framerate_cap === 0 ? 0.0 : Math.floor(1000 * frametime_margin / this.framerate_cap);
|
||||
}
|
||||
|
||||
_handle_smooth_follow_enabled_change() {
|
||||
if (this._smooth_follow_timeout_id !== undefined) GLib.source_remove(this._smooth_follow_timeout_id);
|
||||
|
||||
this._smooth_follow_slerping = true;
|
||||
this._smooth_follow_timeout_id = GLib.timeout_add(GLib.PRIORITY_DEFAULT, SMOOTH_FOLLOW_SLERP_TIMELINE_MS, (() => {
|
||||
this._smooth_follow_slerping = false;
|
||||
this._smooth_follow_timeout_id = undefined;
|
||||
return GLib.SOURCE_REMOVE;
|
||||
}).bind(this));
|
||||
}
|
||||
|
||||
_change_distance() {
|
||||
this.display_distance = this._is_display_distance_at_end ?
|
||||
this.toggle_display_distance_start : this.toggle_display_distance_end;
|
||||
}
|
||||
|
||||
vfunc_dispose() {
|
||||
Globals.logger.log_debug(`Disposing VirtualMonitorsActor`);
|
||||
this._is_disposed = true;
|
||||
|
||||
if (this._redraw_timeline) {
|
||||
this._redraw_timeline.stop();
|
||||
this._redraw_timeline = null;
|
||||
}
|
||||
|
||||
this.monitor_actors.forEach(({ viewport, containerActor, monitorClone, effect }) => {
|
||||
viewport.remove_effect(effect);
|
||||
containerActor.remove_child(monitorClone);
|
||||
viewport.remove_child(containerActor);
|
||||
this.remove_child(viewport);
|
||||
});
|
||||
this.monitor_actors = [];
|
||||
|
||||
this._property_bindings.forEach(binding => binding.unbind());
|
||||
this._property_bindings = [];
|
||||
|
||||
this._property_connections.forEach(connection => this.disconnect(connection));
|
||||
}
|
||||
});
|
||||
|
|
@ -1,453 +0,0 @@
|
|||
import Clutter from 'gi://Clutter';
|
||||
import Cogl from 'gi://Cogl';
|
||||
import GdkPixbuf from 'gi://GdkPixbuf';
|
||||
import GLib from 'gi://GLib';
|
||||
import GObject from 'gi://GObject';
|
||||
import Shell from 'gi://Shell';
|
||||
|
||||
import Globals from './globals.js';
|
||||
|
||||
import {
|
||||
dataViewEnd,
|
||||
dataViewUint8,
|
||||
dataViewBigUint,
|
||||
dataViewUint32Array,
|
||||
dataViewUint8Array,
|
||||
dataViewFloat,
|
||||
dataViewFloatArray,
|
||||
BOOL_SIZE,
|
||||
DATA_VIEW_INFO_COUNT_INDEX,
|
||||
DATA_VIEW_INFO_OFFSET_INDEX,
|
||||
FLOAT_SIZE,
|
||||
UINT_SIZE,
|
||||
UINT8_SIZE
|
||||
} from "./ipc.js";
|
||||
import { degreeToRadian } from "./math.js";
|
||||
import { getShaderSource } from "./shader.js";
|
||||
import { isValidKeepAlive, toSec } from "./time.js";
|
||||
|
||||
export const IPC_FILE_PATH = "/dev/shm/breezy_desktop_imu";
|
||||
|
||||
// the driver should be using the same data layout version
|
||||
const DATA_LAYOUT_VERSION = 3;
|
||||
|
||||
// DataView info: [offset, size, count]
|
||||
const VERSION = [0, UINT8_SIZE, 1];
|
||||
const ENABLED = [dataViewEnd(VERSION), BOOL_SIZE, 1];
|
||||
const LOOK_AHEAD_CFG = [dataViewEnd(ENABLED), FLOAT_SIZE, 4];
|
||||
const DISPLAY_RES = [dataViewEnd(LOOK_AHEAD_CFG), UINT_SIZE, 2];
|
||||
const DISPLAY_FOV = [dataViewEnd(DISPLAY_RES), FLOAT_SIZE, 1];
|
||||
const LENS_DISTANCE_RATIO = [dataViewEnd(DISPLAY_FOV), FLOAT_SIZE, 1];
|
||||
const SBS_ENABLED = [dataViewEnd(LENS_DISTANCE_RATIO), BOOL_SIZE, 1];
|
||||
const CUSTOM_BANNER_ENABLED = [dataViewEnd(SBS_ENABLED), BOOL_SIZE, 1];
|
||||
const EPOCH_MS = [dataViewEnd(CUSTOM_BANNER_ENABLED), UINT_SIZE, 2];
|
||||
const IMU_QUAT_DATA = [dataViewEnd(EPOCH_MS), FLOAT_SIZE, 16];
|
||||
const IMU_PARITY_BYTE = [dataViewEnd(IMU_QUAT_DATA), UINT8_SIZE, 1];
|
||||
const DATA_VIEW_LENGTH = dataViewEnd(IMU_PARITY_BYTE);
|
||||
|
||||
// cached after first retrieval
|
||||
const shaderUniformLocations = {
|
||||
'virtual_display_enabled': null,
|
||||
'show_banner': null,
|
||||
'imu_quat_data': null,
|
||||
'look_ahead_cfg': null,
|
||||
'look_ahead_ms': null,
|
||||
'trim_percent': null,
|
||||
'display_size': null,
|
||||
'display_north_offset': null,
|
||||
'lens_vector': null,
|
||||
'lens_vector_r': null, // only used if sbs_enabled is true
|
||||
'texcoord_x_limits': null, // index 0: min; index 1: max
|
||||
'texcoord_x_limits_r': null, // only used if sbs_enabled is true
|
||||
'sbs_enabled': null,
|
||||
'custom_banner_enabled': null,
|
||||
'half_fov_z_rads': null,
|
||||
'half_fov_y_rads': null,
|
||||
'fov_half_widths': null,
|
||||
'fov_widths': null,
|
||||
'display_resolution': null,
|
||||
'source_to_display_ratio': null,
|
||||
'curved_display': null,
|
||||
|
||||
// only used by the reshade integration, but needs to be set to a default value by this effect
|
||||
'frametime': null,
|
||||
'sideview_enabled': null,
|
||||
'sideview_position': null,
|
||||
'sideview_display_size': null
|
||||
};
|
||||
|
||||
function setUniformFloat(effect, locationName, dataViewInfo, value) {
|
||||
effect.set_uniform_float(shaderUniformLocations[locationName], dataViewInfo[DATA_VIEW_INFO_COUNT_INDEX], value);
|
||||
}
|
||||
|
||||
function transferUniformFloat(effect, locationName, dataView, dataViewInfo) {
|
||||
setUniformFloat(effect, locationName, dataViewInfo, dataViewFloatArray(dataView, dataViewInfo));
|
||||
}
|
||||
|
||||
function setSingleFloat(effect, locationName, value) {
|
||||
effect.set_uniform_float(shaderUniformLocations[locationName], 1, [value]);
|
||||
}
|
||||
|
||||
function setUniformMatrix(effect, locationName, components, dataView, dataViewInfo) {
|
||||
const numValues = dataViewInfo[DATA_VIEW_INFO_COUNT_INDEX];
|
||||
if (numValues / components !== components) {
|
||||
throw new Error('Invalid matrix size');
|
||||
}
|
||||
|
||||
const floatArray = [].fill(0, 0, numValues);
|
||||
let offset = dataViewInfo[DATA_VIEW_INFO_OFFSET_INDEX];
|
||||
for (let i = 0; i < numValues; i++) {
|
||||
// GLSL uses column-major order, so we need to transpose the matrix
|
||||
const row = i % components;
|
||||
const column = Math.floor(i / components);
|
||||
|
||||
floatArray[row * components + column] = dataView.getFloat32(offset, true);
|
||||
offset += FLOAT_SIZE;
|
||||
}
|
||||
effect.set_uniform_matrix(shaderUniformLocations[locationName], true, components, floatArray);
|
||||
}
|
||||
|
||||
function lookAheadMS(dataView) {
|
||||
const lookAheadCfg = dataViewFloatArray(dataView, LOOK_AHEAD_CFG);
|
||||
const imuDateMS = dataViewBigUint(dataView, EPOCH_MS);
|
||||
|
||||
// how stale the imu data is
|
||||
const dataAge = Date.now() - imuDateMS;
|
||||
|
||||
return lookAheadCfg[0] + dataAge;
|
||||
}
|
||||
|
||||
// most uniforms don't change frequently, this function should be called periodically
|
||||
function setIntermittentUniformVariables() {
|
||||
try {
|
||||
const dataView = this._dataView;
|
||||
|
||||
if (dataView.byteLength === DATA_VIEW_LENGTH) {
|
||||
const version = dataViewUint8(dataView, VERSION);
|
||||
const imuDateMs = dataViewBigUint(dataView, EPOCH_MS);
|
||||
const validKeepalive = isValidKeepAlive(toSec(imuDateMs));
|
||||
const imuData = dataViewFloatArray(dataView, IMU_QUAT_DATA);
|
||||
const imuResetState = validKeepalive && imuData[0] === 0.0 && imuData[1] === 0.0 && imuData[2] === 0.0 && imuData[3] === 1.0;
|
||||
const enabled = dataViewUint8(dataView, ENABLED) !== 0 && version === DATA_LAYOUT_VERSION && validKeepalive;
|
||||
const displayRes = dataViewUint32Array(dataView, DISPLAY_RES);
|
||||
const sbsEnabled = dataViewUint8(dataView, SBS_ENABLED) !== 0;
|
||||
|
||||
if (enabled) {
|
||||
const displayFov = dataViewFloat(dataView, DISPLAY_FOV);
|
||||
|
||||
// TODO - drive these values from settings
|
||||
const sbsContent = false;
|
||||
const sbsModeStretched = true;
|
||||
|
||||
// compute these values once, they only change when the XR device changes
|
||||
const displayAspectRatio = displayRes[0] / displayRes[1];
|
||||
const diagToVertRatio = Math.sqrt(Math.pow(displayAspectRatio, 2) + 1);
|
||||
const halfFovZRads = degreeToRadian(displayFov / diagToVertRatio) / 2;
|
||||
const halfFovYRads = halfFovZRads * displayAspectRatio;
|
||||
const fovHalfWidths = [Math.tan(halfFovYRads), Math.tan(halfFovZRads)];
|
||||
const fovWidths = [fovHalfWidths[0] * 2, fovHalfWidths[1] * 2];
|
||||
const lensDistanceRatio = dataViewFloat(dataView, LENS_DISTANCE_RATIO);
|
||||
let lensFromCenter = 0.0;
|
||||
let texcoordXLimits = [0.0, 1.0];
|
||||
let texcoordXLimitsRight = [0.0, 1.0];
|
||||
if (sbsEnabled) {
|
||||
lensFromCenter = lensDistanceRatio / 3.0;
|
||||
if (sbsContent) {
|
||||
texcoordXLimits[1] = 0.5;
|
||||
texcoordXLimitsRight[0] = 0.5;
|
||||
if (!sbsModeStretched) {
|
||||
texcoordXLimits[0] = 0.25;
|
||||
texcoordXLimitsRight[1] = 0.75;
|
||||
}
|
||||
} else if (!sbsModeStretched) {
|
||||
texcoordXLimits[0] = 0.25;
|
||||
texcoordXLimits[1] = 0.75;
|
||||
texcoordXLimitsRight[0] = 0.25;
|
||||
texcoordXLimitsRight[1] = 0.75;
|
||||
}
|
||||
}
|
||||
const lensVector = [lensDistanceRatio, lensFromCenter, 0.0];
|
||||
const lensVectorRight = [lensDistanceRatio, -lensFromCenter, 0.0];
|
||||
|
||||
// our overlay doesn't quite cover the full screen texture, which allows us to see some of the real desktop
|
||||
// underneath, so we trim three pixels around the entire edge of the texture
|
||||
const trimWidthPercent = 3.0 / this.target_monitor.width;
|
||||
const trimHeightPercent = 3.0 / this.target_monitor.height;
|
||||
|
||||
// all these values are transferred directly, unmodified from the driver
|
||||
transferUniformFloat(this, 'look_ahead_cfg', dataView, LOOK_AHEAD_CFG);
|
||||
transferUniformFloat(this, 'lens_distance_ratio', dataView, LENS_DISTANCE_RATIO);
|
||||
|
||||
// computed values with no dataViewInfo, so we set these manually
|
||||
this.set_uniform_float(shaderUniformLocations['trim_percent'], 2, [trimWidthPercent, trimHeightPercent]);
|
||||
setSingleFloat(this, 'half_fov_z_rads', halfFovZRads);
|
||||
setSingleFloat(this, 'half_fov_y_rads', halfFovYRads);
|
||||
this.set_uniform_float(shaderUniformLocations['fov_half_widths'], 2, fovHalfWidths);
|
||||
this.set_uniform_float(shaderUniformLocations['fov_widths'], 2, fovWidths);
|
||||
setSingleFloat(this, 'curved_display', this.curved_display ? 1.0 : 0.0);
|
||||
this.set_uniform_float(shaderUniformLocations['texcoord_x_limits'], 2, texcoordXLimits);
|
||||
this.set_uniform_float(shaderUniformLocations['texcoord_x_limits_r'], 2, texcoordXLimitsRight);
|
||||
this.set_uniform_float(shaderUniformLocations['lens_vector'], 3, lensVector);
|
||||
this.set_uniform_float(shaderUniformLocations['lens_vector_r'], 3, lensVectorRight);
|
||||
}
|
||||
|
||||
// update the supported device detected property if the state changes, trigger "notify::" events
|
||||
if (this.supported_device_detected !== validKeepalive) this.supported_device_detected = validKeepalive;
|
||||
|
||||
// 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;
|
||||
|
||||
// these variables are always in play, even if enabled is false
|
||||
setSingleFloat(this, 'virtual_display_enabled', enabled ? 1.0 : 0.0);
|
||||
setSingleFloat(this, 'show_banner', imuResetState ? 1.0 : 0.0);
|
||||
setSingleFloat(this, 'sbs_enabled', sbsEnabled ? 1.0 : 0.0);
|
||||
setSingleFloat(this, 'custom_banner_enabled', dataViewUint8(dataView, CUSTOM_BANNER_ENABLED) !== 0 ? 1.0 : 0.0);
|
||||
setSingleFloat(this, 'frametime', 0.0);
|
||||
|
||||
setSingleFloat(this, 'sideview_enabled', 0.0);
|
||||
setSingleFloat(this, 'sideview_position', 0.0);
|
||||
setSingleFloat(this, 'sideview_display_size', 1.0);
|
||||
|
||||
this.set_uniform_float(shaderUniformLocations['display_resolution'], 2, displayRes);
|
||||
this.set_uniform_float(shaderUniformLocations['source_to_display_ratio'], 2, [this.target_monitor.width/displayRes[0], this.target_monitor.height/displayRes[1]]);
|
||||
} else if (dataView.byteLength !== 0) {
|
||||
throw new Error(`Invalid dataView.byteLength: ${dataView.byteLength} !== ${DATA_VIEW_LENGTH}`);
|
||||
}
|
||||
} catch (e) {
|
||||
Globals.logger.log(`[ERROR] xrEffect.js setIntermittentUniformVariables ${e.message}\n${e.stack}`);
|
||||
}
|
||||
}
|
||||
|
||||
function checkParityByte(dataView) {
|
||||
const parityByte = dataViewUint8(dataView, IMU_PARITY_BYTE);
|
||||
let parity = 0;
|
||||
const epochUint8 = dataViewUint8Array(dataView, EPOCH_MS);
|
||||
const imuDataUint8 = dataViewUint8Array(dataView, IMU_QUAT_DATA);
|
||||
for (let i = 0; i < epochUint8.length; i++) {
|
||||
parity ^= epochUint8[i];
|
||||
}
|
||||
for (let i = 0; i < imuDataUint8.length; i++) {
|
||||
parity ^= imuDataUint8[i];
|
||||
}
|
||||
return parityByte === parity;
|
||||
}
|
||||
|
||||
export const XREffect = GObject.registerClass({
|
||||
Properties: {
|
||||
'supported-device-detected': GObject.ParamSpec.boolean(
|
||||
'supported-device-detected',
|
||||
'Supported device detected',
|
||||
'Whether a supported device is connected',
|
||||
GObject.ParamFlags.READWRITE,
|
||||
false
|
||||
),
|
||||
'target-monitor': GObject.ParamSpec.jsobject(
|
||||
'target-monitor',
|
||||
'Target Monitor',
|
||||
'Geometry of the target monitor for this effect',
|
||||
GObject.ParamFlags.READWRITE
|
||||
),
|
||||
'target-framerate': GObject.ParamSpec.uint(
|
||||
'target-framerate',
|
||||
'Target Framerate',
|
||||
'Target framerate for this effect',
|
||||
GObject.ParamFlags.READWRITE, 30, 240, 60
|
||||
),
|
||||
'display-distance': GObject.ParamSpec.double(
|
||||
'display-distance',
|
||||
'Display Distance',
|
||||
'How far away the display appears',
|
||||
GObject.ParamFlags.READWRITE,
|
||||
0.2,
|
||||
2.5,
|
||||
1.05
|
||||
),
|
||||
'display-size': GObject.ParamSpec.double(
|
||||
'display-size',
|
||||
'Display size',
|
||||
'Size of the display',
|
||||
GObject.ParamFlags.READWRITE,
|
||||
0.2,
|
||||
2.5,
|
||||
1.0
|
||||
),
|
||||
'toggle-display-distance-start': GObject.ParamSpec.double(
|
||||
'toggle-display-distance-start',
|
||||
'Display distance start',
|
||||
'Start distance when using the "change distance" shortcut.',
|
||||
GObject.ParamFlags.READWRITE,
|
||||
0.2,
|
||||
2.5,
|
||||
1.05
|
||||
),
|
||||
'toggle-display-distance-end': GObject.ParamSpec.double(
|
||||
'toggle-display-distance-end',
|
||||
'Display distance end',
|
||||
'End distance when using the "change distance" shortcut.',
|
||||
GObject.ParamFlags.READWRITE,
|
||||
0.2,
|
||||
2.5,
|
||||
1.05
|
||||
),
|
||||
'curved-display': GObject.ParamSpec.boolean(
|
||||
'curved-display',
|
||||
'Curved Display',
|
||||
'Whether the display is curved',
|
||||
GObject.ParamFlags.READWRITE,
|
||||
false
|
||||
),
|
||||
'widescreen-mode-state': GObject.ParamSpec.boolean(
|
||||
'widescreen-mode-state',
|
||||
'Widescreen mode state',
|
||||
'The state of widescreen mode from the perspective of the driver',
|
||||
GObject.ParamFlags.READWRITE,
|
||||
false
|
||||
),
|
||||
'look-ahead-override': GObject.ParamSpec.int(
|
||||
'look-ahead-override',
|
||||
'Look ahead override',
|
||||
'Override the look ahead value',
|
||||
GObject.ParamFlags.READWRITE,
|
||||
-1,
|
||||
45,
|
||||
-1
|
||||
),
|
||||
'disable-anti-aliasing': GObject.ParamSpec.boolean(
|
||||
'disable-anti-aliasing',
|
||||
'Disable anti-aliasing',
|
||||
'Disable anti-aliasing for the effect',
|
||||
GObject.ParamFlags.READWRITE,
|
||||
false
|
||||
)
|
||||
}
|
||||
}, class XREffect extends Shell.GLSLEffect {
|
||||
constructor(params = {}) {
|
||||
super(params);
|
||||
|
||||
this._distance_ease_timeline = null;
|
||||
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._handle_display_distance_properties_change();
|
||||
|
||||
const calibrating = GdkPixbuf.Pixbuf.new_from_file(`${Globals.extension_dir}/textures/calibrating.png`);
|
||||
this.calibratingImage = new Clutter.Image();
|
||||
this.calibratingImage.set_data(calibrating.get_pixels(), Cogl.PixelFormat.RGB_888,
|
||||
calibrating.width, calibrating.height, calibrating.rowstride);
|
||||
|
||||
const customBanner = GdkPixbuf.Pixbuf.new_from_file(`${Globals.extension_dir}/textures/custom_banner.png`);
|
||||
this.customBannerImage = new Clutter.Image();
|
||||
this.customBannerImage.set_data(customBanner.get_pixels(), Cogl.PixelFormat.RGB_888,
|
||||
customBanner.width, customBanner.height, customBanner.rowstride);
|
||||
}
|
||||
|
||||
_handle_display_distance_properties_change() {
|
||||
const distance_from_end = Math.abs(this.display_distance - this.toggle_display_distance_end);
|
||||
const distance_from_start = Math.abs(this.display_distance - this.toggle_display_distance_start);
|
||||
this._is_display_distance_at_end = distance_from_end < distance_from_start;
|
||||
}
|
||||
|
||||
_change_distance() {
|
||||
if (this._distance_ease_timeline?.is_playing()) this._distance_ease_timeline.stop();
|
||||
|
||||
this._distance_ease_start = this.display_distance;
|
||||
this._distance_ease_timeline = Clutter.Timeline.new_for_actor(this.get_actor(), 250);
|
||||
|
||||
const toggle_display_distance_target = this._is_display_distance_at_end ?
|
||||
this.toggle_display_distance_start : this.toggle_display_distance_end;
|
||||
this._distance_ease_timeline.connect('new-frame', () => {
|
||||
this.display_distance = this._distance_ease_start +
|
||||
this._distance_ease_timeline.get_progress() *
|
||||
(toggle_display_distance_target - this._distance_ease_start);
|
||||
});
|
||||
|
||||
this._distance_ease_timeline.start();
|
||||
}
|
||||
|
||||
vfunc_build_pipeline() {
|
||||
const code = getShaderSource(`${Globals.extension_dir}/Sombrero.frag`);
|
||||
const main = 'PS_Sombrero(virtual_display_enabled, false, source_to_display_ratio, show_banner, cogl_tex_coord_in[0].xy, cogl_color_out);';
|
||||
this.add_glsl_snippet(Shell.SnippetHook.FRAGMENT, code, main, false);
|
||||
}
|
||||
|
||||
vfunc_paint_target(node, paintContext) {
|
||||
var calibratingImage = this.calibratingImage;
|
||||
var customBannerImage = this.customBannerImage;
|
||||
let data = Globals.ipc_file.load_contents(null);
|
||||
if (data[0]) {
|
||||
let buffer = new Uint8Array(data[1]).buffer;
|
||||
this._dataView = new DataView(buffer);
|
||||
if (!this._initialized) {
|
||||
this.set_uniform_float(this.get_uniform_location('screenTexture'), 1, [0]);
|
||||
|
||||
this.get_pipeline().set_layer_texture(1, calibratingImage.get_texture());
|
||||
this.get_pipeline().set_layer_texture(2, customBannerImage.get_texture());
|
||||
this.get_pipeline().set_uniform_1i(this.get_uniform_location('calibratingTexture'), 1);
|
||||
this.get_pipeline().set_uniform_1i(this.get_uniform_location('customBannerTexture'), 2);
|
||||
|
||||
for (let key in shaderUniformLocations) {
|
||||
shaderUniformLocations[key] = this.get_uniform_location(key);
|
||||
}
|
||||
this.setIntermittentUniformVariables = setIntermittentUniformVariables.bind(this);
|
||||
this.setIntermittentUniformVariables();
|
||||
|
||||
this._redraw_timeline = Clutter.Timeline.new_for_actor(this.get_actor(), 1000);
|
||||
this._redraw_timeline.connect('new-frame', (() => {
|
||||
this.queue_repaint();
|
||||
}).bind(this));
|
||||
this._redraw_timeline.set_repeat_count(-1);
|
||||
this._redraw_timeline.start();
|
||||
|
||||
this._uniforms_timeout_id = GLib.timeout_add(GLib.PRIORITY_DEFAULT, 250, (() => {
|
||||
this.setIntermittentUniformVariables();
|
||||
return GLib.SOURCE_CONTINUE;
|
||||
}).bind(this));
|
||||
|
||||
this._initialized = true;
|
||||
}
|
||||
|
||||
let success = false;
|
||||
let attempts = 0;
|
||||
while (!success && attempts < 2) {
|
||||
if (this._dataView.byteLength === DATA_VIEW_LENGTH) {
|
||||
if (checkParityByte(this._dataView)) {
|
||||
setSingleFloat(this, 'display_north_offset', this.display_distance);
|
||||
setSingleFloat(this, 'look_ahead_ms',
|
||||
this.look_ahead_override === -1 ? lookAheadMS(this._dataView) : this.look_ahead_override);
|
||||
setUniformMatrix(this, 'imu_quat_data', 4, this._dataView, IMU_QUAT_DATA);
|
||||
setSingleFloat(this, 'display_size', this.display_size);
|
||||
success = true;
|
||||
}
|
||||
} else if (this._dataView.byteLength !== 0) {
|
||||
Globals.logger.log(`[ERROR] Invalid dataView.byteLength: ${this._dataView.byteLength} !== ${DATA_VIEW_LENGTH}`)
|
||||
}
|
||||
|
||||
if (!success && ++attempts < 3) {
|
||||
data = Globals.ipc_file.load_contents(null);
|
||||
if (data[0]) {
|
||||
buffer = new Uint8Array(data[1]).buffer;
|
||||
this._dataView = new DataView(buffer);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!this.disable_anti_aliasing) {
|
||||
// improves sampling quality for smooth text and edges
|
||||
this.get_pipeline().set_layer_filters(
|
||||
0,
|
||||
Cogl.PipelineFilter.LINEAR_MIPMAP_LINEAR,
|
||||
Cogl.PipelineFilter.LINEAR
|
||||
);
|
||||
}
|
||||
}
|
||||
super.vfunc_paint_target(node, paintContext);
|
||||
}
|
||||
|
||||
cleanup() {
|
||||
if (this._redraw_timeline) {
|
||||
this._redraw_timeline.stop();
|
||||
this._redraw_timeline = null;
|
||||
}
|
||||
if (this._uniforms_timeout_id) GLib.source_remove(this._uniforms_timeout_id);
|
||||
}
|
||||
});
|
||||
|
|
@ -1 +1 @@
|
|||
Subproject commit 53002afde8406eef7fe309206268ad6dc39e2da6
|
||||
Subproject commit a66c9aee82989ea7e98da5a05fde621ffb47af83
|
||||
|
|
@ -43,6 +43,7 @@ cp $UI_BUILD_PATH/src/breezydesktop.gresource $PACKAGE_BREEZY_DIR
|
|||
cp -r po/mo/* $PACKAGE_LOCALE_DIR
|
||||
cp data/com.xronlinux.BreezyDesktop.gschema.xml $PACKAGE_SCHEMAS_DIR
|
||||
cp $UI_BUILD_PATH/src/breezydesktop $PACKAGE_BIN_DIR
|
||||
cp $UI_BUILD_PATH/src/virtualdisplay $PACKAGE_BIN_DIR
|
||||
cp $UI_BUILD_PATH/data/com.xronlinux.BreezyDesktop.desktop $PACKAGE_APPS_DIR
|
||||
|
||||
mkdir -p $PACKAGE_ICONS_DIR/64x64/apps
|
||||
|
|
|
|||
|
|
@ -91,6 +91,42 @@
|
|||
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="monitor-spacing" type="i">
|
||||
<default>
|
||||
0
|
||||
</default>
|
||||
<summary>Monitor spacing</summary>
|
||||
<description>
|
||||
How far apart the monitors are visually (not logically)
|
||||
</description>
|
||||
</key>
|
||||
<key name="curved-display" type="b">
|
||||
<default>
|
||||
false
|
||||
|
|
@ -120,7 +156,7 @@
|
|||
</key>
|
||||
<key name="headset-as-primary" type="b">
|
||||
<default>
|
||||
true
|
||||
false
|
||||
</default>
|
||||
<summary>Headset as primary</summary>
|
||||
<description>
|
||||
|
|
@ -154,6 +190,15 @@
|
|||
Disable anti-aliasing
|
||||
</description>
|
||||
</key>
|
||||
<key name="disable-physical-displays" type="b">
|
||||
<default>
|
||||
true
|
||||
</default>
|
||||
<summary>Disable physical displays</summary>
|
||||
<description>
|
||||
Disable physical displays when XR effect is enabled
|
||||
</description>
|
||||
</key>
|
||||
<key name="developer-mode" type="b">
|
||||
<default>
|
||||
false
|
||||
|
|
@ -172,6 +217,15 @@
|
|||
Log debug messages
|
||||
</description>
|
||||
</key>
|
||||
<key name="debug-no-device" type="b">
|
||||
<default>
|
||||
false
|
||||
</default>
|
||||
<summary>Debug no device</summary>
|
||||
<description>
|
||||
Debug no device
|
||||
</description>
|
||||
</key>
|
||||
<key name="custom-monitor-product" type="s">
|
||||
<default>
|
||||
""
|
||||
|
|
@ -180,6 +234,15 @@
|
|||
<description>
|
||||
Custom monitor product
|
||||
</description>
|
||||
</key>
|
||||
<key name="framerate-cap" type="d">
|
||||
<default>
|
||||
0.0
|
||||
</default>
|
||||
<summary>Framerate cap</summary>
|
||||
<description>
|
||||
Framerate cap
|
||||
</description>
|
||||
</key>
|
||||
</schema>
|
||||
</schemalist>
|
||||
|
|
|
|||
|
|
@ -1 +1 @@
|
|||
Subproject commit c3b0ddab302e11e517b57b621ff334faf03173de
|
||||
Subproject commit b01239646d7ea6f78a823f591946855b880f0484
|
||||
|
|
@ -8,7 +8,7 @@ msgid ""
|
|||
msgstr ""
|
||||
"Project-Id-Version: PACKAGE VERSION\n"
|
||||
"Report-Msgid-Bugs-To: \n"
|
||||
"POT-Creation-Date: 2024-10-23 11:32-0700\n"
|
||||
"POT-Creation-Date: 2025-03-05 12:28-0800\n"
|
||||
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
|
||||
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
|
||||
"Language-Team: LANGUAGE <LL@li.org>\n"
|
||||
|
|
@ -17,16 +17,58 @@ msgstr ""
|
|||
"Content-Type: text/plain; charset=UTF-8\n"
|
||||
"Content-Transfer-Encoding: 8bit\n"
|
||||
|
||||
#: src/connecteddevice.py:17
|
||||
#: src/connecteddevice.py:23
|
||||
msgid ""
|
||||
"Switches your glasses into side-by-side mode and doubles the width of the "
|
||||
"display."
|
||||
msgstr ""
|
||||
|
||||
#: src/connecteddevice.py:18
|
||||
#: src/connecteddevice.py:24
|
||||
msgid "This feature is not currently supported for your device."
|
||||
msgstr ""
|
||||
|
||||
#: src/connecteddevice.py:124
|
||||
msgid "Set Focused Display Distance"
|
||||
msgstr ""
|
||||
|
||||
#: src/connecteddevice.py:125
|
||||
msgid "Use a closer value so the display zooms in when you look at it."
|
||||
msgstr ""
|
||||
|
||||
#: src/connecteddevice.py:132
|
||||
msgid "Set All Displays Distance"
|
||||
msgstr ""
|
||||
|
||||
#: src/connecteddevice.py:133
|
||||
msgid "Use a farther value so the displays are zoomed out when you look away."
|
||||
msgstr ""
|
||||
|
||||
#: src/connecteddevice.py:231
|
||||
msgid ""
|
||||
"Unable to add virtual displays on this machine. xdg-desktop-portal is "
|
||||
"required."
|
||||
msgstr ""
|
||||
|
||||
#: src/connecteddevice.py:265
|
||||
msgid "Focused display"
|
||||
msgstr ""
|
||||
|
||||
#: src/connecteddevice.py:271
|
||||
msgid "All displays"
|
||||
msgstr ""
|
||||
|
||||
#: src/displaydistancedialogcontent.py:41
|
||||
msgid "closer"
|
||||
msgstr ""
|
||||
|
||||
#: src/displaydistancedialogcontent.py:45
|
||||
msgid "fullscreen"
|
||||
msgstr ""
|
||||
|
||||
#: src/displaydistancedialogcontent.py:48
|
||||
msgid "farther"
|
||||
msgstr ""
|
||||
|
||||
#: src/licensedialogcontent.py:63
|
||||
msgid "Paid Tier Status"
|
||||
msgstr ""
|
||||
|
|
@ -35,7 +77,7 @@ msgstr ""
|
|||
msgid "Feature Availability"
|
||||
msgstr ""
|
||||
|
||||
#: src/licensefeaturerow.py:15 src/shortcutdialog.py:107
|
||||
#: src/licensefeaturerow.py:15 src/shortcutdialog.py:104
|
||||
msgid "Disabled"
|
||||
msgstr ""
|
||||
|
||||
|
|
@ -164,173 +206,235 @@ msgid "Enables the Breezy Desktop XR effect."
|
|||
msgstr ""
|
||||
|
||||
#: src/gtk/connected-device.ui:55
|
||||
msgid "Widescreen mode"
|
||||
msgid "Zoom on focus"
|
||||
msgstr ""
|
||||
|
||||
#: src/gtk/connected-device.ui:66
|
||||
#: src/gtk/connected-device.ui:56
|
||||
msgid ""
|
||||
"Automatically move a display closer when you look at it.\n"
|
||||
"Set your preferred focused and unfocused distances in the Adjustments "
|
||||
"section.\n"
|
||||
" "
|
||||
msgstr ""
|
||||
|
||||
#: src/gtk/connected-device.ui:69
|
||||
msgid "Follow mode"
|
||||
msgstr ""
|
||||
|
||||
#: src/gtk/connected-device.ui:67
|
||||
msgid "Keep the virtual display near the center of your view."
|
||||
#: src/gtk/connected-device.ui:70
|
||||
msgid "Keep the focused display near the center of your view."
|
||||
msgstr ""
|
||||
|
||||
#: src/gtk/connected-device.ui:77
|
||||
msgid "Curved display"
|
||||
#: src/gtk/connected-device.ui:80 src/gtk/no-device.ui:34
|
||||
msgid "Disable physical displays"
|
||||
msgstr ""
|
||||
|
||||
#: src/gtk/connected-device.ui:78
|
||||
msgid "Switch between flat and curved displays."
|
||||
#: src/gtk/connected-device.ui:81 src/gtk/no-device.ui:35
|
||||
msgid ""
|
||||
"Automatically disable all physical displays when the XR effect is enabled."
|
||||
msgstr ""
|
||||
|
||||
#: src/gtk/connected-device.ui:91
|
||||
msgid "Virtual displays"
|
||||
msgstr ""
|
||||
|
||||
#: src/gtk/connected-device.ui:103
|
||||
msgid "Rearrange displays"
|
||||
msgstr ""
|
||||
|
||||
#: src/gtk/connected-device.ui:115
|
||||
msgid "1080p"
|
||||
msgstr ""
|
||||
|
||||
#: src/gtk/connected-device.ui:116
|
||||
msgid "1440p"
|
||||
msgstr ""
|
||||
|
||||
#: src/gtk/connected-device.ui:140
|
||||
msgid "Adjustments"
|
||||
msgstr ""
|
||||
|
||||
#: src/gtk/connected-device.ui:94
|
||||
msgid "Display distance"
|
||||
#: src/gtk/connected-device.ui:143
|
||||
msgid "Display distances"
|
||||
msgstr ""
|
||||
|
||||
#: src/gtk/connected-device.ui:95
|
||||
msgid ""
|
||||
"Closer appears larger, further appears smaller. Controls depth when in "
|
||||
"widescreen mode."
|
||||
#: src/gtk/connected-device.ui:144
|
||||
msgid "Set how close you want displays to appear."
|
||||
msgstr ""
|
||||
|
||||
#: src/gtk/connected-device.ui:123
|
||||
msgid "Display size"
|
||||
msgstr ""
|
||||
|
||||
#: src/gtk/connected-device.ui:124
|
||||
msgid ""
|
||||
"Combine with display distance to achieve a comfortable level of depth and "
|
||||
"size."
|
||||
msgstr ""
|
||||
|
||||
#: src/gtk/connected-device.ui:152
|
||||
msgid "Display toggle distances"
|
||||
msgstr ""
|
||||
|
||||
#: src/gtk/connected-device.ui:153
|
||||
msgid ""
|
||||
"Use the buttons to capture the current display distance for use with the "
|
||||
"keyboard shortcut."
|
||||
msgstr ""
|
||||
|
||||
#: src/gtk/connected-device.ui:178
|
||||
#: src/gtk/connected-device.ui:199
|
||||
msgid "Follow threshold"
|
||||
msgstr ""
|
||||
|
||||
#: src/gtk/connected-device.ui:179
|
||||
#: src/gtk/connected-device.ui:200
|
||||
msgid "How far away you can look before the display follows."
|
||||
msgstr ""
|
||||
|
||||
#: src/gtk/connected-device.ui:209 src/gtk/connected-device.ui:215
|
||||
#: src/gtk/connected-device.ui:223
|
||||
msgid "Display angling"
|
||||
msgstr ""
|
||||
|
||||
#: src/gtk/connected-device.ui:224
|
||||
msgid ""
|
||||
"When there are multiple displays, choose how they should angle towards you."
|
||||
msgstr ""
|
||||
|
||||
#: src/gtk/connected-device.ui:238
|
||||
msgid "Automatic"
|
||||
msgstr ""
|
||||
|
||||
#: src/gtk/connected-device.ui:239
|
||||
msgid "Side-angled"
|
||||
msgstr ""
|
||||
|
||||
#: src/gtk/connected-device.ui:240
|
||||
msgid "Top-angled"
|
||||
msgstr ""
|
||||
|
||||
#: src/gtk/connected-device.ui:241
|
||||
msgid "Flat"
|
||||
msgstr ""
|
||||
|
||||
#: src/gtk/connected-device.ui:251
|
||||
msgid "Display spacing"
|
||||
msgstr ""
|
||||
|
||||
#: src/gtk/connected-device.ui:252
|
||||
msgid "Put empty space between displays, when there are multiple."
|
||||
msgstr ""
|
||||
|
||||
#: src/gtk/connected-device.ui:282
|
||||
msgid "Viewport horizontal offset"
|
||||
msgstr ""
|
||||
|
||||
#: src/gtk/connected-device.ui:283
|
||||
msgid ""
|
||||
"By default, the viewport will center on the primary display. Use this slider "
|
||||
"to move the viewport to the left or right."
|
||||
msgstr ""
|
||||
|
||||
#: src/gtk/connected-device.ui:312
|
||||
msgid "Viewport vertical offset"
|
||||
msgstr ""
|
||||
|
||||
#: src/gtk/connected-device.ui:313
|
||||
msgid ""
|
||||
"By default, the viewport will center on the primary display. Use this slider "
|
||||
"to move the viewport up or down."
|
||||
msgstr ""
|
||||
|
||||
#: src/gtk/connected-device.ui:349 src/gtk/connected-device.ui:355
|
||||
msgid "Keyboard Shortcuts"
|
||||
msgstr ""
|
||||
|
||||
#: src/gtk/connected-device.ui:218
|
||||
#: src/gtk/connected-device.ui:358
|
||||
msgid "XR Effect on/off shortcut"
|
||||
msgstr ""
|
||||
|
||||
#: src/gtk/connected-device.ui:219
|
||||
#: src/gtk/connected-device.ui:359
|
||||
msgid ""
|
||||
"Quickly enable or disable the XR Effect. You may need to enable the effect "
|
||||
"manually once in order to enable the shortcut."
|
||||
msgstr ""
|
||||
|
||||
#: src/gtk/connected-device.ui:238 src/gtk/connected-device.ui:267
|
||||
#: src/gtk/connected-device.ui:296 src/gtk/connected-device.ui:325
|
||||
#: src/gtk/connected-device.ui:378 src/gtk/connected-device.ui:407
|
||||
#: src/gtk/connected-device.ui:436 src/gtk/connected-device.ui:465
|
||||
msgid "Change"
|
||||
msgstr ""
|
||||
|
||||
#: src/gtk/connected-device.ui:247
|
||||
#: src/gtk/connected-device.ui:387
|
||||
msgid "Re-center display shortcut"
|
||||
msgstr ""
|
||||
|
||||
#: src/gtk/connected-device.ui:248
|
||||
#: src/gtk/connected-device.ui:388
|
||||
msgid "Pin the virtual display to the current position."
|
||||
msgstr ""
|
||||
|
||||
#: src/gtk/connected-device.ui:276
|
||||
msgid "Display distance shortcut"
|
||||
#: src/gtk/connected-device.ui:416
|
||||
msgid "Toggle zoom on focus shortcut"
|
||||
msgstr ""
|
||||
|
||||
#: src/gtk/connected-device.ui:277
|
||||
msgid "Quickly toggle between two predefined distances."
|
||||
#: src/gtk/connected-device.ui:417
|
||||
msgid "Quickly toggle zoom on focus mode."
|
||||
msgstr ""
|
||||
|
||||
#: src/gtk/connected-device.ui:305
|
||||
#: src/gtk/connected-device.ui:445
|
||||
msgid "Toggle follow mode shortcut"
|
||||
msgstr ""
|
||||
|
||||
#: src/gtk/connected-device.ui:306
|
||||
#: src/gtk/connected-device.ui:446
|
||||
msgid "Quickly toggle follow mode."
|
||||
msgstr ""
|
||||
|
||||
#: src/gtk/connected-device.ui:341 src/gtk/connected-device.ui:347
|
||||
#: src/gtk/connected-device.ui:481 src/gtk/connected-device.ui:487
|
||||
msgid "Advanced Settings"
|
||||
msgstr ""
|
||||
|
||||
#: src/gtk/connected-device.ui:350
|
||||
#: src/gtk/connected-device.ui:490
|
||||
msgid "Find optimal display config"
|
||||
msgstr ""
|
||||
|
||||
#: src/gtk/connected-device.ui:351
|
||||
#: src/gtk/connected-device.ui:491
|
||||
msgid ""
|
||||
"Automatically modify the glasses display configuration for maximum "
|
||||
"resolution and best scaling when plugged in."
|
||||
msgstr ""
|
||||
|
||||
#: src/gtk/connected-device.ui:361
|
||||
#: src/gtk/connected-device.ui:501
|
||||
msgid "Use highest refresh rate"
|
||||
msgstr ""
|
||||
|
||||
#: src/gtk/connected-device.ui:362
|
||||
#: src/gtk/connected-device.ui:502
|
||||
msgid "Refresh rate may affect performance, disable this to set it manually."
|
||||
msgstr ""
|
||||
|
||||
#: src/gtk/connected-device.ui:372
|
||||
#: src/gtk/connected-device.ui:512
|
||||
msgid "Always primary display"
|
||||
msgstr ""
|
||||
|
||||
#: src/gtk/connected-device.ui:373
|
||||
#: src/gtk/connected-device.ui:513
|
||||
msgid "Automatically set the glasses as the primary display when plugged in."
|
||||
msgstr ""
|
||||
|
||||
#: src/gtk/connected-device.ui:383
|
||||
msgid "Fast SBS mode switching"
|
||||
msgstr ""
|
||||
|
||||
#: src/gtk/connected-device.ui:384
|
||||
msgid ""
|
||||
"Switches glasses to SBS mode immediately when plugged in, if widescreen mode "
|
||||
"is on. May cause instability."
|
||||
msgstr ""
|
||||
|
||||
#: src/gtk/connected-device.ui:394
|
||||
#: src/gtk/connected-device.ui:523
|
||||
msgid "Movement look-ahead"
|
||||
msgstr ""
|
||||
|
||||
#: src/gtk/connected-device.ui:395
|
||||
#: src/gtk/connected-device.ui:524
|
||||
msgid ""
|
||||
"Counteracts input lag by predicting head-tracking position ahead of render "
|
||||
"time. Stick with default unless virtual display drags behind your head "
|
||||
"movements, jumps ahead, or is very shaky."
|
||||
msgstr ""
|
||||
|
||||
#: src/gtk/connected-device.ui:413
|
||||
#: src/gtk/connected-device.ui:542
|
||||
msgid "Default"
|
||||
msgstr ""
|
||||
|
||||
#: src/gtk/connected-device.ui:425
|
||||
#: src/gtk/connected-device.ui:554
|
||||
msgid "Text Scaling"
|
||||
msgstr ""
|
||||
|
||||
#: src/gtk/connected-device.ui:426
|
||||
#: src/gtk/connected-device.ui:555
|
||||
msgid "Scaling text below 1.0 will simulate a higher resolution display"
|
||||
msgstr ""
|
||||
|
||||
#: src/gtk/connected-device.ui:585
|
||||
msgid "Enable multi-tap detection"
|
||||
msgstr ""
|
||||
|
||||
#: src/gtk/connected-device.ui:586
|
||||
msgid "Enables double-tap to recenter and triple-tap to recalibrate."
|
||||
msgstr ""
|
||||
|
||||
#: src/gtk/display-distance-dialog.ui:9
|
||||
msgid "Show full range"
|
||||
msgstr ""
|
||||
|
||||
#: src/gtk/display-distance-dialog.ui:18
|
||||
msgid "Done"
|
||||
msgstr ""
|
||||
|
||||
#: src/gtk/failed-verification.ui:13
|
||||
msgid "Breezy Desktop GNOME invalid setup"
|
||||
msgstr ""
|
||||
|
|
@ -375,14 +479,6 @@ msgid ""
|
|||
"connected."
|
||||
msgstr ""
|
||||
|
||||
#: src/gtk/no-device.ui:34
|
||||
msgid "Start in widescreen mode"
|
||||
msgstr ""
|
||||
|
||||
#: src/gtk/no-device.ui:35
|
||||
msgid "Widescreen mode is not supported for all glasses."
|
||||
msgstr ""
|
||||
|
||||
#: src/gtk/no-driver.ui:13
|
||||
msgid "No driver running"
|
||||
msgstr ""
|
||||
|
|
|
|||
348
ui/po/de.po
348
ui/po/de.po
|
|
@ -7,7 +7,7 @@ msgid ""
|
|||
msgstr ""
|
||||
"Project-Id-Version: PACKAGE VERSION\n"
|
||||
"Report-Msgid-Bugs-To: \n"
|
||||
"POT-Creation-Date: 2024-10-30 09:36-0700\n"
|
||||
"POT-Creation-Date: 2025-03-05 12:28-0800\n"
|
||||
"PO-Revision-Date: 2024-08-02 20:54-0700\n"
|
||||
"Last-Translator: <wayne@xronlinux.com>\n"
|
||||
"Language-Team: German <translation-team-de@lists.sourceforge.net>\n"
|
||||
|
|
@ -17,7 +17,7 @@ msgstr ""
|
|||
"Content-Transfer-Encoding: 8bit\n"
|
||||
"Plural-Forms: nplurals=2; plural=(n != 1);\n"
|
||||
|
||||
#: src/connecteddevice.py:17
|
||||
#: src/connecteddevice.py:23
|
||||
msgid ""
|
||||
"Switches your glasses into side-by-side mode and doubles the width of the "
|
||||
"display."
|
||||
|
|
@ -25,10 +25,56 @@ msgstr ""
|
|||
"Schaltet Ihre Brille in den Side-by-Side-Modus und verdoppelt die Breite des "
|
||||
"Displays."
|
||||
|
||||
#: src/connecteddevice.py:18
|
||||
#: src/connecteddevice.py:24
|
||||
msgid "This feature is not currently supported for your device."
|
||||
msgstr "Diese Funktion wird von Ihrem Gerät derzeit nicht unterstützt."
|
||||
|
||||
#: src/connecteddevice.py:124
|
||||
#, fuzzy
|
||||
msgid "Set Focused Display Distance"
|
||||
msgstr "Display-Entfernung"
|
||||
|
||||
#: src/connecteddevice.py:125
|
||||
msgid "Use a closer value so the display zooms in when you look at it."
|
||||
msgstr ""
|
||||
|
||||
#: src/connecteddevice.py:132
|
||||
#, fuzzy
|
||||
msgid "Set All Displays Distance"
|
||||
msgstr "Display-Entfernung"
|
||||
|
||||
#: src/connecteddevice.py:133
|
||||
msgid "Use a farther value so the displays are zoomed out when you look away."
|
||||
msgstr ""
|
||||
|
||||
#: src/connecteddevice.py:231
|
||||
msgid ""
|
||||
"Unable to add virtual displays on this machine. xdg-desktop-portal is "
|
||||
"required."
|
||||
msgstr ""
|
||||
|
||||
#: src/connecteddevice.py:265
|
||||
#, fuzzy
|
||||
msgid "Focused display"
|
||||
msgstr "Display-Entfernung"
|
||||
|
||||
#: src/connecteddevice.py:271
|
||||
#, fuzzy
|
||||
msgid "All displays"
|
||||
msgstr "Gebogenes Display"
|
||||
|
||||
#: src/displaydistancedialogcontent.py:41
|
||||
msgid "closer"
|
||||
msgstr ""
|
||||
|
||||
#: src/displaydistancedialogcontent.py:45
|
||||
msgid "fullscreen"
|
||||
msgstr ""
|
||||
|
||||
#: src/displaydistancedialogcontent.py:48
|
||||
msgid "farther"
|
||||
msgstr ""
|
||||
|
||||
#: src/licensedialogcontent.py:63
|
||||
msgid "Paid Tier Status"
|
||||
msgstr "Bezahlter Tarifstatus"
|
||||
|
|
@ -37,7 +83,7 @@ msgstr "Bezahlter Tarifstatus"
|
|||
msgid "Feature Availability"
|
||||
msgstr "Funktionsverfügbarkeit"
|
||||
|
||||
#: src/licensefeaturerow.py:15 src/shortcutdialog.py:107
|
||||
#: src/licensefeaturerow.py:15 src/shortcutdialog.py:104
|
||||
msgid "Disabled"
|
||||
msgstr "Deaktiviert"
|
||||
|
||||
|
|
@ -166,82 +212,138 @@ msgid "Enables the Breezy Desktop XR effect."
|
|||
msgstr "Aktiviert den Breezy Desktop XR-Effekt."
|
||||
|
||||
#: src/gtk/connected-device.ui:55
|
||||
msgid "Widescreen mode"
|
||||
msgstr "Breitbildmodus"
|
||||
msgid "Zoom on focus"
|
||||
msgstr ""
|
||||
|
||||
#: src/gtk/connected-device.ui:66
|
||||
#: src/gtk/connected-device.ui:56
|
||||
msgid ""
|
||||
"Automatically move a display closer when you look at it.\n"
|
||||
"Set your preferred focused and unfocused distances in the Adjustments "
|
||||
"section.\n"
|
||||
" "
|
||||
msgstr ""
|
||||
|
||||
#: src/gtk/connected-device.ui:69
|
||||
msgid "Follow mode"
|
||||
msgstr "Folgemodus"
|
||||
|
||||
#: src/gtk/connected-device.ui:67
|
||||
msgid "Keep the virtual display near the center of your view."
|
||||
#: src/gtk/connected-device.ui:70
|
||||
#, fuzzy
|
||||
msgid "Keep the focused display near the center of your view."
|
||||
msgstr "Halten Sie das virtuelle Display Nahe der Mitte Ihres Blickfelds."
|
||||
|
||||
#: src/gtk/connected-device.ui:77
|
||||
msgid "Curved display"
|
||||
msgstr "Gebogenes Display"
|
||||
#: src/gtk/connected-device.ui:80 src/gtk/no-device.ui:34
|
||||
msgid "Disable physical displays"
|
||||
msgstr ""
|
||||
|
||||
#: src/gtk/connected-device.ui:78
|
||||
msgid "Switch between flat and curved displays."
|
||||
msgstr "Zwischen flachen und gebogenen Displays wechseln."
|
||||
#: src/gtk/connected-device.ui:81 src/gtk/no-device.ui:35
|
||||
msgid ""
|
||||
"Automatically disable all physical displays when the XR effect is enabled."
|
||||
msgstr ""
|
||||
|
||||
#: src/gtk/connected-device.ui:91
|
||||
#, fuzzy
|
||||
msgid "Virtual displays"
|
||||
msgstr "Gebogenes Display"
|
||||
|
||||
#: src/gtk/connected-device.ui:103
|
||||
#, fuzzy
|
||||
msgid "Rearrange displays"
|
||||
msgstr "Gebogenes Display"
|
||||
|
||||
#: src/gtk/connected-device.ui:115
|
||||
msgid "1080p"
|
||||
msgstr ""
|
||||
|
||||
#: src/gtk/connected-device.ui:116
|
||||
msgid "1440p"
|
||||
msgstr ""
|
||||
|
||||
#: src/gtk/connected-device.ui:140
|
||||
msgid "Adjustments"
|
||||
msgstr "Einstellungen"
|
||||
|
||||
#: src/gtk/connected-device.ui:94
|
||||
msgid "Display distance"
|
||||
#: src/gtk/connected-device.ui:143
|
||||
#, fuzzy
|
||||
msgid "Display distances"
|
||||
msgstr "Display-Entfernung"
|
||||
|
||||
#: src/gtk/connected-device.ui:95
|
||||
msgid ""
|
||||
"Closer appears larger, further appears smaller. Controls depth when in "
|
||||
"widescreen mode."
|
||||
#: src/gtk/connected-device.ui:144
|
||||
msgid "Set how close you want displays to appear."
|
||||
msgstr ""
|
||||
"Näher erscheint größer, weiter erscheint kleiner. Steuert die Tiefe, wenn im "
|
||||
"Breitbildmodus."
|
||||
|
||||
#: src/gtk/connected-device.ui:123
|
||||
msgid "Display size"
|
||||
msgstr "Display-Größe"
|
||||
|
||||
#: src/gtk/connected-device.ui:124
|
||||
msgid ""
|
||||
"Combine with display distance to achieve a comfortable level of depth and "
|
||||
"size."
|
||||
msgstr ""
|
||||
"Kombinieren Sie mit der Display-Entfernung, um eine bequeme Ebene der Tiefe "
|
||||
"und Größe zu erreichen."
|
||||
|
||||
#: src/gtk/connected-device.ui:152
|
||||
msgid "Display toggle distances"
|
||||
msgstr "Umschalten der Display-Entfernungen"
|
||||
|
||||
#: src/gtk/connected-device.ui:153
|
||||
msgid ""
|
||||
"Use the buttons to capture the current display distance for use with the "
|
||||
"keyboard shortcut."
|
||||
msgstr ""
|
||||
"Verwenden Sie die Schaltflächen, um die aktuelle Display-Entfernung für die "
|
||||
"Verwendung mit der Tastenkombination aufzufangen."
|
||||
|
||||
#: src/gtk/connected-device.ui:178
|
||||
#: src/gtk/connected-device.ui:199
|
||||
msgid "Follow threshold"
|
||||
msgstr "Folgemodus-Schwelle"
|
||||
|
||||
#: src/gtk/connected-device.ui:179
|
||||
#: src/gtk/connected-device.ui:200
|
||||
msgid "How far away you can look before the display follows."
|
||||
msgstr "Wie weit Sie wegschauen können, bevor das Display folgt."
|
||||
|
||||
#: src/gtk/connected-device.ui:209 src/gtk/connected-device.ui:215
|
||||
#: src/gtk/connected-device.ui:223
|
||||
#, fuzzy
|
||||
msgid "Display angling"
|
||||
msgstr "Display-Größe"
|
||||
|
||||
#: src/gtk/connected-device.ui:224
|
||||
msgid ""
|
||||
"When there are multiple displays, choose how they should angle towards you."
|
||||
msgstr ""
|
||||
|
||||
#: src/gtk/connected-device.ui:238
|
||||
msgid "Automatic"
|
||||
msgstr ""
|
||||
|
||||
#: src/gtk/connected-device.ui:239
|
||||
msgid "Side-angled"
|
||||
msgstr ""
|
||||
|
||||
#: src/gtk/connected-device.ui:240
|
||||
msgid "Top-angled"
|
||||
msgstr ""
|
||||
|
||||
#: src/gtk/connected-device.ui:241
|
||||
msgid "Flat"
|
||||
msgstr ""
|
||||
|
||||
#: src/gtk/connected-device.ui:251
|
||||
#, fuzzy
|
||||
msgid "Display spacing"
|
||||
msgstr "Display-Größe"
|
||||
|
||||
#: src/gtk/connected-device.ui:252
|
||||
msgid "Put empty space between displays, when there are multiple."
|
||||
msgstr ""
|
||||
|
||||
#: src/gtk/connected-device.ui:282
|
||||
msgid "Viewport horizontal offset"
|
||||
msgstr ""
|
||||
|
||||
#: src/gtk/connected-device.ui:283
|
||||
msgid ""
|
||||
"By default, the viewport will center on the primary display. Use this slider "
|
||||
"to move the viewport to the left or right."
|
||||
msgstr ""
|
||||
|
||||
#: src/gtk/connected-device.ui:312
|
||||
msgid "Viewport vertical offset"
|
||||
msgstr ""
|
||||
|
||||
#: src/gtk/connected-device.ui:313
|
||||
msgid ""
|
||||
"By default, the viewport will center on the primary display. Use this slider "
|
||||
"to move the viewport up or down."
|
||||
msgstr ""
|
||||
|
||||
#: src/gtk/connected-device.ui:349 src/gtk/connected-device.ui:355
|
||||
msgid "Keyboard Shortcuts"
|
||||
msgstr "Tastenkombinationen"
|
||||
|
||||
#: src/gtk/connected-device.ui:218
|
||||
#: src/gtk/connected-device.ui:358
|
||||
msgid "XR Effect on/off shortcut"
|
||||
msgstr "XR-Effekt an/aus Tastenkombination"
|
||||
|
||||
#: src/gtk/connected-device.ui:219
|
||||
#: src/gtk/connected-device.ui:359
|
||||
msgid ""
|
||||
"Quickly enable or disable the XR Effect. You may need to enable the effect "
|
||||
"manually once in order to enable the shortcut."
|
||||
|
|
@ -250,44 +352,46 @@ msgstr ""
|
|||
"Effekt einmalig manuell aktiviert werden, um die Tastenkombination zu "
|
||||
"aktivieren."
|
||||
|
||||
#: src/gtk/connected-device.ui:238 src/gtk/connected-device.ui:267
|
||||
#: src/gtk/connected-device.ui:296 src/gtk/connected-device.ui:325
|
||||
#: src/gtk/connected-device.ui:378 src/gtk/connected-device.ui:407
|
||||
#: src/gtk/connected-device.ui:436 src/gtk/connected-device.ui:465
|
||||
msgid "Change"
|
||||
msgstr "Ändern"
|
||||
|
||||
#: src/gtk/connected-device.ui:247
|
||||
#: src/gtk/connected-device.ui:387
|
||||
msgid "Re-center display shortcut"
|
||||
msgstr "Display-Zentrierung-Tastenkombination"
|
||||
|
||||
#: src/gtk/connected-device.ui:248
|
||||
#: src/gtk/connected-device.ui:388
|
||||
msgid "Pin the virtual display to the current position."
|
||||
msgstr "Heften Sie das virtuelle Display an die aktuelle Position an."
|
||||
|
||||
#: src/gtk/connected-device.ui:276
|
||||
msgid "Display distance shortcut"
|
||||
msgstr "Display-Entfernung-Tastenkombination"
|
||||
#: src/gtk/connected-device.ui:416
|
||||
#, fuzzy
|
||||
msgid "Toggle zoom on focus shortcut"
|
||||
msgstr "Folgemodus-Tastenkombination umschalten"
|
||||
|
||||
#: src/gtk/connected-device.ui:277
|
||||
msgid "Quickly toggle between two predefined distances."
|
||||
msgstr "Schnell zwischen zwei vordefinierten Entfernungen wechseln."
|
||||
#: src/gtk/connected-device.ui:417
|
||||
#, fuzzy
|
||||
msgid "Quickly toggle zoom on focus mode."
|
||||
msgstr "Schnell den Folgemodus wechseln."
|
||||
|
||||
#: src/gtk/connected-device.ui:305
|
||||
#: src/gtk/connected-device.ui:445
|
||||
msgid "Toggle follow mode shortcut"
|
||||
msgstr "Folgemodus-Tastenkombination umschalten"
|
||||
|
||||
#: src/gtk/connected-device.ui:306
|
||||
#: src/gtk/connected-device.ui:446
|
||||
msgid "Quickly toggle follow mode."
|
||||
msgstr "Schnell den Folgemodus wechseln."
|
||||
|
||||
#: src/gtk/connected-device.ui:341 src/gtk/connected-device.ui:347
|
||||
#: src/gtk/connected-device.ui:481 src/gtk/connected-device.ui:487
|
||||
msgid "Advanced Settings"
|
||||
msgstr "Erweiterte Einstellungen"
|
||||
|
||||
#: src/gtk/connected-device.ui:350
|
||||
#: src/gtk/connected-device.ui:490
|
||||
msgid "Find optimal display config"
|
||||
msgstr "Optimale Display-Konfiguration finden"
|
||||
|
||||
#: src/gtk/connected-device.ui:351
|
||||
#: src/gtk/connected-device.ui:491
|
||||
msgid ""
|
||||
"Automatically modify the glasses display configuration for maximum "
|
||||
"resolution and best scaling when plugged in."
|
||||
|
|
@ -295,43 +399,31 @@ msgstr ""
|
|||
"Ändern Sie die Display-Konfiguration der Brille automatisch zur maximalen "
|
||||
"Auflösung und besten Skalierung, wenn sie angeschlossen ist."
|
||||
|
||||
#: src/gtk/connected-device.ui:361
|
||||
#: src/gtk/connected-device.ui:501
|
||||
msgid "Use highest refresh rate"
|
||||
msgstr "Höchste Bildwiederholrate verwenden"
|
||||
|
||||
#: src/gtk/connected-device.ui:362
|
||||
#: src/gtk/connected-device.ui:502
|
||||
msgid "Refresh rate may affect performance, disable this to set it manually."
|
||||
msgstr ""
|
||||
"Die Bildwiederholrate kann die Leistung beeinflussen, deaktivieren Sie dies, "
|
||||
"um sie manuell festzulegen."
|
||||
|
||||
#: src/gtk/connected-device.ui:372
|
||||
#: src/gtk/connected-device.ui:512
|
||||
msgid "Always primary display"
|
||||
msgstr "Immer primäres Display"
|
||||
|
||||
#: src/gtk/connected-device.ui:373
|
||||
#: src/gtk/connected-device.ui:513
|
||||
msgid "Automatically set the glasses as the primary display when plugged in."
|
||||
msgstr ""
|
||||
"Setzen Sie die Brille automatisch als primäres Display, wenn sie "
|
||||
"angeschlossen ist."
|
||||
|
||||
#: src/gtk/connected-device.ui:383
|
||||
msgid "Fast SBS mode switching"
|
||||
msgstr "Schnelles SBS-Modus-Wechseln"
|
||||
|
||||
#: src/gtk/connected-device.ui:384
|
||||
msgid ""
|
||||
"Switches glasses to SBS mode immediately when plugged in, if widescreen mode "
|
||||
"is on. May cause instability."
|
||||
msgstr ""
|
||||
"Schaltet die Brille sofort in den SBS-Modus, wenn sie angeschlossen ist, "
|
||||
"wenn der Breitbildmodus aktiviert ist. Kann zu Instabilität führen."
|
||||
|
||||
#: src/gtk/connected-device.ui:394
|
||||
#: src/gtk/connected-device.ui:523
|
||||
msgid "Movement look-ahead"
|
||||
msgstr "Bewegungsvorausschau"
|
||||
|
||||
#: src/gtk/connected-device.ui:395
|
||||
#: src/gtk/connected-device.ui:524
|
||||
msgid ""
|
||||
"Counteracts input lag by predicting head-tracking position ahead of render "
|
||||
"time. Stick with default unless virtual display drags behind your head "
|
||||
|
|
@ -342,18 +434,34 @@ msgstr ""
|
|||
"es sei denn, das virtuelle Display hängt hinter Ihren Kopfbewegungen "
|
||||
"hinterher, springt vor oder ist sehr wackelig."
|
||||
|
||||
#: src/gtk/connected-device.ui:413
|
||||
#: src/gtk/connected-device.ui:542
|
||||
msgid "Default"
|
||||
msgstr "Standard"
|
||||
|
||||
#: src/gtk/connected-device.ui:425
|
||||
#: src/gtk/connected-device.ui:554
|
||||
msgid "Text Scaling"
|
||||
msgstr "Textskalierung"
|
||||
|
||||
#: src/gtk/connected-device.ui:426
|
||||
#: src/gtk/connected-device.ui:555
|
||||
msgid "Scaling text below 1.0 will simulate a higher resolution display"
|
||||
msgstr "Text unter 1.0 skalieren simuliert ein höher aufgelöstes Display"
|
||||
|
||||
#: src/gtk/connected-device.ui:585
|
||||
msgid "Enable multi-tap detection"
|
||||
msgstr ""
|
||||
|
||||
#: src/gtk/connected-device.ui:586
|
||||
msgid "Enables double-tap to recenter and triple-tap to recalibrate."
|
||||
msgstr ""
|
||||
|
||||
#: src/gtk/display-distance-dialog.ui:9
|
||||
msgid "Show full range"
|
||||
msgstr ""
|
||||
|
||||
#: src/gtk/display-distance-dialog.ui:18
|
||||
msgid "Done"
|
||||
msgstr ""
|
||||
|
||||
#: src/gtk/failed-verification.ui:13
|
||||
msgid "Breezy Desktop GNOME invalid setup"
|
||||
msgstr "Ungültige Breezy Desktop GNOME-Installation"
|
||||
|
|
@ -403,14 +511,6 @@ msgstr ""
|
|||
"Automatisch den Breezy Desktop XR-Effekt aktivieren, wenn unterstützte "
|
||||
"Gläser verbunden werden"
|
||||
|
||||
#: src/gtk/no-device.ui:34
|
||||
msgid "Start in widescreen mode"
|
||||
msgstr "Im Breitbildmodus starten"
|
||||
|
||||
#: src/gtk/no-device.ui:35
|
||||
msgid "Widescreen mode is not supported for all glasses."
|
||||
msgstr "Breitbildmodus wird nicht für alle Gläsern unterstützt"
|
||||
|
||||
#: src/gtk/no-driver.ui:13
|
||||
msgid "No driver running"
|
||||
msgstr "Kein Treiber wird ausgeführt"
|
||||
|
|
@ -522,3 +622,59 @@ msgstr "Zurrücksetzung erwzingen"
|
|||
#: src/gtk/window.ui:99
|
||||
msgid "About BreezyDesktop"
|
||||
msgstr "Über BreezyDesktop"
|
||||
|
||||
#~ msgid "Fast SBS mode switching"
|
||||
#~ msgstr "Schnelles SBS-Modus-Wechseln"
|
||||
|
||||
#~ msgid ""
|
||||
#~ "Switches glasses to SBS mode immediately when plugged in, if widescreen "
|
||||
#~ "mode is on. May cause instability."
|
||||
#~ msgstr ""
|
||||
#~ "Schaltet die Brille sofort in den SBS-Modus, wenn sie angeschlossen ist, "
|
||||
#~ "wenn der Breitbildmodus aktiviert ist. Kann zu Instabilität führen."
|
||||
|
||||
#, fuzzy
|
||||
#~ msgid "Set Unfocused Displays Distance"
|
||||
#~ msgstr "Display-Entfernung"
|
||||
|
||||
#~ msgid "Widescreen mode"
|
||||
#~ msgstr "Breitbildmodus"
|
||||
|
||||
#~ msgid "Switch between flat and curved displays."
|
||||
#~ msgstr "Zwischen flachen und gebogenen Displays wechseln."
|
||||
|
||||
#~ msgid ""
|
||||
#~ "Closer appears larger, further appears smaller. Controls depth when in "
|
||||
#~ "widescreen mode."
|
||||
#~ msgstr ""
|
||||
#~ "Näher erscheint größer, weiter erscheint kleiner. Steuert die Tiefe, wenn "
|
||||
#~ "im Breitbildmodus."
|
||||
|
||||
#~ msgid ""
|
||||
#~ "Combine with display distance to achieve a comfortable level of depth and "
|
||||
#~ "size."
|
||||
#~ msgstr ""
|
||||
#~ "Kombinieren Sie mit der Display-Entfernung, um eine bequeme Ebene der "
|
||||
#~ "Tiefe und Größe zu erreichen."
|
||||
|
||||
#~ msgid "Display toggle distances"
|
||||
#~ msgstr "Umschalten der Display-Entfernungen"
|
||||
|
||||
#~ msgid ""
|
||||
#~ "Use the buttons to capture the current display distance for use with the "
|
||||
#~ "keyboard shortcut."
|
||||
#~ msgstr ""
|
||||
#~ "Verwenden Sie die Schaltflächen, um die aktuelle Display-Entfernung für "
|
||||
#~ "die Verwendung mit der Tastenkombination aufzufangen."
|
||||
|
||||
#~ msgid "Display distance shortcut"
|
||||
#~ msgstr "Display-Entfernung-Tastenkombination"
|
||||
|
||||
#~ msgid "Quickly toggle between two predefined distances."
|
||||
#~ msgstr "Schnell zwischen zwei vordefinierten Entfernungen wechseln."
|
||||
|
||||
#~ msgid "Start in widescreen mode"
|
||||
#~ msgstr "Im Breitbildmodus starten"
|
||||
|
||||
#~ msgid "Widescreen mode is not supported for all glasses."
|
||||
#~ msgstr "Breitbildmodus wird nicht für alle Gläsern unterstützt"
|
||||
|
|
|
|||
362
ui/po/es.po
362
ui/po/es.po
|
|
@ -7,7 +7,7 @@ msgid ""
|
|||
msgstr ""
|
||||
"Project-Id-Version: PACKAGE VERSION\n"
|
||||
"Report-Msgid-Bugs-To: \n"
|
||||
"POT-Creation-Date: 2024-10-22 13:27-0700\n"
|
||||
"POT-Creation-Date: 2025-03-05 12:28-0800\n"
|
||||
"PO-Revision-Date: 2024-08-02 20:55-0700\n"
|
||||
"Last-Translator: <wayne@xronlinux.com>\n"
|
||||
"Language-Team: Spanish <es@tp.org.es>\n"
|
||||
|
|
@ -17,17 +17,63 @@ msgstr ""
|
|||
"Content-Transfer-Encoding: 8bit\n"
|
||||
"Plural-Forms: nplurals=2; plural=(n != 1);\n"
|
||||
|
||||
#: src/connecteddevice.py:17
|
||||
#: src/connecteddevice.py:23
|
||||
msgid ""
|
||||
"Switches your glasses into side-by-side mode and doubles the width of the "
|
||||
"display."
|
||||
msgstr ""
|
||||
"Cambia tus gafas al modo lado a lado y duplica el ancho de la pantalla."
|
||||
|
||||
#: src/connecteddevice.py:18
|
||||
#: src/connecteddevice.py:24
|
||||
msgid "This feature is not currently supported for your device."
|
||||
msgstr "Esta función no es compatible con tu dispositivo en este momento."
|
||||
|
||||
#: src/connecteddevice.py:124
|
||||
#, fuzzy
|
||||
msgid "Set Focused Display Distance"
|
||||
msgstr "Distancia de la pantalla"
|
||||
|
||||
#: src/connecteddevice.py:125
|
||||
msgid "Use a closer value so the display zooms in when you look at it."
|
||||
msgstr ""
|
||||
|
||||
#: src/connecteddevice.py:132
|
||||
#, fuzzy
|
||||
msgid "Set All Displays Distance"
|
||||
msgstr "Distancia de la pantalla"
|
||||
|
||||
#: src/connecteddevice.py:133
|
||||
msgid "Use a farther value so the displays are zoomed out when you look away."
|
||||
msgstr ""
|
||||
|
||||
#: src/connecteddevice.py:231
|
||||
msgid ""
|
||||
"Unable to add virtual displays on this machine. xdg-desktop-portal is "
|
||||
"required."
|
||||
msgstr ""
|
||||
|
||||
#: src/connecteddevice.py:265
|
||||
#, fuzzy
|
||||
msgid "Focused display"
|
||||
msgstr "Distancia de la pantalla"
|
||||
|
||||
#: src/connecteddevice.py:271
|
||||
#, fuzzy
|
||||
msgid "All displays"
|
||||
msgstr "Pantalla curvada"
|
||||
|
||||
#: src/displaydistancedialogcontent.py:41
|
||||
msgid "closer"
|
||||
msgstr ""
|
||||
|
||||
#: src/displaydistancedialogcontent.py:45
|
||||
msgid "fullscreen"
|
||||
msgstr ""
|
||||
|
||||
#: src/displaydistancedialogcontent.py:48
|
||||
msgid "farther"
|
||||
msgstr ""
|
||||
|
||||
#: src/licensedialogcontent.py:63
|
||||
msgid "Paid Tier Status"
|
||||
msgstr "Estado del Nivel de Membresía Pagada"
|
||||
|
|
@ -36,7 +82,7 @@ msgstr "Estado del Nivel de Membresía Pagada"
|
|||
msgid "Feature Availability"
|
||||
msgstr "Disponibilidad de Características"
|
||||
|
||||
#: src/licensefeaturerow.py:15 src/shortcutdialog.py:107
|
||||
#: src/licensefeaturerow.py:15 src/shortcutdialog.py:104
|
||||
msgid "Disabled"
|
||||
msgstr "Deshabilitado"
|
||||
|
||||
|
|
@ -165,127 +211,185 @@ msgid "Enables the Breezy Desktop XR effect."
|
|||
msgstr "Habilita el efecto XR de Breezy Desktop."
|
||||
|
||||
#: src/gtk/connected-device.ui:55
|
||||
msgid "Widescreen mode"
|
||||
msgstr "Modo pantalla ancha"
|
||||
msgid "Zoom on focus"
|
||||
msgstr ""
|
||||
|
||||
#: src/gtk/connected-device.ui:66
|
||||
#: src/gtk/connected-device.ui:56
|
||||
msgid ""
|
||||
"Automatically move a display closer when you look at it.\n"
|
||||
"Set your preferred focused and unfocused distances in the Adjustments "
|
||||
"section.\n"
|
||||
" "
|
||||
msgstr ""
|
||||
|
||||
#: src/gtk/connected-device.ui:69
|
||||
msgid "Follow mode"
|
||||
msgstr "Modo de seguimiento"
|
||||
|
||||
#: src/gtk/connected-device.ui:67
|
||||
msgid "Keep the virtual display near the center of your view."
|
||||
#: src/gtk/connected-device.ui:70
|
||||
#, fuzzy
|
||||
msgid "Keep the focused display near the center of your view."
|
||||
msgstr "Mantenga la pantalla virtual cerca del centro de su vista."
|
||||
|
||||
#: src/gtk/connected-device.ui:77
|
||||
msgid "Curved display"
|
||||
msgstr "Pantalla curvada"
|
||||
#: src/gtk/connected-device.ui:80 src/gtk/no-device.ui:34
|
||||
msgid "Disable physical displays"
|
||||
msgstr ""
|
||||
|
||||
#: src/gtk/connected-device.ui:78
|
||||
msgid "Switch between flat and curved displays."
|
||||
msgstr "Cambiar entre pantallas planas y curvadas."
|
||||
#: src/gtk/connected-device.ui:81 src/gtk/no-device.ui:35
|
||||
msgid ""
|
||||
"Automatically disable all physical displays when the XR effect is enabled."
|
||||
msgstr ""
|
||||
|
||||
#: src/gtk/connected-device.ui:91
|
||||
#, fuzzy
|
||||
msgid "Virtual displays"
|
||||
msgstr "Pantalla curvada"
|
||||
|
||||
#: src/gtk/connected-device.ui:103
|
||||
#, fuzzy
|
||||
msgid "Rearrange displays"
|
||||
msgstr "Pantalla curvada"
|
||||
|
||||
#: src/gtk/connected-device.ui:115
|
||||
msgid "1080p"
|
||||
msgstr ""
|
||||
|
||||
#: src/gtk/connected-device.ui:116
|
||||
msgid "1440p"
|
||||
msgstr ""
|
||||
|
||||
#: src/gtk/connected-device.ui:140
|
||||
msgid "Adjustments"
|
||||
msgstr "Ajustes"
|
||||
|
||||
#: src/gtk/connected-device.ui:94
|
||||
msgid "Display distance"
|
||||
#: src/gtk/connected-device.ui:143
|
||||
#, fuzzy
|
||||
msgid "Display distances"
|
||||
msgstr "Distancia de la pantalla"
|
||||
|
||||
#: src/gtk/connected-device.ui:95
|
||||
msgid ""
|
||||
"Closer appears larger, further appears smaller. Controls depth when in "
|
||||
"widescreen mode."
|
||||
#: src/gtk/connected-device.ui:144
|
||||
msgid "Set how close you want displays to appear."
|
||||
msgstr ""
|
||||
"Más cerca parece más grande, más lejos parece más pequeño. Controla la "
|
||||
"profundidad cuando está en modo de pantalla ancha."
|
||||
|
||||
#: src/gtk/connected-device.ui:123
|
||||
msgid "Display size"
|
||||
msgstr "Tamaño de la pantalla"
|
||||
|
||||
#: src/gtk/connected-device.ui:124
|
||||
msgid ""
|
||||
"Combine with display distance to achieve a comfortable level of depth and "
|
||||
"size."
|
||||
msgstr ""
|
||||
"Combínalo con la distancia de la pantalla para lograr un nivel cómodo de "
|
||||
"profundidad y tamaño."
|
||||
|
||||
#: src/gtk/connected-device.ui:152
|
||||
msgid "Display toggle distances"
|
||||
msgstr "Distancias de alternancia de pantalla"
|
||||
|
||||
#: src/gtk/connected-device.ui:153
|
||||
msgid ""
|
||||
"Use the buttons to capture the current display distance for use with the "
|
||||
"keyboard shortcut."
|
||||
msgstr ""
|
||||
"Utilice los botones para capturar la distancia actual de la pantalla para su "
|
||||
"uso con el método abreviado de teclado."
|
||||
|
||||
#: src/gtk/connected-device.ui:178
|
||||
#: src/gtk/connected-device.ui:199
|
||||
msgid "Follow threshold"
|
||||
msgstr "Umbral de seguimiento"
|
||||
|
||||
#: src/gtk/connected-device.ui:179
|
||||
#: src/gtk/connected-device.ui:200
|
||||
msgid "How far away you can look before the display follows."
|
||||
msgstr "Hasta qué punto puedes mirar antes de que la pantalla siga."
|
||||
|
||||
#: src/gtk/connected-device.ui:209 src/gtk/connected-device.ui:215
|
||||
#: src/gtk/connected-device.ui:223
|
||||
#, fuzzy
|
||||
msgid "Display angling"
|
||||
msgstr "Tamaño de la pantalla"
|
||||
|
||||
#: src/gtk/connected-device.ui:224
|
||||
msgid ""
|
||||
"When there are multiple displays, choose how they should angle towards you."
|
||||
msgstr ""
|
||||
|
||||
#: src/gtk/connected-device.ui:238
|
||||
msgid "Automatic"
|
||||
msgstr ""
|
||||
|
||||
#: src/gtk/connected-device.ui:239
|
||||
msgid "Side-angled"
|
||||
msgstr ""
|
||||
|
||||
#: src/gtk/connected-device.ui:240
|
||||
msgid "Top-angled"
|
||||
msgstr ""
|
||||
|
||||
#: src/gtk/connected-device.ui:241
|
||||
msgid "Flat"
|
||||
msgstr ""
|
||||
|
||||
#: src/gtk/connected-device.ui:251
|
||||
#, fuzzy
|
||||
msgid "Display spacing"
|
||||
msgstr "Tamaño de la pantalla"
|
||||
|
||||
#: src/gtk/connected-device.ui:252
|
||||
msgid "Put empty space between displays, when there are multiple."
|
||||
msgstr ""
|
||||
|
||||
#: src/gtk/connected-device.ui:282
|
||||
msgid "Viewport horizontal offset"
|
||||
msgstr ""
|
||||
|
||||
#: src/gtk/connected-device.ui:283
|
||||
msgid ""
|
||||
"By default, the viewport will center on the primary display. Use this slider "
|
||||
"to move the viewport to the left or right."
|
||||
msgstr ""
|
||||
|
||||
#: src/gtk/connected-device.ui:312
|
||||
msgid "Viewport vertical offset"
|
||||
msgstr ""
|
||||
|
||||
#: src/gtk/connected-device.ui:313
|
||||
msgid ""
|
||||
"By default, the viewport will center on the primary display. Use this slider "
|
||||
"to move the viewport up or down."
|
||||
msgstr ""
|
||||
|
||||
#: src/gtk/connected-device.ui:349 src/gtk/connected-device.ui:355
|
||||
msgid "Keyboard Shortcuts"
|
||||
msgstr "Atajos de teclado"
|
||||
|
||||
#: src/gtk/connected-device.ui:218
|
||||
#: src/gtk/connected-device.ui:358
|
||||
msgid "XR Effect on/off shortcut"
|
||||
msgstr "Atajo encendido/apagado Efecto XR"
|
||||
|
||||
#: src/gtk/connected-device.ui:219
|
||||
#: src/gtk/connected-device.ui:359
|
||||
msgid ""
|
||||
"Quickly enable or disable the XR Effect. You may need to enable the effect "
|
||||
"manually once in order to enable the shortcut."
|
||||
msgstr ""
|
||||
"Activa o desactiva rápidamente el Efecto XR. Es posible que necesites activar "
|
||||
"el efecto manualmente una vez para habilitar el atajo."
|
||||
"Activa o desactiva rápidamente el Efecto XR. Es posible que necesites "
|
||||
"activar el efecto manualmente una vez para habilitar el atajo."
|
||||
|
||||
#: src/gtk/connected-device.ui:238 src/gtk/connected-device.ui:267
|
||||
#: src/gtk/connected-device.ui:296 src/gtk/connected-device.ui:325
|
||||
#: src/gtk/connected-device.ui:378 src/gtk/connected-device.ui:407
|
||||
#: src/gtk/connected-device.ui:436 src/gtk/connected-device.ui:465
|
||||
msgid "Change"
|
||||
msgstr "Cambiar"
|
||||
|
||||
#: src/gtk/connected-device.ui:247
|
||||
#: src/gtk/connected-device.ui:387
|
||||
msgid "Re-center display shortcut"
|
||||
msgstr "Atajo para recentrar la pantalla"
|
||||
|
||||
#: src/gtk/connected-device.ui:248
|
||||
#: src/gtk/connected-device.ui:388
|
||||
msgid "Pin the virtual display to the current position."
|
||||
msgstr "Fije la pantalla virtual en la posición actual."
|
||||
|
||||
#: src/gtk/connected-device.ui:276
|
||||
msgid "Display distance shortcut"
|
||||
msgstr "Atajo de distancia de pantalla"
|
||||
#: src/gtk/connected-device.ui:416
|
||||
#, fuzzy
|
||||
msgid "Toggle zoom on focus shortcut"
|
||||
msgstr "Atajo para alternar el modo de seguimiento"
|
||||
|
||||
#: src/gtk/connected-device.ui:277
|
||||
msgid "Quickly toggle between two predefined distances."
|
||||
msgstr "Cambiar rápidamente entre dos distancias predefinidas."
|
||||
#: src/gtk/connected-device.ui:417
|
||||
#, fuzzy
|
||||
msgid "Quickly toggle zoom on focus mode."
|
||||
msgstr "Activar el modo de seguimiento."
|
||||
|
||||
#: src/gtk/connected-device.ui:305
|
||||
#: src/gtk/connected-device.ui:445
|
||||
msgid "Toggle follow mode shortcut"
|
||||
msgstr "Atajo para alternar el modo de seguimiento"
|
||||
|
||||
#: src/gtk/connected-device.ui:306
|
||||
#: src/gtk/connected-device.ui:446
|
||||
msgid "Quickly toggle follow mode."
|
||||
msgstr "Activar el modo de seguimiento."
|
||||
|
||||
#: src/gtk/connected-device.ui:341 src/gtk/connected-device.ui:347
|
||||
#: src/gtk/connected-device.ui:481 src/gtk/connected-device.ui:487
|
||||
msgid "Advanced Settings"
|
||||
msgstr "Configuración Avanzada"
|
||||
|
||||
#: src/gtk/connected-device.ui:350
|
||||
#: src/gtk/connected-device.ui:490
|
||||
msgid "Find optimal display config"
|
||||
msgstr "Encuentre la configuración de pantalla óptima"
|
||||
|
||||
#: src/gtk/connected-device.ui:351
|
||||
#: src/gtk/connected-device.ui:491
|
||||
msgid ""
|
||||
"Automatically modify the glasses display configuration for maximum "
|
||||
"resolution and best scaling when plugged in."
|
||||
|
|
@ -294,43 +398,30 @@ msgstr ""
|
|||
"obtener la máxima resolución y la mejor escalabilidad cuando estén "
|
||||
"enchufadas."
|
||||
|
||||
#: src/gtk/connected-device.ui:361
|
||||
#: src/gtk/connected-device.ui:501
|
||||
msgid "Use highest refresh rate"
|
||||
msgstr "Utilizar la frecuencia de actualización más alta"
|
||||
|
||||
#: src/gtk/connected-device.ui:362
|
||||
#: src/gtk/connected-device.ui:502
|
||||
msgid "Refresh rate may affect performance, disable this to set it manually."
|
||||
msgstr ""
|
||||
"La frecuencia de actualización puede afectar el rendimiento, deshabilite "
|
||||
"esto para configurarlo manualmente."
|
||||
|
||||
#: src/gtk/connected-device.ui:372
|
||||
#: src/gtk/connected-device.ui:512
|
||||
msgid "Always primary display"
|
||||
msgstr "Siempre como pantalla principal"
|
||||
|
||||
#: src/gtk/connected-device.ui:373
|
||||
#: src/gtk/connected-device.ui:513
|
||||
msgid "Automatically set the glasses as the primary display when plugged in."
|
||||
msgstr ""
|
||||
"Automáticamente configurar las gafas como pantalla principal al enchufarse."
|
||||
|
||||
#: src/gtk/connected-device.ui:383
|
||||
msgid "Fast SBS mode switching"
|
||||
msgstr "Cambio rápido de modo SBS"
|
||||
|
||||
#: src/gtk/connected-device.ui:384
|
||||
msgid ""
|
||||
"Switches glasses to SBS mode immediately when plugged in, if widescreen mode "
|
||||
"is on. May cause instability."
|
||||
msgstr ""
|
||||
"Cambia las gafas al modo SBS (lado a lado) inmediatamente cuando se "
|
||||
"enchufan, si el modo de pantalla ancha está activado. Puede causar "
|
||||
"inestabilidad."
|
||||
|
||||
#: src/gtk/connected-device.ui:394
|
||||
#: src/gtk/connected-device.ui:523
|
||||
msgid "Movement look-ahead"
|
||||
msgstr "Anticipación de movimiento"
|
||||
|
||||
#: src/gtk/connected-device.ui:395
|
||||
#: src/gtk/connected-device.ui:524
|
||||
msgid ""
|
||||
"Counteracts input lag by predicting head-tracking position ahead of render "
|
||||
"time. Stick with default unless virtual display drags behind your head "
|
||||
|
|
@ -341,17 +432,35 @@ msgstr ""
|
|||
"predeterminado a menos que la pantalla virtual se retrase detrás de los "
|
||||
"movimientos de la cabeza, se adelante o sea muy inestable."
|
||||
|
||||
#: src/gtk/connected-device.ui:413
|
||||
#: src/gtk/connected-device.ui:542
|
||||
msgid "Default"
|
||||
msgstr "Predeterminado"
|
||||
|
||||
#: src/gtk/connected-device.ui:425
|
||||
#: src/gtk/connected-device.ui:554
|
||||
msgid "Text Scaling"
|
||||
msgstr "Escalado de Texto"
|
||||
|
||||
#: src/gtk/connected-device.ui:426
|
||||
#: src/gtk/connected-device.ui:555
|
||||
msgid "Scaling text below 1.0 will simulate a higher resolution display"
|
||||
msgstr "Escalando el texto por debajo de 1.0 simulará una pantalla de mayor resolución"
|
||||
msgstr ""
|
||||
"Escalando el texto por debajo de 1.0 simulará una pantalla de mayor "
|
||||
"resolución"
|
||||
|
||||
#: src/gtk/connected-device.ui:585
|
||||
msgid "Enable multi-tap detection"
|
||||
msgstr ""
|
||||
|
||||
#: src/gtk/connected-device.ui:586
|
||||
msgid "Enables double-tap to recenter and triple-tap to recalibrate."
|
||||
msgstr ""
|
||||
|
||||
#: src/gtk/display-distance-dialog.ui:9
|
||||
msgid "Show full range"
|
||||
msgstr ""
|
||||
|
||||
#: src/gtk/display-distance-dialog.ui:18
|
||||
msgid "Done"
|
||||
msgstr ""
|
||||
|
||||
#: src/gtk/failed-verification.ui:13
|
||||
msgid "Breezy Desktop GNOME invalid setup"
|
||||
|
|
@ -398,16 +507,8 @@ msgid ""
|
|||
"Automatically enable the Breezy Desktop XR effect when supported glasses are "
|
||||
"connected."
|
||||
msgstr ""
|
||||
"Habilita automáticamente el efecto Breezy Desktop XR cuando se conectan gafas "
|
||||
"compatibles."
|
||||
|
||||
#: src/gtk/no-device.ui:34
|
||||
msgid "Start in widescreen mode"
|
||||
msgstr "Empezar en modo pantalla ancha"
|
||||
|
||||
#: src/gtk/no-device.ui:35
|
||||
msgid "Widescreen mode is not supported for all glasses."
|
||||
msgstr "El modo pantalla ancha no está soportado en todas las gafas."
|
||||
"Habilita automáticamente el efecto Breezy Desktop XR cuando se conectan "
|
||||
"gafas compatibles."
|
||||
|
||||
#: src/gtk/no-driver.ui:13
|
||||
msgid "No driver running"
|
||||
|
|
@ -518,3 +619,60 @@ msgstr "Reinicio forzoso"
|
|||
#: src/gtk/window.ui:99
|
||||
msgid "About BreezyDesktop"
|
||||
msgstr "Acerca de BreezyDesktop"
|
||||
|
||||
#~ msgid "Fast SBS mode switching"
|
||||
#~ msgstr "Cambio rápido de modo SBS"
|
||||
|
||||
#~ msgid ""
|
||||
#~ "Switches glasses to SBS mode immediately when plugged in, if widescreen "
|
||||
#~ "mode is on. May cause instability."
|
||||
#~ msgstr ""
|
||||
#~ "Cambia las gafas al modo SBS (lado a lado) inmediatamente cuando se "
|
||||
#~ "enchufan, si el modo de pantalla ancha está activado. Puede causar "
|
||||
#~ "inestabilidad."
|
||||
|
||||
#, fuzzy
|
||||
#~ msgid "Set Unfocused Displays Distance"
|
||||
#~ msgstr "Distancia de la pantalla"
|
||||
|
||||
#~ msgid "Widescreen mode"
|
||||
#~ msgstr "Modo pantalla ancha"
|
||||
|
||||
#~ msgid "Switch between flat and curved displays."
|
||||
#~ msgstr "Cambiar entre pantallas planas y curvadas."
|
||||
|
||||
#~ msgid ""
|
||||
#~ "Closer appears larger, further appears smaller. Controls depth when in "
|
||||
#~ "widescreen mode."
|
||||
#~ msgstr ""
|
||||
#~ "Más cerca parece más grande, más lejos parece más pequeño. Controla la "
|
||||
#~ "profundidad cuando está en modo de pantalla ancha."
|
||||
|
||||
#~ msgid ""
|
||||
#~ "Combine with display distance to achieve a comfortable level of depth and "
|
||||
#~ "size."
|
||||
#~ msgstr ""
|
||||
#~ "Combínalo con la distancia de la pantalla para lograr un nivel cómodo de "
|
||||
#~ "profundidad y tamaño."
|
||||
|
||||
#~ msgid "Display toggle distances"
|
||||
#~ msgstr "Distancias de alternancia de pantalla"
|
||||
|
||||
#~ msgid ""
|
||||
#~ "Use the buttons to capture the current display distance for use with the "
|
||||
#~ "keyboard shortcut."
|
||||
#~ msgstr ""
|
||||
#~ "Utilice los botones para capturar la distancia actual de la pantalla para "
|
||||
#~ "su uso con el método abreviado de teclado."
|
||||
|
||||
#~ msgid "Display distance shortcut"
|
||||
#~ msgstr "Atajo de distancia de pantalla"
|
||||
|
||||
#~ msgid "Quickly toggle between two predefined distances."
|
||||
#~ msgstr "Cambiar rápidamente entre dos distancias predefinidas."
|
||||
|
||||
#~ msgid "Start in widescreen mode"
|
||||
#~ msgstr "Empezar en modo pantalla ancha"
|
||||
|
||||
#~ msgid "Widescreen mode is not supported for all glasses."
|
||||
#~ msgstr "El modo pantalla ancha no está soportado en todas las gafas."
|
||||
|
|
|
|||
355
ui/po/fr.po
355
ui/po/fr.po
|
|
@ -7,7 +7,7 @@ msgid ""
|
|||
msgstr ""
|
||||
"Project-Id-Version: PACKAGE VERSION\n"
|
||||
"Report-Msgid-Bugs-To: \n"
|
||||
"POT-Creation-Date: 2024-10-22 13:27-0700\n"
|
||||
"POT-Creation-Date: 2025-03-05 12:28-0800\n"
|
||||
"PO-Revision-Date: 2024-08-02 20:54-0700\n"
|
||||
"Last-Translator: <wayne@xronlinux.com>\n"
|
||||
"Language-Team: French <traduc@traduc.org>\n"
|
||||
|
|
@ -17,7 +17,7 @@ msgstr ""
|
|||
"Content-Transfer-Encoding: 8bit\n"
|
||||
"Plural-Forms: nplurals=2; plural=(n > 1);\n"
|
||||
|
||||
#: src/connecteddevice.py:17
|
||||
#: src/connecteddevice.py:23
|
||||
msgid ""
|
||||
"Switches your glasses into side-by-side mode and doubles the width of the "
|
||||
"display."
|
||||
|
|
@ -25,12 +25,58 @@ msgstr ""
|
|||
"Basculez vos lunettes en mode Side-By-Side (Côte-à-Côte) et doublez la "
|
||||
"largeur de l'écran."
|
||||
|
||||
#: src/connecteddevice.py:18
|
||||
#: src/connecteddevice.py:24
|
||||
msgid "This feature is not currently supported for your device."
|
||||
msgstr ""
|
||||
"Cette fonctionnalité n'est actuellement pas prise en charge par votre "
|
||||
"appareil."
|
||||
|
||||
#: src/connecteddevice.py:124
|
||||
#, fuzzy
|
||||
msgid "Set Focused Display Distance"
|
||||
msgstr "Distance d'affichage"
|
||||
|
||||
#: src/connecteddevice.py:125
|
||||
msgid "Use a closer value so the display zooms in when you look at it."
|
||||
msgstr ""
|
||||
|
||||
#: src/connecteddevice.py:132
|
||||
#, fuzzy
|
||||
msgid "Set All Displays Distance"
|
||||
msgstr "Distance d'affichage"
|
||||
|
||||
#: src/connecteddevice.py:133
|
||||
msgid "Use a farther value so the displays are zoomed out when you look away."
|
||||
msgstr ""
|
||||
|
||||
#: src/connecteddevice.py:231
|
||||
msgid ""
|
||||
"Unable to add virtual displays on this machine. xdg-desktop-portal is "
|
||||
"required."
|
||||
msgstr ""
|
||||
|
||||
#: src/connecteddevice.py:265
|
||||
#, fuzzy
|
||||
msgid "Focused display"
|
||||
msgstr "Distance d'affichage"
|
||||
|
||||
#: src/connecteddevice.py:271
|
||||
#, fuzzy
|
||||
msgid "All displays"
|
||||
msgstr "Affichage incurvé"
|
||||
|
||||
#: src/displaydistancedialogcontent.py:41
|
||||
msgid "closer"
|
||||
msgstr ""
|
||||
|
||||
#: src/displaydistancedialogcontent.py:45
|
||||
msgid "fullscreen"
|
||||
msgstr ""
|
||||
|
||||
#: src/displaydistancedialogcontent.py:48
|
||||
msgid "farther"
|
||||
msgstr ""
|
||||
|
||||
#: src/licensedialogcontent.py:63
|
||||
msgid "Paid Tier Status"
|
||||
msgstr "Statut de l'abonnement payant"
|
||||
|
|
@ -39,7 +85,7 @@ msgstr "Statut de l'abonnement payant"
|
|||
msgid "Feature Availability"
|
||||
msgstr "Disponibilité des fonctionnalités"
|
||||
|
||||
#: src/licensefeaturerow.py:15 src/shortcutdialog.py:107
|
||||
#: src/licensefeaturerow.py:15 src/shortcutdialog.py:104
|
||||
msgid "Disabled"
|
||||
msgstr "Désactivé"
|
||||
|
||||
|
|
@ -168,126 +214,185 @@ msgid "Enables the Breezy Desktop XR effect."
|
|||
msgstr "Active l'effet Breezy Desktop XR."
|
||||
|
||||
#: src/gtk/connected-device.ui:55
|
||||
msgid "Widescreen mode"
|
||||
msgstr "Mode grand écran"
|
||||
msgid "Zoom on focus"
|
||||
msgstr ""
|
||||
|
||||
#: src/gtk/connected-device.ui:66
|
||||
#: src/gtk/connected-device.ui:56
|
||||
msgid ""
|
||||
"Automatically move a display closer when you look at it.\n"
|
||||
"Set your preferred focused and unfocused distances in the Adjustments "
|
||||
"section.\n"
|
||||
" "
|
||||
msgstr ""
|
||||
|
||||
#: src/gtk/connected-device.ui:69
|
||||
msgid "Follow mode"
|
||||
msgstr "Mode de suivi"
|
||||
|
||||
#: src/gtk/connected-device.ui:67
|
||||
msgid "Keep the virtual display near the center of your view."
|
||||
#: src/gtk/connected-device.ui:70
|
||||
#, fuzzy
|
||||
msgid "Keep the focused display near the center of your view."
|
||||
msgstr "Gardez l'affichage virtuel près du centre de votre champ de vision."
|
||||
|
||||
#: src/gtk/connected-device.ui:77
|
||||
msgid "Curved display"
|
||||
msgstr "Affichage incurvé"
|
||||
#: src/gtk/connected-device.ui:80 src/gtk/no-device.ui:34
|
||||
msgid "Disable physical displays"
|
||||
msgstr ""
|
||||
|
||||
#: src/gtk/connected-device.ui:78
|
||||
msgid "Switch between flat and curved displays."
|
||||
msgstr "Basculez entre les affichages plats et incurvés."
|
||||
#: src/gtk/connected-device.ui:81 src/gtk/no-device.ui:35
|
||||
msgid ""
|
||||
"Automatically disable all physical displays when the XR effect is enabled."
|
||||
msgstr ""
|
||||
|
||||
#: src/gtk/connected-device.ui:91
|
||||
#, fuzzy
|
||||
msgid "Virtual displays"
|
||||
msgstr "Affichage incurvé"
|
||||
|
||||
#: src/gtk/connected-device.ui:103
|
||||
#, fuzzy
|
||||
msgid "Rearrange displays"
|
||||
msgstr "Affichage incurvé"
|
||||
|
||||
#: src/gtk/connected-device.ui:115
|
||||
msgid "1080p"
|
||||
msgstr ""
|
||||
|
||||
#: src/gtk/connected-device.ui:116
|
||||
msgid "1440p"
|
||||
msgstr ""
|
||||
|
||||
#: src/gtk/connected-device.ui:140
|
||||
msgid "Adjustments"
|
||||
msgstr "Réglages"
|
||||
|
||||
#: src/gtk/connected-device.ui:94
|
||||
msgid "Display distance"
|
||||
#: src/gtk/connected-device.ui:143
|
||||
#, fuzzy
|
||||
msgid "Display distances"
|
||||
msgstr "Distance d'affichage"
|
||||
|
||||
#: src/gtk/connected-device.ui:95
|
||||
msgid ""
|
||||
"Closer appears larger, further appears smaller. Controls depth when in "
|
||||
"widescreen mode."
|
||||
#: src/gtk/connected-device.ui:144
|
||||
msgid "Set how close you want displays to appear."
|
||||
msgstr ""
|
||||
"Plus proche apparaît plus grand, plus éloigné apparaît plus petit. Contrôle "
|
||||
"la profondeur lorsque vous êtes en mode grand écran."
|
||||
|
||||
#: src/gtk/connected-device.ui:123
|
||||
msgid "Display size"
|
||||
msgstr "Taille de l'affichage"
|
||||
|
||||
#: src/gtk/connected-device.ui:124
|
||||
msgid ""
|
||||
"Combine with display distance to achieve a comfortable level of depth and "
|
||||
"size."
|
||||
msgstr ""
|
||||
"Combinez avec la distance d'affichage pour obtenir un niveau de profondeur "
|
||||
"et de taille confortable."
|
||||
|
||||
#: src/gtk/connected-device.ui:152
|
||||
msgid "Display toggle distances"
|
||||
msgstr "Distances de basculement de l'affichage"
|
||||
|
||||
#: src/gtk/connected-device.ui:153
|
||||
msgid ""
|
||||
"Use the buttons to capture the current display distance for use with the "
|
||||
"keyboard shortcut."
|
||||
msgstr ""
|
||||
"Utilisez les boutons pour capturer la distance d'affichage actuelle pour une "
|
||||
"utilisation avec le raccourci clavier."
|
||||
|
||||
#: src/gtk/connected-device.ui:178
|
||||
#: src/gtk/connected-device.ui:199
|
||||
msgid "Follow threshold"
|
||||
msgstr "Seuil de suivi"
|
||||
|
||||
#: src/gtk/connected-device.ui:179
|
||||
#: src/gtk/connected-device.ui:200
|
||||
msgid "How far away you can look before the display follows."
|
||||
msgstr "Distance jusqu'où vous pouvez regarder avant que l'affichage ne suive."
|
||||
|
||||
#: src/gtk/connected-device.ui:209 src/gtk/connected-device.ui:215
|
||||
#: src/gtk/connected-device.ui:223
|
||||
#, fuzzy
|
||||
msgid "Display angling"
|
||||
msgstr "Taille de l'affichage"
|
||||
|
||||
#: src/gtk/connected-device.ui:224
|
||||
msgid ""
|
||||
"When there are multiple displays, choose how they should angle towards you."
|
||||
msgstr ""
|
||||
|
||||
#: src/gtk/connected-device.ui:238
|
||||
msgid "Automatic"
|
||||
msgstr ""
|
||||
|
||||
#: src/gtk/connected-device.ui:239
|
||||
msgid "Side-angled"
|
||||
msgstr ""
|
||||
|
||||
#: src/gtk/connected-device.ui:240
|
||||
msgid "Top-angled"
|
||||
msgstr ""
|
||||
|
||||
#: src/gtk/connected-device.ui:241
|
||||
msgid "Flat"
|
||||
msgstr ""
|
||||
|
||||
#: src/gtk/connected-device.ui:251
|
||||
#, fuzzy
|
||||
msgid "Display spacing"
|
||||
msgstr "Taille de l'affichage"
|
||||
|
||||
#: src/gtk/connected-device.ui:252
|
||||
msgid "Put empty space between displays, when there are multiple."
|
||||
msgstr ""
|
||||
|
||||
#: src/gtk/connected-device.ui:282
|
||||
msgid "Viewport horizontal offset"
|
||||
msgstr ""
|
||||
|
||||
#: src/gtk/connected-device.ui:283
|
||||
msgid ""
|
||||
"By default, the viewport will center on the primary display. Use this slider "
|
||||
"to move the viewport to the left or right."
|
||||
msgstr ""
|
||||
|
||||
#: src/gtk/connected-device.ui:312
|
||||
msgid "Viewport vertical offset"
|
||||
msgstr ""
|
||||
|
||||
#: src/gtk/connected-device.ui:313
|
||||
msgid ""
|
||||
"By default, the viewport will center on the primary display. Use this slider "
|
||||
"to move the viewport up or down."
|
||||
msgstr ""
|
||||
|
||||
#: src/gtk/connected-device.ui:349 src/gtk/connected-device.ui:355
|
||||
msgid "Keyboard Shortcuts"
|
||||
msgstr "Raccourcis clavier"
|
||||
|
||||
#: src/gtk/connected-device.ui:218
|
||||
#: src/gtk/connected-device.ui:358
|
||||
msgid "XR Effect on/off shortcut"
|
||||
msgstr "Raccourci on/off de l'effet XR"
|
||||
|
||||
#: src/gtk/connected-device.ui:219
|
||||
#: src/gtk/connected-device.ui:359
|
||||
msgid ""
|
||||
"Quickly enable or disable the XR Effect. You may need to enable the effect "
|
||||
"manually once in order to enable the shortcut."
|
||||
msgstr "Activez ou désactivez rapidement l'effet XR. Il se peut que vous deviez "
|
||||
msgstr ""
|
||||
"Activez ou désactivez rapidement l'effet XR. Il se peut que vous deviez "
|
||||
"activer l'effet manuellement une fois pour activer le raccourci."
|
||||
|
||||
#: src/gtk/connected-device.ui:238 src/gtk/connected-device.ui:267
|
||||
#: src/gtk/connected-device.ui:296 src/gtk/connected-device.ui:325
|
||||
#: src/gtk/connected-device.ui:378 src/gtk/connected-device.ui:407
|
||||
#: src/gtk/connected-device.ui:436 src/gtk/connected-device.ui:465
|
||||
msgid "Change"
|
||||
msgstr "Changer"
|
||||
|
||||
#: src/gtk/connected-device.ui:247
|
||||
#: src/gtk/connected-device.ui:387
|
||||
msgid "Re-center display shortcut"
|
||||
msgstr "Raccourci de recentrage de l'affichage"
|
||||
|
||||
#: src/gtk/connected-device.ui:248
|
||||
#: src/gtk/connected-device.ui:388
|
||||
msgid "Pin the virtual display to the current position."
|
||||
msgstr "Fixez l'affichage virtuel à la position actuelle."
|
||||
|
||||
#: src/gtk/connected-device.ui:276
|
||||
msgid "Display distance shortcut"
|
||||
msgstr "Raccourci de distance d'affichage"
|
||||
#: src/gtk/connected-device.ui:416
|
||||
#, fuzzy
|
||||
msgid "Toggle zoom on focus shortcut"
|
||||
msgstr "Raccourci de basculement du mode de suivi"
|
||||
|
||||
#: src/gtk/connected-device.ui:277
|
||||
msgid "Quickly toggle between two predefined distances."
|
||||
msgstr "Basculez rapidement entre deux distances prédéfinies."
|
||||
#: src/gtk/connected-device.ui:417
|
||||
#, fuzzy
|
||||
msgid "Quickly toggle zoom on focus mode."
|
||||
msgstr "Basculer rapidement le mode de suivi."
|
||||
|
||||
#: src/gtk/connected-device.ui:305
|
||||
#: src/gtk/connected-device.ui:445
|
||||
msgid "Toggle follow mode shortcut"
|
||||
msgstr "Raccourci de basculement du mode de suivi"
|
||||
|
||||
#: src/gtk/connected-device.ui:306
|
||||
#: src/gtk/connected-device.ui:446
|
||||
msgid "Quickly toggle follow mode."
|
||||
msgstr "Basculer rapidement le mode de suivi."
|
||||
|
||||
#: src/gtk/connected-device.ui:341 src/gtk/connected-device.ui:347
|
||||
#: src/gtk/connected-device.ui:481 src/gtk/connected-device.ui:487
|
||||
msgid "Advanced Settings"
|
||||
msgstr "Paramètres avancés"
|
||||
|
||||
#: src/gtk/connected-device.ui:350
|
||||
#: src/gtk/connected-device.ui:490
|
||||
msgid "Find optimal display config"
|
||||
msgstr "Trouver la configuration d'affichage optimale"
|
||||
|
||||
#: src/gtk/connected-device.ui:351
|
||||
#: src/gtk/connected-device.ui:491
|
||||
msgid ""
|
||||
"Automatically modify the glasses display configuration for maximum "
|
||||
"resolution and best scaling when plugged in."
|
||||
|
|
@ -296,43 +401,31 @@ msgstr ""
|
|||
"résolution maximale et une meilleure mise à l'échelle lorsque elles sont "
|
||||
"branchées."
|
||||
|
||||
#: src/gtk/connected-device.ui:361
|
||||
#: src/gtk/connected-device.ui:501
|
||||
msgid "Use highest refresh rate"
|
||||
msgstr "Utiliser le taux de rafraîchissement le plus élevé"
|
||||
|
||||
#: src/gtk/connected-device.ui:362
|
||||
#: src/gtk/connected-device.ui:502
|
||||
msgid "Refresh rate may affect performance, disable this to set it manually."
|
||||
msgstr ""
|
||||
"Un taux de rafraîchissement élevé peut affecter les performances, désactivez-"
|
||||
"le pour le définir manuellement."
|
||||
|
||||
#: src/gtk/connected-device.ui:372
|
||||
#: src/gtk/connected-device.ui:512
|
||||
msgid "Always primary display"
|
||||
msgstr "Affichage principal en permanence"
|
||||
|
||||
#: src/gtk/connected-device.ui:373
|
||||
#: src/gtk/connected-device.ui:513
|
||||
msgid "Automatically set the glasses as the primary display when plugged in."
|
||||
msgstr ""
|
||||
"Définissez automatiquement les lunettes comme affichage principal "
|
||||
"lorsqu'elles sont branchées."
|
||||
|
||||
#: src/gtk/connected-device.ui:383
|
||||
msgid "Fast SBS mode switching"
|
||||
msgstr "Bascule rapide vers le mode SBS"
|
||||
|
||||
#: src/gtk/connected-device.ui:384
|
||||
msgid ""
|
||||
"Switches glasses to SBS mode immediately when plugged in, if widescreen mode "
|
||||
"is on. May cause instability."
|
||||
msgstr ""
|
||||
"Bascule les lunettes vers le mode SBS immédiatement lorsqu'elles sont "
|
||||
"branchées si le mode grand écran est activé. Peut provoquer des instabilités."
|
||||
|
||||
#: src/gtk/connected-device.ui:394
|
||||
#: src/gtk/connected-device.ui:523
|
||||
msgid "Movement look-ahead"
|
||||
msgstr "Prédiction de mouvement"
|
||||
|
||||
#: src/gtk/connected-device.ui:395
|
||||
#: src/gtk/connected-device.ui:524
|
||||
msgid ""
|
||||
"Counteracts input lag by predicting head-tracking position ahead of render "
|
||||
"time. Stick with default unless virtual display drags behind your head "
|
||||
|
|
@ -342,20 +435,36 @@ msgstr ""
|
|||
"le temps de rendu. Restez sur la valeur par défaut à moins que l'affichage "
|
||||
"virtuel ne soit lent, ne saute pas ou ne soit très instable."
|
||||
|
||||
#: src/gtk/connected-device.ui:413
|
||||
#: src/gtk/connected-device.ui:542
|
||||
msgid "Default"
|
||||
msgstr "Par défaut"
|
||||
|
||||
#: src/gtk/connected-device.ui:425
|
||||
#: src/gtk/connected-device.ui:554
|
||||
msgid "Text Scaling"
|
||||
msgstr "Mise à l'échelle du texte"
|
||||
|
||||
#: src/gtk/connected-device.ui:426
|
||||
#: src/gtk/connected-device.ui:555
|
||||
msgid "Scaling text below 1.0 will simulate a higher resolution display"
|
||||
msgstr ""
|
||||
"Une mise à l'échelle du texte en dessous de 1.0 simulera un affichage de "
|
||||
"plus haute résolution"
|
||||
|
||||
#: src/gtk/connected-device.ui:585
|
||||
msgid "Enable multi-tap detection"
|
||||
msgstr ""
|
||||
|
||||
#: src/gtk/connected-device.ui:586
|
||||
msgid "Enables double-tap to recenter and triple-tap to recalibrate."
|
||||
msgstr ""
|
||||
|
||||
#: src/gtk/display-distance-dialog.ui:9
|
||||
msgid "Show full range"
|
||||
msgstr ""
|
||||
|
||||
#: src/gtk/display-distance-dialog.ui:18
|
||||
msgid "Done"
|
||||
msgstr ""
|
||||
|
||||
#: src/gtk/failed-verification.ui:13
|
||||
msgid "Breezy Desktop GNOME invalid setup"
|
||||
msgstr "Configuration Breezy Desktop GNOME non valide"
|
||||
|
|
@ -401,17 +510,10 @@ msgstr "Activation automatique de l'effet XR"
|
|||
msgid ""
|
||||
"Automatically enable the Breezy Desktop XR effect when supported glasses are "
|
||||
"connected."
|
||||
msgstr "Activer automatiquement l'effet Breezy Desktop XR lorsque des lunettes "
|
||||
msgstr ""
|
||||
"Activer automatiquement l'effet Breezy Desktop XR lorsque des lunettes "
|
||||
"compatibles sont connectées."
|
||||
|
||||
#: src/gtk/no-device.ui:34
|
||||
msgid "Start in widescreen mode"
|
||||
msgstr "Démarer en mode grand écran"
|
||||
|
||||
#: src/gtk/no-device.ui:35
|
||||
msgid "Widescreen mode is not supported for all glasses."
|
||||
msgstr "Le mode écran large n'est pas compatible avec toutes les lunettes."
|
||||
|
||||
#: src/gtk/no-driver.ui:13
|
||||
msgid "No driver running"
|
||||
msgstr "Aucun pilote en cours d'exécution"
|
||||
|
|
@ -521,3 +623,60 @@ msgstr "Réinitialiser"
|
|||
#: src/gtk/window.ui:99
|
||||
msgid "About BreezyDesktop"
|
||||
msgstr "À propos de BreezyDesktop"
|
||||
|
||||
#~ msgid "Fast SBS mode switching"
|
||||
#~ msgstr "Bascule rapide vers le mode SBS"
|
||||
|
||||
#~ msgid ""
|
||||
#~ "Switches glasses to SBS mode immediately when plugged in, if widescreen "
|
||||
#~ "mode is on. May cause instability."
|
||||
#~ msgstr ""
|
||||
#~ "Bascule les lunettes vers le mode SBS immédiatement lorsqu'elles sont "
|
||||
#~ "branchées si le mode grand écran est activé. Peut provoquer des "
|
||||
#~ "instabilités."
|
||||
|
||||
#, fuzzy
|
||||
#~ msgid "Set Unfocused Displays Distance"
|
||||
#~ msgstr "Distance d'affichage"
|
||||
|
||||
#~ msgid "Widescreen mode"
|
||||
#~ msgstr "Mode grand écran"
|
||||
|
||||
#~ msgid "Switch between flat and curved displays."
|
||||
#~ msgstr "Basculez entre les affichages plats et incurvés."
|
||||
|
||||
#~ msgid ""
|
||||
#~ "Closer appears larger, further appears smaller. Controls depth when in "
|
||||
#~ "widescreen mode."
|
||||
#~ msgstr ""
|
||||
#~ "Plus proche apparaît plus grand, plus éloigné apparaît plus petit. "
|
||||
#~ "Contrôle la profondeur lorsque vous êtes en mode grand écran."
|
||||
|
||||
#~ msgid ""
|
||||
#~ "Combine with display distance to achieve a comfortable level of depth and "
|
||||
#~ "size."
|
||||
#~ msgstr ""
|
||||
#~ "Combinez avec la distance d'affichage pour obtenir un niveau de "
|
||||
#~ "profondeur et de taille confortable."
|
||||
|
||||
#~ msgid "Display toggle distances"
|
||||
#~ msgstr "Distances de basculement de l'affichage"
|
||||
|
||||
#~ msgid ""
|
||||
#~ "Use the buttons to capture the current display distance for use with the "
|
||||
#~ "keyboard shortcut."
|
||||
#~ msgstr ""
|
||||
#~ "Utilisez les boutons pour capturer la distance d'affichage actuelle pour "
|
||||
#~ "une utilisation avec le raccourci clavier."
|
||||
|
||||
#~ msgid "Display distance shortcut"
|
||||
#~ msgstr "Raccourci de distance d'affichage"
|
||||
|
||||
#~ msgid "Quickly toggle between two predefined distances."
|
||||
#~ msgstr "Basculez rapidement entre deux distances prédéfinies."
|
||||
|
||||
#~ msgid "Start in widescreen mode"
|
||||
#~ msgstr "Démarer en mode grand écran"
|
||||
|
||||
#~ msgid "Widescreen mode is not supported for all glasses."
|
||||
#~ msgstr "Le mode écran large n'est pas compatible avec toutes les lunettes."
|
||||
|
|
|
|||
401
ui/po/it.po
401
ui/po/it.po
|
|
@ -7,7 +7,7 @@ msgid ""
|
|||
msgstr ""
|
||||
"Project-Id-Version: PACKAGE VERSION\n"
|
||||
"Report-Msgid-Bugs-To: \n"
|
||||
"POT-Creation-Date: 2024-10-22 13:27-0700\n"
|
||||
"POT-Creation-Date: 2025-03-05 12:28-0800\n"
|
||||
"PO-Revision-Date: 2024-08-02 21:14-0700\n"
|
||||
"Last-Translator: <wayne@xronlinux.com>\n"
|
||||
"Language-Team: Italian <tp@lists.linux.it>\n"
|
||||
|
|
@ -17,17 +17,64 @@ msgstr ""
|
|||
"Content-Transfer-Encoding: 8bit\n"
|
||||
"Plural-Forms: nplurals=2; plural=(n != 1);\n"
|
||||
|
||||
#: src/connecteddevice.py:17
|
||||
#: src/connecteddevice.py:23
|
||||
msgid ""
|
||||
"Switches your glasses into side-by-side mode and doubles the width of the "
|
||||
"display."
|
||||
msgstr ""
|
||||
"Passa i tuoi occhiali in modalità side-by-side e raddoppia la larghezza del display."
|
||||
"Passa i tuoi occhiali in modalità side-by-side e raddoppia la larghezza del "
|
||||
"display."
|
||||
|
||||
#: src/connecteddevice.py:18
|
||||
#: src/connecteddevice.py:24
|
||||
msgid "This feature is not currently supported for your device."
|
||||
msgstr "Questa funzione non è attualmente supportata sul tuo dispositivo."
|
||||
|
||||
#: src/connecteddevice.py:124
|
||||
#, fuzzy
|
||||
msgid "Set Focused Display Distance"
|
||||
msgstr "Distanza del display"
|
||||
|
||||
#: src/connecteddevice.py:125
|
||||
msgid "Use a closer value so the display zooms in when you look at it."
|
||||
msgstr ""
|
||||
|
||||
#: src/connecteddevice.py:132
|
||||
#, fuzzy
|
||||
msgid "Set All Displays Distance"
|
||||
msgstr "Distanza del display"
|
||||
|
||||
#: src/connecteddevice.py:133
|
||||
msgid "Use a farther value so the displays are zoomed out when you look away."
|
||||
msgstr ""
|
||||
|
||||
#: src/connecteddevice.py:231
|
||||
msgid ""
|
||||
"Unable to add virtual displays on this machine. xdg-desktop-portal is "
|
||||
"required."
|
||||
msgstr ""
|
||||
|
||||
#: src/connecteddevice.py:265
|
||||
#, fuzzy
|
||||
msgid "Focused display"
|
||||
msgstr "Distanza del display"
|
||||
|
||||
#: src/connecteddevice.py:271
|
||||
#, fuzzy
|
||||
msgid "All displays"
|
||||
msgstr "Display curvo"
|
||||
|
||||
#: src/displaydistancedialogcontent.py:41
|
||||
msgid "closer"
|
||||
msgstr ""
|
||||
|
||||
#: src/displaydistancedialogcontent.py:45
|
||||
msgid "fullscreen"
|
||||
msgstr ""
|
||||
|
||||
#: src/displaydistancedialogcontent.py:48
|
||||
msgid "farther"
|
||||
msgstr ""
|
||||
|
||||
#: src/licensedialogcontent.py:63
|
||||
msgid "Paid Tier Status"
|
||||
msgstr "Stato del livello a pagamento"
|
||||
|
|
@ -36,7 +83,7 @@ msgstr "Stato del livello a pagamento"
|
|||
msgid "Feature Availability"
|
||||
msgstr "Disponibilità delle funzionalità"
|
||||
|
||||
#: src/licensefeaturerow.py:15 src/shortcutdialog.py:107
|
||||
#: src/licensefeaturerow.py:15 src/shortcutdialog.py:104
|
||||
msgid "Disabled"
|
||||
msgstr "Disabilitato"
|
||||
|
||||
|
|
@ -165,178 +212,257 @@ msgid "Enables the Breezy Desktop XR effect."
|
|||
msgstr "Abilita l'effetto XR di Breezy Desktop."
|
||||
|
||||
#: src/gtk/connected-device.ui:55
|
||||
msgid "Widescreen mode"
|
||||
msgstr "Modalità widescreen"
|
||||
msgid "Zoom on focus"
|
||||
msgstr ""
|
||||
|
||||
#: src/gtk/connected-device.ui:66
|
||||
#: src/gtk/connected-device.ui:56
|
||||
msgid ""
|
||||
"Automatically move a display closer when you look at it.\n"
|
||||
"Set your preferred focused and unfocused distances in the Adjustments "
|
||||
"section.\n"
|
||||
" "
|
||||
msgstr ""
|
||||
|
||||
#: src/gtk/connected-device.ui:69
|
||||
msgid "Follow mode"
|
||||
msgstr "Modalità di inseguimento"
|
||||
|
||||
#: src/gtk/connected-device.ui:67
|
||||
msgid "Keep the virtual display near the center of your view."
|
||||
#: src/gtk/connected-device.ui:70
|
||||
#, fuzzy
|
||||
msgid "Keep the focused display near the center of your view."
|
||||
msgstr "Mantieni il display virtuale vicino al centro del tuo campo visivo."
|
||||
|
||||
#: src/gtk/connected-device.ui:77
|
||||
msgid "Curved display"
|
||||
msgstr "Display curvo"
|
||||
#: src/gtk/connected-device.ui:80 src/gtk/no-device.ui:34
|
||||
msgid "Disable physical displays"
|
||||
msgstr ""
|
||||
|
||||
#: src/gtk/connected-device.ui:78
|
||||
msgid "Switch between flat and curved displays."
|
||||
msgstr "Passa da display piatti a curvi."
|
||||
#: src/gtk/connected-device.ui:81 src/gtk/no-device.ui:35
|
||||
msgid ""
|
||||
"Automatically disable all physical displays when the XR effect is enabled."
|
||||
msgstr ""
|
||||
|
||||
#: src/gtk/connected-device.ui:91
|
||||
#, fuzzy
|
||||
msgid "Virtual displays"
|
||||
msgstr "Display curvo"
|
||||
|
||||
#: src/gtk/connected-device.ui:103
|
||||
#, fuzzy
|
||||
msgid "Rearrange displays"
|
||||
msgstr "Display curvo"
|
||||
|
||||
#: src/gtk/connected-device.ui:115
|
||||
msgid "1080p"
|
||||
msgstr ""
|
||||
|
||||
#: src/gtk/connected-device.ui:116
|
||||
msgid "1440p"
|
||||
msgstr ""
|
||||
|
||||
#: src/gtk/connected-device.ui:140
|
||||
msgid "Adjustments"
|
||||
msgstr "Regolazioni"
|
||||
|
||||
#: src/gtk/connected-device.ui:94
|
||||
msgid "Display distance"
|
||||
#: src/gtk/connected-device.ui:143
|
||||
#, fuzzy
|
||||
msgid "Display distances"
|
||||
msgstr "Distanza del display"
|
||||
|
||||
#: src/gtk/connected-device.ui:95
|
||||
msgid ""
|
||||
"Closer appears larger, further appears smaller. Controls depth when in "
|
||||
"widescreen mode."
|
||||
#: src/gtk/connected-device.ui:144
|
||||
msgid "Set how close you want displays to appear."
|
||||
msgstr ""
|
||||
"Più vicino appare più grande, più lontano appare più piccolo. Controlla la profondità quando sei in modalità widescreen."
|
||||
|
||||
#: src/gtk/connected-device.ui:123
|
||||
msgid "Display size"
|
||||
msgstr "Dimensione del display"
|
||||
|
||||
#: src/gtk/connected-device.ui:124
|
||||
msgid ""
|
||||
"Combine with display distance to achieve a comfortable level of depth and "
|
||||
"size."
|
||||
msgstr ""
|
||||
"Da combinare con la distanza del display per ottenere un livello confortevole di profondità e dimensione."
|
||||
|
||||
#: src/gtk/connected-device.ui:152
|
||||
msgid "Display toggle distances"
|
||||
msgstr "Distanze di attivazione del cambio display"
|
||||
|
||||
#: src/gtk/connected-device.ui:153
|
||||
msgid ""
|
||||
"Use the buttons to capture the current display distance for use with the "
|
||||
"keyboard shortcut."
|
||||
msgstr ""
|
||||
"Usa i pulsanti per acquisire la distanza attuale del display da utilizzare con la scorciatoia da tastiera."
|
||||
|
||||
#: src/gtk/connected-device.ui:178
|
||||
#: src/gtk/connected-device.ui:199
|
||||
msgid "Follow threshold"
|
||||
msgstr "Soglia di inseguimento"
|
||||
|
||||
#: src/gtk/connected-device.ui:179
|
||||
#: src/gtk/connected-device.ui:200
|
||||
msgid "How far away you can look before the display follows."
|
||||
msgstr "Quanto lontano puoi guardare prima che il display ti segua."
|
||||
|
||||
#: src/gtk/connected-device.ui:209 src/gtk/connected-device.ui:215
|
||||
#: src/gtk/connected-device.ui:223
|
||||
#, fuzzy
|
||||
msgid "Display angling"
|
||||
msgstr "Dimensione del display"
|
||||
|
||||
#: src/gtk/connected-device.ui:224
|
||||
msgid ""
|
||||
"When there are multiple displays, choose how they should angle towards you."
|
||||
msgstr ""
|
||||
|
||||
#: src/gtk/connected-device.ui:238
|
||||
msgid "Automatic"
|
||||
msgstr ""
|
||||
|
||||
#: src/gtk/connected-device.ui:239
|
||||
msgid "Side-angled"
|
||||
msgstr ""
|
||||
|
||||
#: src/gtk/connected-device.ui:240
|
||||
msgid "Top-angled"
|
||||
msgstr ""
|
||||
|
||||
#: src/gtk/connected-device.ui:241
|
||||
msgid "Flat"
|
||||
msgstr ""
|
||||
|
||||
#: src/gtk/connected-device.ui:251
|
||||
#, fuzzy
|
||||
msgid "Display spacing"
|
||||
msgstr "Dimensione del display"
|
||||
|
||||
#: src/gtk/connected-device.ui:252
|
||||
msgid "Put empty space between displays, when there are multiple."
|
||||
msgstr ""
|
||||
|
||||
#: src/gtk/connected-device.ui:282
|
||||
msgid "Viewport horizontal offset"
|
||||
msgstr ""
|
||||
|
||||
#: src/gtk/connected-device.ui:283
|
||||
msgid ""
|
||||
"By default, the viewport will center on the primary display. Use this slider "
|
||||
"to move the viewport to the left or right."
|
||||
msgstr ""
|
||||
|
||||
#: src/gtk/connected-device.ui:312
|
||||
msgid "Viewport vertical offset"
|
||||
msgstr ""
|
||||
|
||||
#: src/gtk/connected-device.ui:313
|
||||
msgid ""
|
||||
"By default, the viewport will center on the primary display. Use this slider "
|
||||
"to move the viewport up or down."
|
||||
msgstr ""
|
||||
|
||||
#: src/gtk/connected-device.ui:349 src/gtk/connected-device.ui:355
|
||||
msgid "Keyboard Shortcuts"
|
||||
msgstr "Scorciatoie da tastiera"
|
||||
|
||||
#: src/gtk/connected-device.ui:218
|
||||
#: src/gtk/connected-device.ui:358
|
||||
msgid "XR Effect on/off shortcut"
|
||||
msgstr "Scorciatoia per on/off dell'effetto XR"
|
||||
|
||||
#: src/gtk/connected-device.ui:219
|
||||
#: src/gtk/connected-device.ui:359
|
||||
msgid ""
|
||||
"Quickly enable or disable the XR Effect. You may need to enable the effect "
|
||||
"manually once in order to enable the shortcut."
|
||||
msgstr "Abilitazione/disabilitazione rapida dell'effetto XR. Può essere necessario abilitare l'effetto manualmente almeno una volta per abilitare la scorciatoia da tastiera."
|
||||
msgstr ""
|
||||
"Abilitazione/disabilitazione rapida dell'effetto XR. Può essere necessario "
|
||||
"abilitare l'effetto manualmente almeno una volta per abilitare la "
|
||||
"scorciatoia da tastiera."
|
||||
|
||||
#: src/gtk/connected-device.ui:238 src/gtk/connected-device.ui:267
|
||||
#: src/gtk/connected-device.ui:296 src/gtk/connected-device.ui:325
|
||||
#: src/gtk/connected-device.ui:378 src/gtk/connected-device.ui:407
|
||||
#: src/gtk/connected-device.ui:436 src/gtk/connected-device.ui:465
|
||||
msgid "Change"
|
||||
msgstr "Cambia"
|
||||
|
||||
#: src/gtk/connected-device.ui:247
|
||||
#: src/gtk/connected-device.ui:387
|
||||
msgid "Re-center display shortcut"
|
||||
msgstr "Scorciatoia per ricentrare il display"
|
||||
|
||||
#: src/gtk/connected-device.ui:248
|
||||
#: src/gtk/connected-device.ui:388
|
||||
msgid "Pin the virtual display to the current position."
|
||||
msgstr "Fissa il display virtuale alla posizione attuale."
|
||||
|
||||
#: src/gtk/connected-device.ui:276
|
||||
msgid "Display distance shortcut"
|
||||
msgstr "Scorciatoia per la distanza del display"
|
||||
#: src/gtk/connected-device.ui:416
|
||||
#, fuzzy
|
||||
msgid "Toggle zoom on focus shortcut"
|
||||
msgstr "Scorciatoia per attivare/disattivare la modalità di inseguimento"
|
||||
|
||||
#: src/gtk/connected-device.ui:277
|
||||
msgid "Quickly toggle between two predefined distances."
|
||||
msgstr "Scambio rapido tra due distanze predefinite."
|
||||
#: src/gtk/connected-device.ui:417
|
||||
#, fuzzy
|
||||
msgid "Quickly toggle zoom on focus mode."
|
||||
msgstr "Attivazione/disattivazione rapida della modalità di inseguimento."
|
||||
|
||||
#: src/gtk/connected-device.ui:305
|
||||
#: src/gtk/connected-device.ui:445
|
||||
msgid "Toggle follow mode shortcut"
|
||||
msgstr "Scorciatoia per attivare/disattivare la modalità di inseguimento"
|
||||
|
||||
#: src/gtk/connected-device.ui:306
|
||||
#: src/gtk/connected-device.ui:446
|
||||
msgid "Quickly toggle follow mode."
|
||||
msgstr "Attivazione/disattivazione rapida della modalità di inseguimento."
|
||||
|
||||
#: src/gtk/connected-device.ui:341 src/gtk/connected-device.ui:347
|
||||
#: src/gtk/connected-device.ui:481 src/gtk/connected-device.ui:487
|
||||
msgid "Advanced Settings"
|
||||
msgstr "Impostazioni avanzate"
|
||||
|
||||
#: src/gtk/connected-device.ui:350
|
||||
#: src/gtk/connected-device.ui:490
|
||||
msgid "Find optimal display config"
|
||||
msgstr "Trova la configurazione ottimale del display"
|
||||
|
||||
#: src/gtk/connected-device.ui:351
|
||||
#: src/gtk/connected-device.ui:491
|
||||
msgid ""
|
||||
"Automatically modify the glasses display configuration for maximum "
|
||||
"resolution and best scaling when plugged in."
|
||||
msgstr ""
|
||||
"Modifica automaticamente la configurazione del display degli occhiali per ottenere la massima risoluzione e la migliore scalabilità quando collegati."
|
||||
"Modifica automaticamente la configurazione del display degli occhiali per "
|
||||
"ottenere la massima risoluzione e la migliore scalabilità quando collegati."
|
||||
|
||||
#: src/gtk/connected-device.ui:361
|
||||
#: src/gtk/connected-device.ui:501
|
||||
msgid "Use highest refresh rate"
|
||||
msgstr "Usa la frequenza di aggiornamento più elevata"
|
||||
|
||||
#: src/gtk/connected-device.ui:362
|
||||
#: src/gtk/connected-device.ui:502
|
||||
msgid "Refresh rate may affect performance, disable this to set it manually."
|
||||
msgstr "La frequenza di aggiornamento potrebbe influire sulle prestazioni, disabilitala per impostarla manualmente."
|
||||
msgstr ""
|
||||
"La frequenza di aggiornamento potrebbe influire sulle prestazioni, "
|
||||
"disabilitala per impostarla manualmente."
|
||||
|
||||
#: src/gtk/connected-device.ui:372
|
||||
#: src/gtk/connected-device.ui:512
|
||||
msgid "Always primary display"
|
||||
msgstr "Imposta sempre come display primario"
|
||||
|
||||
#: src/gtk/connected-device.ui:373
|
||||
#: src/gtk/connected-device.ui:513
|
||||
msgid "Automatically set the glasses as the primary display when plugged in."
|
||||
msgstr "Imposta automaticamente gli occhiali come display primario quando sono collegati."
|
||||
|
||||
#: src/gtk/connected-device.ui:383
|
||||
msgid "Fast SBS mode switching"
|
||||
msgstr "Passaggio rapido alla modalità SBS"
|
||||
|
||||
#: src/gtk/connected-device.ui:384
|
||||
msgid ""
|
||||
"Switches glasses to SBS mode immediately when plugged in, if widescreen mode "
|
||||
"is on. May cause instability."
|
||||
msgstr ""
|
||||
"Passa immediatamente gli occhiali alla modalità SBS quando vengono collegati, se la modalità widescreen è attiva. Potrebbe causare instabilità."
|
||||
"Imposta automaticamente gli occhiali come display primario quando sono "
|
||||
"collegati."
|
||||
|
||||
#: src/gtk/connected-device.ui:394
|
||||
#: src/gtk/connected-device.ui:523
|
||||
msgid "Movement look-ahead"
|
||||
msgstr "Anticipo del movimento"
|
||||
|
||||
#: src/gtk/connected-device.ui:395
|
||||
#: src/gtk/connected-device.ui:524
|
||||
msgid ""
|
||||
"Counteracts input lag by predicting head-tracking position ahead of render "
|
||||
"time. Stick with default unless virtual display drags behind your head "
|
||||
"movements, jumps ahead, or is very shaky."
|
||||
msgstr ""
|
||||
"Compensa il ritardo di input prevedendo la posizione del tracciamento della testa prima del tempo di rendering. Rimani con il valore predefinito a meno che il display virtuale non rimanga indietro rispetto ai tuoi movimenti, non salti in avanti o sia molto tremolante."
|
||||
"Compensa il ritardo di input prevedendo la posizione del tracciamento della "
|
||||
"testa prima del tempo di rendering. Rimani con il valore predefinito a meno "
|
||||
"che il display virtuale non rimanga indietro rispetto ai tuoi movimenti, non "
|
||||
"salti in avanti o sia molto tremolante."
|
||||
|
||||
#: src/gtk/connected-device.ui:413
|
||||
#: src/gtk/connected-device.ui:542
|
||||
msgid "Default"
|
||||
msgstr "Predefinito"
|
||||
|
||||
#: src/gtk/connected-device.ui:425
|
||||
#: src/gtk/connected-device.ui:554
|
||||
msgid "Text Scaling"
|
||||
msgstr "Ridimensionamento del testo"
|
||||
|
||||
#: src/gtk/connected-device.ui:426
|
||||
#: src/gtk/connected-device.ui:555
|
||||
msgid "Scaling text below 1.0 will simulate a higher resolution display"
|
||||
msgstr "Ridimensionando il testo sotto a 1.0 si simula una maggiore risoluzione del display"
|
||||
msgstr ""
|
||||
"Ridimensionando il testo sotto a 1.0 si simula una maggiore risoluzione del "
|
||||
"display"
|
||||
|
||||
#: src/gtk/connected-device.ui:585
|
||||
msgid "Enable multi-tap detection"
|
||||
msgstr ""
|
||||
|
||||
#: src/gtk/connected-device.ui:586
|
||||
msgid "Enables double-tap to recenter and triple-tap to recalibrate."
|
||||
msgstr ""
|
||||
|
||||
#: src/gtk/display-distance-dialog.ui:9
|
||||
msgid "Show full range"
|
||||
msgstr ""
|
||||
|
||||
#: src/gtk/display-distance-dialog.ui:18
|
||||
msgid "Done"
|
||||
msgstr ""
|
||||
|
||||
#: src/gtk/failed-verification.ui:13
|
||||
msgid "Breezy Desktop GNOME invalid setup"
|
||||
|
|
@ -347,7 +473,9 @@ msgid ""
|
|||
"Your Breezy GNOME setup is invalid or incomplete. Please re-run the setup "
|
||||
"script. Report this issue if it persists."
|
||||
msgstr ""
|
||||
"La tua configurazione di Breezy GNOME non è valida o è incompleta. Ripeti l'esecuzione dello script di configurazione. Segnala questo problema se persiste."
|
||||
"La tua configurazione di Breezy GNOME non è valida o è incompleta. Ripeti "
|
||||
"l'esecuzione dello script di configurazione. Segnala questo problema se "
|
||||
"persiste."
|
||||
|
||||
#: src/gtk/license-dialog-content.ui:15
|
||||
msgid "Donate"
|
||||
|
|
@ -381,15 +509,9 @@ msgstr "Abilitazione automatica effetto XR"
|
|||
msgid ""
|
||||
"Automatically enable the Breezy Desktop XR effect when supported glasses are "
|
||||
"connected."
|
||||
msgstr "Abilita automaticamente l'effetto XR di Breezy Desktop quando vengono connessi degli occhiali supportati"
|
||||
|
||||
#: src/gtk/no-device.ui:34
|
||||
msgid "Start in widescreen mode"
|
||||
msgstr "Si attiva in modalità widescreen"
|
||||
|
||||
#: src/gtk/no-device.ui:35
|
||||
msgid "Widescreen mode is not supported for all glasses."
|
||||
msgstr "Breezy Desktop non è riuscito a rilevare alcun dispositivo XR supportato."
|
||||
msgstr ""
|
||||
"Abilita automaticamente l'effetto XR di Breezy Desktop quando vengono "
|
||||
"connessi degli occhiali supportati"
|
||||
|
||||
#: src/gtk/no-driver.ui:13
|
||||
msgid "No driver running"
|
||||
|
|
@ -407,10 +529,12 @@ msgid ""
|
|||
" "
|
||||
msgstr ""
|
||||
"\n"
|
||||
" Se hai installato tramite AUR, assicurati di aver eseguito il comando di post-installazione consigliato:\n"
|
||||
" Se hai installato tramite AUR, assicurati di aver eseguito il "
|
||||
"comando di post-installazione consigliato:\n"
|
||||
" systemctl --user enable --now xr-driver.service\n"
|
||||
"\n"
|
||||
" In caso contrario, segnala il problema su GitHub o crea un nuovo thread nel canale #troubleshooting su Discord.\n"
|
||||
" In caso contrario, segnala il problema su GitHub o crea un nuovo "
|
||||
"thread nel canale #troubleshooting su Discord.\n"
|
||||
" "
|
||||
|
||||
#: src/gtk/no-extension.ui:13
|
||||
|
|
@ -422,7 +546,9 @@ msgid ""
|
|||
"If you have just run the setup, then you may need to log out and back in to "
|
||||
"use it. Otherwise, please follow the Breezy GNOME setup instructions."
|
||||
msgstr ""
|
||||
"Se hai appena eseguito la configurazione, potrebbe essere necessario disconnettersi e riconnettersi per utilizzarla. In caso contrario, segui le istruzioni di configurazione di Breezy GNOME."
|
||||
"Se hai appena eseguito la configurazione, potrebbe essere necessario "
|
||||
"disconnettersi e riconnettersi per utilizzarla. In caso contrario, segui le "
|
||||
"istruzioni di configurazione di Breezy GNOME."
|
||||
|
||||
#: src/gtk/no-license.ui:13
|
||||
msgid "No license file was found"
|
||||
|
|
@ -444,11 +570,16 @@ msgid ""
|
|||
" "
|
||||
msgstr ""
|
||||
"\n"
|
||||
" La prima volta che utilizzi Breezy Desktop, è necessaria una connessione Internet per recuperare la licenza del tuo dispositivo.\n"
|
||||
" La prima volta che utilizzi Breezy Desktop, è necessaria una "
|
||||
"connessione Internet per recuperare la licenza del tuo dispositivo.\n"
|
||||
" \n"
|
||||
" Non preoccuparti, non è obbligatorio donare adesso. Se non lo hai già fatto, ti verrà fornita una licenza di prova in modo da poter decidere se Breezy Desktop soddisfa le tue esigenze.\n"
|
||||
" Non preoccuparti, non è obbligatorio donare adesso. Se non lo hai "
|
||||
"già fatto, ti verrà fornita una licenza di prova in modo da poter decidere "
|
||||
"se Breezy Desktop soddisfa le tue esigenze.\n"
|
||||
" \n"
|
||||
" Una volta ottenuta una licenza, di prova o altra, puoi utilizzare Breezy Desktop offline fino alla scadenza delle funzionalità (o a tempo indeterminato, se hai scelto l'accesso perpetuo).\n"
|
||||
" Una volta ottenuta una licenza, di prova o altra, puoi utilizzare "
|
||||
"Breezy Desktop offline fino alla scadenza delle funzionalità (o a tempo "
|
||||
"indeterminato, se hai scelto l'accesso perpetuo).\n"
|
||||
" "
|
||||
|
||||
#: src/gtk/no-license.ui:27
|
||||
|
|
@ -490,3 +621,61 @@ msgstr "Reset forzato"
|
|||
#: src/gtk/window.ui:99
|
||||
msgid "About BreezyDesktop"
|
||||
msgstr "Informazioni su BreezyDesktop"
|
||||
|
||||
#~ msgid "Fast SBS mode switching"
|
||||
#~ msgstr "Passaggio rapido alla modalità SBS"
|
||||
|
||||
#~ msgid ""
|
||||
#~ "Switches glasses to SBS mode immediately when plugged in, if widescreen "
|
||||
#~ "mode is on. May cause instability."
|
||||
#~ msgstr ""
|
||||
#~ "Passa immediatamente gli occhiali alla modalità SBS quando vengono "
|
||||
#~ "collegati, se la modalità widescreen è attiva. Potrebbe causare "
|
||||
#~ "instabilità."
|
||||
|
||||
#, fuzzy
|
||||
#~ msgid "Set Unfocused Displays Distance"
|
||||
#~ msgstr "Distanza del display"
|
||||
|
||||
#~ msgid "Widescreen mode"
|
||||
#~ msgstr "Modalità widescreen"
|
||||
|
||||
#~ msgid "Switch between flat and curved displays."
|
||||
#~ msgstr "Passa da display piatti a curvi."
|
||||
|
||||
#~ msgid ""
|
||||
#~ "Closer appears larger, further appears smaller. Controls depth when in "
|
||||
#~ "widescreen mode."
|
||||
#~ msgstr ""
|
||||
#~ "Più vicino appare più grande, più lontano appare più piccolo. Controlla "
|
||||
#~ "la profondità quando sei in modalità widescreen."
|
||||
|
||||
#~ msgid ""
|
||||
#~ "Combine with display distance to achieve a comfortable level of depth and "
|
||||
#~ "size."
|
||||
#~ msgstr ""
|
||||
#~ "Da combinare con la distanza del display per ottenere un livello "
|
||||
#~ "confortevole di profondità e dimensione."
|
||||
|
||||
#~ msgid "Display toggle distances"
|
||||
#~ msgstr "Distanze di attivazione del cambio display"
|
||||
|
||||
#~ msgid ""
|
||||
#~ "Use the buttons to capture the current display distance for use with the "
|
||||
#~ "keyboard shortcut."
|
||||
#~ msgstr ""
|
||||
#~ "Usa i pulsanti per acquisire la distanza attuale del display da "
|
||||
#~ "utilizzare con la scorciatoia da tastiera."
|
||||
|
||||
#~ msgid "Display distance shortcut"
|
||||
#~ msgstr "Scorciatoia per la distanza del display"
|
||||
|
||||
#~ msgid "Quickly toggle between two predefined distances."
|
||||
#~ msgstr "Scambio rapido tra due distanze predefinite."
|
||||
|
||||
#~ msgid "Start in widescreen mode"
|
||||
#~ msgstr "Si attiva in modalità widescreen"
|
||||
|
||||
#~ msgid "Widescreen mode is not supported for all glasses."
|
||||
#~ msgstr ""
|
||||
#~ "Breezy Desktop non è riuscito a rilevare alcun dispositivo XR supportato."
|
||||
|
|
|
|||
352
ui/po/ja.po
352
ui/po/ja.po
|
|
@ -11,7 +11,7 @@ msgid ""
|
|||
msgstr ""
|
||||
"Project-Id-Version: PACKAGE VERSION\n"
|
||||
"Report-Msgid-Bugs-To: \n"
|
||||
"POT-Creation-Date: 2024-10-22 13:27-0700\n"
|
||||
"POT-Creation-Date: 2025-03-05 12:28-0800\n"
|
||||
"PO-Revision-Date: 2024-08-02 20:55-0700\n"
|
||||
"Last-Translator: <wayne@xronlinux.com>\n"
|
||||
"Language-Team: Japanese <translation-team-ja@lists.sourceforge.net>\n"
|
||||
|
|
@ -21,16 +21,62 @@ msgstr ""
|
|||
"Content-Transfer-Encoding: 8bit\n"
|
||||
"Plural-Forms: nplurals=1; plural=0;\n"
|
||||
|
||||
#: src/connecteddevice.py:17
|
||||
#: src/connecteddevice.py:23
|
||||
msgid ""
|
||||
"Switches your glasses into side-by-side mode and doubles the width of the "
|
||||
"display."
|
||||
msgstr "メガネを3Dモードに切り替え、表示の幅を2倍にします。"
|
||||
|
||||
#: src/connecteddevice.py:18
|
||||
#: src/connecteddevice.py:24
|
||||
msgid "This feature is not currently supported for your device."
|
||||
msgstr "現在接続されているデバイスはこの機能に対応していません。"
|
||||
|
||||
#: src/connecteddevice.py:124
|
||||
#, fuzzy
|
||||
msgid "Set Focused Display Distance"
|
||||
msgstr "ディスプレイ距離"
|
||||
|
||||
#: src/connecteddevice.py:125
|
||||
msgid "Use a closer value so the display zooms in when you look at it."
|
||||
msgstr ""
|
||||
|
||||
#: src/connecteddevice.py:132
|
||||
#, fuzzy
|
||||
msgid "Set All Displays Distance"
|
||||
msgstr "ディスプレイ距離"
|
||||
|
||||
#: src/connecteddevice.py:133
|
||||
msgid "Use a farther value so the displays are zoomed out when you look away."
|
||||
msgstr ""
|
||||
|
||||
#: src/connecteddevice.py:231
|
||||
msgid ""
|
||||
"Unable to add virtual displays on this machine. xdg-desktop-portal is "
|
||||
"required."
|
||||
msgstr ""
|
||||
|
||||
#: src/connecteddevice.py:265
|
||||
#, fuzzy
|
||||
msgid "Focused display"
|
||||
msgstr "ディスプレイ距離"
|
||||
|
||||
#: src/connecteddevice.py:271
|
||||
#, fuzzy
|
||||
msgid "All displays"
|
||||
msgstr "曲面ディスプレイ"
|
||||
|
||||
#: src/displaydistancedialogcontent.py:41
|
||||
msgid "closer"
|
||||
msgstr ""
|
||||
|
||||
#: src/displaydistancedialogcontent.py:45
|
||||
msgid "fullscreen"
|
||||
msgstr ""
|
||||
|
||||
#: src/displaydistancedialogcontent.py:48
|
||||
msgid "farther"
|
||||
msgstr ""
|
||||
|
||||
#: src/licensedialogcontent.py:63
|
||||
msgid "Paid Tier Status"
|
||||
msgstr "有料ティアの状態"
|
||||
|
|
@ -39,7 +85,7 @@ msgstr "有料ティアの状態"
|
|||
msgid "Feature Availability"
|
||||
msgstr "利用できる機能"
|
||||
|
||||
#: src/licensefeaturerow.py:15 src/shortcutdialog.py:107
|
||||
#: src/licensefeaturerow.py:15 src/shortcutdialog.py:104
|
||||
msgid "Disabled"
|
||||
msgstr "無効"
|
||||
|
||||
|
|
@ -168,82 +214,138 @@ msgid "Enables the Breezy Desktop XR effect."
|
|||
msgstr "Breezy DesktopのXRエフェクトを有効にします。"
|
||||
|
||||
#: src/gtk/connected-device.ui:55
|
||||
msgid "Widescreen mode"
|
||||
msgstr "ワイドスクリーンモード"
|
||||
msgid "Zoom on focus"
|
||||
msgstr ""
|
||||
|
||||
#: src/gtk/connected-device.ui:66
|
||||
#: src/gtk/connected-device.ui:56
|
||||
msgid ""
|
||||
"Automatically move a display closer when you look at it.\n"
|
||||
"Set your preferred focused and unfocused distances in the Adjustments "
|
||||
"section.\n"
|
||||
" "
|
||||
msgstr ""
|
||||
|
||||
#: src/gtk/connected-device.ui:69
|
||||
msgid "Follow mode"
|
||||
msgstr "フォローモード"
|
||||
|
||||
#: src/gtk/connected-device.ui:67
|
||||
msgid "Keep the virtual display near the center of your view."
|
||||
#: src/gtk/connected-device.ui:70
|
||||
#, fuzzy
|
||||
msgid "Keep the focused display near the center of your view."
|
||||
msgstr "仮想ディスプレイを視界の中心近くに保ちます。"
|
||||
|
||||
#: src/gtk/connected-device.ui:77
|
||||
msgid "Curved display"
|
||||
msgstr "曲面ディスプレイ"
|
||||
#: src/gtk/connected-device.ui:80 src/gtk/no-device.ui:34
|
||||
msgid "Disable physical displays"
|
||||
msgstr ""
|
||||
|
||||
#: src/gtk/connected-device.ui:78
|
||||
msgid "Switch between flat and curved displays."
|
||||
msgstr "平面と曲面ディスプレイを切り替えます。"
|
||||
#: src/gtk/connected-device.ui:81 src/gtk/no-device.ui:35
|
||||
msgid ""
|
||||
"Automatically disable all physical displays when the XR effect is enabled."
|
||||
msgstr ""
|
||||
|
||||
#: src/gtk/connected-device.ui:91
|
||||
#, fuzzy
|
||||
msgid "Virtual displays"
|
||||
msgstr "曲面ディスプレイ"
|
||||
|
||||
#: src/gtk/connected-device.ui:103
|
||||
#, fuzzy
|
||||
msgid "Rearrange displays"
|
||||
msgstr "曲面ディスプレイ"
|
||||
|
||||
#: src/gtk/connected-device.ui:115
|
||||
msgid "1080p"
|
||||
msgstr ""
|
||||
|
||||
#: src/gtk/connected-device.ui:116
|
||||
msgid "1440p"
|
||||
msgstr ""
|
||||
|
||||
#: src/gtk/connected-device.ui:140
|
||||
msgid "Adjustments"
|
||||
msgstr "調整"
|
||||
|
||||
#: src/gtk/connected-device.ui:94
|
||||
msgid "Display distance"
|
||||
#: src/gtk/connected-device.ui:143
|
||||
#, fuzzy
|
||||
msgid "Display distances"
|
||||
msgstr "ディスプレイ距離"
|
||||
|
||||
#: src/gtk/connected-device.ui:95
|
||||
msgid ""
|
||||
"Closer appears larger, further appears smaller. Controls depth when in "
|
||||
"widescreen mode."
|
||||
#: src/gtk/connected-device.ui:144
|
||||
msgid "Set how close you want displays to appear."
|
||||
msgstr ""
|
||||
"近づけると大きく見え、遠ざけると小さく見えます。\n"
|
||||
"ワイドスクリーンモードの奥行きを制御します。"
|
||||
|
||||
#: src/gtk/connected-device.ui:123
|
||||
msgid "Display size"
|
||||
msgstr "ディスプレイサイズ"
|
||||
|
||||
#: src/gtk/connected-device.ui:124
|
||||
msgid ""
|
||||
"Combine with display distance to achieve a comfortable level of depth and "
|
||||
"size."
|
||||
msgstr ""
|
||||
"ディスプレイ距離と組み合わせて、\n"
|
||||
"快適な奥行きとサイズを実現します。"
|
||||
|
||||
#: src/gtk/connected-device.ui:152
|
||||
msgid "Display toggle distances"
|
||||
msgstr "ディスプレイ距離の切り替え"
|
||||
|
||||
#: src/gtk/connected-device.ui:153
|
||||
msgid ""
|
||||
"Use the buttons to capture the current display distance for use with the "
|
||||
"keyboard shortcut."
|
||||
msgstr ""
|
||||
"2個のボタンを使用して、キーボードショートカットで使用する現在のディスプレイ距"
|
||||
"離をそれぞれ設定します。"
|
||||
|
||||
#: src/gtk/connected-device.ui:178
|
||||
#: src/gtk/connected-device.ui:199
|
||||
msgid "Follow threshold"
|
||||
msgstr "フォローしきい値"
|
||||
|
||||
#: src/gtk/connected-device.ui:179
|
||||
#: src/gtk/connected-device.ui:200
|
||||
msgid "How far away you can look before the display follows."
|
||||
msgstr "ディスプレイがフォロー(追従)を開始するまでの距離"
|
||||
|
||||
#: src/gtk/connected-device.ui:209 src/gtk/connected-device.ui:215
|
||||
#: src/gtk/connected-device.ui:223
|
||||
#, fuzzy
|
||||
msgid "Display angling"
|
||||
msgstr "ディスプレイサイズ"
|
||||
|
||||
#: src/gtk/connected-device.ui:224
|
||||
msgid ""
|
||||
"When there are multiple displays, choose how they should angle towards you."
|
||||
msgstr ""
|
||||
|
||||
#: src/gtk/connected-device.ui:238
|
||||
msgid "Automatic"
|
||||
msgstr ""
|
||||
|
||||
#: src/gtk/connected-device.ui:239
|
||||
msgid "Side-angled"
|
||||
msgstr ""
|
||||
|
||||
#: src/gtk/connected-device.ui:240
|
||||
msgid "Top-angled"
|
||||
msgstr ""
|
||||
|
||||
#: src/gtk/connected-device.ui:241
|
||||
msgid "Flat"
|
||||
msgstr ""
|
||||
|
||||
#: src/gtk/connected-device.ui:251
|
||||
#, fuzzy
|
||||
msgid "Display spacing"
|
||||
msgstr "ディスプレイサイズ"
|
||||
|
||||
#: src/gtk/connected-device.ui:252
|
||||
msgid "Put empty space between displays, when there are multiple."
|
||||
msgstr ""
|
||||
|
||||
#: src/gtk/connected-device.ui:282
|
||||
msgid "Viewport horizontal offset"
|
||||
msgstr ""
|
||||
|
||||
#: src/gtk/connected-device.ui:283
|
||||
msgid ""
|
||||
"By default, the viewport will center on the primary display. Use this slider "
|
||||
"to move the viewport to the left or right."
|
||||
msgstr ""
|
||||
|
||||
#: src/gtk/connected-device.ui:312
|
||||
msgid "Viewport vertical offset"
|
||||
msgstr ""
|
||||
|
||||
#: src/gtk/connected-device.ui:313
|
||||
msgid ""
|
||||
"By default, the viewport will center on the primary display. Use this slider "
|
||||
"to move the viewport up or down."
|
||||
msgstr ""
|
||||
|
||||
#: src/gtk/connected-device.ui:349 src/gtk/connected-device.ui:355
|
||||
msgid "Keyboard Shortcuts"
|
||||
msgstr "キーボードショートカット"
|
||||
|
||||
#: src/gtk/connected-device.ui:218
|
||||
#: src/gtk/connected-device.ui:358
|
||||
msgid "XR Effect on/off shortcut"
|
||||
msgstr "XRエフェクトの切り替え"
|
||||
|
||||
#: src/gtk/connected-device.ui:219
|
||||
#: src/gtk/connected-device.ui:359
|
||||
msgid ""
|
||||
"Quickly enable or disable the XR Effect. You may need to enable the effect "
|
||||
"manually once in order to enable the shortcut."
|
||||
|
|
@ -251,44 +353,46 @@ msgstr ""
|
|||
"XRエフェクトの有効・無効を切り替えます。このショートカットを有効にするために"
|
||||
"手動で1回XRエフェクトを有効にする必要があります。"
|
||||
|
||||
#: src/gtk/connected-device.ui:238 src/gtk/connected-device.ui:267
|
||||
#: src/gtk/connected-device.ui:296 src/gtk/connected-device.ui:325
|
||||
#: src/gtk/connected-device.ui:378 src/gtk/connected-device.ui:407
|
||||
#: src/gtk/connected-device.ui:436 src/gtk/connected-device.ui:465
|
||||
msgid "Change"
|
||||
msgstr "変更"
|
||||
|
||||
#: src/gtk/connected-device.ui:247
|
||||
#: src/gtk/connected-device.ui:387
|
||||
msgid "Re-center display shortcut"
|
||||
msgstr "ディスプレイを中央へ移動"
|
||||
|
||||
#: src/gtk/connected-device.ui:248
|
||||
#: src/gtk/connected-device.ui:388
|
||||
msgid "Pin the virtual display to the current position."
|
||||
msgstr "仮想ディスプレイを現在の視点に固定します。"
|
||||
|
||||
#: src/gtk/connected-device.ui:276
|
||||
msgid "Display distance shortcut"
|
||||
msgstr "ディスプレイ距離の切り替え"
|
||||
#: src/gtk/connected-device.ui:416
|
||||
#, fuzzy
|
||||
msgid "Toggle zoom on focus shortcut"
|
||||
msgstr "フォローモードの切り替え"
|
||||
|
||||
#: src/gtk/connected-device.ui:277
|
||||
msgid "Quickly toggle between two predefined distances."
|
||||
msgstr "設定してある2個の距離をすばやく切り替えます。"
|
||||
#: src/gtk/connected-device.ui:417
|
||||
#, fuzzy
|
||||
msgid "Quickly toggle zoom on focus mode."
|
||||
msgstr "フォローモードのオン/オフをすばやく切り替えます。"
|
||||
|
||||
#: src/gtk/connected-device.ui:305
|
||||
#: src/gtk/connected-device.ui:445
|
||||
msgid "Toggle follow mode shortcut"
|
||||
msgstr "フォローモードの切り替え"
|
||||
|
||||
#: src/gtk/connected-device.ui:306
|
||||
#: src/gtk/connected-device.ui:446
|
||||
msgid "Quickly toggle follow mode."
|
||||
msgstr "フォローモードのオン/オフをすばやく切り替えます。"
|
||||
|
||||
#: src/gtk/connected-device.ui:341 src/gtk/connected-device.ui:347
|
||||
#: src/gtk/connected-device.ui:481 src/gtk/connected-device.ui:487
|
||||
msgid "Advanced Settings"
|
||||
msgstr "詳細設定"
|
||||
|
||||
#: src/gtk/connected-device.ui:350
|
||||
#: src/gtk/connected-device.ui:490
|
||||
msgid "Find optimal display config"
|
||||
msgstr "ディスプレイ設定を最適化する"
|
||||
|
||||
#: src/gtk/connected-device.ui:351
|
||||
#: src/gtk/connected-device.ui:491
|
||||
msgid ""
|
||||
"Automatically modify the glasses display configuration for maximum "
|
||||
"resolution and best scaling when plugged in."
|
||||
|
|
@ -296,41 +400,29 @@ msgstr ""
|
|||
"メガネ接続時、最大解像度と最適なスケーリングのためにディスプレイ設定を自動的"
|
||||
"に変更します。"
|
||||
|
||||
#: src/gtk/connected-device.ui:361
|
||||
#: src/gtk/connected-device.ui:501
|
||||
msgid "Use highest refresh rate"
|
||||
msgstr "最大のリフレッシュレートを使用する"
|
||||
|
||||
#: src/gtk/connected-device.ui:362
|
||||
#: src/gtk/connected-device.ui:502
|
||||
msgid "Refresh rate may affect performance, disable this to set it manually."
|
||||
msgstr ""
|
||||
"リフレッシュレートはパフォーマンスに影響を与える可能性があります。手動で設定"
|
||||
"する場合は無効にしてください。"
|
||||
|
||||
#: src/gtk/connected-device.ui:372
|
||||
#: src/gtk/connected-device.ui:512
|
||||
msgid "Always primary display"
|
||||
msgstr "常にプライマリディスプレイにする"
|
||||
|
||||
#: src/gtk/connected-device.ui:373
|
||||
#: src/gtk/connected-device.ui:513
|
||||
msgid "Automatically set the glasses as the primary display when plugged in."
|
||||
msgstr "メガネ接続時、自動的にプライマリディスプレイにします。"
|
||||
|
||||
#: src/gtk/connected-device.ui:383
|
||||
msgid "Fast SBS mode switching"
|
||||
msgstr "高速SBSモード切り替え"
|
||||
|
||||
#: src/gtk/connected-device.ui:384
|
||||
msgid ""
|
||||
"Switches glasses to SBS mode immediately when plugged in, if widescreen mode "
|
||||
"is on. May cause instability."
|
||||
msgstr ""
|
||||
"ワイドスクリーンモードがオンになっている場合、メガネ接続時にたたちにSBSモード"
|
||||
"に切り替えます。不安定になる可能性があります。"
|
||||
|
||||
#: src/gtk/connected-device.ui:394
|
||||
#: src/gtk/connected-device.ui:523
|
||||
msgid "Movement look-ahead"
|
||||
msgstr "動きの先読み"
|
||||
|
||||
#: src/gtk/connected-device.ui:395
|
||||
#: src/gtk/connected-device.ui:524
|
||||
msgid ""
|
||||
"Counteracts input lag by predicting head-tracking position ahead of render "
|
||||
"time. Stick with default unless virtual display drags behind your head "
|
||||
|
|
@ -340,20 +432,36 @@ msgstr ""
|
|||
"ます。仮想ディスプレイが頭の動きに遅れたり、先に進んだり、非常に揺れたりする"
|
||||
"場合を除き、デフォルトのままで問題ありません。"
|
||||
|
||||
#: src/gtk/connected-device.ui:413
|
||||
#: src/gtk/connected-device.ui:542
|
||||
msgid "Default"
|
||||
msgstr "デフォルト"
|
||||
|
||||
#: src/gtk/connected-device.ui:425
|
||||
#: src/gtk/connected-device.ui:554
|
||||
msgid "Text Scaling"
|
||||
msgstr "テキストスケーリング"
|
||||
|
||||
#: src/gtk/connected-device.ui:426
|
||||
#: src/gtk/connected-device.ui:555
|
||||
msgid "Scaling text below 1.0 will simulate a higher resolution display"
|
||||
msgstr ""
|
||||
"テキストを1.0未満にスケーリングすると、高解像度ディスプレイをシミュレートしま"
|
||||
"す。"
|
||||
|
||||
#: src/gtk/connected-device.ui:585
|
||||
msgid "Enable multi-tap detection"
|
||||
msgstr ""
|
||||
|
||||
#: src/gtk/connected-device.ui:586
|
||||
msgid "Enables double-tap to recenter and triple-tap to recalibrate."
|
||||
msgstr ""
|
||||
|
||||
#: src/gtk/display-distance-dialog.ui:9
|
||||
msgid "Show full range"
|
||||
msgstr ""
|
||||
|
||||
#: src/gtk/display-distance-dialog.ui:18
|
||||
msgid "Done"
|
||||
msgstr ""
|
||||
|
||||
#: src/gtk/failed-verification.ui:13
|
||||
msgid "Breezy Desktop GNOME invalid setup"
|
||||
msgstr "Breezy Desktop GNOMEの無効なセットアップ"
|
||||
|
|
@ -398,15 +506,8 @@ msgstr "XRエフェクトの自動有効化"
|
|||
msgid ""
|
||||
"Automatically enable the Breezy Desktop XR effect when supported glasses are "
|
||||
"connected."
|
||||
msgstr "対応メガネを接続するとBreezy DesktopのXRエフェクトを自動的に開始します。"
|
||||
|
||||
#: src/gtk/no-device.ui:34
|
||||
msgid "Start in widescreen mode"
|
||||
msgstr "ワイドスクリーンモードで起動"
|
||||
|
||||
#: src/gtk/no-device.ui:35
|
||||
msgid "Widescreen mode is not supported for all glasses."
|
||||
msgstr "ワイドスクリーンモードはすべてのメガネで対応しているわけではありません。"
|
||||
msgstr ""
|
||||
"対応メガネを接続するとBreezy DesktopのXRエフェクトを自動的に開始します。"
|
||||
|
||||
#: src/gtk/no-driver.ui:13
|
||||
msgid "No driver running"
|
||||
|
|
@ -517,3 +618,60 @@ msgstr "強制リセット"
|
|||
#: src/gtk/window.ui:99
|
||||
msgid "About BreezyDesktop"
|
||||
msgstr "Breezy Desktopについて"
|
||||
|
||||
#~ msgid "Fast SBS mode switching"
|
||||
#~ msgstr "高速SBSモード切り替え"
|
||||
|
||||
#~ msgid ""
|
||||
#~ "Switches glasses to SBS mode immediately when plugged in, if widescreen "
|
||||
#~ "mode is on. May cause instability."
|
||||
#~ msgstr ""
|
||||
#~ "ワイドスクリーンモードがオンになっている場合、メガネ接続時にたたちにSBS"
|
||||
#~ "モードに切り替えます。不安定になる可能性があります。"
|
||||
|
||||
#, fuzzy
|
||||
#~ msgid "Set Unfocused Displays Distance"
|
||||
#~ msgstr "ディスプレイ距離"
|
||||
|
||||
#~ msgid "Widescreen mode"
|
||||
#~ msgstr "ワイドスクリーンモード"
|
||||
|
||||
#~ msgid "Switch between flat and curved displays."
|
||||
#~ msgstr "平面と曲面ディスプレイを切り替えます。"
|
||||
|
||||
#~ msgid ""
|
||||
#~ "Closer appears larger, further appears smaller. Controls depth when in "
|
||||
#~ "widescreen mode."
|
||||
#~ msgstr ""
|
||||
#~ "近づけると大きく見え、遠ざけると小さく見えます。\n"
|
||||
#~ "ワイドスクリーンモードの奥行きを制御します。"
|
||||
|
||||
#~ msgid ""
|
||||
#~ "Combine with display distance to achieve a comfortable level of depth and "
|
||||
#~ "size."
|
||||
#~ msgstr ""
|
||||
#~ "ディスプレイ距離と組み合わせて、\n"
|
||||
#~ "快適な奥行きとサイズを実現します。"
|
||||
|
||||
#~ msgid "Display toggle distances"
|
||||
#~ msgstr "ディスプレイ距離の切り替え"
|
||||
|
||||
#~ msgid ""
|
||||
#~ "Use the buttons to capture the current display distance for use with the "
|
||||
#~ "keyboard shortcut."
|
||||
#~ msgstr ""
|
||||
#~ "2個のボタンを使用して、キーボードショートカットで使用する現在のディスプレ"
|
||||
#~ "イ距離をそれぞれ設定します。"
|
||||
|
||||
#~ msgid "Display distance shortcut"
|
||||
#~ msgstr "ディスプレイ距離の切り替え"
|
||||
|
||||
#~ msgid "Quickly toggle between two predefined distances."
|
||||
#~ msgstr "設定してある2個の距離をすばやく切り替えます。"
|
||||
|
||||
#~ msgid "Start in widescreen mode"
|
||||
#~ msgstr "ワイドスクリーンモードで起動"
|
||||
|
||||
#~ msgid "Widescreen mode is not supported for all glasses."
|
||||
#~ msgstr ""
|
||||
#~ "ワイドスクリーンモードはすべてのメガネで対応しているわけではありません。"
|
||||
|
|
|
|||
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
262
ui/po/pl.po
262
ui/po/pl.po
|
|
@ -7,7 +7,7 @@ msgid ""
|
|||
msgstr ""
|
||||
"Project-Id-Version: PACKAGE VERSION\n"
|
||||
"Report-Msgid-Bugs-To: \n"
|
||||
"POT-Creation-Date: 2024-10-22 13:27-0700\n"
|
||||
"POT-Creation-Date: 2025-03-05 12:28-0800\n"
|
||||
"PO-Revision-Date: 2024-08-16 10:26-0700\n"
|
||||
"Last-Translator: <wayne@xronlinux.com>\n"
|
||||
"Language-Team: Polish <translation-team-pl@lists.sourceforge.net>\n"
|
||||
|
|
@ -18,16 +18,58 @@ msgstr ""
|
|||
"Plural-Forms: nplurals=3; plural=(n==1 ? 0 : n%10>=2 && n%10<=4 && (n%100<10 "
|
||||
"|| n%100>=20) ? 1 : 2);\n"
|
||||
|
||||
#: src/connecteddevice.py:17
|
||||
#: src/connecteddevice.py:23
|
||||
msgid ""
|
||||
"Switches your glasses into side-by-side mode and doubles the width of the "
|
||||
"display."
|
||||
msgstr ""
|
||||
|
||||
#: src/connecteddevice.py:18
|
||||
#: src/connecteddevice.py:24
|
||||
msgid "This feature is not currently supported for your device."
|
||||
msgstr ""
|
||||
|
||||
#: src/connecteddevice.py:124
|
||||
msgid "Set Focused Display Distance"
|
||||
msgstr ""
|
||||
|
||||
#: src/connecteddevice.py:125
|
||||
msgid "Use a closer value so the display zooms in when you look at it."
|
||||
msgstr ""
|
||||
|
||||
#: src/connecteddevice.py:132
|
||||
msgid "Set All Displays Distance"
|
||||
msgstr ""
|
||||
|
||||
#: src/connecteddevice.py:133
|
||||
msgid "Use a farther value so the displays are zoomed out when you look away."
|
||||
msgstr ""
|
||||
|
||||
#: src/connecteddevice.py:231
|
||||
msgid ""
|
||||
"Unable to add virtual displays on this machine. xdg-desktop-portal is "
|
||||
"required."
|
||||
msgstr ""
|
||||
|
||||
#: src/connecteddevice.py:265
|
||||
msgid "Focused display"
|
||||
msgstr ""
|
||||
|
||||
#: src/connecteddevice.py:271
|
||||
msgid "All displays"
|
||||
msgstr ""
|
||||
|
||||
#: src/displaydistancedialogcontent.py:41
|
||||
msgid "closer"
|
||||
msgstr ""
|
||||
|
||||
#: src/displaydistancedialogcontent.py:45
|
||||
msgid "fullscreen"
|
||||
msgstr ""
|
||||
|
||||
#: src/displaydistancedialogcontent.py:48
|
||||
msgid "farther"
|
||||
msgstr ""
|
||||
|
||||
#: src/licensedialogcontent.py:63
|
||||
msgid "Paid Tier Status"
|
||||
msgstr ""
|
||||
|
|
@ -36,7 +78,7 @@ msgstr ""
|
|||
msgid "Feature Availability"
|
||||
msgstr ""
|
||||
|
||||
#: src/licensefeaturerow.py:15 src/shortcutdialog.py:107
|
||||
#: src/licensefeaturerow.py:15 src/shortcutdialog.py:104
|
||||
msgid "Disabled"
|
||||
msgstr ""
|
||||
|
||||
|
|
@ -165,173 +207,235 @@ msgid "Enables the Breezy Desktop XR effect."
|
|||
msgstr ""
|
||||
|
||||
#: src/gtk/connected-device.ui:55
|
||||
msgid "Widescreen mode"
|
||||
msgid "Zoom on focus"
|
||||
msgstr ""
|
||||
|
||||
#: src/gtk/connected-device.ui:66
|
||||
#: src/gtk/connected-device.ui:56
|
||||
msgid ""
|
||||
"Automatically move a display closer when you look at it.\n"
|
||||
"Set your preferred focused and unfocused distances in the Adjustments "
|
||||
"section.\n"
|
||||
" "
|
||||
msgstr ""
|
||||
|
||||
#: src/gtk/connected-device.ui:69
|
||||
msgid "Follow mode"
|
||||
msgstr ""
|
||||
|
||||
#: src/gtk/connected-device.ui:67
|
||||
msgid "Keep the virtual display near the center of your view."
|
||||
#: src/gtk/connected-device.ui:70
|
||||
msgid "Keep the focused display near the center of your view."
|
||||
msgstr ""
|
||||
|
||||
#: src/gtk/connected-device.ui:77
|
||||
msgid "Curved display"
|
||||
#: src/gtk/connected-device.ui:80 src/gtk/no-device.ui:34
|
||||
msgid "Disable physical displays"
|
||||
msgstr ""
|
||||
|
||||
#: src/gtk/connected-device.ui:78
|
||||
msgid "Switch between flat and curved displays."
|
||||
#: src/gtk/connected-device.ui:81 src/gtk/no-device.ui:35
|
||||
msgid ""
|
||||
"Automatically disable all physical displays when the XR effect is enabled."
|
||||
msgstr ""
|
||||
|
||||
#: src/gtk/connected-device.ui:91
|
||||
msgid "Virtual displays"
|
||||
msgstr ""
|
||||
|
||||
#: src/gtk/connected-device.ui:103
|
||||
msgid "Rearrange displays"
|
||||
msgstr ""
|
||||
|
||||
#: src/gtk/connected-device.ui:115
|
||||
msgid "1080p"
|
||||
msgstr ""
|
||||
|
||||
#: src/gtk/connected-device.ui:116
|
||||
msgid "1440p"
|
||||
msgstr ""
|
||||
|
||||
#: src/gtk/connected-device.ui:140
|
||||
msgid "Adjustments"
|
||||
msgstr ""
|
||||
|
||||
#: src/gtk/connected-device.ui:94
|
||||
msgid "Display distance"
|
||||
#: src/gtk/connected-device.ui:143
|
||||
msgid "Display distances"
|
||||
msgstr ""
|
||||
|
||||
#: src/gtk/connected-device.ui:95
|
||||
msgid ""
|
||||
"Closer appears larger, further appears smaller. Controls depth when in "
|
||||
"widescreen mode."
|
||||
#: src/gtk/connected-device.ui:144
|
||||
msgid "Set how close you want displays to appear."
|
||||
msgstr ""
|
||||
|
||||
#: src/gtk/connected-device.ui:123
|
||||
msgid "Display size"
|
||||
msgstr ""
|
||||
|
||||
#: src/gtk/connected-device.ui:124
|
||||
msgid ""
|
||||
"Combine with display distance to achieve a comfortable level of depth and "
|
||||
"size."
|
||||
msgstr ""
|
||||
|
||||
#: src/gtk/connected-device.ui:152
|
||||
msgid "Display toggle distances"
|
||||
msgstr ""
|
||||
|
||||
#: src/gtk/connected-device.ui:153
|
||||
msgid ""
|
||||
"Use the buttons to capture the current display distance for use with the "
|
||||
"keyboard shortcut."
|
||||
msgstr ""
|
||||
|
||||
#: src/gtk/connected-device.ui:178
|
||||
#: src/gtk/connected-device.ui:199
|
||||
msgid "Follow threshold"
|
||||
msgstr ""
|
||||
|
||||
#: src/gtk/connected-device.ui:179
|
||||
#: src/gtk/connected-device.ui:200
|
||||
msgid "How far away you can look before the display follows."
|
||||
msgstr ""
|
||||
|
||||
#: src/gtk/connected-device.ui:209 src/gtk/connected-device.ui:215
|
||||
#: src/gtk/connected-device.ui:223
|
||||
msgid "Display angling"
|
||||
msgstr ""
|
||||
|
||||
#: src/gtk/connected-device.ui:224
|
||||
msgid ""
|
||||
"When there are multiple displays, choose how they should angle towards you."
|
||||
msgstr ""
|
||||
|
||||
#: src/gtk/connected-device.ui:238
|
||||
msgid "Automatic"
|
||||
msgstr ""
|
||||
|
||||
#: src/gtk/connected-device.ui:239
|
||||
msgid "Side-angled"
|
||||
msgstr ""
|
||||
|
||||
#: src/gtk/connected-device.ui:240
|
||||
msgid "Top-angled"
|
||||
msgstr ""
|
||||
|
||||
#: src/gtk/connected-device.ui:241
|
||||
msgid "Flat"
|
||||
msgstr ""
|
||||
|
||||
#: src/gtk/connected-device.ui:251
|
||||
msgid "Display spacing"
|
||||
msgstr ""
|
||||
|
||||
#: src/gtk/connected-device.ui:252
|
||||
msgid "Put empty space between displays, when there are multiple."
|
||||
msgstr ""
|
||||
|
||||
#: src/gtk/connected-device.ui:282
|
||||
msgid "Viewport horizontal offset"
|
||||
msgstr ""
|
||||
|
||||
#: src/gtk/connected-device.ui:283
|
||||
msgid ""
|
||||
"By default, the viewport will center on the primary display. Use this slider "
|
||||
"to move the viewport to the left or right."
|
||||
msgstr ""
|
||||
|
||||
#: src/gtk/connected-device.ui:312
|
||||
msgid "Viewport vertical offset"
|
||||
msgstr ""
|
||||
|
||||
#: src/gtk/connected-device.ui:313
|
||||
msgid ""
|
||||
"By default, the viewport will center on the primary display. Use this slider "
|
||||
"to move the viewport up or down."
|
||||
msgstr ""
|
||||
|
||||
#: src/gtk/connected-device.ui:349 src/gtk/connected-device.ui:355
|
||||
msgid "Keyboard Shortcuts"
|
||||
msgstr ""
|
||||
|
||||
#: src/gtk/connected-device.ui:218
|
||||
#: src/gtk/connected-device.ui:358
|
||||
msgid "XR Effect on/off shortcut"
|
||||
msgstr ""
|
||||
|
||||
#: src/gtk/connected-device.ui:219
|
||||
#: src/gtk/connected-device.ui:359
|
||||
msgid ""
|
||||
"Quickly enable or disable the XR Effect. You may need to enable the effect "
|
||||
"manually once in order to enable the shortcut."
|
||||
msgstr ""
|
||||
|
||||
#: src/gtk/connected-device.ui:238 src/gtk/connected-device.ui:267
|
||||
#: src/gtk/connected-device.ui:296 src/gtk/connected-device.ui:325
|
||||
#: src/gtk/connected-device.ui:378 src/gtk/connected-device.ui:407
|
||||
#: src/gtk/connected-device.ui:436 src/gtk/connected-device.ui:465
|
||||
msgid "Change"
|
||||
msgstr ""
|
||||
|
||||
#: src/gtk/connected-device.ui:247
|
||||
#: src/gtk/connected-device.ui:387
|
||||
msgid "Re-center display shortcut"
|
||||
msgstr ""
|
||||
|
||||
#: src/gtk/connected-device.ui:248
|
||||
#: src/gtk/connected-device.ui:388
|
||||
msgid "Pin the virtual display to the current position."
|
||||
msgstr ""
|
||||
|
||||
#: src/gtk/connected-device.ui:276
|
||||
msgid "Display distance shortcut"
|
||||
#: src/gtk/connected-device.ui:416
|
||||
msgid "Toggle zoom on focus shortcut"
|
||||
msgstr ""
|
||||
|
||||
#: src/gtk/connected-device.ui:277
|
||||
msgid "Quickly toggle between two predefined distances."
|
||||
#: src/gtk/connected-device.ui:417
|
||||
msgid "Quickly toggle zoom on focus mode."
|
||||
msgstr ""
|
||||
|
||||
#: src/gtk/connected-device.ui:305
|
||||
#: src/gtk/connected-device.ui:445
|
||||
msgid "Toggle follow mode shortcut"
|
||||
msgstr ""
|
||||
|
||||
#: src/gtk/connected-device.ui:306
|
||||
#: src/gtk/connected-device.ui:446
|
||||
msgid "Quickly toggle follow mode."
|
||||
msgstr ""
|
||||
|
||||
#: src/gtk/connected-device.ui:341 src/gtk/connected-device.ui:347
|
||||
#: src/gtk/connected-device.ui:481 src/gtk/connected-device.ui:487
|
||||
msgid "Advanced Settings"
|
||||
msgstr ""
|
||||
|
||||
#: src/gtk/connected-device.ui:350
|
||||
#: src/gtk/connected-device.ui:490
|
||||
msgid "Find optimal display config"
|
||||
msgstr ""
|
||||
|
||||
#: src/gtk/connected-device.ui:351
|
||||
#: src/gtk/connected-device.ui:491
|
||||
msgid ""
|
||||
"Automatically modify the glasses display configuration for maximum "
|
||||
"resolution and best scaling when plugged in."
|
||||
msgstr ""
|
||||
|
||||
#: src/gtk/connected-device.ui:361
|
||||
#: src/gtk/connected-device.ui:501
|
||||
msgid "Use highest refresh rate"
|
||||
msgstr ""
|
||||
|
||||
#: src/gtk/connected-device.ui:362
|
||||
#: src/gtk/connected-device.ui:502
|
||||
msgid "Refresh rate may affect performance, disable this to set it manually."
|
||||
msgstr ""
|
||||
|
||||
#: src/gtk/connected-device.ui:372
|
||||
#: src/gtk/connected-device.ui:512
|
||||
msgid "Always primary display"
|
||||
msgstr ""
|
||||
|
||||
#: src/gtk/connected-device.ui:373
|
||||
#: src/gtk/connected-device.ui:513
|
||||
msgid "Automatically set the glasses as the primary display when plugged in."
|
||||
msgstr ""
|
||||
|
||||
#: src/gtk/connected-device.ui:383
|
||||
msgid "Fast SBS mode switching"
|
||||
msgstr ""
|
||||
|
||||
#: src/gtk/connected-device.ui:384
|
||||
msgid ""
|
||||
"Switches glasses to SBS mode immediately when plugged in, if widescreen mode "
|
||||
"is on. May cause instability."
|
||||
msgstr ""
|
||||
|
||||
#: src/gtk/connected-device.ui:394
|
||||
#: src/gtk/connected-device.ui:523
|
||||
msgid "Movement look-ahead"
|
||||
msgstr ""
|
||||
|
||||
#: src/gtk/connected-device.ui:395
|
||||
#: src/gtk/connected-device.ui:524
|
||||
msgid ""
|
||||
"Counteracts input lag by predicting head-tracking position ahead of render "
|
||||
"time. Stick with default unless virtual display drags behind your head "
|
||||
"movements, jumps ahead, or is very shaky."
|
||||
msgstr ""
|
||||
|
||||
#: src/gtk/connected-device.ui:413
|
||||
#: src/gtk/connected-device.ui:542
|
||||
msgid "Default"
|
||||
msgstr ""
|
||||
|
||||
#: src/gtk/connected-device.ui:425
|
||||
#: src/gtk/connected-device.ui:554
|
||||
msgid "Text Scaling"
|
||||
msgstr ""
|
||||
|
||||
#: src/gtk/connected-device.ui:426
|
||||
#: src/gtk/connected-device.ui:555
|
||||
msgid "Scaling text below 1.0 will simulate a higher resolution display"
|
||||
msgstr ""
|
||||
|
||||
#: src/gtk/connected-device.ui:585
|
||||
msgid "Enable multi-tap detection"
|
||||
msgstr ""
|
||||
|
||||
#: src/gtk/connected-device.ui:586
|
||||
msgid "Enables double-tap to recenter and triple-tap to recalibrate."
|
||||
msgstr ""
|
||||
|
||||
#: src/gtk/display-distance-dialog.ui:9
|
||||
msgid "Show full range"
|
||||
msgstr ""
|
||||
|
||||
#: src/gtk/display-distance-dialog.ui:18
|
||||
msgid "Done"
|
||||
msgstr ""
|
||||
|
||||
#: src/gtk/failed-verification.ui:13
|
||||
msgid "Breezy Desktop GNOME invalid setup"
|
||||
msgstr ""
|
||||
|
|
@ -376,14 +480,6 @@ msgid ""
|
|||
"connected."
|
||||
msgstr ""
|
||||
|
||||
#: src/gtk/no-device.ui:34
|
||||
msgid "Start in widescreen mode"
|
||||
msgstr ""
|
||||
|
||||
#: src/gtk/no-device.ui:35
|
||||
msgid "Widescreen mode is not supported for all glasses."
|
||||
msgstr ""
|
||||
|
||||
#: src/gtk/no-driver.ui:13
|
||||
msgid "No driver running"
|
||||
msgstr ""
|
||||
|
|
|
|||
351
ui/po/pt_BR.po
351
ui/po/pt_BR.po
|
|
@ -7,18 +7,18 @@ msgid ""
|
|||
msgstr ""
|
||||
"Project-Id-Version: PACKAGE VERSION\n"
|
||||
"Report-Msgid-Bugs-To: \n"
|
||||
"POT-Creation-Date: 2024-10-22 13:27-0700\n"
|
||||
"POT-Creation-Date: 2025-03-05 12:28-0800\n"
|
||||
"PO-Revision-Date: 2024-08-19 09:39-0700\n"
|
||||
"Last-Translator: <wayne@xronlinux.com>\n"
|
||||
"Language-Team: Brazilian Portuguese <ldpbr-translation@lists.sourceforge."
|
||||
"net>\n"
|
||||
"Language-Team: Brazilian Portuguese <ldpbr-"
|
||||
"translation@lists.sourceforge.net>\n"
|
||||
"Language: pt_BR\n"
|
||||
"MIME-Version: 1.0\n"
|
||||
"Content-Type: text/plain; charset=UTF-8\n"
|
||||
"Content-Transfer-Encoding: 8bit\n"
|
||||
"Plural-Forms: nplurals=2; plural=(n > 1);\n"
|
||||
|
||||
#: src/connecteddevice.py:17
|
||||
#: src/connecteddevice.py:23
|
||||
msgid ""
|
||||
"Switches your glasses into side-by-side mode and doubles the width of the "
|
||||
"display."
|
||||
|
|
@ -26,10 +26,56 @@ msgstr ""
|
|||
"Altera o modo dos óculos para lado a lado (SBS) e dobra a largura da tela "
|
||||
"(ultrawide)."
|
||||
|
||||
#: src/connecteddevice.py:18
|
||||
#: src/connecteddevice.py:24
|
||||
msgid "This feature is not currently supported for your device."
|
||||
msgstr "Este recurso não é atualmente suportado para o seu dispositivo."
|
||||
|
||||
#: src/connecteddevice.py:124
|
||||
#, fuzzy
|
||||
msgid "Set Focused Display Distance"
|
||||
msgstr "Distância da tela"
|
||||
|
||||
#: src/connecteddevice.py:125
|
||||
msgid "Use a closer value so the display zooms in when you look at it."
|
||||
msgstr ""
|
||||
|
||||
#: src/connecteddevice.py:132
|
||||
#, fuzzy
|
||||
msgid "Set All Displays Distance"
|
||||
msgstr "Distância da tela"
|
||||
|
||||
#: src/connecteddevice.py:133
|
||||
msgid "Use a farther value so the displays are zoomed out when you look away."
|
||||
msgstr ""
|
||||
|
||||
#: src/connecteddevice.py:231
|
||||
msgid ""
|
||||
"Unable to add virtual displays on this machine. xdg-desktop-portal is "
|
||||
"required."
|
||||
msgstr ""
|
||||
|
||||
#: src/connecteddevice.py:265
|
||||
#, fuzzy
|
||||
msgid "Focused display"
|
||||
msgstr "Distância da tela"
|
||||
|
||||
#: src/connecteddevice.py:271
|
||||
#, fuzzy
|
||||
msgid "All displays"
|
||||
msgstr "Tela curva"
|
||||
|
||||
#: src/displaydistancedialogcontent.py:41
|
||||
msgid "closer"
|
||||
msgstr ""
|
||||
|
||||
#: src/displaydistancedialogcontent.py:45
|
||||
msgid "fullscreen"
|
||||
msgstr ""
|
||||
|
||||
#: src/displaydistancedialogcontent.py:48
|
||||
msgid "farther"
|
||||
msgstr ""
|
||||
|
||||
#: src/licensedialogcontent.py:63
|
||||
msgid "Paid Tier Status"
|
||||
msgstr "Status do Nível Pago"
|
||||
|
|
@ -38,7 +84,7 @@ msgstr "Status do Nível Pago"
|
|||
msgid "Feature Availability"
|
||||
msgstr "Disponibilidade de Recursos"
|
||||
|
||||
#: src/licensefeaturerow.py:15 src/shortcutdialog.py:107
|
||||
#: src/licensefeaturerow.py:15 src/shortcutdialog.py:104
|
||||
msgid "Disabled"
|
||||
msgstr "Desabilitado"
|
||||
|
||||
|
|
@ -167,125 +213,183 @@ msgid "Enables the Breezy Desktop XR effect."
|
|||
msgstr "Habilita o efeito XR do Breezy Desktop."
|
||||
|
||||
#: src/gtk/connected-device.ui:55
|
||||
msgid "Widescreen mode"
|
||||
msgstr "Modo Ultrawide"
|
||||
msgid "Zoom on focus"
|
||||
msgstr ""
|
||||
|
||||
#: src/gtk/connected-device.ui:66
|
||||
#: src/gtk/connected-device.ui:56
|
||||
msgid ""
|
||||
"Automatically move a display closer when you look at it.\n"
|
||||
"Set your preferred focused and unfocused distances in the Adjustments "
|
||||
"section.\n"
|
||||
" "
|
||||
msgstr ""
|
||||
|
||||
#: src/gtk/connected-device.ui:69
|
||||
msgid "Follow mode"
|
||||
msgstr "Modo de acompanhamento"
|
||||
|
||||
#: src/gtk/connected-device.ui:67
|
||||
msgid "Keep the virtual display near the center of your view."
|
||||
#: src/gtk/connected-device.ui:70
|
||||
#, fuzzy
|
||||
msgid "Keep the focused display near the center of your view."
|
||||
msgstr "Mantenha a tela virtual próxima ao centro da sua visão."
|
||||
|
||||
#: src/gtk/connected-device.ui:77
|
||||
msgid "Curved display"
|
||||
msgstr "Tela curva"
|
||||
#: src/gtk/connected-device.ui:80 src/gtk/no-device.ui:34
|
||||
msgid "Disable physical displays"
|
||||
msgstr ""
|
||||
|
||||
#: src/gtk/connected-device.ui:78
|
||||
msgid "Switch between flat and curved displays."
|
||||
msgstr "Alterne entre tela plana e tela curva."
|
||||
#: src/gtk/connected-device.ui:81 src/gtk/no-device.ui:35
|
||||
msgid ""
|
||||
"Automatically disable all physical displays when the XR effect is enabled."
|
||||
msgstr ""
|
||||
|
||||
#: src/gtk/connected-device.ui:91
|
||||
#, fuzzy
|
||||
msgid "Virtual displays"
|
||||
msgstr "Tela curva"
|
||||
|
||||
#: src/gtk/connected-device.ui:103
|
||||
#, fuzzy
|
||||
msgid "Rearrange displays"
|
||||
msgstr "Tela curva"
|
||||
|
||||
#: src/gtk/connected-device.ui:115
|
||||
msgid "1080p"
|
||||
msgstr ""
|
||||
|
||||
#: src/gtk/connected-device.ui:116
|
||||
msgid "1440p"
|
||||
msgstr ""
|
||||
|
||||
#: src/gtk/connected-device.ui:140
|
||||
msgid "Adjustments"
|
||||
msgstr "Ajustes"
|
||||
|
||||
#: src/gtk/connected-device.ui:94
|
||||
msgid "Display distance"
|
||||
#: src/gtk/connected-device.ui:143
|
||||
#, fuzzy
|
||||
msgid "Display distances"
|
||||
msgstr "Distância da tela"
|
||||
|
||||
#: src/gtk/connected-device.ui:95
|
||||
msgid ""
|
||||
"Closer appears larger, further appears smaller. Controls depth when in "
|
||||
"widescreen mode."
|
||||
#: src/gtk/connected-device.ui:144
|
||||
msgid "Set how close you want displays to appear."
|
||||
msgstr ""
|
||||
"Mais perto parece maior, mais longe parece menor. Controla a profundidade no "
|
||||
"modo ultrawide."
|
||||
|
||||
#: src/gtk/connected-device.ui:123
|
||||
msgid "Display size"
|
||||
msgstr "Tamanho da tela"
|
||||
|
||||
#: src/gtk/connected-device.ui:124
|
||||
msgid ""
|
||||
"Combine with display distance to achieve a comfortable level of depth and "
|
||||
"size."
|
||||
msgstr ""
|
||||
"Combine com a distância da tela para alcançar um nível confortável de "
|
||||
"profundidade e tamanho."
|
||||
|
||||
#: src/gtk/connected-device.ui:152
|
||||
msgid "Display toggle distances"
|
||||
msgstr "Alternância das distâncias de tela"
|
||||
|
||||
#: src/gtk/connected-device.ui:153
|
||||
msgid ""
|
||||
"Use the buttons to capture the current display distance for use with the "
|
||||
"keyboard shortcut."
|
||||
msgstr ""
|
||||
"Use os botões para obter a distância atual da tela para depois usar com o "
|
||||
"atalho de teclado."
|
||||
|
||||
#: src/gtk/connected-device.ui:178
|
||||
#: src/gtk/connected-device.ui:199
|
||||
msgid "Follow threshold"
|
||||
msgstr "Sensibilidade do modo de acompanhamento"
|
||||
|
||||
#: src/gtk/connected-device.ui:179
|
||||
#: src/gtk/connected-device.ui:200
|
||||
msgid "How far away you can look before the display follows."
|
||||
msgstr "Quanto você pode mover a cabeça antes que a tela te acompanhe."
|
||||
|
||||
#: src/gtk/connected-device.ui:209 src/gtk/connected-device.ui:215
|
||||
#: src/gtk/connected-device.ui:223
|
||||
#, fuzzy
|
||||
msgid "Display angling"
|
||||
msgstr "Tamanho da tela"
|
||||
|
||||
#: src/gtk/connected-device.ui:224
|
||||
msgid ""
|
||||
"When there are multiple displays, choose how they should angle towards you."
|
||||
msgstr ""
|
||||
|
||||
#: src/gtk/connected-device.ui:238
|
||||
msgid "Automatic"
|
||||
msgstr ""
|
||||
|
||||
#: src/gtk/connected-device.ui:239
|
||||
msgid "Side-angled"
|
||||
msgstr ""
|
||||
|
||||
#: src/gtk/connected-device.ui:240
|
||||
msgid "Top-angled"
|
||||
msgstr ""
|
||||
|
||||
#: src/gtk/connected-device.ui:241
|
||||
msgid "Flat"
|
||||
msgstr ""
|
||||
|
||||
#: src/gtk/connected-device.ui:251
|
||||
#, fuzzy
|
||||
msgid "Display spacing"
|
||||
msgstr "Tamanho da tela"
|
||||
|
||||
#: src/gtk/connected-device.ui:252
|
||||
msgid "Put empty space between displays, when there are multiple."
|
||||
msgstr ""
|
||||
|
||||
#: src/gtk/connected-device.ui:282
|
||||
msgid "Viewport horizontal offset"
|
||||
msgstr ""
|
||||
|
||||
#: src/gtk/connected-device.ui:283
|
||||
msgid ""
|
||||
"By default, the viewport will center on the primary display. Use this slider "
|
||||
"to move the viewport to the left or right."
|
||||
msgstr ""
|
||||
|
||||
#: src/gtk/connected-device.ui:312
|
||||
msgid "Viewport vertical offset"
|
||||
msgstr ""
|
||||
|
||||
#: src/gtk/connected-device.ui:313
|
||||
msgid ""
|
||||
"By default, the viewport will center on the primary display. Use this slider "
|
||||
"to move the viewport up or down."
|
||||
msgstr ""
|
||||
|
||||
#: src/gtk/connected-device.ui:349 src/gtk/connected-device.ui:355
|
||||
msgid "Keyboard Shortcuts"
|
||||
msgstr "Atalhos de teclado"
|
||||
|
||||
#: src/gtk/connected-device.ui:218
|
||||
#: src/gtk/connected-device.ui:358
|
||||
msgid "XR Effect on/off shortcut"
|
||||
msgstr ""
|
||||
|
||||
#: src/gtk/connected-device.ui:219
|
||||
#: src/gtk/connected-device.ui:359
|
||||
msgid ""
|
||||
"Quickly enable or disable the XR Effect. You may need to enable the effect "
|
||||
"manually once in order to enable the shortcut."
|
||||
msgstr ""
|
||||
|
||||
#: src/gtk/connected-device.ui:238 src/gtk/connected-device.ui:267
|
||||
#: src/gtk/connected-device.ui:296 src/gtk/connected-device.ui:325
|
||||
#: src/gtk/connected-device.ui:378 src/gtk/connected-device.ui:407
|
||||
#: src/gtk/connected-device.ui:436 src/gtk/connected-device.ui:465
|
||||
msgid "Change"
|
||||
msgstr "Alterar"
|
||||
|
||||
#: src/gtk/connected-device.ui:247
|
||||
#: src/gtk/connected-device.ui:387
|
||||
msgid "Re-center display shortcut"
|
||||
msgstr "Atalho para recentralizar a tela"
|
||||
|
||||
#: src/gtk/connected-device.ui:248
|
||||
#: src/gtk/connected-device.ui:388
|
||||
msgid "Pin the virtual display to the current position."
|
||||
msgstr "Traga a tela virtual para onde você está olhando."
|
||||
|
||||
#: src/gtk/connected-device.ui:276
|
||||
msgid "Display distance shortcut"
|
||||
msgstr "Atalho de distância da tela"
|
||||
#: src/gtk/connected-device.ui:416
|
||||
#, fuzzy
|
||||
msgid "Toggle zoom on focus shortcut"
|
||||
msgstr "Atalho para alternar o modo de acompanhamento"
|
||||
|
||||
#: src/gtk/connected-device.ui:277
|
||||
msgid "Quickly toggle between two predefined distances."
|
||||
msgstr "Alterne rapidamente entre as duas distâncias predefinidas."
|
||||
#: src/gtk/connected-device.ui:417
|
||||
#, fuzzy
|
||||
msgid "Quickly toggle zoom on focus mode."
|
||||
msgstr "Alterne rapidamente o modo de acompanhamento."
|
||||
|
||||
#: src/gtk/connected-device.ui:305
|
||||
#: src/gtk/connected-device.ui:445
|
||||
msgid "Toggle follow mode shortcut"
|
||||
msgstr "Atalho para alternar o modo de acompanhamento"
|
||||
|
||||
#: src/gtk/connected-device.ui:306
|
||||
#: src/gtk/connected-device.ui:446
|
||||
msgid "Quickly toggle follow mode."
|
||||
msgstr "Alterne rapidamente o modo de acompanhamento."
|
||||
|
||||
#: src/gtk/connected-device.ui:341 src/gtk/connected-device.ui:347
|
||||
#: src/gtk/connected-device.ui:481 src/gtk/connected-device.ui:487
|
||||
msgid "Advanced Settings"
|
||||
msgstr "Configurações Avançadas"
|
||||
|
||||
#: src/gtk/connected-device.ui:350
|
||||
#: src/gtk/connected-device.ui:490
|
||||
msgid "Find optimal display config"
|
||||
msgstr "Encontre a configuração de tela ideal"
|
||||
|
||||
#: src/gtk/connected-device.ui:351
|
||||
#: src/gtk/connected-device.ui:491
|
||||
msgid ""
|
||||
"Automatically modify the glasses display configuration for maximum "
|
||||
"resolution and best scaling when plugged in."
|
||||
|
|
@ -293,42 +397,30 @@ msgstr ""
|
|||
"Modifique automaticamente a configuração de exibição dos óculos para máxima "
|
||||
"resolução e melhor dimensionamento quando conectado."
|
||||
|
||||
#: src/gtk/connected-device.ui:361
|
||||
#: src/gtk/connected-device.ui:501
|
||||
msgid "Use highest refresh rate"
|
||||
msgstr "Use a taxa de atualização mais alta"
|
||||
|
||||
#: src/gtk/connected-device.ui:362
|
||||
#: src/gtk/connected-device.ui:502
|
||||
msgid "Refresh rate may affect performance, disable this to set it manually."
|
||||
msgstr ""
|
||||
"A taxa de atualização pode afetar o desempenho, desative-a para defini-la "
|
||||
"manualmente."
|
||||
|
||||
#: src/gtk/connected-device.ui:372
|
||||
#: src/gtk/connected-device.ui:512
|
||||
msgid "Always primary display"
|
||||
msgstr "Sempre tela principal"
|
||||
|
||||
#: src/gtk/connected-device.ui:373
|
||||
#: src/gtk/connected-device.ui:513
|
||||
msgid "Automatically set the glasses as the primary display when plugged in."
|
||||
msgstr ""
|
||||
"Defina automaticamente os óculos como a tela primária quando conectados."
|
||||
|
||||
#: src/gtk/connected-device.ui:383
|
||||
msgid "Fast SBS mode switching"
|
||||
msgstr "Alternância rápida do modo SBS"
|
||||
|
||||
#: src/gtk/connected-device.ui:384
|
||||
msgid ""
|
||||
"Switches glasses to SBS mode immediately when plugged in, if widescreen mode "
|
||||
"is on. May cause instability."
|
||||
msgstr ""
|
||||
"Altera os óculos para o modo SBS imediatamente quando conectados, se o modo "
|
||||
"ultrawide estiver ativado. Pode causar instabilidade."
|
||||
|
||||
#: src/gtk/connected-device.ui:394
|
||||
#: src/gtk/connected-device.ui:523
|
||||
msgid "Movement look-ahead"
|
||||
msgstr "Antecipação de movimento"
|
||||
|
||||
#: src/gtk/connected-device.ui:395
|
||||
#: src/gtk/connected-device.ui:524
|
||||
msgid ""
|
||||
"Counteracts input lag by predicting head-tracking position ahead of render "
|
||||
"time. Stick with default unless virtual display drags behind your head "
|
||||
|
|
@ -339,19 +431,35 @@ msgstr ""
|
|||
"virtual tenha atrasos, avance ou seja muito instável em relação aos "
|
||||
"movimentos da cabeça "
|
||||
|
||||
#: src/gtk/connected-device.ui:413
|
||||
#: src/gtk/connected-device.ui:542
|
||||
msgid "Default"
|
||||
msgstr "Padrão"
|
||||
|
||||
#: src/gtk/connected-device.ui:425
|
||||
#: src/gtk/connected-device.ui:554
|
||||
msgid "Text Scaling"
|
||||
msgstr "Redimensionamento de Texto"
|
||||
|
||||
#: src/gtk/connected-device.ui:426
|
||||
#: src/gtk/connected-device.ui:555
|
||||
msgid "Scaling text below 1.0 will simulate a higher resolution display"
|
||||
msgstr ""
|
||||
"Redimensionar o texto abaixo de 1.0 simulará uma tela de resolução mais alta"
|
||||
|
||||
#: src/gtk/connected-device.ui:585
|
||||
msgid "Enable multi-tap detection"
|
||||
msgstr ""
|
||||
|
||||
#: src/gtk/connected-device.ui:586
|
||||
msgid "Enables double-tap to recenter and triple-tap to recalibrate."
|
||||
msgstr ""
|
||||
|
||||
#: src/gtk/display-distance-dialog.ui:9
|
||||
msgid "Show full range"
|
||||
msgstr ""
|
||||
|
||||
#: src/gtk/display-distance-dialog.ui:18
|
||||
msgid "Done"
|
||||
msgstr ""
|
||||
|
||||
#: src/gtk/failed-verification.ui:13
|
||||
msgid "Breezy Desktop GNOME invalid setup"
|
||||
msgstr "Configuração inválida do Breezy Desktop GNOME"
|
||||
|
|
@ -401,15 +509,6 @@ msgid ""
|
|||
"connected."
|
||||
msgstr ""
|
||||
|
||||
#: src/gtk/no-device.ui:34
|
||||
#, fuzzy
|
||||
msgid "Start in widescreen mode"
|
||||
msgstr "Modo Ultrawide"
|
||||
|
||||
#: src/gtk/no-device.ui:35
|
||||
msgid "Widescreen mode is not supported for all glasses."
|
||||
msgstr ""
|
||||
|
||||
#: src/gtk/no-driver.ui:13
|
||||
msgid "No driver running"
|
||||
msgstr "Nenhum driver em execução"
|
||||
|
|
@ -516,3 +615,57 @@ msgstr "Forçar redefinição"
|
|||
#: src/gtk/window.ui:99
|
||||
msgid "About BreezyDesktop"
|
||||
msgstr "Sobre o BreezyDesktop"
|
||||
|
||||
#~ msgid "Fast SBS mode switching"
|
||||
#~ msgstr "Alternância rápida do modo SBS"
|
||||
|
||||
#~ msgid ""
|
||||
#~ "Switches glasses to SBS mode immediately when plugged in, if widescreen "
|
||||
#~ "mode is on. May cause instability."
|
||||
#~ msgstr ""
|
||||
#~ "Altera os óculos para o modo SBS imediatamente quando conectados, se o "
|
||||
#~ "modo ultrawide estiver ativado. Pode causar instabilidade."
|
||||
|
||||
#, fuzzy
|
||||
#~ msgid "Set Unfocused Displays Distance"
|
||||
#~ msgstr "Distância da tela"
|
||||
|
||||
#~ msgid "Widescreen mode"
|
||||
#~ msgstr "Modo Ultrawide"
|
||||
|
||||
#~ msgid "Switch between flat and curved displays."
|
||||
#~ msgstr "Alterne entre tela plana e tela curva."
|
||||
|
||||
#~ msgid ""
|
||||
#~ "Closer appears larger, further appears smaller. Controls depth when in "
|
||||
#~ "widescreen mode."
|
||||
#~ msgstr ""
|
||||
#~ "Mais perto parece maior, mais longe parece menor. Controla a profundidade "
|
||||
#~ "no modo ultrawide."
|
||||
|
||||
#~ msgid ""
|
||||
#~ "Combine with display distance to achieve a comfortable level of depth and "
|
||||
#~ "size."
|
||||
#~ msgstr ""
|
||||
#~ "Combine com a distância da tela para alcançar um nível confortável de "
|
||||
#~ "profundidade e tamanho."
|
||||
|
||||
#~ msgid "Display toggle distances"
|
||||
#~ msgstr "Alternância das distâncias de tela"
|
||||
|
||||
#~ msgid ""
|
||||
#~ "Use the buttons to capture the current display distance for use with the "
|
||||
#~ "keyboard shortcut."
|
||||
#~ msgstr ""
|
||||
#~ "Use os botões para obter a distância atual da tela para depois usar com o "
|
||||
#~ "atalho de teclado."
|
||||
|
||||
#~ msgid "Display distance shortcut"
|
||||
#~ msgstr "Atalho de distância da tela"
|
||||
|
||||
#~ msgid "Quickly toggle between two predefined distances."
|
||||
#~ msgstr "Alterne rapidamente entre as duas distâncias predefinidas."
|
||||
|
||||
#, fuzzy
|
||||
#~ msgid "Start in widescreen mode"
|
||||
#~ msgstr "Modo Ultrawide"
|
||||
|
|
|
|||
347
ui/po/ru.po
347
ui/po/ru.po
|
|
@ -7,7 +7,7 @@ msgid ""
|
|||
msgstr ""
|
||||
"Project-Id-Version: PACKAGE VERSION\n"
|
||||
"Report-Msgid-Bugs-To: \n"
|
||||
"POT-Creation-Date: 2024-10-22 13:27-0700\n"
|
||||
"POT-Creation-Date: 2025-03-05 12:28-0800\n"
|
||||
"PO-Revision-Date: 2024-08-17 09:39-0700\n"
|
||||
"Last-Translator: <wayne@xronlinux.com>\n"
|
||||
"Language-Team: Russian <gnu@d07.ru>\n"
|
||||
|
|
@ -18,17 +18,63 @@ msgstr ""
|
|||
"Plural-Forms: nplurals=3; plural=(n%10==1 && n%100!=11 ? 0 : n%10>=2 && "
|
||||
"n%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2);\n"
|
||||
|
||||
#: src/connecteddevice.py:17
|
||||
#: src/connecteddevice.py:23
|
||||
msgid ""
|
||||
"Switches your glasses into side-by-side mode and doubles the width of the "
|
||||
"display."
|
||||
msgstr ""
|
||||
"Переключает очки в режим «сторона к стороне» и удваивает ширину дисплея."
|
||||
|
||||
#: src/connecteddevice.py:18
|
||||
#: src/connecteddevice.py:24
|
||||
msgid "This feature is not currently supported for your device."
|
||||
msgstr "Эта функция в настоящее время не поддерживается для вашего устройства."
|
||||
|
||||
#: src/connecteddevice.py:124
|
||||
#, fuzzy
|
||||
msgid "Set Focused Display Distance"
|
||||
msgstr "Расстояние дисплея"
|
||||
|
||||
#: src/connecteddevice.py:125
|
||||
msgid "Use a closer value so the display zooms in when you look at it."
|
||||
msgstr ""
|
||||
|
||||
#: src/connecteddevice.py:132
|
||||
#, fuzzy
|
||||
msgid "Set All Displays Distance"
|
||||
msgstr "Расстояние дисплея"
|
||||
|
||||
#: src/connecteddevice.py:133
|
||||
msgid "Use a farther value so the displays are zoomed out when you look away."
|
||||
msgstr ""
|
||||
|
||||
#: src/connecteddevice.py:231
|
||||
msgid ""
|
||||
"Unable to add virtual displays on this machine. xdg-desktop-portal is "
|
||||
"required."
|
||||
msgstr ""
|
||||
|
||||
#: src/connecteddevice.py:265
|
||||
#, fuzzy
|
||||
msgid "Focused display"
|
||||
msgstr "Расстояние дисплея"
|
||||
|
||||
#: src/connecteddevice.py:271
|
||||
#, fuzzy
|
||||
msgid "All displays"
|
||||
msgstr "Изогнутый дисплей"
|
||||
|
||||
#: src/displaydistancedialogcontent.py:41
|
||||
msgid "closer"
|
||||
msgstr ""
|
||||
|
||||
#: src/displaydistancedialogcontent.py:45
|
||||
msgid "fullscreen"
|
||||
msgstr ""
|
||||
|
||||
#: src/displaydistancedialogcontent.py:48
|
||||
msgid "farther"
|
||||
msgstr ""
|
||||
|
||||
#: src/licensedialogcontent.py:63
|
||||
msgid "Paid Tier Status"
|
||||
msgstr "Статус платного уровня"
|
||||
|
|
@ -37,7 +83,7 @@ msgstr "Статус платного уровня"
|
|||
msgid "Feature Availability"
|
||||
msgstr "Статус функций"
|
||||
|
||||
#: src/licensefeaturerow.py:15 src/shortcutdialog.py:107
|
||||
#: src/licensefeaturerow.py:15 src/shortcutdialog.py:104
|
||||
msgid "Disabled"
|
||||
msgstr "Отключено"
|
||||
|
||||
|
|
@ -166,126 +212,184 @@ msgid "Enables the Breezy Desktop XR effect."
|
|||
msgstr "Включает эффект Breezy Desktop XR."
|
||||
|
||||
#: src/gtk/connected-device.ui:55
|
||||
msgid "Widescreen mode"
|
||||
msgstr "Режим широкого экрана"
|
||||
msgid "Zoom on focus"
|
||||
msgstr ""
|
||||
|
||||
#: src/gtk/connected-device.ui:66
|
||||
#: src/gtk/connected-device.ui:56
|
||||
msgid ""
|
||||
"Automatically move a display closer when you look at it.\n"
|
||||
"Set your preferred focused and unfocused distances in the Adjustments "
|
||||
"section.\n"
|
||||
" "
|
||||
msgstr ""
|
||||
|
||||
#: src/gtk/connected-device.ui:69
|
||||
msgid "Follow mode"
|
||||
msgstr "Режим следования"
|
||||
|
||||
#: src/gtk/connected-device.ui:67
|
||||
msgid "Keep the virtual display near the center of your view."
|
||||
#: src/gtk/connected-device.ui:70
|
||||
#, fuzzy
|
||||
msgid "Keep the focused display near the center of your view."
|
||||
msgstr "Поддерживает виртуальный дисплей вблизи центра вашего зрения."
|
||||
|
||||
#: src/gtk/connected-device.ui:77
|
||||
msgid "Curved display"
|
||||
msgstr "Изогнутый дисплей"
|
||||
#: src/gtk/connected-device.ui:80 src/gtk/no-device.ui:34
|
||||
msgid "Disable physical displays"
|
||||
msgstr ""
|
||||
|
||||
#: src/gtk/connected-device.ui:78
|
||||
msgid "Switch between flat and curved displays."
|
||||
msgstr "Переключается между плоскими и изогнутыми дисплеями."
|
||||
#: src/gtk/connected-device.ui:81 src/gtk/no-device.ui:35
|
||||
msgid ""
|
||||
"Automatically disable all physical displays when the XR effect is enabled."
|
||||
msgstr ""
|
||||
|
||||
#: src/gtk/connected-device.ui:91
|
||||
#, fuzzy
|
||||
msgid "Virtual displays"
|
||||
msgstr "Изогнутый дисплей"
|
||||
|
||||
#: src/gtk/connected-device.ui:103
|
||||
#, fuzzy
|
||||
msgid "Rearrange displays"
|
||||
msgstr "Изогнутый дисплей"
|
||||
|
||||
#: src/gtk/connected-device.ui:115
|
||||
msgid "1080p"
|
||||
msgstr ""
|
||||
|
||||
#: src/gtk/connected-device.ui:116
|
||||
msgid "1440p"
|
||||
msgstr ""
|
||||
|
||||
#: src/gtk/connected-device.ui:140
|
||||
msgid "Adjustments"
|
||||
msgstr "Настройки"
|
||||
|
||||
#: src/gtk/connected-device.ui:94
|
||||
msgid "Display distance"
|
||||
#: src/gtk/connected-device.ui:143
|
||||
#, fuzzy
|
||||
msgid "Display distances"
|
||||
msgstr "Расстояние дисплея"
|
||||
|
||||
#: src/gtk/connected-device.ui:95
|
||||
msgid ""
|
||||
"Closer appears larger, further appears smaller. Controls depth when in "
|
||||
"widescreen mode."
|
||||
#: src/gtk/connected-device.ui:144
|
||||
msgid "Set how close you want displays to appear."
|
||||
msgstr ""
|
||||
"Чем ближе, тем больше. Чем дальше, тем меньше. Управляет глубиной при "
|
||||
"использовании режима широкого экрана."
|
||||
|
||||
#: src/gtk/connected-device.ui:123
|
||||
msgid "Display size"
|
||||
msgstr "Размер дисплея"
|
||||
|
||||
#: src/gtk/connected-device.ui:124
|
||||
msgid ""
|
||||
"Combine with display distance to achieve a comfortable level of depth and "
|
||||
"size."
|
||||
msgstr ""
|
||||
"Комбинируйте с расстоянием дисплея, чтобы достичь комфортного уровня глубины "
|
||||
"и размера."
|
||||
|
||||
#: src/gtk/connected-device.ui:152
|
||||
msgid "Display toggle distances"
|
||||
msgstr "Переключения расстояние дисплея"
|
||||
|
||||
#: src/gtk/connected-device.ui:153
|
||||
msgid ""
|
||||
"Use the buttons to capture the current display distance for use with the "
|
||||
"keyboard shortcut."
|
||||
msgstr ""
|
||||
"Используйте кнопки, чтобы зафиксировать текущее расстояние дисплея для "
|
||||
"использования с сочетанием клавиш."
|
||||
|
||||
#: src/gtk/connected-device.ui:178
|
||||
#: src/gtk/connected-device.ui:199
|
||||
msgid "Follow threshold"
|
||||
msgstr "Порог следования"
|
||||
|
||||
#: src/gtk/connected-device.ui:179
|
||||
#: src/gtk/connected-device.ui:200
|
||||
msgid "How far away you can look before the display follows."
|
||||
msgstr ""
|
||||
"Как далеко вы можете отвернуть взгляд, прежде чем дисплей последует за вами."
|
||||
|
||||
#: src/gtk/connected-device.ui:209 src/gtk/connected-device.ui:215
|
||||
#: src/gtk/connected-device.ui:223
|
||||
#, fuzzy
|
||||
msgid "Display angling"
|
||||
msgstr "Размер дисплея"
|
||||
|
||||
#: src/gtk/connected-device.ui:224
|
||||
msgid ""
|
||||
"When there are multiple displays, choose how they should angle towards you."
|
||||
msgstr ""
|
||||
|
||||
#: src/gtk/connected-device.ui:238
|
||||
msgid "Automatic"
|
||||
msgstr ""
|
||||
|
||||
#: src/gtk/connected-device.ui:239
|
||||
msgid "Side-angled"
|
||||
msgstr ""
|
||||
|
||||
#: src/gtk/connected-device.ui:240
|
||||
msgid "Top-angled"
|
||||
msgstr ""
|
||||
|
||||
#: src/gtk/connected-device.ui:241
|
||||
msgid "Flat"
|
||||
msgstr ""
|
||||
|
||||
#: src/gtk/connected-device.ui:251
|
||||
#, fuzzy
|
||||
msgid "Display spacing"
|
||||
msgstr "Размер дисплея"
|
||||
|
||||
#: src/gtk/connected-device.ui:252
|
||||
msgid "Put empty space between displays, when there are multiple."
|
||||
msgstr ""
|
||||
|
||||
#: src/gtk/connected-device.ui:282
|
||||
msgid "Viewport horizontal offset"
|
||||
msgstr ""
|
||||
|
||||
#: src/gtk/connected-device.ui:283
|
||||
msgid ""
|
||||
"By default, the viewport will center on the primary display. Use this slider "
|
||||
"to move the viewport to the left or right."
|
||||
msgstr ""
|
||||
|
||||
#: src/gtk/connected-device.ui:312
|
||||
msgid "Viewport vertical offset"
|
||||
msgstr ""
|
||||
|
||||
#: src/gtk/connected-device.ui:313
|
||||
msgid ""
|
||||
"By default, the viewport will center on the primary display. Use this slider "
|
||||
"to move the viewport up or down."
|
||||
msgstr ""
|
||||
|
||||
#: src/gtk/connected-device.ui:349 src/gtk/connected-device.ui:355
|
||||
msgid "Keyboard Shortcuts"
|
||||
msgstr "Сочетания клавиш"
|
||||
|
||||
#: src/gtk/connected-device.ui:218
|
||||
#: src/gtk/connected-device.ui:358
|
||||
msgid "XR Effect on/off shortcut"
|
||||
msgstr ""
|
||||
|
||||
#: src/gtk/connected-device.ui:219
|
||||
#: src/gtk/connected-device.ui:359
|
||||
msgid ""
|
||||
"Quickly enable or disable the XR Effect. You may need to enable the effect "
|
||||
"manually once in order to enable the shortcut."
|
||||
msgstr ""
|
||||
|
||||
#: src/gtk/connected-device.ui:238 src/gtk/connected-device.ui:267
|
||||
#: src/gtk/connected-device.ui:296 src/gtk/connected-device.ui:325
|
||||
#: src/gtk/connected-device.ui:378 src/gtk/connected-device.ui:407
|
||||
#: src/gtk/connected-device.ui:436 src/gtk/connected-device.ui:465
|
||||
msgid "Change"
|
||||
msgstr "Изменить"
|
||||
|
||||
#: src/gtk/connected-device.ui:247
|
||||
#: src/gtk/connected-device.ui:387
|
||||
msgid "Re-center display shortcut"
|
||||
msgstr "Сочетание клавиш для перецентровки дисплея"
|
||||
|
||||
#: src/gtk/connected-device.ui:248
|
||||
#: src/gtk/connected-device.ui:388
|
||||
msgid "Pin the virtual display to the current position."
|
||||
msgstr "Фиксировать виртуальный дисплей в текущем положении."
|
||||
|
||||
#: src/gtk/connected-device.ui:276
|
||||
msgid "Display distance shortcut"
|
||||
msgstr "Сочетание клавиш для расстояния дисплея"
|
||||
#: src/gtk/connected-device.ui:416
|
||||
#, fuzzy
|
||||
msgid "Toggle zoom on focus shortcut"
|
||||
msgstr "Сочетание клавиш для переключения режима следования"
|
||||
|
||||
#: src/gtk/connected-device.ui:277
|
||||
msgid "Quickly toggle between two predefined distances."
|
||||
msgstr "Быстро переключаться между двумя предопределенными расстояниями."
|
||||
#: src/gtk/connected-device.ui:417
|
||||
#, fuzzy
|
||||
msgid "Quickly toggle zoom on focus mode."
|
||||
msgstr "Быстро переключать режим следования."
|
||||
|
||||
#: src/gtk/connected-device.ui:305
|
||||
#: src/gtk/connected-device.ui:445
|
||||
msgid "Toggle follow mode shortcut"
|
||||
msgstr "Сочетание клавиш для переключения режима следования"
|
||||
|
||||
#: src/gtk/connected-device.ui:306
|
||||
#: src/gtk/connected-device.ui:446
|
||||
msgid "Quickly toggle follow mode."
|
||||
msgstr "Быстро переключать режим следования."
|
||||
|
||||
#: src/gtk/connected-device.ui:341 src/gtk/connected-device.ui:347
|
||||
#: src/gtk/connected-device.ui:481 src/gtk/connected-device.ui:487
|
||||
msgid "Advanced Settings"
|
||||
msgstr "Дополнительные настройки"
|
||||
|
||||
#: src/gtk/connected-device.ui:350
|
||||
#: src/gtk/connected-device.ui:490
|
||||
msgid "Find optimal display config"
|
||||
msgstr "Найти оптимальную конфигурацию дисплея"
|
||||
|
||||
#: src/gtk/connected-device.ui:351
|
||||
#: src/gtk/connected-device.ui:491
|
||||
msgid ""
|
||||
"Automatically modify the glasses display configuration for maximum "
|
||||
"resolution and best scaling when plugged in."
|
||||
|
|
@ -293,43 +397,31 @@ msgstr ""
|
|||
"Автоматически изменять конфигурацию дисплея очков для максимального "
|
||||
"разрешения и лучшей масштабирования при подключении."
|
||||
|
||||
#: src/gtk/connected-device.ui:361
|
||||
#: src/gtk/connected-device.ui:501
|
||||
msgid "Use highest refresh rate"
|
||||
msgstr "Использовать высшую частоту обновления"
|
||||
|
||||
#: src/gtk/connected-device.ui:362
|
||||
#: src/gtk/connected-device.ui:502
|
||||
msgid "Refresh rate may affect performance, disable this to set it manually."
|
||||
msgstr ""
|
||||
"Частота обновления может повлиять на производительность, отключите это, "
|
||||
"чтобы установить ее вручную."
|
||||
|
||||
#: src/gtk/connected-device.ui:372
|
||||
#: src/gtk/connected-device.ui:512
|
||||
msgid "Always primary display"
|
||||
msgstr "Всегда основной дисплей"
|
||||
|
||||
#: src/gtk/connected-device.ui:373
|
||||
#: src/gtk/connected-device.ui:513
|
||||
msgid "Automatically set the glasses as the primary display when plugged in."
|
||||
msgstr ""
|
||||
"Автоматически устанавливать очки в качестве основного дисплея при "
|
||||
"подключении."
|
||||
|
||||
#: src/gtk/connected-device.ui:383
|
||||
msgid "Fast SBS mode switching"
|
||||
msgstr "Быстрое переключение режима SBS"
|
||||
|
||||
#: src/gtk/connected-device.ui:384
|
||||
msgid ""
|
||||
"Switches glasses to SBS mode immediately when plugged in, if widescreen mode "
|
||||
"is on. May cause instability."
|
||||
msgstr ""
|
||||
"Переключает очки в режим SBS сразу при подключении, если режим широкого "
|
||||
"экрана включен. Может вызвать нестабильность."
|
||||
|
||||
#: src/gtk/connected-device.ui:394
|
||||
#: src/gtk/connected-device.ui:523
|
||||
msgid "Movement look-ahead"
|
||||
msgstr "Прогнозирование движения"
|
||||
|
||||
#: src/gtk/connected-device.ui:395
|
||||
#: src/gtk/connected-device.ui:524
|
||||
msgid ""
|
||||
"Counteracts input lag by predicting head-tracking position ahead of render "
|
||||
"time. Stick with default unless virtual display drags behind your head "
|
||||
|
|
@ -340,18 +432,34 @@ msgstr ""
|
|||
"виртуальный дисплей не отстает от движений вашей головы, не опережает или не "
|
||||
"очень трясётся."
|
||||
|
||||
#: src/gtk/connected-device.ui:413
|
||||
#: src/gtk/connected-device.ui:542
|
||||
msgid "Default"
|
||||
msgstr "По умолчанию"
|
||||
|
||||
#: src/gtk/connected-device.ui:425
|
||||
#: src/gtk/connected-device.ui:554
|
||||
msgid "Text Scaling"
|
||||
msgstr ""
|
||||
|
||||
#: src/gtk/connected-device.ui:426
|
||||
#: src/gtk/connected-device.ui:555
|
||||
msgid "Scaling text below 1.0 will simulate a higher resolution display"
|
||||
msgstr ""
|
||||
|
||||
#: src/gtk/connected-device.ui:585
|
||||
msgid "Enable multi-tap detection"
|
||||
msgstr ""
|
||||
|
||||
#: src/gtk/connected-device.ui:586
|
||||
msgid "Enables double-tap to recenter and triple-tap to recalibrate."
|
||||
msgstr ""
|
||||
|
||||
#: src/gtk/display-distance-dialog.ui:9
|
||||
msgid "Show full range"
|
||||
msgstr ""
|
||||
|
||||
#: src/gtk/display-distance-dialog.ui:18
|
||||
msgid "Done"
|
||||
msgstr ""
|
||||
|
||||
#: src/gtk/failed-verification.ui:13
|
||||
msgid "Breezy Desktop GNOME invalid setup"
|
||||
msgstr "Недействительная настройка Breezy Desktop GNOME"
|
||||
|
|
@ -400,15 +508,6 @@ msgid ""
|
|||
"connected."
|
||||
msgstr ""
|
||||
|
||||
#: src/gtk/no-device.ui:34
|
||||
#, fuzzy
|
||||
msgid "Start in widescreen mode"
|
||||
msgstr "Режим широкого экрана"
|
||||
|
||||
#: src/gtk/no-device.ui:35
|
||||
msgid "Widescreen mode is not supported for all glasses."
|
||||
msgstr ""
|
||||
|
||||
#: src/gtk/no-driver.ui:13
|
||||
msgid "No driver running"
|
||||
msgstr "Драйвер не запущен"
|
||||
|
|
@ -517,3 +616,57 @@ msgstr "Сброс"
|
|||
#: src/gtk/window.ui:99
|
||||
msgid "About BreezyDesktop"
|
||||
msgstr "О BreezyDesktop"
|
||||
|
||||
#~ msgid "Fast SBS mode switching"
|
||||
#~ msgstr "Быстрое переключение режима SBS"
|
||||
|
||||
#~ msgid ""
|
||||
#~ "Switches glasses to SBS mode immediately when plugged in, if widescreen "
|
||||
#~ "mode is on. May cause instability."
|
||||
#~ msgstr ""
|
||||
#~ "Переключает очки в режим SBS сразу при подключении, если режим широкого "
|
||||
#~ "экрана включен. Может вызвать нестабильность."
|
||||
|
||||
#, fuzzy
|
||||
#~ msgid "Set Unfocused Displays Distance"
|
||||
#~ msgstr "Расстояние дисплея"
|
||||
|
||||
#~ msgid "Widescreen mode"
|
||||
#~ msgstr "Режим широкого экрана"
|
||||
|
||||
#~ msgid "Switch between flat and curved displays."
|
||||
#~ msgstr "Переключается между плоскими и изогнутыми дисплеями."
|
||||
|
||||
#~ msgid ""
|
||||
#~ "Closer appears larger, further appears smaller. Controls depth when in "
|
||||
#~ "widescreen mode."
|
||||
#~ msgstr ""
|
||||
#~ "Чем ближе, тем больше. Чем дальше, тем меньше. Управляет глубиной при "
|
||||
#~ "использовании режима широкого экрана."
|
||||
|
||||
#~ msgid ""
|
||||
#~ "Combine with display distance to achieve a comfortable level of depth and "
|
||||
#~ "size."
|
||||
#~ msgstr ""
|
||||
#~ "Комбинируйте с расстоянием дисплея, чтобы достичь комфортного уровня "
|
||||
#~ "глубины и размера."
|
||||
|
||||
#~ msgid "Display toggle distances"
|
||||
#~ msgstr "Переключения расстояние дисплея"
|
||||
|
||||
#~ msgid ""
|
||||
#~ "Use the buttons to capture the current display distance for use with the "
|
||||
#~ "keyboard shortcut."
|
||||
#~ msgstr ""
|
||||
#~ "Используйте кнопки, чтобы зафиксировать текущее расстояние дисплея для "
|
||||
#~ "использования с сочетанием клавиш."
|
||||
|
||||
#~ msgid "Display distance shortcut"
|
||||
#~ msgstr "Сочетание клавиш для расстояния дисплея"
|
||||
|
||||
#~ msgid "Quickly toggle between two predefined distances."
|
||||
#~ msgstr "Быстро переключаться между двумя предопределенными расстояниями."
|
||||
|
||||
#, fuzzy
|
||||
#~ msgid "Start in widescreen mode"
|
||||
#~ msgstr "Режим широкого экрана"
|
||||
|
|
|
|||
348
ui/po/sv.po
348
ui/po/sv.po
|
|
@ -7,7 +7,7 @@ msgid ""
|
|||
msgstr ""
|
||||
"Project-Id-Version: PACKAGE VERSION\n"
|
||||
"Report-Msgid-Bugs-To: \n"
|
||||
"POT-Creation-Date: 2024-10-22 13:27-0700\n"
|
||||
"POT-Creation-Date: 2025-03-05 12:28-0800\n"
|
||||
"PO-Revision-Date: 2024-08-16 10:31-0700\n"
|
||||
"Last-Translator: <wayne@xronlinux.com>\n"
|
||||
"Language-Team: Swedish <tp-sv@listor.tp-sv.se>\n"
|
||||
|
|
@ -17,7 +17,7 @@ msgstr ""
|
|||
"Content-Transfer-Encoding: 8bit\n"
|
||||
"Plural-Forms: nplurals=2; plural=(n != 1);\n"
|
||||
|
||||
#: src/connecteddevice.py:17
|
||||
#: src/connecteddevice.py:23
|
||||
msgid ""
|
||||
"Switches your glasses into side-by-side mode and doubles the width of the "
|
||||
"display."
|
||||
|
|
@ -25,10 +25,56 @@ msgstr ""
|
|||
"Växlar dina glasögon till side-by-side-läget och dubblerar bredden på "
|
||||
"visningen."
|
||||
|
||||
#: src/connecteddevice.py:18
|
||||
#: src/connecteddevice.py:24
|
||||
msgid "This feature is not currently supported for your device."
|
||||
msgstr "Din enhet stöder inte den här funktionen för tillfället."
|
||||
|
||||
#: src/connecteddevice.py:124
|
||||
#, fuzzy
|
||||
msgid "Set Focused Display Distance"
|
||||
msgstr "Avstånd till skärmen"
|
||||
|
||||
#: src/connecteddevice.py:125
|
||||
msgid "Use a closer value so the display zooms in when you look at it."
|
||||
msgstr ""
|
||||
|
||||
#: src/connecteddevice.py:132
|
||||
#, fuzzy
|
||||
msgid "Set All Displays Distance"
|
||||
msgstr "Avstånd till skärmen"
|
||||
|
||||
#: src/connecteddevice.py:133
|
||||
msgid "Use a farther value so the displays are zoomed out when you look away."
|
||||
msgstr ""
|
||||
|
||||
#: src/connecteddevice.py:231
|
||||
msgid ""
|
||||
"Unable to add virtual displays on this machine. xdg-desktop-portal is "
|
||||
"required."
|
||||
msgstr ""
|
||||
|
||||
#: src/connecteddevice.py:265
|
||||
#, fuzzy
|
||||
msgid "Focused display"
|
||||
msgstr "Avstånd till skärmen"
|
||||
|
||||
#: src/connecteddevice.py:271
|
||||
#, fuzzy
|
||||
msgid "All displays"
|
||||
msgstr "Böjd skärm"
|
||||
|
||||
#: src/displaydistancedialogcontent.py:41
|
||||
msgid "closer"
|
||||
msgstr ""
|
||||
|
||||
#: src/displaydistancedialogcontent.py:45
|
||||
msgid "fullscreen"
|
||||
msgstr ""
|
||||
|
||||
#: src/displaydistancedialogcontent.py:48
|
||||
msgid "farther"
|
||||
msgstr ""
|
||||
|
||||
#: src/licensedialogcontent.py:63
|
||||
msgid "Paid Tier Status"
|
||||
msgstr "Betalningsstatus"
|
||||
|
|
@ -37,7 +83,7 @@ msgstr "Betalningsstatus"
|
|||
msgid "Feature Availability"
|
||||
msgstr "Funktions tillgänglighet"
|
||||
|
||||
#: src/licensefeaturerow.py:15 src/shortcutdialog.py:107
|
||||
#: src/licensefeaturerow.py:15 src/shortcutdialog.py:104
|
||||
msgid "Disabled"
|
||||
msgstr "Inaktiverad"
|
||||
|
||||
|
|
@ -166,82 +212,138 @@ msgid "Enables the Breezy Desktop XR effect."
|
|||
msgstr "Aktiverar Breezy Desktop XR-effekten."
|
||||
|
||||
#: src/gtk/connected-device.ui:55
|
||||
msgid "Widescreen mode"
|
||||
msgstr "Bredbildsläge"
|
||||
msgid "Zoom on focus"
|
||||
msgstr ""
|
||||
|
||||
#: src/gtk/connected-device.ui:66
|
||||
#: src/gtk/connected-device.ui:56
|
||||
msgid ""
|
||||
"Automatically move a display closer when you look at it.\n"
|
||||
"Set your preferred focused and unfocused distances in the Adjustments "
|
||||
"section.\n"
|
||||
" "
|
||||
msgstr ""
|
||||
|
||||
#: src/gtk/connected-device.ui:69
|
||||
msgid "Follow mode"
|
||||
msgstr "Följningsläge"
|
||||
|
||||
#: src/gtk/connected-device.ui:67
|
||||
msgid "Keep the virtual display near the center of your view."
|
||||
#: src/gtk/connected-device.ui:70
|
||||
#, fuzzy
|
||||
msgid "Keep the focused display near the center of your view."
|
||||
msgstr "Håll den virtuella skärmen nära mitten av din syn."
|
||||
|
||||
#: src/gtk/connected-device.ui:77
|
||||
msgid "Curved display"
|
||||
msgstr "Böjd skärm"
|
||||
#: src/gtk/connected-device.ui:80 src/gtk/no-device.ui:34
|
||||
msgid "Disable physical displays"
|
||||
msgstr ""
|
||||
|
||||
#: src/gtk/connected-device.ui:78
|
||||
msgid "Switch between flat and curved displays."
|
||||
msgstr "Växla mellan platt eller böjd skärm."
|
||||
#: src/gtk/connected-device.ui:81 src/gtk/no-device.ui:35
|
||||
msgid ""
|
||||
"Automatically disable all physical displays when the XR effect is enabled."
|
||||
msgstr ""
|
||||
|
||||
#: src/gtk/connected-device.ui:91
|
||||
#, fuzzy
|
||||
msgid "Virtual displays"
|
||||
msgstr "Böjd skärm"
|
||||
|
||||
#: src/gtk/connected-device.ui:103
|
||||
#, fuzzy
|
||||
msgid "Rearrange displays"
|
||||
msgstr "Böjd skärm"
|
||||
|
||||
#: src/gtk/connected-device.ui:115
|
||||
msgid "1080p"
|
||||
msgstr ""
|
||||
|
||||
#: src/gtk/connected-device.ui:116
|
||||
msgid "1440p"
|
||||
msgstr ""
|
||||
|
||||
#: src/gtk/connected-device.ui:140
|
||||
msgid "Adjustments"
|
||||
msgstr "Justeringar"
|
||||
|
||||
#: src/gtk/connected-device.ui:94
|
||||
msgid "Display distance"
|
||||
#: src/gtk/connected-device.ui:143
|
||||
#, fuzzy
|
||||
msgid "Display distances"
|
||||
msgstr "Avstånd till skärmen"
|
||||
|
||||
#: src/gtk/connected-device.ui:95
|
||||
msgid ""
|
||||
"Closer appears larger, further appears smaller. Controls depth when in "
|
||||
"widescreen mode."
|
||||
#: src/gtk/connected-device.ui:144
|
||||
msgid "Set how close you want displays to appear."
|
||||
msgstr ""
|
||||
"Närmare verkar större, längre verkar mindre. Kontrollerar djupet när du är i "
|
||||
"bredbildsläge."
|
||||
|
||||
#: src/gtk/connected-device.ui:123
|
||||
msgid "Display size"
|
||||
msgstr "Skärmens storlek"
|
||||
|
||||
#: src/gtk/connected-device.ui:124
|
||||
msgid ""
|
||||
"Combine with display distance to achieve a comfortable level of depth and "
|
||||
"size."
|
||||
msgstr ""
|
||||
"Kombinera med skärmens avstånd för att uppnå en bekväm nivå av djup och "
|
||||
"storlek."
|
||||
|
||||
#: src/gtk/connected-device.ui:152
|
||||
msgid "Display toggle distances"
|
||||
msgstr "Växla skärm-avstånd"
|
||||
|
||||
#: src/gtk/connected-device.ui:153
|
||||
msgid ""
|
||||
"Use the buttons to capture the current display distance for use with the "
|
||||
"keyboard shortcut."
|
||||
msgstr ""
|
||||
"Använd knapparna för att fanga nuvarande skärmavståndet för användning med "
|
||||
"tangentbordsgenvägar."
|
||||
|
||||
#: src/gtk/connected-device.ui:178
|
||||
#: src/gtk/connected-device.ui:199
|
||||
msgid "Follow threshold"
|
||||
msgstr "Automatisk följtröskel"
|
||||
|
||||
#: src/gtk/connected-device.ui:179
|
||||
#: src/gtk/connected-device.ui:200
|
||||
msgid "How far away you can look before the display follows."
|
||||
msgstr "Huvudrörelsetröskel för automatisk efterföljning."
|
||||
|
||||
#: src/gtk/connected-device.ui:209 src/gtk/connected-device.ui:215
|
||||
#: src/gtk/connected-device.ui:223
|
||||
#, fuzzy
|
||||
msgid "Display angling"
|
||||
msgstr "Skärmens storlek"
|
||||
|
||||
#: src/gtk/connected-device.ui:224
|
||||
msgid ""
|
||||
"When there are multiple displays, choose how they should angle towards you."
|
||||
msgstr ""
|
||||
|
||||
#: src/gtk/connected-device.ui:238
|
||||
msgid "Automatic"
|
||||
msgstr ""
|
||||
|
||||
#: src/gtk/connected-device.ui:239
|
||||
msgid "Side-angled"
|
||||
msgstr ""
|
||||
|
||||
#: src/gtk/connected-device.ui:240
|
||||
msgid "Top-angled"
|
||||
msgstr ""
|
||||
|
||||
#: src/gtk/connected-device.ui:241
|
||||
msgid "Flat"
|
||||
msgstr ""
|
||||
|
||||
#: src/gtk/connected-device.ui:251
|
||||
#, fuzzy
|
||||
msgid "Display spacing"
|
||||
msgstr "Skärmens storlek"
|
||||
|
||||
#: src/gtk/connected-device.ui:252
|
||||
msgid "Put empty space between displays, when there are multiple."
|
||||
msgstr ""
|
||||
|
||||
#: src/gtk/connected-device.ui:282
|
||||
msgid "Viewport horizontal offset"
|
||||
msgstr ""
|
||||
|
||||
#: src/gtk/connected-device.ui:283
|
||||
msgid ""
|
||||
"By default, the viewport will center on the primary display. Use this slider "
|
||||
"to move the viewport to the left or right."
|
||||
msgstr ""
|
||||
|
||||
#: src/gtk/connected-device.ui:312
|
||||
msgid "Viewport vertical offset"
|
||||
msgstr ""
|
||||
|
||||
#: src/gtk/connected-device.ui:313
|
||||
msgid ""
|
||||
"By default, the viewport will center on the primary display. Use this slider "
|
||||
"to move the viewport up or down."
|
||||
msgstr ""
|
||||
|
||||
#: src/gtk/connected-device.ui:349 src/gtk/connected-device.ui:355
|
||||
msgid "Keyboard Shortcuts"
|
||||
msgstr "Tangentbordsgenvägar"
|
||||
|
||||
#: src/gtk/connected-device.ui:218
|
||||
#: src/gtk/connected-device.ui:358
|
||||
msgid "XR Effect on/off shortcut"
|
||||
msgstr "XR-Effekt genväg på/av"
|
||||
|
||||
#: src/gtk/connected-device.ui:219
|
||||
#: src/gtk/connected-device.ui:359
|
||||
msgid ""
|
||||
"Quickly enable or disable the XR Effect. You may need to enable the effect "
|
||||
"manually once in order to enable the shortcut."
|
||||
|
|
@ -249,44 +351,46 @@ msgstr ""
|
|||
"Skifta snabbt mellan att slå av eller på XR-Effekt. Du kan behöva slå på den "
|
||||
"manuellt en gång för att genvägen ska fungera."
|
||||
|
||||
#: src/gtk/connected-device.ui:238 src/gtk/connected-device.ui:267
|
||||
#: src/gtk/connected-device.ui:296 src/gtk/connected-device.ui:325
|
||||
#: src/gtk/connected-device.ui:378 src/gtk/connected-device.ui:407
|
||||
#: src/gtk/connected-device.ui:436 src/gtk/connected-device.ui:465
|
||||
msgid "Change"
|
||||
msgstr "Ändra"
|
||||
|
||||
#: src/gtk/connected-device.ui:247
|
||||
#: src/gtk/connected-device.ui:387
|
||||
msgid "Re-center display shortcut"
|
||||
msgstr "Om-centrering tangentbordsgenväg"
|
||||
|
||||
#: src/gtk/connected-device.ui:248
|
||||
#: src/gtk/connected-device.ui:388
|
||||
msgid "Pin the virtual display to the current position."
|
||||
msgstr "Fäst den virtuella skärmen i den nuvarande positionen."
|
||||
|
||||
#: src/gtk/connected-device.ui:276
|
||||
msgid "Display distance shortcut"
|
||||
msgstr "Skärm avstånd genväg"
|
||||
#: src/gtk/connected-device.ui:416
|
||||
#, fuzzy
|
||||
msgid "Toggle zoom on focus shortcut"
|
||||
msgstr "Växla följ läge kort"
|
||||
|
||||
#: src/gtk/connected-device.ui:277
|
||||
msgid "Quickly toggle between two predefined distances."
|
||||
msgstr "Växla snabbt mellan två fördefinierade avstånd."
|
||||
#: src/gtk/connected-device.ui:417
|
||||
#, fuzzy
|
||||
msgid "Quickly toggle zoom on focus mode."
|
||||
msgstr "Växla snabbt följ läge."
|
||||
|
||||
#: src/gtk/connected-device.ui:305
|
||||
#: src/gtk/connected-device.ui:445
|
||||
msgid "Toggle follow mode shortcut"
|
||||
msgstr "Växla följ läge kort"
|
||||
|
||||
#: src/gtk/connected-device.ui:306
|
||||
#: src/gtk/connected-device.ui:446
|
||||
msgid "Quickly toggle follow mode."
|
||||
msgstr "Växla snabbt följ läge."
|
||||
|
||||
#: src/gtk/connected-device.ui:341 src/gtk/connected-device.ui:347
|
||||
#: src/gtk/connected-device.ui:481 src/gtk/connected-device.ui:487
|
||||
msgid "Advanced Settings"
|
||||
msgstr "Avancerade inställningar"
|
||||
|
||||
#: src/gtk/connected-device.ui:350
|
||||
#: src/gtk/connected-device.ui:490
|
||||
msgid "Find optimal display config"
|
||||
msgstr "Hitta optimal konfiguration till skärmen"
|
||||
|
||||
#: src/gtk/connected-device.ui:351
|
||||
#: src/gtk/connected-device.ui:491
|
||||
msgid ""
|
||||
"Automatically modify the glasses display configuration for maximum "
|
||||
"resolution and best scaling when plugged in."
|
||||
|
|
@ -294,41 +398,29 @@ msgstr ""
|
|||
"Ändrar automatisk glasögonens skärmkonfiguration för maximal upplösning och "
|
||||
"bästa skälning när den är ansluten."
|
||||
|
||||
#: src/gtk/connected-device.ui:361
|
||||
#: src/gtk/connected-device.ui:501
|
||||
msgid "Use highest refresh rate"
|
||||
msgstr "Använd högsta uppdateringsfrekvens"
|
||||
|
||||
#: src/gtk/connected-device.ui:362
|
||||
#: src/gtk/connected-device.ui:502
|
||||
msgid "Refresh rate may affect performance, disable this to set it manually."
|
||||
msgstr ""
|
||||
"Uppdateringsfrekvens kan påverka prestanda, inaktivera detta för att ställa "
|
||||
"in det manuellt."
|
||||
|
||||
#: src/gtk/connected-device.ui:372
|
||||
#: src/gtk/connected-device.ui:512
|
||||
msgid "Always primary display"
|
||||
msgstr "Alltid primär skärm"
|
||||
|
||||
#: src/gtk/connected-device.ui:373
|
||||
#: src/gtk/connected-device.ui:513
|
||||
msgid "Automatically set the glasses as the primary display when plugged in."
|
||||
msgstr "Ställer automatisk glasögon som primär skärm när den är ansluten."
|
||||
|
||||
#: src/gtk/connected-device.ui:383
|
||||
msgid "Fast SBS mode switching"
|
||||
msgstr "Snabb SBS läge växling"
|
||||
|
||||
#: src/gtk/connected-device.ui:384
|
||||
msgid ""
|
||||
"Switches glasses to SBS mode immediately when plugged in, if widescreen mode "
|
||||
"is on. May cause instability."
|
||||
msgstr ""
|
||||
"Växlar glasögon till SBS läge omedelbart när den är ansluten, om bredbildsläge är "
|
||||
"på. Kan orsaka instabilitet."
|
||||
|
||||
#: src/gtk/connected-device.ui:394
|
||||
#: src/gtk/connected-device.ui:523
|
||||
msgid "Movement look-ahead"
|
||||
msgstr "Rörs förväntning"
|
||||
|
||||
#: src/gtk/connected-device.ui:395
|
||||
#: src/gtk/connected-device.ui:524
|
||||
msgid ""
|
||||
"Counteracts input lag by predicting head-tracking position ahead of render "
|
||||
"time. Stick with default unless virtual display drags behind your head "
|
||||
|
|
@ -337,18 +429,34 @@ msgstr ""
|
|||
"Motverkar ingångsfördröjning genom förutsägelse av huvudrörelser.Behåll "
|
||||
"standardinställningen om inte skärmen skakar mycket eller rörsig konstigt."
|
||||
|
||||
#: src/gtk/connected-device.ui:413
|
||||
#: src/gtk/connected-device.ui:542
|
||||
msgid "Default"
|
||||
msgstr "Standard"
|
||||
|
||||
#: src/gtk/connected-device.ui:425
|
||||
#: src/gtk/connected-device.ui:554
|
||||
msgid "Text Scaling"
|
||||
msgstr "Textskalning"
|
||||
|
||||
#: src/gtk/connected-device.ui:426
|
||||
#: src/gtk/connected-device.ui:555
|
||||
msgid "Scaling text below 1.0 will simulate a higher resolution display"
|
||||
msgstr "Textskalning under 1.0 kommer att simulera en högre skärmupplösning"
|
||||
|
||||
#: src/gtk/connected-device.ui:585
|
||||
msgid "Enable multi-tap detection"
|
||||
msgstr ""
|
||||
|
||||
#: src/gtk/connected-device.ui:586
|
||||
msgid "Enables double-tap to recenter and triple-tap to recalibrate."
|
||||
msgstr ""
|
||||
|
||||
#: src/gtk/display-distance-dialog.ui:9
|
||||
msgid "Show full range"
|
||||
msgstr ""
|
||||
|
||||
#: src/gtk/display-distance-dialog.ui:18
|
||||
msgid "Done"
|
||||
msgstr ""
|
||||
|
||||
#: src/gtk/failed-verification.ui:13
|
||||
msgid "Breezy Desktop GNOME invalid setup"
|
||||
msgstr "Breezy Desktop GNOME ogiltig inställning"
|
||||
|
|
@ -397,14 +505,6 @@ msgstr ""
|
|||
"Aktivera Breezy Desktop XR-effekten automatiskt när glasögon som stöds är "
|
||||
"anslutna."
|
||||
|
||||
#: src/gtk/no-device.ui:34
|
||||
msgid "Start in widescreen mode"
|
||||
msgstr "Starta i bredbildsläge"
|
||||
|
||||
#: src/gtk/no-device.ui:35
|
||||
msgid "Widescreen mode is not supported for all glasses."
|
||||
msgstr "Bredbildsläge stöds inte av alla glasögon."
|
||||
|
||||
#: src/gtk/no-driver.ui:13
|
||||
msgid "No driver running"
|
||||
msgstr "Inget drivrutin köres"
|
||||
|
|
@ -513,3 +613,59 @@ msgstr "Tvinga Reset"
|
|||
#: src/gtk/window.ui:99
|
||||
msgid "About BreezyDesktop"
|
||||
msgstr "Om BreezyDesktop"
|
||||
|
||||
#~ msgid "Fast SBS mode switching"
|
||||
#~ msgstr "Snabb SBS läge växling"
|
||||
|
||||
#~ msgid ""
|
||||
#~ "Switches glasses to SBS mode immediately when plugged in, if widescreen "
|
||||
#~ "mode is on. May cause instability."
|
||||
#~ msgstr ""
|
||||
#~ "Växlar glasögon till SBS läge omedelbart när den är ansluten, om "
|
||||
#~ "bredbildsläge är på. Kan orsaka instabilitet."
|
||||
|
||||
#, fuzzy
|
||||
#~ msgid "Set Unfocused Displays Distance"
|
||||
#~ msgstr "Avstånd till skärmen"
|
||||
|
||||
#~ msgid "Widescreen mode"
|
||||
#~ msgstr "Bredbildsläge"
|
||||
|
||||
#~ msgid "Switch between flat and curved displays."
|
||||
#~ msgstr "Växla mellan platt eller böjd skärm."
|
||||
|
||||
#~ msgid ""
|
||||
#~ "Closer appears larger, further appears smaller. Controls depth when in "
|
||||
#~ "widescreen mode."
|
||||
#~ msgstr ""
|
||||
#~ "Närmare verkar större, längre verkar mindre. Kontrollerar djupet när du "
|
||||
#~ "är i bredbildsläge."
|
||||
|
||||
#~ msgid ""
|
||||
#~ "Combine with display distance to achieve a comfortable level of depth and "
|
||||
#~ "size."
|
||||
#~ msgstr ""
|
||||
#~ "Kombinera med skärmens avstånd för att uppnå en bekväm nivå av djup och "
|
||||
#~ "storlek."
|
||||
|
||||
#~ msgid "Display toggle distances"
|
||||
#~ msgstr "Växla skärm-avstånd"
|
||||
|
||||
#~ msgid ""
|
||||
#~ "Use the buttons to capture the current display distance for use with the "
|
||||
#~ "keyboard shortcut."
|
||||
#~ msgstr ""
|
||||
#~ "Använd knapparna för att fanga nuvarande skärmavståndet för användning "
|
||||
#~ "med tangentbordsgenvägar."
|
||||
|
||||
#~ msgid "Display distance shortcut"
|
||||
#~ msgstr "Skärm avstånd genväg"
|
||||
|
||||
#~ msgid "Quickly toggle between two predefined distances."
|
||||
#~ msgstr "Växla snabbt mellan två fördefinierade avstånd."
|
||||
|
||||
#~ msgid "Start in widescreen mode"
|
||||
#~ msgstr "Starta i bredbildsläge"
|
||||
|
||||
#~ msgid "Widescreen mode is not supported for all glasses."
|
||||
#~ msgstr "Bredbildsläge stöds inte av alla glasögon."
|
||||
|
|
|
|||
347
ui/po/uk_UA.po
347
ui/po/uk_UA.po
|
|
@ -7,7 +7,7 @@ msgid ""
|
|||
msgstr ""
|
||||
"Project-Id-Version: PACKAGE VERSION\n"
|
||||
"Report-Msgid-Bugs-To: \n"
|
||||
"POT-Creation-Date: 2024-10-22 13:27-0700\n"
|
||||
"POT-Creation-Date: 2025-03-05 12:28-0800\n"
|
||||
"PO-Revision-Date: 2024-08-17 10:08-0700\n"
|
||||
"Last-Translator: <wayne@xronlinux.com>\n"
|
||||
"Language-Team: Ukrainian <trans-uk@lists.fedoraproject.org>\n"
|
||||
|
|
@ -18,16 +18,62 @@ msgstr ""
|
|||
"Plural-Forms: nplurals=3; plural=(n%10==1 && n%100!=11 ? 0 : n%10>=2 && "
|
||||
"n%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2);\n"
|
||||
|
||||
#: src/connecteddevice.py:17
|
||||
#: src/connecteddevice.py:23
|
||||
msgid ""
|
||||
"Switches your glasses into side-by-side mode and doubles the width of the "
|
||||
"display."
|
||||
msgstr "Переключає окуляри в режим «бок о бок» і подвоює ширину дисплея."
|
||||
|
||||
#: src/connecteddevice.py:18
|
||||
#: src/connecteddevice.py:24
|
||||
msgid "This feature is not currently supported for your device."
|
||||
msgstr "Ця функція наразі не підтримується на вашому пристрої."
|
||||
|
||||
#: src/connecteddevice.py:124
|
||||
#, fuzzy
|
||||
msgid "Set Focused Display Distance"
|
||||
msgstr "Відстань дисплея"
|
||||
|
||||
#: src/connecteddevice.py:125
|
||||
msgid "Use a closer value so the display zooms in when you look at it."
|
||||
msgstr ""
|
||||
|
||||
#: src/connecteddevice.py:132
|
||||
#, fuzzy
|
||||
msgid "Set All Displays Distance"
|
||||
msgstr "Відстань дисплея"
|
||||
|
||||
#: src/connecteddevice.py:133
|
||||
msgid "Use a farther value so the displays are zoomed out when you look away."
|
||||
msgstr ""
|
||||
|
||||
#: src/connecteddevice.py:231
|
||||
msgid ""
|
||||
"Unable to add virtual displays on this machine. xdg-desktop-portal is "
|
||||
"required."
|
||||
msgstr ""
|
||||
|
||||
#: src/connecteddevice.py:265
|
||||
#, fuzzy
|
||||
msgid "Focused display"
|
||||
msgstr "Відстань дисплея"
|
||||
|
||||
#: src/connecteddevice.py:271
|
||||
#, fuzzy
|
||||
msgid "All displays"
|
||||
msgstr "Викривлений дисплей"
|
||||
|
||||
#: src/displaydistancedialogcontent.py:41
|
||||
msgid "closer"
|
||||
msgstr ""
|
||||
|
||||
#: src/displaydistancedialogcontent.py:45
|
||||
msgid "fullscreen"
|
||||
msgstr ""
|
||||
|
||||
#: src/displaydistancedialogcontent.py:48
|
||||
msgid "farther"
|
||||
msgstr ""
|
||||
|
||||
#: src/licensedialogcontent.py:63
|
||||
msgid "Paid Tier Status"
|
||||
msgstr "Статус платного рівня"
|
||||
|
|
@ -36,7 +82,7 @@ msgstr "Статус платного рівня"
|
|||
msgid "Feature Availability"
|
||||
msgstr "Статус функцій"
|
||||
|
||||
#: src/licensefeaturerow.py:15 src/shortcutdialog.py:107
|
||||
#: src/licensefeaturerow.py:15 src/shortcutdialog.py:104
|
||||
msgid "Disabled"
|
||||
msgstr "Вимкнено"
|
||||
|
||||
|
|
@ -165,127 +211,185 @@ msgid "Enables the Breezy Desktop XR effect."
|
|||
msgstr "Включає ефект Breezy Desktop XR."
|
||||
|
||||
#: src/gtk/connected-device.ui:55
|
||||
msgid "Widescreen mode"
|
||||
msgstr "Режим широкого екрану"
|
||||
msgid "Zoom on focus"
|
||||
msgstr ""
|
||||
|
||||
#: src/gtk/connected-device.ui:66
|
||||
#: src/gtk/connected-device.ui:56
|
||||
msgid ""
|
||||
"Automatically move a display closer when you look at it.\n"
|
||||
"Set your preferred focused and unfocused distances in the Adjustments "
|
||||
"section.\n"
|
||||
" "
|
||||
msgstr ""
|
||||
|
||||
#: src/gtk/connected-device.ui:69
|
||||
msgid "Follow mode"
|
||||
msgstr "Режим слідування"
|
||||
|
||||
#: src/gtk/connected-device.ui:67
|
||||
msgid "Keep the virtual display near the center of your view."
|
||||
#: src/gtk/connected-device.ui:70
|
||||
#, fuzzy
|
||||
msgid "Keep the focused display near the center of your view."
|
||||
msgstr "Зберігае віртуальний дисплей поблизу центру вашого зору."
|
||||
|
||||
#: src/gtk/connected-device.ui:77
|
||||
msgid "Curved display"
|
||||
msgstr "Викривлений дисплей"
|
||||
#: src/gtk/connected-device.ui:80 src/gtk/no-device.ui:34
|
||||
msgid "Disable physical displays"
|
||||
msgstr ""
|
||||
|
||||
#: src/gtk/connected-device.ui:78
|
||||
msgid "Switch between flat and curved displays."
|
||||
msgstr "Переключается між плоскими і викривленими дисплеями."
|
||||
#: src/gtk/connected-device.ui:81 src/gtk/no-device.ui:35
|
||||
msgid ""
|
||||
"Automatically disable all physical displays when the XR effect is enabled."
|
||||
msgstr ""
|
||||
|
||||
#: src/gtk/connected-device.ui:91
|
||||
#, fuzzy
|
||||
msgid "Virtual displays"
|
||||
msgstr "Викривлений дисплей"
|
||||
|
||||
#: src/gtk/connected-device.ui:103
|
||||
#, fuzzy
|
||||
msgid "Rearrange displays"
|
||||
msgstr "Викривлений дисплей"
|
||||
|
||||
#: src/gtk/connected-device.ui:115
|
||||
msgid "1080p"
|
||||
msgstr ""
|
||||
|
||||
#: src/gtk/connected-device.ui:116
|
||||
msgid "1440p"
|
||||
msgstr ""
|
||||
|
||||
#: src/gtk/connected-device.ui:140
|
||||
msgid "Adjustments"
|
||||
msgstr "Налаштування"
|
||||
|
||||
#: src/gtk/connected-device.ui:94
|
||||
msgid "Display distance"
|
||||
#: src/gtk/connected-device.ui:143
|
||||
#, fuzzy
|
||||
msgid "Display distances"
|
||||
msgstr "Відстань дисплея"
|
||||
|
||||
#: src/gtk/connected-device.ui:95
|
||||
msgid ""
|
||||
"Closer appears larger, further appears smaller. Controls depth when in "
|
||||
"widescreen mode."
|
||||
#: src/gtk/connected-device.ui:144
|
||||
msgid "Set how close you want displays to appear."
|
||||
msgstr ""
|
||||
"Чим ближче, тим більший. Чим далі, тим менший. Керує глибиною при "
|
||||
"використанні режиму широкого екрана."
|
||||
|
||||
#: src/gtk/connected-device.ui:123
|
||||
msgid "Display size"
|
||||
msgstr "Розмір дисплея"
|
||||
|
||||
#: src/gtk/connected-device.ui:124
|
||||
msgid ""
|
||||
"Combine with display distance to achieve a comfortable level of depth and "
|
||||
"size."
|
||||
msgstr ""
|
||||
"Поєднуйте з відстанню дисплея, щоб досягти комфортного рівня глибини і "
|
||||
"розміру."
|
||||
|
||||
#: src/gtk/connected-device.ui:152
|
||||
msgid "Display toggle distances"
|
||||
msgstr "Перемикання відстані дисплея"
|
||||
|
||||
#: src/gtk/connected-device.ui:153
|
||||
msgid ""
|
||||
"Use the buttons to capture the current display distance for use with the "
|
||||
"keyboard shortcut."
|
||||
msgstr ""
|
||||
"Використовуйте кнопки, щоб зафіксувати поточну відстань дисплея для "
|
||||
"використання з сполученням клавіш."
|
||||
|
||||
#: src/gtk/connected-device.ui:178
|
||||
#: src/gtk/connected-device.ui:199
|
||||
msgid "Follow threshold"
|
||||
msgstr "Поріг слідування"
|
||||
|
||||
#: src/gtk/connected-device.ui:179
|
||||
#: src/gtk/connected-device.ui:200
|
||||
msgid "How far away you can look before the display follows."
|
||||
msgstr ""
|
||||
"Як далеко ви можете відвернути ваш взор, перш ніж дисплей почне слідувати за "
|
||||
"вами."
|
||||
|
||||
#: src/gtk/connected-device.ui:209 src/gtk/connected-device.ui:215
|
||||
#: src/gtk/connected-device.ui:223
|
||||
#, fuzzy
|
||||
msgid "Display angling"
|
||||
msgstr "Розмір дисплея"
|
||||
|
||||
#: src/gtk/connected-device.ui:224
|
||||
msgid ""
|
||||
"When there are multiple displays, choose how they should angle towards you."
|
||||
msgstr ""
|
||||
|
||||
#: src/gtk/connected-device.ui:238
|
||||
msgid "Automatic"
|
||||
msgstr ""
|
||||
|
||||
#: src/gtk/connected-device.ui:239
|
||||
msgid "Side-angled"
|
||||
msgstr ""
|
||||
|
||||
#: src/gtk/connected-device.ui:240
|
||||
msgid "Top-angled"
|
||||
msgstr ""
|
||||
|
||||
#: src/gtk/connected-device.ui:241
|
||||
msgid "Flat"
|
||||
msgstr ""
|
||||
|
||||
#: src/gtk/connected-device.ui:251
|
||||
#, fuzzy
|
||||
msgid "Display spacing"
|
||||
msgstr "Розмір дисплея"
|
||||
|
||||
#: src/gtk/connected-device.ui:252
|
||||
msgid "Put empty space between displays, when there are multiple."
|
||||
msgstr ""
|
||||
|
||||
#: src/gtk/connected-device.ui:282
|
||||
msgid "Viewport horizontal offset"
|
||||
msgstr ""
|
||||
|
||||
#: src/gtk/connected-device.ui:283
|
||||
msgid ""
|
||||
"By default, the viewport will center on the primary display. Use this slider "
|
||||
"to move the viewport to the left or right."
|
||||
msgstr ""
|
||||
|
||||
#: src/gtk/connected-device.ui:312
|
||||
msgid "Viewport vertical offset"
|
||||
msgstr ""
|
||||
|
||||
#: src/gtk/connected-device.ui:313
|
||||
msgid ""
|
||||
"By default, the viewport will center on the primary display. Use this slider "
|
||||
"to move the viewport up or down."
|
||||
msgstr ""
|
||||
|
||||
#: src/gtk/connected-device.ui:349 src/gtk/connected-device.ui:355
|
||||
msgid "Keyboard Shortcuts"
|
||||
msgstr "Сполучення клавіш"
|
||||
|
||||
#: src/gtk/connected-device.ui:218
|
||||
#: src/gtk/connected-device.ui:358
|
||||
msgid "XR Effect on/off shortcut"
|
||||
msgstr ""
|
||||
|
||||
#: src/gtk/connected-device.ui:219
|
||||
#: src/gtk/connected-device.ui:359
|
||||
msgid ""
|
||||
"Quickly enable or disable the XR Effect. You may need to enable the effect "
|
||||
"manually once in order to enable the shortcut."
|
||||
msgstr ""
|
||||
|
||||
#: src/gtk/connected-device.ui:238 src/gtk/connected-device.ui:267
|
||||
#: src/gtk/connected-device.ui:296 src/gtk/connected-device.ui:325
|
||||
#: src/gtk/connected-device.ui:378 src/gtk/connected-device.ui:407
|
||||
#: src/gtk/connected-device.ui:436 src/gtk/connected-device.ui:465
|
||||
msgid "Change"
|
||||
msgstr "Змінити"
|
||||
|
||||
#: src/gtk/connected-device.ui:247
|
||||
#: src/gtk/connected-device.ui:387
|
||||
msgid "Re-center display shortcut"
|
||||
msgstr "Сполучення клавіш для центрування дисплея"
|
||||
|
||||
#: src/gtk/connected-device.ui:248
|
||||
#: src/gtk/connected-device.ui:388
|
||||
msgid "Pin the virtual display to the current position."
|
||||
msgstr "Фіксувати віртуальний дисплей у поточній позиції."
|
||||
|
||||
#: src/gtk/connected-device.ui:276
|
||||
msgid "Display distance shortcut"
|
||||
msgstr "Сполучення клавіш для відстані дисплея"
|
||||
#: src/gtk/connected-device.ui:416
|
||||
#, fuzzy
|
||||
msgid "Toggle zoom on focus shortcut"
|
||||
msgstr "Сполучення клавіш для перемикання режиму слідування"
|
||||
|
||||
#: src/gtk/connected-device.ui:277
|
||||
msgid "Quickly toggle between two predefined distances."
|
||||
msgstr "Швидко перемикатися між двома попередньо визначеними відстанями."
|
||||
#: src/gtk/connected-device.ui:417
|
||||
#, fuzzy
|
||||
msgid "Quickly toggle zoom on focus mode."
|
||||
msgstr "Швидко перемикати режим слідування."
|
||||
|
||||
#: src/gtk/connected-device.ui:305
|
||||
#: src/gtk/connected-device.ui:445
|
||||
msgid "Toggle follow mode shortcut"
|
||||
msgstr "Сполучення клавіш для перемикання режиму слідування"
|
||||
|
||||
#: src/gtk/connected-device.ui:306
|
||||
#: src/gtk/connected-device.ui:446
|
||||
msgid "Quickly toggle follow mode."
|
||||
msgstr "Швидко перемикати режим слідування."
|
||||
|
||||
#: src/gtk/connected-device.ui:341 src/gtk/connected-device.ui:347
|
||||
#: src/gtk/connected-device.ui:481 src/gtk/connected-device.ui:487
|
||||
msgid "Advanced Settings"
|
||||
msgstr "Додаткові налаштування"
|
||||
|
||||
#: src/gtk/connected-device.ui:350
|
||||
#: src/gtk/connected-device.ui:490
|
||||
msgid "Find optimal display config"
|
||||
msgstr "Знайти оптимальну конфігурацію дисплея"
|
||||
|
||||
#: src/gtk/connected-device.ui:351
|
||||
#: src/gtk/connected-device.ui:491
|
||||
msgid ""
|
||||
"Automatically modify the glasses display configuration for maximum "
|
||||
"resolution and best scaling when plugged in."
|
||||
|
|
@ -293,41 +397,29 @@ msgstr ""
|
|||
"Автоматично змінює конфігурацію дисплея окулярів для максимальної роздільної "
|
||||
"здатності і найкращого масштабування при підключенні."
|
||||
|
||||
#: src/gtk/connected-device.ui:361
|
||||
#: src/gtk/connected-device.ui:501
|
||||
msgid "Use highest refresh rate"
|
||||
msgstr "Використовувати найвищу частоту оновлення"
|
||||
|
||||
#: src/gtk/connected-device.ui:362
|
||||
#: src/gtk/connected-device.ui:502
|
||||
msgid "Refresh rate may affect performance, disable this to set it manually."
|
||||
msgstr ""
|
||||
"Частота оновлення може вплинути на продуктивність, вимкніть це, щоб "
|
||||
"встановити її вручну."
|
||||
|
||||
#: src/gtk/connected-device.ui:372
|
||||
#: src/gtk/connected-device.ui:512
|
||||
msgid "Always primary display"
|
||||
msgstr "Завжди основний дисплей"
|
||||
|
||||
#: src/gtk/connected-device.ui:373
|
||||
#: src/gtk/connected-device.ui:513
|
||||
msgid "Automatically set the glasses as the primary display when plugged in."
|
||||
msgstr "Автоматично встановлює окуляри як основний дисплей при підключенні."
|
||||
|
||||
#: src/gtk/connected-device.ui:383
|
||||
msgid "Fast SBS mode switching"
|
||||
msgstr "Швидке перемикання режиму SBS"
|
||||
|
||||
#: src/gtk/connected-device.ui:384
|
||||
msgid ""
|
||||
"Switches glasses to SBS mode immediately when plugged in, if widescreen mode "
|
||||
"is on. May cause instability."
|
||||
msgstr ""
|
||||
"Переключає окуляри в режим SBS відразу після підключення, якщо режим "
|
||||
"широкого екрана увімкнено. Може викликати нестабільність."
|
||||
|
||||
#: src/gtk/connected-device.ui:394
|
||||
#: src/gtk/connected-device.ui:523
|
||||
msgid "Movement look-ahead"
|
||||
msgstr "Прогнозування руху"
|
||||
|
||||
#: src/gtk/connected-device.ui:395
|
||||
#: src/gtk/connected-device.ui:524
|
||||
msgid ""
|
||||
"Counteracts input lag by predicting head-tracking position ahead of render "
|
||||
"time. Stick with default unless virtual display drags behind your head "
|
||||
|
|
@ -338,18 +430,34 @@ msgstr ""
|
|||
"віртуальний дисплей відстає від рухів вашої голови, випереджає або дуже "
|
||||
"тремтить."
|
||||
|
||||
#: src/gtk/connected-device.ui:413
|
||||
#: src/gtk/connected-device.ui:542
|
||||
msgid "Default"
|
||||
msgstr "За замовчуванням"
|
||||
|
||||
#: src/gtk/connected-device.ui:425
|
||||
#: src/gtk/connected-device.ui:554
|
||||
msgid "Text Scaling"
|
||||
msgstr ""
|
||||
|
||||
#: src/gtk/connected-device.ui:426
|
||||
#: src/gtk/connected-device.ui:555
|
||||
msgid "Scaling text below 1.0 will simulate a higher resolution display"
|
||||
msgstr ""
|
||||
|
||||
#: src/gtk/connected-device.ui:585
|
||||
msgid "Enable multi-tap detection"
|
||||
msgstr ""
|
||||
|
||||
#: src/gtk/connected-device.ui:586
|
||||
msgid "Enables double-tap to recenter and triple-tap to recalibrate."
|
||||
msgstr ""
|
||||
|
||||
#: src/gtk/display-distance-dialog.ui:9
|
||||
msgid "Show full range"
|
||||
msgstr ""
|
||||
|
||||
#: src/gtk/display-distance-dialog.ui:18
|
||||
msgid "Done"
|
||||
msgstr ""
|
||||
|
||||
#: src/gtk/failed-verification.ui:13
|
||||
msgid "Breezy Desktop GNOME invalid setup"
|
||||
msgstr "Невірна настройка Breezy Desktop GNOME"
|
||||
|
|
@ -397,15 +505,6 @@ msgid ""
|
|||
"connected."
|
||||
msgstr ""
|
||||
|
||||
#: src/gtk/no-device.ui:34
|
||||
#, fuzzy
|
||||
msgid "Start in widescreen mode"
|
||||
msgstr "Режим широкого екрану"
|
||||
|
||||
#: src/gtk/no-device.ui:35
|
||||
msgid "Widescreen mode is not supported for all glasses."
|
||||
msgstr ""
|
||||
|
||||
#: src/gtk/no-driver.ui:13
|
||||
msgid "No driver running"
|
||||
msgstr "Жоден драйвер не запущений"
|
||||
|
|
@ -514,3 +613,57 @@ msgstr "Скинути"
|
|||
#: src/gtk/window.ui:99
|
||||
msgid "About BreezyDesktop"
|
||||
msgstr "Про BreezyDesktop"
|
||||
|
||||
#~ msgid "Fast SBS mode switching"
|
||||
#~ msgstr "Швидке перемикання режиму SBS"
|
||||
|
||||
#~ msgid ""
|
||||
#~ "Switches glasses to SBS mode immediately when plugged in, if widescreen "
|
||||
#~ "mode is on. May cause instability."
|
||||
#~ msgstr ""
|
||||
#~ "Переключає окуляри в режим SBS відразу після підключення, якщо режим "
|
||||
#~ "широкого екрана увімкнено. Може викликати нестабільність."
|
||||
|
||||
#, fuzzy
|
||||
#~ msgid "Set Unfocused Displays Distance"
|
||||
#~ msgstr "Відстань дисплея"
|
||||
|
||||
#~ msgid "Widescreen mode"
|
||||
#~ msgstr "Режим широкого екрану"
|
||||
|
||||
#~ msgid "Switch between flat and curved displays."
|
||||
#~ msgstr "Переключается між плоскими і викривленими дисплеями."
|
||||
|
||||
#~ msgid ""
|
||||
#~ "Closer appears larger, further appears smaller. Controls depth when in "
|
||||
#~ "widescreen mode."
|
||||
#~ msgstr ""
|
||||
#~ "Чим ближче, тим більший. Чим далі, тим менший. Керує глибиною при "
|
||||
#~ "використанні режиму широкого екрана."
|
||||
|
||||
#~ msgid ""
|
||||
#~ "Combine with display distance to achieve a comfortable level of depth and "
|
||||
#~ "size."
|
||||
#~ msgstr ""
|
||||
#~ "Поєднуйте з відстанню дисплея, щоб досягти комфортного рівня глибини і "
|
||||
#~ "розміру."
|
||||
|
||||
#~ msgid "Display toggle distances"
|
||||
#~ msgstr "Перемикання відстані дисплея"
|
||||
|
||||
#~ msgid ""
|
||||
#~ "Use the buttons to capture the current display distance for use with the "
|
||||
#~ "keyboard shortcut."
|
||||
#~ msgstr ""
|
||||
#~ "Використовуйте кнопки, щоб зафіксувати поточну відстань дисплея для "
|
||||
#~ "використання з сполученням клавіш."
|
||||
|
||||
#~ msgid "Display distance shortcut"
|
||||
#~ msgstr "Сполучення клавіш для відстані дисплея"
|
||||
|
||||
#~ msgid "Quickly toggle between two predefined distances."
|
||||
#~ msgstr "Швидко перемикатися між двома попередньо визначеними відстанями."
|
||||
|
||||
#, fuzzy
|
||||
#~ msgid "Start in widescreen mode"
|
||||
#~ msgstr "Режим широкого екрану"
|
||||
|
|
|
|||
340
ui/po/zh_CN.po
340
ui/po/zh_CN.po
|
|
@ -7,7 +7,7 @@ msgid ""
|
|||
msgstr ""
|
||||
"Project-Id-Version: PACKAGE VERSION\n"
|
||||
"Report-Msgid-Bugs-To: \n"
|
||||
"POT-Creation-Date: 2024-10-22 13:27-0700\n"
|
||||
"POT-Creation-Date: 2025-03-05 12:28-0800\n"
|
||||
"PO-Revision-Date: 2024-08-02 20:55-0700\n"
|
||||
"Last-Translator: <wayne@xronlinux.com>\n"
|
||||
"Language-Team: Chinese (simplified) <i18n-zh@googlegroups.com>\n"
|
||||
|
|
@ -16,16 +16,62 @@ msgstr ""
|
|||
"Content-Type: text/plain; charset=UTF-8\n"
|
||||
"Content-Transfer-Encoding: 8bit\n"
|
||||
|
||||
#: src/connecteddevice.py:17
|
||||
#: src/connecteddevice.py:23
|
||||
msgid ""
|
||||
"Switches your glasses into side-by-side mode and doubles the width of the "
|
||||
"display."
|
||||
msgstr "切换到并排模式,并将显示宽度翻倍。"
|
||||
|
||||
#: src/connecteddevice.py:18
|
||||
#: src/connecteddevice.py:24
|
||||
msgid "This feature is not currently supported for your device."
|
||||
msgstr "您的设备目前不支援此功能。"
|
||||
|
||||
#: src/connecteddevice.py:124
|
||||
#, fuzzy
|
||||
msgid "Set Focused Display Distance"
|
||||
msgstr "显示距离"
|
||||
|
||||
#: src/connecteddevice.py:125
|
||||
msgid "Use a closer value so the display zooms in when you look at it."
|
||||
msgstr ""
|
||||
|
||||
#: src/connecteddevice.py:132
|
||||
#, fuzzy
|
||||
msgid "Set All Displays Distance"
|
||||
msgstr "显示距离"
|
||||
|
||||
#: src/connecteddevice.py:133
|
||||
msgid "Use a farther value so the displays are zoomed out when you look away."
|
||||
msgstr ""
|
||||
|
||||
#: src/connecteddevice.py:231
|
||||
msgid ""
|
||||
"Unable to add virtual displays on this machine. xdg-desktop-portal is "
|
||||
"required."
|
||||
msgstr ""
|
||||
|
||||
#: src/connecteddevice.py:265
|
||||
#, fuzzy
|
||||
msgid "Focused display"
|
||||
msgstr "显示距离"
|
||||
|
||||
#: src/connecteddevice.py:271
|
||||
#, fuzzy
|
||||
msgid "All displays"
|
||||
msgstr "曲面显示"
|
||||
|
||||
#: src/displaydistancedialogcontent.py:41
|
||||
msgid "closer"
|
||||
msgstr ""
|
||||
|
||||
#: src/displaydistancedialogcontent.py:45
|
||||
msgid "fullscreen"
|
||||
msgstr ""
|
||||
|
||||
#: src/displaydistancedialogcontent.py:48
|
||||
msgid "farther"
|
||||
msgstr ""
|
||||
|
||||
#: src/licensedialogcontent.py:63
|
||||
msgid "Paid Tier Status"
|
||||
msgstr "订阅状态"
|
||||
|
|
@ -34,7 +80,7 @@ msgstr "订阅状态"
|
|||
msgid "Feature Availability"
|
||||
msgstr "功能状态"
|
||||
|
||||
#: src/licensefeaturerow.py:15 src/shortcutdialog.py:107
|
||||
#: src/licensefeaturerow.py:15 src/shortcutdialog.py:104
|
||||
msgid "Disabled"
|
||||
msgstr "已禁用"
|
||||
|
||||
|
|
@ -163,176 +209,245 @@ msgid "Enables the Breezy Desktop XR effect."
|
|||
msgstr "启用 Breezy Desktop XR 效果。"
|
||||
|
||||
#: src/gtk/connected-device.ui:55
|
||||
msgid "Widescreen mode"
|
||||
msgstr "宽屏模式"
|
||||
msgid "Zoom on focus"
|
||||
msgstr ""
|
||||
|
||||
#: src/gtk/connected-device.ui:66
|
||||
#: src/gtk/connected-device.ui:56
|
||||
msgid ""
|
||||
"Automatically move a display closer when you look at it.\n"
|
||||
"Set your preferred focused and unfocused distances in the Adjustments "
|
||||
"section.\n"
|
||||
" "
|
||||
msgstr ""
|
||||
|
||||
#: src/gtk/connected-device.ui:69
|
||||
msgid "Follow mode"
|
||||
msgstr "跟随模式"
|
||||
|
||||
#: src/gtk/connected-device.ui:67
|
||||
msgid "Keep the virtual display near the center of your view."
|
||||
#: src/gtk/connected-device.ui:70
|
||||
#, fuzzy
|
||||
msgid "Keep the focused display near the center of your view."
|
||||
msgstr "虚拟显示保持在视野中心附近。"
|
||||
|
||||
#: src/gtk/connected-device.ui:77
|
||||
msgid "Curved display"
|
||||
msgstr "曲面显示"
|
||||
#: src/gtk/connected-device.ui:80 src/gtk/no-device.ui:34
|
||||
msgid "Disable physical displays"
|
||||
msgstr ""
|
||||
|
||||
#: src/gtk/connected-device.ui:78
|
||||
msgid "Switch between flat and curved displays."
|
||||
msgstr "平板和曲面显示模式之间切换。"
|
||||
#: src/gtk/connected-device.ui:81 src/gtk/no-device.ui:35
|
||||
msgid ""
|
||||
"Automatically disable all physical displays when the XR effect is enabled."
|
||||
msgstr ""
|
||||
|
||||
#: src/gtk/connected-device.ui:91
|
||||
#, fuzzy
|
||||
msgid "Virtual displays"
|
||||
msgstr "曲面显示"
|
||||
|
||||
#: src/gtk/connected-device.ui:103
|
||||
#, fuzzy
|
||||
msgid "Rearrange displays"
|
||||
msgstr "曲面显示"
|
||||
|
||||
#: src/gtk/connected-device.ui:115
|
||||
msgid "1080p"
|
||||
msgstr ""
|
||||
|
||||
#: src/gtk/connected-device.ui:116
|
||||
msgid "1440p"
|
||||
msgstr ""
|
||||
|
||||
#: src/gtk/connected-device.ui:140
|
||||
msgid "Adjustments"
|
||||
msgstr "调整"
|
||||
|
||||
#: src/gtk/connected-device.ui:94
|
||||
msgid "Display distance"
|
||||
#: src/gtk/connected-device.ui:143
|
||||
#, fuzzy
|
||||
msgid "Display distances"
|
||||
msgstr "显示距离"
|
||||
|
||||
#: src/gtk/connected-device.ui:95
|
||||
msgid ""
|
||||
"Closer appears larger, further appears smaller. Controls depth when in "
|
||||
"widescreen mode."
|
||||
msgstr "距离近看起来大,距离远看起来小。调整使用宽屏模式时的深度。"
|
||||
#: src/gtk/connected-device.ui:144
|
||||
msgid "Set how close you want displays to appear."
|
||||
msgstr ""
|
||||
|
||||
#: src/gtk/connected-device.ui:123
|
||||
msgid "Display size"
|
||||
msgstr "显示大小"
|
||||
|
||||
#: src/gtk/connected-device.ui:124
|
||||
msgid ""
|
||||
"Combine with display distance to achieve a comfortable level of depth and "
|
||||
"size."
|
||||
msgstr "可以跟显示距离一起配合来实现舒适的深度和大小。"
|
||||
|
||||
#: src/gtk/connected-device.ui:152
|
||||
msgid "Display toggle distances"
|
||||
msgstr "显示切换距离"
|
||||
|
||||
#: src/gtk/connected-device.ui:153
|
||||
msgid ""
|
||||
"Use the buttons to capture the current display distance for use with the "
|
||||
"keyboard shortcut."
|
||||
msgstr "使用按钮记住当时的显示距离,以设成键盘快捷键。"
|
||||
|
||||
#: src/gtk/connected-device.ui:178
|
||||
#: src/gtk/connected-device.ui:199
|
||||
msgid "Follow threshold"
|
||||
msgstr "跟随触发值"
|
||||
|
||||
#: src/gtk/connected-device.ui:179
|
||||
#: src/gtk/connected-device.ui:200
|
||||
msgid "How far away you can look before the display follows."
|
||||
msgstr "在显示内容跟随前您可以看多远。"
|
||||
|
||||
#: src/gtk/connected-device.ui:209 src/gtk/connected-device.ui:215
|
||||
#: src/gtk/connected-device.ui:223
|
||||
#, fuzzy
|
||||
msgid "Display angling"
|
||||
msgstr "显示大小"
|
||||
|
||||
#: src/gtk/connected-device.ui:224
|
||||
msgid ""
|
||||
"When there are multiple displays, choose how they should angle towards you."
|
||||
msgstr ""
|
||||
|
||||
#: src/gtk/connected-device.ui:238
|
||||
msgid "Automatic"
|
||||
msgstr ""
|
||||
|
||||
#: src/gtk/connected-device.ui:239
|
||||
msgid "Side-angled"
|
||||
msgstr ""
|
||||
|
||||
#: src/gtk/connected-device.ui:240
|
||||
msgid "Top-angled"
|
||||
msgstr ""
|
||||
|
||||
#: src/gtk/connected-device.ui:241
|
||||
msgid "Flat"
|
||||
msgstr ""
|
||||
|
||||
#: src/gtk/connected-device.ui:251
|
||||
#, fuzzy
|
||||
msgid "Display spacing"
|
||||
msgstr "显示大小"
|
||||
|
||||
#: src/gtk/connected-device.ui:252
|
||||
msgid "Put empty space between displays, when there are multiple."
|
||||
msgstr ""
|
||||
|
||||
#: src/gtk/connected-device.ui:282
|
||||
msgid "Viewport horizontal offset"
|
||||
msgstr ""
|
||||
|
||||
#: src/gtk/connected-device.ui:283
|
||||
msgid ""
|
||||
"By default, the viewport will center on the primary display. Use this slider "
|
||||
"to move the viewport to the left or right."
|
||||
msgstr ""
|
||||
|
||||
#: src/gtk/connected-device.ui:312
|
||||
msgid "Viewport vertical offset"
|
||||
msgstr ""
|
||||
|
||||
#: src/gtk/connected-device.ui:313
|
||||
msgid ""
|
||||
"By default, the viewport will center on the primary display. Use this slider "
|
||||
"to move the viewport up or down."
|
||||
msgstr ""
|
||||
|
||||
#: src/gtk/connected-device.ui:349 src/gtk/connected-device.ui:355
|
||||
msgid "Keyboard Shortcuts"
|
||||
msgstr "键盘快捷键"
|
||||
|
||||
#: src/gtk/connected-device.ui:218
|
||||
#: src/gtk/connected-device.ui:358
|
||||
msgid "XR Effect on/off shortcut"
|
||||
msgstr "XR效果 开/关 快捷键"
|
||||
|
||||
#: src/gtk/connected-device.ui:219
|
||||
#: src/gtk/connected-device.ui:359
|
||||
msgid ""
|
||||
"Quickly enable or disable the XR Effect. You may need to enable the effect "
|
||||
"manually once in order to enable the shortcut."
|
||||
msgstr "快速启用或禁用 XR 效果。您可能需要先手动启用一次该效果,才能设此快捷键"
|
||||
|
||||
#: src/gtk/connected-device.ui:238 src/gtk/connected-device.ui:267
|
||||
#: src/gtk/connected-device.ui:296 src/gtk/connected-device.ui:325
|
||||
#: src/gtk/connected-device.ui:378 src/gtk/connected-device.ui:407
|
||||
#: src/gtk/connected-device.ui:436 src/gtk/connected-device.ui:465
|
||||
msgid "Change"
|
||||
msgstr "更改"
|
||||
|
||||
#: src/gtk/connected-device.ui:247
|
||||
#: src/gtk/connected-device.ui:387
|
||||
msgid "Re-center display shortcut"
|
||||
msgstr "重新居中显示快捷键"
|
||||
|
||||
#: src/gtk/connected-device.ui:248
|
||||
#: src/gtk/connected-device.ui:388
|
||||
msgid "Pin the virtual display to the current position."
|
||||
msgstr "将虚拟显示固定在当前位置。"
|
||||
|
||||
#: src/gtk/connected-device.ui:276
|
||||
msgid "Display distance shortcut"
|
||||
msgstr "显示距离快捷键"
|
||||
#: src/gtk/connected-device.ui:416
|
||||
#, fuzzy
|
||||
msgid "Toggle zoom on focus shortcut"
|
||||
msgstr "切换跟随模式快捷键"
|
||||
|
||||
#: src/gtk/connected-device.ui:277
|
||||
msgid "Quickly toggle between two predefined distances."
|
||||
msgstr "快速地在两个预定的距离之间切换。"
|
||||
#: src/gtk/connected-device.ui:417
|
||||
#, fuzzy
|
||||
msgid "Quickly toggle zoom on focus mode."
|
||||
msgstr "快速切换跟随模式。"
|
||||
|
||||
#: src/gtk/connected-device.ui:305
|
||||
#: src/gtk/connected-device.ui:445
|
||||
msgid "Toggle follow mode shortcut"
|
||||
msgstr "切换跟随模式快捷键"
|
||||
|
||||
#: src/gtk/connected-device.ui:306
|
||||
#: src/gtk/connected-device.ui:446
|
||||
msgid "Quickly toggle follow mode."
|
||||
msgstr "快速切换跟随模式。"
|
||||
|
||||
#: src/gtk/connected-device.ui:341 src/gtk/connected-device.ui:347
|
||||
#: src/gtk/connected-device.ui:481 src/gtk/connected-device.ui:487
|
||||
msgid "Advanced Settings"
|
||||
msgstr "高级设定"
|
||||
|
||||
#: src/gtk/connected-device.ui:350
|
||||
#: src/gtk/connected-device.ui:490
|
||||
msgid "Find optimal display config"
|
||||
msgstr "寻找最佳显示设定"
|
||||
|
||||
#: src/gtk/connected-device.ui:351
|
||||
#: src/gtk/connected-device.ui:491
|
||||
msgid ""
|
||||
"Automatically modify the glasses display configuration for maximum "
|
||||
"resolution and best scaling when plugged in."
|
||||
msgstr "连接时,可以自动修改眼镜显示设定以表现出最大解析度和最佳的对比。"
|
||||
|
||||
#: src/gtk/connected-device.ui:361
|
||||
#: src/gtk/connected-device.ui:501
|
||||
msgid "Use highest refresh rate"
|
||||
msgstr "使用最高刷新率"
|
||||
|
||||
#: src/gtk/connected-device.ui:362
|
||||
#: src/gtk/connected-device.ui:502
|
||||
msgid "Refresh rate may affect performance, disable this to set it manually."
|
||||
msgstr "刷新率可能会影响性能,禁用此功能即可手动设置。"
|
||||
|
||||
#: src/gtk/connected-device.ui:372
|
||||
#: src/gtk/connected-device.ui:512
|
||||
msgid "Always primary display"
|
||||
msgstr "每次设置为主要显示"
|
||||
|
||||
#: src/gtk/connected-device.ui:373
|
||||
#: src/gtk/connected-device.ui:513
|
||||
msgid "Automatically set the glasses as the primary display when plugged in."
|
||||
msgstr "连接时,自动将眼镜设置为主要显示。"
|
||||
|
||||
#: src/gtk/connected-device.ui:383
|
||||
msgid "Fast SBS mode switching"
|
||||
msgstr "快速并排模式切换"
|
||||
|
||||
#: src/gtk/connected-device.ui:384
|
||||
msgid ""
|
||||
"Switches glasses to SBS mode immediately when plugged in, if widescreen mode "
|
||||
"is on. May cause instability."
|
||||
msgstr ""
|
||||
"连接时,如果宽屏模式开启,眼镜会立即切换到 并排模式。这可能会导致不稳定。"
|
||||
|
||||
#: src/gtk/connected-device.ui:394
|
||||
#: src/gtk/connected-device.ui:523
|
||||
msgid "Movement look-ahead"
|
||||
msgstr "移动预测"
|
||||
|
||||
#: src/gtk/connected-device.ui:395
|
||||
#: src/gtk/connected-device.ui:524
|
||||
msgid ""
|
||||
"Counteracts input lag by predicting head-tracking position ahead of render "
|
||||
"time. Stick with default unless virtual display drags behind your head "
|
||||
"movements, jumps ahead, or is very shaky."
|
||||
msgstr ""
|
||||
"透过预测头部追踪位置,提前于渲染时间进行预测来抵消输入延迟。"
|
||||
"除非虚拟显示滞后于头部,提前跳动或非常抖动,请尽量使用默认设置。"
|
||||
"透过预测头部追踪位置,提前于渲染时间进行预测来抵消输入延迟。除非虚拟显示滞后"
|
||||
"于头部,提前跳动或非常抖动,请尽量使用默认设置。"
|
||||
|
||||
#: src/gtk/connected-device.ui:413
|
||||
#: src/gtk/connected-device.ui:542
|
||||
msgid "Default"
|
||||
msgstr "默认"
|
||||
|
||||
#: src/gtk/connected-device.ui:425
|
||||
#: src/gtk/connected-device.ui:554
|
||||
msgid "Text Scaling"
|
||||
msgstr "字体大小比例"
|
||||
|
||||
#: src/gtk/connected-device.ui:426
|
||||
#: src/gtk/connected-device.ui:555
|
||||
msgid "Scaling text below 1.0 will simulate a higher resolution display"
|
||||
msgstr "字体缩放小于1.0,将模拟解析度更高的显示效果"
|
||||
|
||||
#: src/gtk/connected-device.ui:585
|
||||
msgid "Enable multi-tap detection"
|
||||
msgstr ""
|
||||
|
||||
#: src/gtk/connected-device.ui:586
|
||||
msgid "Enables double-tap to recenter and triple-tap to recalibrate."
|
||||
msgstr ""
|
||||
|
||||
#: src/gtk/display-distance-dialog.ui:9
|
||||
msgid "Show full range"
|
||||
msgstr ""
|
||||
|
||||
#: src/gtk/display-distance-dialog.ui:18
|
||||
msgid "Done"
|
||||
msgstr ""
|
||||
|
||||
#: src/gtk/failed-verification.ui:13
|
||||
msgid "Breezy Desktop GNOME invalid setup"
|
||||
msgstr "Breezy Desktop GNOME 无效设置"
|
||||
|
|
@ -379,14 +494,6 @@ msgid ""
|
|||
"connected."
|
||||
msgstr "当支援的设备已连接,将BREEZY DESKTOP XR效果自动启动"
|
||||
|
||||
#: src/gtk/no-device.ui:34
|
||||
msgid "Start in widescreen mode"
|
||||
msgstr "使用宽屏模式以启动软件"
|
||||
|
||||
#: src/gtk/no-device.ui:35
|
||||
msgid "Widescreen mode is not supported for all glasses."
|
||||
msgstr "宽屏模式不支援每一个型号的XR眼睛"
|
||||
|
||||
#: src/gtk/no-driver.ui:13
|
||||
msgid "No driver running"
|
||||
msgstr "未运行驱动程序"
|
||||
|
|
@ -490,3 +597,52 @@ msgstr "强制重置"
|
|||
#: src/gtk/window.ui:99
|
||||
msgid "About BreezyDesktop"
|
||||
msgstr "关于 Breezy Desktop"
|
||||
|
||||
#~ msgid "Fast SBS mode switching"
|
||||
#~ msgstr "快速并排模式切换"
|
||||
|
||||
#~ msgid ""
|
||||
#~ "Switches glasses to SBS mode immediately when plugged in, if widescreen "
|
||||
#~ "mode is on. May cause instability."
|
||||
#~ msgstr ""
|
||||
#~ "连接时,如果宽屏模式开启,眼镜会立即切换到 并排模式。这可能会导致不稳定。"
|
||||
|
||||
#, fuzzy
|
||||
#~ msgid "Set Unfocused Displays Distance"
|
||||
#~ msgstr "显示距离"
|
||||
|
||||
#~ msgid "Widescreen mode"
|
||||
#~ msgstr "宽屏模式"
|
||||
|
||||
#~ msgid "Switch between flat and curved displays."
|
||||
#~ msgstr "平板和曲面显示模式之间切换。"
|
||||
|
||||
#~ msgid ""
|
||||
#~ "Closer appears larger, further appears smaller. Controls depth when in "
|
||||
#~ "widescreen mode."
|
||||
#~ msgstr "距离近看起来大,距离远看起来小。调整使用宽屏模式时的深度。"
|
||||
|
||||
#~ msgid ""
|
||||
#~ "Combine with display distance to achieve a comfortable level of depth and "
|
||||
#~ "size."
|
||||
#~ msgstr "可以跟显示距离一起配合来实现舒适的深度和大小。"
|
||||
|
||||
#~ msgid "Display toggle distances"
|
||||
#~ msgstr "显示切换距离"
|
||||
|
||||
#~ msgid ""
|
||||
#~ "Use the buttons to capture the current display distance for use with the "
|
||||
#~ "keyboard shortcut."
|
||||
#~ msgstr "使用按钮记住当时的显示距离,以设成键盘快捷键。"
|
||||
|
||||
#~ msgid "Display distance shortcut"
|
||||
#~ msgstr "显示距离快捷键"
|
||||
|
||||
#~ msgid "Quickly toggle between two predefined distances."
|
||||
#~ msgstr "快速地在两个预定的距离之间切换。"
|
||||
|
||||
#~ msgid "Start in widescreen mode"
|
||||
#~ msgstr "使用宽屏模式以启动软件"
|
||||
|
||||
#~ msgid "Widescreen mode is not supported for all glasses."
|
||||
#~ msgstr "宽屏模式不支援每一个型号的XR眼睛"
|
||||
|
|
|
|||
|
|
@ -2,6 +2,8 @@
|
|||
<gresources>
|
||||
<gresource prefix="/com/xronlinux/BreezyDesktop">
|
||||
<file preprocess="xml-stripblanks">gtk/connected-device.ui</file>
|
||||
<file preprocess="xml-stripblanks">gtk/display-distance-dialog.ui</file>
|
||||
<file preprocess="xml-stripblanks">gtk/display-distance-dialog-content.ui</file>
|
||||
<file preprocess="xml-stripblanks">gtk/failed-verification.ui</file>
|
||||
<file preprocess="xml-stripblanks">gtk/license-dialog.ui</file>
|
||||
<file preprocess="xml-stripblanks">gtk/license-dialog-content.ui</file>
|
||||
|
|
@ -10,6 +12,7 @@
|
|||
<file preprocess="xml-stripblanks">gtk/no-extension.ui</file>
|
||||
<file preprocess="xml-stripblanks">gtk/no-license.ui</file>
|
||||
<file preprocess="xml-stripblanks">gtk/shortcut-dialog.ui</file>
|
||||
<file preprocess="xml-stripblanks">gtk/virtual-display-row.ui</file>
|
||||
<file preprocess="xml-stripblanks">gtk/window.ui</file>
|
||||
</gresource>
|
||||
</gresources>
|
||||
|
|
|
|||
|
|
@ -6,6 +6,7 @@ from .xrdriveripc import XRDriverIPC
|
|||
class ConfigManager(GObject.GObject):
|
||||
__gproperties__ = {
|
||||
'breezy-desktop-enabled': (bool, 'Breezy Desktop Enabled', 'Whether Breezy Desktop is enabled', False, GObject.ParamFlags.READWRITE),
|
||||
'multi-tap-enabled': (bool, 'Multi-Tap Enabled', 'Whether Multi-Tap is enabled', False, GObject.ParamFlags.READWRITE),
|
||||
}
|
||||
|
||||
_instance = None
|
||||
|
|
@ -27,6 +28,7 @@ class ConfigManager(GObject.GObject):
|
|||
GObject.GObject.__init__(self)
|
||||
self.ipc = XRDriverIPC.get_instance()
|
||||
self.breezy_desktop_enabled = None
|
||||
self.multi_tap_enabled = None
|
||||
self._running = True
|
||||
self._refresh_config()
|
||||
|
||||
|
|
@ -38,6 +40,9 @@ class ConfigManager(GObject.GObject):
|
|||
if self._is_breezy_desktop_enabled() != self.breezy_desktop_enabled:
|
||||
self.set_property('breezy-desktop-enabled', self._is_breezy_desktop_enabled())
|
||||
|
||||
if self.config['multi_tap_enabled'] != self.multi_tap_enabled:
|
||||
self.set_property('multi-tap-enabled', self.config['multi_tap_enabled'])
|
||||
|
||||
if self._running: threading.Timer(1.0, self._refresh_config).start()
|
||||
|
||||
def _is_breezy_desktop_enabled(self):
|
||||
|
|
@ -48,17 +53,26 @@ class ConfigManager(GObject.GObject):
|
|||
self.config['disabled'] = False
|
||||
self.config['output_mode'] = 'external_only'
|
||||
self.config['external_mode'] = ['breezy_desktop']
|
||||
self.ipc.write_config(self.config)
|
||||
else:
|
||||
self.config['external_mode'] = []
|
||||
self.ipc.write_config(self.config)
|
||||
|
||||
self.ipc.write_config(self.config)
|
||||
self.breezy_desktop_enabled = value
|
||||
|
||||
def _set_multi_tap_enabled(self, value):
|
||||
if self.multi_tap_enabled != value:
|
||||
self.config['multi_tap_enabled'] = value
|
||||
self.ipc.write_config(self.config)
|
||||
self.multi_tap_enabled = value
|
||||
|
||||
def do_set_property(self, prop, value):
|
||||
if prop.name == 'breezy-desktop-enabled':
|
||||
self._set_breezy_desktop_enabled(value)
|
||||
elif prop.name == 'multi-tap-enabled':
|
||||
self._set_multi_tap_enabled(value)
|
||||
|
||||
def do_get_property(self, prop):
|
||||
if prop.name == 'breezy-desktop-enabled':
|
||||
return self.breezy_desktop_enabled
|
||||
return self.breezy_desktop_enabled
|
||||
elif prop.name == 'multi-tap-enabled':
|
||||
return self.multi_tap_enabled
|
||||
|
|
@ -1,14 +1,20 @@
|
|||
from gi.repository import Gio, Gtk, GObject
|
||||
from gi.repository import Gio, GLib, Gtk, GObject
|
||||
from .configmanager import ConfigManager
|
||||
from .extensionsmanager import ExtensionsManager
|
||||
from .displaydistancedialog import DisplayDistanceDialog
|
||||
from .license import BREEZY_GNOME_FEATURES
|
||||
from .settingsmanager import SettingsManager
|
||||
from .shortcutdialog import bind_shortcut_settings
|
||||
from .statemanager import StateManager
|
||||
from .virtualdisplaymanager import VirtualDisplayManager
|
||||
from .virtualdisplay import is_screencast_available
|
||||
from .virtualdisplayrow import VirtualDisplayRow
|
||||
from .xrdriveripc import XRDriverIPC
|
||||
import gettext
|
||||
import logging
|
||||
|
||||
_ = gettext.gettext
|
||||
logger = logging.getLogger('breezy_ui')
|
||||
|
||||
@Gtk.Template(resource_path='/com/xronlinux/BreezyDesktop/gtk/connected-device.ui')
|
||||
class ConnectedDevice(Gtk.Box):
|
||||
|
|
@ -19,18 +25,20 @@ class ConnectedDevice(Gtk.Box):
|
|||
|
||||
device_label = Gtk.Template.Child()
|
||||
effect_enable_switch = Gtk.Template.Child()
|
||||
display_distance_scale = Gtk.Template.Child()
|
||||
display_distance_adjustment = Gtk.Template.Child()
|
||||
display_size_scale = Gtk.Template.Child()
|
||||
display_size_adjustment = Gtk.Template.Child()
|
||||
disable_physical_displays_switch = Gtk.Template.Child()
|
||||
display_zoom_on_focus_switch = Gtk.Template.Child()
|
||||
follow_threshold_scale = Gtk.Template.Child()
|
||||
follow_threshold_adjustment = Gtk.Template.Child()
|
||||
follow_mode_switch = Gtk.Template.Child()
|
||||
widescreen_mode_switch = Gtk.Template.Child()
|
||||
widescreen_mode_row = Gtk.Template.Child()
|
||||
curved_display_switch = Gtk.Template.Child()
|
||||
set_toggle_display_distance_start_button = Gtk.Template.Child()
|
||||
set_toggle_display_distance_end_button = Gtk.Template.Child()
|
||||
top_features_group = Gtk.Template.Child()
|
||||
virtual_displays_row = Gtk.Template.Child()
|
||||
add_virtual_display_menu = Gtk.Template.Child()
|
||||
add_virtual_display_button = Gtk.Template.Child()
|
||||
launch_display_settings_button = Gtk.Template.Child()
|
||||
all_displays_distance_label = Gtk.Template.Child()
|
||||
change_all_displays_distance_button = Gtk.Template.Child()
|
||||
focused_display_distance_label = Gtk.Template.Child()
|
||||
change_focused_display_distance_button = Gtk.Template.Child()
|
||||
reassign_toggle_xr_effect_shortcut_button = Gtk.Template.Child()
|
||||
toggle_xr_effect_shortcut_label = Gtk.Template.Child()
|
||||
reassign_recenter_display_shortcut_button = Gtk.Template.Child()
|
||||
|
|
@ -42,44 +50,65 @@ class ConnectedDevice(Gtk.Box):
|
|||
headset_as_primary_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_adjustment = Gtk.Template.Child()
|
||||
text_scaling_scale = Gtk.Template.Child()
|
||||
text_scaling_adjustment = Gtk.Template.Child()
|
||||
|
||||
enable_multi_tap_switch = Gtk.Template.Child()
|
||||
monitor_wrapping_scheme_menu = Gtk.Template.Child()
|
||||
monitor_spacing_scale = Gtk.Template.Child()
|
||||
monitor_spacing_adjustment = Gtk.Template.Child()
|
||||
viewport_offset_x_scale = Gtk.Template.Child()
|
||||
viewport_offset_x_adjustment = Gtk.Template.Child()
|
||||
viewport_offset_y_scale = Gtk.Template.Child()
|
||||
viewport_offset_y_adjustment = Gtk.Template.Child()
|
||||
|
||||
def __init__(self):
|
||||
super(Gtk.Box, self).__init__()
|
||||
self.init_template()
|
||||
self.active = True
|
||||
self.all_enabled_state_inputs = [
|
||||
self.display_distance_scale,
|
||||
self.display_size_scale,
|
||||
self.display_zoom_on_focus_switch,
|
||||
# self.display_size_scale,
|
||||
self.follow_mode_switch,
|
||||
self.follow_threshold_scale,
|
||||
self.curved_display_switch,
|
||||
self.set_toggle_display_distance_start_button,
|
||||
self.set_toggle_display_distance_end_button,
|
||||
self.movement_look_ahead_scale
|
||||
# self.curved_display_switch,
|
||||
self.add_virtual_display_menu,
|
||||
self.add_virtual_display_button,
|
||||
self.change_all_displays_distance_button,
|
||||
self.change_focused_display_distance_button,
|
||||
self.movement_look_ahead_scale,
|
||||
self.monitor_wrapping_scheme_menu,
|
||||
self.monitor_spacing_scale,
|
||||
self.viewport_offset_x_scale,
|
||||
self.viewport_offset_y_scale
|
||||
]
|
||||
|
||||
self.settings = SettingsManager.get_instance().settings
|
||||
self.desktop_settings = SettingsManager.get_instance().desktop_settings
|
||||
self.ipc = XRDriverIPC.get_instance()
|
||||
self.virtual_display_manager = VirtualDisplayManager.get_instance()
|
||||
self.extensions_manager = ExtensionsManager.get_instance()
|
||||
|
||||
self.settings.bind('display-distance', self.display_distance_adjustment, 'value', Gio.SettingsBindFlags.DEFAULT)
|
||||
self.settings.bind('display-size', self.display_size_adjustment, 'value', Gio.SettingsBindFlags.DEFAULT)
|
||||
self.settings.bind('disable-physical-displays', self.disable_physical_displays_switch, 'active', Gio.SettingsBindFlags.DEFAULT)
|
||||
self.settings.connect('changed::display-distance', self._handle_display_distance)
|
||||
# self.settings.bind('display-size', self.display_size_adjustment, 'value', Gio.SettingsBindFlags.DEFAULT)
|
||||
self.settings.bind('follow-threshold', self.follow_threshold_adjustment, 'value', Gio.SettingsBindFlags.DEFAULT)
|
||||
self.settings.bind('widescreen-mode', self.widescreen_mode_switch, 'active', Gio.SettingsBindFlags.DEFAULT)
|
||||
self.settings.bind('curved-display', self.curved_display_switch, 'active', Gio.SettingsBindFlags.DEFAULT)
|
||||
# self.settings.bind('widescreen-mode', self.widescreen_mode_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('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('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('monitor-spacing', self.monitor_spacing_adjustment, 'value', Gio.SettingsBindFlags.DEFAULT)
|
||||
self.settings.bind('viewport-offset-x', self.viewport_offset_x_adjustment, 'value', Gio.SettingsBindFlags.DEFAULT)
|
||||
self.settings.bind('viewport-offset-y', self.viewport_offset_y_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.display_zoom_on_focus_switch.connect('notify::active', self._handle_zoom_on_focus_switch_changed)
|
||||
self.monitor_wrapping_scheme_menu.connect('changed', self._handle_monitor_wrapping_scheme_menu_changed)
|
||||
self._handle_monitor_wrapping_scheme_setting_changed(self.settings, self.settings.get_string('monitor-wrapping-scheme'))
|
||||
|
||||
bind_shortcut_settings(self.get_parent(), [
|
||||
[self.reassign_toggle_xr_effect_shortcut_button, self.toggle_xr_effect_shortcut_label],
|
||||
|
|
@ -88,10 +117,28 @@ class ConnectedDevice(Gtk.Box):
|
|||
[self.reassign_toggle_follow_shortcut_button, self.toggle_follow_shortcut_label]
|
||||
])
|
||||
|
||||
self.bind_set_distance_toggle([
|
||||
self.set_toggle_display_distance_start_button,
|
||||
self.set_toggle_display_distance_end_button
|
||||
])
|
||||
self.change_focused_display_distance_button.connect('clicked',
|
||||
self._on_display_distance_preset_change_button_clicked,
|
||||
'toggle-display-distance-start',
|
||||
self._on_set_focused_display_distance,
|
||||
_('Set Focused Display Distance'),
|
||||
_('Use a closer value so the display zooms in when you look at it.'),
|
||||
0.2, 1.0
|
||||
)
|
||||
self.change_all_displays_distance_button.connect('clicked',
|
||||
self._on_display_distance_preset_change_button_clicked,
|
||||
'toggle-display-distance-end',
|
||||
self._on_set_all_displays_distance,
|
||||
_('Set All Displays Distance'),
|
||||
_('Use a farther value so the displays are zoomed out when you look away.'),
|
||||
1.0, 2.5
|
||||
)
|
||||
self._set_all_displays_distance(self.settings.get_double('toggle-display-distance-end'))
|
||||
self._set_focused_display_distance(self.settings.get_double('toggle-display-distance-start'))
|
||||
|
||||
self.add_virtual_display_menu.set_active_id('1080p')
|
||||
self.add_virtual_display_button.connect('clicked', self._on_add_virtual_display)
|
||||
self.launch_display_settings_button.connect('clicked', self._launch_display_settings)
|
||||
|
||||
self.state_manager = StateManager.get_instance()
|
||||
self.state_manager.bind_property('follow-mode', self.follow_mode_switch, 'active', GObject.BindingFlags.DEFAULT)
|
||||
|
|
@ -104,16 +151,46 @@ class ConnectedDevice(Gtk.Box):
|
|||
|
||||
self.config_manager = ConfigManager.get_instance()
|
||||
self.config_manager.connect('notify::breezy-desktop-enabled', self._handle_enabled_config)
|
||||
self.config_manager.bind_property('multi-tap-enabled', self.enable_multi_tap_switch, 'active', Gio.SettingsBindFlags.DEFAULT)
|
||||
self.enable_multi_tap_switch.connect('notify::active', lambda widget, param: self.config_manager.set_property('multi-tap-enabled', widget.get_active()))
|
||||
|
||||
self.use_optimal_monitor_config_switch.connect('notify::active', self._refresh_use_optimal_monitor_config)
|
||||
|
||||
self._handle_switch_enabled_state(self.effect_enable_switch, None)
|
||||
self._handle_display_distance(self.settings, self.settings.get_double('display-distance'))
|
||||
self._handle_enabled_features(self.state_manager, None)
|
||||
self._handle_device_supports_sbs(self.state_manager, None)
|
||||
self._handle_enabled_config(None, None)
|
||||
self._refresh_use_optimal_monitor_config(self.use_optimal_monitor_config_switch, None)
|
||||
self.extensions_manager.connect('notify::breezy-enabled', self._handle_enabled_config)
|
||||
|
||||
self.connect("destroy", self._on_widget_destroy)
|
||||
self.virtual_display_manager.connect('notify::displays', self._on_virtual_displays_update)
|
||||
self._on_virtual_displays_update(self.virtual_display_manager, None)
|
||||
|
||||
self.virtual_displays_by_pid = {}
|
||||
|
||||
self._settings_displays_app_info = None
|
||||
|
||||
for appinfo in Gio.AppInfo.get_all():
|
||||
if appinfo.get_id() == 'gnome-display-panel.desktop':
|
||||
self._settings_displays_app_info = appinfo
|
||||
break
|
||||
|
||||
def _handle_zoom_on_focus_switch_changed(self, widget, param):
|
||||
display_distance = self.settings.get_double('display-distance')
|
||||
toggle_display_distance_end = self.settings.get_double('toggle-display-distance-end')
|
||||
toggle_display_distance_start = self.settings.get_double('toggle-display-distance-start')
|
||||
is_zoom_on_focus_already_enabled = display_distance < toggle_display_distance_end
|
||||
if widget.get_active() and not is_zoom_on_focus_already_enabled:
|
||||
self.settings.set_double('display-distance', toggle_display_distance_start)
|
||||
elif not widget.get_active() and is_zoom_on_focus_already_enabled:
|
||||
self.settings.set_double('display-distance', toggle_display_distance_end)
|
||||
|
||||
def _handle_monitor_wrapping_scheme_setting_changed(self, settings, val):
|
||||
self.monitor_wrapping_scheme_menu.set_active_id(val)
|
||||
|
||||
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]
|
||||
|
|
@ -125,9 +202,9 @@ class ConnectedDevice(Gtk.Box):
|
|||
def _handle_device_supports_sbs(self, state_manager, val):
|
||||
if not state_manager.get_property('device-supports-sbs'):
|
||||
self.settings.set_boolean('widescreen-mode', False)
|
||||
self.widescreen_mode_switch.set_sensitive(state_manager.get_property('device-supports-sbs'))
|
||||
subtitle = self.widescreen_mode_subtitle if state_manager.get_property('device-supports-sbs') else self.widescreen_mode_not_supported_subtitle
|
||||
self.widescreen_mode_row.set_subtitle(subtitle)
|
||||
# self.widescreen_mode_switch.set_sensitive(state_manager.get_property('device-supports-sbs'))
|
||||
# subtitle = self.widescreen_mode_subtitle if state_manager.get_property('device-supports-sbs') else self.widescreen_mode_not_supported_subtitle
|
||||
# self.widescreen_mode_row.set_subtitle(subtitle)
|
||||
|
||||
def _handle_enabled_config(self, object, val):
|
||||
enabled = self.config_manager.get_property('breezy-desktop-enabled') and self.extensions_manager.get_property('breezy-enabled')
|
||||
|
|
@ -135,6 +212,9 @@ class ConnectedDevice(Gtk.Box):
|
|||
self.effect_enable_switch.set_active(enabled)
|
||||
|
||||
def _handle_switch_enabled_state(self, switch, param):
|
||||
GLib.idle_add(self._handle_switch_enabled_state_gui, switch, param)
|
||||
|
||||
def _handle_switch_enabled_state_gui(self, switch, param):
|
||||
requesting_enabled = switch.get_active()
|
||||
|
||||
# never turn off the extension, disabling the effect is done via configs only
|
||||
|
|
@ -145,12 +225,17 @@ class ConnectedDevice(Gtk.Box):
|
|||
|
||||
for widget in self.all_enabled_state_inputs:
|
||||
widget.set_sensitive(requesting_enabled)
|
||||
|
||||
if not is_screencast_available():
|
||||
self.virtual_displays_row.set_subtitle(
|
||||
_("Unable to add virtual displays on this machine. xdg-desktop-portal is required."))
|
||||
self.add_virtual_display_button.set_sensitive(False)
|
||||
self.add_virtual_display_menu.set_sensitive(False)
|
||||
|
||||
if requesting_enabled:
|
||||
self._refresh_follow_mode(self.follow_mode_switch, None)
|
||||
|
||||
def _refresh_follow_mode(self, switch, param):
|
||||
self.follow_threshold_scale.set_sensitive(switch.get_active())
|
||||
if (self.state_manager.get_property('follow-mode') == switch.get_active()):
|
||||
return
|
||||
|
||||
|
|
@ -167,18 +252,90 @@ class ConnectedDevice(Gtk.Box):
|
|||
|
||||
def set_device_name(self, name):
|
||||
self.device_label.set_markup(f"<b>{name}</b>")
|
||||
|
||||
def _handle_display_distance(self, *args):
|
||||
display_distance = self.settings.get_double('display-distance')
|
||||
toggle_display_distance_end = self.settings.get_double('toggle-display-distance-end')
|
||||
|
||||
should_zoom_on_focus_be_enabled = display_distance < toggle_display_distance_end
|
||||
if self.display_zoom_on_focus_switch.get_active() != should_zoom_on_focus_be_enabled:
|
||||
self.display_zoom_on_focus_switch.set_active(should_zoom_on_focus_be_enabled)
|
||||
|
||||
def _set_focused_display_distance(self, distance):
|
||||
self.focused_display_distance_label.set_markup(f"{_("Focused display")}: <b>{distance}</b>")
|
||||
self.settings.set_double('toggle-display-distance-start', distance)
|
||||
|
||||
self.display_zoom_on_focus_switch.set_sensitive(distance != self.settings.get_double('toggle-display-distance-end'))
|
||||
|
||||
def _set_all_displays_distance(self, distance):
|
||||
self.all_displays_distance_label.set_markup(f"{_("All displays")}: <b>{distance}</b>")
|
||||
self.settings.set_double('toggle-display-distance-end', distance)
|
||||
self.display_zoom_on_focus_switch.set_active(False)
|
||||
self.display_zoom_on_focus_switch.set_sensitive(distance != self.settings.get_double('toggle-display-distance-start'))
|
||||
|
||||
def _on_display_distance_preset_change_button_clicked(self, widget, settings_key, on_save_callback, title, subtitle, lower_limit, upper_limit):
|
||||
dialog = DisplayDistanceDialog(settings_key, on_save_callback, title, subtitle, lower_limit, upper_limit)
|
||||
dialog.set_transient_for(widget.get_ancestor(Gtk.Window))
|
||||
dialog.present()
|
||||
|
||||
def bind_set_distance_toggle(self, widgets):
|
||||
for widget in widgets:
|
||||
widget.connect('clicked', lambda *args, widget=widget: on_set_display_distance_toggle(widget))
|
||||
reload_display_distance_toggle_button(widget)
|
||||
|
||||
def _on_widget_destroy(self, widget):
|
||||
self.state_manager.unbind_property('follow-mode', self.follow_mode_switch, 'active')
|
||||
self.settings.unbind('display-distance', self.display_distance_adjustment, 'value')
|
||||
self.settings.unbind('display-size', self.display_size_adjustment, 'value')
|
||||
self.settings.unbind('follow-threshold', self.follow_threshold_adjustment, 'value')
|
||||
self.settings.unbind('widescreen-mode', self.widescreen_mode_switch, 'active')
|
||||
def _on_set_all_displays_distance(self, prev_distance, distance):
|
||||
focused_display_distance = self.settings.get_double('toggle-display-distance-start')
|
||||
all_displays_distance = self.settings.get_double('toggle-display-distance-end')
|
||||
if (distance < focused_display_distance):
|
||||
self._set_focused_display_distance(distance)
|
||||
|
||||
self._set_all_displays_distance(distance)
|
||||
|
||||
if prev_distance == focused_display_distance:
|
||||
self.settings.set_double('display-distance', prev_distance)
|
||||
|
||||
def _on_set_focused_display_distance(self, prev_distance, distance):
|
||||
focused_display_distance = self.settings.get_double('toggle-display-distance-start')
|
||||
all_displays_distance = self.settings.get_double('toggle-display-distance-end')
|
||||
if (distance > all_displays_distance):
|
||||
self._set_all_displays_distance(distance)
|
||||
|
||||
self._set_focused_display_distance(distance)
|
||||
|
||||
def _on_add_virtual_display(self, *args):
|
||||
resolution = self.add_virtual_display_menu.get_active_id()
|
||||
logger.info(f"Adding virtual display {resolution}")
|
||||
|
||||
width = 1920
|
||||
height = 1080
|
||||
if resolution == '1440p':
|
||||
width = 2560
|
||||
height = 1440
|
||||
|
||||
self.virtual_display_manager.create_virtual_display(width, height, 60)
|
||||
|
||||
def _on_virtual_displays_update(self, virtual_display_manager, val):
|
||||
GLib.idle_add(self._on_virtual_displays_update_gui, virtual_display_manager)
|
||||
|
||||
def _on_virtual_displays_update_gui(self, virtual_display_manager):
|
||||
effect_enabled = self.effect_enable_switch.get_active()
|
||||
virtual_displays_present = len(virtual_display_manager.displays) > 0
|
||||
self.launch_display_settings_button.set_visible(
|
||||
self._settings_displays_app_info is not None and virtual_displays_present
|
||||
)
|
||||
self.monitor_wrapping_scheme_menu.set_sensitive(effect_enabled and virtual_displays_present)
|
||||
self.monitor_spacing_scale.set_sensitive(effect_enabled and virtual_displays_present)
|
||||
|
||||
for pid, child in self.virtual_displays_by_pid.items():
|
||||
self.top_features_group.remove(child)
|
||||
|
||||
new_displays_by_pid = {}
|
||||
for display in virtual_display_manager.displays:
|
||||
child = self.virtual_displays_by_pid.get(
|
||||
display['pid'],
|
||||
VirtualDisplayRow(display['pid'], display['width'], display['height'], 60))
|
||||
self.top_features_group.add(child)
|
||||
new_displays_by_pid[display['pid']] = child
|
||||
|
||||
self.virtual_displays_by_pid = new_displays_by_pid
|
||||
|
||||
def _launch_display_settings(self, *args):
|
||||
self._settings_displays_app_info.launch()
|
||||
|
||||
def reload_display_distance_toggle_button(widget):
|
||||
distance = SettingsManager.get_instance().settings.get_double(widget.get_name())
|
||||
|
|
|
|||
|
|
@ -0,0 +1,28 @@
|
|||
from gi.repository import Gtk, Gio
|
||||
from .displaydistancedialogcontent import DisplayDistanceDialogContent
|
||||
|
||||
@Gtk.Template(resource_path='/com/xronlinux/BreezyDesktop/gtk/display-distance-dialog.ui')
|
||||
class DisplayDistanceDialog(Gtk.Dialog):
|
||||
__gtype_name__ = 'DisplayDistanceDialog'
|
||||
|
||||
show_full_scale_button = Gtk.Template.Child()
|
||||
save_button = Gtk.Template.Child()
|
||||
|
||||
def __init__(self, settings_key, on_save_callback, title, subtitle, lower_limit, upper_limit):
|
||||
super(Gtk.Dialog, self).__init__()
|
||||
self.init_template()
|
||||
|
||||
self.on_save_callback = on_save_callback
|
||||
self.set_title(title)
|
||||
|
||||
self.content = DisplayDistanceDialogContent(settings_key, self.show_full_scale_button, self.save_button, self._on_save_callback, subtitle, lower_limit, upper_limit)
|
||||
self.get_content_area().append(self.content)
|
||||
|
||||
self.show_full_scale_button.connect('clicked', self._on_show_full_scale_button_clicked)
|
||||
|
||||
def _on_show_full_scale_button_clicked(self, button):
|
||||
self.show_full_scale_button.set_visible(False)
|
||||
|
||||
def _on_save_callback(self, prev_distance, distance):
|
||||
self.on_save_callback(prev_distance, distance)
|
||||
self.close()
|
||||
|
|
@ -0,0 +1,58 @@
|
|||
from gi.repository import Gtk, Gio
|
||||
from .settingsmanager import SettingsManager
|
||||
|
||||
import gettext
|
||||
|
||||
_ = gettext.gettext
|
||||
|
||||
|
||||
@Gtk.Template(resource_path='/com/xronlinux/BreezyDesktop/gtk/display-distance-dialog-content.ui')
|
||||
class DisplayDistanceDialogContent(Gtk.Box):
|
||||
__gtype_name__ = 'DisplayDistanceDialogContent'
|
||||
|
||||
display_distance_subtitle = Gtk.Template.Child()
|
||||
display_distance_scale = Gtk.Template.Child()
|
||||
display_distance_adjustment = Gtk.Template.Child()
|
||||
|
||||
def __init__(self, settings_key, show_full_scale_button, save_button, on_save_callback, subtitle, lower_limit, upper_limit):
|
||||
super(Gtk.Box, self).__init__()
|
||||
self.init_template()
|
||||
|
||||
self.display_distance_subtitle.set_markup(f"""<span size="small">{subtitle}</span>""")
|
||||
|
||||
self.on_save_callback = on_save_callback
|
||||
self.settings = SettingsManager.get_instance().settings
|
||||
self.prev_distance = self.settings.get_double('display-distance')
|
||||
|
||||
self.lower_limit_orig = self.display_distance_adjustment.get_lower()
|
||||
self.upper_limit_orig = self.display_distance_adjustment.get_upper()
|
||||
|
||||
self._add_marks(lower_limit, upper_limit)
|
||||
|
||||
self.settings.bind('display-distance', self.display_distance_adjustment, 'value', Gio.SettingsBindFlags.DEFAULT)
|
||||
|
||||
show_full_scale_button.connect('clicked', self._on_show_full_scale_button_clicked)
|
||||
save_button.connect('clicked', self._on_save_button_clicked)
|
||||
|
||||
def _add_marks(self, lower_limit, upper_limit):
|
||||
self.display_distance_scale.clear_marks()
|
||||
|
||||
if self.lower_limit_orig == lower_limit:
|
||||
self.display_distance_scale.add_mark(self.lower_limit_orig, Gtk.PositionType.BOTTOM, _("closer"))
|
||||
else:
|
||||
self.display_distance_adjustment.set_lower(lower_limit)
|
||||
|
||||
self.display_distance_scale.add_mark(1.0, Gtk.PositionType.BOTTOM, _("fullscreen"))
|
||||
|
||||
if self.upper_limit_orig == upper_limit:
|
||||
self.display_distance_scale.add_mark(self.upper_limit_orig, Gtk.PositionType.BOTTOM, _("farther"))
|
||||
else:
|
||||
self.display_distance_adjustment.set_upper(upper_limit)
|
||||
|
||||
def _on_show_full_scale_button_clicked(self, button):
|
||||
self._add_marks(self.lower_limit_orig, self.upper_limit_orig)
|
||||
self.display_distance_adjustment.set_lower(self.lower_limit_orig)
|
||||
self.display_distance_adjustment.set_upper(self.upper_limit_orig)
|
||||
|
||||
def _on_save_button_clicked(self, button):
|
||||
self.on_save_callback(self.prev_distance, self.display_distance_adjustment.get_value())
|
||||
|
|
@ -37,7 +37,7 @@
|
|||
<property name="margin-end">20</property>
|
||||
<property name="spacing">20</property>
|
||||
<child>
|
||||
<object class="AdwPreferencesGroup">
|
||||
<object class="AdwPreferencesGroup" id="top_features_group">
|
||||
<property name="title" translatable="yes"><!-- section heading for switches that enable certain features -->Features</property>
|
||||
<child>
|
||||
<object class="AdwActionRow">
|
||||
|
|
@ -51,11 +51,14 @@
|
|||
</object>
|
||||
</child>
|
||||
<child>
|
||||
<object class="AdwActionRow" id="widescreen_mode_row">
|
||||
<property name="title" translatable="yes"><!-- feature switch -->Widescreen mode</property>
|
||||
<property name="valign">2</property>
|
||||
<object class="AdwActionRow">
|
||||
<property name="title" translatable="yes"><!-- feature switch -->Zoom on focus</property>
|
||||
<property name="subtitle" translatable="yes"><!--
|
||||
-->Automatically move a display closer when you look at it.
|
||||
<!-- -->Set your preferred focused and unfocused distances in the Adjustments section.
|
||||
</property>
|
||||
<child>
|
||||
<object class="GtkSwitch" id="widescreen_mode_switch">
|
||||
<object class="GtkSwitch" id="display_zoom_on_focus_switch">
|
||||
<property name="valign">3</property>
|
||||
</object>
|
||||
</child>
|
||||
|
|
@ -64,7 +67,7 @@
|
|||
<child>
|
||||
<object class="AdwActionRow">
|
||||
<property name="title" translatable="yes"><!-- feature switch -->Follow mode</property>
|
||||
<property name="subtitle" translatable="yes">Keep the virtual display near the center of your view.</property>
|
||||
<property name="subtitle" translatable="yes">Keep the focused display near the center of your view.</property>
|
||||
<child>
|
||||
<object class="GtkSwitch" id="follow_mode_switch">
|
||||
<property name="valign">3</property>
|
||||
|
|
@ -74,12 +77,58 @@
|
|||
</child>
|
||||
<child>
|
||||
<object class="AdwActionRow">
|
||||
<property name="title" translatable="yes"><!-- feature switch -->Curved display</property>
|
||||
<property name="subtitle" translatable="yes">Switch between flat and curved displays.</property>
|
||||
<property name="title" translatable="yes"><!-- feature switch -->Disable physical displays</property>
|
||||
<property name="subtitle" translatable="yes">Automatically disable all physical displays when the XR effect is enabled.</property>
|
||||
<child>
|
||||
<object class="GtkSwitch" id="disable_physical_displays_switch">
|
||||
<property name="valign">3</property>
|
||||
</object>
|
||||
</child>
|
||||
</object>
|
||||
</child>
|
||||
<child>
|
||||
<object class="AdwActionRow" id="virtual_displays_row">
|
||||
<property name="title" translatable="yes">Virtual displays</property>
|
||||
<property name="valign">2</property>
|
||||
<child>
|
||||
<object class="GtkSwitch" id="curved_display_switch">
|
||||
<object class="GtkBox">
|
||||
<property name="spacing">30</property>
|
||||
<property name="width-request">150</property>
|
||||
<property name="margin-start">30</property>
|
||||
<child>
|
||||
<object class="GtkButton" id="launch_display_settings_button">
|
||||
<property name="visible">0</property>
|
||||
<property name="name">launch-display-settings</property>
|
||||
<property name="valign">3</property>
|
||||
<property name="label" translatable="yes">Rearrange displays</property>
|
||||
</object>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkBox">
|
||||
<property name="valign">3</property>
|
||||
<style>
|
||||
<class name="flat"/>
|
||||
</style>
|
||||
<child>
|
||||
<object class="GtkComboBoxText" id="add_virtual_display_menu">
|
||||
<items>
|
||||
<item translatable="yes" id="1080p">1080p</item>
|
||||
<item translatable="yes" id="1440p">1440p</item>
|
||||
</items>
|
||||
</object>
|
||||
</child>
|
||||
</object>
|
||||
</child>
|
||||
</object>
|
||||
</child>
|
||||
<child type="suffix">
|
||||
<object class="GtkButton" id="add_virtual_display_button">
|
||||
<property name="name">add-virtual-display</property>
|
||||
<property name="icon-name">list-add-symbolic</property>
|
||||
<property name="valign">3</property>
|
||||
<style>
|
||||
<class name="flat"/>
|
||||
</style>
|
||||
</object>
|
||||
</child>
|
||||
</object>
|
||||
|
|
@ -91,82 +140,54 @@
|
|||
<property name="title" translatable="yes"><!-- Section containing sliders for adjusting the XR effect -->Adjustments</property>
|
||||
<child>
|
||||
<object class="AdwActionRow" id="display_distance_row">
|
||||
<property name="title" translatable="yes"><!-- adjustment slider -->Display distance</property>
|
||||
<property name="subtitle" translatable="yes">Closer appears larger, further appears smaller. Controls depth when in widescreen mode.</property>
|
||||
<child>
|
||||
<object class="GtkScale" id="display_distance_scale">
|
||||
<property name="valign">3</property>
|
||||
<property name="draw-value">true</property>
|
||||
<property name="value-pos">0</property>
|
||||
<property name="digits">2</property>
|
||||
<property name="width-request">350</property>
|
||||
<property name="has-origin">false</property>
|
||||
<property name="adjustment">
|
||||
<object class="GtkAdjustment" id="display_distance_adjustment">
|
||||
<property name="lower">0.2</property>
|
||||
<property name="upper">2.5</property>
|
||||
<property name="step-increment">0.01</property>
|
||||
<property name="value">1.05</property>
|
||||
</object>
|
||||
</property>
|
||||
<marks>
|
||||
<mark value="0.2" position="bottom"></mark>
|
||||
<mark value="1.0" position="bottom"></mark>
|
||||
<mark value="2.5" position="bottom"></mark>
|
||||
</marks>
|
||||
</object>
|
||||
</child>
|
||||
</object>
|
||||
</child>
|
||||
<child>
|
||||
<object class="AdwActionRow">
|
||||
<property name="title" translatable="yes"><!-- adjustment slider -->Display size</property>
|
||||
<property name="subtitle" translatable="yes">Combine with display distance to achieve a comfortable level of depth and size.</property>
|
||||
<child>
|
||||
<object class="GtkScale" id="display_size_scale">
|
||||
<property name="valign">3</property>
|
||||
<property name="draw-value">true</property>
|
||||
<property name="value-pos">0</property>
|
||||
<property name="digits">2</property>
|
||||
<property name="width-request">350</property>
|
||||
<property name="has-origin">false</property>
|
||||
<property name="adjustment">
|
||||
<object class="GtkAdjustment" id="display_size_adjustment">
|
||||
<property name="lower">0.2</property>
|
||||
<property name="upper">2.5</property>
|
||||
<property name="step-increment">0.01</property>
|
||||
<property name="value">1.0</property>
|
||||
</object>
|
||||
</property>
|
||||
<marks>
|
||||
<mark value="0.2" position="bottom"></mark>
|
||||
<mark value="1.0" position="bottom"></mark>
|
||||
<mark value="2.5" position="bottom"></mark>
|
||||
</marks>
|
||||
</object>
|
||||
</child>
|
||||
</object>
|
||||
</child>
|
||||
<child>
|
||||
<object class="AdwActionRow">
|
||||
<property name="title" translatable="yes"><!-- adjustment slider -->Display toggle distances</property>
|
||||
<property name="subtitle" translatable="yes">Use the buttons to capture the current display distance for use with the keyboard shortcut.</property>
|
||||
<property name="valign">2</property>
|
||||
<property name="title" translatable="yes"><!-- adjustment slider -->Display distances</property>
|
||||
<property name="subtitle" translatable="yes">Set how close you want displays to appear.</property>
|
||||
<child>
|
||||
<object class="GtkBox">
|
||||
<property name="spacing">30</property>
|
||||
<property name="width-request">150</property>
|
||||
<property name="margin-start">30</property>
|
||||
<property name="spacing">25</property>
|
||||
<property name="homogeneous">1</property>
|
||||
<property name="margin-top">15</property>
|
||||
<property name="margin-bottom">15</property>
|
||||
<child>
|
||||
<object class="GtkButton" id="set_toggle_display_distance_start_button">
|
||||
<property name="name">toggle-display-distance-start</property>
|
||||
<property name="valign">3</property>
|
||||
<object class="GtkBox">
|
||||
<property name="orientation">vertical</property>
|
||||
<property name="spacing">10</property>
|
||||
<child>
|
||||
<object class="GtkLabel" id="focused_display_distance_label">
|
||||
<property name="label" translatable="yes"></property>
|
||||
<property name="valign">3</property>
|
||||
</object>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkButton" id="change_focused_display_distance_button">
|
||||
<property name="name">set-all-displays-distance</property>
|
||||
<property name="valign">3</property>
|
||||
<property name="label">Change</property>
|
||||
<property name="margin-start">20</property>
|
||||
<property name="margin-end">20</property>
|
||||
</object>
|
||||
</child>
|
||||
</object>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkButton" id="set_toggle_display_distance_end_button">
|
||||
<property name="name">toggle-display-distance-end</property>
|
||||
<property name="valign">3</property>
|
||||
<object class="GtkBox">
|
||||
<property name="orientation">vertical</property>
|
||||
<property name="spacing">10</property>
|
||||
<child>
|
||||
<object class="GtkLabel" id="all_displays_distance_label">
|
||||
<property name="label" translatable="yes"></property>
|
||||
<property name="valign">3</property>
|
||||
</object>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkButton" id="change_all_displays_distance_button">
|
||||
<property name="name">set-all-displays-distance</property>
|
||||
<property name="valign">3</property>
|
||||
<property name="label">Change</property>
|
||||
<property name="margin-start">20</property>
|
||||
<property name="margin-end">20</property>
|
||||
</object>
|
||||
</child>
|
||||
</object>
|
||||
</child>
|
||||
</object>
|
||||
|
|
@ -197,6 +218,125 @@
|
|||
</child>
|
||||
</object>
|
||||
</child>
|
||||
<child>
|
||||
<object class="AdwActionRow">
|
||||
<property name="title" translatable="yes"><!-- dropdown menu -->Display angling</property>
|
||||
<property name="subtitle" translatable="yes">When there are multiple displays, choose how they should angle towards 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>
|
||||
<property name="valign">3</property>
|
||||
<style>
|
||||
<class name="flat"/>
|
||||
</style>
|
||||
<child>
|
||||
<object class="GtkComboBoxText" id="monitor_wrapping_scheme_menu">
|
||||
<items>
|
||||
<item translatable="yes" id="automatic">Automatic</item>
|
||||
<item translatable="yes" id="horizontal">Side-angled</item>
|
||||
<item translatable="yes" id="vertical">Top-angled</item>
|
||||
<item translatable="yes" id="none">Flat</item>
|
||||
</items>
|
||||
</object>
|
||||
</child>
|
||||
</object>
|
||||
</child>
|
||||
</object>
|
||||
</child>
|
||||
<child>
|
||||
<object class="AdwActionRow">
|
||||
<property name="title" translatable="yes"><!-- adjustment slider -->Display spacing</property>
|
||||
<property name="subtitle" translatable="yes">Put empty space between displays, when there are multiple.</property>
|
||||
<child>
|
||||
<object class="GtkScale" id="monitor_spacing_scale">
|
||||
<property name="valign">3</property>
|
||||
<property name="draw-value">true</property>
|
||||
<property name="value-pos">0</property>
|
||||
<property name="digits">0</property>
|
||||
<property name="width-request">350</property>
|
||||
<property name="has-origin">false</property>
|
||||
<property name="adjustment">
|
||||
<object class="GtkAdjustment" id="monitor_spacing_adjustment">
|
||||
<property name="lower">0</property>
|
||||
<property name="upper">100</property>
|
||||
<property name="step-increment">1</property>
|
||||
<property name="value">0</property>
|
||||
</object>
|
||||
</property>
|
||||
<marks>
|
||||
<mark value="0" position="bottom">0</mark>
|
||||
<mark value="25" position="bottom"></mark>
|
||||
<mark value="50" position="bottom">50</mark>
|
||||
<mark value="75" position="bottom"></mark>
|
||||
<mark value="100" position="bottom">100</mark>
|
||||
</marks>
|
||||
</object>
|
||||
</child>
|
||||
</object>
|
||||
</child>
|
||||
<child>
|
||||
<object class="AdwActionRow">
|
||||
<property name="title" translatable="yes"><!-- adjustment slider -->Viewport horizontal offset</property>
|
||||
<property name="subtitle" translatable="yes">By default, the viewport will center on the primary display. Use this slider to move the viewport to the left or right.</property>
|
||||
<child>
|
||||
<object class="GtkScale" id="viewport_offset_x_scale">
|
||||
<property name="valign">3</property>
|
||||
<property name="value-pos">0</property>
|
||||
<property name="digits">1</property>
|
||||
<property name="width-request">350</property>
|
||||
<property name="has-origin">false</property>
|
||||
<property name="adjustment">
|
||||
<object class="GtkAdjustment" id="viewport_offset_x_adjustment">
|
||||
<property name="lower">-2.5</property>
|
||||
<property name="upper">2.5</property>
|
||||
<property name="step-increment">0.1</property>
|
||||
<property name="value">0.0</property>
|
||||
</object>
|
||||
</property>
|
||||
<marks>
|
||||
<mark value="-2.0" position="bottom">left</mark>
|
||||
<mark value="-1.0" position="bottom"></mark>
|
||||
<mark value="0.0" position="bottom">center</mark>
|
||||
<mark value="1.0" position="bottom"></mark>
|
||||
<mark value="2.0" position="bottom">right</mark>
|
||||
</marks>
|
||||
</object>
|
||||
</child>
|
||||
</object>
|
||||
</child>
|
||||
<child>
|
||||
<object class="AdwActionRow">
|
||||
<property name="title" translatable="yes"><!-- adjustment slider -->Viewport vertical offset</property>
|
||||
<property name="subtitle" translatable="yes">By default, the viewport will center on the primary display. Use this slider to move the viewport up or down.</property>
|
||||
<child>
|
||||
<object class="GtkScale" id="viewport_offset_y_scale">
|
||||
<property name="valign">3</property>
|
||||
<property name="value-pos">0</property>
|
||||
<property name="digits">1</property>
|
||||
<property name="width-request">350</property>
|
||||
<property name="has-origin">false</property>
|
||||
<property name="adjustment">
|
||||
<object class="GtkAdjustment" id="viewport_offset_y_adjustment">
|
||||
<property name="lower">-2.5</property>
|
||||
<property name="upper">2.5</property>
|
||||
<property name="step-increment">0.1</property>
|
||||
<property name="value">0.0</property>
|
||||
</object>
|
||||
</property>
|
||||
<marks>
|
||||
<mark value="-2.0" position="bottom">down</mark>
|
||||
<mark value="-1.0" position="bottom"></mark>
|
||||
<mark value="0.0" position="bottom">center</mark>
|
||||
<mark value="1.0" position="bottom"></mark>
|
||||
<mark value="2.0" position="bottom">up</mark>
|
||||
</marks>
|
||||
</object>
|
||||
</child>
|
||||
</object>
|
||||
</child>
|
||||
</object>
|
||||
</child>
|
||||
</object>
|
||||
|
|
@ -273,8 +413,8 @@
|
|||
</child>
|
||||
<child>
|
||||
<object class="AdwActionRow">
|
||||
<property name="title" translatable="yes">Display distance shortcut</property>
|
||||
<property name="subtitle" translatable="yes">Quickly toggle between two predefined distances.</property>
|
||||
<property name="title" translatable="yes">Toggle zoom on focus shortcut</property>
|
||||
<property name="subtitle" translatable="yes">Quickly toggle zoom on focus mode.</property>
|
||||
<property name="valign">2</property>
|
||||
<child>
|
||||
<object class="GtkBox">
|
||||
|
|
@ -378,17 +518,6 @@
|
|||
</child>
|
||||
</object>
|
||||
</child>
|
||||
<child>
|
||||
<object class="AdwActionRow">
|
||||
<property name="title" translatable="yes">Fast SBS mode switching</property>
|
||||
<property name="subtitle" translatable="yes">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>
|
||||
<object class="AdwActionRow">
|
||||
<property name="title" translatable="yes">Movement look-ahead</property>
|
||||
|
|
@ -451,6 +580,17 @@
|
|||
</child>
|
||||
</object>
|
||||
</child>
|
||||
<child>
|
||||
<object class="AdwActionRow">
|
||||
<property name="title" translatable="yes">Enable multi-tap detection</property>
|
||||
<property name="subtitle" translatable="yes">Enables double-tap to recenter and triple-tap to recalibrate.</property>
|
||||
<child>
|
||||
<object class="GtkSwitch" id="enable_multi_tap_switch">
|
||||
<property name="valign">3</property>
|
||||
</object>
|
||||
</child>
|
||||
</object>
|
||||
</child>
|
||||
</object>
|
||||
</child>
|
||||
</object>
|
||||
|
|
|
|||
|
|
@ -0,0 +1,37 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<interface>
|
||||
<requires lib="gtk" version="4.0"/>
|
||||
<template class="DisplayDistanceDialogContent" parent="GtkBox">
|
||||
<property name="orientation">vertical</property>
|
||||
<property name="valign">3</property>
|
||||
<child>
|
||||
<object class="GtkLabel" id="display_distance_subtitle">
|
||||
<property name="wrap">true</property>
|
||||
<property name="margin-top">20</property>
|
||||
<property name="margin-start">20</property>
|
||||
<property name="margin-end">20</property>
|
||||
</object>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkScale" id="display_distance_scale">
|
||||
<property name="valign">3</property>
|
||||
<property name="margin-top">20</property>
|
||||
<property name="margin-start">20</property>
|
||||
<property name="margin-end">20</property>
|
||||
<property name="draw-value">true</property>
|
||||
<property name="value-pos">0</property>
|
||||
<property name="digits">2</property>
|
||||
<property name="width-request">350</property>
|
||||
<property name="has-origin">false</property>
|
||||
<property name="adjustment">
|
||||
<object class="GtkAdjustment" id="display_distance_adjustment">
|
||||
<property name="lower">0.2</property>
|
||||
<property name="upper">2.5</property>
|
||||
<property name="step-increment">0.01</property>
|
||||
<property name="value">1.05</property>
|
||||
</object>
|
||||
</property>
|
||||
</object>
|
||||
</child>
|
||||
</template>
|
||||
</interface>
|
||||
|
|
@ -0,0 +1,26 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<interface>
|
||||
<requires lib="gtk" version="4.0"/>
|
||||
<template class="DisplayDistanceDialog" parent="GtkDialog">
|
||||
<property name="modal">1</property>
|
||||
<property name="use-header-bar">1</property>
|
||||
<child type="action">
|
||||
<object class="GtkButton" id="show_full_scale_button">
|
||||
<property name="label" translatable="yes">Show full range</property>
|
||||
<property name="margin-top">10</property>
|
||||
<property name="margin-bottom">10</property>
|
||||
<property name="margin-start">10</property>
|
||||
<property name="margin-end">10</property>
|
||||
</object>
|
||||
</child>
|
||||
<child type="action">
|
||||
<object class="GtkButton" id="save_button">
|
||||
<property name="label" translatable="yes">Done</property>
|
||||
<property name="margin-top">10</property>
|
||||
<property name="margin-bottom">10</property>
|
||||
<property name="margin-start">10</property>
|
||||
<property name="margin-end">10</property>
|
||||
</object>
|
||||
</child>
|
||||
</template>
|
||||
</interface>
|
||||
|
|
@ -30,12 +30,11 @@
|
|||
</object>
|
||||
</child>
|
||||
<child>
|
||||
<object class="AdwActionRow" id="widescreen_mode_row">
|
||||
<property name="title" translatable="yes"><!-- feature switch -->Start in widescreen mode</property>
|
||||
<property name="subtitle" translatable="yes">Widescreen mode is not supported for all glasses.</property>
|
||||
<property name="valign">2</property>
|
||||
<object class="AdwActionRow">
|
||||
<property name="title" translatable="yes"><!-- feature switch -->Disable physical displays</property>
|
||||
<property name="subtitle" translatable="yes">Automatically disable all physical displays when the XR effect is enabled.</property>
|
||||
<child>
|
||||
<object class="GtkSwitch" id="widescreen_mode_switch">
|
||||
<object class="GtkSwitch" id="disable_physical_displays_switch">
|
||||
<property name="valign">3</property>
|
||||
</object>
|
||||
</child>
|
||||
|
|
|
|||
|
|
@ -0,0 +1,17 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<interface>
|
||||
<requires lib="gtk" version="4.0"/>
|
||||
<template class="VirtualDisplayRow" parent="AdwActionRow">
|
||||
<property name="subtitle"></property>
|
||||
<child type="suffix">
|
||||
<object class="GtkButton" id="remove_virtual_display_button">
|
||||
<property name="name">remove-virtual-display</property>
|
||||
<property name="icon-name">user-trash-symbolic</property>
|
||||
<property name="valign">center</property>
|
||||
<style>
|
||||
<class name="flat"/>
|
||||
</style>
|
||||
</object>
|
||||
</child>
|
||||
</template>
|
||||
</interface>
|
||||
|
|
@ -26,12 +26,23 @@ configure_file(
|
|||
install_mode: 'r-xr-xr-x'
|
||||
)
|
||||
|
||||
configure_file(
|
||||
input: 'virtualdisplay.in',
|
||||
output: 'virtualdisplay',
|
||||
configuration: conf,
|
||||
install: true,
|
||||
install_dir: get_option('bindir'),
|
||||
install_mode: 'r-xr-xr-x'
|
||||
)
|
||||
|
||||
breezydesktop_sources = [
|
||||
'../modules/PyXRLinuxDriverIPC/xrdriveripc.py',
|
||||
'__init__.py',
|
||||
'configmanager.py',
|
||||
'connecteddevice.py',
|
||||
'extensionsmanager.py',
|
||||
'displaydistancedialog.py',
|
||||
'displaydistancedialogcontent.py',
|
||||
'failedverification.py',
|
||||
'license.py',
|
||||
'licensedialog.py',
|
||||
|
|
@ -47,8 +58,11 @@ breezydesktop_sources = [
|
|||
'shortcutdialog.py',
|
||||
'statemanager.py',
|
||||
'time.py',
|
||||
'virtualdisplay.py',
|
||||
'virtualdisplaymanager.py',
|
||||
'verify.py',
|
||||
'window.py'
|
||||
]
|
||||
|
||||
install_data(breezydesktop_sources, install_dir: moduledir)
|
||||
install_subdir('../lib', install_dir: moduledir)
|
||||
|
|
@ -10,7 +10,8 @@ class NoDevice(Gtk.Box):
|
|||
__gtype_name__ = "NoDevice"
|
||||
|
||||
effect_enable_switch = Gtk.Template.Child()
|
||||
widescreen_mode_switch = Gtk.Template.Child()
|
||||
disable_physical_displays_switch = Gtk.Template.Child()
|
||||
# widescreen_mode_switch = Gtk.Template.Child()
|
||||
|
||||
def __init__(self):
|
||||
super(Gtk.Box, self).__init__()
|
||||
|
|
@ -23,7 +24,8 @@ class NoDevice(Gtk.Box):
|
|||
self.config_manager.connect('notify::breezy-desktop-enabled', self._handle_enabled_config)
|
||||
|
||||
self.effect_enable_switch.connect('notify::active', self._handle_switch_enabled_state)
|
||||
self.settings.bind('widescreen-mode', self.widescreen_mode_switch, 'active', Gio.SettingsBindFlags.DEFAULT)
|
||||
# self.settings.bind('widescreen-mode', self.widescreen_mode_switch, 'active', Gio.SettingsBindFlags.DEFAULT)
|
||||
self.settings.bind('disable-physical-displays', self.disable_physical_displays_switch, 'active', Gio.SettingsBindFlags.DEFAULT)
|
||||
|
||||
self._handle_enabled_config(self.config_manager, None)
|
||||
|
||||
|
|
@ -41,5 +43,5 @@ class NoDevice(Gtk.Box):
|
|||
|
||||
self.config_manager.set_property('breezy-desktop-enabled', requesting_enabled)
|
||||
|
||||
def _on_widget_destroy(self, widget):
|
||||
self.settings.unbind('widescreen-mode', self.widescreen_mode_switch, 'active')
|
||||
# def _on_widget_destroy(self, widget):
|
||||
# self.settings.unbind('widescreen-mode', self.widescreen_mode_switch, 'active')
|
||||
|
|
|
|||
|
|
@ -36,9 +36,6 @@ class ShortcutDialog(Gtk.Dialog):
|
|||
keycode,
|
||||
state
|
||||
)
|
||||
label = Gtk.accelerator_get_label(keyval, state)
|
||||
|
||||
# hacky way to store the label, causes warnings from the WM
|
||||
SettingsManager.get_instance().settings.set_strv(self.settings_key, [binding])
|
||||
|
||||
self.close()
|
||||
|
|
|
|||
|
|
@ -0,0 +1,107 @@
|
|||
#!/usr/bin/env python3
|
||||
|
||||
# virtualdisplay.in
|
||||
#
|
||||
# Copyright 2024 Unknown
|
||||
#
|
||||
# This program is free software: you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License as published by
|
||||
# the Free Software Foundation, either version 3 of the License, or
|
||||
# (at your option) any later version.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
#
|
||||
# SPDX-License-Identifier: GPL-3.0-or-later
|
||||
|
||||
import logging
|
||||
import os
|
||||
import sys
|
||||
|
||||
lib_dir = os.path.join(os.path.dirname(os.path.abspath(__file__)), 'lib')
|
||||
sys.path.insert(0, lib_dir)
|
||||
|
||||
from logging.handlers import TimedRotatingFileHandler
|
||||
|
||||
config_home = os.environ.get('XDG_CONFIG_HOME', '~/.config')
|
||||
config_dir = os.path.expanduser(config_home)
|
||||
state_home = os.environ.get('XDG_STATE_HOME', '~/.local/state')
|
||||
state_dir = os.path.expanduser(state_home)
|
||||
breezy_state_dir = os.path.join(state_dir, 'breezy_gnome')
|
||||
log_dir = os.path.join(breezy_state_dir, 'logs/ui')
|
||||
os.makedirs(log_dir, exist_ok=True)
|
||||
|
||||
logger = logging.getLogger('breezy_ui')
|
||||
logger.setLevel(logging.INFO)
|
||||
logname = os.path.join(log_dir, "breezy_desktop.log")
|
||||
handler = TimedRotatingFileHandler(logname, when="midnight", backupCount=30)
|
||||
handler.suffix = "%Y%m%d"
|
||||
formatter = logging.Formatter('%(asctime)s - %(name)s - %(levelname)s - %(message)s')
|
||||
handler.setFormatter(formatter)
|
||||
logger.addHandler(handler)
|
||||
|
||||
import sys
|
||||
import argparse
|
||||
import signal
|
||||
import time
|
||||
|
||||
VERSION = '@VERSION@'
|
||||
|
||||
xdg_data_home = os.getenv('XDG_DATA_HOME', os.path.join(os.path.expanduser('~'), '.local', 'share'))
|
||||
appdir = os.getenv('APPDIR', xdg_data_home)
|
||||
locale_dir = os.path.join(appdir, 'locale')
|
||||
pkgdatadir = os.path.join(appdir, 'breezydesktop')
|
||||
sys.path.insert(1, pkgdatadir)
|
||||
|
||||
import gi
|
||||
|
||||
gi.require_version('GLib', '2.0')
|
||||
|
||||
from gi.repository import GLib
|
||||
|
||||
def graceful_shutdown(signum, frame):
|
||||
global virtual_display_instance
|
||||
global loop
|
||||
|
||||
if virtual_display_instance is not None:
|
||||
virtual_display_instance.terminate()
|
||||
|
||||
def _on_display_closed():
|
||||
global loop
|
||||
loop.quit()
|
||||
|
||||
def create_display(width, height, framerate):
|
||||
global virtual_display_instance
|
||||
|
||||
virtual_display_instance = VirtualDisplay(width, height, framerate, _on_display_closed)
|
||||
virtual_display_instance.create()
|
||||
|
||||
if __name__ == "__main__":
|
||||
from breezydesktop import virtualdisplay
|
||||
from breezydesktop.virtualdisplay import VirtualDisplay
|
||||
|
||||
global virtual_display_instance
|
||||
global loop
|
||||
|
||||
parser = argparse.ArgumentParser(description="Virtual display arguments")
|
||||
parser.add_argument("--height", type=int, required=True, help="Height of the display")
|
||||
parser.add_argument("--width", type=int, required=True, help="Width of the display")
|
||||
parser.add_argument("--framerate", type=int, default=60, help="Framerate of the display")
|
||||
args = parser.parse_args()
|
||||
|
||||
signal.signal(signal.SIGTERM, graceful_shutdown)
|
||||
signal.signal(signal.SIGINT, graceful_shutdown)
|
||||
|
||||
loop = GLib.MainLoop()
|
||||
|
||||
try:
|
||||
GLib.idle_add(create_display, args.width, args.height, args.framerate)
|
||||
loop.run()
|
||||
except Exception as e:
|
||||
logger.error(f"Error in main loop: {e}")
|
||||
sys.exit(1)
|
||||
|
|
@ -0,0 +1,100 @@
|
|||
#!/usr/bin/python3
|
||||
|
||||
import argparse
|
||||
import logging
|
||||
import sys
|
||||
import signal
|
||||
from .lib import pydbus
|
||||
import gi
|
||||
import time
|
||||
|
||||
gi.require_version('Gst', '1.0')
|
||||
from gi.repository import GLib, GObject, Gst
|
||||
|
||||
logger = logging.getLogger('breezy_ui')
|
||||
|
||||
screen_cast_iface = 'org.gnome.Mutter.ScreenCast'
|
||||
screen_cast_session_iface = 'org.gnome.Mutter.ScreenCast.Session'
|
||||
screen_cast_stream_iface = 'org.gnome.Mutter.ScreenCast.Session'
|
||||
gst_pipeline_format = "pipewiresrc path=%u ! video/x-raw,max-framerate=%d/1,width=%d,height=%d ! fakesink sync=false"
|
||||
|
||||
class VirtualDisplay:
|
||||
def __init__(self, width, height, framerate, on_closed_cb):
|
||||
self.width = width
|
||||
self.height = height
|
||||
self.framerate = framerate
|
||||
self.on_closed_cb = on_closed_cb
|
||||
|
||||
Gst.init(None)
|
||||
|
||||
def _screen_cast_session(self):
|
||||
bus = pydbus.SessionBus()
|
||||
screen_cast = bus.get(screen_cast_iface, '/org/gnome/Mutter/ScreenCast')
|
||||
session_path = screen_cast.CreateSession([])
|
||||
screen_cast_session = bus.get(screen_cast_iface, session_path)
|
||||
|
||||
return screen_cast_session
|
||||
|
||||
def _on_session_closed(self):
|
||||
self.stream = None
|
||||
self.terminate()
|
||||
|
||||
def create(self):
|
||||
session = self._screen_cast_session()
|
||||
session.onClosed = self._on_session_closed
|
||||
stream_path = session.RecordVirtual({
|
||||
'is-platform': GLib.Variant.new_boolean(True),
|
||||
})
|
||||
bus = pydbus.SessionBus()
|
||||
self.stream = bus.get(screen_cast_iface, stream_path)
|
||||
|
||||
self.stream.onPipeWireStreamAdded = self._on_pipewire_stream_added
|
||||
|
||||
session.Start()
|
||||
|
||||
def terminate(self):
|
||||
try:
|
||||
if self.stream is not None:
|
||||
self.stream.Stop()
|
||||
except Exception as e:
|
||||
logger.error("Failed to stop stream: %s" % e)
|
||||
|
||||
try:
|
||||
if self.pipeline is not None:
|
||||
self.pipeline.send_event(Gst.Event.new_eos())
|
||||
self.pipeline.set_state(Gst.State.NULL)
|
||||
except Exception as e:
|
||||
logger.error("Failed to stop pipeline: %s" % e)
|
||||
|
||||
self.on_closed_cb()
|
||||
|
||||
def _on_message(self, bus, message):
|
||||
type = message.type
|
||||
logger.info("message type: %s" % type)
|
||||
if type == Gst.MessageType.EOS:
|
||||
self.pipeline = None
|
||||
self.terminate()
|
||||
elif type == Gst.MessageType.ERROR:
|
||||
err, debug = message.parse_error()
|
||||
logger.error("Error: %s" % err)
|
||||
logger.error("Debug: %s" % debug)
|
||||
self.terminate()
|
||||
|
||||
def _on_pipewire_stream_added(self, node_id):
|
||||
self.pipeline = Gst.parse_launch(gst_pipeline_format % (node_id, self.framerate, self.width, self.height))
|
||||
self.pipeline.set_state(Gst.State.PLAYING)
|
||||
self.pipeline.get_bus().connect('message', self._on_message)
|
||||
self.pipeline.set_state(Gst.State.PAUSED)
|
||||
|
||||
def is_screencast_available():
|
||||
try:
|
||||
bus = pydbus.SessionBus()
|
||||
# Try to get the ScreenCast interface
|
||||
screen_cast = bus.get(screen_cast_iface, '/org/gnome/Mutter/ScreenCast')
|
||||
return True
|
||||
except Exception as e:
|
||||
logger.warning(f"ScreenCast portal not available: {e}")
|
||||
return False
|
||||
|
||||
|
||||
|
||||
|
|
@ -0,0 +1,122 @@
|
|||
import gi
|
||||
import json
|
||||
import os
|
||||
import signal
|
||||
import subprocess
|
||||
import time
|
||||
from pathlib import Path
|
||||
|
||||
import logging
|
||||
logger = logging.getLogger('breezy_ui')
|
||||
|
||||
gi.require_version('GLib', '2.0')
|
||||
from gi.repository import GLib, GObject
|
||||
|
||||
xdg_bin_home = os.getenv('XDG_BIN_HOME', os.path.join(os.path.expanduser('~'), '.local', 'bin'))
|
||||
bindir = os.getenv('BINDIR', xdg_bin_home)
|
||||
|
||||
class VirtualDisplayManager(GObject.GObject):
|
||||
__gproperties__ = {
|
||||
'displays': (object, 'Displays', 'A list of the displays', GObject.ParamFlags.READWRITE)
|
||||
}
|
||||
_instance = None
|
||||
|
||||
@staticmethod
|
||||
def get_instance():
|
||||
if not VirtualDisplayManager._instance:
|
||||
VirtualDisplayManager._instance = VirtualDisplayManager()
|
||||
|
||||
return VirtualDisplayManager._instance
|
||||
|
||||
def __init__(self):
|
||||
GObject.GObject.__init__(self)
|
||||
|
||||
self.shm_path = Path("/dev/shm/breezy_virtual_displays.json")
|
||||
self._load_displays()
|
||||
self._prune_dead_display_processes()
|
||||
|
||||
GLib.timeout_add_seconds(15, self._prune_dead_display_processes)
|
||||
|
||||
def _process_dead(self, pid):
|
||||
if (not os.path.exists(f"/proc/{pid}")):
|
||||
return True
|
||||
|
||||
try:
|
||||
if (os.waitpid(pid, os.WNOHANG) == (pid, 0)):
|
||||
return True
|
||||
except ChildProcessError:
|
||||
# process isn't tied to the current process, it's not dead if it's still open
|
||||
return False
|
||||
|
||||
return False
|
||||
|
||||
def _prune_dead_display_processes(self):
|
||||
new_displays = [disp for disp in self.displays if not self._process_dead(disp['pid'])]
|
||||
if new_displays != self.displays:
|
||||
self.set_property('displays', new_displays)
|
||||
self._save_processes()
|
||||
|
||||
return GLib.SOURCE_CONTINUE
|
||||
|
||||
def create_virtual_display(self, width, height, framerate):
|
||||
try:
|
||||
process = subprocess.Popen(
|
||||
[f"{bindir}/virtualdisplay", "--width", str(width), "--height", str(height), "--framerate", str(framerate)],
|
||||
start_new_session=True,
|
||||
stdout=subprocess.PIPE,
|
||||
stderr=subprocess.PIPE,
|
||||
text=True
|
||||
)
|
||||
|
||||
if process.returncode is not None:
|
||||
logger.error(f"Failed to create virtual display: {process.stderr.read()}")
|
||||
return
|
||||
|
||||
self.displays.append({
|
||||
'pid': process.pid,
|
||||
'width': width,
|
||||
'height': height
|
||||
})
|
||||
self.set_property('displays', self.displays)
|
||||
self._save_processes()
|
||||
except Exception as e:
|
||||
logger.error(f"Failed to create virtual display: {e}")
|
||||
|
||||
def destroy_virtual_display(self, pid: str) -> bool:
|
||||
try:
|
||||
# Send SIGTERM to allow graceful shutdown
|
||||
os.killpg(pid, signal.SIGTERM)
|
||||
self.set_property('displays', [disp for disp in self.displays if disp['pid'] != pid])
|
||||
self._save_processes()
|
||||
return True
|
||||
except ProcessLookupError:
|
||||
# Process already gone, delete pid from list
|
||||
self.set_property('displays', [disp for disp in self.displays if disp['pid'] != pid])
|
||||
self._save_processes()
|
||||
return True
|
||||
except Exception as e:
|
||||
print(f"Failed to kill process {pid}: {e}")
|
||||
return False
|
||||
|
||||
def _save_processes(self):
|
||||
with open(self.shm_path, 'w') as f:
|
||||
json.dump(self.displays, f)
|
||||
|
||||
def _load_displays(self):
|
||||
displays = []
|
||||
if self.shm_path.exists():
|
||||
try:
|
||||
with open(self.shm_path, 'r') as f:
|
||||
displays = json.load(f)
|
||||
except Exception:
|
||||
displays = []
|
||||
|
||||
self.set_property('displays', displays)
|
||||
|
||||
def do_set_property(self, prop, value):
|
||||
if prop.name == 'displays':
|
||||
self.displays = value
|
||||
|
||||
def do_get_property(self, prop):
|
||||
if prop.name == 'displays':
|
||||
return self.displays
|
||||
|
|
@ -0,0 +1,31 @@
|
|||
from gi.repository import Adw, Gtk
|
||||
from .virtualdisplaymanager import VirtualDisplayManager
|
||||
|
||||
import gettext
|
||||
|
||||
_ = gettext.gettext
|
||||
|
||||
@Gtk.Template(resource_path='/com/xronlinux/BreezyDesktop/gtk/virtual-display-row.ui')
|
||||
class VirtualDisplayRow(Adw.ActionRow):
|
||||
__gtype_name__ = "VirtualDisplayRow"
|
||||
|
||||
remove_virtual_display_button = Gtk.Template.Child()
|
||||
|
||||
def __init__(self, pid, width, height, framerate):
|
||||
super(Adw.ActionRow, self).__init__()
|
||||
self.init_template()
|
||||
self.pid = pid
|
||||
|
||||
icon = Gtk.Image.new_from_icon_name("video-display-symbolic")
|
||||
|
||||
# padding around the icon
|
||||
self.add_prefix(Gtk.Label(label=" "))
|
||||
self.add_prefix(icon)
|
||||
self.add_prefix(Gtk.Label(label=" "))
|
||||
|
||||
self.set_subtitle(f"{width} x {height}")
|
||||
|
||||
self.remove_virtual_display_button.connect('clicked', self._remove_virtual_display)
|
||||
|
||||
def _remove_virtual_display(self, widget):
|
||||
VirtualDisplayManager.get_instance().destroy_virtual_display(self.pid)
|
||||
|
|
@ -22,6 +22,7 @@ from .extensionsmanager import ExtensionsManager
|
|||
from .license import BREEZY_GNOME_FEATURES
|
||||
from .licensedialog import LicenseDialog
|
||||
from .statemanager import StateManager
|
||||
from .settingsmanager import SettingsManager
|
||||
from .connecteddevice import ConnectedDevice
|
||||
from .failedverification import FailedVerification
|
||||
from .nodevice import NoDevice
|
||||
|
|
@ -42,14 +43,6 @@ class BreezydesktopWindow(Gtk.ApplicationWindow):
|
|||
|
||||
def __init__(self, skip_verification, **kwargs):
|
||||
super().__init__(**kwargs)
|
||||
|
||||
self._skip_verification = skip_verification
|
||||
|
||||
self.state_manager = StateManager.get_instance()
|
||||
self.state_manager.connect('device-update', self._handle_state_update)
|
||||
self.state_manager.connect('notify::license-action-needed', self._handle_state_update)
|
||||
self.state_manager.connect('notify::license-present', self._handle_state_update)
|
||||
self.state_manager.connect('notify::enabled-features-list', self._handle_state_update)
|
||||
|
||||
self.connected_device = ConnectedDevice()
|
||||
self.failed_verification = FailedVerification()
|
||||
|
|
@ -57,6 +50,16 @@ class BreezydesktopWindow(Gtk.ApplicationWindow):
|
|||
self.no_driver = NoDriver()
|
||||
self.no_extension = NoExtension()
|
||||
self.no_license = NoLicense()
|
||||
|
||||
self._skip_verification = skip_verification
|
||||
|
||||
self.settings = SettingsManager.get_instance().settings
|
||||
self.state_manager = StateManager.get_instance()
|
||||
self.state_manager.connect('device-update', self._handle_state_update)
|
||||
self.state_manager.connect('notify::license-action-needed', self._handle_state_update)
|
||||
self.state_manager.connect('notify::license-present', self._handle_state_update)
|
||||
self.state_manager.connect('notify::enabled-features-list', self._handle_state_update)
|
||||
self.settings.connect('changed::debug-no-device', self._handle_settings_update)
|
||||
|
||||
self.license_action_needed_button.connect('clicked', self._on_license_button_clicked)
|
||||
self.missing_breezy_features_button.connect('clicked', self._on_license_button_clicked)
|
||||
|
|
@ -67,6 +70,9 @@ class BreezydesktopWindow(Gtk.ApplicationWindow):
|
|||
|
||||
self.connect("destroy", self._on_window_destroy)
|
||||
|
||||
def _handle_settings_update(self, settings_manager, key):
|
||||
self._handle_state_update(self.state_manager, None)
|
||||
|
||||
def _handle_state_update(self, state_manager, val):
|
||||
GLib.idle_add(self._handle_state_update_gui, state_manager)
|
||||
|
||||
|
|
@ -79,7 +85,10 @@ class BreezydesktopWindow(Gtk.ApplicationWindow):
|
|||
for child in self.main_content:
|
||||
self.main_content.remove(child)
|
||||
|
||||
if not self._skip_verification and not verify_installation():
|
||||
if self.settings.get_boolean('debug-no-device'):
|
||||
self.main_content.append(self.connected_device)
|
||||
self.connected_device.set_device_name('Fake device')
|
||||
elif not self._skip_verification and not verify_installation():
|
||||
self.main_content.append(self.failed_verification)
|
||||
elif not ExtensionsManager.get_instance().is_installed():
|
||||
self.main_content.append(self.no_extension)
|
||||
|
|
|
|||
Loading…
Reference in New Issue