diff --git a/prefs.js b/prefs.js index 034e3ef..ac87853 100644 --- a/prefs.js +++ b/prefs.js @@ -59,7 +59,12 @@ function fillPreferencesWindow(window) { keybinds.add(focusBindings); focusBindings.add(_createKeybind(settings, "cycle-next")); focusBindings.add(_createKeybind(settings, "cycle-prev")); - focusBindings.add(_createKeybind(settings, "zoom")); + + const swapBindings = new Adw.PreferencesGroup(); + keybinds.add(swapBindings); + swapBindings.add(_createKeybind(settings, "swap-next")); + swapBindings.add(_createKeybind(settings, "swap-prev")); + swapBindings.add(_createKeybind(settings, "zoom")); const tileBindings = new Adw.PreferencesGroup(); keybinds.add(tileBindings); diff --git a/schemas/org.gnome.shell.extensions.fairy.gschema.xml b/schemas/org.gnome.shell.extensions.fairy.gschema.xml index d3a48de..343da56 100644 --- a/schemas/org.gnome.shell.extensions.fairy.gschema.xml +++ b/schemas/org.gnome.shell.extensions.fairy.gschema.xml @@ -55,11 +55,6 @@ j']]]> Cycle prev - - Return']]]> - Swap the current window with the master - - l']]]> @@ -79,6 +74,19 @@ Decrease the number of windows in the master area - + + k']]]> + Swap the current window with next + + + j']]]> + Swap the current window with previous + + + Return']]]> + Swap the current window with the master + + + diff --git a/sources/keybinds.js b/sources/keybinds.js index 4d88193..79be195 100644 --- a/sources/keybinds.js +++ b/sources/keybinds.js @@ -58,30 +58,20 @@ var KeyboardManager = GObject.registerClass( this._switchLayout("floating") ); - this._addBinding("cycle-next", () => { + this._addBinding("cycle-prev", () => { const mon = global.display.get_current_monitor(); const state = this._state.monitors[mon]; const idx = this._state.workIndexByHandle(state.focused); const newW = this._state.workIndex(mon, state.tags, idx + 1); this._state.focus(newW.handle); }); - this._addBinding("cycle-prev", () => { + this._addBinding("cycle-next", () => { const mon = global.display.get_current_monitor(); const state = this._state.monitors[mon]; const idx = this._state.workIndexByHandle(state.focused); const win = this._state.workIndex(mon, state.tags, idx - 1); this._state.focus(win.handle); }); - this._addBinding("zoom", () => { - const mon = global.display.get_current_monitor(); - const state = this._state.monitors[mon]; - const beforeZoom = state.focused; - if (this._state.workIndexByHandle(state.focused)) { - const win = this._state.workIndex(mon, state.tags, 0); - this._state.focus(win.handle); - } else this.state.focus(state.beforeZoom); - state.beforeZoom = beforeZoom; - }); this._addBinding("incrmfact", () => { const mon = global.display.get_current_monitor(); @@ -107,6 +97,34 @@ var KeyboardManager = GObject.registerClass( this._state.monitors[mon].nmaster -= 1; this._renderer.render(mon); }); + + this._addBinding("swap-prev", () => { + const mon = global.display.get_current_monitor(); + const state = this._state.monitors[mon]; + const idx = this._state.workIndexByHandle(state.focused); + this._state.swap(mon, state.tags, idx, idx + 1); + this._renderer.render(mon); + }); + this._addBinding("swap-next", () => { + const mon = global.display.get_current_monitor(); + const state = this._state.monitors[mon]; + const idx = this._state.workIndexByHandle(state.focused); + this._state.swap(mon, state.tags, idx, idx - 1); + this._renderer.render(mon); + }); + this._addBinding("zoom", () => { + const mon = global.display.get_current_monitor(); + const state = this._state.monitors[mon]; + const idx = this._state.workIndexByHandle(state.focused); + + // if the master is not focused + if (idx !== 0) + this._state.swap(mon, state.tags, idx, 0) + else + this._state.swap(mon, state.tags, idx, state.beforeZoom); + state.beforeZoom = idx; + this._renderer.render(mon); + }); } disable() { @@ -116,12 +134,15 @@ var KeyboardManager = GObject.registerClass( this._removeBinding("cycle-next"); this._removeBinding("cycle-prev"); - this._removeBinding("zoom"); this._removeBinding("incrmfact"); this._removeBinding("decrmfact"); this._removeBinding("incrnmaster"); this._removeBinding("decrnmaster"); + + this._removeBinding("swap-next"); + this._removeBinding("swap-prev"); + this._removeBinding("zoom"); } } ); diff --git a/sources/state.js b/sources/state.js index 9782a18..163ba0f 100644 --- a/sources/state.js +++ b/sources/state.js @@ -16,7 +16,7 @@ var StateManager = GObject.registerClass( */ focused: null, /** - * @type {Meta.Window} window's handle that was focused just before a zoom + * @type {number | null} window's index that was focused just before a zoom */ beforeZoom: null, tags: 1, @@ -54,8 +54,10 @@ var StateManager = GObject.registerClass( * @param {Meta.Window} handle */ newWindow(handle) { - this.windows.unshift(this._windowFromHandle(handle)); - log("New window on tag", this.windows[0].tags); + const window = this._windowFromHandle(handle); + this.monitors[window.monitor].beforeZoom = null; + log("New window on tag", window.tags); + this.windows.unshift(window); } /** @@ -72,6 +74,7 @@ var StateManager = GObject.registerClass( popByHandle(handle) { const window = this.windows.find((x) => x.handle === handle); if (!window) return null; + this.monitors[window.monitor].beforeZoom = null; this.windows = this.windows.filter((x) => x !== window); return window; } @@ -125,11 +128,32 @@ var StateManager = GObject.registerClass( /** * @param {Meta.Window} handle */ - warpCusror(handle) { + warpCursor(handle) { // TODO: Warp the cursor // TODO: Check if the warp-cursor setting is enabled. } + /** + * @param {number} mon + * @param {number} tags + * @param {number} idx + * @param {number} newIdx (will loop if over/under flow) + */ + swap(mon, tags, idx, newIdx) { + const windows = this.windows.filter( + (x) => x.monitor === mon && x.tags & tags + ); + if (newIdx < 0) newIdx = windows.length + newIdx; + newIdx %= windows.length; + + const gIdx = this.windows.findIndex(x => x === windows[idx]); + const gNewIdx = this.windows.findIndex(x => x === windows[newIdx]); + + const tmp = this.windows[gIdx]; + this.windows[gIdx] = this.windows[gNewIdx]; + this.windows[gNewIdx] = tmp; + } + /** * @param {number} mon * @param {number} tags