Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

wayland: Window controls and drag #11525

Merged
merged 10 commits into from
May 14, 2024
7 changes: 5 additions & 2 deletions crates/collab_ui/src/collab_titlebar_item.rs
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,7 @@ impl Render for CollabTitlebarItem {
let project_id = self.project.read(cx).remote_id();
let workspace = self.workspace.upgrade();

TitleBar::new("collab-titlebar")
TitleBar::new("collab-titlebar", Box::new(workspace::CloseWindow))
// note: on windows titlebar behaviour is handled by the platform implementation
.when(cfg!(not(windows)), |this| {
this.on_click(|event, cx| {
Expand All @@ -73,7 +73,8 @@ impl Render for CollabTitlebarItem {
.gap_1()
.children(self.render_project_host(cx))
.child(self.render_project_name(cx))
.children(self.render_project_branch(cx)),
.children(self.render_project_branch(cx))
.on_mouse_move(|_, cx| cx.stop_propagation()),
)
.child(
h_flex()
Expand Down Expand Up @@ -105,6 +106,7 @@ impl Render for CollabTitlebarItem {

this.children(current_user_face_pile.map(|face_pile| {
v_flex()
.on_mouse_move(|_, cx| cx.stop_propagation())
.child(face_pile)
.child(render_color_ribbon(player_colors.local().cursor))
}))
Expand Down Expand Up @@ -167,6 +169,7 @@ impl Render for CollabTitlebarItem {
h_flex()
.gap_1()
.pr_1()
.on_mouse_move(|_, cx| cx.stop_propagation())
.when_some(room, |this, room| {
let room = room.read(cx);
let project = self.project.read(cx);
Expand Down
4 changes: 4 additions & 0 deletions crates/gpui/src/platform.rs
Original file line number Diff line number Diff line change
Expand Up @@ -226,6 +226,10 @@ pub(crate) trait PlatformWindow: HasWindowHandle + HasDisplayHandle {
#[cfg(target_os = "windows")]
fn get_raw_handle(&self) -> windows::HWND;

fn show_window_menu(&self, position: Point<Pixels>);
fn start_system_move(&self);
fn should_render_window_controls(&self) -> bool;

#[cfg(any(test, feature = "test-support"))]
fn as_test(&mut self) -> Option<&mut TestWindow> {
None
Expand Down
17 changes: 16 additions & 1 deletion crates/gpui/src/platform/linux/wayland/client.rs
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ use wayland_client::globals::{registry_queue_init, GlobalList, GlobalListContent
use wayland_client::protocol::wl_callback::{self, WlCallback};
use wayland_client::protocol::wl_data_device_manager::DndAction;
use wayland_client::protocol::wl_pointer::{AxisRelativeDirection, AxisSource};
use wayland_client::protocol::wl_seat::WlSeat;
use wayland_client::protocol::{
wl_data_device, wl_data_device_manager, wl_data_offer, wl_data_source, wl_output, wl_region,
};
Expand Down Expand Up @@ -80,6 +81,7 @@ pub struct Globals {
pub data_device_manager: Option<wl_data_device_manager::WlDataDeviceManager>,
pub wm_base: xdg_wm_base::XdgWmBase,
pub shm: wl_shm::WlShm,
pub seat: wl_seat::WlSeat,
pub viewporter: Option<wp_viewporter::WpViewporter>,
pub fractional_scale_manager:
Option<wp_fractional_scale_manager_v1::WpFractionalScaleManagerV1>,
Expand All @@ -93,6 +95,7 @@ impl Globals {
globals: GlobalList,
executor: ForegroundExecutor,
qh: QueueHandle<WaylandClientStatePtr>,
seat: wl_seat::WlSeat,
) -> Self {
Globals {
activation: globals.bind(&qh, 1..=1, ()).ok(),
Expand All @@ -113,6 +116,7 @@ impl Globals {
)
.ok(),
shm: globals.bind(&qh, 1..=1, ()).unwrap(),
seat,
wm_base: globals.bind(&qh, 1..=1, ()).unwrap(),
viewporter: globals.bind(&qh, 1..=1, ()).ok(),
fractional_scale_manager: globals.bind(&qh, 1..=1, ()).ok(),
Expand Down Expand Up @@ -193,6 +197,10 @@ impl WaylandClientStatePtr {
.expect("The pointer should always be valid when dispatching in wayland")
}

pub fn get_serial(&self, kind: SerialKind) -> u32 {
self.0.upgrade().unwrap().borrow().serial_tracker.get(kind)
}

pub fn drop_window(&self, surface_id: &ObjectId) {
let mut client = self.get_client();
let mut state = client.borrow_mut();
Expand Down Expand Up @@ -303,7 +311,12 @@ impl WaylandClient {
});

let seat = seat.unwrap();
let globals = Globals::new(globals, common.foreground_executor.clone(), qh.clone());
let globals = Globals::new(
globals,
common.foreground_executor.clone(),
qh.clone(),
seat.clone(),
);

let data_device = globals
.data_device_manager
Expand Down Expand Up @@ -962,6 +975,7 @@ impl Dispatch<wl_pointer::WlPointer, ()> for WaylandClientStatePtr {
} => {
state.serial_tracker.update(SerialKind::MouseEnter, serial);
state.mouse_location = Some(point(px(surface_x as f32), px(surface_y as f32)));
state.button_pressed = None;

if let Some(window) = get_window(&mut state, &surface.id()) {
state.mouse_focused_window = Some(window.clone());
Expand Down Expand Up @@ -990,6 +1004,7 @@ impl Dispatch<wl_pointer::WlPointer, ()> for WaylandClientStatePtr {
});
state.mouse_focused_window = None;
state.mouse_location = None;
state.button_pressed = None;

drop(state);
focused_window.handle_input(input);
Expand Down
26 changes: 24 additions & 2 deletions crates/gpui/src/platform/linux/wayland/window.rs
Original file line number Diff line number Diff line change
Expand Up @@ -23,12 +23,13 @@ use wayland_protocols_plasma::blur::client::{org_kde_kwin_blur, org_kde_kwin_blu

use crate::platform::blade::{BladeRenderer, BladeSurfaceConfig};
use crate::platform::linux::wayland::display::WaylandDisplay;
use crate::platform::linux::wayland::serial::SerialKind;
use crate::platform::{PlatformAtlas, PlatformInputHandler, PlatformWindow};
use crate::scene::Scene;
use crate::{
px, size, Bounds, DevicePixels, Globals, Modifiers, Pixels, PlatformDisplay, PlatformInput,
Point, PromptLevel, Size, WaylandClientState, WaylandClientStatePtr, WindowAppearance,
WindowBackgroundAppearance, WindowBounds, WindowParams,
Point, PromptLevel, Size, WaylandClientStatePtr, WindowAppearance, WindowBackgroundAppearance,
WindowBounds, WindowParams,
};

#[derive(Default)]
Expand Down Expand Up @@ -753,6 +754,27 @@ impl PlatformWindow for WaylandWindow {
let state = self.borrow();
state.renderer.sprite_atlas().clone()
}

fn show_window_menu(&self, position: Point<Pixels>) {
let state = self.borrow();
let serial = state.client.get_serial(SerialKind::MousePress);
state.toplevel.show_window_menu(
&state.globals.seat,
serial,
position.x.0 as i32,
position.y.0 as i32,
);
}

fn start_system_move(&self) {
let state = self.borrow();
let serial = state.client.get_serial(SerialKind::MousePress);
state.toplevel._move(&state.globals.seat, serial);
}

fn should_render_window_controls(&self) -> bool {
self.borrow().decoration_state == WaylandDecorationState::Client
}
}

#[derive(Debug, Copy, Clone, Eq, PartialEq, Hash)]
Expand Down
11 changes: 11 additions & 0 deletions crates/gpui/src/platform/linux/x11/window.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ use crate::{
Scene, Size, WindowAppearance, WindowBackgroundAppearance, WindowBounds, WindowOptions,
WindowParams, X11Client, X11ClientState, X11ClientStatePtr,
};

use blade_graphics as gpu;
use parking_lot::Mutex;
use raw_window_handle as rwh;
Expand Down Expand Up @@ -719,4 +720,14 @@ impl PlatformWindow for X11Window {
let inner = self.0.state.borrow();
inner.renderer.sprite_atlas().clone()
}

// todo(linux)
fn show_window_menu(&self, _position: Point<Pixels>) {}

// todo(linux)
fn start_system_move(&self) {}

fn should_render_window_controls(&self) -> bool {
false
}
}
8 changes: 8 additions & 0 deletions crates/gpui/src/platform/mac/window.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1100,6 +1100,14 @@ impl PlatformWindow for MacWindow {
fn sprite_atlas(&self) -> Arc<dyn PlatformAtlas> {
self.0.lock().renderer.sprite_atlas().clone()
}

fn show_window_menu(&self, _position: Point<Pixels>) {}

fn start_system_move(&self) {}

fn should_render_window_controls(&self) -> bool {
false
}
}

impl rwh::HasWindowHandle for MacWindow {
Expand Down
12 changes: 12 additions & 0 deletions crates/gpui/src/platform/test/window.rs
Original file line number Diff line number Diff line change
Expand Up @@ -257,6 +257,18 @@ impl PlatformWindow for TestWindow {
fn get_raw_handle(&self) -> windows::Win32::Foundation::HWND {
unimplemented!()
}

fn show_window_menu(&self, _position: Point<Pixels>) {
unimplemented!()
}

fn start_system_move(&self) {
unimplemented!()
}

fn should_render_window_controls(&self) -> bool {
false
}
}

pub(crate) struct TestAtlasState {
Expand Down
8 changes: 8 additions & 0 deletions crates/gpui/src/platform/windows/window.rs
Original file line number Diff line number Diff line change
Expand Up @@ -628,6 +628,14 @@ impl PlatformWindow for WindowsWindow {
fn get_raw_handle(&self) -> HWND {
self.0.hwnd
}

fn show_window_menu(&self, _position: Point<Pixels>) {}

fn start_system_move(&self) {}

fn should_render_window_controls(&self) -> bool {
false
}
}

#[implement(IDropTarget)]
Expand Down
17 changes: 17 additions & 0 deletions crates/gpui/src/window.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1131,6 +1131,23 @@ impl<'a> WindowContext<'a> {
self.window.platform_window.zoom();
}

/// Opens the native title bar context menu, useful when implementing client side decorations (Wayland only)
pub fn show_window_menu(&self, position: Point<Pixels>) {
self.window.platform_window.show_window_menu(position)
}

/// Tells the compositor to take control of window movement (Wayland only)
///
/// Events may not be received during a move operation.
pub fn start_system_move(&self) {
self.window.platform_window.start_system_move()
}

/// Returns whether the title bar window controls need to be rendered by the application (Wayland and X11)
pub fn should_render_window_controls(&self) -> bool {
self.window.platform_window.should_render_window_controls()
}

/// Updates the window's title at the platform level.
pub fn set_window_title(&mut self, title: &str) {
self.window.platform_window.set_title(title);
Expand Down
8 changes: 4 additions & 4 deletions crates/ui/src/components/stories/title_bar.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
use gpui::Render;
use gpui::{NoAction, Render};
use story::{StoryContainer, StoryItem, StorySection};

use crate::{prelude::*, PlatformStyle, TitleBar};
Expand All @@ -19,7 +19,7 @@ impl Render for TitleBarStory {
StorySection::new().child(
StoryItem::new(
"Default (macOS)",
TitleBar::new("macos")
TitleBar::new("macos", Box::new(NoAction))
.platform_style(PlatformStyle::Mac)
.map(add_sample_children),
)
Expand All @@ -31,7 +31,7 @@ impl Render for TitleBarStory {
StorySection::new().child(
StoryItem::new(
"Default (Linux)",
TitleBar::new("linux")
TitleBar::new("linux", Box::new(NoAction))
.platform_style(PlatformStyle::Linux)
.map(add_sample_children),
)
Expand All @@ -43,7 +43,7 @@ impl Render for TitleBarStory {
StorySection::new().child(
StoryItem::new(
"Default (Windows)",
TitleBar::new("windows")
TitleBar::new("windows", Box::new(NoAction))
.platform_style(PlatformStyle::Windows)
.map(add_sample_children),
)
Expand Down
1 change: 1 addition & 0 deletions crates/ui/src/components/title_bar.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
mod linux_window_controls;
mod title_bar;
mod windows_window_controls;

Expand Down
Loading
Loading