summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAbdiel Janulgue <abdiel.janulgue@nokia.com>2010-08-12 20:53:54 +0300
committerAbdiel Janulgue <abdiel.janulgue@nokia.com>2010-08-12 20:53:54 +0300
commit8a14b80d9984ed0e4b36280295602fa6b4023f8d (patch)
tree0f77e770e3c9ca9c1a733880d552470fc4e2c9cd
parentb5a3f7bc6734420fe926d4dfd66b9d7e923984c7 (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.cpp196
-rw-r--r--src/mcompositemanager_p.h7
-rw-r--r--src/mcompositewindow.cpp77
-rw-r--r--src/mcompositewindow.h48
-rw-r--r--src/mcompwindowanimator.cpp23
-rw-r--r--src/mtexturepixmapitem_egl.cpp4
-rw-r--r--src/mtexturepixmapitem_glx.cpp2
-rw-r--r--src/mwindowpropertycache.h2
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: