1
/* * This file is part of Maliit framework *
3
* Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
6
* Contact: maliit-discuss@lists.maliit.org
8
* Copyright (C) 2012 One Laptop per Child Association
10
* This library is free software; you can redistribute it and/or
11
* modify it under the terms of the GNU Lesser General Public
12
* License version 2.1 as published by the Free Software Foundation
13
* and appearing in the file LICENSE.LGPL included in the packaging
17
#include "windowedsurface.h"
18
#include "windowedsurface_p.h"
19
#include "windowedsurfacefactory_p.h"
21
#if QT_VERSION < QT_VERSION_CHECK(5, 0, 0)
22
#include "mimdummyinputcontext.h"
25
#include "mimapphostedserverlogic.h"
27
#include <maliit/plugins/abstractwidgetssurface.h>
29
#include <QApplication>
31
#include <QDesktopWidget>
32
#include <QGraphicsScene>
33
#include <QGraphicsView>
34
#include <QGraphicsItem>
37
#if QT_VERSION >= QT_VERSION_CHECK(5, 0, 0)
38
#include <QGuiApplication>
41
#include <qpa/qplatformnativeinterface.h>
49
using Maliit::Plugins::AbstractSurface;
55
const Qt::WindowFlags g_window_flags =
56
#if QT_VERSION >= QT_VERSION_CHECK(5, 0, 0)
57
Qt::WindowFlags(Qt::Dialog | Qt::FramelessWindowHint | Qt::WindowStaysOnTopHint | Qt::X11BypassWindowManagerHint
58
| Qt::WindowDoesNotAcceptFocus);
60
Qt::WindowFlags(Qt::Dialog | Qt::FramelessWindowHint | Qt::WindowStaysOnTopHint | Qt::X11BypassWindowManagerHint);
64
WindowedSurface::WindowedSurface(WindowedSurfaceFactory *factory,
65
AbstractSurface::Options options,
66
const QSharedPointer<WindowedSurface> &parent,
77
QWidget *parentWidget = 0;
79
parentWidget = parent->mToplevel.data();
81
mToplevel->setParent(parentWidget, g_window_flags);
83
#if QT_VERSION < QT_VERSION_CHECK(5, 0, 0)
84
mToplevel->setAttribute(Qt::WA_X11DoNotAcceptFocus);
86
mToplevel->setAutoFillBackground(false);
87
mToplevel->setBackgroundRole(QPalette::NoRole);
89
mToplevel->setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed);
93
mToplevel->installEventFilter(this);
96
WindowedSurface::~WindowedSurface()
100
void WindowedSurface::show()
106
void WindowedSurface::hide()
112
QSize WindowedSurface::size() const
114
return mToplevel->size();
117
void WindowedSurface::setSize(const QSize &size)
120
// stand-alone Maliit server
121
if (mOptions & PositionCenterBottom) {
122
const QSize desktopSize = QApplication::desktop()->screenGeometry().size();
124
mToplevel->setGeometry(QRect(QPoint((desktopSize.width() - size.width()) / 2,
125
desktopSize.height() - size.height()), size));
127
mToplevel->resize(size);
130
// application-hosted Maliit server
131
mToplevel->resize(size);
133
mFactory->updateInputMethodArea();
136
QPoint WindowedSurface::relativePosition() const
138
return mRelativePosition;
141
void WindowedSurface::setRelativePosition(const QPoint &position)
143
mRelativePosition = position;
144
QPoint parentPosition(0, 0);
146
if (isWindow() && !mParent->isWindow()) {
147
parentPosition = mParent->mapToGlobal(QPoint(0, 0));
148
} else if (!isWindow() && mParent->isWindow()) {
151
parentPosition = mParent->mToplevel->pos();
154
mToplevel->move(parentPosition + mRelativePosition);
155
mFactory->updateInputMethodArea();
158
QSharedPointer<AbstractSurface> WindowedSurface::parent() const
163
QPoint WindowedSurface::translateEventPosition(const QPoint &eventPosition,
164
const QSharedPointer<AbstractSurface> &eventSurface) const
167
return eventPosition;
169
QSharedPointer<WindowedSurface> windowedSurface = qSharedPointerDynamicCast<WindowedSurface>(eventSurface);
170
if (!windowedSurface)
173
return -mToplevel->pos() + eventPosition + windowedSurface->mToplevel->pos();
176
void WindowedSurface::setActive(bool active)
182
void WindowedSurface::applicationFocusChanged(WId winId)
187
XSetTransientForHint(QX11Info::display(),
188
mToplevel->window()->effectiveWinId(),
195
QRegion WindowedSurface::inputMethodArea()
197
if (!mToplevel->isVisible())
200
return QRegion(mToplevel->geometry());
203
void WindowedSurface::updateVisibility()
205
mToplevel->setVisible(mActive && mVisible);
206
mFactory->updateInputMethodArea();
209
bool WindowedSurface::isWindow() const
211
return mToplevel->isWindow();
214
QPoint WindowedSurface::mapToGlobal(const QPoint &pos) const
216
return mToplevel->mapToGlobal(pos);
219
bool WindowedSurface::eventFilter(QObject *, QEvent *event)
222
if (event->type() == QEvent::WinIdChange) {
223
mSurface = static_cast<struct input_panel_surface *>(mFactory->getInputPanelSurface(mToplevel->windowHandle()));
224
input_panel_surface_set_toplevel(mSurface);
233
class GraphicsView : public QGraphicsView
239
setWindowFlags(g_window_flags);
240
#if QT_VERSION < QT_VERSION_CHECK(5, 0, 0)
241
setAttribute(Qt::WA_X11DoNotAcceptFocus);
243
// Fixes: MALIIT#194 - Maliit can not input when QML viewer is set to
244
// full screen on QWS without x11
245
setAttribute(Qt::WA_ShowWithoutActivating);
247
setAutoFillBackground(false);
248
setBackgroundRole(QPalette::NoRole);
249
setBackgroundBrush(Qt::transparent);
251
// This is a workaround for non-compositing window managers. Apparently
252
// setting this attribute while using such WMs may cause garbled
254
#ifndef DISABLE_TRANSLUCENT_BACKGROUND_HINT
255
setAttribute(Qt::WA_TranslucentBackground);
257
viewport()->setAutoFillBackground(false);
262
: public QGraphicsItem
268
explicit RootItem(QGraphicsItem *parent = 0)
269
: QGraphicsItem(parent)
272
setFlag(QGraphicsItem::ItemHasNoContents);
275
void setRect(const QRectF &rect)
280
virtual QRectF boundingRect() const
285
virtual void paint(QPainter *,
286
const QStyleOptionGraphicsItem *,
291
class WindowedGraphicsViewSurface : public WindowedSurface, public Maliit::Plugins::AbstractGraphicsViewSurface
294
WindowedGraphicsViewSurface(WindowedSurfaceFactory *factory, AbstractSurface::Options options,
295
const QSharedPointer<WindowedSurface> &parent)
296
: WindowedSurface(factory, options, parent, new GraphicsView),
297
AbstractGraphicsViewSurface(),
300
#if QT_VERSION < QT_VERSION_CHECK(5, 0, 0)
301
MIMDummyInputContext dummy;
303
QGraphicsView *view = static_cast<QGraphicsView*>(mToplevel.data());
304
view->setViewportUpdateMode(QGraphicsView::MinimalViewportUpdate);
305
view->setOptimizationFlags(QGraphicsView::DontClipPainter | QGraphicsView::DontSavePainterState);
306
view->setFrameShape(QFrame::NoFrame);
307
view->setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
308
view->setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
310
#if QT_VERSION < QT_VERSION_CHECK(5, 0, 0)
311
// Calling QGraphicsView::setScene() indirectly calls QWidget::inputContext() on the view. If there isn't
312
// an input context set on the widget, this calls QApplication::inputContext(), which leads to infinite
313
// recursion if surface creation happens during input method creation and QT_IM_MODULE is set (for example
314
// when embedding maliit-server in the application)
315
view->setInputContext(&dummy);
317
QGraphicsScene *scene = new QGraphicsScene(view);
318
view->setScene(scene);
320
#if QT_VERSION < QT_VERSION_CHECK(5, 0, 0)
321
view->setInputContext(0);
325
~WindowedGraphicsViewSurface() {}
327
QGraphicsScene *scene() const
329
return view()->scene();
332
QGraphicsView *view() const
334
return static_cast<QGraphicsView*>(mToplevel.data());
339
WindowedSurface::show();
341
const QRect rect(QPoint(), mToplevel->size());
344
scene()->addItem(mRoot = new RootItem);
345
mRoot->setRect(rect);
350
void setSize(const QSize &size)
352
WindowedSurface::setSize(size);
354
view()->setSceneRect(QRect(QPoint(), mToplevel->size()));
356
mRoot->setRect(QRect(QPoint(), mToplevel->size()));
366
QGraphicsItem *root() const
371
QWidget *widget() const
380
class WindowedWidgetSurface : public WindowedSurface, public Maliit::Plugins::AbstractWidgetSurface
383
WindowedWidgetSurface(WindowedSurfaceFactory *factory, AbstractSurface::Options options,
384
const QSharedPointer<WindowedSurface> &parent)
385
: WindowedSurface(factory, options, parent, new QWidget),
386
AbstractWidgetSurface()
389
QWidget* widget() const {
390
return mToplevel.data();
397
void registryGlobal(void *data,
398
wl_registry *registry,
400
const char *interface,
403
WindowedSurfaceFactoryPrivate *d = static_cast<WindowedSurfaceFactoryPrivate *>(data);
406
d->handleRegistryGlobal(name, interface, version);
409
void registryGlobalRemove(void *data,
410
wl_registry *registry,
413
WindowedSurfaceFactoryPrivate *d = static_cast<WindowedSurfaceFactoryPrivate *>(data);
416
d->handleRegistryGlobalRemove(name);
419
const wl_registry_listener maliit_registry_listener = {
424
void outputGeometry(void *data,
425
struct wl_output *output,
428
int32_t physical_width,
429
int32_t physical_height,
434
WindowedSurfaceFactoryPrivate *d = static_cast<WindowedSurfaceFactoryPrivate *>(data);
437
d->handleOutputGeometry(x, y, physical_width, physical_height, subpixel, make,
441
void outputMode(void *data,
442
struct wl_output *output,
447
WindowedSurfaceFactoryPrivate *d = static_cast<WindowedSurfaceFactoryPrivate *>(data);
450
d->handleOutputMode(flags, width, height, refresh);
453
const wl_output_listener maliit_output_listener = {
458
} // unnamed namespace
461
WindowedSurfaceFactoryPrivate::WindowedSurfaceFactoryPrivate(WindowedSurfaceFactory *factory)
470
, output_configured(false)
473
connect(QApplication::desktop(), SIGNAL(resized(int)),
474
this, SLOT(screenResized(int)));
477
wl_display *display = static_cast<wl_display *>(QGuiApplication::platformNativeInterface()->nativeResourceForIntegration("display"));
479
qCritical() << __PRETTY_FUNCTION__ << "Failed to get a display.";
482
registry = wl_display_get_registry(display);
483
wl_registry_add_listener(registry, &maliit_registry_listener, this);
484
// QtWayland will do dispatching for us.
489
void WindowedSurfaceFactoryPrivate::handleRegistryGlobal(uint32_t name,
490
const char *interface,
495
if (!strcmp(interface, "input_panel")) {
496
panel = static_cast<input_panel *>(wl_registry_bind(registry, name, &input_panel_interface, 1));
497
} else if (!strcmp(interface, "wl_output")) {
499
// Ignoring the event - we already have an output.
500
// TODO: Later we will want to store those outputs as well
501
// to be able to choose where the input method plugin is
506
output = static_cast<wl_output *>(wl_registry_bind(registry, name, &wl_output_interface, 1));
507
wl_output_add_listener (output, &maliit_output_listener, this);
511
void WindowedSurfaceFactoryPrivate::handleRegistryGlobalRemove(uint32_t name)
516
void WindowedSurfaceFactoryPrivate::handleOutputGeometry(int32_t x,
518
int32_t physical_width,
519
int32_t physical_height,
527
Q_UNUSED(physical_width);
528
Q_UNUSED(physical_height);
535
void WindowedSurfaceFactoryPrivate::handleOutputMode(uint32_t flags,
543
qDebug() << __PRETTY_FUNCTION__;
544
if ((flags & WL_OUTPUT_MODE_CURRENT) == WL_OUTPUT_MODE_CURRENT) {
545
output_configured = true;
550
void WindowedSurfaceFactoryPrivate::screenResized(int)
552
Q_Q(WindowedSurfaceFactory);
554
Q_FOREACH(QWeakPointer<WindowedSurface> weakSurface, surfaces) {
555
QSharedPointer<WindowedSurface> surface = weakSurface.toStrongRef();
557
surface->setSize(surface->size());
558
if (surface->parent()) {
559
surface->setRelativePosition(surface->relativePosition());
563
Q_EMIT q->screenSizeChanged(q->screenSize());
567
void *WindowedSurfaceFactory::getInputPanelSurface(QWindow *window)
569
Q_D(WindowedSurfaceFactory);
571
struct wl_surface *surface = static_cast<struct wl_surface *>(QGuiApplication::platformNativeInterface()->nativeResourceForWindow("surface", window));
573
return input_panel_get_input_panel_surface(d->panel, surface);
577
// Windowed Surface Factory
579
WindowedSurfaceFactory::WindowedSurfaceFactory()
580
: AbstractSurfaceFactory()
581
, d_ptr(new WindowedSurfaceFactoryPrivate(this))
585
WindowedSurfaceFactory::~WindowedSurfaceFactory()
589
QSize WindowedSurfaceFactory::screenSize() const
591
return QApplication::desktop()->screenGeometry().size();
594
bool WindowedSurfaceFactory::supported(Maliit::Plugins::AbstractSurface::Options options) const
596
return options & AbstractSurface::TypeGraphicsView;
601
QSharedPointer<WindowedSurface> createSurface(WindowedSurfaceFactory *factory,
602
AbstractSurface::Options options,
603
const QSharedPointer<WindowedSurface> &parent)
605
if (options & Maliit::Plugins::AbstractSurface::TypeGraphicsView) {
606
return QSharedPointer<WindowedSurface>(new WindowedGraphicsViewSurface(factory,
610
if (options & Maliit::Plugins::AbstractSurface::TypeWidget) {
611
return QSharedPointer<WindowedSurface>(new WindowedWidgetSurface(factory,
615
return QSharedPointer<WindowedSurface>();
618
} // unnamed namespace
620
QSharedPointer<AbstractSurface> WindowedSurfaceFactory::create(AbstractSurface::Options options,
621
const QSharedPointer<AbstractSurface> &parent)
623
Q_D(WindowedSurfaceFactory);
625
QSharedPointer<WindowedSurface> default_surface_parent(qSharedPointerDynamicCast<WindowedSurface>(parent));
626
QSharedPointer<WindowedSurface> new_surface(createSurface(this, options,
627
default_surface_parent));
630
d->surfaces.push_back(new_surface);
631
Q_EMIT surfaceWidgetCreated(new_surface->widget(), options);
636
void WindowedSurfaceFactory::activate()
638
Q_D(WindowedSurfaceFactory);
642
Q_FOREACH(QWeakPointer<WindowedSurface> weakSurface, d->surfaces) {
643
QSharedPointer<WindowedSurface> surface = weakSurface.toStrongRef();
645
surface->setActive(true);
649
void WindowedSurfaceFactory::deactivate()
651
Q_D(WindowedSurfaceFactory);
655
Q_FOREACH(QWeakPointer<WindowedSurface> weakSurface, d->surfaces) {
656
QSharedPointer<WindowedSurface> surface = weakSurface.toStrongRef();
658
surface->setActive(false);
662
void WindowedSurfaceFactory::applicationFocusChanged(WId winId)
664
Q_D(WindowedSurfaceFactory);
666
Q_FOREACH(QWeakPointer<WindowedSurface> weakSurface, d->surfaces) {
667
QSharedPointer<WindowedSurface> surface = weakSurface.toStrongRef();
669
surface->applicationFocusChanged(winId);
674
void WindowedSurfaceFactory::updateInputMethodArea()
676
Q_D(WindowedSurfaceFactory);
681
QRegion inputMethodArea;
683
Q_FOREACH(QWeakPointer<WindowedSurface> weakSurface, d->surfaces) {
684
QSharedPointer<WindowedSurface> surface = weakSurface.toStrongRef();
685
if (surface && !surface->parent()) {
686
inputMethodArea |= surface->inputMethodArea();
690
Q_EMIT inputMethodAreaChanged(inputMethodArea);
693
} // namespace Server
694
} // namespace Maliit