2022-03-20 16:51:14 +01:00
# include "HyprCtl.hpp"
2022-03-21 18:29:41 +01:00
# include <netinet/in.h>
# include <stdio.h>
# include <stdlib.h>
# include <string.h>
# include <sys/socket.h>
2022-03-20 16:51:14 +01:00
# include <sys/stat.h>
2022-03-21 18:29:41 +01:00
# include <sys/types.h>
2022-03-20 16:51:14 +01:00
# include <unistd.h>
2022-03-30 16:24:42 +02:00
# include <errno.h>
2022-03-20 16:51:14 +01:00
# include <string>
std : : string monitorsRequest ( ) {
std : : string result = " " ;
for ( auto & m : g_pCompositor - > m_lMonitors ) {
2022-04-21 21:25:28 +02:00
result + = getFormat ( " Monitor %s (ID %i): \n \t %ix%i@%f at %ix%i \n \t active workspace: %i (%s) \n \t reserved: %i %i %i %i \n \n " ,
m . szName . c_str ( ) , m . ID , ( int ) m . vecSize . x , ( int ) m . vecSize . y , m . refreshRate , ( int ) m . vecPosition . x , ( int ) m . vecPosition . y , m . activeWorkspace , g_pCompositor - > getWorkspaceByID ( m . activeWorkspace ) - > m_szName . c_str ( ) , ( int ) m . vecReservedTopLeft . x , ( int ) m . vecReservedTopLeft . y , ( int ) m . vecReservedBottomRight . x , ( int ) m . vecReservedBottomRight . y ) ;
2022-03-20 16:51:14 +01:00
}
return result ;
}
std : : string clientsRequest ( ) {
std : : string result = " " ;
for ( auto & w : g_pCompositor - > m_lWindows ) {
2022-04-21 21:25:28 +02:00
result + = getFormat ( " Window %x -> %s: \n \t at: %i,%i \n \t size: %i, %i \n \t workspace: %i (%s) \n \t floating: %i \n \n " ,
& w , w . m_szTitle . c_str ( ) , ( int ) w . m_vRealPosition . x , ( int ) w . m_vRealPosition . y , ( int ) w . m_vRealSize . x , ( int ) w . m_vRealSize . y , w . m_iWorkspaceID , ( w . m_iWorkspaceID = = - 1 ? " " : g_pCompositor - > getWorkspaceByID ( w . m_iWorkspaceID ) - > m_szName . c_str ( ) ) , ( int ) w . m_bIsFloating ) ;
2022-03-20 16:51:14 +01:00
}
return result ;
}
std : : string workspacesRequest ( ) {
std : : string result = " " ;
for ( auto & w : g_pCompositor - > m_lWorkspaces ) {
2022-04-21 21:25:28 +02:00
result + = getFormat ( " workspace ID %i (%s) on monitor %s: \n \t windows: %i \n \t hasfullscreen: %i \n \n " ,
w . m_iID , w . m_szName . c_str ( ) , g_pCompositor - > getMonitorFromID ( w . m_iMonitorID ) - > szName . c_str ( ) , g_pCompositor - > getWindowsOnWorkspace ( w . m_iID ) , ( int ) w . m_bHasFullscreenWindow ) ;
2022-03-20 16:51:14 +01:00
}
return result ;
}
2022-03-22 16:54:45 +01:00
std : : string activeWindowRequest ( ) {
2022-04-02 18:57:09 +02:00
const auto PWINDOW = g_pCompositor - > m_pLastWindow ;
2022-03-22 16:54:45 +01:00
if ( ! g_pCompositor - > windowValidMapped ( PWINDOW ) )
return " Invalid " ;
2022-04-21 21:25:28 +02:00
return getFormat ( " Window %x -> %s: \n \t at: %i,%i \n \t size: %i, %i \n \t workspace: %i (%s) \n \t floating: %i \n \n " ,
PWINDOW , PWINDOW - > m_szTitle . c_str ( ) , ( int ) PWINDOW - > m_vRealPosition . x , ( int ) PWINDOW - > m_vRealPosition . y , ( int ) PWINDOW - > m_vRealSize . x , ( int ) PWINDOW - > m_vRealSize . y , PWINDOW - > m_iWorkspaceID , ( PWINDOW - > m_iWorkspaceID = = - 1 ? " " : g_pCompositor - > getWorkspaceByID ( PWINDOW - > m_iWorkspaceID ) - > m_szName . c_str ( ) ) , ( int ) PWINDOW - > m_bIsFloating ) ;
2022-03-22 16:54:45 +01:00
}
std : : string layersRequest ( ) {
std : : string result = " " ;
for ( auto & mon : g_pCompositor - > m_lMonitors ) {
result + = getFormat ( " Monitor %s: \n " ) ;
int layerLevel = 0 ;
for ( auto & level : mon . m_aLayerSurfaceLists ) {
result + = getFormat ( " \t Layer level %i: \n " , layerLevel ) ;
for ( auto & layer : level ) {
2022-03-31 17:25:23 +02:00
result + = getFormat ( " \t \t Layer %x: xywh: %i %i %i %i \n " , layer , layer - > geometry . x , layer - > geometry . y , layer - > geometry . width , layer - > geometry . height ) ;
2022-03-22 16:54:45 +01:00
}
layerLevel + + ;
}
result + = " \n \n " ;
}
return result ;
}
2022-04-22 18:14:25 +02:00
std : : string versionRequest ( ) {
2022-04-22 18:33:30 +02:00
std : : string result = " Hyprland, built from branch " + std : : string ( GIT_BRANCH ) + " at commit " + GIT_COMMIT_HASH + GIT_DIRTY + " ( " + GIT_COMMIT_MESSAGE + " ). \n flags: (if any) \n " ;
2022-04-22 18:14:25 +02:00
# ifdef LEGACY_RENDERER
result + = " legacyrenderer \n " ;
# endif
# ifndef NDEBUG
result + = " debug \n " ;
# endif
# ifdef NO_XWAYLAND
result + = " no xwayland \n " ;
# endif
return result ;
}
2022-04-21 16:11:29 +02:00
std : : string dispatchRequest ( std : : string in ) {
// get rid of the dispatch keyword
in = in . substr ( in . find_first_of ( ' ' ) + 1 ) ;
const auto DISPATCHSTR = in . substr ( 0 , in . find_first_of ( ' ' ) ) ;
const auto DISPATCHARG = in . substr ( in . find_first_of ( ' ' ) + 1 ) ;
const auto DISPATCHER = g_pKeybindManager - > m_mDispatchers . find ( DISPATCHSTR ) ;
if ( DISPATCHER = = g_pKeybindManager - > m_mDispatchers . end ( ) )
return " Invalid dispatcher " ;
DISPATCHER - > second ( DISPATCHARG ) ;
2022-04-21 21:48:37 +02:00
Debug : : log ( LOG , " Hyprctl: dispatcher %s : %s " , DISPATCHSTR . c_str ( ) , DISPATCHARG . c_str ( ) ) ;
2022-04-21 16:11:29 +02:00
return " ok " ;
}
2022-04-21 16:56:27 +02:00
std : : string dispatchKeyword ( std : : string in ) {
// get rid of the keyword keyword
in = in . substr ( in . find_first_of ( ' ' ) + 1 ) ;
const auto COMMAND = in . substr ( 0 , in . find_first_of ( ' ' ) ) ;
const auto VALUE = in . substr ( in . find_first_of ( ' ' ) + 1 ) ;
std : : string retval = g_pConfigManager - > parseKeyword ( COMMAND , VALUE , true ) ;
2022-04-21 21:36:45 +02:00
if ( COMMAND = = " monitor " )
g_pConfigManager - > m_bWantsMonitorReload = true ; // for monitor keywords
2022-04-21 17:36:28 +02:00
2022-04-22 14:11:52 +02:00
if ( COMMAND . find ( " input " ) ! = std : : string : : npos )
g_pInputManager - > setKeyboardLayout ( ) ; // update kb layout
2022-04-21 21:48:37 +02:00
Debug : : log ( LOG , " Hyprctl: keyword %s : %s " , COMMAND . c_str ( ) , VALUE . c_str ( ) ) ;
2022-04-21 16:56:27 +02:00
if ( retval = = " " )
return " ok " ;
return retval ;
}
2022-04-21 22:00:03 +02:00
void HyprCtl : : tickHyprCtl ( ) {
if ( ! requestMade )
return ;
std : : string reply = " " ;
try {
if ( request = = " monitors " )
reply = monitorsRequest ( ) ;
else if ( request = = " workspaces " )
reply = workspacesRequest ( ) ;
else if ( request = = " clients " )
reply = clientsRequest ( ) ;
else if ( request = = " activewindow " )
reply = activeWindowRequest ( ) ;
else if ( request = = " layers " )
reply = layersRequest ( ) ;
2022-04-22 18:14:25 +02:00
else if ( request = = " version " )
reply = versionRequest ( ) ;
2022-04-21 22:00:03 +02:00
else if ( request . find ( " dispatch " ) = = 0 )
reply = dispatchRequest ( request ) ;
else if ( request . find ( " keyword " ) = = 0 )
reply = dispatchKeyword ( request ) ;
} catch ( std : : exception & e ) {
Debug : : log ( ERR , " Error in request: %s " , e . what ( ) ) ;
reply = " Err: " + std : : string ( e . what ( ) ) ;
}
request = reply ;
requestMade = false ;
requestReady = true ;
}
std : : string getRequestFromThread ( std : : string rq ) {
while ( HyprCtl : : request ! = " " | | HyprCtl : : requestMade | | HyprCtl : : requestReady ) {
std : : this_thread : : sleep_for ( std : : chrono : : milliseconds ( 5 ) ) ;
}
HyprCtl : : request = rq ;
HyprCtl : : requestMade = true ;
while ( ! HyprCtl : : requestReady ) {
std : : this_thread : : sleep_for ( std : : chrono : : milliseconds ( 5 ) ) ;
}
HyprCtl : : requestReady = false ;
HyprCtl : : requestMade = false ;
std : : string toReturn = HyprCtl : : request ;
HyprCtl : : request = " " ;
return toReturn ;
}
2022-03-21 18:29:41 +01:00
void HyprCtl : : startHyprCtlSocket ( ) {
std : : thread ( [ & ] ( ) {
2022-03-30 16:24:42 +02:00
uint16_t connectPort = 9187 ;
2022-03-21 18:29:41 +01:00
const auto SOCKET = socket ( AF_INET , SOCK_STREAM , 0 ) ;
2022-03-20 16:51:14 +01:00
2022-03-21 18:29:41 +01:00
if ( SOCKET < 0 ) {
Debug : : log ( ERR , " Couldn't start the Hyprland Socket. (1) IPC will not work. " ) ;
return ;
}
2022-03-20 16:51:14 +01:00
2022-03-30 16:24:42 +02:00
sockaddr_in SERVERADDRESS = { . sin_family = AF_INET , . sin_port = connectPort , . sin_addr = ( in_addr ) INADDR_ANY } ;
2022-03-20 16:51:14 +01:00
2022-03-30 16:24:42 +02:00
while ( connectPort < 11000 ) {
if ( bind ( SOCKET , ( sockaddr * ) & SERVERADDRESS , sizeof ( SERVERADDRESS ) ) < 0 ) {
Debug : : log ( LOG , " IPC: Port %d failed with an error: %s " , connectPort , strerror ( errno ) ) ;
} else {
2022-03-22 16:54:45 +01:00
break ;
}
2022-03-30 16:24:42 +02:00
connectPort + + ;
SERVERADDRESS . sin_port = connectPort ;
2022-03-20 16:51:14 +01:00
}
2022-03-30 16:24:42 +02:00
2022-03-20 16:51:14 +01:00
2022-03-21 18:29:41 +01:00
// 10 max queued.
listen ( SOCKET , 10 ) ;
sockaddr_in clientAddress ;
socklen_t clientSize = sizeof ( clientAddress ) ;
char readBuffer [ 1024 ] = { 0 } ;
2022-03-30 16:24:42 +02:00
Debug : : log ( LOG , " Hypr socket started on port %i " , connectPort ) ;
2022-03-21 18:29:41 +01:00
2022-03-24 18:25:18 +01:00
std : : string cmd = " rm -f /tmp/hypr/.socket " ;
2022-03-21 18:29:41 +01:00
system ( cmd . c_str ( ) ) ; // forgive me for using system() but it works and it doesnt matter here that much
2022-03-30 16:24:42 +02:00
cmd = " echo \" " + std : : to_string ( connectPort ) + " \" > /tmp/hypr/.socket " ;
2022-03-24 18:25:18 +01:00
system ( cmd . c_str ( ) ) ;
2022-03-21 18:29:41 +01:00
while ( 1 ) {
const auto ACCEPTEDCONNECTION = accept ( SOCKET , ( sockaddr * ) & clientAddress , & clientSize ) ;
if ( ACCEPTEDCONNECTION < 0 ) {
Debug : : log ( ERR , " Couldn't listen on the Hyprland Socket. (3) IPC will not work. " ) ;
break ;
}
auto messageSize = read ( ACCEPTEDCONNECTION , readBuffer , 1024 ) ;
readBuffer [ messageSize = = 1024 ? 1024 : messageSize ] = ' \0 ' ;
std : : string request ( readBuffer ) ;
2022-04-21 22:00:03 +02:00
std : : string reply = getRequestFromThread ( request ) ;
2022-04-21 16:11:29 +02:00
2022-03-21 18:29:41 +01:00
write ( ACCEPTEDCONNECTION , reply . c_str ( ) , reply . length ( ) ) ;
close ( ACCEPTEDCONNECTION ) ;
}
2022-03-22 16:54:45 +01:00
close ( SOCKET ) ;
2022-03-21 18:29:41 +01:00
} ) . detach ( ) ;
2022-03-20 16:51:14 +01:00
}