logiguard fork: GPUI xdg-activation keyboard-focus serial fix
Some checks failed
Update All Top Ranking Issues / update_top_ranking_issues (push) Has been cancelled
Triage Project Sync (#84) / Sync triage project (push) Has been cancelled
release_nightly / notify_on_failure (push) Has been cancelled
release_nightly / check_style (push) Has been cancelled
release_nightly / run_tests_windows (push) Has been cancelled
release_nightly / clippy_windows (push) Has been cancelled
release_nightly / bundle_linux_aarch64 (push) Has been cancelled
release_nightly / bundle_linux_x86_64 (push) Has been cancelled
release_nightly / bundle_mac_aarch64 (push) Has been cancelled
release_nightly / bundle_mac_x86_64 (push) Has been cancelled
release_nightly / bundle_windows_aarch64 (push) Has been cancelled
release_nightly / bundle_windows_x86_64 (push) Has been cancelled
release_nightly / build_nix_linux_x86_64 (push) Has been cancelled
release_nightly / build_nix_mac_aarch64 (push) Has been cancelled
release_nightly / update_nightly_tag (push) Has been cancelled
Hotfix Review Monitor / check-hotfix-reviews (push) Has been cancelled
Stale PR Review Reminder / check-stale-prs (push) Has been cancelled
Update Weekly Top Ranking Issues / update_top_ranking_issues (push) Has been cancelled
Bump collab-staging Tag / update-collab-staging-tag (push) Has been cancelled
compliance_check / scheduled_compliance_check (push) Has been cancelled
Some checks failed
Update All Top Ranking Issues / update_top_ranking_issues (push) Has been cancelled
Triage Project Sync (#84) / Sync triage project (push) Has been cancelled
release_nightly / notify_on_failure (push) Has been cancelled
release_nightly / check_style (push) Has been cancelled
release_nightly / run_tests_windows (push) Has been cancelled
release_nightly / clippy_windows (push) Has been cancelled
release_nightly / bundle_linux_aarch64 (push) Has been cancelled
release_nightly / bundle_linux_x86_64 (push) Has been cancelled
release_nightly / bundle_mac_aarch64 (push) Has been cancelled
release_nightly / bundle_mac_x86_64 (push) Has been cancelled
release_nightly / bundle_windows_aarch64 (push) Has been cancelled
release_nightly / bundle_windows_x86_64 (push) Has been cancelled
release_nightly / build_nix_linux_x86_64 (push) Has been cancelled
release_nightly / build_nix_mac_aarch64 (push) Has been cancelled
release_nightly / update_nightly_tag (push) Has been cancelled
Hotfix Review Monitor / check-hotfix-reviews (push) Has been cancelled
Stale PR Review Reminder / check-stale-prs (push) Has been cancelled
Update Weekly Top Ranking Issues / update_top_ranking_issues (push) Has been cancelled
Bump collab-staging Tag / update-collab-staging-tag (push) Has been cancelled
compliance_check / scheduled_compliance_check (push) Has been cancelled
Single-commit orphan branch: full zed-industries/zed @ 8c74db0 source tree with a 3-file patch applied (no upstream history). Patch (crates/gpui_linux/src/linux/wayland/): - serial.rs: add SerialKind::KeyboardEnter - client.rs: store wl_keyboard.enter serial; add latest_serial_of() - window.rs: activate() uses keyboard-enter serial (Mutter focus gate) Mutter honors window activation only when the token carries the keyboard- focus serial from wl_keyboard.enter; GPUI used a stale mouse-press serial. See docs/tray-window-focus-wayland.md in logiguard. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
24
crates/ui_prompt/Cargo.toml
Normal file
24
crates/ui_prompt/Cargo.toml
Normal file
@@ -0,0 +1,24 @@
|
||||
[package]
|
||||
name = "ui_prompt"
|
||||
version = "0.1.0"
|
||||
edition.workspace = true
|
||||
publish.workspace = true
|
||||
license = "GPL-3.0-or-later"
|
||||
|
||||
[lints]
|
||||
workspace = true
|
||||
|
||||
[lib]
|
||||
path = "src/ui_prompt.rs"
|
||||
|
||||
[features]
|
||||
default = []
|
||||
|
||||
[dependencies]
|
||||
gpui.workspace = true
|
||||
markdown.workspace = true
|
||||
menu.workspace = true
|
||||
settings.workspace = true
|
||||
theme_settings.workspace = true
|
||||
ui.workspace = true
|
||||
workspace.workspace = true
|
||||
1
crates/ui_prompt/LICENSE-GPL
Symbolic link
1
crates/ui_prompt/LICENSE-GPL
Symbolic link
@@ -0,0 +1 @@
|
||||
../../LICENSE-GPL
|
||||
205
crates/ui_prompt/src/ui_prompt.rs
Normal file
205
crates/ui_prompt/src/ui_prompt.rs
Normal file
@@ -0,0 +1,205 @@
|
||||
use gpui::{
|
||||
App, Entity, EventEmitter, FocusHandle, Focusable, PromptButton, PromptHandle, PromptLevel,
|
||||
PromptResponse, RenderablePromptHandle, SharedString, TextStyleRefinement, Window, div,
|
||||
prelude::*,
|
||||
};
|
||||
use markdown::{Markdown, MarkdownElement, MarkdownStyle};
|
||||
use settings::{Settings, SettingsStore};
|
||||
use theme_settings::ThemeSettings;
|
||||
use ui::{FluentBuilder, TintColor, prelude::*};
|
||||
use workspace::WorkspaceSettings;
|
||||
|
||||
pub fn init(cx: &mut App) {
|
||||
process_settings(cx);
|
||||
|
||||
cx.observe_global::<SettingsStore>(process_settings)
|
||||
.detach();
|
||||
}
|
||||
|
||||
fn process_settings(cx: &mut App) {
|
||||
let settings = WorkspaceSettings::get_global(cx);
|
||||
if settings.use_system_prompts && cfg!(not(any(target_os = "linux", target_os = "freebsd"))) {
|
||||
cx.reset_prompt_builder();
|
||||
} else {
|
||||
cx.set_prompt_builder(zed_prompt_renderer);
|
||||
}
|
||||
}
|
||||
|
||||
/// Use this function in conjunction with [App::set_prompt_builder] to force
|
||||
/// GPUI to use the internal prompt system.
|
||||
fn zed_prompt_renderer(
|
||||
level: PromptLevel,
|
||||
message: &str,
|
||||
detail: Option<&str>,
|
||||
actions: &[PromptButton],
|
||||
handle: PromptHandle,
|
||||
window: &mut Window,
|
||||
cx: &mut App,
|
||||
) -> RenderablePromptHandle {
|
||||
let renderer = cx.new({
|
||||
|cx| ZedPromptRenderer {
|
||||
_level: level,
|
||||
message: cx.new(|cx| Markdown::new(SharedString::new(message), None, None, cx)),
|
||||
actions: actions.iter().map(|a| a.label().to_string()).collect(),
|
||||
focus: cx.focus_handle(),
|
||||
active_action_id: 0,
|
||||
detail: detail
|
||||
.filter(|text| !text.is_empty())
|
||||
.map(|text| cx.new(|cx| Markdown::new(SharedString::new(text), None, None, cx))),
|
||||
}
|
||||
});
|
||||
|
||||
handle.with_view(renderer, window, cx)
|
||||
}
|
||||
|
||||
pub struct ZedPromptRenderer {
|
||||
_level: PromptLevel,
|
||||
message: Entity<Markdown>,
|
||||
actions: Vec<String>,
|
||||
focus: FocusHandle,
|
||||
active_action_id: usize,
|
||||
detail: Option<Entity<Markdown>>,
|
||||
}
|
||||
|
||||
impl ZedPromptRenderer {
|
||||
fn confirm(&mut self, _: &menu::Confirm, _window: &mut Window, cx: &mut Context<Self>) {
|
||||
cx.emit(PromptResponse(self.active_action_id));
|
||||
}
|
||||
|
||||
fn cancel(&mut self, _: &menu::Cancel, _window: &mut Window, cx: &mut Context<Self>) {
|
||||
if let Some(ix) = self.actions.iter().position(|a| a == "Cancel") {
|
||||
cx.emit(PromptResponse(ix));
|
||||
}
|
||||
}
|
||||
|
||||
fn select_first(
|
||||
&mut self,
|
||||
_: &menu::SelectFirst,
|
||||
_window: &mut Window,
|
||||
cx: &mut Context<Self>,
|
||||
) {
|
||||
self.active_action_id = self.actions.len().saturating_sub(1);
|
||||
cx.notify();
|
||||
}
|
||||
|
||||
fn select_last(&mut self, _: &menu::SelectLast, _window: &mut Window, cx: &mut Context<Self>) {
|
||||
self.active_action_id = 0;
|
||||
cx.notify();
|
||||
}
|
||||
|
||||
fn select_next(&mut self, _: &menu::SelectNext, _window: &mut Window, cx: &mut Context<Self>) {
|
||||
self.active_action_id = (self.active_action_id + 1) % self.actions.len();
|
||||
cx.notify();
|
||||
}
|
||||
|
||||
fn select_previous(
|
||||
&mut self,
|
||||
_: &menu::SelectPrevious,
|
||||
_window: &mut Window,
|
||||
cx: &mut Context<Self>,
|
||||
) {
|
||||
if self.active_action_id > 0 {
|
||||
self.active_action_id -= 1;
|
||||
} else {
|
||||
self.active_action_id = self.actions.len().saturating_sub(1);
|
||||
}
|
||||
cx.notify();
|
||||
}
|
||||
}
|
||||
|
||||
impl Render for ZedPromptRenderer {
|
||||
fn render(&mut self, window: &mut Window, cx: &mut Context<Self>) -> impl IntoElement {
|
||||
let settings = ThemeSettings::get_global(cx);
|
||||
|
||||
let dialog = v_flex()
|
||||
.key_context("Prompt")
|
||||
.cursor_default()
|
||||
.track_focus(&self.focus)
|
||||
.on_action(cx.listener(Self::confirm))
|
||||
.on_action(cx.listener(Self::cancel))
|
||||
.on_action(cx.listener(Self::select_next))
|
||||
.on_action(cx.listener(Self::select_previous))
|
||||
.on_action(cx.listener(Self::select_first))
|
||||
.on_action(cx.listener(Self::select_last))
|
||||
.w_80()
|
||||
.p_4()
|
||||
.gap_4()
|
||||
.elevation_3(cx)
|
||||
.overflow_hidden()
|
||||
.font_family(settings.ui_font.family.clone())
|
||||
.child(div().w_full().child(MarkdownElement::new(
|
||||
self.message.clone(),
|
||||
markdown_style(true, window, cx),
|
||||
)))
|
||||
.children(self.detail.clone().map(|detail| {
|
||||
div().w_full().text_xs().child(MarkdownElement::new(
|
||||
detail,
|
||||
markdown_style(false, window, cx),
|
||||
))
|
||||
}))
|
||||
.child(
|
||||
v_flex()
|
||||
.gap_1()
|
||||
.children(self.actions.iter().enumerate().map(|(ix, action)| {
|
||||
Button::new(ix, action.clone())
|
||||
.full_width()
|
||||
.style(ButtonStyle::Outlined)
|
||||
.when(ix == self.active_action_id, |s| {
|
||||
s.style(ButtonStyle::Tinted(TintColor::Accent))
|
||||
})
|
||||
.tab_index(ix as isize)
|
||||
.on_click(cx.listener(move |_, _, _window, cx| {
|
||||
cx.emit(PromptResponse(ix));
|
||||
}))
|
||||
})),
|
||||
);
|
||||
|
||||
div()
|
||||
.size_full()
|
||||
.occlude()
|
||||
.bg(gpui::black().opacity(0.2))
|
||||
.child(
|
||||
v_flex()
|
||||
.size_full()
|
||||
.absolute()
|
||||
.top_0()
|
||||
.left_0()
|
||||
.items_center()
|
||||
.justify_center()
|
||||
.child(dialog),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
fn markdown_style(main_message: bool, window: &Window, cx: &App) -> MarkdownStyle {
|
||||
let mut base_text_style = window.text_style();
|
||||
let settings = ThemeSettings::get_global(cx);
|
||||
let font_size = settings.ui_font_size(cx).into();
|
||||
|
||||
let color = if main_message {
|
||||
Color::Default.color(cx)
|
||||
} else {
|
||||
Color::Muted.color(cx)
|
||||
};
|
||||
|
||||
base_text_style.refine(&TextStyleRefinement {
|
||||
font_family: Some(settings.ui_font.family.clone()),
|
||||
font_size: Some(font_size),
|
||||
color: Some(color),
|
||||
..Default::default()
|
||||
});
|
||||
|
||||
MarkdownStyle {
|
||||
base_text_style,
|
||||
selection_background_color: cx.theme().colors().element_selection_background,
|
||||
..Default::default()
|
||||
}
|
||||
}
|
||||
|
||||
impl EventEmitter<PromptResponse> for ZedPromptRenderer {}
|
||||
|
||||
impl Focusable for ZedPromptRenderer {
|
||||
fn focus_handle(&self, _: &crate::App) -> FocusHandle {
|
||||
self.focus.clone()
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user