1
/* * This file is part of Maliit framework *
3
* Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
6
* Contact: maliit-discuss@lists.maliit.org
8
* This library is free software; you can redistribute it and/or
9
* modify it under the terms of the GNU Lesser General Public
10
* License version 2.1 as published by the Free Software Foundation
11
* and appearing in the file LICENSE.LGPL included in the packaging
14
#include "mpassthruwindow.h"
15
#include "mimxapplication.h"
16
#include "mimremotewindow.h"
17
#include "mimserveroptions.h"
20
#include <QGraphicsView>
24
#include <X11/Xatom.h>
25
#include <X11/Xutil.h>
26
#include <X11/extensions/Xfixes.h>
27
#include <X11/extensions/shape.h>
29
class ForcedWidgetUpdater
32
const QRect globalBoundingRect;
35
explicit ForcedWidgetUpdater(const QRegion &globalRegion)
36
: globalBoundingRect(globalRegion.boundingRect())
40
bool operator()(QWidget *w)
46
const QRect g(w->geometry());
47
const QRect globalWidgetRect(w->mapToGlobal(g.topLeft()),
48
w->mapToGlobal(g.bottomRight()));
49
const QRect updateArea(globalBoundingRect.intersect(globalWidgetRect));
51
// Check whether there's anything to update for this widget (and its
53
if (updateArea.isEmpty()) {
54
// Assumes that parent widgets fully contain their children.
58
const QRect localWidgetRect(w->mapFromGlobal(updateArea.topLeft()),
59
w->mapFromGlobal(updateArea.bottomRight()));
61
// QGrapicsView's do not redraw the scene when calling QWidget::update.
62
// However, the widget's background is part of the scene, and we need
63
// to enforce redrawing of the background. Hence the manual
64
// scene invalidation.
65
if (QGraphicsView *v = qobject_cast<QGraphicsView *>(w)) {
66
v->invalidateScene(localWidgetRect, QGraphicsScene::BackgroundLayer);
67
QList<QRectF> rectList;
68
rectList.append(QRectF(localWidgetRect));
69
v->updateScene(rectList);
72
w->update(localWidgetRect);
77
MPassThruWindow::MPassThruWindow(MImXServerLogic *serverLogic,
78
const MImServerXOptions &options)
82
mServerLogic(serverLogic),
85
setWindowTitle("MInputMethod");
86
setFocusPolicy(Qt::NoFocus);
88
Qt::WindowFlags windowFlags = Qt::FramelessWindowHint | Qt::WindowStaysOnTopHint;
90
if (xOptions.bypassWMHint) {
91
windowFlags |= Qt::X11BypassWindowManagerHint;
94
setWindowFlags(windowFlags);
96
// We do not want input focus for that window.
97
setAttribute(Qt::WA_X11DoNotAcceptFocus);
99
QObject::connect(mServerLogic, SIGNAL(remoteWindowChanged(MImRemoteWindow *)),
100
this, SLOT(setRemoteWindow(MImRemoteWindow *)));
103
MPassThruWindow::~MPassThruWindow()
107
void MPassThruWindow::closeEvent(QCloseEvent *ev)
109
ev->ignore(); // We don't want to be closed.
112
bool MPassThruWindow::event(QEvent *e)
114
if (e->type() == QEvent::WinIdChange) {
117
} else if (e->type() == QEvent::Show) {
118
// Qt resets the window type after we get the WinIdChange event.
119
// We need to set it again before the window is mapped.
123
return QWidget::event(e);
126
void MPassThruWindow::inputPassthrough(const QRegion ®ion)
128
qDebug() << __PRETTY_FUNCTION__ << region << "geometry=" << geometry();
132
// selective compositing
133
if (region.isEmpty()) {
134
if (xOptions.selfComposited && remoteWindow) {
135
remoteWindow->unredirect();
140
if (xOptions.selfComposited && remoteWindow) {
141
remoteWindow->redirect();
144
// Do not call multiple times showFullScreen() because it could
145
// break focus from the activateWindow() call. See QTBUG-18130.
146
// Do not call when no remote window is existent or remote window
147
// is iconified (since the keyboard is transient to the remote
148
// window it could result in the remote window to be shown by calling
151
// Check can be overidden by the unconditionalShow option. For instance on Ubuntu 11.10 with Unity
152
// isVisible() sometimes starts to return true when the window is still unmapped, causing
153
// the logic to fail, preventing the input method window to show if done conditionally
154
if (xOptions.unconditionalShow || (!isVisible() && remoteWindow && !remoteWindow->isIconified())) {
157
// If bypassing window hint, also do raise to ensure visibility:
158
if (xOptions.bypassWMHint) {
165
void MPassThruWindow::updateInputRegion()
167
qDebug() << __PRETTY_FUNCTION__ << "QWidget::effectiveWinId(): " << effectiveWinId();
169
if (!effectiveWinId())
172
const QVector<QRect> ®ionRects(mRegion.rects());
173
const int size = regionRects.size();
178
XRectangle * const rects = new XRectangle[size];
180
quint32 customRegion[size * 4]; // custom region is pack of x, y, w, h
181
XRectangle *rect = rects;
182
for (int i = 0; i < size; ++i, ++rect) {
183
rect->x = regionRects.at(i).x();
184
rect->y = regionRects.at(i).y();
185
rect->width = regionRects.at(i).width();
186
rect->height = regionRects.at(i).height();
187
customRegion[i * 4 + 0] = rect->x;
188
customRegion[i * 4 + 1] = rect->y;
189
customRegion[i * 4 + 2] = rect->width;
190
customRegion[i * 4 + 3] = rect->height;
193
const XserverRegion shapeRegion = XFixesCreateRegion(QX11Info::display(), rects, size);
194
XFixesSetWindowShapeRegion(QX11Info::display(), effectiveWinId(), ShapeBounding, 0, 0, 0);
195
XFixesSetWindowShapeRegion(QX11Info::display(), effectiveWinId(), ShapeInput, 0, 0, shapeRegion);
197
XFixesDestroyRegion(QX11Info::display(), shapeRegion);
199
XChangeProperty(QX11Info::display(), effectiveWinId(),
200
XInternAtom(QX11Info::display(), "_MEEGOTOUCH_CUSTOM_REGION", False),
201
XA_CARDINAL, 32, PropModeReplace,
202
(unsigned char *) customRegion, size * 4);
207
void MPassThruWindow::updateWindowType()
209
qDebug() << __PRETTY_FUNCTION__ << "QWidget::effectiveWinId(): " << effectiveWinId();
211
if (!effectiveWinId())
214
// Set _NET_WM_WINDOW_TYPE to _NET_WM_WINDOW_TYPE_INPUT
215
static Atom input = XInternAtom(QX11Info::display(), "_NET_WM_WINDOW_TYPE_INPUT", False);
216
static Atom window_type = XInternAtom(QX11Info::display(), "_NET_WM_WINDOW_TYPE", False);
217
XChangeProperty(QX11Info::display(), effectiveWinId(), window_type, XA_ATOM, 32,
218
PropModeReplace, (unsigned char *) &input, 1);
221
void MPassThruWindow::setRemoteWindow(MImRemoteWindow *newWindow)
223
remoteWindow = newWindow;
229
void MPassThruWindow::updateFromRemoteWindow(const QRegion ®ion)
231
visitWidgetHierarchy(ForcedWidgetUpdater(region), this);
234
const QRegion & MPassThruWindow::region()