From f162ac0624a23055635ee8e3c5fa4a2de1901e2f Mon Sep 17 00:00:00 2001 From: Charles Gagnon Date: Mon, 10 Feb 2025 15:01:52 -0500 Subject: [PATCH] Centralize notifications state --- src/appIcons.js | 122 +++++++++++++++--------------------- src/notificationsMonitor.js | 50 +++++++++++---- src/stylesheet.css | 3 + src/taskbar.js | 4 +- 4 files changed, 95 insertions(+), 84 deletions(-) diff --git a/src/appIcons.js b/src/appIcons.js index 9009258..4fcc206 100644 --- a/src/appIcons.js +++ b/src/appIcons.js @@ -120,7 +120,6 @@ export const TaskbarAppIcon = GObject.registerClass( _init(appInfo, panel, iconParams, previewMenu, iconAnimator) { this.dtpPanel = panel this._nWindows = 0 - this._notifications = {} this.window = appInfo.window this.isLauncher = appInfo.isLauncher this._previewMenu = previewMenu @@ -223,6 +222,11 @@ export const TaskbarAppIcon = GObject.registerClass( this._numberOverlay() this._signalsHandler.add( + [ + this, + 'notify::mapped', + () => (this.mapped ? this._handleNotifications() : null), + ], [ Utils.getStageTheme(), 'changed', @@ -300,6 +304,11 @@ export const TaskbarAppIcon = GObject.registerClass( `update-${this.app.id}`, this._handleNotifications.bind(this), ], + [ + SETTINGS, + 'changed::progress-show-count', + this._handleNotifications.bind(this), + ], [ SETTINGS, 'changed::animate-appicon-hover', @@ -1599,67 +1608,49 @@ export const TaskbarAppIcon = GObject.registerClass( cr.$dispose() } - _handleNotifications(notificationsMonitor, state) { - if (!this._nWindows && !this.window) { - delete this._notifications.total - return - } + _handleNotifications() { + if (!this._nWindows && !this.window) return - let urgent = - 'urgent' in state ? state.urgent : this._notifications.urgent || false - let formatCount = (count) => { - if (!count) return 0 + let monitor = this.dtpPanel.panelManager.notificationsMonitor + let state = monitor.getState(this.app) + let count = 0 - return count > 10 ? '10+' : count - } + if (!state) return - if ('count-visible' in state) - this._notifications.countVisible = state['count-visible'] - - if ('count' in state) this._notifications.count = state.count - - if ('trayCount' in state) - this._notifications.trayCount = this._checkIfFocusedApp() - ? 0 - : state.trayCount - - this._notifications.total = - SETTINGS.get_boolean('progress-show-count') && - ((this._notifications.countVisible || 0) && - (this._notifications.count || 0)) + - (this._notifications.trayCount || 0) - - urgent = urgent && !!this._notifications.total - - if (urgent !== this._notifications.urgent) - this.iconAnimator[`${urgent ? 'add' : 'remove'}Animation`]( + if (SETTINGS.get_boolean('progress-show-count')) { + this.iconAnimator[`${state.urgent ? 'add' : 'remove'}Animation`]( this.icon._iconBin, 'dance', ) - this._notifications.urgent = urgent + if (state.total) count = state.total > 9 ? '9+' : state.total + } - // restore hotkeys number if no more notifications - this._maybeToggleNumberOverlay( - formatCount(this._notifications.total) || - this._numberHotkeysOverlayLabel, - ) + this._notificationsCount = count + + this._maybeUpdateNumberOverlay() } - _maybeToggleNumberOverlay(labelNumber) { + _maybeUpdateNumberOverlay() { let visible = this._numberOverlayBin.visible let shouldBeVisible = - this._hotkeysOverlayActive || this._notifications.total + (this._hotkeysOverlayActiveMode && + this._numberHotkeysOverlayLabel > -1) || + this._notificationsCount + + let showNotifications = + this._notificationsCount && + this._hotkeysOverlayActiveMode !== 'TEMPORARILY' + let label = showNotifications + ? this._notificationsCount + : this._numberHotkeysOverlayLabel this._numberOverlayLabel[ - `${this._notifications.total ? 'add' : 'remove'}_style_class_name` + `${showNotifications ? 'add' : 'remove'}_style_class_name` ]('notification-badge') - if ( - shouldBeVisible && - labelNumber != this._numberOverlayLabel.get_text() - ) { - this._numberOverlayLabel.set_text(labelNumber.toString()) + if (shouldBeVisible && label !== this._numberOverlayLabel.get_text()) { + this._numberOverlayLabel.set_text(label.toString()) this._updateNumberOverlay() } @@ -1687,28 +1678,16 @@ export const TaskbarAppIcon = GObject.registerClass( // pixels, so make sure to consider the scale. // Set the font size to something smaller than the whole icon so it is // still visible. The border radius is large to make the shape circular - let [, natWidth] = this._dtpIconContainer.get_preferred_width(-1) - let font_size = Math.round( - Math.max(12, 0.3 * natWidth) / Utils.getScaleFactor(), + let panelSize = + this.dtpPanel.geom[this.dtpPanel.checkIfVertical() ? 'w' : 'h'] + let fontSize = Math.round( + Math.max(10, 0.3 * panelSize) / Utils.getScaleFactor(), ) - let size = Math.round(font_size * 1.3) - let style = - 'font-size: ' + - font_size + - 'px;' + - 'border-radius: ' + - this.icon.iconSize + - 'px;' + - 'height: ' + - size + - 'px;' - - if (this._numberOverlayLabel.get_text().length == 1) { - style += 'width: ' + size + 'px;' - } else { - style += 'padding: 0 2px;' - } - + let size = Math.round(fontSize * 1.3) + let style = ` + font-size: ${fontSize}px; + height: ${size}px; + ` this._numberOverlayLabel.set_style(style) } @@ -1716,12 +1695,11 @@ export const TaskbarAppIcon = GObject.registerClass( this._numberHotkeysOverlayLabel = number } - toggleHotkeysNumberOverlay(activate) { - this._hotkeysOverlayActive = - activate && this._numberHotkeysOverlayLabel > -1 + toggleHotkeysNumberOverlay(activateMode) { + this._hotkeysOverlayActiveMode = + this._numberHotkeysOverlayLabel > -1 && activateMode - if (!this._notifications.total) - this._maybeToggleNumberOverlay(this._numberHotkeysOverlayLabel) + this._maybeUpdateNumberOverlay() } handleDragOver(source) { diff --git a/src/notificationsMonitor.js b/src/notificationsMonitor.js index 803685b..45f4411 100644 --- a/src/notificationsMonitor.js +++ b/src/notificationsMonitor.js @@ -33,6 +33,7 @@ export const NotificationsMonitor = class extends EventEmitter { constructor() { super() + this._state = {} this._signalsHandler = new Utils.GlobalSignalsHandler() // pretty much useless, but might as well keep it for now @@ -59,7 +60,7 @@ export const NotificationsMonitor = class extends EventEmitter { () => { // reset notifications from message tray on app focus if (tracker.focus_app) - this.dispatch(tracker.focus_app.id, { trayCount: 0 }, true) + this._updateState(tracker.focus_app.id, { trayCount: 0 }, true) }, ]) this._acquireUnityDBus() @@ -75,10 +76,11 @@ export const NotificationsMonitor = class extends EventEmitter { this._signalsHandler.destroy() } - dispatch(appId, state, ignoreMapping) { + _updateState(appId, state, ignoreMapping) { // depending of the notification source, some app id end // with ".desktop" and some don't ¯\_(ツ)_/¯ appId = appId.replace('.desktop', '') + appId = `${appId}.desktop` // some app have different source app id, deamon and such, // but it maps to a desktop app so match those here @@ -88,7 +90,29 @@ export const NotificationsMonitor = class extends EventEmitter { knownCorrespondances[k].some((regex) => appId.match(regex)), ) || appId - this.emit(`update-${appId}.desktop`, state) + this._state[appId] = this._state[appId] || {} + this._mergeState(appId, state) + + this.emit(`update-${appId}`) + } + + getState(app) { + return this._state[app.id] + } + + _mergeState(appId, state) { + this._state[appId] = Object.assign(this._state[appId], state) + + if (tracker.focus_app?.id == appId) this._state[appId].trayCount = 0 + + this._state[appId].urgent = + state.urgent || + (this._state[appId].trayUrgent && this._state[appId].trayCount) || + false + + this._state[appId].total = + ((this._state[appId]['count-visible'] || 0) && + (this._state[appId].count || 0)) + (this._state[appId].trayCount || 0) } _acquireUnityDBus() { @@ -120,26 +144,30 @@ export const NotificationsMonitor = class extends EventEmitter { for (let property in properties) updates[property] = properties[property].unpack() - this.dispatch(appId, updates) + this._updateState(appId, updates) } _checkNotifications() { let addSource = (tray, source) => { let appId = source?._appId || source?.app?.id + let updateTray = () => { + this._updateState(appId, { + trayCount: source.count, // always source.unseenCount might be less annoying + trayUrgent: !!source.notifications.find( + (n) => n.urgency > MessageTray.Urgency.NORMAL, + ), + }) + } if (!appId) return this._signalsHandler.addWithLabel(appId, [ source, 'notify::count', - () => - this.dispatch(appId, { - trayCount: source.count, // source.unseenCount might be less annoying - urgent: !!source.notifications.find( - (n) => n.urgency > MessageTray.Urgency.NORMAL, - ), - }), + updateTray, ]) + + updateTray() } this._signalsHandler.add( diff --git a/src/stylesheet.css b/src/stylesheet.css index 96fb7c9..4f6efe2 100644 --- a/src/stylesheet.css +++ b/src/stylesheet.css @@ -144,8 +144,11 @@ #dashtopanelScrollview .badge { color: rgba(255, 255, 255, 1); + padding: 0.2em 0.5em; + border-radius: 1em; font-weight: bold; text-align: center; + margin: 0 0 0 2px; } #dashtopanelScrollview .number-overlay { diff --git a/src/taskbar.js b/src/taskbar.js index d66a993..c785f35 100644 --- a/src/taskbar.js +++ b/src/taskbar.js @@ -1303,7 +1303,9 @@ export const Taskbar = class extends EventEmitter { toggleHotkeysNumberOverlay(activate) { let appIcons = this._getAppIcons() appIcons.forEach(function (icon) { - icon.toggleHotkeysNumberOverlay(activate) + icon.toggleHotkeysNumberOverlay( + activate ? SETTINGS.get_string('hotkeys-overlay-combo') : false, + ) }) }