- System protection script with custom enhancements and TUI interface - Browser tab limiting and application-specific monitoring - AI behavior learning and predictive analysis - Terminal-based configuration interface - Multi-distro installation support
751 lines
36 KiB
Python
Executable File
751 lines
36 KiB
Python
Executable File
#!/usr/bin/env python3
|
|
"""
|
|
PC Anti-Freeze Monitor - GUI Settings Manager
|
|
Advanced configuration interface for the PC monitoring system
|
|
"""
|
|
|
|
import tkinter as tk
|
|
from tkinter import ttk, messagebox, filedialog
|
|
import subprocess
|
|
import os
|
|
import json
|
|
import configparser
|
|
from pathlib import Path
|
|
import threading
|
|
import time
|
|
|
|
class PCMonitorGUI:
|
|
def __init__(self, root):
|
|
self.root = root
|
|
self.root.title("PC Anti-Freeze Monitor - Advanced Settings")
|
|
self.root.geometry("800x700")
|
|
self.root.resizable(True, True)
|
|
|
|
# Configuration file path
|
|
self.config_file = "/etc/pc-monitor.conf"
|
|
self.service_name = "pc-monitor"
|
|
|
|
# Default values
|
|
self.default_config = {
|
|
'CPU_THRESHOLD': '85',
|
|
'MEMORY_THRESHOLD': '90',
|
|
'TEMP_THRESHOLD': '80',
|
|
'DISK_THRESHOLD': '95',
|
|
'PROCESS_HANG_TIME': '30',
|
|
'SWAP_THRESHOLD': '80',
|
|
'LOAD_AVG_THRESHOLD': '10',
|
|
'NETWORK_THRESHOLD': '50',
|
|
'IO_THRESHOLD': '100',
|
|
'BROWSER_TAB_LIMIT': '20',
|
|
'AGGRESSIVE_ON_BROWSERS': 'true',
|
|
'AGGRESSIVE_CPU_THRESHOLD': '75',
|
|
'AGGRESSIVE_MEMORY_THRESHOLD': '80',
|
|
'BROWSER_CPU_THRESHOLD': '60',
|
|
'BROWSER_MEMORY_THRESHOLD': '70',
|
|
'GAME_CPU_THRESHOLD': '95',
|
|
'GAME_MEMORY_THRESHOLD': '85',
|
|
'IDE_MEMORY_THRESHOLD': '75',
|
|
'FIREFOX_MAX_TABS': '15',
|
|
'CHROME_MAX_TABS': '15',
|
|
'EDGE_MAX_TABS': '10',
|
|
'NOTIFICATION_TIMEOUT': '5000'
|
|
}
|
|
|
|
self.create_widgets()
|
|
self.load_config()
|
|
self.update_service_status()
|
|
|
|
# Auto-refresh service status
|
|
self.root.after(2000, self.auto_refresh_status)
|
|
|
|
def create_widgets(self):
|
|
# Create main notebook for tabs
|
|
self.notebook = ttk.Notebook(self.root)
|
|
self.notebook.pack(fill=tk.BOTH, expand=True, padx=10, pady=10)
|
|
|
|
# Create tabs
|
|
self.create_basic_tab()
|
|
self.create_advanced_tab()
|
|
self.create_browser_tab()
|
|
self.create_app_specific_tab()
|
|
self.create_monitoring_tab()
|
|
self.create_control_tab()
|
|
|
|
# Create button frame
|
|
button_frame = ttk.Frame(self.root)
|
|
button_frame.pack(fill=tk.X, padx=10, pady=5)
|
|
|
|
ttk.Button(button_frame, text="Save Configuration",
|
|
command=self.save_config).pack(side=tk.LEFT, padx=5)
|
|
ttk.Button(button_frame, text="Load Configuration",
|
|
command=self.load_config).pack(side=tk.LEFT, padx=5)
|
|
ttk.Button(button_frame, text="Reset to Defaults",
|
|
command=self.reset_to_defaults).pack(side=tk.LEFT, padx=5)
|
|
ttk.Button(button_frame, text="Export Config",
|
|
command=self.export_config).pack(side=tk.LEFT, padx=5)
|
|
ttk.Button(button_frame, text="Import Config",
|
|
command=self.import_config).pack(side=tk.LEFT, padx=5)
|
|
|
|
def create_basic_tab(self):
|
|
# Basic Settings Tab
|
|
basic_frame = ttk.Frame(self.notebook)
|
|
self.notebook.add(basic_frame, text="Basic Settings")
|
|
|
|
# CPU Settings
|
|
cpu_frame = ttk.LabelFrame(basic_frame, text="CPU Monitoring", padding=10)
|
|
cpu_frame.pack(fill=tk.X, padx=10, pady=5)
|
|
|
|
ttk.Label(cpu_frame, text="CPU Threshold (%):").grid(row=0, column=0, sticky=tk.W, pady=2)
|
|
self.cpu_threshold = ttk.Scale(cpu_frame, from_=50, to=100, orient=tk.HORIZONTAL, length=200)
|
|
self.cpu_threshold.grid(row=0, column=1, padx=10, pady=2)
|
|
self.cpu_threshold_label = ttk.Label(cpu_frame, text="85%")
|
|
self.cpu_threshold_label.grid(row=0, column=2, pady=2)
|
|
self.cpu_threshold.configure(command=lambda v: self.cpu_threshold_label.config(text=f"{int(float(v))}%"))
|
|
|
|
# Memory Settings
|
|
mem_frame = ttk.LabelFrame(basic_frame, text="Memory Monitoring", padding=10)
|
|
mem_frame.pack(fill=tk.X, padx=10, pady=5)
|
|
|
|
ttk.Label(mem_frame, text="Memory Threshold (%):").grid(row=0, column=0, sticky=tk.W, pady=2)
|
|
self.memory_threshold = ttk.Scale(mem_frame, from_=50, to=100, orient=tk.HORIZONTAL, length=200)
|
|
self.memory_threshold.grid(row=0, column=1, padx=10, pady=2)
|
|
self.memory_threshold_label = ttk.Label(mem_frame, text="90%")
|
|
self.memory_threshold_label.grid(row=0, column=2, pady=2)
|
|
self.memory_threshold.configure(command=lambda v: self.memory_threshold_label.config(text=f"{int(float(v))}%"))
|
|
|
|
# Temperature Settings
|
|
temp_frame = ttk.LabelFrame(basic_frame, text="Temperature Monitoring", padding=10)
|
|
temp_frame.pack(fill=tk.X, padx=10, pady=5)
|
|
|
|
ttk.Label(temp_frame, text="Temperature Threshold (°C):").grid(row=0, column=0, sticky=tk.W, pady=2)
|
|
self.temp_threshold = ttk.Scale(temp_frame, from_=60, to=100, orient=tk.HORIZONTAL, length=200)
|
|
self.temp_threshold.grid(row=0, column=1, padx=10, pady=2)
|
|
self.temp_threshold_label = ttk.Label(temp_frame, text="80°C")
|
|
self.temp_threshold_label.grid(row=0, column=2, pady=2)
|
|
self.temp_threshold.configure(command=lambda v: self.temp_threshold_label.config(text=f"{int(float(v))}°C"))
|
|
|
|
# Disk Settings
|
|
disk_frame = ttk.LabelFrame(basic_frame, text="Disk Monitoring", padding=10)
|
|
disk_frame.pack(fill=tk.X, padx=10, pady=5)
|
|
|
|
ttk.Label(disk_frame, text="Disk Usage Threshold (%):").grid(row=0, column=0, sticky=tk.W, pady=2)
|
|
self.disk_threshold = ttk.Scale(disk_frame, from_=80, to=99, orient=tk.HORIZONTAL, length=200)
|
|
self.disk_threshold.grid(row=0, column=1, padx=10, pady=2)
|
|
self.disk_threshold_label = ttk.Label(disk_frame, text="95%")
|
|
self.disk_threshold_label.grid(row=0, column=2, pady=2)
|
|
self.disk_threshold.configure(command=lambda v: self.disk_threshold_label.config(text=f"{int(float(v))}%"))
|
|
|
|
def create_advanced_tab(self):
|
|
# Advanced Settings Tab
|
|
advanced_frame = ttk.Frame(self.notebook)
|
|
self.notebook.add(advanced_frame, text="Advanced Settings")
|
|
|
|
# Aggressive Mode
|
|
aggressive_frame = ttk.LabelFrame(advanced_frame, text="Aggressive Mode", padding=10)
|
|
aggressive_frame.pack(fill=tk.X, padx=10, pady=5)
|
|
|
|
self.aggressive_browsers = tk.BooleanVar()
|
|
ttk.Checkbutton(aggressive_frame, text="Enable Aggressive Mode for Browsers",
|
|
variable=self.aggressive_browsers).pack(anchor=tk.W)
|
|
|
|
ttk.Label(aggressive_frame, text="Aggressive CPU Threshold (%):").pack(anchor=tk.W, pady=(10,0))
|
|
self.aggressive_cpu_threshold = ttk.Scale(aggressive_frame, from_=50, to=90, orient=tk.HORIZONTAL, length=300)
|
|
self.aggressive_cpu_threshold.pack(pady=5)
|
|
|
|
ttk.Label(aggressive_frame, text="Aggressive Memory Threshold (%):").pack(anchor=tk.W)
|
|
self.aggressive_memory_threshold = ttk.Scale(aggressive_frame, from_=50, to=90, orient=tk.HORIZONTAL, length=300)
|
|
self.aggressive_memory_threshold.pack(pady=5)
|
|
|
|
# Network & I/O Settings
|
|
network_frame = ttk.LabelFrame(advanced_frame, text="Network & I/O Monitoring", padding=10)
|
|
network_frame.pack(fill=tk.X, padx=10, pady=5)
|
|
|
|
ttk.Label(network_frame, text="Network Threshold (MB/s):").pack(anchor=tk.W)
|
|
self.network_threshold = ttk.Entry(network_frame, width=10)
|
|
self.network_threshold.pack(anchor=tk.W, pady=2)
|
|
|
|
ttk.Label(network_frame, text="I/O Threshold (MB/s):").pack(anchor=tk.W, pady=(10,0))
|
|
self.io_threshold = ttk.Entry(network_frame, width=10)
|
|
self.io_threshold.pack(anchor=tk.W, pady=2)
|
|
|
|
# Process Settings
|
|
process_frame = ttk.LabelFrame(advanced_frame, text="Process Monitoring", padding=10)
|
|
process_frame.pack(fill=tk.X, padx=10, pady=5)
|
|
|
|
ttk.Label(process_frame, text="Process Hang Time (seconds):").pack(anchor=tk.W)
|
|
self.process_hang_time = ttk.Entry(process_frame, width=10)
|
|
self.process_hang_time.pack(anchor=tk.W, pady=2)
|
|
|
|
ttk.Label(process_frame, text="Swap Threshold (%):").pack(anchor=tk.W, pady=(10,0))
|
|
self.swap_threshold = ttk.Entry(process_frame, width=10)
|
|
self.swap_threshold.pack(anchor=tk.W, pady=2)
|
|
|
|
ttk.Label(process_frame, text="Load Average Threshold:").pack(anchor=tk.W, pady=(10,0))
|
|
self.load_avg_threshold = ttk.Entry(process_frame, width=10)
|
|
self.load_avg_threshold.pack(anchor=tk.W, pady=2)
|
|
|
|
def create_browser_tab(self):
|
|
# Browser Settings Tab
|
|
browser_frame = ttk.Frame(self.notebook)
|
|
self.notebook.add(browser_frame, text="Browser Control")
|
|
|
|
# Browser Tab Limits
|
|
tab_frame = ttk.LabelFrame(browser_frame, text="Browser Tab Limits", padding=10)
|
|
tab_frame.pack(fill=tk.X, padx=10, pady=5)
|
|
|
|
browsers = [
|
|
("Firefox Max Tabs:", "firefox_max_tabs"),
|
|
("Chrome Max Tabs:", "chrome_max_tabs"),
|
|
("Edge Max Tabs:", "edge_max_tabs")
|
|
]
|
|
|
|
self.browser_entries = {}
|
|
for i, (label, key) in enumerate(browsers):
|
|
ttk.Label(tab_frame, text=label).grid(row=i, column=0, sticky=tk.W, pady=5)
|
|
self.browser_entries[key] = ttk.Entry(tab_frame, width=10)
|
|
self.browser_entries[key].grid(row=i, column=1, padx=10, pady=5)
|
|
|
|
# Browser Thresholds
|
|
browser_threshold_frame = ttk.LabelFrame(browser_frame, text="Browser Resource Thresholds", padding=10)
|
|
browser_threshold_frame.pack(fill=tk.X, padx=10, pady=5)
|
|
|
|
ttk.Label(browser_threshold_frame, text="Browser CPU Threshold (%):").pack(anchor=tk.W)
|
|
self.browser_cpu_threshold = ttk.Scale(browser_threshold_frame, from_=30, to=90, orient=tk.HORIZONTAL, length=300)
|
|
self.browser_cpu_threshold.pack(pady=5)
|
|
|
|
ttk.Label(browser_threshold_frame, text="Browser Memory Threshold (%):").pack(anchor=tk.W)
|
|
self.browser_memory_threshold = ttk.Scale(browser_threshold_frame, from_=30, to=90, orient=tk.HORIZONTAL, length=300)
|
|
self.browser_memory_threshold.pack(pady=5)
|
|
|
|
# General Browser Tab Limit
|
|
general_frame = ttk.LabelFrame(browser_frame, text="General Browser Settings", padding=10)
|
|
general_frame.pack(fill=tk.X, padx=10, pady=5)
|
|
|
|
ttk.Label(general_frame, text="Global Browser Tab Limit:").pack(anchor=tk.W)
|
|
self.browser_tab_limit = ttk.Entry(general_frame, width=10)
|
|
self.browser_tab_limit.pack(anchor=tk.W, pady=2)
|
|
|
|
def create_app_specific_tab(self):
|
|
# Application-Specific Settings Tab
|
|
app_frame = ttk.Frame(self.notebook)
|
|
self.notebook.add(app_frame, text="App-Specific")
|
|
|
|
# Game Settings
|
|
game_frame = ttk.LabelFrame(app_frame, text="Gaming Applications", padding=10)
|
|
game_frame.pack(fill=tk.X, padx=10, pady=5)
|
|
|
|
ttk.Label(game_frame, text="Game CPU Threshold (%):").pack(anchor=tk.W)
|
|
self.game_cpu_threshold = ttk.Scale(game_frame, from_=70, to=100, orient=tk.HORIZONTAL, length=300)
|
|
self.game_cpu_threshold.pack(pady=5)
|
|
|
|
ttk.Label(game_frame, text="Game Memory Threshold (%):").pack(anchor=tk.W)
|
|
self.game_memory_threshold = ttk.Scale(game_frame, from_=70, to=100, orient=tk.HORIZONTAL, length=300)
|
|
self.game_memory_threshold.pack(pady=5)
|
|
|
|
# IDE Settings
|
|
ide_frame = ttk.LabelFrame(app_frame, text="Development Tools (IDEs)", padding=10)
|
|
ide_frame.pack(fill=tk.X, padx=10, pady=5)
|
|
|
|
ttk.Label(ide_frame, text="IDE Memory Threshold (%):").pack(anchor=tk.W)
|
|
self.ide_memory_threshold = ttk.Scale(ide_frame, from_=50, to=90, orient=tk.HORIZONTAL, length=300)
|
|
self.ide_memory_threshold.pack(pady=5)
|
|
|
|
# Media & Graphics Settings
|
|
media_frame = ttk.LabelFrame(app_frame, text="Media & Graphics Applications", padding=10)
|
|
media_frame.pack(fill=tk.X, padx=10, pady=5)
|
|
|
|
ttk.Label(media_frame, text="More lenient thresholds for media editing applications").pack(anchor=tk.W)
|
|
ttk.Label(media_frame, text="(Blender, GIMP, video editors, etc.)").pack(anchor=tk.W)
|
|
|
|
def create_monitoring_tab(self):
|
|
# Monitoring & Logs Tab
|
|
monitoring_frame = ttk.Frame(self.notebook)
|
|
self.notebook.add(monitoring_frame, text="Monitoring")
|
|
|
|
# System Status
|
|
status_frame = ttk.LabelFrame(monitoring_frame, text="System Status", padding=10)
|
|
status_frame.pack(fill=tk.X, padx=10, pady=5)
|
|
|
|
self.status_text = tk.Text(status_frame, height=8, width=70)
|
|
scrollbar = ttk.Scrollbar(status_frame, orient=tk.VERTICAL, command=self.status_text.yview)
|
|
self.status_text.configure(yscrollcommand=scrollbar.set)
|
|
self.status_text.pack(side=tk.LEFT, fill=tk.BOTH, expand=True)
|
|
scrollbar.pack(side=tk.RIGHT, fill=tk.Y)
|
|
|
|
# Refresh button
|
|
ttk.Button(monitoring_frame, text="Refresh Status",
|
|
command=self.update_system_status).pack(pady=5)
|
|
|
|
# Log viewer
|
|
log_frame = ttk.LabelFrame(monitoring_frame, text="Recent Logs", padding=10)
|
|
log_frame.pack(fill=tk.BOTH, expand=True, padx=10, pady=5)
|
|
|
|
self.log_text = tk.Text(log_frame, height=10, width=70)
|
|
log_scrollbar = ttk.Scrollbar(log_frame, orient=tk.VERTICAL, command=self.log_text.yview)
|
|
self.log_text.configure(yscrollcommand=log_scrollbar.set)
|
|
self.log_text.pack(side=tk.LEFT, fill=tk.BOTH, expand=True)
|
|
log_scrollbar.pack(side=tk.RIGHT, fill=tk.Y)
|
|
|
|
ttk.Button(monitoring_frame, text="Refresh Logs",
|
|
command=self.update_logs).pack(pady=5)
|
|
|
|
def create_control_tab(self):
|
|
# Service Control Tab
|
|
control_frame = ttk.Frame(self.notebook)
|
|
self.notebook.add(control_frame, text="Service Control")
|
|
|
|
# Service Status
|
|
service_frame = ttk.LabelFrame(control_frame, text="Service Status", padding=10)
|
|
service_frame.pack(fill=tk.X, padx=10, pady=5)
|
|
|
|
self.service_status_label = ttk.Label(service_frame, text="Status: Checking...", font=("Arial", 12, "bold"))
|
|
self.service_status_label.pack(pady=10)
|
|
|
|
# Service Controls
|
|
button_frame = ttk.Frame(service_frame)
|
|
button_frame.pack(pady=10)
|
|
|
|
ttk.Button(button_frame, text="Start Service",
|
|
command=self.start_service).pack(side=tk.LEFT, padx=5)
|
|
ttk.Button(button_frame, text="Stop Service",
|
|
command=self.stop_service).pack(side=tk.LEFT, padx=5)
|
|
ttk.Button(button_frame, text="Restart Service",
|
|
command=self.restart_service).pack(side=tk.LEFT, padx=5)
|
|
ttk.Button(button_frame, text="Enable Auto-start",
|
|
command=self.enable_service).pack(side=tk.LEFT, padx=5)
|
|
ttk.Button(button_frame, text="Disable Auto-start",
|
|
command=self.disable_service).pack(side=tk.LEFT, padx=5)
|
|
|
|
# Installation/Uninstallation
|
|
install_frame = ttk.LabelFrame(control_frame, text="Installation Management", padding=10)
|
|
install_frame.pack(fill=tk.X, padx=10, pady=5)
|
|
|
|
install_button_frame = ttk.Frame(install_frame)
|
|
install_button_frame.pack(pady=10)
|
|
|
|
ttk.Button(install_button_frame, text="Install/Reinstall Service",
|
|
command=self.install_service).pack(side=tk.LEFT, padx=5)
|
|
ttk.Button(install_button_frame, text="Uninstall Service",
|
|
command=self.uninstall_service).pack(side=tk.LEFT, padx=5)
|
|
|
|
# Notification Settings
|
|
notification_frame = ttk.LabelFrame(control_frame, text="Notification Settings", padding=10)
|
|
notification_frame.pack(fill=tk.X, padx=10, pady=5)
|
|
|
|
ttk.Label(notification_frame, text="Notification Timeout (ms):").pack(anchor=tk.W)
|
|
self.notification_timeout = ttk.Entry(notification_frame, width=10)
|
|
self.notification_timeout.pack(anchor=tk.W, pady=2)
|
|
|
|
ttk.Button(notification_frame, text="Test Notification",
|
|
command=self.test_notification).pack(pady=10)
|
|
|
|
def load_config(self):
|
|
"""Load configuration from file"""
|
|
config_values = self.default_config.copy()
|
|
|
|
if os.path.exists(self.config_file):
|
|
try:
|
|
with open(self.config_file, 'r') as f:
|
|
for line in f:
|
|
line = line.strip()
|
|
if line and not line.startswith('#') and '=' in line:
|
|
key, value = line.split('=', 1)
|
|
config_values[key.strip()] = value.strip()
|
|
except Exception as e:
|
|
messagebox.showerror("Error", f"Failed to load configuration: {e}")
|
|
|
|
# Update GUI elements
|
|
self.cpu_threshold.set(float(config_values.get('CPU_THRESHOLD', '85')))
|
|
self.memory_threshold.set(float(config_values.get('MEMORY_THRESHOLD', '90')))
|
|
self.temp_threshold.set(float(config_values.get('TEMP_THRESHOLD', '80')))
|
|
self.disk_threshold.set(float(config_values.get('DISK_THRESHOLD', '95')))
|
|
|
|
self.aggressive_browsers.set(config_values.get('AGGRESSIVE_ON_BROWSERS', 'true').lower() == 'true')
|
|
self.aggressive_cpu_threshold.set(float(config_values.get('AGGRESSIVE_CPU_THRESHOLD', '75')))
|
|
self.aggressive_memory_threshold.set(float(config_values.get('AGGRESSIVE_MEMORY_THRESHOLD', '80')))
|
|
|
|
self.network_threshold.delete(0, tk.END)
|
|
self.network_threshold.insert(0, config_values.get('NETWORK_THRESHOLD', '50'))
|
|
|
|
self.io_threshold.delete(0, tk.END)
|
|
self.io_threshold.insert(0, config_values.get('IO_THRESHOLD', '100'))
|
|
|
|
self.process_hang_time.delete(0, tk.END)
|
|
self.process_hang_time.insert(0, config_values.get('PROCESS_HANG_TIME', '30'))
|
|
|
|
self.swap_threshold.delete(0, tk.END)
|
|
self.swap_threshold.insert(0, config_values.get('SWAP_THRESHOLD', '80'))
|
|
|
|
self.load_avg_threshold.delete(0, tk.END)
|
|
self.load_avg_threshold.insert(0, config_values.get('LOAD_AVG_THRESHOLD', '10'))
|
|
|
|
# Browser settings
|
|
self.browser_entries['firefox_max_tabs'].delete(0, tk.END)
|
|
self.browser_entries['firefox_max_tabs'].insert(0, config_values.get('FIREFOX_MAX_TABS', '15'))
|
|
|
|
self.browser_entries['chrome_max_tabs'].delete(0, tk.END)
|
|
self.browser_entries['chrome_max_tabs'].insert(0, config_values.get('CHROME_MAX_TABS', '15'))
|
|
|
|
self.browser_entries['edge_max_tabs'].delete(0, tk.END)
|
|
self.browser_entries['edge_max_tabs'].insert(0, config_values.get('EDGE_MAX_TABS', '10'))
|
|
|
|
self.browser_cpu_threshold.set(float(config_values.get('BROWSER_CPU_THRESHOLD', '60')))
|
|
self.browser_memory_threshold.set(float(config_values.get('BROWSER_MEMORY_THRESHOLD', '70')))
|
|
|
|
self.browser_tab_limit.delete(0, tk.END)
|
|
self.browser_tab_limit.insert(0, config_values.get('BROWSER_TAB_LIMIT', '20'))
|
|
|
|
# App-specific settings
|
|
self.game_cpu_threshold.set(float(config_values.get('GAME_CPU_THRESHOLD', '95')))
|
|
self.game_memory_threshold.set(float(config_values.get('GAME_MEMORY_THRESHOLD', '85')))
|
|
self.ide_memory_threshold.set(float(config_values.get('IDE_MEMORY_THRESHOLD', '75')))
|
|
|
|
self.notification_timeout.delete(0, tk.END)
|
|
self.notification_timeout.insert(0, config_values.get('NOTIFICATION_TIMEOUT', '5000'))
|
|
|
|
def save_config(self):
|
|
"""Save configuration to file"""
|
|
try:
|
|
config_content = f"""# PC Monitor Enhanced Configuration
|
|
# ===================================
|
|
|
|
# Basic Thresholds
|
|
CPU_THRESHOLD={int(self.cpu_threshold.get())}
|
|
MEMORY_THRESHOLD={int(self.memory_threshold.get())}
|
|
TEMP_THRESHOLD={int(self.temp_threshold.get())}
|
|
DISK_THRESHOLD={int(self.disk_threshold.get())}
|
|
PROCESS_HANG_TIME={self.process_hang_time.get()}
|
|
SWAP_THRESHOLD={self.swap_threshold.get()}
|
|
LOAD_AVG_THRESHOLD={self.load_avg_threshold.get()}
|
|
|
|
# Advanced Features
|
|
NETWORK_THRESHOLD={self.network_threshold.get()}
|
|
IO_THRESHOLD={self.io_threshold.get()}
|
|
BROWSER_TAB_LIMIT={self.browser_tab_limit.get()}
|
|
AGGRESSIVE_ON_BROWSERS={'true' if self.aggressive_browsers.get() else 'false'}
|
|
AGGRESSIVE_CPU_THRESHOLD={int(self.aggressive_cpu_threshold.get())}
|
|
AGGRESSIVE_MEMORY_THRESHOLD={int(self.aggressive_memory_threshold.get())}
|
|
|
|
# Application-Specific Thresholds
|
|
BROWSER_CPU_THRESHOLD={int(self.browser_cpu_threshold.get())}
|
|
BROWSER_MEMORY_THRESHOLD={int(self.browser_memory_threshold.get())}
|
|
GAME_CPU_THRESHOLD={int(self.game_cpu_threshold.get())}
|
|
GAME_MEMORY_THRESHOLD={int(self.game_memory_threshold.get())}
|
|
IDE_MEMORY_THRESHOLD={int(self.ide_memory_threshold.get())}
|
|
|
|
# Browser Tab Limits
|
|
FIREFOX_MAX_TABS={self.browser_entries['firefox_max_tabs'].get()}
|
|
CHROME_MAX_TABS={self.browser_entries['chrome_max_tabs'].get()}
|
|
EDGE_MAX_TABS={self.browser_entries['edge_max_tabs'].get()}
|
|
|
|
# Notification Settings
|
|
NOTIFICATION_TIMEOUT={self.notification_timeout.get()}
|
|
"""
|
|
|
|
# Write to temporary file first
|
|
temp_file = "/tmp/pc-monitor.conf"
|
|
with open(temp_file, 'w') as f:
|
|
f.write(config_content)
|
|
|
|
# Copy to system location with sudo
|
|
result = subprocess.run(['sudo', 'cp', temp_file, self.config_file],
|
|
capture_output=True, text=True)
|
|
|
|
if result.returncode == 0:
|
|
messagebox.showinfo("Success", "Configuration saved successfully!")
|
|
# Restart service to apply changes
|
|
self.restart_service()
|
|
else:
|
|
messagebox.showerror("Error", f"Failed to save configuration: {result.stderr}")
|
|
|
|
except Exception as e:
|
|
messagebox.showerror("Error", f"Failed to save configuration: {e}")
|
|
|
|
def reset_to_defaults(self):
|
|
"""Reset all settings to default values"""
|
|
if messagebox.askyesno("Confirm Reset", "Reset all settings to default values?"):
|
|
for key, value in self.default_config.items():
|
|
if key in ['CPU_THRESHOLD', 'MEMORY_THRESHOLD', 'TEMP_THRESHOLD', 'DISK_THRESHOLD']:
|
|
getattr(self, key.lower()).set(float(value))
|
|
elif key == 'AGGRESSIVE_ON_BROWSERS':
|
|
self.aggressive_browsers.set(value.lower() == 'true')
|
|
elif hasattr(self, key.lower()):
|
|
widget = getattr(self, key.lower())
|
|
if hasattr(widget, 'set'):
|
|
widget.set(float(value))
|
|
elif hasattr(widget, 'delete'):
|
|
widget.delete(0, tk.END)
|
|
widget.insert(0, value)
|
|
|
|
def export_config(self):
|
|
"""Export configuration to JSON file"""
|
|
filename = filedialog.asksaveasfilename(
|
|
defaultextension=".json",
|
|
filetypes=[("JSON files", "*.json"), ("All files", "*.*")]
|
|
)
|
|
if filename:
|
|
try:
|
|
config_data = {}
|
|
# Collect all configuration values
|
|
config_data['CPU_THRESHOLD'] = int(self.cpu_threshold.get())
|
|
config_data['MEMORY_THRESHOLD'] = int(self.memory_threshold.get())
|
|
config_data['TEMP_THRESHOLD'] = int(self.temp_threshold.get())
|
|
config_data['DISK_THRESHOLD'] = int(self.disk_threshold.get())
|
|
config_data['AGGRESSIVE_ON_BROWSERS'] = self.aggressive_browsers.get()
|
|
config_data['AGGRESSIVE_CPU_THRESHOLD'] = int(self.aggressive_cpu_threshold.get())
|
|
config_data['AGGRESSIVE_MEMORY_THRESHOLD'] = int(self.aggressive_memory_threshold.get())
|
|
config_data['NETWORK_THRESHOLD'] = self.network_threshold.get()
|
|
config_data['IO_THRESHOLD'] = self.io_threshold.get()
|
|
config_data['PROCESS_HANG_TIME'] = self.process_hang_time.get()
|
|
config_data['SWAP_THRESHOLD'] = self.swap_threshold.get()
|
|
config_data['LOAD_AVG_THRESHOLD'] = self.load_avg_threshold.get()
|
|
config_data['FIREFOX_MAX_TABS'] = self.browser_entries['firefox_max_tabs'].get()
|
|
config_data['CHROME_MAX_TABS'] = self.browser_entries['chrome_max_tabs'].get()
|
|
config_data['EDGE_MAX_TABS'] = self.browser_entries['edge_max_tabs'].get()
|
|
config_data['BROWSER_CPU_THRESHOLD'] = int(self.browser_cpu_threshold.get())
|
|
config_data['BROWSER_MEMORY_THRESHOLD'] = int(self.browser_memory_threshold.get())
|
|
config_data['BROWSER_TAB_LIMIT'] = self.browser_tab_limit.get()
|
|
config_data['GAME_CPU_THRESHOLD'] = int(self.game_cpu_threshold.get())
|
|
config_data['GAME_MEMORY_THRESHOLD'] = int(self.game_memory_threshold.get())
|
|
config_data['IDE_MEMORY_THRESHOLD'] = int(self.ide_memory_threshold.get())
|
|
config_data['NOTIFICATION_TIMEOUT'] = self.notification_timeout.get()
|
|
|
|
with open(filename, 'w') as f:
|
|
json.dump(config_data, f, indent=2)
|
|
|
|
messagebox.showinfo("Success", f"Configuration exported to {filename}")
|
|
except Exception as e:
|
|
messagebox.showerror("Error", f"Failed to export configuration: {e}")
|
|
|
|
def import_config(self):
|
|
"""Import configuration from JSON file"""
|
|
filename = filedialog.askopenfilename(
|
|
filetypes=[("JSON files", "*.json"), ("All files", "*.*")]
|
|
)
|
|
if filename:
|
|
try:
|
|
with open(filename, 'r') as f:
|
|
config_data = json.load(f)
|
|
|
|
# Update GUI with imported values
|
|
for key, value in config_data.items():
|
|
if key in ['CPU_THRESHOLD', 'MEMORY_THRESHOLD', 'TEMP_THRESHOLD', 'DISK_THRESHOLD']:
|
|
getattr(self, key.lower()).set(float(value))
|
|
elif key == 'AGGRESSIVE_ON_BROWSERS':
|
|
self.aggressive_browsers.set(bool(value))
|
|
elif hasattr(self, key.lower()):
|
|
widget = getattr(self, key.lower())
|
|
if hasattr(widget, 'set'):
|
|
widget.set(float(value))
|
|
elif hasattr(widget, 'delete'):
|
|
widget.delete(0, tk.END)
|
|
widget.insert(0, str(value))
|
|
|
|
messagebox.showinfo("Success", f"Configuration imported from {filename}")
|
|
except Exception as e:
|
|
messagebox.showerror("Error", f"Failed to import configuration: {e}")
|
|
|
|
def update_service_status(self):
|
|
"""Update service status display"""
|
|
try:
|
|
result = subprocess.run(['systemctl', 'is-active', self.service_name],
|
|
capture_output=True, text=True)
|
|
if result.returncode == 0:
|
|
status = "🟢 Active"
|
|
color = "green"
|
|
else:
|
|
status = "🔴 Inactive"
|
|
color = "red"
|
|
|
|
self.service_status_label.config(text=f"Status: {status}", foreground=color)
|
|
except Exception:
|
|
self.service_status_label.config(text="Status: Unknown", foreground="orange")
|
|
|
|
def start_service(self):
|
|
"""Start the monitoring service"""
|
|
try:
|
|
result = subprocess.run(['sudo', 'systemctl', 'start', self.service_name],
|
|
capture_output=True, text=True)
|
|
if result.returncode == 0:
|
|
messagebox.showinfo("Success", "Service started successfully!")
|
|
else:
|
|
messagebox.showerror("Error", f"Failed to start service: {result.stderr}")
|
|
self.update_service_status()
|
|
except Exception as e:
|
|
messagebox.showerror("Error", f"Failed to start service: {e}")
|
|
|
|
def stop_service(self):
|
|
"""Stop the monitoring service"""
|
|
try:
|
|
result = subprocess.run(['sudo', 'systemctl', 'stop', self.service_name],
|
|
capture_output=True, text=True)
|
|
if result.returncode == 0:
|
|
messagebox.showinfo("Success", "Service stopped successfully!")
|
|
else:
|
|
messagebox.showerror("Error", f"Failed to stop service: {result.stderr}")
|
|
self.update_service_status()
|
|
except Exception as e:
|
|
messagebox.showerror("Error", f"Failed to stop service: {e}")
|
|
|
|
def restart_service(self):
|
|
"""Restart the monitoring service"""
|
|
try:
|
|
result = subprocess.run(['sudo', 'systemctl', 'restart', self.service_name],
|
|
capture_output=True, text=True)
|
|
if result.returncode == 0:
|
|
messagebox.showinfo("Success", "Service restarted successfully!")
|
|
else:
|
|
messagebox.showerror("Error", f"Failed to restart service: {result.stderr}")
|
|
self.update_service_status()
|
|
except Exception as e:
|
|
messagebox.showerror("Error", f"Failed to restart service: {e}")
|
|
|
|
def enable_service(self):
|
|
"""Enable service auto-start"""
|
|
try:
|
|
result = subprocess.run(['sudo', 'systemctl', 'enable', self.service_name],
|
|
capture_output=True, text=True)
|
|
if result.returncode == 0:
|
|
messagebox.showinfo("Success", "Service auto-start enabled!")
|
|
else:
|
|
messagebox.showerror("Error", f"Failed to enable service: {result.stderr}")
|
|
except Exception as e:
|
|
messagebox.showerror("Error", f"Failed to enable service: {e}")
|
|
|
|
def disable_service(self):
|
|
"""Disable service auto-start"""
|
|
try:
|
|
result = subprocess.run(['sudo', 'systemctl', 'disable', self.service_name],
|
|
capture_output=True, text=True)
|
|
if result.returncode == 0:
|
|
messagebox.showinfo("Success", "Service auto-start disabled!")
|
|
else:
|
|
messagebox.showerror("Error", f"Failed to disable service: {result.stderr}")
|
|
except Exception as e:
|
|
messagebox.showerror("Error", f"Failed to disable service: {e}")
|
|
|
|
def install_service(self):
|
|
"""Install or reinstall the service"""
|
|
try:
|
|
# Run the installation script
|
|
script_path = os.path.join(os.path.dirname(__file__), 'install.sh')
|
|
if os.path.exists(script_path):
|
|
result = subprocess.run(['sudo', 'bash', script_path],
|
|
capture_output=True, text=True)
|
|
if result.returncode == 0:
|
|
messagebox.showinfo("Success", "Service installed successfully!")
|
|
else:
|
|
messagebox.showerror("Error", f"Installation failed: {result.stderr}")
|
|
else:
|
|
messagebox.showerror("Error", "Installation script not found!")
|
|
self.update_service_status()
|
|
except Exception as e:
|
|
messagebox.showerror("Error", f"Failed to install service: {e}")
|
|
|
|
def uninstall_service(self):
|
|
"""Uninstall the service"""
|
|
if messagebox.askyesno("Confirm Uninstall", "Are you sure you want to uninstall the PC Monitor service?"):
|
|
try:
|
|
# Stop and disable service
|
|
subprocess.run(['sudo', 'systemctl', 'stop', self.service_name], capture_output=True)
|
|
subprocess.run(['sudo', 'systemctl', 'disable', self.service_name], capture_output=True)
|
|
|
|
# Remove service file
|
|
subprocess.run(['sudo', 'rm', '-f', f'/etc/systemd/system/{self.service_name}.service'],
|
|
capture_output=True)
|
|
|
|
# Remove configuration file
|
|
subprocess.run(['sudo', 'rm', '-f', self.config_file], capture_output=True)
|
|
|
|
# Remove executable
|
|
subprocess.run(['sudo', 'rm', '-f', '/usr/local/bin/pc-monitor'], capture_output=True)
|
|
|
|
# Reload systemd
|
|
subprocess.run(['sudo', 'systemctl', 'daemon-reload'], capture_output=True)
|
|
|
|
messagebox.showinfo("Success", "Service uninstalled successfully!")
|
|
self.update_service_status()
|
|
except Exception as e:
|
|
messagebox.showerror("Error", f"Failed to uninstall service: {e}")
|
|
|
|
def test_notification(self):
|
|
"""Test desktop notification"""
|
|
try:
|
|
subprocess.run(['notify-send', '--urgency=normal', '--expire-time=3000',
|
|
'PC Monitor GUI', 'Test notification from PC Monitor settings'],
|
|
capture_output=True)
|
|
messagebox.showinfo("Success", "Test notification sent!")
|
|
except Exception as e:
|
|
messagebox.showerror("Error", f"Failed to send notification: {e}")
|
|
|
|
def update_system_status(self):
|
|
"""Update system status display"""
|
|
try:
|
|
# Get system information
|
|
cpu_info = subprocess.run(['top', '-bn1'], capture_output=True, text=True)
|
|
memory_info = subprocess.run(['free', '-h'], capture_output=True, text=True)
|
|
disk_info = subprocess.run(['df', '-h', '/'], capture_output=True, text=True)
|
|
temp_info = subprocess.run(['sensors'], capture_output=True, text=True)
|
|
|
|
status_text = "=== SYSTEM STATUS ===\n\n"
|
|
|
|
# CPU usage
|
|
if cpu_info.returncode == 0:
|
|
for line in cpu_info.stdout.split('\n'):
|
|
if 'Cpu(s)' in line:
|
|
status_text += f"CPU: {line}\n"
|
|
break
|
|
|
|
# Memory usage
|
|
if memory_info.returncode == 0:
|
|
lines = memory_info.stdout.split('\n')
|
|
if len(lines) > 1:
|
|
status_text += f"Memory: {lines[1]}\n"
|
|
|
|
# Disk usage
|
|
if disk_info.returncode == 0:
|
|
lines = disk_info.stdout.split('\n')
|
|
if len(lines) > 1:
|
|
status_text += f"Disk: {lines[1]}\n"
|
|
|
|
# Temperature
|
|
if temp_info.returncode == 0:
|
|
status_text += f"\nTemperatures:\n{temp_info.stdout[:200]}...\n"
|
|
|
|
self.status_text.delete(1.0, tk.END)
|
|
self.status_text.insert(1.0, status_text)
|
|
|
|
except Exception as e:
|
|
self.status_text.delete(1.0, tk.END)
|
|
self.status_text.insert(1.0, f"Error updating status: {e}")
|
|
|
|
def update_logs(self):
|
|
"""Update log display"""
|
|
try:
|
|
# Get recent logs
|
|
result = subprocess.run(['sudo', 'tail', '-50', '/var/log/pc-monitor.log'],
|
|
capture_output=True, text=True)
|
|
|
|
if result.returncode == 0:
|
|
self.log_text.delete(1.0, tk.END)
|
|
self.log_text.insert(1.0, result.stdout)
|
|
else:
|
|
self.log_text.delete(1.0, tk.END)
|
|
self.log_text.insert(1.0, "Log file not found or inaccessible")
|
|
|
|
except Exception as e:
|
|
self.log_text.delete(1.0, tk.END)
|
|
self.log_text.insert(1.0, f"Error reading logs: {e}")
|
|
|
|
def auto_refresh_status(self):
|
|
"""Auto-refresh service status"""
|
|
self.update_service_status()
|
|
self.root.after(5000, self.auto_refresh_status) # Refresh every 5 seconds
|
|
|
|
def main():
|
|
root = tk.Tk()
|
|
app = PCMonitorGUI(root)
|
|
root.mainloop()
|
|
|
|
if __name__ == "__main__":
|
|
main() |