diff --git a/abstract_client.h b/abstract_client.h --- a/abstract_client.h +++ b/abstract_client.h @@ -453,7 +453,7 @@ return _shortcut; } void setShortcut(const QString &cut); - virtual bool performMouseCommand(Options::MouseCommand, const QPoint &globalPos); + bool performMouseCommand(Options::MouseCommand, const QPoint &globalPos); void setOnAllDesktops(bool set); void setDesktop(int); void enterDesktop(VirtualDesktop *desktop); @@ -517,15 +517,11 @@ bool isShade() const { return shadeMode() == ShadeNormal; } - /** - * Default implementation returns @c ShadeNone - */ - virtual ShadeMode shadeMode() const; // Prefer isShade() + ShadeMode shadeMode() const; // Prefer isShade() void setShade(bool set); - /** - * Default implementation does nothing - */ - virtual void setShade(ShadeMode mode); + void setShade(ShadeMode mode); + void toggleShade(); + void cancelShadeHoverTimer(); /** * Whether the Client can be shaded. Default implementation returns @c false. */ @@ -949,6 +945,13 @@ * Default implementation does nothing. */ virtual void doSetKeepBelow(); + /** + * Called from setShade() once the shadeMode value got updated, but before the changed signal + * is emitted. + * + * Default implementation does nothing. + */ + virtual void doSetShade(ShadeMode previousShadeMode); /** * Called from setDeskop once the desktop value got updated, but before the changed signal * is emitted. @@ -1203,6 +1206,13 @@ bool tabTo(AbstractClient *other, bool behind, bool activate); + void startShadeHoverTimer(); + void startShadeUnhoverTimer(); + +private Q_SLOTS: + void shadeHover(); + void shadeUnhover(); + private: void handlePaletteChange(); QSharedPointer m_tabBoxClient; @@ -1221,6 +1231,8 @@ bool m_demandsAttention = false; bool m_minimized = false; QTimer *m_autoRaiseTimer = nullptr; + QTimer *m_shadeHoverTimer = nullptr; + ShadeMode m_shadeMode = ShadeNone; QVector m_desktops; QString m_colorScheme; diff --git a/abstract_client.cpp b/abstract_client.cpp --- a/abstract_client.cpp +++ b/abstract_client.cpp @@ -545,6 +545,11 @@ return x11Ids; } +ShadeMode AbstractClient::shadeMode() const +{ + return m_shadeMode; +} + bool AbstractClient::isShadeable() const { return false; @@ -557,12 +562,85 @@ void AbstractClient::setShade(ShadeMode mode) { - Q_UNUSED(mode) + if (!isShadeable()) + return; + if (mode == ShadeHover && isMove()) + return; // causes geometry breaks and is probably nasty + if (isSpecialWindow() || noBorder()) + mode = ShadeNone; + + mode = rules()->checkShade(mode); + if (m_shadeMode == mode) + return; + + const bool wasShade = isShade(); + const ShadeMode previousShadeMode = shadeMode(); + m_shadeMode = mode; + + if (wasShade == isShade()) { + // Decoration may want to update after e.g. hover-shade changes + emit shadeChanged(); + return; // No real change in shaded state + } + + Q_ASSERT(isDecorated()); + GeometryUpdatesBlocker blocker(this); + + doSetShade(previousShadeMode); + + discardWindowPixmap(); + updateWindowRules(Rules::Shade); + + emit shadeChanged(); } -ShadeMode AbstractClient::shadeMode() const +void AbstractClient::doSetShade(ShadeMode previousShadeMode) +{ + Q_UNUSED(previousShadeMode) +} + +void AbstractClient::shadeHover() +{ + setShade(ShadeHover); + cancelShadeHoverTimer(); +} + +void AbstractClient::shadeUnhover() { - return ShadeNone; + setShade(ShadeNormal); + cancelShadeHoverTimer(); +} + +void AbstractClient::startShadeHoverTimer() +{ + if (!isShade()) + return; + m_shadeHoverTimer = new QTimer(this); + connect(m_shadeHoverTimer, &QTimer::timeout, this, &AbstractClient::shadeHover); + m_shadeHoverTimer->setSingleShot(true); + m_shadeHoverTimer->start(options->shadeHoverInterval()); +} + +void AbstractClient::startShadeUnhoverTimer() +{ + if (m_shadeMode == ShadeHover && !isMoveResize() && !isMoveResizePointerButtonDown()) { + m_shadeHoverTimer = new QTimer(this); + connect(m_shadeHoverTimer, &QTimer::timeout, this, &AbstractClient::shadeUnhover); + m_shadeHoverTimer->setSingleShot(true); + m_shadeHoverTimer->start(options->shadeHoverInterval()); + } +} + +void AbstractClient::cancelShadeHoverTimer() +{ + delete m_shadeHoverTimer; + m_shadeHoverTimer = nullptr; +} + +void AbstractClient::toggleShade() +{ + // If the mode is ShadeHover or ShadeActive, cancel shade too. + setShade(shadeMode() == ShadeNone ? ShadeNormal : ShadeNone); } AbstractClient::Position AbstractClient::titlebarPosition() const @@ -1745,6 +1823,18 @@ updateCursor(); break; } + case Options::MouseShade: + toggleShade(); + cancelShadeHoverTimer(); + break; + case Options::MouseSetShade: + setShade(ShadeNormal); + cancelShadeHoverTimer(); + break; + case Options::MouseUnsetShade: + setShade(ShadeNone); + cancelShadeHoverTimer(); + break; case Options::MouseNothing: default: replay = true; @@ -2324,7 +2414,11 @@ void AbstractClient::enterEvent(const QPoint &globalPos) { - // TODO: shade hover + if (options->isShadeHover()) { + cancelShadeHoverTimer(); + startShadeHoverTimer(); + } + if (options->focusPolicy() == Options::ClickToFocus || workspace()->userActionsMenu()->isShown()) return; @@ -2350,7 +2444,8 @@ { cancelAutoRaise(); workspace()->cancelDelayFocus(); - // TODO: shade hover + cancelShadeHoverTimer(); + startShadeUnhoverTimer(); // TODO: send hover leave to deco // TODO: handle Options::FocusStrictlyUnderMouse } diff --git a/events.cpp b/events.cpp --- a/events.cpp +++ b/events.cpp @@ -774,16 +774,6 @@ #define MOUSE_DRIVEN_FOCUS (!options->focusPolicyIsReasonable() || \ (options->focusPolicy() == Options::FocusFollowsMouse && options->isNextFocusPrefersMouse())) if (e->mode == XCB_NOTIFY_MODE_NORMAL || (e->mode == XCB_NOTIFY_MODE_UNGRAB && MOUSE_DRIVEN_FOCUS)) { - - if (options->isShadeHover()) { - cancelShadeHoverTimer(); - if (isShade()) { - shadeHoverTimer = new QTimer(this); - connect(shadeHoverTimer, SIGNAL(timeout()), this, SLOT(shadeHover())); - shadeHoverTimer->setSingleShot(true); - shadeHoverTimer->start(options->shadeHoverInterval()); - } - } #undef MOUSE_DRIVEN_FOCUS enterEvent(QPoint(e->root_x, e->root_y)); @@ -817,13 +807,6 @@ } if (lostMouse) { leaveEvent(); - cancelShadeHoverTimer(); - if (shade_mode == ShadeHover && !isMoveResize() && !isMoveResizePointerButtonDown()) { - shadeHoverTimer = new QTimer(this); - connect(shadeHoverTimer, SIGNAL(timeout()), this, SLOT(shadeUnhover())); - shadeHoverTimer->setSingleShot(true); - shadeHoverTimer->start(options->shadeHoverInterval()); - } if (isDecorated()) { // sending a move instead of a leave. With leave we need to send proper coords, with move it's handled internally QHoverEvent leaveEvent(QEvent::HoverMove, QPointF(-1, -1), QPointF(-1, -1), Qt::NoModifier); diff --git a/tabbox/tabbox.cpp b/tabbox/tabbox.cpp --- a/tabbox/tabbox.cpp +++ b/tabbox/tabbox.cpp @@ -318,16 +318,12 @@ void TabBoxHandlerImpl::shadeClient(TabBoxClient *c, bool b) const { - X11Client *cl = dynamic_cast(static_cast(c)->client()); - if (!cl) { - // shading is X11 specific - return; - } - cl->cancelShadeHoverTimer(); // stop core shading action - if (!b && cl->shadeMode() == ShadeNormal) - cl->setShade(ShadeHover); - else if (b && cl->shadeMode() == ShadeHover) - cl->setShade(ShadeNormal); + AbstractClient *client = static_cast(c)->client(); + client->cancelShadeHoverTimer(); // stop core shading action + if (!b && client->shadeMode() == ShadeNormal) + client->setShade(ShadeHover); + else if (b && client->shadeMode() == ShadeHover) + client->setShade(ShadeNormal); } QWeakPointer TabBoxHandlerImpl::desktopClient() const diff --git a/useractions.cpp b/useractions.cpp --- a/useractions.cpp +++ b/useractions.cpp @@ -1132,31 +1132,6 @@ } } -/** - * Performs a mouse command on this client (see options.h) - */ -bool X11Client::performMouseCommand(Options::MouseCommand command, const QPoint &globalPos) -{ - bool replay = false; - switch(command) { - case Options::MouseShade : - toggleShade(); - cancelShadeHoverTimer(); - break; - case Options::MouseSetShade: - setShade(ShadeNormal); - cancelShadeHoverTimer(); - break; - case Options::MouseUnsetShade: - setShade(ShadeNone); - cancelShadeHoverTimer(); - break; - default: - return AbstractClient::performMouseCommand(command, globalPos); - } - return replay; -} - void Workspace::slotActivateAttentionWindow() { if (attention_chain.count() > 0) diff --git a/x11client.h b/x11client.h --- a/x11client.h +++ b/x11client.h @@ -144,10 +144,7 @@ bool isShown(bool shaded_is_shown) const override; bool isHiddenInternal() const override; // For compositing - ShadeMode shadeMode() const override; // Prefer isShade() - void setShade(ShadeMode mode) override; bool isShadeable() const override; - bool isMaximizable() const override; MaximizeMode maximizeMode() const override; @@ -201,8 +198,6 @@ bool providesContextHelp() const override; - bool performMouseCommand(Options::MouseCommand, const QPoint& globalPos) override; - QRect adjustedClientArea(const QRect& desktop, const QRect& area) const; xcb_colormap_t colormap() const; @@ -251,9 +246,7 @@ static bool sameAppWindowRoleMatch(const X11Client *c1, const X11Client *c2, bool active_hack); void killWindow() override; - void toggleShade(); void showContextHelp() override; - void cancelShadeHoverTimer(); void checkActiveModal(); StrutRect strutRect(StrutArea area) const; StrutRects strutRects() const; @@ -330,10 +323,6 @@ void closeWindow() override; void updateCaption() override; -private Q_SLOTS: - void shadeHover(); - void shadeUnhover(); - private: // Handlers for X11 events bool mapRequestEvent(xcb_map_request_event_t *e); @@ -359,6 +348,7 @@ void doSetActive() override; void doSetKeepAbove() override; void doSetKeepBelow() override; + void doSetShade(ShadeMode previousShadeMode) override; void doSetDesktop() override; void doMinimize() override; void doSetSkipPager() override; @@ -503,7 +493,6 @@ void setTransient(xcb_window_t new_transient_for_id); xcb_window_t m_transientForId; xcb_window_t m_originalTransientForId; - ShadeMode shade_mode; X11Client *shade_below; uint deleting : 1; ///< True when doing cleanup and destroying the client Xcb::MotifHints m_motif; @@ -522,7 +511,6 @@ QRect m_bufferGeometry = QRect(0, 0, 100, 100); QRect m_clientGeometry = QRect(0, 0, 100, 100); QRect geom_fs_restore; - QTimer* shadeHoverTimer; xcb_colormap_t m_colormap; QString cap_normal, cap_iconic, cap_suffix; Group* in_group; @@ -607,11 +595,6 @@ return hidden; } -inline ShadeMode X11Client::shadeMode() const -{ - return shade_mode; -} - inline MaximizeMode X11Client::maximizeMode() const { return max_mode; diff --git a/x11client.cpp b/x11client.cpp --- a/x11client.cpp +++ b/x11client.cpp @@ -120,7 +120,6 @@ , shade_below(nullptr) , m_motif(atoms->motif_wm_hints) , blocks_compositing(false) - , shadeHoverTimer(nullptr) , m_colormap(XCB_COLORMAP_NONE) , in_group(nullptr) , ping_timer(nullptr) @@ -147,7 +146,6 @@ info = nullptr; - shade_mode = ShadeNone; deleting = false; m_fullscreenMode = FullScreenNone; hidden = false; @@ -1468,35 +1466,8 @@ return !isSpecialWindow() && !noBorder() && (rules()->checkShade(ShadeNormal) != rules()->checkShade(ShadeNone)); } -void X11Client::setShade(ShadeMode mode) +void X11Client::doSetShade(ShadeMode previousShadeMode) { - if (mode == ShadeHover && isMove()) - return; // causes geometry breaks and is probably nasty - if (isSpecialWindow() || noBorder()) - mode = ShadeNone; - mode = rules()->checkShade(mode); - if (shade_mode == mode) - return; - bool was_shade = isShade(); - ShadeMode was_shade_mode = shade_mode; - shade_mode = mode; - - // Decorations may turn off some borders when shaded - // this has to happen _before_ the tab alignment since it will restrict the minimum geometry -#if 0 - if (decoration) - decoration->borders(border_left, border_right, border_top, border_bottom); -#endif - - if (was_shade == isShade()) { - // Decoration may want to update after e.g. hover-shade changes - emit shadeChanged(); - return; // No real change in shaded state - } - - Q_ASSERT(isDecorated()); // noborder windows can't be shaded - GeometryUpdatesBlocker blocker(this); - // TODO: All this unmapping, resizing etc. feels too much duplicated from elsewhere if (isShade()) { // shade_mode == ShadeNormal @@ -1512,7 +1483,7 @@ exportMappingState(XCB_ICCCM_WM_STATE_ICONIC); plainResize(s); shade_geometry_change = false; - if (was_shade_mode == ShadeHover) { + if (previousShadeMode == ShadeHover) { if (shade_below && workspace()->stackingOrder().indexOf(shade_below) > -1) workspace()->restack(this, shade_below, true); if (isActive()) @@ -1528,9 +1499,9 @@ shade_geometry_change = false; plainResize(s); setGeometryRestore(frameGeometry()); - if ((shade_mode == ShadeHover || shade_mode == ShadeActivated) && rules()->checkAcceptFocus(info->input())) + if ((shadeMode() == ShadeHover || shadeMode() == ShadeActivated) && rules()->checkAcceptFocus(info->input())) setActive(true); - if (shade_mode == ShadeHover) { + if (shadeMode() == ShadeHover) { QList order = workspace()->stackingOrder(); // invalidate, since "this" could be the topmost toplevel and shade_below dangeling shade_below = nullptr; @@ -1554,36 +1525,8 @@ } info->setState(isShade() ? NET::Shaded : NET::States(), NET::Shaded); info->setState(isShown(false) ? NET::States() : NET::Hidden, NET::Hidden); - discardWindowPixmap(); updateVisibility(); updateAllowedActions(); - updateWindowRules(Rules::Shade); - - emit shadeChanged(); -} - -void X11Client::shadeHover() -{ - setShade(ShadeHover); - cancelShadeHoverTimer(); -} - -void X11Client::shadeUnhover() -{ - setShade(ShadeNormal); - cancelShadeHoverTimer(); -} - -void X11Client::cancelShadeHoverTimer() -{ - delete shadeHoverTimer; - shadeHoverTimer = nullptr; -} - -void X11Client::toggleShade() -{ - // If the mode is ShadeHover or ShadeActive, cancel shade too - setShade(shade_mode == ShadeNone ? ShadeNormal : ShadeNone); } void X11Client::updateVisibility()