Skip to content

Commit

Permalink
add support for portrait mode
Browse files Browse the repository at this point in the history
Screens in Portrait mode will automatically switch column and row values.
Example:
You have 2 ultrawide monitors, one is landscape, the other is portrait.
Your config is set to 5 columns and 2 rows.
The landscape screen with have 5 columns and 2 rows.
The portrait screen with have 5 rows and 2 columns.

resolves #160
  • Loading branch information
GrylledCheez committed Jul 29, 2023
1 parent b7785bb commit 0ee1d4c
Show file tree
Hide file tree
Showing 3 changed files with 99 additions and 72 deletions.
5 changes: 3 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,11 +4,12 @@ standard `Win-Arrow` keys of Windows 10, allowing you to maximize, maximize
to sides, or 1/4 sized to corner a window using just `<Super>`+`<Arrows>`.

WinTile also supports:
- 2-5 columns for standard or ultrawide monitors
- 2-4 rows for standard or ultrawide monitors
- 1-5 columns for standard or ultrawide monitors
- 1-5 rows for standard or ultrawide monitors
- Mouse preview and snapping for placing tiles
- "Maximize" mode, which adds/removes GNOME animations
- Ultrawide-only mode allows 16:9 screens to use separate row/col counts
- Portrait screens will automatically swap columns and rows
- Adding gaps around tiles

<img src='demo.gif'>
Expand Down
164 changes: 95 additions & 69 deletions extension.js
Original file line number Diff line number Diff line change
Expand Up @@ -131,36 +131,38 @@ function moveAppCoordinates(app, x, y, w, h) {
*/
function moveApp(app, loc) {
_log(`moveApp) ${JSON.stringify(loc)}`);
var space = null;
if (loc.mouse) {
var curMonitor = getCurrentMonitor();
space = getActiveWorkspace().get_work_area_for_monitor(curMonitor);
} else {
space = app.get_work_area_current_monitor();
}
const isNotUltrawide = (space.width / space.height) < 1.9;
_log(`moveApp) isNotUltrawide: ${isNotUltrawide}`);
var monitor = null;
var monitorIndex = null;
if (loc.mouse)
monitorIndex = getCurrentMonitor();
else
monitorIndex = app.get_monitor();

monitor = getMonitorInfo(monitorIndex);

_log(`moveApp) monitor: ${JSON.stringify(monitor)}`);

var colCount = monitor.colCount;
var rowCount = monitor.rowCount;

var colCount = config.ultrawideOnly && isNotUltrawide ? config.nonUltraCols : config.cols;
// if the colCount >= than loc.col means that we're moving into a non-ultrawide monitor and it's near the right of the screen
if (loc.col >= colCount)
loc.col = colCount - 1;

var rowCount = config.ultrawideOnly && isNotUltrawide ? config.nonUltraRows : config.rows;
// if the rowCount >= than loc.row means that we're moving into a non-ultrawide monitor and it's near the bottom of the screen
if (loc.row >= rowCount)
loc.row = rowCount - 1;

var colWidth = Math.floor(space.width / colCount);
var rowHeight = Math.floor(space.height / rowCount);
var colWidth = Math.floor(monitor.width / colCount);
var rowHeight = Math.floor(monitor.height / rowCount);

let x = loc.col * colWidth + space.x;
let y = loc.row * rowHeight + space.y;
let x = loc.col * colWidth + monitor.x;
let y = loc.row * rowHeight + monitor.y;
let w = loc.width * colWidth;
let h = loc.height * rowHeight;

if (loc.col + loc.width === colCount)
w += space.width % colCount;
w += monitor.width % colCount;

if (!config.useMaximize) {
unMaximizeIfMaximized(app);
Expand Down Expand Up @@ -308,18 +310,18 @@ function sendMove(direction, ctrlPressed = false) {
_log('---');
_log(`sendMove) ${direction} ctrl: ${ctrlPressed}`);
var app = global.display.focus_window;
var space = app.get_work_area_current_monitor();
var monitorIndex = app.get_monitor();
var curMonitor = Main.layoutManager.monitors[monitorIndex];
var curMonitor = getMonitorInfo(monitorIndex);

let monitorToLeft = -1;
let monitorToRight = -1;
for (var i = 0; i < Main.layoutManager.monitors.length; i++) {
if (i === monitorIndex)
continue;

let testMonitor = Main.layoutManager.monitors[i];
_log(`sendMove) curMonitor: ${i} x: ${curMonitor.x} width: ${curMonitor.width}`);
_log(`sendMove) testMonitor: ${i} x: ${testMonitor.x} width: ${testMonitor.width}`);
let testMonitor = getMonitorInfo(i);
_log(`sendMove) curMonitor: ${JSON.stringify(curMonitor)}`);
_log(`sendMove) testMonitor: ${JSON.stringify(testMonitor)}`);

if (testMonitor.x + testMonitor.width === curMonitor.x)
monitorToLeft = i;
Expand All @@ -333,10 +335,8 @@ function sendMove(direction, ctrlPressed = false) {
if (!app.wintile && app.maximized_horizontally && app.maximized_vertically)
initApp(app, true);

const isNotUltrawide = (space.width / space.height) < 1.9;
_log(`sendMove) isNotUltrawide: ${isNotUltrawide}`);
var colCount = config.ultrawideOnly && isNotUltrawide ? config.nonUltraCols : config.cols;
var rowCount = config.ultrawideOnly && isNotUltrawide ? config.nonUltraRows : config.rows;
var colCount = curMonitor.colCount;
var rowCount = curMonitor.rowCount;

if (!app.wintile) {
// We are not in a tile. Reset and find the most logical position
Expand Down Expand Up @@ -755,17 +755,16 @@ function checkIfNearGrid(app) {
let ctrlPressed = mask & Clutter.ModifierType.CONTROL_MASK;
let superPressed = mask & Clutter.ModifierType.MOD4_MASK; // windows key
var close = false;
var curMonitor = getCurrentMonitor();
var monitor = Main.layoutManager.monitors[curMonitor];
var space = getActiveWorkspace().get_work_area_for_monitor(curMonitor);
const isNotUltrawide = (space.width / space.height) < 1.9;
_log(`checkIfNearGrid) isNotUltrawide: ${isNotUltrawide}`);

var colCount = config.ultrawideOnly && isNotUltrawide ? config.nonUltraCols : config.cols;
var colWidth = Math.floor(space.width / colCount);
var monitorIndex = getCurrentMonitor();
var monitor = getMonitorInfo(monitorIndex);
_log(`checkIfNearGrid) monitor: ${JSON.stringify(monitor)}`);

var rowCount = config.ultrawideOnly && isNotUltrawide ? config.nonUltraRows : config.rows;
var rowHeight = Math.floor(space.height / rowCount);
var colCount = monitor.colCount;
var rowCount = monitor.rowCount;

var colWidth = Math.floor(monitor.width / colCount);
var rowHeight = Math.floor(monitor.height / rowCount);

var inMonitorBounds = false;
if (mouseX >= monitor.x && mouseX < monitor.x + monitor.width && mouseY >= monitor.y && mouseY < monitor.y + monitor.height)
Expand All @@ -775,48 +774,47 @@ function checkIfNearGrid(app) {
_log(`checkIfNearGrid) mouse - mouseX:${mouseX} mouseY:${mouseY} mask:${mask}`);
_log(`checkIfNearGrid) keys - ctrl:${ctrlPressed} superPressed:${superPressed}`);
_log(`checkIfNearGrid) monitor - x:${monitor.x} y:${monitor.y} w:${monitor.width} h:${monitor.height} inB:${inMonitorBounds}`);
_log(`checkIfNearGrid) space - x:${space.x} y:${space.y} w:${space.width} h:${space.height}`);
_log(`checkIfNearGrid) window - x:${window.x} y:${window.y} w:${window.width} h:${window.height}`);
if (inMonitorBounds) {
var c = Math.floor((mouseX - space.x) / colWidth);
var r = Math.floor((mouseY - space.y) / rowHeight);
var c = Math.floor((mouseX - monitor.x) / colWidth);
var r = Math.floor((mouseY - monitor.y) / rowHeight);
c = Math.max(0, Math.min(c, colCount - 1));
r = Math.max(0, Math.min(r, rowCount - 1));

var gridX = c * colWidth + space.x;
var gridX = c * colWidth + monitor.x;
var inGrid = mouseX > gridX && mouseX < gridX + colWidth;
var centerOfGrid = mouseX > Math.floor(gridX + colWidth / 3) && mouseX < Math.floor(gridX + (2 * colWidth / 3));
var topRow = mouseY < space.y + rowHeight;
var bottomRow = mouseY > space.y + space.height - rowHeight;
var nearTop = isClose(mouseY, space.y) || mouseY < space.y;
var nearBottom = isClose(mouseY, space.y + space.height) || mouseY > space.y + space.height;
var nearLeft = isClose(mouseX, space.x) || mouseX < space.x;
var nearRight = isClose(mouseX, space.x + space.width) || mouseX > space.x + space.width;

var centerOfScreenH = space.x + Math.floor(space.width / 2);
var topRow = mouseY < monitor.y + rowHeight;
var bottomRow = mouseY > monitor.y + monitor.height - rowHeight;
var nearTop = isClose(mouseY, monitor.y) || mouseY < monitor.y;
var nearBottom = isClose(mouseY, monitor.y + monitor.height) || mouseY > monitor.y + monitor.height;
var nearLeft = isClose(mouseX, monitor.x) || mouseX < monitor.x;
var nearRight = isClose(mouseX, monitor.x + monitor.width) || mouseX > monitor.x + monitor.width;

var centerOfScreenH = monitor.x + Math.floor(monitor.width / 2);
var columnWidthFraction = Math.floor(colWidth / 5);
var nearCenterH = mouseX > centerOfScreenH - (columnWidthFraction / 2) && mouseX < centerOfScreenH + (columnWidthFraction / 2);

var centerOfScreenV = space.y + Math.floor(space.height / 2);
var centerOfScreenV = monitor.y + Math.floor(monitor.height / 2);
var rowHeightFraction = Math.floor(rowHeight / 5);
var nearCenterV = mouseY > centerOfScreenV - (rowHeightFraction / 2) && mouseY < centerOfScreenV + (rowHeightFraction / 2);

if (ctrlPressed && superPressed && dragStart === null) {
dragStart = {col: c, row: r, monitor: curMonitor};
dragStart = {col: c, row: r, monitorIndex};
_log(`checkIfNearGrid) dragStart: ${JSON.stringify(dragStart)}`);
}

if (ctrlPressed && superPressed) {
// check if it's on the samescreen it was on before, otherwise reinitialize dragStart
if (dragStart.monitor !== curMonitor)
dragStart = {col: c, row: r, monitor: curMonitor};
if (dragStart.monitorIndex !== monitorIndex)
dragStart = {col: c, row: r, monitor};
// If ctrl and super are pressed, draw the box from start to finish
showPreview({
col: Math.min(c, dragStart.col),
row: Math.min(r, dragStart.row),
width: Math.abs(c - dragStart.col) + 1,
height: Math.abs(r - dragStart.row) + 1,
}, space.x, space.y, colWidth, rowHeight);
}, monitor.x, monitor.y, colWidth, rowHeight);
close = true;
} else if (nearTop && nearCenterH) {
// If we are in the center top, show a preview for maximize
Expand All @@ -825,7 +823,7 @@ function checkIfNearGrid(app) {
row: 0,
width: colCount,
height: rowCount,
}, space.x, space.y, colWidth, rowHeight);
}, monitor.x, monitor.y, colWidth, rowHeight);
close = true;
} else if (nearBottom && nearCenterH) {
// If we are in the center bottom, show a preview for bottom maximized horizontally
Expand All @@ -834,7 +832,7 @@ function checkIfNearGrid(app) {
row: rowCount - 1,
width: colCount,
height: 1,
}, space.x, space.y, colWidth, rowHeight);
}, monitor.x, monitor.y, colWidth, rowHeight);
close = true;
} else if (nearLeft && nearCenterV) {
// If we are in the center left, show a preview for left maximize
Expand All @@ -844,14 +842,14 @@ function checkIfNearGrid(app) {
row: 0,
width: 2,
height: rowCount,
}, space.x, space.y, colWidth, rowHeight);
}, monitor.x, monitor.y, colWidth, rowHeight);
} else {
showPreview({
col: 0,
row: 0,
width: 1,
height: rowCount,
}, space.x, space.y, colWidth, rowHeight);
}, monitor.x, monitor.y, colWidth, rowHeight);
}
close = true;
} else if (nearRight && nearCenterV) {
Expand All @@ -862,14 +860,14 @@ function checkIfNearGrid(app) {
row: 0,
width: 2,
height: rowCount,
}, space.x, space.y, colWidth, rowHeight);
}, monitor.x, monitor.y, colWidth, rowHeight);
} else {
showPreview({
col: colCount - 1,
row: 0,
width: 1,
height: rowCount,
}, space.x, space.y, colWidth, rowHeight);
}, monitor.x, monitor.y, colWidth, rowHeight);
}
close = true;
} else if (nearLeft && topRow) {
Expand All @@ -880,14 +878,14 @@ function checkIfNearGrid(app) {
row: 0,
width: 2,
height: 1,
}, space.x, space.y, colWidth, rowHeight);
}, monitor.x, monitor.y, colWidth, rowHeight);
} else {
showPreview({
col: 0,
row: 0,
width: 1,
height: 1,
}, space.x, space.y, colWidth, rowHeight);
}, monitor.x, monitor.y, colWidth, rowHeight);
}
close = true;
} else if (nearLeft && bottomRow) {
Expand All @@ -898,14 +896,14 @@ function checkIfNearGrid(app) {
row: rowCount - 1,
width: 2,
height: 1,
}, space.x, space.y, colWidth, rowHeight);
}, monitor.x, monitor.y, colWidth, rowHeight);
} else {
showPreview({
col: 0,
row: rowCount - 1,
width: 1,
height: 1,
}, space.x, space.y, colWidth, rowHeight);
}, monitor.x, monitor.y, colWidth, rowHeight);
}
close = true;
} else if (nearRight && topRow) {
Expand All @@ -916,14 +914,14 @@ function checkIfNearGrid(app) {
row: 0,
width: 2,
height: 1,
}, space.x, space.y, colWidth, rowHeight);
}, monitor.x, monitor.y, colWidth, rowHeight);
} else {
showPreview({
col: colCount - 1,
row: 0,
width: 1,
height: 1,
}, space.x, space.y, colWidth, rowHeight);
}, monitor.x, monitor.y, colWidth, rowHeight);
}
close = true;
} else if (nearRight && bottomRow) {
Expand All @@ -934,14 +932,14 @@ function checkIfNearGrid(app) {
row: rowCount - 1,
width: 2,
height: 1,
}, space.x, space.y, colWidth, rowHeight);
}, monitor.x, monitor.y, colWidth, rowHeight);
} else {
showPreview({
col: colCount - 1,
row: rowCount - 1,
width: 1,
height: 1,
}, space.x, space.y, colWidth, rowHeight);
}, monitor.x, monitor.y, colWidth, rowHeight);
}
close = true;
} else if (nearTop && inGrid) {
Expand All @@ -951,7 +949,7 @@ function checkIfNearGrid(app) {
row: 0,
width: 1,
height: 1,
}, space.x, space.y, colWidth, rowHeight);
}, monitor.x, monitor.y, colWidth, rowHeight);
close = true;
} else if (nearBottom && centerOfGrid) {
// If we are close to the bottom and in the middle of a grid, show a preview for the bottom grid item at full height
Expand All @@ -960,7 +958,7 @@ function checkIfNearGrid(app) {
row: 0,
width: 1,
height: rowCount,
}, space.x, space.y, colWidth, rowHeight);
}, monitor.x, monitor.y, colWidth, rowHeight);
close = true;
} else if (nearBottom && inGrid) {
// If we are close to the bottom, show a preview for the bottom grid item
Expand All @@ -969,7 +967,7 @@ function checkIfNearGrid(app) {
row: rowCount - 1,
width: 1,
height: 1,
}, space.x, space.y, colWidth, rowHeight);
}, monitor.x, monitor.y, colWidth, rowHeight);
close = true;
} else if (ctrlPressed) {
// If we are close to the left or right or ctrl pressed, show the preview, wherever the pointer is
Expand All @@ -978,7 +976,7 @@ function checkIfNearGrid(app) {
row: r,
width: 1,
height: 1,
}, space.x, space.y, colWidth, rowHeight);
}, monitor.x, monitor.y, colWidth, rowHeight);
close = true;
}
}
Expand Down Expand Up @@ -1010,6 +1008,34 @@ function getCurrentMonitor() {
return monitorProvider.get_current_monitor();
}

/**
* @param {int} monitorIndex self explanatory
*/
function getMonitorInfo(monitorIndex) {
let space = getActiveWorkspace().get_work_area_for_monitor(monitorIndex);
let isPortrait = space.width < space.height;
let isNotUltrawide = (space.height / space.width) < 1.9 && (space.width / space.height) < 1.9;
var colCount = config.ultrawideOnly && isNotUltrawide ? config.nonUltraCols : config.cols;
var rowCount = config.ultrawideOnly && isNotUltrawide ? config.nonUltraRows : config.rows;

// swap col and row in portrait mode
if (isPortrait)
[colCount, rowCount] = [rowCount, colCount];

let monitor = {
monitorIndex,
x: space.x,
y: space.y,
width: space.width,
height: space.height,
isPortrait,
isNotUltrawide,
colCount,
rowCount,
};
return monitor;
}

/**
*
*/
Expand Down
2 changes: 1 addition & 1 deletion metadata.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "WinTile",
"description": "WinTile is a hotkey driven window tiling system for GNOME that imitates the standard Win-Arrow keys of Windows 10, allowing you to maximize, maximize to sides, or 1/4 sized to corner across a single or multiple monitors using just Super+Arrow.\n\nAs of v14, WinTile also supports:\n- 2-5 columns and 1-4 rows for standard or ultrawide monitors\n- Top/bottom half support\n- Mouse preview and snapping for placing windows\n- 'Maximize' mode, which adds/removes GNOME animations\n- 'Ultrawide-only' mode, to allow standard screens to have different cols/row than ultrawides\n- Add gaps around tiles to avoid the 'crowded elevator' feeling'\n- Ctrl+Super+Arrow to grow a tile in that direction if space is available\n- Ctrl+drag to drop a tile in a specific spot\n- Ctrl+Super+drag to draw a grid for the new tile",
"description": "WinTile is a hotkey driven window tiling system for GNOME that imitates the standard Win-Arrow keys of Windows 10, allowing you to maximize, maximize to sides, or 1/4 sized to corner across a single or multiple monitors using just Super+Arrow.\n\nAs of v14, WinTile also supports:\n- 2-5 columns and 1-4 rows for standard or ultrawide monitors\n- Top/bottom half support\n- Mouse preview and snapping for placing windows\n- 'Maximize' mode, which adds/removes GNOME animations\n- 'Ultrawide-only' mode, to allow standard screens to have different cols/row than ultrawides\n- Portrait screens will automatically swap columns and rows\n- Add gaps around tiles to avoid the 'crowded elevator' feeling'\n- Ctrl+Super+Arrow to grow a tile in that direction if space is available\n- Ctrl+drag to drop a tile in a specific spot\n- Ctrl+Super+drag to draw a grid for the new tile",
"uuid": "[email protected]",
"url": "https://github.com/fmstrat/wintile",
"settings-schema":"org.gnome.shell.extensions.wintile",
Expand Down

0 comments on commit 0ee1d4c

Please sign in to comment.