-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathtask_manager.py
More file actions
226 lines (187 loc) · 7.49 KB
/
task_manager.py
File metadata and controls
226 lines (187 loc) · 7.49 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
# __ __ _____ ___ ___
# / / /\ \ \/\ /\/__ \/___\/ _ \
# \ \/ \/ / /_/ / / /\// // /_)/
# \ /\ / __ / / / / \_// ___/
# \/ \/\/ /_/ \/ \___/\/
#
# MAIN CODE ENTRY POINT, LOOKING FOR SOMETHING? TRY THE MODULES FOLDER!
import sys
import os
import time
import psutil
# Check for Windows
if sys.platform != 'win32':
print("This application is designed for Windows only. If this is linux, use htop instead, and if this is macos, use Activity Monitor.")
sys.exit(1)
# Import modules
try:
from modules.config import *
from modules import config
from modules.state import state
from modules.utils import *
from modules.hardware import get_hardware_info, update_system_stats, update_system_stats_fast, update_system_stats_slow
from modules.processes import get_processes
from modules.input import handle_input
# Conditional Rich UI import
if config.USE_RICH_UI:
try:
from modules.richui import render, render_startup
except ImportError as e:
print(f"Rich UI failed to load ({e}), falling back to ANSI UI...")
from modules.ui import render, render_startup
config.USE_RICH_UI = False
else:
from modules.ui import render, render_startup
except ImportError as e:
print(f"Error loading modules: {e}")
time.sleep(2)
print("Please open an issue on GitHub with the error message (preferably as a .txt file).")
time.sleep(2)
sys.exit(1)
try:
import modules.audio_vis
except ImportError:
pass
def main():
"""Main application loop."""
# Enable ANSI
os.system("")
# Clear screen and hide cursor
clear_screen()
sys.stdout.write("\033[?25l")
sys.stdout.flush()
# Total initialization steps for progress tracking
TOTAL_STEPS = 100
current_step = 0
# Helper to advance progress
def bump_progress(amount=1, msg=None):
nonlocal current_step
current_step += amount
if current_step > TOTAL_STEPS: current_step = TOTAL_STEPS
render_startup(current_step, TOTAL_STEPS, msg)
# Step: Initial splash
bump_progress(5, "Initializing terminal magic...")
# Step: Poke kernel (enable virtual terminal)
bump_progress(5, "Poking the system kernel...")
time.sleep(0.1)
# Step: Fetch CPU info (Can take 1-2s)
bump_progress(5, "Interrogating your CPU...")
get_hardware_info()
# Step: GPU & More
bump_progress(10, "Waking up the GPU...")
time.sleep(0.05)
# Step: Collect process breadcrumbs
bump_progress(5, "Collecting process breadcrumbs...")
psutil.cpu_percent(percpu=True)
# Step: Prime individual process CPU times (Main delay)
bump_progress(5, "Priming the performance counters...")
# We will use about 50 steps for this loop
proc_list = list(psutil.process_iter()) # Snapshot first
total_procs = len(proc_list)
# Flavor text for the loop
flavor_msgs = [
"Reordering electrons...",
"Compiling bitstreams...",
"Calibrating flux capacitor...",
"Reticulating splines...",
"Defragmenting ghosts...",
"Scanning quantum fluctuations..."
]
import random
for i, proc in enumerate(proc_list):
try:
proc.cpu_times()
except:
pass
# Update UI every chunk of processes
if i % 10 == 0 or i == total_procs - 1:
# Calculate progress within the loop (allocating 50 steps)
loop_progress = int((i / total_procs) * 50)
base_progress = 35 # Steps before this loop
# Switch flavor text occasionally
flavor = "Priming performance counters..."
if i % 40 == 0:
flavor = flavor_msgs[(i // 40) % len(flavor_msgs)]
render_startup(base_progress + loop_progress, TOTAL_STEPS, f"{flavor} ({int(i/total_procs*100)}%)")
current_step = 85 # Jump to after loop
# Step: Initial system stats
bump_progress(5, "Gathering system vitals...")
update_system_stats()
# Step: Final polish
bump_progress(5, "Polishing the UI...")
get_processes()
# Step: Ready
bump_progress(5, "Ready to go!")
time.sleep(0.3)
# Clear screen after startup to prevent "Ready to go!" from lingering
clear_screen()
try:
last_update = 0
last_process_update = 0
frame_count = 0
while state.app_running:
now = time.time()
refresh_interval = REFRESH_RATES.get(state.current_refresh_rate, 2.0)
# Party mode: skip ALL psutil updates - bars are driven by audio only
if state.party_mode:
# Just render the audio visualization at max speed
render()
handle_input()
time.sleep(max(0.001, refresh_interval * 0.5))
continue
# For high-speed modes (ultrafast), split updates:
# - Fast (CPU only): every frame for smooth bars
# - Slow (mem, disk, net, gpu): every 0.5s
# - Processes: every 0.5s
is_high_speed = refresh_interval < 0.5
slow_update_interval = 0.5 if is_high_speed else refresh_interval
# Always update at refresh interval
if now - last_update >= refresh_interval:
if is_high_speed:
# High-speed: only CPU stats every frame
update_system_stats_fast()
else:
# Normal: all stats every frame
update_system_stats()
frame_count += 1
last_update = now
# Slow updates (processes + non-CPU stats) less frequently
if now - last_process_update >= slow_update_interval:
if is_high_speed:
update_system_stats_slow()
get_processes()
last_process_update = now
render()
# Input polling - minimal delay for high-speed modes
if is_high_speed:
# Quick input check, no long polling loop
handle_input()
time.sleep(max(0.001, refresh_interval * 0.5))
else:
# Normal polling for slower modes
poll_end = time.time() + min(0.1, refresh_interval * 0.5)
while time.time() < poll_end:
handle_input()
if not state.app_running:
break
time.sleep(0.02)
except KeyboardInterrupt:
pass
except Exception as e:
# Emergency exit to see errors
sys.stdout.write("\033[?25h")
sys.stdout.write(C_RESET)
print(f"CRASH: {e}")
import traceback
traceback.print_exc()
finally:
# Clean up party mode audio if active
if state.party_visualizer:
state.party_visualizer.stop()
sys.stdout.write("\033[?25h") # Show cursor
sys.stdout.write(C_RESET)
clear_screen()
print("Exiting Task Manager... Cya!")
time.sleep(1)
if __name__ == "__main__":
main()