-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathmonitor_control_tk.py
More file actions
107 lines (87 loc) · 3.95 KB
/
Copy pathmonitor_control_tk.py
File metadata and controls
107 lines (87 loc) · 3.95 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
#!/usr/bin/env python3
import tkinter as tk
from tkinter import ttk, messagebox
import subprocess
class FlexibleMonitorControl:
def __init__(self, root):
self.root = root
self.root.title("Monitor Control")
self.root.geometry("350x400")
self.monitors = [] # List of (display_index, model_name)
# UI Components
tk.Label(root, text="Monitor Control", font=("Arial", 14, "bold")).pack(pady=10)
# Monitor Selector
tk.Label(root, text="Select Display:").pack()
self.monitor_selector = ttk.Combobox(root, state="readonly", width=30)
self.monitor_selector.pack(pady=5)
# Sliders
self.bright_slider = self.create_slider("Brightness", 10)
self.cont_slider = self.create_slider("Contrast", 12)
# Buttons
tk.Button(root, text="Apply All Settings", command=self.apply_settings,
bg="#2196F3", fg="white", height=2).pack(pady=20, fill="x", padx=40)
tk.Button(root, text="Rescan Monitors", command=self.detect_monitors).pack()
# Initial Run
self.detect_monitors()
def create_slider(self, label, code):
tk.Label(self.root, text=label).pack(pady=(10,0))
slider = tk.Scale(self.root, from_=0, to=100, orient="horizontal", length=250)
slider.pack()
return slider
def detect_monitors(self):
"""A more robust way to find displays by looking for the 'Display' keyword."""
self.monitors = []
try:
# We use standard output here because terse can be finicky
output = subprocess.check_output(["ddcutil", "detect"]).decode()
# Simple line-by-line parsing
current_idx = None
for line in output.splitlines():
line = line.strip()
if line.startswith("Display"):
# Extract the number after "Display"
parts = line.split()
if len(parts) >= 2:
current_idx = parts[1]
if "Model:" in line and current_idx:
model = line.split("Model:")[1].strip()
self.monitors.append((current_idx, model))
current_idx = None # Reset for next display
if not self.monitors:
# FALLBACK: If detection fails, assume at least one display exists
self.monitors = [("1", "Default Display")]
self.monitor_selector['values'] = [f"{m[0]}: {m[1]}" for m in self.monitors]
self.monitor_selector.current(0)
self.sync_sliders()
except Exception as e:
messagebox.showerror("Error", f"Detection failed: {e}")
def sync_sliders(self):
"""Update sliders with current hardware values."""
display_id = self.get_selected_id()
self.bright_slider.set(self.get_vcp_value(display_id, "10"))
self.cont_slider.set(self.get_vcp_value(display_id, "12"))
def get_selected_id(self):
selection = self.monitor_selector.get()
return selection.split(":")[0] if selection else "1"
def get_vcp_value(self, display_id, code):
try:
output = subprocess.check_output(
["ddcutil", "getvcp", code, "--display", display_id, "--terse"]
).decode().split()
return int(output[3])
except:
return 50 # Default if read fails
def apply_settings(self):
display_id = self.get_selected_id()
b_val = self.bright_slider.get()
c_val = self.cont_slider.get()
try:
# Apply both settings
subprocess.run(["ddcutil", "setvcp", "10", str(b_val), "--display", display_id])
subprocess.run(["ddcutil", "setvcp", "12", str(c_val), "--display", display_id])
except Exception as e:
messagebox.showerror("Error", f"Failed to apply: {e}")
if __name__ == "__main__":
root = tk.Tk()
app = FlexibleMonitorControl(root)
root.mainloop()