[gnome] Update extensions
This commit is contained in:
@ -1,6 +1,6 @@
|
||||
/* busUtils.js
|
||||
/* displayConfigState.js
|
||||
*
|
||||
* Copyright (C) 2022 kosmospredanie, efosmark
|
||||
* Copyright (C) 2024 kosmospredanie, shyzus
|
||||
*
|
||||
* 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
|
||||
@ -17,65 +17,11 @@
|
||||
*/
|
||||
|
||||
import GLib from 'gi://GLib';
|
||||
import Gio from 'gi://Gio';
|
||||
|
||||
export const Methods = Object.freeze({
|
||||
'verify': 0,
|
||||
'temporary': 1,
|
||||
'persistent': 2
|
||||
});
|
||||
import { Monitor } from './monitor.js'
|
||||
import { LogicalMonitor } from './logicalMonitor.js'
|
||||
|
||||
export const Monitor = class Monitor {
|
||||
constructor(variant) {
|
||||
let unpacked = variant.unpack();
|
||||
this.connector = unpacked[0].unpack()[0].unpack();
|
||||
|
||||
let modes = unpacked[1].unpack();
|
||||
for (let i = 0; i < modes.length; i++) {
|
||||
let mode = modes[i].unpack();
|
||||
let id = mode[0].unpack();
|
||||
let mode_props = mode[6].unpack();
|
||||
if ('is-current' in mode_props) {
|
||||
let is_current = mode_props['is-current'].unpack().get_boolean();
|
||||
if (is_current) {
|
||||
this.current_mode_id = id;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
let props = unpacked[2].unpack();
|
||||
if ('is-underscanning' in props) {
|
||||
this.is_underscanning = props['is-underscanning'].unpack().get_boolean();
|
||||
} else {
|
||||
this.is_underscanning = false;
|
||||
}
|
||||
if ('is-builtin' in props) {
|
||||
this.is_builtin = props['is-builtin'].unpack().get_boolean();
|
||||
} else {
|
||||
this.is_builtin = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export const LogicalMonitor = class LogicalMonitor {
|
||||
constructor(variant) {
|
||||
let unpacked = variant.unpack();
|
||||
this.x = unpacked[0].unpack();
|
||||
this.y = unpacked[1].unpack();
|
||||
this.scale = unpacked[2].unpack();
|
||||
this.transform = unpacked[3].unpack();
|
||||
this.primary = unpacked[4].unpack();
|
||||
// [ [connector, vendor, product, serial]* ]
|
||||
this.monitors = unpacked[5].deep_unpack();
|
||||
this.properties = unpacked[6].unpack();
|
||||
for (let key in this.properties) {
|
||||
this.properties[key] = this.properties[key].unpack().unpack();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export const DisplayConfigState = class DisplayConfigState {
|
||||
export class DisplayConfigState {
|
||||
constructor(result) {
|
||||
let unpacked = result.unpack();
|
||||
|
||||
@ -102,8 +48,7 @@ export const DisplayConfigState = class DisplayConfigState {
|
||||
}
|
||||
|
||||
get builtin_monitor() {
|
||||
for (let i = 0; i < this.monitors.length; i++) {
|
||||
let monitor = this.monitors[i];
|
||||
for (let monitor of this.monitors) {
|
||||
if (monitor.is_builtin) {
|
||||
return monitor;
|
||||
}
|
||||
@ -112,8 +57,7 @@ export const DisplayConfigState = class DisplayConfigState {
|
||||
}
|
||||
|
||||
get_monitor(connector) {
|
||||
for (let i = 0; i < this.monitors.length; i++) {
|
||||
let monitor = this.monitors[i];
|
||||
for (let monitor of this.monitors) {
|
||||
if (monitor.connector === connector) {
|
||||
return monitor;
|
||||
}
|
||||
@ -122,12 +66,10 @@ export const DisplayConfigState = class DisplayConfigState {
|
||||
}
|
||||
|
||||
get_logical_monitor_for(connector) {
|
||||
for (let i = 0; i < this.logical_monitors.length; i++) {
|
||||
let lmonitor = this.logical_monitors[i];
|
||||
for (let j = 0; j < lmonitor.monitors.length; j++) {
|
||||
let lm_connector = lmonitor.monitors[j][0];
|
||||
if (connector === lm_connector) {
|
||||
return lmonitor;
|
||||
for (let log_monitor of this.logical_monitors) {
|
||||
for (let lm_monitor of log_monitor.monitors) {
|
||||
if (connector === lm_monitor[0]) {
|
||||
return log_monitor;
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -149,8 +91,8 @@ export const DisplayConfigState = class DisplayConfigState {
|
||||
[]
|
||||
];
|
||||
let monitors = lmonitor_pack[5];
|
||||
for (let i = 0; i < lmonitor.monitors.length; i++) {
|
||||
let connector = lmonitor.monitors[i][0];
|
||||
for (let log_monitor of lmonitor.monitors) {
|
||||
let connector = log_monitor[0];
|
||||
let monitor = this.get_monitor(connector);
|
||||
monitors.push([
|
||||
connector,
|
||||
@ -15,197 +15,109 @@
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
import { Extension, gettext as _ } from 'resource:///org/gnome/shell/extensions/extension.js';
|
||||
|
||||
import Gio from 'gi://Gio';
|
||||
import GObject from 'gi://GObject';
|
||||
import GLib from 'gi://GLib';
|
||||
|
||||
import * as SystemActions from 'resource:///org/gnome/shell/misc/systemActions.js';
|
||||
import { Extension } from 'resource:///org/gnome/shell/extensions/extension.js';
|
||||
import * as Main from 'resource:///org/gnome/shell/ui/main.js';
|
||||
import * as SystemActions from 'resource:///org/gnome/shell/misc/systemActions.js';
|
||||
|
||||
import * as Rotator from './rotator.js'
|
||||
import * as PopupMenu from 'resource:///org/gnome/shell/ui/popupMenu.js';
|
||||
import { Orientation } from './orientation.js';
|
||||
import { ManualOrientationIndicator } from './manualOrientationIndicator.js';
|
||||
import { SensorProxy } from './sensorProxy.js';
|
||||
|
||||
const ORIENTATION_LOCK_SCHEMA = 'org.gnome.settings-daemon.peripherals.touchscreen';
|
||||
const ORIENTATION_LOCK_KEY = 'orientation-lock';
|
||||
const A11Y_APPLICATIONS_SCHEMA = 'org.gnome.desktop.a11y.applications';
|
||||
const SHOW_KEYBOARD = 'screen-keyboard-enabled';
|
||||
const PERIPHERAL_TOUCHPAD_SCHEMA = 'org.gnome.desktop.peripherals.touchpad';
|
||||
const TOUCHPAD_EVENTS = 'send-events';
|
||||
|
||||
import { QuickMenuToggle, QuickSettingsMenu, SystemIndicator } from 'resource:///org/gnome/shell/ui/quickSettings.js';
|
||||
|
||||
// Orientation names must match those provided by net.hadess.SensorProxy
|
||||
const Orientation = Object.freeze({
|
||||
'normal': 0,
|
||||
'left-up': 1,
|
||||
'bottom-up': 2,
|
||||
'right-up': 3
|
||||
});
|
||||
|
||||
const ManualOrientationIndicator = GObject.registerClass(
|
||||
class ManualOrientationIndicator extends SystemIndicator {
|
||||
_init(ext_ref) {
|
||||
super._init();
|
||||
this.toggle = new ManualOrientationMenuToggle(ext_ref);
|
||||
this.quickSettingsItems.push(this.toggle);
|
||||
}
|
||||
|
||||
destroy() {
|
||||
this.quickSettingsItems.pop(this.toggle);
|
||||
this.toggle.destroy();
|
||||
}
|
||||
});
|
||||
|
||||
const ManualOrientationMenuToggle = GObject.registerClass(
|
||||
class ManualOrientationMenuToggle extends QuickMenuToggle {
|
||||
_init(ext) {
|
||||
super._init({
|
||||
title: _('Rotate'),
|
||||
iconName: 'object-rotate-left-symbolic',
|
||||
menuEnabled: true,
|
||||
toggleMode: true,
|
||||
});
|
||||
|
||||
this.menu.setHeader('object-rotate-left-symbolic', _('Screen Rotate'));
|
||||
|
||||
this._section = new PopupMenu.PopupMenuSection();
|
||||
this.menu.addMenuItem(this._section);
|
||||
|
||||
this.landscapeItem = new PopupMenu.PopupMenuItem('Landscape', {
|
||||
reactive: true,
|
||||
can_focus: true,
|
||||
});
|
||||
|
||||
this.portraitLeftItem = new PopupMenu.PopupMenuItem('Portrait Left', {
|
||||
reactive: true,
|
||||
can_focus: true,
|
||||
});
|
||||
|
||||
this.landscapeFlipItem = new PopupMenu.PopupMenuItem('Landscape Flipped', {
|
||||
reactive: true,
|
||||
can_focus: true,
|
||||
});
|
||||
|
||||
this.portraitRightItem = new PopupMenu.PopupMenuItem('Portrait Right', {
|
||||
reactive: true,
|
||||
can_focus: true,
|
||||
});
|
||||
|
||||
this.landscapeItem.connect('activate', () => {
|
||||
this._onItemActivate(this.landscapeItem);
|
||||
ext.rotate_to('normal');
|
||||
});
|
||||
this.portraitLeftItem.connect('activate', () => {
|
||||
this._onItemActivate(this.portraitLeftItem);
|
||||
ext.rotate_to('left-up');
|
||||
});
|
||||
this.landscapeFlipItem.connect('activate', () => {
|
||||
this._onItemActivate(this.landscapeFlipItem);
|
||||
ext.rotate_to('bottom-up');
|
||||
});
|
||||
this.portraitRightItem.connect('activate', () => {
|
||||
this._onItemActivate(this.portraitRightItem);
|
||||
ext.rotate_to('right-up');
|
||||
});
|
||||
|
||||
this._section.addMenuItem(this.landscapeItem);
|
||||
this._section.addMenuItem(this.portraitLeftItem);
|
||||
this._section.addMenuItem(this.landscapeFlipItem);
|
||||
this._section.addMenuItem(this.portraitRightItem);
|
||||
|
||||
this.menu.addMenuItem(new PopupMenu.PopupSeparatorMenuItem());
|
||||
this.menu.addSettingsAction(_('Extension Settings'),
|
||||
'com.mattjakeman.ExtensionManager.desktop');
|
||||
|
||||
this.connect('clicked', () => {
|
||||
if (this.checked == true) {
|
||||
ext.rotate_to('right-up');
|
||||
} else {
|
||||
ext.rotate_to('normal');
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
_onItemActivate(item) {
|
||||
this.landscapeItem.setOrnament(PopupMenu.Ornament.HIDDEN);
|
||||
this.portraitLeftItem.setOrnament(PopupMenu.Ornament.HIDDEN);
|
||||
this.landscapeFlipItem.setOrnament(PopupMenu.Ornament.HIDDEN);
|
||||
this.portraitRightItem.setOrnament(PopupMenu.Ornament.HIDDEN);
|
||||
|
||||
item.setOrnament(PopupMenu.Ornament.CHECK);
|
||||
}
|
||||
});
|
||||
|
||||
class SensorProxy {
|
||||
constructor(rotate_cb) {
|
||||
this._rotate_cb = rotate_cb;
|
||||
this._proxy = null;
|
||||
this._enabled = false;
|
||||
this._watcher_id = Gio.bus_watch_name(
|
||||
Gio.BusType.SYSTEM,
|
||||
'net.hadess.SensorProxy',
|
||||
Gio.BusNameWatcherFlags.NONE,
|
||||
this.appeared.bind(this),
|
||||
this.vanished.bind(this)
|
||||
);
|
||||
}
|
||||
|
||||
destroy() {
|
||||
Gio.bus_unwatch_name(this._watcher_id);
|
||||
if (this._enabled) this.disable();
|
||||
this._proxy = null;
|
||||
}
|
||||
|
||||
export default class ScreenAutoRotateExtension extends Extension {
|
||||
enable() {
|
||||
this._enabled = true;
|
||||
if (this._proxy === null) return;
|
||||
this._proxy.call_sync('ClaimAccelerometer', null, Gio.DBusCallFlags.NONE, -1, null);
|
||||
}
|
||||
|
||||
disable() {
|
||||
this._enabled = false;
|
||||
if (this._proxy === null) return;
|
||||
this._proxy.call_sync('ReleaseAccelerometer', null, Gio.DBusCallFlags.NONE, -1, null);
|
||||
}
|
||||
|
||||
appeared(connection, name, name_owner) {
|
||||
this._proxy = Gio.DBusProxy.new_for_bus_sync(
|
||||
Gio.BusType.SYSTEM, Gio.DBusProxyFlags.NONE, null,
|
||||
'net.hadess.SensorProxy', '/net/hadess/SensorProxy', 'net.hadess.SensorProxy',
|
||||
null);
|
||||
this._proxy.connect('g-properties-changed', this.properties_changed.bind(this));
|
||||
if (this._enabled) {
|
||||
this._proxy.call_sync('ClaimAccelerometer', null, Gio.DBusCallFlags.NONE, -1, null);
|
||||
}
|
||||
}
|
||||
|
||||
vanished(connection, name) {
|
||||
this._proxy = null;
|
||||
}
|
||||
|
||||
properties_changed(proxy, changed, invalidated) {
|
||||
if (!this._enabled) return;
|
||||
let properties = changed.deep_unpack();
|
||||
for (let [name, value] of Object.entries(properties)) {
|
||||
if (name != 'AccelerometerOrientation') continue;
|
||||
let target = value.unpack();
|
||||
this._rotate_cb(target);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
class ScreenAutorotate {
|
||||
constructor(settings) {
|
||||
this._settings = this.getSettings();
|
||||
this._system_actions = SystemActions.getDefault();
|
||||
this._settings = settings;
|
||||
this._system_actions_backup = null;
|
||||
this._override_system_actions();
|
||||
|
||||
this._a11yApplicationsSettings = new Gio.Settings({ schema_id: A11Y_APPLICATIONS_SCHEMA });
|
||||
this._peripheralTouchpadSettings = new Gio.Settings({ schema_id: PERIPHERAL_TOUCHPAD_SCHEMA });
|
||||
this._orientation_settings = new Gio.Settings({ schema_id: ORIENTATION_LOCK_SCHEMA });
|
||||
this._orientation_settings.connect('changed::' + ORIENTATION_LOCK_KEY, this._orientation_lock_changed.bind(this));
|
||||
this._orientation_settings_handler = this._orientation_settings.connect('changed::' + ORIENTATION_LOCK_KEY, this._orientation_lock_changed.bind(this));
|
||||
|
||||
this._sensor_proxy = new SensorProxy(this.rotate_to.bind(this));
|
||||
|
||||
this._state = false; // enabled or not
|
||||
this._state = false;
|
||||
|
||||
let locked = this._orientation_settings.get_boolean(ORIENTATION_LOCK_KEY);
|
||||
if (!locked) this.enable();
|
||||
if (!locked) {
|
||||
this.toggle_rotation_lock()
|
||||
}
|
||||
|
||||
this._manual_flip_settings_handler = this._settings.connect('changed::manual-flip', (settings, key) => {
|
||||
if (settings.get_boolean(key)) {
|
||||
this._add_manual_flip();
|
||||
} else {
|
||||
this._remove_manual_flip();
|
||||
}
|
||||
});
|
||||
|
||||
this._hide_lock_rotate_settings_handler = this._settings.connect('changed::hide-lock-rotate', (settings, key) => {
|
||||
this._set_hide_lock_rotate(settings.get_boolean(key));
|
||||
});
|
||||
|
||||
if (this._settings.get_boolean('manual-flip')) {
|
||||
this._add_manual_flip();
|
||||
} else {
|
||||
this._remove_manual_flip();
|
||||
}
|
||||
|
||||
/* Timeout needed due to unknown race condition causing 'Auto Rotate'
|
||||
* Quick Toggle to be undefined for a brief moment.
|
||||
*/
|
||||
this._timeoutId = setTimeout(() => {
|
||||
this._set_hide_lock_rotate(this._settings.get_boolean('hide-lock-rotate'));
|
||||
}, 1000);
|
||||
}
|
||||
|
||||
toggle_rotation_lock() {
|
||||
if (this._state) {
|
||||
this._a11yApplicationsSettings.set_boolean(SHOW_KEYBOARD, this._originala11yKeyboardSetting);
|
||||
this._originala11yKeyboardSetting = null;
|
||||
this._sensor_proxy.disable();
|
||||
this._state = false;
|
||||
} else {
|
||||
this._originala11yKeyboardSetting = this._a11yApplicationsSettings.get_boolean(SHOW_KEYBOARD);
|
||||
this._sensor_proxy.enable();
|
||||
this._state = true;
|
||||
}
|
||||
}
|
||||
|
||||
_set_hide_lock_rotate(state) {
|
||||
const autoRotateIndicator = Main.panel.statusArea.quickSettings._autoRotate;
|
||||
|
||||
if (state) {
|
||||
Main.panel.statusArea.quickSettings._indicators.remove_child(autoRotateIndicator);
|
||||
Main.panel.statusArea.quickSettings.menu._grid.remove_child(autoRotateIndicator.quickSettingsItems[0]);
|
||||
} else {
|
||||
Main.panel.statusArea.quickSettings._indicators.add_child(autoRotateIndicator);
|
||||
Main.panel.statusArea.quickSettings._addItemsBefore(
|
||||
autoRotateIndicator.quickSettingsItems,
|
||||
Main.panel.statusArea.quickSettings._rfkill.quickSettingsItems[0]
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
_add_manual_flip() {
|
||||
this.flipIndicator = new ManualOrientationIndicator(this);
|
||||
Main.panel.statusArea.quickSettings.addExternalIndicator(this.flipIndicator);
|
||||
}
|
||||
|
||||
_remove_manual_flip() {
|
||||
if (this.flipIndicator !== null && this.flipIndicator !== undefined) {
|
||||
this.flipIndicator.destroy();
|
||||
this.flipIndicator = null;
|
||||
}
|
||||
}
|
||||
|
||||
_override_system_actions() {
|
||||
@ -230,34 +142,76 @@ class ScreenAutorotate {
|
||||
|
||||
_orientation_lock_changed() {
|
||||
let locked = this._orientation_settings.get_boolean(ORIENTATION_LOCK_KEY);
|
||||
if (this._state == locked) {
|
||||
this.toggle();
|
||||
if (this._state === locked) {
|
||||
this.toggle_rotation_lock();
|
||||
}
|
||||
}
|
||||
|
||||
destroy() {
|
||||
this._sensor_proxy.destroy();
|
||||
this._orientation_settings = null;
|
||||
this._restore_system_actions();
|
||||
}
|
||||
|
||||
toggle() {
|
||||
if (this._state) {
|
||||
this.disable();
|
||||
} else {
|
||||
this.enable();
|
||||
_handle_osk(target) {
|
||||
const landscapeOsk = this._settings.get_boolean('landscape-osk');
|
||||
const portraitRightOsk = this._settings.get_boolean('portrait-right-osk');
|
||||
const portraitLeftOsk = this._settings.get_boolean('portrait-left-osk');
|
||||
const landscapeFlippedOsk = this._settings.get_boolean('landscape-flipped-osk');
|
||||
switch (target) {
|
||||
case 0:
|
||||
this._a11yApplicationsSettings.set_boolean(SHOW_KEYBOARD, landscapeOsk);
|
||||
break;
|
||||
case 1:
|
||||
this._a11yApplicationsSettings.set_boolean(SHOW_KEYBOARD, portraitLeftOsk);
|
||||
break;
|
||||
case 2:
|
||||
this._a11yApplicationsSettings.set_boolean(SHOW_KEYBOARD, landscapeFlippedOsk);
|
||||
break;
|
||||
case 3:
|
||||
this._a11yApplicationsSettings.set_boolean(SHOW_KEYBOARD, portraitRightOsk);
|
||||
break;
|
||||
}
|
||||
}
|
||||
enable() {
|
||||
this._sensor_proxy.enable();
|
||||
this._state = true;
|
||||
}
|
||||
|
||||
disable() {
|
||||
this._sensor_proxy.disable();
|
||||
this._state = false;
|
||||
}
|
||||
_handle_dor_touchpad(target) {
|
||||
const dorLandscape = this._settings.get_boolean('dor-touchpad-landscape');
|
||||
const dorPortraitRight = this._settings.get_boolean('dor-touchpad-portrait-right');
|
||||
const dorPortraitLeft = this._settings.get_boolean('dor-touchpad-portrait-left');
|
||||
const dorLandscapeFlipped = this._settings.get_boolean('dor-touchpad-landscape-flipped');
|
||||
|
||||
let setting_value = undefined;
|
||||
|
||||
switch (target) {
|
||||
case 0:
|
||||
if (dorLandscape) {
|
||||
setting_value = "disabled";
|
||||
} else {
|
||||
setting_value = "enabled";
|
||||
}
|
||||
this._peripheralTouchpadSettings.set_string(TOUCHPAD_EVENTS, setting_value);
|
||||
break;
|
||||
case 1:
|
||||
if (dorPortraitLeft) {
|
||||
setting_value = "disabled";
|
||||
} else {
|
||||
setting_value = "enabled";
|
||||
}
|
||||
this._peripheralTouchpadSettings.set_string(TOUCHPAD_EVENTS, setting_value);
|
||||
break;
|
||||
case 2:
|
||||
if (dorLandscapeFlipped) {
|
||||
setting_value = "disabled";
|
||||
} else {
|
||||
setting_value = "enabled";
|
||||
}
|
||||
this._peripheralTouchpadSettings.set_string(TOUCHPAD_EVENTS, setting_value);
|
||||
break;
|
||||
case 3:
|
||||
if (dorPortraitRight) {
|
||||
setting_value = "disabled";
|
||||
} else {
|
||||
setting_value = "enabled";
|
||||
}
|
||||
this._peripheralTouchpadSettings.set_string(TOUCHPAD_EVENTS, setting_value);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
rotate_to(orientation) {
|
||||
const sensor = Orientation[orientation];
|
||||
const invert_horizontal_direction = this._settings.get_boolean('invert-horizontal-rotation-direction');
|
||||
@ -294,70 +248,13 @@ class ScreenAutorotate {
|
||||
|
||||
target = (target + offset) % 4;
|
||||
if (this._settings.get_boolean('debug-logging')) {
|
||||
console.debug(`sensor=${Orientation[orientation]}`);
|
||||
console.debug(`offset=${offset}`);
|
||||
console.debug(`target=${target}`);
|
||||
console.log(`sensor=${Orientation[orientation]}`);
|
||||
console.log(`offset=${offset}`);
|
||||
console.log(`target=${target}`);
|
||||
}
|
||||
Rotator.rotate_to(target);
|
||||
}
|
||||
}
|
||||
|
||||
export default class ScreenAutoRotateExtension extends Extension {
|
||||
enable() {
|
||||
this._settings = this.getSettings();
|
||||
this._ext = new ScreenAutorotate(this._settings);
|
||||
|
||||
this._settings.connect('changed::manual-flip', (settings, key) => {
|
||||
if (settings.get_boolean(key)) {
|
||||
this._add_manual_flip();
|
||||
} else {
|
||||
this._remove_manual_flip();
|
||||
}
|
||||
});
|
||||
|
||||
this._settings.connect('changed::hide-lock-rotate', (settings, key) => {
|
||||
this._set_hide_lock_rotate(settings.get_boolean(key));
|
||||
});
|
||||
|
||||
if (this._settings.get_boolean('manual-flip')) {
|
||||
this._add_manual_flip();
|
||||
} else {
|
||||
this._remove_manual_flip();
|
||||
}
|
||||
|
||||
/* Timeout needed due to unknown race condition causing 'Auto Rotate'
|
||||
* Quick Toggle to be undefined for a brief moment.
|
||||
*/
|
||||
this._timeoutId = setTimeout(() => {
|
||||
this._set_hide_lock_rotate(this._settings.get_boolean('hide-lock-rotate'));
|
||||
}, 1000);
|
||||
}
|
||||
|
||||
_set_hide_lock_rotate(state) {
|
||||
const autoRotateIndicator = Main.panel.statusArea.quickSettings._autoRotate;
|
||||
|
||||
if (state) {
|
||||
Main.panel.statusArea.quickSettings._indicators.remove_child(autoRotateIndicator);
|
||||
Main.panel.statusArea.quickSettings.menu._grid.remove_child(autoRotateIndicator.quickSettingsItems[0]);
|
||||
} else {
|
||||
Main.panel.statusArea.quickSettings._indicators.add_child(autoRotateIndicator);
|
||||
Main.panel.statusArea.quickSettings._addItemsBefore(
|
||||
autoRotateIndicator.quickSettingsItems,
|
||||
Main.panel.statusArea.quickSettings._rfkill.quickSettingsItems[0]
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
_add_manual_flip() {
|
||||
this.flipIndicator = new ManualOrientationIndicator(this._ext);
|
||||
Main.panel.statusArea.quickSettings.addExternalIndicator(this.flipIndicator);
|
||||
}
|
||||
|
||||
_remove_manual_flip() {
|
||||
if (this.flipIndicator != null) {
|
||||
this.flipIndicator.destroy();
|
||||
this.flipIndicator = null;
|
||||
}
|
||||
this._handle_osk(target);
|
||||
this._handle_dor_touchpad(target);
|
||||
}
|
||||
|
||||
disable() {
|
||||
@ -368,12 +265,17 @@ export default class ScreenAutoRotateExtension extends Extension {
|
||||
have auto-locked. This provides the ability to log back in regardless of
|
||||
the orientation of the device in tablet mode.
|
||||
*/
|
||||
this._settings.disconnect(this._manual_flip_settings_handler);
|
||||
this._settings.disconnect(this._hide_lock_rotate_settings_handler);
|
||||
this._settings = null;
|
||||
clearTimeout(this._timeoutId);
|
||||
this._timeoutId = null;
|
||||
this._remove_manual_flip();
|
||||
this._ext.destroy();
|
||||
this._ext = null;
|
||||
this._sensor_proxy.destroy();
|
||||
this._orientation_settings.disconnect(this._orientation_settings_handler);
|
||||
this._orientation_settings = null;
|
||||
this._a11yApplicationsSettings = null;
|
||||
this._restore_system_actions();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -0,0 +1,34 @@
|
||||
/* logicalMonitor.js
|
||||
*
|
||||
* Copyright (C) 2024 kosmospredanie, shyzus
|
||||
*
|
||||
* 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/>.
|
||||
*/
|
||||
|
||||
export class LogicalMonitor {
|
||||
constructor(variant) {
|
||||
let unpacked = variant.unpack();
|
||||
this.x = unpacked[0].unpack();
|
||||
this.y = unpacked[1].unpack();
|
||||
this.scale = unpacked[2].unpack();
|
||||
this.transform = unpacked[3].unpack();
|
||||
this.primary = unpacked[4].unpack();
|
||||
// [ [connector, vendor, product, serial]* ]
|
||||
this.monitors = unpacked[5].deep_unpack();
|
||||
this.properties = unpacked[6].unpack();
|
||||
for (let key in this.properties) {
|
||||
this.properties[key] = this.properties[key].unpack().unpack();
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,36 @@
|
||||
/* manualOrientationIndicator.js
|
||||
* Copyright (C) 2024 shyzus
|
||||
*
|
||||
* 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/>.
|
||||
*/
|
||||
|
||||
import GObject from 'gi://GObject';
|
||||
|
||||
import { SystemIndicator } from 'resource:///org/gnome/shell/ui/quickSettings.js';
|
||||
|
||||
import { ManualOrientationMenuToggle } from './manualOrientationMenuToggle.js';
|
||||
|
||||
export const ManualOrientationIndicator = GObject.registerClass(
|
||||
class ManualOrientationIndicator extends SystemIndicator {
|
||||
constructor(ext) {
|
||||
super();
|
||||
this.toggle = new ManualOrientationMenuToggle(ext);
|
||||
this.quickSettingsItems.push(this.toggle);
|
||||
}
|
||||
|
||||
destroy() {
|
||||
this.quickSettingsItems.pop(this.toggle);
|
||||
this.toggle.destroy();
|
||||
}
|
||||
});
|
||||
@ -0,0 +1,102 @@
|
||||
/* manualOrientationMenuToggle.js
|
||||
* Copyright (C) 2024 shyzus
|
||||
*
|
||||
* 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/>.
|
||||
*/
|
||||
|
||||
import GObject from 'gi://GObject';
|
||||
|
||||
import { QuickMenuToggle } from 'resource:///org/gnome/shell/ui/quickSettings.js';
|
||||
import * as PopupMenu from 'resource:///org/gnome/shell/ui/popupMenu.js';
|
||||
|
||||
export const ManualOrientationMenuToggle = GObject.registerClass(
|
||||
class ManualOrientationMenuToggle extends QuickMenuToggle {
|
||||
constructor(ext) {
|
||||
super({
|
||||
title: 'Rotate',
|
||||
iconName: 'object-rotate-left-symbolic',
|
||||
menuEnabled: true,
|
||||
toggleMode: true,
|
||||
});
|
||||
|
||||
this.menu.setHeader('object-rotate-left-symbolic', 'Screen Rotate');
|
||||
|
||||
this._section = new PopupMenu.PopupMenuSection();
|
||||
this.menu.addMenuItem(this._section);
|
||||
|
||||
this.landscapeItem = new PopupMenu.PopupMenuItem('Landscape', {
|
||||
reactive: true,
|
||||
can_focus: true,
|
||||
});
|
||||
|
||||
this.portraitLeftItem = new PopupMenu.PopupMenuItem('Portrait Left', {
|
||||
reactive: true,
|
||||
can_focus: true,
|
||||
});
|
||||
|
||||
this.landscapeFlipItem = new PopupMenu.PopupMenuItem('Landscape Flipped', {
|
||||
reactive: true,
|
||||
can_focus: true,
|
||||
});
|
||||
|
||||
this.portraitRightItem = new PopupMenu.PopupMenuItem('Portrait Right', {
|
||||
reactive: true,
|
||||
can_focus: true,
|
||||
});
|
||||
|
||||
this.landscapeItem.connect('activate', () => {
|
||||
this._onItemActivate(this.landscapeItem);
|
||||
ext.rotate_to('normal');
|
||||
});
|
||||
this.portraitLeftItem.connect('activate', () => {
|
||||
this._onItemActivate(this.portraitLeftItem);
|
||||
ext.rotate_to('left-up');
|
||||
});
|
||||
this.landscapeFlipItem.connect('activate', () => {
|
||||
this._onItemActivate(this.landscapeFlipItem);
|
||||
ext.rotate_to('bottom-up');
|
||||
});
|
||||
this.portraitRightItem.connect('activate', () => {
|
||||
this._onItemActivate(this.portraitRightItem);
|
||||
ext.rotate_to('right-up');
|
||||
});
|
||||
|
||||
this._section.addMenuItem(this.landscapeItem);
|
||||
this._section.addMenuItem(this.portraitLeftItem);
|
||||
this._section.addMenuItem(this.landscapeFlipItem);
|
||||
this._section.addMenuItem(this.portraitRightItem);
|
||||
|
||||
this.menu.addMenuItem(new PopupMenu.PopupSeparatorMenuItem());
|
||||
this.menu.addSettingsAction('Extension Settings',
|
||||
'com.mattjakeman.ExtensionManager.desktop');
|
||||
|
||||
this.connect('clicked', () => {
|
||||
if (this.checked === true) {
|
||||
ext.rotate_to('right-up');
|
||||
} else {
|
||||
ext.rotate_to('normal');
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
_onItemActivate(item) {
|
||||
this.landscapeItem.setOrnament(PopupMenu.Ornament.HIDDEN);
|
||||
this.portraitLeftItem.setOrnament(PopupMenu.Ornament.HIDDEN);
|
||||
this.landscapeFlipItem.setOrnament(PopupMenu.Ornament.HIDDEN);
|
||||
this.portraitRightItem.setOrnament(PopupMenu.Ornament.HIDDEN);
|
||||
|
||||
item.setOrnament(PopupMenu.Ornament.CHECK);
|
||||
}
|
||||
});
|
||||
|
||||
@ -10,9 +10,10 @@
|
||||
"settings-schema": "org.gnome.shell.extensions.screen-rotate",
|
||||
"shell-version": [
|
||||
"45",
|
||||
"46"
|
||||
"46",
|
||||
"47"
|
||||
],
|
||||
"url": "https://github.com/shyzus/gnome-shell-extension-screen-autorotate",
|
||||
"uuid": "screen-rotate@shyzus.github.io",
|
||||
"version": 19
|
||||
"version": 24
|
||||
}
|
||||
@ -0,0 +1,50 @@
|
||||
/* monitor.js
|
||||
*
|
||||
* Copyright (C) 2024 kosmospredanie, efosmark, shyzus
|
||||
*
|
||||
* 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/>.
|
||||
*/
|
||||
|
||||
export class Monitor {
|
||||
constructor(variant) {
|
||||
let unpacked = variant.unpack();
|
||||
this.connector = unpacked[0].unpack()[0].unpack();
|
||||
|
||||
let modes = unpacked[1].unpack();
|
||||
for (let mode_idx in modes) {
|
||||
let mode = modes[mode_idx].unpack();
|
||||
let id = mode[0].unpack();
|
||||
let mode_props = mode[6].unpack();
|
||||
if ('is-current' in mode_props) {
|
||||
let is_current = mode_props['is-current'].unpack().get_boolean();
|
||||
if (is_current) {
|
||||
this.current_mode_id = id;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
let props = unpacked[2].unpack();
|
||||
if ('is-underscanning' in props) {
|
||||
this.is_underscanning = props['is-underscanning'].unpack().get_boolean();
|
||||
} else {
|
||||
this.is_underscanning = false;
|
||||
}
|
||||
if ('is-builtin' in props) {
|
||||
this.is_builtin = props['is-builtin'].unpack().get_boolean();
|
||||
} else {
|
||||
this.is_builtin = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,24 @@
|
||||
/* orientation.js
|
||||
* Copyright (C) 2024 shyzus
|
||||
*
|
||||
* 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/>.
|
||||
*/
|
||||
|
||||
// Orientation names must match those provided by net.hadess.SensorProxy
|
||||
export const Orientation = Object.freeze({
|
||||
'normal': 0,
|
||||
'left-up': 1,
|
||||
'bottom-up': 2,
|
||||
'right-up': 3
|
||||
});
|
||||
@ -21,6 +21,8 @@ import Adw from 'gi://Adw';
|
||||
|
||||
import { ExtensionPreferences } from 'resource:///org/gnome/Shell/Extensions/js/extensions/prefs.js';
|
||||
|
||||
import { Orientation } from './orientation.js';
|
||||
|
||||
export default class MyExtensionPreferences extends ExtensionPreferences {
|
||||
|
||||
fillPreferencesWindow(window) {
|
||||
@ -37,6 +39,14 @@ export default class MyExtensionPreferences extends ExtensionPreferences {
|
||||
shellMenuGroup.set_title('GNOME Shell Menu Settings');
|
||||
page.add(shellMenuGroup);
|
||||
|
||||
const oskSettingsGroup = new Adw.PreferencesGroup();
|
||||
oskSettingsGroup.set_title('On-Screen-Keyboard Settings');
|
||||
page.add(oskSettingsGroup);
|
||||
|
||||
const disableOnRotateGroup = new Adw.PreferencesGroup();
|
||||
disableOnRotateGroup.set_title('Disable-On-Rotation Settings');
|
||||
page.add(disableOnRotateGroup);
|
||||
|
||||
const debugGroup = new Adw.PreferencesGroup();
|
||||
debugGroup.set_title('Debug Settings');
|
||||
page.add(debugGroup);
|
||||
@ -59,9 +69,10 @@ export default class MyExtensionPreferences extends ExtensionPreferences {
|
||||
|
||||
const setOffsetRow = new Adw.ActionRow({
|
||||
title: 'Set orientation offset',
|
||||
subtitle: 'Valid offset range: 0 to 3. Default is 0\nExperiment with this in case\
|
||||
orientation is incorrect due to the display being mounted in a non-landscape orientation\
|
||||
e.g PineTab2 or GPD Pocket 3'
|
||||
subtitle: 'Valid offset range: 0 to 3. Default is 0\nExperiment with' +
|
||||
' this in case orientation is incorrect due to the display' +
|
||||
' being mounted in a non-landscape orientation' +
|
||||
' e.g PineTab2 or GPD Pocket 3'
|
||||
});
|
||||
|
||||
orientationGroup.add(setOffsetRow);
|
||||
@ -77,6 +88,26 @@ export default class MyExtensionPreferences extends ExtensionPreferences {
|
||||
});
|
||||
shellMenuGroup.add(hideLockRotateRow);
|
||||
|
||||
const landscapeOskRow = new Adw.ActionRow({
|
||||
title: 'Show OSK in landscape orientation'
|
||||
});
|
||||
oskSettingsGroup.add(landscapeOskRow);
|
||||
|
||||
const portraitRightOskRow = new Adw.ActionRow({
|
||||
title: 'Show OSK in portrait (right) orientation'
|
||||
});
|
||||
oskSettingsGroup.add(portraitRightOskRow);
|
||||
|
||||
const landscapeFlippedOskRow = new Adw.ActionRow({
|
||||
title: 'Show OSK in landscape (flipped) orientation'
|
||||
});
|
||||
oskSettingsGroup.add(landscapeFlippedOskRow);
|
||||
|
||||
const portraitLeftOskRow = new Adw.ActionRow({
|
||||
title: 'Show OSK in portrait (left) orientation'
|
||||
});
|
||||
oskSettingsGroup.add(portraitLeftOskRow);
|
||||
|
||||
const toggleLoggingRow = new Adw.ActionRow({
|
||||
title: 'Enable debug logging',
|
||||
subtitle: 'Use "journalctl /usr/bin/gnome-shell -f" to see log output.'
|
||||
@ -111,6 +142,125 @@ export default class MyExtensionPreferences extends ExtensionPreferences {
|
||||
valign: Gtk.Align.CENTER,
|
||||
});
|
||||
|
||||
const landscapeOskCheckButton = new Gtk.CheckButton({
|
||||
active: window._settings.get_boolean('landscape-osk'),
|
||||
valign: Gtk.Align.CENTER
|
||||
});
|
||||
|
||||
const portraitRightOskCheckButton = new Gtk.CheckButton({
|
||||
active: window._settings.get_boolean('portrait-right-osk'),
|
||||
valign: Gtk.Align.CENTER
|
||||
});
|
||||
|
||||
const portraitLeftOskCheckButton = new Gtk.CheckButton({
|
||||
active: window._settings.get_boolean('portrait-left-osk'),
|
||||
valign: Gtk.Align.CENTER
|
||||
});
|
||||
|
||||
const landscapeFlippedOskCheckButton = new Gtk.CheckButton({
|
||||
active: window._settings.get_boolean('landscape-flipped-osk'),
|
||||
valign: Gtk.Align.CENTER
|
||||
});
|
||||
|
||||
const dorNotebook = new Gtk.Notebook();
|
||||
|
||||
const dorKeyboardPage = new Gtk.ListBox();
|
||||
dorKeyboardPage.set_visible(false); // Keep hidden until feature can be implemented.
|
||||
dorKeyboardPage.set_selection_mode(Gtk.SelectionMode.NONE);
|
||||
|
||||
for (let orientation in Orientation) {
|
||||
let actionRowTitle = undefined;
|
||||
let checkButtonBoolId = undefined;
|
||||
|
||||
switch (orientation) {
|
||||
case 'normal':
|
||||
actionRowTitle = "Landscape";
|
||||
checkButtonBoolId = "dor-keyboard-landscape";
|
||||
break;
|
||||
case 'left-up':
|
||||
actionRowTitle = "Portrait (Left)";
|
||||
checkButtonBoolId = "dor-keyboard-portrait-left";
|
||||
break;
|
||||
case 'bottom-up':
|
||||
actionRowTitle = "Landscape Flipped";
|
||||
checkButtonBoolId = "dor-keyboard-landscape-flipped";
|
||||
break;
|
||||
case 'right-up':
|
||||
actionRowTitle = "Portrait (Right)";
|
||||
checkButtonBoolId = "dor-keyboard-portrait-right";
|
||||
break;
|
||||
}
|
||||
|
||||
const dorActionRow = new Adw.ActionRow({
|
||||
title: actionRowTitle
|
||||
});
|
||||
|
||||
const dorCheckButton = new Gtk.CheckButton({
|
||||
active: window._settings.get_boolean(checkButtonBoolId),
|
||||
valign: Gtk.Align.CENTER
|
||||
});
|
||||
|
||||
window._settings.bind(checkButtonBoolId,
|
||||
dorCheckButton, 'active', Gio.SettingsBindFlags.DEFAULT);
|
||||
|
||||
dorActionRow.add_suffix(dorCheckButton);
|
||||
dorActionRow.activatable_widget = dorCheckButton;
|
||||
|
||||
dorKeyboardPage.append(dorActionRow);
|
||||
}
|
||||
|
||||
const dorTouchpadPage = new Gtk.ListBox();
|
||||
dorTouchpadPage.set_selection_mode(Gtk.SelectionMode.NONE);
|
||||
|
||||
for (let orientation in Orientation) {
|
||||
let actionRowTitle = undefined;
|
||||
let checkButtonBoolId = undefined;
|
||||
|
||||
switch (orientation) {
|
||||
case 'normal':
|
||||
actionRowTitle = "Landscape";
|
||||
checkButtonBoolId = "dor-touchpad-landscape";
|
||||
break;
|
||||
case 'left-up':
|
||||
actionRowTitle = "Portrait (Left)";
|
||||
checkButtonBoolId = "dor-touchpad-portrait-left";
|
||||
break;
|
||||
case 'bottom-up':
|
||||
actionRowTitle = "Landscape Flipped";
|
||||
checkButtonBoolId = "dor-touchpad-landscape-flipped";
|
||||
break;
|
||||
case 'right-up':
|
||||
actionRowTitle = "Portrait (Right)";
|
||||
checkButtonBoolId = "dor-touchpad-portrait-right";
|
||||
break;
|
||||
}
|
||||
|
||||
const dorActionRow = new Adw.ActionRow({
|
||||
title: actionRowTitle
|
||||
});
|
||||
|
||||
const dorCheckButton = new Gtk.CheckButton({
|
||||
active: window._settings.get_boolean(checkButtonBoolId),
|
||||
valign: Gtk.Align.CENTER
|
||||
});
|
||||
|
||||
window._settings.bind(checkButtonBoolId,
|
||||
dorCheckButton, 'active', Gio.SettingsBindFlags.DEFAULT);
|
||||
|
||||
dorActionRow.add_suffix(dorCheckButton);
|
||||
dorActionRow.activatable_widget = dorCheckButton;
|
||||
|
||||
dorTouchpadPage.append(dorActionRow);
|
||||
}
|
||||
|
||||
const dorKeyboardLabel = Gtk.Label.new('Keyboard');
|
||||
dorNotebook.append_page(dorKeyboardPage, dorKeyboardLabel);
|
||||
|
||||
const dorTouchpadLabel = Gtk.Label.new('Touchpad');
|
||||
dorNotebook.append_page(dorTouchpadPage, dorTouchpadLabel)
|
||||
|
||||
disableOnRotateGroup.add(dorNotebook);
|
||||
|
||||
const toggleLoggingSwitch = new Gtk.Switch({
|
||||
active: window._settings.get_boolean('debug-logging'),
|
||||
valign: Gtk.Align.CENTER
|
||||
@ -134,6 +284,18 @@ export default class MyExtensionPreferences extends ExtensionPreferences {
|
||||
window._settings.bind('hide-lock-rotate',
|
||||
hideLockRotateSwitch, 'active', Gio.SettingsBindFlags.DEFAULT);
|
||||
|
||||
window._settings.bind('landscape-osk',
|
||||
landscapeOskCheckButton, 'active', Gio.SettingsBindFlags.DEFAULT);
|
||||
|
||||
window._settings.bind('portrait-right-osk',
|
||||
portraitRightOskCheckButton, 'active', Gio.SettingsBindFlags.DEFAULT);
|
||||
|
||||
window._settings.bind('portrait-left-osk',
|
||||
portraitLeftOskCheckButton, 'active', Gio.SettingsBindFlags.DEFAULT);
|
||||
|
||||
window._settings.bind('landscape-flipped-osk',
|
||||
landscapeFlippedOskCheckButton, 'active', Gio.SettingsBindFlags.DEFAULT);
|
||||
|
||||
window._settings.bind('debug-logging',
|
||||
toggleLoggingSwitch, 'active', Gio.SettingsBindFlags.DEFAULT);
|
||||
|
||||
@ -155,6 +317,18 @@ export default class MyExtensionPreferences extends ExtensionPreferences {
|
||||
hideLockRotateRow.add_suffix(hideLockRotateSwitch);
|
||||
hideLockRotateRow.activatable_widget = hideLockRotateSwitch;
|
||||
|
||||
landscapeOskRow.add_suffix(landscapeOskCheckButton);
|
||||
landscapeOskRow.activatable_widget = landscapeOskCheckButton;
|
||||
|
||||
portraitRightOskRow.add_suffix(portraitRightOskCheckButton);
|
||||
portraitRightOskRow.activatable_widget = portraitRightOskCheckButton;
|
||||
|
||||
portraitLeftOskRow.add_suffix(portraitLeftOskCheckButton);
|
||||
portraitLeftOskRow.activatable_widget = portraitLeftOskCheckButton;
|
||||
|
||||
landscapeFlippedOskRow.add_suffix(landscapeFlippedOskCheckButton);
|
||||
landscapeFlippedOskRow.activatable_widget = landscapeFlippedOskCheckButton;
|
||||
|
||||
toggleLoggingRow.add_suffix(toggleLoggingSwitch);
|
||||
toggleLoggingRow.activatable_widget = toggleLoggingSwitch;
|
||||
}
|
||||
|
||||
@ -17,11 +17,18 @@
|
||||
*/
|
||||
import Gio from 'gi://Gio';
|
||||
|
||||
import * as BusUtils from './busUtils.js';
|
||||
import { DisplayConfigState } from './displayConfigState.js'
|
||||
|
||||
const connection = Gio.DBus.session;
|
||||
|
||||
export function call_dbus_method(method, params = null, handler) {
|
||||
if (handler != undefined || handler != null) {
|
||||
export const Methods = Object.freeze({
|
||||
'verify': 0,
|
||||
'temporary': 1,
|
||||
'persistent': 2
|
||||
});
|
||||
|
||||
export function call_dbus_method(method, handler, params = null) {
|
||||
if (handler !== undefined || handler !== null) {
|
||||
connection.call(
|
||||
'org.gnome.Mutter.DisplayConfig',
|
||||
'/org/gnome/Mutter/DisplayConfig',
|
||||
@ -49,10 +56,10 @@ export function call_dbus_method(method, params = null, handler) {
|
||||
|
||||
export function get_state() {
|
||||
return new Promise((resolve, reject) => {
|
||||
call_dbus_method('GetCurrentState', null, (connection, res) => {
|
||||
call_dbus_method('GetCurrentState', (conn, res) => {
|
||||
try {
|
||||
let reply = connection.call_finish(res);
|
||||
let configState = new BusUtils.DisplayConfigState(reply)
|
||||
let reply = conn.call_finish(res);
|
||||
let configState = new DisplayConfigState(reply)
|
||||
resolve(configState);
|
||||
} catch (err) {
|
||||
reject(err);
|
||||
@ -65,13 +72,13 @@ export function get_state() {
|
||||
export function rotate_to(transform) {
|
||||
this.get_state().then(state => {
|
||||
let target_monitor = state.builtin_monitor;
|
||||
if (target_monitor == undefined) {
|
||||
if (target_monitor === undefined) {
|
||||
target_monitor = state.monitors[0]
|
||||
}
|
||||
let logical_monitor = state.get_logical_monitor_for(target_monitor.connector);
|
||||
logical_monitor.transform = transform;
|
||||
let variant = state.pack_to_apply(BusUtils.Methods['temporary']);
|
||||
call_dbus_method('ApplyMonitorsConfig', variant);
|
||||
let variant = state.pack_to_apply(this.Methods['temporary']);
|
||||
call_dbus_method('ApplyMonitorsConfig', null, variant);
|
||||
}).catch(err => {
|
||||
console.error(err);
|
||||
})
|
||||
|
||||
Binary file not shown.
@ -1,21 +1,3 @@
|
||||
<!--
|
||||
- org.gnome.shell.extensions.screen-rotate.gschema.xml
|
||||
- Copyright (C) 2024 shyzus, Shinigaminai
|
||||
-
|
||||
- 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/>.
|
||||
-
|
||||
-->
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<schemalist>
|
||||
<schema id="org.gnome.shell.extensions.screen-rotate"
|
||||
@ -40,10 +22,59 @@
|
||||
<key type="b" name="manual-flip">
|
||||
<default>false</default>
|
||||
<description>Enable a toggle in the GNOME Shell System Menu to manually flip between landscape and portrait.</description>
|
||||
</key><key type="b" name="hide-lock-rotate">
|
||||
</key>
|
||||
<key type="b" name="hide-lock-rotate">
|
||||
<default>false</default>
|
||||
<description>Hide the 'Auto Rotate' quick toggle.</description>
|
||||
</key>
|
||||
<key type="b" name="landscape-osk">
|
||||
<default>false</default>
|
||||
<description>Enable the use of the On-Screen-Keyboard for the landscape orientation.</description>
|
||||
</key>
|
||||
<key type="b" name="portrait-right-osk">
|
||||
<default>false</default>
|
||||
<description>Enable the use of the On-Screen-Keyboard for the portrait (right) orientation.</description>
|
||||
</key>
|
||||
<key type="b" name="portrait-left-osk">
|
||||
<default>false</default>
|
||||
<description>Enable the use of the On-Screen-Keyboard for the portrait (left) orientation.</description>
|
||||
</key>
|
||||
<key type="b" name="landscape-flipped-osk">
|
||||
<default>false</default>
|
||||
<description>Enable the use of the On-Screen-Keyboard for the landscape (flipped) orientation.</description>
|
||||
</key>
|
||||
<key type="b" name="dor-keyboard-landscape">
|
||||
<default>false</default>
|
||||
<description>Toggle disabling the keyboard when the orientation is landscape.</description>
|
||||
</key>
|
||||
<key type="b" name="dor-keyboard-portrait-left">
|
||||
<default>false</default>
|
||||
<description>Toggle disabling the keyboard when the orientation is portrait left.</description>
|
||||
</key>
|
||||
<key type="b" name="dor-keyboard-landscape-flipped">
|
||||
<default>false</default>
|
||||
<description>Toggle disabling the keyboard when the orientation is landscape-flipped.</description>
|
||||
</key>
|
||||
<key type="b" name="dor-keyboard-portrait-right">
|
||||
<default>false</default>
|
||||
<description>Toggle disabling the keyboard when the orientation is portrait right.</description>
|
||||
</key>
|
||||
<key type="b" name="dor-touchpad-landscape">
|
||||
<default>false</default>
|
||||
<description>Toggle disabling the touchpad when the orientation is landscape.</description>
|
||||
</key>
|
||||
<key type="b" name="dor-touchpad-portrait-left">
|
||||
<default>false</default>
|
||||
<description>Toggle disabling the touchpad when the orientation is portrait left.</description>
|
||||
</key>
|
||||
<key type="b" name="dor-touchpad-landscape-flipped">
|
||||
<default>false</default>
|
||||
<description>Toggle disabling the touchpad when the orientation is landscape-flipped.</description>
|
||||
</key>
|
||||
<key type="b" name="dor-touchpad-portrait-right">
|
||||
<default>false</default>
|
||||
<description>Toggle disabling the touchpad when the orientation is portrait right.</description>
|
||||
</key>
|
||||
<key type="b" name="debug-logging">
|
||||
<default>false</default>
|
||||
<description>Toggle debug logging.</description>
|
||||
|
||||
@ -0,0 +1,76 @@
|
||||
/* sensorProxy.js
|
||||
* Copyright (C) 2024 kosmospredanie, shyzus
|
||||
*
|
||||
* 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/>.
|
||||
*/
|
||||
|
||||
import Gio from 'gi://Gio';
|
||||
|
||||
export class SensorProxy {
|
||||
constructor(rotate_cb) {
|
||||
this._rotate_cb = rotate_cb;
|
||||
this._proxy = null;
|
||||
this._enabled = false;
|
||||
this._watcher_id = Gio.bus_watch_name(
|
||||
Gio.BusType.SYSTEM,
|
||||
'net.hadess.SensorProxy',
|
||||
Gio.BusNameWatcherFlags.NONE,
|
||||
this.appeared.bind(this),
|
||||
this.vanished.bind(this)
|
||||
);
|
||||
}
|
||||
|
||||
destroy() {
|
||||
Gio.bus_unwatch_name(this._watcher_id);
|
||||
if (this._enabled) this.disable();
|
||||
this._proxy = null;
|
||||
}
|
||||
|
||||
enable() {
|
||||
this._enabled = true;
|
||||
if (this._proxy === null) return;
|
||||
this._proxy.call_sync('ClaimAccelerometer', null, Gio.DBusCallFlags.NONE, -1, null);
|
||||
}
|
||||
|
||||
disable() {
|
||||
this._enabled = false;
|
||||
if (this._proxy === null) return;
|
||||
this._proxy.call_sync('ReleaseAccelerometer', null, Gio.DBusCallFlags.NONE, -1, null);
|
||||
}
|
||||
|
||||
appeared(_connection, _name, _name_owner) {
|
||||
this._proxy = Gio.DBusProxy.new_for_bus_sync(
|
||||
Gio.BusType.SYSTEM, Gio.DBusProxyFlags.NONE, null,
|
||||
'net.hadess.SensorProxy', '/net/hadess/SensorProxy', 'net.hadess.SensorProxy',
|
||||
null);
|
||||
this._proxy.connect('g-properties-changed', this.properties_changed.bind(this));
|
||||
if (this._enabled) {
|
||||
this._proxy.call_sync('ClaimAccelerometer', null, Gio.DBusCallFlags.NONE, -1, null);
|
||||
}
|
||||
}
|
||||
|
||||
vanished(_connection, _name) {
|
||||
this._proxy = null;
|
||||
}
|
||||
|
||||
properties_changed(proxy, changed, _invalidated) {
|
||||
if (!this._enabled) return;
|
||||
let properties = changed.deep_unpack();
|
||||
for (let [name, value] of Object.entries(properties)) {
|
||||
if (name !== 'AccelerometerOrientation') continue;
|
||||
let target = value.unpack();
|
||||
this._rotate_cb(target);
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user