2020-08-02 22:22:19 +00:00
|
|
|
/*
|
|
|
|
KWin - the KDE window manager
|
|
|
|
This file is part of the KDE project.
|
2007-04-29 17:35:43 +00:00
|
|
|
|
2020-08-02 22:22:19 +00:00
|
|
|
SPDX-FileCopyrightText: 2007 Rivo Laks <rivolaks@hot.ee>
|
|
|
|
SPDX-FileCopyrightText: 2008 Lucas Murray <lmurray@undefinedfire.com>
|
2007-04-29 17:35:43 +00:00
|
|
|
|
2020-08-02 22:22:19 +00:00
|
|
|
SPDX-License-Identifier: GPL-2.0-or-later
|
|
|
|
*/
|
2007-04-29 17:35:43 +00:00
|
|
|
|
|
|
|
#include "presentwindows.h"
|
2012-09-13 06:49:13 +00:00
|
|
|
//KConfigSkeleton
|
|
|
|
#include "presentwindowsconfig.h"
|
2013-08-14 19:13:12 +00:00
|
|
|
#include <QAction>
|
2014-03-17 15:24:10 +00:00
|
|
|
#include <KGlobalAccel>
|
|
|
|
#include <KLocalizedString>
|
2007-04-29 17:35:43 +00:00
|
|
|
|
2009-05-01 20:41:38 +00:00
|
|
|
#include <kwinglutils.h>
|
|
|
|
|
2007-04-29 17:35:43 +00:00
|
|
|
#include <QMouseEvent>
|
2011-03-13 15:56:25 +00:00
|
|
|
#include <netwm_def.h>
|
2007-04-29 17:35:43 +00:00
|
|
|
|
2013-02-04 15:46:34 +00:00
|
|
|
#include <QApplication>
|
2013-08-05 12:08:23 +00:00
|
|
|
#include <QQmlContext>
|
|
|
|
#include <QQmlEngine>
|
|
|
|
#include <QQuickItem>
|
2013-10-25 10:57:34 +00:00
|
|
|
#include <QQuickView>
|
2013-03-11 08:33:38 +00:00
|
|
|
#include <QGraphicsObject>
|
2010-10-25 01:33:44 +00:00
|
|
|
#include <QTimer>
|
2012-05-28 10:00:31 +00:00
|
|
|
#include <QVector2D>
|
2011-02-12 09:14:30 +00:00
|
|
|
#include <QVector4D>
|
2007-04-29 17:35:43 +00:00
|
|
|
|
2019-07-09 19:19:26 +00:00
|
|
|
#include <climits>
|
|
|
|
#include <cmath>
|
|
|
|
|
2007-04-29 17:35:43 +00:00
|
|
|
namespace KWin
|
|
|
|
{
|
|
|
|
|
|
|
|
PresentWindowsEffect::PresentWindowsEffect()
|
2011-01-30 14:34:42 +00:00
|
|
|
: m_proxy(this)
|
|
|
|
, m_activated(false)
|
|
|
|
, m_ignoreMinimized(false)
|
|
|
|
, m_decalOpacity(0.0)
|
|
|
|
, m_hasKeyboardGrab(false)
|
|
|
|
, m_mode(ModeCurrentDesktop)
|
Use nullptr everywhere
Summary:
Because KWin is a very old project, we use three kinds of null pointer
literals: 0, NULL, and nullptr. Since C++11, it's recommended to use
nullptr keyword.
This change converts all usages of 0 and NULL literal to nullptr. Even
though it breaks git history, we need to do it in order to have consistent
code as well to ease code reviews (it's very tempting for some people to
add unrelated changes to their patches, e.g. converting NULL to nullptr).
Test Plan: Compiles.
Reviewers: #kwin, davidedmundson, romangg
Reviewed By: #kwin, davidedmundson, romangg
Subscribers: romangg, kwin
Tags: #kwin
Differential Revision: https://phabricator.kde.org/D23618
2019-09-19 14:46:54 +00:00
|
|
|
, m_managerWindow(nullptr)
|
2013-07-12 16:25:57 +00:00
|
|
|
, m_needInitialSelection(false)
|
Use nullptr everywhere
Summary:
Because KWin is a very old project, we use three kinds of null pointer
literals: 0, NULL, and nullptr. Since C++11, it's recommended to use
nullptr keyword.
This change converts all usages of 0 and NULL literal to nullptr. Even
though it breaks git history, we need to do it in order to have consistent
code as well to ease code reviews (it's very tempting for some people to
add unrelated changes to their patches, e.g. converting NULL to nullptr).
Test Plan: Compiles.
Reviewers: #kwin, davidedmundson, romangg
Reviewed By: #kwin, davidedmundson, romangg
Subscribers: romangg, kwin
Tags: #kwin
Differential Revision: https://phabricator.kde.org/D23618
2019-09-19 14:46:54 +00:00
|
|
|
, m_highlightedWindow(nullptr)
|
|
|
|
, m_filterFrame(nullptr)
|
|
|
|
, m_closeView(nullptr)
|
2017-04-01 17:30:44 +00:00
|
|
|
, m_exposeAction(new QAction(this))
|
|
|
|
, m_exposeAllAction(new QAction(this))
|
|
|
|
, m_exposeClassAction(new QAction(this))
|
2011-01-30 14:34:42 +00:00
|
|
|
{
|
2016-12-02 19:27:43 +00:00
|
|
|
initConfig<PresentWindowsConfig>();
|
2020-05-24 01:37:25 +00:00
|
|
|
|
2017-09-10 14:51:18 +00:00
|
|
|
auto announceSupportProperties = [this] {
|
|
|
|
m_atomDesktop = effects->announceSupportProperty("_KDE_PRESENT_WINDOWS_DESKTOP", this);
|
|
|
|
m_atomWindows = effects->announceSupportProperty("_KDE_PRESENT_WINDOWS_GROUP", this);
|
|
|
|
};
|
|
|
|
announceSupportProperties();
|
|
|
|
connect(effects, &EffectsHandler::xcbConnectionChanged, this, announceSupportProperties);
|
2009-06-27 10:21:49 +00:00
|
|
|
|
2017-04-01 17:30:44 +00:00
|
|
|
QAction* exposeAction = m_exposeAction;
|
2013-12-10 10:45:33 +00:00
|
|
|
exposeAction->setObjectName(QStringLiteral("Expose"));
|
2013-08-14 19:13:12 +00:00
|
|
|
exposeAction->setText(i18n("Toggle Present Windows (Current desktop)"));
|
|
|
|
KGlobalAccel::self()->setDefaultShortcut(exposeAction, QList<QKeySequence>() << Qt::CTRL + Qt::Key_F9);
|
|
|
|
KGlobalAccel::self()->setShortcut(exposeAction, QList<QKeySequence>() << Qt::CTRL + Qt::Key_F9);
|
|
|
|
shortcut = KGlobalAccel::self()->shortcut(exposeAction);
|
2013-07-10 10:26:50 +00:00
|
|
|
effects->registerGlobalShortcut(Qt::CTRL + Qt::Key_F9, exposeAction);
|
2019-01-01 20:48:53 +00:00
|
|
|
connect(exposeAction, &QAction::triggered, this, &PresentWindowsEffect::toggleActive);
|
2020-05-24 01:37:25 +00:00
|
|
|
|
2017-04-01 17:30:44 +00:00
|
|
|
QAction* exposeAllAction = m_exposeAllAction;
|
2013-12-10 10:45:33 +00:00
|
|
|
exposeAllAction->setObjectName(QStringLiteral("ExposeAll"));
|
2013-08-14 19:13:12 +00:00
|
|
|
exposeAllAction->setText(i18n("Toggle Present Windows (All desktops)"));
|
2014-06-20 07:26:28 +00:00
|
|
|
KGlobalAccel::self()->setDefaultShortcut(exposeAllAction, QList<QKeySequence>() << Qt::CTRL + Qt::Key_F10 << Qt::Key_LaunchC);
|
|
|
|
KGlobalAccel::self()->setShortcut(exposeAllAction, QList<QKeySequence>() << Qt::CTRL + Qt::Key_F10 << Qt::Key_LaunchC);
|
2013-08-14 19:13:12 +00:00
|
|
|
shortcutAll = KGlobalAccel::self()->shortcut(exposeAllAction);
|
2013-07-10 10:26:50 +00:00
|
|
|
effects->registerGlobalShortcut(Qt::CTRL + Qt::Key_F10, exposeAllAction);
|
2017-03-18 10:00:30 +00:00
|
|
|
effects->registerTouchpadSwipeShortcut(SwipeDirection::Down, exposeAllAction);
|
2019-01-01 20:48:53 +00:00
|
|
|
connect(exposeAllAction, &QAction::triggered, this, &PresentWindowsEffect::toggleActiveAllDesktops);
|
2020-05-24 01:37:25 +00:00
|
|
|
|
2017-04-01 17:30:44 +00:00
|
|
|
QAction* exposeClassAction = m_exposeClassAction;
|
2013-12-10 10:45:33 +00:00
|
|
|
exposeClassAction->setObjectName(QStringLiteral("ExposeClass"));
|
2013-08-14 19:13:12 +00:00
|
|
|
exposeClassAction->setText(i18n("Toggle Present Windows (Window class)"));
|
|
|
|
KGlobalAccel::self()->setDefaultShortcut(exposeClassAction, QList<QKeySequence>() << Qt::CTRL + Qt::Key_F7);
|
|
|
|
KGlobalAccel::self()->setShortcut(exposeClassAction, QList<QKeySequence>() << Qt::CTRL + Qt::Key_F7);
|
2013-07-10 10:26:50 +00:00
|
|
|
effects->registerGlobalShortcut(Qt::CTRL + Qt::Key_F7, exposeClassAction);
|
2019-01-01 20:48:53 +00:00
|
|
|
connect(exposeClassAction, &QAction::triggered, this, &PresentWindowsEffect::toggleActiveClass);
|
2013-08-14 19:13:12 +00:00
|
|
|
shortcutClass = KGlobalAccel::self()->shortcut(exposeClassAction);
|
|
|
|
connect(KGlobalAccel::self(), &KGlobalAccel::globalShortcutChanged, this, &PresentWindowsEffect::globalShortcutChanged);
|
2020-05-24 01:37:25 +00:00
|
|
|
|
2011-01-30 14:34:42 +00:00
|
|
|
reconfigure(ReconfigureAll);
|
2019-01-01 20:48:53 +00:00
|
|
|
connect(effects, &EffectsHandler::windowAdded, this, &PresentWindowsEffect::slotWindowAdded);
|
|
|
|
connect(effects, &EffectsHandler::windowClosed, this, &PresentWindowsEffect::slotWindowClosed);
|
|
|
|
connect(effects, &EffectsHandler::windowDeleted, this, &PresentWindowsEffect::slotWindowDeleted);
|
2020-02-11 17:03:58 +00:00
|
|
|
connect(effects, &EffectsHandler::windowFrameGeometryChanged, this, &PresentWindowsEffect::slotWindowFrameGeometryChanged);
|
2019-01-01 20:48:53 +00:00
|
|
|
connect(effects, &EffectsHandler::propertyNotify, this, &PresentWindowsEffect::slotPropertyNotify);
|
2015-08-28 05:50:20 +00:00
|
|
|
connect(effects, &EffectsHandler::numberScreensChanged, this,
|
|
|
|
[this] {
|
|
|
|
if (isActive())
|
|
|
|
reCreateGrids();
|
|
|
|
}
|
|
|
|
);
|
2019-06-23 15:59:44 +00:00
|
|
|
connect(effects, &EffectsHandler::screenAboutToLock, this, [this]() {
|
|
|
|
setActive(false);
|
|
|
|
});
|
2011-01-30 14:34:42 +00:00
|
|
|
}
|
2008-10-02 09:27:32 +00:00
|
|
|
|
|
|
|
PresentWindowsEffect::~PresentWindowsEffect()
|
2011-01-30 14:34:42 +00:00
|
|
|
{
|
2010-07-18 16:32:37 +00:00
|
|
|
delete m_filterFrame;
|
2010-09-30 20:25:22 +00:00
|
|
|
delete m_closeView;
|
2011-01-30 14:34:42 +00:00
|
|
|
}
|
2008-09-22 13:03:00 +00:00
|
|
|
|
2011-01-30 14:34:42 +00:00
|
|
|
void PresentWindowsEffect::reconfigure(ReconfigureFlags)
|
|
|
|
{
|
2014-03-25 15:29:03 +00:00
|
|
|
PresentWindowsConfig::self()->read();
|
2011-01-30 14:34:42 +00:00
|
|
|
foreach (ElectricBorder border, m_borderActivate) {
|
2013-01-22 11:47:06 +00:00
|
|
|
effects->unreserveElectricBorder(border, this);
|
2011-01-30 14:34:42 +00:00
|
|
|
}
|
|
|
|
foreach (ElectricBorder border, m_borderActivateAll) {
|
2013-01-22 11:47:06 +00:00
|
|
|
effects->unreserveElectricBorder(border, this);
|
2011-01-30 14:34:42 +00:00
|
|
|
}
|
2009-03-29 12:57:20 +00:00
|
|
|
m_borderActivate.clear();
|
|
|
|
m_borderActivateAll.clear();
|
2020-05-24 01:37:25 +00:00
|
|
|
|
2012-09-13 06:49:13 +00:00
|
|
|
foreach (int i, PresentWindowsConfig::borderActivate()) {
|
2011-01-30 14:34:42 +00:00
|
|
|
m_borderActivate.append(ElectricBorder(i));
|
2013-01-22 11:47:06 +00:00
|
|
|
effects->reserveElectricBorder(ElectricBorder(i), this);
|
2011-01-30 14:34:42 +00:00
|
|
|
}
|
2012-09-13 06:49:13 +00:00
|
|
|
foreach (int i, PresentWindowsConfig::borderActivateAll()) {
|
2011-01-30 14:34:42 +00:00
|
|
|
m_borderActivateAll.append(ElectricBorder(i));
|
2013-01-22 11:47:06 +00:00
|
|
|
effects->reserveElectricBorder(ElectricBorder(i), this);
|
2007-04-29 17:35:43 +00:00
|
|
|
}
|
2012-09-13 06:49:13 +00:00
|
|
|
foreach (int i, PresentWindowsConfig::borderActivateClass()) {
|
2011-12-24 19:26:01 +00:00
|
|
|
m_borderActivateClass.append(ElectricBorder(i));
|
2013-01-22 11:47:06 +00:00
|
|
|
effects->reserveElectricBorder(ElectricBorder(i), this);
|
2011-12-24 19:26:01 +00:00
|
|
|
}
|
2020-05-24 01:37:25 +00:00
|
|
|
|
2012-09-13 06:49:13 +00:00
|
|
|
m_layoutMode = PresentWindowsConfig::layoutMode();
|
|
|
|
m_showCaptions = PresentWindowsConfig::drawWindowCaptions();
|
|
|
|
m_showIcons = PresentWindowsConfig::drawWindowIcons();
|
|
|
|
m_doNotCloseWindows = !PresentWindowsConfig::allowClosingWindows();
|
2020-05-24 01:37:25 +00:00
|
|
|
|
2015-03-02 15:00:10 +00:00
|
|
|
if (m_doNotCloseWindows) {
|
|
|
|
delete m_closeView;
|
|
|
|
m_closeView = nullptr;
|
|
|
|
}
|
2020-05-24 01:37:25 +00:00
|
|
|
|
2012-09-13 06:49:13 +00:00
|
|
|
m_ignoreMinimized = PresentWindowsConfig::ignoreMinimized();
|
|
|
|
m_accuracy = PresentWindowsConfig::accuracy() * 20;
|
|
|
|
m_fillGaps = PresentWindowsConfig::fillGaps();
|
2011-01-30 14:34:42 +00:00
|
|
|
m_fadeDuration = double(animationTime(150));
|
2012-09-13 06:49:13 +00:00
|
|
|
m_showPanel = PresentWindowsConfig::showPanel();
|
|
|
|
m_leftButtonWindow = (WindowMouseAction)PresentWindowsConfig::leftButtonWindow();
|
|
|
|
m_middleButtonWindow = (WindowMouseAction)PresentWindowsConfig::middleButtonWindow();
|
|
|
|
m_rightButtonWindow = (WindowMouseAction)PresentWindowsConfig::rightButtonWindow();
|
|
|
|
m_leftButtonDesktop = (DesktopMouseAction)PresentWindowsConfig::leftButtonDesktop();
|
|
|
|
m_middleButtonDesktop = (DesktopMouseAction)PresentWindowsConfig::middleButtonDesktop();
|
|
|
|
m_rightButtonDesktop = (DesktopMouseAction)PresentWindowsConfig::rightButtonDesktop();
|
2017-04-01 17:30:44 +00:00
|
|
|
|
|
|
|
// touch screen edges
|
|
|
|
const QVector<ElectricBorder> relevantBorders{ElectricLeft, ElectricTop, ElectricRight, ElectricBottom};
|
|
|
|
for (auto e : relevantBorders) {
|
|
|
|
effects->unregisterTouchBorder(e, m_exposeAction);
|
|
|
|
effects->unregisterTouchBorder(e, m_exposeAllAction);
|
|
|
|
effects->unregisterTouchBorder(e, m_exposeClassAction);
|
|
|
|
}
|
2017-08-24 11:36:22 +00:00
|
|
|
auto touchEdge = [&relevantBorders] (const QList<int> touchBorders, QAction *action) {
|
2017-04-01 17:30:44 +00:00
|
|
|
for (int i : touchBorders) {
|
2017-08-24 11:36:22 +00:00
|
|
|
if (!relevantBorders.contains(ElectricBorder(i))) {
|
|
|
|
continue;
|
|
|
|
}
|
2017-04-01 17:30:44 +00:00
|
|
|
effects->registerTouchBorder(ElectricBorder(i), action);
|
|
|
|
}
|
|
|
|
};
|
|
|
|
touchEdge(PresentWindowsConfig::touchBorderActivate(), m_exposeAction);
|
|
|
|
touchEdge(PresentWindowsConfig::touchBorderActivateAll(), m_exposeAllAction);
|
|
|
|
touchEdge(PresentWindowsConfig::touchBorderActivateClass(), m_exposeClassAction);
|
2011-01-30 14:34:42 +00:00
|
|
|
}
|
2007-04-29 17:35:43 +00:00
|
|
|
|
2009-09-02 02:30:22 +00:00
|
|
|
void* PresentWindowsEffect::proxy()
|
2011-01-30 14:34:42 +00:00
|
|
|
{
|
2009-02-06 10:15:06 +00:00
|
|
|
return &m_proxy;
|
2011-01-30 14:34:42 +00:00
|
|
|
}
|
2009-02-06 10:15:06 +00:00
|
|
|
|
2009-06-30 19:11:02 +00:00
|
|
|
void PresentWindowsEffect::toggleActiveClass()
|
|
|
|
{
|
2011-01-30 14:34:42 +00:00
|
|
|
if (!m_activated) {
|
|
|
|
if (!effects->activeWindow())
|
2010-01-01 20:45:40 +00:00
|
|
|
return;
|
|
|
|
m_mode = ModeWindowClass;
|
|
|
|
m_class = effects->activeWindow()->windowClass();
|
2011-01-30 14:34:42 +00:00
|
|
|
}
|
|
|
|
setActive(!m_activated);
|
2009-06-30 19:11:02 +00:00
|
|
|
}
|
|
|
|
|
2008-09-22 13:03:00 +00:00
|
|
|
//-----------------------------------------------------------------------------
|
|
|
|
// Screen painting
|
2007-04-29 17:35:43 +00:00
|
|
|
|
2011-01-30 14:34:42 +00:00
|
|
|
void PresentWindowsEffect::prePaintScreen(ScreenPrePaintData &data, int time)
|
|
|
|
{
|
|
|
|
m_motionManager.calculate(time);
|
2007-04-29 17:35:43 +00:00
|
|
|
|
2008-09-22 13:03:00 +00:00
|
|
|
// We need to mark the screen as having been transformed otherwise there will be no repainting
|
2011-01-30 14:34:42 +00:00
|
|
|
if (m_activated || m_motionManager.managingWindows())
|
2007-07-07 14:01:32 +00:00
|
|
|
data.mask |= Effect::PAINT_SCREEN_WITH_TRANSFORMED_WINDOWS;
|
2007-04-29 17:35:43 +00:00
|
|
|
|
2011-01-30 14:34:42 +00:00
|
|
|
if (m_activated)
|
|
|
|
m_decalOpacity = qMin(1.0, m_decalOpacity + time / m_fadeDuration);
|
2008-09-22 13:03:00 +00:00
|
|
|
else
|
2011-01-30 14:34:42 +00:00
|
|
|
m_decalOpacity = qMax(0.0, m_decalOpacity - time / m_fadeDuration);
|
2007-04-29 17:35:43 +00:00
|
|
|
|
2011-01-30 14:34:42 +00:00
|
|
|
effects->prePaintScreen(data, time);
|
|
|
|
}
|
2007-04-29 17:35:43 +00:00
|
|
|
|
2019-10-29 22:04:15 +00:00
|
|
|
void PresentWindowsEffect::paintScreen(int mask, const QRegion ®ion, ScreenPaintData &data)
|
2011-01-30 14:34:42 +00:00
|
|
|
{
|
|
|
|
effects->paintScreen(mask, region, data);
|
2008-09-22 13:03:00 +00:00
|
|
|
|
|
|
|
// Display the filter box
|
2011-01-30 14:34:42 +00:00
|
|
|
if (!m_windowFilter.isEmpty())
|
|
|
|
m_filterFrame->render(region);
|
2019-10-21 13:36:39 +00:00
|
|
|
|
|
|
|
if (m_closeView)
|
|
|
|
effects->renderEffectQuickView(m_closeView);
|
2011-01-30 14:34:42 +00:00
|
|
|
}
|
2007-04-29 17:35:43 +00:00
|
|
|
|
2008-09-22 13:03:00 +00:00
|
|
|
void PresentWindowsEffect::postPaintScreen()
|
2011-01-30 14:34:42 +00:00
|
|
|
{
|
|
|
|
if (m_motionManager.areWindowsMoving())
|
2008-09-22 13:03:00 +00:00
|
|
|
effects->addRepaintFull();
|
2019-10-21 13:36:39 +00:00
|
|
|
else if (!m_activated && m_motionManager.managingWindows() && !(m_closeView && m_closeView->isVisible())) {
|
2011-01-30 14:34:42 +00:00
|
|
|
// We have finished moving them back, stop processing
|
2008-09-22 13:03:00 +00:00
|
|
|
m_motionManager.unmanageAll();
|
2009-02-22 13:04:16 +00:00
|
|
|
|
|
|
|
DataHash::iterator i = m_windowData.begin();
|
2011-01-30 14:34:42 +00:00
|
|
|
while (i != m_windowData.end()) {
|
2009-02-22 13:04:16 +00:00
|
|
|
delete i.value().textFrame;
|
|
|
|
delete i.value().iconFrame;
|
2011-08-02 15:21:56 +00:00
|
|
|
++i;
|
2011-01-30 14:34:42 +00:00
|
|
|
}
|
2008-09-22 13:03:00 +00:00
|
|
|
m_windowData.clear();
|
2009-02-22 13:04:16 +00:00
|
|
|
|
2011-01-30 14:34:42 +00:00
|
|
|
foreach (EffectWindow * w, effects->stackingOrder()) {
|
2018-06-11 11:25:10 +00:00
|
|
|
w->setData(WindowForceBlurRole, QVariant());
|
|
|
|
w->setData(WindowForceBackgroundContrastRole, QVariant());
|
2008-09-22 13:03:00 +00:00
|
|
|
}
|
Use nullptr everywhere
Summary:
Because KWin is a very old project, we use three kinds of null pointer
literals: 0, NULL, and nullptr. Since C++11, it's recommended to use
nullptr keyword.
This change converts all usages of 0 and NULL literal to nullptr. Even
though it breaks git history, we need to do it in order to have consistent
code as well to ease code reviews (it's very tempting for some people to
add unrelated changes to their patches, e.g. converting NULL to nullptr).
Test Plan: Compiles.
Reviewers: #kwin, davidedmundson, romangg
Reviewed By: #kwin, davidedmundson, romangg
Subscribers: romangg, kwin
Tags: #kwin
Differential Revision: https://phabricator.kde.org/D23618
2019-09-19 14:46:54 +00:00
|
|
|
effects->setActiveFullScreenEffect(nullptr);
|
2011-09-18 15:53:14 +00:00
|
|
|
effects->addRepaintFull();
|
2013-06-27 19:54:50 +00:00
|
|
|
} else if (m_activated && m_needInitialSelection) {
|
|
|
|
m_needInitialSelection = false;
|
|
|
|
QMouseEvent me(QEvent::MouseMove, cursorPos(), Qt::NoButton, Qt::NoButton, Qt::NoModifier);
|
|
|
|
windowInputMouseEvent(&me);
|
2011-01-30 14:34:42 +00:00
|
|
|
}
|
2008-09-22 13:03:00 +00:00
|
|
|
|
|
|
|
// Update windows that are changing brightness or opacity
|
2009-10-30 06:51:59 +00:00
|
|
|
DataHash::const_iterator i;
|
2011-01-30 14:34:42 +00:00
|
|
|
for (i = m_windowData.constBegin(); i != m_windowData.constEnd(); ++i) {
|
|
|
|
if (i.value().opacity > 0.0 && i.value().opacity < 1.0)
|
2009-10-30 06:51:59 +00:00
|
|
|
i.key()->addRepaintFull();
|
2012-04-10 23:19:36 +00:00
|
|
|
if (i.key()->isDesktop() && !m_motionManager.isManaging(i.key())) {
|
|
|
|
if (i.value().highlight != 0.3)
|
|
|
|
i.key()->addRepaintFull();
|
|
|
|
}
|
|
|
|
else if (i.value().highlight > 0.0 && i.value().highlight < 1.0)
|
2009-10-30 06:51:59 +00:00
|
|
|
i.key()->addRepaintFull();
|
2011-01-30 14:34:42 +00:00
|
|
|
}
|
2009-10-30 06:51:59 +00:00
|
|
|
|
2008-09-22 13:03:00 +00:00
|
|
|
effects->postPaintScreen();
|
2011-01-30 14:34:42 +00:00
|
|
|
}
|
2008-09-22 13:03:00 +00:00
|
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
|
|
// Window painting
|
|
|
|
|
2011-01-30 14:34:42 +00:00
|
|
|
void PresentWindowsEffect::prePaintWindow(EffectWindow *w, WindowPrePaintData &data, int time)
|
|
|
|
{
|
2008-09-22 13:03:00 +00:00
|
|
|
// 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.
|
2019-10-21 13:36:39 +00:00
|
|
|
if (m_activated || m_motionManager.areWindowsMoving() || m_closeView) {
|
2011-03-07 23:19:52 +00:00
|
|
|
DataHash::iterator winData = m_windowData.find(w);
|
|
|
|
if (winData == m_windowData.end()) {
|
|
|
|
effects->prePaintWindow(w, data, time);
|
|
|
|
return;
|
|
|
|
}
|
2011-01-30 14:34:42 +00:00
|
|
|
w->enablePainting(EffectWindow::PAINT_DISABLED_BY_MINIMIZE); // Display always
|
|
|
|
w->enablePainting(EffectWindow::PAINT_DISABLED_BY_DESKTOP);
|
2008-09-22 13:03:00 +00:00
|
|
|
|
|
|
|
// Calculate window's opacity
|
|
|
|
// TODO: Minimized windows or windows not on the current desktop are only 75% visible?
|
2011-03-07 23:19:52 +00:00
|
|
|
if (winData->visible) {
|
|
|
|
if (winData->deleted)
|
|
|
|
winData->opacity = qMax(0.0, winData->opacity - time / m_fadeDuration);
|
2009-07-14 09:06:37 +00:00
|
|
|
else
|
2011-03-07 23:19:52 +00:00
|
|
|
winData->opacity = qMin(/*(w->isMinimized() || !w->isOnCurrentDesktop()) ? 0.75 :*/ 1.0,
|
|
|
|
winData->opacity + time / m_fadeDuration);
|
2011-01-30 14:34:42 +00:00
|
|
|
} else
|
2011-03-07 23:19:52 +00:00
|
|
|
winData->opacity = qMax(0.0, winData->opacity - time / m_fadeDuration);
|
2020-05-24 01:37:25 +00:00
|
|
|
|
2011-03-07 23:19:52 +00:00
|
|
|
if (winData->opacity <= 0.0) {
|
2009-01-13 10:19:47 +00:00
|
|
|
// don't disable painting for panels if show panel is set
|
2011-03-07 23:19:52 +00:00
|
|
|
if (!(m_showPanel && w->isDock()))
|
2011-01-30 14:34:42 +00:00
|
|
|
w->disablePainting(EffectWindow::PAINT_DISABLED);
|
2011-03-07 23:19:52 +00:00
|
|
|
} else if (winData->opacity != 1.0)
|
2008-09-22 13:03:00 +00:00
|
|
|
data.setTranslucent();
|
|
|
|
|
2011-04-25 15:04:04 +00:00
|
|
|
const bool isInMotion = m_motionManager.isManaging(w);
|
2008-09-22 13:03:00 +00:00
|
|
|
// Calculate window's brightness
|
2019-10-21 13:36:39 +00:00
|
|
|
if (w == m_highlightedWindow || !m_activated)
|
2011-03-07 23:19:52 +00:00
|
|
|
winData->highlight = qMin(1.0, winData->highlight + time / m_fadeDuration);
|
2011-04-25 15:04:04 +00:00
|
|
|
else if (!isInMotion && w->isDesktop())
|
|
|
|
winData->highlight = 0.3;
|
2008-09-22 13:03:00 +00:00
|
|
|
else
|
2011-03-07 23:19:52 +00:00
|
|
|
winData->highlight = qMax(0.0, winData->highlight - time / m_fadeDuration);
|
2008-09-22 13:03:00 +00:00
|
|
|
|
2011-01-30 14:34:42 +00:00
|
|
|
// Closed windows
|
2011-03-07 23:19:52 +00:00
|
|
|
if (winData->deleted) {
|
2009-07-14 09:06:37 +00:00
|
|
|
data.setTranslucent();
|
2011-03-07 23:19:52 +00:00
|
|
|
if (winData->opacity <= 0.0 && winData->referenced) {
|
2009-07-14 09:06:37 +00:00
|
|
|
// it's possible that another effect has referenced the window
|
|
|
|
// we have to keep the window in the list to prevent flickering
|
2011-03-07 23:19:52 +00:00
|
|
|
winData->referenced = false;
|
2009-07-14 09:06:37 +00:00
|
|
|
w->unrefWindow();
|
2011-01-30 14:34:42 +00:00
|
|
|
} else
|
|
|
|
w->enablePainting(EffectWindow::PAINT_DISABLED_BY_DELETE);
|
|
|
|
}
|
2009-07-14 09:06:37 +00:00
|
|
|
|
2009-10-29 17:02:41 +00:00
|
|
|
// desktop windows on other desktops (Plasma activity per desktop) should not be painted
|
2011-01-30 14:34:42 +00:00
|
|
|
if (w->isDesktop() && !w->isOnCurrentDesktop())
|
|
|
|
w->disablePainting(EffectWindow::PAINT_DISABLED_BY_DESKTOP);
|
2009-10-29 17:02:41 +00:00
|
|
|
|
2011-04-25 15:04:04 +00:00
|
|
|
if (isInMotion)
|
2008-09-22 13:03:00 +00:00
|
|
|
data.setTransformed(); // We will be moving this window
|
|
|
|
}
|
2011-01-30 14:34:42 +00:00
|
|
|
effects->prePaintWindow(w, data, time);
|
|
|
|
}
|
2008-09-22 13:03:00 +00:00
|
|
|
|
2011-01-30 14:34:42 +00:00
|
|
|
void PresentWindowsEffect::paintWindow(EffectWindow *w, int mask, QRegion region, WindowPaintData &data)
|
|
|
|
{
|
2011-03-07 23:19:52 +00:00
|
|
|
if (m_activated || m_motionManager.areWindowsMoving()) {
|
2011-04-04 07:26:09 +00:00
|
|
|
DataHash::const_iterator winData = m_windowData.constFind(w);
|
2011-03-07 23:19:52 +00:00
|
|
|
if (winData == m_windowData.constEnd() || (w->isDock() && m_showPanel)) {
|
2009-01-13 10:19:47 +00:00
|
|
|
// in case the panel should be shown just display it without any changes
|
2011-01-30 14:34:42 +00:00
|
|
|
effects->paintWindow(w, mask, region, data);
|
2009-01-13 10:19:47 +00:00
|
|
|
return;
|
2011-01-30 14:34:42 +00:00
|
|
|
}
|
2009-02-28 10:18:46 +00:00
|
|
|
|
2011-04-25 15:04:04 +00:00
|
|
|
mask |= PAINT_WINDOW_LANCZOS;
|
2008-09-22 13:03:00 +00:00
|
|
|
// Apply opacity and brightness
|
2012-07-12 15:20:17 +00:00
|
|
|
data.multiplyOpacity(winData->opacity);
|
|
|
|
data.multiplyBrightness(interpolate(0.40, 1.0, winData->highlight));
|
2008-09-22 13:03:00 +00:00
|
|
|
|
2011-01-30 14:34:42 +00:00
|
|
|
if (m_motionManager.isManaging(w)) {
|
2011-12-30 00:18:04 +00:00
|
|
|
if (w->isDesktop()) {
|
2011-04-25 15:04:04 +00:00
|
|
|
effects->paintWindow(w, mask, region, data);
|
2011-12-30 00:18:04 +00:00
|
|
|
}
|
2011-01-30 14:34:42 +00:00
|
|
|
m_motionManager.apply(w, data);
|
2011-04-25 15:04:04 +00:00
|
|
|
QRect rect = m_motionManager.transformedGeometry(w).toRect();
|
|
|
|
|
2013-06-27 19:54:50 +00:00
|
|
|
if (m_activated && winData->highlight > 0.0) {
|
2011-04-25 15:04:04 +00:00
|
|
|
// scale the window (interpolated by the highlight level) to at least 105% or to cover 1/16 of the screen size - yet keep it in screen bounds
|
2012-03-20 14:20:05 +00:00
|
|
|
QRect area = effects->clientArea(FullScreenArea, w);
|
2012-01-04 22:10:17 +00:00
|
|
|
|
2012-05-28 10:00:31 +00:00
|
|
|
QSizeF effSize(w->width()*data.xScale(), w->height()*data.yScale());
|
2014-02-04 18:00:08 +00:00
|
|
|
const float xr = area.width()/effSize.width();
|
|
|
|
const float yr = area.height()/effSize.height();
|
|
|
|
float tScale = 0.0;
|
|
|
|
if (xr < yr) {
|
|
|
|
tScale = qMax(xr/4.0, yr/32.0);
|
|
|
|
} else {
|
|
|
|
tScale = qMax(xr/32.0, yr/4.0);
|
|
|
|
}
|
2011-12-30 00:18:04 +00:00
|
|
|
if (tScale < 1.05) {
|
2011-04-25 15:04:04 +00:00
|
|
|
tScale = 1.05;
|
2011-12-30 00:18:04 +00:00
|
|
|
}
|
2011-04-25 15:04:04 +00:00
|
|
|
if (effSize.width()*tScale > area.width())
|
|
|
|
tScale = area.width() / effSize.width();
|
|
|
|
if (effSize.height()*tScale > area.height())
|
|
|
|
tScale = area.height() / effSize.height();
|
2020-05-24 01:37:25 +00:00
|
|
|
|
2012-05-28 10:00:31 +00:00
|
|
|
const qreal scale = interpolate(1.0, tScale, winData->highlight);
|
2011-04-25 15:04:04 +00:00
|
|
|
if (scale > 1.0) {
|
|
|
|
if (scale < tScale) // don't use lanczos during transition
|
|
|
|
mask &= ~PAINT_WINDOW_LANCZOS;
|
|
|
|
|
2011-12-30 00:18:04 +00:00
|
|
|
const float df = (tScale-1.0f)*0.5f;
|
|
|
|
int tx = qRound(rect.width()*df);
|
|
|
|
int ty = qRound(rect.height()*df);
|
|
|
|
QRect tRect(rect.adjusted(-tx, -ty, tx, ty));
|
|
|
|
tx = qMax(tRect.x(), area.x()) + qMin(0, area.right()-tRect.right());
|
|
|
|
ty = qMax(tRect.y(), area.y()) + qMin(0, area.bottom()-tRect.bottom());
|
|
|
|
tx = qRound((tx-rect.x())*winData->highlight);
|
|
|
|
ty = qRound((ty-rect.y())*winData->highlight);
|
2011-04-25 15:04:04 +00:00
|
|
|
|
|
|
|
rect.translate(tx,ty);
|
|
|
|
rect.setWidth(rect.width()*scale);
|
|
|
|
rect.setHeight(rect.height()*scale);
|
2011-12-30 00:18:04 +00:00
|
|
|
|
2012-05-28 10:00:31 +00:00
|
|
|
data *= QVector2D(scale, scale);
|
2012-05-28 12:45:46 +00:00
|
|
|
data += QPoint(tx, ty);
|
2011-04-25 15:04:04 +00:00
|
|
|
}
|
|
|
|
}
|
2008-09-22 13:03:00 +00:00
|
|
|
|
2011-04-25 15:04:04 +00:00
|
|
|
if (m_motionManager.areWindowsMoving()) {
|
|
|
|
mask &= ~PAINT_WINDOW_LANCZOS;
|
2011-01-30 14:34:42 +00:00
|
|
|
}
|
|
|
|
effects->paintWindow(w, mask, region, data);
|
|
|
|
|
|
|
|
if (m_showIcons) {
|
|
|
|
QPoint point(rect.x() + rect.width() * 0.95,
|
|
|
|
rect.y() + rect.height() * 0.95);
|
2011-03-07 23:19:52 +00:00
|
|
|
winData->iconFrame->setPosition(point);
|
2012-09-20 09:33:32 +00:00
|
|
|
if (effects->compositingType() == KWin::OpenGL2Compositing && data.shader) {
|
2012-07-12 15:20:17 +00:00
|
|
|
const float a = 0.9 * data.opacity() * m_decalOpacity * 0.75;
|
2011-02-12 00:36:21 +00:00
|
|
|
data.shader->setUniform(GLShader::ModulationConstant, QVector4D(a, a, a, a));
|
2009-02-22 13:04:16 +00:00
|
|
|
}
|
2012-07-12 15:20:17 +00:00
|
|
|
winData->iconFrame->render(region, 0.9 * data.opacity() * m_decalOpacity, 0.75);
|
2011-01-30 14:34:42 +00:00
|
|
|
}
|
|
|
|
if (m_showCaptions) {
|
|
|
|
QPoint point(rect.x() + rect.width() / 2,
|
|
|
|
rect.y() + rect.height() / 2);
|
2011-03-07 23:19:52 +00:00
|
|
|
winData->textFrame->setPosition(point);
|
2012-09-20 09:33:32 +00:00
|
|
|
if (effects->compositingType() == KWin::OpenGL2Compositing && data.shader) {
|
2012-07-12 15:20:17 +00:00
|
|
|
const float a = 0.9 * data.opacity() * m_decalOpacity * 0.75;
|
2011-02-12 00:36:21 +00:00
|
|
|
data.shader->setUniform(GLShader::ModulationConstant, QVector4D(a, a, a, a));
|
2007-04-29 17:35:43 +00:00
|
|
|
}
|
2012-07-12 15:20:17 +00:00
|
|
|
winData->textFrame->render(region, 0.9 * data.opacity() * m_decalOpacity, 0.75);
|
2007-04-29 17:35:43 +00:00
|
|
|
}
|
2013-10-25 10:57:34 +00:00
|
|
|
} else {
|
2011-01-30 14:34:42 +00:00
|
|
|
effects->paintWindow(w, mask, region, data);
|
2013-10-25 10:57:34 +00:00
|
|
|
}
|
2011-01-30 14:34:42 +00:00
|
|
|
} else
|
|
|
|
effects->paintWindow(w, mask, region, data);
|
|
|
|
}
|
2007-04-29 17:35:43 +00:00
|
|
|
|
2008-09-22 13:03:00 +00:00
|
|
|
//-----------------------------------------------------------------------------
|
|
|
|
// User interaction
|
2007-07-05 11:41:02 +00:00
|
|
|
|
2011-02-25 21:06:02 +00:00
|
|
|
void PresentWindowsEffect::slotWindowAdded(EffectWindow *w)
|
2011-01-30 14:34:42 +00:00
|
|
|
{
|
|
|
|
if (!m_activated)
|
2009-02-23 14:24:20 +00:00
|
|
|
return;
|
2020-05-24 01:37:25 +00:00
|
|
|
|
2011-03-07 23:19:52 +00:00
|
|
|
WindowData *winData = &m_windowData[w];
|
|
|
|
winData->visible = isVisibleWindow(w);
|
|
|
|
winData->opacity = 0.0;
|
|
|
|
winData->highlight = 0.0;
|
|
|
|
winData->textFrame = effects->effectFrame(EffectFrameUnstyled, false);
|
2020-05-24 01:37:25 +00:00
|
|
|
|
2009-02-22 13:04:16 +00:00
|
|
|
QFont font;
|
2011-01-30 14:34:42 +00:00
|
|
|
font.setBold(true);
|
|
|
|
font.setPointSize(12);
|
2020-05-24 01:37:25 +00:00
|
|
|
|
2011-03-07 23:19:52 +00:00
|
|
|
winData->textFrame->setFont(font);
|
|
|
|
winData->iconFrame = effects->effectFrame(EffectFrameUnstyled, false);
|
|
|
|
winData->iconFrame->setAlignment(Qt::AlignRight | Qt::AlignBottom);
|
|
|
|
winData->iconFrame->setIcon(w->icon());
|
2013-12-06 13:41:23 +00:00
|
|
|
winData->iconFrame->setIconSize(QSize(32, 32));
|
2020-05-24 01:37:25 +00:00
|
|
|
|
2011-01-30 14:34:42 +00:00
|
|
|
if (isSelectableWindow(w)) {
|
|
|
|
m_motionManager.manage(w);
|
2008-09-22 13:03:00 +00:00
|
|
|
rearrangeWindows();
|
2011-01-30 14:34:42 +00:00
|
|
|
}
|
|
|
|
}
|
2007-04-29 17:35:43 +00:00
|
|
|
|
2011-02-27 08:25:45 +00:00
|
|
|
void PresentWindowsEffect::slotWindowClosed(EffectWindow *w)
|
2011-01-30 14:34:42 +00:00
|
|
|
{
|
|
|
|
if (m_managerWindow == w)
|
Use nullptr everywhere
Summary:
Because KWin is a very old project, we use three kinds of null pointer
literals: 0, NULL, and nullptr. Since C++11, it's recommended to use
nullptr keyword.
This change converts all usages of 0 and NULL literal to nullptr. Even
though it breaks git history, we need to do it in order to have consistent
code as well to ease code reviews (it's very tempting for some people to
add unrelated changes to their patches, e.g. converting NULL to nullptr).
Test Plan: Compiles.
Reviewers: #kwin, davidedmundson, romangg
Reviewed By: #kwin, davidedmundson, romangg
Subscribers: romangg, kwin
Tags: #kwin
Differential Revision: https://phabricator.kde.org/D23618
2019-09-19 14:46:54 +00:00
|
|
|
m_managerWindow = nullptr;
|
2020-05-24 01:37:25 +00:00
|
|
|
|
2011-03-07 23:19:52 +00:00
|
|
|
DataHash::iterator winData = m_windowData.find(w);
|
|
|
|
if (winData == m_windowData.end())
|
2009-03-08 05:07:42 +00:00
|
|
|
return;
|
2020-05-24 01:37:25 +00:00
|
|
|
|
2011-03-07 23:19:52 +00:00
|
|
|
winData->deleted = true;
|
2013-03-11 15:19:16 +00:00
|
|
|
if (!winData->referenced) {
|
|
|
|
winData->referenced = true;
|
|
|
|
w->refWindow();
|
|
|
|
}
|
2020-05-24 01:37:25 +00:00
|
|
|
|
2011-01-30 14:34:42 +00:00
|
|
|
if (m_highlightedWindow == w)
|
|
|
|
setHighlightedWindow(findFirstWindow());
|
2020-05-24 01:37:25 +00:00
|
|
|
|
2011-01-30 14:34:42 +00:00
|
|
|
rearrangeWindows();
|
2011-03-06 18:08:14 +00:00
|
|
|
|
2011-03-07 23:19:52 +00:00
|
|
|
foreach (EffectWindow *w, m_motionManager.managedWindows()) {
|
|
|
|
winData = m_windowData.find(w);
|
2011-03-06 18:08:14 +00:00
|
|
|
if (winData != m_windowData.end() && !winData->deleted)
|
|
|
|
return; // found one that is not deleted? then we go on
|
|
|
|
}
|
|
|
|
setActive(false); //else no need to keep this open
|
2011-01-30 14:34:42 +00:00
|
|
|
}
|
2008-09-22 13:03:00 +00:00
|
|
|
|
2011-02-27 09:47:42 +00:00
|
|
|
void PresentWindowsEffect::slotWindowDeleted(EffectWindow *w)
|
2011-01-30 14:34:42 +00:00
|
|
|
{
|
2011-03-07 23:19:52 +00:00
|
|
|
DataHash::iterator winData = m_windowData.find(w);
|
|
|
|
if (winData == m_windowData.end())
|
2009-02-23 14:24:20 +00:00
|
|
|
return;
|
2020-05-24 01:37:25 +00:00
|
|
|
|
2011-03-07 23:19:52 +00:00
|
|
|
delete winData->textFrame;
|
|
|
|
delete winData->iconFrame;
|
|
|
|
m_windowData.erase(winData);
|
2011-01-30 14:34:42 +00:00
|
|
|
m_motionManager.unmanage(w);
|
|
|
|
}
|
2008-09-23 03:16:36 +00:00
|
|
|
|
2020-02-11 17:03:58 +00:00
|
|
|
void PresentWindowsEffect::slotWindowFrameGeometryChanged(EffectWindow* w, const QRect& old)
|
2011-01-30 14:34:42 +00:00
|
|
|
{
|
|
|
|
Q_UNUSED(old)
|
2020-05-24 01:37:25 +00:00
|
|
|
|
2011-01-30 14:34:42 +00:00
|
|
|
if (!m_activated)
|
2010-03-14 16:18:57 +00:00
|
|
|
return;
|
2011-01-30 14:34:42 +00:00
|
|
|
if (!m_windowData.contains(w))
|
2010-03-14 16:18:57 +00:00
|
|
|
return;
|
2020-05-24 01:37:25 +00:00
|
|
|
|
2020-03-24 13:10:36 +00:00
|
|
|
rearrangeWindows();
|
2011-01-30 14:34:42 +00:00
|
|
|
}
|
2010-03-14 16:18:57 +00:00
|
|
|
|
2011-01-30 14:34:42 +00:00
|
|
|
bool PresentWindowsEffect::borderActivated(ElectricBorder border)
|
|
|
|
{
|
2011-12-24 19:26:01 +00:00
|
|
|
int mode = 0;
|
|
|
|
if (m_borderActivate.contains(border))
|
|
|
|
mode |= 1;
|
|
|
|
else if (m_borderActivateAll.contains(border))
|
|
|
|
mode |= 2;
|
|
|
|
else if (m_borderActivateClass.contains(border))
|
|
|
|
mode |= 4;
|
|
|
|
|
|
|
|
if (!mode)
|
2008-09-22 13:03:00 +00:00
|
|
|
return false;
|
2011-12-24 19:26:01 +00:00
|
|
|
|
2011-01-30 14:34:42 +00:00
|
|
|
if (effects->activeFullScreenEffect() && effects->activeFullScreenEffect() != this)
|
2008-09-22 13:03:00 +00:00
|
|
|
return true;
|
2011-12-24 19:26:01 +00:00
|
|
|
|
|
|
|
if (mode & 1)
|
2009-02-06 14:21:20 +00:00
|
|
|
toggleActive();
|
2011-12-24 19:26:01 +00:00
|
|
|
else if (mode & 2)
|
2008-09-22 13:03:00 +00:00
|
|
|
toggleActiveAllDesktops();
|
2011-12-24 19:26:01 +00:00
|
|
|
else if (mode & 4)
|
|
|
|
toggleActiveClass();
|
2009-02-06 14:21:20 +00:00
|
|
|
return true;
|
2011-01-30 14:34:42 +00:00
|
|
|
}
|
2007-04-29 17:35:43 +00:00
|
|
|
|
2013-04-24 14:51:04 +00:00
|
|
|
void PresentWindowsEffect::windowInputMouseEvent(QEvent *e)
|
2011-01-30 14:34:42 +00:00
|
|
|
{
|
2016-03-04 13:12:29 +00:00
|
|
|
QMouseEvent* me = dynamic_cast< QMouseEvent* >(e);
|
|
|
|
if (!me) {
|
|
|
|
return;
|
|
|
|
}
|
2020-02-12 08:03:39 +00:00
|
|
|
me->setAccepted(false);
|
2020-05-24 01:37:25 +00:00
|
|
|
|
2013-10-25 10:57:34 +00:00
|
|
|
if (m_closeView) {
|
|
|
|
const bool contains = m_closeView->geometry().contains(me->pos());
|
|
|
|
if (!m_closeView->isVisible() && contains) {
|
2010-09-30 20:25:22 +00:00
|
|
|
updateCloseWindow();
|
2011-01-30 14:34:42 +00:00
|
|
|
}
|
2019-10-21 13:36:39 +00:00
|
|
|
m_closeView->forwardMouseEvent(e);
|
2011-01-30 14:34:42 +00:00
|
|
|
}
|
2020-02-12 08:03:39 +00:00
|
|
|
if (e->isAccepted()) {
|
|
|
|
return;
|
|
|
|
}
|
2016-08-15 13:44:10 +00:00
|
|
|
inputEventUpdate(me->pos(), me->type(), me->button());
|
|
|
|
}
|
|
|
|
|
|
|
|
void PresentWindowsEffect::inputEventUpdate(const QPoint &pos, QEvent::Type type, Qt::MouseButton button)
|
|
|
|
{
|
2008-09-22 13:03:00 +00:00
|
|
|
// Which window are we hovering over? Always trigger as we don't always get move events before clicking
|
|
|
|
// We cannot use m_motionManager.windowAtPoint() as the window might not be visible
|
|
|
|
EffectWindowList windows = m_motionManager.managedWindows();
|
2009-06-28 17:17:29 +00:00
|
|
|
bool hovering = false;
|
Use nullptr everywhere
Summary:
Because KWin is a very old project, we use three kinds of null pointer
literals: 0, NULL, and nullptr. Since C++11, it's recommended to use
nullptr keyword.
This change converts all usages of 0 and NULL literal to nullptr. Even
though it breaks git history, we need to do it in order to have consistent
code as well to ease code reviews (it's very tempting for some people to
add unrelated changes to their patches, e.g. converting NULL to nullptr).
Test Plan: Compiles.
Reviewers: #kwin, davidedmundson, romangg
Reviewed By: #kwin, davidedmundson, romangg
Subscribers: romangg, kwin
Tags: #kwin
Differential Revision: https://phabricator.kde.org/D23618
2019-09-19 14:46:54 +00:00
|
|
|
EffectWindow *highlightCandidate = nullptr;
|
2011-03-07 23:19:52 +00:00
|
|
|
for (int i = 0; i < windows.size(); ++i) {
|
2011-04-04 07:26:09 +00:00
|
|
|
DataHash::const_iterator winData = m_windowData.constFind(windows.at(i));
|
2011-03-07 23:19:52 +00:00
|
|
|
if (winData == m_windowData.constEnd())
|
|
|
|
continue;
|
2020-05-24 01:37:25 +00:00
|
|
|
|
2016-08-15 13:44:10 +00:00
|
|
|
if (m_motionManager.transformedGeometry(windows.at(i)).contains(pos) &&
|
2011-03-07 23:19:52 +00:00
|
|
|
winData->visible && !winData->deleted) {
|
2009-06-28 17:17:29 +00:00
|
|
|
hovering = true;
|
2014-03-16 12:26:11 +00:00
|
|
|
if (windows.at(i) && m_highlightedWindow != windows.at(i))
|
2013-06-27 19:54:50 +00:00
|
|
|
highlightCandidate = windows.at(i);
|
2008-09-22 13:03:00 +00:00
|
|
|
break;
|
2007-04-29 17:35:43 +00:00
|
|
|
}
|
2011-01-30 14:34:42 +00:00
|
|
|
}
|
2020-05-24 01:37:25 +00:00
|
|
|
|
2012-03-13 07:46:09 +00:00
|
|
|
if (!hovering)
|
Use nullptr everywhere
Summary:
Because KWin is a very old project, we use three kinds of null pointer
literals: 0, NULL, and nullptr. Since C++11, it's recommended to use
nullptr keyword.
This change converts all usages of 0 and NULL literal to nullptr. Even
though it breaks git history, we need to do it in order to have consistent
code as well to ease code reviews (it's very tempting for some people to
add unrelated changes to their patches, e.g. converting NULL to nullptr).
Test Plan: Compiles.
Reviewers: #kwin, davidedmundson, romangg
Reviewed By: #kwin, davidedmundson, romangg
Subscribers: romangg, kwin
Tags: #kwin
Differential Revision: https://phabricator.kde.org/D23618
2019-09-19 14:46:54 +00:00
|
|
|
setHighlightedWindow(nullptr);
|
2016-08-15 13:44:10 +00:00
|
|
|
if (m_highlightedWindow && m_motionManager.transformedGeometry(m_highlightedWindow).contains(pos))
|
2010-09-30 20:25:22 +00:00
|
|
|
updateCloseWindow();
|
2012-02-17 19:35:21 +00:00
|
|
|
else if (m_closeView)
|
2010-09-30 20:25:22 +00:00
|
|
|
m_closeView->hide();
|
2008-09-22 13:03:00 +00:00
|
|
|
|
2016-08-15 13:44:10 +00:00
|
|
|
if (type == QEvent::MouseButtonRelease) {
|
2013-06-27 19:54:50 +00:00
|
|
|
if (highlightCandidate)
|
|
|
|
setHighlightedWindow(highlightCandidate);
|
2016-08-15 13:44:10 +00:00
|
|
|
if (button == Qt::LeftButton) {
|
2011-04-27 07:57:18 +00:00
|
|
|
if (hovering) {
|
|
|
|
// mouse is hovering above a window - use MouseActionsWindow
|
|
|
|
mouseActionWindow(m_leftButtonWindow);
|
|
|
|
} else {
|
|
|
|
// mouse is hovering above desktop - use MouseActionsDesktop
|
|
|
|
mouseActionDesktop(m_leftButtonDesktop);
|
|
|
|
}
|
2009-06-28 17:17:29 +00:00
|
|
|
}
|
2020-09-01 05:14:58 +00:00
|
|
|
if (button == Qt::MiddleButton) {
|
2011-04-27 07:57:18 +00:00
|
|
|
if (hovering) {
|
|
|
|
// mouse is hovering above a window - use MouseActionsWindow
|
|
|
|
mouseActionWindow(m_middleButtonWindow);
|
|
|
|
} else {
|
|
|
|
// mouse is hovering above desktop - use MouseActionsDesktop
|
|
|
|
mouseActionDesktop(m_middleButtonDesktop);
|
|
|
|
}
|
2009-06-28 17:17:29 +00:00
|
|
|
}
|
2016-08-15 13:44:10 +00:00
|
|
|
if (button == Qt::RightButton) {
|
2011-04-27 07:57:18 +00:00
|
|
|
if (hovering) {
|
|
|
|
// mouse is hovering above a window - use MouseActionsWindow
|
|
|
|
mouseActionWindow(m_rightButtonWindow);
|
|
|
|
} else {
|
|
|
|
// mouse is hovering above desktop - use MouseActionsDesktop
|
|
|
|
mouseActionDesktop(m_rightButtonDesktop);
|
|
|
|
}
|
|
|
|
}
|
2013-06-27 19:54:50 +00:00
|
|
|
} else if (highlightCandidate && !m_motionManager.areWindowsMoving())
|
|
|
|
setHighlightedWindow(highlightCandidate);
|
2011-01-30 14:34:42 +00:00
|
|
|
}
|
2009-06-28 17:17:29 +00:00
|
|
|
|
2019-08-11 19:57:45 +00:00
|
|
|
bool PresentWindowsEffect::touchDown(qint32 id, const QPointF &pos, quint32 time)
|
2016-08-15 13:44:10 +00:00
|
|
|
{
|
|
|
|
Q_UNUSED(time)
|
2020-05-24 01:37:25 +00:00
|
|
|
|
2016-08-15 13:44:10 +00:00
|
|
|
if (!m_activated) {
|
|
|
|
return false;
|
|
|
|
}
|
2020-05-24 01:37:25 +00:00
|
|
|
|
2016-08-15 13:44:10 +00:00
|
|
|
// only if we don't track a touch id yet
|
|
|
|
if (!m_touch.active) {
|
|
|
|
m_touch.active = true;
|
|
|
|
m_touch.id = id;
|
|
|
|
inputEventUpdate(pos.toPoint());
|
|
|
|
}
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2019-08-11 19:57:45 +00:00
|
|
|
bool PresentWindowsEffect::touchMotion(qint32 id, const QPointF &pos, quint32 time)
|
2016-08-15 13:44:10 +00:00
|
|
|
{
|
|
|
|
Q_UNUSED(id)
|
|
|
|
Q_UNUSED(time)
|
2020-05-24 01:37:25 +00:00
|
|
|
|
2016-08-15 13:44:10 +00:00
|
|
|
if (!m_activated) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
if (m_touch.active && m_touch.id == id) {
|
|
|
|
// only update for the touch id we track
|
|
|
|
inputEventUpdate(pos.toPoint());
|
|
|
|
}
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2019-08-11 19:57:45 +00:00
|
|
|
bool PresentWindowsEffect::touchUp(qint32 id, quint32 time)
|
2016-08-15 13:44:10 +00:00
|
|
|
{
|
|
|
|
Q_UNUSED(id)
|
|
|
|
Q_UNUSED(time)
|
2020-05-24 01:37:25 +00:00
|
|
|
|
2016-08-15 13:44:10 +00:00
|
|
|
if (!m_activated) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
if (m_touch.active && m_touch.id == id) {
|
|
|
|
m_touch.active = false;
|
|
|
|
m_touch.id = 0;
|
|
|
|
if (m_highlightedWindow) {
|
|
|
|
mouseActionWindow(m_leftButtonWindow);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2011-01-30 14:34:42 +00:00
|
|
|
void PresentWindowsEffect::mouseActionWindow(WindowMouseAction& action)
|
|
|
|
{
|
|
|
|
switch(action) {
|
|
|
|
case WindowActivateAction:
|
|
|
|
if (m_highlightedWindow)
|
|
|
|
effects->activateWindow(m_highlightedWindow);
|
|
|
|
setActive(false);
|
|
|
|
break;
|
|
|
|
case WindowExitAction:
|
|
|
|
setActive(false);
|
|
|
|
break;
|
|
|
|
case WindowToCurrentDesktopAction:
|
|
|
|
if (m_highlightedWindow)
|
|
|
|
effects->windowToDesktop(m_highlightedWindow, effects->currentDesktop());
|
|
|
|
break;
|
|
|
|
case WindowToAllDesktopsAction:
|
|
|
|
if (m_highlightedWindow) {
|
|
|
|
if (m_highlightedWindow->isOnAllDesktops())
|
|
|
|
effects->windowToDesktop(m_highlightedWindow, effects->currentDesktop());
|
|
|
|
else
|
|
|
|
effects->windowToDesktop(m_highlightedWindow, NET::OnAllDesktops);
|
2007-04-29 17:35:43 +00:00
|
|
|
}
|
2011-01-30 14:34:42 +00:00
|
|
|
break;
|
|
|
|
case WindowMinimizeAction:
|
|
|
|
if (m_highlightedWindow) {
|
|
|
|
if (m_highlightedWindow->isMinimized())
|
|
|
|
m_highlightedWindow->unminimize();
|
|
|
|
else
|
|
|
|
m_highlightedWindow->minimize();
|
|
|
|
}
|
|
|
|
break;
|
[effects/presentwindows] Allow closing windows on middle-click
Summary:
Plasma's Task manager exposes an optional feature whereby the user
can middle-click on a window to close it, but the Present Windows effect
does not do the same.
The presence of a close button you can left-click does not replace the desirable
feature to be able to middle-click on a window to close it, because then the
whole window becomes a click target, so it can be much much faster than
having to aim for the little close button. Also it's off by default, so a user
who goes out of their way to turn it on is signaling that they want to accept the
risk of accidentally closing a window by accident.
Finally, the feature is not allowed for left-click, so people can never accidentally
wreck Present Windows for themselves by assigning it to left-click by accident
and then mistakenly closing their windows.
This reverts commit 55585514f926d1251148e876bfe9ce3504432997.
FEATURE: 321190
FIXED-IN: 5.17.0
Test Plan:
Set "Close window" in the Present windows effect, trigger effect, and middle-click on window
{F6815303}
Reviewers: #kwin, davidedmundson, broulik, zzag, #plasma, hein, mart
Reviewed By: #kwin, #plasma, mart
Subscribers: mart, abetts, apol, zzag, luebking, kossebau, graesslin, kwin
Tags: #kwin
Differential Revision: https://phabricator.kde.org/D21083
2019-05-08 14:57:08 +00:00
|
|
|
case WindowCloseAction:
|
|
|
|
if (m_highlightedWindow) {
|
|
|
|
m_highlightedWindow->closeWindow();
|
|
|
|
}
|
|
|
|
break;
|
2011-01-30 14:34:42 +00:00
|
|
|
default:
|
|
|
|
break;
|
2008-09-22 13:03:00 +00:00
|
|
|
}
|
2011-01-30 14:34:42 +00:00
|
|
|
}
|
2007-04-29 17:35:43 +00:00
|
|
|
|
2011-01-30 14:34:42 +00:00
|
|
|
void PresentWindowsEffect::mouseActionDesktop(DesktopMouseAction& action)
|
|
|
|
{
|
|
|
|
switch(action) {
|
|
|
|
case DesktopActivateAction:
|
|
|
|
if (m_highlightedWindow)
|
|
|
|
effects->activateWindow(m_highlightedWindow);
|
|
|
|
setActive(false);
|
|
|
|
break;
|
|
|
|
case DesktopExitAction:
|
|
|
|
setActive(false);
|
|
|
|
break;
|
|
|
|
case DesktopShowDesktopAction:
|
|
|
|
effects->setShowingDesktop(true);
|
|
|
|
setActive(false);
|
|
|
|
default:
|
|
|
|
break;
|
2009-06-28 17:17:29 +00:00
|
|
|
}
|
2011-01-30 14:34:42 +00:00
|
|
|
}
|
2009-06-28 17:17:29 +00:00
|
|
|
|
2011-01-30 14:34:42 +00:00
|
|
|
void PresentWindowsEffect::grabbedKeyboardEvent(QKeyEvent *e)
|
|
|
|
{
|
|
|
|
if (e->type() == QEvent::KeyPress) {
|
2009-03-30 11:27:57 +00:00
|
|
|
// 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 == ModeCurrentDesktop && shortcut.contains(e->key() + e->modifiers())) {
|
2009-03-30 11:27:57 +00:00
|
|
|
toggleActive();
|
|
|
|
return;
|
2011-01-30 14:34:42 +00:00
|
|
|
}
|
|
|
|
if (m_mode == ModeAllDesktops && shortcutAll.contains(e->key() + e->modifiers())) {
|
2009-03-30 11:27:57 +00:00
|
|
|
toggleActiveAllDesktops();
|
|
|
|
return;
|
2011-01-30 14:34:42 +00:00
|
|
|
}
|
|
|
|
if (m_mode == ModeWindowClass && shortcutClass.contains(e->key() + e->modifiers())) {
|
2009-06-30 19:11:02 +00:00
|
|
|
toggleActiveClass();
|
|
|
|
return;
|
2011-01-30 14:34:42 +00:00
|
|
|
}
|
2009-03-30 11:27:57 +00:00
|
|
|
|
2011-01-30 14:34:42 +00:00
|
|
|
switch(e->key()) {
|
|
|
|
// Wrap only if not auto-repeating
|
|
|
|
case Qt::Key_Left:
|
2012-03-13 07:46:09 +00:00
|
|
|
setHighlightedWindow(relativeWindow(m_highlightedWindow, -1, 0, !e->isAutoRepeat()));
|
2011-01-30 14:34:42 +00:00
|
|
|
break;
|
|
|
|
case Qt::Key_Right:
|
2012-03-13 07:46:09 +00:00
|
|
|
setHighlightedWindow(relativeWindow(m_highlightedWindow, 1, 0, !e->isAutoRepeat()));
|
2011-01-30 14:34:42 +00:00
|
|
|
break;
|
|
|
|
case Qt::Key_Up:
|
2012-03-13 07:46:09 +00:00
|
|
|
setHighlightedWindow(relativeWindow(m_highlightedWindow, 0, -1, !e->isAutoRepeat()));
|
2011-01-30 14:34:42 +00:00
|
|
|
break;
|
|
|
|
case Qt::Key_Down:
|
2012-03-13 07:46:09 +00:00
|
|
|
setHighlightedWindow(relativeWindow(m_highlightedWindow, 0, 1, !e->isAutoRepeat()));
|
2011-01-30 14:34:42 +00:00
|
|
|
break;
|
|
|
|
case Qt::Key_Home:
|
2012-03-13 07:46:09 +00:00
|
|
|
setHighlightedWindow(relativeWindow(m_highlightedWindow, -1000, 0, false));
|
2011-01-30 14:34:42 +00:00
|
|
|
break;
|
|
|
|
case Qt::Key_End:
|
2012-03-13 07:46:09 +00:00
|
|
|
setHighlightedWindow(relativeWindow(m_highlightedWindow, 1000, 0, false));
|
2011-01-30 14:34:42 +00:00
|
|
|
break;
|
|
|
|
case Qt::Key_PageUp:
|
2012-03-13 07:46:09 +00:00
|
|
|
setHighlightedWindow(relativeWindow(m_highlightedWindow, 0, -1000, false));
|
2011-01-30 14:34:42 +00:00
|
|
|
break;
|
|
|
|
case Qt::Key_PageDown:
|
2012-03-13 07:46:09 +00:00
|
|
|
setHighlightedWindow(relativeWindow(m_highlightedWindow, 0, 1000, false));
|
2011-01-30 14:34:42 +00:00
|
|
|
break;
|
|
|
|
case Qt::Key_Backspace:
|
|
|
|
if (!m_windowFilter.isEmpty()) {
|
|
|
|
m_windowFilter.remove(m_windowFilter.length() - 1, 1);
|
|
|
|
updateFilterFrame();
|
|
|
|
rearrangeWindows();
|
|
|
|
}
|
|
|
|
return;
|
|
|
|
case Qt::Key_Escape:
|
|
|
|
setActive(false);
|
|
|
|
return;
|
|
|
|
case Qt::Key_Return:
|
|
|
|
case Qt::Key_Enter:
|
|
|
|
if (m_highlightedWindow)
|
|
|
|
effects->activateWindow(m_highlightedWindow);
|
|
|
|
setActive(false);
|
|
|
|
return;
|
|
|
|
case Qt::Key_Tab:
|
|
|
|
return; // Nothing at the moment
|
|
|
|
case Qt::Key_Delete:
|
|
|
|
if (!m_windowFilter.isEmpty()) {
|
|
|
|
m_windowFilter.clear();
|
|
|
|
updateFilterFrame();
|
|
|
|
rearrangeWindows();
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
case 0:
|
|
|
|
return; // HACK: Workaround for Qt bug on unbound keys (#178547)
|
|
|
|
default:
|
|
|
|
if (!e->text().isEmpty()) {
|
|
|
|
m_windowFilter.append(e->text());
|
|
|
|
updateFilterFrame();
|
|
|
|
rearrangeWindows();
|
2008-09-22 13:03:00 +00:00
|
|
|
return;
|
2007-04-29 17:35:43 +00:00
|
|
|
}
|
2011-01-30 14:34:42 +00:00
|
|
|
break;
|
2007-04-29 17:35:43 +00:00
|
|
|
}
|
2008-08-26 14:06:09 +00:00
|
|
|
}
|
2011-01-30 14:34:42 +00:00
|
|
|
}
|
2008-08-26 14:06:09 +00:00
|
|
|
|
2009-06-27 10:21:49 +00:00
|
|
|
//-----------------------------------------------------------------------------
|
|
|
|
// Atom handling
|
2011-03-12 18:18:19 +00:00
|
|
|
void PresentWindowsEffect::slotPropertyNotify(EffectWindow* w, long a)
|
2011-01-30 14:34:42 +00:00
|
|
|
{
|
2017-09-10 14:51:18 +00:00
|
|
|
if (m_atomDesktop == XCB_ATOM_NONE && m_atomWindows == XCB_ATOM_NONE) {
|
|
|
|
return;
|
|
|
|
}
|
2011-01-30 14:34:42 +00:00
|
|
|
if (!w || (a != m_atomDesktop && a != m_atomWindows))
|
2009-06-27 10:21:49 +00:00
|
|
|
return; // Not our atom
|
|
|
|
|
2011-01-30 14:34:42 +00:00
|
|
|
if (a == m_atomDesktop) {
|
|
|
|
QByteArray byteData = w->readProperty(m_atomDesktop, m_atomDesktop, 32);
|
|
|
|
if (byteData.length() < 1) {
|
2009-06-27 10:21:49 +00:00
|
|
|
// Property was removed, end present windows
|
2011-01-30 14:34:42 +00:00
|
|
|
setActive(false);
|
2009-06-27 10:21:49 +00:00
|
|
|
return;
|
2011-01-30 14:34:42 +00:00
|
|
|
}
|
2013-09-25 06:54:22 +00:00
|
|
|
auto* data = reinterpret_cast<uint32_t*>(byteData.data());
|
2009-06-27 10:21:49 +00:00
|
|
|
|
2011-01-30 14:34:42 +00:00
|
|
|
if (!data[0]) {
|
2009-06-27 10:21:49 +00:00
|
|
|
// Purposely ending present windows by issuing a NULL target
|
2011-01-30 14:34:42 +00:00
|
|
|
setActive(false);
|
2009-06-27 10:21:49 +00:00
|
|
|
return;
|
2011-01-30 14:34:42 +00:00
|
|
|
}
|
2009-06-27 10:21:49 +00:00
|
|
|
// present windows is active so don't do anything
|
2011-01-30 14:34:42 +00:00
|
|
|
if (m_activated)
|
2009-06-27 10:21:49 +00:00
|
|
|
return;
|
|
|
|
|
|
|
|
int desktop = data[0];
|
2011-01-30 14:34:42 +00:00
|
|
|
if (desktop > effects->numberOfDesktops())
|
2009-06-27 10:21:49 +00:00
|
|
|
return;
|
2011-01-30 14:34:42 +00:00
|
|
|
if (desktop == -1)
|
2009-06-27 10:21:49 +00:00
|
|
|
toggleActiveAllDesktops();
|
2011-01-30 14:34:42 +00:00
|
|
|
else {
|
2009-06-27 10:21:49 +00:00
|
|
|
m_mode = ModeSelectedDesktop;
|
|
|
|
m_desktop = desktop;
|
|
|
|
m_managerWindow = w;
|
2011-01-30 14:34:42 +00:00
|
|
|
setActive(true);
|
2009-06-27 10:21:49 +00:00
|
|
|
}
|
2011-01-30 14:34:42 +00:00
|
|
|
} else if (a == m_atomWindows) {
|
|
|
|
QByteArray byteData = w->readProperty(m_atomWindows, m_atomWindows, 32);
|
|
|
|
if (byteData.length() < 1) {
|
2009-06-27 10:21:49 +00:00
|
|
|
// Property was removed, end present windows
|
2011-01-30 14:34:42 +00:00
|
|
|
setActive(false);
|
2009-06-27 10:21:49 +00:00
|
|
|
return;
|
2011-01-30 14:34:42 +00:00
|
|
|
}
|
2013-09-25 06:54:22 +00:00
|
|
|
auto* data = reinterpret_cast<uint32_t*>(byteData.data());
|
2009-06-27 10:21:49 +00:00
|
|
|
|
2011-01-30 14:34:42 +00:00
|
|
|
if (!data[0]) {
|
2009-06-27 10:21:49 +00:00
|
|
|
// Purposely ending present windows by issuing a NULL target
|
2011-01-30 14:34:42 +00:00
|
|
|
setActive(false);
|
2009-06-27 10:21:49 +00:00
|
|
|
return;
|
2011-01-30 14:34:42 +00:00
|
|
|
}
|
2009-06-27 10:21:49 +00:00
|
|
|
// present windows is active so don't do anything
|
2011-01-30 14:34:42 +00:00
|
|
|
if (m_activated)
|
2009-06-27 10:21:49 +00:00
|
|
|
return;
|
|
|
|
|
|
|
|
// for security clear selected windows
|
|
|
|
m_selectedWindows.clear();
|
2011-01-30 14:34:42 +00:00
|
|
|
int length = byteData.length() / sizeof(data[0]);
|
|
|
|
for (int i = 0; i < length; i++) {
|
|
|
|
EffectWindow* foundWin = effects->findWindow(data[i]);
|
|
|
|
if (!foundWin) {
|
2013-11-29 05:18:28 +00:00
|
|
|
qCDebug(KWINEFFECTS) << "Invalid window targetted for present windows. Requested:" << data[i];
|
2009-06-27 10:21:49 +00:00
|
|
|
continue;
|
|
|
|
}
|
2011-01-30 14:34:42 +00:00
|
|
|
m_selectedWindows.append(foundWin);
|
|
|
|
}
|
2009-06-27 10:21:49 +00:00
|
|
|
m_mode = ModeWindowGroup;
|
|
|
|
m_managerWindow = w;
|
2011-01-30 14:34:42 +00:00
|
|
|
setActive(true);
|
2009-06-27 10:21:49 +00:00
|
|
|
}
|
2011-01-30 14:34:42 +00:00
|
|
|
}
|
2009-06-27 10:21:49 +00:00
|
|
|
|
2008-09-22 13:03:00 +00:00
|
|
|
//-----------------------------------------------------------------------------
|
|
|
|
// Window rearranging
|
|
|
|
|
2007-04-29 17:35:43 +00:00
|
|
|
void PresentWindowsEffect::rearrangeWindows()
|
2011-01-30 14:34:42 +00:00
|
|
|
{
|
|
|
|
if (!m_activated)
|
2007-04-29 17:35:43 +00:00
|
|
|
return;
|
|
|
|
|
2008-09-22 13:03:00 +00:00
|
|
|
effects->addRepaintFull(); // Trigger the first repaint
|
2012-02-17 19:35:21 +00:00
|
|
|
if (m_closeView)
|
|
|
|
m_closeView->hide();
|
2008-09-22 13:03:00 +00:00
|
|
|
|
|
|
|
// Work out which windows are on which screens
|
2007-04-29 17:35:43 +00:00
|
|
|
EffectWindowList windowlist;
|
2008-09-22 13:03:00 +00:00
|
|
|
QList<EffectWindowList> windowlists;
|
2011-01-30 14:34:42 +00:00
|
|
|
for (int i = 0; i < effects->numScreens(); i++)
|
|
|
|
windowlists.append(EffectWindowList());
|
2008-06-10 15:49:49 +00:00
|
|
|
|
2011-01-30 14:34:42 +00:00
|
|
|
if (m_windowFilter.isEmpty()) {
|
2012-03-20 14:20:05 +00:00
|
|
|
windowlist = m_motionManager.managedWindows();
|
2011-01-30 14:34:42 +00:00
|
|
|
foreach (EffectWindow * w, m_motionManager.managedWindows()) {
|
2011-03-07 23:19:52 +00:00
|
|
|
DataHash::iterator winData = m_windowData.find(w);
|
|
|
|
if (winData == m_windowData.end() || winData->deleted)
|
2009-07-14 09:06:37 +00:00
|
|
|
continue; // don't include closed windows
|
2011-01-30 14:34:42 +00:00
|
|
|
windowlists[w->screen()].append(w);
|
2011-03-07 23:19:52 +00:00
|
|
|
winData->visible = true;
|
2008-06-10 15:49:49 +00:00
|
|
|
}
|
2011-01-30 14:34:42 +00:00
|
|
|
} else {
|
|
|
|
// Can we move this filtering somewhere else?
|
|
|
|
foreach (EffectWindow * w, m_motionManager.managedWindows()) {
|
2011-03-07 23:19:52 +00:00
|
|
|
DataHash::iterator winData = m_windowData.find(w);
|
|
|
|
if (winData == m_windowData.end() || winData->deleted)
|
2009-07-14 09:06:37 +00:00
|
|
|
continue; // don't include closed windows
|
2020-05-24 01:37:25 +00:00
|
|
|
|
2011-01-30 14:34:42 +00:00
|
|
|
if (w->caption().contains(m_windowFilter, Qt::CaseInsensitive) ||
|
|
|
|
w->windowClass().contains(m_windowFilter, Qt::CaseInsensitive) ||
|
|
|
|
w->windowRole().contains(m_windowFilter, Qt::CaseInsensitive)) {
|
|
|
|
windowlist.append(w);
|
|
|
|
windowlists[w->screen()].append(w);
|
2011-03-07 23:19:52 +00:00
|
|
|
winData->visible = true;
|
2011-01-30 14:34:42 +00:00
|
|
|
} else
|
2011-03-07 23:19:52 +00:00
|
|
|
winData->visible = false;
|
2007-04-29 17:35:43 +00:00
|
|
|
}
|
2011-01-30 14:34:42 +00:00
|
|
|
}
|
|
|
|
if (windowlist.isEmpty()) {
|
Use nullptr everywhere
Summary:
Because KWin is a very old project, we use three kinds of null pointer
literals: 0, NULL, and nullptr. Since C++11, it's recommended to use
nullptr keyword.
This change converts all usages of 0 and NULL literal to nullptr. Even
though it breaks git history, we need to do it in order to have consistent
code as well to ease code reviews (it's very tempting for some people to
add unrelated changes to their patches, e.g. converting NULL to nullptr).
Test Plan: Compiles.
Reviewers: #kwin, davidedmundson, romangg
Reviewed By: #kwin, davidedmundson, romangg
Subscribers: romangg, kwin
Tags: #kwin
Differential Revision: https://phabricator.kde.org/D23618
2019-09-19 14:46:54 +00:00
|
|
|
setHighlightedWindow(nullptr);
|
2007-04-29 17:35:43 +00:00
|
|
|
return;
|
2011-01-30 14:34:42 +00:00
|
|
|
}
|
2007-04-29 17:35:43 +00:00
|
|
|
|
2008-09-22 13:03:00 +00:00
|
|
|
// We filtered out the highlighted window
|
2011-01-30 14:34:42 +00:00
|
|
|
if (m_highlightedWindow) {
|
2011-03-07 23:19:52 +00:00
|
|
|
DataHash::iterator winData = m_windowData.find(m_highlightedWindow);
|
|
|
|
if (winData != m_windowData.end() && !winData->visible)
|
2011-01-30 14:34:42 +00:00
|
|
|
setHighlightedWindow(findFirstWindow());
|
2012-03-20 14:20:05 +00:00
|
|
|
} else
|
2011-01-30 14:34:42 +00:00
|
|
|
setHighlightedWindow(findFirstWindow());
|
2008-06-10 15:49:49 +00:00
|
|
|
|
2012-03-20 14:20:05 +00:00
|
|
|
int screens = effects->numScreens();
|
2011-01-30 14:34:42 +00:00
|
|
|
for (int screen = 0; screen < screens; screen++) {
|
2008-09-22 13:03:00 +00:00
|
|
|
EffectWindowList windows;
|
2012-03-20 14:20:05 +00:00
|
|
|
windows = windowlists[screen];
|
2008-09-22 13:03:00 +00:00
|
|
|
|
|
|
|
// Don't rearrange if the grid is the same size as what it was before to prevent
|
|
|
|
// windows moving to a better spot if one was filtered out.
|
2011-01-30 14:34:42 +00:00
|
|
|
if (m_layoutMode == LayoutRegularGrid &&
|
2018-04-20 18:18:24 +00:00
|
|
|
m_gridSizes[screen].columns &&
|
|
|
|
m_gridSizes[screen].rows &&
|
2011-01-30 14:34:42 +00:00
|
|
|
windows.size() < m_gridSizes[screen].columns * m_gridSizes[screen].rows &&
|
|
|
|
windows.size() > (m_gridSizes[screen].columns - 1) * m_gridSizes[screen].rows &&
|
2012-03-20 14:20:05 +00:00
|
|
|
windows.size() > m_gridSizes[screen].columns *(m_gridSizes[screen].rows - 1))
|
2008-09-22 13:03:00 +00:00
|
|
|
continue;
|
2008-08-27 08:29:09 +00:00
|
|
|
|
2008-09-22 13:03:00 +00:00
|
|
|
// No point continuing if there is no windows to process
|
2011-01-30 14:34:42 +00:00
|
|
|
if (!windows.count())
|
2008-09-22 13:03:00 +00:00
|
|
|
continue;
|
2008-06-10 15:49:49 +00:00
|
|
|
|
2011-01-30 14:34:42 +00:00
|
|
|
calculateWindowTransformations(windows, screen, m_motionManager);
|
|
|
|
}
|
2009-02-22 13:04:16 +00:00
|
|
|
|
|
|
|
// Resize text frames if required
|
Use nullptr everywhere
Summary:
Because KWin is a very old project, we use three kinds of null pointer
literals: 0, NULL, and nullptr. Since C++11, it's recommended to use
nullptr keyword.
This change converts all usages of 0 and NULL literal to nullptr. Even
though it breaks git history, we need to do it in order to have consistent
code as well to ease code reviews (it's very tempting for some people to
add unrelated changes to their patches, e.g. converting NULL to nullptr).
Test Plan: Compiles.
Reviewers: #kwin, davidedmundson, romangg
Reviewed By: #kwin, davidedmundson, romangg
Subscribers: romangg, kwin
Tags: #kwin
Differential Revision: https://phabricator.kde.org/D23618
2019-09-19 14:46:54 +00:00
|
|
|
QFontMetrics* metrics = nullptr; // All fonts are the same
|
2011-01-30 14:34:42 +00:00
|
|
|
foreach (EffectWindow * w, m_motionManager.managedWindows()) {
|
2011-03-07 23:19:52 +00:00
|
|
|
DataHash::iterator winData = m_windowData.find(w);
|
|
|
|
if (winData == m_windowData.end())
|
|
|
|
continue;
|
2020-05-24 01:37:25 +00:00
|
|
|
|
2011-01-30 14:34:42 +00:00
|
|
|
if (!metrics)
|
2011-03-07 23:19:52 +00:00
|
|
|
metrics = new QFontMetrics(winData->textFrame->font());
|
2020-05-24 01:37:25 +00:00
|
|
|
|
2011-01-30 14:34:42 +00:00
|
|
|
QRect geom = m_motionManager.targetGeometry(w).toRect();
|
|
|
|
QString string = metrics->elidedText(w->caption(), Qt::ElideRight, geom.width() * 0.9);
|
2011-03-07 23:19:52 +00:00
|
|
|
if (string != winData->textFrame->text())
|
|
|
|
winData->textFrame->setText(string);
|
2007-04-29 17:35:43 +00:00
|
|
|
}
|
2011-01-30 14:34:42 +00:00
|
|
|
delete metrics;
|
|
|
|
}
|
2007-04-29 17:35:43 +00:00
|
|
|
|
2011-01-30 14:34:42 +00:00
|
|
|
void PresentWindowsEffect::calculateWindowTransformations(EffectWindowList windowlist, int screen,
|
|
|
|
WindowMotionManager& motionManager, bool external)
|
|
|
|
{
|
2012-03-20 14:20:05 +00:00
|
|
|
if (m_layoutMode == LayoutRegularGrid)
|
2011-01-30 14:34:42 +00:00
|
|
|
calculateWindowTransformationsClosest(windowlist, screen, motionManager);
|
|
|
|
else if (m_layoutMode == LayoutFlexibleGrid)
|
|
|
|
calculateWindowTransformationsKompose(windowlist, screen, motionManager);
|
2009-12-18 03:34:28 +00:00
|
|
|
else
|
2011-01-30 14:34:42 +00:00
|
|
|
calculateWindowTransformationsNatural(windowlist, screen, motionManager);
|
2009-12-18 03:34:28 +00:00
|
|
|
|
|
|
|
// If called externally we don't need to remember this data
|
2011-01-30 14:34:42 +00:00
|
|
|
if (external)
|
2009-12-18 03:34:28 +00:00
|
|
|
m_windowData.clear();
|
2011-01-30 14:34:42 +00:00
|
|
|
}
|
2009-12-18 03:34:28 +00:00
|
|
|
|
2011-03-07 23:19:52 +00:00
|
|
|
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)));
|
|
|
|
}
|
|
|
|
|
2011-01-30 14:34:42 +00:00
|
|
|
void PresentWindowsEffect::calculateWindowTransformationsClosest(EffectWindowList windowlist, int screen,
|
|
|
|
WindowMotionManager& motionManager)
|
|
|
|
{
|
2009-12-18 03:34:28 +00:00
|
|
|
// This layout mode requires at least one window visible
|
2011-01-30 14:34:42 +00:00
|
|
|
if (windowlist.count() == 0)
|
2009-12-18 03:34:28 +00:00
|
|
|
return;
|
|
|
|
|
2011-01-30 14:34:42 +00:00
|
|
|
QRect area = effects->clientArea(ScreenArea, screen, effects->currentDesktop());
|
|
|
|
if (m_showPanel) // reserve space for the panel
|
|
|
|
area = effects->clientArea(MaximizeArea, screen, effects->currentDesktop());
|
|
|
|
int columns = int(ceil(sqrt(double(windowlist.count()))));
|
|
|
|
int rows = int(ceil(windowlist.count() / double(columns)));
|
2008-09-22 13:03:00 +00:00
|
|
|
|
|
|
|
// Remember the size for later
|
2009-12-18 03:34:28 +00:00
|
|
|
// If we are using this layout externally we don't need to remember m_gridSizes.
|
2011-01-30 14:34:42 +00:00
|
|
|
if (m_gridSizes.size() != 0) {
|
2009-12-18 03:34:28 +00:00
|
|
|
m_gridSizes[screen].columns = columns;
|
|
|
|
m_gridSizes[screen].rows = rows;
|
2011-01-30 14:34:42 +00:00
|
|
|
}
|
2008-09-22 13:03:00 +00:00
|
|
|
|
|
|
|
// Assign slots
|
2011-03-07 23:19:52 +00:00
|
|
|
int slotWidth = area.width() / columns;
|
|
|
|
int slotHeight = area.height() / rows;
|
|
|
|
QVector<EffectWindow*> takenSlots;
|
|
|
|
takenSlots.resize(rows*columns);
|
|
|
|
takenSlots.fill(0);
|
|
|
|
|
2012-03-20 14:20:05 +00:00
|
|
|
// precalculate all slot centers
|
|
|
|
QVector<QPoint> slotCenters;
|
|
|
|
slotCenters.resize(rows*columns);
|
|
|
|
for (int x = 0; x < columns; ++x)
|
|
|
|
for (int y = 0; y < rows; ++y) {
|
|
|
|
slotCenters[x + y*columns] = QPoint(area.x() + slotWidth * x + slotWidth / 2,
|
|
|
|
area.y() + slotHeight * y + slotHeight / 2);
|
|
|
|
}
|
2011-03-07 23:19:52 +00:00
|
|
|
|
2012-03-20 14:20:05 +00:00
|
|
|
// 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();
|
2020-05-24 01:37:25 +00:00
|
|
|
|
2012-03-20 14:20:05 +00:00
|
|
|
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];
|
2019-08-31 14:28:37 +00:00
|
|
|
Q_ASSERT(occupier != w);
|
2012-03-20 14:20:05 +00:00
|
|
|
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;
|
2011-03-07 23:19:52 +00:00
|
|
|
}
|
|
|
|
}
|
2008-06-10 15:49:49 +00:00
|
|
|
}
|
2019-08-31 14:28:37 +00:00
|
|
|
Q_ASSERT(slotCandidate != -1);
|
2012-03-20 14:20:05 +00:00
|
|
|
if (takenSlots[slotCandidate])
|
|
|
|
tmpList << takenSlots[slotCandidate]; // occupier needs a new home now :p
|
|
|
|
tmpList.removeAll(w);
|
|
|
|
takenSlots[slotCandidate] = w; // ...and we rumble in =)
|
2011-01-30 14:34:42 +00:00
|
|
|
}
|
2007-04-29 17:35:43 +00:00
|
|
|
|
2011-03-07 23:19:52 +00:00
|
|
|
for (int slot = 0; slot < columns*rows; ++slot) {
|
|
|
|
EffectWindow *w = takenSlots[slot];
|
|
|
|
if (!w) // some slots might be empty
|
|
|
|
continue;
|
2008-09-22 13:03:00 +00:00
|
|
|
|
|
|
|
// Work out where the slot is
|
|
|
|
QRect target(
|
2011-03-07 23:19:52 +00:00
|
|
|
area.x() + (slot % columns) * slotWidth,
|
|
|
|
area.y() + (slot / columns) * slotHeight,
|
2011-01-30 14:34:42 +00:00
|
|
|
slotWidth, slotHeight);
|
|
|
|
target.adjust(10, 10, -10, -10); // Borders
|
2020-05-24 01:37:25 +00:00
|
|
|
|
2008-09-22 13:03:00 +00:00
|
|
|
double scale;
|
2011-01-30 14:34:42 +00:00
|
|
|
if (target.width() / double(w->width()) < target.height() / double(w->height())) {
|
|
|
|
// Center vertically
|
|
|
|
scale = target.width() / double(w->width());
|
|
|
|
target.moveTop(target.top() + (target.height() - int(w->height() * scale)) / 2);
|
|
|
|
target.setHeight(int(w->height() * scale));
|
|
|
|
} else {
|
|
|
|
// Center horizontally
|
|
|
|
scale = target.height() / double(w->height());
|
|
|
|
target.moveLeft(target.left() + (target.width() - int(w->width() * scale)) / 2);
|
|
|
|
target.setWidth(int(w->width() * scale));
|
|
|
|
}
|
2008-09-22 13:03:00 +00:00
|
|
|
// Don't scale the windows too much
|
2011-01-30 14:34:42 +00:00
|
|
|
if (scale > 2.0 || (scale > 1.0 && (w->width() > 300 || w->height() > 300))) {
|
|
|
|
scale = (w->width() > 300 || w->height() > 300) ? 1.0 : 2.0;
|
2008-09-22 13:03:00 +00:00
|
|
|
target = QRect(
|
2011-01-30 14:34:42 +00:00
|
|
|
target.center().x() - int(w->width() * scale) / 2,
|
|
|
|
target.center().y() - int(w->height() * scale) / 2,
|
|
|
|
scale * w->width(), scale * w->height());
|
2008-09-22 13:03:00 +00:00
|
|
|
}
|
2011-01-30 14:34:42 +00:00
|
|
|
motionManager.moveWindow(w, target);
|
2007-04-29 17:35:43 +00:00
|
|
|
}
|
2011-01-30 14:34:42 +00:00
|
|
|
}
|
2007-04-29 17:35:43 +00:00
|
|
|
|
2011-01-30 14:34:42 +00:00
|
|
|
void PresentWindowsEffect::calculateWindowTransformationsKompose(EffectWindowList windowlist, int screen,
|
|
|
|
WindowMotionManager& motionManager)
|
|
|
|
{
|
2009-12-18 03:34:28 +00:00
|
|
|
// This layout mode requires at least one window visible
|
2011-01-30 14:34:42 +00:00
|
|
|
if (windowlist.count() == 0)
|
2009-12-18 03:34:28 +00:00
|
|
|
return;
|
|
|
|
|
2011-01-30 14:34:42 +00:00
|
|
|
QRect availRect = effects->clientArea(ScreenArea, screen, effects->currentDesktop());
|
|
|
|
if (m_showPanel) // reserve space for the panel
|
|
|
|
availRect = effects->clientArea(MaximizeArea, screen, effects->currentDesktop());
|
2019-07-09 21:00:07 +00:00
|
|
|
std::sort(windowlist.begin(), windowlist.end()); // The location of the windows should not depend on the stacking order
|
2007-04-29 17:35:43 +00:00
|
|
|
|
|
|
|
// Following code is taken from Kompose 0.5.4, src/komposelayout.cpp
|
|
|
|
int spacing = 10;
|
|
|
|
int rows, columns;
|
2007-09-03 15:00:43 +00:00
|
|
|
double parentRatio = availRect.width() / (double)availRect.height();
|
2007-04-29 17:35:43 +00:00
|
|
|
// Use more columns than rows when parent's width > parent's height
|
2011-01-30 14:34:42 +00:00
|
|
|
if (parentRatio > 1) {
|
|
|
|
columns = (int)ceil(sqrt((double)windowlist.count()));
|
|
|
|
rows = (int)ceil((double)windowlist.count() / (double)columns);
|
|
|
|
} else {
|
|
|
|
rows = (int)ceil(sqrt((double)windowlist.count()));
|
|
|
|
columns = (int)ceil((double)windowlist.count() / (double)rows);
|
2007-04-29 17:35:43 +00:00
|
|
|
}
|
2013-11-29 05:18:28 +00:00
|
|
|
//qCDebug(KWINEFFECTS) << "Using " << rows << " rows & " << columns << " columns for " << windowlist.count() << " clients";
|
2007-04-29 17:35:43 +00:00
|
|
|
|
|
|
|
// Calculate width & height
|
2011-01-30 14:34:42 +00:00
|
|
|
int w = (availRect.width() - (columns + 1) * spacing) / columns;
|
|
|
|
int h = (availRect.height() - (rows + 1) * spacing) / rows;
|
2007-04-29 17:35:43 +00:00
|
|
|
|
2011-01-30 14:34:42 +00:00
|
|
|
EffectWindowList::iterator it(windowlist.begin());
|
2007-04-29 17:35:43 +00:00
|
|
|
QList<QRect> geometryRects;
|
|
|
|
QList<int> maxRowHeights;
|
|
|
|
// Process rows
|
2011-01-30 14:34:42 +00:00
|
|
|
for (int i = 0; i < rows; ++i) {
|
2007-04-29 17:35:43 +00:00
|
|
|
int xOffsetFromLastCol = 0;
|
|
|
|
int maxHeightInRow = 0;
|
|
|
|
// Process columns
|
2011-01-30 14:34:42 +00:00
|
|
|
for (int j = 0; j < columns; ++j) {
|
2007-04-29 17:35:43 +00:00
|
|
|
EffectWindow* window;
|
|
|
|
|
|
|
|
// Check for end of List
|
2011-01-30 14:34:42 +00:00
|
|
|
if (it == windowlist.end())
|
2007-04-29 17:35:43 +00:00
|
|
|
break;
|
|
|
|
window = *it;
|
|
|
|
|
|
|
|
// Calculate width and height of widget
|
2011-01-30 14:34:42 +00:00
|
|
|
double ratio = aspectRatio(window);
|
2007-04-29 17:35:43 +00:00
|
|
|
|
|
|
|
int widgetw = 100;
|
|
|
|
int widgeth = 100;
|
|
|
|
int usableW = w;
|
|
|
|
int usableH = h;
|
|
|
|
|
|
|
|
// use width of two boxes if there is no right neighbour
|
2011-01-30 14:34:42 +00:00
|
|
|
if (window == windowlist.last() && j != columns - 1) {
|
|
|
|
usableW = 2 * w;
|
|
|
|
}
|
2007-04-29 17:35:43 +00:00
|
|
|
++it; // We need access to the neighbour in the following
|
|
|
|
// expand if right neighbour has ratio < 1
|
2011-01-30 14:34:42 +00:00
|
|
|
if (j != columns - 1 && it != windowlist.end() && aspectRatio(*it) < 1) {
|
2008-09-22 13:03:00 +00:00
|
|
|
int addW = w - widthForHeight(*it, h);
|
2011-01-30 14:34:42 +00:00
|
|
|
if (addW > 0) {
|
2007-04-29 17:35:43 +00:00
|
|
|
usableW = w + addW;
|
|
|
|
}
|
2011-01-30 14:34:42 +00:00
|
|
|
}
|
2007-04-29 17:35:43 +00:00
|
|
|
|
2011-01-30 14:34:42 +00:00
|
|
|
if (ratio == -1) {
|
2007-04-29 17:35:43 +00:00
|
|
|
widgetw = w;
|
|
|
|
widgeth = h;
|
2011-01-30 14:34:42 +00:00
|
|
|
} else {
|
|
|
|
double widthByHeight = widthForHeight(window, usableH);
|
|
|
|
double heightByWidth = heightForWidth(window, usableW);
|
|
|
|
if ((ratio >= 1.0 && heightByWidth <= usableH) ||
|
|
|
|
(ratio < 1.0 && widthByHeight > usableW)) {
|
2007-04-29 17:35:43 +00:00
|
|
|
widgetw = usableW;
|
2008-09-22 13:03:00 +00:00
|
|
|
widgeth = (int)heightByWidth;
|
2011-01-30 14:34:42 +00:00
|
|
|
} else if ((ratio < 1.0 && widthByHeight <= usableW) ||
|
|
|
|
(ratio >= 1.0 && heightByWidth > usableH)) {
|
2007-04-29 17:35:43 +00:00
|
|
|
widgeth = usableH;
|
2008-09-22 13:03:00 +00:00
|
|
|
widgetw = (int)widthByHeight;
|
2011-01-30 14:34:42 +00:00
|
|
|
}
|
2008-08-25 09:17:15 +00:00
|
|
|
// Don't upscale large-ish windows
|
2011-01-30 14:34:42 +00:00
|
|
|
if (widgetw > window->width() && (window->width() > 300 || window->height() > 300)) {
|
2008-08-25 09:17:15 +00:00
|
|
|
widgetw = window->width();
|
|
|
|
widgeth = window->height();
|
2007-04-29 17:35:43 +00:00
|
|
|
}
|
2011-01-30 14:34:42 +00:00
|
|
|
}
|
2007-04-29 17:35:43 +00:00
|
|
|
|
|
|
|
// Set the Widget's size
|
|
|
|
|
|
|
|
int alignmentXoffset = 0;
|
|
|
|
int alignmentYoffset = 0;
|
2011-01-30 14:34:42 +00:00
|
|
|
if (i == 0 && h > widgeth)
|
2007-04-29 17:35:43 +00:00
|
|
|
alignmentYoffset = h - widgeth;
|
2011-01-30 14:34:42 +00:00
|
|
|
if (j == 0 && w > widgetw)
|
2007-04-29 17:35:43 +00:00
|
|
|
alignmentXoffset = w - widgetw;
|
2011-01-30 14:34:42 +00:00
|
|
|
QRect geom(availRect.x() + j *(w + spacing) + spacing + alignmentXoffset + xOffsetFromLastCol,
|
|
|
|
availRect.y() + i *(h + spacing) + spacing + alignmentYoffset,
|
|
|
|
widgetw, widgeth);
|
2007-04-29 17:35:43 +00:00
|
|
|
geometryRects.append(geom);
|
|
|
|
|
2011-01-30 14:34:42 +00:00
|
|
|
// Set the x offset for the next column
|
|
|
|
if (alignmentXoffset == 0)
|
|
|
|
xOffsetFromLastCol += widgetw - w;
|
2007-04-29 17:35:43 +00:00
|
|
|
if (maxHeightInRow < widgeth)
|
|
|
|
maxHeightInRow = widgeth;
|
|
|
|
}
|
|
|
|
maxRowHeights.append(maxHeightInRow);
|
|
|
|
}
|
|
|
|
|
|
|
|
int topOffset = 0;
|
2011-01-30 14:34:42 +00:00
|
|
|
for (int i = 0; i < rows; i++) {
|
|
|
|
for (int j = 0; j < columns; j++) {
|
|
|
|
int pos = i * columns + j;
|
|
|
|
if (pos >= windowlist.count())
|
2007-04-29 17:35:43 +00:00
|
|
|
break;
|
|
|
|
|
|
|
|
EffectWindow* window = windowlist[pos];
|
2008-09-22 13:03:00 +00:00
|
|
|
QRect target = geometryRects[pos];
|
2011-01-30 14:34:42 +00:00
|
|
|
target.setY(target.y() + topOffset);
|
2011-03-07 23:19:52 +00:00
|
|
|
// @Marrtin: any idea what this is good for?
|
|
|
|
// DataHash::iterator winData = m_windowData.find(window);
|
|
|
|
// if (winData != m_windowData.end())
|
|
|
|
// winData->slot = pos;
|
2011-01-30 14:34:42 +00:00
|
|
|
motionManager.moveWindow(window, target);
|
2007-04-29 17:35:43 +00:00
|
|
|
|
2013-11-29 05:18:28 +00:00
|
|
|
//qCDebug(KWINEFFECTS) << "Window '" << window->caption() << "' gets moved to (" <<
|
2008-08-25 09:17:15 +00:00
|
|
|
// mWindowData[window].area.left() << "; " << mWindowData[window].area.right() <<
|
|
|
|
// "), scale: " << mWindowData[window].scale << endl;
|
2007-04-29 17:35:43 +00:00
|
|
|
}
|
2011-01-30 14:34:42 +00:00
|
|
|
if (maxRowHeights[i] - h > 0)
|
|
|
|
topOffset += maxRowHeights[i] - h;
|
2007-04-29 17:35:43 +00:00
|
|
|
}
|
2011-01-30 14:34:42 +00:00
|
|
|
}
|
2007-04-29 17:35:43 +00:00
|
|
|
|
2011-01-30 14:34:42 +00:00
|
|
|
void PresentWindowsEffect::calculateWindowTransformationsNatural(EffectWindowList windowlist, int screen,
|
|
|
|
WindowMotionManager& motionManager)
|
|
|
|
{
|
2008-11-27 15:11:10 +00:00
|
|
|
// If windows do not overlap they scale into nothingness, fix by resetting. To reproduce
|
|
|
|
// 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.
|
2011-01-30 14:34:42 +00:00
|
|
|
foreach (EffectWindow * w, windowlist)
|
2011-03-07 23:19:52 +00:00
|
|
|
if (motionManager.transformedGeometry(w) == w->geometry())
|
|
|
|
motionManager.reset(w);
|
2008-11-27 15:11:10 +00:00
|
|
|
|
2011-01-30 14:34:42 +00:00
|
|
|
if (windowlist.count() == 1) {
|
2008-11-27 15:11:10 +00:00
|
|
|
// Just move the window to its original location to save time
|
2011-01-30 14:34:42 +00:00
|
|
|
if (effects->clientArea(FullScreenArea, windowlist[0]).contains(windowlist[0]->geometry())) {
|
|
|
|
motionManager.moveWindow(windowlist[0], windowlist[0]->geometry());
|
2009-09-16 09:13:02 +00:00
|
|
|
return;
|
2008-09-29 02:25:02 +00:00
|
|
|
}
|
2011-01-30 14:34:42 +00:00
|
|
|
}
|
2008-09-29 02:25:02 +00:00
|
|
|
|
2008-09-22 13:03:00 +00:00
|
|
|
// As we are using pseudo-random movement (See "slot") we need to make sure the list
|
|
|
|
// is always sorted the same way no matter which window is currently active.
|
2019-07-09 21:00:07 +00:00
|
|
|
std::sort(windowlist.begin(), windowlist.end());
|
2008-09-22 13:03:00 +00:00
|
|
|
|
2011-01-30 14:34:42 +00:00
|
|
|
QRect area = effects->clientArea(ScreenArea, screen, effects->currentDesktop());
|
|
|
|
if (m_showPanel) // reserve space for the panel
|
|
|
|
area = effects->clientArea(MaximizeArea, screen, effects->currentDesktop());
|
2008-09-22 13:03:00 +00:00
|
|
|
QRect bounds = area;
|
|
|
|
int direction = 0;
|
|
|
|
QHash<EffectWindow*, QRect> targets;
|
2009-11-15 12:38:26 +00:00
|
|
|
QHash<EffectWindow*, int> directions;
|
2011-01-30 14:34:42 +00:00
|
|
|
foreach (EffectWindow * w, windowlist) {
|
|
|
|
bounds = bounds.united(w->geometry());
|
2008-09-22 13:03:00 +00:00
|
|
|
targets[w] = w->geometry();
|
|
|
|
// Reuse the unused "slot" as a preferred direction attribute. This is used when the window
|
|
|
|
// is on the edge of the screen to try to use as much screen real estate as possible.
|
2009-11-15 12:38:26 +00:00
|
|
|
directions[w] = direction;
|
2008-09-22 13:03:00 +00:00
|
|
|
direction++;
|
2011-01-30 14:34:42 +00:00
|
|
|
if (direction == 4)
|
2008-09-22 13:03:00 +00:00
|
|
|
direction = 0;
|
2011-01-30 14:34:42 +00:00
|
|
|
}
|
|
|
|
|
2008-09-22 13:03:00 +00:00
|
|
|
// Iterate over all windows, if two overlap push them apart _slightly_ as we try to
|
|
|
|
// brute-force the most optimal positions over many iterations.
|
|
|
|
bool overlap;
|
2011-01-30 14:34:42 +00:00
|
|
|
do {
|
2008-08-25 09:17:15 +00:00
|
|
|
overlap = false;
|
2011-01-30 14:34:42 +00:00
|
|
|
foreach (EffectWindow * w, windowlist) {
|
2011-03-07 23:19:52 +00:00
|
|
|
QRect *target_w = &targets[w];
|
2011-01-30 14:34:42 +00:00
|
|
|
foreach (EffectWindow * e, windowlist) {
|
2011-03-07 23:19:52 +00:00
|
|
|
if (w == e)
|
|
|
|
continue;
|
2020-05-24 01:37:25 +00:00
|
|
|
|
2011-03-07 23:19:52 +00:00
|
|
|
QRect *target_e = &targets[e];
|
|
|
|
if (target_w->adjusted(-5, -5, 5, 5).intersects(target_e->adjusted(-5, -5, 5, 5))) {
|
2008-08-25 09:17:15 +00:00
|
|
|
overlap = true;
|
|
|
|
|
|
|
|
// Determine pushing direction
|
2011-03-07 23:19:52 +00:00
|
|
|
QPoint diff(target_e->center() - target_w->center());
|
2008-08-25 09:17:15 +00:00
|
|
|
// Prevent dividing by zero and non-movement
|
2011-01-30 14:34:42 +00:00
|
|
|
if (diff.x() == 0 && diff.y() == 0)
|
|
|
|
diff.setX(1);
|
2008-08-25 09:17:15 +00:00
|
|
|
// Try to keep screen aspect ratio
|
2011-03-07 23:19:52 +00:00
|
|
|
//if (bounds.height() / bounds.width() > area.height() / area.width())
|
|
|
|
// diff.setY(diff.y() / 2);
|
2008-08-25 09:17:15 +00:00
|
|
|
//else
|
2011-03-07 23:19:52 +00:00
|
|
|
// diff.setX(diff.x() / 2);
|
2008-08-25 09:17:15 +00:00
|
|
|
// Approximate a vector of between 10px and 20px in magnitude in the same direction
|
2011-01-30 14:34:42 +00:00
|
|
|
diff *= m_accuracy / double(diff.manhattanLength());
|
2008-08-25 09:17:15 +00:00
|
|
|
// Move both windows apart
|
2011-03-07 23:19:52 +00:00
|
|
|
target_w->translate(-diff);
|
|
|
|
target_e->translate(diff);
|
2008-08-25 09:17:15 +00:00
|
|
|
|
|
|
|
// 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
|
|
|
|
// equal sections, if the window center is in any of the corner sections pull the
|
|
|
|
// window towards the outer corner. If it is in any of the other edge sections
|
|
|
|
// alternate between each corner on that edge. We don't want to determine it
|
|
|
|
// randomly as it will not produce consistant locations when using the filter.
|
|
|
|
// Only move one window so we don't cause large amounts of unnecessary zooming
|
2008-09-17 08:19:16 +00:00
|
|
|
// in some situations. We need to do this even when expanding later just in case
|
|
|
|
// all windows are the same size.
|
2008-08-25 09:17:15 +00:00
|
|
|
// (We are using an old bounding rect for this, hopefully it doesn't matter)
|
2011-03-07 23:19:52 +00:00
|
|
|
int xSection = (target_w->x() - bounds.x()) / (bounds.width() / 3);
|
|
|
|
int ySection = (target_w->y() - bounds.y()) / (bounds.height() / 3);
|
2011-01-30 14:34:42 +00:00
|
|
|
diff = QPoint(0, 0);
|
|
|
|
if (xSection != 1 || ySection != 1) { // Remove this if you want the center to pull as well
|
|
|
|
if (xSection == 1)
|
|
|
|
xSection = (directions[w] / 2 ? 2 : 0);
|
|
|
|
if (ySection == 1)
|
|
|
|
ySection = (directions[w] % 2 ? 2 : 0);
|
|
|
|
}
|
|
|
|
if (xSection == 0 && ySection == 0)
|
2011-03-07 23:19:52 +00:00
|
|
|
diff = QPoint(bounds.topLeft() - target_w->center());
|
2011-01-30 14:34:42 +00:00
|
|
|
if (xSection == 2 && ySection == 0)
|
2011-03-07 23:19:52 +00:00
|
|
|
diff = QPoint(bounds.topRight() - target_w->center());
|
2011-01-30 14:34:42 +00:00
|
|
|
if (xSection == 2 && ySection == 2)
|
2011-03-07 23:19:52 +00:00
|
|
|
diff = QPoint(bounds.bottomRight() - target_w->center());
|
2011-01-30 14:34:42 +00:00
|
|
|
if (xSection == 0 && ySection == 2)
|
2011-03-07 23:19:52 +00:00
|
|
|
diff = QPoint(bounds.bottomLeft() - target_w->center());
|
2011-01-30 14:34:42 +00:00
|
|
|
if (diff.x() != 0 || diff.y() != 0) {
|
|
|
|
diff *= m_accuracy / double(diff.manhattanLength());
|
2011-03-07 23:19:52 +00:00
|
|
|
target_w->translate(diff);
|
2008-08-25 09:17:15 +00:00
|
|
|
}
|
2011-01-30 14:34:42 +00:00
|
|
|
|
|
|
|
// Update bounding rect
|
2011-03-07 23:19:52 +00:00
|
|
|
bounds = bounds.united(*target_w);
|
|
|
|
bounds = bounds.united(*target_e);
|
2008-08-25 09:17:15 +00:00
|
|
|
}
|
|
|
|
}
|
2011-01-30 14:34:42 +00:00
|
|
|
}
|
|
|
|
} while (overlap);
|
2008-08-25 09:17:15 +00:00
|
|
|
|
|
|
|
// Work out scaling by getting the most top-left and most bottom-right window coords.
|
|
|
|
// The 20's and 10's are so that the windows don't touch the edge of the screen.
|
|
|
|
double scale;
|
2011-01-30 14:34:42 +00:00
|
|
|
if (bounds == area)
|
2008-08-25 09:17:15 +00:00
|
|
|
scale = 1.0; // Don't add borders to the screen
|
2011-01-30 14:34:42 +00:00
|
|
|
else if (area.width() / double(bounds.width()) < area.height() / double(bounds.height()))
|
|
|
|
scale = (area.width() - 20) / double(bounds.width());
|
2008-08-25 09:17:15 +00:00
|
|
|
else
|
2011-01-30 14:34:42 +00:00
|
|
|
scale = (area.height() - 20) / double(bounds.height());
|
2008-08-25 09:17:15 +00:00
|
|
|
// Make bounding rect fill the screen size for later steps
|
|
|
|
bounds = QRect(
|
Correctly align natural layout in present windows
Summary:
Present windows works as follows:
- It moves all windows about until nothing is overlapping with any
other window.
- This doesn't resize anything so ultimately we end up with a new
co-ordinate space that's bigger than the screen depending on the amount
of overlap.
- We then render this whole view transformed to the screen
The rectangle "bounds" is in overviewpixels, with "scale" being the
ratio to convert to screen pixels.
When adjusting the new bounds there's an attempt to centre align things.
As bounds is in "overviewpixels" we multiply references to the previous
bounds by scale, and divide everything through at the end. bounds.x/y
were missed.
This is mostly unoticable except on massive super-ultra-wide monitors
which will otherwise have a tendency to shift to the left.
Test Plan:
Kai created a whole new test framework for this code that copy pasted
this algorithm then showed mock windows as rectangles
Reviewers: #kwin, apol, broulik, zzag
Reviewed By: #kwin, apol, broulik, zzag
Subscribers: zzag, apol, kwin
Tags: #kwin
Differential Revision: https://phabricator.kde.org/D29705
2020-05-26 09:52:16 +00:00
|
|
|
(bounds.x() * scale - (area.width() - 20 - bounds.width() * scale) / 2 - 10) / scale,
|
|
|
|
(bounds.y() * scale - (area.height() - 20 - bounds.height() * scale) / 2 - 10) / scale,
|
2011-01-30 14:34:42 +00:00
|
|
|
area.width() / scale,
|
|
|
|
area.height() / scale
|
|
|
|
);
|
2008-08-25 09:17:15 +00:00
|
|
|
|
|
|
|
// Move all windows back onto the screen and set their scale
|
2011-03-07 23:19:52 +00:00
|
|
|
QHash<EffectWindow*, QRect>::iterator target = targets.begin();
|
|
|
|
while (target != targets.end()) {
|
|
|
|
target->setRect((target->x() - bounds.x()) * scale + area.x(),
|
|
|
|
(target->y() - bounds.y()) * scale + area.y(),
|
|
|
|
target->width() * scale,
|
|
|
|
target->height() * scale
|
|
|
|
);
|
|
|
|
++target;
|
|
|
|
}
|
2008-08-25 09:17:15 +00:00
|
|
|
|
|
|
|
// Try to fill the gaps by enlarging windows if they have the space
|
2011-01-30 14:34:42 +00:00
|
|
|
if (m_fillGaps) {
|
2008-08-25 09:17:15 +00:00
|
|
|
// Don't expand onto or over the border
|
2011-01-30 14:34:42 +00:00
|
|
|
QRegion borderRegion(area.adjusted(-200, -200, 200, 200));
|
|
|
|
borderRegion ^= area.adjusted(10 / scale, 10 / scale, -10 / scale, -10 / scale);
|
|
|
|
|
2008-08-25 09:17:15 +00:00
|
|
|
bool moved;
|
2011-01-30 14:34:42 +00:00
|
|
|
do {
|
2008-08-25 09:17:15 +00:00
|
|
|
moved = false;
|
2011-01-30 14:34:42 +00:00
|
|
|
foreach (EffectWindow * w, windowlist) {
|
2008-08-25 09:17:15 +00:00
|
|
|
QRect oldRect;
|
2011-03-07 23:19:52 +00:00
|
|
|
QRect *target = &targets[w];
|
2008-08-25 09:17:15 +00:00
|
|
|
// This may cause some slight distortion if the windows are enlarged a large amount
|
2008-09-22 13:03:00 +00:00
|
|
|
int widthDiff = m_accuracy;
|
2011-03-07 23:19:52 +00:00
|
|
|
int heightDiff = heightForWidth(w, target->width() + widthDiff) - target->height();
|
2008-08-25 09:17:15 +00:00
|
|
|
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.
|
2011-01-30 14:34:42 +00:00
|
|
|
|
2019-11-26 17:48:29 +00:00
|
|
|
// heightDiff (and yDiff) will be re-computed after each successful enlargement attempt
|
[effects/presentwindows] Avoid potential freeze during fill-gaps
Summary:
When using the natural layout algorithm with the fill-gaps option, a small
error (less than one) is introduced in windows' aspect ratio each time they are
enlarged due to floating-point roundoff.
Currently, the algorithm computes the width and height enlargement factors and
then attempts to enlarge in each of the four possible directions, repeating
until it can't enlarge any windows any further. Hence, this aspect ratio error
can be multiplied by up to four. Especially for small, long, and narrow
windows, this can result in a total error of greater than one by the end of
that loop iteration. If this occurs, on subsequent iterations the height
enlargement factor might then be computed as negative violating some of the
core assumptions of the algorithm and resulting in the loop iterating endlessly
until one of the window dimensions overflows, freezing the program for up to
several minutes.
To fix this, the height enlargement factor should be re-computed based on the
new width each time the window is enlarged, ensuring the error introduced in
the aspect ratio never exceeds one.
BUG: 364709
BUG: 380865
BUG: 368811
FIXED-IN: 5.15.0
Test Plan:
The most reliable way to reproduce the freeze seems to be to activate the
desktop-grid effect while a tool-tip window is fading in.
Ensure desktop-grid is configured to use present windows, and that present
windows is configured to use the natural layout algorithm with the fill gaps
option selected.
The freeze is still intermittent, but using this method should be able to be
triggered within about 10 tries without this fix.
After applying the fix, the freeze has never been observed.
Reviewers: #kwin, zzag
Reviewed By: #kwin, zzag
Subscribers: graesslin, kwin, zzag
Tags: #kwin
Differential Revision: https://phabricator.kde.org/D16278
2018-10-20 15:36:41 +00:00
|
|
|
// so that the error introduced in the window's aspect ratio is minimized
|
|
|
|
|
2008-08-25 09:17:15 +00:00
|
|
|
// Attempt enlarging to the top-right
|
2011-03-07 23:19:52 +00:00
|
|
|
oldRect = *target;
|
|
|
|
target->setRect(target->x() + xDiff,
|
|
|
|
target->y() - yDiff - heightDiff,
|
|
|
|
target->width() + widthDiff,
|
|
|
|
target->height() + heightDiff
|
|
|
|
);
|
2011-01-30 14:34:42 +00:00
|
|
|
if (isOverlappingAny(w, targets, borderRegion))
|
2011-03-07 23:19:52 +00:00
|
|
|
*target = oldRect;
|
[effects/presentwindows] Avoid potential freeze during fill-gaps
Summary:
When using the natural layout algorithm with the fill-gaps option, a small
error (less than one) is introduced in windows' aspect ratio each time they are
enlarged due to floating-point roundoff.
Currently, the algorithm computes the width and height enlargement factors and
then attempts to enlarge in each of the four possible directions, repeating
until it can't enlarge any windows any further. Hence, this aspect ratio error
can be multiplied by up to four. Especially for small, long, and narrow
windows, this can result in a total error of greater than one by the end of
that loop iteration. If this occurs, on subsequent iterations the height
enlargement factor might then be computed as negative violating some of the
core assumptions of the algorithm and resulting in the loop iterating endlessly
until one of the window dimensions overflows, freezing the program for up to
several minutes.
To fix this, the height enlargement factor should be re-computed based on the
new width each time the window is enlarged, ensuring the error introduced in
the aspect ratio never exceeds one.
BUG: 364709
BUG: 380865
BUG: 368811
FIXED-IN: 5.15.0
Test Plan:
The most reliable way to reproduce the freeze seems to be to activate the
desktop-grid effect while a tool-tip window is fading in.
Ensure desktop-grid is configured to use present windows, and that present
windows is configured to use the natural layout algorithm with the fill gaps
option selected.
The freeze is still intermittent, but using this method should be able to be
triggered within about 10 tries without this fix.
After applying the fix, the freeze has never been observed.
Reviewers: #kwin, zzag
Reviewed By: #kwin, zzag
Subscribers: graesslin, kwin, zzag
Tags: #kwin
Differential Revision: https://phabricator.kde.org/D16278
2018-10-20 15:36:41 +00:00
|
|
|
else {
|
2008-08-25 09:17:15 +00:00
|
|
|
moved = true;
|
[effects/presentwindows] Avoid potential freeze during fill-gaps
Summary:
When using the natural layout algorithm with the fill-gaps option, a small
error (less than one) is introduced in windows' aspect ratio each time they are
enlarged due to floating-point roundoff.
Currently, the algorithm computes the width and height enlargement factors and
then attempts to enlarge in each of the four possible directions, repeating
until it can't enlarge any windows any further. Hence, this aspect ratio error
can be multiplied by up to four. Especially for small, long, and narrow
windows, this can result in a total error of greater than one by the end of
that loop iteration. If this occurs, on subsequent iterations the height
enlargement factor might then be computed as negative violating some of the
core assumptions of the algorithm and resulting in the loop iterating endlessly
until one of the window dimensions overflows, freezing the program for up to
several minutes.
To fix this, the height enlargement factor should be re-computed based on the
new width each time the window is enlarged, ensuring the error introduced in
the aspect ratio never exceeds one.
BUG: 364709
BUG: 380865
BUG: 368811
FIXED-IN: 5.15.0
Test Plan:
The most reliable way to reproduce the freeze seems to be to activate the
desktop-grid effect while a tool-tip window is fading in.
Ensure desktop-grid is configured to use present windows, and that present
windows is configured to use the natural layout algorithm with the fill gaps
option selected.
The freeze is still intermittent, but using this method should be able to be
triggered within about 10 tries without this fix.
After applying the fix, the freeze has never been observed.
Reviewers: #kwin, zzag
Reviewed By: #kwin, zzag
Subscribers: graesslin, kwin, zzag
Tags: #kwin
Differential Revision: https://phabricator.kde.org/D16278
2018-10-20 15:36:41 +00:00
|
|
|
heightDiff = heightForWidth(w, target->width() + widthDiff) - target->height();
|
|
|
|
yDiff = heightDiff / 2;
|
|
|
|
}
|
2011-01-30 14:34:42 +00:00
|
|
|
|
2008-08-25 09:17:15 +00:00
|
|
|
// Attempt enlarging to the bottom-right
|
2011-03-07 23:19:52 +00:00
|
|
|
oldRect = *target;
|
|
|
|
target->setRect(
|
|
|
|
target->x() + xDiff,
|
|
|
|
target->y() + yDiff,
|
|
|
|
target->width() + widthDiff,
|
|
|
|
target->height() + heightDiff
|
2011-01-30 14:34:42 +00:00
|
|
|
);
|
|
|
|
if (isOverlappingAny(w, targets, borderRegion))
|
2011-03-07 23:19:52 +00:00
|
|
|
*target = oldRect;
|
[effects/presentwindows] Avoid potential freeze during fill-gaps
Summary:
When using the natural layout algorithm with the fill-gaps option, a small
error (less than one) is introduced in windows' aspect ratio each time they are
enlarged due to floating-point roundoff.
Currently, the algorithm computes the width and height enlargement factors and
then attempts to enlarge in each of the four possible directions, repeating
until it can't enlarge any windows any further. Hence, this aspect ratio error
can be multiplied by up to four. Especially for small, long, and narrow
windows, this can result in a total error of greater than one by the end of
that loop iteration. If this occurs, on subsequent iterations the height
enlargement factor might then be computed as negative violating some of the
core assumptions of the algorithm and resulting in the loop iterating endlessly
until one of the window dimensions overflows, freezing the program for up to
several minutes.
To fix this, the height enlargement factor should be re-computed based on the
new width each time the window is enlarged, ensuring the error introduced in
the aspect ratio never exceeds one.
BUG: 364709
BUG: 380865
BUG: 368811
FIXED-IN: 5.15.0
Test Plan:
The most reliable way to reproduce the freeze seems to be to activate the
desktop-grid effect while a tool-tip window is fading in.
Ensure desktop-grid is configured to use present windows, and that present
windows is configured to use the natural layout algorithm with the fill gaps
option selected.
The freeze is still intermittent, but using this method should be able to be
triggered within about 10 tries without this fix.
After applying the fix, the freeze has never been observed.
Reviewers: #kwin, zzag
Reviewed By: #kwin, zzag
Subscribers: graesslin, kwin, zzag
Tags: #kwin
Differential Revision: https://phabricator.kde.org/D16278
2018-10-20 15:36:41 +00:00
|
|
|
else {
|
2008-08-25 09:17:15 +00:00
|
|
|
moved = true;
|
[effects/presentwindows] Avoid potential freeze during fill-gaps
Summary:
When using the natural layout algorithm with the fill-gaps option, a small
error (less than one) is introduced in windows' aspect ratio each time they are
enlarged due to floating-point roundoff.
Currently, the algorithm computes the width and height enlargement factors and
then attempts to enlarge in each of the four possible directions, repeating
until it can't enlarge any windows any further. Hence, this aspect ratio error
can be multiplied by up to four. Especially for small, long, and narrow
windows, this can result in a total error of greater than one by the end of
that loop iteration. If this occurs, on subsequent iterations the height
enlargement factor might then be computed as negative violating some of the
core assumptions of the algorithm and resulting in the loop iterating endlessly
until one of the window dimensions overflows, freezing the program for up to
several minutes.
To fix this, the height enlargement factor should be re-computed based on the
new width each time the window is enlarged, ensuring the error introduced in
the aspect ratio never exceeds one.
BUG: 364709
BUG: 380865
BUG: 368811
FIXED-IN: 5.15.0
Test Plan:
The most reliable way to reproduce the freeze seems to be to activate the
desktop-grid effect while a tool-tip window is fading in.
Ensure desktop-grid is configured to use present windows, and that present
windows is configured to use the natural layout algorithm with the fill gaps
option selected.
The freeze is still intermittent, but using this method should be able to be
triggered within about 10 tries without this fix.
After applying the fix, the freeze has never been observed.
Reviewers: #kwin, zzag
Reviewed By: #kwin, zzag
Subscribers: graesslin, kwin, zzag
Tags: #kwin
Differential Revision: https://phabricator.kde.org/D16278
2018-10-20 15:36:41 +00:00
|
|
|
heightDiff = heightForWidth(w, target->width() + widthDiff) - target->height();
|
|
|
|
yDiff = heightDiff / 2;
|
|
|
|
}
|
2011-01-30 14:34:42 +00:00
|
|
|
|
2008-08-25 09:17:15 +00:00
|
|
|
// Attempt enlarging to the bottom-left
|
2011-03-07 23:19:52 +00:00
|
|
|
oldRect = *target;
|
|
|
|
target->setRect(
|
|
|
|
target->x() - xDiff - widthDiff,
|
|
|
|
target->y() + yDiff,
|
|
|
|
target->width() + widthDiff,
|
|
|
|
target->height() + heightDiff
|
2011-01-30 14:34:42 +00:00
|
|
|
);
|
|
|
|
if (isOverlappingAny(w, targets, borderRegion))
|
2011-03-07 23:19:52 +00:00
|
|
|
*target = oldRect;
|
[effects/presentwindows] Avoid potential freeze during fill-gaps
Summary:
When using the natural layout algorithm with the fill-gaps option, a small
error (less than one) is introduced in windows' aspect ratio each time they are
enlarged due to floating-point roundoff.
Currently, the algorithm computes the width and height enlargement factors and
then attempts to enlarge in each of the four possible directions, repeating
until it can't enlarge any windows any further. Hence, this aspect ratio error
can be multiplied by up to four. Especially for small, long, and narrow
windows, this can result in a total error of greater than one by the end of
that loop iteration. If this occurs, on subsequent iterations the height
enlargement factor might then be computed as negative violating some of the
core assumptions of the algorithm and resulting in the loop iterating endlessly
until one of the window dimensions overflows, freezing the program for up to
several minutes.
To fix this, the height enlargement factor should be re-computed based on the
new width each time the window is enlarged, ensuring the error introduced in
the aspect ratio never exceeds one.
BUG: 364709
BUG: 380865
BUG: 368811
FIXED-IN: 5.15.0
Test Plan:
The most reliable way to reproduce the freeze seems to be to activate the
desktop-grid effect while a tool-tip window is fading in.
Ensure desktop-grid is configured to use present windows, and that present
windows is configured to use the natural layout algorithm with the fill gaps
option selected.
The freeze is still intermittent, but using this method should be able to be
triggered within about 10 tries without this fix.
After applying the fix, the freeze has never been observed.
Reviewers: #kwin, zzag
Reviewed By: #kwin, zzag
Subscribers: graesslin, kwin, zzag
Tags: #kwin
Differential Revision: https://phabricator.kde.org/D16278
2018-10-20 15:36:41 +00:00
|
|
|
else {
|
2008-08-25 09:17:15 +00:00
|
|
|
moved = true;
|
[effects/presentwindows] Avoid potential freeze during fill-gaps
Summary:
When using the natural layout algorithm with the fill-gaps option, a small
error (less than one) is introduced in windows' aspect ratio each time they are
enlarged due to floating-point roundoff.
Currently, the algorithm computes the width and height enlargement factors and
then attempts to enlarge in each of the four possible directions, repeating
until it can't enlarge any windows any further. Hence, this aspect ratio error
can be multiplied by up to four. Especially for small, long, and narrow
windows, this can result in a total error of greater than one by the end of
that loop iteration. If this occurs, on subsequent iterations the height
enlargement factor might then be computed as negative violating some of the
core assumptions of the algorithm and resulting in the loop iterating endlessly
until one of the window dimensions overflows, freezing the program for up to
several minutes.
To fix this, the height enlargement factor should be re-computed based on the
new width each time the window is enlarged, ensuring the error introduced in
the aspect ratio never exceeds one.
BUG: 364709
BUG: 380865
BUG: 368811
FIXED-IN: 5.15.0
Test Plan:
The most reliable way to reproduce the freeze seems to be to activate the
desktop-grid effect while a tool-tip window is fading in.
Ensure desktop-grid is configured to use present windows, and that present
windows is configured to use the natural layout algorithm with the fill gaps
option selected.
The freeze is still intermittent, but using this method should be able to be
triggered within about 10 tries without this fix.
After applying the fix, the freeze has never been observed.
Reviewers: #kwin, zzag
Reviewed By: #kwin, zzag
Subscribers: graesslin, kwin, zzag
Tags: #kwin
Differential Revision: https://phabricator.kde.org/D16278
2018-10-20 15:36:41 +00:00
|
|
|
heightDiff = heightForWidth(w, target->width() + widthDiff) - target->height();
|
|
|
|
yDiff = heightDiff / 2;
|
|
|
|
}
|
2011-01-30 14:34:42 +00:00
|
|
|
|
2008-08-25 09:17:15 +00:00
|
|
|
// Attempt enlarging to the top-left
|
2011-03-07 23:19:52 +00:00
|
|
|
oldRect = *target;
|
|
|
|
target->setRect(
|
|
|
|
target->x() - xDiff - widthDiff,
|
|
|
|
target->y() - yDiff - heightDiff,
|
|
|
|
target->width() + widthDiff,
|
|
|
|
target->height() + heightDiff
|
2011-01-30 14:34:42 +00:00
|
|
|
);
|
|
|
|
if (isOverlappingAny(w, targets, borderRegion))
|
2011-03-07 23:19:52 +00:00
|
|
|
*target = oldRect;
|
2008-08-25 09:17:15 +00:00
|
|
|
else
|
|
|
|
moved = true;
|
2011-01-30 14:34:42 +00:00
|
|
|
}
|
|
|
|
} while (moved);
|
2008-08-25 09:17:15 +00:00
|
|
|
|
|
|
|
// The expanding code above can actually enlarge windows over 1.0/2.0 scale, we don't like this
|
|
|
|
// 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.
|
2011-01-30 14:34:42 +00:00
|
|
|
foreach (EffectWindow * w, windowlist) {
|
2011-03-07 23:19:52 +00:00
|
|
|
QRect *target = &targets[w];
|
|
|
|
double scale = target->width() / double(w->width());
|
2011-01-30 14:34:42 +00:00
|
|
|
if (scale > 2.0 || (scale > 1.0 && (w->width() > 300 || w->height() > 300))) {
|
|
|
|
scale = (w->width() > 300 || w->height() > 300) ? 1.0 : 2.0;
|
2011-03-07 23:19:52 +00:00
|
|
|
target->setRect(
|
|
|
|
target->center().x() - int(w->width() * scale) / 2,
|
|
|
|
target->center().y() - int(w->height() * scale) / 2,
|
2011-01-30 14:34:42 +00:00
|
|
|
w->width() * scale,
|
|
|
|
w->height() * scale);
|
2008-08-25 09:17:15 +00:00
|
|
|
}
|
|
|
|
}
|
2011-01-30 14:34:42 +00:00
|
|
|
}
|
2008-09-22 13:03:00 +00:00
|
|
|
|
|
|
|
// Notify the motion manager of the targets
|
2011-01-30 14:34:42 +00:00
|
|
|
foreach (EffectWindow * w, windowlist)
|
2011-03-07 23:19:52 +00:00
|
|
|
motionManager.moveWindow(w, targets.value(w));
|
2011-01-30 14:34:42 +00:00
|
|
|
}
|
2008-09-22 13:03:00 +00:00
|
|
|
|
2011-01-30 14:34:42 +00:00
|
|
|
bool PresentWindowsEffect::isOverlappingAny(EffectWindow *w, const QHash<EffectWindow*, QRect> &targets, const QRegion &border)
|
|
|
|
{
|
2011-03-07 23:19:52 +00:00
|
|
|
QHash<EffectWindow*, QRect>::const_iterator winTarget = targets.find(w);
|
|
|
|
if (winTarget == targets.constEnd())
|
|
|
|
return false;
|
|
|
|
if (border.intersects(*winTarget))
|
2008-08-25 09:17:15 +00:00
|
|
|
return true;
|
2020-05-24 01:37:25 +00:00
|
|
|
|
2008-08-25 09:17:15 +00:00
|
|
|
// Is there a better way to do this?
|
2011-03-07 23:19:52 +00:00
|
|
|
QHash<EffectWindow*, QRect>::const_iterator target;
|
|
|
|
for (target = targets.constBegin(); target != targets.constEnd(); ++target) {
|
|
|
|
if (target == winTarget)
|
2008-08-25 09:17:15 +00:00
|
|
|
continue;
|
2011-03-07 23:19:52 +00:00
|
|
|
if (winTarget->adjusted(-5, -5, 5, 5).intersects(target->adjusted(-5, -5, 5, 5)))
|
2008-08-25 09:17:15 +00:00
|
|
|
return true;
|
|
|
|
}
|
2011-01-30 14:34:42 +00:00
|
|
|
return false;
|
|
|
|
}
|
2008-08-25 09:17:15 +00:00
|
|
|
|
2008-09-22 13:03:00 +00:00
|
|
|
//-----------------------------------------------------------------------------
|
|
|
|
// Activation
|
|
|
|
|
2012-05-24 09:15:24 +00:00
|
|
|
void PresentWindowsEffect::setActive(bool active)
|
2011-01-30 14:34:42 +00:00
|
|
|
{
|
|
|
|
if (effects->activeFullScreenEffect() && effects->activeFullScreenEffect() != this)
|
2008-09-22 13:03:00 +00:00
|
|
|
return;
|
2011-01-30 14:34:42 +00:00
|
|
|
if (m_activated == active)
|
2008-09-22 13:03:00 +00:00
|
|
|
return;
|
2020-05-24 01:37:25 +00:00
|
|
|
|
2008-09-22 13:03:00 +00:00
|
|
|
m_activated = active;
|
2011-01-30 14:34:42 +00:00
|
|
|
if (m_activated) {
|
2015-02-18 01:09:00 +00:00
|
|
|
effects->setShowingDesktop(false);
|
2013-06-27 19:54:50 +00:00
|
|
|
m_needInitialSelection = true;
|
2011-04-25 15:04:04 +00:00
|
|
|
m_closeButtonCorner = (Qt::Corner)effects->kwinOption(KWin::CloseButtonCorner).toInt();
|
2008-09-22 13:03:00 +00:00
|
|
|
m_decalOpacity = 0.0;
|
Use nullptr everywhere
Summary:
Because KWin is a very old project, we use three kinds of null pointer
literals: 0, NULL, and nullptr. Since C++11, it's recommended to use
nullptr keyword.
This change converts all usages of 0 and NULL literal to nullptr. Even
though it breaks git history, we need to do it in order to have consistent
code as well to ease code reviews (it's very tempting for some people to
add unrelated changes to their patches, e.g. converting NULL to nullptr).
Test Plan: Compiles.
Reviewers: #kwin, davidedmundson, romangg
Reviewed By: #kwin, davidedmundson, romangg
Subscribers: romangg, kwin
Tags: #kwin
Differential Revision: https://phabricator.kde.org/D23618
2019-09-19 14:46:54 +00:00
|
|
|
m_highlightedWindow = nullptr;
|
2008-09-22 13:03:00 +00:00
|
|
|
m_windowFilter.clear();
|
|
|
|
|
2015-03-02 15:00:10 +00:00
|
|
|
if (!(m_doNotCloseWindows || m_closeView)) {
|
2012-02-17 19:35:21 +00:00
|
|
|
m_closeView = new CloseWindowView();
|
2019-10-21 13:36:39 +00:00
|
|
|
connect(m_closeView, &EffectQuickView::repaintNeeded, this, []() {
|
|
|
|
effects->addRepaintFull();
|
|
|
|
});
|
2013-08-05 12:08:23 +00:00
|
|
|
connect(m_closeView, &CloseWindowView::requestClose, this, &PresentWindowsEffect::closeWindow);
|
2012-02-17 19:35:21 +00:00
|
|
|
}
|
2010-09-30 20:25:22 +00:00
|
|
|
|
2008-09-22 13:03:00 +00:00
|
|
|
// Add every single window to m_windowData (Just calling [w] creates it)
|
2011-01-30 14:34:42 +00:00
|
|
|
foreach (EffectWindow * w, effects->stackingOrder()) {
|
2011-03-07 23:19:52 +00:00
|
|
|
DataHash::iterator winData;
|
|
|
|
if ((winData = m_windowData.find(w)) != m_windowData.end()) {
|
|
|
|
winData->visible = isVisibleWindow(w);
|
|
|
|
continue; // Happens if we reactivate before the ending animation finishes
|
|
|
|
}
|
2020-05-24 01:37:25 +00:00
|
|
|
|
2011-03-07 23:19:52 +00:00
|
|
|
winData = m_windowData.insert(w, WindowData());
|
|
|
|
winData->visible = isVisibleWindow(w);
|
|
|
|
winData->deleted = false;
|
|
|
|
winData->referenced = false;
|
|
|
|
winData->opacity = 0.0;
|
2011-01-30 14:34:42 +00:00
|
|
|
if (w->isOnCurrentDesktop() && !w->isMinimized())
|
2011-03-07 23:19:52 +00:00
|
|
|
winData->opacity = 1.0;
|
2020-05-24 01:37:25 +00:00
|
|
|
|
2011-03-07 23:19:52 +00:00
|
|
|
winData->highlight = 1.0;
|
|
|
|
winData->textFrame = effects->effectFrame(EffectFrameUnstyled, false);
|
2020-05-24 01:37:25 +00:00
|
|
|
|
2009-02-22 13:04:16 +00:00
|
|
|
QFont font;
|
2011-01-30 14:34:42 +00:00
|
|
|
font.setBold(true);
|
|
|
|
font.setPointSize(12);
|
2020-05-24 01:37:25 +00:00
|
|
|
|
2011-03-07 23:19:52 +00:00
|
|
|
winData->textFrame->setFont(font);
|
|
|
|
winData->iconFrame = effects->effectFrame(EffectFrameUnstyled, false);
|
|
|
|
winData->iconFrame->setAlignment(Qt::AlignRight | Qt::AlignBottom);
|
|
|
|
winData->iconFrame->setIcon(w->icon());
|
2013-12-06 13:41:23 +00:00
|
|
|
winData->iconFrame->setIconSize(QSize(32, 32));
|
2011-01-30 14:34:42 +00:00
|
|
|
}
|
2020-05-24 01:37:25 +00:00
|
|
|
|
2012-03-20 14:20:05 +00:00
|
|
|
// Filter out special windows such as panels and taskbars
|
|
|
|
foreach (EffectWindow * w, effects->stackingOrder()) {
|
|
|
|
if (isSelectableWindow(w)) {
|
2011-01-30 14:34:42 +00:00
|
|
|
m_motionManager.manage(w);
|
2011-03-07 23:19:52 +00:00
|
|
|
}
|
2011-01-30 14:34:42 +00:00
|
|
|
}
|
2020-05-24 01:37:25 +00:00
|
|
|
|
2011-01-30 14:34:42 +00:00
|
|
|
if (m_motionManager.managedWindows().isEmpty() ||
|
2020-05-24 01:37:25 +00:00
|
|
|
((m_motionManager.managedWindows().count() == 1) && m_motionManager.managedWindows().first()->isOnCurrentDesktop() &&
|
2011-01-30 14:34:42 +00:00
|
|
|
(m_ignoreMinimized || !m_motionManager.managedWindows().first()->isMinimized()))) {
|
|
|
|
// No point triggering if there is nothing to do
|
2008-09-22 13:03:00 +00:00
|
|
|
m_activated = false;
|
2009-02-22 13:04:16 +00:00
|
|
|
|
|
|
|
DataHash::iterator i = m_windowData.begin();
|
2011-01-30 14:34:42 +00:00
|
|
|
while (i != m_windowData.end()) {
|
2009-02-22 13:04:16 +00:00
|
|
|
delete i.value().textFrame;
|
|
|
|
delete i.value().iconFrame;
|
2011-03-07 23:19:52 +00:00
|
|
|
++i;
|
2011-01-30 14:34:42 +00:00
|
|
|
}
|
2008-09-22 13:03:00 +00:00
|
|
|
m_windowData.clear();
|
2009-02-22 13:04:16 +00:00
|
|
|
|
2008-09-22 13:03:00 +00:00
|
|
|
m_motionManager.unmanageAll();
|
|
|
|
return;
|
2011-01-30 14:34:42 +00:00
|
|
|
}
|
2008-09-22 13:03:00 +00:00
|
|
|
|
|
|
|
// Create temporary input window to catch mouse events
|
2013-04-24 14:51:04 +00:00
|
|
|
effects->startMouseInterception(this, Qt::PointingHandCursor);
|
2011-01-30 14:34:42 +00:00
|
|
|
m_hasKeyboardGrab = effects->grabKeyboard(this);
|
|
|
|
effects->setActiveFullScreenEffect(this);
|
2008-09-22 13:03:00 +00:00
|
|
|
|
2015-08-28 05:50:20 +00:00
|
|
|
reCreateGrids();
|
2008-09-22 13:03:00 +00:00
|
|
|
rearrangeWindows();
|
2012-03-20 14:20:05 +00:00
|
|
|
setHighlightedWindow(effects->activeWindow());
|
2010-06-23 16:47:08 +00:00
|
|
|
|
2011-01-30 14:34:42 +00:00
|
|
|
foreach (EffectWindow * w, effects->stackingOrder()) {
|
[effects/presentwindows] Enable blur behind windows
Summary:
Use the blur effect even when the present windows is used.
Previously it was only enabled for the close buttons and the dock.
Test Plan: {F5828442}
Reviewers: davidedmundson, fredrik, #vdg, #kwin, graesslin, ngraham
Reviewed By: #vdg, #kwin, graesslin, ngraham
Subscribers: ngraham, zzag, kwin, #kwin
Tags: #kwin
Differential Revision: https://phabricator.kde.org/D12619
2018-05-01 20:55:48 +00:00
|
|
|
w->setData(WindowForceBlurRole, QVariant(true));
|
|
|
|
w->setData(WindowForceBackgroundContrastRole, QVariant(true));
|
2007-04-29 17:35:43 +00:00
|
|
|
}
|
2011-01-30 14:34:42 +00:00
|
|
|
} else {
|
2013-06-27 19:54:50 +00:00
|
|
|
m_needInitialSelection = false;
|
2011-04-25 15:04:04 +00:00
|
|
|
if (m_highlightedWindow)
|
|
|
|
effects->setElevatedWindow(m_highlightedWindow, false);
|
2020-05-24 01:37:25 +00:00
|
|
|
|
2008-09-22 13:03:00 +00:00
|
|
|
// Fade in/out all windows
|
2009-12-06 13:54:23 +00:00
|
|
|
EffectWindow *activeWindow = effects->activeWindow();
|
|
|
|
int desktop = effects->currentDesktop();
|
2011-01-30 14:34:42 +00:00
|
|
|
if (activeWindow && !activeWindow->isOnAllDesktops())
|
2009-12-06 13:54:23 +00:00
|
|
|
desktop = activeWindow->desktop();
|
2011-01-30 14:34:42 +00:00
|
|
|
foreach (EffectWindow * w, effects->stackingOrder()) {
|
2011-03-07 23:19:52 +00:00
|
|
|
DataHash::iterator winData = m_windowData.find(w);
|
|
|
|
if (winData != m_windowData.end())
|
|
|
|
winData->visible = (w->isOnDesktop(desktop) || w->isOnAllDesktops()) &&
|
2019-09-14 08:58:12 +00:00
|
|
|
!w->isMinimized();
|
2011-01-30 14:34:42 +00:00
|
|
|
}
|
2015-03-02 15:00:10 +00:00
|
|
|
if (m_closeView)
|
|
|
|
m_closeView->hide();
|
2008-09-22 13:03:00 +00:00
|
|
|
|
|
|
|
// Move all windows back to their original position
|
2011-01-30 14:34:42 +00:00
|
|
|
foreach (EffectWindow * w, m_motionManager.managedWindows())
|
|
|
|
m_motionManager.moveWindow(w, w->geometry());
|
2012-05-03 08:34:09 +00:00
|
|
|
if (m_filterFrame) {
|
|
|
|
m_filterFrame->free();
|
|
|
|
}
|
2008-09-22 13:03:00 +00:00
|
|
|
m_windowFilter.clear();
|
2009-06-27 10:21:49 +00:00
|
|
|
m_selectedWindows.clear();
|
2008-09-22 13:03:00 +00:00
|
|
|
|
2013-04-24 14:51:04 +00:00
|
|
|
effects->stopMouseInterception(this);
|
2011-01-30 14:34:42 +00:00
|
|
|
if (m_hasKeyboardGrab)
|
2008-09-22 13:03:00 +00:00
|
|
|
effects->ungrabKeyboard();
|
|
|
|
m_hasKeyboardGrab = false;
|
2009-06-27 10:21:49 +00:00
|
|
|
|
|
|
|
// destroy atom on manager window
|
2011-01-30 14:34:42 +00:00
|
|
|
if (m_managerWindow) {
|
2017-09-10 14:51:18 +00:00
|
|
|
if (m_mode == ModeSelectedDesktop && m_atomDesktop != XCB_ATOM_NONE)
|
2011-01-30 14:34:42 +00:00
|
|
|
m_managerWindow->deleteProperty(m_atomDesktop);
|
2017-09-10 14:51:18 +00:00
|
|
|
else if (m_mode == ModeWindowGroup && m_atomWindows != XCB_ATOM_NONE)
|
2011-01-30 14:34:42 +00:00
|
|
|
m_managerWindow->deleteProperty(m_atomWindows);
|
Use nullptr everywhere
Summary:
Because KWin is a very old project, we use three kinds of null pointer
literals: 0, NULL, and nullptr. Since C++11, it's recommended to use
nullptr keyword.
This change converts all usages of 0 and NULL literal to nullptr. Even
though it breaks git history, we need to do it in order to have consistent
code as well to ease code reviews (it's very tempting for some people to
add unrelated changes to their patches, e.g. converting NULL to nullptr).
Test Plan: Compiles.
Reviewers: #kwin, davidedmundson, romangg
Reviewed By: #kwin, davidedmundson, romangg
Subscribers: romangg, kwin
Tags: #kwin
Differential Revision: https://phabricator.kde.org/D23618
2019-09-19 14:46:54 +00:00
|
|
|
m_managerWindow = nullptr;
|
2008-09-22 13:03:00 +00:00
|
|
|
}
|
2007-04-29 17:35:43 +00:00
|
|
|
}
|
2020-05-24 01:37:25 +00:00
|
|
|
|
2011-01-30 14:34:42 +00:00
|
|
|
effects->addRepaintFull(); // Trigger the first repaint
|
|
|
|
}
|
2007-04-29 17:35:43 +00:00
|
|
|
|
2008-09-22 13:03:00 +00:00
|
|
|
//-----------------------------------------------------------------------------
|
|
|
|
// Filter box
|
|
|
|
|
2009-02-21 04:53:13 +00:00
|
|
|
void PresentWindowsEffect::updateFilterFrame()
|
2011-01-30 14:34:42 +00:00
|
|
|
{
|
|
|
|
QRect area = effects->clientArea(ScreenArea, effects->activeScreen(), effects->currentDesktop());
|
2012-05-03 08:34:09 +00:00
|
|
|
if (!m_filterFrame) {
|
2012-05-01 17:50:22 +00:00
|
|
|
m_filterFrame = effects->effectFrame(EffectFrameStyled, false);
|
|
|
|
QFont font;
|
|
|
|
font.setPointSize(font.pointSize() * 2);
|
|
|
|
font.setBold(true);
|
|
|
|
m_filterFrame->setFont(font);
|
|
|
|
}
|
2011-01-30 14:34:42 +00:00
|
|
|
m_filterFrame->setPosition(QPoint(area.x() + area.width() / 2, area.y() + area.height() / 2));
|
|
|
|
m_filterFrame->setText(i18n("Filter:\n%1", m_windowFilter));
|
|
|
|
}
|
2007-11-21 11:57:09 +00:00
|
|
|
|
2008-09-22 13:03:00 +00:00
|
|
|
//-----------------------------------------------------------------------------
|
|
|
|
// Helper functions
|
|
|
|
|
2011-01-30 14:34:42 +00:00
|
|
|
bool PresentWindowsEffect::isSelectableWindow(EffectWindow *w)
|
|
|
|
{
|
2011-04-24 12:20:47 +00:00
|
|
|
if (!w->isOnCurrentActivity())
|
|
|
|
return false;
|
2011-01-30 14:34:42 +00:00
|
|
|
if (w->isSpecialWindow() || w->isUtility())
|
2008-09-22 13:03:00 +00:00
|
|
|
return false;
|
2011-01-30 14:34:42 +00:00
|
|
|
if (w->isDeleted())
|
2008-09-22 13:03:00 +00:00
|
|
|
return false;
|
2011-01-30 14:34:42 +00:00
|
|
|
if (!w->acceptsFocus())
|
2009-02-08 08:45:21 +00:00
|
|
|
return false;
|
2011-01-30 14:34:42 +00:00
|
|
|
if (w->isSkipSwitcher())
|
2010-05-03 20:04:44 +00:00
|
|
|
return false;
|
2011-01-30 14:34:42 +00:00
|
|
|
if (m_ignoreMinimized && w->isMinimized())
|
2010-12-17 15:10:18 +00:00
|
|
|
return false;
|
2020-05-24 01:37:25 +00:00
|
|
|
|
2011-01-30 14:34:42 +00:00
|
|
|
switch(m_mode) {
|
|
|
|
default:
|
|
|
|
case ModeAllDesktops:
|
|
|
|
return true;
|
|
|
|
case ModeCurrentDesktop:
|
|
|
|
return w->isOnCurrentDesktop();
|
|
|
|
case ModeSelectedDesktop:
|
|
|
|
return w->isOnDesktop(m_desktop);
|
|
|
|
case ModeWindowGroup:
|
|
|
|
return m_selectedWindows.contains(w);
|
|
|
|
case ModeWindowClass:
|
|
|
|
return m_class == w->windowClass();
|
2007-11-21 11:57:09 +00:00
|
|
|
}
|
2011-01-30 14:34:42 +00:00
|
|
|
}
|
2007-11-21 11:57:09 +00:00
|
|
|
|
2011-01-30 14:34:42 +00:00
|
|
|
bool PresentWindowsEffect::isVisibleWindow(EffectWindow *w)
|
|
|
|
{
|
2019-10-21 13:36:39 +00:00
|
|
|
if (w->isDesktop())
|
2008-09-22 13:03:00 +00:00
|
|
|
return true;
|
2011-01-30 14:34:42 +00:00
|
|
|
return isSelectableWindow(w);
|
|
|
|
}
|
2008-09-22 13:03:00 +00:00
|
|
|
|
2011-01-30 14:34:42 +00:00
|
|
|
void PresentWindowsEffect::setHighlightedWindow(EffectWindow *w)
|
|
|
|
{
|
Use nullptr everywhere
Summary:
Because KWin is a very old project, we use three kinds of null pointer
literals: 0, NULL, and nullptr. Since C++11, it's recommended to use
nullptr keyword.
This change converts all usages of 0 and NULL literal to nullptr. Even
though it breaks git history, we need to do it in order to have consistent
code as well to ease code reviews (it's very tempting for some people to
add unrelated changes to their patches, e.g. converting NULL to nullptr).
Test Plan: Compiles.
Reviewers: #kwin, davidedmundson, romangg
Reviewed By: #kwin, davidedmundson, romangg
Subscribers: romangg, kwin
Tags: #kwin
Differential Revision: https://phabricator.kde.org/D23618
2019-09-19 14:46:54 +00:00
|
|
|
if (w == m_highlightedWindow || (w != nullptr && !m_motionManager.isManaging(w)))
|
2008-09-22 13:03:00 +00:00
|
|
|
return;
|
|
|
|
|
2012-02-08 18:17:58 +00:00
|
|
|
if (m_closeView)
|
|
|
|
m_closeView->hide();
|
2011-04-25 15:04:04 +00:00
|
|
|
if (m_highlightedWindow) {
|
|
|
|
effects->setElevatedWindow(m_highlightedWindow, false);
|
2008-09-22 13:03:00 +00:00
|
|
|
m_highlightedWindow->addRepaintFull(); // Trigger the first repaint
|
2011-04-25 15:04:04 +00:00
|
|
|
}
|
2008-09-22 13:03:00 +00:00
|
|
|
m_highlightedWindow = w;
|
2011-04-25 15:04:04 +00:00
|
|
|
if (m_highlightedWindow) {
|
|
|
|
effects->setElevatedWindow(m_highlightedWindow, true);
|
2008-09-22 13:03:00 +00:00
|
|
|
m_highlightedWindow->addRepaintFull(); // Trigger the first repaint
|
2011-04-25 15:04:04 +00:00
|
|
|
}
|
2008-08-25 09:17:15 +00:00
|
|
|
|
2010-09-30 20:25:22 +00:00
|
|
|
updateCloseWindow();
|
2011-01-30 14:34:42 +00:00
|
|
|
}
|
2010-09-30 20:25:22 +00:00
|
|
|
|
|
|
|
void PresentWindowsEffect::updateCloseWindow()
|
2011-01-30 14:34:42 +00:00
|
|
|
{
|
2012-04-01 15:01:58 +00:00
|
|
|
if (!m_closeView || m_doNotCloseWindows)
|
2010-11-11 17:04:42 +00:00
|
|
|
return;
|
2015-03-20 21:34:42 +00:00
|
|
|
|
|
|
|
if (!m_activated || !m_highlightedWindow || m_highlightedWindow->isDesktop()) {
|
2011-04-25 15:04:04 +00:00
|
|
|
m_closeView->hide();
|
|
|
|
return;
|
|
|
|
}
|
2011-01-30 14:34:42 +00:00
|
|
|
if (m_closeView->isVisible())
|
2010-09-30 20:25:22 +00:00
|
|
|
return;
|
2011-04-25 15:04:04 +00:00
|
|
|
|
|
|
|
const QRectF rect(m_motionManager.targetGeometry(m_highlightedWindow));
|
2019-10-21 13:36:39 +00:00
|
|
|
if (2*m_closeView->geometry().width() > rect.width() && 2*m_closeView->geometry().height() > rect.height()) {
|
2011-04-25 15:04:04 +00:00
|
|
|
// not for tiny windows (eg. with many windows) - they might become unselectable
|
2010-09-30 20:25:22 +00:00
|
|
|
m_closeView->hide();
|
|
|
|
return;
|
2011-01-30 14:34:42 +00:00
|
|
|
}
|
2020-05-24 01:37:25 +00:00
|
|
|
|
2013-08-05 12:08:23 +00:00
|
|
|
QRect cvr(QPoint(0,0), m_closeView->size());
|
2011-04-25 15:04:04 +00:00
|
|
|
switch (m_closeButtonCorner)
|
|
|
|
{
|
|
|
|
case Qt::TopLeftCorner:
|
|
|
|
default:
|
|
|
|
cvr.moveTopLeft(rect.topLeft().toPoint()); break;
|
|
|
|
case Qt::TopRightCorner:
|
|
|
|
cvr.moveTopRight(rect.topRight().toPoint()); break;
|
|
|
|
case Qt::BottomLeftCorner:
|
|
|
|
cvr.moveBottomLeft(rect.bottomLeft().toPoint()); break;
|
|
|
|
case Qt::BottomRightCorner:
|
|
|
|
cvr.moveBottomRight(rect.bottomRight().toPoint()); break;
|
|
|
|
}
|
2020-05-24 01:37:25 +00:00
|
|
|
|
2011-04-25 15:04:04 +00:00
|
|
|
m_closeView->setGeometry(cvr);
|
2020-05-24 01:37:25 +00:00
|
|
|
|
2011-04-25 15:04:04 +00:00
|
|
|
if (rect.contains(effects->cursorPos())) {
|
|
|
|
m_closeView->show();
|
|
|
|
m_closeView->disarm();
|
|
|
|
}
|
2010-09-30 20:25:22 +00:00
|
|
|
else
|
|
|
|
m_closeView->hide();
|
2011-01-30 14:34:42 +00:00
|
|
|
}
|
2010-09-30 20:25:22 +00:00
|
|
|
|
|
|
|
void PresentWindowsEffect::closeWindow()
|
2011-01-30 14:34:42 +00:00
|
|
|
{
|
|
|
|
if (m_highlightedWindow)
|
2010-09-30 20:25:22 +00:00
|
|
|
m_highlightedWindow->closeWindow();
|
2011-01-30 14:34:42 +00:00
|
|
|
}
|
2008-09-22 13:03:00 +00:00
|
|
|
|
2011-01-30 14:34:42 +00:00
|
|
|
EffectWindow* PresentWindowsEffect::relativeWindow(EffectWindow *w, int xdiff, int ydiff, bool wrap) const
|
|
|
|
{
|
2012-03-13 07:46:09 +00:00
|
|
|
if (!w)
|
|
|
|
return m_motionManager.managedWindows().first();
|
2020-05-24 01:37:25 +00:00
|
|
|
|
2011-01-30 14:34:42 +00:00
|
|
|
// TODO: Is it possible to select hidden windows?
|
2008-08-25 09:17:15 +00:00
|
|
|
EffectWindow* next;
|
2011-01-30 14:34:42 +00:00
|
|
|
QRect area = effects->clientArea(FullArea, 0, effects->currentDesktop());
|
2008-08-25 09:17:15 +00:00
|
|
|
QRect detectRect;
|
|
|
|
|
|
|
|
// Detect across the width of the desktop
|
2011-01-30 14:34:42 +00:00
|
|
|
if (xdiff != 0) {
|
|
|
|
if (xdiff > 0) {
|
|
|
|
// Detect right
|
|
|
|
for (int i = 0; i < xdiff; i++) {
|
|
|
|
QRectF wArea = m_motionManager.transformedGeometry(w);
|
|
|
|
detectRect = QRect(0, wArea.y(), area.width(), wArea.height());
|
Use nullptr everywhere
Summary:
Because KWin is a very old project, we use three kinds of null pointer
literals: 0, NULL, and nullptr. Since C++11, it's recommended to use
nullptr keyword.
This change converts all usages of 0 and NULL literal to nullptr. Even
though it breaks git history, we need to do it in order to have consistent
code as well to ease code reviews (it's very tempting for some people to
add unrelated changes to their patches, e.g. converting NULL to nullptr).
Test Plan: Compiles.
Reviewers: #kwin, davidedmundson, romangg
Reviewed By: #kwin, davidedmundson, romangg
Subscribers: romangg, kwin
Tags: #kwin
Differential Revision: https://phabricator.kde.org/D23618
2019-09-19 14:46:54 +00:00
|
|
|
next = nullptr;
|
2020-05-24 01:37:25 +00:00
|
|
|
|
2011-01-30 14:34:42 +00:00
|
|
|
foreach (EffectWindow * e, m_motionManager.managedWindows()) {
|
2011-03-07 23:19:52 +00:00
|
|
|
DataHash::const_iterator winData = m_windowData.find(e);
|
|
|
|
if (winData == m_windowData.end() || !winData->visible)
|
2008-12-16 04:24:20 +00:00
|
|
|
continue;
|
2020-05-24 01:37:25 +00:00
|
|
|
|
2011-01-30 14:34:42 +00:00
|
|
|
QRectF eArea = m_motionManager.transformedGeometry(e);
|
|
|
|
if (eArea.intersects(detectRect) &&
|
|
|
|
eArea.x() > wArea.x()) {
|
Use nullptr everywhere
Summary:
Because KWin is a very old project, we use three kinds of null pointer
literals: 0, NULL, and nullptr. Since C++11, it's recommended to use
nullptr keyword.
This change converts all usages of 0 and NULL literal to nullptr. Even
though it breaks git history, we need to do it in order to have consistent
code as well to ease code reviews (it's very tempting for some people to
add unrelated changes to their patches, e.g. converting NULL to nullptr).
Test Plan: Compiles.
Reviewers: #kwin, davidedmundson, romangg
Reviewed By: #kwin, davidedmundson, romangg
Subscribers: romangg, kwin
Tags: #kwin
Differential Revision: https://phabricator.kde.org/D23618
2019-09-19 14:46:54 +00:00
|
|
|
if (next == nullptr)
|
2008-08-25 09:17:15 +00:00
|
|
|
next = e;
|
2011-01-30 14:34:42 +00:00
|
|
|
else {
|
|
|
|
QRectF nArea = m_motionManager.transformedGeometry(next);
|
|
|
|
if (eArea.x() < nArea.x())
|
2008-09-22 13:03:00 +00:00
|
|
|
next = e;
|
2008-08-25 09:17:15 +00:00
|
|
|
}
|
|
|
|
}
|
2011-01-30 14:34:42 +00:00
|
|
|
}
|
Use nullptr everywhere
Summary:
Because KWin is a very old project, we use three kinds of null pointer
literals: 0, NULL, and nullptr. Since C++11, it's recommended to use
nullptr keyword.
This change converts all usages of 0 and NULL literal to nullptr. Even
though it breaks git history, we need to do it in order to have consistent
code as well to ease code reviews (it's very tempting for some people to
add unrelated changes to their patches, e.g. converting NULL to nullptr).
Test Plan: Compiles.
Reviewers: #kwin, davidedmundson, romangg
Reviewed By: #kwin, davidedmundson, romangg
Subscribers: romangg, kwin
Tags: #kwin
Differential Revision: https://phabricator.kde.org/D23618
2019-09-19 14:46:54 +00:00
|
|
|
if (next == nullptr) {
|
2011-01-30 14:34:42 +00:00
|
|
|
if (wrap) // We are at the right-most window, now get the left-most one to wrap
|
|
|
|
return relativeWindow(w, -1000, 0, false);
|
2008-08-25 09:17:15 +00:00
|
|
|
break; // No more windows to the right
|
|
|
|
}
|
2011-01-30 14:34:42 +00:00
|
|
|
w = next;
|
2008-08-25 09:17:15 +00:00
|
|
|
}
|
2011-01-30 14:34:42 +00:00
|
|
|
return w;
|
|
|
|
} else {
|
|
|
|
// Detect left
|
|
|
|
for (int i = 0; i < -xdiff; i++) {
|
|
|
|
QRectF wArea = m_motionManager.transformedGeometry(w);
|
|
|
|
detectRect = QRect(0, wArea.y(), area.width(), wArea.height());
|
Use nullptr everywhere
Summary:
Because KWin is a very old project, we use three kinds of null pointer
literals: 0, NULL, and nullptr. Since C++11, it's recommended to use
nullptr keyword.
This change converts all usages of 0 and NULL literal to nullptr. Even
though it breaks git history, we need to do it in order to have consistent
code as well to ease code reviews (it's very tempting for some people to
add unrelated changes to their patches, e.g. converting NULL to nullptr).
Test Plan: Compiles.
Reviewers: #kwin, davidedmundson, romangg
Reviewed By: #kwin, davidedmundson, romangg
Subscribers: romangg, kwin
Tags: #kwin
Differential Revision: https://phabricator.kde.org/D23618
2019-09-19 14:46:54 +00:00
|
|
|
next = nullptr;
|
2020-05-24 01:37:25 +00:00
|
|
|
|
2011-01-30 14:34:42 +00:00
|
|
|
foreach (EffectWindow * e, m_motionManager.managedWindows()) {
|
2011-03-07 23:19:52 +00:00
|
|
|
DataHash::const_iterator winData = m_windowData.find(e);
|
|
|
|
if (winData == m_windowData.end() || !winData->visible)
|
2008-12-16 04:24:20 +00:00
|
|
|
continue;
|
2020-05-24 01:37:25 +00:00
|
|
|
|
2011-01-30 14:34:42 +00:00
|
|
|
QRectF eArea = m_motionManager.transformedGeometry(e);
|
|
|
|
if (eArea.intersects(detectRect) &&
|
|
|
|
eArea.x() + eArea.width() < wArea.x() + wArea.width()) {
|
Use nullptr everywhere
Summary:
Because KWin is a very old project, we use three kinds of null pointer
literals: 0, NULL, and nullptr. Since C++11, it's recommended to use
nullptr keyword.
This change converts all usages of 0 and NULL literal to nullptr. Even
though it breaks git history, we need to do it in order to have consistent
code as well to ease code reviews (it's very tempting for some people to
add unrelated changes to their patches, e.g. converting NULL to nullptr).
Test Plan: Compiles.
Reviewers: #kwin, davidedmundson, romangg
Reviewed By: #kwin, davidedmundson, romangg
Subscribers: romangg, kwin
Tags: #kwin
Differential Revision: https://phabricator.kde.org/D23618
2019-09-19 14:46:54 +00:00
|
|
|
if (next == nullptr)
|
2008-08-25 09:17:15 +00:00
|
|
|
next = e;
|
2011-01-30 14:34:42 +00:00
|
|
|
else {
|
|
|
|
QRectF nArea = m_motionManager.transformedGeometry(next);
|
|
|
|
if (eArea.x() + eArea.width() > nArea.x() + nArea.width())
|
2008-09-22 13:03:00 +00:00
|
|
|
next = e;
|
2008-08-25 09:17:15 +00:00
|
|
|
}
|
|
|
|
}
|
2011-01-30 14:34:42 +00:00
|
|
|
}
|
Use nullptr everywhere
Summary:
Because KWin is a very old project, we use three kinds of null pointer
literals: 0, NULL, and nullptr. Since C++11, it's recommended to use
nullptr keyword.
This change converts all usages of 0 and NULL literal to nullptr. Even
though it breaks git history, we need to do it in order to have consistent
code as well to ease code reviews (it's very tempting for some people to
add unrelated changes to their patches, e.g. converting NULL to nullptr).
Test Plan: Compiles.
Reviewers: #kwin, davidedmundson, romangg
Reviewed By: #kwin, davidedmundson, romangg
Subscribers: romangg, kwin
Tags: #kwin
Differential Revision: https://phabricator.kde.org/D23618
2019-09-19 14:46:54 +00:00
|
|
|
if (next == nullptr) {
|
2011-01-30 14:34:42 +00:00
|
|
|
if (wrap) // We are at the left-most window, now get the right-most one to wrap
|
|
|
|
return relativeWindow(w, 1000, 0, false);
|
2008-08-25 09:17:15 +00:00
|
|
|
break; // No more windows to the left
|
|
|
|
}
|
2011-01-30 14:34:42 +00:00
|
|
|
w = next;
|
2008-08-25 09:17:15 +00:00
|
|
|
}
|
2011-01-30 14:34:42 +00:00
|
|
|
return w;
|
2008-08-25 09:17:15 +00:00
|
|
|
}
|
2011-01-30 14:34:42 +00:00
|
|
|
}
|
2008-08-25 09:17:15 +00:00
|
|
|
|
|
|
|
// Detect across the height of the desktop
|
2011-01-30 14:34:42 +00:00
|
|
|
if (ydiff != 0) {
|
|
|
|
if (ydiff > 0) {
|
|
|
|
// Detect down
|
|
|
|
for (int i = 0; i < ydiff; i++) {
|
|
|
|
QRectF wArea = m_motionManager.transformedGeometry(w);
|
|
|
|
detectRect = QRect(wArea.x(), 0, wArea.width(), area.height());
|
Use nullptr everywhere
Summary:
Because KWin is a very old project, we use three kinds of null pointer
literals: 0, NULL, and nullptr. Since C++11, it's recommended to use
nullptr keyword.
This change converts all usages of 0 and NULL literal to nullptr. Even
though it breaks git history, we need to do it in order to have consistent
code as well to ease code reviews (it's very tempting for some people to
add unrelated changes to their patches, e.g. converting NULL to nullptr).
Test Plan: Compiles.
Reviewers: #kwin, davidedmundson, romangg
Reviewed By: #kwin, davidedmundson, romangg
Subscribers: romangg, kwin
Tags: #kwin
Differential Revision: https://phabricator.kde.org/D23618
2019-09-19 14:46:54 +00:00
|
|
|
next = nullptr;
|
2020-05-24 01:37:25 +00:00
|
|
|
|
2011-01-30 14:34:42 +00:00
|
|
|
foreach (EffectWindow * e, m_motionManager.managedWindows()) {
|
2011-03-07 23:19:52 +00:00
|
|
|
DataHash::const_iterator winData = m_windowData.find(e);
|
|
|
|
if (winData == m_windowData.end() || !winData->visible)
|
2008-12-16 04:24:20 +00:00
|
|
|
continue;
|
2020-05-24 01:37:25 +00:00
|
|
|
|
2011-01-30 14:34:42 +00:00
|
|
|
QRectF eArea = m_motionManager.transformedGeometry(e);
|
|
|
|
if (eArea.intersects(detectRect) &&
|
|
|
|
eArea.y() > wArea.y()) {
|
Use nullptr everywhere
Summary:
Because KWin is a very old project, we use three kinds of null pointer
literals: 0, NULL, and nullptr. Since C++11, it's recommended to use
nullptr keyword.
This change converts all usages of 0 and NULL literal to nullptr. Even
though it breaks git history, we need to do it in order to have consistent
code as well to ease code reviews (it's very tempting for some people to
add unrelated changes to their patches, e.g. converting NULL to nullptr).
Test Plan: Compiles.
Reviewers: #kwin, davidedmundson, romangg
Reviewed By: #kwin, davidedmundson, romangg
Subscribers: romangg, kwin
Tags: #kwin
Differential Revision: https://phabricator.kde.org/D23618
2019-09-19 14:46:54 +00:00
|
|
|
if (next == nullptr)
|
2008-08-25 09:17:15 +00:00
|
|
|
next = e;
|
2011-01-30 14:34:42 +00:00
|
|
|
else {
|
|
|
|
QRectF nArea = m_motionManager.transformedGeometry(next);
|
|
|
|
if (eArea.y() < nArea.y())
|
2008-09-22 13:03:00 +00:00
|
|
|
next = e;
|
2008-08-25 09:17:15 +00:00
|
|
|
}
|
|
|
|
}
|
2011-01-30 14:34:42 +00:00
|
|
|
}
|
Use nullptr everywhere
Summary:
Because KWin is a very old project, we use three kinds of null pointer
literals: 0, NULL, and nullptr. Since C++11, it's recommended to use
nullptr keyword.
This change converts all usages of 0 and NULL literal to nullptr. Even
though it breaks git history, we need to do it in order to have consistent
code as well to ease code reviews (it's very tempting for some people to
add unrelated changes to their patches, e.g. converting NULL to nullptr).
Test Plan: Compiles.
Reviewers: #kwin, davidedmundson, romangg
Reviewed By: #kwin, davidedmundson, romangg
Subscribers: romangg, kwin
Tags: #kwin
Differential Revision: https://phabricator.kde.org/D23618
2019-09-19 14:46:54 +00:00
|
|
|
if (next == nullptr) {
|
2011-01-30 14:34:42 +00:00
|
|
|
if (wrap) // We are at the bottom-most window, now get the top-most one to wrap
|
|
|
|
return relativeWindow(w, 0, -1000, false);
|
2008-08-25 09:17:15 +00:00
|
|
|
break; // No more windows to the bottom
|
|
|
|
}
|
2011-01-30 14:34:42 +00:00
|
|
|
w = next;
|
2008-08-25 09:17:15 +00:00
|
|
|
}
|
2011-01-30 14:34:42 +00:00
|
|
|
return w;
|
|
|
|
} else {
|
|
|
|
// Detect up
|
|
|
|
for (int i = 0; i < -ydiff; i++) {
|
|
|
|
QRectF wArea = m_motionManager.transformedGeometry(w);
|
|
|
|
detectRect = QRect(wArea.x(), 0, wArea.width(), area.height());
|
Use nullptr everywhere
Summary:
Because KWin is a very old project, we use three kinds of null pointer
literals: 0, NULL, and nullptr. Since C++11, it's recommended to use
nullptr keyword.
This change converts all usages of 0 and NULL literal to nullptr. Even
though it breaks git history, we need to do it in order to have consistent
code as well to ease code reviews (it's very tempting for some people to
add unrelated changes to their patches, e.g. converting NULL to nullptr).
Test Plan: Compiles.
Reviewers: #kwin, davidedmundson, romangg
Reviewed By: #kwin, davidedmundson, romangg
Subscribers: romangg, kwin
Tags: #kwin
Differential Revision: https://phabricator.kde.org/D23618
2019-09-19 14:46:54 +00:00
|
|
|
next = nullptr;
|
2020-05-24 01:37:25 +00:00
|
|
|
|
2011-01-30 14:34:42 +00:00
|
|
|
foreach (EffectWindow * e, m_motionManager.managedWindows()) {
|
2011-03-07 23:19:52 +00:00
|
|
|
DataHash::const_iterator winData = m_windowData.find(e);
|
|
|
|
if (winData == m_windowData.end() || !winData->visible)
|
2008-12-16 04:24:20 +00:00
|
|
|
continue;
|
2020-05-24 01:37:25 +00:00
|
|
|
|
2011-01-30 14:34:42 +00:00
|
|
|
QRectF eArea = m_motionManager.transformedGeometry(e);
|
|
|
|
if (eArea.intersects(detectRect) &&
|
|
|
|
eArea.y() + eArea.height() < wArea.y() + wArea.height()) {
|
Use nullptr everywhere
Summary:
Because KWin is a very old project, we use three kinds of null pointer
literals: 0, NULL, and nullptr. Since C++11, it's recommended to use
nullptr keyword.
This change converts all usages of 0 and NULL literal to nullptr. Even
though it breaks git history, we need to do it in order to have consistent
code as well to ease code reviews (it's very tempting for some people to
add unrelated changes to their patches, e.g. converting NULL to nullptr).
Test Plan: Compiles.
Reviewers: #kwin, davidedmundson, romangg
Reviewed By: #kwin, davidedmundson, romangg
Subscribers: romangg, kwin
Tags: #kwin
Differential Revision: https://phabricator.kde.org/D23618
2019-09-19 14:46:54 +00:00
|
|
|
if (next == nullptr)
|
2008-08-25 09:17:15 +00:00
|
|
|
next = e;
|
2011-01-30 14:34:42 +00:00
|
|
|
else {
|
|
|
|
QRectF nArea = m_motionManager.transformedGeometry(next);
|
|
|
|
if (eArea.y() + eArea.height() > nArea.y() + nArea.height())
|
2008-09-22 13:03:00 +00:00
|
|
|
next = e;
|
2008-08-25 09:17:15 +00:00
|
|
|
}
|
|
|
|
}
|
2011-01-30 14:34:42 +00:00
|
|
|
}
|
Use nullptr everywhere
Summary:
Because KWin is a very old project, we use three kinds of null pointer
literals: 0, NULL, and nullptr. Since C++11, it's recommended to use
nullptr keyword.
This change converts all usages of 0 and NULL literal to nullptr. Even
though it breaks git history, we need to do it in order to have consistent
code as well to ease code reviews (it's very tempting for some people to
add unrelated changes to their patches, e.g. converting NULL to nullptr).
Test Plan: Compiles.
Reviewers: #kwin, davidedmundson, romangg
Reviewed By: #kwin, davidedmundson, romangg
Subscribers: romangg, kwin
Tags: #kwin
Differential Revision: https://phabricator.kde.org/D23618
2019-09-19 14:46:54 +00:00
|
|
|
if (next == nullptr) {
|
2011-01-30 14:34:42 +00:00
|
|
|
if (wrap) // We are at the top-most window, now get the bottom-most one to wrap
|
|
|
|
return relativeWindow(w, 0, 1000, false);
|
2008-08-25 09:17:15 +00:00
|
|
|
break; // No more windows to the top
|
|
|
|
}
|
2011-01-30 14:34:42 +00:00
|
|
|
w = next;
|
2008-08-25 09:17:15 +00:00
|
|
|
}
|
2011-01-30 14:34:42 +00:00
|
|
|
return w;
|
2008-08-25 09:17:15 +00:00
|
|
|
}
|
2011-01-30 14:34:42 +00:00
|
|
|
}
|
2008-08-25 09:17:15 +00:00
|
|
|
|
2008-09-17 11:44:51 +00:00
|
|
|
abort(); // Should never get here
|
2011-01-30 14:34:42 +00:00
|
|
|
}
|
2008-08-25 09:17:15 +00:00
|
|
|
|
2007-11-21 11:57:09 +00:00
|
|
|
EffectWindow* PresentWindowsEffect::findFirstWindow() const
|
2011-01-30 14:34:42 +00:00
|
|
|
{
|
Use nullptr everywhere
Summary:
Because KWin is a very old project, we use three kinds of null pointer
literals: 0, NULL, and nullptr. Since C++11, it's recommended to use
nullptr keyword.
This change converts all usages of 0 and NULL literal to nullptr. Even
though it breaks git history, we need to do it in order to have consistent
code as well to ease code reviews (it's very tempting for some people to
add unrelated changes to their patches, e.g. converting NULL to nullptr).
Test Plan: Compiles.
Reviewers: #kwin, davidedmundson, romangg
Reviewed By: #kwin, davidedmundson, romangg
Subscribers: romangg, kwin
Tags: #kwin
Differential Revision: https://phabricator.kde.org/D23618
2019-09-19 14:46:54 +00:00
|
|
|
EffectWindow *topLeft = nullptr;
|
2008-09-22 13:03:00 +00:00
|
|
|
QRectF topLeftGeometry;
|
2020-05-24 01:37:25 +00:00
|
|
|
|
2011-01-30 14:34:42 +00:00
|
|
|
foreach (EffectWindow * w, m_motionManager.managedWindows()) {
|
2011-03-07 23:19:52 +00:00
|
|
|
DataHash::const_iterator winData = m_windowData.find(w);
|
|
|
|
if (winData == m_windowData.end())
|
|
|
|
continue;
|
2011-01-30 14:34:42 +00:00
|
|
|
QRectF geometry = m_motionManager.transformedGeometry(w);
|
2011-03-07 23:19:52 +00:00
|
|
|
if (winData->visible == false)
|
2008-09-22 13:03:00 +00:00
|
|
|
continue; // Not visible
|
2011-03-07 23:19:52 +00:00
|
|
|
if (winData->deleted)
|
2009-07-14 09:06:37 +00:00
|
|
|
continue; // Window has been closed
|
Use nullptr everywhere
Summary:
Because KWin is a very old project, we use three kinds of null pointer
literals: 0, NULL, and nullptr. Since C++11, it's recommended to use
nullptr keyword.
This change converts all usages of 0 and NULL literal to nullptr. Even
though it breaks git history, we need to do it in order to have consistent
code as well to ease code reviews (it's very tempting for some people to
add unrelated changes to their patches, e.g. converting NULL to nullptr).
Test Plan: Compiles.
Reviewers: #kwin, davidedmundson, romangg
Reviewed By: #kwin, davidedmundson, romangg
Subscribers: romangg, kwin
Tags: #kwin
Differential Revision: https://phabricator.kde.org/D23618
2019-09-19 14:46:54 +00:00
|
|
|
if (topLeft == nullptr) {
|
2008-09-22 13:03:00 +00:00
|
|
|
topLeft = w;
|
|
|
|
topLeftGeometry = geometry;
|
2011-01-30 14:34:42 +00:00
|
|
|
} else if (geometry.x() < topLeftGeometry.x() || geometry.y() < topLeftGeometry.y()) {
|
2008-09-22 13:03:00 +00:00
|
|
|
topLeft = w;
|
|
|
|
topLeftGeometry = geometry;
|
2007-04-29 17:35:43 +00:00
|
|
|
}
|
|
|
|
}
|
2011-01-30 14:34:42 +00:00
|
|
|
return topLeft;
|
|
|
|
}
|
2007-04-29 17:35:43 +00:00
|
|
|
|
2013-08-14 19:13:12 +00:00
|
|
|
void PresentWindowsEffect::globalShortcutChanged(QAction *action, const QKeySequence& seq)
|
2011-01-30 14:34:42 +00:00
|
|
|
{
|
2013-08-14 19:13:12 +00:00
|
|
|
if (action->objectName() == QStringLiteral("Expose")) {
|
|
|
|
shortcut.clear();
|
|
|
|
shortcut.append(seq);
|
|
|
|
} else if (action->objectName() == QStringLiteral("ExposeAll")) {
|
|
|
|
shortcutAll.clear();
|
|
|
|
shortcutAll.append(seq);
|
|
|
|
} else if (action->objectName() == QStringLiteral("ExposeClass")) {
|
|
|
|
shortcutClass.clear();
|
|
|
|
shortcutClass.append(seq);
|
|
|
|
}
|
2011-01-30 14:34:42 +00:00
|
|
|
}
|
2009-06-30 19:11:02 +00:00
|
|
|
|
2011-08-27 09:21:31 +00:00
|
|
|
bool PresentWindowsEffect::isActive() const
|
|
|
|
{
|
2015-11-20 10:17:16 +00:00
|
|
|
return (m_activated || m_motionManager.managingWindows()) && !effects->isScreenLocked();
|
2011-08-27 09:21:31 +00:00
|
|
|
}
|
|
|
|
|
2015-08-28 05:50:20 +00:00
|
|
|
void PresentWindowsEffect::reCreateGrids()
|
2013-02-04 15:46:34 +00:00
|
|
|
{
|
|
|
|
m_gridSizes.clear();
|
|
|
|
for (int i = 0; i < effects->numScreens(); ++i) {
|
|
|
|
m_gridSizes.append(GridSize());
|
|
|
|
}
|
|
|
|
rearrangeWindows();
|
|
|
|
}
|
|
|
|
|
2013-10-25 10:57:34 +00:00
|
|
|
CloseWindowView::CloseWindowView(QObject *parent)
|
2019-10-21 13:36:39 +00:00
|
|
|
: EffectQuickScene(parent)
|
2011-01-30 14:34:42 +00:00
|
|
|
{
|
2019-10-21 13:36:39 +00:00
|
|
|
setSource(QUrl(QStandardPaths::locate(QStandardPaths::GenericDataLocation, QStringLiteral("kwin/effects/presentwindows/main.qml"))));
|
|
|
|
if (QQuickItem *item = rootItem()) {
|
|
|
|
connect(item, SIGNAL(clicked()), this, SLOT(clicked()));
|
|
|
|
setGeometry(QRect(QPoint(), QSize(item->implicitWidth(), item->implicitHeight())));
|
2013-01-16 13:50:43 +00:00
|
|
|
}
|
2019-10-21 15:45:00 +00:00
|
|
|
m_armTimer.restart();
|
2011-01-30 14:34:42 +00:00
|
|
|
}
|
2010-09-30 20:25:22 +00:00
|
|
|
|
2019-10-21 13:36:39 +00:00
|
|
|
void CloseWindowView::clicked()
|
2011-01-30 14:34:42 +00:00
|
|
|
{
|
2019-10-21 13:36:39 +00:00
|
|
|
// 50ms until the window is elevated (seen!) and 300ms more to be "realized" by the user.
|
2019-10-21 15:45:00 +00:00
|
|
|
if (m_armTimer.hasExpired(350)) {
|
2019-10-21 13:36:39 +00:00
|
|
|
emit requestClose();
|
2010-09-30 20:25:22 +00:00
|
|
|
}
|
2011-01-30 14:34:42 +00:00
|
|
|
}
|
2010-09-30 20:25:22 +00:00
|
|
|
|
2011-04-25 15:04:04 +00:00
|
|
|
void CloseWindowView::disarm()
|
2011-01-30 14:34:42 +00:00
|
|
|
{
|
2019-10-21 15:45:00 +00:00
|
|
|
m_armTimer.restart();
|
2011-01-30 14:34:42 +00:00
|
|
|
}
|
2010-10-25 01:33:44 +00:00
|
|
|
|
|
|
|
|
2007-04-29 17:35:43 +00:00
|
|
|
} // namespace
|