Initial commit - GridSnap Cinnamon Extension
This commit is contained in:
14
.gitignore
vendored
Normal file
14
.gitignore
vendored
Normal file
@@ -0,0 +1,14 @@
|
|||||||
|
# Editor files
|
||||||
|
*~
|
||||||
|
*.swp
|
||||||
|
*.swo
|
||||||
|
.vscode/
|
||||||
|
.idea/
|
||||||
|
|
||||||
|
# OS files
|
||||||
|
.DS_Store
|
||||||
|
Thumbs.db
|
||||||
|
|
||||||
|
# Temporary files
|
||||||
|
*.tmp
|
||||||
|
*.bak
|
||||||
132
README.md
Normal file
132
README.md
Normal file
@@ -0,0 +1,132 @@
|
|||||||
|
# GridSnap for Cinnamon Desktop
|
||||||
|
|
||||||
|
A window tiling manager extension for Linux Mint's Cinnamon Desktop, inspired by Microsoft PowerToys FancyZones.
|
||||||
|
|
||||||
|
## Features
|
||||||
|
|
||||||
|
- **Multiple Zone Layouts**: Pre-configured layouts including 2x2 grid, 3 columns, and focus layouts
|
||||||
|
- **Visual Overlay**: See your zones while dragging windows
|
||||||
|
- **Keyboard Shortcuts**: Quick snap to zones using hotkeys
|
||||||
|
- **Layout Cycling**: Switch between different zone layouts on the fly
|
||||||
|
|
||||||
|
## Installation
|
||||||
|
|
||||||
|
1. Copy the extension folder to your Cinnamon extensions directory:
|
||||||
|
```bash
|
||||||
|
cp -r gridsnap-cinnamon ~/.local/share/cinnamon/extensions/gridsnap@cinnamon-extension
|
||||||
|
```
|
||||||
|
|
||||||
|
2. Restart Cinnamon (Alt+F2, type 'r', press Enter) or log out and back in
|
||||||
|
|
||||||
|
3. Enable the extension:
|
||||||
|
- Open System Settings → Extensions
|
||||||
|
- Find "GridSnap"
|
||||||
|
- Toggle it on
|
||||||
|
|
||||||
|
## Usage
|
||||||
|
|
||||||
|
### Keyboard Shortcuts
|
||||||
|
|
||||||
|
- **Super + Z**: Toggle zone overlay (show/hide zones)
|
||||||
|
- **Super + Shift + Z**: Cycle through different layouts
|
||||||
|
- **Super + Numpad 1-9**: Snap focused window to zone 1-9
|
||||||
|
|
||||||
|
### Mouse Usage
|
||||||
|
|
||||||
|
1. Hold **Shift** while dragging a window to see the zone overlay
|
||||||
|
2. Drop the window over a zone to snap it there
|
||||||
|
3. Release Shift or move outside zones to cancel
|
||||||
|
|
||||||
|
## Available Layouts
|
||||||
|
|
||||||
|
1. **2x2 Grid**: Four equal quadrants
|
||||||
|
2. **3 Columns**: Three equal vertical columns
|
||||||
|
3. **Focus Left**: Large left area with two smaller right zones
|
||||||
|
|
||||||
|
## Customization
|
||||||
|
|
||||||
|
To add your own layouts, edit the `DEFAULT_LAYOUTS` object in `extension.js`:
|
||||||
|
|
||||||
|
```javascript
|
||||||
|
const DEFAULT_LAYOUTS = {
|
||||||
|
'custom-layout': {
|
||||||
|
name: 'My Custom Layout',
|
||||||
|
zones: [
|
||||||
|
{ x: 0, y: 0, width: 0.5, height: 1 }, // Left half
|
||||||
|
{ x: 0.5, y: 0, width: 0.5, height: 1 } // Right half
|
||||||
|
]
|
||||||
|
}
|
||||||
|
};
|
||||||
|
```
|
||||||
|
|
||||||
|
Zone coordinates are relative (0.0 to 1.0):
|
||||||
|
- `x`: Horizontal position (0 = left edge, 1 = right edge)
|
||||||
|
- `y`: Vertical position (0 = top edge, 1 = bottom edge)
|
||||||
|
- `width`: Zone width as fraction of screen width
|
||||||
|
- `height`: Zone height as fraction of screen height
|
||||||
|
|
||||||
|
## Troubleshooting
|
||||||
|
|
||||||
|
### Extension won't load
|
||||||
|
- Check the Looking Glass console (Alt+F2, type 'lg', press Enter) for errors
|
||||||
|
- Ensure the UUID in metadata.json matches the folder name
|
||||||
|
|
||||||
|
### Overlay doesn't show
|
||||||
|
- Make sure no other extensions conflict with window management
|
||||||
|
- Try disabling and re-enabling the extension
|
||||||
|
|
||||||
|
### Keybindings don't work
|
||||||
|
- Check System Settings → Keyboard → Shortcuts for conflicts
|
||||||
|
- Ensure the extension is enabled
|
||||||
|
|
||||||
|
## Development
|
||||||
|
|
||||||
|
### File Structure
|
||||||
|
```
|
||||||
|
gridsnap@cinnamon-extension/
|
||||||
|
├── metadata.json # Extension metadata
|
||||||
|
├── extension.js # Main extension code
|
||||||
|
├── stylesheet.css # Visual styling
|
||||||
|
└── README.md # This file
|
||||||
|
```
|
||||||
|
|
||||||
|
### Testing Changes
|
||||||
|
After editing:
|
||||||
|
1. Reload Cinnamon: Alt+F2 → 'r' → Enter
|
||||||
|
2. Or use Looking Glass: Alt+F2 → 'lg' → Enter
|
||||||
|
|
||||||
|
### Debug Logging
|
||||||
|
Add logging in extension.js:
|
||||||
|
```javascript
|
||||||
|
global.log('GridSnap: Your message here');
|
||||||
|
```
|
||||||
|
View logs with:
|
||||||
|
```bash
|
||||||
|
tail -f ~/.cinnamon/glass.log
|
||||||
|
```
|
||||||
|
|
||||||
|
## Future Enhancements
|
||||||
|
|
||||||
|
- [ ] Custom layout editor GUI
|
||||||
|
- [ ] Per-monitor zone configurations
|
||||||
|
- [ ] Save window positions and restore on login
|
||||||
|
- [ ] Zone layout import/export
|
||||||
|
- [ ] More pre-configured layouts
|
||||||
|
- [ ] Animation effects
|
||||||
|
- [ ] Settings panel for configuration
|
||||||
|
|
||||||
|
## Contributing
|
||||||
|
|
||||||
|
Feel free to fork and submit pull requests! Areas that could use help:
|
||||||
|
- Additional layout presets
|
||||||
|
- UI improvements for the overlay
|
||||||
|
- Settings GUI implementation
|
||||||
|
- Multi-monitor support improvements
|
||||||
|
|
||||||
|
## License
|
||||||
|
|
||||||
|
MIT License - Feel free to use and modify as needed.
|
||||||
|
|
||||||
|
## Credits
|
||||||
|
|
||||||
|
Inspired by Microsoft PowerToys FancyZones for Windows.
|
||||||
308
extension.js
Normal file
308
extension.js
Normal file
@@ -0,0 +1,308 @@
|
|||||||
|
const St = imports.gi.St;
|
||||||
|
const Main = imports.ui.main;
|
||||||
|
const Meta = imports.gi.Meta;
|
||||||
|
const Clutter = imports.gi.Clutter;
|
||||||
|
const Lang = imports.lang;
|
||||||
|
const Mainloop = imports.mainloop;
|
||||||
|
const Settings = imports.ui.settings;
|
||||||
|
|
||||||
|
let zoneManager;
|
||||||
|
|
||||||
|
// Default zone layouts
|
||||||
|
const DEFAULT_LAYOUTS = {
|
||||||
|
'grid-2x2': {
|
||||||
|
name: '2x2 Grid',
|
||||||
|
zones: [
|
||||||
|
{ x: 0, y: 0, width: 0.5, height: 0.5 }, // Top-left
|
||||||
|
{ x: 0.5, y: 0, width: 0.5, height: 0.5 }, // Top-right
|
||||||
|
{ x: 0, y: 0.5, width: 0.5, height: 0.5 }, // Bottom-left
|
||||||
|
{ x: 0.5, y: 0.5, width: 0.5, height: 0.5 } // Bottom-right
|
||||||
|
]
|
||||||
|
},
|
||||||
|
'columns-3': {
|
||||||
|
name: '3 Columns',
|
||||||
|
zones: [
|
||||||
|
{ x: 0, y: 0, width: 0.33, height: 1 },
|
||||||
|
{ x: 0.33, y: 0, width: 0.34, height: 1 },
|
||||||
|
{ x: 0.67, y: 0, width: 0.33, height: 1 }
|
||||||
|
]
|
||||||
|
},
|
||||||
|
'focus-left': {
|
||||||
|
name: 'Focus Left',
|
||||||
|
zones: [
|
||||||
|
{ x: 0, y: 0, width: 0.7, height: 1 }, // Main left
|
||||||
|
{ x: 0.7, y: 0, width: 0.3, height: 0.5 }, // Top-right
|
||||||
|
{ x: 0.7, y: 0.5, width: 0.3, height: 0.5 } // Bottom-right
|
||||||
|
]
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
function ZoneManager() {
|
||||||
|
this._init();
|
||||||
|
}
|
||||||
|
|
||||||
|
ZoneManager.prototype = {
|
||||||
|
_init: function() {
|
||||||
|
this.overlay = null;
|
||||||
|
this.currentLayout = 'grid-2x2';
|
||||||
|
this.layouts = DEFAULT_LAYOUTS;
|
||||||
|
this.isShowing = false;
|
||||||
|
this.dragInProgress = false;
|
||||||
|
|
||||||
|
// Connect to window grab events
|
||||||
|
this._connectSignals();
|
||||||
|
this._setupKeybindings();
|
||||||
|
},
|
||||||
|
|
||||||
|
_connectSignals: function() {
|
||||||
|
// Monitor for window grab begin/end
|
||||||
|
this.grabOpBeginId = global.display.connect('grab-op-begin',
|
||||||
|
Lang.bind(this, this._onGrabBegin));
|
||||||
|
this.grabOpEndId = global.display.connect('grab-op-end',
|
||||||
|
Lang.bind(this, this._onGrabEnd));
|
||||||
|
},
|
||||||
|
|
||||||
|
_setupKeybindings: function() {
|
||||||
|
// Add keybinding to show zones overlay (Super+Z)
|
||||||
|
Main.keybindingManager.addHotKey(
|
||||||
|
'show-zones',
|
||||||
|
'<Super>z',
|
||||||
|
Lang.bind(this, this._toggleZonesOverlay)
|
||||||
|
);
|
||||||
|
|
||||||
|
// Add keybindings for quick snap to zones (Super+Numpad)
|
||||||
|
for (let i = 1; i <= 9; i++) {
|
||||||
|
Main.keybindingManager.addHotKey(
|
||||||
|
'snap-to-zone-' + i,
|
||||||
|
'<Super>KP_' + i,
|
||||||
|
Lang.bind(this, function() { this._snapToZone(i - 1); })
|
||||||
|
);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
_onGrabBegin: function(display, window, op) {
|
||||||
|
// Check if this is a window move operation
|
||||||
|
if (op === Meta.GrabOp.MOVING) {
|
||||||
|
this.dragInProgress = true;
|
||||||
|
|
||||||
|
// Check if Shift is held - show overlay
|
||||||
|
let mods = global.get_pointer()[2];
|
||||||
|
if (mods & Clutter.ModifierType.SHIFT_MASK) {
|
||||||
|
this._showZonesOverlay();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
_onGrabEnd: function(display, window, op) {
|
||||||
|
if (op === Meta.GrabOp.MOVING && this.dragInProgress) {
|
||||||
|
this.dragInProgress = false;
|
||||||
|
|
||||||
|
if (this.isShowing) {
|
||||||
|
// Snap to zone if cursor is over one
|
||||||
|
this._snapWindowToZone(window);
|
||||||
|
this._hideZonesOverlay();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
_toggleZonesOverlay: function() {
|
||||||
|
if (this.isShowing) {
|
||||||
|
this._hideZonesOverlay();
|
||||||
|
} else {
|
||||||
|
this._showZonesOverlay();
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
_showZonesOverlay: function() {
|
||||||
|
if (this.isShowing) return;
|
||||||
|
|
||||||
|
let monitor = Main.layoutManager.primaryMonitor;
|
||||||
|
|
||||||
|
// Create overlay container
|
||||||
|
this.overlay = new St.Widget({
|
||||||
|
style_class: 'gridsnap-overlay',
|
||||||
|
reactive: false,
|
||||||
|
x: monitor.x,
|
||||||
|
y: monitor.y,
|
||||||
|
width: monitor.width,
|
||||||
|
height: monitor.height
|
||||||
|
});
|
||||||
|
|
||||||
|
// Add semi-transparent background
|
||||||
|
this.overlay.set_style(
|
||||||
|
'background-color: rgba(0, 0, 0, 0.3);'
|
||||||
|
);
|
||||||
|
|
||||||
|
// Draw zones
|
||||||
|
let layout = this.layouts[this.currentLayout];
|
||||||
|
layout.zones.forEach((zone, index) => {
|
||||||
|
let zoneActor = this._createZoneActor(zone, monitor, index);
|
||||||
|
this.overlay.add_child(zoneActor);
|
||||||
|
});
|
||||||
|
|
||||||
|
Main.layoutManager.addChrome(this.overlay);
|
||||||
|
this.isShowing = true;
|
||||||
|
},
|
||||||
|
|
||||||
|
_createZoneActor: function(zone, monitor, index) {
|
||||||
|
let x = monitor.width * zone.x;
|
||||||
|
let y = monitor.height * zone.y;
|
||||||
|
let width = monitor.width * zone.width;
|
||||||
|
let height = monitor.height * zone.height;
|
||||||
|
|
||||||
|
let actor = new St.Widget({
|
||||||
|
style_class: 'gridsnap-zone',
|
||||||
|
x: x,
|
||||||
|
y: y,
|
||||||
|
width: width,
|
||||||
|
height: height
|
||||||
|
});
|
||||||
|
|
||||||
|
actor.set_style(
|
||||||
|
'border: 2px solid rgba(100, 149, 237, 0.8);' +
|
||||||
|
'background-color: rgba(100, 149, 237, 0.2);' +
|
||||||
|
'border-radius: 4px;'
|
||||||
|
);
|
||||||
|
|
||||||
|
// Add zone number label
|
||||||
|
let label = new St.Label({
|
||||||
|
text: String(index + 1),
|
||||||
|
style_class: 'gridsnap-zone-label',
|
||||||
|
x: 10,
|
||||||
|
y: 10
|
||||||
|
});
|
||||||
|
label.set_style(
|
||||||
|
'color: white;' +
|
||||||
|
'font-size: 24px;' +
|
||||||
|
'font-weight: bold;' +
|
||||||
|
'text-shadow: 2px 2px 4px rgba(0,0,0,0.8);'
|
||||||
|
);
|
||||||
|
actor.add_child(label);
|
||||||
|
|
||||||
|
return actor;
|
||||||
|
},
|
||||||
|
|
||||||
|
_hideZonesOverlay: function() {
|
||||||
|
if (!this.isShowing) return;
|
||||||
|
|
||||||
|
if (this.overlay) {
|
||||||
|
Main.layoutManager.removeChrome(this.overlay);
|
||||||
|
this.overlay.destroy();
|
||||||
|
this.overlay = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
this.isShowing = false;
|
||||||
|
},
|
||||||
|
|
||||||
|
_snapWindowToZone: function(window) {
|
||||||
|
if (!window) return;
|
||||||
|
|
||||||
|
let [x, y] = global.get_pointer();
|
||||||
|
let monitor = Main.layoutManager.primaryMonitor;
|
||||||
|
|
||||||
|
// Convert to relative coordinates
|
||||||
|
let relX = (x - monitor.x) / monitor.width;
|
||||||
|
let relY = (y - monitor.y) / monitor.height;
|
||||||
|
|
||||||
|
// Find which zone the cursor is in
|
||||||
|
let layout = this.layouts[this.currentLayout];
|
||||||
|
let targetZone = null;
|
||||||
|
|
||||||
|
for (let zone of layout.zones) {
|
||||||
|
if (relX >= zone.x && relX < zone.x + zone.width &&
|
||||||
|
relY >= zone.y && relY < zone.y + zone.height) {
|
||||||
|
targetZone = zone;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (targetZone) {
|
||||||
|
this._moveWindowToZone(window, targetZone, monitor);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
_snapToZone: function(zoneIndex) {
|
||||||
|
// Snap the focused window to a specific zone
|
||||||
|
let window = global.display.focus_window;
|
||||||
|
if (!window) return;
|
||||||
|
|
||||||
|
let layout = this.layouts[this.currentLayout];
|
||||||
|
if (zoneIndex >= layout.zones.length) return;
|
||||||
|
|
||||||
|
let monitor = Main.layoutManager.primaryMonitor;
|
||||||
|
this._moveWindowToZone(window, layout.zones[zoneIndex], monitor);
|
||||||
|
},
|
||||||
|
|
||||||
|
_moveWindowToZone: function(window, zone, monitor) {
|
||||||
|
// Unmaximize if maximized
|
||||||
|
if (window.get_maximized()) {
|
||||||
|
window.unmaximize(Meta.MaximizeFlags.BOTH);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Calculate absolute coordinates
|
||||||
|
let x = monitor.x + Math.round(monitor.width * zone.x);
|
||||||
|
let y = monitor.y + Math.round(monitor.height * zone.y);
|
||||||
|
let width = Math.round(monitor.width * zone.width);
|
||||||
|
let height = Math.round(monitor.height * zone.height);
|
||||||
|
|
||||||
|
// Move and resize window
|
||||||
|
window.move_resize_frame(true, x, y, width, height);
|
||||||
|
},
|
||||||
|
|
||||||
|
cycleLayout: function() {
|
||||||
|
let layouts = Object.keys(this.layouts);
|
||||||
|
let currentIndex = layouts.indexOf(this.currentLayout);
|
||||||
|
let nextIndex = (currentIndex + 1) % layouts.length;
|
||||||
|
this.currentLayout = layouts[nextIndex];
|
||||||
|
|
||||||
|
Main.notify('GridSnap', 'Layout: ' + this.layouts[this.currentLayout].name);
|
||||||
|
|
||||||
|
// Refresh overlay if showing
|
||||||
|
if (this.isShowing) {
|
||||||
|
this._hideZonesOverlay();
|
||||||
|
this._showZonesOverlay();
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
destroy: function() {
|
||||||
|
// Disconnect signals
|
||||||
|
if (this.grabOpBeginId) {
|
||||||
|
global.display.disconnect(this.grabOpBeginId);
|
||||||
|
}
|
||||||
|
if (this.grabOpEndId) {
|
||||||
|
global.display.disconnect(this.grabOpEndId);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Remove keybindings
|
||||||
|
Main.keybindingManager.removeHotKey('show-zones');
|
||||||
|
for (let i = 1; i <= 9; i++) {
|
||||||
|
Main.keybindingManager.removeHotKey('snap-to-zone-' + i);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Clean up overlay
|
||||||
|
this._hideZonesOverlay();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
function init(metadata) {
|
||||||
|
// Extension initialization
|
||||||
|
}
|
||||||
|
|
||||||
|
function enable() {
|
||||||
|
zoneManager = new ZoneManager();
|
||||||
|
|
||||||
|
// Add keybinding to cycle layouts
|
||||||
|
Main.keybindingManager.addHotKey(
|
||||||
|
'cycle-layout',
|
||||||
|
'<Super><Shift>z',
|
||||||
|
Lang.bind(zoneManager, zoneManager.cycleLayout)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
function disable() {
|
||||||
|
if (zoneManager) {
|
||||||
|
Main.keybindingManager.removeHotKey('cycle-layout');
|
||||||
|
zoneManager.destroy();
|
||||||
|
zoneManager = null;
|
||||||
|
}
|
||||||
|
}
|
||||||
11
icon.svg
Normal file
11
icon.svg
Normal file
@@ -0,0 +1,11 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<svg width="64" height="64" version="1.1" viewBox="0 0 64 64" xmlns="http://www.w3.org/2000/svg">
|
||||||
|
<rect x="2" y="2" width="28" height="28" fill="none" stroke="#6495ed" stroke-width="2" rx="2"/>
|
||||||
|
<rect x="34" y="2" width="28" height="28" fill="none" stroke="#6495ed" stroke-width="2" rx="2"/>
|
||||||
|
<rect x="2" y="34" width="28" height="28" fill="none" stroke="#6495ed" stroke-width="2" rx="2"/>
|
||||||
|
<rect x="34" y="34" width="28" height="28" fill="none" stroke="#6495ed" stroke-width="2" rx="2"/>
|
||||||
|
<text x="16" y="22" font-family="sans-serif" font-size="16" font-weight="bold" fill="#6495ed" text-anchor="middle">1</text>
|
||||||
|
<text x="48" y="22" font-family="sans-serif" font-size="16" font-weight="bold" fill="#6495ed" text-anchor="middle">2</text>
|
||||||
|
<text x="16" y="54" font-family="sans-serif" font-size="16" font-weight="bold" fill="#6495ed" text-anchor="middle">3</text>
|
||||||
|
<text x="48" y="54" font-family="sans-serif" font-size="16" font-weight="bold" fill="#6495ed" text-anchor="middle">4</text>
|
||||||
|
</svg>
|
||||||
|
After Width: | Height: | Size: 1.0 KiB |
34
install.sh
Executable file
34
install.sh
Executable file
@@ -0,0 +1,34 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
|
||||||
|
# GridSnap for Cinnamon - Installation Script
|
||||||
|
|
||||||
|
EXTENSION_UUID="gridsnap@cinnamon-extension"
|
||||||
|
INSTALL_DIR="$HOME/.local/share/cinnamon/extensions/$EXTENSION_UUID"
|
||||||
|
|
||||||
|
echo "Installing GridSnap for Cinnamon..."
|
||||||
|
|
||||||
|
# Create extensions directory if it doesn't exist
|
||||||
|
mkdir -p "$HOME/.local/share/cinnamon/extensions"
|
||||||
|
|
||||||
|
# Copy extension files
|
||||||
|
echo "Copying extension files..."
|
||||||
|
cp -r . "$INSTALL_DIR"
|
||||||
|
|
||||||
|
# Remove the install script from the installed version
|
||||||
|
rm -f "$INSTALL_DIR/install.sh"
|
||||||
|
|
||||||
|
echo ""
|
||||||
|
echo "Installation complete!"
|
||||||
|
echo ""
|
||||||
|
echo "To enable the extension:"
|
||||||
|
echo "1. Restart Cinnamon (Alt+F2, type 'r', press Enter)"
|
||||||
|
echo " OR log out and back in"
|
||||||
|
echo "2. Open System Settings → Extensions"
|
||||||
|
echo "3. Find 'GridSnap' and toggle it on"
|
||||||
|
echo ""
|
||||||
|
echo "Keyboard shortcuts:"
|
||||||
|
echo " Super+Z : Show/hide zones"
|
||||||
|
echo " Super+Shift+Z : Cycle layouts"
|
||||||
|
echo " Super+Numpad1-9 : Snap to zone"
|
||||||
|
echo ""
|
||||||
|
echo "Enjoy your new window manager!"
|
||||||
8
metadata.json
Normal file
8
metadata.json
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
{
|
||||||
|
"uuid": "gridsnap@cinnamon-extension",
|
||||||
|
"name": "GridSnap",
|
||||||
|
"description": "Advanced window tiling manager with customizable zone layouts",
|
||||||
|
"version": "0.1.0",
|
||||||
|
"cinnamon-version": ["5.0", "5.2", "5.4", "5.6", "6.0"],
|
||||||
|
"author": "Your Name"
|
||||||
|
}
|
||||||
22
stylesheet.css
Normal file
22
stylesheet.css
Normal file
@@ -0,0 +1,22 @@
|
|||||||
|
.gridsnap-overlay {
|
||||||
|
background-color: rgba(0, 0, 0, 0.3);
|
||||||
|
}
|
||||||
|
|
||||||
|
.gridsnap-zone {
|
||||||
|
border: 2px solid rgba(100, 149, 237, 0.8);
|
||||||
|
background-color: rgba(100, 149, 237, 0.2);
|
||||||
|
border-radius: 4px;
|
||||||
|
transition: all 0.2s ease;
|
||||||
|
}
|
||||||
|
|
||||||
|
.gridsnap-zone:hover {
|
||||||
|
background-color: rgba(100, 149, 237, 0.4);
|
||||||
|
border-color: rgba(100, 149, 237, 1.0);
|
||||||
|
}
|
||||||
|
|
||||||
|
.gridsnap-zone-label {
|
||||||
|
color: white;
|
||||||
|
font-size: 24px;
|
||||||
|
font-weight: bold;
|
||||||
|
text-shadow: 2px 2px 4px rgba(0, 0, 0, 0.8);
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user