diff --git a/js/ui/altTab.js b/js/ui/altTab.js index 7029bf75a..cf1174bd1 100644 --- a/js/ui/altTab.js +++ b/js/ui/altTab.js @@ -354,6 +354,59 @@ const AppSwitcherPopup = new Lang.Class({ } }); +const CyclerPopup = new Lang.Class({ + Name: 'CyclerPopup', + Extends: SwitcherPopup.SwitcherPopup, + Abstract: true, + + _init : function() { + this.parent(); + + this._items = this._getWindows(); + + if (this._items.length == 0) + return; + + // We don't show an actual popup, so just provide what SwitcherPopup + // expects instead of inheriting from SwitcherList + this._switcherList = { actor: new St.Widget(), + highlight: Lang.bind(this, this._highlightItem), + connect: function() {} }; + }, + + _highlightItem: function(index, justOutline) { + Main.activateWindow(this._items[index]); + }, + + _finish: function() { + this._highlightItem(this._selectedIndex); + + this.parent(); + } +}); + + +const GroupCyclerPopup = new Lang.Class({ + Name: 'GroupCyclerPopup', + Extends: CyclerPopup, + + _getWindows: function() { + let app = Shell.WindowTracker.get_default().focus_app; + return app ? app.get_windows() : []; + }, + + _keyPressHandler: function(keysym, action) { + if (action == Meta.KeyBindingAction.CYCLE_GROUP) + this._select(this._next()); + else if (action == Meta.KeyBindingAction.CYCLE_GROUP_BACKWARD) + this._select(this._previous()); + else + return Clutter.EVENT_PROPAGATE; + + return Clutter.EVENT_STOP; + } +}); + const WindowSwitcherPopup = new Lang.Class({ Name: 'WindowSwitcherPopup', Extends: SwitcherPopup.SwitcherPopup, @@ -401,6 +454,32 @@ const WindowSwitcherPopup = new Lang.Class({ } }); +const WindowCyclerPopup = new Lang.Class({ + Name: 'WindowCyclerPopup', + Extends: CyclerPopup, + + _init: function() { + this._settings = new Gio.Settings({ schema_id: 'org.gnome.shell.window-switcher' }); + this.parent(); + }, + + _getWindows: function() { + let workspace = this._settings.get_boolean('current-workspace-only') ? global.screen.get_active_workspace() : null; + return global.display.get_tab_list(Meta.TabList.NORMAL, workspace); + }, + + _keyPressHandler: function(keysym, action) { + if (action == Meta.KeyBindingAction.CYCLE_WINDOWS) + this._select(this._next()); + else if (action == Meta.KeyBindingAction.CYCLE_WINDOWS_BACKWARD) + this._select(this._previous()); + else + return Clutter.EVENT_PROPAGATE; + + return Clutter.EVENT_STOP; + } +}); + const AppIcon = new Lang.Class({ Name: 'AppIcon', diff --git a/js/ui/windowManager.js b/js/ui/windowManager.js index bb54d836c..f8aef2dc8 100644 --- a/js/ui/windowManager.js +++ b/js/ui/windowManager.js @@ -866,6 +866,18 @@ const WindowManager = new Lang.Class({ this.setCustomKeybindingHandler('switch-windows-backward', Shell.ActionMode.NORMAL, Lang.bind(this, this._startWindowSwitcher)); + this.setCustomKeybindingHandler('cycle-windows', + Shell.ActionMode.NORMAL, + Lang.bind(this, this._startWindowCycler)); + this.setCustomKeybindingHandler('cycle-windows-backward', + Shell.ActionMode.NORMAL, + Lang.bind(this, this._startWindowCycler)); + this.setCustomKeybindingHandler('cycle-group', + Shell.ActionMode.NORMAL, + Lang.bind(this, this._startGroupCycler)); + this.setCustomKeybindingHandler('cycle-group-backward', + Shell.ActionMode.NORMAL, + Lang.bind(this, this._startGroupCycler)); this.setCustomKeybindingHandler('switch-panels', Shell.ActionMode.NORMAL | Shell.ActionMode.OVERVIEW | @@ -1766,6 +1778,28 @@ const WindowManager = new Lang.Class({ tabPopup.destroy(); }, + _startWindowCycler : function(display, screen, window, binding) { + /* prevent a corner case where both popups show up at once */ + if (this._workspaceSwitcherPopup != null) + this._workspaceSwitcherPopup.destroy(); + + let tabPopup = new AltTab.WindowCyclerPopup(); + + if (!tabPopup.show(binding.is_reversed(), binding.get_name(), binding.get_mask())) + tabPopup.destroy(); + }, + + _startGroupCycler : function(display, screen, window, binding) { + /* prevent a corner case where both popups show up at once */ + if (this._workspaceSwitcherPopup != null) + this._workspaceSwitcherPopup.destroy(); + + let tabPopup = new AltTab.GroupCyclerPopup(); + + if (!tabPopup.show(binding.is_reversed(), binding.get_name(), binding.get_mask())) + tabPopup.destroy(); + }, + _startA11ySwitcher : function(display, screen, window, binding) { Main.ctrlAltTabManager.popup(binding.is_reversed(), binding.get_name(), binding.get_mask()); },