winit_surface_window 0.2.0

A helper library to use existing Android Surfaces (like Presentations) as windows within the Rust ecosystem, compatible with raw-window-handle.
Documentation
# winit_surface_window


一个用于在 Rust 生态系统中使用现有 Android Surface(如 Presentation)作为窗口的辅助库,兼容 raw-window-handle 标准。

该库允许您从现有的 Android Surface 对象创建窗口,这在使用 Android Presentation API 或需要在副屏或特定 Surface 上进行渲染的场景中特别有用。

## 功能特性


- 从 Android Surface 对象创建 [`SurfaceWindow`]src/window.rs
- 兼容 [`raw-window-handle`]src/window.rs 标准,便于与各种图形库集成
- 与 winit 事件循环的深度集成
- 线程安全的实现
- 支持 Android Presentation API 用于多显示器管理

## 核心组件


### 窗口管理

- [`SurfaceWindow`]src/window.rs - 核心窗口抽象,从 Android Surface 创建
- [`PresentationWindow`]src/presentation.rs - Android Presentation 窗口管理

### Winit 集成

- [`winit_ext`]src/winit_ext.rs - Winit 事件循环扩展(需要 `winit-integration` 特性)

## 使用方法


在 `Cargo.toml` 中添加依赖:

```toml
[dependencies]
winit_surface_window = { path = "path/to/winit_surface_window" }

# 启用特性支持

[features]
winit-integration = ["winit_surface_window/winit-integration"] # Winit 集成支持
```

## 完整使用示例


以下是一个使用 winit 事件循环的完整示例:

```rust
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 => {
                // 清理 Presentation 资源
                if let Some(mut presentation) = presentation_window.take() {
                    let _ = presentation.dismiss();
                }
                presentation_window = None;
                presentation_initialized = false;
                event_loop.exit();
            }
            winit::event::WindowEvent::RedrawRequested => {
                // 执行渲染操作
                if let Some(presentation) = &presentation_window {
                    if let Some(surface_window) = presentation.surface_window() {
                        // 在这里添加您的渲染代码
                        println!("Rendering to surface: {}x{}", 
                                 surface_window.width(), surface_window.height());
                    }
                }
            }
            _ => (),
        },
        winit::event::Event::Resumed => {
            // 创建主窗口
            let win = event_loop
                .create_window(WindowAttributes::default())
                .unwrap();
            window = Some(win);

            // 在 Resumed 事件中初始化 Presentation
            if !presentation_initialized {
                // 添加延迟确保 Activity 完全准备好
                std::thread::sleep(std::time::Duration::from_millis(500));

                // 初始化 Presentation 系统
                match event_loop.init_presentation_android_app(&app) {
                    Ok(_) => {
                        println!("Presentation system initialized successfully");

                        // 列出可用显示器
                        if let Ok(displays) = event_loop.get_available_displays() {
                            println!("Available displays: {:?}", displays);
                        }

                        // 创建 Presentation
                        match event_loop.create_presentation_on_secondary_display(10000) {
                            Ok(presentation) => {
                                println!("Presentation created successfully!");

                                // 获取 SurfaceWindow 进行渲染
                                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 参考


### 核心类型


#### `SurfaceWindow`

主要结构体,表示 Android Surface 窗口。实现了 `HasRawWindowHandle` 和 `HasRawDisplayHandle` 接口,可与各种图形库兼容。

```rust
// 从 Android Surface 创建窗口
let surface_window = unsafe { SurfaceWindow::from_surface(&mut env, surface)? };

// 获取窗口尺寸
let width = surface_window.width();
let height = surface_window.height();
```

#### `PresentationWindow`

Android Presentation 窗口管理器,用于在副屏或指定显示器上创建窗口。

```rust
// 在副屏创建 Presentation
let presentation = PresentationWindow::new_on_secondary_display(5000)?;

// 在指定显示器创建 Presentation
let presentation = PresentationWindow::new_on_display(1, 5000)?;

// 获取可用显示器列表
let displays = PresentationWindow::get_available_displays()?;

// 获取底层 SurfaceWindow
if let Some(surface_window) = presentation.surface_window() {
    // 进行渲染操作
}
```

### Winit 集成 (需要 `winit-integration` 特性)


#### `EventLoopInitExt`

用于初始化 Presentation 系统的 EventLoop 扩展。

```rust
// 使用 AndroidApp 初始化
event_loop.init_presentation_android_app(&app)?;

// 使用 NativeActivity 初始化  
event_loop.init_presentation_system_ndk(&activity)?;
```

#### `ActiveEventLoopPresentationExt`

在事件处理器中创建 Presentation 的扩展。

```rust
// 在副屏创建 Presentation
let presentation = event_loop.create_presentation_on_secondary_display(5000)?;

// 在指定显示器创建 Presentation
let presentation = event_loop.create_presentation_on_display(1, 5000)?;

// 获取可用显示器
let displays = event_loop.get_available_displays()?;
```

## 构建配置


### Android 目标

```bash
# 基础构建

cargo build --target aarch64-linux-android

# 启用 Winit 集成

cargo build --target aarch64-linux-android --features winit-integration
```

## 注意事项


1. **线程安全**:所有 Presentation 相关操作必须在主 UI 线程中执行。
2. **初始化时机**:确保在 `Event::Resumed` 事件中初始化 Presentation,而不是在 `RedrawRequested` 中。
3. **资源清理**:在应用关闭时务必调用 `presentation.dismiss()` 清理资源。
4. **Android 版本**:需要 Android API level 23+ 支持。
5. **权限要求**:可能需要 `SYSTEM_ALERT_WINDOW` 权限用于副屏显示。

## 许可证


本项目使用以下许可证之一:

* Apache License, Version 2.0 ([LICENSE-APACHE]LICENSE-APACHEhttp://www.apache.org/licenses/LICENSE-2.0)
* MIT license ([LICENSE-MIT]LICENSE-MIThttp://opensource.org/licenses/MIT)

您可以选择其中任何一种许可证。