MessageTray: add right click menu for summary items
This provides straight forward controls for opening the corresponding application or removing the summary item. https://bugzilla.gnome.org/show_bug.cgi?id=617224
This commit is contained in:
parent
4282748483
commit
868bf5838d
@ -977,7 +977,7 @@ StTooltip StLabel {
|
||||
padding-bottom: 8px;
|
||||
}
|
||||
|
||||
.summary-notification-boxpointer {
|
||||
.summary-boxpointer {
|
||||
-arrow-border-radius: 9px;
|
||||
-arrow-background-color: rgba(0,0,0,0.9);
|
||||
-arrow-border-width: 2px;
|
||||
@ -986,12 +986,18 @@ StTooltip StLabel {
|
||||
-arrow-rise: 15px;
|
||||
}
|
||||
|
||||
.summary-notification-boxpointer #notification {
|
||||
.summary-boxpointer #notification {
|
||||
border-radius: 9px;
|
||||
background: rgba(0,0,0,0) !important;
|
||||
padding-bottom: 12px;
|
||||
}
|
||||
|
||||
.summary-boxpointer #summary-right-click-menu {
|
||||
font-size: 14px;
|
||||
padding-top: 12px;
|
||||
padding-bottom: 12px;
|
||||
}
|
||||
|
||||
#notification-scrollview {
|
||||
max-height: 10em;
|
||||
}
|
||||
|
@ -15,6 +15,7 @@ const St = imports.gi.St;
|
||||
const BoxPointer = imports.ui.boxpointer;
|
||||
const GnomeSession = imports.misc.gnomeSession;
|
||||
const Main = imports.ui.main;
|
||||
const PopupMenu = imports.ui.popupMenu;
|
||||
const Params = imports.misc.params;
|
||||
const Tweener = imports.ui.tweener;
|
||||
const Util = imports.misc.util;
|
||||
@ -853,7 +854,7 @@ Source.prototype = {
|
||||
|
||||
this.notification = notification;
|
||||
|
||||
this._notificationClickedId = notification.connect('clicked', Lang.bind(this, this._notificationClicked));
|
||||
this._notificationClickedId = notification.connect('clicked', Lang.bind(this, this.open));
|
||||
this._notificationDestroyedId = notification.connect('destroy', Lang.bind(this,
|
||||
function () {
|
||||
if (this.notification == notification) {
|
||||
@ -881,7 +882,7 @@ Source.prototype = {
|
||||
},
|
||||
|
||||
// Default implementation is to do nothing, but subclasses can override
|
||||
_notificationClicked: function(notification) {
|
||||
open: function(notification) {
|
||||
},
|
||||
|
||||
// Default implementation is to destroy this source, but subclasses can override
|
||||
@ -917,6 +918,27 @@ SummaryItem.prototype = {
|
||||
this._sourceBox.add_actor(this._sourceIcon);
|
||||
this._sourceBox.add_actor(this._sourceTitleBin, { expand: true });
|
||||
this.actor.child = this._sourceBox;
|
||||
this.rightClickMenu = new St.BoxLayout({ name: 'summary-right-click-menu',
|
||||
vertical: true });
|
||||
|
||||
let item;
|
||||
|
||||
item = new PopupMenu.PopupMenuItem(_("Open"));
|
||||
item.connect('activate', Lang.bind(this, function() {
|
||||
source.open();
|
||||
this.emit('right-click-menu-done-displaying');
|
||||
}));
|
||||
this.rightClickMenu.add(item.actor);
|
||||
|
||||
item = new PopupMenu.PopupMenuItem(_("Remove"));
|
||||
item.connect('activate', Lang.bind(this, function() {
|
||||
source.destroy();
|
||||
this.emit('right-click-menu-done-displaying');
|
||||
}));
|
||||
this.rightClickMenu.add(item.actor);
|
||||
|
||||
let focusManager = St.FocusManager.get_for_stage(global.stage);
|
||||
focusManager.add_group(this.rightClickMenu);
|
||||
},
|
||||
|
||||
// getTitleNaturalWidth, getTitleWidth, and setTitleWidth include
|
||||
@ -943,6 +965,7 @@ SummaryItem.prototype = {
|
||||
this._sourceTitle.clutter_text.ellipsize = mode;
|
||||
}
|
||||
};
|
||||
Signals.addSignalMethods(SummaryItem.prototype);
|
||||
|
||||
function MessageTray() {
|
||||
this._init();
|
||||
@ -980,17 +1003,19 @@ MessageTray.prototype = {
|
||||
|
||||
this._summaryMotionId = 0;
|
||||
|
||||
this._summaryNotificationBoxPointer = new BoxPointer.BoxPointer(St.Side.BOTTOM,
|
||||
{ reactive: true,
|
||||
track_hover: true });
|
||||
this._summaryNotificationBoxPointer.actor.style_class = 'summary-notification-boxpointer';
|
||||
this.actor.add_actor(this._summaryNotificationBoxPointer.actor);
|
||||
this._summaryNotificationBoxPointer.actor.lower_bottom();
|
||||
this._summaryNotificationBoxPointer.actor.hide();
|
||||
this._summaryBoxPointer = new BoxPointer.BoxPointer(St.Side.BOTTOM,
|
||||
{ reactive: true,
|
||||
track_hover: true });
|
||||
this._summaryBoxPointer.actor.style_class = 'summary-boxpointer';
|
||||
this.actor.add_actor(this._summaryBoxPointer.actor);
|
||||
this._summaryBoxPointer.actor.lower_bottom();
|
||||
this._summaryBoxPointer.actor.hide();
|
||||
|
||||
this._summaryNotification = null;
|
||||
this._summaryNotificationClickedId = 0;
|
||||
this._summaryRightClickMenuClickedId = 0;
|
||||
this._clickedSummaryItem = null;
|
||||
this._clickedSummaryItemMouseButton = -1;
|
||||
this._clickedSummaryItemAllocationChangedId = 0;
|
||||
this._expandedSummaryItem = null;
|
||||
this._summaryItemTitleWidth = 0;
|
||||
@ -1004,7 +1029,7 @@ MessageTray.prototype = {
|
||||
this._focusGrabber = new FocusGrabber();
|
||||
this._focusGrabber.connect('focus-grabbed', Lang.bind(this,
|
||||
function() {
|
||||
if (this._summaryNotification)
|
||||
if (this._summaryBoxPointer.bin.child)
|
||||
this._lock();
|
||||
}));
|
||||
this._focusGrabber.connect('focus-ungrabbed', Lang.bind(this, this._unlock));
|
||||
@ -1027,7 +1052,7 @@ MessageTray.prototype = {
|
||||
this._notificationState = State.HIDDEN;
|
||||
this._notificationTimeoutId = 0;
|
||||
this._notificationExpandedId = 0;
|
||||
this._summaryNotificationState = State.HIDDEN;
|
||||
this._summaryBoxPointerState = State.HIDDEN;
|
||||
this._summaryNotificationTimeoutId = 0;
|
||||
this._summaryNotificationExpandedId = 0;
|
||||
this._overviewVisible = Main.overview.visible;
|
||||
@ -1037,7 +1062,7 @@ MessageTray.prototype = {
|
||||
Main.chrome.addActor(this.actor, { affectsStruts: false,
|
||||
visibleInOverview: true });
|
||||
Main.chrome.trackActor(this._notificationBin);
|
||||
Main.chrome.trackActor(this._summaryNotificationBoxPointer.actor);
|
||||
Main.chrome.trackActor(this._summaryBoxPointer.actor);
|
||||
|
||||
global.gdk_screen.connect('monitors-changed', Lang.bind(this, this._setSizePosition));
|
||||
|
||||
@ -1138,9 +1163,9 @@ MessageTray.prototype = {
|
||||
this._onSummaryItemHoverChanged(summaryItem);
|
||||
}));
|
||||
|
||||
summaryItem.actor.connect('clicked', Lang.bind(this,
|
||||
function () {
|
||||
this._onSummaryItemClicked(summaryItem);
|
||||
summaryItem.actor.connect('button-press-event', Lang.bind(this,
|
||||
function (actor, event) {
|
||||
this._onSummaryItemClicked(summaryItem, event);
|
||||
}));
|
||||
|
||||
source.connect('destroy', Lang.bind(this, this._onSourceDestroy));
|
||||
@ -1354,11 +1379,16 @@ MessageTray.prototype = {
|
||||
this._expandedSummaryItem.setEllipsization(Pango.EllipsizeMode.END);
|
||||
},
|
||||
|
||||
_onSummaryItemClicked: function(summaryItem) {
|
||||
if (!this._clickedSummaryItem || this._clickedSummaryItem != summaryItem)
|
||||
_onSummaryItemClicked: function(summaryItem, event) {
|
||||
let clickedButton = event.get_button();
|
||||
if (!this._clickedSummaryItem ||
|
||||
this._clickedSummaryItem != summaryItem ||
|
||||
this._clickedSummaryItemMouseButton != clickedButton) {
|
||||
this._clickedSummaryItem = summaryItem;
|
||||
else
|
||||
this._clickedSummaryItemMouseButton = clickedButton;
|
||||
} else {
|
||||
this._unsetClickedSummaryItem();
|
||||
}
|
||||
|
||||
this._updateState();
|
||||
},
|
||||
@ -1385,7 +1415,7 @@ MessageTray.prototype = {
|
||||
// leaving the tray. The tray is locked when the summary notification is visible anyway, but we
|
||||
// should treat the mouse being over the summary notification as the tray being left for collapsing
|
||||
// any expanded summary item other than the one related to the notification.
|
||||
if (this._summaryNotificationBoxPointer.bin.hover)
|
||||
if (this._summaryBoxPointer.bin.hover)
|
||||
return;
|
||||
|
||||
this._useLongerTrayLeftTimeout = false;
|
||||
@ -1543,19 +1573,23 @@ MessageTray.prototype = {
|
||||
}
|
||||
|
||||
// Summary notification
|
||||
let haveSummaryNotification = this._clickedSummaryItem != null;
|
||||
let summaryNotificationIsMainNotification = (haveSummaryNotification &&
|
||||
let haveClickedSummaryItem = this._clickedSummaryItem != null;
|
||||
let summaryNotificationIsMainNotification = (haveClickedSummaryItem &&
|
||||
this._clickedSummaryItem.source.notification == this._notification);
|
||||
let canShowSummaryNotification = this._summaryState == State.SHOWN;
|
||||
let wrongSummaryNotification = (haveSummaryNotification &&
|
||||
let canShowSummaryBoxPointer = this._summaryState == State.SHOWN;
|
||||
let wrongSummaryNotification = (this._clickedSummaryItemMouseButton == 1 &&
|
||||
this._summaryNotification != this._clickedSummaryItem.source.notification);
|
||||
let wrongSummaryRightClickMenu = (this._clickedSummaryItemMouseButton == 3 &&
|
||||
this._summaryBoxPointer.bin.child != this._clickedSummaryItem.rightClickMenu);
|
||||
let wrongSummaryBoxPointer = (haveClickedSummaryItem &&
|
||||
(wrongSummaryNotification || wrongSummaryRightClickMenu));
|
||||
|
||||
if (this._summaryNotificationState == State.HIDDEN) {
|
||||
if (haveSummaryNotification && !summaryNotificationIsMainNotification && canShowSummaryNotification)
|
||||
this._showSummaryNotification();
|
||||
} else if (this._summaryNotificationState == State.SHOWN) {
|
||||
if (!haveSummaryNotification || !canShowSummaryNotification || wrongSummaryNotification)
|
||||
this._hideSummaryNotification();
|
||||
if (this._summaryBoxPointerState == State.HIDDEN) {
|
||||
if (haveClickedSummaryItem && !summaryNotificationIsMainNotification && canShowSummaryBoxPointer)
|
||||
this._showSummaryBoxPointer();
|
||||
} else if (this._summaryBoxPointerState == State.SHOWN) {
|
||||
if (!haveClickedSummaryItem || !canShowSummaryBoxPointer || wrongSummaryBoxPointer)
|
||||
this._hideSummaryBoxPointer();
|
||||
}
|
||||
|
||||
// Tray itself
|
||||
@ -1813,44 +1847,53 @@ MessageTray.prototype = {
|
||||
this._expandedSummaryItemTitleWidth = this._summaryItemTitleWidth;
|
||||
},
|
||||
|
||||
_showSummaryNotification: function() {
|
||||
this._summaryNotification = this._clickedSummaryItem.source.notification;
|
||||
this._summaryNotificationClickedId = this._summaryNotification.connect('done-displaying',
|
||||
Lang.bind(this, this._escapeTray));
|
||||
let index = this._notificationQueue.indexOf(this._summaryNotification);
|
||||
if (index != -1)
|
||||
this._notificationQueue.splice(index, 1);
|
||||
_showSummaryBoxPointer: function() {
|
||||
if (this._clickedSummaryItemMouseButton == 1) {
|
||||
let clickedSummaryItemNotification = this._clickedSummaryItem.source.notification;
|
||||
let index = this._notificationQueue.indexOf(clickedSummaryItemNotification);
|
||||
if (index != -1)
|
||||
this._notificationQueue.splice(index, 1);
|
||||
|
||||
this._summaryNotificationBoxPointer.bin.child = this._summaryNotification.actor;
|
||||
this._focusGrabber.grabFocus(this._summaryNotification.actor);
|
||||
this._summaryNotification = clickedSummaryItemNotification;
|
||||
this._summaryNotificationClickedId = this._summaryNotification.connect('done-displaying',
|
||||
Lang.bind(this, this._escapeTray));
|
||||
this._summaryBoxPointer.bin.child = this._summaryNotification.actor;
|
||||
if (!this._summaryNotificationExpandedId)
|
||||
this._summaryNotificationExpandedId = this._summaryNotification.connect('expanded',
|
||||
Lang.bind(this, this._onSummaryBoxPointerExpanded));
|
||||
this._summaryNotification.expand(false);
|
||||
} else if (this._clickedSummaryItemMouseButton == 3) {
|
||||
this._summaryRightClickMenuClickedId = this._clickedSummaryItem.connect('right-click-menu-done-displaying',
|
||||
Lang.bind(this, this._escapeTray));
|
||||
this._summaryBoxPointer.bin.child = this._clickedSummaryItem.rightClickMenu;
|
||||
}
|
||||
|
||||
this._focusGrabber.grabFocus(this._summaryBoxPointer.bin.child);
|
||||
|
||||
if (!this._summaryNotificationExpandedId)
|
||||
this._summaryNotificationExpandedId = this._summaryNotification.connect('expanded', Lang.bind(this, this._onSummaryNotificationExpanded));
|
||||
this._summaryNotification.expand(false);
|
||||
|
||||
this._clickedSummaryItemAllocationChangedId =
|
||||
this._clickedSummaryItem.actor.connect('allocation-changed',
|
||||
Lang.bind(this, this._adjustNotificationBoxPointerPosition));
|
||||
Lang.bind(this, this._adjustSummaryBoxPointerPosition));
|
||||
// _clickedSummaryItem.actor can change absolute postiion without changing allocation
|
||||
this._summaryMotionId = this._summary.connect('allocation-changed',
|
||||
Lang.bind(this, this._adjustNotificationBoxPointerPosition));
|
||||
Lang.bind(this, this._adjustSummaryBoxPointerPosition));
|
||||
|
||||
this._summaryNotificationBoxPointer.actor.opacity = 0;
|
||||
this._summaryNotificationBoxPointer.actor.show();
|
||||
this._adjustNotificationBoxPointerPosition();
|
||||
this._summaryBoxPointer.actor.opacity = 0;
|
||||
this._summaryBoxPointer.actor.show();
|
||||
this._adjustSummaryBoxPointerPosition();
|
||||
|
||||
this._summaryNotificationState = State.SHOWING;
|
||||
this._summaryNotificationBoxPointer.show(true, Lang.bind(this, function() {
|
||||
this._summaryNotificationState = State.SHOWN;
|
||||
this._summaryBoxPointerState = State.SHOWING;
|
||||
this._summaryBoxPointer.show(true, Lang.bind(this, function() {
|
||||
this._summaryBoxPointerState = State.SHOWN;
|
||||
}));
|
||||
},
|
||||
|
||||
_adjustNotificationBoxPointerPosition: function() {
|
||||
_adjustSummaryBoxPointerPosition: function() {
|
||||
// The position of the arrow origin should be the same as center of this._clickedSummaryItem.actor
|
||||
if (!this._clickedSummaryItem)
|
||||
return;
|
||||
|
||||
this._summaryNotificationBoxPointer.setPosition(this._clickedSummaryItem.actor, 0, 0.5);
|
||||
this._summaryBoxPointer.setPosition(this._clickedSummaryItem.actor, 0, 0.5);
|
||||
},
|
||||
|
||||
_unsetClickedSummaryItem: function() {
|
||||
@ -1861,14 +1904,20 @@ MessageTray.prototype = {
|
||||
this._summaryMotionId = 0;
|
||||
}
|
||||
|
||||
if (this._summaryRightClickMenuClickedId) {
|
||||
this._clickedSummaryItem.disconnect(this._summaryRightClickMenuClickedId);
|
||||
this._summaryRightClickMenuClickedId = 0;
|
||||
}
|
||||
|
||||
this._clickedSummaryItem = null;
|
||||
this._clickedSummaryItemMouseButton = -1;
|
||||
},
|
||||
|
||||
_onSummaryNotificationExpanded: function() {
|
||||
this._adjustNotificationBoxPointerPosition();
|
||||
_onSummaryBoxPointerExpanded: function() {
|
||||
this._adjustSummaryBoxPointerPosition();
|
||||
},
|
||||
|
||||
_hideSummaryNotification: function() {
|
||||
_hideSummaryBoxPointer: function() {
|
||||
if (this._summaryNotificationExpandedId) {
|
||||
this._summaryNotification.disconnect(this._summaryNotificationExpandedId);
|
||||
this._summaryNotificationExpandedId = 0;
|
||||
@ -1878,23 +1927,25 @@ MessageTray.prototype = {
|
||||
this._unsetClickedSummaryItem();
|
||||
|
||||
this._focusGrabber.ungrabFocus();
|
||||
this._summaryNotificationState = State.HIDING;
|
||||
this._summaryNotificationBoxPointer.hide(true, Lang.bind(this, this._hideSummaryNotificationCompleted));
|
||||
this._summaryBoxPointerState = State.HIDING;
|
||||
this._summaryBoxPointer.hide(true, Lang.bind(this, this._hideSummaryBoxPointerCompleted));
|
||||
},
|
||||
|
||||
_hideSummaryNotificationCompleted: function() {
|
||||
this._summaryNotificationState = State.HIDDEN;
|
||||
this._summaryNotificationBoxPointer.bin.child = null;
|
||||
this._summaryNotification.collapseCompleted();
|
||||
this._summaryNotification.disconnect(this._summaryNotificationClickedId);
|
||||
this._summaryNotificationClickedId = 0;
|
||||
let summaryNotification = this._summaryNotification;
|
||||
this._summaryNotification = null;
|
||||
if (summaryNotification.isTransient && !this._reNotifyWithSummaryNotificationAfterHide)
|
||||
summaryNotification.destroy(NotificationDestroyedReason.EXPIRED);
|
||||
if (this._reNotifyWithSummaryNotificationAfterHide) {
|
||||
this._onNotify(summaryNotification.source, summaryNotification);
|
||||
this._reNotifyWithSummaryNotificationAfterHide = false;
|
||||
_hideSummaryBoxPointerCompleted: function() {
|
||||
this._summaryBoxPointerState = State.HIDDEN;
|
||||
this._summaryBoxPointer.bin.child = null;
|
||||
if (this._summaryNotification != null) {
|
||||
this._summaryNotification.collapseCompleted();
|
||||
this._summaryNotification.disconnect(this._summaryNotificationClickedId);
|
||||
this._summaryNotificationClickedId = 0;
|
||||
let summaryNotification = this._summaryNotification;
|
||||
this._summaryNotification = null;
|
||||
if (summaryNotification.isTransient && !this._reNotifyWithSummaryNotificationAfterHide)
|
||||
summaryNotification.destroy(NotificationDestroyedReason.EXPIRED);
|
||||
if (this._reNotifyWithSummaryNotificationAfterHide) {
|
||||
this._onNotify(summaryNotification.source, summaryNotification);
|
||||
this._reNotifyWithSummaryNotificationAfterHide = false;
|
||||
}
|
||||
}
|
||||
if (this._clickedSummaryItem)
|
||||
this._updateState();
|
||||
@ -1920,7 +1971,7 @@ SystemNotificationSource.prototype = {
|
||||
icon_size: this.ICON_SIZE });
|
||||
},
|
||||
|
||||
_notificationClicked: function() {
|
||||
open: function() {
|
||||
this.destroy();
|
||||
}
|
||||
};
|
||||
|
@ -473,7 +473,7 @@ Source.prototype = {
|
||||
this._isTrayIcon = true;
|
||||
},
|
||||
|
||||
_notificationClicked: function(notification) {
|
||||
open: function(notification) {
|
||||
this.openApp();
|
||||
},
|
||||
|
||||
|
@ -54,8 +54,10 @@ PopupBaseMenuItem.prototype = {
|
||||
}
|
||||
if (params.reactive && params.hover)
|
||||
this.actor.connect('notify::hover', Lang.bind(this, this._onHoverChanged));
|
||||
if (params.reactive)
|
||||
if (params.reactive) {
|
||||
this.actor.connect('key-focus-in', Lang.bind(this, this._onKeyFocusIn));
|
||||
this.actor.connect('key-focus-out', Lang.bind(this, this._onKeyFocusOut));
|
||||
}
|
||||
},
|
||||
|
||||
_onStyleChanged: function (actor) {
|
||||
@ -81,6 +83,10 @@ PopupBaseMenuItem.prototype = {
|
||||
this.setActive(true);
|
||||
},
|
||||
|
||||
_onKeyFocusOut: function (actor) {
|
||||
this.setActive(false);
|
||||
},
|
||||
|
||||
_onHoverChanged: function (actor) {
|
||||
this.setActive(actor.hover);
|
||||
},
|
||||
|
@ -173,7 +173,7 @@ Source.prototype = {
|
||||
}
|
||||
},
|
||||
|
||||
_notificationClicked: function(notification) {
|
||||
open: function(notification) {
|
||||
let props = {};
|
||||
props[Tp.PROP_CHANNEL_CHANNEL_TYPE] = Tp.IFACE_CHANNEL_TYPE_TEXT;
|
||||
[props[Tp.PROP_CHANNEL_TARGET_HANDLE], props[Tp.PROP_CHANNEL_TARGET_HANDLE_TYPE]] = this._channel.get_handle();
|
||||
|
@ -101,7 +101,7 @@ Source.prototype = {
|
||||
return this._app.create_icon_texture(this.ICON_SIZE);
|
||||
},
|
||||
|
||||
_notificationClicked : function(notification) {
|
||||
open : function(notification) {
|
||||
Main.activateWindow(this._window);
|
||||
this.destroy();
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user