2021-11-18 18:04:09 +01:00
# include "windowManager.hpp"
# include "./events/events.hpp"
2021-11-21 17:40:02 +01:00
# include <string.h>
2021-11-18 18:04:09 +01:00
2021-11-21 11:25:26 +01:00
xcb_visualtype_t * CWindowManager : : setupColors ( ) {
auto depthIter = xcb_screen_allowed_depths_iterator ( Screen ) ;
xcb_visualtype_iterator_t visualIter ;
for ( ; depthIter . rem ; xcb_depth_next ( & depthIter ) ) {
if ( depthIter . data - > depth = = Depth ) {
visualIter = xcb_depth_visuals_iterator ( depthIter . data ) ;
return visualIter . data ;
}
}
return nullptr ;
}
2021-11-21 17:40:02 +01:00
void CWindowManager : : setupRandrMonitors ( ) {
2021-11-22 22:37:01 +01:00
// TODO: this stopped working on my machine for some reason.
// i3 works though...?
// finds 0 monitors
XCBQUERYCHECK ( RANDRVER , xcb_randr_query_version_reply (
2021-11-23 16:24:31 +01:00
DisplayConnection , xcb_randr_query_version ( DisplayConnection , XCB_RANDR_MAJOR_VERSION , XCB_RANDR_MINOR_VERSION ) , & errorRANDRVER ) , " RandR query failed! " ) ;
2021-11-22 22:37:01 +01:00
free ( RANDRVER ) ;
2021-11-23 16:24:31 +01:00
Debug : : log ( LOG , " Setting up RandR! Query: v1.5. " ) ;
XCBQUERYCHECK ( MONITORS , xcb_randr_get_monitors_reply ( DisplayConnection , xcb_randr_get_monitors ( DisplayConnection , Screen - > root , true ) , & errorMONITORS ) , " Couldn't get monitors. " + std : : to_string ( errorMONITORS - > error_code ) ) ;
const auto MONITORNUM = xcb_randr_get_monitors_monitors_length ( MONITORS ) ;
Debug : : log ( LOG , " Found " + std : : to_string ( MONITORNUM ) + " Monitors! " ) ;
if ( MONITORNUM < 1 ) {
// TODO: RandR 1.4 maybe for people with ancient hardware?
Debug : : log ( ERR , " RandR returned an invalid amount of monitors. Falling back to 1 monitor. " ) ;
2021-11-21 17:40:02 +01:00
return ;
}
2021-11-23 16:24:31 +01:00
for ( xcb_randr_monitor_info_iterator_t iterator = xcb_randr_get_monitors_monitors_iterator ( MONITORS ) ; iterator . rem ; xcb_randr_monitor_info_next ( & iterator ) ) {
const auto MONITORINFO = iterator . data ;
// basically an XCBQUERYCHECK but with continue; as its not fatal
xcb_generic_error_t * error ;
const auto ATOMNAME = xcb_get_atom_name_reply ( DisplayConnection , xcb_get_atom_name ( DisplayConnection , MONITORINFO - > name ) , & error ) ;
if ( error ! = NULL ) {
Debug : : log ( ERR , " Failed to get monitor info... " ) ;
free ( error ) ;
free ( ATOMNAME ) ;
continue ;
}
free ( error ) ;
monitors . push_back ( SMonitor ( ) ) ;
const auto NAMELEN = xcb_get_atom_name_name_length ( ATOMNAME ) ;
const auto NAME = xcb_get_atom_name_name ( ATOMNAME ) ;
free ( ATOMNAME ) ;
for ( int j = 0 ; j < NAMELEN ; + + j ) {
monitors [ monitors . size ( ) - 1 ] . szName + = NAME [ j ] ;
}
monitors [ monitors . size ( ) - 1 ] . vecPosition = Vector2D ( MONITORINFO - > x , MONITORINFO - > y ) ;
monitors [ monitors . size ( ) - 1 ] . vecSize = Vector2D ( MONITORINFO - > width , MONITORINFO - > height ) ;
monitors [ monitors . size ( ) - 1 ] . primary = MONITORINFO - > primary ;
monitors [ monitors . size ( ) - 1 ] . ID = monitors . size ( ) - 1 ;
Debug : : log ( NONE , " Monitor " + monitors [ monitors . size ( ) - 1 ] . szName + " : " + std : : to_string ( monitors [ monitors . size ( ) - 1 ] . vecSize . x ) + " x " + std : : to_string ( monitors [ monitors . size ( ) - 1 ] . vecSize . y ) +
" , at " + std : : to_string ( monitors [ monitors . size ( ) - 1 ] . vecPosition . x ) + " , " + std : : to_string ( monitors [ monitors . size ( ) - 1 ] . vecPosition . y ) + " , ID: " + std : : to_string ( monitors [ monitors . size ( ) - 1 ] . ID ) ) ;
}
free ( MONITORS ) ;
2021-11-21 17:40:02 +01:00
const auto EXTENSIONREPLY = xcb_get_extension_data ( DisplayConnection , & xcb_randr_id ) ;
if ( ! EXTENSIONREPLY - > present )
Debug : : log ( ERR , " RandR extension missing " ) ;
else {
//listen for screen change events
xcb_randr_select_input ( DisplayConnection , Screen - > root , XCB_RANDR_NOTIFY_MASK_SCREEN_CHANGE ) ;
}
2021-11-22 22:37:01 +01:00
xcb_flush ( DisplayConnection ) ;
2021-11-21 17:40:02 +01:00
}
2021-11-20 09:25:21 +01:00
void CWindowManager : : setupManager ( ) {
2021-11-24 21:23:14 +01:00
EWMH : : setupInitEWMH ( ) ;
2021-11-21 17:40:02 +01:00
setupRandrMonitors ( ) ;
2021-11-23 16:53:29 +01:00
if ( monitors . size ( ) = = 0 ) {
2021-11-21 17:40:02 +01:00
// RandR failed!
Debug : : log ( WARN , " RandR failed! " ) ;
2021-11-23 16:51:56 +01:00
# define TESTING_MON_AMOUNT 3
2021-11-22 18:43:55 +01:00
for ( int i = 0 ; i < TESTING_MON_AMOUNT /* Testing on 3 monitors, RandR shouldnt fail on a real desktop */ ; + + i ) {
monitors . push_back ( SMonitor ( ) ) ;
monitors [ i ] . vecPosition = Vector2D ( i * Screen - > width_in_pixels / TESTING_MON_AMOUNT , 0 ) ;
monitors [ i ] . vecSize = Vector2D ( Screen - > width_in_pixels / TESTING_MON_AMOUNT , Screen - > height_in_pixels ) ;
monitors [ i ] . ID = i ;
monitors [ i ] . szName = " Screen " + std : : to_string ( i ) ;
}
2021-11-21 17:40:02 +01:00
}
2021-11-21 19:59:59 +01:00
Debug : : log ( LOG , " RandR done. " ) ;
2021-11-19 20:20:05 +01:00
2021-11-20 09:25:21 +01:00
Values [ 0 ] = XCB_EVENT_MASK_SUBSTRUCTURE_REDIRECT | XCB_EVENT_MASK_STRUCTURE_NOTIFY | XCB_EVENT_MASK_SUBSTRUCTURE_NOTIFY | XCB_EVENT_MASK_PROPERTY_CHANGE ;
xcb_change_window_attributes_checked ( DisplayConnection , Screen - > root ,
XCB_CW_EVENT_MASK , Values ) ;
2021-11-19 20:20:05 +01:00
2021-11-23 16:49:53 +01:00
ConfigManager : : init ( ) ;
2021-11-21 19:59:59 +01:00
Debug : : log ( LOG , " Keys done. " ) ;
2021-11-20 10:04:14 +01:00
2021-11-21 17:40:02 +01:00
// Add workspaces to the monitors
2021-11-22 18:43:55 +01:00
for ( long unsigned int i = 0 ; i < monitors . size ( ) ; + + i ) {
2021-11-21 17:40:02 +01:00
CWorkspace protoWorkspace ;
protoWorkspace . setID ( i + 1 ) ;
protoWorkspace . setMonitor ( i ) ;
2021-11-21 19:59:59 +01:00
protoWorkspace . setHasFullscreenWindow ( false ) ;
2021-11-21 17:40:02 +01:00
workspaces . push_back ( protoWorkspace ) ;
2021-11-21 19:59:59 +01:00
activeWorkspaces . push_back ( workspaces [ i ] . getID ( ) ) ;
2021-11-21 17:40:02 +01:00
}
2021-11-21 19:59:59 +01:00
Debug : : log ( LOG , " Workspace protos done. " ) ;
2021-11-20 10:04:14 +01:00
//
2021-11-21 11:25:26 +01:00
// init visual type, default 32 bit depth
// TODO: fix this, ugh
Depth = 24 ; //32
VisualType = setupColors ( ) ;
if ( VisualType = = NULL ) {
Depth = 24 ;
VisualType = setupColors ( ) ;
}
// ---- INIT THE BAR ---- //
2021-11-21 17:40:02 +01:00
for ( auto & monitor : monitors ) {
if ( monitor . primary ) {
2021-11-21 20:40:22 +01:00
statusBar . setup ( ConfigManager : : configValues [ " bar_monitor " ] . intValue ) ;
2021-11-21 17:40:02 +01:00
}
}
2021-11-21 11:25:26 +01:00
2021-11-21 22:24:38 +01:00
// Update bar info
updateBarInfo ( ) ;
2021-11-21 11:25:26 +01:00
// start its' update thread
2021-11-23 18:48:03 +01:00
Events : : setThread ( ) ;
2021-11-21 19:59:59 +01:00
Debug : : log ( LOG , " Bar done. " ) ;
ConfigManager : : loadConfigLoadVars ( ) ;
Debug : : log ( LOG , " Finished setup! " ) ;
2021-11-23 22:15:36 +01:00
// TODO: EWMH
2021-11-18 18:04:09 +01:00
}
2021-11-20 09:25:21 +01:00
bool CWindowManager : : handleEvent ( ) {
if ( xcb_connection_has_error ( DisplayConnection ) )
2021-11-18 18:04:09 +01:00
return false ;
2021-11-21 11:25:26 +01:00
xcb_flush ( DisplayConnection ) ;
2021-11-20 09:25:21 +01:00
const auto ev = xcb_wait_for_event ( DisplayConnection ) ;
2021-11-18 18:04:09 +01:00
if ( ev ! = NULL ) {
2021-11-23 18:48:03 +01:00
while ( animationUtilBusy ) {
; // wait for it to finish
}
// Set thread state, halt animations until done.
mainThreadBusy = true ;
2021-11-18 18:04:09 +01:00
switch ( ev - > response_type & ~ 0x80 ) {
case XCB_ENTER_NOTIFY :
Events : : eventEnter ( ev ) ;
Debug : : log ( LOG , " Event dispatched ENTER " ) ;
break ;
2021-11-18 22:08:28 +01:00
case XCB_LEAVE_NOTIFY :
Events : : eventLeave ( ev ) ;
Debug : : log ( LOG , " Event dispatched LEAVE " ) ;
break ;
2021-11-18 18:04:09 +01:00
case XCB_DESTROY_NOTIFY :
Events : : eventDestroy ( ev ) ;
Debug : : log ( LOG , " Event dispatched DESTROY " ) ;
break ;
case XCB_MAP_REQUEST :
Events : : eventMapWindow ( ev ) ;
Debug : : log ( LOG , " Event dispatched MAP " ) ;
break ;
2021-11-19 20:20:05 +01:00
case XCB_BUTTON_PRESS :
2021-11-22 21:20:32 +01:00
Events : : eventButtonPress ( ev ) ;
2021-11-21 15:25:57 +01:00
Debug : : log ( LOG , " Event dispatched BUTTON_PRESS " ) ;
2021-11-19 20:20:05 +01:00
break ;
2021-11-22 21:20:32 +01:00
case XCB_BUTTON_RELEASE :
Events : : eventButtonRelease ( ev ) ;
Debug : : log ( LOG , " Event dispatched BUTTON_RELEASE " ) ;
break ;
case XCB_MOTION_NOTIFY :
Events : : eventMotionNotify ( ev ) ;
//Debug::log(LOG, "Event dispatched MOTION_NOTIFY"); // Spam!!
break ;
2021-11-21 11:25:26 +01:00
case XCB_EXPOSE :
Events : : eventExpose ( ev ) ;
Debug : : log ( LOG , " Event dispatched EXPOSE " ) ;
break ;
2021-11-21 15:25:57 +01:00
case XCB_KEY_PRESS :
2021-11-22 21:20:32 +01:00
Events : : eventKeyPress ( ev ) ;
2021-11-21 15:25:57 +01:00
Debug : : log ( LOG , " Event dispatched KEY_PRESS " ) ;
break ;
2021-11-18 18:04:09 +01:00
default :
2021-11-19 23:08:59 +01:00
//Debug::log(WARN, "Unknown event: " + std::to_string(ev->response_type & ~0x80));
2021-11-18 18:04:09 +01:00
break ;
}
free ( ev ) ;
}
// refresh and apply the parameters of all dirty windows.
2021-11-20 09:25:21 +01:00
refreshDirtyWindows ( ) ;
2021-11-18 18:04:09 +01:00
2021-11-24 18:51:34 +01:00
// Sanity checks
for ( const auto active : activeWorkspaces ) {
sanityCheckOnWorkspace ( active ) ;
}
2021-11-20 10:04:14 +01:00
// remove unused workspaces
cleanupUnusedWorkspaces ( ) ;
2021-11-20 09:25:21 +01:00
xcb_flush ( DisplayConnection ) ;
2021-11-18 18:04:09 +01:00
2021-11-23 18:48:03 +01:00
// Restore thread state
mainThreadBusy = false ;
2021-11-18 18:04:09 +01:00
return true ;
}
2021-11-20 10:04:14 +01:00
void CWindowManager : : cleanupUnusedWorkspaces ( ) {
std : : vector < CWorkspace > temp = workspaces ;
workspaces . clear ( ) ;
for ( auto & work : temp ) {
2021-11-21 17:40:02 +01:00
if ( ! isWorkspaceVisible ( work . getID ( ) ) ) {
2021-11-20 10:04:14 +01:00
// check if it has any children
bool hasChildren = false ;
for ( auto & window : windows ) {
if ( window . getWorkspaceID ( ) = = work . getID ( ) ) {
hasChildren = true ;
break ;
}
}
if ( hasChildren ) {
// Has windows opened on it.
workspaces . push_back ( work ) ;
}
} else {
// Foreground workspace
workspaces . push_back ( work ) ;
}
}
2021-11-21 22:24:38 +01:00
// Update bar info
updateBarInfo ( ) ;
2021-11-20 10:04:14 +01:00
}
2021-11-20 09:25:21 +01:00
void CWindowManager : : refreshDirtyWindows ( ) {
2021-11-18 18:04:09 +01:00
for ( auto & window : windows ) {
if ( window . getDirty ( ) ) {
2021-11-22 21:20:32 +01:00
window . setDirty ( false ) ;
2021-11-20 10:04:14 +01:00
2021-11-22 18:43:55 +01:00
// Check if the window isn't a node
2021-11-22 21:20:32 +01:00
if ( window . getChildNodeAID ( ) ! = 0 )
2021-11-22 18:43:55 +01:00
continue ;
2021-11-22 21:20:32 +01:00
2021-11-21 12:40:03 +01:00
setEffectiveSizePosUsingConfig ( & window ) ;
2021-11-21 11:42:44 +01:00
// Fullscreen flag
2021-11-21 17:40:02 +01:00
bool bHasFullscreenWindow = getWorkspaceByID ( window . getWorkspaceID ( ) ) - > getHasFullscreenWindow ( ) ;
2021-11-21 11:42:44 +01:00
2021-11-21 17:40:02 +01:00
// first and foremost, let's check if the window isn't on a hidden workspace
2021-11-21 11:42:44 +01:00
// or that it is not a non-fullscreen window in a fullscreen workspace
2021-11-21 17:40:02 +01:00
if ( ! isWorkspaceVisible ( window . getWorkspaceID ( ) )
| | ( bHasFullscreenWindow & & ! window . getFullscreen ( ) ) ) {
2021-11-20 10:04:14 +01:00
// Move it to hades
Values [ 0 ] = ( int ) 1500000 ; // hmu when monitors actually have that many pixels
Values [ 1 ] = ( int ) 1500000 ; // and we are still using xorg =)
xcb_configure_window ( DisplayConnection , window . getDrawable ( ) , XCB_CONFIG_WINDOW_X | XCB_CONFIG_WINDOW_Y , Values ) ;
// Set the size JIC.
Values [ 0 ] = ( int ) window . getEffectiveSize ( ) . x ;
Values [ 1 ] = ( int ) window . getEffectiveSize ( ) . y ;
xcb_configure_window ( DisplayConnection , window . getDrawable ( ) , XCB_CONFIG_WINDOW_WIDTH | XCB_CONFIG_WINDOW_HEIGHT , Values ) ;
continue ;
}
2021-11-19 22:29:44 +01:00
2021-11-21 11:42:44 +01:00
// Fullscreen window. No border, all screen.
if ( window . getFullscreen ( ) ) {
Values [ 0 ] = 0 ;
xcb_configure_window ( DisplayConnection , window . getDrawable ( ) , XCB_CONFIG_WINDOW_BORDER_WIDTH , Values ) ;
Values [ 0 ] = 0x555555 ; // GRAY :)
xcb_change_window_attributes ( DisplayConnection , window . getDrawable ( ) , XCB_CW_BORDER_PIXEL , Values ) ;
2021-11-21 22:24:38 +01:00
const auto MONITOR = getMonitorFromWindow ( & window ) ;
Values [ 0 ] = ( int ) MONITOR - > vecSize . x ;
Values [ 1 ] = ( int ) MONITOR - > vecSize . y ;
2021-11-21 11:42:44 +01:00
xcb_configure_window ( DisplayConnection , window . getDrawable ( ) , XCB_CONFIG_WINDOW_WIDTH | XCB_CONFIG_WINDOW_HEIGHT , Values ) ;
2021-11-21 22:24:38 +01:00
Values [ 0 ] = ( int ) MONITOR - > vecPosition . x ;
Values [ 1 ] = ( int ) MONITOR - > vecPosition . y ;
2021-11-21 11:42:44 +01:00
xcb_configure_window ( DisplayConnection , window . getDrawable ( ) , XCB_CONFIG_WINDOW_X | XCB_CONFIG_WINDOW_Y , Values ) ;
continue ;
}
2021-11-23 18:48:03 +01:00
Values [ 0 ] = ( int ) window . getRealSize ( ) . x ;
Values [ 1 ] = ( int ) window . getRealSize ( ) . y ;
2021-11-20 09:25:21 +01:00
xcb_configure_window ( DisplayConnection , window . getDrawable ( ) , XCB_CONFIG_WINDOW_WIDTH | XCB_CONFIG_WINDOW_HEIGHT , Values ) ;
2021-11-18 18:04:09 +01:00
2021-11-21 22:24:38 +01:00
// Update the position because the border makes the window jump
// I have added the bordersize vec2d before in the setEffectiveSizePosUsingConfig function.
2021-11-23 18:48:03 +01:00
Values [ 0 ] = ( int ) window . getRealPosition ( ) . x - ConfigManager : : getInt ( " border_size " ) ;
Values [ 1 ] = ( int ) window . getRealPosition ( ) . y - ConfigManager : : getInt ( " border_size " ) ;
2021-11-20 09:25:21 +01:00
xcb_configure_window ( DisplayConnection , window . getDrawable ( ) , XCB_CONFIG_WINDOW_X | XCB_CONFIG_WINDOW_Y , Values ) ;
2021-11-18 18:04:09 +01:00
2021-11-18 22:08:28 +01:00
// Focused special border.
2021-11-20 09:25:21 +01:00
if ( window . getDrawable ( ) = = LastWindow ) {
2021-11-21 12:40:03 +01:00
Values [ 0 ] = ( int ) ConfigManager : : getInt ( " border_size " ) ;
2021-11-20 09:25:21 +01:00
xcb_configure_window ( DisplayConnection , window . getDrawable ( ) , XCB_CONFIG_WINDOW_BORDER_WIDTH , Values ) ;
2021-11-18 22:08:28 +01:00
2021-11-22 19:06:00 +01:00
Values [ 0 ] = ConfigManager : : getInt ( " col.active_border " ) ;
2021-11-20 09:25:21 +01:00
xcb_change_window_attributes ( DisplayConnection , window . getDrawable ( ) , XCB_CW_BORDER_PIXEL , Values ) ;
2021-11-18 22:08:28 +01:00
} else {
2021-11-22 19:06:00 +01:00
Values [ 0 ] = ConfigManager : : getInt ( " col.inactive_border " ) ;
2021-11-20 09:25:21 +01:00
xcb_change_window_attributes ( DisplayConnection , window . getDrawable ( ) , XCB_CW_BORDER_PIXEL , Values ) ;
2021-11-18 22:08:28 +01:00
}
2021-11-19 22:29:44 +01:00
Debug : : log ( LOG , " Refreshed dirty window, with an ID of " + std : : to_string ( window . getDrawable ( ) ) ) ;
2021-11-18 18:04:09 +01:00
}
}
}
2021-11-20 09:25:21 +01:00
void CWindowManager : : setFocusedWindow ( xcb_drawable_t window ) {
if ( window & & window ! = Screen - > root ) {
xcb_set_input_focus ( DisplayConnection , XCB_INPUT_FOCUS_POINTER_ROOT , window , XCB_CURRENT_TIME ) ;
2021-11-18 22:08:28 +01:00
// Fix border from the old window that was in focus.
2021-11-22 19:06:00 +01:00
Values [ 0 ] = ConfigManager : : getInt ( " col.inactive_border " ) ;
2021-11-21 22:24:38 +01:00
xcb_change_window_attributes ( DisplayConnection , LastWindow , XCB_CW_BORDER_PIXEL , Values ) ;
2021-11-22 19:06:00 +01:00
Values [ 0 ] = ConfigManager : : getInt ( " col.active_border " ) ;
2021-11-21 22:24:38 +01:00
xcb_change_window_attributes ( DisplayConnection , window , XCB_CW_BORDER_PIXEL , Values ) ;
2021-11-18 22:08:28 +01:00
2021-11-22 21:20:32 +01:00
float values [ 1 ] ;
if ( g_pWindowManager - > getWindowFromDrawable ( window ) & & g_pWindowManager - > getWindowFromDrawable ( window ) - > getIsFloating ( ) ) {
values [ 0 ] = XCB_STACK_MODE_ABOVE ;
xcb_configure_window ( g_pWindowManager - > DisplayConnection , window , XCB_CONFIG_WINDOW_STACK_MODE , values ) ;
}
2021-11-20 09:25:21 +01:00
LastWindow = window ;
2021-11-18 18:04:09 +01:00
}
}
2021-11-24 21:50:44 +01:00
// TODO: make this executed less. It's too often imo.
2021-11-24 18:51:34 +01:00
void CWindowManager : : sanityCheckOnWorkspace ( int workspaceID ) {
for ( auto & w : windows ) {
if ( w . getWorkspaceID ( ) = = workspaceID ) {
// Check #1: Parent has 2 identical children (happens!)
if ( w . getDrawable ( ) < 0 ) {
const auto CHILDA = w . getChildNodeAID ( ) ;
const auto CHILDB = w . getChildNodeBID ( ) ;
if ( CHILDA = = CHILDB ) {
// Fix. Remove this parent, replace with child.
Debug : : log ( LOG , " Sanity check A triggered for window ID " + std : : to_string ( w . getDrawable ( ) ) ) ;
const auto PCHILD = getWindowFromDrawable ( CHILDA ) ;
2021-11-24 21:50:44 +01:00
if ( ! PCHILD ) {
// Means both children are 0 (dead)
removeWindowFromVectorSafe ( w . getDrawable ( ) ) ;
continue ;
}
2021-11-24 18:51:34 +01:00
PCHILD - > setPosition ( w . getPosition ( ) ) ;
PCHILD - > setSize ( w . getSize ( ) ) ;
// make the sibling replace the parent
PCHILD - > setParentNodeID ( w . getParentNodeID ( ) ) ;
if ( w . getParentNodeID ( ) ! = 0 & & getWindowFromDrawable ( w . getParentNodeID ( ) ) ) {
if ( getWindowFromDrawable ( w . getParentNodeID ( ) ) - > getChildNodeAID ( ) = = w . getDrawable ( ) ) {
getWindowFromDrawable ( w . getParentNodeID ( ) ) - > setChildNodeAID ( w . getDrawable ( ) ) ;
} else {
getWindowFromDrawable ( w . getParentNodeID ( ) ) - > setChildNodeBID ( w . getDrawable ( ) ) ;
}
}
// Make the sibling eat the closed window
PCHILD - > setDirtyRecursive ( true ) ;
PCHILD - > recalcSizePosRecursive ( ) ;
// Remove the parent
removeWindowFromVectorSafe ( w . getDrawable ( ) ) ;
if ( findWindowAtCursor ( ) )
setFocusedWindow ( findWindowAtCursor ( ) - > getDrawable ( ) ) ; // Set focus. :)
Debug : : log ( LOG , " Sanity check A finished successfully. " ) ;
}
}
2021-11-24 19:01:29 +01:00
// Hypothetical check #2: Check if children are present and tiled. (for nodes)
// I have not found this occurring but I have had some issues with... stuff.
if ( w . getDrawable ( ) < 0 ) {
const auto CHILDA = getWindowFromDrawable ( w . getChildNodeAID ( ) ) ;
const auto CHILDB = getWindowFromDrawable ( w . getChildNodeBID ( ) ) ;
if ( CHILDA & & CHILDB ) {
if ( CHILDA - > getIsFloating ( ) ) {
g_pWindowManager - > fixWindowOnClose ( CHILDA ) ;
g_pWindowManager - > calculateNewWindowParams ( CHILDA ) ;
2021-11-24 21:50:44 +01:00
Debug : : log ( LOG , " Found an invalid tiled window, ID: " + std : : to_string ( CHILDA - > getDrawable ( ) ) + " , untiling it. " ) ;
2021-11-24 19:01:29 +01:00
}
if ( CHILDB - > getIsFloating ( ) ) {
g_pWindowManager - > fixWindowOnClose ( CHILDB ) ;
g_pWindowManager - > calculateNewWindowParams ( CHILDB ) ;
2021-11-24 21:50:44 +01:00
Debug : : log ( LOG , " Found an invalid tiled window, ID: " + std : : to_string ( CHILDB - > getDrawable ( ) ) + " , untiling it. " ) ;
2021-11-24 19:01:29 +01:00
}
} else {
Debug : : log ( ERR , " Malformed node ID " + std : : to_string ( w . getDrawable ( ) ) + " with 2 children but one or both are nullptr. " ) ;
}
}
2021-11-24 21:50:44 +01:00
// Check #3: Check if the window exists with xcb
// Some windows do not report they are dead for w/e reason
if ( w . getDrawable ( ) > 0 ) {
const auto GEOMETRYCOOKIE = xcb_get_geometry ( g_pWindowManager - > DisplayConnection , w . getDrawable ( ) ) ;
const auto GEOMETRY = xcb_get_geometry_reply ( g_pWindowManager - > DisplayConnection , GEOMETRYCOOKIE , 0 ) ;
if ( ! GEOMETRY | | ( GEOMETRY - > width < 1 | | GEOMETRY - > height < 1 ) ) {
Debug : : log ( LOG , " Found a dead window, ID: " + std : : to_string ( w . getDrawable ( ) ) + " , removing it. " ) ;
closeWindowAllChecks ( w . getDrawable ( ) ) ;
continue ;
}
}
2021-11-24 18:51:34 +01:00
}
}
}
2021-11-22 18:43:55 +01:00
CWindow * CWindowManager : : getWindowFromDrawable ( int64_t window ) {
2021-11-24 21:50:44 +01:00
if ( ! window )
return nullptr ;
2021-11-20 09:25:21 +01:00
for ( auto & w : windows ) {
2021-11-18 18:04:09 +01:00
if ( w . getDrawable ( ) = = window ) {
return & w ;
}
}
return nullptr ;
}
2021-11-20 09:25:21 +01:00
void CWindowManager : : addWindowToVectorSafe ( CWindow window ) {
for ( auto & w : windows ) {
2021-11-18 18:04:09 +01:00
if ( w . getDrawable ( ) = = window . getDrawable ( ) )
return ; // Do not add if already present.
}
2021-11-20 09:25:21 +01:00
windows . push_back ( window ) ;
2021-11-18 18:04:09 +01:00
}
2021-11-23 17:41:30 +01:00
void CWindowManager : : removeWindowFromVectorSafe ( int64_t window ) {
2021-11-18 18:04:09 +01:00
if ( ! window )
return ;
2021-11-20 09:25:21 +01:00
std : : vector < CWindow > temp = windows ;
2021-11-18 18:04:09 +01:00
2021-11-20 09:25:21 +01:00
windows . clear ( ) ;
2021-11-18 18:04:09 +01:00
for ( auto p : temp ) {
if ( p . getDrawable ( ) ! = window ) {
2021-11-20 09:25:21 +01:00
windows . push_back ( p ) ;
2021-11-18 18:04:09 +01:00
continue ;
}
}
}
2021-11-20 09:25:21 +01:00
void CWindowManager : : setEffectiveSizePosUsingConfig ( CWindow * pWindow ) {
2021-11-18 22:08:28 +01:00
if ( ! pWindow )
return ;
2021-11-21 20:34:31 +01:00
const auto MONITOR = getMonitorFromWindow ( pWindow ) ;
2021-11-19 19:04:42 +01:00
// set some flags.
2021-11-21 20:34:31 +01:00
const bool DISPLAYLEFT = STICKS ( pWindow - > getPosition ( ) . x , MONITOR - > vecPosition . x ) ;
const bool DISPLAYRIGHT = STICKS ( pWindow - > getPosition ( ) . x + pWindow - > getSize ( ) . x , MONITOR - > vecPosition . x + MONITOR - > vecSize . x ) ;
const bool DISPLAYTOP = STICKS ( pWindow - > getPosition ( ) . y , MONITOR - > vecPosition . y ) ;
const bool DISPLAYBOTTOM = STICKS ( pWindow - > getPosition ( ) . y + pWindow - > getSize ( ) . y , MONITOR - > vecPosition . y + MONITOR - > vecSize . y ) ;
2021-11-19 19:04:42 +01:00
2021-11-21 12:40:03 +01:00
pWindow - > setEffectivePosition ( pWindow - > getPosition ( ) + Vector2D ( ConfigManager : : getInt ( " border_size " ) , ConfigManager : : getInt ( " border_size " ) ) ) ;
pWindow - > setEffectiveSize ( pWindow - > getSize ( ) - ( Vector2D ( ConfigManager : : getInt ( " border_size " ) , ConfigManager : : getInt ( " border_size " ) ) * 2 ) ) ;
2021-11-19 19:04:42 +01:00
// do gaps, set top left
2021-11-22 18:43:55 +01:00
pWindow - > setEffectivePosition ( pWindow - > getEffectivePosition ( ) + Vector2D ( DISPLAYLEFT ? ConfigManager : : getInt ( " gaps_out " ) : ConfigManager : : getInt ( " gaps_in " ) , DISPLAYTOP ? ConfigManager : : getInt ( " gaps_out " ) + ( MONITOR - > ID = = statusBar . getMonitorID ( ) ? ConfigManager : : getInt ( " bar_height " ) : 0 ) : ConfigManager : : getInt ( " gaps_in " ) ) ) ;
2021-11-19 19:04:42 +01:00
// fix to old size bottom right
2021-11-22 18:43:55 +01:00
pWindow - > setEffectiveSize ( pWindow - > getEffectiveSize ( ) - Vector2D ( DISPLAYLEFT ? ConfigManager : : getInt ( " gaps_out " ) : ConfigManager : : getInt ( " gaps_in " ) , DISPLAYTOP ? ConfigManager : : getInt ( " gaps_out " ) + ( MONITOR - > ID = = statusBar . getMonitorID ( ) ? ConfigManager : : getInt ( " bar_height " ) : 0 ) : ConfigManager : : getInt ( " gaps_in " ) ) ) ;
2021-11-19 19:04:42 +01:00
// set bottom right
2021-11-21 12:40:03 +01:00
pWindow - > setEffectiveSize ( pWindow - > getEffectiveSize ( ) - Vector2D ( DISPLAYRIGHT ? ConfigManager : : getInt ( " gaps_out " ) : ConfigManager : : getInt ( " gaps_in " ) , DISPLAYBOTTOM ? ConfigManager : : getInt ( " gaps_out " ) : ConfigManager : : getInt ( " gaps_in " ) ) ) ;
2021-11-18 22:08:28 +01:00
}
2021-11-21 15:15:33 +01:00
CWindow * CWindowManager : : findWindowAtCursor ( ) {
const auto POINTERCOOKIE = xcb_query_pointer ( DisplayConnection , Screen - > root ) ;
2021-11-22 21:20:32 +01:00
Vector2D cursorPos = getCursorPos ( ) ;
2021-11-21 15:15:33 +01:00
2021-11-21 17:40:02 +01:00
const auto WORKSPACE = activeWorkspaces [ getMonitorFromCursor ( ) - > ID ] ;
2021-11-21 15:15:33 +01:00
for ( auto & window : windows ) {
2021-11-21 19:59:59 +01:00
if ( window . getWorkspaceID ( ) = = WORKSPACE & & ! window . getIsFloating ( ) ) {
2021-11-21 15:15:33 +01:00
if ( cursorPos . x > = window . getPosition ( ) . x
& & cursorPos . x < = window . getPosition ( ) . x + window . getSize ( ) . x
& & cursorPos . y > = window . getPosition ( ) . y
& & cursorPos . y < = window . getPosition ( ) . y + window . getSize ( ) . y ) {
return & window ;
}
}
}
2021-11-21 17:40:02 +01:00
return nullptr ;
2021-11-21 15:15:33 +01:00
}
2021-11-20 09:25:21 +01:00
void CWindowManager : : calculateNewTileSetOldTile ( CWindow * pWindow ) {
2021-11-22 18:43:55 +01:00
// Get the parent and both children, one of which will be pWindow
const auto PPARENT = getWindowFromDrawable ( pWindow - > getParentNodeID ( ) ) ;
if ( ! PPARENT ) {
// New window on this workspace.
// Open a fullscreen window.
const auto MONITOR = getMonitorFromCursor ( ) ;
2021-11-22 22:37:01 +01:00
if ( ! MONITOR ) {
Debug : : log ( ERR , " Monitor was nullptr! (calculateNewTileSetOldTile) " ) ;
return ;
}
2021-11-22 18:43:55 +01:00
pWindow - > setSize ( Vector2D ( MONITOR - > vecSize . x , MONITOR - > vecSize . y ) ) ;
pWindow - > setPosition ( Vector2D ( MONITOR - > vecPosition . x , MONITOR - > vecPosition . y ) ) ;
2021-11-21 15:15:33 +01:00
2021-11-22 18:43:55 +01:00
return ;
2021-11-21 15:15:33 +01:00
}
2021-11-22 18:43:55 +01:00
// Get the sibling
const auto PSIBLING = getWindowFromDrawable ( PPARENT - > getChildNodeAID ( ) = = pWindow - > getDrawable ( ) ? PPARENT - > getChildNodeBID ( ) : PPARENT - > getChildNodeAID ( ) ) ;
// Should NEVER be null
if ( PSIBLING ) {
const auto PLASTSIZE = PPARENT - > getSize ( ) ;
const auto PLASTPOS = PPARENT - > getPosition ( ) ;
2021-11-18 18:04:09 +01:00
if ( PLASTSIZE . x > PLASTSIZE . y ) {
2021-11-22 18:43:55 +01:00
PSIBLING - > setPosition ( Vector2D ( PLASTPOS . x , PLASTPOS . y ) ) ;
PSIBLING - > setSize ( Vector2D ( PLASTSIZE . x / 2.f , PLASTSIZE . y ) ) ;
2021-11-18 18:04:09 +01:00
pWindow - > setSize ( Vector2D ( PLASTSIZE . x / 2.f , PLASTSIZE . y ) ) ;
pWindow - > setPosition ( Vector2D ( PLASTPOS . x + PLASTSIZE . x / 2.f , PLASTPOS . y ) ) ;
} else {
2021-11-22 18:43:55 +01:00
PSIBLING - > setPosition ( Vector2D ( PLASTPOS . x , PLASTPOS . y ) ) ;
PSIBLING - > setSize ( Vector2D ( PLASTSIZE . x , PLASTSIZE . y / 2.f ) ) ;
2021-11-18 18:04:09 +01:00
pWindow - > setSize ( Vector2D ( PLASTSIZE . x , PLASTSIZE . y / 2.f ) ) ;
pWindow - > setPosition ( Vector2D ( PLASTPOS . x , PLASTPOS . y + PLASTSIZE . y / 2.f ) ) ;
}
2021-11-22 18:43:55 +01:00
PSIBLING - > setDirty ( true ) ;
2021-11-18 18:04:09 +01:00
} else {
2021-11-22 18:43:55 +01:00
Debug : : log ( ERR , " Sibling node was null?? pWindow x,y,w,h: " + std : : to_string ( pWindow - > getPosition ( ) . x ) + " "
+ std : : to_string ( pWindow - > getPosition ( ) . y ) + " " + std : : to_string ( pWindow - > getSize ( ) . x ) + " "
+ std : : to_string ( pWindow - > getSize ( ) . y ) ) ;
2021-11-18 18:04:09 +01:00
}
2021-11-22 21:20:32 +01:00
Values [ 0 ] = XCB_STACK_MODE_BELOW ;
xcb_configure_window ( DisplayConnection , pWindow - > getDrawable ( ) , XCB_CONFIG_WINDOW_STACK_MODE , Values ) ;
2021-11-18 18:04:09 +01:00
}
2021-11-21 15:15:33 +01:00
void CWindowManager : : calculateNewFloatingWindow ( CWindow * pWindow ) {
if ( ! pWindow )
return ;
pWindow - > setPosition ( pWindow - > getDefaultPosition ( ) ) ;
pWindow - > setSize ( pWindow - > getDefaultSize ( ) ) ;
2021-11-22 21:20:32 +01:00
2021-11-24 19:33:32 +01:00
pWindow - > setEffectivePosition ( pWindow - > getDefaultPosition ( ) ) ;
pWindow - > setEffectiveSize ( pWindow - > getDefaultSize ( ) ) ;
2021-11-22 21:20:32 +01:00
Values [ 0 ] = XCB_STACK_MODE_ABOVE ;
xcb_configure_window ( DisplayConnection , pWindow - > getDrawable ( ) , XCB_CONFIG_WINDOW_STACK_MODE , Values ) ;
2021-11-21 15:15:33 +01:00
}
2021-11-20 09:25:21 +01:00
void CWindowManager : : calculateNewWindowParams ( CWindow * pWindow ) {
2021-11-18 18:04:09 +01:00
// And set old one's if needed.
if ( ! pWindow )
return ;
if ( ! pWindow - > getIsFloating ( ) ) {
calculateNewTileSetOldTile ( pWindow ) ;
2021-11-21 15:15:33 +01:00
} else {
calculateNewFloatingWindow ( pWindow ) ;
2021-11-18 18:04:09 +01:00
}
2021-11-23 18:48:03 +01:00
setEffectiveSizePosUsingConfig ( pWindow ) ;
2021-11-18 18:04:09 +01:00
pWindow - > setDirty ( true ) ;
}
2021-11-20 09:25:21 +01:00
bool CWindowManager : : isNeighbor ( CWindow * a , CWindow * b ) {
2021-11-20 10:04:14 +01:00
2021-11-21 20:17:49 +01:00
if ( a - > getWorkspaceID ( ) ! = b - > getWorkspaceID ( ) )
2021-11-20 10:04:14 +01:00
return false ; // Different workspaces
2021-11-18 18:04:09 +01:00
const auto POSA = a - > getPosition ( ) ;
const auto POSB = b - > getPosition ( ) ;
const auto SIZEA = a - > getSize ( ) ;
2021-11-18 22:26:29 +01:00
const auto SIZEB = b - > getSize ( ) ;
2021-11-18 18:04:09 +01:00
if ( POSA . x ! = 0 ) {
if ( STICKS ( POSA . x , ( POSB . x + SIZEB . x ) ) ) {
return true ;
}
}
if ( POSA . y ! = 0 ) {
if ( STICKS ( POSA . y , ( POSB . y + SIZEB . y ) ) ) {
return true ;
}
}
if ( POSB . x ! = 0 ) {
if ( STICKS ( POSB . x , ( POSA . x + SIZEA . x ) ) ) {
return true ;
}
}
if ( POSB . y ! = 0 ) {
if ( STICKS ( POSB . y , ( POSA . y + SIZEA . y ) ) ) {
return true ;
}
}
return false ;
}
2021-11-20 09:25:21 +01:00
bool CWindowManager : : canEatWindow ( CWindow * a , CWindow * toEat ) {
2021-11-19 19:04:42 +01:00
// Pos is min of both.
const auto POSAFTEREAT = Vector2D ( std : : min ( a - > getPosition ( ) . x , toEat - > getPosition ( ) . x ) , std : : min ( a - > getPosition ( ) . y , toEat - > getPosition ( ) . y ) ) ;
// Size is pos + size max - pos
const auto OPPCORNERA = Vector2D ( POSAFTEREAT ) + a - > getSize ( ) ;
const auto OPPCORNERB = toEat - > getPosition ( ) + toEat - > getSize ( ) ;
const auto SIZEAFTEREAT = Vector2D ( std : : max ( OPPCORNERA . x , OPPCORNERB . x ) , std : : max ( OPPCORNERA . y , OPPCORNERB . y ) ) - POSAFTEREAT ;
const auto doOverlap = [ & ] ( CWindow * b ) {
const auto RIGHT1 = Vector2D ( POSAFTEREAT . x + SIZEAFTEREAT . x , POSAFTEREAT . y + SIZEAFTEREAT . y ) ;
const auto RIGHT2 = b - > getPosition ( ) + b - > getSize ( ) ;
const auto LEFT1 = POSAFTEREAT ;
const auto LEFT2 = b - > getPosition ( ) ;
return ! ( LEFT1 . x > = RIGHT2 . x | | LEFT2 . x > = RIGHT1 . x | | LEFT1 . y > = RIGHT2 . y | | LEFT2 . y > = RIGHT1 . y ) ;
} ;
2021-11-20 09:25:21 +01:00
for ( auto & w : windows ) {
2021-11-21 17:40:02 +01:00
if ( w . getDrawable ( ) = = a - > getDrawable ( ) | | w . getDrawable ( ) = = toEat - > getDrawable ( ) | | w . getWorkspaceID ( ) ! = toEat - > getWorkspaceID ( )
| | w . getIsFloating ( ) | | getMonitorFromWindow ( & w ) ! = getMonitorFromWindow ( toEat ) )
2021-11-19 19:04:42 +01:00
continue ;
if ( doOverlap ( & w ) )
return false ;
}
return true ;
}
2021-11-20 09:25:21 +01:00
void CWindowManager : : eatWindow ( CWindow * a , CWindow * toEat ) {
2021-11-19 22:29:44 +01:00
2021-11-18 18:04:09 +01:00
// Size is pos + size max - pos
const auto OPPCORNERA = a - > getPosition ( ) + a - > getSize ( ) ;
const auto OPPCORNERB = toEat - > getPosition ( ) + toEat - > getSize ( ) ;
2021-11-19 20:39:43 +01:00
// Pos is min of both.
a - > setPosition ( Vector2D ( std : : min ( a - > getPosition ( ) . x , toEat - > getPosition ( ) . x ) , std : : min ( a - > getPosition ( ) . y , toEat - > getPosition ( ) . y ) ) ) ;
2021-11-18 18:04:09 +01:00
a - > setSize ( Vector2D ( std : : max ( OPPCORNERA . x , OPPCORNERB . x ) , std : : max ( OPPCORNERA . y , OPPCORNERB . y ) ) - a - > getPosition ( ) ) ;
}
2021-11-24 21:50:44 +01:00
void CWindowManager : : closeWindowAllChecks ( int64_t id ) {
// fix last window if tile
const auto CLOSEDWINDOW = g_pWindowManager - > getWindowFromDrawable ( id ) ;
if ( CLOSEDWINDOW & & ! CLOSEDWINDOW - > getIsFloating ( ) ) {
g_pWindowManager - > fixWindowOnClose ( CLOSEDWINDOW ) ;
// delete off of the arr
g_pWindowManager - > removeWindowFromVectorSafe ( id ) ;
}
}
2021-11-20 09:25:21 +01:00
void CWindowManager : : fixWindowOnClose ( CWindow * pClosedWindow ) {
2021-11-18 18:04:09 +01:00
if ( ! pClosedWindow )
return ;
2021-11-22 18:43:55 +01:00
// Get the parent and both children, one of which will be pWindow
const auto PPARENT = getWindowFromDrawable ( pClosedWindow - > getParentNodeID ( ) ) ;
2021-11-21 17:40:02 +01:00
2021-11-22 18:43:55 +01:00
if ( ! PPARENT )
return ; // if there was no parent, we do not need to update anything. it was a fullscreen window, the only one on a given workspace.
2021-11-21 11:42:44 +01:00
2021-11-22 18:43:55 +01:00
// Get the sibling
const auto PSIBLING = getWindowFromDrawable ( PPARENT - > getChildNodeAID ( ) = = pClosedWindow - > getDrawable ( ) ? PPARENT - > getChildNodeBID ( ) : PPARENT - > getChildNodeAID ( ) ) ;
2021-11-18 18:04:09 +01:00
2021-11-22 21:20:32 +01:00
if ( ! PSIBLING ) {
Debug : : log ( ERR , " No sibling found in fixOnClose! (Corrupted tree...?) " ) ;
return ;
}
2021-11-22 18:43:55 +01:00
PSIBLING - > setPosition ( PPARENT - > getPosition ( ) ) ;
PSIBLING - > setSize ( PPARENT - > getSize ( ) ) ;
// make the sibling replace the parent
PSIBLING - > setParentNodeID ( PPARENT - > getParentNodeID ( ) ) ;
if ( PPARENT - > getParentNodeID ( ) ! = 0
& & getWindowFromDrawable ( PPARENT - > getParentNodeID ( ) ) ) {
if ( getWindowFromDrawable ( PPARENT - > getParentNodeID ( ) ) - > getChildNodeAID ( ) = = PPARENT - > getDrawable ( ) ) {
getWindowFromDrawable ( PPARENT - > getParentNodeID ( ) ) - > setChildNodeAID ( PSIBLING - > getDrawable ( ) ) ;
} else {
getWindowFromDrawable ( PPARENT - > getParentNodeID ( ) ) - > setChildNodeBID ( PSIBLING - > getDrawable ( ) ) ;
}
2021-11-18 18:04:09 +01:00
}
2021-11-22 18:43:55 +01:00
// Make the sibling eat the closed window
PSIBLING - > setDirtyRecursive ( true ) ;
PSIBLING - > recalcSizePosRecursive ( ) ;
2021-11-18 18:04:09 +01:00
2021-11-22 18:43:55 +01:00
// Remove the parent
removeWindowFromVectorSafe ( PPARENT - > getDrawable ( ) ) ;
2021-11-18 18:04:09 +01:00
2021-11-22 18:43:55 +01:00
if ( findWindowAtCursor ( ) )
setFocusedWindow ( findWindowAtCursor ( ) - > getDrawable ( ) ) ; // Set focus. :)
2021-11-19 22:29:44 +01:00
}
2021-11-20 09:25:21 +01:00
CWindow * CWindowManager : : getNeighborInDir ( char dir ) {
2021-11-19 22:29:44 +01:00
2021-11-20 09:25:21 +01:00
const auto CURRENTWINDOW = getWindowFromDrawable ( LastWindow ) ;
2021-11-19 22:29:44 +01:00
if ( ! CURRENTWINDOW )
return nullptr ;
const auto POSA = CURRENTWINDOW - > getPosition ( ) ;
const auto SIZEA = CURRENTWINDOW - > getSize ( ) ;
2021-11-20 09:25:21 +01:00
for ( auto & w : windows ) {
2021-11-20 10:04:14 +01:00
if ( w . getDrawable ( ) = = CURRENTWINDOW - > getDrawable ( ) | | w . getWorkspaceID ( ) ! = CURRENTWINDOW - > getWorkspaceID ( ) )
2021-11-19 22:29:44 +01:00
continue ;
const auto POSB = w . getPosition ( ) ;
const auto SIZEB = w . getSize ( ) ;
switch ( dir ) {
case ' l ' :
if ( STICKS ( POSA . x , POSB . x + SIZEB . x ) )
return & w ;
break ;
case ' r ' :
if ( STICKS ( POSA . x + SIZEA . x , POSB . x ) )
return & w ;
break ;
case ' t ' :
if ( STICKS ( POSA . y , POSB . y + SIZEB . y ) )
return & w ;
break ;
case ' b ' :
if ( STICKS ( POSA . y + SIZEA . y , POSB . y ) )
return & w ;
break ;
}
}
return nullptr ;
}
2021-11-19 23:08:59 +01:00
// I don't know if this works, it might be an issue with my nested Xorg session I am using rn to test this.
// Will check later.
// TODO:
2021-11-20 09:25:21 +01:00
void CWindowManager : : warpCursorTo ( Vector2D to ) {
const auto POINTERCOOKIE = xcb_query_pointer ( DisplayConnection , Screen - > root ) ;
2021-11-19 23:08:59 +01:00
2021-11-20 09:25:21 +01:00
xcb_query_pointer_reply_t * pointerreply = xcb_query_pointer_reply ( DisplayConnection , POINTERCOOKIE , NULL ) ;
2021-11-19 23:08:59 +01:00
if ( ! pointerreply ) {
Debug : : log ( ERR , " Couldn't query pointer. " ) ;
2021-11-22 22:37:01 +01:00
free ( pointerreply ) ;
2021-11-19 23:08:59 +01:00
return ;
}
2021-11-20 09:25:21 +01:00
xcb_warp_pointer ( DisplayConnection , XCB_NONE , Screen - > root , 0 , 0 , 0 , 0 , ( int ) to . x , ( int ) to . y ) ;
2021-11-19 23:08:59 +01:00
free ( pointerreply ) ;
}
2021-11-20 09:25:21 +01:00
void CWindowManager : : moveActiveWindowTo ( char dir ) {
const auto CURRENTWINDOW = getWindowFromDrawable ( LastWindow ) ;
2021-11-19 22:29:44 +01:00
if ( ! CURRENTWINDOW )
return ;
const auto neighbor = getNeighborInDir ( dir ) ;
if ( ! neighbor )
return ;
// swap their stuff and mark dirty
const auto TEMP_SIZEA = CURRENTWINDOW - > getSize ( ) ;
const auto TEMP_POSA = CURRENTWINDOW - > getPosition ( ) ;
CURRENTWINDOW - > setSize ( neighbor - > getSize ( ) ) ;
CURRENTWINDOW - > setPosition ( neighbor - > getPosition ( ) ) ;
neighbor - > setSize ( TEMP_SIZEA ) ;
neighbor - > setPosition ( TEMP_POSA ) ;
CURRENTWINDOW - > setDirty ( true ) ;
neighbor - > setDirty ( true ) ;
2021-11-19 23:08:59 +01:00
// finish by moving the cursor to the current window
2021-11-20 09:25:21 +01:00
warpCursorTo ( CURRENTWINDOW - > getPosition ( ) + CURRENTWINDOW - > getSize ( ) / 2.f ) ;
2021-11-20 10:04:14 +01:00
}
void CWindowManager : : changeWorkspaceByID ( int ID ) {
2021-11-21 17:40:02 +01:00
2021-11-21 22:24:38 +01:00
const auto MONITOR = getMonitorFromCursor ( ) ;
2021-11-22 22:37:01 +01:00
if ( ! MONITOR ) {
Debug : : log ( ERR , " Monitor was nullptr! (changeWorkspaceByID) " ) ;
return ;
}
2021-11-21 22:24:38 +01:00
// mark old workspace dirty
setAllWorkspaceWindowsDirtyByID ( activeWorkspaces [ MONITOR - > ID ] ) ;
2021-11-21 17:40:02 +01:00
2021-11-20 10:04:14 +01:00
for ( auto & workspace : workspaces ) {
if ( workspace . getID ( ) = = ID ) {
2021-11-23 22:23:22 +01:00
// set workspaces dirty
setAllWorkspaceWindowsDirtyByID ( activeWorkspaces [ workspace . getMonitor ( ) ] ) ;
setAllWorkspaceWindowsDirtyByID ( ID ) ;
2021-11-21 19:59:59 +01:00
activeWorkspaces [ workspace . getMonitor ( ) ] = workspace . getID ( ) ;
2021-11-21 21:16:19 +01:00
2021-11-23 22:23:22 +01:00
// set the focus to any window on that workspace
for ( auto & window : windows ) {
if ( window . getWorkspaceID ( ) = = ID & & window . getDrawable ( ) > 0 ) {
g_pWindowManager - > setFocusedWindow ( window . getDrawable ( ) ) ;
break ;
}
}
2021-11-21 22:24:38 +01:00
// Update bar info
updateBarInfo ( ) ;
2021-11-23 22:23:22 +01:00
2021-11-21 19:59:59 +01:00
return ;
2021-11-20 10:04:14 +01:00
}
}
// If we are here it means the workspace is new. Let's create it.
CWorkspace newWorkspace ;
newWorkspace . setID ( ID ) ;
2021-11-21 17:40:02 +01:00
newWorkspace . setMonitor ( MONITOR - > ID ) ;
2021-11-20 10:04:14 +01:00
workspaces . push_back ( newWorkspace ) ;
2021-11-21 19:59:59 +01:00
activeWorkspaces [ MONITOR - > ID ] = workspaces [ workspaces . size ( ) - 1 ] . getID ( ) ;
2021-11-20 10:04:14 +01:00
LastWindow = - 1 ;
2021-11-21 21:16:19 +01:00
2021-11-21 22:24:38 +01:00
// Update bar info
updateBarInfo ( ) ;
// no need for the new dirty, it's empty
2021-11-20 10:04:14 +01:00
}
2021-11-21 12:40:03 +01:00
void CWindowManager : : setAllWindowsDirty ( ) {
for ( auto & window : windows ) {
window . setDirty ( true ) ;
}
}
2021-11-20 10:04:14 +01:00
void CWindowManager : : setAllWorkspaceWindowsDirtyByID ( int ID ) {
int workspaceID = - 1 ;
for ( auto & workspace : workspaces ) {
if ( workspace . getID ( ) = = ID ) {
workspaceID = workspace . getID ( ) ;
break ;
}
}
if ( workspaceID = = - 1 )
return ;
for ( auto & window : windows ) {
if ( window . getWorkspaceID ( ) = = workspaceID )
window . setDirty ( true ) ;
}
2021-11-21 11:25:26 +01:00
}
int CWindowManager : : getHighestWorkspaceID ( ) {
int max = - 1 ;
for ( auto & workspace : workspaces ) {
if ( workspace . getID ( ) > max ) {
max = workspace . getID ( ) ;
}
}
return max ;
}
CWorkspace * CWindowManager : : getWorkspaceByID ( int ID ) {
for ( auto & workspace : workspaces ) {
if ( workspace . getID ( ) = = ID ) {
return & workspace ;
}
}
return nullptr ;
2021-11-21 17:40:02 +01:00
}
SMonitor * CWindowManager : : getMonitorFromWindow ( CWindow * pWindow ) {
return & monitors [ pWindow - > getMonitor ( ) ] ;
}
SMonitor * CWindowManager : : getMonitorFromCursor ( ) {
2021-11-22 21:20:32 +01:00
const auto CURSORPOS = getCursorPos ( ) ;
for ( auto & monitor : monitors ) {
if ( VECINRECT ( CURSORPOS , monitor . vecPosition . x , monitor . vecPosition . y , monitor . vecPosition . x + monitor . vecSize . x , monitor . vecPosition . y + monitor . vecSize . y ) )
return & monitor ;
}
// should never happen tho, I'm using >= and the cursor cant get outside the screens, i hope.
return nullptr ;
}
Vector2D CWindowManager : : getCursorPos ( ) {
2021-11-21 17:40:02 +01:00
const auto POINTERCOOKIE = xcb_query_pointer ( DisplayConnection , Screen - > root ) ;
xcb_query_pointer_reply_t * pointerreply = xcb_query_pointer_reply ( DisplayConnection , POINTERCOOKIE , NULL ) ;
if ( ! pointerreply ) {
Debug : : log ( ERR , " Couldn't query pointer. " ) ;
2021-11-22 22:37:01 +01:00
free ( pointerreply ) ;
2021-11-22 21:20:32 +01:00
return Vector2D ( 0 , 0 ) ;
2021-11-21 17:40:02 +01:00
}
const auto CURSORPOS = Vector2D ( pointerreply - > root_x , pointerreply - > root_y ) ;
free ( pointerreply ) ;
2021-11-22 21:20:32 +01:00
return CURSORPOS ;
2021-11-21 17:40:02 +01:00
}
bool CWindowManager : : isWorkspaceVisible ( int workspaceID ) {
for ( auto & workspace : activeWorkspaces ) {
2021-11-21 19:59:59 +01:00
if ( workspace = = workspaceID )
2021-11-21 17:40:02 +01:00
return true ;
}
return false ;
}
2021-11-21 22:24:38 +01:00
void CWindowManager : : updateBarInfo ( ) {
statusBar . openWorkspaces . clear ( ) ;
for ( auto & workspace : workspaces ) {
statusBar . openWorkspaces . push_back ( workspace . getID ( ) ) ;
}
std : : sort ( statusBar . openWorkspaces . begin ( ) , statusBar . openWorkspaces . end ( ) ) ;
2021-11-22 22:37:01 +01:00
if ( ! getMonitorFromCursor ( ) ) {
Debug : : log ( ERR , " Monitor was null! (updateBarInfo) " ) ;
return ;
}
2021-11-21 22:24:38 +01:00
statusBar . setCurrentWorkspace ( activeWorkspaces [ getMonitorFromCursor ( ) - > ID ] ) ;
2021-11-23 16:53:29 +01:00
}
2021-11-23 17:43:27 +01:00
void CWindowManager : : setAllFloatingWindowsTop ( ) {
for ( auto & window : windows ) {
if ( window . getIsFloating ( ) ) {
Values [ 0 ] = XCB_STACK_MODE_ABOVE ;
xcb_configure_window ( g_pWindowManager - > DisplayConnection , window . getDrawable ( ) , XCB_CONFIG_WINDOW_STACK_MODE , Values ) ;
}
}
2021-11-23 22:15:36 +01:00
}
bool CWindowManager : : shouldBeFloatedOnInit ( int64_t window ) {
// Should be floated also sets some properties
2021-11-24 18:37:45 +01:00
2021-11-23 22:15:36 +01:00
// get stuffza
// floating for krunner
// TODO: config this
2021-11-24 18:37:45 +01:00
const auto WINCLASS = getClassName ( window ) ;
const auto CLASSNAME = WINCLASS . second ;
const auto CLASSINSTANCE = WINCLASS . first ;
2021-11-23 22:15:36 +01:00
Debug : : log ( LOG , " New window got class " + ( std : : string ) CLASSINSTANCE + " -> " + CLASSNAME ) ;
xcb_change_property ( DisplayConnection , XCB_PROP_MODE_REPLACE , window , XCB_ATOM_WM_NAME , XCB_ATOM_STRING , 8 , strlen ( " hypr " ) , " hypr " ) ;
if ( ( ( std : : string ) CLASSNAME ) . find ( " krunner " ) ! = std : : string : : npos ) {
return true ;
}
2021-11-24 18:37:45 +01:00
// Role stuff
const auto WINROLE = getRoleName ( window ) ;
Debug : : log ( LOG , " Window opened with a role of " + WINROLE ) ;
if ( WINROLE . find ( " pop-up " ) ! = std : : string : : npos | | WINROLE . find ( " task_dialog " ) ! = std : : string : : npos ) {
return true ;
}
//
// Type stuff
//
PROP ( wm_type_cookie , HYPRATOMS [ " _NET_WM_WINDOW_TYPE " ] , UINT32_MAX ) ;
xcb_atom_t TYPEATOM = NULL ;
if ( wm_type_cookiereply = = NULL | | xcb_get_property_value_length ( wm_type_cookiereply ) < 1 ) {
Debug : : log ( LOG , " No preferred type found. " ) ;
} else {
const auto ATOMS = ( xcb_atom_t * ) xcb_get_property_value ( wm_type_cookiereply ) ;
if ( ! ATOMS ) {
Debug : : log ( ERR , " Atoms not found in preferred type! " ) ;
} else {
if ( xcbContainsAtom ( wm_type_cookiereply , HYPRATOMS [ " _NET_WM_WINDOW_TYPE_NOTIFICATION " ] ) ) {
free ( wm_type_cookiereply ) ;
return true ;
}
}
}
free ( wm_type_cookiereply ) ;
//
//
//
2021-11-23 22:15:36 +01:00
return false ;
2021-11-23 17:43:27 +01:00
}