d245035a17
BUG: 290959 BUG: 265160 BUG: 229292 BUG: 238279 BUG: 290758 BUG: 222831 BUG: 278275 BUG: 245747 BUG: 230000 BUG: 253697 BUG: 230570 BUG: 265977 BUG: 225337 BUG: 225339 REVIEW: 103855
968 lines
38 KiB
C++
968 lines
38 KiB
C++
/********************************************************************
|
|
KWin - the KDE window manager
|
|
This file is part of the KDE project.
|
|
|
|
Copyright (C) 2007 Philip Falkner <philip.falkner@gmail.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 "boxswitch.h"
|
|
|
|
#include <kwinconfig.h>
|
|
|
|
#include <QMouseEvent>
|
|
#include <QSize>
|
|
|
|
#include <kapplication.h>
|
|
#include <kcolorscheme.h>
|
|
#include <kconfiggroup.h>
|
|
|
|
namespace KWin
|
|
{
|
|
|
|
KWIN_EFFECT(boxswitch, BoxSwitchEffect)
|
|
|
|
BoxSwitchEffect::BoxSwitchEffect()
|
|
: mActivated(0)
|
|
, mMode(0)
|
|
, thumbnailFrame(effects->effectFrame(EffectFrameStyled))
|
|
, selected_window(0)
|
|
, painting_desktop(0)
|
|
, animation(false)
|
|
, highlight_is_set(false)
|
|
, primaryTabBox(true)
|
|
, secondaryTabBox(false)
|
|
, mProxy(this)
|
|
, mProxyActivated(0)
|
|
, mProxyAnimateSwitch(0)
|
|
, mProxyShowText(0)
|
|
, mPositioningFactor(0.5f)
|
|
{
|
|
text_font.setBold(true);
|
|
text_font.setPointSize(12);
|
|
thumbnailFrame->setFont(text_font);
|
|
thumbnailFrame->setAlignment(Qt::AlignBottom | Qt::AlignHCenter);
|
|
|
|
highlight_margin = 10;
|
|
reconfigure(ReconfigureAll);
|
|
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()));
|
|
connect(effects, SIGNAL(windowGeometryShapeChanged(EffectWindow*,QRect)), this, SLOT(slotWindowGeometryShapeChanged(EffectWindow*,QRect)));
|
|
connect(effects, SIGNAL(windowDamaged(EffectWindow*,QRect)), this, SLOT(slotWindowDamaged(EffectWindow*,QRect)));
|
|
}
|
|
|
|
BoxSwitchEffect::~BoxSwitchEffect()
|
|
{
|
|
delete thumbnailFrame;
|
|
}
|
|
|
|
void BoxSwitchEffect::reconfigure(ReconfigureFlags)
|
|
{
|
|
color_frame = KColorScheme(QPalette::Active, KColorScheme::Window).background().color();
|
|
color_frame.setAlphaF(0.9);
|
|
color_highlight = KColorScheme(QPalette::Active, KColorScheme::Selection).background().color();
|
|
color_highlight.setAlphaF(0.9);
|
|
activeTimeLine.setDuration(animationTime(250));
|
|
activeTimeLine.setCurveShape(QTimeLine::EaseInOutCurve);
|
|
timeLine.setDuration(animationTime(150));
|
|
timeLine.setCurveShape(QTimeLine::EaseInOutCurve);
|
|
KConfigGroup conf = effects->effectConfig("BoxSwitch");
|
|
|
|
bg_opacity = conf.readEntry("BackgroundOpacity", 25) / 100.0;
|
|
elevate_window = conf.readEntry("ElevateSelected", true);
|
|
mAnimateSwitch = conf.readEntry("AnimateSwitch", false);
|
|
|
|
primaryTabBox = conf.readEntry("TabBox", false);
|
|
secondaryTabBox = conf.readEntry("TabBoxAlternative", false);
|
|
}
|
|
|
|
void BoxSwitchEffect::prePaintWindow(EffectWindow* w, WindowPrePaintData& data, int time)
|
|
{
|
|
if (activeTimeLine.currentValue() != 0.0 && !mProxyActivated) {
|
|
if (mMode == TabBoxWindowsMode || mMode == TabBoxWindowsAlternativeMode) {
|
|
if (windows.contains(w)) {
|
|
if (w == selected_window)
|
|
w->enablePainting(EffectWindow::PAINT_DISABLED_BY_TAB_GROUP);
|
|
else
|
|
data.setTranslucent();
|
|
w->enablePainting(EffectWindow::PAINT_DISABLED_BY_MINIMIZE | EffectWindow::PAINT_DISABLED_BY_DESKTOP);
|
|
}
|
|
} else {
|
|
if (painting_desktop) {
|
|
if (w->isOnDesktop(painting_desktop))
|
|
w->enablePainting(EffectWindow::PAINT_DISABLED_BY_DESKTOP);
|
|
else
|
|
w->disablePainting(EffectWindow::PAINT_DISABLED_BY_DESKTOP);
|
|
}
|
|
}
|
|
}
|
|
effects->prePaintWindow(w, data, time);
|
|
}
|
|
|
|
void BoxSwitchEffect::prePaintScreen(ScreenPrePaintData& data, int time)
|
|
{
|
|
if (mActivated)
|
|
activeTimeLine.setCurrentTime(activeTimeLine.currentTime() + time);
|
|
else {
|
|
activeTimeLine.setCurrentTime(activeTimeLine.currentTime() - time);
|
|
if (activeTimeLine.currentValue() == 0.0) {
|
|
// No longer need the window data
|
|
qDeleteAll(windows);
|
|
windows.clear();
|
|
}
|
|
}
|
|
if (mActivated && animation) {
|
|
timeLine.setCurrentTime(timeLine.currentTime() + time);
|
|
calculateItemSizes();
|
|
}
|
|
effects->prePaintScreen(data, time);
|
|
}
|
|
|
|
void BoxSwitchEffect::paintScreen(int mask, QRegion region, ScreenPaintData& data)
|
|
{
|
|
effects->paintScreen(mask, region, data);
|
|
if (mActivated && !mProxyActivated) {
|
|
if (mMode == TabBoxWindowsMode || mMode == TabBoxWindowsAlternativeMode) {
|
|
paintWindowsBox(region);
|
|
} else {
|
|
if (!painting_desktop) {
|
|
thumbnailFrame->setSelection(desktops[ selected_desktop ]->area);
|
|
thumbnailFrame->render(region);
|
|
|
|
QHash< int, ItemInfo* >::const_iterator i;
|
|
for (i = desktops.constBegin(); i != desktops.constEnd(); ++i) {
|
|
painting_desktop = i.key();
|
|
paintDesktopThumbnail(painting_desktop);
|
|
}
|
|
painting_desktop = 0;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
void BoxSwitchEffect::paintWindowsBox(const QRegion& region)
|
|
{
|
|
if ((mAnimateSwitch && !mProxyActivated) || (mProxyActivated && mProxyAnimateSwitch))
|
|
thumbnailFrame->setSelection(highlight_area);
|
|
else {
|
|
ItemInfo *info = windows.value(selected_window, 0);
|
|
thumbnailFrame->setSelection(info ? info->area : QRect());
|
|
}
|
|
thumbnailFrame->render(region);
|
|
|
|
if ((mAnimateSwitch && !mProxyActivated) || (mProxyActivated && mProxyAnimateSwitch)) {
|
|
// HACK: PaintClipper is used because window split is somehow wrong if the height is greater than width
|
|
PaintClipper::push(frame_area);
|
|
QHash< EffectWindow*, ItemInfo* >::const_iterator i;
|
|
for (i = windows.constBegin(); i != windows.constEnd(); ++i) {
|
|
paintWindowThumbnail(i.key());
|
|
paintWindowIcon(i.key());
|
|
}
|
|
PaintClipper::pop(frame_area);
|
|
} else {
|
|
QHash< EffectWindow*, ItemInfo* >::const_iterator i;
|
|
for (i = windows.constBegin(); i != windows.constEnd(); ++i) {
|
|
paintWindowThumbnail(i.key());
|
|
paintWindowIcon(i.key());
|
|
}
|
|
}
|
|
}
|
|
|
|
void BoxSwitchEffect::postPaintScreen()
|
|
{
|
|
if (mActivated && activeTimeLine.currentValue() != 1.0)
|
|
effects->addRepaintFull();
|
|
if (!mActivated && activeTimeLine.currentValue() != 0.0)
|
|
effects->addRepaintFull();
|
|
if (mActivated && animation) {
|
|
if (timeLine.currentValue() == 1.0) {
|
|
timeLine.setCurrentTime(0);
|
|
animation = false;
|
|
if (!scheduled_directions.isEmpty()) {
|
|
direction = scheduled_directions.dequeue();
|
|
animation = true;
|
|
}
|
|
}
|
|
QRect repaint = QRect(frame_area.x() - item_max_size.width() * 0.5,
|
|
frame_area.y(),
|
|
frame_area.width() + item_max_size.width(),
|
|
frame_area.height());
|
|
effects->addRepaint(repaint);
|
|
}
|
|
effects->postPaintScreen();
|
|
}
|
|
|
|
void BoxSwitchEffect::paintWindow(EffectWindow* w, int mask, QRegion region, WindowPaintData& data)
|
|
{
|
|
if (((mActivated && (mMode == TabBoxWindowsMode || mMode == TabBoxWindowsAlternativeMode))
|
|
|| (!mActivated && activeTimeLine.currentValue() != 0.0)) && !mProxyActivated) {
|
|
if (windows.contains(w) && w != selected_window) {
|
|
if (w->isMinimized() || !w->isOnCurrentDesktop())
|
|
// TODO: When deactivating minimized windows are not painted at all
|
|
data.opacity *= activeTimeLine.currentValue() * bg_opacity;
|
|
else
|
|
data.opacity *= 1.0 - activeTimeLine.currentValue() * (1.0 - bg_opacity);
|
|
}
|
|
}
|
|
effects->paintWindow(w, mask, region, data);
|
|
}
|
|
|
|
void BoxSwitchEffect::windowInputMouseEvent(Window w, QEvent* e)
|
|
{
|
|
assert(w == mInput);
|
|
Q_UNUSED(w);
|
|
if (e->type() != QEvent::MouseButtonPress)
|
|
return;
|
|
QPoint pos = static_cast< QMouseEvent* >(e)->pos();
|
|
pos += frame_area.topLeft();
|
|
|
|
// determine which item was clicked
|
|
if (mMode == TabBoxWindowsMode || mMode == TabBoxWindowsAlternativeMode) {
|
|
QHash< EffectWindow*, ItemInfo* >::const_iterator i;
|
|
for (i = windows.constBegin(); i != windows.constEnd(); ++i) {
|
|
if (i.value()->clickable.contains(pos)) {
|
|
effects->setTabBoxWindow(i.key());
|
|
break;
|
|
}
|
|
}
|
|
// special handling for second half of window in case of animation and even number of windows
|
|
if (mAnimateSwitch && (windows.size() % 2 == 0)) {
|
|
QRect additionalRect = QRect(frame_area.x(), frame_area.y(),
|
|
item_max_size.width() * 0.5, item_max_size.height());
|
|
if (additionalRect.contains(pos)) {
|
|
effects->setTabBoxWindow(right_window);
|
|
}
|
|
}
|
|
} else {
|
|
QHash< int, ItemInfo* >::const_iterator i;
|
|
for (i = desktops.constBegin(); i != desktops.constEnd(); ++i) {
|
|
if (i.value()->clickable.contains(pos))
|
|
effects->setTabBoxDesktop(i.key());
|
|
}
|
|
}
|
|
}
|
|
|
|
void BoxSwitchEffect::slotWindowDamaged(EffectWindow* w, const QRect& damage)
|
|
{
|
|
Q_UNUSED(damage);
|
|
if (mActivated) {
|
|
if (mMode == TabBoxWindowsMode || mMode == TabBoxWindowsAlternativeMode) {
|
|
if (windows.contains(w)) {
|
|
effects->addRepaint(frame_area);
|
|
}
|
|
} else {
|
|
if (w->isOnAllDesktops()) {
|
|
foreach (ItemInfo * info, desktops)
|
|
effects->addRepaint(info->area);
|
|
} else {
|
|
effects->addRepaint(desktops[ w->desktop()]->area);
|
|
}
|
|
}
|
|
#ifdef KWIN_HAVE_OPENGLES
|
|
// without full repaints, blur effect flickers on GLES, see BUG 272688
|
|
effects->addRepaintFull();
|
|
#endif
|
|
}
|
|
}
|
|
|
|
void BoxSwitchEffect::slotWindowGeometryShapeChanged(EffectWindow* w, const QRect& old)
|
|
{
|
|
if (mActivated) {
|
|
if (mMode == TabBoxWindowsMode || mMode == TabBoxWindowsAlternativeMode) {
|
|
ItemInfo *info = windows.value( w, 0L );
|
|
if (info && w->size() != old.size()) {
|
|
effects->addRepaint(info->area);
|
|
}
|
|
} else {
|
|
if (w->isOnAllDesktops()) {
|
|
foreach (ItemInfo * info, desktops)
|
|
effects->addRepaint(info->area);
|
|
} else {
|
|
effects->addRepaint(desktops[ w->desktop()]->area);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
void BoxSwitchEffect::slotTabBoxAdded(int mode)
|
|
{
|
|
if (!mActivated) {
|
|
if ((mode == TabBoxWindowsMode && primaryTabBox) ||
|
|
(mode == TabBoxWindowsAlternativeMode && secondaryTabBox)) {
|
|
if (effects->currentTabBoxWindowList().count() > 0) {
|
|
mMode = mode;
|
|
effects->refTabBox();
|
|
highlight_is_set = false;
|
|
animation = false;
|
|
scheduled_directions.clear();
|
|
right_window = 0;
|
|
setActive();
|
|
}
|
|
} else if (mode == TabBoxDesktopListMode || mode == TabBoxDesktopMode) {
|
|
// DesktopMode
|
|
if (effects->currentTabBoxDesktopList().count() > 0) {
|
|
mMode = mode;
|
|
painting_desktop = 0;
|
|
effects->refTabBox();
|
|
setActive();
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
void BoxSwitchEffect::slotTabBoxClosed()
|
|
{
|
|
if (mActivated)
|
|
setInactive();
|
|
}
|
|
|
|
void BoxSwitchEffect::slotTabBoxUpdated()
|
|
{
|
|
if (mActivated) {
|
|
if ((mMode == TabBoxWindowsMode || mMode == TabBoxWindowsAlternativeMode)
|
|
&& selected_window != effects->currentTabBoxWindow()) {
|
|
if (selected_window != NULL) {
|
|
if ((mAnimateSwitch && !mProxyActivated) || (mProxyActivated && mProxyAnimateSwitch)) {
|
|
int old_index = effects->currentTabBoxWindowList().indexOf(selected_window);
|
|
int new_index = effects->currentTabBoxWindowList().indexOf(effects->currentTabBoxWindow());
|
|
Direction new_direction;
|
|
int distance = new_index - old_index;
|
|
if (distance > 0)
|
|
new_direction = Left;
|
|
if (distance < 0)
|
|
new_direction = Right;
|
|
if (distance != 0) {
|
|
distance = abs(distance);
|
|
int tempDistance = effects->currentTabBoxWindowList().count() - distance;
|
|
if (tempDistance < abs(distance)) {
|
|
distance = tempDistance;
|
|
if (new_direction == Left)
|
|
new_direction = Right;
|
|
else
|
|
new_direction = Left;
|
|
}
|
|
if (!animation) {
|
|
animation = true;
|
|
direction = new_direction;
|
|
distance--;
|
|
}
|
|
for (int i = 0; i < distance; i++) {
|
|
if (!scheduled_directions.isEmpty() && scheduled_directions.last() != new_direction)
|
|
scheduled_directions.pop_back();
|
|
else
|
|
scheduled_directions.enqueue(new_direction);
|
|
if (scheduled_directions.count() == effects->currentTabBoxWindowList().count())
|
|
scheduled_directions.clear();
|
|
}
|
|
}
|
|
}
|
|
if (ItemInfo *info = windows.value(selected_window, 0))
|
|
effects->addRepaint(info->area);
|
|
selected_window->addRepaintFull();
|
|
}
|
|
setSelectedWindow(effects->currentTabBoxWindow());
|
|
if (ItemInfo *info = windows.value(selected_window, 0))
|
|
effects->addRepaint(info->area);
|
|
if (selected_window) // @Martin can effects->currentTabBoxWindow() be NULL?
|
|
selected_window->addRepaintFull();
|
|
effects->addRepaint(text_area);
|
|
} else if (mMode != TabBoxWindowsMode && mMode != TabBoxWindowsAlternativeMode) {
|
|
// DesktopMode
|
|
if (ItemInfo *info = desktops.value(selected_desktop, 0))
|
|
effects->addRepaint(info->area);
|
|
selected_desktop = effects->currentTabBoxDesktop();
|
|
if (!mProxyActivated || mProxyShowText)
|
|
thumbnailFrame->setText(effects->desktopName(selected_desktop));
|
|
if (ItemInfo *info = desktops.value(selected_desktop, 0))
|
|
effects->addRepaint(info->area);
|
|
effects->addRepaint(text_area);
|
|
if (effects->currentTabBoxDesktopList() == original_desktops)
|
|
return;
|
|
original_desktops = effects->currentTabBoxDesktopList();
|
|
}
|
|
// for safety copy list each time tabbox is updated
|
|
original_windows = effects->currentTabBoxWindowList();
|
|
effects->addRepaint(frame_area);
|
|
calculateFrameSize();
|
|
calculateItemSizes();
|
|
moveResizeInputWindow(frame_area.x(), frame_area.y(), frame_area.width(), frame_area.height());
|
|
effects->addRepaint(frame_area);
|
|
}
|
|
}
|
|
|
|
void BoxSwitchEffect::setActive()
|
|
{
|
|
mActivated = true;
|
|
|
|
// Just in case we are activated again before the deactivation animation finished
|
|
qDeleteAll(windows);
|
|
windows.clear();
|
|
|
|
if (mMode == TabBoxWindowsMode || mMode == TabBoxWindowsAlternativeMode) {
|
|
original_windows = effects->currentTabBoxWindowList();
|
|
setSelectedWindow(effects->currentTabBoxWindow());
|
|
} else {
|
|
original_desktops = effects->currentTabBoxDesktopList();
|
|
selected_desktop = effects->currentTabBoxDesktop();
|
|
if (!mProxyActivated || mProxyShowText)
|
|
thumbnailFrame->setText(effects->desktopName(selected_desktop));
|
|
}
|
|
calculateFrameSize();
|
|
calculateItemSizes();
|
|
if (!mProxyActivated) {
|
|
// only create the input window when effect is not activated via the proxy
|
|
mInput = effects->createInputWindow(this, frame_area.x(), frame_area.y(),
|
|
frame_area.width(), frame_area.height(), Qt::ArrowCursor);
|
|
}
|
|
effects->addRepaint(frame_area);
|
|
if (mMode == TabBoxWindowsMode || mMode == TabBoxWindowsAlternativeMode) {
|
|
QHash< EffectWindow*, ItemInfo* >::const_iterator i;
|
|
for (i = windows.constBegin(); i != windows.constEnd(); ++i) {
|
|
i.key()->addRepaintFull();
|
|
}
|
|
}
|
|
}
|
|
|
|
void BoxSwitchEffect::setInactive()
|
|
{
|
|
mActivated = false;
|
|
effects->unrefTabBox();
|
|
if (!mProxyActivated && mInput != None) {
|
|
effects->destroyInputWindow(mInput);
|
|
mInput = None;
|
|
}
|
|
mProxyActivated = false;
|
|
mPositioningFactor = 0.5f;
|
|
if (mMode == TabBoxWindowsMode || mMode == TabBoxWindowsAlternativeMode) {
|
|
QHash< EffectWindow*, ItemInfo* >::const_iterator i;
|
|
for (i = windows.constBegin(); i != windows.constEnd(); ++i) {
|
|
if (i.key() != selected_window)
|
|
i.key()->addRepaintFull();
|
|
}
|
|
// We don't unset the selected window so we have correct fading
|
|
// But we do need to remove elevation status
|
|
if (elevate_window && selected_window)
|
|
effects->setElevatedWindow(selected_window, false);
|
|
|
|
foreach (EffectWindow * w, referrencedWindows) {
|
|
w->unrefWindow();
|
|
}
|
|
referrencedWindows.clear();
|
|
} else {
|
|
// DesktopMode
|
|
qDeleteAll(windows);
|
|
desktops.clear();
|
|
}
|
|
thumbnailFrame->free();
|
|
effects->addRepaint(frame_area);
|
|
frame_area = QRect();
|
|
}
|
|
|
|
void BoxSwitchEffect::setSelectedWindow(EffectWindow* w)
|
|
{
|
|
if (elevate_window && selected_window) {
|
|
effects->setElevatedWindow(selected_window, false);
|
|
}
|
|
selected_window = w;
|
|
if (selected_window && (!mProxyActivated || mProxyShowText))
|
|
thumbnailFrame->setText(selected_window->caption());
|
|
if (elevate_window && w) {
|
|
effects->setElevatedWindow(selected_window, true);
|
|
}
|
|
}
|
|
|
|
void BoxSwitchEffect::slotWindowClosed(EffectWindow* w)
|
|
{
|
|
if (!mActivated) {
|
|
return;
|
|
}
|
|
if (w == selected_window) {
|
|
setSelectedWindow(0);
|
|
}
|
|
QHash<EffectWindow*, ItemInfo*>::iterator it = windows.find(w);
|
|
if (it != windows.end()) {
|
|
w->refWindow();
|
|
referrencedWindows.append(w);
|
|
original_windows.removeAll(w);
|
|
delete *it; *it = 0;
|
|
windows.erase( it );
|
|
effects->addRepaintFull();
|
|
}
|
|
}
|
|
|
|
void BoxSwitchEffect::moveResizeInputWindow(int x, int y, int width, int height)
|
|
{
|
|
XMoveWindow(display(), mInput, x, y);
|
|
XResizeWindow(display(), mInput, width, height);
|
|
}
|
|
|
|
void BoxSwitchEffect::calculateFrameSize()
|
|
{
|
|
int itemcount;
|
|
|
|
if (mMode == TabBoxWindowsMode || mMode == TabBoxWindowsAlternativeMode) {
|
|
itemcount = original_windows.count();
|
|
item_max_size.setWidth(200);
|
|
item_max_size.setHeight(200);
|
|
} else {
|
|
itemcount = original_desktops.count();
|
|
item_max_size.setWidth(200);
|
|
item_max_size.setHeight(200);
|
|
}
|
|
// How much height to reserve for a one-line text label
|
|
text_area.setHeight(QFontMetrics(text_font).height() * 1.2);
|
|
// Separator space between items and text
|
|
const int separator_height = 6;
|
|
// Shrink the size until all windows/desktops can fit onscreen
|
|
frame_area.setWidth(itemcount * item_max_size.width());
|
|
QRect screenr = effects->clientArea(PlacementArea, effects->activeScreen(), effects->currentDesktop());
|
|
while (frame_area.width() > screenr.width()) {
|
|
item_max_size /= 2;
|
|
frame_area.setWidth(itemcount * item_max_size.width());
|
|
}
|
|
frame_area.setHeight(item_max_size.height() +
|
|
separator_height + text_area.height());
|
|
if (mProxyActivated && !mProxyShowText)
|
|
frame_area.setHeight(item_max_size.height());
|
|
text_area.setWidth(frame_area.width());
|
|
|
|
frame_area.moveTo(screenr.x() + (screenr.width() - frame_area.width()) / 2,
|
|
screenr.y() + (screenr.height() - frame_area.height()) / 2 * mPositioningFactor * 2);
|
|
text_area.moveTo(frame_area.x(),
|
|
frame_area.y() + item_max_size.height() + separator_height);
|
|
|
|
thumbnailFrame->setGeometry(frame_area);
|
|
}
|
|
|
|
void BoxSwitchEffect::calculateItemSizes()
|
|
{
|
|
if (mMode == TabBoxWindowsMode || mMode == TabBoxWindowsAlternativeMode) {
|
|
qDeleteAll(windows);
|
|
windows.clear();
|
|
if ((mAnimateSwitch && !mProxyActivated) || (mProxyActivated && mProxyAnimateSwitch)) {
|
|
if (original_windows.isEmpty()) {
|
|
// can happen when last window is closed.
|
|
return;
|
|
}
|
|
int index = original_windows.indexOf(effects->currentTabBoxWindow());
|
|
int leftIndex = index;
|
|
int rightIndex = index + 1;
|
|
if (rightIndex == original_windows.count())
|
|
rightIndex = 0;
|
|
EffectWindowList ordered_windows;
|
|
|
|
int leftWindowCount = original_windows.count() / 2;
|
|
int rightWindowCount = leftWindowCount;
|
|
if (original_windows.count() % 2 == 1)
|
|
leftWindowCount++;
|
|
for (int i = 0; i < leftWindowCount; i++) {
|
|
int tempIndex = (leftIndex - i);
|
|
if (tempIndex < 0)
|
|
tempIndex = original_windows.count() + tempIndex;
|
|
ordered_windows.prepend(original_windows[ tempIndex ]);
|
|
}
|
|
for (int i = 0; i < rightWindowCount; i++) {
|
|
int tempIndex = (rightIndex + i) % original_windows.count();
|
|
ordered_windows.append(original_windows[ tempIndex ]);
|
|
}
|
|
// move items cause of schedule
|
|
for (int i = 0; i < scheduled_directions.count(); i++) {
|
|
Direction actual = scheduled_directions[ i ];
|
|
if (actual == Left) {
|
|
EffectWindow* w = ordered_windows.takeLast();
|
|
ordered_windows.prepend(w);
|
|
} else {
|
|
EffectWindow* w = ordered_windows.takeFirst();
|
|
ordered_windows.append(w);
|
|
}
|
|
}
|
|
if (animation && timeLine.currentValue() < 0.5) {
|
|
if (direction == Left) {
|
|
EffectWindow* w = ordered_windows.takeLast();
|
|
edge_window = w;
|
|
ordered_windows.prepend(w);
|
|
} else {
|
|
EffectWindow* w = ordered_windows.takeFirst();
|
|
edge_window = w;
|
|
ordered_windows.append(w);
|
|
}
|
|
} else if (animation && timeLine.currentValue() >= 0.5) {
|
|
if (animation && direction == Left)
|
|
edge_window = ordered_windows.last();
|
|
if (animation && direction == Right)
|
|
edge_window = ordered_windows.first();
|
|
}
|
|
int offset = 0;
|
|
if (animation) {
|
|
if (direction == Left)
|
|
offset = (float)item_max_size.width() * (1.0 - timeLine.currentValue());
|
|
else
|
|
offset = -(float)item_max_size.width() * (1.0 - timeLine.currentValue());
|
|
}
|
|
for (int i = 0; i < ordered_windows.count(); i++) {
|
|
if (!ordered_windows.at(i))
|
|
continue;
|
|
EffectWindow* w = ordered_windows.at(i);
|
|
ItemInfo *info = windows.value(w, 0);
|
|
if (!info)
|
|
windows[ w ] = info = new ItemInfo();
|
|
|
|
info->iconFrame = effects->effectFrame(EffectFrameUnstyled, false);
|
|
info->iconFrame->setAlignment(Qt::AlignTop | Qt::AlignLeft);
|
|
info->iconFrame->setIcon(w->icon());
|
|
|
|
float moveIndex = i;
|
|
if (animation && timeLine.currentValue() < 0.5) {
|
|
if (direction == Left)
|
|
moveIndex--;
|
|
else
|
|
moveIndex++;
|
|
}
|
|
if (ordered_windows.count() % 2 == 0)
|
|
moveIndex += 0.5;
|
|
info->area = QRect(frame_area.x() + moveIndex * item_max_size.width() + offset,
|
|
frame_area.y(),
|
|
item_max_size.width(), item_max_size.height());
|
|
info->clickable = info->area;
|
|
}
|
|
if (ordered_windows.count() % 2 == 0) {
|
|
right_window = ordered_windows.last();
|
|
}
|
|
if (!highlight_is_set) {
|
|
ItemInfo *info = windows.value(selected_window, 0);
|
|
highlight_area = info ? info->area : QRect();
|
|
highlight_is_set = true;
|
|
}
|
|
} else {
|
|
for (int i = 0; i < original_windows.count(); i++) {
|
|
if (!original_windows.at(i))
|
|
continue;
|
|
EffectWindow* w = original_windows.at(i);
|
|
ItemInfo *info = windows.value(w, 0);
|
|
if (!info)
|
|
windows[ w ] = info = new ItemInfo();
|
|
|
|
info->iconFrame = effects->effectFrame(EffectFrameUnstyled, false);
|
|
info->iconFrame->setAlignment(Qt::AlignTop | Qt::AlignLeft);
|
|
info->iconFrame->setIcon(w->icon());
|
|
|
|
info->area = QRect(frame_area.x() + i * item_max_size.width(),
|
|
frame_area.y(),
|
|
item_max_size.width(), item_max_size.height());
|
|
info->clickable = info->area;
|
|
}
|
|
}
|
|
} else {
|
|
desktops.clear();
|
|
for (int i = 0; i < original_desktops.count(); i++) {
|
|
int it = original_desktops.at(i);
|
|
ItemInfo *info = desktops.value( it, 0 );
|
|
if (!info)
|
|
desktops[ it ] = info = new ItemInfo();
|
|
|
|
info->area = QRect(frame_area.x() + i * item_max_size.width(),
|
|
frame_area.y(),
|
|
item_max_size.width(), item_max_size.height());
|
|
info->clickable = info->area;
|
|
}
|
|
}
|
|
}
|
|
|
|
void BoxSwitchEffect::paintWindowThumbnail(EffectWindow* w)
|
|
{
|
|
ItemInfo *info = windows.value(w, 0);
|
|
if (!info)
|
|
return;
|
|
WindowPaintData data(w);
|
|
|
|
setPositionTransformations(data,
|
|
info->thumbnail, w,
|
|
info->area.adjusted(highlight_margin, highlight_margin, -highlight_margin, -highlight_margin),
|
|
Qt::KeepAspectRatio);
|
|
|
|
if (animation && (w == edge_window) && (windows.size() % 2 == 1)) {
|
|
// in case of animation:
|
|
// the window which has to change the side will be split and painted on both sides of the edge
|
|
double splitPoint = 0.0;
|
|
if (direction == Left) {
|
|
splitPoint = w->geometry().width() * timeLine.currentValue();
|
|
} else {
|
|
splitPoint = w->geometry().width() - w->geometry().width() * timeLine.currentValue();
|
|
}
|
|
data.quads = data.quads.splitAtX(splitPoint);
|
|
WindowQuadList left_quads;
|
|
WindowQuadList right_quads;
|
|
foreach (const WindowQuad & quad, data.quads) {
|
|
if (quad.left() >= splitPoint)
|
|
left_quads << quad;
|
|
if (quad.right() <= splitPoint)
|
|
right_quads << quad;
|
|
}
|
|
// the base position of the window is changed after half of the animation
|
|
if (timeLine.currentValue() < 0.5) {
|
|
if (direction == Left)
|
|
data.quads = left_quads;
|
|
else
|
|
data.quads = right_quads;
|
|
} else {
|
|
if (direction == Left)
|
|
data.quads = right_quads;
|
|
else
|
|
data.quads = left_quads;
|
|
}
|
|
|
|
// paint one part of the thumbnail
|
|
effects->paintWindow(w,
|
|
PAINT_WINDOW_OPAQUE | PAINT_WINDOW_TRANSFORMED,
|
|
info->thumbnail, data);
|
|
|
|
QRect secondThumbnail;
|
|
|
|
// paint the second part of the thumbnail:
|
|
// the other window quads are needed and a new rect for transformation has to be calculated
|
|
if (direction == Left) {
|
|
if (timeLine.currentValue() < 0.5) {
|
|
data.quads = right_quads;
|
|
secondThumbnail = QRect(frame_area.x() + frame_area.width() -
|
|
(float)item_max_size.width() * timeLine.currentValue(),
|
|
frame_area.y(), item_max_size.width(), item_max_size.height());
|
|
} else {
|
|
data.quads = left_quads;
|
|
secondThumbnail = QRect(frame_area.x() - (float)item_max_size.width() * timeLine.currentValue(),
|
|
frame_area.y(), item_max_size.width(), item_max_size.height());
|
|
if (right_window)
|
|
secondThumbnail = QRect(frame_area.x() -
|
|
(float)item_max_size.width() * (timeLine.currentValue() - 0.5),
|
|
frame_area.y(), item_max_size.width(), item_max_size.height());
|
|
}
|
|
} else {
|
|
if (timeLine.currentValue() < 0.5) {
|
|
data.quads = left_quads;
|
|
secondThumbnail = QRect(frame_area.x() -
|
|
(float)item_max_size.width() * (1.0 - timeLine.currentValue()),
|
|
frame_area.y(), item_max_size.width(), item_max_size.height());
|
|
} else {
|
|
data.quads = right_quads;
|
|
secondThumbnail = QRect(frame_area.x() + frame_area.width() -
|
|
(float)item_max_size.width() * (1.0 - timeLine.currentValue()),
|
|
frame_area.y(), item_max_size.width(), item_max_size.height());
|
|
}
|
|
}
|
|
setPositionTransformations(data,
|
|
info->thumbnail, w,
|
|
secondThumbnail.adjusted(highlight_margin, highlight_margin, -highlight_margin, -highlight_margin),
|
|
Qt::KeepAspectRatio);
|
|
effects->paintWindow(w,
|
|
PAINT_WINDOW_OPAQUE | PAINT_WINDOW_TRANSFORMED,
|
|
info->thumbnail, data);
|
|
} else if ((windows.size() % 2 == 0) && (w == right_window)) {
|
|
// in case of even number of thumbnails:
|
|
// the window on the right is painted one half on left and on half on the right side
|
|
float animationOffset = 0.0f;
|
|
double splitPoint = w->geometry().width() * 0.5;
|
|
if (animation && timeLine.currentValue() <= 0.5) {
|
|
// in case of animation the right window has only to be split during first half of animation
|
|
if (direction == Left) {
|
|
splitPoint += w->geometry().width() * timeLine.currentValue();
|
|
animationOffset = -(float)item_max_size.width() * timeLine.currentValue();
|
|
} else {
|
|
splitPoint -= w->geometry().width() * timeLine.currentValue();
|
|
animationOffset = (float)item_max_size.width() * timeLine.currentValue();
|
|
}
|
|
}
|
|
if (animation && timeLine.currentValue() > 0.5) {
|
|
// at half of animation a different window has become the right window
|
|
// we have to adjust the splitting again
|
|
if (direction == Left) {
|
|
splitPoint -= w->geometry().width() * (1.0 - timeLine.currentValue());
|
|
animationOffset = (float)item_max_size.width() * (1.0 - timeLine.currentValue());
|
|
} else {
|
|
splitPoint += w->geometry().width() * (1.0 - timeLine.currentValue());
|
|
animationOffset = -(float)item_max_size.width() * (1.0 - timeLine.currentValue());
|
|
}
|
|
}
|
|
data.quads = data.quads.splitAtX(splitPoint);
|
|
WindowQuadList rightQuads;
|
|
WindowQuadList leftQuads;
|
|
foreach (const WindowQuad & quad, data.quads) {
|
|
if (quad.right() <= splitPoint)
|
|
leftQuads << quad;
|
|
else
|
|
rightQuads << quad;
|
|
}
|
|
|
|
// left quads are painted on right side of frame
|
|
data.quads = leftQuads;
|
|
effects->drawWindow(w,
|
|
PAINT_WINDOW_OPAQUE | PAINT_WINDOW_TRANSFORMED,
|
|
info->thumbnail, data);
|
|
|
|
// right quads are painted on left side of frame
|
|
data.quads = rightQuads;
|
|
QRect secondThumbnail;
|
|
secondThumbnail = QRect(frame_area.x() -
|
|
(float)item_max_size.width() * 0.5 + animationOffset,
|
|
frame_area.y(), item_max_size.width(), item_max_size.height());
|
|
setPositionTransformations(data,
|
|
info->thumbnail, w,
|
|
secondThumbnail.adjusted(highlight_margin, highlight_margin, -highlight_margin, -highlight_margin),
|
|
Qt::KeepAspectRatio);
|
|
effects->drawWindow(w,
|
|
PAINT_WINDOW_OPAQUE | PAINT_WINDOW_TRANSFORMED,
|
|
info->thumbnail, data);
|
|
} else {
|
|
effects->drawWindow(w,
|
|
PAINT_WINDOW_OPAQUE | PAINT_WINDOW_TRANSFORMED | PAINT_WINDOW_LANCZOS,
|
|
info->thumbnail, data);
|
|
}
|
|
}
|
|
|
|
void BoxSwitchEffect::paintDesktopThumbnail(int iDesktop)
|
|
{
|
|
ItemInfo *info = desktops.value(iDesktop, 0);
|
|
if (!info)
|
|
return;
|
|
|
|
ScreenPaintData data;
|
|
QRect region;
|
|
QRect r = info->area.adjusted(highlight_margin, highlight_margin, -highlight_margin, -highlight_margin);
|
|
QSize size = QSize(displayWidth(), displayHeight());
|
|
|
|
size.scale(r.size(), Qt::KeepAspectRatio);
|
|
data.xScale = size.width() / double(displayWidth());
|
|
data.yScale = size.height() / double(displayHeight());
|
|
int width = int(displayWidth() * data.xScale);
|
|
int height = int(displayHeight() * data.yScale);
|
|
int x = r.x() + (r.width() - width) / 2;
|
|
int y = r.y() + (r.height() - height) / 2;
|
|
region = QRect(x, y, width, height);
|
|
data.xTranslate = x;
|
|
data.yTranslate = y;
|
|
|
|
effects->paintScreen(PAINT_SCREEN_TRANSFORMED | PAINT_SCREEN_BACKGROUND_FIRST,
|
|
region, data);
|
|
}
|
|
|
|
void BoxSwitchEffect::paintWindowIcon(EffectWindow* w)
|
|
{
|
|
ItemInfo *info = windows.value(w, 0);
|
|
if (!info)
|
|
return;
|
|
// Don't render null icons
|
|
if (w->icon().isNull()) {
|
|
return;
|
|
}
|
|
|
|
int width = w->icon().width();
|
|
int height = w->icon().height();
|
|
int x = info->area.x() + info->area.width() - width - highlight_margin;
|
|
int y = info->area.y() + info->area.height() - height - highlight_margin;
|
|
if ((windows.size() % 2 == 0)) {
|
|
if (w == right_window) {
|
|
// in case of right window the icon has to be painted on the left side of the frame
|
|
x = frame_area.x() + info->area.width() * 0.5 - width - highlight_margin;
|
|
if (animation) {
|
|
if (timeLine.currentValue() <= 0.5) {
|
|
if (direction == Left) {
|
|
x -= info->area.width() * timeLine.currentValue();
|
|
x = qMax(x, frame_area.x());
|
|
} else
|
|
x += info->area.width() * timeLine.currentValue();
|
|
} else {
|
|
if (direction == Left)
|
|
x += info->area.width() * (1.0 - timeLine.currentValue());
|
|
else {
|
|
x -= info->area.width() * (1.0 - timeLine.currentValue());
|
|
x = qMax(x, frame_area.x());
|
|
}
|
|
}
|
|
}
|
|
}
|
|
} else {
|
|
// during animation the icon of the edge window has to change position
|
|
if (animation && w == edge_window) {
|
|
if (timeLine.currentValue() < 0.5) {
|
|
if (direction == Left)
|
|
x += info->area.width() * timeLine.currentValue();
|
|
else
|
|
x -= info->area.width() * timeLine.currentValue();
|
|
} else {
|
|
if (direction == Left)
|
|
x -= info->area.width() * (1.0 - timeLine.currentValue());
|
|
else
|
|
x += info->area.width() * (1.0 - timeLine.currentValue());
|
|
}
|
|
}
|
|
}
|
|
|
|
info->iconFrame->setPosition(QPoint(x, y));
|
|
info->iconFrame->render(infiniteRegion(), 1.0, 0.75);
|
|
}
|
|
|
|
void* BoxSwitchEffect::proxy()
|
|
{
|
|
return &mProxy;
|
|
}
|
|
|
|
void BoxSwitchEffect::activateFromProxy(int mode, bool animate, bool showText, float positioningFactor)
|
|
{
|
|
if (!mActivated) {
|
|
mProxyActivated = true;
|
|
mProxyAnimateSwitch = animate;
|
|
mProxyShowText = showText;
|
|
mPositioningFactor = positioningFactor;
|
|
thumbnailFrame->setText(" ");
|
|
if ((mode == TabBoxWindowsMode) || (mode == TabBoxWindowsAlternativeMode)) {
|
|
if (effects->currentTabBoxWindowList().count() > 0) {
|
|
mMode = mode;
|
|
effects->refTabBox();
|
|
highlight_is_set = false;
|
|
animation = false;
|
|
scheduled_directions.clear();
|
|
right_window = 0;
|
|
setActive();
|
|
}
|
|
} else if (mode == TabBoxDesktopListMode || mode == TabBoxDesktopMode) {
|
|
// DesktopMode
|
|
if (effects->currentTabBoxDesktopList().count() > 0) {
|
|
mMode = mode;
|
|
painting_desktop = 0;
|
|
effects->refTabBox();
|
|
setActive();
|
|
}
|
|
}
|
|
if (!mActivated)
|
|
mProxyActivated = false;
|
|
}
|
|
}
|
|
|
|
bool BoxSwitchEffect::isActive() const
|
|
{
|
|
return mActivated;
|
|
}
|
|
|
|
BoxSwitchEffect::ItemInfo::ItemInfo()
|
|
: iconFrame(NULL)
|
|
{
|
|
}
|
|
|
|
BoxSwitchEffect::ItemInfo::~ItemInfo()
|
|
{
|
|
delete iconFrame;
|
|
}
|
|
|
|
} // namespace
|