Skip to content

Commit 4afaadc

Browse files
authored
Merge pull request #361 from Leleat/save-state-on-tiling
fix: save/restore state on un/tiling instead of session lock/unlock
2 parents 9d2f8e5 + bf2cec4 commit 4afaadc

File tree

3 files changed

+91
-54
lines changed

3 files changed

+91
-54
lines changed

tiling-assistant@leleat-on-github/extension.js

Lines changed: 37 additions & 54 deletions
Original file line numberDiff line numberDiff line change
@@ -274,55 +274,37 @@ export default class TilingAssistantExtension extends Extension {
274274

275275
this._wasLocked = true;
276276

277-
const rectToJsObj = rect => rect && {
278-
x: rect.x,
279-
y: rect.y,
280-
width: rect.width,
281-
height: rect.height
282-
};
283-
284-
// can't just check for isTiled because maximized windows may
285-
// have an untiledRect as well in case window gaps are used
286-
const openWindows = this._twm.getWindows(true);
287-
const savedWindows = openWindows.filter(w => w.untiledRect).map(w => {
288-
return {
289-
windowId: w.get_stable_sequence(),
290-
isTiled: w.isTiled,
291-
tiledRect: rectToJsObj(w.tiledRect),
292-
untiledRect: rectToJsObj(w.untiledRect)
293-
};
294-
});
295-
296-
const saveObj = {
297-
'windows': savedWindows,
298-
'tileGroups': Array.from(this._twm.getTileGroups())
299-
};
300-
301277
const userPath = GLib.get_user_config_dir();
302278
const parentPath = GLib.build_filenamev([userPath, '/tiling-assistant']);
303279
const parent = Gio.File.new_for_path(parentPath);
304280

305281
try {
306282
parent.make_directory_with_parents(null);
307283
} catch (e) {
308-
if (e.code !== Gio.IOErrorEnum.EXISTS) {
284+
if (e.code !== Gio.IOErrorEnum.EXISTS)
309285
throw e;
310-
}
311286
}
312287

313-
const path = GLib.build_filenamev([parentPath, '/tiledSessionRestore.json']);
288+
const path = GLib.build_filenamev([parentPath, '/tiledSessionRestore2.json']);
314289
const file = Gio.File.new_for_path(path);
315290

316291
try {
317292
file.create(Gio.FileCreateFlags.NONE, null);
318293
} catch (e) {
319-
if (e.code !== Gio.IOErrorEnum.EXISTS) {
294+
if (e.code !== Gio.IOErrorEnum.EXISTS)
320295
throw e;
321-
}
322296
}
323297

324-
file.replace_contents(JSON.stringify(saveObj), null, false,
325-
Gio.FileCreateFlags.REPLACE_DESTINATION, null);
298+
file.replace_contents(
299+
JSON.stringify({
300+
windows: Object.fromEntries(this._twm.getTileStates()),
301+
tileGroups: Object.fromEntries(this._twm.getTileGroups())
302+
}),
303+
null,
304+
false,
305+
Gio.FileCreateFlags.REPLACE_DESTINATION,
306+
null
307+
);
326308
}
327309

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

338320
const userPath = GLib.get_user_config_dir();
339-
const path = GLib.build_filenamev([userPath, '/tiling-assistant/tiledSessionRestore.json']);
321+
const path = GLib.build_filenamev([userPath, '/tiling-assistant/tiledSessionRestore2.json']);
340322
const file = Gio.File.new_for_path(path);
341323
if (!file.query_exists(null))
342324
return;
343325

344326
try {
345327
file.create(Gio.FileCreateFlags.NONE, null);
346328
} catch (e) {
347-
if (e.code !== Gio.IOErrorEnum.EXISTS) {
329+
if (e.code !== Gio.IOErrorEnum.EXISTS)
348330
throw e;
349-
}
350331
}
351332

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

356-
const openWindows = this._twm.getWindows(true);
357-
const saveObj = JSON.parse(new TextDecoder().decode(contents));
337+
const states = JSON.parse(new TextDecoder().decode(contents));
338+
const keysAsNumbers = entries => entries.map(([key, value]) => [parseInt(key), value]);
339+
const tileGroups = new Map(keysAsNumbers(Object.entries(states.tileGroups)));
340+
const tileStates = new Map(keysAsNumbers(Object.entries(states.windows)));
341+
const openWindows = global.display.list_all_windows();
358342

359-
const windowObjects = saveObj['windows'];
360-
windowObjects.forEach(wObj => {
361-
const { windowId, isTiled, tiledRect, untiledRect } = wObj;
362-
const window = openWindows.find(w => w.get_stable_sequence() === windowId);
363-
if (!window)
364-
return;
343+
this._twm.setTileGroups(tileGroups);
344+
this._twm.setTileStates(tileStates);
365345

366-
const jsToRect = jsRect => jsRect && new Rect(
367-
jsRect.x, jsRect.y, jsRect.width, jsRect.height
368-
);
346+
openWindows.forEach(window => {
347+
const tileState = tileStates.get(window.get_id());
369348

370-
window.isTiled = isTiled;
371-
window.tiledRect = jsToRect(tiledRect);
372-
window.untiledRect = jsToRect(untiledRect);
373-
});
349+
if (tileState) {
350+
const { isTiled, tiledRect, untiledRect } = tileState;
351+
const jsToRect = jsRect => jsRect && new Rect(
352+
jsRect.x, jsRect.y, jsRect.width, jsRect.height
353+
);
374354

375-
const tileGroups = new Map(saveObj['tileGroups']);
376-
this._twm.setTileGroups(tileGroups);
377-
openWindows.forEach(w => {
378-
if (tileGroups.has(w.get_id())) {
379-
const group = this._twm.getTileGroupFor(w);
355+
window.isTiled = isTiled;
356+
window.tiledRect = jsToRect(tiledRect);
357+
window.untiledRect = jsToRect(untiledRect);
358+
}
359+
360+
361+
if (tileGroups.has(window.get_id())) {
362+
const group = this._twm.getTileGroupFor(window);
380363
this._twm.updateTileGroup(group);
381364
}
382365
});

tiling-assistant@leleat-on-github/src/extension/resizeHandler.js

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -352,6 +352,8 @@ export default class TilingResizeHandler {
352352
newGrabbedTiledRectHeight
353353
);
354354

355+
Twm.saveTileState(window);
356+
355357
// Now calculate the new tiledRects for the windows, which were resized
356358
// along the window based on the diff of the window's tiledRect pre
357359
// and after the grab.
@@ -379,6 +381,8 @@ export default class TilingResizeHandler {
379381
win.tiledRect.y += isResizingS ? tiledRectDiffHeight : 0;
380382
win.tiledRect.height -= tiledRectDiffHeight;
381383
}
384+
385+
Twm.saveTileState(win);
382386
});
383387

384388
this._preGrabRects.clear();

tiling-assistant@leleat-on-github/src/extension/tilingWindowManager.js

Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,11 @@ export class TilingWindowManager {
1616
// { windowId1: [windowIdX, windowIdY, ...], windowId2: [...], ... }
1717
this._tileGroups = new Map();
1818

19+
/**
20+
* {windowId: {isTiled: boolean, tiledRect: {}, untiledRect: {}}}
21+
*/
22+
this._tileStates = new Map();
23+
1924
const assertExistenceFor = window => {
2025
window.assertExistence = () => {};
2126

@@ -65,6 +70,7 @@ export class TilingWindowManager {
6570
});
6671

6772
this._tileGroups.clear();
73+
this._tileStates.clear();
6874

6975
if (this._openAppTiledTimerId) {
7076
GLib.Source.remove(this._openAppTiledTimerId);
@@ -246,19 +252,22 @@ export class TilingWindowManager {
246252
// Maximized with gaps
247253
if (maximize) {
248254
this._updateGappedMaxWindowSignals(window);
255+
this.saveTileState(window);
249256

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

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

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

@@ -334,6 +343,8 @@ export class TilingWindowManager {
334343
window.tiledRect = null;
335344
window.untiledRect = null;
336345

346+
this.deleteTilingState(window);
347+
337348
this.emit('window-untiled', window);
338349
}
339350

@@ -392,6 +403,17 @@ export class TilingWindowManager {
392403
this.updateTileGroup(tileGroup);
393404
}
394405

406+
static getTileStates() {
407+
return this._tileStates;
408+
}
409+
410+
/**
411+
* @param {Map<number, object>} states -
412+
*/
413+
static setTileStates(states) {
414+
this._tileStates = states;
415+
}
416+
395417
/**
396418
* @returns {Map<number,number>}
397419
* For ex: { windowId1: [windowIdX, windowIdY, ...], windowId2: ... }
@@ -1057,6 +1079,34 @@ export class TilingWindowManager {
10571079
app.open_new_window(-1);
10581080
}
10591081

1082+
static saveTileState(window) {
1083+
const windowState = this._tileStates.get(window.get_id());
1084+
const rectToJsObject = rect => {
1085+
return rect
1086+
? { x: rect.x, y: rect.y, width: rect.width, height: rect.height }
1087+
: undefined;
1088+
};
1089+
1090+
if (windowState) {
1091+
windowState.isTiled = window.isTiled;
1092+
windowState.tiledRect = rectToJsObject(window.tiledRect);
1093+
windowState.untiledRect = rectToJsObject(window.untiledRect);
1094+
} else {
1095+
this._tileStates.set(
1096+
window.get_id(),
1097+
{
1098+
isTiled: window.isTiled,
1099+
tiledRect: rectToJsObject(window.tiledRect),
1100+
untiledRect: rectToJsObject(window.untiledRect)
1101+
}
1102+
);
1103+
}
1104+
}
1105+
1106+
static deleteTilingState(window) {
1107+
this._tileStates.delete(window.get_id());
1108+
}
1109+
10601110
/**
10611111
* Gets the top windows, which are supposed to be in a tile group. That
10621112
* means windows, which are tiled, and don't overlap each other.

0 commit comments

Comments
 (0)