mirror of
https://github.com/zoriya/fairy.git
synced 2025-12-06 05:36:09 +00:00
wip: Add multi monitor support
This commit is contained in:
@@ -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);
|
||||||
|
|||||||
@@ -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">
|
||||||
|
|||||||
@@ -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({
|
||||||
|
|||||||
@@ -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);
|
||||||
|
|||||||
@@ -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);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -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":
|
||||||
|
|||||||
Reference in New Issue
Block a user