mirror of
https://github.com/niri-wm/niri.git
synced 2026-06-23 02:05:33 +07:00
Send output enter/leave to pointer and DnD surfaces
This allows them to apply the right scale factor.
This commit is contained in:
@@ -91,6 +91,10 @@ impl Cursor {
|
|||||||
})
|
})
|
||||||
.clone()
|
.clone()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn get_cached_hotspot(&self, scale: i32) -> Option<Point<i32, Physical>> {
|
||||||
|
self.cache.get(&scale).map(|(_, hotspot)| *hotspot)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn load_xcursor(theme: &str) -> anyhow::Result<Vec<Image>> {
|
fn load_xcursor(theme: &str) -> anyhow::Result<Vec<Image>> {
|
||||||
|
|||||||
@@ -116,6 +116,7 @@ fn main() {
|
|||||||
|
|
||||||
// These should be called periodically, before flushing the clients.
|
// These should be called periodically, before flushing the clients.
|
||||||
state.niri.monitor_set.refresh();
|
state.niri.monitor_set.refresh();
|
||||||
|
state.niri.refresh_pointer_outputs();
|
||||||
state.niri.popups.cleanup();
|
state.niri.popups.cleanup();
|
||||||
state.update_focus();
|
state.update_focus();
|
||||||
|
|
||||||
|
|||||||
+86
-4
@@ -12,6 +12,7 @@ use _server_decoration::server::org_kde_kwin_server_decoration_manager::Mode as
|
|||||||
use anyhow::Context;
|
use anyhow::Context;
|
||||||
use sd_notify::NotifyState;
|
use sd_notify::NotifyState;
|
||||||
use smithay::backend::allocator::Fourcc;
|
use smithay::backend::allocator::Fourcc;
|
||||||
|
use smithay::backend::renderer::element::solid::{SolidColorBuffer, SolidColorRenderElement};
|
||||||
use smithay::backend::renderer::element::surface::{
|
use smithay::backend::renderer::element::surface::{
|
||||||
render_elements_from_surface_tree, WaylandSurfaceRenderElement,
|
render_elements_from_surface_tree, WaylandSurfaceRenderElement,
|
||||||
};
|
};
|
||||||
@@ -24,10 +25,10 @@ use smithay::backend::renderer::element::{
|
|||||||
use smithay::backend::renderer::gles::{GlesMapping, GlesRenderer, GlesTexture};
|
use smithay::backend::renderer::gles::{GlesMapping, GlesRenderer, GlesTexture};
|
||||||
use smithay::backend::renderer::{Bind, ExportMem, Frame, ImportAll, Offscreen, Renderer};
|
use smithay::backend::renderer::{Bind, ExportMem, Frame, ImportAll, Offscreen, Renderer};
|
||||||
use smithay::desktop::utils::{
|
use smithay::desktop::utils::{
|
||||||
send_dmabuf_feedback_surface_tree, send_frames_surface_tree,
|
bbox_from_surface_tree, output_update, send_dmabuf_feedback_surface_tree,
|
||||||
surface_presentation_feedback_flags_from_states, surface_primary_scanout_output,
|
send_frames_surface_tree, surface_presentation_feedback_flags_from_states,
|
||||||
take_presentation_feedback_surface_tree, update_surface_primary_scanout_output,
|
surface_primary_scanout_output, take_presentation_feedback_surface_tree,
|
||||||
OutputPresentationFeedback,
|
update_surface_primary_scanout_output, OutputPresentationFeedback,
|
||||||
};
|
};
|
||||||
use smithay::desktop::{layer_map_for_output, PopupManager, Space, Window, WindowSurfaceType};
|
use smithay::desktop::{layer_map_for_output, PopupManager, Space, Window, WindowSurfaceType};
|
||||||
use smithay::input::keyboard::XkbConfig;
|
use smithay::input::keyboard::XkbConfig;
|
||||||
@@ -1072,6 +1073,86 @@ impl Niri {
|
|||||||
pointer_elements
|
pointer_elements
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn refresh_pointer_outputs(&self) {
|
||||||
|
let _span = tracy_client::span!("Niri::refresh_pointer_outputs");
|
||||||
|
|
||||||
|
match &self.cursor_image {
|
||||||
|
CursorImageStatus::Hidden | CursorImageStatus::Named(_) => {
|
||||||
|
// There's no cursor surface, but there might be a DnD icon.
|
||||||
|
let Some(surface) = &self.dnd_icon else {
|
||||||
|
return;
|
||||||
|
};
|
||||||
|
|
||||||
|
let pointer_pos = self.seat.get_pointer().unwrap().current_location();
|
||||||
|
|
||||||
|
for output in self.global_space.outputs() {
|
||||||
|
let geo = self.global_space.output_geometry(output).unwrap();
|
||||||
|
|
||||||
|
// The default cursor is rendered at the right scale for each output, which
|
||||||
|
// means that it may have a different hotspot for each output.
|
||||||
|
let output_scale = output.current_scale().integer_scale();
|
||||||
|
let Some(hotspot) = self.default_cursor.get_cached_hotspot(output_scale) else {
|
||||||
|
// Oh well; it'll get cached next time we render.
|
||||||
|
continue;
|
||||||
|
};
|
||||||
|
let hotspot = hotspot.to_logical(output_scale);
|
||||||
|
|
||||||
|
let surface_pos = pointer_pos.to_i32_round() - hotspot;
|
||||||
|
let bbox = bbox_from_surface_tree(surface, surface_pos);
|
||||||
|
|
||||||
|
if let Some(mut overlap) = geo.intersection(bbox) {
|
||||||
|
overlap.loc -= surface_pos;
|
||||||
|
output_update(output, Some(overlap), surface);
|
||||||
|
} else {
|
||||||
|
output_update(output, None, surface);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
CursorImageStatus::Surface(surface) => {
|
||||||
|
let hotspot = with_states(surface, |states| {
|
||||||
|
states
|
||||||
|
.data_map
|
||||||
|
.get::<Mutex<CursorImageAttributes>>()
|
||||||
|
.unwrap()
|
||||||
|
.lock()
|
||||||
|
.unwrap()
|
||||||
|
.hotspot
|
||||||
|
});
|
||||||
|
|
||||||
|
let pointer_pos = self.seat.get_pointer().unwrap().current_location();
|
||||||
|
let surface_pos = pointer_pos.to_i32_round() - hotspot;
|
||||||
|
let bbox = bbox_from_surface_tree(surface, surface_pos);
|
||||||
|
|
||||||
|
let dnd = self
|
||||||
|
.dnd_icon
|
||||||
|
.as_ref()
|
||||||
|
.map(|surface| (surface, bbox_from_surface_tree(surface, surface_pos)));
|
||||||
|
|
||||||
|
for output in self.global_space.outputs() {
|
||||||
|
let geo = self.global_space.output_geometry(output).unwrap();
|
||||||
|
|
||||||
|
// Compute pointer surface overlap.
|
||||||
|
if let Some(mut overlap) = geo.intersection(bbox) {
|
||||||
|
overlap.loc -= surface_pos;
|
||||||
|
output_update(output, Some(overlap), surface);
|
||||||
|
} else {
|
||||||
|
output_update(output, None, surface);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Compute DnD icon surface overlap.
|
||||||
|
if let Some((surface, bbox)) = dnd {
|
||||||
|
if let Some(mut overlap) = geo.intersection(bbox) {
|
||||||
|
overlap.loc -= surface_pos;
|
||||||
|
output_update(output, Some(overlap), surface);
|
||||||
|
} else {
|
||||||
|
output_update(output, None, surface);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
fn render(
|
fn render(
|
||||||
&mut self,
|
&mut self,
|
||||||
renderer: &mut GlesRenderer,
|
renderer: &mut GlesRenderer,
|
||||||
@@ -1571,6 +1652,7 @@ render_elements! {
|
|||||||
Monitor = MonitorRenderElement<R>,
|
Monitor = MonitorRenderElement<R>,
|
||||||
Wayland = WaylandSurfaceRenderElement<R>,
|
Wayland = WaylandSurfaceRenderElement<R>,
|
||||||
DefaultPointer = TextureRenderElement<<R as Renderer>::TextureId>,
|
DefaultPointer = TextureRenderElement<<R as Renderer>::TextureId>,
|
||||||
|
X = SolidColorRenderElement,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Default)]
|
#[derive(Default)]
|
||||||
|
|||||||
Reference in New Issue
Block a user