diff --git a/bridge.cpp b/bridge.cpp index 31d285e088..150c474933 100644 --- a/bridge.cpp +++ b/bridge.cpp @@ -43,6 +43,7 @@ Bridge::Bridge(Client* cl) BRIDGE_HELPER(bool, isCloseable, , , const) BRIDGE_HELPER(bool, isMaximizable, , , const) BRIDGE_HELPER(Bridge::MaximizeMode, maximizeMode, , , const) +BRIDGE_HELPER(Bridge::QuickTileMode, quickTileMode, , , const) BRIDGE_HELPER(bool, isMinimizable, , , const) BRIDGE_HELPER(bool, providesContextHelp, , , const) BRIDGE_HELPER(int, desktop, , , const) diff --git a/bridge.h b/bridge.h index 35efc9012e..6312ea73ba 100644 --- a/bridge.h +++ b/bridge.h @@ -36,6 +36,7 @@ public: virtual bool isCloseable() const; virtual bool isMaximizable() const; virtual MaximizeMode maximizeMode() const; + virtual QuickTileMode quickTileMode() const; virtual bool isMinimizable() const; virtual bool providesContextHelp() const; virtual int desktop() const; diff --git a/client.cpp b/client.cpp index f596fb5265..87020b8853 100644 --- a/client.cpp +++ b/client.cpp @@ -638,8 +638,8 @@ void Client::updateFrameExtents() /** * Resizes the decoration, and makes sure the decoration widget gets resize event * even if the size hasn't changed. This is needed to make sure the decoration - * re-layouts (e.g. when options()->moveResizeMaximizedWindows() changes, - * the decoration may turn on/off some borders, but the actual size + * re-layouts (e.g. when maximization state changes, + * the decoration may alter some borders, but the actual size * of the decoration stays the same). */ void Client::resizeDecoration(const QSize& s) @@ -2425,6 +2425,16 @@ QRect Client::decorationRect() const } } +KDecorationDefines::Position Client::titlebarPosition() +{ + Position titlePos = PositionCenter; // PositionTop is returned by the default implementation + // this will hint errors in the metaobject usage ;-) + if (decoration) + QMetaObject::invokeMethod(decoration, "titlebarPosition", Qt::DirectConnection, + Q_RETURN_ARG(KDecorationDefines::Position, titlePos)); + return titlePos; +} + void Client::updateFirstInTabBox() { // TODO: move into KWindowInfo diff --git a/client.h b/client.h index 6582326833..b3a439cc88 100644 --- a/client.h +++ b/client.h @@ -615,6 +615,8 @@ public: bool decorationHasAlpha() const; + Position titlebarPosition(); + enum CoordinateMode { DecorationRelative, // Relative to the top left corner of the decoration WindowRelative // Relative to the top left corner of the window @@ -1156,9 +1158,9 @@ inline Client::MaximizeMode Client::maximizeMode() const return max_mode; } -inline KWin::QuickTileMode Client::quickTileMode() const +inline Client::QuickTileMode Client::quickTileMode() const { - return (KWin::QuickTileMode)quick_tile_mode; + return (Client::QuickTileMode)quick_tile_mode; } inline bool Client::skipTaskbar(bool from_outside) const diff --git a/geometry.cpp b/geometry.cpp index 56255db7cb..a7293ef47f 100644 --- a/geometry.cpp +++ b/geometry.cpp @@ -379,7 +379,12 @@ QPoint Workspace::adjustClientPosition(Client* c, QPoint pos, bool unrestricted, //CT 16mar98, 27May98 - magics: BorderSnapZone, WindowSnapZone //CT adapted for kwin on 25Nov1999 //aleXXX 02Nov2000 added second snapping mode - if (options->windowSnapZone() || options->borderSnapZone() || options->centerSnapZone()) { + int borderSnapZone = options->borderSnapZone(); + if (c->maximizeMode() != MaximizeRestore) + borderSnapZone = qMax(borderSnapZone + 2, clientArea(ScreenArea, c).height() / 16); + + if (options->windowSnapZone() || borderSnapZone || options->centerSnapZone()) { + const bool sOWO = options->isSnapOnlyWhenOverlapping(); const QRect maxRect = clientArea(MovementArea, pos + c->rect().center(), c->desktop()); const int xmin = maxRect.left(); @@ -394,6 +399,19 @@ QPoint Workspace::adjustClientPosition(Client* c, QPoint pos, bool unrestricted, const int rx(cx + cw); const int ry(cy + ch); //these don't change + // only enforce large snap while we're on a corresponding border + if (c->maximizeMode() != MaximizeRestore) { + QRect geo = c->geometry(); + if (c->maximizeMode() & MaximizeVertical && geo.y() != maxRect.top() && geo.bottom() != maxRect.bottom()) { + borderSnapZone = options->borderSnapZone(); + } + if (c->maximizeMode() & MaximizeHorizontal && geo.x() != maxRect.left() && geo.right() != maxRect.right()) { + borderSnapZone = options->borderSnapZone(); + } + if (!(borderSnapZone || options->windowSnapZone() || options->centerSnapZone())) // ma have changed + return pos; + } + int nx(cx), ny(cy); //buffers int deltaX(xmax); int deltaY(ymax); //minimum distance to other clients @@ -401,24 +419,39 @@ QPoint Workspace::adjustClientPosition(Client* c, QPoint pos, bool unrestricted, int lx, ly, lrx, lry; //coords and size for the comparison client, l // border snap - int snap = options->borderSnapZone() * snapAdjust; //snap trigger + int snap = borderSnapZone * snapAdjust; //snap trigger if (snap) { + const QPoint cp = c->clientPos(); + const QSize cs = c->geometry().size() - c->clientSize(); + int padding[4] = { cp.x(), cs.width() - cp.x(), cp.y(), cs.height() - cp.y() }; + + // snap to titlebar + Position titlePos = c->titlebarPosition(); + if (titlePos == PositionLeft) + padding[0] = 0; + if (titlePos == PositionRight) + padding[1] = 0; + if (titlePos == PositionTop) + padding[2] = 0; + if (titlePos == PositionBottom) + padding[3] = 0; + if ((sOWO ? (cx < xmin) : true) && (qAbs(xmin - cx) < snap)) { - deltaX = xmin - cx; - nx = xmin; + deltaX = xmin - (cx - padding[0]); + nx = xmin - padding[0]; } if ((sOWO ? (rx > xmax) : true) && (qAbs(rx - xmax) < snap) && (qAbs(xmax - rx) < deltaX)) { - deltaX = rx - xmax; - nx = xmax - cw; + deltaX = rx + padding[1] - xmax; + nx = xmax - cw + padding[1]; } if ((sOWO ? (cy < ymin) : true) && (qAbs(ymin - cy) < snap)) { - deltaY = ymin - cy; - ny = ymin; + deltaY = ymin - (cy - padding[2]); + ny = ymin - padding[2]; } if ((sOWO ? (ry > ymax) : true) && (qAbs(ry - ymax) < snap) && (qAbs(ymax - ry) < deltaY)) { - deltaY = ry - ymax; - ny = ymax - ch; + deltaY = ry + padding[3] - ymax; + ny = ymax - ch + padding[3]; } } @@ -500,7 +533,7 @@ QPoint Workspace::adjustClientPosition(Client* c, QPoint pos, bool unrestricted, deltaY = diffY; nx = (xmin + xmax) / 2 - cw / 2; ny = (ymin + ymax) / 2 - ch / 2; - } else if (options->borderSnapZone()) { + } else if (borderSnapZone) { // Enhance border snap if ((nx == xmin || nx == xmax - cw) && diffY < snap && diffY < deltaY) { // Snap to vertical center on screen edge @@ -1205,7 +1238,6 @@ void Client::checkOffscreenPosition(QRect* geom, const QRect& screenArea) QSize Client::adjustedSize(const QSize& frame, Sizemode mode) const { // first, get the window size for the given frame size s - QSize wsize(frame.width() - (border_left + border_right), frame.height() - (border_top + border_bottom)); if (wsize.isEmpty()) @@ -1762,8 +1794,6 @@ bool Client::isMovable() const return false; if (isSpecialWindow() && !isSplash() && !isToolbar()) // allow moving of splashscreens :) return false; - if (maximizeMode() == MaximizeFull && !options->moveResizeMaximizedWindows()) - return false; if (rules()->checkPosition(invalidPoint) != invalidPoint) // forced position return false; return true; @@ -1792,8 +1822,6 @@ bool Client::isResizable() const return false; if (isSpecialWindow() || isSplash() || isToolbar()) return false; - if (maximizeMode() == MaximizeFull && !options->moveResizeMaximizedWindows()) - return isMove(); // for quick tiling - maxmode will be unset if we tile if (rules()->checkSize(QSize()).isValid()) // forced size return false; @@ -2201,11 +2229,7 @@ void Client::changeMaximize(bool vertical, bool horizontal, bool adjust) Notify::raise(Notify::UnMaximize); } - ForceGeometry_t geom_mode = NormalGeometrySet; - if (decoration != NULL) { // decorations may turn off some borders when maximized - if (checkBorderSizes(false)) // only query, don't resize - geom_mode = ForceGeometrySet; - } + const ForceGeometry_t geom_mode = decoration && checkBorderSizes(false) ? ForceGeometrySet : NormalGeometrySet; // Conditional quick tiling exit points if (quick_tile_mode != QuickTileNone) { @@ -2553,17 +2577,7 @@ bool Client::startMoveResize() // the top of the screen. When the setting is disabled then doing so is confusing. bool fakeMove = false; if (!isFullScreen()) { // xinerama move across screens -> window is FS, everything else is secondary and untouched - if (maximizeMode() != MaximizeRestore && - (maximizeMode() != MaximizeFull || options->moveResizeMaximizedWindows())) { - // allow moveResize, but unset maximization state in resize case - if (mode != PositionCenter) { // means "isResize()" but moveResizeMode = true is set below - if (maximizeMode() == MaximizeFull) { // partial is cond. reset in finishMoveResize - geom_restore = geometry(); // "restore" to current geometry - setMaximize(false, false); - } - } else if (quick_tile_mode != QuickTileNone) // no longer now - we move, resize is handled below - setQuickTileMode(QuickTileNone); // otherwise we mess every second tile, bug #303937 - } else if ((maximizeMode() == MaximizeFull && options->electricBorderMaximize()) || + if ((maximizeMode() == MaximizeFull && options->electricBorderMaximize()) || (quick_tile_mode != QuickTileNone && isMovable() && mode == PositionCenter)) { // Exit quick tile mode when the user attempts to move a tiled window, cannot use isMove() yet const QRect before = geometry(); @@ -2572,6 +2586,15 @@ bool Client::startMoveResize() moveOffset = QPoint(double(moveOffset.x()) / double(before.width()) * double(geom_restore.width()), double(moveOffset.y()) / double(before.height()) * double(geom_restore.height())); fakeMove = true; + } else if (maximizeMode() != MaximizeRestore) { + // allow moveResize, but unset maximization state in resize case + if (mode != PositionCenter) { // means "isResize()" but moveResizeMode = true is set below + if (maximizeMode() == MaximizeFull) { // partial is cond. reset in finishMoveResize + geom_restore = geometry(); // "restore" to current geometry + setMaximize(false, false); + } + } else if (quick_tile_mode != QuickTileNone) // no longer now - we move, resize is handled below + setQuickTileMode(QuickTileNone); // otherwise we mess every second tile, bug #303937 } } @@ -3069,7 +3092,7 @@ void Client::setElectricBorderMode(QuickTileMode mode) electricMode = mode; } -QuickTileMode Client::electricBorderMode() const +Client::QuickTileMode Client::electricBorderMode() const { return electricMode; } @@ -3145,10 +3168,13 @@ void Client::setQuickTileMode(QuickTileMode mode, bool keyboard) setMaximize(false, false); - // Temporary, so the maximize code doesn't get all confused - quick_tile_mode = QuickTileNone; - if (mode != QuickTileNone) - setGeometry(electricBorderMaximizeGeometry(keyboard ? geometry().center() : cursorPos(), desktop())); + if (mode != QuickTileNone) { + quick_tile_mode = mode; + // decorations may turn off some borders when tiled + const ForceGeometry_t geom_mode = decoration && checkBorderSizes(false) ? ForceGeometrySet : NormalGeometrySet; + quick_tile_mode = QuickTileNone; // Temporary, so the maximize code doesn't get all confused + setGeometry(electricBorderMaximizeGeometry(keyboard ? geometry().center() : cursorPos(), desktop()), geom_mode); + } // Store the mode change quick_tile_mode = mode; @@ -3164,7 +3190,9 @@ void Client::setQuickTileMode(QuickTileMode mode, bool keyboard) // Untiling, so just restore geometry, and we're done. if (!geom_restore.isValid()) // invalid if we started maximized and wait for placement geom_restore = geometry(); - setGeometry(geom_restore); + // decorations may turn off some borders when tiled + const ForceGeometry_t geom_mode = decoration && checkBorderSizes(false) ? ForceGeometrySet : NormalGeometrySet; + setGeometry(geom_restore, geom_mode); checkWorkspacePosition(); // Just in case it's a different screen return; } else { @@ -3213,10 +3241,14 @@ void Client::setQuickTileMode(QuickTileMode mode, bool keyboard) geom_restore = geometry(); } - // Temporary, so the maximize code doesn't get all confused - quick_tile_mode = QuickTileNone; - if (mode != QuickTileNone) - setGeometry(electricBorderMaximizeGeometry(whichScreen, desktop())); + if (mode != QuickTileNone) { + quick_tile_mode = mode; + // decorations may turn off some borders when tiled + const ForceGeometry_t geom_mode = decoration && checkBorderSizes(false) ? ForceGeometrySet : NormalGeometrySet; + // Temporary, so the maximize code doesn't get all confused + quick_tile_mode = QuickTileNone; + setGeometry(electricBorderMaximizeGeometry(whichScreen, desktop()), geom_mode); + } // Store the mode change quick_tile_mode = mode; diff --git a/kcmkwin/kwindecoration/preview.cpp b/kcmkwin/kwindecoration/preview.cpp index 3e25b2aed6..04a91dd967 100644 --- a/kcmkwin/kwindecoration/preview.cpp +++ b/kcmkwin/kwindecoration/preview.cpp @@ -214,6 +214,11 @@ KDecoration::MaximizeMode KDecorationPreviewBridge::maximizeMode() const return KDecoration::MaximizeRestore; } +KDecoration::QuickTileMode KDecorationPreviewBridge::quickTileMode() const +{ + return KDecoration::QuickTileNone; +} + bool KDecorationPreviewBridge::isMinimizable() const { return true; diff --git a/kcmkwin/kwindecoration/preview.h b/kcmkwin/kwindecoration/preview.h index 420e302b64..6e322d44e7 100644 --- a/kcmkwin/kwindecoration/preview.h +++ b/kcmkwin/kwindecoration/preview.h @@ -68,6 +68,7 @@ public: virtual bool isCloseable() const; virtual bool isMaximizable() const; virtual MaximizeMode maximizeMode() const; + virtual QuickTileMode quickTileMode() const; virtual bool isMinimizable() const; virtual bool providesContextHelp() const; virtual int desktop() const; diff --git a/libkdecorations/kdecoration.cpp b/libkdecorations/kdecoration.cpp index 780842e75b..3f692be586 100644 --- a/libkdecorations/kdecoration.cpp +++ b/libkdecorations/kdecoration.cpp @@ -136,6 +136,11 @@ KDecoration::MaximizeMode KDecoration::maximizeMode() const return bridge_->maximizeMode(); } +KDecoration::QuickTileMode KDecoration::quickTileMode() const +{ + return bridge_->quickTileMode(); +} + bool KDecoration::isMinimizable() const { return bridge_->isMinimizable(); @@ -520,6 +525,11 @@ QRegion KDecoration::region(KDecorationDefines::Region) return QRegion(); } +KDecorationDefines::Position KDecoration::titlebarPosition() +{ + return PositionTop; +} + QString KDecorationDefines::tabDragMimeType() { return "text/ClientGroupItem"; @@ -612,7 +622,8 @@ KDecorationOptions::BorderSize KDecorationOptions::preferredBorderSize(KDecorati bool KDecorationOptions::moveResizeMaximizedWindows() const { - return d->move_resize_maximized_windows; + // TODO KF5: remove function with API break + return false; } KDecorationDefines::WindowOperation KDecorationOptions::operationMaxButtonClick(Qt::MouseButtons button) const diff --git a/libkdecorations/kdecoration.h b/libkdecorations/kdecoration.h index 0959e74a14..bda4ea5e2b 100644 --- a/libkdecorations/kdecoration.h +++ b/libkdecorations/kdecoration.h @@ -98,6 +98,19 @@ public: MaximizeFull = MaximizeVertical | MaximizeHorizontal }; + enum QuickTileFlag { + QuickTileNone = 0, + QuickTileLeft = 1, + QuickTileRight = 1<<1, + QuickTileTop = 1<<2, + QuickTileBottom = 1<<3, + QuickTileHorizontal = QuickTileLeft|QuickTileRight, + QuickTileVertical = QuickTileTop|QuickTileBottom, + QuickTileMaximize = QuickTileLeft|QuickTileRight|QuickTileTop|QuickTileBottom + }; + + Q_DECLARE_FLAGS(QuickTileMode, QuickTileFlag) + enum WindowOperation { MaximizeOp = 5000, RestoreOp, @@ -419,11 +432,9 @@ public: */ BorderSize preferredBorderSize(KDecorationFactory* factory) const; - /* - * When this functions returns false, moving and resizing of maximized windows - * is not allowed, and therefore the decoration is allowed to turn off (some of) - * its borders. - * The changed flags for this setting is SettingButtons. + /** + * This functions returns false + * @deprecated */ bool moveResizeMaximizedWindows() const; @@ -510,6 +521,13 @@ public: /** * Returns @a true if the decorated window can be minimized by the user. */ + + /** + * Returns the current quicktiling mode of the decorated window. + * (window is places into one of the corners or edges) + */ + QuickTileMode quickTileMode() const; + bool isMinimizable() const; /** * Return @a true if the decorated window can show context help @@ -930,6 +948,13 @@ public: * Ungrabs X server (if the number of ungrab attempts matches the number of grab attempts). */ void ungrabXServer(); + +public: // invokables; runtime resolution + /** + * reimplement this invokable to signal the core where the titlebar is (usually PositionTop) + */ + Q_INVOKABLE KDecorationDefines::Position titlebarPosition(); + public Q_SLOTS: // requests from decoration @@ -1189,4 +1214,6 @@ inline int KDecoration::height() const /** @} */ +Q_DECLARE_OPERATORS_FOR_FLAGS(KDecoration::QuickTileMode) + #endif diff --git a/libkdecorations/kdecoration_p.cpp b/libkdecorations/kdecoration_p.cpp index 5b54369304..e7fb9b1a5d 100644 --- a/libkdecorations/kdecoration_p.cpp +++ b/libkdecorations/kdecoration_p.cpp @@ -38,7 +38,6 @@ KDecorationOptionsPrivate::KDecorationOptionsPrivate() , show_tooltips(true) , border_size(BorderNormal) , cached_border_size(BordersCount) // invalid - , move_resize_maximized_windows(true) , opMaxButtonRightClick(MaximizeOp) , opMaxButtonMiddleClick(VMaximizeOp) , opMaxButtonLeftClick(HMaximizeOp) @@ -193,12 +192,6 @@ unsigned long KDecorationOptionsPrivate::updateSettings(KConfig* config) changed |= SettingBorder; cached_border_size = BordersCount; // invalid - KConfigGroup windowsConfig(config, "Windows"); - bool old_move_resize_maximized_windows = move_resize_maximized_windows; - move_resize_maximized_windows = windowsConfig.readEntry("MoveResizeMaximizedWindows", false); - if (old_move_resize_maximized_windows != move_resize_maximized_windows) - changed |= SettingBorder; - // destroy cached values int i; for (i = 0; i < NUM_COLORS * 2; ++i) { diff --git a/libkdecorations/kdecoration_p.h b/libkdecorations/kdecoration_p.h index 8a34e2d8cf..e1a38ed027 100644 --- a/libkdecorations/kdecoration_p.h +++ b/libkdecorations/kdecoration_p.h @@ -50,7 +50,6 @@ public: bool custom_button_positions; bool show_tooltips; BorderSize border_size, cached_border_size; - bool move_resize_maximized_windows; WindowOperation opMaxButtonRightClick; WindowOperation opMaxButtonMiddleClick; WindowOperation opMaxButtonLeftClick; diff --git a/libkdecorations/kdecorationbridge.h b/libkdecorations/kdecorationbridge.h index a050e55acc..5096333e28 100644 --- a/libkdecorations/kdecorationbridge.h +++ b/libkdecorations/kdecorationbridge.h @@ -42,6 +42,7 @@ public: virtual bool isCloseable() const = 0; virtual bool isMaximizable() const = 0; virtual MaximizeMode maximizeMode() const = 0; + virtual QuickTileMode quickTileMode() const = 0; virtual bool isMinimizable() const = 0; virtual bool providesContextHelp() const = 0; virtual int desktop() const = 0; diff --git a/libkwineffects/kwinglobals.h b/libkwineffects/kwinglobals.h index 867b0a30b4..505ad5c549 100644 --- a/libkwineffects/kwinglobals.h +++ b/libkwineffects/kwinglobals.h @@ -84,19 +84,6 @@ enum ElectricBorder { ElectricNone }; -enum QuickTileFlag { - QuickTileNone = 0, - QuickTileLeft = 1, - QuickTileRight = 1<<1, - QuickTileTop = 1<<2, - QuickTileBottom = 1<<3, - QuickTileHorizontal = QuickTileLeft|QuickTileRight, - QuickTileVertical = QuickTileTop|QuickTileBottom, - QuickTileMaximize = QuickTileLeft|QuickTileRight|QuickTileTop|QuickTileBottom -}; - -Q_DECLARE_FLAGS(QuickTileMode, QuickTileFlag) - // TODO: Hardcoding is bad, need to add some way of registering global actions to these. // When designing the new system we must keep in mind that we have conditional actions // such as "only when moving windows" desktop switching that the current global action @@ -211,6 +198,4 @@ private: } // namespace -Q_DECLARE_OPERATORS_FOR_FLAGS(KWin::QuickTileMode) - #endif diff --git a/workspace.h b/workspace.h index 17f7743d95..685b3ccc9b 100644 --- a/workspace.h +++ b/workspace.h @@ -971,6 +971,7 @@ inline bool Workspace::decorationSupportsBlurBehind() const return mgr->factory()->supports(AbilityUsesBlurBehind); } + } // namespace #endif