use std::rc::Rc;
use gpui_wgpu::WgpuSurfaceConfig;
use tauri::Wry;
use tauri_runtime_wry::tao::{
dpi::PhysicalPosition,
event::{DeviceId, ElementState, WindowEvent},
};
use super::{Runtime, SurfaceParams};
use crate::{
events,
platform::{
window::{RawWindow, WindowInner},
x11::{Pointer, X11Window},
},
};
pub(super) enum Rewrite {
Keep,
Drop,
Replace(WindowEvent<'static>),
}
impl Runtime {
pub(super) fn x11_surface(&self, window: &tauri::Window<Wry>, params: &mut SurfaceParams) {
let Some(x11) = X11Window::new(window, params.raw.window, &self.waker) else {
return;
};
if x11.take_changes().menu_bar_added
&& let Some(raw) = x11.create_area(&self.waker)
&& let Some(size) = x11.content_size(params.scale_factor)
{
params.raw.window = raw;
params.physical_size = size;
}
params.x11 = Some(x11);
}
pub(super) fn sync_x11(&self, inner: &Rc<WindowInner>) {
let Some(x11) = &inner.x11 else {
return;
};
let changes = x11.take_changes();
if changes.menu_bar_added && !x11.has_area() {
self.move_below_menu_bar(inner, x11);
}
let scale = inner.state.borrow().scale_factor;
if changes.resized
&& let Some(size) = x11.content_size(scale)
{
inner.resized(size, scale);
}
if changes.crossed
&& x11.has_area()
&& let Some(pointer) = x11.pointer()
{
self.x11_hover(inner, &pointer);
}
if changes.exposed {
inner.force_present.set(true);
inner.schedule_frame();
}
}
fn x11_hover(&self, inner: &Rc<WindowInner>, pointer: &Pointer) {
if inner.state.borrow().hovered == pointer.over {
return;
}
let device_id = unsafe { DeviceId::dummy() };
let event = if pointer.over {
WindowEvent::CursorEntered { device_id }
} else {
WindowEvent::CursorLeft { device_id }
};
self.track_window_state(inner, &event);
events::dispatch(inner, &event);
if pointer.over {
self.x11_move(inner, pointer);
}
}
fn x11_move(&self, inner: &WindowInner, pointer: &Pointer) {
if inner.state.borrow().mouse_position == pointer.position {
return;
}
let device_id = unsafe { DeviceId::dummy() };
events::dispatch(inner, &cursor_moved(device_id, inner, pointer));
}
fn move_below_menu_bar(&self, inner: &WindowInner, x11: &X11Window) {
let Some(window) = x11.create_area(&self.waker) else {
return;
};
let scale = inner.state.borrow().scale_factor;
let raw = RawWindow {
window,
display: inner.raw.get().display,
};
let instance = self
.platform
.gpu_context
.borrow()
.as_ref()
.map(|context| context.instance.clone());
let (Some(size), Some(instance)) = (x11.content_size(scale), instance) else {
x11.remove_area();
return;
};
let result = inner.state.borrow_mut().renderer.as_mut().map(|renderer| {
renderer.replace_surface(
&raw,
WgpuSurfaceConfig {
size,
transparent: false,
preferred_present_mode: None,
},
&instance,
)
});
match result {
Some(Ok(())) => {
inner.raw.set(raw);
crate::webview::invalidate(inner);
inner.resized(size, scale);
inner.force_present.set(true);
inner.schedule_frame();
}
Some(Err(error)) => {
log::error!("tauri-plugin-gpui: moving GPUI below the menu bar failed: {error:#}");
x11.remove_area();
}
None => x11.remove_area(),
}
}
pub(super) fn x11_window_event(
&self,
inner: &Rc<WindowInner>,
event: &WindowEvent<'_>,
) -> Rewrite {
if inner.x11.is_none() || inner.closed.get() {
return Rewrite::Keep;
}
{
let _guard = self.enter();
self.sync_x11(inner);
}
let Some(x11) = inner.x11.as_ref().filter(|x11| x11.has_area()) else {
return Rewrite::Keep;
};
match event {
WindowEvent::Resized(_) => {
inner.window_mode_changed();
Rewrite::Drop
}
WindowEvent::ScaleFactorChanged { scale_factor, .. } => {
inner.window_mode_changed();
let scale = *scale_factor as f32;
if let Some(size) = x11.content_size(scale) {
let _guard = self.enter();
inner.resized(size, scale);
}
Rewrite::Drop
}
WindowEvent::CursorEntered { .. } | WindowEvent::CursorLeft { .. } => {
if let Some(pointer) = x11.pointer() {
let _guard = self.enter();
self.x11_hover(inner, &pointer);
}
Rewrite::Drop
}
WindowEvent::CursorMoved { device_id, .. } => {
let Some(pointer) = x11.pointer() else {
return Rewrite::Drop;
};
{
let _guard = self.enter();
self.x11_hover(inner, &pointer);
}
let dragging = inner.state.borrow().pressed_button.is_some();
if !pointer.over && !dragging {
return Rewrite::Drop;
}
Rewrite::Replace(cursor_moved(*device_id, inner, &pointer))
}
WindowEvent::MouseInput {
state: ElementState::Pressed,
..
} => {
if let Some(pointer) = x11.pointer().filter(|pointer| pointer.over) {
let _guard = self.enter();
self.x11_hover(inner, &pointer);
self.x11_move(inner, &pointer);
}
Rewrite::Keep
}
WindowEvent::MouseWheel { .. } if !inner.state.borrow().hovered => Rewrite::Drop,
_ => Rewrite::Keep,
}
}
}
fn cursor_moved(
device_id: DeviceId,
inner: &WindowInner,
pointer: &Pointer,
) -> WindowEvent<'static> {
let scale = inner.state.borrow().scale_factor;
#[allow(deprecated)]
WindowEvent::CursorMoved {
device_id,
position: PhysicalPosition::new(
(f32::from(pointer.position.x) * scale) as f64,
(f32::from(pointer.position.y) * scale) as f64,
),
modifiers: Default::default(),
}
}