From d7287e50d488d5f7d280277d76a025ae7e66ec3b Mon Sep 17 00:00:00 2001 From: S4NKALP Date: Thu, 31 Jul 2025 23:19:40 +0545 Subject: [PATCH] =?UTF-8?q?=E2=9C=A8=20feat(panel):=20improve=20recording?= =?UTF-8?q?=20indicator=20reliability=20and=20timer=20accuracy?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../panel/components/recording_indicator.py | 194 ++++++++++++++---- 1 file changed, 156 insertions(+), 38 deletions(-) diff --git a/modules/panel/components/recording_indicator.py b/modules/panel/components/recording_indicator.py index d9fa1e5..cf2d515 100644 --- a/modules/panel/components/recording_indicator.py +++ b/modules/panel/components/recording_indicator.py @@ -1,3 +1,4 @@ +import os import subprocess import time @@ -9,8 +10,6 @@ from fabric.widgets.button import Button from fabric.widgets.label import Label from fabric.widgets.svg import Svg -# FIX: Make the timer consistent with the recording start time - class RecordingIndicator(Button): def __init__(self, **kwargs): @@ -18,6 +17,13 @@ class RecordingIndicator(Button): self.script_path = get_relative_path("../../../scripts/screen-capture.sh") self.recording_start_time = None + self.last_process_check = 0 + self.process_check_interval = 1.0 + self.timer_update_interval = 1000 + self.status_check_interval = 2000 + + self.timer_timeout_id = None + self.status_timeout_id = None self.recording_icon = Svg( name="indicators-icon", @@ -41,69 +47,181 @@ class RecordingIndicator(Button): self.add(self.recording_box) self.connect("clicked", self.on_stop_recording) + self.connect("button-press-event", self.on_button_press) self.hide() - GLib.timeout_add(1, self._delayed_init) + GLib.timeout_add(100, self._delayed_init) - def check_recording_status(self): + def on_button_press(self, *args): + GLib.timeout_add(100, lambda: self.remove_style_class("pressed") or False) + return False + + def is_wf_recorder_running(self): try: result = subprocess.run( - [self.script_path, "status"], capture_output=True, text=True, timeout=2 + ["pgrep", "-x", "wf-recorder"], + capture_output=True, + text=True, + timeout=1, ) - is_recording = result.stdout.strip() == "true" + return result.returncode == 0 + except Exception: + return False + + def check_recording_status(self): + current_time = time.time() + self.last_process_check = current_time + + try: + is_recording = self.is_wf_recorder_running() if is_recording: if not self.get_visible(): - self.show() + self.set_visible(True) + if self.timer_timeout_id is None: + self.timer_timeout_id = GLib.timeout_add( + self.timer_update_interval, self.update_timer_display + ) - # Get the recording start time if we don't have it if self.recording_start_time is None: self.recording_start_time = self.get_recording_start_time() - # Update the recording time display - if self.recording_start_time: - elapsed_seconds = int(time.time() - self.recording_start_time) - minutes = elapsed_seconds // 60 - seconds = elapsed_seconds % 60 - time_text = f"{minutes:02d}:{seconds:02d}" - self.time_label.set_markup(time_text) - self.set_tooltip_text( - f"Recording in progress ({minutes:02d}:{ - seconds:02d}) - Click to stop" - ) - else: - self.set_tooltip_text("Recording in progress - Click to stop") + self.update_timer_display() else: if self.get_visible(): - self.hide() - self.recording_start_time = None + self.set_visible(False) + self.cleanup_recording_state() - except Exception: - # If we can't check status, hide the indicator + except Exception as e: + print(f"[DEBUG] Error checking recording status: {e}") if self.get_visible(): - self.hide() - self.recording_start_time = None + self.set_visible(False) + self.cleanup_recording_state() - return True # Continue the timeout + return True + + def update_timer_display(self): + if not self.get_visible() or self.recording_start_time is None: + return False + + try: + elapsed_seconds = int(time.time() - self.recording_start_time) + minutes = elapsed_seconds // 60 + seconds = elapsed_seconds % 60 + time_text = f"{minutes:02d}:{seconds:02d}" + + self.time_label.set_markup(time_text) + self.set_tooltip_text( + f"Recording in progress ({time_text}) - Click to stop" + ) + + return True + except Exception as e: + print(f"[DEBUG] Error updating timer display: {e}") + return False + + def cleanup_recording_state(self): + self.recording_start_time = None + + if self.timer_timeout_id: + GLib.source_remove(self.timer_timeout_id) + self.timer_timeout_id = None def get_recording_start_time(self): - """Get the recording start time from the file""" + start_time_file = "/tmp/recording_start_time.txt" + try: - with open("/tmp/recording_start_time.txt", "r") as f: - return float(f.read().strip()) - except Exception: - return None + if not os.path.exists(start_time_file): + return None + + file_mtime = os.path.getmtime(start_time_file) + + with open(start_time_file, "r") as f: + content = f.read().strip() + if content: + recorded_time = float(content) + + current_time = time.time() + if abs(recorded_time - current_time) > 3600: + return file_mtime + + return recorded_time + else: + return file_mtime + + except (ValueError, OSError): + try: + return os.path.getmtime(start_time_file) + except OSError: + return None def on_stop_recording(self, *args): try: - subprocess.Popen([self.script_path, "record", "stop"]) - except Exception as e: - print(f"Error stopping recording: {e}") + self.set_visible(False) + self.cleanup_recording_state() + + def send_stop_command(): + try: + subprocess.Popen( + [self.script_path, "record", "stop"], + stdout=subprocess.DEVNULL, + stderr=subprocess.DEVNULL, + ) + except Exception as e: + print(f"[DEBUG] Error sending stop command: {e}") + + GLib.idle_add(send_stop_command) + GLib.timeout_add(500, self._verify_recording_stopped) + GLib.timeout_add(1500, self._verify_recording_stopped) + GLib.timeout_add(3000, self._verify_recording_stopped) + + except Exception: + self.set_visible(False) + self.cleanup_recording_state() + + def _verify_recording_stopped(self): + try: + if self.is_wf_recorder_running(): + if self.recording_start_time is None: + self.recording_start_time = self.get_recording_start_time() + + if self.recording_start_time: + self.set_visible(True) + self.update_timer_display() + + if self.timer_timeout_id is None: + self.timer_timeout_id = GLib.timeout_add( + self.timer_update_interval, self.update_timer_display + ) + + else: + self.set_visible(False) + self.cleanup_recording_state() + + except Exception: + self.set_visible(False) + self.cleanup_recording_state() + + return False def _delayed_init(self): try: self.check_recording_status() - self.timeout_id = GLib.timeout_add(5000, self.check_recording_status) + self.status_timeout_id = GLib.timeout_add( + self.status_check_interval, self.check_recording_status + ) + except Exception as e: print(f"[DEBUG] Error in delayed recording indicator init: {e}") - return False # Don't repeat this timeout + return False + + def destroy(self): + if self.timer_timeout_id: + GLib.source_remove(self.timer_timeout_id) + self.timer_timeout_id = None + + if self.status_timeout_id: + GLib.source_remove(self.status_timeout_id) + self.status_timeout_id = None + + super().destroy()