diff --git a/schemas/org.gnome.shell.extensions.dash-to-panel.gschema.xml b/schemas/org.gnome.shell.extensions.dash-to-panel.gschema.xml
index 092fd85..0b58223 100644
--- a/schemas/org.gnome.shell.extensions.dash-to-panel.gschema.xml
+++ b/schemas/org.gnome.shell.extensions.dash-to-panel.gschema.xml
@@ -609,14 +609,10 @@
Use favorite icons as application launchers
When the applications are ungrouped, this defines if running applications stay separate from the favorite icons.
-
- -1
+
+ ''
Primary monitor index
- Specifies the index of the primary monitor. -1 if same as gnome-shell primary monitor.
-
-
- 0
- Primary gnome-shell monitor index
+ Specifies the id of the primary monitor.
true
@@ -1308,6 +1304,10 @@
''
The preferences page name to display
+
+ false
+ Track if the preferences window is opened
+
''
Unix time when the donate icon was hidden
diff --git a/src/extension.js b/src/extension.js
index dddd08a..8486f12 100644
--- a/src/extension.js
+++ b/src/extension.js
@@ -22,6 +22,7 @@ import Gio from 'gi://Gio'
import * as Main from 'resource:///org/gnome/shell/ui/main.js'
import { EventEmitter } from 'resource:///org/gnome/shell/misc/signals.js'
import { Extension } from 'resource:///org/gnome/shell/extensions/extension.js'
+import * as PanelSettings from './panelSettings.js'
import * as PanelManager from './panelManager.js'
import * as AppIcons from './appIcons.js'
@@ -49,7 +50,7 @@ export default class DashToPanelExtension extends Extension {
PERSISTENTSTORAGE = {}
}
- enable() {
+ async enable() {
DTP_EXTENSION = this
SETTINGS = this.getSettings('org.gnome.shell.extensions.dash-to-panel')
DESKTOPSETTINGS = new Gio.Settings({
@@ -63,6 +64,14 @@ export default class DashToPanelExtension extends Extension {
//create a global object that can emit signals and conveniently expose functionalities to other extensions
global.dashToPanel = new EventEmitter()
+ // reset to be safe
+ SETTINGS.set_boolean('prefs-opened', false)
+
+ await PanelSettings.init(SETTINGS)
+
+ // To remove later, try to map settings using monitor indexes to monitor ids
+ PanelSettings.adjustMonitorSettings(SETTINGS)
+
let completeEnable = () => {
panelManager = new PanelManager.PanelManager()
panelManager.enable()
@@ -106,6 +115,7 @@ export default class DashToPanelExtension extends Extension {
disable() {
if (ubuntuDockDelayId) clearTimeout(ubuntuDockDelayId)
+ PanelSettings.disable(SETTINGS)
panelManager.disable()
DTP_EXTENSION = null
@@ -125,4 +135,10 @@ export default class DashToPanelExtension extends Extension {
Main.sessionMode.hasOverview = this._realHasOverview
}
+
+ openPreferences() {
+ if (SETTINGS.get_boolean('prefs-opened')) return
+
+ super.openPreferences()
+ }
}
diff --git a/src/panel.js b/src/panel.js
index c0fe97e..264efc6 100644
--- a/src/panel.js
+++ b/src/panel.js
@@ -490,9 +490,10 @@ export const Panel = GObject.registerClass(
}
updateElementPositions() {
- let panelPositions =
- this.panelManager.panelsElementPositions[this.monitor.index] ||
- Pos.defaults
+ let panelPositions = PanelSettings.getPanelElementPositions(
+ SETTINGS,
+ this.monitor.index,
+ )
this._updateGroupedElements(panelPositions)
diff --git a/src/panelManager.js b/src/panelManager.js
index f89b472..656d947 100755
--- a/src/panelManager.js
+++ b/src/panelManager.js
@@ -56,14 +56,12 @@ import {
export const PanelManager = class {
constructor() {
this.overview = new Overview.Overview()
- this.panelsElementPositions = {}
this._injectionManager = new InjectionManager()
-
- this._saveMonitors()
}
enable(reset) {
- let dtpPrimaryIndex = SETTINGS.get_int('primary-monitor')
+ let dtpPrimaryIndex =
+ PanelSettings.monitorIdToIndex[SETTINGS.get_string('primary-monitor')]
this.allPanels = []
this.dtpPrimaryMonitor =
@@ -210,10 +208,10 @@ export const PanelManager = class {
'changed::panel-anchors',
'changed::stockgs-keep-top-panel',
],
- (settings,settingChanged) => {
+ (settings, settingChanged) => {
PanelSettings.clearCache(settingChanged)
this._reset()
- }
+ },
],
[
SETTINGS,
@@ -221,7 +219,7 @@ export const PanelManager = class {
() => {
PanelSettings.clearCache('panel-element-positions')
this._updatePanelElementPositions()
- }
+ },
],
[
SETTINGS,
@@ -241,9 +239,9 @@ export const PanelManager = class {
[
Utils.DisplayWrapper.getMonitorManager(),
'monitors-changed',
- () => {
+ async () => {
if (Main.layoutManager.primaryMonitor) {
- this._saveMonitors()
+ await PanelSettings.setMonitorsInfo(SETTINGS)
this._reset()
}
},
@@ -492,25 +490,6 @@ export const PanelManager = class {
}
}
- _saveMonitors() {
- //Mutter meta_monitor_manager_get_primary_monitor (global.display.get_primary_monitor()) doesn't return the same
- //monitor as GDK gdk_screen_get_primary_monitor (imports.gi.Gdk.Screen.get_default().get_primary_monitor()).
- //Since the Mutter function is what's used in gnome-shell and we can't access it from the settings dialog, store
- //the monitors information in a setting so we can use the same monitor indexes as the ones in gnome-shell
- let keyPrimary = 'primary-monitor'
- let primaryIndex = Main.layoutManager.primaryIndex
- let dtpPrimaryIndex = SETTINGS.get_int(keyPrimary)
-
- if (
- !Main.layoutManager.monitors[dtpPrimaryIndex] ||
- dtpPrimaryIndex == primaryIndex
- )
- dtpPrimaryIndex = -1
-
- SETTINGS.set_int(keyPrimary, dtpPrimaryIndex)
- SETTINGS.set_int('gs-primary-monitor', primaryIndex)
- }
-
checkIfFocusedMonitor(monitor) {
return (
Main.overview._overview._controls._workspacesDisplay._primaryIndex ==
@@ -557,10 +536,6 @@ export const PanelManager = class {
}
_updatePanelElementPositions() {
- this.panelsElementPositions = PanelSettings.getSettingsJson(
- SETTINGS,
- 'panel-element-positions',
- )
this.allPanels.forEach((p) => p.updateElementPositions())
}
diff --git a/src/panelSettings.js b/src/panelSettings.js
index 88a2e11..406ddf9 100644
--- a/src/panelSettings.js
+++ b/src/panelSettings.js
@@ -15,12 +15,48 @@
* along with this program. If not, see .
*/
+import Gio from 'gi://Gio'
+
import * as Pos from './panelPositions.js'
-// cache is a different object in the settings dialog (gjs process)
+const displayConfigWrapper = Gio.DBusProxy.makeProxyWrapper(
+ `
+
+
+
+
+
+
+
+
+ `,
+)
+
+// the module variables here are different in the settings dialog (gjs process)
// and in gnome-shell (gnome-shell process)
+let displayConfigProxy = null
+let prefsOpenedId = null
+let useCache = false
let cache = {}
+export var availableMonitors = []
+export var monitorIdToIndex = {}
+export var monitorIndexToId = {}
+
+export async function init(settings) {
+ useCache = true
+ prefsOpenedId = settings.connect(
+ 'changed::prefs-opened',
+ () => (useCache = !settings.get_boolean('prefs-opened')),
+ )
+
+ await setMonitorsInfo(settings)
+}
+
+export async function disable(settings) {
+ settings.disconnect(prefsOpenedId)
+}
+
export function clearCache(setting) {
if (setting) {
cache[setting] = null
@@ -33,8 +69,7 @@ export function clearCache(setting) {
/** Return object representing a settings value that is stored as JSON. */
export function getSettingsJson(settings, setting) {
try {
- if (cache[setting])
- return cache[setting]
+ if (useCache && cache[setting]) return cache[setting]
let res = JSON.parse(settings.get_string(setting))
@@ -56,13 +91,38 @@ export function setSettingsJson(settings, setting, value) {
}
}
+// Previously, the monitor index was used as an id to persist per monitor
+// settings. Since these indexes are unreliable AF, switch to use the monitor
+// serial as its id while keeping it backward compatible.
+function getMonitorSetting(settings, settingName, monitorIndex, fallback) {
+ let monitorId = monitorIndexToId[monitorIndex]
+
+ settings = getSettingsJson(settings, settingName)
+
+ return settings[monitorId] || settings[monitorIndex] || fallback
+}
+
+function setMonitorSetting(settings, settingName, monitorIndex, value) {
+ let monitorId = monitorIndexToId[monitorIndex]
+ let usedId = monitorId || monitorIndex
+
+ let currentSettings = getSettingsJson(settings, settingName)
+
+ if (monitorId) delete currentSettings[monitorIndex]
+
+ currentSettings[usedId] = value
+ setSettingsJson(settings, settingName, currentSettings)
+}
+
/** Returns size of panel on a specific monitor, in pixels. */
export function getPanelSize(settings, monitorIndex) {
- const sizes = getSettingsJson(settings, 'panel-sizes')
// Pull in deprecated setting if panel-sizes does not have setting for monitor.
- const fallbackSize = settings.get_int('panel-size')
- const theDefault = 48
- return sizes[monitorIndex] || fallbackSize || theDefault
+ return getMonitorSetting(
+ settings,
+ 'panel-sizes',
+ monitorIndex,
+ settings.get_int('panel-size') || 48,
+ )
}
export function setPanelSize(settings, monitorIndex, value) {
@@ -70,9 +130,8 @@ export function setPanelSize(settings, monitorIndex, value) {
console.log('Not setting invalid panel size: ' + value)
return
}
- let sizes = getSettingsJson(settings, 'panel-sizes')
- sizes[monitorIndex] = value
- setSettingsJson(settings, 'panel-sizes', sizes)
+
+ setMonitorSetting(settings, 'panel-sizes', monitorIndex, value)
}
/**
@@ -80,9 +139,7 @@ export function setPanelSize(settings, monitorIndex, value) {
* from settings. e.g. 100
*/
export function getPanelLength(settings, monitorIndex) {
- const lengths = getSettingsJson(settings, 'panel-lengths')
- const theDefault = 100
- return lengths[monitorIndex] || theDefault
+ return getMonitorSetting(settings, 'panel-lengths', monitorIndex, 100)
}
export function setPanelLength(settings, monitorIndex, value) {
@@ -90,17 +147,18 @@ export function setPanelLength(settings, monitorIndex, value) {
console.log('Not setting invalid panel length: ' + value)
return
}
- let lengths = getSettingsJson(settings, 'panel-lengths')
- lengths[monitorIndex] = value
- setSettingsJson(settings, 'panel-lengths', lengths)
+
+ setMonitorSetting(settings, 'panel-lengths', monitorIndex, value)
}
/** Returns position of panel on a specific monitor. */
export function getPanelPosition(settings, monitorIndex) {
- const positions = getSettingsJson(settings, 'panel-positions')
- const fallbackPosition = settings.get_string('panel-position')
- const theDefault = Pos.BOTTOM
- return positions[monitorIndex] || fallbackPosition || theDefault
+ return getMonitorSetting(
+ settings,
+ 'panel-positions',
+ monitorIndex,
+ settings.get_string('panel-position') || Pos.BOTTOM,
+ )
}
export function setPanelPosition(settings, monitorIndex, value) {
@@ -115,16 +173,13 @@ export function setPanelPosition(settings, monitorIndex, value) {
console.log('Not setting invalid panel position: ' + value)
return
}
- const positions = getSettingsJson(settings, 'panel-positions')
- positions[monitorIndex] = value
- setSettingsJson(settings, 'panel-positions', positions)
+
+ setMonitorSetting(settings, 'panel-positions', monitorIndex, value)
}
/** Returns anchor location of panel on a specific monitor. */
export function getPanelAnchor(settings, monitorIndex) {
- const anchors = getSettingsJson(settings, 'panel-anchors')
- const theDefault = Pos.MIDDLE
- return anchors[monitorIndex] || theDefault
+ return getMonitorSetting(settings, 'panel-anchors', monitorIndex, Pos.MIDDLE)
}
export function setPanelAnchor(settings, monitorIndex, value) {
@@ -132,7 +187,109 @@ export function setPanelAnchor(settings, monitorIndex, value) {
console.log('Not setting invalid panel anchor: ' + value)
return
}
- const anchors = getSettingsJson(settings, 'panel-anchors')
- anchors[monitorIndex] = value
- setSettingsJson(settings, 'panel-anchors', anchors)
+
+ setMonitorSetting(settings, 'panel-anchors', monitorIndex, value)
+}
+
+export function getPanelElementPositions(settings, monitorIndex) {
+ return getMonitorSetting(
+ settings,
+ 'panel-element-positions',
+ monitorIndex,
+ Pos.defaults,
+ )
+}
+
+export function setPanelElementPositions(settings, monitorIndex, value) {
+ setMonitorSetting(settings, 'panel-element-positions', monitorIndex, value)
+}
+
+export async function setMonitorsInfo(settings) {
+ return new Promise((resolve, reject) => {
+ try {
+ let monitorInfos = []
+ let saveMonitorState = (proxy) => {
+ proxy.GetCurrentStateRemote((displayInfo, e) => {
+ if (e) return reject(`Error getting display state: ${e}`)
+
+ let gsPrimaryIndex = 0
+
+ //https://gitlab.gnome.org/GNOME/mutter/-/blob/main/data/dbus-interfaces/org.gnome.Mutter.DisplayConfig.xml#L347
+ displayInfo[2].forEach((logicalMonitor, i) => {
+ let id = logicalMonitor[5][0][3]
+ let primary = logicalMonitor[4]
+
+ if (primary) gsPrimaryIndex = i
+
+ monitorInfos.push({
+ id,
+ name: logicalMonitor[5][0][2],
+ primary,
+ })
+
+ monitorIdToIndex[id] = i
+ monitorIndexToId[i] = id
+ })
+
+ _saveMonitors(settings, monitorInfos, gsPrimaryIndex)
+
+ resolve()
+ })
+ }
+
+ if (!displayConfigProxy)
+ displayConfigProxy = new displayConfigWrapper(
+ Gio.DBus.session,
+ 'org.gnome.Mutter.DisplayConfig',
+ '/org/gnome/Mutter/DisplayConfig',
+ (proxy, e) => {
+ if (e) return reject(`Error creating display proxy: ${e}`)
+
+ saveMonitorState(proxy)
+ },
+ )
+ else saveMonitorState(displayConfigProxy)
+ } catch (e) {
+ reject(e)
+ }
+ })
+}
+
+function _saveMonitors(settings, monitorInfos, gsPrimaryIndex) {
+ let keyPrimary = 'primary-monitor'
+ let dtpPrimaryMonitor = settings.get_string(keyPrimary)
+
+ // convert previously saved index to monitor id
+ if (dtpPrimaryMonitor.match(/^\d{1,2}$/))
+ dtpPrimaryMonitor = monitorInfos[dtpPrimaryMonitor]?.id
+
+ // default to gnome-shell primary monitor
+ if (!dtpPrimaryMonitor) dtpPrimaryMonitor = monitorInfos[gsPrimaryIndex]?.id
+
+ settings.set_string(keyPrimary, dtpPrimaryMonitor)
+ availableMonitors = Object.freeze(monitorInfos)
+}
+
+// this is for backward compatibility, to remove in a few versions
+export function adjustMonitorSettings(settings) {
+ let updateSettings = (settingName) => {
+ let monitorSettings = getSettingsJson(settings, settingName)
+ let updatedSettings = {}
+
+ Object.keys(monitorSettings).forEach((key) => {
+ let initialKey = key
+
+ if (key.match(/^\d{1,2}$/)) key = monitorIndexToId[key] || key
+
+ updatedSettings[key] = monitorSettings[initialKey]
+ })
+
+ setSettingsJson(settings, settingName, updatedSettings)
+ }
+
+ updateSettings('panel-sizes')
+ updateSettings('panel-lengths')
+ updateSettings('panel-positions')
+ updateSettings('panel-anchors')
+ updateSettings('panel-element-positions')
}
diff --git a/src/prefs.js b/src/prefs.js
index cd2e0fa..d479e5e 100644
--- a/src/prefs.js
+++ b/src/prefs.js
@@ -290,7 +290,7 @@ const Preferences = class {
)
let topAvailable =
!keepTopPanel ||
- (!monitorSync && this._currentMonitorIndex != this.monitors[0])
+ (!monitorSync && !this.monitors[this._currentMonitorIndex].primary)
let topRadio = this._builder.get_object('position_top_button')
topRadio.set_sensitive(topAvailable)
@@ -310,7 +310,7 @@ const Preferences = class {
'panel-element-positions-monitors-sync',
)
const monitorsToSetFor = monitorSync
- ? this.monitors
+ ? Object.keys(this.monitors)
: [this._currentMonitorIndex]
monitorsToSetFor.forEach((monitorIndex) => {
PanelSettings.setPanelPosition(this._settings, monitorIndex, position)
@@ -447,18 +447,16 @@ const Preferences = class {
let labels = {}
let panelPosition = this._getPanelPosition(monitorIndex)
let isVertical = panelPosition == Pos.LEFT || panelPosition == Pos.RIGHT
- let panelElementPositionsSettings = PanelSettings.getSettingsJson(
+ let panelElementPositions = PanelSettings.getPanelElementPositions(
this._settings,
- 'panel-element-positions',
+ monitorIndex,
)
- let panelElementPositions =
- panelElementPositionsSettings[monitorIndex] || Pos.defaults
let updateElementsSettings = () => {
let newPanelElementPositions = []
let monitorSync = this._settings.get_boolean(
'panel-element-positions-monitors-sync',
)
- let monitors = monitorSync ? this.monitors : [monitorIndex]
+ let monitors = monitorSync ? Object.keys(this.monitors) : [monitorIndex]
let child = taskbarListBox.get_first_child()
while (child != null) {
@@ -470,13 +468,12 @@ const Preferences = class {
child = child.get_next_sibling()
}
- monitors.forEach(
- (m) => (panelElementPositionsSettings[m] = newPanelElementPositions),
- )
- PanelSettings.setSettingsJson(
- this._settings,
- 'panel-element-positions',
- panelElementPositionsSettings,
+ monitors.forEach((m) =>
+ PanelSettings.setPanelElementPositions(
+ this._settings,
+ m,
+ newPanelElementPositions,
+ ),
)
}
@@ -1235,24 +1232,11 @@ const Preferences = class {
})
//multi-monitor
- this.monitors = []
+ this.monitors = PanelSettings.availableMonitors
- for (
- let i = 0;
- i < Gdk.Display.get_default().get_monitors().get_n_items();
- ++i
- ) {
- this.monitors.push(i)
- }
-
- let primaryMonitorIndex = this._settings.get_int('gs-primary-monitor')
- let dtpPrimaryMonitorIndex = this.monitors.indexOf(
- this._settings.get_int('primary-monitor'),
- )
-
- if (dtpPrimaryMonitorIndex < 0) {
- dtpPrimaryMonitorIndex = primaryMonitorIndex
- }
+ let dtpPrimaryMonitorId = this._settings.get_string('primary-monitor')
+ let dtpPrimaryMonitorIndex =
+ PanelSettings.monitorIdToIndex[dtpPrimaryMonitorId]
this._currentMonitorIndex = dtpPrimaryMonitorIndex
@@ -1262,10 +1246,12 @@ const Preferences = class {
this._updateVerticalRelatedOptions()
for (let i = 0; i < this.monitors.length; ++i) {
- let label =
- i == primaryMonitorIndex
- ? _('Primary monitor')
- : _('Monitor ') + (i + 1)
+ let monitor = this.monitors[i]
+ let label = monitor.primary
+ ? _('Primary monitor')
+ : _('Monitor ') + (i + 1)
+
+ label += monitor.name ? ` (${monitor.name})` : ''
this._builder.get_object('multimon_primary_combo').append_text(label)
this._builder
@@ -1306,16 +1292,16 @@ const Preferences = class {
this._builder
.get_object('multimon_primary_combo')
.connect('changed', (widget) => {
- this._settings.set_int(
+ this._settings.set_string(
'primary-monitor',
- this.monitors[widget.get_active()],
+ this.monitors[widget.get_active()].id,
)
})
this._builder
.get_object('taskbar_position_monitor_combo')
.connect('changed', (widget) => {
- this._currentMonitorIndex = this.monitors[widget.get_active()]
+ this._currentMonitorIndex = widget.get_active()
this._updateWidgetSettingsForMonitor(this._currentMonitorIndex)
})
@@ -1337,7 +1323,7 @@ const Preferences = class {
'panel-element-positions-monitors-sync',
)
const monitorsToSetFor = monitorSync
- ? this.monitors
+ ? Object.keys(this.monitors)
: [this._currentMonitorIndex]
monitorsToSetFor.forEach((monitorIndex) => {
PanelSettings.setPanelLength(this._settings, monitorIndex, value)
@@ -1356,7 +1342,7 @@ const Preferences = class {
'panel-element-positions-monitors-sync',
)
const monitorsToSetFor = monitorSync
- ? this.monitors
+ ? Object.keys(this.monitors)
: [this._currentMonitorIndex]
monitorsToSetFor.forEach((monitorIndex) => {
PanelSettings.setPanelAnchor(this._settings, monitorIndex, value)
@@ -3861,7 +3847,9 @@ const BuilderScope = GObject.registerClass(
)
export default class DashToPanelPreferences extends ExtensionPreferences {
- fillPreferencesWindow(window) {
+ async fillPreferencesWindow(window) {
+ let closeRequestId = null
+
window._settings = this.getSettings(
'org.gnome.shell.extensions.dash-to-panel',
)
@@ -3869,6 +3857,14 @@ export default class DashToPanelPreferences extends ExtensionPreferences {
// use default width or window
window.set_default_size(0, 740)
+ window._settings.set_boolean('prefs-opened', true)
+ closeRequestId = window.connect('close-request', () => {
+ window._settings.set_boolean('prefs-opened', false)
+ window.disconnect(closeRequestId)
+ })
+
+ await PanelSettings.setMonitorsInfo(window._settings)
+
new Preferences(window, window._settings, this.path)
}
}
diff --git a/src/taskbar.js b/src/taskbar.js
index ed86bdc..a791ee4 100644
--- a/src/taskbar.js
+++ b/src/taskbar.js
@@ -1732,10 +1732,10 @@ export const TaskbarItemContainer = GObject.registerClass(
else return
let panelPosition = this._dtpPanel.getPosition()
- let panelElementPositions =
- this._dtpPanel.panelManager.panelsElementPositions[
- this._dtpPanel.monitor.index
- ] || Pos.defaults
+ let panelElementPositions = PanelSettings.getPanelElementPositions(
+ SETTINGS,
+ this._dtpPanel.monitor.index,
+ )
let taskbarPosition = panelElementPositions.filter(
(pos) => pos.element == 'taskbar',
)[0].position