You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
gnome-shell-extension-panel.../src/extension.js

401 lines
15 KiB

/*
* Idea: Grab MessageTray OSD widget, and give it new .x and .y co-ordinates.
*
* We're grabbing "private" methods (start with _), so expect this to break
* with different versions of Gnome Shell.
*
* It was tested with 3.6 to 3.11.90 with various themes.
*
* Most of this code is a direct copy from gnome-shell/js/ui/messageTray.js,
* so (C)opyright Gnome-Team, I think :)
*
* The idea comes from 'Shell OSD' gnome-shell extension by
* mpnordland@gmail.com
*/
const ExtensionUtils = imports.misc.extensionUtils;
const Config = imports.misc.config;
const Main = imports.ui.main;
const Tweener = imports.ui.tweener;
const LayoutManager = Main.layoutManager;
const Lang = imports.lang;
const Me = ExtensionUtils.getCurrentExtension();
const Convenience = Me.imports.convenience;
const EXTENSIONDIR = Me.dir.get_path();
const PANEL_OSD_SETTINGS_SCHEMA = 'org.gnome.shell.extensions.panel-osd';
const PANEL_OSD_X_POS_KEY = 'x-pos';
/*
* Save MessageTray's original methods. We're going to change these
* in our extension to move the OSD.
*/
let originalExpandMethod = Main.messageTray._onNotificationExpanded;
let originalShowNotification = Main.messageTray._showNotification;
let originalUpdateShowingNotification = Main.messageTray._updateShowingNotification;
let originalHideNotification = Main.messageTray._hideNotification;
/*
* The widget we're interested in
*/
let notificationWidget = Main.messageTray._notificationWidget;
let panel = Main.layoutManager.panelBox;
let originalNotificationWidgetX = notificationWidget.x;
/*
* We need these constants to call Tween with values consistent to the
* MessageTray
*/
const IDLE_TIME = 1000;
const ANIMATION_TIME = 0.2;
const Urgency = {
LOW: 0,
NORMAL: 1,
HIGH: 2,
CRITICAL: 3
};
const State = {
HIDDEN: 0,
SHOWING: 1,
SHOWN: 2,
HIDING: 3
};
function init() {
}
let Settings;
let loadConfig = function() {
Settings = Convenience.getSettings(PANEL_OSD_SETTINGS_SCHEMA);
};
let getX_position = function() {
if (!Settings)
loadConfig();
return Settings.get_double(PANEL_OSD_X_POS_KEY);
}
/*
* Copied from MessageTray._showNotification()
*
* We only change the .y and .x values to move the OSD. We need to copy
* the whole method to prevent the animation from moving the OSD across the
* entire screen.
*/
let extensionShowNotification = function () {
this._notification = this._notificationQueue.shift();
this._userActiveWhileNotificationShown = this.idleMonitor.get_idletime() <= IDLE_TIME;
if (ExtensionUtils.versionCheck(['3.6'], Config.PACKAGE_VERSION)) {
this._idleMonitorWatchId = this.idleMonitor.add_watch(IDLE_TIME,
Lang.bind(this, this._onIdleMonitorWatch));
}
else
{
if (!this._userActiveWhileNotificationShown) {
// If the user isn't active, set up a watch to let us know
// when the user becomes active.
this.idleMonitor.add_user_active_watch(Lang.bind(this, this._onIdleMonitorBecameActive));
}
}
this._notificationClickedId = this._notification.connect('done-displaying',
Lang.bind(this, this._escapeTray));
this._notificationUnfocusedId = this._notification.connect('unfocused', Lang.bind(this, function() {
this._updateState();
}));
this._notificationBin.child = this._notification.actor;
this._notificationWidget.opacity = 0;
// JRL changes begin
//this._notificationWidget.y = 0;
this._notificationWidget.y = -global.screen_height;
// JRL changes end
this._notificationWidget.show();
this._updateShowingNotification();
let [x, y, mods] = global.get_pointer();
// We save the position of the mouse at the time when we started showing the notification
// in order to determine if the notification popped up under it. We make that check if
// the user starts moving the mouse and _onTrayHoverChanged() gets called. We don't
// expand the notification if it just happened to pop up under the mouse unless the user
// explicitly mouses away from it and then mouses back in.
this._showNotificationMouseX = x;
this._showNotificationMouseY = y;
// We save the coordinates of the mouse at the time when we started showing the notification
// and then we update it in _notificationTimeout(). We don't pop down the notification if
// the mouse is moving towards it or within it.
this._lastSeenMouseX = x;
this._lastSeenMouseY = y;
}
/*
* Copied from MessageTray._hideNotification()
*
* We only change the .y and .x values to move the OSD. We need to copy
* the whole method to prevent the animation from moving the OSD across the
* entire screen.
*/
let extensionHideNotification = function(animate) {
if (ExtensionUtils.versionCheck(['3.6', '3.8'], Config.PACKAGE_VERSION)) {
// HACK!
// There seems to be a reentrancy issue in calling .ungrab() here,
// which causes _updateState to be called before _notificationState
// becomes HIDING. That hides the notification again, nullifying the
// object but not setting _notificationState (and that's the weird part)
// As then _notificationState is stuck into SHOWN but _notification
// is null, every new _updateState fails and the message tray is
// lost forever.
//
// See more at https://bugzilla.gnome.org/show_bug.cgi?id=683986
this._notificationState = State.HIDING;
this._grabHelper.ungrab({ actor: this._notification.actor });
}
else
{
this._notificationFocusGrabber.ungrabFocus();
}
if (this._notificationExpandedId) {
this._notification.disconnect(this._notificationExpandedId);
this._notificationExpandedId = 0;
}
if (ExtensionUtils.versionCheck(['3.6'], Config.PACKAGE_VERSION)) {
if (this._notificationRemoved) {
// JRL changes begin
//this._notificationWidget.y = this.actor.height;
this._notificationWidget.y = -global.screen_height;
// JRL changes end
this._notificationWidget.opacity = 0;
this._notificationState = State.HIDDEN;
this._hideNotificationCompleted();
} else {
this._tween(this._notificationWidget, '_notificationState', State.HIDDEN,
// JRL changes begin
//{ y: this.actor.height,
{ y: -global.screen_height,
// JRL changes end
opacity: 0,
time: ANIMATION_TIME,
transition: 'easeOutQuad',
onComplete: this._hideNotificationCompleted,
onCompleteScope: this
});
}
}
else
{
if (this._notificationClickedId) {
this._notification.disconnect(this._notificationClickedId);
this._notificationClickedId = 0;
}
if (this._notificationUnfocusedId) {
this._notification.disconnect(this._notificationUnfocusedId);
this._notificationUnfocusedId = 0;
}
if (ExtensionUtils.versionCheck(['3.8'], Config.PACKAGE_VERSION)) {
this._useLongerTrayLeftTimeout = false;
if (this._trayLeftTimeoutId) {
Mainloop.source_remove(this._trayLeftTimeoutId);
this._trayLeftTimeoutId = 0;
this._trayLeftMouseX = -1;
this._trayLeftMouseY = -1;
}
if (this._notificationRemoved) {
Tweener.removeTweens(this._notificationWidget);
// JRL changes begin
//this._notificationWidget.y = this.actor.height;
this._notificationWidget.y = -global.screen_height;
// JRL changes end
this._notificationWidget.opacity = 0;
this._notificationState = State.HIDDEN;
this._hideNotificationCompleted();
} else {
this._tween(this._notificationWidget, '_notificationState', State.HIDDEN,
// JRL changes begin
//{ y: this.actor.height,
{ y: -global.screen_height,
// JRL changes end
opacity: 0,
time: ANIMATION_TIME,
transition: 'easeOutQuad',
onComplete: this._hideNotificationCompleted,
onCompleteScope: this
});
}
}
else
{
if (this._notificationLeftTimeoutId) {
Mainloop.source_remove(this._notificationLeftTimeoutId);
this._notificationLeftTimeoutId = 0;
this._notificationLeftMouseX = -1;
this._notificationLeftMouseY = -1;
}
if (animate) {
this._tween(this._notificationWidget, '_notificationState', State.HIDDEN,
// JRL changes begin
//{ y: this.actor.height,
{ y: -global.screen_height,
// JRL changes end
opacity: 0,
time: ANIMATION_TIME,
transition: 'easeOutQuad',
onComplete: this._hideNotificationCompleted,
onCompleteScope: this
});
} else {
Tweener.removeTweens(this._notificationWidget);
// JRL changes begin
//this._notificationWidget.y = this.actor.height;
this._notificationWidget.y = -global.screen_height;
// JRL changes end
this._notificationWidget.opacity = 0;
this._notificationState = State.HIDDEN;
this._hideNotificationCompleted();
}
}
}
}
/*
* Copied from MessageTray._updateShowingNotification()
*
* We only change the .y and .x values to move the OSD. We need to copy
* the whole method to prevent the animation from moving the OSD across the
* entire screen.
*
*/
let extensionUpdateShowingNotification = function() {
// JRL changes begin
// add own class-name to change border-radius, otherwise the changed value remains after switching off the extension
this._notification._table.add_style_class_name('jrlnotification');
// JRL changes end
this._notification.acknowledged = true;
if (ExtensionUtils.versionCheck(['3.6'], Config.PACKAGE_VERSION)) {
// We auto-expand notifications with CRITICAL urgency.
if (this._notification.urgency == Urgency.CRITICAL)
this._expandNotification(true);
}
else
{
this._notification.playSound();
// We auto-expand notifications with CRITICAL urgency, or for which the relevant setting
// is on in the control center.
if (this._notification.urgency == Urgency.CRITICAL ||
this._notification.source.policy.forceExpanded)
this._expandNotification(true);
}
// JRL changes begin
// use panel's y and height property to determine the bottom of the top-panel.
// needed because the "hide top bar" and "hide top panel" use different approaches to hide the
// top bar.
// "hide top panel" keeps the height and just moves the panel out of the visible area, so using
// the panels-height is not enough.
let yPos = panel.y + panel.height - global.screen_height;
if (yPos < (-global.screen_height))
yPos = -global.screen_height;
//
this._notificationWidget.x = (global.screen_width - this._notificationWidget.width) * (getX_position() - 50) / 50 ;
// JRL changes end
// We tween all notifications to full opacity. This ensures that both new notifications and
// notifications that might have been in the process of hiding get full opacity.
//
// We tween any notification showing in the banner mode to the appropriate height
// (which is banner height or expanded height, depending on the notification state)
// This ensures that both new notifications and notifications in the banner mode that might
// have been in the process of hiding are shown with the correct height.
//
// We use this._showNotificationCompleted() onComplete callback to extend the time the updated
// notification is being shown.
let tweenParams = { opacity: 255,
// JRL changes begin
//y: -this._notificationWidget.height,
y: yPos,
// JRL changes end
time: ANIMATION_TIME,
transition: 'easeOutQuad',
onComplete: this._showNotificationCompleted,
onCompleteScope: this
};
this._tween(this._notificationWidget, '_notificationState', State.SHOWN, tweenParams);
}
/*
* Copied from MessageTray._onNotificationExpanded()
*
* We only change the .y and .x values to move the OSD. We need to copy
* the whole method to prevent the animation from moving the OSD across the
* entire screen.
*
*/
let extensiononNotificationExpanded = function() {
// JRL changes begin
//let expandedY = - this._notificationWidget.height;
let expandedY = panel.y + panel.height - global.screen_height;
if (expandedY < (-global.screen_height))
expandedY = -global.screen_height;
// JRL changes end
this._closeButton.show();
// Don't animate the notification to its new position if it has shrunk:
// there will be a very visible "gap" that breaks the illusion.
if (this._notificationWidget.y < expandedY) {
this._notificationWidget.y = expandedY;
} else if (this._notification.y != expandedY) {
// Tween also opacity here, to override a possible tween that's
// currently hiding the notification.
this._tween(this._notificationWidget, '_notificationState', State.SHOWN,
{ y: expandedY,
opacity: 255,
time: ANIMATION_TIME,
transition: 'easeOutQuad'
});
}
}
/*
* Overload the methods.
*/
function enable() {
Main.messageTray._showNotification = extensionShowNotification;
Main.messageTray._hideNotification = extensionHideNotification;
Main.messageTray._updateShowingNotification = extensionUpdateShowingNotification;
Main.messageTray._onNotificationExpanded = extensiononNotificationExpanded;
}
/*
* Put everything back.
*/
function disable() {
// remove our style, in case we just show a notification, otherwise the radius is drawn incorrect
if(Main.messageTray._notification)
Main.messageTray._notification._table.remove_style_class_name('jrlnotification');
// reset x-position
notificationWidget.x = originalNotificationWidgetX;
Main.messageTray._showNotification = originalShowNotification;
Main.messageTray._hideNotification = originalHideNotification;
Main.messageTray._updateShowingNotification = originalUpdateShowingNotification;
Main.messageTray._onNotificationExpanded = originalExpandMethod;
}