From be49a0eed86d4721035b3e7af4950ce49c7c9283 Mon Sep 17 00:00:00 2001 From: David Lapshin Date: Fri, 16 Dec 2022 15:40:13 +0300 Subject: [PATCH 01/33] Russian translation --- po/ru.po | 5 +++++ 1 file changed, 5 insertions(+) create mode 100644 po/ru.po diff --git a/po/ru.po b/po/ru.po new file mode 100644 index 0000000..566922b --- /dev/null +++ b/po/ru.po @@ -0,0 +1,5 @@ +# Quick settings notifications title text + +# Notifications title +msgid "Notifications" +msgstr "Уведомления" From 2e0e60295ebbaa6d5dea3e3f45d009d56172233a Mon Sep 17 00:00:00 2001 From: Andreas Angerer Date: Sun, 25 Dec 2022 10:05:35 +0100 Subject: [PATCH 02/33] Moves notifications-indicator also to the right panel for unread notifications --- libs/dndQuickToogleHandler.js | 58 +++++++++++++++++++++++++++++------ 1 file changed, 48 insertions(+), 10 deletions(-) diff --git a/libs/dndQuickToogleHandler.js b/libs/dndQuickToogleHandler.js index c09e305..49a50df 100644 --- a/libs/dndQuickToogleHandler.js +++ b/libs/dndQuickToogleHandler.js @@ -1,6 +1,7 @@ const { Gio, GObject } = imports.gi; const { QuickToggle, SystemIndicator } = imports.ui.quickSettings; const { St } = imports.gi +const Main = imports.ui.main; const DndQuickToogle = GObject.registerClass( class DndQuickToogle extends QuickToggle { @@ -41,6 +42,10 @@ var Indicator = GObject.registerClass( class Indicator extends SystemIndicator { _init() { super._init(); + + this._sources = []; + this._count = 0; + this._indicator = this._addIndicator(); @@ -51,20 +56,53 @@ class Indicator extends SystemIndicator { schema_id: 'org.gnome.desktop.notifications', }); - this._changedId = this._settings.connect('changed::show-banners', - () => this._sync()); + this._settings.connect('changed::show-banners', this._sync.bind(this)); + + Main.messageTray.connect('source-added', this._onSourceAdded.bind(this)); + Main.messageTray.connect('source-removed', this._onSourceRemoved.bind(this)); + Main.messageTray.connect('queue-changed', this._updateCount.bind(this)); + + + let sources = Main.messageTray.getSources(); + sources.forEach(source => this._onSourceAdded(null, source)); + this._sync(); + + this.connect('destroy', () => { + this._settings.run_dispose(); + this._settings = null; + }); + } - _sync() { - const checked = !this._settings.get_boolean('show-banners'); - if (checked){ - this._indicator.visible = true; - } - else{ - this._indicator.visible = false; - } + + _onSourceAdded(tray, source) { + source.connect('notify::count', this._updateCount.bind(this)); + this._sources.push(source); + this._updateCount(); + } + + _onSourceRemoved(tray, source) { + this._sources.splice(this._sources.indexOf(source), 1); + this._updateCount(); + } + + _updateCount() { + let count = 0; + this._sources.forEach(source => (count += source.unseenCount)); + this._count = count - Main.messageTray.queueCount; + this._sync(); + } + + + _sync() { + let doNotDisturb = !this._settings.get_boolean('show-banners'); + + this._indicator.icon_name = doNotDisturb + ? 'notifications-disabled-symbolic' + : 'message-indicator-symbolic'; + this._indicator.visible = doNotDisturb || this._count > 0; } From 9a82f39aa8c78e6b30a12dc5c98b9be7cb992b68 Mon Sep 17 00:00:00 2001 From: ondra05 Date: Sat, 14 Jan 2023 20:46:57 +0100 Subject: [PATCH 03/33] =?UTF-8?q?Add=20Czech=20=C2=BBNotifications=C2=AB?= =?UTF-8?q?=20title=20translation?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- po/cs.po | 3 +++ 1 file changed, 3 insertions(+) create mode 100644 po/cs.po diff --git a/po/cs.po b/po/cs.po new file mode 100644 index 0000000..a402349 --- /dev/null +++ b/po/cs.po @@ -0,0 +1,3 @@ +# Quick settings notifications title text +msgid "Notifications" +msgstr "Upozornění" From cd8224ef1e797829ed9a2d42de10c0d9ca9ce2f4 Mon Sep 17 00:00:00 2001 From: Kieran Gordon Date: Tue, 18 Apr 2023 19:35:03 +0100 Subject: [PATCH 04/33] Update to GNOME 44 - Rename dndQuickToogleHandler.js to dndQuickToggleHandler.js - Update metadata.js to include GNOME 44 - Replace label with title as per G44 changes & add this.label --- features/dateMenu.js | 126 +++++++++++++++++----------------- features/dndQuickToggle.js | 93 +++++++++++++------------ libs/dndQuickToggleHandler.js | 78 +++++++++++++++++++++ libs/dndQuickToogleHandler.js | 72 ------------------- metadata.json | 4 +- 5 files changed, 189 insertions(+), 184 deletions(-) create mode 100644 libs/dndQuickToggleHandler.js delete mode 100644 libs/dndQuickToogleHandler.js diff --git a/features/dateMenu.js b/features/dateMenu.js index 3584110..d6d7c5c 100644 --- a/features/dateMenu.js +++ b/features/dateMenu.js @@ -1,75 +1,77 @@ -const ExtensionUtils = imports.misc.extensionUtils -const Me = ExtensionUtils.getCurrentExtension() -const { GLib } = imports.gi +const ExtensionUtils = imports.misc.extensionUtils; +const Me = ExtensionUtils.getCurrentExtension(); +const { GLib } = imports.gi; -const featureReloader = Me.imports.libs.featureReloader +const featureReloader = Me.imports.libs.featureReloader; const { - DateMenuNotifications, - DateMenuMediaControl, - DateMenuHolder, - DateMenuBox -} = Me.imports.libs.gnome -const { Indicator } = Me.imports.libs.dndQuickToogleHandler + DateMenuNotifications, + DateMenuMediaControl, + DateMenuHolder, + DateMenuBox, +} = Me.imports.libs.gnome; +const { Indicator } = Me.imports.libs.dndQuickToggleHandler; var dateMenuFeature = class { - load() { - // setup reloader - featureReloader.enableWithSettingKeys(this,[ - "datemenu-remove-media-control", - "datemenu-remove-notifications", - "datemenu-fix-weather-widget" - ]) + load() { + // setup reloader + featureReloader.enableWithSettingKeys(this, [ + "datemenu-remove-media-control", + "datemenu-remove-notifications", + "datemenu-fix-weather-widget", + ]); - // remove media control from date menu - if (this.settings.get_boolean("datemenu-remove-media-control")) { - this.dateMenuMediaControlRemoved = true - DateMenuMediaControl.hide() - this.dateMenuMediaControlConnection = DateMenuMediaControl.connect("show", ()=>{ - DateMenuMediaControl.hide() - }) + // remove media control from date menu + if (this.settings.get_boolean("datemenu-remove-media-control")) { + this.dateMenuMediaControlRemoved = true; + DateMenuMediaControl.hide(); + this.dateMenuMediaControlConnection = DateMenuMediaControl.connect( + "show", + () => { + DateMenuMediaControl.hide(); } + ); + } - // remove notifications from date menu - if (this.settings.get_boolean("datemenu-remove-notifications")) { - this.dateMenuNotificationsRemoved = true - DateMenuNotifications.hide() - DateMenuBox.style = "padding: 4px 6px 4px 0px;" - this.dateMenuConnection = DateMenuNotifications.connect("show", ()=>{ - DateMenuNotifications.hide() - }) - } - - // datemenu fix weather widget - if (this.settings.get_boolean("datemenu-fix-weather-widget")) { - this.weatherFixBackupClass = DateMenuBox.style_class - DateMenuBox.style_class += " qwreey-fixed-weather" - } + // remove notifications from date menu + if (this.settings.get_boolean("datemenu-remove-notifications")) { + this.dateMenuNotificationsRemoved = true; + DateMenuNotifications.hide(); + DateMenuBox.style = "padding: 4px 6px 4px 0px;"; + this.dateMenuConnection = DateMenuNotifications.connect("show", () => { + DateMenuNotifications.hide(); + }); } - unload() { - // disable feature reloader - featureReloader.disable(this) + // datemenu fix weather widget + if (this.settings.get_boolean("datemenu-fix-weather-widget")) { + this.weatherFixBackupClass = DateMenuBox.style_class; + DateMenuBox.style_class += " qwreey-fixed-weather"; + } + } - // restore media control - if (this.dateMenuMediaControlRemoved) { - DateMenuMediaControl.disconnect(this.dateMenuMediaControlConnection) - if (DateMenuMediaControl._shouldShow()) DateMenuMediaControl.show() - this.dateMenuMediaControlRemoved = null - this.dateMenuMediaControlConnection = null - } + unload() { + // disable feature reloader + featureReloader.disable(this); - // restore notifications to date menu - if (this.dateMenuNotificationsRemoved) { - DateMenuNotifications.disconnect(this.dateMenuConnection) - DateMenuNotifications.show() - DateMenuBox.style = "" - this.dateMenuNotificationsRemoved = null - } - // undo weather fix - if (this.weatherFixBackupClass) { - DateMenuBox.style_class = this.weatherFixBackupClass - this.weatherFixBackupClass = null - } + // restore media control + if (this.dateMenuMediaControlRemoved) { + DateMenuMediaControl.disconnect(this.dateMenuMediaControlConnection); + if (DateMenuMediaControl._shouldShow()) DateMenuMediaControl.show(); + this.dateMenuMediaControlRemoved = null; + this.dateMenuMediaControlConnection = null; } -} + // restore notifications to date menu + if (this.dateMenuNotificationsRemoved) { + DateMenuNotifications.disconnect(this.dateMenuConnection); + DateMenuNotifications.show(); + DateMenuBox.style = ""; + this.dateMenuNotificationsRemoved = null; + } + // undo weather fix + if (this.weatherFixBackupClass) { + DateMenuBox.style_class = this.weatherFixBackupClass; + this.weatherFixBackupClass = null; + } + } +}; diff --git a/features/dndQuickToggle.js b/features/dndQuickToggle.js index f54243d..a0b2d56 100644 --- a/features/dndQuickToggle.js +++ b/features/dndQuickToggle.js @@ -1,55 +1,54 @@ -const ExtensionUtils = imports.misc.extensionUtils -const Me = ExtensionUtils.getCurrentExtension() +const ExtensionUtils = imports.misc.extensionUtils; +const Me = ExtensionUtils.getCurrentExtension(); -const featureReloader = Me.imports.libs.featureReloader -const { QuickSettings } = Me.imports.libs.gnome -const { Indicator } = Me.imports.libs.dndQuickToogleHandler -const { DateMenu } = Me.imports.libs.gnome +const featureReloader = Me.imports.libs.featureReloader; +const { QuickSettings } = Me.imports.libs.gnome; +const { Indicator } = Me.imports.libs.dndQuickToggleHandler; +const { DateMenu } = Me.imports.libs.gnome; const { Gio, GObject } = imports.gi; - var dndQuickToggleFeature = class { - load() { - // setup reloader - featureReloader.enableWithSettingKeys(this,[ - "add-dnd-quick-toggle-enabled" - ]) + load() { + // setup reloader + featureReloader.enableWithSettingKeys(this, [ + "add-dnd-quick-toggle-enabled", + ]); - // check is feature enabled - if (!this.settings.get_boolean("add-dnd-quick-toggle-enabled")) return + // check is feature enabled + if (!this.settings.get_boolean("add-dnd-quick-toggle-enabled")) return; - // Add DND Quick Toggle - this.dndToggle = new Indicator() - QuickSettings._indicators.add_child(this.dndToggle) - QuickSettings._addItems(this.dndToggle.quickSettingsItems) - - //remove DND button from datemenu - this.datemenu_dnd = DateMenu.last_child.last_child - this.datemenu_dnd.hide() - this.datemenu_dnd_connection = this.datemenu_dnd.connect("show", () => { this.datemenu_dnd.hide() }) - - } + // Add DND Quick Toggle + this.dndToggle = new Indicator(); + QuickSettings._indicators.add_child(this.dndToggle); + QuickSettings._addItems(this.dndToggle.quickSettingsItems); - unload() { - // disable feature reloader - featureReloader.disable(this) - //put back the button to the datemenu - this.datemenu_dnd.disconnect(this.datemenu_dnd_connection) - this.datemenu_dnd_connection = null; - const _settings = new Gio.Settings({ - schema_id: 'org.gnome.desktop.notifications', - }); - if (!_settings.get_boolean('show-banners')){ - this.datemenu_dnd.show(); - } - // Remove DND Quick Toggle - if (this.dndToggle) { - const dndQSItems = this.dndToggle.quickSettingsItems[0] - dndQSItems.get_parent().remove_child(dndQSItems) - this.dndToggle.get_parent().remove_child(this.dndToggle) - this.dndToggle.destroy() - this.dndToggle = null - } - } -} + //remove DND button from datemenu + this.datemenu_dnd = DateMenu.last_child.last_child; + this.datemenu_dnd.hide(); + this.datemenu_dnd_connection = this.datemenu_dnd.connect("show", () => { + this.datemenu_dnd.hide(); + }); + } + unload() { + // disable feature reloader + featureReloader.disable(this); + //put back the button to the datemenu + this.datemenu_dnd.disconnect(this.datemenu_dnd_connection); + this.datemenu_dnd_connection = null; + const _settings = new Gio.Settings({ + schema_id: "org.gnome.desktop.notifications", + }); + if (!_settings.get_boolean("show-banners")) { + this.datemenu_dnd.show(); + } + // Remove DND Quick Toggle + if (this.dndToggle) { + const dndQSItems = this.dndToggle.quickSettingsItems[0]; + dndQSItems.get_parent().remove_child(dndQSItems); + this.dndToggle.get_parent().remove_child(this.dndToggle); + this.dndToggle.destroy(); + this.dndToggle = null; + } + } +}; diff --git a/libs/dndQuickToggleHandler.js b/libs/dndQuickToggleHandler.js new file mode 100644 index 0000000..5f98c17 --- /dev/null +++ b/libs/dndQuickToggleHandler.js @@ -0,0 +1,78 @@ +const { Gio, GObject } = imports.gi; +const { QuickToggle, SystemIndicator } = imports.ui.quickSettings; +const { St } = imports.gi; + +const DndQuickToggle = GObject.registerClass( + class DndQuickToggle extends QuickToggle { + _init() { + super._init({ + title: "Do Not Disturb", + iconName: "notifications-disabled-symbolic", + }); + + this.label = "Do Not Disturb"; + + this._settings = new Gio.Settings({ + schema_id: "org.gnome.desktop.notifications", + }); + + this._changedId = this._settings.connect("changed::show-banners", () => + this._sync() + ); + + this.connectObject( + "destroy", + () => this._settings.run_dispose(), + "clicked", + () => this._toggleMode(), + this + ); + + this._sync(); + } + + _toggleMode() { + this._settings.set_boolean( + "show-banners", + !this._settings.get_boolean("show-banners") + ); + } + + _sync() { + const checked = !this._settings.get_boolean("show-banners"); + if (this.checked !== checked) this.set({ checked }); + } + } +); + +var Indicator = GObject.registerClass( + class Indicator extends SystemIndicator { + _init() { + super._init(); + + this._indicator = this._addIndicator(); + + this._indicator.icon_name = "notifications-disabled-symbolic"; + this.quickSettingsItems.push(new DndQuickToggle()); + + this._settings = new Gio.Settings({ + schema_id: "org.gnome.desktop.notifications", + }); + + this._changedId = this._settings.connect("changed::show-banners", () => + this._sync() + ); + + this._sync(); + } + + _sync() { + const checked = !this._settings.get_boolean("show-banners"); + if (checked) { + this._indicator.visible = true; + } else { + this._indicator.visible = false; + } + } + } +); diff --git a/libs/dndQuickToogleHandler.js b/libs/dndQuickToogleHandler.js deleted file mode 100644 index c09e305..0000000 --- a/libs/dndQuickToogleHandler.js +++ /dev/null @@ -1,72 +0,0 @@ -const { Gio, GObject } = imports.gi; -const { QuickToggle, SystemIndicator } = imports.ui.quickSettings; -const { St } = imports.gi - -const DndQuickToogle = GObject.registerClass( -class DndQuickToogle extends QuickToggle { - _init() { - super._init({ - label: _('Do Not Disturb'), - iconName: 'notifications-disabled-symbolic' - }); - - this._settings = new Gio.Settings({ - schema_id: 'org.gnome.desktop.notifications', - }); - - this._changedId = this._settings.connect('changed::show-banners', - () => this._sync()); - - this.connectObject( - 'destroy', () => this._settings.run_dispose(), - 'clicked', () => this._toggleMode(), - this); - - this._sync(); - } - - _toggleMode() { - this._settings.set_boolean('show-banners', - !this._settings.get_boolean('show-banners')); - } - - _sync() { - const checked = !this._settings.get_boolean('show-banners'); - if (this.checked !== checked) - this.set({checked}); - } -}); - -var Indicator = GObject.registerClass( -class Indicator extends SystemIndicator { - _init() { - super._init(); - - this._indicator = this._addIndicator(); - - this._indicator.icon_name = 'notifications-disabled-symbolic' - this.quickSettingsItems.push(new DndQuickToogle()); - - this._settings = new Gio.Settings({ - schema_id: 'org.gnome.desktop.notifications', - }); - - this._changedId = this._settings.connect('changed::show-banners', - () => this._sync()); - - this._sync(); - } - - _sync() { - const checked = !this._settings.get_boolean('show-banners'); - if (checked){ - this._indicator.visible = true; - } - else{ - this._indicator.visible = false; - } - - } - - -}); diff --git a/metadata.json b/metadata.json index 0045034..c36bcd9 100644 --- a/metadata.json +++ b/metadata.json @@ -2,9 +2,7 @@ "description": "Let's tweak gnome 43's quick settings! You can add Media Controls, Notifications, Volume Mixer on quick settings and remove useless buttons!", "name": "Quick Settings Tweaker", "url": "https://github.com/qwreey75/quick-settings-tweaks", - "shell-version": [ - "43" - ], + "shell-version": ["43", "44"], "uuid": "quick-settings-tweaks@qwreey", "settings-schema": "org.gnome.shell.extensions.quick-settings-tweaks", "gettext-domain": "quick-settings-tweaks" From 59501540877ee03137b5f78e6b7e2aee2b7f6815 Mon Sep 17 00:00:00 2001 From: Kieran Gordon Date: Mon, 24 Apr 2023 22:43:46 +0100 Subject: [PATCH 05/33] Position DND button above background apps menu --- features/dndQuickToggle.js | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/features/dndQuickToggle.js b/features/dndQuickToggle.js index a0b2d56..6ea8ae7 100644 --- a/features/dndQuickToggle.js +++ b/features/dndQuickToggle.js @@ -1,6 +1,7 @@ const ExtensionUtils = imports.misc.extensionUtils; const Me = ExtensionUtils.getCurrentExtension(); +const QuickSettingsMenu = imports.ui.main.panel.statusArea.quickSettings; const featureReloader = Me.imports.libs.featureReloader; const { QuickSettings } = Me.imports.libs.gnome; const { Indicator } = Me.imports.libs.dndQuickToggleHandler; @@ -22,6 +23,23 @@ var dndQuickToggleFeature = class { QuickSettings._indicators.add_child(this.dndToggle); QuickSettings._addItems(this.dndToggle.quickSettingsItems); + // This is a bit of a hack, but it works for now. I took this from the + // gjs guide on how to position items above the background apps menu. + function addQuickSettingsItems(items) { + // Add the items with the built-in function + QuickSettingsMenu._addItems(items); + + // Ensure the tile(s) are above the background apps menu + for (const item of items) { + QuickSettingsMenu.menu._grid.set_child_below_sibling( + item, + QuickSettingsMenu._backgroundApps.quickSettingsItems[0] + ); + } + } + + addQuickSettingsItems(this.dndToggle.quickSettingsItems); + //remove DND button from datemenu this.datemenu_dnd = DateMenu.last_child.last_child; this.datemenu_dnd.hide(); From 1062fc1bf0f4e58a6cf8eb57c1e76946f6358f16 Mon Sep 17 00:00:00 2001 From: Kieran Gordon Date: Mon, 24 Apr 2023 23:03:28 +0100 Subject: [PATCH 06/33] Update metadata.json and Makefile to reflect fork --- Makefile | 2 +- metadata.json | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/Makefile b/Makefile index dd494d8..fdcfc55 100644 --- a/Makefile +++ b/Makefile @@ -12,7 +12,7 @@ build: install: build gnome-extensions install\ - dist/quick-settings-tweaks@qwreey.shell-extension.zip\ + dist/quick-settings-tweaks@kgdn.shell-extension.zip\ --force dev: install diff --git a/metadata.json b/metadata.json index c36bcd9..68ea265 100644 --- a/metadata.json +++ b/metadata.json @@ -1,9 +1,9 @@ { - "description": "Let's tweak gnome 43's quick settings! You can add Media Controls, Notifications, Volume Mixer on quick settings and remove useless buttons!", - "name": "Quick Settings Tweaker", - "url": "https://github.com/qwreey75/quick-settings-tweaks", + "description": "This is a fork of Quick Settings Tweaker by qwreey75. The original extension can be found here: https://extensions.gnome.org/extension/5446/quick-settings-tweaker/.\n\nLet's tweak gnome 43's quick settings! You can add Media Controls, Notifications, Volume Mixer on quick settings and remove useless buttons!", + "name": "Quick Settings Retweaked", + "url": "https://github.com/kgdn/quick-settings-tweaks", "shell-version": ["43", "44"], - "uuid": "quick-settings-tweaks@qwreey", + "uuid": "quick-settings-tweaks@kgdn", "settings-schema": "org.gnome.shell.extensions.quick-settings-tweaks", "gettext-domain": "quick-settings-tweaks" } From d883a239bd02e9c997f8453ba8c5c63de1fe7478 Mon Sep 17 00:00:00 2001 From: Kieran Gordon Date: Mon, 24 Apr 2023 23:19:41 +0100 Subject: [PATCH 07/33] Update description --- metadata.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/metadata.json b/metadata.json index 68ea265..7cde722 100644 --- a/metadata.json +++ b/metadata.json @@ -1,5 +1,5 @@ { - "description": "This is a fork of Quick Settings Tweaker by qwreey75. The original extension can be found here: https://extensions.gnome.org/extension/5446/quick-settings-tweaker/.\n\nLet's tweak gnome 43's quick settings! You can add Media Controls, Notifications, Volume Mixer on quick settings and remove useless buttons!", + "description": "This is a fork of Quick Settings Tweaker by qwreey75, with GNOME 44 support in mind. The original extension can be found here: https://extensions.gnome.org/extension/5446/quick-settings-tweaker/.\n\nLet's tweak gnome 43's quick settings! You can add Media Controls, Notifications, Volume Mixer on quick settings and remove useless buttons!", "name": "Quick Settings Retweaked", "url": "https://github.com/kgdn/quick-settings-tweaks", "shell-version": ["43", "44"], From 12fa65b1f50036904e6a292be48590f6677b5471 Mon Sep 17 00:00:00 2001 From: Kieran Gordon Date: Wed, 26 Apr 2023 11:56:52 +0100 Subject: [PATCH 08/33] Revert changes to new fork --- Makefile | 2 +- metadata.json | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/Makefile b/Makefile index fdcfc55..dd494d8 100644 --- a/Makefile +++ b/Makefile @@ -12,7 +12,7 @@ build: install: build gnome-extensions install\ - dist/quick-settings-tweaks@kgdn.shell-extension.zip\ + dist/quick-settings-tweaks@qwreey.shell-extension.zip\ --force dev: install diff --git a/metadata.json b/metadata.json index 7cde722..c36bcd9 100644 --- a/metadata.json +++ b/metadata.json @@ -1,9 +1,9 @@ { - "description": "This is a fork of Quick Settings Tweaker by qwreey75, with GNOME 44 support in mind. The original extension can be found here: https://extensions.gnome.org/extension/5446/quick-settings-tweaker/.\n\nLet's tweak gnome 43's quick settings! You can add Media Controls, Notifications, Volume Mixer on quick settings and remove useless buttons!", - "name": "Quick Settings Retweaked", - "url": "https://github.com/kgdn/quick-settings-tweaks", + "description": "Let's tweak gnome 43's quick settings! You can add Media Controls, Notifications, Volume Mixer on quick settings and remove useless buttons!", + "name": "Quick Settings Tweaker", + "url": "https://github.com/qwreey75/quick-settings-tweaks", "shell-version": ["43", "44"], - "uuid": "quick-settings-tweaks@kgdn", + "uuid": "quick-settings-tweaks@qwreey", "settings-schema": "org.gnome.shell.extensions.quick-settings-tweaks", "gettext-domain": "quick-settings-tweaks" } From ecab982271f43fdd88ed478e3ee1ed595ed7f795 Mon Sep 17 00:00:00 2001 From: Rayzeq Date: Thu, 27 Apr 2023 16:10:14 +0200 Subject: [PATCH 09/33] Keep a reference to inputStreamSlider --- features/inputOutput.js | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/features/inputOutput.js b/features/inputOutput.js index d8115b2..f17243c 100644 --- a/features/inputOutput.js +++ b/features/inputOutput.js @@ -17,6 +17,7 @@ var inputOutputFeature = class { "input-always-show" ]) + this._inputStreamSlider = this._getInputStreamSlider() this._setupOutputChangedListener() this._setupInputChangedListener() this._setupInputVisibilityObserver() @@ -34,9 +35,10 @@ var inputOutputFeature = class { Volume.getMixerControl().disconnect(this._inputListener) this._inputListener = null - this._getInputStreamSlider().disconnect(this._inputVisibilityListener) + this._inputStreamSlider.disconnect(this._inputVisibilityListener) this._inputVisibilityListener = null - this._getInputStreamSlider().visible = this._getInputStreamSlider()._shouldBeVisible() + this._inputStreamSlider.visible = this._inputStreamSlider._shouldBeVisible() + this._inputStreamSlider = null } // =========================================== Ouput =========================================== @@ -78,7 +80,7 @@ var inputOutputFeature = class { addChildWithIndex(QuickSettingsGrid, this.inputLabel, this._getInputStreamSliderIndex() - 1) this._spanTwoColumns(this.inputLabel) this._setInputLabelVisibility() - this.inputLabel.text = this._findActiveDevice(this._getInputStreamSlider()) + this.inputLabel.text = this._findActiveDevice(this._inputStreamSlider) } _onInputDeviceChanged(deviceId) { @@ -96,7 +98,7 @@ var inputOutputFeature = class { // =========================================== Input Visbility =========================================== _setupInputVisibilityObserver() { - this._inputVisibilityListener = this._getInputStreamSlider().connect("notify::visible", () => this._onInputStreamSliderSynced()) + this._inputVisibilityListener = this._inputStreamSlider.connect("notify::visible", () => this._onInputStreamSliderSynced()) this._onInputStreamSliderSynced() } @@ -106,11 +108,11 @@ var inputOutputFeature = class { } _setInputStreamSliderVisibility() { - this._getInputStreamSlider().visible = this._getInputStreamSlider()._shouldBeVisible() || this.settings.get_boolean("input-always-show") + this._inputStreamSlider.visible = this._inputStreamSlider._shouldBeVisible() || this.settings.get_boolean("input-always-show") } _setInputLabelVisibility() { - this.inputLabel.visible = this._getInputStreamSlider().visible && this.settings.get_boolean("input-show-selected") + this.inputLabel.visible = this._inputStreamSlider.visible && this.settings.get_boolean("input-show-selected") } From cfb7a18fd2c509c5e1748f980acc6b37fd73a4c7 Mon Sep 17 00:00:00 2001 From: Rayzeq Date: Thu, 27 Apr 2023 16:41:00 +0200 Subject: [PATCH 10/33] Do not emit errors if volume sliders are not here --- features/inputOutput.js | 38 +++++++++++++++++++++++--------------- 1 file changed, 23 insertions(+), 15 deletions(-) diff --git a/features/inputOutput.js b/features/inputOutput.js index f17243c..0506cb4 100644 --- a/features/inputOutput.js +++ b/features/inputOutput.js @@ -18,27 +18,35 @@ var inputOutputFeature = class { ]) this._inputStreamSlider = this._getInputStreamSlider() - this._setupOutputChangedListener() - this._setupInputChangedListener() - this._setupInputVisibilityObserver() + if (this._inputStreamSlider) { + this._setupInputChangedListener() + this._setupInputVisibilityObserver() + } + this._outputStreamSlider = this._getOutputStreamSlider() + if (this._outputStreamSlider) { + this._setupOutputChangedListener() + } } unload() { // disable feature reloader featureReloader.disable(this) - this._detachOutputLabel() - Volume.getMixerControl().disconnect(this._outputListener) - this._outputListener = null - - this._detachInputLabel() - Volume.getMixerControl().disconnect(this._inputListener) - this._inputListener = null + if (this._inputStreamSlider) { + this._detachInputLabel() + Volume.getMixerControl().disconnect(this._inputListener) + this._inputListener = null - this._inputStreamSlider.disconnect(this._inputVisibilityListener) - this._inputVisibilityListener = null - this._inputStreamSlider.visible = this._inputStreamSlider._shouldBeVisible() - this._inputStreamSlider = null + this._inputStreamSlider.disconnect(this._inputVisibilityListener) + this._inputVisibilityListener = null + this._inputStreamSlider.visible = this._inputStreamSlider._shouldBeVisible() + this._inputStreamSlider = null + } + if (this._outputStreamSlider) { + this._detachOutputLabel() + Volume.getMixerControl().disconnect(this._outputListener) + this._outputListener = null + } } // =========================================== Ouput =========================================== @@ -58,7 +66,7 @@ var inputOutputFeature = class { addChildWithIndex(QuickSettingsGrid, this.outputLabel, this._getOutputStreamSliderIndex() - 1); this._spanTwoColumns(this.outputLabel) this.outputLabel.visible = this.settings.get_boolean("output-show-selected") - this.outputLabel.text = this._findActiveDevice(this._getOutputStreamSlider()) + this.outputLabel.text = this._findActiveDevice(this._outputStreamSlider) } _detachOutputLabel() { From 1adc9d920d010ecfabef0d0fee66bc8eda4fe0c7 Mon Sep 17 00:00:00 2001 From: Rayzeq Date: Thu, 27 Apr 2023 17:02:20 +0200 Subject: [PATCH 11/33] Fix error on disable because of `datemenu_dnd` --- features/dndQuickToggle.js | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/features/dndQuickToggle.js b/features/dndQuickToggle.js index 6ea8ae7..79a5a8a 100644 --- a/features/dndQuickToggle.js +++ b/features/dndQuickToggle.js @@ -15,6 +15,7 @@ var dndQuickToggleFeature = class { "add-dnd-quick-toggle-enabled", ]); + this.datemenu_dnd = null; // check is feature enabled if (!this.settings.get_boolean("add-dnd-quick-toggle-enabled")) return; @@ -51,6 +52,9 @@ var dndQuickToggleFeature = class { unload() { // disable feature reloader featureReloader.disable(this); + + if (this.datemenu_dnd == null) return; + //put back the button to the datemenu this.datemenu_dnd.disconnect(this.datemenu_dnd_connection); this.datemenu_dnd_connection = null; From ddc39da395dbe88def51d786327677200f45f538 Mon Sep 17 00:00:00 2001 From: Rayzeq Date: Thu, 27 Apr 2023 17:03:21 +0200 Subject: [PATCH 12/33] Do not resize panels when notifications are separated --- stylesheet.css | 4 ---- 1 file changed, 4 deletions(-) diff --git a/stylesheet.css b/stylesheet.css index 4b22aa9..cd7ecd0 100644 --- a/stylesheet.css +++ b/stylesheet.css @@ -102,10 +102,6 @@ } .QSTWEAKS-notifications-separated { padding: 16px 4px 16px 16px; - margin: 6px 12px 6px 12px; - } - .QSTWEAKS-quick-settings-separated { - margin: 6px 12px 6px 12px; } .QSTWEAKS-notifications-separated .QSTWEAKS-notifications-no-notifications-placeholder { margin: 16px 0px; From 820477bdeb1e1e349c0de4b5061024acc22cfdcb Mon Sep 17 00:00:00 2001 From: Rayzeq Date: Thu, 27 Apr 2023 17:31:29 +0200 Subject: [PATCH 13/33] Null out `this.features` in disable --- extension.js | 1 + 1 file changed, 1 insertion(+) diff --git a/extension.js b/extension.js index b8d8ed1..934260c 100644 --- a/extension.js +++ b/extension.js @@ -28,6 +28,7 @@ class Extension { feature.unload() feature.settings = null } + this.features = null; logger("Diabled") } From b124ae317b197c886f826fbe0bf6c6369f8940c4 Mon Sep 17 00:00:00 2001 From: Rayzeq Date: Sat, 29 Apr 2023 01:07:31 +0200 Subject: [PATCH 14/33] Bugfixes --- extension.js | 8 +++++++- features/inputOutput.js | 2 +- 2 files changed, 8 insertions(+), 2 deletions(-) diff --git a/extension.js b/extension.js index 934260c..ddfde0e 100644 --- a/extension.js +++ b/extension.js @@ -28,7 +28,13 @@ class Extension { feature.unload() feature.settings = null } - this.features = null; + // This cause a crash when disabling the extension. + // Just Perfection said it was necessary to put this for the extension to pass review + // but since `this.features` is created in the constructor that's not a good idea. + // Moreover, I don't think it's necessary because each feature is cleaned up anyway, + // the only remaining things are their object, which are never re-created so it don't + // cause a memoty leak. + //this.features = null; logger("Diabled") } diff --git a/features/inputOutput.js b/features/inputOutput.js index 0506cb4..ae1d6f7 100644 --- a/features/inputOutput.js +++ b/features/inputOutput.js @@ -79,7 +79,7 @@ var inputOutputFeature = class { // =========================================== Input =========================================== _setupInputChangedListener() { this._attachInputLabel() - this._outputListener = Volume.getMixerControl().connect('active-input-update', (c, id) => this._onInputDeviceChanged(id)) + this._inputListener = Volume.getMixerControl().connect('active-input-update', (c, id) => this._onInputDeviceChanged(id)) } _attachInputLabel() { From 070c3fc499a369ec84b607842ac7ddf5f5f6373c Mon Sep 17 00:00:00 2001 From: Rayzeq Date: Sat, 29 Apr 2023 01:07:50 +0200 Subject: [PATCH 15/33] Avoid doing unnecessary work --- features/inputOutput.js | 22 +++++++++++++++------- 1 file changed, 15 insertions(+), 7 deletions(-) diff --git a/features/inputOutput.js b/features/inputOutput.js index ae1d6f7..2470e9b 100644 --- a/features/inputOutput.js +++ b/features/inputOutput.js @@ -17,13 +17,19 @@ var inputOutputFeature = class { "input-always-show" ]) + this._outputListener = null + this._inputListener = null + this._inputVisibilityListener = null + this._inputStreamSlider = this._getInputStreamSlider() - if (this._inputStreamSlider) { + if (this._inputStreamSlider && this.settings.get_boolean("input-show-selected")) { this._setupInputChangedListener() + } + if (this._inputStreamSlider && this.settings.get_boolean("input-always-show")) { this._setupInputVisibilityObserver() } this._outputStreamSlider = this._getOutputStreamSlider() - if (this._outputStreamSlider) { + if (this._outputStreamSlider && this.settings.get_boolean("output-show-selected")) { this._setupOutputChangedListener() } } @@ -32,17 +38,17 @@ var inputOutputFeature = class { // disable feature reloader featureReloader.disable(this) - if (this._inputStreamSlider) { + if (this._inputStreamSlider && this._inputListener) { this._detachInputLabel() Volume.getMixerControl().disconnect(this._inputListener) this._inputListener = null - + } + if (this._inputStreamSlider && this._inputVisibilityListener) { this._inputStreamSlider.disconnect(this._inputVisibilityListener) this._inputVisibilityListener = null this._inputStreamSlider.visible = this._inputStreamSlider._shouldBeVisible() - this._inputStreamSlider = null } - if (this._outputStreamSlider) { + if (this._outputStreamSlider && this._outputListener) { this._detachOutputLabel() Volume.getMixerControl().disconnect(this._outputListener) this._outputListener = null @@ -112,7 +118,9 @@ var inputOutputFeature = class { _onInputStreamSliderSynced() { this._setInputStreamSliderVisibility() - this._setInputLabelVisibility() + if (this._inputListener) { + this._setInputLabelVisibility() + } } _setInputStreamSliderVisibility() { From cfadc2150a7e6afec0ac6617ad3966a274f1fdc7 Mon Sep 17 00:00:00 2001 From: Qwreey Date: Wed, 26 Apr 2023 19:44:23 +0900 Subject: [PATCH 16/33] Update dndQuickToggleHandler.js: Add translate support --- libs/dndQuickToggleHandler.js | 22 +++---- libs/dndQuickToogleHandler.js | 110 ---------------------------------- 2 files changed, 12 insertions(+), 120 deletions(-) delete mode 100644 libs/dndQuickToogleHandler.js diff --git a/libs/dndQuickToggleHandler.js b/libs/dndQuickToggleHandler.js index 5f98c17..81c2de3 100644 --- a/libs/dndQuickToggleHandler.js +++ b/libs/dndQuickToggleHandler.js @@ -6,31 +6,32 @@ const DndQuickToggle = GObject.registerClass( class DndQuickToggle extends QuickToggle { _init() { super._init({ - title: "Do Not Disturb", + title: _('Do Not Disturb'), iconName: "notifications-disabled-symbolic", }); - this.label = "Do Not Disturb"; - + // this.label = "Do Not Disturb"; this._settings = new Gio.Settings({ schema_id: "org.gnome.desktop.notifications", }); - this._changedId = this._settings.connect("changed::show-banners", () => - this._sync() - ); + this._changedId = this._settings.connect("changed::show-banners", this._sync.bind(this)); this.connectObject( - "destroy", - () => this._settings.run_dispose(), - "clicked", - () => this._toggleMode(), + // Destroy event + "destroy", this._settings.run_dispose.bind(this._settings), + + // Clicked event + "clicked", this._toggleMode.bind(this), + this ); + // Fetch DND status once this._sync(); } + // Toggle DND _toggleMode() { this._settings.set_boolean( "show-banners", @@ -38,6 +39,7 @@ const DndQuickToggle = GObject.registerClass( ); } + // Sync DND status _sync() { const checked = !this._settings.get_boolean("show-banners"); if (this.checked !== checked) this.set({ checked }); diff --git a/libs/dndQuickToogleHandler.js b/libs/dndQuickToogleHandler.js deleted file mode 100644 index 49a50df..0000000 --- a/libs/dndQuickToogleHandler.js +++ /dev/null @@ -1,110 +0,0 @@ -const { Gio, GObject } = imports.gi; -const { QuickToggle, SystemIndicator } = imports.ui.quickSettings; -const { St } = imports.gi -const Main = imports.ui.main; - -const DndQuickToogle = GObject.registerClass( -class DndQuickToogle extends QuickToggle { - _init() { - super._init({ - label: _('Do Not Disturb'), - iconName: 'notifications-disabled-symbolic' - }); - - this._settings = new Gio.Settings({ - schema_id: 'org.gnome.desktop.notifications', - }); - - this._changedId = this._settings.connect('changed::show-banners', - () => this._sync()); - - this.connectObject( - 'destroy', () => this._settings.run_dispose(), - 'clicked', () => this._toggleMode(), - this); - - this._sync(); - } - - _toggleMode() { - this._settings.set_boolean('show-banners', - !this._settings.get_boolean('show-banners')); - } - - _sync() { - const checked = !this._settings.get_boolean('show-banners'); - if (this.checked !== checked) - this.set({checked}); - } -}); - -var Indicator = GObject.registerClass( -class Indicator extends SystemIndicator { - _init() { - super._init(); - - this._sources = []; - this._count = 0; - - - this._indicator = this._addIndicator(); - - this._indicator.icon_name = 'notifications-disabled-symbolic' - this.quickSettingsItems.push(new DndQuickToogle()); - - this._settings = new Gio.Settings({ - schema_id: 'org.gnome.desktop.notifications', - }); - - this._settings.connect('changed::show-banners', this._sync.bind(this)); - - Main.messageTray.connect('source-added', this._onSourceAdded.bind(this)); - Main.messageTray.connect('source-removed', this._onSourceRemoved.bind(this)); - Main.messageTray.connect('queue-changed', this._updateCount.bind(this)); - - - let sources = Main.messageTray.getSources(); - sources.forEach(source => this._onSourceAdded(null, source)); - - - this._sync(); - - this.connect('destroy', () => { - this._settings.run_dispose(); - this._settings = null; - }); - - } - - - _onSourceAdded(tray, source) { - source.connect('notify::count', this._updateCount.bind(this)); - this._sources.push(source); - this._updateCount(); - } - - _onSourceRemoved(tray, source) { - this._sources.splice(this._sources.indexOf(source), 1); - this._updateCount(); - } - - _updateCount() { - let count = 0; - this._sources.forEach(source => (count += source.unseenCount)); - this._count = count - Main.messageTray.queueCount; - this._sync(); - } - - - _sync() { - let doNotDisturb = !this._settings.get_boolean('show-banners'); - - this._indicator.icon_name = doNotDisturb - ? 'notifications-disabled-symbolic' - : 'message-indicator-symbolic'; - this._indicator.visible = doNotDisturb || this._count > 0; - - } - - -}); From 7833b0a098e790ae77f659df55e3c805fea36953 Mon Sep 17 00:00:00 2001 From: Qwreey Date: Fri, 28 Apr 2023 15:29:59 +0900 Subject: [PATCH 17/33] notificationHandler.js: Move updateNoNotifications function into method --- libs/notificationHandler.js | 188 ++++++++++++++++++------------------ 1 file changed, 95 insertions(+), 93 deletions(-) diff --git a/libs/notificationHandler.js b/libs/notificationHandler.js index 06ea52c..fde4509 100644 --- a/libs/notificationHandler.js +++ b/libs/notificationHandler.js @@ -5,107 +5,109 @@ const ExtensionUtils = imports.misc.extensionUtils const Me = ExtensionUtils.getCurrentExtension() var Notifications = GObject.registerClass( - class Notifications extends St.BoxLayout{ - _init(options){ - let useNativeControls = options.useNativeControls - let hideWhenNoNotifications = options.hideWhenNoNotifications +class Notifications extends St.BoxLayout{ + _init(options){ + // options { + // hideWhenNoNotifications + // useNativeControls + // } + super._init({ + vertical: true, + }) + this.options = options + + let datemenu = new imports.ui.dateMenu.DateMenuButton() + let messageList = datemenu._messageList + this.notificationList = messageList._notificationSection + this.nativeDndSwitch = messageList._dndButton + this.nativeClearButton = messageList._clearButton + + // media controls + this.mediaSection = messageList._mediaSection + this.mediaSection.get_parent().remove_child(this.mediaSection) + + // notification list scroll + this.list = messageList._scrollView + this.list.get_parent().remove_child(this.list) + this.list.overlay_scrollbars + + // header / title + let headerBox = new St.BoxLayout({ style_class: "QSTWEAKS-notifications-header" }) + this.add_child(headerBox) + this.add_child(this.list) + let titleLabel = new St.Label({ + text: ExtensionUtils.gettext('Notifications'), + style_class: "QSTWEAKS-notifications-title", + y_align: Clutter.ActorAlign.CENTER, + x_align: Clutter.ActorAlign.START, + x_expand: true + }) + headerBox.add_child(titleLabel) + + // no notifications text + let noNotiBox = new St.BoxLayout({x_align: Clutter.ActorAlign.CENTER}) + noNotiBox.style_class = "QSTWEAKS-notifications-no-notifications-box" + const noNotiPlaceholder = new NoNotifPlaceholder() + noNotiBox.add_child(noNotiPlaceholder) + noNotiBox.hide() + this.add_child(noNotiBox) + this.noNotiBox = noNotiBox + + // clear button / dnd switch + if (options.useNativeControls) { + // if use native controls + { + let parent = this.nativeClearButton.get_parent() + parent.remove_child(this.nativeClearButton) + parent.remove_child(this.nativeDndSwitch) + this.nativeDndText = parent.first_child + parent.remove_child(this.nativeDndText) + } - super._init({ - vertical: true, + let nativeControlBox = new St.BoxLayout() + nativeControlBox.add_child(this.nativeDndText) + nativeControlBox.add_child(this.nativeDndSwitch) + nativeControlBox.add_child(this.nativeClearButton) + this.nativeControlBox = nativeControlBox + this.add_child(nativeControlBox) + } else { + this.clearButton = new ClearNotificationsButton() + this.clearButton.connect("clicked",()=>{ + messageList._sectionList.get_children().forEach(s => s.clear()) }) + headerBox.add_child(this.clearButton) + } - let datemenu = new imports.ui.dateMenu.DateMenuButton() - let messageList = datemenu._messageList - this.notificationList = messageList._notificationSection - this.nativeDndSwitch = messageList._dndButton - this.nativeClearButton = messageList._clearButton - - // media controls - this.mediaSection = messageList._mediaSection - this.mediaSection.get_parent().remove_child(this.mediaSection) - - // notification list scroll - this.list = messageList._scrollView - this.list.get_parent().remove_child(this.list) - - // header / title - let headerBox = new St.BoxLayout({ style_class: "QSTWEAKS-notifications-header" }) - this.add_child(headerBox) - this.add_child(this.list) - let titleLabel = new St.Label({ - text: ExtensionUtils.gettext('Notifications'), - style_class: "QSTWEAKS-notifications-title", - y_align: Clutter.ActorAlign.CENTER, - x_align: Clutter.ActorAlign.START, - x_expand: true - }) - headerBox.add_child(titleLabel) - - // no notifications text - let noNotiBox = new St.BoxLayout({x_align: Clutter.ActorAlign.CENTER}) - noNotiBox.style_class = "QSTWEAKS-notifications-no-notifications-box" - const noNotiPlaceholder = new NoNotifPlaceholder() - noNotiBox.add_child(noNotiPlaceholder) - noNotiBox.hide() - this.add_child(noNotiBox) - - // clear button / dnd switch - if (useNativeControls) { - // if use native controls - { - let parent = this.nativeClearButton.get_parent() - parent.remove_child(this.nativeClearButton) - parent.remove_child(this.nativeDndSwitch) - this.nativeDndText = parent.first_child - parent.remove_child(this.nativeDndText) - } - - let nativeControlBox = new St.BoxLayout() - nativeControlBox.add_child(this.nativeDndText) - nativeControlBox.add_child(this.nativeDndSwitch) - nativeControlBox.add_child(this.nativeClearButton) - this.nativeControlBox = nativeControlBox - this.add_child(nativeControlBox) - } else { - this.clearButton = new ClearNotificationsButton() - this.clearButton.connect("clicked",()=>{ - messageList._sectionList.get_children().forEach(s => s.clear()) - }) - headerBox.add_child(this.clearButton) - } + // sync notifications + let stockNotifications = Main.panel.statusArea.dateMenu._messageList._notificationSection + let notifications = stockNotifications._messages + notifications.forEach(n => { + let notification = new Calendar.NotificationMessage(n.notification) + this.notificationList.addMessage(notification) + }) - // sync notifications - let stockNotifications = Main.panel.statusArea.dateMenu._messageList._notificationSection - let notifications = stockNotifications._messages - notifications.forEach(n => { - let notification = new Calendar.NotificationMessage(n.notification) - this.notificationList.addMessage(notification) - }) + // sync no-notification placeholder and clear button + this.nativeClearButton.connect('notify::reactive', this._updateNoNotifications.bind(this)) + this._updateNoNotifications() - // sync no-notification placeholder and clear button - const updateNoNotifications = ()=>{ - if (this.nativeClearButton.reactive) { - this.list.show() - noNotiBox.hide() - if (this.clearButton) this.clearButton.show() - if (hideWhenNoNotifications) this.show() - } else { - this.list.hide() - noNotiBox.show() - if (this.clearButton) this.clearButton.hide() - if (hideWhenNoNotifications) this.hide() - } - } - this.nativeClearButton.connect('notify::reactive', updateNoNotifications) - updateNoNotifications() + this.connect('destroy', datemenu.destroy.bind(datemenu)) + } - this.connect('destroy', () => { - datemenu.destroy() - datemenu = null - }) + // sync no-notification placeholder and clear button + _updateNoNotifications() { + if (this.nativeClearButton.reactive) { + this.list.show() + this.noNotiBox.hide() + if (this.clearButton) this.clearButton.show() + if (this.options. hideWhenNoNotifications) this.show() + } else { + this.list.hide() + this.noNotiBox.show() + if (this.clearButton) this.clearButton.hide() + if (this.options.hideWhenNoNotifications) this.hide() } } -) +}) const NoNotifPlaceholder = GObject.registerClass( class NoNotifPlaceholder extends St.BoxLayout { From 3bd7f6c915c458ad1a2f53b087c413408db085f0 Mon Sep 17 00:00:00 2001 From: Qwreey Date: Sat, 29 Apr 2023 09:19:51 +0900 Subject: [PATCH 18/33] Update makefile and rewrite notificationHandler.js --- Makefile | 2 +- libs/notificationHandler.js | 217 ++++++++++++++++++++---------------- 2 files changed, 122 insertions(+), 97 deletions(-) diff --git a/Makefile b/Makefile index dd494d8..45716ce 100644 --- a/Makefile +++ b/Makefile @@ -17,5 +17,5 @@ install: build dev: install ifeq ($(XDG_SESSION_TYPE),x11) - pkill gnome-shell & + busctl --user call org.gnome.Shell /org/gnome/Shell org.gnome.Shell Eval s 'Meta.restart("Restarting…", global.context)' endif diff --git a/libs/notificationHandler.js b/libs/notificationHandler.js index fde4509..468973d 100644 --- a/libs/notificationHandler.js +++ b/libs/notificationHandler.js @@ -4,20 +4,67 @@ const Calendar = imports.ui.calendar const ExtensionUtils = imports.misc.extensionUtils const Me = ExtensionUtils.getCurrentExtension() -var Notifications = GObject.registerClass( -class Notifications extends St.BoxLayout{ - _init(options){ - // options { - // hideWhenNoNotifications - // useNativeControls - // } +const NoNotifPlaceholder = GObject.registerClass( +class NoNotifPlaceholder extends St.BoxLayout { + _init() { super._init({ + style_class: 'QSTWEAKS-notifications-no-notifications-placeholder', vertical: true, + opacity: 60 }) - this.options = options - let datemenu = new imports.ui.dateMenu.DateMenuButton() - let messageList = datemenu._messageList + this._icon = new St.Icon({ + style_class: 'QSTWEAKS-notifications-no-notifications-placeholder-icon', + icon_name: 'no-notifications-symbolic' + }) + this.add_child(this._icon) + + this._label = new St.Label({ text: _('No Notifications') }) + this.add_child(this._label) + } +}) + +const ClearNotificationsButton = GObject.registerClass( +class ClearNotificationsButton extends St.Button { + _init() { + let container = new St.BoxLayout({ + x_expand: true, + y_expand: true, + }) + + super._init({ + style_class: 'QSTWEAKS-notifications-clear-button', + button_mask: St.ButtonMask.ONE, + child: container, + reactive: true, + can_focus: true, + y_align: Clutter.ActorAlign.CENTER, + }) + + this._icon = new St.Icon({ + style_class: 'QSTWEAKS-notifications-clear-button-icon', + icon_name: 'user-trash-symbolic', + icon_size: 12 + }) + container.add_child(this._icon) + + this._label = new St.Label({ + text: _('Clear') + }) + container.add_child(this._label) + } +}) + +var Notifications = GObject.registerClass( +class Notifications extends St.BoxLayout{ + + // prepare date menu items + _prepareDateMenu() { + // create gnome datemenu + this.datemenu = new imports.ui.dateMenu.DateMenuButton() + + // notifications + let messageList = this.datemenu._messageList this.notificationList = messageList._notificationSection this.nativeDndSwitch = messageList._dndButton this.nativeClearButton = messageList._clearButton @@ -29,12 +76,13 @@ class Notifications extends St.BoxLayout{ // notification list scroll this.list = messageList._scrollView this.list.get_parent().remove_child(this.list) - this.list.overlay_scrollbars + this.add_child(this.list) // mount + } + // Create 'Notifications' text and ClearButton + _createHeaderArea() { // header / title let headerBox = new St.BoxLayout({ style_class: "QSTWEAKS-notifications-header" }) - this.add_child(headerBox) - this.add_child(this.list) let titleLabel = new St.Label({ text: ExtensionUtils.gettext('Notifications'), style_class: "QSTWEAKS-notifications-title", @@ -44,53 +92,31 @@ class Notifications extends St.BoxLayout{ }) headerBox.add_child(titleLabel) - // no notifications text - let noNotiBox = new St.BoxLayout({x_align: Clutter.ActorAlign.CENTER}) - noNotiBox.style_class = "QSTWEAKS-notifications-no-notifications-box" - const noNotiPlaceholder = new NoNotifPlaceholder() - noNotiBox.add_child(noNotiPlaceholder) - noNotiBox.hide() - this.add_child(noNotiBox) - this.noNotiBox = noNotiBox - - // clear button / dnd switch - if (options.useNativeControls) { - // if use native controls - { - let parent = this.nativeClearButton.get_parent() - parent.remove_child(this.nativeClearButton) - parent.remove_child(this.nativeDndSwitch) - this.nativeDndText = parent.first_child - parent.remove_child(this.nativeDndText) - } - - let nativeControlBox = new St.BoxLayout() - nativeControlBox.add_child(this.nativeDndText) - nativeControlBox.add_child(this.nativeDndSwitch) - nativeControlBox.add_child(this.nativeClearButton) - this.nativeControlBox = nativeControlBox - this.add_child(nativeControlBox) - } else { - this.clearButton = new ClearNotificationsButton() - this.clearButton.connect("clicked",()=>{ - messageList._sectionList.get_children().forEach(s => s.clear()) + // clear button + if (!this.options.useNativeControls) { + let clearButton = this.clearButton = new ClearNotificationsButton() + clearButton.connect("clicked",()=>{ + this.messageList._sectionList.get_children().forEach(s => s.clear()) }) - headerBox.add_child(this.clearButton) + headerBox.add_child(clearButton) } - // sync notifications - let stockNotifications = Main.panel.statusArea.dateMenu._messageList._notificationSection - let notifications = stockNotifications._messages - notifications.forEach(n => { - let notification = new Calendar.NotificationMessage(n.notification) - this.notificationList.addMessage(notification) - }) + // mount + this.insert_child_at_index(headerBox,0) + } - // sync no-notification placeholder and clear button - this.nativeClearButton.connect('notify::reactive', this._updateNoNotifications.bind(this)) - this._updateNoNotifications() + // Create 'NoNotification' placeholder + _createNoNotificationArea() { + // container + let noNotiBox = this.noNotiBox = new St.BoxLayout({x_align: Clutter.ActorAlign.CENTER}) + noNotiBox.style_class = "QSTWEAKS-notifications-no-notifications-box" + noNotiBox.hide() - this.connect('destroy', datemenu.destroy.bind(datemenu)) + // no notifications text + noNotiBox.add_child(new NoNotifPlaceholder()) + + // mount + this.add_child(noNotiBox) } // sync no-notification placeholder and clear button @@ -99,7 +125,7 @@ class Notifications extends St.BoxLayout{ this.list.show() this.noNotiBox.hide() if (this.clearButton) this.clearButton.show() - if (this.options. hideWhenNoNotifications) this.show() + if (this.options.hideWhenNoNotifications) this.show() } else { this.list.hide() this.noNotiBox.show() @@ -107,55 +133,54 @@ class Notifications extends St.BoxLayout{ if (this.options.hideWhenNoNotifications) this.hide() } } -}) - -const NoNotifPlaceholder = GObject.registerClass( -class NoNotifPlaceholder extends St.BoxLayout { - _init() { - super._init({ - style_class: 'QSTWEAKS-notifications-no-notifications-placeholder', - vertical: true, - opacity: 60 - }) - this._icon = new St.Icon({ - style_class: 'QSTWEAKS-notifications-no-notifications-placeholder-icon', - icon_name: 'no-notifications-symbolic' + // Sync + _syncNotifications() { + // sync notifications from gnome stock notifications + Main.panel.statusArea.dateMenu._messageList._notificationSection._messages.forEach((notification)=>{ + // for (notification of Main.panel.statusArea.dateMenu._messageList._notificationSection._messages) { + // clone message + this.notificationList.addMessage(new Calendar.NotificationMessage(notification.notification)) }) - this.add_child(this._icon) - this._label = new St.Label({ text: _('No Notifications') }) - this.add_child(this._label) + // sync no-notification placeholder and clear button + this.nativeClearButton.connect('notify::reactive', this._updateNoNotifications.bind(this)) + this._updateNoNotifications() } -}) -const ClearNotificationsButton = GObject.registerClass( -class ClearNotificationsButton extends St.Button { - _init() { - let container = new St.BoxLayout({ - x_expand: true, - y_expand: true, - }) + _createNativeControls() { + // unmount dnd/clear/text from parent + { + let parent = this.nativeClearButton.get_parent() + parent.remove_child(this.nativeClearButton) + parent.remove_child(this.nativeDndSwitch) + parent.remove_child(this.nativeDndText = parent.first_child) + } + + // create container + let nativeControlBox = this.nativeControlBox = new St.BoxLayout() + nativeControlBox.add_child(this.nativeDndText) + nativeControlBox.add_child(this.nativeDndSwitch) + nativeControlBox.add_child(this.nativeClearButton) + this.add_child(nativeControlBox) + } + // options { + // hideWhenNoNotifications + // useNativeControls + // } + _init(options){ super._init({ - style_class: 'QSTWEAKS-notifications-clear-button', - button_mask: St.ButtonMask.ONE, - child: container, - reactive: true, - can_focus: true, - y_align: Clutter.ActorAlign.CENTER, + vertical: true, }) + this.options = options - this._icon = new St.Icon({ - style_class: 'QSTWEAKS-notifications-clear-button-icon', - icon_name: 'user-trash-symbolic', - icon_size: 12 - }) - container.add_child(this._icon) + this._prepareDateMenu() + this._createHeaderArea() + this._createNoNotificationArea() + this._syncNotifications() + if (options.useNativeControls) this._createNativeControls() // native clear/dnd - this._label = new St.Label({ - text: _('Clear') - }) - container.add_child(this._label) + this.connect('destroy', this.datemenu.destroy.bind(this.datemenu)) } }) From fdb1d9a9cd27cf17c36a27a5d03bc378f98c5b06 Mon Sep 17 00:00:00 2001 From: Qwreey Date: Sat, 29 Apr 2023 09:29:41 +0900 Subject: [PATCH 19/33] Remove timeout on extension.js for load immediately --- extension.js | 61 +++++++++++++++++++++------------------------------- 1 file changed, 25 insertions(+), 36 deletions(-) diff --git a/extension.js b/extension.js index ddfde0e..70ed0db 100644 --- a/extension.js +++ b/extension.js @@ -5,56 +5,45 @@ const { logger } = Me.imports.libs.utility const { GLib } = imports.gi class Extension { - constructor() { - logger("Init") - this.features = [ - new Features.dndQuickToggle.dndQuickToggleFeature(), - new Features.notifications.notificationsFeature(), - new Features.volumeMixer.volumeMixerFeature(), - new Features.dateMenu.dateMenuFeature(), - new Features.buttonRemover.buttonRemoverFeature(), - new Features.inputOutput.inputOutputFeature() - ] - } + constructor() {} disable() { logger("Unloading ...") - if (this.timeout) { - GLib.Source.remove(this.timeout) - this.timeout = null - } + // unload features for (const feature of this.features) { logger(`Unload feature '${feature.constructor.name}'`) feature.unload() feature.settings = null } - // This cause a crash when disabling the extension. - // Just Perfection said it was necessary to put this for the extension to pass review - // but since `this.features` is created in the constructor that's not a good idea. - // Moreover, I don't think it's necessary because each feature is cleaned up anyway, - // the only remaining things are their object, which are never re-created so it don't - // cause a memoty leak. - //this.features = null; - + this.features = null + logger("Diabled") } enable() { logger("Loading ...") - + + // load modules + this.features = [ + new Features.dndQuickToggle.dndQuickToggleFeature(), + new Features.notifications.notificationsFeature(), + new Features.volumeMixer.volumeMixerFeature(), + new Features.dateMenu.dateMenuFeature(), + new Features.buttonRemover.buttonRemoverFeature(), + new Features.inputOutput.inputOutputFeature() + ] + + // load settings let settings = ExtensionUtils.getSettings(Me.metadata['settings-schema']) ExtensionUtils.initTranslations(Me.metadata['gettext-domain']) - - // Add timeout for waitting other extensions such as GSConnect - // This is necessary behavior due to ordering qs panel - this.timeout = GLib.timeout_add(GLib.PRIORITY_DEFAULT, 400, () => { - for (const feature of this.features) { - logger(`Loading feature '${feature.constructor.name}'`) - feature.settings = settings - feature.load() - } - logger("Loaded") - return GLib.SOURCE_REMOVE - }) + + // load features + for (const feature of this.features) { + logger(`Loading feature '${feature.constructor.name}'`) + feature.settings = settings + feature.load() + } + + logger("Loaded") } } From 242b03eb68d946f7c8e8c2f247ed31b1cfcf69b3 Mon Sep 17 00:00:00 2001 From: Qwreey Date: Sat, 29 Apr 2023 09:33:52 +0900 Subject: [PATCH 20/33] Apply PR #78 --- libs/dndQuickToggleHandler.js | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/libs/dndQuickToggleHandler.js b/libs/dndQuickToggleHandler.js index 81c2de3..ec7e9ce 100644 --- a/libs/dndQuickToggleHandler.js +++ b/libs/dndQuickToggleHandler.js @@ -6,11 +6,10 @@ const DndQuickToggle = GObject.registerClass( class DndQuickToggle extends QuickToggle { _init() { super._init({ - title: _('Do Not Disturb'), + label: _('Do Not Disturb'), iconName: "notifications-disabled-symbolic", }); - // this.label = "Do Not Disturb"; this._settings = new Gio.Settings({ schema_id: "org.gnome.desktop.notifications", }); From b65062df1cfe3ad4364355faa649e36b3d38e66c Mon Sep 17 00:00:00 2001 From: Qwreey Date: Sat, 29 Apr 2023 11:49:19 +0900 Subject: [PATCH 21/33] Remove addChildWithIndex --- features/dateMenu.js | 39 ++++++++++------------- features/dndQuickToggle.js | 28 +++-------------- features/inputOutput.js | 7 ++--- features/notifications.js | 6 ++-- features/volumeMixer.js | 5 ++- libs/dndQuickToggleHandler.js | 28 ++++++++--------- libs/featureReloader.js | 27 ---------------- libs/utility.js | 59 +++++++++++++++++++++++++---------- 8 files changed, 85 insertions(+), 114 deletions(-) delete mode 100644 libs/featureReloader.js diff --git a/features/dateMenu.js b/features/dateMenu.js index d6d7c5c..c5f5f37 100644 --- a/features/dateMenu.js +++ b/features/dateMenu.js @@ -1,15 +1,15 @@ -const ExtensionUtils = imports.misc.extensionUtils; -const Me = ExtensionUtils.getCurrentExtension(); -const { GLib } = imports.gi; +const ExtensionUtils = imports.misc.extensionUtils +const Me = ExtensionUtils.getCurrentExtension() +const { GLib } = imports.gi -const featureReloader = Me.imports.libs.featureReloader; +const { featureReloader } = Me.imports.libs.utility const { DateMenuNotifications, DateMenuMediaControl, DateMenuHolder, DateMenuBox, -} = Me.imports.libs.gnome; -const { Indicator } = Me.imports.libs.dndQuickToggleHandler; +} = Me.imports.libs.gnome +const { Indicator } = Me.imports.libs.dndQuickToggleHandler var dateMenuFeature = class { load() { @@ -18,34 +18,29 @@ var dateMenuFeature = class { "datemenu-remove-media-control", "datemenu-remove-notifications", "datemenu-fix-weather-widget", - ]); + ]) // remove media control from date menu if (this.settings.get_boolean("datemenu-remove-media-control")) { - this.dateMenuMediaControlRemoved = true; - DateMenuMediaControl.hide(); + this.dateMenuMediaControlRemoved = true + DateMenuMediaControl.hide() this.dateMenuMediaControlConnection = DateMenuMediaControl.connect( - "show", - () => { - DateMenuMediaControl.hide(); - } - ); + "show",DateMenuMediaControl.hide.bind(DateMenuMediaControl) + ) } // remove notifications from date menu if (this.settings.get_boolean("datemenu-remove-notifications")) { - this.dateMenuNotificationsRemoved = true; - DateMenuNotifications.hide(); - DateMenuBox.style = "padding: 4px 6px 4px 0px;"; - this.dateMenuConnection = DateMenuNotifications.connect("show", () => { - DateMenuNotifications.hide(); - }); + this.dateMenuNotificationsRemoved = true + DateMenuNotifications.hide() + DateMenuBox.style = "padding: 4px 6px 4px 0px;" + this.dateMenuConnection = DateMenuNotifications.connect("show", DateMenuNotifications.hide.bind(DateMenuNotifications)) } // datemenu fix weather widget if (this.settings.get_boolean("datemenu-fix-weather-widget")) { - this.weatherFixBackupClass = DateMenuBox.style_class; - DateMenuBox.style_class += " qwreey-fixed-weather"; + this.weatherFixBackupClass = DateMenuBox.style_class + DateMenuBox.style_class += " qwreey-fixed-weather" } } diff --git a/features/dndQuickToggle.js b/features/dndQuickToggle.js index 79a5a8a..103fa45 100644 --- a/features/dndQuickToggle.js +++ b/features/dndQuickToggle.js @@ -1,11 +1,9 @@ const ExtensionUtils = imports.misc.extensionUtils; const Me = ExtensionUtils.getCurrentExtension(); -const QuickSettingsMenu = imports.ui.main.panel.statusArea.quickSettings; -const featureReloader = Me.imports.libs.featureReloader; -const { QuickSettings } = Me.imports.libs.gnome; +const { featureReloader, addQuickSettingsItems } = Me.imports.libs.utility +const { QuickSettings, DateMenu, QuickSettingsGrid } = Me.imports.libs.gnome; const { Indicator } = Me.imports.libs.dndQuickToggleHandler; -const { DateMenu } = Me.imports.libs.gnome; const { Gio, GObject } = imports.gi; var dndQuickToggleFeature = class { @@ -21,25 +19,9 @@ var dndQuickToggleFeature = class { // Add DND Quick Toggle this.dndToggle = new Indicator(); - QuickSettings._indicators.add_child(this.dndToggle); - QuickSettings._addItems(this.dndToggle.quickSettingsItems); - - // This is a bit of a hack, but it works for now. I took this from the - // gjs guide on how to position items above the background apps menu. - function addQuickSettingsItems(items) { - // Add the items with the built-in function - QuickSettingsMenu._addItems(items); - - // Ensure the tile(s) are above the background apps menu - for (const item of items) { - QuickSettingsMenu.menu._grid.set_child_below_sibling( - item, - QuickSettingsMenu._backgroundApps.quickSettingsItems[0] - ); - } - } - - addQuickSettingsItems(this.dndToggle.quickSettingsItems); + QuickSettings._indicators.add_child(this.dndToggle) + // QuickSettings._addItems(this.dndToggle.quickSettingsItems) + addQuickSettingsItems(this.dndToggle.quickSettingsItems) //remove DND button from datemenu this.datemenu_dnd = DateMenu.last_child.last_child; diff --git a/features/inputOutput.js b/features/inputOutput.js index 2470e9b..b3f9c1f 100644 --- a/features/inputOutput.js +++ b/features/inputOutput.js @@ -1,8 +1,7 @@ const ExtensionUtils = imports.misc.extensionUtils const Me = ExtensionUtils.getCurrentExtension() -const featureReloader = Me.imports.libs.featureReloader -const { addChildWithIndex } = Me.imports.libs.utility +const { featureReloader } = Me.imports.libs.utility const { QuickSettingsGrid } = Me.imports.libs.gnome const { Label } = imports.gi.St const Volume = imports.ui.status.volume @@ -69,7 +68,7 @@ var inputOutputFeature = class { _attachOutputLabel() { this.outputLabel = new Label() this.outputLabel.style_class = "QSTWEAKS-volume-mixer-label" - addChildWithIndex(QuickSettingsGrid, this.outputLabel, this._getOutputStreamSliderIndex() - 1); + QuickSettingsGrid.insert_child_at_index(this.outputLabel, this._getOutputStreamSliderIndex() - 1) this._spanTwoColumns(this.outputLabel) this.outputLabel.visible = this.settings.get_boolean("output-show-selected") this.outputLabel.text = this._findActiveDevice(this._outputStreamSlider) @@ -91,7 +90,7 @@ var inputOutputFeature = class { _attachInputLabel() { this.inputLabel = new Label() this.inputLabel.style_class = "QSTWEAKS-volume-mixer-label" - addChildWithIndex(QuickSettingsGrid, this.inputLabel, this._getInputStreamSliderIndex() - 1) + QuickSettingsGrid.insert_child_at_index(this.inputLabel, this._getInputStreamSliderIndex() - 1) this._spanTwoColumns(this.inputLabel) this._setInputLabelVisibility() this.inputLabel.text = this._findActiveDevice(this._inputStreamSlider) diff --git a/features/notifications.js b/features/notifications.js index c366e0a..89cf141 100644 --- a/features/notifications.js +++ b/features/notifications.js @@ -1,9 +1,8 @@ const ExtensionUtils = imports.misc.extensionUtils const Me = ExtensionUtils.getCurrentExtension() -const featureReloader = Me.imports.libs.featureReloader +const { featureReloader } = Me.imports.libs.utility const { Notifications } = Me.imports.libs.notificationHandler -const { addChildWithIndex } = Me.imports.libs.utility const { QuickSettingsGrid, QuickSettingsBox, @@ -107,9 +106,10 @@ var notificationsFeature = class { for (let index = 0; index - this._sync() - ); + }) + // sync + this._changedId = this._settings.connect("changed::show-banners", this._sync.bind(this)) this._sync(); } _sync() { - const checked = !this._settings.get_boolean("show-banners"); + const checked = !this._settings.get_boolean("show-banners") if (checked) { - this._indicator.visible = true; + this._indicator.visible = true } else { - this._indicator.visible = false; + this._indicator.visible = false } } } diff --git a/libs/featureReloader.js b/libs/featureReloader.js deleted file mode 100644 index 8d26c25..0000000 --- a/libs/featureReloader.js +++ /dev/null @@ -1,27 +0,0 @@ -// Enable feature reloader with specific setting keys -function enableWithSettingKeys(feature,settingKeys) { - // save connections here and destroy when disable called - let settingsListeners = feature.settingsListeners - if (!settingsListeners) { - settingsListeners = [] - feature.settingsListeners = settingsListeners - } - - const reload = ()=>{ - feature.unload() - feature.load() - } - - for (const key of settingKeys) { - settingsListeners.push(feature.settings.connect("changed::"+key,reload)) - } -} - -// Disable feature reloader -function disable(feature) { - if (!feature.settingsListeners) return - for (const connection of feature.settingsListeners) { - feature.settings.disconnect(connection) - } - feature.settingsListeners = null -} diff --git a/libs/utility.js b/libs/utility.js index 83b33e6..400842e 100644 --- a/libs/utility.js +++ b/libs/utility.js @@ -1,24 +1,49 @@ -// this module exports many useful functions -// for simplify main codes -function addChildWithIndex(parent,child,addIndex) { - let children = parent.get_children() - let tmp = [] - let tmp_visible = [] - for (let index = addIndex+1; index{ + feature.unload() + feature.load() + } + + for (const key of settingKeys) { + settingsListeners.push(feature.settings.connect("changed::"+key,reload)) + } + }, + + // Disable feature reloader + disable(feature) { + if (!feature.settingsListeners) return + for (const connection of feature.settingsListeners) { + feature.settings.disconnect(connection) + } + feature.settingsListeners = null + } +} From fe771a63cf8de30966071994f212b79aa24bb6b1 Mon Sep 17 00:00:00 2001 From: Qwreey Date: Sat, 29 Apr 2023 11:52:14 +0900 Subject: [PATCH 22/33] Remove featureReloader.js --- features/buttonRemover.js | 2 +- libs/utility.js | 12 +++++++----- 2 files changed, 8 insertions(+), 6 deletions(-) diff --git a/features/buttonRemover.js b/features/buttonRemover.js index b434b7d..e357cb6 100644 --- a/features/buttonRemover.js +++ b/features/buttonRemover.js @@ -5,7 +5,7 @@ const ExtensionUtils = imports.misc.extensionUtils const Me = ExtensionUtils.getCurrentExtension() -const featureReloader = Me.imports.libs.featureReloader +const { featureReloader } = Me.imports.libs.utility const { QuickSettingsGrid } = Me.imports.libs.gnome var buttonRemoverFeature = class { diff --git a/libs/utility.js b/libs/utility.js index 400842e..59ebbba 100644 --- a/libs/utility.js +++ b/libs/utility.js @@ -6,11 +6,13 @@ function addQuickSettingsItems(items) { QuickSettings._addItems(items) // Ensure the tile(s) are above the background apps menu - for (const item of items) { - QuickSettingsGrid.set_child_below_sibling( - item, - QuickSettings._backgroundApps.quickSettingsItems[0] - ); + if (QuickSettings._backgroundApps) { + for (const item of items) { + QuickSettingsGrid.set_child_below_sibling( + item, + QuickSettings._backgroundApps.quickSettingsItems[0] + ) + } } } From 0717c9a2104b709e4f5aae2edde0a91ad9302b86 Mon Sep 17 00:00:00 2001 From: Qwreey Date: Sat, 29 Apr 2023 12:27:57 +0900 Subject: [PATCH 23/33] Fix #19 --- features/buttonRemover.js | 10 +- features/dndQuickToggle.js | 50 ++++----- features/inputOutput.js | 6 +- features/notifications.js | 20 ++-- features/volumeMixer.js | 14 +-- libs/dndQuickToggleHandler.js | 22 ++-- libs/notificationHandler.js | 3 + libs/streamSlider.js | 200 +++++++++++++++++----------------- libs/utility.js | 12 ++ 9 files changed, 169 insertions(+), 168 deletions(-) diff --git a/features/buttonRemover.js b/features/buttonRemover.js index e357cb6..1bf85fe 100644 --- a/features/buttonRemover.js +++ b/features/buttonRemover.js @@ -50,12 +50,10 @@ var buttonRemoverFeature = class { this.settings.set_string("list-buttons",JSON.stringify(listButtons)) } - let items; { - items = this.settings.get_strv("user-removed-buttons") - if (!items) { - items = [] - this.settings.set_strv("user-removed-buttons",items) - } + let items = this.settings.get_strv("user-removed-buttons") + if (!items) { + items = [] + this.settings.set_strv("user-removed-buttons",items) } this._apply(items) diff --git a/features/dndQuickToggle.js b/features/dndQuickToggle.js index 103fa45..0ab3177 100644 --- a/features/dndQuickToggle.js +++ b/features/dndQuickToggle.js @@ -1,58 +1,58 @@ -const ExtensionUtils = imports.misc.extensionUtils; -const Me = ExtensionUtils.getCurrentExtension(); +const ExtensionUtils = imports.misc.extensionUtils +const Me = ExtensionUtils.getCurrentExtension() const { featureReloader, addQuickSettingsItems } = Me.imports.libs.utility -const { QuickSettings, DateMenu, QuickSettingsGrid } = Me.imports.libs.gnome; -const { Indicator } = Me.imports.libs.dndQuickToggleHandler; -const { Gio, GObject } = imports.gi; +const { QuickSettings, DateMenu, QuickSettingsGrid } = Me.imports.libs.gnome +const { Indicator } = Me.imports.libs.dndQuickToggleHandler +const { Gio, GObject } = imports.gi var dndQuickToggleFeature = class { load() { // setup reloader featureReloader.enableWithSettingKeys(this, [ "add-dnd-quick-toggle-enabled", - ]); + ]) - this.datemenu_dnd = null; + this.datemenu_dnd = null // check is feature enabled - if (!this.settings.get_boolean("add-dnd-quick-toggle-enabled")) return; + if (!this.settings.get_boolean("add-dnd-quick-toggle-enabled")) return // Add DND Quick Toggle - this.dndToggle = new Indicator(); + this.dndToggle = new Indicator() QuickSettings._indicators.add_child(this.dndToggle) // QuickSettings._addItems(this.dndToggle.quickSettingsItems) addQuickSettingsItems(this.dndToggle.quickSettingsItems) //remove DND button from datemenu - this.datemenu_dnd = DateMenu.last_child.last_child; - this.datemenu_dnd.hide(); + this.datemenu_dnd = DateMenu.last_child.last_child + this.datemenu_dnd.hide() this.datemenu_dnd_connection = this.datemenu_dnd.connect("show", () => { - this.datemenu_dnd.hide(); - }); + this.datemenu_dnd.hide() + }) } unload() { // disable feature reloader - featureReloader.disable(this); + featureReloader.disable(this) - if (this.datemenu_dnd == null) return; + if (this.datemenu_dnd == null) return //put back the button to the datemenu - this.datemenu_dnd.disconnect(this.datemenu_dnd_connection); - this.datemenu_dnd_connection = null; + this.datemenu_dnd.disconnect(this.datemenu_dnd_connection) + this.datemenu_dnd_connection = null const _settings = new Gio.Settings({ schema_id: "org.gnome.desktop.notifications", - }); + }) if (!_settings.get_boolean("show-banners")) { - this.datemenu_dnd.show(); + this.datemenu_dnd.show() } // Remove DND Quick Toggle if (this.dndToggle) { - const dndQSItems = this.dndToggle.quickSettingsItems[0]; - dndQSItems.get_parent().remove_child(dndQSItems); - this.dndToggle.get_parent().remove_child(this.dndToggle); - this.dndToggle.destroy(); - this.dndToggle = null; + const dndQSItems = this.dndToggle.quickSettingsItems[0] + dndQSItems.get_parent().remove_child(dndQSItems) + this.dndToggle.get_parent().remove_child(this.dndToggle) + this.dndToggle.destroy() + this.dndToggle = null } } -}; +} diff --git a/features/inputOutput.js b/features/inputOutput.js index b3f9c1f..b38b638 100644 --- a/features/inputOutput.js +++ b/features/inputOutput.js @@ -5,7 +5,7 @@ const { featureReloader } = Me.imports.libs.utility const { QuickSettingsGrid } = Me.imports.libs.gnome const { Label } = imports.gi.St const Volume = imports.ui.status.volume -const PopupMenu = imports.ui.popupMenu; +const PopupMenu = imports.ui.popupMenu var inputOutputFeature = class { load() { @@ -184,7 +184,7 @@ var inputOutputFeature = class { if (!device) return - const {description, origin} = device; + const {description, origin} = device const name = origin ? `${description} – ${origin}` : description @@ -195,4 +195,4 @@ var inputOutputFeature = class { _spanTwoColumns(object) { QuickSettingsGrid.layout_manager.child_set_property(QuickSettingsGrid, object, 'column-span', 2) } -}; +} diff --git a/features/notifications.js b/features/notifications.js index 89cf141..b801db0 100644 --- a/features/notifications.js +++ b/features/notifications.js @@ -42,7 +42,7 @@ var notificationsFeature = class { hideWhenNoNotifications: this.settings.get_boolean("notifications-hide-when-no-notifications") }) - let notificationStyle = this.notificationHandler.style_class = + this.notificationHandler.style_class = // If separated, style as popup menu (isIntegrated ? "" : "popup-menu-content quick-settings ") // Integrated or separated @@ -57,10 +57,10 @@ var notificationsFeature = class { // Max height this.notificationHandler.style - = `max-height: ${this.settings.get_int("notifications-max-height")}px;` + = `max-height: ${this.settings.get_int("notifications-max-height")}px` this.maxHeigthListen = this.settings.connect("changed::notifications-max-height",()=>{ this.notificationHandler.style - = `max-height: ${this.settings.get_int("notifications-max-height")}px;` + = `max-height: ${this.settings.get_int("notifications-max-height")}px` }) // Insert media control @@ -100,16 +100,10 @@ var notificationsFeature = class { // Insert notification modal switch (this.settings.get_string("notifications-position")) { case "top": - // get system item index - let gridChildren = QuickSettingsGrid.get_children() - let systemItemIndex = null - for (let index = 0; indexchild.constructor?.name == "SystemItem")+1 + ) break case "bottom": QuickSettingsGrid.add_child(this.notificationHandler) diff --git a/features/volumeMixer.js b/features/volumeMixer.js index c104765..ec8f33a 100644 --- a/features/volumeMixer.js +++ b/features/volumeMixer.js @@ -34,20 +34,14 @@ var volumeMixerFeature = class { 'volume-mixer-use-regex': settings.get_boolean("volume-mixer-use-regex") }) - // Find Input slider index - let inputSliderIndex - let gridChildren = QuickSettingsGrid.get_children() - for (let index = 0; indexchild.constructor?.name == "InputStreamSlider")+1 + ) break case "bottom": QuickSettingsGrid.add_child(this.volumeMixer.actor) diff --git a/libs/dndQuickToggleHandler.js b/libs/dndQuickToggleHandler.js index edd753c..9f4d7df 100644 --- a/libs/dndQuickToggleHandler.js +++ b/libs/dndQuickToggleHandler.js @@ -1,6 +1,6 @@ -const { Gio, GObject } = imports.gi; -const { QuickToggle, SystemIndicator } = imports.ui.quickSettings; -const { St } = imports.gi; +const { Gio, GObject } = imports.gi +const { QuickToggle, SystemIndicator } = imports.ui.quickSettings +const { St } = imports.gi const DndQuickToggle = GObject.registerClass( class DndQuickToggle extends QuickToggle { @@ -8,13 +8,13 @@ const DndQuickToggle = GObject.registerClass( super._init({ label: _('Do Not Disturb'), iconName: "notifications-disabled-symbolic", - }); + }) this._settings = new Gio.Settings({ schema_id: "org.gnome.desktop.notifications", - }); + }) - this._changedId = this._settings.connect("changed::show-banners", this._sync.bind(this)); + this._changedId = this._settings.connect("changed::show-banners", this._sync.bind(this)) this.connectObject( // Destroy event @@ -24,10 +24,10 @@ const DndQuickToggle = GObject.registerClass( "clicked", this._toggleMode.bind(this), this - ); + ) // Fetch DND status once - this._sync(); + this._sync() } // Toggle DND @@ -44,7 +44,7 @@ const DndQuickToggle = GObject.registerClass( if (this.checked !== checked) this.set({ checked }) } } -); +) var Indicator = GObject.registerClass( class Indicator extends SystemIndicator { @@ -62,7 +62,7 @@ var Indicator = GObject.registerClass( // sync this._changedId = this._settings.connect("changed::show-banners", this._sync.bind(this)) - this._sync(); + this._sync() } _sync() { @@ -74,4 +74,4 @@ var Indicator = GObject.registerClass( } } } -); +) diff --git a/libs/notificationHandler.js b/libs/notificationHandler.js index 468973d..9032a67 100644 --- a/libs/notificationHandler.js +++ b/libs/notificationHandler.js @@ -2,7 +2,9 @@ const { GObject, St, Clutter } = imports.gi const Main = imports.ui.main const Calendar = imports.ui.calendar const ExtensionUtils = imports.misc.extensionUtils + const Me = ExtensionUtils.getCurrentExtension() +const { fixStScrollViewScrollbarOverflow } = Me.imports.libs.utility const NoNotifPlaceholder = GObject.registerClass( class NoNotifPlaceholder extends St.BoxLayout { @@ -77,6 +79,7 @@ class Notifications extends St.BoxLayout{ this.list = messageList._scrollView this.list.get_parent().remove_child(this.list) this.add_child(this.list) // mount + fixStScrollViewScrollbarOverflow(this.list) // fix fade effect } // Create 'Notifications' text and ClearButton diff --git a/libs/streamSlider.js b/libs/streamSlider.js index acc443e..2f6c5c6 100644 --- a/libs/streamSlider.js +++ b/libs/streamSlider.js @@ -9,257 +9,257 @@ const { GObject, Gio, GLib, Gvc } = imports.gi const Volume = imports.ui.status.volume -const ALLOW_AMPLIFIED_VOLUME_KEY = 'allow-volume-above-100-percent'; -const { QuickSlider } = imports.ui.quickSettings; -const PopupMenu = imports.ui.popupMenu; +const ALLOW_AMPLIFIED_VOLUME_KEY = 'allow-volume-above-100-percent' +const { QuickSlider } = imports.ui.quickSettings +const PopupMenu = imports.ui.popupMenu var StreamSlider = GObject.registerClass({ Signals: { 'stream-updated': {}, }, }, class StreamSlider extends QuickSlider { _init(control) { - super._init(); + super._init() - this._connections = []; // ADDED BY QWREEY - this._control = control; + this._connections = [] // ADDED BY QWREEY + this._control = control - this._inDrag = false; - this._notifyVolumeChangeId = 0; + this._inDrag = false + this._notifyVolumeChangeId = 0 this._soundSettings = new Gio.Settings({ schema_id: 'org.gnome.desktop.sound', - }); + }) // MODED BY QWREEY this._connections.push([ this._soundSettings, this._soundSettings.connect(`changed::${ALLOW_AMPLIFIED_VOLUME_KEY}`, () => this._amplifySettingsChanged()) - ]); - this._amplifySettingsChanged(); + ]) + this._amplifySettingsChanged() this._sliderChangedId = this.slider.connect('notify::value', - () => this._sliderChanged()); + () => this._sliderChanged()) this._connections.push([ // ADDED BY QWREEY this.slider,this._sliderChangedId - ]); + ]) this._connections.push([ // MODED BY QWREEY this.slider, this.slider.connect('drag-begin', () => (this._inDrag = true)) - ]); + ]) this._connections.push([ // MODED BY QWREEY this.slider, this.slider.connect('drag-end', () => { - this._inDrag = false; - this._notifyVolumeChange(); + this._inDrag = false + this._notifyVolumeChange() }) - ]); + ]) - this._deviceItems = new Map(); + this._deviceItems = new Map() - this._deviceSection = new PopupMenu.PopupMenuSection(); - this.menu.addMenuItem(this._deviceSection); + this._deviceSection = new PopupMenu.PopupMenuSection() + this.menu.addMenuItem(this._deviceSection) - this.menu.addMenuItem(new PopupMenu.PopupSeparatorMenuItem()); - this.menu.addSettingsAction(_('Sound Settings'),'gnome-sound-panel.desktop'); + this.menu.addMenuItem(new PopupMenu.PopupSeparatorMenuItem()) + this.menu.addSettingsAction(_('Sound Settings'),'gnome-sound-panel.desktop') - this._stream = null; - this._volumeCancellable = null; - this._icons = []; + this._stream = null + this._volumeCancellable = null + this._icons = [] - this._sync(); + this._sync() this._connections.push([ // ADDED BY QWREEY this, this.connect('destroy', this._destroy.bind(this)) - ]); + ]) } get stream() { - return this._stream; + return this._stream } set stream(stream) { - this._stream?.disconnectObject(this); + this._stream?.disconnectObject(this) - this._stream = stream; + this._stream = stream if (this._stream) { - this._connectStream(this._stream); - this._updateVolume(); + this._connectStream(this._stream) + this._updateVolume() } else { - this.emit('stream-updated'); + this.emit('stream-updated') } - this._sync(); + this._sync() } _connectStream(stream) { stream.connectObject( 'notify::is-muted', this._updateVolume.bind(this), - 'notify::volume', this._updateVolume.bind(this), this); + 'notify::volume', this._updateVolume.bind(this), this) } _lookupDevice(_id) { throw new GObject.NotImplementedError( - `_lookupDevice in ${this.constructor.name}`); + `_lookupDevice in ${this.constructor.name}`) } _activateDevice(_device) { throw new GObject.NotImplementedError( - `_activateDevice in ${this.constructor.name}`); + `_activateDevice in ${this.constructor.name}`) } _addDevice(id) { if (this._deviceItems.has(id)) - return; + return - const device = this._lookupDevice(id); + const device = this._lookupDevice(id) if (!device) - return; + return - const {description, origin} = device; + const {description, origin} = device const name = origin ? `${description} – ${origin}` - : description; - const item = new PopupMenu.PopupImageMenuItem(name, device.get_gicon()); + : description + const item = new PopupMenu.PopupImageMenuItem(name, device.get_gicon()) this._connections.push([ item, item.connect('activate', () => this._activateDevice(device)) - ]); + ]) - this._deviceSection.addMenuItem(item); - this._deviceItems.set(id, item); + this._deviceSection.addMenuItem(item) + this._deviceItems.set(id, item) - this._sync(); + this._sync() } _removeDevice(id) { - this._deviceItems.get(id)?.destroy(); + this._deviceItems.get(id)?.destroy() if (this._deviceItems.delete(id)) - this._sync(); + this._sync() } _setActiveDevice(activeId) { for (const [id, item] of this._deviceItems) { item.setOrnament(id === activeId ? PopupMenu.Ornament.CHECK - : PopupMenu.Ornament.NONE); + : PopupMenu.Ornament.NONE) } } _shouldBeVisible() { - return this._stream != null; + return this._stream != null } _sync() { - this.visible = this._shouldBeVisible(); - this.menuEnabled = this._deviceItems.size > 1; + this.visible = this._shouldBeVisible() + this.menuEnabled = this._deviceItems.size > 1 } _sliderChanged() { if (!this._stream) - return; + return - let value = this.slider.value; - let volume = value * this._control.get_vol_max_norm(); - let prevMuted = this._stream.is_muted; - let prevVolume = this._stream.volume; + let value = this.slider.value + let volume = value * this._control.get_vol_max_norm() + let prevMuted = this._stream.is_muted + let prevVolume = this._stream.volume if (volume < 1) { - this._stream.volume = 0; + this._stream.volume = 0 if (!prevMuted) - this._stream.change_is_muted(true); + this._stream.change_is_muted(true) } else { - this._stream.volume = volume; + this._stream.volume = volume if (prevMuted) - this._stream.change_is_muted(false); + this._stream.change_is_muted(false) } - this._stream.push_volume(); + this._stream.push_volume() - let volumeChanged = this._stream.volume !== prevVolume; + let volumeChanged = this._stream.volume !== prevVolume if (volumeChanged && !this._notifyVolumeChangeId && !this._inDrag) { this._notifyVolumeChangeId = GLib.timeout_add(GLib.PRIORITY_DEFAULT, 30, () => { - this._notifyVolumeChange(); - this._notifyVolumeChangeId = 0; - return GLib.SOURCE_REMOVE; - }); + this._notifyVolumeChange() + this._notifyVolumeChangeId = 0 + return GLib.SOURCE_REMOVE + }) GLib.Source.set_name_by_id(this._notifyVolumeChangeId, - '[gnome-shell] this._notifyVolumeChangeId'); + '[gnome-shell] this._notifyVolumeChangeId') } } _notifyVolumeChange() { if (this._volumeCancellable) - this._volumeCancellable.cancel(); - this._volumeCancellable = null; + this._volumeCancellable.cancel() + this._volumeCancellable = null if (this._stream.state === Gvc.MixerStreamState.RUNNING) - return; // feedback not necessary while playing + return // feedback not necessary while playing - this._volumeCancellable = new Gio.Cancellable(); - let player = global.display.get_sound_player(); + this._volumeCancellable = new Gio.Cancellable() + let player = global.display.get_sound_player() player.play_from_theme('audio-volume-change', - _('Volume changed'), this._volumeCancellable); + _('Volume changed'), this._volumeCancellable) } _changeSlider(value) { - this.slider.block_signal_handler(this._sliderChangedId); - this.slider.value = value; - this.slider.unblock_signal_handler(this._sliderChangedId); + this.slider.block_signal_handler(this._sliderChangedId) + this.slider.value = value + this.slider.unblock_signal_handler(this._sliderChangedId) } _updateVolume() { - let muted = this._stream.is_muted; + let muted = this._stream.is_muted this._changeSlider(muted - ? 0 : this._stream.volume / this._control.get_vol_max_norm()); - this.emit('stream-updated'); + ? 0 : this._stream.volume / this._control.get_vol_max_norm()) + this.emit('stream-updated') } _amplifySettingsChanged() { - this._allowAmplified = this._soundSettings.get_boolean(ALLOW_AMPLIFIED_VOLUME_KEY); + this._allowAmplified = this._soundSettings.get_boolean(ALLOW_AMPLIFIED_VOLUME_KEY) this.slider.maximum_value = this._allowAmplified - ? this.getMaxLevel() : 1; + ? this.getMaxLevel() : 1 if (this._stream) - this._updateVolume(); + this._updateVolume() } getIcon() { if (!this._stream) - return null; + return null - let volume = this._stream.volume; - let n; + let volume = this._stream.volume + let n if (this._stream.is_muted || volume <= 0) { - n = 0; + n = 0 } else { - n = Math.ceil(3 * volume / this._control.get_vol_max_norm()); - n = Math.clamp(n, 1, this._icons.length - 1); + n = Math.ceil(3 * volume / this._control.get_vol_max_norm()) + n = Math.clamp(n, 1, this._icons.length - 1) } - return this._icons[n]; + return this._icons[n] } getLevel() { if (!this._stream) - return null; + return null - return this._stream.volume / this._control.get_vol_max_norm(); + return this._stream.volume / this._control.get_vol_max_norm() } getMaxLevel() { - let maxVolume = this._control.get_vol_max_norm(); + let maxVolume = this._control.get_vol_max_norm() if (this._allowAmplified) - maxVolume = this._control.get_vol_max_amplified(); + maxVolume = this._control.get_vol_max_amplified() - return maxVolume / this._control.get_vol_max_norm(); + return maxVolume / this._control.get_vol_max_norm() } // ADDED BY QWREEY _destroy() { - GLib.Source.remove(this._notifyVolumeChangeId); + GLib.Source.remove(this._notifyVolumeChangeId) for (item of this._connections) { - item[0].disconnect(item[1]); + item[0].disconnect(item[1]) } - this._connections = null; + this._connections = null } -}); +}) diff --git a/libs/utility.js b/libs/utility.js index 59ebbba..a69da83 100644 --- a/libs/utility.js +++ b/libs/utility.js @@ -1,3 +1,7 @@ +const ExtensionUtils = imports.misc.extensionUtils +const Me = ExtensionUtils.getCurrentExtension() + +const { QuickSettings, QuickSettingsGrid } = Me.imports.libs.gnome // This is a bit of a hack, but it works for now. I took this from the // gjs guide on how to position items above the background apps menu. @@ -16,6 +20,14 @@ function addQuickSettingsItems(items) { } } +// Fix https://github.com/qwreey75/quick-settings-tweaks/issues/19 +// scrollbar appears over fading-effect +function fixStScrollViewScrollbarOverflow(stScrollView) { + let update = ()=>stScrollView.overlay_scrollbars = !stScrollView.vscrollbar_visible + stScrollView.connect("notify::vscrollbar-visible",update) + update() +} + function logger(str) { log("[EXTENSION QSTweaks] " + str) } From ddef2bc9e961d84144cb6750a569faaaec0ab8dc Mon Sep 17 00:00:00 2001 From: Qwreey Date: Sat, 29 Apr 2023 13:01:13 +0900 Subject: [PATCH 24/33] Add 'make log' to debug and show load time taken --- Makefile | 3 +++ extension.js | 6 ++++-- 2 files changed, 7 insertions(+), 2 deletions(-) diff --git a/Makefile b/Makefile index 45716ce..fabecfa 100644 --- a/Makefile +++ b/Makefile @@ -19,3 +19,6 @@ dev: install ifeq ($(XDG_SESSION_TYPE),x11) busctl --user call org.gnome.Shell /org/gnome/Shell org.gnome.Shell Eval s 'Meta.restart("Restarting…", global.context)' endif + +log: + journalctl /usr/bin/gnome-shell -f -q --output cat | grep '\[EXTENSION QSTweaks\] ' diff --git a/extension.js b/extension.js index 70ed0db..aad417f 100644 --- a/extension.js +++ b/extension.js @@ -8,6 +8,7 @@ class Extension { constructor() {} disable() { logger("Unloading ...") + let start = +Date.now() // unload features for (const feature of this.features) { @@ -17,10 +18,11 @@ class Extension { } this.features = null - logger("Diabled") + logger("Diabled. " + (+new Date() - start) + "ms taken") } enable() { logger("Loading ...") + let start = +Date.now() // load modules this.features = [ @@ -43,7 +45,7 @@ class Extension { feature.load() } - logger("Loaded") + logger("Loaded. " + (+Date.now() - start) + "ms taken") } } From 935fa69462bc23468a13cfd16c3c08a9cb26d9e7 Mon Sep 17 00:00:00 2001 From: Qwreey Date: Sat, 29 Apr 2023 18:22:09 +0900 Subject: [PATCH 25/33] Add reorder method on volumeMixerFeature --- features/dateMenu.js | 1 + features/volumeMixer.js | 18 ++++++++++++++---- metadata.json | 2 +- 3 files changed, 16 insertions(+), 5 deletions(-) diff --git a/features/dateMenu.js b/features/dateMenu.js index c5f5f37..1e370bb 100644 --- a/features/dateMenu.js +++ b/features/dateMenu.js @@ -63,6 +63,7 @@ var dateMenuFeature = class { DateMenuBox.style = ""; this.dateMenuNotificationsRemoved = null; } + // undo weather fix if (this.weatherFixBackupClass) { DateMenuBox.style_class = this.weatherFixBackupClass; diff --git a/features/volumeMixer.js b/features/volumeMixer.js index ec8f33a..2d43aae 100644 --- a/features/volumeMixer.js +++ b/features/volumeMixer.js @@ -6,6 +6,19 @@ const { VolumeMixer } = Me.imports.libs.volumeMixerHandler const { QuickSettingsGrid } = Me.imports.libs.gnome var volumeMixerFeature = class { + reorder() { + // reorder on menu open + QuickSettingsGrid.set_child_below_sibling( + this.volumeMixer.actor, + this._getInputStreamSlider() + ) + } + + _getInputStreamSlider() { + return this.inputStreamSlider + || (this.inputStreamSlider = QuickSettingsGrid.get_children().find((child)=>child.constructor?.name == "InputStreamSlider")) + } + load() { let settings = this.settings @@ -38,10 +51,7 @@ var volumeMixerFeature = class { let position = settings.get_string("volume-mixer-position") switch (position) { case "top": - QuickSettingsGrid.insert_child_at_index(this.volumeMixer.actor, - // Find Input slider index - QuickSettingsGrid.get_children().findIndex((child)=>child.constructor?.name == "InputStreamSlider")+1 - ) + QuickSettingsGrid.insert_child_below(this.volumeMixer.actor,this._getInputStreamSlider()) break case "bottom": QuickSettingsGrid.add_child(this.volumeMixer.actor) diff --git a/metadata.json b/metadata.json index c36bcd9..3587992 100644 --- a/metadata.json +++ b/metadata.json @@ -1,6 +1,6 @@ { "description": "Let's tweak gnome 43's quick settings! You can add Media Controls, Notifications, Volume Mixer on quick settings and remove useless buttons!", - "name": "Quick Settings Tweaker", + "name": "[QSTweak] Quick Setting Tweaker", "url": "https://github.com/qwreey75/quick-settings-tweaks", "shell-version": ["43", "44"], "uuid": "quick-settings-tweaks@qwreey", From 66645c909444ac41ab4b6388225bdf706659b887 Mon Sep 17 00:00:00 2001 From: Qwreey Date: Wed, 3 May 2023 00:47:29 +0900 Subject: [PATCH 26/33] Add menuOpenTracker --- extension.js | 16 +++++++++++++++- features/volumeMixer.js | 2 +- 2 files changed, 16 insertions(+), 2 deletions(-) diff --git a/extension.js b/extension.js index aad417f..d0a456a 100644 --- a/extension.js +++ b/extension.js @@ -2,6 +2,7 @@ const ExtensionUtils = imports.misc.extensionUtils const Me = ExtensionUtils.getCurrentExtension() const Features = Me.imports.features const { logger } = Me.imports.libs.utility +const { QuickSettingsGrid } = Me.imports.libs.gnome const { GLib } = imports.gi class Extension { @@ -9,7 +10,11 @@ class Extension { disable() { logger("Unloading ...") let start = +Date.now() - + + // unload menu open tracker + QuickSettingsGrid.disconnect(this.menuOpenTracker) + this.menuOpenTracker = null + // unload features for (const feature of this.features) { logger(`Unload feature '${feature.constructor.name}'`) @@ -45,6 +50,15 @@ class Extension { feature.load() } + // load menu open tracker + this.menuOpenTracker = QuickSettingsGrid.connect("notify::mapped",()=>{ + if (!QuickSettingsGrid.mapped) return + logger(`Update layout`) + for (const feature of this.features) { + if (feature.onMenuOpen) feature.onMenuOpen() + } + }) + logger("Loaded. " + (+Date.now() - start) + "ms taken") } } diff --git a/features/volumeMixer.js b/features/volumeMixer.js index 2d43aae..eb09e43 100644 --- a/features/volumeMixer.js +++ b/features/volumeMixer.js @@ -6,7 +6,7 @@ const { VolumeMixer } = Me.imports.libs.volumeMixerHandler const { QuickSettingsGrid } = Me.imports.libs.gnome var volumeMixerFeature = class { - reorder() { + onMenuOpen() { // reorder on menu open QuickSettingsGrid.set_child_below_sibling( this.volumeMixer.actor, From a894a473b39978980b3c1315d6eafc18820ea168 Mon Sep 17 00:00:00 2001 From: Qwreey Date: Wed, 3 May 2023 01:09:20 +0900 Subject: [PATCH 27/33] Add onMenuOpen() on notification --- features/notifications.js | 28 +++++++++++++++++++++++----- 1 file changed, 23 insertions(+), 5 deletions(-) diff --git a/features/notifications.js b/features/notifications.js index b801db0..f0d0590 100644 --- a/features/notifications.js +++ b/features/notifications.js @@ -11,6 +11,22 @@ const { } = Me.imports.libs.gnome var notificationsFeature = class { + onMenuOpen() { + // reorder on menu open + if (this.mediaControlEnabled) { + QuickSettingsGrid.set_child_at_index( + this.notificationHandler.mediaSection, + -1 + ) + } + if (this.notificationsEnabled && this.notificationsIntegrated) { + QuickSettingsGrid.set_child_at_index( + this.notificationHandler, + this.notificationsPosition == "top" ? QuickSettingsGrid.get_children().findIndex((child)=>child.constructor?.name == "SystemItem")+1 : -1 + ) + } + } + load() { let settings = this.settings @@ -28,8 +44,8 @@ var notificationsFeature = class { ]) // check is feature enabled - let notificationsEnabled = this.settings.get_boolean("notifications-enabled") - let mediaControlEnabled = this.settings.get_boolean("media-control-enabled") + let notificationsEnabled = this.notificationsEnabled = this.settings.get_boolean("notifications-enabled") + let mediaControlEnabled = this.mediaControlEnabled = this.settings.get_boolean("media-control-enabled") let disableAdjustBorder = this.settings.get_boolean("disable-adjust-content-border-radius") let disableRemoveShadow = this.settings.get_boolean("disable-remove-shadow") let nativeControls = this.settings.get_boolean("notifications-use-native-controls") @@ -95,10 +111,12 @@ var notificationsFeature = class { } // Insert notifications + let notificationsPosition = this.notificationsPosition = this.settings.get_string("notifications-position") + let notificationsIntegrated = this.notificationsIntegrated = this.settings.get_string("notifications-position") if (notificationsEnabled) { - if (this.settings.get_boolean("notifications-integrated")) { + if (notificationsIntegrated) { // Insert notification modal - switch (this.settings.get_string("notifications-position")) { + switch (notificationsPosition) { case "top": QuickSettingsGrid.insert_child_at_index(this.notificationHandler, // get system item index @@ -137,7 +155,7 @@ var notificationsFeature = class { } // Insert notification modal - switch (this.settings.get_string("notifications-position")) { + switch (notificationsPosition) { case "top": let quickSettingsModal = QuickSettingsBox.first_child QuickSettingsBox.remove_child(quickSettingsModal) From b4aa85819f9870d1488e55642bc0e840f03a1594 Mon Sep 17 00:00:00 2001 From: Qwreey Date: Wed, 3 May 2023 02:06:06 +0900 Subject: [PATCH 28/33] Add unafe toggle --- extension.js | 3 +- features/unsafeQuickToggle.js | 32 ++++++++++++++++ libs/unsafeQuickToggleHandler.js | 37 +++++++++++++++++++ po/en.po | 6 ++- ...tensions.quick-settings-tweaks.gschema.xml | 8 ++++ 5 files changed, 84 insertions(+), 2 deletions(-) create mode 100644 features/unsafeQuickToggle.js create mode 100644 libs/unsafeQuickToggleHandler.js diff --git a/extension.js b/extension.js index d0a456a..24c13a6 100644 --- a/extension.js +++ b/extension.js @@ -32,11 +32,12 @@ class Extension { // load modules this.features = [ new Features.dndQuickToggle.dndQuickToggleFeature(), + new Features.unsafeQuickToggle.unsafeQuickToggleFeature(), new Features.notifications.notificationsFeature(), new Features.volumeMixer.volumeMixerFeature(), new Features.dateMenu.dateMenuFeature(), new Features.buttonRemover.buttonRemoverFeature(), - new Features.inputOutput.inputOutputFeature() + new Features.inputOutput.inputOutputFeature(), ] // load settings diff --git a/features/unsafeQuickToggle.js b/features/unsafeQuickToggle.js new file mode 100644 index 0000000..11f8aa1 --- /dev/null +++ b/features/unsafeQuickToggle.js @@ -0,0 +1,32 @@ +const ExtensionUtils = imports.misc.extensionUtils +const Me = ExtensionUtils.getCurrentExtension() + +const { featureReloader, addQuickSettingsItems } = Me.imports.libs.utility +const { QuickSettings, DateMenu, QuickSettingsGrid } = Me.imports.libs.gnome +const { UnsafeQuickToggle } = Me.imports.libs.unsafeQuickToggleHandler +const { Gio, GObject } = imports.gi + +var unsafeQuickToggleFeature = class { + load() { + // setup reloader + featureReloader.enableWithSettingKeys(this, [ + "add-unsafe-quick-toggle-enabled", + ]) + + // check is feature enabled + if (!this.settings.get_boolean("add-unsafe-quick-toggle-enabled")) return + global.context.unsafe_mode = this.settings.get_boolean("last-unsafe-state") + + // Add Unsafe Quick Toggle + this.unsafeToggle = new UnsafeQuickToggle((state)=>this.settings.set_boolean("last-unsafe-state",state)) + addQuickSettingsItems([this.unsafeToggle]) + } + + unload() { + // disable feature reloader + featureReloader.disable(this) + + this.unsafeToggle.destroy() + global.context.unsafe_mode = false + } +} diff --git a/libs/unsafeQuickToggleHandler.js b/libs/unsafeQuickToggleHandler.js new file mode 100644 index 0000000..47aaa4d --- /dev/null +++ b/libs/unsafeQuickToggleHandler.js @@ -0,0 +1,37 @@ +const { Gio, GObject } = imports.gi +const { QuickToggle, SystemIndicator } = imports.ui.quickSettings +const { St } = imports.gi +const ExtensionUtils = imports.misc.extensionUtils + +const UnsafeQuickToggle = GObject.registerClass( + class UnsafeQuickToggle extends QuickToggle { + _updateIcon() { + self.iconName = this.checked ? "channel-insecure-symbolic" : "channel-secure-symbolic" + } + + _init(onUpdate) { + super._init({ + label: ExtensionUtils.gettext("UnsafeMode"), + iconName: "channel-insecure-symbolic", + }) + this._onUpdate = onUpdate + + // Fetch global context + this._sync() + } + + // Toggle context + _toggleMode() { + this.checked = !global.context.unsafe_mode + global.context.unsafe_mode = this.checked + this._updateIcon() + this._onUpdate(this.checked) + } + + // Sync context + _sync() { + this.checked = global.context.unsafe_mode + this._updateIcon() + } + } +) diff --git a/po/en.po b/po/en.po index 750ca3b..a50c149 100644 --- a/po/en.po +++ b/po/en.po @@ -1,5 +1,9 @@ # Quick settings notifications title text -# Notifications title +#: Notifications title msgid "Notifications" msgstr "Notifications" + +#: Unsafe mode +msgid "Unsafe Mode" +msgstr "Unsafe Mode" diff --git a/schemas/org.gnome.shell.extensions.quick-settings-tweaks.gschema.xml b/schemas/org.gnome.shell.extensions.quick-settings-tweaks.gschema.xml index 8e77acb..72cb160 100644 --- a/schemas/org.gnome.shell.extensions.quick-settings-tweaks.gschema.xml +++ b/schemas/org.gnome.shell.extensions.quick-settings-tweaks.gschema.xml @@ -12,6 +12,9 @@ true + + false + true @@ -98,5 +101,10 @@ false + + + + false + From 846a2b2884d48e7a652cc29c63859663614cd01b Mon Sep 17 00:00:00 2001 From: Qwreey Date: Wed, 3 May 2023 02:10:41 +0900 Subject: [PATCH 29/33] Error fix --- features/unsafeQuickToggle.js | 6 ++++-- libs/unsafeQuickToggleHandler.js | 4 ++-- prefPages/quickToggles.js | 7 +++++++ 3 files changed, 13 insertions(+), 4 deletions(-) diff --git a/features/unsafeQuickToggle.js b/features/unsafeQuickToggle.js index 11f8aa1..d9a0749 100644 --- a/features/unsafeQuickToggle.js +++ b/features/unsafeQuickToggle.js @@ -26,7 +26,9 @@ var unsafeQuickToggleFeature = class { // disable feature reloader featureReloader.disable(this) - this.unsafeToggle.destroy() - global.context.unsafe_mode = false + if (this.unsafeToggle) { + this.unsafeToggle.destroy() + global.context.unsafe_mode = false + } } } diff --git a/libs/unsafeQuickToggleHandler.js b/libs/unsafeQuickToggleHandler.js index 47aaa4d..4d5cdaa 100644 --- a/libs/unsafeQuickToggleHandler.js +++ b/libs/unsafeQuickToggleHandler.js @@ -3,10 +3,10 @@ const { QuickToggle, SystemIndicator } = imports.ui.quickSettings const { St } = imports.gi const ExtensionUtils = imports.misc.extensionUtils -const UnsafeQuickToggle = GObject.registerClass( +var UnsafeQuickToggle = GObject.registerClass( class UnsafeQuickToggle extends QuickToggle { _updateIcon() { - self.iconName = this.checked ? "channel-insecure-symbolic" : "channel-secure-symbolic" + this.iconName = this.checked ? "channel-insecure-symbolic" : "channel-secure-symbolic" } _init(onUpdate) { diff --git a/prefPages/quickToggles.js b/prefPages/quickToggles.js index 640ae81..979bdce 100644 --- a/prefPages/quickToggles.js +++ b/prefPages/quickToggles.js @@ -30,6 +30,13 @@ var quickTogglesPage = GObject.registerClass({ value: settings.get_boolean("add-dnd-quick-toggle-enabled"), bind: [settings, "add-dnd-quick-toggle-enabled"] }) + makeSwitch({ + parent: newTogglesGroup, + title: "Unsafe Mode Quick Toggle", + subtitle: "Turn on to make the unsafe quick toggle visible on the Quick Settings panel", + value: settings.get_boolean("add-unsafe-quick-toggle-enabled"), + bind: [settings, "add-unsafe-quick-toggle-enabled"] + }) this.add(newTogglesGroup) // description / enable From 5681ab408e3eb5044e59bcc69025571fb8d87844 Mon Sep 17 00:00:00 2001 From: Qwreey Date: Wed, 3 May 2023 02:16:00 +0900 Subject: [PATCH 30/33] Add clicked connection on unsafe quick toggle --- libs/unsafeQuickToggleHandler.js | 3 +++ 1 file changed, 3 insertions(+) diff --git a/libs/unsafeQuickToggleHandler.js b/libs/unsafeQuickToggleHandler.js index 4d5cdaa..1bdfc4b 100644 --- a/libs/unsafeQuickToggleHandler.js +++ b/libs/unsafeQuickToggleHandler.js @@ -16,6 +16,9 @@ var UnsafeQuickToggle = GObject.registerClass( }) this._onUpdate = onUpdate + // bind click + this.connect("clicked", this._toggleMode.bind(this)) + // Fetch global context this._sync() } From ad6a39c221f327f95e054224739441fce948c79b Mon Sep 17 00:00:00 2001 From: Qwreey Date: Wed, 3 May 2023 02:21:16 +0900 Subject: [PATCH 31/33] Unsafe Mode locale fix (space) --- libs/unsafeQuickToggleHandler.js | 2 +- po/en.po | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/libs/unsafeQuickToggleHandler.js b/libs/unsafeQuickToggleHandler.js index 1bdfc4b..c589e6a 100644 --- a/libs/unsafeQuickToggleHandler.js +++ b/libs/unsafeQuickToggleHandler.js @@ -11,7 +11,7 @@ var UnsafeQuickToggle = GObject.registerClass( _init(onUpdate) { super._init({ - label: ExtensionUtils.gettext("UnsafeMode"), + label: ExtensionUtils.gettext("Unsafe Mode"), iconName: "channel-insecure-symbolic", }) this._onUpdate = onUpdate diff --git a/po/en.po b/po/en.po index a50c149..42482d3 100644 --- a/po/en.po +++ b/po/en.po @@ -1,9 +1,9 @@ # Quick settings notifications title text -#: Notifications title +# Notifications title msgid "Notifications" msgstr "Notifications" -#: Unsafe mode +# Unsafe mode msgid "Unsafe Mode" msgstr "Unsafe Mode" From 6e23b4187546a44552d26107d0b9547225bc3fb0 Mon Sep 17 00:00:00 2001 From: Qwreey Date: Wed, 3 May 2023 02:34:51 +0900 Subject: [PATCH 32/33] Fix clear noti button not working --- libs/notificationHandler.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libs/notificationHandler.js b/libs/notificationHandler.js index 9032a67..0377307 100644 --- a/libs/notificationHandler.js +++ b/libs/notificationHandler.js @@ -66,7 +66,7 @@ class Notifications extends St.BoxLayout{ this.datemenu = new imports.ui.dateMenu.DateMenuButton() // notifications - let messageList = this.datemenu._messageList + let messageList = this.messageList = this.datemenu._messageList this.notificationList = messageList._notificationSection this.nativeDndSwitch = messageList._dndButton this.nativeClearButton = messageList._clearButton From 2c1d345dd5bc0628a97c813f3573d7e739e462f3 Mon Sep 17 00:00:00 2001 From: Qwreey Date: Wed, 3 May 2023 02:59:41 +0900 Subject: [PATCH 33/33] Add onMenuItemAdded to fix #73 #65 --- extension.js | 20 +++++++++++++++++--- features/buttonRemover.js | 12 +++++++----- features/volumeMixer.js | 10 ++++++---- 3 files changed, 30 insertions(+), 12 deletions(-) diff --git a/extension.js b/extension.js index 24c13a6..d199c98 100644 --- a/extension.js +++ b/extension.js @@ -13,7 +13,7 @@ class Extension { // unload menu open tracker QuickSettingsGrid.disconnect(this.menuOpenTracker) - this.menuOpenTracker = null + QuickSettingsGrid.disconnect(this.menuItemAddedTracker) // unload features for (const feature of this.features) { @@ -21,7 +21,9 @@ class Extension { feature.unload() feature.settings = null } - this.features = null + + // Null out + this.menuItemAddedTracker = this.features = this.updating = this.menuOpenTracker = null logger("Diabled. " + (+new Date() - start) + "ms taken") } @@ -52,12 +54,24 @@ class Extension { } // load menu open tracker + this.updating = false this.menuOpenTracker = QuickSettingsGrid.connect("notify::mapped",()=>{ if (!QuickSettingsGrid.mapped) return - logger(`Update layout`) + this.updating = true for (const feature of this.features) { if (feature.onMenuOpen) feature.onMenuOpen() } + this.updating = false + }) + + // load menu item added tracker + this.menuItemAddedTracker = QuickSettingsGrid.connect("actor-added",()=>{ + if (this.updating) return + this.updating = true + for (const feature of this.features) { + if (feature.onMenuItemAdded) feature.onMenuItemAdded() + } + this.updating = false }) logger("Loaded. " + (+Date.now() - start) + "ms taken") diff --git a/features/buttonRemover.js b/features/buttonRemover.js index 1bf85fe..417a766 100644 --- a/features/buttonRemover.js +++ b/features/buttonRemover.js @@ -1,7 +1,5 @@ // forked from https://github.com/qwreey75/gnome-quick-settings-button-remover -// ! NEED TO REWRITE - const ExtensionUtils = imports.misc.extensionUtils const Me = ExtensionUtils.getCurrentExtension() @@ -13,6 +11,10 @@ var buttonRemoverFeature = class { this.removedItems = [] this.visibleListeners = [] } + onMenuItemAdded() { + this._unapply() + this._apply(this.userRemovedItems) + } _apply(removedItems) { for (const item of QuickSettingsGrid.get_children()) { let name = item.constructor.name.toString() @@ -50,9 +52,9 @@ var buttonRemoverFeature = class { this.settings.set_string("list-buttons",JSON.stringify(listButtons)) } - let items = this.settings.get_strv("user-removed-buttons") + let items = this.userRemovedItems = this.settings.get_strv("user-removed-buttons") if (!items) { - items = [] + items = this.userRemovedItems = [] this.settings.set_strv("user-removed-buttons",items) } @@ -61,7 +63,7 @@ var buttonRemoverFeature = class { this._removedItemsConnection = this.settings.connect('changed::user-removed-buttons', (settings, key) => { this._unapply() - this._apply(this.settings.get_strv("user-removed-buttons")) + this._apply(this.userRemovedItems = this.settings.get_strv("user-removed-buttons")) }) } unload() { diff --git a/features/volumeMixer.js b/features/volumeMixer.js index eb09e43..d74846b 100644 --- a/features/volumeMixer.js +++ b/features/volumeMixer.js @@ -8,10 +8,12 @@ const { QuickSettingsGrid } = Me.imports.libs.gnome var volumeMixerFeature = class { onMenuOpen() { // reorder on menu open - QuickSettingsGrid.set_child_below_sibling( - this.volumeMixer.actor, - this._getInputStreamSlider() - ) + if (this.volumeMixer) { + QuickSettingsGrid.set_child_below_sibling( + this.volumeMixer.actor, + this._getInputStreamSlider() + ) + } } _getInputStreamSlider() {