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:
245
crates/platform_title_bar/src/platforms/platform_linux.rs
Normal file
245
crates/platform_title_bar/src/platforms/platform_linux.rs
Normal file
@@ -0,0 +1,245 @@
|
||||
use gpui::{
|
||||
Action, AnyElement, Hsla, MAX_BUTTONS_PER_SIDE, MouseButton, WindowButton, prelude::*, svg,
|
||||
};
|
||||
use ui::prelude::*;
|
||||
|
||||
#[derive(IntoElement)]
|
||||
pub struct LinuxWindowControls {
|
||||
id: &'static str,
|
||||
buttons: [Option<WindowButton>; MAX_BUTTONS_PER_SIDE],
|
||||
close_action: Box<dyn Action>,
|
||||
}
|
||||
|
||||
impl LinuxWindowControls {
|
||||
pub fn new(
|
||||
id: &'static str,
|
||||
buttons: [Option<WindowButton>; MAX_BUTTONS_PER_SIDE],
|
||||
close_action: Box<dyn Action>,
|
||||
) -> Self {
|
||||
Self {
|
||||
id,
|
||||
buttons,
|
||||
close_action,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl RenderOnce for LinuxWindowControls {
|
||||
fn render(self, window: &mut Window, cx: &mut App) -> impl IntoElement {
|
||||
let is_maximized = window.is_maximized();
|
||||
let supported_controls = window.window_controls();
|
||||
let button_elements: Vec<AnyElement> = self
|
||||
.buttons
|
||||
.iter()
|
||||
.filter_map(|b| *b)
|
||||
.filter(|button| match button {
|
||||
WindowButton::Minimize => supported_controls.minimize,
|
||||
WindowButton::Maximize => supported_controls.maximize,
|
||||
WindowButton::Close => true,
|
||||
})
|
||||
.map(|button| {
|
||||
create_window_button(button, button.id(), is_maximized, &*self.close_action, cx)
|
||||
})
|
||||
.collect();
|
||||
|
||||
h_flex()
|
||||
.id(self.id)
|
||||
.when(!button_elements.is_empty(), |el| {
|
||||
el.gap_3()
|
||||
.px_3()
|
||||
.on_mouse_down(MouseButton::Left, |_, _, cx| cx.stop_propagation())
|
||||
.children(button_elements)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
fn create_window_button(
|
||||
button: WindowButton,
|
||||
id: &'static str,
|
||||
is_maximized: bool,
|
||||
close_action: &dyn Action,
|
||||
cx: &mut App,
|
||||
) -> AnyElement {
|
||||
match button {
|
||||
WindowButton::Minimize => {
|
||||
WindowControl::new(id, WindowControlType::Minimize, cx).into_any_element()
|
||||
}
|
||||
WindowButton::Maximize => WindowControl::new(
|
||||
id,
|
||||
if is_maximized {
|
||||
WindowControlType::Restore
|
||||
} else {
|
||||
WindowControlType::Maximize
|
||||
},
|
||||
cx,
|
||||
)
|
||||
.into_any_element(),
|
||||
WindowButton::Close => {
|
||||
WindowControl::new_close(id, WindowControlType::Close, close_action.boxed_clone(), cx)
|
||||
.into_any_element()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, PartialEq, Eq, PartialOrd, Ord, Hash, Clone, Copy)]
|
||||
pub enum WindowControlType {
|
||||
Minimize,
|
||||
Restore,
|
||||
Maximize,
|
||||
Close,
|
||||
}
|
||||
|
||||
impl WindowControlType {
|
||||
/// Returns the icon name for the window control type.
|
||||
///
|
||||
/// Will take a [PlatformStyle] in the future to return a different
|
||||
/// icon name based on the platform.
|
||||
pub fn icon(&self) -> IconName {
|
||||
match self {
|
||||
WindowControlType::Minimize => IconName::GenericMinimize,
|
||||
WindowControlType::Restore => IconName::GenericRestore,
|
||||
WindowControlType::Maximize => IconName::GenericMaximize,
|
||||
WindowControlType::Close => IconName::GenericClose,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[allow(unused)]
|
||||
pub struct WindowControlStyle {
|
||||
background: Hsla,
|
||||
background_hover: Hsla,
|
||||
icon: Hsla,
|
||||
icon_hover: Hsla,
|
||||
}
|
||||
|
||||
impl WindowControlStyle {
|
||||
pub fn default(cx: &mut App) -> Self {
|
||||
let colors = cx.theme().colors();
|
||||
|
||||
Self {
|
||||
background: colors.ghost_element_background,
|
||||
background_hover: colors.ghost_element_hover,
|
||||
icon: colors.icon,
|
||||
icon_hover: colors.icon_muted,
|
||||
}
|
||||
}
|
||||
|
||||
#[allow(unused)]
|
||||
/// Sets the background color of the control.
|
||||
pub fn background(mut self, color: impl Into<Hsla>) -> Self {
|
||||
self.background = color.into();
|
||||
self
|
||||
}
|
||||
|
||||
#[allow(unused)]
|
||||
/// Sets the background color of the control when hovered.
|
||||
pub fn background_hover(mut self, color: impl Into<Hsla>) -> Self {
|
||||
self.background_hover = color.into();
|
||||
self
|
||||
}
|
||||
|
||||
#[allow(unused)]
|
||||
/// Sets the color of the icon.
|
||||
pub fn icon(mut self, color: impl Into<Hsla>) -> Self {
|
||||
self.icon = color.into();
|
||||
self
|
||||
}
|
||||
|
||||
#[allow(unused)]
|
||||
/// Sets the color of the icon when hovered.
|
||||
pub fn icon_hover(mut self, color: impl Into<Hsla>) -> Self {
|
||||
self.icon_hover = color.into();
|
||||
self
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(IntoElement)]
|
||||
pub struct WindowControl {
|
||||
id: ElementId,
|
||||
icon: WindowControlType,
|
||||
style: WindowControlStyle,
|
||||
close_action: Option<Box<dyn Action>>,
|
||||
}
|
||||
|
||||
impl WindowControl {
|
||||
pub fn new(id: impl Into<ElementId>, icon: WindowControlType, cx: &mut App) -> Self {
|
||||
let style = WindowControlStyle::default(cx);
|
||||
|
||||
Self {
|
||||
id: id.into(),
|
||||
icon,
|
||||
style,
|
||||
close_action: None,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn new_close(
|
||||
id: impl Into<ElementId>,
|
||||
icon: WindowControlType,
|
||||
close_action: Box<dyn Action>,
|
||||
cx: &mut App,
|
||||
) -> Self {
|
||||
let style = WindowControlStyle::default(cx);
|
||||
|
||||
Self {
|
||||
id: id.into(),
|
||||
icon,
|
||||
style,
|
||||
close_action: Some(close_action.boxed_clone()),
|
||||
}
|
||||
}
|
||||
|
||||
#[allow(unused)]
|
||||
pub fn custom_style(
|
||||
id: impl Into<ElementId>,
|
||||
icon: WindowControlType,
|
||||
style: WindowControlStyle,
|
||||
) -> Self {
|
||||
Self {
|
||||
id: id.into(),
|
||||
icon,
|
||||
style,
|
||||
close_action: None,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl RenderOnce for WindowControl {
|
||||
fn render(self, _window: &mut Window, _cx: &mut App) -> impl IntoElement {
|
||||
let icon = svg()
|
||||
.size_4()
|
||||
.flex_none()
|
||||
.path(self.icon.icon().path())
|
||||
.text_color(self.style.icon)
|
||||
.group_hover("", |this| this.text_color(self.style.icon_hover));
|
||||
|
||||
h_flex()
|
||||
.id(self.id)
|
||||
.group("")
|
||||
.cursor_pointer()
|
||||
.justify_center()
|
||||
.content_center()
|
||||
.rounded_2xl()
|
||||
.w_5()
|
||||
.h_5()
|
||||
.hover(|this| this.bg(self.style.background_hover))
|
||||
.active(|this| this.bg(self.style.background_hover))
|
||||
.child(icon)
|
||||
.on_mouse_move(|_, _, cx| cx.stop_propagation())
|
||||
.on_click(move |_, window, cx| {
|
||||
cx.stop_propagation();
|
||||
match self.icon {
|
||||
WindowControlType::Minimize => window.minimize_window(),
|
||||
WindowControlType::Restore => window.zoom_window(),
|
||||
WindowControlType::Maximize => window.zoom_window(),
|
||||
WindowControlType::Close => window.dispatch_action(
|
||||
self.close_action
|
||||
.as_ref()
|
||||
.expect("Use WindowControl::new_close() for close control.")
|
||||
.boxed_clone(),
|
||||
cx,
|
||||
),
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
137
crates/platform_title_bar/src/platforms/platform_windows.rs
Normal file
137
crates/platform_title_bar/src/platforms/platform_windows.rs
Normal file
@@ -0,0 +1,137 @@
|
||||
use gpui::{Hsla, Rgba, WindowControlArea, prelude::*};
|
||||
|
||||
use ui::prelude::*;
|
||||
|
||||
#[derive(IntoElement)]
|
||||
pub struct WindowsWindowControls {
|
||||
button_height: Pixels,
|
||||
}
|
||||
|
||||
impl WindowsWindowControls {
|
||||
pub fn new(button_height: Pixels) -> Self {
|
||||
Self { button_height }
|
||||
}
|
||||
|
||||
#[cfg(not(target_os = "windows"))]
|
||||
fn get_font() -> &'static str {
|
||||
"Segoe Fluent Icons"
|
||||
}
|
||||
|
||||
#[cfg(target_os = "windows")]
|
||||
fn get_font() -> &'static str {
|
||||
use windows::Wdk::System::SystemServices::RtlGetVersion;
|
||||
|
||||
let mut version = unsafe { std::mem::zeroed() };
|
||||
let status = unsafe { RtlGetVersion(&mut version) };
|
||||
|
||||
if status.is_ok() && version.dwBuildNumber >= 22000 {
|
||||
"Segoe Fluent Icons"
|
||||
} else {
|
||||
"Segoe MDL2 Assets"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl RenderOnce for WindowsWindowControls {
|
||||
fn render(self, window: &mut Window, _: &mut App) -> impl IntoElement {
|
||||
div()
|
||||
.id("windows-window-controls")
|
||||
.font_family(Self::get_font())
|
||||
.flex()
|
||||
.flex_row()
|
||||
.justify_center()
|
||||
.content_stretch()
|
||||
.max_h(self.button_height)
|
||||
.min_h(self.button_height)
|
||||
.child(WindowsCaptionButton::Minimize)
|
||||
.map(|this| {
|
||||
this.child(if window.is_maximized() {
|
||||
WindowsCaptionButton::Restore
|
||||
} else {
|
||||
WindowsCaptionButton::Maximize
|
||||
})
|
||||
})
|
||||
.child(WindowsCaptionButton::Close)
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(IntoElement)]
|
||||
enum WindowsCaptionButton {
|
||||
Minimize,
|
||||
Restore,
|
||||
Maximize,
|
||||
Close,
|
||||
}
|
||||
|
||||
impl WindowsCaptionButton {
|
||||
#[inline]
|
||||
fn id(&self) -> &'static str {
|
||||
match self {
|
||||
Self::Minimize => "minimize",
|
||||
Self::Restore => "restore",
|
||||
Self::Maximize => "maximize",
|
||||
Self::Close => "close",
|
||||
}
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn icon(&self) -> &'static str {
|
||||
match self {
|
||||
Self::Minimize => "\u{e921}",
|
||||
Self::Restore => "\u{e923}",
|
||||
Self::Maximize => "\u{e922}",
|
||||
Self::Close => "\u{e8bb}",
|
||||
}
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn control_area(&self) -> WindowControlArea {
|
||||
match self {
|
||||
Self::Close => WindowControlArea::Close,
|
||||
Self::Maximize | Self::Restore => WindowControlArea::Max,
|
||||
Self::Minimize => WindowControlArea::Min,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl RenderOnce for WindowsCaptionButton {
|
||||
fn render(self, _: &mut Window, cx: &mut App) -> impl IntoElement {
|
||||
let (hover_bg, hover_fg, active_bg, active_fg) = match self {
|
||||
Self::Close => {
|
||||
let color: Hsla = Rgba {
|
||||
r: 232.0 / 255.0,
|
||||
g: 17.0 / 255.0,
|
||||
b: 32.0 / 255.0,
|
||||
a: 1.0,
|
||||
}
|
||||
.into();
|
||||
|
||||
(
|
||||
color,
|
||||
gpui::white(),
|
||||
color.opacity(0.8),
|
||||
gpui::white().opacity(0.8),
|
||||
)
|
||||
}
|
||||
_ => (
|
||||
cx.theme().colors().ghost_element_hover,
|
||||
cx.theme().colors().text,
|
||||
cx.theme().colors().ghost_element_active,
|
||||
cx.theme().colors().text,
|
||||
),
|
||||
};
|
||||
|
||||
h_flex()
|
||||
.id(self.id())
|
||||
.justify_center()
|
||||
.content_center()
|
||||
.occlude()
|
||||
.w(px(36.))
|
||||
.h_full()
|
||||
.text_size(px(10.0))
|
||||
.hover(|style| style.bg(hover_bg).text_color(hover_fg))
|
||||
.active(|style| style.bg(active_bg).text_color(active_fg))
|
||||
.window_control_area(self.control_area())
|
||||
.child(self.icon())
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user