204 files changed
+51505
No files matched your search
@@ -0,0 +1,411 @@
|
||||
import json
|
||||
import os
|
||||
import subprocess
|
||||
|
||||
from fabric.hyprland.widgets import HyprlandActiveWindow as ActiveWindow
|
||||
from fabric.utils import FormattedString
|
||||
from fabric.widgets.box import Box
|
||||
from fabric.widgets.button import Button
|
||||
from fabric.widgets.centerbox import CenterBox
|
||||
from fabric.widgets.label import Label
|
||||
|
||||
from modules.about import About, AboutApp
|
||||
from utils.roam import modus_service
|
||||
from widgets.dropdown import ModusDropdown, dropdown_divider
|
||||
from widgets.mousecapture import DropDownMouseCapture
|
||||
from utils.app_name_resolver import format_window
|
||||
|
||||
|
||||
def show_about_app():
|
||||
"""Show about dialog for current active application"""
|
||||
try:
|
||||
# Use modus_service's Hyprland connection to get current window info
|
||||
wmclass = ""
|
||||
title = ""
|
||||
|
||||
if (
|
||||
hasattr(modus_service, "_hyprland_connection")
|
||||
and modus_service._hyprland_connection
|
||||
):
|
||||
window_data = modus_service._hyprland_connection.send_command(
|
||||
"j/activewindow"
|
||||
).reply
|
||||
if window_data:
|
||||
window_info = json.loads(window_data.decode("utf-8"))
|
||||
wmclass = window_info.get("class", "")
|
||||
title = window_info.get("title", "")
|
||||
|
||||
# Don't show about dialog if there's no active window (Finder state)
|
||||
if not wmclass and not title:
|
||||
return
|
||||
|
||||
app_name = modus_service.current_active_app_name or "Finder"
|
||||
# Don't show about dialog for Finder
|
||||
if app_name == "Finder":
|
||||
return
|
||||
|
||||
about_window = AboutApp(app_name=app_name, wmclass=wmclass)
|
||||
about_window.toggle(None)
|
||||
except Exception:
|
||||
# Fallback: only show if we have a real app name
|
||||
app_name = modus_service.current_active_app_name or ""
|
||||
if app_name and app_name != "Finder":
|
||||
about_window = AboutApp(app_name=app_name, wmclass="")
|
||||
about_window.toggle(None)
|
||||
|
||||
|
||||
def dropdown_option(
|
||||
label: str = "",
|
||||
keybind: str = "",
|
||||
on_click='echo "ModusPanelDropdown Action"',
|
||||
on_clicked=None,
|
||||
):
|
||||
def on_click_subthread(button):
|
||||
# Execute the action first
|
||||
if on_clicked:
|
||||
on_clicked(button)
|
||||
else:
|
||||
subprocess.Popen(
|
||||
f"nohup {on_click} &",
|
||||
shell=True,
|
||||
stdout=subprocess.DEVNULL,
|
||||
stderr=subprocess.DEVNULL,
|
||||
)
|
||||
|
||||
# Hide dropdown by finding the current visible dropdown and calling its hide method
|
||||
from widgets.dropdown import dropdowns
|
||||
|
||||
for dropdown in dropdowns:
|
||||
if dropdown.is_visible() and hasattr(dropdown, "hide_via_mousecapture"):
|
||||
dropdown.hide_via_mousecapture()
|
||||
break
|
||||
|
||||
return Button(
|
||||
child=CenterBox(
|
||||
start_children=[
|
||||
Label(label=label, h_align="start", name="dropdown-option-label"),
|
||||
],
|
||||
end_children=[
|
||||
Label(label=keybind, h_align="end", name="dropdown-option-keybind")
|
||||
],
|
||||
orientation="horizontal",
|
||||
h_align="fill",
|
||||
h_expand=True,
|
||||
v_expand=True,
|
||||
),
|
||||
name="dropdown-option",
|
||||
h_align="fill",
|
||||
on_clicked=on_click_subthread,
|
||||
h_expand=True,
|
||||
v_expand=True,
|
||||
)
|
||||
|
||||
|
||||
class SystemDropdown(ModusDropdown):
|
||||
def __init__(self, parent, **kwargs):
|
||||
super().__init__(
|
||||
dropdown_id="os-menu",
|
||||
parent=parent,
|
||||
dropdown_children=[
|
||||
dropdown_option(
|
||||
"About this PC", on_clicked=lambda _: About().toggle(_)
|
||||
),
|
||||
dropdown_divider("---------------------"),
|
||||
dropdown_option(
|
||||
"System Settings...",
|
||||
# TODO: Open Modus own setting
|
||||
# on_click="xdg-open settings",
|
||||
),
|
||||
dropdown_divider("---------------------"),
|
||||
dropdown_option("Force Quit", "", "hyprctl kill"),
|
||||
dropdown_divider("---------------------"),
|
||||
dropdown_option("Sleep", "", "systemctl suspend"),
|
||||
dropdown_option("Restart...", "", "systemctl reboot"),
|
||||
dropdown_option("Shut Down...", "", "shutdown now"),
|
||||
dropdown_divider("---------------------"),
|
||||
dropdown_option("Lock Screen", " L", "hyprlock"),
|
||||
],
|
||||
**kwargs,
|
||||
)
|
||||
|
||||
|
||||
class MenuBarDropdowns:
|
||||
def __init__(self, parent):
|
||||
self.parent = parent
|
||||
|
||||
# System dropdown
|
||||
self.system_dropdown = SystemDropdown(parent=parent)
|
||||
self.menu_button_dropdown = DropDownMouseCapture(
|
||||
layer="bottom", child_window=self.system_dropdown
|
||||
)
|
||||
self.menu_button = Button(
|
||||
label="Modus",
|
||||
name="menu-button",
|
||||
style_classes="button",
|
||||
on_clicked=lambda _: self.menu_button_dropdown.toggle_mousecapture(),
|
||||
)
|
||||
self.menu_button_dropdown.child_window.set_pointing_to(self.menu_button)
|
||||
|
||||
# Global menu dropdowns
|
||||
self.global_title_menu_about = dropdown_option(
|
||||
f"About {modus_service.current_active_app_name}",
|
||||
on_clicked=lambda _: show_about_app(),
|
||||
)
|
||||
self.global_menu_title = DropDownMouseCapture(
|
||||
layer="bottom",
|
||||
child_window=ModusDropdown(
|
||||
dropdown_id="global-menu-title",
|
||||
parent=parent,
|
||||
dropdown_children=[self.global_title_menu_about],
|
||||
),
|
||||
)
|
||||
|
||||
self.global_menu_file = None
|
||||
self.global_menu_edit = None
|
||||
self.global_menu_view = DropDownMouseCapture(
|
||||
layer="bottom",
|
||||
child_window=ModusDropdown(
|
||||
dropdown_id="global-menu-view",
|
||||
parent=parent,
|
||||
dropdown_children=[
|
||||
dropdown_option(
|
||||
"Enter Full Screen",
|
||||
on_click="hyprctl dispatch fullscreen",
|
||||
),
|
||||
],
|
||||
),
|
||||
)
|
||||
self.global_menu_go = None
|
||||
self.global_menu_window = DropDownMouseCapture(
|
||||
layer="bottom",
|
||||
child_window=ModusDropdown(
|
||||
dropdown_id="global-menu-window",
|
||||
parent=parent,
|
||||
dropdown_children=[
|
||||
dropdown_option(
|
||||
"Zoom In",
|
||||
" +",
|
||||
on_click="hyprctl -q keyword cursor:zoom_factor $(hyprctl getoption cursor:zoom_factor -j | jq '.float * 1.1')",
|
||||
),
|
||||
dropdown_option(
|
||||
"Zoom Out",
|
||||
" -",
|
||||
on_click="hyprctl -q keyword cursor:zoom_factor $(hyprctl getoption cursor:zoom_factor -j | jq '(.float * 0.9) | if . < 1 then 1 else . end')",
|
||||
),
|
||||
dropdown_divider("---------------------"),
|
||||
dropdown_option(
|
||||
"Move Window to Left",
|
||||
on_click="hyprctl dispatch movewindow l",
|
||||
),
|
||||
dropdown_option(
|
||||
"Move Window to Right",
|
||||
on_click="hyprctl dispatch movewindow r",
|
||||
),
|
||||
dropdown_option(
|
||||
"Cycle Through Windows",
|
||||
on_click="hyprctl dispatch cyclenext",
|
||||
),
|
||||
dropdown_divider("---------------------"),
|
||||
dropdown_option(
|
||||
"Float", on_click="hyprctl dispatch togglefloating"
|
||||
),
|
||||
dropdown_option("Quit", on_click="hyprctl dispatch killactive"),
|
||||
dropdown_option("Pseudo", on_click="hyprctl dispatch pseudo"),
|
||||
dropdown_option(
|
||||
"Toggle Split", on_click="hyprctl dispatch togglesplit"
|
||||
),
|
||||
dropdown_option("Center", on_click="hyprctl dispatch centerwindow"),
|
||||
dropdown_option("Group", on_click="hyprctl dispatch togglegroup"),
|
||||
dropdown_option(
|
||||
"Pin",
|
||||
on_clicked=lambda _: subprocess.run(
|
||||
"bash ~/.config/scripts/winpin.sh", shell=True
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
)
|
||||
|
||||
self.global_menu_help = DropDownMouseCapture(
|
||||
layer="bottom",
|
||||
child_window=ModusDropdown(
|
||||
dropdown_id="global-menu-help",
|
||||
parent=parent,
|
||||
dropdown_children=[
|
||||
dropdown_option(
|
||||
"Modus",
|
||||
on_click="xdg-open https://github.com/S4NKALP/Modus/issues",
|
||||
),
|
||||
dropdown_divider("---------------------"),
|
||||
dropdown_option(
|
||||
"Hyprland Wiki", on_click="xdg-open https://wiki.hyprland.org/"
|
||||
),
|
||||
],
|
||||
),
|
||||
)
|
||||
|
||||
# Create menu buttons
|
||||
modus_service.connect(
|
||||
"current-active-app-name-changed",
|
||||
lambda _, value: self.global_title_menu_about.set_property(
|
||||
"label", f"About {value}"
|
||||
),
|
||||
)
|
||||
|
||||
# Connect to active app name changes to update the title button
|
||||
modus_service.connect("current-active-app-name-changed", self._on_active_app_changed)
|
||||
|
||||
self.global_menu_button_title = Button(
|
||||
child=ActiveWindow(
|
||||
formatter=FormattedString(
|
||||
"{ format_window(win_title, win_class) }",
|
||||
format_window=format_window,
|
||||
)
|
||||
),
|
||||
name="global-title-button",
|
||||
style_classes="button",
|
||||
on_clicked=self._on_title_button_clicked,
|
||||
)
|
||||
|
||||
self.global_menu_title.child_window.set_pointing_to(
|
||||
self.global_menu_button_title
|
||||
)
|
||||
|
||||
self.global_menu_button_file = Button(
|
||||
label="File", name="global-menu-button-file", style_classes="button"
|
||||
)
|
||||
self.global_menu_button_edit = Button(
|
||||
label="Edit", name="global-menu-button-edit", style_classes="button"
|
||||
)
|
||||
self.global_menu_button_view = Button(
|
||||
label="View",
|
||||
name="global-menu-button-view",
|
||||
style_classes="button",
|
||||
on_clicked=lambda _: self.global_menu_view.toggle_mousecapture(),
|
||||
)
|
||||
self.global_menu_view.child_window.set_pointing_to(self.global_menu_button_view)
|
||||
self.global_menu_button_go = Button(
|
||||
label="Go", name="global-menu-button-go", style_classes="button"
|
||||
)
|
||||
self.global_menu_button_window = Button(
|
||||
label="Window",
|
||||
name="global-menu-button-window",
|
||||
style_classes="button",
|
||||
on_clicked=lambda _: self.global_menu_window.toggle_mousecapture(),
|
||||
)
|
||||
self.global_menu_window.child_window.set_pointing_to(
|
||||
self.global_menu_button_window
|
||||
)
|
||||
self.global_menu_button_help = Button(
|
||||
label="Help",
|
||||
name="global-menu-button-help",
|
||||
style_classes="button",
|
||||
on_clicked=lambda _: self.global_menu_help.toggle_mousecapture(),
|
||||
)
|
||||
self.global_menu_help.child_window.set_pointing_to(self.global_menu_button_help)
|
||||
|
||||
modus_service.connect("current-dropdown-changed", self.changed_dropdown)
|
||||
modus_service.connect("dropdowns-hide-changed", self.hide_dropdowns)
|
||||
|
||||
def _on_title_button_clicked(self, _):
|
||||
"""Handle title button click - only show dropdown if there's an active window"""
|
||||
try:
|
||||
# Use modus_service's Hyprland connection to get current window info
|
||||
if (
|
||||
hasattr(modus_service, "_hyprland_connection")
|
||||
and modus_service._hyprland_connection
|
||||
):
|
||||
window_data = modus_service._hyprland_connection.send_command(
|
||||
"j/activewindow"
|
||||
).reply
|
||||
if window_data:
|
||||
window_info = json.loads(window_data.decode("utf-8"))
|
||||
wmclass = window_info.get("class", "")
|
||||
title = window_info.get("title", "")
|
||||
|
||||
# Only show dropdown if there's an active window (not Finder)
|
||||
if wmclass or title:
|
||||
self.global_menu_title.toggle_mousecapture()
|
||||
return
|
||||
|
||||
# Fallback: check if current_active_app_name is not "Finder"
|
||||
if (
|
||||
modus_service.current_active_app_name
|
||||
and modus_service.current_active_app_name != "Finder"
|
||||
):
|
||||
self.global_menu_title.toggle_mousecapture()
|
||||
except Exception:
|
||||
# If we can't get window info, don't show dropdown
|
||||
pass
|
||||
|
||||
def _on_active_app_changed(self, _, value):
|
||||
"""Handle active app name changes"""
|
||||
# Update the "About" menu item label
|
||||
self.global_title_menu_about.set_property("label", f"About {value}")
|
||||
|
||||
def hide_dropdowns(self, *_):
|
||||
self.menu_button.remove_style_class("active")
|
||||
self.global_menu_button_edit.remove_style_class("active")
|
||||
self.global_menu_button_file.remove_style_class("active")
|
||||
self.global_menu_button_go.remove_style_class("active")
|
||||
self.global_menu_button_help.remove_style_class("active")
|
||||
self.global_menu_button_title.remove_style_class("active")
|
||||
self.global_menu_button_view.remove_style_class("active")
|
||||
self.global_menu_button_window.remove_style_class("active")
|
||||
|
||||
def changed_dropdown(self, _, dropdown_id):
|
||||
self.hide_dropdowns(_, True)
|
||||
match dropdown_id:
|
||||
case "os-menu":
|
||||
self.menu_button.add_style_class("active")
|
||||
case "global-menu-edit":
|
||||
self.global_menu_button_edit.add_style_class("active")
|
||||
case "global-menu-file":
|
||||
self.global_menu_button_file.add_style_class("active")
|
||||
case "global-menu-go":
|
||||
self.global_menu_button_go.add_style_class("active")
|
||||
case "global-menu-help":
|
||||
self.global_menu_button_help.add_style_class("active")
|
||||
case "global-menu-title":
|
||||
self.global_menu_button_title.add_style_class("active")
|
||||
case "global-menu-view":
|
||||
self.global_menu_button_view.add_style_class("active")
|
||||
case "global-menu-window":
|
||||
self.global_menu_button_window.add_style_class("active")
|
||||
case _:
|
||||
pass
|
||||
|
||||
|
||||
class MenuBar(Box):
|
||||
"""Main MenuBar widget that contains all menu buttons"""
|
||||
|
||||
def __init__(self, parent_window=None, **kwargs):
|
||||
# Extract parent_window from kwargs if not provided as parameter
|
||||
if parent_window is None:
|
||||
parent_window = kwargs.pop("parent_window", None)
|
||||
|
||||
super().__init__(name="menubar", orientation="horizontal", spacing=0, **kwargs)
|
||||
|
||||
# Create the dropdown system
|
||||
self.dropdown_system = MenuBarDropdowns(parent=parent_window)
|
||||
|
||||
# Add all the menu buttons to the menubar
|
||||
self.children = [
|
||||
self.dropdown_system.global_menu_button_title,
|
||||
self.dropdown_system.global_menu_button_file,
|
||||
self.dropdown_system.global_menu_button_edit,
|
||||
self.dropdown_system.global_menu_button_view,
|
||||
self.dropdown_system.global_menu_button_go,
|
||||
self.dropdown_system.global_menu_button_window,
|
||||
self.dropdown_system.global_menu_button_help,
|
||||
]
|
||||
|
||||
def show_system_dropdown(self, imac_button):
|
||||
self.dropdown_system.menu_button_dropdown.child_window.set_pointing_to(
|
||||
imac_button
|
||||
)
|
||||
mouse_capture = self.dropdown_system.menu_button_dropdown
|
||||
if mouse_capture.is_visible():
|
||||
mouse_capture.set_child_window_visible(False)
|
||||
else:
|
||||
mouse_capture.set_child_window_visible(True)
|
||||
Reference in new issue
Block a user