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

Provided by KDAB

Privacy Policy
Learn to use CMake with our Intro Training
Find out more

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