From 22b9f888fbe95fcabe04e522c5f279700105f051 Mon Sep 17 00:00:00 2001 From: Arik W Date: Fri, 21 Apr 2023 12:33:00 +0300 Subject: [PATCH] window-list: Add tooltip for long window titles MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Adds a tooltip feature to the window buttons. If a button’s label is too long to fit, a tooltip will show the complete content when the user hovers over the button. Fixes https://gitlab.gnome.org/GNOME/gnome-shell-extensions/-/issues/170 Part-of: --- extensions/window-list/extension.js | 75 +++++++++++++++++++++++++++++ 1 file changed, 75 insertions(+) diff --git a/extensions/window-list/extension.js b/extensions/window-list/extension.js index 1f4a22f3..39bac0fc 100644 --- a/extensions/window-list/extension.js +++ b/extensions/window-list/extension.js @@ -16,6 +16,9 @@ const _ = ExtensionUtils.gettext; const ICON_TEXTURE_SIZE = 24; const DND_ACTIVATE_TIMEOUT = 500; +const TOOLTIP_OFFSET = 6; +const TOOLTIP_ANIMATION_TIME = 150; + const GroupingMode = { NEVER: 0, AUTO: 1, @@ -224,6 +227,12 @@ class BaseButton extends St.Button { 'window-left-monitor', this._windowEnteredOrLeftMonitor.bind(this)); } + + this._tooltip = new Tooltip(this, { + style_class: 'dash-label', + visible: false, + }); + Main.uiGroup.add_child(this._tooltip); } get active() { @@ -391,6 +400,8 @@ class BaseButton extends St.Button { if (this._windowLeftMonitorId) global.display.disconnect(this._windowLeftMonitorId); this._windowLeftMonitorId = 0; + + this._tooltip.destroy(); } } @@ -1205,6 +1216,70 @@ class Extension { } } +class Tooltip extends St.Label { + static { + GObject.registerClass(this); + } + + constructor(widget, params) { + super(params); + + this._widget = widget; + + this._widget.connect('notify::hover', () => { + if (this._widget.hover) + this.open(); + else + this.close(); + }); + } + + open() { + const buttonTitleWidget = this._widget.label_actor; + const [, , preferredTitleWidth] = buttonTitleWidget.get_preferred_size(); + const maxTitleWidth = buttonTitleWidget.allocation.get_width(); + const isTitleFullyShown = preferredTitleWidth <= maxTitleWidth; + + if (isTitleFullyShown) + return; + + this.set({ + text: this._widget.label_actor.get_text(), + visible: true, + opacity: 0, + }); + + const [stageX, stageY] = this._widget.get_transformed_position(); + const thumbWidth = this._widget.allocation.get_width(); + const tipWidth = this.width; + const tipHeight = this.height; + const xOffset = Math.floor((thumbWidth - tipWidth) / 2); + const monitor = Main.layoutManager.findMonitorForActor(this); + const x = Math.clamp( + stageX + xOffset, + monitor.x, + monitor.x + monitor.width - tipWidth); + const y = stageY - tipHeight - TOOLTIP_OFFSET; + this.set_position(x, y); + + this.ease({ + opacity: 255, + duration: TOOLTIP_ANIMATION_TIME, + mode: Clutter.AnimationMode.EASE_OUT_QUAD, + onComplete: () => (this.visible = this._widget.hover), + }); + } + + close() { + this.ease({ + opacity: 0, + duration: TOOLTIP_ANIMATION_TIME, + mode: Clutter.AnimationMode.EASE_OUT_QUAD, + onComplete: () => (this.visible = this._widget.hover), + }); + } +} + /** * @returns {Extension} - the extension's state object */