Compare commits
59 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
5004417285 | ||
|
|
a110aee7ce | ||
|
|
817ea64171 | ||
|
|
af930a9b2f | ||
|
|
489a1447e7 | ||
|
|
b984f025ec | ||
|
|
4e1204f1bd | ||
|
|
bbcf51783d | ||
|
|
019da3766e | ||
|
|
1535c994b8 | ||
|
|
296d0deca9 | ||
|
|
17e7d5b46e | ||
|
|
840a50d14d | ||
|
|
4f99c4dd45 | ||
|
|
030eddaf34 | ||
|
|
7246a7660e | ||
|
|
687256d1dd | ||
|
|
12bb7506cc | ||
|
|
1808ee0025 | ||
|
|
3021f61933 | ||
|
|
e908138478 | ||
|
|
99ad115370 | ||
|
|
c5a4238f5f | ||
|
|
0670d9c265 | ||
|
|
845874b0d0 | ||
|
|
a422a077f6 | ||
|
|
2fe1be99cb | ||
|
|
1a449c238d | ||
|
|
9bda7d1a09 | ||
|
|
2ce72bcee8 | ||
|
|
ff3f6c5d6b | ||
|
|
3ab230b498 | ||
|
|
ba9f362a1c | ||
|
|
ad6c3f1cae | ||
|
|
ba4dd2a9c1 | ||
|
|
bb61853009 | ||
|
|
0cfd9b9e36 | ||
|
|
43c4f7ef9a | ||
|
|
9cb3f33ecb | ||
|
|
31b9e61ae3 | ||
|
|
668e6696ab | ||
|
|
e63959cfbf | ||
|
|
ef2650beb8 | ||
|
|
750c47c040 | ||
|
|
88ca0d02e1 | ||
|
|
aba786b754 | ||
|
|
47aa625c99 | ||
|
|
03c7cc6503 | ||
|
|
9e9ff2b74f | ||
|
|
5674624e6f | ||
|
|
44dd88ef7c | ||
|
|
f800d6ecf0 | ||
|
|
3477e17bb3 | ||
|
|
755c781646 | ||
|
|
926345ba31 | ||
|
|
a2295ede43 | ||
|
|
ca80a7ca28 | ||
|
|
64474b1677 | ||
|
|
eca63cbc16 |
2
.gitignore
vendored
2
.gitignore
vendored
@@ -1,4 +1,4 @@
|
|||||||
/package/contents/code/main.js
|
/package/contents/code/main.js
|
||||||
/package/contents/config/main.xml
|
/package/contents/config/main.xml
|
||||||
/karousel.tar.gz
|
/karousel*.tar.gz
|
||||||
/.idea
|
/.idea
|
||||||
|
|||||||
5
Makefile
5
Makefile
@@ -1,6 +1,7 @@
|
|||||||
.PHONY: *
|
.PHONY: *
|
||||||
|
|
||||||
TSC_SCRIPT_FLAGS = --lib es2020 ./src/extern/qt.d.ts
|
TSC_SCRIPT_FLAGS = --lib es2020 ./src/extern/qt.d.ts
|
||||||
|
VERSION = $(shell grep '"Version":' ./package/metadata.json | grep -o '[0-9\.]*')
|
||||||
|
|
||||||
config:
|
config:
|
||||||
mkdir -p ./package/contents/config
|
mkdir -p ./package/contents/config
|
||||||
@@ -15,8 +16,8 @@ install: build config
|
|||||||
uninstall:
|
uninstall:
|
||||||
kpackagetool5 --type=KWin/Script -r ./package
|
kpackagetool5 --type=KWin/Script -r ./package
|
||||||
|
|
||||||
package:
|
package: build config
|
||||||
tar -czf ./karousel.tar.gz ./package
|
tar -czf ./karousel_${subst .,_,${VERSION}}.tar.gz ./package
|
||||||
|
|
||||||
logs:
|
logs:
|
||||||
journalctl -t kwin_x11 -g '^qml:|^file://.*karousel' -f
|
journalctl -t kwin_x11 -g '^qml:|^file://.*karousel' -f
|
||||||
|
|||||||
@@ -13,7 +13,8 @@ unprompted reflow of window content.
|
|||||||
Windows are automatically centered when possible. And when running out of width, windows can be
|
Windows are automatically centered when possible. And when running out of width, windows can be
|
||||||
scrolled through horizontally.
|
scrolled through horizontally.
|
||||||
|
|
||||||
Similar window managers include [PaperWM](https://github.com/paperwm/PaperWM) and
|
Similar window managers include [PaperWM](https://github.com/paperwm/PaperWM),
|
||||||
|
[Niri](https://github.com/YaLTeR/niri), and
|
||||||
[Cardboard](https://gitlab.com/cardboardwm/cardboard).
|
[Cardboard](https://gitlab.com/cardboardwm/cardboard).
|
||||||
|
|
||||||
## Dependencies
|
## Dependencies
|
||||||
@@ -52,6 +53,7 @@ Here's the default ones:
|
|||||||
| Meta+Ctrl+Shift+End | Move column to end |
|
| Meta+Ctrl+Shift+End | Move column to end |
|
||||||
| Meta+Ctrl++ | Increase column width |
|
| Meta+Ctrl++ | Increase column width |
|
||||||
| Meta+Ctrl+- | Decrease column width |
|
| Meta+Ctrl+- | Decrease column width |
|
||||||
|
| Meta+Ctrl+X | Equalize widths of visible columns |
|
||||||
| Meta+Alt+Return | Center focused window (Scrolls so that the focused window is centered in the screen) |
|
| Meta+Alt+Return | Center focused window (Scrolls so that the focused window is centered in the screen) |
|
||||||
| Meta+Alt+A | Scroll one column to the left |
|
| Meta+Alt+A | Scroll one column to the left |
|
||||||
| Meta+Alt+D | Scroll one column to the right |
|
| Meta+Alt+D | Scroll one column to the right |
|
||||||
|
|||||||
@@ -5,9 +5,20 @@ console.log(`<?xml version="1.0" encoding="UTF-8"?>
|
|||||||
|
|
||||||
for (const entry of configDef) {
|
for (const entry of configDef) {
|
||||||
console.log(` <entry name="${entry.name}" type="${entry.type}">
|
console.log(` <entry name="${entry.name}" type="${entry.type}">
|
||||||
<default>${entry.default}</default>
|
<default>${escapeXml(entry.default)}</default>
|
||||||
</entry>`);
|
</entry>`);
|
||||||
}
|
}
|
||||||
|
|
||||||
console.log(` </group>
|
console.log(` </group>
|
||||||
</kcfg>`);
|
</kcfg>`);
|
||||||
|
|
||||||
|
function escapeXml(input: any) {
|
||||||
|
if (typeof input === "string") {
|
||||||
|
return input
|
||||||
|
.replace(/&/g, '&')
|
||||||
|
.replace(/</g, '<')
|
||||||
|
.replace(/>/g, '>');
|
||||||
|
} else {
|
||||||
|
return input;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@@ -21,7 +21,7 @@ function formatComment(comment: string | undefined) {
|
|||||||
|
|
||||||
function printCols(...columns: (string[] | string)[]) {
|
function printCols(...columns: (string[] | string)[]) {
|
||||||
const nCols = columns.length;
|
const nCols = columns.length;
|
||||||
if (nCols == 0) {
|
if (nCols === 0) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -30,7 +30,7 @@ function printCols(...columns: (string[] | string)[]) {
|
|||||||
).map(
|
).map(
|
||||||
(column: string[] | string) => column.length
|
(column: string[] | string) => column.length
|
||||||
));
|
));
|
||||||
if (nRows == Infinity) {
|
if (nRows === Infinity) {
|
||||||
// we only have single string columns
|
// we only have single string columns
|
||||||
nRows = 1;
|
nRows = 1;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -11,6 +11,136 @@
|
|||||||
<layout class="QVBoxLayout" name="layout_main">
|
<layout class="QVBoxLayout" name="layout_main">
|
||||||
<item>
|
<item>
|
||||||
<widget class="QTabWidget" name="tabContainer">
|
<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_stackColumnsByDefault">
|
||||||
|
<property name="text">
|
||||||
|
<string>Stack columns by default</string>
|
||||||
|
</property>
|
||||||
|
<property name="toolTip">
|
||||||
|
<string>New columns start in stacked mode (one window in the column visible, others shaded). Not supported on Wayland.</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>Layering mode</string>
|
||||||
|
</property>
|
||||||
|
<layout class="QVBoxLayout">
|
||||||
|
<item>
|
||||||
|
<widget class="QRadioButton" name="kcfg_tiledKeepBelow">
|
||||||
|
<property name="text">
|
||||||
|
<string>Keep tiled windows below</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="QRadioButton" name="kcfg_floatingKeepAbove">
|
||||||
|
<property name="text">
|
||||||
|
<string>Keep floating windows above</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">
|
<widget class="QWidget" name="tab_parameters">
|
||||||
<attribute name="title">
|
<attribute name="title">
|
||||||
<string>Parameters</string>
|
<string>Parameters</string>
|
||||||
@@ -143,14 +273,14 @@
|
|||||||
</item>
|
</item>
|
||||||
|
|
||||||
<item row="6" column="0">
|
<item row="6" column="0">
|
||||||
<widget class="QLabel" name="label_overscroll">
|
<widget class="QLabel" name="label_manualScrollStep">
|
||||||
<property name="text">
|
<property name="text">
|
||||||
<string>Overscroll amount:</string>
|
<string>Manual scroll step size:</string>
|
||||||
</property>
|
</property>
|
||||||
</widget>
|
</widget>
|
||||||
</item>
|
</item>
|
||||||
<item row="6" column="1">
|
<item row="6" column="1">
|
||||||
<widget class="QSpinBox" name="kcfg_overscroll">
|
<widget class="QSpinBox" name="kcfg_manualScrollStep">
|
||||||
<property name="suffix">
|
<property name="suffix">
|
||||||
<string> px</string>
|
<string> px</string>
|
||||||
</property>
|
</property>
|
||||||
@@ -164,14 +294,14 @@
|
|||||||
</item>
|
</item>
|
||||||
|
|
||||||
<item row="7" column="0">
|
<item row="7" column="0">
|
||||||
<widget class="QLabel" name="label_manualScrollStep">
|
<widget class="QLabel" name="label_manualResizeStep">
|
||||||
<property name="text">
|
<property name="text">
|
||||||
<string>Manual scroll step size:</string>
|
<string>Manual resize step size:</string>
|
||||||
</property>
|
</property>
|
||||||
</widget>
|
</widget>
|
||||||
</item>
|
</item>
|
||||||
<item row="7" column="1">
|
<item row="7" column="1">
|
||||||
<widget class="QSpinBox" name="kcfg_manualScrollStep">
|
<widget class="QSpinBox" name="kcfg_manualResizeStep">
|
||||||
<property name="suffix">
|
<property name="suffix">
|
||||||
<string> px</string>
|
<string> px</string>
|
||||||
</property>
|
</property>
|
||||||
@@ -207,136 +337,6 @@
|
|||||||
</layout>
|
</layout>
|
||||||
</widget>
|
</widget>
|
||||||
|
|
||||||
<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_stackColumnsByDefault">
|
|
||||||
<property name="text">
|
|
||||||
<string>Stack columns by default</string>
|
|
||||||
</property>
|
|
||||||
<property name="toolTip">
|
|
||||||
<string>New columns start in stacked mode (one window in the column visible, others shaded). Not supported on Wayland.</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>Prevent needlessly obscuring columns</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>Keep tiled windows below</string>
|
|
||||||
</property>
|
|
||||||
</widget>
|
|
||||||
</item>
|
|
||||||
<item>
|
|
||||||
<widget class="QRadioButton" name="kcfg_floatingKeepAbove">
|
|
||||||
<property name="text">
|
|
||||||
<string>Keep floating windows above</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_windowRules">
|
<widget class="QWidget" name="tab_windowRules">
|
||||||
<attribute name="title">
|
<attribute name="title">
|
||||||
<string>Window Rules</string>
|
<string>Window Rules</string>
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
{
|
{
|
||||||
"KPlugin": {
|
"KPlugin": {
|
||||||
"Name": "Karousel",
|
"Name": "Karousel",
|
||||||
"Description": "Manual columnar tiling extension for KWin",
|
"Description": "Scrollable tiling extension for KWin",
|
||||||
"Icon": "preferences-system-windows",
|
"Icon": "preferences-system-windows",
|
||||||
"Authors": [{
|
"Authors": [{
|
||||||
"Email": "peter.fajdiga@gmail.com",
|
"Email": "peter.fajdiga@gmail.com",
|
||||||
@@ -9,7 +9,7 @@
|
|||||||
}],
|
}],
|
||||||
"Id": "karousel",
|
"Id": "karousel",
|
||||||
"ServiceTypes": ["KWin/Script"],
|
"ServiceTypes": ["KWin/Script"],
|
||||||
"Version": "0.6",
|
"Version": "0.7.2",
|
||||||
"License": "GPLv3",
|
"License": "GPLv3",
|
||||||
"Website": "https://github.com/peterfajdiga/karousel",
|
"Website": "https://github.com/peterfajdiga/karousel",
|
||||||
"BugReportUrl": "https://github.com/peterfajdiga/karousel/issues"
|
"BugReportUrl": "https://github.com/peterfajdiga/karousel/issues"
|
||||||
|
|||||||
@@ -2,7 +2,7 @@ namespace Actions {
|
|||||||
export function init(world: World, config: Config) {
|
export function init(world: World, config: Config) {
|
||||||
return {
|
return {
|
||||||
focusLeft: () => {
|
focusLeft: () => {
|
||||||
world.doIfTiledFocused(true, (world, desktopManager, window, column, grid) => {
|
world.doIfTiledFocused(true, (clientManager, desktopManager, window, column, grid) => {
|
||||||
const prevColumn = grid.getPrevColumn(column);
|
const prevColumn = grid.getPrevColumn(column);
|
||||||
if (prevColumn === null) {
|
if (prevColumn === null) {
|
||||||
return;
|
return;
|
||||||
@@ -12,7 +12,7 @@ namespace Actions {
|
|||||||
},
|
},
|
||||||
|
|
||||||
focusRight: () => {
|
focusRight: () => {
|
||||||
world.doIfTiledFocused(true, (world, desktopManager, window, column, grid) => {
|
world.doIfTiledFocused(true, (clientManager, desktopManager, window, column, grid) => {
|
||||||
const nextColumn = grid.getNextColumn(column);
|
const nextColumn = grid.getNextColumn(column);
|
||||||
if (nextColumn === null) {
|
if (nextColumn === null) {
|
||||||
return;
|
return;
|
||||||
@@ -22,7 +22,7 @@ namespace Actions {
|
|||||||
},
|
},
|
||||||
|
|
||||||
focusUp: () => {
|
focusUp: () => {
|
||||||
world.doIfTiledFocused(true, (world, desktopManager, window, column, grid) => {
|
world.doIfTiledFocused(true, (clientManager, desktopManager, window, column, grid) => {
|
||||||
const prevWindow = column.getPrevWindow(window);
|
const prevWindow = column.getPrevWindow(window);
|
||||||
if (prevWindow === null) {
|
if (prevWindow === null) {
|
||||||
return;
|
return;
|
||||||
@@ -32,7 +32,7 @@ namespace Actions {
|
|||||||
},
|
},
|
||||||
|
|
||||||
focusDown: () => {
|
focusDown: () => {
|
||||||
world.doIfTiledFocused(true, (world, desktopManager, window, column, grid) => {
|
world.doIfTiledFocused(true, (clientManager, desktopManager, window, column, grid) => {
|
||||||
const nextWindow = column.getNextWindow(window);
|
const nextWindow = column.getNextWindow(window);
|
||||||
if (nextWindow === null) {
|
if (nextWindow === null) {
|
||||||
return;
|
return;
|
||||||
@@ -64,7 +64,7 @@ namespace Actions {
|
|||||||
},
|
},
|
||||||
|
|
||||||
windowMoveLeft: () => {
|
windowMoveLeft: () => {
|
||||||
world.doIfTiledFocused(true, (world, desktopManager, window, column, grid) => {
|
world.doIfTiledFocused(true, (clientManager, desktopManager, window, column, grid) => {
|
||||||
if (column.getWindowCount() === 1) {
|
if (column.getWindowCount() === 1) {
|
||||||
// move from own column into existing column
|
// move from own column into existing column
|
||||||
const prevColumn = grid.getPrevColumn(column);
|
const prevColumn = grid.getPrevColumn(column);
|
||||||
@@ -82,7 +82,7 @@ namespace Actions {
|
|||||||
},
|
},
|
||||||
|
|
||||||
windowMoveRight: () => {
|
windowMoveRight: () => {
|
||||||
world.doIfTiledFocused(true, (world, desktopManager, window, column, grid) => {
|
world.doIfTiledFocused(true, (clientManager, desktopManager, window, column, grid) => {
|
||||||
if (column.getWindowCount() === 1) {
|
if (column.getWindowCount() === 1) {
|
||||||
// move from own column into existing column
|
// move from own column into existing column
|
||||||
const nextColumn = grid.getNextColumn(column);
|
const nextColumn = grid.getNextColumn(column);
|
||||||
@@ -101,27 +101,27 @@ namespace Actions {
|
|||||||
|
|
||||||
windowMoveUp: () => {
|
windowMoveUp: () => {
|
||||||
// TODO (optimization): only arrange moved windows
|
// TODO (optimization): only arrange moved windows
|
||||||
world.doIfTiledFocused(true, (world, desktopManager, window, column, grid) => {
|
world.doIfTiledFocused(true, (clientManager, desktopManager, window, column, grid) => {
|
||||||
column.moveWindowUp(window);
|
column.moveWindowUp(window);
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
|
|
||||||
windowMoveDown: () => {
|
windowMoveDown: () => {
|
||||||
// TODO (optimization): only arrange moved windows
|
// TODO (optimization): only arrange moved windows
|
||||||
world.doIfTiledFocused(true, (world, desktopManager, window, column, grid) => {
|
world.doIfTiledFocused(true, (clientManager, desktopManager, window, column, grid) => {
|
||||||
column.moveWindowDown(window);
|
column.moveWindowDown(window);
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
|
|
||||||
windowMoveStart: () => {
|
windowMoveStart: () => {
|
||||||
world.doIfTiledFocused(true, (world, desktopManager, window, column, grid) => {
|
world.doIfTiledFocused(true, (clientManager, desktopManager, window, column, grid) => {
|
||||||
const newColumn = new Column(grid, null);
|
const newColumn = new Column(grid, null);
|
||||||
window.moveToColumn(newColumn);
|
window.moveToColumn(newColumn);
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
|
|
||||||
windowMoveEnd: () => {
|
windowMoveEnd: () => {
|
||||||
world.doIfTiledFocused(true, (world, desktopManager, window, column, grid) => {
|
world.doIfTiledFocused(true, (clientManager, desktopManager, window, column, grid) => {
|
||||||
const newColumn = new Column(grid, grid.getLastColumn());
|
const newColumn = new Column(grid, grid.getLastColumn());
|
||||||
window.moveToColumn(newColumn);
|
window.moveToColumn(newColumn);
|
||||||
});
|
});
|
||||||
@@ -135,44 +135,44 @@ namespace Actions {
|
|||||||
},
|
},
|
||||||
|
|
||||||
columnMoveLeft: () => {
|
columnMoveLeft: () => {
|
||||||
world.doIfTiledFocused(true, (world, desktopManager, window, column, grid) => {
|
world.doIfTiledFocused(true, (clientManager, desktopManager, window, column, grid) => {
|
||||||
grid.moveColumnLeft(column);
|
grid.moveColumnLeft(column);
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
|
|
||||||
columnMoveRight: () => {
|
columnMoveRight: () => {
|
||||||
world.doIfTiledFocused(true, (world, desktopManager, window, column, grid) => {
|
world.doIfTiledFocused(true, (clientManager, desktopManager, window, column, grid) => {
|
||||||
grid.moveColumnRight(column);
|
grid.moveColumnRight(column);
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
|
|
||||||
columnMoveStart: () => {
|
columnMoveStart: () => {
|
||||||
world.doIfTiledFocused(true, (world, desktopManager, window, column, grid) => {
|
world.doIfTiledFocused(true, (clientManager, desktopManager, window, column, grid) => {
|
||||||
column.moveAfter(null);
|
column.moveAfter(null);
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
|
|
||||||
columnMoveEnd: () => {
|
columnMoveEnd: () => {
|
||||||
world.doIfTiledFocused(true, (world, desktopManager, window, column, grid) => {
|
world.doIfTiledFocused(true, (clientManager, desktopManager, window, column, grid) => {
|
||||||
column.moveAfter(grid.getLastColumn());
|
column.moveAfter(grid.getLastColumn());
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
|
|
||||||
columnToggleStacked: () => {
|
columnToggleStacked: () => {
|
||||||
world.doIfTiledFocused(false, (world, desktopManager, window, column, grid) => {
|
world.doIfTiledFocused(false, (clientManager, desktopManager, window, column, grid) => {
|
||||||
column.toggleStacked();
|
column.toggleStacked();
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
|
|
||||||
columnWidthIncrease: () => {
|
columnWidthIncrease: () => {
|
||||||
world.doIfTiledFocused(false, (world, desktopManager, window, column, grid) => {
|
world.doIfTiledFocused(false, (clientManager, desktopManager, window, column, grid) => {
|
||||||
grid.increaseColumnWidth(column);
|
config.columnResizer.increaseWidth(column, config.manualResizeStep);
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
|
|
||||||
columnWidthDecrease: () => {
|
columnWidthDecrease: () => {
|
||||||
world.doIfTiledFocused(false, (world, desktopManager, window, column, grid) => {
|
world.doIfTiledFocused(false, (clientManager, desktopManager, window, column, grid) => {
|
||||||
grid.decreaseColumnWidth(column);
|
config.columnResizer.decreaseWidth(column, config.manualResizeStep);
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
|
|
||||||
@@ -213,7 +213,7 @@ namespace Actions {
|
|||||||
},
|
},
|
||||||
|
|
||||||
gridScrollFocused: () => {
|
gridScrollFocused: () => {
|
||||||
world.doIfTiledFocused(true, (world, desktopManager, window, column, grid) => {
|
world.doIfTiledFocused(true, (clientManager, desktopManager, window, column, grid) => {
|
||||||
grid.desktop.scrollCenterRange(column);
|
grid.desktop.scrollCenterRange(column);
|
||||||
})
|
})
|
||||||
},
|
},
|
||||||
@@ -261,17 +261,17 @@ namespace Actions {
|
|||||||
const grid = desktopManager.getCurrentDesktop().grid;
|
const grid = desktopManager.getCurrentDesktop().grid;
|
||||||
const targetColumn = grid.getColumnAtIndex(columnIndex);
|
const targetColumn = grid.getColumnAtIndex(columnIndex);
|
||||||
if (targetColumn === null) {
|
if (targetColumn === null) {
|
||||||
return null;
|
return;
|
||||||
}
|
}
|
||||||
targetColumn.focus();
|
targetColumn.focus();
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
|
|
||||||
windowMoveToColumn: (columnIndex: number) => {
|
windowMoveToColumn: (columnIndex: number) => {
|
||||||
world.doIfTiledFocused(true, (world, desktopManager, window, column, grid) => {
|
world.doIfTiledFocused(true, (clientManager, desktopManager, window, column, grid) => {
|
||||||
const targetColumn = grid.getColumnAtIndex(columnIndex);
|
const targetColumn = grid.getColumnAtIndex(columnIndex);
|
||||||
if (targetColumn === null) {
|
if (targetColumn === null) {
|
||||||
return null;
|
return;
|
||||||
}
|
}
|
||||||
window.moveToColumn(targetColumn);
|
window.moveToColumn(targetColumn);
|
||||||
grid.desktop.autoAdjustScroll();
|
grid.desktop.autoAdjustScroll();
|
||||||
@@ -279,10 +279,10 @@ namespace Actions {
|
|||||||
},
|
},
|
||||||
|
|
||||||
columnMoveToColumn: (columnIndex: number) => {
|
columnMoveToColumn: (columnIndex: number) => {
|
||||||
world.doIfTiledFocused(true, (world, desktopManager, window, column, grid) => {
|
world.doIfTiledFocused(true, (clientManager, desktopManager, window, column, grid) => {
|
||||||
const targetColumn = grid.getColumnAtIndex(columnIndex);
|
const targetColumn = grid.getColumnAtIndex(columnIndex);
|
||||||
if (targetColumn === null || targetColumn === column) {
|
if (targetColumn === null || targetColumn === column) {
|
||||||
return null;
|
return;
|
||||||
}
|
}
|
||||||
if (targetColumn.isAfter(column)) {
|
if (targetColumn.isAfter(column)) {
|
||||||
column.moveAfter(targetColumn);
|
column.moveAfter(targetColumn);
|
||||||
@@ -325,5 +325,12 @@ namespace Actions {
|
|||||||
|
|
||||||
export type Config = {
|
export type Config = {
|
||||||
manualScrollStep: number,
|
manualScrollStep: number,
|
||||||
|
manualResizeStep: number,
|
||||||
|
columnResizer: ColumnResizer,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export type ColumnResizer = {
|
||||||
|
increaseWidth(column: Column, step: number): void,
|
||||||
|
decreaseWidth(column: Column, step: number): void,
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,10 +0,0 @@
|
|||||||
enum ClientAreaOption {
|
|
||||||
PlacementArea,
|
|
||||||
MovementArea,
|
|
||||||
MaximizeArea,
|
|
||||||
MaximizeFullArea,
|
|
||||||
FullScreenArea,
|
|
||||||
WorkArea,
|
|
||||||
FullArea,
|
|
||||||
ScreenArea,
|
|
||||||
}
|
|
||||||
96
src/behavior/columnResizer/ContextualResizer.ts
Normal file
96
src/behavior/columnResizer/ContextualResizer.ts
Normal file
@@ -0,0 +1,96 @@
|
|||||||
|
class ContextualResizer {
|
||||||
|
public increaseWidth(column: Column, step: number) {
|
||||||
|
const grid = column.grid;
|
||||||
|
const desktop = grid.desktop;
|
||||||
|
const visibleRange = desktop.getCurrentVisibleRange();
|
||||||
|
if(!column.isVisible(visibleRange, true) || column.getWidth() >= column.getMaxWidth()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
let leftVisibleColumn = grid.getLeftmostVisibleColumn(visibleRange, true);
|
||||||
|
let rightVisibleColumn = grid.getRightmostVisibleColumn(visibleRange, true);
|
||||||
|
if (leftVisibleColumn === null || rightVisibleColumn === null) {
|
||||||
|
console.assert(false); // should at least see self
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const leftSpace = leftVisibleColumn.getLeft() - visibleRange.getLeft();
|
||||||
|
const rightSpace = visibleRange.getRight() - rightVisibleColumn.getRight();
|
||||||
|
|
||||||
|
const newWidth = ContextualResizer.findNextStep(
|
||||||
|
[
|
||||||
|
visibleRange.getWidth(),
|
||||||
|
column.getWidth() + step,
|
||||||
|
column.getWidth() + leftSpace + rightSpace,
|
||||||
|
column.getWidth() + leftSpace + rightSpace + leftVisibleColumn.getWidth() + grid.config.gapsInnerHorizontal,
|
||||||
|
column.getWidth() + leftSpace + rightSpace + rightVisibleColumn.getWidth() + grid.config.gapsInnerHorizontal,
|
||||||
|
],
|
||||||
|
width => width - column.getWidth(),
|
||||||
|
)
|
||||||
|
if (newWidth === undefined) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
column.setWidth(newWidth, true);
|
||||||
|
desktop.scrollCenterVisible(column);
|
||||||
|
}
|
||||||
|
|
||||||
|
public decreaseWidth(column: Column, step: number) {
|
||||||
|
const grid = column.grid;
|
||||||
|
const desktop = grid.desktop;
|
||||||
|
const visibleRange = desktop.getCurrentVisibleRange();
|
||||||
|
if(!column.isVisible(visibleRange, true) || column.getWidth() <= column.getMinWidth()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const leftVisibleColumn = grid.getLeftmostVisibleColumn(visibleRange, true);
|
||||||
|
const rightVisibleColumn = grid.getRightmostVisibleColumn(visibleRange, true);
|
||||||
|
if (leftVisibleColumn === null || rightVisibleColumn === null) {
|
||||||
|
console.assert(false); // should at least see self
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
let leftOffScreenColumn = grid.getPrevColumn(leftVisibleColumn);
|
||||||
|
if (leftOffScreenColumn === column) {
|
||||||
|
leftOffScreenColumn = null;
|
||||||
|
}
|
||||||
|
let rightOffScreenColumn = grid.getNextColumn(rightVisibleColumn);
|
||||||
|
if (rightOffScreenColumn === column) {
|
||||||
|
rightOffScreenColumn = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
const visibleColumnsWidth = rightVisibleColumn.getRight() - leftVisibleColumn.getLeft();
|
||||||
|
const unusedWidth = visibleRange.getWidth() - visibleColumnsWidth;
|
||||||
|
const leftOffScreen = leftOffScreenColumn === null ? 0 : leftOffScreenColumn.getWidth() + grid.config.gapsInnerHorizontal - unusedWidth;
|
||||||
|
const rightOffScreen = rightOffScreenColumn === null ? 0 : rightOffScreenColumn.getWidth() + grid.config.gapsInnerHorizontal - unusedWidth;
|
||||||
|
|
||||||
|
const newWidth = ContextualResizer.findNextStep(
|
||||||
|
[
|
||||||
|
visibleRange.getWidth(),
|
||||||
|
column.getWidth() - step,
|
||||||
|
column.getWidth() - leftOffScreen,
|
||||||
|
column.getWidth() - rightOffScreen,
|
||||||
|
],
|
||||||
|
width => column.getWidth() - width,
|
||||||
|
)
|
||||||
|
if (newWidth === undefined) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
column.setWidth(newWidth, true);
|
||||||
|
desktop.scrollCenterVisible(column);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static findNextStep(steps: number[], evaluate: (step: number) => number) {
|
||||||
|
let bestScore = Infinity;
|
||||||
|
let bestStep = undefined;
|
||||||
|
for (const step of steps) {
|
||||||
|
const score = evaluate(step);
|
||||||
|
if (score > 0 && score < bestScore) {
|
||||||
|
bestScore = score;
|
||||||
|
bestStep = step;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return bestStep;
|
||||||
|
}
|
||||||
|
}
|
||||||
9
src/behavior/columnResizer/RawResizer.ts
Normal file
9
src/behavior/columnResizer/RawResizer.ts
Normal file
@@ -0,0 +1,9 @@
|
|||||||
|
class RawResizer {
|
||||||
|
public increaseWidth(column: Column, step: number) {
|
||||||
|
column.adjustWidth(step, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
public decreaseWidth(column: Column, step: number) {
|
||||||
|
column.adjustWidth(-step, true);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,13 +1,5 @@
|
|||||||
class ScrollerCentered {
|
class CenterClamper {
|
||||||
public scrollToColumn(desktop: Desktop, column: Column) {
|
|
||||||
desktop.scrollCenterRange(column);
|
|
||||||
}
|
|
||||||
|
|
||||||
public clampScrollX(desktop: Desktop, x: number) {
|
public clampScrollX(desktop: Desktop, x: number) {
|
||||||
return ScrollerCentered.clampScrollX(desktop, x);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static clampScrollX(desktop: Desktop, x: number) {
|
|
||||||
const firstColumn = desktop.grid.getFirstColumn();
|
const firstColumn = desktop.grid.getFirstColumn();
|
||||||
if (firstColumn === null) {
|
if (firstColumn === null) {
|
||||||
return 0;
|
return 0;
|
||||||
@@ -1,8 +1,4 @@
|
|||||||
class ScrollerLazy {
|
class EdgeClamper {
|
||||||
public scrollToColumn(desktop: Desktop, column: Column) {
|
|
||||||
desktop.scrollToRange(column);
|
|
||||||
}
|
|
||||||
|
|
||||||
public clampScrollX(desktop: Desktop, x: number) {
|
public clampScrollX(desktop: Desktop, x: number) {
|
||||||
let minScroll = 0;
|
let minScroll = 0;
|
||||||
let maxScroll = desktop.grid.getWidth() - desktop.tilingArea.width;
|
let maxScroll = desktop.grid.getWidth() - desktop.tilingArea.width;
|
||||||
5
src/behavior/scroller/CenteredScroller.ts
Normal file
5
src/behavior/scroller/CenteredScroller.ts
Normal file
@@ -0,0 +1,5 @@
|
|||||||
|
class CenteredScroller {
|
||||||
|
public scrollToColumn(desktop: Desktop, column: Column) {
|
||||||
|
desktop.scrollCenterRange(column);
|
||||||
|
}
|
||||||
|
}
|
||||||
5
src/behavior/scroller/GroupedScroller.ts
Normal file
5
src/behavior/scroller/GroupedScroller.ts
Normal file
@@ -0,0 +1,5 @@
|
|||||||
|
class GroupedScroller {
|
||||||
|
public scrollToColumn(desktop: Desktop, column: Column) {
|
||||||
|
desktop.scrollCenterVisible(column);
|
||||||
|
}
|
||||||
|
}
|
||||||
5
src/behavior/scroller/LazyScroller.ts
Normal file
5
src/behavior/scroller/LazyScroller.ts
Normal file
@@ -0,0 +1,5 @@
|
|||||||
|
class LazyScroller {
|
||||||
|
public scrollToColumn(desktop: Desktop, column: Column) {
|
||||||
|
desktop.scrollIntoView(column);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -5,8 +5,8 @@ type Config = {
|
|||||||
gapsOuterRight: number,
|
gapsOuterRight: number,
|
||||||
gapsInnerHorizontal: number,
|
gapsInnerHorizontal: number,
|
||||||
gapsInnerVertical: number,
|
gapsInnerVertical: number,
|
||||||
overscroll: number,
|
|
||||||
manualScrollStep: number,
|
manualScrollStep: number,
|
||||||
|
manualResizeStep: number,
|
||||||
offScreenOpacity: number,
|
offScreenOpacity: number,
|
||||||
untileOnDrag: boolean,
|
untileOnDrag: boolean,
|
||||||
stackColumnsByDefault: boolean,
|
stackColumnsByDefault: boolean,
|
||||||
|
|||||||
@@ -72,103 +72,103 @@ const defaultWindowRules = `[
|
|||||||
|
|
||||||
const configDef = [
|
const configDef = [
|
||||||
{
|
{
|
||||||
"name": "gapsOuterTop",
|
name: "gapsOuterTop",
|
||||||
"type": "UInt",
|
type: "UInt",
|
||||||
"default": 18
|
default: 18,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "gapsOuterBottom",
|
name: "gapsOuterBottom",
|
||||||
"type": "UInt",
|
type: "UInt",
|
||||||
"default": 18
|
default: 18,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "gapsOuterLeft",
|
name: "gapsOuterLeft",
|
||||||
"type": "UInt",
|
type: "UInt",
|
||||||
"default": 18
|
default: 18,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "gapsOuterRight",
|
name: "gapsOuterRight",
|
||||||
"type": "UInt",
|
type: "UInt",
|
||||||
"default": 18
|
default: 18,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "gapsInnerHorizontal",
|
name: "gapsInnerHorizontal",
|
||||||
"type": "UInt",
|
type: "UInt",
|
||||||
"default": 18
|
default: 18,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "gapsInnerVertical",
|
name: "gapsInnerVertical",
|
||||||
"type": "UInt",
|
type: "UInt",
|
||||||
"default": 18
|
default: 18,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "overscroll",
|
name: "manualScrollStep",
|
||||||
"type": "UInt",
|
type: "UInt",
|
||||||
"default": 0
|
default: 200,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "manualScrollStep",
|
name: "manualResizeStep",
|
||||||
"type": "UInt",
|
type: "UInt",
|
||||||
"default": 200
|
default: 600,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "offScreenOpacity",
|
name: "offScreenOpacity",
|
||||||
"type": "UInt",
|
type: "UInt",
|
||||||
"default": 100
|
default: 100,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "untileOnDrag",
|
name: "untileOnDrag",
|
||||||
"type": "Bool",
|
type: "Bool",
|
||||||
"default": true
|
default: true,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "stackColumnsByDefault",
|
name: "stackColumnsByDefault",
|
||||||
"type": "Bool",
|
type: "Bool",
|
||||||
"default": false
|
default: false,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "resizeNeighborColumn",
|
name: "resizeNeighborColumn",
|
||||||
"type": "Bool",
|
type: "Bool",
|
||||||
"default": false
|
default: false,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "reMaximize",
|
name: "reMaximize",
|
||||||
"type": "Bool",
|
type: "Bool",
|
||||||
"default": false
|
default: false,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "skipSwitcher",
|
name: "skipSwitcher",
|
||||||
"type": "Bool",
|
type: "Bool",
|
||||||
"default": false
|
default: false,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "scrollingLazy",
|
name: "scrollingLazy",
|
||||||
"type": "Bool",
|
type: "Bool",
|
||||||
"default": true
|
default: true,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "scrollingCentered",
|
name: "scrollingCentered",
|
||||||
"type": "Bool",
|
type: "Bool",
|
||||||
"default": false
|
default: false,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "scrollingGrouped",
|
name: "scrollingGrouped",
|
||||||
"type": "Bool",
|
type: "Bool",
|
||||||
"default": false
|
default: false,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "tiledKeepBelow",
|
name: "tiledKeepBelow",
|
||||||
"type": "Bool",
|
type: "Bool",
|
||||||
"default": true
|
default: true,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "floatingKeepAbove",
|
name: "floatingKeepAbove",
|
||||||
"type": "Bool",
|
type: "Bool",
|
||||||
"default": false
|
default: false,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "windowRules",
|
name: "windowRules",
|
||||||
"type": "String",
|
type: "String",
|
||||||
"default": defaultWindowRules
|
default: defaultWindowRules,
|
||||||
}
|
}
|
||||||
];
|
];
|
||||||
|
|||||||
62
src/extern/kwin.d.ts
vendored
62
src/extern/kwin.d.ts
vendored
@@ -1,39 +1,44 @@
|
|||||||
declare const KWin: {
|
declare const KWin: {
|
||||||
// Functions
|
|
||||||
readConfig(key: string, defaultValue: any): any;
|
readConfig(key: string, defaultValue: any): any;
|
||||||
registerShortcut(name: string, description: string, keySequence: string, callback: () => void): void;
|
registerShortcut(name: string, description: string, keySequence: string, callback: () => void): void;
|
||||||
};
|
};
|
||||||
|
|
||||||
declare const workspace: {
|
declare const workspace: {
|
||||||
// Read-write Properties
|
|
||||||
readonly desktops: number;
|
readonly desktops: number;
|
||||||
readonly currentDesktop: number;
|
readonly currentDesktop: number;
|
||||||
readonly currentActivity: string;
|
readonly currentActivity: string;
|
||||||
|
|
||||||
// Read-write Properties
|
|
||||||
activeClient: KwinClient;
|
activeClient: KwinClient;
|
||||||
|
|
||||||
// Signals
|
readonly currentDesktopChanged: QSignal<[]>
|
||||||
currentDesktopChanged: QSignal<[oldDesktopNumber: number]>
|
readonly clientAdded: QSignal<[KwinClient]>;
|
||||||
clientAdded: QSignal<[KwinClient]>;
|
readonly clientRemoved: QSignal<[KwinClient]>;
|
||||||
clientRemoved: QSignal<[KwinClient]>;
|
readonly clientMinimized: QSignal<[KwinClient]>;
|
||||||
clientMinimized: QSignal<[KwinClient]>;
|
readonly clientUnminimized: QSignal<[KwinClient]>;
|
||||||
clientUnminimized: QSignal<[KwinClient]>;
|
readonly clientMaximizeSet: QSignal<[KwinClient, horizontally: boolean, vertically: boolean]>;
|
||||||
clientMaximizeSet: QSignal<[KwinClient, horizontally: boolean, vertically: boolean]>;
|
readonly clientActivated: QSignal<[KwinClient]>;
|
||||||
clientActivated: QSignal<[KwinClient]>;
|
readonly numberDesktopsChanged: QSignal<[]>;
|
||||||
numberDesktopsChanged: QSignal<[oldNumberOfVirtualDesktops: number]>;
|
readonly currentActivityChanged: QSignal<[]>;
|
||||||
currentActivityChanged: QSignal<[newActivity: string]>;
|
readonly virtualScreenSizeChanged: QSignal<[]>;
|
||||||
virtualScreenSizeChanged: QSignal<[void]>;
|
|
||||||
|
|
||||||
// Functions
|
|
||||||
clientArea(option: ClientAreaOption, screenNumber: number, desktopNumber: number);
|
clientArea(option: ClientAreaOption, screenNumber: number, desktopNumber: number);
|
||||||
clientList(): KwinClient[];
|
clientList(): KwinClient[];
|
||||||
};
|
};
|
||||||
|
|
||||||
type Tile = any;
|
const enum ClientAreaOption {
|
||||||
|
PlacementArea,
|
||||||
|
MovementArea,
|
||||||
|
MaximizeArea,
|
||||||
|
MaximizeFullArea,
|
||||||
|
FullScreenArea,
|
||||||
|
WorkArea,
|
||||||
|
FullArea,
|
||||||
|
ScreenArea,
|
||||||
|
}
|
||||||
|
|
||||||
|
type Tile = unknown;
|
||||||
|
|
||||||
interface KwinClient {
|
interface KwinClient {
|
||||||
// Read-only Properties
|
|
||||||
readonly shadeable: boolean;
|
readonly shadeable: boolean;
|
||||||
readonly caption: string;
|
readonly caption: string;
|
||||||
readonly minSize: QmlSize;
|
readonly minSize: QmlSize;
|
||||||
@@ -47,9 +52,8 @@ interface KwinClient {
|
|||||||
readonly dock: boolean;
|
readonly dock: boolean;
|
||||||
readonly normalWindow: boolean;
|
readonly normalWindow: boolean;
|
||||||
readonly managed: boolean;
|
readonly managed: boolean;
|
||||||
opacity: number;
|
|
||||||
|
|
||||||
// Read-write Properties
|
opacity: number;
|
||||||
fullScreen: boolean;
|
fullScreen: boolean;
|
||||||
activities: string[]; // empty array means all activities
|
activities: string[]; // empty array means all activities
|
||||||
skipSwitcher: boolean;
|
skipSwitcher: boolean;
|
||||||
@@ -61,17 +65,15 @@ interface KwinClient {
|
|||||||
desktop: number; // -1 means all desktops
|
desktop: number; // -1 means all desktops
|
||||||
tile: Tile;
|
tile: Tile;
|
||||||
|
|
||||||
// Signals
|
readonly fullScreenChanged: QSignal<[]>;
|
||||||
fullScreenChanged: QSignal<[void]>;
|
readonly desktopChanged: QSignal<[]>;
|
||||||
desktopChanged: QSignal<[void]>;
|
readonly activitiesChanged: QSignal<[]>;
|
||||||
activitiesChanged: QSignal<[KwinClient]>;
|
readonly captionChanged: QSignal<[]>;
|
||||||
captionChanged: QSignal<[void]>;
|
readonly tileChanged: QSignal<[]>;
|
||||||
tileChanged: QSignal<[Tile]>;
|
readonly moveResizedChanged: QSignal<[]>;
|
||||||
moveResizedChanged: QSignal<[void]>;
|
readonly moveResizeCursorChanged: QSignal<[]>;
|
||||||
moveResizeCursorChanged: QSignal<[void]>;
|
readonly clientStartUserMovedResized: QSignal<[]>;
|
||||||
clientStartUserMovedResized: QSignal<[void]>;
|
readonly frameGeometryChanged: QSignal<[KwinClient, oldGeometry: QmlRect]>;
|
||||||
frameGeometryChanged: QSignal<[KwinClient, oldGeometry: QmlRect]>;
|
|
||||||
|
|
||||||
// Functions
|
|
||||||
setMaximize(vertically: boolean, horizontally: boolean): void;
|
setMaximize(vertically: boolean, horizontally: boolean): void;
|
||||||
}
|
}
|
||||||
|
|||||||
3
src/extern/qt.d.ts
vendored
3
src/extern/qt.d.ts
vendored
@@ -1,5 +1,6 @@
|
|||||||
declare const console: {
|
declare const console: {
|
||||||
log(...args: any[]);
|
log(...args: any[]);
|
||||||
|
trace();
|
||||||
assert(boolean);
|
assert(boolean);
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -35,7 +36,7 @@ type QSignal<T extends unknown[]> = {
|
|||||||
|
|
||||||
type QmlTimer = {
|
type QmlTimer = {
|
||||||
interval: number;
|
interval: number;
|
||||||
triggered: QSignal<[void]>;
|
readonly triggered: QSignal<[]>;
|
||||||
restart(): void;
|
restart(): void;
|
||||||
destroy(): void;
|
destroy(): void;
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -1,218 +1,218 @@
|
|||||||
const keyBindings: KeyBinding[] = [
|
const keyBindings: KeyBinding[] = [
|
||||||
{
|
{
|
||||||
"name": "window-toggle-floating",
|
name: "window-toggle-floating",
|
||||||
"description": "Toggle floating",
|
description: "Toggle floating",
|
||||||
"defaultKeySequence": "Meta+Space",
|
defaultKeySequence: "Meta+Space",
|
||||||
"action": "windowToggleFloating",
|
action: "windowToggleFloating",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "focus-left",
|
name: "focus-left",
|
||||||
"description": "Move focus left",
|
description: "Move focus left",
|
||||||
"defaultKeySequence": "Meta+A",
|
defaultKeySequence: "Meta+A",
|
||||||
"action": "focusLeft",
|
action: "focusLeft",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "focus-right",
|
name: "focus-right",
|
||||||
"description": "Move focus right",
|
description: "Move focus right",
|
||||||
"comment": "Clashes with default KDE shortcuts, may require manual remapping",
|
comment: "Clashes with default KDE shortcuts, may require manual remapping",
|
||||||
"defaultKeySequence": "Meta+D",
|
defaultKeySequence: "Meta+D",
|
||||||
"action": "focusRight",
|
action: "focusRight",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "focus-up",
|
name: "focus-up",
|
||||||
"description": "Move focus up",
|
description: "Move focus up",
|
||||||
"comment": "Clashes with default KDE shortcuts, may require manual remapping",
|
comment: "Clashes with default KDE shortcuts, may require manual remapping",
|
||||||
"defaultKeySequence": "Meta+W",
|
defaultKeySequence: "Meta+W",
|
||||||
"action": "focusUp",
|
action: "focusUp",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "focus-down",
|
name: "focus-down",
|
||||||
"description": "Move focus down",
|
description: "Move focus down",
|
||||||
"comment": "Clashes with default KDE shortcuts, may require manual remapping",
|
comment: "Clashes with default KDE shortcuts, may require manual remapping",
|
||||||
"defaultKeySequence": "Meta+S",
|
defaultKeySequence: "Meta+S",
|
||||||
"action": "focusDown",
|
action: "focusDown",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "focus-start",
|
name: "focus-start",
|
||||||
"description": "Move focus to start",
|
description: "Move focus to start",
|
||||||
"defaultKeySequence": "Meta+Home",
|
defaultKeySequence: "Meta+Home",
|
||||||
"action": "focusStart",
|
action: "focusStart",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "focus-end",
|
name: "focus-end",
|
||||||
"description": "Move focus to end",
|
description: "Move focus to end",
|
||||||
"defaultKeySequence": "Meta+End",
|
defaultKeySequence: "Meta+End",
|
||||||
"action": "focusEnd",
|
action: "focusEnd",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "window-move-left",
|
name: "window-move-left",
|
||||||
"description": "Move window left",
|
description: "Move window left",
|
||||||
"comment": "Moves window out of and into columns",
|
comment: "Moves window out of and into columns",
|
||||||
"defaultKeySequence": "Meta+Shift+A",
|
defaultKeySequence: "Meta+Shift+A",
|
||||||
"action": "windowMoveLeft",
|
action: "windowMoveLeft",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "window-move-right",
|
name: "window-move-right",
|
||||||
"description": "Move window right",
|
description: "Move window right",
|
||||||
"comment": "Moves window out of and into columns",
|
comment: "Moves window out of and into columns",
|
||||||
"defaultKeySequence": "Meta+Shift+D",
|
defaultKeySequence: "Meta+Shift+D",
|
||||||
"action": "windowMoveRight",
|
action: "windowMoveRight",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "window-move-up",
|
name: "window-move-up",
|
||||||
"description": "Move window up",
|
description: "Move window up",
|
||||||
"defaultKeySequence": "Meta+Shift+W",
|
defaultKeySequence: "Meta+Shift+W",
|
||||||
"action": "windowMoveUp",
|
action: "windowMoveUp",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "window-move-down",
|
name: "window-move-down",
|
||||||
"description": "Move window down",
|
description: "Move window down",
|
||||||
"defaultKeySequence": "Meta+Shift+S",
|
defaultKeySequence: "Meta+Shift+S",
|
||||||
"action": "windowMoveDown",
|
action: "windowMoveDown",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "window-move-start",
|
name: "window-move-start",
|
||||||
"description": "Move window to start",
|
description: "Move window to start",
|
||||||
"defaultKeySequence": "Meta+Shift+Home",
|
defaultKeySequence: "Meta+Shift+Home",
|
||||||
"action": "windowMoveStart",
|
action: "windowMoveStart",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "window-move-end",
|
name: "window-move-end",
|
||||||
"description": "Move window to end",
|
description: "Move window to end",
|
||||||
"defaultKeySequence": "Meta+Shift+End",
|
defaultKeySequence: "Meta+Shift+End",
|
||||||
"action": "windowMoveEnd",
|
action: "windowMoveEnd",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "column-toggle-stacked",
|
name: "column-toggle-stacked",
|
||||||
"description": "Toggle stacked layout for focused column",
|
description: "Toggle stacked layout for focused column",
|
||||||
"comment": "One window in the column visible, others shaded; not supported on Wayland",
|
comment: "One window in the column visible, others shaded; not supported on Wayland",
|
||||||
"defaultKeySequence": "Meta+X",
|
defaultKeySequence: "Meta+X",
|
||||||
"action": "columnToggleStacked",
|
action: "columnToggleStacked",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "column-move-left",
|
name: "column-move-left",
|
||||||
"description": "Move column left",
|
description: "Move column left",
|
||||||
"defaultKeySequence": "Meta+Ctrl+Shift+A",
|
defaultKeySequence: "Meta+Ctrl+Shift+A",
|
||||||
"action": "columnMoveLeft",
|
action: "columnMoveLeft",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "column-move-right",
|
name: "column-move-right",
|
||||||
"description": "Move column right",
|
description: "Move column right",
|
||||||
"defaultKeySequence": "Meta+Ctrl+Shift+D",
|
defaultKeySequence: "Meta+Ctrl+Shift+D",
|
||||||
"action": "columnMoveRight",
|
action: "columnMoveRight",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "column-move-start",
|
name: "column-move-start",
|
||||||
"description": "Move column to start",
|
description: "Move column to start",
|
||||||
"defaultKeySequence": "Meta+Ctrl+Shift+Home",
|
defaultKeySequence: "Meta+Ctrl+Shift+Home",
|
||||||
"action": "columnMoveStart",
|
action: "columnMoveStart",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "column-move-end",
|
name: "column-move-end",
|
||||||
"description": "Move column to end",
|
description: "Move column to end",
|
||||||
"defaultKeySequence": "Meta+Ctrl+Shift+End",
|
defaultKeySequence: "Meta+Ctrl+Shift+End",
|
||||||
"action": "columnMoveEnd",
|
action: "columnMoveEnd",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "column-width-increase",
|
name: "column-width-increase",
|
||||||
"description": "Increase column width",
|
description: "Increase column width",
|
||||||
"defaultKeySequence": "Meta+Ctrl++",
|
defaultKeySequence: "Meta+Ctrl++",
|
||||||
"action": "columnWidthIncrease",
|
action: "columnWidthIncrease",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "column-width-decrease",
|
name: "column-width-decrease",
|
||||||
"description": "Decrease column width",
|
description: "Decrease column width",
|
||||||
"defaultKeySequence": "Meta+Ctrl+-",
|
defaultKeySequence: "Meta+Ctrl+-",
|
||||||
"action": "columnWidthDecrease",
|
action: "columnWidthDecrease",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "columns-width-equalize",
|
name: "columns-width-equalize",
|
||||||
"description": "Equalize widths of visible columns",
|
description: "Equalize widths of visible columns",
|
||||||
"defaultKeySequence": "Meta+Ctrl+X",
|
defaultKeySequence: "Meta+Ctrl+X",
|
||||||
"action": "columnsWidthEqualize",
|
action: "columnsWidthEqualize",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "grid-scroll-focused",
|
name: "grid-scroll-focused",
|
||||||
"description": "Center focused window",
|
description: "Center focused window",
|
||||||
"comment": "Scrolls so that the focused window is centered in the screen",
|
comment: "Scrolls so that the focused window is centered in the screen",
|
||||||
"defaultKeySequence": "Meta+Alt+Return",
|
defaultKeySequence: "Meta+Alt+Return",
|
||||||
"action": "gridScrollFocused",
|
action: "gridScrollFocused",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "grid-scroll-left-column",
|
name: "grid-scroll-left-column",
|
||||||
"description": "Scroll one column to the left",
|
description: "Scroll one column to the left",
|
||||||
"defaultKeySequence": "Meta+Alt+A",
|
defaultKeySequence: "Meta+Alt+A",
|
||||||
"action": "gridScrollLeftColumn",
|
action: "gridScrollLeftColumn",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "grid-scroll-right-column",
|
name: "grid-scroll-right-column",
|
||||||
"description": "Scroll one column to the right",
|
description: "Scroll one column to the right",
|
||||||
"defaultKeySequence": "Meta+Alt+D",
|
defaultKeySequence: "Meta+Alt+D",
|
||||||
"action": "gridScrollRightColumn",
|
action: "gridScrollRightColumn",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "grid-scroll-left",
|
name: "grid-scroll-left",
|
||||||
"description": "Scroll left",
|
description: "Scroll left",
|
||||||
"defaultKeySequence": "Meta+Alt+PgUp",
|
defaultKeySequence: "Meta+Alt+PgUp",
|
||||||
"action": "gridScrollLeft",
|
action: "gridScrollLeft",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "grid-scroll-right",
|
name: "grid-scroll-right",
|
||||||
"description": "Scroll right",
|
description: "Scroll right",
|
||||||
"defaultKeySequence": "Meta+Alt+PgDown",
|
defaultKeySequence: "Meta+Alt+PgDown",
|
||||||
"action": "gridScrollRight",
|
action: "gridScrollRight",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "grid-scroll-start",
|
name: "grid-scroll-start",
|
||||||
"description": "Scroll to start",
|
description: "Scroll to start",
|
||||||
"defaultKeySequence": "Meta+Alt+Home",
|
defaultKeySequence: "Meta+Alt+Home",
|
||||||
"action": "gridScrollStart",
|
action: "gridScrollStart",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "grid-scroll-end",
|
name: "grid-scroll-end",
|
||||||
"description": "Scroll to end",
|
description: "Scroll to end",
|
||||||
"defaultKeySequence": "Meta+Alt+End",
|
defaultKeySequence: "Meta+Alt+End",
|
||||||
"action": "gridScrollEnd",
|
action: "gridScrollEnd",
|
||||||
},
|
},
|
||||||
];
|
];
|
||||||
|
|
||||||
const numKeyBindings: NumKeyBinding[] = [
|
const numKeyBindings: NumKeyBinding[] = [
|
||||||
{
|
{
|
||||||
"name": "focus-",
|
name: "focus-",
|
||||||
"description": "Move focus to column ",
|
description: "Move focus to column ",
|
||||||
"comment": "Clashes with default KDE shortcuts, may require manual remapping",
|
comment: "Clashes with default KDE shortcuts, may require manual remapping",
|
||||||
"defaultModifiers": "Meta",
|
defaultModifiers: "Meta",
|
||||||
"fKeys": false,
|
fKeys: false,
|
||||||
"action": "focusColumn",
|
action: "focusColumn",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "window-move-to-column-",
|
name: "window-move-to-column-",
|
||||||
"description": "Move window to column ",
|
description: "Move window to column ",
|
||||||
"comment": "Requires manual remapping according to your keyboard layout, e.g. Meta+Shift+1 -> Meta+!",
|
comment: "Requires manual remapping according to your keyboard layout, e.g. Meta+Shift+1 -> Meta+!",
|
||||||
"defaultModifiers": "Meta+Shift",
|
defaultModifiers: "Meta+Shift",
|
||||||
"fKeys": false,
|
fKeys: false,
|
||||||
"action": "windowMoveToColumn",
|
action: "windowMoveToColumn",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "column-move-to-column-",
|
name: "column-move-to-column-",
|
||||||
"description": "Move column to position ",
|
description: "Move column to position ",
|
||||||
"comment": "Requires manual remapping according to your keyboard layout, e.g. Meta+Ctrl+Shift+1 -> Meta+Ctrl+!",
|
comment: "Requires manual remapping according to your keyboard layout, e.g. Meta+Ctrl+Shift+1 -> Meta+Ctrl+!",
|
||||||
"defaultModifiers": "Meta+Ctrl+Shift",
|
defaultModifiers: "Meta+Ctrl+Shift",
|
||||||
"fKeys": false,
|
fKeys: false,
|
||||||
"action": "columnMoveToColumn",
|
action: "columnMoveToColumn",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "column-move-to-desktop-",
|
name: "column-move-to-desktop-",
|
||||||
"description": "Move column to desktop ",
|
description: "Move column to desktop ",
|
||||||
"defaultModifiers": "Meta+Ctrl+Shift",
|
defaultModifiers: "Meta+Ctrl+Shift",
|
||||||
"fKeys": true,
|
fKeys: true,
|
||||||
"action": "columnMoveToDesktop",
|
action: "columnMoveToDesktop",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "tail-move-to-desktop-",
|
name: "tail-move-to-desktop-",
|
||||||
"description": "Move this and all following columns to desktop ",
|
description: "Move this and all following columns to desktop ",
|
||||||
"defaultModifiers": "Meta+Ctrl+Shift+Alt",
|
defaultModifiers: "Meta+Ctrl+Shift+Alt",
|
||||||
"fKeys": true,
|
fKeys: true,
|
||||||
"action": "tailMoveToDesktop",
|
action: "tailMoveToDesktop",
|
||||||
},
|
},
|
||||||
];
|
];
|
||||||
|
|||||||
@@ -53,7 +53,12 @@ function registerNumKeyBindings(name: string, description: string, modifiers: st
|
|||||||
}
|
}
|
||||||
|
|
||||||
function registerKeyBindings(world: World, config: Config) {
|
function registerKeyBindings(world: World, config: Config) {
|
||||||
const actions = Actions.init(world, config);
|
const actions = Actions.init(world, {
|
||||||
|
manualScrollStep: config.manualScrollStep,
|
||||||
|
manualResizeStep: config.manualResizeStep,
|
||||||
|
columnResizer: config.scrollingCentered ? new RawResizer() : new ContextualResizer(),
|
||||||
|
});
|
||||||
|
|
||||||
for (const binding of keyBindings) {
|
for (const binding of keyBindings) {
|
||||||
registerKeyBinding(binding.name, binding.description, binding.defaultKeySequence, actions[binding.action]);
|
registerKeyBinding(binding.name, binding.description, binding.defaultKeySequence, actions[binding.action]);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -92,16 +92,17 @@ class Column {
|
|||||||
|
|
||||||
public setWidth(width: number, setPreferred: boolean) {
|
public setWidth(width: number, setPreferred: boolean) {
|
||||||
width = clamp(width, this.getMinWidth(), this.getMaxWidth());
|
width = clamp(width, this.getMinWidth(), this.getMaxWidth());
|
||||||
const oldWidth = this.width;
|
if (width === this.width) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
this.width = width;
|
this.width = width;
|
||||||
if (setPreferred) {
|
if (setPreferred) {
|
||||||
for (const window of this.windows.iterator()) {
|
for (const window of this.windows.iterator()) {
|
||||||
window.client.preferredWidth = width;
|
window.client.preferredWidth = width;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (width !== oldWidth) {
|
this.grid.onColumnWidthChanged(this);
|
||||||
this.grid.onColumnWidthChanged(this, oldWidth, width);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public adjustWidth(widthDelta: number, setPreferred: boolean) {
|
public adjustWidth(widthDelta: number, setPreferred: boolean) {
|
||||||
|
|||||||
@@ -55,10 +55,9 @@ class Desktop {
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
// calculates a Range that scrolls the contained Range into view
|
public scrollIntoView(range: Desktop.Range) {
|
||||||
public calculateVisibleRange(containedRange: Desktop.Range) {
|
const left = range.getLeft();
|
||||||
const left = containedRange.getLeft();
|
const right = range.getRight();
|
||||||
const right = containedRange.getRight();
|
|
||||||
const initialVisibleRange = this.getCurrentVisibleRange();
|
const initialVisibleRange = this.getCurrentVisibleRange();
|
||||||
|
|
||||||
let targetScrollX: number;
|
let targetScrollX: number;
|
||||||
@@ -67,26 +66,10 @@ class Desktop {
|
|||||||
} else if (right > initialVisibleRange.getRight()) {
|
} else if (right > initialVisibleRange.getRight()) {
|
||||||
targetScrollX = right - this.tilingArea.width;
|
targetScrollX = right - this.tilingArea.width;
|
||||||
} else {
|
} else {
|
||||||
return this.getVisibleRange(this.clampScrollX(this.scrollX));
|
targetScrollX = initialVisibleRange.getLeft();
|
||||||
}
|
}
|
||||||
|
|
||||||
const overscroll = this.getTargetOverscroll(targetScrollX, left < initialVisibleRange.getLeft());
|
this.setScroll(targetScrollX, false);
|
||||||
return this.getVisibleRange(this.clampScrollX(targetScrollX + overscroll));
|
|
||||||
}
|
|
||||||
|
|
||||||
private getTargetOverscroll(targetScrollX: number, scrollLeft: boolean) {
|
|
||||||
if (this.config.overscroll === 0) {
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
const visibleColumnsWidth = this.grid.getVisibleColumnsWidth(this.getVisibleRange(targetScrollX), true);
|
|
||||||
const remainingSpace = this.tilingArea.width - visibleColumnsWidth;
|
|
||||||
const overscrollX = Math.min(this.config.overscroll, Math.round(remainingSpace / 2));
|
|
||||||
const direction = scrollLeft ? -1 : 1;
|
|
||||||
return overscrollX * direction;
|
|
||||||
}
|
|
||||||
|
|
||||||
public scrollToRange(range: Desktop.Range) {
|
|
||||||
this.setScroll(this.calculateVisibleRange(range).getLeft(), true);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public scrollCenterRange(range: Desktop.Range) {
|
public scrollCenterRange(range: Desktop.Range) {
|
||||||
@@ -95,6 +78,13 @@ class Desktop {
|
|||||||
this.adjustScroll(Math.round(windowCenter - screenCenter), false);
|
this.adjustScroll(Math.round(windowCenter - screenCenter), false);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public scrollCenterVisible(focusedColumn: Column) {
|
||||||
|
const columnRange = new Desktop.ColumnRange(focusedColumn);
|
||||||
|
const visibleRange = this.getCurrentVisibleRange();
|
||||||
|
columnRange.addNeighbors(visibleRange, this.grid.config.gapsInnerHorizontal);
|
||||||
|
this.scrollCenterRange(columnRange);
|
||||||
|
}
|
||||||
|
|
||||||
public autoAdjustScroll() {
|
public autoAdjustScroll() {
|
||||||
const focusedColumn = this.grid.getLastFocusedColumn();
|
const focusedColumn = this.grid.getLastFocusedColumn();
|
||||||
if (focusedColumn === null || focusedColumn.grid !== this.grid) {
|
if (focusedColumn === null || focusedColumn.grid !== this.grid) {
|
||||||
@@ -119,7 +109,7 @@ class Desktop {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private clampScrollX(x: number) {
|
private clampScrollX(x: number) {
|
||||||
return this.config.scroller.clampScrollX(this, x);
|
return this.config.clamper.clampScrollX(this, x);
|
||||||
}
|
}
|
||||||
|
|
||||||
public setScroll(x: number, force: boolean) {
|
public setScroll(x: number, force: boolean) {
|
||||||
@@ -141,18 +131,32 @@ class Desktop {
|
|||||||
|
|
||||||
let remainingWidth = this.tilingArea.width - (visibleColumns.length-1) * this.grid.config.gapsInnerHorizontal;
|
let remainingWidth = this.tilingArea.width - (visibleColumns.length-1) * this.grid.config.gapsInnerHorizontal;
|
||||||
let remainingColumns = visibleColumns.length;
|
let remainingColumns = visibleColumns.length;
|
||||||
for (const column of visibleColumns) {
|
|
||||||
const columnWidth = Math.round(remainingWidth / remainingColumns);
|
const minWidths = visibleColumns.map(column => column.getMinWidth()).sort((a, b) => b - a);
|
||||||
column.setWidth(columnWidth, true);
|
for (const minWidth of minWidths) {
|
||||||
remainingWidth -= columnWidth;
|
if (minWidth > remainingWidth / remainingColumns) {
|
||||||
remainingColumns--;
|
remainingWidth -= minWidth;
|
||||||
|
remainingColumns--;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const targetVisibleRange = Desktop.RangeImpl.fromRanges(
|
const avgWidth = remainingWidth / remainingColumns;
|
||||||
|
for (const column of visibleColumns) {
|
||||||
|
const minWidth = column.getMinWidth();
|
||||||
|
if (minWidth > avgWidth) {
|
||||||
|
column.setWidth(minWidth, true);
|
||||||
|
} else {
|
||||||
|
const columnWidth = Math.round(remainingWidth / remainingColumns);
|
||||||
|
column.setWidth(columnWidth, true);
|
||||||
|
remainingWidth -= column.getWidth();
|
||||||
|
remainingColumns--;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
this.scrollCenterRange(Desktop.RangeImpl.fromRanges(
|
||||||
visibleColumns[0],
|
visibleColumns[0],
|
||||||
visibleColumns[visibleColumns.length - 1],
|
visibleColumns[visibleColumns.length - 1],
|
||||||
);
|
));
|
||||||
this.setScroll(this.calculateVisibleRange(targetVisibleRange).getLeft(), false);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public arrange() {
|
public arrange() {
|
||||||
@@ -187,8 +191,8 @@ namespace Desktop {
|
|||||||
marginBottom: number,
|
marginBottom: number,
|
||||||
marginLeft: number,
|
marginLeft: number,
|
||||||
marginRight: number,
|
marginRight: number,
|
||||||
overscroll: number,
|
|
||||||
scroller: Desktop.Scroller,
|
scroller: Desktop.Scroller,
|
||||||
|
clamper: Desktop.Clamper,
|
||||||
};
|
};
|
||||||
|
|
||||||
export type Range = {
|
export type Range = {
|
||||||
@@ -225,8 +229,83 @@ namespace Desktop {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export class ColumnRange {
|
||||||
|
private left: Column;
|
||||||
|
private right: Column;
|
||||||
|
private width: number;
|
||||||
|
|
||||||
|
constructor(initialColumn: Column) {
|
||||||
|
this.left = initialColumn;
|
||||||
|
this.right = initialColumn;
|
||||||
|
this.width = initialColumn.getWidth();
|
||||||
|
}
|
||||||
|
|
||||||
|
public addNeighbors(visibleRange: Desktop.Range, gap: number) {
|
||||||
|
const grid = this.left.grid;
|
||||||
|
|
||||||
|
const columnRange = this;
|
||||||
|
function canFit(column: Column) {
|
||||||
|
return columnRange.width + gap + column.getWidth() <= visibleRange.getWidth();
|
||||||
|
}
|
||||||
|
function isUsable(column: Column|null) {
|
||||||
|
return column !== null && canFit(column);
|
||||||
|
}
|
||||||
|
|
||||||
|
let leftColumn = grid.getPrevColumn(this.left);
|
||||||
|
let rightColumn = grid.getNextColumn(this.right);
|
||||||
|
function checkColumns() {
|
||||||
|
if (!isUsable(leftColumn)) {
|
||||||
|
leftColumn = null;
|
||||||
|
}
|
||||||
|
if (!isUsable(rightColumn)) {
|
||||||
|
rightColumn = null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
checkColumns();
|
||||||
|
|
||||||
|
const visibleCenter = visibleRange.getLeft() + visibleRange.getWidth() / 2;
|
||||||
|
while (leftColumn !== null || rightColumn !== null) {
|
||||||
|
const leftToCenter = leftColumn === null ? Infinity : Math.abs(leftColumn.getLeft() - visibleCenter);
|
||||||
|
const rightToCenter = rightColumn === null ? Infinity : Math.abs(rightColumn.getRight() - visibleCenter);
|
||||||
|
if (leftToCenter < rightToCenter) {
|
||||||
|
this.addLeft(leftColumn!, gap);
|
||||||
|
leftColumn = grid.getPrevColumn(leftColumn!);
|
||||||
|
} else {
|
||||||
|
this.addRight(rightColumn!, gap);
|
||||||
|
rightColumn = grid.getNextColumn(rightColumn!);
|
||||||
|
}
|
||||||
|
checkColumns();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public addLeft(column: Column, gap: number) {
|
||||||
|
this.left = column;
|
||||||
|
this.width += column.getWidth() + gap;
|
||||||
|
}
|
||||||
|
|
||||||
|
public addRight(column: Column, gap: number) {
|
||||||
|
this.right = column;
|
||||||
|
this.width += column.getWidth() + gap;
|
||||||
|
}
|
||||||
|
|
||||||
|
public getLeft() {
|
||||||
|
return this.left.getLeft();
|
||||||
|
}
|
||||||
|
|
||||||
|
public getRight() {
|
||||||
|
return this.right.getRight();
|
||||||
|
}
|
||||||
|
|
||||||
|
public getWidth() {
|
||||||
|
return this.width;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
export type Scroller = {
|
export type Scroller = {
|
||||||
scrollToColumn(desktop: Desktop, column: Column): void;
|
scrollToColumn(desktop: Desktop, column: Column): void;
|
||||||
|
}
|
||||||
|
|
||||||
|
export type Clamper = {
|
||||||
clampScrollX(desktop: Desktop, x: number): number;
|
clampScrollX(desktop: Desktop, x: number): number;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -43,6 +43,10 @@ class Grid {
|
|||||||
return this.width;
|
return this.width;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public isUserResizing() {
|
||||||
|
return this.userResize;
|
||||||
|
}
|
||||||
|
|
||||||
public getPrevColumn(column: Column) {
|
public getPrevColumn(column: Column) {
|
||||||
return this.columns.getPrev(column);
|
return this.columns.getPrev(column);
|
||||||
}
|
}
|
||||||
@@ -134,93 +138,6 @@ class Grid {
|
|||||||
return width;
|
return width;
|
||||||
}
|
}
|
||||||
|
|
||||||
public increaseColumnWidth(column: Column) {
|
|
||||||
const visibleRange = this.desktop.calculateVisibleRange(column);
|
|
||||||
if(!column.isVisible(visibleRange, true) || column.getWidth() >= column.getMaxWidth()) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
let leftVisibleColumn = this.getLeftmostVisibleColumn(visibleRange, true);
|
|
||||||
let rightVisibleColumn = this.getRightmostVisibleColumn(visibleRange, true);
|
|
||||||
if (leftVisibleColumn === null || rightVisibleColumn === null) {
|
|
||||||
console.assert(false);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
const leftSpace = leftVisibleColumn.getLeft() - visibleRange.getLeft();
|
|
||||||
const rightSpace = visibleRange.getRight() - rightVisibleColumn.getRight();
|
|
||||||
if (leftSpace + rightSpace > 0) {
|
|
||||||
column.adjustWidth(leftSpace + rightSpace, true);
|
|
||||||
} else {
|
|
||||||
// left and right columns are touching the screen's edges
|
|
||||||
const leftSpace = leftVisibleColumn === column ? Infinity : leftVisibleColumn.getWidth() + this.config.gapsInnerHorizontal;
|
|
||||||
const rightSpace = rightVisibleColumn === column ? Infinity : rightVisibleColumn.getWidth() + this.config.gapsInnerHorizontal;
|
|
||||||
if (leftSpace < rightSpace) {
|
|
||||||
column.adjustWidth(leftSpace, true);
|
|
||||||
leftVisibleColumn = this.getNextColumn(leftVisibleColumn)!;
|
|
||||||
} else {
|
|
||||||
column.adjustWidth(rightSpace, true);
|
|
||||||
rightVisibleColumn = this.getPrevColumn(rightVisibleColumn)!;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
this.desktop.scrollCenterRange(Desktop.RangeImpl.fromRanges(leftVisibleColumn, rightVisibleColumn));
|
|
||||||
}
|
|
||||||
|
|
||||||
public decreaseColumnWidth(column: Column) {
|
|
||||||
const visibleRange = this.desktop.calculateVisibleRange(column);
|
|
||||||
if (!column.isVisible(visibleRange, true)) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (this.width <= visibleRange.getWidth()) {
|
|
||||||
column.setWidth(Math.round(column.getWidth() / 2), true);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
const leftVisibleColumn = this.getLeftmostVisibleColumn(visibleRange, true);
|
|
||||||
const rightVisibleColumn = this.getRightmostVisibleColumn(visibleRange, true);
|
|
||||||
if (leftVisibleColumn === null || rightVisibleColumn === null) {
|
|
||||||
console.assert(false);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
let leftOffScreenColumn = this.getPrevColumn(leftVisibleColumn);
|
|
||||||
if (leftOffScreenColumn === column) {
|
|
||||||
leftOffScreenColumn = null;
|
|
||||||
}
|
|
||||||
let rightOffScreenColumn = this.getNextColumn(rightVisibleColumn);
|
|
||||||
if (rightOffScreenColumn === column) {
|
|
||||||
rightOffScreenColumn = null;
|
|
||||||
}
|
|
||||||
if (leftOffScreenColumn === null && rightOffScreenColumn === null) {
|
|
||||||
console.assert(false);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
const leftInvisibleWidth = leftOffScreenColumn === null ? Infinity : visibleRange.getLeft() - leftOffScreenColumn.getLeft();
|
|
||||||
const rightInvisibleWidth = rightOffScreenColumn === null ? Infinity : rightOffScreenColumn.getRight() - visibleRange.getRight();
|
|
||||||
|
|
||||||
const leftSpace = leftVisibleColumn.getLeft() - visibleRange.getLeft();
|
|
||||||
const rightSpace = visibleRange.getRight() - rightVisibleColumn.getRight();
|
|
||||||
|
|
||||||
if (leftInvisibleWidth < rightInvisibleWidth) {
|
|
||||||
const deltaWidth = rightSpace - leftInvisibleWidth;
|
|
||||||
column.adjustWidth(deltaWidth, true);
|
|
||||||
console.assert(leftOffScreenColumn !== null);
|
|
||||||
const newVisibleWidth = rightVisibleColumn.getRight() - leftOffScreenColumn!.getLeft();
|
|
||||||
const leftVisibleColumn = newVisibleWidth <= visibleRange.getWidth() ? leftOffScreenColumn! : this.getNextColumn(leftOffScreenColumn!)!;
|
|
||||||
this.desktop.scrollCenterRange(Desktop.RangeImpl.fromRanges(leftVisibleColumn, rightVisibleColumn));
|
|
||||||
} else {
|
|
||||||
const deltaWidth = leftSpace - rightInvisibleWidth;
|
|
||||||
column.adjustWidth(deltaWidth, true);
|
|
||||||
console.assert(rightOffScreenColumn !== null);
|
|
||||||
const newVisibleWidth = rightOffScreenColumn!.getRight() - leftVisibleColumn.getLeft();
|
|
||||||
const rightVisibleColumn = newVisibleWidth <= visibleRange.getWidth() ? rightOffScreenColumn! : this.getPrevColumn(rightOffScreenColumn!)!;
|
|
||||||
this.desktop.scrollCenterRange(Desktop.RangeImpl.fromRanges(leftVisibleColumn, rightVisibleColumn));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public arrange(x: number, visibleRange: Range) {
|
public arrange(x: number, visibleRange: Range) {
|
||||||
for (const column of this.columns.iterator()) {
|
for (const column of this.columns.iterator()) {
|
||||||
column.arrange(x, visibleRange, this.userResize);
|
column.arrange(x, visibleRange, this.userResize);
|
||||||
@@ -272,13 +189,13 @@ class Grid {
|
|||||||
this.desktop.autoAdjustScroll();
|
this.desktop.autoAdjustScroll();
|
||||||
}
|
}
|
||||||
|
|
||||||
public onColumnWidthChanged(column: Column, oldWidth: number, width: number) {
|
public onColumnWidthChanged(column: Column) {
|
||||||
const nextColumn = this.columns.getNext(column);
|
const nextColumn = this.columns.getNext(column);
|
||||||
this.columnsSetX(nextColumn);
|
this.columnsSetX(nextColumn);
|
||||||
|
this.desktop.onLayoutChanged();
|
||||||
if (!this.userResize) {
|
if (!this.userResize) {
|
||||||
this.desktop.autoAdjustScroll();
|
this.desktop.autoAdjustScroll();
|
||||||
}
|
}
|
||||||
this.desktop.onLayoutChanged();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public onColumnFocused(column: Column) {
|
public onColumnFocused(column: Column) {
|
||||||
|
|||||||
@@ -1,87 +0,0 @@
|
|||||||
class ScrollerGrouped {
|
|
||||||
private readonly layoutConfig: LayoutConfig;
|
|
||||||
|
|
||||||
constructor(layoutConfig: LayoutConfig) {
|
|
||||||
this.layoutConfig = layoutConfig;
|
|
||||||
}
|
|
||||||
|
|
||||||
public scrollToColumn(desktop: Desktop, column: Column) {
|
|
||||||
const columnRange = new ScrollerGrouped.ColumnRange(column);
|
|
||||||
const visibleRange = desktop.getCurrentVisibleRange();
|
|
||||||
columnRange.addNeighbors(visibleRange, this.layoutConfig.gapsInnerHorizontal, true);
|
|
||||||
columnRange.addNeighbors(visibleRange, this.layoutConfig.gapsInnerHorizontal, false);
|
|
||||||
desktop.scrollCenterRange(columnRange);
|
|
||||||
}
|
|
||||||
|
|
||||||
public clampScrollX(desktop: Desktop, x: number) {
|
|
||||||
return ScrollerCentered.clampScrollX(desktop, x);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
namespace ScrollerGrouped {
|
|
||||||
import Range = Desktop.Range;
|
|
||||||
|
|
||||||
export class ColumnRange {
|
|
||||||
private left: Column;
|
|
||||||
private right: Column;
|
|
||||||
private width: number;
|
|
||||||
|
|
||||||
constructor(initialColumn: Column) {
|
|
||||||
this.left = initialColumn;
|
|
||||||
this.right = initialColumn;
|
|
||||||
this.width = initialColumn.getWidth();
|
|
||||||
}
|
|
||||||
|
|
||||||
public addNeighbors(visibleRange: Range, gap: number, requireVisible: boolean) {
|
|
||||||
const grid = this.left.grid;
|
|
||||||
|
|
||||||
let leftColumn: Column|null = this.left;
|
|
||||||
while (true) {
|
|
||||||
leftColumn = grid.getPrevColumn(leftColumn);
|
|
||||||
if (
|
|
||||||
leftColumn === null ||
|
|
||||||
requireVisible && !leftColumn.isVisible(visibleRange, true) ||
|
|
||||||
this.width + gap + leftColumn.getWidth() > visibleRange.getWidth()
|
|
||||||
) {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
this.addLeft(leftColumn, gap);
|
|
||||||
}
|
|
||||||
|
|
||||||
let rightColumn: Column|null = this.right;
|
|
||||||
while (true) {
|
|
||||||
rightColumn = grid.getNextColumn(rightColumn);
|
|
||||||
if (
|
|
||||||
rightColumn === null ||
|
|
||||||
requireVisible && !rightColumn.isVisible(visibleRange, true) ||
|
|
||||||
this.width + gap + rightColumn.getWidth() > visibleRange.getWidth()
|
|
||||||
) {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
this.addRight(rightColumn, gap);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public addLeft(column: Column, gap: number) {
|
|
||||||
this.left = column;
|
|
||||||
this.width += column.getWidth() + gap;
|
|
||||||
}
|
|
||||||
|
|
||||||
public addRight(column: Column, gap: number) {
|
|
||||||
this.right = column;
|
|
||||||
this.width += column.getWidth() + gap;
|
|
||||||
}
|
|
||||||
|
|
||||||
public getLeft() {
|
|
||||||
return this.left.getLeft();
|
|
||||||
}
|
|
||||||
|
|
||||||
public getRight() {
|
|
||||||
return this.right.getRight();
|
|
||||||
}
|
|
||||||
|
|
||||||
public getWidth() {
|
|
||||||
return this.width;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -31,8 +31,9 @@ class WindowRuleEnforcer {
|
|||||||
manager.connect(kwinClient.captionChanged, () => {
|
manager.connect(kwinClient.captionChanged, () => {
|
||||||
const shouldTile = enforcer.shouldTile(kwinClient);
|
const shouldTile = enforcer.shouldTile(kwinClient);
|
||||||
world.do((clientManager, desktopManager) => {
|
world.do((clientManager, desktopManager) => {
|
||||||
if (shouldTile) {
|
const desktop = desktopManager.getDesktopForClient(kwinClient);
|
||||||
clientManager.tileClient(kwinClient);
|
if (shouldTile && desktop !== undefined) {
|
||||||
|
clientManager.tileClient(kwinClient, desktop.grid);
|
||||||
} else {
|
} else {
|
||||||
clientManager.untileClient(kwinClient);
|
clientManager.untileClient(kwinClient);
|
||||||
}
|
}
|
||||||
@@ -71,11 +72,11 @@ class WindowRuleEnforcer {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private static joinRegexes(regexes: string[]) {
|
private static joinRegexes(regexes: string[]) {
|
||||||
if (regexes.length == 0) {
|
if (regexes.length === 0) {
|
||||||
return new RegExp("");
|
return new RegExp("");
|
||||||
}
|
}
|
||||||
|
|
||||||
if (regexes.length == 1) {
|
if (regexes.length === 1) {
|
||||||
return new RegExp("^" + regexes[0] + "$");
|
return new RegExp("^" + regexes[0] + "$");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -38,7 +38,7 @@ function initWorkspaceSignalHandlers(world: World) {
|
|||||||
if ((horizontally || vertically) && kwinClient.tile !== null) {
|
if ((horizontally || vertically) && kwinClient.tile !== null) {
|
||||||
kwinClient.tile = null;
|
kwinClient.tile = null;
|
||||||
}
|
}
|
||||||
world.doIfTiled(kwinClient, false, (world, desktopManager, window, column, grid) => {
|
world.doIfTiled(kwinClient, false, (clientManager, desktopManager, window, column, grid) => {
|
||||||
window.onMaximizedChanged(horizontally, vertically);
|
window.onMaximizedChanged(horizontally, vertically);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
@@ -60,7 +60,7 @@ function initWorkspaceSignalHandlers(world: World) {
|
|||||||
world.do(() => {}); // re-arrange desktop
|
world.do(() => {}); // re-arrange desktop
|
||||||
});
|
});
|
||||||
|
|
||||||
manager.connect(workspace.numberDesktopsChanged, (oldNumberOfVirtualDesktops: number) => {
|
manager.connect(workspace.numberDesktopsChanged, () => {
|
||||||
world.updateDesktops();
|
world.updateDesktops();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|||||||
@@ -27,13 +27,13 @@ class ClientManager {
|
|||||||
|
|
||||||
public addClient(kwinClient: KwinClient) {
|
public addClient(kwinClient: KwinClient) {
|
||||||
console.assert(!this.hasClient(kwinClient));
|
console.assert(!this.hasClient(kwinClient));
|
||||||
|
const desktop = this.desktopManager.getDesktopForClient(kwinClient);
|
||||||
|
|
||||||
let constructState: (client: ClientWrapper) => ClientState.State;
|
let constructState: (client: ClientWrapper) => ClientState.State;
|
||||||
if (kwinClient.dock) {
|
if (kwinClient.dock) {
|
||||||
constructState = () => new ClientState.Docked(this.world, kwinClient);
|
constructState = () => new ClientState.Docked(this.world, kwinClient);
|
||||||
} else if (this.windowRuleEnforcer.shouldTile(kwinClient)) {
|
} else if (this.windowRuleEnforcer.shouldTile(kwinClient) && desktop !== undefined) {
|
||||||
const grid = this.desktopManager.getDesktopForClient(kwinClient).grid;
|
constructState = (client: ClientWrapper) => new ClientState.Tiled(this.world, client, desktop.grid);
|
||||||
constructState = (client: ClientWrapper) => new ClientState.Tiled(this.world, client, grid);
|
|
||||||
} else {
|
} else {
|
||||||
constructState = (client: ClientWrapper) => new ClientState.Floating(this.world, client, this.config, false);
|
constructState = (client: ClientWrapper) => new ClientState.Floating(this.world, client, this.config, false);
|
||||||
}
|
}
|
||||||
@@ -86,12 +86,16 @@ class ClientManager {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (client.stateManager.getState() instanceof ClientState.TiledMinimized) {
|
if (client.stateManager.getState() instanceof ClientState.TiledMinimized) {
|
||||||
const grid = this.desktopManager.getDesktopForClient(kwinClient).grid;
|
const desktop = this.desktopManager.getDesktopForClient(kwinClient);
|
||||||
client.stateManager.setState(() => new ClientState.Tiled(this.world, client, grid), false);
|
if (desktop !== undefined) {
|
||||||
|
client.stateManager.setState(() => new ClientState.Tiled(this.world, client, desktop.grid), false);
|
||||||
|
} else {
|
||||||
|
client.stateManager.setState(() => new ClientState.Floating(this.world, client, this.config, false), false);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public tileClient(kwinClient: KwinClient) {
|
public tileClient(kwinClient: KwinClient, grid: Grid) {
|
||||||
const client = this.clientMap.get(kwinClient);
|
const client = this.clientMap.get(kwinClient);
|
||||||
if (client === undefined) {
|
if (client === undefined) {
|
||||||
return;
|
return;
|
||||||
@@ -99,7 +103,6 @@ class ClientManager {
|
|||||||
if (client.stateManager.getState() instanceof ClientState.Tiled) {
|
if (client.stateManager.getState() instanceof ClientState.Tiled) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
const grid = this.desktopManager.getDesktopForClient(kwinClient).grid;
|
|
||||||
client.stateManager.setState(() => new ClientState.Tiled(this.world, client, grid), false);
|
client.stateManager.setState(() => new ClientState.Tiled(this.world, client, grid), false);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -147,8 +150,11 @@ class ClientManager {
|
|||||||
const clientState = client.stateManager.getState();
|
const clientState = client.stateManager.getState();
|
||||||
if ((clientState instanceof ClientState.Floating || clientState instanceof ClientState.Pinned) && Clients.canTileEver(kwinClient)) {
|
if ((clientState instanceof ClientState.Floating || clientState instanceof ClientState.Pinned) && Clients.canTileEver(kwinClient)) {
|
||||||
Clients.makeTileable(kwinClient);
|
Clients.makeTileable(kwinClient);
|
||||||
const grid = this.desktopManager.getDesktopForClient(kwinClient).grid;
|
const desktop = this.desktopManager.getDesktopForClient(kwinClient);
|
||||||
client.stateManager.setState(() => new ClientState.Tiled(this.world, client, grid), false);
|
if (desktop === undefined) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
client.stateManager.setState(() => new ClientState.Tiled(this.world, client, desktop.grid), false);
|
||||||
} else if (clientState instanceof ClientState.Tiled) {
|
} else if (clientState instanceof ClientState.Tiled) {
|
||||||
client.stateManager.setState(() => new ClientState.Floating(this.world, client, this.config, true), false);
|
client.stateManager.setState(() => new ClientState.Floating(this.world, client, this.config, true), false);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -33,8 +33,15 @@ class ClientWrapper {
|
|||||||
// window is being manually resized, prevent fighting with the user
|
// window is being manually resized, prevent fighting with the user
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
this.lastPlacement = Qt.rect(x, y, width, height);
|
const clientWrapper = this; // workaround for bug in Qt5's JS engine
|
||||||
this.kwinClient.frameGeometry = this.lastPlacement;
|
clientWrapper.lastPlacement = Qt.rect(x, y, width, height);
|
||||||
|
clientWrapper.kwinClient.frameGeometry = clientWrapper.lastPlacement;
|
||||||
|
if (clientWrapper.kwinClient.frameGeometry !== clientWrapper.lastPlacement) {
|
||||||
|
// frameGeometry assignment failed. This sometimes happens on Wayland
|
||||||
|
// when a window is off-screen, effectively making it stuck there.
|
||||||
|
clientWrapper.kwinClient.frameGeometry.x = x; // This makes it unstuck.
|
||||||
|
clientWrapper.kwinClient.frameGeometry = clientWrapper.lastPlacement;
|
||||||
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -39,7 +39,9 @@ class DesktopManager {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public getDesktopForClient(kwinClient: KwinClient) {
|
public getDesktopForClient(kwinClient: KwinClient) {
|
||||||
console.assert(kwinClient.activities.length === 1 && kwinClient.desktop > 0);
|
if (kwinClient.activities.length !== 1 || kwinClient.desktop <= 0) {
|
||||||
|
return undefined;
|
||||||
|
}
|
||||||
return this.getDesktop(kwinClient.activities[0], kwinClient.desktop);
|
return this.getDesktop(kwinClient.activities[0], kwinClient.desktop);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -11,7 +11,7 @@ class World {
|
|||||||
this.workspaceSignalManager = initWorkspaceSignalHandlers(this);
|
this.workspaceSignalManager = initWorkspaceSignalHandlers(this);
|
||||||
|
|
||||||
this.screenResizedDelayer = new Delayer(1000, () => {
|
this.screenResizedDelayer = new Delayer(1000, () => {
|
||||||
// this delay ensures that docks get taken into account by `workspace.clientArea`
|
// this delay ensures that docks are taken into account by `workspace.clientArea`
|
||||||
const desktopManager = this.desktopManager; // workaround for bug in Qt5's JS engine
|
const desktopManager = this.desktopManager; // workaround for bug in Qt5's JS engine
|
||||||
for (const desktop of desktopManager.desktops()) {
|
for (const desktop of desktopManager.desktops()) {
|
||||||
desktop.onLayoutChanged();
|
desktop.onLayoutChanged();
|
||||||
@@ -40,11 +40,11 @@ class World {
|
|||||||
marginBottom: config.gapsOuterBottom,
|
marginBottom: config.gapsOuterBottom,
|
||||||
marginLeft: config.gapsOuterLeft,
|
marginLeft: config.gapsOuterLeft,
|
||||||
marginRight: config.gapsOuterRight,
|
marginRight: config.gapsOuterRight,
|
||||||
overscroll: config.overscroll,
|
scroller: config.scrollingLazy ? new LazyScroller() :
|
||||||
scroller: config.scrollingLazy ? new ScrollerLazy() :
|
config.scrollingCentered ? new CenteredScroller() :
|
||||||
config.scrollingCentered ? new ScrollerCentered() :
|
config.scrollingGrouped ? new GroupedScroller() :
|
||||||
config.scrollingGrouped ? new ScrollerGrouped(layoutConfig) :
|
|
||||||
console.assert(false),
|
console.assert(false),
|
||||||
|
clamper: config.scrollingLazy ? new EdgeClamper() : new CenterClamper(),
|
||||||
},
|
},
|
||||||
layoutConfig,
|
layoutConfig,
|
||||||
workspace.currentActivity,
|
workspace.currentActivity,
|
||||||
|
|||||||
@@ -54,7 +54,7 @@ namespace ClientState {
|
|||||||
clientManager.pinClient(kwinClient);
|
clientManager.pinClient(kwinClient);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
})
|
});
|
||||||
|
|
||||||
return manager;
|
return manager;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -68,7 +68,7 @@ namespace ClientState {
|
|||||||
oldDesktopNumber = kwinClient.desktop;
|
oldDesktopNumber = kwinClient.desktop;
|
||||||
});
|
});
|
||||||
|
|
||||||
manager.connect(kwinClient.activitiesChanged, (kwinClient: KwinClient) => {
|
manager.connect(kwinClient.activitiesChanged, () => {
|
||||||
const desktops = kwinClient.desktop === -1 ? [] : [kwinClient.desktop];
|
const desktops = kwinClient.desktop === -1 ? [] : [kwinClient.desktop];
|
||||||
const changedActivities = oldActivities.length === 0 || kwinClient.activities.length === 0 ?
|
const changedActivities = oldActivities.length === 0 || kwinClient.activities.length === 0 ?
|
||||||
[] :
|
[] :
|
||||||
|
|||||||
@@ -33,23 +33,25 @@ namespace ClientState {
|
|||||||
|
|
||||||
manager.connect(kwinClient.desktopChanged, () => {
|
manager.connect(kwinClient.desktopChanged, () => {
|
||||||
world.do((clientManager, desktopManager) => {
|
world.do((clientManager, desktopManager) => {
|
||||||
if (kwinClient.desktop === -1) {
|
const desktop = desktopManager.getDesktopForClient(kwinClient);
|
||||||
|
if (desktop === undefined) {
|
||||||
// windows on all desktops are not supported
|
// windows on all desktops are not supported
|
||||||
clientManager.untileClient(kwinClient);
|
clientManager.untileClient(kwinClient);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
Tiled.moveWindowToCorrectGrid(desktopManager, window);
|
Tiled.moveWindowToGrid(window, desktop.grid);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
manager.connect(kwinClient.activitiesChanged, () => {
|
manager.connect(kwinClient.activitiesChanged, () => {
|
||||||
world.do((clientManager, desktopManager) => {
|
world.do((clientManager, desktopManager) => {
|
||||||
if (kwinClient.activities.length !== 1) {
|
const desktop = desktopManager.getDesktopForClient(kwinClient);
|
||||||
|
if (desktop === undefined) {
|
||||||
// windows on multiple activities are not supported
|
// windows on multiple activities are not supported
|
||||||
clientManager.untileClient(kwinClient);
|
clientManager.untileClient(kwinClient);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
Tiled.moveWindowToCorrectGrid(desktopManager, window);
|
Tiled.moveWindowToGrid(window, desktop.grid);
|
||||||
});
|
});
|
||||||
})
|
})
|
||||||
|
|
||||||
@@ -106,6 +108,7 @@ namespace ClientState {
|
|||||||
if (kwinClient.resize) {
|
if (kwinClient.resize) {
|
||||||
world.do(() => window.onUserResize(oldGeometry, !cursorChangedAfterResizeStart));
|
world.do(() => window.onUserResize(oldGeometry, !cursorChangedAfterResizeStart));
|
||||||
} else if (
|
} else if (
|
||||||
|
!window.column.grid.isUserResizing() &&
|
||||||
!client.isManipulatingGeometry(newGeometry) &&
|
!client.isManipulatingGeometry(newGeometry) &&
|
||||||
!Clients.isMaximizedGeometry(kwinClient) &&
|
!Clients.isMaximizedGeometry(kwinClient) &&
|
||||||
!Clients.isFullScreenGeometry(kwinClient) // not using `kwinClient.fullScreen` because it may not be set yet at this point
|
!Clients.isFullScreenGeometry(kwinClient) // not using `kwinClient.fullScreen` because it may not be set yet at this point
|
||||||
@@ -130,17 +133,13 @@ namespace ClientState {
|
|||||||
return manager;
|
return manager;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static moveWindowToCorrectGrid(desktopManager: DesktopManager, window: Window) {
|
private static moveWindowToGrid(window: Window, grid: Grid) {
|
||||||
const kwinClient = window.client.kwinClient;
|
if (grid === window.column.grid) {
|
||||||
|
// window already on the given grid
|
||||||
const oldGrid = window.column.grid;
|
|
||||||
const newGrid = desktopManager.getDesktopForClient(kwinClient).grid;
|
|
||||||
if (oldGrid === newGrid) {
|
|
||||||
// window already on the correct grid
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
const newColumn = new Column(newGrid, newGrid.getLastFocusedColumn() ?? newGrid.getLastColumn());
|
const newColumn = new Column(grid, grid.getLastFocusedColumn() ?? grid.getLastColumn());
|
||||||
window.moveToColumn(newColumn);
|
window.moveToColumn(newColumn);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user