Skip to content

Commit

Permalink
Merge pull request #361 from Leleat/save-state-on-tiling
Browse files Browse the repository at this point in the history
fix: save/restore state on un/tiling instead of session lock/unlock
  • Loading branch information
Leleat authored Aug 5, 2024
2 parents 9d2f8e5 + bf2cec4 commit 4afaadc
Show file tree
Hide file tree
Showing 3 changed files with 91 additions and 54 deletions.
91 changes: 37 additions & 54 deletions tiling-assistant@leleat-on-github/extension.js
Original file line number Diff line number Diff line change
Expand Up @@ -274,55 +274,37 @@ export default class TilingAssistantExtension extends Extension {

this._wasLocked = true;

const rectToJsObj = rect => rect && {
x: rect.x,
y: rect.y,
width: rect.width,
height: rect.height
};

// can't just check for isTiled because maximized windows may
// have an untiledRect as well in case window gaps are used
const openWindows = this._twm.getWindows(true);
const savedWindows = openWindows.filter(w => w.untiledRect).map(w => {
return {
windowId: w.get_stable_sequence(),
isTiled: w.isTiled,
tiledRect: rectToJsObj(w.tiledRect),
untiledRect: rectToJsObj(w.untiledRect)
};
});

const saveObj = {
'windows': savedWindows,
'tileGroups': Array.from(this._twm.getTileGroups())
};

const userPath = GLib.get_user_config_dir();
const parentPath = GLib.build_filenamev([userPath, '/tiling-assistant']);
const parent = Gio.File.new_for_path(parentPath);

try {
parent.make_directory_with_parents(null);
} catch (e) {
if (e.code !== Gio.IOErrorEnum.EXISTS) {
if (e.code !== Gio.IOErrorEnum.EXISTS)
throw e;
}
}

const path = GLib.build_filenamev([parentPath, '/tiledSessionRestore.json']);
const path = GLib.build_filenamev([parentPath, '/tiledSessionRestore2.json']);
const file = Gio.File.new_for_path(path);

try {
file.create(Gio.FileCreateFlags.NONE, null);
} catch (e) {
if (e.code !== Gio.IOErrorEnum.EXISTS) {
if (e.code !== Gio.IOErrorEnum.EXISTS)
throw e;
}
}

file.replace_contents(JSON.stringify(saveObj), null, false,
Gio.FileCreateFlags.REPLACE_DESTINATION, null);
file.replace_contents(
JSON.stringify({
windows: Object.fromEntries(this._twm.getTileStates()),
tileGroups: Object.fromEntries(this._twm.getTileGroups())
}),
null,
false,
Gio.FileCreateFlags.REPLACE_DESTINATION,
null
);
}

/**
Expand All @@ -336,47 +318,48 @@ export default class TilingAssistantExtension extends Extension {
this._wasLocked = false;

const userPath = GLib.get_user_config_dir();
const path = GLib.build_filenamev([userPath, '/tiling-assistant/tiledSessionRestore.json']);
const path = GLib.build_filenamev([userPath, '/tiling-assistant/tiledSessionRestore2.json']);
const file = Gio.File.new_for_path(path);
if (!file.query_exists(null))
return;

try {
file.create(Gio.FileCreateFlags.NONE, null);
} catch (e) {
if (e.code !== Gio.IOErrorEnum.EXISTS) {
if (e.code !== Gio.IOErrorEnum.EXISTS)
throw e;
}
}

const [success, contents] = file.load_contents(null);
if (!success || !contents.length)
return;

const openWindows = this._twm.getWindows(true);
const saveObj = JSON.parse(new TextDecoder().decode(contents));
const states = JSON.parse(new TextDecoder().decode(contents));
const keysAsNumbers = entries => entries.map(([key, value]) => [parseInt(key), value]);
const tileGroups = new Map(keysAsNumbers(Object.entries(states.tileGroups)));
const tileStates = new Map(keysAsNumbers(Object.entries(states.windows)));
const openWindows = global.display.list_all_windows();

const windowObjects = saveObj['windows'];
windowObjects.forEach(wObj => {
const { windowId, isTiled, tiledRect, untiledRect } = wObj;
const window = openWindows.find(w => w.get_stable_sequence() === windowId);
if (!window)
return;
this._twm.setTileGroups(tileGroups);
this._twm.setTileStates(tileStates);

const jsToRect = jsRect => jsRect && new Rect(
jsRect.x, jsRect.y, jsRect.width, jsRect.height
);
openWindows.forEach(window => {
const tileState = tileStates.get(window.get_id());

window.isTiled = isTiled;
window.tiledRect = jsToRect(tiledRect);
window.untiledRect = jsToRect(untiledRect);
});
if (tileState) {
const { isTiled, tiledRect, untiledRect } = tileState;
const jsToRect = jsRect => jsRect && new Rect(
jsRect.x, jsRect.y, jsRect.width, jsRect.height
);

const tileGroups = new Map(saveObj['tileGroups']);
this._twm.setTileGroups(tileGroups);
openWindows.forEach(w => {
if (tileGroups.has(w.get_id())) {
const group = this._twm.getTileGroupFor(w);
window.isTiled = isTiled;
window.tiledRect = jsToRect(tiledRect);
window.untiledRect = jsToRect(untiledRect);
}


if (tileGroups.has(window.get_id())) {
const group = this._twm.getTileGroupFor(window);
this._twm.updateTileGroup(group);
}
});
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -352,6 +352,8 @@ export default class TilingResizeHandler {
newGrabbedTiledRectHeight
);

Twm.saveTileState(window);

// Now calculate the new tiledRects for the windows, which were resized
// along the window based on the diff of the window's tiledRect pre
// and after the grab.
Expand Down Expand Up @@ -379,6 +381,8 @@ export default class TilingResizeHandler {
win.tiledRect.y += isResizingS ? tiledRectDiffHeight : 0;
win.tiledRect.height -= tiledRectDiffHeight;
}

Twm.saveTileState(win);
});

this._preGrabRects.clear();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,11 @@ export class TilingWindowManager {
// { windowId1: [windowIdX, windowIdY, ...], windowId2: [...], ... }
this._tileGroups = new Map();

/**
* {windowId: {isTiled: boolean, tiledRect: {}, untiledRect: {}}}
*/
this._tileStates = new Map();

const assertExistenceFor = window => {
window.assertExistence = () => {};

Expand Down Expand Up @@ -65,6 +70,7 @@ export class TilingWindowManager {
});

this._tileGroups.clear();
this._tileStates.clear();

if (this._openAppTiledTimerId) {
GLib.Source.remove(this._openAppTiledTimerId);
Expand Down Expand Up @@ -246,19 +252,22 @@ export class TilingWindowManager {
// Maximized with gaps
if (maximize) {
this._updateGappedMaxWindowSignals(window);
this.saveTileState(window);

// Tiled window
} else if (!fakeTile) {
// Make the tile group only consist of the window itself to stop
// resizing or raising together. Also don't call the Tiling Popup.
if (Settings.getBoolean('disable-tile-groups') || ignoreTA) {
this.updateTileGroup([window]);
this.saveTileState(window);
return;
}

// Setup the (new) tileGroup to raise tiled windows as a group
const topTileGroup = this._getWindowsForBuildingTileGroup(monitor);
this.updateTileGroup(topTileGroup);
this.saveTileState(window);

this.emit('window-tiled', window);

Expand Down Expand Up @@ -334,6 +343,8 @@ export class TilingWindowManager {
window.tiledRect = null;
window.untiledRect = null;

this.deleteTilingState(window);

this.emit('window-untiled', window);
}

Expand Down Expand Up @@ -392,6 +403,17 @@ export class TilingWindowManager {
this.updateTileGroup(tileGroup);
}

static getTileStates() {
return this._tileStates;
}

/**
* @param {Map<number, object>} states -
*/
static setTileStates(states) {
this._tileStates = states;
}

/**
* @returns {Map<number,number>}
* For ex: { windowId1: [windowIdX, windowIdY, ...], windowId2: ... }
Expand Down Expand Up @@ -1057,6 +1079,34 @@ export class TilingWindowManager {
app.open_new_window(-1);
}

static saveTileState(window) {
const windowState = this._tileStates.get(window.get_id());
const rectToJsObject = rect => {
return rect
? { x: rect.x, y: rect.y, width: rect.width, height: rect.height }
: undefined;
};

if (windowState) {
windowState.isTiled = window.isTiled;
windowState.tiledRect = rectToJsObject(window.tiledRect);
windowState.untiledRect = rectToJsObject(window.untiledRect);
} else {
this._tileStates.set(
window.get_id(),
{
isTiled: window.isTiled,
tiledRect: rectToJsObject(window.tiledRect),
untiledRect: rectToJsObject(window.untiledRect)
}
);
}
}

static deleteTilingState(window) {
this._tileStates.delete(window.get_id());
}

/**
* Gets the top windows, which are supposed to be in a tile group. That
* means windows, which are tiled, and don't overlap each other.
Expand Down

0 comments on commit 4afaadc

Please sign in to comment.