Fixa omladdningsloopen + churn; CI/släpp flyttat till x64-byggnoden
Some checks failed
check / check (push) Failing after 1m4s
Some checks failed
check / check (push) Failing after 1m4s
- KRITISKT: notify-watchern reagerade på Access-events, så vår egen läsning av configen triggade ny omladdning i all oändlighet (var 155:e ms). Panelen revs och byggdes om konstant → blinkande hover, klick som aldrig landade. Nu filtreras eventen till riktiga skrivningar (Modify/Create/Remove/Close-Write). - Titeländringar (webbläsare/terminaler) bygger inte längre om UI:t; tooltips slås i stället upp färskt vid hover (query-tooltip), och klick/skroll/menyer agerar på färskt fönster-state vid eventtillfället. - hotspots::rebuild är idempotent (skippar om config+skärmar oförändrade). - Settings: markup-escape i rubriker (Kant & skugga-varningen). - CI: check + release körs på byggnoden brasse-linux01 (runs-on linux-amd64) — waydock byggs BARA för x86_64, aldrig på Pi5:ns arm-runner. Ny release.yaml: vX.Y.Z-tagg bygger x64-binären och laddar upp till Gitea-släppsidan + rullande latest. release.sh är nu bara tagga-och-pusha. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
@@ -1,7 +1,8 @@
|
||||
name: check
|
||||
|
||||
# Kompilerings- och lintvakt på Pi5-runnern (arm64). Bygger inga
|
||||
# artefakter — släpp byggs lokalt på brasse-linux01 via ./release.sh.
|
||||
# Kompilerings- och lintvakt på byggnoden på brasse-linux01 (x64-runnern
|
||||
# med exklusiva labeln linux-amd64). waydock byggs BARA för x86_64 —
|
||||
# aldrig på Pi5:ns arm-runner.
|
||||
on:
|
||||
push:
|
||||
branches: [master]
|
||||
@@ -14,7 +15,7 @@ on:
|
||||
|
||||
jobs:
|
||||
check:
|
||||
runs-on: ubuntu-latest
|
||||
runs-on: linux-amd64
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v4
|
||||
|
||||
101
.gitea/workflows/release.yaml
Normal file
101
.gitea/workflows/release.yaml
Normal file
@@ -0,0 +1,101 @@
|
||||
name: release
|
||||
|
||||
# Släppbygge på byggnoden på brasse-linux01 (x64-runnern, label
|
||||
# linux-amd64). En vX.Y.Z-tagg ger en versionerad release + uppdaterar
|
||||
# rullande "latest". Bara linux-x64 byggs — waydock är en desktopapp
|
||||
# för brasse-linux01, ingen arm-build.
|
||||
on:
|
||||
push:
|
||||
tags: ["v*"]
|
||||
workflow_dispatch:
|
||||
inputs:
|
||||
tag:
|
||||
description: "Release-tag (lämna tom för 'latest')"
|
||||
required: false
|
||||
|
||||
jobs:
|
||||
build-release:
|
||||
runs-on: linux-amd64
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v4
|
||||
|
||||
- name: Bestäm tag
|
||||
id: t
|
||||
run: |
|
||||
case "$GITHUB_REF" in
|
||||
refs/tags/*) T="$GITHUB_REF_NAME" ;;
|
||||
*) T="${{ inputs.tag }}"; [ -z "$T" ] && T="latest" ;;
|
||||
esac
|
||||
echo "tag=$T" >> "$GITHUB_OUTPUT"
|
||||
echo "bygger release: $T"
|
||||
|
||||
- name: Install toolchain + GTK4 deps
|
||||
run: |
|
||||
export DEBIAN_FRONTEND=noninteractive
|
||||
apt-get update -qq
|
||||
apt-get install -y -qq curl build-essential pkg-config git jq \
|
||||
libgtk-4-dev meson ninja-build wayland-protocols libwayland-dev
|
||||
if ! apt-get install -y -qq libgtk4-layer-shell-dev; then
|
||||
git clone --depth 1 https://github.com/wmww/gtk4-layer-shell.git /tmp/g4ls
|
||||
meson setup /tmp/g4ls/build /tmp/g4ls \
|
||||
-Dintrospection=false -Dvapi=false -Dexamples=false \
|
||||
-Ddocs=false -Dtests=false
|
||||
ninja -C /tmp/g4ls/build install
|
||||
ldconfig
|
||||
arch_dir=$(gcc -dumpmachine)
|
||||
echo "PKG_CONFIG_PATH=/usr/local/lib/${arch_dir}/pkgconfig:/usr/local/lib/pkgconfig" >> "$GITHUB_ENV"
|
||||
echo "LD_LIBRARY_PATH=/usr/local/lib/${arch_dir}:/usr/local/lib" >> "$GITHUB_ENV"
|
||||
fi
|
||||
curl -sSf https://sh.rustup.rs | sh -s -- -y --profile minimal
|
||||
echo "$HOME/.cargo/bin" >> "$GITHUB_PATH"
|
||||
|
||||
- name: Bygg x64-binären
|
||||
run: |
|
||||
cargo build --release --locked
|
||||
cargo test --locked
|
||||
mkdir -p out
|
||||
cp target/release/waydock "out/waydock-${{ steps.t.outputs.tag }}-linux-x64"
|
||||
cp target/release/waydock out/waydock-latest-linux-x64
|
||||
cp install.sh out/install.sh
|
||||
cd out && sha256sum waydock-* install.sh > checksums.txt && ls -la
|
||||
|
||||
- name: Skapa Gitea-release + ladda upp assets
|
||||
env:
|
||||
API: ${{ github.server_url }}/api/v1
|
||||
REPO: ${{ github.repository }}
|
||||
TAG: ${{ steps.t.outputs.tag }}
|
||||
TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
run: |
|
||||
BODY="waydock $TAG — linux-x64. Installera: curl -fsSL https://gitea.brasse-pc.eu/brasse/waydock/raw/branch/master/install.sh | sh"
|
||||
publish() { # $1 = releasetagg, $2... = assetfiler
|
||||
local tag=$1; shift
|
||||
local rid
|
||||
rid=$(curl -s -X POST "$API/repos/$REPO/releases" \
|
||||
-H "Authorization: token $TOKEN" -H 'Content-Type: application/json' \
|
||||
-d "{\"tag_name\":\"$tag\",\"name\":\"waydock $tag\",\"body\":\"$BODY\"}" | jq -r '.id // empty')
|
||||
[ -z "$rid" ] && rid=$(curl -s "$API/repos/$REPO/releases/tags/$tag" \
|
||||
-H "Authorization: token $TOKEN" | jq -r '.id')
|
||||
echo "release $tag -> id $rid"
|
||||
for f in "$@"; do
|
||||
local aid
|
||||
aid=$(curl -s "$API/repos/$REPO/releases/$rid/assets" \
|
||||
-H "Authorization: token $TOKEN" | jq -r ".[] | select(.name==\"$f\") | .id")
|
||||
if [ -n "$aid" ] && [ "$aid" != "null" ]; then
|
||||
curl -s -X DELETE "$API/repos/$REPO/releases/$rid/assets/$aid" \
|
||||
-H "Authorization: token $TOKEN" -o /dev/null
|
||||
fi
|
||||
curl -s -X POST "$API/repos/$REPO/releases/$rid/assets?name=$f" \
|
||||
-H "Authorization: token $TOKEN" -F "attachment=@out/$f" \
|
||||
-o /dev/null -w " $f -> HTTP %{http_code}\n"
|
||||
done
|
||||
}
|
||||
if [ "$TAG" != "latest" ]; then
|
||||
publish "$TAG" "waydock-$TAG-linux-x64" install.sh checksums.txt
|
||||
fi
|
||||
# rullande latest: flytta taggen till HEAD och publicera om
|
||||
git config user.name gitea-actions
|
||||
git config user.email actions@gitea.brasse-pc.eu
|
||||
git tag -f latest
|
||||
git push -f origin latest || echo "kunde inte flytta latest-taggen (fortsätter ändå)"
|
||||
publish latest waydock-latest-linux-x64 install.sh checksums.txt
|
||||
@@ -55,7 +55,12 @@ scale/expo-toggle och fönstergeometri till intelligent autohide.
|
||||
## Släpp
|
||||
|
||||
```bash
|
||||
./release.sh v0.1.0 # taggar, bygger x64, skapar Gitea-release + latest
|
||||
./release.sh v0.1.0 # taggar och pushar — CI bygger och publicerar
|
||||
```
|
||||
|
||||
CI på Gitea (Pi5) kör `cargo check`/`clippy`/`test` vid varje push.
|
||||
All CI kör på **byggnoden på brasse-linux01** (x64-runnern, label
|
||||
`linux-amd64`) — waydock byggs bara för x86_64, aldrig på Pi5:ns
|
||||
arm-runner. Push till master kör `cargo check`/`clippy`/`test`; en
|
||||
vX.Y.Z-tagg bygger release-binären och laddar upp den till
|
||||
[släppsidan](https://gitea.brasse-pc.eu/brasse/waydock/releases)
|
||||
(+ rullande `latest`).
|
||||
|
||||
11
doc/plan.md
11
doc/plan.md
@@ -26,11 +26,12 @@ inbyggt settings-GUI, med live-uppdatering åt båda hållen.
|
||||
|
||||
Pattern A (binär), med lokalt släppbygge:
|
||||
|
||||
- **CI (Gitea Actions, Pi5/arm64):** `cargo check` + `clippy` + `test`
|
||||
vid push till master — kompilerings-/lintvakt, inga artefakter.
|
||||
- **Släpp:** `./release.sh vX.Y.Z` på brasse-linux01 — taggar, bygger
|
||||
x64-release, skapar Gitea-release med binären + uppdaterar rullande
|
||||
`latest`. `install.sh` ger en-rads-install via curl.
|
||||
- **CI (Gitea Actions, x64-runnern `linux-amd64` på brasse-linux01):**
|
||||
`cargo check` + `clippy` + `test` vid push till master. Bara x86_64 —
|
||||
ingen arm-build (Pi5-runnern rör aldrig det här repot).
|
||||
- **Släpp:** `./release.sh vX.Y.Z` taggar och pushar; release-workflowet
|
||||
på byggnoden bygger x64-binären och laddar upp till Gitea-släppsidan
|
||||
+ uppdaterar rullande `latest`. `install.sh` ger en-rads-install.
|
||||
|
||||
## Config
|
||||
|
||||
|
||||
46
release.sh
46
release.sh
@@ -1,56 +1,24 @@
|
||||
#!/usr/bin/env bash
|
||||
# Lokalt släppbygge för waydock (körs på brasse-linux01, x64).
|
||||
# Släpp waydock: taggar vX.Y.Z och pushar — själva bygget och uppladdningen
|
||||
# till Gitea-releasen görs av CI-jobbet .gitea/workflows/release.yaml på
|
||||
# byggnoden (x64-runnern på brasse-linux01).
|
||||
# ./release.sh v0.2.0
|
||||
# Taggar, bygger release-binären, skapar Gitea-release med binären som
|
||||
# asset och uppdaterar den rullande "latest"-releasen.
|
||||
set -euo pipefail
|
||||
|
||||
TAG="${1:?användning: ./release.sh vX.Y.Z}"
|
||||
[[ "$TAG" =~ ^v[0-9]+\.[0-9]+\.[0-9]+$ ]] || { echo "taggen ska vara vX.Y.Z"; exit 1; }
|
||||
|
||||
OWNER=brasse REPO=waydock
|
||||
API=https://gitea.brasse-pc.eu/api/v1
|
||||
TOKEN="${GITEA_TOKEN:-$(jq -r .token ~/.config/giteactl/config.json)}"
|
||||
BIN=target/release/waydock
|
||||
ASSET="waydock-${TAG}-linux-x64"
|
||||
|
||||
# versionen i Cargo.toml ska matcha taggen
|
||||
CARGO_VER=$(grep -m1 '^version' Cargo.toml | cut -d'"' -f2)
|
||||
[[ "v$CARGO_VER" == "$TAG" ]] || { echo "Cargo.toml har $CARGO_VER, taggen är $TAG — uppdatera först"; exit 1; }
|
||||
|
||||
echo "==> bygger $TAG"
|
||||
echo "==> snabbkoll innan tagg"
|
||||
cargo build --release --locked
|
||||
cargo test --locked
|
||||
|
||||
echo "==> taggar + pushar"
|
||||
echo "==> taggar + pushar (CI bygger och publicerar releasen)"
|
||||
git tag -a "$TAG" -m "waydock $TAG"
|
||||
git push origin master "$TAG"
|
||||
|
||||
api() { # method path [json|@fil]
|
||||
local m=$1 p=$2; shift 2
|
||||
curl -fsS -X "$m" -H "Authorization: token $TOKEN" "$@" "$API$p"
|
||||
}
|
||||
|
||||
make_release() { # tag namn prerelease
|
||||
api POST "/repos/$OWNER/$REPO/releases" \
|
||||
-H 'Content-Type: application/json' \
|
||||
-d "{\"tag_name\":\"$1\",\"name\":\"$2\",\"body\":\"waydock $TAG — linux-x64.\\n\\nInstallera:\\n\`\`\`\\ncurl -fsSL https://gitea.brasse-pc.eu/brasse/waydock/raw/branch/master/install.sh | sh\\n\`\`\`\"}"
|
||||
}
|
||||
|
||||
upload() { # release-id filnamn
|
||||
api POST "/repos/$OWNER/$REPO/releases/$1/assets?name=$2" \
|
||||
-F "attachment=@$BIN;filename=$2" > /dev/null
|
||||
}
|
||||
|
||||
echo "==> skapar release $TAG"
|
||||
REL_ID=$(make_release "$TAG" "waydock $TAG" | jq .id)
|
||||
upload "$REL_ID" "$ASSET"
|
||||
|
||||
echo "==> uppdaterar rullande latest"
|
||||
OLD=$(api GET "/repos/$OWNER/$REPO/releases/tags/latest" 2>/dev/null | jq -r .id) || OLD=""
|
||||
[[ -n "$OLD" && "$OLD" != null ]] && api DELETE "/repos/$OWNER/$REPO/releases/$OLD" || true
|
||||
git tag -f latest && git push -f origin latest
|
||||
LATEST_ID=$(make_release "latest" "waydock latest ($TAG)" | jq .id)
|
||||
upload "$LATEST_ID" "waydock-latest-linux-x64"
|
||||
|
||||
echo "==> klart: https://gitea.brasse-pc.eu/$OWNER/$REPO/releases"
|
||||
echo "==> följ bygget: giteactl runs waydock"
|
||||
echo "==> releaser: https://gitea.brasse-pc.eu/brasse/waydock/releases"
|
||||
|
||||
@@ -389,11 +389,23 @@ pub fn watch(path: &Path, on_change: Rc<dyn Fn()>) {
|
||||
let dir = path.parent().unwrap_or(Path::new(".")).to_path_buf();
|
||||
|
||||
let mut watcher = match notify::recommended_watcher(move |res: notify::Result<notify::Event>| {
|
||||
use notify::event::{AccessKind, AccessMode, EventKind};
|
||||
if let Ok(ev) = res {
|
||||
let hit = ev
|
||||
.paths
|
||||
.iter()
|
||||
.any(|p| p.file_name().map(|s| s.to_os_string()) == file_name);
|
||||
// VIKTIGT: bara riktiga skrivningar. Access-events (öppna/läsa)
|
||||
// måste ignoreras — annars triggar vår egen läsning en ny
|
||||
// omladdning i all oändlighet.
|
||||
let relevant = matches!(
|
||||
ev.kind,
|
||||
EventKind::Modify(_)
|
||||
| EventKind::Create(_)
|
||||
| EventKind::Remove(_)
|
||||
| EventKind::Access(AccessKind::Close(AccessMode::Write))
|
||||
);
|
||||
let hit = relevant
|
||||
&& ev
|
||||
.paths
|
||||
.iter()
|
||||
.any(|p| p.file_name().map(|s| s.to_os_string()) == file_name);
|
||||
if hit {
|
||||
let _ = tx.send_blocking(());
|
||||
}
|
||||
|
||||
69
src/dock.rs
69
src/dock.rs
@@ -415,6 +415,33 @@ pub fn recompute_dodge(ctx: &Rc<Ctx>) {
|
||||
update_autohide(ctx);
|
||||
}
|
||||
|
||||
/// Färska fönster för en ikon — slås upp vid klick-/tooltip-tillfället så
|
||||
/// att closures aldrig agerar på inaktuellt state.
|
||||
pub fn fresh_windows(ctx: &Ctx, connector: &str, key: &str) -> Vec<ToplevelInfo> {
|
||||
let service = ctx.service.borrow();
|
||||
let Some(service) = service.as_ref() else {
|
||||
return Vec::new();
|
||||
};
|
||||
let only_here = ctx.cfg.borrow().only_this_output(connector);
|
||||
service
|
||||
.snapshot()
|
||||
.into_iter()
|
||||
.filter(|t| {
|
||||
(!only_here || t.outputs.iter().any(|o| o == connector))
|
||||
&& icons::lookup(&t.app_id).key == key
|
||||
})
|
||||
.collect()
|
||||
}
|
||||
|
||||
/// Bygg en färsk kopia av en ikon vid interaktionstillfället.
|
||||
fn live_item(ctx: &Ctx, connector: &str, item: &Item) -> Rc<Item> {
|
||||
Rc::new(Item {
|
||||
meta: item.meta.clone(),
|
||||
windows: fresh_windows(ctx, connector, &item.meta.key),
|
||||
pinned: item.pinned,
|
||||
})
|
||||
}
|
||||
|
||||
/// Gruppera snapshot → ikonrad för en viss skärm.
|
||||
fn build_items(ctx: &Ctx, connector: &str, snapshot: &[ToplevelInfo]) -> Vec<Item> {
|
||||
let cfg = ctx.cfg.borrow();
|
||||
@@ -459,7 +486,7 @@ pub fn refresh_items(ctx: &Rc<Ctx>) {
|
||||
}
|
||||
add_special_buttons(ctx, dock);
|
||||
for item in build_items(ctx, &dock.connector, &snapshot) {
|
||||
let widget = build_item_widget(ctx, Rc::new(item));
|
||||
let widget = build_item_widget(ctx, &dock.connector, Rc::new(item));
|
||||
dock.panel.append(&widget);
|
||||
}
|
||||
}
|
||||
@@ -496,7 +523,7 @@ fn add_special_buttons(ctx: &Rc<Ctx>, dock: &Rc<Dock>) {
|
||||
}
|
||||
}
|
||||
|
||||
fn build_item_widget(ctx: &Rc<Ctx>, item: Rc<Item>) -> gtk::Button {
|
||||
fn build_item_widget(ctx: &Rc<Ctx>, connector: &str, item: Rc<Item>) -> gtk::Button {
|
||||
let cfg = ctx.cfg.borrow();
|
||||
let icon_size = cfg.appearance.icon_size;
|
||||
let max_dots = cfg.appearance.indicator.max as usize;
|
||||
@@ -543,15 +570,23 @@ fn build_item_widget(ctx: &Rc<Ctx>, item: Rc<Item>) -> gtk::Button {
|
||||
btn.set_child(Some(&vbox));
|
||||
|
||||
if tooltips {
|
||||
let tip = match item.windows.len() {
|
||||
0 => item.meta.display_name.clone(),
|
||||
1 => {
|
||||
let t = &item.windows[0].title;
|
||||
if t.is_empty() { item.meta.display_name.clone() } else { t.clone() }
|
||||
}
|
||||
n => format!("{} — {n} fönster", item.meta.display_name),
|
||||
};
|
||||
btn.set_tooltip_text(Some(&tip));
|
||||
btn.set_has_tooltip(true);
|
||||
let ctx2 = ctx.clone();
|
||||
let item2 = item.clone();
|
||||
let conn2 = connector.to_string();
|
||||
btn.connect_query_tooltip(move |_, _, _, _, tooltip| {
|
||||
let windows = fresh_windows(&ctx2, &conn2, &item2.meta.key);
|
||||
let tip = match windows.len() {
|
||||
0 => item2.meta.display_name.clone(),
|
||||
1 => {
|
||||
let t = &windows[0].title;
|
||||
if t.is_empty() { item2.meta.display_name.clone() } else { t.clone() }
|
||||
}
|
||||
n => format!("{} — {n} fönster", item2.meta.display_name),
|
||||
};
|
||||
tooltip.set_text(Some(&tip));
|
||||
true
|
||||
});
|
||||
}
|
||||
|
||||
// klick: vänster/mitt/höger
|
||||
@@ -561,12 +596,14 @@ fn build_item_widget(ctx: &Rc<Ctx>, item: Rc<Item>) -> gtk::Button {
|
||||
let ctx = ctx.clone();
|
||||
let item = item.clone();
|
||||
let btn2 = btn.clone();
|
||||
let conn2 = connector.to_string();
|
||||
click.connect_released(move |gesture, _, _, _| {
|
||||
gesture.set_state(gtk::EventSequenceState::Claimed);
|
||||
let live = live_item(&ctx, &conn2, &item);
|
||||
match gesture.current_button() {
|
||||
1 => primary_action(&ctx, &item, &btn2),
|
||||
2 => middle_action(&ctx, &item),
|
||||
3 => menu::popup_item_menu(&ctx, &item, &btn2),
|
||||
1 => primary_action(&ctx, &live, &btn2),
|
||||
2 => middle_action(&ctx, &live),
|
||||
3 => menu::popup_item_menu(&ctx, &live, &btn2),
|
||||
_ => {}
|
||||
}
|
||||
});
|
||||
@@ -578,9 +615,11 @@ fn build_item_widget(ctx: &Rc<Ctx>, item: Rc<Item>) -> gtk::Button {
|
||||
{
|
||||
let ctx = ctx.clone();
|
||||
let item = item.clone();
|
||||
let conn2 = connector.to_string();
|
||||
scroll.connect_scroll(move |_, _, dy| {
|
||||
if ctx.cfg.borrow().behavior.scroll == ScrollAction::CycleWindows {
|
||||
cycle_windows(&ctx, &item, dy > 0.0);
|
||||
let live = live_item(&ctx, &conn2, &item);
|
||||
cycle_windows(&ctx, &live, dy > 0.0);
|
||||
glib::Propagation::Stop
|
||||
} else {
|
||||
glib::Propagation::Proceed
|
||||
|
||||
@@ -101,8 +101,24 @@ fn build_hotspot(
|
||||
win
|
||||
}
|
||||
|
||||
thread_local! {
|
||||
static LAST_SIGNATURE: std::cell::RefCell<String> =
|
||||
const { std::cell::RefCell::new(String::new()) };
|
||||
}
|
||||
|
||||
/// Bygg om alla hotspot-ytor enligt configen (körs vid start + configbyte).
|
||||
/// Idempotent: oförändrad hotspot-config + skärmuppsättning → ingen ombyggnad.
|
||||
pub fn rebuild(ctx: &Rc<Ctx>) {
|
||||
let n_monitors = gdk::Display::default()
|
||||
.map(|d| d.monitors().n_items())
|
||||
.unwrap_or(0);
|
||||
let signature = format!("{:?}|{n_monitors}", ctx.cfg.borrow().hotspots);
|
||||
let unchanged = LAST_SIGNATURE.with(|s| *s.borrow() == signature);
|
||||
if unchanged {
|
||||
return;
|
||||
}
|
||||
LAST_SIGNATURE.with(|s| *s.borrow_mut() = signature);
|
||||
|
||||
for win in ctx.hotspot_windows.borrow_mut().drain(..) {
|
||||
win.destroy();
|
||||
}
|
||||
|
||||
@@ -77,7 +77,7 @@ fn row(list: >k::Box, label: &str, widget: &impl IsA<gtk::Widget>) {
|
||||
|
||||
fn heading(list: >k::Box, text: &str) {
|
||||
let lbl = gtk::Label::new(None);
|
||||
lbl.set_markup(&format!("<b>{text}</b>"));
|
||||
lbl.set_markup(&format!("<b>{}</b>", glib::markup_escape_text(text)));
|
||||
lbl.set_halign(gtk::Align::Start);
|
||||
lbl.set_margin_top(10);
|
||||
list.append(&lbl);
|
||||
|
||||
@@ -43,6 +43,7 @@ struct ToplevelEntry {
|
||||
activated: bool,
|
||||
outputs: Vec<ObjectId>,
|
||||
initialized: bool, // första done har kommit
|
||||
changed: bool, // något UI-relevant ändrat sedan senaste done
|
||||
}
|
||||
|
||||
struct OutputEntry {
|
||||
@@ -169,6 +170,7 @@ impl Dispatch<ZwlrForeignToplevelManagerV1, ()> for WlState {
|
||||
activated: false,
|
||||
outputs: Vec::new(),
|
||||
initialized: false,
|
||||
changed: false,
|
||||
},
|
||||
));
|
||||
}
|
||||
@@ -199,9 +201,12 @@ impl Dispatch<ZwlrForeignToplevelHandleV1, ()> for WlState {
|
||||
Event::AppId { app_id } => {
|
||||
if let Some(e) = state.entry_mut(&id) {
|
||||
e.app_id = app_id;
|
||||
e.changed = true;
|
||||
}
|
||||
}
|
||||
Event::Title { title } => {
|
||||
// titlar byts hela tiden (webbläsare, terminaler) — spara
|
||||
// dem men bygg inte om UI:t; tooltips slås upp färskt ändå
|
||||
if let Some(e) = state.entry_mut(&id) {
|
||||
e.title = title;
|
||||
}
|
||||
@@ -209,11 +214,13 @@ impl Dispatch<ZwlrForeignToplevelHandleV1, ()> for WlState {
|
||||
Event::OutputEnter { output } => {
|
||||
if let Some(e) = state.entry_mut(&id) {
|
||||
e.outputs.push(output.id());
|
||||
e.changed = true;
|
||||
}
|
||||
}
|
||||
Event::OutputLeave { output } => {
|
||||
if let Some(e) = state.entry_mut(&id) {
|
||||
e.outputs.retain(|o| *o != output.id());
|
||||
e.changed = true;
|
||||
}
|
||||
}
|
||||
Event::State { state: raw } => {
|
||||
@@ -231,16 +238,26 @@ impl Dispatch<ZwlrForeignToplevelHandleV1, ()> for WlState {
|
||||
}
|
||||
}
|
||||
if let Some(e) = state.entry_mut(&id) {
|
||||
if e.minimized != min || e.maximized != max || e.activated != act {
|
||||
e.changed = true;
|
||||
}
|
||||
e.minimized = min;
|
||||
e.maximized = max;
|
||||
e.activated = act;
|
||||
}
|
||||
}
|
||||
Event::Done => {
|
||||
let mut mark_dirty = false;
|
||||
if let Some(e) = state.entry_mut(&id) {
|
||||
if !e.initialized || e.changed {
|
||||
mark_dirty = true;
|
||||
}
|
||||
e.initialized = true;
|
||||
e.changed = false;
|
||||
}
|
||||
if mark_dirty {
|
||||
state.dirty = true;
|
||||
}
|
||||
state.dirty = true;
|
||||
}
|
||||
Event::Closed => {
|
||||
state.toplevels.retain(|(tid, _)| *tid != id);
|
||||
|
||||
Reference in New Issue
Block a user