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