Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 1 addition & 2 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -37,8 +37,7 @@ winio-ui-gtk = { path = "winio-ui-gtk", version = "0.5.0" }
winio-ui-qt = { path = "winio-ui-qt", version = "0.5.0" }
winio-ui-app-kit = { path = "winio-ui-app-kit", version = "0.5.0" }

compio = { version = "0.18.0", default-features = false }
compio-runtime = "0.11.0"
compio = { version = "0.19.0-rc.1", default-features = false }
compio-log = "0.1.0"

bitflags = "2"
Expand Down
8 changes: 4 additions & 4 deletions winio-layout/src/stack_panel.rs
Original file line number Diff line number Diff line change
Expand Up @@ -53,15 +53,15 @@ impl<'a, E> StackPanel<'a, E> {
style.size.width = match child.width {
Some(w) => length(w as f32),
None => match (self.orient, child.halign, child.grow) {
(Orient::Vertical, HAlign::Stretch, _) => percent(1.0),
(Orient::Vertical, HAlign::Stretch, _) => percent(1.0f32),
(Orient::Horizontal, _, true) => auto(),
_ => length(preferred_size.width as f32),
},
};
style.size.height = match child.height {
Some(h) => length(h as f32),
None => match (self.orient, child.valign, child.grow) {
(Orient::Horizontal, VAlign::Stretch, _) => percent(1.0),
(Orient::Horizontal, VAlign::Stretch, _) => percent(1.0f32),
(Orient::Vertical, _, true) => auto(),
_ => length(preferred_size.height as f32),
},
Expand Down Expand Up @@ -90,14 +90,14 @@ impl<'a, E> StackPanel<'a, E> {
}
}
if child.grow {
style.flex_grow = 1.0
style.flex_grow = 1.0f32
}
let node = tree.new_leaf(style)?;
nodes.push(node);
}
let root = tree.new_with_children(
Style {
size: taffy::Size::from_percent(1.0, 1.0),
size: taffy::Size::from_percent(1.0f32, 1.0f32),
flex_direction: match self.orient {
Orient::Horizontal => taffy::FlexDirection::Row,
Orient::Vertical => taffy::FlexDirection::Column,
Expand Down
5 changes: 4 additions & 1 deletion winio-pollable/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,10 @@ license = { workspace = true }
repository = { workspace = true }

[dependencies]
compio = { workspace = true, features = ["runtime"], public = true }
compio = { workspace = true, features = ["runtime"] }

futures-util = { workspace = true }
scoped-tls = { workspace = true }

[target.'cfg(target_os = "linux")'.dependencies]
rustix = { version = "1", features = ["event"] }
115 changes: 97 additions & 18 deletions winio-pollable/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,13 +8,21 @@
#[cfg(target_os = "linux")]
use std::os::fd::OwnedFd;
use std::{
cell::RefCell,
future::Future,
io,
ops::{Deref, DerefMut},
pin::Pin,
sync::Arc,
task::{Context, Poll, Waker},
time::Duration,
};

use compio::driver::{AsRawFd, RawFd};
use compio::{
driver::{AsRawFd, RawFd},
runtime::OptWaker,
};
use futures_util::FutureExt;

/// See [`Runtime`]
///
Expand Down Expand Up @@ -70,11 +78,22 @@ impl Runtime {
}

impl Runtime {
/// Run the scheduled tasks.
pub fn run(&self) -> bool {
let main_task_remaining = if MAIN_TASK.is_set() {
MAIN_TASK.with(|task| task.poll())
} else {
false
};

self.runtime.run() | main_task_remaining
}

/// Poll the runtime. Returns the next timeout.
pub fn poll_and_run(&self) -> Option<Duration> {
self.runtime.poll_with(Some(Duration::ZERO));

let remaining_tasks = self.runtime.run();
let remaining_tasks = self.run();

if remaining_tasks {
Some(Duration::ZERO)
Expand All @@ -83,25 +102,37 @@ impl Runtime {
}
}

/// Set the current main task and wait for its completion.
pub fn enter_block_on<F: Future<Output = ()>, T>(&self, future: F, f: impl FnOnce() -> T) -> T {
let opt_waker = self.runtime.opt_waker();
let task = unsafe { MainTask::new(future, opt_waker) };
MAIN_TASK.set(&task, f)
}

/// Block on the future till it completes. Users should enter the runtime
/// before calling this function, and poll the runtime themselves.
pub fn block_on<F: Future>(&self, future: F, poll: impl Fn(Option<Duration>)) -> F::Output {
let mut result = None;
unsafe {
self.runtime
.spawn_unchecked(async { result = Some(future.await) })
}
.detach();
loop {
let timeout = self.poll_and_run();
if let Some(result) = result.take() {
break result;
}

poll(timeout);

self.clear().ok();
}
let result = RefCell::new(None);

self.enter_block_on(
async {
let res = Some(future.await);
result.replace(res);
},
|| {
loop {
let timeout = self.poll_and_run();

if let Some(result) = result.take() {
break result;
}

poll(timeout);

self.clear().ok();
}
},
)
}
}

Expand Down Expand Up @@ -134,3 +165,51 @@ impl AsRawFd for Runtime {
}
}
}

struct MainTask {
future: RefCell<Pin<Box<dyn Future<Output = ()>>>>,
opt_waker: Arc<OptWaker>,
waker: Waker,
}

unsafe fn reduce_lifetime<'a>(
future: impl Future<Output = ()> + 'a,
) -> Pin<Box<dyn Future<Output = ()> + 'static>> {
let future = Box::pin(future) as Pin<Box<dyn Future<Output = ()> + 'a>>;
unsafe {
std::mem::transmute::<
Pin<Box<dyn Future<Output = ()> + 'a>>,
Pin<Box<dyn Future<Output = ()> + 'static>>,
>(future)
}
}
Comment thread
Berrysoft marked this conversation as resolved.

impl MainTask {
pub unsafe fn new(future: impl Future<Output = ()>, opt_waker: Arc<OptWaker>) -> Self {
let waker = Waker::from(opt_waker.clone());
Self {
// SAFETY: the future will only be polled within the scope of `enter_block_on`, which
// guarantees that the future will not outlive the main task.
future: RefCell::new(unsafe { reduce_lifetime(future.fuse()) }),
opt_waker,
waker,
}
}

pub fn poll(&self) -> bool {
let mut cx = Context::from_waker(&self.waker);
if let Ok(mut fut) = self.future.try_borrow_mut() {
if let Poll::Ready(()) = fut.as_mut().poll(&mut cx) {
// The future has completed, so we should not wait for the driver to wake us up
// anymore.
true
Comment thread
Berrysoft marked this conversation as resolved.
} else {
self.opt_waker.reset()
}
} else {
false
}
}
}

scoped_tls::scoped_thread_local!(static MAIN_TASK: MainTask);
58 changes: 28 additions & 30 deletions winio-ui-win32/src/runtime.rs
Original file line number Diff line number Diff line change
Expand Up @@ -141,36 +141,36 @@ impl Runtime {
}

pub fn block_on<F: Future>(&self, future: F) -> F::Output {
let result = RefCell::new(None);
let future = async {
let res = future.await;
unsafe { PostQuitMessage(0) };
result.replace(Some(res));
};
self.enter(|| {
let mut result = None;
unsafe {
self.runtime.spawn_unchecked(async {
result = Some(future.await);
PostQuitMessage(0);
})
}
.detach();

loop {
let mut msg = MaybeUninit::uninit();
let res = unsafe { self.runtime.get_message(msg.as_mut_ptr(), null_mut(), 0, 0) };
if res > 0 {
let msg = unsafe { msg.assume_init() };
unsafe {
let root = GetAncestor(msg.hwnd, GA_ROOT);
let handled = !root.is_null() && (IsDialogMessageW(root, &msg) != 0);
if !handled {
TranslateMessage(&msg);
DispatchMessageW(&msg);
self.runtime.enter_block_on(future, || {
loop {
let mut msg = MaybeUninit::uninit();
let res =
unsafe { self.runtime.get_message(msg.as_mut_ptr(), null_mut(), 0, 0) };
if res > 0 {
let msg = unsafe { msg.assume_init() };
unsafe {
let root = GetAncestor(msg.hwnd, GA_ROOT);
let handled = !root.is_null() && (IsDialogMessageW(root, &msg) != 0);
if !handled {
TranslateMessage(&msg);
DispatchMessageW(&msg);
}
}
} else if res == 0 {
debug!("Received WM_QUIT");
break result.take().expect("received WM_QUIT but no result");
} else {
panic!("MsgWaitForMultipleObjectsEx: {:?}", Error::from_thread());
}
} else if res == 0 {
debug!("Received WM_QUIT");
break result.take().expect("received WM_QUIT but no result");
} else {
panic!("MsgWaitForMultipleObjectsEx: {:?}", Error::from_thread());
}
}
})
})
}

Expand Down Expand Up @@ -291,10 +291,8 @@ pub(crate) unsafe extern "system" fn window_proc(
return control_color_static(hwnd, hdc);
}
},
WM_CTLCOLORBTN => {
if is_dark_mode_allowed_for_app() {
return unsafe { GetStockObject(BLACK_BRUSH) as _ };
}
WM_CTLCOLORBTN if is_dark_mode_allowed_for_app() => {
return unsafe { GetStockObject(BLACK_BRUSH) as _ };
}
WM_CTLCOLOREDIT | WM_CTLCOLORLISTBOX => {
if let Some(res) = unsafe { control_color_edit(handle, lparam as HWND, wparam as HDC) }
Expand Down
8 changes: 3 additions & 5 deletions winio-ui-win32/src/ui/edit.rs
Original file line number Diff line number Diff line change
Expand Up @@ -323,11 +323,9 @@ unsafe extern "system" fn multiline_edit_wnd_proc(
WM_GETDLGCODE => {
res &= !(DLGC_WANTALLKEYS as isize);
}
WM_KEYUP => {
if wparam == VK_RETURN as _ {
const RETURN_TEXT: *const u16 = w!("\r\n");
unsafe { DefSubclassProc(hwnd, EM_REPLACESEL, 1, RETURN_TEXT as _) };
}
WM_KEYUP if wparam == VK_RETURN as _ => {
const RETURN_TEXT: *const u16 = w!("\r\n");
unsafe { DefSubclassProc(hwnd, EM_REPLACESEL, 1, RETURN_TEXT as _) };
}
_ => {}
}
Expand Down
14 changes: 5 additions & 9 deletions winio-ui-windows-common/src/darkmode/hook.rs
Original file line number Diff line number Diff line change
Expand Up @@ -481,11 +481,9 @@ unsafe extern "system" fn dark_draw_theme_background_ex(
&& let Some((_, ty)) = HTHEME_MAP.lock().unwrap().get(&htheme)
{
match ty {
ThemeType::Progress => {
if ipartid == PP_TRANSPARENTBAR {
unsafe { FillRect(hdc, prect, DLG_GRAY_BACK.0) };
return S_OK;
}
ThemeType::Progress if ipartid == PP_TRANSPARENTBAR => {
unsafe { FillRect(hdc, prect, DLG_GRAY_BACK.0) };
return S_OK;
}
ThemeType::Tab => match ipartid {
TABP_TABITEM
Expand Down Expand Up @@ -729,10 +727,8 @@ unsafe extern "system" fn task_dialog_subclass(
error!("task_dialog_refresh: {_e:?}");
}
}
WM_CTLCOLORDLG => {
if is_dark_mode_allowed_for_app() {
return DLG_DARK_BACK.0 as _;
}
WM_CTLCOLORDLG if is_dark_mode_allowed_for_app() => {
return DLG_DARK_BACK.0 as _;
}
_ => {}
}
Expand Down
15 changes: 10 additions & 5 deletions winio-ui-windows-common/src/filebox.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
use std::{panic::resume_unwind, path::PathBuf};
use std::path::PathBuf;

use compio::runtime::ResumeUnwind;
use widestring::{U16CStr, U16CString};
use windows::{
Win32::{
Expand Down Expand Up @@ -65,7 +66,8 @@ impl FileBox {
.result()
})
.await
.unwrap_or_else(|e| resume_unwind(e))
.resume_unwind()
.expect("task cancelled")
}

pub async fn open_multiple(self, parent: Option<impl AsWindow>) -> Result<Vec<PathBuf>> {
Expand All @@ -86,7 +88,8 @@ impl FileBox {
.results()
})
.await
.unwrap_or_else(|e| resume_unwind(e))
.resume_unwind()
.expect("task cancelled")
}

pub async fn open_folder(self, parent: Option<impl AsWindow>) -> Result<Option<PathBuf>> {
Expand All @@ -107,7 +110,8 @@ impl FileBox {
.result()
})
.await
.unwrap_or_else(|e| resume_unwind(e))
.resume_unwind()
.expect("task cancelled")
}

pub async fn save(self, parent: Option<impl AsWindow>) -> Result<Option<PathBuf>> {
Expand All @@ -128,7 +132,8 @@ impl FileBox {
.result()
})
.await
.unwrap_or_else(|e| resume_unwind(e))
.resume_unwind()
.expect("task cancelled")
}
}

Expand Down
9 changes: 4 additions & 5 deletions winio-ui-windows-common/src/msgbox.rs
Original file line number Diff line number Diff line change
@@ -1,8 +1,6 @@
use std::{
panic::resume_unwind,
ptr::{null, null_mut},
};
use std::ptr::{null, null_mut};

use compio::runtime::ResumeUnwind;
use widestring::U16CString;
use windows::core::HRESULT;
use windows_sys::Win32::{
Expand Down Expand Up @@ -84,7 +82,8 @@ async fn msgbox(
(res, result)
})
.await
.unwrap_or_else(|e| resume_unwind(e));
.resume_unwind()
.expect("task cancelled");

if res >= 0 {
let res = match result {
Expand Down
Loading
Loading