logiguard fork v3: full patch set on verified 8c74db0 tree
Includes prior-session patches (carry forward so the app compiles): - crates/gpui/build.rs: cross-compile manifest fix - crates/gpui/src/platform.rs: PlatformWindow::activate_with_token trait method - crates/gpui/src/window.rs: Window::activate_with_token public API - crates/gpui_linux/src/linux/wayland/window.rs: WaylandWindow::activate_with_token + activate() keyboard-serial fix Plus the focus-serial fix: - serial.rs: SerialKind::KeyboardEnter - client.rs: store wl_keyboard.enter serial; latest_serial_of() Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
25
crates/session/Cargo.toml
Normal file
25
crates/session/Cargo.toml
Normal file
@@ -0,0 +1,25 @@
|
||||
[package]
|
||||
name = "session"
|
||||
version = "0.1.0"
|
||||
edition.workspace = true
|
||||
publish.workspace = true
|
||||
license = "GPL-3.0-or-later"
|
||||
|
||||
[lints]
|
||||
workspace = true
|
||||
|
||||
[lib]
|
||||
path = "src/session.rs"
|
||||
doctest = false
|
||||
|
||||
[features]
|
||||
test-support = [
|
||||
"db/test-support",
|
||||
]
|
||||
|
||||
[dependencies]
|
||||
db.workspace = true
|
||||
gpui.workspace = true
|
||||
uuid.workspace = true
|
||||
util.workspace = true
|
||||
serde_json.workspace = true
|
||||
1
crates/session/LICENSE-GPL
Symbolic link
1
crates/session/LICENSE-GPL
Symbolic link
@@ -0,0 +1 @@
|
||||
../../LICENSE-GPL
|
||||
149
crates/session/src/session.rs
Normal file
149
crates/session/src/session.rs
Normal file
@@ -0,0 +1,149 @@
|
||||
use db::kvp::KeyValueStore;
|
||||
use gpui::{App, AppContext as _, Context, Subscription, Task, WindowId};
|
||||
use util::ResultExt;
|
||||
|
||||
pub struct Session {
|
||||
session_id: String,
|
||||
old_session_id: Option<String>,
|
||||
old_window_ids: Option<Vec<WindowId>>,
|
||||
}
|
||||
|
||||
const SESSION_ID_KEY: &str = "session_id";
|
||||
const SESSION_WINDOW_STACK_KEY: &str = "session_window_stack";
|
||||
|
||||
impl Session {
|
||||
pub async fn new(session_id: String, db: KeyValueStore) -> Self {
|
||||
let old_session_id = db.read_kvp(SESSION_ID_KEY).ok().flatten();
|
||||
|
||||
db.write_kvp(SESSION_ID_KEY.to_string(), session_id.clone())
|
||||
.await
|
||||
.log_err();
|
||||
|
||||
let old_window_ids = db
|
||||
.read_kvp(SESSION_WINDOW_STACK_KEY)
|
||||
.ok()
|
||||
.flatten()
|
||||
.and_then(|json| serde_json::from_str::<Vec<u64>>(&json).ok())
|
||||
.map(|vec: Vec<u64>| {
|
||||
vec.into_iter()
|
||||
.map(WindowId::from)
|
||||
.collect::<Vec<WindowId>>()
|
||||
});
|
||||
|
||||
Self {
|
||||
session_id,
|
||||
old_session_id,
|
||||
old_window_ids,
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(any(test, feature = "test-support"))]
|
||||
pub fn test() -> Self {
|
||||
Self {
|
||||
session_id: uuid::Uuid::new_v4().to_string(),
|
||||
old_session_id: None,
|
||||
old_window_ids: None,
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(any(test, feature = "test-support"))]
|
||||
pub fn test_with_old_session(old_session_id: String) -> Self {
|
||||
Self {
|
||||
session_id: uuid::Uuid::new_v4().to_string(),
|
||||
old_session_id: Some(old_session_id),
|
||||
old_window_ids: None,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn id(&self) -> &str {
|
||||
&self.session_id
|
||||
}
|
||||
}
|
||||
|
||||
pub struct AppSession {
|
||||
session: Session,
|
||||
_serialization_task: Task<()>,
|
||||
_subscriptions: Vec<Subscription>,
|
||||
}
|
||||
|
||||
impl AppSession {
|
||||
pub fn new(session: Session, cx: &Context<Self>) -> Self {
|
||||
let _subscriptions = vec![cx.on_app_quit(Self::app_will_quit)];
|
||||
|
||||
#[cfg(not(any(test, feature = "test-support")))]
|
||||
let _serialization_task = {
|
||||
let db = KeyValueStore::global(cx);
|
||||
cx.spawn(async move |_, cx| {
|
||||
// Disabled in tests: the infinite loop bypasses "parking forbidden" checks,
|
||||
// causing tests to hang instead of panicking.
|
||||
{
|
||||
let mut current_window_stack = Vec::new();
|
||||
loop {
|
||||
if let Some(windows) = cx.update(|cx| window_stack(cx))
|
||||
&& windows != current_window_stack
|
||||
{
|
||||
store_window_stack(db.clone(), &windows).await;
|
||||
current_window_stack = windows;
|
||||
}
|
||||
|
||||
cx.background_executor()
|
||||
.timer(std::time::Duration::from_millis(500))
|
||||
.await;
|
||||
}
|
||||
}
|
||||
})
|
||||
};
|
||||
|
||||
#[cfg(any(test, feature = "test-support"))]
|
||||
let _serialization_task = Task::ready(());
|
||||
|
||||
Self {
|
||||
session,
|
||||
_subscriptions,
|
||||
_serialization_task,
|
||||
}
|
||||
}
|
||||
|
||||
fn app_will_quit(&mut self, cx: &mut Context<Self>) -> Task<()> {
|
||||
if let Some(window_stack) = window_stack(cx) {
|
||||
let db = KeyValueStore::global(cx);
|
||||
cx.background_spawn(async move { store_window_stack(db, &window_stack).await })
|
||||
} else {
|
||||
Task::ready(())
|
||||
}
|
||||
}
|
||||
|
||||
pub fn id(&self) -> &str {
|
||||
self.session.id()
|
||||
}
|
||||
|
||||
pub fn last_session_id(&self) -> Option<&str> {
|
||||
self.session.old_session_id.as_deref()
|
||||
}
|
||||
|
||||
#[cfg(any(test, feature = "test-support"))]
|
||||
pub fn replace_session_for_test(&mut self, session: Session) {
|
||||
self.session = session;
|
||||
}
|
||||
|
||||
pub fn last_session_window_stack(&self) -> Option<Vec<WindowId>> {
|
||||
self.session.old_window_ids.clone()
|
||||
}
|
||||
}
|
||||
|
||||
fn window_stack(cx: &App) -> Option<Vec<u64>> {
|
||||
Some(
|
||||
cx.window_stack()?
|
||||
.into_iter()
|
||||
.map(|window| window.window_id().as_u64())
|
||||
.collect(),
|
||||
)
|
||||
}
|
||||
|
||||
async fn store_window_stack(db: KeyValueStore, windows: &[u64]) {
|
||||
if let Ok(window_ids_json) = serde_json::to_string(windows) {
|
||||
db.write_kvp(SESSION_WINDOW_STACK_KEY.to_string(), window_ids_json)
|
||||
.await
|
||||
.log_err();
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user