Lock down mac os platform type visibility in the rest of GPUI
Add documentation to all platform types
This commit is contained in:
parent
33105486aa
commit
9da6b8c7f6
15 changed files with 261 additions and 67 deletions
|
@ -1,3 +1,5 @@
|
||||||
|
#![deny(missing_docs)]
|
||||||
|
|
||||||
mod app_menu;
|
mod app_menu;
|
||||||
mod keystroke;
|
mod keystroke;
|
||||||
#[cfg(target_os = "macos")]
|
#[cfg(target_os = "macos")]
|
||||||
|
@ -34,7 +36,7 @@ use uuid::Uuid;
|
||||||
pub use app_menu::*;
|
pub use app_menu::*;
|
||||||
pub use keystroke::*;
|
pub use keystroke::*;
|
||||||
#[cfg(target_os = "macos")]
|
#[cfg(target_os = "macos")]
|
||||||
pub use mac::*;
|
pub(crate) use mac::*;
|
||||||
#[cfg(any(test, feature = "test-support"))]
|
#[cfg(any(test, feature = "test-support"))]
|
||||||
pub use test::*;
|
pub use test::*;
|
||||||
use time::UtcOffset;
|
use time::UtcOffset;
|
||||||
|
@ -69,11 +71,10 @@ pub(crate) trait Platform: 'static {
|
||||||
fn set_display_link_output_callback(
|
fn set_display_link_output_callback(
|
||||||
&self,
|
&self,
|
||||||
display_id: DisplayId,
|
display_id: DisplayId,
|
||||||
callback: Box<dyn FnMut(&VideoTimestamp, &VideoTimestamp) + Send>,
|
callback: Box<dyn FnMut() + Send>,
|
||||||
);
|
);
|
||||||
fn start_display_link(&self, display_id: DisplayId);
|
fn start_display_link(&self, display_id: DisplayId);
|
||||||
fn stop_display_link(&self, display_id: DisplayId);
|
fn stop_display_link(&self, display_id: DisplayId);
|
||||||
// fn add_status_item(&self, _handle: AnyWindowHandle) -> Box<dyn PlatformWindow>;
|
|
||||||
|
|
||||||
fn open_url(&self, url: &str);
|
fn open_url(&self, url: &str);
|
||||||
fn on_open_urls(&self, callback: Box<dyn FnMut(Vec<String>)>);
|
fn on_open_urls(&self, callback: Box<dyn FnMut(Vec<String>)>);
|
||||||
|
@ -395,20 +396,50 @@ impl PlatformInputHandler {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Zed's interface for handling text input from the platform's IME system
|
||||||
|
/// This is currently a 1:1 exposure of the NSTextInputClient API:
|
||||||
|
///
|
||||||
|
/// <https://developer.apple.com/documentation/appkit/nstextinputclient>
|
||||||
pub trait InputHandler: 'static {
|
pub trait InputHandler: 'static {
|
||||||
|
/// Get the range of the user's currently selected text, if any
|
||||||
|
/// Corresponds to [selectedRange()](https://developer.apple.com/documentation/appkit/nstextinputclient/1438242-selectedrange)
|
||||||
|
///
|
||||||
|
/// Return value is in terms of UTF-16 characters, from 0 to the length of the document
|
||||||
fn selected_text_range(&mut self, cx: &mut WindowContext) -> Option<Range<usize>>;
|
fn selected_text_range(&mut self, cx: &mut WindowContext) -> Option<Range<usize>>;
|
||||||
|
|
||||||
|
/// Get the range of the currently marked text, if any
|
||||||
|
/// Corresponds to [markedRange()](https://developer.apple.com/documentation/appkit/nstextinputclient/1438250-markedrange)
|
||||||
|
///
|
||||||
|
/// Return value is in terms of UTF-16 characters, from 0 to the length of the document
|
||||||
fn marked_text_range(&mut self, cx: &mut WindowContext) -> Option<Range<usize>>;
|
fn marked_text_range(&mut self, cx: &mut WindowContext) -> Option<Range<usize>>;
|
||||||
|
|
||||||
|
/// Get the text for the given document range in UTF-16 characters
|
||||||
|
/// Corresponds to [attributedSubstring(forProposedRange: actualRange:)](https://developer.apple.com/documentation/appkit/nstextinputclient/1438238-attributedsubstring)
|
||||||
|
///
|
||||||
|
/// range_utf16 is in terms of UTF-16 characters
|
||||||
fn text_for_range(
|
fn text_for_range(
|
||||||
&mut self,
|
&mut self,
|
||||||
range_utf16: Range<usize>,
|
range_utf16: Range<usize>,
|
||||||
cx: &mut WindowContext,
|
cx: &mut WindowContext,
|
||||||
) -> Option<String>;
|
) -> Option<String>;
|
||||||
|
|
||||||
|
/// Replace the text in the given document range with the given text
|
||||||
|
/// Corresponds to [insertText(_:replacementRange:)](https://developer.apple.com/documentation/appkit/nstextinputclient/1438258-inserttext)
|
||||||
|
///
|
||||||
|
/// replacement_range is in terms of UTF-16 characters
|
||||||
fn replace_text_in_range(
|
fn replace_text_in_range(
|
||||||
&mut self,
|
&mut self,
|
||||||
replacement_range: Option<Range<usize>>,
|
replacement_range: Option<Range<usize>>,
|
||||||
text: &str,
|
text: &str,
|
||||||
cx: &mut WindowContext,
|
cx: &mut WindowContext,
|
||||||
);
|
);
|
||||||
|
|
||||||
|
/// Replace the text in the given document range with the given text,
|
||||||
|
/// and mark the given text as part of of an IME 'composing' state
|
||||||
|
/// Corresponds to [setMarkedText(_:selectedRange:replacementRange:)](https://developer.apple.com/documentation/appkit/nstextinputclient/1438246-setmarkedtext)
|
||||||
|
///
|
||||||
|
/// range_utf16 is in terms of UTF-16 characters
|
||||||
|
/// new_selected_range is in terms of UTF-16 characters
|
||||||
fn replace_and_mark_text_in_range(
|
fn replace_and_mark_text_in_range(
|
||||||
&mut self,
|
&mut self,
|
||||||
range_utf16: Option<Range<usize>>,
|
range_utf16: Option<Range<usize>>,
|
||||||
|
@ -416,7 +447,15 @@ pub trait InputHandler: 'static {
|
||||||
new_selected_range: Option<Range<usize>>,
|
new_selected_range: Option<Range<usize>>,
|
||||||
cx: &mut WindowContext,
|
cx: &mut WindowContext,
|
||||||
);
|
);
|
||||||
|
|
||||||
|
/// Remove the IME 'composing' state from the document
|
||||||
|
/// Corresponds to [unmarkText()](https://developer.apple.com/documentation/appkit/nstextinputclient/1438239-unmarktext)
|
||||||
fn unmark_text(&mut self, cx: &mut WindowContext);
|
fn unmark_text(&mut self, cx: &mut WindowContext);
|
||||||
|
|
||||||
|
/// Get the bounds of the given document range in screen coordinates
|
||||||
|
/// Corresponds to [firstRect(forCharacterRange:actualRange:)](https://developer.apple.com/documentation/appkit/nstextinputclient/1438240-firstrect)
|
||||||
|
///
|
||||||
|
/// This is used for positioning the IME candidate window
|
||||||
fn bounds_for_range(
|
fn bounds_for_range(
|
||||||
&mut self,
|
&mut self,
|
||||||
range_utf16: Range<usize>,
|
range_utf16: Range<usize>,
|
||||||
|
@ -424,15 +463,31 @@ pub trait InputHandler: 'static {
|
||||||
) -> Option<Bounds<Pixels>>;
|
) -> Option<Bounds<Pixels>>;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// The variables that can be configured when creating a new window
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub struct WindowOptions {
|
pub struct WindowOptions {
|
||||||
|
/// The initial bounds of the window
|
||||||
pub bounds: WindowBounds,
|
pub bounds: WindowBounds,
|
||||||
|
|
||||||
|
/// The titlebar configuration of the window
|
||||||
pub titlebar: Option<TitlebarOptions>,
|
pub titlebar: Option<TitlebarOptions>,
|
||||||
|
|
||||||
|
/// Whether the window should be centered on the screen
|
||||||
pub center: bool,
|
pub center: bool,
|
||||||
|
|
||||||
|
/// Whether the window should be focused when created
|
||||||
pub focus: bool,
|
pub focus: bool,
|
||||||
|
|
||||||
|
/// Whether the window should be shown when created
|
||||||
pub show: bool,
|
pub show: bool,
|
||||||
|
|
||||||
|
/// The kind of window to create
|
||||||
pub kind: WindowKind,
|
pub kind: WindowKind,
|
||||||
|
|
||||||
|
/// Whether the window should be movable by the user
|
||||||
pub is_movable: bool,
|
pub is_movable: bool,
|
||||||
|
|
||||||
|
/// The display to create the window on
|
||||||
pub display_id: Option<DisplayId>,
|
pub display_id: Option<DisplayId>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -455,46 +510,67 @@ impl Default for WindowOptions {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// The options that can be configured for a window's titlebar
|
||||||
#[derive(Debug, Default)]
|
#[derive(Debug, Default)]
|
||||||
pub struct TitlebarOptions {
|
pub struct TitlebarOptions {
|
||||||
|
/// The initial title of the window
|
||||||
pub title: Option<SharedString>,
|
pub title: Option<SharedString>,
|
||||||
|
|
||||||
|
/// Whether the titlebar should appear transparent
|
||||||
pub appears_transparent: bool,
|
pub appears_transparent: bool,
|
||||||
|
|
||||||
|
/// The position of the macOS traffic light buttons
|
||||||
pub traffic_light_position: Option<Point<Pixels>>,
|
pub traffic_light_position: Option<Point<Pixels>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Copy, Clone, Debug)]
|
/// The kind of window to create
|
||||||
pub enum Appearance {
|
|
||||||
Light,
|
|
||||||
VibrantLight,
|
|
||||||
Dark,
|
|
||||||
VibrantDark,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Default for Appearance {
|
|
||||||
fn default() -> Self {
|
|
||||||
Self::Light
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
|
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
|
||||||
pub enum WindowKind {
|
pub enum WindowKind {
|
||||||
|
/// A normal application window
|
||||||
Normal,
|
Normal,
|
||||||
|
|
||||||
|
/// A window that appears above all other windows, usually used for alerts or popups
|
||||||
|
/// use sparingly!
|
||||||
PopUp,
|
PopUp,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Which bounds algorithm to use for the initial size a window
|
||||||
#[derive(Copy, Clone, Debug, PartialEq, Default)]
|
#[derive(Copy, Clone, Debug, PartialEq, Default)]
|
||||||
pub enum WindowBounds {
|
pub enum WindowBounds {
|
||||||
|
/// The window should be full screen, on macOS this corresponds to the full screen feature
|
||||||
Fullscreen,
|
Fullscreen,
|
||||||
|
|
||||||
|
/// Make the window as large as the current display's size.
|
||||||
#[default]
|
#[default]
|
||||||
Maximized,
|
Maximized,
|
||||||
|
|
||||||
|
/// Set the window to the given size in pixels
|
||||||
Fixed(Bounds<GlobalPixels>),
|
Fixed(Bounds<GlobalPixels>),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// The appearance of the window, as defined by the operating system
|
||||||
|
/// On macOS, this corresponds to named [NSAppearance](https://developer.apple.com/documentation/appkit/nsappearance)
|
||||||
|
/// values
|
||||||
#[derive(Copy, Clone, Debug)]
|
#[derive(Copy, Clone, Debug)]
|
||||||
pub enum WindowAppearance {
|
pub enum WindowAppearance {
|
||||||
|
/// A light appearance
|
||||||
|
///
|
||||||
|
/// on macOS, this corresponds to the `aqua` appearance
|
||||||
Light,
|
Light,
|
||||||
|
|
||||||
|
/// A light appearance with vibrant colors
|
||||||
|
///
|
||||||
|
/// on macOS, this corresponds to the `NSAppearanceNameVibrantLight` appearance
|
||||||
VibrantLight,
|
VibrantLight,
|
||||||
|
|
||||||
|
/// A dark appearance
|
||||||
|
///
|
||||||
|
/// on macOS, this corresponds to the `darkAqua` appearance
|
||||||
Dark,
|
Dark,
|
||||||
|
|
||||||
|
/// A dark appearance with vibrant colors
|
||||||
|
///
|
||||||
|
/// on macOS, this corresponds to the `NSAppearanceNameVibrantDark` appearance
|
||||||
VibrantDark,
|
VibrantDark,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -504,40 +580,102 @@ impl Default for WindowAppearance {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// The options that can be configured for a file dialog prompt
|
||||||
#[derive(Copy, Clone, Debug)]
|
#[derive(Copy, Clone, Debug)]
|
||||||
pub struct PathPromptOptions {
|
pub struct PathPromptOptions {
|
||||||
|
/// Should the prompt allow files to be selected?
|
||||||
pub files: bool,
|
pub files: bool,
|
||||||
|
/// Should the prompt allow directories to be selected?
|
||||||
pub directories: bool,
|
pub directories: bool,
|
||||||
|
/// Should the prompt allow multiple files to be selected?
|
||||||
pub multiple: bool,
|
pub multiple: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// What kind of prompt styling to show
|
||||||
#[derive(Copy, Clone, Debug)]
|
#[derive(Copy, Clone, Debug)]
|
||||||
pub enum PromptLevel {
|
pub enum PromptLevel {
|
||||||
|
/// A prompt that is shown when the user should be notified of something
|
||||||
Info,
|
Info,
|
||||||
|
|
||||||
|
/// A prompt that is shown when the user needs to be warned of a potential problem
|
||||||
Warning,
|
Warning,
|
||||||
|
|
||||||
|
/// A prompt that is shown when a critical problem has occurred
|
||||||
Critical,
|
Critical,
|
||||||
}
|
}
|
||||||
|
|
||||||
/// The style of the cursor (pointer)
|
/// The style of the cursor (pointer)
|
||||||
#[derive(Copy, Clone, Debug)]
|
#[derive(Copy, Clone, Debug)]
|
||||||
pub enum CursorStyle {
|
pub enum CursorStyle {
|
||||||
|
/// The default cursor
|
||||||
Arrow,
|
Arrow,
|
||||||
|
|
||||||
|
/// A text input cursor
|
||||||
|
/// corresponds to the CSS cursor value `text`
|
||||||
IBeam,
|
IBeam,
|
||||||
|
|
||||||
|
/// A crosshair cursor
|
||||||
|
/// corresponds to the CSS cursor value `crosshair`
|
||||||
Crosshair,
|
Crosshair,
|
||||||
|
|
||||||
|
/// A closed hand cursor
|
||||||
|
/// corresponds to the CSS cursor value `grabbing`
|
||||||
ClosedHand,
|
ClosedHand,
|
||||||
|
|
||||||
|
/// An open hand cursor
|
||||||
|
/// corresponds to the CSS cursor value `grab`
|
||||||
OpenHand,
|
OpenHand,
|
||||||
|
|
||||||
|
/// A pointing hand cursor
|
||||||
|
/// corresponds to the CSS cursor value `pointer`
|
||||||
PointingHand,
|
PointingHand,
|
||||||
|
|
||||||
|
/// A resize left cursor
|
||||||
|
/// corresponds to the CSS cursor value `w-resize`
|
||||||
ResizeLeft,
|
ResizeLeft,
|
||||||
|
|
||||||
|
/// A resize right cursor
|
||||||
|
/// corresponds to the CSS cursor value `e-resize`
|
||||||
ResizeRight,
|
ResizeRight,
|
||||||
|
|
||||||
|
/// A resize cursor to the left and right
|
||||||
|
/// corresponds to the CSS cursor value `col-resize`
|
||||||
ResizeLeftRight,
|
ResizeLeftRight,
|
||||||
|
|
||||||
|
/// A resize up cursor
|
||||||
|
/// corresponds to the CSS cursor value `n-resize`
|
||||||
ResizeUp,
|
ResizeUp,
|
||||||
|
|
||||||
|
/// A resize down cursor
|
||||||
|
/// corresponds to the CSS cursor value `s-resize`
|
||||||
ResizeDown,
|
ResizeDown,
|
||||||
|
|
||||||
|
/// A resize cursor directing up and down
|
||||||
|
/// corresponds to the CSS cursor value `row-resize`
|
||||||
ResizeUpDown,
|
ResizeUpDown,
|
||||||
|
|
||||||
|
/// A cursor indicating that something will dissappear if moved here
|
||||||
|
/// Does not correspond to a CSS cursor value
|
||||||
DisappearingItem,
|
DisappearingItem,
|
||||||
|
|
||||||
|
/// A text input cursor for vertical layout
|
||||||
|
/// corresponds to the CSS cursor value `vertical-text`
|
||||||
IBeamCursorForVerticalLayout,
|
IBeamCursorForVerticalLayout,
|
||||||
|
|
||||||
|
/// A cursor indicating that the operation is not allowed
|
||||||
|
/// corresponds to the CSS cursor value `not-allowed`
|
||||||
OperationNotAllowed,
|
OperationNotAllowed,
|
||||||
|
|
||||||
|
/// A cursor indicating that the operation will result in a link
|
||||||
|
/// corresponds to the CSS cursor value `alias`
|
||||||
DragLink,
|
DragLink,
|
||||||
|
|
||||||
|
/// A cursor indicating that the operation will result in a copy
|
||||||
|
/// corresponds to the CSS cursor value `copy`
|
||||||
DragCopy,
|
DragCopy,
|
||||||
|
|
||||||
|
/// A cursor indicating that the operation will result in a context menu
|
||||||
|
/// corresponds to the CSS cursor value `context-menu`
|
||||||
ContextualMenu,
|
ContextualMenu,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -547,6 +685,7 @@ impl Default for CursorStyle {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// A datastructure representing a semantic version number
|
||||||
#[derive(Clone, Copy, Debug, Default, Eq, Ord, PartialEq, PartialOrd, Serialize)]
|
#[derive(Clone, Copy, Debug, Default, Eq, Ord, PartialEq, PartialOrd, Serialize)]
|
||||||
pub struct SemanticVersion {
|
pub struct SemanticVersion {
|
||||||
major: usize,
|
major: usize,
|
||||||
|
@ -585,6 +724,7 @@ impl Display for SemanticVersion {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// A clipboard item that should be copied to the clipboard
|
||||||
#[derive(Clone, Debug, Eq, PartialEq)]
|
#[derive(Clone, Debug, Eq, PartialEq)]
|
||||||
pub struct ClipboardItem {
|
pub struct ClipboardItem {
|
||||||
pub(crate) text: String,
|
pub(crate) text: String,
|
||||||
|
@ -592,6 +732,7 @@ pub struct ClipboardItem {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ClipboardItem {
|
impl ClipboardItem {
|
||||||
|
/// Create a new clipboard item with the given text
|
||||||
pub fn new(text: String) -> Self {
|
pub fn new(text: String) -> Self {
|
||||||
Self {
|
Self {
|
||||||
text,
|
text,
|
||||||
|
@ -599,15 +740,18 @@ impl ClipboardItem {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Create a new clipboard item with the given text and metadata
|
||||||
pub fn with_metadata<T: Serialize>(mut self, metadata: T) -> Self {
|
pub fn with_metadata<T: Serialize>(mut self, metadata: T) -> Self {
|
||||||
self.metadata = Some(serde_json::to_string(&metadata).unwrap());
|
self.metadata = Some(serde_json::to_string(&metadata).unwrap());
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Get the text of the clipboard item
|
||||||
pub fn text(&self) -> &String {
|
pub fn text(&self) -> &String {
|
||||||
&self.text
|
&self.text
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Get the metadata of the clipboard item
|
||||||
pub fn metadata<T>(&self) -> Option<T>
|
pub fn metadata<T>(&self) -> Option<T>
|
||||||
where
|
where
|
||||||
T: for<'a> Deserialize<'a>,
|
T: for<'a> Deserialize<'a>,
|
||||||
|
|
|
@ -1,30 +1,49 @@
|
||||||
use crate::{Action, AppContext, Platform};
|
use crate::{Action, AppContext, Platform};
|
||||||
use util::ResultExt;
|
use util::ResultExt;
|
||||||
|
|
||||||
|
/// A menu of the application, either a main menu or a submenu
|
||||||
pub struct Menu<'a> {
|
pub struct Menu<'a> {
|
||||||
|
/// The name of the menu
|
||||||
pub name: &'a str,
|
pub name: &'a str,
|
||||||
|
|
||||||
|
/// The items in the menu
|
||||||
pub items: Vec<MenuItem<'a>>,
|
pub items: Vec<MenuItem<'a>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// The different kinds of items that can be in a menu
|
||||||
pub enum MenuItem<'a> {
|
pub enum MenuItem<'a> {
|
||||||
|
/// A separator between items
|
||||||
Separator,
|
Separator,
|
||||||
|
|
||||||
|
/// A submenu
|
||||||
Submenu(Menu<'a>),
|
Submenu(Menu<'a>),
|
||||||
|
|
||||||
|
/// An action that can be performed
|
||||||
Action {
|
Action {
|
||||||
|
/// The name of this menu item
|
||||||
name: &'a str,
|
name: &'a str,
|
||||||
|
|
||||||
|
/// the action to perform when this menu item is selected
|
||||||
action: Box<dyn Action>,
|
action: Box<dyn Action>,
|
||||||
|
|
||||||
|
/// The OS Action that corresponds to this action, if any
|
||||||
|
/// See [`OsAction`] for more information
|
||||||
os_action: Option<OsAction>,
|
os_action: Option<OsAction>,
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> MenuItem<'a> {
|
impl<'a> MenuItem<'a> {
|
||||||
|
/// Creates a new menu item that is a separator
|
||||||
pub fn separator() -> Self {
|
pub fn separator() -> Self {
|
||||||
Self::Separator
|
Self::Separator
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Creates a new menu item that is a submenu
|
||||||
pub fn submenu(menu: Menu<'a>) -> Self {
|
pub fn submenu(menu: Menu<'a>) -> Self {
|
||||||
Self::Submenu(menu)
|
Self::Submenu(menu)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Creates a new menu item that invokes an action
|
||||||
pub fn action(name: &'a str, action: impl Action) -> Self {
|
pub fn action(name: &'a str, action: impl Action) -> Self {
|
||||||
Self::Action {
|
Self::Action {
|
||||||
name,
|
name,
|
||||||
|
@ -33,6 +52,7 @@ impl<'a> MenuItem<'a> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Creates a new menu item that invokes an action and has an OS action
|
||||||
pub fn os_action(name: &'a str, action: impl Action, os_action: OsAction) -> Self {
|
pub fn os_action(name: &'a str, action: impl Action, os_action: OsAction) -> Self {
|
||||||
Self::Action {
|
Self::Action {
|
||||||
name,
|
name,
|
||||||
|
@ -42,13 +62,31 @@ impl<'a> MenuItem<'a> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// TODO: As part of the global selections refactor, these should
|
||||||
|
// be moved to GPUI-provided actions that make this association
|
||||||
|
// without leaking the platform details to GPUI users
|
||||||
|
|
||||||
|
/// OS actions are actions that are recognized by the operating system
|
||||||
|
/// This allows the operating system to provide specialized behavior for
|
||||||
|
/// these actions
|
||||||
#[derive(Copy, Clone, Eq, PartialEq)]
|
#[derive(Copy, Clone, Eq, PartialEq)]
|
||||||
pub enum OsAction {
|
pub enum OsAction {
|
||||||
|
/// The 'cut' action
|
||||||
Cut,
|
Cut,
|
||||||
|
|
||||||
|
/// The 'copy' action
|
||||||
Copy,
|
Copy,
|
||||||
|
|
||||||
|
/// The 'paste' action
|
||||||
Paste,
|
Paste,
|
||||||
|
|
||||||
|
/// The 'select all' action
|
||||||
SelectAll,
|
SelectAll,
|
||||||
|
|
||||||
|
/// The 'undo' action
|
||||||
Undo,
|
Undo,
|
||||||
|
|
||||||
|
/// The 'redo' action
|
||||||
Redo,
|
Redo,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -3,24 +3,31 @@ use serde::Deserialize;
|
||||||
use smallvec::SmallVec;
|
use smallvec::SmallVec;
|
||||||
use std::fmt::Write;
|
use std::fmt::Write;
|
||||||
|
|
||||||
|
/// A keystroke and associated metadata generated by the platform
|
||||||
#[derive(Clone, Debug, Eq, PartialEq, Default, Deserialize, Hash)]
|
#[derive(Clone, Debug, Eq, PartialEq, Default, Deserialize, Hash)]
|
||||||
pub struct Keystroke {
|
pub struct Keystroke {
|
||||||
|
/// the state of the modifier keys at the time the keystroke was generated
|
||||||
pub modifiers: Modifiers,
|
pub modifiers: Modifiers,
|
||||||
|
|
||||||
/// key is the character printed on the key that was pressed
|
/// key is the character printed on the key that was pressed
|
||||||
/// e.g. for option-s, key is "s"
|
/// e.g. for option-s, key is "s"
|
||||||
pub key: String,
|
pub key: String,
|
||||||
|
|
||||||
/// ime_key is the character inserted by the IME engine when that key was pressed.
|
/// ime_key is the character inserted by the IME engine when that key was pressed.
|
||||||
/// e.g. for option-s, ime_key is "ß"
|
/// e.g. for option-s, ime_key is "ß"
|
||||||
pub ime_key: Option<String>,
|
pub ime_key: Option<String>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Keystroke {
|
impl Keystroke {
|
||||||
// When matching a key we cannot know whether the user intended to type
|
/// When matching a key we cannot know whether the user intended to type
|
||||||
// the ime_key or the key. On some non-US keyboards keys we use in our
|
/// the ime_key or the key itself. On some non-US keyboards keys we use in our
|
||||||
// bindings are behind option (for example `$` is typed `alt-ç` on a Czech keyboard),
|
/// bindings are behind option (for example `$` is typed `alt-ç` on a Czech keyboard),
|
||||||
// and on some keyboards the IME handler converts a sequence of keys into a
|
/// and on some keyboards the IME handler converts a sequence of keys into a
|
||||||
// specific character (for example `"` is typed as `" space` on a brazilian keyboard).
|
/// specific character (for example `"` is typed as `" space` on a brazilian keyboard).
|
||||||
pub fn match_candidates(&self) -> SmallVec<[Keystroke; 2]> {
|
///
|
||||||
|
/// This method generates a list of potential keystroke candidates that could be matched
|
||||||
|
/// against when resolving a keybinding.
|
||||||
|
pub(crate) fn match_candidates(&self) -> SmallVec<[Keystroke; 2]> {
|
||||||
let mut possibilities = SmallVec::new();
|
let mut possibilities = SmallVec::new();
|
||||||
match self.ime_key.as_ref() {
|
match self.ime_key.as_ref() {
|
||||||
None => possibilities.push(self.clone()),
|
None => possibilities.push(self.clone()),
|
||||||
|
@ -47,7 +54,7 @@ impl Keystroke {
|
||||||
|
|
||||||
/// key syntax is:
|
/// key syntax is:
|
||||||
/// [ctrl-][alt-][shift-][cmd-][fn-]key[->ime_key]
|
/// [ctrl-][alt-][shift-][cmd-][fn-]key[->ime_key]
|
||||||
/// ime_key is only used for generating test events,
|
/// ime_key syntax is only used for generating test events,
|
||||||
/// when matching a key with an ime_key set will be matched without it.
|
/// when matching a key with an ime_key set will be matched without it.
|
||||||
pub fn parse(source: &str) -> anyhow::Result<Self> {
|
pub fn parse(source: &str) -> anyhow::Result<Self> {
|
||||||
let mut control = false;
|
let mut control = false;
|
||||||
|
@ -135,16 +142,29 @@ impl std::fmt::Display for Keystroke {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// The state of the modifier keys at some point in time
|
||||||
#[derive(Copy, Clone, Debug, Eq, PartialEq, Default, Deserialize, Hash)]
|
#[derive(Copy, Clone, Debug, Eq, PartialEq, Default, Deserialize, Hash)]
|
||||||
pub struct Modifiers {
|
pub struct Modifiers {
|
||||||
|
/// The control key
|
||||||
pub control: bool,
|
pub control: bool,
|
||||||
|
|
||||||
|
/// The alt key
|
||||||
|
/// Sometimes also known as the 'meta' key
|
||||||
pub alt: bool,
|
pub alt: bool,
|
||||||
|
|
||||||
|
/// The shift key
|
||||||
pub shift: bool,
|
pub shift: bool,
|
||||||
|
|
||||||
|
/// The command key, on macos
|
||||||
|
/// the windows key, on windows
|
||||||
pub command: bool,
|
pub command: bool,
|
||||||
|
|
||||||
|
/// The function key
|
||||||
pub function: bool,
|
pub function: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Modifiers {
|
impl Modifiers {
|
||||||
|
/// Returns true if any modifier key is pressed
|
||||||
pub fn modified(&self) -> bool {
|
pub fn modified(&self) -> bool {
|
||||||
self.control || self.alt || self.shift || self.command || self.function
|
self.control || self.alt || self.shift || self.command || self.function
|
||||||
}
|
}
|
||||||
|
|
|
@ -21,13 +21,13 @@ use metal_renderer::*;
|
||||||
use objc::runtime::{BOOL, NO, YES};
|
use objc::runtime::{BOOL, NO, YES};
|
||||||
use std::ops::Range;
|
use std::ops::Range;
|
||||||
|
|
||||||
pub use dispatcher::*;
|
pub(crate) use dispatcher::*;
|
||||||
pub use display::*;
|
pub(crate) use display::*;
|
||||||
pub use display_linker::*;
|
pub(crate) use display_linker::*;
|
||||||
pub use metal_atlas::*;
|
pub(crate) use metal_atlas::*;
|
||||||
pub use platform::*;
|
pub(crate) use platform::*;
|
||||||
pub use text_system::*;
|
pub(crate) use text_system::*;
|
||||||
pub use window::*;
|
pub(crate) use window::*;
|
||||||
|
|
||||||
trait BoolExt {
|
trait BoolExt {
|
||||||
fn to_objc(self) -> BOOL;
|
fn to_objc(self) -> BOOL;
|
||||||
|
|
|
@ -24,7 +24,7 @@ pub(crate) fn dispatch_get_main_queue() -> dispatch_queue_t {
|
||||||
unsafe { &_dispatch_main_q as *const _ as dispatch_queue_t }
|
unsafe { &_dispatch_main_q as *const _ as dispatch_queue_t }
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct MacDispatcher {
|
pub(crate) struct MacDispatcher {
|
||||||
parker: Arc<Mutex<Parker>>,
|
parker: Arc<Mutex<Parker>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -11,7 +11,7 @@ use objc::{msg_send, sel, sel_impl};
|
||||||
use uuid::Uuid;
|
use uuid::Uuid;
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub struct MacDisplay(pub(crate) CGDirectDisplayID);
|
pub(crate) struct MacDisplay(pub(crate) CGDirectDisplayID);
|
||||||
|
|
||||||
unsafe impl Send for MacDisplay {}
|
unsafe impl Send for MacDisplay {}
|
||||||
|
|
||||||
|
@ -21,11 +21,6 @@ impl MacDisplay {
|
||||||
Self::all().find(|screen| screen.id() == id)
|
Self::all().find(|screen| screen.id() == id)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Get the screen with the given persistent [`Uuid`].
|
|
||||||
pub fn find_by_uuid(uuid: Uuid) -> Option<Self> {
|
|
||||||
Self::all().find(|screen| screen.uuid().ok() == Some(uuid))
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Get the primary screen - the one with the menu bar, and whose bottom left
|
/// Get the primary screen - the one with the menu bar, and whose bottom left
|
||||||
/// corner is at the origin of the AppKit coordinate system.
|
/// corner is at the origin of the AppKit coordinate system.
|
||||||
pub fn primary() -> Self {
|
pub fn primary() -> Self {
|
||||||
|
|
|
@ -7,8 +7,6 @@ use std::{
|
||||||
use crate::DisplayId;
|
use crate::DisplayId;
|
||||||
use collections::HashMap;
|
use collections::HashMap;
|
||||||
use parking_lot::Mutex;
|
use parking_lot::Mutex;
|
||||||
pub use sys::CVSMPTETime as SmtpeTime;
|
|
||||||
pub use sys::CVTimeStamp as VideoTimestamp;
|
|
||||||
|
|
||||||
pub(crate) struct MacDisplayLinker {
|
pub(crate) struct MacDisplayLinker {
|
||||||
links: HashMap<DisplayId, MacDisplayLink>,
|
links: HashMap<DisplayId, MacDisplayLink>,
|
||||||
|
@ -27,13 +25,13 @@ impl MacDisplayLinker {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
type OutputCallback = Mutex<Box<dyn FnMut(&VideoTimestamp, &VideoTimestamp) + Send>>;
|
type OutputCallback = Mutex<Box<dyn FnMut() + Send>>;
|
||||||
|
|
||||||
impl MacDisplayLinker {
|
impl MacDisplayLinker {
|
||||||
pub fn set_output_callback(
|
pub fn set_output_callback(
|
||||||
&mut self,
|
&mut self,
|
||||||
display_id: DisplayId,
|
display_id: DisplayId,
|
||||||
output_callback: Box<dyn FnMut(&VideoTimestamp, &VideoTimestamp) + Send>,
|
output_callback: Box<dyn FnMut() + Send>,
|
||||||
) {
|
) {
|
||||||
if let Some(mut system_link) = unsafe { sys::DisplayLink::on_display(display_id.0) } {
|
if let Some(mut system_link) = unsafe { sys::DisplayLink::on_display(display_id.0) } {
|
||||||
let callback = Arc::new(Mutex::new(output_callback));
|
let callback = Arc::new(Mutex::new(output_callback));
|
||||||
|
@ -81,11 +79,11 @@ unsafe extern "C" fn trampoline(
|
||||||
_flags_out: *mut i64,
|
_flags_out: *mut i64,
|
||||||
user_data: *mut c_void,
|
user_data: *mut c_void,
|
||||||
) -> i32 {
|
) -> i32 {
|
||||||
if let Some((current_time, output_time)) = current_time.as_ref().zip(output_time.as_ref()) {
|
if let Some((_current_time, _output_time)) = current_time.as_ref().zip(output_time.as_ref()) {
|
||||||
let output_callback: Weak<OutputCallback> =
|
let output_callback: Weak<OutputCallback> =
|
||||||
Weak::from_raw(user_data as *mut OutputCallback);
|
Weak::from_raw(user_data as *mut OutputCallback);
|
||||||
if let Some(output_callback) = output_callback.upgrade() {
|
if let Some(output_callback) = output_callback.upgrade() {
|
||||||
(output_callback.lock())(current_time, output_time)
|
(output_callback.lock())()
|
||||||
}
|
}
|
||||||
mem::forget(output_callback);
|
mem::forget(output_callback);
|
||||||
}
|
}
|
||||||
|
@ -126,7 +124,7 @@ mod sys {
|
||||||
|
|
||||||
#[repr(C)]
|
#[repr(C)]
|
||||||
#[derive(Clone, Copy)]
|
#[derive(Clone, Copy)]
|
||||||
pub struct CVTimeStamp {
|
pub(crate) struct CVTimeStamp {
|
||||||
pub version: u32,
|
pub version: u32,
|
||||||
pub video_time_scale: i32,
|
pub video_time_scale: i32,
|
||||||
pub video_time: i64,
|
pub video_time: i64,
|
||||||
|
@ -154,7 +152,7 @@ mod sys {
|
||||||
|
|
||||||
#[repr(C)]
|
#[repr(C)]
|
||||||
#[derive(Clone, Copy, Default)]
|
#[derive(Clone, Copy, Default)]
|
||||||
pub struct CVSMPTETime {
|
pub(crate) struct CVSMPTETime {
|
||||||
pub subframes: i16,
|
pub subframes: i16,
|
||||||
pub subframe_divisor: i16,
|
pub subframe_divisor: i16,
|
||||||
pub counter: u32,
|
pub counter: u32,
|
||||||
|
|
|
@ -83,7 +83,10 @@ unsafe fn read_modifiers(native_event: id) -> Modifiers {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl PlatformInput {
|
impl PlatformInput {
|
||||||
pub unsafe fn from_native(native_event: id, window_height: Option<Pixels>) -> Option<Self> {
|
pub(crate) unsafe fn from_native(
|
||||||
|
native_event: id,
|
||||||
|
window_height: Option<Pixels>,
|
||||||
|
) -> Option<Self> {
|
||||||
let event_type = native_event.eventType();
|
let event_type = native_event.eventType();
|
||||||
|
|
||||||
// Filter out event types that aren't in the NSEventType enum.
|
// Filter out event types that aren't in the NSEventType enum.
|
||||||
|
|
|
@ -10,10 +10,10 @@ use metal::Device;
|
||||||
use parking_lot::Mutex;
|
use parking_lot::Mutex;
|
||||||
use std::borrow::Cow;
|
use std::borrow::Cow;
|
||||||
|
|
||||||
pub struct MetalAtlas(Mutex<MetalAtlasState>);
|
pub(crate) struct MetalAtlas(Mutex<MetalAtlasState>);
|
||||||
|
|
||||||
impl MetalAtlas {
|
impl MetalAtlas {
|
||||||
pub fn new(device: Device) -> Self {
|
pub(crate) fn new(device: Device) -> Self {
|
||||||
MetalAtlas(Mutex::new(MetalAtlasState {
|
MetalAtlas(Mutex::new(MetalAtlasState {
|
||||||
device: AssertSend(device),
|
device: AssertSend(device),
|
||||||
monochrome_textures: Default::default(),
|
monochrome_textures: Default::default(),
|
||||||
|
|
|
@ -3,7 +3,7 @@ use crate::{
|
||||||
Action, AnyWindowHandle, BackgroundExecutor, ClipboardItem, CursorStyle, DisplayId,
|
Action, AnyWindowHandle, BackgroundExecutor, ClipboardItem, CursorStyle, DisplayId,
|
||||||
ForegroundExecutor, Keymap, MacDispatcher, MacDisplay, MacDisplayLinker, MacTextSystem,
|
ForegroundExecutor, Keymap, MacDispatcher, MacDisplay, MacDisplayLinker, MacTextSystem,
|
||||||
MacWindow, Menu, MenuItem, PathPromptOptions, Platform, PlatformDisplay, PlatformInput,
|
MacWindow, Menu, MenuItem, PathPromptOptions, Platform, PlatformDisplay, PlatformInput,
|
||||||
PlatformTextSystem, PlatformWindow, Result, SemanticVersion, VideoTimestamp, WindowOptions,
|
PlatformTextSystem, PlatformWindow, Result, SemanticVersion, WindowOptions,
|
||||||
};
|
};
|
||||||
use anyhow::anyhow;
|
use anyhow::anyhow;
|
||||||
use block::ConcreteBlock;
|
use block::ConcreteBlock;
|
||||||
|
@ -139,9 +139,9 @@ unsafe fn build_classes() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct MacPlatform(Mutex<MacPlatformState>);
|
pub(crate) struct MacPlatform(Mutex<MacPlatformState>);
|
||||||
|
|
||||||
pub struct MacPlatformState {
|
pub(crate) struct MacPlatformState {
|
||||||
background_executor: BackgroundExecutor,
|
background_executor: BackgroundExecutor,
|
||||||
foreground_executor: ForegroundExecutor,
|
foreground_executor: ForegroundExecutor,
|
||||||
text_system: Arc<MacTextSystem>,
|
text_system: Arc<MacTextSystem>,
|
||||||
|
@ -169,7 +169,7 @@ impl Default for MacPlatform {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl MacPlatform {
|
impl MacPlatform {
|
||||||
pub fn new() -> Self {
|
pub(crate) fn new() -> Self {
|
||||||
let dispatcher = Arc::new(MacDispatcher::new());
|
let dispatcher = Arc::new(MacDispatcher::new());
|
||||||
Self(Mutex::new(MacPlatformState {
|
Self(Mutex::new(MacPlatformState {
|
||||||
background_executor: BackgroundExecutor::new(dispatcher.clone()),
|
background_executor: BackgroundExecutor::new(dispatcher.clone()),
|
||||||
|
@ -475,10 +475,6 @@ impl Platform for MacPlatform {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// fn add_status_item(&self, _handle: AnyWindowHandle) -> Box<dyn platform::Window> {
|
|
||||||
// Box::new(StatusItem::add(self.fonts()))
|
|
||||||
// }
|
|
||||||
|
|
||||||
fn displays(&self) -> Vec<Rc<dyn PlatformDisplay>> {
|
fn displays(&self) -> Vec<Rc<dyn PlatformDisplay>> {
|
||||||
MacDisplay::all()
|
MacDisplay::all()
|
||||||
.map(|screen| Rc::new(screen) as Rc<_>)
|
.map(|screen| Rc::new(screen) as Rc<_>)
|
||||||
|
@ -504,7 +500,7 @@ impl Platform for MacPlatform {
|
||||||
fn set_display_link_output_callback(
|
fn set_display_link_output_callback(
|
||||||
&self,
|
&self,
|
||||||
display_id: DisplayId,
|
display_id: DisplayId,
|
||||||
callback: Box<dyn FnMut(&VideoTimestamp, &VideoTimestamp) + Send>,
|
callback: Box<dyn FnMut() + Send>,
|
||||||
) {
|
) {
|
||||||
self.0
|
self.0
|
||||||
.lock()
|
.lock()
|
||||||
|
|
|
@ -41,7 +41,7 @@ use super::open_type;
|
||||||
#[allow(non_upper_case_globals)]
|
#[allow(non_upper_case_globals)]
|
||||||
const kCGImageAlphaOnly: u32 = 7;
|
const kCGImageAlphaOnly: u32 = 7;
|
||||||
|
|
||||||
pub struct MacTextSystem(RwLock<MacTextSystemState>);
|
pub(crate) struct MacTextSystem(RwLock<MacTextSystemState>);
|
||||||
|
|
||||||
struct MacTextSystemState {
|
struct MacTextSystemState {
|
||||||
memory_source: MemSource,
|
memory_source: MemSource,
|
||||||
|
@ -54,7 +54,7 @@ struct MacTextSystemState {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl MacTextSystem {
|
impl MacTextSystem {
|
||||||
pub fn new() -> Self {
|
pub(crate) fn new() -> Self {
|
||||||
Self(RwLock::new(MacTextSystemState {
|
Self(RwLock::new(MacTextSystemState {
|
||||||
memory_source: MemSource::empty(),
|
memory_source: MemSource::empty(),
|
||||||
system_source: SystemSource::new(),
|
system_source: SystemSource::new(),
|
||||||
|
|
|
@ -220,7 +220,7 @@ unsafe fn build_classes() {
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn convert_mouse_position(position: NSPoint, window_height: Pixels) -> Point<Pixels> {
|
pub(crate) fn convert_mouse_position(position: NSPoint, window_height: Pixels) -> Point<Pixels> {
|
||||||
point(
|
point(
|
||||||
px(position.x as f32),
|
px(position.x as f32),
|
||||||
// MacOS screen coordinates are relative to bottom left
|
// MacOS screen coordinates are relative to bottom left
|
||||||
|
@ -446,7 +446,7 @@ impl MacWindowState {
|
||||||
|
|
||||||
unsafe impl Send for MacWindowState {}
|
unsafe impl Send for MacWindowState {}
|
||||||
|
|
||||||
pub struct MacWindow(Arc<Mutex<MacWindowState>>);
|
pub(crate) struct MacWindow(Arc<Mutex<MacWindowState>>);
|
||||||
|
|
||||||
impl MacWindow {
|
impl MacWindow {
|
||||||
pub fn open(
|
pub fn open(
|
||||||
|
|
|
@ -8,7 +8,7 @@ use objc::{msg_send, sel, sel_impl};
|
||||||
use std::ffi::CStr;
|
use std::ffi::CStr;
|
||||||
|
|
||||||
impl WindowAppearance {
|
impl WindowAppearance {
|
||||||
pub unsafe fn from_native(appearance: id) -> Self {
|
pub(crate) unsafe fn from_native(appearance: id) -> Self {
|
||||||
let name: id = msg_send![appearance, name];
|
let name: id = msg_send![appearance, name];
|
||||||
if name == NSAppearanceNameVibrantLight {
|
if name == NSAppearanceNameVibrantLight {
|
||||||
Self::VibrantLight
|
Self::VibrantLight
|
||||||
|
|
|
@ -1,11 +1,11 @@
|
||||||
use crate::{
|
use crate::{
|
||||||
self as gpui, hsla, point, px, relative, rems, AbsoluteLength, AlignItems, CursorStyle,
|
self as gpui, hsla, point, px, relative, rems, AbsoluteLength, AlignItems, CursorStyle,
|
||||||
DefiniteLength, Display, Fill, FlexDirection, FontWeight, Hsla, JustifyContent, Length,
|
DefiniteLength, Fill, FlexDirection, FontWeight, Hsla, JustifyContent, Length, Position,
|
||||||
Position, SharedString, StyleRefinement, Visibility, WhiteSpace,
|
SharedString, StyleRefinement, Visibility, WhiteSpace,
|
||||||
};
|
};
|
||||||
use crate::{BoxShadow, TextStyleRefinement};
|
use crate::{BoxShadow, TextStyleRefinement};
|
||||||
use smallvec::{smallvec, SmallVec};
|
use smallvec::{smallvec, SmallVec};
|
||||||
use taffy::style::Overflow;
|
use taffy::style::{Display, Overflow};
|
||||||
|
|
||||||
pub trait Styled: Sized {
|
pub trait Styled: Sized {
|
||||||
fn style(&mut self) -> &mut StyleRefinement;
|
fn style(&mut self) -> &mut StyleRefinement;
|
||||||
|
|
|
@ -737,7 +737,7 @@ impl<'a> WindowContext<'a> {
|
||||||
let (tx, mut rx) = mpsc::unbounded::<()>();
|
let (tx, mut rx) = mpsc::unbounded::<()>();
|
||||||
self.platform.set_display_link_output_callback(
|
self.platform.set_display_link_output_callback(
|
||||||
display_id,
|
display_id,
|
||||||
Box::new(move |_current_time, _output_time| _ = tx.unbounded_send(())),
|
Box::new(move || _ = tx.unbounded_send(())),
|
||||||
);
|
);
|
||||||
|
|
||||||
let consumer_task = self.app.spawn(|cx| async move {
|
let consumer_task = self.app.spawn(|cx| async move {
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue