wip: Add multi monitor support

This commit is contained in:
2023-05-20 16:23:14 +09:00
parent 7c13c3d3d6
commit cce0a605e6
6 changed files with 70 additions and 30 deletions

View File

@@ -14,7 +14,7 @@ class Extension {
this._state = new State.StateManager();
this._settings = ExtensionUtils.getSettings("org.gnome.shell.extensions.fairy");
this._border = new Border.BorderManager(this._state);
this._border = new Border.BorderManager(this._state, this._settings);
this._indicator = new Indicator.Indicator(this._state, this._renderer, this._keybinds);
this._renderer = new Renderer.Renderer(this._state, this._settings, this._indicator, this._border);
this._keybinds = new Keybinds.KeyboardManager(this._state, this._renderer, this._indicator);

View File

@@ -5,6 +5,10 @@
<default>true</default>
<summary>Should the cursor warp to newly focused windows</summary>
</key>
<key type="b" name="single-tagset">
<default>false</default>
<summary>Should tag be shared between monitors</summary>
</key>
<!-- Visual things -->
<key type="b" name="show-layout">

View File

@@ -25,6 +25,7 @@ var Indicator = GObject.registerClass(
floating: Gio.icon_new_for_string(`${Me.path}/icons/floating.svg`),
deck: Gio.icon_new_for_string(`${Me.path}/icons/deck.svg`),
};
this._destroyed = true;
}
endInit(ext) {
@@ -34,7 +35,6 @@ var Indicator = GObject.registerClass(
this._keybinds = ext._keybinds;
}
_createSelectableItem(title, cb) {
const menuItem = new PopupMenu.PopupMenuItem(title, {});
menuItem.connect("activate", cb);
@@ -142,7 +142,8 @@ var Indicator = GObject.registerClass(
const tag = 0b1 << tagNbr;
const active = state.tags & tag;
const hasWindow =
this._state.windows.find((x) => x.tags & tag) !== undefined;
this._state.windows.find((x) => x.monitor == mon && x.tags & tag) !==
undefined;
if (!active && !hasWindow) continue;
const style = "width: 30px;";
const tagBtn = new St.Button({

View File

@@ -164,8 +164,13 @@ var KeyboardManager = GObject.registerClass(
const mon = global.display.get_current_monitor();
let takkenTags = 0;
for (let i = 0; i < this._state.monitors.length; i++)
if (this._state.sharedTagset) {
for (let i = 0; i < global.display.get_n_monitors(); i++)
takkenTags |= this._state.monitors[i].tags;
}
else {
takkenTags = ~0;
}
this._state.monitors[mon].tags |= ~takkenTags;
this._renderer.render(mon);

View File

@@ -41,6 +41,7 @@ var Renderer = GObject.registerClass(
outerGaps: this._settings.get_uint("outer-gap-size"),
};
this.warpEnabled = this._settings.get_boolean("warp-cursor");
this._state.singleTagset = this._settings.get_boolean("single-tagset");
for (const window of global.display.list_all_windows())
this.trackWindow(window);
@@ -50,9 +51,14 @@ var Renderer = GObject.registerClass(
.get_active_workspace_index();
const tags = 0b1 << workspace;
if (Meta.prefs_get_workspaces_only_on_primary()) {
this._state.monitors[global.display.get_primary_monitor()].tags = tags;
const primaryMon = global.display.get_primary_monitor();
this._state.monitors[primaryMon].tags = tags;
for (let i = 0; i < global.display.get_n_monitors(); i++) {
if (primaryMon === i) continue;
this._state.monitors[i].tags = 0b1 << i;
}
} else {
for (let i = 0; i < this._state.monitors.length; i++)
for (let i = 0; i < global.display.get_n_monitors(); i++)
this._state.monitors[i].tags = tags;
}
@@ -148,9 +154,13 @@ var Renderer = GObject.registerClass(
this._indicator.update();
})
),
// global.display.connect("window-entered-monitor", (_display, monitor, window) => {
//
// }),
global.display.connect("window-entered-monitor", (_display, _monitor, handle) => {
const [oldW, newW] = this._state.updateByHandle(handle);
log("Monitor changed for window", oldW.handle.get_title(), oldW.monitor, "to", newW.monitor);
if (oldW) this.render(oldW.monitor);
if (newW) this.render(newW.monitor);
this._indicator.update();
}),
];
this._workspaceSignals = [
global.workspace_manager.connect("active-workspace-changed", () => {
@@ -164,7 +174,7 @@ var Renderer = GObject.registerClass(
const primaryMon = global.display.get_primary_monitor();
this.setTags(primaryMon, tags);
} else {
for (let i = 0; i < this._state.monitors.length; i++) {
for (let i = 0; i < global.display.get_n_monitors(); i++) {
this._state.monitors[i].tags = tags;
const focusedWindow = this._state.windows.find(
(x) => x.handle === this._state.monitors[i].focused
@@ -196,6 +206,16 @@ var Renderer = GObject.registerClass(
case "warp-cursor":
this.warpEnabled = this._settings.get_boolean(key);
break;
case "single-tagset":
this._state.singleTagset = this._settings.get_boolean(key);
const primaryMon = global.display.get_primary_monitor();
for (let i = 0; i < global.display.get_n_monitors(); i++) {
if (i === primaryMon) continue;
this._state.monitors[i].tags = 0b1 << i;
}
this.renderAll();
this._indicator.update();
break;
}
});
}
@@ -233,13 +253,13 @@ var Renderer = GObject.registerClass(
this._indicator.update();
}),
handle.connect("workspace-changed", (handle) => {
log("Workspace changed for window");
if (handle._ignoreWorkspaceChange) {
handle._ignoreWorkspaceChange = false;
return;
}
if (!this._isValidWindow(handle)) return;
const [oldW, newW] = this._state.updateByHandle(handle);
log("Workspace changed for window", oldW.handle.get_title(), oldW.tags, "to", newW.tags);
if (oldW) this.render(oldW.monitor);
if (newW) this.render(newW.monitor);
this._indicator.update();
@@ -306,7 +326,8 @@ var Renderer = GObject.registerClass(
this._state.monitors[mon].tags = tags;
this._setGWorkspaceIfNeeded(mon);
for (let i = 0; i < this._state.monitors.length; i++) {
if (this._state.singleTagset) {
for (let i = 0; i < global.display.get_n_monitors(); i++) {
if (this._state.monitors[i] & tags && mon !== i) {
// Remove the selected tag from other monitors.
// If the other monitor had only this tag, swap monitor's tags instead.
@@ -315,6 +336,7 @@ var Renderer = GObject.registerClass(
this.render(i);
}
}
}
this.render(mon);
this._indicator.update(mon);

View File

@@ -25,6 +25,8 @@ var StateManager = GObject.registerClass(
mfact: 55,
}));
this.sharedTagset = false;
// The currently focused monitor.
this.focusedMon = 0;
@@ -40,9 +42,8 @@ var StateManager = GObject.registerClass(
*/
_windowFromHandle(handle) {
const mon = handle.get_monitor();
const tags = handle.on_all_workspaces
? ~0
: 0b1 << handle.get_workspace().index();
const tags = this.monitors[mon].tags;
log("New window", handle.get_title(), "Monitor", mon, "tags", tags);
return {
handle,
monitor: mon,
@@ -58,13 +59,13 @@ var StateManager = GObject.registerClass(
newWindow(handle) {
const window = this._windowFromHandle(handle);
this.monitors[window.monitor].beforeZoom = null;
log("New window on tag", window.tags);
log("New window on tag", window.tags, "monitor", window.monitor);
this.windows.unshift(window);
}
/**
* @param {Meta.Window} handle
* @returns {[FairyWindow, FairyWindow]} [old, new]
* @returns {[Fairyit worked, but recent update caused it to go bad, i literally updated today and it broke, now i need to see what package broke itWindow, FairyWindow]} [old, new]
*/
updateByHandle(handle) {
const i = this.windows.findIndex((x) => x.handle === handle);
@@ -89,7 +90,9 @@ var StateManager = GObject.registerClass(
*/
workIndex(mon, tags, idx) {
const windows = this.windows.filter(
(x) => x.monitor === mon && x.tags & tags
this.singleTagset
? (x) => x.tags & tags
: (x) => x.monitor === mon && x.tags & tags
);
if (idx < 0) idx = windows.length + idx;
return windows[idx % windows.length];
@@ -102,7 +105,9 @@ var StateManager = GObject.registerClass(
workIndexByHandle(handle) {
const window = this.windows.find((x) => x.handle === handle);
const windows = this.windows.filter(
(x) => x.monitor === window.monitor && x.tags & window.tags
this.singleTagset
? (x) => x.tags & window.tags
: (x) => x.monitor === window.monitor && x.tags & window.tags
);
return windows.findIndex((x) => x.handle === handle);
}
@@ -115,7 +120,9 @@ var StateManager = GObject.registerClass(
*/
swap(mon, tags, idx, newIdx) {
const windows = this.windows.filter(
(x) => x.monitor === mon && x.tags & tags
this.singleTagset
? (x) => x.tags & tags
: (x) => x.monitor === mon && x.tags & tags
);
if (newIdx < 0) newIdx = windows.length + newIdx;
newIdx %= windows.length;
@@ -146,15 +153,16 @@ var StateManager = GObject.registerClass(
*/
render(mon, tags) {
const windows = this.windows.filter(
(x) => x.monitor === mon && x.tags & tags
this.singleTagset
? (x) => x.tags & tags
: (x) => x.monitor === mon && x.tags & tags
);
log(`${windows.length} windows for monitor ${mon} with tags ${tags}`);
return this._layout(this.monitors[mon], windows);
}
_layout({ layout, nmaster, mfact, focused }, windows) {
const focusedW = windows.find((x) => x.handle === focused)
?? windows[0];
const focusedW = windows.find((x) => x.handle === focused) ?? windows[0];
switch (layout) {
case "monocle":