Implement custom layout persistence
Features: - Custom layouts now saved to ~/.local/share/gridsnap/layouts.json - Layouts automatically loaded on extension initialization - Layouts persist across Cinnamon restarts and extension reloads - Only custom layouts saved to file (default layouts remain in code) - Added GLib and Gio imports for file operations - Error handling for file read/write operations Technical implementation: - _loadLayouts(): Merges default layouts with saved custom layouts on startup - _saveLayouts(): Extracts and saves only custom-* layouts to JSON file - Automatically creates storage directory if it doesn't exist - Called when user saves a layout in the graphical editor Fixes TODO item #1 - Custom Layout Persistence Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
This commit is contained in:
14
TODO.md
14
TODO.md
@@ -2,14 +2,14 @@
|
|||||||
|
|
||||||
## Critical Issues
|
## Critical Issues
|
||||||
|
|
||||||
### 1. Custom Layout Persistence (extension.js:297)
|
### 1. Custom Layout Persistence ✅ COMPLETED
|
||||||
**Priority: High**
|
**Priority: High**
|
||||||
- [ ] Custom layouts are only stored in memory
|
- [x] Custom layouts are only stored in memory
|
||||||
- [ ] Layouts are lost when extension reloads or Cinnamon restarts
|
- [x] Layouts are lost when extension reloads or Cinnamon restarts
|
||||||
- [ ] Need to implement file-based storage
|
- [x] Need to implement file-based storage
|
||||||
- [ ] Location: `~/.config/gridsnap/layouts.json` or similar
|
- [x] Location: `~/.local/share/gridsnap/layouts.json`
|
||||||
- [ ] Save layouts when created in graphical editor
|
- [x] Save layouts when created in graphical editor
|
||||||
- [ ] Load layouts on extension initialization
|
- [x] Load layouts on extension initialization
|
||||||
|
|
||||||
### 2. Remove Last Zone Implementation (extension.js:236-274)
|
### 2. Remove Last Zone Implementation (extension.js:236-274)
|
||||||
**Priority: Medium**
|
**Priority: Medium**
|
||||||
|
|||||||
71
extension.js
71
extension.js
@@ -5,9 +5,15 @@ const Clutter = imports.gi.Clutter;
|
|||||||
const Lang = imports.lang;
|
const Lang = imports.lang;
|
||||||
const Mainloop = imports.mainloop;
|
const Mainloop = imports.mainloop;
|
||||||
const Settings = imports.ui.settings;
|
const Settings = imports.ui.settings;
|
||||||
|
const GLib = imports.gi.GLib;
|
||||||
|
const Gio = imports.gi.Gio;
|
||||||
|
|
||||||
let zoneManager;
|
let zoneManager;
|
||||||
|
|
||||||
|
// Storage path for custom layouts
|
||||||
|
const STORAGE_DIR = GLib.get_user_data_dir() + '/gridsnap';
|
||||||
|
const LAYOUTS_FILE = STORAGE_DIR + '/layouts.json';
|
||||||
|
|
||||||
// Default zone layouts
|
// Default zone layouts
|
||||||
const DEFAULT_LAYOUTS = {
|
const DEFAULT_LAYOUTS = {
|
||||||
'grid-2x2': {
|
'grid-2x2': {
|
||||||
@@ -291,11 +297,11 @@ ZoneEditor.prototype = {
|
|||||||
zones: this.zones
|
zones: this.zones
|
||||||
};
|
};
|
||||||
zoneManager.currentLayout = layoutId;
|
zoneManager.currentLayout = layoutId;
|
||||||
|
|
||||||
|
// Persist to file for permanent storage
|
||||||
|
zoneManager._saveLayouts();
|
||||||
|
|
||||||
Main.notify('GridSnap', 'Layout saved: ' + layoutName);
|
Main.notify('GridSnap', 'Layout saved: ' + layoutName);
|
||||||
|
|
||||||
// TODO: Persist to file for permanent storage
|
|
||||||
global.log('GridSnap: Layout saved - ' + JSON.stringify(zoneManager.layouts[layoutId]));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
this._cancelEditor();
|
this._cancelEditor();
|
||||||
@@ -330,12 +336,15 @@ ZoneManager.prototype = {
|
|||||||
_init: function() {
|
_init: function() {
|
||||||
this.overlay = null;
|
this.overlay = null;
|
||||||
this.currentLayout = 'grid-2x2';
|
this.currentLayout = 'grid-2x2';
|
||||||
this.layouts = DEFAULT_LAYOUTS;
|
this.layouts = {};
|
||||||
this.isShowing = false;
|
this.isShowing = false;
|
||||||
this.dragInProgress = false;
|
this.dragInProgress = false;
|
||||||
this.draggedWindow = null;
|
this.draggedWindow = null;
|
||||||
this.editor = new ZoneEditor();
|
this.editor = new ZoneEditor();
|
||||||
|
|
||||||
|
// Load layouts (default + saved custom layouts)
|
||||||
|
this._loadLayouts();
|
||||||
|
|
||||||
// Connect to window grab events
|
// Connect to window grab events
|
||||||
this._connectSignals();
|
this._connectSignals();
|
||||||
this._setupKeybindings();
|
this._setupKeybindings();
|
||||||
@@ -379,6 +388,58 @@ ZoneManager.prototype = {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
|
_loadLayouts: function() {
|
||||||
|
// Start with default layouts
|
||||||
|
for (let layoutId in DEFAULT_LAYOUTS) {
|
||||||
|
this.layouts[layoutId] = DEFAULT_LAYOUTS[layoutId];
|
||||||
|
}
|
||||||
|
|
||||||
|
// Try to load custom layouts from file
|
||||||
|
try {
|
||||||
|
let file = Gio.File.new_for_path(LAYOUTS_FILE);
|
||||||
|
if (file.query_exists(null)) {
|
||||||
|
let [success, contents] = file.load_contents(null);
|
||||||
|
if (success) {
|
||||||
|
let customLayouts = JSON.parse(contents.toString());
|
||||||
|
// Merge custom layouts with defaults
|
||||||
|
for (let layoutId in customLayouts) {
|
||||||
|
this.layouts[layoutId] = customLayouts[layoutId];
|
||||||
|
}
|
||||||
|
global.log('GridSnap: Loaded ' + Object.keys(customLayouts).length + ' custom layout(s)');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} catch(e) {
|
||||||
|
global.logError('GridSnap: Error loading custom layouts - ' + e);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
_saveLayouts: function() {
|
||||||
|
try {
|
||||||
|
// Create directory if it doesn't exist
|
||||||
|
let dir = Gio.File.new_for_path(STORAGE_DIR);
|
||||||
|
if (!dir.query_exists(null)) {
|
||||||
|
dir.make_directory_with_parents(null);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Extract only custom layouts (those starting with 'custom-')
|
||||||
|
let customLayouts = {};
|
||||||
|
for (let layoutId in this.layouts) {
|
||||||
|
if (layoutId.startsWith('custom-')) {
|
||||||
|
customLayouts[layoutId] = this.layouts[layoutId];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Save to file
|
||||||
|
let file = Gio.File.new_for_path(LAYOUTS_FILE);
|
||||||
|
let contents = JSON.stringify(customLayouts, null, 2);
|
||||||
|
file.replace_contents(contents, null, false, Gio.FileCreateFlags.REPLACE_DESTINATION, null);
|
||||||
|
|
||||||
|
global.log('GridSnap: Saved ' + Object.keys(customLayouts).length + ' custom layout(s) to ' + LAYOUTS_FILE);
|
||||||
|
} catch(e) {
|
||||||
|
global.logError('GridSnap: Error saving custom layouts - ' + e);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
_checkModifiersDuringDrag: function() {
|
_checkModifiersDuringDrag: function() {
|
||||||
if (!this.dragInProgress) {
|
if (!this.dragInProgress) {
|
||||||
|
|||||||
Reference in New Issue
Block a user