Grab focus in expanded notifications on hover
In addition to already grabbing focus in the summary notifications, we also want to grab focus in the new notifications when the user hovers over them and expands them. The notifications that expand automatically will only get focus once the user hovers over them. The notifications that don't expand will never grab focus because they don't need it. Make sure that we toggle the way we grab focus when switching between the overview and the main mode. This is necessary because, unlike summary notifications that pop down when the user moves between the two modes, new notifications keep being shown as long as the user hovers over them or until they time out. https://bugzilla.gnome.org/show_bug.cgi?id=617224
This commit is contained in:
parent
46906eef43
commit
95d438b86d
@ -76,6 +76,7 @@ Notification.prototype = {
|
|||||||
this.urgent = false;
|
this.urgent = false;
|
||||||
|
|
||||||
this._hasFocus = false;
|
this._hasFocus = false;
|
||||||
|
this._lockTrayOnFocusGrab = false;
|
||||||
// We use this._prevFocusedWindow and this._prevKeyFocusActor to return the
|
// We use this._prevFocusedWindow and this._prevKeyFocusActor to return the
|
||||||
// focus where it previously belonged after a focus grab, unless the user
|
// focus where it previously belonged after a focus grab, unless the user
|
||||||
// has explicitly changed that.
|
// has explicitly changed that.
|
||||||
@ -98,6 +99,15 @@ Notification.prototype = {
|
|||||||
reactive: true });
|
reactive: true });
|
||||||
this.actor.connect('style-changed', Lang.bind(this, this._styleChanged));
|
this.actor.connect('style-changed', Lang.bind(this, this._styleChanged));
|
||||||
this.update(title, banner, true);
|
this.update(title, banner, true);
|
||||||
|
|
||||||
|
Main.overview.connect('showing', Lang.bind(this,
|
||||||
|
function() {
|
||||||
|
this._toggleFocusGrabMode();
|
||||||
|
}));
|
||||||
|
Main.overview.connect('hidden', Lang.bind(this,
|
||||||
|
function() {
|
||||||
|
this._toggleFocusGrabMode();
|
||||||
|
}));
|
||||||
},
|
},
|
||||||
|
|
||||||
// update:
|
// update:
|
||||||
@ -371,10 +381,12 @@ Notification.prototype = {
|
|||||||
return true;
|
return true;
|
||||||
},
|
},
|
||||||
|
|
||||||
grabFocus: function() {
|
grabFocus: function(lockTray) {
|
||||||
if (this._hasFocus)
|
if (this._hasFocus)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
this._lockTrayOnFocusGrab = lockTray;
|
||||||
|
|
||||||
let metaDisplay = global.screen.get_display();
|
let metaDisplay = global.screen.get_display();
|
||||||
|
|
||||||
this._prevFocusedWindow = metaDisplay.focus_window;
|
this._prevFocusedWindow = metaDisplay.focus_window;
|
||||||
@ -402,6 +414,7 @@ Notification.prototype = {
|
|||||||
this._focusActorChangedId = global.stage.connect('notify::key-focus', Lang.bind(this, this._focusActorChanged));
|
this._focusActorChangedId = global.stage.connect('notify::key-focus', Lang.bind(this, this._focusActorChanged));
|
||||||
|
|
||||||
this._hasFocus = true;
|
this._hasFocus = true;
|
||||||
|
if (lockTray)
|
||||||
Main.messageTray.lock();
|
Main.messageTray.lock();
|
||||||
},
|
},
|
||||||
|
|
||||||
@ -488,7 +501,16 @@ Notification.prototype = {
|
|||||||
if (focusedActor && this.actor.contains(focusedActor))
|
if (focusedActor && this.actor.contains(focusedActor))
|
||||||
global.stage.set_key_focus(null);
|
global.stage.set_key_focus(null);
|
||||||
}
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
// Because we grab focus differently in the overview
|
||||||
|
// and in the main view, we need to change how it is
|
||||||
|
// done when we move between the two.
|
||||||
|
_toggleFocusGrabMode: function() {
|
||||||
|
if (this._hasFocus) {
|
||||||
|
this.ungrabFocus();
|
||||||
|
this.grabFocus(this._lockTrayOnFocusGrab);
|
||||||
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
destroy: function() {
|
destroy: function() {
|
||||||
@ -727,7 +749,7 @@ MessageTray.prototype = {
|
|||||||
this._notificationTimeoutId = 0;
|
this._notificationTimeoutId = 0;
|
||||||
this._summaryNotificationState = State.HIDDEN;
|
this._summaryNotificationState = State.HIDDEN;
|
||||||
this._summaryNotificationTimeoutId = 0;
|
this._summaryNotificationTimeoutId = 0;
|
||||||
this._overviewVisible = false;
|
this._overviewVisible = Main.overview.visible;
|
||||||
this._notificationRemoved = false;
|
this._notificationRemoved = false;
|
||||||
|
|
||||||
Main.chrome.addActor(this.actor, { affectsStruts: false,
|
Main.chrome.addActor(this.actor, { affectsStruts: false,
|
||||||
@ -742,12 +764,18 @@ MessageTray.prototype = {
|
|||||||
Main.overview.connect('showing', Lang.bind(this,
|
Main.overview.connect('showing', Lang.bind(this,
|
||||||
function() {
|
function() {
|
||||||
this._overviewVisible = true;
|
this._overviewVisible = true;
|
||||||
|
if (this._locked)
|
||||||
this.unlock();
|
this.unlock();
|
||||||
|
else
|
||||||
|
this._updateState();
|
||||||
}));
|
}));
|
||||||
Main.overview.connect('hiding', Lang.bind(this,
|
Main.overview.connect('hiding', Lang.bind(this,
|
||||||
function() {
|
function() {
|
||||||
this._overviewVisible = false;
|
this._overviewVisible = false;
|
||||||
|
if (this._locked)
|
||||||
this.unlock();
|
this.unlock();
|
||||||
|
else
|
||||||
|
this._updateState();
|
||||||
}));
|
}));
|
||||||
|
|
||||||
this._summaryItems = {};
|
this._summaryItems = {};
|
||||||
@ -911,6 +939,8 @@ MessageTray.prototype = {
|
|||||||
},
|
},
|
||||||
|
|
||||||
unlock: function() {
|
unlock: function() {
|
||||||
|
if (!this._locked)
|
||||||
|
return;
|
||||||
this._locked = false;
|
this._locked = false;
|
||||||
this._clickedSummaryItem = null;
|
this._clickedSummaryItem = null;
|
||||||
this._updateState();
|
this._updateState();
|
||||||
@ -1000,6 +1030,8 @@ MessageTray.prototype = {
|
|||||||
this._hideNotification();
|
this._hideNotification();
|
||||||
else if (notificationPinned && !notificationExpanded)
|
else if (notificationPinned && !notificationExpanded)
|
||||||
this._expandNotification();
|
this._expandNotification();
|
||||||
|
else if (notificationPinned)
|
||||||
|
this._ensureNotificationFocused();
|
||||||
}
|
}
|
||||||
|
|
||||||
// Summary
|
// Summary
|
||||||
@ -1141,6 +1173,7 @@ MessageTray.prototype = {
|
|||||||
},
|
},
|
||||||
|
|
||||||
_hideNotification: function() {
|
_hideNotification: function() {
|
||||||
|
this._notification.ungrabFocus();
|
||||||
this._notification.popIn();
|
this._notification.popIn();
|
||||||
|
|
||||||
if (this._reExpandNotificationId) {
|
if (this._reExpandNotificationId) {
|
||||||
@ -1167,6 +1200,9 @@ MessageTray.prototype = {
|
|||||||
|
|
||||||
_expandNotification: function() {
|
_expandNotification: function() {
|
||||||
if (this._notification && this._notification.popOut()) {
|
if (this._notification && this._notification.popOut()) {
|
||||||
|
// Don't grab focus in urgent notifications that are auto-expanded.
|
||||||
|
if (!this._notification.urgent)
|
||||||
|
this._notification.grabFocus(false);
|
||||||
this._tween(this._notificationBin, '_notificationState', State.SHOWN,
|
this._tween(this._notificationBin, '_notificationState', State.SHOWN,
|
||||||
{ y: this.actor.height - this._notificationBin.height,
|
{ y: this.actor.height - this._notificationBin.height,
|
||||||
time: ANIMATION_TIME,
|
time: ANIMATION_TIME,
|
||||||
@ -1178,6 +1214,12 @@ MessageTray.prototype = {
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
|
// We use this function to grab focus when the user moves the pointer
|
||||||
|
// to an urgent notification that was already auto-expanded.
|
||||||
|
_ensureNotificationFocused: function() {
|
||||||
|
this._notification.grabFocus(false);
|
||||||
|
},
|
||||||
|
|
||||||
_showSummary: function(withTimeout) {
|
_showSummary: function(withTimeout) {
|
||||||
let primary = global.get_primary_monitor();
|
let primary = global.get_primary_monitor();
|
||||||
this._summaryBin.opacity = 0;
|
this._summaryBin.opacity = 0;
|
||||||
@ -1226,8 +1268,8 @@ MessageTray.prototype = {
|
|||||||
this._notificationQueue.splice(index, 1);
|
this._notificationQueue.splice(index, 1);
|
||||||
|
|
||||||
this._summaryNotificationBin.child = this._summaryNotification.actor;
|
this._summaryNotificationBin.child = this._summaryNotification.actor;
|
||||||
this._summaryNotification.grabFocus();
|
|
||||||
this._summaryNotification.popOut();
|
this._summaryNotification.popOut();
|
||||||
|
this._summaryNotification.grabFocus(true);
|
||||||
|
|
||||||
this._summaryNotificationBin.opacity = 0;
|
this._summaryNotificationBin.opacity = 0;
|
||||||
this._summaryNotificationBin.y = this.actor.height;
|
this._summaryNotificationBin.y = this.actor.height;
|
||||||
|
@ -579,7 +579,6 @@ Notification.prototype = {
|
|||||||
MessageTray.Notification.prototype._init.call(this, id, source, source.title);
|
MessageTray.Notification.prototype._init.call(this, id, source, source.title);
|
||||||
|
|
||||||
this._responseEntry = new St.Entry({ style_class: 'chat-response' });
|
this._responseEntry = new St.Entry({ style_class: 'chat-response' });
|
||||||
this._responseEntry.clutter_text.connect('key-focus-in', Lang.bind(this, this.grabFocus));
|
|
||||||
this._responseEntry.clutter_text.connect('activate', Lang.bind(this, this._onEntryActivated));
|
this._responseEntry.clutter_text.connect('activate', Lang.bind(this, this._onEntryActivated));
|
||||||
this.setActionArea(this._responseEntry);
|
this.setActionArea(this._responseEntry);
|
||||||
|
|
||||||
@ -620,10 +619,10 @@ Notification.prototype = {
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
grabFocus: function() {
|
grabFocus: function(lockTray) {
|
||||||
// Need to call the base class function first so that
|
// Need to call the base class function first so that
|
||||||
// it saves where the key focus was before.
|
// it saves where the key focus was before.
|
||||||
MessageTray.Notification.prototype.grabFocus.call(this);
|
MessageTray.Notification.prototype.grabFocus.call(this, lockTray);
|
||||||
global.stage.set_key_focus(this._responseEntry.clutter_text);
|
global.stage.set_key_focus(this._responseEntry.clutter_text);
|
||||||
},
|
},
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user