From ce6e314fde5a8eff5cdfc8536c578712b81057dd Mon Sep 17 00:00:00 2001 From: zach Date: Fri, 26 Jun 2026 17:23:56 +0200 Subject: [PATCH] chore: regions now manually set, moved to separate file --- Drawers/Regions.qml | 89 ++++++++++ Drawers/Windows.qml | 46 ++---- Modules/SysTray/TrayItem.qml | 4 +- network-dev/wifi-sim.sh | 310 +++++++++++++++++++++++++++++++++++ 4 files changed, 415 insertions(+), 34 deletions(-) create mode 100644 Drawers/Regions.qml create mode 100755 network-dev/wifi-sim.sh diff --git a/Drawers/Regions.qml b/Drawers/Regions.qml new file mode 100644 index 0000000..5d74faf --- /dev/null +++ b/Drawers/Regions.qml @@ -0,0 +1,89 @@ +pragma ComponentBehavior: Bound + +import QtQuick +import Quickshell +import qs.Modules.Bar as Bar + +Region { + id: root + + required property Bar.BarLoader bar + readonly property real borderThickness: win.borderThickness + readonly property alias menuPopoutRegion: menuPopoutRegion + required property Panels panels + required property var win + + height: win.height - bar.implicitHeight - win.borderThickness - win.dragMaskPadding * 2 + intersection: Intersection.Xor + width: win.width - win.borderThickness * 2 - win.dragMaskPadding * 2 + x: win.borderThickness + win.dragMaskPadding + y: bar.implicitHeight + win.dragMaskPadding + + R { + panel: root.panels.dashboardWrapper + } + + R { + panel: root.panels.launcher + } + + R { + id: sidebarRegion + + panel: root.panels.sidebar + width: panel.width * (1 - root.panels.sidebar.offsetScale) + root.borderThickness + x: root.win.width - width + } + + R { + panel: root.panels.osdWrapper + width: panel.width * (1 - root.panels.osd.offsetScale) + root.borderThickness + x: root.win.width - width + } + + R { + panel: root.panels.notifications + } + + R { + height: panel.height * (1 - root.panels.utilities.offsetScale) + root.borderThickness + panel: root.panels.utilities + y: root.win.height - height + } + + R { + panel: root.panels.popoutsWrapper + } + + R { + panel: root.panels.resourcesWrapper + } + + R { + panel: root.panels.settingsWrapper + } + + R { + panel: root.panels.dock + } + + R { + panel: root.panels.clipboard + } + + Region { + id: menuPopoutRegion + + intersection: Intersection.Subtract + } + + component R: Region { + required property Item panel + + height: panel.height + intersection: Intersection.Subtract + width: panel.width + x: panel.x + root.borderThickness + y: panel.y + root.bar.implicitHeight + } +} diff --git a/Drawers/Windows.qml b/Drawers/Windows.qml index cf5c486..6d6842e 100644 --- a/Drawers/Windows.qml +++ b/Drawers/Windows.qml @@ -44,7 +44,7 @@ CustomWindow { readonly property bool hasFullscreenOnNormalWs: monitor?.activeWorkspace?.toplevels.values.some(t => t.lastIpcObject.fullscreen > 1) ?? false readonly property bool hasSpecialWorkspace: (monitor?.lastIpcObject.specialWorkspace?.name.length ?? 0) > 0 readonly property alias interactionWrapper: interactions - readonly property alias menuRegion: menuPopoutRegion + readonly property alias menuRegion: regions.menuPopoutRegion readonly property HyprlandMonitor monitor: Hypr.monitorFor(screen) property var root: Quickshell.shellDir readonly property real sdfBorderOffset: 2 * fsTransitionProg @@ -56,7 +56,7 @@ CustomWindow { WlrLayershell.layer: (fsTransitionProg > 0 && Config.general.showOverFullscreen) || (hasSpecialWorkspace && hasFullscreenOnNormalWs) ? WlrLayer.Overlay : WlrLayer.Top color: "transparent" contentItem.focus: true - mask: visibilities.isDrawing ? null : (hasFullscreen ? emptyRegion : region) + mask: visibilities.isDrawing ? null : (hasFullscreen ? emptyRegion : regions) name: "Bar" Behavior on fsTransitionProg { @@ -93,12 +93,6 @@ CustomWindow { panels.popouts.hasCurrent = false; } - Region { - id: menuPopoutRegion - - intersection: Intersection.Subtract - } - Region { id: emptyRegion @@ -106,17 +100,21 @@ CustomWindow { width: panels.notifications.width x: panels.notifications.x + root.borderThickness y: panels.notifications.y + bar.implicitHeight + + Region { + height: panels.osd.height + width: panels.osdWrapper.width * (1 - panels.osd.offsetScale) + root.borderThickness + x: root.width - width + y: panels.osdWrapper.y + bar.implicitHeight + } } - Region { - id: region + Regions { + id: regions - height: root.height - bar.implicitHeight - root.borderThickness - root.dragMaskPadding * 2 - intersection: Intersection.Xor - regions: [...popoutRegions.instances, menuPopoutRegion] - width: root.width - root.borderThickness * 2 - root.dragMaskPadding * 2 - x: root.borderThickness + root.dragMaskPadding - y: bar.implicitHeight + root.dragMaskPadding + bar: bar + panels: panels + win: root } anchors { @@ -126,22 +124,6 @@ CustomWindow { top: true } - Variants { - id: popoutRegions - - model: panels.children - - Region { - required property Item modelData - - height: modelData.height - intersection: Intersection.Subtract - width: modelData.width - x: modelData.x + root.borderThickness - y: modelData.y + bar.implicitHeight - } - } - HyprlandFocusGrab { id: focusGrab diff --git a/Modules/SysTray/TrayItem.qml b/Modules/SysTray/TrayItem.qml index 9f9e388..c0f80bc 100644 --- a/Modules/SysTray/TrayItem.qml +++ b/Modules/SysTray/TrayItem.qml @@ -45,13 +45,13 @@ Item { CustomRect { anchors.fill: parent anchors.margins: 3 - color: Config.general.color.scheduleDark && root.current ? DynamicColors.palette.m3primary : "transparent" + color: icon.layer.enabled && root.current ? DynamicColors.palette.m3primary : "transparent" radius: Appearance.rounding.full StateLayer { acceptedButtons: Qt.LeftButton | Qt.RightButton anchors.fill: parent - color: Config.general.color.scheduleDark && root.current ? DynamicColors.palette.m3onPrimary : DynamicColors.palette.m3onSurface + color: icon.layer.enabled && root.current ? DynamicColors.palette.m3onPrimary : DynamicColors.palette.m3onSurface onClicked: mouse => { if (mouse.button === Qt.LeftButton) { diff --git a/network-dev/wifi-sim.sh b/network-dev/wifi-sim.sh new file mode 100755 index 0000000..f3b2cea --- /dev/null +++ b/network-dev/wifi-sim.sh @@ -0,0 +1,310 @@ +#!/bin/bash +# ============================================================================= +# wifi-sim.sh — Virtual WiFi environment for development & testing +# +# Creates 3 dummy networks using mac80211_hwsim + hostapd: +# - FreeWifi (open, strong signal, ch 1) +# - OfficeNetwork (open, medium signal, ch 6) +# - HomeNetwork (WPA2, weak signal, ch 11) +# +# Usage: +# sudo ./wifi-sim.sh start +# sudo ./wifi-sim.sh stop +# sudo ./wifi-sim.sh status +# ============================================================================= + +set -euo pipefail + +# --- User configuration ------------------------------------------------------ + +SSID_STRONG="FreeWifi" # Open network, strong signal +SSID_MEDIUM="OfficeNetwork" # Open network, medium signal +SSID_SECURE="HomeNetwork" # WPA2 network, weak signal +WIFI_PASSWORD="testpassword123" + +# TX power levels in mBm (millibel-milliwatts). Higher = stronger signal. +# These affect the RSSI reported to scanning clients. +TXPOWER_STRONG=3000 # 30 dBm +TXPOWER_MEDIUM=1500 # 15 dBm +TXPOWER_WEAK=100 # 1 dBm + +RUN_DIR="/tmp/wifi-sim" + +# --- Helpers ----------------------------------------------------------------- + +die() { + echo "ERROR: $*" >&2 + exit 1 +} +info() { echo "[*] $*"; } +ok() { echo "[+] $*"; } + +require_cmds() { + local missing=() + for cmd in "$@"; do + command -v "$cmd" &>/dev/null || missing+=("$cmd") + done + if [[ ${#missing[@]} -gt 0 ]]; then + die "Missing required tools: ${missing[*]} + Install with: sudo apt install hostapd wpasupplicant iw" + fi +} + +get_phy_for_iface() { + iw dev "$1" info | awk '/wiphy/{print "phy"$2}' +} + +# --- Start ------------------------------------------------------------------- + +cmd_start() { + [[ $EUID -ne 0 ]] && die "Please run as root: sudo $0 start" + require_cmds hostapd iw ip + + if [[ -d "$RUN_DIR" && -f "$RUN_DIR/interfaces" ]]; then + die "wifi-sim appears to already be running. Run 'sudo $0 stop' first." + fi + mkdir -p "$RUN_DIR" + + # Snapshot existing wlan interfaces so we can identify the new ones + info "Snapshotting existing interfaces..." + BEFORE=($(iw dev 2>/dev/null | awk '/Interface/{print $2}' | grep -v '^hwsim' || true)) + + # Load the kernel module with 4 radios (3 APs + 1 client) + info "Loading mac80211_hwsim (4 radios)..." + if lsmod | grep -q mac80211_hwsim; then + die "mac80211_hwsim is already loaded. Run 'sudo $0 stop' or 'sudo rmmod mac80211_hwsim' first." + fi + modprobe mac80211_hwsim radios=4 + sleep 1 # Give the kernel a moment to register all interfaces + + # Find the interfaces created by our modprobe + AFTER=($(iw dev 2>/dev/null | awk '/Interface/{print $2}' | grep -v '^hwsim')) + NEW_IFACES=() + for iface in "${AFTER[@]}"; do + [[ ! " ${BEFORE[*]:-} " =~ " $iface " ]] && NEW_IFACES+=("$iface") + done + + if [[ ${#NEW_IFACES[@]} -lt 4 ]]; then + rmmod mac80211_hwsim 2>/dev/null || true + die "Expected 4 new wlan interfaces, found ${#NEW_IFACES[@]}. Check 'dmesg' for errors." + fi + + AP1="${NEW_IFACES[0]}" # Will host SSID_STRONG + AP2="${NEW_IFACES[1]}" # Will host SSID_MEDIUM + AP3="${NEW_IFACES[2]}" # Will host SSID_SECURE + CLIENT="${NEW_IFACES[3]}" # Client-side interface for your code to use + + info "Interfaces assigned: AP1=$AP1 AP2=$AP2 AP3=$AP3 Client=$CLIENT" + echo "$AP1 $AP2 $AP3 $CLIENT" >"$RUN_DIR/interfaces" + + # Prevent NetworkManager from fighting us over these interfaces + if command -v nmcli &>/dev/null && nmcli general status &>/dev/null 2>&1; then + info "Marking interfaces as unmanaged in NetworkManager..." + for iface in "$AP1" "$AP2" "$AP3"; do + nmcli device set "$iface" managed no 2>/dev/null || true + done + + nmcli device set "$CLIENT" managed yes + fi + + # Set TX power on each physical radio to simulate signal strength differences. + # mac80211_hwsim factors TX power into the RSSI reported to scanning clients. + # Note: for precise RSSI control, consider 'wmediumd' (a wireless medium daemon). + info "Setting TX power levels for signal strength simulation..." + PHY1=$(get_phy_for_iface "$AP1") + PHY2=$(get_phy_for_iface "$AP2") + PHY3=$(get_phy_for_iface "$AP3") + + iw phy "$PHY1" set txpower fixed $TXPOWER_STRONG + iw phy "$PHY2" set txpower fixed $TXPOWER_MEDIUM + iw phy "$PHY3" set txpower fixed $TXPOWER_WEAK + + # --- hostapd config: AP1 (open, strong, channel 1) ----------------------- + cat >"$RUN_DIR/ap1.conf" <"$RUN_DIR/ap2.conf" <"$RUN_DIR/ap3.conf" <"$RUN_DIR/ap1.log" 2>&1 || + { + cat "$RUN_DIR/ap1.log" + die "hostapd failed for AP1. See log above." + } + + hostapd -B -P "$RUN_DIR/ap2.pid" "$RUN_DIR/ap2.conf" \ + >"$RUN_DIR/ap2.log" 2>&1 || + { + cat "$RUN_DIR/ap2.log" + die "hostapd failed for AP2. See log above." + } + + hostapd -B -P "$RUN_DIR/ap3.pid" "$RUN_DIR/ap3.conf" \ + >"$RUN_DIR/ap3.log" 2>&1 || + { + cat "$RUN_DIR/ap3.log" + die "hostapd failed for AP3. See log above." + } + + # Bring up the client interface so it's ready to scan/connect + ip link set "$CLIENT" up + + # --- Summary ------------------------------------------------------------- + ok "Virtual WiFi environment is up!" + echo "" + echo " Networks:" + echo " ┌──────────────────┬──────────┬────────┬─────────────┐" + echo " │ SSID │ Security │ Signal │ Interface │" + echo " ├──────────────────┼──────────┼────────┼─────────────┤" + printf " │ %-16s │ %-8s │ %-6s │ %-11s │\n" "$SSID_STRONG" "Open" "Strong" "$AP1" + printf " │ %-16s │ %-8s │ %-6s │ %-11s │\n" "$SSID_MEDIUM" "Open" "Medium" "$AP2" + printf " │ %-16s │ %-8s │ %-6s │ %-11s │\n" "$SSID_SECURE" "WPA2" "Weak" "$AP3" + echo " └──────────────────┴──────────┴────────┴─────────────┘" + echo "" + echo " WPA2 password : $WIFI_PASSWORD" + echo " Client iface : $CLIENT (use this in your code)" + echo "" + echo " Useful commands:" + echo " Scan for networks : sudo iw dev $CLIENT scan | grep -E 'SSID|signal'" + echo " Connect (open) : sudo iw dev $CLIENT connect \"$SSID_STRONG\"" + echo " Connect (WPA2) : sudo wpa_supplicant -Dnl80211 -i$CLIENT \\" + echo " -c <(wpa_passphrase \"$SSID_SECURE\" \"$WIFI_PASSWORD\")" + echo " Stop simulation : sudo $0 stop" + echo "" + echo " Logs: $RUN_DIR/ap{1,2,3}.log" +} + +# --- Stop -------------------------------------------------------------------- + +cmd_stop() { + [[ $EUID -ne 0 ]] && die "Please run as root: sudo $0 stop" + + info "Stopping virtual WiFi environment..." + local had_something=false + + # Kill hostapd processes via PID files + for ap in ap1 ap2 ap3; do + PID_FILE="$RUN_DIR/$ap.pid" + if [[ -f "$PID_FILE" ]]; then + PID=$(cat "$PID_FILE") + if kill "$PID" 2>/dev/null; then + info "Stopped hostapd for $ap (PID $PID)" + fi + rm -f "$PID_FILE" + had_something=true + fi + done + + # Re-enable NetworkManager management for these interfaces + if [[ -f "$RUN_DIR/interfaces" ]]; then + read -r AP1 AP2 AP3 CLIENT <"$RUN_DIR/interfaces" + if command -v nmcli &>/dev/null; then + for iface in "$AP1" "$AP2" "$AP3" "$CLIENT"; do + nmcli device set "$iface" managed yes 2>/dev/null || true + done + fi + fi + + # Unload the kernel module (also destroys all virtual interfaces) + if lsmod | grep -q mac80211_hwsim; then + info "Unloading mac80211_hwsim..." + rmmod mac80211_hwsim && had_something=true + fi + + # Clean up runtime directory + rm -rf "$RUN_DIR" + + if $had_something; then + ok "Virtual WiFi environment stopped." + else + echo "Nothing was running." + fi +} + +# --- Status ------------------------------------------------------------------ + +cmd_status() { + if [[ ! -f "$RUN_DIR/interfaces" ]]; then + echo "wifi-sim is not running." + return + fi + + read -r AP1 AP2 AP3 CLIENT <"$RUN_DIR/interfaces" + echo "wifi-sim is running." + echo "" + echo " Interfaces:" + for iface in "$AP1" "$AP2" "$AP3" "$CLIENT"; do + STATE=$(ip link show "$iface" 2>/dev/null | awk '/state/{print $9}' || echo "unknown") + CHANNEL=$(iw dev "$iface" info 2>/dev/null | awk '/channel/{print $2}' || echo "?") + printf " %-10s state=%-4s channel=%s\n" "$iface" "$STATE" "$CHANNEL" + done + echo "" + echo " Processes:" + for ap in ap1 ap2 ap3; do + PID_FILE="$RUN_DIR/$ap.pid" + if [[ -f "$PID_FILE" ]]; then + PID=$(cat "$PID_FILE") + if kill -0 "$PID" 2>/dev/null; then + echo " hostapd ($ap) PID=$PID running" + else + echo " hostapd ($ap) PID=$PID DEAD (check $RUN_DIR/$ap.log)" + fi + fi + done +} + +# --- Entry point ------------------------------------------------------------- + +case "${1:-help}" in +start) cmd_start ;; +stop) cmd_stop ;; +status) cmd_status ;; +*) + echo "Usage: sudo $0 {start|stop|status}" + echo "" + echo " start Load mac80211_hwsim and bring up 3 virtual APs" + echo " stop Tear down all virtual interfaces and unload module" + echo " status Show current state of interfaces and processes" + echo "" + echo "Networks created on start:" + printf " %-16s open, strong signal\n" "$SSID_STRONG" + printf " %-16s open, medium signal\n" "$SSID_MEDIUM" + printf " %-16s WPA2, weak signal (password: $WIFI_PASSWORD)\n" "$SSID_SECURE" + ;; +esac