diff options
Diffstat (limited to 'src/mcompositewindow.cpp')
-rw-r--r-- | src/mcompositewindow.cpp | 494 |
1 files changed, 494 insertions, 0 deletions
diff --git a/src/mcompositewindow.cpp b/src/mcompositewindow.cpp new file mode 100644 index 0000000..5b48210 --- /dev/null +++ b/src/mcompositewindow.cpp @@ -0,0 +1,494 @@ +/*************************************************************************** +** +** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (directui@nokia.com) +** +** This file is part of mcompositor. +** +** If you have questions regarding the use of this file, please contact +** Nokia at directui@nokia.com. +** +** This library is free software; you can redistribute it and/or +** modify it under the terms of the GNU Lesser General Public +** License version 2.1 as published by the Free Software Foundation +** and appearing in the file LICENSE.LGPL included in the packaging +** of this file. +** +****************************************************************************/ + +#include "mcompositewindow.h" +#include "mcompwindowanimator.h" +#include "mcompositemanager.h" +#include "mcompositemanager_p.h" +#include "mtexturepixmapitem.h" + +#include <QX11Info> +#include <QGraphicsScene> +#include <QGraphicsSceneMouseEvent> +#include <X11/Xatom.h> + +bool MCompositeWindow::window_transitioning = false; + +MCompositeWindow::MCompositeWindow(Qt::HANDLE window, QGraphicsItem *p) + : QGraphicsItem(p), + scalefrom(1), + scaleto(1), + scaled(false), + zval(1), + blur(false), + iconified(false), + iconified_final(false), + iconify_state(NoIconifyState), + destroyed(false), + requestzval(false), + process_status(NORMAL), + need_decor(false), + is_decorator(false), + window_visible(true), + transient_for(0), + wants_focus(false), + window_obscured(false), + win_id(window) +{ + anim = new MCompWindowAnimator(this); + connect(anim, SIGNAL(transitionDone()), SLOT(finalizeState())); + connect(anim, SIGNAL(transitionDone()), SLOT(windowSettled())); + connect(anim, SIGNAL(transitionStart()), SLOT(windowTransitioning())); + thumb_mode = false; + setAcceptHoverEvents(true); + + t_ping = new QTimer(this); + connect(t_ping, SIGNAL(timeout()), SLOT(pingWindow())); +} + +MCompositeWindow::~MCompositeWindow() +{ + delete anim; + anim = 0; +} + +void MCompositeWindow::setBlurred(bool b) +{ + blur = b; + update(); +} + +void MCompositeWindow::setUnBlurred() +{ + blur = false; + update(); +} + +bool MCompositeWindow::blurred() +{ + return blur; +} + +void MCompositeWindow::saveState() +{ + anim->saveState(); +} + +void MCompositeWindow::localSaveState() +{ + anim->localSaveState(); +} + +// void MCompositeWindow::restore() +// { +// anim->restore(); +// } + +// set the scale point to actual values +void MCompositeWindow::setScalePoint(qreal from, qreal to) +{ + scalefrom = from; + scaleto = to; +} + +void MCompositeWindow::setThumbMode(bool mode) +{ + thumb_mode = mode; +} + +/* This is a delayed animation. Actual animation is triggered + * when startTransition() is called + */ +void MCompositeWindow::iconify(const QRectF &iconGeometry, bool defer) +{ + this->iconGeometry = iconGeometry; + origPosition = pos(); + + // horizontal and vert. scaling factors + qreal sx = iconGeometry.width() / boundingRect().width(); + qreal sy = iconGeometry.height() / boundingRect().height(); + + anim->deferAnimation(defer); + anim->translateScale(qreal(1.0), qreal(1.0), sx, sy, + iconGeometry.topLeft()); + iconified = true; +} + +void MCompositeWindow::setIconified(bool iconified) +{ + iconified_final = iconified; + iconify_state = ManualIconifyState; + if (iconified && !anim->pendingAnimation()) + emit itemIconified(this); + else if (!iconified && !anim->pendingAnimation()) + iconify_state = NoIconifyState; +} + +MCompositeWindow::IconifyState MCompositeWindow::iconifyState() const +{ + return iconify_state; +} + +void MCompositeWindow::setWindowObscured(bool obscured, bool no_notify) +{ + if (obscured == window_obscured) + return; + window_obscured = obscured; + + if (!no_notify) { + XVisibilityEvent c; + c.type = VisibilityNotify; + c.send_event = True; + c.window = window(); + c.state = obscured ? VisibilityFullyObscured : + VisibilityUnobscured; + XSendEvent(QX11Info::display(), window(), true, + VisibilityChangeMask, (XEvent *)&c); + } +} + +void MCompositeWindow::startTransition() +{ + if (anim->pendingAnimation()) { + anim->startAnimation(); + anim->deferAnimation(false); + } +} + +// TODO: have an option of disabling the animation +void MCompositeWindow::restore(const QRectF &iconGeometry, bool defer) +{ + this->iconGeometry = iconGeometry; + // horizontal and vert. scaling factors + qreal sx = iconGeometry.width() / boundingRect().width(); + qreal sy = iconGeometry.height() / boundingRect().height(); + + setVisible(true); + + anim->deferAnimation(defer); + anim->translateScale(qreal(1.0), qreal(1.0), sx, sy, origPosition, true); + iconified = false; +} + +void MCompositeWindow::prettyDestroy() +{ + setVisible(true); + destroyed = true; + iconify(); +} + +void MCompositeWindow::finalizeState() +{ + // request zvalue + if (requestzval) + setZValue(zval); + + // iconification status + if (iconified) { + iconified_final = true; + hide(); + iconify_state = TransitionIconifyState; + emit itemIconified(this); + } else { + iconify_state = NoIconifyState; + iconified_final = false; + show(); + QTimer::singleShot(200, this, SLOT(q_itemRestored())); + } + + // item lifetime + if (destroyed) + deleteLater(); + + requestzval = false; +} + +void MCompositeWindow::q_itemRestored() +{ + emit itemRestored(this); +} + +void MCompositeWindow::requestZValue(int zvalue) +{ + if (anim->isActive()) { + zval = zvalue; + requestzval = true; + } else { + setZValue(zvalue); + requestzval = false; + } +} + +bool MCompositeWindow::isIconified() const +{ + if (anim->isActive()) + return false; + + return iconified_final; +} +bool MCompositeWindow::isScaled() const +{ + return scaled; +} +void MCompositeWindow::setScaled(bool s) +{ + scaled = s; +} + +Window MCompositeWindow::transientFor() +{ + /* TODO: make this update the property based on PropertyNotifys */ + XGetTransientForHint(QX11Info::display(), win_id, &transient_for); + return transient_for; +} + +bool MCompositeWindow::wantsFocus() +{ + /* FIXME: check if it is enough to cache this... */ + bool val = true; + XWMHints *h = XGetWMHints(QX11Info::display(), win_id); + if (h) { + if ((h->flags & InputHint) && (h->input == False)) + val = false; + XFree(h); + } + wants_focus = val; + return wants_focus; +} + +XID MCompositeWindow::windowGroup() +{ + /* FIXME: check if it is enough to cache this... */ + XID val = 0; + XWMHints *h = XGetWMHints(QX11Info::display(), win_id); + if (h) { + if (h->flags & WindowGroupHint) + val = h->window_group; + XFree(h); + } + return val; +} + +const QList<Atom>& MCompositeWindow::supportedProtocols() +{ + static Atom atom = 0; + Atom actual_type; + int actual_format; + unsigned long actual_n, left; + unsigned char *data = NULL; + if (!atom) + atom = XInternAtom(QX11Info::display(), "WM_PROTOCOLS", False); + int result = XGetWindowProperty(QX11Info::display(), win_id, + atom, 0, 100, + False, XA_ATOM, &actual_type, + &actual_format, + &actual_n, &left, &data); + if (result == Success && data && actual_type == XA_ATOM) { + wm_protocols.clear(); + for (unsigned int i = 0; i < actual_n; ++i) + wm_protocols.append(((Atom *)data)[i]); + } + if (data) XFree(data); + + return wm_protocols; +} + +void MCompositeWindow::hoverEnterEvent(QGraphicsSceneHoverEvent *e) +{ + if (thumb_mode) { + zval = zValue(); + setZValue(scene()->items().count() + 1); + setZValue(100); + anim->translateScale(scalefrom, scalefrom, scaleto, scaleto, pos()); + + } + return QGraphicsItem::hoverEnterEvent(e); +} + +void MCompositeWindow::hoverLeaveEvent(QGraphicsSceneHoverEvent *e) +{ + if (thumb_mode) { + setZValue(zval); + anim->translateScale(scalefrom, scalefrom, scaleto, scaleto, pos(), true); + } + return QGraphicsItem::hoverLeaveEvent(e); +} + +void MCompositeWindow::mouseReleaseEvent(QGraphicsSceneMouseEvent *m) +{ + anim->restore(); + setThumbMode(false); + setScaled(false); + setZValue(100); + + emit acceptingInput(); + windowRaised(); + QGraphicsItem::mouseReleaseEvent(m); +} + +void MCompositeWindow::manipulationEnabled(bool isEnabled) +{ + setFlag(QGraphicsItem::ItemIsMovable, isEnabled); + setFlag(QGraphicsItem::ItemIsSelectable, isEnabled); +} + +void MCompositeWindow::setVisible(bool visible) +{ + // Set the iconification status as well + iconified_final = !visible; + if (visible != window_visible) + emit visualized(visible); + window_visible = visible; + + QGraphicsItem::setVisible(visible); + MCompositeManager *p = (MCompositeManager *) qApp; + p->d->setWindowDebugProperties(window()); +} + +void MCompositeWindow::startPing() +{ + if (t_ping->isActive()) + t_ping->stop(); + // this could be configurable. But will do for now. Most WMs use 5s delay + t_ping->start(5000); +} + +void MCompositeWindow::stopPing() +{ + t_ping->stop(); +} + +void MCompositeWindow::receivedPing(ulong serverTimeStamp) +{ + ping_server_timestamp = serverTimeStamp; + startPing(); + process_status = NORMAL; + if (blurred()) + setBlurred(false); +} + +void MCompositeWindow::pingTimeout() +{ + if (ping_server_timestamp != ping_client_timestamp && process_status != HUNG) { + setBlurred(true); + emit windowHung(this); + process_status = HUNG; + } +} + +void MCompositeWindow::setClientTimeStamp(ulong timeStamp) +{ + ping_client_timestamp = timeStamp; +} + +void MCompositeWindow::pingWindow() +{ + QTimer::singleShot(5000, this, SLOT(pingTimeout())); + emit pingTriggered(this); +} + +MCompositeWindow::ProcessStatus MCompositeWindow::status() const +{ + return process_status; +} + +bool MCompositeWindow::needDecoration() const +{ + return need_decor; +} + +void MCompositeWindow::setDecorated(bool decorated) +{ + need_decor = decorated; +} + +MCompositeWindow *MCompositeWindow::compositeWindow(Qt::HANDLE window) +{ + MCompositeManager *p = (MCompositeManager *) qApp; + return p->d->texturePixmapItem(window); +} + +Qt::HANDLE MCompositeWindow::window() const +{ + return win_id; +} + +bool MCompositeWindow::isDecorator() const +{ + return is_decorator; +} + +void MCompositeWindow::setIsDecorator(bool decorator) +{ + is_decorator = decorator; +} + +void MCompositeWindow::windowTransitioning() +{ + window_transitioning = true; +} + +void MCompositeWindow::windowSettled() +{ + window_transitioning = false; +} + +bool MCompositeWindow::isTransitioning() +{ + return window_transitioning; +} + +void MCompositeWindow::delayShow(int delay) +{ + // TODO: only do this for qt/dui apps because it delays translucency + setVisible(false); + QTimer::singleShot(delay, this, SLOT(q_delayShow())); +} + +void MCompositeWindow::q_delayShow() +{ + MCompositeWindow::setVisible(true); + updateWindowPixmap(); + MCompositeManager *p = (MCompositeManager *) qApp; + p->d->updateWinList(); +} + +QVariant MCompositeWindow::itemChange(GraphicsItemChange change, const QVariant &value) +{ + MCompositeManager *p = (MCompositeManager *) qApp; + bool zvalChanged = (change == ItemZValueHasChanged); + if (zvalChanged) + p->d->setWindowDebugProperties(window()); + + if (zvalChanged || change == ItemVisibleHasChanged || change == ItemParentHasChanged) + p->d->glwidget->update(); + + return QGraphicsItem::itemChange(change, value); +} + +void MCompositeWindow::update() +{ + MCompositeManager *p = (MCompositeManager *) qApp; + p->d->glwidget->update(); +} + +bool MCompositeWindow::windowVisible() const +{ + return window_visible; +} |