Files
Scripts/pc-monitor-gui.py
Wiktor Olszewski 2c0000079b Add PC Anti-Freeze Monitor with enhanced features
- 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
2025-07-01 19:51:06 +02:00

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()