mirror of
https://github.com/zed-industries/zed.git
synced 2025-02-03 17:44:30 +00:00
x11: create window and route events
This commit is contained in:
parent
cefc98258f
commit
aed363d3c7
5 changed files with 194 additions and 52 deletions
|
@ -1,5 +1,6 @@
|
|||
mod blade_atlas;
|
||||
mod blade_belt;
|
||||
mod blade_renderer;
|
||||
mod dispatcher;
|
||||
mod display;
|
||||
mod platform;
|
||||
|
@ -14,3 +15,4 @@ pub(crate) use text_system::*;
|
|||
pub(crate) use window::*;
|
||||
|
||||
use blade_belt::*;
|
||||
use blade_renderer::*;
|
||||
|
|
|
@ -22,6 +22,22 @@ struct BladeAtlasState {
|
|||
tiles_by_key: FxHashMap<AtlasKey, AtlasTile>,
|
||||
}
|
||||
|
||||
impl BladeAtlasState {
|
||||
fn destroy(&mut self) {
|
||||
for texture in self.monochrome_textures.drain(..) {
|
||||
self.gpu.destroy_texture(texture.raw);
|
||||
}
|
||||
for texture in self.polychrome_textures.drain(..) {
|
||||
self.gpu.destroy_texture(texture.raw);
|
||||
}
|
||||
for texture in self.path_textures.drain(..) {
|
||||
self.gpu.destroy_texture(texture.raw);
|
||||
}
|
||||
self.gpu.destroy_command_encoder(&mut self.gpu_encoder);
|
||||
self.upload_belt.destroy(&self.gpu);
|
||||
}
|
||||
}
|
||||
|
||||
impl BladeAtlas {
|
||||
pub(crate) fn new(gpu: &Arc<blade::Context>) -> Self {
|
||||
BladeAtlas(Mutex::new(BladeAtlasState {
|
||||
|
@ -41,6 +57,10 @@ impl BladeAtlas {
|
|||
}))
|
||||
}
|
||||
|
||||
pub(crate) fn destroy(&self) {
|
||||
self.0.lock().destroy();
|
||||
}
|
||||
|
||||
pub(crate) fn clear_textures(&self, texture_kind: AtlasTextureKind) {
|
||||
let mut lock = self.0.lock();
|
||||
let textures = match texture_kind {
|
||||
|
|
11
crates/gpui/src/platform/linux/blade_renderer.rs
Normal file
11
crates/gpui/src/platform/linux/blade_renderer.rs
Normal file
|
@ -0,0 +1,11 @@
|
|||
use std::sync::Arc;
|
||||
|
||||
pub struct BladeRenderer {
|
||||
gpu: Arc<blade::Context>,
|
||||
}
|
||||
|
||||
impl BladeRenderer {
|
||||
pub fn new(gpu: Arc<blade::Context>) -> Self {
|
||||
Self { gpu }
|
||||
}
|
||||
}
|
|
@ -2,11 +2,13 @@
|
|||
|
||||
use crate::{
|
||||
Action, AnyWindowHandle, BackgroundExecutor, ClipboardItem, CursorStyle, DisplayId,
|
||||
ForegroundExecutor, Keymap, LinuxDispatcher, LinuxDisplay, LinuxTextSystem, LinuxWindow, Menu,
|
||||
PathPromptOptions, Platform, PlatformDisplay, PlatformInput, PlatformTextSystem,
|
||||
PlatformWindow, Result, SemanticVersion, Task, WindowOptions,
|
||||
ForegroundExecutor, Keymap, LinuxDispatcher, LinuxDisplay, LinuxTextSystem, LinuxWindow,
|
||||
LinuxWindowState, LinuxWindowStatePtr, Menu, PathPromptOptions, Platform, PlatformDisplay,
|
||||
PlatformInput, PlatformTextSystem, PlatformWindow, Result, SemanticVersion, Task,
|
||||
WindowOptions,
|
||||
};
|
||||
|
||||
use collections::{HashMap, HashSet};
|
||||
use futures::channel::oneshot;
|
||||
use parking_lot::Mutex;
|
||||
|
||||
|
@ -17,16 +19,48 @@ use std::{
|
|||
time::Duration,
|
||||
};
|
||||
use time::UtcOffset;
|
||||
use x11rb::{connection::Connection as _, rust_connection::RustConnection};
|
||||
use x11rb::{
|
||||
connection::Connection as _,
|
||||
protocol::{
|
||||
xproto::{Atom, ConnectionExt as _},
|
||||
Event,
|
||||
},
|
||||
rust_connection::RustConnection,
|
||||
};
|
||||
|
||||
pub(crate) struct LinuxPlatform(Mutex<LinuxPlatformState>);
|
||||
|
||||
pub(crate) struct WmAtoms {
|
||||
pub protocols: Atom,
|
||||
pub delete_window: Atom,
|
||||
}
|
||||
|
||||
impl WmAtoms {
|
||||
fn new(x11_connection: &RustConnection) -> Self {
|
||||
Self {
|
||||
protocols: x11_connection
|
||||
.intern_atom(false, b"WM_PROTOCOLS")
|
||||
.unwrap()
|
||||
.reply()
|
||||
.unwrap()
|
||||
.atom,
|
||||
delete_window: x11_connection
|
||||
.intern_atom(false, b"WM_DELETE_WINDOW")
|
||||
.unwrap()
|
||||
.reply()
|
||||
.unwrap()
|
||||
.atom,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) struct LinuxPlatformState {
|
||||
x11_connection: RustConnection,
|
||||
x11_root_index: usize,
|
||||
gpu: Arc<blade::Context>,
|
||||
atoms: WmAtoms,
|
||||
background_executor: BackgroundExecutor,
|
||||
foreground_executor: ForegroundExecutor,
|
||||
windows: HashMap<u32, LinuxWindowStatePtr>,
|
||||
text_system: Arc<LinuxTextSystem>,
|
||||
}
|
||||
|
||||
|
@ -39,24 +73,17 @@ impl Default for LinuxPlatform {
|
|||
impl LinuxPlatform {
|
||||
pub(crate) fn new() -> Self {
|
||||
let (x11_connection, x11_root_index) = x11rb::connect(None).unwrap();
|
||||
let atoms = WmAtoms::new(&x11_connection);
|
||||
|
||||
let dispatcher = Arc::new(LinuxDispatcher::new());
|
||||
let gpu = Arc::new(
|
||||
unsafe {
|
||||
blade::Context::init(blade::ContextDesc {
|
||||
validation: cfg!(debug_assertions),
|
||||
capture: false,
|
||||
})
|
||||
}
|
||||
.unwrap(),
|
||||
);
|
||||
|
||||
Self(Mutex::new(LinuxPlatformState {
|
||||
x11_connection,
|
||||
x11_root_index,
|
||||
gpu,
|
||||
atoms,
|
||||
background_executor: BackgroundExecutor::new(dispatcher.clone()),
|
||||
foreground_executor: ForegroundExecutor::new(dispatcher),
|
||||
windows: HashMap::default(),
|
||||
text_system: Arc::new(LinuxTextSystem::new()),
|
||||
}))
|
||||
}
|
||||
|
@ -76,7 +103,58 @@ impl Platform for LinuxPlatform {
|
|||
}
|
||||
|
||||
fn run(&self, on_finish_launching: Box<dyn FnOnce()>) {
|
||||
on_finish_launching()
|
||||
on_finish_launching();
|
||||
|
||||
let mut need_repaint = HashSet::<u32>::default();
|
||||
|
||||
while !self.0.lock().windows.is_empty() {
|
||||
let event = self.0.lock().x11_connection.wait_for_event().unwrap();
|
||||
let mut event_option = Some(event);
|
||||
while let Some(event) = event_option {
|
||||
match event {
|
||||
Event::Expose(event) => {
|
||||
if event.count == 0 {
|
||||
need_repaint.insert(event.window);
|
||||
}
|
||||
}
|
||||
Event::ConfigureNotify(event) => {
|
||||
let lock = self.0.lock();
|
||||
let mut window = lock.windows[&event.window].lock();
|
||||
window.resize(event.width, event.height);
|
||||
}
|
||||
Event::MotionNotify(_event) => {
|
||||
//mouse_position = (event.event_x, event.event_y);
|
||||
//need_repaint.insert(event.window);
|
||||
}
|
||||
Event::MapNotify(_) => {}
|
||||
Event::ClientMessage(event) => {
|
||||
let mut lock = self.0.lock();
|
||||
let data = event.data.as_data32();
|
||||
if data[0] == lock.atoms.delete_window {
|
||||
{
|
||||
let mut window = lock.windows[&event.window].lock();
|
||||
window.destroy();
|
||||
}
|
||||
lock.windows.remove(&event.window);
|
||||
}
|
||||
}
|
||||
Event::Error(error) => {
|
||||
log::error!("X11 error {:?}", error);
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
|
||||
let lock = self.0.lock();
|
||||
event_option = lock.x11_connection.poll_for_event().unwrap();
|
||||
}
|
||||
|
||||
for x11_window in need_repaint.drain() {
|
||||
let lock = self.0.lock();
|
||||
let mut window = lock.windows[&x11_window].lock();
|
||||
window.paint();
|
||||
lock.x11_connection.flush().unwrap();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn quit(&self) {}
|
||||
|
@ -118,14 +196,19 @@ impl Platform for LinuxPlatform {
|
|||
handle: AnyWindowHandle,
|
||||
options: WindowOptions,
|
||||
) -> Box<dyn PlatformWindow> {
|
||||
let lock = self.0.lock();
|
||||
Box::new(LinuxWindow::new(
|
||||
let mut lock = self.0.lock();
|
||||
let win_id = lock.x11_connection.generate_id().unwrap();
|
||||
|
||||
let window_ptr = LinuxWindowState::new_ptr(
|
||||
options,
|
||||
handle,
|
||||
&lock.x11_connection,
|
||||
lock.x11_root_index,
|
||||
&lock.gpu,
|
||||
))
|
||||
win_id,
|
||||
&lock.atoms,
|
||||
);
|
||||
lock.windows.insert(win_id, window_ptr.clone());
|
||||
Box::new(LinuxWindow(window_ptr))
|
||||
}
|
||||
|
||||
fn set_display_link_output_callback(
|
||||
|
|
|
@ -1,8 +1,9 @@
|
|||
use super::BladeRenderer;
|
||||
use crate::{
|
||||
px, AnyWindowHandle, AtlasKey, AtlasTextureId, AtlasTile, BladeAtlas, Bounds, KeyDownEvent,
|
||||
Keystroke, LinuxDisplay, Pixels, PlatformAtlas, PlatformDisplay, PlatformInput,
|
||||
PlatformInputHandler, PlatformWindow, Point, Size, TileId, WindowAppearance, WindowBounds,
|
||||
WindowOptions,
|
||||
WindowOptions, WmAtoms,
|
||||
};
|
||||
use collections::HashMap;
|
||||
use parking_lot::Mutex;
|
||||
|
@ -21,45 +22,37 @@ use x11rb::{
|
|||
|
||||
pub(crate) struct LinuxWindowState {
|
||||
display: Rc<dyn PlatformDisplay>,
|
||||
win_id: u32,
|
||||
x11_window: u32,
|
||||
window_bounds: WindowBounds,
|
||||
content_size: Size<Pixels>,
|
||||
sprite_atlas: Arc<BladeAtlas>,
|
||||
renderer: BladeRenderer,
|
||||
}
|
||||
|
||||
pub(crate) type LinuxWindowStatePtr = Arc<Mutex<LinuxWindowState>>;
|
||||
#[derive(Clone)]
|
||||
pub(crate) struct LinuxWindow(pub(crate) Arc<Mutex<LinuxWindowState>>);
|
||||
pub(crate) struct LinuxWindow(pub(crate) LinuxWindowStatePtr);
|
||||
|
||||
impl LinuxWindow {
|
||||
pub fn new(
|
||||
impl LinuxWindowState {
|
||||
pub fn new_ptr(
|
||||
options: WindowOptions,
|
||||
handle: AnyWindowHandle,
|
||||
x11_connection: &RustConnection,
|
||||
x11_main_screen_index: usize,
|
||||
gpu: &Arc<blade::Context>,
|
||||
) -> Self {
|
||||
x11_window: u32,
|
||||
atoms: &WmAtoms,
|
||||
) -> LinuxWindowStatePtr {
|
||||
let x11_screen_index = options
|
||||
.display_id
|
||||
.map_or(x11_main_screen_index, |did| did.0 as usize);
|
||||
let screen = &x11_connection.setup().roots[x11_screen_index];
|
||||
|
||||
let win_id = x11_connection.generate_id().unwrap();
|
||||
let win_aux = CreateWindowAux::new()
|
||||
.event_mask(
|
||||
EventMask::EXPOSURE | EventMask::STRUCTURE_NOTIFY | EventMask::POINTER_MOTION,
|
||||
)
|
||||
.background_pixel(screen.white_pixel);
|
||||
|
||||
let wm_protocols = x11_connection
|
||||
.intern_atom(false, b"WM_PROTOCOLS")
|
||||
.unwrap()
|
||||
.reply()
|
||||
.unwrap()
|
||||
.atom;
|
||||
let wm_delete_window = x11_connection
|
||||
.intern_atom(false, b"WM_DELETE_WINDOW")
|
||||
.unwrap()
|
||||
.reply()
|
||||
.unwrap()
|
||||
.atom;
|
||||
let (bound_x, bound_y, bound_width, bound_height) = match options.bounds {
|
||||
WindowBounds::Fullscreen | WindowBounds::Maximized => {
|
||||
(0, 0, screen.width_in_pixels, screen.height_in_pixels)
|
||||
|
@ -75,7 +68,7 @@ impl LinuxWindow {
|
|||
x11_connection
|
||||
.create_window(
|
||||
x11rb::COPY_DEPTH_FROM_PARENT,
|
||||
win_id,
|
||||
x11_window,
|
||||
screen.root,
|
||||
bound_x,
|
||||
bound_y,
|
||||
|
@ -93,7 +86,7 @@ impl LinuxWindow {
|
|||
x11_connection
|
||||
.change_property8(
|
||||
PropMode::REPLACE,
|
||||
win_id,
|
||||
x11_window,
|
||||
AtomEnum::WM_NAME,
|
||||
AtomEnum::STRING,
|
||||
title.as_bytes(),
|
||||
|
@ -104,30 +97,63 @@ impl LinuxWindow {
|
|||
x11_connection
|
||||
.change_property32(
|
||||
PropMode::REPLACE,
|
||||
win_id,
|
||||
wm_protocols,
|
||||
x11_window,
|
||||
atoms.protocols,
|
||||
AtomEnum::ATOM,
|
||||
&[wm_delete_window],
|
||||
&[atoms.delete_window],
|
||||
)
|
||||
.unwrap();
|
||||
|
||||
x11_connection.map_window(win_id).unwrap();
|
||||
x11_connection.map_window(x11_window).unwrap();
|
||||
x11_connection.flush().unwrap();
|
||||
|
||||
Self(Arc::new(Mutex::new(LinuxWindowState {
|
||||
let gpu = Arc::new(
|
||||
unsafe {
|
||||
blade::Context::init(blade::ContextDesc {
|
||||
validation: cfg!(debug_assertions),
|
||||
capture: false,
|
||||
})
|
||||
}
|
||||
.unwrap(),
|
||||
);
|
||||
|
||||
Arc::new(Mutex::new(Self {
|
||||
display: Rc::new(LinuxDisplay::new(x11_connection, x11_screen_index)),
|
||||
win_id,
|
||||
sprite_atlas: Arc::new(BladeAtlas::new(gpu)),
|
||||
})))
|
||||
x11_window,
|
||||
window_bounds: options.bounds,
|
||||
content_size: Size {
|
||||
width: Pixels(bound_width as f32),
|
||||
height: Pixels(bound_height as f32),
|
||||
},
|
||||
sprite_atlas: Arc::new(BladeAtlas::new(&gpu)),
|
||||
renderer: BladeRenderer::new(gpu),
|
||||
}))
|
||||
}
|
||||
|
||||
pub fn resize(&mut self, width: u16, height: u16) {
|
||||
self.content_size = Size {
|
||||
width: Pixels(width as f32),
|
||||
height: Pixels(height as f32),
|
||||
};
|
||||
}
|
||||
|
||||
pub fn destroy(&mut self) {
|
||||
self.sprite_atlas.destroy();
|
||||
}
|
||||
|
||||
pub fn paint(&mut self) {
|
||||
//TODO
|
||||
}
|
||||
}
|
||||
|
||||
impl PlatformWindow for LinuxWindow {
|
||||
fn bounds(&self) -> WindowBounds {
|
||||
unimplemented!()
|
||||
//TODO: update when window moves
|
||||
self.0.lock().window_bounds
|
||||
}
|
||||
|
||||
fn content_size(&self) -> Size<Pixels> {
|
||||
unimplemented!()
|
||||
self.0.lock().content_size
|
||||
}
|
||||
|
||||
fn scale_factor(&self) -> f32 {
|
||||
|
|
Loading…
Reference in a new issue