Skip to content

Commit e2f741f

Browse files
committed
X11 impl
1 parent 94f43b8 commit e2f741f

5 files changed

Lines changed: 193 additions & 4 deletions

File tree

‎Cargo.toml‎

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -96,7 +96,18 @@ objc2-app-kit = { version = "0.3.2", default-features = false, features = [
9696
] }
9797

9898
[workspace]
99-
members = ["examples/cursors", "examples/open_parented", "examples/open_window", "examples/plugin_clack", "examples/render_femtovg", "examples/render_wgpu", "examples/plugin_clack_femtovg", "examples/test-frame-pacing", "examples/external-wakeup"]
99+
members = [
100+
"examples/cursors",
101+
"examples/open_parented",
102+
"examples/open_window",
103+
"examples/plugin_clack",
104+
"examples/render_femtovg",
105+
"examples/render_wgpu",
106+
"examples/plugin_clack_femtovg",
107+
"examples/test-frame-pacing",
108+
"examples/external-wakeup",
109+
"tests/partial-rendering"
110+
]
100111

101112
[lints.clippy]
102113
missing-safety-doc = "allow"

‎src/handler.rs‎

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,24 @@
11
use super::*;
2+
use crate::dpi::{PhysicalPosition, PhysicalSize};
23
use crate::platform::Result;
34

45
#[non_exhaustive]
6+
#[derive(Debug, Copy, Clone)]
57
pub enum DamageArea {
68
FullWindow,
7-
// Later: single rect, perhaps list of rects
9+
Rect { position: PhysicalPosition<u32>, size: PhysicalSize<u32> },
10+
}
11+
12+
impl DamageArea {
13+
pub(crate) fn from_rect_and_window_size(
14+
position: PhysicalPosition<u32>, size: PhysicalSize<u32>, window_size: PhysicalSize<u32>,
15+
) -> Self {
16+
if position.x == 0 && position.y == 0 && size == window_size {
17+
Self::FullWindow
18+
} else {
19+
Self::Rect { position, size }
20+
}
21+
}
822
}
923

1024
pub trait WindowHandler: 'static {

‎src/platform/x11/event_loop.rs‎

Lines changed: 13 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,12 +9,13 @@ use crate::platform::x11::error::FatalError;
99
use crate::platform::x11::window_thread::{
1010
HostCallback, WindowThreadRequest, WindowThreadResponseMessage,
1111
};
12-
use crate::warn;
1312
use crate::wrappers::xkbcommon::XkbcommonState;
13+
use crate::{warn, DamageArea};
1414
use crate::{Event, MouseButton, MouseEvent, ScrollDelta, WindowEvent, WindowHandler, WindowSize};
1515
use calloop::generic::Generic;
1616
use calloop::timer::{TimeoutAction, Timer};
1717
use calloop::{Interest, LoopHandle, LoopSignal, Mode, PostAction};
18+
use dpi::PhysicalInsets;
1819
use std::rc::Rc;
1920
use std::sync::mpsc;
2021
use std::sync::mpsc::Receiver;
@@ -482,7 +483,17 @@ impl EventLoop {
482483
}
483484

484485
XEvent::Expose(e) if e.window == self.window.raw_id() => {
485-
self.window.present_notify_requested.set(true)
486+
if e.count == 0 {
487+
self.window.present_notify_requested.set(true);
488+
}
489+
490+
let current_window_size = self.new_size.unwrap_or_else(|| self.window.get_size());
491+
492+
self.handler.damage(DamageArea::from_rect_and_window_size(
493+
PhysicalPosition::new(e.x, e.y).cast(),
494+
PhysicalSize::new(e.width, e.height).cast(),
495+
current_window_size.cast(),
496+
));
486497
}
487498

488499
////

‎tests/partial-rendering/Cargo.toml‎

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
[package]
2+
name = "partial-rendering"
3+
version = "0.1.0"
4+
edition = "2021"
5+
publish = false
6+
7+
[dependencies]
8+
baseview = { path = "../..", features = ["opengl"] }
9+
femtovg = "0.27.0"
10+
rand = "0.10.3"
11+
color = "0.3.3"
Lines changed: 142 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,142 @@
1+
use baseview::dpi::{LogicalSize, PhysicalPosition, PhysicalSize};
2+
use baseview::gl::{GlConfig, GlContext};
3+
use baseview::{
4+
DamageArea, Event, EventStatus, HandlerError, Window, WindowContext, WindowHandler,
5+
WindowSettings, WindowSize,
6+
};
7+
use color::{Hsl, OpaqueColor};
8+
use femtovg::renderer::OpenGl;
9+
use femtovg::{Canvas, Color};
10+
use std::cell::{Cell, RefCell};
11+
12+
struct FemtovgExample {
13+
gl_context: GlContext,
14+
canvas: RefCell<Canvas<OpenGl>>,
15+
damage_handler: DamageHandler,
16+
}
17+
18+
impl FemtovgExample {
19+
fn new(window_context: WindowContext) -> Result<Self, HandlerError> {
20+
let Some(gl_context) = window_context.gl_context() else { unreachable!() };
21+
unsafe { gl_context.make_current()? };
22+
23+
let renderer =
24+
unsafe { OpenGl::new_from_function_cstr(|s| gl_context.get_proc_address(s)) }?;
25+
26+
let mut canvas = Canvas::new(renderer)?;
27+
let size = window_context.size();
28+
29+
canvas.set_size(size.physical.width, size.physical.height, size.scale_factor as f32);
30+
31+
unsafe { gl_context.make_not_current()? };
32+
Ok(Self { gl_context, canvas: canvas.into(), damage_handler: DamageHandler::new() })
33+
}
34+
}
35+
36+
impl WindowHandler for FemtovgExample {
37+
fn draw(&self) -> Result<(), HandlerError> {
38+
let context = &self.gl_context;
39+
unsafe { context.make_current()? };
40+
41+
let mut canvas = self.canvas.borrow_mut();
42+
43+
let screen_height = canvas.height();
44+
let screen_width = canvas.width();
45+
46+
let color_of_the_day = new_random_color();
47+
48+
if self.damage_handler.is_full_screen_clear() {
49+
canvas.clear_rect(0, 0, screen_width, screen_height, color_of_the_day);
50+
} else {
51+
while let Some((pos, size)) = self.damage_handler.next_damage() {
52+
dbg!((pos, size));
53+
canvas.clear_rect(pos.x, pos.y, size.width, size.height, color_of_the_day);
54+
}
55+
}
56+
57+
self.damage_handler.clear();
58+
59+
// Tell renderer to execute all drawing commands
60+
canvas.flush();
61+
context.swap_buffers()?;
62+
unsafe { context.make_not_current()? };
63+
64+
Ok(())
65+
}
66+
67+
fn damage(&self, area: DamageArea) {
68+
eprintln!("Damaged: {area:?}");
69+
match area {
70+
DamageArea::FullWindow => self.damage_handler.set_full_screen_clear(),
71+
DamageArea::Rect { position, size } => {
72+
self.damage_handler.add_damaged_rect(position, size)
73+
}
74+
_ => {}
75+
}
76+
}
77+
78+
fn resized(&self, new_size: WindowSize) -> Result<(), HandlerError> {
79+
let size = new_size.physical;
80+
self.canvas.borrow_mut().set_size(size.width, size.height, new_size.scale_factor as f32);
81+
82+
Ok(())
83+
}
84+
85+
fn on_event(&self, _event: Event) -> EventStatus {
86+
EventStatus::Ignored
87+
}
88+
}
89+
90+
fn main() -> Result<(), baseview::Error> {
91+
unsafe { baseview::assume_standalone_in_process() };
92+
93+
let window_open_options = WindowSettings::new()
94+
.with_title("Baseview Partial redraw example")
95+
.with_size(LogicalSize::new(512, 512))
96+
.with_gl_config(GlConfig { alpha_bits: 8, ..GlConfig::default() });
97+
98+
let window = Window::create(window_open_options, |ctx| FemtovgExample::new(ctx))?;
99+
100+
window.run_until_closed()?;
101+
Ok(())
102+
}
103+
104+
fn new_random_color() -> Color {
105+
let hue = rand::random_range(0.0..360.0);
106+
let hsv_color = OpaqueColor::<Hsl>::new([hue, 100.0, 15.0]);
107+
let color = hsv_color.to_rgba8();
108+
109+
Color::rgb(color.r, color.g, color.b)
110+
}
111+
112+
struct DamageHandler {
113+
full_screen: Cell<bool>,
114+
damaged_rects: RefCell<Vec<(PhysicalPosition<u32>, PhysicalSize<u32>)>>,
115+
}
116+
117+
impl DamageHandler {
118+
fn new() -> Self {
119+
Self { full_screen: false.into(), damaged_rects: RefCell::new(Vec::with_capacity(8)) }
120+
}
121+
122+
fn is_full_screen_clear(&self) -> bool {
123+
self.full_screen.get()
124+
}
125+
126+
fn set_full_screen_clear(&self) {
127+
self.full_screen.set(true)
128+
}
129+
130+
fn clear(&self) {
131+
self.full_screen.set(false);
132+
self.damaged_rects.borrow_mut().clear();
133+
}
134+
135+
fn next_damage(&self) -> Option<(PhysicalPosition<u32>, PhysicalSize<u32>)> {
136+
self.damaged_rects.borrow_mut().pop()
137+
}
138+
139+
fn add_damaged_rect(&self, position: PhysicalPosition<u32>, size: PhysicalSize<u32>) {
140+
self.damaged_rects.borrow_mut().push((position, size));
141+
}
142+
}

0 commit comments

Comments
 (0)