1 /* 2 * Copyright (C) 2009 Apple Inc. All Rights Reserved. 3 * 4 * Redistribution and use in source and binary forms, with or without 5 * modification, are permitted provided that the following conditions 6 * are met: 7 * 1. Redistributions of source code must retain the above copyright 8 * notice, this list of conditions and the following disclaimer. 9 * 2. Redistributions in binary form must reproduce the above copyright 10 * notice, this list of conditions and the following disclaimer in the 11 * documentation and/or other materials provided with the distribution. 12 * 13 * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY 14 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 15 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 16 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR 17 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 18 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 19 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 20 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY 21 * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 22 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 23 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 24 * 25 * Modified by Josh Aas of Mozilla Corporation. 26 */ 27 28 #import "ComplexTextInputPanel.h" 29 30 #if MAC_OS_X_VERSION_MAX_ALLOWED <= MAC_OS_X_VERSION_10_5 31 @interface NSView (SnowLeopardMethods) 32 - (NSTextInputContext *)inputContext; 33 @end 34 35 // This is actually an NSTextInputContext method, but we can't declare 36 // that since the whole class is 10.6+. 37 @interface NSObject (SnowLeopardMethods) 38 - (BOOL)handleEvent:(NSEvent *)theEvent; 39 @end 40 41 static NSString* const NSTextInputContextKeyboardSelectionDidChangeNotification = 42 @"NSTextInputContextKeyboardSelectionDidChangeNotification"; 43 #endif 44 45 #define kInputWindowHeight 20 46 47 @implementation ComplexTextInputPanel 48 49 + (ComplexTextInputPanel*)sharedComplexTextInputPanel 50 { 51 static ComplexTextInputPanel *sComplexTextInputPanel; 52 if (!sComplexTextInputPanel) 53 sComplexTextInputPanel = [[ComplexTextInputPanel alloc] init]; 54 return sComplexTextInputPanel; 55 } 56 57 - (id)init 58 { 59 // In the original Apple code the style mask is given by a function which is not open source. 60 // What could possibly be worth hiding in that function, I do not know. 61 // Courtesy of gdb: stylemask: 011000011111, 0x61f 62 self = [super initWithContentRect:NSZeroRect styleMask:0x61f backing:NSBackingStoreBuffered defer:YES]; 63 if (!self) 64 return nil; 65 66 // Set the frame size. 67 NSRect visibleFrame = [[NSScreen mainScreen] visibleFrame]; 68 NSRect frame = NSMakeRect(visibleFrame.origin.x, visibleFrame.origin.y, visibleFrame.size.width, kInputWindowHeight); 69 70 [self setFrame:frame display:NO]; 71 72 mInputTextView = [[NSTextView alloc] initWithFrame:[self.contentView frame]]; 73 mInputTextView.autoresizingMask = NSViewWidthSizable | NSViewHeightSizable | NSViewMaxXMargin | NSViewMinXMargin | NSViewMaxYMargin | NSViewMinYMargin; 74 75 NSScrollView* scrollView = [[NSScrollView alloc] initWithFrame:[self.contentView frame]]; 76 scrollView.documentView = mInputTextView; 77 self.contentView = scrollView; 78 [scrollView release]; 79 80 [self setFloatingPanel:YES]; 81 82 [[NSNotificationCenter defaultCenter] addObserver:self 83 selector:@selector(keyboardInputSourceChanged:) 84 name:NSTextInputContextKeyboardSelectionDidChangeNotification 85 object:nil]; 86 87 return self; 88 } 89 90 - (void)dealloc 91 { 92 [[NSNotificationCenter defaultCenter] removeObserver:self]; 93 94 [mInputTextView release]; 95 96 [super dealloc]; 97 } 98 99 - (void)keyboardInputSourceChanged:(NSNotification *)notification 100 { 101 [self cancelComposition]; 102 } 103 104 - (BOOL)interpretKeyEvent:(NSEvent*)event string:(NSString**)string 105 { 106 BOOL hadMarkedText = [mInputTextView hasMarkedText]; 107 108 *string = nil; 109 110 if (![[mInputTextView inputContext] handleEvent:event]) 111 return NO; 112 113 if ([mInputTextView hasMarkedText]) { 114 // Don't show the input method window for dead keys 115 if ([[event characters] length] > 0) 116 [self orderFront:nil]; 117 118 return YES; 119 } else { 120 [self orderOut:nil]; 121 122 NSString *text = [[mInputTextView textStorage] string]; 123 if ([text length] > 0) 124 *string = [[text copy] autorelease]; 125 } 126 127 [mInputTextView setString:@""]; 128 return hadMarkedText; 129 } 130 131 - (NSTextInputContext*)inputContext 132 { 133 return [mInputTextView inputContext]; 134 } 135 136 - (void)cancelComposition 137 { 138 [mInputTextView setString:@""]; 139 [self orderOut:nil]; 140 } 141 142 - (BOOL)inComposition 143 { 144 return [mInputTextView hasMarkedText]; 145 } 146 147 @end 148