1188 lines
47 KiB
Python
1188 lines
47 KiB
Python
import json
|
|
import os
|
|
import subprocess
|
|
import threading
|
|
import time
|
|
|
|
import gi
|
|
from fabric.widgets.box import Box
|
|
from fabric.widgets.button import Button
|
|
from fabric.widgets.entry import Entry
|
|
from fabric.widgets.image import Image as FabricImage
|
|
from fabric.widgets.label import Label
|
|
from fabric.widgets.scrolledwindow import ScrolledWindow
|
|
from fabric.widgets.stack import Stack
|
|
from fabric.widgets.window import Window
|
|
from gi.repository import GdkPixbuf, GLib, Gtk
|
|
from PIL import Image
|
|
|
|
from config.data import APP_NAME, APP_NAME_CAP, NOTIF_POS_DEFAULT, NOTIF_POS_KEY
|
|
from config.settings.utils import backup_and_replace, bind_vars, start_config
|
|
|
|
gi.require_version("Gtk", "3.0")
|
|
|
|
|
|
class HyprConfGUI(Window):
|
|
def __init__(self, show_lock_checkbox: bool, show_idle_checkbox: bool, **kwargs):
|
|
super().__init__(
|
|
title="Modus Settings",
|
|
name="modus-settings-window",
|
|
size=(640, 640),
|
|
**kwargs,
|
|
)
|
|
|
|
self.set_resizable(False)
|
|
self.themes = ["Pills", "Dense", "Edge"]
|
|
self.selected_face_icon = None
|
|
self.show_lock_checkbox = show_lock_checkbox
|
|
self.show_idle_checkbox = show_idle_checkbox
|
|
|
|
root_box = Box(orientation="v", spacing=10, style="margin: 10px;")
|
|
self.add(root_box)
|
|
|
|
main_content_box = Box(orientation="h", spacing=6, v_expand=True, h_expand=True)
|
|
root_box.add(main_content_box)
|
|
|
|
self.tab_stack = Stack(
|
|
transition_type="slide-up-down",
|
|
transition_duration=250,
|
|
v_expand=True,
|
|
h_expand=True,
|
|
)
|
|
|
|
self.key_bindings_tab_content = self.create_key_bindings_tab()
|
|
self.appearance_tab_content = self.create_appearance_tab()
|
|
self.system_tab_content = self.create_system_tab()
|
|
self.about_tab_content = self.create_about_tab()
|
|
|
|
self.tab_stack.add_titled(
|
|
self.key_bindings_tab_content, "key_bindings", "Key Bindings"
|
|
)
|
|
self.tab_stack.add_titled(
|
|
self.appearance_tab_content, "appearance", "Appearance"
|
|
)
|
|
self.tab_stack.add_titled(self.system_tab_content, "system", "System")
|
|
self.tab_stack.add_titled(self.about_tab_content, "about", "About")
|
|
|
|
tab_switcher = Gtk.StackSwitcher()
|
|
tab_switcher.set_stack(self.tab_stack)
|
|
tab_switcher.set_orientation(Gtk.Orientation.VERTICAL)
|
|
main_content_box.add(tab_switcher)
|
|
main_content_box.add(self.tab_stack)
|
|
|
|
button_box = Box(orientation="h", spacing=10, h_align="end")
|
|
reset_btn = Button(label="Reset to Defaults", on_clicked=self.on_reset)
|
|
button_box.add(reset_btn)
|
|
close_btn = Button(label="Close", on_clicked=self.on_close)
|
|
button_box.add(close_btn)
|
|
accept_btn = Button(label="Apply & Reload", on_clicked=self.on_accept)
|
|
button_box.add(accept_btn)
|
|
root_box.add(button_box)
|
|
|
|
def create_key_bindings_tab(self):
|
|
scrolled_window = ScrolledWindow(
|
|
h_scrollbar_policy="never",
|
|
v_scrollbar_policy="automatic",
|
|
h_expand=True,
|
|
v_expand=True,
|
|
propagate_width=False,
|
|
propagate_height=False,
|
|
)
|
|
|
|
main_vbox = Box(orientation="v", spacing=10, style="margin: 15px;")
|
|
scrolled_window.add(main_vbox)
|
|
|
|
keybind_grid = Gtk.Grid()
|
|
keybind_grid.set_column_spacing(10)
|
|
keybind_grid.set_row_spacing(8)
|
|
keybind_grid.set_margin_start(5)
|
|
keybind_grid.set_margin_end(5)
|
|
keybind_grid.set_margin_top(5)
|
|
keybind_grid.set_margin_bottom(5)
|
|
|
|
action_label = Label(
|
|
markup="<b>Action</b>", h_align="start", style="margin-bottom: 5px;"
|
|
)
|
|
modifier_label = Label(
|
|
markup="<b>Modifier</b>", h_align="start", style="margin-bottom: 5px;"
|
|
)
|
|
separator_label = Label(
|
|
label="+", h_align="center", style="margin-bottom: 5px;"
|
|
)
|
|
key_label = Label(
|
|
markup="<b>Key</b>", h_align="start", style="margin-bottom: 5px;"
|
|
)
|
|
|
|
keybind_grid.attach(action_label, 0, 0, 1, 1)
|
|
keybind_grid.attach(modifier_label, 1, 0, 1, 1)
|
|
keybind_grid.attach(separator_label, 2, 0, 1, 1)
|
|
keybind_grid.attach(key_label, 3, 0, 1, 1)
|
|
|
|
self.entries = []
|
|
bindings = [
|
|
(f"Reload {APP_NAME_CAP}", "prefix_restart", "suffix_restart"),
|
|
("Message", "prefix_msg", "suffix_msg"),
|
|
(
|
|
"Application Switcher",
|
|
"prefix_application_switcher",
|
|
"suffix_application_switcher",
|
|
),
|
|
("Launcher", "prefix_launcher", "suffix_launcher"),
|
|
("App Launcher", "prefix_app_launcher", "suffix_app_launcher"),
|
|
("Clipboard History", "prefix_cliphist", "suffix_cliphist"),
|
|
("Wallpapers", "prefix_wallpapers", "suffix_wallpapers"),
|
|
("Random Wallpaper", "prefix_randwall", "suffix_randwall"),
|
|
("Emoji Picker", "prefix_emoji", "suffix_emoji"),
|
|
("Kanban", "prefix_kanban", "suffix_kanban"),
|
|
("Power Menu", "prefix_power", "suffix_power"),
|
|
("Toggle Caffeine", "prefix_caffeine", "suffix_caffeine"),
|
|
("Settings", "prefix_settings", "suffix_settings"),
|
|
(
|
|
"Restart with inspector",
|
|
"prefix_restart_inspector",
|
|
"suffix_restart_inspector",
|
|
),
|
|
]
|
|
|
|
for i, (label_text, prefix_key, suffix_key) in enumerate(bindings):
|
|
row = i + 1
|
|
binding_label = Label(label=label_text, h_align="start")
|
|
keybind_grid.attach(binding_label, 0, row, 1, 1)
|
|
prefix_entry = Entry(text=bind_vars.get(prefix_key, ""))
|
|
keybind_grid.attach(prefix_entry, 1, row, 1, 1)
|
|
plus_label = Label(label="+", h_align="center")
|
|
keybind_grid.attach(plus_label, 2, row, 1, 1)
|
|
suffix_entry = Entry(text=bind_vars.get(suffix_key, ""))
|
|
keybind_grid.attach(suffix_entry, 3, row, 1, 1)
|
|
self.entries.append((prefix_key, suffix_key, prefix_entry, suffix_entry))
|
|
|
|
main_vbox.add(keybind_grid)
|
|
return scrolled_window
|
|
|
|
def create_appearance_tab(self):
|
|
scrolled_window = ScrolledWindow(
|
|
h_scrollbar_policy="never",
|
|
v_scrollbar_policy="automatic",
|
|
h_expand=True,
|
|
v_expand=True,
|
|
propagate_width=False,
|
|
propagate_height=False,
|
|
)
|
|
|
|
vbox = Box(orientation="v", spacing=15, style="margin: 15px;")
|
|
scrolled_window.add(vbox)
|
|
|
|
top_grid = Gtk.Grid()
|
|
top_grid.set_column_spacing(20)
|
|
top_grid.set_row_spacing(5)
|
|
top_grid.set_margin_bottom(10)
|
|
vbox.add(top_grid)
|
|
|
|
wall_header = Label(markup="<b>Wallpapers</b>", h_align="start")
|
|
top_grid.attach(wall_header, 0, 0, 1, 1)
|
|
wall_label = Label(label="Directory:", h_align="start", v_align="center")
|
|
top_grid.attach(wall_label, 0, 1, 1, 1)
|
|
|
|
chooser_container = Gtk.Box(orientation=Gtk.Orientation.HORIZONTAL)
|
|
chooser_container.set_halign(Gtk.Align.START)
|
|
chooser_container.set_valign(Gtk.Align.CENTER)
|
|
self.wall_dir_chooser = Gtk.FileChooserButton(
|
|
title="Select a folder", action=Gtk.FileChooserAction.SELECT_FOLDER
|
|
)
|
|
self.wall_dir_chooser.set_tooltip_text(
|
|
"Select the directory containing your wallpaper images"
|
|
)
|
|
self.wall_dir_chooser.set_filename(bind_vars.get("wallpapers_dir", ""))
|
|
self.wall_dir_chooser.set_size_request(180, -1)
|
|
chooser_container.add(self.wall_dir_chooser)
|
|
top_grid.attach(chooser_container, 1, 1, 1, 1)
|
|
|
|
face_header = Label(markup="<b>Profile Icon</b>", h_align="start")
|
|
top_grid.attach(face_header, 2, 0, 2, 1)
|
|
current_face = os.path.expanduser("~/.face.icon")
|
|
face_image_container = Box(
|
|
style_classes=["image-frame"], h_align="center", v_align="center"
|
|
)
|
|
self.face_image = FabricImage(size=64)
|
|
try:
|
|
if os.path.exists(current_face):
|
|
pixbuf = GdkPixbuf.Pixbuf.new_from_file_at_size(current_face, 64, 64)
|
|
self.face_image.set_from_pixbuf(pixbuf)
|
|
else:
|
|
self.face_image.set_from_icon_name("user-info", Gtk.IconSize.DIALOG)
|
|
except Exception as e:
|
|
print(f"Error loading face icon: {e}")
|
|
self.face_image.set_from_icon_name("image-missing", Gtk.IconSize.DIALOG)
|
|
face_image_container.add(self.face_image)
|
|
top_grid.attach(face_image_container, 2, 1, 1, 1)
|
|
|
|
browse_btn_container = Gtk.Box(orientation=Gtk.Orientation.HORIZONTAL)
|
|
browse_btn_container.set_halign(Gtk.Align.START)
|
|
browse_btn_container.set_valign(Gtk.Align.CENTER)
|
|
face_btn = Button(
|
|
label="Browse...",
|
|
tooltip_text="Select a square image for your profile icon",
|
|
on_clicked=self.on_select_face_icon,
|
|
)
|
|
browse_btn_container.add(face_btn)
|
|
top_grid.attach(browse_btn_container, 3, 1, 1, 1)
|
|
self.face_status_label = Label(label="", h_align="start")
|
|
top_grid.attach(self.face_status_label, 2, 2, 2, 1)
|
|
|
|
separator1 = Box(
|
|
style="min-height: 1px; background-color: alpha(@fg_color, 0.2); margin: 5px 0px;",
|
|
h_expand=True,
|
|
)
|
|
vbox.add(separator1)
|
|
|
|
layout_header = Label(markup="<b>Layout Options</b>", h_align="start")
|
|
vbox.add(layout_header)
|
|
layout_grid = Gtk.Grid()
|
|
layout_grid.set_column_spacing(20)
|
|
layout_grid.set_row_spacing(10)
|
|
layout_grid.set_margin_start(10)
|
|
layout_grid.set_margin_top(5)
|
|
vbox.add(layout_grid)
|
|
|
|
# Workspace mode
|
|
ws_mode_label = Label(label="Workspace Mode", h_align="start", v_align="center")
|
|
layout_grid.attach(ws_mode_label, 0, 0, 1, 1)
|
|
|
|
ws_mode_combo_container = Gtk.Box(
|
|
orientation=Gtk.Orientation.HORIZONTAL,
|
|
halign=Gtk.Align.START,
|
|
valign=Gtk.Align.CENTER,
|
|
)
|
|
self.ws_mode_combo = Gtk.ComboBoxText()
|
|
self.ws_mode_combo.set_tooltip_text("Select how workspaces are displayed")
|
|
ws_modes = ["Dots", "Numbers", "Single Button"]
|
|
for mode in ws_modes:
|
|
self.ws_mode_combo.append_text(mode)
|
|
|
|
# Set current mode based on config
|
|
current_dots = bind_vars.get("workspace_dots", True)
|
|
current_nums = bind_vars.get("workspace_nums", False)
|
|
if current_dots:
|
|
current_mode = "Dots"
|
|
elif current_nums:
|
|
current_mode = "Numbers"
|
|
else:
|
|
current_mode = "Single Button"
|
|
|
|
try:
|
|
self.ws_mode_combo.set_active(ws_modes.index(current_mode))
|
|
except ValueError:
|
|
self.ws_mode_combo.set_active(0)
|
|
|
|
self.ws_mode_combo.connect("changed", self.on_ws_mode_changed)
|
|
ws_mode_combo_container.add(self.ws_mode_combo)
|
|
layout_grid.attach(ws_mode_combo_container, 1, 0, 1, 1)
|
|
|
|
# Chinese numerals option
|
|
ws_chinese_label = Label(
|
|
label="Use Chinese Numerals", h_align="start", v_align="center"
|
|
)
|
|
layout_grid.attach(ws_chinese_label, 2, 0, 1, 1)
|
|
ws_chinese_switch_container = Gtk.Box(
|
|
orientation=Gtk.Orientation.HORIZONTAL,
|
|
halign=Gtk.Align.START,
|
|
valign=Gtk.Align.CENTER,
|
|
)
|
|
self.ws_chinese_switch = Gtk.Switch(
|
|
active=bind_vars.get("workspace_use_chinese_numerals", False),
|
|
sensitive=current_nums, # Only enabled when numbers mode is selected
|
|
)
|
|
self.ws_chinese_switch.set_tooltip_text(
|
|
"Use Chinese numerals (一, 二, 三...) instead of Arabic numbers"
|
|
)
|
|
ws_chinese_switch_container.add(self.ws_chinese_switch)
|
|
layout_grid.attach(ws_chinese_switch_container, 3, 0, 1, 1)
|
|
|
|
position_label = Label(label="Dock Position", h_align="start", v_align="center")
|
|
layout_grid.attach(position_label, 0, 1, 1, 1)
|
|
position_combo_container = Gtk.Box(
|
|
orientation=Gtk.Orientation.HORIZONTAL,
|
|
halign=Gtk.Align.START,
|
|
valign=Gtk.Align.CENTER,
|
|
)
|
|
self.position_combo = Gtk.ComboBoxText()
|
|
self.position_combo.set_tooltip_text("Select the position of the dock")
|
|
positions = ["Bottom", "Left", "Right"]
|
|
for pos in positions:
|
|
self.position_combo.append_text(pos)
|
|
current_position = bind_vars.get("dock_position", "Bottom")
|
|
try:
|
|
self.position_combo.set_active(positions.index(current_position))
|
|
except ValueError:
|
|
self.position_combo.set_active(0)
|
|
self.position_combo.connect("changed", self.on_position_changed)
|
|
position_combo_container.add(self.position_combo)
|
|
layout_grid.attach(position_combo_container, 1, 1, 1, 1)
|
|
|
|
dock_theme_label = Label(label="Dock Theme", h_align="start", v_align="center")
|
|
layout_grid.attach(dock_theme_label, 2, 1, 1, 1)
|
|
dock_theme_combo_container = Gtk.Box(
|
|
orientation=Gtk.Orientation.HORIZONTAL,
|
|
halign=Gtk.Align.START,
|
|
valign=Gtk.Align.CENTER,
|
|
)
|
|
self.dock_theme_combo = Gtk.ComboBoxText()
|
|
self.dock_theme_combo.set_tooltip_text("Select the visual theme for the dock")
|
|
for theme in self.themes:
|
|
self.dock_theme_combo.append_text(theme)
|
|
current_dock_theme = bind_vars.get("dock_theme", "Pills")
|
|
try:
|
|
self.dock_theme_combo.set_active(self.themes.index(current_dock_theme))
|
|
except ValueError:
|
|
self.dock_theme_combo.set_active(0)
|
|
dock_theme_combo_container.add(self.dock_theme_combo)
|
|
layout_grid.attach(dock_theme_combo_container, 3, 1, 1, 1)
|
|
|
|
# Add icon size scale
|
|
icon_size_label = Label(
|
|
label="Taskbar Icon Size", h_align="start", v_align="center"
|
|
)
|
|
layout_grid.attach(icon_size_label, 0, 4, 1, 1)
|
|
|
|
icon_size_scale_container = Gtk.Box(
|
|
orientation=Gtk.Orientation.HORIZONTAL,
|
|
halign=Gtk.Align.START,
|
|
valign=Gtk.Align.CENTER,
|
|
hexpand=True,
|
|
)
|
|
|
|
self.icon_size_scale = Gtk.Scale.new_with_range(
|
|
Gtk.Orientation.HORIZONTAL, 20, 30, 2
|
|
)
|
|
self.icon_size_scale.set_value(bind_vars.get("dock_icon_size", 20))
|
|
self.icon_size_scale.set_size_request(150, -1)
|
|
self.icon_size_scale.set_draw_value(True)
|
|
self.icon_size_scale.set_value_pos(Gtk.PositionType.RIGHT)
|
|
self.icon_size_scale.set_tooltip_text("Adjust the size of dock icons")
|
|
|
|
icon_size_scale_container.add(self.icon_size_scale)
|
|
layout_grid.attach(icon_size_scale_container, 1, 4, 1, 1)
|
|
|
|
# Add application switcher items scale
|
|
application_switcher_label = Label(
|
|
label="Application Switcher Items", h_align="start", v_align="center"
|
|
)
|
|
layout_grid.attach(application_switcher_label, 2, 4, 1, 1)
|
|
|
|
application_switcher_scale_container = Gtk.Box(
|
|
orientation=Gtk.Orientation.HORIZONTAL,
|
|
halign=Gtk.Align.START,
|
|
valign=Gtk.Align.CENTER,
|
|
hexpand=True,
|
|
)
|
|
|
|
self.application_switcher_scale = Gtk.Scale.new_with_range(
|
|
Gtk.Orientation.HORIZONTAL, 5, 20, 1
|
|
)
|
|
self.application_switcher_scale.set_value(
|
|
bind_vars.get("window_switcher_items_per_row", 13)
|
|
)
|
|
self.application_switcher_scale.set_size_request(150, -1)
|
|
self.application_switcher_scale.set_draw_value(True)
|
|
self.application_switcher_scale.set_value_pos(Gtk.PositionType.RIGHT)
|
|
self.application_switcher_scale.set_tooltip_text(
|
|
"Adjust the number of items per row in the application switcher"
|
|
)
|
|
|
|
application_switcher_scale_container.add(self.application_switcher_scale)
|
|
layout_grid.attach(application_switcher_scale_container, 3, 4, 1, 1)
|
|
|
|
dock_label = Label(label="Show Dock", h_align="start", v_align="center")
|
|
layout_grid.attach(dock_label, 0, 2, 1, 1)
|
|
dock_switch_container = Gtk.Box(
|
|
orientation=Gtk.Orientation.HORIZONTAL,
|
|
halign=Gtk.Align.START,
|
|
valign=Gtk.Align.CENTER,
|
|
)
|
|
self.dock_switch = Gtk.Switch(active=bind_vars.get("dock_enabled", True))
|
|
self.dock_switch.connect("notify::active", self.on_dock_enabled_changed)
|
|
dock_switch_container.add(self.dock_switch)
|
|
layout_grid.attach(dock_switch_container, 1, 2, 1, 1)
|
|
|
|
dock_auto_hide_label = Label(
|
|
label="Auto-hide Dock", h_align="start", v_align="center"
|
|
)
|
|
layout_grid.attach(dock_auto_hide_label, 0, 3, 1, 1)
|
|
dock_auto_hide_switch_container = Gtk.Box(
|
|
orientation=Gtk.Orientation.HORIZONTAL,
|
|
halign=Gtk.Align.START,
|
|
valign=Gtk.Align.CENTER,
|
|
)
|
|
self.dock_auto_hide_switch = Gtk.Switch(
|
|
active=bind_vars.get("dock_auto_hide", False),
|
|
sensitive=self.dock_switch.get_active(),
|
|
)
|
|
dock_auto_hide_switch_container.add(self.dock_auto_hide_switch)
|
|
layout_grid.attach(dock_auto_hide_switch_container, 1, 3, 1, 1)
|
|
|
|
dock_hover_label = Label(
|
|
label="Show Dock Only on Hover", h_align="start", v_align="center"
|
|
)
|
|
layout_grid.attach(dock_hover_label, 2, 2, 1, 1)
|
|
dock_hover_switch_container = Gtk.Box(
|
|
orientation=Gtk.Orientation.HORIZONTAL,
|
|
halign=Gtk.Align.START,
|
|
valign=Gtk.Align.CENTER,
|
|
)
|
|
self.dock_hover_switch = Gtk.Switch(
|
|
active=bind_vars.get("dock_always_occluded", False),
|
|
sensitive=self.dock_switch.get_active(),
|
|
)
|
|
dock_hover_switch_container.add(self.dock_hover_switch)
|
|
layout_grid.attach(dock_hover_switch_container, 3, 2, 1, 1)
|
|
|
|
notification_pos_label = Label(
|
|
label="Notification Position", h_align="start", v_align="center"
|
|
)
|
|
layout_grid.attach(notification_pos_label, 0, 8, 1, 1)
|
|
|
|
notification_pos_combo_container = Box(
|
|
orientation=Gtk.Orientation.HORIZONTAL,
|
|
halign=Gtk.Align.START,
|
|
valign=Gtk.Align.CENTER,
|
|
)
|
|
|
|
self.notification_pos_combo = Gtk.ComboBoxText()
|
|
self.notification_pos_combo.set_tooltip_text(
|
|
"Select where notifications appear on the screen."
|
|
)
|
|
|
|
notification_positions_list = ["Top", "Bottom"]
|
|
for pos in notification_positions_list:
|
|
self.notification_pos_combo.append_text(pos)
|
|
|
|
current_notif_pos = bind_vars.get(NOTIF_POS_KEY, NOTIF_POS_DEFAULT)
|
|
try:
|
|
self.notification_pos_combo.set_active(
|
|
notification_positions_list.index(current_notif_pos)
|
|
)
|
|
except ValueError:
|
|
self.notification_pos_combo.set_active(0)
|
|
|
|
self.notification_pos_combo.connect(
|
|
"changed", self.on_notification_position_changed
|
|
)
|
|
|
|
notification_pos_combo_container.add(self.notification_pos_combo)
|
|
layout_grid.attach(notification_pos_combo_container, 1, 8, 3, 1)
|
|
|
|
separator2 = Box(
|
|
style="min-height: 1px; background-color: alpha(@fg_color, 0.2); margin: 5px 0px;",
|
|
h_expand=True,
|
|
)
|
|
vbox.add(separator2)
|
|
|
|
components_header = Label(markup="<b>Modules</b>", h_align="start")
|
|
vbox.add(components_header)
|
|
components_grid = Gtk.Grid()
|
|
components_grid.set_column_spacing(15)
|
|
components_grid.set_row_spacing(8)
|
|
components_grid.set_margin_start(10)
|
|
components_grid.set_margin_top(5)
|
|
vbox.add(components_grid)
|
|
|
|
self.component_switches = {}
|
|
component_display_names = {
|
|
"workspace": "Workspaces",
|
|
"metrics": "System Metrics",
|
|
"date_time": "Date & Time",
|
|
"battery": "Battery Indicator",
|
|
"controls": "Control Panel",
|
|
"indicators": "Indicators",
|
|
"applications": "Taskbar",
|
|
"language": "Language Indicator",
|
|
"music_player": "Music Player",
|
|
}
|
|
|
|
self.corners_switch = Gtk.Switch(active=bind_vars.get("corners_visible", True))
|
|
num_components = len(component_display_names) + 1
|
|
rows_per_column = (num_components + 1) // 2
|
|
|
|
corners_label = Label(
|
|
label="Rounded Corners", h_align="start", v_align="center"
|
|
)
|
|
components_grid.attach(corners_label, 0, 0, 1, 1)
|
|
switch_container_corners = Gtk.Box(
|
|
orientation=Gtk.Orientation.HORIZONTAL,
|
|
halign=Gtk.Align.START,
|
|
valign=Gtk.Align.CENTER,
|
|
)
|
|
switch_container_corners.add(self.corners_switch)
|
|
components_grid.attach(switch_container_corners, 1, 0, 1, 1)
|
|
|
|
current_row = 0
|
|
current_col = 0
|
|
item_idx = 0
|
|
for i, (name, display) in enumerate(component_display_names.items()):
|
|
if item_idx < (rows_per_column - 1):
|
|
row = item_idx + 1
|
|
col = 0
|
|
else:
|
|
row = item_idx - (rows_per_column - 1)
|
|
col = 2
|
|
|
|
component_label = Label(label=display, h_align="start", v_align="center")
|
|
components_grid.attach(component_label, col, row, 1, 1)
|
|
|
|
switch_container = Gtk.Box(
|
|
orientation=Gtk.Orientation.HORIZONTAL,
|
|
halign=Gtk.Align.START,
|
|
valign=Gtk.Align.CENTER,
|
|
)
|
|
component_switch = Gtk.Switch(
|
|
active=bind_vars.get(f"dock_{name}_visible", True)
|
|
)
|
|
switch_container.add(component_switch)
|
|
components_grid.attach(switch_container, col + 1, row, 1, 1)
|
|
self.component_switches[name] = component_switch
|
|
item_idx += 1
|
|
|
|
return scrolled_window
|
|
|
|
def on_notification_position_changed(self, combo: Gtk.ComboBoxText):
|
|
selected_text = combo.get_active_text()
|
|
if selected_text:
|
|
bind_vars[NOTIF_POS_KEY] = selected_text
|
|
print(
|
|
f"Notification position updated in bind_vars: {
|
|
bind_vars[NOTIF_POS_KEY]
|
|
}"
|
|
)
|
|
|
|
def create_system_tab(self):
|
|
scrolled_window = ScrolledWindow(
|
|
h_scrollbar_policy="never",
|
|
v_scrollbar_policy="automatic",
|
|
h_expand=True,
|
|
v_expand=True,
|
|
propagate_width=False,
|
|
propagate_height=False,
|
|
)
|
|
|
|
vbox = Box(orientation="v", spacing=15, style="margin: 15px;")
|
|
scrolled_window.add(vbox)
|
|
|
|
system_grid = Gtk.Grid()
|
|
system_grid.set_column_spacing(20)
|
|
system_grid.set_row_spacing(10)
|
|
system_grid.set_margin_bottom(15)
|
|
vbox.add(system_grid)
|
|
|
|
terminal_header = Label(markup="<b>Terminal Settings</b>", h_align="start")
|
|
system_grid.attach(terminal_header, 0, 0, 2, 1)
|
|
terminal_label = Label(label="Command:", h_align="start", v_align="center")
|
|
system_grid.attach(terminal_label, 0, 1, 1, 1)
|
|
self.terminal_entry = Entry(
|
|
text=bind_vars.get("terminal_command", "kitty -e"),
|
|
tooltip_text="Command used to launch terminal apps (e.g., 'kitty -e')",
|
|
h_expand=True,
|
|
)
|
|
system_grid.attach(self.terminal_entry, 1, 1, 1, 1)
|
|
hint_label = Label(
|
|
markup="<small>Examples: 'kitty -e', 'alacritty -e', 'foot -e'</small>",
|
|
h_align="start",
|
|
)
|
|
system_grid.attach(hint_label, 0, 2, 2, 1)
|
|
|
|
hypr_header = Label(markup="<b>Hyprland Integration</b>", h_align="start")
|
|
system_grid.attach(hypr_header, 2, 0, 2, 1)
|
|
row = 1
|
|
self.lock_switch = None
|
|
if self.show_lock_checkbox:
|
|
lock_label = Label(
|
|
label="Replace Hyprlock config", h_align="start", v_align="center"
|
|
)
|
|
system_grid.attach(lock_label, 2, row, 1, 1)
|
|
lock_switch_container = Gtk.Box(
|
|
orientation=Gtk.Orientation.HORIZONTAL,
|
|
halign=Gtk.Align.START,
|
|
valign=Gtk.Align.CENTER,
|
|
)
|
|
self.lock_switch = Gtk.Switch(
|
|
tooltip_text="Replace Hyprlock configuration with Modus's custom config"
|
|
)
|
|
lock_switch_container.add(self.lock_switch)
|
|
system_grid.attach(lock_switch_container, 3, row, 1, 1)
|
|
row += 1
|
|
self.idle_switch = None
|
|
if self.show_idle_checkbox:
|
|
idle_label = Label(
|
|
label="Replace Hypridle config", h_align="start", v_align="center"
|
|
)
|
|
system_grid.attach(idle_label, 2, row, 1, 1)
|
|
idle_switch_container = Gtk.Box(
|
|
orientation=Gtk.Orientation.HORIZONTAL,
|
|
halign=Gtk.Align.START,
|
|
valign=Gtk.Align.CENTER,
|
|
)
|
|
self.idle_switch = Gtk.Switch(
|
|
tooltip_text="Replace Hypridle configuration with Modus's custom config"
|
|
)
|
|
idle_switch_container.add(self.idle_switch)
|
|
system_grid.attach(idle_switch_container, 3, row, 1, 1)
|
|
row += 1
|
|
if self.show_lock_checkbox or self.show_idle_checkbox:
|
|
note_label = Label(
|
|
markup="<small>Existing configs will be backed up</small>",
|
|
h_align="start",
|
|
)
|
|
system_grid.attach(note_label, 2, row, 2, 1)
|
|
|
|
metrics_header = Label(markup="<b>System Metrics Options</b>", h_align="start")
|
|
vbox.add(metrics_header)
|
|
metrics_grid = Gtk.Grid(
|
|
column_spacing=15, row_spacing=8, margin_start=10, margin_top=5
|
|
)
|
|
vbox.add(metrics_grid)
|
|
|
|
self.metrics_switches = {}
|
|
metric_names = {
|
|
"cpu": "CPU",
|
|
"ram": "RAM",
|
|
"swap": "Swap",
|
|
"disk": "Disk",
|
|
"gpu": "GPU",
|
|
}
|
|
|
|
metrics_grid.attach(Label(label="Show in Metrics", h_align="start"), 0, 0, 1, 1)
|
|
for i, (key, label_text) in enumerate(metric_names.items()):
|
|
switch = Gtk.Switch(
|
|
active=bind_vars.get("metrics_visible", {}).get(key, True)
|
|
)
|
|
self.metrics_switches[key] = switch
|
|
metrics_grid.attach(
|
|
Label(label=label_text, h_align="start"), 0, i + 1, 1, 1
|
|
)
|
|
metrics_grid.attach(switch, 1, i + 1, 1, 1)
|
|
|
|
def enforce_minimum_metrics(switch_dict):
|
|
enabled_switches = [s for s in switch_dict.values() if s.get_active()]
|
|
can_disable = len(enabled_switches) > 1
|
|
for s in switch_dict.values():
|
|
s.set_sensitive(True if can_disable or not s.get_active() else False)
|
|
|
|
def on_metric_toggle(switch, gparam, switch_dict):
|
|
enforce_minimum_metrics(switch_dict)
|
|
|
|
for k_s, s_s in self.metrics_switches.items():
|
|
s_s.connect("notify::active", on_metric_toggle, self.metrics_switches)
|
|
enforce_minimum_metrics(self.metrics_switches)
|
|
|
|
disks_label = Label(
|
|
label="Disk directories for Metrics", h_align="start", v_align="center"
|
|
)
|
|
vbox.add(disks_label)
|
|
self.disk_entries = Box(orientation="v", spacing=8, h_align="start")
|
|
|
|
self._create_disk_edit_entry_func = lambda path: self._add_disk_entry_widget(
|
|
path
|
|
)
|
|
|
|
for p in bind_vars.get("metrics_disks", ["/"]):
|
|
self._create_disk_edit_entry_func(p)
|
|
vbox.add(self.disk_entries)
|
|
|
|
add_container = Gtk.Box(
|
|
orientation=Gtk.Orientation.HORIZONTAL,
|
|
halign=Gtk.Align.START,
|
|
valign=Gtk.Align.CENTER,
|
|
)
|
|
add_btn = Button(
|
|
label="Add new disk",
|
|
on_clicked=lambda _: self._create_disk_edit_entry_func("/"),
|
|
)
|
|
add_container.add(add_btn)
|
|
vbox.add(add_container)
|
|
|
|
return scrolled_window
|
|
|
|
def _add_disk_entry_widget(self, path):
|
|
"""Helper para añadir una fila de entrada de disco al Box disk_entries."""
|
|
bar = Box(orientation="h", spacing=10, h_align="start")
|
|
entry = Entry(text=path, h_expand=True)
|
|
bar.add(entry)
|
|
x_btn = Button(label="X")
|
|
x_btn.connect(
|
|
"clicked",
|
|
lambda _, current_bar_to_remove=bar: self.disk_entries.remove(
|
|
current_bar_to_remove
|
|
),
|
|
)
|
|
bar.add(x_btn)
|
|
self.disk_entries.add(bar)
|
|
self.disk_entries.show_all()
|
|
|
|
def create_about_tab(self):
|
|
vbox = Box(orientation="v", spacing=18, style="margin: 30px;")
|
|
vbox.add(
|
|
Label(
|
|
markup=f"<b>{APP_NAME_CAP}</b>",
|
|
h_align="start",
|
|
style="font-size: 1.5em; margin-bottom: 8px;",
|
|
)
|
|
)
|
|
vbox.add(
|
|
Label(
|
|
label="A hackable shell for Hyprland, powered by Fabric.",
|
|
h_align="start",
|
|
style="margin-bottom: 12px;",
|
|
)
|
|
)
|
|
repo_box = Box(orientation="h", spacing=6, h_align="start")
|
|
repo_label = Label(label="GitHub:", h_align="start")
|
|
repo_link = Label(
|
|
markup='<a href="https://github.com/S4NKALP/Modus">https://github.com/S4NKALP/Modus</a>'
|
|
)
|
|
repo_box.add(repo_label)
|
|
repo_box.add(repo_link)
|
|
vbox.add(repo_box)
|
|
|
|
# def on_kofi_clicked(_):
|
|
# import webbrowser
|
|
|
|
# webbrowser.open("https://github.com/S4NKALP")
|
|
|
|
# kofi_btn = Button(
|
|
# label="Support on Ko-Fi ❤️",
|
|
# on_clicked=on_kofi_clicked,
|
|
# tooltip_text="Support S4NKALP on Ko-Fi",
|
|
# style="margin-top: 18px; min-width: 160px;",
|
|
# )
|
|
# vbox.add(kofi_btn)
|
|
vbox.add(Box(v_expand=True))
|
|
return vbox
|
|
|
|
def on_ws_mode_changed(self, combo):
|
|
mode = combo.get_active_text()
|
|
is_numbers_mode = mode == "Numbers"
|
|
self.ws_chinese_switch.set_sensitive(is_numbers_mode)
|
|
if not is_numbers_mode:
|
|
self.ws_chinese_switch.set_active(False)
|
|
|
|
def on_ws_num_changed(self, switch, gparam):
|
|
is_active = switch.get_active()
|
|
self.ws_chinese_switch.set_sensitive(is_active)
|
|
if not is_active:
|
|
self.ws_chinese_switch.set_active(False)
|
|
|
|
def on_position_changed(self, combo):
|
|
position = combo.get_active_text()
|
|
is_vertical = position in ["Left", "Right"]
|
|
self.centered_switch.set_sensitive(is_vertical)
|
|
if not is_vertical:
|
|
self.centered_switch.set_active(False)
|
|
|
|
def on_dock_enabled_changed(self, switch, gparam):
|
|
is_active = switch.get_active()
|
|
self.dock_hover_switch.set_sensitive(is_active)
|
|
self.dock_auto_hide_switch.set_sensitive(is_active)
|
|
if not is_active:
|
|
self.dock_hover_switch.set_active(False)
|
|
self.dock_auto_hide_switch.set_active(False)
|
|
|
|
def on_select_face_icon(self, widget):
|
|
dialog = Gtk.FileChooserDialog(
|
|
title="Select Face Icon",
|
|
transient_for=self.get_toplevel(),
|
|
action=Gtk.FileChooserAction.OPEN,
|
|
)
|
|
dialog.add_buttons(
|
|
Gtk.STOCK_CANCEL,
|
|
Gtk.ResponseType.CANCEL,
|
|
Gtk.STOCK_OPEN,
|
|
Gtk.ResponseType.OK,
|
|
)
|
|
image_filter = Gtk.FileFilter()
|
|
image_filter.set_name("Image files")
|
|
for mime in ["image/png", "image/jpeg"]:
|
|
image_filter.add_mime_type(mime)
|
|
for pattern in ["*.png", "*.jpg", "*.jpeg"]:
|
|
image_filter.add_pattern(pattern)
|
|
dialog.add_filter(image_filter)
|
|
if dialog.run() == Gtk.ResponseType.OK:
|
|
self.selected_face_icon = dialog.get_filename()
|
|
self.face_status_label.label = (
|
|
f"Selected: {os.path.basename(self.selected_face_icon)}"
|
|
)
|
|
try:
|
|
pixbuf = GdkPixbuf.Pixbuf.new_from_file_at_size(
|
|
self.selected_face_icon, 64, 64
|
|
)
|
|
self.face_image.set_from_pixbuf(pixbuf)
|
|
except Exception as e:
|
|
print(f"Error loading selected face icon preview: {e}")
|
|
self.face_image.set_from_icon_name("image-missing", Gtk.IconSize.DIALOG)
|
|
dialog.destroy()
|
|
|
|
def on_accept(self, widget):
|
|
current_bind_vars_snapshot = {}
|
|
for prefix_key, suffix_key, prefix_entry, suffix_entry in self.entries:
|
|
current_bind_vars_snapshot[prefix_key] = prefix_entry.get_text()
|
|
current_bind_vars_snapshot[suffix_key] = suffix_entry.get_text()
|
|
|
|
current_bind_vars_snapshot["wallpapers_dir"] = (
|
|
self.wall_dir_chooser.get_filename()
|
|
)
|
|
|
|
current_bind_vars_snapshot["dock_position"] = (
|
|
self.position_combo.get_active_text()
|
|
)
|
|
current_bind_vars_snapshot["vertical"] = current_bind_vars_snapshot[
|
|
"dock_position"
|
|
] in ["Left", "Right"]
|
|
|
|
current_bind_vars_snapshot["dock_enabled"] = self.dock_switch.get_active()
|
|
current_bind_vars_snapshot["dock_auto_hide"] = (
|
|
self.dock_auto_hide_switch.get_active()
|
|
)
|
|
current_bind_vars_snapshot["dock_always_occluded"] = (
|
|
self.dock_hover_switch.get_active()
|
|
)
|
|
current_bind_vars_snapshot["dock_icon_size"] = int(
|
|
self.icon_size_scale.get_value()
|
|
)
|
|
current_bind_vars_snapshot["window_switcher_items_per_row"] = int(
|
|
self.application_switcher_scale.get_value()
|
|
)
|
|
current_bind_vars_snapshot["terminal_command"] = self.terminal_entry.get_text()
|
|
current_bind_vars_snapshot["corners_visible"] = self.corners_switch.get_active()
|
|
current_bind_vars_snapshot["dock_theme"] = (
|
|
self.dock_theme_combo.get_active_text()
|
|
)
|
|
|
|
selected_notif_pos_text = self.notification_pos_combo.get_active_text()
|
|
if selected_notif_pos_text:
|
|
current_bind_vars_snapshot[NOTIF_POS_KEY] = selected_notif_pos_text
|
|
else:
|
|
current_bind_vars_snapshot[NOTIF_POS_KEY] = NOTIF_POS_DEFAULT
|
|
|
|
for component_name, switch in self.component_switches.items():
|
|
current_bind_vars_snapshot[f"dock_{component_name}_visible"] = (
|
|
switch.get_active()
|
|
)
|
|
|
|
# Save workspace settings
|
|
ws_mode = self.ws_mode_combo.get_active_text()
|
|
current_bind_vars_snapshot["workspace_dots"] = ws_mode == "Dots"
|
|
current_bind_vars_snapshot["workspace_nums"] = ws_mode == "Numbers"
|
|
current_bind_vars_snapshot["workspace_use_chinese_numerals"] = (
|
|
self.ws_chinese_switch.get_active()
|
|
)
|
|
|
|
current_bind_vars_snapshot["metrics_visible"] = {
|
|
k: s.get_active() for k, s in self.metrics_switches.items()
|
|
}
|
|
current_bind_vars_snapshot["metrics_disks"] = [
|
|
child.get_children()[0].get_text()
|
|
for child in self.disk_entries.get_children()
|
|
if isinstance(child, Gtk.Box)
|
|
and child.get_children()
|
|
and isinstance(child.get_children()[0], Entry)
|
|
]
|
|
|
|
selected_icon_path = self.selected_face_icon
|
|
replace_lock = self.lock_switch and self.lock_switch.get_active()
|
|
replace_idle = self.idle_switch and self.idle_switch.get_active()
|
|
|
|
if self.selected_face_icon:
|
|
self.selected_face_icon = None
|
|
self.face_status_label.label = ""
|
|
|
|
def _apply_and_reload_task_thread():
|
|
nonlocal current_bind_vars_snapshot
|
|
|
|
from . import utils
|
|
|
|
utils.bind_vars.clear()
|
|
utils.bind_vars.update(current_bind_vars_snapshot)
|
|
|
|
start_time = time.time()
|
|
print(f"{start_time:.4f}: Background task started.")
|
|
|
|
config_json = os.path.expanduser(
|
|
f"~/.config/{APP_NAME_CAP}/config/json/config.json"
|
|
)
|
|
os.makedirs(os.path.dirname(config_json), exist_ok=True)
|
|
try:
|
|
with open(config_json, "w") as f:
|
|
json.dump(utils.bind_vars, f, indent=4)
|
|
print(f"{time.time():.4f}: Saved config.json.")
|
|
except Exception as e:
|
|
print(f"Error saving config.json: {e}")
|
|
|
|
if selected_icon_path:
|
|
print(f"{time.time():.4f}: Processing face icon...")
|
|
try:
|
|
img = Image.open(selected_icon_path)
|
|
side = min(img.size)
|
|
left = (img.width - side) // 2
|
|
top = (img.height - side) // 2
|
|
cropped_img = img.crop((left, top, left + side, top + side))
|
|
face_icon_dest = os.path.expanduser("~/.face.icon")
|
|
cropped_img.save(face_icon_dest, format="PNG")
|
|
print(f"{time.time():.4f}: Face icon saved to {face_icon_dest}")
|
|
GLib.idle_add(self._update_face_image_widget, face_icon_dest)
|
|
except Exception as e:
|
|
print(f"Error processing face icon: {e}")
|
|
print(f"{time.time():.4f}: Finished processing face icon.")
|
|
|
|
if replace_lock:
|
|
print(f"{time.time():.4f}: Replacing hyprlock config...")
|
|
src = os.path.expanduser(
|
|
f"~/.config/{APP_NAME_CAP}/config/hypr/hyprlock.conf"
|
|
)
|
|
dest = os.path.expanduser("~/.config/hypr/hyprlock.conf")
|
|
if os.path.exists(src):
|
|
backup_and_replace(src, dest, "Hyprlock")
|
|
else:
|
|
print(f"Warning: Source hyprlock config not found at {src}")
|
|
print(f"{time.time():.4f}: Finished replacing hyprlock config.")
|
|
|
|
if replace_idle:
|
|
print(f"{time.time():.4f}: Replacing hypridle config...")
|
|
src = os.path.expanduser(
|
|
f"~/.config/{APP_NAME_CAP}/config/hypr/hypridle.conf"
|
|
)
|
|
dest = os.path.expanduser("~/.config/hypr/hypridle.conf")
|
|
if os.path.exists(src):
|
|
backup_and_replace(src, dest, "Hypridle")
|
|
else:
|
|
print(f"Warning: Source hypridle config not found at {src}")
|
|
print(f"{time.time():.4f}: Finished replacing hypridle config.")
|
|
|
|
print(
|
|
f"{time.time():.4f}: Checking/Appending hyprland.conf source string..."
|
|
)
|
|
hypr_path = os.path.expanduser("~/.config/hypr/hyprland.conf")
|
|
try:
|
|
from .constants import SOURCE_STRING
|
|
|
|
needs_append = True
|
|
if os.path.exists(hypr_path):
|
|
with open(hypr_path, "r") as f:
|
|
if SOURCE_STRING.strip() in f.read():
|
|
needs_append = False
|
|
else:
|
|
os.makedirs(os.path.dirname(hypr_path), exist_ok=True)
|
|
|
|
if needs_append:
|
|
with open(hypr_path, "a") as f:
|
|
f.write("\n" + SOURCE_STRING)
|
|
print(f"Appended source string to {hypr_path}")
|
|
except Exception as e:
|
|
print(f"Error updating {hypr_path}: {e}")
|
|
print(
|
|
f"{time.time():.4f}: Finished checking/appending hyprland.conf source string."
|
|
)
|
|
|
|
print(f"{time.time():.4f}: Running start_config()...")
|
|
start_config()
|
|
print(f"{time.time():.4f}: Finished start_config().")
|
|
|
|
print(f"{time.time():.4f}: Initiating Modus restart using Popen...")
|
|
main_py = os.path.expanduser(f"~/.config/{APP_NAME_CAP}/main.py")
|
|
kill_cmd = f"killall {APP_NAME}"
|
|
start_cmd = ["uwsm", "app", "--", "python", main_py]
|
|
try:
|
|
kill_proc = subprocess.Popen(
|
|
kill_cmd,
|
|
shell=True,
|
|
stdout=subprocess.DEVNULL,
|
|
stderr=subprocess.DEVNULL,
|
|
)
|
|
kill_proc.wait(timeout=2)
|
|
print(f"{time.time():.4f}: killall process finished (o timed out).")
|
|
except subprocess.TimeoutExpired:
|
|
print("Warning: killall command timed out.")
|
|
except Exception as e:
|
|
print(f"Error running killall: {e}")
|
|
|
|
try:
|
|
subprocess.Popen(
|
|
start_cmd,
|
|
stdout=subprocess.DEVNULL,
|
|
stderr=subprocess.DEVNULL,
|
|
start_new_session=True,
|
|
)
|
|
print(f"{APP_NAME_CAP} restart initiated via Popen.")
|
|
except FileNotFoundError as e:
|
|
print(f"Error restarting {APP_NAME_CAP}: Command not found ({e})")
|
|
except Exception as e:
|
|
print(f"Error restarting {APP_NAME_CAP} via Popen: {e}")
|
|
|
|
print(f"{time.time():.4f}: Modus restart commands issued via Popen.")
|
|
end_time = time.time()
|
|
print(
|
|
f"{end_time:.4f}: Background task finished (Total: {
|
|
end_time - start_time:.4f
|
|
}s)."
|
|
)
|
|
|
|
thread = threading.Thread(target=_apply_and_reload_task_thread)
|
|
thread.daemon = True
|
|
thread.start()
|
|
print("Configuration apply/reload task started in background.")
|
|
|
|
def _update_face_image_widget(self, icon_path):
|
|
try:
|
|
if self.face_image and self.face_image.get_window():
|
|
pixbuf = GdkPixbuf.Pixbuf.new_from_file_at_size(icon_path, 64, 64)
|
|
self.face_image.set_from_pixbuf(pixbuf)
|
|
except Exception as e:
|
|
print(f"Error reloading face icon preview: {e}")
|
|
if self.face_image and self.face_image.get_window():
|
|
self.face_image.set_from_icon_name("image-missing", Gtk.IconSize.DIALOG)
|
|
return GLib.SOURCE_REMOVE
|
|
|
|
def on_reset(self, widget):
|
|
dialog = Gtk.MessageDialog(
|
|
transient_for=self.get_toplevel(),
|
|
flags=0,
|
|
message_type=Gtk.MessageType.QUESTION,
|
|
buttons=Gtk.ButtonsType.YES_NO,
|
|
text="Reset all settings to defaults?",
|
|
)
|
|
dialog.format_secondary_text(
|
|
"This will reset all keybindings and appearance settings to their default values."
|
|
)
|
|
response = dialog.run()
|
|
dialog.hide() # Hide the dialog first
|
|
dialog.destroy() # Then destroy it
|
|
|
|
# Process any pending events
|
|
while Gtk.events_pending():
|
|
Gtk.main_iteration()
|
|
|
|
if response == Gtk.ResponseType.YES:
|
|
from . import utils
|
|
from .constants import DEFAULTS
|
|
|
|
utils.bind_vars.clear()
|
|
utils.bind_vars.update(DEFAULTS.copy())
|
|
|
|
for prefix_key, suffix_key, prefix_entry, suffix_entry in self.entries:
|
|
prefix_entry.set_text(utils.bind_vars[prefix_key])
|
|
suffix_entry.set_text(utils.bind_vars[suffix_key])
|
|
|
|
self.wall_dir_chooser.set_filename(utils.bind_vars["wallpapers_dir"])
|
|
|
|
positions = ["Bottom", "Left", "Right"]
|
|
default_position = DEFAULTS.get("dock_position", "Bottom")
|
|
try:
|
|
self.position_combo.set_active(positions.index(default_position))
|
|
except ValueError:
|
|
self.position_combo.set_active(0)
|
|
|
|
self.dock_switch.set_active(utils.bind_vars.get("dock_enabled", True))
|
|
self.dock_auto_hide_switch.set_active(
|
|
utils.bind_vars.get("dock_auto_hide", True)
|
|
)
|
|
self.dock_hover_switch.set_active(
|
|
utils.bind_vars.get("dock_always_occluded", False)
|
|
)
|
|
self.dock_hover_switch.set_sensitive(self.dock_switch.get_active())
|
|
self.dock_auto_hide_switch.set_sensitive(self.dock_switch.get_active())
|
|
self.terminal_entry.set_text(utils.bind_vars["terminal_command"])
|
|
|
|
default_dock_theme_val = DEFAULTS.get("dock_theme", "Pills")
|
|
try:
|
|
self.dock_theme_combo.set_active(
|
|
self.themes.index(default_dock_theme_val)
|
|
)
|
|
except ValueError:
|
|
self.dock_theme_combo.set_active(0)
|
|
|
|
default_notif_pos_val = DEFAULTS.get(NOTIF_POS_KEY, NOTIF_POS_DEFAULT)
|
|
notification_positions_list = ["Top", "Bottom"]
|
|
try:
|
|
self.notification_pos_combo.set_active(
|
|
notification_positions_list.index(default_notif_pos_val)
|
|
)
|
|
except ValueError:
|
|
self.notification_pos_combo.set_active(0)
|
|
|
|
for name, switch in self.component_switches.items():
|
|
switch.set_active(utils.bind_vars.get(f"dock_{name}_visible", True))
|
|
|
|
# Reset workspace settings
|
|
default_dots = DEFAULTS.get("workspace_dots", True)
|
|
default_nums = DEFAULTS.get("workspace_nums", False)
|
|
if default_dots:
|
|
default_mode = "Dots"
|
|
elif default_nums:
|
|
default_mode = "Numbers"
|
|
else:
|
|
default_mode = "Single Button"
|
|
|
|
ws_modes = ["Dots", "Numbers", "Single Button"]
|
|
try:
|
|
self.ws_mode_combo.set_active(ws_modes.index(default_mode))
|
|
except ValueError:
|
|
self.ws_mode_combo.set_active(0)
|
|
|
|
self.ws_chinese_switch.set_active(
|
|
utils.bind_vars.get("workspace_use_chinese_numerals", False)
|
|
)
|
|
self.ws_chinese_switch.set_sensitive(default_nums)
|
|
self.corners_switch.set_active(utils.bind_vars.get("corners_visible", True))
|
|
|
|
metrics_vis_defaults = DEFAULTS.get("metrics_visible", {})
|
|
for k, s_widget in self.metrics_switches.items():
|
|
s_widget.set_active(metrics_vis_defaults.get(k, True))
|
|
|
|
def enforce_minimum_metrics(switch_dict):
|
|
enabled_switches = [s for s in switch_dict.values() if s.get_active()]
|
|
can_disable = len(enabled_switches) > 1
|
|
for s in switch_dict.values():
|
|
s.set_sensitive(
|
|
True if can_disable or not s.get_active() else False
|
|
)
|
|
|
|
enforce_minimum_metrics(self.metrics_switches)
|
|
|
|
for child in list(self.disk_entries.get_children()):
|
|
self.disk_entries.remove(child)
|
|
|
|
for p in DEFAULTS.get("metrics_disks", ["/"]):
|
|
self._add_disk_edit_entry_func(p)
|
|
|
|
self._update_panel_position_sensitivity()
|
|
|
|
self.selected_face_icon = None
|
|
self.face_status_label.label = ""
|
|
current_face = os.path.expanduser("~/.face.icon")
|
|
try:
|
|
pixbuf = (
|
|
GdkPixbuf.Pixbuf.new_from_file_at_size(current_face, 64, 64)
|
|
if os.path.exists(current_face)
|
|
else None
|
|
)
|
|
if pixbuf:
|
|
self.face_image.set_from_pixbuf(pixbuf)
|
|
else:
|
|
self.face_image.set_from_icon_name("user-info", Gtk.IconSize.DIALOG)
|
|
except Exception:
|
|
self.face_image.set_from_icon_name("image-missing", Gtk.IconSize.DIALOG)
|
|
|
|
if self.lock_switch:
|
|
self.lock_switch.set_active(False)
|
|
if self.idle_switch:
|
|
self.idle_switch.set_active(False)
|
|
# Add reset for icon size scale
|
|
self.icon_size_scale.set_value(utils.bind_vars.get("dock_icon_size", 20))
|
|
self.application_switcher_scale.set_value(
|
|
utils.bind_vars.get("window_switcher_items_per_row", 13)
|
|
)
|
|
print("Settings reset to defaults.")
|
|
|
|
def on_close(self, widget):
|
|
if self.application:
|
|
self.application.quit()
|
|
else:
|
|
self.destroy()
|