fix close button side for present windows effect
BUG: 262543 pint desktop as background when including desktop in switcher BUG: 262137 zoom windows as hover/selection indicaton (1/8 of the screen or 105%) BUG: 215348 CCBUG: 175521 no closer on "show desktop" desktop show closer immediately but have it disabled for a short time to allow the user realize it REVIEW: 101318
This commit is contained in:
parent
4b81841268
commit
a2d9ff72aa
9 changed files with 172 additions and 34 deletions
11
effects.cpp
11
effects.cpp
|
@ -1256,6 +1256,17 @@ EffectFrame* EffectsHandlerImpl::effectFrame(EffectFrameStyle style, bool static
|
|||
return new EffectFrameImpl(style, staticSize, position, alignment);
|
||||
}
|
||||
|
||||
|
||||
QVariant EffectsHandlerImpl::kwinOption(KWinOption kwopt)
|
||||
{
|
||||
switch (kwopt)
|
||||
{
|
||||
case CloseButtonCorner:
|
||||
return Workspace::self()->decorationCloseButtonCorner();
|
||||
}
|
||||
return QVariant(); // an invalid one
|
||||
}
|
||||
|
||||
void EffectsHandlerImpl::slotShowOutline(const QRect& geometry)
|
||||
{
|
||||
emit showOutline(geometry);
|
||||
|
|
|
@ -151,6 +151,8 @@ public:
|
|||
|
||||
virtual EffectFrame* effectFrame(EffectFrameStyle style, bool staticSize, const QPoint& position, Qt::Alignment alignment) const;
|
||||
|
||||
virtual QVariant kwinOption(KWinOption kwopt);
|
||||
|
||||
// internal (used by kwin core or compositing code)
|
||||
void startPaint();
|
||||
bool borderActivated(ElectricBorder border);
|
||||
|
|
|
@ -295,9 +295,12 @@ void PresentWindowsEffect::prePaintWindow(EffectWindow *w, WindowPrePaintData &d
|
|||
} else if (winData->opacity != 1.0)
|
||||
data.setTranslucent();
|
||||
|
||||
const bool isInMotion = m_motionManager.isManaging(w);
|
||||
// Calculate window's brightness
|
||||
if (w == m_highlightedWindow || w == m_closeWindow || !m_activated)
|
||||
winData->highlight = qMin(1.0, winData->highlight + time / m_fadeDuration);
|
||||
else if (!isInMotion && w->isDesktop())
|
||||
winData->highlight = 0.3;
|
||||
else
|
||||
winData->highlight = qMax(0.0, winData->highlight - time / m_fadeDuration);
|
||||
|
||||
|
@ -317,7 +320,7 @@ void PresentWindowsEffect::prePaintWindow(EffectWindow *w, WindowPrePaintData &d
|
|||
if (w->isDesktop() && !w->isOnCurrentDesktop())
|
||||
w->disablePainting(EffectWindow::PAINT_DISABLED_BY_DESKTOP);
|
||||
|
||||
if (m_motionManager.isManaging(w))
|
||||
if (isInMotion)
|
||||
data.setTransformed(); // We will be moving this window
|
||||
}
|
||||
effects->prePaintWindow(w, data, time);
|
||||
|
@ -333,15 +336,50 @@ void PresentWindowsEffect::paintWindow(EffectWindow *w, int mask, QRegion region
|
|||
return;
|
||||
}
|
||||
|
||||
mask |= PAINT_WINDOW_LANCZOS;
|
||||
// Apply opacity and brightness
|
||||
data.opacity *= winData->opacity;
|
||||
data.brightness *= interpolate(0.7, 1.0, winData->highlight);
|
||||
data.brightness *= interpolate(0.40, 1.0, winData->highlight);
|
||||
|
||||
if (m_motionManager.isManaging(w)) {
|
||||
if (w->isDesktop())
|
||||
effects->paintWindow(w, mask, region, data);
|
||||
m_motionManager.apply(w, data);
|
||||
QRect rect = m_motionManager.transformedGeometry(w).toRect();
|
||||
|
||||
if (!m_motionManager.areWindowsMoving()) {
|
||||
mask |= PAINT_WINDOW_LANCZOS;
|
||||
if (winData->highlight > 0.0) {
|
||||
// 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
|
||||
QRect area = effects->clientArea(FullScreenArea, w);
|
||||
QSizeF effSize(w->width()*data.xScale, w->height()*data.yScale);
|
||||
float tScale = sqrt((area.width()*area.height()) / (16.0*effSize.width()*effSize.height()));
|
||||
if (tScale < 1.05)
|
||||
tScale = 1.05;
|
||||
if (effSize.width()*tScale > area.width())
|
||||
tScale = area.width() / effSize.width();
|
||||
if (effSize.height()*tScale > area.height())
|
||||
tScale = area.height() / effSize.height();
|
||||
const float scale = interpolate(1.0, tScale, winData->highlight);
|
||||
if (scale > 1.0) {
|
||||
if (scale < tScale) // don't use lanczos during transition
|
||||
mask &= ~PAINT_WINDOW_LANCZOS;
|
||||
|
||||
const QPoint ac = area.center();
|
||||
const QPoint wc = rect.center();
|
||||
|
||||
data.xScale *= scale;
|
||||
data.yScale *= scale;
|
||||
const int tx = -w->width()*data.xScale*(scale-1.0)*(0.5+(wc.x() - ac.x())/area.width());
|
||||
const int ty = -w->height()*data.yScale*(scale-1.0)*(0.5+(wc.y() - ac.y())/area.height());
|
||||
rect.translate(tx,ty);
|
||||
rect.setWidth(rect.width()*scale);
|
||||
rect.setHeight(rect.height()*scale);
|
||||
data.xTranslate += tx;
|
||||
data.yTranslate += ty;
|
||||
}
|
||||
}
|
||||
|
||||
if (m_motionManager.areWindowsMoving()) {
|
||||
mask &= ~PAINT_WINDOW_LANCZOS;
|
||||
}
|
||||
if (m_dragInProgress && m_dragWindow == w) {
|
||||
QPoint diff = cursorPos() - m_dragStart;
|
||||
|
@ -350,7 +388,7 @@ void PresentWindowsEffect::paintWindow(EffectWindow *w, int mask, QRegion region
|
|||
}
|
||||
effects->paintWindow(w, mask, region, data);
|
||||
|
||||
QRect rect = m_motionManager.transformedGeometry(w).toRect();
|
||||
|
||||
if (m_showIcons) {
|
||||
QPoint point(rect.x() + rect.width() * 0.95,
|
||||
rect.y() + rect.height() * 0.95);
|
||||
|
@ -484,7 +522,7 @@ void PresentWindowsEffect::windowInputMouseEvent(Window w, QEvent *e)
|
|||
}
|
||||
if (m_closeView->isVisible()) {
|
||||
const QPoint widgetPos = m_closeView->mapFromGlobal(me->pos());
|
||||
const QPointF scenePos = m_closeView->mapToScene(widgetPos);
|
||||
// const QPointF scenePos = m_closeView->mapToScene(widgetPos);
|
||||
QMouseEvent event(me->type(), widgetPos, me->pos(), me->button(), me->buttons(), me->modifiers());
|
||||
m_closeView->windowInputMouseEvent(&event);
|
||||
return;
|
||||
|
@ -1546,6 +1584,7 @@ void PresentWindowsEffect::setActive(bool active, bool closingTab)
|
|||
}
|
||||
m_activated = active;
|
||||
if (m_activated) {
|
||||
m_closeButtonCorner = (Qt::Corner)effects->kwinOption(KWin::CloseButtonCorner).toInt();
|
||||
m_decalOpacity = 0.0;
|
||||
m_highlightedWindow = NULL;
|
||||
m_windowFilter.clear();
|
||||
|
@ -1648,6 +1687,8 @@ void PresentWindowsEffect::setActive(bool active, bool closingTab)
|
|||
}
|
||||
}
|
||||
} else {
|
||||
if (m_highlightedWindow)
|
||||
effects->setElevatedWindow(m_highlightedWindow, false);
|
||||
// Fade in/out all windows
|
||||
EffectWindow *activeWindow = effects->activeWindow();
|
||||
if (m_tabBoxEnabled)
|
||||
|
@ -1752,32 +1793,65 @@ void PresentWindowsEffect::setHighlightedWindow(EffectWindow *w)
|
|||
return;
|
||||
|
||||
m_closeView->hide();
|
||||
if (m_highlightedWindow)
|
||||
if (m_highlightedWindow) {
|
||||
effects->setElevatedWindow(m_highlightedWindow, false);
|
||||
m_highlightedWindow->addRepaintFull(); // Trigger the first repaint
|
||||
}
|
||||
m_highlightedWindow = w;
|
||||
if (m_highlightedWindow)
|
||||
if (m_highlightedWindow) {
|
||||
effects->setElevatedWindow(m_highlightedWindow, true);
|
||||
m_highlightedWindow->addRepaintFull(); // Trigger the first repaint
|
||||
}
|
||||
|
||||
if (m_tabBoxEnabled && m_highlightedWindow)
|
||||
effects->setTabBoxWindow(w);
|
||||
updateCloseWindow();
|
||||
}
|
||||
|
||||
void PresentWindowsEffect::elevateCloseWindow()
|
||||
{
|
||||
if (EffectWindow *cw = effects->findWindow(m_closeView->winId()))
|
||||
effects->setElevatedWindow(cw, true);
|
||||
}
|
||||
|
||||
void PresentWindowsEffect::updateCloseWindow()
|
||||
{
|
||||
if (m_doNotCloseWindows)
|
||||
return;
|
||||
if (m_closeView->isVisible())
|
||||
return;
|
||||
if (!m_highlightedWindow) {
|
||||
if (!m_highlightedWindow || m_highlightedWindow->isDesktop()) {
|
||||
m_closeView->hide();
|
||||
return;
|
||||
}
|
||||
const QRectF rect = m_motionManager.targetGeometry(m_highlightedWindow);
|
||||
m_closeView->setGeometry(rect.x() + rect.width() - m_closeView->sceneRect().width(), rect.y(),
|
||||
m_closeView->sceneRect().width(), m_closeView->sceneRect().height());
|
||||
if (rect.contains(effects->cursorPos()))
|
||||
m_closeView->delayedShow();
|
||||
if (m_closeView->isVisible())
|
||||
return;
|
||||
|
||||
const QRectF rect(m_motionManager.targetGeometry(m_highlightedWindow));
|
||||
if (2*m_closeView->sceneRect().width() > rect.width() && 2*m_closeView->sceneRect().height() > rect.height()) {
|
||||
// not for tiny windows (eg. with many windows) - they might become unselectable
|
||||
m_closeView->hide();
|
||||
return;
|
||||
}
|
||||
QRect cvr(QPoint(0,0), m_closeView->sceneRect().size().toSize());
|
||||
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;
|
||||
}
|
||||
m_closeView->setGeometry(cvr);
|
||||
if (rect.contains(effects->cursorPos())) {
|
||||
m_closeView->show();
|
||||
m_closeView->disarm();
|
||||
// to wait for the next event cycle (or more if the show takes more time)
|
||||
// TODO: make the closeWindow a graphicsviewitem? why should there be an extra scene to be used in an exiting scene??
|
||||
QTimer::singleShot(50, this, SLOT(elevateCloseWindow()));
|
||||
}
|
||||
else
|
||||
m_closeView->hide();
|
||||
}
|
||||
|
@ -1972,7 +2046,7 @@ void PresentWindowsEffect::globalShortcutChangedClass(const QKeySequence& seq)
|
|||
************************************************/
|
||||
CloseWindowView::CloseWindowView(QWidget* parent)
|
||||
: QGraphicsView(parent)
|
||||
, m_delayedShowTimer(new QTimer(this))
|
||||
, m_armTimer(new QTimer(this))
|
||||
{
|
||||
setWindowFlags(Qt::X11BypassWindowManagerHint);
|
||||
setAttribute(Qt::WA_TranslucentBackground);
|
||||
|
@ -2013,15 +2087,15 @@ CloseWindowView::CloseWindowView(QWidget* parent)
|
|||
scene->setSceneRect(QRectF(QPointF(0, 0), QSizeF(width, height)));
|
||||
setScene(scene);
|
||||
|
||||
// setup the timer
|
||||
m_delayedShowTimer->setSingleShot(true);
|
||||
m_delayedShowTimer->setInterval(500);
|
||||
connect(m_delayedShowTimer, SIGNAL(timeout()), SLOT(show()));
|
||||
// setup the timer - attempt to prevent accidental clicks
|
||||
m_armTimer->setSingleShot(true);
|
||||
m_armTimer->setInterval(350); // 50ms until the window is elevated (seen!) and 300ms more to be "realized" by the user.
|
||||
connect(m_armTimer, SIGNAL(timeout()), SLOT(arm()));
|
||||
}
|
||||
|
||||
void CloseWindowView::windowInputMouseEvent(QMouseEvent* e)
|
||||
{
|
||||
if (m_delayedShowTimer->isActive())
|
||||
if (!isEnabled())
|
||||
return;
|
||||
if (e->type() == QEvent::MouseMove) {
|
||||
mouseMoveEvent(e);
|
||||
|
@ -2041,17 +2115,15 @@ void CloseWindowView::drawBackground(QPainter* painter, const QRectF& rect)
|
|||
m_frame->paintFrame(painter);
|
||||
}
|
||||
|
||||
void CloseWindowView::hide()
|
||||
void CloseWindowView::arm()
|
||||
{
|
||||
m_delayedShowTimer->stop();
|
||||
QWidget::hide();
|
||||
setEnabled(true);
|
||||
}
|
||||
|
||||
void CloseWindowView::delayedShow()
|
||||
void CloseWindowView::disarm()
|
||||
{
|
||||
if (isVisible() || m_delayedShowTimer->isActive())
|
||||
return;
|
||||
m_delayedShowTimer->start();
|
||||
setEnabled(false);
|
||||
m_armTimer->start();
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -46,8 +46,9 @@ public:
|
|||
void windowInputMouseEvent(QMouseEvent* e);
|
||||
virtual void drawBackground(QPainter* painter, const QRectF& rect);
|
||||
|
||||
void delayedShow();
|
||||
void hide();
|
||||
void disarm();
|
||||
public slots:
|
||||
void arm();
|
||||
|
||||
Q_SIGNALS:
|
||||
void close();
|
||||
|
@ -55,7 +56,7 @@ Q_SIGNALS:
|
|||
private:
|
||||
Plasma::PushButton* m_closeButton;
|
||||
Plasma::FrameSvg* m_frame;
|
||||
QTimer* m_delayedShowTimer;
|
||||
QTimer* m_armTimer;
|
||||
};
|
||||
|
||||
/**
|
||||
|
@ -160,6 +161,7 @@ public slots:
|
|||
|
||||
private slots:
|
||||
void closeWindow();
|
||||
void elevateCloseWindow();
|
||||
|
||||
protected:
|
||||
// Window rearranging
|
||||
|
@ -265,6 +267,7 @@ private:
|
|||
|
||||
CloseWindowView* m_closeView;
|
||||
EffectWindow* m_closeWindow;
|
||||
Qt::Corner m_closeButtonCorner;
|
||||
|
||||
// drag to close
|
||||
QPoint m_dragStart;
|
||||
|
|
|
@ -28,12 +28,21 @@ DEALINGS IN THE SOFTWARE.
|
|||
|
||||
#include "kdecorationbridge.h"
|
||||
|
||||
KDecorationFactory::KDecorationFactory()
|
||||
class KDecorationFactoryPrivate {
|
||||
public:
|
||||
KDecorationFactoryPrivate() {
|
||||
closeButtonCorner = (Qt::Corner)0;
|
||||
}
|
||||
Qt::Corner closeButtonCorner;
|
||||
};
|
||||
|
||||
KDecorationFactory::KDecorationFactory() : d(new KDecorationFactoryPrivate)
|
||||
{
|
||||
}
|
||||
|
||||
KDecorationFactory::~KDecorationFactory()
|
||||
{
|
||||
delete d;
|
||||
assert(_decorations.count() == 0);
|
||||
}
|
||||
|
||||
|
@ -56,6 +65,18 @@ bool KDecorationFactory::exists(const KDecoration* deco) const
|
|||
return _decorations.contains(const_cast< KDecoration* >(deco));
|
||||
}
|
||||
|
||||
Qt::Corner KDecorationFactory::closeButtonCorner()
|
||||
{
|
||||
if (d->closeButtonCorner)
|
||||
return d->closeButtonCorner;
|
||||
return options()->titleButtonsLeft().contains('X') ? Qt::TopLeftCorner : Qt::TopRightCorner;
|
||||
}
|
||||
|
||||
void KDecorationFactory::setCloseButtonCorner(Qt::Corner cnr)
|
||||
{
|
||||
d->closeButtonCorner = cnr;
|
||||
}
|
||||
|
||||
void KDecorationFactory::addDecoration(KDecoration* deco)
|
||||
{
|
||||
_decorations.append(deco);
|
||||
|
|
|
@ -88,6 +88,21 @@ public:
|
|||
* after such actions.
|
||||
*/
|
||||
bool exists(const KDecoration* deco) const;
|
||||
|
||||
/**
|
||||
* Set & get the position of the close button - most decorations don't have to call this ever.
|
||||
*
|
||||
* By default, the legacy position indicated by the options (top left or top right) will be
|
||||
* returned.
|
||||
* Only if you need to provide a bottom corner or your decoration does not respect those
|
||||
* settings you will have to specify the exact corner (eg. used by the "present windows"
|
||||
* closer)
|
||||
*
|
||||
* @since 4.8
|
||||
*/
|
||||
Qt::Corner closeButtonCorner();
|
||||
void setCloseButtonCorner(Qt::Corner cnr);
|
||||
|
||||
/**
|
||||
* @internal
|
||||
*/
|
||||
|
|
|
@ -166,7 +166,7 @@ X-KDE-Library=kwin4_effect_cooleffect
|
|||
|
||||
#define KWIN_EFFECT_API_MAKE_VERSION( major, minor ) (( major ) << 8 | ( minor ))
|
||||
#define KWIN_EFFECT_API_VERSION_MAJOR 0
|
||||
#define KWIN_EFFECT_API_VERSION_MINOR 180
|
||||
#define KWIN_EFFECT_API_VERSION_MINOR 181
|
||||
#define KWIN_EFFECT_API_VERSION KWIN_EFFECT_API_MAKE_VERSION( \
|
||||
KWIN_EFFECT_API_VERSION_MAJOR, KWIN_EFFECT_API_VERSION_MINOR )
|
||||
|
||||
|
@ -580,6 +580,7 @@ public:
|
|||
virtual void paintEffectFrame(EffectFrame* frame, QRegion region, double opacity, double frameOpacity) = 0;
|
||||
virtual void drawWindow(EffectWindow* w, int mask, QRegion region, WindowPaintData& data) = 0;
|
||||
virtual void buildQuads(EffectWindow* w, WindowQuadList& quadList) = 0;
|
||||
virtual QVariant kwinOption(KWinOption kwopt) = 0;
|
||||
// Functions for handling input - e.g. when an Expose-like effect is shown, an input window
|
||||
// covering the whole screen is created and all mouse events will be intercepted by it.
|
||||
// The effect's windowInputMouseEvent() will get called with such events.
|
||||
|
|
|
@ -105,6 +105,10 @@ enum TabBoxMode {
|
|||
TabBoxWindowsAlternativeMode // Secondary window switching mode
|
||||
};
|
||||
|
||||
enum KWinOption {
|
||||
CloseButtonCorner
|
||||
};
|
||||
|
||||
inline
|
||||
KWIN_EXPORT Display* display()
|
||||
{
|
||||
|
|
|
@ -431,6 +431,7 @@ public:
|
|||
bool rulesUpdatesDisabled() const;
|
||||
|
||||
bool hasDecorationShadows() const;
|
||||
Qt::Corner decorationCloseButtonCorner();
|
||||
bool decorationHasAlpha() const;
|
||||
bool decorationSupportsClientGrouping() const; // Returns true if the decoration supports tabs.
|
||||
bool decorationSupportsFrameOverlap() const;
|
||||
|
@ -1169,6 +1170,14 @@ inline bool Workspace::hasDecorationShadows() const
|
|||
return mgr->factory()->supports(AbilityProvidesShadow);
|
||||
}
|
||||
|
||||
inline Qt::Corner Workspace::decorationCloseButtonCorner()
|
||||
{
|
||||
if (!hasDecorationPlugin()) {
|
||||
return Qt::TopRightCorner;
|
||||
}
|
||||
return mgr->factory()->closeButtonCorner();
|
||||
}
|
||||
|
||||
inline bool Workspace::decorationHasAlpha() const
|
||||
{
|
||||
if (!hasDecorationPlugin()) {
|
||||
|
|
Loading…
Reference in a new issue