urgent tags
This commit is contained in:
parent
0966c1ce70
commit
736e1a47c9
13
bar/bar.css
13
bar/bar.css
@ -73,12 +73,21 @@ button {
|
|||||||
font-size: 0px;
|
font-size: 0px;
|
||||||
}
|
}
|
||||||
|
|
||||||
#workspaces>button:hover {
|
#workspaces button.hover {
|
||||||
background-color: var(--ws-hover);
|
background-color: var(--ws-hover);
|
||||||
}
|
}
|
||||||
|
|
||||||
#workspaces>button.urgent {
|
#workspaces button.urgent {
|
||||||
background-color: var(--ws-urgent);
|
background-color: var(--ws-urgent);
|
||||||
|
color: var(--foreground);
|
||||||
|
font-weight: bold;
|
||||||
|
animation: urgent-blink 1s infinite;
|
||||||
|
}
|
||||||
|
|
||||||
|
@keyframes urgent-blink {
|
||||||
|
0% { opacity: 1.0; }
|
||||||
|
50% { opacity: 0.5; }
|
||||||
|
100% { opacity: 1.0; }
|
||||||
}
|
}
|
||||||
|
|
||||||
#workspaces>button.empty {
|
#workspaces>button.empty {
|
||||||
|
|||||||
@ -10,7 +10,7 @@ from fabric.utils.helpers import idle_add
|
|||||||
|
|
||||||
# Import pywayland components - ensure these imports are correct
|
# Import pywayland components - ensure these imports are correct
|
||||||
from pywayland.client import Display
|
from pywayland.client import Display
|
||||||
from pywayland.protocol.wayland import WlOutput, WlRegistry, WlSeat
|
from pywayland.protocol.wayland import WlOutput, WlSeat
|
||||||
from .generated.river_status_unstable_v1 import ZriverStatusManagerV1
|
from .generated.river_status_unstable_v1 import ZriverStatusManagerV1
|
||||||
|
|
||||||
|
|
||||||
@ -23,6 +23,7 @@ class OutputInfo:
|
|||||||
status: Any = None # ZriverOutputStatusV1
|
status: Any = None # ZriverOutputStatusV1
|
||||||
tags_view: List[int] = field(default_factory=list)
|
tags_view: List[int] = field(default_factory=list)
|
||||||
tags_focused: List[int] = field(default_factory=list)
|
tags_focused: List[int] = field(default_factory=list)
|
||||||
|
tags_urgent: List[int] = field(default_factory=list)
|
||||||
|
|
||||||
|
|
||||||
@dataclass(frozen=True)
|
@dataclass(frozen=True)
|
||||||
@ -190,11 +191,23 @@ class River(Service):
|
|||||||
|
|
||||||
return handler
|
return handler
|
||||||
|
|
||||||
|
def make_urgent_tags_handler(output_id):
|
||||||
|
def handler(_, tags):
|
||||||
|
decoded = self._decode_bitfields(tags)
|
||||||
|
state["outputs"][output_id].tags_urgent = decoded
|
||||||
|
logger.debug(
|
||||||
|
f"[RiverService] Output {output_id} urgent tags: {decoded}"
|
||||||
|
)
|
||||||
|
idle_add(lambda: self._emit_urgent_tags(output_id, decoded))
|
||||||
|
|
||||||
|
return handler
|
||||||
|
|
||||||
# Bind output status listeners
|
# Bind output status listeners
|
||||||
for name, info in list(state["outputs"].items()):
|
for name, info in list(state["outputs"].items()):
|
||||||
status = state["river_status_mgr"].get_river_output_status(info.output)
|
status = state["river_status_mgr"].get_river_output_status(info.output)
|
||||||
status.dispatcher["view_tags"] = make_view_tags_handler(name)
|
status.dispatcher["view_tags"] = make_view_tags_handler(name)
|
||||||
status.dispatcher["focused_tags"] = make_focused_tags_handler(name)
|
status.dispatcher["focused_tags"] = make_focused_tags_handler(name)
|
||||||
|
status.dispatcher["urgent_tags"] = make_urgent_tags_handler(name)
|
||||||
info.status = status
|
info.status = status
|
||||||
logger.info(f"[RiverService] Set up status for output {name}")
|
logger.info(f"[RiverService] Set up status for output {name}")
|
||||||
|
|
||||||
@ -251,6 +264,13 @@ class River(Service):
|
|||||||
self.notify("active-window")
|
self.notify("active-window")
|
||||||
return False # Don't repeat
|
return False # Don't repeat
|
||||||
|
|
||||||
|
def _emit_urgent_tags(self, output_id, tags):
|
||||||
|
"""Emit urgent_tags events (called on main thread)"""
|
||||||
|
event = RiverEvent("urgent_tags", tags, output_id)
|
||||||
|
self.emit("event::urgent_tags", event)
|
||||||
|
self.emit(f"event::urgent_tags::{output_id}", tags)
|
||||||
|
return False # Don't repeat
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def _decode_bitfields(bitfields) -> List[int]:
|
def _decode_bitfields(bitfields) -> List[int]:
|
||||||
"""Decode River's tag bitfields into a list of tag indices"""
|
"""Decode River's tag bitfields into a list of tag indices"""
|
||||||
|
|||||||
@ -43,11 +43,36 @@ class RiverWorkspaceButton(Button):
|
|||||||
self._empty = value
|
self._empty = value
|
||||||
(self.remove_style_class if not value else self.add_style_class)("empty")
|
(self.remove_style_class if not value else self.add_style_class)("empty")
|
||||||
|
|
||||||
|
@Property(bool, "read-write", default_value=False)
|
||||||
|
def urgent(self) -> bool:
|
||||||
|
return self._urgent
|
||||||
|
|
||||||
|
@urgent.setter
|
||||||
|
def urgent(self, value: bool):
|
||||||
|
self._urgent = value
|
||||||
|
self._update_style()
|
||||||
|
|
||||||
def __init__(self, id: int, label: str = None, **kwargs):
|
def __init__(self, id: int, label: str = None, **kwargs):
|
||||||
super().__init__(label or str(id), **kwargs)
|
super().__init__(label or str(id), **kwargs)
|
||||||
self._id = id
|
self._id = id
|
||||||
self._active = False
|
self._active = False
|
||||||
self._empty = True
|
self._empty = True
|
||||||
|
self._urgent = False
|
||||||
|
|
||||||
|
def _update_style(self):
|
||||||
|
"""Update button styles based on states"""
|
||||||
|
# Remove all state-related styles first
|
||||||
|
self.remove_style_class("active")
|
||||||
|
self.remove_style_class("empty")
|
||||||
|
self.remove_style_class("urgent")
|
||||||
|
|
||||||
|
# Then apply current states
|
||||||
|
if self._active:
|
||||||
|
self.add_style_class("active")
|
||||||
|
if self._empty:
|
||||||
|
self.add_style_class("empty")
|
||||||
|
if self._urgent:
|
||||||
|
self.add_style_class("urgent")
|
||||||
|
|
||||||
|
|
||||||
class RiverWorkspaces(EventBox):
|
class RiverWorkspaces(EventBox):
|
||||||
@ -71,6 +96,7 @@ class RiverWorkspaces(EventBox):
|
|||||||
# Connect to service events
|
# Connect to service events
|
||||||
self.service.connect("event::focused_tags", self.on_focus_change_general)
|
self.service.connect("event::focused_tags", self.on_focus_change_general)
|
||||||
self.service.connect("event::view_tags", self.on_view_change_general)
|
self.service.connect("event::view_tags", self.on_view_change_general)
|
||||||
|
self.service.connect("event::urgent_tags", self.on_urgent_change_general)
|
||||||
self.service.connect("event::output_removed", self.on_output_removed)
|
self.service.connect("event::output_removed", self.on_output_removed)
|
||||||
|
|
||||||
# Initial setup when service is ready
|
# Initial setup when service is ready
|
||||||
@ -100,14 +126,16 @@ class RiverWorkspaces(EventBox):
|
|||||||
# Access fields directly on the OutputInfo dataclass
|
# Access fields directly on the OutputInfo dataclass
|
||||||
focused_tags = output_info.tags_focused
|
focused_tags = output_info.tags_focused
|
||||||
view_tags = output_info.tags_view
|
view_tags = output_info.tags_view
|
||||||
|
urgent_tags = output_info.tags_urgent
|
||||||
|
|
||||||
logger.debug(
|
logger.debug(
|
||||||
f"[RiverWorkspaces] Initial state - focused: {focused_tags}, view: {view_tags}"
|
f"[RiverWorkspaces] Initial state - focused: {focused_tags}, view: {view_tags}, urgent: {urgent_tags}"
|
||||||
)
|
)
|
||||||
|
|
||||||
for i, btn in self._buttons.items():
|
for i, btn in self._buttons.items():
|
||||||
btn.active = i in focused_tags
|
btn.active = i in focused_tags
|
||||||
btn.empty = i not in view_tags
|
btn.empty = i not in view_tags
|
||||||
|
btn.urgent = i in urgent_tags
|
||||||
|
|
||||||
def on_focus_change(self, _, tags):
|
def on_focus_change(self, _, tags):
|
||||||
"""Handle focused tags change for our specific output"""
|
"""Handle focused tags change for our specific output"""
|
||||||
@ -143,6 +171,23 @@ class RiverWorkspaces(EventBox):
|
|||||||
)
|
)
|
||||||
self.on_view_change(_, event.data)
|
self.on_view_change(_, event.data)
|
||||||
|
|
||||||
|
def on_urgent_change(self, _, tags):
|
||||||
|
"""Handle urgent tags change for our specific output"""
|
||||||
|
logger.debug(
|
||||||
|
f"[RiverWorkspaces] Urgent change on output {self.output_id}: {tags}"
|
||||||
|
)
|
||||||
|
for i, btn in self._buttons.items():
|
||||||
|
btn.urgent = i in tags
|
||||||
|
|
||||||
|
def on_urgent_change_general(self, _, event):
|
||||||
|
"""Handle general urgent tags event"""
|
||||||
|
# Only handle event if it's for our output
|
||||||
|
if event.output_id == self.output_id:
|
||||||
|
logger.debug(
|
||||||
|
f"[RiverWorkspaces] General urgent change for output {self.output_id}"
|
||||||
|
)
|
||||||
|
self.on_urgent_change(_, event.data)
|
||||||
|
|
||||||
def on_output_removed(self, _, event):
|
def on_output_removed(self, _, event):
|
||||||
"""Handle output removal"""
|
"""Handle output removal"""
|
||||||
removed_id = event.data[0]
|
removed_id = event.data[0]
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user