From c60c17100b2e03d03863c8ecadfe77f51c10d0db Mon Sep 17 00:00:00 2001
From: rokosun <rokosun@noreply.git.trom.tf>
Date: Mon, 25 Dec 2023 07:50:13 +0000
Subject: [PATCH 1/8] Replace bash script with the new code in Nim

---
 layout-switcher    |  60 ------------------
 layoutSwitcher.nim | 147 +++++++++++++++++++++++++++++++++++++++++++++
 2 files changed, 147 insertions(+), 60 deletions(-)
 delete mode 100644 layout-switcher
 create mode 100644 layoutSwitcher.nim

diff --git a/layout-switcher b/layout-switcher
deleted file mode 100644
index 661af07..0000000
--- a/layout-switcher
+++ /dev/null
@@ -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"
\ No newline at end of file
diff --git a/layoutSwitcher.nim b/layoutSwitcher.nim
new file mode 100644
index 0000000..f8e8c79
--- /dev/null
+++ b/layoutSwitcher.nim
@@ -0,0 +1,147 @@
+from std/os import symlinkExists, getConfigDir, `/`, sleep
+from std/envvars import existsEnv, getEnv, delEnv, putEnv
+from std/options import Option, some, get, isNone
+from std/strutils import toLowerAscii, split
+import 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 > image {
+  -gtk-icon-transform: scale(19);
+}
+
+.layout-button {
+  min-height: 200px;
+  min-width: 300px;
+}"""
+  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, "Failed installing global menu!", "Make sure that you are not currently installing any apps or updating the system.\nEnabling internet connection might solve the issue.")
+      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, "Failed removing global menu!", "Make sure that you are not currently installing any apps or updating the system.")
+      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
+
+proc enableLayout(layoutName: string) =
+  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
+
+  discard runCommand("/usr/bin/xfce4-panel-profiles", ["load", profilesDir / layoutName & ".tar.bz2"])
+  if runCommand("/usr/bin/killall", ["mate-hud"]) == 0:
+    discard runCommand("/usr/bin/setsid", ["-f", "/usr/lib/mate-hud/mate-hud"])
+  sleep(5000)
+  sendNotification(appID, "Layout Switcher", layoutName & " layout was enabled",
+    icon = iconsDir / layoutName.toLowerAscii() & "-layout.png")
+
+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:
+  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))
+
+method view(app: AppState): Widget =
+  result = gui:
+    Window:
+      title = "TROMjaro Layout Switcher"
+      # Shrink window to the smallest size
+      defaultSize = (0, 0)
+      iconName = "tromjaro-layout-switcher"
+      Box(orient = OrientY, margin = 7, spacing = 5):
+        Box(orient = OrientX):
+          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:
+          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):
+            for tooltip in row:
+              let layoutName = tooltip.split(' ', 1)[0]
+              Button {.vAlign: AlignCenter, hAlign: AlignCenter.}:
+                icon = layoutName.toLowerAscii() & "-layout"
+                tooltip = tooltip
+                style = [ButtonFlat, StyleClass("layout-button")]
+                proc clicked() =
+                  enableLayout(layoutName)
+
+brew(appID, gui(App()), icons=[iconsDir], stylesheets=[newStylesheet(gtkCSS)])
-- 
2.39.5


From b7578dd97f5737151aef432b413554e4e94eb3e6 Mon Sep 17 00:00:00 2001
From: rokosun <rokosun@noreply.git.trom.tf>
Date: Mon, 25 Dec 2023 07:52:09 +0000
Subject: [PATCH 2/8] Add sharedModule.nim

---
 sharedModule.nim | 10 ++++++++++
 1 file changed, 10 insertions(+)
 create mode 100644 sharedModule.nim

diff --git a/sharedModule.nim b/sharedModule.nim
new file mode 100644
index 0000000..6c079ec
--- /dev/null
+++ b/sharedModule.nim
@@ -0,0 +1,10 @@
+from std/osproc import startProcess, ProcessOption, waitForExit, close
+
+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 runCommand("/usr/bin/pacman", ["-Qq", "vala-panel-appmenu-registrar"]) == 0
-- 
2.39.5


From 87ae3a63f50e8e89d7d981ec5fade3f4b2b73a25 Mon Sep 17 00:00:00 2001
From: rokosun <rokosun@noreply.git.trom.tf>
Date: Mon, 25 Dec 2023 07:54:45 +0000
Subject: [PATCH 3/8] Add toggleGlobalMenu.nim

---
 toggleGlobalMenu.nim | 44 ++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 44 insertions(+)
 create mode 100644 toggleGlobalMenu.nim

diff --git a/toggleGlobalMenu.nim b/toggleGlobalMenu.nim
new file mode 100644
index 0000000..33cd91c
--- /dev/null
+++ b/toggleGlobalMenu.nim
@@ -0,0 +1,44 @@
+from std/os import paramCount, paramStr, extractFilename
+from std/strformat import fmt
+import sharedModule
+
+proc enableGlobalMenus(): int =
+  return runCommand("/usr/bin/env", ["SKIP_AUTOSNAP=", "/usr/bin/pacman", "-S", "--noconfirm", "vala-panel-appmenu-registrar"])
+
+proc disableGlobalMenus(): int =
+  result = runCommand("/usr/bin/env", ["SKIP_AUTOSNAP=", "/usr/bin/pacman", "-R", "--noconfirm", "vala-panel-appmenu-registrar"])
+  if result == 0:
+    discard runCommand("/usr/bin/killall", ["appmenu-registrar"])
+
+proc showHelp() =
+  let executableName = paramStr(0).extractFilename()
+  echo fmt"""
+Usage: {executableName} <option>
+Options:
+    enable      install global menus
+    disable     remove global menus"""
+
+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)
-- 
2.39.5


From 779117672e693e8ee9f8cbcee145a69374a7ca8e Mon Sep 17 00:00:00 2001
From: rokosun <rokosun@noreply.git.trom.tf>
Date: Mon, 25 Dec 2023 08:00:39 +0000
Subject: [PATCH 4/8] Add polkit action file

---
 com.tromjaro.LayoutSwitcher.policy | 19 +++++++++++++++++++
 1 file changed, 19 insertions(+)
 create mode 100644 com.tromjaro.LayoutSwitcher.policy

diff --git a/com.tromjaro.LayoutSwitcher.policy b/com.tromjaro.LayoutSwitcher.policy
new file mode 100644
index 0000000..a5124ca
--- /dev/null
+++ b/com.tromjaro.LayoutSwitcher.policy
@@ -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">Install or remove global menu</description>
+		<message gettext-domain="LayoutSwitcher">Authentication is required to install/remove 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>
-- 
2.39.5


From b1dc6d7e296bb9007791446010b31480807a3a63 Mon Sep 17 00:00:00 2001
From: rokosun <rokosun@noreply.git.trom.tf>
Date: Mon, 25 Dec 2023 08:01:59 +0000
Subject: [PATCH 5/8] Update PKGBUILD for the new code in Nim

---
 PKGBUILD | 79 +++++++++++++++++++++++++++++++++++++++-----------------
 1 file changed, 55 insertions(+), 24 deletions(-)

diff --git a/PKGBUILD b/PKGBUILD
index 7d4aa59..df27dcd 100644
--- a/PKGBUILD
+++ b/PKGBUILD
@@ -3,22 +3,25 @@ pkgname=tromjaro-layout-switcher
 pkgver=1.4
 pkgrel=1
 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'
+         'util-linux'
          'vala-panel-appmenu-xfce-git'
          'vala-panel-appmenu-common-git'
          'libdbusmenu-gtk2'
          'appmenu-gtk-module')
+makedepends=('choosenim')
 optdepends=('vala-panel-appmenu-registrar')
 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"
         "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 +29,51 @@ sha256sums=('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@#head
+}
+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 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
 }
-- 
2.39.5


From ea7d1b82702901ae00e246bcda4a1be70f4c1a0d Mon Sep 17 00:00:00 2001
From: rokosun <rokosun@noreply.git.trom.tf>
Date: Mon, 25 Dec 2023 08:02:42 +0000
Subject: [PATCH 6/8] Update Makefile

---
 Makefile | 6 +++---
 1 file changed, 3 insertions(+), 3 deletions(-)

diff --git a/Makefile b/Makefile
index 1027abb..0c8be77 100644
--- a/Makefile
+++ b/Makefile
@@ -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
-- 
2.39.5


From c020b3626fb0e4451b0c823c24975d08f72e4328 Mon Sep 17 00:00:00 2001
From: rokosun <rokosun@noreply.git.trom.tf>
Date: Mon, 25 Dec 2023 08:27:04 +0000
Subject: [PATCH 7/8] Add more dependencies

---
 PKGBUILD | 6 ++++++
 1 file changed, 6 insertions(+)

diff --git a/PKGBUILD b/PKGBUILD
index df27dcd..35e8978 100644
--- a/PKGBUILD
+++ b/PKGBUILD
@@ -8,6 +8,12 @@ url="https://git.trom.tf/TROMjaro/layout-switcher-package"
 license=(unknown)
 depends=('xfce4-panel-profiles'
          'util-linux'
+         'xfconf'
+         'polkit'
+         'mate-hud'
+         'psmisc'
+         'pacman'
+         'coreutils'
          'vala-panel-appmenu-xfce-git'
          'vala-panel-appmenu-common-git'
          'libdbusmenu-gtk2'
-- 
2.39.5


From 1f29b13f85005fc9cdc7bec90cd62ee160b44423 Mon Sep 17 00:00:00 2001
From: rokosun <rokosun@noreply.git.trom.tf>
Date: Mon, 25 Dec 2023 15:23:03 +0000
Subject: [PATCH 8/8] Show loading animation when changing layouts

---
 layoutSwitcher.nim | 102 +++++++++++++++++++++++++++------------------
 1 file changed, 62 insertions(+), 40 deletions(-)

diff --git a/layoutSwitcher.nim b/layoutSwitcher.nim
index f8e8c79..9992ba1 100644
--- a/layoutSwitcher.nim
+++ b/layoutSwitcher.nim
@@ -75,24 +75,6 @@ proc disableTopBarIntegration(): bool =
     args=["--channel=xfwm4", "--property=/general/button_layout", "--create", "--type=string", "--set=|HMC"])
   return true
 
-proc enableLayout(layoutName: string) =
-  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
-
-  discard runCommand("/usr/bin/xfce4-panel-profiles", ["load", profilesDir / layoutName & ".tar.bz2"])
-  if runCommand("/usr/bin/killall", ["mate-hud"]) == 0:
-    discard runCommand("/usr/bin/setsid", ["-f", "/usr/lib/mate-hud/mate-hud"])
-  sleep(5000)
-  sendNotification(appID, "Layout Switcher", layoutName & " layout was enabled",
-    icon = iconsDir / layoutName.toLowerAscii() & "-layout.png")
-
 var
   oldConfigDir: Option[string]
   configDirChanged: bool
@@ -105,6 +87,7 @@ if symlinkExists(getConfigDir() / "gtk-4.0"):
   configDirChanged = true
 
 viewable App:
+  loading: bool
   hooks:
     build:
       # Reset the user's XDG_CONFIG_HOME variable back to what it was before
@@ -114,6 +97,37 @@ viewable App:
         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"])
+  # Wait 5 seconds for the effects to take place on screen
+  sleep(5000)
+  sendNotification(appID, "Layout Switcher", layoutName & " layout was enabled",
+    icon = iconsDir / layoutName.toLowerAscii() & "-layout.png")
+
+var thread: Thread[(string, AppState)]
+
 method view(app: AppState): Widget =
   result = gui:
     Window:
@@ -121,27 +135,35 @@ method view(app: AppState): Widget =
       # Shrink window to the smallest size
       defaultSize = (0, 0)
       iconName = "tromjaro-layout-switcher"
-      Box(orient = OrientY, margin = 7, spacing = 5):
-        Box(orient = OrientX):
-          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:
-          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):
-            for tooltip in row:
-              let layoutName = tooltip.split(' ', 1)[0]
-              Button {.vAlign: AlignCenter, hAlign: AlignCenter.}:
-                icon = layoutName.toLowerAscii() & "-layout"
-                tooltip = tooltip
-                style = [ButtonFlat, StyleClass("layout-button")]
-                proc clicked() =
-                  enableLayout(layoutName)
+      if app.loading:
+        Box(orient = OrientY, margin = 70):
+          Spinner(spinning = true)
+          Label(text = "Loading your layout, please wait...") {.expand: false.}
+      else:
+        Box(orient = OrientY, margin = 7, spacing = 5):
+          Box(orient = OrientX):
+            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:
+            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):
+              for tooltip in row:
+                let layoutName = tooltip.split(' ', 1)[0]
+                Button {.vAlign: AlignCenter, hAlign: AlignCenter.}:
+                  icon = layoutName.toLowerAscii() & "-layout"
+                  tooltip = tooltip
+                  style = [ButtonFlat, StyleClass("layout-button")]
+                  proc clicked() =
+                    app.loading = true
+                    createThread(thread, enableLayout, (layoutName, app))
 
 brew(appID, gui(App()), icons=[iconsDir], stylesheets=[newStylesheet(gtkCSS)])
+
+joinThread(thread)
-- 
2.39.5