Skip to content
This repository has been archived by the owner on Jul 15, 2024. It is now read-only.

Fullscreen support #100

Draft
wants to merge 3 commits into
base: main
Choose a base branch
from
Draft
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
188 changes: 188 additions & 0 deletions examples/fullscreen.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,188 @@
use glazier::{Application, KeyEvent, Region, Scalable, WinHandler, WindowHandle};
use keyboard_types::Key;
use parley::{FontContext, Layout};
use std::any::Any;
use vello::util::{RenderContext, RenderSurface};
use vello::Renderer;
use vello::{
glyph::{
pinot::{types::Tag, FontRef},
GlyphContext,
},
kurbo::{Affine, Point, Rect},
peniko::{Brush, Color, Fill},
Scene, SceneBuilder,
};

fn main() {
let app = Application::new().unwrap();
let window = glazier::WindowBuilder::new(app.clone())
.size((640., 480.).into())
.handler(Box::new(WindowState::new()))
.build()
.unwrap();
window.show();
app.run(None);
}

struct WindowState {
handle: WindowHandle,
renderer: Option<Renderer>,
render: RenderContext,
surface: Option<RenderSurface>,
scene: Scene,
font_context: FontContext,
fullscreen: bool,
}

impl WindowState {
pub fn new() -> Self {
let render = RenderContext::new().unwrap();
Self {
handle: Default::default(),
surface: None,
renderer: None,
render,
scene: Default::default(),
font_context: FontContext::new(),
fullscreen: false,
}
}

fn schedule_render(&self) {
self.handle.invalidate();
}

fn surface_size(&self) -> (u32, u32) {
let handle = &self.handle;
let scale = handle.get_scale().unwrap_or_default();
let insets = handle.content_insets().to_px(scale);
let mut size = handle.get_size().to_px(scale);
size.width -= insets.x_value();
size.height -= insets.y_value();
(size.width as u32, size.height as u32)
}

fn render(&mut self) {
let (width, height) = self.surface_size();
if self.surface.is_none() {
self.surface = Some(pollster::block_on(self.render.create_surface(
&self.handle,
width,
height,
)));
}

let mut sb = SceneBuilder::for_scene(&mut self.scene);
let rect = Rect::from_origin_size(Point::new(0.0, 0.0), (width.into(), height.into()));
sb.fill(
Fill::NonZero,
Affine::IDENTITY,
&Brush::Solid(Color::WHITE_SMOKE),
None,
&rect,
);

let mut lcx = parley::LayoutContext::new();
let mut layout_builder =
lcx.ranged_builder(&mut self.font_context, "Press f to toggle fullscreen", 1.0);
let mut layout = layout_builder.build();
layout.break_all_lines(None, parley::layout::Alignment::Start);
render_text(&mut sb, Affine::IDENTITY, &layout);

if let Some(surface) = self.surface.as_mut() {
if surface.config.width != width || surface.config.height != height {
self.render.resize_surface(surface, width, height);
}
let surface_texture = surface.surface.get_current_texture().unwrap();
let dev_id = surface.dev_id;
let device = &self.render.devices[dev_id].device;
let queue = &self.render.devices[dev_id].queue;
self.renderer
.get_or_insert_with(|| Renderer::new(device).unwrap())
.render_to_surface(device, queue, &self.scene, &surface_texture, width, height)
.unwrap();
surface_texture.present();
}
}
}

impl WinHandler for WindowState {
fn connect(&mut self, handle: &WindowHandle) {
self.handle = handle.clone();
self.schedule_render();
}

fn prepare_paint(&mut self) {}

fn paint(&mut self, _: &Region) {
self.render();
self.schedule_render();
}

fn key_up(&mut self, event: KeyEvent) {
if event.key == Key::Character("f".into()) {
self.fullscreen ^= true;
self.handle.set_fullscreen(self.fullscreen);
}
}

fn request_close(&mut self) {
self.handle.close();
}

fn destroy(&mut self) {
Application::global().quit()
}

fn as_any(&mut self) -> &mut dyn Any {
self
}
}

#[derive(Clone, Debug)]
pub struct ParleyBrush(pub Brush);

impl Default for ParleyBrush {
fn default() -> ParleyBrush {
ParleyBrush(Brush::Solid(Color::rgb8(0, 0, 0)))
}
}

impl PartialEq<ParleyBrush> for ParleyBrush {
fn eq(&self, _other: &ParleyBrush) -> bool {
true // FIXME
}
}

impl parley::style::Brush for ParleyBrush {}

pub fn render_text(builder: &mut SceneBuilder, transform: Affine, layout: &Layout<ParleyBrush>) {
let mut gcx = GlyphContext::new();
for line in layout.lines() {
for glyph_run in line.glyph_runs() {
let mut x = glyph_run.offset();
let y = glyph_run.baseline();
let run = glyph_run.run();
let font = run.font().as_ref();
let font_size = run.font_size();
let font_ref = FontRef {
data: font.data,
offset: font.offset,
};
let style = glyph_run.style();
let vars: [(Tag, f32); 0] = [];
let mut gp = gcx.new_provider(&font_ref, None, font_size, false, vars);
for glyph in glyph_run.glyphs() {
if let Some(fragment) = gp.get(glyph.id, Some(&style.brush.0)) {
let gx = x + glyph.x;
let gy = y - glyph.y;
let xform = Affine::translate((gx as f64, gy as f64))
* Affine::scale_non_uniform(1.0, -1.0);
builder.append(&fragment, Some(transform * xform));
}
x += glyph.advance;
}
}
}
}
8 changes: 7 additions & 1 deletion src/backend/gtk/window.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1004,6 +1004,10 @@ impl WindowHandle {
}
}

pub fn set_fullscreen(&self, _fullscreen: bool) {
warn!("set_fullscreen unimplemented on gtk");
}

pub fn set_position(&self, mut position: Point) {
if let Some(state) = self.state.upgrade() {
if let Some(parent_state) = &state.parent {
Expand Down Expand Up @@ -1085,11 +1089,13 @@ impl WindowHandle {
}

pub fn set_window_state(&mut self, size_state: window::WindowState) {
use window::WindowState::{Maximized, Minimized, Restored};
use window::WindowState::{Fullscreen, Maximized, Minimized, Restored};
let cur_size_state = self.get_window_state();
if let Some(state) = self.state.upgrade() {
match (size_state, cur_size_state) {
(s1, s2) if s1 == s2 => (),
(Fullscreen, _) => (), // Fullscreen not yet supported,
(_, Fullscreen) => (),
(Maximized, _) => state.window.maximize(),
(Minimized, _) => state.window.iconify(),
(Restored, Maximized) => state.window.unmaximize(),
Expand Down
5 changes: 5 additions & 0 deletions src/backend/mac/window.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1327,6 +1327,9 @@ impl WindowHandle {
// TODO: Implement this
pub fn show_titlebar(&self, _show_titlebar: bool) {}

// TODO: Implement this
pub fn set_fullscreen(&self, _fullscreen: bool) {}

// Need to translate mac y coords, as they start from bottom left
pub fn set_position(&self, mut position: Point) {
// TODO: Maybe @cmyr can get this into a state where modal windows follow the parent?
Expand Down Expand Up @@ -1451,6 +1454,8 @@ impl WindowHandle {
(WindowState::Restored, WindowState::Minimized) => {
let () = msg_send![window, deminiaturize: self];
}
(WindowState::Fullscreen, _) => {} // Fullscreen not yet implemented
(_, WindowState::Fullscreen) => {}
(WindowState::Restored, WindowState::Restored) => {} // Can't be reached
}
}
Expand Down
4 changes: 4 additions & 0 deletions src/backend/wayland/window.rs
Original file line number Diff line number Diff line change
Expand Up @@ -110,6 +110,10 @@ impl WindowHandle {
tracing::warn!("show_titlebar is unimplemented on wayland");
}

pub fn set_fullscreen(&self, _fullscreen: bool) {
tracing::warn!("set_fullscreen unimplemented on wayland");
}

pub fn set_position(&self, _position: Point) {
tracing::warn!("set_position is unimplemented on wayland");
}
Expand Down
4 changes: 4 additions & 0 deletions src/backend/web/window.rs
Original file line number Diff line number Diff line change
Expand Up @@ -514,6 +514,10 @@ impl WindowHandle {
warn!("show_titlebar unimplemented for web");
}

pub fn set_fullscreen(&self, _fullscreen: bool) {
warn!("WindowHandle::set_fullscreen unimplemented for web");
}

pub fn set_position(&self, _position: Point) {
warn!("WindowHandle::set_position unimplemented for web");
}
Expand Down
Loading