~timo-jyrinki/ubuntu/trusty/maliit-framework/fix_qt52

« back to all changes in this revision

Viewing changes to src/mpassthruwindow.cpp

  • Committer: Package Import Robot
  • Author(s): Ricardo Salveti de Araujo
  • Date: 2013-07-23 19:47:04 UTC
  • mto: This revision was merged to the branch mainline in revision 8.
  • Revision ID: package-import@ubuntu.com-20130723194704-0o18p2ao0x9sa1zx
Tags: upstream-0.99.0+git20130615+97e8335
ImportĀ upstreamĀ versionĀ 0.99.0+git20130615+97e8335

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
/* * This file is part of Maliit framework *
2
 
 *
3
 
 * Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
4
 
 * All rights reserved.
5
 
 *
6
 
 * Contact: maliit-discuss@lists.maliit.org
7
 
 *
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
12
 
 * of this file.
13
 
 */
14
 
#include "mpassthruwindow.h"
15
 
#include "mimxapplication.h"
16
 
#include "mimremotewindow.h"
17
 
#include "mimserveroptions.h"
18
 
 
19
 
#include <QDebug>
20
 
#include <QGraphicsView>
21
 
#include <QX11Info>
22
 
 
23
 
#include <X11/Xlib.h>
24
 
#include <X11/Xatom.h>
25
 
#include <X11/Xutil.h>
26
 
#include <X11/extensions/Xfixes.h>
27
 
#include <X11/extensions/shape.h>
28
 
 
29
 
class ForcedWidgetUpdater
30
 
{
31
 
private:
32
 
    const QRect globalBoundingRect;
33
 
 
34
 
public:
35
 
    explicit ForcedWidgetUpdater(const QRegion &globalRegion)
36
 
        : globalBoundingRect(globalRegion.boundingRect())
37
 
    {
38
 
    }
39
 
 
40
 
    bool operator()(QWidget *w)
41
 
    {
42
 
        if (not w) {
43
 
            return false;
44
 
        }
45
 
 
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));
50
 
 
51
 
        // Check whether there's anything to update for this widget (and its
52
 
        // children):
53
 
        if (updateArea.isEmpty()) {
54
 
            // Assumes that parent widgets fully contain their children.
55
 
            return false;
56
 
        }
57
 
 
58
 
        const QRect localWidgetRect(w->mapFromGlobal(updateArea.topLeft()),
59
 
                                    w->mapFromGlobal(updateArea.bottomRight()));
60
 
 
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);
70
 
        }
71
 
 
72
 
        w->update(localWidgetRect);
73
 
        return true;
74
 
    }
75
 
};
76
 
 
77
 
MPassThruWindow::MPassThruWindow(MImXServerLogic *serverLogic,
78
 
                                 const MImServerXOptions &options)
79
 
    : QWidget(0),
80
 
      remoteWindow(0),
81
 
      mRegion(),
82
 
      mServerLogic(serverLogic),
83
 
      xOptions(options)
84
 
{
85
 
    setWindowTitle("MInputMethod");
86
 
    setFocusPolicy(Qt::NoFocus);
87
 
 
88
 
    Qt::WindowFlags windowFlags = Qt::FramelessWindowHint | Qt::WindowStaysOnTopHint;
89
 
 
90
 
    if (xOptions.bypassWMHint) {
91
 
        windowFlags |= Qt::X11BypassWindowManagerHint;
92
 
    }
93
 
 
94
 
    setWindowFlags(windowFlags);
95
 
 
96
 
    // We do not want input focus for that window.
97
 
    setAttribute(Qt::WA_X11DoNotAcceptFocus);
98
 
 
99
 
    QObject::connect(mServerLogic, SIGNAL(remoteWindowChanged(MImRemoteWindow *)),
100
 
                     this, SLOT(setRemoteWindow(MImRemoteWindow *)));
101
 
}
102
 
 
103
 
MPassThruWindow::~MPassThruWindow()
104
 
{
105
 
}
106
 
 
107
 
void MPassThruWindow::closeEvent(QCloseEvent *ev)
108
 
{
109
 
    ev->ignore(); // We don't want to be closed.
110
 
}
111
 
 
112
 
bool MPassThruWindow::event(QEvent *e)
113
 
{
114
 
    if (e->type() == QEvent::WinIdChange) {
115
 
        updateWindowType();
116
 
        updateInputRegion();
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.
120
 
        updateWindowType();
121
 
    }
122
 
 
123
 
    return QWidget::event(e);
124
 
}
125
 
 
126
 
void MPassThruWindow::inputPassthrough(const QRegion &region)
127
 
{
128
 
    qDebug() << __PRETTY_FUNCTION__ << region << "geometry=" << geometry();
129
 
    mRegion = region;
130
 
    updateInputRegion();
131
 
 
132
 
    // selective compositing
133
 
    if (region.isEmpty()) {
134
 
        if (xOptions.selfComposited && remoteWindow) {
135
 
            remoteWindow->unredirect();
136
 
        }
137
 
 
138
 
        hide();
139
 
    } else {
140
 
        if (xOptions.selfComposited && remoteWindow) {
141
 
            remoteWindow->redirect();
142
 
        }
143
 
 
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
149
 
        // showFullScreen)
150
 
        //
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())) {
155
 
            showFullScreen();
156
 
 
157
 
            // If bypassing window hint, also do raise to ensure visibility:
158
 
            if (xOptions.bypassWMHint) {
159
 
                raise();
160
 
            }
161
 
        }
162
 
    }
163
 
}
164
 
 
165
 
void MPassThruWindow::updateInputRegion()
166
 
{
167
 
    qDebug() << __PRETTY_FUNCTION__ << "QWidget::effectiveWinId(): " << effectiveWinId();
168
 
 
169
 
    if (!effectiveWinId())
170
 
        return;
171
 
 
172
 
    const QVector<QRect> &regionRects(mRegion.rects());
173
 
    const int size = regionRects.size();
174
 
 
175
 
    if (!size)
176
 
        return;
177
 
 
178
 
    XRectangle * const rects = new XRectangle[size];
179
 
 
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;
191
 
    }
192
 
 
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);
196
 
 
197
 
    XFixesDestroyRegion(QX11Info::display(), shapeRegion);
198
 
 
199
 
    XChangeProperty(QX11Info::display(), effectiveWinId(),
200
 
                    XInternAtom(QX11Info::display(), "_MEEGOTOUCH_CUSTOM_REGION", False),
201
 
                    XA_CARDINAL, 32, PropModeReplace,
202
 
                    (unsigned char *) customRegion, size * 4);
203
 
 
204
 
    delete[] rects;
205
 
}
206
 
 
207
 
void MPassThruWindow::updateWindowType()
208
 
{
209
 
    qDebug() << __PRETTY_FUNCTION__ << "QWidget::effectiveWinId(): " << effectiveWinId();
210
 
 
211
 
    if (!effectiveWinId())
212
 
        return;
213
 
 
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);
219
 
}
220
 
 
221
 
void MPassThruWindow::setRemoteWindow(MImRemoteWindow *newWindow)
222
 
{
223
 
    remoteWindow = newWindow;
224
 
 
225
 
    if (!newWindow)
226
 
        inputPassthrough();
227
 
}
228
 
 
229
 
void MPassThruWindow::updateFromRemoteWindow(const QRegion &region)
230
 
{
231
 
    visitWidgetHierarchy(ForcedWidgetUpdater(region), this);
232
 
}
233
 
 
234
 
const QRegion & MPassThruWindow::region()
235
 
{
236
 
    return mRegion;
237
 
}
238