123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281 |
- /* extension.js
- * Copyright (C) 2024 kosmospredanie, 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/>.
- */
- import Gio from 'gi://Gio';
- 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 { 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';
- export default class ScreenAutoRotateExtension extends Extension {
- enable() {
- this._settings = this.getSettings();
- this._system_actions = SystemActions.getDefault();
- 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_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;
- let locked = this._orientation_settings.get_boolean(ORIENTATION_LOCK_KEY);
- 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() {
- this._system_actions_backup = {
- '_updateOrientationLock': this._system_actions._updateOrientationLock
- };
- this._system_actions._updateOrientationLock = function() {
- this._actions.get('lock-orientation').available = true;
- this.notify('can-lock-orientation');
- };
- this._system_actions._updateOrientationLock();
- }
- _restore_system_actions() {
- if (this._system_actions_backup === null) return;
- this._system_actions._updateOrientationLock = this._system_actions_backup['_updateOrientationLock'];
- this._system_actions._updateOrientationLock();
- this._system_actions_backup = null;
- }
- _orientation_lock_changed() {
- let locked = this._orientation_settings.get_boolean(ORIENTATION_LOCK_KEY);
- if (this._state === locked) {
- this.toggle_rotation_lock();
- }
- }
- _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;
- }
- }
- _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');
- const invert_vertical_direction = this._settings.get_boolean('invert-vertical-rotation-direction');
- const offset = this._settings.get_int('orientation-offset');
- let target = sensor; // Default to sensor output.
- switch (sensor) {
- case 0:
- // sensor reports landscape
- if (invert_horizontal_direction) {
- target = 2;
- }
- break;
- case 1:
- // sensor reports portrait
- if (invert_vertical_direction) {
- target = 3;
- }
- break;
- case 2:
- // sensor reports landscape-inverted
- if (invert_horizontal_direction) {
- target = 0;
- }
- break;
- case 3:
- // sensor reports portrait-inverted
- if (invert_vertical_direction) {
- target = 1;
- }
- break;
- }
- target = (target + offset) % 4;
- if (this._settings.get_boolean('debug-logging')) {
- console.log(`sensor=${Orientation[orientation]}`);
- console.log(`offset=${offset}`);
- console.log(`target=${target}`);
- }
- Rotator.rotate_to(target);
- this._handle_osk(target);
- this._handle_dor_touchpad(target);
- }
- disable() {
- /*
- Comment for unlock-dialog usage:
- The unlock-dialog session-mode is useful for this extension as it allows
- the user to rotate their screen or lock rotation after their device may
- 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._sensor_proxy.destroy();
- this._orientation_settings.disconnect(this._orientation_settings_handler);
- this._orientation_settings = null;
- this._a11yApplicationsSettings = null;
- this._restore_system_actions();
- }
- }
|