Works in UbuntuGnome

This commit is contained in:
nathan 2016-09-21 22:13:13 +02:00
parent ad509db696
commit 83cea322f1
2 changed files with 132 additions and 57 deletions

View File

@ -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_;

View File

@ -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);