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
26#if USE(PLUGIN_HOST_PROCESS)
27
28#import "WebTextInputWindowController.h"
29
30#import <WebKitSystemInterface.h>
31
32@interface WebTextInputView : NSTextView {
33}
34@end
35
36@implementation WebTextInputView
37
38- (NSArray *)validAttributesForMarkedText
39{
40    // Let TSM know that a bottom input window would be created for marked text.
41    NSArray *regularAttributes = [super validAttributesForMarkedText];
42    NSMutableArray *floatingWindowAttributes = [NSMutableArray arrayWithArray:regularAttributes];
43    [floatingWindowAttributes addObject:@"__NSUsesFloatingInputWindow"];
44    return floatingWindowAttributes;
45}
46
47@end
48
49@interface WebTextInputPanel : NSPanel {
50    NSTextView *_inputTextView;
51}
52
53- (NSTextInputContext *)_inputContext;
54- (BOOL)_interpretKeyEvent:(NSEvent *)event string:(NSString **)string;
55
56@end
57
58#define inputWindowHeight 20
59
60@implementation WebTextInputPanel
61
62- (void)dealloc
63{
64    [[NSNotificationCenter defaultCenter] removeObserver:self];
65
66    [_inputTextView release];
67
68    [super dealloc];
69}
70
71- (id)init
72{
73    self = [super initWithContentRect:NSZeroRect styleMask:WKGetInputPanelWindowStyle() backing:NSBackingStoreBuffered defer:YES];
74    if (!self)
75        return nil;
76
77    // Set the frame size.
78    NSRect visibleFrame = [[NSScreen mainScreen] visibleFrame];
79    NSRect frame = NSMakeRect(visibleFrame.origin.x, visibleFrame.origin.y, visibleFrame.size.width, inputWindowHeight);
80
81    [self setFrame:frame display:NO];
82
83    _inputTextView = [[WebTextInputView alloc] initWithFrame:[self.contentView frame]];
84    _inputTextView.autoresizingMask = NSViewWidthSizable | NSViewHeightSizable | NSViewMaxXMargin | NSViewMinXMargin | NSViewMaxYMargin | NSViewMinYMargin;
85
86    NSScrollView* scrollView = [[NSScrollView alloc] initWithFrame:[self.contentView frame]];
87    scrollView.documentView = _inputTextView;
88    self.contentView = scrollView;
89    [scrollView release];
90
91    [self setFloatingPanel:YES];
92
93    [[NSNotificationCenter defaultCenter] addObserver:self
94                                             selector:@selector(_keyboardInputSourceChanged:)
95                                                 name:NSTextInputContextKeyboardSelectionDidChangeNotification
96                                               object:nil];
97
98    return self;
99}
100
101- (void)_keyboardInputSourceChanged:(NSNotification *)notification
102{
103    [_inputTextView setString:@""];
104    [self orderOut:nil];
105}
106
107- (BOOL)_interpretKeyEvent:(NSEvent *)event string:(NSString **)string
108{
109#pragma clang diagnostic push
110#pragma clang diagnostic ignored "-Wdeprecated-declarations"
111    BOOL hadMarkedText = [_inputTextView hasMarkedText];
112#pragma clang diagnostic pop
113
114    *string = nil;
115
116    // Let TSM know that a bottom input window would be created for marked text.
117    // FIXME: Can be removed once we can rely on __NSUsesFloatingInputWindow (or a better API) being available everywhere.
118    EventRef carbonEvent = (EventRef)[event eventRef];
119    if (carbonEvent) {
120        Boolean ignorePAH = true;
121        SetEventParameter(carbonEvent, 'iPAH', typeBoolean, sizeof(ignorePAH), &ignorePAH);
122    }
123
124    if (![[_inputTextView inputContext] handleEvent:event])
125        return NO;
126
127#pragma clang diagnostic push
128#pragma clang diagnostic ignored "-Wdeprecated-declarations"
129    if ([_inputTextView hasMarkedText]) {
130#pragma clang diagnostic pop
131        // Don't show the input method window for dead keys
132        if ([[event characters] length] > 0)
133            [self orderFront:nil];
134
135        return YES;
136    }
137
138    if (hadMarkedText) {
139        [self orderOut:nil];
140
141        NSString *text = [[_inputTextView textStorage] string];
142        if ([text length] > 0)
143            *string = [[text copy] autorelease];
144    }
145
146    [_inputTextView setString:@""];
147    return hadMarkedText;
148}
149
150- (NSTextInputContext *)_inputContext
151{
152    return [_inputTextView inputContext];
153}
154
155@end
156
157@implementation WebTextInputWindowController
158
159+ (WebTextInputWindowController *)sharedTextInputWindowController
160{
161    static WebTextInputWindowController *textInputWindowController;
162    if (!textInputWindowController)
163        textInputWindowController = [[WebTextInputWindowController alloc] init];
164
165    return textInputWindowController;
166}
167
168- (id)init
169{
170    self = [super init];
171    if (!self)
172        return nil;
173
174    _panel = [[WebTextInputPanel alloc] init];
175
176    return self;
177}
178
179- (NSTextInputContext *)inputContext
180{
181    return [_panel _inputContext];
182}
183
184- (BOOL)interpretKeyEvent:(NSEvent *)event string:(NSString **)string
185{
186    return [_panel _interpretKeyEvent:event string:string];
187}
188
189@end
190
191#endif // USE(PLUGIN_HOST_PROCESS)
192
193