From b00b65b330036a88d9db23d47a594308efeb6812 Mon Sep 17 00:00:00 2001 From: Dzmitry Malyshau Date: Mon, 19 Feb 2024 17:54:54 -0800 Subject: [PATCH] linux/x11: implement window focus (#8002) Release Notes: - N/A --- crates/gpui/src/platform/linux/x11/client.rs | 20 +++++++++- crates/gpui/src/platform/linux/x11/window.rs | 41 +++++++++++++------- 2 files changed, 47 insertions(+), 14 deletions(-) diff --git a/crates/gpui/src/platform/linux/x11/client.rs b/crates/gpui/src/platform/linux/x11/client.rs index fca487fc3736a227efb450bfea7e309f711d6aef..6243851dc7b26366067529c7193afd4f8c8f2572 100644 --- a/crates/gpui/src/platform/linux/x11/client.rs +++ b/crates/gpui/src/platform/linux/x11/client.rs @@ -11,7 +11,8 @@ use crate::platform::{ LinuxPlatformInner, PlatformWindow, X11Display, X11Window, X11WindowState, XcbAtoms, }; use crate::{ - AnyWindowHandle, Bounds, DisplayId, PlatformDisplay, PlatformInput, Point, Size, WindowOptions, + AnyWindowHandle, Bounds, DisplayId, PlatformDisplay, PlatformInput, Point, ScrollDelta, Size, + TouchPhase, WindowOptions, }; pub(crate) struct X11ClientState { @@ -106,6 +107,14 @@ impl Client for X11Client { window.request_refresh(); } xcb::Event::Present(xcb::present::Event::IdleNotify(_ev)) => {} + xcb::Event::X(x::Event::FocusIn(ev)) => { + let window = self.get_window(ev.event()); + window.set_focused(true); + } + xcb::Event::X(x::Event::FocusOut(ev)) => { + let window = self.get_window(ev.event()); + window.set_focused(false); + } xcb::Event::X(x::Event::KeyPress(ev)) => { let window = self.get_window(ev.event()); let modifiers = super::modifiers_from_state(ev.state()); @@ -155,6 +164,15 @@ impl Client for X11Client { modifiers, click_count: 1, })); + } else if ev.detail() >= 4 && ev.detail() <= 5 { + // https://stackoverflow.com/questions/15510472/scrollwheel-event-in-x11 + let delta_x = if ev.detail() == 4 { 1.0 } else { -1.0 }; + window.handle_input(PlatformInput::ScrollWheel(crate::ScrollWheelEvent { + position, + delta: ScrollDelta::Lines(Point::new(0.0, delta_x)), + modifiers, + touch_phase: TouchPhase::default(), + })); } else { log::warn!("Unknown button press: {ev:?}"); } diff --git a/crates/gpui/src/platform/linux/x11/window.rs b/crates/gpui/src/platform/linux/x11/window.rs index b5904cd425de239496977287b2931609d29bac2d..2e225828860d95f7a4084970f70e095d33f2b46c 100644 --- a/crates/gpui/src/platform/linux/x11/window.rs +++ b/crates/gpui/src/platform/linux/x11/window.rs @@ -2,9 +2,9 @@ #![allow(unused)] use crate::{ - platform::blade::BladeRenderer, size, Bounds, GlobalPixels, Pixels, PlatformDisplay, - PlatformInput, PlatformInputHandler, PlatformWindow, Point, Size, WindowAppearance, - WindowBounds, WindowOptions, X11Display, + platform::blade::BladeRenderer, size, Bounds, GlobalPixels, Modifiers, Pixels, PlatformAtlas, + PlatformDisplay, PlatformInput, PlatformInputHandler, PlatformWindow, Point, PromptLevel, + Scene, Size, WindowAppearance, WindowBounds, WindowOptions, X11Display, }; use blade_graphics as gpu; use parking_lot::Mutex; @@ -27,7 +27,7 @@ use std::{ #[derive(Default)] struct Callbacks { request_frame: Option>, - input: Option bool>>, + input: Option bool>>, active_status_change: Option>, resize: Option, f32)>>, fullscreen: Option>, @@ -155,6 +155,9 @@ impl X11WindowState { x::Cw::EventMask( x::EventMask::EXPOSURE | x::EventMask::STRUCTURE_NOTIFY + | x::EventMask::ENTER_WINDOW + | x::EventMask::LEAVE_WINDOW + | x::EventMask::FOCUS_CHANGE | x::EventMask::KEY_PRESS | x::EventMask::KEY_RELEASE | x::EventMask::BUTTON_PRESS @@ -345,6 +348,12 @@ impl X11WindowState { } } } + + pub fn set_focused(&self, focus: bool) { + if let Some(ref mut fun) = self.callbacks.lock().active_status_change { + fun(focus); + } + } } impl PlatformWindow for X11Window { @@ -374,14 +383,20 @@ impl PlatformWindow for X11Window { Rc::clone(&self.0.display) } - //todo!(linux) fn mouse_position(&self) -> Point { - Point::default() + let cookie = self.0.xcb_connection.send_request(&x::QueryPointer { + window: self.0.x_window, + }); + let reply: x::QueryPointerReply = self.0.xcb_connection.wait_for_reply(cookie).unwrap(); + Point::new( + (reply.root_x() as u32).into(), + (reply.root_y() as u32).into(), + ) } //todo!(linux) - fn modifiers(&self) -> crate::Modifiers { - crate::Modifiers::default() + fn modifiers(&self) -> Modifiers { + Modifiers::default() } fn as_any_mut(&mut self) -> &mut dyn std::any::Any { @@ -399,7 +414,7 @@ impl PlatformWindow for X11Window { //todo!(linux) fn prompt( &self, - _level: crate::PromptLevel, + _level: PromptLevel, _msg: &str, _detail: Option<&str>, _answers: &[&str], @@ -456,7 +471,7 @@ impl PlatformWindow for X11Window { self.0.callbacks.lock().request_frame = Some(callback); } - fn on_input(&self, callback: Box bool>) { + fn on_input(&self, callback: Box bool>) { self.0.callbacks.lock().input = Some(callback); } @@ -489,16 +504,16 @@ impl PlatformWindow for X11Window { } //todo!(linux) - fn is_topmost_for_position(&self, _position: crate::Point) -> bool { + fn is_topmost_for_position(&self, _position: Point) -> bool { unimplemented!() } - fn draw(&self, scene: &crate::Scene) { + fn draw(&self, scene: &Scene) { let mut inner = self.0.inner.lock(); inner.renderer.draw(scene); } - fn sprite_atlas(&self) -> sync::Arc { + fn sprite_atlas(&self) -> sync::Arc { let inner = self.0.inner.lock(); inner.renderer.sprite_atlas().clone() }