Merge branch 'main' of github.com:noctalia-dev/noctalia-shell

This commit is contained in:
Lemmy
2026-01-29 13:42:05 -05:00
3 changed files with 99 additions and 43 deletions
+51 -9
View File
@@ -77,6 +77,8 @@ Loader {
readonly property int peekHeight: 1
readonly property int iconSize: Math.round(12 + 24 * (Settings.data.dock.size ?? 1))
readonly property int floatingMargin: Settings.data.dock.floatingRatio * Style.marginL
readonly property int maxWidth: modelData ? modelData.width * 0.8 : 1000
readonly property int maxHeight: modelData ? modelData.height * 0.8 : 1000
// Dock position properties
readonly property string dockPosition: Settings.data.dock.position
@@ -532,7 +534,7 @@ Loader {
WlrLayershell.exclusionMode: exclusive ? ExclusionMode.Auto : ExclusionMode.Ignore
implicitWidth: Math.round(dockContainerWrapper.width + (root.isVertical ? 0 : Style.marginXL * 6))
implicitHeight: Math.round(dockContainerWrapper.height)
implicitHeight: Math.round(dockContainerWrapper.height + (root.isVertical ? Style.marginXL * 6 : 0))
// Position based on dock setting
anchors.top: dockPosition === "top"
@@ -595,8 +597,8 @@ Loader {
Rectangle {
id: dockContainer
// For vertical dock, swap width and height logic
width: isVertical ? Math.round(iconSize * 1.5) : dockLayout.implicitWidth + Style.marginXL
height: isVertical ? dockLayout.implicitHeight + Style.marginXL : Math.round(iconSize * 1.5)
width: isVertical ? Math.round(iconSize * 1.5) : Math.min(dockLayout.implicitWidth + Style.marginXL, root.maxWidth)
height: isVertical ? Math.min(dockLayout.implicitHeight + Style.marginXL, root.maxHeight) : Math.round(iconSize * 1.5)
color: Qt.alpha(Color.mSurface, Settings.data.dock.backgroundOpacity)
// Anchor based on padding to achieve centering shift
@@ -643,12 +645,50 @@ Loader {
}
}
Item {
Flickable {
id: dock
// Swap dimensions based on orientation
width: isVertical ? parent.width - (Style.marginXL) : dockLayout.implicitWidth
height: isVertical ? dockLayout.implicitHeight : parent.height - (Style.marginXL)
// Use parent dimensions more directly to avoid clipping
width: isVertical ? parent.width - Style.marginS * 2 : Math.min(dockLayout.implicitWidth, parent.width - Style.marginXL)
height: !isVertical ? parent.height - Style.marginS * 2 : Math.min(dockLayout.implicitHeight, parent.height - Style.marginXL)
contentWidth: dockLayout.implicitWidth
contentHeight: dockLayout.implicitHeight
anchors.centerIn: parent
clip: true
flickableDirection: isVertical ? Flickable.VerticalFlick : Flickable.HorizontalFlick
// Keep interactive dependent on overflow
interactive: isVertical ? contentHeight > height : contentWidth > width
// Centering margins
leftMargin: !isVertical && contentWidth < width ? (width - contentWidth) / 2 : 0
rightMargin: leftMargin
topMargin: isVertical && contentHeight < height ? (height - contentHeight) / 2 : 0
bottomMargin: topMargin
WheelHandler {
acceptedDevices: PointerDevice.Mouse | PointerDevice.TouchPad
onWheel: event => {
var delta = (event.angleDelta.y !== 0) ? event.angleDelta.y : event.angleDelta.x;
if (root.isVertical) {
dock.contentY = Math.max(-dock.topMargin, Math.min(dock.contentHeight - dock.height + dock.bottomMargin, dock.contentY - delta));
} else {
// For horizontal dock, we want to scroll contentX with BOTH x and y wheels
var hDelta = (event.angleDelta.x !== 0) ? event.angleDelta.x : event.angleDelta.y;
dock.contentX = Math.max(-dock.leftMargin, Math.min(dock.contentWidth - dock.width + dock.rightMargin, dock.contentX - hDelta));
}
event.accepted = true;
}
}
ScrollBar.horizontal: ScrollBar {
visible: !isVertical && dock.interactive
policy: ScrollBar.AsNeeded
}
ScrollBar.vertical: ScrollBar {
visible: isVertical && dock.interactive
policy: ScrollBar.AsNeeded
}
function getAppIcon(appData): string {
if (!appData || !appData.appId)
@@ -663,7 +703,10 @@ Loader {
rows: isVertical ? -1 : 1
rowSpacing: Style.marginS
columnSpacing: Style.marginS
anchors.centerIn: parent
// Ensure the layout takes its full implicit size
width: implicitWidth
height: implicitHeight
Repeater {
model: dockApps
@@ -909,7 +952,6 @@ Loader {
// Only allow left-click dragging via axis control
drag.target: iconContainer
drag.axis: (pressedButtons & Qt.LeftButton) ? (root.isVertical ? Drag.YAxis : Drag.XAxis) : Drag.None
preventStealing: true
onPressed: {
var p1 = appButton.mapFromItem(dockContainer, 0, 0);
+47 -33
View File
@@ -3,19 +3,20 @@
import asyncio
import os
import sys
import shutil
from pathlib import Path
async def run_command(*args):
process = await asyncio.create_subprocess_exec(
*args,
stdout=asyncio.subprocess.PIPE,
stderr=asyncio.subprocess.PIPE
*args, stdout=asyncio.subprocess.PIPE, stderr=asyncio.subprocess.PIPE
)
stdout, stderr = await process.communicate()
if process.returncode != 0:
print(f"Error running {' '.join(args)}: {stderr.decode().strip()}", file=sys.stderr)
return stdout.decode().strip()
async def apply_gtk3_colors(config_dir: Path):
gtk3_dir = config_dir / "gtk-3.0"
colors_file = gtk3_dir / "noctalia.css"
@@ -36,6 +37,7 @@ async def apply_gtk3_colors(config_dir: Path):
print(f"Created symlink: {gtk_css} -> noctalia.css")
return True
async def apply_gtk4_colors(config_dir: Path):
gtk4_dir = config_dir / "gtk-4.0"
colors_file = gtk4_dir / "noctalia.css"
@@ -50,35 +52,47 @@ async def apply_gtk4_colors(config_dir: Path):
print("Updated GTK4 CSS import")
return True
async def refresh_theme():
raw_theme = await run_command("gsettings", "get", "org.gnome.desktop.interface", "gtk-theme")
current_theme = raw_theme.strip("'")
raw_scheme = await run_command("gsettings", "get", "org.gnome.desktop.interface", "color-scheme")
current_scheme = raw_scheme.strip("'")
if not current_theme: current_theme = "adw-gtk3-dark"
if not current_scheme: current_scheme = "prefer-dark"
temp_scheme = "default" if current_scheme == "prefer-dark" else "prefer-dark"
# await run_command("gsettings", "set", "org.gnome.desktop.interface", "color-scheme", temp_scheme)
# await run_command("dconf", "write", "/org/gnome/desktop/interface/color-scheme", f"'{temp_scheme}'")
# await run_command("gsettings", "set", "org.gnome.desktop.interface", "gtk-theme", "")
# await run_command("dconf", "write", "/org/gnome/desktop/interface/gtk-theme", "''")
# await asyncio.sleep(0.01)
await run_command("gsettings", "set", "org.gnome.desktop.interface", "color-scheme", current_scheme)
await run_command("dconf", "write", "/org/gnome/desktop/interface/color-scheme", f"'{current_scheme}'")
await run_command("gsettings", "set", "org.gnome.desktop.interface", "gtk-theme", current_theme)
await run_command("dconf", "write", "/org/gnome/desktop/interface/gtk-theme", f"'{current_theme}'")
async def refresh_theme():
has_gsettings = shutil.which("gsettings")
has_dconf = shutil.which("dconf")
if not has_gsettings and not has_dconf:
print("No gsettings or dconf found, skip GTK refresh")
return
if mode == "light":
target_theme = "adw-gtk3"
else:
target_theme = "adw-gtk3-dark"
if has_gsettings:
schemas = await run_command("gsettings", "list-schemas")
if schemas and "org.gnome.desktop.interface" in schemas:
await run_command("gsettings", "set", "org.gnome.desktop.interface", "color-scheme", f"prefer-{mode}")
await run_command("gsettings", "set", "org.gnome.desktop.interface", "gtk-theme", f"{target_theme}")
return
if has_dconf:
await run_command("dconf", "write", "/org/gnome/desktop/interface/color-scheme", f"'prefer-{mode}'")
await run_command("dconf", "write", "/org/gnome/desktop/interface/gtk-theme", f"'{target_theme}'")
async def get_config_dir() -> Path:
# 1. project-specific override
if value := os.environ.get("NOCTALIA_CONFIG_DIR"):
return Path(value).expanduser()
# 2. XDG standard
if value := os.environ.get("XDG_CONFIG_HOME"):
return Path(value).expanduser()
# 3. fallback
return Path.home() / ".config"
async def main():
config_dir_path = sys.argv[1] if len(sys.argv) > 1 else os.path.expanduser("~/.config")
config_dir = Path(config_dir_path)
config_dir = await get_config_dir()
if not config_dir.is_dir():
print(f"Error: Config directory not found: {config_dir}", file=sys.stderr)
@@ -87,10 +101,7 @@ async def main():
(config_dir / "gtk-3.0").mkdir(parents=True, exist_ok=True)
(config_dir / "gtk-4.0").mkdir(parents=True, exist_ok=True)
results = await asyncio.gather(
apply_gtk3_colors(config_dir),
apply_gtk4_colors(config_dir)
)
results = await asyncio.gather(apply_gtk3_colors(config_dir), apply_gtk4_colors(config_dir))
if all(results):
await refresh_theme()
@@ -98,5 +109,8 @@ async def main():
else:
sys.exit(1)
if __name__ == "__main__":
mode = sys.argv[1] # light or dark
asyncio.run(main())
+1 -1
View File
@@ -66,7 +66,7 @@ Singleton {
"path": "~/.config/gtk-4.0/noctalia.css"
}
],
"postProcess": mode => `gsettings set org.gnome.desktop.interface color-scheme prefer-${mode} && python3 ${gtkRefreshScript}`
"postProcess": mode => `python3 ${gtkRefreshScript} ${mode}`
},
{
"id": "qt",