diff --git a/client.cpp b/client.cpp index b8ad60d1f8..fcf37730c7 100644 --- a/client.cpp +++ b/client.cpp @@ -127,6 +127,7 @@ Client::Client( Workspace* ws ) // Set the initial mapping state mapping_state = Withdrawn; + quick_tile_mode = QuickTileNone; desk = 0; // No desktop yet mode = PositionCenter; diff --git a/client.h b/client.h index 6562e0b642..662af5e311 100644 --- a/client.h +++ b/client.h @@ -229,6 +229,12 @@ class Client bool isElectricBorderMaximizing() const; QRect electricBorderMaximizeGeometry(); + /** Set the quick tile mode ("snap") of this window. + * This will also handle preserving and restoring of window geometry as necessary. + * @param mode The tile mode (left/right) to give this window. + */ + void setQuickTileMode( QuickTileMode mode ); + void growHorizontal(); void shrinkHorizontal(); void growVertical(); @@ -492,6 +498,11 @@ class Client Kept ///< The frame should be unmapped, but is kept (For compositing) }; MappingState mapping_state; + + /** The quick tile mode of this window. + */ + QuickTileMode quick_tile_mode; + void readTransient(); Window verifyTransientFor( Window transient_for, bool set ); void addTransient( Client* cl ); diff --git a/geometry.cpp b/geometry.cpp index 56ccf1f9c8..78f5c35975 100644 --- a/geometry.cpp +++ b/geometry.cpp @@ -2169,7 +2169,15 @@ void Client::maximize( MaximizeMode m ) Sets the maximization according to \a vertically and \a horizontally */ void Client::setMaximize( bool vertically, bool horizontally ) - { // changeMaximize() flips the state, so change from set->flip + { + // If maximizing, and a quick tile mode is set, drop it: + // this will restore the original geometry, meaning we can save it correctly here, + // as well as moving from maximized to quick tiled properly if desired. + // (remember, a quick tile is technically not maximized in any way!) + if( (vertically || horizontally) && quick_tile_mode != QuickTileNone ) + setQuickTileMode( QuickTileNone ); + + // changeMaximize() flips the state, so change from set->flip changeMaximize( max_mode & MaximizeVertical ? !vertically : vertically, max_mode & MaximizeHorizontal ? !horizontally : horizontally, @@ -2691,6 +2699,10 @@ bool Client::startMoveResize() } if ( maximizeMode() != MaximizeRestore ) resetMaximize(); + // Undo any quick tile state this window has (it will trigger a resize, but that's expected) + if( quick_tile_mode != QuickTileNone ) + setQuickTileMode( QuickTileNone ); + moveResizeMode = true; workspace()->setClientIsMoving(this); initialMoveResizeGeom = moveResizeGeom = geometry(); @@ -2742,14 +2754,12 @@ void Client::finishMoveResize( bool cancel ) break; case ElectricLeftMode: { - QRect max = workspace()->clientArea( MaximizeArea, cursorPos() ,workspace()->currentDesktop() ); - setGeometry( QRect( max.x(), max.y(), max.width()/2, max.height() ) ); + setQuickTileMode( QuickTileLeft ); break; } case ElectricRightMode: { - QRect max = workspace()->clientArea( MaximizeArea, cursorPos() ,workspace()->currentDesktop() ); - setGeometry( QRect( max.x() + max.width()/2, max.y(), max.width()/2, max.height() ) ); + setQuickTileMode( QuickTileRight ); break; } } @@ -3221,4 +3231,58 @@ QRect Client::electricBorderMaximizeGeometry() return ret; } +void Client::setQuickTileMode( QuickTileMode mode ) + { + // Only allow quick tile on a regular or maximized window + if( !isResizable() && maximizeMode() != MaximizeFull ) + return; + + // restore from maximized so that it is possible to tile maximized windows with one hit or by dragging + if( maximizeMode() == MaximizeFull ) + { + setMaximize(false, false); + checkMaximizeGeometry(); + } + + // First, check if the requested tile negates the tile we're in now: move right when left or left when right + // is the same as explicitly untiling this window, so allow it. + if( mode == QuickTileNone || + (quick_tile_mode == QuickTileLeft && mode == QuickTileRight) || + (quick_tile_mode == QuickTileRight && mode == QuickTileLeft) ) + { + // Untiling, so just restore geometry, and we're done. + setGeometry( geom_restore ); + quick_tile_mode = QuickTileNone; + return; + } + else + { + // Check they aren't retiling in an existing direction, so we don't overwrite the saved geometry needlessly + if ( quick_tile_mode == mode ) + return; + + // Not coming out of an existing tile, not shifting monitors, we're setting a brand new tile. + // Store geometry first, so we can go out of this tile later. + geom_restore = geometry(); + + // Temporary, so the maximize code doesn't get all confused + quick_tile_mode = QuickTileNone; + + // Do the actual tile. + if( mode == QuickTileLeft ) + { + QRect max = workspace()->clientArea( MaximizeArea, this ); + setGeometry( QRect( max.x(), max.y(), max.width()/2, max.height() ) ); + } + else + { + QRect max = workspace()->clientArea( MaximizeArea, this); + setGeometry( QRect( max.x() + max.width()/2, max.y(), max.width()/2, max.height() ) ); + } + + // Store the mode change + quick_tile_mode = mode; + } + } + } // namespace diff --git a/kwinbindings.cpp b/kwinbindings.cpp index 4b05a69650..63be6c1918 100644 --- a/kwinbindings.cpp +++ b/kwinbindings.cpp @@ -115,6 +115,10 @@ along with this program. If not, see . 0, slotWindowShrinkHorizontal() ); DEF2( "Window Shrink Vertical", I18N_NOOP("Pack Shrink Window Vertically"), 0, slotWindowShrinkVertical() ); + DEF2( "Window Quick Tile Left", I18N_NOOP("Quick Tile Window to the Left"), + 0, slotWindowQuickTileLeft() ); + DEF2( "Window Quick Tile Right", I18N_NOOP("Quick Tile Window to the Right"), + 0, slotWindowQuickTileRight() ); a = actionCollection->addAction( "Group:Window Desktop" ); a->setText( i18n("Window & Desktop") ); diff --git a/lib/kwinglobals.h b/lib/kwinglobals.h index 7cde22f625..600bba6417 100644 --- a/lib/kwinglobals.h +++ b/lib/kwinglobals.h @@ -79,6 +79,13 @@ enum ElectricMaximizingMode ElectricRightMode }; +enum QuickTileMode +{ + QuickTileNone, + QuickTileLeft, + QuickTileRight +}; + // 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 diff --git a/placement.cpp b/placement.cpp index a1e50db73e..c27bc390ec 100644 --- a/placement.cpp +++ b/placement.cpp @@ -721,6 +721,23 @@ void Client::shrinkVertical() setGeometry( geom ); } + +void Workspace::slotWindowQuickTileLeft() + { + if( !active_client ) + return; + + active_client->setQuickTileMode( QuickTileLeft ); + } + +void Workspace::slotWindowQuickTileRight() + { + if( !active_client ) + return; + + active_client->setQuickTileMode( QuickTileRight ); + } + int Workspace::packPositionLeft( const Client* cl, int oldx, bool left_edge ) const { int newx = clientArea( MovementArea, cl ).left(); diff --git a/workspace.h b/workspace.h index b635cd2462..74cc8bc09c 100644 --- a/workspace.h +++ b/workspace.h @@ -569,6 +569,8 @@ class Workspace : public QObject, public KDecorationDefines void slotWindowGrowVertical(); void slotWindowShrinkHorizontal(); void slotWindowShrinkVertical(); + void slotWindowQuickTileLeft(); + void slotWindowQuickTileRight(); void slotWalkThroughDesktops(); void slotWalkBackThroughDesktops();