diff --git a/README.md b/README.md
index 4f82f1b..2604384 100644
--- a/README.md
+++ b/README.md
@@ -59,6 +59,7 @@ PaperWM doesn't handle attached modal dialogs very well, so it's best to turn it
| SuperShiftTab or AltShiftTab | Cycle backwards through the most recently used windows |
| SuperC | Center the active window horizontally |
| SuperR | Resize the window (cycles through useful widths) |
+| SuperShiftR | Resize the window (cycles through useful heights) |
| SuperF | Maximize the width of a window |
| SuperShiftF | Toggle fullscreen |
| SuperReturn or SuperN | Create a new window from the active application |
diff --git a/examples/keybindings.js b/examples/keybindings.js
index 678d759..0b11c71 100644
--- a/examples/keybindings.js
+++ b/examples/keybindings.js
@@ -90,56 +90,6 @@ function showNavigator() {
}
-function cycleWindowHeight() {
- Keybindings.bindkey("q", "cycle-height", cycleHeight, { activeInNavigator: true });
-
- var Tiling = Extension.imports.tiling;
-
- function cycleHeight(metaWindow) {
- const ratios = [1/3, 1/2, 2/3];
-
- function findNext(tr) {
- // Find the first ratio that is significantly bigger than 'tr'
- for (let i = 0; i < ratios.length; i++) {
- let r = ratios[i]
- if (tr <= r) {
- if (tr/r > 0.9) {
- return (i+1) % ratios.length;
- } else {
- return i;
- }
- }
- }
- return 0; // cycle
- }
-
- let space = Tiling.spaces.spaceOfWindow(metaWindow);
- if (!space)
- return;
-
- let i = space.indexOf(metaWindow);
-
- function allocate(column, available) {
- available -= (column.length - 1) * Tiling.prefs.window_gap;
- let frame = metaWindow.get_frame_rect();
- let r = frame.height / available;
- let nextR = ratios[findNext(r)];
- return column.map(mw => {
- if (mw === metaWindow) {
- return Math.floor(available * nextR);
- } else {
- return Math.floor(available * (1-nextR)/(column.length-1));
- }
- });
- }
-
- if (space[i].length > 1) {
- space.layout(false, {customAllocators: {[i]: allocate}});
- }
- }
-}
-
-
// listFreeBindings("").join("\n")
function listFreeBindings(modifierString) {
let free = [];
diff --git a/keybindings.js b/keybindings.js
index a1f5809..d80d3f8 100644
--- a/keybindings.js
+++ b/keybindings.js
@@ -118,6 +118,11 @@ function init() {
Tiling),
Meta.KeyBindingFlags.PER_WINDOW);
+ registerPaperAction("cycle-height",
+ dynamic_function_ref("cycleWindowHeight",
+ Tiling),
+ Meta.KeyBindingFlags.PER_WINDOW);
+
registerPaperAction("center-horizontally",
dynamic_function_ref("centerWindowHorizontally",
Tiling),
diff --git a/prefs.js b/prefs.js
index ac96c77..7fffc6d 100644
--- a/prefs.js
+++ b/prefs.js
@@ -164,7 +164,8 @@ class SettingsWidget {
'switch-first', 'switch-last', 'live-alt-tab', 'live-alt-tab-backward',
'move-left', 'move-right', 'move-up', 'move-down',
'slurp-in', 'barf-out', 'center-horizontally',
- 'paper-toggle-fullscreen', 'toggle-maximize-width', 'cycle-width']
+ 'paper-toggle-fullscreen', 'toggle-maximize-width', 'cycle-width',
+ 'cycle-height']
.forEach(k => {
addKeybinding(windows.model.child_model, settings, k);
});
diff --git a/schemas/gschemas.compiled b/schemas/gschemas.compiled
index dbf5152..2fb3064 100644
Binary files a/schemas/gschemas.compiled and b/schemas/gschemas.compiled differ
diff --git a/schemas/org.gnome.shell.extensions.org-scrollwm.gschema.xml b/schemas/org.gnome.shell.extensions.org-scrollwm.gschema.xml
index bde02a2..2be67e1 100644
--- a/schemas/org.gnome.shell.extensions.org-scrollwm.gschema.xml
+++ b/schemas/org.gnome.shell.extensions.org-scrollwm.gschema.xml
@@ -113,6 +113,11 @@
Cycle through useful window widths
+
+ r']]]>
+ Cycle through useful window heights
+
+
c']]]>
Center window horizontally
diff --git a/tiling.js b/tiling.js
index 9123434..134b79b 100644
--- a/tiling.js
+++ b/tiling.js
@@ -2345,6 +2345,54 @@ function cycleWindowWidth(metaWindow) {
metaWindow.move_resize_frame(true, nextX, frame.y, nextW, frame.height);
}
+function cycleWindowHeight(metaWindow) {
+ log("OMG")
+ const ratios = [1/3, 1/2, 2/3];
+
+ function findNext(tr) {
+ // Find the first ratio that is significantly bigger than 'tr'
+ for (let i = 0; i < ratios.length; i++) {
+ let r = ratios[i]
+ if (tr <= r) {
+ if (tr/r > 0.9) {
+ return (i+1) % ratios.length;
+ } else {
+ return i;
+ }
+ }
+ }
+ return 0; // cycle
+ }
+
+ let space = spaces.spaceOfWindow(metaWindow);
+ if (!space)
+ return;
+
+ let i = space.indexOf(metaWindow);
+
+ // Fix `frame` outside `allocate` so the allocation wont change during
+ // fixpoint calculation. (could move more out, but then we'd have to
+ // calculate available manually)
+ let frame = metaWindow.get_frame_rect();
+
+ function allocate(column, available) {
+ available -= (column.length - 1) * prefs.window_gap;
+ let r = frame.height / available;
+ let nextR = ratios[findNext(r)];
+ return column.map(mw => {
+ if (mw === metaWindow) {
+ return Math.floor(available * nextR);
+ } else {
+ return Math.floor(available * (1-nextR)/(column.length-1));
+ }
+ });
+ }
+
+ if (space[i].length > 1) {
+ space.layout(false, {customAllocators: {[i]: allocate}});
+ }
+}
+
function activateNthWindow(n, space) {
space = space || spaces.spaceOf(workspaceManager.get_active_workspace());
let nth = space[n][0];