diff options
author | Abdiel Janulgue <abdiel.janulgue@nokia.com> | 2010-08-12 20:53:54 +0300 |
---|---|---|
committer | Abdiel Janulgue <abdiel.janulgue@nokia.com> | 2010-08-12 20:53:54 +0300 |
commit | 8a14b80d9984ed0e4b36280295602fa6b4023f8d (patch) | |
tree | 0f77e770e3c9ca9c1a733880d552470fc4e2c9cd | |
parent | b5a3f7bc6734420fe926d4dfd66b9d7e923984c7 (diff) |
Fixes: NB#181749 - Window animations feel 'cheap' compared to Fremantle
Details:
- Added MapRequesterPrivate class to properly synchronize mapping windows
only after compositing is enabled since enableCompositing() is asynchrounous.
Without this, artifacts may be quite visible when mapping windows and compositing
effects are required but compositing is not yet enabled.
- Don't delete the object when a window is destoyed if it is animating
- Delay sending of WM_DELETE only when a window has finished animating during close
window effects
- Wrap the MWindowProperty cache in a QPointer so the the MCompositeWindow can know
if the property cache has been deleted or not.
- Implemented additional background dimming effects when mapping windows as dictated
by Harmattan Motion Design Guidelines.
RevBy: TrustMe
-rw-r--r-- | src/mcompositemanager.cpp | 196 | ||||
-rw-r--r-- | src/mcompositemanager_p.h | 7 | ||||
-rw-r--r-- | src/mcompositewindow.cpp | 77 | ||||
-rw-r--r-- | src/mcompositewindow.h | 48 | ||||
-rw-r--r-- | src/mcompwindowanimator.cpp | 23 | ||||
-rw-r--r-- | src/mtexturepixmapitem_egl.cpp | 4 | ||||
-rw-r--r-- | src/mtexturepixmapitem_glx.cpp | 2 | ||||
-rw-r--r-- | src/mwindowpropertycache.h | 2 |
8 files changed, 242 insertions, 117 deletions
diff --git a/src/mcompositemanager.cpp b/src/mcompositemanager.cpp index 03ce118..0ba838d 100644 --- a/src/mcompositemanager.cpp +++ b/src/mcompositemanager.cpp @@ -332,6 +332,45 @@ Atom MCompAtoms::getAtom(Window w, Atoms atomtype) return 0; } +class MapRequesterPrivate: public QObject +{ + Q_OBJECT +public: + static MapRequesterPrivate* instance(QObject* parent = 0) + { + if (!d) + d = new MapRequesterPrivate(parent); + return d; + } + + void requestMap(Window window) + { + if ( !((MCompositeManager *) qApp)->isCompositing() ) + map_requests.push_back(window); + else + XMapWindow(QX11Info::display(), window); + } + +public slots: + void grantMapRequests() + { + while (!map_requests.isEmpty()) { + Window w = map_requests.takeLast(); + XMapWindow(QX11Info::display(), w); + } + } + +private: + QList<Window> map_requests; + explicit MapRequesterPrivate(QObject* parent = 0) + :QObject(parent) + {} + + static MapRequesterPrivate *d; +}; + +MapRequesterPrivate* MapRequesterPrivate::d = 0; + static Window transient_for(Window window) { Window transient_for = 0; @@ -617,6 +656,9 @@ MCompositeManagerPrivate::MCompositeManagerPrivate(QObject *p) this, SLOT(callOngoing(bool))); stacking_timer.setSingleShot(true); connect(&stacking_timer, SIGNAL(timeout()), this, SLOT(stackingTimeout())); + connect(this, SIGNAL(compositingEnabled()), MapRequesterPrivate::instance(this), + SLOT(grantMapRequests())); + } MCompositeManagerPrivate::~MCompositeManagerPrivate() @@ -767,7 +809,8 @@ void MCompositeManagerPrivate::destroyEvent(XDestroyWindowEvent *e) MCompositeWindow *item = COMPOSITE_WINDOW(e->window); if (item) { - item->deleteLater(); + if (!item->isClosing()) + item->deleteLater(); if (!removeWindow(e->window)) qWarning("destroyEvent(): Error removing window"); } else { @@ -779,7 +822,8 @@ void MCompositeManagerPrivate::destroyEvent(XDestroyWindowEvent *e) delete fd.frame; } } - if (prop_caches.contains(e->window)) { + + if (prop_caches.contains(e->window) && (!item || (item && !item->isClosing()))) { delete prop_caches.value(e->window); prop_caches.remove(e->window); } @@ -854,7 +898,7 @@ MCompositeWindow *MCompositeManagerPrivate::getHighestDecorated() MWindowPropertyCache *pc; if (cw && cw->isMapped() && (pc = cw->propertyCache()) && !pc->isOverrideRedirect() && - (cw->needDecoration() || cw->status() == MCompositeWindow::HUNG + (cw->needDecoration() || cw->status() == MCompositeWindow::Hung || (FULLSCREEN_WINDOW(cw) && pc->windowTypeAtom() != ATOM(_KDE_NET_WM_WINDOW_TYPE_OVERRIDE) && pc->windowTypeAtom() != ATOM(_NET_WM_WINDOW_TYPE_MENU) @@ -892,19 +936,11 @@ bool MCompositeManagerPrivate::possiblyUnredirectTopmostWindow() break; } } - // check if we have a window that is about to map, because that should - // affect the decision - bool being_mapped = false; - for (QHash<Window, MWindowPropertyCache*>::iterator it = prop_caches.begin(); - it != prop_caches.end(); ++it) { - MWindowPropertyCache *pc = it.value(); - if (pc->beingMapped()) { - being_mapped = true; - break; - } - } - if (!being_mapped && top && cw && - !MCompositeWindow::hasTransitioningWindow()) { + + // compositing is always assumed when a window gets mapped because of our + // MapRequester class + + if (top && cw && !MCompositeWindow::hasTransitioningWindow()) { // unredirect the chosen window and any docks and OR windows above it // TODO: what else should be unredirected? if (!((MTexturePixmapItem *)cw)->isDirectRendered()) { @@ -979,7 +1015,7 @@ void MCompositeManagerPrivate::unmapEvent(XUnmapEvent *e) positionWindow(MDecoratorFrame::instance()->winId(), STACK_BOTTOM); } else { - if (cw->status() == MCompositeWindow::HUNG) { + if (cw->status() == MCompositeWindow::Hung) { MDecoratorFrame::instance()->setManagedWindow(cw, true); MDecoratorFrame::instance()->setOnlyStatusbar(false); } else if (FULLSCREEN_WINDOW(cw) && device_state->ongoingCall()) { @@ -1056,7 +1092,7 @@ void MCompositeManagerPrivate::configureEvent(XConfigureEvent *e) MDecoratorFrame::instance()->decoratorItem() && MDecoratorFrame::instance()->managedWindow() == e->window) { if (FULLSCREEN_WINDOW(item) && - item->status() != MCompositeWindow::HUNG) { + item->status() != MCompositeWindow::Hung) { // ongoing call case MDecoratorFrame::instance()->setManagedWindow(item, true); MDecoratorFrame::instance()->setOnlyStatusbar(true); @@ -1281,7 +1317,7 @@ void MCompositeManagerPrivate::mapRequestEvent(XMapRequestEvent *e) MDecoratorFrame::instance()->setManagedWindow(0); MCompositeWindow *cw; if ((cw = getHighestDecorated())) { - if (cw->status() == MCompositeWindow::HUNG) { + if (cw->status() == MCompositeWindow::Hung) { MDecoratorFrame::instance()->setManagedWindow(cw, true); } else if (FULLSCREEN_WINDOW(cw) && device_state->ongoingCall()) { MDecoratorFrame::instance()->setManagedWindow(cw, true); @@ -1308,7 +1344,7 @@ void MCompositeManagerPrivate::mapRequestEvent(XMapRequestEvent *e) if (MDecoratorFrame::instance()->decoratorItem()) { enableCompositing(); - XMapWindow(QX11Info::display(), e->window); + MapRequesterPrivate::instance()->requestMap(e->window); // initially visualize decorator item so selective compositing // checks won't disable compositing MDecoratorFrame::instance()->decoratorItem()->setVisible(true); @@ -1353,8 +1389,8 @@ void MCompositeManagerPrivate::mapRequestEvent(XMapRequestEvent *e) XReparentWindow(QX11Info::display(), e->window, frame->windowArea(), 0, 0); - setWindowState(e->window, NormalState); - XMapWindow(QX11Info::display(), e->window); + setWindowState(e->window, NormalState); + MapRequesterPrivate::instance()->requestMap(e->window); frame->show(); XSync(QX11Info::display(), False); @@ -1365,7 +1401,7 @@ void MCompositeManagerPrivate::mapRequestEvent(XMapRequestEvent *e) setWindowState(e->window, IconicState); else setWindowState(e->window, NormalState); - XMapWindow(QX11Info::display(), e->window); + MapRequesterPrivate::instance()->requestMap(e->window); } } @@ -1593,7 +1629,7 @@ void MCompositeManagerPrivate::checkStacking(bool force_visibility_check, == ATOM(_NET_WM_WINDOW_TYPE_DOCK)) else if (active_app && aw && deco->decoratorItem() && deco->managedWindow() == active_app && - (fs_app || aw->status() == MCompositeWindow::HUNG)) { + (fs_app || aw->status() == MCompositeWindow::Hung)) { // no dock => decorator starts from (0,0) XMoveWindow(QX11Info::display(), deco->decoratorItem()->window(), 0, 0); } @@ -1654,7 +1690,7 @@ void MCompositeManagerPrivate::checkStacking(bool force_visibility_check, if (highest_d && highest_d == topmost && deco->decoratorItem() && deco->managedWindow() == highest_d->window() && (!FULLSCREEN_WINDOW(highest_d) - || highest_d->status() == MCompositeWindow::HUNG + || highest_d->status() == MCompositeWindow::Hung || device_state->ongoingCall())) { Window deco_w = deco->decoratorItem()->window(); int deco_i = stacking_list.indexOf(deco_w); @@ -1681,7 +1717,7 @@ void MCompositeManagerPrivate::checkStacking(bool force_visibility_check, MCompositeWindow *witem = COMPOSITE_WINDOW(stacking_list.at(i)); if (witem && witem->isMapped() && !witem->propertyCache()->isOverrideRedirect() - && !witem->isNewlyMapped()) + && !witem->isNewlyMapped() && !witem->isClosing()) only_mapped.append(stacking_list.at(i)); } static QList<Window> prev_only_mapped; @@ -1786,7 +1822,7 @@ void MCompositeManagerPrivate::stackingTimeout() { checkStacking(stacking_timeout_check_visibility); stacking_timeout_check_visibility = false; - if (!device_state->displayOff() && !possiblyUnredirectTopmostWindow()) + if (!device_state->displayOff() && !possiblyUnredirectTopmostWindow()) enableCompositing(true); } @@ -1889,13 +1925,14 @@ void MCompositeManagerPrivate::mapEvent(XMapEvent *e) setWindowDebugProperties(item->window()); } else item->saveBackingStore(true); - item->setVisible(true); // TODO: don't show the animation if the window is not stacked on top const XWMHints &h = pc->getWMHints(); if (!(h.flags & StateHint) || h.initial_state != IconicState) - item->fadeIn(); - else + item->showWindow(); + else { + item->setVisible(true); item->setNewlyMapped(false); + } goto stack_and_return; } @@ -1916,7 +1953,7 @@ void MCompositeManagerPrivate::mapEvent(XMapEvent *e) const XWMHints &h = pc->getWMHints(); if ((!(h.flags & StateHint) || h.initial_state != IconicState) && item->isAppWindow()) - item->fadeIn(); + item->showWindow(); else { item->setVisible(true); item->setNewlyMapped(false); @@ -2027,45 +2064,18 @@ void MCompositeManagerPrivate::rootMessageEvent(XClientMessageEvent *event) // use composition due to the transition effect activateWindow(event->window, CurrentTime, false); } else if (event->message_type == ATOM(_NET_CLOSE_WINDOW)) { - Window close_window = event->window; - if (i) { - i->setClosing(true); - i->fadeOut(); - } - bool delete_sent = false; - if (i && (i->propertyCache()->supportedProtocols().indexOf( - ATOM(WM_DELETE_WINDOW)) != -1) && i->status() == MCompositeWindow::NORMAL) { - // send WM_DELETE_WINDOW message to the window that needs to close - XEvent ev; - memset(&ev, 0, sizeof(ev)); - - ev.xclient.type = ClientMessage; - ev.xclient.window = close_window; - ev.xclient.message_type = ATOM(WM_PROTOCOLS); - ev.xclient.format = 32; - ev.xclient.data.l[0] = ATOM(WM_DELETE_WINDOW); - ev.xclient.data.l[1] = CurrentTime; - - XSendEvent(QX11Info::display(), close_window, False, - NoEventMask, &ev); - // FIXME: we should check if desktop is exposed or not - setExposeDesktop(true); - delete_sent = true; - } - if (i && (!delete_sent || i->status() == MCompositeWindow::HUNG)) { - kill_window(close_window); - MDecoratorFrame::instance()->lower(); - removeWindow(close_window); - delete i; // it is already removed from hash tables - return; - } + + i->closeWindow(); + // update stacking lit to remove window from switcher + checkStacking(false); + } else if (event->message_type == ATOM(WM_PROTOCOLS)) { if (event->data.l[0] == (long) ATOM(_NET_WM_PING)) { MCompositeWindow *ping_source = COMPOSITE_WINDOW(event->data.l[2]); if (ping_source) { - bool was_hung = ping_source->status() == MCompositeWindow::HUNG; + bool was_hung = ping_source->status() == MCompositeWindow::Hung; ping_source->receivedPing(event->data.l[1]); - Q_ASSERT(ping_source->status() != MCompositeWindow::HUNG); + Q_ASSERT(ping_source->status() != MCompositeWindow::Hung); Window managed = MDecoratorFrame::instance()->managedWindow(); if (was_hung && ping_source->window() == managed && !ping_source->needDecoration()) { @@ -2103,7 +2113,7 @@ void MCompositeManagerPrivate::clientMessageEvent(XClientMessageEvent *event) MCompositeWindow *i = COMPOSITE_WINDOW(event->window); MCompositeWindow *d_item = COMPOSITE_WINDOW(stack[DESKTOP_LAYER]); - if (d_item && i) { + if (d_item && i && i->status() != MCompositeWindow::Minimizing) { d_item->setZValue(i->zValue() - 1); Window lower, topmost = getTopmostApp(); @@ -2161,7 +2171,37 @@ void MCompositeManagerPrivate::clientMessageEvent(XClientMessageEvent *event) rootMessageEvent(event); } -void MCompositeManagerPrivate::iconifyOnLower(MCompositeWindow *window) +void MCompositeManagerPrivate::closeHandler(MCompositeWindow *window) +{ + bool delete_sent = false; + if ((window->propertyCache()->supportedProtocols().indexOf( + ATOM(WM_DELETE_WINDOW)) != -1) && window->status() == MCompositeWindow::Normal) { + // send WM_DELETE_WINDOW message to the window that needs to close + XEvent ev; + memset(&ev, 0, sizeof(ev)); + + ev.xclient.type = ClientMessage; + ev.xclient.window = window->window(); + ev.xclient.message_type = ATOM(WM_PROTOCOLS); + ev.xclient.format = 32; + ev.xclient.data.l[0] = ATOM(WM_DELETE_WINDOW); + ev.xclient.data.l[1] = CurrentTime; + + XSendEvent(QX11Info::display(), window->window(), False, + NoEventMask, &ev); + // FIXME: we should check if desktop is exposed or not + setExposeDesktop(true); + delete_sent = true; + } + + if ((!delete_sent || window->status() == MCompositeWindow::Hung)) { + kill_window(window->window()); + MDecoratorFrame::instance()->lower(); + removeWindow(window->window()); + } +} + +void MCompositeManagerPrivate::lowerHandler(MCompositeWindow *window) { if (window->iconifyState() != MCompositeWindow::TransitionIconifyState) return; @@ -2187,7 +2227,7 @@ void MCompositeManagerPrivate::iconifyOnLower(MCompositeWindow *window) } } -void MCompositeManagerPrivate::raiseOnRestore(MCompositeWindow *window) +void MCompositeManagerPrivate::restoreHandler(MCompositeWindow *window) { Window last = getLastVisibleParent(window->propertyCache()); MCompositeWindow *to_stack; @@ -2262,16 +2302,16 @@ void MCompositeManagerPrivate::activateWindow(Window w, Time timestamp, // move it to the correct position in the stack positionWindow(to_stack->window(), STACK_TOP); // possibly set decorator - if (cw == getHighestDecorated() || cw->status() == MCompositeWindow::HUNG) { + if (cw == getHighestDecorated() || cw->status() == MCompositeWindow::Hung) { if (FULLSCREEN_WINDOW(cw)) { // fullscreen window has decorator above it during ongoing call // and when it's jammed MDecoratorFrame::instance()->setManagedWindow(cw, true); - if (cw->status() == MCompositeWindow::HUNG) + if (cw->status() == MCompositeWindow::Hung) MDecoratorFrame::instance()->setOnlyStatusbar(false); else MDecoratorFrame::instance()->setOnlyStatusbar(true); - } else if (cw->status() == MCompositeWindow::HUNG) { + } else if (cw->status() == MCompositeWindow::Hung) { MDecoratorFrame::instance()->setManagedWindow(cw, true); MDecoratorFrame::instance()->setOnlyStatusbar(false); } else { @@ -2575,10 +2615,8 @@ bool MCompositeManagerPrivate::isRedirected(Window w) bool MCompositeManagerPrivate::removeWindow(Window w) { - // remove it from MCompositeScene or we may try to paint it and crash - MCompositeWindow *cw = COMPOSITE_WINDOW(w); - if (cw) - watch->removeItem(cw); + // Item is already removed from scene when it is deleted + bool ret = true; windows_as_mapped.removeAll(w); if (windows.remove(w) == 0) @@ -2784,8 +2822,10 @@ void MCompositeManagerPrivate::addItem(MCompositeWindow *item) connect(item, SIGNAL(itemIconified(MCompositeWindow *)), SLOT(exposeDesktop())); connect(this, SIGNAL(compositingEnabled()), item, SLOT(startTransition())); - connect(item, SIGNAL(itemRestored(MCompositeWindow *)), SLOT(raiseOnRestore(MCompositeWindow *))); - connect(item, SIGNAL(itemIconified(MCompositeWindow *)), SLOT(iconifyOnLower(MCompositeWindow *))); + connect(item, SIGNAL(itemRestored(MCompositeWindow *)), SLOT(restoreHandler(MCompositeWindow *))); + connect(item, SIGNAL(itemIconified(MCompositeWindow *)), SLOT(lowerHandler(MCompositeWindow *))); + connect(item, SIGNAL(windowClosed(MCompositeWindow *)), SLOT(closeHandler(MCompositeWindow *))); + // ping protocol connect(item, SIGNAL(windowHung(MCompositeWindow *)), @@ -3072,3 +3112,5 @@ bool MCompositeManager::isCompositing() { return d->compositing; } + +#include "mcompositemanager.moc" diff --git a/src/mcompositemanager_p.h b/src/mcompositemanager_p.h index a45955c..2ae5c04 100644 --- a/src/mcompositemanager_p.h +++ b/src/mcompositemanager_p.h @@ -170,8 +170,11 @@ public slots: void disableCompositing(ForcingLevel forced = NO_FORCED); void showLaunchIndicator(int timeout); void hideLaunchIndicator(); - void iconifyOnLower(MCompositeWindow *window); - void raiseOnRestore(MCompositeWindow *window); + + void lowerHandler(MCompositeWindow *window); + void restoreHandler(MCompositeWindow *window); + void closeHandler(MCompositeWindow *window); + void onDesktopActivated(MCompositeWindow*); void exposeDesktop(); void enablePaintedCompositing(); diff --git a/src/mcompositewindow.cpp b/src/mcompositewindow.cpp index 218d6fb..49394f5 100644 --- a/src/mcompositewindow.cpp +++ b/src/mcompositewindow.cpp @@ -22,6 +22,7 @@ #include "mcompositemanager.h" #include "mcompositemanager_p.h" #include "mtexturepixmapitem.h" +#include "mdecoratorframe.h" #include <QX11Info> #include <QGraphicsScene> @@ -46,12 +47,12 @@ MCompositeWindow::MCompositeWindow(Qt::HANDLE window, iconified_final(false), iconify_state(NoIconifyState), destroyed(false), - process_status(NORMAL), + window_status(Normal), need_decor(false), window_obscured(true), // true to synthesize initial visibility event - is_closing(false), is_transitioning(false), pinging_enabled(false), + dimmed_effect(false), win_id(window) { thumb_mode = false; @@ -91,6 +92,7 @@ MCompositeWindow::MCompositeWindow(Qt::HANDLE window, // or it's corresponding thumbnail rendered by the switcher bool is_app = isAppWindow(); window_visible = !is_app; + setVisible(window_visible); newly_mapped = is_app; if (fadeRect.isEmpty()) { @@ -113,7 +115,12 @@ MCompositeWindow::~MCompositeWindow() is_transitioning = false; } anim = 0; - pc = 0; + + if (pc) { + MCompositeManager *p = (MCompositeManager *) qApp; + p->d->prop_caches.remove(window()); + pc->deleteLater(); + } } void MCompositeWindow::setBlurred(bool b) @@ -160,6 +167,9 @@ void MCompositeWindow::setThumbMode(bool mode) */ void MCompositeWindow::iconify(const QRectF &iconGeometry, bool defer) { + if (window_status != MCompositeWindow::Closing) + window_status = MCompositeWindow::Minimizing; + this->iconGeometry = iconGeometry; if (!iconified) origPosition = pos(); @@ -241,13 +251,14 @@ void MCompositeWindow::restore(const QRectF &iconGeometry, bool defer) } } -void MCompositeWindow::fadeIn() +void MCompositeWindow::showWindow() { // defer putting this window in the _NET_CLIENT_LIST // only after animation is done to prevent the switcher from rendering it if (!isAppWindow()) return; + findBehindWindow(); if (!is_transitioning) { ++window_transitioning; is_transitioning = true; @@ -274,22 +285,26 @@ void MCompositeWindow::q_fadeIn() newly_mapped = true; } -void MCompositeWindow::fadeOut() +void MCompositeWindow::closeWindow() { if (!isAppWindow()) { setVisible(false); + emit windowClosed(this); return; } + window_status = MCompositeWindow::Closing; MCompositeManager *p = (MCompositeManager *) qApp; bool defer = false; + setVisible(true); if (!p->isCompositing()) { - p->enableCompositing(); + p->d->enableCompositing(true); defer = true; } updateWindowPixmap(); - iconify(fadeRect, defer); + origPosition = pos(); + iconify(iconGeometry, defer); } void MCompositeWindow::deleteLater() @@ -321,12 +336,18 @@ void MCompositeWindow::finalizeState() hide(); iconify_state = TransitionIconifyState; emit itemIconified(this); + if (isClosing()) { + emit windowClosed(this); + QTimer::singleShot(200, this, SLOT(deleteLater())); + return; + } } else { iconify_state = NoIconifyState; iconified_final = false; show(); QTimer::singleShot(200, this, SLOT(q_itemRestored())); } + window_status = Normal; // item lifetime if (destroyed) @@ -403,9 +424,10 @@ void MCompositeWindow::manipulationEnabled(bool isEnabled) void MCompositeWindow::setVisible(bool visible) { - if (visible && newly_mapped && isAppWindow()) + if ((visible && newly_mapped && isAppWindow()) || + (!visible && is_transitioning)) return; - + // Set the iconification status as well iconified_final = !visible; if (visible != window_visible) @@ -443,7 +465,9 @@ void MCompositeWindow::stopPing() void MCompositeWindow::receivedPing(ulong serverTimeStamp) { received_ping_timestamp = serverTimeStamp; - process_status = NORMAL; + + if (window_status != Minimizing || window_status != Closing) + window_status = Normal; if (blurred()) setBlurred(false); } @@ -451,9 +475,11 @@ void MCompositeWindow::receivedPing(ulong serverTimeStamp) void MCompositeWindow::pingTimeout() { if (pinging_enabled && received_ping_timestamp < sent_ping_timestamp - && process_status != HUNG) { + && window_status != Hung) { setBlurred(true); - process_status = HUNG; + + if (window_status != Minimizing || window_status != Closing) + window_status = Hung; emit windowHung(this); } if (pinging_enabled) @@ -480,9 +506,9 @@ void MCompositeWindow::pingWindow() XSendEvent(QX11Info::display(), w, False, NoEventMask, &ev); } -MCompositeWindow::ProcessStatus MCompositeWindow::status() const +MCompositeWindow::WindowStatus MCompositeWindow::status() const { - return process_status; + return window_status; } bool MCompositeWindow::needDecoration() const @@ -526,15 +552,34 @@ QVariant MCompositeWindow::itemChange(GraphicsItemChange change, const QVariant { MCompositeManager *p = (MCompositeManager *) qApp; bool zvalChanged = (change == ItemZValueHasChanged); - if (zvalChanged) + if (zvalChanged) { + findBehindWindow(); p->d->setWindowDebugProperties(window()); - + } + if (zvalChanged || change == ItemVisibleHasChanged || change == ItemParentHasChanged) p->d->glwidget->update(); return QGraphicsItem::itemChange(change, value); } +void MCompositeWindow::findBehindWindow() +{ + MCompositeManager *p = (MCompositeManager *) qApp; + int behind_i = indexInStack() - 1; + if (behind_i >= 0 && behind_i < p->d->stacking_list.size()) { + MCompositeWindow* w = MCompositeWindow::compositeWindow(p->d->stacking_list.at(behind_i)); + if (w->propertyCache()->windowState() == NormalState + && w->propertyCache()->isMapped() + && !w->propertyCache()->isDecorator()) + behind_window = w; + else if (w->propertyCache()->isDecorator() && MDecoratorFrame::instance()->managedClient()) + behind_window = MDecoratorFrame::instance()->managedClient(); + else + behind_window = MCompositeWindow::compositeWindow(p->d->stack[DESKTOP_LAYER]); + } +} + void MCompositeWindow::update() { MCompositeManager *p = (MCompositeManager *) qApp; diff --git a/src/mcompositewindow.h b/src/mcompositewindow.h index 6a4291a..b4a1b33 100644 --- a/src/mcompositewindow.h +++ b/src/mcompositewindow.h @@ -22,6 +22,7 @@ #include <QGraphicsItem> #include <QtOpenGL> +#include <QPointer> #include <X11/Xutil.h> #include "mcompatoms_p.h" #include "mwindowpropertycache.h" @@ -42,10 +43,12 @@ class MCompositeWindow: public QObject, public QGraphicsItem #endif public: - - enum ProcessStatus { - NORMAL = 0, - HUNG + + enum WindowStatus { + Normal = 0, + Hung, + Minimizing, + Closing }; enum IconifyState { NoIconifyState = 0, @@ -204,9 +207,9 @@ public: bool wantsFocus(); /*! - * Returns if window is hung or not. + * Returns a WindowStatus enum of the current state of the window */ - ProcessStatus status() const; + WindowStatus status() const; // For _NET_WM_PING abstraction void startPing(); @@ -265,8 +268,7 @@ public: */ bool isAppWindow(bool include_transients = false); - void setClosing(bool closing) { is_closing = closing; } - bool isClosing() const { return is_closing; } + bool isClosing() const { return window_status == Closing; } MWindowPropertyCache *propertyCache() const { return pc; } @@ -279,6 +281,16 @@ public: * Returns the index of this window in the stacking list */ int indexInStack() const; + + /*! + * Returns whatever window is directly behind this window. 0 if there is none. + */ + MCompositeWindow* behind() const { return behind_window; } + + /*! Disabled alpha-blending for a dim-effect instead */ + void setDimmedEffect(bool dimmed) { dimmed_effect = dimmed; } + + bool dimmedEffect() const { return dimmed_effect; } public slots: @@ -286,9 +298,11 @@ public slots: void manipulationEnabled(bool isEnabled); void setUnBlurred(); void setBlurred(bool); - void fadeIn(); - void fadeOut(); - + + /* Operations with transition animations*/ + void closeWindow(); + void showWindow(); + private slots: /*! Called internally to update how this item looks when the transitions @@ -302,7 +316,7 @@ private slots: void q_delayShow(); void q_itemRestored(); void q_fadeIn(); - + signals: /*! * Emitted if this window is hung @@ -318,6 +332,8 @@ signals: void itemIconified(MCompositeWindow *window); /*! Emitted when desktop is raised */ void desktopActivated(MCompositeWindow *window); + /*! Emitted when this window is closed */ + void windowClosed(MCompositeWindow *window); protected: @@ -328,7 +344,10 @@ protected: virtual QPainterPath shape() const; private: - MWindowPropertyCache *pc; + void findBehindWindow(); + + QPointer<MWindowPropertyCache> pc; + QPointer<MCompositeWindow> behind_window; bool thumb_mode; MCompWindowAnimator *anim; qreal scalefrom; @@ -342,7 +361,7 @@ private: bool iconified_final; IconifyState iconify_state; bool destroyed; - ProcessStatus process_status; + WindowStatus window_status; bool need_decor; bool window_visible; bool window_obscured; @@ -351,6 +370,7 @@ private: bool is_closing; bool is_transitioning; bool pinging_enabled; + bool dimmed_effect; static int window_transitioning; diff --git a/src/mcompwindowanimator.cpp b/src/mcompwindowanimator.cpp index 303be3e..03b6979 100644 --- a/src/mcompwindowanimator.cpp +++ b/src/mcompwindowanimator.cpp @@ -36,7 +36,6 @@ MCompWindowAnimator::MCompWindowAnimator(MCompositeWindow *item) deferred_animation(false) { this->item = item; - timer.setCurveShape(QTimeLine::EaseInCurve); timer.setFrameRange(0, 2000); timer.setUpdateInterval(int(1000.0 / Fps)); @@ -73,6 +72,9 @@ void MCompWindowAnimator::restore() // item transition void MCompWindowAnimator::advanceFrame(qreal step) { +#define OPAQUE 1.0 +#define DIMMED 0.1 + //item->setTransform(QTransform(anim.matrixAt(step)) ); item->setTransform(matrix); @@ -80,10 +82,19 @@ void MCompWindowAnimator::advanceFrame(qreal step) anim.verticalScaleAt(step)); item->setPos(anim.posAt(step)); + qreal opac_norm = interpolate(step, OPAQUE, DIMMED); + qreal opac_rev = interpolate(step, DIMMED, OPAQUE); + // TODO: move calculation to GPU to imrpove speed - item->setOpacity(!reversed ? interpolate(step, 1.0, 0.1) : - interpolate(step, 0.1, 1.0)); - + // TODO: Use QPropertyAnimation instead + ((MCompositeWindow*)item)->setDimmedEffect(false); + item->setOpacity(!reversed ? opac_norm : opac_rev); + MCompositeWindow* behind = ((MCompositeWindow*)item)->behind(); + if (behind) { + behind->setDimmedEffect(true); + behind->setOpacity(!reversed ? opac_rev : opac_norm); + } + MCompositeManager *p = (MCompositeManager *) qApp; p->d->glwidget->update(); } @@ -97,11 +108,15 @@ void MCompWindowAnimator::translateScale(qreal fromSx, qreal fromSy, reversed = reverse; if (!reverse) { + timer.setCurveShape(QTimeLine::EaseInCurve); + anim.setScaleAt(0, fromSx, fromSy); anim.setScaleAt(1.0, toSx, toSy); anim.setPosAt(0, item->pos()); anim.setPosAt(1.0, newPos); } else { + timer.setCurveShape(QTimeLine::EaseOutCurve); + if (item->transform().m22() == 1.0 && item->transform().m11() == 1.0) item->scale(toSx, toSy); diff --git a/src/mtexturepixmapitem_egl.cpp b/src/mtexturepixmapitem_egl.cpp index dae8918..44e431e 100644 --- a/src/mtexturepixmapitem_egl.cpp +++ b/src/mtexturepixmapitem_egl.cpp @@ -329,10 +329,10 @@ void MTexturePixmapItem::paint(QPainter *painter, if (!d->ctx) d->ctx = const_cast<QGLContext *>(gl->context()); - if (propertyCache()->hasAlpha() || opacity() < 1.0f) { + if (propertyCache()->hasAlpha() || (opacity() < 1.0f && !dimmedEffect()) ) { glEnable(GL_BLEND); glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); - } + } glBindTexture(GL_TEXTURE_2D, d->custom_tfp ? d->ctextureId : d->textureId); const QRegion &shape = propertyCache()->shapeRegion(); diff --git a/src/mtexturepixmapitem_glx.cpp b/src/mtexturepixmapitem_glx.cpp index f2b3e94..cfbd09a 100644 --- a/src/mtexturepixmapitem_glx.cpp +++ b/src/mtexturepixmapitem_glx.cpp @@ -313,7 +313,7 @@ void MTexturePixmapItem::paint(QPainter *painter, #endif glEnable(GL_TEXTURE_2D); - if (propertyCache()->hasAlpha() || opacity() < 1.0f) { + if (propertyCache()->hasAlpha() || (opacity() < 1.0f && !dimmedEffect()) ) { glEnable(GL_BLEND); glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); glColor4f(1.0, 1.0, 1.0, opacity()); diff --git a/src/mwindowpropertycache.h b/src/mwindowpropertycache.h index 38df81a..020adaf 100644 --- a/src/mwindowpropertycache.h +++ b/src/mwindowpropertycache.h @@ -31,7 +31,7 @@ /*! * This is a class for caching window property values for a window. */ -class MWindowPropertyCache +class MWindowPropertyCache: public QObject { public: |