Skip to content

Commit

Permalink
initial release
Browse files Browse the repository at this point in the history
  • Loading branch information
nclarius committed May 24, 2022
0 parents commit f45eeb5
Show file tree
Hide file tree
Showing 17 changed files with 995 additions and 0 deletions.
Binary file added .img/screenshot.gif
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
1 change: 1 addition & 0 deletions CHANGELOG.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
- initial release
674 changes: 674 additions & 0 deletions LICENSE

Large diffs are not rendered by default.

14 changes: 14 additions & 0 deletions README.bbcode
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
Extension for KDE's window manager to automatically raise all other windows of the same application when activating a task.

This creates a workflow with two levels of task switching: one mode for switching applications and one mode for switching between windows of an application.

[b]Please make sure to install the most recent version (v6.3) and to not use Discover for installation.[/b] For more information on installation, configuration and usage as well as any requests, please visit [url=https://github.com/nclarius/floating-tiles]the GitHub page[/url].

© 2021-2022 Natalie Clarius ‹[email protected]

This work is licensed under the GNU General Public License v3.0.
This program comes with absolutely no warranty.
This is free software, and you are welcome to redistribute and/or modify it under certain conditions.

If you would like to thank me, you can always make me happy with a review or a cup of coffee:
[url="https://www.paypal.com/donate/?hosted_button_id=7LUUJD83BWRM4"][img height="30"]https://www.paypalobjects.com/en_US/DK/i/btn/btn_donateCC_LG.gif[/img][/url] [url="https://www.buymeacoffee.com/nclarius"][img height="30"]https://cdn.buymeacoffee.com/buttons/v2/default-yellow.png[/img][/url]
75 changes: 75 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
# Application Switcher

[latest release](https://github.com/nclarius/application-switcher/releases/latest) | [view in KDE store]()

Extension for KDE's window manager to automatically raise all other windows of the same application together when activating one of them.

This creates a workflow with two levels of task switching: one mode for switching applications and one mode for switching between windows of an application.

Raising all windows of an application whenever an application is being switched to means that closing or minimizing a window will keep focus on the same application by switching to the most recently active window of that application provided that there is any, rather than switching to the most recently active window which may belong to a different application.

![screenshot](.img/screenshot.gif)

## Installation

### Dependencies

`kwin`.

### Installation via graphical interface

**Please make sure to select the most recent version (v1.0)** in the installation process.

A [bug](https://bugs.kde.org/show_bug.cgi?id=453521) in Discover causes a wrong version to be installed, so using the installation module in System Settings instead is recommended.

1. Install the script via Discover or *System Settings* > *Window Management* > *KWin Scripts* > *Get New Scripts …* > search for *Application Switcher* > *Install*.
2. Enable the script by activating its checkbox, and apply the settings.

### Installation via command line

```bash
git clone https://github.com/nclarius/application-switcher.git
cd application-switcher
./install.sh
```

## Usage

### Tips

If you are intending to have one mode for switching applications and one mode for switching application windows, you may want to use the following settings:
- Task switcher:

System Settings > Window Management > Task Switcher >

- Main (for switching between applications) >
- Visualization: Large Icons
- Only one window per application: checked
- Shortcuts > All windows (which now means switching applications): set your preferred shortcut pair, e.g. Alt+(Shift+)Tab; Current application: leave empty

- Alternative (for switching between windows of an application) >
- Visualization: Thumbnails
- Only one window per application: unchecked
- Shortcuts > Current application: set your preferred shortcut pair, e.g. Alt+(Shift+)`; All windows: leave empty

- Task bar:

right-click on task bar > Configure Task Manager … > Behavior > Group: By application name; Combine into single button: checked

### Limitations

- The KWin scripting API provides no possibility to distinguish how a window was activated (via alt-tabbing, panel task bar clicking, clicking on the window, or being requested from another process), so the plugin can not be applied selectively to only some activation types.
- The KWin scripting API provides no possibility to manipulate the recently used and stacking order without actually activating the window, so focus will briefly shift as windows are being brought to the front; however this happens so fast it shouldn’t be noticeable.

## Small Print

© 2022 Natalie Clarius \<[email protected]\>

This work is licensed under the GNU General Public License v3.0.
This program comes with absolutely no warranty.
This is free software, and you are welcome to redistribute and/or modify it under certain conditions.

Development was sponsored by user RedBearAK.

If you would like to thank me, you can always make me happy with a review or a cup of coffee:
<a href="https://store.kde.org/p/1619690"><img src="https://raw.githubusercontent.com/nclarius/Plasma-window-decorations/main/.img/kdestore.png" height="25"/></a> <a href="https://www.paypal.com/donate/?hosted_button_id=7LUUJD83BWRM4"><img src="https://www.paypalobjects.com/en_US/DK/i/btn/btn_donateCC_LG.gif" height="25"/></a>&nbsp;&nbsp;<a href="https://www.buymeacoffee.com/nclarius"><img src="https://cdn.buymeacoffee.com/buttons/v2/default-yellow.png" height="25"/></a>
6 changes: 6 additions & 0 deletions contents/.directory
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
[Dolphin]
GroupedSorting=true
SortRole=type
Timestamp=2022,4,22,15,14,59.543
Version=4
ViewMode=1
6 changes: 6 additions & 0 deletions contents/code/.directory
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
[Dolphin]
GroupedSorting=true
SortRole=type
Timestamp=2022,4,22,15,15,4.36
Version=4
ViewMode=1
109 changes: 109 additions & 0 deletions contents/code/main.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,109 @@
/*
KWin Script Application Switcher
(C) 2022 Natalie Clarius <[email protected]>
GNU General Public License v3.0
*/

///////////////////////
// initialization
///////////////////////

const debugMode = readConfig("debugMode", true);
function debug(...args) {
if (debugMode) { console.debug("applicationswitcher:", ...args); }
}
debug("initializing");


///////////////////////
// keep track of active application (to check whether app has been switched)
///////////////////////

// set previously active application for initially active window
// "dolphin"
var prevActiveApp =
workspace.activeClient ? String(workspace.activeClient.resourceClass) : "";


///////////////////////
// keep track of windows belonging to same application in order of activation
///////////////////////

// {"dolphin": [oldest window, ..., most recent window], "konsole": ...}
var appGroups = {};

// compute app groups for initially present windows
workspace.clientList().forEach(win => updateAppGroups(win));

// update app groups with recently activated window
function updateAppGroups(active) {
if (!active) return;
debug("updating app groups");
let app = String(active.resourceClass);

if (!appGroups[app]) appGroups[app] = [];
appGroups[app] = appGroups[app].filter(w => w && w != active);
appGroups[app].push(active);

debug("updated; app groups:", appGroups[app].map(client => client.caption));
}

// return other visible windows of same application as recently active window
function getAppGroups(active) {
if (!active) return;
debug("getting app groups");
let app = String(active.resourceClass);

debug("fetched; app groups:", appGroups[app].map(client => client.caption));
return appGroups[app].filter(w => !w.minimized &&
(w.desktop == active.desktop ||
active.onAllDesktops || w.onAllDesktops));
}


///////////////////////
// keep track of auto-raised windows
///////////////////////

// [dolphin window 1, dolphin window 2, ...]
var autoActivated = [];

function addAutoActivated(activated) {
autoActivated = autoActivated.filter(w => w && w != activated);
autoActivated.push(activated);
}

function delAutoActivated(activated) {
autoActivated = autoActivated.filter(w => w && w != activated);
}

///////////////////////
// application switching
///////////////////////

// when client is activated, auto-raise other windows of the same applicaiton
workspace.clientActivated.connect(active => {
if (!active) return;
debug("activated", active.caption);
// abort if current activation was due to auto-raise
if (autoActivated.includes(active)) {
delAutoActivated(active);
return;
}

let app = String(active.resourceClass);
updateAppGroups(active);

// if application was switched
if (app != prevActiveApp) {
debug("app switched");
// auto-raise other windows of same application
for (const window of getAppGroups(active)) {
debug("auto-raising", window.caption);
addAutoActivated(window);
workspace.activeClient = window;
}
}

prevActiveApp = app;
});
4 changes: 4 additions & 0 deletions debug_off.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
#!/bin/bash
name=$(grep -oP '(?<=X-KDE-PluginInfo-Name=).*' ./metadata.desktop)
kwriteconfig5 --file kwinrc --group Script-"$name" --key debugMode false
qdbus org.kde.KWin /KWin reconfigure
4 changes: 4 additions & 0 deletions debug_on.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
#!/bin/bash
name=$(grep -oP '(?<=X-KDE-PluginInfo-Name=).*' ./metadata.desktop)
kwriteconfig5 --file kwinrc --group Script-"$name" --key debugMode true
qdbus org.kde.KWin /KWin reconfigure
4 changes: 4 additions & 0 deletions disable.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
#!/bin/sh
name=$(grep -oP '(?<=X-KDE-PluginInfo-Name=).*' ./metadata.desktop)
kwriteconfig5 --file kwinrc --group Plugins --key "$name"Enabled false
qdbus org.kde.KWin /KWin reconfigure
4 changes: 4 additions & 0 deletions enable.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
#!/bin/sh
name=$(grep -oP '(?<=X-KDE-PluginInfo-Name=).*' ./metadata.desktop)
kwriteconfig5 --file kwinrc --group Plugins --key "$name"Enabled true
qdbus org.kde.KWin /KWin reconfigure
5 changes: 5 additions & 0 deletions install.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
#!/bin/bash
name=$(grep -oP '(?<=X-KDE-PluginInfo-Name=).*' ./metadata.desktop)
kpackagetool5 --type=KWin/Script --install . || kpackagetool5 --type=KWin/Script --upgrade .
kwriteconfig5 --file kwinrc --group Plugins --key "$name"Enabled true
qdbus org.kde.KWin /KWin reconfigure
20 changes: 20 additions & 0 deletions metadata.desktop
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
# KWin Script Application Switcher
# (C) 2022 Natalie Clarius <[email protected]>
# GNU General Public License v3.0

[Desktop Entry]
Name=Application Switcher
Comment=Collectively raise all windows of the same application when switching tasks
Icon=preferences-system-windows

X-KDE-PluginInfo-Name=applicationswitcher
X-KDE-PluginInfo-Version=1.0
X-KDE-PluginInfo-Author=Natalie Clarius
X-KDE-PluginInfo-Email[email protected]
X-KDE-PluginInfo-License=GPLv3.0
X-KDE-PluginInfo-Website=

Type=Service
X-Plasma-API=javascript
X-Plasma-MainScript=code/main.js
X-KDE-ServiceTypes=KWin/Script,KCModule
54 changes: 54 additions & 0 deletions package.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
#!/bin/bash

# get plugin info
name=$(basename "$PWD")
version=$(grep -oP '(?<=X-KDE-PluginInfo-Version=).*' ./metadata.desktop)
echo "$name"' v'"$version"

# generate changelog in markdown format
heading_md=$([[ $version == *.0 ]] && echo '#' || echo '##')
caption_md="${heading_md}"' v'"${version}"
changes_md=$(cat CHANGELOG.txt)
changelog_md="$caption_md"$'\n'"$changes_md"$'\n\n'"$(cat CHANGELOG.md)"
if ! grep -Fxq "$caption_md" CHANGELOG.md
then
echo "$changelog_md" > "CHANGELOG.md"
echo 'generated changelog markdown'
fi

# generate changelog in bbcode format
heading_bb=$([[ $version == *.0 ]] && echo "h1" || echo "h2")
caption_bb='['"$heading_bb"']v'"$version"'[/'"$heading_bb"']'
changes_bb='[list]\n'"$(cat CHANGELOG.txt | sed 's/- /[*] /g')"$'\n[/list]'
changelog_bb="$caption_bb"$'\n'"$changes_bb"$'\n\n'"$(cat CHANGELOG.bbcode)"
if ! grep -Fxq "$caption_bb" CHANGELOG.bbcode
then
echo "$changelog_bb" > "CHANGELOG.bbcode"
echo 'generated changelog bbcode'
fi

# generate kwinscript package
find . -name "*.kwinscript" -type f -delete
zip -rq "${name}"'_v'"${version}"'.kwinscript' \
contents \
metadata.desktop \
install.sh \
uninstall.sh \
README.md \
README.bbcode \
CHANGELOG.md \
CHANGELOG.bbcode \
LICENSE
echo 'generated kwinscript package'

# commit changes to GitHub
git add .
git commit -q -m "$(paste -sd '; ' CHANGELOG.txt | sed 's/- / /g')"
git push -q
echo 'commited changes to git'

# generate GitHub release
gh release create "${name}"'_v'"${version}" -F CHANGELOG.txt "${name}"'_v'"${version}"'.kwinscript'
echo 'generated GitHub release'

echo 'done'
3 changes: 3 additions & 0 deletions uninstall.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
#!/bin/bash
kpackagetool5 --type=KWin/Script --remove .
qdbus org.kde.KWin /KWin reconfigure
12 changes: 12 additions & 0 deletions update.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
#!/bin/bash

# update
kpackagetool5 --type=KWin/Script --install . || kpackagetool5 --type=KWin/Script --upgrade .

# enable
kwriteconfig5 --file kwinrc --group Plugins --key "$(grep -oP '(?<=X-KDE-PluginInfo-Name=).*' ./metadata.desktop)"Enabled true

# reload
qdbus org.kde.KWin /KWin reconfigure
source /home/natalie/kde/build/kwin/prefix.sh
/home/natalie/kde/usr/bin/kwin_"$(printenv XDG_SESSION_TYPE)" --replace

0 comments on commit f45eeb5

Please sign in to comment.