diff options
author | Mavridis Philippe <mavridisf@gmail.com> | 2023-04-05 22:08:38 +0300 |
---|---|---|
committer | Mavridis Philippe <mavridisf@gmail.com> | 2023-05-27 16:32:23 +0300 |
commit | 31335a04ed9bc01fd3ede33afde40d6f3359f2e9 (patch) | |
tree | c15b7ab30c4af1e4992b908e48921d6c6c7017a8 /twin/geometry.cpp | |
parent | 3285a47d5dc3ffecabe49aaa11877f1abe71df44 (diff) | |
download | tdebase-31335a04ed9bc01fd3ede33afde40d6f3359f2e9.tar.gz tdebase-31335a04ed9bc01fd3ede33afde40d6f3359f2e9.zip |
TWin: Active borders and snap tiling
This commit is a squash of the commits of TDE/tdebase#331.
In short, this backports some improvements to existing electric border
functionality from KDE, adds the snap tiling (or aerosnap) feature and
brings rudimentary support for active corners, which will be fully
implemented in a later PR.
The options dialog and the documentation has been updated to reflect
these changes.
Additionally, a new relevant option is introduced: an option for
restoring the original size of maximized/tiled windows when the user
starts dragging them. The option is set to be off by default,
preserving the traditional behaviour of KDE 3.x/TDE.
Last but not least, the term "electric" in relation to borders and
corners is replaced by "active" for clarity to the users.
Signed-off-by: Mavridis Philippe <mavridisf@gmail.com>
Diffstat (limited to 'twin/geometry.cpp')
-rw-r--r-- | twin/geometry.cpp | 266 |
1 files changed, 197 insertions, 69 deletions
diff --git a/twin/geometry.cpp b/twin/geometry.cpp index 5c71e7c1f..7dd38bee2 100644 --- a/twin/geometry.cpp +++ b/twin/geometry.cpp @@ -40,7 +40,7 @@ namespace KWinInternal Resizes the workspace after an XRANDR screen size change */ void Workspace::desktopResized() - { +{ //printf("Workspace::desktopResized()\n"); TQRect geom = TDEApplication::desktop()->geometry(); NETSize desktop_geometry; @@ -49,24 +49,17 @@ void Workspace::desktopResized() rootInfo->setDesktopGeometry( -1, desktop_geometry ); updateClientArea( true ); - checkElectricBorders( true ); - } + destroyActiveBorders(); + updateActiveBorders(); +} /*! Resizes the workspace after kdesktop signals a desktop resize */ void Workspace::kDestopResized() - { - //printf("Workspace::kDesktopResized()\n"); - TQRect geom = TDEApplication::desktop()->geometry(); - NETSize desktop_geometry; - desktop_geometry.width = geom.width(); - desktop_geometry.height = geom.height(); - rootInfo->setDesktopGeometry( -1, desktop_geometry ); - - updateClientArea( true ); - checkElectricBorders( true ); - } +{ + desktopResized(); +} /*! Updates the current client areas according to the current clients. @@ -2302,7 +2295,7 @@ class EatAllPaintEvents static EatAllPaintEvents* eater = 0; bool Client::startMoveResize() - { +{ assert( !moveResizeMode ); assert( TQWidget::keyboardGrabber() == NULL ); assert( TQWidget::mouseGrabber() == NULL ); @@ -2324,28 +2317,55 @@ bool Client::startMoveResize() if( XGrabKeyboard( tqt_xdisplay(), frameId(), False, GrabModeAsync, GrabModeAsync, GET_QT_X_TIME() ) == Success ) has_grab = true; if( !has_grab ) // at least one grab is necessary in order to be able to finish move/resize - { + { XDestroyWindow( tqt_xdisplay(), move_resize_grab_window ); move_resize_grab_window = None; return false; - } - if ( maximizeMode() != MaximizeRestore ) - resetMaximize(); + } + removeShadow(); moveResizeMode = true; + initialMoveResizeGeom = geometry(); + + if (activeTiled) + { + // Restore original geometry + activeTiled = false; + if (options->resetMaximizedWindowGeometry() && isMove()) { + setGeometry(activeTiledOrigGeom); + } + } + + if ( maximizeMode() != MaximizeRestore ) + { + if (options->resetMaximizedWindowGeometry() && isMove()) { + maximize(MaximizeRestore); + } + else { + resetMaximize(); + } + activeTiled = false; + } + + moveResizeGeom = geometry(); workspace()->setClientIsMoving(this); - initialMoveResizeGeom = moveResizeGeom = geometry(); checkUnrestrictedMoveResize(); + // rule out non opaque windows from useless translucency settings, maybe resizes? if ((isResize() && options->removeShadowsOnResize) || (isMove() && options->removeShadowsOnMove)) + { setShadowSize(0); - if (rules()->checkMoveResizeMode( options->moveMode ) == Options::Opaque){ + } + + if (rules()->checkMoveResizeMode( options->moveMode ) == Options::Opaque) + { savedOpacity_ = opacity_; setOpacity(options->translucentMovingWindows, options->movingWindowOpacity); } + if ( ( isMove() && rules()->checkMoveResizeMode( options->moveMode ) != Options::Opaque ) || ( isResize() && rules()->checkMoveResizeMode( options->resizeMode ) != Options::Opaque ) ) - { + { grabXServer(); kapp->sendPostedEvents(); // we have server grab -> nothing should cause paint events @@ -2355,25 +2375,57 @@ bool Client::startMoveResize() // paint events for the geometrytip need to be allowed, though eater = new EatAllPaintEvents; // not needed anymore? kapp->installEventFilter( eater ); - } + } Notify::raise( isResize() ? Notify::ResizeStart : Notify::MoveStart ); - return true; + + if (options->activeBorders() == Options::ActiveSwitchOnMove || + options->activeBorders() == Options::ActiveTileMaximize || + options->activeBorders() == Options::ActiveTileOnly) + + { + workspace()->reserveActiveBorderSwitching(true); } + return true; +} + void Client::finishMoveResize( bool cancel ) - { +{ leaveMoveResize(); - if( cancel ) - setGeometry( initialMoveResizeGeom ); + + if (!isActiveBorderMaximizing()) { + setGeometry(cancel ? initialMoveResizeGeom : moveResizeGeom); + } + else - setGeometry( moveResizeGeom ); + { + kdDebug() <<"finishing moveresize in active mode, cancel is " << cancel << endl; + activeMaximizing = false; + activeTiled = true; + activeTiledOrigGeom = initialMoveResizeGeom; + switch(activeMode) + { + case ActiveMaximizeMode: + { + if (!cancel) { + bool full = (maximizeMode() == MaximizeFull); + setMaximize(!full, !full); + } + break; + } + default: + setGeometry(cancel ? initialMoveResizeGeom + : activeBorderMaximizeGeometry()); + } + } + checkMaximizeGeometry(); // FRAME update(); Notify::raise( isResize() ? Notify::ResizeEnd : Notify::MoveEnd ); - } +} void Client::leaveMoveResize() - { +{ // rule out non opaque windows from useless translucency settings, maybe resizes? if (rules()->checkMoveResizeMode( options->moveMode ) == Options::Opaque) setOpacity(true, savedOpacity_); @@ -2401,12 +2453,19 @@ void Client::leaveMoveResize() delete eater; eater = 0; if (options->shadowEnabled(isActive())) - { + { drawIntersectingShadows(); updateOpacityCache(); - } } + if (options->activeBorders() == Options::ActiveSwitchOnMove || + options->activeBorders() == Options::ActiveTileMaximize || + options->activeBorders() == Options::ActiveTileOnly) + { + workspace()->reserveActiveBorderSwitching(false); + } +} + // This function checks if it actually makes sense to perform a restricted move/resize. // If e.g. the titlebar is already outside of the workarea, there's no point in performing // a restricted move resize, because then e.g. resize would also move the window (#74555). @@ -2454,25 +2513,25 @@ void Client::checkUnrestrictedMoveResize() void Client::handleMoveResize( int x, int y, int x_root, int y_root ) { - if(( mode == PositionCenter && !isMovable()) - || ( mode != PositionCenter && ( isShade() || !isResizable()))) + if ( (mode == PositionCenter && !isMovable()) + || (mode != PositionCenter && (isShade() || !isResizable())) ) return; - if ( !moveResizeMode ) - { - TQPoint p( TQPoint( x, y ) - moveOffset ); + if (!moveResizeMode) + { + TQPoint p(TQPoint( x, y ) - moveOffset); if (p.manhattanLength() >= 6) + { + if(!startMoveResize()) { - if( !startMoveResize()) - { buttonDown = false; setCursor( mode ); return; - } } + } else return; - } + } // ShadeHover or ShadeActive, ShadeNormal was already avoided above if ( mode != PositionCenter && shade_mode != ShadeNone ) @@ -2494,7 +2553,7 @@ void Client::handleMoveResize( int x, int y, int x_root, int y_root ) if( unrestrictedMoveResize ) // unrestricted, just don't let it go out completely left_marge = right_marge = top_marge = bottom_marge = titlebar_marge = 5; else // restricted move/resize - keep at least part of the titlebar always visible - { + { // how much must remain visible when moved away in that direction left_marge = KMIN( 100 + border_right, moveResizeGeom.width()); right_marge = KMIN( 100 + border_left, moveResizeGeom.width()); @@ -2502,16 +2561,16 @@ void Client::handleMoveResize( int x, int y, int x_root, int y_root ) titlebar_marge = initialMoveResizeGeom.height(); top_marge = border_bottom; bottom_marge = border_top; - } + } bool update = false; - if( isResize()) - { + if (isResize()) + { // first resize (without checking constraints), then snap, then check bounds, then check constraints TQRect orig = initialMoveResizeGeom; Sizemode sizemode = SizemodeAny; switch ( mode ) - { + { case PositionTopLeft: moveResizeGeom = TQRect( topleft, orig.bottomRight() ) ; break; @@ -2544,7 +2603,7 @@ void Client::handleMoveResize( int x, int y, int x_root, int y_root ) default: assert( false ); break; - } + } // adjust new size to snap to other windows/borders moveResizeGeom = workspace()->adjustClientSize( this, moveResizeGeom, mode ); @@ -2567,7 +2626,7 @@ void Client::handleMoveResize( int x, int y, int x_root, int y_root ) bottomright = TQPoint( moveResizeGeom.left() + size.width() - 1, moveResizeGeom.top() + size.height() - 1 ); orig = moveResizeGeom; switch ( mode ) - { // these 4 corners ones are copied from above + { // these 4 corners ones are copied from above case PositionTopLeft: moveResizeGeom = TQRect( topleft, orig.bottomRight() ) ; break; @@ -2599,12 +2658,12 @@ void Client::handleMoveResize( int x, int y, int x_root, int y_root ) default: assert( false ); break; - } - if( moveResizeGeom.size() != previousMoveResizeGeom.size()) - update = true; } - else if( isMove()) - { + if (moveResizeGeom.size() != previousMoveResizeGeom.size()) + update = true; + } + else if (isMove()) + { assert( mode == PositionCenter ); // first move, then snap, then check bounds moveResizeGeom.moveTopLeft( topleft ); @@ -2621,29 +2680,98 @@ void Client::handleMoveResize( int x, int y, int x_root, int y_root ) moveResizeGeom.moveLeft(desktopArea.right() - right_marge ); if( moveResizeGeom.topLeft() != previousMoveResizeGeom.topLeft()) update = true; - } + } else - assert( false ); + assert(false); - if( update ) + if (update) + { + if (rules()->checkMoveResizeMode(isResize() ? options->resizeMode : options->moveMode) == Options::Opaque + && !isActiveBorderMaximizing()) { - if( rules()->checkMoveResizeMode - ( isResize() ? options->resizeMode : options->moveMode ) == Options::Opaque ) - { setGeometry( moveResizeGeom ); positionGeometryTip(); - } - else if( rules()->checkMoveResizeMode - ( isResize() ? options->resizeMode : options->moveMode ) == Options::Transparent ) - { - clearbound(); // it's necessary to move the geometry tip when there's no outline - positionGeometryTip(); // shown, otherwise it would cause repaint problems in case - drawbound( moveResizeGeom ); // they overlap; the paint event will come after this, - } // so the geometry tip will be painted above the outline } - if ( isMove() ) - workspace()->clientMoved(globalPos, GET_QT_X_TIME()); + else if (rules()->checkMoveResizeMode(isResize() ? options->resizeMode : options->moveMode) == Options::Transparent ) + { + /* It's necessary to move the geometry tip when there's no outline + * shown, otherwise it would cause repaint problems in case + * they overlap; the paint event will come after this, + * so the geometry tip will be painted above the outline + */ + clearbound(); + positionGeometryTip(); + drawbound(isActiveBorderMaximizing() ? activeBorderMaximizeGeometry() : moveResizeGeom); + } } + if (isMove()) + workspace()->checkActiveBorder(globalPos, GET_QT_X_TIME()); +} + +void Client::setActiveBorderMode( ActiveMaximizingMode mode ) +{ + activeMode = mode; +} + +ActiveMaximizingMode Client::activeBorderMode() const +{ + return activeMode; +} + +bool Client::isActiveBorderMaximizing() const +{ + return activeMaximizing; +} +void Client::setActiveBorderMaximizing( bool maximizing ) +{ + activeMaximizing = maximizing; + + if (maximizing || rules()->checkMoveResizeMode(isResize() ? options->resizeMode : options->moveMode) == Options::Opaque) { + clearbound(); + } + + if (maximizing) { + drawbound(activeBorderMaximizeGeometry()); + } +} + +TQRect Client::activeBorderMaximizeGeometry() +{ + TQRect ret; + TQRect max = workspace()->clientArea(MaximizeArea, TQCursor::pos(), workspace()->currentDesktop()); + switch (activeMode) + { + case ActiveMaximizeMode: + { + if (maximizeMode() == MaximizeFull) + ret = geometryRestore(); + else + ret = max; + break; + } + case ActiveLeftMode: + { + ret = TQRect( max.x(), max.y(), max.width()/2, max.height() ); + break; + } + case ActiveRightMode: + { + ret = TQRect( max.x() + max.width()/2, max.y(), max.width()/2, max.height() ); + break; + } + case ActiveTopMode: + { + ret = TQRect( max.x(), max.y(), max.width(), max.height()/2 ); + break; + } + case ActiveBottomMode: + { + ret = TQRect( max.x(), max.y() + max.height()/2, max.width(), max.height()/2 ); + break; + } + } + return ret; +} } // namespace |