gnome-shell/js/ui/windowAttentionHandler.js
Florian Müllner 3fc7ed4088 notification: Pass policy in the Source contructor
Commit 932ccac1 changed Source to use a regular constructor
instead of `_init()`.

Unfortunately that results in ordering issues for subclasses
that override `_createPolicy()`, if that method needs to access
any properties that are set in the constructor (as `this` is
only available after chaining up to the parent).

We can fix that by simply setting the policy from the constructor,
instead of relying on some overriden method being called.

Part-of: <https://gitlab.gnome.org/GNOME/gnome-shell/-/merge_requests/3170>
2024-02-09 11:12:51 +00:00

90 lines
2.9 KiB
JavaScript

// -*- mode: js; js-indent-level: 4; indent-tabs-mode: nil -*-
import GObject from 'gi://GObject';
import Shell from 'gi://Shell';
import * as Main from './main.js';
import * as MessageTray from './messageTray.js';
export class WindowAttentionHandler {
constructor() {
this._tracker = Shell.WindowTracker.get_default();
global.display.connectObject(
'window-demands-attention', this._onWindowDemandsAttention.bind(this),
'window-marked-urgent', this._onWindowDemandsAttention.bind(this),
this);
}
_getTitleAndBanner(app, window) {
let title = app.get_name();
let banner = _('“%s” is ready').format(window.get_title());
return [title, banner];
}
_onWindowDemandsAttention(display, window) {
// We don't want to show the notification when the window is already focused,
// because this is rather pointless.
// Some apps (like GIMP) do things like setting the urgency hint on the
// toolbar windows which would result into a notification even though GIMP itself is
// focused.
// We are just ignoring the hint on skip_taskbar windows for now.
// (Which is the same behaviour as with metacity + panel)
if (!window || window.has_focus() || window.is_skip_taskbar())
return;
let app = this._tracker.get_window_app(window);
let source = new WindowAttentionSource(app, window);
Main.messageTray.add(source);
let [title, banner] = this._getTitleAndBanner(app, window);
let notification = new MessageTray.Notification(source, title, banner);
notification.connect('activated', () => {
source.open();
});
notification.setForFeedback(true);
source.showNotification(notification);
window.connectObject('notify::title', () => {
[title, banner] = this._getTitleAndBanner(app, window);
notification.update(title, banner);
}, source);
}
}
const WindowAttentionSource = GObject.registerClass(
class WindowAttentionSource extends MessageTray.Source {
constructor(app, window) {
super({
title: app.get_name(),
icon: app.get_icon(),
policy: MessageTray.NotificationPolicy.newForApp(app),
});
this._window = window;
this._window.connectObject(
'notify::demands-attention', this._sync.bind(this),
'notify::urgent', this._sync.bind(this),
'focus', () => this.destroy(),
'unmanaged', () => this.destroy(), this);
}
_sync() {
if (this._window.demands_attention || this._window.urgent)
return;
this.destroy();
}
destroy(params) {
this._window.disconnectObject(this);
super.destroy(params);
}
open() {
Main.activateWindow(this._window);
}
});