4 Commits

Author SHA1 Message Date
Peter Fajdiga
d68494d257 WIP 2025-11-30 11:10:51 +01:00
Peter Fajdiga
679d1d488c Simplify SignalGrouping 2025-11-30 11:10:38 +01:00
Peter Fajdiga
ce4884c48a Implement signal grouping 2025-11-30 09:02:58 +01:00
Peter Fajdiga
1c89391739 MockWorkspace.removeWindow: Randomize the order of signals 2025-11-26 23:54:12 +01:00
3 changed files with 101 additions and 19 deletions

View File

@@ -0,0 +1,62 @@
namespace SignalGrouping {
export class Group {
private argsBySignal: Map<QSignal<[any]>, [[any]]> = new Map();
private delayer = new Delayer(50, () => this.fire());
constructor(
private handlers: Handler<any>[], // in order of decreasing priority
) {}
public connect(manager: SignalManager) {
const signals = collectSignals(this.handlers);
for (const signal of signals) {
manager.connect(signal, (...args: any) => {
this.argsBySignal.set(signal, args);
this.delayer.run();
});
}
}
private fire() {
for (const handler of this.handlers) {
const args = this.getGroupArgs(handler.signals);
if (args !== null) {
handler.f(args);
break;
}
}
this.argsBySignal.clear();
}
private getGroupArgs(signals: QSignal<[any]>[]) {
const groupArgs = signals.map(signal => this.argsBySignal.get(signal));
if (groupArgs.some(args => args === undefined)) {
return null;
}
return groupArgs;
}
}
function collectSignals<S extends QSignal<any>[]>(handlers: Handler<S>[]) {
const signals: S[number][] = [];
for (const handler of handlers) {
for (const signal of handler.signals) {
if (!signals.includes(signal)) {
signals.push(signal);
}
}
}
return signals;
}
export class Handler<S extends QSignal<any>[]> {
constructor(
public signals: [...S],
public f: (...args: [...GroupArgs<S>]) => void,
) {}
}
type GroupArgs<S extends QSignal<any>[]> = {
[K in keyof S]: S[K] extends QSignal<infer A> ? A : never;
};
}

View File

@@ -7,22 +7,40 @@ function initWorkspaceSignalHandlers(world: World, focusPasser: FocusPassing.Pas
});
});
manager.connect(Workspace.windowRemoved, (kwinClient: KwinClient) => {
world.do((clientManager, desktopManager) => {
clientManager.removeClient(kwinClient, FocusPassing.Type.Immediate);
});
});
manager.connect(Workspace.windowActivated, (kwinClient: KwinClient|null) => {
if (kwinClient === null) {
focusPasser.activate();
} else {
focusPasser.clearIfDifferent(kwinClient);
world.do((clientManager, desktopManager) => {
clientManager.onClientFocused(kwinClient);
});
}
});
new SignalGrouping.Group([
new SignalGrouping.Handler(
[Workspace.windowRemoved, Workspace.windowActivated] as const,
(windowRemovedArgs, windowActivatedArgs) => {
const kwinClient = windowRemovedArgs[0];
world.do((clientManager, desktopManager) => {
clientManager.removeClient(kwinClient, FocusPassing.Type.Immediate);
});
},
),
new SignalGrouping.Handler(
[Workspace.windowRemoved],
(windowRemovedArgs) => {
const kwinClient = windowRemovedArgs[0];
world.do((clientManager, desktopManager) => {
clientManager.removeClient(kwinClient, FocusPassing.Type.Immediate);
});
},
),
new SignalGrouping.Handler(
[Workspace.windowActivated],
(windowActivatedArgs) => {
const kwinClient = windowActivatedArgs[0];
if (kwinClient === null) {
focusPasser.activate();
} else {
focusPasser.clearIfDifferent(kwinClient);
world.do((clientManager, desktopManager) => {
clientManager.onClientFocused(kwinClient);
});
}
},
),
]).connect(manager);
manager.connect(Workspace.currentDesktopChanged, () => {
world.do(() => {}); // re-arrange desktop

View File

@@ -54,12 +54,14 @@ class MockWorkspace {
public removeWindow(window: MockKwinClient) {
this.activeWindow = null;
runReorder(
() => {
if (this.activeWindow === null) {
activateRandomWindowOnDesktop(this.currentDesktop);
};
},
() => this.windows.splice(this.windows.indexOf(window), 1),
() => this.windowRemoved.fire(window),
);
if (this.activeWindow === null) {
activateRandomWindowOnDesktop(this.currentDesktop);
};
}
public moveWindow(window: MockKwinClient, ...deltas: QmlPoint[]) {