♻️ refactor(dock): overhaul dock implementation for improved performance and maintainability
This commit is contained in:
1 parent
8ba98e33d3
commit
4852fa01e2
22 files changed
+876
-2755
No files matched your search
@@ -7,7 +7,6 @@ config/assets/config.json
|
||||
config/assets/accounts.json
|
||||
config/assets/passwords.json
|
||||
config/assets/bookmarks.json
|
||||
config/assets/screentime.json
|
||||
config/hypr/modus.conf
|
||||
config/hypr/colors.conf
|
||||
fabric/**
|
||||
|
||||
+6
-34
@@ -1,34 +1,6 @@
|
||||
{
|
||||
"pinned_apps": [
|
||||
{
|
||||
"name": "Bulk Rename",
|
||||
"display_name": "Bulk Rename",
|
||||
"window_class": null,
|
||||
"executable": "thunar",
|
||||
"command_line": "thunar --bulk-rename %F"
|
||||
},
|
||||
{
|
||||
"name": "Ghostty",
|
||||
"display_name": "Ghostty",
|
||||
"window_class": "com.mitchellh.ghostty",
|
||||
"executable": "ghostty",
|
||||
"command_line": "ghostty"
|
||||
},
|
||||
{
|
||||
"name": "Zen Browser",
|
||||
"display_name": "Zen Browser",
|
||||
"window_class": "zen",
|
||||
"executable": "/opt/zen-browser-bin/zen-bin",
|
||||
"command_line": "/opt/zen-browser-bin/zen-bin %u"
|
||||
},
|
||||
{
|
||||
"name": "Visual Studio Code",
|
||||
"display_name": "Visual Studio Code",
|
||||
"window_class": "Code",
|
||||
"executable": "/usr/bin/code",
|
||||
"command_line": "/usr/bin/code %F",
|
||||
"icon_name": "visual-studio-code"
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
[
|
||||
"zen",
|
||||
"kitty",
|
||||
"code",
|
||||
"Vesktop"
|
||||
]
|
||||
@@ -1,9 +0,0 @@
|
||||
<svg version="1.1" viewBox="0 0 22 22" xmlns="http://www.w3.org/2000/svg">
|
||||
<defs>
|
||||
<style id="current-color-scheme" type="text/css">.ColorScheme-Text {
|
||||
color:#dedede;
|
||||
}</style>
|
||||
</defs>
|
||||
<path class="ColorScheme-Text" d="m6.1738 5.6631c0.37981 1e-7 0.54189 0.12418 0.65234 0.18555 0.0072 0.00447 0.01438 0.00902 0.02148 0.013672l6.9356 4.0957c0.07518 0.043562 0.20874 0.10765 0.36914 0.30469 0.16225 0.1993 0.25781 0.52881 0.25781 0.73633 0 0.20754-0.08765 0.52075-0.24219 0.7207-0.15288 0.1978-0.29598 0.27643-0.38477 0.32812l-6.9355 4.0957c-0.0071 0.0046-0.01426 0.0092-0.02148 0.01367-0.16196 0.09008-0.38778 0.17969-0.65234 0.17969-0.25637-5e-6 -0.58772-0.09652-0.83203-0.3418-0.24432-0.24527-0.3418-0.587-0.3418-0.84766v-8.2871c0-0.26064 0.08983-0.5862 0.32031-0.83203 0.23049-0.24583 0.57064-0.36523 0.85352-0.36523zm0 1c-0.09815 0-0.17383 0.068844-0.17383 0.19727v8.2871c0 0.12841 0.07568 0.18945 0.17383 0.18945 0.04538 0 0.09802-0.01687 0.16602-0.05469l6.9355-4.0957c0.09064-0.05286 0.13477-0.09682 0.13477-0.1875s-0.04412-0.12878-0.13477-0.18164l-6.9355-4.0957c-0.06799-0.037776-0.12063-0.058594-0.16602-0.058594z" fill="currentColor"/>
|
||||
<rect class="ColorScheme-Text" transform="scale(-1,1)" x="-17" y="6" width="1" height="10" rx=".5" ry=".5" fill="currentColor"/>
|
||||
</svg>
|
||||
|
Before Width: | Height: | Size: 1.3 KiB |
@@ -1,14 +0,0 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 22 22">
|
||||
<defs id="defs3051">
|
||||
<style type="text/css" id="current-color-scheme">
|
||||
.ColorScheme-Text {
|
||||
color:#dedede;
|
||||
}
|
||||
</style>
|
||||
</defs>
|
||||
<path
|
||||
style="fill:currentColor;fill-opacity:1;stroke:none"
|
||||
d="M 16 5 L 16 7 L 3 7 L 3 8 L 16 8 L 16 10 L 19 7.5 L 16 5 z M 16 12 L 16 14 L 3 14 L 3 15 L 16 15 L 16 17 L 19 14.5 L 16 12 z "
|
||||
class="ColorScheme-Text"
|
||||
/>
|
||||
</svg>
|
||||
|
Before Width: | Height: | Size: 465 B |
@@ -1,11 +0,0 @@
|
||||
<svg version="1.1" viewBox="0 0 22 22" xmlns="http://www.w3.org/2000/svg">
|
||||
<defs>
|
||||
<style id="current-color-scheme" type="text/css">.ColorScheme-Text {
|
||||
color:#dedede;
|
||||
}</style>
|
||||
</defs>
|
||||
<g class="ColorScheme-Text" fill="currentColor">
|
||||
<path d="m9.5 8c-0.277 0-0.5 0.223-0.5 0.5v5c0 0.277 0.223 0.5 0.5 0.5s0.5-0.223 0.5-0.5v-5c0-0.277-0.223-0.5-0.5-0.5zm3 0c-0.277 0-0.5 0.223-0.5 0.5v5c0 0.277 0.223 0.5 0.5 0.5s0.5-0.223 0.5-0.5v-5c0-0.277-0.223-0.5-0.5-0.5z"/>
|
||||
<path d="m11 3a8 8 0 0 0-8 8 8 8 0 0 0 8 8 8 8 0 0 0 8-8 8 8 0 0 0-8-8zm0 1a7 7 0 0 1 7 7 7 7 0 0 1-7 7 7 7 0 0 1-7-7 7 7 0 0 1 7-7z"/>
|
||||
</g>
|
||||
</svg>
|
||||
|
Before Width: | Height: | Size: 634 B |
@@ -1,9 +0,0 @@
|
||||
<svg version="1.1" viewBox="0 0 22 22" xmlns="http://www.w3.org/2000/svg">
|
||||
<defs>
|
||||
<style id="current-color-scheme" type="text/css">.ColorScheme-Text {
|
||||
color:#dedede;
|
||||
}</style>
|
||||
</defs>
|
||||
<path class="ColorScheme-Text" d="m11 3a8 8 0 0 0-8 8 8 8 0 0 0 8 8 8 8 0 0 0 8-8 8 8 0 0 0-8-8zm0 1a7 7 0 0 1 7 7 7 7 0 0 1-7 7 7 7 0 0 1-7-7 7 7 0 0 1 7-7z" fill="currentColor"/>
|
||||
<path class="ColorScheme-Text" d="m9.498 7.5723c-0.26595 0.011578-0.49805 0.18369-0.49805 0.46875v5.9063c0 0.41453 0.46559 0.61778 0.86328 0.38086l4.873-2.8691c0.35533-0.20313 0.34686-0.71884 0-0.92188l-4.873-2.877c-0.11636-0.066104-0.24435-0.093154-0.36523-0.087891z" fill="currentColor"/>
|
||||
</svg>
|
||||
|
Before Width: | Height: | Size: 683 B |
@@ -1,9 +0,0 @@
|
||||
<svg version="1.1" viewBox="0 0 22 22" xmlns="http://www.w3.org/2000/svg">
|
||||
<defs>
|
||||
<style id="current-color-scheme" type="text/css">.ColorScheme-Text {
|
||||
color:#dedede;
|
||||
}</style>
|
||||
</defs>
|
||||
<path class="ColorScheme-Text" d="m15.826 5.6631c-0.37981 1e-7 -0.54189 0.12418-0.65234 0.18555-0.0072 0.00447-0.01438 0.00902-0.02148 0.013672l-6.9356 4.0957c-0.075177 0.043562-0.20874 0.10765-0.36914 0.30469-0.16225 0.1993-0.25781 0.52881-0.25781 0.73633 0 0.20754 0.087648 0.52075 0.24219 0.7207 0.15287 0.1978 0.29598 0.27643 0.38477 0.32812l6.9355 4.0957c0.0071 0.0046 0.01426 0.0092 0.02148 0.01367 0.16196 0.09008 0.38778 0.17969 0.65234 0.17969 0.25637-5e-6 0.58772-0.09652 0.83203-0.3418 0.24432-0.24527 0.3418-0.587 0.3418-0.84766v-8.2871c0-0.26064-0.08983-0.5862-0.32031-0.83203-0.23049-0.24583-0.57064-0.36523-0.85352-0.36523zm0 1c0.09815 0 0.17383 0.068844 0.17383 0.19727v8.2871c0 0.12841-0.07568 0.18945-0.17383 0.18945-0.04538 0-0.09802-0.01687-0.16602-0.05469l-6.9355-4.0957c-0.09064-0.05286-0.13477-0.09682-0.13477-0.1875s0.04412-0.12878 0.13477-0.18164l6.9355-4.0957c0.06799-0.037776 0.12063-0.058594 0.16602-0.058594z" fill="currentColor"/>
|
||||
<rect class="ColorScheme-Text" x="5" y="6" width="1" height="10" rx=".5" ry=".5" fill="currentColor"/>
|
||||
</svg>
|
||||
|
Before Width: | Height: | Size: 1.2 KiB |
@@ -1,14 +0,0 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 22 22">
|
||||
<defs id="defs3051">
|
||||
<style type="text/css" id="current-color-scheme">
|
||||
.ColorScheme-Text {
|
||||
color:#dedede;
|
||||
}
|
||||
</style>
|
||||
</defs>
|
||||
<path
|
||||
style="fill:currentColor;fill-opacity:1;stroke:none"
|
||||
d="M 16 5 L 16 7 L 13 7 C 10.784 7 9 8.784 9 11 C 9 12.662 7.662 14 6 14 L 3 14 L 3 15 L 6 15 C 8.216 15 10 13.216 10 11 C 10 9.338 11.338 8 13 8 L 16 8 L 16 10 L 19 7.5 L 16 5 z M 3 7 L 3 8 L 6 8 C 6.8536128 8 7.6168144 8.3572581 8.1621094 8.9257812 C 8.2578781 8.5814037 8.3956215 8.2568349 8.5742188 7.9570312 C 7.8779048 7.3680394 6.9875937 7 6 7 L 3 7 z M 16 12 L 16 14 L 13 14 C 12.146387 14 11.383186 13.642742 10.837891 13.074219 C 10.742121 13.418597 10.604379 13.743165 10.425781 14.042969 C 11.122095 14.631961 12.012406 15 13 15 L 16 15 L 16 17 L 19 14.5 L 16 12 z "
|
||||
class="ColorScheme-Text"
|
||||
/>
|
||||
</svg>
|
||||
|
Before Width: | Height: | Size: 914 B |
@@ -1,171 +0,0 @@
|
||||
{
|
||||
"todos": [
|
||||
{
|
||||
"id": 14,
|
||||
"title": "yo",
|
||||
"description": "",
|
||||
"priority": "low",
|
||||
"category": "",
|
||||
"due_date": null,
|
||||
"completed": false,
|
||||
"created": "2025-06-26T16:51:06.643095",
|
||||
"completed_at": null
|
||||
},
|
||||
{
|
||||
"id": 16,
|
||||
"title": "Medium priority task",
|
||||
"description": "",
|
||||
"priority": "medium",
|
||||
"category": "normal",
|
||||
"due_date": null,
|
||||
"completed": false,
|
||||
"created": "2025-06-26T16:52:59.579365",
|
||||
"completed_at": null
|
||||
},
|
||||
{
|
||||
"id": 17,
|
||||
"title": "Low priority task",
|
||||
"description": "",
|
||||
"priority": "low",
|
||||
"category": "later",
|
||||
"due_date": null,
|
||||
"completed": false,
|
||||
"created": "2025-06-26T16:52:59.583278",
|
||||
"completed_at": null
|
||||
},
|
||||
{
|
||||
"id": 18,
|
||||
"title": "🔥 URGENT: Fix critical bug",
|
||||
"description": "",
|
||||
"priority": "high",
|
||||
"category": "work",
|
||||
"due_date": null,
|
||||
"completed": true,
|
||||
"created": "2025-06-26T16:53:51.412081",
|
||||
"completed_at": "2025-06-26T16:53:51.418575"
|
||||
},
|
||||
{
|
||||
"id": 19,
|
||||
"title": "📝 Review documentation",
|
||||
"description": "",
|
||||
"priority": "medium",
|
||||
"category": "work",
|
||||
"due_date": null,
|
||||
"completed": false,
|
||||
"created": "2025-06-26T16:53:51.413594",
|
||||
"completed_at": null
|
||||
},
|
||||
{
|
||||
"id": 20,
|
||||
"title": "🧹 Clean desk",
|
||||
"description": "",
|
||||
"priority": "low",
|
||||
"category": "personal",
|
||||
"due_date": null,
|
||||
"completed": false,
|
||||
"created": "2025-06-26T16:53:51.415181",
|
||||
"completed_at": null
|
||||
},
|
||||
{
|
||||
"id": 21,
|
||||
"title": "Test high priority",
|
||||
"description": "",
|
||||
"priority": "high",
|
||||
"category": "test",
|
||||
"due_date": null,
|
||||
"completed": true,
|
||||
"created": "2025-06-26T16:55:12.629834",
|
||||
"completed_at": "2025-06-26T17:00:48.989919"
|
||||
},
|
||||
{
|
||||
"id": 22,
|
||||
"title": "Test medium priority",
|
||||
"description": "",
|
||||
"priority": "medium",
|
||||
"category": "test",
|
||||
"due_date": null,
|
||||
"completed": false,
|
||||
"created": "2025-06-26T16:55:12.631496",
|
||||
"completed_at": null
|
||||
},
|
||||
{
|
||||
"id": 23,
|
||||
"title": "Test low priority",
|
||||
"description": "",
|
||||
"priority": "low",
|
||||
"category": "test",
|
||||
"due_date": null,
|
||||
"completed": false,
|
||||
"created": "2025-06-26T16:55:12.632521",
|
||||
"completed_at": null
|
||||
},
|
||||
{
|
||||
"id": 24,
|
||||
"title": "High priority task",
|
||||
"description": "",
|
||||
"priority": "high",
|
||||
"category": "test",
|
||||
"due_date": null,
|
||||
"completed": true,
|
||||
"created": "2025-06-26T16:57:15.780304",
|
||||
"completed_at": "2025-06-26T16:57:15.800393"
|
||||
},
|
||||
{
|
||||
"id": 25,
|
||||
"title": "Medium priority task",
|
||||
"description": "",
|
||||
"priority": "medium",
|
||||
"category": "test",
|
||||
"due_date": null,
|
||||
"completed": false,
|
||||
"created": "2025-06-26T16:57:15.783358",
|
||||
"completed_at": null
|
||||
},
|
||||
{
|
||||
"id": 26,
|
||||
"title": "Low priority task",
|
||||
"description": "",
|
||||
"priority": "low",
|
||||
"category": "test",
|
||||
"due_date": null,
|
||||
"completed": false,
|
||||
"created": "2025-06-26T16:57:15.792488",
|
||||
"completed_at": null
|
||||
},
|
||||
{
|
||||
"id": 27,
|
||||
"title": "🔥 High priority",
|
||||
"description": "",
|
||||
"priority": "high",
|
||||
"category": "test",
|
||||
"due_date": null,
|
||||
"completed": true,
|
||||
"created": "2025-06-26T16:57:50.943800",
|
||||
"completed_at": "2025-06-26T17:00:50.482300"
|
||||
},
|
||||
{
|
||||
"id": 28,
|
||||
"title": "📝 Medium priority",
|
||||
"description": "",
|
||||
"priority": "medium",
|
||||
"category": "test",
|
||||
"due_date": null,
|
||||
"completed": false,
|
||||
"created": "2025-06-26T16:57:50.952343",
|
||||
"completed_at": null
|
||||
},
|
||||
{
|
||||
"id": 29,
|
||||
"title": "🧹 Low priority",
|
||||
"description": "",
|
||||
"priority": "low",
|
||||
"category": "test",
|
||||
"due_date": null,
|
||||
"completed": false,
|
||||
"created": "2025-06-26T16:57:50.968381",
|
||||
"completed_at": null
|
||||
}
|
||||
],
|
||||
"next_id": 30,
|
||||
"last_modified": "2025-06-26T17:00:50.482384"
|
||||
}
|
||||
+5
-4
@@ -56,7 +56,7 @@ CURRENT_WIDTH = screen.get_width()
|
||||
CURRENT_HEIGHT = screen.get_height()
|
||||
|
||||
|
||||
WALLPAPERS_DIR_DEFAULT = get_relative_path("../assets/wallpapers_example/")
|
||||
WALLPAPERS_DIR_DEFAULT = os.path.expanduser(f"~/Pictures/wallpapers/")
|
||||
CONFIG_FILE = get_relative_path("../config/assets/config.json")
|
||||
MATUGEN_STATE_FILE = os.path.join(CONFIG_DIR, "matugen")
|
||||
|
||||
@@ -91,8 +91,7 @@ if os.path.exists(CONFIG_FILE):
|
||||
DOCK_ENABLED = config.get("dock_enabled", True)
|
||||
DOCK_AUTO_HIDE = config.get("dock_auto_hide", True)
|
||||
DOCK_ALWAYS_OCCLUDED = config.get("dock_always_occluded", False)
|
||||
DOCK_THEME = config.get("dock_theme", "Pills")
|
||||
DOCK_ICON_SIZE = config.get("dock_icon_size", 28)
|
||||
DOCK_ICON_SIZE = config.get("dock_icon_size", 60)
|
||||
WORKSPACE_NUMS = config.get("workspace_nums", False)
|
||||
WORKSPACE_USE_CHINESE_NUMERAL = config.get("workspace_use_chinese_numerals", False)
|
||||
WORKSPACE_DOTS = config.get("workspace_dots", False)
|
||||
@@ -101,6 +100,7 @@ if os.path.exists(CONFIG_FILE):
|
||||
DOCK_HIDE_SPECIAL_WORKSPACE_APPS = config.get(
|
||||
"dock_hide_special_workspace_apps", True
|
||||
)
|
||||
DOCK_PREVIEW_APPS = config.get("dock_preview_apps", False)
|
||||
|
||||
NOTIFICATION_TIMEOUT_STR = config.get("notification_timeout", "5s")
|
||||
NOTIFICATION_TIMEOUT = parse_timeout_string(NOTIFICATION_TIMEOUT_STR)
|
||||
@@ -133,10 +133,11 @@ else:
|
||||
DOCK_AUTO_HIDE = True
|
||||
TERMINAL_COMMAND = "kitty -e"
|
||||
DOCK_THEME = "Pills"
|
||||
DOCK_ICON_SIZE = 30
|
||||
DOCK_ICON_SIZE = 60
|
||||
WINDOW_SWITCHER_ITEMS_PER_ROW = 13
|
||||
DOCK_HIDE_SPECIAL_WORKSPACE = True
|
||||
DOCK_HIDE_SPECIAL_WORKSPACE_APPS = True
|
||||
DOCK_PREVIEW_APPS = False
|
||||
|
||||
NOTIFICATION_TIMEOUT_STR = "5s"
|
||||
NOTIFICATION_TIMEOUT = parse_timeout_string(NOTIFICATION_TIMEOUT_STR)
|
||||
|
||||
@@ -1,9 +0,0 @@
|
||||
<esh name="ControlCenter">
|
||||
<BoxV h_expand="true" name="control-center-widgets">
|
||||
<BoxH name="top-widget" h_expand="true">
|
||||
<BoxV name="wb-widget" style_classes="menu" spacing="5">
|
||||
<Ref>self.bluetooth_man</Ref>
|
||||
</BoxV>
|
||||
</BoxH>
|
||||
</BoxV>
|
||||
</esh>
|
||||
@@ -1,26 +0,0 @@
|
||||
<esh name="ControlCenter">
|
||||
<BoxV h_expand="true" name="control-center-widgets">
|
||||
<BoxH name="top-widget" h_expand="true">
|
||||
<BoxV name="wb-widget" style_classes="menu" spacing="5">
|
||||
<Ref>self.wlan_widget</Ref>
|
||||
<Ref>self.bluetooth_widget</Ref>
|
||||
</BoxV>
|
||||
<BoxH name="dnd-widget" style_classes="menu" h_expand="true">
|
||||
<Ref>self.focus_widget</Ref>
|
||||
</BoxH>
|
||||
</BoxH>
|
||||
<BoxV name="brightness-widget" style_classes="menu" h_expand="true">
|
||||
<Label label="Display" style_classes="title" h_align="start"/>
|
||||
<Ref>self.brightness_scale</Ref>
|
||||
<Label label=" " name="brightness-widget-icon" h_align="start"/>
|
||||
</BoxV>
|
||||
<BoxV name="volume-widget" style_classes="menu" h_expand="true">
|
||||
<Label label="Sound" style_classes="title" h_align="start"/>
|
||||
<Ref>self.volume_scale</Ref>
|
||||
<Label label=" " name="brightness-widget-icon" h_align="start"/>
|
||||
</BoxV>
|
||||
<BoxV>
|
||||
<Ref>self.music_widget</Ref>
|
||||
</BoxV>
|
||||
</BoxV>
|
||||
</esh>
|
||||
@@ -1,9 +0,0 @@
|
||||
<esh name="ControlCenter">
|
||||
<BoxV h_expand="true" name="control-center-widgets">
|
||||
<BoxH name="top-widget" h_expand="true">
|
||||
<BoxV name="wb-widget" style_classes="menu" spacing="5">
|
||||
<Ref>self.wifi_man</Ref>
|
||||
</BoxV>
|
||||
</BoxH>
|
||||
</BoxV>
|
||||
</esh>
|
||||
+630
-942
File diff suppressed because it is too large.
Load diff
File diff suppressed because it is too large.
Load diff
@@ -5,9 +5,9 @@ import subprocess
|
||||
|
||||
from fabric.utils import DesktopApp
|
||||
from fabric.utils.helpers import get_desktop_applications, get_relative_path
|
||||
from modules.dock import Dock
|
||||
from modules.launcher.plugin_base import PluginBase
|
||||
from modules.launcher.result import Result
|
||||
from utils.roam import modus_service
|
||||
|
||||
|
||||
class ApplicationsPlugin(PluginBase):
|
||||
@@ -24,48 +24,33 @@ class ApplicationsPlugin(PluginBase):
|
||||
|
||||
def _pin_application(self, app):
|
||||
"""Pin an application to the dock."""
|
||||
app_data = {
|
||||
k: v
|
||||
for k, v in {
|
||||
"name": app.name,
|
||||
"display_name": app.display_name,
|
||||
"window_class": app.window_class,
|
||||
"executable": app.executable,
|
||||
"command_line": app.command_line,
|
||||
"icon_name": app.icon_name,
|
||||
}.items()
|
||||
if v is not None
|
||||
}
|
||||
|
||||
config_path = get_relative_path("../../../config/assets/dock.json")
|
||||
try:
|
||||
with open(config_path, "r") as file:
|
||||
data = json.load(file)
|
||||
pinned_apps = json.load(file)
|
||||
except (FileNotFoundError, json.JSONDecodeError):
|
||||
data = {"pinned_apps": []}
|
||||
pinned_apps = []
|
||||
|
||||
already_pinned = False
|
||||
for pinned_app in data.get("pinned_apps", []):
|
||||
if (
|
||||
isinstance(pinned_app, dict)
|
||||
and pinned_app.get("name") == app_data["name"]
|
||||
):
|
||||
already_pinned = True
|
||||
pinned_app.update(app_data)
|
||||
break
|
||||
elif isinstance(pinned_app, str) and pinned_app == app_data["name"]:
|
||||
already_pinned = True
|
||||
data["pinned_apps"].remove(pinned_app)
|
||||
data["pinned_apps"].append(app_data)
|
||||
break
|
||||
# Handle legacy format (dict with "pinned_apps" key) and convert to new format (simple list)
|
||||
if isinstance(pinned_apps, dict):
|
||||
pinned_apps = pinned_apps.get("pinned_apps", [])
|
||||
|
||||
if not already_pinned:
|
||||
data.setdefault("pinned_apps", []).append(app_data)
|
||||
# Check if app is already pinned (by name/app_id)
|
||||
app_id = app.name # Use app.name as the identifier
|
||||
if app_id not in pinned_apps:
|
||||
pinned_apps.append(app_id)
|
||||
|
||||
with open(config_path, "w") as file:
|
||||
json.dump(data, file, indent=4)
|
||||
# Save the updated list
|
||||
with open(config_path, "w") as file:
|
||||
json.dump(pinned_apps, file, indent=4)
|
||||
|
||||
Dock.notify_config_change()
|
||||
# Notify dock about the change via modus_service
|
||||
if modus_service:
|
||||
try:
|
||||
dock_apps_json = json.dumps(pinned_apps)
|
||||
modus_service.dock_apps = dock_apps_json
|
||||
except Exception as e:
|
||||
print(f"Failed to notify dock about pinned app change: {e}")
|
||||
|
||||
def query(self, query_string: str) -> List[Result]:
|
||||
"""Search applications based on query."""
|
||||
@@ -156,8 +141,6 @@ class ApplicationsPlugin(PluginBase):
|
||||
pattern = ".*".join(re.escape(char) for char in query)
|
||||
return bool(re.search(pattern, text, re.IGNORECASE))
|
||||
|
||||
import subprocess
|
||||
|
||||
def _launch_application(self, app: DesktopApp):
|
||||
print("Original:", app.command_line)
|
||||
|
||||
|
||||
+24
-80
@@ -1,95 +1,39 @@
|
||||
#dock {
|
||||
background-color: alpha(#fff, 0.05);
|
||||
padding: 8px;
|
||||
margin: 8px 8px 5px 8px;
|
||||
background-color: alpha(#fff, 0.07);
|
||||
padding: 4px 4px;
|
||||
margin: 4px 4px;
|
||||
border: none;
|
||||
border-radius: 16px;
|
||||
/* border: 2px solid var(--surface); */
|
||||
/* transition: all 0.25s cubic-bezier(0.175, 0.885, 0.32, 1.275); */
|
||||
}
|
||||
|
||||
#dock-app-overlay {
|
||||
}
|
||||
#dock-app-overlay label {
|
||||
background-color: alpha(#000, 0.5);
|
||||
font-size: 12px;
|
||||
font-family: "SF Pro Rounded";
|
||||
margin-top: 20px;
|
||||
min-width: 17px;
|
||||
border-radius: 8px;
|
||||
}
|
||||
#dock.vertical {
|
||||
margin: 8px 0 8px 8px;
|
||||
border-radius: 20px 0 0 20px;
|
||||
}
|
||||
|
||||
#dock.vertical.left {
|
||||
margin: 8px 8px 8px 0;
|
||||
border-radius: 0 20px 20px 0;
|
||||
}
|
||||
|
||||
#dock-full {
|
||||
/* transition: all 0.25s cubic-bezier(0.175, 0.885, 0.32, 1.275); */
|
||||
opacity: 1;
|
||||
}
|
||||
|
||||
#dock-separator {
|
||||
padding: 2px;
|
||||
border-radius: 16px;
|
||||
background-color: var(--surface-bright);
|
||||
transition: all 0.25s cubic-bezier(0.5, 0.25, 0, 1);
|
||||
}
|
||||
|
||||
#dock-app-button {
|
||||
padding: 6px;
|
||||
border-radius: 24px;
|
||||
transition: all 0.2s cubic-bezier(0.25, 0.46, 0.45, 0.94);
|
||||
/* box-shadow: 0 0 4px alpha(var(--shadow), 0.5); */
|
||||
/* transition: all 0.25s cubic-bezier(0.175, 0.885, 0.32, 1.275); */
|
||||
border-radius: 16px;
|
||||
}
|
||||
|
||||
#dock-app-button.dock-icon-hover {
|
||||
padding: 4px;
|
||||
border-radius: 28px;
|
||||
background-color: alpha(#fff, 0.15);
|
||||
box-shadow: 0 4px 12px alpha(#000, 0.2);
|
||||
#dock-separator {
|
||||
min-width: 3px;
|
||||
margin: 2px 0;
|
||||
background-color: var(--surface-bright);
|
||||
border-radius: 8px;
|
||||
}
|
||||
|
||||
#dock-app-button:hover {
|
||||
background-color: var(--surface-bright);
|
||||
margin-top: -55px;
|
||||
margin-bottom: 4px;
|
||||
transition: all 0.15s ease-out;
|
||||
}
|
||||
|
||||
#dock-app-button:hover.instance {
|
||||
background-color: var(--outline);
|
||||
#dock-app-button.semi_hovered {
|
||||
margin-top: -20px;
|
||||
margin-bottom: 2px;
|
||||
transition: all 0.15s ease-out;
|
||||
}
|
||||
|
||||
#dock-app-button:active,
|
||||
#dock-app-button:active.instance {
|
||||
background-color: var(--primary);
|
||||
}
|
||||
|
||||
#dock-app-button.instance {
|
||||
border-radius: 12px;
|
||||
}
|
||||
|
||||
#dock-app-dot {
|
||||
background-color: var(--primary);
|
||||
border-radius: 50%;
|
||||
margin-top: 4px;
|
||||
min-width: 4px;
|
||||
min-height: 4px;
|
||||
}
|
||||
|
||||
#dock-corner-left {
|
||||
margin: 0 -8px 0 0;
|
||||
}
|
||||
|
||||
#dock-corner-right {
|
||||
margin: 0 0 0 -8px;
|
||||
}
|
||||
|
||||
#dock-corner-top {
|
||||
margin: 0 0 -8px 0;
|
||||
}
|
||||
|
||||
#dock-corner-bottom {
|
||||
margin: -8px 0 0 0;
|
||||
#dock-app-overlay label {
|
||||
background-color: alpha(#000, 0.5);
|
||||
font-size: 12px;
|
||||
margin-top: 20px;
|
||||
min-width: 15px;
|
||||
border-radius: 8px;
|
||||
}
|
||||
@@ -1,98 +0,0 @@
|
||||
from xml import etree
|
||||
from xml.etree import ElementTree
|
||||
from fabric.utils import get_relative_path
|
||||
import json
|
||||
|
||||
|
||||
def parse(xml):
|
||||
with open(xml, "rb") as f:
|
||||
tree = ElementTree.parse(f)
|
||||
root = tree.getroot()
|
||||
return root
|
||||
|
||||
|
||||
def dxml(root, depth=0):
|
||||
val = []
|
||||
for child in root:
|
||||
attrstring = {}
|
||||
additional = {}
|
||||
if len(child.attrib) == 0:
|
||||
if child.tag == "BoxV":
|
||||
additional["orientation"] = "vertical"
|
||||
elif child.tag == "BoxH":
|
||||
additional["orientation"] = "horizontal"
|
||||
for k, v in child.attrib.items():
|
||||
if v == None:
|
||||
continue
|
||||
if child.tag == "Ref":
|
||||
continue
|
||||
if child.tag == "BoxV":
|
||||
additional["orientation"] = "vertical"
|
||||
elif child.tag == "BoxH":
|
||||
additional["orientation"] = "horizontal"
|
||||
if k == "path":
|
||||
# Handle path resolution more robustly
|
||||
import os
|
||||
|
||||
# Get the directory where the XML file is located
|
||||
current_dir = os.path.dirname(os.path.abspath(__file__))
|
||||
# Go up to project root and then to the specified path
|
||||
project_root = os.path.dirname(current_dir) # Go up from utils/
|
||||
full_path = os.path.join(project_root, v)
|
||||
v = full_path
|
||||
k = "svg_file"
|
||||
if v == "true" or v == "false":
|
||||
v = v == "true"
|
||||
attrstring[k] = v
|
||||
for k, v in additional.items():
|
||||
attrstring[k] = v
|
||||
tag = child.tag
|
||||
if tag in ["BoxV", "BoxH"]:
|
||||
tag = "Box"
|
||||
if tag == "Ref":
|
||||
val.append(
|
||||
{
|
||||
"name": tag,
|
||||
"text": child.text,
|
||||
}
|
||||
)
|
||||
continue
|
||||
val.append(
|
||||
{
|
||||
"name": tag,
|
||||
"attributes": attrstring,
|
||||
"children": dxml(child, depth + 1),
|
||||
}
|
||||
)
|
||||
return val
|
||||
|
||||
|
||||
def parse_child(tags, refs, child, parent):
|
||||
for ch in child:
|
||||
ch = ch.copy()
|
||||
name = ch.get("name", None)
|
||||
attrs = ch.get("attributes", None)
|
||||
if attrs:
|
||||
for attr in attrs:
|
||||
if str(attrs[attr]).isnumeric():
|
||||
attrs[attr] = int(attrs[attr])
|
||||
children = ch.get("children", None)
|
||||
if children:
|
||||
ch.pop("children")
|
||||
if name == "Ref":
|
||||
text = ch.get("text", None)
|
||||
v = refs[text]
|
||||
parent.children = [*parent.children, v]
|
||||
else:
|
||||
v = tags[name](**attrs)
|
||||
if children:
|
||||
v.children = parse_child(tags, refs, children, v)
|
||||
parent.children = [*parent.children, v]
|
||||
return parent.children
|
||||
|
||||
|
||||
def exml(file: str, tags: dict, refs: dict, root):
|
||||
odi = dxml(parse(file))
|
||||
di = root(children=[])
|
||||
parse_child(tags, refs, odi, di)
|
||||
return di
|
||||
@@ -0,0 +1,51 @@
|
||||
import json
|
||||
import os
|
||||
import threading
|
||||
from typing import Dict, List, Optional
|
||||
|
||||
from loguru import logger
|
||||
|
||||
# Threading helper functions
|
||||
|
||||
|
||||
def thread(target, *args, **kwargs) -> threading.Thread:
|
||||
"""
|
||||
Simply run the given function in a thread.
|
||||
The provided args and kwargs will be passed to the function.
|
||||
"""
|
||||
th = threading.Thread(target=target, args=args, kwargs=kwargs, daemon=True)
|
||||
th.start()
|
||||
return th
|
||||
|
||||
|
||||
def run_in_thread(func):
|
||||
"""
|
||||
Decorator to run the decorated function in a thread.
|
||||
"""
|
||||
|
||||
def wrapper(*args, **kwargs):
|
||||
return thread(func, *args, **kwargs)
|
||||
|
||||
return wrapper
|
||||
|
||||
|
||||
@run_in_thread
|
||||
def write_json_file(data: Dict, path: str):
|
||||
try:
|
||||
with open(path, "w") as f:
|
||||
json.dump(data, f, indent=4, ensure_ascii=False)
|
||||
except Exception as e:
|
||||
logger.warning(f"Failed to write json: {e}")
|
||||
|
||||
|
||||
def read_json_file(file_path: str) -> Optional[List]:
|
||||
if not os.path.exists(file_path):
|
||||
logger.error(f"JSON file {file_path} does not exist.")
|
||||
return None
|
||||
|
||||
with open(file_path, "r") as file:
|
||||
try:
|
||||
return json.load(file)
|
||||
except json.JSONDecodeError as e:
|
||||
logger.error(f"Failed to read JSON file {file_path}: {e}")
|
||||
return None
|
||||
-234
@@ -1,234 +0,0 @@
|
||||
# Parameters
|
||||
font_family: str = "tabler-icons"
|
||||
font_weight: str = "normal"
|
||||
|
||||
span: str = f"<span font-family='{font_family}' font-weight='{font_weight}'>"
|
||||
|
||||
# Panels
|
||||
apps: str = ""
|
||||
dashboard: str = ""
|
||||
chat: str = ""
|
||||
windows: str = ""
|
||||
|
||||
# Bar
|
||||
colorpicker: str = ""
|
||||
media: str = ""
|
||||
|
||||
# Toolbox
|
||||
|
||||
toolbox: str = ""
|
||||
ssfull: str = ""
|
||||
ssregion: str = ""
|
||||
sswindow: str = ""
|
||||
screenshots: str = ""
|
||||
screenrecord: str = ""
|
||||
recordings: str = ""
|
||||
ocr: str = "ﳃ"
|
||||
gamemode: str = ""
|
||||
gamemode_off: str = ""
|
||||
close: str = ""
|
||||
|
||||
# Circles
|
||||
temp: str = ""
|
||||
disk: str = ""
|
||||
battery: str = ""
|
||||
memory: str = "流"
|
||||
cpu: str = ""
|
||||
gpu: str = ""
|
||||
swap: str = ""
|
||||
|
||||
|
||||
# AIchat
|
||||
reload: str = ""
|
||||
detach: str = ""
|
||||
|
||||
# Wallpapers
|
||||
add: str = ""
|
||||
sort: str = ""
|
||||
circle: str = ""
|
||||
|
||||
# Chevrons
|
||||
chevron_up: str = ""
|
||||
chevron_down: str = ""
|
||||
chevron_left: str = ""
|
||||
chevron_right: str = ""
|
||||
|
||||
# Power
|
||||
lock: str = ""
|
||||
suspend: str = ""
|
||||
logout: str = ""
|
||||
reboot: str = ""
|
||||
shutdown: str = ""
|
||||
|
||||
# Power Manager
|
||||
power_saving: str = ""
|
||||
power_balanced: str = "勺"
|
||||
power_performance: str = ""
|
||||
charging: str = ""
|
||||
discharging: str = ""
|
||||
alert: str = ""
|
||||
bat_charging: str = ""
|
||||
bat_discharging: str = ""
|
||||
bat_low: str = "="
|
||||
bat_full: str = ""
|
||||
|
||||
|
||||
# Applets
|
||||
|
||||
# Applets
|
||||
wifi_0: str = ""
|
||||
wifi_1: str = ""
|
||||
wifi_2: str = ""
|
||||
wifi_3: str = ""
|
||||
world: str = ""
|
||||
world_off: str = ""
|
||||
bluetooth: str = ""
|
||||
night: str = ""
|
||||
coffee: str = ""
|
||||
notifications: str = ""
|
||||
notifications_dots: str = ""
|
||||
|
||||
wifi_off: str = ""
|
||||
bluetooth_off: str = ""
|
||||
night_off: str = ""
|
||||
notifications_off: str = ""
|
||||
|
||||
notifications_clear: str = ""
|
||||
|
||||
download: str = ""
|
||||
upload: str = ""
|
||||
|
||||
# Bluetooth
|
||||
bluetooth_connected: str = ""
|
||||
bluetooth_disconnected: str = ""
|
||||
|
||||
# Player
|
||||
pause: str = ""
|
||||
play: str = ""
|
||||
stop: str = ""
|
||||
skip_back: str = ""
|
||||
skip_forward: str = ""
|
||||
prev: str = ""
|
||||
next: str = ""
|
||||
shuffle: str = ""
|
||||
repeat: str = ""
|
||||
music: str = ""
|
||||
rewind_backward_5: str = "謹"
|
||||
rewind_forward_5: str = "難"
|
||||
|
||||
next_fill: str = chr(0xF04AD)
|
||||
previous_fill: str = chr(0xF04AE)
|
||||
|
||||
# Volume
|
||||
vol_off: str = ""
|
||||
vol_mute: str = ""
|
||||
vol_medium: str = ""
|
||||
vol_high: str = ""
|
||||
|
||||
mic: str = ""
|
||||
mic_mute: str = ""
|
||||
|
||||
speaker: str = "𐁅"
|
||||
headphones: str = "屮"
|
||||
mic_filled: str = "️"
|
||||
|
||||
# Overview
|
||||
circle_plus: str = ""
|
||||
|
||||
# Pins
|
||||
paperclip: str = ""
|
||||
|
||||
# Clipboard Manager
|
||||
clipboard: str = ""
|
||||
clip_text: str = ""
|
||||
|
||||
# Confirm
|
||||
accept: str = ""
|
||||
cancel: str = ""
|
||||
trash: str = ""
|
||||
|
||||
# Config
|
||||
config: str = ""
|
||||
|
||||
# Icons
|
||||
firefox: str = ""
|
||||
chromium: str = ""
|
||||
spotify: str = "ﺆ"
|
||||
disc: str = "𐀾"
|
||||
disc_off: str = ""
|
||||
|
||||
# Brightness
|
||||
brightness_low: str = ""
|
||||
brightness_medium: str = ""
|
||||
brightness_high: str = ""
|
||||
|
||||
brightness: str = ""
|
||||
|
||||
# Dashboard
|
||||
widgets: str = ""
|
||||
pins: str = ""
|
||||
kanban: str = ""
|
||||
wallpapers: str = ""
|
||||
sparkles: str = ""
|
||||
|
||||
# Misc
|
||||
dot: str = ""
|
||||
palette: str = ""
|
||||
cloud_off: str = ""
|
||||
loader: str = ""
|
||||
radar: str = ""
|
||||
emoji: str = ""
|
||||
keyboard: str = ""
|
||||
terminal: str = ""
|
||||
timer_off: str = ""
|
||||
timer_on: str = ""
|
||||
spy: str = ""
|
||||
calculator: str = ""
|
||||
file: str = ""
|
||||
calendar: str = ""
|
||||
connect: str = ""
|
||||
disconnect: str = "ﴖ"
|
||||
auth: str = ""
|
||||
bookmark: str = ""
|
||||
star: str = ""
|
||||
process: str = ""
|
||||
|
||||
|
||||
music: str = ""
|
||||
# otp
|
||||
check: str = ""
|
||||
bulb: str = ""
|
||||
key: str = ""
|
||||
magnifier: str = ""
|
||||
plus: str = ""
|
||||
info: str = ""
|
||||
|
||||
# Dice
|
||||
dice_1: str = ""
|
||||
dice_2: str = ""
|
||||
dice_3: str = ""
|
||||
dice_4: str = ""
|
||||
dice_5: str = ""
|
||||
dice_6: str = ""
|
||||
|
||||
# search engine
|
||||
reddit: str = ""
|
||||
youtube: str = ""
|
||||
duckduckgo: str = ""
|
||||
github: str = ""
|
||||
stackoverflow: str = ""
|
||||
google: str = ""
|
||||
linkedin: str = ""
|
||||
wikipedia: str = "啕"
|
||||
|
||||
exceptions: list[str] = ["font_family", "font_weight", "span"]
|
||||
|
||||
|
||||
def apply_span() -> None:
|
||||
global_dict = globals()
|
||||
for key in global_dict:
|
||||
if key not in exceptions and not key.startswith("__"):
|
||||
global_dict[key] = f"{span}{global_dict[key]}</span>"
|
||||
|
||||
|
||||
apply_span()
|
||||
@@ -0,0 +1,60 @@
|
||||
import json
|
||||
import warnings
|
||||
from typing import Dict
|
||||
import time
|
||||
from fabric.hyprland import Hyprland
|
||||
from gi.repository import Gdk
|
||||
from functools import lru_cache
|
||||
|
||||
warnings.filterwarnings("ignore", category=DeprecationWarning)
|
||||
|
||||
|
||||
def ttl_lru_cache(seconds_to_live: int, maxsize: int = 128):
|
||||
def wrapper(func):
|
||||
@lru_cache(maxsize)
|
||||
def inner(__ttl, *args, **kwargs):
|
||||
return func(*args, **kwargs)
|
||||
|
||||
return lambda *args, **kwargs: inner(
|
||||
time.time() // seconds_to_live, *args, **kwargs
|
||||
)
|
||||
|
||||
return wrapper
|
||||
|
||||
|
||||
class HyprlandWithMonitors(Hyprland):
|
||||
"""A Hyprland class with additional monitor common."""
|
||||
|
||||
instance = None
|
||||
|
||||
@staticmethod
|
||||
def get_default():
|
||||
if HyprlandWithMonitors.instance is None:
|
||||
HyprlandWithMonitors.instance = HyprlandWithMonitors()
|
||||
|
||||
return HyprlandWithMonitors.instance
|
||||
|
||||
def __init__(self, commands_only: bool = False, **kwargs):
|
||||
self.display: Gdk.Display = Gdk.Display.get_default()
|
||||
super().__init__(commands_only, **kwargs)
|
||||
|
||||
@ttl_lru_cache(100, 5)
|
||||
def get_all_monitors(self) -> Dict:
|
||||
monitors = json.loads(self.send_command("j/monitors").reply)
|
||||
return {monitor["id"]: monitor["name"] for monitor in monitors}
|
||||
|
||||
def get_gdk_monitor_id_from_name(self, plug_name: str) -> int | None:
|
||||
for i in range(self.display.get_n_monitors()):
|
||||
if self.display.get_default_screen().get_monitor_plug_name(i) == plug_name:
|
||||
return i
|
||||
return None
|
||||
|
||||
def get_gdk_monitor_id(self, hyprland_id: int) -> int | None:
|
||||
monitors = self.get_all_monitors()
|
||||
if hyprland_id in monitors:
|
||||
return self.get_gdk_monitor_id_from_name(monitors[hyprland_id])
|
||||
return None
|
||||
|
||||
def get_current_gdk_monitor_id(self) -> int | None:
|
||||
active_workspace = json.loads(self.send_command("j/activeworkspace").reply)
|
||||
return self.get_gdk_monitor_id_from_name(active_workspace["monitor"])
|
||||
+80
-34
@@ -1,26 +1,33 @@
|
||||
import contextlib
|
||||
import gi # type: ignore
|
||||
from gi.repository import Gdk, Gtk, GtkLayerShell # type: ignore
|
||||
|
||||
from widgets.wayland import WaylandWindow
|
||||
from utils.monitors import HyprlandWithMonitors
|
||||
|
||||
gi.require_version("GtkLayerShell", "0.1")
|
||||
|
||||
|
||||
class PopupWindow(WaylandWindow):
|
||||
"""A simple popover window that can point to a widget."""
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
parent: WaylandWindow,
|
||||
pointing_to: Gtk.Widget | None = None,
|
||||
margin: tuple[int, ...] | str = "0px 0px 0px 0px",
|
||||
enable_boundary_checking: bool = True,
|
||||
**kwargs,
|
||||
):
|
||||
super().__init__(**kwargs)
|
||||
self.exclusivity = "none"
|
||||
|
||||
self._is_centered = False
|
||||
self._parent = parent
|
||||
self._pointing_widget = pointing_to
|
||||
self._hyprland = HyprlandWithMonitors()
|
||||
self._base_margin = self.extract_margin(margin)
|
||||
self.margin = self._base_margin.values()
|
||||
self._enable_boundary_checking = enable_boundary_checking
|
||||
|
||||
self.connect("notify::visible", self.do_update_handlers)
|
||||
|
||||
@@ -36,10 +43,8 @@ class PopupWindow(WaylandWindow):
|
||||
|
||||
def set_pointing_to(self, widget: Gtk.Widget | None):
|
||||
if self._pointing_widget:
|
||||
try:
|
||||
with contextlib.suppress(Exception):
|
||||
self._pointing_widget.disconnect_by_func(self.do_handle_size_allocate)
|
||||
except Exception:
|
||||
pass
|
||||
self._pointing_widget = widget
|
||||
return self.do_update_handlers()
|
||||
|
||||
@@ -68,12 +73,15 @@ class PopupWindow(WaylandWindow):
|
||||
parent_anchor = self._parent.anchor
|
||||
|
||||
if len(parent_anchor) != 3:
|
||||
self.anchor = "left bottom"
|
||||
self._is_centered = True
|
||||
return move_axe
|
||||
|
||||
if (
|
||||
GtkLayerShell.Edge.LEFT in parent_anchor
|
||||
and GtkLayerShell.Edge.RIGHT in parent_anchor
|
||||
):
|
||||
# horizontal -> move on x-axies
|
||||
move_axe = "x"
|
||||
if GtkLayerShell.Edge.TOP in parent_anchor:
|
||||
self.anchor = "left top"
|
||||
@@ -83,12 +91,14 @@ class PopupWindow(WaylandWindow):
|
||||
GtkLayerShell.Edge.TOP in parent_anchor
|
||||
and GtkLayerShell.Edge.BOTTOM in parent_anchor
|
||||
):
|
||||
# vertical -> move on y-axies
|
||||
move_axe = "y"
|
||||
if GtkLayerShell.Edge.RIGHT in parent_anchor:
|
||||
self.anchor = "top right"
|
||||
else:
|
||||
self.anchor = "top left"
|
||||
|
||||
self._is_centered = False
|
||||
return move_axe
|
||||
|
||||
def do_reposition(self, move_axe: str):
|
||||
@@ -98,48 +108,84 @@ class PopupWindow(WaylandWindow):
|
||||
height = self.get_allocated_height()
|
||||
width = self.get_allocated_width()
|
||||
|
||||
screen = Gdk.Screen.get_default()
|
||||
screen_width = screen.get_width()
|
||||
# Get monitor geometry for boundary checking
|
||||
current_monitor_id = self._hyprland.get_current_gdk_monitor_id()
|
||||
if current_monitor_id is not None:
|
||||
monitor = self._hyprland.display.get_monitor(current_monitor_id)
|
||||
monitor_geometry = monitor.get_geometry()
|
||||
monitor_x, monitor_y = monitor_geometry.x, monitor_geometry.y
|
||||
monitor_width, monitor_height = monitor_geometry.width, monitor_geometry.height
|
||||
else:
|
||||
# Fallback to default screen
|
||||
screen = Gdk.Screen.get_default()
|
||||
monitor_x, monitor_y = 0, 0
|
||||
monitor_width, monitor_height = screen.get_width(), screen.get_height()
|
||||
|
||||
if self._pointing_widget:
|
||||
coords = self.get_coords_for_widget(self._pointing_widget)
|
||||
if coords[0] + width > screen_width:
|
||||
coords_centered = (
|
||||
round(
|
||||
coords[0]
|
||||
- (width - self._pointing_widget.get_allocated_width())
|
||||
),
|
||||
round(coords[1] + self._pointing_widget.get_allocated_height() / 2),
|
||||
)
|
||||
else:
|
||||
coords_centered = (
|
||||
round(coords[0]),
|
||||
round(coords[1] + self._pointing_widget.get_allocated_height() / 2),
|
||||
)
|
||||
coords_centered = (
|
||||
round(coords[0] + self._pointing_widget.get_allocated_width() / 2),
|
||||
round(coords[1] + self._pointing_widget.get_allocated_height() / 2),
|
||||
)
|
||||
else:
|
||||
coords_centered = (
|
||||
round(self._parent.get_allocated_width() / 2),
|
||||
round(self._parent.get_allocated_height() / 2),
|
||||
)
|
||||
|
||||
if self._is_centered:
|
||||
# Calculate centered position with boundary checking
|
||||
centered_x = (
|
||||
(monitor_width / 2 - self._parent.get_allocated_width() / 2)
|
||||
- width / 2
|
||||
) + coords_centered[0]
|
||||
|
||||
# Apply boundary checking only if enabled
|
||||
if self._enable_boundary_checking:
|
||||
if centered_x < monitor_x:
|
||||
centered_x = monitor_x
|
||||
elif centered_x + width > monitor_x + monitor_width:
|
||||
centered_x = monitor_x + monitor_width - width
|
||||
|
||||
self.margin = tuple(
|
||||
a + b
|
||||
for a, b in zip(
|
||||
(0, 0, 0, centered_x),
|
||||
self._base_margin.values(),
|
||||
)
|
||||
)
|
||||
return
|
||||
|
||||
# Calculate position with boundary checking
|
||||
if move_axe == "x":
|
||||
# Horizontal positioning
|
||||
calculated_x = round((parent_x_margin + coords_centered[0]) - (width / 2))
|
||||
|
||||
# Apply boundary checking only if enabled
|
||||
if self._enable_boundary_checking:
|
||||
if calculated_x < monitor_x:
|
||||
calculated_x = monitor_x
|
||||
elif calculated_x + width > monitor_x + monitor_width:
|
||||
calculated_x = monitor_x + monitor_width - width
|
||||
|
||||
margin_values = (0, 0, 0, calculated_x)
|
||||
else:
|
||||
# Vertical positioning
|
||||
calculated_y = round((parent_y_margin + coords_centered[1]) - (height / 2))
|
||||
|
||||
# Apply boundary checking only if enabled
|
||||
if self._enable_boundary_checking:
|
||||
if calculated_y < monitor_y:
|
||||
calculated_y = monitor_y
|
||||
elif calculated_y + height > monitor_y + monitor_height:
|
||||
calculated_y = monitor_y + monitor_height - height
|
||||
|
||||
margin_values = (calculated_y, 0, 0, 0)
|
||||
|
||||
self.margin = tuple(
|
||||
a + b
|
||||
for a, b in zip(
|
||||
(
|
||||
(
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
round((parent_x_margin + coords_centered[0])),
|
||||
)
|
||||
if move_axe == "x"
|
||||
else (
|
||||
round((parent_y_margin + coords_centered[1]) - (height / 2)),
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
)
|
||||
),
|
||||
margin_values,
|
||||
self._base_margin.values(),
|
||||
)
|
||||
)
|
||||
Reference in new issue
Block a user