Fix rendering errors of close window button in Present Windows

Hiding and Showing the close window button all the time can result in
the window not having a proper content. To fix this issue we keep the
window around, but just don't show it. For this the CloseWindowView
inherits from QObject and delegates the needed calls to the nested
QQuickView.
This commit is contained in:
Martin Gräßlin 2013-10-25 12:57:34 +02:00
parent bf9219bd9a
commit 5d5673ebc0
2 changed files with 80 additions and 28 deletions

View file

@ -41,6 +41,7 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
#include <QQmlContext> #include <QQmlContext>
#include <QQmlEngine> #include <QQmlEngine>
#include <QQuickItem> #include <QQuickItem>
#include <QQuickView>
#include <QDesktopWidget> #include <QDesktopWidget>
#include <QGraphicsObject> #include <QGraphicsObject>
#include <QTimer> #include <QTimer>
@ -400,8 +401,12 @@ void PresentWindowsEffect::paintWindow(EffectWindow *w, int mask, QRegion region
} }
winData->textFrame->render(region, 0.9 * data.opacity() * m_decalOpacity, 0.75); winData->textFrame->render(region, 0.9 * data.opacity() * m_decalOpacity, 0.75);
} }
} else } else {
if (w == m_closeWindow && m_closeView && !m_closeView->isVisible()) {
data.setOpacity(0);
}
effects->paintWindow(w, mask, region, data); effects->paintWindow(w, mask, region, data);
}
} else } else
effects->paintWindow(w, mask, region, data); effects->paintWindow(w, mask, region, data);
} }
@ -522,8 +527,9 @@ bool PresentWindowsEffect::borderActivated(ElectricBorder border)
void PresentWindowsEffect::windowInputMouseEvent(QEvent *e) void PresentWindowsEffect::windowInputMouseEvent(QEvent *e)
{ {
QMouseEvent* me = static_cast< QMouseEvent* >(e); QMouseEvent* me = static_cast< QMouseEvent* >(e);
if (m_closeView && m_closeView->geometry().contains(me->pos())) { if (m_closeView) {
if (!m_closeView->isVisible()) { const bool contains = m_closeView->geometry().contains(me->pos());
if (!m_closeView->isVisible() && contains) {
updateCloseWindow(); updateCloseWindow();
} }
if (m_closeView->isVisible()) { if (m_closeView->isVisible()) {
@ -531,7 +537,10 @@ void PresentWindowsEffect::windowInputMouseEvent(QEvent *e)
// const QPointF scenePos = m_closeView->mapToScene(widgetPos); // const QPointF scenePos = m_closeView->mapToScene(widgetPos);
QMouseEvent event(me->type(), widgetPos, me->pos(), me->button(), me->buttons(), me->modifiers()); QMouseEvent event(me->type(), widgetPos, me->pos(), me->button(), me->buttons(), me->modifiers());
m_closeView->windowInputMouseEvent(&event); m_closeView->windowInputMouseEvent(&event);
return; if (contains) {
// filter out
return;
}
} }
} }
// Which window are we hovering over? Always trigger as we don't always get move events before clicking // Which window are we hovering over? Always trigger as we don't always get move events before clicking
@ -1945,15 +1954,17 @@ void PresentWindowsEffect::screenCountChanged()
/************************************************ /************************************************
* CloseWindowView * CloseWindowView
************************************************/ ************************************************/
CloseWindowView::CloseWindowView(QWindow *parent) CloseWindowView::CloseWindowView(QObject *parent)
: QQuickView(parent) : QObject(parent)
, m_armTimer(new QElapsedTimer()) , m_armTimer(new QElapsedTimer())
, m_window(new QQuickView())
, m_visible(false)
{ {
setFlags(Qt::X11BypassWindowManagerHint); m_window->setFlags(Qt::X11BypassWindowManagerHint);
setColor(Qt::transparent); m_window->setColor(Qt::transparent);
setSource(QUrl(QStandardPaths::locate(QStandardPaths::GenericDataLocation, QStringLiteral("kwin/effects/presentwindows/main.qml")))); m_window->setSource(QUrl(QStandardPaths::locate(QStandardPaths::GenericDataLocation, QStringLiteral("kwin/effects/presentwindows/main.qml"))));
if (QObject *item = rootObject()->findChild<QObject*>(QStringLiteral("closeButton"))) { if (QObject *item = m_window->rootObject()->findChild<QObject*>(QStringLiteral("closeButton"))) {
connect(item, SIGNAL(clicked()), SIGNAL(requestClose())); connect(item, SIGNAL(clicked()), SIGNAL(requestClose()));
} }
@ -1963,17 +1974,12 @@ CloseWindowView::CloseWindowView(QWindow *parent)
void CloseWindowView::windowInputMouseEvent(QMouseEvent *e) void CloseWindowView::windowInputMouseEvent(QMouseEvent *e)
{ {
if (e->type() == QEvent::MouseMove) { if (e->type() == QEvent::MouseMove) {
mouseMoveEvent(e); qApp->sendEvent(m_window.data(), e);
} else if (!m_armTimer->hasExpired(350)) { } else if (!m_armTimer->hasExpired(350)) {
// 50ms until the window is elevated (seen!) and 300ms more to be "realized" by the user. // 50ms until the window is elevated (seen!) and 300ms more to be "realized" by the user.
return; return;
} else if (e->type() == QEvent::MouseButtonPress) {
mousePressEvent(e);
} else if (e->type() == QEvent::MouseButtonDblClick) {
mouseDoubleClickEvent(e);
} else if (e->type() == QEvent::MouseButtonRelease) {
mouseReleaseEvent(e);
} }
qApp->sendEvent(m_window.data(), e);
} }
void CloseWindowView::disarm() void CloseWindowView::disarm()
@ -1981,12 +1987,46 @@ void CloseWindowView::disarm()
m_armTimer->restart(); m_armTimer->restart();
} }
void CloseWindowView::hideEvent(QHideEvent *event) bool CloseWindowView::isVisible() const
{ {
const QPoint globalPos = mapToGlobal(QPoint(-1,-1)); return m_visible;
QMouseEvent me(QEvent::MouseMove, QPoint(-1,-1), globalPos, Qt::NoButton, Qt::NoButton, Qt::NoModifier); }
mouseMoveEvent(&me);
QQuickView::hideEvent(event); void CloseWindowView::show()
{
m_visible = true;
m_window->show();
}
void CloseWindowView::hide()
{
m_visible = false;
QEvent event(QEvent::Leave);
qApp->sendEvent(m_window.data(), &event);
}
#define DELEGATE(type, name) \
type CloseWindowView::name() const \
{ \
return m_window->name(); \
}
DELEGATE(int, width)
DELEGATE(int, height)
DELEGATE(QSize, size)
DELEGATE(QRect, geometry)
DELEGATE(WId, winId)
#undef DELEGATE
void CloseWindowView::setGeometry(const QRect &geometry)
{
m_window->setGeometry(geometry);
}
QPoint CloseWindowView::mapFromGlobal(const QPoint &pos) const
{
return m_window->mapFromGlobal(pos);
} }
} // namespace } // namespace

View file

@ -25,28 +25,40 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
#include "presentwindows_proxy.h" #include "presentwindows_proxy.h"
#include <kwineffects.h> #include <kwineffects.h>
#include <QQuickView>
class QElapsedTimer; class QElapsedTimer;
class QQuickView;
namespace KWin namespace KWin
{ {
class CloseWindowView : public QQuickView class CloseWindowView : public QObject
{ {
Q_OBJECT Q_OBJECT
public: public:
explicit CloseWindowView(QWindow *parent = 0); explicit CloseWindowView(QObject *parent = 0);
void windowInputMouseEvent(QMouseEvent* e); void windowInputMouseEvent(QMouseEvent* e);
void disarm(); void disarm();
void show();
void hide();
bool isVisible() const;
// delegate to QWindow
int width() const;
int height() const;
QSize size() const;
QRect geometry() const;
WId winId() const;
void setGeometry(const QRect &geometry);
QPoint mapFromGlobal(const QPoint &pos) const;
Q_SIGNALS: Q_SIGNALS:
void requestClose(); void requestClose();
protected:
void hideEvent(QHideEvent *event);
private: private:
QScopedPointer<QElapsedTimer> m_armTimer; QScopedPointer<QElapsedTimer> m_armTimer;
QScopedPointer<QQuickView> m_window;
bool m_visible;
}; };
/** /**