diff --git a/data/theme/cinnamon-sass/_colors.scss b/data/theme/cinnamon-sass/_colors.scss index c9f18d40d4..3cdde45a0d 100644 --- a/data/theme/cinnamon-sass/_colors.scss +++ b/data/theme/cinnamon-sass/_colors.scss @@ -20,6 +20,7 @@ $warning_bg_color: #cd9309; $accent_color: #78aeed; $accent_bg_color: #3584e4; +$accent_bg_color_alternative: #d035e4; $large_icon_color: transparentize($fg_color, 0.6); $light_text_color: mix($fg_color, $bg_color, 65%); diff --git a/data/theme/cinnamon-sass/widgets/_windowlist.scss b/data/theme/cinnamon-sass/widgets/_windowlist.scss index 4c8028e0d2..03e6942ff3 100644 --- a/data/theme/cinnamon-sass/widgets/_windowlist.scss +++ b/data/theme/cinnamon-sass/widgets/_windowlist.scss @@ -73,14 +73,24 @@ &-button-label { padding-left: 4px;} - &-number-label { - font-size: 0.8em; + &-windows-badge { + border-radius: 9999px; + color: $fg_color; + background-color: $accent_bg_color; + } + + &-windows-badge-label { z-index: 99; } - &-badge { + &-notifications-badge { border-radius: 9999px; - background-color: $bg_color; + color: $fg_color; + background-color: $accent_bg_color_alternative; + } + + &-notifications-badge-label { + z-index: 99; } } diff --git a/files/usr/share/cinnamon/applets/grouped-window-list@cinnamon.org/appGroup.js b/files/usr/share/cinnamon/applets/grouped-window-list@cinnamon.org/appGroup.js index 6a0f0990c5..21c1e6f7dc 100644 --- a/files/usr/share/cinnamon/applets/grouped-window-list@cinnamon.org/appGroup.js +++ b/files/usr/share/cinnamon/applets/grouped-window-list@cinnamon.org/appGroup.js @@ -70,6 +70,7 @@ class AppGroup { appInfo: params.app.get_app_info(), metaWindows: params.metaWindows || [], windowCount: params.metaWindows ? params.metaWindows.length : 0, + notificationCount: 0, lastFocused: params.metaWindow || null, isFavoriteApp: !params.metaWindow ? true : params.isFavoriteApp === true, autoStartIndex: this.state.autoStartApps.findIndex( app => app.id === params.appId), @@ -119,31 +120,50 @@ class AppGroup { }); this.actor.add_child(this.progressOverlay); - // Create the app button icon, number label, and text label for titleDisplay + // Create the app button icon, window count and notification badges, and text label for titleDisplay this.iconBox = new Cinnamon.Slicer({name: 'appMenuIcon'}); this.actor.add_child(this.iconBox); this.setActorAttributes(null, params.metaWindow); - this.badge = new St.BoxLayout({ - style_class: 'grouped-window-list-badge', + this.windowsBadge = new St.BoxLayout({ + style_class: 'grouped-window-list-windows-badge', important: true, + x_align: St.Align.MIDDLE, + y_align: St.Align.MIDDLE, + show_on_set_parent: false, + }); + this.windowsBadgeLabel = new St.Label({ + style_class: 'grouped-window-list-windows-badge-label', + important: true, + text: '' + }); + this.windowsBadgeLabel.clutter_text.ellipsize = false; + this.windowsBadge.add(this.windowsBadgeLabel, { x_align: St.Align.START, + y_align: St.Align.START, + }); + this.actor.add_child(this.windowsBadge); + this.windowsBadge.set_text_direction(St.TextDirection.LTR); + + this.notificationsBadge = new St.BoxLayout({ + style_class: 'grouped-window-list-notifications-badge', + important: true, + x_align: St.Align.MIDDLE, y_align: St.Align.MIDDLE, show_on_set_parent: false, }); - this.numberLabel = new St.Label({ - style_class: 'grouped-window-list-number-label', + this.notificationsBadgeLabel = new St.Label({ + style_class: 'grouped-window-list-notifications-badge-label', important: true, - text: '', - anchor_x: -3 * global.ui_scale, + text: '' }); - this.numberLabel.clutter_text.ellipsize = false; - this.badge.add(this.numberLabel, { + this.notificationsBadgeLabel.clutter_text.ellipsize = false; + this.notificationsBadge.add(this.notificationsBadgeLabel, { x_align: St.Align.START, y_align: St.Align.START, }); - this.actor.add_child(this.badge); - this.badge.set_text_direction(St.TextDirection.LTR); + this.actor.add_child(this.notificationsBadge); + this.notificationsBadge.set_text_direction(St.TextDirection.LTR); this.label = new St.Label({ style_class: 'grouped-window-list-button-label', @@ -394,15 +414,23 @@ class AppGroup { this.iconBox.allocate(childBox, flags); - // Set badge position - const windowCountFactor = this.groupState.windowCount > 9 ? 1.5 : 2; - const badgeOffset = 2 * global.ui_scale; - childBox.x1 = childBox.x1 - badgeOffset; - childBox.x2 = childBox.x1 + (this.numberLabel.width * windowCountFactor); - childBox.y1 = Math.max(childBox.y1 - badgeOffset, 0); - childBox.y2 = childBox.y1 + this.badge.get_preferred_height(childBox.get_width())[1]; + this.updateBadgesTextSize(); + + // Set windows badge position + childBox.x1 = box.x1; + childBox.x2 = childBox.x1 + this.windowsBadgeLabel.width; + childBox.y1 = box.y1; + childBox.y2 = childBox.y1 + this.windowsBadge.get_preferred_height(childBox.get_width())[1]; + + this.windowsBadge.allocate(childBox, flags); - this.badge.allocate(childBox, flags); + // Set notifications badge position + childBox.x2 = box.x2; + childBox.x1 = childBox.x2 - this.notificationsBadgeLabel.width; + childBox.y1 = box.y1; + childBox.y2 = childBox.y1 + this.notificationsBadge.get_preferred_height(childBox.get_width())[1]; + + this.notificationsBadge.allocate(childBox, flags); // Set label position if (this.drawLabel) { @@ -450,6 +478,14 @@ class AppGroup { if (this.progressOverlay.visible) this.allocateProgress(childBox, flags); } + updateBadgesTextSize() { + const badgeTextSize = Math.round(this.iconBox.width / 2.5 / global.ui_scale); + const badgePadding = Math.round(badgeTextSize / 4); + const sizeStyle = `font-size: ${badgeTextSize}px; padding-left: ${badgePadding}px; padding-right: ${badgePadding}px;`; + this.windowsBadgeLabel.set_style(sizeStyle); + this.notificationsBadgeLabel.set_style(sizeStyle); + } + showLabel(animate = false) { if (this.labelVisiblePref || !this.label @@ -676,8 +712,8 @@ class AppGroup { } showOrderLabel(number) { - this.numberLabel.text = (number + 1).toString(); - this.badge.show(); + this.windowsBadgeLabel.text = (number + 1).toString(); + this.windowsBadge.show(); } launchNewInstance(offload=false) { @@ -917,6 +953,7 @@ class AppGroup { this.setIcon(metaWindow) this.calcWindowNumber(); + this.updateNotificationsBadge(); this.onFocusChange(); } set({ @@ -1071,23 +1108,42 @@ class AppGroup { this.checkFocusStyle(); } - calcWindowNumber() { + incrementNotificationCount() { if (this.groupState.willUnmount) return; - const windowCount = this.groupState.metaWindows ? this.groupState.metaWindows.length : 0; - this.numberLabel.text = windowCount.toString(); + this.groupState.set({ notificationCount: this.groupState.notificationCount + 1 }); + this.updateNotificationsBadge(); + } - this.groupState.set({windowCount}); + resetNotificationCount() { + if (this.groupState.willUnmount) return; + + this.groupState.set({ notificationCount : 0 }); + this.updateNotificationsBadge(); + } - if (this.state.settings.numDisplay) { - if (windowCount <= 1) { - this.badge.hide(); - } else { - this.badge.show(); + calcWindowNumber() { + if (this.groupState.willUnmount) return; - } + this.groupState.set({windowCount: this.groupState.metaWindows ? this.groupState.metaWindows.length : 0}); + this.updateWindowsBadge(); + } + + updateWindowsBadge(){ + if (this.groupState.windowCount > 1) { + this.windowsBadgeLabel.text = this.groupState.windowCount.toString(); + this.windowsBadge.show(); + } else { + this.windowsBadge.hide(); + } + } + + updateNotificationsBadge(){ + if (this.groupState.notificationCount > 0) { + this.notificationsBadgeLabel.text = this.groupState.notificationCount.toString(); + this.notificationsBadge.show(); } else { - this.badge.hide(); + this.notificationsBadge.hide(); } } diff --git a/files/usr/share/cinnamon/applets/grouped-window-list@cinnamon.org/applet.js b/files/usr/share/cinnamon/applets/grouped-window-list@cinnamon.org/applet.js index 75d1c85208..35bfc3dee7 100644 --- a/files/usr/share/cinnamon/applets/grouped-window-list@cinnamon.org/applet.js +++ b/files/usr/share/cinnamon/applets/grouped-window-list@cinnamon.org/applet.js @@ -307,7 +307,6 @@ class GroupedWindowListApplet extends Applet.Applet { {key: 'super-num-hotkeys', value: 'SuperNumHotkeys', cb: this.bindAppKeys}, {key: 'title-display', value: 'titleDisplay', cb: this.updateTitleDisplay}, {key: 'launcher-animation-effect', value: 'launcherAnimationEffect', cb: null}, - {key: 'number-display', value: 'numDisplay', cb: this.updateWindowNumberState}, {key: 'enable-app-button-dragging', value: 'enableDragging', cb: this.draggableSettingChanged}, {key: 'thumbnail-scroll-behavior', value: 'thumbnailScrollBehavior', cb: null}, {key: 'show-thumbnails', value: 'showThumbs', cb: this.updateVerticalThumbnailState}, @@ -584,12 +583,6 @@ class GroupedWindowListApplet extends Applet.Applet { }); } - updateWindowNumberState() { - this.workspaces.forEach( - workspace => workspace.calcAllWindowNumbers() - ); - } - updateAttentionState(display, window) { this.workspaces.forEach( workspace => workspace.updateAttentionState(display, window) diff --git a/files/usr/share/cinnamon/applets/grouped-window-list@cinnamon.org/settings-schema.json b/files/usr/share/cinnamon/applets/grouped-window-list@cinnamon.org/settings-schema.json index b86af45073..2715fd70d1 100644 --- a/files/usr/share/cinnamon/applets/grouped-window-list@cinnamon.org/settings-schema.json +++ b/files/usr/share/cinnamon/applets/grouped-window-list@cinnamon.org/settings-schema.json @@ -50,7 +50,6 @@ "keys": [ "title-display", "launcher-animation-effect", - "number-display", "enable-app-button-dragging" ] }, @@ -184,11 +183,6 @@ "Scale": 3 } }, - "number-display": { - "type": "checkbox", - "default": true, - "description": "Show window count numbers" - }, "enable-app-button-dragging": { "type": "checkbox", "default": true, diff --git a/files/usr/share/cinnamon/applets/grouped-window-list@cinnamon.org/workspace.js b/files/usr/share/cinnamon/applets/grouped-window-list@cinnamon.org/workspace.js index 4329489297..974cb4919b 100644 --- a/files/usr/share/cinnamon/applets/grouped-window-list@cinnamon.org/workspace.js +++ b/files/usr/share/cinnamon/applets/grouped-window-list@cinnamon.org/workspace.js @@ -32,7 +32,10 @@ class Workspace { }, updateFocusState: (focusedAppId) => { this.appGroups.forEach( appGroup => { - if (focusedAppId === appGroup.groupState.appId) return; + if (focusedAppId === appGroup.groupState.appId) { + appGroup.resetNotificationCount(); + return; + } appGroup.onFocusChange(false); }); } @@ -53,6 +56,7 @@ class Workspace { // Ugly change: refresh the removed app instances from all workspaces this.signals.connect(this.metaWorkspace, 'window-removed', (...args) => this.windowRemoved(...args)); this.signals.connect(global.window_manager, 'switch-workspace' , (...args) => this.reloadList(...args)); + Main.messageTray.connect('notify-applet-update', (mtray, notification) => this.notificationReceived(mtray, notification)); this.on_orientation_changed(null, true); } @@ -77,6 +81,17 @@ class Workspace { return windowCount; } + notificationReceived(mtray, notification) { + const appId = notification.source.app?.get_id(); + if (!appId) return; + this.appGroups.forEach(appGroup => { + if (appId === appGroup.groupState.appId) { + appGroup.incrementNotificationCount(notification); + return; + } + }); + } + closeAllHoverMenus(cb) { this.appGroups.forEach( appGroup => { const {hoverMenu, groupState} = appGroup;