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._state = new State.StateManager();
this._settings = ExtensionUtils.getSettings("org.gnome.shell.extensions.fairy"); 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._indicator = new Indicator.Indicator(this._state, this._renderer, this._keybinds);
this._renderer = new Renderer.Renderer(this._state, this._settings, this._indicator, this._border); this._renderer = new Renderer.Renderer(this._state, this._settings, this._indicator, this._border);
this._keybinds = new Keybinds.KeyboardManager(this._state, this._renderer, this._indicator); this._keybinds = new Keybinds.KeyboardManager(this._state, this._renderer, this._indicator);

View File

@@ -5,6 +5,10 @@
<default>true</default> <default>true</default>
<summary>Should the cursor warp to newly focused windows</summary> <summary>Should the cursor warp to newly focused windows</summary>
</key> </key>
<key type="b" name="single-tagset">
<default>false</default>
<summary>Should tag be shared between monitors</summary>
</key>
<!-- Visual things --> <!-- Visual things -->
<key type="b" name="show-layout"> <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`), floating: Gio.icon_new_for_string(`${Me.path}/icons/floating.svg`),
deck: Gio.icon_new_for_string(`${Me.path}/icons/deck.svg`), deck: Gio.icon_new_for_string(`${Me.path}/icons/deck.svg`),
}; };
this._destroyed = true;
} }
endInit(ext) { endInit(ext) {
@@ -34,7 +35,6 @@ var Indicator = GObject.registerClass(
this._keybinds = ext._keybinds; this._keybinds = ext._keybinds;
} }
_createSelectableItem(title, cb) { _createSelectableItem(title, cb) {
const menuItem = new PopupMenu.PopupMenuItem(title, {}); const menuItem = new PopupMenu.PopupMenuItem(title, {});
menuItem.connect("activate", cb); menuItem.connect("activate", cb);
@@ -142,7 +142,8 @@ var Indicator = GObject.registerClass(
const tag = 0b1 << tagNbr; const tag = 0b1 << tagNbr;
const active = state.tags & tag; const active = state.tags & tag;
const hasWindow = 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; if (!active && !hasWindow) continue;
const style = "width: 30px;"; const style = "width: 30px;";
const tagBtn = new St.Button({ const tagBtn = new St.Button({

View File

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

View File

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

View File

@@ -25,6 +25,8 @@ var StateManager = GObject.registerClass(
mfact: 55, mfact: 55,
})); }));
this.sharedTagset = false;
// The currently focused monitor. // The currently focused monitor.
this.focusedMon = 0; this.focusedMon = 0;
@@ -40,9 +42,8 @@ var StateManager = GObject.registerClass(
*/ */
_windowFromHandle(handle) { _windowFromHandle(handle) {
const mon = handle.get_monitor(); const mon = handle.get_monitor();
const tags = handle.on_all_workspaces const tags = this.monitors[mon].tags;
? ~0 log("New window", handle.get_title(), "Monitor", mon, "tags", tags);
: 0b1 << handle.get_workspace().index();
return { return {
handle, handle,
monitor: mon, monitor: mon,
@@ -58,13 +59,13 @@ var StateManager = GObject.registerClass(
newWindow(handle) { newWindow(handle) {
const window = this._windowFromHandle(handle); const window = this._windowFromHandle(handle);
this.monitors[window.monitor].beforeZoom = null; 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); this.windows.unshift(window);
} }
/** /**
* @param {Meta.Window} handle * @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) { updateByHandle(handle) {
const i = this.windows.findIndex((x) => x.handle === handle); const i = this.windows.findIndex((x) => x.handle === handle);
@@ -89,7 +90,9 @@ var StateManager = GObject.registerClass(
*/ */
workIndex(mon, tags, idx) { workIndex(mon, tags, idx) {
const windows = this.windows.filter( 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; if (idx < 0) idx = windows.length + idx;
return windows[idx % windows.length]; return windows[idx % windows.length];
@@ -102,7 +105,9 @@ var StateManager = GObject.registerClass(
workIndexByHandle(handle) { workIndexByHandle(handle) {
const window = this.windows.find((x) => x.handle === handle); const window = this.windows.find((x) => x.handle === handle);
const windows = this.windows.filter( 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); return windows.findIndex((x) => x.handle === handle);
} }
@@ -115,7 +120,9 @@ var StateManager = GObject.registerClass(
*/ */
swap(mon, tags, idx, newIdx) { swap(mon, tags, idx, newIdx) {
const windows = this.windows.filter( 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; if (newIdx < 0) newIdx = windows.length + newIdx;
newIdx %= windows.length; newIdx %= windows.length;
@@ -146,15 +153,16 @@ var StateManager = GObject.registerClass(
*/ */
render(mon, tags) { render(mon, tags) {
const windows = this.windows.filter( 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}`); log(`${windows.length} windows for monitor ${mon} with tags ${tags}`);
return this._layout(this.monitors[mon], windows); return this._layout(this.monitors[mon], windows);
} }
_layout({ layout, nmaster, mfact, focused }, windows) { _layout({ layout, nmaster, mfact, focused }, windows) {
const focusedW = windows.find((x) => x.handle === focused) const focusedW = windows.find((x) => x.handle === focused) ?? windows[0];
?? windows[0];
switch (layout) { switch (layout) {
case "monocle": case "monocle":