Strip QHash::operator[] from present window effect

also rewrite of the regular grid assignment - was
a) a suboptimal implementation
b) required because otherwise broken in desktopgrid proxy mode (which btw. polluted the effect through QHash::operator[])

BUG:262485
This commit is contained in:
Thomas Lübking 2011-03-08 00:19:52 +01:00
parent bfd922d7fa
commit 48939462da
2 changed files with 252 additions and 239 deletions

View file

@ -257,42 +257,47 @@ void PresentWindowsEffect::prePaintWindow(EffectWindow *w, WindowPrePaintData &d
{ {
// TODO: We should also check to see if any windows are fading just in case fading takes longer // TODO: We should also check to see if any windows are fading just in case fading takes longer
// than moving the windows when the effect is deactivated. // than moving the windows when the effect is deactivated.
if ((m_activated || m_motionManager.areWindowsMoving()) && m_windowData.contains(w)) { if (m_activated || m_motionManager.areWindowsMoving()) {
DataHash::iterator winData = m_windowData.find(w);
if (winData == m_windowData.end()) {
effects->prePaintWindow(w, data, time);
return;
}
w->enablePainting(EffectWindow::PAINT_DISABLED_BY_MINIMIZE); // Display always w->enablePainting(EffectWindow::PAINT_DISABLED_BY_MINIMIZE); // Display always
w->enablePainting(EffectWindow::PAINT_DISABLED_BY_DESKTOP); w->enablePainting(EffectWindow::PAINT_DISABLED_BY_DESKTOP);
if (m_windowData[w].visible) if (winData->visible)
w->enablePainting(EffectWindow::PAINT_DISABLED_BY_CLIENT_GROUP); w->enablePainting(EffectWindow::PAINT_DISABLED_BY_CLIENT_GROUP);
// Calculate window's opacity // Calculate window's opacity
// TODO: Minimized windows or windows not on the current desktop are only 75% visible? // TODO: Minimized windows or windows not on the current desktop are only 75% visible?
if (m_windowData[w].visible) { if (winData->visible) {
if (m_windowData[w].deleted) if (winData->deleted)
m_windowData[w].opacity = qMax(0.0, m_windowData[w].opacity - time / m_fadeDuration); winData->opacity = qMax(0.0, winData->opacity - time / m_fadeDuration);
else else
m_windowData[w].opacity = qMin(/*( w->isMinimized() || !w->isOnCurrentDesktop() ) ? 0.75 :*/ 1.0, winData->opacity = qMin(/*(w->isMinimized() || !w->isOnCurrentDesktop()) ? 0.75 :*/ 1.0,
m_windowData[w].opacity + time / m_fadeDuration); winData->opacity + time / m_fadeDuration);
} else } else
m_windowData[w].opacity = qMax(0.0, m_windowData[w].opacity - time / m_fadeDuration); winData->opacity = qMax(0.0, winData->opacity - time / m_fadeDuration);
if (m_windowData[w].opacity == 0.0) { if (winData->opacity <= 0.0) {
// don't disable painting for panels if show panel is set // don't disable painting for panels if show panel is set
if (!w->isDock() || (w->isDock() && !m_showPanel)) if (!(m_showPanel && w->isDock()))
w->disablePainting(EffectWindow::PAINT_DISABLED); w->disablePainting(EffectWindow::PAINT_DISABLED);
} else if (m_windowData[w].opacity != 1.0) } else if (winData->opacity != 1.0)
data.setTranslucent(); data.setTranslucent();
// Calculate window's brightness // Calculate window's brightness
if (w == m_highlightedWindow || w == m_closeWindow || !m_activated) if (w == m_highlightedWindow || w == m_closeWindow || !m_activated)
m_windowData[w].highlight = qMin(1.0, m_windowData[w].highlight + time / m_fadeDuration); winData->highlight = qMin(1.0, winData->highlight + time / m_fadeDuration);
else else
m_windowData[w].highlight = qMax(0.0, m_windowData[w].highlight - time / m_fadeDuration); winData->highlight = qMax(0.0, winData->highlight - time / m_fadeDuration);
// Closed windows // Closed windows
if (m_windowData[w].deleted) { if (winData->deleted) {
data.setTranslucent(); data.setTranslucent();
if (m_windowData[w].opacity <= 0.0 && m_windowData[w].referenced) { if (winData->opacity <= 0.0 && winData->referenced) {
// it's possible that another effect has referenced the window // it's possible that another effect has referenced the window
// we have to keep the window in the list to prevent flickering // we have to keep the window in the list to prevent flickering
m_windowData[w].referenced = false; winData->referenced = false;
w->unrefWindow(); w->unrefWindow();
} else } else
w->enablePainting(EffectWindow::PAINT_DISABLED_BY_DELETE); w->enablePainting(EffectWindow::PAINT_DISABLED_BY_DELETE);
@ -310,16 +315,17 @@ void PresentWindowsEffect::prePaintWindow(EffectWindow *w, WindowPrePaintData &d
void PresentWindowsEffect::paintWindow(EffectWindow *w, int mask, QRegion region, WindowPaintData &data) void PresentWindowsEffect::paintWindow(EffectWindow *w, int mask, QRegion region, WindowPaintData &data)
{ {
if ((m_activated || m_motionManager.areWindowsMoving()) && m_windowData.contains(w)) { if (m_activated || m_motionManager.areWindowsMoving()) {
if (w->isDock() && m_showPanel) { DataHash::const_iterator winData = m_windowData.find(w);
if (winData == m_windowData.constEnd() || (w->isDock() && m_showPanel)) {
// in case the panel should be shown just display it without any changes // in case the panel should be shown just display it without any changes
effects->paintWindow(w, mask, region, data); effects->paintWindow(w, mask, region, data);
return; return;
} }
// Apply opacity and brightness // Apply opacity and brightness
data.opacity *= m_windowData[w].opacity; data.opacity *= winData->opacity;
data.brightness *= interpolate(0.7, 1.0, m_windowData[w].highlight); data.brightness *= interpolate(0.7, 1.0, winData->highlight);
if (m_motionManager.isManaging(w)) { if (m_motionManager.isManaging(w)) {
m_motionManager.apply(w, data); m_motionManager.apply(w, data);
@ -333,7 +339,7 @@ void PresentWindowsEffect::paintWindow(EffectWindow *w, int mask, QRegion region
if (m_showIcons) { if (m_showIcons) {
QPoint point(rect.x() + rect.width() * 0.95, QPoint point(rect.x() + rect.width() * 0.95,
rect.y() + rect.height() * 0.95); rect.y() + rect.height() * 0.95);
m_windowData[w].iconFrame->setPosition(point); winData->iconFrame->setPosition(point);
#ifdef KWIN_HAVE_OPENGL_COMPOSITING #ifdef KWIN_HAVE_OPENGL_COMPOSITING
if (effects->compositingType() == KWin::OpenGLCompositing && data.shader) { if (effects->compositingType() == KWin::OpenGLCompositing && data.shader) {
const float a = 0.9 * data.opacity * m_decalOpacity * 0.75; const float a = 0.9 * data.opacity * m_decalOpacity * 0.75;
@ -342,12 +348,12 @@ void PresentWindowsEffect::paintWindow(EffectWindow *w, int mask, QRegion region
data.shader->setUniform(GLShader::ModulationConstant, QVector4D(a, a, a, a)); data.shader->setUniform(GLShader::ModulationConstant, QVector4D(a, a, a, a));
} }
#endif #endif
m_windowData[w].iconFrame->render(region, 0.9 * data.opacity * m_decalOpacity, 0.75); winData->iconFrame->render(region, 0.9 * data.opacity * m_decalOpacity, 0.75);
} }
if (m_showCaptions) { if (m_showCaptions) {
QPoint point(rect.x() + rect.width() / 2, QPoint point(rect.x() + rect.width() / 2,
rect.y() + rect.height() / 2); rect.y() + rect.height() / 2);
m_windowData[w].textFrame->setPosition(point); winData->textFrame->setPosition(point);
#ifdef KWIN_HAVE_OPENGL_COMPOSITING #ifdef KWIN_HAVE_OPENGL_COMPOSITING
if (effects->compositingType() == KWin::OpenGLCompositing && data.shader) { if (effects->compositingType() == KWin::OpenGLCompositing && data.shader) {
const float a = 0.9 * data.opacity * m_decalOpacity * 0.75; const float a = 0.9 * data.opacity * m_decalOpacity * 0.75;
@ -356,7 +362,7 @@ void PresentWindowsEffect::paintWindow(EffectWindow *w, int mask, QRegion region
data.shader->setUniform(GLShader::ModulationConstant, QVector4D(a, a, a, a)); data.shader->setUniform(GLShader::ModulationConstant, QVector4D(a, a, a, a));
} }
#endif #endif
m_windowData[w].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
effects->paintWindow(w, mask, region, data); effects->paintWindow(w, mask, region, data);
@ -371,24 +377,25 @@ void PresentWindowsEffect::slotWindowAdded(EffectWindow *w)
{ {
if (!m_activated) if (!m_activated)
return; return;
m_windowData[w].visible = isVisibleWindow(w); WindowData *winData = &m_windowData[w];
m_windowData[w].opacity = 0.0; winData->visible = isVisibleWindow(w);
m_windowData[w].highlight = 0.0; winData->opacity = 0.0;
m_windowData[w].textFrame = effects->effectFrame(EffectFrameUnstyled, false); winData->highlight = 0.0;
winData->textFrame = effects->effectFrame(EffectFrameUnstyled, false);
QFont font; QFont font;
font.setBold(true); font.setBold(true);
font.setPointSize(12); font.setPointSize(12);
m_windowData[w].textFrame->setFont(font); winData->textFrame->setFont(font);
m_windowData[w].iconFrame = effects->effectFrame(EffectFrameUnstyled, false); winData->iconFrame = effects->effectFrame(EffectFrameUnstyled, false);
m_windowData[w].iconFrame->setAlignment(Qt::AlignRight | Qt::AlignBottom); winData->iconFrame->setAlignment(Qt::AlignRight | Qt::AlignBottom);
m_windowData[w].iconFrame->setIcon(w->icon()); winData->iconFrame->setIcon(w->icon());
if (isSelectableWindow(w)) { if (isSelectableWindow(w)) {
m_motionManager.manage(w); m_motionManager.manage(w);
rearrangeWindows(); rearrangeWindows();
} }
if (w == effects->findWindow(m_closeView->winId())) { if (w == effects->findWindow(m_closeView->winId())) {
m_windowData[w].visible = true; winData->visible = true;
m_windowData[w].highlight = 1.0; winData->highlight = 1.0;
m_closeWindow = w; m_closeWindow = w;
w->setData(WindowForceBlurRole, QVariant(true)); w->setData(WindowForceBlurRole, QVariant(true));
} }
@ -398,10 +405,11 @@ void PresentWindowsEffect::slotWindowClosed(EffectWindow *w)
{ {
if (m_managerWindow == w) if (m_managerWindow == w)
m_managerWindow = NULL; m_managerWindow = NULL;
if (!m_windowData.contains(w)) DataHash::iterator winData = m_windowData.find(w);
if (winData == m_windowData.end())
return; return;
m_windowData[w].deleted = true; winData->deleted = true;
m_windowData[w].referenced = true; winData->referenced = true;
w->refWindow(); w->refWindow();
if (m_highlightedWindow == w) if (m_highlightedWindow == w)
setHighlightedWindow(findFirstWindow()); setHighlightedWindow(findFirstWindow());
@ -411,8 +419,8 @@ void PresentWindowsEffect::slotWindowClosed(EffectWindow *w)
} }
rearrangeWindows(); rearrangeWindows();
foreach (EffectWindow * w, m_motionManager.managedWindows()) { foreach (EffectWindow *w, m_motionManager.managedWindows()) {
DataHash::iterator winData = m_windowData.find( w ); winData = m_windowData.find(w);
if (winData != m_windowData.end() && !winData->deleted) if (winData != m_windowData.end() && !winData->deleted)
return; // found one that is not deleted? then we go on return; // found one that is not deleted? then we go on
} }
@ -421,11 +429,12 @@ void PresentWindowsEffect::slotWindowClosed(EffectWindow *w)
void PresentWindowsEffect::slotWindowDeleted(EffectWindow *w) void PresentWindowsEffect::slotWindowDeleted(EffectWindow *w)
{ {
if (!m_windowData.contains(w)) DataHash::iterator winData = m_windowData.find(w);
if (winData == m_windowData.end())
return; return;
delete m_windowData[w].textFrame; delete winData->textFrame;
delete m_windowData[w].iconFrame; delete winData->iconFrame;
m_windowData.remove(w); m_windowData.erase(winData);
m_motionManager.unmanage(w); m_motionManager.unmanage(w);
} }
@ -474,10 +483,12 @@ void PresentWindowsEffect::windowInputMouseEvent(Window w, QEvent *e)
// We cannot use m_motionManager.windowAtPoint() as the window might not be visible // We cannot use m_motionManager.windowAtPoint() as the window might not be visible
EffectWindowList windows = m_motionManager.managedWindows(); EffectWindowList windows = m_motionManager.managedWindows();
bool hovering = false; bool hovering = false;
for (int i = 0; i < windows.size(); i++) { for (int i = 0; i < windows.size(); ++i) {
assert(m_windowData.contains(windows.at(i))); DataHash::const_iterator winData = m_windowData.find(windows.at(i));
if (winData == m_windowData.constEnd())
continue;
if (m_motionManager.transformedGeometry(windows.at(i)).contains(cursorPos()) && if (m_motionManager.transformedGeometry(windows.at(i)).contains(cursorPos()) &&
m_windowData[windows.at(i)].visible && !m_windowData[windows.at(i)].deleted) { winData->visible && !winData->deleted) {
hovering = true; hovering = true;
if (windows.at(i) && m_highlightedWindow != windows.at(i)) if (windows.at(i) && m_highlightedWindow != windows.at(i))
setHighlightedWindow(windows.at(i)); setHighlightedWindow(windows.at(i));
@ -844,26 +855,26 @@ void PresentWindowsEffect::rearrangeWindows()
else else
windowlist = m_motionManager.managedWindows(); windowlist = m_motionManager.managedWindows();
foreach (EffectWindow * w, m_motionManager.managedWindows()) { foreach (EffectWindow * w, m_motionManager.managedWindows()) {
if (m_windowData[w].deleted) DataHash::iterator winData = m_windowData.find(w);
if (winData == m_windowData.end() || winData->deleted)
continue; // don't include closed windows continue; // don't include closed windows
windowlists[w->screen()].append(w); windowlists[w->screen()].append(w);
assert(m_windowData.contains(w)); winData->visible = true;
m_windowData[w].visible = true;
} }
} else { } else {
// Can we move this filtering somewhere else? // Can we move this filtering somewhere else?
foreach (EffectWindow * w, m_motionManager.managedWindows()) { foreach (EffectWindow * w, m_motionManager.managedWindows()) {
assert(m_windowData.contains(w)); DataHash::iterator winData = m_windowData.find(w);
if (m_windowData[w].deleted) if (winData == m_windowData.end() || winData->deleted)
continue; // don't include closed windows continue; // don't include closed windows
if (w->caption().contains(m_windowFilter, Qt::CaseInsensitive) || if (w->caption().contains(m_windowFilter, Qt::CaseInsensitive) ||
w->windowClass().contains(m_windowFilter, Qt::CaseInsensitive) || w->windowClass().contains(m_windowFilter, Qt::CaseInsensitive) ||
w->windowRole().contains(m_windowFilter, Qt::CaseInsensitive)) { w->windowRole().contains(m_windowFilter, Qt::CaseInsensitive)) {
windowlist.append(w); windowlist.append(w);
windowlists[w->screen()].append(w); windowlists[w->screen()].append(w);
m_windowData[w].visible = true; winData->visible = true;
} else } else
m_windowData[w].visible = false; winData->visible = false;
} }
} }
if (windowlist.isEmpty()) { if (windowlist.isEmpty()) {
@ -873,8 +884,8 @@ void PresentWindowsEffect::rearrangeWindows()
// We filtered out the highlighted window // We filtered out the highlighted window
if (m_highlightedWindow) { if (m_highlightedWindow) {
assert(m_windowData.contains(m_highlightedWindow)); DataHash::iterator winData = m_windowData.find(m_highlightedWindow);
if (m_windowData[m_highlightedWindow].visible == false) if (winData != m_windowData.end() && !winData->visible)
setHighlightedWindow(findFirstWindow()); setHighlightedWindow(findFirstWindow());
} else if (m_tabBoxEnabled) } else if (m_tabBoxEnabled)
setHighlightedWindow(effects->currentTabBoxWindow()); setHighlightedWindow(effects->currentTabBoxWindow());
@ -911,12 +922,15 @@ void PresentWindowsEffect::rearrangeWindows()
// Resize text frames if required // Resize text frames if required
QFontMetrics* metrics = NULL; // All fonts are the same QFontMetrics* metrics = NULL; // All fonts are the same
foreach (EffectWindow * w, m_motionManager.managedWindows()) { foreach (EffectWindow * w, m_motionManager.managedWindows()) {
DataHash::iterator winData = m_windowData.find(w);
if (winData == m_windowData.end())
continue;
if (!metrics) if (!metrics)
metrics = new QFontMetrics(m_windowData[w].textFrame->font()); metrics = new QFontMetrics(winData->textFrame->font());
QRect geom = m_motionManager.targetGeometry(w).toRect(); QRect geom = m_motionManager.targetGeometry(w).toRect();
QString string = metrics->elidedText(w->caption(), Qt::ElideRight, geom.width() * 0.9); QString string = metrics->elidedText(w->caption(), Qt::ElideRight, geom.width() * 0.9);
if (string != m_windowData[w].textFrame->text()) if (string != winData->textFrame->text())
m_windowData[w].textFrame->setText(string); winData->textFrame->setText(string);
} }
delete metrics; delete metrics;
} }
@ -936,6 +950,13 @@ void PresentWindowsEffect::calculateWindowTransformations(EffectWindowList windo
m_windowData.clear(); m_windowData.clear();
} }
static inline int distance(QPoint &pos1, QPoint &pos2)
{
const int xdiff = pos1.x() - pos2.x();
const int ydiff = pos1.y() - pos2.y();
return int(sqrt(float(xdiff*xdiff + ydiff*ydiff)));
}
void PresentWindowsEffect::calculateWindowTransformationsClosest(EffectWindowList windowlist, int screen, void PresentWindowsEffect::calculateWindowTransformationsClosest(EffectWindowList windowlist, int screen,
WindowMotionManager& motionManager) WindowMotionManager& motionManager)
{ {
@ -957,43 +978,68 @@ void PresentWindowsEffect::calculateWindowTransformationsClosest(EffectWindowLis
} }
// Assign slots // Assign slots
foreach (EffectWindow * w, windowlist) int slotWidth = area.width() / columns;
m_windowData[w].slot = -1; int slotHeight = area.height() / rows;
QVector<EffectWindow*> takenSlots;
takenSlots.resize(rows*columns);
takenSlots.fill(0);
if (m_tabBoxEnabled) { if (m_tabBoxEnabled) {
// Rearrange in the correct order. As rearrangeWindows() is only ever // Rearrange in the correct order. As rearrangeWindows() is only ever
// called once so we can use effects->currentTabBoxWindow() here. // called once so we can use effects->currentTabBoxWindow() here.
int selectedWindow = qMax(0, windowlist.indexOf(effects->currentTabBoxWindow())); int selectedWindow = qMax(0, windowlist.indexOf(effects->currentTabBoxWindow()));
int slot = 0; int j = 0;
for (int i = selectedWindow; i < windowlist.count(); i++) for (int i = selectedWindow; i < windowlist.count(); ++i)
m_windowData[windowlist[i]].slot = slot++; takenSlots[j++] = windowlist[i];
for (int i = selectedWindow - 1; i >= 0; i--) for (int i = selectedWindow - 1; i >= 0; --i)
m_windowData[windowlist[i]].slot = slot++; takenSlots[j++] = windowlist[i];
} else { } else {
for (;;) {
// Assign each window to the closest available slot // precalculate all slot centers
assignSlots(windowlist, area, columns, rows); QVector<QPoint> slotCenters;
// Leave only the closest window in each slot, remove further conflicts slotCenters.resize(rows*columns);
getBestAssignments(windowlist); for (int x = 0; x < columns; ++x)
bool allAssigned = true; for (int y = 0; y < rows; ++y) {
foreach (EffectWindow * w, windowlist) slotCenters[x + y*columns] = QPoint(area.x() + slotWidth * x + slotWidth / 2,
if (m_windowData[w].slot == -1) { area.y() + slotHeight * y + slotHeight / 2);
allAssigned = false;
break;
} }
if (allAssigned)
break; // Assign each window to the closest available slot
EffectWindowList tmpList = windowlist; // use a QLinkedList copy instead?
QPoint otherPos;
while (!tmpList.isEmpty()) {
EffectWindow *w = tmpList.first();
int slotCandidate = -1, slotCandidateDistance = INT_MAX;
QPoint pos = w->geometry().center();
for (int i = 0; i < columns*rows; ++i) { // all slots
const int dist = distance(pos, slotCenters[i]);
if (dist < slotCandidateDistance) { // window is interested in this slot
EffectWindow *occupier = takenSlots[i];
assert(occupier != w);
if (!occupier || dist < distance((otherPos = occupier->geometry().center()), slotCenters[i])) {
// either nobody lives here, or we're better - takeover the slot if it's our best
slotCandidate = i;
slotCandidateDistance = dist;
}
}
}
assert(slotCandidate != -1);
if (takenSlots[slotCandidate])
tmpList << takenSlots[slotCandidate]; // occupier needs a new home now :p
tmpList.removeAll(w);
takenSlots[slotCandidate] = w; // ...and we rumble in =)
} }
} }
int slotWidth = area.width() / columns; for (int slot = 0; slot < columns*rows; ++slot) {
int slotHeight = area.height() / rows; EffectWindow *w = takenSlots[slot];
foreach (EffectWindow * w, windowlist) { if (!w) // some slots might be empty
assert(m_windowData[w].slot != -1); continue;
// Work out where the slot is // Work out where the slot is
QRect target( QRect target(
area.x() + (m_windowData[w].slot % columns) * slotWidth, area.x() + (slot % columns) * slotWidth,
area.y() + (m_windowData[w].slot / columns) * slotHeight, area.y() + (slot / columns) * slotHeight,
slotWidth, slotHeight); slotWidth, slotHeight);
target.adjust(10, 10, -10, -10); // Borders target.adjust(10, 10, -10, -10); // Borders
double scale; double scale;
@ -1142,7 +1188,10 @@ void PresentWindowsEffect::calculateWindowTransformationsKompose(EffectWindowLis
EffectWindow* window = windowlist[pos]; EffectWindow* window = windowlist[pos];
QRect target = geometryRects[pos]; QRect target = geometryRects[pos];
target.setY(target.y() + topOffset); target.setY(target.y() + topOffset);
m_windowData[window].slot = pos; // @Marrtin: any idea what this is good for?
// DataHash::iterator winData = m_windowData.find(window);
// if (winData != m_windowData.end())
// winData->slot = pos;
motionManager.moveWindow(window, target); motionManager.moveWindow(window, target);
//kDebug(1212) << "Window '" << window->caption() << "' gets moved to (" << //kDebug(1212) << "Window '" << window->caption() << "' gets moved to (" <<
@ -1161,8 +1210,8 @@ void PresentWindowsEffect::calculateWindowTransformationsNatural(EffectWindowLis
// just have a single window on a Xinerama screen or have two windows that do not touch. // just have a single window on a Xinerama screen or have two windows that do not touch.
// TODO: Work out why this happens, is most likely a bug in the manager. // TODO: Work out why this happens, is most likely a bug in the manager.
foreach (EffectWindow * w, windowlist) foreach (EffectWindow * w, windowlist)
if (motionManager.transformedGeometry(w) == w->geometry()) if (motionManager.transformedGeometry(w) == w->geometry())
motionManager.reset(w); motionManager.reset(w);
if (windowlist.count() == 1) { if (windowlist.count() == 1) {
// Just move the window to its original location to save time // Just move the window to its original location to save time
@ -1200,26 +1249,29 @@ void PresentWindowsEffect::calculateWindowTransformationsNatural(EffectWindowLis
do { do {
overlap = false; overlap = false;
foreach (EffectWindow * w, windowlist) { foreach (EffectWindow * w, windowlist) {
QRect *target_w = &targets[w];
foreach (EffectWindow * e, windowlist) { foreach (EffectWindow * e, windowlist) {
if (w != e && targets[w].adjusted(-5, -5, 5, 5).intersects( if (w == e)
targets[e].adjusted(-5, -5, 5, 5))) { continue;
QRect *target_e = &targets[e];
if (target_w->adjusted(-5, -5, 5, 5).intersects(target_e->adjusted(-5, -5, 5, 5))) {
overlap = true; overlap = true;
// Determine pushing direction // Determine pushing direction
QPoint diff(targets[e].center() - targets[w].center()); QPoint diff(target_e->center() - target_w->center());
// Prevent dividing by zero and non-movement // Prevent dividing by zero and non-movement
if (diff.x() == 0 && diff.y() == 0) if (diff.x() == 0 && diff.y() == 0)
diff.setX(1); diff.setX(1);
// Try to keep screen aspect ratio // Try to keep screen aspect ratio
//if ( bounds.height() / bounds.width() > area.height() / area.width() ) //if (bounds.height() / bounds.width() > area.height() / area.width())
// diff.setY( diff.y() / 2 ); // diff.setY(diff.y() / 2);
//else //else
// diff.setX( diff.x() / 2 ); // diff.setX(diff.x() / 2);
// Approximate a vector of between 10px and 20px in magnitude in the same direction // Approximate a vector of between 10px and 20px in magnitude in the same direction
diff *= m_accuracy / double(diff.manhattanLength()); diff *= m_accuracy / double(diff.manhattanLength());
// Move both windows apart // Move both windows apart
targets[w].translate(-diff); target_w->translate(-diff);
targets[e].translate(diff); target_e->translate(diff);
// Try to keep the bounding rect the same aspect as the screen so that more // Try to keep the bounding rect the same aspect as the screen so that more
// screen real estate is utilised. We do this by splitting the screen into nine // screen real estate is utilised. We do this by splitting the screen into nine
@ -1231,8 +1283,8 @@ void PresentWindowsEffect::calculateWindowTransformationsNatural(EffectWindowLis
// in some situations. We need to do this even when expanding later just in case // in some situations. We need to do this even when expanding later just in case
// all windows are the same size. // all windows are the same size.
// (We are using an old bounding rect for this, hopefully it doesn't matter) // (We are using an old bounding rect for this, hopefully it doesn't matter)
int xSection = (targets[w].x() - bounds.x()) / (bounds.width() / 3); int xSection = (target_w->x() - bounds.x()) / (bounds.width() / 3);
int ySection = (targets[w].y() - bounds.y()) / (bounds.height() / 3); int ySection = (target_w->y() - bounds.y()) / (bounds.height() / 3);
diff = QPoint(0, 0); diff = QPoint(0, 0);
if (xSection != 1 || ySection != 1) { // Remove this if you want the center to pull as well if (xSection != 1 || ySection != 1) { // Remove this if you want the center to pull as well
if (xSection == 1) if (xSection == 1)
@ -1241,21 +1293,21 @@ void PresentWindowsEffect::calculateWindowTransformationsNatural(EffectWindowLis
ySection = (directions[w] % 2 ? 2 : 0); ySection = (directions[w] % 2 ? 2 : 0);
} }
if (xSection == 0 && ySection == 0) if (xSection == 0 && ySection == 0)
diff = QPoint(bounds.topLeft() - targets[w].center()); diff = QPoint(bounds.topLeft() - target_w->center());
if (xSection == 2 && ySection == 0) if (xSection == 2 && ySection == 0)
diff = QPoint(bounds.topRight() - targets[w].center()); diff = QPoint(bounds.topRight() - target_w->center());
if (xSection == 2 && ySection == 2) if (xSection == 2 && ySection == 2)
diff = QPoint(bounds.bottomRight() - targets[w].center()); diff = QPoint(bounds.bottomRight() - target_w->center());
if (xSection == 0 && ySection == 2) if (xSection == 0 && ySection == 2)
diff = QPoint(bounds.bottomLeft() - targets[w].center()); diff = QPoint(bounds.bottomLeft() - target_w->center());
if (diff.x() != 0 || diff.y() != 0) { if (diff.x() != 0 || diff.y() != 0) {
diff *= m_accuracy / double(diff.manhattanLength()); diff *= m_accuracy / double(diff.manhattanLength());
targets[w].translate(diff); target_w->translate(diff);
} }
// Update bounding rect // Update bounding rect
bounds = bounds.united(targets[w]); bounds = bounds.united(*target_w);
bounds = bounds.united(targets[e]); bounds = bounds.united(*target_e);
} }
} }
} }
@ -1279,13 +1331,15 @@ void PresentWindowsEffect::calculateWindowTransformationsNatural(EffectWindowLis
); );
// Move all windows back onto the screen and set their scale // Move all windows back onto the screen and set their scale
foreach (EffectWindow * w, windowlist) QHash<EffectWindow*, QRect>::iterator target = targets.begin();
targets[w] = QRect( while (target != targets.end()) {
(targets[w].x() - bounds.x()) * scale + area.x(), target->setRect((target->x() - bounds.x()) * scale + area.x(),
(targets[w].y() - bounds.y()) * scale + area.y(), (target->y() - bounds.y()) * scale + area.y(),
targets[w].width() * scale, target->width() * scale,
targets[w].height() * scale target->height() * scale
); );
++target;
}
// Try to fill the gaps by enlarging windows if they have the space // Try to fill the gaps by enlarging windows if they have the space
if (m_fillGaps) { if (m_fillGaps) {
@ -1298,61 +1352,61 @@ void PresentWindowsEffect::calculateWindowTransformationsNatural(EffectWindowLis
moved = false; moved = false;
foreach (EffectWindow * w, windowlist) { foreach (EffectWindow * w, windowlist) {
QRect oldRect; QRect oldRect;
QRect *target = &targets[w];
// This may cause some slight distortion if the windows are enlarged a large amount // This may cause some slight distortion if the windows are enlarged a large amount
int widthDiff = m_accuracy; int widthDiff = m_accuracy;
int heightDiff = heightForWidth(w, targets[w].width() + widthDiff) - targets[w].height(); int heightDiff = heightForWidth(w, target->width() + widthDiff) - target->height();
int xDiff = widthDiff / 2; // Also move a bit in the direction of the enlarge, allows the int xDiff = widthDiff / 2; // Also move a bit in the direction of the enlarge, allows the
int yDiff = heightDiff / 2; // center windows to be enlarged if there is gaps on the side. int yDiff = heightDiff / 2; // center windows to be enlarged if there is gaps on the side.
// Attempt enlarging to the top-right // Attempt enlarging to the top-right
oldRect = targets[w]; oldRect = *target;
targets[w] = QRect( target->setRect(target->x() + xDiff,
targets[w].x() + xDiff, target->y() - yDiff - heightDiff,
targets[w].y() - yDiff - heightDiff, target->width() + widthDiff,
targets[w].width() + widthDiff, target->height() + heightDiff
targets[w].height() + heightDiff );
);
if (isOverlappingAny(w, targets, borderRegion)) if (isOverlappingAny(w, targets, borderRegion))
targets[w] = oldRect; *target = oldRect;
else else
moved = true; moved = true;
// Attempt enlarging to the bottom-right // Attempt enlarging to the bottom-right
oldRect = targets[w]; oldRect = *target;
targets[w] = QRect( target->setRect(
targets[w].x() + xDiff, target->x() + xDiff,
targets[w].y() + yDiff, target->y() + yDiff,
targets[w].width() + widthDiff, target->width() + widthDiff,
targets[w].height() + heightDiff target->height() + heightDiff
); );
if (isOverlappingAny(w, targets, borderRegion)) if (isOverlappingAny(w, targets, borderRegion))
targets[w] = oldRect; *target = oldRect;
else else
moved = true; moved = true;
// Attempt enlarging to the bottom-left // Attempt enlarging to the bottom-left
oldRect = targets[w]; oldRect = *target;
targets[w] = QRect( target->setRect(
targets[w].x() - xDiff - widthDiff, target->x() - xDiff - widthDiff,
targets[w].y() + yDiff, target->y() + yDiff,
targets[w].width() + widthDiff, target->width() + widthDiff,
targets[w].height() + heightDiff target->height() + heightDiff
); );
if (isOverlappingAny(w, targets, borderRegion)) if (isOverlappingAny(w, targets, borderRegion))
targets[w] = oldRect; *target = oldRect;
else else
moved = true; moved = true;
// Attempt enlarging to the top-left // Attempt enlarging to the top-left
oldRect = targets[w]; oldRect = *target;
targets[w] = QRect( target->setRect(
targets[w].x() - xDiff - widthDiff, target->x() - xDiff - widthDiff,
targets[w].y() - yDiff - heightDiff, target->y() - yDiff - heightDiff,
targets[w].width() + widthDiff, target->width() + widthDiff,
targets[w].height() + heightDiff target->height() + heightDiff
); );
if (isOverlappingAny(w, targets, borderRegion)) if (isOverlappingAny(w, targets, borderRegion))
targets[w] = oldRect; *target = oldRect;
else else
moved = true; moved = true;
} }
@ -1362,12 +1416,13 @@ void PresentWindowsEffect::calculateWindowTransformationsNatural(EffectWindowLis
// We can't add this to the loop above as it would cause a never-ending loop so we have to make // We can't add this to the loop above as it would cause a never-ending loop so we have to make
// do with the less-than-optimal space usage with using this method. // do with the less-than-optimal space usage with using this method.
foreach (EffectWindow * w, windowlist) { foreach (EffectWindow * w, windowlist) {
double scale = targets[w].width() / double(w->width()); QRect *target = &targets[w];
double scale = target->width() / double(w->width());
if (scale > 2.0 || (scale > 1.0 && (w->width() > 300 || w->height() > 300))) { if (scale > 2.0 || (scale > 1.0 && (w->width() > 300 || w->height() > 300))) {
scale = (w->width() > 300 || w->height() > 300) ? 1.0 : 2.0; scale = (w->width() > 300 || w->height() > 300) ? 1.0 : 2.0;
targets[w] = QRect( target->setRect(
targets[w].center().x() - int(w->width() * scale) / 2, target->center().x() - int(w->width() * scale) / 2,
targets[w].center().y() - int(w->height() * scale) / 2, target->center().y() - int(w->height() * scale) / 2,
w->width() * scale, w->width() * scale,
w->height() * scale); w->height() * scale);
} }
@ -1376,76 +1431,23 @@ void PresentWindowsEffect::calculateWindowTransformationsNatural(EffectWindowLis
// Notify the motion manager of the targets // Notify the motion manager of the targets
foreach (EffectWindow * w, windowlist) foreach (EffectWindow * w, windowlist)
motionManager.moveWindow(w, targets[w]); motionManager.moveWindow(w, targets.value(w));
} }
//-----------------------------------------------------------------------------
// Helper functions for window rearranging
void PresentWindowsEffect::assignSlots(EffectWindowList windowlist, const QRect &area, int columns, int rows)
{
QVector< bool > taken;
taken.fill(false, columns * rows);
foreach (EffectWindow * w, windowlist)
if (m_windowData[w].slot != -1)
taken[ m_windowData[w].slot ] = true;
int slotWidth = area.width() / columns;
int slotHeight = area.height() / rows;
foreach (EffectWindow * w, windowlist) {
WindowData *wData = &m_windowData[w];
if (wData->slot != -1)
continue; // it already has a slot
QPoint pos = w->geometry().center();
if (pos.x() < area.left())
pos.setX(area.left());
if (pos.x() > area.right())
pos.setX(area.right());
if (pos.y() < area.top())
pos.setY(area.top());
if (pos.y() > area.bottom())
pos.setY(area.bottom());
int distance = INT_MAX;
for (int x = 0; x < columns; x++)
for (int y = 0; y < rows; y++) {
int slot = x + y * columns;
if (taken[slot])
continue;
int xdiff = pos.x() - (area.x() + slotWidth * x + slotWidth / 2);
int ydiff = pos.y() - (area.y() + slotHeight * y + slotHeight / 2);
int dist = int(sqrt(double(xdiff * xdiff + ydiff * ydiff)));
if (dist < distance) {
distance = dist;
wData->slot = slot;
wData->slot_distance = distance;
}
}
}
}
void PresentWindowsEffect::getBestAssignments(EffectWindowList windowlist)
{
foreach (EffectWindow * w1, windowlist) {
WindowData *windowData1 = &m_windowData[w1];
foreach (EffectWindow * w2, windowlist) {
WindowData *windowData2 = &m_windowData[w2];
if (w1 != w2 && windowData1->slot == windowData2->slot &&
windowData1->slot_distance >= windowData2->slot_distance)
windowData1->slot = -1;
}
}
}
bool PresentWindowsEffect::isOverlappingAny(EffectWindow *w, const QHash<EffectWindow*, QRect> &targets, const QRegion &border) bool PresentWindowsEffect::isOverlappingAny(EffectWindow *w, const QHash<EffectWindow*, QRect> &targets, const QRegion &border)
{ {
if (border.intersects(targets[w])) QHash<EffectWindow*, QRect>::const_iterator winTarget = targets.find(w);
if (winTarget == targets.constEnd())
return false;
if (border.intersects(*winTarget))
return true; return true;
// Is there a better way to do this? // Is there a better way to do this?
QHash<EffectWindow*, QRect>::const_iterator i; QHash<EffectWindow*, QRect>::const_iterator target;
for (i = targets.constBegin(); i != targets.constEnd(); ++i) { for (target = targets.constBegin(); target != targets.constEnd(); ++target) {
if (w == i.key()) if (target == winTarget)
continue; continue;
if (targets[w].adjusted(-5, -5, 5, 5).intersects( if (winTarget->adjusted(-5, -5, 5, 5).intersects(target->adjusted(-5, -5, 5, 5)))
i.value().adjusted(-5, -5, 5, 5)))
return true; return true;
} }
return false; return false;
@ -1475,37 +1477,44 @@ void PresentWindowsEffect::setActive(bool active, bool closingTab)
// Add every single window to m_windowData (Just calling [w] creates it) // Add every single window to m_windowData (Just calling [w] creates it)
foreach (EffectWindow * w, effects->stackingOrder()) { foreach (EffectWindow * w, effects->stackingOrder()) {
if (m_windowData.contains(w)) // Happens if we reactivate before the ending animation finishes DataHash::iterator winData;
continue; if ((winData = m_windowData.find(w)) != m_windowData.end()) {
m_windowData[w].visible = isVisibleWindow(w); winData->visible = isVisibleWindow(w);
m_windowData[w].deleted = false; continue; // Happens if we reactivate before the ending animation finishes
m_windowData[w].referenced = false; }
m_windowData[w].opacity = 0.0; winData = m_windowData.insert(w, WindowData());
winData->visible = isVisibleWindow(w);
winData->deleted = false;
winData->referenced = false;
winData->opacity = 0.0;
if (w->isOnCurrentDesktop() && !w->isMinimized()) if (w->isOnCurrentDesktop() && !w->isMinimized())
m_windowData[w].opacity = 1.0; winData->opacity = 1.0;
m_windowData[w].highlight = 1.0; winData->highlight = 1.0;
m_windowData[w].textFrame = effects->effectFrame(EffectFrameUnstyled, false); winData->textFrame = effects->effectFrame(EffectFrameUnstyled, false);
QFont font; QFont font;
font.setBold(true); font.setBold(true);
font.setPointSize(12); font.setPointSize(12);
m_windowData[w].textFrame->setFont(font); winData->textFrame->setFont(font);
m_windowData[w].iconFrame = effects->effectFrame(EffectFrameUnstyled, false); winData->iconFrame = effects->effectFrame(EffectFrameUnstyled, false);
m_windowData[w].iconFrame->setAlignment(Qt::AlignRight | Qt::AlignBottom); winData->iconFrame->setAlignment(Qt::AlignRight | Qt::AlignBottom);
m_windowData[w].iconFrame->setIcon(w->icon()); winData->iconFrame->setIcon(w->icon());
} }
if (m_tabBoxEnabled) { if (m_tabBoxEnabled) {
DataHash::iterator winData;
foreach (EffectWindow * w, effects->currentTabBoxWindowList()) { foreach (EffectWindow * w, effects->currentTabBoxWindowList()) {
if (!w) if (!w)
continue; continue;
m_motionManager.manage(w); m_motionManager.manage(w);
assert(m_windowData.contains(w)); if ((winData = m_windowData.find(w)) != m_windowData.end())
m_windowData[w].visible = effects->currentTabBoxWindowList().contains(w); winData->visible = effects->currentTabBoxWindowList().contains(w);
} }
// Hide windows not in the list // Hide windows not in the list
foreach (EffectWindow * w, effects->stackingOrder()) foreach (EffectWindow * w, effects->stackingOrder()) {
m_windowData[w].visible = isVisibleWindow(w) && if ((winData = m_windowData.find(w)) != m_windowData.end())
(!isSelectableWindow(w) || effects->currentTabBoxWindowList().contains(w)); winData->visible = isVisibleWindow(w) &&
(!isSelectableWindow(w) || effects->currentTabBoxWindowList().contains(w));
}
} else { } else {
// Filter out special windows such as panels and taskbars // Filter out special windows such as panels and taskbars
foreach (EffectWindow * w, effects->stackingOrder()) foreach (EffectWindow * w, effects->stackingOrder())
@ -1522,7 +1531,7 @@ void PresentWindowsEffect::setActive(bool active, bool closingTab)
while (i != m_windowData.end()) { while (i != m_windowData.end()) {
delete i.value().textFrame; delete i.value().textFrame;
delete i.value().iconFrame; delete i.value().iconFrame;
i++; ++i;
} }
m_windowData.clear(); m_windowData.clear();
@ -1536,7 +1545,7 @@ void PresentWindowsEffect::setActive(bool active, bool closingTab)
effects->setActiveFullScreenEffect(this); effects->setActiveFullScreenEffect(this);
m_gridSizes.clear(); m_gridSizes.clear();
for (int i = 0; i < effects->numScreens(); i++) for (int i = 0; i < effects->numScreens(); ++i)
m_gridSizes.append(GridSize()); m_gridSizes.append(GridSize());
rearrangeWindows(); rearrangeWindows();
@ -1559,9 +1568,10 @@ void PresentWindowsEffect::setActive(bool active, bool closingTab)
if (activeWindow && !activeWindow->isOnAllDesktops()) if (activeWindow && !activeWindow->isOnAllDesktops())
desktop = activeWindow->desktop(); desktop = activeWindow->desktop();
foreach (EffectWindow * w, effects->stackingOrder()) { foreach (EffectWindow * w, effects->stackingOrder()) {
assert(m_windowData.contains(w)); DataHash::iterator winData = m_windowData.find(w);
m_windowData[w].visible = (w->isOnDesktop(desktop) || w->isOnAllDesktops()) && if (winData != m_windowData.end())
!w->isMinimized() && (w->visibleInClientGroup() || m_windowData[w].visible); winData->visible = (w->isOnDesktop(desktop) || w->isOnAllDesktops()) &&
!w->isMinimized() && (w->visibleInClientGroup() || winData->visible);
} }
delete m_closeView; delete m_closeView;
m_closeView = 0; m_closeView = 0;
@ -1701,7 +1711,8 @@ EffectWindow* PresentWindowsEffect::relativeWindow(EffectWindow *w, int xdiff, i
detectRect = QRect(0, wArea.y(), area.width(), wArea.height()); detectRect = QRect(0, wArea.y(), area.width(), wArea.height());
next = NULL; next = NULL;
foreach (EffectWindow * e, m_motionManager.managedWindows()) { foreach (EffectWindow * e, m_motionManager.managedWindows()) {
if (!m_windowData[e].visible) DataHash::const_iterator winData = m_windowData.find(e);
if (winData == m_windowData.end() || !winData->visible)
continue; continue;
QRectF eArea = m_motionManager.transformedGeometry(e); QRectF eArea = m_motionManager.transformedGeometry(e);
if (eArea.intersects(detectRect) && if (eArea.intersects(detectRect) &&
@ -1730,7 +1741,8 @@ EffectWindow* PresentWindowsEffect::relativeWindow(EffectWindow *w, int xdiff, i
detectRect = QRect(0, wArea.y(), area.width(), wArea.height()); detectRect = QRect(0, wArea.y(), area.width(), wArea.height());
next = NULL; next = NULL;
foreach (EffectWindow * e, m_motionManager.managedWindows()) { foreach (EffectWindow * e, m_motionManager.managedWindows()) {
if (!m_windowData[e].visible) DataHash::const_iterator winData = m_windowData.find(e);
if (winData == m_windowData.end() || !winData->visible)
continue; continue;
QRectF eArea = m_motionManager.transformedGeometry(e); QRectF eArea = m_motionManager.transformedGeometry(e);
if (eArea.intersects(detectRect) && if (eArea.intersects(detectRect) &&
@ -1764,7 +1776,8 @@ EffectWindow* PresentWindowsEffect::relativeWindow(EffectWindow *w, int xdiff, i
detectRect = QRect(wArea.x(), 0, wArea.width(), area.height()); detectRect = QRect(wArea.x(), 0, wArea.width(), area.height());
next = NULL; next = NULL;
foreach (EffectWindow * e, m_motionManager.managedWindows()) { foreach (EffectWindow * e, m_motionManager.managedWindows()) {
if (!m_windowData[e].visible) DataHash::const_iterator winData = m_windowData.find(e);
if (winData == m_windowData.end() || !winData->visible)
continue; continue;
QRectF eArea = m_motionManager.transformedGeometry(e); QRectF eArea = m_motionManager.transformedGeometry(e);
if (eArea.intersects(detectRect) && if (eArea.intersects(detectRect) &&
@ -1793,7 +1806,8 @@ EffectWindow* PresentWindowsEffect::relativeWindow(EffectWindow *w, int xdiff, i
detectRect = QRect(wArea.x(), 0, wArea.width(), area.height()); detectRect = QRect(wArea.x(), 0, wArea.width(), area.height());
next = NULL; next = NULL;
foreach (EffectWindow * e, m_motionManager.managedWindows()) { foreach (EffectWindow * e, m_motionManager.managedWindows()) {
if (!m_windowData[e].visible) DataHash::const_iterator winData = m_windowData.find(e);
if (winData == m_windowData.end() || !winData->visible)
continue; continue;
QRectF eArea = m_motionManager.transformedGeometry(e); QRectF eArea = m_motionManager.transformedGeometry(e);
if (eArea.intersects(detectRect) && if (eArea.intersects(detectRect) &&
@ -1826,10 +1840,13 @@ EffectWindow* PresentWindowsEffect::findFirstWindow() const
EffectWindow *topLeft = NULL; EffectWindow *topLeft = NULL;
QRectF topLeftGeometry; QRectF topLeftGeometry;
foreach (EffectWindow * w, m_motionManager.managedWindows()) { foreach (EffectWindow * w, m_motionManager.managedWindows()) {
DataHash::const_iterator winData = m_windowData.find(w);
if (winData == m_windowData.end())
continue;
QRectF geometry = m_motionManager.transformedGeometry(w); QRectF geometry = m_motionManager.transformedGeometry(w);
if (m_windowData[w].visible == false) if (winData->visible == false)
continue; // Not visible continue; // Not visible
if (m_windowData[w].deleted) if (winData->deleted)
continue; // Window has been closed continue; // Window has been closed
if (topLeft == NULL) { if (topLeft == NULL) {
topLeft = w; topLeft = w;

View file

@ -74,8 +74,6 @@ private:
bool referenced; bool referenced;
double opacity; double opacity;
double highlight; double highlight;
int slot;
int slot_distance;
EffectFrame* textFrame; EffectFrame* textFrame;
EffectFrame* iconFrame; EffectFrame* iconFrame;
}; };
@ -185,8 +183,6 @@ protected:
inline int heightForWidth(EffectWindow *w, int width) { inline int heightForWidth(EffectWindow *w, int width) {
return int((width / double(w->width())) * w->height()); return int((width / double(w->width())) * w->height());
} }
void assignSlots(EffectWindowList windowlist, const QRect &area, int columns, int rows);
void getBestAssignments(EffectWindowList windowlist);
bool isOverlappingAny(EffectWindow *w, const QHash<EffectWindow*, QRect> &targets, const QRegion &border); bool isOverlappingAny(EffectWindow *w, const QHash<EffectWindow*, QRect> &targets, const QRegion &border);
// Filter box // Filter box