1616#include <string.h>
1717#include <ctype.h>
1818#include <windows.h>
19+ #include <time.h>
20+ #include <stdint.h>
1921
2022#define SECONDS_PER_MINUTE 60
2123#define SECONDS_PER_HOUR 3600
@@ -51,6 +53,22 @@ char CLOCK_TIMEOUT_FILE_PATH[MAX_PATH] = "";
5153int time_options [MAX_TIME_OPTIONS ] = {0 };
5254int time_options_count = 0 ;
5355
56+ /* Absolute Time State Definitions (Milliseconds) */
57+ int64_t g_target_end_time = 0 ;
58+ int64_t g_start_time = 0 ;
59+ int64_t g_pause_start_time = 0 ;
60+
61+ /* Helper for millisecond precision */
62+ int64_t GetAbsoluteTimeMs (void ) {
63+ FILETIME ft ;
64+ GetSystemTimeAsFileTime (& ft );
65+ ULARGE_INTEGER uli ;
66+ uli .LowPart = ft .dwLowDateTime ;
67+ uli .HighPart = ft .dwHighDateTime ;
68+ /* Convert 100-nanosecond intervals (since Jan 1, 1601) to milliseconds */
69+ return (int64_t )(uli .QuadPart / 10000ULL );
70+ }
71+
5472/** Reset QPC baseline to prevent time jumps after pause/resume */
5573BOOL InitializeHighPrecisionTimer (void ) {
5674 if (!QueryPerformanceFrequency (& timer_frequency )) {
@@ -63,45 +81,6 @@ BOOL InitializeHighPrecisionTimer(void) {
6381 return TRUE;
6482}
6583
66- /** Delta-based measurement, auto-updates baseline to avoid accumulation errors */
67- static double GetElapsedMilliseconds (void ) {
68- if (!high_precision_timer_initialized ) {
69- if (!InitializeHighPrecisionTimer ()) {
70- return 0.0 ;
71- }
72- }
73-
74- LARGE_INTEGER current_count ;
75- if (!QueryPerformanceCounter (& current_count )) {
76- return 0.0 ;
77- }
78-
79- double elapsed = (double )(current_count .QuadPart - timer_last_count .QuadPart )
80- * MILLISECONDS_PER_SECOND / (double )timer_frequency .QuadPart ;
81- timer_last_count = current_count ;
82-
83- return elapsed ;
84- }
85-
86- /** Accumulate elapsed time, clamp countdown to prevent negative display */
87- static void UpdateElapsedTime (void ) {
88- if (CLOCK_IS_PAUSED ) {
89- return ;
90- }
91-
92- double elapsed_ms = GetElapsedMilliseconds ();
93- int elapsed_sec = (int )(elapsed_ms / MILLISECONDS_PER_SECOND );
94-
95- if (CLOCK_COUNT_UP ) {
96- countup_elapsed_time += elapsed_sec ;
97- } else {
98- countdown_elapsed_time += elapsed_sec ;
99- if (countdown_elapsed_time > CLOCK_TOTAL_TIME ) {
100- countdown_elapsed_time = CLOCK_TOTAL_TIME ;
101- }
102- }
103- }
104-
10584/** Leading spaces stabilize width when hours/minutes disappear during countdown */
10685static void FormatTimeComponents (int hours , int minutes , int seconds ,
10786 char * buffer , size_t buffer_size ) {
@@ -153,7 +132,7 @@ static void FormatSystemClock(char* time_text) {
153132}
154133
155134static void FormatCountUpTime (char * time_text ) {
156- UpdateElapsedTime ();
135+ // Elapsed time is now updated by HandleMainTimer in timer_events.c
157136
158137 int hours = countup_elapsed_time / SECONDS_PER_HOUR ;
159138 int minutes = (countup_elapsed_time % SECONDS_PER_HOUR ) / SECONDS_PER_MINUTE ;
@@ -163,7 +142,7 @@ static void FormatCountUpTime(char* time_text) {
163142}
164143
165144static void FormatCountdownTime (char * time_text ) {
166- UpdateElapsedTime ();
145+ // Elapsed time is now updated by HandleMainTimer in timer_events.c
167146
168147 int remaining = CLOCK_TOTAL_TIME - countdown_elapsed_time ;
169148 if (remaining <= 0 ) {
@@ -272,18 +251,23 @@ void WriteConfigDefaultStartTime(int seconds) {
272251
273252/** Fallback to DEFAULT_FALLBACK_TIME if countdown has invalid total time */
274253void ResetTimer (void ) {
254+ int64_t now = GetAbsoluteTimeMs ();
255+
275256 if (CLOCK_COUNT_UP ) {
276257 countup_elapsed_time = 0 ;
258+ g_start_time = now ;
277259 } else {
278260 countdown_elapsed_time = 0 ;
279261 if (CLOCK_TOTAL_TIME <= 0 ) {
280262 CLOCK_TOTAL_TIME = DEFAULT_FALLBACK_TIME ;
281263 }
264+ g_target_end_time = now + ((int64_t )CLOCK_TOTAL_TIME * 1000 );
282265 }
283266
284267 CLOCK_IS_PAUSED = FALSE;
285268 countdown_message_shown = FALSE;
286269 countup_message_shown = FALSE;
270+ g_pause_start_time = 0 ;
287271
288272 InitializeHighPrecisionTimer ();
289273 ResetMillisecondAccumulator ();
@@ -294,10 +278,19 @@ void TogglePauseTimer(void) {
294278 BOOL was_paused = CLOCK_IS_PAUSED ;
295279 CLOCK_IS_PAUSED = !CLOCK_IS_PAUSED ;
296280
281+ int64_t now = GetAbsoluteTimeMs ();
282+
297283 if (CLOCK_IS_PAUSED && !was_paused ) {
284+ g_pause_start_time = now ;
298285 PauseTimerMilliseconds ();
299286 } else if (!CLOCK_IS_PAUSED && was_paused ) {
287+ if (g_pause_start_time > 0 ) {
288+ int64_t pause_duration = now - g_pause_start_time ;
289+ g_target_end_time += pause_duration ;
290+ g_start_time += pause_duration ;
291+ g_pause_start_time = 0 ;
292+ }
300293 InitializeHighPrecisionTimer ();
301294 ResetMillisecondAccumulator ();
302295 }
303- }
296+ }
0 commit comments