generated from eblume/project-template
Compare commits
4 commits
feature/cl
...
main
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
b34371af87 | ||
| 17dab0e281 | |||
| 470ef1de0e | |||
| aec807fd28 |
5 changed files with 63 additions and 2 deletions
|
|
@ -12,6 +12,14 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/).
|
||||||
|
|
||||||
<!-- towncrier release notes start -->
|
<!-- towncrier release notes start -->
|
||||||
|
|
||||||
|
## [v1.4.1] - 2026-06-08
|
||||||
|
|
||||||
|
### Bug Fixes
|
||||||
|
|
||||||
|
- The `heph` CLI and `heph-tui` now survive a daemon restart. Previously the unix-socket client connected once and never reconnected, so an opt-in self-update or `heph daemon restart` left every subsequent call failing — `heph-tui` would sit on errors until relaunched. The client now reconnects on a dropped socket: a request that never went out is retried transparently, while a reply lost mid-request is surfaced (not silently retried) so a mutation is never double-applied. A long-running TUI self-heals on its next refresh tick.
|
||||||
|
- Quick-add popover (⌘'): hand keyboard focus back to the previously active app when it hides, and stop the (now invisible) overlay from intercepting clicks where it used to sit.
|
||||||
|
|
||||||
|
|
||||||
## [v1.4.0] - 2026-06-08
|
## [v1.4.0] - 2026-06-08
|
||||||
|
|
||||||
### Features
|
### Features
|
||||||
|
|
|
||||||
2
Cargo.lock
generated
2
Cargo.lock
generated
|
|
@ -2237,6 +2237,8 @@ dependencies = [
|
||||||
"heph-core",
|
"heph-core",
|
||||||
"hephd",
|
"hephd",
|
||||||
"libc",
|
"libc",
|
||||||
|
"objc2 0.6.4",
|
||||||
|
"objc2-app-kit 0.3.2",
|
||||||
"serde_json",
|
"serde_json",
|
||||||
"winit",
|
"winit",
|
||||||
]
|
]
|
||||||
|
|
|
||||||
|
|
@ -19,7 +19,16 @@ global-hotkey = "0.8"
|
||||||
|
|
||||||
# macOS-only: winit for the accessory-mode activation policy (no Dock icon),
|
# macOS-only: winit for the accessory-mode activation policy (no Dock icon),
|
||||||
# pinned to the same minor eframe carries so cargo unifies to one winit; libc
|
# pinned to the same minor eframe carries so cargo unifies to one winit; libc
|
||||||
# for getppid() (orphan detection — self-exit when the supervising daemon dies).
|
# for getppid() (orphan detection — self-exit when the supervising daemon dies);
|
||||||
|
# objc2 + objc2-app-kit to hand keyboard focus back to the previously active app
|
||||||
|
# when the popover hides (NSApplication.hide:/unhide:). Pinned to the 0.6/0.3
|
||||||
|
# line global-hotkey already pulls in, so cargo unifies to one copy.
|
||||||
[target.'cfg(target_os = "macos")'.dependencies]
|
[target.'cfg(target_os = "macos")'.dependencies]
|
||||||
winit = "0.30"
|
winit = "0.30"
|
||||||
libc = "0.2"
|
libc = "0.2"
|
||||||
|
objc2 = "0.6"
|
||||||
|
objc2-app-kit = { version = "0.3", default-features = false, features = [
|
||||||
|
"std",
|
||||||
|
"NSApplication",
|
||||||
|
"NSResponder",
|
||||||
|
] }
|
||||||
|
|
|
||||||
|
|
@ -226,6 +226,9 @@ impl QuickAdd {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn show(&mut self, ctx: &egui::Context) {
|
fn show(&mut self, ctx: &egui::Context) {
|
||||||
|
// Undo the app-level hide from the previous `hide()` so we can take focus
|
||||||
|
// again (no-op the first time / off macOS).
|
||||||
|
app_take_focus();
|
||||||
self.visible = true;
|
self.visible = true;
|
||||||
self.focus_pending = true;
|
self.focus_pending = true;
|
||||||
self.current_hint = random_hint(self.current_hint);
|
self.current_hint = random_hint(self.current_hint);
|
||||||
|
|
@ -256,6 +259,13 @@ impl QuickAdd {
|
||||||
ctx.send_viewport_cmd(egui::ViewportCommand::InnerSize(egui::vec2(WIN_W, BASE_H)));
|
ctx.send_viewport_cmd(egui::ViewportCommand::InnerSize(egui::vec2(WIN_W, BASE_H)));
|
||||||
self.win_h_applied = BASE_H;
|
self.win_h_applied = BASE_H;
|
||||||
}
|
}
|
||||||
|
// Hand keyboard focus back to the app underneath us. winit's
|
||||||
|
// `Visible(false)` alone leaves *us* the active application, so focus
|
||||||
|
// never returns and the borderless always-on-top overlay can keep eating
|
||||||
|
// clicks where it used to sit. `NSApplication.hide:` orders our windows
|
||||||
|
// fully out and activates the next app in line — exactly the one the user
|
||||||
|
// was in (no-op off macOS).
|
||||||
|
app_yield_focus();
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Optimistic submit: hide now, create in the background.
|
/// Optimistic submit: hide now, create in the background.
|
||||||
|
|
@ -596,6 +606,39 @@ impl QuickAdd {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Hide the popover at the *application* level so macOS hands keyboard focus
|
||||||
|
/// back to the previously active app. `NSApplication.hide:` orders all our
|
||||||
|
/// windows out and activates the next app in line — the one the user was in —
|
||||||
|
/// which a plain winit `Visible(false)` does not do. No-op off macOS.
|
||||||
|
#[cfg(target_os = "macos")]
|
||||||
|
fn app_yield_focus() {
|
||||||
|
use objc2::MainThreadMarker;
|
||||||
|
use objc2_app_kit::NSApplication;
|
||||||
|
// eframe's `update` runs on the main thread, so this marker is always Some.
|
||||||
|
if let Some(mtm) = MainThreadMarker::new() {
|
||||||
|
NSApplication::sharedApplication(mtm).hide(None);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(not(target_os = "macos"))]
|
||||||
|
fn app_yield_focus() {}
|
||||||
|
|
||||||
|
/// Undo [`app_yield_focus`]: clear the app-level hidden flag before re-showing,
|
||||||
|
/// so the window the viewport `Focus` command then makes key actually appears.
|
||||||
|
/// (`unhide:` also re-activates us; the per-window `Focus`/`Visible` viewport
|
||||||
|
/// commands do the rest.) No-op off macOS.
|
||||||
|
#[cfg(target_os = "macos")]
|
||||||
|
fn app_take_focus() {
|
||||||
|
use objc2::MainThreadMarker;
|
||||||
|
use objc2_app_kit::NSApplication;
|
||||||
|
if let Some(mtm) = MainThreadMarker::new() {
|
||||||
|
NSApplication::sharedApplication(mtm).unhide(None);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(not(target_os = "macos"))]
|
||||||
|
fn app_take_focus() {}
|
||||||
|
|
||||||
/// The current parent process id, for orphan detection. `None` off macOS (where
|
/// The current parent process id, for orphan detection. `None` off macOS (where
|
||||||
/// hephd does not supervise a helper — there is no Aqua session to inherit).
|
/// hephd does not supervise a helper — there is no Aqua session to inherit).
|
||||||
fn current_parent_pid() -> Option<i32> {
|
fn current_parent_pid() -> Option<i32> {
|
||||||
|
|
|
||||||
|
|
@ -1 +0,0 @@
|
||||||
The `heph` CLI and `heph-tui` now survive a daemon restart. Previously the unix-socket client connected once and never reconnected, so an opt-in self-update or `heph daemon restart` left every subsequent call failing — `heph-tui` would sit on errors until relaunched. The client now reconnects on a dropped socket: a request that never went out is retried transparently, while a reply lost mid-request is surfaced (not silently retried) so a mutation is never double-applied. A long-running TUI self-heals on its next refresh tick.
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue