2 unstable releases
| 0.2.0 | Aug 23, 2025 |
|---|---|
| 0.1.0 | Aug 9, 2025 |
#22 in #surface
96KB
1.5K
SLoC
winit_surface_window
A helper library for using existing Android Surfaces (like Presentations) as windows within the Rust ecosystem, compatible with raw-window-handle.
This library allows you to create a window from an existing Android Surface object, which is particularly useful when working with Android Presentation APIs or other scenarios where you need to render to a secondary display or a specific surface.
Features
- Create
SurfaceWindowfrom Android Surface objects - Compatible with
raw-window-handlefor integration with various graphics libraries - Deep integration with winit event loop
- Thread-safe implementation
- Support for Android Presentation API for multi-display management
Core Components
Window Management
SurfaceWindow- Core window abstraction, created from Android SurfacePresentationWindow- Android Presentation window management
Winit Integration
winit_ext- Winit event loop extensions (requireswinit-integrationfeature)
Usage
Add this to your Cargo.toml:
[dependencies]
winit_surface_window = { path = "path/to/winit_surface_window" }
# Enable feature support
[features]
winit-integration = ["winit_surface_window/winit-integration"] # Winit integration support
Complete Usage Example
Here's a complete example using winit event loop:
use android_activity::AndroidApp;
use winit::event_loop::{EventLoop, EventLoopBuilder};
use winit::platform::android::EventLoopBuilderExtAndroid;
use winit::window::WindowAttributes;
use winit_surface_window::{
ActiveEventLoopPresentationExt, EventLoopInitExt, PresentationWindow
};
#[no_mangle]
fn android_main(app: AndroidApp) {
android_logger::init_once(
android_logger::Config::default().with_max_level(log::LevelFilter::Debug),
);
let event_loop: EventLoop<()> = EventLoopBuilder::new()
.with_android_app(app.clone())
.build()
.unwrap();
let mut window = None;
let mut presentation_window: Option<PresentationWindow> = None;
let mut presentation_initialized = false;
event_loop.run(move |event, event_loop| match event {
winit::event::Event::WindowEvent { event, .. } => match event {
winit::event::WindowEvent::CloseRequested => {
// Clean up Presentation resources
if let Some(mut presentation) = presentation_window.take() {
let _ = presentation.dismiss();
}
presentation_window = None;
presentation_initialized = false;
event_loop.exit();
}
winit::event::WindowEvent::RedrawRequested => {
// Perform rendering operations
if let Some(presentation) = &presentation_window {
if let Some(surface_window) = presentation.surface_window() {
// Add your rendering code here
println!("Rendering to surface: {}x{}",
surface_window.width(), surface_window.height());
}
}
}
_ => (),
},
winit::event::Event::Resumed => {
// Create main window
let win = event_loop
.create_window(WindowAttributes::default())
.unwrap();
window = Some(win);
// Initialize Presentation in Resumed event
if !presentation_initialized {
// Add delay to ensure Activity is fully ready
std::thread::sleep(std::time::Duration::from_millis(500));
// Initialize Presentation system
match event_loop.init_presentation_android_app(&app) {
Ok(_) => {
println!("Presentation system initialized successfully");
// List available displays
if let Ok(displays) = event_loop.get_available_displays() {
println!("Available displays: {:?}", displays);
}
// Create Presentation
match event_loop.create_presentation_on_secondary_display(10000) {
Ok(presentation) => {
println!("Presentation created successfully!");
// Get SurfaceWindow for rendering
if let Some(surface_window) = presentation.surface_window() {
println!("SurfaceWindow available: {}x{}",
surface_window.width(), surface_window.height());
}
presentation_window = Some(presentation);
}
Err(err) => {
println!("Failed to create presentation: {}", err);
}
}
presentation_initialized = true;
}
Err(err) => {
println!("Failed to initialize presentation system: {}", err);
}
}
}
}
winit::event::Event::AboutToWait => {
std::thread::sleep(std::time::Duration::from_millis(16));
if let Some(window) = &window {
window.request_redraw();
}
}
_ => (),
}).unwrap();
}
API Reference
Core Types
SurfaceWindow
The main struct representing an Android Surface as a window. Implements HasRawWindowHandle and HasRawDisplayHandle for compatibility with various graphics libraries.
// Create window from Android Surface
let surface_window = unsafe { SurfaceWindow::from_surface(&mut env, surface)? };
// Get window dimensions
let width = surface_window.width();
let height = surface_window.height();
PresentationWindow
Android Presentation window manager for creating windows on secondary displays or specific displays.
// Create Presentation on secondary display
let presentation = PresentationWindow::new_on_secondary_display(5000)?;
// Create Presentation on specific display
let presentation = PresentationWindow::new_on_display(1, 5000)?;
// Get available display list
let displays = PresentationWindow::get_available_displays()?;
// Get underlying SurfaceWindow
if let Some(surface_window) = presentation.surface_window() {
// Perform rendering operations
}
Winit Integration (requires winit-integration feature)
EventLoopInitExt
EventLoop extension for initializing the Presentation system.
// Initialize using AndroidApp
event_loop.init_presentation_android_app(&app)?;
// Initialize using NativeActivity
event_loop.init_presentation_system_ndk(&activity)?;
ActiveEventLoopPresentationExt
Extension for creating Presentations within event handlers.
// Create Presentation on secondary display
let presentation = event_loop.create_presentation_on_secondary_display(5000)?;
// Create Presentation on specific display
let presentation = event_loop.create_presentation_on_display(1, 5000)?;
// Get available displays
let displays = event_loop.get_available_displays()?;
Build Configuration
Android Target
# Basic build
cargo build --target aarch64-linux-android
# Enable Winit integration
cargo build --target aarch64-linux-android --features winit-integration
Important Notes
- Thread Safety: All Presentation-related operations must be executed on the main UI thread.
- Initialization Timing: Ensure Presentation initialization in
Event::Resumedevent, not inRedrawRequested. - Resource Cleanup: Always call
presentation.dismiss()when the application closes to clean up resources. - Android Version: Requires Android API level 23+ support.
- Permission Requirements: May require
SYSTEM_ALERT_WINDOWpermission for secondary display.
License
This project is licensed under either of
- Apache License, Version 2.0 (LICENSE-APACHE or http://www.apache.org/licenses/LICENSE-2.0)
- MIT license (LICENSE-MIT or http://opensource.org/licenses/MIT)
at your option.
Dependencies
~0–21MB
~270K SLoC