all: implement damage tracking
This commit is contained in:
parent
76a3c50560
commit
bb66abb817
28 changed files with 473 additions and 82 deletions
|
|
@ -180,6 +180,5 @@ Jay supports the following wayland protocols:
|
|||
|
||||
The following features are currently not supported but might get implemented in the future:
|
||||
|
||||
- Fine-grained damage tracking.
|
||||
- Touch support.
|
||||
- Tearing updates of fullscreen games.
|
||||
|
|
|
|||
|
|
@ -1,5 +1,7 @@
|
|||
# Unreleased
|
||||
|
||||
- Add fine-grained damage tracking.
|
||||
|
||||
# 1.4.0 (2024-07-07)
|
||||
|
||||
- Add window management mode.
|
||||
|
|
|
|||
|
|
@ -468,9 +468,11 @@ fn create_dummy_output(state: &Rc<State>) {
|
|||
screencasts: Default::default(),
|
||||
hardware_cursor_needs_render: Cell::new(false),
|
||||
screencopies: Default::default(),
|
||||
title_visible: Cell::new(false),
|
||||
});
|
||||
let dummy_workspace = Rc::new(WorkspaceNode {
|
||||
id: state.node_ids.next(),
|
||||
state: state.clone(),
|
||||
is_dummy: true,
|
||||
output: CloneCell::new(dummy_output.clone()),
|
||||
position: Default::default(),
|
||||
|
|
|
|||
|
|
@ -720,8 +720,6 @@ impl ConfigProxyHandler {
|
|||
if let Some(ws) = self.state.workspaces.get(name.as_str()) {
|
||||
ws.may_capture.set(capture);
|
||||
ws.update_has_captures();
|
||||
ws.output.get().schedule_update_render_data();
|
||||
self.state.damage();
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
|
@ -863,7 +861,6 @@ impl ConfigProxyHandler {
|
|||
move_ws_to_output(&link, &output, config);
|
||||
ws.desired_output.set(output.global.output_id.clone());
|
||||
self.state.tree_changed();
|
||||
self.state.damage();
|
||||
Ok(())
|
||||
}
|
||||
|
||||
|
|
@ -1032,7 +1029,6 @@ impl ConfigProxyHandler {
|
|||
let scale = Scale::from_f64(scale);
|
||||
let connector = self.get_output_node(connector)?;
|
||||
connector.set_preferred_scale(scale);
|
||||
self.state.damage();
|
||||
Ok(())
|
||||
}
|
||||
|
||||
|
|
@ -1043,7 +1039,6 @@ impl ConfigProxyHandler {
|
|||
) -> Result<(), CphError> {
|
||||
let connector = self.get_output_node(connector)?;
|
||||
connector.update_transform(transform);
|
||||
self.state.damage();
|
||||
Ok(())
|
||||
}
|
||||
|
||||
|
|
@ -1371,6 +1366,7 @@ impl ConfigProxyHandler {
|
|||
}
|
||||
}
|
||||
self.state.root.clone().node_visit(&mut V);
|
||||
self.state.damage(self.state.root.extents.get());
|
||||
}
|
||||
|
||||
fn colors_changed(&self) {
|
||||
|
|
@ -1386,6 +1382,7 @@ impl ConfigProxyHandler {
|
|||
}
|
||||
}
|
||||
self.state.root.clone().node_visit(&mut V);
|
||||
self.state.damage(self.state.root.extents.get());
|
||||
}
|
||||
|
||||
fn get_sized(&self, sized: Resizable) -> Result<ThemeSized, CphError> {
|
||||
|
|
|
|||
|
|
@ -3,6 +3,7 @@ use {
|
|||
cursor::{Cursor, KnownCursor, DEFAULT_CURSOR_SIZE},
|
||||
fixed::Fixed,
|
||||
rect::Rect,
|
||||
scale::Scale,
|
||||
state::State,
|
||||
tree::OutputNode,
|
||||
utils::{
|
||||
|
|
@ -74,13 +75,26 @@ impl CursorUserGroup {
|
|||
group
|
||||
}
|
||||
|
||||
fn damage_active(&self) {
|
||||
if let Some(active) = self.active.get() {
|
||||
if let Some(cursor) = active.cursor.get() {
|
||||
let (x, y) = active.pos.get();
|
||||
let x_int = x.round_down();
|
||||
let y_int = y.round_down();
|
||||
let extents = cursor.extents_at_scale(Scale::default());
|
||||
self.state.damage(extents.move_(x_int, y_int));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn deactivate(&self) {
|
||||
if self.hardware_cursor.get() {
|
||||
self.remove_hardware_cursor();
|
||||
} else {
|
||||
self.damage_active();
|
||||
}
|
||||
self.active_id.take();
|
||||
self.active.take();
|
||||
self.state.damage();
|
||||
}
|
||||
|
||||
pub fn latest_output(&self) -> Rc<OutputNode> {
|
||||
|
|
@ -150,6 +164,7 @@ impl CursorUserGroup {
|
|||
if self.hardware_cursor.replace(hardware_cursor) == hardware_cursor {
|
||||
return;
|
||||
}
|
||||
self.damage_active();
|
||||
if hardware_cursor {
|
||||
let prev = self
|
||||
.state
|
||||
|
|
@ -157,6 +172,7 @@ impl CursorUserGroup {
|
|||
.set(Some(self.clone()));
|
||||
if let Some(prev) = prev {
|
||||
prev.hardware_cursor.set(false);
|
||||
prev.damage_active();
|
||||
}
|
||||
match self.active.get() {
|
||||
None => self.remove_hardware_cursor(),
|
||||
|
|
@ -230,9 +246,7 @@ impl CursorUser {
|
|||
self.owner.take();
|
||||
self.group.users.remove(&self.id);
|
||||
if self.group.active_id.get() == Some(self.id) {
|
||||
self.group.active_id.take();
|
||||
self.group.active.take();
|
||||
self.group.state.damage();
|
||||
self.group.deactivate();
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -240,10 +254,15 @@ impl CursorUser {
|
|||
if self.group.active_id.replace(Some(self.id)) == Some(self.id) {
|
||||
return;
|
||||
}
|
||||
if self.software_cursor() {
|
||||
self.group.damage_active();
|
||||
}
|
||||
self.group.latest_output.set(self.output.get());
|
||||
self.group.active.set(Some(self.clone()));
|
||||
self.update_hardware_cursor();
|
||||
self.group.state.damage();
|
||||
if self.software_cursor() {
|
||||
self.group.damage_active();
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg_attr(not(feature = "it"), allow(dead_code))]
|
||||
|
|
@ -341,6 +360,9 @@ impl CursorUser {
|
|||
}
|
||||
}
|
||||
old.handle_unset();
|
||||
if self.software_cursor() {
|
||||
self.group.damage_active();
|
||||
}
|
||||
}
|
||||
if let Some(cursor) = cursor.as_ref() {
|
||||
cursor.clone().handle_set();
|
||||
|
|
@ -348,6 +370,9 @@ impl CursorUser {
|
|||
}
|
||||
self.cursor.set(cursor.clone());
|
||||
self.update_hardware_cursor();
|
||||
if self.software_cursor() {
|
||||
self.group.damage_active();
|
||||
}
|
||||
}
|
||||
|
||||
pub fn position(&self) -> (Fixed, Fixed) {
|
||||
|
|
@ -368,6 +393,16 @@ impl CursorUser {
|
|||
x = x.apply_fract(x_tmp);
|
||||
y = y.apply_fract(y_tmp);
|
||||
}
|
||||
if self.software_cursor() {
|
||||
if let Some(cursor) = self.cursor.get() {
|
||||
let (old_x, old_y) = self.pos.get();
|
||||
let old_x_int = old_x.round_down();
|
||||
let old_y_int = old_y.round_down();
|
||||
let extents = cursor.extents_at_scale(Scale::default());
|
||||
self.group.state.damage(extents.move_(old_x_int, old_y_int));
|
||||
self.group.state.damage(extents.move_(x_int, y_int));
|
||||
}
|
||||
}
|
||||
self.pos.set((x, y));
|
||||
self.update_hardware_cursor_(false);
|
||||
(x, y)
|
||||
|
|
@ -381,6 +416,10 @@ impl CursorUser {
|
|||
self.is_active() && self.group.hardware_cursor.get()
|
||||
}
|
||||
|
||||
pub fn software_cursor(&self) -> bool {
|
||||
self.is_active() && !self.group.hardware_cursor.get()
|
||||
}
|
||||
|
||||
fn update_hardware_cursor_(&self, render: bool) {
|
||||
if !self.hardware_cursor() {
|
||||
return;
|
||||
|
|
|
|||
|
|
@ -74,7 +74,7 @@ impl ExtSessionLockManagerV1RequestHandler for ExtSessionLockManagerV1 {
|
|||
state.lock.locked.set(true);
|
||||
state.lock.lock.set(Some(new.clone()));
|
||||
state.tree_changed();
|
||||
state.damage();
|
||||
state.damage(state.root.extents.get());
|
||||
new.send_locked();
|
||||
} else {
|
||||
new.finish();
|
||||
|
|
|
|||
|
|
@ -327,9 +327,6 @@ impl JayScreencast {
|
|||
Target::Toplevel(tl) => {
|
||||
let data = tl.tl_data();
|
||||
data.jay_screencasts.remove(&(self.client.id, self.id));
|
||||
if data.jay_screencasts.is_empty() {
|
||||
self.client.state.damage();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -418,10 +415,16 @@ impl JayScreencast {
|
|||
|
||||
fn damage(&self) {
|
||||
if let Some(target) = self.target.get() {
|
||||
match target {
|
||||
Target::Output(o) => o.global.connector.connector.damage(),
|
||||
Target::Toplevel(_) => self.client.state.damage(),
|
||||
}
|
||||
let rect = match target {
|
||||
Target::Output(o) => o.global.pos.get(),
|
||||
Target::Toplevel(t) => {
|
||||
if !t.node_visible() {
|
||||
return;
|
||||
}
|
||||
t.node_absolute_position()
|
||||
}
|
||||
};
|
||||
self.client.state.damage(rect);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -535,9 +538,6 @@ impl JayScreencastRequestHandler for JayScreencast {
|
|||
}
|
||||
let t = t.toplevel.clone();
|
||||
let data = t.tl_data();
|
||||
if data.jay_screencasts.is_empty() {
|
||||
data.state.damage();
|
||||
}
|
||||
data.jay_screencasts
|
||||
.set((self.client.id, self.id), slf.clone());
|
||||
new_target = Some(Target::Toplevel(t));
|
||||
|
|
@ -577,6 +577,10 @@ impl JayScreencastRequestHandler for JayScreencast {
|
|||
}
|
||||
}
|
||||
|
||||
if self.running.get() {
|
||||
self.damage();
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -561,7 +561,6 @@ impl WlSeatGlobal {
|
|||
if let Some(parent) = tl.tl_data().parent.get() {
|
||||
if let Some(tl) = parent.node_toplevel() {
|
||||
self.focus_node(tl.tl_into_node());
|
||||
self.state.damage();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -411,10 +411,18 @@ impl WlSeatGlobal {
|
|||
}
|
||||
|
||||
fn set_pointer_cursor_position(&self, x: Fixed, y: Fixed) -> (Fixed, Fixed) {
|
||||
let dnd_icon = self.pointer_owner.dnd_icon();
|
||||
if let Some(dnd_icon) = &dnd_icon {
|
||||
let (x_old, y_old) = self.pointer_cursor.position_int();
|
||||
dnd_icon.damage_at(x_old, y_old);
|
||||
}
|
||||
let (x, y) = self.pointer_cursor.set_position(x, y);
|
||||
let x_int = x.round_down();
|
||||
let y_int = y.round_down();
|
||||
if let Some(dnd_icon) = &dnd_icon {
|
||||
dnd_icon.damage_at(x_int, y_int);
|
||||
}
|
||||
if let Some(td) = self.pointer_owner.toplevel_drag() {
|
||||
let x_int = x.round_down();
|
||||
let y_int = y.round_down();
|
||||
td.move_(x_int, y_int);
|
||||
}
|
||||
(x, y)
|
||||
|
|
@ -894,7 +902,6 @@ impl WlSeatGlobal {
|
|||
}
|
||||
|
||||
pub(super) fn apply_changes(self: &Rc<Self>) {
|
||||
self.state.damage();
|
||||
self.pointer_owner.apply_changes(self);
|
||||
if self.changes.get().contains(CHANGE_TREE) {
|
||||
self.tablet_apply_changes();
|
||||
|
|
|
|||
|
|
@ -385,7 +385,6 @@ impl<T: SimplePointerOwnerUsecase> PointerOwner for SimplePointerOwner<T> {
|
|||
if !T::IS_DEFAULT {
|
||||
seat.pointer_owner.set_default_pointer_owner(seat);
|
||||
seat.trigger_tree_changed();
|
||||
seat.state.damage();
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -763,21 +762,17 @@ impl<S: ToplevelSelector> NodeSelectorUsecase for SelectToplevelUsecase<S> {
|
|||
}
|
||||
|
||||
fn node_focus(self: &Rc<Self>, seat: &Rc<WlSeatGlobal>, node: &Rc<dyn Node>) {
|
||||
let mut damage = false;
|
||||
let tl = node.clone().node_into_toplevel();
|
||||
if let Some(tl) = &tl {
|
||||
tl.tl_data().render_highlight.fetch_add(1);
|
||||
if !tl.tl_admits_children() {
|
||||
seat.pointer_cursor().set_known(KnownCursor::Pointer);
|
||||
}
|
||||
damage = true;
|
||||
seat.state.damage(tl.node_absolute_position());
|
||||
}
|
||||
if let Some(prev) = self.latest.set(tl) {
|
||||
prev.tl_data().render_highlight.fetch_sub(1);
|
||||
damage = true;
|
||||
}
|
||||
if damage {
|
||||
seat.state.damage();
|
||||
seat.state.damage(prev.node_absolute_position());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -787,7 +782,7 @@ impl<S: ?Sized> Drop for SelectToplevelUsecase<S> {
|
|||
if let Some(prev) = self.latest.take() {
|
||||
prev.tl_data().render_highlight.fetch_sub(1);
|
||||
if let Some(seat) = self.seat.upgrade() {
|
||||
seat.state.damage();
|
||||
seat.state.damage(prev.node_absolute_position());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -812,19 +807,15 @@ impl<S: WorkspaceSelector> NodeSelectorUsecase for SelectWorkspaceUsecase<S> {
|
|||
}
|
||||
|
||||
fn node_focus(self: &Rc<Self>, seat: &Rc<WlSeatGlobal>, node: &Rc<dyn Node>) {
|
||||
let mut damage = false;
|
||||
let ws = node.clone().node_into_workspace();
|
||||
if let Some(ws) = &ws {
|
||||
ws.render_highlight.fetch_add(1);
|
||||
seat.pointer_cursor().set_known(KnownCursor::Pointer);
|
||||
damage = true;
|
||||
seat.state.damage(ws.position.get());
|
||||
}
|
||||
if let Some(prev) = self.latest.set(ws) {
|
||||
prev.render_highlight.fetch_sub(1);
|
||||
damage = true;
|
||||
}
|
||||
if damage {
|
||||
seat.state.damage();
|
||||
seat.state.damage(prev.position.get());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -834,7 +825,7 @@ impl<S: ?Sized> Drop for SelectWorkspaceUsecase<S> {
|
|||
if let Some(prev) = self.latest.take() {
|
||||
prev.render_highlight.fetch_sub(1);
|
||||
if let Some(seat) = self.seat.upgrade() {
|
||||
seat.state.damage();
|
||||
seat.state.damage(prev.position.get());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -257,6 +257,7 @@ pub struct WlSurface {
|
|||
opaque_region: Cell<Option<Rc<Region>>>,
|
||||
buffer_points: RefCell<BufferPoints>,
|
||||
pub buffer_points_norm: RefCell<SampleRect>,
|
||||
damage_matrix: Cell<DamageMatrix>,
|
||||
buffer_transform: Cell<Transform>,
|
||||
buffer_scale: Cell<i32>,
|
||||
src_rect: Cell<Option<[Fixed; 4]>>,
|
||||
|
|
@ -568,6 +569,7 @@ impl WlSurface {
|
|||
opaque_region: Default::default(),
|
||||
buffer_points: Default::default(),
|
||||
buffer_points_norm: Default::default(),
|
||||
damage_matrix: Default::default(),
|
||||
buffer_transform: Cell::new(Transform::None),
|
||||
buffer_scale: Cell::new(1),
|
||||
src_rect: Cell::new(None),
|
||||
|
|
@ -669,8 +671,13 @@ impl WlSurface {
|
|||
}
|
||||
|
||||
fn set_absolute_position(&self, x1: i32, y1: i32) {
|
||||
self.buffer_abs_pos
|
||||
.set(self.buffer_abs_pos.get().at_point(x1, y1));
|
||||
let old_pos = self.buffer_abs_pos.get();
|
||||
let new_pos = old_pos.at_point(x1, y1);
|
||||
if self.visible.get() && self.toplevel.is_none() {
|
||||
self.client.state.damage(old_pos);
|
||||
self.client.state.damage(new_pos);
|
||||
}
|
||||
self.buffer_abs_pos.set(new_pos);
|
||||
if let Some(children) = self.children.borrow_mut().deref_mut() {
|
||||
for ss in children.subsurfaces.values() {
|
||||
let pos = ss.position.get();
|
||||
|
|
@ -843,6 +850,9 @@ impl WlSurface {
|
|||
fn unset_dnd_icons(&self) {
|
||||
while let Some((_, dnd_icon)) = self.dnd_icons.pop() {
|
||||
dnd_icon.seat.remove_dnd_icon();
|
||||
if self.visible.get() {
|
||||
dnd_icon.damage();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -1169,6 +1179,18 @@ impl WlSurface {
|
|||
y2,
|
||||
buffer_transform: self.buffer_transform.get(),
|
||||
};
|
||||
let (buffer_width, buffer_height) = buffer.buffer.rect.size();
|
||||
let (dst_width, dst_height) = new_size.unwrap_or_default();
|
||||
let damage_matrix = DamageMatrix::new(
|
||||
self.buffer_transform.get(),
|
||||
self.buffer_scale.get(),
|
||||
buffer_width,
|
||||
buffer_height,
|
||||
self.src_rect.get(),
|
||||
dst_width,
|
||||
dst_height,
|
||||
);
|
||||
self.damage_matrix.set(damage_matrix);
|
||||
}
|
||||
}
|
||||
let (width, height) = new_size.unwrap_or_default();
|
||||
|
|
@ -1232,15 +1254,65 @@ impl WlSurface {
|
|||
fr.send_done(now);
|
||||
let _ = fr.client.remove_obj(&*fr);
|
||||
}
|
||||
} else {
|
||||
self.apply_damage(pending);
|
||||
}
|
||||
}
|
||||
self.client.state.damage();
|
||||
pending.buffer_damage.clear();
|
||||
pending.surface_damage.clear();
|
||||
pending.damage_full = false;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn apply_damage(&self, pending: &PendingState) {
|
||||
let bounds = self.toplevel.get().map(|tl| tl.node_absolute_position());
|
||||
let pos = self.buffer_abs_pos.get();
|
||||
let apply_damage = |pos: Rect| {
|
||||
if pending.damage_full {
|
||||
let mut damage = pos;
|
||||
if let Some(bounds) = bounds {
|
||||
damage = damage.intersect(bounds);
|
||||
}
|
||||
self.client.state.damage(damage);
|
||||
} else {
|
||||
let matrix = self.damage_matrix.get();
|
||||
if let Some(buffer) = self.buffer.get() {
|
||||
for damage in &pending.buffer_damage {
|
||||
let mut damage =
|
||||
matrix.apply(pos.x1(), pos.y1(), damage.intersect(buffer.buffer.rect));
|
||||
if let Some(bounds) = bounds {
|
||||
damage = damage.intersect(bounds);
|
||||
}
|
||||
self.client.state.damage(damage);
|
||||
}
|
||||
}
|
||||
for damage in &pending.surface_damage {
|
||||
let mut damage = damage.move_(pos.x1(), pos.y1());
|
||||
damage = damage.intersect(bounds.unwrap_or(pos));
|
||||
self.client.state.damage(damage);
|
||||
}
|
||||
}
|
||||
};
|
||||
match self.role.get() {
|
||||
SurfaceRole::Cursor => {
|
||||
for (_, cursor) in &self.cursors {
|
||||
if cursor.needs_damage_tracking() {
|
||||
let (x, y) = cursor.surface_position();
|
||||
apply_damage(pos.at_point(x, y));
|
||||
}
|
||||
}
|
||||
}
|
||||
SurfaceRole::DndIcon => {
|
||||
for (_, dnd_icon) in &self.dnd_icons {
|
||||
let (x, y) = dnd_icon.seat.pointer_cursor().position_int();
|
||||
let (x, y) = dnd_icon.surface_position(x, y);
|
||||
apply_damage(pos.at_point(x, y));
|
||||
}
|
||||
}
|
||||
_ => apply_damage(pos),
|
||||
}
|
||||
}
|
||||
|
||||
fn verify_explicit_sync(&self, pending: &mut PendingState) -> Result<(), WlSurfaceError> {
|
||||
pending.explicit_sync = self.sync_obj_surface.is_some();
|
||||
if !pending.explicit_sync {
|
||||
|
|
@ -1378,8 +1450,8 @@ impl WlSurface {
|
|||
}
|
||||
}
|
||||
self.seat_state.destroy_node(self);
|
||||
if self.visible.get() {
|
||||
self.client.state.damage();
|
||||
if self.visible.get() && self.toplevel.is_none() {
|
||||
self.client.state.damage(self.buffer_abs_pos.get());
|
||||
}
|
||||
if set_invisible {
|
||||
self.visible.set(false);
|
||||
|
|
@ -1757,3 +1829,114 @@ efrom!(WlSurfaceError, ClientError);
|
|||
efrom!(WlSurfaceError, XdgSurfaceError);
|
||||
efrom!(WlSurfaceError, ZwlrLayerSurfaceV1Error);
|
||||
efrom!(WlSurfaceError, CommitTimelineError);
|
||||
|
||||
#[derive(Copy, Clone, Debug)]
|
||||
struct DamageMatrix {
|
||||
transform: Transform,
|
||||
mx: f64,
|
||||
my: f64,
|
||||
dx: f64,
|
||||
dy: f64,
|
||||
smear: i32,
|
||||
}
|
||||
|
||||
impl Default for DamageMatrix {
|
||||
fn default() -> Self {
|
||||
Self {
|
||||
transform: Default::default(),
|
||||
mx: 1.0,
|
||||
my: 1.0,
|
||||
dx: 0.0,
|
||||
dy: 0.0,
|
||||
smear: 0,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl DamageMatrix {
|
||||
fn apply(&self, dx: i32, dy: i32, rect: Rect) -> Rect {
|
||||
let x1 = rect.x1() - self.smear;
|
||||
let x2 = rect.x2() + self.smear;
|
||||
let y1 = rect.y1() - self.smear;
|
||||
let y2 = rect.y2() + self.smear;
|
||||
let [x1, y1, x2, y2] = match self.transform {
|
||||
Transform::None => [x1, y1, x2, y2],
|
||||
Transform::Rotate90 => [-y2, x1, -y1, x2],
|
||||
Transform::Rotate180 => [-x2, -y2, -x1, -y1],
|
||||
Transform::Rotate270 => [y1, -x2, y2, -x1],
|
||||
Transform::Flip => [-x2, y1, -x1, y2],
|
||||
Transform::FlipRotate90 => [y1, x1, y2, x2],
|
||||
Transform::FlipRotate180 => [x1, -y2, x2, -y1],
|
||||
Transform::FlipRotate270 => [-y2, -x2, -y1, -x1],
|
||||
};
|
||||
let x1 = (x1 as f64 * self.mx + self.dx).floor() as i32 + dx;
|
||||
let y1 = (y1 as f64 * self.my + self.dy).floor() as i32 + dy;
|
||||
let x2 = (x2 as f64 * self.mx + self.dx).ceil() as i32 + dx;
|
||||
let y2 = (y2 as f64 * self.my + self.dy).ceil() as i32 + dy;
|
||||
Rect::new(x1, y1, x2, y2).unwrap()
|
||||
}
|
||||
|
||||
fn new(
|
||||
transform: Transform,
|
||||
legacy_scale: i32,
|
||||
buffer_width: i32,
|
||||
buffer_height: i32,
|
||||
viewport: Option<[Fixed; 4]>,
|
||||
dst_width: i32,
|
||||
dst_height: i32,
|
||||
) -> DamageMatrix {
|
||||
let mut buffer_width = buffer_width as f64;
|
||||
let mut buffer_height = buffer_height as f64;
|
||||
let dst_width = dst_width as f64;
|
||||
let dst_height = dst_height as f64;
|
||||
|
||||
let mut mx = 1.0;
|
||||
let mut my = 1.0;
|
||||
if legacy_scale != 1 {
|
||||
let scale_inv = 1.0 / (legacy_scale as f64);
|
||||
mx = scale_inv;
|
||||
my = scale_inv;
|
||||
buffer_width *= scale_inv;
|
||||
buffer_height *= scale_inv;
|
||||
}
|
||||
let (mut buffer_width, mut buffer_height) =
|
||||
transform.maybe_swap((buffer_width, buffer_height));
|
||||
let (mut dx, mut dy) = match transform {
|
||||
Transform::None => (0.0, 0.0),
|
||||
Transform::Rotate90 => (buffer_width, 0.0),
|
||||
Transform::Rotate180 => (buffer_width, buffer_height),
|
||||
Transform::Rotate270 => (0.0, buffer_height),
|
||||
Transform::Flip => (buffer_width, 0.0),
|
||||
Transform::FlipRotate90 => (0.0, 0.0),
|
||||
Transform::FlipRotate180 => (0.0, buffer_height),
|
||||
Transform::FlipRotate270 => (buffer_width, buffer_height),
|
||||
};
|
||||
if let Some([x, y, w, h]) = viewport {
|
||||
dx -= x.to_f64();
|
||||
dy -= y.to_f64();
|
||||
buffer_width = w.to_f64();
|
||||
buffer_height = h.to_f64();
|
||||
}
|
||||
let mut smear = false;
|
||||
if dst_width != buffer_width {
|
||||
let scale = dst_width / buffer_width;
|
||||
mx *= scale;
|
||||
dx *= scale;
|
||||
smear |= dst_width > buffer_width;
|
||||
}
|
||||
if dst_height != buffer_height {
|
||||
let scale = dst_height / buffer_height;
|
||||
my *= scale;
|
||||
dy *= scale;
|
||||
smear |= dst_height > buffer_height;
|
||||
}
|
||||
DamageMatrix {
|
||||
transform,
|
||||
mx,
|
||||
my,
|
||||
dx,
|
||||
dy,
|
||||
smear: smear as _,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -60,6 +60,16 @@ impl CursorSurface {
|
|||
pub fn update_hardware_cursor(&self) {
|
||||
self.user.update_hardware_cursor();
|
||||
}
|
||||
|
||||
pub fn needs_damage_tracking(&self) -> bool {
|
||||
self.user.software_cursor()
|
||||
}
|
||||
|
||||
pub fn surface_position(&self) -> (i32, i32) {
|
||||
let (x, y) = self.user.position();
|
||||
let (dx, dy) = self.hotspot.get();
|
||||
(x.to_int() - dx, y.to_int() - dy)
|
||||
}
|
||||
}
|
||||
|
||||
impl Cursor for CursorSurface {
|
||||
|
|
|
|||
|
|
@ -18,9 +18,13 @@ impl DndIcon {
|
|||
}
|
||||
|
||||
fn update_visible(&self) {
|
||||
let was_visible = self.surface.visible.get();
|
||||
let is_visible =
|
||||
self.surface.dnd_icons.is_not_empty() && self.surface.client.state.root_visible();
|
||||
self.surface.set_visible(is_visible);
|
||||
if was_visible != is_visible {
|
||||
self.damage();
|
||||
}
|
||||
}
|
||||
|
||||
pub fn enable(self: &Rc<Self>) {
|
||||
|
|
@ -45,6 +49,16 @@ impl DndIcon {
|
|||
self.surface.extents.get().move_(x, y)
|
||||
}
|
||||
|
||||
pub fn damage(&self) {
|
||||
let (x, y) = self.seat.pointer_cursor().position_int();
|
||||
self.damage_at(x, y);
|
||||
}
|
||||
|
||||
pub fn damage_at(&self, x: i32, y: i32) {
|
||||
let extents = self.extents(x, y);
|
||||
self.surface.client.state.damage(extents);
|
||||
}
|
||||
|
||||
pub fn render(&self, renderer: &mut Renderer<'_>, cursor_rect: &Rect, x: i32, y: i32) {
|
||||
let extents = self.extents(x, y);
|
||||
if extents.intersects(&cursor_rect) {
|
||||
|
|
|
|||
|
|
@ -352,6 +352,9 @@ impl SurfaceExt for WlSubsurface {
|
|||
if self.had_buffer.replace(has_buffer) != has_buffer {
|
||||
if has_buffer {
|
||||
if self.parent.visible.get() {
|
||||
let (x, y) = self.surface.buffer_abs_pos.get().position();
|
||||
let extents = self.surface.extents.get();
|
||||
self.surface.client.state.damage(extents.move_(x, y));
|
||||
self.surface.set_visible(true);
|
||||
}
|
||||
} else {
|
||||
|
|
|
|||
|
|
@ -252,6 +252,7 @@ impl Xwindow {
|
|||
|
||||
pub fn map_status_changed(self: &Rc<Self>) {
|
||||
let map_change = self.map_change();
|
||||
let override_redirect = self.data.info.override_redirect.get();
|
||||
match map_change {
|
||||
Change::None => return,
|
||||
Change::Unmap => {
|
||||
|
|
@ -261,7 +262,7 @@ impl Xwindow {
|
|||
.set(self.data.info.extents.take());
|
||||
self.tl_destroy();
|
||||
}
|
||||
Change::Map if self.data.info.override_redirect.get() => {
|
||||
Change::Map if override_redirect => {
|
||||
self.clone()
|
||||
.tl_change_extents(&self.data.info.pending_extents.get());
|
||||
*self.display_link.borrow_mut() =
|
||||
|
|
@ -284,12 +285,17 @@ impl Xwindow {
|
|||
match map_change {
|
||||
Change::Unmap => self.tl_set_visible(false),
|
||||
Change::Map => {
|
||||
self.tl_set_visible(true);
|
||||
if override_redirect {
|
||||
self.tl_set_visible(true);
|
||||
}
|
||||
self.toplevel_data.broadcast(self.clone());
|
||||
}
|
||||
Change::None => {}
|
||||
}
|
||||
self.data.state.tree_changed();
|
||||
if override_redirect {
|
||||
self.data.state.damage(self.data.info.pending_extents.get());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -414,7 +420,10 @@ impl ToplevelNodeBase for Xwindow {
|
|||
// log::info!("xwin {} change_extents {:?}", self.data.window_id, rect);
|
||||
let old = self.data.info.extents.replace(*rect);
|
||||
if old != *rect {
|
||||
if !self.data.info.override_redirect.get() {
|
||||
if self.data.info.override_redirect.get() {
|
||||
self.data.state.damage(old);
|
||||
self.data.state.damage(*rect);
|
||||
} else {
|
||||
self.data
|
||||
.state
|
||||
.xwayland
|
||||
|
|
|
|||
|
|
@ -167,6 +167,10 @@ pub trait XdgSurfaceExt: Debug {
|
|||
fn extents_changed(&self) {
|
||||
// nothing
|
||||
}
|
||||
|
||||
fn geometry_changed(&self) {
|
||||
// nothing
|
||||
}
|
||||
}
|
||||
|
||||
impl XdgSurface {
|
||||
|
|
@ -258,6 +262,12 @@ impl XdgSurface {
|
|||
}
|
||||
}
|
||||
|
||||
pub fn damage(&self) {
|
||||
let (x, y) = self.surface.buffer_abs_pos.get().position();
|
||||
let extents = self.surface.extents.get();
|
||||
self.surface.client.state.damage(extents.move_(x, y));
|
||||
}
|
||||
|
||||
pub fn geometry(&self) -> Option<Rect> {
|
||||
self.geometry.get()
|
||||
}
|
||||
|
|
@ -497,6 +507,9 @@ impl SurfaceExt for XdgSurface {
|
|||
if prev != Some(geometry) {
|
||||
self.update_extents();
|
||||
self.update_surface_position();
|
||||
if let Some(ext) = self.ext.get() {
|
||||
ext.geometry_changed();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -407,11 +407,13 @@ impl XdgToplevel {
|
|||
}
|
||||
self.toplevel_data.broadcast(self.clone());
|
||||
self.tl_set_visible(self.state.root_visible());
|
||||
self.xdg.damage();
|
||||
}
|
||||
self.extents_changed();
|
||||
} else {
|
||||
if self.is_mapped.replace(false) {
|
||||
self.tl_set_visible(false);
|
||||
self.xdg.damage();
|
||||
}
|
||||
}
|
||||
return;
|
||||
|
|
@ -677,6 +679,14 @@ impl XdgSurfaceExt for XdgToplevel {
|
|||
self.toplevel_data.pos.set(self.xdg.extents.get());
|
||||
self.tl_extents_changed();
|
||||
}
|
||||
|
||||
fn geometry_changed(&self) {
|
||||
self.xdg
|
||||
.surface
|
||||
.client
|
||||
.state
|
||||
.damage(self.node_absolute_position());
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Error)]
|
||||
|
|
|
|||
|
|
@ -588,6 +588,11 @@ impl SurfaceExt for ZwlrLayerSurfaceV1 {
|
|||
}
|
||||
if self.mapped.get() != was_mapped {
|
||||
output.update_visible();
|
||||
if self.mapped.get() {
|
||||
let (x, y) = self.surface.buffer_abs_pos.get().position();
|
||||
let extents = self.surface.extents.get().move_(x, y);
|
||||
self.client.state.damage(extents);
|
||||
}
|
||||
}
|
||||
if self.mapped.get() {
|
||||
match self.keyboard_interactivity.get() {
|
||||
|
|
|
|||
|
|
@ -44,17 +44,24 @@ pub async fn input_popup_positioning(state: Rc<State>) {
|
|||
}
|
||||
|
||||
impl ZwpInputPopupSurfaceV2 {
|
||||
fn damage(&self) {
|
||||
let (x, y) = self.surface.buffer_abs_pos.get().position();
|
||||
let extents = self.surface.extents.get();
|
||||
self.client.state.damage(extents.move_(x, y));
|
||||
}
|
||||
|
||||
pub fn update_visible(self: &Rc<Self>) {
|
||||
let was_visible = self.surface.visible.get();
|
||||
let is_visible = self.surface.buffer.is_some()
|
||||
&& self.input_method.connection.is_some()
|
||||
&& self.client.state.root_visible();
|
||||
self.surface.set_visible(is_visible);
|
||||
if was_visible || is_visible {
|
||||
self.client.state.damage();
|
||||
}
|
||||
if !was_visible && is_visible {
|
||||
self.schedule_positioning();
|
||||
if was_visible != is_visible {
|
||||
if is_visible {
|
||||
self.schedule_positioning();
|
||||
} else {
|
||||
self.damage();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -132,6 +139,9 @@ impl ZwpInputPopupSurfaceV2 {
|
|||
}
|
||||
|
||||
fn detach(&self) {
|
||||
if self.surface.visible.get() {
|
||||
self.damage();
|
||||
}
|
||||
self.surface.destroy_node();
|
||||
self.surface.unset_ext();
|
||||
self.input_method.popups.remove(&self.id);
|
||||
|
|
|
|||
|
|
@ -9,7 +9,7 @@ use {
|
|||
object::{Object, Version},
|
||||
rect::Rect,
|
||||
renderer::Renderer,
|
||||
tree::ToplevelNode,
|
||||
tree::{Node, ToplevelNode},
|
||||
utils::clonecell::CloneCell,
|
||||
wire::{xdg_toplevel_drag_v1::*, XdgToplevelDragV1Id},
|
||||
},
|
||||
|
|
@ -53,16 +53,22 @@ impl XdgToplevelDragV1 {
|
|||
}
|
||||
}
|
||||
|
||||
fn move2(&self, x: i32, y: i32) {
|
||||
fn move2(&self, x: i32, y: i32, damage_initial: bool) {
|
||||
if let Some(tl) = self.toplevel.get() {
|
||||
if damage_initial && tl.node_visible() {
|
||||
tl.xdg.damage();
|
||||
}
|
||||
let extents = tl.xdg.absolute_desired_extents.get();
|
||||
let extents = extents.at_point(x - self.x_off.get(), y - self.y_off.get());
|
||||
tl.clone().tl_change_extents(&extents);
|
||||
if tl.node_visible() {
|
||||
tl.xdg.damage();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn move_(&self, x: i32, y: i32) {
|
||||
self.move2(x, y);
|
||||
self.move2(x, y, true);
|
||||
}
|
||||
|
||||
pub fn render(&self, renderer: &mut Renderer<'_>, cursor_rect: &Rect, x: i32, y: i32) {
|
||||
|
|
@ -122,7 +128,7 @@ impl XdgToplevelDragV1 {
|
|||
self.client.state.tree_changed();
|
||||
if let Some(seat) = self.source.data.seat.get() {
|
||||
let (x, y) = seat.pointer_cursor().position_int();
|
||||
self.move2(x, y)
|
||||
self.move2(x, y, false)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
16
src/state.rs
16
src/state.rs
|
|
@ -662,7 +662,6 @@ impl State {
|
|||
ws.flush_jay_workspaces();
|
||||
output.schedule_update_render_data();
|
||||
self.tree_changed();
|
||||
self.damage();
|
||||
// let seats = self.globals.seats.lock();
|
||||
// for seat in seats.values() {
|
||||
// seat.workspace_changed(&output);
|
||||
|
|
@ -689,7 +688,6 @@ impl State {
|
|||
for output in outputs.values() {
|
||||
output.set_status(&status);
|
||||
}
|
||||
self.damage();
|
||||
}
|
||||
|
||||
pub fn input_occurred(&self) {
|
||||
|
|
@ -731,10 +729,14 @@ impl State {
|
|||
serial as _
|
||||
}
|
||||
|
||||
pub fn damage(&self) {
|
||||
for connector in self.connectors.lock().values() {
|
||||
if connector.connected.get() {
|
||||
connector.connector.damage();
|
||||
pub fn damage(&self, rect: Rect) {
|
||||
if rect.is_empty() {
|
||||
return;
|
||||
}
|
||||
self.damage_visualizer.add(rect);
|
||||
for output in self.root.outputs.lock().values() {
|
||||
if output.global.pos.get().intersects(&rect) {
|
||||
output.global.connector.connector.damage();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -748,7 +750,7 @@ impl State {
|
|||
}
|
||||
}
|
||||
self.tree_changed();
|
||||
self.damage();
|
||||
self.damage(self.root.extents.get());
|
||||
}
|
||||
|
||||
pub fn clear(&self) {
|
||||
|
|
|
|||
|
|
@ -172,7 +172,9 @@ impl ConnectorHandler {
|
|||
update_render_data_scheduled: Cell::new(false),
|
||||
hardware_cursor_needs_render: Cell::new(false),
|
||||
screencopies: Default::default(),
|
||||
title_visible: Default::default(),
|
||||
});
|
||||
on.update_visible();
|
||||
on.update_rects();
|
||||
self.state
|
||||
.add_output_scale(on.global.persistent.scale.get());
|
||||
|
|
@ -295,7 +297,7 @@ impl ConnectorHandler {
|
|||
.remove_output_scale(on.global.persistent.scale.get());
|
||||
let _ = self.state.remove_global(&*global);
|
||||
self.state.tree_changed();
|
||||
self.state.damage();
|
||||
self.state.damage(self.state.root.extents.get());
|
||||
}
|
||||
|
||||
async fn handle_non_desktop_connected(&self, monitor_info: MonitorInfo) {
|
||||
|
|
|
|||
|
|
@ -355,9 +355,24 @@ impl ContainerNode {
|
|||
self.schedule_compute_render_data();
|
||||
}
|
||||
|
||||
fn damage(&self) {
|
||||
self.state.damage(
|
||||
Rect::new_sized(
|
||||
self.abs_x1.get(),
|
||||
self.abs_y1.get(),
|
||||
self.width.get(),
|
||||
self.height.get(),
|
||||
)
|
||||
.unwrap(),
|
||||
);
|
||||
}
|
||||
|
||||
fn schedule_layout(self: &Rc<Self>) {
|
||||
if !self.layout_scheduled.replace(true) {
|
||||
self.state.pending_container_layout.push(self.clone());
|
||||
if self.toplevel_data.visible.get() {
|
||||
self.damage();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -677,8 +692,13 @@ impl ContainerNode {
|
|||
let split = self.split.get();
|
||||
let have_active = self.children.iter().any(|c| c.active.get());
|
||||
let scales = self.state.scales.lock();
|
||||
let abs_x = self.abs_x1.get();
|
||||
let abs_y = self.abs_y1.get();
|
||||
for (i, child) in self.children.iter().enumerate() {
|
||||
let rect = child.title_rect.get();
|
||||
if self.toplevel_data.visible.get() {
|
||||
self.state.damage(rect.move_(abs_x, abs_y));
|
||||
}
|
||||
if i > 0 {
|
||||
let rect = if mono {
|
||||
Rect::new_sized(rect.x1() - bw, 0, bw, th)
|
||||
|
|
@ -1471,6 +1491,7 @@ impl ContainingNode for ContainerNode {
|
|||
if let Some(body) = body {
|
||||
let body = body.move_(self.abs_x1.get(), self.abs_y1.get());
|
||||
new.clone().tl_change_extents(&body);
|
||||
self.state.damage(body);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -79,6 +79,9 @@ impl DisplayNode {
|
|||
for seat in state.globals.seats.lock().values() {
|
||||
seat.set_visible(visible);
|
||||
}
|
||||
if visible {
|
||||
state.damage(self.extents.get());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -135,6 +135,9 @@ impl FloatNode {
|
|||
child.tl_set_visible(floater.visible.get());
|
||||
child.tl_restack_popups();
|
||||
floater.schedule_layout();
|
||||
if floater.visible.get() {
|
||||
state.damage(position);
|
||||
}
|
||||
floater
|
||||
}
|
||||
|
||||
|
|
@ -199,11 +202,12 @@ impl FloatNode {
|
|||
_ => return,
|
||||
};
|
||||
let scales = self.state.scales.lock();
|
||||
let tr = Rect::new_sized(pos.x1() + bw, pos.y1() + bw, pos.width() - 2 * bw, th).unwrap();
|
||||
for (scale, _) in scales.iter() {
|
||||
let old_tex = self.title_textures.remove(scale);
|
||||
let mut th = th;
|
||||
let mut th = tr.height();
|
||||
let mut scalef = None;
|
||||
let mut width = pos.width() - 2 * bw;
|
||||
let mut width = tr.width();
|
||||
if *scale != 1 {
|
||||
let scale = scale.to_f64();
|
||||
th = (th as f64 * scale).round() as _;
|
||||
|
|
@ -222,6 +226,9 @@ impl FloatNode {
|
|||
};
|
||||
self.title_textures.set(*scale, texture);
|
||||
}
|
||||
if self.visible.get() {
|
||||
self.state.damage(tr);
|
||||
}
|
||||
}
|
||||
|
||||
fn pointer_move(
|
||||
|
|
@ -307,8 +314,12 @@ impl FloatNode {
|
|||
y2 = y2.max(y1 + 2 * bw + th + 1);
|
||||
}
|
||||
}
|
||||
self.position.set(Rect::new(x1, y1, x2, y2).unwrap());
|
||||
self.state.damage();
|
||||
let new_pos = Rect::new(x1, y1, x2, y2).unwrap();
|
||||
self.position.set(new_pos);
|
||||
if self.visible.get() {
|
||||
self.state.damage(pos);
|
||||
self.state.damage(new_pos);
|
||||
}
|
||||
self.schedule_layout();
|
||||
return;
|
||||
}
|
||||
|
|
@ -684,6 +695,9 @@ impl ContainingNode for FloatNode {
|
|||
self.pull_child_properties();
|
||||
new.tl_set_visible(self.visible.get());
|
||||
self.schedule_layout();
|
||||
if self.visible.get() {
|
||||
self.state.damage(self.position.get());
|
||||
}
|
||||
}
|
||||
|
||||
fn cnode_remove_child2(self: Rc<Self>, _child: &dyn Node, _preserve_focus: bool) {
|
||||
|
|
@ -691,6 +705,9 @@ impl ContainingNode for FloatNode {
|
|||
self.child.set(None);
|
||||
self.display_link.borrow_mut().take();
|
||||
self.workspace_link.set(None);
|
||||
if self.visible.get() {
|
||||
self.state.damage(self.position.get());
|
||||
}
|
||||
}
|
||||
|
||||
fn cnode_accepts_child(&self, _node: &dyn Node) -> bool {
|
||||
|
|
@ -716,8 +733,10 @@ impl ContainingNode for FloatNode {
|
|||
let (x, y) = (x - bw, y - th - bw - 1);
|
||||
let pos = self.position.get();
|
||||
if pos.position() != (x, y) {
|
||||
self.position.set(pos.at_point(x, y));
|
||||
self.state.damage();
|
||||
let new_pos = pos.at_point(x, y);
|
||||
self.position.set(new_pos);
|
||||
self.state.damage(pos);
|
||||
self.state.damage(new_pos);
|
||||
self.schedule_layout();
|
||||
}
|
||||
}
|
||||
|
|
@ -753,7 +772,10 @@ impl ContainingNode for FloatNode {
|
|||
let new_pos = Rect::new(x1, y1, x2, y2).unwrap();
|
||||
if new_pos != pos {
|
||||
self.position.set(new_pos);
|
||||
self.state.damage();
|
||||
if self.visible.get() {
|
||||
self.state.damage(pos);
|
||||
self.state.damage(new_pos);
|
||||
}
|
||||
self.schedule_layout();
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -76,6 +76,7 @@ pub struct OutputNode {
|
|||
pub update_render_data_scheduled: Cell<bool>,
|
||||
pub screencasts: CopyHashMap<(ClientId, JayScreencastId), Rc<JayScreencast>>,
|
||||
pub screencopies: CopyHashMap<(ClientId, ZwlrScreencopyFrameV1Id), Rc<ZwlrScreencopyFrameV1>>,
|
||||
pub title_visible: Cell<bool>,
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone, Debug, Eq, PartialEq, Hash)]
|
||||
|
|
@ -114,6 +115,9 @@ impl OutputNode {
|
|||
if let Some(c) = self.workspace.get() {
|
||||
c.change_extents(&self.workspace_rect.get());
|
||||
}
|
||||
if self.node_visible() {
|
||||
self.state.damage(self.global.pos.get());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -307,7 +311,8 @@ impl OutputNode {
|
|||
texture_height = (th as f64 * scale).round() as _;
|
||||
}
|
||||
let active_id = self.workspace.get().map(|w| w.id);
|
||||
let output_width = self.non_exclusive_rect.get().width();
|
||||
let non_exclusive_rect = self.non_exclusive_rect.get();
|
||||
let output_width = non_exclusive_rect.width();
|
||||
rd.underline = Rect::new_sized(0, th, output_width, 1).unwrap();
|
||||
for ws in self.workspaces.iter() {
|
||||
let old_tex = ws.title_texture.take();
|
||||
|
|
@ -414,7 +419,16 @@ impl OutputNode {
|
|||
tex: title,
|
||||
});
|
||||
}
|
||||
self.state.damage();
|
||||
if self.title_visible.get() {
|
||||
let title_rect = Rect::new_sized(
|
||||
non_exclusive_rect.x1(),
|
||||
non_exclusive_rect.y1(),
|
||||
non_exclusive_rect.width(),
|
||||
th,
|
||||
)
|
||||
.unwrap();
|
||||
self.state.damage(title_rect);
|
||||
}
|
||||
}
|
||||
|
||||
pub fn ensure_workspace(self: &Rc<Self>) -> Rc<WorkspaceNode> {
|
||||
|
|
@ -460,12 +474,16 @@ impl OutputNode {
|
|||
for seat in seats {
|
||||
ws.clone().node_do_focus(&seat, Direction::Unspecified);
|
||||
}
|
||||
if self.node_visible() {
|
||||
self.state.damage(self.global.pos.get());
|
||||
}
|
||||
true
|
||||
}
|
||||
|
||||
pub fn create_workspace(self: &Rc<Self>, name: &str) -> Rc<WorkspaceNode> {
|
||||
let ws = Rc::new(WorkspaceNode {
|
||||
id: self.state.node_ids.next(),
|
||||
state: self.state.clone(),
|
||||
is_dummy: false,
|
||||
output: CloneCell::new(self.clone()),
|
||||
position: Cell::new(Default::default()),
|
||||
|
|
@ -582,6 +600,11 @@ impl OutputNode {
|
|||
}
|
||||
|
||||
fn change_extents_(self: &Rc<Self>, rect: &Rect) {
|
||||
if self.node_visible() {
|
||||
let old_pos = self.global.pos.get();
|
||||
self.state.damage(old_pos);
|
||||
self.state.damage(*rect);
|
||||
}
|
||||
self.global.persistent.pos.set((rect.x1(), rect.y1()));
|
||||
self.global.pos.set(*rect);
|
||||
self.state.root.update_extents();
|
||||
|
|
@ -702,6 +725,13 @@ impl OutputNode {
|
|||
prev
|
||||
}
|
||||
|
||||
pub fn fullscreen_changed(&self) {
|
||||
self.update_visible();
|
||||
if self.node_visible() {
|
||||
self.state.damage(self.global.pos.get());
|
||||
}
|
||||
}
|
||||
|
||||
pub fn update_visible(&self) {
|
||||
let mut visible = self.state.root_visible();
|
||||
if self.state.lock.locked.get() {
|
||||
|
|
@ -722,6 +752,7 @@ impl OutputNode {
|
|||
have_fullscreen = ws.fullscreen.is_some();
|
||||
}
|
||||
let lower_visible = visible && !have_fullscreen;
|
||||
self.title_visible.set(lower_visible);
|
||||
set_layer_visible!(self.layers[0], lower_visible);
|
||||
set_layer_visible!(self.layers[1], lower_visible);
|
||||
if let Some(ws) = self.workspace.get() {
|
||||
|
|
@ -822,7 +853,7 @@ impl Node for OutputNode {
|
|||
}
|
||||
|
||||
fn node_visible(&self) -> bool {
|
||||
true
|
||||
self.state.root_visible()
|
||||
}
|
||||
|
||||
fn node_absolute_position(&self) -> Rect {
|
||||
|
|
|
|||
|
|
@ -435,7 +435,6 @@ impl ToplevelData {
|
|||
.tl_into_node()
|
||||
.node_do_focus(&seat, Direction::Unspecified);
|
||||
}
|
||||
state.damage();
|
||||
}
|
||||
|
||||
pub fn unset_fullscreen(&self, state: &Rc<State>, node: Rc<dyn ToplevelNode>) {
|
||||
|
|
@ -480,7 +479,6 @@ impl ToplevelData {
|
|||
fd.placeholder
|
||||
.node_seat_state()
|
||||
.destroy_node(fd.placeholder.deref());
|
||||
state.damage();
|
||||
}
|
||||
|
||||
pub fn set_visible(&self, node: &dyn Node, visible: bool) {
|
||||
|
|
@ -496,7 +494,6 @@ impl ToplevelData {
|
|||
if let Some(parent) = self.parent.get() {
|
||||
parent.cnode_child_attention_request_changed(node, false);
|
||||
}
|
||||
self.state.damage();
|
||||
}
|
||||
|
||||
pub fn request_attention(&self, node: &dyn Node) {
|
||||
|
|
@ -510,6 +507,5 @@ impl ToplevelData {
|
|||
if let Some(parent) = self.parent.get() {
|
||||
parent.cnode_child_attention_request_changed(node, true);
|
||||
}
|
||||
self.state.damage();
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -11,6 +11,7 @@ use {
|
|||
},
|
||||
rect::Rect,
|
||||
renderer::Renderer,
|
||||
state::State,
|
||||
text::TextTexture,
|
||||
tree::{
|
||||
container::ContainerNode, walker::NodeVisitor, ContainingNode, Direction,
|
||||
|
|
@ -38,6 +39,7 @@ tree_id!(WorkspaceNodeId);
|
|||
|
||||
pub struct WorkspaceNode {
|
||||
pub id: WorkspaceNodeId,
|
||||
pub state: Rc<State>,
|
||||
pub is_dummy: bool,
|
||||
pub output: CloneCell<Rc<OutputNode>>,
|
||||
pub position: Cell<Rect>,
|
||||
|
|
@ -85,6 +87,7 @@ impl WorkspaceNode {
|
|||
}
|
||||
if self.has_capture.replace(has_capture) != has_capture {
|
||||
output.schedule_update_render_data();
|
||||
output.state.damage(output.global.pos.get());
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -117,6 +120,7 @@ impl WorkspaceNode {
|
|||
container.tl_set_parent(self.clone());
|
||||
container.tl_set_visible(self.container_visible());
|
||||
self.container.set(Some(container.clone()));
|
||||
self.state.damage(self.position.get());
|
||||
}
|
||||
|
||||
pub fn is_empty(&self) -> bool {
|
||||
|
|
@ -168,7 +172,7 @@ impl WorkspaceNode {
|
|||
}
|
||||
self.pull_child_properties(&**node);
|
||||
if self.visible.get() {
|
||||
self.output.get().update_visible();
|
||||
self.output.get().fullscreen_changed();
|
||||
} else {
|
||||
node.tl_set_visible(false);
|
||||
}
|
||||
|
|
@ -183,7 +187,7 @@ impl WorkspaceNode {
|
|||
if let Some(node) = self.fullscreen.take() {
|
||||
self.discard_child_properties(&*node);
|
||||
if self.visible.get() {
|
||||
self.output.get().update_visible();
|
||||
self.output.get().fullscreen_changed();
|
||||
}
|
||||
if let Some(surface) = node.tl_scanout_surface() {
|
||||
if let Some(fb) = surface.client.state.drm_feedback.get() {
|
||||
|
|
@ -324,6 +328,7 @@ impl ContainingNode for WorkspaceNode {
|
|||
if container.node_id() == child.node_id() {
|
||||
self.discard_child_properties(&*container);
|
||||
self.container.set(None);
|
||||
self.state.damage(self.position.get());
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
|
@ -387,4 +392,10 @@ pub fn move_ws_to_output(
|
|||
if !source.is_dummy {
|
||||
source.schedule_update_render_data();
|
||||
}
|
||||
if source.node_visible() {
|
||||
target.state.damage(source.global.pos.get());
|
||||
}
|
||||
if target.node_visible() {
|
||||
target.state.damage(target.global.pos.get());
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue