2024-02-18 23:08:03 +00:00
# include "hyprlock.hpp"
2025-01-06 12:34:21 +00:00
# include "AnimationManager.hpp"
2024-02-18 23:08:03 +00:00
# include "../helpers/Log.hpp"
# include "../config/ConfigManager.hpp"
# include "../renderer/Renderer.hpp"
2025-09-03 09:32:12 +00:00
# include "../renderer/AsyncResourceGatherer.hpp"
2024-12-16 18:58:36 +00:00
# include "../auth/Auth.hpp"
# include "../auth/Fingerprint.hpp"
2024-02-18 23:08:03 +00:00
# include "Egl.hpp"
2025-06-22 09:24:39 +02:00
# include <chrono>
2025-03-05 08:35:43 +01:00
# include <hyprutils/memory/UniquePtr.hpp>
2024-02-20 00:11:19 +00:00
# include <sys/wait.h>
# include <sys/poll.h>
2024-02-18 23:08:03 +00:00
# include <sys/mman.h>
2024-02-20 00:11:19 +00:00
# include <fcntl.h>
2025-02-06 16:36:08 +05:00
# include <csignal>
2024-02-20 00:11:19 +00:00
# include <unistd.h>
2025-02-06 16:36:08 +05:00
# include <cassert>
# include <cstring>
2024-02-21 21:38:37 +00:00
# include <xf86drm.h>
2024-03-05 23:32:31 +00:00
# include <filesystem>
# include <fstream>
2024-03-15 15:43:29 +01:00
# include <algorithm>
2024-10-21 17:08:24 -07:00
# include <sdbus-c++/sdbus-c++.h>
2024-12-08 15:42:16 +00:00
# include <hyprutils/os/Process.hpp>
2025-02-09 17:39:23 +00:00
# include <malloc.h>
2024-12-08 15:42:16 +00:00
using namespace Hyprutils : : OS ;
2024-02-18 23:08:03 +00:00
2025-02-09 17:39:23 +00:00
static void setMallocThreshold ( ) {
# ifdef M_TRIM_THRESHOLD
// The default is 128 pages,
// which is very large and can lead to a lot of memory used for no reason
// because trimming hasn't happened
static const int PAGESIZE = sysconf ( _SC_PAGESIZE ) ;
mallopt ( M_TRIM_THRESHOLD , 6 * PAGESIZE ) ;
# endif
}
2025-06-26 09:35:25 +02:00
CHyprlock : : CHyprlock ( const std : : string & wlDisplay , const bool immediateRender , const int graceSeconds ) {
2025-02-09 17:39:23 +00:00
setMallocThreshold ( ) ;
2024-02-19 15:20:52 +00:00
m_sWaylandState . display = wl_display_connect ( wlDisplay . empty ( ) ? nullptr : wlDisplay . c_str ( ) ) ;
2025-03-30 01:33:34 +01:00
RASSERT ( m_sWaylandState . display , " Couldn't connect to a wayland compositor " ) ;
2024-02-18 23:08:03 +00:00
2025-03-05 08:35:43 +01:00
g_pEGL = makeUnique < CEGL > ( m_sWaylandState . display ) ;
2024-02-18 23:08:03 +00:00
2025-06-26 09:35:25 +02:00
if ( graceSeconds > 0 )
m_tGraceEnds = std : : chrono : : system_clock : : now ( ) + std : : chrono : : seconds ( graceSeconds ) ;
else
2024-03-08 23:54:34 +01:00
m_tGraceEnds = std : : chrono : : system_clock : : from_time_t ( 0 ) ;
2024-07-07 18:43:17 +02:00
2025-01-29 22:10:27 +00:00
static const auto IMMEDIATERENDER = g_pConfigManager - > getValue < Hyprlang : : INT > ( " general:immediate_render " ) ;
m_bImmediateRender = immediateRender | | * IMMEDIATERENDER ;
2024-08-03 17:34:54 +02:00
2024-08-05 20:22:01 +02:00
const auto CURRENTDESKTOP = getenv ( " XDG_CURRENT_DESKTOP " ) ;
const auto SZCURRENTD = std : : string { CURRENTDESKTOP ? CURRENTDESKTOP : " " } ;
m_sCurrentDesktop = SZCURRENTD ;
2024-02-18 23:08:03 +00:00
}
2024-05-25 20:05:37 +02:00
CHyprlock : : ~ CHyprlock ( ) {
2024-07-06 12:24:29 +02:00
if ( dma . gbmDevice )
gbm_device_destroy ( dma . gbmDevice ) ;
2024-02-21 21:38:37 +00:00
}
2024-12-29 18:36:08 +00:00
static void registerSignalAction ( int sig , void ( * handler ) ( int ) , int sa_flags = 0 ) {
struct sigaction sa ;
sa . sa_handler = handler ;
sigemptyset ( & sa . sa_mask ) ;
sa . sa_flags = sa_flags ;
sigaction ( sig , & sa , nullptr ) ;
2024-02-21 21:38:37 +00:00
}
2024-12-29 18:36:08 +00:00
static void handleUnlockSignal ( int sig ) {
if ( sig = = SIGUSR1 ) {
Debug : : log ( LOG , " Unlocking with a SIGUSR1 " ) ;
2025-04-30 09:12:40 +02:00
g_pAuth - > enqueueUnlock ( ) ;
2024-02-21 21:38:37 +00:00
}
}
2024-12-29 18:36:08 +00:00
static void handleForceUpdateSignal ( int sig ) {
if ( sig = = SIGUSR2 ) {
for ( auto & t : g_pHyprlock - > getTimers ( ) ) {
if ( t - > canForceUpdate ( ) ) {
t - > call ( t ) ;
t - > cancel ( ) ;
}
}
2024-02-21 21:38:37 +00:00
}
}
2024-12-29 18:36:08 +00:00
static void handlePollTerminate ( int sig ) {
2024-02-21 21:38:37 +00:00
;
}
static char * gbm_find_render_node ( drmDevice * device ) {
drmDevice * devices [ 64 ] ;
2024-12-29 18:36:08 +00:00
char * render_node = nullptr ;
2024-02-21 21:38:37 +00:00
int n = drmGetDevices2 ( 0 , devices , sizeof ( devices ) / sizeof ( devices [ 0 ] ) ) ;
for ( int i = 0 ; i < n ; + + i ) {
drmDevice * dev = devices [ i ] ;
if ( device & & ! drmDevicesEqual ( device , dev ) ) {
continue ;
}
if ( ! ( dev - > available_nodes & ( 1 < < DRM_NODE_RENDER ) ) )
continue ;
render_node = strdup ( dev - > nodes [ DRM_NODE_RENDER ] ) ;
break ;
}
drmFreeDevices ( devices , n ) ;
return render_node ;
}
gbm_device * CHyprlock : : createGBMDevice ( drmDevice * dev ) {
char * renderNode = gbm_find_render_node ( dev ) ;
if ( ! renderNode ) {
Debug : : log ( ERR , " [core] Couldn't find a render node " ) ;
return nullptr ;
}
Debug : : log ( TRACE , " [core] createGBMDevice: render node {} " , renderNode ) ;
int fd = open ( renderNode , O_RDWR | O_CLOEXEC ) ;
if ( fd < 0 ) {
Debug : : log ( ERR , " [core] couldn't open render node " ) ;
free ( renderNode ) ;
2024-12-29 18:36:08 +00:00
return nullptr ;
2024-02-21 21:38:37 +00:00
}
free ( renderNode ) ;
return gbm_create_device ( fd ) ;
}
2024-12-29 18:36:08 +00:00
void CHyprlock : : addDmabufListener ( ) {
dma . linuxDmabufFeedback - > setTrancheDone ( [ this ] ( CCZwpLinuxDmabufFeedbackV1 * r ) {
Debug : : log ( TRACE , " [core] dmabufFeedbackTrancheDone " ) ;
2024-02-21 21:38:37 +00:00
2024-12-29 18:36:08 +00:00
dma . deviceUsed = false ;
} ) ;
2024-02-18 23:08:03 +00:00
2024-12-29 18:36:08 +00:00
dma . linuxDmabufFeedback - > setTrancheFormats ( [ this ] ( CCZwpLinuxDmabufFeedbackV1 * r , wl_array * indices ) {
Debug : : log ( TRACE , " [core] dmabufFeedbackTrancheFormats " ) ;
2024-02-18 23:08:03 +00:00
2024-12-29 18:36:08 +00:00
if ( ! dma . deviceUsed | | ! dma . formatTable )
return ;
2024-02-18 23:08:03 +00:00
2024-12-29 18:36:08 +00:00
struct fm_entry {
uint32_t format ;
uint32_t padding ;
uint64_t modifier ;
} ;
// An entry in the table has to be 16 bytes long
2025-02-06 16:36:08 +05:00
static_assert ( sizeof ( fm_entry ) = = 16 ) ;
2024-02-18 23:08:03 +00:00
2024-12-29 18:36:08 +00:00
uint32_t n_modifiers = dma . formatTableSize / sizeof ( fm_entry ) ;
fm_entry * fm_entry = ( struct fm_entry * ) dma . formatTable ;
uint16_t * idx ;
2024-02-18 23:08:03 +00:00
2024-12-29 18:36:08 +00:00
for ( idx = ( uint16_t * ) indices - > data ; ( const char * ) idx < ( const char * ) indices - > data + indices - > size ; idx + + ) {
if ( * idx > = n_modifiers )
continue ;
Debug : : log ( TRACE , " GPU Reports supported format {:x} with modifier {:x} " , ( fm_entry + * idx ) - > format , ( fm_entry + * idx ) - > modifier ) ;
dma . dmabufMods . push_back ( { ( fm_entry + * idx ) - > format , ( fm_entry + * idx ) - > modifier } ) ;
2024-02-18 23:08:03 +00:00
}
2024-12-29 18:36:08 +00:00
} ) ;
2024-02-18 23:08:03 +00:00
2024-12-29 18:36:08 +00:00
dma . linuxDmabufFeedback - > setTrancheTargetDevice ( [ this ] ( CCZwpLinuxDmabufFeedbackV1 * r , wl_array * device_arr ) {
Debug : : log ( TRACE , " [core] dmabufFeedbackTrancheTargetDevice " ) ;
dev_t device ;
assert ( device_arr - > size = = sizeof ( device ) ) ;
memcpy ( & device , device_arr - > data , sizeof ( device ) ) ;
drmDevice * drmDev ;
if ( drmGetDeviceFromDevId ( device , /* flags */ 0 , & drmDev ) ! = 0 )
2024-02-21 21:38:37 +00:00
return ;
2024-12-29 18:36:08 +00:00
if ( dma . gbmDevice ) {
drmDevice * drmDevRenderer = nullptr ;
drmGetDevice2 ( gbm_device_get_fd ( dma . gbmDevice ) , /* flags */ 0 , & drmDevRenderer ) ;
dma . deviceUsed = drmDevicesEqual ( drmDevRenderer , drmDev ) ;
} else {
dma . gbmDevice = createGBMDevice ( drmDev ) ;
dma . deviceUsed = dma . gbm ;
2024-02-21 21:38:37 +00:00
}
2024-12-29 18:36:08 +00:00
} ) ;
2024-02-21 21:38:37 +00:00
2024-12-29 18:36:08 +00:00
dma . linuxDmabufFeedback - > setDone ( [ this ] ( CCZwpLinuxDmabufFeedbackV1 * r ) {
Debug : : log ( TRACE , " [core] dmabufFeedbackDone " ) ;
2024-02-18 23:08:03 +00:00
2024-12-29 18:36:08 +00:00
if ( dma . formatTable )
munmap ( dma . formatTable , dma . formatTableSize ) ;
2024-02-18 23:08:03 +00:00
2024-12-29 18:36:08 +00:00
dma . formatTable = nullptr ;
dma . formatTableSize = 0 ;
} ) ;
2024-02-18 23:08:03 +00:00
2024-12-29 18:36:08 +00:00
dma . linuxDmabufFeedback - > setFormatTable ( [ this ] ( CCZwpLinuxDmabufFeedbackV1 * r , int fd , uint32_t size ) {
Debug : : log ( TRACE , " [core] dmabufFeedbackFormatTable " ) ;
2024-03-08 23:54:34 +01:00
2024-12-29 18:36:08 +00:00
dma . dmabufMods . clear ( ) ;
2024-02-26 01:08:12 +11:00
2024-12-29 18:36:08 +00:00
dma . formatTable = mmap ( nullptr , size , PROT_READ , MAP_PRIVATE , fd , 0 ) ;
if ( dma . formatTable = = MAP_FAILED ) {
Debug : : log ( ERR , " [core] format table failed to mmap " ) ;
dma . formatTable = nullptr ;
dma . formatTableSize = 0 ;
return ;
2024-03-14 00:25:06 +03:00
}
2024-12-29 18:36:08 +00:00
dma . formatTableSize = size ;
} ) ;
2024-03-11 00:38:01 +03:00
2024-12-29 18:36:08 +00:00
dma . linuxDmabufFeedback - > setMainDevice ( [ this ] ( CCZwpLinuxDmabufFeedbackV1 * r , wl_array * device_arr ) {
Debug : : log ( LOG , " [core] dmabufFeedbackMainDevice " ) ;
2024-03-08 23:54:34 +01:00
2024-12-29 18:36:08 +00:00
RASSERT ( ! dma . gbm , " double dmabuf feedback " ) ;
2024-03-10 21:42:42 +00:00
2024-12-29 18:36:08 +00:00
dev_t device ;
assert ( device_arr - > size = = sizeof ( device ) ) ;
memcpy ( & device , device_arr - > data , sizeof ( device ) ) ;
2024-03-10 21:42:42 +00:00
2024-12-29 18:36:08 +00:00
drmDevice * drmDev ;
2025-03-30 01:33:34 +01:00
RASSERT ( drmGetDeviceFromDevId ( device , /* flags */ 0 , & drmDev ) = = 0 , " unable to open main device? " ) ;
2024-12-29 18:36:08 +00:00
dma . gbmDevice = createGBMDevice ( drmDev ) ;
drmFreeDevice ( & drmDev ) ;
} ) ;
dma . linuxDmabuf - > setModifier ( [ this ] ( CCZwpLinuxDmabufV1 * r , uint32_t format , uint32_t modifier_hi , uint32_t modifier_lo ) {
dma . dmabufMods . push_back ( { format , ( ( ( uint64_t ) modifier_hi ) < < 32 ) | modifier_lo } ) ;
} ) ;
2024-03-05 19:03:55 +00:00
}
2025-08-27 14:40:51 +00:00
void CHyprlock : : removeDmabufListener ( ) {
if ( dma . linuxDmabufFeedback ) {
dma . linuxDmabufFeedback - > sendDestroy ( ) ;
dma . linuxDmabufFeedback . reset ( ) ;
}
if ( dma . linuxDmabuf ) {
dma . linuxDmabuf - > sendDestroy ( ) ;
dma . linuxDmabuf . reset ( ) ;
}
}
2024-02-18 23:08:03 +00:00
void CHyprlock : : run ( ) {
2024-12-29 18:36:08 +00:00
m_sWaylandState . registry = makeShared < CCWlRegistry > ( ( wl_proxy * ) wl_display_get_registry ( m_sWaylandState . display ) ) ;
m_sWaylandState . registry - > setGlobal ( [ this ] ( CCWlRegistry * r , uint32_t name , const char * interface , uint32_t version ) {
const std : : string IFACE = interface ;
Debug : : log ( LOG , " | got iface: {} v{} " , IFACE , version ) ;
if ( IFACE = = zwp_linux_dmabuf_v1_interface . name ) {
if ( version < 4 ) {
Debug : : log ( ERR , " cannot use linux_dmabuf with ver < 4 " ) ;
return ;
}
dma . linuxDmabuf = makeShared < CCZwpLinuxDmabufV1 > ( ( wl_proxy * ) wl_registry_bind ( ( wl_registry * ) r - > resource ( ) , name , & zwp_linux_dmabuf_v1_interface , 4 ) ) ;
dma . linuxDmabufFeedback = makeShared < CCZwpLinuxDmabufFeedbackV1 > ( dma . linuxDmabuf - > sendGetDefaultFeedback ( ) ) ;
2024-02-18 23:08:03 +00:00
2024-12-29 18:36:08 +00:00
addDmabufListener ( ) ;
} else if ( IFACE = = wl_seat_interface . name ) {
if ( g_pSeatManager - > registered ( ) ) {
Debug : : log ( WARN , " Hyprlock does not support multi-seat configurations. Only binding to the first seat. " ) ;
return ;
}
2025-01-04 17:32:44 +01:00
g_pSeatManager - > registerSeat ( makeShared < CCWlSeat > ( ( wl_proxy * ) wl_registry_bind ( ( wl_registry * ) r - > resource ( ) , name , & wl_seat_interface , 8 ) ) ) ;
2024-12-29 18:36:08 +00:00
} else if ( IFACE = = ext_session_lock_manager_v1_interface . name )
m_sWaylandState . sessionLock =
makeShared < CCExtSessionLockManagerV1 > ( ( wl_proxy * ) wl_registry_bind ( ( wl_registry * ) r - > resource ( ) , name , & ext_session_lock_manager_v1_interface , 1 ) ) ;
2025-03-05 08:35:43 +01:00
else if ( IFACE = = wl_output_interface . name ) {
2025-03-08 09:58:29 +00:00
const auto POUTPUT = makeShared < COutput > ( ) ;
POUTPUT - > create ( POUTPUT , makeShared < CCWlOutput > ( ( wl_proxy * ) wl_registry_bind ( ( wl_registry * ) r - > resource ( ) , name , & wl_output_interface , 4 ) ) , name ) ;
m_vOutputs . emplace_back ( POUTPUT ) ;
2025-03-05 08:35:43 +01:00
} else if ( IFACE = = wp_cursor_shape_manager_v1_interface . name )
2024-12-29 18:36:08 +00:00
g_pSeatManager - > registerCursorShape (
makeShared < CCWpCursorShapeManagerV1 > ( ( wl_proxy * ) wl_registry_bind ( ( wl_registry * ) r - > resource ( ) , name , & wp_cursor_shape_manager_v1_interface , 1 ) ) ) ;
else if ( IFACE = = wl_compositor_interface . name )
m_sWaylandState . compositor = makeShared < CCWlCompositor > ( ( wl_proxy * ) wl_registry_bind ( ( wl_registry * ) r - > resource ( ) , name , & wl_compositor_interface , 4 ) ) ;
else if ( IFACE = = wp_fractional_scale_manager_v1_interface . name )
m_sWaylandState . fractional =
makeShared < CCWpFractionalScaleManagerV1 > ( ( wl_proxy * ) wl_registry_bind ( ( wl_registry * ) r - > resource ( ) , name , & wp_fractional_scale_manager_v1_interface , 1 ) ) ;
else if ( IFACE = = wp_viewporter_interface . name )
m_sWaylandState . viewporter = makeShared < CCWpViewporter > ( ( wl_proxy * ) wl_registry_bind ( ( wl_registry * ) r - > resource ( ) , name , & wp_viewporter_interface , 1 ) ) ;
else if ( IFACE = = zwlr_screencopy_manager_v1_interface . name )
m_sWaylandState . screencopy =
makeShared < CCZwlrScreencopyManagerV1 > ( ( wl_proxy * ) wl_registry_bind ( ( wl_registry * ) r - > resource ( ) , name , & zwlr_screencopy_manager_v1_interface , 3 ) ) ;
2025-01-24 13:25:37 +00:00
else if ( IFACE = = wl_shm_interface . name )
m_sWaylandState . shm = makeShared < CCWlShm > ( ( wl_proxy * ) wl_registry_bind ( ( wl_registry * ) r - > resource ( ) , name , & wl_shm_interface , 1 ) ) ;
2024-12-29 18:36:08 +00:00
else
return ;
Debug : : log ( LOG , " > Bound to {} v{} " , IFACE , version ) ;
} ) ;
m_sWaylandState . registry - > setGlobalRemove ( [ this ] ( CCWlRegistry * r , uint32_t name ) {
Debug : : log ( LOG , " | removed iface {} " , name ) ;
2025-03-05 08:35:43 +01:00
auto outputIt = std : : ranges : : find_if ( m_vOutputs , [ id = name ] ( const auto & other ) { return other - > m_ID = = id ; } ) ;
2024-12-29 18:36:08 +00:00
if ( outputIt ! = m_vOutputs . end ( ) ) {
2025-03-05 08:35:43 +01:00
g_pRenderer - > removeWidgetsFor ( ( * outputIt ) - > m_ID ) ;
2024-12-29 18:36:08 +00:00
m_vOutputs . erase ( outputIt ) ;
}
} ) ;
2024-02-18 23:08:03 +00:00
wl_display_roundtrip ( m_sWaylandState . display ) ;
if ( ! m_sWaylandState . sessionLock ) {
Debug : : log ( CRIT , " Couldn't bind to ext-session-lock-v1, does your compositor support it? " ) ;
exit ( 1 ) ;
}
// gather info about monitors
wl_display_roundtrip ( m_sWaylandState . display ) ;
2025-09-03 09:32:12 +00:00
g_pRenderer = makeUnique < CRenderer > ( ) ;
g_pAsyncResourceGatherer = makeUnique < CAsyncResourceGatherer > ( ) ;
g_pAuth = makeUnique < CAuth > ( ) ;
2024-12-16 18:58:36 +00:00
g_pAuth - > start ( ) ;
2024-02-21 21:38:37 +00:00
2024-08-05 20:22:01 +02:00
Debug : : log ( LOG , " Running on {} " , m_sCurrentDesktop ) ;
2024-03-03 02:19:25 +00:00
2025-06-22 09:24:39 +02:00
if ( ! g_pHyprlock - > m_bImmediateRender ) {
// Gather background resources and screencopy frames before locking the screen.
// We need to do this because as soon as we lock the screen, workspaces frames can no longer be captured. It either won't work at all, or we will capture hyprlock itself.
// Bypass with --immediate-render (can cause the background first rendering a solid color and missing or inaccurate screencopy frames)
const auto MAXDELAYMS = 2000 ; // 2 Seconds
const auto STARTGATHERTP = std : : chrono : : system_clock : : now ( ) ;
int fdcount = 1 ;
pollfd pollfds [ 2 ] ;
pollfds [ 0 ] = {
. fd = wl_display_get_fd ( m_sWaylandState . display ) ,
. events = POLLIN ,
} ;
2025-09-03 09:32:12 +00:00
if ( g_pAsyncResourceGatherer - > gatheredEventfd . isValid ( ) ) {
2025-06-22 09:24:39 +02:00
pollfds [ 1 ] = {
2025-09-03 09:32:12 +00:00
. fd = g_pAsyncResourceGatherer - > gatheredEventfd . get ( ) ,
2025-06-22 09:24:39 +02:00
. events = POLLIN ,
} ;
fdcount + + ;
}
2025-09-03 09:32:12 +00:00
while ( ! g_pAsyncResourceGatherer - > gathered ) {
2024-03-03 02:19:25 +00:00
wl_display_flush ( m_sWaylandState . display ) ;
if ( wl_display_prepare_read ( m_sWaylandState . display ) = = 0 ) {
2025-06-22 09:24:39 +02:00
if ( poll ( pollfds , fdcount , /* 100ms timeout */ 100 ) < 0 ) {
RASSERT ( errno = = EINTR , " [core] Polling fds failed with {} " , errno ) ;
wl_display_cancel_read ( m_sWaylandState . display ) ;
continue ;
}
2024-03-03 02:19:25 +00:00
wl_display_read_events ( m_sWaylandState . display ) ;
wl_display_dispatch_pending ( m_sWaylandState . display ) ;
} else {
2025-06-22 09:24:39 +02:00
std : : this_thread : : sleep_for ( std : : chrono : : milliseconds ( 1 ) ) ;
2024-03-03 02:19:25 +00:00
wl_display_dispatch ( m_sWaylandState . display ) ;
}
2025-06-22 09:24:39 +02:00
if ( std : : chrono : : duration_cast < std : : chrono : : milliseconds > ( std : : chrono : : system_clock : : now ( ) - STARTGATHERTP ) . count ( ) > MAXDELAYMS ) {
Debug : : log ( WARN , " Gathering resources timed out after {} milliseconds. Backgrounds may be delayed and render `background:color` at first. " , MAXDELAYMS ) ;
break ;
}
2024-03-03 02:19:25 +00:00
}
2025-06-22 09:24:39 +02:00
Debug : : log ( LOG , " Resources gathered after {} milliseconds " ,
std : : chrono : : duration_cast < std : : chrono : : milliseconds > ( std : : chrono : : system_clock : : now ( ) - STARTGATHERTP ) . count ( ) ) ;
2024-03-03 02:19:25 +00:00
}
2025-02-16 06:29:52 +00:00
// Failed to lock the session
if ( ! acquireSessionLock ( ) ) {
2024-08-21 18:25:14 +08:00
m_sLoopState . timerEvent = true ;
m_sLoopState . timerCV . notify_all ( ) ;
2024-12-18 14:52:35 +00:00
g_pAuth - > terminate ( ) ;
2024-07-14 16:59:06 +02:00
exit ( 1 ) ;
2024-08-21 18:25:14 +08:00
}
2024-07-14 16:59:06 +02:00
2024-12-16 18:58:36 +00:00
const auto fingerprintAuth = g_pAuth - > getImpl ( AUTH_IMPL_FINGERPRINT ) ;
const auto dbusConn = ( fingerprintAuth ) ? ( ( CFingerprint * ) fingerprintAuth . get ( ) ) - > getConnection ( ) : nullptr ;
2024-10-21 17:08:24 -07:00
2024-03-08 23:54:34 +01:00
registerSignalAction ( SIGUSR1 , handleUnlockSignal , SA_RESTART ) ;
2024-03-11 00:38:01 +03:00
registerSignalAction ( SIGUSR2 , handleForceUpdateSignal ) ;
registerSignalAction ( SIGRTMIN , handlePollTerminate ) ;
2024-02-26 01:08:12 +11:00
2024-10-21 17:08:24 -07:00
pollfd pollfds [ 2 ] ;
pollfds [ 0 ] = {
. fd = wl_display_get_fd ( m_sWaylandState . display ) ,
. events = POLLIN ,
2024-02-20 00:11:19 +00:00
} ;
2024-12-16 18:58:36 +00:00
if ( dbusConn ) {
2024-10-21 17:08:24 -07:00
pollfds [ 1 ] = {
2024-12-16 18:58:36 +00:00
. fd = dbusConn - > getEventLoopPollData ( ) . fd ,
2024-10-21 17:08:24 -07:00
. events = POLLIN ,
} ;
}
2024-12-16 18:58:36 +00:00
size_t fdcount = dbusConn ? 2 : 1 ;
2024-02-20 00:11:19 +00:00
2024-10-21 17:08:24 -07:00
std : : thread pollThr ( [ this , & pollfds , fdcount ] ( ) {
2024-03-02 15:21:41 +01:00
while ( ! m_bTerminate ) {
2025-01-21 13:42:11 +00:00
bool preparedToRead = wl_display_prepare_read ( m_sWaylandState . display ) = = 0 ;
2024-02-20 01:30:47 +00:00
2025-01-21 13:42:11 +00:00
int events = 0 ;
if ( preparedToRead ) {
events = poll ( pollfds , fdcount , 5000 ) ;
2024-03-09 23:46:22 +07:00
2025-01-21 13:42:11 +00:00
if ( events < 0 ) {
2025-03-30 01:33:34 +01:00
RASSERT ( errno = = EINTR , " [core] Polling fds failed with {} " , errno ) ;
2025-04-30 08:11:57 +02:00
wl_display_cancel_read ( m_sWaylandState . display ) ;
continue ;
2024-02-20 00:11:19 +00:00
}
2025-01-21 13:42:11 +00:00
for ( size_t i = 0 ; i < fdcount ; + + i ) {
2025-03-30 01:33:34 +01:00
RASSERT ( ! ( pollfds [ i ] . revents & POLLHUP ) , " [core] Disconnected from pollfd id {} " , i ) ;
2025-01-21 13:42:11 +00:00
}
wl_display_read_events ( m_sWaylandState . display ) ;
m_sLoopState . wlDispatched = false ;
2024-02-20 00:11:19 +00:00
}
2025-01-21 13:42:11 +00:00
if ( events > 0 | | ! preparedToRead ) {
2024-02-20 00:11:19 +00:00
Debug : : log ( TRACE , " [core] got poll event " ) ;
2025-01-21 13:42:11 +00:00
std : : unique_lock lk ( m_sLoopState . eventLoopMutex ) ;
2024-02-20 00:11:19 +00:00
m_sLoopState . event = true ;
m_sLoopState . loopCV . notify_all ( ) ;
2025-01-21 13:42:11 +00:00
m_sLoopState . wlDispatchCV . wait_for ( lk , std : : chrono : : milliseconds ( 100 ) , [ this ] { return m_sLoopState . wlDispatched ; } ) ;
2024-02-20 00:11:19 +00:00
}
}
} ) ;
std : : thread timersThr ( [ this ] ( ) {
2024-03-02 15:21:41 +01:00
while ( ! m_bTerminate ) {
2024-02-20 00:11:19 +00:00
// calc nearest thing
m_sLoopState . timersMutex . lock ( ) ;
float least = 10000 ;
for ( auto & t : m_vTimers ) {
2024-02-20 03:18:17 +00:00
const auto TIME = std : : clamp ( t - > leftMs ( ) , 1.f , INFINITY ) ;
2025-02-16 06:29:52 +00:00
least = std : : min ( TIME , least ) ;
2024-02-20 00:11:19 +00:00
}
m_sLoopState . timersMutex . unlock ( ) ;
std : : unique_lock lk ( m_sLoopState . timerRequestMutex ) ;
2024-02-20 00:31:11 +00:00
m_sLoopState . timerCV . wait_for ( lk , std : : chrono : : milliseconds ( ( int ) least + 1 ) , [ this ] { return m_sLoopState . timerEvent ; } ) ;
m_sLoopState . timerEvent = false ;
2024-02-20 00:11:19 +00:00
// notify main
std : : lock_guard < std : : mutex > lg2 ( m_sLoopState . eventLoopMutex ) ;
Debug : : log ( TRACE , " timer thread firing " ) ;
m_sLoopState . event = true ;
m_sLoopState . loopCV . notify_all ( ) ;
}
} ) ;
m_sLoopState . event = true ; // let it process once
2025-01-06 12:34:21 +00:00
g_pRenderer - > startFadeIn ( ) ;
2024-02-20 00:11:19 +00:00
2024-04-09 12:14:04 +02:00
while ( ! m_bTerminate ) {
2024-02-20 00:11:19 +00:00
std : : unique_lock lk ( m_sLoopState . eventRequestMutex ) ;
2025-02-06 16:36:08 +05:00
if ( ! m_sLoopState . event )
2024-02-20 03:07:34 +00:00
m_sLoopState . loopCV . wait_for ( lk , std : : chrono : : milliseconds ( 5000 ) , [ this ] { return m_sLoopState . event ; } ) ;
2024-02-20 00:11:19 +00:00
2024-04-09 12:14:04 +02:00
if ( m_bTerminate )
break ;
2024-02-20 00:11:19 +00:00
std : : lock_guard < std : : mutex > lg ( m_sLoopState . eventLoopMutex ) ;
m_sLoopState . event = false ;
2025-01-21 13:42:11 +00:00
wl_display_dispatch_pending ( m_sWaylandState . display ) ;
wl_display_flush ( m_sWaylandState . display ) ;
m_sLoopState . wlDispatched = true ;
m_sLoopState . wlDispatchCV . notify_all ( ) ;
2024-10-21 17:08:24 -07:00
if ( pollfds [ 1 ] . revents & POLLIN /* dbus */ ) {
2024-12-16 18:58:36 +00:00
while ( dbusConn & & dbusConn - > processPendingEvent ( ) ) {
2024-10-21 17:08:24 -07:00
;
}
}
2024-02-26 18:25:52 +00:00
// do timers
2024-02-20 00:11:19 +00:00
m_sLoopState . timersMutex . lock ( ) ;
auto timerscpy = m_vTimers ;
m_sLoopState . timersMutex . unlock ( ) ;
2025-06-28 11:01:28 +02:00
std : : vector < ASP < CTimer > > passed ;
2024-02-20 00:11:19 +00:00
for ( auto & t : timerscpy ) {
if ( t - > passed ( ) & & ! t - > cancelled ( ) ) {
t - > call ( t ) ;
passed . push_back ( t ) ;
}
if ( t - > cancelled ( ) )
passed . push_back ( t ) ;
}
m_sLoopState . timersMutex . lock ( ) ;
std : : erase_if ( m_vTimers , [ passed ] ( const auto & timer ) { return std : : find ( passed . begin ( ) , passed . end ( ) , timer ) ! = passed . end ( ) ; } ) ;
m_sLoopState . timersMutex . unlock ( ) ;
passed . clear ( ) ;
2024-02-18 23:08:03 +00:00
}
2024-12-29 18:36:08 +00:00
const auto DPY = m_sWaylandState . display ;
2024-02-20 03:18:17 +00:00
m_sLoopState . timerEvent = true ;
2024-02-20 00:31:11 +00:00
m_sLoopState . timerCV . notify_all ( ) ;
2024-12-29 18:36:08 +00:00
m_sWaylandState = { } ;
dma = { } ;
2024-02-20 01:30:47 +00:00
2024-02-20 01:38:02 +00:00
m_vOutputs . clear ( ) ;
2024-12-29 18:36:08 +00:00
g_pSeatManager . reset ( ) ;
2025-09-03 09:32:12 +00:00
g_pAsyncResourceGatherer . reset ( ) ;
g_pRenderer . reset ( ) ;
g_pEGL . reset ( ) ;
2024-02-20 01:38:02 +00:00
2024-12-29 18:36:08 +00:00
wl_display_disconnect ( DPY ) ;
2024-02-20 00:31:11 +00:00
2024-03-11 00:38:01 +03:00
pthread_kill ( pollThr . native_handle ( ) , SIGRTMIN ) ;
2024-03-08 23:54:34 +01:00
2024-04-10 23:41:31 +02:00
g_pAuth - > terminate ( ) ;
2024-02-20 03:05:51 +00:00
// wait for threads to exit cleanly to avoid a coredump
pollThr . join ( ) ;
timersThr . join ( ) ;
2024-02-18 23:08:03 +00:00
Debug : : log ( LOG , " Reached the end, exiting " ) ;
}
2024-03-15 19:49:07 +01:00
void CHyprlock : : unlock ( ) {
2025-01-25 20:43:21 +00:00
if ( ! m_bLocked ) {
Debug : : log ( WARN , " Unlock called, but not locked yet. This can happen when dpms is off during the grace period. " ) ;
return ;
}
2025-06-22 09:24:39 +02:00
g_pRenderer - > startFadeOut ( true ) ;
2024-03-15 19:49:07 +01:00
2024-07-02 00:45:06 +02:00
renderAllOutputs ( ) ;
2024-03-15 19:49:07 +01:00
}
2024-07-17 15:22:42 +02:00
bool CHyprlock : : isUnlocked ( ) {
2025-06-22 09:24:39 +02:00
return ! m_bLocked ;
2024-07-17 15:22:42 +02:00
}
2024-04-10 23:41:31 +02:00
void CHyprlock : : clearPasswordBuffer ( ) {
if ( m_sPasswordState . passBuffer . empty ( ) )
return ;
2024-02-20 00:53:49 +00:00
2024-04-10 23:41:31 +02:00
m_sPasswordState . passBuffer = " " ;
2024-07-02 00:45:06 +02:00
renderAllOutputs ( ) ;
2024-02-20 00:53:49 +00:00
}
2024-03-19 03:49:12 +01:00
void CHyprlock : : renderOutput ( const std : : string & stringPort ) {
2025-02-06 16:36:08 +05:00
const auto MON = std : : ranges : : find_if ( m_vOutputs , [ stringPort ] ( const auto & other ) { return other - > stringPort = = stringPort ; } ) ;
2024-03-19 03:49:12 +01:00
2025-03-05 08:35:43 +01:00
if ( MON = = m_vOutputs . end ( ) | | ! * MON )
2024-03-19 03:49:12 +01:00
return ;
2025-03-05 08:35:43 +01:00
const auto & PMONITOR = * MON ;
2024-03-19 03:49:12 +01:00
2025-03-05 08:35:43 +01:00
if ( ! PMONITOR - > m_sessionLockSurface )
2024-07-02 00:45:06 +02:00
return ;
2025-03-05 08:35:43 +01:00
PMONITOR - > m_sessionLockSurface - > render ( ) ;
2024-03-19 03:49:12 +01:00
}
2024-07-02 00:45:06 +02:00
void CHyprlock : : renderAllOutputs ( ) {
for ( auto & o : m_vOutputs ) {
2025-03-05 08:35:43 +01:00
if ( ! o - > m_sessionLockSurface )
2024-07-02 00:45:06 +02:00
continue ;
2025-03-05 08:35:43 +01:00
o - > m_sessionLockSurface - > render ( ) ;
2024-07-02 00:45:06 +02:00
}
}
2024-05-14 17:11:45 +02:00
void CHyprlock : : startKeyRepeat ( xkb_keysym_t sym ) {
if ( m_pKeyRepeatTimer ) {
m_pKeyRepeatTimer - > cancel ( ) ;
m_pKeyRepeatTimer . reset ( ) ;
}
2024-12-29 18:36:08 +00:00
if ( g_pSeatManager - > m_pXKBComposeState )
xkb_compose_state_reset ( g_pSeatManager - > m_pXKBComposeState ) ;
2024-11-11 16:49:51 +01:00
2024-05-14 17:11:45 +02:00
if ( m_iKeebRepeatDelay < = 0 )
return ;
2025-06-28 11:01:28 +02:00
m_pKeyRepeatTimer = addTimer ( std : : chrono : : milliseconds ( m_iKeebRepeatDelay ) , [ sym ] ( ASP < CTimer > self , void * data ) { g_pHyprlock - > repeatKey ( sym ) ; } , nullptr ) ;
2024-05-14 17:11:45 +02:00
}
void CHyprlock : : repeatKey ( xkb_keysym_t sym ) {
if ( m_iKeebRepeatRate < = 0 )
return ;
2024-11-11 16:49:51 +01:00
handleKeySym ( sym , false ) ;
2024-05-14 17:11:45 +02:00
// This condition is for backspace and delete keys, but should also be ok for other keysyms since our buffer won't be empty anyways
if ( bool CONTINUE = m_sPasswordState . passBuffer . length ( ) > 0 ; CONTINUE )
2025-06-28 11:01:28 +02:00
m_pKeyRepeatTimer = addTimer ( std : : chrono : : milliseconds ( m_iKeebRepeatRate ) , [ sym ] ( ASP < CTimer > self , void * data ) { g_pHyprlock - > repeatKey ( sym ) ; } , nullptr ) ;
2024-05-14 17:11:45 +02:00
2024-07-02 00:45:06 +02:00
renderAllOutputs ( ) ;
2024-05-14 17:11:45 +02:00
}
2024-02-26 02:28:33 +00:00
void CHyprlock : : onKey ( uint32_t key , bool down ) {
2025-01-06 12:34:21 +00:00
if ( isUnlocked ( ) )
2024-03-15 19:49:07 +01:00
return ;
2024-02-18 23:08:03 +00:00
2024-03-15 19:49:07 +01:00
if ( down & & std : : chrono : : system_clock : : now ( ) < m_tGraceEnds ) {
unlock ( ) ;
2024-03-01 13:53:05 +00:00
return ;
}
2025-02-06 16:36:08 +05:00
if ( down & & std : : ranges : : find ( m_vPressedKeys , key ) ! = m_vPressedKeys . end ( ) ) {
2024-02-26 02:28:33 +00:00
Debug : : log ( ERR , " Invalid key down event (key already pressed?) " ) ;
return ;
2025-02-06 16:36:08 +05:00
} else if ( ! down & & std : : ranges : : find ( m_vPressedKeys , key ) = = m_vPressedKeys . end ( ) ) {
2024-02-26 02:28:33 +00:00
Debug : : log ( ERR , " Invalid key down event (stray release event?) " ) ;
return ;
}
if ( down )
2024-02-26 16:18:52 -05:00
m_vPressedKeys . push_back ( key ) ;
2024-05-14 17:11:45 +02:00
else {
2024-02-26 16:18:52 -05:00
std : : erase ( m_vPressedKeys , key ) ;
2024-05-14 17:11:45 +02:00
if ( m_pKeyRepeatTimer ) {
m_pKeyRepeatTimer - > cancel ( ) ;
m_pKeyRepeatTimer . reset ( ) ;
}
}
2024-02-26 02:28:33 +00:00
2024-04-10 23:41:31 +02:00
if ( g_pAuth - > checkWaiting ( ) ) {
2024-07-02 00:45:06 +02:00
renderAllOutputs ( ) ;
2024-02-21 23:05:36 +00:00
return ;
}
2025-04-02 22:13:22 +02:00
if ( g_pAuth - > m_bDisplayFailText )
g_pAuth - > resetDisplayFail ( ) ;
2024-03-17 03:32:43 +03:00
if ( down ) {
2024-12-29 18:36:08 +00:00
m_bCapsLock = xkb_state_mod_name_is_active ( g_pSeatManager - > m_pXKBState , XKB_MOD_NAME_CAPS , XKB_STATE_MODS_LOCKED ) ;
m_bNumLock = xkb_state_mod_name_is_active ( g_pSeatManager - > m_pXKBState , XKB_MOD_NAME_NUM , XKB_STATE_MODS_LOCKED ) ;
m_bCtrl = xkb_state_mod_name_is_active ( g_pSeatManager - > m_pXKBState , XKB_MOD_NAME_CTRL , XKB_STATE_MODS_EFFECTIVE ) ;
2024-02-21 11:01:52 +00:00
2024-12-29 18:36:08 +00:00
const auto SYM = xkb_state_key_get_one_sym ( g_pSeatManager - > m_pXKBState , key + 8 ) ;
2024-11-11 16:49:51 +01:00
enum xkb_compose_status composeStatus = XKB_COMPOSE_NOTHING ;
2024-12-29 18:36:08 +00:00
if ( g_pSeatManager - > m_pXKBComposeState ) {
xkb_compose_state_feed ( g_pSeatManager - > m_pXKBComposeState , SYM ) ;
composeStatus = xkb_compose_state_get_status ( g_pSeatManager - > m_pXKBComposeState ) ;
2024-11-11 16:49:51 +01:00
}
handleKeySym ( SYM , composeStatus = = XKB_COMPOSE_COMPOSED ) ;
2024-05-14 17:11:45 +02:00
if ( SYM = = XKB_KEY_BackSpace | | SYM = = XKB_KEY_Delete ) // keys allowed to repeat
startKeyRepeat ( SYM ) ;
2024-11-11 16:49:51 +01:00
2024-12-29 18:36:08 +00:00
} else if ( g_pSeatManager - > m_pXKBComposeState & & xkb_compose_state_get_status ( g_pSeatManager - > m_pXKBComposeState ) = = XKB_COMPOSE_COMPOSED )
xkb_compose_state_reset ( g_pSeatManager - > m_pXKBComposeState ) ;
2024-03-24 20:43:32 +00:00
2024-07-02 00:45:06 +02:00
renderAllOutputs ( ) ;
2024-05-14 17:11:45 +02:00
}
2024-03-23 17:02:03 +02:00
2024-11-11 16:49:51 +01:00
void CHyprlock : : handleKeySym ( xkb_keysym_t sym , bool composed ) {
2024-05-14 17:11:45 +02:00
const auto SYM = sym ;
2024-11-11 16:49:51 +01:00
2025-07-29 15:07:45 +02:00
if ( SYM = = XKB_KEY_Escape | | ( m_bCtrl & & ( SYM = = XKB_KEY_u | | SYM = = XKB_KEY_BackSpace | | SYM = = XKB_KEY_a ) ) ) {
2024-05-14 17:11:45 +02:00
Debug : : log ( LOG , " Clearing password buffer " ) ;
2024-03-23 17:02:03 +02:00
2024-05-14 17:11:45 +02:00
m_sPasswordState . passBuffer = " " ;
} else if ( SYM = = XKB_KEY_Return | | SYM = = XKB_KEY_KP_Enter ) {
Debug : : log ( LOG , " Authenticating " ) ;
2024-03-23 17:02:03 +02:00
2025-01-29 22:10:27 +00:00
static const auto IGNOREEMPTY = g_pConfigManager - > getValue < Hyprlang : : INT > ( " general:ignore_empty_input " ) ;
2024-05-14 17:11:45 +02:00
2025-01-29 22:10:27 +00:00
if ( m_sPasswordState . passBuffer . empty ( ) & & * IGNOREEMPTY ) {
2024-05-14 17:11:45 +02:00
Debug : : log ( LOG , " Ignoring empty input " ) ;
return ;
2024-03-17 03:32:43 +03:00
}
2024-02-18 23:08:03 +00:00
2024-05-14 17:11:45 +02:00
g_pAuth - > submitInput ( m_sPasswordState . passBuffer ) ;
} else if ( SYM = = XKB_KEY_BackSpace | | SYM = = XKB_KEY_Delete ) {
if ( m_sPasswordState . passBuffer . length ( ) > 0 ) {
// handle utf-8
while ( ( m_sPasswordState . passBuffer . back ( ) & 0xc0 ) = = 0x80 )
m_sPasswordState . passBuffer . pop_back ( ) ;
m_sPasswordState . passBuffer = m_sPasswordState . passBuffer . substr ( 0 , m_sPasswordState . passBuffer . length ( ) - 1 ) ;
}
} else if ( SYM = = XKB_KEY_Caps_Lock ) {
m_bCapsLock = ! m_bCapsLock ;
} else if ( SYM = = XKB_KEY_Num_Lock ) {
m_bNumLock = ! m_bNumLock ;
} else {
char buf [ 16 ] = { 0 } ;
2024-12-29 18:36:08 +00:00
int len = ( composed ) ? xkb_compose_state_get_utf8 ( g_pSeatManager - > m_pXKBComposeState , buf , sizeof ( buf ) ) /* nullbyte */ + 1 :
2024-11-11 16:49:51 +01:00
xkb_keysym_to_utf8 ( SYM , buf , sizeof ( buf ) ) /* already includes a nullbyte */ ;
2024-05-14 17:11:45 +02:00
if ( len > 1 )
m_sPasswordState . passBuffer + = std : : string { buf , len - 1 } ;
2024-02-18 23:08:03 +00:00
}
}
2025-05-05 17:11:24 +02:00
void CHyprlock : : onClick ( uint32_t button , bool down , const Vector2D & pos ) {
2025-07-20 09:46:49 +02:00
if ( ! down )
return ;
2025-05-05 17:11:24 +02:00
if ( ! m_focusedOutput . lock ( ) )
return ;
// TODO: add the UNLIKELY marco from Hyprland
if ( ! m_focusedOutput - > m_sessionLockSurface )
return ;
const auto SCALEDPOS = pos * m_focusedOutput - > m_sessionLockSurface - > fractionalScale ;
const auto widgets = g_pRenderer - > getOrCreateWidgetsFor ( * m_focusedOutput - > m_sessionLockSurface ) ;
for ( const auto & widget : widgets ) {
if ( widget - > containsPoint ( SCALEDPOS ) )
widget - > onClick ( button , down , pos ) ;
}
}
void CHyprlock : : onHover ( const Vector2D & pos ) {
if ( ! m_focusedOutput . lock ( ) )
return ;
if ( ! m_focusedOutput - > m_sessionLockSurface )
return ;
bool outputNeedsRedraw = false ;
bool cursorChanged = false ;
const auto SCALEDPOS = pos * m_focusedOutput - > m_sessionLockSurface - > fractionalScale ;
const auto widgets = g_pRenderer - > getOrCreateWidgetsFor ( * m_focusedOutput - > m_sessionLockSurface ) ;
for ( const auto & widget : widgets ) {
const bool CONTAINSPOINT = widget - > containsPoint ( SCALEDPOS ) ;
const bool HOVERED = widget - > isHovered ( ) ;
if ( CONTAINSPOINT ) {
if ( ! HOVERED ) {
widget - > setHover ( true ) ;
widget - > onHover ( pos ) ;
outputNeedsRedraw = true ;
}
if ( ! cursorChanged )
cursorChanged = true ;
} else if ( HOVERED ) {
widget - > setHover ( false ) ;
outputNeedsRedraw = true ;
}
}
if ( ! cursorChanged )
g_pSeatManager - > m_pCursorShape - > setShape ( WP_CURSOR_SHAPE_DEVICE_V1_SHAPE_DEFAULT ) ;
if ( outputNeedsRedraw )
m_focusedOutput - > m_sessionLockSurface - > render ( ) ;
}
2025-02-16 06:29:52 +00:00
bool CHyprlock : : acquireSessionLock ( ) {
2024-02-18 23:08:03 +00:00
Debug : : log ( LOG , " Locking session " ) ;
2024-12-29 18:36:08 +00:00
m_sLockState . lock = makeShared < CCExtSessionLockV1 > ( m_sWaylandState . sessionLock - > sendLock ( ) ) ;
2025-02-16 06:29:52 +00:00
if ( ! m_sLockState . lock ) {
Debug : : log ( ERR , " Failed to create a lock object! " ) ;
return false ;
}
2024-12-29 18:36:08 +00:00
m_sLockState . lock - > setLocked ( [ this ] ( CCExtSessionLockV1 * r ) { onLockLocked ( ) ; } ) ;
m_sLockState . lock - > setFinished ( [ this ] ( CCExtSessionLockV1 * r ) { onLockFinished ( ) ; } ) ;
2024-06-25 13:46:58 +02:00
2024-07-14 16:59:06 +02:00
// roundtrip in case the compositor sends `finished` right away
2024-06-25 13:46:58 +02:00
wl_display_roundtrip ( m_sWaylandState . display ) ;
2025-02-16 06:29:52 +00:00
// recieved finished right away (probably already locked)
if ( m_bTerminate )
return false ;
m_lockAquired = true ;
// create a session lock surface for exiting outputs
for ( auto & o : m_vOutputs ) {
if ( ! o - > done )
continue ;
2025-03-05 08:35:43 +01:00
o - > createSessionLockSurface ( ) ;
2025-02-16 06:29:52 +00:00
}
return true ;
2024-02-18 23:08:03 +00:00
}
2024-03-15 19:49:07 +01:00
void CHyprlock : : releaseSessionLock ( ) {
2024-02-18 23:08:03 +00:00
Debug : : log ( LOG , " Unlocking session " ) ;
2025-01-06 12:34:21 +00:00
2024-07-19 17:26:38 +02:00
if ( m_bTerminate ) {
2024-03-02 15:21:41 +01:00
Debug : : log ( ERR , " Unlock already happend? " ) ;
return ;
}
2024-07-19 17:26:38 +02:00
if ( ! m_sLockState . lock ) {
Debug : : log ( ERR , " Unlock without a lock object! " ) ;
return ;
}
2024-07-14 16:59:06 +02:00
if ( ! m_bLocked ) {
// Would be a protocol error to allow this
Debug : : log ( ERR , " Trying to unlock the session, but never recieved the locked event! " ) ;
return ;
}
2024-12-29 18:36:08 +00:00
m_sLockState . lock - > sendUnlockAndDestroy ( ) ;
2024-02-18 23:08:03 +00:00
m_sLockState . lock = nullptr ;
Debug : : log ( LOG , " Unlocked, exiting! " ) ;
m_bTerminate = true ;
2024-02-26 17:58:50 +00:00
m_bLocked = false ;
2024-02-20 03:31:10 +00:00
2024-03-01 23:45:38 +01:00
wl_display_roundtrip ( m_sWaylandState . display ) ;
2024-02-18 23:08:03 +00:00
}
2024-07-14 16:59:06 +02:00
void CHyprlock : : onLockLocked ( ) {
Debug : : log ( LOG , " onLockLocked called " ) ;
2024-02-26 17:58:50 +00:00
m_bLocked = true ;
2024-02-18 23:08:03 +00:00
}
void CHyprlock : : onLockFinished ( ) {
Debug : : log ( LOG , " onLockFinished called. Seems we got yeeten. Is another lockscreen running? " ) ;
2024-07-19 17:26:38 +02:00
if ( ! m_sLockState . lock ) {
Debug : : log ( ERR , " onLockFinished without a lock object! " ) ;
return ;
}
2024-07-11 16:15:32 +02:00
if ( m_bLocked )
// The `finished` event specifies that whenever the `locked` event has been recieved and the compositor sends `finished`,
// `unlock_and_destroy` should be called by the client.
2024-12-29 18:36:08 +00:00
// This does not mean the session gets unlocked! That is ultimately the responsiblity of the compositor.
m_sLockState . lock - > sendUnlockAndDestroy ( ) ;
2024-07-11 16:15:32 +02:00
else
2024-12-29 18:36:08 +00:00
m_sLockState . lock . reset ( ) ;
2024-07-11 16:15:32 +02:00
2024-07-17 15:22:42 +02:00
m_sLockState . lock = nullptr ;
m_bTerminate = true ;
2024-02-18 23:08:03 +00:00
}
2024-12-29 18:36:08 +00:00
SP < CCExtSessionLockManagerV1 > CHyprlock : : getSessionLockMgr ( ) {
2024-02-18 23:08:03 +00:00
return m_sWaylandState . sessionLock ;
}
2024-12-29 18:36:08 +00:00
SP < CCExtSessionLockV1 > CHyprlock : : getSessionLock ( ) {
2024-02-18 23:08:03 +00:00
return m_sLockState . lock ;
}
2024-12-29 18:36:08 +00:00
SP < CCWlCompositor > CHyprlock : : getCompositor ( ) {
2024-02-18 23:08:03 +00:00
return m_sWaylandState . compositor ;
}
wl_display * CHyprlock : : getDisplay ( ) {
return m_sWaylandState . display ;
}
2024-12-29 18:36:08 +00:00
SP < CCWpFractionalScaleManagerV1 > CHyprlock : : getFractionalMgr ( ) {
2024-02-18 23:08:03 +00:00
return m_sWaylandState . fractional ;
}
2024-12-29 18:36:08 +00:00
SP < CCWpViewporter > CHyprlock : : getViewporter ( ) {
2024-02-18 23:08:03 +00:00
return m_sWaylandState . viewporter ;
}
size_t CHyprlock : : getPasswordBufferLen ( ) {
return m_sPasswordState . passBuffer . length ( ) ;
}
2024-02-20 00:11:19 +00:00
2024-03-10 15:33:01 +01:00
size_t CHyprlock : : getPasswordBufferDisplayLen ( ) {
// Counts utf-8 codepoints in the buffer. A byte is counted if it does not match 0b10xxxxxx.
return std : : count_if ( m_sPasswordState . passBuffer . begin ( ) , m_sPasswordState . passBuffer . end ( ) , [ ] ( char c ) { return ( c & 0xc0 ) ! = 0x80 ; } ) ;
}
2025-06-28 11:01:28 +02:00
ASP < CTimer > CHyprlock : : addTimer ( const std : : chrono : : system_clock : : duration & timeout , std : : function < void ( ASP < CTimer > self , void * data ) > cb_ , void * data , bool force ) {
2024-02-20 00:11:19 +00:00
std : : lock_guard < std : : mutex > lg ( m_sLoopState . timersMutex ) ;
2025-06-28 11:01:28 +02:00
const auto T = m_vTimers . emplace_back ( makeAtomicShared < CTimer > ( timeout , cb_ , data , force ) ) ;
2024-02-20 00:31:11 +00:00
m_sLoopState . timerEvent = true ;
m_sLoopState . timerCV . notify_all ( ) ;
return T ;
2024-02-20 00:11:19 +00:00
}
2024-02-21 14:08:40 +00:00
2025-06-28 11:01:28 +02:00
std : : vector < ASP < CTimer > > CHyprlock : : getTimers ( ) {
2024-03-11 00:38:01 +03:00
return m_vTimers ;
}
2024-04-10 23:41:31 +02:00
void CHyprlock : : enqueueForceUpdateTimers ( ) {
2024-12-29 18:36:08 +00:00
addTimer (
std : : chrono : : milliseconds ( 1 ) ,
2025-06-28 11:01:28 +02:00
[ ] ( ASP < CTimer > self , void * data ) {
2024-12-29 18:36:08 +00:00
for ( auto & t : g_pHyprlock - > getTimers ( ) ) {
if ( t - > canForceUpdate ( ) ) {
t - > call ( t ) ;
t - > cancel ( ) ;
}
}
} ,
nullptr , false ) ;
2024-04-10 23:41:31 +02:00
}
2024-12-29 18:36:08 +00:00
SP < CCZwlrScreencopyManagerV1 > CHyprlock : : getScreencopy ( ) {
2024-02-21 21:38:37 +00:00
return m_sWaylandState . screencopy ;
2024-03-05 19:03:55 +00:00
}
2025-01-24 13:25:37 +00:00
SP < CCWlShm > CHyprlock : : getShm ( ) {
return m_sWaylandState . shm ;
}