mirror of
https://github.com/GraphiteEditor/Graphite.git
synced 2025-12-23 10:11:54 +00:00
parent
2e4481880e
commit
a5cf62a90b
6 changed files with 68 additions and 16 deletions
|
|
@ -361,8 +361,8 @@ impl App {
|
|||
}
|
||||
}
|
||||
AppEvent::CursorChange(cursor) => {
|
||||
if let Some(window) = &self.window {
|
||||
window.set_cursor(cursor);
|
||||
if let Some(window) = &mut self.window {
|
||||
window.set_cursor(event_loop, cursor);
|
||||
}
|
||||
}
|
||||
AppEvent::CloseWindow => {
|
||||
|
|
|
|||
|
|
@ -12,16 +12,19 @@
|
|||
//!
|
||||
//! The system gracefully falls back to CPU textures when hardware acceleration is unavailable.
|
||||
|
||||
use crate::event::{AppEvent, AppEventScheduler};
|
||||
use crate::render::FrameBufferRef;
|
||||
use crate::wrapper::{WgpuContext, deserialize_editor_message};
|
||||
use std::fs::File;
|
||||
use std::io::{Cursor, Read};
|
||||
use std::io;
|
||||
use std::io::Read;
|
||||
use std::path::PathBuf;
|
||||
use std::sync::mpsc::Receiver;
|
||||
use std::sync::{Arc, Mutex};
|
||||
use std::time::Instant;
|
||||
|
||||
use crate::event::{AppEvent, AppEventScheduler};
|
||||
use crate::render::FrameBufferRef;
|
||||
use crate::window::Cursor;
|
||||
use crate::wrapper::{WgpuContext, deserialize_editor_message};
|
||||
|
||||
mod consts;
|
||||
mod context;
|
||||
mod dirs;
|
||||
|
|
@ -42,7 +45,7 @@ pub(crate) trait CefEventHandler: Send + Sync + 'static {
|
|||
#[cfg(feature = "accelerated_paint")]
|
||||
fn draw_gpu(&self, shared_texture: SharedTextureHandle);
|
||||
fn load_resource(&self, path: PathBuf) -> Option<Resource>;
|
||||
fn cursor_change(&self, cursor: winit::cursor::Cursor);
|
||||
fn cursor_change(&self, cursor: Cursor);
|
||||
/// Schedule the main event loop to run the CEF event loop after the timeout.
|
||||
/// See [`_cef_browser_process_handler_t::on_schedule_message_pump_work`] for more documentation.
|
||||
fn schedule_cef_message_loop_work(&self, scheduled_time: Instant);
|
||||
|
|
@ -105,7 +108,7 @@ pub(crate) struct Resource {
|
|||
#[expect(dead_code)]
|
||||
#[derive(Clone)]
|
||||
pub(crate) enum ResourceReader {
|
||||
Embedded(Cursor<&'static [u8]>),
|
||||
Embedded(io::Cursor<&'static [u8]>),
|
||||
File(Arc<File>),
|
||||
}
|
||||
impl Read for ResourceReader {
|
||||
|
|
@ -227,7 +230,7 @@ impl CefEventHandler for CefHandler {
|
|||
&& let Some(file) = resources.get_file(&path)
|
||||
{
|
||||
return Some(Resource {
|
||||
reader: ResourceReader::Embedded(Cursor::new(file.contents())),
|
||||
reader: ResourceReader::Embedded(io::Cursor::new(file.contents())),
|
||||
mimetype,
|
||||
});
|
||||
}
|
||||
|
|
@ -252,7 +255,7 @@ impl CefEventHandler for CefHandler {
|
|||
None
|
||||
}
|
||||
|
||||
fn cursor_change(&self, cursor: winit::cursor::Cursor) {
|
||||
fn cursor_change(&self, cursor: Cursor) {
|
||||
self.app_event_scheduler.schedule(AppEvent::CursorChange(cursor));
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
use cef::rc::{Rc, RcImpl};
|
||||
use cef::sys::{_cef_display_handler_t, cef_base_ref_counted_t, cef_cursor_type_t::*, cef_log_severity_t::*};
|
||||
use cef::{CefString, ImplDisplayHandler, WrapDisplayHandler};
|
||||
use cef::{CefString, ImplDisplayHandler, Point, Size, WrapDisplayHandler};
|
||||
use winit::cursor::CursorIcon;
|
||||
|
||||
use crate::cef::CefEventHandler;
|
||||
|
|
@ -25,7 +25,21 @@ type CefCursorHandle = cef::CursorHandle;
|
|||
type CefCursorHandle = *mut u8;
|
||||
|
||||
impl<H: CefEventHandler> ImplDisplayHandler for DisplayHandlerImpl<H> {
|
||||
fn on_cursor_change(&self, _browser: Option<&mut cef::Browser>, _cursor: CefCursorHandle, cursor_type: cef::CursorType, _custom_cursor_info: Option<&cef::CursorInfo>) -> std::ffi::c_int {
|
||||
fn on_cursor_change(&self, _browser: Option<&mut cef::Browser>, _cursor: CefCursorHandle, cursor_type: cef::CursorType, custom_cursor_info: Option<&cef::CursorInfo>) -> std::ffi::c_int {
|
||||
if let Some(custom_cursor_info) = custom_cursor_info {
|
||||
let Size { width, height } = custom_cursor_info.size;
|
||||
let Point { x: hotspot_x, y: hotspot_y } = custom_cursor_info.hotspot;
|
||||
let buffer_size = (width * height * 4) as usize;
|
||||
let buffer_ptr = custom_cursor_info.buffer as *const u8;
|
||||
|
||||
if !buffer_ptr.is_null() && buffer_ptr.align_offset(std::mem::align_of::<u8>()) == 0 {
|
||||
let buffer = unsafe { std::slice::from_raw_parts(buffer_ptr, buffer_size) }.to_vec();
|
||||
let cursor = winit::cursor::CustomCursorSource::from_rgba(buffer, width as u16, height as u16, hotspot_x as u16, hotspot_y as u16).unwrap();
|
||||
self.event_handler.cursor_change(cursor.into());
|
||||
return 1; // We handled the cursor change.
|
||||
}
|
||||
}
|
||||
|
||||
let cursor = match cursor_type.into() {
|
||||
CT_POINTER => CursorIcon::Default,
|
||||
CT_CROSS => CursorIcon::Crosshair,
|
||||
|
|
@ -72,7 +86,6 @@ impl<H: CefEventHandler> ImplDisplayHandler for DisplayHandlerImpl<H> {
|
|||
CT_GRABBING => CursorIcon::Grabbing,
|
||||
CT_MIDDLE_PANNING_VERTICAL => CursorIcon::AllScroll,
|
||||
CT_MIDDLE_PANNING_HORIZONTAL => CursorIcon::AllScroll,
|
||||
CT_CUSTOM => CursorIcon::Default,
|
||||
CT_DND_NONE => CursorIcon::Default,
|
||||
CT_DND_MOVE => CursorIcon::Move,
|
||||
CT_DND_COPY => CursorIcon::Copy,
|
||||
|
|
|
|||
|
|
@ -3,7 +3,7 @@ use crate::wrapper::messages::DesktopWrapperMessage;
|
|||
|
||||
pub(crate) enum AppEvent {
|
||||
UiUpdate(wgpu::Texture),
|
||||
CursorChange(winit::cursor::Cursor),
|
||||
CursorChange(crate::window::Cursor),
|
||||
ScheduleBrowserWork(std::time::Instant),
|
||||
WebCommunicationInitialized,
|
||||
DesktopWrapperMessage(DesktopWrapperMessage),
|
||||
|
|
|
|||
|
|
@ -1,4 +1,6 @@
|
|||
use std::collections::HashMap;
|
||||
use std::sync::Arc;
|
||||
use winit::cursor::{CursorIcon, CustomCursor, CustomCursorSource};
|
||||
use winit::event_loop::ActiveEventLoop;
|
||||
use winit::window::{Window as WinitWindow, WindowAttributes};
|
||||
|
||||
|
|
@ -35,6 +37,7 @@ pub(crate) struct Window {
|
|||
winit_window: Arc<dyn winit::window::Window>,
|
||||
#[allow(dead_code)]
|
||||
native_handle: native::NativeWindowImpl,
|
||||
custom_cursors: HashMap<CustomCursorSource, CustomCursor>,
|
||||
}
|
||||
|
||||
impl Window {
|
||||
|
|
@ -57,6 +60,7 @@ impl Window {
|
|||
Self {
|
||||
winit_window: winit_window.into(),
|
||||
native_handle,
|
||||
custom_cursors: HashMap::new(),
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -108,7 +112,24 @@ impl Window {
|
|||
self.native_handle.show_all();
|
||||
}
|
||||
|
||||
pub(crate) fn set_cursor(&self, cursor: winit::cursor::Cursor) {
|
||||
pub(crate) fn set_cursor(&mut self, event_loop: &dyn ActiveEventLoop, cursor: Cursor) {
|
||||
let cursor = match cursor {
|
||||
Cursor::Icon(cursor_icon) => cursor_icon.into(),
|
||||
Cursor::Custom(custom_cursor_source) => {
|
||||
let custom_cursor = match self.custom_cursors.get(&custom_cursor_source).cloned() {
|
||||
Some(cursor) => cursor,
|
||||
None => {
|
||||
let Ok(custom_cursor) = event_loop.create_custom_cursor(custom_cursor_source.clone()) else {
|
||||
tracing::error!("Failed to create custom cursor");
|
||||
return;
|
||||
};
|
||||
self.custom_cursors.insert(custom_cursor_source, custom_cursor.clone());
|
||||
custom_cursor
|
||||
}
|
||||
};
|
||||
custom_cursor.into()
|
||||
}
|
||||
};
|
||||
self.winit_window.set_cursor(cursor);
|
||||
}
|
||||
|
||||
|
|
@ -116,3 +137,18 @@ impl Window {
|
|||
self.native_handle.update_menu(entries);
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) enum Cursor {
|
||||
Icon(CursorIcon),
|
||||
Custom(CustomCursorSource),
|
||||
}
|
||||
impl From<CursorIcon> for Cursor {
|
||||
fn from(icon: CursorIcon) -> Self {
|
||||
Cursor::Icon(icon)
|
||||
}
|
||||
}
|
||||
impl From<CustomCursorSource> for Cursor {
|
||||
fn from(custom: CustomCursorSource) -> Self {
|
||||
Cursor::Custom(custom)
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -32,7 +32,7 @@ if (isInstallNeeded()) {
|
|||
console.log("Finished installing npm packages.");
|
||||
} catch (_) {
|
||||
// eslint-disable-next-line no-console
|
||||
console.error("Failed to install npm packages. Please run `npm install` from the `/frontend` directory.");
|
||||
console.error("Failed to install npm packages. Please delete the `node_modules` folder and run `npm install` from the `/frontend` directory.");
|
||||
process.exit(1);
|
||||
}
|
||||
} else {
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue