2022-03-20 16:51:14 +01:00
# include "HyprCtl.hpp"
2025-08-22 20:24:25 +03:00
# include "helpers/Monitor.hpp"
2022-03-20 16:51:14 +01:00
2024-11-11 13:44:41 +00:00
# include <algorithm>
2024-06-11 19:49:54 +02:00
# include <format>
2024-11-10 15:54:15 +00:00
# include <fstream>
2024-11-11 13:44:41 +00:00
# include <iterator>
2022-03-21 18:29:41 +01:00
# include <netinet/in.h>
2024-12-07 18:51:18 +01:00
# include <cstdio>
# include <cstdlib>
# include <cstring>
2022-03-21 18:29:41 +01:00
# 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>
2024-01-01 17:53:00 +01:00
# include <sys/utsname.h>
2022-05-24 19:42:43 +02:00
# include <sys/un.h>
2022-03-20 16:51:14 +01:00
# include <unistd.h>
2024-06-18 21:38:33 +02:00
# include <sys/poll.h>
2024-07-21 13:09:54 +02:00
# include <filesystem>
# include <ranges>
2025-04-29 18:59:43 +02:00
# include <sys/eventfd.h>
2022-03-20 16:51:14 +01:00
2023-01-31 00:03:23 +00:00
# include <sstream>
2022-03-20 16:51:14 +01:00
# include <string>
2024-02-18 15:00:34 +00:00
# include <typeindex>
2024-05-29 05:37:24 +08:00
# include <numeric>
2022-03-20 16:51:14 +01:00
2024-06-11 17:17:45 +02:00
# include <hyprutils/string/String.hpp>
2025-04-29 18:59:43 +02:00
# include <hyprutils/os/FileDescriptor.hpp>
2024-06-11 17:17:45 +02:00
using namespace Hyprutils : : String ;
2025-01-30 12:30:12 +01:00
using namespace Hyprutils : : OS ;
2024-07-21 13:09:54 +02:00
# include <aquamarine/input/Input.hpp>
2024-06-11 17:17:45 +02:00
2024-04-09 18:14:53 +03:00
# include "../config/ConfigDataValues.hpp"
2024-03-03 18:39:20 +00:00
# include "../config/ConfigValue.hpp"
2024-03-09 16:52:59 +00:00
# include "../managers/CursorManager.hpp"
2024-03-20 21:55:13 -04:00
# include "../hyprerror/HyprError.hpp"
2024-05-03 22:34:10 +01:00
# include "../devices/IPointer.hpp"
# include "../devices/IKeyboard.hpp"
# include "../devices/ITouch.hpp"
2024-05-06 02:15:26 +01:00
# include "../devices/Tablet.hpp"
2024-07-30 16:33:56 -05:00
# include "../protocols/GlobalShortcuts.hpp"
2024-06-14 13:11:40 +03:00
# include "debug/RollingLogFollow.hpp"
2024-05-25 20:46:07 +00:00
# include "config/ConfigManager.hpp"
2024-06-11 19:49:54 +02:00
# include "helpers/MiscFunctions.hpp"
2025-12-08 15:04:40 +00:00
# include "../desktop/view/LayerSurface.hpp"
2025-11-17 18:34:02 +00:00
# include "../desktop/rule/Engine.hpp"
2025-11-26 07:44:26 +09:00
# include "../desktop/state/FocusState.hpp"
2024-12-05 19:35:50 +00:00
# include "../version.h"
2024-03-03 18:39:20 +00:00
2025-01-17 15:21:35 +00:00
# include "../Compositor.hpp"
# include "../managers/input/InputManager.hpp"
# include "../managers/XWaylandManager.hpp"
# include "../managers/LayoutManager.hpp"
# include "../plugins/PluginSystem.hpp"
2025-08-28 11:20:29 +02:00
# include "../managers/animation/AnimationManager.hpp"
2025-01-17 15:21:35 +00:00
# include "../debug/HyprNotificationOverlay.hpp"
# include "../render/Renderer.hpp"
2025-03-29 03:19:35 +03:00
# include "../render/OpenGL.hpp"
2025-01-17 15:21:35 +00:00
2025-04-29 18:59:43 +02:00
# if defined(__DragonFly__) || defined(__FreeBSD__)
# include <sys/ucred.h>
# define CRED_T xucred
# define CRED_LVL SOL_LOCAL
# define CRED_OPT LOCAL_PEERCRED
# define CRED_PID cr_pid
# elif defined(__NetBSD__)
# define CRED_T unpcbid
# define CRED_LVL SOL_LOCAL
# define CRED_OPT LOCAL_PEEREID
# define CRED_PID unp_pid
# else
# if defined(__OpenBSD__)
# define CRED_T sockpeercred
# else
# define CRED_T ucred
# endif
# define CRED_LVL SOL_SOCKET
# define CRED_OPT SO_PEERCRED
# define CRED_PID pid
# endif
2023-05-24 08:46:56 -07:00
static void trimTrailingComma ( std : : string & str ) {
if ( ! str . empty ( ) & & str . back ( ) = = ' , ' )
str . pop_back ( ) ;
}
2024-03-05 13:55:33 +00:00
static std : : string formatToString ( uint32_t drmFormat ) {
switch ( drmFormat ) {
case DRM_FORMAT_XRGB2101010 : return " XRGB2101010 " ;
case DRM_FORMAT_XBGR2101010 : return " XBGR2101010 " ;
case DRM_FORMAT_XRGB8888 : return " XRGB8888 " ;
case DRM_FORMAT_XBGR8888 : return " XBGR8888 " ;
default : break ;
}
return " Invalid " ;
}
2024-10-19 23:03:29 +01:00
static std : : string availableModesForOutput ( PHLMONITOR pMonitor , eHyprCtlOutputFormat format ) {
2024-03-05 13:55:33 +00:00
std : : string result ;
2025-04-30 23:45:20 +02:00
for ( auto const & m : pMonitor - > m_output - > modes ) {
2024-07-21 13:09:54 +02:00
if ( format = = FORMAT_NORMAL )
result + = std : : format ( " {}x{}@{:.2f}Hz " , m - > pixelSize . x , m - > pixelSize . y , m - > refreshRate / 1000.0 ) ;
else
result + = std : : format ( " \" {}x{}@{:.2f}Hz \" , " , m - > pixelSize . x , m - > pixelSize . y , m - > refreshRate / 1000.0 ) ;
2024-03-05 13:55:33 +00:00
}
2024-07-21 13:09:54 +02:00
trimTrailingComma ( result ) ;
2024-03-05 13:55:33 +00:00
return result ;
}
2025-08-22 20:24:25 +03:00
const std : : array < const char * , CMonitor : : SC_CHECKS_COUNT > SOLITARY_REASONS_JSON = {
2025-09-17 14:03:49 +02:00
" \" UNKNOWN \" " , " \" NOTIFICATION \" " , " \" LOCK \" " , " \" WORKSPACE \" " , " \" WINDOWED \" " , " \" DND \" " , " \" SPECIAL \" " , " \" ALPHA \" " , " \" OFFSET \" " ,
" \" CANDIDATE \" " , " \" OPAQUE \" " , " \" TRANSFORM \" " , " \" OVERLAYS \" " , " \" FLOAT \" " , " \" WORKSPACES \" " , " \" SURFACES \" " , " \" CONFIGERROR \" " ,
2025-08-22 20:24:25 +03:00
} ;
const std : : array < const char * , CMonitor : : SC_CHECKS_COUNT > SOLITARY_REASONS_TEXT = {
2025-09-17 14:03:49 +02:00
" unknown reason " , " notification " , " session lock " , " invalid workspace " , " windowed mode " , " dnd active " ,
" special workspace " , " alpha channel " , " workspace offset " , " missing candidate " , " not opaque " , " surface transformations " ,
" other overlays " , " floating windows " , " other workspaces " , " subsurfaces " , " config error " ,
2025-08-22 20:24:25 +03:00
} ;
std : : string CHyprCtl : : getSolitaryBlockedReason ( Hyprutils : : Memory : : CSharedPointer < CMonitor > m , eHyprCtlOutputFormat format ) {
const auto reasons = m - > isSolitaryBlocked ( true ) ;
if ( ! reasons )
return " null " ;
std : : string reasonStr = " " ;
const auto TEXTS = format = = eHyprCtlOutputFormat : : FORMAT_JSON ? SOLITARY_REASONS_JSON : SOLITARY_REASONS_TEXT ;
2025-09-17 14:03:49 +02:00
for ( uint32_t i = 0 ; i < CMonitor : : SC_CHECKS_COUNT ; i + + ) {
2025-08-22 20:24:25 +03:00
if ( reasons & ( 1 < < i ) ) {
if ( reasonStr ! = " " )
reasonStr + = " , " ;
reasonStr + = TEXTS [ i ] ;
}
}
return format = = eHyprCtlOutputFormat : : FORMAT_JSON ? " [ " + reasonStr + " ] " : reasonStr ;
}
const std : : array < const char * , CMonitor : : DS_CHECKS_COUNT > DS_REASONS_JSON = {
" \" UNKNOWN \" " , " \" USER \" " , " \" WINDOWED \" " , " \" CONTENT \" " , " \" MIRROR \" " , " \" RECORD \" " , " \" SW \" " ,
2025-08-29 14:31:07 +03:00
" \" CANDIDATE \" " , " \" SURFACE \" " , " \" TRANSFORM \" " , " \" DMA \" " , " \" TEARING \" " , " \" FAILED \" " , " \" CM \" " ,
2025-08-22 20:24:25 +03:00
} ;
const std : : array < const char * , CMonitor : : DS_CHECKS_COUNT > DS_REASONS_TEXT = {
" unknown reason " , " user settings " , " windowed mode " , " content type " , " monitor mirrors " , " screen record/screenshot " , " software renders/cursors " ,
2025-08-29 14:31:07 +03:00
" missing candidate " , " invalid surface " , " surface transformations " , " invalid buffer " , " tearing " , " activation failed " , " color management " ,
2025-08-22 20:24:25 +03:00
} ;
std : : string CHyprCtl : : getDSBlockedReason ( Hyprutils : : Memory : : CSharedPointer < CMonitor > m , eHyprCtlOutputFormat format ) {
const auto reasons = m - > isDSBlocked ( true ) ;
if ( ! reasons )
return " null " ;
std : : string reasonStr = " " ;
const auto TEXTS = format = = eHyprCtlOutputFormat : : FORMAT_JSON ? DS_REASONS_JSON : DS_REASONS_TEXT ;
for ( int i = 0 ; i < CMonitor : : DS_CHECKS_COUNT ; i + + ) {
if ( reasons & ( 1 < < i ) ) {
if ( reasonStr ! = " " )
reasonStr + = " , " ;
reasonStr + = TEXTS [ i ] ;
}
}
return format = = eHyprCtlOutputFormat : : FORMAT_JSON ? " [ " + reasonStr + " ] " : reasonStr ;
}
const std : : array < const char * , CMonitor : : TC_CHECKS_COUNT > TEARING_REASONS_JSON = {
" \" UNKNOWN \" " , " \" NOT_TORN \" " , " \" USER \" " , " \" ZOOM \" " , " \" SUPPORT \" " , " \" CANDIDATE \" " , " \" WINDOW \" " ,
} ;
const std : : array < const char * , CMonitor : : TC_CHECKS_COUNT > TEARING_REASONS_TEXT = {
" unknown reason " , " next frame is not torn " , " user settings " , " zoom " , " not supported by monitor " , " missing candidate " , " window settings " ,
} ;
std : : string CHyprCtl : : getTearingBlockedReason ( Hyprutils : : Memory : : CSharedPointer < CMonitor > m , eHyprCtlOutputFormat format ) {
const auto reasons = m - > isTearingBlocked ( true ) ;
if ( ! reasons | | ( reasons = = CMonitor : : TC_NOT_TORN & & m - > m_tearingState . activelyTearing ) )
return " null " ;
std : : string reasonStr = " " ;
const auto TEXTS = format = = eHyprCtlOutputFormat : : FORMAT_JSON ? TEARING_REASONS_JSON : TEARING_REASONS_TEXT ;
for ( int i = 0 ; i < CMonitor : : TC_CHECKS_COUNT ; i + + ) {
if ( reasons & ( 1 < < i ) ) {
if ( reasonStr ! = " " )
reasonStr + = " , " ;
reasonStr + = TEXTS [ i ] ;
}
}
return format = = eHyprCtlOutputFormat : : FORMAT_JSON ? " [ " + reasonStr + " ] " : reasonStr ;
}
2024-07-07 17:52:56 +02:00
std : : string CHyprCtl : : getMonitorData ( Hyprutils : : Memory : : CSharedPointer < CMonitor > m , eHyprCtlOutputFormat format ) {
std : : string result ;
2025-04-30 23:45:20 +02:00
if ( ! m - > m_output | | m - > m_id = = - 1 )
2024-07-07 17:52:56 +02:00
return " " ;
2023-03-16 00:18:39 +00:00
2024-07-21 13:09:54 +02:00
if ( format = = eHyprCtlOutputFormat : : FORMAT_JSON ) {
result + = std : : format (
R " #({{
2023-09-06 12:51:36 +02:00
" id " : { } ,
" name " : " {} " ,
" description " : " {} " ,
" make " : " {} " ,
" model " : " {} " ,
" serial " : " {} " ,
" width " : { } ,
" height " : { } ,
2025-08-04 21:28:54 +02:00
" physicalWidth " : { } ,
" physicalHeight " : { } ,
2023-09-06 12:51:36 +02:00
" refreshRate " : { : .5f } ,
" x " : { } ,
" y " : { } ,
" activeWorkspace " : { {
" id " : { } ,
" name " : " {} "
} } ,
" specialWorkspace " : { {
" id " : { } ,
" name " : " {} "
} } ,
" reserved " : [ { } , { } , { } , { } ] ,
" scale " : { : .2f } ,
" transform " : { } ,
" focused " : { } ,
" dpmsStatus " : { } ,
2023-09-30 13:08:55 +01:00
" vrr " : { } ,
2024-09-25 09:59:18 +01:00
" solitary " : " {:x} " ,
2025-08-22 20:24:25 +03:00
" solitaryBlockedBy " : { } ,
2024-03-05 13:55:33 +00:00
" activelyTearing " : { } ,
2025-08-22 20:24:25 +03:00
" tearingBlockedBy " : { } ,
2024-12-05 19:33:54 +00:00
" directScanoutTo " : " {:x} " ,
2025-08-22 20:24:25 +03:00
" directScanoutBlockedBy " : { } ,
2024-04-10 09:50:00 +01:00
" disabled " : { } ,
2024-03-05 13:55:33 +00:00
" currentFormat " : " {} " ,
2024-11-05 16:20:04 +00:00
" mirrorOf " : " {} " ,
2025-10-24 21:18:39 +02:00
" availableModes " : [ { } ] ,
" colorManagementPreset " : " {} " ,
" sdrBrightness " : { : .2f } ,
" sdrSaturation " : { : .2f } ,
" sdrMinLuminance " : { : .2f } ,
" sdrMaxLuminance " : { }
2023-09-06 12:51:36 +02:00
} } , ) # " ,
2024-07-21 13:09:54 +02:00
2025-04-30 23:45:20 +02:00
m - > m_id , escapeJSONStrings ( m - > m_name ) , escapeJSONStrings ( m - > m_shortDescription ) , escapeJSONStrings ( m - > m_output - > make ) , escapeJSONStrings ( m - > m_output - > model ) ,
2025-08-22 20:24:25 +03:00
escapeJSONStrings ( m - > m_output - > serial ) , sc < int > ( m - > m_pixelSize . x ) , sc < int > ( m - > m_pixelSize . y ) , sc < int > ( m - > m_output - > physicalSize . x ) ,
sc < int > ( m - > m_output - > physicalSize . y ) , m - > m_refreshRate , sc < int > ( m - > m_position . x ) , sc < int > ( m - > m_position . y ) , m - > activeWorkspaceID ( ) ,
2025-08-14 19:44:56 +05:00
( ! m - > m_activeWorkspace ? " " : escapeJSONStrings ( m - > m_activeWorkspace - > m_name ) ) , m - > activeSpecialWorkspaceID ( ) ,
2025-12-05 14:16:22 +00:00
escapeJSONStrings ( m - > m_activeSpecialWorkspace ? m - > m_activeSpecialWorkspace - > m_name : " " ) , sc < int > ( m - > m_reservedArea . left ( ) ) , sc < int > ( m - > m_reservedArea . top ( ) ) ,
sc < int > ( m - > m_reservedArea . right ( ) ) , sc < int > ( m - > m_reservedArea . bottom ( ) ) , m - > m_scale , sc < int > ( m - > m_transform ) ,
2025-11-26 07:44:26 +09:00
( m = = Desktop : : focusState ( ) - > monitor ( ) ? " true " : " false " ) , ( m - > m_dpmsStatus ? " true " : " false " ) , ( m - > m_output - > state - > state ( ) . adaptiveSync ? " true " : " false " ) ,
rc < uint64_t > ( m - > m_solitaryClient . get ( ) ) , getSolitaryBlockedReason ( m , format ) , ( m - > m_tearingState . activelyTearing ? " true " : " false " ) ,
getTearingBlockedReason ( m , format ) , rc < uint64_t > ( m - > m_lastScanout . get ( ) ) , getDSBlockedReason ( m , format ) , ( m - > m_enabled ? " false " : " true " ) ,
formatToString ( m - > m_output - > state - > state ( ) . drmFormat ) , m - > m_mirrorOf ? std : : format ( " {} " , m - > m_mirrorOf - > m_id ) : " none " , availableModesForOutput ( m , format ) ,
( NCMType : : toString ( m - > m_cmType ) ) , ( m - > m_sdrBrightness ) , ( m - > m_sdrSaturation ) , ( m - > m_sdrMinLuminance ) , ( m - > m_sdrMaxLuminance ) ) ;
2024-07-21 13:09:54 +02:00
} else {
2025-08-04 21:28:54 +02:00
result + = std : : format (
" Monitor {} (ID {}): \n \t {}x{}@{:.5f} at {}x{} \n \t description: {} \n \t make: {} \n \t model: {} \n \t physical size (mm): {}x{} \n \t serial: {} \n \t active workspace: {} ({}) \n \t "
" special workspace: {} ({}) \n \t reserved: {} {} {} {} \n \t scale: {:.2f} \n \t transform: {} \n \t focused: {} \n \t "
2025-08-22 20:24:25 +03:00
" dpmsStatus: {} \n \t vrr: {} \n \t solitary: {:x} \n \t solitaryBlockedBy: {} \n \t activelyTearing: {} \n \t tearingBlockedBy: {} \n \t directScanoutTo: "
" {:x} \n \t directScanoutBlockedBy: {} \n \t disabled: "
" {} \n \t currentFormat: {} \n \t mirrorOf: "
2025-10-24 21:18:39 +02:00
" {} \n \t availableModes: {} \n \t colorManagementPreset: {} \n \t sdrBrightness: {:.2f} \n \t sdrSaturation: {:.2f} \n \t sdrMinLuminance: {:.2f} \n \t sdrMaxLuminance: {} \n \n " ,
2025-08-14 19:44:56 +05:00
m - > m_name , m - > m_id , sc < int > ( m - > m_pixelSize . x ) , sc < int > ( m - > m_pixelSize . y ) , m - > m_refreshRate , sc < int > ( m - > m_position . x ) , sc < int > ( m - > m_position . y ) , m - > m_shortDescription ,
m - > m_output - > make , m - > m_output - > model , sc < int > ( m - > m_output - > physicalSize . x ) , sc < int > ( m - > m_output - > physicalSize . y ) , m - > m_output - > serial , m - > activeWorkspaceID ( ) ,
2025-08-04 21:28:54 +02:00
( ! m - > m_activeWorkspace ? " " : m - > m_activeWorkspace - > m_name ) , m - > activeSpecialWorkspaceID ( ) , ( m - > m_activeSpecialWorkspace ? m - > m_activeSpecialWorkspace - > m_name : " " ) ,
2025-12-05 14:16:22 +00:00
sc < int > ( m - > m_reservedArea . left ( ) ) , sc < int > ( m - > m_reservedArea . top ( ) ) , sc < int > ( m - > m_reservedArea . right ( ) ) , sc < int > ( m - > m_reservedArea . bottom ( ) ) , m - > m_scale ,
2025-11-26 07:44:26 +09:00
sc < int > ( m - > m_transform ) , ( m = = Desktop : : focusState ( ) - > monitor ( ) ? " yes " : " no " ) , sc < int > ( m - > m_dpmsStatus ) , m - > m_output - > state - > state ( ) . adaptiveSync ,
2025-08-22 20:24:25 +03:00
rc < uint64_t > ( m - > m_solitaryClient . get ( ) ) , getSolitaryBlockedReason ( m , format ) , m - > m_tearingState . activelyTearing , getTearingBlockedReason ( m , format ) ,
rc < uint64_t > ( m - > m_lastScanout . get ( ) ) , getDSBlockedReason ( m , format ) , ! m - > m_enabled , formatToString ( m - > m_output - > state - > state ( ) . drmFormat ) ,
2025-10-24 21:18:39 +02:00
m - > m_mirrorOf ? std : : format ( " {} " , m - > m_mirrorOf - > m_id ) : " none " , availableModesForOutput ( m , format ) , ( NCMType : : toString ( m - > m_cmType ) ) , ( m - > m_sdrBrightness ) ,
( m - > m_sdrSaturation ) , ( m - > m_sdrMinLuminance ) , ( m - > m_sdrMaxLuminance ) ) ;
2024-07-21 13:09:54 +02:00
}
2024-07-07 17:52:56 +02:00
return result ;
}
2024-12-18 19:56:01 -06:00
static std : : string monitorsRequest ( eHyprCtlOutputFormat format , std : : string request ) {
2024-07-07 17:52:56 +02:00
CVarList vars ( request , 0 , ' ' ) ;
auto allMonitors = false ;
if ( vars . size ( ) > 2 )
return " too many args " ;
if ( vars . size ( ) = = 2 & & vars [ 1 ] = = " all " )
allMonitors = true ;
std : : string result = " " ;
if ( format = = eHyprCtlOutputFormat : : FORMAT_JSON ) {
result + = " [ " ;
2025-04-22 15:23:29 +02:00
for ( auto const & m : allMonitors ? g_pCompositor - > m_realMonitors : g_pCompositor - > m_monitors ) {
2024-07-07 17:52:56 +02:00
result + = CHyprCtl : : getMonitorData ( m , format ) ;
2022-07-12 11:57:33 -06:00
}
2023-05-24 08:46:56 -07:00
trimTrailingComma ( result ) ;
2022-07-12 11:57:33 -06:00
result + = " ] " ;
} else {
2025-04-22 15:23:29 +02:00
for ( auto const & m : allMonitors ? g_pCompositor - > m_realMonitors : g_pCompositor - > m_monitors ) {
2025-04-30 23:45:20 +02:00
if ( ! m - > m_output | | m - > m_id = = - 1 )
2023-03-16 00:18:39 +00:00
continue ;
2024-09-25 23:38:11 +01:00
result + = CHyprCtl : : getMonitorData ( m , format ) ;
2022-07-12 11:57:33 -06:00
}
2022-03-20 16:51:14 +01:00
}
return result ;
}
2024-05-29 05:37:24 +08:00
static std : : string getTagsData ( PHLWINDOW w , eHyprCtlOutputFormat format ) {
2025-11-17 18:34:02 +00:00
const auto tags = w - > m_ruleApplicator - > m_tagKeeper . getTags ( ) ;
2024-05-29 05:37:24 +08:00
if ( format = = eHyprCtlOutputFormat : : FORMAT_JSON )
2025-05-30 18:25:59 +05:00
return std : : ranges : : fold_left ( tags , std : : string ( ) ,
[ ] ( const std : : string & a , const std : : string & b ) { return a . empty ( ) ? std : : format ( " \" {} \" " , b ) : std : : format ( " {}, \" {} \" " , a , b ) ; } ) ;
2024-05-29 05:37:24 +08:00
else
2025-05-30 18:25:59 +05:00
return std : : ranges : : fold_left ( tags , std : : string ( ) , [ ] ( const std : : string & a , const std : : string & b ) { return a . empty ( ) ? b : a + " , " + b ; } ) ;
2024-05-29 05:37:24 +08:00
}
2024-04-27 12:43:12 +01:00
static std : : string getGroupedData ( PHLWINDOW w , eHyprCtlOutputFormat format ) {
2024-02-05 01:56:38 +00:00
const bool isJson = format = = eHyprCtlOutputFormat : : FORMAT_JSON ;
2025-04-28 22:25:22 +02:00
if ( w - > m_groupData . pNextWindow . expired ( ) )
2022-12-04 13:03:29 -08:00
return isJson ? " " : " 0 " ;
std : : ostringstream result ;
2024-04-27 12:43:12 +01:00
PHLWINDOW head = w - > getGroupHead ( ) ;
PHLWINDOW curr = head ;
2023-11-09 17:05:05 +01:00
while ( true ) {
2023-09-20 07:26:20 +00:00
if ( isJson )
2025-08-14 19:44:56 +05:00
result < < std : : format ( " \" 0x{:x} \" " , rc < uintptr_t > ( curr . get ( ) ) ) ;
2023-09-20 07:26:20 +00:00
else
2025-08-14 19:44:56 +05:00
result < < std : : format ( " {:x} " , rc < uintptr_t > ( curr . get ( ) ) ) ;
2025-04-28 22:25:22 +02:00
curr = curr - > m_groupData . pNextWindow . lock ( ) ;
2023-11-09 17:05:05 +01:00
// We've wrapped around to the start, break out without trailing comma
if ( curr = = head )
break ;
result < < ( isJson ? " , " : " , " ) ;
2022-12-04 13:03:29 -08:00
}
return result . str ( ) ;
}
2024-07-07 17:52:56 +02:00
std : : string CHyprCtl : : getWindowData ( PHLWINDOW w , eHyprCtlOutputFormat format ) {
2024-04-27 12:43:12 +01:00
auto getFocusHistoryID = [ ] ( PHLWINDOW wnd ) - > int {
2025-11-26 07:44:26 +09:00
for ( size_t i = 0 ; i < Desktop : : focusState ( ) - > windowHistory ( ) . size ( ) ; + + i ) {
if ( Desktop : : focusState ( ) - > windowHistory ( ) [ i ] . lock ( ) = = wnd )
2023-10-28 17:22:31 +01:00
return i ;
}
return - 1 ;
} ;
2024-02-05 01:56:38 +00:00
if ( format = = eHyprCtlOutputFormat : : FORMAT_JSON ) {
2023-09-20 07:26:20 +00:00
return std : : format (
2023-09-06 12:51:36 +02:00
R " #({{
" address " : " 0x{:x} " ,
" mapped " : { } ,
" hidden " : { } ,
" at " : [ { } , { } ] ,
" size " : [ { } , { } ] ,
" workspace " : { {
" id " : { } ,
" name " : " {} "
} } ,
" floating " : { } ,
2024-06-19 23:19:18 +02:00
" pseudo " : { } ,
2023-09-06 12:51:36 +02:00
" monitor " : { } ,
" class " : " {} " ,
" title " : " {} " ,
" initialClass " : " {} " ,
" initialTitle " : " {} " ,
" pid " : { } ,
" xwayland " : { } ,
" pinned " : { } ,
" fullscreen " : { } ,
2024-07-31 17:55:52 +00:00
" fullscreenClient " : { } ,
2023-09-06 12:51:36 +02:00
" grouped " : [ { } ] ,
2024-05-29 05:37:24 +08:00
" tags " : [ { } ] ,
2023-10-28 17:22:31 +01:00
" swallowing " : " 0x{:x} " ,
2024-12-13 21:30:19 +00:00
" focusHistoryID " : { } ,
2025-04-21 22:22:06 +01:00
" inhibitingIdle " : { } ,
" xdgTag " : " {} " ,
2025-11-20 07:01:07 -05:00
" xdgDescription " : " {} " ,
" contentType " : " {} "
2023-09-06 12:51:36 +02:00
} } , ) # " ,
2025-08-14 19:44:56 +05:00
rc < uintptr_t > ( w . get ( ) ) , ( w - > m_isMapped ? " true " : " false " ) , ( w - > isHidden ( ) ? " true " : " false " ) , sc < int > ( w - > m_realPosition - > goal ( ) . x ) ,
sc < int > ( w - > m_realPosition - > goal ( ) . y ) , sc < int > ( w - > m_realSize - > goal ( ) . x ) , sc < int > ( w - > m_realSize - > goal ( ) . y ) , w - > m_workspace ? w - > workspaceID ( ) : WORKSPACE_INVALID ,
escapeJSONStrings ( ! w - > m_workspace ? " " : w - > m_workspace - > m_name ) , ( sc < int > ( w - > m_isFloating ) = = 1 ? " true " : " false " ) , ( w - > m_isPseudotiled ? " true " : " false " ) ,
w - > monitorID ( ) , escapeJSONStrings ( w - > m_class ) , escapeJSONStrings ( w - > m_title ) , escapeJSONStrings ( w - > m_initialClass ) , escapeJSONStrings ( w - > m_initialTitle ) , w - > getPID ( ) ,
( sc < int > ( w - > m_isX11 ) = = 1 ? " true " : " false " ) , ( w - > m_pinned ? " true " : " false " ) , sc < uint8_t > ( w - > m_fullscreenState . internal ) , sc < uint8_t > ( w - > m_fullscreenState . client ) ,
getGroupedData ( w , format ) , getTagsData ( w , format ) , rc < uintptr_t > ( w - > m_swallowed . get ( ) ) , getFocusHistoryID ( w ) ,
2025-11-20 07:01:07 -05:00
( g_pInputManager - > isWindowInhibiting ( w , false ) ? " true " : " false " ) , escapeJSONStrings ( w - > xdgTag ( ) . value_or ( " " ) ) , escapeJSONStrings ( w - > xdgDescription ( ) . value_or ( " " ) ) ,
escapeJSONStrings ( NContentType : : toString ( w - > getContentType ( ) ) ) ) ;
2022-11-13 01:39:21 +01:00
} else {
2024-06-19 23:19:18 +02:00
return std : : format (
" Window {:x} -> {}: \n \t mapped: {} \n \t hidden: {} \n \t at: {},{} \n \t size: {},{} \n \t workspace: {} ({}) \n \t floating: {} \n \t pseudo: {} \n \t monitor: {} \n \t class: {} \n \t title: "
" {} \n \t initialClass: {} \n \t initialTitle: {} \n \t pid: "
" {} \n \t xwayland: {} \n \t pinned: "
2025-04-21 22:22:06 +01:00
" {} \n \t fullscreen: {} \n \t fullscreenClient: {} \n \t grouped: {} \n \t tags: {} \n \t swallowing: {:x} \n \t focusHistoryID: {} \n \t inhibitingIdle: {} \n \t xdgTag: "
2025-11-20 07:01:07 -05:00
" {} \n \t xdgDescription: {} \n \t contentType: {} \n \n " ,
2025-08-14 19:44:56 +05:00
rc < uintptr_t > ( w . get ( ) ) , w - > m_title , sc < int > ( w - > m_isMapped ) , sc < int > ( w - > isHidden ( ) ) , sc < int > ( w - > m_realPosition - > goal ( ) . x ) , sc < int > ( w - > m_realPosition - > goal ( ) . y ) ,
sc < int > ( w - > m_realSize - > goal ( ) . x ) , sc < int > ( w - > m_realSize - > goal ( ) . y ) , w - > m_workspace ? w - > workspaceID ( ) : WORKSPACE_INVALID ,
( ! w - > m_workspace ? " " : w - > m_workspace - > m_name ) , sc < int > ( w - > m_isFloating ) , sc < int > ( w - > m_isPseudotiled ) , w - > monitorID ( ) , w - > m_class , w - > m_title , w - > m_initialClass ,
w - > m_initialTitle , w - > getPID ( ) , sc < int > ( w - > m_isX11 ) , sc < int > ( w - > m_pinned ) , sc < uint8_t > ( w - > m_fullscreenState . internal ) , sc < uint8_t > ( w - > m_fullscreenState . client ) ,
getGroupedData ( w , format ) , getTagsData ( w , format ) , rc < uintptr_t > ( w - > m_swallowed . get ( ) ) , getFocusHistoryID ( w ) , sc < int > ( g_pInputManager - > isWindowInhibiting ( w , false ) ) ,
2025-11-20 07:01:07 -05:00
w - > xdgTag ( ) . value_or ( " " ) , w - > xdgDescription ( ) . value_or ( " " ) , NContentType : : toString ( w - > getContentType ( ) ) ) ;
2022-11-13 01:39:21 +01:00
}
}
2024-12-18 19:56:01 -06:00
static std : : string clientsRequest ( eHyprCtlOutputFormat format , std : : string request ) {
2022-11-13 01:39:21 +01:00
std : : string result = " " ;
2024-02-05 01:56:38 +00:00
if ( format = = eHyprCtlOutputFormat : : FORMAT_JSON ) {
2022-11-13 01:39:21 +01:00
result + = " [ " ;
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 & & ! g_pHyprCtl - > m_currentRequestParams . all )
2024-03-08 17:47:12 +00:00
continue ;
2024-07-07 17:52:56 +02:00
result + = CHyprCtl : : getWindowData ( w , format ) ;
2022-07-12 11:57:33 -06:00
}
2023-05-24 08:46:56 -07:00
trimTrailingComma ( result ) ;
2022-07-12 11:57:33 -06:00
result + = " ] " ;
} else {
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 & & ! g_pHyprCtl - > m_currentRequestParams . all )
2024-03-08 17:47:12 +00:00
continue ;
2024-07-07 17:52:56 +02:00
result + = CHyprCtl : : getWindowData ( w , format ) ;
2022-06-27 13:17:11 +02:00
}
2025-06-23 13:49:24 +02:00
if ( result . empty ( ) )
return " no open windows " ;
2022-03-20 16:51:14 +01:00
}
return result ;
}
2024-07-07 17:52:56 +02:00
std : : string CHyprCtl : : getWorkspaceData ( PHLWORKSPACE w , eHyprCtlOutputFormat format ) {
2023-05-02 06:51:52 -07:00
const auto PLASTW = w - > getLastFocusedWindow ( ) ;
2025-04-25 02:37:12 +02:00
const auto PMONITOR = w - > m_monitor . lock ( ) ;
2024-02-05 01:56:38 +00:00
if ( format = = eHyprCtlOutputFormat : : FORMAT_JSON ) {
2023-09-20 07:26:20 +00:00
return std : : format ( R " #({{
2023-09-06 12:51:36 +02:00
" id " : { } ,
" name " : " {} " ,
" monitor " : " {} " ,
2023-10-24 01:03:40 +01:00
" monitorID " : { } ,
2023-09-06 12:51:36 +02:00
" windows " : { } ,
" hasfullscreen " : { } ,
" lastwindow " : " 0x{:x} " ,
2025-02-15 15:01:52 +01:00
" lastwindowtitle " : " {} " ,
" ispersistent " : { }
2023-09-06 12:51:36 +02:00
} } ) # " ,
2025-04-30 23:45:20 +02:00
w - > m_id , escapeJSONStrings ( w - > m_name ) , escapeJSONStrings ( PMONITOR ? PMONITOR - > m_name : " ? " ) ,
escapeJSONStrings ( PMONITOR ? std : : to_string ( PMONITOR - > m_id ) : " null " ) , w - > getWindows ( ) , w - > m_hasFullscreenWindow ? " true " : " false " ,
2025-08-14 19:44:56 +05:00
rc < uintptr_t > ( PLASTW . get ( ) ) , PLASTW ? escapeJSONStrings ( PLASTW - > m_title ) : " " , w - > isPersistent ( ) ? " true " : " false " ) ;
2023-05-02 06:51:52 -07:00
} else {
2025-02-15 15:01:52 +01:00
return std : : format (
" workspace ID {} ({}) on monitor {}: \n \t monitorID: {} \n \t windows: {} \n \t hasfullscreen: {} \n \t lastwindow: 0x{:x} \n \t lastwindowtitle: {} \n \t ispersistent: {} \n \n " ,
2025-08-14 19:44:56 +05:00
w - > m_id , w - > m_name , PMONITOR ? PMONITOR - > m_name : " ? " , PMONITOR ? std : : to_string ( PMONITOR - > m_id ) : " null " , w - > getWindows ( ) , sc < int > ( w - > m_hasFullscreenWindow ) ,
rc < uintptr_t > ( PLASTW . get ( ) ) , PLASTW ? PLASTW - > m_title : " " , sc < int > ( w - > isPersistent ( ) ) ) ;
2023-05-02 06:51:52 -07:00
}
}
2024-02-05 01:56:38 +00:00
static std : : string getWorkspaceRuleData ( const SWorkspaceRule & r , eHyprCtlOutputFormat format ) {
2023-10-21 03:28:34 +02:00
const auto boolToString = [ ] ( const bool b ) - > std : : string { return b ? " true " : " false " ; } ;
2024-02-05 01:56:38 +00:00
if ( format = = eHyprCtlOutputFormat : : FORMAT_JSON ) {
2024-09-24 01:19:05 +01:00
const std : : string monitor = r . monitor . empty ( ) ? " " : std : : format ( " , \n \" monitor \" : \" {} \" " , escapeJSONStrings ( r . monitor ) ) ;
2025-08-14 19:44:56 +05:00
const std : : string default_ = sc < bool > ( r . isDefault ) ? std : : format ( " , \n \" default \" : {} " , boolToString ( r . isDefault ) ) : " " ;
const std : : string persistent = sc < bool > ( r . isPersistent ) ? std : : format ( " , \n \" persistent \" : {} " , boolToString ( r . isPersistent ) ) : " " ;
const std : : string gapsIn = sc < bool > ( r . gapsIn ) ?
2025-04-20 20:39:33 +02:00
std : : format ( " , \n \" gapsIn \" : [{}, {}, {}, {}] " , r . gapsIn . value ( ) . m_top , r . gapsIn . value ( ) . m_right , r . gapsIn . value ( ) . m_bottom , r . gapsIn . value ( ) . m_left ) :
2024-09-24 01:19:05 +01:00
" " ;
2025-08-14 19:44:56 +05:00
const std : : string gapsOut = sc < bool > ( r . gapsOut ) ?
2025-04-20 20:39:33 +02:00
std : : format ( " , \n \" gapsOut \" : [{}, {}, {}, {}] " , r . gapsOut . value ( ) . m_top , r . gapsOut . value ( ) . m_right , r . gapsOut . value ( ) . m_bottom , r . gapsOut . value ( ) . m_left ) :
2024-02-23 21:25:04 +00:00
" " ;
2025-08-14 19:44:56 +05:00
const std : : string borderSize = sc < bool > ( r . borderSize ) ? std : : format ( " , \n \" borderSize \" : {} " , r . borderSize . value ( ) ) : " " ;
const std : : string border = sc < bool > ( r . noBorder ) ? std : : format ( " , \n \" border \" : {} " , boolToString ( ! r . noBorder . value ( ) ) ) : " " ;
const std : : string rounding = sc < bool > ( r . noRounding ) ? std : : format ( " , \n \" rounding \" : {} " , boolToString ( ! r . noRounding . value ( ) ) ) : " " ;
const std : : string decorate = sc < bool > ( r . decorate ) ? std : : format ( " , \n \" decorate \" : {} " , boolToString ( r . decorate . value ( ) ) ) : " " ;
const std : : string shadow = sc < bool > ( r . noShadow ) ? std : : format ( " , \n \" shadow \" : {} " , boolToString ( ! r . noShadow . value ( ) ) ) : " " ;
2024-09-24 01:19:05 +01:00
const std : : string defaultName = r . defaultName . has_value ( ) ? std : : format ( " , \n \" defaultName \" : \" {} \" " , escapeJSONStrings ( r . defaultName . value ( ) ) ) : " " ;
std : : string result =
std : : format ( R " #({{
" workspaceString " : " {} " { } { } { } { } { } { } { } { } { } { } { }
2023-10-21 03:28:34 +02:00
} } ) # " ,
2024-09-24 01:19:05 +01:00
escapeJSONStrings ( r . workspaceString ) , monitor , default_ , persistent , gapsIn , gapsOut , borderSize , border , rounding , decorate , shadow , defaultName ) ;
2023-10-21 03:28:34 +02:00
return result ;
} else {
2025-04-20 20:39:33 +02:00
const std : : string monitor = std : : format ( " \t monitor: {} \n " , r . monitor . empty ( ) ? " <unset> " : escapeJSONStrings ( r . monitor ) ) ;
2025-08-14 19:44:56 +05:00
const std : : string default_ = std : : format ( " \t default: {} \n " , sc < bool > ( r . isDefault ) ? boolToString ( r . isDefault ) : " <unset> " ) ;
const std : : string persistent = std : : format ( " \t persistent: {} \n " , sc < bool > ( r . isPersistent ) ? boolToString ( r . isPersistent ) : " <unset> " ) ;
const std : : string gapsIn = sc < bool > ( r . gapsIn ) ? std : : format ( " \t gapsIn: {} {} {} {} \n " , std : : to_string ( r . gapsIn . value ( ) . m_top ) , std : : to_string ( r . gapsIn . value ( ) . m_right ) ,
std : : to_string ( r . gapsIn . value ( ) . m_bottom ) , std : : to_string ( r . gapsIn . value ( ) . m_left ) ) :
std : : format ( " \t gapsIn: <unset> \n " ) ;
const std : : string gapsOut = sc < bool > ( r . gapsOut ) ?
std : : format ( " \t gapsOut: {} {} {} {} \n " , std : : to_string ( r . gapsOut . value ( ) . m_top ) , std : : to_string ( r . gapsOut . value ( ) . m_right ) , std : : to_string ( r . gapsOut . value ( ) . m_bottom ) ,
std : : to_string ( r . gapsOut . value ( ) . m_left ) ) :
std : : format ( " \t gapsOut: <unset> \n " ) ;
const std : : string borderSize = std : : format ( " \t borderSize: {} \n " , sc < bool > ( r . borderSize ) ? std : : to_string ( r . borderSize . value ( ) ) : " <unset> " ) ;
const std : : string border = std : : format ( " \t border: {} \n " , sc < bool > ( r . noBorder ) ? boolToString ( ! r . noBorder . value ( ) ) : " <unset> " ) ;
const std : : string rounding = std : : format ( " \t rounding: {} \n " , sc < bool > ( r . noRounding ) ? boolToString ( ! r . noRounding . value ( ) ) : " <unset> " ) ;
const std : : string decorate = std : : format ( " \t decorate: {} \n " , sc < bool > ( r . decorate ) ? boolToString ( r . decorate . value ( ) ) : " <unset> " ) ;
const std : : string shadow = std : : format ( " \t shadow: {} \n " , sc < bool > ( r . noShadow ) ? boolToString ( ! r . noShadow . value ( ) ) : " <unset> " ) ;
2024-09-24 01:19:05 +01:00
const std : : string defaultName = std : : format ( " \t defaultName: {} \n " , r . defaultName . value_or ( " <unset> " ) ) ;
std : : string result = std : : format ( " Workspace rule {}: \n {}{}{}{}{}{}{}{}{}{}{} \n " , escapeJSONStrings ( r . workspaceString ) , monitor , default_ , persistent , gapsIn , gapsOut ,
borderSize , border , rounding , decorate , shadow , defaultName ) ;
2023-10-21 03:28:34 +02:00
return result ;
}
}
2024-12-18 19:56:01 -06:00
static std : : string activeWorkspaceRequest ( eHyprCtlOutputFormat format , std : : string request ) {
2025-11-26 07:44:26 +09:00
if ( ! Desktop : : focusState ( ) - > monitor ( ) )
2023-09-25 15:00:19 +01:00
return " unsafe state " ;
2023-05-02 06:51:52 -07:00
std : : string result = " " ;
2025-11-26 07:44:26 +09:00
auto w = Desktop : : focusState ( ) - > monitor ( ) - > m_activeWorkspace ;
2023-09-25 15:00:19 +01:00
2024-04-02 20:32:39 +01:00
if ( ! valid ( w ) )
2023-09-25 15:00:19 +01:00
return " internal error " ;
2024-07-07 17:52:56 +02:00
return CHyprCtl : : getWorkspaceData ( w , format ) ;
2023-05-02 06:51:52 -07:00
}
2024-12-18 19:56:01 -06:00
static std : : string workspacesRequest ( eHyprCtlOutputFormat format , std : : string request ) {
2023-05-02 06:51:52 -07:00
std : : string result = " " ;
2024-02-05 01:56:38 +00:00
if ( format = = eHyprCtlOutputFormat : : FORMAT_JSON ) {
2023-05-02 06:51:52 -07:00
result + = " [ " ;
2025-07-24 00:36:29 +02:00
for ( auto const & w : g_pCompositor - > getWorkspaces ( ) ) {
result + = CHyprCtl : : getWorkspaceData ( w . lock ( ) , format ) ;
2023-05-02 06:51:52 -07:00
result + = " , " ;
2022-07-12 11:57:33 -06:00
}
2023-05-24 08:46:56 -07:00
trimTrailingComma ( result ) ;
2022-07-12 11:57:33 -06:00
result + = " ] " ;
} else {
2025-07-24 00:36:29 +02:00
for ( auto const & w : g_pCompositor - > getWorkspaces ( ) ) {
result + = CHyprCtl : : getWorkspaceData ( w . lock ( ) , format ) ;
2022-07-12 11:57:33 -06:00
}
2022-03-20 16:51:14 +01:00
}
2023-05-02 06:51:52 -07:00
2022-03-20 16:51:14 +01:00
return result ;
}
2024-12-18 19:56:01 -06:00
static std : : string workspaceRulesRequest ( eHyprCtlOutputFormat format , std : : string request ) {
2023-10-21 03:28:34 +02:00
std : : string result = " " ;
2024-02-05 01:56:38 +00:00
if ( format = = eHyprCtlOutputFormat : : FORMAT_JSON ) {
2023-10-21 03:28:34 +02:00
result + = " [ " ;
2024-08-26 17:25:39 +02:00
for ( auto const & r : g_pConfigManager - > getAllWorkspaceRules ( ) ) {
2023-10-21 03:28:34 +02:00
result + = getWorkspaceRuleData ( r , format ) ;
result + = " , " ;
}
trimTrailingComma ( result ) ;
result + = " ] " ;
} else {
2024-08-26 17:25:39 +02:00
for ( auto const & r : g_pConfigManager - > getAllWorkspaceRules ( ) ) {
2023-10-21 03:28:34 +02:00
result + = getWorkspaceRuleData ( r , format ) ;
}
}
return result ;
}
2024-12-18 19:56:01 -06:00
static std : : string activeWindowRequest ( eHyprCtlOutputFormat format , std : : string request ) {
2025-11-26 07:44:26 +09:00
const auto PWINDOW = Desktop : : focusState ( ) - > window ( ) ;
2022-03-22 16:54:45 +01:00
2024-04-27 12:43:12 +01:00
if ( ! validMapped ( PWINDOW ) )
2024-02-05 01:56:38 +00:00
return format = = eHyprCtlOutputFormat : : FORMAT_JSON ? " {} " : " Invalid " ;
2022-11-13 11:12:04 +00:00
2024-07-07 17:52:56 +02:00
auto result = CHyprCtl : : getWindowData ( PWINDOW , format ) ;
2022-12-16 17:17:31 +00:00
2024-02-05 01:56:38 +00:00
if ( format = = eHyprCtlOutputFormat : : FORMAT_JSON )
2022-11-13 11:12:04 +00:00
result . pop_back ( ) ;
return result ;
2022-03-22 16:54:45 +01:00
}
2024-12-18 19:56:01 -06:00
static std : : string layersRequest ( eHyprCtlOutputFormat format , std : : string request ) {
2022-03-22 16:54:45 +01:00
std : : string result = " " ;
2024-02-05 01:56:38 +00:00
if ( format = = eHyprCtlOutputFormat : : FORMAT_JSON ) {
2022-07-12 11:57:33 -06:00
result + = " { \n " ;
2025-04-22 15:23:29 +02:00
for ( auto const & mon : g_pCompositor - > m_monitors ) {
2023-09-20 07:26:20 +00:00
result + = std : : format (
2023-09-06 12:51:36 +02:00
R " #( " { } " : {{
" levels " : { {
2022-07-12 11:57:33 -06:00
) # " ,
2025-04-30 23:45:20 +02:00
escapeJSONStrings ( mon - > m_name ) ) ;
2022-07-12 11:57:33 -06:00
int layerLevel = 0 ;
2025-04-30 23:45:20 +02:00
for ( auto const & level : mon - > m_layerSurfaceLayers ) {
2023-09-20 07:26:20 +00:00
result + = std : : format (
2022-12-16 17:17:31 +00:00
R " #(
2023-09-06 12:51:36 +02:00
" {} " : [
2022-07-12 11:57:33 -06:00
) # " ,
2022-12-16 17:17:31 +00:00
layerLevel ) ;
2024-08-26 20:24:30 +02:00
for ( auto const & layer : level ) {
2023-09-20 07:26:20 +00:00
result + = std : : format (
2023-09-06 12:51:36 +02:00
R " #( {{
" address " : " 0x{:x} " ,
" x " : { } ,
" y " : { } ,
" w " : { } ,
" h " : { } ,
2025-02-26 23:03:06 +08:00
" namespace " : " {} " ,
" pid " : { }
2023-09-06 12:51:36 +02:00
} } , ) # " ,
2025-08-14 19:44:56 +05:00
rc < uintptr_t > ( layer . get ( ) ) , layer - > m_geometry . x , layer - > m_geometry . y , layer - > m_geometry . width , layer - > m_geometry . height ,
escapeJSONStrings ( layer - > m_namespace ) , layer - > getPID ( ) ) ;
2022-07-12 11:57:33 -06:00
}
2023-05-24 08:46:56 -07:00
trimTrailingComma ( result ) ;
2022-07-12 11:57:33 -06:00
2025-05-31 23:49:50 +05:00
if ( ! level . empty ( ) )
2022-07-12 11:57:33 -06:00
result + = " \n " ;
result + = " ], " ;
layerLevel + + ;
2022-03-22 16:54:45 +01:00
}
2023-05-24 08:46:56 -07:00
trimTrailingComma ( result ) ;
2022-07-12 11:57:33 -06:00
result + = " \n } \n }, " ;
}
2023-05-24 08:46:56 -07:00
trimTrailingComma ( result ) ;
2022-07-12 11:57:33 -06:00
result + = " \n } \n " ;
2022-09-25 20:07:48 +02:00
2022-07-12 11:57:33 -06:00
} else {
2025-04-22 15:23:29 +02:00
for ( auto const & mon : g_pCompositor - > m_monitors ) {
2025-04-30 23:45:20 +02:00
result + = std : : format ( " Monitor {}: \n " , mon - > m_name ) ;
2023-01-09 21:26:07 +01:00
int layerLevel = 0 ;
static const std : : array < std : : string , 4 > levelNames = { " background " , " bottom " , " top " , " overlay " } ;
2025-04-30 23:45:20 +02:00
for ( auto const & level : mon - > m_layerSurfaceLayers ) {
2023-09-20 07:26:20 +00:00
result + = std : : format ( " \t Layer level {} ({}): \n " , layerLevel , levelNames [ layerLevel ] ) ;
2022-07-12 11:57:33 -06:00
2024-08-26 20:24:30 +02:00
for ( auto const & layer : level ) {
2025-08-14 19:44:56 +05:00
result + = std : : format ( " \t \t Layer {:x}: xywh: {} {} {} {}, namespace: {}, pid: {} \n " , rc < uintptr_t > ( layer . get ( ) ) , layer - > m_geometry . x , layer - > m_geometry . y ,
2025-04-24 20:49:49 +02:00
layer - > m_geometry . width , layer - > m_geometry . height , layer - > m_namespace , layer - > getPID ( ) ) ;
2022-07-12 11:57:33 -06:00
}
layerLevel + + ;
}
result + = " \n \n " ;
2022-03-22 16:54:45 +01:00
}
}
return result ;
}
2024-12-18 19:56:01 -06:00
static std : : string layoutsRequest ( eHyprCtlOutputFormat format , std : : string request ) {
2023-11-21 13:43:38 -05:00
std : : string result = " " ;
2024-02-05 01:56:38 +00:00
if ( format = = eHyprCtlOutputFormat : : FORMAT_JSON ) {
2023-11-21 13:43:38 -05:00
result + = " [ " ;
2024-08-26 20:24:30 +02:00
for ( auto const & m : g_pLayoutManager - > getAllLayoutNames ( ) ) {
2023-11-21 13:43:38 -05:00
result + = std : : format (
R " #(
" {} " , ) # " ,
m ) ;
}
trimTrailingComma ( result ) ;
result + = " \n ] \n " ;
} else {
2024-08-26 20:24:30 +02:00
for ( auto const & m : g_pLayoutManager - > getAllLayoutNames ( ) ) {
2023-11-21 13:43:38 -05:00
result + = std : : format ( " {} \n " , m ) ;
}
}
return result ;
}
2024-12-18 19:56:01 -06:00
static std : : string configErrorsRequest ( eHyprCtlOutputFormat format , std : : string request ) {
2024-03-20 21:55:13 -04:00
std : : string result = " " ;
std : : string currErrors = g_pConfigManager - > getErrors ( ) ;
CVarList errLines ( currErrors , 0 , ' \n ' ) ;
if ( format = = eHyprCtlOutputFormat : : FORMAT_JSON ) {
result + = " [ " ;
2024-12-07 18:51:18 +01:00
for ( const auto & line : errLines ) {
2024-03-20 21:55:13 -04:00
result + = std : : format (
R " #(
" {} " , ) # " ,
escapeJSONStrings ( line ) ) ;
}
trimTrailingComma ( result ) ;
result + = " \n ] \n " ;
} else {
2024-12-07 18:51:18 +01:00
for ( const auto & line : errLines ) {
2024-03-20 21:55:13 -04:00
result + = std : : format ( " {} \n " , line ) ;
}
}
return result ;
}
2024-12-18 19:56:01 -06:00
static std : : string devicesRequest ( eHyprCtlOutputFormat format , std : : string request ) {
2022-06-02 13:59:33 +02:00
std : : string result = " " ;
2024-10-24 15:01:08 +02:00
auto getModState = [ ] ( SP < IKeyboard > keyboard , const char * xkbModName ) - > bool {
2025-04-29 19:51:07 +02:00
auto IDX = xkb_keymap_mod_get_index ( keyboard - > m_xkbKeymap , xkbModName ) ;
2024-10-24 15:01:08 +02:00
if ( IDX = = XKB_MOD_INVALID )
return false ;
2025-04-29 19:51:07 +02:00
return ( keyboard - > m_modifiersState . locked & ( 1 < < IDX ) ) > 0 ;
2024-10-24 15:01:08 +02:00
} ;
2024-02-05 01:56:38 +00:00
if ( format = = eHyprCtlOutputFormat : : FORMAT_JSON ) {
2022-07-12 11:57:33 -06:00
result + = " { \n " ;
result + = " \" mice \" : [ \n " ;
2025-05-01 23:57:11 +02:00
for ( auto const & m : g_pInputManager - > m_pointers ) {
2023-09-20 07:26:20 +00:00
result + = std : : format (
2023-09-06 12:51:36 +02:00
R " #( {{
" address " : " 0x{:x} " ,
" name " : " {} " ,
2025-09-02 13:16:43 +02:00
" defaultSpeed " : { : .5f } ,
" scrollFactor " : { : .2f }
2023-09-06 12:51:36 +02:00
} } , ) # " ,
2025-08-14 19:44:56 +05:00
rc < uintptr_t > ( m . get ( ) ) , escapeJSONStrings ( m - > m_hlName ) ,
2025-09-02 13:16:43 +02:00
m - > aq ( ) & & m - > aq ( ) - > getLibinputHandle ( ) ? libinput_device_config_accel_get_default_speed ( m - > aq ( ) - > getLibinputHandle ( ) ) : 0.f , m - > m_scrollFactor . value_or ( - 1 ) ) ;
2022-07-12 11:57:33 -06:00
}
2022-06-02 13:59:33 +02:00
2023-05-24 08:46:56 -07:00
trimTrailingComma ( result ) ;
2022-07-12 11:57:33 -06:00
result + = " \n ], \n " ;
result + = " \" keyboards \" : [ \n " ;
2025-05-01 23:57:11 +02:00
for ( auto const & k : g_pInputManager - > m_keyboards ) {
2025-09-09 15:19:51 +02:00
const auto INDEX_OPT = k - > getActiveLayoutIndex ( ) ;
const auto KI = INDEX_OPT . has_value ( ) ? std : : to_string ( INDEX_OPT . value ( ) ) : " none " ;
const auto KM = k - > getActiveLayout ( ) ;
2023-09-20 07:26:20 +00:00
result + = std : : format (
2023-09-06 12:51:36 +02:00
R " #( {{
" address " : " 0x{:x} " ,
" name " : " {} " ,
" rules " : " {} " ,
" model " : " {} " ,
" layout " : " {} " ,
" variant " : " {} " ,
" options " : " {} " ,
2025-09-09 15:19:51 +02:00
" active_layout_index " : { } ,
2023-09-06 12:51:36 +02:00
" active_keymap " : " {} " ,
2024-10-24 15:01:08 +02:00
" capsLock " : { } ,
" numLock " : { } ,
2023-09-06 12:51:36 +02:00
" main " : { }
} } , ) # " ,
2025-08-14 19:44:56 +05:00
rc < uintptr_t > ( k . get ( ) ) , escapeJSONStrings ( k - > m_hlName ) , escapeJSONStrings ( k - > m_currentRules . rules ) , escapeJSONStrings ( k - > m_currentRules . model ) ,
2025-09-09 15:19:51 +02:00
escapeJSONStrings ( k - > m_currentRules . layout ) , escapeJSONStrings ( k - > m_currentRules . variant ) , escapeJSONStrings ( k - > m_currentRules . options ) , KI , escapeJSONStrings ( KM ) ,
2025-04-29 19:51:07 +02:00
( getModState ( k , XKB_MOD_NAME_CAPS ) ? " true " : " false " ) , ( getModState ( k , XKB_MOD_NAME_NUM ) ? " true " : " false " ) , ( k - > m_active ? " true " : " false " ) ) ;
2022-07-12 11:57:33 -06:00
}
2022-06-02 13:59:33 +02:00
2023-05-24 08:46:56 -07:00
trimTrailingComma ( result ) ;
2022-07-12 11:57:33 -06:00
result + = " \n ], \n " ;
2022-06-02 13:59:33 +02:00
2022-07-12 11:57:33 -06:00
result + = " \" tablets \" : [ \n " ;
2022-06-02 13:59:33 +02:00
2025-05-01 23:57:11 +02:00
for ( auto const & d : g_pInputManager - > m_tabletPads ) {
2023-09-20 07:26:20 +00:00
result + = std : : format (
2023-09-06 12:51:36 +02:00
R " #( {{
" address " : " 0x{:x} " ,
2022-07-12 11:57:33 -06:00
" type " : " tabletPad " ,
2023-09-06 12:51:36 +02:00
" belongsTo " : { {
" address " : " 0x{:x} " ,
" name " : " {} "
} }
} } , ) # " ,
2025-08-14 19:44:56 +05:00
rc < uintptr_t > ( d . get ( ) ) , rc < uintptr_t > ( d - > m_parent . get ( ) ) , escapeJSONStrings ( d - > m_parent ? d - > m_parent - > m_hlName : " " ) ) ;
2022-07-12 11:57:33 -06:00
}
2022-06-09 19:25:26 +02:00
2025-05-01 23:57:11 +02:00
for ( auto const & d : g_pInputManager - > m_tablets ) {
2023-09-20 07:26:20 +00:00
result + = std : : format (
2023-09-06 12:51:36 +02:00
R " #( {{
" address " : " 0x{:x} " ,
" name " : " {} "
} } , ) # " ,
2025-08-14 19:44:56 +05:00
rc < uintptr_t > ( d . get ( ) ) , escapeJSONStrings ( d - > m_hlName ) ) ;
2022-07-12 11:57:33 -06:00
}
2022-06-09 19:25:26 +02:00
2025-05-01 23:57:11 +02:00
for ( auto const & d : g_pInputManager - > m_tabletTools ) {
2023-09-20 07:26:20 +00:00
result + = std : : format (
2023-09-06 12:51:36 +02:00
R " #( {{
" address " : " 0x{:x} " ,
2022-07-12 11:57:33 -06:00
" type " : " tabletTool " ,
2023-09-06 12:51:36 +02:00
} } , ) # " ,
2025-08-14 19:44:56 +05:00
rc < uintptr_t > ( d . get ( ) ) ) ;
2022-07-12 11:57:33 -06:00
}
2023-05-24 08:46:56 -07:00
trimTrailingComma ( result ) ;
2022-09-21 14:39:25 +01:00
result + = " \n ], \n " ;
result + = " \" touch \" : [ \n " ;
2025-05-01 23:57:11 +02:00
for ( auto const & d : g_pInputManager - > m_touches ) {
2023-09-20 07:26:20 +00:00
result + = std : : format (
2023-09-06 12:51:36 +02:00
R " #( {{
" address " : " 0x{:x} " ,
" name " : " {} "
} } , ) # " ,
2025-08-14 19:44:56 +05:00
rc < uintptr_t > ( d . get ( ) ) , escapeJSONStrings ( d - > m_hlName ) ) ;
2022-09-21 14:39:25 +01:00
}
2023-05-24 08:46:56 -07:00
trimTrailingComma ( result ) ;
2022-10-04 20:07:21 +01:00
result + = " \n ], \n " ;
result + = " \" switches \" : [ \n " ;
2025-05-01 23:57:11 +02:00
for ( auto const & d : g_pInputManager - > m_switches ) {
2023-09-20 07:26:20 +00:00
result + = std : : format (
2023-09-06 12:51:36 +02:00
R " #( {{
" address " : " 0x{:x} " ,
" name " : " {} "
} } , ) # " ,
2025-08-14 19:44:56 +05:00
rc < uintptr_t > ( & d ) , escapeJSONStrings ( d . pDevice ? d . pDevice - > getName ( ) : " " ) ) ;
2022-10-04 20:07:21 +01:00
}
2023-05-24 08:46:56 -07:00
trimTrailingComma ( result ) ;
2022-07-12 11:57:33 -06:00
result + = " \n ] \n " ;
2022-06-09 19:25:26 +02:00
2022-07-12 11:57:33 -06:00
result + = " } \n " ;
} else {
result + = " mice: \n " ;
2025-05-01 23:57:11 +02:00
for ( auto const & m : g_pInputManager - > m_pointers ) {
2025-09-02 13:16:43 +02:00
result + = std : : format ( " \t Mouse at {:x}: \n \t \t {} \n \t \t \t default speed: {:.5f} \n \t \t \t scroll factor: {:.2f} \n " , rc < uintptr_t > ( m . get ( ) ) , m - > m_hlName ,
( m - > aq ( ) & & m - > aq ( ) - > getLibinputHandle ( ) ? libinput_device_config_accel_get_default_speed ( m - > aq ( ) - > getLibinputHandle ( ) ) : 0.f ) ,
m - > m_scrollFactor . value_or ( - 1 ) ) ;
2022-07-12 11:57:33 -06:00
}
result + = " \n \n Keyboards: \n " ;
2025-05-01 23:57:11 +02:00
for ( auto const & k : g_pInputManager - > m_keyboards ) {
2025-09-09 15:19:51 +02:00
const auto INDEX_OPT = k - > getActiveLayoutIndex ( ) ;
const auto KI = INDEX_OPT . has_value ( ) ? std : : to_string ( INDEX_OPT . value ( ) ) : " none " ;
const auto KM = k - > getActiveLayout ( ) ;
result + = std : : format ( " \t Keyboard at {:x}: \n \t \t {} \n \t \t \t rules: r \" {} \" , m \" {} \" , l \" {} \" , v \" {} \" , o \" {} \" \n \t \t \t active layout index: {} \n \t \t \t active keymap: "
" {} \n \t \t \t capsLock: "
2025-04-29 19:51:07 +02:00
" {} \n \t \t \t numLock: {} \n \t \t \t main: {} \n " ,
2025-08-14 19:44:56 +05:00
rc < uintptr_t > ( k . get ( ) ) , k - > m_hlName , k - > m_currentRules . rules , k - > m_currentRules . model , k - > m_currentRules . layout , k - > m_currentRules . variant ,
2025-09-09 15:19:51 +02:00
k - > m_currentRules . options , KI , KM , ( getModState ( k , XKB_MOD_NAME_CAPS ) ? " yes " : " no " ) , ( getModState ( k , XKB_MOD_NAME_NUM ) ? " yes " : " no " ) ,
2025-04-29 19:51:07 +02:00
( k - > m_active ? " yes " : " no " ) ) ;
2022-07-12 11:57:33 -06:00
}
result + = " \n \n Tablets: \n " ;
2025-05-01 23:57:11 +02:00
for ( auto const & d : g_pInputManager - > m_tabletPads ) {
2025-08-14 19:44:56 +05:00
result + =
std : : format ( " \t Tablet Pad at {:x} (belongs to {:x} -> {}) \n " , rc < uintptr_t > ( d . get ( ) ) , rc < uintptr_t > ( d - > m_parent . get ( ) ) , d - > m_parent ? d - > m_parent - > m_hlName : " " ) ;
2022-07-12 11:57:33 -06:00
}
2025-05-01 23:57:11 +02:00
for ( auto const & d : g_pInputManager - > m_tablets ) {
2025-08-14 19:44:56 +05:00
result + = std : : format ( " \t Tablet at {:x}: \n \t \t {} \n \t \t \t size: {}x{}mm \n " , rc < uintptr_t > ( d . get ( ) ) , d - > m_hlName , d - > aq ( ) - > physicalSize . x , d - > aq ( ) - > physicalSize . y ) ;
2022-07-12 11:57:33 -06:00
}
2025-05-01 23:57:11 +02:00
for ( auto const & d : g_pInputManager - > m_tabletTools ) {
2025-08-14 19:44:56 +05:00
result + = std : : format ( " \t Tablet Tool at {:x} \n " , rc < uintptr_t > ( d . get ( ) ) ) ;
2022-07-12 11:57:33 -06:00
}
2022-09-21 14:39:25 +01:00
result + = " \n \n Touch: \n " ;
2025-05-01 23:57:11 +02:00
for ( auto const & d : g_pInputManager - > m_touches ) {
2025-08-14 19:44:56 +05:00
result + = std : : format ( " \t Touch Device at {:x}: \n \t \t {} \n " , rc < uintptr_t > ( d . get ( ) ) , d - > m_hlName ) ;
2022-09-21 14:39:25 +01:00
}
2022-10-04 20:07:21 +01:00
result + = " \n \n Switches: \n " ;
2025-05-01 23:57:11 +02:00
for ( auto const & d : g_pInputManager - > m_switches ) {
2025-08-14 19:44:56 +05:00
result + = std : : format ( " \t Switch Device at {:x}: \n \t \t {} \n " , rc < uintptr_t > ( & d ) , d . pDevice ? d . pDevice - > getName ( ) : " " ) ;
2022-10-04 20:07:21 +01:00
}
2022-06-09 19:25:26 +02:00
}
2022-06-02 13:59:33 +02:00
return result ;
}
2024-12-18 19:56:01 -06:00
static std : : string animationsRequest ( eHyprCtlOutputFormat format , std : : string request ) {
2023-01-25 15:16:28 +00:00
std : : string ret = " " ;
2024-02-05 01:56:38 +00:00
if ( format = = eHyprCtlOutputFormat : : FORMAT_NORMAL ) {
2023-01-25 15:16:28 +00:00
ret + = " animations: \n " ;
2024-08-26 20:24:30 +02:00
for ( auto const & ac : g_pConfigManager - > getAnimationConfig ( ) ) {
2025-08-14 19:44:56 +05:00
ret + = std : : format ( " \n \t name: {} \n \t \t overriden: {} \n \t \t bezier: {} \n \t \t enabled: {} \n \t \t speed: {:.2f} \n \t \t style: {} \n " , ac . first , sc < int > ( ac . second - > overridden ) ,
2025-01-07 17:55:14 +00:00
ac . second - > internalBezier , ac . second - > internalEnabled , ac . second - > internalSpeed , ac . second - > internalStyle ) ;
2023-01-25 15:16:28 +00:00
}
ret + = " beziers: \n " ;
2024-08-26 20:24:30 +02:00
for ( auto const & bz : g_pAnimationManager - > getAllBeziers ( ) ) {
2025-07-16 21:35:15 +02:00
auto & controlPoints = bz . second - > getControlPoints ( ) ;
ret + = std : : format ( " \n \t name: {} \n \t \t X0: {:.2f} \n \t \t Y0: {:.2f} \n \t \t X1: {:.2f} \n \t \t Y1: {:.2f} " , bz . first , controlPoints [ 1 ] . x , controlPoints [ 1 ] . y , controlPoints [ 2 ] . x ,
controlPoints [ 2 ] . y ) ;
2023-01-25 15:16:28 +00:00
}
} else {
// json
ret + = " [[ " ;
2024-08-26 20:24:30 +02:00
for ( auto const & ac : g_pConfigManager - > getAnimationConfig ( ) ) {
2023-09-20 07:26:20 +00:00
ret + = std : : format ( R " #(
2023-09-06 12:51:36 +02:00
{ {
" name " : " {} " ,
" overridden " : { } ,
" bezier " : " {} " ,
" enabled " : { } ,
" speed " : { : .2f } ,
" style " : " {} "
} } , ) # " ,
2025-01-07 17:55:14 +00:00
ac . first , ac . second - > overridden ? " true " : " false " , escapeJSONStrings ( ac . second - > internalBezier ) , ac . second - > internalEnabled ? " true " : " false " ,
ac . second - > internalSpeed , escapeJSONStrings ( ac . second - > internalStyle ) ) ;
2023-01-25 15:16:28 +00:00
}
ret [ ret . length ( ) - 1 ] = ' ] ' ;
ret + = " , \n [ " ;
2024-08-26 17:25:39 +02:00
for ( auto const & bz : g_pAnimationManager - > getAllBeziers ( ) ) {
2025-07-16 21:35:15 +02:00
auto & controlPoints = bz . second - > getControlPoints ( ) ;
2023-09-20 07:26:20 +00:00
ret + = std : : format ( R " #(
2023-09-06 12:51:36 +02:00
{ {
2025-07-16 21:35:15 +02:00
" name " : " {} " ,
" X0 " : { : .2f } ,
" Y0 " : { : .2f } ,
" X1 " : { : .2f } ,
" Y1 " : { : .2f }
2023-09-06 12:51:36 +02:00
} } , ) # " ,
2025-07-16 21:35:15 +02:00
escapeJSONStrings ( bz . first ) , controlPoints [ 1 ] . x , controlPoints [ 1 ] . y , controlPoints [ 2 ] . x , controlPoints [ 2 ] . y ) ;
2023-01-25 15:16:28 +00:00
}
2023-05-24 08:46:56 -07:00
trimTrailingComma ( ret ) ;
2023-01-25 15:16:28 +00:00
2023-02-11 20:54:32 +00:00
ret + = " ]] " ;
2023-01-25 15:16:28 +00:00
}
return ret ;
}
2024-12-18 19:56:01 -06:00
static std : : string rollinglogRequest ( eHyprCtlOutputFormat format , std : : string request ) {
2023-11-14 20:06:04 +00:00
std : : string result = " " ;
2024-02-05 01:56:38 +00:00
if ( format = = eHyprCtlOutputFormat : : FORMAT_JSON ) {
2023-11-14 20:06:04 +00:00
result + = " [ \n \" log \" : \" " ;
2025-04-21 20:42:02 +02:00
result + = escapeJSONStrings ( Debug : : m_rollingLog ) ;
2023-11-14 20:06:04 +00:00
result + = " \" ] " ;
} else {
2025-04-21 20:42:02 +02:00
result = Debug : : m_rollingLog ;
2023-11-14 20:06:04 +00:00
}
return result ;
}
2024-12-18 19:56:01 -06:00
static std : : string globalShortcutsRequest ( eHyprCtlOutputFormat format , std : : string request ) {
2023-04-09 13:48:20 +01:00
std : : string ret = " " ;
2024-07-30 16:33:56 -05:00
const auto SHORTCUTS = PROTO : : globalShortcuts - > getAllShortcuts ( ) ;
2024-02-05 01:56:38 +00:00
if ( format = = eHyprCtlOutputFormat : : FORMAT_NORMAL ) {
2025-02-18 00:33:27 +00:00
for ( auto const & sh : SHORTCUTS ) {
2023-09-20 07:26:20 +00:00
ret + = std : : format ( " {}:{} -> {} \n " , sh . appid , sh . id , sh . description ) ;
2025-02-18 00:33:27 +00:00
}
if ( ret . empty ( ) )
ret = " none " ;
2023-04-09 13:48:20 +01:00
} else {
ret + = " [ " ;
2024-08-26 17:25:39 +02:00
for ( auto const & sh : SHORTCUTS ) {
2023-09-20 07:26:20 +00:00
ret + = std : : format ( R " #(
2023-09-06 12:51:36 +02:00
{ {
" name " : " {} " ,
" description " : " {} "
} } , ) # " ,
2023-09-20 07:26:20 +00:00
escapeJSONStrings ( sh . appid + " : " + sh . id ) , escapeJSONStrings ( sh . description ) ) ;
2023-04-09 13:48:20 +01:00
}
2023-05-24 08:46:56 -07:00
trimTrailingComma ( ret ) ;
2023-04-09 13:48:20 +01:00
ret + = " ] \n " ;
}
return ret ;
}
2024-12-18 19:56:01 -06:00
static std : : string bindsRequest ( eHyprCtlOutputFormat format , std : : string request ) {
2023-01-06 14:32:25 +01:00
std : : string ret = " " ;
2024-02-05 01:56:38 +00:00
if ( format = = eHyprCtlOutputFormat : : FORMAT_NORMAL ) {
2025-05-02 17:07:20 +02:00
for ( auto const & kb : g_pKeybindManager - > m_keybinds ) {
2023-01-06 14:32:25 +01:00
ret + = " bind " ;
2024-11-18 19:56:26 +00:00
if ( kb - > locked )
2023-01-06 14:32:25 +01:00
ret + = " l " ;
2024-11-18 19:56:26 +00:00
if ( kb - > mouse )
2023-01-06 14:32:25 +01:00
ret + = " m " ;
2024-11-18 19:56:26 +00:00
if ( kb - > release )
2023-01-06 14:32:25 +01:00
ret + = " r " ;
2024-11-18 19:56:26 +00:00
if ( kb - > repeat )
2023-01-06 14:32:25 +01:00
ret + = " e " ;
2024-11-18 19:56:26 +00:00
if ( kb - > nonConsuming )
2023-06-14 04:08:56 -07:00
ret + = " n " ;
2024-11-18 19:56:26 +00:00
if ( kb - > hasDescription )
2024-06-11 19:49:54 +02:00
ret + = " d " ;
2023-01-06 14:32:25 +01:00
2024-11-18 19:56:26 +00:00
ret + = std : : format ( " \n \t modmask: {} \n \t submap: {} \n \t key: {} \n \t keycode: {} \n \t catchall: {} \n \t description: {} \n \t dispatcher: {} \n \t arg: {} \n \n " , kb - > modmask ,
2025-10-11 02:40:18 +02:00
kb - > submap . name , kb - > key , kb - > keycode , kb - > catchAll , kb - > description , kb - > handler , kb - > arg ) ;
2023-01-06 14:32:25 +01:00
}
} else {
// json
ret + = " [ " ;
2025-05-02 17:07:20 +02:00
for ( auto const & kb : g_pKeybindManager - > m_keybinds ) {
2023-09-20 07:26:20 +00:00
ret + = std : : format (
2023-01-06 14:32:25 +01:00
R " #(
2023-09-06 12:51:36 +02:00
{ {
" locked " : { } ,
" mouse " : { } ,
" release " : { } ,
" repeat " : { } ,
2024-11-16 07:21:59 +08:00
" longPress " : { } ,
2023-09-06 12:51:36 +02:00
" non_consuming " : { } ,
2024-06-11 19:49:54 +02:00
" has_description " : { } ,
2023-09-06 12:51:36 +02:00
" modmask " : { } ,
" submap " : " {} " ,
2025-11-11 22:59:21 +00:00
" submap_universal " : " {} " ,
2023-09-06 12:51:36 +02:00
" key " : " {} " ,
" keycode " : { } ,
2024-03-03 01:17:02 +01:00
" catch_all " : { } ,
2024-06-11 19:49:54 +02:00
" description " : " {} " ,
2023-09-06 12:51:36 +02:00
" dispatcher " : " {} " ,
" arg " : " {} "
} } , ) # " ,
2024-11-18 19:56:26 +00:00
kb - > locked ? " true " : " false " , kb - > mouse ? " true " : " false " , kb - > release ? " true " : " false " , kb - > repeat ? " true " : " false " , kb - > longPress ? " true " : " false " ,
2025-11-11 22:59:21 +00:00
kb - > nonConsuming ? " true " : " false " , kb - > hasDescription ? " true " : " false " , kb - > modmask , escapeJSONStrings ( kb - > submap . name ) , kb - > submapUniversal ,
escapeJSONStrings ( kb - > key ) , kb - > keycode , kb - > catchAll ? " true " : " false " , escapeJSONStrings ( kb - > description ) , escapeJSONStrings ( kb - > handler ) ,
escapeJSONStrings ( kb - > arg ) ) ;
2023-01-06 14:32:25 +01:00
}
2023-05-24 08:46:56 -07:00
trimTrailingComma ( ret ) ;
2023-01-06 14:32:25 +01:00
ret + = " ] " ;
}
return ret ;
}
2024-02-05 01:56:38 +00:00
std : : string versionRequest ( eHyprCtlOutputFormat format , std : : string request ) {
2022-08-11 21:28:37 +02:00
2024-06-11 17:17:45 +02:00
auto commitMsg = trim ( GIT_COMMIT_MESSAGE ) ;
2025-05-30 18:25:59 +05:00
std : : ranges : : replace ( commitMsg , ' # ' , ' ' ) ;
2023-07-23 19:43:15 +02:00
2024-02-05 01:56:38 +00:00
if ( format = = eHyprCtlOutputFormat : : FORMAT_NORMAL ) {
2024-10-11 13:19:16 +02:00
std : : string result = std : : format ( " Hyprland {} built from branch {} at commit {} {} ({}). \n "
" Date: {} \n "
2025-10-06 23:20:21 +02:00
" Tag: {}, commits: {} \n " ,
HYPRLAND_VERSION , GIT_BRANCH , GIT_COMMIT_HASH , GIT_DIRTY , commitMsg , GIT_COMMIT_DATE , GIT_TAG , GIT_COMMITS ) ;
result + = " \n " ;
result + = getBuiltSystemLibraryNames ( ) ;
result + = " \n " ;
2025-12-04 18:00:15 +00:00
result + = " Version ABI string: " ;
result + = __hyprland_api_get_hash ( ) ;
result + = " \n " ;
2024-10-11 13:19:16 +02:00
2025-05-15 11:13:24 +02:00
# if (!ISDEBUG && !defined(NO_XWAYLAND))
2024-10-11 13:19:16 +02:00
result + = " no flags were set \n " ;
# else
result + = " flags set: \n " ;
2024-12-25 04:32:18 +05:00
# if ISDEBUG
2022-12-16 17:17:31 +00:00
result + = " debug \n " ;
2022-06-18 13:09:38 +02:00
# endif
2022-04-22 18:14:25 +02:00
# ifdef NO_XWAYLAND
2022-08-11 21:28:37 +02:00
result + = " no xwayland \n " ;
2022-04-22 18:14:25 +02:00
# endif
2024-10-11 13:19:16 +02:00
# endif
2022-08-11 21:28:37 +02:00
return result ;
} else {
2023-09-20 07:26:20 +00:00
std : : string result = std : : format (
2023-09-06 12:51:36 +02:00
R " #({{
" branch " : " {} " ,
" commit " : " {} " ,
2024-10-11 13:19:16 +02:00
" version " : " {} " ,
2023-09-06 12:51:36 +02:00
" dirty " : { } ,
" commit_message " : " {} " ,
2023-12-17 14:29:58 +00:00
" commit_date " : " {} " ,
2023-09-06 12:51:36 +02:00
" tag " : " {} " ,
2024-04-29 16:10:22 +01:00
" commits " : " {} " ,
2024-09-19 11:39:54 +01:00
" buildAquamarine " : " {} " ,
2024-12-02 16:31:22 +00:00
" buildHyprlang " : " {} " ,
" buildHyprutils " : " {} " ,
" buildHyprcursor " : " {} " ,
2024-12-03 18:58:24 +00:00
" buildHyprgraphics " : " {} " ,
2025-10-06 23:20:21 +02:00
" systemAquamarine " : " {} " ,
" systemHyprlang " : " {} " ,
" systemHyprutils " : " {} " ,
" systemHyprcursor " : " {} " ,
" systemHyprgraphics " : " {} " ,
2025-12-04 18:00:15 +00:00
" abiHash " : " {} " ,
2022-12-16 17:17:31 +00:00
" flags " : [ ) # " ,
2024-10-11 13:19:16 +02:00
GIT_BRANCH , GIT_COMMIT_HASH , HYPRLAND_VERSION , ( strcmp ( GIT_DIRTY , " dirty " ) = = 0 ? " true " : " false " ) , escapeJSONStrings ( commitMsg ) , GIT_COMMIT_DATE , GIT_TAG ,
2025-10-06 23:20:21 +02:00
GIT_COMMITS , AQUAMARINE_VERSION , HYPRLANG_VERSION , HYPRUTILS_VERSION , HYPRCURSOR_VERSION , HYPRGRAPHICS_VERSION , getSystemLibraryVersion ( " aquamarine " ) ,
2025-12-04 18:00:15 +00:00
getSystemLibraryVersion ( " hyprlang " ) , getSystemLibraryVersion ( " hyprutils " ) , getSystemLibraryVersion ( " hyprcursor " ) , getSystemLibraryVersion ( " hyprgraphics " ) ,
__hyprland_api_get_hash ( ) ) ;
2022-08-11 21:28:37 +02:00
2024-12-25 04:32:18 +05:00
# if ISDEBUG
2022-12-16 17:17:31 +00:00
result + = " \" debug \" , " ;
2022-08-11 21:28:37 +02:00
# endif
# ifdef NO_XWAYLAND
result + = " \" no xwayland \" , " ;
# endif
2023-05-24 08:46:56 -07:00
trimTrailingComma ( result ) ;
2022-08-11 21:28:37 +02:00
result + = " ] \n } " ;
return result ;
}
return " " ; // make the compiler happy
2022-04-22 18:14:25 +02:00
}
2024-02-05 01:56:38 +00:00
std : : string systemInfoRequest ( eHyprCtlOutputFormat format , std : : string request ) {
std : : string result = versionRequest ( eHyprCtlOutputFormat : : FORMAT_NORMAL , " " ) ;
2024-01-01 17:53:00 +01:00
2025-07-20 14:51:10 +02:00
static auto check = [ ] ( bool y ) - > std : : string { return y ? " ✔️ " : " ❌ " ; } ;
static auto backend = [ ] ( Aquamarine : : eBackendType t ) - > std : : string {
switch ( t ) {
case Aquamarine : : AQ_BACKEND_DRM : return " drm " ;
case Aquamarine : : AQ_BACKEND_HEADLESS : return " headless " ;
case Aquamarine : : AQ_BACKEND_WAYLAND : return " wayland " ;
default : break ;
}
return " ? " ;
} ;
2024-01-01 17:53:00 +01:00
result + = " \n \n System Information: \n " ;
struct utsname unameInfo ;
uname ( & unameInfo ) ;
result + = " System name: " + std : : string { unameInfo . sysname } + " \n " ;
result + = " Node name: " + std : : string { unameInfo . nodename } + " \n " ;
result + = " Release: " + std : : string { unameInfo . release } + " \n " ;
result + = " Version: " + std : : string { unameInfo . version } + " \n " ;
2025-10-06 23:20:21 +02:00
result + = " \n " ;
result + = getBuiltSystemLibraryNames ( ) ;
result + = " \n " ;
2024-01-01 17:53:00 +01:00
result + = " \n \n " ;
# if defined(__DragonFly__) || defined(__FreeBSD__)
2024-11-17 21:57:00 +00:00
const std : : string GPUINFO = execAndGet ( " pciconf -lv | grep -F -A4 vga " ) ;
2024-05-23 19:04:39 +03:00
# elif defined(__arm__) || defined(__aarch64__)
2024-11-11 13:44:41 +00:00
std : : string GPUINFO ;
const std : : filesystem : : path dev_tree = " /proc/device-tree " ;
try {
if ( std : : filesystem : : exists ( dev_tree ) & & std : : filesystem : : is_directory ( dev_tree ) ) {
std : : for_each ( std : : filesystem : : directory_iterator ( dev_tree ) , std : : filesystem : : directory_iterator { } , [ & ] ( const std : : filesystem : : directory_entry & entry ) {
if ( std : : filesystem : : is_directory ( entry ) & & entry . path ( ) . filename ( ) . string ( ) . starts_with ( " soc " ) ) {
std : : for_each ( std : : filesystem : : directory_iterator ( entry . path ( ) ) , std : : filesystem : : directory_iterator { } , [ & ] ( const std : : filesystem : : directory_entry & sub_entry ) {
if ( std : : filesystem : : is_directory ( sub_entry ) & & sub_entry . path ( ) . filename ( ) . string ( ) . starts_with ( " gpu " ) ) {
std : : filesystem : : path file_path = sub_entry . path ( ) / " compatible " ;
std : : ifstream file ( file_path ) ;
if ( file )
GPUINFO . append ( std : : istreambuf_iterator < char > ( file ) , std : : istreambuf_iterator < char > ( ) ) ;
}
} ) ;
}
} ) ;
}
} catch ( . . . ) { GPUINFO = " error " ; }
2024-01-01 17:53:00 +01:00
# else
2024-12-19 04:08:57 +05:00
const std : : string GPUINFO = execAndGet ( " lspci -vnn | grep -E '(VGA|Display|3D)' " ) ;
2024-01-01 17:53:00 +01:00
# endif
2024-06-30 14:16:41 +03:00
result + = " GPU information: \n " + GPUINFO ;
2024-11-10 15:54:15 +00:00
if ( GPUINFO . contains ( " NVIDIA " ) & & std : : filesystem : : exists ( " /proc/driver/nvidia/version " ) ) {
std : : ifstream file ( " /proc/driver/nvidia/version " ) ;
std : : string line ;
if ( file . is_open ( ) ) {
while ( std : : getline ( file , line ) ) {
if ( ! line . contains ( " NVRM " ) )
continue ;
result + = line ;
result + = " \n " ;
}
} else
result + = " error " ;
}
2024-06-30 14:16:41 +03:00
result + = " \n \n " ;
2024-01-01 17:53:00 +01:00
2024-11-10 15:54:15 +00:00
if ( std : : ifstream file ( " /etc/os-release " ) ; file . is_open ( ) ) {
std : : stringstream buffer ;
buffer < < file . rdbuf ( ) ;
result + = " os-release: " + buffer . str ( ) + " \n \n " ;
} else
result + = " os-release: error \n \n " ;
2024-01-01 17:53:00 +01:00
result + = " plugins: \n " ;
2024-09-25 10:36:43 +01:00
if ( g_pPluginSystem ) {
for ( auto const & pl : g_pPluginSystem - > getAllPlugins ( ) ) {
2025-05-03 16:06:24 +02:00
result + = std : : format ( " {} by {} ver {} \n " , pl - > m_name , pl - > m_author , pl - > m_version ) ;
2024-09-25 10:36:43 +01:00
}
} else
result + = " \t unknown: not runtime \n " ;
2024-01-01 17:53:00 +01:00
2025-09-25 01:44:07 +02:00
if ( g_pHyprOpenGL ) {
result + = std : : format ( " \n Explicit sync: {} " , g_pHyprOpenGL - > m_exts . EGL_ANDROID_native_fence_sync_ext ? " supported " : " missing " ) ;
result + = std : : format ( " \n GL ver: {} " , g_pHyprOpenGL - > m_eglContextVersion = = CHyprOpenGLImpl : : EGL_CONTEXT_GLES_3_2 ? " 3.2 " : " 3.0 " ) ;
}
if ( g_pCompositor ) {
result + = std : : format ( " \n Backend: {} " , g_pCompositor - > m_aqBackend - > hasSession ( ) ? " drm " : " sessionless " ) ;
result + = " \n \n Monitor info: " ;
for ( const auto & m : g_pCompositor - > m_monitors ) {
result + = std : : format ( " \n \t Panel {}: {}x{}, {} {} {} {} -> backend {} \n \t \t explicit {} \n \t \t edid: \n \t \t \t hdr {} \n \t \t \t chroma {} \n \t \t \t bt2020 {} \n \t \t vrr capable "
" {} \n \t \t non-desktop {} \n \t \t " ,
m - > m_name , sc < int > ( m - > m_pixelSize . x ) , sc < int > ( m - > m_pixelSize . y ) , m - > m_output - > name , m - > m_output - > make , m - > m_output - > model , m - > m_output - > serial ,
backend ( m - > m_output - > getBackend ( ) - > type ( ) ) , check ( m - > m_output - > supportsExplicit ) , check ( m - > m_output - > parsedEDID . hdrMetadata . has_value ( ) ) ,
check ( m - > m_output - > parsedEDID . chromaticityCoords . has_value ( ) ) , check ( m - > m_output - > parsedEDID . supportsBT2020 ) , check ( m - > m_output - > vrrCapable ) ,
check ( m - > m_output - > nonDesktop ) ) ;
}
2025-07-20 14:51:10 +02:00
}
2025-04-21 20:42:02 +02:00
if ( g_pHyprCtl & & g_pHyprCtl - > m_currentRequestParams . sysInfoConfig ) {
2024-05-25 20:46:07 +00:00
result + = " \n ======Config-Start====== \n " ;
result + = g_pConfigManager - > getConfigString ( ) ;
result + = " \n ======Config-End======== \n " ;
}
2024-01-01 17:53:00 +01:00
return result ;
}
2024-12-18 19:56:01 -06:00
static std : : string dispatchRequest ( eHyprCtlOutputFormat format , std : : string in ) {
2022-04-21 16:11:29 +02:00
// get rid of the dispatch keyword
in = in . substr ( in . find_first_of ( ' ' ) + 1 ) ;
const auto DISPATCHSTR = in . substr ( 0 , in . find_first_of ( ' ' ) ) ;
2023-07-21 17:20:23 +02:00
auto DISPATCHARG = std : : string ( ) ;
2025-08-14 19:44:56 +05:00
if ( sc < int > ( in . find_first_of ( ' ' ) ) ! = - 1 )
2023-07-21 17:20:23 +02:00
DISPATCHARG = in . substr ( in . find_first_of ( ' ' ) + 1 ) ;
2022-04-21 16:11:29 +02:00
2025-05-02 17:07:20 +02:00
const auto DISPATCHER = g_pKeybindManager - > m_dispatchers . find ( DISPATCHSTR ) ;
if ( DISPATCHER = = g_pKeybindManager - > m_dispatchers . end ( ) )
2022-04-21 16:11:29 +02:00
return " Invalid dispatcher " ;
2024-08-24 11:45:53 -05:00
SDispatchResult res = DISPATCHER - > second ( DISPATCHARG ) ;
2022-04-21 16:11:29 +02:00
2024-08-24 11:45:53 -05:00
Debug : : log ( LOG , " Hyprctl: dispatcher {} : {}{} " , DISPATCHSTR , DISPATCHARG , res . success ? " " : " -> " + res . error ) ;
2022-04-21 21:48:37 +02:00
2024-08-24 11:45:53 -05:00
return res . success ? " ok " : res . error ;
2022-04-21 16:11:29 +02:00
}
2024-12-18 19:56:01 -06:00
static std : : string dispatchKeyword ( eHyprCtlOutputFormat format , std : : string in ) {
2024-08-27 20:42:30 +02:00
// Find the first space to strip the keyword keyword
auto const firstSpacePos = in . find_first_of ( ' ' ) ;
if ( firstSpacePos = = std : : string : : npos ) // Handle the case where there's no space found (invalid input)
return " Invalid input: no space found " ;
// Strip the keyword
in = in . substr ( firstSpacePos + 1 ) ;
// Find the next space for the COMMAND and VALUE
auto const secondSpacePos = in . find_first_of ( ' ' ) ;
if ( secondSpacePos = = std : : string : : npos ) // Handle the case where there's no second space (invalid input)
return " Invalid input: command and value not properly formatted " ;
// Extract COMMAND and VALUE
const auto COMMAND = in . substr ( 0 , secondSpacePos ) ;
const auto VALUE = in . substr ( secondSpacePos + 1 ) ;
2024-09-17 11:24:54 +01:00
// If COMMAND is empty, handle accordingly
if ( COMMAND . empty ( ) )
return " Invalid input: command is empty " ;
2022-04-21 16:56:27 +02:00
2025-11-17 18:34:02 +00:00
g_pHyprCtl - > m_currentRequestParams . isDynamicKeyword = true ;
2024-02-18 15:00:34 +00:00
std : : string retval = g_pConfigManager - > parseKeyword ( COMMAND , VALUE ) ;
2022-04-21 16:56:27 +02:00
2025-11-17 18:34:02 +00:00
g_pHyprCtl - > m_currentRequestParams . isDynamicKeyword = false ;
2024-02-19 12:45:05 +00:00
// if we are executing a dynamic source we have to reload everything, so every if will have a check for source.
if ( COMMAND = = " monitor " | | COMMAND = = " source " )
2025-04-20 20:39:33 +02:00
g_pConfigManager - > m_wantsMonitorReload = true ; // for monitor keywords
2022-04-21 17:36:28 +02:00
2025-06-05 17:56:46 +03:00
if ( COMMAND . contains ( " monitorv2 " ) )
g_pEventLoopManager - > doLater ( [ ] { g_pConfigManager - > m_wantsMonitorReload = true ; } ) ;
2024-02-19 12:45:05 +00:00
if ( COMMAND . contains ( " input " ) | | COMMAND . contains ( " device " ) | | COMMAND = = " source " ) {
2022-12-16 17:17:31 +00:00
g_pInputManager - > setKeyboardLayout ( ) ; // update kb layout
g_pInputManager - > setPointerConfigs ( ) ; // update mouse cfgs
2022-10-07 16:03:52 +02:00
g_pInputManager - > setTouchDeviceConfigs ( ) ; // update touch device cfgs
2022-12-21 15:11:39 +00:00
g_pInputManager - > setTabletConfigs ( ) ; // update tablets
2022-08-20 18:57:30 +02:00
}
2022-04-22 14:11:52 +02:00
2024-03-03 18:39:20 +00:00
static auto PLAYOUT = CConfigValue < std : : string > ( " general:layout " ) ;
2024-02-18 15:00:34 +00:00
2022-07-16 22:44:29 +02:00
if ( COMMAND . contains ( " general:layout " ) )
2024-02-18 15:00:34 +00:00
g_pLayoutManager - > switchToLayout ( * PLAYOUT ) ; // update layout
2022-12-16 17:17:31 +00:00
2024-02-19 12:45:05 +00:00
if ( COMMAND . contains ( " decoration:screen_shader " ) | | COMMAND = = " source " )
2025-05-05 23:44:49 +02:00
g_pHyprOpenGL - > m_reloadScreenShader = true ;
2022-07-16 22:44:29 +02:00
2024-02-19 12:45:05 +00:00
if ( COMMAND . contains ( " blur " ) | | COMMAND = = " source " ) {
2025-05-05 23:44:49 +02:00
for ( auto & [ m , rd ] : g_pHyprOpenGL - > m_monitorRenderResources ) {
2022-12-18 15:05:34 +00:00
rd . blurFBDirty = true ;
}
}
2025-01-29 10:50:39 +00:00
if ( COMMAND . contains ( " misc:disable_autoreload " ) )
g_pConfigManager - > updateWatcher ( ) ;
2023-01-12 12:14:57 +01:00
// decorations will probably need a repaint
2025-11-17 18:34:02 +00:00
if ( COMMAND . contains ( " decoration: " ) | | COMMAND . contains ( " border " ) | | COMMAND = = " workspace " | | COMMAND . contains ( " zoom_factor " ) | | COMMAND = = " source " ) {
2025-07-01 11:33:48 +02:00
static auto PZOOMFACTOR = CConfigValue < Hyprlang : : FLOAT > ( " cursor:zoom_factor " ) ;
2025-04-22 15:23:29 +02:00
for ( auto const & m : g_pCompositor - > m_monitors ) {
2025-07-01 11:33:48 +02:00
* ( m - > m_cursorZoom ) = * PZOOMFACTOR ;
2024-10-19 23:03:29 +01:00
g_pHyprRenderer - > damageMonitor ( m ) ;
2025-04-30 23:45:20 +02:00
g_pLayoutManager - > getCurrentLayout ( ) - > recalculateMonitor ( m - > m_id ) ;
2023-01-24 14:04:01 +00:00
}
2023-01-12 12:14:57 +01:00
}
2025-11-17 18:34:02 +00:00
if ( COMMAND . contains ( " windowrule " ) | | COMMAND . contains ( " windowrule[ " ) )
g_pConfigManager - > reloadRules ( ) ;
2025-07-27 18:46:23 +02:00
if ( COMMAND . contains ( " workspace " ) )
g_pConfigManager - > ensurePersistentWorkspacesPresent ( ) ;
2023-09-06 21:45:37 +02:00
Debug : : log ( LOG , " Hyprctl: keyword {} : {} " , COMMAND , VALUE ) ;
2022-04-21 21:48:37 +02:00
2025-05-31 23:49:50 +05:00
if ( retval . empty ( ) )
2022-04-21 16:56:27 +02:00
return " ok " ;
return retval ;
}
2024-12-18 19:56:01 -06:00
static std : : string reloadRequest ( eHyprCtlOutputFormat format , std : : string request ) {
2022-09-25 20:07:48 +02:00
2022-08-14 23:26:18 +02:00
const auto REQMODE = request . substr ( request . find_last_of ( ' ' ) + 1 ) ;
2025-01-19 15:39:19 +01:00
if ( REQMODE = = " config-only " )
2025-04-20 20:39:33 +02:00
g_pConfigManager - > m_noMonitorReload = true ;
2022-08-14 23:26:18 +02:00
2025-01-19 15:39:19 +01:00
g_pConfigManager - > reload ( ) ;
2022-09-13 15:36:49 +02:00
2022-05-08 15:28:45 +02:00
return " ok " ;
}
2024-12-18 19:56:01 -06:00
static std : : string killRequest ( eHyprCtlOutputFormat format , std : : string request ) {
2022-06-27 13:42:20 +02:00
g_pInputManager - > setClickMode ( CLICKMODE_KILL ) ;
return " ok " ;
}
2024-12-18 19:56:01 -06:00
static std : : string splashRequest ( eHyprCtlOutputFormat format , std : : string request ) {
2025-04-22 15:23:29 +02:00
return g_pCompositor - > m_currentSplash ;
2022-07-10 15:41:26 +02:00
}
2024-12-18 19:56:01 -06:00
static std : : string cursorPosRequest ( eHyprCtlOutputFormat format , std : : string request ) {
2022-10-26 13:19:37 +01:00
const auto CURSORPOS = g_pInputManager - > getMouseCoordsInternal ( ) . floor ( ) ;
2024-02-05 01:56:38 +00:00
if ( format = = eHyprCtlOutputFormat : : FORMAT_NORMAL ) {
2025-08-14 19:44:56 +05:00
return std : : format ( " {}, {} " , sc < int > ( CURSORPOS . x ) , sc < int > ( CURSORPOS . y ) ) ;
2022-10-26 13:19:37 +01:00
} else {
2023-09-20 07:26:20 +00:00
return std : : format ( R " #(
2023-09-06 12:51:36 +02:00
{ {
" x " : { } ,
" y " : { }
} }
2022-12-16 17:17:31 +00:00
) # " ,
2025-08-14 19:44:56 +05:00
sc < int > ( CURSORPOS . x ) , sc < int > ( CURSORPOS . y ) ) ;
2022-10-26 13:19:37 +01:00
}
return " error " ;
}
2024-12-18 19:56:01 -06:00
static std : : string dispatchBatch ( eHyprCtlOutputFormat format , std : : string request ) {
2025-01-06 17:52:59 +01:00
// split by ; ignores ; inside [] and adds ; on last command
2022-04-29 19:44:09 +02:00
2025-01-06 17:52:59 +01:00
request = request . substr ( 9 ) ;
std : : string reply = " " ;
2024-05-27 23:31:35 +03:00
const std : : string DELIMITER = " \n \n \n " ;
2025-01-06 17:52:59 +01:00
int bracket = 0 ;
size_t idx = 0 ;
for ( size_t i = 0 ; i < = request . size ( ) ; + + i ) {
char ch = ( i < request . size ( ) ) ? request [ i ] : ' ; ' ;
if ( ch = = ' [ ' )
+ + bracket ;
else if ( ch = = ' ] ' )
- - bracket ;
else if ( ch = = ' ; ' & & bracket = = 0 ) {
if ( idx < i )
reply + = g_pHyprCtl - > getReply ( trim ( request . substr ( idx , i - idx ) ) ) . append ( DELIMITER ) ;
idx = i + 1 ;
continue ;
}
2022-04-29 19:44:09 +02:00
}
2025-08-14 19:44:56 +05:00
return reply . substr ( 0 , std : : max ( sc < int > ( reply . size ( ) - DELIMITER . size ( ) ) , 0 ) ) ;
2022-04-29 19:44:09 +02:00
}
2024-12-18 19:56:01 -06:00
static std : : string dispatchSetCursor ( eHyprCtlOutputFormat format , std : : string request ) {
2023-05-02 06:51:52 -07:00
CVarList vars ( request , 0 , ' ' ) ;
2023-04-20 23:59:31 +01:00
2023-05-02 06:51:52 -07:00
const auto SIZESTR = vars [ vars . size ( ) - 1 ] ;
std : : string theme = " " ;
2023-04-20 23:59:31 +01:00
for ( size_t i = 1 ; i < vars . size ( ) - 1 ; + + i )
theme + = vars [ i ] + " " ;
2023-09-23 13:26:35 +01:00
if ( ! theme . empty ( ) )
theme . pop_back ( ) ;
2023-04-20 23:59:31 +01:00
int size = 0 ;
try {
size = std : : stoi ( SIZESTR ) ;
2023-05-02 06:51:52 -07:00
} catch ( . . . ) { return " size not int " ; }
2022-08-10 21:22:11 +02:00
2023-04-20 23:59:31 +01:00
if ( size < = 0 )
return " size not positive " ;
2022-08-10 21:22:11 +02:00
2024-05-28 16:35:18 -05:00
if ( ! g_pCursorManager - > changeTheme ( theme , size ) )
return " failed to set cursor " ;
2022-08-10 21:22:11 +02:00
return " ok " ;
}
2024-12-18 19:56:01 -06:00
static std : : string switchXKBLayoutRequest ( eHyprCtlOutputFormat format , std : : string request ) {
2024-08-28 14:05:31 +02:00
CVarList vars ( request , 0 , ' ' ) ;
2022-12-03 15:56:07 +00:00
2024-08-28 14:05:31 +02:00
const auto KB = vars [ 1 ] ;
const auto CMD = vars [ 2 ] ;
2022-12-03 15:56:07 +00:00
2024-08-28 14:05:31 +02:00
SP < IKeyboard > pKeyboard ;
2022-12-03 15:56:07 +00:00
2024-08-28 14:05:31 +02:00
auto updateKeyboard = [ ] ( const SP < IKeyboard > KEEB , const std : : string & CMD ) - > std : : optional < std : : string > {
2025-04-29 19:51:07 +02:00
const auto LAYOUTS = xkb_keymap_num_layouts ( KEEB - > m_xkbKeymap ) ;
2024-08-28 14:05:31 +02:00
xkb_layout_index_t activeLayout = 0 ;
while ( activeLayout < LAYOUTS ) {
2025-04-29 19:51:07 +02:00
if ( xkb_state_layout_index_is_active ( KEEB - > m_xkbState , activeLayout , XKB_STATE_LAYOUT_EFFECTIVE ) = = 1 )
2024-08-28 14:05:31 +02:00
break ;
2022-12-03 15:56:07 +00:00
2024-08-28 14:05:31 +02:00
activeLayout + + ;
}
2024-07-21 13:09:54 +02:00
2024-08-28 14:05:31 +02:00
if ( CMD = = " next " )
2025-04-29 19:51:07 +02:00
KEEB - > updateModifiers ( KEEB - > m_modifiersState . depressed , KEEB - > m_modifiersState . latched , KEEB - > m_modifiersState . locked , activeLayout > LAYOUTS ? 0 : activeLayout + 1 ) ;
2024-08-28 14:05:31 +02:00
else if ( CMD = = " prev " )
2025-04-29 19:51:07 +02:00
KEEB - > updateModifiers ( KEEB - > m_modifiersState . depressed , KEEB - > m_modifiersState . latched , KEEB - > m_modifiersState . locked ,
activeLayout = = 0 ? LAYOUTS - 1 : activeLayout - 1 ) ;
2024-08-28 14:05:31 +02:00
else {
int requestedLayout = 0 ;
try {
requestedLayout = std : : stoi ( CMD ) ;
} catch ( std : : exception & e ) { return " invalid arg 2 " ; }
2025-08-14 19:44:56 +05:00
if ( requestedLayout < 0 | | sc < uint64_t > ( requestedLayout ) > LAYOUTS - 1 ) {
2024-08-28 14:05:31 +02:00
return " layout idx out of range of " + std : : to_string ( LAYOUTS ) ;
}
2022-12-03 15:56:07 +00:00
2025-04-29 19:51:07 +02:00
KEEB - > updateModifiers ( KEEB - > m_modifiersState . depressed , KEEB - > m_modifiersState . latched , KEEB - > m_modifiersState . locked , requestedLayout ) ;
2024-08-28 14:05:31 +02:00
}
return std : : nullopt ;
} ;
if ( KB = = " main " | | KB = = " active " | | KB = = " current " ) {
2025-05-01 23:57:11 +02:00
for ( auto const & k : g_pInputManager - > m_keyboards ) {
2025-04-29 19:51:07 +02:00
if ( ! k - > m_active )
2024-08-28 14:05:31 +02:00
continue ;
2022-12-03 15:56:07 +00:00
2024-08-28 14:05:31 +02:00
pKeyboard = k ;
break ;
2022-12-03 15:56:07 +00:00
}
2024-08-28 14:05:31 +02:00
} else if ( KB = = " all " ) {
std : : string result = " " ;
2025-05-01 23:57:11 +02:00
for ( auto const & k : g_pInputManager - > m_keyboards ) {
2024-08-28 14:05:31 +02:00
auto res = updateKeyboard ( k , CMD ) ;
if ( res . has_value ( ) )
result + = * res + " \n " ;
}
return result . empty ( ) ? " ok " : result ;
} else {
2025-08-04 16:29:39 -03:00
auto k = std : : ranges : : find_if ( g_pInputManager - > m_keyboards , [ & ] ( const auto & other ) { return other - > m_hlName = = deviceNameToInternalString ( KB ) ; } ) ;
2022-12-03 15:56:07 +00:00
2025-05-01 23:57:11 +02:00
if ( k = = g_pInputManager - > m_keyboards . end ( ) )
2024-08-28 14:05:31 +02:00
return " device not found " ;
pKeyboard = * k ;
2022-12-03 15:56:07 +00:00
}
2024-08-28 14:05:31 +02:00
if ( ! pKeyboard )
return " no device " ;
auto result = updateKeyboard ( pKeyboard , CMD ) ;
if ( result . has_value ( ) )
return * result ;
2022-12-03 15:56:07 +00:00
return " ok " ;
}
2024-12-18 19:56:01 -06:00
static std : : string dispatchSeterror ( eHyprCtlOutputFormat format , std : : string request ) {
2023-01-22 16:38:17 +01:00
CVarList vars ( request , 0 , ' ' ) ;
std : : string errorMessage = " " ;
if ( vars . size ( ) < 3 ) {
g_pHyprError - > destroy ( ) ;
2023-01-22 16:51:32 +01:00
2025-08-03 13:21:29 +02:00
if ( vars . size ( ) = = 2 & & ! vars [ 1 ] . contains ( " dis " ) )
2023-01-22 16:51:32 +01:00
return " var 1 not color or disable " ;
2023-01-22 16:38:17 +01:00
return " ok " ;
}
2024-12-03 18:58:24 +00:00
const CHyprColor COLOR = configStringToInt ( vars [ 1 ] ) . value_or ( 0 ) ;
2023-01-22 16:38:17 +01:00
for ( size_t i = 2 ; i < vars . size ( ) ; + + i )
errorMessage + = vars [ i ] + ' ' ;
if ( errorMessage . empty ( ) ) {
g_pHyprError - > destroy ( ) ;
} else {
errorMessage . pop_back ( ) ; // pop last space
g_pHyprError - > queueCreate ( errorMessage , COLOR ) ;
}
return " ok " ;
}
2025-08-18 16:41:17 +01:00
static std : : string dispatchGetProp ( eHyprCtlOutputFormat format , std : : string request ) {
CVarList vars ( request , 0 , ' ' ) ;
if ( vars . size ( ) < 3 )
return " not enough args " ;
const auto WINREGEX = vars [ 1 ] ;
const auto PROP = vars [ 2 ] ;
const auto PWINDOW = g_pCompositor - > getWindowByRegex ( WINREGEX ) ;
if ( ! PWINDOW )
return " window not found " ;
const bool FORMNORM = format = = FORMAT_NORMAL ;
auto sizeToString = [ & ] ( bool max ) - > std : : string {
2025-11-17 18:34:02 +00:00
auto sizeValue = PWINDOW - > m_ruleApplicator - > minSize ( ) . valueOr ( Vector2D ( MIN_WINDOW_SIZE , MIN_WINDOW_SIZE ) ) ;
2025-08-18 16:41:17 +01:00
if ( max )
2025-11-17 18:34:02 +00:00
sizeValue = PWINDOW - > m_ruleApplicator - > maxSize ( ) . valueOr ( Vector2D ( INFINITY , INFINITY ) ) ;
2025-08-18 16:41:17 +01:00
if ( FORMNORM )
return std : : format ( " {} {} " , sizeValue . x , sizeValue . y ) ;
else {
std : : string xSizeString = ( sizeValue . x ! = INFINITY ) ? std : : to_string ( sizeValue . x ) : " null " ;
std : : string ySizeString = ( sizeValue . y ! = INFINITY ) ? std : : to_string ( sizeValue . y ) : " null " ;
return std : : format ( R " ({{ " { } " : [{},{}]}}) " , PROP , xSizeString , ySizeString ) ;
}
} ;
2025-11-17 18:34:02 +00:00
auto alphaToString = [ & ] ( Desktop : : Types : : COverridableVar < Desktop : : Types : : SAlphaValue > & alpha , bool getAlpha ) - > std : : string {
2025-08-18 16:41:17 +01:00
if ( FORMNORM ) {
if ( getAlpha )
return std : : format ( " {} " , alpha . valueOrDefault ( ) . alpha ) ;
else
return std : : format ( " {} " , alpha . valueOrDefault ( ) . overridden ) ;
} else {
if ( getAlpha )
return std : : format ( R " ({{ " { } " : {}}}) " , PROP , alpha . valueOrDefault ( ) . alpha ) ;
else
return std : : format ( R " ({{ " { } " : {}}}) " , PROP , alpha . valueOrDefault ( ) . overridden ) ;
}
} ;
auto borderColorToString = [ & ] ( bool active ) - > std : : string {
static auto PACTIVECOL = CConfigValue < Hyprlang : : CUSTOMTYPE > ( " general:col.active_border " ) ;
static auto PINACTIVECOL = CConfigValue < Hyprlang : : CUSTOMTYPE > ( " general:col.inactive_border " ) ;
static auto PNOGROUPACTIVECOL = CConfigValue < Hyprlang : : CUSTOMTYPE > ( " general:col.nogroup_border_active " ) ;
static auto PNOGROUPINACTIVECOL = CConfigValue < Hyprlang : : CUSTOMTYPE > ( " general:col.nogroup_border " ) ;
static auto PGROUPACTIVECOL = CConfigValue < Hyprlang : : CUSTOMTYPE > ( " group:col.border_active " ) ;
static auto PGROUPINACTIVECOL = CConfigValue < Hyprlang : : CUSTOMTYPE > ( " group:col.border_inactive " ) ;
static auto PGROUPACTIVELOCKEDCOL = CConfigValue < Hyprlang : : CUSTOMTYPE > ( " group:col.border_locked_active " ) ;
static auto PGROUPINACTIVELOCKEDCOL = CConfigValue < Hyprlang : : CUSTOMTYPE > ( " group:col.border_locked_inactive " ) ;
const bool GROUPLOCKED = PWINDOW - > m_groupData . pNextWindow . lock ( ) ? PWINDOW - > getGroupHead ( ) - > m_groupData . locked : false ;
if ( active ) {
auto * const ACTIVECOL = ( CGradientValueData * ) ( PACTIVECOL . ptr ( ) ) - > getData ( ) ;
auto * const NOGROUPACTIVECOL = ( CGradientValueData * ) ( PNOGROUPACTIVECOL . ptr ( ) ) - > getData ( ) ;
auto * const GROUPACTIVECOL = ( CGradientValueData * ) ( PGROUPACTIVECOL . ptr ( ) ) - > getData ( ) ;
auto * const GROUPACTIVELOCKEDCOL = ( CGradientValueData * ) ( PGROUPACTIVELOCKEDCOL . ptr ( ) ) - > getData ( ) ;
const auto * const ACTIVECOLOR =
! PWINDOW - > m_groupData . pNextWindow . lock ( ) ? ( ! PWINDOW - > m_groupData . deny ? ACTIVECOL : NOGROUPACTIVECOL ) : ( GROUPLOCKED ? GROUPACTIVELOCKEDCOL : GROUPACTIVECOL ) ;
2025-11-17 18:34:02 +00:00
std : : string borderColorString = PWINDOW - > m_ruleApplicator - > activeBorderColor ( ) . valueOr ( * ACTIVECOLOR ) . toString ( ) ;
2025-08-18 16:41:17 +01:00
if ( FORMNORM )
return borderColorString ;
else
return std : : format ( R " ({{ " { } " : " { } " }}) " , PROP , borderColorString ) ;
} else {
auto * const INACTIVECOL = ( CGradientValueData * ) ( PINACTIVECOL . ptr ( ) ) - > getData ( ) ;
auto * const NOGROUPINACTIVECOL = ( CGradientValueData * ) ( PNOGROUPINACTIVECOL . ptr ( ) ) - > getData ( ) ;
auto * const GROUPINACTIVECOL = ( CGradientValueData * ) ( PGROUPINACTIVECOL . ptr ( ) ) - > getData ( ) ;
auto * const GROUPINACTIVELOCKEDCOL = ( CGradientValueData * ) ( PGROUPINACTIVELOCKEDCOL . ptr ( ) ) - > getData ( ) ;
const auto * const INACTIVECOLOR = ! PWINDOW - > m_groupData . pNextWindow . lock ( ) ? ( ! PWINDOW - > m_groupData . deny ? INACTIVECOL : NOGROUPINACTIVECOL ) :
( GROUPLOCKED ? GROUPINACTIVELOCKEDCOL : GROUPINACTIVECOL ) ;
2025-11-17 18:34:02 +00:00
std : : string borderColorString = PWINDOW - > m_ruleApplicator - > inactiveBorderColor ( ) . valueOr ( * INACTIVECOLOR ) . toString ( ) ;
2025-08-18 16:41:17 +01:00
if ( FORMNORM )
return borderColorString ;
else
return std : : format ( R " ({{ " { } " : " { } " }}) " , PROP , borderColorString ) ;
}
} ;
auto windowPropToString = [ & ] ( auto & prop ) - > std : : string {
if ( FORMNORM )
return std : : format ( " {} " , prop . valueOrDefault ( ) ) ;
else
return std : : format ( R " ({{ " { } " : {}}}) " , PROP , prop . valueOrDefault ( ) ) ;
} ;
2025-11-17 18:34:02 +00:00
if ( PROP = = " animation " ) {
auto & animationStyle = PWINDOW - > m_ruleApplicator - > animationStyle ( ) ;
2025-08-18 16:41:17 +01:00
if ( FORMNORM )
return animationStyle . valueOr ( " (unset) " ) ;
else
return std : : format ( R " ({{ " { } " : " { } " }}) " , PROP , animationStyle . valueOr ( " " ) ) ;
2025-11-17 18:34:02 +00:00
} else if ( PROP = = " max_size " )
2025-08-18 16:41:17 +01:00
return sizeToString ( true ) ;
2025-11-17 18:34:02 +00:00
else if ( PROP = = " min_size " )
2025-08-18 16:41:17 +01:00
return sizeToString ( false ) ;
2025-11-17 18:34:02 +00:00
else if ( PROP = = " opacity " )
return alphaToString ( PWINDOW - > m_ruleApplicator - > alpha ( ) , true ) ;
else if ( PROP = = " opacity_inactive " )
return alphaToString ( PWINDOW - > m_ruleApplicator - > alphaInactive ( ) , true ) ;
else if ( PROP = = " opacity_fullscreen " )
return alphaToString ( PWINDOW - > m_ruleApplicator - > alphaFullscreen ( ) , true ) ;
else if ( PROP = = " opacity_override " )
return alphaToString ( PWINDOW - > m_ruleApplicator - > alpha ( ) , false ) ;
else if ( PROP = = " opacity_inactive_override " )
return alphaToString ( PWINDOW - > m_ruleApplicator - > alphaInactive ( ) , false ) ;
else if ( PROP = = " opacity_fullscreen_override " )
return alphaToString ( PWINDOW - > m_ruleApplicator - > alphaFullscreen ( ) , false ) ;
else if ( PROP = = " active_border_color " )
2025-08-18 16:41:17 +01:00
return borderColorToString ( true ) ;
2025-11-17 18:34:02 +00:00
else if ( PROP = = " inactive_border_color " )
2025-08-18 16:41:17 +01:00
return borderColorToString ( false ) ;
2025-11-17 18:34:02 +00:00
else if ( PROP = = " allows_input " )
return windowPropToString ( PWINDOW - > m_ruleApplicator - > allowsInput ( ) ) ;
else if ( PROP = = " decorate " )
return windowPropToString ( PWINDOW - > m_ruleApplicator - > decorate ( ) ) ;
else if ( PROP = = " focus_on_activate " )
return windowPropToString ( PWINDOW - > m_ruleApplicator - > focusOnActivate ( ) ) ;
else if ( PROP = = " keep_aspect_ratio " )
return windowPropToString ( PWINDOW - > m_ruleApplicator - > keepAspectRatio ( ) ) ;
else if ( PROP = = " nearest_neighbor " )
return windowPropToString ( PWINDOW - > m_ruleApplicator - > nearestNeighbor ( ) ) ;
else if ( PROP = = " no_anim " )
return windowPropToString ( PWINDOW - > m_ruleApplicator - > noAnim ( ) ) ;
else if ( PROP = = " no_blur " )
return windowPropToString ( PWINDOW - > m_ruleApplicator - > noBlur ( ) ) ;
else if ( PROP = = " no_dim " )
return windowPropToString ( PWINDOW - > m_ruleApplicator - > noDim ( ) ) ;
else if ( PROP = = " no_focus " )
return windowPropToString ( PWINDOW - > m_ruleApplicator - > noFocus ( ) ) ;
else if ( PROP = = " no_max_size " )
return windowPropToString ( PWINDOW - > m_ruleApplicator - > noMaxSize ( ) ) ;
else if ( PROP = = " no_shadow " )
return windowPropToString ( PWINDOW - > m_ruleApplicator - > noShadow ( ) ) ;
else if ( PROP = = " no_shortcuts_inhibit " )
return windowPropToString ( PWINDOW - > m_ruleApplicator - > noShortcutsInhibit ( ) ) ;
else if ( PROP = = " opaque " )
return windowPropToString ( PWINDOW - > m_ruleApplicator - > opaque ( ) ) ;
else if ( PROP = = " dim_around " )
return windowPropToString ( PWINDOW - > m_ruleApplicator - > dimAround ( ) ) ;
else if ( PROP = = " force_rgbx " )
return windowPropToString ( PWINDOW - > m_ruleApplicator - > RGBX ( ) ) ;
else if ( PROP = = " sync_fullscreen " )
return windowPropToString ( PWINDOW - > m_ruleApplicator - > syncFullscreen ( ) ) ;
else if ( PROP = = " immediate " )
return windowPropToString ( PWINDOW - > m_ruleApplicator - > tearing ( ) ) ;
else if ( PROP = = " xray " )
return windowPropToString ( PWINDOW - > m_ruleApplicator - > xray ( ) ) ;
else if ( PROP = = " render_unfocused " )
return windowPropToString ( PWINDOW - > m_ruleApplicator - > renderUnfocused ( ) ) ;
else if ( PROP = = " no_follow_mouse " )
return windowPropToString ( PWINDOW - > m_ruleApplicator - > noFollowMouse ( ) ) ;
else if ( PROP = = " no_screen_share " )
return windowPropToString ( PWINDOW - > m_ruleApplicator - > noScreenShare ( ) ) ;
else if ( PROP = = " no_vrr " )
return windowPropToString ( PWINDOW - > m_ruleApplicator - > noVRR ( ) ) ;
else if ( PROP = = " persistent_size " )
return windowPropToString ( PWINDOW - > m_ruleApplicator - > persistentSize ( ) ) ;
else if ( PROP = = " stay_focused " )
return windowPropToString ( PWINDOW - > m_ruleApplicator - > stayFocused ( ) ) ;
else if ( PROP = = " idle_inhibit " )
return windowPropToString ( PWINDOW - > m_ruleApplicator - > idleInhibitMode ( ) ) ;
else if ( PROP = = " border_size " )
return windowPropToString ( PWINDOW - > m_ruleApplicator - > borderSize ( ) ) ;
else if ( PROP = = " rounding " )
return windowPropToString ( PWINDOW - > m_ruleApplicator - > rounding ( ) ) ;
else if ( PROP = = " rounding_power " )
return windowPropToString ( PWINDOW - > m_ruleApplicator - > roundingPower ( ) ) ;
else if ( PROP = = " scroll_mouse " )
return windowPropToString ( PWINDOW - > m_ruleApplicator - > scrollMouse ( ) ) ;
else if ( PROP = = " scroll_touchpad " )
return windowPropToString ( PWINDOW - > m_ruleApplicator - > scrollTouchpad ( ) ) ;
2025-08-18 16:41:17 +01:00
return " prop not found " ;
}
2024-12-18 19:56:01 -06:00
static std : : string dispatchGetOption ( eHyprCtlOutputFormat format , std : : string request ) {
2022-08-11 21:16:38 +02:00
std : : string curitem = " " ;
2022-12-16 17:17:31 +00:00
auto nextItem = [ & ] ( ) {
2022-08-11 21:16:38 +02:00
auto idx = request . find_first_of ( ' ' ) ;
if ( idx ! = std : : string : : npos ) {
curitem = request . substr ( 0 , idx ) ;
request = request . substr ( idx + 1 ) ;
} else {
curitem = request ;
request = " " ;
}
2024-06-11 17:17:45 +02:00
curitem = trim ( curitem ) ;
2022-08-11 21:16:38 +02:00
} ;
nextItem ( ) ;
nextItem ( ) ;
2024-02-18 15:00:34 +00:00
const auto VAR = g_pConfigManager - > getHyprlangConfigValuePtr ( curitem ) ;
2022-08-11 21:16:38 +02:00
2024-02-18 15:00:34 +00:00
if ( ! VAR )
2022-08-11 21:16:38 +02:00
return " no such option " ;
2024-02-18 15:00:34 +00:00
const auto VAL = VAR - > getValue ( ) ;
const auto TYPE = std : : type_index ( VAL . type ( ) ) ;
if ( format = = FORMAT_NORMAL ) {
if ( TYPE = = typeid ( Hyprlang : : INT ) )
return std : : format ( " int: {} \n set: {} " , std : : any_cast < Hyprlang : : INT > ( VAL ) , VAR - > m_bSetByUser ) ;
else if ( TYPE = = typeid ( Hyprlang : : FLOAT ) )
return std : : format ( " float: {:2f} \n set: {} " , std : : any_cast < Hyprlang : : FLOAT > ( VAL ) , VAR - > m_bSetByUser ) ;
else if ( TYPE = = typeid ( Hyprlang : : VEC2 ) )
return std : : format ( " vec2: [{}, {}] \n set: {} " , std : : any_cast < Hyprlang : : VEC2 > ( VAL ) . x , std : : any_cast < Hyprlang : : VEC2 > ( VAL ) . y , VAR - > m_bSetByUser ) ;
else if ( TYPE = = typeid ( Hyprlang : : STRING ) )
return std : : format ( " str: {} \n set: {} " , std : : any_cast < Hyprlang : : STRING > ( VAL ) , VAR - > m_bSetByUser ) ;
2024-03-04 10:36:32 +00:00
else if ( TYPE = = typeid ( void * ) )
2025-08-14 19:44:56 +05:00
return std : : format ( " custom type: {} \n set: {} " , sc < ICustomConfigValueData * > ( std : : any_cast < void * > ( VAL ) ) - > toString ( ) , VAR - > m_bSetByUser ) ;
2024-02-18 15:00:34 +00:00
} else {
if ( TYPE = = typeid ( Hyprlang : : INT ) )
2024-12-07 18:51:18 +01:00
return std : : format ( R " ({{ " option " : " { } " , " int " : {}, " set " : {} }}) " , curitem , std : : any_cast < Hyprlang : : INT > ( VAL ) , VAR - > m_bSetByUser ) ;
2024-02-18 15:00:34 +00:00
else if ( TYPE = = typeid ( Hyprlang : : FLOAT ) )
2024-12-07 18:51:18 +01:00
return std : : format ( R " ({{ " option " : " { } " , " float " : {:2f}, " set " : {} }}) " , curitem , std : : any_cast < Hyprlang : : FLOAT > ( VAL ) , VAR - > m_bSetByUser ) ;
2024-02-18 15:00:34 +00:00
else if ( TYPE = = typeid ( Hyprlang : : VEC2 ) )
2024-12-07 18:51:18 +01:00
return std : : format ( R " ({{ " option " : " { } " , " vec2 " : [{},{}], " set " : {} }}) " , curitem , std : : any_cast < Hyprlang : : VEC2 > ( VAL ) . x , std : : any_cast < Hyprlang : : VEC2 > ( VAL ) . y ,
2024-02-18 15:00:34 +00:00
VAR - > m_bSetByUser ) ;
else if ( TYPE = = typeid ( Hyprlang : : STRING ) )
2024-12-07 18:51:18 +01:00
return std : : format ( R " ({{ " option " : " { } " , " str " : " { } " , " set " : {} }}) " , curitem , escapeJSONStrings ( std : : any_cast < Hyprlang : : STRING > ( VAL ) ) , VAR - > m_bSetByUser ) ;
2024-03-04 10:36:32 +00:00
else if ( TYPE = = typeid ( void * ) )
2025-08-14 19:44:56 +05:00
return std : : format ( R " ({{ " option " : " { } " , " custom " : " { } " , " set " : {} }}) " , curitem , sc < ICustomConfigValueData * > ( std : : any_cast < void * > ( VAL ) ) - > toString ( ) , VAR - > m_bSetByUser ) ;
2022-08-11 21:16:38 +02:00
}
2024-02-18 15:00:34 +00:00
return " invalid type (internal error) " ;
2022-08-11 21:16:38 +02:00
}
2024-12-18 19:56:01 -06:00
static std : : string decorationRequest ( eHyprCtlOutputFormat format , std : : string request ) {
2023-12-28 15:38:16 +00:00
CVarList vars ( request , 0 , ' ' ) ;
const auto PWINDOW = g_pCompositor - > getWindowByRegex ( vars [ 1 ] ) ;
if ( ! PWINDOW )
return " none " ;
std : : string result = " " ;
2024-02-05 01:56:38 +00:00
if ( format = = eHyprCtlOutputFormat : : FORMAT_JSON ) {
2023-12-28 15:38:16 +00:00
result + = " [ " ;
2025-04-28 22:25:22 +02:00
for ( auto const & wd : PWINDOW - > m_windowDecorations ) {
2023-12-28 15:38:16 +00:00
result + = " { \n \" decorationName \" : \" " + wd - > getDisplayName ( ) + " \" , \n \" priority \" : " + std : : to_string ( wd - > getPositioningInfo ( ) . priority ) + " \n }, " ;
}
trimTrailingComma ( result ) ;
result + = " ] " ;
} else {
result = + " Decoration \t Priority \n " ;
2025-04-28 22:25:22 +02:00
for ( auto const & wd : PWINDOW - > m_windowDecorations ) {
2023-12-28 15:38:16 +00:00
result + = wd - > getDisplayName ( ) + " \t " + std : : to_string ( wd - > getPositioningInfo ( ) . priority ) + " \n " ;
}
}
return result ;
}
2024-12-18 19:56:01 -06:00
static std : : string dispatchOutput ( eHyprCtlOutputFormat format , std : : string request ) {
2024-06-05 12:26:38 -04:00
CVarList vars ( request , 0 , ' ' ) ;
2022-11-05 18:04:44 +00:00
2024-06-05 12:26:38 -04:00
if ( vars . size ( ) < 2 )
return " not enough args " ;
const auto MODE = vars [ 1 ] ;
2022-11-05 18:04:44 +00:00
2024-07-21 13:09:54 +02:00
bool added = false ;
if ( ! vars [ 3 ] . empty ( ) ) {
2025-04-22 15:23:29 +02:00
for ( auto const & m : g_pCompositor - > m_realMonitors ) {
2025-04-30 23:45:20 +02:00
if ( m - > m_name = = vars [ 3 ] )
2024-07-21 13:09:54 +02:00
return " Name already taken " ;
}
}
2022-11-05 18:04:44 +00:00
if ( MODE = = " create " | | MODE = = " add " ) {
2024-06-05 12:26:38 -04:00
if ( g_pCompositor - > getMonitorFromName ( vars [ 3 ] ) )
return " A real monitor already uses that name. " ;
2025-04-22 15:23:29 +02:00
for ( auto const & impl : g_pCompositor - > m_aqBackend - > getImplementations ( ) | std : : views : : reverse ) {
2024-07-21 13:09:54 +02:00
auto type = impl - > type ( ) ;
if ( type = = Aquamarine : : AQ_BACKEND_HEADLESS & & ( vars [ 2 ] = = " headless " | | vars [ 2 ] = = " auto " ) ) {
added = true ;
impl - > createOutput ( vars [ 3 ] ) ;
break ;
}
2022-11-05 18:04:44 +00:00
2024-07-21 13:09:54 +02:00
if ( type = = Aquamarine : : AQ_BACKEND_WAYLAND & & ( vars [ 2 ] = = " wayland " | | vars [ 2 ] = = " auto " ) ) {
added = true ;
impl - > createOutput ( vars [ 3 ] ) ;
break ;
}
}
2022-11-05 18:04:44 +00:00
2024-07-21 13:09:54 +02:00
if ( ! added )
2022-11-05 18:04:44 +00:00
return " no backend replied to the request " ;
} else if ( MODE = = " destroy " | | MODE = = " remove " ) {
2024-06-05 12:26:38 -04:00
const auto PMONITOR = g_pCompositor - > getMonitorFromName ( vars [ 2 ] ) ;
2022-11-05 18:04:44 +00:00
if ( ! PMONITOR )
return " output not found " ;
2025-04-30 23:45:20 +02:00
if ( ! PMONITOR - > m_createdByUser )
2022-11-05 18:04:44 +00:00
return " cannot remove a real display. Use the monitor keyword. " ;
2025-04-30 23:45:20 +02:00
PMONITOR - > m_output - > destroy ( ) ;
2022-11-05 18:04:44 +00:00
}
return " ok " ;
}
2024-12-18 19:56:01 -06:00
static std : : string dispatchPlugin ( eHyprCtlOutputFormat format , std : : string request ) {
2023-02-27 12:32:38 +00:00
CVarList vars ( request , 0 , ' ' ) ;
if ( vars . size ( ) < 2 )
return " not enough args " ;
const auto OPERATION = vars [ 1 ] ;
const auto PATH = vars [ 2 ] ;
if ( OPERATION = = " load " ) {
if ( vars . size ( ) < 3 )
return " not enough args " ;
2025-04-29 18:59:43 +02:00
g_pHyprCtl - > m_currentRequestParams . pendingPromise = CPromise < std : : string > : : make ( [ PATH ] ( SP < CPromiseResolver < std : : string > > resolver ) {
g_pPluginSystem - > loadPlugin ( PATH ) - > then ( [ resolver , PATH ] ( SP < CPromiseResult < CPlugin * > > result ) {
if ( result - > hasError ( ) ) {
resolver - > reject ( result - > error ( ) ) ;
return ;
}
2023-02-27 12:32:38 +00:00
2025-04-29 18:59:43 +02:00
resolver - > resolve ( " ok " ) ;
} ) ;
} ) ;
return " ok " ;
2023-02-27 12:32:38 +00:00
} else if ( OPERATION = = " unload " ) {
if ( vars . size ( ) < 3 )
return " not enough args " ;
const auto PLUGIN = g_pPluginSystem - > getPluginByPath ( PATH ) ;
if ( ! PLUGIN )
return " plugin not loaded " ;
g_pPluginSystem - > unloadPlugin ( PLUGIN ) ;
} else if ( OPERATION = = " list " ) {
2024-11-17 02:18:30 +03:00
const auto PLUGINS = g_pPluginSystem - > getAllPlugins ( ) ;
std : : string result = " " ;
2024-03-31 22:45:22 +02:00
2024-11-17 02:18:30 +03:00
if ( format = = eHyprCtlOutputFormat : : FORMAT_JSON ) {
result + = " [ " ;
2023-02-27 12:32:38 +00:00
2025-05-31 23:49:50 +05:00
if ( PLUGINS . empty ( ) )
2024-11-17 02:18:30 +03:00
return " [] " ;
for ( auto const & p : PLUGINS ) {
result + = std : : format (
R " #(
{ {
" name " : " {} " ,
" author " : " {} " ,
" handle " : " {:x} " ,
" version " : " {} " ,
" description " : " {} "
} } , ) # " ,
2025-08-14 19:44:56 +05:00
escapeJSONStrings ( p - > m_name ) , escapeJSONStrings ( p - > m_author ) , rc < uintptr_t > ( p - > m_handle ) , escapeJSONStrings ( p - > m_version ) , escapeJSONStrings ( p - > m_description ) ) ;
2024-11-17 02:18:30 +03:00
}
trimTrailingComma ( result ) ;
result + = " ] " ;
} else {
2025-05-31 23:49:50 +05:00
if ( PLUGINS . empty ( ) )
2024-11-17 02:18:30 +03:00
return " no plugins loaded " ;
for ( auto const & p : PLUGINS ) {
2025-08-14 19:44:56 +05:00
result + = std : : format ( " \n Plugin {} by {}: \n \t Handle: {:x} \n \t Version: {} \n \t Description: {} \n " , p - > m_name , p - > m_author , rc < uintptr_t > ( p - > m_handle ) , p - > m_version ,
2025-05-03 16:06:24 +02:00
p - > m_description ) ;
2024-11-17 02:18:30 +03:00
}
2023-02-27 12:32:38 +00:00
}
2024-11-17 02:18:30 +03:00
return result ;
2023-02-27 12:32:38 +00:00
} else {
return " unknown opt " ;
}
return " ok " ;
}
2024-12-18 19:56:01 -06:00
static std : : string dispatchNotify ( eHyprCtlOutputFormat format , std : : string request ) {
2023-03-20 16:00:54 +00:00
CVarList vars ( request , 0 , ' ' ) ;
if ( vars . size ( ) < 5 )
return " not enough args " ;
const auto ICON = vars [ 1 ] ;
if ( ! isNumber ( ICON ) )
return " invalid arg 1 " ;
int icon = - 1 ;
try {
icon = std : : stoi ( ICON ) ;
} catch ( std : : exception & e ) { return " invalid arg 1 " ; }
2024-11-19 01:16:11 +00:00
if ( icon > ICON_NONE | | icon < 0 )
2023-03-20 16:00:54 +00:00
icon = ICON_NONE ;
const auto TIME = vars [ 2 ] ;
int time = 0 ;
try {
time = std : : stoi ( TIME ) ;
} catch ( std : : exception & e ) { return " invalid arg 2 " ; }
2024-11-19 01:16:11 +00:00
const auto COLOR_RESULT = configStringToInt ( vars [ 3 ] ) ;
if ( ! COLOR_RESULT )
return " invalid arg 3 " ;
2024-12-03 18:58:24 +00:00
CHyprColor color = * COLOR_RESULT ;
2023-03-20 16:00:54 +00:00
2024-12-03 18:58:24 +00:00
size_t msgidx = 4 ;
float fontsize = 13.f ;
2024-03-08 00:34:33 +01:00
if ( vars [ msgidx ] . length ( ) > 9 & & vars [ msgidx ] . compare ( 0 , 9 , " fontsize: " ) = = 0 ) {
2024-03-06 22:20:26 +01:00
const auto FONTSIZE = vars [ msgidx ] . substr ( 9 ) ;
2023-03-20 16:00:54 +00:00
2024-03-06 22:20:26 +01:00
if ( ! isNumber ( FONTSIZE , true ) )
return " invalid fontsize kwarg " ;
try {
fontsize = std : : stoi ( FONTSIZE ) ;
} catch ( std : : exception & e ) { return " invalid fontsize karg " ; }
+ + msgidx ;
2023-03-20 16:00:54 +00:00
}
2024-03-06 22:20:26 +01:00
if ( vars . size ( ) < = msgidx )
return " not enough args " ;
const auto MESSAGE = vars . join ( " " , msgidx ) ;
2023-03-20 16:00:54 +00:00
2025-08-14 19:44:56 +05:00
g_pHyprNotificationOverlay - > addNotification ( MESSAGE , color , time , sc < eIcons > ( icon ) , fontsize ) ;
2023-03-20 16:00:54 +00:00
return " ok " ;
}
2024-12-18 19:56:01 -06:00
static std : : string dispatchDismissNotify ( eHyprCtlOutputFormat format , std : : string request ) {
2024-03-02 19:12:31 +01:00
CVarList vars ( request , 0 , ' ' ) ;
int amount = - 1 ;
if ( vars . size ( ) > 1 ) {
const auto AMOUNT = vars [ 1 ] ;
if ( ! isNumber ( AMOUNT ) )
return " invalid arg 1 " ;
try {
amount = std : : stoi ( AMOUNT ) ;
} catch ( std : : exception & e ) { return " invalid arg 1 " ; }
}
g_pHyprNotificationOverlay - > dismissNotifications ( amount ) ;
return " ok " ;
}
2024-12-18 19:56:01 -06:00
static std : : string getIsLocked ( eHyprCtlOutputFormat format , std : : string request ) {
2024-05-13 16:57:06 +03:00
std : : string lockedStr = g_pSessionLockManager - > isSessionLocked ( ) ? " true " : " false " ;
if ( format = = eHyprCtlOutputFormat : : FORMAT_JSON )
lockedStr = std : : format ( R " #(
{ {
" locked " : { }
} }
) # " ,
lockedStr ) ;
return lockedStr ;
}
2024-12-18 19:56:01 -06:00
static std : : string getDescriptions ( eHyprCtlOutputFormat format , std : : string request ) {
2025-08-06 16:28:07 +02:00
std : : string json = " [ " ;
2024-08-17 17:33:16 +01:00
const auto & DESCS = g_pConfigManager - > getAllDescriptions ( ) ;
for ( const auto & d : DESCS ) {
json + = d . jsonify ( ) + " , \n " ;
}
json . pop_back ( ) ;
json . pop_back ( ) ;
2025-08-06 16:28:07 +02:00
json + = " ] \n " ;
2024-08-17 17:33:16 +01:00
return json ;
}
2024-12-18 19:56:01 -06:00
static std : : string submapRequest ( eHyprCtlOutputFormat format , std : : string request ) {
2025-10-11 02:40:18 +02:00
std : : string submap = g_pKeybindManager - > getCurrentSubmap ( ) . name ;
2024-09-24 11:25:05 +01:00
if ( submap . empty ( ) )
submap = " default " ;
return format = = FORMAT_JSON ? std : : format ( " {{ \" {} \" }} \n " , escapeJSONStrings ( submap ) ) : ( submap + " \n " ) ;
}
2025-03-29 03:19:35 +03:00
static std : : string reloadShaders ( eHyprCtlOutputFormat format , std : : string request ) {
if ( g_pHyprOpenGL - > initShaders ( ) )
return format = = FORMAT_JSON ? " { \" ok \" : true} " : " ok " ;
else
return format = = FORMAT_JSON ? " { \" ok \" : false} " : " error " ;
}
2024-02-05 01:43:45 +00:00
CHyprCtl : : CHyprCtl ( ) {
2024-02-05 01:56:38 +00:00
registerCommand ( SHyprCtlCommand { " workspaces " , true , workspacesRequest } ) ;
registerCommand ( SHyprCtlCommand { " workspacerules " , true , workspaceRulesRequest } ) ;
registerCommand ( SHyprCtlCommand { " activeworkspace " , true , activeWorkspaceRequest } ) ;
registerCommand ( SHyprCtlCommand { " clients " , true , clientsRequest } ) ;
registerCommand ( SHyprCtlCommand { " kill " , true , killRequest } ) ;
registerCommand ( SHyprCtlCommand { " activewindow " , true , activeWindowRequest } ) ;
registerCommand ( SHyprCtlCommand { " layers " , true , layersRequest } ) ;
registerCommand ( SHyprCtlCommand { " version " , true , versionRequest } ) ;
registerCommand ( SHyprCtlCommand { " devices " , true , devicesRequest } ) ;
registerCommand ( SHyprCtlCommand { " splash " , true , splashRequest } ) ;
registerCommand ( SHyprCtlCommand { " cursorpos " , true , cursorPosRequest } ) ;
registerCommand ( SHyprCtlCommand { " binds " , true , bindsRequest } ) ;
registerCommand ( SHyprCtlCommand { " globalshortcuts " , true , globalShortcutsRequest } ) ;
registerCommand ( SHyprCtlCommand { " systeminfo " , true , systemInfoRequest } ) ;
registerCommand ( SHyprCtlCommand { " animations " , true , animationsRequest } ) ;
registerCommand ( SHyprCtlCommand { " rollinglog " , true , rollinglogRequest } ) ;
registerCommand ( SHyprCtlCommand { " layouts " , true , layoutsRequest } ) ;
2024-03-20 21:55:13 -04:00
registerCommand ( SHyprCtlCommand { " configerrors " , true , configErrorsRequest } ) ;
2024-05-13 16:57:06 +03:00
registerCommand ( SHyprCtlCommand { " locked " , true , getIsLocked } ) ;
2024-08-17 17:33:16 +01:00
registerCommand ( SHyprCtlCommand { " descriptions " , true , getDescriptions } ) ;
2024-09-24 11:25:05 +01:00
registerCommand ( SHyprCtlCommand { " submap " , true , submapRequest } ) ;
2025-03-29 03:19:35 +03:00
registerCommand ( SHyprCtlCommand { . name = " reloadshaders " , . exact = true , . fn = reloadShaders } ) ;
2024-02-05 01:56:38 +00:00
registerCommand ( SHyprCtlCommand { " monitors " , false , monitorsRequest } ) ;
registerCommand ( SHyprCtlCommand { " reload " , false , reloadRequest } ) ;
registerCommand ( SHyprCtlCommand { " plugin " , false , dispatchPlugin } ) ;
registerCommand ( SHyprCtlCommand { " notify " , false , dispatchNotify } ) ;
2024-03-02 19:12:31 +01:00
registerCommand ( SHyprCtlCommand { " dismissnotify " , false , dispatchDismissNotify } ) ;
2025-08-18 16:41:17 +01:00
registerCommand ( SHyprCtlCommand { " getprop " , false , dispatchGetProp } ) ;
2024-02-05 01:56:38 +00:00
registerCommand ( SHyprCtlCommand { " seterror " , false , dispatchSeterror } ) ;
registerCommand ( SHyprCtlCommand { " switchxkblayout " , false , switchXKBLayoutRequest } ) ;
registerCommand ( SHyprCtlCommand { " output " , false , dispatchOutput } ) ;
registerCommand ( SHyprCtlCommand { " dispatch " , false , dispatchRequest } ) ;
registerCommand ( SHyprCtlCommand { " keyword " , false , dispatchKeyword } ) ;
registerCommand ( SHyprCtlCommand { " setcursor " , false , dispatchSetCursor } ) ;
registerCommand ( SHyprCtlCommand { " getoption " , false , dispatchGetOption } ) ;
registerCommand ( SHyprCtlCommand { " decorations " , false , decorationRequest } ) ;
registerCommand ( SHyprCtlCommand { " [[BATCH]] " , false , dispatchBatch } ) ;
2024-02-05 01:43:45 +00:00
startHyprCtlSocket ( ) ;
}
2024-06-02 18:42:54 +02:00
CHyprCtl : : ~ CHyprCtl ( ) {
if ( m_eventSource )
wl_event_source_remove ( m_eventSource ) ;
2024-07-31 21:00:14 +02:00
if ( ! m_socketPath . empty ( ) )
unlink ( m_socketPath . c_str ( ) ) ;
2024-06-02 18:42:54 +02:00
}
2024-05-05 17:16:00 +01:00
SP < SHyprCtlCommand > CHyprCtl : : registerCommand ( SHyprCtlCommand cmd ) {
2025-04-21 20:42:02 +02:00
return m_commands . emplace_back ( makeShared < SHyprCtlCommand > ( cmd ) ) ;
2024-02-05 01:43:45 +00:00
}
2024-05-05 17:16:00 +01:00
void CHyprCtl : : unregisterCommand ( const SP < SHyprCtlCommand > & cmd ) {
2025-04-21 20:42:02 +02:00
std : : erase ( m_commands , cmd ) ;
2024-02-05 01:43:45 +00:00
}
std : : string CHyprCtl : : getReply ( std : : string request ) {
2025-04-29 18:59:43 +02:00
auto format = eHyprCtlOutputFormat : : FORMAT_NORMAL ;
bool reloadAll = false ;
m_currentRequestParams . all = false ;
m_currentRequestParams . sysInfoConfig = false ;
2022-07-12 14:59:36 -06:00
2022-07-12 16:34:28 -06:00
// process flags for non-batch requests
2024-01-14 17:12:52 +00:00
if ( ! request . starts_with ( " [[BATCH]] " ) & & request . contains ( " / " ) ) {
2022-07-13 15:48:47 +02:00
long unsigned int sepIndex = 0 ;
2022-07-12 16:34:28 -06:00
for ( const auto & c : request ) {
if ( c = = ' / ' ) { // stop at separator
break ;
}
2024-01-14 17:12:52 +00:00
// after whitespace assume the first word as a keyword,
// so its value can have slashes (e.g., a path)
if ( c = = ' ' ) {
sepIndex = request . size ( ) ;
break ;
}
2022-07-12 16:34:28 -06:00
sepIndex + + ;
2022-09-25 20:07:48 +02:00
2022-07-12 16:34:28 -06:00
if ( c = = ' j ' )
2024-02-05 01:56:38 +00:00
format = eHyprCtlOutputFormat : : FORMAT_JSON ;
2024-03-08 17:47:12 +00:00
else if ( c = = ' r ' )
2024-02-24 14:01:58 +00:00
reloadAll = true ;
2024-03-08 17:47:12 +00:00
else if ( c = = ' a ' )
2025-04-21 20:42:02 +02:00
m_currentRequestParams . all = true ;
2024-05-25 20:46:07 +00:00
else if ( c = = ' c ' )
2025-04-21 20:42:02 +02:00
m_currentRequestParams . sysInfoConfig = true ;
2022-07-12 14:59:36 -06:00
}
2022-07-12 16:34:28 -06:00
if ( sepIndex < request . size ( ) )
request = request . substr ( sepIndex + 1 ) ; // remove flags and separator so we can compare the rest of the string
2022-07-12 14:59:36 -06:00
}
2024-02-24 14:01:58 +00:00
std : : string result = " " ;
2024-02-05 01:43:45 +00:00
// parse exact cmds first, then non-exact.
2025-04-21 20:42:02 +02:00
for ( auto const & cmd : m_commands ) {
2024-02-05 01:43:45 +00:00
if ( ! cmd - > exact )
continue ;
2024-02-24 14:01:58 +00:00
if ( cmd - > name = = request ) {
result = cmd - > fn ( format , request ) ;
break ;
}
2024-02-05 01:43:45 +00:00
}
2024-02-24 14:01:58 +00:00
if ( result . empty ( ) )
2025-04-21 20:42:02 +02:00
for ( auto const & cmd : m_commands ) {
2024-02-24 14:01:58 +00:00
if ( cmd - > exact )
continue ;
2024-02-05 01:43:45 +00:00
2024-02-24 14:01:58 +00:00
if ( request . starts_with ( cmd - > name ) ) {
result = cmd - > fn ( format , request ) ;
break ;
}
}
if ( result . empty ( ) )
return " unknown request " ;
if ( reloadAll ) {
2025-04-20 20:39:33 +02:00
g_pConfigManager - > m_wantsMonitorReload = true ; // for monitor keywords
2024-02-24 14:01:58 +00:00
g_pInputManager - > setKeyboardLayout ( ) ; // update kb layout
g_pInputManager - > setPointerConfigs ( ) ; // update mouse cfgs
g_pInputManager - > setTouchDeviceConfigs ( ) ; // update touch device cfgs
g_pInputManager - > setTabletConfigs ( ) ; // update tablets
2024-03-03 18:39:20 +00:00
static auto PLAYOUT = CConfigValue < std : : string > ( " general:layout " ) ;
2024-02-24 14:01:58 +00:00
g_pLayoutManager - > switchToLayout ( * PLAYOUT ) ; // update layout
2025-05-05 23:44:49 +02:00
g_pHyprOpenGL - > m_reloadScreenShader = true ;
2024-02-24 14:01:58 +00:00
2025-05-05 23:44:49 +02:00
for ( auto & [ m , rd ] : g_pHyprOpenGL - > m_monitorRenderResources ) {
2024-02-24 14:01:58 +00:00
rd . blurFBDirty = true ;
}
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 - > m_workspace | | ! w - > m_workspace - > isVisible ( ) )
2024-11-01 13:03:06 +00:00
continue ;
2025-11-17 18:34:02 +00:00
Desktop : : Rule : : ruleEngine ( ) - > updateAllRules ( ) ;
2024-11-01 13:03:06 +00:00
}
2025-04-22 15:23:29 +02:00
for ( auto const & m : g_pCompositor - > m_monitors ) {
2024-10-19 23:03:29 +01:00
g_pHyprRenderer - > damageMonitor ( m ) ;
2025-04-30 23:45:20 +02:00
g_pLayoutManager - > getCurrentLayout ( ) - > recalculateMonitor ( m - > m_id ) ;
2024-02-24 14:01:58 +00:00
}
2024-02-05 01:43:45 +00:00
}
2022-04-29 19:44:09 +02:00
2024-02-24 14:01:58 +00:00
return result ;
2022-04-29 19:44:09 +02:00
}
2024-02-05 01:43:45 +00:00
std : : string CHyprCtl : : makeDynamicCall ( const std : : string & input ) {
2023-02-27 12:32:38 +00:00
return getReply ( input ) ;
}
2024-12-18 19:56:01 -06:00
static bool successWrite ( int fd , const std : : string & data , bool needLog = true ) {
2024-06-14 13:11:40 +03:00
if ( write ( fd , data . c_str ( ) , data . length ( ) ) > 0 )
return true ;
if ( errno = = EAGAIN )
return true ;
if ( needLog )
Debug : : log ( ERR , " Couldn't write to socket. Error: " + std : : string ( strerror ( errno ) ) ) ;
return false ;
}
2024-12-18 19:56:01 -06:00
static void runWritingDebugLogThread ( const int conn ) {
2024-06-14 13:11:40 +03:00
using namespace std : : chrono_literals ;
Debug : : log ( LOG , " In followlog thread, got connection, start writing: {} " , conn ) ;
//will be finished, when reading side close connection
std : : thread ( [ conn ] ( ) {
2024-12-07 18:51:18 +01:00
while ( Debug : : SRollingLogFollow : : get ( ) . isRunning ( ) ) {
if ( Debug : : SRollingLogFollow : : get ( ) . isEmpty ( conn ) ) {
2024-06-14 13:11:40 +03:00
std : : this_thread : : sleep_for ( 1000 ms ) ;
continue ;
}
2024-12-07 18:51:18 +01:00
auto line = Debug : : SRollingLogFollow : : get ( ) . getLog ( conn ) ;
2024-06-14 13:11:40 +03:00
if ( ! successWrite ( conn , line ) )
// We cannot write, when connection is closed. So thread will successfully exit by itself
break ;
std : : this_thread : : sleep_for ( 100 ms ) ;
}
close ( conn ) ;
2024-12-07 18:51:18 +01:00
Debug : : SRollingLogFollow : : get ( ) . stopFor ( conn ) ;
2024-06-14 13:11:40 +03:00
} ) . detach ( ) ;
}
2024-12-18 19:56:01 -06:00
static bool isFollowUpRollingLogRequest ( const std : : string & request ) {
2024-06-14 13:11:40 +03:00
return request . contains ( " rollinglog " ) & & request . contains ( " f " ) ;
}
2024-12-18 19:56:01 -06:00
static int hyprCtlFDTick ( int fd , uint32_t mask , void * data ) {
2022-09-10 21:21:28 +02:00
if ( mask & WL_EVENT_ERROR | | mask & WL_EVENT_HANGUP )
return 0 ;
2025-04-21 20:42:02 +02:00
if ( ! g_pHyprCtl - > m_socketFD . isValid ( ) )
2025-01-30 12:30:12 +01:00
return 0 ;
2023-11-13 16:30:37 +00:00
sockaddr_in clientAddress ;
socklen_t clientSize = sizeof ( clientAddress ) ;
2022-09-10 21:21:28 +02:00
2025-08-14 19:44:56 +05:00
const auto ACCEPTEDCONNECTION = accept4 ( g_pHyprCtl - > m_socketFD . get ( ) , rc < sockaddr * > ( & clientAddress ) , & clientSize , SOCK_CLOEXEC ) ;
2022-09-10 21:21:28 +02:00
2023-11-13 16:30:37 +00:00
std : : array < char , 1024 > readBuffer ;
2022-09-10 21:21:28 +02:00
2025-04-29 18:59:43 +02:00
// try to get creds
CRED_T creds ;
uint32_t len = sizeof ( creds ) ;
if ( getsockopt ( ACCEPTEDCONNECTION , CRED_LVL , CRED_OPT , & creds , & len ) = = - 1 )
Debug : : log ( ERR , " Hyprctl: failed to get peer creds " ) ;
else {
g_pHyprCtl - > m_currentRequestParams . pid = creds . CRED_PID ;
Debug : : log ( LOG , " Hyprctl: new connection from pid {} " , creds . CRED_PID ) ;
}
2024-06-18 21:38:33 +02:00
//
pollfd pollfds [ 1 ] = {
{
. fd = ACCEPTEDCONNECTION ,
. events = POLLIN ,
} ,
} ;
int ret = poll ( pollfds , 1 , 5000 ) ;
2023-07-21 17:20:23 +02:00
2024-06-18 21:38:33 +02:00
if ( ret < = 0 ) {
2023-07-21 17:20:23 +02:00
close ( ACCEPTEDCONNECTION ) ;
return 0 ;
}
2023-11-13 16:30:37 +00:00
std : : string request ;
while ( true ) {
readBuffer . fill ( 0 ) ;
auto messageSize = read ( ACCEPTEDCONNECTION , readBuffer . data ( ) , 1023 ) ;
if ( messageSize < 1 )
break ;
std : : string recvd = readBuffer . data ( ) ;
request + = recvd ;
if ( messageSize < 1023 )
break ;
}
2022-04-21 22:00:03 +02:00
std : : string reply = " " ;
try {
2024-02-05 01:43:45 +00:00
reply = g_pHyprCtl - > getReply ( request ) ;
2022-04-21 22:00:03 +02:00
} catch ( std : : exception & e ) {
2023-09-06 12:51:36 +02:00
Debug : : log ( ERR , " Error in request: {} " , e . what ( ) ) ;
2022-04-21 22:00:03 +02:00
reply = " Err: " + std : : string ( e . what ( ) ) ;
}
2025-04-29 18:59:43 +02:00
if ( g_pHyprCtl - > m_currentRequestParams . pendingPromise ) {
// we have a promise pending
g_pHyprCtl - > m_currentRequestParams . pendingPromise - > then ( [ ACCEPTEDCONNECTION , request ] ( SP < CPromiseResult < std : : string > > result ) {
const auto RES = result - > hasError ( ) ? result - > error ( ) : result - > result ( ) ;
successWrite ( ACCEPTEDCONNECTION , RES ) ;
2022-04-21 22:00:03 +02:00
2025-04-29 18:59:43 +02:00
// No rollinglog or ensureMonitor here. These are only for plugins for now.
close ( ACCEPTEDCONNECTION ) ;
} ) ;
2022-08-03 17:12:38 +02:00
2025-04-29 18:59:43 +02:00
g_pHyprCtl - > m_currentRequestParams . pendingPromise . reset ( ) ;
} else {
successWrite ( ACCEPTEDCONNECTION , reply ) ;
if ( isFollowUpRollingLogRequest ( request ) ) {
Debug : : log ( LOG , " Followup rollinglog request received. Starting thread to write to socket. " ) ;
Debug : : SRollingLogFollow : : get ( ) . startFor ( ACCEPTEDCONNECTION ) ;
runWritingDebugLogThread ( ACCEPTEDCONNECTION ) ;
Debug : : log ( LOG , Debug : : SRollingLogFollow : : get ( ) . debugInfo ( ) ) ;
} else
close ( ACCEPTEDCONNECTION ) ;
if ( g_pConfigManager - > m_wantsMonitorReload )
g_pConfigManager - > ensureMonitorStatus ( ) ;
g_pHyprCtl - > m_currentRequestParams . pid = 0 ;
}
2022-04-21 22:00:03 +02:00
2022-09-10 21:21:28 +02:00
return 0 ;
2022-04-21 22:00:03 +02:00
}
2024-02-05 01:43:45 +00:00
void CHyprCtl : : startHyprCtlSocket ( ) {
2025-04-21 20:42:02 +02:00
m_socketFD = CFileDescriptor { socket ( AF_UNIX , SOCK_STREAM | SOCK_CLOEXEC , 0 ) } ;
2022-03-21 18:29:41 +01:00
2025-04-21 20:42:02 +02:00
if ( ! m_socketFD . isValid ( ) ) {
2022-09-10 21:21:28 +02:00
Debug : : log ( ERR , " Couldn't start the Hyprland Socket. (1) IPC will not work. " ) ;
return ;
}
2022-03-21 18:29:41 +01:00
2022-09-10 21:21:28 +02:00
sockaddr_un SERVERADDRESS = { . sun_family = AF_UNIX } ;
2022-03-21 18:29:41 +01:00
2025-04-22 15:23:29 +02:00
m_socketPath = g_pCompositor - > m_instancePath + " /.socket.sock " ;
2022-03-21 18:29:41 +01:00
2025-07-20 18:31:53 +05:00
snprintf ( SERVERADDRESS . sun_path , sizeof ( SERVERADDRESS . sun_path ) , " %s " , m_socketPath . c_str ( ) ) ;
2022-03-21 18:29:41 +01:00
2025-08-14 19:44:56 +05:00
if ( bind ( m_socketFD . get ( ) , rc < sockaddr * > ( & SERVERADDRESS ) , SUN_LEN ( & SERVERADDRESS ) ) < 0 ) {
2022-12-16 17:17:31 +00:00
Debug : : log ( ERR , " Couldn't start the Hyprland Socket. (2) IPC will not work. " ) ;
return ;
}
2022-03-21 18:29:41 +01:00
2022-09-10 21:21:28 +02:00
// 10 max queued.
2025-04-21 20:42:02 +02:00
listen ( m_socketFD . get ( ) , 10 ) ;
2022-03-22 16:54:45 +01:00
2024-07-31 21:00:14 +02:00
Debug : : log ( LOG , " Hypr socket started at {} " , m_socketPath ) ;
2022-08-28 11:19:08 +02:00
2025-04-22 15:23:29 +02:00
m_eventSource = wl_event_loop_add_fd ( g_pCompositor - > m_wlEventLoop , m_socketFD . get ( ) , WL_EVENT_READABLE , hyprCtlFDTick , nullptr ) ;
2022-08-04 16:25:56 -07:00
}