Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions docs/widgets/(Widget)-Taskbar.md
Original file line number Diff line number Diff line change
Expand Up @@ -102,6 +102,12 @@ taskbar:
.taskbar-widget .app-container.flashing {
background-color: rgba(255, 106, 106, 0.63);
}
.taskbar-widget .app-container.running {
background-color: rgba(255, 255, 255, 0.25);
}
.taskbar-widget .app-container:hover {
background-color: rgba(255, 255, 255, 0.15);
}
.taskbar-widget .app-container .app-title {
padding-left: 4px;
}
Expand Down
39 changes: 20 additions & 19 deletions src/core/bar.py
Original file line number Diff line number Diff line change
Expand Up @@ -66,8 +66,9 @@ def __init__(
self._os_theme_manager = None
self._fullscreen_manager = None
self._autohide_manager = None
self._target_screen = bar_screen

self.screen_name = self.screen().name()
self.screen_name = self._target_screen.name()
self.app_bar_edge = (
app_bar.AppBarEdge.Top if self._alignment["position"] == "top" else app_bar.AppBarEdge.Bottom
)
Expand Down Expand Up @@ -109,11 +110,11 @@ def __init__(
self.position_bar(init)
self.monitor_hwnd = get_monitor_hwnd(int(self.winId()))

self._add_widgets(widgets)

if self._is_auto_width:
self._sync_auto_width()
self._bar_frame.installEventFilter(self)

self._add_widgets(widgets)
QTimer.singleShot(0, self._sync_auto_width)

if not self._window_flags["windows_app_bar"]:
try:
Expand All @@ -133,7 +134,7 @@ def __init__(
BorderColor=blur_effect["border_color"],
)

self.screen().geometryChanged.connect(self.on_geometry_changed, Qt.ConnectionType.QueuedConnection)
self._target_screen.geometryChanged.connect(self.on_geometry_changed, Qt.ConnectionType.QueuedConnection)

self.handle_bar_management.connect(self._handle_bar_management)
self._event_service.register_event("handle_bar_cli", self.handle_bar_management)
Expand All @@ -143,7 +144,7 @@ def __init__(
self._autohide_manager = AutoHideManager(self, self)
self._autohide_manager.setup_autohide()

QTimer.singleShot(0, self.show)
self.show()

@property
def bar_id(self) -> str:
Expand All @@ -165,7 +166,7 @@ def try_add_app_bar(self, scale_screen_height=False) -> None:
self.winId().__int__(),
self.app_bar_edge,
self._dimensions["height"] + self._padding["top"] + self._padding["bottom"],
self.screen(),
self._target_screen,
scale_screen_height,
)

Expand All @@ -174,8 +175,8 @@ def try_remove_app_bar(self) -> None:
self.app_bar_manager.remove_appbar()

def bar_pos(self, bar_w: int, bar_h: int, screen_w: int, screen_h: int) -> tuple[int, int]:
screen_x = self.screen().geometry().x()
screen_y = self.screen().geometry().y()
screen_x = self._target_screen.geometry().x()
screen_y = self._target_screen.geometry().y()

if self._align == "center" or self._alignment.get("center", False):
available_x = screen_x + self._padding["left"]
Expand Down Expand Up @@ -206,13 +207,16 @@ def position_bar(self, init=False) -> None:
bar_width = self._dimensions["width"]
bar_height = self._dimensions["height"]

screen_width = self.screen().geometry().width()
screen_height = self.screen().geometry().height()
screen_width = self._target_screen.geometry().width()
screen_height = self._target_screen.geometry().height()

scale_state = self.screen().devicePixelRatio() > 1.0
scale_state = self._target_screen.devicePixelRatio() > 1.0

if self._is_auto_width:
bar_width = self._update_auto_width()
if self._bar_frame.layout() is not None:
bar_width = self._update_auto_width()
else:
bar_width = 0

elif is_valid_percentage_str(str(self._dimensions["width"])):
percent = percent_to_float(self._dimensions["width"])
Expand All @@ -236,7 +240,7 @@ def _update_auto_width(self) -> int:
layout.activate()

requested = max(self._bar_frame.sizeHint().width(), 0)
available = self.screen().geometry().width() - self._padding["left"] - self._padding["right"]
available = self._target_screen.geometry().width() - self._padding["left"] - self._padding["right"]
new_width = min(requested, available)
self._current_auto_width = new_width
return new_width
Expand All @@ -247,7 +251,7 @@ def _apply_auto_width(self, new_width: int) -> None:
return

bar_height = self._dimensions["height"]
screen_geometry = self.screen().geometry()
screen_geometry = self._target_screen.geometry()
bar_x, bar_y = self.bar_pos(
new_width,
bar_height,
Expand All @@ -260,9 +264,6 @@ def _apply_auto_width(self, new_width: int) -> None:

def _sync_auto_width(self) -> None:
"""Ensure auto width matches the layout after a DPI/geometry."""
if not self._is_auto_width:
return

previous_width = self._current_auto_width
new_width = self._update_auto_width()

Expand Down Expand Up @@ -369,7 +370,7 @@ def hide(self):
super().hide()

def _handle_bar_management(self, action, screen_name):
current_screen_matches = not screen_name or self.screen().name() == screen_name
current_screen_matches = not screen_name or self._target_screen.name() == screen_name
if current_screen_matches:
if action == "show":
self.show()
Expand Down
41 changes: 5 additions & 36 deletions src/core/utils/widgets/animation_manager.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,15 +7,15 @@
class AnimationManager:
_instances = {}
_repeating_animations = {} # Track widgets with repeating animations
ALLOWED_ANIMATIONS = ["fadeInOut", "blink"]
ALLOWED_ANIMATIONS = ["fadeInOut"]

@classmethod
def animate(cls, widget, animation_type: str, duration: int = 200):
"""Execute a single animation on a widget.

Args:
widget: The widget to animate
animation_type: Type of animation ('fadeInOut', 'flash', etc.)
animation_type: Type of animation ('fadeInOut', etc.)
duration: Duration of the animation in milliseconds
"""
if animation_type not in cls.ALLOWED_ANIMATIONS:
Expand All @@ -39,7 +39,7 @@ def start_animation(

Args:
widget: The widget to animate
animation_type: Type of animation ('blink', 'fadeInOut', etc.)
animation_type: Type of animation ('fadeInOut', etc.)
animation_duration: Duration of each animation cycle in ms (default 800ms)
repeat_interval: Time between animation cycles in ms (default 2000ms = 2s)
timeout: Auto-stop after this many ms (default 5000ms = 5s), 0 = no timeout
Expand Down Expand Up @@ -128,44 +128,13 @@ def on_finished():
widget.setGraphicsEffect(None)
except Exception:
pass

anim.finished.connect(on_finished)

# Keep reference to prevent garbage collection
widget._yasb_animation = anim
anim.start()

def blink(self, widget):
"""Blink animation - dim and brighten like Windows taskbar notification blinking."""
effect = QGraphicsOpacityEffect(widget)
effect.setEnabled(True)
effect.setOpacity(1.0)
widget.setGraphicsEffect(effect)

anim = QPropertyAnimation(effect, b"opacity", widget)
anim.setDuration(self.duration)
anim.setStartValue(1.0)
anim.setEndValue(0.7)
anim.setEasingCurve(QEasingCurve.Type.InOutQuad)

# Reverse the animation to go back to full opacity
anim.setDirection(QPropertyAnimation.Direction.Forward)

def on_finished():
try:
# Fade back to full opacity
if anim.direction() == QPropertyAnimation.Direction.Forward:
anim.setDirection(QPropertyAnimation.Direction.Backward)
anim.start()
else:
# Animation complete, clean up
effect.setEnabled(False)
widget.setGraphicsEffect(None)
widget._yasb_animation = None
except Exception:
pass

anim.finished.connect(on_finished)

# Keep reference to prevent garbage collection
# Keep reference to prevent garbage collection if not cleared
widget._yasb_animation = anim
anim.start()
Loading