feat: bury offline mode, ship antergos-layan-theme
remember when i thought an offline installer was a good idea? a pre-built squashfs that still needed internet to install DEs? "offline" in name only. it was a lie. a beautiful, naive lie. so i killed it. ripped out the mode picker, the connectivity check, the whole AskMode() circus. calamares-next now just shows a notice saying "yeah that wasnt actually offline" and launches directly into online mode. no more pretending. also fixed the QML nav button because having a greyed out "Next" on the last page is terrible UX. now it says "Done" and quits. youre welcome. and since we nuked the offline mode, might as well make the online mode look fucking spectacular. enter antergos-layan-theme: - kvantum theme because your apps deserve better than qt dreck - sddm theme (AntergosDark-Layan) for a sexy login screen - every plasma plasmoid from the rice (panel colorizer, netspeed, shutdown switch, applets, separators, music toolbar, the works) - yakuake arc-dark skin - antergos logos in /usr/share/logos and /usr/share/pixmaps - konsole profile, desktop appletsrc, all that jazz - kde_settings.conf now points to AntergosDark-Layan sddm theme also replaced the old antergos-grub-theme with the Layan grub theme because the old one was a git-sourced abomination. 75 distro icons, terminal box, selection widgets, antergos wallpaper. ships to /usr/share/grub/themes/antergos/ so calamares finds it. oh and a dozen audit fixes: - kscreenlockerrc wallpaper path fixed - kdialogrc no longer says some other distro - 7 stale knsregistry files deleted (dev machine was leaking) - systemd-inhibit guarded with command -v (dinit doesnt have it) - plasma restart uses killall not systemctl --user - "XeroLinux Toolkit" -> "Antergos Toolkit" in appletsrc - KDE_SESSION_VERSION=5 -> =6 (its 2026) - mirrorlist script says Artix not Arch - SDDM Messages.sh removed from build artifacts
This commit is contained in:
+109
@@ -0,0 +1,109 @@
|
||||
/*
|
||||
This file is part of the KDE project.
|
||||
|
||||
SPDX-FileCopyrightText: 2012 Martin Gräßlin <mgraesslin@kde.org>
|
||||
|
||||
SPDX-License-Identifier: GPL-2.0-or-later
|
||||
*/
|
||||
|
||||
"use strict";
|
||||
|
||||
function sleep(miliseconds) {
|
||||
var currentTime = new Date().getTime();
|
||||
|
||||
while (currentTime + miliseconds >= new Date().getTime()) {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
class MaximizeEffect {
|
||||
constructor() {
|
||||
effect.configChanged.connect(this.loadConfig.bind(this));
|
||||
effects.windowFrameGeometryChanged.connect(
|
||||
this.onWindowFrameGeometryChanged.bind(this));
|
||||
effects.windowMaximizedStateChanged.connect(
|
||||
this.onWindowMaximizedStateChanged.bind(this));
|
||||
effect.animationEnded.connect(this.restoreForceBlurState.bind(this));
|
||||
|
||||
this.loadConfig();
|
||||
}
|
||||
|
||||
loadConfig() {
|
||||
this.duration = animationTime(250);
|
||||
}
|
||||
|
||||
onWindowMaximizedStateChanged(window) {
|
||||
if (!window.oldGeometry) {
|
||||
return;
|
||||
}
|
||||
sleep(50); //Skip some frames
|
||||
window.setData(Effect.WindowForceBlurRole, true);
|
||||
let oldGeometry = window.oldGeometry;
|
||||
const newGeometry = window.geometry;
|
||||
if (oldGeometry.width == newGeometry.width && oldGeometry.height == newGeometry.height)
|
||||
oldGeometry = window.olderGeometry;
|
||||
window.olderGeometry = Object.assign({}, window.oldGeometry);
|
||||
window.oldGeometry = Object.assign({}, newGeometry);
|
||||
window.maximizeAnimation1 = animate({
|
||||
window: window,
|
||||
duration: this.duration,
|
||||
animations: [{
|
||||
type: Effect.Size,
|
||||
to: {
|
||||
value1: newGeometry.width,
|
||||
value2: newGeometry.height
|
||||
},
|
||||
from: {
|
||||
value1: oldGeometry.width,
|
||||
value2: oldGeometry.height
|
||||
},
|
||||
curve: QEasingCurve.OutCubic
|
||||
}, {
|
||||
type: Effect.Translation,
|
||||
to: {
|
||||
value1: 0,
|
||||
value2: 0
|
||||
},
|
||||
from: {
|
||||
value1: oldGeometry.x - newGeometry.x - (newGeometry.width / 2 - oldGeometry.width / 2),
|
||||
value2: oldGeometry.y - newGeometry.y - (newGeometry.height / 2 - oldGeometry.height / 2)
|
||||
},
|
||||
curve: QEasingCurve.OutCubic
|
||||
}]
|
||||
});
|
||||
if (!window.resize) {
|
||||
window.maximizeAnimation2 =animate({
|
||||
window: window,
|
||||
duration: this.duration,
|
||||
animations: [{
|
||||
type: Effect.CrossFadePrevious,
|
||||
to: 1.0,
|
||||
from: 0.0,
|
||||
curve: QEasingCurve.OutCubic
|
||||
}]
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
restoreForceBlurState(window) {
|
||||
window.setData(Effect.WindowForceBlurRole, null);
|
||||
}
|
||||
|
||||
onWindowFrameGeometryChanged(window, oldGeometry) {
|
||||
if (window.maximizeAnimation1) {
|
||||
if (window.geometry.width != window.oldGeometry.width ||
|
||||
window.geometry.height != window.oldGeometry.height) {
|
||||
cancel(window.maximizeAnimation1);
|
||||
delete window.maximizeAnimation1;
|
||||
if (window.maximizeAnimation2) {
|
||||
cancel(window.maximizeAnimation2);
|
||||
delete window.maximizeAnimation2;
|
||||
}
|
||||
}
|
||||
}
|
||||
window.oldGeometry = Object.assign({}, window.geometry);
|
||||
window.olderGeometry = Object.assign({}, oldGeometry);
|
||||
}
|
||||
}
|
||||
|
||||
new MaximizeEffect();
|
||||
+113
@@ -0,0 +1,113 @@
|
||||
/********************************************************************
|
||||
This file is part of the KDE project.
|
||||
|
||||
Copyright (C) 2012 Martin Gräßlin <mgraesslin@kde.org>
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*********************************************************************/
|
||||
|
||||
"use strict";
|
||||
|
||||
function sleep(miliseconds) {
|
||||
var currentTime = new Date().getTime();
|
||||
|
||||
while (currentTime + miliseconds >= new Date().getTime()) {
|
||||
}
|
||||
}
|
||||
|
||||
var maximizeEffect = {
|
||||
duration: animationTime(150),
|
||||
loadConfig: function () {
|
||||
maximizeEffect.duration = animationTime(150);
|
||||
},
|
||||
maximizeChanged: function (window) {
|
||||
var m = Math.floor((Math.random() * 2) + 1);
|
||||
sleep(50); //Skip some frames
|
||||
if (!window.oldGeometry) {
|
||||
return;
|
||||
}
|
||||
window.setData(Effect.WindowForceBlurRole, true);
|
||||
var oldGeometry, newGeometry;
|
||||
oldGeometry = window.oldGeometry;
|
||||
newGeometry = window.geometry;
|
||||
if (oldGeometry.width == newGeometry.width && oldGeometry.height == newGeometry.height)
|
||||
oldGeometry = window.olderGeometry;
|
||||
window.olderGeometry = window.oldGeometry;
|
||||
window.oldGeometry = newGeometry;
|
||||
window.maximizeAnimation1 = animate({
|
||||
window: window,
|
||||
duration: maximizeEffect.duration,
|
||||
animations: [{
|
||||
type: Effect.Size,
|
||||
to: {
|
||||
value1: newGeometry.width,
|
||||
value2: newGeometry.height
|
||||
},
|
||||
from: {
|
||||
value1: oldGeometry.width,
|
||||
value2: oldGeometry.height
|
||||
}
|
||||
}, {
|
||||
type: Effect.Translation,
|
||||
to: {
|
||||
value1: 0,
|
||||
value2: 0
|
||||
},
|
||||
from: {
|
||||
value1: oldGeometry.x - newGeometry.x - (newGeometry.width / 2 - oldGeometry.width / 2),
|
||||
value2: oldGeometry.y - newGeometry.y - (newGeometry.height / 2 - oldGeometry.height / 2)
|
||||
}
|
||||
}]
|
||||
});
|
||||
//if (!window.resize) {
|
||||
if (1 == 2 ) { // disabled the routine because
|
||||
// CrossFadePrevious+xrender grabs a garbled texture as the start crossfade point
|
||||
window.maximizeAnimation2 =animate({
|
||||
window: window,
|
||||
duration: maximizeEffect.duration,
|
||||
animations: [{
|
||||
delay: animationTime(32),
|
||||
type: Effect.CrossFadePrevious,
|
||||
to: 1.0,
|
||||
from: 0.0
|
||||
}]
|
||||
});
|
||||
}
|
||||
},
|
||||
restoreForceBlurState: function(window) {
|
||||
window.setData(Effect.WindowForceBlurRole, null);
|
||||
},
|
||||
geometryChange: function (window, oldGeometry) {
|
||||
if (window.maximizeAnimation1) {
|
||||
if (window.geometry.width != window.oldGeometry.width ||
|
||||
window.geometry.height != window.oldGeometry.height) {
|
||||
cancel(window.maximizeAnimation1);
|
||||
delete window.maximizeAnimation1;
|
||||
if (window.maximizeAnimation2) {
|
||||
cancel(window.maximizeAnimation2);
|
||||
delete window.maximizeAnimation2;
|
||||
}
|
||||
}
|
||||
}
|
||||
window.oldGeometry = window.geometry;
|
||||
window.olderGeometry = oldGeometry;
|
||||
},
|
||||
init: function () {
|
||||
effect.configChanged.connect(maximizeEffect.loadConfig);
|
||||
effects.windowGeometryShapeChanged.connect(maximizeEffect.geometryChange);
|
||||
effects.windowMaximizedStateChanged.connect(maximizeEffect.maximizeChanged);
|
||||
effect.animationEnded.connect(maximizeEffect.restoreForceBlurState);
|
||||
}
|
||||
};
|
||||
maximizeEffect.init();
|
||||
+19
@@ -0,0 +1,19 @@
|
||||
[Desktop Entry]
|
||||
Comment=Animation for windows going to maximize/restore from maximize, less glitches
|
||||
Icon=preferences-system-windows-effect-maximize
|
||||
Name=Maximize antiglitch
|
||||
Type=Service
|
||||
X-KDE-ParentApp=
|
||||
X-KDE-PluginInfo-Author=Martin Gräßlin (changed by Antonio Orefice)
|
||||
X-KDE-PluginInfo-Category=Appearance
|
||||
X-KDE-PluginInfo-Email=kokoko3k@gmail.com
|
||||
X-KDE-PluginInfo-License=GPL
|
||||
X-KDE-PluginInfo-Name=kwin4_effect_maximize_xrender
|
||||
X-KDE-PluginInfo-Version=1.1
|
||||
X-KDE-PluginInfo-Website=
|
||||
X-KDE-ServiceTypes=KWin/Effect
|
||||
X-KDE-PluginInfo-EnabledByDefault=false
|
||||
X-KDE-Ordering=60
|
||||
X-Plasma-API=javascript
|
||||
X-Plasma-MainScript=code/maximize-xrender.js
|
||||
|
||||
+111
@@ -0,0 +1,111 @@
|
||||
/********************************************************************
|
||||
This file is part of the KDE project.
|
||||
|
||||
Copyright (C) 2012 Martin Gräßlin <mgraesslin@kde.org>
|
||||
Copyright (C) 2018 Alex Nemeth <alex.nemeth329@gmail.com
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*********************************************************************/
|
||||
|
||||
var rubberbandMaximizeEffect = {
|
||||
duration: animationTime(200),
|
||||
deviation: 0.05,
|
||||
loadConfig: function () {
|
||||
"use strict";
|
||||
rubberbandMaximizeEffect.duration = animationTime(200);
|
||||
},
|
||||
slotWindowMaximizedStateChanged: function (window) {
|
||||
"use strict";
|
||||
if (!window.oldGeometry) {
|
||||
return;
|
||||
}
|
||||
|
||||
window.setData(Effect.WindowForceBackgroundContrastRole, true);
|
||||
window.setData(Effect.WindowForceBlurRole, true);
|
||||
|
||||
var oldGeometry = window.oldGeometry;
|
||||
var newGeometry = window.geometry;
|
||||
if (oldGeometry.width == newGeometry.width &&
|
||||
oldGeometry.height == newGeometry.height) {
|
||||
oldGeometry = window.olderGeometry;
|
||||
}
|
||||
|
||||
var scale = 0;
|
||||
|
||||
if (oldGeometry.width < newGeometry.width) {
|
||||
scale = 1 - rubberbandMaximizeEffect.deviation;
|
||||
} else {
|
||||
scale = 1 + rubberbandMaximizeEffect.deviation;
|
||||
}
|
||||
|
||||
window.olderGeometry = window.oldGeometry;
|
||||
window.oldGeometry = newGeometry;
|
||||
|
||||
window.maximizeAnimation = animate({
|
||||
window: window,
|
||||
curve: QEasingCurve.OutSine,
|
||||
duration: rubberbandMaximizeEffect.duration,
|
||||
animations: [
|
||||
{
|
||||
type: Effect.Size,
|
||||
delay: animationTime(10),
|
||||
from: {
|
||||
value1: newGeometry.width * scale,
|
||||
value2: newGeometry.height * scale
|
||||
},
|
||||
to: {
|
||||
value1: newGeometry.width,
|
||||
value2: newGeometry.height
|
||||
}
|
||||
},
|
||||
{
|
||||
type: Effect.Translation,
|
||||
from: {
|
||||
value1: (oldGeometry.x - newGeometry.x - (newGeometry.width - oldGeometry.width) / 2) * rubberbandMaximizeEffect.deviation,
|
||||
value2: (oldGeometry.y - newGeometry.y - (newGeometry.height - oldGeometry.height) / 2) * rubberbandMaximizeEffect.deviation
|
||||
},
|
||||
to: {
|
||||
value1: 0,
|
||||
value2: 0
|
||||
}
|
||||
}
|
||||
]
|
||||
});
|
||||
},
|
||||
slotWindowGeometryShapeChanged: function (window, oldGeometry) {
|
||||
"use strict";
|
||||
if (window.maximizeAnimation) {
|
||||
if (window.geometry.width != window.oldGeometry.width ||
|
||||
window.geometry.height != window.oldGeometry.height) {
|
||||
cancel(window.maximizeAnimation);
|
||||
delete window.maximizeAnimation;
|
||||
}
|
||||
}
|
||||
window.oldGeometry = window.geometry;
|
||||
window.olderGeometry = oldGeometry;
|
||||
},
|
||||
slotAnimationEnded: function (window) {
|
||||
window.setData(Effect.WindowForceBackgroundContrastRole, null);
|
||||
window.setData(Effect.WindowForceBlurRole, null);
|
||||
},
|
||||
init: function () {
|
||||
"use strict";
|
||||
effect.configChanged.connect(rubberbandMaximizeEffect.loadConfig);
|
||||
effect.animationEnded.connect(rubberbandMaximizeEffect.slotAnimationEnded);
|
||||
effects.windowGeometryShapeChanged.connect(rubberbandMaximizeEffect.slotWindowGeometryShapeChanged);
|
||||
effects.windowMaximizedStateChanged.connect(rubberbandMaximizeEffect.slotWindowMaximizedStateChanged);
|
||||
}
|
||||
};
|
||||
|
||||
rubberbandMaximizeEffect.init();
|
||||
+18
@@ -0,0 +1,18 @@
|
||||
[Desktop Entry]
|
||||
Comment=Maximize/Restore window animation similar to Windows 10
|
||||
Icon=preferences-system-windows-effect-rubberband-maximize
|
||||
Name=Rubberband Maximize
|
||||
Type=Service
|
||||
X-KDE-ParentApp=
|
||||
X-KDE-PluginInfo-Author=Alex Nemeth
|
||||
X-KDE-PluginInfo-Category=Appearance
|
||||
X-KDE-PluginInfo-Email=alex.nemeth329@gmail.com
|
||||
X-KDE-PluginInfo-License=GPL
|
||||
X-KDE-PluginInfo-Name=kwin4_effect_rubberband_maximize
|
||||
X-KDE-PluginInfo-Version=1
|
||||
X-KDE-PluginInfo-Website=
|
||||
X-KDE-ServiceTypes=KWin/Effect
|
||||
X-KDE-PluginInfo-EnabledByDefault=true
|
||||
X-KDE-Ordering=60
|
||||
X-Plasma-API=javascript
|
||||
X-Plasma-MainScript=code/main.js
|
||||
+91
@@ -0,0 +1,91 @@
|
||||
import QtQuick 2.0;
|
||||
import org.kde.plasma.core 2.0 as PlasmaCore;
|
||||
import org.kde.plasma.components 2.0 as Plasma;
|
||||
import org.kde.kwin 2.0;
|
||||
|
||||
Item {
|
||||
id: root
|
||||
|
||||
PlasmaCore.DataSource {
|
||||
id: composition
|
||||
engine: 'executable'
|
||||
connectedSources: []
|
||||
property QtObject client
|
||||
|
||||
function set(aClient) {
|
||||
client = aClient
|
||||
var windowId = client.windowId.toString(16)
|
||||
composition.connectSource("xprop -id 0x" + windowId + " _NET_WM_BYPASS_COMPOSITOR")
|
||||
}
|
||||
|
||||
function preference(stdout) {
|
||||
if (clientIsException()) {
|
||||
return "on"
|
||||
} else {
|
||||
var splittedStdout = stdout.split(" ")
|
||||
var compositionPreference = splittedStdout[2]
|
||||
|
||||
if (compositionPreference == "not") {
|
||||
return "none"
|
||||
} else if (compositionPreference == 1) {
|
||||
return "off"
|
||||
} else if (compositionPreference == 2) {
|
||||
return "on"
|
||||
} else {
|
||||
var error = ": Invalid composition preference: "
|
||||
console.error(client.resourceClass + error + compositionPreference)
|
||||
return false
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function clientIsException() {
|
||||
var result = false;
|
||||
const exceptions = ['plasmashell', 'ksmserver-logout-greeter'];
|
||||
let index = 0;
|
||||
|
||||
while (!result && index < exceptions.length) {
|
||||
result = (client.resourceClass == exceptions[index]);
|
||||
index++;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
onNewData: {
|
||||
var exitCode = data["exit code"]
|
||||
var exitStatus = data["exit status"]
|
||||
var stdout = data["stdout"]
|
||||
var stderr = data["stderr"]
|
||||
|
||||
if (exitCode != 0) {
|
||||
console.error(stderr)
|
||||
return false
|
||||
} else {
|
||||
let compositionPreference = composition.preference(stdout)
|
||||
|
||||
if (client.fullScreen && compositionPreference != "on") {
|
||||
client.blocksCompositing = true
|
||||
} else if (!client.fullScreen && compositionPreference != "off") {
|
||||
client.blocksCompositing = false
|
||||
}
|
||||
}
|
||||
|
||||
disconnectSource(sourceName)
|
||||
}
|
||||
}
|
||||
|
||||
Connections {
|
||||
target: workspace
|
||||
|
||||
function onClientAdded(client) {
|
||||
if (client.fullScreen) {
|
||||
composition.set(client)
|
||||
}
|
||||
}
|
||||
|
||||
function onClientFullScreenSet(client) {
|
||||
composition.set(client)
|
||||
}
|
||||
}
|
||||
}
|
||||
+19
@@ -0,0 +1,19 @@
|
||||
[Desktop Entry]
|
||||
|
||||
Name=Autocomposer
|
||||
X-KDE-PluginInfo-Version=4
|
||||
Comment=Blocks compositing on fullscreen, to improve graphical performance
|
||||
Icon=preferences-desktop-effects
|
||||
|
||||
X-KDE-PluginInfo-License=GPLv3
|
||||
X-KDE-PluginInfo-Website=https://store.kde.org/p/1502826/
|
||||
|
||||
X-KDE-PluginInfo-Name=autocomposer
|
||||
Type=Service
|
||||
X-KDE-PluginInfo-Category=Kwin Script
|
||||
X-KDE-PluginInfo-EnabledByDefault=true
|
||||
|
||||
X-KDE-ServiceTypes=KWin/Script
|
||||
X-Plasma-API=declarativescript
|
||||
X-Plasma-MainScript=code/main.qml
|
||||
X-KWin-Border-Activate=true
|
||||
+1
@@ -0,0 +1 @@
|
||||
kpackagetool6 --type KWin/Script --install .
|
||||
+56
@@ -0,0 +1,56 @@
|
||||
BSD 3‑Clause License
|
||||
|
||||
Copyright (c) 2019, Nikita Sorokovikov
|
||||
Copyright (c) 2025, MurderFromMars
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are met:
|
||||
|
||||
1. Redistributions of source code must retain the above copyright notice, this
|
||||
list of conditions and the following disclaimer.
|
||||
|
||||
2. Redistributions in binary form must reproduce the above copyright notice,
|
||||
this list of conditions and the following disclaimer in the documentation
|
||||
and/or other materials provided with the distribution.
|
||||
|
||||
3. Neither the name of the copyright holder nor the names of its
|
||||
contributors may be used to endorse or promote products derived from
|
||||
this software without specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
|
||||
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
||||
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
||||
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
|
||||
----------------------------------------------------------------------
|
||||
NOTICE — Modifications by MurderFromMars
|
||||
----------------------------------------------------------------------
|
||||
|
||||
This project is a fork of "dynamic_workspaces" by Nikita Sorokovikov (2019),
|
||||
licensed under the BSD 3‑Clause License.
|
||||
|
||||
A non‑exhaustive list of specific changes includes:
|
||||
|
||||
- Major rewrite of the compatibility layer to target Plasma 6 exclusively
|
||||
- Removal of all Plasma 5 logic, legacy APIs, and dual‑mode behavior
|
||||
- Introduction of a GNOME‑style dynamic workspace model
|
||||
- Automatic removal of all empty desktops except the last
|
||||
- Complete desktop renumbering system to maintain sequential ordering
|
||||
- Replacement of the original window‑shifting algorithm with simplified reassignment logic
|
||||
- New startup initialization logic enforcing GNOME workspace semantics
|
||||
- New startup redirection to ensure consistent initial desktop behavior
|
||||
- Rewritten event‑handling system for window addition, removal, and desktop changes
|
||||
- New cleanup system triggered on window removal, desktop switch, and client movement
|
||||
- Simplified and modernized desktop deletion logic
|
||||
- New helper functions: renumberDesktops, enforceGnomeModel, desktopIsEmpty, trimToMinimum
|
||||
- Rewritten onClientAdded and desktop‑change handling logic
|
||||
- Updated logging system and naming conventions
|
||||
- General restructuring, cleanup, and modernization of the codebase
|
||||
+52
@@ -0,0 +1,52 @@
|
||||
# Better Dynamic Workspaces #
|
||||
---
|
||||
|
||||
# Purpose of This Fork
|
||||
|
||||
The original script was created for Plasma 5, which used different APIs and session handling rules. Plasma 6 introduced new desktop management behavior, new virtual desktop APIs, and a different approach to session restoration. These changes made the original design harder to maintain and led to issues such as inconsistent numbering, restored clutter from previous sessions, and unpredictable startup desktops.
|
||||
|
||||
This fork focuses exclusively on Plasma 6 and rebuilds the concept around its modern architecture. The goal is to deliver a stable, predictable, GNOME style dynamic workspace system that behaves consistently across sessions and window events.
|
||||
|
||||
# Key Features
|
||||
|
||||
## Plasma 6 Native Codebase
|
||||
The script uses Plasma 6’s virtual desktop API directly. This removes the need for compatibility layers and allows the logic to be simpler, more reliable, and easier to maintain. Window events, desktop creation, and desktop removal all use Plasma 6’s native structures.
|
||||
|
||||
## GNOME Style Dynamic Workspace Model
|
||||
The workspace lifecycle follows the GNOME approach. The session always begins with two desktops. The user always starts on Desktop 1. A new desktop is created only when the last one becomes occupied. Empty desktops are removed automatically, and the final desktop is always kept empty. This creates a self maintaining layout that grows and shrinks naturally based on activity.
|
||||
|
||||
## Unified Cleanup System
|
||||
The original project used direction based cleanup and shifted windows to earlier desktops to maintain order. Plasma 6 made this approach less reliable. This fork replaces it with a single cleanup pass that runs after any structural change. It removes empty desktops, ensures the last desktop remains empty, and keeps the layout free of gaps. The cleanup is direction agnostic and does not shift windows, which makes the behavior consistent and predictable.
|
||||
|
||||
## Consistent Desktop Renumbering
|
||||
Desktops are always kept in sequential order. Renumbering happens automatically whenever desktops are added or removed. This keeps the pager, window manager, and internal logic aligned at all times.
|
||||
|
||||
## Predictable Startup Behavior
|
||||
The script ensures that every session begins in a clean state. The user always starts on Desktop 1. The session always begins with exactly two desktops. Plasma’s session restore behavior is bypassed so that old desktops are not recreated automatically.
|
||||
|
||||
---
|
||||
|
||||
# Comparison With the Original Project
|
||||
|
||||
| Feature | Original Project (maurges) | This Fork |
|
||||
|--------|-----------------------------|-----------|
|
||||
| Plasma 5 support | Yes | No |
|
||||
| Plasma 6 support | Partial | Full, native |
|
||||
| Startup desktops | Restores all from last session | Always 2 |
|
||||
| Startup focus | Last used desktop | Always Desktop 1 |
|
||||
| Desktop renumbering | No | Yes, always sequential |
|
||||
| Dynamic behavior | Basic | GNOME like |
|
||||
| Cleanup model | Direction based shift left logic | Unified GNOME style cleanup |
|
||||
| Workspace lifecycle | Mixed rules | Strictly append only |
|
||||
| Code complexity | Higher | Reduced, Plasma 6 only |
|
||||
| Window shifting | Required | Removed |
|
||||
| Session consistency | Variable | Deterministic |
|
||||
|
||||
# License
|
||||
|
||||
This fork maintains the BSD 3 license of the original project with proper attribution.
|
||||
|
||||
# Credits
|
||||
|
||||
Inspired by and built upon the original dynamic_workspaces by maurges, whose work established dynamic workspaces on KDE.
|
||||
|
||||
+239
@@ -0,0 +1,239 @@
|
||||
// Better Dynamic Workspaces
|
||||
|
||||
const MIN_DESKTOPS = 2;
|
||||
const LOG_LEVEL = 2; // 0 verbose, 1 debug, 2 normal
|
||||
|
||||
function log(...args) { print("[better_dynamic_ws]", ...args); }
|
||||
function debug(...args) { if (LOG_LEVEL <= 1) log(...args); }
|
||||
function trace(...args) { if (LOG_LEVEL <= 0) log(...args); }
|
||||
|
||||
let animationGuard = false;
|
||||
|
||||
/******** Plasma 6 Compatibility Layer ********/
|
||||
|
||||
const compat = {
|
||||
addDesktop: () => {
|
||||
workspace.createDesktop(workspace.desktops.length, undefined);
|
||||
},
|
||||
|
||||
windowAddedSignal: ws => ws.windowAdded,
|
||||
windowList: ws => ws.windowList(),
|
||||
|
||||
desktopChangedSignal: client => client.desktopsChanged,
|
||||
|
||||
toDesktop: d => d,
|
||||
|
||||
workspaceDesktops: () => workspace.desktops,
|
||||
|
||||
lastDesktop: () => workspace.desktops[workspace.desktops.length - 1],
|
||||
|
||||
deleteLastDesktop: () => {
|
||||
try {
|
||||
animationGuard = true;
|
||||
|
||||
const desktops = workspace.desktops;
|
||||
const last = desktops[desktops.length - 1];
|
||||
const current = workspace.currentDesktop;
|
||||
const idx = desktops.indexOf(current);
|
||||
|
||||
const fallback =
|
||||
idx + 1 < desktops.length || idx === -1
|
||||
? desktops[idx + 1]
|
||||
: current;
|
||||
|
||||
workspace.currentDesktop = fallback;
|
||||
workspace.removeDesktop(last);
|
||||
workspace.currentDesktop = current;
|
||||
} finally {
|
||||
animationGuard = false;
|
||||
}
|
||||
},
|
||||
|
||||
findDesktop: (list, d) => list.indexOf(d),
|
||||
|
||||
clientDesktops: c => c.desktops,
|
||||
|
||||
setClientDesktops: (c, ds) => { c.desktops = ds; },
|
||||
|
||||
clientOnDesktop: (c, d) => c.desktops.indexOf(d) !== -1,
|
||||
|
||||
desktopAmount: () => workspace.desktops.length,
|
||||
};
|
||||
|
||||
/******** Desktop Renumbering ********/
|
||||
|
||||
function renumberDesktops() {
|
||||
let count = compat.desktopAmount();
|
||||
|
||||
for (let i = 0; i < count; i++) {
|
||||
const desktops = compat.workspaceDesktops();
|
||||
const current = desktops[i];
|
||||
|
||||
if (desktops.indexOf(current) !== i) {
|
||||
compat.addDesktop();
|
||||
const newDesk = compat.lastDesktop();
|
||||
|
||||
compat.windowList(workspace).forEach(client => {
|
||||
if (compat.clientOnDesktop(client, current)) {
|
||||
const newList = compat.clientDesktops(client)
|
||||
.map(d => (d === current ? newDesk : d));
|
||||
compat.setClientDesktops(client, newList);
|
||||
}
|
||||
});
|
||||
|
||||
compat.deleteLastDesktop();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/******** GNOME‑Accurate Cleanup ********/
|
||||
|
||||
function desktopIsEmpty(idx) {
|
||||
const d = compat.workspaceDesktops()[idx];
|
||||
const clients = compat.windowList(workspace);
|
||||
|
||||
for (const c of clients) {
|
||||
if (
|
||||
compat.clientOnDesktop(c, d) &&
|
||||
!c.skipPager &&
|
||||
!c.onAllDesktops
|
||||
) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
function removeDesktop(idx) {
|
||||
const count = compat.desktopAmount();
|
||||
if (count - 1 <= idx) return false;
|
||||
if (count <= MIN_DESKTOPS) return false;
|
||||
|
||||
compat.windowList(workspace).forEach(c => {
|
||||
const cds = compat.clientDesktops(c);
|
||||
const all = compat.workspaceDesktops();
|
||||
const updated = cds.map(d => {
|
||||
const i = all.indexOf(d);
|
||||
return i > idx ? all[i - 1] : d;
|
||||
});
|
||||
compat.setClientDesktops(c, updated);
|
||||
});
|
||||
|
||||
compat.deleteLastDesktop();
|
||||
renumberDesktops();
|
||||
return true;
|
||||
}
|
||||
|
||||
/******** Unified GNOME Cleanup ********/
|
||||
|
||||
function enforceGnomeModel() {
|
||||
if (animationGuard) return;
|
||||
|
||||
animationGuard = true;
|
||||
try {
|
||||
const all = compat.workspaceDesktops();
|
||||
const lastIdx = all.length - 1;
|
||||
|
||||
// Remove all empty desktops except the last one
|
||||
for (let i = lastIdx - 1; i >= 0; i--) {
|
||||
if (desktopIsEmpty(i)) {
|
||||
removeDesktop(i);
|
||||
}
|
||||
}
|
||||
|
||||
// Ensure last desktop is empty
|
||||
const newLastIdx = compat.desktopAmount() - 1;
|
||||
if (!desktopIsEmpty(newLastIdx)) {
|
||||
compat.addDesktop();
|
||||
}
|
||||
|
||||
renumberDesktops();
|
||||
} finally {
|
||||
animationGuard = false;
|
||||
}
|
||||
}
|
||||
|
||||
/******** Core Behavior ********/
|
||||
|
||||
function handleClientDesktopChange(client) {
|
||||
if (compat.clientOnDesktop(client, compat.lastDesktop())) {
|
||||
compat.addDesktop();
|
||||
renumberDesktops();
|
||||
}
|
||||
enforceGnomeModel();
|
||||
}
|
||||
|
||||
function onClientAdded(client) {
|
||||
if (!client || client.skipPager) return;
|
||||
|
||||
if (compat.clientOnDesktop(client, compat.lastDesktop())) {
|
||||
compat.addDesktop();
|
||||
renumberDesktops();
|
||||
}
|
||||
|
||||
compat.desktopChangedSignal(client).connect(() => {
|
||||
handleClientDesktopChange(client);
|
||||
});
|
||||
|
||||
enforceGnomeModel();
|
||||
}
|
||||
|
||||
/******** Initialization ********/
|
||||
|
||||
function trimToMinimum() {
|
||||
while (compat.desktopAmount() > MIN_DESKTOPS) {
|
||||
try {
|
||||
compat.deleteLastDesktop();
|
||||
} catch (err) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
trimToMinimum();
|
||||
|
||||
(function setupInitialDesktops() {
|
||||
const ds = compat.workspaceDesktops();
|
||||
workspace.currentDesktop = ds[0];
|
||||
|
||||
while (compat.desktopAmount() > MIN_DESKTOPS) {
|
||||
try {
|
||||
compat.deleteLastDesktop();
|
||||
} catch (err) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (compat.desktopAmount() < MIN_DESKTOPS) {
|
||||
compat.addDesktop();
|
||||
}
|
||||
|
||||
renumberDesktops();
|
||||
})();
|
||||
|
||||
compat.windowList(workspace).forEach(onClientAdded);
|
||||
compat.windowAddedSignal(workspace).connect(onClientAdded);
|
||||
workspace.windowRemoved.connect(() => enforceGnomeModel());
|
||||
|
||||
workspace.currentDesktopChanged.connect(() => enforceGnomeModel());
|
||||
|
||||
// Startup redirect to enforce GNOME behavior.... might not be needed anymore tbh XD
|
||||
let initialRedirectDone = false;
|
||||
workspace.currentDesktopChanged.connect(function () {
|
||||
if (initialRedirectDone) return;
|
||||
initialRedirectDone = true;
|
||||
|
||||
const all = compat.workspaceDesktops();
|
||||
const currIdx = compat.findDesktop(all, workspace.currentDesktop);
|
||||
|
||||
if (currIdx === 1) {
|
||||
animationGuard = true;
|
||||
try {
|
||||
workspace.currentDesktop = all[0];
|
||||
} finally {
|
||||
animationGuard = false;
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
+21
@@ -0,0 +1,21 @@
|
||||
|
||||
{ "KPackageStructure": "KWin/Script"
|
||||
, "KPlugin":
|
||||
{ "Authors":
|
||||
[ { "Name": "Maurges, MurderFromMars" }
|
||||
]
|
||||
, "Description": "True Gnome Style Workspace Management"
|
||||
, "Icon": "preferences-system-windows-script-test"
|
||||
, "Id": "better_dynamic_workspaces"
|
||||
, "License": "BSD"
|
||||
, "Name": "Better Dynamic Workspaces"
|
||||
, "Version": "1.3"
|
||||
}
|
||||
, "X-KDE-PluginKeyword": "workspaces"
|
||||
|
||||
, "X-Plasma-API": "javascript"
|
||||
, "X-Plasma-API-Minimum-Version": "6.0"
|
||||
|
||||
, "X-KDE-Library": "kwin/effects/configs/kcm_kwin4_genericscripted"
|
||||
, "X-Plasma-MainScript": "code/main.js"
|
||||
}
|
||||
+14
@@ -0,0 +1,14 @@
|
||||
function isCSD(client) {
|
||||
return client.resourceClass == "gedit" || client.resourceClass == "nautilus" || client.resourceClass == "lollypop" || client.resourceClass == "gtg" || client.resourceClass == "totem" || client.resourceClass == "corebird" || client.resourceClass == "gnome-music" || client.resourceClass == "gnome-boxes" || client.resourceClass == "evince" || client.resourceClass == "baobab" || client.resourceClass == "epiphany" || client.resourceClass == "dconf-editor" || client.resourceClass == "file-roller" || client.resourceClass == "five-or-more" || client.resourceClass == "four-in-a-row" || client.resourceClass == "gnome-calculator" || client.resourceClass == "gnome-chess" || client.resourceClass == "gnome-clocks" || client.resourceClass == "gnome-contacts" || client.resourceClass == "gnome-control-center" || client.resourceClass == "gnome-dictionary" || client.resourceClass == "gnome-disks" || client.resourceClass == "gnome-builder" || client.resourceClass == "gnome-font-viewer" || client.resourceClass == "gnome-klotski" || client.resourceClass == "gnome-logs" || client.resourceClass == "gnome-mahjongg" || client.resourceClass == "gnome-mines" || client.resourceClass == "gnome-multi-writer" || client.resourceClass == "gnome-robots" || client.resourceClass == "gnome-sudoku" || client.resourceClass == "gnome-taquin" || client.resourceClass == "gnome-tetravex" || client.resourceClass == "gnome-usage" || client.resourceClass == "hitori" || client.resourceClass == "iagno" || client.resourceClass == "simple-scan" || client.resourceClass == "sysprof" || client.resourceClass == "notes-up" || client.resourceClass == "gnome-mpv" || client.resourceClass == "glade" || client.resourceClass == "eolie" || client.resourceClass == "gnome-calendar" || client.resourceClass == "gnome-todo" || client.resourceClass == "marker" || client.resourceClass == "pitivi" || client.resourceClass == "pamac-manager";
|
||||
}
|
||||
|
||||
|
||||
|
||||
function onClientAdded(client) {
|
||||
if (isCSD(client)) {
|
||||
client.noBorder = false;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
workspace.clientAdded.connect(onClientAdded);
|
||||
+22
@@ -0,0 +1,22 @@
|
||||
[Desktop Entry]
|
||||
Name=Force Decorations for GTK+ 3
|
||||
Comment=Adds KWin decorations to GTK's header bars
|
||||
Icon=preferences-system-windows-script-test
|
||||
|
||||
X-Plasma-API=javascript
|
||||
X-Plasma-MainScript=code/main.js
|
||||
|
||||
X-KDE-PluginInfo-Author=Jack Gandy
|
||||
X-KDE-PluginInfo-Email=scionicspectre@gmail.com
|
||||
X-KDE-PluginInfo-Name=force-decorations-gtk3
|
||||
X-KDE-PluginInfo-Version=0.1
|
||||
|
||||
X-KDE-PluginInfo-Depends=
|
||||
X-KDE-PluginInfo-License=GPL
|
||||
X-KDE-ServiceTypes=KWin/Script,KCModule
|
||||
|
||||
X-KDE-Library=kwin/effects/configs/kcm_kwin4_genericscripted
|
||||
X-KDE-PluginKeyword=force-decoration-gtk3
|
||||
X-KDE-ParentComponents=force-decoration-gtk3
|
||||
|
||||
Type=Service
|
||||
+21
@@ -0,0 +1,21 @@
|
||||
MIT License
|
||||
|
||||
Copyright (c) 2019 Eon S. Jeon <esjeon@hyunmu.am>
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
+67
@@ -0,0 +1,67 @@
|
||||
|
||||
Force Blur
|
||||
==========
|
||||
|
||||
A KWin script to force-enable KWin Blur effect on user-specified windows.
|
||||
|
||||

|
||||
|
||||
This is more useful than shell script hacks, because KWin script receives event
|
||||
notification and window info from KWin. This can also fix tray-based apps,
|
||||
which loses blur hints when restored from system tray.
|
||||
|
||||
|
||||
System Requirement
|
||||
------------------
|
||||
|
||||
* Operating System:
|
||||
- (K)Ubuntu 18.10 or newer
|
||||
- Fedora 29 or newer
|
||||
- Arch Linux - kwin 5.14 or newer
|
||||
|
||||
* Make sure you're using "Blur" desktop effect, which can be enabled through System Settings.
|
||||
|
||||
* This script internally calls `xprop` command, which would be already installed
|
||||
on your system.
|
||||
|
||||
* X11 display server (the script does not support wayland applications)
|
||||
|
||||
|
||||
How to Use
|
||||
----------
|
||||
|
||||
1. Install the script.
|
||||
|
||||
2. Run the following in terminal, to enable script configuration:
|
||||
|
||||
mkdir -p ~/.local/share/kservices5/
|
||||
cp ~/.local/share/kwin/scripts/forceblur/metadata.desktop ~/.local/share/kservices5/forceblur.desktop
|
||||
|
||||
3. Open `Kwin Scripts` page in `System Settings`.
|
||||
|
||||
4. Enable `Force Blur` script by checking the checkbox next to it.
|
||||
|
||||
5. Change script settings. Note that the script can only match with window classes.
|
||||
|
||||
6. Click `OK` to enable the script.
|
||||
|
||||
7. Whenever settings are changed, you must disable and re-enable the script.
|
||||
(Uncheck -> `Apply` -> Check -> `Apply`)
|
||||
|
||||
|
||||
GTK CSD Shadow
|
||||
--------------
|
||||
|
||||
Some GTK applications render client-side shadows, which look ugly if blurred. To
|
||||
prevent this, you can enable "**Blur only the content of window**" option.
|
||||
|
||||
This works by updating the blur region info whenever a window is resized, so
|
||||
might have some performance impacts. Use with caution.
|
||||
|
||||
|
||||
Authors
|
||||
-------
|
||||
|
||||
* Eon S. Jeon <esjeon@hyunmu.am> - main author
|
||||
* Aaron Miller (https://github.com/aaronm-cloudtek) - blacklist mode
|
||||
|
||||
+24
@@ -0,0 +1,24 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<kcfg xmlns="http://www.kde.org/standards/kcfg/1.0"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://www.kde.org/standards/kcfg/1.0
|
||||
http://www.kde.org/standards/kcfg/1.0/kcfg.xsd" >
|
||||
<kcfgfile name=""/>
|
||||
<group name="">
|
||||
<entry name="patterns" type="String">
|
||||
<label>Comma-separated list of window classes</label>
|
||||
<default>yakuake
|
||||
urxvt
|
||||
keepassxc</default>
|
||||
</entry>
|
||||
<entry name="blurMatching" type="Bool">
|
||||
<default>true</default>
|
||||
</entry>
|
||||
<entry name="blurExceptMatching" type="Bool">
|
||||
<default>false</default>
|
||||
</entry>
|
||||
<entry name="blurContent" type="Bool">
|
||||
<default>false</default>
|
||||
</entry>
|
||||
</group>
|
||||
</kcfg>
|
||||
+99
@@ -0,0 +1,99 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<ui version="4.0">
|
||||
<class>ForceBlurConfigForm</class>
|
||||
<widget class="QWidget" name="ForceBlurConfigForm">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>400</width>
|
||||
<height>400</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="minimumSize">
|
||||
<size>
|
||||
<width>400</width>
|
||||
<height>350</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="windowTitle">
|
||||
<string>Form</string>
|
||||
</property>
|
||||
<layout class="QVBoxLayout" name="verticalLayout_2">
|
||||
<item>
|
||||
<widget class="QGroupBox" name="groupMatching">
|
||||
<property name="title">
|
||||
<string>Window Matching</string>
|
||||
</property>
|
||||
<layout class="QVBoxLayout" name="layoutMatching">
|
||||
<item>
|
||||
<widget class="QLabel" name="labelMatching">
|
||||
<property name="whatsThis">
|
||||
<string><html><head/><body><p><span style=" font-weight:600;">&lt;&lt;Example&gt;&gt;</span></p><p>yakuake</p><p>keepassxc</p><p>urxvt</p></body></html></string>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string notr="true"><html><head/><body><p>Enter window class names, <span style=" text-decoration: underline;">one per line</span>.</p></body></html></string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QPlainTextEdit" name="kcfg_patterns">
|
||||
<property name="toolTip">
|
||||
<string><!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd">
|
||||
<html><head><meta name="qrichtext" content="1" /><style type="text/css">
|
||||
p, li { white-space: pre-wrap; }
|
||||
</style></head><body style=" font-family:'Fira Sans Book'; font-size:11pt; font-weight:232; font-style:normal;">
|
||||
<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Enter the class names of the windows you want to enable/disable blurring.</p>
|
||||
<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p>
|
||||
<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Class names can be obtained by using <span style=" font-weight:600;">xprop</span> utility in terminal. (xprop WM_CLASS)</p></body></html></string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<layout class="QHBoxLayout" name="layoutMatchingMode">
|
||||
<item>
|
||||
<widget class="QRadioButton" name="kcfg_blurMatching">
|
||||
<property name="text">
|
||||
<string>Blur only matching</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QRadioButton" name="kcfg_blurExceptMatching">
|
||||
<property name="text">
|
||||
<string>Blur all except matching</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QGroupBox" name="groupOptions">
|
||||
<property name="title">
|
||||
<string>Options</string>
|
||||
</property>
|
||||
<layout class="QVBoxLayout" name="verticalLayout">
|
||||
<item>
|
||||
<widget class="QCheckBox" name="kcfg_blurContent">
|
||||
<property name="toolTip">
|
||||
<string><html><head/><body><p>Enabling this option prevents blurring behind the non-content regions of window, like <span style=" font-weight:600;">CSD shadows in GTK</span>.</p><p>This <span style=" text-decoration: underline;">might</span> cause performance issues and flickers, thus users should be careful about turning this on.</p></body></html></string>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Blur only the content of window</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
<resources/>
|
||||
<connections/>
|
||||
<buttongroups>
|
||||
<buttongroup name="matchTypeGroup"/>
|
||||
</buttongroups>
|
||||
</ui>
|
||||
+100
@@ -0,0 +1,100 @@
|
||||
import QtQuick 2.0
|
||||
import org.kde.plasma.core 2.0 as PlasmaCore;
|
||||
import org.kde.plasma.components 2.0 as Plasma;
|
||||
import org.kde.kwin 2.0;
|
||||
|
||||
Item {
|
||||
id: root
|
||||
|
||||
readonly property var patterns: (
|
||||
KWin.readConfig("patterns", "yakuake\nurxvt\nkeepassxc")
|
||||
.split("\n")
|
||||
.map(function(rule) {
|
||||
return rule.trim().toLowerCase();
|
||||
})
|
||||
)
|
||||
|
||||
readonly property var blurMatching: (
|
||||
KWin.readConfig("blurMatching", true)
|
||||
)
|
||||
|
||||
readonly property var blurContent: (
|
||||
KWin.readConfig("blurContent", false)
|
||||
)
|
||||
|
||||
PlasmaCore.DataSource {
|
||||
id: shell
|
||||
engine: 'executable'
|
||||
|
||||
connectedSources: []
|
||||
|
||||
function run(cmd) {
|
||||
shell.connectSource(cmd);
|
||||
}
|
||||
|
||||
onNewData: {
|
||||
shell.disconnectSource(sourceName);
|
||||
}
|
||||
}
|
||||
|
||||
function onClientAdded(client) {
|
||||
if (!shell) return;
|
||||
|
||||
var cls = client.resourceClass.toString().toLowerCase();
|
||||
var name = client.resourceName.toString().toLowerCase();
|
||||
var clsMatches = root.patterns.indexOf(cls) >= 0 || root.patterns.indexOf(name) >= 0;
|
||||
|
||||
if (clsMatches == root.blurMatching) {
|
||||
if (root.blurContent) {
|
||||
registerHintUpdater(client);
|
||||
} else {
|
||||
var wid = "0x" + client.windowId.toString(16);
|
||||
shell.run("xprop -f _KDE_NET_WM_BLUR_BEHIND_REGION 32c -set _KDE_NET_WM_BLUR_BEHIND_REGION 0 -id " + wid);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function registerHintUpdater(client) {
|
||||
var prevWidth = client.geometry.width;
|
||||
var prevHeight = client.geometry.height;
|
||||
var handler = function() {
|
||||
try { if (!root) return; } catch(e) {
|
||||
client.geometryChanged.disconnect(handler);
|
||||
throw e;
|
||||
}
|
||||
|
||||
root.onClientGeometryChanged(client, prevWidth, prevHeight);
|
||||
|
||||
prevWidth = client.geometry.width;
|
||||
prevHeight = client.geometry.height;
|
||||
}
|
||||
|
||||
client.geometryChanged.connect(handler);
|
||||
root.onClientGeometryChanged(client, 0, 0);
|
||||
}
|
||||
|
||||
function onClientGeometryChanged(client, prevWidth, prevHeight) {
|
||||
if (!shell) return;
|
||||
|
||||
/* Skip if window *size* isn't really changed */
|
||||
if (client.geometry.width === prevWidth && client.geometry.height === prevHeight)
|
||||
return;
|
||||
|
||||
var wid = "0x" + client.windowId.toString(16);
|
||||
var region = "0,0," + client.geometry.width + "," + client.geometry.height;
|
||||
var cmd = "xprop -id " + wid + " -f _KDE_NET_WM_BLUR_BEHIND_REGION 32c -set _KDE_NET_WM_BLUR_BEHIND_REGION " + region
|
||||
shell.run(cmd);
|
||||
}
|
||||
|
||||
Component.onCompleted: {
|
||||
console.log("FORCE-BLUR: starting the script");
|
||||
console.log(JSON.stringify(root.patterns));
|
||||
|
||||
var clients = workspace.clientList();
|
||||
for (var i = 0; i < clients.length; i++) {
|
||||
root.onClientAdded(clients[i]);
|
||||
}
|
||||
|
||||
workspace.onClientAdded.connect(root.onClientAdded);
|
||||
}
|
||||
}
|
||||
+18
@@ -0,0 +1,18 @@
|
||||
[Desktop Entry]
|
||||
Name=Force Blur
|
||||
Comment=Force-enable Blur effect for certain windows
|
||||
Icon=preferences-system-windows-script-test
|
||||
|
||||
X-Plasma-API=declarativescript
|
||||
X-Plasma-MainScript=ui/main.qml
|
||||
|
||||
X-KDE-PluginInfo-Author=Eon S. Jeon
|
||||
X-KDE-PluginInfo-Email=esjeon@hyunmu.am
|
||||
X-KDE-PluginInfo-Name=forceblur
|
||||
X-KDE-PluginInfo-Version=0.6
|
||||
X-KDE-PluginInfo-License=MIT
|
||||
|
||||
Type=Service
|
||||
X-KDE-ServiceTypes=KWin/Script
|
||||
|
||||
X-KDE-ConfigModule=kwin/effects/configs/kcm_kwin4_genericscripted
|
||||
+3766
File diff suppressed because it is too large
Load Diff
+148
@@ -0,0 +1,148 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<kcfg xmlns="http://www.kde.org/standards/kcfg/1.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.kde.org/standards/kcfg/1.0 http://www.kde.org/standards/kcfg/1.0/kcfg.xsd">
|
||||
<kcfgfile name="kwinrc" />
|
||||
<group name="">
|
||||
<entry name="gapsOuterTop" type="UInt">
|
||||
<default>16</default>
|
||||
</entry>
|
||||
<entry name="gapsOuterBottom" type="UInt">
|
||||
<default>16</default>
|
||||
</entry>
|
||||
<entry name="gapsOuterLeft" type="UInt">
|
||||
<default>16</default>
|
||||
</entry>
|
||||
<entry name="gapsOuterRight" type="UInt">
|
||||
<default>16</default>
|
||||
</entry>
|
||||
<entry name="gapsInnerHorizontal" type="UInt">
|
||||
<default>8</default>
|
||||
</entry>
|
||||
<entry name="gapsInnerVertical" type="UInt">
|
||||
<default>8</default>
|
||||
</entry>
|
||||
<entry name="stackOffsetX" type="UInt">
|
||||
<default>8</default>
|
||||
</entry>
|
||||
<entry name="stackOffsetY" type="UInt">
|
||||
<default>32</default>
|
||||
</entry>
|
||||
<entry name="manualScrollStep" type="UInt">
|
||||
<default>200</default>
|
||||
</entry>
|
||||
<entry name="presetWidths" type="String">
|
||||
<default>50%, 100%</default>
|
||||
</entry>
|
||||
<entry name="offScreenOpacity" type="UInt">
|
||||
<default>100</default>
|
||||
</entry>
|
||||
<entry name="untileOnDrag" type="Bool">
|
||||
<default>true</default>
|
||||
</entry>
|
||||
<entry name="cursorFollowsFocus" type="Bool">
|
||||
<default>false</default>
|
||||
</entry>
|
||||
<entry name="stackColumnsByDefault" type="Bool">
|
||||
<default>false</default>
|
||||
</entry>
|
||||
<entry name="resizeNeighborColumn" type="Bool">
|
||||
<default>false</default>
|
||||
</entry>
|
||||
<entry name="reMaximize" type="Bool">
|
||||
<default>false</default>
|
||||
</entry>
|
||||
<entry name="skipSwitcher" type="Bool">
|
||||
<default>false</default>
|
||||
</entry>
|
||||
<entry name="scrollingLazy" type="Bool">
|
||||
<default>true</default>
|
||||
</entry>
|
||||
<entry name="scrollingCentered" type="Bool">
|
||||
<default>false</default>
|
||||
</entry>
|
||||
<entry name="scrollingGrouped" type="Bool">
|
||||
<default>false</default>
|
||||
</entry>
|
||||
<entry name="gestureScroll" type="Bool">
|
||||
<default>false</default>
|
||||
</entry>
|
||||
<entry name="gestureScrollInvert" type="Bool">
|
||||
<default>false</default>
|
||||
</entry>
|
||||
<entry name="gestureScrollStep" type="UInt">
|
||||
<default>1920</default>
|
||||
</entry>
|
||||
<entry name="tiledKeepBelow" type="Bool">
|
||||
<default>true</default>
|
||||
</entry>
|
||||
<entry name="floatingKeepAbove" type="Bool">
|
||||
<default>false</default>
|
||||
</entry>
|
||||
<entry name="noLayering" type="Bool">
|
||||
<default>false</default>
|
||||
</entry>
|
||||
<entry name="windowRules" type="String">
|
||||
<default>[
|
||||
{
|
||||
"class": "(org\\.kde\\.)?plasmashell",
|
||||
"tile": false
|
||||
},
|
||||
{
|
||||
"class": "(org\\.kde\\.)?polkit-kde-authentication-agent-1",
|
||||
"tile": false
|
||||
},
|
||||
{
|
||||
"class": "(org\\.kde\\.)?kded6",
|
||||
"tile": false
|
||||
},
|
||||
{
|
||||
"class": "(org\\.kde\\.)?kcalc",
|
||||
"tile": false
|
||||
},
|
||||
{
|
||||
"class": "(org\\.kde\\.)?kfind",
|
||||
"tile": true
|
||||
},
|
||||
{
|
||||
"class": "(org\\.kde\\.)?kruler",
|
||||
"tile": false
|
||||
},
|
||||
{
|
||||
"class": "(org\\.kde\\.)?krunner",
|
||||
"tile": false
|
||||
},
|
||||
{
|
||||
"class": "(org\\.kde\\.)?yakuake",
|
||||
"tile": false
|
||||
},
|
||||
{
|
||||
"class": "wl-copy|wl-paste",
|
||||
"caption": "wl-clipboard",
|
||||
"tile": false
|
||||
},
|
||||
{
|
||||
"class": "steam",
|
||||
"caption": "Steam Big Picture Mode",
|
||||
"tile": false
|
||||
},
|
||||
{
|
||||
"class": "zoom",
|
||||
"caption": "Zoom Cloud Meetings|zoom|zoom <2>",
|
||||
"tile": false
|
||||
},
|
||||
{
|
||||
"class": "jetbrains-.*",
|
||||
"caption": "splash",
|
||||
"tile": false
|
||||
},
|
||||
{
|
||||
"class": "jetbrains-.*",
|
||||
"caption": "Unstash Changes|Paths Affected by stash@.*",
|
||||
"tile": true
|
||||
}
|
||||
]</default>
|
||||
</entry>
|
||||
<entry name="tiledDesktops" type="String">
|
||||
<default>.*</default>
|
||||
</entry>
|
||||
</group>
|
||||
</kcfg>
|
||||
+510
@@ -0,0 +1,510 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<ui version="4.0">
|
||||
<class>KWin::KarouselConfigForm</class>
|
||||
<widget class="QWidget" name="KWin::KarouselConfigForm">
|
||||
<property name="windowTitle">
|
||||
<string>Karousel</string>
|
||||
</property>
|
||||
<property name="autoFillBackground">
|
||||
<bool>false</bool>
|
||||
</property>
|
||||
<layout class="QVBoxLayout" name="layout_main">
|
||||
<item>
|
||||
<widget class="QTabWidget" name="tabContainer">
|
||||
<widget class="QWidget" name="tab_behavior">
|
||||
<attribute name="title">
|
||||
<string>Behavior</string>
|
||||
</attribute>
|
||||
<layout class="QVBoxLayout">
|
||||
<item>
|
||||
<widget class="QGroupBox">
|
||||
<property name="flat">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
<layout class="QVBoxLayout">
|
||||
<item>
|
||||
<widget class="QCheckBox" name="kcfg_untileOnDrag">
|
||||
<property name="text">
|
||||
<string>Un-tile windows by dragging them</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QCheckBox" name="kcfg_cursorFollowsFocus">
|
||||
<property name="text">
|
||||
<string>Cursor follows focus (experimental)</string>
|
||||
</property>
|
||||
<property name="toolTip">
|
||||
<string>When a window gains focus, move the cursor to it</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QCheckBox" name="kcfg_stackColumnsByDefault">
|
||||
<property name="text">
|
||||
<string>Stack columns by default</string>
|
||||
</property>
|
||||
<property name="toolTip">
|
||||
<string>New columns start in stacked mode (only the active window visible)</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QCheckBox" name="kcfg_resizeNeighborColumn">
|
||||
<property name="text">
|
||||
<string>Resize neighbor column on edge resize</string>
|
||||
</property>
|
||||
<property name="toolTip">
|
||||
<string>When resizing a column by dragging its edge, also inversely resize the column on the other side of the edge</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QCheckBox" name="kcfg_reMaximize">
|
||||
<property name="text">
|
||||
<string>Re-maximize tiled windows</string>
|
||||
</property>
|
||||
<property name="toolTip">
|
||||
<string>Restore maximized and full-screen states of tiled windows on focus</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QCheckBox" name="kcfg_skipSwitcher">
|
||||
<property name="text">
|
||||
<string>Tiled windows skip switcher</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
|
||||
<item>
|
||||
<widget class="QGroupBox">
|
||||
<property name="title">
|
||||
<string>Scrolling mode</string>
|
||||
</property>
|
||||
<layout class="QVBoxLayout">
|
||||
<item>
|
||||
<widget class="QRadioButton" name="kcfg_scrollingLazy">
|
||||
<property name="text">
|
||||
<string>Only scroll as necessary</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QRadioButton" name="kcfg_scrollingCentered">
|
||||
<property name="text">
|
||||
<string>Center focused column</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QRadioButton" name="kcfg_scrollingGrouped">
|
||||
<property name="text">
|
||||
<string>Center visible columns</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
|
||||
<item>
|
||||
<widget class="QGroupBox">
|
||||
<property name="title">
|
||||
<string>Touchpad scrolling (Wayland only)</string>
|
||||
</property>
|
||||
<layout class="QVBoxLayout">
|
||||
<item>
|
||||
<widget class="QCheckBox" name="kcfg_gestureScroll">
|
||||
<property name="text">
|
||||
<string>Enable scrolling with touchpad gestures
|
||||
(please don't forget to disable KDE's workspace switching gestures)</string>
|
||||
</property>
|
||||
<property name="toolTip">
|
||||
<string>Scroll with a three-finger horizontal swipe gesture</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
|
||||
<item>
|
||||
<widget class="QCheckBox" name="kcfg_gestureScrollInvert">
|
||||
<property name="text">
|
||||
<string>Invert scroll direction (Natural scrolling)</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
|
||||
<item>
|
||||
<widget class="QGroupBox">
|
||||
<property name="title">
|
||||
<string>Layering mode</string>
|
||||
</property>
|
||||
<layout class="QVBoxLayout">
|
||||
<item>
|
||||
<widget class="QRadioButton" name="kcfg_tiledKeepBelow">
|
||||
<property name="text">
|
||||
<string>Set "Keep Below" for tiled windows</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QRadioButton" name="kcfg_floatingKeepAbove">
|
||||
<property name="text">
|
||||
<string>Set "Keep Above" for floating windows</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QRadioButton" name="kcfg_noLayering">
|
||||
<property name="text">
|
||||
<string>No layering</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
|
||||
<item>
|
||||
<spacer name="spacer_footer">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Vertical</enum>
|
||||
</property>
|
||||
<property name="sizeHint" stdset="0">
|
||||
<size>
|
||||
<width>0</width>
|
||||
<height>0</height>
|
||||
</size>
|
||||
</property>
|
||||
</spacer>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
|
||||
<widget class="QWidget" name="tab_parameters">
|
||||
<attribute name="title">
|
||||
<string>Parameters</string>
|
||||
</attribute>
|
||||
<layout class="QFormLayout">
|
||||
<item row="0" column="0">
|
||||
<widget class="QLabel" name="label_gapsOuterTop">
|
||||
<property name="text">
|
||||
<string>Top margin:</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="1">
|
||||
<widget class="QSpinBox" name="kcfg_gapsOuterTop">
|
||||
<property name="suffix">
|
||||
<string> px</string>
|
||||
</property>
|
||||
<property name="maximum">
|
||||
<number>999</number>
|
||||
</property>
|
||||
<property name="value">
|
||||
<number>0</number>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
|
||||
<item row="1" column="0">
|
||||
<widget class="QLabel" name="label_gapsOuterBottom">
|
||||
<property name="text">
|
||||
<string>Bottom margin:</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="1">
|
||||
<widget class="QSpinBox" name="kcfg_gapsOuterBottom">
|
||||
<property name="suffix">
|
||||
<string> px</string>
|
||||
</property>
|
||||
<property name="maximum">
|
||||
<number>999</number>
|
||||
</property>
|
||||
<property name="value">
|
||||
<number>0</number>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
|
||||
<item row="2" column="0">
|
||||
<widget class="QLabel" name="label_gapsOuterLeft">
|
||||
<property name="text">
|
||||
<string>Left margin:</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="2" column="1">
|
||||
<widget class="QSpinBox" name="kcfg_gapsOuterLeft">
|
||||
<property name="suffix">
|
||||
<string> px</string>
|
||||
</property>
|
||||
<property name="maximum">
|
||||
<number>999</number>
|
||||
</property>
|
||||
<property name="value">
|
||||
<number>0</number>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
|
||||
<item row="3" column="0">
|
||||
<widget class="QLabel" name="label_gapsOuterRight">
|
||||
<property name="text">
|
||||
<string>Right margin:</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="3" column="1">
|
||||
<widget class="QSpinBox" name="kcfg_gapsOuterRight">
|
||||
<property name="suffix">
|
||||
<string> px</string>
|
||||
</property>
|
||||
<property name="maximum">
|
||||
<number>999</number>
|
||||
</property>
|
||||
<property name="value">
|
||||
<number>0</number>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
|
||||
<item row="4" column="0">
|
||||
<widget class="QLabel" name="label_gapsInnerHorizontal">
|
||||
<property name="text">
|
||||
<string>Horizontal gaps between windows:</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="4" column="1">
|
||||
<widget class="QSpinBox" name="kcfg_gapsInnerHorizontal">
|
||||
<property name="suffix">
|
||||
<string> px</string>
|
||||
</property>
|
||||
<property name="maximum">
|
||||
<number>999</number>
|
||||
</property>
|
||||
<property name="value">
|
||||
<number>0</number>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
|
||||
<item row="5" column="0">
|
||||
<widget class="QLabel" name="label_gapsInnerVertical">
|
||||
<property name="text">
|
||||
<string>Vertical gaps between windows:</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="5" column="1">
|
||||
<widget class="QSpinBox" name="kcfg_gapsInnerVertical">
|
||||
<property name="suffix">
|
||||
<string> px</string>
|
||||
</property>
|
||||
<property name="maximum">
|
||||
<number>999</number>
|
||||
</property>
|
||||
<property name="value">
|
||||
<number>0</number>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
|
||||
<item row="6" column="0">
|
||||
<widget class="QLabel" name="label_stackOffsetX">
|
||||
<property name="text">
|
||||
<string>Horizontal offset for stacked columns:</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="6" column="1">
|
||||
<widget class="QSpinBox" name="kcfg_stackOffsetX">
|
||||
<property name="suffix">
|
||||
<string> px</string>
|
||||
</property>
|
||||
<property name="maximum">
|
||||
<number>999</number>
|
||||
</property>
|
||||
<property name="value">
|
||||
<number>0</number>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
|
||||
<item row="7" column="0">
|
||||
<widget class="QLabel" name="label_stackOffsetY">
|
||||
<property name="text">
|
||||
<string>Vertical offset for stacked columns:</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="7" column="1">
|
||||
<widget class="QSpinBox" name="kcfg_stackOffsetY">
|
||||
<property name="suffix">
|
||||
<string> px</string>
|
||||
</property>
|
||||
<property name="maximum">
|
||||
<number>999</number>
|
||||
</property>
|
||||
<property name="value">
|
||||
<number>0</number>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
|
||||
<item row="8" column="0">
|
||||
<widget class="QLabel" name="label_manualScrollStep">
|
||||
<property name="text">
|
||||
<string>Manual scroll step size:</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="8" column="1">
|
||||
<widget class="QSpinBox" name="kcfg_manualScrollStep">
|
||||
<property name="suffix">
|
||||
<string> px</string>
|
||||
</property>
|
||||
<property name="maximum">
|
||||
<number>999</number>
|
||||
</property>
|
||||
<property name="value">
|
||||
<number>0</number>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
|
||||
<item row="9" column="0">
|
||||
<widget class="QLabel" name="label_gestureScrollStep">
|
||||
<property name="text">
|
||||
<string>Touchpad gesture scrolling speed:</string>
|
||||
</property>
|
||||
<property name="toolTip">
|
||||
<string>The amount to scroll per edge-to-edge gesture</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="9" column="1">
|
||||
<widget class="QSpinBox" name="kcfg_gestureScrollStep">
|
||||
<property name="suffix">
|
||||
<string> px</string>
|
||||
</property>
|
||||
<property name="maximum">
|
||||
<number>10000</number>
|
||||
</property>
|
||||
<property name="minimum">
|
||||
<number>100</number>
|
||||
</property>
|
||||
<property name="singleStep">
|
||||
<number>100</number>
|
||||
</property>
|
||||
<property name="value">
|
||||
<number>1920</number>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
|
||||
<item row="10" column="0">
|
||||
<widget class="QLabel" name="label_presetWidths">
|
||||
<property name="text">
|
||||
<string>Preset widths:</string>
|
||||
</property>
|
||||
<property name="toolTip">
|
||||
<string>Widths used for cycling through widths</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="10" column="1">
|
||||
<widget class="QLineEdit" name="kcfg_presetWidths">
|
||||
<property name="toolTip">
|
||||
<string>Comma-separated list of widths. Supported units: "px" and "%".</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
|
||||
<item row="11" column="0">
|
||||
<widget class="QLabel" name="label_offScreenOpacity">
|
||||
<property name="text">
|
||||
<string>Obscured window opacity:</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="11" column="1">
|
||||
<widget class="QSpinBox" name="kcfg_offScreenOpacity">
|
||||
<property name="suffix">
|
||||
<string> %</string>
|
||||
</property>
|
||||
<property name="maximum">
|
||||
<number>100</number>
|
||||
</property>
|
||||
<property name="value">
|
||||
<number>0</number>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
|
||||
</layout>
|
||||
</widget>
|
||||
|
||||
<widget class="QWidget" name="tab_windowRules">
|
||||
<attribute name="title">
|
||||
<string>Window Rules</string>
|
||||
</attribute>
|
||||
<layout class="QVBoxLayout">
|
||||
<item>
|
||||
<layout class="QHBoxLayout">
|
||||
<item>
|
||||
<widget class="QLabel" name="label_desktops">
|
||||
<property name="text">
|
||||
<string>Tiled desktops:</string>
|
||||
</property>
|
||||
<property name="wordWrap">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QLineEdit" name="kcfg_tiledDesktops">
|
||||
<property name="toolTip">
|
||||
<string>Regex string to match desktops by desktop name"</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QPlainTextEdit" name="kcfg_windowRules">
|
||||
<property name="tabChangesFocus">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
<property name="lineWrapMode">
|
||||
<enum>QPlainTextEdit::NoWrap</enum>
|
||||
</property>
|
||||
<property name="font">
|
||||
<font><family>Monospace</family></font>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QLabel" name="label">
|
||||
<property name="text">
|
||||
<string>Karousel script needs to be restarted for changes to take effect.</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
<resources/>
|
||||
<connections/>
|
||||
</ui>
|
||||
+73
@@ -0,0 +1,73 @@
|
||||
import QtQuick 6.0
|
||||
import org.kde.kwin 3.0
|
||||
import org.kde.notification 1.0
|
||||
import "../code/main.js" as Karousel
|
||||
|
||||
Item {
|
||||
id: qmlBase
|
||||
|
||||
property var karouselInstance
|
||||
|
||||
Component.onCompleted: {
|
||||
qmlBase.karouselInstance = Karousel.init();
|
||||
}
|
||||
|
||||
Component.onDestruction: {
|
||||
qmlBase.karouselInstance.destroy();
|
||||
}
|
||||
|
||||
Notification {
|
||||
id: notificationInvalidTiledDesktops
|
||||
componentName: "plasma_workspace"
|
||||
eventId: "notification"
|
||||
title: "Karousel"
|
||||
text: "Your Tiled Desktops regex is malformed, please review your Karousel configuration"
|
||||
flags: Notification.Persistent
|
||||
urgency: Notification.HighUrgency
|
||||
}
|
||||
|
||||
Notification {
|
||||
id: notificationInvalidWindowRules
|
||||
componentName: "plasma_workspace"
|
||||
eventId: "notification"
|
||||
title: "Karousel"
|
||||
text: "Your Window Rules JSON is malformed, please review your Karousel configuration"
|
||||
flags: Notification.Persistent
|
||||
urgency: Notification.HighUrgency
|
||||
}
|
||||
|
||||
Notification {
|
||||
id: notificationInvalidPresetWidths
|
||||
componentName: "plasma_workspace"
|
||||
eventId: "notification"
|
||||
title: "Karousel"
|
||||
text: "Your preset widths are malformed, please review your Karousel configuration"
|
||||
flags: Notification.Persistent
|
||||
urgency: Notification.HighUrgency
|
||||
}
|
||||
|
||||
SwipeGestureHandler {
|
||||
direction: SwipeGestureHandler.Direction.Left
|
||||
fingerCount: 3
|
||||
onActivated: qmlBase.karouselInstance.gestureScrollFinish()
|
||||
onCancelled: qmlBase.karouselInstance.gestureScrollFinish()
|
||||
onProgressChanged: qmlBase.karouselInstance.gestureScroll(-progress)
|
||||
}
|
||||
|
||||
SwipeGestureHandler {
|
||||
direction: SwipeGestureHandler.Direction.Right
|
||||
fingerCount: 3
|
||||
onActivated: qmlBase.karouselInstance.gestureScrollFinish()
|
||||
onCancelled: qmlBase.karouselInstance.gestureScrollFinish()
|
||||
onProgressChanged: qmlBase.karouselInstance.gestureScroll(progress)
|
||||
}
|
||||
|
||||
DBusCall {
|
||||
id: moveCursorToFocus
|
||||
|
||||
service: "org.kde.kglobalaccel"
|
||||
path: "/component/kwin"
|
||||
method: "invokeShortcut"
|
||||
arguments: ["MoveMouseToFocus"]
|
||||
}
|
||||
}
|
||||
+23
@@ -0,0 +1,23 @@
|
||||
{
|
||||
"KPackageStructure": "KWin/Script",
|
||||
"KPlugin": {
|
||||
"Name": "Karousel",
|
||||
"Description": "Scrollable tiling extension for KWin",
|
||||
"Icon": "preferences-system-windows",
|
||||
"Authors": [
|
||||
{
|
||||
"Email": "peter.fajdiga@gmail.com",
|
||||
"Name": "Peter Fajdiga"
|
||||
}
|
||||
],
|
||||
"Id": "karousel",
|
||||
"Version": "0.16",
|
||||
"License": "GPLv3",
|
||||
"Website": "https://github.com/peterfajdiga/karousel",
|
||||
"BugReportUrl": "https://github.com/peterfajdiga/karousel/issues"
|
||||
},
|
||||
"X-Plasma-API": "declarativescript",
|
||||
"X-Plasma-API-Minimum-Version": "6.0",
|
||||
"X-Plasma-MainScript": "ui/main.qml",
|
||||
"X-KDE-ConfigModule": "kwin/effects/configs/kcm_kwin4_genericscripted"
|
||||
}
|
||||
+1
@@ -0,0 +1 @@
|
||||
print("KWin need me. Don't ask why.");
|
||||
+5229
File diff suppressed because it is too large
Load Diff
+448
@@ -0,0 +1,448 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<kcfg xmlns="http://www.kde.org/standards/kcfg/1.0"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://www.kde.org/standards/kcfg/1.0
|
||||
http://www.kde.org/standards/kcfg/1.0/kcfg.xsd" >
|
||||
<kcfgfile name=""/>
|
||||
<group name="">
|
||||
|
||||
<entry name="dockOrderLeft" type="Int">
|
||||
<label>The order of the docked window in the dock</label>
|
||||
<default>1</default>
|
||||
</entry>
|
||||
|
||||
<entry name="dockOrderTop" type="Int">
|
||||
<label>The order of the docked window in the dock</label>
|
||||
<default>2</default>
|
||||
</entry>
|
||||
|
||||
<entry name="dockOrderRight" type="Int">
|
||||
<label>The order of the docked window in the dock</label>
|
||||
<default>3</default>
|
||||
</entry>
|
||||
|
||||
<entry name="dockOrderBottom" type="Int">
|
||||
<label>The order of the docked window in the dock</label>
|
||||
<default>4</default>
|
||||
</entry>
|
||||
|
||||
<entry name="dockHHeight" type="Int">
|
||||
<label>The default height of a horizontal docked window in percent</label>
|
||||
<default>15</default>
|
||||
</entry>
|
||||
|
||||
<entry name="dockHWide" type="Int">
|
||||
<label>The default width of a horizontal docked window in percent</label>
|
||||
<default>100</default>
|
||||
</entry>
|
||||
|
||||
<entry name="dockHGap" type="Int">
|
||||
<label>The default Gap of a horizontal docked window in pixels</label>
|
||||
<default>0</default>
|
||||
</entry>
|
||||
|
||||
<entry name="dockHEdgeGap" type="Int">
|
||||
<label>The default Vertical Gap of a horizontal docked window in pixels</label>
|
||||
<default>0</default>
|
||||
</entry>
|
||||
|
||||
<entry name="dockHAlignment" type="Int">
|
||||
<label>The default Alignment of a horizontal docked window which can be Center , Left, Right</label>
|
||||
<default>0</default>
|
||||
</entry>
|
||||
|
||||
<entry name="dockHEdgeAlignment" type="Int">
|
||||
<label>The default vertical Alignment of a horizontal docked window which can be Edge Screen, Middle, Center Screen</label>
|
||||
<default>0</default>
|
||||
</entry>
|
||||
|
||||
<entry name="dockVHeight" type="Int">
|
||||
<label>The default height of a vertical docked window in percent</label>
|
||||
<default>100</default>
|
||||
</entry>
|
||||
|
||||
<entry name="dockVWide" type="Int">
|
||||
<label>The default width of a vertical docked window in percent</label>
|
||||
<default>15</default>
|
||||
</entry>
|
||||
|
||||
<entry name="dockVEdgeGap" type="Int">
|
||||
<label>The default horizontal Gap of a vertical docked window in pixels</label>
|
||||
<default>0</default>
|
||||
</entry>
|
||||
|
||||
<entry name="dockVGap" type="Int">
|
||||
<label>The default Gap of a vertical docked window in pixels</label>
|
||||
<default>0</default>
|
||||
</entry>
|
||||
|
||||
<entry name="dockVEdgeAlignment" type="Int">
|
||||
<label>The default horizontal Alignment of a vertical docked window which can be Edge Screen, Middle or Center Screen</label>
|
||||
<default>0</default>
|
||||
</entry>
|
||||
|
||||
<entry name="dockVAlignment" type="Int">
|
||||
<label>The default vertical Alignment of a vertical docked window which can be Center, Top, Bottom</label>
|
||||
<default>0</default>
|
||||
</entry>
|
||||
|
||||
<entry name="dockSurfacesConfig" type="String">
|
||||
<label>Dock settings change the default parameters for the surface</label>
|
||||
<default></default>
|
||||
</entry>
|
||||
|
||||
<entry name="dockWindowClassConfig" type="String">
|
||||
<label>Dock default settings for WindowClass which with high priority.</label>
|
||||
<default></default>
|
||||
</entry>
|
||||
|
||||
<entry name="tileLayoutOrder" type="Int">
|
||||
<label> Tile layout order</label>
|
||||
<default>1</default>
|
||||
</entry>
|
||||
|
||||
<entry name="tileLayoutInitialRotationAngle" type="String">
|
||||
<label>Tile layout initial rotation angle</label>
|
||||
<default>0</default>
|
||||
</entry>
|
||||
<entry name="monocleLayoutOrder" type="Int">
|
||||
<label> Monocle layout order</label>
|
||||
<default>2</default>
|
||||
</entry>
|
||||
|
||||
<entry name="threeColumnLayoutOrder" type="Int">
|
||||
<label> Three Column layout order</label>
|
||||
<default>3</default>
|
||||
</entry>
|
||||
|
||||
<entry name="spiralLayoutOrder" type="Int">
|
||||
<label> Spiral layout order</label>
|
||||
<default>4</default>
|
||||
</entry>
|
||||
|
||||
<entry name="quarterLayoutOrder" type="Int">
|
||||
<label> Quarter layout order</label>
|
||||
<default>5</default>
|
||||
</entry>
|
||||
<entry name="quarterLayoutReset" type="Bool">
|
||||
<label>Reset Quarter layout after closing a window</label>
|
||||
<default>false</default>
|
||||
</entry>
|
||||
|
||||
<entry name="stackedLayoutOrder" type="Int">
|
||||
<label> Stacked layout order</label>
|
||||
<default>6</default>
|
||||
</entry>
|
||||
|
||||
<entry name="columnsLayoutOrder" type="Int">
|
||||
<label> Columns layout order</label>
|
||||
<default>7</default>
|
||||
</entry>
|
||||
<entry name="enableColumnsLayout" type="Bool">
|
||||
<label>Enable/disable Columns layout</label>
|
||||
<default>true</default>
|
||||
</entry>
|
||||
<entry name="columnsLayoutInitialRotationAngle" type="String">
|
||||
<label>Columns layout initial rotation angle</label>
|
||||
<default>0</default>
|
||||
</entry>
|
||||
<entry name="columnsBalanced" type="Bool">
|
||||
<label>Enable/disable creating a new window in the shortest column</label>
|
||||
<default>false</default>
|
||||
</entry>
|
||||
<entry name="columnsLayerConf" type="String">
|
||||
<label>Columns layout default configuration.</label>
|
||||
<default></default>
|
||||
</entry>
|
||||
|
||||
<entry name="spreadLayoutOrder" type="Int">
|
||||
<label> Spread layout order</label>
|
||||
<default>8</default>
|
||||
</entry>
|
||||
|
||||
<entry name="floatingLayoutOrder" type="Int">
|
||||
<label> Floating layout order</label>
|
||||
<default>9</default>
|
||||
</entry>
|
||||
|
||||
<entry name="stairLayoutOrder" type="Int">
|
||||
<label> Stair layout order</label>
|
||||
<default>10</default>
|
||||
</entry>
|
||||
<entry name="stairReverse" type="Bool">
|
||||
<label>Reverse the stair layout's orientation</label>
|
||||
<default>false</default>
|
||||
</entry>
|
||||
|
||||
<entry name="binaryTreeLayoutOrder" type="Int">
|
||||
<label> BTree layout order</label>
|
||||
<default>11</default>
|
||||
</entry>
|
||||
|
||||
<entry name="cascadeLayoutOrder" type="Int">
|
||||
<label> Cascade layout order</label>
|
||||
<default>12</default>
|
||||
</entry>
|
||||
|
||||
<entry name="ignoreActivity" type="String">
|
||||
<label>Do not apply tiling on some activities(comma-separated list of activity names)</label>
|
||||
<default></default>
|
||||
</entry>
|
||||
|
||||
<entry name="ignoreClass" type="String">
|
||||
<label>Ignore windows with certain classes(comma-separated list)</label>
|
||||
<default>krunner,yakuake,spectacle,kded5,xwaylandvideobridge,plasmashell,ksplashqml,org.kde.plasmashell,org.kde.polkit-kde-authentication-agent-1,org.kde.kruler,kruler,kwin_wayland,ksmserver-logout-greeter</default>
|
||||
</entry>
|
||||
|
||||
<entry name="ignoreRole" type="String">
|
||||
<label>Ignore windows with specific role(comma-separated list)</label>
|
||||
<default>quake</default>
|
||||
</entry>
|
||||
|
||||
<entry name="ignoreScreen" type="String">
|
||||
<label>Do not apply tiling on some screens(comma-separated list of screen names)</label>
|
||||
<default></default>
|
||||
</entry>
|
||||
|
||||
<entry name="ignoreVDesktop" type="String">
|
||||
<label>Do not apply tiling on some virtual desktops(comma-separated list of virtual desktops names)</label>
|
||||
<default></default>
|
||||
</entry>
|
||||
|
||||
<entry name="ignoreTitle" type="String">
|
||||
<label>Ignore windows with certain string in title(comma-separated list)</label>
|
||||
<default></default>
|
||||
</entry>
|
||||
|
||||
<entry name="screenDefaultLayout" type="String">
|
||||
<label>Assigning number of layout to screen(output) by default</label>
|
||||
<default></default>
|
||||
</entry>
|
||||
|
||||
<entry name="tileNothing" type="Bool">
|
||||
<label>Don't tile any windows by default</label>
|
||||
<default>false</default>
|
||||
</entry>
|
||||
|
||||
<entry name="tilingClass" type="String">
|
||||
<label>Tile windows with certain classes(comma-separated list)</label>
|
||||
<default></default>
|
||||
</entry>
|
||||
|
||||
<entry name="floatingClass" type="String">
|
||||
<label>Float windows with certain classes(comma-separated list)</label>
|
||||
<default></default>
|
||||
</entry>
|
||||
|
||||
<entry name="floatingTitle" type="String">
|
||||
<label>Float windows with certain string in title(comma-separated list)</label>
|
||||
<default></default>
|
||||
</entry>
|
||||
|
||||
<entry name="floatUtility" type="Bool">
|
||||
<label>Automatically float utility windows (Dialog, Splash, Utility)</label>
|
||||
<default>true</default>
|
||||
</entry>
|
||||
|
||||
<entry name="layoutPerActivity" type="Bool">
|
||||
<label>Use separate layouts per activity.</label>
|
||||
<default>true</default>
|
||||
</entry>
|
||||
|
||||
<entry name="layoutPerDesktop" type="Bool">
|
||||
<label>Use separate layouts per desktop.</label>
|
||||
<default>true</default>
|
||||
</entry>
|
||||
|
||||
<entry name="tiledWindowsLayer" type="Int">
|
||||
<label>What layer will have tiled windows</label>
|
||||
<default>0</default>
|
||||
</entry>
|
||||
|
||||
<entry name="floatedWindowsLayer" type="Int">
|
||||
<label>What layer will have floated windows</label>
|
||||
<default>1</default>
|
||||
</entry>
|
||||
|
||||
<entry name="soleWindowWidth" type="Int">
|
||||
<label>The sole window width in percent.</label>
|
||||
<default>100</default>
|
||||
</entry>
|
||||
|
||||
<entry name="soleWindowHeight" type="Int">
|
||||
<label>The sole window height in percent.</label>
|
||||
<default>100</default>
|
||||
</entry>
|
||||
|
||||
<entry name="soleWindowNoBorders" type="Bool">
|
||||
<label>Do not draw borders around sole window</label>
|
||||
<default>false</default>
|
||||
</entry>
|
||||
|
||||
<entry name="soleWindowNoGaps" type="Bool">
|
||||
<label>Do not draw gaps around sole window</label>
|
||||
<default>false</default>
|
||||
</entry>
|
||||
|
||||
<entry name="monocleMaximize" type="Bool">
|
||||
<label>Always maximize windows in Monocle layout</label>
|
||||
<default>true</default>
|
||||
</entry>
|
||||
|
||||
<entry name="monocleMinimizeRest" type="Bool">
|
||||
<label>Minimize other tiles than the current one in Monocle layout</label>
|
||||
<default>false</default>
|
||||
</entry>
|
||||
|
||||
<entry name="adjustLayout" type="Bool">
|
||||
<label>Adjust layout with mouse</label>
|
||||
<default>true</default>
|
||||
</entry>
|
||||
|
||||
<entry name="adjustLayoutLive" type="Bool">
|
||||
<label>Adjust as window is being resized</label>
|
||||
<default>true</default>
|
||||
</entry>
|
||||
|
||||
<entry name="keepTilingOnDrag" type="Bool">
|
||||
<label>Always preserve the tiling status of a window upon dragging</label>
|
||||
<default>true</default>
|
||||
</entry>
|
||||
|
||||
<entry name="noTileBorder" type="Bool">
|
||||
<label>Remove borders of tiled windows</label>
|
||||
<default>false</default>
|
||||
</entry>
|
||||
|
||||
<entry name="preventMinimize" type="Bool">
|
||||
<label>Prevent windows from minimizing</label>
|
||||
<default>false</default>
|
||||
</entry>
|
||||
|
||||
<entry name="preventProtrusion" type="Bool">
|
||||
<label>Prevent windows from protruding out of screen</label>
|
||||
<default>true</default>
|
||||
</entry>
|
||||
|
||||
<entry name="notificationDuration" type="Int">
|
||||
<label>Duration of pop-up notifications</label>
|
||||
<default>1000</default>
|
||||
</entry>
|
||||
|
||||
<entry name="screenGapLeft" type="Int">
|
||||
<label>Gap between tiles and screen borders (Left)</label>
|
||||
<default>0</default>
|
||||
</entry>
|
||||
|
||||
<entry name="screenGapRight" type="Int">
|
||||
<label>Gap between tiles and screen borders (Right)</label>
|
||||
<default>0</default>
|
||||
</entry>
|
||||
|
||||
<entry name="screenGapTop" type="Int">
|
||||
<label>Gap between tiles and screen borders (Top)</label>
|
||||
<default>0</default>
|
||||
</entry>
|
||||
|
||||
<entry name="screenGapBottom" type="Int">
|
||||
<label>Gap between tiles and screen borders (Bottom)</label>
|
||||
<default>0</default>
|
||||
</entry>
|
||||
|
||||
<entry name="screenGapBetween" type="Int">
|
||||
<label>Gap between tiles in Tile layout</label>
|
||||
<default>0</default>
|
||||
</entry>
|
||||
|
||||
<entry name="gapsOverrideConfig" type="String">
|
||||
<label>Override default screen gaps</label>
|
||||
<default></default>
|
||||
</entry>
|
||||
|
||||
<entry name="floatSkipPagerWindows" type="Bool">
|
||||
<label>Make the window float if its property: skipPager=true (HACK)</label>
|
||||
<default>false</default>
|
||||
</entry>
|
||||
|
||||
<entry name="directionalKeyDwm" type="Bool">
|
||||
<label>Up, Down, Left, and Right shortcut behaves like dwm</label>
|
||||
<default>false</default>
|
||||
</entry>
|
||||
|
||||
<entry name="directionalKeyFocus" type="Bool">
|
||||
<label>Up, Down, Left, and Right shortcut moves focus</label>
|
||||
<default>true</default>
|
||||
</entry>
|
||||
|
||||
<entry name="limitTileWidth" type="Bool">
|
||||
<label>Limit the width of tiles</label>
|
||||
<default>false</default>
|
||||
</entry>
|
||||
|
||||
<entry name="limitTileWidthRatio" type="Double">
|
||||
<label>Ratio of maximum tile width to the height of screen</label>
|
||||
<default>1.6</default>
|
||||
</entry>
|
||||
|
||||
<entry name="newWindowPosition" type="Int">
|
||||
<label>The position every new window in the screen window array</label>
|
||||
<default>0</default>
|
||||
</entry>
|
||||
|
||||
<entry name="logging" type="Bool">
|
||||
<label>Enable logging</label>
|
||||
<default>false</default>
|
||||
</entry>
|
||||
|
||||
<entry name="logNewWindows" type="Bool">
|
||||
<label>Log new windows</label>
|
||||
<default>false</default>
|
||||
</entry>
|
||||
|
||||
<entry name="logFilteredWindows" type="Bool">
|
||||
<label>Log filtered windows</label>
|
||||
<default>false</default>
|
||||
</entry>
|
||||
|
||||
<entry name="logUnmanagedWindows" type="Bool">
|
||||
<label>Log unmanaged windows</label>
|
||||
<default>false</default>
|
||||
</entry>
|
||||
|
||||
<entry name="logWorkspaceSignals" type="Bool">
|
||||
<label>Log signals from workspace</label>
|
||||
<default>false</default>
|
||||
</entry>
|
||||
<entry name="logWorkspaceSignalsSubmodules" type="String">
|
||||
<label>Specify a comma separated list of numbers workspace signals submodules</label>
|
||||
<default></default>
|
||||
</entry>
|
||||
|
||||
<entry name="logWindowSignals" type="Bool">
|
||||
<label>Log signals from windows</label>
|
||||
<default>false</default>
|
||||
</entry>
|
||||
<entry name="logWindowSignalsSubmodules" type="String">
|
||||
<label>Specify a comma separated list of numbers window signals submodules</label>
|
||||
<default></default>
|
||||
</entry>
|
||||
|
||||
<entry name="logOther" type="Bool">
|
||||
<label>Log all other modules</label>
|
||||
<default>false</default>
|
||||
</entry>
|
||||
<entry name="logOtherSubmodules" type="String">
|
||||
<label>Specify a comma separated list of numbers all other submodules</label>
|
||||
<default></default>
|
||||
</entry>
|
||||
|
||||
<entry name="logFilter" type="Bool">
|
||||
<label>Enable log filters</label>
|
||||
<default>false</default>
|
||||
</entry>
|
||||
<entry name="logFilterStr" type="String">
|
||||
<label>Specify a comma separated list of filters</label>
|
||||
<default></default>
|
||||
</entry>
|
||||
</group>
|
||||
</kcfg>
|
||||
BIN
Binary file not shown.
BIN
Binary file not shown.
+4143
File diff suppressed because it is too large
Load Diff
+62
@@ -0,0 +1,62 @@
|
||||
// Copyright (c) 2018 Eon S. Jeon <esjeon@hyunmu.am>
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a
|
||||
// copy of this software and associated documentation files (the "Software"),
|
||||
// to deal in the Software without restriction, including without limitation
|
||||
// the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
||||
// and/or sell copies of the Software, and to permit persons to whom the
|
||||
// Software is furnished to do so, subject to the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be included in
|
||||
// all copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
||||
// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
||||
// DEALINGS IN THE SOFTWARE.
|
||||
|
||||
import QtQuick 2.15
|
||||
import org.kde.plasma.core as PlasmaCore;
|
||||
import org.kde.plasma.components as Plasma;
|
||||
import org.kde.plasma.plasma5support as Plasma5Support
|
||||
import org.kde.kwin 3.0;
|
||||
import org.kde.taskmanager as TaskManager
|
||||
import "../code/script.js" as K
|
||||
|
||||
Item {
|
||||
id: scriptRoot
|
||||
|
||||
TaskManager.ActivityInfo {
|
||||
id: activityInfo
|
||||
}
|
||||
|
||||
Loader {
|
||||
id: popupDialog
|
||||
source: "popup.qml"
|
||||
|
||||
function show(text, duration) {
|
||||
var area = Workspace.clientArea(KWin.FullScreenArea, Workspace.activeScreen, Workspace.currentDesktop);
|
||||
this.item.show(text, area, duration);
|
||||
}
|
||||
}
|
||||
|
||||
Component.onCompleted: {
|
||||
console.log("KROHNKITE: starting the script");
|
||||
const api = {
|
||||
"workspace": Workspace,
|
||||
// "options": Options,
|
||||
"kwin": KWin,
|
||||
"shortcuts": shortcutsLoader.item
|
||||
};
|
||||
|
||||
(new K.KWinDriver(api)).main();
|
||||
}
|
||||
Loader {
|
||||
id: shortcutsLoader;
|
||||
|
||||
source: "shortcuts.qml";
|
||||
}
|
||||
}
|
||||
+78
@@ -0,0 +1,78 @@
|
||||
// Copyright (c) 2018 Eon S. Jeon <esjeon@hyunmu.am>
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a
|
||||
// copy of this software and associated documentation files (the "Software"),
|
||||
// to deal in the Software without restriction, including without limitation
|
||||
// the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
||||
// and/or sell copies of the Software, and to permit persons to whom the
|
||||
// Software is furnished to do so, subject to the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be included in
|
||||
// all copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
||||
// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
||||
// DEALINGS IN THE SOFTWARE.
|
||||
|
||||
import QtQuick 2.15
|
||||
import QtQuick.Controls 2.15
|
||||
import org.kde.plasma.core as PlasmaCore;
|
||||
|
||||
/*
|
||||
* Component Documentation
|
||||
* - PlasmaCore global `theme` object:
|
||||
* https://techbase.kde.org/Development/Tutorials/Plasma2/QML2/API#Plasma_Themes
|
||||
* - PlasmaCore.Dialog:
|
||||
* https://techbase.kde.org/Development/Tutorials/Plasma2/QML2/API#Top_Level_windows
|
||||
*/
|
||||
|
||||
PlasmaCore.Dialog {
|
||||
id: popupDialog
|
||||
type: PlasmaCore.Dialog.OnScreenDisplay
|
||||
flags: Qt.Popup | Qt.WindowStaysOnTopHint
|
||||
location: PlasmaCore.Types.Floating
|
||||
outputOnly: true
|
||||
|
||||
visible: false
|
||||
|
||||
mainItem: Item {
|
||||
width: messageLabel.implicitWidth
|
||||
height: messageLabel.implicitHeight
|
||||
|
||||
Label {
|
||||
id: messageLabel
|
||||
padding: 10
|
||||
|
||||
font.pointSize: Math.round(10)
|
||||
font.weight: Font.Bold
|
||||
}
|
||||
|
||||
/* hides the popup window when triggered */
|
||||
Timer {
|
||||
id: hideTimer
|
||||
repeat: false
|
||||
|
||||
onTriggered: {
|
||||
popupDialog.visible = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
function show(text, area, duration) {
|
||||
hideTimer.stop();
|
||||
|
||||
messageLabel.text = text;
|
||||
|
||||
this.x = (area.x + area.width / 2) - this.width / 2;
|
||||
this.y = (area.y + area.height / 2) - this.height / 2;
|
||||
this.visible = true;
|
||||
|
||||
hideTimer.interval = duration;
|
||||
hideTimer.start();
|
||||
}
|
||||
}
|
||||
+358
@@ -0,0 +1,358 @@
|
||||
import QtQuick;
|
||||
import org.kde.kwin;
|
||||
|
||||
Item {
|
||||
id: dbus;
|
||||
function getToggleDock() {
|
||||
return toggleDock;
|
||||
}
|
||||
ShortcutHandler {
|
||||
id: toggleDock;
|
||||
|
||||
name: "KrohnkitetoggleDock";
|
||||
text: "Krohnkite: Toggle Dock";
|
||||
sequence: "";
|
||||
}
|
||||
|
||||
function getFocusNext() {
|
||||
return focusNext;
|
||||
}
|
||||
ShortcutHandler {
|
||||
id: focusNext;
|
||||
|
||||
name: "KrohnkiteFocusNext";
|
||||
text: "Krohnkite: Focus Next";
|
||||
sequence: "Meta+.";
|
||||
}
|
||||
function getFocusPrev() {
|
||||
return focusPrev;
|
||||
}
|
||||
ShortcutHandler {
|
||||
id: focusPrev;
|
||||
|
||||
name: "KrohnkiteFocusPrev";
|
||||
text: "Krohnkite: Focus Previous";
|
||||
sequence: "Meta+,";
|
||||
}
|
||||
|
||||
function getFocusDown() {
|
||||
return focusDown;
|
||||
}
|
||||
ShortcutHandler {
|
||||
id: focusDown;
|
||||
|
||||
name: "KrohnkiteFocusDown";
|
||||
text: "Krohnkite: Focus Down";
|
||||
sequence: "Meta+J";
|
||||
}
|
||||
function getFocusUp() {
|
||||
return focusUp;
|
||||
}
|
||||
ShortcutHandler {
|
||||
id: focusUp;
|
||||
|
||||
name: "KrohnkiteFocusUp";
|
||||
text: "Krohnkite: Focus Up";
|
||||
sequence: "Meta+K";
|
||||
}
|
||||
function getFocusLeft() {
|
||||
return focusLeft;
|
||||
}
|
||||
ShortcutHandler {
|
||||
id: focusLeft;
|
||||
|
||||
name: "KrohnkiteFocusLeft";
|
||||
text: "Krohnkite: Focus Left";
|
||||
sequence: "Meta+H";
|
||||
}
|
||||
function getFocusRight() {
|
||||
return focusRight;
|
||||
}
|
||||
ShortcutHandler {
|
||||
id: focusRight;
|
||||
|
||||
name: "KrohnkiteFocusRight";
|
||||
text: "Krohnkite: Focus Right";
|
||||
sequence: "Meta+L";
|
||||
}
|
||||
function getShiftDown() {
|
||||
return shiftDown;
|
||||
}
|
||||
ShortcutHandler {
|
||||
id: shiftDown;
|
||||
|
||||
name: "KrohnkiteShiftDown";
|
||||
text: "Krohnkite: Move Down/Next";
|
||||
sequence: "Meta+Shift+J";
|
||||
}
|
||||
function getShiftUp() {
|
||||
return shiftUp;
|
||||
}
|
||||
ShortcutHandler {
|
||||
id: shiftUp;
|
||||
|
||||
name: "KrohnkiteShiftUp";
|
||||
text: "Krohnkite: Move Up/Prev";
|
||||
sequence: "Meta+Shift+K";
|
||||
}
|
||||
function getShiftLeft() {
|
||||
return shiftLeft;
|
||||
}
|
||||
ShortcutHandler {
|
||||
id: shiftLeft;
|
||||
|
||||
name: "KrohnkiteShiftLeft";
|
||||
text: "Krohnkite: Move Left";
|
||||
sequence: "Meta+Shift+H";
|
||||
}
|
||||
function getShiftRight() {
|
||||
return shiftRight;
|
||||
}
|
||||
ShortcutHandler {
|
||||
id: shiftRight;
|
||||
|
||||
name: "KrohnkiteShiftRight";
|
||||
text: "Krohnkite: Move Right";
|
||||
sequence: "Meta+Shift+L";
|
||||
}
|
||||
function getGrowHeight() {
|
||||
return growHeight;
|
||||
}
|
||||
ShortcutHandler {
|
||||
id: growHeight;
|
||||
|
||||
name: "KrohnkiteGrowHeight";
|
||||
text: "Krohnkite: Grow Height";
|
||||
sequence: "Meta+Ctrl+J";
|
||||
}
|
||||
function getShrinkHeight() {
|
||||
return shrinkHeight;
|
||||
}
|
||||
ShortcutHandler {
|
||||
id: shrinkHeight;
|
||||
|
||||
name: "KrohnkiteShrinkHeight";
|
||||
text: "Krohnkite: Shrink Height";
|
||||
sequence: "Meta+Ctrl+K";
|
||||
}
|
||||
function getShrinkWidth() {
|
||||
return shrinkWidth;
|
||||
}
|
||||
ShortcutHandler {
|
||||
id: shrinkWidth;
|
||||
|
||||
name: "KrohnkiteShrinkWidth";
|
||||
text: "Krohnkite: Shrink Width";
|
||||
sequence: "Meta+Ctrl+H";
|
||||
}
|
||||
function getGrowWidth() {
|
||||
return growWidth;
|
||||
}
|
||||
ShortcutHandler {
|
||||
id: growWidth;
|
||||
|
||||
name: "KrohnkitegrowWidth";
|
||||
text: "Krohnkite: Grow Width";
|
||||
sequence: "Meta+Ctrl+L";
|
||||
}
|
||||
function getIncrease() {
|
||||
return increase;
|
||||
}
|
||||
ShortcutHandler {
|
||||
id: increase;
|
||||
|
||||
name: "KrohnkiteIncrease";
|
||||
text: "Krohnkite: Increase";
|
||||
sequence: "Meta+I";
|
||||
}
|
||||
function getDecrease() {
|
||||
return decrease;
|
||||
}
|
||||
ShortcutHandler {
|
||||
id: decrease;
|
||||
|
||||
name: "KrohnkiteDecrease";
|
||||
text: "Krohnkite: Decrease";
|
||||
sequence: "Meta+D";
|
||||
}
|
||||
function getToggleFloat() {
|
||||
return toggleFloat;
|
||||
}
|
||||
ShortcutHandler {
|
||||
id: toggleFloat;
|
||||
|
||||
name: "KrohnkiteToggleFloat";
|
||||
text: "Krohnkite: Toggle Float";
|
||||
sequence: "Meta+F";
|
||||
}
|
||||
function getFloatAll() {
|
||||
return floatAll;
|
||||
}
|
||||
ShortcutHandler {
|
||||
id: floatAll;
|
||||
|
||||
name: "KrohnkiteFloatAll";
|
||||
text: "Krohnkite: Toggle Float All";
|
||||
sequence: "Meta+Shift+F";
|
||||
}
|
||||
function getNextLayout() {
|
||||
return nextLayout;
|
||||
}
|
||||
ShortcutHandler {
|
||||
id: nextLayout;
|
||||
|
||||
name: "KrohnkiteNextLayout";
|
||||
text: "Krohnkite: Next Layout";
|
||||
sequence: "Meta+\\";
|
||||
}
|
||||
function getPreviousLayout() {
|
||||
return previousLayout;
|
||||
}
|
||||
ShortcutHandler {
|
||||
id: previousLayout;
|
||||
|
||||
name: "KrohnkitePreviousLayout";
|
||||
text: "Krohnkite: Previous Layout";
|
||||
sequence: "Meta+|";
|
||||
}
|
||||
function getRotate() {
|
||||
return rotate;
|
||||
}
|
||||
ShortcutHandler {
|
||||
id: rotate;
|
||||
|
||||
name: "KrohnkiteRotate";
|
||||
text: "Krohnkite: Rotate";
|
||||
sequence: "Meta+R";
|
||||
}
|
||||
function getRotatePart() {
|
||||
return rotatePart;
|
||||
}
|
||||
ShortcutHandler {
|
||||
id: rotatePart;
|
||||
|
||||
name: "KrohnkiteRotatePart";
|
||||
text: "Krohnkite: Rotate Part";
|
||||
sequence: "Meta+Shift+R";
|
||||
}
|
||||
function getSetMaster() {
|
||||
return setMaster;
|
||||
}
|
||||
ShortcutHandler {
|
||||
id: setMaster;
|
||||
|
||||
name: "KrohnkiteSetMaster";
|
||||
text: "Krohnkite: Set master";
|
||||
sequence: "Meta+Return";
|
||||
}
|
||||
function getTileLayout() {
|
||||
return tileLayout;
|
||||
}
|
||||
ShortcutHandler {
|
||||
id: tileLayout;
|
||||
|
||||
name: "KrohnkiteTileLayout";
|
||||
text: "Krohnkite: Tile Layout";
|
||||
sequence: "Meta+T";
|
||||
}
|
||||
function getMonocleLayout() {
|
||||
return monocleLayout;
|
||||
}
|
||||
ShortcutHandler {
|
||||
id: monocleLayout;
|
||||
|
||||
name: "KrohnkiteMonocleLayout";
|
||||
text: "Krohnkite: Monocle Layout";
|
||||
sequence: "Meta+M";
|
||||
}
|
||||
function getThreeColumnLayout() {
|
||||
return treeColumnLayout;
|
||||
}
|
||||
ShortcutHandler {
|
||||
id: treeColumnLayout;
|
||||
|
||||
name: "KrohnkiteTreeColumnLayout";
|
||||
text: "Krohnkite: Three Column Layout";
|
||||
sequence: "";
|
||||
}
|
||||
function getSpreadLayout() {
|
||||
return spreadLayout;
|
||||
}
|
||||
ShortcutHandler {
|
||||
id: spreadLayout;
|
||||
|
||||
name: "KrohnkiteSpreadLayout";
|
||||
text: "Krohnkite: Spread Layout";
|
||||
sequence: "";
|
||||
}
|
||||
function getStairLayout() {
|
||||
return stairLayout;
|
||||
}
|
||||
ShortcutHandler {
|
||||
id: stairLayout;
|
||||
|
||||
name: "KrohnkiteStairLayout";
|
||||
text: "Krohnkite: Stair Layout";
|
||||
sequence: "";
|
||||
}
|
||||
function getFloatingLayout() {
|
||||
return floatingLayout;
|
||||
}
|
||||
ShortcutHandler {
|
||||
id: floatingLayout;
|
||||
|
||||
name: "KrohnkiteFloatingLayout";
|
||||
text: "Krohnkite: Floating Layout";
|
||||
sequence: "";
|
||||
}
|
||||
function getQuarterLayout() {
|
||||
return quarterLayout;
|
||||
}
|
||||
ShortcutHandler {
|
||||
id: quarterLayout;
|
||||
|
||||
name: "KrohnkiteQuarterLayout";
|
||||
text: "Krohnkite: Quarter Layout";
|
||||
sequence: "";
|
||||
}
|
||||
function getStackedLayout() {
|
||||
return stackedLayout;
|
||||
}
|
||||
ShortcutHandler {
|
||||
id: stackedLayout;
|
||||
|
||||
name: "KrohnkiteStackedLayout";
|
||||
text: "Krohnkite: Stacked Layout";
|
||||
sequence: "";
|
||||
}
|
||||
function getBTreeLayout() {
|
||||
return bTreeLayout;
|
||||
}
|
||||
ShortcutHandler {
|
||||
id: bTreeLayout;
|
||||
|
||||
name: "KrohnkiteBTreeLayout";
|
||||
text: "Krohnkite: BTree Layout";
|
||||
sequence: "";
|
||||
}
|
||||
function getSpiralLayout() {
|
||||
return spiralLayout;
|
||||
}
|
||||
ShortcutHandler {
|
||||
id: spiralLayout;
|
||||
|
||||
name: "KrohnkiteSpiralLayout";
|
||||
text: "Krohnkite: Spiral Layout";
|
||||
sequence: "";
|
||||
}
|
||||
function getColumnsLayout() {
|
||||
return columnsLayout;
|
||||
}
|
||||
ShortcutHandler {
|
||||
id: columnsLayout;
|
||||
|
||||
name: "KrohnkiteColumnsLayout";
|
||||
text: "Krohnkite: Columns Layout";
|
||||
sequence: "";
|
||||
}
|
||||
}
|
||||
+23
@@ -0,0 +1,23 @@
|
||||
{
|
||||
"KPackageStructure": "KWin/Script",
|
||||
"KPlugin": {
|
||||
"Name": "Krohnkite",
|
||||
"Description": "A dynamic tiling script for KWin (1d7fd74)",
|
||||
"Icon": "dialog-tile-clones",
|
||||
"Authors": [
|
||||
{
|
||||
"Email": "esjeon@hyunmu.am",
|
||||
"Name": "Eon S. Jeon"
|
||||
}
|
||||
],
|
||||
"Id": "krohnkite",
|
||||
"Version": "0.9.9.2",
|
||||
"License": "MIT",
|
||||
"Website": "https://github.com/anametologin/krohnkite#readme"
|
||||
},
|
||||
"X-Plasma-API": "declarativescript",
|
||||
"X-Plasma-API-Minimum-Version": "6.0",
|
||||
"X-Plasma-MainScript": "ui/main.qml",
|
||||
"X-KDE-ConfigModule": "kwin/effects/configs/kcm_kwin4_genericscripted",
|
||||
"X-KWin-Config-TranslationDomain": "krohnkite"
|
||||
}
|
||||
+2
@@ -0,0 +1,2 @@
|
||||
// Cannot package without this file due to a bug in kpackagetool6
|
||||
// This file is empty on purpose, the implementation is done in the ui/main.qml file instead
|
||||
+376
@@ -0,0 +1,376 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<kcfg xmlns="http://www.kde.org/standards/kcfg/1.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.kde.org/standards/kcfg/1.0 http://www.kde.org/standards/kcfg/1.0/kcfg.xsd">
|
||||
<kcfgfile name=""/>
|
||||
<group name="">
|
||||
<entry name="defaultTiler" type="Int">
|
||||
<default>0</default>
|
||||
</entry>
|
||||
<entry name="centerInTileMode" type="Int">
|
||||
<default>0</default>
|
||||
</entry>
|
||||
<entry name="rememberTiler" type="Bool">
|
||||
<default>false</default>
|
||||
</entry>
|
||||
<entry name="restoreSize" type="Bool">
|
||||
<default>false</default>
|
||||
</entry>
|
||||
<entry name="allowTransient" type="Bool">
|
||||
<default>false</default>
|
||||
</entry>
|
||||
<entry name="allowModal" type="Bool">
|
||||
<default>false</default>
|
||||
</entry>
|
||||
<entry name="tilerVisibility" type="Int">
|
||||
<default>0</default>
|
||||
</entry>
|
||||
<entry name="revealMargin" type="Int">
|
||||
<default>200</default>
|
||||
</entry>
|
||||
<entry name="displayAs" type="Int">
|
||||
<default>0</default>
|
||||
</entry>
|
||||
<entry name="windowVisibility" type="Int">
|
||||
<default>0</default>
|
||||
</entry>
|
||||
<entry name="theme" type="Int">
|
||||
<default>0</default>
|
||||
</entry>
|
||||
<entry name="tileMargin" type="Int">
|
||||
<default>0</default>
|
||||
</entry>
|
||||
<entry name="screenMargin" type="Int">
|
||||
<default>0</default>
|
||||
</entry>
|
||||
<entry name="defaultInput" type="Int">
|
||||
<default>0</default>
|
||||
</entry>
|
||||
<entry name="showOverlayTextHint" type="Bool">
|
||||
<default>true</default>
|
||||
</entry>
|
||||
<entry name="overlayLayout" type="String">
|
||||
<default>4x2</default>
|
||||
</entry>
|
||||
<entry name="overlayScreenEdgeMargin" type="Int">
|
||||
<default>0</default>
|
||||
</entry>
|
||||
<entry name="overlayPollingRate" type="Int">
|
||||
<default>100</default>
|
||||
</entry>
|
||||
<entry name="rememberAllLayouts" type="Bool">
|
||||
<default>false</default>
|
||||
</entry>
|
||||
<entry name="showTargetTileHint" type="Bool">
|
||||
<default>true</default>
|
||||
</entry>
|
||||
<entry name="showTextHint" type="Bool">
|
||||
<default>true</default>
|
||||
</entry>
|
||||
<entry name="gridTilerOpacity" type="Int">
|
||||
<default>100</default>
|
||||
<min>0</min>
|
||||
<max>100</max>
|
||||
</entry>
|
||||
<entry name="popupGridAt" type="Int">
|
||||
<default>0</default>
|
||||
</entry>
|
||||
<entry name="horizontalAlignment" type="Int">
|
||||
<default>1</default>
|
||||
</entry>
|
||||
<entry name="verticalAlignment" type="Int">
|
||||
<default>1</default>
|
||||
</entry>
|
||||
<entry name="gridColumns" type="Int">
|
||||
<default>3</default>
|
||||
</entry>
|
||||
<entry name="gridAllColumns" type="Int">
|
||||
<default>6</default>
|
||||
</entry>
|
||||
<entry name="gridSpacing" type="Int">
|
||||
<default>10</default>
|
||||
</entry>
|
||||
<entry name="gridWidth" type="Int">
|
||||
<default>130</default>
|
||||
</entry>
|
||||
<entry name="gridHeight" type="Int">
|
||||
<default>70</default>
|
||||
</entry>
|
||||
<entry name="popupGridPollingRate" type="Int">
|
||||
<default>100</default>
|
||||
</entry>
|
||||
<entry name="virtualDesktopVisibility" type="Int">
|
||||
<default>0</default>
|
||||
</entry>
|
||||
<entry name="virtualDesktopDropAction" type="Int">
|
||||
<default>0</default>
|
||||
</entry>
|
||||
<entry name="virtualDesktopHoverTime" type="Int">
|
||||
<default>500</default>
|
||||
</entry>
|
||||
<entry name="moveBackOnDrop" type="Bool">
|
||||
<default>false</default>
|
||||
</entry>
|
||||
<entry name="moveBackOnTile" type="Bool">
|
||||
<default>false</default>
|
||||
</entry>
|
||||
<entry name="showAddVirtualDesktopButton" type="Bool">
|
||||
<default>true</default>
|
||||
</entry>
|
||||
<entry name="autoRemoveEmptyVirtualDesktops" type="Bool">
|
||||
<default>false</default>
|
||||
</entry>
|
||||
<entry name="popupLayout" type="String">
|
||||
<default>1x1
|
||||
2x1
|
||||
3x1
|
||||
SPECIAL_SPLIT_HORIZONTAL
|
||||
0,0,75,100+25,0,75,100+25,0,50,100
|
||||
4x1
|
||||
2x2
|
||||
SPECIAL_FILL
|
||||
4x2
|
||||
SPECIAL_AUTO_TILER_1
|
||||
SPECIAL_AUTO_TILER_2
|
||||
SPECIAL_AUTO_TILER_3</default>
|
||||
</entry>
|
||||
<entry name="allPopupLayouts" type="String">
|
||||
<default>SPECIAL_FILL
|
||||
SPECIAL_SPLIT_VERTICAL
|
||||
SPECIAL_SPLIT_HORIZONTAL
|
||||
SPECIAL_MAXIMIZE
|
||||
SPECIAL_MINIMIZE
|
||||
SPECIAL_FULLSCREEN
|
||||
0,0,50,100+50,0,50,50+50,50,50,50
|
||||
0,0,50,50+0,50,50,50+50,0,50,100
|
||||
0,0,25,50+0,50,25,50+25,0,50,100+75,0,25,50+75,50,25,50
|
||||
0,0,25,50+0,50,25,50+25,0,50,50+25,50,50,50+75,0,25,50+75,50,25,50
|
||||
SPECIAL_KEEP_ABOVE
|
||||
SPECIAL_KEEP_BELOW
|
||||
0,0,50,100+50,0,25,50+50,50,25,50+75,0,25,50+75,50,25,50
|
||||
0,0,25,50+0,50,25,50+25,0,25,50+25,50,25,50+50,0,50,100
|
||||
0,0,50,50+0,50,50,50+50,0,25,50+50,50,25,50+75,0,25,50+75,50,25,50
|
||||
0,0,25,50+0,50,25,50+25,0,25,50+25,50,25,50+50,0,50,50+50,50,50,50
|
||||
SPECIAL_NO_TITLEBAR_AND_FRAME
|
||||
SPECIAL_CLOSE
|
||||
1x1
|
||||
2x1
|
||||
3x1
|
||||
4x1
|
||||
5x1
|
||||
6x1
|
||||
1x2
|
||||
1x3
|
||||
1x4
|
||||
1x5
|
||||
0,0,75,100+25,0,75,100+25,0,50,100
|
||||
0,0,75,50+25,0,75,50+25,0,50,50+0,50,75,50+25,50,75,50+25,50,50,50
|
||||
2x2
|
||||
3x2
|
||||
4x2
|
||||
5x2
|
||||
0,0,67,100+33,0,67,100+17,0,66,100
|
||||
0,0,67,50+33,0,67,50+17,0,66,50+0,50,67,50+33,50,67,50+17,50,66,50
|
||||
2x3
|
||||
3x3
|
||||
4x3
|
||||
5x3
|
||||
1x1+17,0,66,100+33,0,34,100
|
||||
1x2+17,0,66,50+33,0,34,50+17,50,66,50+33,50,34,50
|
||||
11,25,26,50+37,25,26,50+63,25,26,50
|
||||
11,0,26,100+37,0,26,100+63,0,26,100
|
||||
11,0,26,50+37,0,26,50+63,0,26,50 + 11,50,26,50+37,50,26,50+63,50,26,50
|
||||
11,0,26,100+37,0,26,100+63,0,26,100 + 11,12,26,76+37,12,26,76+63,12,26,76 + 11,25,26,50+37,25,26,50+63,25,26,50
|
||||
1x1+12,0,76,100+25,0,50,100+37,0,26,100
|
||||
1x2+12,0,76,50+25,0,50,50+37,0,26,50+12,50,76,50+25,50,50,50+37,50,26,50
|
||||
0,25,37,50+37,25,26,50+63,25,37,50
|
||||
0,0,37,100+37,0,26,100+63,0,37,100
|
||||
0,0,37,50+37,0,26,50+63,0,37,50 + 0,50,37,50+37,50,26,50+63,50,37,50
|
||||
0,0,37,100+37,0,26,100+63,0,37,100 + 0,12,37,76+37,12,26,76+63,12,37,76 + 0,25,37,50+37,25,26,50+63,25,37,50
|
||||
1x1+17,17,66,66+33,33,34,34
|
||||
1x1+12,12,76,76+25,25,50,50+37,37,26,26
|
||||
0,0,25,100+75,0,25,100+25,0,50,100
|
||||
0,0,25,67+75,0,25,67+25,0,50,67+0,67,25,33+75,67,25,33+25,67,50,33
|
||||
0,0,25,33+75,0,25,33+25,0,50,33+0,33,25,67+75,33,25,67+25,33,50,67
|
||||
0,0,25,67+75,0,25,67+25,0,50,67+0,33,25,67+75,33,25,67+25,33,50,67
|
||||
0,0,33,67+33,0,34,67+67,0,33,67+0,67,33,33+33,67,34,33+67,67,33,33
|
||||
0,0,33,33+33,0,34,33+67,0,33,33+0,33,33,67+33,33,34,67+67,33,33,67
|
||||
0,0,67,100+67,0,33,100
|
||||
0,0,33,100+33,0,67,100
|
||||
0,0,67,100+67,0,33,50+67,50,33,50
|
||||
0,0,33,50+0,50,33,50+33,0,67,100
|
||||
0,0,67,50+67,0,33,50+0,50,67,50+67,50,33,50
|
||||
0,0,33,50+33,0,67,50+0,50,33,50+33,50,67,50
|
||||
SPECIAL_AUTO_TILER_TOGGLE
|
||||
SPECIAL_AUTO_TILER_1
|
||||
SPECIAL_AUTO_TILER_2
|
||||
SPECIAL_AUTO_TILER_3</default>
|
||||
</entry>
|
||||
<entry name="shortcutChangeMode" type="String">
|
||||
<default>Meta+Ctrl+Space</default>
|
||||
</entry>
|
||||
<entry name="shortcutShowAllSpan" type="String">
|
||||
<default>Ctrl+Space</default>
|
||||
</entry>
|
||||
<entry name="shortcutVisibility" type="String">
|
||||
<default>Meta+Space</default>
|
||||
</entry>
|
||||
<entry name="shortcutInputType" type="String">
|
||||
<default>Ctrl+Alt+I</default>
|
||||
</entry>
|
||||
<entry name="shortcutCenterInTile" type="String">
|
||||
<default>Meta+Ctrl+C</default>
|
||||
</entry>
|
||||
<entry name="shortcutMoveOnDrop" type="String">
|
||||
<default>Meta+Ctrl+V</default>
|
||||
</entry>
|
||||
<entry name="shortcutToggleTilingSuggestions" type="String">
|
||||
<default>Meta+Ctrl+S</default>
|
||||
</entry>
|
||||
<entry name="hintChangeMode" type="Bool">
|
||||
<default>true</default>
|
||||
</entry>
|
||||
<entry name="hintShowAllSpan" type="Bool">
|
||||
<default>true</default>
|
||||
</entry>
|
||||
<entry name="hintVisibility" type="Bool">
|
||||
<default>true</default>
|
||||
</entry>
|
||||
<entry name="hintInputType" type="Bool">
|
||||
<default>true</default>
|
||||
</entry>
|
||||
<entry name="hintCenterInTile" type="Bool">
|
||||
<default>true</default>
|
||||
</entry>
|
||||
<entry name="hintMoveOnDrop" type="Bool">
|
||||
<default>true</default>
|
||||
</entry>
|
||||
<entry name="hintToggleTilingSuggestions" type="Bool">
|
||||
<default>true</default>
|
||||
</entry>
|
||||
<entry name="showHintHint" type="Bool">
|
||||
<default>true</default>
|
||||
</entry>
|
||||
<entry name="debugLogs" type="Bool">
|
||||
<default>false</default>
|
||||
</entry>
|
||||
<entry name="showPositionHint" type="Bool">
|
||||
<default>false</default>
|
||||
</entry>
|
||||
<entry name="positionHintFormat" type="Int">
|
||||
<default>0</default>
|
||||
</entry>
|
||||
<entry name="showSizeHint" type="Bool">
|
||||
<default>false</default>
|
||||
</entry>
|
||||
<entry name="sizeHintFormat" type="Int">
|
||||
<default>0</default>
|
||||
</entry>
|
||||
<entry name="autoTileNewWindows" type="Bool">
|
||||
<default>false</default>
|
||||
</entry>
|
||||
<entry name="autoTilerEdgeScroll" type="Bool">
|
||||
<default>true</default>
|
||||
</entry>
|
||||
<entry name="autoTileMinimizedMaximized" type="Bool">
|
||||
<default>true</default>
|
||||
</entry>
|
||||
<entry name="autoTileRestoreSize" type="Bool">
|
||||
<default>false</default>
|
||||
</entry>
|
||||
<entry name="autoTileRestoreSizeAndPosition" type="Bool">
|
||||
<default>true</default>
|
||||
</entry>
|
||||
<entry name="autoTileToggleBehavior" type="Int">
|
||||
<default>0</default>
|
||||
</entry>
|
||||
<entry name="autoTileIds" type="String">
|
||||
<default></default>
|
||||
</entry>
|
||||
<entry name="autoTileBlacklist" type="String">
|
||||
<default>krunner,kded,polkit,plasmashell,yakuake,spectacle,org.kde.spectacle,kded5,xwaylandvideobridge,ksplashqml,org.kde.plasmashell,org.kde.polkit-kde-authentication-agent-1,org.kde.kruler,kruler,kwin_wayland,kwin,ksmserver-logout-greeter,ksmserver</default>
|
||||
</entry>
|
||||
<entry name="autoTileWindowAction" type="Int">
|
||||
<default>0</default>
|
||||
</entry>
|
||||
<entry name="autoTileWindowIndex" type="Int">
|
||||
<default>0</default>
|
||||
</entry>
|
||||
<entry name="autoTileFocusAction" type="Int">
|
||||
<default>0</default>
|
||||
</entry>
|
||||
<entry name="autoTileFocusIndex" type="Int">
|
||||
<default>0</default>
|
||||
</entry>
|
||||
<entry name="autoTileMinimizedFocusAction" type="Int">
|
||||
<default>0</default>
|
||||
</entry>
|
||||
<entry name="autoTileMinimizedFocusIndex" type="Int">
|
||||
<default>0</default>
|
||||
</entry>
|
||||
<entry name="autoTileDragSwapAction" type="Int">
|
||||
<default>0</default>
|
||||
</entry>
|
||||
<entry name="autoTileLayer" type="Int">
|
||||
<default>2</default>
|
||||
</entry>
|
||||
<entry name="maxAutoTileDelay" type="Int">
|
||||
<default>5</default>
|
||||
</entry>
|
||||
<entry name="maxAutoTileDelaySessionStart" type="Int">
|
||||
<default>10</default>
|
||||
</entry>
|
||||
<entry name="autoTilerMode1" type="Int">
|
||||
<default>8</default>
|
||||
</entry>
|
||||
<entry name="autoTilerMode2" type="Int">
|
||||
<default>1</default>
|
||||
</entry>
|
||||
<entry name="autoTilerMode3" type="Int">
|
||||
<default>12</default>
|
||||
</entry>
|
||||
<entry name="autoTilerCustom1" type="String">
|
||||
<default>0:0,0,100,100
|
||||
0:0,0,50,100+1:50,0,50,100
|
||||
0:0,0,50,100+1:50,0,50,50+2:50,50,50,50
|
||||
0:0,0,50,50+3:0,50,50,50+1:50,0,50,50+2:50,50,50,50</default>
|
||||
</entry>
|
||||
<entry name="autoTilerCustom2" type="String">
|
||||
<default>{"carousel":true}
|
||||
0:0,0,100,100</default>
|
||||
</entry>
|
||||
<entry name="autoTilerCustom3" type="String">
|
||||
<default>0:0,0,67,100
|
||||
0:0,0,67,100+1:67,0,33,100
|
||||
0:0,0,67,100+1:67,0,33,50+2:67,50,33,50</default>
|
||||
</entry>
|
||||
<entry name="autoTilerCarousel1" type="Bool">
|
||||
<default>false</default>
|
||||
</entry>
|
||||
<entry name="autoTilerCarousel2" type="Bool">
|
||||
<default>false</default>
|
||||
</entry>
|
||||
<entry name="autoTilerCarousel3" type="Bool">
|
||||
<default>false</default>
|
||||
</entry>
|
||||
<entry name="suggestionsVisibility" type="Int">
|
||||
<default>0</default>
|
||||
</entry>
|
||||
<entry name="suggestionsMode" type="Int">
|
||||
<default>0</default>
|
||||
</entry>
|
||||
<entry name="suggestOtherScreens" type="Bool">
|
||||
<default>false</default>
|
||||
</entry>
|
||||
<entry name="suggestOtherDesktops" type="Bool">
|
||||
<default>false</default>
|
||||
</entry>
|
||||
<entry name="suggestOtherActivities" type="Bool">
|
||||
<default>false</default>
|
||||
</entry>
|
||||
<entry name="suggestAutoTiled" type="Bool">
|
||||
<default>false</default>
|
||||
</entry>
|
||||
<entry name="suggestMinimized" type="Bool">
|
||||
<default>false</default>
|
||||
</entry>
|
||||
</group>
|
||||
</kcfg>
|
||||
+1763
File diff suppressed because it is too large
Load Diff
+239
@@ -0,0 +1,239 @@
|
||||
import QtQuick
|
||||
import org.kde.kirigami as Kirigami
|
||||
|
||||
Item {
|
||||
Kirigami.Theme.colorSet: Kirigami.Theme.View
|
||||
|
||||
property bool lightTheme: {
|
||||
return Kirigami.ColorUtils.brightnessForColor(Kirigami.Theme.backgroundColor) === Kirigami.ColorUtils.Light;
|
||||
}
|
||||
|
||||
property var backgroundColor: {
|
||||
switch (config.theme) {
|
||||
case 1:
|
||||
return "#161925";
|
||||
case 2:
|
||||
return "#110B00";
|
||||
case 3:
|
||||
return "#FFFFFF";
|
||||
case 4:
|
||||
return "#110000";
|
||||
case 5:
|
||||
return "#020900";
|
||||
case 6:
|
||||
return "#0A0010";
|
||||
case 7:
|
||||
return "#001100";
|
||||
case 8:
|
||||
return "#111100";
|
||||
case 9:
|
||||
return "#000710";
|
||||
default:
|
||||
return Kirigami.Theme.backgroundColor;
|
||||
}
|
||||
}
|
||||
|
||||
property var borderColor: {
|
||||
switch (config.theme) {
|
||||
case 1:
|
||||
return "#666666";
|
||||
case 2:
|
||||
return "#7F4F00";
|
||||
case 3:
|
||||
return "#777777";
|
||||
case 4:
|
||||
return "#780000";
|
||||
case 5:
|
||||
return "#587C00";
|
||||
case 6:
|
||||
return "#4A0076";
|
||||
case 7:
|
||||
return "#225522";
|
||||
case 8:
|
||||
return "#555500";
|
||||
case 9:
|
||||
return "#004093";
|
||||
default:
|
||||
if (lightTheme) {
|
||||
return Kirigami.ColorUtils.tintWithAlpha(Kirigami.Theme.backgroundColor, "black", 0.2);
|
||||
} else {
|
||||
return Kirigami.ColorUtils.tintWithAlpha(Kirigami.Theme.backgroundColor, "white", 0.2);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
property var textColor: {
|
||||
switch (config.theme) {
|
||||
case 1:
|
||||
return "white";
|
||||
case 2:
|
||||
return "white";
|
||||
case 3:
|
||||
return "black";
|
||||
case 4:
|
||||
return "white";
|
||||
case 5:
|
||||
return "white";
|
||||
case 6:
|
||||
return "white";
|
||||
case 7:
|
||||
return "white";
|
||||
case 8:
|
||||
return "white";
|
||||
case 9:
|
||||
return "white";
|
||||
default:
|
||||
return lightTheme ? "black" : "white";
|
||||
}
|
||||
}
|
||||
|
||||
property var overlayTextColor: {
|
||||
switch (config.theme) {
|
||||
case 1:
|
||||
return "white";
|
||||
case 2:
|
||||
return "white";
|
||||
case 3:
|
||||
return "black";
|
||||
case 4:
|
||||
return "black";
|
||||
case 5:
|
||||
return "black";
|
||||
case 6:
|
||||
return "white";
|
||||
case 7:
|
||||
return "black";
|
||||
case 8:
|
||||
return "black";
|
||||
case 9:
|
||||
return "white";
|
||||
default:
|
||||
return lightTheme ? "black" : "white";
|
||||
}
|
||||
}
|
||||
|
||||
property var hintBackgroundColor: {
|
||||
switch (config.theme) {
|
||||
case 1:
|
||||
return "#590099FF";
|
||||
case 2:
|
||||
return "#59FF9F00";
|
||||
case 3:
|
||||
return "#59FF0000";
|
||||
case 4:
|
||||
return "#59FF0000";
|
||||
case 5:
|
||||
return "#59B5FF00";
|
||||
case 6:
|
||||
return "#599F00FF";
|
||||
case 7:
|
||||
return "#5900FF00";
|
||||
case 8:
|
||||
return "#59FFFF00";
|
||||
case 9:
|
||||
return "#590067FF";
|
||||
default:
|
||||
return Kirigami.ColorUtils.tintWithAlpha("transparent", Kirigami.Theme.highlightColor, 0.35);
|
||||
}
|
||||
}
|
||||
|
||||
property var tileBorderColor: {
|
||||
switch (config.theme) {
|
||||
case 1:
|
||||
return "#0099FF";
|
||||
case 2:
|
||||
return "#FF9F00";
|
||||
case 3:
|
||||
return "#FF0000";
|
||||
case 4:
|
||||
return "#FF0000";
|
||||
case 5:
|
||||
return "#B5FF00";
|
||||
case 6:
|
||||
return "#9F00FF";
|
||||
case 7:
|
||||
return "#00FF00";
|
||||
case 8:
|
||||
return "#FFFF00";
|
||||
case 9:
|
||||
return "#0067FF";
|
||||
default:
|
||||
return Kirigami.Theme.highlightColor;
|
||||
}
|
||||
}
|
||||
|
||||
property var tileBackgroundColor: {
|
||||
switch (config.theme) {
|
||||
case 1:
|
||||
return "#0C0099FF";
|
||||
case 2:
|
||||
return "#0CFF9F00";
|
||||
case 3:
|
||||
return "#3CFF0000";
|
||||
case 4:
|
||||
return "#3CFF0000";
|
||||
case 5:
|
||||
return "#3CB5FF00";
|
||||
case 6:
|
||||
return "#3C9F00FF";
|
||||
case 7:
|
||||
return "#3C00FF00";
|
||||
case 8:
|
||||
return "#3CFFFF00";
|
||||
case 9:
|
||||
return "#3C0067FF";
|
||||
default:
|
||||
return Kirigami.ColorUtils.tintWithAlpha("transparent", Kirigami.Theme.highlightColor, 0.05);
|
||||
}
|
||||
}
|
||||
|
||||
property var tileBackgroundColorIntense: {
|
||||
switch (config.theme) {
|
||||
case 1:
|
||||
return "#3C0099FF";
|
||||
case 2:
|
||||
return "#3CFF9F00";
|
||||
case 3:
|
||||
return "#3CFF0000";
|
||||
case 4:
|
||||
return "#3CFF0000";
|
||||
case 5:
|
||||
return "#3CB5FF00";
|
||||
case 6:
|
||||
return "#3C9F00FF";
|
||||
case 7:
|
||||
return "#3C00FF00";
|
||||
case 8:
|
||||
return "#3CFFFF00";
|
||||
case 9:
|
||||
return "#3C0067FF";
|
||||
default:
|
||||
return Kirigami.ColorUtils.tintWithAlpha("transparent", Kirigami.Theme.highlightColor, 0.23);
|
||||
}
|
||||
}
|
||||
|
||||
property var tileBackgroundColorActive: {
|
||||
switch (config.theme) {
|
||||
case 1:
|
||||
return "#BE0099FF";
|
||||
case 2:
|
||||
return "#BEFF9F00";
|
||||
case 3:
|
||||
return "#BEFF0000";
|
||||
case 4:
|
||||
return "#BEFF0000";
|
||||
case 5:
|
||||
return "#BEB5FF00";
|
||||
case 6:
|
||||
return "#BE9F00FF";
|
||||
case 7:
|
||||
return "#BE00FF00";
|
||||
case 8:
|
||||
return "#BEFFFF00";
|
||||
case 9:
|
||||
return "#BE0067FF";
|
||||
default:
|
||||
return Kirigami.ColorUtils.tintWithAlpha("transparent", Kirigami.Theme.highlightColor, 0.75);
|
||||
}
|
||||
}
|
||||
}
|
||||
+182
@@ -0,0 +1,182 @@
|
||||
import QtQuick
|
||||
import QtQuick.Controls
|
||||
import QtQuick.Layouts
|
||||
import org.kde.kwin
|
||||
import org.kde.kirigami as Kirigami
|
||||
// import QtWebView
|
||||
|
||||
ApplicationWindow {
|
||||
property var overrides: {}
|
||||
property var currentOverrides: {}
|
||||
property var currentApplications: []
|
||||
property var currentWindows: []
|
||||
property var defaultConfig: {}
|
||||
property var currentApplicationIndex: -1
|
||||
property var currentWindowIndex: -1
|
||||
// property var isX11: Qt.platform.pluginName == 'xcb'
|
||||
property var mouseStartX
|
||||
property var mouseStartY
|
||||
property var windowStartX
|
||||
property var windowStartY
|
||||
|
||||
Kirigami.Theme.colorSet: Kirigami.Theme.Window
|
||||
|
||||
property var lightTheme: {
|
||||
return Kirigami.ColorUtils.brightnessForColor(Kirigami.Theme.backgroundColor) === Kirigami.ColorUtils.Light;
|
||||
}
|
||||
|
||||
property var headerColor: {
|
||||
if (lightTheme) {
|
||||
return Kirigami.ColorUtils.tintWithAlpha(Kirigami.Theme.backgroundColor, "white", 0.4);
|
||||
} else {
|
||||
return Kirigami.ColorUtils.tintWithAlpha(Kirigami.Theme.backgroundColor, "black", 0.3);
|
||||
}
|
||||
}
|
||||
|
||||
property var headerBorderColor: {
|
||||
if (lightTheme) {
|
||||
return Kirigami.ColorUtils.tintWithAlpha(Kirigami.Theme.backgroundColor, "black", 0.2);
|
||||
} else {
|
||||
return Kirigami.ColorUtils.tintWithAlpha(Kirigami.Theme.backgroundColor, "white", 0.2);
|
||||
}
|
||||
}
|
||||
|
||||
id: mainMenuRoot
|
||||
width: 1000
|
||||
height: 734
|
||||
title: "Mouse Tiler Configuration"
|
||||
color: Kirigami.Theme.backgroundColor
|
||||
flags: Qt.FramelessWindowHint | Qt.Window | Qt.BypassWindowManagerHint
|
||||
// flags: ixX11 ? Qt.X11BypassWindowManagerHint : flags
|
||||
|
||||
// x: isX11 ? Workspace.virtualScreenSize.width / 2 - width / 2 : x
|
||||
// y: isX11 ? Workspace.virtualScreenSize.height / 2 - height / 2 : y
|
||||
x: Workspace.virtualScreenSize.width / 2 - width / 2
|
||||
y: Workspace.virtualScreenSize.height / 2 - height / 2
|
||||
|
||||
function initMainMenu() {
|
||||
}
|
||||
|
||||
Rectangle {
|
||||
color: headerColor
|
||||
height: 34
|
||||
anchors.top: parent.top
|
||||
anchors.left: parent.left
|
||||
anchors.right: parent.right
|
||||
border.color: headerBorderColor
|
||||
border.width: 1
|
||||
|
||||
MouseArea {
|
||||
anchors.fill: parent
|
||||
acceptedButtons: Qt.LeftButton
|
||||
|
||||
onPressed: {
|
||||
mouseStartX = Workspace.cursorPos.x;
|
||||
mouseStartY = Workspace.cursorPos.y;
|
||||
windowStartX = mainMenuRoot.x;
|
||||
windowStartY = mainMenuRoot.y;
|
||||
}
|
||||
|
||||
onPositionChanged: {
|
||||
mainMenuRoot.x = windowStartX + (Workspace.cursorPos.x - mouseStartX);
|
||||
mainMenuRoot.y = windowStartY + (Workspace.cursorPos.y - mouseStartY);
|
||||
}
|
||||
|
||||
onReleased: {
|
||||
mainMenuRoot.x = windowStartX + (Workspace.cursorPos.x - mouseStartX);
|
||||
mainMenuRoot.y = windowStartY + (Workspace.cursorPos.y - mouseStartY);
|
||||
}
|
||||
|
||||
Label {
|
||||
text: "Mouse Tiler Configuration"
|
||||
anchors.centerIn: parent
|
||||
}
|
||||
|
||||
Button {
|
||||
text: "X"
|
||||
flat: true
|
||||
|
||||
width: 26
|
||||
height: 26
|
||||
anchors.right: parent.right
|
||||
anchors.top: parent.top
|
||||
anchors.margins: 4
|
||||
|
||||
onClicked: root.closeMainMenu()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
GroupBox {
|
||||
id: mainGroupBox
|
||||
anchors.fill: parent
|
||||
anchors.topMargin: 35
|
||||
|
||||
// WebView {
|
||||
// id: webView
|
||||
// anchors.fill: parent
|
||||
// url: "https://rxweb.epizy.com/mousetiler/editor.html"
|
||||
// }
|
||||
|
||||
ColumnLayout {
|
||||
id: mainChoice
|
||||
visible: true
|
||||
anchors.left: parent.left
|
||||
anchors.right: parent.right
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
|
||||
GroupBox {
|
||||
spacing: 5
|
||||
Layout.fillWidth: true
|
||||
|
||||
ColumnLayout {
|
||||
anchors.fill: parent
|
||||
|
||||
Label {
|
||||
Layout.fillWidth: true
|
||||
horizontalAlignment: Text.AlignHCenter
|
||||
text: "This was meant to be the UI designer. However it is a lot of work to implement it, probaly at least 1-2 weeks full time. Sadly I got rent to pay and a 3 year old son to feed and based on my previous project Remember Window Positions, I will not be able to feed us from my contributions to Linux. (After over 3 months full time work I earned $100 total which I apreciate but it's not possible to survive on). I might implement it in the future if the situation changes."
|
||||
wrapMode: Text.WordWrap
|
||||
}
|
||||
|
||||
// Label {
|
||||
// Layout.fillWidth: true
|
||||
// text: "Not implemented yet"
|
||||
// wrapMode: Text.WordWrap
|
||||
// }
|
||||
}
|
||||
}
|
||||
|
||||
// GroupBox {
|
||||
// spacing: 5
|
||||
// Layout.fillWidth: true
|
||||
|
||||
// ColumnLayout {
|
||||
// anchors.fill: parent
|
||||
|
||||
// Label {
|
||||
// Layout.fillWidth: true
|
||||
// horizontalAlignment: Text.AlignHCenter
|
||||
// text: "."
|
||||
// wrapMode: Text.WordWrap
|
||||
// }
|
||||
|
||||
// Button {
|
||||
// id: selectWindowButton
|
||||
// text: "Select Application/Window"
|
||||
// Layout.fillWidth: true
|
||||
|
||||
// onClicked: selectWindow()
|
||||
// }
|
||||
|
||||
// Button {
|
||||
// text: "Edit Saved Applications and Windows"
|
||||
// Layout.fillWidth: true
|
||||
|
||||
// onClicked: editSavedAppOrWindow()
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
}
|
||||
}
|
||||
}
|
||||
+319
@@ -0,0 +1,319 @@
|
||||
import QtQuick
|
||||
import org.kde.kwin
|
||||
import org.kde.plasma.core as PlasmaCore
|
||||
|
||||
// Window {
|
||||
PlasmaCore.Dialog {
|
||||
id: overlayTiler
|
||||
|
||||
property var activeScreen: null
|
||||
property var clientArea: ({width: 1, height: 1, x: 0, y: 0})
|
||||
property var tilePadding: 2
|
||||
property int activeIndex: -1
|
||||
property int spanFromIndex: -1
|
||||
property int minSpanX: -1
|
||||
property int minSpanY: -1
|
||||
property int maxSpanX: -1
|
||||
property int maxSpanY: -1
|
||||
property var convertedOverlay: ([])
|
||||
|
||||
// Workaround for plasma 6.6 and earlier - needed by Window and Plasma Dialog - replaced by Qt.WindowTransparentForInput in Plasma 6.7
|
||||
property bool outputOnly: true
|
||||
|
||||
width: clientArea.width - root.config.overlayScreenEdgeMargin * 2
|
||||
height: clientArea.height - root.config.overlayScreenEdgeMargin * 2
|
||||
x: clientArea.x + root.config.overlayScreenEdgeMargin
|
||||
y: clientArea.y + root.config.overlayScreenEdgeMargin
|
||||
// flags: Qt.Popup | Qt.BypassWindowManagerHint | Qt.FramelessWindowHint
|
||||
// flags: Qt.Tool | Qt.BypassWindowManagerHint | Qt.FramelessWindowHint | Qt.WindowStaysOnTopHint | Qt.WindowDoesNotAcceptFocus
|
||||
flags: (root.config.displayAs == 0 ? 0 : Qt.Popup) | (Qt.BypassWindowManagerHint | Qt.FramelessWindowHint | Qt.WindowStaysOnTopHint | Qt.WindowDoesNotAcceptFocus | Qt.WindowTransparentForInput)
|
||||
// color: "transparent" // Window
|
||||
visible: false
|
||||
backgroundHints: PlasmaCore.Types.NoBackground // PlasmaCore.Dialog
|
||||
// outputOnly: true // PlasmaCore.Dialog
|
||||
// type: PlasmaCore.Dialog.OnScreenDisplay
|
||||
location: PlasmaCore.Types.Desktop // PlasmaCore.Dialog
|
||||
|
||||
function reset() {
|
||||
activeScreen = null;
|
||||
spanFromIndex = -1;
|
||||
activeIndex = -1;
|
||||
updateSpan();
|
||||
}
|
||||
|
||||
function startAnimations() {
|
||||
overlayTiler.opacity = 0;
|
||||
showOverlayTilerAnimation.start();
|
||||
}
|
||||
|
||||
function updateScreen() {
|
||||
if (activeScreen != Workspace.activeScreen) {
|
||||
autoTiler.updateShouldShowScreenEdges();
|
||||
root.logE('updateScreen ' + Workspace.virtualScreenSize);
|
||||
reset();
|
||||
activeScreen = Workspace.activeScreen;
|
||||
clientArea = Workspace.clientArea(KWin.FullScreenArea, activeScreen, Workspace.currentDesktop);
|
||||
convertLayoutToScreen();
|
||||
}
|
||||
}
|
||||
|
||||
function convertLayoutToScreen() {
|
||||
let layout = root.config.overlay;
|
||||
let converted = [];
|
||||
for (let i = 0; i < layout.length; i++) {
|
||||
let tile = layout[i];
|
||||
let width = (tile.pxW == undefined ? tile.w / 100 * mainItem.width : tile.pxW);
|
||||
let height = (tile.pxH == undefined ? tile.h / 100 * mainItem.height : tile.pxH);
|
||||
converted.push({
|
||||
pxX: (tile.pxX == undefined ? tile.x / 100 * mainItem.width : tile.pxX) - (tile.aX == undefined ? 0 : tile.aX * width / 100),
|
||||
pxY: (tile.pxY == undefined ? tile.y / 100 * mainItem.height : tile.pxY) - (tile.aY == undefined ? 0 : tile.aY * height / 100),
|
||||
pxW: width,
|
||||
pxH: height
|
||||
});
|
||||
}
|
||||
convertedOverlay = converted;
|
||||
}
|
||||
|
||||
function toggleSpan() {
|
||||
if (spanFromIndex != activeIndex && spanFromIndex == -1) {
|
||||
spanFromIndex = activeIndex;
|
||||
updateSpan();
|
||||
} else if (spanFromIndex >= 0) {
|
||||
spanFromIndex = -1;
|
||||
updateSpan();
|
||||
}
|
||||
}
|
||||
|
||||
function updateSpan() {
|
||||
if (activeIndex == -1 || spanFromIndex == -1) {
|
||||
minSpanX = -1;
|
||||
minSpanY = -1;
|
||||
maxSpanX = -1;
|
||||
maxSpanY = -1;
|
||||
} else {
|
||||
let itemActive = tileRepeater.itemAt(activeIndex);
|
||||
let itemSpan = tileRepeater.itemAt(spanFromIndex);
|
||||
minSpanX = Math.min(itemActive.x, itemSpan.x);
|
||||
minSpanY = Math.min(itemActive.y, itemSpan.y);
|
||||
maxSpanX = Math.max(itemActive.x + itemActive.width, itemSpan.x + itemSpan.width);
|
||||
maxSpanY = Math.max(itemActive.y + itemActive.height, itemSpan.y + itemSpan.height);
|
||||
}
|
||||
root.log('Span activeIndex: ' + activeIndex + ' spanFromIndex: ' + spanFromIndex + ' minSpanX: ' + minSpanX + ' minSpanY: ' + minSpanY + ' maxSpanX: ' + maxSpanX + ' maxSpanY: ' + maxSpanY);
|
||||
}
|
||||
|
||||
function getGeometry() {
|
||||
if (activeIndex >= 0) {
|
||||
let x, y, width, height;
|
||||
if (spanFromIndex >= 0) {
|
||||
x = clientArea.x + minSpanX;
|
||||
y = clientArea.y + minSpanY;
|
||||
width = maxSpanX - minSpanX;
|
||||
height = maxSpanY - minSpanY;
|
||||
} else {
|
||||
let item = tileRepeater.itemAt(activeIndex);
|
||||
x = clientArea.x + item.x;
|
||||
y = clientArea.y + item.y;
|
||||
width = item.width;
|
||||
height = item.height;
|
||||
}
|
||||
if (root.centerInTile) {
|
||||
return {
|
||||
x: x + width / 2 - root.currentlyMovedWindow.width / 2,
|
||||
y: y + height / 2 - root.currentlyMovedWindow.height / 2,
|
||||
width: root.currentlyMovedWindow.width,
|
||||
height: root.currentlyMovedWindow.height
|
||||
};
|
||||
} else {
|
||||
return {
|
||||
x: x,
|
||||
y: y,
|
||||
width: width,
|
||||
height: height
|
||||
};
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
function getActiveVirtualDesktopIndex() {
|
||||
return -1;
|
||||
}
|
||||
|
||||
Item {
|
||||
id: mainItem
|
||||
width: popupTiler.width
|
||||
height: popupTiler.height
|
||||
|
||||
SequentialAnimation {
|
||||
id: showOverlayTilerAnimation
|
||||
running: false
|
||||
|
||||
NumberAnimation {
|
||||
target: overlayTiler;
|
||||
property: "opacity";
|
||||
from: 0;
|
||||
to: 0;
|
||||
duration: 32;
|
||||
}
|
||||
|
||||
NumberAnimation {
|
||||
target: overlayTiler;
|
||||
property: "opacity";
|
||||
from: 1;
|
||||
to: 1;
|
||||
duration: 1;
|
||||
}
|
||||
|
||||
onFinished: {
|
||||
root.updateWindowVisibility();
|
||||
}
|
||||
}
|
||||
|
||||
Colors {
|
||||
id: colors
|
||||
}
|
||||
|
||||
Repeater {
|
||||
id: tileRepeater
|
||||
model: overlayTiler.convertedOverlay
|
||||
|
||||
Item {
|
||||
id: tile
|
||||
|
||||
property bool active: activeIndex == index
|
||||
property bool spanned: !active && Math.ceil(modelData.pxX) >= Math.floor(minSpanX) && Math.floor(modelData.pxX) + Math.floor(modelData.pxW) <= Math.ceil(maxSpanX) && Math.ceil(modelData.pxY) >= Math.floor(minSpanY) && Math.floor(modelData.pxY) + Math.floor(modelData.pxH) <= Math.ceil(maxSpanY)
|
||||
property bool spannedFrom: spanFromIndex == index
|
||||
|
||||
x: modelData.pxX
|
||||
y: modelData.pxY
|
||||
width: modelData.pxW
|
||||
height: modelData.pxH
|
||||
|
||||
Rectangle {
|
||||
anchors.fill: parent
|
||||
anchors.margins: tilePadding
|
||||
border.color: colors.tileBorderColor
|
||||
border.width: 2
|
||||
color: "transparent"
|
||||
radius: 12
|
||||
|
||||
Rectangle {
|
||||
anchors.fill: parent
|
||||
radius: 12
|
||||
color: active || spanned ? colors.tileBackgroundColorActive : colors.tileBackgroundColor
|
||||
}
|
||||
|
||||
Text {
|
||||
anchors.centerIn: parent
|
||||
color: colors.overlayTextColor
|
||||
textFormat: Text.StyledText
|
||||
text: {
|
||||
let defaultHint = "";
|
||||
let insertExtraBreak = false;
|
||||
|
||||
if (root.config.showHintHint) {
|
||||
defaultHint += (defaultHint.length > 0 ? "<br>" : "") + "Configure tiler visibility and these hints in settings.";
|
||||
insertExtraBreak = true;
|
||||
}
|
||||
if (root.config.hintShowAllSpan) {
|
||||
if (insertExtraBreak) {
|
||||
defaultHint += "<br>";
|
||||
insertExtraBreak = false;
|
||||
}
|
||||
defaultHint += (defaultHint.length > 0 ? "<br>" : "") + (spannedFrom ? "Stop spanning (<b>" + root.config.shortcutShowAllSpan + "</b>)" : "Span from this tile (<b>" + root.config.shortcutShowAllSpan + "</b>)");
|
||||
insertExtraBreak = true;
|
||||
}
|
||||
if (root.config.hintVisibility) {
|
||||
if (insertExtraBreak) {
|
||||
defaultHint += "<br>";
|
||||
insertExtraBreak = false;
|
||||
}
|
||||
defaultHint += (defaultHint.length > 0 ? "<br>" : "") + "Toggle visibility (<b>" + root.config.shortcutVisibility + "</b>)";
|
||||
}
|
||||
if (root.config.hintInputType) {
|
||||
if (insertExtraBreak) {
|
||||
defaultHint += "<br>";
|
||||
insertExtraBreak = false;
|
||||
}
|
||||
defaultHint += (defaultHint.length > 0 ? "<br>" : "") + "Input type: " + (root.useMouseCursor ? "Mouse" : "Window") + " (<b>" + root.config.shortcutInputType + "</b>)";
|
||||
}
|
||||
if (root.config.hintCenterInTile) {
|
||||
if (insertExtraBreak) {
|
||||
defaultHint += "<br>";
|
||||
insertExtraBreak = false;
|
||||
}
|
||||
defaultHint += (defaultHint.length > 0 ? "<br>" : "") + "Center in tile: " + (root.centerInTile ? "Enabled" : "Disabled") + " (<b>" + root.config.shortcutCenterInTile + "</b>)";
|
||||
}
|
||||
if (root.config.hintChangeMode) {
|
||||
insertExtraBreak = false;
|
||||
defaultHint += (defaultHint.length > 0 ? "<br><br>" : "") + "Switch mode (<b>" + root.config.shortcutChangeMode + "</b>)";
|
||||
}
|
||||
|
||||
if (root.centerInTile) {
|
||||
return (spannedFrom ? "<b>Center in spanned tiles</b><br><br>" : "<b>Center in this tile</b><br><br>") + defaultHint;
|
||||
} else {
|
||||
return defaultHint;
|
||||
}
|
||||
return defaultHint;
|
||||
}
|
||||
font.pixelSize: 16
|
||||
font.family: "Noto Sans"
|
||||
horizontalAlignment: Text.AlignHCenter
|
||||
visible: root.config.showOverlayTextHint && (active && spanFromIndex == -1 || spannedFrom)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Rectangle {
|
||||
id: popupWindowCursor
|
||||
anchors.left: parent.left
|
||||
anchors.leftMargin: root.getCursorPosition().x - clientArea.x - 6
|
||||
anchors.top: parent.top
|
||||
anchors.topMargin: root.getCursorPosition().y - clientArea.y - 6
|
||||
width: 12
|
||||
height: 12
|
||||
border.color: colors.tileBorderColor
|
||||
border.width: 2
|
||||
color: colors.tileBackgroundColorActive
|
||||
radius: 6
|
||||
visible: !root.useMouseCursor
|
||||
|
||||
Rectangle {
|
||||
anchors.centerIn: parent
|
||||
width: 2
|
||||
height: 2
|
||||
color: colors.textColor
|
||||
radius: 1
|
||||
opacity: 0.8
|
||||
}
|
||||
}
|
||||
|
||||
Timer {
|
||||
interval: root.config.overlayPollingRate
|
||||
repeat: true
|
||||
running: overlayTiler.visible
|
||||
onTriggered: {
|
||||
updateScreen();
|
||||
|
||||
let localCursorPos = Workspace.activeScreen.mapFromGlobal(root.getCursorPosition());
|
||||
let x = localCursorPos.x - root.config.overlayScreenEdgeMargin;
|
||||
let y = localCursorPos.y - root.config.overlayScreenEdgeMargin;
|
||||
let index = -1;
|
||||
|
||||
for (let i = 0; i < tileRepeater.count; i++) {
|
||||
let item = tileRepeater.itemAt(i);
|
||||
if (item.x <= x && item.x + item.width >= x && item.y <= y && item.y + item.height >= y) {
|
||||
index = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (index != activeIndex) {
|
||||
activeIndex = index;
|
||||
updateSpan();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
+978
@@ -0,0 +1,978 @@
|
||||
import QtQuick
|
||||
import QtQuick.Layouts
|
||||
import org.kde.kwin
|
||||
import org.kde.plasma.core as PlasmaCore
|
||||
|
||||
// Window {
|
||||
PlasmaCore.Dialog {
|
||||
id: popupTiler
|
||||
|
||||
property var activeScreen: null
|
||||
property var clientArea: ({width: 1, height: 1, x: 0, y: 0})
|
||||
property int tilePadding: 2
|
||||
property int borderOffset: 2
|
||||
property int activeLayoutIndex: -1
|
||||
property int activeTileIndex: -1
|
||||
property int positionX: 0
|
||||
property int positionY: 0
|
||||
property bool showAll: false
|
||||
property bool lastShowAll: false
|
||||
property var hint: null
|
||||
property bool showPopupDropHint: false
|
||||
property bool hasValidPopupDropHint: false
|
||||
property var popupDropHintX: 0
|
||||
property var popupDropHintY: 0
|
||||
property var popupDropHintWidth: 0
|
||||
property var popupDropHintHeight: 0
|
||||
property bool popupDropHintIsCenterInTile: false
|
||||
property bool sizeEstablished: false
|
||||
property var revealBox: null
|
||||
property bool revealed: false
|
||||
property bool currentlyHovered: false
|
||||
property int activeVirtualDesktopIndex: -1
|
||||
property var activeVirtualDesktopHoverTime: -1
|
||||
property bool virtualDesktopVisibilityOverride: false
|
||||
// property bool shouldShowAutoTileScroll: false
|
||||
// property var scrollLeftTime: 0
|
||||
// property var scrollRightTime: 0
|
||||
|
||||
// Workaround for plasma 6.6 and earlier - needed by Window and Plasma Dialog - replaced by Qt.WindowTransparentForInput in Plasma 6.7
|
||||
property bool outputOnly: true
|
||||
|
||||
width: clientArea.width
|
||||
height: clientArea.height
|
||||
x: clientArea.x
|
||||
y: clientArea.y
|
||||
//flags: Qt.Popup | Qt.BypassWindowManagerHint | Qt.FramelessWindowHint
|
||||
// flags: Qt.Tool | Qt.BypassWindowManagerHint | Qt.FramelessWindowHint | Qt.WindowStaysOnTopHint | Qt.WindowDoesNotAcceptFocus
|
||||
flags: (root.config.displayAs == 0 ? 0 : Qt.Popup) | (Qt.BypassWindowManagerHint | Qt.FramelessWindowHint | Qt.WindowStaysOnTopHint | Qt.WindowDoesNotAcceptFocus | Qt.WindowTransparentForInput)
|
||||
// color: "transparent" // Window
|
||||
visible: false
|
||||
backgroundHints: PlasmaCore.Types.NoBackground // PlasmaCore.Dialog
|
||||
// outputOnly: true // PlasmaCore.Dialog
|
||||
// type: PlasmaCore.Dialog.OnScreenDisplay
|
||||
location: PlasmaCore.Types.Desktop // PlasmaCore.Dialog
|
||||
|
||||
function reset() {
|
||||
activeScreen = null;
|
||||
activeLayoutIndex = -1;
|
||||
activeTileIndex = -1;
|
||||
hint = null;
|
||||
showPopupDropHint = false;
|
||||
updateHintContent();
|
||||
}
|
||||
|
||||
function resetShowAll() {
|
||||
showAll = false;
|
||||
lastShowAll = false;
|
||||
}
|
||||
|
||||
function startAnimations() {
|
||||
popupTiler.opacity = 0;
|
||||
showPopupTilerAnimation.start();
|
||||
}
|
||||
|
||||
function updateScreen(forceUpdate = false) {
|
||||
if (forceUpdate || activeScreen != Workspace.activeScreen) {
|
||||
root.logE('updateScreen ' + Workspace.virtualScreenSize);
|
||||
if (activeScreen != Workspace.activeScreen) {
|
||||
autoTiler.updateAutoTilersInPopupTiler();
|
||||
}
|
||||
autoTiler.updateShouldShowScreenEdges();
|
||||
// shouldShowAutoTileScroll = autoTiler.shouldShowAutoTileScroll();
|
||||
activeScreen = Workspace.activeScreen;
|
||||
clientArea = Workspace.clientArea(KWin.FullScreenArea, Workspace.activeScreen, Workspace.currentDesktop);
|
||||
|
||||
let localCursorPos = Workspace.activeScreen.mapFromGlobal(root.getCursorPosition());
|
||||
|
||||
let visibleHeight = virtualDesktopVisibilityOverride || root.config.virtualDesktopVisibility != 1 ? layouts.height : 0;
|
||||
|
||||
if (root.config.popupGridAt == 0) {
|
||||
switch (root.config.horizontalAlignment) {
|
||||
default:
|
||||
positionX = localCursorPos.x - root.config.gridWidth / 2 - root.config.gridSpacing;
|
||||
break;
|
||||
case 1:
|
||||
positionX = localCursorPos.x - layouts.width / 2;
|
||||
break;
|
||||
case 2:
|
||||
positionX = localCursorPos.x - layouts.width + root.config.gridWidth / 2 + root.config.gridSpacing;
|
||||
break;
|
||||
}
|
||||
|
||||
if (visibleHeight == 0) {
|
||||
positionY = localCursorPos.y;
|
||||
} else {
|
||||
switch (root.config.verticalAlignment) {
|
||||
default:
|
||||
positionY = localCursorPos.y - root.config.gridHeight / 2 - root.config.gridSpacing;
|
||||
break;
|
||||
case 1:
|
||||
positionY = localCursorPos.y - layouts.height / 2;
|
||||
break;
|
||||
case 2:
|
||||
positionY = localCursorPos.y - layouts.height + root.config.gridHeight / 2 + root.config.gridSpacing;
|
||||
break;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
switch (root.config.horizontalAlignment) {
|
||||
default:
|
||||
positionX = 0;
|
||||
break;
|
||||
case 1:
|
||||
positionX = clientArea.width / 2 - layouts.width / 2;
|
||||
break;
|
||||
case 2:
|
||||
positionX = clientArea.width - layouts.width;
|
||||
break;
|
||||
}
|
||||
|
||||
switch (root.config.verticalAlignment) {
|
||||
default:
|
||||
positionY = 0;
|
||||
break;
|
||||
case 1:
|
||||
positionY = clientArea.height / 2 - visibleHeight / 2;
|
||||
break;
|
||||
case 2:
|
||||
positionY = clientArea.height - visibleHeight;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// positionX = localCursorPos.x - layouts.width / 2;
|
||||
// positionY = localCursorPos.y - (layouts.height + popupHint.height + 2) / 2;
|
||||
|
||||
if (positionX < 0) {
|
||||
positionX = 0;
|
||||
} else if (positionX + layouts.width > popupTiler.width) {
|
||||
positionX = popupTiler.width - layouts.width;
|
||||
}
|
||||
|
||||
let totalHeight = visibleHeight;
|
||||
if (root.virtualDesktopVisibile) {
|
||||
if (totalHeight > 0) {
|
||||
totalHeight += 2;
|
||||
}
|
||||
totalHeight += virtualDesktop.height;
|
||||
}
|
||||
if (root.config.showTextHint) {
|
||||
totalHeight += popupHint.height + 2;
|
||||
}
|
||||
|
||||
if (positionY < 0) {
|
||||
positionY = 0;
|
||||
} else if (positionY + totalHeight > popupTiler.height) {
|
||||
positionY = popupTiler.height - totalHeight;
|
||||
}
|
||||
|
||||
if (root.config.tilerVisibility == 3) {
|
||||
let triggerLeft = Math.max(positionX - config.revealMargin, 0);
|
||||
let triggerRight = Math.min(positionX + layouts.width + config.revealMargin, popupTiler.width);
|
||||
let triggerTop = Math.max(positionY - config.revealMargin, 0);
|
||||
let triggerBottom = Math.min(positionY + totalHeight + config.revealMargin, popupTiler.height);
|
||||
let leftTop = Workspace.activeScreen.mapToGlobal(Qt.point(triggerLeft, triggerTop));
|
||||
let rightBottom = Workspace.activeScreen.mapToGlobal(Qt.point(triggerRight, triggerBottom));
|
||||
revealBox = { left: leftTop.x, right: rightBottom.x, top: leftTop.y, bottom: rightBottom.y };
|
||||
updateRevealed(true);
|
||||
} else {
|
||||
revealBox = null;
|
||||
updateRevealed(true);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function getGeometry() {
|
||||
if (activeLayoutIndex >= 0 && activeTileIndex >= 0) {
|
||||
if (root.centerInTile && hasValidPopupDropHint) {
|
||||
return {
|
||||
x: clientArea.x + popupDropHintX,
|
||||
y: clientArea.y + popupDropHintY,
|
||||
width: popupDropHintWidth,
|
||||
height: popupDropHintHeight
|
||||
};
|
||||
} else if (layoutRepeater.model[activeLayoutIndex].special) {
|
||||
return {
|
||||
special: layoutRepeater.model[activeLayoutIndex].special,
|
||||
specialMode: activeTileIndex
|
||||
};
|
||||
} else if (!root.centerInTile) {
|
||||
return {
|
||||
x: clientArea.x + popupDropHintX,
|
||||
y: clientArea.y + popupDropHintY,
|
||||
width: popupDropHintWidth,
|
||||
height: popupDropHintHeight,
|
||||
defaultLayouts: !showAll,
|
||||
layoutIndex: activeLayoutIndex,
|
||||
tileIndex: activeTileIndex
|
||||
};
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
function getActiveVirtualDesktopIndex() {
|
||||
return activeVirtualDesktopIndex;
|
||||
}
|
||||
|
||||
function resetVirtualDesktopOverride() {
|
||||
virtualDesktopVisibilityOverride = false;
|
||||
}
|
||||
|
||||
function toggleShowAll() {
|
||||
reset();
|
||||
if (root.config.virtualDesktopVisibility == 1 && !virtualDesktopVisibilityOverride) {
|
||||
virtualDesktopVisibilityOverride = true;
|
||||
} else {
|
||||
showAll = !showAll;
|
||||
updateHintContent();
|
||||
}
|
||||
}
|
||||
|
||||
function updateAndShowPopupDropHint() {
|
||||
let shouldShowPopupDropHint = false;
|
||||
let special = layoutRepeater.model[activeLayoutIndex].special;
|
||||
let geometry = null;
|
||||
switch (special) {
|
||||
case 'SPECIAL_FILL':
|
||||
if (root.currentlyMovedWindow != null) {
|
||||
geometry = root.getFillGeometry(root.currentlyMovedWindow, activeTileIndex == 0);
|
||||
}
|
||||
break;
|
||||
case 'SPECIAL_SPLIT_VERTICAL':
|
||||
if (root.currentlyMovedWindow != null) {
|
||||
geometry = splitAndMoveSplitted(root.currentlyMovedWindow, true, activeTileIndex == 0, false);
|
||||
}
|
||||
break;
|
||||
case 'SPECIAL_SPLIT_HORIZONTAL':
|
||||
if (root.currentlyMovedWindow != null) {
|
||||
geometry = splitAndMoveSplitted(root.currentlyMovedWindow, false, activeTileIndex == 0, false);
|
||||
}
|
||||
break;
|
||||
case 'SPECIAL_NO_TITLEBAR_AND_FRAME':
|
||||
case 'SPECIAL_KEEP_ABOVE':
|
||||
case 'SPECIAL_KEEP_BELOW':
|
||||
case 'SPECIAL_EMPTY':
|
||||
case 'SPECIAL_MINIMIZE':
|
||||
case 'SPECIAL_CLOSE':
|
||||
case 'SPECIAL_AUTO_TILER_TOGGLE':
|
||||
break;
|
||||
case 'SPECIAL_AUTO_TILER_1':
|
||||
case 'SPECIAL_AUTO_TILER_2':
|
||||
case 'SPECIAL_AUTO_TILER_3':
|
||||
if (!layoutRepeater.model[activeLayoutIndex].activeAutoTiler) {
|
||||
break;
|
||||
}
|
||||
default:
|
||||
let layout = layoutRepeater.model[activeLayoutIndex].tiles[activeTileIndex];
|
||||
let hintWidth = layout.w == undefined ? layout.pxW : layout.w / 100 * clientArea.width;
|
||||
let hintHeight = layout.h == undefined ? layout.pxH : layout.h / 100 * clientArea.height;
|
||||
let hintX = (layout.x == undefined ? layout.pxX : layout.x / 100 * clientArea.width) - (layout.aX == undefined ? 0 : layout.aX * hintWidth / 100);
|
||||
let hintY = (layout.y == undefined ? layout.pxY : layout.y / 100 * clientArea.height) - (layout.aY == undefined ? 0 : layout.aY * hintHeight / 100);
|
||||
if (root.centerInTile) {
|
||||
popupDropHintWidth = root.currentlyMovedWindow.width;
|
||||
popupDropHintHeight = root.currentlyMovedWindow.height;
|
||||
popupDropHintX = hintX + hintWidth / 2 - root.currentlyMovedWindow.width / 2;
|
||||
popupDropHintY = hintY + hintHeight / 2 - root.currentlyMovedWindow.height / 2;
|
||||
} else {
|
||||
popupDropHintWidth = hintWidth;
|
||||
popupDropHintHeight = hintHeight;
|
||||
popupDropHintX = hintX;
|
||||
popupDropHintY = hintY;
|
||||
}
|
||||
showPopupDropHint = root.config.showTargetTileHint;
|
||||
hasValidPopupDropHint = true;
|
||||
return; // Force return to avoid hiding popup
|
||||
}
|
||||
if (geometry != null) {
|
||||
if (root.centerInTile) {
|
||||
popupDropHintX = (geometry.x - clientArea.x) + geometry.width / 2 - root.currentlyMovedWindow.width / 2;
|
||||
popupDropHintY = (geometry.y - clientArea.y) + geometry.height / 2 - root.currentlyMovedWindow.height / 2;
|
||||
popupDropHintWidth = root.currentlyMovedWindow.width;
|
||||
popupDropHintHeight = root.currentlyMovedWindow.height;
|
||||
shouldShowPopupDropHint = true;
|
||||
} else {
|
||||
popupDropHintX = geometry.x - clientArea.x;
|
||||
popupDropHintY = geometry.y - clientArea.y;
|
||||
popupDropHintWidth = geometry.width;
|
||||
popupDropHintHeight = geometry.height;
|
||||
shouldShowPopupDropHint = true;
|
||||
}
|
||||
}
|
||||
if (root.config.showTargetTileHint) {
|
||||
showPopupDropHint = shouldShowPopupDropHint;
|
||||
} else {
|
||||
showPopupDropHint = false;
|
||||
}
|
||||
hasValidPopupDropHint = shouldShowPopupDropHint;
|
||||
}
|
||||
|
||||
function updateHintContent() {
|
||||
if (activeVirtualDesktopIndex >= 0) {
|
||||
hasValidPopupDropHint = false;
|
||||
showPopupDropHint = false;
|
||||
if (root.virtualDesktops[activeVirtualDesktopIndex].isAdd) {
|
||||
switch (config.virtualDesktopDropAction) {
|
||||
case 0:
|
||||
if (root.moveToVirtualDesktopOnDrop) {
|
||||
// hint = '<b>Drop</b> - Switch to a new virtual desktop, and move window';
|
||||
hint = '<b>Drop</b> - Move window to a new virtual desktop, and switch to it';
|
||||
} else {
|
||||
// hint = '<b>Drop</b> - Add new virtual desktop, and move window';
|
||||
// hint = '<b>Drop</b> - Move window to a new virtual desktop without switching';
|
||||
hint = '<b>Drop</b> - Move window to a new virtual desktop then go back to ' + root.virtualDesktopAtMoveStart.name;
|
||||
}
|
||||
break;
|
||||
case 1:
|
||||
if (root.moveToVirtualDesktopOnDrop) {
|
||||
// hint = '<b>Drop</b> - Switch to a new virtual desktop, and maximize window';
|
||||
hint = '<b>Drop</b> - Maximize window on a new virtual desktop, and switch to it';
|
||||
} else {
|
||||
// hint = '<b>Drop</b> - Add new virtual desktop, and maximize window';
|
||||
// hint = '<b>Drop</b> - Maximize window on a new virtual desktop without switching';
|
||||
hint = '<b>Drop</b> - Maximize window on a new virtual desktop then go back to ' + root.virtualDesktopAtMoveStart.name;
|
||||
}
|
||||
break;
|
||||
}
|
||||
if (root.config.hintMoveOnDrop) {
|
||||
hint += ' (<b>' + root.config.shortcutMoveOnDrop + '</b>)';
|
||||
}
|
||||
} else {
|
||||
let virtualDesktopName = root.virtualDesktops[activeVirtualDesktopIndex].desktop.name;
|
||||
let virtualDesktopHoverChanged = activeVirtualDesktopIndex != root.virtualDesktopIndexAtMoveStart;
|
||||
switch (config.virtualDesktopDropAction) {
|
||||
case 0:
|
||||
if (!virtualDesktopHoverChanged) {
|
||||
hint = '<b>Drop</b> - Cancel move';
|
||||
} else if (root.moveToVirtualDesktopOnDrop) {
|
||||
// hint = '<b>Hover</b> - Switch to ' + virtualDesktopName + '<br><b>Drop</b> - Move window, and switch to ' + virtualDesktopName;
|
||||
hint = '<b>Drop</b> - Move window to ' + virtualDesktopName + ', and switch to it';
|
||||
} else {
|
||||
// hint = '<b>Hover</b> - Switch to ' + virtualDesktopName + '<br><b>Drop</b> - Move window to ' + virtualDesktopName;
|
||||
// hint = '<b>Hover</b> - Switch to ' + virtualDesktopName + '<br><b>Drop</b> - Move window to ' + virtualDesktopName + ' without switching';
|
||||
hint = '<b>Drop</b> - Move window to ' + virtualDesktopName + ' then go back to ' + root.virtualDesktopAtMoveStart.name;
|
||||
}
|
||||
break;
|
||||
case 1:
|
||||
if (!virtualDesktopHoverChanged) {
|
||||
hint = '<b>Drop</b> - Maximize window on current virtual desktop';
|
||||
} else if (root.moveToVirtualDesktopOnDrop) {
|
||||
// hint = '<b>Hover</b> - Switch to ' + virtualDesktopName + '<br><b>Drop</b> - Maximize window on, and switch to ' + virtualDesktopName;
|
||||
hint = '<b>Drop</b> - Maximize window on ' + virtualDesktopName + ', and switch to it';
|
||||
} else {
|
||||
// hint = '<b>Hover</b> - Switch to ' + virtualDesktopName + '<br><b>Drop</b> - Maximize window on ' + virtualDesktopName;
|
||||
// hint = '<b>Hover</b> - Switch to ' + virtualDesktopName + '<br><b>Drop</b> - Maximize window on ' + virtualDesktopName + ' without switching';
|
||||
hint = '<b>Drop</b> - Maximize window on ' + virtualDesktopName + ' then go back to ' + root.virtualDesktopAtMoveStart.name;
|
||||
}
|
||||
break;
|
||||
}
|
||||
if (virtualDesktopHoverChanged && root.config.hintMoveOnDrop) {
|
||||
hint += ' (<b>' + root.config.shortcutMoveOnDrop + '</b>)';
|
||||
}
|
||||
if (root.currentVirtualDesktopIndex != activeVirtualDesktopIndex) {
|
||||
hint += '<br><b>Hover</b> - Switch to ' + virtualDesktopName;
|
||||
}
|
||||
}
|
||||
} else if (!virtualDesktopVisibilityOverride && root.config.virtualDesktopVisibility == 1) {
|
||||
hint = "Show tiler (<b>" + root.config.shortcutShowAllSpan + "</b>)";
|
||||
hasValidPopupDropHint = false;
|
||||
showPopupDropHint = false;
|
||||
} else if (activeLayoutIndex >= 0 && activeTileIndex >= 0) {
|
||||
updateAndShowPopupDropHint();
|
||||
popupDropHintIsCenterInTile = root.centerInTile;
|
||||
let special = layoutRepeater.model[activeLayoutIndex].special;
|
||||
let tile = layoutRepeater.model[activeLayoutIndex].tiles[activeTileIndex];
|
||||
if (root.centerInTile && hasValidPopupDropHint) {
|
||||
hint = '<b>Center in tile</b> - will not resize the window' + (root.config.hintCenterInTile ? '<br>Toggle with <b>' + root.config.shortcutCenterInTile + '</b>' : '');
|
||||
} else if (tile.hint) {
|
||||
switch (special) {
|
||||
case 'SPECIAL_KEEP_ABOVE':
|
||||
hint = tile.hint + '<br>Currently <b>' + (root.currentlyMovedWindow.keepAbove ? 'Enabled' : 'Disabled') + '</b>';
|
||||
break;
|
||||
case 'SPECIAL_KEEP_BELOW':
|
||||
hint = tile.hint + '<br>Currently <b>' + (root.currentlyMovedWindow.keepBelow ? 'Enabled' : 'Disabled') + '</b>';
|
||||
break;
|
||||
case 'SPECIAL_FILL':
|
||||
hint = hasValidPopupDropHint ? tile.hint : '<font color="orange">⚠</font> No free space available';
|
||||
break;
|
||||
case 'SPECIAL_SPLIT_HORIZONTAL':
|
||||
case 'SPECIAL_SPLIT_VERTICAL':
|
||||
hint = hasValidPopupDropHint ? tile.hint : '<font color="orange">⚠</font> No window available for splitting';
|
||||
break;
|
||||
case 'SPECIAL_AUTO_TILER_TOGGLE':
|
||||
hint = root.currentlyMovedWindow.mt_auto == undefined ? '<b>Enable</b> auto-tiling for this window' : '<b>Disable</b> auto-tiling for this window';
|
||||
break;
|
||||
default:
|
||||
hint = tile.hint;
|
||||
break;
|
||||
}
|
||||
} else if (layoutRepeater.model[activeLayoutIndex].activeAutoTiler == true && tile.t != '*') {
|
||||
hint = 'Auto-tile in this tile<br>Cycle auto-tiled windows with Ctrl+Alt+Left or Right';
|
||||
} else if (root.virtualDesktopChangedSinceMoveStart) {
|
||||
if (root.moveToVirtualDesktopOnTile) {
|
||||
hint = 'Tile window on current virtual dekstop';
|
||||
} else {
|
||||
hint = 'Tile window on ' + Workspace.currentDesktop.name + ' then go back to ' + root.virtualDesktopAtMoveStart.name;
|
||||
}
|
||||
if (root.config.hintMoveOnDrop) {
|
||||
hint += ' (<b>' + root.config.shortcutMoveOnDrop + '</b>)';
|
||||
}
|
||||
} else if ((root.config.showSizeHint || root.config.showPositionHint) && !special) {
|
||||
hint = '';
|
||||
|
||||
if (root.config.showPositionHint) {
|
||||
if (root.config.showPositionHintInPixels) {
|
||||
hint += 'X: <b>' + Math.round(popupDropHintX) + '</b> Y: <b>' + Math.round(popupDropHintY) + '</b>';
|
||||
} else {
|
||||
hint += 'X: <b>' + Math.round(100 * popupDropHintX / clientArea.width) + '</b>% Y: <b>' + Math.round(100 * popupDropHintY / clientArea.height) + '</b>%';
|
||||
}
|
||||
}
|
||||
if (root.config.showSizeHint) {
|
||||
if (hint.length > 0) {
|
||||
hint += '<br>';
|
||||
}
|
||||
if (root.config.showSizeHintInPixels) {
|
||||
hint += 'W: <b>' + Math.round(popupDropHintWidth) + '</b> H: <b>' + Math.round(popupDropHintHeight) + '</b>';
|
||||
} else {
|
||||
hint += 'W: <b>' + Math.round(100 * popupDropHintWidth / clientArea.width) + '</b>% H: <b>' + Math.round(100 * popupDropHintHeight / clientArea.height) + '</b>%';
|
||||
}
|
||||
}
|
||||
} else {
|
||||
hint = null;
|
||||
}
|
||||
} else {
|
||||
hasValidPopupDropHint = false;
|
||||
showPopupDropHint = false;
|
||||
hint = null;
|
||||
}
|
||||
|
||||
if (hint == null) {
|
||||
let defaultHint = "";
|
||||
let hasShortcutHint = false;
|
||||
|
||||
if (root.config.showHintHint) {
|
||||
defaultHint += (defaultHint.length > 0 ? " " : "") + "Configure tiler visibility and these hints in settings.<br>";
|
||||
}
|
||||
if (root.config.hintShowAllSpan) {
|
||||
defaultHint += (hasShortcutHint ? " - " : "") + (showAll ? "Show default (<b>" + root.config.shortcutShowAllSpan + "</b>)" : "Show all (<b>" + root.config.shortcutShowAllSpan + "</b>)");
|
||||
hasShortcutHint = true;
|
||||
}
|
||||
if (root.config.hintVisibility) {
|
||||
defaultHint += (hasShortcutHint ? " - " : "") + "Visibility (<b>" + root.config.shortcutVisibility + "</b>)";
|
||||
hasShortcutHint = true;
|
||||
}
|
||||
if (root.config.hintChangeMode) {
|
||||
defaultHint += (hasShortcutHint ? " - " : "") + "Mode (<b>" + root.config.shortcutChangeMode + "</b>)";
|
||||
hasShortcutHint = true;
|
||||
}
|
||||
if (root.config.hintInputType) {
|
||||
defaultHint += (hasShortcutHint ? " - " : "") + "Input type (<b>" + root.config.shortcutInputType + "</b>)";
|
||||
hasShortcutHint = true;
|
||||
}
|
||||
if (root.config.hintCenterInTile) {
|
||||
defaultHint += (hasShortcutHint ? " - " : "") + "Center in tile (<b>" + root.config.shortcutCenterInTile + "</b>)";
|
||||
hasShortcutHint = true;
|
||||
}
|
||||
if (root.config.hintToggleTilingSuggestions) {
|
||||
defaultHint += (hasShortcutHint ? " - " : "") + "Suggestions: <b>" + (settings.showTilingSuggestions ? "Enabled": "Disabled") + "</b> (<b>" + root.config.shortcutToggleTilingSuggestions + "</b>)";
|
||||
hasShortcutHint = true;
|
||||
}
|
||||
|
||||
if (defaultHint.length > 0) {
|
||||
hint = defaultHint;
|
||||
}
|
||||
}
|
||||
|
||||
if (root.useAutoTilerPreview) {
|
||||
if (root.validAutoTilerPreview) {
|
||||
hint = 'Valid auto tile configuration - good job! :)';
|
||||
} else {
|
||||
hint = '<font color="orange">⚠</font> <b>WARNING</b> <font color="orange">⚠</font> INVALID AUTO TILE CONFIGURATION';
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function updateRevealed(forceUpdate = false) {
|
||||
var updatedRevealed;
|
||||
if (revealBox == null) {
|
||||
updatedRevealed = true;
|
||||
} else {
|
||||
let x = root.getCursorPosition().x;
|
||||
let y = root.getCursorPosition().y;
|
||||
updatedRevealed = revealBox.left <= x && revealBox.right >= x && revealBox.top <= y && revealBox.bottom >= y;
|
||||
}
|
||||
|
||||
if (forceUpdate || updatedRevealed != revealed) {
|
||||
revealed = updatedRevealed;
|
||||
root.updateWindowVisibility();
|
||||
}
|
||||
}
|
||||
|
||||
Item {
|
||||
id: mainItem
|
||||
width: popupTiler.width
|
||||
height: popupTiler.height
|
||||
visible: revealed
|
||||
|
||||
SequentialAnimation {
|
||||
id: showPopupTilerAnimation
|
||||
running: false
|
||||
|
||||
NumberAnimation {
|
||||
target: popupTiler;
|
||||
property: "opacity";
|
||||
from: 0;
|
||||
to: 0;
|
||||
duration: 32;
|
||||
}
|
||||
|
||||
NumberAnimation {
|
||||
target: popupTiler;
|
||||
property: "opacity";
|
||||
from: 1;
|
||||
to: 1;
|
||||
duration: 1;
|
||||
}
|
||||
|
||||
onFinished: {
|
||||
root.updateWindowVisibility();
|
||||
}
|
||||
}
|
||||
|
||||
Colors {
|
||||
id: colors
|
||||
}
|
||||
|
||||
Rectangle {
|
||||
id: popupDropHint
|
||||
anchors.left: parent.left
|
||||
anchors.leftMargin: popupDropHintX
|
||||
anchors.top: parent.top
|
||||
anchors.topMargin: popupDropHintY
|
||||
width: popupDropHintWidth
|
||||
height: popupDropHintHeight
|
||||
border.color: colors.tileBorderColor
|
||||
border.width: 2
|
||||
color: "transparent"
|
||||
radius: 12
|
||||
visible: showPopupDropHint
|
||||
|
||||
Rectangle {
|
||||
anchors.fill: parent
|
||||
color: colors.hintBackgroundColor
|
||||
radius: 12
|
||||
}
|
||||
}
|
||||
|
||||
Rectangle {
|
||||
id: layouts
|
||||
width: layoutGrid.implicitWidth + layoutGrid.columnSpacing * 2
|
||||
height: layoutGrid.implicitHeight + layoutGrid.rowSpacing * 2
|
||||
color: root.config.gridTilerOpacity != 1 ? Qt.alpha(colors.backgroundColor, root.config.gridTilerOpacity) : colors.backgroundColor
|
||||
border.color: colors.borderColor
|
||||
border.width: 1
|
||||
radius: 8
|
||||
visible: virtualDesktopVisibilityOverride || root.config.virtualDesktopVisibility != 1
|
||||
|
||||
anchors.left: parent.left
|
||||
anchors.leftMargin: positionX
|
||||
anchors.top: parent.top
|
||||
anchors.topMargin: positionY
|
||||
|
||||
GridLayout {
|
||||
id: layoutGrid
|
||||
columns: showAll ? root.config.gridAllColumns : root.config.gridColumns
|
||||
columnSpacing: root.config.gridSpacing
|
||||
rowSpacing: root.config.gridSpacing
|
||||
anchors.fill: parent
|
||||
anchors.margins: root.config.gridSpacing
|
||||
uniformCellWidths: true
|
||||
uniformCellHeights: true
|
||||
|
||||
Repeater {
|
||||
id: layoutRepeater
|
||||
model: showAll ? root.popupGridAllLayouts : root.popupGridLayouts
|
||||
|
||||
Rectangle {
|
||||
id: tiles
|
||||
width: root.config.gridWidth
|
||||
height: root.config.gridHeight
|
||||
color: "transparent"
|
||||
border.color: modelData.activeAutoTiler ? colors.tileBorderColor : colors.borderColor
|
||||
border.width: 1
|
||||
radius: 8
|
||||
clip: modelData.clip == true
|
||||
|
||||
property bool layoutActive: activeLayoutIndex == index
|
||||
|
||||
Repeater {
|
||||
id: tileRepeater
|
||||
model: modelData.tiles
|
||||
|
||||
Item {
|
||||
id: tile
|
||||
|
||||
property bool tileActive: activeTileIndex == index
|
||||
property bool tileDisabled: modelData.d ? true : false
|
||||
|
||||
width: (modelData.w == undefined ? modelData.pxW / clientArea.width : modelData.w / 100) * (tiles.width - borderOffset * 2)
|
||||
height: (modelData.h == undefined ? modelData.pxH / clientArea.height : modelData.h / 100) * (tiles.height - borderOffset * 2)
|
||||
x: (modelData.x == undefined ? modelData.pxX / clientArea.width : modelData.x / 100) * (tiles.width - borderOffset * 2) + borderOffset - (modelData.aX == undefined ? 0 : modelData.aX * width / 100)
|
||||
y: (modelData.y == undefined ? modelData.pxY / clientArea.height : modelData.y / 100) * (tiles.height - borderOffset * 2) + borderOffset - (modelData.aY == undefined ? 0 : modelData.aY * height / 100)
|
||||
|
||||
Rectangle {
|
||||
anchors.fill: parent
|
||||
anchors.margins: tilePadding
|
||||
border.color: colors.tileBorderColor
|
||||
border.width: 1
|
||||
// color: "#152030"
|
||||
color: "transparent"
|
||||
radius: 6
|
||||
opacity: tileDisabled ? 0.3 : 1
|
||||
|
||||
Rectangle {
|
||||
anchors.fill: parent
|
||||
color: layoutActive && tileActive ? colors.tileBackgroundColorActive : colors.tileBackgroundColor
|
||||
radius: 6
|
||||
}
|
||||
|
||||
Text {
|
||||
anchors.centerIn: parent
|
||||
color: colors.textColor
|
||||
textFormat: Text.StyledText
|
||||
// ⸰ ·
|
||||
text: root.centerInTile && layoutActive && tileActive && hasValidPopupDropHint ? "⸰" : (modelData.t && modelData.t.length > 0 ? modelData.t : "")
|
||||
font.pixelSize: 14
|
||||
font.family: "Noto Sans"
|
||||
horizontalAlignment: Text.AlignHCenter
|
||||
visible: root.centerInTile && layoutActive && tileActive && hasValidPopupDropHint ? true : (modelData.t ? modelData.t : false)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Rectangle {
|
||||
// id: autoTilerScrollLeft
|
||||
|
||||
// width: 34 + layoutGrid.columnSpacing * 2
|
||||
// height: 34 + layoutGrid.columnSpacing * 2
|
||||
// color: root.config.gridTilerOpacity != 1 ? Qt.alpha(colors.backgroundColor, root.config.gridTilerOpacity) : colors.backgroundColor
|
||||
// border.color: colors.borderColor
|
||||
// border.width: 1
|
||||
// radius: 8
|
||||
// visible: layouts.visible
|
||||
// anchors.verticalCenter: layouts.verticalCenter
|
||||
// anchors.right: layouts.left
|
||||
// anchors.rightMargin: 2
|
||||
|
||||
|
||||
// Text {
|
||||
// anchors.centerIn: parent
|
||||
// color: colors.textColor
|
||||
// textFormat: Text.StyledText
|
||||
// text: "◀"
|
||||
// font.pixelSize: 14
|
||||
// font.family: "Noto Sans"
|
||||
// horizontalAlignment: Text.AlignHCenter
|
||||
// }
|
||||
// }
|
||||
|
||||
// Rectangle {
|
||||
// id: autoTilerScrollRight
|
||||
|
||||
// width: 34 + layoutGrid.columnSpacing * 2
|
||||
// height: 34 + layoutGrid.columnSpacing * 2
|
||||
// color: root.config.gridTilerOpacity != 1 ? Qt.alpha(colors.backgroundColor, root.config.gridTilerOpacity) : colors.backgroundColor
|
||||
// border.color: colors.borderColor
|
||||
// border.width: 1
|
||||
// radius: 8
|
||||
// visible: layouts.visible
|
||||
// anchors.verticalCenter: layouts.verticalCenter
|
||||
// anchors.left: layouts.right
|
||||
// anchors.leftMargin: 2
|
||||
|
||||
|
||||
// Text {
|
||||
// anchors.centerIn: parent
|
||||
// color: colors.textColor
|
||||
// textFormat: Text.StyledText
|
||||
// text: "▶"
|
||||
// font.pixelSize: 14
|
||||
// font.family: "Noto Sans"
|
||||
// horizontalAlignment: Text.AlignHCenter
|
||||
// }
|
||||
// }
|
||||
|
||||
Rectangle {
|
||||
id: virtualDesktop
|
||||
width: layoutGrid.implicitWidth + layoutGrid.columnSpacing * 2
|
||||
height: virtualDesktopLayout.implicitHeight + layoutGrid.rowSpacing * 2
|
||||
color: root.config.gridTilerOpacity != 1 ? Qt.alpha(colors.backgroundColor, root.config.gridTilerOpacity) : colors.backgroundColor
|
||||
border.color: colors.borderColor
|
||||
border.width: 1
|
||||
radius: 8
|
||||
visible: root.virtualDesktopVisibile
|
||||
|
||||
anchors.left: parent.left
|
||||
anchors.leftMargin: positionX
|
||||
anchors.top: layouts.visible ? layouts.bottom : parent.top
|
||||
anchors.topMargin: layouts.visible ? 2 : positionY
|
||||
|
||||
GridLayout {
|
||||
id: virtualDesktopLayout
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
anchors.horizontalCenter: parent.horizontalCenter
|
||||
rowSpacing: 1
|
||||
columnSpacing: 1
|
||||
columns: layoutGrid.implicitWidth / 35
|
||||
|
||||
Repeater {
|
||||
id: virtualDesktopRepeater
|
||||
model: root.virtualDesktops
|
||||
|
||||
Item {
|
||||
id: virtualDesktop
|
||||
|
||||
property bool currentVirtualDesktop: root.currentVirtualDesktopIndex == index
|
||||
property bool activeVirtualDesktop: activeVirtualDesktopIndex == index
|
||||
|
||||
width: 34
|
||||
height: 34
|
||||
|
||||
Rectangle {
|
||||
anchors.fill: parent
|
||||
anchors.margins: tilePadding
|
||||
border.color: colors.tileBorderColor
|
||||
border.width: 1
|
||||
color: "transparent"
|
||||
radius: 6
|
||||
|
||||
Rectangle {
|
||||
anchors.fill: parent
|
||||
color: activeVirtualDesktop ? colors.tileBackgroundColorActive : colors.tileBackgroundColor
|
||||
radius: 6
|
||||
}
|
||||
|
||||
Text {
|
||||
anchors.centerIn: parent
|
||||
color: colors.textColor
|
||||
textFormat: Text.StyledText
|
||||
text: modelData.isAdd ? "+" : "⸰"
|
||||
font.pixelSize: 14
|
||||
font.family: "Noto Sans"
|
||||
horizontalAlignment: Text.AlignHCenter
|
||||
visible: modelData.isAdd || currentVirtualDesktop
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Rectangle {
|
||||
id: popupHint
|
||||
width: layoutGrid.implicitWidth + layoutGrid.columnSpacing * 2
|
||||
height: popupHintText.implicitHeight + layoutGrid.rowSpacing * 2
|
||||
color: root.config.gridTilerOpacity != 1 ? Qt.alpha(colors.backgroundColor, root.config.gridTilerOpacity) : colors.backgroundColor
|
||||
border.color: colors.borderColor
|
||||
border.width: 1
|
||||
radius: 8
|
||||
visible: root.config.showTextHint && hint != null
|
||||
|
||||
anchors.left: parent.left
|
||||
anchors.leftMargin: positionX
|
||||
anchors.top: virtualDesktop.visible ? virtualDesktop.bottom : layouts.bottom
|
||||
anchors.topMargin: 2
|
||||
|
||||
Text {
|
||||
id: popupHintText
|
||||
width: parent.width - 4
|
||||
anchors.centerIn: parent
|
||||
color: colors.textColor
|
||||
textFormat: Text.StyledText
|
||||
text: hint != null ? hint : ""
|
||||
font.pixelSize: 12
|
||||
font.family: "Noto Sans"
|
||||
horizontalAlignment: Text.AlignHCenter
|
||||
wrapMode: Text.WordWrap
|
||||
}
|
||||
}
|
||||
|
||||
Rectangle {
|
||||
id: popupWindowCursor
|
||||
anchors.left: parent.left
|
||||
anchors.leftMargin: root.getCursorPosition().x - clientArea.x - 6
|
||||
anchors.top: parent.top
|
||||
anchors.topMargin: root.getCursorPosition().y - clientArea.y - 6
|
||||
width: 12
|
||||
height: 12
|
||||
border.color: colors.tileBorderColor
|
||||
border.width: 2
|
||||
color: colors.tileBackgroundColorActive
|
||||
radius: 6
|
||||
visible: !root.useMouseCursor
|
||||
|
||||
Rectangle {
|
||||
anchors.centerIn: parent
|
||||
width: 2
|
||||
height: 2
|
||||
color: colors.textColor
|
||||
radius: 1
|
||||
opacity: 0.8
|
||||
}
|
||||
}
|
||||
|
||||
Timer {
|
||||
interval: 1
|
||||
repeat: false
|
||||
running: popupTiler.visible && !sizeEstablished
|
||||
onTriggered: {
|
||||
sizeEstablished = true;
|
||||
updateScreen(true);
|
||||
}
|
||||
}
|
||||
|
||||
Timer {
|
||||
interval: root.config.popupGridPollingRate
|
||||
repeat: true
|
||||
running: popupTiler.visible
|
||||
onTriggered: {
|
||||
let forceUpdate = lastShowAll != showAll;
|
||||
|
||||
if (forceUpdate) {
|
||||
if (showAll) {
|
||||
lastShowAll = true;
|
||||
} else {
|
||||
lastShowAll = false;
|
||||
}
|
||||
}
|
||||
updateScreen(forceUpdate);
|
||||
|
||||
updateRevealed();
|
||||
|
||||
let x = root.getCursorPosition().x;
|
||||
let y = root.getCursorPosition().y;
|
||||
let layoutIndex = -1;
|
||||
let tileIndex = -1;
|
||||
let virtualDesktopIndex = -1;
|
||||
|
||||
if (root.config.windowVisibility == 2) {
|
||||
var updatedHovered;
|
||||
let layoutsPosition = layouts.mapToGlobal(Qt.point(0, 0));
|
||||
let visibleHeight = (layouts.visible ? layouts.height : 0) + (virtualDesktop.visible ? virtualDesktop.height : 0) + (layouts.visible && virtualDesktop.visible ? 2 : 0)
|
||||
if (layoutsPosition.x <= x && layoutsPosition.x + layouts.width >= x && layoutsPosition.y <= y && layoutsPosition.y + visibleHeight >= y) {
|
||||
updatedHovered = true;
|
||||
} else {
|
||||
updatedHovered = false;
|
||||
}
|
||||
if (updatedHovered != currentlyHovered) {
|
||||
currentlyHovered = updatedHovered;
|
||||
root.updateWindowVisibility();
|
||||
}
|
||||
}
|
||||
|
||||
if (layouts.visible) {
|
||||
for (let i = 0; i < layoutRepeater.count; i++) {
|
||||
let currentLayout = layoutRepeater.itemAt(i);
|
||||
let currentLayoutPosition = currentLayout.mapToGlobal(Qt.point(0, 0));
|
||||
|
||||
if (currentLayoutPosition.x <= x && currentLayoutPosition.x + currentLayout.width >= x && currentLayoutPosition.y <= y && currentLayoutPosition.y + currentLayout.height >= y) {
|
||||
layoutIndex = i;
|
||||
// if (layoutRepeater.model[layoutIndex].special) {
|
||||
// tileIndex = 0;
|
||||
// } else {
|
||||
//for (let j = 0; j < currentLayout.children.length; j++) {
|
||||
for (let j = currentLayout.children.length - 1; j >= 0; j--) {
|
||||
let currentTile = currentLayout.children[j];
|
||||
// if (currentTile.tileDisabled) {
|
||||
// continue;
|
||||
// }
|
||||
let currentTilePosition = currentTile.mapToGlobal(Qt.point(0, 0));
|
||||
if (currentTilePosition.x <= x && currentTilePosition.x + currentTile.width >= x && currentTilePosition.y <= y && currentTilePosition.y + currentTile.height >= y) {
|
||||
tileIndex = j;
|
||||
break;
|
||||
}
|
||||
}
|
||||
// }
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (root.virtualDesktopVisibile && layoutIndex == -1) {
|
||||
for (let i = 0; i < virtualDesktopRepeater.count; i++) {
|
||||
let currentVirtualDesktop = virtualDesktopRepeater.itemAt(i);
|
||||
let currentVirtualDesktopPosition = currentVirtualDesktop.mapToGlobal(Qt.point(0, 0));
|
||||
if (currentVirtualDesktopPosition.x <= x && currentVirtualDesktopPosition.x + currentVirtualDesktop.width >= x && currentVirtualDesktopPosition.y <= y && currentVirtualDesktopPosition.y + currentVirtualDesktop.height >= y) {
|
||||
virtualDesktopIndex = i;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
let switchVirtualDesktop = virtualDesktopIndex != -1 && !root.virtualDesktops[virtualDesktopIndex].isAdd && virtualDesktopIndex != root.currentVirtualDesktopIndex;
|
||||
if (activeVirtualDesktopIndex != virtualDesktopIndex) {
|
||||
activeVirtualDesktopIndex = virtualDesktopIndex;
|
||||
if (switchVirtualDesktop) {
|
||||
if (config.virtualDesktopHoverTime == 0) {
|
||||
autoTiler.virtualDesktopAboutToChange(); // Notify to remove window from current virtual desktop auto-tiler
|
||||
Workspace.currentDesktop = root.virtualDesktops[activeVirtualDesktopIndex].desktop;
|
||||
} else {
|
||||
activeVirtualDesktopHoverTime = Date.now();
|
||||
}
|
||||
}
|
||||
updateHintContent();
|
||||
} else if (switchVirtualDesktop && config.virtualDesktopHoverTime > 0 && Date.now() - activeVirtualDesktopHoverTime > config.virtualDesktopHoverTime) {
|
||||
autoTiler.virtualDesktopAboutToChange(); // Notify to remove window from current virtual desktop auto-tiler
|
||||
Workspace.currentDesktop = root.virtualDesktops[activeVirtualDesktopIndex].desktop;
|
||||
updateHintContent();
|
||||
}
|
||||
|
||||
// if (layoutIndex == -1) {
|
||||
// let leftScroll = autoTilerScrollLeft.mapToGlobal(Qt.point(0, 0));
|
||||
// let rightScroll = autoTilerScrollRight.mapToGlobal(Qt.point(0, 0));
|
||||
// if (leftScroll.x <= x && leftScroll.x + autoTilerScrollLeft.width >= x && leftScroll.y <= y && leftScroll.y + autoTilerScrollLeft.height >= y) {
|
||||
// logDev('HOVERING LEFT!!!!');
|
||||
// let timeNow = Date.now();
|
||||
// if (scrollLeftTime == 0) {
|
||||
// scrollLeftTime = timeNow + 1000;
|
||||
// } else if (timeNow >= scrollLeftTime) {
|
||||
// autoTiler.modifyPrimaryIndex(-1);
|
||||
// scrollLeftTime = timeNow + 1000;
|
||||
// }
|
||||
// } else if (rightScroll.x <= x && rightScroll.x + autoTilerScrollRight.width >= x && rightScroll.y <= y && rightScroll.y + autoTilerScrollRight.height >= y) {
|
||||
// logDev('HOVERING RIGHT!!!!');
|
||||
// let timeNow = Date.now();
|
||||
// if (scrollLeftTime == 0) {
|
||||
// scrollLeftTime = timeNow + 1000;
|
||||
// } else if (timeNow >= scrollLeftTime) {
|
||||
// autoTiler.modifyPrimaryIndex(-1);
|
||||
// scrollLeftTime = timeNow + 1000;
|
||||
// }
|
||||
// } else {
|
||||
// scrollLeftTime = 0;
|
||||
// scrollRightTime = 0;
|
||||
// }
|
||||
// } else {
|
||||
// scrollLeftTime = 0;
|
||||
// scrollRightTime = 0;
|
||||
// }
|
||||
|
||||
// TODO: Add support for negative values (-)
|
||||
// TODO: Span more than 1 layout if x < 0 || y < 0 || w > 100 || h > 100 to support SPECIAL_EMPTY
|
||||
if (layoutIndex != activeLayoutIndex || tileIndex != activeTileIndex) {
|
||||
activeLayoutIndex = layoutIndex;
|
||||
activeTileIndex = tileIndex;
|
||||
updateHintContent();
|
||||
} else if (popupDropHintIsCenterInTile != root.centerInTile && activeLayoutIndex >= 0 && activeTileIndex >= 0) {
|
||||
updateHintContent();
|
||||
popupDropHintIsCenterInTile = root.centerInTile;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
+517
@@ -0,0 +1,517 @@
|
||||
import QtQuick
|
||||
import org.kde.kwin
|
||||
import org.kde.plasma.core as PlasmaCore
|
||||
import org.kde.kirigami as Kirigami
|
||||
import org.kde.plasma.components as PlasmaComponents
|
||||
|
||||
// Window {
|
||||
PlasmaCore.Dialog {
|
||||
id: windowSuggestions
|
||||
|
||||
property var activeScreen: null
|
||||
property var currentDesktop: null
|
||||
property var currentActivity: null
|
||||
property bool isDefault: true
|
||||
property int layoutIndex: 0
|
||||
property int tileIndex: 0
|
||||
|
||||
property var clientArea: ({width: 1, height: 1, x: 0, y: 0})
|
||||
property var tilePadding: 2
|
||||
property list<var> convertedOverlay: ([])
|
||||
|
||||
property int skipIndex: -1
|
||||
property int activeIndex: -1
|
||||
|
||||
property int suggestionsVisibility: 0
|
||||
property bool suggestionsInsideTile: true
|
||||
property bool excludeOtherScreens: true
|
||||
property bool excludeOtherDesktops: true
|
||||
property bool excludeOtherActivities: true
|
||||
property bool excludeAutoTiled: true
|
||||
property bool excludeMinimized: true
|
||||
|
||||
property int sortMode: 2
|
||||
property int colCount: 1
|
||||
property int rowCount: 1
|
||||
property int cellWidth: 0
|
||||
property int previewHeight: 0
|
||||
property real cellRatio: 0
|
||||
property int cellHeight: 0
|
||||
property int cellBottomMargin: 0
|
||||
property int textSize: 14
|
||||
property int totalWidth: 0
|
||||
property int totalHeight: 0
|
||||
|
||||
property int offsetX: 0
|
||||
property int offsetY: 0
|
||||
|
||||
property int gridSpacing: 20
|
||||
|
||||
property list<var> validWindows: ([])
|
||||
|
||||
width: clientArea.width
|
||||
height: clientArea.height
|
||||
x: clientArea.x
|
||||
y: clientArea.y
|
||||
flags: Qt.FramelessWindowHint | Qt.WindowStaysOnTopHint | Qt.WindowDoesNotAcceptFocus | Qt.BypassWindowManagerHint
|
||||
// flags: Qt.Tool | Qt.BypassWindowManagerHint | Qt.FramelessWindowHint | Qt.WindowStaysOnTopHint | Qt.WindowDoesNotAcceptFocus
|
||||
// flags: Qt.Tool | Qt.BypassWindowManagerHint | Qt.FramelessWindowHint
|
||||
// color: "transparent" // PlasmaCore.Dialog
|
||||
visible: false
|
||||
// outputOnly: true
|
||||
backgroundHints: PlasmaCore.Types.NoBackground // PlasmaCore.Dialog
|
||||
// type: PlasmaCore.Dialog.OnScreenDisplay
|
||||
location: PlasmaCore.Types.Desktop // PlasmaCore.Dialog
|
||||
|
||||
function init() {
|
||||
suggestionsVisibility = KWin.readConfig("suggestionsVisibility", 0);
|
||||
suggestionsInsideTile = KWin.readConfig("suggestionsMode", 0) == 0;
|
||||
excludeOtherScreens = !KWin.readConfig("suggestOtherScreens", false);
|
||||
excludeOtherDesktops = !KWin.readConfig("suggestOtherDesktops", false);
|
||||
excludeOtherActivities = !KWin.readConfig("suggestOtherActivities", false);
|
||||
excludeAutoTiled = !KWin.readConfig("suggestAutoTiled", false);
|
||||
excludeMinimized = !KWin.readConfig("suggestMinimized", false);
|
||||
}
|
||||
|
||||
function updateValid(addedWindow) {
|
||||
let valid = [];
|
||||
|
||||
for (let i = 0; i < Workspace.stackingOrder.length; i++) {
|
||||
let window = Workspace.stackingOrder[i];
|
||||
if (window == addedWindow) continue;
|
||||
if (!root.isValidWindow(window)) continue;
|
||||
if (window.fullScreen) continue;
|
||||
// if (window.maximizeMode > 0) continue;
|
||||
if (excludeAutoTiled && window.mt_auto) continue;
|
||||
if (excludeMinimized && window.minimized) continue;
|
||||
if (excludeOtherScreens && window.output != activeScreen) continue;
|
||||
if (excludeOtherDesktops && window.desktops.length > 0 && !window.desktops.includes(currentDesktop)) continue;
|
||||
if (excludeOtherActivities && window.activities.length > 0 && !window.activities.includes(currentActivity)) continue;
|
||||
valid.push(window);
|
||||
}
|
||||
|
||||
switch (sortMode) {
|
||||
case 0: // newest focused first
|
||||
valid.reverse();
|
||||
break;
|
||||
case 1: // oldest focused first
|
||||
break;
|
||||
case 2: // a-z
|
||||
valid.sort((a, b) => a.caption.toLowerCase().localeCompare(b.caption.toLowerCase()));
|
||||
break;
|
||||
}
|
||||
|
||||
validWindows = valid;
|
||||
}
|
||||
|
||||
function updateSizes() {
|
||||
let count = validWindows.length;
|
||||
|
||||
log('Valid count: ' + count);
|
||||
|
||||
let usableHeight = suggestionsInsideTile ? convertedOverlay[activeIndex].height : clientArea.height - 180;
|
||||
let usableWidth = suggestionsInsideTile ? convertedOverlay[activeIndex].width : clientArea.width / 2;
|
||||
let wantedRatio = 16 / 9;
|
||||
let ratio = usableWidth / usableHeight;
|
||||
|
||||
if (!suggestionsInsideTile) {
|
||||
if (ratio < wantedRatio) {
|
||||
usableWidth = parseInt(usableWidth);
|
||||
usableHeight = parseInt(usableWidth / wantedRatio);
|
||||
} else {
|
||||
usableHeight = parseInt(usableHeight);
|
||||
usableWidth = parseInt(usableHeight * wantedRatio);
|
||||
}
|
||||
}
|
||||
|
||||
colCount = Math.ceil(Math.sqrt(count));
|
||||
rowCount = Math.ceil(count / colCount);
|
||||
cellWidth = (usableWidth - gridSpacing * (colCount + 1)) / Math.max(colCount, 2);
|
||||
log('CellWidth before: ' + cellWidth);
|
||||
if (suggestionsInsideTile) {
|
||||
if (cellWidth < 320) {
|
||||
colCount = Math.min(count, Math.floor(convertedOverlay[activeIndex].width / 320));
|
||||
} else {
|
||||
colCount = Math.min(count, Math.floor(convertedOverlay[activeIndex].width / cellWidth));
|
||||
}
|
||||
cellWidth = (convertedOverlay[activeIndex].width - gridSpacing * (colCount + 1)) / Math.max(colCount, 2);
|
||||
}
|
||||
log('ColCount: ' + colCount + ' width: ' + cellWidth + ' gridSpacing: ' + gridSpacing + ' width: ' + convertedOverlay[activeIndex].width + ' usable: ' + usableWidth);
|
||||
cellBottomMargin = Kirigami.Units.iconSizes.large / 4;
|
||||
previewHeight = (usableHeight - gridSpacing * (rowCount + 1)) / Math.max(colCount, 2);
|
||||
if (suggestionsInsideTile && previewHeight < 200) {
|
||||
rowCount = Math.ceil(count / colCount);
|
||||
previewHeight = 200;
|
||||
}
|
||||
cellHeight = previewHeight - cellBottomMargin - textSize;
|
||||
totalWidth = suggestionsInsideTile ? convertedOverlay[activeIndex].width : cellWidth * Math.max(colCount, 2) + gridSpacing * (colCount + 1);
|
||||
totalHeight = suggestionsInsideTile ? convertedOverlay[activeIndex].height : previewHeight * rowCount + gridSpacing * (rowCount + 1);
|
||||
cellRatio = cellWidth / previewHeight;
|
||||
log('Count: ' + count + ' rowCount: ' + rowCount + ' colCount: ' + colCount + ' width: ' + usableWidth + ' height: ' + usableHeight + ' ratio: ' + ratio + ' wanted ratio: ' + wantedRatio + ' cell width: ' + cellWidth + ' cell height: ' + cellHeight + ' totalHeight: ' + totalHeight);
|
||||
}
|
||||
|
||||
function showSuggestions(window, screen, virtualDesktop, activity, isDefault, layoutIndex, tileIndex) {
|
||||
log('screen: ' + screen.name + ' virtualDesktop: ' + virtualDesktop.id + ' activity: ' + activity + ' isDefault: ' + isDefault + ' layoutIndex: ' + layoutIndex + ' tileIndex: ' + tileIndex);
|
||||
activeScreen = screen;
|
||||
currentDesktop = virtualDesktop;
|
||||
currentActivity = activity;
|
||||
windowSuggestions.isDefault = isDefault;
|
||||
windowSuggestions.layoutIndex = layoutIndex;
|
||||
windowSuggestions.tileIndex = tileIndex;
|
||||
|
||||
clientArea = Workspace.clientArea(KWin.FullScreenArea, activeScreen, currentDesktop);
|
||||
activeIndex = 0;
|
||||
skipIndex = tileIndex;
|
||||
|
||||
convertLayoutToScreen();
|
||||
|
||||
updateValid(window);
|
||||
|
||||
if (validWindows.length > 0 && convertedOverlay.length > 0) {
|
||||
updateSizes();
|
||||
updateOffsets();
|
||||
windowSuggestions.visible = true;
|
||||
}
|
||||
}
|
||||
|
||||
function convertLayoutToScreen() {
|
||||
let layout = isDefault ? popupGridLayouts[layoutIndex].tiles : popupGridAllLayouts[layoutIndex].tiles;
|
||||
log('Window suggestions layout to convert: ' + JSON.stringify(layout));
|
||||
let converted = [];
|
||||
for (let i = 0; i < layout.length; i++) {
|
||||
if (i == skipIndex) continue;
|
||||
let tile = layout[i];
|
||||
let width = (tile.pxW == undefined ? tile.w / 100 * windowSuggestions.width : tile.pxW);
|
||||
let height = (tile.pxH == undefined ? tile.h / 100 * windowSuggestions.height : tile.pxH);
|
||||
|
||||
// Temporarily add clientArea x/y since it is needed for calculating margins
|
||||
let geometry = {
|
||||
x: clientArea.x + ((tile.pxX == undefined ? tile.x / 100 * windowSuggestions.width : tile.pxX) - (tile.aX == undefined ? 0 : tile.aX * width / 100)),
|
||||
y: clientArea.y + ((tile.pxY == undefined ? tile.y / 100 * windowSuggestions.height : tile.pxY) - (tile.aY == undefined ? 0 : tile.aY * height / 100)),
|
||||
width: width,
|
||||
height: height,
|
||||
tileIndex: i
|
||||
};
|
||||
root.addMargins(geometry, true, true, true, true);
|
||||
geometry.x -= clientArea.x;
|
||||
geometry.y -= clientArea.y;
|
||||
converted.push(geometry);
|
||||
}
|
||||
windowSuggestions.convertedOverlay = converted;
|
||||
}
|
||||
|
||||
function updateOffsets() {
|
||||
if (activeIndex < convertedOverlay.length) {
|
||||
if (suggestionsInsideTile) {
|
||||
offsetX = convertedOverlay[activeIndex].x;
|
||||
offsetY = convertedOverlay[activeIndex].y;
|
||||
} else {
|
||||
let overlay = convertedOverlay[activeIndex];
|
||||
let rightSpace = clientArea.width - overlay.x - overlay.width;
|
||||
if (overlay.x < rightSpace) {
|
||||
offsetX = Math.min(clientArea.width - rightSpace + 2, clientArea.width - totalWidth - 2);
|
||||
} else {
|
||||
offsetX = Math.max(overlay.x - totalWidth - 2, 2);
|
||||
}
|
||||
|
||||
offsetY = overlay.y - ((totalHeight + 80 - overlay.height) / 2);
|
||||
if (offsetY < 0) {
|
||||
offsetY = 0;
|
||||
} else if (offsetY + totalHeight + 80 > clientArea.height) {
|
||||
offsetY = clientArea.height - totalHeight - 80;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function selectSuggestion(index, tileIndex) {
|
||||
log('Select suggestion: ' + index + ' ' + tileIndex);
|
||||
activeIndex = index;
|
||||
if (suggestionsInsideTile) {
|
||||
updateSizes();
|
||||
}
|
||||
updateOffsets();
|
||||
}
|
||||
|
||||
function addWindowToSelected(window) {
|
||||
log('Selected window caption: ' + window.caption);
|
||||
|
||||
if (activeIndex != -1 && validWindows.length > 0) {
|
||||
let localWindows = [...validWindows];
|
||||
let overlays = JSON.parse(JSON.stringify(windowSuggestions.convertedOverlay)); // Workaround for a strange bug where wrong item is fetched even if activeIndex is correct
|
||||
let geometry = overlays.splice(activeIndex, 1)[0];
|
||||
windowSuggestions.convertedOverlay = [...overlays];
|
||||
geometry.x += clientArea.x;
|
||||
geometry.y += clientArea.y;
|
||||
let index = localWindows.indexOf(window);
|
||||
if (index != -1) {
|
||||
localWindows.splice(index, 1);
|
||||
|
||||
if (!window.desktops.includes(currentDesktop)) {
|
||||
window.desktops = [currentDesktop];
|
||||
}
|
||||
if (!window.activities.includes(currentActivity)) {
|
||||
window.activities = [currentActivity];
|
||||
}
|
||||
if (window.mt_auto) {
|
||||
autoTiler.disableAutoTiling(window);
|
||||
}
|
||||
if (window.minimized) {
|
||||
window.minimized = false;
|
||||
}
|
||||
if (window.maximizeMode > 0) {
|
||||
window.setMaximize(false, false);
|
||||
}
|
||||
if (!window.mt_originalSize) {
|
||||
window.mt_originalSize = {x: window.x, y: window.y, width: window.width, height: window.height};
|
||||
}
|
||||
root.moveAndResizeWindow(window, geometry);
|
||||
Workspace.raiseWindow(window);
|
||||
|
||||
activeIndex = 0;
|
||||
|
||||
if (localWindows.length == 0 || convertedOverlay.length == 0) {
|
||||
windowSuggestions.visible = false;
|
||||
validWindows = [];
|
||||
} else {
|
||||
validWindows = localWindows;
|
||||
if (suggestionsInsideTile) {
|
||||
updateSizes();
|
||||
}
|
||||
updateOffsets();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function windowClosed(window) {
|
||||
log('Closed window caption: ' + window.caption);
|
||||
|
||||
if (activeIndex != -1 && validWindows.length > 0) {
|
||||
let localWindows = [...validWindows];
|
||||
let index = localWindows.indexOf(window);
|
||||
if (index != -1) {
|
||||
localWindows.splice(index, 1);
|
||||
|
||||
if (localWindows.length == 0) {
|
||||
validWindows = [];
|
||||
} else {
|
||||
validWindows = localWindows;
|
||||
if (suggestionsInsideTile) {
|
||||
updateSizes();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Item {
|
||||
id: mainItem
|
||||
width: windowSuggestions.width
|
||||
height: windowSuggestions.height
|
||||
|
||||
TapHandler {
|
||||
onTapped: windowSuggestions.visible = false;
|
||||
}
|
||||
|
||||
Colors {
|
||||
id: colors
|
||||
}
|
||||
|
||||
Repeater {
|
||||
id: tileRepeater
|
||||
model: windowSuggestions.convertedOverlay
|
||||
|
||||
Item {
|
||||
id: tile
|
||||
|
||||
property bool active: activeIndex == index
|
||||
property int tileIndex: modelData.tileIndex
|
||||
|
||||
x: modelData.x
|
||||
y: modelData.y
|
||||
width: modelData.width
|
||||
height: modelData.height
|
||||
|
||||
Rectangle {
|
||||
anchors.fill: parent
|
||||
anchors.margins: tilePadding
|
||||
border.color: colors.tileBorderColor
|
||||
border.width: 2
|
||||
color: active ? colors.tileBackgroundColorActive : colors.tileBackgroundColorIntense
|
||||
radius: 12
|
||||
|
||||
Text {
|
||||
anchors.centerIn: parent
|
||||
color: colors.overlayTextColor
|
||||
textFormat: Text.StyledText
|
||||
text: "<b>Select a window to tile here</b>"
|
||||
font.pixelSize: 16
|
||||
font.family: "Noto Sans"
|
||||
horizontalAlignment: Text.AlignHCenter
|
||||
visible: active && !suggestionsInsideTile
|
||||
}
|
||||
|
||||
TapHandler {
|
||||
gesturePolicy: TapHandler.ReleaseWithinBounds
|
||||
onTapped: selectSuggestion(index, tileIndex);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Item {
|
||||
height: suggestionsInsideTile ? totalHeight : totalHeight + 80
|
||||
width: totalWidth
|
||||
anchors.top: parent.top
|
||||
// anchors.topMargin: (clientArea.height - height) / 2
|
||||
anchors.topMargin: offsetY
|
||||
anchors.left: parent.left
|
||||
anchors.leftMargin: offsetX
|
||||
|
||||
Rectangle {
|
||||
id: cellWrapper
|
||||
width: totalWidth
|
||||
height: suggestionsInsideTile ? totalHeight : totalHeight + 80
|
||||
color: suggestionsInsideTile ? "transparent" : "#BB000000"
|
||||
border.width: 1
|
||||
border.color: suggestionsInsideTile ? "transparent" : "#80FFFFFF"
|
||||
radius: 6
|
||||
|
||||
GridView {
|
||||
id: listView
|
||||
model: validWindows
|
||||
width: colCount * (windowSuggestions.cellWidth + gridSpacing)
|
||||
// height: rowCount * (previewHeight + gridSpacing)
|
||||
height: suggestionsInsideTile ? Math.min((previewHeight + gridSpacing) * rowCount, totalHeight - 80 - gridSpacing * 2) : totalHeight - 80 - gridSpacing * 2
|
||||
cellWidth: windowSuggestions.cellWidth + gridSpacing
|
||||
cellHeight: previewHeight + gridSpacing
|
||||
interactive: suggestionsInsideTile ? true : false
|
||||
clip: suggestionsInsideTile
|
||||
anchors.top: parent.top
|
||||
anchors.topMargin: suggestionsInsideTile ? (cellWrapper.height - height) / 2 : 40 + gridSpacing
|
||||
anchors.left: parent.left
|
||||
anchors.leftMargin: suggestionsInsideTile ? (cellWrapper.width + gridSpacing - width) / 2 : gridSpacing
|
||||
|
||||
delegate: Rectangle {
|
||||
width: windowSuggestions.cellWidth
|
||||
height: previewHeight
|
||||
color: "transparent"
|
||||
|
||||
property real previewRatio: modelData.width / modelData.height
|
||||
property int previewActualWidth: previewRatio > cellRatio ? windowSuggestions.cellWidth : windowSuggestions.cellHeight * previewRatio
|
||||
property int previewActualHeight: previewRatio > cellRatio ? windowSuggestions.cellWidth / previewRatio : windowSuggestions.cellHeight
|
||||
|
||||
WindowThumbnail {
|
||||
id: preview
|
||||
client: modelData
|
||||
width: previewActualWidth
|
||||
height: previewActualHeight
|
||||
anchors.centerIn: parent
|
||||
anchors.verticalCenterOffset: -((textSize + cellBottomMargin) / 2)
|
||||
|
||||
TapHandler {
|
||||
gesturePolicy: TapHandler.ReleaseWithinBounds
|
||||
onTapped: addWindowToSelected(modelData);
|
||||
}
|
||||
|
||||
Kirigami.Icon {
|
||||
id: icon
|
||||
width: Kirigami.Units.iconSizes.large
|
||||
height: Kirigami.Units.iconSizes.large
|
||||
source: modelData.icon
|
||||
anchors.horizontalCenter: preview.horizontalCenter
|
||||
anchors.verticalCenter: preview.bottom
|
||||
anchors.verticalCenterOffset: -Math.round(height / 4)
|
||||
|
||||
PlasmaComponents.Label {
|
||||
id: text
|
||||
width: windowSuggestions.cellWidth
|
||||
height: textSize
|
||||
text: modelData.caption
|
||||
anchors.top: parent.bottom
|
||||
anchors.horizontalCenter: parent.horizontalCenter
|
||||
horizontalAlignment: Text.AlignHCenter
|
||||
elide: Text.ElideRight
|
||||
color: "white"
|
||||
|
||||
background: Rectangle {
|
||||
anchors.centerIn: parent
|
||||
anchors.verticalCenterOffset: 3
|
||||
height: parent.height + 4
|
||||
width: parent.contentWidth + 6
|
||||
color: "#66000000"
|
||||
radius: 3
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Rectangle {
|
||||
anchors.top: parent.top
|
||||
anchors.topMargin: suggestionsInsideTile ? 4 : 1
|
||||
anchors.left: parent.left
|
||||
anchors.leftMargin: suggestionsInsideTile ? 4 : 1
|
||||
width: suggestionsInsideTile ? totalWidth - 8 : totalWidth - 2
|
||||
height: 40;
|
||||
color: "#EE333333"
|
||||
radius: suggestionsInsideTile ? 12 : 6
|
||||
|
||||
Text {
|
||||
anchors.centerIn: parent
|
||||
color: "white"
|
||||
textFormat: Text.StyledText
|
||||
text: suggestionsInsideTile ? "Select a window to place here" : "Select a window to place in the highlighted tile"
|
||||
font.pixelSize: 16
|
||||
font.family: "Noto Sans"
|
||||
horizontalAlignment: Text.AlignHCenter
|
||||
}
|
||||
|
||||
|
||||
Text {
|
||||
anchors.right: parent.right
|
||||
anchors.rightMargin: 12
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
color: "white"
|
||||
textFormat: Text.StyledText
|
||||
text: "✖"
|
||||
font.pixelSize: 16
|
||||
font.family: "Noto Sans"
|
||||
horizontalAlignment: Text.AlignHCenter
|
||||
}
|
||||
|
||||
TapHandler {
|
||||
gesturePolicy: TapHandler.ReleaseWithinBounds
|
||||
onTapped: windowSuggestions.visible = false;
|
||||
}
|
||||
}
|
||||
Rectangle {
|
||||
anchors.bottom: parent.bottom
|
||||
anchors.bottomMargin: suggestionsInsideTile ? 4 : 1
|
||||
anchors.left: parent.left
|
||||
anchors.leftMargin: suggestionsInsideTile ? 4 : 1
|
||||
width: suggestionsInsideTile ? totalWidth - 8 : totalWidth - 2
|
||||
height: 40;
|
||||
color: "#EE333333"
|
||||
radius: suggestionsInsideTile ? 12 : 6
|
||||
|
||||
Text {
|
||||
anchors.centerIn: parent
|
||||
color: "white"
|
||||
textFormat: Text.StyledText
|
||||
text: "Click a tile to switch to it. Click anywhere else to close suggestions. Disable suggestions (<b>" + config.shortcutToggleTilingSuggestions + "</b>)"
|
||||
font.pixelSize: 16
|
||||
font.family: "Noto Sans"
|
||||
horizontalAlignment: Text.AlignHCenter
|
||||
}
|
||||
|
||||
TapHandler {
|
||||
gesturePolicy: TapHandler.ReleaseWithinBounds
|
||||
onTapped: windowSuggestions.visible = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
+3880
File diff suppressed because it is too large
Load Diff
+1781
File diff suppressed because it is too large
Load Diff
+20
@@ -0,0 +1,20 @@
|
||||
{
|
||||
"KPackageStructure": "KWin/Script",
|
||||
"KPlugin": {
|
||||
"Authors": [
|
||||
{
|
||||
"Name": "rxappdev"
|
||||
}
|
||||
],
|
||||
"Name": "Mouse Tiler",
|
||||
"Description": "Tile your windows with minimal effort",
|
||||
"Icon": "preferences-desktop-virtual",
|
||||
"Id": "mousetiler",
|
||||
"Version": "6.4.0",
|
||||
"License": "GPLv3",
|
||||
"Website": "https://github.com/rxappdev/MouseTiler"
|
||||
},
|
||||
"X-Plasma-API": "declarativescript",
|
||||
"X-Plasma-MainScript": "ui/main.qml",
|
||||
"X-KDE-ConfigModule": "kwin/effects/configs/kcm_kwin4_genericscripted"
|
||||
}
|
||||
+339
@@ -0,0 +1,339 @@
|
||||
GNU GENERAL PUBLIC LICENSE
|
||||
Version 2, June 1991
|
||||
|
||||
Copyright (C) 1989, 1991 Free Software Foundation, Inc.,
|
||||
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
Everyone is permitted to copy and distribute verbatim copies
|
||||
of this license document, but changing it is not allowed.
|
||||
|
||||
Preamble
|
||||
|
||||
The licenses for most software are designed to take away your
|
||||
freedom to share and change it. By contrast, the GNU General Public
|
||||
License is intended to guarantee your freedom to share and change free
|
||||
software--to make sure the software is free for all its users. This
|
||||
General Public License applies to most of the Free Software
|
||||
Foundation's software and to any other program whose authors commit to
|
||||
using it. (Some other Free Software Foundation software is covered by
|
||||
the GNU Lesser General Public License instead.) You can apply it to
|
||||
your programs, too.
|
||||
|
||||
When we speak of free software, we are referring to freedom, not
|
||||
price. Our General Public Licenses are designed to make sure that you
|
||||
have the freedom to distribute copies of free software (and charge for
|
||||
this service if you wish), that you receive source code or can get it
|
||||
if you want it, that you can change the software or use pieces of it
|
||||
in new free programs; and that you know you can do these things.
|
||||
|
||||
To protect your rights, we need to make restrictions that forbid
|
||||
anyone to deny you these rights or to ask you to surrender the rights.
|
||||
These restrictions translate to certain responsibilities for you if you
|
||||
distribute copies of the software, or if you modify it.
|
||||
|
||||
For example, if you distribute copies of such a program, whether
|
||||
gratis or for a fee, you must give the recipients all the rights that
|
||||
you have. You must make sure that they, too, receive or can get the
|
||||
source code. And you must show them these terms so they know their
|
||||
rights.
|
||||
|
||||
We protect your rights with two steps: (1) copyright the software, and
|
||||
(2) offer you this license which gives you legal permission to copy,
|
||||
distribute and/or modify the software.
|
||||
|
||||
Also, for each author's protection and ours, we want to make certain
|
||||
that everyone understands that there is no warranty for this free
|
||||
software. If the software is modified by someone else and passed on, we
|
||||
want its recipients to know that what they have is not the original, so
|
||||
that any problems introduced by others will not reflect on the original
|
||||
authors' reputations.
|
||||
|
||||
Finally, any free program is threatened constantly by software
|
||||
patents. We wish to avoid the danger that redistributors of a free
|
||||
program will individually obtain patent licenses, in effect making the
|
||||
program proprietary. To prevent this, we have made it clear that any
|
||||
patent must be licensed for everyone's free use or not licensed at all.
|
||||
|
||||
The precise terms and conditions for copying, distribution and
|
||||
modification follow.
|
||||
|
||||
GNU GENERAL PUBLIC LICENSE
|
||||
TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
|
||||
|
||||
0. This License applies to any program or other work which contains
|
||||
a notice placed by the copyright holder saying it may be distributed
|
||||
under the terms of this General Public License. The "Program", below,
|
||||
refers to any such program or work, and a "work based on the Program"
|
||||
means either the Program or any derivative work under copyright law:
|
||||
that is to say, a work containing the Program or a portion of it,
|
||||
either verbatim or with modifications and/or translated into another
|
||||
language. (Hereinafter, translation is included without limitation in
|
||||
the term "modification".) Each licensee is addressed as "you".
|
||||
|
||||
Activities other than copying, distribution and modification are not
|
||||
covered by this License; they are outside its scope. The act of
|
||||
running the Program is not restricted, and the output from the Program
|
||||
is covered only if its contents constitute a work based on the
|
||||
Program (independent of having been made by running the Program).
|
||||
Whether that is true depends on what the Program does.
|
||||
|
||||
1. You may copy and distribute verbatim copies of the Program's
|
||||
source code as you receive it, in any medium, provided that you
|
||||
conspicuously and appropriately publish on each copy an appropriate
|
||||
copyright notice and disclaimer of warranty; keep intact all the
|
||||
notices that refer to this License and to the absence of any warranty;
|
||||
and give any other recipients of the Program a copy of this License
|
||||
along with the Program.
|
||||
|
||||
You may charge a fee for the physical act of transferring a copy, and
|
||||
you may at your option offer warranty protection in exchange for a fee.
|
||||
|
||||
2. You may modify your copy or copies of the Program or any portion
|
||||
of it, thus forming a work based on the Program, and copy and
|
||||
distribute such modifications or work under the terms of Section 1
|
||||
above, provided that you also meet all of these conditions:
|
||||
|
||||
a) You must cause the modified files to carry prominent notices
|
||||
stating that you changed the files and the date of any change.
|
||||
|
||||
b) You must cause any work that you distribute or publish, that in
|
||||
whole or in part contains or is derived from the Program or any
|
||||
part thereof, to be licensed as a whole at no charge to all third
|
||||
parties under the terms of this License.
|
||||
|
||||
c) If the modified program normally reads commands interactively
|
||||
when run, you must cause it, when started running for such
|
||||
interactive use in the most ordinary way, to print or display an
|
||||
announcement including an appropriate copyright notice and a
|
||||
notice that there is no warranty (or else, saying that you provide
|
||||
a warranty) and that users may redistribute the program under
|
||||
these conditions, and telling the user how to view a copy of this
|
||||
License. (Exception: if the Program itself is interactive but
|
||||
does not normally print such an announcement, your work based on
|
||||
the Program is not required to print an announcement.)
|
||||
|
||||
These requirements apply to the modified work as a whole. If
|
||||
identifiable sections of that work are not derived from the Program,
|
||||
and can be reasonably considered independent and separate works in
|
||||
themselves, then this License, and its terms, do not apply to those
|
||||
sections when you distribute them as separate works. But when you
|
||||
distribute the same sections as part of a whole which is a work based
|
||||
on the Program, the distribution of the whole must be on the terms of
|
||||
this License, whose permissions for other licensees extend to the
|
||||
entire whole, and thus to each and every part regardless of who wrote it.
|
||||
|
||||
Thus, it is not the intent of this section to claim rights or contest
|
||||
your rights to work written entirely by you; rather, the intent is to
|
||||
exercise the right to control the distribution of derivative or
|
||||
collective works based on the Program.
|
||||
|
||||
In addition, mere aggregation of another work not based on the Program
|
||||
with the Program (or with a work based on the Program) on a volume of
|
||||
a storage or distribution medium does not bring the other work under
|
||||
the scope of this License.
|
||||
|
||||
3. You may copy and distribute the Program (or a work based on it,
|
||||
under Section 2) in object code or executable form under the terms of
|
||||
Sections 1 and 2 above provided that you also do one of the following:
|
||||
|
||||
a) Accompany it with the complete corresponding machine-readable
|
||||
source code, which must be distributed under the terms of Sections
|
||||
1 and 2 above on a medium customarily used for software interchange; or,
|
||||
|
||||
b) Accompany it with a written offer, valid for at least three
|
||||
years, to give any third party, for a charge no more than your
|
||||
cost of physically performing source distribution, a complete
|
||||
machine-readable copy of the corresponding source code, to be
|
||||
distributed under the terms of Sections 1 and 2 above on a medium
|
||||
customarily used for software interchange; or,
|
||||
|
||||
c) Accompany it with the information you received as to the offer
|
||||
to distribute corresponding source code. (This alternative is
|
||||
allowed only for noncommercial distribution and only if you
|
||||
received the program in object code or executable form with such
|
||||
an offer, in accord with Subsection b above.)
|
||||
|
||||
The source code for a work means the preferred form of the work for
|
||||
making modifications to it. For an executable work, complete source
|
||||
code means all the source code for all modules it contains, plus any
|
||||
associated interface definition files, plus the scripts used to
|
||||
control compilation and installation of the executable. However, as a
|
||||
special exception, the source code distributed need not include
|
||||
anything that is normally distributed (in either source or binary
|
||||
form) with the major components (compiler, kernel, and so on) of the
|
||||
operating system on which the executable runs, unless that component
|
||||
itself accompanies the executable.
|
||||
|
||||
If distribution of executable or object code is made by offering
|
||||
access to copy from a designated place, then offering equivalent
|
||||
access to copy the source code from the same place counts as
|
||||
distribution of the source code, even though third parties are not
|
||||
compelled to copy the source along with the object code.
|
||||
|
||||
4. You may not copy, modify, sublicense, or distribute the Program
|
||||
except as expressly provided under this License. Any attempt
|
||||
otherwise to copy, modify, sublicense or distribute the Program is
|
||||
void, and will automatically terminate your rights under this License.
|
||||
However, parties who have received copies, or rights, from you under
|
||||
this License will not have their licenses terminated so long as such
|
||||
parties remain in full compliance.
|
||||
|
||||
5. You are not required to accept this License, since you have not
|
||||
signed it. However, nothing else grants you permission to modify or
|
||||
distribute the Program or its derivative works. These actions are
|
||||
prohibited by law if you do not accept this License. Therefore, by
|
||||
modifying or distributing the Program (or any work based on the
|
||||
Program), you indicate your acceptance of this License to do so, and
|
||||
all its terms and conditions for copying, distributing or modifying
|
||||
the Program or works based on it.
|
||||
|
||||
6. Each time you redistribute the Program (or any work based on the
|
||||
Program), the recipient automatically receives a license from the
|
||||
original licensor to copy, distribute or modify the Program subject to
|
||||
these terms and conditions. You may not impose any further
|
||||
restrictions on the recipients' exercise of the rights granted herein.
|
||||
You are not responsible for enforcing compliance by third parties to
|
||||
this License.
|
||||
|
||||
7. If, as a consequence of a court judgment or allegation of patent
|
||||
infringement or for any other reason (not limited to patent issues),
|
||||
conditions are imposed on you (whether by court order, agreement or
|
||||
otherwise) that contradict the conditions of this License, they do not
|
||||
excuse you from the conditions of this License. If you cannot
|
||||
distribute so as to satisfy simultaneously your obligations under this
|
||||
License and any other pertinent obligations, then as a consequence you
|
||||
may not distribute the Program at all. For example, if a patent
|
||||
license would not permit royalty-free redistribution of the Program by
|
||||
all those who receive copies directly or indirectly through you, then
|
||||
the only way you could satisfy both it and this License would be to
|
||||
refrain entirely from distribution of the Program.
|
||||
|
||||
If any portion of this section is held invalid or unenforceable under
|
||||
any particular circumstance, the balance of the section is intended to
|
||||
apply and the section as a whole is intended to apply in other
|
||||
circumstances.
|
||||
|
||||
It is not the purpose of this section to induce you to infringe any
|
||||
patents or other property right claims or to contest validity of any
|
||||
such claims; this section has the sole purpose of protecting the
|
||||
integrity of the free software distribution system, which is
|
||||
implemented by public license practices. Many people have made
|
||||
generous contributions to the wide range of software distributed
|
||||
through that system in reliance on consistent application of that
|
||||
system; it is up to the author/donor to decide if he or she is willing
|
||||
to distribute software through any other system and a licensee cannot
|
||||
impose that choice.
|
||||
|
||||
This section is intended to make thoroughly clear what is believed to
|
||||
be a consequence of the rest of this License.
|
||||
|
||||
8. If the distribution and/or use of the Program is restricted in
|
||||
certain countries either by patents or by copyrighted interfaces, the
|
||||
original copyright holder who places the Program under this License
|
||||
may add an explicit geographical distribution limitation excluding
|
||||
those countries, so that distribution is permitted only in or among
|
||||
countries not thus excluded. In such case, this License incorporates
|
||||
the limitation as if written in the body of this License.
|
||||
|
||||
9. The Free Software Foundation may publish revised and/or new versions
|
||||
of the General Public License from time to time. Such new versions will
|
||||
be similar in spirit to the present version, but may differ in detail to
|
||||
address new problems or concerns.
|
||||
|
||||
Each version is given a distinguishing version number. If the Program
|
||||
specifies a version number of this License which applies to it and "any
|
||||
later version", you have the option of following the terms and conditions
|
||||
either of that version or of any later version published by the Free
|
||||
Software Foundation. If the Program does not specify a version number of
|
||||
this License, you may choose any version ever published by the Free Software
|
||||
Foundation.
|
||||
|
||||
10. If you wish to incorporate parts of the Program into other free
|
||||
programs whose distribution conditions are different, write to the author
|
||||
to ask for permission. For software which is copyrighted by the Free
|
||||
Software Foundation, write to the Free Software Foundation; we sometimes
|
||||
make exceptions for this. Our decision will be guided by the two goals
|
||||
of preserving the free status of all derivatives of our free software and
|
||||
of promoting the sharing and reuse of software generally.
|
||||
|
||||
NO WARRANTY
|
||||
|
||||
11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
|
||||
FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN
|
||||
OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
|
||||
PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
|
||||
OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
||||
MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS
|
||||
TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE
|
||||
PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
|
||||
REPAIR OR CORRECTION.
|
||||
|
||||
12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
|
||||
WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
|
||||
REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
|
||||
INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
|
||||
OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
|
||||
TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
|
||||
YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
|
||||
PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
|
||||
POSSIBILITY OF SUCH DAMAGES.
|
||||
|
||||
END OF TERMS AND CONDITIONS
|
||||
|
||||
How to Apply These Terms to Your New Programs
|
||||
|
||||
If you develop a new program, and you want it to be of the greatest
|
||||
possible use to the public, the best way to achieve this is to make it
|
||||
free software which everyone can redistribute and change under these terms.
|
||||
|
||||
To do so, attach the following notices to the program. It is safest
|
||||
to attach them to the start of each source file to most effectively
|
||||
convey the exclusion of warranty; and each file should have at least
|
||||
the "copyright" line and a pointer to where the full notice is found.
|
||||
|
||||
<one line to give the program's name and a brief idea of what it does.>
|
||||
Copyright (C) <year> <name of author>
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License along
|
||||
with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
|
||||
Also add information on how to contact you by electronic and paper mail.
|
||||
|
||||
If the program is interactive, make it output a short notice like this
|
||||
when it starts in an interactive mode:
|
||||
|
||||
Gnomovision version 69, Copyright (C) year name of author
|
||||
Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
|
||||
This is free software, and you are welcome to redistribute it
|
||||
under certain conditions; type `show c' for details.
|
||||
|
||||
The hypothetical commands `show w' and `show c' should show the appropriate
|
||||
parts of the General Public License. Of course, the commands you use may
|
||||
be called something other than `show w' and `show c'; they could even be
|
||||
mouse-clicks or menu items--whatever suits your program.
|
||||
|
||||
You should also get your employer (if you work as a programmer) or your
|
||||
school, if any, to sign a "copyright disclaimer" for the program, if
|
||||
necessary. Here is a sample; alter the names:
|
||||
|
||||
Yoyodyne, Inc., hereby disclaims all copyright interest in the program
|
||||
`Gnomovision' (which makes passes at compilers) written by James Hacker.
|
||||
|
||||
<signature of Ty Coon>, 1 April 1989
|
||||
Ty Coon, President of Vice
|
||||
|
||||
This General Public License does not permit incorporating your program into
|
||||
proprietary programs. If your program is a subroutine library, you may
|
||||
consider it more useful to permit linking proprietary applications with the
|
||||
library. If this is what you want to do, use the GNU Lesser General
|
||||
Public License instead of this License.
|
||||
+27
@@ -0,0 +1,27 @@
|
||||
// Copyright (C) 2018 Konstantinos Smanis <konstantinos.smanis@gmail.com>
|
||||
//
|
||||
// This program is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 2 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
|
||||
registerShortcut("MoveWindowToCenter", "Move Window to Center", "Meta+C", function () {
|
||||
var client = workspace.activeClient;
|
||||
if (client.moveable) {
|
||||
var maxArea = workspace.clientArea(KWin.MaximizeArea, client);
|
||||
client.geometry = {
|
||||
x: maxArea.x + (maxArea.width - client.width) / 2,
|
||||
y: maxArea.y + (maxArea.height - client.height) / 2,
|
||||
width: client.width,
|
||||
height: client.height
|
||||
};
|
||||
}
|
||||
});
|
||||
+18
@@ -0,0 +1,18 @@
|
||||
[Desktop Entry]
|
||||
Name=Move Window to Center
|
||||
Comment=Centers the active window in the current screen.
|
||||
Icon=preferences-system-windows-move
|
||||
|
||||
X-Plasma-API=javascript
|
||||
X-Plasma-MainScript=code/main.js
|
||||
|
||||
X-KDE-PluginInfo-Author=Konstantinos Smanis
|
||||
X-KDE-PluginInfo-Email=konstantinos.smanis@gmail.com
|
||||
X-KDE-PluginInfo-Name=movewindowtocenter
|
||||
X-KDE-PluginInfo-Version=1.1
|
||||
X-KDE-PluginInfo-EnabledByDefault=true
|
||||
|
||||
X-KDE-PluginInfo-Depends=
|
||||
X-KDE-PluginInfo-License=GPL
|
||||
X-KDE-ServiceTypes=KWin/Script
|
||||
Type=Service
|
||||
+82
@@ -0,0 +1,82 @@
|
||||
/********************************************************************
|
||||
KWin - the KDE window manager
|
||||
This file is part of the KDE project.
|
||||
|
||||
Copyright (C) 2014 Thomas Lübking <thomas.luebking@gmail.com>
|
||||
KDE5 revisions 2016 Bob Farmer <kde@bfarmer.net>
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*********************************************************************/
|
||||
|
||||
var snapInnerX = readConfig("InnerX", 10);
|
||||
var snapOuterX= readConfig("OuterX", 10);
|
||||
var snapInnerY = readConfig("InnerY", 10);
|
||||
var snapOuterY= readConfig("OuterY", 10);
|
||||
|
||||
// ---------------------------------------------------------
|
||||
|
||||
var clientStepUserMovedResized = function(client, rect) {
|
||||
if (rect == undefined)
|
||||
rect = client.geometry;
|
||||
else if (!client.move)
|
||||
return;
|
||||
var area = workspace.clientArea(KWin.WorkArea, workspace.activeScreen, workspace.currentDesktop);
|
||||
var adjust = false;
|
||||
var diff = rect.x - area.x;
|
||||
if (diff < snapInnerX && diff > -snapOuterX) {
|
||||
adjust = true;
|
||||
var width = rect.width;
|
||||
rect.x = area.x;
|
||||
rect.width = width;
|
||||
} else {
|
||||
diff = rect.x + rect.width - (area.x + area.width);
|
||||
if (diff > -snapInnerX && diff < snapOuterX) {
|
||||
adjust = true;
|
||||
var width = rect.width;
|
||||
rect.x = area.x + area.width - width;
|
||||
rect.width = width;
|
||||
}
|
||||
}
|
||||
diff = rect.y - area.y;
|
||||
if (diff < snapInnerY && diff > -snapOuterY) {
|
||||
adjust = true;
|
||||
var height = rect.height;
|
||||
rect.y = area.y;
|
||||
rect.height = height;
|
||||
} else {
|
||||
diff = rect.y + rect.height - (area.y + area.height);
|
||||
if (diff > -snapInnerY && diff < snapOuterY) {
|
||||
adjust = true;
|
||||
var height = rect.height;
|
||||
rect.y = area.y + area.height - height;
|
||||
rect.height = height;
|
||||
}
|
||||
}
|
||||
if (adjust)
|
||||
client.geometry = rect;
|
||||
}
|
||||
|
||||
var addClient = function(client) {
|
||||
client.clientStepUserMovedResized.connect(clientStepUserMovedResized);
|
||||
client.clientFinishUserMovedResized.connect(clientStepUserMovedResized);
|
||||
clientStepUserMovedResized(client);
|
||||
}
|
||||
|
||||
options.borderSnapZone = 0;
|
||||
workspace.clientAdded.connect(addClient);
|
||||
var clients = workspace.clientList();
|
||||
for (var i = 0; i < clients.length; ++i) {
|
||||
addClient(clients[i])
|
||||
}
|
||||
|
||||
+22
@@ -0,0 +1,22 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<kcfg xmlns="http://www.kde.org/standards/kcfg/1.0"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://www.kde.org/standards/kcfg/1.0
|
||||
http://www.kde.org/standards/kcfg/1.0/kcfg.xsd" >
|
||||
<kcfgfile name=""/>
|
||||
<group name="">
|
||||
<entry name="InnerX" type="int">
|
||||
<default>10</default>
|
||||
</entry>
|
||||
<entry name="OuterX" type="int">
|
||||
<default>10</default>
|
||||
</entry>
|
||||
<entry name="InnerY" type="int">
|
||||
<default>10</default>
|
||||
</entry>
|
||||
<entry name="OuterY" type="int">
|
||||
<default>10</default>
|
||||
</entry>
|
||||
</group>
|
||||
|
||||
</kcfg>
|
||||
+181
@@ -0,0 +1,181 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<ui version="4.0">
|
||||
<class>KWin::ScreenSnappingConfigForm</class>
|
||||
<widget class="QWidget" name="KWin::ScreenSnappingConfigForm">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>362</width>
|
||||
<height>190</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="windowTitle">
|
||||
<string>Screen Snapping</string>
|
||||
</property>
|
||||
<layout class="QGridLayout" name="gridLayout" columnstretch="3,1">
|
||||
<item row="0" column="0">
|
||||
<widget class="QGroupBox" name="groupBox">
|
||||
<property name="title">
|
||||
<string>Horizontal Snapping</string>
|
||||
</property>
|
||||
<property name="flat">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
<layout class="QHBoxLayout" name="horizontalLayout">
|
||||
<item>
|
||||
<widget class="QLabel" name="label_4">
|
||||
<property name="text">
|
||||
<string>Inside</string>
|
||||
</property>
|
||||
<property name="alignment">
|
||||
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QSpinBox" name="kcfg_InnerX">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="MinimumExpanding" vsizetype="Fixed">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="suffix">
|
||||
<string>px</string>
|
||||
</property>
|
||||
<property name="value">
|
||||
<number>10</number>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QLabel" name="label_3">
|
||||
<property name="text">
|
||||
<string>Outside</string>
|
||||
</property>
|
||||
<property name="alignment">
|
||||
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QSpinBox" name="kcfg_OuterX">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="MinimumExpanding" vsizetype="Fixed">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="suffix">
|
||||
<string>px</string>
|
||||
</property>
|
||||
<property name="maximum">
|
||||
<number>5000</number>
|
||||
</property>
|
||||
<property name="value">
|
||||
<number>10</number>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="0">
|
||||
<widget class="QGroupBox" name="groupBox_2">
|
||||
<property name="title">
|
||||
<string>Vertical Snapping</string>
|
||||
</property>
|
||||
<property name="flat">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
<layout class="QHBoxLayout" name="horizontalLayout_2">
|
||||
<item>
|
||||
<widget class="QLabel" name="label_5">
|
||||
<property name="text">
|
||||
<string>Inside</string>
|
||||
</property>
|
||||
<property name="alignment">
|
||||
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QSpinBox" name="kcfg_InnerY">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="MinimumExpanding" vsizetype="Fixed">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="suffix">
|
||||
<string>px</string>
|
||||
</property>
|
||||
<property name="value">
|
||||
<number>10</number>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QLabel" name="label_6">
|
||||
<property name="text">
|
||||
<string>Outside</string>
|
||||
</property>
|
||||
<property name="alignment">
|
||||
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QSpinBox" name="kcfg_OuterY">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="MinimumExpanding" vsizetype="Fixed">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="suffix">
|
||||
<string>px</string>
|
||||
</property>
|
||||
<property name="maximum">
|
||||
<number>5000</number>
|
||||
</property>
|
||||
<property name="value">
|
||||
<number>10</number>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="2" column="0">
|
||||
<spacer name="verticalSpacer">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Vertical</enum>
|
||||
</property>
|
||||
<property name="sizeHint" stdset="0">
|
||||
<size>
|
||||
<width>20</width>
|
||||
<height>40</height>
|
||||
</size>
|
||||
</property>
|
||||
</spacer>
|
||||
</item>
|
||||
<item row="0" column="1" rowspan="2">
|
||||
<spacer name="horizontalSpacer">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Horizontal</enum>
|
||||
</property>
|
||||
<property name="sizeHint" stdset="0">
|
||||
<size>
|
||||
<width>42</width>
|
||||
<height>124</height>
|
||||
</size>
|
||||
</property>
|
||||
</spacer>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
<resources/>
|
||||
<connections/>
|
||||
</ui>
|
||||
+21
@@ -0,0 +1,21 @@
|
||||
[Desktop Entry]
|
||||
Name=Screen Snapping 5
|
||||
Comment=Snap to deco instead of window content
|
||||
Icon=preferences-system-windows-script-test
|
||||
|
||||
Type=Service
|
||||
|
||||
X-Plasma-API=javascript
|
||||
X-Plasma-MainScript=code/main.js
|
||||
|
||||
X-KDE-PluginInfo-Author=Bob Farmer
|
||||
X-KDE-PluginInfo-Email=kde@bfarmer.net
|
||||
X-KDE-PluginInfo-Name=screenSnapping5
|
||||
X-KDE-PluginInfo-Version=1.0
|
||||
|
||||
X-KDE-PluginInfo-Depends=
|
||||
X-KDE-PluginInfo-License=GPL
|
||||
X-KDE-ServiceTypes=KWin/Script,KCModule
|
||||
X-KDE-Library=kwin/effects/configs/kcm_kwin4_genericscripted
|
||||
X-KDE-PluginKeyword=screenSnapping5
|
||||
X-KDE-ParentComponents=screenSnapping5
|
||||
+170
@@ -0,0 +1,170 @@
|
||||
import QtQuick 2.0
|
||||
import QtQuick.Layouts 1.1
|
||||
import org.kde.plasma.core 2.0 as PlasmaCore
|
||||
import org.kde.plasma.components 2.0 as PlasmaComponents
|
||||
import org.kde.kquickcontrolsaddons 2.0
|
||||
import org.kde.kwin 2.0 as KWin
|
||||
|
||||
// Reused code from the Grid Thumbnail switcher.
|
||||
// https://techbase.kde.org/Development/Tutorials/KWin/WindowSwitcher
|
||||
KWin.Switcher {
|
||||
id: tabBox
|
||||
currentIndex: thumbnailListView.currentIndex
|
||||
|
||||
PlasmaCore.Dialog {
|
||||
id: dialog
|
||||
location: PlasmaCore.Types.Floating
|
||||
visible: tabBox.visible
|
||||
flags: Qt.X11BypassWindowManagerHint
|
||||
x: tabBox.screenGeometry.x + tabBox.screenGeometry.width * 0.5 - dialogMainItem.width * 0.5
|
||||
y: tabBox.screenGeometry.y + tabBox.screenGeometry.height * 0.5 - dialogMainItem.height * 0.5
|
||||
|
||||
mainItem: Item {
|
||||
id: dialogMainItem
|
||||
|
||||
property int maxWidth: tabBox.screenGeometry.width * 0.75
|
||||
property int maxHeight: tabBox.screenGeometry.height * 0.9
|
||||
property real screenFactor: tabBox.screenGeometry.width / tabBox.screenGeometry.height
|
||||
property int listRows: thumbnailListView.count
|
||||
|
||||
width: thumbnailListView.width
|
||||
height: thumbnailListView.height
|
||||
|
||||
clip: true
|
||||
|
||||
|
||||
// just to get the margin sizes
|
||||
PlasmaCore.FrameSvgItem {
|
||||
id: hoverItem
|
||||
imagePath: "widgets/viewitem"
|
||||
prefix: "hover"
|
||||
visible: false
|
||||
}
|
||||
|
||||
ListView {
|
||||
id: thumbnailListView
|
||||
model: tabBox.model
|
||||
orientation: ListView.Vertical
|
||||
anchors.fill: parent
|
||||
|
||||
property int captionRowHeight: 22
|
||||
property int thumbnailWidth: dialogMainItem.maxWidth
|
||||
property int thumbnailHeight: thumbnailWidth * (1.0/dialogMainItem.screenFactor)
|
||||
width: hoverItem.margins.left + thumbnailWidth + hoverItem.margins.right
|
||||
height: hoverItem.margins.top + captionRowHeight + thumbnailHeight + hoverItem.margins.bottom
|
||||
|
||||
delegate: Item {
|
||||
width: thumbnailListView.width
|
||||
height: thumbnailListView.height
|
||||
|
||||
MouseArea {
|
||||
anchors.fill: parent
|
||||
onClicked: {
|
||||
parent.select_relative(0)
|
||||
}
|
||||
onWheel: {
|
||||
if (wheel.angleDelta.x < 0) {
|
||||
parent.select_relative(1)
|
||||
} else {
|
||||
parent.select_relative(-1)
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
function select_relative(x) {
|
||||
thumbnailListView.currentIndex = (index + thumbnailListView.count + x) % thumbnailListView.count;
|
||||
thumbnailListView.currentIndexChanged(thumbnailListView.currentIndex);
|
||||
}
|
||||
|
||||
|
||||
Item {
|
||||
z: 0
|
||||
anchors.fill: parent
|
||||
anchors.leftMargin: hoverItem.margins.left
|
||||
anchors.topMargin: hoverItem.margins.top
|
||||
anchors.rightMargin: hoverItem.margins.right
|
||||
anchors.bottomMargin: hoverItem.margins.bottom
|
||||
|
||||
|
||||
RowLayout {
|
||||
id: captionRow
|
||||
anchors.top: parent.top
|
||||
anchors.right: parent.right
|
||||
height: thumbnailListView.captionRowHeight
|
||||
spacing: 4
|
||||
|
||||
QIconItem {
|
||||
id: iconItem
|
||||
icon: model.icon
|
||||
width: parent.height
|
||||
height: parent.height
|
||||
state: index == thumbnailListView.currentIndex ? QIconItem.ActiveState : QIconItem.DefaultState
|
||||
}
|
||||
|
||||
PlasmaComponents.Label {
|
||||
text: model.caption
|
||||
height: parent.height
|
||||
Layout.fillWidth: true
|
||||
elide: Text.ElideRight
|
||||
}
|
||||
PlasmaComponents.Label {
|
||||
text: model.desktopName
|
||||
color: "green"
|
||||
height: parent.height
|
||||
Layout.fillWidth: true
|
||||
elide: Text.ElideRight
|
||||
}
|
||||
|
||||
PlasmaComponents.ToolButton {
|
||||
visible: model.closeable && typeof tabBox.model.close !== 'undefined' || false
|
||||
iconSource: 'window-close-symbolic'
|
||||
onClicked: {
|
||||
console.log(tabBox.model, index, model.closeable, tabBox.model.close)
|
||||
tabBox.model.close(index)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Cannot draw icon on top of thumbnail.
|
||||
KWin.ThumbnailItem {
|
||||
wId: windowId
|
||||
// clip: true
|
||||
// clipTo: thumbnailListView
|
||||
clip: true
|
||||
clipTo: parent
|
||||
anchors.fill: parent
|
||||
anchors.topMargin: captionRow.height
|
||||
}
|
||||
}
|
||||
} // GridView.delegate
|
||||
|
||||
highlight: PlasmaCore.FrameSvgItem {
|
||||
id: highlightItem
|
||||
imagePath: "widgets/viewitem"
|
||||
prefix: "hover"
|
||||
width: thumbnailListView.width
|
||||
height: thumbnailListView.height
|
||||
}
|
||||
highlightMoveDuration: 200
|
||||
// property int selectedIndex: -1
|
||||
Connections {
|
||||
target: tabBox
|
||||
onCurrentIndexChanged: {
|
||||
thumbnailListView.currentIndex = tabBox.currentIndex
|
||||
}
|
||||
}
|
||||
|
||||
// keyNavigationEnabled: true // Requires: Qt 5.7 and QtQuick 2.? (2.7 didn't work).
|
||||
// keyNavigationWraps: true // Requires: Qt 5.7 and QtQuick 2.? (2.7 didn't work).
|
||||
|
||||
} // GridView
|
||||
|
||||
|
||||
// This doesn't work, nor does keyboard input work on any other tabbox skin (KDE 5.7.4)
|
||||
// It does work in the preview however.
|
||||
} // Dialog.mainItem
|
||||
} // Dialog
|
||||
|
||||
|
||||
}
|
||||
+16
@@ -0,0 +1,16 @@
|
||||
[Desktop Entry]
|
||||
Name=Preview Reel
|
||||
Comment=
|
||||
|
||||
Type=Service
|
||||
X-KDE-ServiceTypes=KWin/WindowSwitcher
|
||||
|
||||
X-Plasma-API=declarativeappletscript
|
||||
X-Plasma-MainScript=ui/main.qml
|
||||
|
||||
Icon=preferences-system-windows-switcher-big-icons
|
||||
X-KDE-PluginInfo-Author=Mohamed Helmy
|
||||
X-KDE-PluginInfo-Email=helmym40@gmail.com
|
||||
X-KDE-PluginInfo-Name=preview_reel
|
||||
X-KDE-PluginInfo-Version=0.1
|
||||
X-KDE-PluginInfo-Depends=
|
||||
Reference in New Issue
Block a user