kwin/effects/flipswitch/flipswitch.cpp

960 lines
38 KiB
C++
Raw Normal View History

/********************************************************************
KWin - the KDE window manager
This file is part of the KDE project.
Copyright (C) 2008, 2009 Martin Gräßlin <kde@martin-graesslin.com>
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*********************************************************************/
#include "flipswitch.h"
#include <kwinconfig.h>
#include <QFont>
2011-03-13 15:56:25 +00:00
#include <QKeyEvent>
#include <QMatrix4x4>
#include <kconfiggroup.h>
#include <kdebug.h>
#include <KAction>
#include <KActionCollection>
#include <KLocale>
#include <kwinglutils.h>
#include <math.h>
namespace KWin
{
2011-01-30 14:34:42 +00:00
KWIN_EFFECT(flipswitch, FlipSwitchEffect)
KWIN_EFFECT_SUPPORTED(flipswitch, FlipSwitchEffect::supported())
FlipSwitchEffect::FlipSwitchEffect()
: m_currentAnimationShape(QTimeLine::EaseInOutCurve)
2011-01-30 14:34:42 +00:00
, m_active(false)
, m_start(false)
, m_stop(false)
, m_animation(false)
, m_hasKeyboardGrab(false)
, m_captionFrame(effects->effectFrame(EffectFrameStyled))
{
reconfigure(ReconfigureAll);
// Caption frame
2011-01-30 14:34:42 +00:00
m_captionFont.setBold(true);
m_captionFont.setPointSize(m_captionFont.pointSize() * 2);
m_captionFrame->setFont(m_captionFont);
m_captionFrame->enableCrossFade(true);
KActionCollection* actionCollection = new KActionCollection(this);
KAction* a = (KAction*)actionCollection->addAction("FlipSwitchCurrent");
a->setText(i18n("Toggle Flip Switch (Current desktop)"));
a->setGlobalShortcut(KShortcut(), KAction::ActiveShortcut);
m_shortcutCurrent = a->globalShortcut();
2011-01-30 14:34:42 +00:00
connect(a, SIGNAL(triggered(bool)), this, SLOT(toggleActiveCurrent()));
connect(a, SIGNAL(globalShortcutChanged(QKeySequence)), this, SLOT(globalShortcutChangedCurrent(QKeySequence)));
KAction* b = (KAction*)actionCollection->addAction("FlipSwitchAll");
b->setText(i18n("Toggle Flip Switch (All desktops)"));
b->setGlobalShortcut(KShortcut(), KAction::ActiveShortcut);
m_shortcutAll = b->globalShortcut();
2011-01-30 14:34:42 +00:00
connect(b, SIGNAL(triggered(bool)), this, SLOT(toggleActiveAllDesktops()));
connect(b, SIGNAL(globalShortcutChanged(QKeySequence)), this, SLOT(globalShortcutChangedAll(QKeySequence)));
connect(effects, SIGNAL(windowAdded(EffectWindow*)), this, SLOT(slotWindowAdded(EffectWindow*)));
connect(effects, SIGNAL(windowClosed(EffectWindow*)), this, SLOT(slotWindowClosed(EffectWindow*)));
connect(effects, SIGNAL(tabBoxAdded(int)), this, SLOT(slotTabBoxAdded(int)));
connect(effects, SIGNAL(tabBoxClosed()), this, SLOT(slotTabBoxClosed()));
connect(effects, SIGNAL(tabBoxUpdated()), this, SLOT(slotTabBoxUpdated()));
2011-01-30 14:34:42 +00:00
}
FlipSwitchEffect::~FlipSwitchEffect()
2011-01-30 14:34:42 +00:00
{
foreach (ElectricBorder border, m_borderActivate) {
effects->unreserveElectricBorder(border);
}
foreach (ElectricBorder border, m_borderActivateAll) {
effects->unreserveElectricBorder(border);
}
2011-01-30 14:34:42 +00:00
delete m_captionFrame;
}
bool FlipSwitchEffect::supported()
2011-01-30 14:34:42 +00:00
{
return effects->compositingType() == OpenGLCompositing;
2011-01-30 14:34:42 +00:00
}
2011-01-30 14:34:42 +00:00
void FlipSwitchEffect::reconfigure(ReconfigureFlags)
{
KConfigGroup conf = effects->effectConfig("FlipSwitch");
foreach (ElectricBorder border, m_borderActivate) {
effects->unreserveElectricBorder(border);
}
foreach (ElectricBorder border, m_borderActivateAll) {
effects->unreserveElectricBorder(border);
}
m_borderActivate.clear();
m_borderActivateAll.clear();
QList<int> borderList = QList<int>();
2011-01-30 14:34:42 +00:00
borderList.append(int(ElectricNone));
borderList = conf.readEntry("BorderActivate", borderList);
foreach (int i, borderList) {
m_borderActivate.append(ElectricBorder(i));
effects->reserveElectricBorder(ElectricBorder(i));
}
borderList.clear();
2011-01-30 14:34:42 +00:00
borderList.append(int(ElectricNone));
borderList = conf.readEntry("BorderActivateAll", borderList);
foreach (int i, borderList) {
m_borderActivateAll.append(ElectricBorder(i));
effects->reserveElectricBorder(ElectricBorder(i));
}
2011-01-30 14:34:42 +00:00
m_tabbox = conf.readEntry("TabBox", false);
m_tabboxAlternative = conf.readEntry("TabBoxAlternative", false);
float duration = animationTime(conf, "Duration", 200);
m_timeLine.setDuration(duration);
m_startStopTimeLine.setDuration(duration);
m_angle = conf.readEntry("Angle", 30);
m_xPosition = float(conf.readEntry("XPosition", 33)) / 100.0f;
m_yPosition = float(conf.readEntry("YPosition", 100)) / 100.0f;
m_windowTitle = conf.readEntry("WindowTitle", true);
}
void FlipSwitchEffect::prePaintScreen(ScreenPrePaintData& data, int time)
{
if (m_active) {
data.mask |= PAINT_SCREEN_WITH_TRANSFORMED_WINDOWS;
2011-01-30 14:34:42 +00:00
if (m_start)
m_startStopTimeLine.setCurrentTime(m_startStopTimeLine.currentTime() + time);
2011-01-30 14:34:42 +00:00
if (m_stop && m_scheduledDirections.isEmpty())
m_startStopTimeLine.setCurrentTime(m_startStopTimeLine.currentTime() - time);
2011-01-30 14:34:42 +00:00
if (m_animation)
m_timeLine.setCurrentTime(m_timeLine.currentTime() + time);
}
2011-01-30 14:34:42 +00:00
effects->prePaintScreen(data, time);
}
2011-01-30 14:34:42 +00:00
void FlipSwitchEffect::paintScreen(int mask, QRegion region, ScreenPaintData& data)
{
effects->paintScreen(mask, region, data);
if (m_active) {
EffectWindowList tempList;
2011-01-30 14:34:42 +00:00
if (m_mode == TabboxMode)
tempList = effects->currentTabBoxWindowList();
2011-01-30 14:34:42 +00:00
else {
// we have to setup the list
// using stacking order directly is not possible
// as not each window in stacking order is shown
// TODO: store list instead of calculating in each frame?
2011-01-30 14:34:42 +00:00
foreach (EffectWindow * w, effects->stackingOrder()) {
if (m_windows.contains(w))
tempList.append(w);
}
2011-01-30 14:34:42 +00:00
}
m_flipOrderedWindows.clear();
2011-01-30 14:34:42 +00:00
int index = tempList.indexOf(m_selectedWindow);
int tabIndex = index;
2011-01-30 14:34:42 +00:00
if (m_mode == TabboxMode) {
foreach (SwitchingDirection direction, m_scheduledDirections) { // krazy:exclude=foreach
if (direction == DirectionBackward)
index++;
else
index--;
2011-01-30 14:34:42 +00:00
if (index < 0)
index = tempList.count() + index;
2011-01-30 14:34:42 +00:00
if (index >= tempList.count())
index = index % tempList.count();
2011-01-30 14:34:42 +00:00
}
tabIndex = index;
EffectWindow* w = NULL;
2011-01-30 14:34:42 +00:00
if (!m_scheduledDirections.isEmpty() && m_scheduledDirections.head() == DirectionBackward) {
index--;
2011-01-30 14:34:42 +00:00
if (index < 0)
index = tempList.count() + index;
2011-01-30 14:34:42 +00:00
w = tempList.at(index);
}
for (int i = index - 1; i >= 0; i--)
m_flipOrderedWindows.append(tempList.at(i));
for (int i = effects->currentTabBoxWindowList().count() - 1; i >= index; i--)
m_flipOrderedWindows.append(tempList.at(i));
if (w) {
m_flipOrderedWindows.removeAll(w);
m_flipOrderedWindows.append(w);
}
} else {
foreach (SwitchingDirection direction, m_scheduledDirections) { // krazy:exclude=foreach
if (direction == DirectionForward)
index++;
else
index--;
2011-01-30 14:34:42 +00:00
if (index < 0)
index = tempList.count() - 1;
if (index >= tempList.count())
index = 0;
2011-01-30 14:34:42 +00:00
}
tabIndex = index;
EffectWindow* w = NULL;
2011-01-30 14:34:42 +00:00
if (!m_scheduledDirections.isEmpty() && m_scheduledDirections.head() == DirectionBackward) {
index++;
2011-01-30 14:34:42 +00:00
if (index >= tempList.count())
index = 0;
2011-01-30 14:34:42 +00:00
}
// sort from stacking order
2011-01-30 14:34:42 +00:00
for (int i = index + 1; i < tempList.count(); i++)
m_flipOrderedWindows.append(tempList.at(i));
for (int i = 0; i <= index; i++)
m_flipOrderedWindows.append(tempList.at(i));
if (w) {
m_flipOrderedWindows.removeAll(w);
m_flipOrderedWindows.append(w);
}
2011-01-30 14:34:42 +00:00
}
// multiscreen part taken from coverswitch.cpp
// TODO: move to kwinglutils
QMatrix4x4 origProjection;
QMatrix4x4 origModelview;
ShaderManager *shaderManager = ShaderManager::instance();
2011-01-30 14:34:42 +00:00
if (effects->numScreens() > 1) {
// unfortunatelly we have to change the projection matrix in dual screen mode
2011-01-30 14:34:42 +00:00
QRect fullRect = effects->clientArea(FullArea, effects->activeScreen(), effects->currentDesktop());
float fovy = 60.0f;
float aspect = 1.0f;
float zNear = 0.1f;
float zFar = 100.0f;
2011-01-30 14:34:42 +00:00
float ymax = zNear * tan(fovy * M_PI / 360.0f);
float ymin = -ymax;
float xmin = ymin * aspect;
float xmax = ymax * aspect;
float xTranslate = 0.0;
float yTranslate = 0.0;
float xminFactor = 1.0;
float xmaxFactor = 1.0;
float yminFactor = 1.0;
float ymaxFactor = 1.0;
2011-01-30 14:34:42 +00:00
if (m_screenArea.x() == 0 && m_screenArea.width() != fullRect.width()) {
// horizontal layout: left screen
2011-01-30 14:34:42 +00:00
xminFactor = (float)m_screenArea.width() / (float)fullRect.width();
xmaxFactor = ((float)fullRect.width() - (float)m_screenArea.width() * 0.5f) / ((float)fullRect.width() * 0.5f);
xTranslate = (float)fullRect.width() * 0.5f - (float)m_screenArea.width() * 0.5f;
}
if (m_screenArea.x() != 0 && m_screenArea.width() != fullRect.width()) {
// horizontal layout: right screen
2011-01-30 14:34:42 +00:00
xminFactor = ((float)fullRect.width() - (float)m_screenArea.width() * 0.5f) / ((float)fullRect.width() * 0.5f);
xmaxFactor = (float)m_screenArea.width() / (float)fullRect.width();
xTranslate = (float)fullRect.width() * 0.5f - (float)m_screenArea.width() * 0.5f;
}
if (m_screenArea.y() == 0 && m_screenArea.height() != fullRect.height()) {
// vertical layout: top screen
2011-01-30 14:34:42 +00:00
yminFactor = ((float)fullRect.height() - (float)m_screenArea.height() * 0.5f) / ((float)fullRect.height() * 0.5f);
ymaxFactor = (float)m_screenArea.height() / (float)fullRect.height();
yTranslate = (float)fullRect.height() * 0.5f - (float)m_screenArea.height() * 0.5f;
}
if (m_screenArea.y() != 0 && m_screenArea.height() != fullRect.height()) {
// vertical layout: bottom screen
2011-01-30 14:34:42 +00:00
yminFactor = (float)m_screenArea.height() / (float)fullRect.height();
ymaxFactor = ((float)fullRect.height() - (float)m_screenArea.height() * 0.5f) / ((float)fullRect.height() * 0.5f);
yTranslate = (float)fullRect.height() * 0.5f - (float)m_screenArea.height() * 0.5f;
}
QMatrix4x4 projection;
2011-01-30 14:34:42 +00:00
projection.frustum(xmin * xminFactor, xmax * xmaxFactor, ymin * yminFactor, ymax * ymaxFactor, zNear, zFar);
QMatrix4x4 modelview;
modelview.translate(xTranslate, yTranslate, 0.0);
if (shaderManager->isShaderBound()) {
GLShader *shader = shaderManager->pushShader(ShaderManager::GenericShader);
origProjection = shader->getUniformMatrix4x4("projection");
origModelview = shader->getUniformMatrix4x4("modelview");
shader->setUniform("projection", projection);
2011-01-30 14:34:42 +00:00
shader->setUniform("modelview", origModelview * modelview);
shaderManager->popShader();
} else {
#ifndef KWIN_HAVE_OPENGLES
glMatrixMode(GL_PROJECTION);
pushMatrix();
loadMatrix(projection);
glMatrixMode(GL_MODELVIEW);
pushMatrix(modelview);
#endif
}
2011-01-30 14:34:42 +00:00
}
int winMask = PAINT_WINDOW_TRANSFORMED | PAINT_WINDOW_TRANSLUCENT;
RotationData rot;
rot.axis = RotationData::YAxis;
rot.angle = m_angle * m_startStopTimeLine.currentValue();
// fade in/out one window at the end of the stack during animation
2011-01-30 14:34:42 +00:00
if (m_animation && !m_scheduledDirections.isEmpty()) {
EffectWindow* w = m_flipOrderedWindows.last();
if (ItemInfo *info = m_windows.value(w,0)) {
2011-01-30 14:34:42 +00:00
WindowPaintData data(w);
data.opacity = info->opacity;
data.brightness = info->brightness;
data.saturation = info->saturation;
int distance = tempList.count() - 1;
float zDistance = 500.0f;
data.xTranslate -= (w->x() - m_screenArea.x() + data.xTranslate) * m_startStopTimeLine.currentValue();
data.xTranslate += m_screenArea.width() * m_xPosition * m_startStopTimeLine.currentValue();
data.yTranslate += (m_screenArea.y() + m_screenArea.height() * m_yPosition - (w->y() + w->height() + data.yTranslate)) * m_startStopTimeLine.currentValue();
data.xTranslate -= (m_screenArea.width() * 0.25f) * distance * m_startStopTimeLine.currentValue();
data.yTranslate -= (m_screenArea.height() * 0.10f) * distance * m_startStopTimeLine.currentValue();
data.zTranslate -= (zDistance * distance) * m_startStopTimeLine.currentValue();
2011-01-30 14:34:42 +00:00
if (m_scheduledDirections.head() == DirectionForward)
data.opacity *= 0.8 * m_timeLine.currentValue();
else
data.opacity *= 0.8 * (1.0 - m_timeLine.currentValue());
2011-01-30 14:34:42 +00:00
if (effects->numScreens() > 1) {
adjustWindowMultiScreen(w, data);
}
2011-01-30 14:34:42 +00:00
data.rotation = &rot;
effects->drawWindow(w, winMask, infiniteRegion(), data);
}
2011-01-30 14:34:42 +00:00
}
foreach (EffectWindow *w, m_flipOrderedWindows) {
ItemInfo *info = m_windows.value(w,0);
if (!info)
continue;
2011-01-30 14:34:42 +00:00
WindowPaintData data(w);
data.opacity = info->opacity;
data.brightness = info->brightness;
data.saturation = info->saturation;
2011-01-30 14:34:42 +00:00
int windowIndex = tempList.indexOf(w);
int distance;
2011-01-30 14:34:42 +00:00
if (m_mode == TabboxMode) {
if (windowIndex < tabIndex)
distance = tempList.count() - (tabIndex - windowIndex);
2011-01-30 14:34:42 +00:00
else if (windowIndex > tabIndex)
distance = windowIndex - tabIndex;
else
distance = 0;
2011-01-30 14:34:42 +00:00
} else {
distance = m_flipOrderedWindows.count() - m_flipOrderedWindows.indexOf(w) - 1;
2011-01-30 14:34:42 +00:00
if (!m_scheduledDirections.isEmpty() && m_scheduledDirections.head() == DirectionBackward) {
distance--;
}
2011-01-30 14:34:42 +00:00
}
if (!m_scheduledDirections.isEmpty() && m_scheduledDirections.head() == DirectionBackward) {
if (w == m_flipOrderedWindows.last()) {
distance = -1;
data.opacity *= m_timeLine.currentValue();
}
2011-01-30 14:34:42 +00:00
}
float zDistance = 500.0f;
data.xTranslate -= (w->x() - m_screenArea.x() + data.xTranslate) * m_startStopTimeLine.currentValue();
data.xTranslate += m_screenArea.width() * m_xPosition * m_startStopTimeLine.currentValue();
data.yTranslate += (m_screenArea.y() + m_screenArea.height() * m_yPosition - (w->y() + w->height() + data.yTranslate)) * m_startStopTimeLine.currentValue();
data.xTranslate -= (m_screenArea.width() * 0.25f) * distance * m_startStopTimeLine.currentValue();
data.yTranslate -= (m_screenArea.height() * 0.10f) * distance * m_startStopTimeLine.currentValue();
data.zTranslate -= (zDistance * distance) * m_startStopTimeLine.currentValue();
2011-01-30 14:34:42 +00:00
if (m_animation && !m_scheduledDirections.isEmpty()) {
if (m_scheduledDirections.head() == DirectionForward) {
data.xTranslate += (m_screenArea.width() * 0.25f) * m_timeLine.currentValue();
data.yTranslate += (m_screenArea.height() * 0.10f) * m_timeLine.currentValue();
data.zTranslate += zDistance * m_timeLine.currentValue();
2011-01-30 14:34:42 +00:00
if (distance == 0)
data.opacity *= (1.0 - m_timeLine.currentValue());
2011-01-30 14:34:42 +00:00
} else {
data.xTranslate -= (m_screenArea.width() * 0.25f) * m_timeLine.currentValue();
data.yTranslate -= (m_screenArea.height() * 0.10f) * m_timeLine.currentValue();
data.zTranslate -= zDistance * m_timeLine.currentValue();
}
2011-01-30 14:34:42 +00:00
}
data.opacity *= (0.8 + 0.2 * (1.0 - m_startStopTimeLine.currentValue()));
2011-01-30 14:34:42 +00:00
if (effects->numScreens() > 1) {
adjustWindowMultiScreen(w, data);
}
data.rotation = &rot;
2011-01-30 14:34:42 +00:00
effects->drawWindow(w, winMask, infiniteRegion(), data);
}
2011-01-30 14:34:42 +00:00
if (effects->numScreens() > 1) {
if (shaderManager->isShaderBound()) {
GLShader *shader = shaderManager->pushShader(ShaderManager::GenericShader);
shader->setUniform("projection", origProjection);
shader->setUniform("modelview", origModelview);
shaderManager->popShader();
} else {
#ifndef KWIN_HAVE_OPENGLES
popMatrix();
// revert change of projection matrix
glMatrixMode(GL_PROJECTION);
popMatrix();
glMatrixMode(GL_MODELVIEW);
#endif
}
2011-01-30 14:34:42 +00:00
}
2011-01-30 14:34:42 +00:00
if (m_windowTitle) {
// Render the caption frame
2011-01-30 14:34:42 +00:00
if (m_animation) {
m_captionFrame->setCrossFadeProgress(m_timeLine.currentValue());
}
m_captionFrame->render(region, m_startStopTimeLine.currentValue());
}
}
2011-01-30 14:34:42 +00:00
}
void FlipSwitchEffect::postPaintScreen()
2011-01-30 14:34:42 +00:00
{
if (m_active) {
if (m_start && m_startStopTimeLine.currentValue() == 1.0f) {
m_start = false;
2011-01-30 14:34:42 +00:00
if (!m_scheduledDirections.isEmpty()) {
m_animation = true;
m_timeLine.setCurrentTime(0);
2011-01-30 14:34:42 +00:00
if (m_scheduledDirections.count() == 1) {
m_currentAnimationShape = QTimeLine::EaseOutCurve;
2011-01-30 14:34:42 +00:00
m_timeLine.setCurveShape(m_currentAnimationShape);
} else {
m_currentAnimationShape = QTimeLine::LinearCurve;
2011-01-30 14:34:42 +00:00
m_timeLine.setCurveShape(m_currentAnimationShape);
}
}
2011-01-30 14:34:42 +00:00
effects->addRepaintFull();
}
if (m_stop && m_startStopTimeLine.currentValue() == 0.0f) {
m_stop = false;
m_active = false;
m_captionFrame->free();
2011-01-30 14:34:42 +00:00
effects->setActiveFullScreenEffect(0);
effects->addRepaintFull();
2011-01-30 14:34:42 +00:00
qDeleteAll(m_windows);
m_windows.clear();
2011-01-30 14:34:42 +00:00
}
if (m_animation && m_timeLine.currentValue() == 1.0f) {
m_timeLine.setCurrentTime(0);
m_scheduledDirections.dequeue();
2011-01-30 14:34:42 +00:00
if (m_scheduledDirections.isEmpty()) {
m_animation = false;
effects->addRepaintFull();
2011-01-30 14:34:42 +00:00
} else {
if (m_scheduledDirections.count() == 1) {
if (m_stop)
m_currentAnimationShape = QTimeLine::LinearCurve;
else
m_currentAnimationShape = QTimeLine::EaseOutCurve;
2011-01-30 14:34:42 +00:00
} else {
m_currentAnimationShape = QTimeLine::LinearCurve;
}
2011-01-30 14:34:42 +00:00
m_timeLine.setCurveShape(m_currentAnimationShape);
}
}
2011-01-30 14:34:42 +00:00
if (m_start || m_stop || m_animation)
effects->addRepaintFull();
}
2011-01-30 14:34:42 +00:00
effects->postPaintScreen();
}
2011-01-30 14:34:42 +00:00
void FlipSwitchEffect::prePaintWindow(EffectWindow* w, WindowPrePaintData& data, int time)
{
if (m_active) {
if (m_windows.contains(w)) {
data.setTransformed();
data.setTranslucent();
2011-01-30 14:34:42 +00:00
if (!w->isOnCurrentDesktop())
w->enablePainting(EffectWindow::PAINT_DISABLED_BY_DESKTOP);
if (w->isMinimized())
w->enablePainting(EffectWindow::PAINT_DISABLED_BY_MINIMIZE);
if (!w->visibleInClientGroup())
w->enablePainting(EffectWindow::PAINT_DISABLED_BY_CLIENT_GROUP);
2011-01-30 14:34:42 +00:00
} else {
if ((m_start || m_stop) && !w->isDesktop() && w->isOnCurrentDesktop())
data.setTranslucent();
2011-01-30 14:34:42 +00:00
else if (!w->isDesktop())
w->disablePainting(EffectWindow::PAINT_DISABLED_BY_DESKTOP);
}
}
2011-01-30 14:34:42 +00:00
effects->prePaintWindow(w, data, time);
}
2011-01-30 14:34:42 +00:00
void FlipSwitchEffect::paintWindow(EffectWindow* w, int mask, QRegion region, WindowPaintData& data)
{
if (m_active) {
ItemInfo *info = m_windows.value(w,0);
if (info) {
info->opacity = data.opacity;
info->brightness = data.brightness;
info->saturation = data.saturation;
2011-01-30 14:34:42 +00:00
}
// fade out all windows not in window list except the desktops
const bool isFader = (m_start || m_stop) && !info && !w->isDesktop();
if (isFader)
data.opacity *= (1.0 - m_startStopTimeLine.currentValue());
// if not a fader or the desktop, skip painting here to prevent flicker
if (!(isFader || w->isDesktop()))
return;
}
effects->paintWindow(w, mask, region, data);
2011-01-30 14:34:42 +00:00
}
//*************************************************************
// Tabbox handling
//*************************************************************
void FlipSwitchEffect::slotTabBoxAdded(int mode)
2011-01-30 14:34:42 +00:00
{
if (effects->activeFullScreenEffect() && effects->activeFullScreenEffect() != this)
return;
// only for windows mode
2011-01-30 14:34:42 +00:00
if (((mode == TabBoxWindowsMode && m_tabbox) ||
(mode == TabBoxWindowsAlternativeMode && m_tabboxAlternative))
&& (!m_active || (m_active && m_stop))
&& !effects->currentTabBoxWindowList().isEmpty()) {
setActive(true, TabboxMode);
if (m_active)
effects->refTabBox();
}
2011-01-30 14:34:42 +00:00
}
void FlipSwitchEffect::slotTabBoxClosed()
2011-01-30 14:34:42 +00:00
{
if (m_active) {
setActive(false, TabboxMode);
effects->unrefTabBox();
}
2011-01-30 14:34:42 +00:00
}
void FlipSwitchEffect::slotTabBoxUpdated()
2011-01-30 14:34:42 +00:00
{
if (m_active && !m_stop) {
if (!effects->currentTabBoxWindowList().isEmpty()) {
// determine the switch direction
2011-01-30 14:34:42 +00:00
if (m_selectedWindow != effects->currentTabBoxWindow()) {
if (m_selectedWindow != NULL) {
int old_index = effects->currentTabBoxWindowList().indexOf(m_selectedWindow);
int new_index = effects->currentTabBoxWindowList().indexOf(effects->currentTabBoxWindow());
SwitchingDirection new_direction;
int distance = new_index - old_index;
2011-01-30 14:34:42 +00:00
if (distance > 0)
new_direction = DirectionForward;
2011-01-30 14:34:42 +00:00
if (distance < 0)
new_direction = DirectionBackward;
2011-01-30 14:34:42 +00:00
if (effects->currentTabBoxWindowList().count() == 2) {
new_direction = DirectionForward;
distance = 1;
2011-01-30 14:34:42 +00:00
}
if (distance != 0) {
distance = abs(distance);
int tempDistance = effects->currentTabBoxWindowList().count() - distance;
2011-01-30 14:34:42 +00:00
if (tempDistance < abs(distance)) {
distance = tempDistance;
2011-01-30 14:34:42 +00:00
if (new_direction == DirectionForward)
new_direction = DirectionBackward;
else
new_direction = DirectionForward;
}
2011-01-30 14:34:42 +00:00
scheduleAnimation(new_direction, distance);
}
}
2011-01-30 14:34:42 +00:00
m_selectedWindow = effects->currentTabBoxWindow();
m_captionFrame->setText(m_selectedWindow->caption());
m_captionFrame->setIcon(m_selectedWindow->icon());
}
}
2011-01-30 14:34:42 +00:00
effects->addRepaintFull();
}
2011-01-30 14:34:42 +00:00
}
//*************************************************************
// Window adding/removing handling
//*************************************************************
void FlipSwitchEffect::slotWindowAdded(EffectWindow* w)
2011-01-30 14:34:42 +00:00
{
if (m_active && isSelectableWindow(w)) {
m_windows[ w ] = new ItemInfo;
}
2011-01-30 14:34:42 +00:00
}
void FlipSwitchEffect::slotWindowClosed(EffectWindow* w)
2011-01-30 14:34:42 +00:00
{
if (m_selectedWindow == w)
m_selectedWindow = 0;
if (m_active) {
QHash< const EffectWindow*, ItemInfo* >::iterator it = m_windows.find(w);
if (it != m_windows.end()) {
delete *it;
m_windows.erase(it);
}
}
2011-01-30 14:34:42 +00:00
}
//*************************************************************
// Activation
//*************************************************************
2011-01-30 14:34:42 +00:00
void FlipSwitchEffect::setActive(bool activate, FlipSwitchMode mode)
{
if (activate) {
// effect already active, do some sanity checks
2011-01-30 14:34:42 +00:00
if (m_active) {
if (m_stop) {
if (mode != m_mode) {
// only the same mode may reactivate the effect
return;
}
2011-01-30 14:34:42 +00:00
} else {
// active, but not scheduled for closing -> abort
return;
}
2011-01-30 14:34:42 +00:00
}
m_mode = mode;
2011-01-30 14:34:42 +00:00
foreach (EffectWindow * w, effects->stackingOrder()) {
if (isSelectableWindow(w) && !m_windows.contains(w))
m_windows[ w ] = new ItemInfo;
2011-01-30 14:34:42 +00:00
}
if (m_windows.isEmpty())
return;
2011-01-30 14:34:42 +00:00
effects->setActiveFullScreenEffect(this);
m_active = true;
m_start = true;
m_startStopTimeLine.setCurveShape(QTimeLine::EaseInOutCurve);
m_activeScreen = effects->activeScreen();
2011-01-30 14:34:42 +00:00
m_screenArea = effects->clientArea(ScreenArea, m_activeScreen, effects->currentDesktop());
2011-01-30 14:34:42 +00:00
if (m_stop) {
// effect is still closing from last usage
m_stop = false;
2011-01-30 14:34:42 +00:00
} else {
// things to do only when there is no closing animation
m_scheduledDirections.clear();
2011-01-30 14:34:42 +00:00
}
2011-01-30 14:34:42 +00:00
switch(m_mode) {
case TabboxMode:
m_selectedWindow = effects->currentTabBoxWindow();
break;
case CurrentDesktopMode:
m_selectedWindow = effects->activeWindow();
m_input = effects->createFullScreenInputWindow(this, Qt::BlankCursor);
m_hasKeyboardGrab = effects->grabKeyboard(this);
break;
case AllDesktopsMode:
m_selectedWindow = effects->activeWindow();
m_input = effects->createFullScreenInputWindow(this, Qt::BlankCursor);
m_hasKeyboardGrab = effects->grabKeyboard(this);
break;
}
// Setup caption frame geometry
2011-01-30 14:34:42 +00:00
QRect frameRect = QRect(m_screenArea.width() * 0.25f + m_screenArea.x(),
m_screenArea.height() * 0.1f + m_screenArea.y() - QFontMetrics(m_captionFont).height(),
m_screenArea.width() * 0.5f,
QFontMetrics(m_captionFont).height());
m_captionFrame->setGeometry(frameRect);
m_captionFrame->setIconSize(QSize(frameRect.height(), frameRect.height()));
m_captionFrame->setText(m_selectedWindow->caption());
m_captionFrame->setIcon(m_selectedWindow->icon());
effects->addRepaintFull();
2011-01-30 14:34:42 +00:00
} else {
// only deactivate if mode is current mode
2011-01-30 14:34:42 +00:00
if (mode != m_mode)
return;
2011-01-30 14:34:42 +00:00
if (m_start && m_scheduledDirections.isEmpty()) {
m_start = false;
2011-01-30 14:34:42 +00:00
}
m_stop = true;
2011-01-30 14:34:42 +00:00
if (m_animation) {
m_startStopTimeLine.setCurveShape(QTimeLine::EaseOutCurve);
2011-01-30 14:34:42 +00:00
if (m_scheduledDirections.count() == 1) {
if (m_currentAnimationShape == QTimeLine::EaseInOutCurve)
m_currentAnimationShape = QTimeLine::EaseInCurve;
else if (m_currentAnimationShape == QTimeLine::EaseOutCurve)
m_currentAnimationShape = QTimeLine::LinearCurve;
2011-01-30 14:34:42 +00:00
m_timeLine.setCurveShape(m_currentAnimationShape);
}
2011-01-30 14:34:42 +00:00
} else
m_startStopTimeLine.setCurveShape(QTimeLine::EaseInOutCurve);
2011-01-30 14:34:42 +00:00
if (mode != TabboxMode)
effects->destroyInputWindow(m_input);
if (m_hasKeyboardGrab) {
effects->ungrabKeyboard();
m_hasKeyboardGrab = false;
}
2011-01-30 14:34:42 +00:00
effects->addRepaintFull();
}
2011-01-30 14:34:42 +00:00
}
void FlipSwitchEffect::toggleActiveAllDesktops()
2011-01-30 14:34:42 +00:00
{
if (m_active) {
if (m_stop) {
// reactivate if stopping
2011-01-30 14:34:42 +00:00
setActive(true, AllDesktopsMode);
} else {
// deactivate if not stopping
2011-01-30 14:34:42 +00:00
setActive(false, AllDesktopsMode);
}
2011-01-30 14:34:42 +00:00
} else {
setActive(true, AllDesktopsMode);
}
2011-01-30 14:34:42 +00:00
}
void FlipSwitchEffect::toggleActiveCurrent()
2011-01-30 14:34:42 +00:00
{
if (m_active) {
if (m_stop) {
// reactivate if stopping
2011-01-30 14:34:42 +00:00
setActive(true, CurrentDesktopMode);
} else {
// deactivate if not stopping
2011-01-30 14:34:42 +00:00
setActive(false, CurrentDesktopMode);
}
2011-01-30 14:34:42 +00:00
} else {
setActive(true, CurrentDesktopMode);
}
2011-01-30 14:34:42 +00:00
}
bool FlipSwitchEffect::borderActivated(ElectricBorder border)
2011-01-30 14:34:42 +00:00
{
if (!m_borderActivate.contains(border) && !m_borderActivateAll.contains(border))
return false;
2011-01-30 14:34:42 +00:00
if (effects->activeFullScreenEffect() && effects->activeFullScreenEffect() != this)
return true;
2011-01-30 14:34:42 +00:00
if (m_borderActivate.contains(border))
toggleActiveCurrent();
else
toggleActiveAllDesktops();
return true;
2011-01-30 14:34:42 +00:00
}
//*************************************************************
// Helper function
//*************************************************************
2011-01-30 14:34:42 +00:00
bool FlipSwitchEffect::isSelectableWindow(EffectWindow* w) const
{
// desktop windows might be included
2011-01-30 14:34:42 +00:00
if ((w->isSpecialWindow() && !w->isDesktop()) || w->isUtility())
return false;
2011-01-30 14:34:42 +00:00
if (w->isDesktop())
return (m_mode == TabboxMode && effects->currentTabBoxWindowList().contains(w));
if (w->isDeleted())
return false;
2011-01-30 14:34:42 +00:00
if (!w->acceptsFocus())
return false;
2011-01-30 14:34:42 +00:00
switch(m_mode) {
case TabboxMode:
return effects->currentTabBoxWindowList().contains(w);
case CurrentDesktopMode:
return w->isOnCurrentDesktop();
case AllDesktopsMode:
//nothing special
break;
}
2011-01-30 14:34:42 +00:00
return true;
}
2011-01-30 14:34:42 +00:00
void FlipSwitchEffect::scheduleAnimation(const SwitchingDirection& direction, int distance)
{
if (m_start) {
// start is still active so change the shape to have a nice transition
m_startStopTimeLine.setCurveShape(QTimeLine::EaseInCurve);
2011-01-30 14:34:42 +00:00
}
if (!m_animation && !m_start) {
m_animation = true;
2011-01-30 14:34:42 +00:00
m_scheduledDirections.enqueue(direction);
distance--;
// reset shape just to make sure
m_currentAnimationShape = QTimeLine::EaseInOutCurve;
2011-01-30 14:34:42 +00:00
m_timeLine.setCurveShape(m_currentAnimationShape);
}
for (int i = 0; i < distance; i++) {
if (m_scheduledDirections.count() > 1 && m_scheduledDirections.last() != direction)
m_scheduledDirections.pop_back();
else
2011-01-30 14:34:42 +00:00
m_scheduledDirections.enqueue(direction);
if (m_scheduledDirections.count() == m_windows.count() + 1) {
SwitchingDirection temp = m_scheduledDirections.dequeue();
m_scheduledDirections.clear();
2011-01-30 14:34:42 +00:00
m_scheduledDirections.enqueue(temp);
}
2011-01-30 14:34:42 +00:00
}
if (m_scheduledDirections.count() > 1) {
QTimeLine::CurveShape newShape = QTimeLine::EaseInOutCurve;
2011-01-30 14:34:42 +00:00
switch(m_currentAnimationShape) {
case QTimeLine::EaseInOutCurve:
newShape = QTimeLine::EaseInCurve;
2011-01-30 14:34:42 +00:00
break;
case QTimeLine::EaseOutCurve:
newShape = QTimeLine::LinearCurve;
2011-01-30 14:34:42 +00:00
break;
default:
newShape = m_currentAnimationShape;
}
if (newShape != m_currentAnimationShape) {
m_currentAnimationShape = newShape;
2011-01-30 14:34:42 +00:00
m_timeLine.setCurveShape(m_currentAnimationShape);
}
}
2011-01-30 14:34:42 +00:00
}
2011-01-30 14:34:42 +00:00
void FlipSwitchEffect::adjustWindowMultiScreen(const KWin::EffectWindow* w, WindowPaintData& data)
{
if (effects->numScreens() <= 1)
return;
2011-01-30 14:34:42 +00:00
QRect clientRect = effects->clientArea(FullScreenArea, w->screen(), effects->currentDesktop());
QRect rect = effects->clientArea(ScreenArea, m_activeScreen, effects->currentDesktop());
QRect fullRect = effects->clientArea(FullArea, m_activeScreen, effects->currentDesktop());
if (w->screen() == m_activeScreen) {
if (clientRect.width() != fullRect.width() && clientRect.x() != fullRect.x()) {
data.xTranslate -= clientRect.x();
2011-01-30 14:34:42 +00:00
}
if (clientRect.height() != fullRect.height() && clientRect.y() != fullRect.y()) {
data.yTranslate -= clientRect.y();
}
2011-01-30 14:34:42 +00:00
} else {
if (clientRect.width() != fullRect.width() && clientRect.x() < rect.x()) {
data.xTranslate -= clientRect.width();
2011-01-30 14:34:42 +00:00
}
if (clientRect.height() != fullRect.height() && clientRect.y() < m_screenArea.y()) {
data.yTranslate -= clientRect.height();
}
}
2011-01-30 14:34:42 +00:00
}
//*************************************************************
// Keyboard handling
//*************************************************************
2011-01-30 14:34:42 +00:00
void FlipSwitchEffect::globalShortcutChangedAll(QKeySequence shortcut)
{
m_shortcutAll = KShortcut(shortcut);
}
void FlipSwitchEffect::globalShortcutChangedCurrent(QKeySequence shortcut)
2011-01-30 14:34:42 +00:00
{
m_shortcutCurrent = KShortcut(shortcut);
}
void FlipSwitchEffect::grabbedKeyboardEvent(QKeyEvent* e)
2011-01-30 14:34:42 +00:00
{
if (e->type() == QEvent::KeyPress) {
// check for global shortcuts
// HACK: keyboard grab disables the global shortcuts so we have to check for global shortcut (bug 156155)
2011-01-30 14:34:42 +00:00
if (m_mode == CurrentDesktopMode && m_shortcutCurrent.contains(e->key() + e->modifiers())) {
toggleActiveCurrent();
return;
2011-01-30 14:34:42 +00:00
}
if (m_mode == AllDesktopsMode && m_shortcutAll.contains(e->key() + e->modifiers())) {
toggleActiveAllDesktops();
return;
2011-01-30 14:34:42 +00:00
}
2011-01-30 14:34:42 +00:00
switch(e->key()) {
case Qt::Key_Escape:
setActive(false, m_mode);
return;
case Qt::Key_Tab: {
// find next window
if (m_windows.isEmpty())
return; // sanity check
bool found = false;
for (int i = effects->stackingOrder().indexOf(m_selectedWindow) - 1; i >= 0; i--) {
if (isSelectableWindow(effects->stackingOrder().at(i))) {
m_selectedWindow = effects->stackingOrder().at(i);
found = true;
break;
}
}
if (!found) {
for (int i = effects->stackingOrder().count() - 1; i > effects->stackingOrder().indexOf(m_selectedWindow); i--) {
if (isSelectableWindow(effects->stackingOrder().at(i))) {
m_selectedWindow = effects->stackingOrder().at(i);
found = true;
break;
}
}
2011-01-30 14:34:42 +00:00
}
if (found) {
m_captionFrame->setText(m_selectedWindow->caption());
m_captionFrame->setIcon(m_selectedWindow->icon());
scheduleAnimation(DirectionForward);
}
break;
}
case Qt::Key_Backtab: {
// find previous window
if (m_windows.isEmpty())
return; // sanity check
bool found = false;
for (int i = effects->stackingOrder().indexOf(m_selectedWindow) + 1; i < effects->stackingOrder().count(); i++) {
if (isSelectableWindow(effects->stackingOrder().at(i))) {
m_selectedWindow = effects->stackingOrder().at(i);
found = true;
break;
}
}
if (!found) {
for (int i = 0; i < effects->stackingOrder().indexOf(m_selectedWindow); i++) {
if (isSelectableWindow(effects->stackingOrder().at(i))) {
m_selectedWindow = effects->stackingOrder().at(i);
found = true;
break;
}
}
}
2011-01-30 14:34:42 +00:00
if (found) {
m_captionFrame->setText(m_selectedWindow->caption());
m_captionFrame->setIcon(m_selectedWindow->icon());
scheduleAnimation(DirectionBackward);
}
break;
}
case Qt::Key_Return:
case Qt::Key_Enter:
case Qt::Key_Space:
if (m_selectedWindow)
effects->activateWindow(m_selectedWindow);
setActive(false, m_mode);
break;
default:
break;
}
2011-01-30 14:34:42 +00:00
effects->addRepaintFull();
}
2011-01-30 14:34:42 +00:00
}
bool FlipSwitchEffect::isActive() const
{
return m_active;
}
//*************************************************************
// Item Info
//*************************************************************
FlipSwitchEffect::ItemInfo::ItemInfo()
: deleted(false)
2011-01-30 14:34:42 +00:00
, opacity(0.0)
, brightness(0.0)
, saturation(0.0)
{
}
FlipSwitchEffect::ItemInfo::~ItemInfo()
2011-01-30 14:34:42 +00:00
{
}
} // namespace
#include "flipswitch.moc"