Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Initializes WindowAdapter implementation #1178

Merged
merged 1 commit into from
Dec 12, 2024
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
11 changes: 1 addition & 10 deletions gui/main_window.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -25,8 +25,7 @@
#include <fcntl.h>
#endif

MainWindow::MainWindow() :
m_main(nullptr)
MainWindow::MainWindow()
{
// File menu.
auto fileMenu = menuBar()->addMenu("&File");
Expand All @@ -36,19 +35,11 @@ MainWindow::MainWindow() :

// Help menu.
auto helpMenu = menuBar()->addMenu("&Help");
auto aboutQt = new QAction("About &Qt", this);
auto about = new QAction("&About Obliteration", this);

connect(aboutQt, &QAction::triggered, &QApplication::aboutQt);
connect(about, &QAction::triggered, this, &MainWindow::aboutObliteration);

helpMenu->addAction(aboutQt);
helpMenu->addAction(about);

// Central widget.
m_main = new QStackedWidget();

setCentralWidget(m_main);
}

MainWindow::~MainWindow()
Expand Down
4 changes: 0 additions & 4 deletions gui/main_window.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -3,14 +3,10 @@
#include <QList>
#include <QMainWindow>

class QStackedWidget;

class MainWindow final : public QMainWindow {
public:
MainWindow();
~MainWindow() override;
private slots:
void aboutObliteration();
private:
QStackedWidget *m_main;
};
37 changes: 37 additions & 0 deletions gui/src/rt/context.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
use std::cell::Cell;
use std::mem::transmute;
use std::ptr::null;
use winit::event_loop::ActiveEventLoop;

/// Execution context of the runtime.
pub struct RuntimeContext<'a> {
el: &'a ActiveEventLoop,
}

impl<'a> RuntimeContext<'a> {
pub(super) fn new(el: &'a ActiveEventLoop) -> Self {
Self { el }
}

/// # Panics
/// If called from the other thread than main thread.
pub fn with<R>(f: impl FnOnce(&Self) -> R) -> R {
let cx = CONTEXT.get();
assert!(!cx.is_null());
unsafe { f(&*cx) }
}

pub fn event_loop(&self) -> &ActiveEventLoop {
self.el
}

pub(super) fn run(&self, f: impl FnOnce()) {
assert!(CONTEXT.replace(unsafe { transmute(self) }).is_null());
f();
CONTEXT.set(null());
}
}

thread_local! {
static CONTEXT: Cell<*const RuntimeContext<'static>> = Cell::new(null());
}
10 changes: 8 additions & 2 deletions gui/src/rt/mod.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
pub use self::context::*;

use futures::executor::LocalPool;
use futures::task::LocalSpawnExt;
use std::future::Future;
Expand All @@ -8,6 +10,8 @@ use winit::event::WindowEvent;
use winit::event_loop::{ActiveEventLoop, EventLoop};
use winit::window::WindowId;

mod context;

pub fn block_on(main: impl Future<Output = ()> + 'static) -> Result<(), RuntimeError> {
// Setup winit event loop.
let mut el = EventLoop::<Event>::with_user_event();
Expand All @@ -17,7 +21,7 @@ pub fn block_on(main: impl Future<Output = ()> + 'static) -> Result<(), RuntimeE
exe.spawner()
.spawn_local(async move {
main.await;
todo!()
RuntimeContext::with(|cx| cx.event_loop().exit());
})
.unwrap();

Expand All @@ -31,7 +35,9 @@ struct AsyncExecutor(LocalPool);

impl ApplicationHandler<Event> for AsyncExecutor {
fn resumed(&mut self, event_loop: &ActiveEventLoop) {
self.0.run_until_stalled();
let cx = RuntimeContext::new(event_loop);

cx.run(|| self.0.run_until_stalled());
}

fn window_event(
Expand Down
26 changes: 24 additions & 2 deletions gui/src/ui/backend/mod.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,12 @@
use self::window::Window;
use crate::rt::RuntimeContext;
use i_slint_renderer_skia::SkiaRenderer;
use slint::platform::WindowAdapter;
use slint::PlatformError;
use slint::{PhysicalSize, PlatformError};
use std::rc::Rc;

mod window;

/// Back-end for Slint to run on top of winit event loop.
///
/// This back-end does not supports [`slint::run_event_loop()`].
Expand All @@ -15,6 +20,23 @@ impl SlintBackend {

impl slint::platform::Platform for SlintBackend {
fn create_window_adapter(&self) -> Result<Rc<dyn WindowAdapter>, PlatformError> {
todo!()
// Create winit window.
let attrs = winit::window::Window::default_attributes();
let win = match RuntimeContext::with(move |cx| cx.event_loop().create_window(attrs)) {
Ok(v) => Rc::new(v),
Err(e) => return Err(PlatformError::OtherError(Box::new(e))),
};

// Create WindowAdapter.
let size = win.inner_size();
let renderer = SkiaRenderer::new(
win.clone(),
win.clone(),
PhysicalSize::new(size.width, size.height),
)?;

Ok(Rc::<Window>::new_cyclic(move |weak| {
Window::new(win, slint::Window::new(weak.clone()), renderer)
}))
}
}
41 changes: 41 additions & 0 deletions gui/src/ui/backend/window.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
use i_slint_renderer_skia::SkiaRenderer;
use slint::platform::{Renderer, WindowAdapter};
use slint::PhysicalSize;
use std::rc::Rc;

/// Implementation of [`WindowAdapter`].
pub struct Window {
winit: Rc<winit::window::Window>,
slint: slint::Window,
renderer: SkiaRenderer,
}

impl Window {
pub fn new(
winit: Rc<winit::window::Window>,
slint: slint::Window,
renderer: SkiaRenderer,
) -> Self {
Self {
winit,
slint,
renderer,
}
}
}

impl WindowAdapter for Window {
fn window(&self) -> &slint::Window {
&self.slint
}

fn size(&self) -> PhysicalSize {
let s = self.winit.inner_size();

PhysicalSize::new(s.width, s.height)
}

fn renderer(&self) -> &dyn Renderer {
&self.renderer
}
}