Skip to content

Commit

Permalink
Merge pull request #59 from thedjinn/disable-calayer-actions
Browse files Browse the repository at this point in the history
Disable CALayer fade action when setting buffers
  • Loading branch information
jackpot51 authored Jan 6, 2023
2 parents ee3e6e8 + b72055d commit c0142e9
Show file tree
Hide file tree
Showing 2 changed files with 110 additions and 1 deletion.
100 changes: 100 additions & 0 deletions examples/rectangle.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,100 @@
use softbuffer::GraphicsContext;
use winit::event::{ElementState, Event, KeyboardInput, VirtualKeyCode, WindowEvent};
use winit::event_loop::{ControlFlow, EventLoop};
use winit::window::WindowBuilder;

fn redraw(buffer: &mut [u32], width: usize, height: usize, flag: bool) {
for (index, color) in buffer.iter_mut().enumerate() {
let y = index / width;
let x = index % width;

if flag && x >= 100 && x < width - 100 && y >= 100 && y < height - 100 {
*color = 0x00ffffff;
} else {
let red = (x & 0xff) ^ (y & 0xff);
let green = (x & 0x7f) ^ (y & 0x7f);
let blue = (x & 0x3f) ^ (y & 0x3f);
*color = (blue | (green << 8) | (red << 16)) as u32;
}
}
}

fn main() {
let event_loop = EventLoop::new();

let window = WindowBuilder::new()
.with_title("Press space to show/hide a rectangle")
.build(&event_loop)
.unwrap();

#[cfg(target_arch = "wasm32")]
{
use winit::platform::web::WindowExtWebSys;

web_sys::window()
.unwrap()
.document()
.unwrap()
.body()
.unwrap()
.append_child(&window.canvas())
.unwrap();
}

let mut graphics_context = unsafe { GraphicsContext::new(&window, &window) }.unwrap();

let mut buffer = Vec::new();
let mut flag = false;

event_loop.run(move |event, _, control_flow| {
*control_flow = ControlFlow::Wait;

match event {
Event::RedrawRequested(window_id) if window_id == window.id() => {
// Grab the window's client area dimensions
let (width, height) = {
let size = window.inner_size();
(size.width as usize, size.height as usize)
};

// Resize the off-screen buffer if the window size has changed
if buffer.len() != width * height {
buffer.resize(width * height, 0);
}

// Draw something in the offscreen buffer
redraw(&mut buffer, width, height, flag);

// Blit the offscreen buffer to the window's client area
graphics_context.set_buffer(&buffer, width as u16, height as u16);
}

Event::WindowEvent {
event: WindowEvent::CloseRequested,
window_id,
} if window_id == window.id() => {
*control_flow = ControlFlow::Exit;
}

Event::WindowEvent {
event:
WindowEvent::KeyboardInput {
input:
KeyboardInput {
state: ElementState::Pressed,
virtual_keycode: Some(VirtualKeyCode::Space),
..
},
..
},
window_id,
} if window_id == window.id() => {
// Flip the rectangle flag and request a redraw to show the changed image
flag = !flag;
window.request_redraw();
}

_ => {}
}
});
}
11 changes: 10 additions & 1 deletion src/cg.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ use raw_window_handle::AppKitWindowHandle;

use cocoa::appkit::{NSView, NSViewHeightSizable, NSViewWidthSizable, NSWindow};
use cocoa::base::{id, nil};
use cocoa::quartzcore::{CALayer, ContentsGravity};
use cocoa::quartzcore::{transaction, CALayer, ContentsGravity};
use foreign_types::ForeignType;

use std::sync::Arc;
Expand Down Expand Up @@ -55,6 +55,15 @@ impl CGImpl {
false,
kCGRenderingIntentDefault,
);

// The CALayer has a default action associated with a change in the layer contents, causing
// a quarter second fade transition to happen every time a new buffer is applied. This can
// be mitigated by wrapping the operation in a transaction and disabling all actions.
transaction::begin();
transaction::set_disable_actions(true);

unsafe { self.layer.set_contents(image.as_ptr() as id) };

transaction::commit();
}
}

0 comments on commit c0142e9

Please sign in to comment.