1// Copyright (C) 2016 The Qt Company Ltd.
2// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
3
4#include <QtVirtualKeyboard/private/qvirtualkeyboard_global_p.h>
5#include <QtVirtualKeyboard/private/desktopinputpanel_p.h>
6#include <QtVirtualKeyboard/private/appinputpanel_p_p.h>
7#include <QtVirtualKeyboard/private/inputview_p.h>
8#include <QtVirtualKeyboard/private/platforminputcontext_p.h>
9#include <QtVirtualKeyboard/private/qvirtualkeyboardinputcontext_p.h>
10#include <QtVirtualKeyboard/qvirtualkeyboardinputcontext.h>
11#include <QGuiApplication>
12#include <QQmlEngine>
13#include <QScreen>
14#include <QtVirtualKeyboard/private/virtualkeyboarddebug_p.h>
15#include <qpa/qplatformnativeinterface.h>
16#include <QtCore/private/qobject_p.h>
17#include <QtCore/QLibraryInfo>
18
19QT_BEGIN_NAMESPACE
20namespace QtVirtualKeyboard {
21
22class DesktopInputPanelPrivate : public AppInputPanelPrivate
23{
24public:
25 enum WindowingSystem {
26 Windows,
27 Xcb,
28 Other,
29 };
30
31 DesktopInputPanelPrivate() :
32 AppInputPanelPrivate(),
33 view(),
34 keyboardRect(),
35 previewRect(),
36 previewVisible(false),
37 previewBindingActive(false),
38 windowingSystem(Other)
39 {
40 const QString platformName = QGuiApplication::platformName();
41 if (platformName == QLatin1String("windows"))
42 windowingSystem = Windows;
43 else if (platformName == QLatin1String("xcb"))
44 windowingSystem = Xcb;
45 }
46
47 QScopedPointer<InputView> view;
48 QRectF keyboardRect;
49 QRectF previewRect;
50 bool previewVisible;
51 bool previewBindingActive;
52 WindowingSystem windowingSystem;
53};
54
55/*!
56 \class QtVirtualKeyboard::DesktopInputPanel
57 \internal
58*/
59
60DesktopInputPanel::DesktopInputPanel(QObject *parent) :
61 AppInputPanel(*new DesktopInputPanelPrivate(), parent)
62{
63 /* Activate the alpha buffer for this application.
64 */
65 QQuickWindow::setDefaultAlphaBuffer(true);
66 QScreen *screen = QGuiApplication::primaryScreen();
67 connect(asender: screen, SIGNAL(virtualGeometryChanged(QRect)), SLOT(repositionView(QRect)));
68}
69
70DesktopInputPanel::~DesktopInputPanel()
71{
72}
73
74void DesktopInputPanel::show()
75{
76 AppInputPanel::show();
77 Q_D(DesktopInputPanel);
78 if (d->view) {
79 repositionView(rect: QGuiApplication::primaryScreen()->availableGeometry());
80 d->view->show();
81 }
82}
83
84void DesktopInputPanel::hide()
85{
86 AppInputPanel::hide();
87 Q_D(DesktopInputPanel);
88 if (d->view)
89 d->view->hide();
90}
91
92bool DesktopInputPanel::isVisible() const
93{
94 return AppInputPanel::isVisible();
95}
96
97void DesktopInputPanel::setInputRect(const QRect &inputRect)
98{
99 Q_D(DesktopInputPanel);
100 d->keyboardRect = inputRect;
101 updateInputRegion();
102}
103
104void DesktopInputPanel::createView()
105{
106 Q_D(DesktopInputPanel);
107 if (!d->view) {
108 if (qGuiApp) {
109 connect(qGuiApp, SIGNAL(focusWindowChanged(QWindow*)), SLOT(focusWindowChanged(QWindow*)));
110 focusWindowChanged(qGuiApp->focusWindow());
111 }
112 d->view.reset(other: new InputView());
113 d->view->setFlags(Qt::FramelessWindowHint | Qt::WindowStaysOnTopHint | Qt::WindowDoesNotAcceptFocus);
114 /* Set appropriate WindowType for target environment.
115 There seems to be no common type which would
116 work in all environments. The purpose of this
117 flag is to avoid the window from capturing focus,
118 as well as hiding it from the task bar. */
119 switch (d->windowingSystem) {
120 case DesktopInputPanelPrivate::Xcb:
121 d->view->setFlags(d->view->flags() | Qt::Window | Qt::BypassWindowManagerHint);
122 break;
123 default:
124 d->view->setFlags(d->view->flags() | Qt::Tool);
125 break;
126 }
127 d->view->setColor(QColor(Qt::transparent));
128 d->view->setSource(QUrl(QLatin1String("qrc:///qt-project.org/imports/QtQuick/VirtualKeyboard/InputPanel.qml")));
129 if (QGuiApplication *app = qGuiApp)
130 connect(asender: app, SIGNAL(aboutToQuit()), SLOT(destroyView()));
131 }
132}
133
134void DesktopInputPanel::destroyView()
135{
136 Q_D(DesktopInputPanel);
137 d->view.reset();
138 d->previewBindingActive = false;
139}
140
141void DesktopInputPanel::repositionView(const QRect &rect)
142{
143 Q_D(DesktopInputPanel);
144 VIRTUALKEYBOARD_DEBUG() << "DesktopInputPanel::repositionView():" << rect;
145 if (d->view && d->view->geometry() != rect) {
146 QVirtualKeyboardInputContext *inputContext = qobject_cast<PlatformInputContext *>(object: parent())->inputContext();
147 if (inputContext) {
148 inputContext->setAnimating(true);
149 if (!d->previewBindingActive) {
150 QVirtualKeyboardInputContextPrivate *inputContextPrivate = inputContext->priv();
151 QObject::connect(sender: inputContextPrivate, signal: &QVirtualKeyboardInputContextPrivate::previewRectangleChanged, context: this, slot: &DesktopInputPanel::previewRectangleChanged);
152 QObject::connect(sender: inputContextPrivate, signal: &QVirtualKeyboardInputContextPrivate::previewVisibleChanged, context: this, slot: &DesktopInputPanel::previewVisibleChanged);
153 d->previewBindingActive = true;
154 }
155 }
156 d->view->setResizeMode(QQuickView::SizeViewToRootObject);
157 setInputRect(QRect());
158 d->view->setGeometry(rect);
159 d->view->setResizeMode(QQuickView::SizeRootObjectToView);
160 if (inputContext)
161 inputContext->setAnimating(false);
162 }
163}
164
165void DesktopInputPanel::focusWindowChanged(QWindow *focusWindow)
166{
167 disconnect(receiver: this, SLOT(focusWindowVisibleChanged(bool)));
168 if (focusWindow)
169 connect(sender: focusWindow, signal: &QWindow::visibleChanged, context: this, slot: &DesktopInputPanel::focusWindowVisibleChanged);
170}
171
172void DesktopInputPanel::focusWindowVisibleChanged(bool visible)
173{
174 if (!visible) {
175 QVirtualKeyboardInputContext *inputContext = qobject_cast<PlatformInputContext *>(object: parent())->inputContext();
176 if (inputContext)
177 inputContext->priv()->hideInputPanel();
178 }
179}
180
181void DesktopInputPanel::previewRectangleChanged()
182{
183 Q_D(DesktopInputPanel);
184 QVirtualKeyboardInputContext *inputContext = qobject_cast<PlatformInputContext *>(object: parent())->inputContext();
185 d->previewRect = inputContext->priv()->previewRectangle();
186 if (d->previewVisible)
187 updateInputRegion();
188}
189
190void DesktopInputPanel::previewVisibleChanged()
191{
192 Q_D(DesktopInputPanel);
193 QVirtualKeyboardInputContext *inputContext = qobject_cast<PlatformInputContext *>(object: parent())->inputContext();
194 d->previewVisible = inputContext->priv()->previewVisible();
195 if (d->view->isVisible())
196 updateInputRegion();
197}
198
199void DesktopInputPanel::updateInputRegion()
200{
201 Q_D(DesktopInputPanel);
202
203 if (d->view.isNull() || d->keyboardRect.isEmpty())
204 return;
205
206 // Make sure the native window is created
207 if (!d->view->handle())
208 d->view->create();
209
210 QRegion inputRegion(d->keyboardRect.toRect());
211 if (d->previewVisible && !d->previewRect.isEmpty())
212 inputRegion += d->previewRect.toRect();
213
214 d->view->setMask(inputRegion);
215}
216
217} // namespace QtVirtualKeyboard
218QT_END_NAMESPACE
219

source code of qtvirtualkeyboard/src/virtualkeyboard/desktopinputpanel.cpp