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

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:
Mohamad Khani
2026-07-14 02:22:17 +03:30
commit b72a46db68
3984 changed files with 1583326 additions and 0 deletions

View 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,
),
}
})
}
}

View 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())
}
}