Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
4ca21483e5 | ||
|
|
c95cde8ec8 | ||
|
|
6b80cd672a | ||
|
|
7faf78ddeb |
No files matched your search
Generated
+1
-1
@@ -1540,7 +1540,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "ink-notes"
|
||||
version = "0.39.2"
|
||||
version = "0.39.3"
|
||||
dependencies = [
|
||||
"ab_glyph",
|
||||
"android_logger",
|
||||
|
||||
+2
-2
@@ -1,6 +1,6 @@
|
||||
[package]
|
||||
name = "ink-notes"
|
||||
version = "0.39.2"
|
||||
version = "0.39.3"
|
||||
edition = "2021"
|
||||
description = "Notizbuch-App für Stift, Touch und Maus unter Linux"
|
||||
repository = "https://gitea.pansi.eu/harald/ink-notes"
|
||||
@@ -69,7 +69,7 @@ wayland-backend = { version = "0.3", features = ["client_system"] }
|
||||
wayland-protocols = { version = "0.31", features = ["client", "unstable"] }
|
||||
|
||||
# Android (Issue #42): winit bound to the native activity. The library is built as
|
||||
# cdylib with `cargo rustc --lib --crate-type cdylib --target aarch64-linux-android`
|
||||
# cdylib and packed into an APK by scripts/package-android.sh
|
||||
[target.'cfg(target_os = "android")'.dependencies]
|
||||
winit = { version = "0.29", features = ["rwh_06", "android-native-activity"] }
|
||||
android_logger = { version = "0.13", default-features = false }
|
||||
|
||||
+1
-1
@@ -156,7 +156,7 @@ Die CI prüft zusätzlich `cargo fmt --check` und `cargo clippy --all-targets --
|
||||
|
||||
Andere Systeme:
|
||||
- **Windows** wird unter Linux übersetzt: `scripts/package-windows.sh` (braucht `gcc-mingw-w64-x86-64`); die Tests laufen mit `wine` als Runner (`CARGO_TARGET_X86_64_PC_WINDOWS_GNU_RUNNER=wine cargo test --target x86_64-pc-windows-gnu`).
|
||||
- **Android** (in Arbeit, Issue #42): `cargo check --target aarch64-linux-android` und `cargo rustc --lib --crate-type cdylib --target aarch64-linux-android` mit dem NDK-Compiler in `CC_aarch64_linux_android`. Dort startet die App noch nicht: Die Fensterfläche muss erst dem Lebenszyklus der Activity folgen.
|
||||
- **Android** (experimentell, Issue #42): `scripts/package-android.sh` baut `target/ink-notes_<version>_arm64.apk` ohne Gradle. Nötig sind das Android-SDK (build-tools, Plattform 34; `ANDROID_HOME`, Standard `~/android-sdk`) und das NDK; der Signierschlüssel kommt aus `ANDROID_KEYSTORE`, `ANDROID_KEYSTORE_PASS` und `ANDROID_KEY_ALIAS`, sonst wird der Debug-Schlüssel verwendet. Installieren mit `adb install -r target/ink-notes_<version>_arm64.apk`, Log-Ausgaben mit `adb logcat -s ink-notes`. Notizbücher bleiben vorerst in der App; Stifterkennung, Bildschirmtastatur und Dateidialoge fehlen noch.
|
||||
|
||||
### Projektstruktur
|
||||
|
||||
|
||||
@@ -156,7 +156,7 @@ CI additionally checks `cargo fmt --check` and `cargo clippy --all-targets -- -D
|
||||
|
||||
Other systems:
|
||||
- **Windows** is cross-compiled on Linux: `scripts/package-windows.sh` (needs `gcc-mingw-w64-x86-64`); the tests run with `wine` as runner (`CARGO_TARGET_X86_64_PC_WINDOWS_GNU_RUNNER=wine cargo test --target x86_64-pc-windows-gnu`).
|
||||
- **Android** (in progress, Issue #42): `cargo check --target aarch64-linux-android` and `cargo rustc --lib --crate-type cdylib --target aarch64-linux-android` with the NDK compiler in `CC_aarch64_linux_android`. The app does not start there yet: the window surface still has to follow the activity lifecycle.
|
||||
- **Android** (experimental, Issue #42): `scripts/package-android.sh` builds `target/ink-notes_<version>_arm64.apk` without Gradle. It needs the Android SDK (build-tools, platform 34; `ANDROID_HOME`, default `~/android-sdk`) and the NDK; the signing key comes from `ANDROID_KEYSTORE`, `ANDROID_KEYSTORE_PASS` and `ANDROID_KEY_ALIAS`, otherwise the debug key is used. Install with `adb install -r target/ink-notes_<version>_arm64.apk`, log output with `adb logcat -s ink-notes`. Notebooks stay inside the app for now; pen detection, on-screen keyboard and file dialogs are still missing.
|
||||
|
||||
New code comments and commit messages are written in English; older code and history still contain German.
|
||||
|
||||
|
||||
@@ -0,0 +1,31 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!-- Manifest of the Android app (Issue #42). scripts/package-android.sh fills in the version.
|
||||
NativeActivity loads libink_notes.so, whose android_main runs the app. -->
|
||||
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
package="eu.pansi.inknotes"
|
||||
android:versionCode="@VERSION_CODE@"
|
||||
android:versionName="@VERSION@">
|
||||
|
||||
<uses-feature android:name="android.hardware.touchscreen" android:required="false" />
|
||||
|
||||
<application
|
||||
android:label="ink-notes"
|
||||
android:icon="@mipmap/ic_launcher"
|
||||
android:hasCode="false"
|
||||
android:extractNativeLibs="true"
|
||||
android:theme="@android:style/Theme.Material.Light.NoActionBar">
|
||||
<!-- configChanges: rotating the tablet or attaching a keyboard must not restart the
|
||||
activity; the app adapts to the new window size itself -->
|
||||
<activity
|
||||
android:name="android.app.NativeActivity"
|
||||
android:exported="true"
|
||||
android:launchMode="singleTask"
|
||||
android:configChanges="orientation|screenSize|smallestScreenSize|screenLayout|keyboard|keyboardHidden|navigation|density|uiMode|fontScale|locale|layoutDirection">
|
||||
<meta-data android:name="android.app.lib_name" android:value="ink_notes" />
|
||||
<intent-filter>
|
||||
<action android:name="android.intent.action.MAIN" />
|
||||
<category android:name="android.intent.category.LAUNCHER" />
|
||||
</intent-filter>
|
||||
</activity>
|
||||
</application>
|
||||
</manifest>
|
||||
@@ -84,6 +84,11 @@
|
||||
</branding>
|
||||
<content_rating type="oars-1.1" />
|
||||
<releases>
|
||||
<release version="0.39.3" date="2026-10-27">
|
||||
<description>
|
||||
<p>Much lower battery use: the app no longer redraws the window continuously while nothing happens.</p>
|
||||
</description>
|
||||
</release>
|
||||
<release version="0.39.2" date="2026-10-27">
|
||||
<description>
|
||||
<p>PDF export now uses its own small PDF writer on lopdf 0.46 instead of printpdf; the exported files look the same.</p>
|
||||
|
||||
@@ -84,6 +84,11 @@
|
||||
</branding>
|
||||
<content_rating type="oars-1.1" />
|
||||
<releases>
|
||||
<release version="0.39.3" date="2026-10-27">
|
||||
<description>
|
||||
<p>Much lower battery use: the app no longer redraws the window continuously while nothing happens.</p>
|
||||
</description>
|
||||
</release>
|
||||
<release version="0.39.2" date="2026-10-27">
|
||||
<description>
|
||||
<p>PDF export now uses its own small PDF writer on lopdf 0.46 instead of printpdf; the exported files look the same.</p>
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
Notebook app for pen, touch and mouse on Linux (tested on Zorin OS 18 / Ubuntu 24.04).
|
||||
|
||||
### Highlights:
|
||||
- **Battery drain fixed**: ink-notes redrew its window at full frame rate even when nothing happened, which kept the app and the desktop (e.g. gnome-shell) busy and drained the battery. It now only draws when something changes; idle CPU load drops to practically zero. Also applies to Windows. Internally, the Android version now follows the app lifecycle and can be packed into an APK (not part of the release yet)
|
||||
- **PDF export on current lopdf**: The PDF export uses its own small PDF writer on top of lopdf 0.46 instead of the outdated printpdf 0.7 (which pinned lopdf 0.31). Exported PDFs look the same – layers, searchable text, images, highlighters and bookmarks stay as before
|
||||
- **Windows mouse fix**: The mouse works normally again in the Windows version – Windows Ink reported it as a pen, so clicks and moves went the wrong way. Nothing changes on Linux
|
||||
- **Windows (experimental)**: `ink-notes_<version>_x86_64.exe` is a portable program for Windows 10/11 – just start it, no installation. Notebooks and settings are stored in `%APPDATA%\ink-notes`, pen input uses Windows Ink, updates replace the `.exe` and take effect at the next start. Not yet tested on real tablet hardware – feedback welcome. Nothing changes on Linux; internally the groundwork for an Android version was laid
|
||||
|
||||
Executable
+94
@@ -0,0 +1,94 @@
|
||||
#!/usr/bin/env bash
|
||||
# ==============================================================================
|
||||
# Builds the Android app target/ink-notes_<version>_arm64.apk (Issues #42, #45)
|
||||
# without Gradle: the Rust library is built as cdylib with the NDK, aapt2 links the
|
||||
# manifest and the icon, zipalign and apksigner finish the APK.
|
||||
#
|
||||
# Needs the Android SDK (build-tools, platform android-34) and the NDK:
|
||||
# ANDROID_HOME SDK folder (default: ~/android-sdk)
|
||||
# ANDROID_NDK_HOME NDK folder (default: newest in $ANDROID_HOME/ndk)
|
||||
#
|
||||
# Signing key (all three, otherwise the debug key ~/.android/debug.keystore is used and
|
||||
# created if missing; such an APK is only meant for testing):
|
||||
# ANDROID_KEYSTORE, ANDROID_KEYSTORE_PASS, ANDROID_KEY_ALIAS
|
||||
# ==============================================================================
|
||||
set -euo pipefail
|
||||
|
||||
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
||||
ROOT_DIR="$(cd "${SCRIPT_DIR}/.." && pwd)"
|
||||
cd "${ROOT_DIR}"
|
||||
|
||||
TARGET="aarch64-linux-android"
|
||||
ABI="arm64-v8a"
|
||||
MIN_SDK=26
|
||||
TARGET_SDK=34
|
||||
VERSION=$(grep -m1 '^version = ' Cargo.toml | cut -d '"' -f2)
|
||||
IFS=. read -r MAJOR MINOR PATCH <<<"${VERSION%%-*}"
|
||||
VERSION_CODE=$((MAJOR * 10000 + MINOR * 100 + PATCH))
|
||||
APK_NAME="ink-notes_${VERSION}_arm64.apk"
|
||||
|
||||
ANDROID_HOME="${ANDROID_HOME:-${HOME}/android-sdk}"
|
||||
if [ -z "${ANDROID_NDK_HOME:-}" ]; then
|
||||
ANDROID_NDK_HOME=$(ls -d "${ANDROID_HOME}"/ndk/*/ 2>/dev/null | sort -V | tail -n1)
|
||||
fi
|
||||
BUILD_TOOLS=$(ls -d "${ANDROID_HOME}"/build-tools/*/ 2>/dev/null | sort -V | tail -n1)
|
||||
ANDROID_JAR="${ANDROID_HOME}/platforms/android-${TARGET_SDK}/android.jar"
|
||||
NDK_BIN="${ANDROID_NDK_HOME%/}/toolchains/llvm/prebuilt/linux-x86_64/bin"
|
||||
|
||||
for needed in "${NDK_BIN}/${TARGET}${MIN_SDK}-clang" "${BUILD_TOOLS}aapt2" "${ANDROID_JAR}"; do
|
||||
if [ ! -e "${needed}" ]; then
|
||||
echo "FEHLER: ${needed} nicht gefunden (Android-SDK/NDK, siehe Kopf des Skripts)."
|
||||
exit 1
|
||||
fi
|
||||
done
|
||||
if command -v rustup >/dev/null 2>&1; then
|
||||
rustup target add "${TARGET}"
|
||||
fi
|
||||
|
||||
echo "=== [1/4] Baue libink_notes.so (${TARGET}) ==="
|
||||
export CC_aarch64_linux_android="${NDK_BIN}/${TARGET}${MIN_SDK}-clang"
|
||||
export AR_aarch64_linux_android="${NDK_BIN}/llvm-ar"
|
||||
export CARGO_TARGET_AARCH64_LINUX_ANDROID_LINKER="${NDK_BIN}/${TARGET}${MIN_SDK}-clang"
|
||||
cargo rustc --release --lib --crate-type cdylib --target "${TARGET}"
|
||||
LIB="${CARGO_TARGET_DIR:-target}/${TARGET}/release/libink_notes.so"
|
||||
|
||||
echo "=== [2/4] Ressourcen und Manifest ==="
|
||||
WORK="target/android-apk"
|
||||
rm -rf "${WORK}"
|
||||
mkdir -p "${WORK}/res/mipmap-xxxhdpi" "${WORK}/compiled" "${WORK}/apk/lib/${ABI}"
|
||||
cp assets/ink-notes.png "${WORK}/res/mipmap-xxxhdpi/ic_launcher.png"
|
||||
sed -e "s/@VERSION_CODE@/${VERSION_CODE}/" -e "s/@VERSION@/${VERSION}/" \
|
||||
packaging/android/AndroidManifest.xml >"${WORK}/AndroidManifest.xml"
|
||||
"${BUILD_TOOLS}aapt2" compile --dir "${WORK}/res" -o "${WORK}/compiled/res.zip"
|
||||
"${BUILD_TOOLS}aapt2" link -o "${WORK}/unaligned.apk" -I "${ANDROID_JAR}" \
|
||||
--manifest "${WORK}/AndroidManifest.xml" \
|
||||
--min-sdk-version "${MIN_SDK}" --target-sdk-version "${TARGET_SDK}" \
|
||||
"${WORK}/compiled/res.zip"
|
||||
|
||||
echo "=== [3/4] Native Bibliothek hinzufügen ==="
|
||||
cp "${LIB}" "${WORK}/apk/lib/${ABI}/"
|
||||
(cd "${WORK}/apk" && zip -q -r ../unaligned.apk lib)
|
||||
"${BUILD_TOOLS}zipalign" -f -p 4 "${WORK}/unaligned.apk" "${WORK}/aligned.apk"
|
||||
|
||||
echo "=== [4/4] Signieren ==="
|
||||
if [ -n "${ANDROID_KEYSTORE:-}" ] && [ -n "${ANDROID_KEYSTORE_PASS:-}" ] && [ -n "${ANDROID_KEY_ALIAS:-}" ]; then
|
||||
KEYSTORE="${ANDROID_KEYSTORE}"
|
||||
KEY_ALIAS="${ANDROID_KEY_ALIAS}"
|
||||
export KS_PASS="${ANDROID_KEYSTORE_PASS}"
|
||||
else
|
||||
KEYSTORE="${HOME}/.android/debug.keystore"
|
||||
KEY_ALIAS="androiddebugkey"
|
||||
export KS_PASS="android"
|
||||
if [ ! -f "${KEYSTORE}" ]; then
|
||||
mkdir -p "$(dirname "${KEYSTORE}")"
|
||||
keytool -genkeypair -keystore "${KEYSTORE}" -storepass android -keypass android \
|
||||
-alias androiddebugkey -keyalg RSA -keysize 2048 -validity 10000 \
|
||||
-dname "CN=Android Debug,O=Android,C=US"
|
||||
fi
|
||||
echo "Hinweis: Signiert mit dem Debug-Schlüssel ${KEYSTORE} (nur zum Testen)."
|
||||
fi
|
||||
"${BUILD_TOOLS}apksigner" sign --ks "${KEYSTORE}" --ks-key-alias "${KEY_ALIAS}" \
|
||||
--ks-pass env:KS_PASS --key-pass env:KS_PASS \
|
||||
--out "target/${APK_NAME}" "${WORK}/aligned.apk"
|
||||
"${BUILD_TOOLS}apksigner" verify "target/${APK_NAME}"
|
||||
ls -lh "target/${APK_NAME}"
|
||||
+1464
-346
File diff suppressed because it is too large.
Load diff
+43
-5
@@ -165,7 +165,10 @@ struct NeighborPage {
|
||||
}
|
||||
|
||||
pub struct CanvasState {
|
||||
pub surface: wgpu::Surface<'static>,
|
||||
/// Drawing surface of the window; `None` while the app is in the background on Android
|
||||
/// (the native window only exists between `Resumed` and `Suspended`)
|
||||
surface: Option<wgpu::Surface<'static>>,
|
||||
instance: wgpu::Instance,
|
||||
/// Verwendeter Grafikadapter (für erneute Abfrage der Surface-Fähigkeiten bei Größenänderung)
|
||||
adapter: wgpu::Adapter,
|
||||
/// Multisampling der Zeichenfläche (1 = aus) und das zugehörige Zwischenbild
|
||||
@@ -591,7 +594,8 @@ impl CanvasState {
|
||||
let egui_renderer = egui_wgpu::Renderer::new(&device, render_format(&config), None, 1);
|
||||
|
||||
Ok(Self {
|
||||
surface,
|
||||
surface: Some(surface),
|
||||
instance,
|
||||
adapter,
|
||||
msaa_samples,
|
||||
msaa_view,
|
||||
@@ -727,14 +731,42 @@ impl CanvasState {
|
||||
self.update_uniforms();
|
||||
}
|
||||
|
||||
/// Releases the drawing surface: on Android the native window goes away when the app
|
||||
/// is sent to the background (`Event::Suspended`). Drawing is skipped until [`Self::resume`].
|
||||
pub fn suspend(&mut self) {
|
||||
self.surface = None;
|
||||
}
|
||||
|
||||
/// Creates the drawing surface again for the window (`Event::Resumed` on Android).
|
||||
pub fn resume(&mut self, window: Arc<Window>) -> Result<(), Box<dyn std::error::Error>> {
|
||||
if self.surface.is_some() {
|
||||
return Ok(());
|
||||
}
|
||||
let surface = self.instance.create_surface(window.clone())?;
|
||||
if !surface
|
||||
.get_capabilities(&self.adapter)
|
||||
.formats
|
||||
.contains(&self.config.format)
|
||||
{
|
||||
return Err("surface format changed".into());
|
||||
}
|
||||
self.surface = Some(surface);
|
||||
// Configures the new surface (the window may have changed size meanwhile)
|
||||
self.resize(window.inner_size());
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Passt die Surface und Projektionsmatrizen an eine neue Fenstergröße an.
|
||||
pub fn resize(&mut self, new_size: PhysicalSize<u32>) {
|
||||
if new_size.width > 0 && new_size.height > 0 {
|
||||
self.size = new_size;
|
||||
self.config.width = new_size.width;
|
||||
self.config.height = new_size.height;
|
||||
let Some(surface) = &self.surface else {
|
||||
return;
|
||||
};
|
||||
// Fähigkeiten neu abfragen: Ein nicht (mehr) angebotener Modus führt in wgpu zum Absturz
|
||||
let caps = self.surface.get_capabilities(&self.adapter);
|
||||
let caps = surface.get_capabilities(&self.adapter);
|
||||
if !caps.present_modes.contains(&self.config.present_mode) {
|
||||
match choose_present_mode(&caps.present_modes) {
|
||||
Some(mode) => self.config.present_mode = mode,
|
||||
@@ -750,7 +782,7 @@ impl CanvasState {
|
||||
}
|
||||
}
|
||||
}
|
||||
self.surface.configure(&self.device, &self.config);
|
||||
surface.configure(&self.device, &self.config);
|
||||
self.msaa_view = create_msaa_view(&self.device, &self.config, self.msaa_samples);
|
||||
self.stencil_view = create_stencil_view(&self.device, &self.config, self.msaa_samples);
|
||||
self.recalculate_viewport();
|
||||
@@ -1386,7 +1418,13 @@ impl CanvasState {
|
||||
.update_texture(&self.device, &self.queue, *id, image_delta);
|
||||
}
|
||||
|
||||
let output = self.surface.get_current_texture()?;
|
||||
let Some(surface) = &self.surface else {
|
||||
for id in &textures_delta.free {
|
||||
self.egui_renderer.free_texture(id);
|
||||
}
|
||||
return Ok(());
|
||||
};
|
||||
let output = surface.get_current_texture()?;
|
||||
let view = output.texture.create_view(&wgpu::TextureViewDescriptor {
|
||||
format: Some(render_format(&self.config)),
|
||||
..Default::default()
|
||||
|
||||
+22
-3
@@ -19,7 +19,21 @@ use crate::storage::{self, NotebookManifest, OpenMarker, PageData};
|
||||
/// Time between two checks.
|
||||
pub const INTERVAL: Duration = Duration::from_secs(3);
|
||||
|
||||
type Fingerprint = (Option<SystemTime>, u64);
|
||||
/// Modification time, size and, for small files, a hash of the content.
|
||||
type Fingerprint = (Option<SystemTime>, u64, Option<u64>);
|
||||
|
||||
/// Files up to this size are also compared by content: file times are only as fine as the
|
||||
/// kernel clock tick, so a file rewritten right after a check with the same length (e.g. a
|
||||
/// manifest with one page replaced by another) would otherwise look unchanged.
|
||||
const HASHED_FILE_SIZE: u64 = 64 * 1024;
|
||||
|
||||
fn content_hash(path: &Path) -> Option<u64> {
|
||||
use std::hash::{Hash, Hasher};
|
||||
let bytes = fs::read(path).ok()?;
|
||||
let mut hasher = std::collections::hash_map::DefaultHasher::new();
|
||||
bytes.hash(&mut hasher);
|
||||
Some(hasher.finish())
|
||||
}
|
||||
|
||||
/// What a check found and took over.
|
||||
#[derive(Debug, Default, Clone, PartialEq)]
|
||||
@@ -61,8 +75,13 @@ fn scan(dir: &Path) -> HashMap<String, Fingerprint> {
|
||||
return None;
|
||||
}
|
||||
let meta = entry.metadata().ok()?;
|
||||
meta.is_file()
|
||||
.then(|| (name, (meta.modified().ok(), meta.len())))
|
||||
if !meta.is_file() {
|
||||
return None;
|
||||
}
|
||||
let hash = (meta.len() <= HASHED_FILE_SIZE)
|
||||
.then(|| content_hash(&entry.path()))
|
||||
.flatten();
|
||||
Some((name, (meta.modified().ok(), meta.len(), hash)))
|
||||
})
|
||||
.collect()
|
||||
}
|
||||
|
||||
+3
-3
@@ -38,9 +38,7 @@ pub mod xopp;
|
||||
|
||||
/// Entry point on Android (Issue #42), called by the native activity.
|
||||
///
|
||||
/// Builds with `cargo rustc --lib --crate-type cdylib --target aarch64-linux-android`. Not
|
||||
/// usable yet: the window surface still has to be created on `Resumed` and dropped on
|
||||
/// `Suspended`.
|
||||
/// `scripts/package-android.sh` builds the library and packs it into an APK.
|
||||
#[cfg(target_os = "android")]
|
||||
#[no_mangle]
|
||||
fn android_main(app: winit::platform::android::activity::AndroidApp) {
|
||||
@@ -51,6 +49,8 @@ fn android_main(app: winit::platform::android::activity::AndroidApp) {
|
||||
.with_max_level(log::LevelFilter::Info)
|
||||
.with_tag("ink-notes"),
|
||||
);
|
||||
// Panics would otherwise only go to stderr, which Android discards
|
||||
std::panic::set_hook(Box::new(|info| log::error!("{info}")));
|
||||
if let Some(dir) = app.internal_data_path() {
|
||||
paths::set_app_dir(dir);
|
||||
}
|
||||
|
||||
@@ -82,6 +82,51 @@ pub fn desktop_event_loop() -> Result<winit::event_loop::EventLoop<()>, winit::e
|
||||
builder.build()
|
||||
}
|
||||
|
||||
/// Waits until the window can be drawn to. On Android the native window only exists after
|
||||
/// `Event::Resumed` (Issue #42); on the desktop it is there right away.
|
||||
pub fn wait_until_resumed(
|
||||
#[allow(unused_variables)] event_loop: &mut winit::event_loop::EventLoop<()>,
|
||||
) {
|
||||
#[cfg(target_os = "android")]
|
||||
{
|
||||
use winit::event::Event;
|
||||
use winit::platform::pump_events::{EventLoopExtPumpEvents, PumpStatus};
|
||||
let mut resumed = false;
|
||||
while !resumed {
|
||||
let status = event_loop.pump_events(None, |event, _| {
|
||||
if matches!(event, Event::Resumed) {
|
||||
resumed = true;
|
||||
}
|
||||
});
|
||||
if let PumpStatus::Exit(_) = status {
|
||||
std::process::exit(0);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Runs the event loop until the app quits. On Android the loop was already started by
|
||||
/// [`wait_until_resumed`], so it is driven with `pump_events` (`run` would refuse to start).
|
||||
pub fn run_event_loop<F>(
|
||||
#[allow(unused_mut)] mut event_loop: winit::event_loop::EventLoop<()>,
|
||||
#[allow(unused_mut)] mut handler: F,
|
||||
) -> Result<(), winit::error::EventLoopError>
|
||||
where
|
||||
F: FnMut(winit::event::Event<()>, &winit::event_loop::EventLoopWindowTarget<()>),
|
||||
{
|
||||
#[cfg(target_os = "android")]
|
||||
{
|
||||
use winit::platform::pump_events::{EventLoopExtPumpEvents, PumpStatus};
|
||||
loop {
|
||||
if let PumpStatus::Exit(_) = event_loop.pump_events(None, &mut handler) {
|
||||
return Ok(());
|
||||
}
|
||||
}
|
||||
}
|
||||
#[cfg(not(target_os = "android"))]
|
||||
event_loop.run(handler)
|
||||
}
|
||||
|
||||
/// Gives the window the app id (Wayland: app_id, X11: WM_CLASS), so that dock and task bar
|
||||
/// show the app icon for it.
|
||||
pub fn with_app_id(
|
||||
|
||||
Reference in new issue
Block a user