2022-06-30 12:09:05 +02:00
# include "IHyprLayout.hpp"
# include "../defines.hpp"
# include "../Compositor.hpp"
2023-11-19 12:29:01 +00:00
# include "../render/decorations/CHyprGroupBarDecoration.hpp"
2024-03-03 18:39:20 +00:00
# include "../config/ConfigValue.hpp"
2025-04-15 23:00:40 +00:00
# include "../config/ConfigManager.hpp"
2024-03-20 01:44:51 +00:00
# include "../desktop/Window.hpp"
2024-05-10 23:28:33 +01:00
# include "../protocols/XDGShell.hpp"
2024-06-08 10:07:59 +02:00
# include "../protocols/core/Compositor.hpp"
2024-05-25 22:43:51 +02:00
# include "../xwayland/XSurface.hpp"
2025-01-17 15:21:35 +00:00
# include "../render/Renderer.hpp"
# include "../managers/input/InputManager.hpp"
# include "../managers/LayoutManager.hpp"
# include "../managers/EventManager.hpp"
# include "../managers/HookSystemManager.hpp"
2022-06-30 12:09:05 +02:00
2024-04-27 12:43:12 +01:00
void IHyprLayout : : onWindowCreated ( PHLWINDOW pWindow , eDirection direction ) {
2025-03-07 20:12:02 -05:00
CBox desiredGeometry = g_pXWaylandManager - > getGeometryForWindow ( pWindow ) ;
2022-08-05 17:52:14 +02:00
2025-05-06 09:53:43 +08:00
const bool HASPERSISTENTSIZE = std : : ranges : : any_of ( pWindow - > m_matchedRules , [ ] ( const auto & rule ) { return rule - > m_ruleType = = CWindowRule : : RULE_PERSISTENTSIZE ; } ) ;
2025-03-07 20:12:02 -05:00
const auto STOREDSIZE = HASPERSISTENTSIZE ? g_pConfigManager - > getStoredFloatingSize ( pWindow ) : std : : nullopt ;
if ( STOREDSIZE . has_value ( ) ) {
2025-04-28 22:25:22 +02:00
Debug : : log ( LOG , " using stored size {}x{} for new window {}::{} " , STOREDSIZE - > x , STOREDSIZE - > y , pWindow - > m_class , pWindow - > m_title ) ;
pWindow - > m_lastFloatingSize = STOREDSIZE . value ( ) ;
2025-03-07 20:12:02 -05:00
} else if ( desiredGeometry . width < = 5 | | desiredGeometry . height < = 5 ) {
2025-04-28 22:25:22 +02:00
const auto PMONITOR = pWindow - > m_monitor . lock ( ) ;
2025-04-30 23:45:20 +02:00
pWindow - > m_lastFloatingSize = PMONITOR - > m_size / 2.f ;
2024-10-02 11:22:19 +02:00
} else
2025-04-28 22:25:22 +02:00
pWindow - > m_lastFloatingSize = Vector2D ( desiredGeometry . width , desiredGeometry . height ) ;
2022-08-05 17:52:14 +02:00
2025-04-28 22:25:22 +02:00
pWindow - > m_pseudoSize = pWindow - > m_lastFloatingSize ;
2023-06-30 11:29:02 +02:00
2024-10-02 11:22:19 +02:00
bool autoGrouped = IHyprLayout : : onWindowCreatedAutoGroup ( pWindow ) ;
if ( autoGrouped )
return ;
2025-04-28 22:25:22 +02:00
if ( pWindow - > m_isFloating )
2024-10-02 11:22:19 +02:00
onWindowCreatedFloating ( pWindow ) ;
else
2023-09-13 10:13:29 +00:00
onWindowCreatedTiling ( pWindow , direction ) ;
2024-12-19 19:22:40 +00:00
if ( ! g_pXWaylandManager - > shouldBeFloated ( pWindow ) ) // do not apply group rules to child windows
pWindow - > applyGroupRules ( ) ;
2022-06-30 12:09:05 +02:00
}
2024-04-27 12:43:12 +01:00
void IHyprLayout : : onWindowRemoved ( PHLWINDOW pWindow ) {
2024-07-31 17:55:52 +00:00
if ( pWindow - > isFullscreen ( ) )
g_pCompositor - > setWindowFullscreenInternal ( pWindow , FSMODE_NONE ) ;
2022-12-07 18:55:56 +00:00
2025-04-28 22:25:22 +02:00
if ( ! pWindow - > m_groupData . pNextWindow . expired ( ) ) {
if ( pWindow - > m_groupData . pNextWindow . lock ( ) = = pWindow )
pWindow - > m_groupData . pNextWindow . reset ( ) ;
2023-02-19 21:07:32 +00:00
else {
// find last window and update
2024-04-27 12:43:12 +01:00
PHLWINDOW PWINDOWPREV = pWindow - > getGroupPrevious ( ) ;
2023-09-04 13:13:39 +00:00
const auto WINDOWISVISIBLE = pWindow - > getGroupCurrent ( ) = = pWindow ;
2023-02-19 21:07:32 +00:00
2023-09-04 13:13:39 +00:00
if ( WINDOWISVISIBLE )
2025-04-28 22:25:22 +02:00
PWINDOWPREV - > setGroupCurrent ( pWindow - > m_groupData . head ? pWindow - > m_groupData . pNextWindow . lock ( ) : PWINDOWPREV ) ;
2023-02-19 21:07:32 +00:00
2025-04-28 22:25:22 +02:00
PWINDOWPREV - > m_groupData . pNextWindow = pWindow - > m_groupData . pNextWindow ;
2023-02-19 21:07:32 +00:00
2025-04-28 22:25:22 +02:00
pWindow - > m_groupData . pNextWindow . reset ( ) ;
2023-02-19 21:07:32 +00:00
2025-04-28 22:25:22 +02:00
if ( pWindow - > m_groupData . head ) {
std : : swap ( PWINDOWPREV - > m_groupData . pNextWindow - > m_groupData . head , pWindow - > m_groupData . head ) ;
std : : swap ( PWINDOWPREV - > m_groupData . pNextWindow - > m_groupData . locked , pWindow - > m_groupData . locked ) ;
2023-02-19 21:07:32 +00:00
}
2025-05-01 13:27:07 +02:00
if ( pWindow = = m_lastTiledWindow )
m_lastTiledWindow . reset ( ) ;
2023-02-19 21:07:32 +00:00
2023-02-19 23:26:36 +00:00
pWindow - > setHidden ( false ) ;
2023-08-30 15:39:22 +00:00
pWindow - > updateWindowDecos ( ) ;
2023-09-04 13:13:39 +00:00
PWINDOWPREV - > getGroupCurrent ( ) - > updateWindowDecos ( ) ;
2023-08-30 15:39:22 +00:00
g_pCompositor - > updateWindowAnimatedDecorationValues ( pWindow ) ;
2023-02-19 21:07:32 +00:00
return ;
}
}
2025-04-28 22:25:22 +02:00
if ( pWindow - > m_isFloating ) {
2022-06-30 12:09:05 +02:00
onWindowRemovedFloating ( pWindow ) ;
} else {
onWindowRemovedTiling ( pWindow ) ;
}
2022-10-24 12:25:36 +01:00
2025-05-01 13:27:07 +02:00
if ( pWindow = = m_lastTiledWindow )
m_lastTiledWindow . reset ( ) ;
2022-06-30 12:09:05 +02:00
}
2024-04-27 12:43:12 +01:00
void IHyprLayout : : onWindowRemovedFloating ( PHLWINDOW pWindow ) {
2024-12-07 18:51:18 +01:00
; // no-op
2022-06-30 12:09:05 +02:00
}
2024-04-27 12:43:12 +01:00
void IHyprLayout : : onWindowCreatedFloating ( PHLWINDOW pWindow ) {
2023-08-17 08:13:19 +00:00
2025-01-26 15:05:34 +00:00
CBox desiredGeometry = g_pXWaylandManager - > getGeometryForWindow ( pWindow ) ;
2025-04-28 22:25:22 +02:00
const auto PMONITOR = pWindow - > m_monitor . lock ( ) ;
2023-08-15 20:09:32 +02:00
2025-04-28 22:25:22 +02:00
if ( pWindow - > m_isX11 ) {
2023-08-15 20:09:32 +02:00
Vector2D xy = { desiredGeometry . x , desiredGeometry . y } ;
xy = g_pXWaylandManager - > xwaylandToWaylandCoords ( xy ) ;
desiredGeometry . x = xy . x ;
desiredGeometry . y = xy . y ;
}
2023-06-22 21:43:31 +02:00
2024-03-03 18:39:20 +00:00
static auto PXWLFORCESCALEZERO = CConfigValue < Hyprlang : : INT > ( " xwayland:force_zero_scaling " ) ;
2022-06-30 12:09:05 +02:00
if ( ! PMONITOR ) {
2023-09-20 15:25:03 +00:00
Debug : : log ( ERR , " {:m} has an invalid monitor in onWindowCreatedFloating!!! " , pWindow ) ;
2022-06-30 12:09:05 +02:00
return ;
}
2022-07-18 13:14:31 +02:00
if ( desiredGeometry . width < = 5 | | desiredGeometry . height < = 5 ) {
2025-04-28 22:25:22 +02:00
const auto PWINDOWSURFACE = pWindow - > m_wlSurface - > resource ( ) ;
2025-05-03 16:02:49 +02:00
* pWindow - > m_realSize = PWINDOWSURFACE - > m_current . size ;
2022-07-28 15:40:06 +02:00
2025-04-28 22:25:22 +02:00
if ( ( desiredGeometry . width < = 1 | | desiredGeometry . height < = 1 ) & & pWindow - > m_isX11 & &
2024-08-30 14:12:23 +02:00
pWindow - > isX11OverrideRedirect ( ) ) { // XDG windows should be fine. TODO: check for weird atoms?
2022-10-14 20:46:32 +01:00
pWindow - > setHidden ( true ) ;
2022-07-28 15:40:06 +02:00
return ;
}
2022-09-25 20:07:48 +02:00
2022-07-18 13:14:31 +02:00
// reject any windows with size <= 5x5
2025-04-28 22:25:22 +02:00
if ( pWindow - > m_realSize - > goal ( ) . x < = 5 | | pWindow - > m_realSize - > goal ( ) . y < = 5 )
2025-04-30 23:45:20 +02:00
* pWindow - > m_realSize = PMONITOR - > m_size / 2.f ;
2022-06-30 12:09:05 +02:00
2025-04-28 22:25:22 +02:00
if ( pWindow - > m_isX11 & & pWindow - > isX11OverrideRedirect ( ) ) {
2023-02-03 21:09:11 +00:00
2025-05-07 15:21:44 +02:00
if ( pWindow - > m_xwaylandSurface - > m_geometry . x ! = 0 & & pWindow - > m_xwaylandSurface - > m_geometry . y ! = 0 )
* pWindow - > m_realPosition = g_pXWaylandManager - > xwaylandToWaylandCoords ( pWindow - > m_xwaylandSurface - > m_geometry . pos ( ) ) ;
2023-02-03 21:09:11 +00:00
else
2025-04-30 23:45:20 +02:00
* pWindow - > m_realPosition = Vector2D ( PMONITOR - > m_position . x + ( PMONITOR - > m_size . x - pWindow - > m_realSize - > goal ( ) . x ) / 2.f ,
PMONITOR - > m_position . y + ( PMONITOR - > m_size . y - pWindow - > m_realSize - > goal ( ) . y ) / 2.f ) ;
2023-02-03 21:09:11 +00:00
} else {
2025-04-30 23:45:20 +02:00
* pWindow - > m_realPosition = Vector2D ( PMONITOR - > m_position . x + ( PMONITOR - > m_size . x - pWindow - > m_realSize - > goal ( ) . x ) / 2.f ,
PMONITOR - > m_position . y + ( PMONITOR - > m_size . y - pWindow - > m_realSize - > goal ( ) . y ) / 2.f ) ;
2023-02-03 21:09:11 +00:00
}
2022-06-30 12:09:05 +02:00
} else {
// we respect the size.
2025-04-28 22:25:22 +02:00
* pWindow - > m_realSize = Vector2D ( desiredGeometry . width , desiredGeometry . height ) ;
2022-06-30 12:09:05 +02:00
// check if it's on the correct monitor!
Vector2D middlePoint = Vector2D ( desiredGeometry . x , desiredGeometry . y ) + Vector2D ( desiredGeometry . width , desiredGeometry . height ) / 2.f ;
2022-09-13 22:23:48 +02:00
// check if it's visible on any monitor (only for XDG)
2025-04-28 22:25:22 +02:00
bool visible = pWindow - > m_isX11 ;
2022-09-13 12:29:56 +02:00
2023-08-25 18:10:12 +02:00
if ( ! visible ) {
visible = g_pCompositor - > isPointOnAnyMonitor ( Vector2D ( desiredGeometry . x , desiredGeometry . y ) ) & &
g_pCompositor - > isPointOnAnyMonitor ( Vector2D ( desiredGeometry . x + desiredGeometry . width , desiredGeometry . y ) ) & &
g_pCompositor - > isPointOnAnyMonitor ( Vector2D ( desiredGeometry . x , desiredGeometry . y + desiredGeometry . height ) ) & &
g_pCompositor - > isPointOnAnyMonitor ( Vector2D ( desiredGeometry . x + desiredGeometry . width , desiredGeometry . y + desiredGeometry . height ) ) ;
2022-09-13 12:29:56 +02:00
}
2022-06-30 12:09:05 +02:00
// TODO: detect a popup in a more consistent way.
2025-04-28 22:25:22 +02:00
if ( ( desiredGeometry . x = = 0 & & desiredGeometry . y = = 0 ) | | ! visible | | ! pWindow - > m_isX11 ) {
2025-05-08 21:00:28 +02:00
// if the pos isn't set, fall back to the center placement if it's not a child
auto pos = PMONITOR - > m_position + PMONITOR - > m_size / 2.F - desiredGeometry . size ( ) / 2.F ;
// otherwise middle of parent if available
if ( ! pWindow - > m_isX11 ) {
if ( const auto PARENT = pWindow - > parent ( ) ; PARENT ) {
* pWindow - > m_realPosition = PARENT - > m_realPosition - > goal ( ) + PARENT - > m_realSize - > goal ( ) / 2.F - desiredGeometry . size ( ) / 2.F ;
pWindow - > m_workspace = PARENT - > m_workspace ;
pWindow - > m_monitor = PARENT - > m_monitor ;
}
}
* pWindow - > m_realPosition = pos ;
2022-06-30 12:09:05 +02:00
} else {
// if it is, we respect where it wants to put itself, but apply monitor offset if outside
// most of these are popups
2025-04-30 23:45:20 +02:00
if ( const auto POPENMON = g_pCompositor - > getMonitorFromVector ( middlePoint ) ; POPENMON - > m_id ! = PMONITOR - > m_id )
* pWindow - > m_realPosition = Vector2D ( desiredGeometry . x , desiredGeometry . y ) - POPENMON - > m_position + PMONITOR - > m_position ;
2023-07-01 16:28:17 +02:00
else
2025-04-28 22:25:22 +02:00
* pWindow - > m_realPosition = Vector2D ( desiredGeometry . x , desiredGeometry . y ) ;
2022-06-30 12:09:05 +02:00
}
}
2025-04-28 22:25:22 +02:00
if ( * PXWLFORCESCALEZERO & & pWindow - > m_isX11 )
2025-04-30 23:45:20 +02:00
* pWindow - > m_realSize = pWindow - > m_realSize - > goal ( ) / PMONITOR - > m_scale ;
2023-06-22 21:43:31 +02:00
2025-04-28 22:25:22 +02:00
if ( pWindow - > m_X11DoesntWantBorders | | ( pWindow - > m_isX11 & & pWindow - > isX11OverrideRedirect ( ) ) ) {
pWindow - > m_realPosition - > warp ( ) ;
pWindow - > m_realSize - > warp ( ) ;
2022-06-30 12:09:05 +02:00
}
2025-02-06 11:21:04 +00:00
if ( ! pWindow - > isX11OverrideRedirect ( ) )
2023-09-21 17:18:26 -04:00
g_pCompositor - > changeWindowZOrder ( pWindow , true ) ;
2025-02-06 11:21:04 +00:00
else {
2025-04-28 22:25:22 +02:00
pWindow - > m_pendingReportedSize = pWindow - > m_realSize - > goal ( ) ;
pWindow - > m_reportedSize = pWindow - > m_pendingReportedSize ;
2023-11-09 22:43:52 +00:00
}
2022-06-30 12:09:05 +02:00
}
2024-10-02 11:22:19 +02:00
bool IHyprLayout : : onWindowCreatedAutoGroup ( PHLWINDOW pWindow ) {
2024-10-27 00:44:55 +00:00
static auto PAUTOGROUP = CConfigValue < Hyprlang : : INT > ( " group:auto_group " ) ;
2025-04-28 22:25:22 +02:00
const PHLWINDOW OPENINGON = g_pCompositor - > m_lastWindow . lock ( ) & & g_pCompositor - > m_lastWindow - > m_workspace = = pWindow - > m_workspace ?
2025-04-22 15:23:29 +02:00
g_pCompositor - > m_lastWindow . lock ( ) :
2025-04-28 22:25:22 +02:00
( pWindow - > m_workspace ? pWindow - > m_workspace - > getFirstWindow ( ) : nullptr ) ;
const bool FLOATEDINTOTILED = pWindow - > m_isFloating & & ! OPENINGON - > m_isFloating ;
const bool SWALLOWING = pWindow - > m_swallowed | | pWindow - > m_groupSwallowed ;
2024-10-27 00:44:55 +00:00
if ( ( * PAUTOGROUP | | SWALLOWING ) // continue if auto_group is enabled or if dealing with window swallowing.
2024-10-22 23:51:25 +00:00
& & OPENINGON // this shouldn't be 0, but honestly, better safe than sorry.
2024-10-16 21:13:35 +00:00
& & OPENINGON ! = pWindow // prevent freeze when the "group set" window rule makes the new window to be already a group.
2025-04-28 22:25:22 +02:00
& & OPENINGON - > m_groupData . pNextWindow . lock ( ) // check if OPENINGON is a group.
2024-10-13 23:25:19 +00:00
& & pWindow - > canBeGroupedInto ( OPENINGON ) // check if the new window can be grouped into OPENINGON.
2024-10-27 00:44:55 +00:00
& & ! g_pXWaylandManager - > shouldBeFloated ( pWindow ) // don't group child windows. Fix for floated groups. Tiled groups don't need this because we check if !FLOATEDINTOTILED.
& & ! FLOATEDINTOTILED ) { // don't group a new floated window into a tiled group (for convenience).
2024-10-02 11:22:19 +02:00
2025-04-28 22:25:22 +02:00
pWindow - > m_isFloating = OPENINGON - > m_isFloating ; // match the floating state. Needed to autogroup a new tiled window into a floated group.
2024-10-02 11:22:19 +02:00
static auto USECURRPOS = CConfigValue < Hyprlang : : INT > ( " group:insert_after_current " ) ;
2024-10-07 14:22:55 +02:00
( * USECURRPOS ? OPENINGON : OPENINGON - > getGroupTail ( ) ) - > insertWindowToGroup ( pWindow ) ;
2024-10-02 11:22:19 +02:00
2024-10-07 14:22:55 +02:00
OPENINGON - > setGroupCurrent ( pWindow ) ;
2024-12-21 16:35:47 +00:00
pWindow - > applyGroupRules ( ) ;
2024-10-02 11:22:19 +02:00
pWindow - > updateWindowDecos ( ) ;
recalculateWindow ( pWindow ) ;
if ( ! pWindow - > getDecorationByType ( DECORATION_GROUPBAR ) )
2025-01-23 21:55:41 +01:00
pWindow - > addWindowDeco ( makeUnique < CHyprGroupBarDecoration > ( pWindow ) ) ;
2024-10-02 11:22:19 +02:00
return true ;
}
return false ;
}
2022-06-30 12:09:05 +02:00
void IHyprLayout : : onBeginDragWindow ( ) {
2025-05-01 23:57:11 +02:00
const auto DRAGGINGWINDOW = g_pInputManager - > m_currentlyDraggedWindow . lock ( ) ;
2025-04-12 10:43:13 -04:00
static auto PDRAGTHRESHOLD = CConfigValue < Hyprlang : : INT > ( " binds:drag_threshold " ) ;
2022-06-30 12:09:05 +02:00
2025-05-01 13:27:07 +02:00
m_mouseMoveEventCount = 1 ;
m_beginDragSizeXY = Vector2D ( ) ;
2022-06-30 12:09:05 +02:00
// Window will be floating. Let's check if it's valid. It should be, but I don't like crashing.
2024-04-27 12:43:12 +01:00
if ( ! validMapped ( DRAGGINGWINDOW ) ) {
2022-06-30 12:09:05 +02:00
Debug : : log ( ERR , " Dragging attempted on an invalid window! " ) ;
2024-07-27 16:46:19 +00:00
g_pKeybindManager - > changeMouseBindMode ( MBIND_INVALID ) ;
2022-06-30 12:09:05 +02:00
return ;
}
2025-04-12 10:43:13 -04:00
// Try to pick up dragged window now if drag_threshold is disabled
// or at least update dragging related variables for the cursors
2025-05-01 23:57:11 +02:00
g_pInputManager - > m_dragThresholdReached = * PDRAGTHRESHOLD < = 0 ;
2025-04-12 10:43:13 -04:00
if ( updateDragWindow ( ) )
2022-06-30 12:09:05 +02:00
return ;
2022-10-03 22:41:05 +01:00
// get the grab corner
2024-03-12 22:43:22 -04:00
static auto RESIZECORNER = CConfigValue < Hyprlang : : INT > ( " general:resize_corner " ) ;
2025-04-28 22:25:22 +02:00
if ( * RESIZECORNER ! = 0 & & * RESIZECORNER < = 4 & & DRAGGINGWINDOW - > m_isFloating ) {
2024-03-12 22:43:22 -04:00
switch ( * RESIZECORNER ) {
case 1 :
2025-05-01 13:27:07 +02:00
m_grabbedCorner = CORNER_TOPLEFT ;
2024-03-12 22:43:22 -04:00
g_pInputManager - > setCursorImageUntilUnset ( " nw-resize " ) ;
break ;
case 2 :
2025-05-01 13:27:07 +02:00
m_grabbedCorner = CORNER_TOPRIGHT ;
2024-03-12 22:43:22 -04:00
g_pInputManager - > setCursorImageUntilUnset ( " ne-resize " ) ;
break ;
case 3 :
2025-05-01 13:27:07 +02:00
m_grabbedCorner = CORNER_BOTTOMRIGHT ;
2024-03-12 22:43:22 -04:00
g_pInputManager - > setCursorImageUntilUnset ( " se-resize " ) ;
break ;
case 4 :
2025-05-01 13:27:07 +02:00
m_grabbedCorner = CORNER_BOTTOMLEFT ;
2024-03-12 22:43:22 -04:00
g_pInputManager - > setCursorImageUntilUnset ( " sw-resize " ) ;
break ;
}
2025-05-01 13:27:07 +02:00
} else if ( m_beginDragXY . x < m_beginDragPositionXY . x + m_beginDragSizeXY . x / 2.0 ) {
if ( m_beginDragXY . y < m_beginDragPositionXY . y + m_beginDragSizeXY . y / 2.0 ) {
m_grabbedCorner = CORNER_TOPLEFT ;
2023-02-26 03:56:23 +02:00
g_pInputManager - > setCursorImageUntilUnset ( " nw-resize " ) ;
} else {
2025-05-01 13:27:07 +02:00
m_grabbedCorner = CORNER_BOTTOMLEFT ;
2023-02-26 03:56:23 +02:00
g_pInputManager - > setCursorImageUntilUnset ( " sw-resize " ) ;
}
2022-10-03 22:41:05 +01:00
} else {
2025-05-01 13:27:07 +02:00
if ( m_beginDragXY . y < m_beginDragPositionXY . y + m_beginDragSizeXY . y / 2.0 ) {
m_grabbedCorner = CORNER_TOPRIGHT ;
2023-02-26 03:56:23 +02:00
g_pInputManager - > setCursorImageUntilUnset ( " ne-resize " ) ;
} else {
2025-05-01 13:27:07 +02:00
m_grabbedCorner = CORNER_BOTTOMRIGHT ;
2023-02-26 03:56:23 +02:00
g_pInputManager - > setCursorImageUntilUnset ( " se-resize " ) ;
}
2022-10-03 22:41:05 +01:00
}
2025-05-01 23:57:11 +02:00
if ( g_pInputManager - > m_dragMode ! = MBIND_RESIZE & & g_pInputManager - > m_dragMode ! = MBIND_RESIZE_FORCE_RATIO & & g_pInputManager - > m_dragMode ! = MBIND_RESIZE_BLOCK_RATIO )
2025-01-29 01:27:34 -08:00
g_pInputManager - > setCursorImageUntilUnset ( " grabbing " ) ;
2023-02-26 23:08:20 +00:00
2022-06-30 12:09:05 +02:00
g_pHyprRenderer - > damageWindow ( DRAGGINGWINDOW ) ;
2022-07-21 19:44:34 +02:00
g_pKeybindManager - > shadowKeybinds ( ) ;
2023-07-13 18:20:40 +00:00
g_pCompositor - > focusWindow ( DRAGGINGWINDOW ) ;
2023-09-21 17:18:26 -04:00
g_pCompositor - > changeWindowZOrder ( DRAGGINGWINDOW , true ) ;
2022-06-30 12:09:05 +02:00
}
void IHyprLayout : : onEndDragWindow ( ) {
2025-05-01 23:57:11 +02:00
const auto DRAGGINGWINDOW = g_pInputManager - > m_currentlyDraggedWindow . lock ( ) ;
2022-06-30 12:09:05 +02:00
2025-05-01 13:27:07 +02:00
m_mouseMoveEventCount = 1 ;
2024-03-06 03:15:44 +03:00
2024-04-27 12:43:12 +01:00
if ( ! validMapped ( DRAGGINGWINDOW ) ) {
2023-02-18 23:35:31 +01:00
if ( DRAGGINGWINDOW ) {
g_pInputManager - > unsetCursorImage ( ) ;
2025-05-01 23:57:11 +02:00
g_pInputManager - > m_currentlyDraggedWindow . reset ( ) ;
2023-02-18 23:35:31 +01:00
}
2022-06-30 12:09:05 +02:00
return ;
2023-02-18 23:35:31 +01:00
}
g_pInputManager - > unsetCursorImage ( ) ;
2025-05-01 23:57:11 +02:00
g_pInputManager - > m_currentlyDraggedWindow . reset ( ) ;
g_pInputManager - > m_wasDraggingWindow = true ;
2023-01-02 12:06:06 +01:00
2025-05-01 23:57:11 +02:00
if ( g_pInputManager - > m_dragMode = = MBIND_MOVE ) {
2023-11-19 12:29:01 +00:00
g_pHyprRenderer - > damageWindow ( DRAGGINGWINDOW ) ;
const auto MOUSECOORDS = g_pInputManager - > getMouseCoordsInternal ( ) ;
2024-10-08 12:20:41 +02:00
PHLWINDOW pWindow = g_pCompositor - > vectorToWindowUnified ( MOUSECOORDS , RESERVED_EXTENTS | INPUT_EXTENTS | ALLOW_FLOATING , DRAGGINGWINDOW ) ;
2023-11-19 12:29:01 +00:00
2024-02-04 15:40:20 +00:00
if ( pWindow ) {
2023-12-28 22:54:41 +00:00
if ( pWindow - > checkInputOnDecos ( INPUT_TYPE_DRAG_END , MOUSECOORDS , DRAGGINGWINDOW ) )
return ;
2023-11-19 12:29:01 +00:00
2025-04-28 22:25:22 +02:00
const bool FLOATEDINTOTILED = ! pWindow - > m_isFloating & & ! DRAGGINGWINDOW - > m_draggingTiled ;
2024-10-27 00:44:55 +00:00
static auto PDRAGINTOGROUP = CConfigValue < Hyprlang : : INT > ( " group:drag_into_group " ) ;
2024-10-30 10:00:58 +00:00
2025-04-28 22:25:22 +02:00
if ( pWindow - > m_groupData . pNextWindow . lock ( ) & & DRAGGINGWINDOW - > canBeGroupedInto ( pWindow ) & & * PDRAGINTOGROUP = = 1 & & ! FLOATEDINTOTILED ) {
2024-10-30 10:00:58 +00:00
2025-04-28 22:25:22 +02:00
if ( DRAGGINGWINDOW - > m_groupData . pNextWindow ) {
PHLWINDOW next = DRAGGINGWINDOW - > m_groupData . pNextWindow . lock ( ) ;
2024-10-30 10:00:58 +00:00
while ( next ! = DRAGGINGWINDOW ) {
2025-04-28 22:25:22 +02:00
next - > m_isFloating = pWindow - > m_isFloating ; // match the floating state of group members
* next - > m_realSize = pWindow - > m_realSize - > goal ( ) ; // match the size of group members
* next - > m_realPosition = pWindow - > m_realPosition - > goal ( ) ; // match the position of group members
next = next - > m_groupData . pNextWindow . lock ( ) ;
2024-10-08 12:20:41 +02:00
}
}
2025-04-28 22:25:22 +02:00
DRAGGINGWINDOW - > m_isFloating = pWindow - > m_isFloating ; // match the floating state of the window
2025-05-01 13:27:07 +02:00
DRAGGINGWINDOW - > m_lastFloatingSize = m_draggingWindowOriginalFloatSize ;
2025-04-28 22:25:22 +02:00
DRAGGINGWINDOW - > m_draggingTiled = false ;
2024-10-08 12:20:41 +02:00
2024-03-03 18:39:20 +00:00
static auto USECURRPOS = CConfigValue < Hyprlang : : INT > ( " group:insert_after_current " ) ;
( * USECURRPOS ? pWindow : pWindow - > getGroupTail ( ) ) - > insertWindowToGroup ( DRAGGINGWINDOW ) ;
2023-11-19 12:29:01 +00:00
pWindow - > setGroupCurrent ( DRAGGINGWINDOW ) ;
2024-12-21 16:35:47 +00:00
DRAGGINGWINDOW - > applyGroupRules ( ) ;
2023-11-19 12:29:01 +00:00
DRAGGINGWINDOW - > updateWindowDecos ( ) ;
if ( ! DRAGGINGWINDOW - > getDecorationByType ( DECORATION_GROUPBAR ) )
2025-01-23 21:55:41 +01:00
DRAGGINGWINDOW - > addWindowDeco ( makeUnique < CHyprGroupBarDecoration > ( DRAGGINGWINDOW ) ) ;
2023-11-19 12:29:01 +00:00
}
}
2022-06-30 12:09:05 +02:00
}
2025-04-28 22:25:22 +02:00
if ( DRAGGINGWINDOW - > m_draggingTiled ) {
DRAGGINGWINDOW - > m_isFloating = false ;
2024-10-08 12:20:41 +02:00
g_pInputManager - > refocus ( ) ;
changeWindowFloatingMode ( DRAGGINGWINDOW ) ;
2025-05-01 13:27:07 +02:00
DRAGGINGWINDOW - > m_lastFloatingSize = m_draggingWindowOriginalFloatSize ;
2024-10-08 12:20:41 +02:00
}
2022-06-30 12:09:05 +02:00
g_pHyprRenderer - > damageWindow ( DRAGGINGWINDOW ) ;
2023-08-05 18:53:13 +00:00
g_pCompositor - > focusWindow ( DRAGGINGWINDOW ) ;
2023-10-29 20:14:47 +00:00
2025-05-01 23:57:11 +02:00
g_pInputManager - > m_wasDraggingWindow = false ;
2022-06-30 12:09:05 +02:00
}
2024-10-31 07:21:08 -04:00
static inline bool canSnap ( const double SIDEA , const double SIDEB , const double GAP ) {
return std : : abs ( SIDEA - SIDEB ) < GAP ;
2024-10-21 11:08:25 -04:00
}
2024-10-31 07:21:08 -04:00
static void snapMove ( double & start , double & end , const double P ) {
end = P + ( end - start ) ;
start = P ;
2024-10-21 11:08:25 -04:00
}
2024-10-31 07:21:08 -04:00
static void snapResize ( double & start , double & end , const double P ) {
start = P ;
2024-10-21 11:08:25 -04:00
}
typedef std : : function < void ( double & , double & , const double ) > SnapFn ;
2024-10-31 07:21:08 -04:00
static void performSnap ( Vector2D & sourcePos , Vector2D & sourceSize , PHLWINDOW DRAGGINGWINDOW , const eMouseBindMode MODE , const int CORNER , const Vector2D & BEGINSIZE ) {
static auto SNAPWINDOWGAP = CConfigValue < Hyprlang : : INT > ( " general:snap:window_gap " ) ;
static auto SNAPMONITORGAP = CConfigValue < Hyprlang : : INT > ( " general:snap:monitor_gap " ) ;
static auto SNAPBORDEROVERLAP = CConfigValue < Hyprlang : : INT > ( " general:snap:border_overlap " ) ;
2024-10-21 11:08:25 -04:00
2024-10-31 07:21:08 -04:00
const SnapFn SNAP = ( MODE = = MBIND_MOVE ) ? snapMove : snapResize ;
int snaps = 0 ;
2024-10-21 11:08:25 -04:00
2024-10-31 07:21:08 -04:00
const bool OVERLAP = * SNAPBORDEROVERLAP ;
2024-10-27 23:39:52 +00:00
const int DRAGGINGBORDERSIZE = DRAGGINGWINDOW - > getRealBorderSize ( ) ;
2024-10-31 07:21:08 -04:00
struct SRange {
double start = 0 ;
double end = 0 ;
} ;
SRange sourceX = { sourcePos . x , sourcePos . x + sourceSize . x } ;
SRange sourceY = { sourcePos . y , sourcePos . y + sourceSize . y } ;
2024-10-27 23:39:52 +00:00
2024-10-21 11:08:25 -04:00
if ( * SNAPWINDOWGAP ) {
2025-01-06 11:37:13 -05:00
const double GAPSIZE = * SNAPWINDOWGAP ;
const auto WSID = DRAGGINGWINDOW - > workspaceID ( ) ;
2025-04-28 22:25:22 +02:00
const bool HASFULLSCREEN = DRAGGINGWINDOW - > m_workspace & & DRAGGINGWINDOW - > m_workspace - > m_hasFullscreenWindow ;
2024-10-21 11:08:25 -04:00
2025-04-22 15:23:29 +02:00
for ( auto & other : g_pCompositor - > m_windows ) {
2025-04-28 22:25:22 +02:00
if ( ( HASFULLSCREEN & & ! other - > m_createdOverFullscreen ) | | other = = DRAGGINGWINDOW | | other - > workspaceID ( ) ! = WSID | | ! other - > m_isMapped | | other - > m_fadingOut | |
2025-01-06 11:37:13 -05:00
other - > isX11OverrideRedirect ( ) )
2024-10-21 11:08:25 -04:00
continue ;
2024-10-31 07:21:08 -04:00
const int OTHERBORDERSIZE = other - > getRealBorderSize ( ) ;
const double BORDERSIZE = OVERLAP ? std : : max ( DRAGGINGBORDERSIZE , OTHERBORDERSIZE ) : ( DRAGGINGBORDERSIZE + OTHERBORDERSIZE ) ;
2024-10-21 11:08:25 -04:00
2024-10-31 07:21:08 -04:00
const CBox SURF = other - > getWindowMainSurfaceBox ( ) ;
const SRange SURFBX = { SURF . x - BORDERSIZE , SURF . x + SURF . w + BORDERSIZE } ;
const SRange SURFBY = { SURF . y - BORDERSIZE , SURF . y + SURF . h + BORDERSIZE } ;
2024-10-21 11:08:25 -04:00
2024-10-31 07:21:08 -04:00
// only snap windows if their ranges overlap in the opposite axis
if ( sourceY . start < = SURFBY . end & & SURFBY . start < = sourceY . end ) {
if ( CORNER & ( CORNER_TOPLEFT | CORNER_BOTTOMLEFT ) & & canSnap ( sourceX . start , SURFBX . end , GAPSIZE ) ) {
SNAP ( sourceX . start , sourceX . end , SURFBX . end ) ;
2024-10-21 11:08:25 -04:00
snaps | = SNAP_LEFT ;
2024-10-31 07:21:08 -04:00
} else if ( CORNER & ( CORNER_TOPRIGHT | CORNER_BOTTOMRIGHT ) & & canSnap ( sourceX . end , SURFBX . start , GAPSIZE ) ) {
SNAP ( sourceX . end , sourceX . start , SURFBX . start ) ;
2024-10-21 11:08:25 -04:00
snaps | = SNAP_RIGHT ;
}
}
2024-10-31 07:21:08 -04:00
if ( sourceX . start < = SURFBX . end & & SURFBX . start < = sourceX . end ) {
if ( CORNER & ( CORNER_TOPLEFT | CORNER_TOPRIGHT ) & & canSnap ( sourceY . start , SURFBY . end , GAPSIZE ) ) {
SNAP ( sourceY . start , sourceY . end , SURFBY . end ) ;
2024-10-21 11:08:25 -04:00
snaps | = SNAP_UP ;
2024-10-31 07:21:08 -04:00
} else if ( CORNER & ( CORNER_BOTTOMLEFT | CORNER_BOTTOMRIGHT ) & & canSnap ( sourceY . end , SURFBY . start , GAPSIZE ) ) {
SNAP ( sourceY . end , sourceY . start , SURFBY . start ) ;
2024-10-21 11:08:25 -04:00
snaps | = SNAP_DOWN ;
}
}
// corner snapping
2024-10-31 07:21:08 -04:00
const double BORDERDIFF = OTHERBORDERSIZE - DRAGGINGBORDERSIZE ;
2024-12-27 16:49:45 -05:00
if ( sourceX . start = = SURFBX . end | | SURFBX . start = = sourceX . end ) {
2024-10-31 07:21:08 -04:00
const SRange SURFY = { SURF . y - BORDERDIFF , SURF . y + SURF . h + BORDERDIFF } ;
2024-12-29 06:18:14 -05:00
if ( CORNER & ( CORNER_TOPLEFT | CORNER_TOPRIGHT ) & & ! ( snaps & SNAP_UP ) & & canSnap ( sourceY . start , SURFY . start , GAPSIZE ) ) {
2024-10-31 07:21:08 -04:00
SNAP ( sourceY . start , sourceY . end , SURFY . start ) ;
2024-10-21 11:08:25 -04:00
snaps | = SNAP_UP ;
2024-12-29 06:18:14 -05:00
} else if ( CORNER & ( CORNER_BOTTOMLEFT | CORNER_BOTTOMRIGHT ) & & ! ( snaps & SNAP_DOWN ) & & canSnap ( sourceY . end , SURFY . end , GAPSIZE ) ) {
2024-10-31 07:21:08 -04:00
SNAP ( sourceY . end , sourceY . start , SURFY . end ) ;
2024-10-21 11:08:25 -04:00
snaps | = SNAP_DOWN ;
}
}
2024-12-27 16:49:45 -05:00
if ( sourceY . start = = SURFBY . end | | SURFBY . start = = sourceY . end ) {
2024-10-31 07:21:08 -04:00
const SRange SURFX = { SURF . x - BORDERDIFF , SURF . x + SURF . w + BORDERDIFF } ;
2024-12-29 06:18:14 -05:00
if ( CORNER & ( CORNER_TOPLEFT | CORNER_BOTTOMLEFT ) & & ! ( snaps & SNAP_LEFT ) & & canSnap ( sourceX . start , SURFX . start , GAPSIZE ) ) {
2024-10-31 07:21:08 -04:00
SNAP ( sourceX . start , sourceX . end , SURFX . start ) ;
2024-10-21 11:08:25 -04:00
snaps | = SNAP_LEFT ;
2024-12-29 06:18:14 -05:00
} else if ( CORNER & ( CORNER_TOPRIGHT | CORNER_BOTTOMRIGHT ) & & ! ( snaps & SNAP_RIGHT ) & & canSnap ( sourceX . end , SURFX . end , GAPSIZE ) ) {
2024-10-31 07:21:08 -04:00
SNAP ( sourceX . end , sourceX . start , SURFX . end ) ;
2024-10-21 11:08:25 -04:00
snaps | = SNAP_RIGHT ;
}
}
}
}
if ( * SNAPMONITORGAP ) {
2024-10-31 07:21:08 -04:00
const double GAPSIZE = * SNAPMONITORGAP ;
2024-12-13 11:34:04 -05:00
const double BORDERDIFF = OVERLAP ? DRAGGINGBORDERSIZE : 0 ;
2025-04-28 22:25:22 +02:00
const auto MON = DRAGGINGWINDOW - > m_monitor . lock ( ) ;
2024-10-31 07:21:08 -04:00
2025-04-30 23:45:20 +02:00
SRange monX = { MON - > m_position . x + MON - > m_reservedTopLeft . x + DRAGGINGBORDERSIZE , MON - > m_position . x + MON - > m_size . x - MON - > m_reservedBottomRight . x - DRAGGINGBORDERSIZE } ;
SRange monY = { MON - > m_position . y + MON - > m_reservedTopLeft . y + DRAGGINGBORDERSIZE , MON - > m_position . y + MON - > m_size . y - MON - > m_reservedBottomRight . y - DRAGGINGBORDERSIZE } ;
2024-10-31 07:21:08 -04:00
2024-12-04 13:12:04 -05:00
if ( CORNER & ( CORNER_TOPLEFT | CORNER_BOTTOMLEFT ) & &
2025-04-30 23:45:20 +02:00
( ( MON - > m_reservedTopLeft . x > 0 & & canSnap ( sourceX . start , monX . start , GAPSIZE ) ) | |
canSnap ( sourceX . start , ( monX . start - = MON - > m_reservedTopLeft . x + BORDERDIFF ) , GAPSIZE ) ) ) {
2024-10-31 07:21:08 -04:00
SNAP ( sourceX . start , sourceX . end , monX . start ) ;
2024-10-21 11:08:25 -04:00
snaps | = SNAP_LEFT ;
}
2024-12-04 13:12:04 -05:00
if ( CORNER & ( CORNER_TOPRIGHT | CORNER_BOTTOMRIGHT ) & &
2025-04-30 23:45:20 +02:00
( ( MON - > m_reservedBottomRight . x > 0 & & canSnap ( sourceX . end , monX . end , GAPSIZE ) ) | |
canSnap ( sourceX . end , ( monX . end + = MON - > m_reservedBottomRight . x + BORDERDIFF ) , GAPSIZE ) ) ) {
2024-10-31 07:21:08 -04:00
SNAP ( sourceX . end , sourceX . start , monX . end ) ;
2024-10-21 11:08:25 -04:00
snaps | = SNAP_RIGHT ;
}
2024-12-04 13:12:04 -05:00
if ( CORNER & ( CORNER_TOPLEFT | CORNER_TOPRIGHT ) & &
2025-04-30 23:45:20 +02:00
( ( MON - > m_reservedTopLeft . y > 0 & & canSnap ( sourceY . start , monY . start , GAPSIZE ) ) | |
canSnap ( sourceY . start , ( monY . start - = MON - > m_reservedTopLeft . y + BORDERDIFF ) , GAPSIZE ) ) ) {
2024-10-31 07:21:08 -04:00
SNAP ( sourceY . start , sourceY . end , monY . start ) ;
2024-10-21 11:08:25 -04:00
snaps | = SNAP_UP ;
}
2024-12-04 13:12:04 -05:00
if ( CORNER & ( CORNER_BOTTOMLEFT | CORNER_BOTTOMRIGHT ) & &
2025-04-30 23:45:20 +02:00
( ( MON - > m_reservedBottomRight . y > 0 & & canSnap ( sourceY . end , monY . end , GAPSIZE ) ) | |
canSnap ( sourceY . end , ( monY . end + = MON - > m_reservedBottomRight . y + BORDERDIFF ) , GAPSIZE ) ) ) {
2024-10-31 07:21:08 -04:00
SNAP ( sourceY . end , sourceY . start , monY . end ) ;
2024-10-21 11:08:25 -04:00
snaps | = SNAP_DOWN ;
}
}
2024-10-31 07:21:08 -04:00
if ( MODE = = MBIND_RESIZE_FORCE_RATIO ) {
if ( ( CORNER & ( CORNER_TOPLEFT | CORNER_BOTTOMLEFT ) & & snaps & SNAP_LEFT ) | | ( CORNER & ( CORNER_TOPRIGHT | CORNER_BOTTOMRIGHT ) & & snaps & SNAP_RIGHT ) ) {
const double SIZEY = ( sourceX . end - sourceX . start ) * ( BEGINSIZE . y / BEGINSIZE . x ) ;
if ( CORNER & ( CORNER_TOPLEFT | CORNER_TOPRIGHT ) )
sourceY . start = sourceY . end - SIZEY ;
else
sourceY . end = sourceY . start + SIZEY ;
} else if ( ( CORNER & ( CORNER_TOPLEFT | CORNER_TOPRIGHT ) & & snaps & SNAP_UP ) | | ( CORNER & ( CORNER_BOTTOMLEFT | CORNER_BOTTOMRIGHT ) & & snaps & SNAP_DOWN ) ) {
const double SIZEX = ( sourceY . end - sourceY . start ) * ( BEGINSIZE . x / BEGINSIZE . y ) ;
if ( CORNER & ( CORNER_TOPLEFT | CORNER_BOTTOMLEFT ) )
sourceX . start = sourceX . end - SIZEX ;
else
sourceX . end = sourceX . start + SIZEX ;
2024-10-21 11:08:25 -04:00
}
}
2024-10-27 23:39:52 +00:00
2024-10-31 07:21:08 -04:00
sourcePos = { sourceX . start , sourceY . start } ;
sourceSize = { sourceX . end - sourceX . start , sourceY . end - sourceY . start } ;
2024-10-21 11:08:25 -04:00
}
2022-06-30 12:09:05 +02:00
void IHyprLayout : : onMouseMove ( const Vector2D & mousePos ) {
2025-05-01 23:57:11 +02:00
if ( g_pInputManager - > m_currentlyDraggedWindow . expired ( ) )
2024-07-27 16:46:19 +00:00
return ;
2025-05-01 23:57:11 +02:00
const auto DRAGGINGWINDOW = g_pInputManager - > m_currentlyDraggedWindow . lock ( ) ;
2025-04-12 10:43:13 -04:00
static auto PDRAGTHRESHOLD = CConfigValue < Hyprlang : : INT > ( " binds:drag_threshold " ) ;
2022-06-30 12:09:05 +02:00
// Window invalid or drag begin size 0,0 meaning we rejected it.
2025-05-01 13:27:07 +02:00
if ( ( ! validMapped ( DRAGGINGWINDOW ) | | m_beginDragSizeXY = = Vector2D ( ) ) ) {
2024-07-27 16:46:19 +00:00
g_pKeybindManager - > changeMouseBindMode ( MBIND_INVALID ) ;
2022-06-30 12:09:05 +02:00
return ;
}
2025-04-12 10:43:13 -04:00
// Yoink dragged window here instead if using drag_threshold and it has been reached
2025-05-01 23:57:11 +02:00
if ( * PDRAGTHRESHOLD > 0 & & ! g_pInputManager - > m_dragThresholdReached ) {
2025-05-01 13:27:07 +02:00
if ( ( m_beginDragXY . distanceSq ( mousePos ) < = std : : pow ( * PDRAGTHRESHOLD , 2 ) & & m_beginDragXY = = m_lastDragXY ) )
2025-04-12 10:43:13 -04:00
return ;
2025-05-01 23:57:11 +02:00
g_pInputManager - > m_dragThresholdReached = true ;
2025-04-12 10:43:13 -04:00
if ( updateDragWindow ( ) )
return ;
}
2024-03-06 03:15:44 +03:00
static auto TIMER = std : : chrono : : high_resolution_clock : : now ( ) , MSTIMER = TIMER ;
2022-12-09 17:08:04 +00:00
2024-04-02 20:32:39 +01:00
const auto SPECIAL = DRAGGINGWINDOW - > onSpecialWorkspace ( ) ;
2022-06-30 12:09:05 +02:00
2025-05-01 13:27:07 +02:00
const auto DELTA = Vector2D ( mousePos . x - m_beginDragXY . x , mousePos . y - m_beginDragXY . y ) ;
const auto TICKDELTA = Vector2D ( mousePos . x - m_lastDragXY . x , mousePos . y - m_lastDragXY . y ) ;
2022-08-16 21:56:54 +02:00
2024-03-03 18:39:20 +00:00
static auto PANIMATEMOUSE = CConfigValue < Hyprlang : : INT > ( " misc:animate_mouse_windowdragging " ) ;
static auto PANIMATE = CConfigValue < Hyprlang : : INT > ( " misc:animate_manual_resizes " ) ;
2023-03-04 00:14:20 +00:00
2024-10-21 11:08:25 -04:00
static auto SNAPENABLED = CConfigValue < Hyprlang : : INT > ( " general:snap:enabled " ) ;
2024-03-06 03:15:44 +03:00
const auto TIMERDELTA = std : : chrono : : duration_cast < std : : chrono : : milliseconds > ( std : : chrono : : high_resolution_clock : : now ( ) - TIMER ) . count ( ) ;
const auto MSDELTA = std : : chrono : : duration_cast < std : : chrono : : milliseconds > ( std : : chrono : : high_resolution_clock : : now ( ) - MSTIMER ) . count ( ) ;
2025-05-05 23:44:49 +02:00
const auto MSMONITOR = 1000.0 / g_pHyprRenderer - > m_mostHzMonitor - > m_refreshRate ;
2024-03-06 03:15:44 +03:00
static int totalMs = 0 ;
bool canSkipUpdate = true ;
MSTIMER = std : : chrono : : high_resolution_clock : : now ( ) ;
2025-05-01 13:27:07 +02:00
if ( m_mouseMoveEventCount = = 1 )
2024-03-06 03:15:44 +03:00
totalMs = 0 ;
if ( MSMONITOR > 16.0 ) {
2025-05-01 13:27:07 +02:00
totalMs + = MSDELTA < MSMONITOR ? MSDELTA : std : : round ( totalMs * 1.0 / m_mouseMoveEventCount ) ;
m_mouseMoveEventCount + = 1 ;
2024-03-06 03:15:44 +03:00
// check if time-window is enough to skip update on 60hz monitor
2025-05-01 13:27:07 +02:00
canSkipUpdate = std : : clamp ( MSMONITOR - TIMERDELTA , 0.0 , MSMONITOR ) > totalMs * 1.0 / m_mouseMoveEventCount ;
2024-03-06 03:15:44 +03:00
}
2025-05-01 23:57:11 +02:00
if ( ( abs ( TICKDELTA . x ) < 1.f & & abs ( TICKDELTA . y ) < 1.f ) | | ( TIMERDELTA < MSMONITOR & & canSkipUpdate & & ( g_pInputManager - > m_dragMode ! = MBIND_MOVE | | * PANIMATEMOUSE ) ) )
2022-06-30 12:09:05 +02:00
return ;
2023-03-04 00:14:20 +00:00
TIMER = std : : chrono : : high_resolution_clock : : now ( ) ;
2025-05-01 13:27:07 +02:00
m_lastDragXY = mousePos ;
2022-06-30 12:09:05 +02:00
g_pHyprRenderer - > damageWindow ( DRAGGINGWINDOW ) ;
2025-05-01 23:57:11 +02:00
if ( g_pInputManager - > m_dragMode = = MBIND_MOVE ) {
2022-10-19 21:17:49 +01:00
2025-05-01 13:27:07 +02:00
Vector2D newPos = m_beginDragPositionXY + DELTA ;
2025-04-28 22:25:22 +02:00
Vector2D newSize = DRAGGINGWINDOW - > m_realSize - > goal ( ) ;
2024-10-21 11:08:25 -04:00
2025-04-28 22:25:22 +02:00
if ( * SNAPENABLED & & ! DRAGGINGWINDOW - > m_draggingTiled )
2025-05-01 13:27:07 +02:00
performSnap ( newPos , newSize , DRAGGINGWINDOW , MBIND_MOVE , - 1 , m_beginDragSizeXY ) ;
2024-10-21 11:08:25 -04:00
CBox wb = { newPos , newSize } ;
2023-11-07 20:47:09 +00:00
wb . round ( ) ;
2024-03-03 18:39:20 +00:00
if ( * PANIMATEMOUSE )
2025-04-28 22:25:22 +02:00
* DRAGGINGWINDOW - > m_realPosition = wb . pos ( ) ;
2025-02-06 11:21:04 +00:00
else {
2025-04-28 22:25:22 +02:00
DRAGGINGWINDOW - > m_realPosition - > setValueAndWarp ( wb . pos ( ) ) ;
2025-02-06 11:21:04 +00:00
DRAGGINGWINDOW - > sendWindowSize ( ) ;
}
2022-06-30 12:09:05 +02:00
2025-04-28 22:25:22 +02:00
DRAGGINGWINDOW - > m_position = wb . pos ( ) ;
2025-04-06 23:41:27 +02:00
2025-05-01 23:57:11 +02:00
} else if ( g_pInputManager - > m_dragMode = = MBIND_RESIZE | | g_pInputManager - > m_dragMode = = MBIND_RESIZE_FORCE_RATIO | | g_pInputManager - > m_dragMode = = MBIND_RESIZE_BLOCK_RATIO ) {
2025-04-28 22:25:22 +02:00
if ( DRAGGINGWINDOW - > m_isFloating ) {
2022-08-05 17:58:08 +02:00
2025-04-28 22:25:22 +02:00
Vector2D MINSIZE = DRAGGINGWINDOW - > requestedMinSize ( ) . clamp ( DRAGGINGWINDOW - > m_windowData . minSize . valueOr ( Vector2D ( MIN_WINDOW_SIZE , MIN_WINDOW_SIZE ) ) ) ;
2024-07-11 14:10:42 +00:00
Vector2D MAXSIZE ;
2025-04-28 22:25:22 +02:00
if ( DRAGGINGWINDOW - > m_windowData . maxSize . hasValue ( ) )
MAXSIZE = DRAGGINGWINDOW - > requestedMaxSize ( ) . clamp ( { } , DRAGGINGWINDOW - > m_windowData . maxSize . value ( ) ) ;
2024-07-11 14:10:42 +00:00
else
2024-11-17 19:31:54 +00:00
MAXSIZE = DRAGGINGWINDOW - > requestedMaxSize ( ) . clamp ( { } , Vector2D ( std : : numeric_limits < double > : : max ( ) , std : : numeric_limits < double > : : max ( ) ) ) ;
2022-10-03 22:41:05 +01:00
2025-05-01 13:27:07 +02:00
Vector2D newSize = m_beginDragSizeXY ;
Vector2D newPos = m_beginDragPositionXY ;
2022-10-03 22:41:05 +01:00
2025-05-01 13:27:07 +02:00
if ( m_grabbedCorner = = CORNER_BOTTOMRIGHT )
2023-08-08 16:52:20 +00:00
newSize = newSize + DELTA ;
2025-05-01 13:27:07 +02:00
else if ( m_grabbedCorner = = CORNER_TOPLEFT )
2023-08-08 16:52:20 +00:00
newSize = newSize - DELTA ;
2025-05-01 13:27:07 +02:00
else if ( m_grabbedCorner = = CORNER_TOPRIGHT )
2023-08-08 16:52:20 +00:00
newSize = newSize + Vector2D ( DELTA . x , - DELTA . y ) ;
2025-05-01 13:27:07 +02:00
else if ( m_grabbedCorner = = CORNER_BOTTOMLEFT )
2023-08-08 16:52:20 +00:00
newSize = newSize + Vector2D ( - DELTA . x , DELTA . y ) ;
2025-05-01 23:57:11 +02:00
eMouseBindMode mode = g_pInputManager - > m_dragMode ;
2025-04-28 22:25:22 +02:00
if ( DRAGGINGWINDOW - > m_windowData . keepAspectRatio . valueOrDefault ( ) & & mode ! = MBIND_RESIZE_BLOCK_RATIO )
2024-10-21 11:08:25 -04:00
mode = MBIND_RESIZE_FORCE_RATIO ;
2025-05-01 13:27:07 +02:00
if ( m_beginDragSizeXY . x > = 1 & & m_beginDragSizeXY . y > = 1 & & mode = = MBIND_RESIZE_FORCE_RATIO ) {
2023-08-08 16:52:20 +00:00
2025-05-01 13:27:07 +02:00
const float RATIO = m_beginDragSizeXY . y / m_beginDragSizeXY . x ;
2023-08-08 16:52:20 +00:00
if ( MINSIZE . x * RATIO > MINSIZE . y )
MINSIZE = Vector2D ( MINSIZE . x , MINSIZE . x * RATIO ) ;
else
MINSIZE = Vector2D ( MINSIZE . y / RATIO , MINSIZE . y ) ;
if ( MAXSIZE . x * RATIO < MAXSIZE . y )
MAXSIZE = Vector2D ( MAXSIZE . x , MAXSIZE . x * RATIO ) ;
else
MAXSIZE = Vector2D ( MAXSIZE . y / RATIO , MAXSIZE . y ) ;
if ( newSize . x * RATIO > newSize . y )
newSize = Vector2D ( newSize . x , newSize . x * RATIO ) ;
else
newSize = Vector2D ( newSize . y / RATIO , newSize . y ) ;
2022-10-03 22:41:05 +01:00
}
2023-08-08 16:52:20 +00:00
newSize = newSize . clamp ( MINSIZE , MAXSIZE ) ;
2025-05-01 13:27:07 +02:00
if ( m_grabbedCorner = = CORNER_TOPLEFT )
newPos = newPos - newSize + m_beginDragSizeXY ;
else if ( m_grabbedCorner = = CORNER_TOPRIGHT )
newPos = newPos + Vector2D ( 0.0 , ( m_beginDragSizeXY - newSize ) . y ) ;
else if ( m_grabbedCorner = = CORNER_BOTTOMLEFT )
newPos = newPos + Vector2D ( ( m_beginDragSizeXY - newSize ) . x , 0.0 ) ;
2023-08-08 16:52:20 +00:00
2024-10-21 11:08:25 -04:00
if ( * SNAPENABLED ) {
2025-05-01 13:27:07 +02:00
performSnap ( newPos , newSize , DRAGGINGWINDOW , mode , m_grabbedCorner , m_beginDragSizeXY ) ;
2024-10-21 11:08:25 -04:00
newSize = newSize . clamp ( MINSIZE , MAXSIZE ) ;
}
2023-11-06 17:00:37 +00:00
CBox wb = { newPos , newSize } ;
wb . round ( ) ;
2024-03-03 18:39:20 +00:00
if ( * PANIMATE ) {
2025-04-28 22:25:22 +02:00
* DRAGGINGWINDOW - > m_realSize = wb . size ( ) ;
* DRAGGINGWINDOW - > m_realPosition = wb . pos ( ) ;
2022-08-16 21:56:54 +02:00
} else {
2025-04-28 22:25:22 +02:00
DRAGGINGWINDOW - > m_realSize - > setValueAndWarp ( wb . size ( ) ) ;
DRAGGINGWINDOW - > m_realPosition - > setValueAndWarp ( wb . pos ( ) ) ;
2025-02-06 11:21:04 +00:00
DRAGGINGWINDOW - > sendWindowSize ( ) ;
2022-08-16 21:56:54 +02:00
}
2025-04-06 23:41:27 +02:00
2025-04-28 22:25:22 +02:00
DRAGGINGWINDOW - > m_position = wb . pos ( ) ;
DRAGGINGWINDOW - > m_size = wb . size ( ) ;
2022-06-30 12:09:05 +02:00
} else {
2025-05-01 13:27:07 +02:00
resizeActiveWindow ( TICKDELTA , m_grabbedCorner , DRAGGINGWINDOW ) ;
2022-06-30 12:09:05 +02:00
}
}
// get middle point
2025-04-28 22:25:22 +02:00
Vector2D middle = DRAGGINGWINDOW - > m_realPosition - > value ( ) + DRAGGINGWINDOW - > m_realSize - > value ( ) / 2.f ;
2022-06-30 12:09:05 +02:00
// and check its monitor
const auto PMONITOR = g_pCompositor - > getMonitorFromVector ( middle ) ;
2022-12-09 17:08:04 +00:00
if ( PMONITOR & & ! SPECIAL ) {
2025-04-28 22:25:22 +02:00
DRAGGINGWINDOW - > m_monitor = PMONITOR ;
2025-04-30 23:45:20 +02:00
DRAGGINGWINDOW - > moveToWorkspace ( PMONITOR - > m_activeWorkspace ) ;
2023-03-18 16:30:29 +00:00
DRAGGINGWINDOW - > updateGroupOutputs ( ) ;
2022-09-25 20:07:48 +02:00
2022-08-06 20:57:38 +02:00
DRAGGINGWINDOW - > updateToplevel ( ) ;
2022-06-30 12:09:05 +02:00
}
2022-08-05 19:23:53 +02:00
DRAGGINGWINDOW - > updateWindowDecos ( ) ;
2022-06-30 12:09:05 +02:00
g_pHyprRenderer - > damageWindow ( DRAGGINGWINDOW ) ;
}
2024-04-27 12:43:12 +01:00
void IHyprLayout : : changeWindowFloatingMode ( PHLWINDOW pWindow ) {
2022-06-30 12:09:05 +02:00
2024-07-31 17:55:52 +00:00
if ( pWindow - > isFullscreen ( ) ) {
2023-08-28 22:55:52 +02:00
Debug : : log ( LOG , " changeWindowFloatingMode: fullscreen " ) ;
2024-07-31 17:55:52 +00:00
g_pCompositor - > setWindowFullscreenInternal ( pWindow , FSMODE_NONE ) ;
2022-06-30 12:09:05 +02:00
}
2025-04-28 22:25:22 +02:00
pWindow - > m_pinned = false ;
2022-09-10 13:11:02 +02:00
2025-01-24 17:51:11 +00:00
g_pHyprRenderer - > damageWindow ( pWindow , true ) ;
2025-01-23 22:15:09 +00:00
2022-06-30 12:09:05 +02:00
const auto TILED = isWindowTiled ( pWindow ) ;
2022-12-09 18:51:44 +00:00
// event
2024-04-27 12:43:12 +01:00
g_pEventManager - > postEvent ( SHyprIPCEvent { " changefloatingmode " , std : : format ( " {:x},{} " , ( uintptr_t ) pWindow . get ( ) , ( int ) TILED ) } ) ;
2023-02-19 20:54:53 +00:00
EMIT_HOOK_EVENT ( " changeFloatingMode " , pWindow ) ;
2022-12-09 18:51:44 +00:00
2022-06-30 12:09:05 +02:00
if ( ! TILED ) {
2025-04-28 22:25:22 +02:00
const auto PNEWMON = g_pCompositor - > getMonitorFromVector ( pWindow - > m_realPosition - > value ( ) + pWindow - > m_realSize - > value ( ) / 2.f ) ;
pWindow - > m_monitor = PNEWMON ;
2025-04-30 23:45:20 +02:00
pWindow - > moveToWorkspace ( PNEWMON - > m_activeSpecialWorkspace ? PNEWMON - > m_activeSpecialWorkspace : PNEWMON - > m_activeWorkspace ) ;
2023-03-18 16:30:29 +00:00
pWindow - > updateGroupOutputs ( ) ;
2022-06-30 12:09:05 +02:00
2025-04-30 23:45:20 +02:00
const auto PWORKSPACE = PNEWMON - > m_activeSpecialWorkspace ? PNEWMON - > m_activeSpecialWorkspace : PNEWMON - > m_activeWorkspace ;
2024-03-10 22:31:49 +00:00
2025-04-25 02:37:12 +02:00
if ( PWORKSPACE - > m_hasFullscreenWindow )
2024-11-22 16:01:02 +00:00
g_pCompositor - > setWindowFullscreenInternal ( PWORKSPACE - > getFullscreenWindow ( ) , FSMODE_NONE ) ;
2024-03-10 22:31:49 +00:00
2022-06-30 12:09:05 +02:00
// save real pos cuz the func applies the default 5,5 mid
2025-04-28 22:25:22 +02:00
const auto PSAVEDPOS = pWindow - > m_realPosition - > goal ( ) ;
const auto PSAVEDSIZE = pWindow - > m_realSize - > goal ( ) ;
2022-06-30 12:09:05 +02:00
// if the window is pseudo, update its size
2025-04-28 22:25:22 +02:00
if ( ! pWindow - > m_draggingTiled )
pWindow - > m_pseudoSize = pWindow - > m_realSize - > goal ( ) ;
2022-06-30 12:09:05 +02:00
2025-04-28 22:25:22 +02:00
pWindow - > m_lastFloatingSize = PSAVEDSIZE ;
2022-08-05 17:52:14 +02:00
2024-10-08 12:20:41 +02:00
// move to narnia because we don't wanna find our own node. onWindowCreatedTiling should apply the coords back.
2025-04-28 22:25:22 +02:00
pWindow - > m_position = Vector2D ( - 999999 , - 999999 ) ;
2022-10-19 21:32:30 +01:00
2024-10-08 12:20:41 +02:00
onWindowCreatedTiling ( pWindow ) ;
2022-06-30 12:09:05 +02:00
2025-04-28 22:25:22 +02:00
pWindow - > m_realPosition - > setValue ( PSAVEDPOS ) ;
pWindow - > m_realSize - > setValue ( PSAVEDSIZE ) ;
2022-06-30 12:09:05 +02:00
// fix pseudo leaving artifacts
2025-04-28 22:25:22 +02:00
g_pHyprRenderer - > damageMonitor ( pWindow - > m_monitor . lock ( ) ) ;
2022-10-24 12:25:36 +01:00
2025-04-22 15:23:29 +02:00
if ( pWindow = = g_pCompositor - > m_lastWindow )
2025-05-01 13:27:07 +02:00
m_lastTiledWindow = pWindow ;
2022-06-30 12:09:05 +02:00
} else {
onWindowRemovedTiling ( pWindow ) ;
2023-09-21 17:18:26 -04:00
g_pCompositor - > changeWindowZOrder ( pWindow , true ) ;
2022-07-08 21:52:52 +02:00
2025-04-28 22:25:22 +02:00
CBox wb = { pWindow - > m_realPosition - > goal ( ) + ( pWindow - > m_realSize - > goal ( ) - pWindow - > m_lastFloatingSize ) / 2.f , pWindow - > m_lastFloatingSize } ;
2024-01-10 18:08:58 +01:00
wb . round ( ) ;
2025-04-28 22:25:22 +02:00
if ( ! ( pWindow - > m_isFloating & & pWindow - > m_isPseudotiled ) & & DELTALESSTHAN ( pWindow - > m_realSize - > value ( ) . x , pWindow - > m_lastFloatingSize . x , 10 ) & &
DELTALESSTHAN ( pWindow - > m_realSize - > value ( ) . y , pWindow - > m_lastFloatingSize . y , 10 ) ) {
2024-01-10 18:08:58 +01:00
wb = { wb . pos ( ) + Vector2D { 10 , 10 } , wb . size ( ) - Vector2D { 20 , 20 } } ;
2023-04-06 19:45:59 +01:00
}
2025-04-28 22:25:22 +02:00
* pWindow - > m_realPosition = wb . pos ( ) ;
* pWindow - > m_realSize = wb . size ( ) ;
2022-07-08 21:52:52 +02:00
2025-04-28 22:25:22 +02:00
pWindow - > m_size = wb . size ( ) ;
pWindow - > m_position = wb . pos ( ) ;
2022-11-09 22:01:53 +00:00
2025-04-28 22:25:22 +02:00
g_pHyprRenderer - > damageMonitor ( pWindow - > m_monitor . lock ( ) ) ;
2022-08-05 18:08:23 +02:00
2024-07-11 14:10:42 +00:00
pWindow - > unsetWindowData ( PRIORITY_LAYOUT ) ;
2024-07-15 09:57:52 +00:00
pWindow - > updateWindowData ( ) ;
2022-10-24 12:25:36 +01:00
2025-05-01 13:27:07 +02:00
if ( pWindow = = m_lastTiledWindow )
m_lastTiledWindow . reset ( ) ;
2022-06-30 12:09:05 +02:00
}
2022-08-06 20:57:38 +02:00
2022-08-11 19:29:39 +02:00
g_pCompositor - > updateWindowAnimatedDecorationValues ( pWindow ) ;
2022-08-06 20:57:38 +02:00
pWindow - > updateToplevel ( ) ;
2025-01-23 22:15:09 +00:00
g_pHyprRenderer - > damageWindow ( pWindow ) ;
2022-06-30 12:09:05 +02:00
}
2024-04-27 12:43:12 +01:00
void IHyprLayout : : moveActiveWindow ( const Vector2D & delta , PHLWINDOW pWindow ) {
2025-04-22 15:23:29 +02:00
const auto PWINDOW = pWindow ? pWindow : g_pCompositor - > m_lastWindow . lock ( ) ;
2022-06-30 12:09:05 +02:00
2024-04-27 12:43:12 +01:00
if ( ! validMapped ( PWINDOW ) )
2022-06-30 12:09:05 +02:00
return ;
2025-04-28 22:25:22 +02:00
if ( ! PWINDOW - > m_isFloating ) {
2022-06-30 12:09:05 +02:00
Debug : : log ( LOG , " Dwindle cannot move a tiled window in moveActiveWindow! " ) ;
return ;
}
2024-03-18 19:52:52 -07:00
PWINDOW - > setAnimationsToMove ( ) ;
2025-04-28 22:25:22 +02:00
PWINDOW - > m_position + = delta ;
* PWINDOW - > m_realPosition = PWINDOW - > m_realPosition - > goal ( ) + delta ;
2022-06-30 12:09:05 +02:00
g_pHyprRenderer - > damageWindow ( PWINDOW ) ;
2022-09-25 20:07:48 +02:00
}
2022-10-24 12:25:36 +01:00
2024-04-27 12:43:12 +01:00
void IHyprLayout : : onWindowFocusChange ( PHLWINDOW pNewFocus ) {
2025-05-01 13:27:07 +02:00
m_lastTiledWindow = pNewFocus & & ! pNewFocus - > m_isFloating ? pNewFocus : m_lastTiledWindow ;
2022-10-24 12:25:36 +01:00
}
2024-04-27 12:43:12 +01:00
PHLWINDOW IHyprLayout : : getNextWindowCandidate ( PHLWINDOW pWindow ) {
2022-10-24 12:25:36 +01:00
// although we don't expect nullptrs here, let's verify jic
if ( ! pWindow )
return nullptr ;
2025-04-28 22:25:22 +02:00
const auto PWORKSPACE = pWindow - > m_workspace ;
2022-10-24 12:25:36 +01:00
// first of all, if this is a fullscreen workspace,
2025-04-25 02:37:12 +02:00
if ( PWORKSPACE - > m_hasFullscreenWindow )
2024-11-22 16:01:02 +00:00
return PWORKSPACE - > getFullscreenWindow ( ) ;
2022-10-24 12:25:36 +01:00
2025-04-28 22:25:22 +02:00
if ( pWindow - > m_isFloating ) {
2022-10-24 12:25:36 +01:00
2022-11-27 12:11:45 +00:00
// find whether there is a floating window below this one
2025-04-22 15:23:29 +02:00
for ( auto const & w : g_pCompositor - > m_windows ) {
2025-04-28 22:25:22 +02:00
if ( w - > m_isMapped & & ! w - > isHidden ( ) & & w - > m_isFloating & & ! w - > isX11OverrideRedirect ( ) & & w - > m_workspace = = pWindow - > m_workspace & & ! w - > m_X11ShouldntFocus & &
! w - > m_windowData . noFocus . valueOrDefault ( ) & & w ! = pWindow ) {
if ( VECINRECT ( ( pWindow - > m_size / 2.f + pWindow - > m_position ) , w - > m_position . x , w - > m_position . y , w - > m_position . x + w - > m_size . x , w - > m_position . y + w - > m_size . y ) ) {
2024-04-27 12:43:12 +01:00
return w ;
2022-11-27 12:11:45 +00:00
}
}
}
// let's try the last tiled window.
2025-05-01 13:27:07 +02:00
if ( m_lastTiledWindow . lock ( ) & & m_lastTiledWindow - > m_workspace = = pWindow - > m_workspace )
return m_lastTiledWindow . lock ( ) ;
2022-10-24 12:25:36 +01:00
// if we don't, let's try to find any window that is in the middle
2024-02-04 15:40:20 +00:00
if ( const auto PWINDOWCANDIDATE = g_pCompositor - > vectorToWindowUnified ( pWindow - > middle ( ) , RESERVED_EXTENTS | INPUT_EXTENTS | ALLOW_FLOATING ) ;
PWINDOWCANDIDATE & & PWINDOWCANDIDATE ! = pWindow )
2022-10-24 12:25:36 +01:00
return PWINDOWCANDIDATE ;
// if not, floating window
2025-04-22 15:23:29 +02:00
for ( auto const & w : g_pCompositor - > m_windows ) {
2025-04-28 22:25:22 +02:00
if ( w - > m_isMapped & & ! w - > isHidden ( ) & & w - > m_isFloating & & ! w - > isX11OverrideRedirect ( ) & & w - > m_workspace = = pWindow - > m_workspace & & ! w - > m_X11ShouldntFocus & &
! w - > m_windowData . noFocus . valueOrDefault ( ) & & w ! = pWindow )
2024-04-27 12:43:12 +01:00
return w ;
2022-10-24 12:25:36 +01:00
}
// if there is no candidate, too bad
return nullptr ;
}
// if it was a tiled window, we first try to find the window that will replace it.
2024-02-04 15:40:20 +00:00
auto pWindowCandidate = g_pCompositor - > vectorToWindowUnified ( pWindow - > middle ( ) , RESERVED_EXTENTS | INPUT_EXTENTS | ALLOW_FLOATING ) ;
2022-10-24 12:25:36 +01:00
2023-12-12 16:44:31 +00:00
if ( ! pWindowCandidate )
2024-11-22 16:01:02 +00:00
pWindowCandidate = PWORKSPACE - > getTopLeftWindow ( ) ;
2023-12-12 16:44:31 +00:00
if ( ! pWindowCandidate )
2024-11-22 16:01:02 +00:00
pWindowCandidate = PWORKSPACE - > getFirstWindow ( ) ;
2023-12-12 16:44:31 +00:00
2025-04-28 22:25:22 +02:00
if ( ! pWindowCandidate | | pWindow = = pWindowCandidate | | ! pWindowCandidate - > m_isMapped | | pWindowCandidate - > isHidden ( ) | | pWindowCandidate - > m_X11ShouldntFocus | |
pWindowCandidate - > isX11OverrideRedirect ( ) | | pWindowCandidate - > m_monitor ! = g_pCompositor - > m_lastMonitor )
2022-10-24 12:25:36 +01:00
return nullptr ;
2023-12-12 16:44:31 +00:00
return pWindowCandidate ;
2022-10-24 12:25:36 +01:00
}
2022-11-29 03:04:24 +08:00
2024-04-27 12:43:12 +01:00
bool IHyprLayout : : isWindowReachable ( PHLWINDOW pWindow ) {
2025-04-28 22:25:22 +02:00
return pWindow & & ( ! pWindow - > isHidden ( ) | | pWindow - > m_groupData . pNextWindow ) ;
2023-09-12 14:37:08 -07:00
}
2024-04-27 12:43:12 +01:00
void IHyprLayout : : bringWindowToTop ( PHLWINDOW pWindow ) {
2023-09-12 14:37:08 -07:00
if ( pWindow = = nullptr )
return ;
2025-04-28 22:25:22 +02:00
if ( pWindow - > isHidden ( ) & & pWindow - > m_groupData . pNextWindow ) {
2023-07-19 03:39:45 -07:00
// grouped, change the current to this window
pWindow - > setGroupCurrent ( pWindow ) ;
}
2023-09-12 14:37:08 -07:00
}
2023-07-19 03:39:45 -07:00
2024-04-27 12:43:12 +01:00
void IHyprLayout : : requestFocusForWindow ( PHLWINDOW pWindow ) {
2023-09-12 14:37:08 -07:00
bringWindowToTop ( pWindow ) ;
2023-07-19 03:39:45 -07:00
g_pCompositor - > focusWindow ( pWindow ) ;
2024-03-06 01:56:06 +08:00
g_pCompositor - > warpCursorTo ( pWindow - > middle ( ) ) ;
2023-07-19 03:39:45 -07:00
}
2024-04-27 12:43:12 +01:00
Vector2D IHyprLayout : : predictSizeForNewWindowFloating ( PHLWINDOW pWindow ) { // get all rules, see if we have any size overrides.
2024-03-29 00:43:50 +00:00
Vector2D sizeOverride = { } ;
2025-04-22 15:23:29 +02:00
if ( g_pCompositor - > m_lastMonitor ) {
2025-05-06 09:53:43 +08:00
// If `persistentsize` is set, use the stored size if available.
const bool HASPERSISTENTSIZE = std : : ranges : : any_of ( pWindow - > m_matchedRules , [ ] ( const auto & rule ) { return rule - > m_ruleType = = CWindowRule : : RULE_PERSISTENTSIZE ; } ) ;
const auto STOREDSIZE = HASPERSISTENTSIZE ? g_pConfigManager - > getStoredFloatingSize ( pWindow ) : std : : nullopt ;
if ( STOREDSIZE . has_value ( ) ) {
Debug : : log ( LOG , " using stored size {}x{} for new floating window {}::{} " , STOREDSIZE - > x , STOREDSIZE - > y , pWindow - > m_class , pWindow - > m_title ) ;
return STOREDSIZE . value ( ) ;
}
2024-08-26 20:24:30 +02:00
for ( auto const & r : g_pConfigManager - > getMatchingRules ( pWindow , true , true ) ) {
2025-04-28 22:25:22 +02:00
if ( r - > m_ruleType ! = CWindowRule : : RULE_SIZE )
2024-12-16 19:05:24 +01:00
continue ;
2024-10-30 18:58:36 +00:00
2024-12-16 19:05:24 +01:00
try {
2025-04-28 22:25:22 +02:00
const auto VALUE = r - > m_rule . substr ( r - > m_rule . find ( ' ' ) + 1 ) ;
2024-12-16 19:05:24 +01:00
const auto SIZEXSTR = VALUE . substr ( 0 , VALUE . find ( ' ' ) ) ;
const auto SIZEYSTR = VALUE . substr ( VALUE . find ( ' ' ) + 1 ) ;
2024-10-30 18:58:36 +00:00
2024-12-16 19:05:24 +01:00
const auto MAXSIZE = pWindow - > requestedMaxSize ( ) ;
2024-10-30 18:58:36 +00:00
2025-04-30 23:45:20 +02:00
const float SIZEX = SIZEXSTR = = " max " ? std : : clamp ( MAXSIZE . x , MIN_WINDOW_SIZE , g_pCompositor - > m_lastMonitor - > m_size . x ) :
stringToPercentage ( SIZEXSTR , g_pCompositor - > m_lastMonitor - > m_size . x ) ;
2024-03-29 00:43:50 +00:00
2025-04-30 23:45:20 +02:00
const float SIZEY = SIZEYSTR = = " max " ? std : : clamp ( MAXSIZE . y , MIN_WINDOW_SIZE , g_pCompositor - > m_lastMonitor - > m_size . y ) :
stringToPercentage ( SIZEYSTR , g_pCompositor - > m_lastMonitor - > m_size . y ) ;
2024-03-29 00:43:50 +00:00
2024-12-16 19:05:24 +01:00
sizeOverride = { SIZEX , SIZEY } ;
2025-04-28 22:25:22 +02:00
} catch ( . . . ) { Debug : : log ( LOG , " Rule size failed, rule: {} -> {} " , r - > m_rule , r - > m_value ) ; }
2024-12-16 19:05:24 +01:00
break ;
2024-03-29 00:43:50 +00:00
}
}
return sizeOverride ;
}
2024-04-27 12:43:12 +01:00
Vector2D IHyprLayout : : predictSizeForNewWindow ( PHLWINDOW pWindow ) {
2024-03-29 00:43:50 +00:00
bool shouldBeFloated = g_pXWaylandManager - > shouldBeFloated ( pWindow , true ) ;
if ( ! shouldBeFloated ) {
2024-08-26 17:25:39 +02:00
for ( auto const & r : g_pConfigManager - > getMatchingRules ( pWindow , true , true ) ) {
2025-04-28 22:25:22 +02:00
if ( r - > m_ruleType ! = CWindowRule : : RULE_FLOAT )
2024-12-16 19:05:24 +01:00
continue ;
shouldBeFloated = true ;
break ;
2024-03-29 00:43:50 +00:00
}
}
Vector2D sizePredicted = { } ;
if ( ! shouldBeFloated )
sizePredicted = predictSizeForNewWindowTiled ( ) ;
else
sizePredicted = predictSizeForNewWindowFloating ( pWindow ) ;
2025-05-04 23:39:00 +02:00
Vector2D maxSize = pWindow - > m_xdgSurface - > m_toplevel - > m_pending . maxSize ;
2024-03-29 00:43:50 +00:00
if ( ( maxSize . x > 0 & & maxSize . x < sizePredicted . x ) | | ( maxSize . y > 0 & & maxSize . y < sizePredicted . y ) )
sizePredicted = { } ;
return sizePredicted ;
2024-02-28 11:45:43 +00:00
}
2025-04-12 10:43:13 -04:00
bool IHyprLayout : : updateDragWindow ( ) {
2025-05-01 23:57:11 +02:00
const auto DRAGGINGWINDOW = g_pInputManager - > m_currentlyDraggedWindow . lock ( ) ;
2025-04-13 11:32:53 -04:00
const bool WAS_FULLSCREEN = DRAGGINGWINDOW - > isFullscreen ( ) ;
2025-04-12 10:43:13 -04:00
2025-05-01 23:57:11 +02:00
if ( g_pInputManager - > m_dragThresholdReached ) {
2025-04-13 11:32:53 -04:00
if ( WAS_FULLSCREEN ) {
2025-04-12 10:43:13 -04:00
Debug : : log ( LOG , " Dragging a fullscreen window " ) ;
g_pCompositor - > setWindowFullscreenInternal ( DRAGGINGWINDOW , FSMODE_NONE ) ;
}
2025-04-28 22:25:22 +02:00
const auto PWORKSPACE = DRAGGINGWINDOW - > m_workspace ;
2025-04-12 10:43:13 -04:00
2025-05-08 14:59:51 -04:00
if ( PWORKSPACE - > m_hasFullscreenWindow & & ( ! DRAGGINGWINDOW - > m_isFloating | | ( ! DRAGGINGWINDOW - > m_createdOverFullscreen & & ! DRAGGINGWINDOW - > m_pinned ) ) ) {
2025-04-12 10:43:13 -04:00
Debug : : log ( LOG , " Rejecting drag on a fullscreen workspace. (window under fullscreen) " ) ;
g_pKeybindManager - > changeMouseBindMode ( MBIND_INVALID ) ;
return true ;
}
}
2025-05-01 13:27:07 +02:00
DRAGGINGWINDOW - > m_draggingTiled = false ;
m_draggingWindowOriginalFloatSize = DRAGGINGWINDOW - > m_lastFloatingSize ;
2025-04-13 11:32:53 -04:00
2025-04-28 22:25:22 +02:00
if ( WAS_FULLSCREEN & & DRAGGINGWINDOW - > m_isFloating ) {
const auto MOUSECOORDS = g_pInputManager - > getMouseCoordsInternal ( ) ;
* DRAGGINGWINDOW - > m_realPosition = MOUSECOORDS - DRAGGINGWINDOW - > m_realSize - > goal ( ) / 2.f ;
2025-05-01 23:57:11 +02:00
} else if ( ! DRAGGINGWINDOW - > m_isFloating & & g_pInputManager - > m_dragMode = = MBIND_MOVE ) {
2025-04-28 22:25:22 +02:00
Vector2D MINSIZE = DRAGGINGWINDOW - > requestedMinSize ( ) . clamp ( DRAGGINGWINDOW - > m_windowData . minSize . valueOr ( Vector2D ( MIN_WINDOW_SIZE , MIN_WINDOW_SIZE ) ) ) ;
DRAGGINGWINDOW - > m_lastFloatingSize = ( DRAGGINGWINDOW - > m_realSize - > goal ( ) * 0.8489 ) . clamp ( MINSIZE , Vector2D { } ) . floor ( ) ;
* DRAGGINGWINDOW - > m_realPosition = g_pInputManager - > getMouseCoordsInternal ( ) - DRAGGINGWINDOW - > m_realSize - > goal ( ) / 2.f ;
2025-05-01 23:57:11 +02:00
if ( g_pInputManager - > m_dragThresholdReached ) {
2025-04-12 10:43:13 -04:00
changeWindowFloatingMode ( DRAGGINGWINDOW ) ;
2025-04-28 22:25:22 +02:00
DRAGGINGWINDOW - > m_isFloating = true ;
DRAGGINGWINDOW - > m_draggingTiled = true ;
2025-04-12 10:43:13 -04:00
}
}
2025-05-01 13:27:07 +02:00
m_beginDragXY = g_pInputManager - > getMouseCoordsInternal ( ) ;
m_beginDragPositionXY = DRAGGINGWINDOW - > m_realPosition - > goal ( ) ;
m_beginDragSizeXY = DRAGGINGWINDOW - > m_realSize - > goal ( ) ;
m_lastDragXY = m_beginDragXY ;
2025-04-12 10:43:13 -04:00
return false ;
}