Compare commits

..

26 Commits

Author SHA1 Message Date
ec806de9bd Update PKGBUILD 2025-01-06 19:14:54 +00:00
85ac25afcc Make layout buttons resizable 2025-01-06 16:14:38 +05:30
3b779b3f67 preserve some configs for layouts 2024-09-11 13:31:52 +00:00
b39718516f fixed whisker searches 2024-09-04 22:25:20 +00:00
72c118a6ee using the vala-panel-appmenu-registrar git version 2024-05-05 12:22:34 +00:00
da7cfce288 using the vala-panel-appmenu-registrar git version 2024-05-05 12:21:50 +00:00
ae83bfbbd6 Update command for installing owlkettle 2024-03-28 17:20:46 +00:00
e270acc3dd remove optdepends=('vala-panel-appmenu-registrar') 2024-03-04 12:06:39 +00:00
1f24cd0bf0 revert d412f8a653
revert removed optdepends=('vala-panel-appmenu-registrar')
2024-03-04 12:00:03 +00:00
d412f8a653 removed optdepends=('vala-panel-appmenu-registrar') 2024-03-01 15:39:35 +00:00
07b1641178 removed vala-panel-appmenu-common-git
the vala-panel-appmenu-xfce-git depends on it anyway
2024-03-01 13:53:09 +00:00
486f650395 Update PKGBUILD 2024-01-06 21:54:31 +00:00
c9a2438c1d bump up the version 2024-01-03 18:21:01 +00:00
d43af1f7fd better-manage-global-menu ()
Reviewed-on: 
2024-01-01 15:38:54 +00:00
666d24625b Remove the 3 second delay 2023-12-26 19:02:06 +00:00
2eb10c5b71 Check if thread is running before passing it to joinThread() 2023-12-26 18:48:04 +00:00
f2ec92a22d Change delay from 5 seconds to 3 seconds 2023-12-26 05:22:49 +00:00
43c356debb Merge pull request 'Rewrite layout switcher in Nim' () from nim-rewrite into master
Reviewed-on: 
2023-12-26 00:08:42 +00:00
1f29b13f85 Show loading animation when changing layouts 2023-12-25 15:23:03 +00:00
c020b3626f Add more dependencies 2023-12-25 08:27:04 +00:00
ea7d1b8270 Update Makefile 2023-12-25 08:02:42 +00:00
b1dc6d7e29 Update PKGBUILD for the new code in Nim 2023-12-25 08:01:59 +00:00
779117672e Add polkit action file 2023-12-25 08:00:39 +00:00
87ae3a63f5 Add toggleGlobalMenu.nim 2023-12-25 07:54:45 +00:00
b7578dd97f Add sharedModule.nim 2023-12-25 07:52:09 +00:00
c60c17100b Replace bash script with the new code in Nim 2023-12-25 07:50:13 +00:00
8 changed files with 339 additions and 91 deletions

@ -1,12 +1,12 @@
# makefile for layout-switcher
build:
makepkg
makepkg -s
install:
pamac-installer tromjaro-layout-switcher-*.tar.xz
pamac-installer tromjaro-layout-switcher-*.tar.zst
remove:
pamac-installer --remove tromjaro-layout-switcher
clean:
$(RM) -rf src/ pkg/ *.tar.xz
$(RM) -rf src/ pkg/ icons.zip profiles.zip *.tar.zst

@ -1,24 +1,33 @@
# Maintainer: TROM <contact@tromsite.com>
pkgname=tromjaro-layout-switcher
pkgver=1.4
pkgrel=1
pkgver=2
pkgrel=4
pkgdesc="TROMjaro Layout switcher application"
arch=(any)
url=""
arch=('x86_64')
url="https://git.trom.tf/TROMjaro/layout-switcher-package"
license=(unknown)
depends=('yad'
'zensu'
'xfce4-panel-profiles'
depends=('xfce4-panel-profiles'
'vala-panel-appmenu-registrar-git'
'util-linux'
'xfconf'
'polkit'
'mate-hud'
'psmisc'
'pacman'
'coreutils'
'vala-panel-appmenu-xfce-git'
'vala-panel-appmenu-common-git'
'libdbusmenu-gtk2'
'appmenu-gtk-module')
optdepends=('vala-panel-appmenu-registrar')
makedepends=('choosenim')
provides=('tromjaro-layout-switcher')
backup=()
options=(!strip)
source=("layout-switcher"
source=("layoutSwitcher.nim"
"toggleGlobalMenu.nim"
"sharedModule.nim"
"tromjaro-layout-switcher.desktop"
"com.tromjaro.LayoutSwitcher.policy"
"disable-global-menu.hook"
"tromjaro-layout-switcher.svg"
"icons.zip::https://www.drive.tromsite.com/s/SWmAcokLcxLB3gM/download"
"profiles.zip::https://www.drive.tromsite.com/s/6dHoNjar9wJzeLd/download")
@ -26,23 +35,55 @@ sha256sums=('SKIP'
'SKIP'
'SKIP'
'SKIP'
'SKIP'
'SKIP'
'SKIP'
'SKIP'
'SKIP')
package() {
# copy icons
install -d ${pkgdir}/usr/share/tromjaro-layout-switcher/icons
install -Dm644 ${srcdir}/icons/* ${pkgdir}/usr/share/tromjaro-layout-switcher/icons
# copy profiles
install -d ${pkgdir}/usr/share/tromjaro-layout-switcher/profiles
install -Dm644 ${srcdir}/profiles/* ${pkgdir}/usr/share/tromjaro-layout-switcher/profiles
# copy executables
install -Dm644 ${srcdir}/tromjaro-layout-switcher.desktop ${pkgdir}/usr/share/applications/tromjaro-layout-switcher.desktop
install -Dm755 ${srcdir}/layout-switcher ${pkgdir}/usr/bin/tromjaro-layout-switcher
# copy icon
install -d ${pkgdir}/usr/share/icons/hicolor/scalable/apps
install -Dm644 ${srcdir}/tromjaro-layout-switcher.svg ${pkgdir}/usr/share/icons/hicolor/scalable/apps
prepare() {
# Disable telemetry in choosenim if user is running it for the first time
[ -f "$HOME"/.choosenim/analytics ] || {
mkdir -p "$HOME"/.choosenim
touch "$HOME"/.choosenim/analytics
}
echo 'Install Nim if not already installed:'
choosenim stable
echo 'Update Nim to the latest stable release:'
choosenim update stable
echo 'Refresh nimble package list:'
"$HOME"/.nimble/bin/nimble --nim:"$HOME"/.nimble/bin/nim refresh
echo 'Install owlkettle from the latest git commit:'
"$HOME"/.nimble/bin/nimble --nim:"$HOME"/.nimble/bin/nim install owlkettle
}
build(){
echo 'Compile layoutSwitcher.nim for release build:'
"$HOME"/.nimble/bin/nim c -d:release --out:${srcdir}/layoutSwitcher ${srcdir}/layoutSwitcher.nim
echo 'Compile toggleGlobalMenu.nim for release build:'
"$HOME"/.nimble/bin/nim c -d:release --out:${srcdir}/toggleGlobalMenu ${srcdir}/toggleGlobalMenu.nim
}
package() {
# copy icons
install -d ${pkgdir}/usr/share/tromjaro-layout-switcher/icons
install -Dm644 ${srcdir}/icons/* ${pkgdir}/usr/share/tromjaro-layout-switcher/icons
# copy profiles
install -d ${pkgdir}/usr/share/tromjaro-layout-switcher/profiles
install -Dm644 ${srcdir}/profiles/* ${pkgdir}/usr/share/tromjaro-layout-switcher/profiles
# copy pacman hook file
install -Dm644 ${srcdir}/disable-global-menu.hook ${pkgdir}/usr/share/tromjaro-layout-switcher
# copy executables
install -d ${pkgdir}/usr/share/applications
install -Dm644 ${srcdir}/tromjaro-layout-switcher.desktop ${pkgdir}/usr/share/applications
install -Dm755 ${srcdir}/layoutSwitcher ${pkgdir}/usr/bin/tromjaro-layout-switcher
install -Dm755 ${srcdir}/toggleGlobalMenu ${pkgdir}/usr/bin/toggle-global-menu
# copy polkit action
install -d ${pkgdir}/usr/share/polkit-1/actions
install -Dm644 com.tromjaro.LayoutSwitcher.policy ${pkgdir}/usr/share/polkit-1/actions
# copy desktop icon
install -d ${pkgdir}/usr/share/icons/hicolor/scalable/apps
install -Dm644 ${srcdir}/tromjaro-layout-switcher.svg ${pkgdir}/usr/share/icons/hicolor/scalable/apps
}

@ -0,0 +1,19 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE policyconfig PUBLIC
"-//freedesktop//DTD PolicyKit Policy Configuration 1.0//EN"
"http://www.freedesktop.org/standards/PolicyKit/1.0/policyconfig.dtd">
<policyconfig>
<vendor>TROMjaro</vendor>
<vendor_url>https://www.tromjaro.com/</vendor_url>
<icon_name>tromjaro-layout-switcher</icon_name>
<action id="com.tromjaro.LayoutSwitcher.toggleGlobalMenu">
<description gettext-domain="LayoutSwitcher">Enable or disable global menu</description>
<message gettext-domain="LayoutSwitcher">Authentication is required to enable/disable global menu</message>
<defaults>
<allow_any>auth_admin</allow_any>
<allow_inactive>auth_admin</allow_inactive>
<allow_active>auth_admin</allow_active>
</defaults>
<annotate key="org.freedesktop.policykit.exec.path">/usr/bin/toggle-global-menu</annotate>
</action>
</policyconfig>

10
disable-global-menu.hook Normal file

@ -0,0 +1,10 @@
[Trigger]
Operation = Upgrade
Operation = Install
Type = Package
Target = vala-panel-appmenu-registrar-git
[Action]
Description = Disabling global menu...
When = PostTransaction
Exec = /usr/bin/toggle-global-menu disable

@ -1,60 +0,0 @@
#! /bin/bash
data=/usr/share/tromjaro-layout-switcher
icons=$data/icons
profiles=$data/profiles
enable-top-bar-integration() {
# Enable global menus
pacman -Qq vala-panel-appmenu-registrar ||
zensu SKIP_AUTOSNAP= pacman -S --noconfirm vala-panel-appmenu-registrar ||
{ notify-send 'Error' 'Failed installing vala-panel-appmenu-registrar !\nmake sure that you typed the password correctly or that you are not currently installing or updating your system\nEnabling the internet connection might solve the issue'; exit; }
pacman -Qq vala-panel-appmenu-registrar || exit
# Hide window borders when maximized
xfconf-query -c xfwm4 -p /general/borderless_maximize -n -t bool -s true
# Hide top bar of windows when maximized
xfconf-query -c xfwm4 -p /general/titleless_maximize -n -t bool -s true
# Put window buttons on left side
xfconf-query -c xfwm4 -p /general/button_layout -n -t string -s "CMH|"
}
disable-top-bar-integration() {
# Disable global menus
! pacman -Qq vala-panel-appmenu-registrar ||
zensu SKIP_AUTOSNAP= pacman -R --noconfirm vala-panel-appmenu-registrar ||
{ notify-send 'Error' 'Failed removing vala-panel-appmenu-registrar !\nmake sure that you typed the password correctly or that you are not currently installing or updating your system'; exit; }
pacman -Qq vala-panel-appmenu-registrar && exit
killall appmenu-registrar
# Hide window borders when maximized
xfconf-query -c xfwm4 -p /general/borderless_maximize -n -t bool -s true
# Don't hide top bar of windows when maximized
xfconf-query -c xfwm4 -p /general/titleless_maximize -n -t bool -s false
# Put window buttons on right side
xfconf-query -c xfwm4 -p /general/button_layout -n -t string -s "|HMC"
}
choice=$(
yad --no-buttons --center --keep-icon-size --separator='' --use-interp --title 'TROMjaro Layout Switcher' --text-align=center --text ' Please use the Panel Profiles to save your current configuration in case you did any manual changes, else you may lose them.
Changing to or from any layout that has global menus, will require your admin password.' --form --columns 3 \
--field=!"$icons/windows.png"!'Windows-Like (default)':BTN "kill -USR1 \$YAD_PID; echo -n 'Windows-Like'" \
--field=!"$icons/macos.png"!'MacOS-Like (experimental)':BTN "kill -USR1 \$YAD_PID; echo -n 'MacOS-Like'" \
--field=!"$icons/mx.png"!'MX-Like':BTN "kill -USR1 \$YAD_PID; echo -n 'MX-Like'" \
--field=!"$icons/gnome.png"!'Gnome-Like':BTN "kill -USR1 \$YAD_PID; echo -n 'Gnome-Like'" \
--field=!"$icons/unity.png"!'Unity-Like (experimental)':BTN "kill -USR1 \$YAD_PID; echo -n 'Unity-Like'" \
--field=!"$icons/topx.png"!'TopX-Like':BTN "kill -USR1 \$YAD_PID; echo -n 'TopX-Like'"
)
case "$choice" in
'Windows-Like'|'MX-Like'|'Gnome-Like'|'TopX-Like')
disable-top-bar-integration ;;
'Unity-Like'|'MacOS-Like')
enable-top-bar-integration ;;
*) exit ;;
esac
# Apply the XFCE panel profiles for the chosen layout
xfce4-panel-profiles load "$profiles/$choice.tar.bz2"
killall mate-hud && setsid -f /usr/lib/mate-hud/mate-hud
sleep 2.5 && notify-send "$choice layout was enabled"

169
layoutSwitcher.nim Normal file

@ -0,0 +1,169 @@
from std/os import symlinkExists, getConfigDir, `/`
from std/envvars import existsEnv, getEnv, delEnv, putEnv
from std/options import Option, some, get, isNone
from std/strutils import toLowerAscii, split
import pkg/owlkettle, ./sharedModule
const
dataDir = "/usr/share/tromjaro-layout-switcher"
iconsDir = dataDir / "icons"
profilesDir = dataDir / "profiles"
# GTK CSS for changing the default icon size and shape of our layout buttons
gtkCSS = """
.layout-button {
min-width: 16.2em;
min-height: 10.4em;
}
"""
appID = "com.tromjaro.LayoutSwitcher"
layoutsGrid = [
[ "Windows-Like (default)", "MacOS-Like (experimental)", "MX-Like" ],
[ "Gnome-Like", "Unity-Like (experimental)", "TopX-Like" ]
]
proc enableTopBarIntegration(): bool =
if not isGlobalMenuEnabled():
# Enable global menu
let exitCode = runCommand("/usr/bin/pkexec", ["/usr/bin/toggle-global-menu", "enable"])
case exitCode
of 0:
discard
of 126:
return false
of 127:
sendNotification(appID, "Layout Switcher", "Authentication failed!")
return false
else:
sendNotification(appID, "Layout Switcher", "Failed to enable global menu!")
return false
# Hide window borders when maximized
discard runCommand("/usr/bin/xfconf-query",
args=["--channel=xfwm4", "--property=/general/borderless_maximize", "--create", "--type=bool", "--set=true"])
# Hide top bar of windows when maximized
discard runCommand("/usr/bin/xfconf-query",
args=["--channel=xfwm4", "--property=/general/titleless_maximize", "--create", "--type=bool", "--set=true"])
# Put window buttons on left side
discard runCommand("/usr/bin/xfconf-query",
args=["--channel=xfwm4", "--property=/general/button_layout", "--create", "--type=string", "--set=CMH|"])
return true
proc disableTopBarIntegration(): bool =
if isGlobalMenuEnabled():
# Disable global menu
let exitCode = runCommand("/usr/bin/pkexec", ["/usr/bin/toggle-global-menu", "disable"])
case exitCode
of 0:
discard
of 126:
return false
of 127:
sendNotification(appID, "Layout Switcher", "Authentication failed!")
else:
sendNotification(appID, "Layout Switcher", "Failed to disable global menu!")
return false
# Hide window borders when maximized
discard runCommand("/usr/bin/xfconf-query",
args=["--channel=xfwm4", "--property=/general/borderless_maximize", "--create", "--type=bool", "--set=true"])
# Don't hide top bar of windows when maximized
discard runCommand("/usr/bin/xfconf-query",
args=["--channel=xfwm4", "--property=/general/titleless_maximize", "--create", "--type=bool", "--set=false"])
# Put window buttons on right side
discard runCommand("/usr/bin/xfconf-query",
args=["--channel=xfwm4", "--property=/general/button_layout", "--create", "--type=string", "--set=|HMC"])
return true
var
oldConfigDir: Option[string]
configDirChanged: bool
# Prevent loading GTK theme from ~/.config/gtk-4.0 directory when it is a symlink
if symlinkExists(getConfigDir() / "gtk-4.0"):
if existsEnv("XDG_CONFIG_HOME"):
oldConfigDir = some(getEnv("XDG_CONFIG_HOME"))
putEnv("XDG_CONFIG_HOME", "/dev/null")
configDirChanged = true
viewable App:
loading: bool
hooks:
build:
# Reset the user's XDG_CONFIG_HOME variable back to what it was before
if configDirChanged == true:
if oldConfigDir.isNone():
delEnv("XDG_CONFIG_HOME")
else:
putEnv("XDG_CONFIG_HOME", get(oldConfigDir))
proc enableLayout(args: tuple[layoutName: string, app: AppState]) {.thread.} =
let
layoutName = args.layoutName
app = args.app
defer:
app.loading = false
app.redrawFromThread()
case layoutName
of "Windows-Like", "MX-Like", "Gnome-Like", "TopX-Like":
if not disableTopBarIntegration():
return
of "Unity-Like", "MacOS-Like":
if not enableTopBarIntegration():
return
else:
return
# Load the layout profile
discard runCommand("/usr/bin/xfce4-panel-profiles", ["load", profilesDir / layoutName & ".tar.bz2"])
# Restart mate-hud
if runCommand("/usr/bin/killall", ["mate-hud"]) == 0:
discard runCommand("/usr/bin/setsid", ["-f", "/usr/lib/mate-hud/mate-hud"])
sendNotification(appID, "Layout Switcher", layoutName & " layout was enabled",
icon = iconsDir / layoutName.toLowerAscii() & "-layout.svg")
var thread: Thread[(string, AppState)]
method view(app: AppState): Widget =
result = gui:
Window:
title = "TROMjaro Layout Switcher"
# Shrink window to the smallest size
defaultSize = (1, 1)
iconName = "tromjaro-layout-switcher"
if app.loading:
Box(orient = OrientY):
Spinner {.vAlign: AlignEnd.}:
spinning = true
sizeRequest = (300, 300)
Label {.vAlign: AlignStart.}:
text = "Loading your layout, please wait..."
else:
Box(orient = OrientY, margin = 7, spacing = 5):
Box(orient = OrientX) {.vAlign: AlignEnd.}:
Label {.hAlign: AlignEnd.}:
text = "Please use the"
LinkButton {.expand: false.}:
text = "Panel Profiles"
proc clicked() =
discard runCommand("/usr/bin/setsid", ["-f", "/usr/bin/xfce4-panel-profiles"])
Label {.hAlign: AlignStart.}:
text = "to save your current configuration in case you did any manual changes, else you may lose them."
Label {.vAlign: AlignStart.}:
text = "Changing to or from any layout that has global menu will require your admin password."
for row in layoutsGrid:
Box(orient = OrientX, spacing = 5) {.vAlign: AlignStart.}:
for tooltip in row:
let layoutName = tooltip.split(' ', 1)[0]
Button {.hAlign: AlignCenter.}:
Picture:
pixbuf = loadPixbuf(iconsDir / layoutName.toLowerAscii() & "-layout.svg")
tooltip = tooltip
style = [ButtonFlat, StyleClass("layout-button")]
proc clicked() =
app.loading = true
createThread(thread, enableLayout, (layoutName, app))
brew(appID, gui(App()), stylesheets=[newStylesheet(gtkCSS)])
if running(thread):
joinThread(thread)

11
sharedModule.nim Normal file

@ -0,0 +1,11 @@
from std/osproc import startProcess, ProcessOption, waitForExit, close
from std/os import fileExists
proc runCommand*(command: string, args: openArray[string]): int =
## This will run a command with the given args and return its exit code upon completion
let process = startProcess(command, args=args, options={poParentStreams})
result = process.waitForExit()
process.close()
proc isGlobalMenuEnabled*(): bool =
return fileExists("/usr/lib/vala-panel/appmenu-registrar")

58
toggleGlobalMenu.nim Normal file

@ -0,0 +1,58 @@
from std/osproc import execProcess
from std/strformat import fmt
import sharedModule, std/os
proc enableGlobalMenus(): int =
try:
moveFile("/usr/lib/vala-panel/appmenu-registrar.disabled", "/usr/lib/vala-panel/appmenu-registrar")
removeFile("/usr/share/libalpm/hooks/disable-global-menu.hook")
except:
return 1
proc disableGlobalMenus(): int =
try:
moveFile("/usr/lib/vala-panel/appmenu-registrar", "/usr/lib/vala-panel/appmenu-registrar.disabled")
if not fileExists("/usr/share/libalpm/hooks/disable-global-menu.hook"):
createDir("/usr/share/libalpm/hooks")
copyFileWithPermissions("/usr/share/tromjaro-layout-switcher/disable-global-menu.hook",
"/usr/share/libalpm/hooks/disable-global-menu.hook")
discard runCommand("/usr/bin/killall", ["appmenu-registrar"])
except:
return 1
proc showHelp() =
let executableName = paramStr(0).extractFilename()
echo fmt"""
Usage: {executableName} <option>
Options:
enable enable global menus
disable disable global menus"""
if execProcess("/usr/bin/id", args=["--user"], options={}) != "0\n":
echo "Run this program as root."
quit(1)
var exitCode: int
if paramCount() < 1:
if isGlobalMenuEnabled():
exitCode = disableGlobalMenus()
else:
exitCode = enableGlobalMenus()
else:
case paramStr(1)
of "enable":
if isGlobalMenuEnabled():
echo "Global menus are already enabled."
exitCode = 0
else:
exitCode = enableGlobalMenus()
of "disable":
if not isGlobalMenuEnabled():
echo "Global menus are already disabled."
exitCode = 0
else:
exitCode = disableGlobalMenus()
else:
showHelp()
quit(exitCode)