1/****************************************************************************
2**
3** Copyright (C) 2016 The Qt Company Ltd.
4** Contact: https://www.qt.io/licensing/
5**
6** This file is part of the plugins of the Qt Toolkit.
7**
8** $QT_BEGIN_LICENSE:LGPL$
9** Commercial License Usage
10** Licensees holding valid commercial Qt licenses may use this file in
11** accordance with the commercial license agreement provided with the
12** Software or, alternatively, in accordance with the terms contained in
13** a written agreement between you and The Qt Company. For licensing terms
14** and conditions see https://www.qt.io/terms-conditions. For further
15** information use the contact form at https://www.qt.io/contact-us.
16**
17** GNU Lesser General Public License Usage
18** Alternatively, this file may be used under the terms of the GNU Lesser
19** General Public License version 3 as published by the Free Software
20** Foundation and appearing in the file LICENSE.LGPL3 included in the
21** packaging of this file. Please review the following information to
22** ensure the GNU Lesser General Public License version 3 requirements
23** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
24**
25** GNU General Public License Usage
26** Alternatively, this file may be used under the terms of the GNU
27** General Public License version 2.0 or (at your option) the GNU General
28** Public license version 3 or any later version approved by the KDE Free
29** Qt Foundation. The licenses are as published by the Free Software
30** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
31** included in the packaging of this file. Please review the following
32** information to ensure the GNU General Public License requirements will
33** be met: https://www.gnu.org/licenses/gpl-2.0.html and
34** https://www.gnu.org/licenses/gpl-3.0.html.
35**
36** $QT_END_LICENSE$
37**
38****************************************************************************/
39
40#include "qnsview.h"
41#include "qcocoainputcontext.h"
42#include "qcocoanativeinterface.h"
43#include "qcocoawindow.h"
44#include "qcocoahelpers.h"
45
46#include <Carbon/Carbon.h>
47
48#include <QtCore/QRect>
49#include <QtGui/QGuiApplication>
50#include <QtGui/QWindow>
51
52QT_BEGIN_NAMESPACE
53
54/*!
55    \class QCocoaInputContext
56    \brief Cocoa Input context implementation
57
58    Handles input of foreign characters (particularly East Asian)
59    languages.
60
61    \section1 Testing
62
63    \list
64    \o Select input sources like 'Kotoeri' in Language & Text Preferences
65    \o Compile the \a mainwindows/mdi example and open a text window.
66    \o In the language bar, switch to 'Hiragana'.
67    \o In a text editor control, type the syllable \a 'la'.
68       Underlined characters show up, indicating that there is completion
69       available. Press the Space key two times. A completion popup occurs
70       which shows the options.
71    \endlist
72
73    \section1 Interaction
74
75    Input method support in Cocoa uses NSTextInput protorol. Therefore
76    almost all functionality is implemented in QNSView.
77*/
78
79
80
81QCocoaInputContext::QCocoaInputContext()
82    : QPlatformInputContext()
83    , mWindow(QGuiApplication::focusWindow())
84{
85    QMetaObject::invokeMethod(this, "connectSignals", Qt::QueuedConnection);
86    updateLocale();
87}
88
89QCocoaInputContext::~QCocoaInputContext()
90{
91}
92
93/*!
94    \brief Cancels a composition.
95*/
96
97void QCocoaInputContext::reset()
98{
99    QPlatformInputContext::reset();
100
101    if (!mWindow)
102        return;
103
104    QCocoaWindow *window = static_cast<QCocoaWindow *>(mWindow->handle());
105    QNSView *view = qnsview_cast(window->view());
106    if (!view)
107        return;
108
109    QMacAutoReleasePool pool;
110    if (NSTextInputContext *ctxt = [NSTextInputContext currentInputContext]) {
111        [ctxt discardMarkedText];
112        [view unmarkText];
113    }
114}
115
116void QCocoaInputContext::connectSignals()
117{
118    connect(qApp, SIGNAL(focusObjectChanged(QObject*)), this, SLOT(focusObjectChanged(QObject*)));
119    focusObjectChanged(qApp->focusObject());
120}
121
122void QCocoaInputContext::focusObjectChanged(QObject *focusObject)
123{
124    Q_UNUSED(focusObject);
125    if (mWindow == QGuiApplication::focusWindow()) {
126        if (!mWindow)
127            return;
128
129        QCocoaWindow *window = static_cast<QCocoaWindow *>(mWindow->handle());
130        if (!window)
131            return;
132        QNSView *view = qnsview_cast(window->view());
133        if (!view)
134            return;
135
136        if (NSTextInputContext *ctxt = [NSTextInputContext currentInputContext]) {
137            [ctxt discardMarkedText];
138            [view cancelComposingText];
139        }
140    } else {
141        mWindow = QGuiApplication::focusWindow();
142    }
143}
144
145void QCocoaInputContext::updateLocale()
146{
147    TISInputSourceRef source = TISCopyCurrentKeyboardInputSource();
148    CFArrayRef languages = (CFArrayRef) TISGetInputSourceProperty(source, kTISPropertyInputSourceLanguages);
149    if (CFArrayGetCount(languages) > 0) {
150        CFStringRef langRef = (CFStringRef)CFArrayGetValueAtIndex(languages, 0);
151        QString name = QString::fromCFString(langRef);
152        QLocale locale(name);
153        if (m_locale != locale) {
154            m_locale = locale;
155            emitLocaleChanged();
156        }
157    }
158    CFRelease(source);
159}
160
161QT_END_NAMESPACE
162