Skip to content
Merged

dock #44

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
1 change: 1 addition & 0 deletions .github/CODEOWNERS
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
* @S4NKALP
3 changes: 1 addition & 2 deletions .github/workflows/codeql.yml
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,8 @@ name: CodeQL

on:
push:
branches: [main, dev]
branches: [macos]
pull_request:
branches: [main, dev]
schedule:
- cron: "0 6 * * 1"

Expand Down
1 change: 0 additions & 1 deletion .github/workflows/commitlint.yml
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@ name: Commit Lint

on:
pull_request:
branches: [main, dev]

permissions:
contents: read
Expand Down
3 changes: 1 addition & 2 deletions .github/workflows/install-test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -2,15 +2,14 @@ name: Install Script Test

on:
push:
branches: [main, dev]
branches: [macos]
paths:
- "install.sh"
- "src/window/globalmenu/**"
- "src/window/switcher/app-capture/**"
- "pyproject.toml"
- "uv.lock"
pull_request:
branches: [main, dev]
paths:
- "install.sh"
- "src/window/globalmenu/**"
Expand Down
3 changes: 1 addition & 2 deletions .github/workflows/pre-commit.yml
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,8 @@ name: Pre-commit

on:
push:
branches: [main, dev]
branches: [macos]
pull_request:
branches: [main, dev]

permissions:
contents: read
Expand Down
2 changes: 2 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -143,6 +143,8 @@ See [Desktop Widgets Guide](docs/desktop_widgets.md) for full docs and examples.

## Documentation

> **Note:** These docs were written with the assistance of LLM tools. Some phrasing may reflect that.

| Doc | What's inside |
| --------------------------------------------- | -------------------------------------------------- |
| [Installation Guide](docs/installation.md) | Automated & manual install, dependencies |
Expand Down
1 change: 1 addition & 0 deletions commitlint.config.js
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
module.exports = { extends: ["@commitlint/config-conventional"] };
8 changes: 5 additions & 3 deletions src/services/config.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
from tomlkit import dump as toml_dump
from tomlkit import item as toml_item
from tomlkit import load as toml_load
from tomlkit import loads as toml_loads

from utils.gtk_utils import toml_file

Expand Down Expand Up @@ -126,12 +127,13 @@ def _load_config(self) -> None:
self._config = toml_load(f)
else:
try:
from utils.constants import DEFAULT
from utils.constants import generate_default_toml

os.makedirs(os.path.dirname(self._config_file), exist_ok=True)
self._config = self._dict_to_toml(DEFAULT)
raw = generate_default_toml()
self._config = toml_loads(raw)
with open(self._config_file, "w") as f:
toml_dump(self._config, f)
f.write(raw)
logger.info(
f"[ConfigService] Generated default config at {self._config_file}"
)
Expand Down
40 changes: 28 additions & 12 deletions src/shared/data.py
Original file line number Diff line number Diff line change
Expand Up @@ -49,19 +49,35 @@ def load_config():
service = start_config_service()
return service.get_all()
except ImportError:
# Fallback to direct file loading
config = {}
pass

if os.path.exists(CONFIG_FILE):
try:
import tomlkit

with open(CONFIG_FILE) as f:
config = dict(tomlkit.load(f))
except Exception as e:
logger.error(f"Error loading config: {e}")

return config
try:
from utils.constants import generate_default_toml
except ImportError:
generate_default_toml = None

config = {}

if os.path.exists(CONFIG_FILE):
try:
import tomlkit

with open(CONFIG_FILE) as f:
config = dict(tomlkit.load(f))
except Exception as e:
logger.error(f"Error loading config: {e}")
elif generate_default_toml:
try:
raw = generate_default_toml()
with open(CONFIG_FILE, "w") as f:
f.write(raw)
import tomlkit

config = dict(tomlkit.loads(raw))
except Exception as e:
logger.error(f"Error generating default config: {e}")

return config


NOTIFICATION_TIMEOUT_STR = "5s"
Expand Down
63 changes: 63 additions & 0 deletions src/utils/constants.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,7 @@
from tomlkit import document as _document
from tomlkit import dumps as _dumps
from tomlkit import table as _table

DEFAULT = {
"general": {
"debug": False,
Expand All @@ -11,6 +15,7 @@
"always_occluded": False,
"icon_size": 52,
"hide_special_workspace_apps": True,
"hover_scale": 1.6,
},
"panel": {
"imac_button": True,
Expand Down Expand Up @@ -42,3 +47,61 @@
"limited_apps_history": ["Spotify"],
},
}


def generate_default_toml() -> str:
"""Build default config.toml with inline comments."""
doc = _document()

general = _table()
general.add("debug", False)
general.add("wallpapers_dir", "src/assets/wallpaper_example/")
general.add("keyboard_layouts", ["us"])
general.add("weather_location", "")
doc.add("general", general)

dock = _table()
dock.add("enabled", True)
dock.add("auto_hide", True)
dock.add("always_occluded", False)
dock.add("icon_size", 52)
dock.add("hide_special_workspace_apps", True)
dock.add("hover_scale", 1.6)
dock["hover_scale"].comment(
"1.0 (min, no effect) to 2.0 (max) | >2.0 not recommended — icons get blurry/pixelated on hover"
)
doc.add("dock", dock)

panel = _table()
panel.add("imac_button", True)
panel.add("systray", True)
panel.add("systray_ignore", ["blueman", "network"])
panel.add("control_center", True)
panel.add("search", True)
panel.add("global_menu", True)
panel.add("network", True)
panel.add("battery", True)
panel.add("notification_center", True)
panel.add("workspace_indicator", True)
panel.add("bluetooth", True)
panel.add("date_time", True)
panel.add("night_light_temperature", 4500)
panel.add("notch", True)
panel.add("osd", True)
panel.add("hide_special_workspace", True)
panel.add("custom_mods", True)
doc.add("panel", panel)

switcher = _table()
switcher.add("live_preview", True)
switcher.add("live_preview_delay_ms", 200)
switcher.add("window_switcher", True)
doc.add("switcher", switcher)

notification = _table()
notification.add("timeout", "5s")
notification.add("ignored_apps", ["Hyprshot"])
notification.add("limited_apps_history", ["Spotify"])
doc.add("notification", notification)

return _dumps(doc)
10 changes: 5 additions & 5 deletions src/window/dock/canvas.py
Original file line number Diff line number Diff line change
Expand Up @@ -41,11 +41,11 @@
INDICATOR_COLOR,
INDICATOR_H,
INDICATOR_RADIUS,
MAX_SCALE,
MIN_SCALE,
PINNED_APPS_FILE,
SEPARATOR_COLOR,
SEPARATOR_WIDTH,
max_scale,
)
from .items import DockHitTest, DockItem, DockModel
from .layout import DockLayout
Expand Down Expand Up @@ -126,7 +126,7 @@ def _base_icon_size(self) -> int:
return int(config().get("dock.icon_size", 52))

def _icon_cache_size(self) -> int:
return int(self._base_icon_size() * MAX_SCALE)
return int(self._base_icon_size() * max_scale())

def _get_desktop_apps(self) -> list:
if not self._desktop_apps:
Expand All @@ -140,7 +140,7 @@ def _get_desktop_apps(self) -> list:
def _canvas_height(self) -> int:
size = self._base_icon_size()
return int(
size * MAX_SCALE + CANVAS_TOP_PAD + 2 * BG_PADDING_V + INDICATOR_H + 4
size * max_scale() + CANVAS_TOP_PAD + 2 * BG_PADDING_V + INDICATOR_H + 4
)

def _canvas_max_width(self) -> int:
Expand All @@ -149,7 +149,7 @@ def _canvas_max_width(self) -> int:
return 200
size = self._base_icon_size()
return int(
n * size * MAX_SCALE + max(n - 1, 0) * ICON_GAP + 2 * BG_PADDING_H + 40
n * size * max_scale() + max(n - 1, 0) * ICON_GAP + 2 * BG_PADDING_H + 40
)

def _canvas_min_width(self) -> int:
Expand Down Expand Up @@ -655,7 +655,7 @@ def _on_motion(self, widget, event: Gdk.EventMotion) -> bool:
bg_h = size + 2 * BG_PADDING_V
bg_y = h - INDICATOR_H - bg_h
baseline_y = bg_y + BG_PADDING_V + size
icon_top_y = baseline_y - size * MAX_SCALE
icon_top_y = baseline_y - size * max_scale()
self._mouse_inside = (
base_start_x <= event.x <= base_start_x + total_base
and icon_top_y <= event.y <= baseline_y
Expand Down
7 changes: 6 additions & 1 deletion src/window/dock/constants.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
from services.config import config
from utils.gtk_utils import toml_file

PINNED_APPS_FILE = toml_file("dock.toml")
Expand All @@ -7,7 +8,11 @@
ANIM_FPS = 60
ANIM_INTERVAL_MS = 1000 // ANIM_FPS

MAX_SCALE = 2.0

def max_scale() -> float:
return float(config().get("dock.hover_scale", 2.0))


MIN_SCALE = 1.0
SIGMA_FACTOR = 1.3

Expand Down
4 changes: 2 additions & 2 deletions src/window/dock/layout.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,9 @@
BG_PADDING_V,
ICON_GAP,
INDICATOR_H,
MAX_SCALE,
MIN_SCALE,
SIGMA_FACTOR,
max_scale,
)
from .items import DockItem

Expand All @@ -27,7 +27,7 @@ def compute(
return

sigma = base_icon_size * SIGMA_FACTOR
amplitude = MAX_SCALE - MIN_SCALE
amplitude = max_scale() - MIN_SCALE

n = len(items)
base_w = base_icon_size + ICON_GAP
Expand Down
3 changes: 3 additions & 0 deletions src/window/dock/main.py
Original file line number Diff line number Diff line change
Expand Up @@ -135,6 +135,9 @@ def _on_config_change(self, new_config, old_config) -> None:
if config().has_changed("dock.hide_special_workspace_apps", old_config):
self.canvas._rebuild_model()

if config().has_changed("dock.hover_scale", old_config):
self.canvas.update_icon_size()

def _update_visibility(self) -> None:
if config().get("dock.enabled", True):
self.show()
Expand Down
14 changes: 10 additions & 4 deletions src/window/settings/main.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
from fabric.utils import Gdk, Gtk, logger
from fabric.utils import Gdk, Gtk
from fabric.widgets.box import Box
from fabric.widgets.button import Button
from fabric.widgets.centerbox import CenterBox
Expand Down Expand Up @@ -90,12 +90,13 @@ def _on_config_change(self, new_config, old_config):

def on_change(self, entry, *args):
value = entry.get_text()
# Try to convert to int if possible
try:
if value.isdigit():
value = int(value)
except Exception as e:
logger.error(f"An error occurred: {e}")
else:
value = float(value)
except (ValueError, TypeError):
pass

config().set(self.config_key, value)
config().save()
Expand Down Expand Up @@ -400,6 +401,11 @@ def _create_dock_page(self):
SettingsSwitch("dock.hide_special_workspace_apps"),
"Hide apps from special workspace in dock",
),
SettingsRow(
"Hover Scale",
SettingsEntry("dock.hover_scale"),
"Icon scale on hover (1.0 = off, 1.6 = default, 2.0 = max)",
),
],
)

Expand Down
8 changes: 0 additions & 8 deletions src/window/spotlight/plugins/clipboard.py
Original file line number Diff line number Diff line change
Expand Up @@ -99,11 +99,7 @@ def _on_debounced_db_change(self):
def _load_history(self) -> None:
result = run_command(["cliphist", "list"], timeout=5)
raw = result.stdout if isinstance(result.stdout, str) else ""
logger.info(
f"[Clipboard] _load_history: stdout type={type(result.stdout).__name__} len={len(raw)} returncode={result.returncode}"
)
lines = raw.splitlines()
logger.info(f"[Clipboard] _load_history: {len(lines)} lines from cliphist")
new_entries = []
for line in lines[:100]:
if "\t" not in line:
Expand All @@ -122,13 +118,9 @@ def _load_history(self) -> None:
if "binary data" in content:
entry["type"] = "image"
new_entries.append(entry)
logger.info(f"[Clipboard] _load_history: parsed {len(new_entries)} entries")
with self._history_lock:
self._history.clear()
self._history.extend(new_entries)
logger.info(
f"[Clipboard] _load_history: history now has {len(self._history)} entries"
)

def _filter_entries(self, query: str) -> list[dict]:
q = query.strip().lower()
Expand Down
Loading