forked from dorkbox/SystemTray
Works in UbuntuGnome
This commit is contained in:
parent
ad509db696
commit
83cea322f1
@ -15,17 +15,18 @@
|
|||||||
*/
|
*/
|
||||||
package dorkbox.systemTray.linux;
|
package dorkbox.systemTray.linux;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.concurrent.atomic.AtomicBoolean;
|
||||||
|
|
||||||
import com.sun.jna.NativeLong;
|
import com.sun.jna.NativeLong;
|
||||||
import com.sun.jna.Pointer;
|
import com.sun.jna.Pointer;
|
||||||
|
|
||||||
import dorkbox.systemTray.linux.jna.GEventCallback;
|
import dorkbox.systemTray.linux.jna.GEventCallback;
|
||||||
import dorkbox.systemTray.linux.jna.GdkEventButton;
|
import dorkbox.systemTray.linux.jna.GdkEventButton;
|
||||||
import dorkbox.systemTray.linux.jna.Gobject;
|
import dorkbox.systemTray.linux.jna.Gobject;
|
||||||
import dorkbox.systemTray.linux.jna.Gtk;
|
import dorkbox.systemTray.linux.jna.Gtk;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
|
||||||
import java.util.List;
|
|
||||||
import java.util.concurrent.atomic.AtomicBoolean;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Class for handling all system tray interactions via GTK.
|
* Class for handling all system tray interactions via GTK.
|
||||||
* <p/>
|
* <p/>
|
||||||
@ -53,6 +54,7 @@ class GtkSystemTray extends GtkTypeSystemTray {
|
|||||||
public
|
public
|
||||||
void run() {
|
void run() {
|
||||||
final Pointer trayIcon_ = Gtk.gtk_status_icon_new();
|
final Pointer trayIcon_ = Gtk.gtk_status_icon_new();
|
||||||
|
Gtk.gtk_status_icon_set_title(trayIcon_, "SystemTray"); // necessary for gnome placement
|
||||||
Gtk.gtk_status_icon_set_name(trayIcon_, "SystemTray");
|
Gtk.gtk_status_icon_set_name(trayIcon_, "SystemTray");
|
||||||
|
|
||||||
trayIcon = trayIcon_;
|
trayIcon = trayIcon_;
|
||||||
|
@ -1,4 +1,3 @@
|
|||||||
// -*- mode: js; js-indent-level: 4; indent-tabs-mode: nil -*-
|
|
||||||
/*
|
/*
|
||||||
* Copyright 2015 dorkbox, llc
|
* Copyright 2015 dorkbox, llc
|
||||||
*
|
*
|
||||||
@ -21,6 +20,16 @@
|
|||||||
* this is considered as released by the original sources as public domain.
|
* this is considered as released by the original sources as public domain.
|
||||||
*
|
*
|
||||||
* Vladimir's email address is unknown.
|
* Vladimir's email address is unknown.
|
||||||
|
*
|
||||||
|
* Viewing the log messages can be performed by one of the following:
|
||||||
|
* gnome-shell --replace (you will see the log messages in the console)
|
||||||
|
* journalctl
|
||||||
|
* .cache/gdm/session.log
|
||||||
|
* .xsession-errors
|
||||||
|
* /var/log/messages
|
||||||
|
* alt-F2 -> lg -> extensions
|
||||||
|
* ~/.cache/upstart/gnome-session.log
|
||||||
|
* journalctl /usr/bin/gnome-shell -f -o cat
|
||||||
*/
|
*/
|
||||||
|
|
||||||
const Clutter = imports.gi.Clutter;
|
const Clutter = imports.gi.Clutter;
|
||||||
@ -34,35 +43,56 @@ const PanelMenu = imports.ui.panelMenu;
|
|||||||
const Meta = imports.gi.Meta;
|
const Meta = imports.gi.Meta;
|
||||||
const Mainloop = imports.mainloop;
|
const Mainloop = imports.mainloop;
|
||||||
const NotificationDaemon = imports.ui.notificationDaemon;
|
const NotificationDaemon = imports.ui.notificationDaemon;
|
||||||
|
const Config = imports.misc.config
|
||||||
|
const MessageTray = imports.ui.messageTray;
|
||||||
|
|
||||||
let APP_NAME = "SystemTray@Dorkbox";
|
let APP_NAME = "SystemTray";
|
||||||
let trayAddedId = 0;
|
let trayAddedId = 0;
|
||||||
let orig_onTrayIconAdded;
|
let orig_onTrayIconAdded;
|
||||||
|
|
||||||
let trayRemovedId = 0;
|
let trayRemovedId = 0;
|
||||||
let orig_onTrayIconRemoved;
|
let orig_onTrayIconRemoved;
|
||||||
|
|
||||||
|
let tray = null;
|
||||||
let orig_getSource = null;
|
let orig_getSource = null;
|
||||||
let icons = [];
|
let icons = [];
|
||||||
|
|
||||||
let notificationDaemon;
|
let DEBUG = true;
|
||||||
|
|
||||||
|
|
||||||
// this value is hardcoded into the display manager
|
// this value is hardcoded into the display manager
|
||||||
const PANEL_ICON_SIZE = 24;
|
let PANEL_ICON_SIZE = 24;
|
||||||
|
|
||||||
|
// Workarounds...
|
||||||
|
let currentArray = Config.PACKAGE_VERSION.split('.');
|
||||||
|
if (currentArray[0] == 3 && currentArray[1] < 5) {
|
||||||
|
// Gnome Shell 3.3 or 3.4
|
||||||
|
PANEL_ICON_SIZE = MessageTray.Source.prototype.ICON_SIZE;
|
||||||
|
} else if (currentArray[0] == 3 && currentArray[1] < 7) {
|
||||||
|
// Gnome Shell 3.5 or 3.6
|
||||||
|
PANEL_ICON_SIZE = MessageTray.NOTIFICATION_ICON_SIZE;
|
||||||
|
} else {
|
||||||
|
// Gnome Shell 3.7 and higher
|
||||||
|
PANEL_ICON_SIZE = MessageTray.Source.prototype.SOURCE_ICON_SIZE;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
function init() {
|
function init() {
|
||||||
if (Main.legacyTray) {
|
if (Main.legacyTray) {
|
||||||
notificationDaemon = Main.legacyTray;
|
global.log("Legacy tray")
|
||||||
NotificationDaemon.STANDARD_TRAY_ICON_IMPLEMENTATIONS = imports.ui.legacyTray.STANDARD_TRAY_ICON_IMPLEMENTATIONS;
|
tray = Main.legacyTray;
|
||||||
|
tray.STANDARD_TRAY_ICON_IMPLEMENTATIONS = imports.ui.legacyTray.STANDARD_TRAY_ICON_IMPLEMENTATIONS;
|
||||||
}
|
}
|
||||||
else if (Main.notificationDaemon._fdoNotificationDaemon) {
|
else if (Main.notificationDaemon._fdoNotificationDaemon) {
|
||||||
notificationDaemon = Main.notificationDaemon._fdoNotificationDaemon;
|
global.log("FDO Notification tray")
|
||||||
orig_getSource = Lang.bind(notificationDaemon, NotificationDaemon.FdoNotificationDaemon.prototype._getSource);
|
tray = Main.notificationDaemon._fdoNotificationDaemon;
|
||||||
|
orig_getSource = Lang.bind(tray, NotificationDaemon.FdoNotificationDaemon.prototype._getSource);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
notificationDaemon = Main.notificationDaemon;
|
global.log("Notification tray")
|
||||||
orig_getSource = Lang.bind(notificationDaemon, NotificationDaemon.NotificationDaemon.prototype._getSource);
|
tray = Main.notificationDaemon;
|
||||||
|
orig_getSource = Lang.bind(tray, NotificationDaemon.NotificationDaemon.prototype._getSource);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -72,19 +102,19 @@ function enable() {
|
|||||||
|
|
||||||
function disable() {
|
function disable() {
|
||||||
if (trayAddedId != 0) {
|
if (trayAddedId != 0) {
|
||||||
notificationDaemon._trayManager.disconnect(trayAddedId);
|
tray._trayManager.disconnect(trayAddedId);
|
||||||
trayAddedId = 0;
|
trayAddedId = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (trayRemovedId != 0) {
|
if (trayRemovedId != 0) {
|
||||||
notificationDaemon._trayManager.disconnect(trayRemovedId);
|
tray._trayManager.disconnect(trayRemovedId);
|
||||||
trayRemovedId = 0;
|
trayRemovedId = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
notificationDaemon._trayIconAddedId = notificationDaemon._trayManager.connect('tray-icon-added', orig_onTrayIconAdded);
|
tray._trayIconAddedId = tray._trayManager.connect('tray-icon-added', orig_onTrayIconAdded);
|
||||||
notificationDaemon._trayIconRemovedId = notificationDaemon._trayManager.connect('tray-icon-removed', orig_onTrayIconRemoved);
|
tray._trayIconRemovedId = tray._trayManager.connect('tray-icon-removed', orig_onTrayIconRemoved);
|
||||||
|
|
||||||
notificationDaemon._getSource = orig_getSource;
|
tray._getSource = orig_getSource;
|
||||||
|
|
||||||
for (let i = 0; i < icons.length; i++) {
|
for (let i = 0; i < icons.length; i++) {
|
||||||
let icon = icons[i];
|
let icon = icons[i];
|
||||||
@ -102,7 +132,7 @@ function disable() {
|
|||||||
|
|
||||||
parent.remove_actor(icon);
|
parent.remove_actor(icon);
|
||||||
parent.destroy();
|
parent.destroy();
|
||||||
notificationDaemon._onTrayIconAdded(notificationDaemon, icon);
|
tray._onTrayIconAdded(tray, icon);
|
||||||
}
|
}
|
||||||
|
|
||||||
icons = [];
|
icons = [];
|
||||||
@ -111,27 +141,38 @@ function disable() {
|
|||||||
|
|
||||||
|
|
||||||
function installHook() {
|
function installHook() {
|
||||||
//global.log("Installing hook")
|
if (DEBUG) {
|
||||||
|
global.log("Installing hook")
|
||||||
|
}
|
||||||
|
|
||||||
// disable the "normal" method of adding icons
|
// disable the "normal" method of adding icons
|
||||||
notificationDaemon._trayManager.disconnect(notificationDaemon._trayIconAddedId);
|
if (tray._trayIconAddedId) {
|
||||||
notificationDaemon._trayManager.disconnect(notificationDaemon._trayIconRemovedId);
|
tray._trayManager.disconnect(tray._trayIconAddedId);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (tray._trayIconRemovedId) {
|
||||||
|
tray._trayManager.disconnect(tray._trayIconRemovedId);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
// save the original method
|
// save the original method
|
||||||
orig_onTrayIconAdded = Lang.bind(notificationDaemon, notificationDaemon._onTrayIconAdded);
|
orig_onTrayIconAdded = Lang.bind(tray, tray._onTrayIconAdded);
|
||||||
orig_onTrayIconRemoved = Lang.bind(notificationDaemon, notificationDaemon._onTrayIconRemoved)
|
orig_onTrayIconRemoved = Lang.bind(tray, tray._onTrayIconRemoved)
|
||||||
|
|
||||||
// add our hook. If our icon doesn't have our specific title, it calls the original method
|
// add our hook. If our icon doesn't have our specific title, it calls the original method
|
||||||
trayAddedId = notificationDaemon._trayManager.connect('tray-icon-added', onTrayIconAdded);
|
trayAddedId = tray._trayManager.connect('tray-icon-added', onTrayIconAdded);
|
||||||
trayRemovedId = notificationDaemon._trayManager.connect('tray-icon-removed', onTrayIconRemoved);
|
trayRemovedId = tray._trayManager.connect('tray-icon-removed', onTrayIconRemoved);
|
||||||
|
|
||||||
notificationDaemon._getSource = getSourceHook;
|
tray._getSource = getSourceHook;
|
||||||
|
|
||||||
// move icons to top
|
// move icons to top
|
||||||
let toDestroy = [];
|
let toDestroy = [];
|
||||||
if (notificationDaemon._sources) {
|
if (tray._sources) {
|
||||||
for (let i = 0; i < notificationDaemon._sources.length; i++) {
|
if (DEBUG) {
|
||||||
let source = notificationDaemon._sources[i];
|
global.log("Adding to sources")
|
||||||
|
}
|
||||||
|
for (let i = 0; i < tray._sources.length; i++) {
|
||||||
|
let source = tray._sources[i];
|
||||||
|
|
||||||
if (!source.trayIcon) {
|
if (!source.trayIcon) {
|
||||||
continue;
|
continue;
|
||||||
@ -151,8 +192,11 @@ function installHook() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
for (let i = 0; i < notificationDaemon._iconBox.get_n_children(); i++) {
|
if (DEBUG) {
|
||||||
let button = notificationDaemon._iconBox.get_child_at_index(i);
|
global.log("Adding to children")
|
||||||
|
}
|
||||||
|
for (let i = 0; i < tray._iconBox.get_n_children(); i++) {
|
||||||
|
let button = tray._iconBox.get_child_at_index(0);
|
||||||
let icon = button.child;
|
let icon = button.child;
|
||||||
|
|
||||||
if (icon.title !== APP_NAME) {
|
if (icon.title !== APP_NAME) {
|
||||||
@ -163,6 +207,7 @@ function installHook() {
|
|||||||
onTrayIconAdded(this, icon);
|
onTrayIconAdded(this, icon);
|
||||||
|
|
||||||
toDestroy.push(button);
|
toDestroy.push(button);
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -173,7 +218,9 @@ function installHook() {
|
|||||||
|
|
||||||
function getSourceHook (title, pid, ndata, sender, trayIcon) {
|
function getSourceHook (title, pid, ndata, sender, trayIcon) {
|
||||||
if (trayIcon && title === APP_NAME) {
|
if (trayIcon && title === APP_NAME) {
|
||||||
//global.log("create source");
|
if (DEBUG) {
|
||||||
|
global.log("create source");
|
||||||
|
}
|
||||||
onTrayIconAdded(this, trayIcon);
|
onTrayIconAdded(this, trayIcon);
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
@ -183,41 +230,57 @@ function getSourceHook (title, pid, ndata, sender, trayIcon) {
|
|||||||
|
|
||||||
// this is the hook that lets us only add ourselves.
|
// this is the hook that lets us only add ourselves.
|
||||||
function onTrayIconAdded(o, icon) {
|
function onTrayIconAdded(o, icon) {
|
||||||
//global.log("adding tray icon 1 " + icon.title);
|
if (DEBUG) {
|
||||||
|
global.log("adding tray icon 1 " + icon.title);
|
||||||
|
}
|
||||||
|
|
||||||
let wmClass = icon.wm_class ? icon.wm_class.toLowerCase() : '';
|
let wmClass = icon.wm_class ? icon.wm_class.toLowerCase() : '';
|
||||||
if (NotificationDaemon.STANDARD_TRAY_ICON_IMPLEMENTATIONS[wmClass] !== undefined) {
|
if (tray.STANDARD_TRAY_ICON_IMPLEMENTATIONS[wmClass] !== undefined) {
|
||||||
|
if (DEBUG) {
|
||||||
|
global.log("Cannot add tray icon, invalid implementation");
|
||||||
|
}
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (icon.title !== APP_NAME) {
|
if (icon.title !== APP_NAME) {
|
||||||
|
if (DEBUG) {
|
||||||
|
global.log("Cannot add tray icon, wrong name: " + icon.title + " Expecting: " + APP_NAME);
|
||||||
|
}
|
||||||
orig_onTrayIconAdded(o, icon);
|
orig_onTrayIconAdded(o, icon);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
//global.log("adding tray icon 2 " + icon.title);
|
if (DEBUG) {
|
||||||
|
global.log("adding tray icon 2 " + icon.title);
|
||||||
|
}
|
||||||
|
|
||||||
let buttonBox = new PanelMenu.ButtonBox();
|
// An empty ButtonBox will still display padding, so create it without visibility.
|
||||||
let box = buttonBox.actor;
|
let buttonBox = new PanelMenu.ButtonBox({visible: false});
|
||||||
let parent = box.get_parent();
|
let boxActor = buttonBox.actor;
|
||||||
|
let parent = boxActor.get_parent();
|
||||||
|
|
||||||
|
|
||||||
|
// size
|
||||||
let scaleFactor = St.ThemeContext.get_for_stage(global.stage).scale_factor;
|
let scaleFactor = St.ThemeContext.get_for_stage(global.stage).scale_factor;
|
||||||
let iconSize = PANEL_ICON_SIZE * scaleFactor;
|
let iconSize = PANEL_ICON_SIZE * scaleFactor;
|
||||||
|
// icon.get_parent().set_size(iconSize, iconSize);
|
||||||
icon.set_size(iconSize, iconSize);
|
icon.set_size(iconSize, iconSize);
|
||||||
box.add_actor(icon);
|
boxActor.add_actor(icon);
|
||||||
|
|
||||||
|
|
||||||
// Reactive actors will receive events.
|
// Reactive actors will receive events.
|
||||||
icon.set_reactive(true);
|
icon.set_reactive(true);
|
||||||
|
icon.reactive = true;
|
||||||
|
|
||||||
if (parent) {
|
if (parent) {
|
||||||
// remove from the (if present) "collapsy tab icon thing"
|
// remove from the (if present) "collapsy tab icon thing"
|
||||||
parent.remove_actor(box);
|
parent.remove_actor(boxActor);
|
||||||
}
|
}
|
||||||
|
|
||||||
// setup proxy for handling click notifications, make it a little larger than the icon
|
// setup proxy for handling click notifications, make it a little larger than the icon
|
||||||
let clickProxy = new St.Bin({ width: iconSize + 4, height: iconSize + 4});
|
let clickProxy = new St.Bin({ width: iconSize + 4, height: iconSize + 4});
|
||||||
clickProxy.set_reactive(true);
|
clickProxy.set_reactive(true);
|
||||||
|
clickProxy.reactive = true;
|
||||||
|
|
||||||
icon._proxyAlloc = Main.panel._rightBox.connect('allocation-changed', function() {
|
icon._proxyAlloc = Main.panel._rightBox.connect('allocation-changed', function() {
|
||||||
Meta.later_add(Meta.LaterType.BEFORE_REDRAW, function() {
|
Meta.later_add(Meta.LaterType.BEFORE_REDRAW, function() {
|
||||||
@ -229,6 +292,7 @@ function onTrayIconAdded(o, icon) {
|
|||||||
|
|
||||||
icon.connect("destroy", function() {
|
icon.connect("destroy", function() {
|
||||||
Main.panel._rightBox.disconnect(icon._proxyAlloc);
|
Main.panel._rightBox.disconnect(icon._proxyAlloc);
|
||||||
|
icon.clear_effects();
|
||||||
clickProxy.destroy();
|
clickProxy.destroy();
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -242,13 +306,22 @@ function onTrayIconAdded(o, icon) {
|
|||||||
Main.uiGroup.add_actor(clickProxy);
|
Main.uiGroup.add_actor(clickProxy);
|
||||||
|
|
||||||
// add the box to the right panel, always at position 0
|
// add the box to the right panel, always at position 0
|
||||||
Main.panel._rightBox.insert_child_at_index(box, 0);
|
Main.panel._rightBox.insert_child_at_index(boxActor, 0);
|
||||||
|
|
||||||
|
GLib.timeout_add(GLib.PRIORITY_DEFAULT, 500, Lang.bind(this, function()
|
||||||
|
{
|
||||||
|
clickProxy.visible = true;
|
||||||
|
boxActor.visible = true;
|
||||||
|
return GLib.SOURCE_REMOVE;
|
||||||
|
}));
|
||||||
|
|
||||||
icons.push(icon);
|
icons.push(icon);
|
||||||
}
|
}
|
||||||
|
|
||||||
function onTrayIconRemoved(o, icon) {
|
function onTrayIconRemoved(o, icon) {
|
||||||
//global.log("removing tray icon " + icon.title);
|
if (DEBUG) {
|
||||||
|
global.log("removing tray icon " + icon.title);
|
||||||
|
}
|
||||||
|
|
||||||
if (icon.title !== APP_NAME) {
|
if (icon.title !== APP_NAME) {
|
||||||
orig_onTrayIconRemoved(o, icon);
|
orig_onTrayIconRemoved(o, icon);
|
||||||
|
Loading…
Reference in New Issue
Block a user