Add keybinds and monitor staet

This commit is contained in:
2023-05-11 23:15:34 +09:00
parent 51794258c5
commit dc3d46bd55
4 changed files with 136 additions and 34 deletions

View File

@@ -6,16 +6,22 @@ const Me = ExtensionUtils.getCurrentExtension();
const Main = imports.ui.main;
const PanelMenu = imports.ui.panelMenu;
const Windows = Me.imports.sources.windows;
const State = Me.imports.sources.state;
const Renderer = Me.imports.sources.renderer;
const Keybinds = Me.imports.sources.keybinds;
class Extension {
constructor() {
this._state = new State.StateManager();
this._renderer = new Renderer.Renderer(this._state);
this._keybinds = new Keybinds.KeyboardManager(this._state, this._renderer);
this._layoutIndicator = null;
this._windows = new Windows.WindowManager();
}
enable() {
this._windows.enable();
this._renderer.enable();
this._keybinds.enable();
this.settings = ExtensionUtils.getSettings(
"org.gnome.shell.extensions.fairy"
@@ -43,7 +49,8 @@ class Extension {
}
disable() {
this._windows.disable();
this._renderer.disable();
this._keybinds.disable();
this._layoutIndicator.destroy();
this._layoutIndicator = null;

78
sources/keybinds.js Normal file
View File

@@ -0,0 +1,78 @@
"use strict";
const GObject = imports.gi.GObject;
const Main = imports.ui.main;
const Meta = imports.gi.Meta;
const Shell = imports.gi.Shell;
const ExtensionUtils = imports.misc.extensionUtils;
var KeyboardManager = GObject.registerClass(
class KeyboardManager extends GObject.Object {
_init(state, renderer) {
super._init();
this._state = state;
this._renderer = renderer;
// TODO: Handle rerender from here.
}
/**
* @param {string} key
* @param {() => void} action
*/
_addBinding(key, action) {
const settings = ExtensionUtils.getSettings(
"org.gnome.shell.extensions.fairy.keybinds"
);
Main.wm.addKeybinding(
key,
settings,
Meta.KeyBindingFlags.IGNORE_AUTOREPEAT,
Shell.ActionMode.NORMAL,
action
);
}
/**
* @param {string} key
*/
_removeBinding(key) {
Main.wm.removeKeybinding(key);
}
enable() {
this._addBinding("incrmfact", () => {
const mon = global.display.get_current_monitor();
const state = this._state.monitors[mon];
state.mfact = Math.min(95, state.mfact + 5);
this._renderer.render(mon);
});
this._addBinding("decmfact", () => {
const mon = global.display.get_current_monitor();
const state = this._state.monitors[mon];
state.mfact = Math.max(5, state.mfact - 5);
this._renderer.render(mon);
});
this._addBinding("incrnmaster", () => {
const mon = global.display.get_current_monitor();
this._state.monitors[mon].mfact += 1;
this._renderer.render(mon);
});
this._addBinding("decnmaster", () => {
const mon = global.display.get_current_monitor();
if (this._state.monitors[mon].nmaster > 0)
this._state.monitors[mon].nmaster -= 1;
this._renderer.render(mon);
});
}
disable() {
this._removeBinding("incrmfact");
this._removeBinding("decrmfact");
this._removeBinding("incrnmaster");
this._removeBinding("decrnmaster");
}
}
);

View File

@@ -8,13 +8,11 @@ const Mainloop = imports.mainloop;
const ExtensionUtils = imports.misc.extensionUtils;
const Me = ExtensionUtils.getCurrentExtension();
const Layout = Me.imports.sources.layout;
var WindowManager = GObject.registerClass(
class WindowManager extends GObject.Object {
_init() {
var Renderer = GObject.registerClass(
class Renderer extends GObject.Object {
_init(state) {
super._init();
this._layout = new Layout.Layout();
this._state = state
log("fairy init");
}
@@ -84,12 +82,17 @@ var WindowManager = GObject.registerClass(
}
_removeSignals() {
for (const signal of this._signals) {
for (const signal of this._displaySignals) {
global.display.disconnect(signal);
}
this._signals = undefined;
this._displaySignals = undefined;
for (const window of this._layout.windows) {
for (const signal of this._wmSignals) {
global.window_manager.disconnect(signal);
}
this._wmSignals = undefined;
for (const window of this._state.windows) {
if (window._signals) {
for (const signal of window._signals) window.disconnect(signal);
}
@@ -99,11 +102,11 @@ var WindowManager = GObject.registerClass(
actor._signals = [];
}
}
this._layout.windows = [];
this._state.windows = [];
}
_bindSignals() {
this._signals = [
this._displaySignals = [
global.display.connect("window-created", (_display, window) =>
this._waitForWindow(window, () => {
this.trackWindow(window);
@@ -114,6 +117,18 @@ var WindowManager = GObject.registerClass(
//
// }),
];
this._wmSignals = [
global.window_manager.connect("switch-workspace", (_wm, _from, to, _direction) => {
// Convert gnome workspaces to fairy's tags
to = 0b1 << to;
if (Meta.prefs_get_workspaces_only_on_primary()) {
this._state.monitors[global.display.get_primary_monitor()].tags = to;
} else {
for (let i = 0; i < this._state.monitors.length; i++)
this._state.monitors[i].tags = to;
}
}),
]
}
/**
@@ -127,7 +142,7 @@ var WindowManager = GObject.registerClass(
}),
window.connect("workspace-changed", (window) => {
if (!this._isValidWindow(window)) return;
const [oldW, newW] = this._layout.updateByHandle(window);
const [oldW, newW] = this._state.updateByHandle(window);
if (oldW) this.render(oldW.monitor, oldW.tags);
if (newW) this.render(newW.monitor, newW.tags);
}),
@@ -135,12 +150,12 @@ var WindowManager = GObject.registerClass(
const actor = window.get_compositor_private();
actor._signals = [
actor.connect("destroy", (actor) => {
const faWindow = this._layout.popByActor(actor);
const faWindow = this._state.popByActor(actor);
if (faWindow) this.render(faWindow.monitor, faWindow.tags);
}),
];
this._layout.newWindow(window);
this._state.newWindow(window);
}
renderAll() {
@@ -155,18 +170,17 @@ var WindowManager = GObject.registerClass(
renderForWindow(window) {
const mon = window.get_monitor();
// TODO: The on_all_workspaces handling is faulty.
const workspace = window.on_all_workspaces
? ~0
: window.get_workspace().index() + 1;
this.render(mon, workspace);
this.render(mon);
}
/**
* @param {number} mon
* @param {number} tags
* @param {number?} tags
*/
render(mon, tags) {
console.log("monitors", this._state.monitors)
if (!tags) tags = this._state.monitors[mon].tags;
// We don't care which workspace it is, we just want the geometry
// for the current monitor without the panel.
const monGeo = global.display
@@ -174,7 +188,7 @@ var WindowManager = GObject.registerClass(
.get_active_workspace()
.get_work_area_for_monitor(mon);
for (const window of this._layout.render(mon, tags)) {
for (const window of this._state.render(mon, tags)) {
if (window.handle.get_monitor() !== mon)
window.handle.move_to_monitor(mon);
if (window.handle.minimized !== window.minimized) {

View File

@@ -2,19 +2,20 @@
const GObject = imports.gi.GObject;
var Layout = GObject.registerClass(
class Layout extends GObject.Object {
var StateManager = GObject.registerClass(
class StateManager extends GObject.Object {
_init() {
super._init();
// Simpler to set 30 monitors than track creation/supression of monitors.
this._monitors = new Array(30).map(() => ({
this.monitors = [...new Array(30)].map(() => ({
/**
* @type {Meta.Window} focused window's handle
*/
focused: null,
tags: 1,
layout: "tiled",
nmaster: 1,
nfact: 60,
mfact: 55,
}));
/**
@@ -80,7 +81,7 @@ var Layout = GObject.registerClass(
* @returns WindowGeometry[]
*/
render(mon, tags) {
const { layout, nmaster, nfact } = this._monitors[mon];
const { layout, nmaster, mfact } = this.monitors[mon];
const windows = this.windows.filter(
(x) => x.monitor === mon && x.tags & tags
);
@@ -91,7 +92,7 @@ var Layout = GObject.registerClass(
case "monocle":
return [
{
handle: this._monitors[mon].focused,
handle: this.monitors[mon].focused,
maximized: true,
minimized: false,
x: 0,
@@ -111,17 +112,19 @@ var Layout = GObject.registerClass(
handle: x.handle,
maximized: false,
minimized: false,
x: i < nmaster ? 0 : nfact,
x: i < nmaster ? 0 : mfact,
y: stackIndex * (100 / stackLength),
width:
windows.length <= nmaster
? 100
: i < nmaster
? nfact
: 100 - nfact,
? mfact
: 100 - mfact,
height: 100 / stackLength,
};
});
default:
return [];
}
}
}