macOS: Implement NSTextInputClient (#518)

Fixes #263
This commit is contained in:
Francesca Frangipane 2018-05-17 21:28:30 -04:00 committed by GitHub
parent 8440091a4e
commit dec728cfa2
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
15 changed files with 648 additions and 147 deletions

View file

@ -25,6 +25,8 @@ use std::sync::Weak;
use std::cell::{Cell, RefCell};
use super::events_loop::{EventsLoop, Shared};
use platform::platform::util;
use platform::platform::view::{new_view, set_ime_spot};
use window::MonitorId as RootMonitorId;
@ -56,15 +58,14 @@ impl DelegateState {
let curr_mask = self.window.styleMask();
if !curr_mask.contains(NSWindowStyleMask::NSTitledWindowMask) {
self.window
.setStyleMask_(NSWindowStyleMask::NSResizableWindowMask);
util::set_style_mask(*self.window, *self.view, NSWindowStyleMask::NSResizableWindowMask);
}
let is_zoomed: BOOL = msg_send![*self.window, isZoomed];
// Roll back temp styles
if !curr_mask.contains(NSWindowStyleMask::NSTitledWindowMask) {
self.window.setStyleMask_(curr_mask);
util::set_style_mask(*self.window, *self.view, curr_mask);
}
is_zoomed != 0
@ -79,7 +80,7 @@ impl DelegateState {
let save_style_opt = self.save_style_mask.take();
if let Some(save_style) = save_style_opt {
self.window.setStyleMask_(save_style);
util::set_style_mask(*self.window, *self.view, save_style);
}
win_attribs.maximized
@ -167,7 +168,7 @@ impl WindowDelegate {
unsafe fn emit_move_event(state: &mut DelegateState) {
let frame_rect = NSWindow::frame(*state.window);
let x = frame_rect.origin.x as _;
let y = Window2::bottom_left_to_top_left(frame_rect);
let y = util::bottom_left_to_top_left(frame_rect);
let moved = state.previous_position != Some((x, y));
if moved {
state.previous_position = Some((x, y));
@ -495,6 +496,7 @@ pub struct Window2 {
pub view: IdRef,
pub window: IdRef,
pub delegate: WindowDelegate,
pub input_context: IdRef,
}
unsafe impl Send for Window2 {}
@ -582,7 +584,7 @@ impl Window2 {
return Err(OsError(format!("Couldn't create NSWindow")));
},
};
let view = match Window2::create_view(*window) {
let view = match Window2::create_view(*window, Weak::clone(&shared)) {
Some(view) => view,
None => {
let _: () = unsafe { msg_send![autoreleasepool, drain] };
@ -590,6 +592,8 @@ impl Window2 {
},
};
let input_context = unsafe { util::create_input_context(*view) };
unsafe {
if win_attribs.transparent {
(*window as id).setOpaque_(NO);
@ -628,6 +632,7 @@ impl Window2 {
view: view,
window: window,
delegate: WindowDelegate::new(ds),
input_context,
};
// Set fullscreen mode after we setup everything
@ -681,13 +686,10 @@ impl Window2 {
static INIT: std::sync::Once = std::sync::ONCE_INIT;
INIT.call_once(|| unsafe {
extern fn on_key_down(_this: &Object, _sel: Sel, _id: id) {}
let window_superclass = Class::get("NSWindow").unwrap();
let mut decl = ClassDecl::new("WinitWindow", window_superclass).unwrap();
decl.add_method(sel!(canBecomeMainWindow), yes as extern fn(&Object, Sel) -> BOOL);
decl.add_method(sel!(canBecomeKeyWindow), yes as extern fn(&Object, Sel) -> BOOL);
decl.add_method(sel!(keyDown:), on_key_down as extern fn(&Object, Sel, id));
WINDOW2_CLASS = decl.register();
});
@ -788,12 +790,13 @@ impl Window2 {
}
}
fn create_view(window: id) -> Option<IdRef> {
fn create_view(window: id, shared: Weak<Shared>) -> Option<IdRef> {
unsafe {
let view = IdRef::new(NSView::init(NSView::alloc(nil)));
let view = new_view(window, shared);
view.non_nil().map(|view| {
view.setWantsBestResolutionOpenGLSurface_(YES);
window.setContentView_(*view);
window.makeFirstResponder_(*view);
view
})
}
@ -816,18 +819,11 @@ impl Window2 {
unsafe { NSWindow::orderOut_(*self.window, nil); }
}
// For consistency with other platforms, this will...
// 1. translate the bottom-left window corner into the top-left window corner
// 2. translate the coordinate from a bottom-left origin coordinate system to a top-left one
fn bottom_left_to_top_left(rect: NSRect) -> i32 {
(CGDisplay::main().pixels_high() as f64 - (rect.origin.y + rect.size.height)) as _
}
pub fn get_position(&self) -> Option<(i32, i32)> {
let frame_rect = unsafe { NSWindow::frame(*self.window) };
Some((
frame_rect.origin.x as i32,
Self::bottom_left_to_top_left(frame_rect),
util::bottom_left_to_top_left(frame_rect),
))
}
@ -840,7 +836,7 @@ impl Window2 {
};
Some((
content_rect.origin.x as i32,
Self::bottom_left_to_top_left(content_rect),
util::bottom_left_to_top_left(content_rect),
))
}
@ -1029,10 +1025,9 @@ impl Window2 {
let curr_mask = state.window.styleMask();
if !curr_mask.contains(NSWindowStyleMask::NSTitledWindowMask) {
state.window.setStyleMask_(
NSWindowStyleMask::NSTitledWindowMask
| NSWindowStyleMask::NSResizableWindowMask,
);
let mask = NSWindowStyleMask::NSTitledWindowMask
| NSWindowStyleMask::NSResizableWindowMask;
util::set_style_mask(*self.window, *self.view, mask);
state.save_style_mask.set(Some(curr_mask));
}
}
@ -1067,21 +1062,26 @@ impl Window2 {
} else {
NSWindowStyleMask::NSBorderlessWindowMask
};
state.window.setStyleMask_(new_mask);
util::set_style_mask(*state.window, *state.view, new_mask);
}
}
#[inline]
pub fn set_window_icon(&self, _icon: Option<::Icon>) {
// macOS doesn't have window icons. Though, there is `setRepresentedFilename`, but that's
// semantically distinct and should only be used when the window is in some representing a
// specific file/directory. For instance, Terminal.app uses this for the CWD. Anyway, that
// should eventually be implemented as `WindowBuilderExt::with_represented_file` or
// something, and doesn't have anything to do with this.
// semantically distinct and should only be used when the window is in some way
// representing a specific file/directory. For instance, Terminal.app uses this for the
// CWD. Anyway, that should eventually be implemented as
// `WindowBuilderExt::with_represented_file` or something, and doesn't have anything to do
// with `set_window_icon`.
// https://developer.apple.com/library/content/documentation/Cocoa/Conceptual/WinPanel/Tasks/SettingWindowTitle.html
}
#[inline]
pub fn set_ime_spot(&self, x: i32, y: i32) {
set_ime_spot(*self.view, *self.input_context, x, y);
}
#[inline]
pub fn get_current_monitor(&self) -> RootMonitorId {
unsafe {
@ -1169,8 +1169,7 @@ impl Drop for IdRef {
fn drop(&mut self) {
if self.0 != nil {
unsafe {
let autoreleasepool =
NSAutoreleasePool::new(nil);
let autoreleasepool = NSAutoreleasePool::new(nil);
let _ : () = msg_send![self.0, release];
let _ : () = msg_send![autoreleasepool, release];
};