diff --git a/js/ui/workspace.js b/js/ui/workspace.js index 4f3958d5c..d1abc225e 100644 --- a/js/ui/workspace.js +++ b/js/ui/workspace.js @@ -63,11 +63,12 @@ const WindowClone = new Lang.Class({ // the invisible border; this is inconvenient; rather than trying // to compensate all over the place we insert a ClutterActor into // the hierarchy that is sized to only the visible portion. - this.actor = new Clutter.Actor({ reactive: true, - x: this.origX, - y: this.origY, - width: outerRect.width, - height: outerRect.height }); + this.actor = new St.Widget({ reactive: true, + can_focus: true, + x: this.origX, + y: this.origY, + width: outerRect.width, + height: outerRect.height }); this.actor.add_child(this._windowClone); @@ -85,10 +86,9 @@ const WindowClone = new Lang.Class({ let clickAction = new Clutter.ClickAction(); clickAction.connect('clicked', Lang.bind(this, this._onClicked)); clickAction.connect('long-press', Lang.bind(this, this._onLongPress)); - this.actor.add_action(clickAction); - this.actor.connect('destroy', Lang.bind(this, this._onDestroy)); + this.actor.connect('key-press-event', Lang.bind(this, this._onKeyPress)); this._draggable = DND.makeDraggable(this.actor, { restoreOnSuccess: true, @@ -197,11 +197,26 @@ const WindowClone = new Lang.Class({ this.disconnectAll(); }, - _onClicked: function(action, actor) { + _activate: function() { this._selected = true; this.emit('selected', global.get_current_time()); }, + _onKeyPress: function(actor, event) { + let symbol = event.get_key_symbol(); + let isEnter = (symbol == Clutter.KEY_Return || symbol == Clutter.KEY_KP_Enter); + if (isEnter) { + this._activate(); + return true; + } + + return false; + }, + + _onClicked: function(action, actor) { + this._activate(); + }, + _onLongPress: function(action, actor, state) { // Take advantage of the Clutter policy to consider // a long-press canceled when the pointer movement @@ -301,6 +316,10 @@ const WindowOverlay = new Lang.Class({ Lang.bind(this, this._onEnter)); windowClone.actor.connect('leave-event', Lang.bind(this, this._onLeave)); + windowClone.actor.connect('key-focus-in', + Lang.bind(this, this._onEnter)); + windowClone.actor.connect('key-focus-out', + Lang.bind(this, this._onLeave)); this._windowAddedId = 0; diff --git a/js/ui/workspacesView.js b/js/ui/workspacesView.js index eaca4f04d..2af8d05ce 100644 --- a/js/ui/workspacesView.js +++ b/js/ui/workspacesView.js @@ -30,6 +30,7 @@ const WorkspacesViewBase = new Lang.Class({ this.actor = new St.Widget({ style_class: 'workspaces-view', reactive: true }); this.actor.connect('destroy', Lang.bind(this, this._onDestroy)); + global.focus_manager.add_group(this.actor); // The actor itself isn't a drop target, so we don't want to pick on its area this.actor.set_size(0, 0); @@ -371,11 +372,21 @@ const ExtraWorkspaceView = new Lang.Class({ }, }); +const DelegateFocusNavigator = new Lang.Class({ + Name: 'DelegateFocusNavigator', + Extends: St.Widget, + + vfunc_navigate_focus: function(from, direction) { + return this._delegate.navigateFocus(from, direction); + }, +}); + const WorkspacesDisplay = new Lang.Class({ Name: 'WorkspacesDisplay', _init: function() { - this.actor = new St.Widget({ clip_to_allocation: true }); + this.actor = new DelegateFocusNavigator({ clip_to_allocation: true }); + this.actor._delegate = this; this.actor.connect('notify::allocation', Lang.bind(this, this._updateWorkspacesActualGeometry)); this.actor.connect('parent-set', Lang.bind(this, this._parentSet)); @@ -437,6 +448,10 @@ const WorkspacesDisplay = new Lang.Class({ return false; }, + navigateFocus: function(from, direction) { + return this._getPrimaryView().actor.navigate_focus(from, direction, false); + }, + show: function() { this._updateWorkspacesViews(); for (let i = 0; i < this._workspacesViews.length; i++)