Bumping manifests a=b2g-bump
[gecko.git] / widget / cocoa / ComplexTextInputPanel.mm
blob2f932e4d10e3ba3594840f5815c653138bc3c4af
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
43   static ComplexTextInputPanel *sComplexTextInputPanel;
44   if (!sComplexTextInputPanel)
45     sComplexTextInputPanel = [[ComplexTextInputPanel alloc] init];
46   return sComplexTextInputPanel;
49 - (id)init
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;
82 - (void)dealloc
84   [[NSNotificationCenter defaultCenter] removeObserver:self];
85   
86   [mInputTextView release];
87   
88   [super dealloc];
91 - (void)keyboardInputSourceChanged:(NSNotification *)notification
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   }
110 - (BOOL)interpretKeyEvent:(NSEvent*)event string:(NSString**)string
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;
137 - (NSTextInputContext*)inputContext
139   return [mInputTextView inputContext];
142 - (void)cancelComposition
144   [mInputTextView setString:@""];
145   [self orderOut:nil];
148 - (BOOL)inComposition
150   return [mInputTextView hasMarkedText];
153 - (void)adjustTo:(NSView*)view
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]];
194 @end