1
/* * This file is part of Maliit framework *
3
* Copyright (C) 2011 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
15
#include "mimremotewindow.h"
16
#include "mimserveroptions.h"
21
#include "mimxapplication.h"
22
#include "mimxerrortrap.h"
26
#include <X11/Xutil.h>
27
#include <X11/extensions/Xcomposite.h>
28
#include <X11/extensions/Xdamage.h>
31
# include <X11/Xatom.h>
39
// MB doesn't update WM_STATE when window is iconified, so, as a
40
// workaround, we monitor _MB_CURRENT_APP_WINDOW. This points to wid
41
// when on FullScreen/Active
42
# define ICONIFIED_ATOM_NAME "_MB_CURRENT_APP_WINDOW"
44
# define ICONIFIED_ATOM_NAME "WM_STATE"
46
static const Atom stateAtom = XInternAtom(QX11Info::display(), ICONIFIED_ATOM_NAME, false);
53
MImRemoteWindow::MImRemoteWindow(WId window,
54
MImXServerLogic *serverLogic,
55
const MImServerXOptions &options) :
63
mServerLogic(serverLogic)
67
MImRemoteWindow::~MImRemoteWindow()
69
XSelectInput(QX11Info::display(), wid, 0);
73
void MImRemoteWindow::setIMWidget(const QWidget *widget)
75
XSetTransientForHint(QX11Info::display(),
76
widget->effectiveWinId(),
79
// Using PropertyChangeMask is a work-around for NB#172722 (a WONTFIX):
80
XSelectInput(QX11Info::display(),
82
StructureNotifyMask | PropertyChangeMask);
85
bool MImRemoteWindow::wasIconified(XEvent *ev) const
87
if (PropertyNotify != ev->type) {
91
if (ev->xproperty.atom == wmStateAtom()) {
98
bool MImRemoteWindow::isIconified() const
102
unsigned long length;
104
unsigned long *state;
108
# define REAL_ATOM XA_WINDOW
109
# define IS_ICONIFIED(_X) _X != wid
111
# define REAL_ATOM AnyPropertyType
112
# define IS_ICONIFIED(_X) _X == IconicState
115
int queryResult = XGetWindowProperty(QX11Info::display(), wid, wmStateAtom(), 0, 2,
116
false, REAL_ATOM, &type, &format, &length,
118
state = reinterpret_cast<unsigned long *>(data);
120
bool result = (queryResult == Success && data && format == 32 && IS_ICONIFIED(*state));
130
bool MImRemoteWindow::wasUnmapped(XEvent *ev) const
132
return (ev->type == UnmapNotify &&
133
ev->xunmap.event == wid);
136
void MImRemoteWindow::setupDamage()
140
damage = XDamageCreate(QX11Info::display(), wid, XDamageReportNonEmpty);
143
void MImRemoteWindow::destroyDamage()
148
XDamageDestroy(QX11Info::display(), damage);
152
void MImRemoteWindow::redirect()
157
if (xOptions.manualRedirection) {
158
MImXErrorTrap xerror(mServerLogic->compositeExtension(), X_CompositeRedirectWindow);
159
XCompositeRedirectWindow(QX11Info::display(),
161
CompositeRedirectManual);
162
if (xerror.untrap() == BadAccess)
163
qDebug() << "Window " << wid << " was already redirected";
171
Q_EMIT contentUpdated(QRegion(QRect(QPoint(), pixmap.size())));
174
void MImRemoteWindow::unredirect()
184
if (xOptions.manualRedirection) {
185
MImXErrorTrap xerror(mServerLogic->compositeExtension(), X_CompositeUnredirectWindow);
186
XCompositeUnredirectWindow(QX11Info::display(),
188
CompositeRedirectManual);
189
if (xerror.untrap() == BadAccess)
190
qDebug() << "Window " << wid << " was not redirected";
194
void MImRemoteWindow::handleEvent(XEvent *event)
196
handleConfigureNotifyEvent(event);
197
handleDamageEvent(event);
200
void MImRemoteWindow::handleConfigureNotifyEvent(XEvent *event)
202
if (event->type != ConfigureNotify)
205
XConfigureEvent *e = &event->xconfigure;
207
if (e->window != wid)
213
void MImRemoteWindow::resetPixmap()
219
void MImRemoteWindow::update(const QRegion ®ion)
221
Q_EMIT contentUpdated(region);
224
void MImRemoteWindow::handleDamageEvent(XEvent *event)
226
if (event->type != mServerLogic->damageExtension().eventBase() + XDamageNotify)
229
XDamageNotifyEvent *e = reinterpret_cast<XDamageNotifyEvent*>(event);
231
if (damage != e->damage)
234
XserverRegion parts = XFixesCreateRegion(QX11Info::display(), 0, 0);
235
XDamageSubtract(QX11Info::display(), e->damage, None, parts);
240
XRectangle *rects = XFixesFetchRegion(QX11Info::display(), parts, &nrects);
242
for (int i = 0; i < nrects; ++i) {
243
region += QRect(rects[i].x, rects[i].y, rects[i].width, rects[i].height);
248
XFixesDestroyRegion(QX11Info::display(), parts);
250
// setup remote pixmap when it failed before
254
Q_EMIT contentUpdated(region);
257
void MImRemoteWindow::setupPixmap()
261
MImXErrorTrap error(mServerLogic->compositeExtension(), X_CompositeNameWindowPixmap);
262
xpixmap = XCompositeNameWindowPixmap(QX11Info::display(), wid);
263
if (error.untrap() == BadMatch) {
264
qDebug() << "Cannot get offscreen reference for Window " << wid;
270
pixmap = QPixmap::fromX11Pixmap(xpixmap, QPixmap::ExplicitlyShared);
274
void MImRemoteWindow::destroyPixmap()
276
if (MImXApplication::instance())
280
XFreePixmap(QX11Info::display(), xpixmap);
285
const QPixmap &MImRemoteWindow::windowPixmap() const
287
// setup remote pixmap when it failed before
288
if (redirected && pixmap.isNull()) {
289
const_cast<MImRemoteWindow*>(this)->setupPixmap();