diff --git a/CoverflowAltTab@dmo60.de/metadata.json b/CoverflowAltTab@dmo60.de/metadata.json index c6013df..0531a16 100644 --- a/CoverflowAltTab@dmo60.de/metadata.json +++ b/CoverflowAltTab@dmo60.de/metadata.json @@ -7,5 +7,6 @@ "dangerous": false, "name": "Coverflow Alt-Tab", "url": "https://github.com/dmo60/CoverflowAltTab", - "uuid": "CoverflowAltTab@dmo60.de" + "uuid": "CoverflowAltTab@dmo60.de", + "version": 666 } diff --git a/CoverflowAltTab@dmo60.de/prefs.js b/CoverflowAltTab@dmo60.de/prefs.js index 6fe1b03..0c92884 100644 --- a/CoverflowAltTab@dmo60.de/prefs.js +++ b/CoverflowAltTab@dmo60.de/prefs.js @@ -20,7 +20,7 @@ * * Preferences dialog for "gnome-extensions prefs" tool * - * Based on preferences in the following extensions: JustPerfection, dash2doc-lite, and desktop cube + * Based on preferences in the following extensions: JustPerfection, dash2doc-lite, night theme switcher, and desktop cube * */ const { Adw, Gdk, GLib, Gtk } = imports.gi; @@ -104,10 +104,7 @@ const easing_options = [ id: 'random', name: "Random" }]; -let settings; - function init() { - settings = Lib.getSettings(SCHEMA); let iconTheme = Gtk.IconTheme.get_for_display(Gdk.Display.get_default()); iconTheme.add_search_path(`${UIFolderPath}/icons`); Lib.initTranslations("coverflow"); @@ -133,7 +130,12 @@ function makeResetButton() { }); } +function getVersionString(_page) { + return _('Version %d').format(Me.metadata.version); +} + function fillPreferencesWindow(window) { + let settings = Lib.getSettings(SCHEMA); let general_page = new Adw.PreferencesPage({ title: _('General'), icon_name: 'general-symbolic', @@ -142,26 +144,26 @@ function fillPreferencesWindow(window) { let switcher_pref_group = new Adw.PreferencesGroup({ title: _('Switcher'), }); - switcher_pref_group.add(buildRadioAdw("switcher-style", [_("Coverflow"), _("Timeline")], _("Style"), _("Pick the type of switcher."))) - switcher_pref_group.add(buildSpinAdw("offset", [-500, 500, 1, 10], _("Vertical Offset"), _("Positive value moves everything down, negative up."))); - switcher_pref_group.add(buildRadioAdw("position", [_("Bottom"), _("Top")], _("Window Title Position"), _("Place window title above or below the switcher."))); - switcher_pref_group.add(buildSwitcherAdw("enforce-primary-monitor", _("Enforce Primary Monitor"), _("Always show on the primary monitor, otherwise, show on the active monitor."))); + switcher_pref_group.add(buildRadioAdw(settings, "switcher-style", [_("Coverflow"), _("Timeline")], _("Style"), _("Pick the type of switcher."))) + switcher_pref_group.add(buildSpinAdw(settings, "offset", [-500, 500, 1, 10], _("Vertical Offset"), _("Positive value moves everything down, negative up."))); + switcher_pref_group.add(buildRadioAdw(settings, "position", [_("Bottom"), _("Top")], _("Window Title Position"), _("Place window title above or below the switcher."))); + switcher_pref_group.add(buildSwitcherAdw(settings, "enforce-primary-monitor", _("Enforce Primary Monitor"), _("Always show on the primary monitor, otherwise, show on the active monitor."))); let behavior_pref_group = new Adw.PreferencesGroup({ title: _("Behavior"), }); - behavior_pref_group.add(buildSwitcherAdw("hide-panel", _("Hide Panel"), _("Hide panel when switching widnows."))); + behavior_pref_group.add(buildSwitcherAdw(settings, "hide-panel", _("Hide Panel"), _("Hide panel when switching widnows."))); let animation_pref_group = new Adw.PreferencesGroup({ title: _('Animation'), }); - animation_pref_group.add(buildDropDownAdw("easing-function", easing_options, "Easing Function", "Determine how windows move.")); - animation_pref_group.add(buildRangeAdw("animation-time", [0.01, 2, 0.001, [0.5, 1, 1.5]], _("Duration"), _("In seconds."), true)); - animation_pref_group.add(buildSwitcherAdw("randomize-animation-times", _("Randomize Durations"), _("Each animation duration assigned randomly between 0 and configured duration"))); + animation_pref_group.add(buildDropDownAdw(settings, "easing-function", easing_options, "Easing Function", "Determine how windows move.")); + animation_pref_group.add(buildRangeAdw(settings, "animation-time", [0.01, 2, 0.001, [0.5, 1, 1.5]], _("Duration"), _("In seconds."), true)); + animation_pref_group.add(buildSwitcherAdw(settings, "randomize-animation-times", _("Randomize Durations"), _("Each animation duration assigned randomly between 0 and configured duration"))); let windows_pref_group = new Adw.PreferencesGroup({ - title: _('Windows'), + title: _('Switcher Windows'), }); options = [{ id: 'current', name: _("Current workspace only") @@ -170,35 +172,58 @@ function fillPreferencesWindow(window) { }, { id: 'all-currentfirst', name: _("All workspaces, current first") }]; - windows_pref_group.add(buildDropDownAdw("current-workspace-only", options, _("Workspaces"), _("Switch between windows on current or on all workspaces"))); - windows_pref_group.add(buildSwitcherAdw("switch-per-monitor", _("Current Monitor"), _("Switch between windows on current monitor"))); + windows_pref_group.add(buildDropDownAdw(settings, "current-workspace-only", options, _("Workspaces"), _("Switch between windows on current or on all workspaces"))); + windows_pref_group.add(buildSwitcherAdw(settings, "switch-per-monitor", _("Current Monitor"), _("Switch between windows on current monitor"))); - let pcorrection_pref_group = new Adw.PreferencesGroup({ - title: _("Perspective Correction") - }) - pcorrection_pref_group.add(buildDropDownAdw("perspective-correction-method", [ - { id: "None", name:_("None") }, - { id: "Move Camera", name: _("Move Camera") }, - { id: "Adjust Angles", name: _("Adjust Angles")}], - _("Perspective Correction"), ("Method to make off-center switcher look centered."))); + let icon_pref_group = new Adw.PreferencesGroup({ + title: _("Icon"), + }); + icon_pref_group.add(buildRadioAdw(settings, "icon-style", [_("Classic"), _("Overlay")], _("Application Icon Style"))); + icon_pref_group.add(buildRangeAdw(settings, "overlay-icon-size", [0, 1024, 1, [32, 64, 128, 256, 512]], _("Overlay Icon Size"), _("Set the overlay icon size in pixels."), true)); + icon_pref_group.add(buildRangeAdw(settings, "overlay-icon-opacity", [0, 1, 0.001, [0.25, 0.5, 0.75]], _("Overlay Icon Opacity"), _("Set the overlay icon opacity."), true)); + icon_pref_group.add(buildSwitcherAdw(settings, "icon-has-shadow", _("Icon Shadow"))); + + let window_size_pref_group = new Adw.PreferencesGroup({ + title: _("Window Size") + }); + window_size_pref_group.add(buildRangeAdw(settings, "preview-to-monitor-ratio", [0, 1, 0.001, [0.250, 0.500, 0.750]], _("Window Preview Size to Monintor Size Ratio"), _("Maximum ratio of window preview size to monitor size."), true)); + window_size_pref_group.add(buildRangeAdw(settings, "preview-scaling-factor", [0, 1, 0.001, [0.250, 0.500, 0.800]], _("Off-center Size Factor"), _("Factor by which to successively shrink previews off to the side"), true)); + + let background_pref_group = new Adw.PreferencesGroup({ + title: _('Background'), + }); + background_pref_group.add(buildRangeAdw(settings, "dim-factor", [0, 1, 0.001, [0.25, 0.5, 0.75]], _("Background Dim-factor"), _("Smaller means darker."), true)); let keybinding_pref_group = new Adw.PreferencesGroup({ title: _("Keybindings"), }); - keybinding_pref_group.add(buildSwitcherAdw("bind-to-switch-windows", _("Bind to 'switch-windows' keybinding"))); - keybinding_pref_group.add(buildSwitcherAdw("bind-to-switch-applications", _("Bind to 'switch-applications' keybinding"))); + keybinding_pref_group.add(buildSwitcherAdw(settings, "bind-to-switch-windows", _("Bind to 'switch-windows'"))); + keybinding_pref_group.add(buildSwitcherAdw(settings, "bind-to-switch-applications", _("Bind to 'switch-applications'"))); general_page.add(switcher_pref_group); general_page.add(animation_pref_group); - general_page.add(behavior_pref_group); + general_page.add(icon_pref_group); general_page.add(windows_pref_group); + general_page.add(window_size_pref_group); + general_page.add(behavior_pref_group); + general_page.add(background_pref_group); general_page.add(keybinding_pref_group); + + let pcorrection_pref_group = new Adw.PreferencesGroup({ + title: _("Perspective Correction") + }) + pcorrection_pref_group.add(buildDropDownAdw(settings, "perspective-correction-method", [ + { id: "None", name:_("None") }, + { id: "Move Camera", name: _("Move Camera") }, + { id: "Adjust Angles", name: _("Adjust Angles")}], + _("Perspective Correction"), ("Method to make off-center switcher look centered."))); + let highlight_mouse_over_pref_group = new Adw.PreferencesGroup({ title: _("Highlight Window Under Mouse"), }); - highlight_mouse_over_pref_group.add(buildSwitcherAdw("highlight-mouse-over", _("Highlight Window Under Mouse"), _("Draw embelishment on window under the mouse to know the effects of clicking."))); - highlight_mouse_over_pref_group.add(buildSwitcherAdw("raise-mouse-over", _("Raise Window Under Mouse"), _("Raise the window under the mouse above all others."))); + highlight_mouse_over_pref_group.add(buildSwitcherAdw(settings, "highlight-mouse-over", _("Highlight Window Under Mouse"), _("Draw embelishment on window under the mouse to know the effects of clicking."))); + highlight_mouse_over_pref_group.add(buildSwitcherAdw(settings, "raise-mouse-over", _("Raise Window Under Mouse"), _("Raise the window under the mouse above all others."))); let tweaks_page = new Adw.PreferencesPage({ title: _('Tweaks'), @@ -212,37 +237,83 @@ function fillPreferencesWindow(window) { icon_name: 'dash-symbolic', }); - let icon_pref_group = new Adw.PreferencesGroup({ - title: _("Icon"), + let contribution_page = new Adw.PreferencesPage({ + title: _("Contribute"), + icon_name: 'contribute-symbolic', }); - icon_pref_group.add(buildRadioAdw("icon-style", [_("Classic"), _("Overlay")], _("Application Icon Style"))); - icon_pref_group.add(buildRangeAdw("overlay-icon-size", [0, 1024, 1, [32, 64, 128, 256, 512]], _("Overlay Icon Size"), _("Set the overlay icon size in pixels."), true)); - icon_pref_group.add(buildRangeAdw("overlay-icon-opacity", [0, 1, 0.001, [0.25, 0.5, 0.75]], _("Overlay Icon Opacity"), _("Set the overlay icon opacity."), true)); - icon_pref_group.add(buildSwitcherAdw("icon-has-shadow", _("Draw Icon with a Shadow"))); - let window_pref_group = new Adw.PreferencesGroup({ - title: _("Window Size") + let contribute_icon_pref_group = new Adw.PreferencesGroup(); + let icon_box = new Gtk.Box({ + orientation: Gtk.Orientation.VERTICAL, + margin_top: 24, + margin_bottom: 24, + spacing: 18, }); - window_pref_group.add(buildRangeAdw("preview-to-monitor-ratio", [0, 1, 0.001, [0.250, 0.500, 0.750]], _("Preview to Monintor Ratio"), _("Maximum ratio of preview to monitor size."), true)); - window_pref_group.add(buildRangeAdw("preview-scaling-factor", [0, 1, 0.001, [0.250, 0.500, 0.800]], _("Off-center Size Factor"), _("Factor by which to shrink previews off to the sides."), true)); - let background_pref_group = new Adw.PreferencesGroup({ - title: _('Background'), + let icon_image = new Gtk.Image({ + icon_name: "coverflow-symbolic", + pixel_size: 128, }); - background_pref_group.add(buildRangeAdw("dim-factor", [0, 1, 0.001, [0.25, 0.5, 0.75]], _("Background Dim-factor"), _("Smaller means darker."))); - appearance_page.add(icon_pref_group); - appearance_page.add(window_pref_group); - appearance_page.add(background_pref_group); + let label_box = new Gtk.Box({ + orientation: Gtk.Orientation.VERTICAL, + spacing: 6, + }); + + let label = new Gtk.Label({ + label: "Coverflow Alt-Tab", + wrap: true, + }); + let context = label.get_style_context(); + context.add_class("title-1"); + + let another_label = new Gtk.Label({ + label: getVersionString(), + }); + + let links_pref_group = new Adw.PreferencesGroup(); + let code_row = new Adw.ActionRow({ + icon_name: "code-symbolic", + title: _("Code (create pull requests, report issues, etc.)") + }); + let github_link = new Gtk.LinkButton({ + label: "Github", + uri: "https://github.com/dmo60/CoverflowAltTab", + }); + let donate_row = new Adw.ActionRow({ + title: _("Support me with a Donation"), + icon_name: "support-symbolic", + }) + let donate_link = new Gtk.LinkButton({ + label: "Liberapay", + uri: "https://liberapay.com/dsheeler/donate", + }); + + code_row.add_suffix(github_link); + code_row.set_activatable_widget(github_link); + donate_row.add_suffix(donate_link); + donate_row.set_activatable_widget(donate_link); + links_pref_group.add(code_row); + links_pref_group.add(donate_row); + + label_box.append(label); + label_box.append(another_label); + icon_box.append(icon_image); + icon_box.append(label_box); + contribute_icon_pref_group.add(icon_box); + + contribution_page.add(contribute_icon_pref_group); + contribution_page.add(links_pref_group) window.add(general_page); - window.add(appearance_page); + // window.add(appearance_page); window.add(tweaks_page) + window.add(contribution_page); window.set_search_enabled(true); } -function buildSwitcherAdw(key, title, subtitle=null) { +function buildSwitcherAdw(settings, key, title, subtitle=null) { let pref = new Adw.ActionRow({ title: title, }); @@ -272,7 +343,7 @@ function buildSwitcherAdw(key, title, subtitle=null) { return pref; } -function buildRangeAdw(key, values, title, subtitle=null, draw_value=false) { +function buildRangeAdw(settings, key, values, title, subtitle=null, draw_value=false) { let [min, max, step, defvs] = values; let pref = new Adw.ActionRow({ @@ -308,7 +379,7 @@ function buildRangeAdw(key, values, title, subtitle=null, draw_value=false) { return pref; } -function buildRadioAdw(key, buttons, title, subtitle=null) { +function buildRadioAdw(settings, key, buttons, title, subtitle=null) { let pref = new Adw.ActionRow({ title: title, }); @@ -355,7 +426,7 @@ function buildRadioAdw(key, buttons, title, subtitle=null) { return pref; }; -function buildSpinAdw(key, values, title, subtitle=null) { +function buildSpinAdw(settings, key, values, title, subtitle=null) { let [min, max, step, page] = values; let pref = new Adw.ActionRow({ title: title, @@ -386,7 +457,7 @@ function buildSpinAdw(key, values, title, subtitle=null) { return pref; } -function buildDropDownAdw(key, values, title, subtitle=null) { +function buildDropDownAdw(settings, key, values, title, subtitle=null) { let pref = new Adw.ActionRow({ title: title, }); @@ -429,179 +500,3 @@ function buildDropDownAdw(key, values, title, subtitle=null) { pref.add_suffix(reset_button); return pref; } - - - -function buildPrefsWidget() { - let frame = new Gtk.Box({ - orientation: Gtk.Orientation.VERTICAL, - 'margin-top': 20, - 'margin-bottom': 20, - 'margin-start': 20, - 'margin-end': 20, - spacing: 10 - }); - - frame.append(buildSwitcher("hide-panel", _("Hide panel during Coverflow"))); - frame.append(buildSwitcher("enforce-primary-monitor", _("Always show the switcher on the primary monitor"))); - frame.append(buildRadio("switcher-style", [_("Coverflow"), _("Timeline")], _("Switcher style"))); - frame.append(buildComboBox("easing-function", easing_options, _("Easing for animations"))); - frame.append(buildRange("animation-time", [0.01, 2, 0.001, [0.5, 1, 1.5]], _("Animation speed (smaller means faster)"))); - frame.append(buildSwitcher("randomize-animation-times", _("Randomize durations of animations"))); - frame.append(buildRange("dim-factor", [0, 1, 0.01, [0.25, 0.5, 0.75]], _("Background dim-factor (smaller means darker)"))); - frame.append(buildRadio("position", [_("Bottom"), _("Top")], _("Window title box position"))); - frame.append(buildRadio("icon-style", [_("Classic"), _("Overlay")], _("Application icon style"))); - frame.append(buildSwitcher("icon-has-shadow", _("Draw icon shadow"))); - frame.append(buildRange("overlay-icon-size", [0, 1024, 1, [32, 64, 128, 256, 512]], _("Overlay icon size"))); - frame.append(buildRange("overlay-icon-opacity", [0, 1, 0.01, [0.25, 0.5, 0.75]], _("Overlay icon opacity"))); - frame.append(buildSpin("offset", [-500, 500, 1, 10], _("Vertical offset (positive value moves everything up, negative down)"))); - frame.append(buildRange("preview-to-monitor-ratio", [0, 1, 0.01, [0.250, 0.500, 0.750]], _("Ratio of preview to monitor size"))); - frame.append(buildRange("preview-scaling-factor", [0, 1, 0.01, [0.250, 0.500, 0.800]], _("Factor by which to shrink previews off to the sides"))); - options = [{ - id: 'current', name: _("Current workspace only") - }, { - id: 'all', name: _("All workspaces") - }, { - id: 'all-currentfirst', name: _("All workspaces, current first") - }] - frame.append(buildComboBox("current-workspace-only", options, _("Show windows from current or all workspaces"))); - frame.append(buildSwitcher("switch-per-monitor", _("Only switch between windows on current monitor"))); - frame.append(buildSwitcher("bind-to-switch-applications", _("Bind to switch-applications keybinding"))); - frame.append(buildSwitcher("bind-to-switch-windows", _("Bind to switch-windows keybinding"))); - frame.append(buildComboBox("perspective-correction-method", [ - { id: "None", name:_("None") }, - { id: "Move Camera", name: _("Move Camera") }, - { id: "Adjust Angles", name: _("Adjust Angles")}], - _("How to Make an Off-Center Monitor Look Centered"))); - frame.append(buildSwitcher("highlight-mouse-over", _("Highlight Window Under Mouse"))); - frame.append(buildSwitcher("raise-mouse-over", _("Raise Window Under Mouse"))); - return frame; -} - -function buildSwitcher(key, labeltext, tooltip) { - let hbox = new Gtk.Box({orientation: Gtk.Orientation.HORIZONTAL, spacing: 10 }); - - let label = new Gtk.Label({label: labeltext, xalign: 0 }); - - let switcher = new Gtk.Switch({active: settings.get_boolean(key)}); - - switcher.connect('notify::active', function(widget) { - settings.set_boolean(key, widget.active); - }); - - label.expand = true; - - hbox.append(label); - hbox.append(switcher); - - return hbox; -} - -function buildRange(key, values, labeltext, tooltip) { - let [min, max, step, defvs] = values; - let hbox = new Gtk.Box({ orientation: Gtk.Orientation.HORIZONTAL, spacing: 10 }); - - let label = new Gtk.Label({label: labeltext, xalign: 0 }); - - let range = Gtk.Scale.new_with_range(Gtk.Orientation.HORIZONTAL, min, max, step); - range.set_value(settings.get_double(key)); - range.set_draw_value(true); - range.set_value_pos(Gtk.PositionType.RIGHT) - for (let defv of defvs) { - range.add_mark(defv, Gtk.PositionType.BOTTOM, null); - } - range.set_size_request(200, -1); - - range.connect('value-changed', function(slider) { - settings.set_double(key, slider.get_value()); - }); - - hbox.append(label); - hbox.append(range); - - return hbox; -} - -function buildRadio(key, buttons, labeltext) { - let hbox = new Gtk.Box({ orientation: Gtk.Orientation.HORIZONTAL, spacing: 10 }); - - let label = new Gtk.Label({label: labeltext, xalign: 0 }); - hbox.append(label) - - let radio = new Gtk.ToggleButton(); - - for (let button of buttons) { - radio = new Gtk.ToggleButton({group: radio, label: button}); - if (getBaseString(button) == settings.get_string(key)) { - radio.set_active(true); - } - - radio.connect('toggled', function(widget) { - if (widget.get_active()) { - settings.set_string(key, getBaseString(widget.get_label())); - } - }); - - hbox.append(radio); - }; - - return hbox; -}; - -function buildSpin(key, values, labeltext) { - let [min, max, step, page] = values; - let hbox = new Gtk.Box({ orientation: Gtk.Orientation.HORIZONTAL, spacing: 10 }); - - let label = new Gtk.Label({label: labeltext, xalign: 0 }); - - let spin = new Gtk.SpinButton(); - spin.set_range(min, max); - spin.set_increments(step, page); - spin.set_value(settings.get_int(key)); - - spin.connect('value-changed', function(widget) { - settings.set_int(key, widget.get_value()); - }); - - hbox.append(label); - hbox.append(spin); - - return hbox; -} - -function buildComboBox(key, values, labeltext) { - - let hbox = new Gtk.Box({ - orientation: Gtk.Orientation.HORIZONTAL, - margin_top: 5 - }); - - let setting_label = new Gtk.Label({ - label: labeltext + ' ', - xalign: 0 - }); - - let setting_enum = new Gtk.ComboBoxText({ - tooltip_text: labeltext - }); - - for (let i = 0; i < values.length; i++) { - let item = values[i]; - setting_enum.append(item.id, item.name); - - if (item.id == settings.get_string(key)) { - setting_enum.set_active_id(item.id); - } - } - - setting_enum.connect('changed', function(entry) { - let id = setting_enum.get_active_id(); - - settings.set_string(key, id); - }); - - hbox.append(setting_label); - hbox.append(setting_enum); - - return hbox; -} \ No newline at end of file diff --git a/CoverflowAltTab@dmo60.de/ui/icons/hicolor/scalable/actions/code-symbolic.svg b/CoverflowAltTab@dmo60.de/ui/icons/hicolor/scalable/actions/code-symbolic.svg new file mode 100644 index 0000000..587c3d3 --- /dev/null +++ b/CoverflowAltTab@dmo60.de/ui/icons/hicolor/scalable/actions/code-symbolic.svg @@ -0,0 +1,10 @@ + + + + + + + diff --git a/CoverflowAltTab@dmo60.de/ui/icons/hicolor/scalable/actions/contribute-symbolic.svg b/CoverflowAltTab@dmo60.de/ui/icons/hicolor/scalable/actions/contribute-symbolic.svg new file mode 100644 index 0000000..67bb36f --- /dev/null +++ b/CoverflowAltTab@dmo60.de/ui/icons/hicolor/scalable/actions/contribute-symbolic.svg @@ -0,0 +1,8 @@ + + + + + diff --git a/CoverflowAltTab@dmo60.de/ui/icons/hicolor/scalable/actions/coverflow-symbolic.svg b/CoverflowAltTab@dmo60.de/ui/icons/hicolor/scalable/actions/coverflow-symbolic.svg new file mode 100644 index 0000000..1519d33 --- /dev/null +++ b/CoverflowAltTab@dmo60.de/ui/icons/hicolor/scalable/actions/coverflow-symbolic.svg @@ -0,0 +1,143 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/CoverflowAltTab@dmo60.de/ui/icons/hicolor/scalable/actions/support-symbolic.svg b/CoverflowAltTab@dmo60.de/ui/icons/hicolor/scalable/actions/support-symbolic.svg new file mode 100644 index 0000000..67bb36f --- /dev/null +++ b/CoverflowAltTab@dmo60.de/ui/icons/hicolor/scalable/actions/support-symbolic.svg @@ -0,0 +1,8 @@ + + + + + diff --git a/CoverflowAltTab@palatis.blogspot.com/metadata.json b/CoverflowAltTab@palatis.blogspot.com/metadata.json index e4686d5..b524749 100644 --- a/CoverflowAltTab@palatis.blogspot.com/metadata.json +++ b/CoverflowAltTab@palatis.blogspot.com/metadata.json @@ -1,5 +1,5 @@ { - "shell-version": ["42"], + "shell-version": ["43"], "uuid": "CoverflowAltTab@palatis.blogspot.com", "name": "Coverflow Alt-Tab", "description": "Replacement of Alt-Tab, iterates through windows in a cover-flow manner.",