Obj-C Refactor: WindowViewCocoa refactor
Changes: - Use macros to reduce Cocoa event forwarding boilerplate - Use @autoreleasepool where necessary - Use idiomatic Objective-C properties for `COCOA_VIEW_CLASS` Style Changes: - Use C-Style Comments - Use braces for conditional statements - Use Objective-C dot-notation Ref #126772 Pull Request: https://projects.blender.org/blender/blender/pulls/126769
This commit is contained in:
committed by
Sergey Sharybin
parent
fbfe407201
commit
73f2bdd1ed
@@ -370,16 +370,18 @@ GHOST_WindowCocoa::GHOST_WindowCocoa(GHOST_SystemCocoa *systemCocoa,
|
||||
CGColorSpaceRelease(colorspace);
|
||||
}
|
||||
|
||||
m_metalView = [[CocoaMetalView alloc] initWithFrame:rect];
|
||||
m_metalView = [[CocoaMetalView alloc] initWithSystemCocoa:systemCocoa
|
||||
windowCocoa:this
|
||||
frame:rect];
|
||||
m_metalView.wantsLayer = YES;
|
||||
m_metalView.layer = m_metalLayer;
|
||||
[m_metalView setSystemAndWindowCocoa:systemCocoa windowCocoa:this];
|
||||
view = m_metalView;
|
||||
}
|
||||
else {
|
||||
/* Fallback to OpenGL view if there is no Metal support. */
|
||||
m_openGLView = [[CocoaOpenGLView alloc] initWithFrame:rect];
|
||||
[m_openGLView setSystemAndWindowCocoa:systemCocoa windowCocoa:this];
|
||||
m_openGLView = [[CocoaOpenGLView alloc] initWithSystemCocoa:systemCocoa
|
||||
windowCocoa:this
|
||||
frame:rect];
|
||||
view = m_openGLView;
|
||||
}
|
||||
|
||||
|
||||
@@ -17,9 +17,6 @@
|
||||
// We need to subclass it in order to give Cocoa the feeling key events are trapped
|
||||
@interface COCOA_VIEW_CLASS : COCOA_VIEW_BASE_CLASS <NSTextInputClient>
|
||||
{
|
||||
GHOST_SystemCocoa *systemCocoa;
|
||||
GHOST_WindowCocoa *associatedWindow;
|
||||
|
||||
bool composing;
|
||||
NSString *composing_text;
|
||||
|
||||
@@ -36,42 +33,60 @@
|
||||
} ime;
|
||||
#endif
|
||||
}
|
||||
- (void)setSystemAndWindowCocoa:(GHOST_SystemCocoa *)sysCocoa
|
||||
windowCocoa:(GHOST_WindowCocoa *)winCocoa;
|
||||
|
||||
@property(nonatomic, readonly, assign) GHOST_SystemCocoa *systemCocoa;
|
||||
@property(nonatomic, readonly, assign) GHOST_WindowCocoa *windowCocoa;
|
||||
|
||||
- (instancetype)initWithSystemCocoa:(GHOST_SystemCocoa *)sysCocoa
|
||||
windowCocoa:(GHOST_WindowCocoa *)winCocoa
|
||||
frame:(NSRect)frameRect;
|
||||
|
||||
#ifdef WITH_INPUT_IME
|
||||
- (void)beginIME:(int32_t)x y:(int32_t)y w:(int32_t)w h:(int32_t)h completed:(bool)completed;
|
||||
|
||||
- (void)endIME;
|
||||
#endif
|
||||
|
||||
@end
|
||||
|
||||
@implementation COCOA_VIEW_CLASS
|
||||
|
||||
- (void)setSystemAndWindowCocoa:(GHOST_SystemCocoa *)sysCocoa
|
||||
windowCocoa:(GHOST_WindowCocoa *)winCocoa
|
||||
{
|
||||
systemCocoa = sysCocoa;
|
||||
associatedWindow = winCocoa;
|
||||
@synthesize systemCocoa = m_systemCocoa;
|
||||
@synthesize windowCocoa = m_windowCocoa;
|
||||
|
||||
composing = false;
|
||||
composing_text = nil;
|
||||
- (instancetype)initWithSystemCocoa:(GHOST_SystemCocoa *)sysCocoa
|
||||
windowCocoa:(GHOST_WindowCocoa *)winCocoa
|
||||
frame:(NSRect)frameRect
|
||||
{
|
||||
self = [super init];
|
||||
|
||||
if (self) {
|
||||
m_systemCocoa = sysCocoa;
|
||||
m_windowCocoa = winCocoa;
|
||||
|
||||
composing = false;
|
||||
composing_text = nil;
|
||||
|
||||
#ifdef WITH_INPUT_IME
|
||||
ime.state_flag = 0;
|
||||
ime.candidate_window_position = NSZeroRect;
|
||||
ime.event.cursor_position = -1;
|
||||
ime.event.target_start = -1;
|
||||
ime.event.target_end = -1;
|
||||
ime.state_flag = 0;
|
||||
ime.candidate_window_position = NSZeroRect;
|
||||
ime.event.cursor_position = -1;
|
||||
ime.event.target_start = -1;
|
||||
ime.event.target_end = -1;
|
||||
|
||||
/* Register a function to be executed when Input Method is changed using
|
||||
* 'Control + Space' or language-specific keys (such as 'Eisu / Kana' key for Japanese). */
|
||||
NSNotificationCenter *center = [NSNotificationCenter defaultCenter];
|
||||
[center addObserver:self
|
||||
selector:@selector(ImeDidChangeCallback:)
|
||||
name:NSTextInputContextKeyboardSelectionDidChangeNotification
|
||||
object:nil];
|
||||
/* Register a function to be executed when Input Method is changed using
|
||||
* 'Control + Space' or language-specific keys (such as 'Eisu / Kana' key for Japanese). */
|
||||
@autoreleasepool {
|
||||
NSNotificationCenter *center = [NSNotificationCenter defaultCenter];
|
||||
[center addObserver:self
|
||||
selector:@selector(ImeDidChangeCallback:)
|
||||
name:NSTextInputContextKeyboardSelectionDidChangeNotification
|
||||
object:nil];
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
return self;
|
||||
}
|
||||
|
||||
- (BOOL)acceptsFirstResponder
|
||||
@@ -95,7 +110,7 @@
|
||||
#endif
|
||||
|
||||
if (!ime_process) {
|
||||
systemCocoa->handleKeyEvent(event);
|
||||
m_systemCocoa->handleKeyEvent(event);
|
||||
}
|
||||
|
||||
/* Start or continue composing? */
|
||||
@@ -104,15 +119,17 @@
|
||||
{
|
||||
composing = YES;
|
||||
|
||||
// interpret event to call insertText
|
||||
[self interpretKeyEvents:[NSArray arrayWithObject:event]]; // calls insertText
|
||||
/* Interpret event to call insertText. */
|
||||
@autoreleasepool {
|
||||
[self interpretKeyEvents:[NSArray arrayWithObject:event]]; /* Calls insertText. */
|
||||
}
|
||||
|
||||
#ifdef WITH_INPUT_IME
|
||||
// For Korean input, control characters are also processed by handleKeyEvent.
|
||||
const int controlCharForKorean = (GHOST_IME_COMPOSITION_EVENT | GHOST_IME_RESULT_EVENT |
|
||||
GHOST_IME_KEY_CONTROL_CHAR);
|
||||
if (((ime.state_flag & controlCharForKorean) == controlCharForKorean)) {
|
||||
systemCocoa->handleKeyEvent(event);
|
||||
m_systemCocoa->handleKeyEvent(event);
|
||||
}
|
||||
|
||||
ime.state_flag &= ~(GHOST_IME_COMPOSITION_EVENT | GHOST_IME_RESULT_EVENT);
|
||||
@@ -124,95 +141,44 @@
|
||||
}
|
||||
}
|
||||
|
||||
- (void)keyUp:(NSEvent *)event
|
||||
{
|
||||
systemCocoa->handleKeyEvent(event);
|
||||
}
|
||||
#define HANDLE_KEY_EVENT(eventType) \
|
||||
-(void)eventType : (NSEvent *)event \
|
||||
{ \
|
||||
m_systemCocoa->handleKeyEvent(event); \
|
||||
}
|
||||
|
||||
- (void)flagsChanged:(NSEvent *)event
|
||||
{
|
||||
systemCocoa->handleKeyEvent(event);
|
||||
}
|
||||
#define HANDLE_MOUSE_EVENT(eventType) \
|
||||
-(void)eventType : (NSEvent *)event \
|
||||
{ \
|
||||
m_systemCocoa->handleMouseEvent(event); \
|
||||
}
|
||||
|
||||
- (void)mouseDown:(NSEvent *)event
|
||||
{
|
||||
systemCocoa->handleMouseEvent(event);
|
||||
}
|
||||
#define HANDLE_TABLET_EVENT(eventType) \
|
||||
-(void)eventType : (NSEvent *)event \
|
||||
{ \
|
||||
m_systemCocoa->handleMouseEvent(event); \
|
||||
}
|
||||
|
||||
- (void)mouseUp:(NSEvent *)event
|
||||
{
|
||||
systemCocoa->handleMouseEvent(event);
|
||||
}
|
||||
HANDLE_KEY_EVENT(keyUp)
|
||||
HANDLE_KEY_EVENT(flagsChanged)
|
||||
|
||||
- (void)rightMouseDown:(NSEvent *)event
|
||||
{
|
||||
systemCocoa->handleMouseEvent(event);
|
||||
}
|
||||
HANDLE_MOUSE_EVENT(mouseDown)
|
||||
HANDLE_MOUSE_EVENT(mouseUp)
|
||||
HANDLE_MOUSE_EVENT(rightMouseDown)
|
||||
HANDLE_MOUSE_EVENT(rightMouseUp)
|
||||
HANDLE_MOUSE_EVENT(mouseMoved)
|
||||
HANDLE_MOUSE_EVENT(mouseDragged)
|
||||
HANDLE_MOUSE_EVENT(rightMouseDragged)
|
||||
HANDLE_MOUSE_EVENT(scrollWheel)
|
||||
HANDLE_MOUSE_EVENT(otherMouseDown)
|
||||
HANDLE_MOUSE_EVENT(otherMouseUp)
|
||||
HANDLE_MOUSE_EVENT(otherMouseDragged)
|
||||
HANDLE_MOUSE_EVENT(magnifyWithEvent)
|
||||
HANDLE_MOUSE_EVENT(smartMagnifyWithEvent)
|
||||
HANDLE_MOUSE_EVENT(rotateWithEvent)
|
||||
|
||||
- (void)rightMouseUp:(NSEvent *)event
|
||||
{
|
||||
systemCocoa->handleMouseEvent(event);
|
||||
}
|
||||
|
||||
- (void)mouseMoved:(NSEvent *)event
|
||||
{
|
||||
systemCocoa->handleMouseEvent(event);
|
||||
}
|
||||
|
||||
- (void)mouseDragged:(NSEvent *)event
|
||||
{
|
||||
systemCocoa->handleMouseEvent(event);
|
||||
}
|
||||
|
||||
- (void)rightMouseDragged:(NSEvent *)event
|
||||
{
|
||||
systemCocoa->handleMouseEvent(event);
|
||||
}
|
||||
|
||||
- (void)scrollWheel:(NSEvent *)event
|
||||
{
|
||||
systemCocoa->handleMouseEvent(event);
|
||||
}
|
||||
|
||||
- (void)otherMouseDown:(NSEvent *)event
|
||||
{
|
||||
systemCocoa->handleMouseEvent(event);
|
||||
}
|
||||
|
||||
- (void)otherMouseUp:(NSEvent *)event
|
||||
{
|
||||
systemCocoa->handleMouseEvent(event);
|
||||
}
|
||||
|
||||
- (void)otherMouseDragged:(NSEvent *)event
|
||||
{
|
||||
systemCocoa->handleMouseEvent(event);
|
||||
}
|
||||
|
||||
- (void)magnifyWithEvent:(NSEvent *)event
|
||||
{
|
||||
systemCocoa->handleMouseEvent(event);
|
||||
}
|
||||
|
||||
- (void)smartMagnifyWithEvent:(NSEvent *)event
|
||||
{
|
||||
systemCocoa->handleMouseEvent(event);
|
||||
}
|
||||
|
||||
- (void)rotateWithEvent:(NSEvent *)event
|
||||
{
|
||||
systemCocoa->handleMouseEvent(event);
|
||||
}
|
||||
|
||||
- (void)tabletPoint:(NSEvent *)event
|
||||
{
|
||||
systemCocoa->handleTabletEvent(event, [event type]);
|
||||
}
|
||||
|
||||
- (void)tabletProximity:(NSEvent *)event
|
||||
{
|
||||
systemCocoa->handleTabletEvent(event, [event type]);
|
||||
}
|
||||
HANDLE_TABLET_EVENT(tabletPoint)
|
||||
HANDLE_TABLET_EVENT(tabletProximity)
|
||||
|
||||
- (BOOL)isOpaque
|
||||
{
|
||||
@@ -226,16 +192,17 @@
|
||||
}
|
||||
else {
|
||||
[super drawRect:rect];
|
||||
systemCocoa->handleWindowEvent(GHOST_kEventWindowUpdate, associatedWindow);
|
||||
m_systemCocoa->handleWindowEvent(GHOST_kEventWindowUpdate, m_windowCocoa);
|
||||
|
||||
/* For some cases like entering full-screen we need to redraw immediately
|
||||
* so our window does not show blank during the animation */
|
||||
if (associatedWindow->getImmediateDraw())
|
||||
systemCocoa->dispatchEvents();
|
||||
if (m_windowCocoa->getImmediateDraw()) {
|
||||
m_systemCocoa->dispatchEvents();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Text input
|
||||
/* Text input. */
|
||||
|
||||
- (void)composing_free
|
||||
{
|
||||
@@ -258,7 +225,7 @@
|
||||
[self processImeEvent:GHOST_kEventImeCompositionStart];
|
||||
}
|
||||
|
||||
// For Chinese and Korean input, insertText may be executed twice with a single keyDown.
|
||||
/* For Chinese and Korean input, insertText may be executed twice with a single keyDown. */
|
||||
if (ime.state_flag & GHOST_IME_RESULT_EVENT) {
|
||||
ime.combined_result += [self convertNSString:chars];
|
||||
}
|
||||
@@ -281,7 +248,7 @@
|
||||
#endif
|
||||
}
|
||||
|
||||
// Processes the Composition String sent from the Input Method.
|
||||
/* Processes the Composition String sent from the Input Method. */
|
||||
- (void)setMarkedText:(id)chars
|
||||
selectedRange:(NSRange)range
|
||||
replacementRange:(NSRange)replacementRange
|
||||
@@ -290,7 +257,7 @@
|
||||
|
||||
if ([chars length] == 0) {
|
||||
#ifdef WITH_INPUT_IME
|
||||
// Processes when the last Composition String is deleted.
|
||||
/* Processes when the last Composition String is deleted. */
|
||||
if (ime.state_flag & GHOST_IME_COMPOSING) {
|
||||
[self setImeResult:std::string()];
|
||||
[self processImeEvent:GHOST_kEventImeComposition];
|
||||
@@ -302,18 +269,19 @@
|
||||
return;
|
||||
}
|
||||
|
||||
// start composing
|
||||
/* Start composing. */
|
||||
composing = YES;
|
||||
composing_text = [chars copy];
|
||||
|
||||
// chars of markedText by Input Method is an instance of NSAttributedString
|
||||
/* Chars of markedText by Input Method is an instance of NSAttributedString */
|
||||
if ([chars isKindOfClass:[NSAttributedString class]]) {
|
||||
composing_text = [[chars string] copy];
|
||||
}
|
||||
|
||||
// if empty, cancel
|
||||
if ([composing_text length] == 0)
|
||||
/* If empty, cancel. */
|
||||
if ([composing_text length] == 0) {
|
||||
[self composing_free];
|
||||
}
|
||||
|
||||
#ifdef WITH_INPUT_IME
|
||||
if (ime.state_flag & GHOST_IME_ENABLED) {
|
||||
@@ -324,7 +292,7 @@
|
||||
|
||||
[self setImeComposition:composing_text selectedRange:range];
|
||||
|
||||
// For Korean input, setMarkedText may be executed twice with a single keyDown.
|
||||
/* For Korean input, setMarkedText may be executed twice with a single keyDown. */
|
||||
if (![self ime_did_composition]) {
|
||||
ime.state_flag |= GHOST_IME_COMPOSITION_EVENT;
|
||||
[self processImeEvent:GHOST_kEventImeComposition];
|
||||
@@ -362,8 +330,9 @@
|
||||
{
|
||||
unsigned int length = (composing_text) ? [composing_text length] : 0;
|
||||
|
||||
if (composing)
|
||||
if (composing) {
|
||||
return NSMakeRange(0, length);
|
||||
}
|
||||
|
||||
return NSMakeRange(NSNotFound, 0);
|
||||
}
|
||||
@@ -424,7 +393,7 @@
|
||||
- (void)setImeCandidateWinPos:(int32_t)x y:(int32_t)y w:(int32_t)w h:(int32_t)h
|
||||
{
|
||||
int32_t outX, outY;
|
||||
associatedWindow->clientToScreen(x, y, outX, outY);
|
||||
m_windowCocoa->clientToScreen(x, y, outX, outY);
|
||||
ime.candidate_window_position = NSMakeRect((CGFloat)outX, (CGFloat)outY, (CGFloat)w, (CGFloat)h);
|
||||
}
|
||||
|
||||
@@ -442,7 +411,9 @@
|
||||
ime.composite.clear();
|
||||
|
||||
[self unmarkText];
|
||||
[[NSTextInputContext currentInputContext] discardMarkedText];
|
||||
@autoreleasepool {
|
||||
[[NSTextInputContext currentInputContext] discardMarkedText];
|
||||
}
|
||||
}
|
||||
|
||||
- (void)processImeEvent:(GHOST_TEventType)imeEventType
|
||||
@@ -453,35 +424,38 @@
|
||||
ime.event.composite = (GHOST_TUserDataPtr)ime.composite.c_str();
|
||||
|
||||
GHOST_Event *event = new GHOST_EventIME(
|
||||
systemCocoa->getMilliSeconds(), imeEventType, associatedWindow, &ime.event);
|
||||
systemCocoa->pushEvent(event);
|
||||
m_systemCocoa->getMilliSeconds(), imeEventType, m_windowCocoa, &ime.event);
|
||||
m_systemCocoa->pushEvent(event);
|
||||
}
|
||||
|
||||
- (std::string)convertNSString:(NSString *)inString
|
||||
{
|
||||
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
|
||||
std::string str([inString UTF8String]);
|
||||
[pool drain];
|
||||
return str;
|
||||
@autoreleasepool {
|
||||
std::string str(inString.UTF8String);
|
||||
return str;
|
||||
}
|
||||
}
|
||||
|
||||
- (void)setImeComposition:(NSString *)inString selectedRange:(NSRange)range
|
||||
{
|
||||
ime.composite = [self convertNSString:inString];
|
||||
|
||||
// For Korean input, both "Result Event" and "Composition Event" can occur in a single keyDown.
|
||||
/* For Korean input, both "Result Event" and "Composition Event" can occur in a single keyDown.
|
||||
*/
|
||||
if (!(ime.state_flag & GHOST_IME_RESULT_EVENT)) {
|
||||
ime.result.clear();
|
||||
}
|
||||
|
||||
/* The target string is equivalent to the string in selectedRange of setMarkedText.
|
||||
* The cursor is displayed at the beginning of the target string. */
|
||||
char *front_string = (char *)[[inString substringWithRange:NSMakeRange(0, range.location)]
|
||||
UTF8String];
|
||||
char *selected_string = (char *)[[inString substringWithRange:range] UTF8String];
|
||||
ime.event.cursor_position = strlen(front_string);
|
||||
ime.event.target_start = ime.event.cursor_position;
|
||||
ime.event.target_end = ime.event.target_start + strlen(selected_string);
|
||||
@autoreleasepool {
|
||||
char *front_string = (char *)[[inString substringWithRange:NSMakeRange(0, range.location)]
|
||||
UTF8String];
|
||||
char *selected_string = (char *)[[inString substringWithRange:range] UTF8String];
|
||||
ime.event.cursor_position = strlen(front_string);
|
||||
ime.event.target_start = ime.event.cursor_position;
|
||||
ime.event.target_end = ime.event.target_start + strlen(selected_string);
|
||||
}
|
||||
}
|
||||
|
||||
- (void)setImeResult:(std::string)result
|
||||
@@ -498,13 +472,13 @@
|
||||
ime.state_flag &= ~GHOST_IME_KEY_CONTROL_CHAR;
|
||||
|
||||
/* Don't use IME for command and ctrl key combinations, these are shortcuts. */
|
||||
if ([event modifierFlags] & (NSEventModifierFlagCommand | NSEventModifierFlagControl)) {
|
||||
if (event.modifierFlags & (NSEventModifierFlagCommand | NSEventModifierFlagControl)) {
|
||||
ime.state_flag |= GHOST_IME_KEY_CONTROL_CHAR;
|
||||
return;
|
||||
}
|
||||
|
||||
/* Don't use IME for these control keys. */
|
||||
switch ([event keyCode]) {
|
||||
switch (event.keyCode) {
|
||||
case kVK_ANSI_KeypadEnter:
|
||||
case kVK_ANSI_KeypadClear:
|
||||
case kVK_F1:
|
||||
|
||||
Reference in New Issue
Block a user