Wed, 31 Dec 2014 06:55:50 +0100
Added tag UPSTREAM_283F7C6 for changeset ca08bd8f51b2
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 */
28 #import "ComplexTextInputPanel.h"
30 #include <algorithm>
31 #include "mozilla/Preferences.h"
32 #include "nsChildView.h"
33 #include "nsCocoaFeatures.h"
35 using namespace mozilla;
37 #define kInputWindowHeight 20
39 @implementation ComplexTextInputPanel
41 + (ComplexTextInputPanel*)sharedComplexTextInputPanel
42 {
43 static ComplexTextInputPanel *sComplexTextInputPanel;
44 if (!sComplexTextInputPanel)
45 sComplexTextInputPanel = [[ComplexTextInputPanel alloc] init];
46 return sComplexTextInputPanel;
47 }
49 - (id)init
50 {
51 // In the original Apple code the style mask is given by a function which is not open source.
52 // What could possibly be worth hiding in that function, I do not know.
53 // Courtesy of gdb: stylemask: 011000011111, 0x61f
54 self = [super initWithContentRect:NSZeroRect styleMask:0x61f backing:NSBackingStoreBuffered defer:YES];
55 if (!self)
56 return nil;
58 // Set the frame size.
59 NSRect visibleFrame = [[NSScreen mainScreen] visibleFrame];
60 NSRect frame = NSMakeRect(visibleFrame.origin.x, visibleFrame.origin.y, visibleFrame.size.width, kInputWindowHeight);
62 [self setFrame:frame display:NO];
64 mInputTextView = [[NSTextView alloc] initWithFrame:[self.contentView frame]];
65 mInputTextView.autoresizingMask = NSViewWidthSizable | NSViewHeightSizable | NSViewMaxXMargin | NSViewMinXMargin | NSViewMaxYMargin | NSViewMinYMargin;
67 NSScrollView* scrollView = [[NSScrollView alloc] initWithFrame:[self.contentView frame]];
68 scrollView.documentView = mInputTextView;
69 self.contentView = scrollView;
70 [scrollView release];
72 [self setFloatingPanel:YES];
74 [[NSNotificationCenter defaultCenter] addObserver:self
75 selector:@selector(keyboardInputSourceChanged:)
76 name:NSTextInputContextKeyboardSelectionDidChangeNotification
77 object:nil];
79 return self;
80 }
82 - (void)dealloc
83 {
84 [[NSNotificationCenter defaultCenter] removeObserver:self];
86 [mInputTextView release];
88 [super dealloc];
89 }
91 - (void)keyboardInputSourceChanged:(NSNotification *)notification
92 {
93 static int8_t sDoCancel = -1;
94 if (!sDoCancel || ![self inComposition]) {
95 return;
96 }
97 if (sDoCancel < 0) {
98 bool cancelComposition = false;
99 static const char* kPrefName =
100 "ui.plugin.cancel_composition_at_input_source_changed";
101 nsresult rv = Preferences::GetBool(kPrefName, &cancelComposition);
102 NS_ENSURE_SUCCESS(rv, );
103 sDoCancel = cancelComposition ? 1 : 0;
104 }
105 if (sDoCancel) {
106 [self cancelComposition];
107 }
108 }
110 - (BOOL)interpretKeyEvent:(NSEvent*)event string:(NSString**)string
111 {
112 BOOL hadMarkedText = [mInputTextView hasMarkedText];
114 *string = nil;
116 if (![[mInputTextView inputContext] handleEvent:event])
117 return NO;
119 if ([mInputTextView hasMarkedText]) {
120 // Don't show the input method window for dead keys
121 if ([[event characters] length] > 0)
122 [self orderFront:nil];
124 return YES;
125 } else {
126 [self orderOut:nil];
128 NSString *text = [[mInputTextView textStorage] string];
129 if ([text length] > 0)
130 *string = [[text copy] autorelease];
131 }
133 [mInputTextView setString:@""];
134 return hadMarkedText;
135 }
137 - (NSTextInputContext*)inputContext
138 {
139 return [mInputTextView inputContext];
140 }
142 - (void)cancelComposition
143 {
144 [mInputTextView setString:@""];
145 [self orderOut:nil];
146 }
148 - (BOOL)inComposition
149 {
150 return [mInputTextView hasMarkedText];
151 }
153 - (void)adjustTo:(NSView*)view
154 {
155 NSRect viewRect = [view frame];
156 viewRect.origin.x = 0;
157 viewRect.origin.y = 0;
158 viewRect = [view convertRect:viewRect toView:nil];
159 if (nsCocoaFeatures::OnLionOrLater()) {
160 viewRect = [[view window] convertRectToScreen:viewRect];
161 } else {
162 viewRect.origin = [[view window] convertBaseToScreen:viewRect.origin];
163 }
164 NSRect selfRect = [self frame];
165 CGFloat minWidth = static_cast<CGFloat>(
166 Preferences::GetUint("ui.plugin.panel.min-width", 500));
167 NSRect rect = NSMakeRect(viewRect.origin.x,
168 viewRect.origin.y - selfRect.size.height,
169 std::max(viewRect.size.width, minWidth),
170 selfRect.size.height);
172 // Adjust to screen.
173 NSRect screenRect = [[NSScreen mainScreen] visibleFrame];
174 if (rect.origin.x < screenRect.origin.x) {
175 rect.origin.x = screenRect.origin.x;
176 }
177 if (rect.origin.y < screenRect.origin.y) {
178 rect.origin.y = screenRect.origin.y;
179 }
180 CGFloat xMostOfScreen = screenRect.origin.x + screenRect.size.width;
181 CGFloat yMostOfScreen = screenRect.origin.y + screenRect.size.height;
182 CGFloat xMost = rect.origin.x + rect.size.width;
183 CGFloat yMost = rect.origin.y + rect.size.height;
184 if (xMostOfScreen < xMost) {
185 rect.origin.x -= xMost - xMostOfScreen;
186 }
187 if (yMostOfScreen < yMost) {
188 rect.origin.y -= yMost - yMostOfScreen;
189 }
191 [self setFrame:rect display:[self isVisible]];
192 }
194 @end