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