From 9b4e7fac4476c7fba7e7447c50bcd040a88dd9bb Mon Sep 17 00:00:00 2001
From: matt1432 <matt@nelim.org>
Date: Tue, 17 Oct 2023 13:47:02 -0400
Subject: [PATCH] refactor(ags): make all widgets functions, use export default
 and some formatting

---
 hosts/wim/config/ags/js/applauncher/main.js   |   4 +-
 hosts/wim/config/ags/js/bar/audio.js          |  42 ++--
 hosts/wim/config/ags/js/bar/battery.js        |  14 +-
 hosts/wim/config/ags/js/bar/brightness.js     |  18 +-
 hosts/wim/config/ags/js/bar/clock.js          |  18 +-
 hosts/wim/config/ags/js/bar/current-window.js |   8 +-
 hosts/wim/config/ags/js/bar/fullscreen.js     |  56 +++--
 hosts/wim/config/ags/js/bar/gesture.js        |  31 ++-
 hosts/wim/config/ags/js/bar/heart.js          |  18 +-
 .../wim/config/ags/js/bar/keyboard-layout.js  |   2 +-
 hosts/wim/config/ags/js/bar/main.js           |  52 ++---
 hosts/wim/config/ags/js/bar/notif-button.js   |  45 ++--
 hosts/wim/config/ags/js/bar/osk-toggle.js     |  34 ++-
 hosts/wim/config/ags/js/bar/quick-settings.js |  15 +-
 hosts/wim/config/ags/js/bar/systray.js        |   4 +-
 hosts/wim/config/ags/js/bar/tablet-toggle.js  |  15 +-
 hosts/wim/config/ags/js/bar/workspaces.js     |  54 ++---
 hosts/wim/config/ags/js/date.js               |  17 +-
 .../wim/config/ags/js/media-player/gesture.js |   4 +-
 hosts/wim/config/ags/js/media-player/mpris.js | 176 ++++++++-------
 .../wim/config/ags/js/media-player/player.js  |  27 ++-
 hosts/wim/config/ags/js/misc/closer.js        |   2 +-
 hosts/wim/config/ags/js/misc/cursorbox.js     |  71 +++---
 hosts/wim/config/ags/js/misc/popup.js         |  52 +++--
 hosts/wim/config/ags/js/misc/separator.js     |  15 +-
 hosts/wim/config/ags/js/notifications/base.js |  39 ++--
 .../wim/config/ags/js/notifications/center.js |  61 +++--
 .../config/ags/js/notifications/gesture.js    |  90 ++++----
 .../wim/config/ags/js/notifications/popup.js  |  13 +-
 hosts/wim/config/ags/js/overview/clients.js   |  30 ++-
 hosts/wim/config/ags/js/overview/dragndrop.js |  39 ++--
 hosts/wim/config/ags/js/overview/main.js      |  19 +-
 .../wim/config/ags/js/overview/workspaces.js  | 212 ++++++++++--------
 hosts/wim/config/ags/js/powermenu.js          |  11 +-
 .../ags/js/quick-settings/button-grid.js      | 123 ++++++----
 .../wim/config/ags/js/quick-settings/main.js  |  24 +-
 .../ags/js/quick-settings/slider-box.js       |   9 +-
 hosts/wim/config/ags/js/screen-corners.js     |  25 ++-
 hosts/wim/config/hypr/main.conf               |   2 +-
 39 files changed, 797 insertions(+), 694 deletions(-)

diff --git a/hosts/wim/config/ags/js/applauncher/main.js b/hosts/wim/config/ags/js/applauncher/main.js
index cac6a644..5039bc3b 100644
--- a/hosts/wim/config/ags/js/applauncher/main.js
+++ b/hosts/wim/config/ags/js/applauncher/main.js
@@ -1,8 +1,8 @@
 import { App, Applications, Utils, Widget } from '../../imports.js';
 const { Label, Box, Icon, Button, Scrollable, Entry } = Widget;
 
-import { Separator } from '../misc/separator.js';
-import { PopupWindow } from '../misc/popup.js';
+import Separator   from '../misc/separator.js';
+import PopupWindow from '../misc/popup.js';
 
 const icons = {
   apps: {
diff --git a/hosts/wim/config/ags/js/bar/audio.js b/hosts/wim/config/ags/js/bar/audio.js
index a0d4cb5f..70db20df 100644
--- a/hosts/wim/config/ags/js/bar/audio.js
+++ b/hosts/wim/config/ags/js/bar/audio.js
@@ -1,8 +1,8 @@
 import { Audio, Widget } from '../../imports.js';
 const { Label, Box, Icon } = Widget;
 
-import { Separator } from '../misc/separator.js';
-import { EventBox } from '../misc/cursorbox.js';
+import Separator from '../misc/separator.js';
+import EventBox  from '../misc/cursorbox.js';
 
 const items = {
   101: 'audio-volume-overamplified-symbolic',
@@ -13,36 +13,36 @@ const items = {
 };
 
 
-const SpeakerIndicator = params => Icon({
-  ...params,
+const SpeakerIndicator = props => Icon({
+  ...props,
   icon: '',
-  connections: [[Audio, icon => {
-    if (Audio.speaker) {
-      if (Audio.speaker.stream.isMuted) {
-        icon.icon = items[0];
-      }
-      else {
-        const vol = Audio.speaker.volume * 100;
-        for (const threshold of [-1, 0, 33, 66, 100]) {
-          if (vol > threshold + 1) {
-            icon.icon = items[threshold + 1];
-          }
-        }
+  connections: [[Audio, self => {
+    if (!Audio.speaker)
+      return;
+
+    if (Audio.speaker.stream.isMuted) {
+      self.icon = items[0];
+    }
+    else {
+      const vol = Audio.speaker.volume * 100;
+
+      for (const threshold of [-1, 0, 33, 66, 100]) {
+        if (vol > threshold + 1)
+          self.icon = items[threshold + 1];
       }
     }
   }, 'speaker-changed']],
 });
 
-const SpeakerPercentLabel = params => Label({
-  ...params,
+const SpeakerPercentLabel = props => Label({
+  ...props,
   connections: [[Audio, label => {
-    if (Audio.speaker) {
+    if (Audio.speaker)
       label.label = Math.round(Audio.speaker.volume * 100) + '%';
-    }
   }, 'speaker-changed']],
 });
 
-export const AudioIndicator = EventBox({
+export default () => EventBox({
   onPrimaryClickRelease: 'pavucontrol',
   className: 'toggle-off',
   child: Box({
diff --git a/hosts/wim/config/ags/js/bar/battery.js b/hosts/wim/config/ags/js/bar/battery.js
index 9b0bcdff..ef510c18 100644
--- a/hosts/wim/config/ags/js/bar/battery.js
+++ b/hosts/wim/config/ags/js/bar/battery.js
@@ -1,7 +1,7 @@
 import { Battery, Widget } from '../../imports.js';
 const { Label, Icon, Stack, Box } = Widget;
 
-import { Separator } from '../misc/separator.js';
+import Separator from '../misc/separator.js';
 
 const icons = charging => ([
   ...Array.from({ length: 10 }, (_, i) => i * 10).map(i => ([
@@ -27,9 +27,9 @@ const Indicators = charging => Stack({
 const Indicator = ({
   charging = Indicators(true),
   discharging = Indicators(false),
-  ...params
+  ...props
 } = {}) => Stack({
-  ...params,
+  ...props,
   className: 'battery-indicator',
   items: [
     ['true', charging],
@@ -43,13 +43,13 @@ const Indicator = ({
   }]],
 });
 
-const LevelLabel = params => Label({
-  ...params,
+const LevelLabel = props => Label({
+  ...props,
   className: 'label',
-  connections: [[Battery, label => label.label = `${Battery.percent}%`]],
+  connections: [[Battery, self => self.label = `${Battery.percent}%`]],
 });
 
-export const BatteryIndicator = Box({
+export default () => Box({
   className: 'toggle-off battery',
   children: [
     Indicator(),
diff --git a/hosts/wim/config/ags/js/bar/brightness.js b/hosts/wim/config/ags/js/bar/brightness.js
index 3c92e472..01859b28 100644
--- a/hosts/wim/config/ags/js/bar/brightness.js
+++ b/hosts/wim/config/ags/js/bar/brightness.js
@@ -1,25 +1,23 @@
 import { Utils, Widget } from '../../imports.js';
 const { ProgressBar, Overlay, Box } = Widget;
 
-import { Separator } from '../misc/separator.js';
-import { Heart }     from './heart.js';
+import Separator from '../misc/separator.js';
+import Heart     from './heart.js';
 
 
-export const Brightness = Overlay({
-  setup: widget => {
-    widget.set_tooltip_text('Brightness');
-  },
+export default () => Overlay({
+  tooltipText: 'Brightness',
   child: ProgressBar({
     className: 'toggle-off brightness',
     connections: [
-      [200, progress => {
+      [200, self => {
         Utils.execAsync('brightnessctl get').then(out => {
           let br = out / 255;
           if (br > 0.33) {
-            progress.value = br;
+            self.value = br;
           }
           else {
-            progress.value = 0.33;
+            self.value = 0.33;
           }
         }).catch(print);
       }],
@@ -30,7 +28,7 @@ export const Brightness = Overlay({
       style: 'color: #CBA6F7;',
       children: [
         Separator(25),
-        Heart,
+        Heart(),
       ],
     }),
   ],
diff --git a/hosts/wim/config/ags/js/bar/clock.js b/hosts/wim/config/ags/js/bar/clock.js
index 6fdcf236..4f0cdfad 100644
--- a/hosts/wim/config/ags/js/bar/clock.js
+++ b/hosts/wim/config/ags/js/bar/clock.js
@@ -4,30 +4,32 @@ const { Box, Label } = Widget;
 import GLib from 'gi://GLib';
 const { DateTime } = GLib;
 
-import { EventBox } from '../misc/cursorbox.js';
+import EventBox from '../misc/cursorbox.js';
 
 
 const ClockModule = ({
     interval = 1000,
-    ...params
+    ...props
 }) => Label({
-    ...params,
+    ...props,
     className: 'clock',
     connections: [
-      [interval, label => {
+      [interval, self => {
         var time = DateTime.new_now_local();
-        label.label = time.format('%a. ') + time.get_day_of_month() + time.format(' %b. %H:%M');
+        self.label = time.format('%a. ') +
+                     time.get_day_of_month() +
+                     time.format(' %b. %H:%M');
       }],
     ],
 });
 
-export const Clock = EventBox({
+export default () => EventBox({
   className: 'toggle-off',
   onPrimaryClickRelease: () => App.toggleWindow('calendar'),
   connections: [
-    [App, (box, windowName, visible) => {
+    [App, (self, windowName, visible) => {
       if (windowName == 'calendar') {
-        box.toggleClassName('toggle-on', visible);
+        self.toggleClassName('toggle-on', visible);
       }
     }],
   ],
diff --git a/hosts/wim/config/ags/js/bar/current-window.js b/hosts/wim/config/ags/js/bar/current-window.js
index faa27482..8548eef9 100644
--- a/hosts/wim/config/ags/js/bar/current-window.js
+++ b/hosts/wim/config/ags/js/bar/current-window.js
@@ -2,12 +2,8 @@ import { Widget, Hyprland } from '../../imports.js';
 const { Label } = Widget;
 
 
-export const CurrentWindow = Label({
+export default () => Label({
   style: 'color: #CBA6F7; font-size: 18px',
   truncate: 'end',
-  connections: [
-    [Hyprland, label => {
-      label.label = Hyprland.active.client.title;
-    }, 'changed'],
-  ],
+  binds: [['label', Hyprland.active.client, 'title']],
 });
diff --git a/hosts/wim/config/ags/js/bar/fullscreen.js b/hosts/wim/config/ags/js/bar/fullscreen.js
index 479a324e..528546ae 100644
--- a/hosts/wim/config/ags/js/bar/fullscreen.js
+++ b/hosts/wim/config/ags/js/bar/fullscreen.js
@@ -4,19 +4,14 @@ const { Box, EventBox, Overlay } = Widget;
 const Revealed = Variable(true);
 const Hovering = Variable(false);
 
-import { Gesture } from './gesture.js';
-import { RoundedCorner }    from '../screen-corners.js';
+import { RoundedCorner } from '../screen-corners.js';
+import Gesture           from './gesture.js';
 
 
-export const Revealer = params => Overlay({
+export default (props) => Overlay({
   overlays: [
-    RoundedCorner('topleft', {
-      className: 'corner',
-    }),
-
-    RoundedCorner('topright', {
-      className: 'corner',
-    }),
+    RoundedCorner('topleft',  { className: 'corner' }),
+    RoundedCorner('topright', { className: 'corner' }),
   ],
 
   child: Box({
@@ -27,27 +22,26 @@ export const Revealer = params => Overlay({
       Widget.Revealer({
         transition: 'slide_down',
         setup: self => self.revealChild = true,
-        properties: [
-          ['timeouts', []],
-        ],
-        connections: [[Hyprland, self => {
-          Utils.execAsync('hyprctl activewindow -j')
-            .then(result => {
-              let client = JSON.parse(result);
-              if (client.fullscreen !== Revealed.value) {
-                Revealed.value = client.fullscreen;
 
-                if (Revealed.value) {
-                  setTimeout(() => {
-                    if (Revealed.value)
-                      self.revealChild = false
-                  }, 2000);
-                }
-                else {
-                  self.revealChild = true;
-                }
-              }
-            }).catch(print);
+        properties: [['timeouts', []]],
+        connections: [[Hyprland, self => {
+          Utils.execAsync('hyprctl activewindow -j').then(out => {
+            let client = JSON.parse(out);
+            if (client.fullscreen === Revealed.value)
+              return;
+
+            Revealed.value = client.fullscreen;
+
+            if (Revealed.value) {
+              setTimeout(() => {
+                if (Revealed.value)
+                  self.revealChild = false
+              }, 2000);
+            }
+            else {
+              self.revealChild = true;
+            }
+          }).catch(print);
         }]],
 
         child: Gesture({
@@ -63,7 +57,7 @@ export const Revealer = params => Overlay({
               }, 2000);
             }
           },
-          ...params,
+          ...props,
         }),
       }),
 
diff --git a/hosts/wim/config/ags/js/bar/gesture.js b/hosts/wim/config/ags/js/bar/gesture.js
index ea6f060e..474e6d75 100644
--- a/hosts/wim/config/ags/js/bar/gesture.js
+++ b/hosts/wim/config/ags/js/bar/gesture.js
@@ -4,30 +4,25 @@ const { CenterBox, EventBox } = Widget;
 import Gtk from 'gi://Gtk';
 
 
-export const Gesture = ({
+export default ({
   child,
-  ...params
+  ...props
 }) => {
-  let w = EventBox({
-    ...params,
+  let widget = EventBox({
+    ...props,
   });
 
-  let gesture = Gtk.GestureSwipe.new(w);
+  let gesture = Gtk.GestureSwipe.new(widget);
 
-  w.child = CenterBox({
-    children: [
-      child,
-    ],
-    connections: [
+  widget.child = CenterBox({
+    children: [ child ],
+    connections: [[gesture, () => {
+      const velocity = gesture.get_velocity()[1];
+      if (velocity < -100)
+        App.openWindow('quick-settings');
 
-      [gesture, _ => {
-        const velocity = gesture.get_velocity()[1];
-        if (velocity < -100)
-          App.openWindow('quick-settings');
-      }, 'update'],
-
-    ],
+    }, 'update']],
   });
 
-  return w;
+  return widget;
 };
diff --git a/hosts/wim/config/ags/js/bar/heart.js b/hosts/wim/config/ags/js/bar/heart.js
index 3ca86a64..1bc3ec6a 100644
--- a/hosts/wim/config/ags/js/bar/heart.js
+++ b/hosts/wim/config/ags/js/bar/heart.js
@@ -2,26 +2,28 @@ import { Utils, Widget } from '../../imports.js';
 const { Box, Label } = Widget;
 const { subprocess, execAsync } = Utils;
 
-import { EventBox } from '../misc/cursorbox.js';
+import EventBox from '../misc/cursorbox.js';
 
 
-subprocess(
-  ['bash', '-c', 'tail -f /home/matt/.config/.heart'],
-  (output) => {
-    Heart.child.children[0].label = ' ' + output;
-  },
-);
-export const Heart = EventBox({
+export default () => EventBox({
   halign: 'center',
+
   onPrimaryClickRelease: () => {
     execAsync(['bash', '-c', '$AGS_PATH/heart.sh toggle']).catch(print);
   },
+
   child: Box({
     className: 'heart-toggle',
     vertical: false,
 
     child: Label({
       label: '',
+      setup: self => {
+        subprocess(
+          ['bash', '-c', 'tail -f /home/matt/.config/.heart'],
+          (output) => self.label = ' ' + output,
+        );
+      },
     }),
   }),
 });
diff --git a/hosts/wim/config/ags/js/bar/keyboard-layout.js b/hosts/wim/config/ags/js/bar/keyboard-layout.js
index 6122fbf5..ecb736c4 100644
--- a/hosts/wim/config/ags/js/bar/keyboard-layout.js
+++ b/hosts/wim/config/ags/js/bar/keyboard-layout.js
@@ -3,7 +3,7 @@ const { Label, Box, Icon } = Widget;
 
 const DEFAULT_KB = "at-translated-set-2-keyboard";
 
-export default Box({
+export default () => Box({
   className: 'toggle-off',
   children: [
     Icon({
diff --git a/hosts/wim/config/ags/js/bar/main.js b/hosts/wim/config/ags/js/bar/main.js
index fe251b6c..182edb7f 100644
--- a/hosts/wim/config/ags/js/bar/main.js
+++ b/hosts/wim/config/ags/js/bar/main.js
@@ -1,20 +1,20 @@
 import { Widget } from '../../imports.js';
 const { Window, CenterBox, Box } = Widget;
 
-import { Separator }        from '../misc/separator.js';
-import { CurrentWindow }    from './current-window.js';
-import { Workspaces }       from './workspaces.js';
-import { OskToggle }        from './osk-toggle.js';
-import { TabletToggle }     from './tablet-toggle.js';
-import { QsToggle }         from './quick-settings.js';
-import { NotifButton }      from './notif-button.js';
-import { Clock }            from './clock.js';
-import { SysTray }          from './systray.js';
-import { BatteryIndicator } from './battery.js';
-import { Brightness }       from './brightness.js';
-import { AudioIndicator }   from './audio.js';
-import { Revealer }         from './fullscreen.js';
-//import KeyboardLayout       from './keyboard-layout.js';
+import Separator      from '../misc/separator.js';
+import CurrentWindow  from './current-window.js';
+import Workspaces     from './workspaces.js';
+import OskToggle      from './osk-toggle.js';
+import TabletToggle   from './tablet-toggle.js';
+import QsToggle       from './quick-settings.js';
+import NotifButton    from './notif-button.js';
+import Clock          from './clock.js';
+import SysTray        from './systray.js';
+import Battery        from './battery.js';
+import Brightness     from './brightness.js';
+import Audio          from './audio.js';
+import Revealer       from './fullscreen.js';
+//import KeyboardLayout from './keyboard-layout.js';
 
 
 export const Bar = () => Window({
@@ -31,55 +31,55 @@ export const Bar = () => Window({
         halign: 'start',
         children: [
 
-          OskToggle,
+          OskToggle(),
 
           Separator(12),
 
-          TabletToggle,
+          TabletToggle(),
 
           Separator(12),
 
-          SysTray,
+          SysTray(),
 
-          AudioIndicator,
+          Audio(),
 
           Separator(12),
 
-          Brightness,
+          Brightness(),
 
           Separator(12),
 
-          Workspaces,
+          Workspaces(),
 
         ],
       }),
 
       centerWidget: Box({
         children: [
-          CurrentWindow,
+          CurrentWindow(),
         ],
       }),
 
       endWidget: Box({
         halign: 'end',
         children: [
-          BatteryIndicator,
+          Battery(),
 
           Separator(12),
 
-          //KeyboardLayout,
+          //KeyboardLayout(),
 
           //Separator(12),
 
-          Clock,
+          Clock(),
 
           Separator(12),
 
-          NotifButton,
+          NotifButton(),
 
           Separator(12),
 
-          QsToggle,
+          QsToggle(),
         ],
       }),
     }),
diff --git a/hosts/wim/config/ags/js/bar/notif-button.js b/hosts/wim/config/ags/js/bar/notif-button.js
index 1bd5b912..bc834b9d 100644
--- a/hosts/wim/config/ags/js/bar/notif-button.js
+++ b/hosts/wim/config/ags/js/bar/notif-button.js
@@ -1,20 +1,17 @@
 import { App, Notifications, Widget } from '../../imports.js';
 const { Box, Label, Icon } = Widget;
 
-import { Separator } from '../misc/separator.js';
-import { EventBox } from '../misc/cursorbox.js';
+import Separator from '../misc/separator.js';
+import EventBox  from '../misc/cursorbox.js';
 
 
-export const NotifButton = EventBox({
+export default () => EventBox({
   className: 'toggle-off',
   onPrimaryClickRelease: () => App.toggleWindow('notification-center'),
-  connections: [
-    [App, (box, windowName, visible) => {
-      if (windowName == 'notification-center') {
-        box.toggleClassName('toggle-on', visible);
-      }
-    }],
-  ],
+  connections: [[App, (self, windowName, visible) => {
+    if (windowName == 'notification-center')
+      self.toggleClassName('toggle-on', visible);
+  }]],
   child: Box({
     className: 'notif-panel',
     vertical: false,
@@ -22,30 +19,26 @@ export const NotifButton = EventBox({
       Separator(28),
 
       Icon({
-        connections: [
-          [Notifications, icon => {
-            if (Notifications.dnd) {
-              icon.icon = 'notification-disabled-symbolic'
+        connections: [[Notifications, self => {
+          if (Notifications.dnd) {
+            self.icon = 'notification-disabled-symbolic'
+          }
+          else {
+            if (Notifications.notifications.length > 0) {
+              self.icon = 'notification-new-symbolic'
             }
             else {
-              if (Notifications.notifications.length > 0) {
-                icon.icon = 'notification-new-symbolic'
-              }
-              else {
-                icon.icon = 'notification-symbolic'
-              }
+              self.icon = 'notification-symbolic'
             }
-          }],
-        ],
+          }
+        }]],
       }),
 
       Separator(8),
 
       Label({
-        connections: [
-          [Notifications, label => {
-            label.label = String(Notifications.notifications.length);
-          }],
+        binds: [
+          ['label', Notifications, 'notifications', n => String(n.length)],
         ],
       }),
 
diff --git a/hosts/wim/config/ags/js/bar/osk-toggle.js b/hosts/wim/config/ags/js/bar/osk-toggle.js
index c53ea848..0d02d455 100644
--- a/hosts/wim/config/ags/js/bar/osk-toggle.js
+++ b/hosts/wim/config/ags/js/bar/osk-toggle.js
@@ -2,33 +2,25 @@ import { Utils, Widget } from '../../imports.js';
 const { Box, Label } = Widget;
 const { subprocess } = Utils;
 
-import { EventBox } from '../misc/cursorbox.js';
+import EventBox from '../misc/cursorbox.js';
 
 
-subprocess(
-  ['bash', '-c', '$AGS_PATH/osk-toggle.sh getState'],
-  (output) => {
-    if (output == 'Running') {
-      OskToggle.toggleClassName('toggle-on', true);
-    } else {
-      OskToggle.toggleClassName('toggle-on', false);
-    }
-  },
-);
-export const OskToggle = EventBox({
+export default () => EventBox({
   className: 'toggle-off',
-  onPrimaryClickRelease: function() {
+  setup: self => {
     subprocess(
-      ['bash', '-c', '$AGS_PATH/osk-toggle.sh toggle'],
-      (output) => {
-        if (output == 'Running') {
-          OskToggle.toggleClassName('toggle-on', false);
-        } else {
-          OskToggle.toggleClassName('toggle-on', true);
-        }
-      },
+      ['bash', '-c', '$AGS_PATH/osk-toggle.sh getState'],
+      (output) => self.toggleClassName('toggle-on', output === 'Running'),
     );
   },
+
+  onPrimaryClickRelease: self => {
+    subprocess(
+      ['bash', '-c', '$AGS_PATH/osk-toggle.sh toggle'],
+      (output) => self.toggleClassName('toggle-on', output !== 'Running'),
+    );
+  },
+
   child: Box({
     className: 'osk-toggle',
     vertical: false,
diff --git a/hosts/wim/config/ags/js/bar/quick-settings.js b/hosts/wim/config/ags/js/bar/quick-settings.js
index e039be06..d03d024c 100644
--- a/hosts/wim/config/ags/js/bar/quick-settings.js
+++ b/hosts/wim/config/ags/js/bar/quick-settings.js
@@ -1,19 +1,16 @@
 import { Widget, App } from '../../imports.js';
 const { Box, Label } = Widget;
 
-import { EventBox } from '../misc/cursorbox.js';
+import EventBox from '../misc/cursorbox.js';
 
 
-export const QsToggle = EventBox({
+export default () => EventBox({
   className: 'toggle-off',
   onPrimaryClickRelease: () => App.toggleWindow('quick-settings'),
-  connections: [
-    [App, (box, windowName, visible) => {
-      if (windowName == 'quick-settings') {
-        box.toggleClassName('toggle-on', visible);
-      }
-    }],
-  ],
+  connections: [[App, (self, windowName, visible) => {
+    if (windowName == 'quick-settings')
+      self.toggleClassName('toggle-on', visible);
+  }]],
   child: Box({
     className: 'quick-settings-toggle',
     vertical: false,
diff --git a/hosts/wim/config/ags/js/bar/systray.js b/hosts/wim/config/ags/js/bar/systray.js
index b31c3dbb..423376ee 100644
--- a/hosts/wim/config/ags/js/bar/systray.js
+++ b/hosts/wim/config/ags/js/bar/systray.js
@@ -3,7 +3,7 @@ const { Box, Revealer, Icon, MenuItem } = Widget;
 
 import Gtk from 'gi://Gtk';
 
-import { Separator } from '../misc/separator.js';
+import Separator from '../misc/separator.js';
 
 
 const SysTrayItem = item => MenuItem({
@@ -21,7 +21,7 @@ const SysTrayItem = item => MenuItem({
   }]]
 });
 
-export const SysTray = Revealer({
+export default () => Revealer({
   transition: 'slide_right',
   connections: [[SystemTray, rev => {
     rev.revealChild = rev.child.children[0].get_children().length > 0;
diff --git a/hosts/wim/config/ags/js/bar/tablet-toggle.js b/hosts/wim/config/ags/js/bar/tablet-toggle.js
index 8b319925..e2319b68 100644
--- a/hosts/wim/config/ags/js/bar/tablet-toggle.js
+++ b/hosts/wim/config/ags/js/bar/tablet-toggle.js
@@ -2,22 +2,15 @@ import { Utils, Widget } from '../../imports.js';
 const { Box, Label } = Widget;
 const { subprocess } = Utils;
 
-import { EventBox } from '../misc/cursorbox.js';
+import EventBox from '../misc/cursorbox.js';
 
 
-export const TabletToggle = EventBox({
+export default () => EventBox({
   className: 'toggle-off',
-  onPrimaryClickRelease: function() {
+  onPrimaryClickRelease: self => {
     subprocess(
       ['bash', '-c', '$AGS_PATH/tablet-toggle.sh toggle'],
-      (output) => {
-        print(output)
-        if (output == 'Tablet') {
-          TabletToggle.toggleClassName('toggle-on', true);
-        } else {
-          TabletToggle.toggleClassName('toggle-on', false);
-        }
-      },
+      (output) => self.toggleClassName('toggle-on', output == 'Tablet'),
     );
   },
   child: Box({
diff --git a/hosts/wim/config/ags/js/bar/workspaces.js b/hosts/wim/config/ags/js/bar/workspaces.js
index e806e8a2..898b8aac 100644
--- a/hosts/wim/config/ags/js/bar/workspaces.js
+++ b/hosts/wim/config/ags/js/bar/workspaces.js
@@ -1,69 +1,69 @@
 import { Hyprland, Utils, Widget } from '../../imports.js';
-const { Box, Label, Revealer } = Widget;
+const { Box, Revealer } = Widget;
 const { execAsync } = Utils;
 
-import { EventBox } from '../misc/cursorbox.js';
+import EventBox from '../misc/cursorbox.js';
 
 
 const Workspace = ({ i } = {}) =>
 Revealer({
   transition: "slide_right",
-  properties: [
-    ['id', i],
-  ],
+  properties: [['id', i]],
+
   child: EventBox({
     tooltipText: `${i}`,
-    onPrimaryClickRelease: () => execAsync(`hyprctl dispatch workspace ${i}`).catch(print),
+    onPrimaryClickRelease: () => {
+      execAsync(`hyprctl dispatch workspace ${i}`)
+      .catch(print);
+    },
     child: Box({
       className: 'button',
-      connections: [
-        [Hyprland, btn => {
-          const occupied = Hyprland.getWorkspace(i)?.windows > 0;
-          btn.toggleClassName('active', Hyprland.active.workspace.id === i);
-          btn.toggleClassName('occupied', occupied);
-          btn.toggleClassName('empty', !occupied);
-        }]
-      ],
+      connections: [[Hyprland, self => {
+        const occupied = Hyprland.getWorkspace(i)?.windows > 0;
+        self.toggleClassName('active', Hyprland.active.workspace.id === i);
+        self.toggleClassName('occupied', occupied);
+        self.toggleClassName('empty', !occupied);
+      }]],
     }),
   }),
 });
 
-export const Workspaces = Box({
+export default () => Box({
   className: 'workspaces',
   children: [EventBox({
     child: Box({
       properties: [
         ['workspaces'],
 
-        ['refresh', box => {
-          box.children.forEach(rev => rev.reveal_child = false);
-          box._workspaces.forEach(ws => {
+        ['refresh', self => {
+          self.children.forEach(rev => rev.reveal_child = false);
+          self._workspaces.forEach(ws => {
             ws.revealChild = true;
           });
         }],
 
-        ['updateWs', box => {
+        ['updateWs', self => {
           Hyprland.workspaces.forEach(ws => {
-            let currentWs = box.children.find(ch => ch._id == ws.id);
+            let currentWs = self.children.find(ch => ch._id == ws.id);
             if (!currentWs && ws.id > 0) {
-              box.add(Workspace({ i: ws.id}));
+              self.add(Workspace({ i: ws.id}));
             }
           });
-          box.show_all();
+          self.show_all();
 
           // Make sure the order is correct
-          box._workspaces.forEach((workspace, i) => {
+          self._workspaces.forEach((workspace, i) => {
             workspace.get_parent().reorder_child(workspace, i);
           });
         }],
       ],
-      connections: [[Hyprland, box => {
-        box._workspaces = box.children.filter(ch => {
+      connections: [[Hyprland, self => {
+        self._workspaces = self.children.filter(ch => {
           return Hyprland.workspaces.find(ws => ws.id == ch._id)
         }).sort((a, b) => a._id - b._id);
 
-        box._updateWs(box);
-        box._refresh(box);
+        self._updateWs(self);
+        self._refresh(self);
       }]],
     }),
   })],
diff --git a/hosts/wim/config/ags/js/date.js b/hosts/wim/config/ags/js/date.js
index af907674..3ac8fc2b 100644
--- a/hosts/wim/config/ags/js/date.js
+++ b/hosts/wim/config/ags/js/date.js
@@ -5,7 +5,7 @@ import Gtk from 'gi://Gtk';
 import GLib from 'gi://GLib';
 const { DateTime } = GLib;
 
-import { PopupWindow } from './misc/popup.js';
+import PopupWindow from './misc/popup.js';
 
 
 const Divider = () => Box({
@@ -27,8 +27,8 @@ const Time = () => Box({
         Label({
           className: 'content',
           label: 'hour',
-          connections: [[1000, label => {
-            label.label = DateTime.new_now_local().format('%H');
+          connections: [[1000, self => {
+            self.label = DateTime.new_now_local().format('%H');
           }]],
         }),
 
@@ -37,8 +37,8 @@ const Time = () => Box({
         Label({
           className: 'content',
           label: 'minute',
-          connections: [[1000, label => {
-            label.label = DateTime.new_now_local().format('%M');
+          connections: [[1000, self => {
+            self.label = DateTime.new_now_local().format('%M');
           }]],
         }),
 
@@ -51,9 +51,11 @@ const Time = () => Box({
       child: Label({
         style: 'font-size: 20px',
         label: 'complete date',
-        connections: [[1000, label => {
+        connections: [[1000, self => {
           var time = DateTime.new_now_local();
-          label.label = time.format("%A, %B ") + time.get_day_of_month()  + time.format(", %Y");
+          self.label = time.format("%A, %B ") +
+                       time.get_day_of_month() +
+                       time.format(", %Y");
         }]],
       }),
     }),
@@ -68,7 +70,6 @@ const CalendarWidget = () => Box({
     showDayNames: true,
     showHeading: true,
     className: 'cal',
-    connections: [/* */]
   }),
 });
 
diff --git a/hosts/wim/config/ags/js/media-player/gesture.js b/hosts/wim/config/ags/js/media-player/gesture.js
index 59d038ae..8cdc344a 100644
--- a/hosts/wim/config/ags/js/media-player/gesture.js
+++ b/hosts/wim/config/ags/js/media-player/gesture.js
@@ -8,12 +8,12 @@ const OFFSCREEN = 500;
 const TRANSITION = 'transition: margin 0.5s ease, opacity 3s ease;';
 
 
-export default ({ properties, connections, params } = {}) => {
+export default ({ properties, connections, props } = {}) => {
   let widget = EventBox();
   let gesture = Gtk.GestureDrag.new(widget)
 
   widget.child = Overlay({
-    ...params,
+    ...props,
     properties: [
       ...properties,
       ['dragging', false],
diff --git a/hosts/wim/config/ags/js/media-player/mpris.js b/hosts/wim/config/ags/js/media-player/mpris.js
index d5ee61b8..4943cbf7 100644
--- a/hosts/wim/config/ags/js/media-player/mpris.js
+++ b/hosts/wim/config/ags/js/media-player/mpris.js
@@ -5,8 +5,8 @@ const { execAsync, lookUpIcon } = Utils;
 import Gdk from 'gi://Gdk';
 const display = Gdk.Display.get_default();
 
-import { EventBox } from '../misc/cursorbox.js';
-import { Separator } from '../misc/separator.js';
+import Separator from '../misc/separator.js';
+import EventBox  from '../misc/cursorbox.js';
 
 const icons = {
   mpris: {
@@ -29,34 +29,35 @@ const icons = {
 }
 
 
-export const CoverArt = (player, params) => CenterBox({
-  ...params,
+export const CoverArt = (player, props) => CenterBox({
+  ...props,
   vertical: true,
   properties: [['bgStyle', '']],
-  connections: [
-    [player, box => {
-      execAsync(['bash', '-c', `[[ -f "${player.coverPath}" ]] && coloryou "${player.coverPath}" | grep -v Warning`])
+  connections: [[player, self => {
+    execAsync(['bash', '-c', `[[ -f "${player.coverPath}" ]] &&
+                  coloryou "${player.coverPath}" | grep -v Warning`])
       .then(out => {
         if (!Mpris.players.find(p => player === p))
           return;
 
         player.colors.value = JSON.parse(out);
 
-        box._bgStyle = `background: radial-gradient(circle,
-                                    rgba(0, 0, 0, 0.4) 30%,
-                                    ${player.colors.value.imageAccent}),
-                                    url("${player.coverPath}");
-                        background-size: cover;
-                        background-position: center;`;
-        if (!box.get_parent()._dragging)
-          box.setStyle(box._bgStyle);
-      }).catch(err => { if (err !== "") print(err) });
-    }],
-  ],
+        self._bgStyle = `background: radial-gradient(circle,
+                                     rgba(0, 0, 0, 0.4) 30%,
+                                     ${player.colors.value.imageAccent}),
+                                     url("${player.coverPath}");
+                         background-size: cover;
+                         background-position: center;`;
+
+        if (!self.get_parent()._dragging)
+          self.setStyle(self._bgStyle);
+
+      }).catch(err => {if (err !== "") print(err)});
+  }]],
 });
 
-export const TitleLabel = (player, params) => Label({
-  ...params,
+export const TitleLabel = (player, props) => Label({
+  ...props,
   xalign: 0,
   maxWidthChars: 40,
   truncate: 'end',
@@ -65,8 +66,8 @@ export const TitleLabel = (player, params) => Label({
   binds: [['label', player, 'track-title']],
 });
 
-export const ArtistLabel = (player, params) => Label({
-  ...params,
+export const ArtistLabel = (player, props) => Label({
+  ...props,
   xalign: 0,
   maxWidthChars: 40,
   truncate: 'end',
@@ -75,80 +76,83 @@ export const ArtistLabel = (player, params) => Label({
   binds: [['label', player, 'track-artists', a => a.join(', ') || '']],
 });
 
-export const PlayerIcon = (player, { symbolic = true, ...params } = {}) => {
+export const PlayerIcon = (player, { symbolic = true, ...props } = {}) => {
   let MainIcon = Icon({
-    ...params,
+    ...props,
     className: 'player-icon',
     size: 32,
     tooltipText: player.identity || '',
-    connections: [
-      [player, icon => {
-        const name = `${player.entry}${symbolic ? '-symbolic' : ''}`;
-        lookUpIcon(name) ? icon.icon = name
-          : icon.icon = icons.mpris.fallback;
-      }],
-    ],
+    connections: [[player, self => {
+      const name = `${player.entry}${symbolic ? '-symbolic' : ''}`;
+      lookUpIcon(name) ? self.icon = name
+                       : self.icon = icons.mpris.fallback;
+    }]],
   });
 
   return Box({
-    connections: [
-      [Mpris, box => {
-        let overlays = box.get_parent().get_parent().get_parent().list();
-        let player = overlays.find(overlay => overlay === box.get_parent().get_parent());
-        let index = overlays.indexOf(player)
+    connections: [[Mpris, self => {
+      let overlays = self.get_parent().get_parent()
+                          .get_parent().list();
 
-        let children = [];
-        for (let i = 0; i < overlays.length; ++i) {
-          if (i === index) {
-            children.push(MainIcon);
-            children.push(Separator(2));
-          }
-          else {
-            children.push(Box({ className: 'position-indicator' }));
-            children.push(Separator(2));
-          }
+      let player = overlays.find(overlay => {
+        overlay === self.get_parent().get_parent();
+      });
+
+      let index = overlays.indexOf(player);
+
+      let children = [];
+      for (let i = 0; i < overlays.length; ++i) {
+        if (i === index) {
+          children.push(MainIcon);
+          children.push(Separator(2));
         }
-        box.children = children;
-      }],
-    ],
+        else {
+          children.push(Box({className: 'position-indicator'}));
+          children.push(Separator(2));
+        }
+      }
+      self.children = children;
+    }]],
   });
 }
 
-export const PositionSlider = (player, params) => EventBox({
+// FIXME: get the cursors right or just don't display when disabled
+export const PositionSlider = (player, props) => EventBox({
   child: Slider({
-    ...params,
+    ...props,
     className: 'position-slider',
     hexpand: true,
     drawValue: false,
     onChange: ({ value }) => {
       player.position = player.length * value;
     },
-    properties: [
-      ['update', slider => {
-        if (slider.dragging) {
-          slider.get_parent().window.set_cursor(Gdk.Cursor.new_from_name(display, 'grabbing'));
+    properties: [['update', slider => {
+      if (slider.dragging) {
+        slider.get_parent().window.set_cursor(Gdk.Cursor
+          .new_from_name(display, 'grabbing'));
+      }
+      else {
+        if (slider.get_parent() && slider.get_parent().window) {
+          slider.get_parent().window.set_cursor(Gdk.Cursor
+            .new_from_name(display, 'pointer'));
         }
-        else {
-          if (slider.get_parent() && slider.get_parent().window) {
-            slider.get_parent().window.set_cursor(Gdk.Cursor.new_from_name(display, 'pointer'));
-          }
 
-          slider.sensitive = player.length > 0;
-          if (player.length > 0) {
-            slider.value = player.position / player.length;
-          }
+        slider.sensitive = player.length > 0;
+        if (player.length > 0) {
+          slider.value = player.position / player.length;
         }
-      }],
-    ],
+      }
+    }]],
     connections: [
       [player, s => s._update(s), 'position'],
       [1000, s => s._update(s)],
       [player.colors, s => {
-        if (player.colors.value)
-          s.setCss(`highlight { background-color: ${player.colors.value.buttonAccent}; }
-                    slider { background-color: ${player.colors.value.buttonAccent}; }
-                    slider:hover { background-color: ${player.colors.value.hoverAccent}; }
-                    trough { background-color: ${player.colors.value.buttonText}; }`);
+        let c = player.colors.value;
+        if (c)
+          s.setCss(`highlight { background-color: ${c.buttonAccent}; }
+                    slider { background-color: ${c.buttonAccent}; }
+                    slider:hover { background-color: ${c.hoverAccent}; }
+                    trough { background-color: ${c.buttonText}; }`);
       }],
     ],
   }),
@@ -162,9 +166,9 @@ function lengthStr(length) {
 }
 
 export const PositionLabel = player => Label({
-  properties: [['update', label => {
-    player.length > 0 ? label.label = lengthStr(player.position)
-                      : label.visible = !!player;
+  properties: [['update', self => {
+    player.length > 0 ? self.label = lengthStr(player.position)
+                      : self.visible = !!player;
   }]],
   connections: [
     [player, l => l._update(l), 'position'],
@@ -173,16 +177,16 @@ export const PositionLabel = player => Label({
 });
 
 export const LengthLabel = player => Label({
-  connections: [[player, label => {
-    player.length > 0 ? label.label = lengthStr(player.length)
-                      : label.visible = !!player;
+  connections: [[player, self => {
+    player.length > 0 ? self.label = lengthStr(player.length)
+                      : self.visible = !!player;
   }]],
 });
 
 export const Slash = player => Label({
   label: '/',
-  connections: [[player, label => {
-    label.visible = player.length > 0;
+  connections: [[player, self => {
+    self.visible = player.length > 0;
   }]],
 });
 
@@ -191,13 +195,13 @@ const PlayerButton = ({ player, items, onClick, prop }) => Button({
   child: Stack({ items }),
   onPrimaryClickRelease: () => player[onClick](),
   properties: [['hovered', false]],
-  onHover: box => {
-    box._hovered = true;
-    if (! box.child.sensitive || ! box.sensitive) {
-      box.window.set_cursor(Gdk.Cursor.new_from_name(display, 'not-allowed'));
+  onHover: self => {
+    self._hovered = true;
+    if (! self.child.sensitive || ! self.sensitive) {
+      self.window.set_cursor(Gdk.Cursor.new_from_name(display, 'not-allowed'));
     }
     else {
-      box.window.set_cursor(Gdk.Cursor.new_from_name(display, 'pointer'));
+      self.window.set_cursor(Gdk.Cursor.new_from_name(display, 'pointer'));
     }
 
     if (prop == 'playBackStatus') {
@@ -209,9 +213,9 @@ const PlayerButton = ({ player, items, onClick, prop }) => Button({
       });
     }
   },
-  onHoverLost: box => {
-    box._hovered = false;
-    box.window.set_cursor(null);
+  onHoverLost: self => {
+    self._hovered = false;
+    self.window.set_cursor(null);
     if (prop == 'playBackStatus') {
       items.forEach(item => {
         item[1].setStyle(`background-color: ${player.colors.value.buttonAccent};
diff --git a/hosts/wim/config/ags/js/media-player/player.js b/hosts/wim/config/ags/js/media-player/player.js
index 8ad8d8b2..c78e7153 100644
--- a/hosts/wim/config/ags/js/media-player/player.js
+++ b/hosts/wim/config/ags/js/media-player/player.js
@@ -1,9 +1,11 @@
 import { Mpris, Variable, Widget } from '../../imports.js';
 const { Box, CenterBox, Label } = Widget;
 
-import * as mpris from './mpris.js';
+import * as mpris    from './mpris.js';
 import PlayerGesture from './gesture.js';
-import { Separator } from '../misc/separator.js';
+import Separator     from '../misc/separator.js';
+
+const FAVE_PLAYER = 'org.mpris.MediaPlayer2.spotify';
 
 
 const Top = player => Box({
@@ -56,20 +58,22 @@ const Center = player => Box({
 const Bottom = player => Box({
   className: 'bottom',
   children: [
-
     mpris.PreviousButton(player, {
       valign: 'end',
       halign: 'start',
     }),
     Separator(8),
+
     mpris.PositionSlider(player),
     Separator(8),
+
     mpris.NextButton(player),
     Separator(8),
+
     mpris.ShuffleButton(player),
     Separator(8),
-    mpris.LoopButton(player),
 
+    mpris.LoopButton(player),
   ],
 });
 
@@ -98,10 +102,12 @@ export default () => Box({
 
         if (!busName) {
           let player = Mpris.players.find(p => !overlay._players.has(p.busName));
-          if (player)
+          if (player) {
             busName = player.busName;
-          else
+          }
+          else {
             return;
+          }
         }
 
         const player = Mpris.getPlayer(busName);
@@ -115,18 +121,20 @@ export default () => Box({
 
         overlay.overlays = result;
 
-        // Favor spotify
+        // Select favorite player at startup
         if (!overlay._setup) {
-          if (overlay._players.has('org.mpris.MediaPlayer2.spotify')) {
-            overlay._selected = overlay._players.get('org.mpris.MediaPlayer2.spotify');
+          if (overlay._players.has(FAVE_PLAYER)) {
+            overlay._selected = overlay._players.get(FAVE_PLAYER);
           }
           overlay._setup = true;
         }
 
         if (overlay._selected)
           overlay.reorder_overlay(overlay._selected, -1);
+
       }, 'player-added'],
 
+
       [Mpris, (overlay, busName) => {
         if (!busName || !overlay._players.has(busName))
           return;
@@ -141,6 +149,7 @@ export default () => Box({
         overlay.overlays = result;
         if (overlay._selected)
           overlay.reorder_overlay(overlay._selected, -1);
+
       }, 'player-closed'],
     ],
   }),
diff --git a/hosts/wim/config/ags/js/misc/closer.js b/hosts/wim/config/ags/js/misc/closer.js
index 3a913963..4db50d3e 100644
--- a/hosts/wim/config/ags/js/misc/closer.js
+++ b/hosts/wim/config/ags/js/misc/closer.js
@@ -21,7 +21,7 @@ const closeAll = () => {
   });
   App.closeWindow('closer');
 };
-globalThis.closeAll = () => closeAll();
+globalThis.closeAll = closeAll;
 
 Pointers.connect('new-line', (_, out) => {
   if (out) {
diff --git a/hosts/wim/config/ags/js/misc/cursorbox.js b/hosts/wim/config/ags/js/misc/cursorbox.js
index 540da80b..50129be2 100644
--- a/hosts/wim/config/ags/js/misc/cursorbox.js
+++ b/hosts/wim/config/ags/js/misc/cursorbox.js
@@ -4,34 +4,43 @@ import Gdk from 'gi://Gdk';
 const display = Gdk.Display.get_default();
 
 
-export const EventBox = ({ reset = true, ...params }) => Widget.EventBox({
-  ...params,
-  onHover: box => {
-    if (! box.child.sensitive || ! box.sensitive) {
-      box.window.set_cursor(Gdk.Cursor.new_from_name(display, 'not-allowed'));
-    }
-    else {
-      box.window.set_cursor(Gdk.Cursor.new_from_name(display, 'pointer'));
-    }
-  },
-  onHoverLost: box => {
-    if (reset)
-      box.window.set_cursor(null);
-  },
-});
-
-export const Button = ({ reset = true, ...params }) => Widget.Button({
-  ...params,
-  onHover: box => {
-    if (! box.child.sensitive || ! box.sensitive) {
-      box.window.set_cursor(Gdk.Cursor.new_from_name(display, 'not-allowed'));
-    }
-    else {
-      box.window.set_cursor(Gdk.Cursor.new_from_name(display, 'pointer'));
-    }
-  },
-  onHoverLost: box => {
-    if (reset)
-      box.window.set_cursor(null);
-  },
-});
+export default ({
+  type = "EventBox",
+  reset = true,
+  ...props
+}) => {
+  if (type === "EventBox") {
+    return Widget.EventBox({
+      ...props,
+      onHover: self => {
+        if (!self.child.sensitive || !self.sensitive) {
+          self.window.set_cursor(Gdk.Cursor.new_from_name(display, 'not-allowed'));
+        }
+        else {
+          self.window.set_cursor(Gdk.Cursor.new_from_name(display, 'pointer'));
+        }
+      },
+      onHoverLost: self => {
+        if (reset)
+          self.window.set_cursor(null);
+      },
+    });
+  }
+  else {
+    return Widget.Button({
+      ...props,
+      onHover: self => {
+        if (!self.child.sensitive || !self.sensitive) {
+          self.window.set_cursor(Gdk.Cursor.new_from_name(display, 'not-allowed'));
+        }
+        else {
+          self.window.set_cursor(Gdk.Cursor.new_from_name(display, 'pointer'));
+        }
+      },
+      onHoverLost: self => {
+        if (reset)
+          self.window.set_cursor(null);
+      },
+    });
+  }
+}
diff --git a/hosts/wim/config/ags/js/misc/popup.js b/hosts/wim/config/ags/js/misc/popup.js
index 2cda285c..72b5ca23 100644
--- a/hosts/wim/config/ags/js/misc/popup.js
+++ b/hosts/wim/config/ags/js/misc/popup.js
@@ -2,32 +2,38 @@ import { App, Widget } from '../../imports.js';
 const { Revealer, Box, Window } = Widget;
 
 
-export const PopupWindow = ({
+export default ({
   name,
   child,
   transition = 'slide_down',
-  ...params
-}) => Window({
-  name,
-  popup: true,
-  visible: false,
-  layer: 'overlay',
-  ...params,
+  onOpen = rev => {},
+  ...props
+}) => {
+  let window = Window({
+    name,
+    popup: true,
+    visible: false,
+    layer: 'overlay',
+    ...props,
 
-  child: Box({
-    style: 'min-height:1px; min-width:1px',
-    child: Revealer({
-      transition,
-      transitionDuration: 500,
-      connections: [[App, (revealer, currentName, visible) => {
-        if (currentName === name) {
-          revealer.reveal_child = visible;
+    child: Box({
+      style: 'min-height:1px; min-width:1px',
+      child: Revealer({
+        transition,
+        transitionDuration: 500,
+        connections: [[App, (rev, currentName, visible) => {
+          if (currentName === name) {
+            rev.reveal_child = visible;
+            onOpen(child);
 
-          if (visible && name !== 'overview')
-            App.openWindow('closer');
-        }
-      }]],
-      child: child,
+            if (visible && name !== 'overview')
+              App.openWindow('closer');
+          }
+        }]],
+        child: child,
+      }),
     }),
-  }),
-});
+  });
+  window.getChild = () => child;
+  return window;
+}
diff --git a/hosts/wim/config/ags/js/misc/separator.js b/hosts/wim/config/ags/js/misc/separator.js
index f8484d6d..5e9e1479 100644
--- a/hosts/wim/config/ags/js/misc/separator.js
+++ b/hosts/wim/config/ags/js/misc/separator.js
@@ -2,6 +2,15 @@ import { Widget } from '../../imports.js';
 const { Box } = Widget;
 
 
-export const Separator = width => Box({
-  style: `min-width: ${width}px;`,
-});
+export default (size, { vertical = false } = {}) => {
+  if (vertical)  {
+    return Box({
+      style: `min-height: ${size}px;`,
+    });
+  }
+  else {
+    return Box({
+      style: `min-width: ${size}px;`,
+    });
+  }
+}
diff --git a/hosts/wim/config/ags/js/notifications/base.js b/hosts/wim/config/ags/js/notifications/base.js
index 3a1bebbb..8f00a5f4 100644
--- a/hosts/wim/config/ags/js/notifications/base.js
+++ b/hosts/wim/config/ags/js/notifications/base.js
@@ -4,8 +4,17 @@ const { Box, Icon, Label, Button } = Widget;
 
 import GLib from 'gi://GLib';
 
+const setTime = time => {
+  return GLib.DateTime
+    .new_from_unix_local(time)
+    .format('%H:%M');
+};
+
+const getDragState = box => box.get_parent().get_parent()
+  .get_parent().get_parent().get_parent()._dragging;
+
 import Gesture from './gesture.js';
-import { EventBox } from '../misc/cursorbox.js'
+import EventBox from '../misc/cursorbox.js'
 
 
 const NotificationIcon = notif => {
@@ -14,19 +23,19 @@ const NotificationIcon = notif => {
   if (Applications.query(notif.appEntry).length > 0) {
     let app = Applications.query(notif.appEntry)[0];
 
-    if (app.app.get_string('StartupWMClass') != null) {
+    let wmClass = app.app.get_string('StartupWMClass');
+    if (app.app.get_filename().includes('discord'))
+      wmClass = 'discord';
+
+    if (wmClass != null) {
       iconCmd = box => {
-        if (!box.get_parent().get_parent().get_parent().get_parent().get_parent()._dragging) {
-          execAsync(['bash', '-c', `$AGS_PATH/launch-app.sh ${app.app.get_string('StartupWMClass')} ${app.app.get_string('Exec')}`]).catch(print);
-          globalThis.closeAll();
-        }
-      }
-    }
-    else if (app.app.get_filename().includes('discord')) {
-      iconCmd = box => {
-        if (!box.get_parent().get_parent().get_parent().get_parent().get_parent()._dragging) {
-          execAsync(['bash', '-c', `$AGS_PATH/launch-app.sh discord ${app.app.get_string('Exec')}`])
-            .catch(print);
+        if (!getDragState(box)) {
+          execAsync(['bash', '-c',
+            `$AGS_PATH/launch-app.sh
+              ${wmClass}
+              ${app.app.get_string('Exec')}`
+          ]).catch(print);
+
           globalThis.closeAll();
         }
       }
@@ -82,7 +91,7 @@ const NotificationIcon = notif => {
   });
 };
 
-export default ({ notif, command = () => {}} = {}) => {
+export default ({ notif, command = () => {}, } = {}) => {
   const BlockedApps = [
     'Spotify',
   ];
@@ -142,7 +151,7 @@ export default ({ notif, command = () => {}} = {}) => {
                       Label({
                         className: 'time',
                         valign: 'start',
-                        label: GLib.DateTime.new_from_unix_local(notif.time).format('%H:%M'),
+                        label: setTime(notif.time),
                       }),
                       EventBox({
                         reset: false,
diff --git a/hosts/wim/config/ags/js/notifications/center.js b/hosts/wim/config/ags/js/notifications/center.js
index c513c5a4..95df553a 100644
--- a/hosts/wim/config/ags/js/notifications/center.js
+++ b/hosts/wim/config/ags/js/notifications/center.js
@@ -3,23 +3,30 @@ const { Button, Label, Box, Icon, Scrollable, Revealer } = Widget;
 const { timeout } = Utils;
 
 import Notification from './base.js';
-import { EventBox } from '../misc/cursorbox.js';
-import { PopupWindow } from '../misc/popup.js';
+import PopupWindow  from '../misc/popup.js';
+import EventBox     from '../misc/cursorbox.js';
 
 
 const ClearButton = () => EventBox({
   child: Button({
     onPrimaryClickRelease: button => {
-      button._popups.children.forEach(ch => ch.child.setStyle(ch.child._leftAnim1));
+      button._popups.children.forEach(ch => {
+        ch.child.setStyle(ch.child._leftAnim1);
+      });
+
       button._notifList.children.forEach(ch => {
-        ch.child.setStyle(ch.child._rightAnim1);
+        if (ch.child)
+          ch.child.setStyle(ch.child._rightAnim1);
         timeout(500, () => {
           button._notifList.remove(ch);
-          Notifications.notifications.forEach(n => n.close());
+          Notifications.clear();
         });
       });
     },
-    properties: [['notifList'], ['popups']],
+    properties: [
+      ['notifList'],
+      ['popups'],
+    ],
     connections: [[Notifications, button => {
       if (!button._notifList)
         button._notifList = NotificationList;
@@ -33,8 +40,8 @@ const ClearButton = () => EventBox({
       children: [
         Label('Clear '),
         Icon({
-          connections: [[Notifications, icon => {
-            icon.icon = Notifications.notifications.length > 0
+          connections: [[Notifications, self => {
+            self.icon = Notifications.notifications.length > 0
                       ? 'user-trash-full-symbolic' : 'user-trash-symbolic';
           }]],
         }),
@@ -46,7 +53,11 @@ const ClearButton = () => EventBox({
 const Header = () => Box({
   className: 'header',
   children: [
-    Label({ label: 'Notifications', hexpand: true, xalign: 0 }),
+    Label({
+      label: 'Notifications',
+      hexpand: true,
+      xalign: 0,
+    }),
     ClearButton(),
   ],
 });
@@ -110,26 +121,28 @@ const Placeholder = () => Revealer({
   }),
 });
 
-const NotificationCenterWidget = Box({
+const NotificationCenterWidget = () => Box({
   className: 'notification-center',
   vertical: true,
   children: [
     Header(),
     Box({
       className: 'notification-wallpaper-box',
-      children: [Scrollable({
-        className: 'notification-list-box',
-        hscroll: 'never',
-        vscroll: 'automatic',
-        child: Box({
-          className: 'notification-list',
-          vertical: true,
-          children: [
-            NotificationList,
-            Placeholder(),
-          ],
-        }),
-      })],
+      children: [
+        Scrollable({
+          className: 'notification-list-box',
+          hscroll: 'never',
+          vscroll: 'automatic',
+          child: Box({
+            className: 'notification-list',
+            vertical: true,
+            children: [
+              NotificationList,
+              Placeholder(),
+            ],
+          }),
+        })
+      ],
     }),
   ],
 });
@@ -138,5 +151,5 @@ export default () => PopupWindow({
   name: 'notification-center',
   anchor: [ 'top', 'right' ],
   margin: [ 8, 60, 0, 0 ],
-  child: NotificationCenterWidget,
+  child: NotificationCenterWidget(),
 });
diff --git a/hosts/wim/config/ags/js/notifications/gesture.js b/hosts/wim/config/ags/js/notifications/gesture.js
index 2f9f035f..45b957be 100644
--- a/hosts/wim/config/ags/js/notifications/gesture.js
+++ b/hosts/wim/config/ags/js/notifications/gesture.js
@@ -16,25 +16,25 @@ export default ({
   child = '',
   children = [],
   properties = [[]],
-  ...params
+  ...props
 }) => {
-  let w = EventBox({
-    ...params,
+  let widget = EventBox({
+    ...props,
     properties: [
       ['dragging', false],
       ...properties,
     ],
-    onHover: box => {
-      box.window.set_cursor(Gdk.Cursor.new_from_name(display, 'grab'));
-      onHover(box);
+    onHover: self => {
+      self.window.set_cursor(Gdk.Cursor.new_from_name(display, 'grab'));
+      onHover(self);
     },
-    onHoverLost: box => {
-      box.window.set_cursor(null);
-      onHoverLost(box);
+    onHoverLost: self => {
+      self.window.set_cursor(null);
+      onHoverLost(self);
     },
   });
 
-  let gesture = Gtk.GestureDrag.new(w);
+  let gesture = Gtk.GestureDrag.new(widget);
 
   let leftAnim1 = `transition: margin 0.5s ease, opacity 0.5s ease;
                    margin-left: -${Number(maxOffset + endMargin)}px;
@@ -56,10 +56,10 @@ export default ({
                     margin-right: -${Number(maxOffset + endMargin)}px;
                     margin-bottom: -70px; margin-top: -70px; opacity: 0;`;
 
-  w.child = Box({
+  widget.child = Box({
     properties: [
-      ['leftAnim1', leftAnim1],
-      ['leftAnim2', leftAnim2],
+      ['leftAnim1',  leftAnim1],
+      ['leftAnim2',  leftAnim2],
       ['rightAnim1', rightAnim1],
       ['rightAnim2', rightAnim2],
       ['ready', false]
@@ -71,39 +71,39 @@ export default ({
     style: leftAnim2,
     connections: [
 
-      [gesture, box => {
+      [gesture, self => {
         var offset = gesture.get_offset()[1];
 
         if (offset >= 0) {
-          box.setStyle('margin-left: ' + Number(offset + startMargin) + 'px; ' +
-                       'margin-right: -' + Number(offset + startMargin) + 'px;');
+          self.setStyle(`margin-left:   ${Number(offset + startMargin)}px;
+                         margin-right: -${Number(offset + startMargin)}px;`);
         }
         else {
           offset = Math.abs(offset);
-          box.setStyle('margin-right: ' + Number(offset + startMargin) + 'px; ' +
-                       'margin-left: -' + Number(offset + startMargin) + 'px;');
+          self.setStyle(`margin-right: ${Number(offset + startMargin)}px;
+                         margin-left: -${Number(offset + startMargin)}px;`);
         }
 
-        box.get_parent()._dragging = Math.abs(offset) > 10;
+        self.get_parent()._dragging = Math.abs(offset) > 10;
 
-        if (w.window)
-          w.window.set_cursor(Gdk.Cursor.new_from_name(display, 'grabbing'));
+        if (widget.window)
+          widget.window.set_cursor(Gdk.Cursor.new_from_name(display, 'grabbing'));
       }, 'drag-update'],
 
-      [gesture, box => {
-        if (!box._ready) {
-          box.setStyle(`transition: margin 0.5s ease, opacity 0.5s ease;
-                        margin-left: -${Number(maxOffset + endMargin)}px;
-                        margin-right: ${Number(maxOffset + endMargin)}px;
-                        margin-bottom: 0px; margin-top: 0px; opacity: 0;`);
+      [gesture, self => {
+        if (!self._ready) {
+          self.setStyle(`transition: margin 0.5s ease, opacity 0.5s ease;
+                         margin-left: -${Number(maxOffset + endMargin)}px;
+                         margin-right: ${Number(maxOffset + endMargin)}px;
+                         margin-bottom: 0px; margin-top: 0px; opacity: 0;`);
 
           setTimeout(() => {
-            box.setStyle('transition: margin 0.5s ease, opacity 0.5s ease; ' +
-                         'margin-left: ' + startMargin + 'px; ' +
-                         'margin-right: ' + startMargin + 'px; ' +
-                         'margin-bottom: unset; margin-top: unset; opacity: 1;');
+            self.setStyle(`transition: margin 0.5s ease, opacity 0.5s ease;
+                           margin-left:  ${startMargin}px;
+                           margin-right: ${startMargin}px;
+                           margin-bottom: unset; margin-top: unset; opacity: 1;`);
           }, 500);
-          setTimeout(() => box._ready = true, 1000);
+          setTimeout(() => self._ready = true, 1000);
           return;
         }
 
@@ -111,32 +111,32 @@ export default ({
 
         if (Math.abs(offset) > maxOffset) {
           if (offset > 0) {
-            box.setStyle(rightAnim1);
-            setTimeout(() => box.setStyle(rightAnim2), 500);
+            self.setStyle(rightAnim1);
+            setTimeout(() => self.setStyle(rightAnim2), 500);
           }
           else {
-            box.setStyle(leftAnim1);
-            setTimeout(() => box.setStyle(leftAnim2), 500);
+            self.setStyle(leftAnim1);
+            setTimeout(() => self.setStyle(leftAnim2), 500);
           }
           setTimeout(() => {
             command();
-            box.destroy();
+            self.destroy();
           }, 1000);
         }
         else {
-          box.setStyle('transition: margin 0.5s ease, opacity 0.5s ease; ' +
-                       'margin-left: ' + startMargin + 'px; ' +
-                       'margin-right: ' + startMargin + 'px; ' +
-                       'margin-bottom: unset; margin-top: unset; opacity: 1;');
-          if (w.window)
-            w.window.set_cursor(Gdk.Cursor.new_from_name(display, 'grab'));
+          self.setStyle(`transition: margin 0.5s ease, opacity 0.5s ease;
+                         margin-left:  ${startMargin}px;
+                         margin-right: ${startMargin}px;
+                         margin-bottom: unset; margin-top: unset; opacity: 1;`);
+          if (widget.window)
+            widget.window.set_cursor(Gdk.Cursor.new_from_name(display, 'grab'));
 
-          box.get_parent()._dragging = false;
+          self.get_parent()._dragging = false;
         }
       }, 'drag-end'],
 
     ],
   });
 
-  return w;
+  return widget;
 };
diff --git a/hosts/wim/config/ags/js/notifications/popup.js b/hosts/wim/config/ags/js/notifications/popup.js
index 0abe15ed..3588ee18 100644
--- a/hosts/wim/config/ags/js/notifications/popup.js
+++ b/hosts/wim/config/ags/js/notifications/popup.js
@@ -8,12 +8,13 @@ const Popups = () => Box({
   vertical: true,
   properties: [
     ['map', new Map()],
-    ['dismiss', (box, id, force = false) => {
-      if (!id || !box._map.has(id))
-        return;
 
-      if (box._map.get(id)._hovered && !force)
+    ['dismiss', (box, id, force = false) => {
+      if (!id || !box._map.has(id) ||
+          box._map.get(id)._hovered && !force) {
+
         return;
+      }
 
       if (box._map.size - 1 === 0)
         box.get_parent().reveal_child = false;
@@ -27,6 +28,7 @@ const Popups = () => Box({
         box._map.delete(id);
       }, 200);
     }],
+
     ['notify', (box, id) => {
       if (!id || Notifications.dnd)
         return;
@@ -43,11 +45,12 @@ const Popups = () => Box({
       }));
 
       box.children = Array.from(box._map.values()).reverse();
+
       setTimeout(() => {
           box.get_parent().revealChild = true;
       }, 10);
+
       box._map.get(id).interval = setInterval(() => {
-        print('interval')
         if (!box._map.get(id)._hovered) {
           box._map.get(id).child.setStyle(box._map.get(id).child._leftAnim1);
 
diff --git a/hosts/wim/config/ags/js/overview/clients.js b/hosts/wim/config/ags/js/overview/clients.js
index 9a5efff2..3da2cfc4 100644
--- a/hosts/wim/config/ags/js/overview/clients.js
+++ b/hosts/wim/config/ags/js/overview/clients.js
@@ -5,10 +5,12 @@ const { execAsync } = Utils;
 import { WindowButton } from './dragndrop.js';
 import * as VARS from './variables.js';
 
+// Has to be a traditional function for 'this' scope
 Array.prototype.remove = function (el) { this.splice(this.indexOf(el), 1) };
 
 const scale = size => size * VARS.SCALE - VARS.MARGIN;
-const getFontSize = client => Math.min(scale(client.size[0]), scale(client.size[1])) * VARS.ICON_SCALE;
+const getFontSize = client => Math.min(scale(client.size[0]),
+  scale(client.size[1])) * VARS.ICON_SCALE;
 
 const IconStyle = client => `transition: font-size 0.2s linear;
                              min-width:  ${scale(client.size[0])}px;
@@ -31,14 +33,22 @@ const Client = (client, active, clients) => {
     ],
     child: WindowButton({
       address: client.address,
-      onSecondaryClickRelease: () => execAsync(`hyprctl dispatch closewindow ${addr}`).catch(print),
+      onSecondaryClickRelease: () => {
+        execAsync(`hyprctl dispatch closewindow ${addr}`)
+          .catch(print);
+      },
+
       onPrimaryClickRelease: () => {
         if (wsId < 0) {
           if (client.workspace.name === 'special') {
-            execAsync(`hyprctl dispatch movetoworkspacesilent special:${wsId},${addr}`).then(
+            execAsync(`hyprctl dispatch
+              movetoworkspacesilent special:${wsId},${addr}`)
+            .then(
+
               execAsync(`hyprctl dispatch togglespecialworkspace ${wsId}`).then(
                 () => App.closeWindow('overview')
               ).catch(print)
+
             ).catch(print);
           }
           else {
@@ -53,13 +63,15 @@ const Client = (client, active, clients) => {
           let currentActive = clients.find(c => c.address === activeAddress)
 
           if (currentActive && currentActive.workspace.id < 0) {
-            execAsync(`hyprctl dispatch togglespecialworkspace ${wsName}`).catch(print);
+            execAsync(`hyprctl dispatch togglespecialworkspace ${wsName}`)
+              .catch(print);
           }
           execAsync(`hyprctl dispatch focuswindow ${addr}`).then(
             () => App.closeWindow('overview')
           ).catch(print);
         }
       },
+
       child: Icon({
         className: `window ${active}`,
         style: IconStyle(client) + 'font-size: 10px;',
@@ -70,15 +82,15 @@ const Client = (client, active, clients) => {
 };
 
 export function updateClients(box) {
-  execAsync('hyprctl clients -j').then(
-  result => {
-    let clients = JSON.parse(result).filter(client => client.class)
+  execAsync('hyprctl clients -j').then(out => {
+    let clients = JSON.parse(out).filter(client => client.class)
 
     box._workspaces.forEach(workspace => {
-      let fixed = workspace.child.child.get_children()[2].children[0];
+      let fixed = workspace.getFixed();
       let toRemove = fixed.get_children();
 
-      clients.filter(client => client.workspace.id == workspace._id).forEach(client => {
+      clients.filter(client => client.workspace.id == workspace._id)
+      .forEach(client => {
         let active = '';
         if (client.address == Hyprland.active.client.address) {
           active = 'active';
diff --git a/hosts/wim/config/ags/js/overview/dragndrop.js b/hosts/wim/config/ags/js/overview/dragndrop.js
index 47f37b92..5f89e6ae 100644
--- a/hosts/wim/config/ags/js/overview/dragndrop.js
+++ b/hosts/wim/config/ags/js/overview/dragndrop.js
@@ -6,7 +6,7 @@ import Gtk from 'gi://Gtk';
 import Gdk from 'gi://Gdk';
 import Cairo from 'cairo';
 
-import { Button } from '../misc/cursorbox.js';
+import Button from '../misc/cursorbox.js';
 import { updateClients } from './clients.js';
 
 const TARGET = [Gtk.TargetEntry.new('text/plain', Gtk.TargetFlags.SAME_APP, 0)];
@@ -29,13 +29,13 @@ function createSurfaceFromWidget(widget) {
 };
 
 let hidden = 0;
-export const WorkspaceDrop = params => EventBox({
-  ...params,
-  connections: [['drag-data-received', (eventbox, _c, _x, _y, data) => {
-    let id = eventbox.get_parent()._id;
+export const WorkspaceDrop = props => EventBox({
+  ...props,
+  connections: [['drag-data-received', (self, _c, _x, _y, data) => {
+    let id = self.get_parent()._id;
 
     if (id < -1) {
-      id = eventbox.get_parent()._name;
+      id = self.get_parent()._name;
     }
     else if (id === -1) {
       id = `special:${++hidden}`;
@@ -46,26 +46,27 @@ export const WorkspaceDrop = params => EventBox({
     execAsync(`hyprctl dispatch movetoworkspacesilent ${id},address:${data.get_text()}`)
       .catch(print);
   }]],
-  setup: eventbox => {
-    eventbox.drag_dest_set(Gtk.DestDefaults.ALL, TARGET, Gdk.DragAction.COPY);
+  setup: self => {
+    self.drag_dest_set(Gtk.DestDefaults.ALL, TARGET, Gdk.DragAction.COPY);
   },
 });
 
-export const WindowButton = ({address, ...params} = {}) => Button({
-  ...params,
-  setup: button => {
-    button.drag_source_set(Gdk.ModifierType.BUTTON1_MASK, TARGET, Gdk.DragAction.COPY);
-    button.connect('drag-data-get', (_w, _c, data) => {
+export const WindowButton = ({address, ...props} = {}) => Button({
+  type: "Button",
+  ...props,
+  setup: self => {
+    self.drag_source_set(Gdk.ModifierType.BUTTON1_MASK, TARGET, Gdk.DragAction.COPY);
+    self.connect('drag-data-get', (_w, _c, data) => {
       data.set_text(address, address.length);
     });
-    button.connect('drag-begin', (_, context) => {
-      Gtk.drag_set_icon_surface(context, createSurfaceFromWidget(button));
-      button.get_parent().revealChild = false;
+    self.connect('drag-begin', (_, context) => {
+      Gtk.drag_set_icon_surface(context, createSurfaceFromWidget(self));
+      self.get_parent().revealChild = false;
     });
-    button.connect('drag-end', () => {
-      button.get_parent().destroy();
+    self.connect('drag-end', () => {
+      self.get_parent().destroy();
 
-      let mainBox = App.getWindow('overview').child.children[0].child;
+      let mainBox = App.getWindow('overview').getChild();
       updateClients(mainBox);
     });
   },
diff --git a/hosts/wim/config/ags/js/overview/main.js b/hosts/wim/config/ags/js/overview/main.js
index a2bb2ba3..7402a9b4 100644
--- a/hosts/wim/config/ags/js/overview/main.js
+++ b/hosts/wim/config/ags/js/overview/main.js
@@ -1,10 +1,11 @@
 import { App, Hyprland, Widget } from '../../imports.js';
 const { Box } = Widget;
 
-import { PopupWindow } from '../misc/popup.js';
+import PopupWindow from '../misc/popup.js';
 import { WorkspaceRow, getWorkspaces, updateWorkspaces } from './workspaces.js';
 import { updateClients } from './clients.js';
 
+
 function update(box) {
   getWorkspaces(box);
   updateWorkspaces(box);
@@ -14,6 +15,7 @@ function update(box) {
 export default () => PopupWindow({
   name: 'overview',
   transition: 'crossfade',
+  onOpen: child => update(child),
 
   child: Box({
     className: 'overview',
@@ -32,17 +34,12 @@ export default () => PopupWindow({
         ],
       }),
     ],
-    // The timeout is because the list of clients is async
-    setup: box => setTimeout(() => update(box), 100),
-    connections: [
-      [Hyprland, box => {
-        if (!App.getWindow('overview').visible)
-          return;
+    connections: [[Hyprland, self => {
+      if (!App.getWindow('overview').visible)
+        return;
 
-        print('running overview');
-        update(box);
-      }],
-    ],
+      update(self);
+    }]],
     properties: [
       ['workspaces'],
     ],
diff --git a/hosts/wim/config/ags/js/overview/workspaces.js b/hosts/wim/config/ags/js/overview/workspaces.js
index bf85c530..3adde232 100644
--- a/hosts/wim/config/ags/js/overview/workspaces.js
+++ b/hosts/wim/config/ags/js/overview/workspaces.js
@@ -6,7 +6,7 @@ import Gtk from 'gi://Gtk';
 import { WorkspaceDrop } from './dragndrop.js';
 import * as VARS from './variables.js';
 
-const DEFAULT_STYLE = `min-width: ${VARS.SCREEN.X * VARS.SCALE}px;
+const DEFAULT_STYLE = `min-width:  ${VARS.SCREEN.X * VARS.SCALE}px;
                        min-height: ${VARS.SCREEN.Y * VARS.SCALE}px;`;
 
 
@@ -48,126 +48,140 @@ export const WorkspaceRow = (className, i) => Revealer({
       child: Box({
         className: className,
         children: [
-          Revealer({
-            transition: 'slide_right',
-            properties: [
-              ['id', className === 'special' ? -1 : 1000],
-              ['name', className === 'special' ? 'special' : ''],
-            ],
-            child: WorkspaceDrop({
-              child: Overlay({
-                child: Box({
-                  className: 'workspace',
-                    style: DEFAULT_STYLE,
-                }),
-                overlays: [
-                  Box({
-                    className: 'workspace active',
-                    style: `${DEFAULT_STYLE} opacity: 0;`,
-                  }),
-                  Box({
-                    style: DEFAULT_STYLE,
-                    children: [
-                      Widget({
-                        type: Gtk.Fixed,
-                      }),
-                      Label({
-                        label: '   +',
-                        style: 'font-size: 40px;',
-                      }),
-                    ],
-                  })
-                ],
-              }),
-            }),
-          }),
+          Workspace(className === 'special' ? -1 : 1000,
+                    className === 'special' ? 'special' : '',
+                    true),
         ],
       }),
     }), null],
   }),
 });
 
-const Workspace = (id, name) => Revealer({
-  transition: 'slide_right',
-  transitionDuration: 500,
-  properties: [
-    ['id', id],
-    ['name', name],
-    ['timeouts', []],
-    ['wasActive', false],
-  ],
-  connections: [[Hyprland, box => {
-    box._timeouts.forEach(timer => timer.destroy());
+// TODO: please make this readable for the love of god
+const Workspace = (id, name, extra = false) => {
+  let workspace;
+  let fixed = Widget({
+    type: Gtk.Fixed,
+  });
 
-    let activeId = Hyprland.active.workspace.id;
-    let active = activeId === box._id;
+  if (!extra) {
+    workspace = Revealer({
+      transition: 'slide_right',
+      transitionDuration: 500,
+      properties: [
+        ['id', id],
+        ['name', name],
+        ['timeouts', []],
+        ['wasActive', false],
+      ],
+      connections: [[Hyprland, box => {
+        box._timeouts.forEach(timer => timer.destroy());
 
-    let rev = box.child.child.get_children()[1];
-    let n = activeId > box._id;
+        let activeId = Hyprland.active.workspace.id;
+        let active = activeId === box._id;
 
-    if (Hyprland.getWorkspace(box._id)?.windows > 0 || active) {
-      rev.setStyle(DEFAULT_STYLE);
-      box._timeouts.push(setTimeout(() => {
-        box.revealChild = true;
-      }, 100));
+        let rev = box.child.child.get_children()[1];
+        let n = activeId > box._id;
 
-    }
-    else if (!Hyprland.getWorkspace(box._id)?.windows > 0) {
-      rev.setStyle(DEFAULT_STYLE);
-      box._timeouts.push(setTimeout(() => {
-        box.revealChild = false;
-      }, 100));
-      return;
-    }
+        if (Hyprland.getWorkspace(box._id)?.windows > 0 || active) {
+          rev.setStyle(DEFAULT_STYLE);
+          box._timeouts.push(setTimeout(() => {
+            box.revealChild = true;
+          }, 100));
 
-    if (active) {
-      rev.setStyle(`${DEFAULT_STYLE}
+        }
+        else if (!Hyprland.getWorkspace(box._id)?.windows > 0) {
+          rev.setStyle(DEFAULT_STYLE);
+          box._timeouts.push(setTimeout(() => {
+            box.revealChild = false;
+          }, 100));
+          return;
+        }
+
+        if (active) {
+          rev.setStyle(`${DEFAULT_STYLE}
                     transition: margin 0.5s ease-in-out;
                     opacity: 1;`);
-      box._wasActive = true;
-    }
-    else if (box._wasActive) {
-      box._timeouts.push(setTimeout(() => {
-        rev.setStyle(`${DEFAULT_STYLE}
+          box._wasActive = true;
+        }
+        else if (box._wasActive) {
+          box._timeouts.push(setTimeout(() => {
+            rev.setStyle(`${DEFAULT_STYLE}
                   transition: margin 0.5s ease-in-out;
                   opacity: 1; margin-left: ${n ? '' : '-'}300px;
                               margin-right: ${n ? '-' : ''}300px;`);
-        box._wasActive = false;
-      }, 120));
-      box._timeouts.push(setTimeout(() => {
-        rev.setStyle(`${DEFAULT_STYLE} opacity: 0;
+            box._wasActive = false;
+          }, 120));
+          box._timeouts.push(setTimeout(() => {
+            rev.setStyle(`${DEFAULT_STYLE} opacity: 0;
                       margin-left: ${n ? '' : '-'}300px;
                       margin-right: ${n ? '-' : ''}300px;`);
-      }, 500));
-    }
-    else {
-      rev.setStyle(`${DEFAULT_STYLE} opacity: 0;
+          }, 500));
+        }
+        else {
+          rev.setStyle(`${DEFAULT_STYLE} opacity: 0;
                     margin-left: ${n ? '' : '-'}300px;
                     margin-right: ${n ? '-' : ''}300px;`);
-    }
-  }]],
-  child: WorkspaceDrop({
-    child: Overlay({
-      child: Box({
-        className: 'workspace active',
-        style: `${DEFAULT_STYLE} opacity: 0;`,
-      }),
-      overlays: [
-        Box({
-          className: 'workspace active',
-          style: `${DEFAULT_STYLE} opacity: 0;`,
-        }),
-        Box({
-          className: 'workspace',
-          style: DEFAULT_STYLE,
-          child: Widget({
-            type: Gtk.Fixed,
+        }
+      }]],
+      child: WorkspaceDrop({
+        child: Overlay({
+          child: Box({
+            className: 'workspace active',
+            style: `${DEFAULT_STYLE} opacity: 0;`,
           }),
-        })
+          overlays: [
+            Box({
+              className: 'workspace active',
+              style: `${DEFAULT_STYLE} opacity: 0;`,
+            }),
+            Box({
+              className: 'workspace',
+              style: DEFAULT_STYLE,
+              child: fixed,
+            })
+          ],
+        }),
+      }),
+    });
+  }
+  else {
+    workspace = Revealer({
+      transition: 'slide_right',
+      properties: [
+        ['id', id],
+        ['name', name],
       ],
-    }),
-  }),
-});
+      child: WorkspaceDrop({
+        child: Overlay({
+          child: Box({
+            className: 'workspace',
+            style: DEFAULT_STYLE,
+          }),
+          overlays: [
+            Box({
+              className: 'workspace active',
+              style: `${DEFAULT_STYLE} opacity: 0;`,
+            }),
+            Box({
+              style: DEFAULT_STYLE,
+              children: [
+                fixed,
+                Label({
+                  label: '   +',
+                  style: 'font-size: 40px;',
+                }),
+              ],
+            })
+          ],
+        }),
+      }),
+    });
+  }
+
+  workspace.getFixed = () => fixed;
+  return workspace;
+};
 
 export function updateWorkspaces(box) {
   Hyprland.workspaces.forEach(ws => {
diff --git a/hosts/wim/config/ags/js/powermenu.js b/hosts/wim/config/ags/js/powermenu.js
index 48c66ab2..5381e904 100644
--- a/hosts/wim/config/ags/js/powermenu.js
+++ b/hosts/wim/config/ags/js/powermenu.js
@@ -1,15 +1,16 @@
 import { Widget } from '../imports.js';
 const { CenterBox, Label } = Widget;
 
-import { PopupWindow } from './misc/popup.js';
-import { Button } from './misc/cursorbox.js'
+import PopupWindow from './misc/popup.js';
+import Button      from './misc/cursorbox.js'
 
 
-const PowermenuWidget = CenterBox({
+const PowermenuWidget = () => CenterBox({
   className: 'powermenu',
   vertical: false,
 
   startWidget: Button({
+    type: "Button",
     className: 'shutdown',
     onPrimaryClickRelease: 'systemctl poweroff',
 
@@ -19,6 +20,7 @@ const PowermenuWidget = CenterBox({
   }),
 
   centerWidget: Button({
+    type: "Button",
     className: 'reboot',
     onPrimaryClickRelease: 'systemctl reboot',
 
@@ -28,6 +30,7 @@ const PowermenuWidget = CenterBox({
   }),
 
   endWidget: Button({
+    type: "Button",
     className: 'logout',
     onPrimaryClickRelease: 'hyprctl dispatch exit',
 
@@ -40,5 +43,5 @@ const PowermenuWidget = CenterBox({
 export default () => PopupWindow({
   name: 'powermenu',
   transition: 'crossfade',
-  child: PowermenuWidget,
+  child: PowermenuWidget(),
 });
diff --git a/hosts/wim/config/ags/js/quick-settings/button-grid.js b/hosts/wim/config/ags/js/quick-settings/button-grid.js
index 402e8468..75de300b 100644
--- a/hosts/wim/config/ags/js/quick-settings/button-grid.js
+++ b/hosts/wim/config/ags/js/quick-settings/button-grid.js
@@ -2,10 +2,14 @@ import { Network, Bluetooth, Audio, App, Utils, Widget } from '../../imports.js'
 const { Box, CenterBox, Label, Icon } = Widget;
 const { execAsync } = Utils;
 
-import { EventBox } from '../misc/cursorbox.js';
+import EventBox from '../misc/cursorbox.js';
 
 
-const GridButton = ({ command = () => {}, secondaryCommand = () => {}, icon } = {}) => Box({
+const GridButton = ({
+  command = () => {},
+  secondaryCommand = () => {},
+  icon
+} = {}) => Box({
   className: 'grid-button',
   children: [
 
@@ -27,7 +31,7 @@ const GridButton = ({ command = () => {}, secondaryCommand = () => {}, icon } =
   ],
 });
 
-const FirstRow = Box({
+const FirstRow = () => Box({
   className: 'button-row',
   halign: 'center',
   style: 'margin-top: 15px; margin-bottom: 7px;',
@@ -35,7 +39,10 @@ const FirstRow = Box({
 
     GridButton({
       command: () => Network.toggleWifi(),
-      secondaryCommand: () => execAsync(['bash', '-c', 'nm-connection-editor']).catch(print),
+      secondaryCommand: () => {
+        execAsync(['bash', '-c', 'nm-connection-editor'])
+          .catch(print);
+      },
       icon: Icon({
         className: 'grid-label',
         connections: [[Network, icon => {
@@ -50,35 +57,47 @@ const FirstRow = Box({
     }),
 
     GridButton({
-      command: () => execAsync(['bash', '-c', '$AGS_PATH/qs-toggles.sh blue-toggle']).catch(print),
-      secondaryCommand: () => execAsync(['bash', '-c', 'blueberry']).catch(print),
+      command: () => {
+        execAsync(['bash', '-c', '$AGS_PATH/qs-toggles.sh blue-toggle'])
+          .catch(print);
+      },
+      secondaryCommand: () => {
+        execAsync(['bash', '-c', 'blueberry'])
+          .catch(print)
+      },
       icon: Icon({
         className: 'grid-label',
-        connections: [[Bluetooth, icon => {
+        connections: [[Bluetooth, self => {
           if (Bluetooth.enabled) {
-            icon.icon = 'bluetooth-active-symbolic';
-            execAsync(['bash', '-c', 'echo 󰂯 > $HOME/.config/.bluetooth']).catch(print);
+            self.icon = 'bluetooth-active-symbolic';
+            execAsync(['bash', '-c', 'echo 󰂯 > $HOME/.config/.bluetooth'])
+              .catch(print);
           }
           else {
-            icon.icon = 'bluetooth-disabled-symbolic';
-            execAsync(['bash', '-c', 'echo 󰂲 > $HOME/.config/.bluetooth']).catch(print);
+            self.icon = 'bluetooth-disabled-symbolic';
+            execAsync(['bash', '-c', 'echo 󰂲 > $HOME/.config/.bluetooth'])
+              .catch(print);
           }
         }, 'changed']],
       })
     }),
 
     GridButton({
-      command: () => execAsync(['bash', '-c', '$AGS_PATH/qs-toggles.sh toggle-radio']).catch(print),
-      secondaryCommand: () => execAsync(['notify-send', 'set this up moron']).catch(print),
+      command: () => {
+        execAsync(['bash', '-c', '$AGS_PATH/qs-toggles.sh toggle-radio'])
+          .catch(print);
+      },
+      secondaryCommand: () => {
+        execAsync(['notify-send', 'set this up moron'])
+          .catch(print);
+      },
       icon: Icon({
         className: 'grid-label',
-        connections: [[Network, icon => {
-          if (Network.wifi.enabled) {
-            icon.icon = 'airplane-mode-disabled-symbolic';
-          }
-          else {
-            icon.icon = 'airplane-mode-symbolic';
-          }
+        connections: [[Network, self => {
+          if (Network.wifi.enabled)
+            self.icon = 'airplane-mode-disabled-symbolic';
+          else
+            self.icon = 'airplane-mode-symbolic';
         }, 'changed']],
       }),
     }),
@@ -86,7 +105,7 @@ const FirstRow = Box({
   ],
 });
 
-const SubRow = CenterBox({
+const SubRow = () => CenterBox({
   halign: 'start',
   children: [
 
@@ -94,8 +113,9 @@ const SubRow = CenterBox({
       className: 'sub-label',
       truncate: 'end',
       maxWidthChars: 12,
-      connections: [[Network, label => {
-        label.label = Network.wifi.ssid;
+      connections: [[Network, self => {
+        // TODO: handle ethernet too
+        self.label = Network.wifi.ssid;
       }, 'changed']],
     }),
 
@@ -103,20 +123,15 @@ const SubRow = CenterBox({
       className: 'sub-label',
       truncate: 'end',
       maxWidthChars: 12,
-      connections: [[Bluetooth, label => {
-        label.label = Bluetooth.connectedDevices[0] ? String(Bluetooth.connectedDevices[0]) :
-                                                      'Disconnected';
+      connections: [[Bluetooth, self => {
+        if (Bluetooth.connectedDevices[0])
+          self.label = String(Bluetooth.connectedDevices[0])
+        else
+          self.label = 'Disconnected';
       }, 'changed']],
     }),
 
-    Label({
-      className: '',
-      truncate: 'end',
-      maxWidthChars: 12,
-      /*connections: [[Network, label => {
-        label.label = Network.wifi.ssid;
-      }, 'changed']],*/
-    }),
+    null,
 
   ],
 });
@@ -135,15 +150,23 @@ const itemsMic = {
   0: 'audio-input-microphone-muted-symbolic',
 };
 
-const SecondRow = Box({
+const SecondRow = () => Box({
   className: 'button-row',
   halign: 'center',
   style: 'margin-top: 7px; margin-bottom: 15px;',
   children: [
 
     GridButton({
-      command: () => execAsync(['swayosd-client', '--output-volume', 'mute-toggle']).catch(print),
-      secondaryCommand: () => execAsync(['bash', '-c', 'pavucontrol']).catch(print),
+      command: () => {
+        execAsync(['swayosd-client', '--output-volume', 'mute-toggle'])
+          .catch(print);
+      },
+
+      secondaryCommand: () => {
+        execAsync(['bash', '-c', 'pavucontrol'])
+          .catch(print);
+      },
+
       icon: Icon({
         className: 'grid-label',
         connections: [[Audio, icon => {
@@ -165,8 +188,16 @@ const SecondRow = Box({
     }),
 
     GridButton({
-      command: () => execAsync(['swayosd-client', '--input-volume', 'mute-toggle']).catch(print),
-      secondaryCommand: () => execAsync(['bash', '-c', 'pavucontrol']).catch(print),
+      command: () => {
+        execAsync(['swayosd-client', '--input-volume', 'mute-toggle'])
+          .catch(print);
+      },
+
+      secondaryCommand: () => {
+        execAsync(['bash', '-c', 'pavucontrol'])
+          .catch(print);
+      },
+
       icon: Icon({
         className: 'grid-label',
         connections: [[Audio, icon => {
@@ -188,7 +219,10 @@ const SecondRow = Box({
     }),
 
     GridButton({
-      command: () => execAsync(['bash', '-c', '$LOCK_PATH/lock.sh']).catch(print),
+      command: () => {
+        execAsync(['bash', '-c', '$LOCK_PATH/lock.sh'])
+          .catch(print);
+      },
       secondaryCommand: () => App.openWindow('powermenu'),
       icon: Label({
         className: 'grid-label',
@@ -199,14 +233,13 @@ const SecondRow = Box({
   ],
 });
 
-
-export const ButtonGrid = Box({
+export default () => Box({
   className: 'button-grid',
   vertical: true,
   halign: 'center',
   children: [
-    FirstRow,
-    SubRow,
-    SecondRow,
+    FirstRow(),
+    SubRow(),
+    SecondRow(),
   ],
 });
diff --git a/hosts/wim/config/ags/js/quick-settings/main.js b/hosts/wim/config/ags/js/quick-settings/main.js
index 834980d0..fad89013 100644
--- a/hosts/wim/config/ags/js/quick-settings/main.js
+++ b/hosts/wim/config/ags/js/quick-settings/main.js
@@ -3,14 +3,14 @@ const { Box, Label, Revealer, Icon } = Widget;
 
 import Gtk from 'gi://Gtk';
 
-import { ButtonGrid } from './button-grid.js';
-import { SliderBox } from './slider-box.js';
-import Player from '../media-player/player.js';
-import { EventBox } from '../misc/cursorbox.js';
-import { PopupWindow } from '../misc/popup.js';
+import ButtonGrid  from './button-grid.js';
+import SliderBox   from './slider-box.js';
+import Player      from '../media-player/player.js';
+import EventBox    from '../misc/cursorbox.js';
+import PopupWindow from '../misc/popup.js';
 
 
-const QuickSettingsWidget = Box({
+const QuickSettingsWidget = () => Box({
   className: 'qs-container',
   vertical: true,
   children: [
@@ -27,9 +27,9 @@ const QuickSettingsWidget = Box({
           style: 'margin-left: 20px'
         }),
 
-        ButtonGrid,
+        ButtonGrid(),
 
-        SliderBox,
+        SliderBox(),
 
         EventBox({
           child: Widget({
@@ -41,13 +41,15 @@ const QuickSettingsWidget = Box({
               });
             },
             connections: [['toggled', button => {
+              let rev = button.get_parent().get_parent().get_parent().children[1];
+
               if (button.get_active()) {
                 button.child.setStyle("-gtk-icon-transform: rotate(0deg);");
-                button.get_parent().get_parent().get_parent().children[1].revealChild = true;
+                rev.revealChild = true;
               }
               else {
                 button.child.setStyle('-gtk-icon-transform: rotate(180deg);');
-                button.get_parent().get_parent().get_parent().children[1].revealChild = false;
+                rev.revealChild = false;
               }
             }]],
             child: Icon({
@@ -73,5 +75,5 @@ export default () => PopupWindow({
   name: 'quick-settings',
   anchor: [ 'top', 'right' ],
   margin: [ 8, 5, 0, ],
-  child: QuickSettingsWidget,
+  child: QuickSettingsWidget(),
 });
diff --git a/hosts/wim/config/ags/js/quick-settings/slider-box.js b/hosts/wim/config/ags/js/quick-settings/slider-box.js
index be3c419e..3aaecfff 100644
--- a/hosts/wim/config/ags/js/quick-settings/slider-box.js
+++ b/hosts/wim/config/ags/js/quick-settings/slider-box.js
@@ -11,7 +11,7 @@ const items = {
 };
 
 
-export const SliderBox = Box({
+export default () => Box({
   className: 'slider-box',
   vertical: true,
   halign: 'center',
@@ -73,11 +73,14 @@ export const SliderBox = Box({
               ['canChange', true],
             ],
             onChange: ({ value }) => {
-              execAsync(`brightnessctl set ${value}`).catch(print);
+              execAsync(`brightnessctl set ${value}`)
+                .catch(print);
             },
             connections: [[1000, slider => {
               if (slider._canChange) {
-                execAsync('brightnessctl get').then(out => slider.value = out).catch(print);
+                execAsync('brightnessctl get')
+                  .then(out => slider.value = out)
+                  .catch(print);
               }
             }]],
             min: 0,
diff --git a/hosts/wim/config/ags/js/screen-corners.js b/hosts/wim/config/ags/js/screen-corners.js
index 5a519be9..7e91c6d1 100644
--- a/hosts/wim/config/ags/js/screen-corners.js
+++ b/hosts/wim/config/ags/js/screen-corners.js
@@ -8,13 +8,23 @@ export const RoundedCorner = (place, props) => Widget({
     halign: place.includes('left') ? 'start' : 'end',
     valign: place.includes('top') ? 'start' : 'end',
     setup: widget => {
-        const r = widget.get_style_context().get_property('border-radius', Gtk.StateFlags.NORMAL);
+        const r = widget.get_style_context()
+          .get_property('border-radius', Gtk.StateFlags.NORMAL);
+
         widget.set_size_request(r, r);
         widget.connect('draw', Lang.bind(widget, (widget, cr) => {
-            const c = widget.get_style_context().get_property('background-color', Gtk.StateFlags.NORMAL);
-            const r = widget.get_style_context().get_property('border-radius', Gtk.StateFlags.NORMAL);
-            const borderColor = widget.get_style_context().get_property('color', Gtk.StateFlags.NORMAL);
-            const borderWidth = widget.get_style_context().get_border(Gtk.StateFlags.NORMAL).left; // ur going to write border-width: something anyway
+            const c = widget.get_style_context()
+              .get_property('background-color', Gtk.StateFlags.NORMAL);
+
+            const r = widget.get_style_context()
+              .get_property('border-radius', Gtk.StateFlags.NORMAL);
+
+            const borderColor = widget.get_style_context()
+              .get_property('color', Gtk.StateFlags.NORMAL);
+
+            // ur going to write border-width: something anyway
+            const borderWidth = widget.get_style_context()
+              .get_border(Gtk.StateFlags.NORMAL).left;
             widget.set_size_request(r, r);
 
             switch (place) {
@@ -43,7 +53,10 @@ export const RoundedCorner = (place, props) => Widget({
             cr.setSourceRGBA(c.red, c.green, c.blue, c.alpha);
             cr.fill();
             cr.setLineWidth(borderWidth);
-            cr.setSourceRGBA(borderColor.red, borderColor.green, borderColor.blue, borderColor.alpha);
+            cr.setSourceRGBA(borderColor.red,
+                             borderColor.green,
+                             borderColor.blue,
+                             borderColor.alpha);
             cr.stroke();
         }));
     },
diff --git a/hosts/wim/config/hypr/main.conf b/hosts/wim/config/hypr/main.conf
index 73b73e35..c07b8072 100644
--- a/hosts/wim/config/hypr/main.conf
+++ b/hosts/wim/config/hypr/main.conf
@@ -28,7 +28,7 @@ exec-once = ags
 exec-once = gnome-keyring-daemon --start --components=secrets
 exec-once = squeekboard
 
-exec-once = bash -c "sleep 1; ags -t applauncher"
+exec-once = bash -c "sleep 3; ags -t applauncher"
 exec-once = hyprpaper
 
 exec-once = wl-paste --watch cliphist store