From f61548234ad217da0f199efd1931e775373c6603 Mon Sep 17 00:00:00 2001 From: Rui Matos Date: Mon, 10 Dec 2012 20:35:29 +0100 Subject: [PATCH] status/keyboard: Add an Alt+Tab like input source switcher https://bugzilla.gnome.org/show_bug.cgi?id=682315 --- data/theme/gnome-shell.css | 5 ++ js/ui/status/keyboard.js | 95 ++++++++++++++++++++++++++++++++++++++ 2 files changed, 100 insertions(+) diff --git a/data/theme/gnome-shell.css b/data/theme/gnome-shell.css index 388b48eae..4084a8452 100644 --- a/data/theme/gnome-shell.css +++ b/data/theme/gnome-shell.css @@ -2431,3 +2431,8 @@ StScrollBar StButton#vhandle:active { padding-bottom: 0px; } +.input-source-switcher-symbol { + font-size: 42pt; + width: 96px; + height: 96px; +} diff --git a/js/ui/status/keyboard.js b/js/ui/status/keyboard.js index a3f92a2a9..7959e6440 100644 --- a/js/ui/status/keyboard.js +++ b/js/ui/status/keyboard.js @@ -1,9 +1,11 @@ // -*- mode: js; js-indent-level: 4; indent-tabs-mode: nil -*- +const Clutter = imports.gi.Clutter; const Gio = imports.gi.Gio; const GLib = imports.gi.GLib; const GnomeDesktop = imports.gi.GnomeDesktop; const Lang = imports.lang; +const Meta = imports.gi.Meta; const Shell = imports.gi.Shell; const Signals = imports.signals; const St = imports.gi.St; @@ -21,6 +23,7 @@ try { const Main = imports.ui.main; const PopupMenu = imports.ui.popupMenu; const PanelMenu = imports.ui.panelMenu; +const SwitcherPopup = imports.ui.switcherPopup; const Util = imports.misc.util; const DESKTOP_INPUT_SOURCES_SCHEMA = 'org.gnome.desktop.input-sources'; @@ -227,6 +230,77 @@ const InputSource = new Lang.Class({ }); Signals.addSignalMethods(InputSource.prototype); +const InputSourcePopup = new Lang.Class({ + Name: 'InputSourcePopup', + Extends: SwitcherPopup.SwitcherPopup, + + _init: function(items, action, actionBackward) { + this.parent(items); + + this._action = action; + this._actionBackward = actionBackward; + }, + + _createSwitcher: function() { + this._switcherList = new InputSourceSwitcher(this._items); + return true; + }, + + _initialSelection: function(backward, binding) { + if (binding == 'switch-input-source') { + if (backward) + this._selectedIndex = this._items.length - 1; + } else if (binding == 'switch-input-source-backward') { + if (!backward) + this._selectedIndex = this._items.length - 1; + } + this._select(this._selectedIndex); + }, + + _keyPressHandler: function(keysym, backwards, action) { + if (action == this._action) + this._select(backwards ? this._previous() : this._next()); + else if (action == this._actionBackward) + this._select(backwards ? this._next() : this._previous()); + else if (keysym == Clutter.Left) + this._select(this._previous()); + else if (keysym == Clutter.Right) + this._select(this._next()); + }, + + _finish : function() { + this.parent(); + + this._items[this._selectedIndex].activate(); + }, +}); + +const InputSourceSwitcher = new Lang.Class({ + Name: 'InputSourceSwitcher', + Extends: SwitcherPopup.SwitcherList, + + _init: function(items) { + this.parent(true); + + for (let i = 0; i < items.length; i++) + this._addIcon(items[i]); + }, + + _addIcon: function(item) { + let box = new St.BoxLayout({ vertical: true }); + + let bin = new St.Bin({ style_class: 'input-source-switcher-symbol' }); + let symbol = new St.Label({ text: item.shortName }); + bin.set_child(symbol); + box.add(bin, { x_fill: false, y_fill: false } ); + + let text = new St.Label({ text: item.displayName }); + box.add(text, { x_fill: false }); + + this.addItem(box, text); + } +}); + const InputSourceIndicator = new Lang.Class({ Name: 'InputSourceIndicator', Extends: PanelMenu.Button, @@ -254,6 +328,19 @@ const InputSourceIndicator = new Lang.Class({ // All valid input sources currently in the gsettings // KEY_INPUT_SOURCES list ordered by most recently used this._mruSources = []; + this._keybindingAction = + Main.wm.addKeybinding('switch-input-source', + new Gio.Settings({ schema: "org.gnome.shell.keybindings" }), + Meta.KeyBindingFlags.REVERSES, + Main.KeybindingMode.ALL, + Lang.bind(this, this._switchInputSource)); + this._keybindingActionBackward = + Main.wm.addKeybinding('switch-input-source-backward', + new Gio.Settings({ schema: "org.gnome.shell.keybindings" }), + Meta.KeyBindingFlags.REVERSES | + Meta.KeyBindingFlags.REVERSED, + Main.KeybindingMode.ALL, + Lang.bind(this, this._switchInputSource)); this._settings = new Gio.Settings({ schema: DESKTOP_INPUT_SOURCES_SCHEMA }); this._settings.connect('changed::' + KEY_CURRENT_INPUT_SOURCE, Lang.bind(this, this._currentInputSourceChanged)); this._settings.connect('changed::' + KEY_INPUT_SOURCES, Lang.bind(this, this._inputSourcesChanged)); @@ -298,6 +385,14 @@ const InputSourceIndicator = new Lang.Class({ this._inputSourcesChanged(); }, + _switchInputSource: function(display, screen, window, binding) { + let popup = new InputSourcePopup(this._mruSources, this._keybindingAction, this._keybindingActionBackward); + let modifiers = binding.get_modifiers(); + let backwards = modifiers & Meta.VirtualModifier.SHIFT_MASK; + if (!popup.show(backwards, binding.get_name(), binding.get_mask())) + popup.destroy(); + }, + _currentInputSourceChanged: function() { let nVisibleSources = Object.keys(this._inputSources).length; let newSourceIndex = this._settings.get_uint(KEY_CURRENT_INPUT_SOURCE);