system tray elsewhere
This commit is contained in:
parent
ecf795b6ef
commit
a4091adbf2
@ -1495,6 +1495,24 @@ StScrollBar StButton#vhandle:active {
|
|||||||
background: #2e3436 url(message-tray-background.png);
|
background: #2e3436 url(message-tray-background.png);
|
||||||
background-repeat: repeat;
|
background-repeat: repeat;
|
||||||
height: 72px;
|
height: 72px;
|
||||||
|
|
||||||
|
padding-right: 8px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.system-tray-icons {
|
||||||
|
border-radius: 8px;
|
||||||
|
border: 1px solid #4c4c4c;
|
||||||
|
}
|
||||||
|
|
||||||
|
.system-tray-icon-button {
|
||||||
|
padding: 8px;
|
||||||
|
|
||||||
|
width: 22px;
|
||||||
|
height: 22px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.system-tray-icon-button:hover {
|
||||||
|
background: 1px solid #4c4c4c;
|
||||||
}
|
}
|
||||||
|
|
||||||
.message-tray-summary {
|
.message-tray-summary {
|
||||||
|
@ -1070,7 +1070,7 @@ const Source = new Lang.Class({
|
|||||||
},
|
},
|
||||||
|
|
||||||
get isClearable() {
|
get isClearable() {
|
||||||
return !this.trayIcon && !this.isChat;
|
return !this.isChat;
|
||||||
},
|
},
|
||||||
|
|
||||||
countUpdated: function() {
|
countUpdated: function() {
|
||||||
@ -1631,6 +1631,71 @@ const MessageTrayIndicator = new Lang.Class({
|
|||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
|
const SystemTrayIconButton = new Lang.Class({
|
||||||
|
Name: 'SystemTrayIconButton',
|
||||||
|
|
||||||
|
_init: function(trayIcon) {
|
||||||
|
this._trayIcon = trayIcon;
|
||||||
|
|
||||||
|
this.actor = new St.Button({ style_class: 'system-tray-icon-button',
|
||||||
|
track_hover: true,
|
||||||
|
can_focus: true,
|
||||||
|
reactive: true });
|
||||||
|
this.actor.connect('clicked', Lang.bind(this, this._onClicked));
|
||||||
|
this.actor.set_child(this._trayIcon);
|
||||||
|
|
||||||
|
this._trayIcon.connect('destroy', Lang.bind(this, function() {
|
||||||
|
this.actor.set_child(null);
|
||||||
|
this.actor.destroy();
|
||||||
|
}));
|
||||||
|
},
|
||||||
|
|
||||||
|
_onClicked: function() {
|
||||||
|
let event = Clutter.get_current_event();
|
||||||
|
|
||||||
|
let id = global.stage.connect('deactivate', Lang.bind(this, function() {
|
||||||
|
global.stage.disconnect(id);
|
||||||
|
this._trayIcon.click(event);
|
||||||
|
}));
|
||||||
|
|
||||||
|
this.emit('clicked');
|
||||||
|
|
||||||
|
Main.overview.hide();
|
||||||
|
return true;
|
||||||
|
},
|
||||||
|
});
|
||||||
|
Signals.addSignalMethods(SystemTrayIconButton.prototype);
|
||||||
|
|
||||||
|
const SystemTraySection = new Lang.Class({
|
||||||
|
Name: 'SystemTraySection',
|
||||||
|
|
||||||
|
_init: function(tray) {
|
||||||
|
this._tray = tray;
|
||||||
|
|
||||||
|
this.actor = new St.BoxLayout({ style_class: 'system-tray-icons',
|
||||||
|
y_align: Clutter.ActorAlign.CENTER,
|
||||||
|
y_expand: true });
|
||||||
|
|
||||||
|
this._trayManager = new Shell.TrayManager();
|
||||||
|
this._trayManager.connect('tray-icon-added', Lang.bind(this, this._onTrayIconAdded));
|
||||||
|
this._trayManager.connect('tray-icon-removed', Lang.bind(this, this._onTrayIconRemoved));
|
||||||
|
|
||||||
|
this._trayManager.manage_screen(global.screen, this.actor);
|
||||||
|
},
|
||||||
|
|
||||||
|
_onTrayIconAdded: function(manager, trayIcon) {
|
||||||
|
let button = new SystemTrayIconButton(trayIcon);
|
||||||
|
button.connect('clicked', Lang.bind(this, function() {
|
||||||
|
this._tray.close();
|
||||||
|
}));
|
||||||
|
this.actor.add_child(button.actor);
|
||||||
|
},
|
||||||
|
|
||||||
|
_onTrayIconRemoved: function(manager, trayIcon) {
|
||||||
|
trayIcon.destroy();
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
const MessageTray = new Lang.Class({
|
const MessageTray = new Lang.Class({
|
||||||
Name: 'MessageTray',
|
Name: 'MessageTray',
|
||||||
|
|
||||||
@ -1683,13 +1748,18 @@ const MessageTray = new Lang.Class({
|
|||||||
return Clutter.EVENT_PROPAGATE;
|
return Clutter.EVENT_PROPAGATE;
|
||||||
}));
|
}));
|
||||||
global.focus_manager.add_group(this.actor);
|
global.focus_manager.add_group(this.actor);
|
||||||
this._summary = new St.BoxLayout({ style_class: 'message-tray-summary',
|
|
||||||
reactive: true,
|
this._summaryGroup = new St.BoxLayout({ x_align: Clutter.ActorAlign.END,
|
||||||
x_align: Clutter.ActorAlign.END,
|
x_expand: true,
|
||||||
x_expand: true,
|
y_align: Clutter.ActorAlign.CENTER,
|
||||||
y_align: Clutter.ActorAlign.CENTER,
|
y_expand: true });
|
||||||
y_expand: true });
|
this.actor.add_child(this._summaryGroup);
|
||||||
this.actor.add_actor(this._summary);
|
|
||||||
|
this._summary = new St.BoxLayout({ style_class: 'message-tray-summary' });
|
||||||
|
this._summaryGroup.add_child(this._summary);
|
||||||
|
|
||||||
|
this._systemTray = new SystemTraySection(this);
|
||||||
|
this._summaryGroup.add_child(this._systemTray.actor);
|
||||||
|
|
||||||
this._summaryMotionId = 0;
|
this._summaryMotionId = 0;
|
||||||
|
|
||||||
|
@ -105,16 +105,10 @@ const FdoNotificationDaemon = new Lang.Class({
|
|||||||
|
|
||||||
this._nextNotificationId = 1;
|
this._nextNotificationId = 1;
|
||||||
|
|
||||||
this._trayManager = new Shell.TrayManager();
|
|
||||||
this._trayIconAddedId = this._trayManager.connect('tray-icon-added', Lang.bind(this, this._onTrayIconAdded));
|
|
||||||
this._trayIconRemovedId = this._trayManager.connect('tray-icon-removed', Lang.bind(this, this._onTrayIconRemoved));
|
|
||||||
|
|
||||||
Shell.WindowTracker.get_default().connect('notify::focus-app',
|
Shell.WindowTracker.get_default().connect('notify::focus-app',
|
||||||
Lang.bind(this, this._onFocusAppChanged));
|
Lang.bind(this, this._onFocusAppChanged));
|
||||||
Main.overview.connect('hidden',
|
Main.overview.connect('hidden',
|
||||||
Lang.bind(this, this._onFocusAppChanged));
|
Lang.bind(this, this._onFocusAppChanged));
|
||||||
|
|
||||||
this._trayManager.manage_screen(global.screen, Main.messageTray.actor);
|
|
||||||
},
|
},
|
||||||
|
|
||||||
_imageForNotificationData: function(hints) {
|
_imageForNotificationData: function(hints) {
|
||||||
@ -155,28 +149,23 @@ const FdoNotificationDaemon = new Lang.Class({
|
|||||||
return null;
|
return null;
|
||||||
},
|
},
|
||||||
|
|
||||||
_lookupSource: function(title, pid, trayIcon) {
|
_lookupSource: function(title, pid) {
|
||||||
for (let i = 0; i < this._sources.length; i++) {
|
for (let i = 0; i < this._sources.length; i++) {
|
||||||
let source = this._sources[i];
|
let source = this._sources[i];
|
||||||
if (source.pid == pid &&
|
if (source.pid == pid && source.initialTitle == title)
|
||||||
(source.initialTitle == title || source.trayIcon || trayIcon))
|
|
||||||
return source;
|
return source;
|
||||||
}
|
}
|
||||||
return null;
|
return null;
|
||||||
},
|
},
|
||||||
|
|
||||||
// Returns the source associated with ndata.notification if it is set.
|
// Returns the source associated with ndata.notification if it is set.
|
||||||
// If the existing or requested source is associated with a tray icon
|
|
||||||
// and passed in pid matches a pid of an existing source, the title
|
|
||||||
// match is ignored to enable representing a tray icon and notifications
|
|
||||||
// from the same application with a single source.
|
|
||||||
//
|
//
|
||||||
// If no existing source is found, a new source is created as long as
|
// If no existing source is found, a new source is created as long as
|
||||||
// pid is provided.
|
// pid is provided.
|
||||||
//
|
//
|
||||||
// Either a pid or ndata.notification is needed to retrieve or
|
// Either a pid or ndata.notification is needed to retrieve or
|
||||||
// create a source.
|
// create a source.
|
||||||
_getSource: function(title, pid, ndata, sender, trayIcon) {
|
_getSource: function(title, pid, ndata, sender) {
|
||||||
if (!pid && !(ndata && ndata.notification))
|
if (!pid && !(ndata && ndata.notification))
|
||||||
return null;
|
return null;
|
||||||
|
|
||||||
@ -187,13 +176,13 @@ const FdoNotificationDaemon = new Lang.Class({
|
|||||||
if (ndata && ndata.notification)
|
if (ndata && ndata.notification)
|
||||||
return ndata.notification.source;
|
return ndata.notification.source;
|
||||||
|
|
||||||
let source = this._lookupSource(title, pid, trayIcon);
|
let source = this._lookupSource(title, pid);
|
||||||
if (source) {
|
if (source) {
|
||||||
source.setTitle(title);
|
source.setTitle(title);
|
||||||
return source;
|
return source;
|
||||||
}
|
}
|
||||||
|
|
||||||
let source = new FdoNotificationDaemonSource(title, pid, sender, trayIcon, ndata ? ndata.hints['desktop-entry'] : null);
|
let source = new FdoNotificationDaemonSource(title, pid, sender, ndata ? ndata.hints['desktop-entry'] : null);
|
||||||
|
|
||||||
this._sources.push(source);
|
this._sources.push(source);
|
||||||
source.connect('destroy', Lang.bind(this, function() {
|
source.connect('destroy', Lang.bind(this, function() {
|
||||||
@ -485,26 +474,15 @@ const FdoNotificationDaemon = new Lang.Class({
|
|||||||
this._dbusImpl.emit_signal('ActionInvoked',
|
this._dbusImpl.emit_signal('ActionInvoked',
|
||||||
GLib.Variant.new('(us)', [id, action]));
|
GLib.Variant.new('(us)', [id, action]));
|
||||||
},
|
},
|
||||||
|
|
||||||
_onTrayIconAdded: function(o, icon) {
|
|
||||||
let source = this._getSource(icon.title || icon.wm_class || C_("program", "Unknown"), icon.pid, null, null, icon);
|
|
||||||
},
|
|
||||||
|
|
||||||
_onTrayIconRemoved: function(o, icon) {
|
|
||||||
let source = this._lookupSource(null, icon.pid, true);
|
|
||||||
if (source)
|
|
||||||
source.destroy();
|
|
||||||
}
|
|
||||||
});
|
});
|
||||||
|
|
||||||
const FdoNotificationDaemonSource = new Lang.Class({
|
const FdoNotificationDaemonSource = new Lang.Class({
|
||||||
Name: 'FdoNotificationDaemonSource',
|
Name: 'FdoNotificationDaemonSource',
|
||||||
Extends: MessageTray.Source,
|
Extends: MessageTray.Source,
|
||||||
|
|
||||||
_init: function(title, pid, sender, trayIcon, appId) {
|
_init: function(title, pid, sender, appId) {
|
||||||
// Need to set the app before chaining up, so
|
// Need to set the app before chaining up, so
|
||||||
// methods called from the parent constructor can find it
|
// methods called from the parent constructor can find it
|
||||||
this.trayIcon = trayIcon;
|
|
||||||
this.pid = pid;
|
this.pid = pid;
|
||||||
this.app = this._getApp(appId);
|
this.app = this._getApp(appId);
|
||||||
|
|
||||||
@ -524,12 +502,6 @@ const FdoNotificationDaemonSource = new Lang.Class({
|
|||||||
Lang.bind(this, this._onNameVanished));
|
Lang.bind(this, this._onNameVanished));
|
||||||
else
|
else
|
||||||
this._nameWatcherId = 0;
|
this._nameWatcherId = 0;
|
||||||
|
|
||||||
if (this.trayIcon) {
|
|
||||||
// Try again finding the app, using the WM_CLASS from the tray icon
|
|
||||||
this._setSummaryIcon(this.trayIcon);
|
|
||||||
this.useNotificationIcon = false;
|
|
||||||
}
|
|
||||||
},
|
},
|
||||||
|
|
||||||
_createPolicy: function() {
|
_createPolicy: function() {
|
||||||
@ -545,17 +517,15 @@ const FdoNotificationDaemonSource = new Lang.Class({
|
|||||||
// Destroy the notification source when its sender is removed from DBus.
|
// Destroy the notification source when its sender is removed from DBus.
|
||||||
// Only do so if this.app is set to avoid removing "notify-send" sources, senders
|
// Only do so if this.app is set to avoid removing "notify-send" sources, senders
|
||||||
// of which аre removed from DBus immediately.
|
// of which аre removed from DBus immediately.
|
||||||
// Sender being removed from DBus would normally result in a tray icon being removed,
|
if (this.app)
|
||||||
// so allow the code path that handles the tray icon being removed to handle that case.
|
|
||||||
if (!this.trayIcon && this.app)
|
|
||||||
this.destroy();
|
this.destroy();
|
||||||
},
|
},
|
||||||
|
|
||||||
processNotification: function(notification, gicon) {
|
processNotification: function(notification, gicon) {
|
||||||
if (gicon)
|
if (gicon)
|
||||||
this._gicon = gicon;
|
this._gicon = gicon;
|
||||||
if (!this.trayIcon)
|
|
||||||
this.iconUpdated();
|
this.iconUpdated();
|
||||||
|
|
||||||
let tracker = Shell.WindowTracker.get_default();
|
let tracker = Shell.WindowTracker.get_default();
|
||||||
if (this.app && tracker.focus_app == this.app)
|
if (this.app && tracker.focus_app == this.app)
|
||||||
@ -564,29 +534,6 @@ const FdoNotificationDaemonSource = new Lang.Class({
|
|||||||
this.notify(notification);
|
this.notify(notification);
|
||||||
},
|
},
|
||||||
|
|
||||||
handleSummaryClick: function(button) {
|
|
||||||
if (!this.trayIcon)
|
|
||||||
return false;
|
|
||||||
|
|
||||||
let event = Clutter.get_current_event();
|
|
||||||
|
|
||||||
// Left clicks are passed through only where there aren't unacknowledged
|
|
||||||
// notifications, so it possible to open them in summary mode; right
|
|
||||||
// clicks are always forwarded, as the right click menu is not useful for
|
|
||||||
// tray icons
|
|
||||||
if (button == 1 &&
|
|
||||||
this.notifications.length > 0)
|
|
||||||
return false;
|
|
||||||
|
|
||||||
let id = global.stage.connect('deactivate', Lang.bind(this, function () {
|
|
||||||
global.stage.disconnect(id);
|
|
||||||
this.trayIcon.click(event);
|
|
||||||
}));
|
|
||||||
|
|
||||||
Main.overview.hide();
|
|
||||||
return true;
|
|
||||||
},
|
|
||||||
|
|
||||||
_getApp: function(appId) {
|
_getApp: function(appId) {
|
||||||
let app;
|
let app;
|
||||||
|
|
||||||
@ -594,16 +541,6 @@ const FdoNotificationDaemonSource = new Lang.Class({
|
|||||||
if (app != null)
|
if (app != null)
|
||||||
return app;
|
return app;
|
||||||
|
|
||||||
if (this.trayIcon) {
|
|
||||||
app = Shell.AppSystem.get_default().lookup_startup_wmclass(this.trayIcon.wm_class);
|
|
||||||
if (app != null)
|
|
||||||
return app;
|
|
||||||
|
|
||||||
app = Shell.AppSystem.get_default().lookup_desktop_wmclass(this.trayIcon.wm_class);
|
|
||||||
if (app != null)
|
|
||||||
return app;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (appId) {
|
if (appId) {
|
||||||
app = Shell.AppSystem.get_default().lookup_app(appId + '.desktop');
|
app = Shell.AppSystem.get_default().lookup_app(appId + '.desktop');
|
||||||
if (app != null)
|
if (app != null)
|
||||||
@ -629,8 +566,7 @@ const FdoNotificationDaemonSource = new Lang.Class({
|
|||||||
},
|
},
|
||||||
|
|
||||||
_lastNotificationRemoved: function() {
|
_lastNotificationRemoved: function() {
|
||||||
if (!this.trayIcon)
|
this.destroy();
|
||||||
this.destroy();
|
|
||||||
},
|
},
|
||||||
|
|
||||||
openApp: function() {
|
openApp: function() {
|
||||||
@ -651,11 +587,7 @@ const FdoNotificationDaemonSource = new Lang.Class({
|
|||||||
},
|
},
|
||||||
|
|
||||||
createIcon: function(size) {
|
createIcon: function(size) {
|
||||||
if (this.trayIcon) {
|
if (this.app) {
|
||||||
return new Clutter.Clone({ width: size,
|
|
||||||
height: size,
|
|
||||||
source: this.trayIcon });
|
|
||||||
} else if (this.app) {
|
|
||||||
return this.app.create_icon_texture(size);
|
return this.app.create_icon_texture(size);
|
||||||
} else if (this._gicon) {
|
} else if (this._gicon) {
|
||||||
return new St.Icon({ gicon: this._gicon,
|
return new St.Icon({ gicon: this._gicon,
|
||||||
|
Loading…
x
Reference in New Issue
Block a user