feat(src/shared): introduce settings window and refine visibility configurationAdd a dedicated settings window with full CSS styling and improve UI consistency

- New Settings window implementation with styling and layout
- Updated visibility configuration to use direct configuration keys
- Simplified layer‑shell positioning logic and improved reliability

Enhancements- Refactored MouseCapture geometry calculations for cleaner code
- Integrated size‑allocate handler to maintain input region sync
- Added global About window singleton and improved toggle behavior

Bug Fixes
- Fixed potential index errors in MouseCapture coordinate calculations- Resolved missing imports and path issues for icon assets
This commit is contained in:
sankalp committed 2026-05-03 22:06:35 +05:45
1 parent ebd50e585c
commit 704c8b229c
5 files changed
+202 -68

No files matched your search

+30 -55
View File
@@ -1,4 +1,4 @@
from fabric.utils import Any, Gdk, cairo
from fabric.utils import Any, Gdk, cairo, GLib
from fabric.widgets.eventbox import EventBox
from fabric.widgets.wayland import WaylandWindow as Window
from fabric.widgets.widget import Widget
@@ -75,52 +75,25 @@ class MouseCapture(Window):
return False
def _get_child_window_bounds(self) -> tuple[int, int, int, int]:
"""Calculates absolute screen bounds for the child window using Layer Shell properties"""
"""Calculates absolute screen bounds for the child window using Gdk origin"""
try:
# Get monitor geometry
monitor = self._hyprland.display.get_monitor_at_window(
self.child_window.get_window()
)
if not monitor:
monitor = self._hyprland.display.get_default_monitor()
window = self.child_window.get_window()
if not window:
# Fallback to allocation if window isn't mapped yet
alloc = self.child_window.get_allocation()
return 0, 0, alloc.width, alloc.height
geom = monitor.get_geometry()
mx, my, mw, mh = geom.x, geom.y, geom.width, geom.height
# get_origin provides absolute screen coordinates
success, x, y = window.get_origin()
if not success:
alloc = self.child_window.get_allocation()
return 0, 0, alloc.width, alloc.height
# Get child window properties
alloc = self.child_window.get_allocation()
ww, wh = alloc.width, alloc.height
# fabric's WaylandWindow usually has anchor and margin accessible
anchor = self.child_window.anchor
margin = self.child_window.margin # (top, right, bottom, left)
# Calculation logic based on Layer Shell anchors
# X coordinate
if GtkLayerShell.Edge.LEFT in anchor and GtkLayerShell.Edge.RIGHT in anchor:
x = mx + margin[3]
elif GtkLayerShell.Edge.LEFT in anchor:
x = mx + margin[3]
elif GtkLayerShell.Edge.RIGHT in anchor:
x = mx + mw - ww - margin[1]
else: # Centered horizontally
x = mx + (mw - ww) // 2 + margin[3] - margin[1]
# Y coordinate
if GtkLayerShell.Edge.TOP in anchor and GtkLayerShell.Edge.BOTTOM in anchor:
y = my + margin[0]
elif GtkLayerShell.Edge.TOP in anchor:
y = my + margin[0]
elif GtkLayerShell.Edge.BOTTOM in anchor:
y = my + mh - wh - margin[2]
else: # Centered vertically
y = my + (mh - wh) // 2 + margin[0] - margin[2]
return x, y, ww, wh
return x, y, alloc.width, alloc.height
except Exception as e:
print(f"Error calculating child window bounds: {e}")
# Fallback to allocation if possible, though likely (0,0)
alloc = self.child_window.get_allocation()
return 0, 0, alloc.width, alloc.height
@@ -128,27 +101,19 @@ class MouseCapture(Window):
"""Calculates absolute screen bounds for a widget in another window"""
try:
toplevel = widget.get_toplevel()
if not toplevel:
if not toplevel or not toplevel.get_window():
return 0, 0, 0, 0
# Get monitor geometry
monitor = self._hyprland.display.get_monitor_at_window(
toplevel.get_window()
)
if not monitor:
monitor = self._hyprland.display.get_default_monitor()
geom = monitor.get_geometry()
mx, my = geom.x, geom.y
# Get the origin of the window containing the widget
success, wx, wy = toplevel.get_window().get_origin()
if not success:
return 0, 0, 0, 0
# Get relative position within toplevel
alloc = widget.get_allocation()
x, y = widget.translate_coordinates(toplevel, 0, 0) or (0, 0)
rx, ry = widget.translate_coordinates(toplevel, 0, 0) or (0, 0)
# If the toplevel is a Layer Shell window, its (0,0) is monitor relative
# but we need to account for its own margin/anchor if it's not full screen.
# However, for the Panel (which is usually top-anchored), (0,0) is (monitor_x, monitor_y).
return mx + x, my + y, alloc.width, alloc.height
return wx + rx, wy + ry, alloc.width, alloc.height
except Exception as e:
print(f"Error calculating widget absolute bounds: {e}")
return 0, 0, 0, 0
@@ -250,13 +215,23 @@ class MouseCapture(Window):
self.set_child_window_visible(True)
def hide_child_window(self, widget: Widget = None, event: Any = None) -> None:
self.set_child_window_visible(False)
def set_child_window_visible(self, visible: bool) -> None:
if visible:
# Connect to child window size changes to keep input region in sync
self._size_handler = self.child_window.connect(
"size-allocate", lambda *_: self.update_input_region()
)
self.child_window.show()
self.show()
# Force update with a small delay to ensure window is mapped
GLib.timeout_add(50, self.update_input_region)
else:
if hasattr(self, "_size_handler") and self._size_handler:
self.child_window.disconnect(self._size_handler)
self._size_handler = None
self.child_window.hide()
self.hide()