11 Commits
v0.8 ... v0.9

Author SHA1 Message Date
Peter Fajdiga
c7cfa261b9 bump version to 0.9 2024-03-30 12:46:59 +01:00
Peter Fajdiga
56955e4df3 src/config: don't tile kded windows 2024-03-30 12:45:42 +01:00
Peter Fajdiga
bb308cfbfb config: merge X11 and Wayland class regexes in window rules 2024-03-30 12:45:40 +01:00
Peter Fajdiga
6c00245943 config: escape . in window rules 2024-03-30 12:45:38 +01:00
Peter Fajdiga
2efdbe5a7b support regex for class selector in window rules (resolves #41) 2024-03-30 12:45:36 +01:00
Peter Fajdiga
092cbf3ff1 kwin.d.ts: remove unused signal maximizedChanged 2024-03-30 12:45:33 +01:00
Peter Fajdiga
f9ae299ce8 Tiled: restore opacity after un-tiling 2024-03-30 12:45:28 +01:00
Peter Fajdiga
695f5edf6a config: add option to disable layering (resolves #41) 2024-03-30 12:45:25 +01:00
Peter Fajdiga
9b80b535a1 readme: update QML dependencies 2024-03-19 10:58:51 +01:00
Peter Fajdiga
752df86db5 bump version to 0.8.1 2024-03-19 10:46:33 +01:00
Peter Fajdiga
f05eefe19b config: add plasmashell to window rules (fixes #38) 2024-03-19 10:17:37 +01:00
9 changed files with 70 additions and 60 deletions

View File

@@ -19,7 +19,7 @@ Similar window managers include [PaperWM](https://github.com/paperwm/PaperWM),
## Dependencies
Karousel requires the following QML modules:
- QtQuick 2.15
- QtQuick 6.0
- org.kde.kwin 3.0
- org.kde.notification 1.0

View File

@@ -121,6 +121,13 @@
</property>
</widget>
</item>
<item>
<widget class="QRadioButton" name="kcfg_noLayering">
<property name="text">
<string>No layering</string>
</property>
</widget>
</item>
</layout>
</widget>
</item>

View File

@@ -9,7 +9,7 @@
"Name": "Peter Fajdiga"
}],
"Id": "karousel",
"Version": "0.8",
"Version": "0.9",
"License": "GPLv3",
"Website": "https://github.com/peterfajdiga/karousel",
"BugReportUrl": "https://github.com/peterfajdiga/karousel/issues"

View File

@@ -4,43 +4,31 @@ const defaultWindowRules = `[
"tile": false
},
{
"class": "kcalc",
"class": "(org\\\\.kde\\\\.)?plasmashell",
"tile": false
},
{
"class": "org.kde.kcalc",
"class": "(org\\\\.kde\\\\.)?kded6",
"tile": false
},
{
"class": "kfind",
"class": "(org\\\\.kde\\\\.)?kcalc",
"tile": false
},
{
"class": "(org\\\\.kde\\\\.)?kfind",
"tile": true
},
{
"class": "org.kde.kfind",
"tile": true
},
{
"class": "kruler",
"class": "(org\\\\.kde\\\\.)?kruler",
"tile": false
},
{
"class": "org.kde.kruler",
"class": "(org\\\\.kde\\\\.)?krunner",
"tile": false
},
{
"class": "krunner",
"tile": false
},
{
"class": "org.kde.krunner",
"tile": false
},
{
"class": "yakuake",
"tile": false
},
{
"class": "org.kde.yakuake",
"class": "(org\\\\.kde\\\\.)?yakuake",
"tile": false
},
{
@@ -166,6 +154,11 @@ const configDef = [
type: "Bool",
default: false,
},
{
name: "noLayering",
type: "Bool",
default: false,
},
{
name: "windowRules",
type: "String",

View File

@@ -81,7 +81,6 @@ interface KwinClient {
readonly desktopsChanged: QSignal<[]>;
readonly activitiesChanged: QSignal<[]>;
readonly minimizedChanged: QSignal<[]>;
readonly maximizedChanged: QSignal<[]>
readonly maximizedAboutToChange: QSignal<[MaximizedMode]>
readonly captionChanged: QSignal<[]>;
readonly tileChanged: QSignal<[]>;

View File

@@ -1,15 +1,19 @@
class ClientMatcher {
private readonly rules: Map<string, RegExp>;
private readonly regex: RegExp;
constructor(rules: Map<string, RegExp>) {
this.rules = rules;
constructor(regex: RegExp) {
this.regex = regex;
}
public matches(kwinClient: KwinClient) {
const rule = this.rules.get(kwinClient.resourceClass);
if (rule === undefined) {
return false;
}
return rule.test(kwinClient.caption);
return this.regex.test(ClientMatcher.getClientString(kwinClient));
}
public static getClientString(kwinClient: KwinClient) {
return ClientMatcher.getRuleString(kwinClient.resourceClass, kwinClient.caption);
}
public static getRuleString(ruleClass: string, ruleCaption: string) {
return ruleClass + "\0" + ruleCaption;
}
}

View File

@@ -1,5 +1,5 @@
type WindowRule = {
class: string,
caption: string,
class: string | undefined,
caption: string | undefined,
tile: boolean,
};

View File

@@ -1,13 +1,16 @@
class WindowRuleEnforcer {
private readonly preferFloating: ClientMatcher;
private readonly preferTiling: ClientMatcher;
private readonly followCaption: Set<string>;
private readonly followCaption: RegExp;
constructor(windowRules: WindowRule[]) {
const [mapFloat, mapTile] = WindowRuleEnforcer.createWindowRuleMaps(windowRules);
this.preferFloating = new ClientMatcher(mapFloat);
this.preferTiling = new ClientMatcher(mapTile);
this.followCaption = new Set([...mapFloat.keys(), ...mapTile.keys()]);
const [floatRegex, tileRegex, followCaptionRegex] = WindowRuleEnforcer.createWindowRuleRegexes(windowRules);
log("floatRegex", floatRegex);
log("tileRegex", tileRegex);
log("followCaptionRegex", followCaptionRegex);
this.preferFloating = new ClientMatcher(floatRegex);
this.preferTiling = new ClientMatcher(tileRegex);
this.followCaption = followCaptionRegex;
}
public shouldTile(kwinClient: KwinClient) {
@@ -22,7 +25,7 @@ class WindowRuleEnforcer {
}
public initClientSignalManager(world: World, kwinClient: KwinClient) {
if (!this.followCaption.has(kwinClient.resourceClass)) {
if (!this.followCaption.test(kwinClient.resourceClass)) {
return null;
}
@@ -42,38 +45,39 @@ class WindowRuleEnforcer {
return manager;
}
private static createWindowRuleMaps(windowRules: WindowRule[]) {
const mapFloat = new Map<string, string[]>();
const mapTile = new Map<string, string[]>();
private static createWindowRuleRegexes(windowRules: WindowRule[]) {
const floatRegexes: string[] = [];
const tileRegexes: string[] = [];
const followCaptionRegexes: string[] = [];
for (const windowRule of windowRules) {
const map = windowRule.tile ? mapTile : mapFloat;
let captions = map.get(windowRule.class);
if (captions === undefined) {
captions = [];
map.set(windowRule.class, captions);
}
if (windowRule.caption !== undefined) {
captions.push(windowRule.caption);
const ruleClass = WindowRuleEnforcer.parseRegex(windowRule.class);
const ruleCaption = WindowRuleEnforcer.parseRegex(windowRule.caption);
const ruleString = ClientMatcher.getRuleString(ruleClass, ruleCaption);
(windowRule.tile ? tileRegexes : floatRegexes).push(ruleString);
if (ruleCaption !== ".*") {
followCaptionRegexes.push(ruleClass);
}
}
return [
WindowRuleEnforcer.createWindowRuleRegexMap(mapFloat),
WindowRuleEnforcer.createWindowRuleRegexMap(mapTile),
WindowRuleEnforcer.joinRegexes(floatRegexes),
WindowRuleEnforcer.joinRegexes(tileRegexes),
WindowRuleEnforcer.joinRegexes(followCaptionRegexes),
];
}
private static createWindowRuleRegexMap(windowRuleMap: Map<string, string[]>) {
const regexMap = new Map<string, RegExp>;
for (const [k, v] of windowRuleMap) {
regexMap.set(k, WindowRuleEnforcer.joinRegexes(v));
private static parseRegex(rawRule: string | undefined) {
if (rawRule === undefined || rawRule === "" || rawRule === ".*") {
return ".*";
} else {
return rawRule;
}
return regexMap;
}
private static joinRegexes(regexes: string[]) {
if (regexes.length === 0) {
return new RegExp("");
return new RegExp("a^"); // match nothing
}
if (regexes.length === 1) {

View File

@@ -174,6 +174,9 @@ namespace ClientState {
if (config.tiledKeepBelow) {
client.kwinClient.keepBelow = false;
}
if (config.offScreenOpacity < 1.0) {
client.kwinClient.opacity = 1.0;
}
client.setShade(false);
client.setFullScreen(false);
if (client.kwinClient.tile === null) {