mirror of
https://github.com/noctalia-dev/noctalia-shell.git
synced 2026-05-11 17:08:27 +08:00
Merge remote-tracking branch 'upstream/main' into pr/networking-refactor-pt2
# Conflicts: # Modules/Panels/Network/WiFiNetworksList.qml
This commit is contained in:
@@ -824,6 +824,8 @@
|
||||
"appearance-density-label": "Bar density",
|
||||
"appearance-desc": "Customize the bar's appearance and position.",
|
||||
"appearance-display-mode-description": "Choose when the bar is visible.",
|
||||
"appearance-enable-exclusion-zone-inset-description": "Reduce the exclusion zone by 1 physical pixel so flush windows bleed perfectly under the bar edge.",
|
||||
"appearance-enable-exclusion-zone-inset-label": "Inset exclusion zone",
|
||||
"appearance-floating-description": "Display the bar as a floating 'pill'.",
|
||||
"appearance-floating-label": "Floating bar",
|
||||
"appearance-font-scale-description": "Adjust the font size scale for text displayed in the bar.",
|
||||
|
||||
@@ -12,6 +12,7 @@
|
||||
"widgetSpacing": 6,
|
||||
"contentPadding": 2,
|
||||
"fontScale": 1,
|
||||
"enableExclusionZoneInset": true,
|
||||
"backgroundOpacity": 0.93,
|
||||
"useSeparateOpacity": false,
|
||||
"floating": false,
|
||||
|
||||
@@ -260,6 +260,15 @@
|
||||
"subTab": 0,
|
||||
"subTabLabel": "common.appearance"
|
||||
},
|
||||
{
|
||||
"labelKey": "panels.bar.appearance-enable-exclusion-zone-inset-label",
|
||||
"descriptionKey": "panels.bar.appearance-enable-exclusion-zone-inset-description",
|
||||
"widget": "NToggle",
|
||||
"tab": 4,
|
||||
"tabLabel": "panels.bar.title",
|
||||
"subTab": 0,
|
||||
"subTabLabel": "common.appearance"
|
||||
},
|
||||
{
|
||||
"labelKey": "panels.bar.appearance-hide-on-overview-label",
|
||||
"descriptionKey": "panels.bar.appearance-hide-on-overview-description",
|
||||
|
||||
+6
-3
@@ -329,15 +329,18 @@ Singleton {
|
||||
if (!Settings.data.ui.translucentWidgets)
|
||||
return baseColor;
|
||||
|
||||
let baseOpacity = Settings.data.ui.panelBackgroundOpacity;
|
||||
let targetOpacity = Settings.data.colorSchemes.darkMode ? baseOpacity : Math.pow(baseOpacity, 2);
|
||||
let alpha = Math.max(targetOpacity, minAlpha);
|
||||
let alpha = Math.max(root.panelBackgroundOpacity, minAlpha);
|
||||
|
||||
// Combine with the base color's existing alpha
|
||||
let resultAlpha = Math.max(0, baseColor.a - (1.0 - alpha));
|
||||
return Qt.alpha(baseColor, resultAlpha);
|
||||
}
|
||||
|
||||
readonly property real panelBackgroundOpacity: {
|
||||
let baseOpacity = Settings.data.ui.panelBackgroundOpacity;
|
||||
return Settings.data.colorSchemes.darkMode ? baseOpacity : Math.pow(baseOpacity, 2);
|
||||
}
|
||||
|
||||
readonly property var colorKeyModel: [
|
||||
{
|
||||
"key": "none",
|
||||
|
||||
@@ -184,6 +184,7 @@ Singleton {
|
||||
property int widgetSpacing: 6
|
||||
property int contentPadding: 2
|
||||
property real fontScale: 1.0
|
||||
property bool enableExclusionZoneInset: true
|
||||
|
||||
// Bar background opacity settings
|
||||
property real backgroundOpacity: 0.93
|
||||
|
||||
@@ -147,13 +147,15 @@ Item {
|
||||
if (PanelService.getPanel("audioPanel", screen)?.isPanelOpen) {
|
||||
return "";
|
||||
} else {
|
||||
return I18n.tr("tooltips.microphone-volume-at", {
|
||||
"volume": (() => {
|
||||
const maxVolume = Settings.data.audio.volumeOverdrive ? 1.5 : 1.0;
|
||||
const displayVolume = Math.min(maxVolume, AudioService.inputVolume);
|
||||
return Math.round(displayVolume * 100);
|
||||
})()
|
||||
});
|
||||
const nick = AudioService.source?.nickname ?? "";
|
||||
const volumeText = I18n.tr("tooltips.microphone-volume-at", {
|
||||
"volume": (() => {
|
||||
const maxVolume = Settings.data.audio.volumeOverdrive ? 1.5 : 1.0;
|
||||
const displayVolume = Math.min(maxVolume, AudioService.inputVolume);
|
||||
return Math.round(displayVolume * 100);
|
||||
})()
|
||||
});
|
||||
return nick ? volumeText + "\n" + nick : volumeText;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -140,13 +140,15 @@ Item {
|
||||
if (PanelService.getPanel("audioPanel", screen)?.isPanelOpen) {
|
||||
return "";
|
||||
} else {
|
||||
I18n.tr("tooltips.volume-at", {
|
||||
"volume": (() => {
|
||||
const maxVolume = Settings.data.audio.volumeOverdrive ? 1.5 : 1.0;
|
||||
const displayVolume = Math.min(maxVolume, AudioService.volume);
|
||||
return Math.round(displayVolume * 100);
|
||||
})()
|
||||
});
|
||||
const nick = AudioService.sink?.nickname ?? "";
|
||||
const volumeText = I18n.tr("tooltips.volume-at", {
|
||||
"volume": (() => {
|
||||
const maxVolume = Settings.data.audio.volumeOverdrive ? 1.5 : 1.0;
|
||||
const displayVolume = Math.min(maxVolume, AudioService.volume);
|
||||
return Math.round(displayVolume * 100);
|
||||
})()
|
||||
});
|
||||
return nick ? volumeText + "\n" + nick : volumeText;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -38,7 +38,7 @@ Item {
|
||||
|
||||
// Enable layer caching to prevent continuous re-rendering
|
||||
layer.enabled: true
|
||||
opacity: Settings.data.ui.panelBackgroundOpacity
|
||||
opacity: Color.panelBackgroundOpacity
|
||||
|
||||
Shape {
|
||||
id: unifiedBackgroundsShape
|
||||
@@ -106,7 +106,7 @@ Item {
|
||||
anchors.fill: parent
|
||||
|
||||
layer.enabled: true
|
||||
opacity: Settings.data.ui.panelBackgroundOpacity
|
||||
opacity: Color.panelBackgroundOpacity
|
||||
|
||||
Shape {
|
||||
id: panelBackgroundsShape
|
||||
|
||||
@@ -23,11 +23,12 @@ PanelWindow {
|
||||
readonly property bool barFloating: Settings.data.bar.floating || false
|
||||
readonly property real barMarginH: (barFloating && edge === Settings.getBarPositionForScreen(screen?.name)) ? Math.ceil(Settings.data.bar.marginHorizontal) : 0
|
||||
readonly property real barMarginV: (barFloating && edge === Settings.getBarPositionForScreen(screen?.name)) ? Math.ceil(Settings.data.bar.marginVertical) : 0
|
||||
// Reduce exclusion zone by 1 physical pixel so app windows blend flush against the bar edge
|
||||
// Allow users to enable a 1-physical-pixel inset for the exclusion zone so window borders can bleed under the bar
|
||||
readonly property real bleedOffset: Settings.data.bar.enableExclusionZoneInset ? 1.0 : 0.0
|
||||
readonly property real bleedInset: {
|
||||
const info = CompositorService.displayScales[screen?.name];
|
||||
const scale = (info && info.scale) ? info.scale : 1.0;
|
||||
return 1.0 / scale;
|
||||
return bleedOffset / scale;
|
||||
}
|
||||
|
||||
// Invisible - just reserves space
|
||||
|
||||
@@ -255,7 +255,7 @@ Variants {
|
||||
|
||||
ShapePath {
|
||||
strokeWidth: -1
|
||||
fillColor: Qt.alpha(Color.mSurfaceVariant, Settings.data.ui.panelBackgroundOpacity)
|
||||
fillColor: Qt.alpha(Color.mSurfaceVariant, Color.panelBackgroundOpacity)
|
||||
|
||||
// Offset by radius to account for Shape's extended bounds
|
||||
startX: panelShape.radius + panelShape.radius * panelShape.tlMultX
|
||||
|
||||
@@ -450,7 +450,7 @@ SmartPanel {
|
||||
radius: Style.radiusM
|
||||
border.width: Style.borderS
|
||||
border.color: modelData.connected ? Color.mPrimary : Color.mOutline
|
||||
color: modelData.connected ? Qt.alpha(Color.mPrimary, Math.min(1.15 - Settings.data.ui.panelBackgroundOpacity, 0.75)) : Color.mSurface
|
||||
color: modelData.connected ? Qt.alpha(Color.mPrimary, Math.min(1.15 - Color.panelBackgroundOpacity, 0.75)) : Color.mSurface
|
||||
|
||||
ColumnLayout {
|
||||
id: ethItemColumn
|
||||
|
||||
@@ -63,7 +63,7 @@ Popup {
|
||||
|
||||
NText {
|
||||
text: I18n.tr("system.widget-settings-title", {
|
||||
"widget": root.widgetId
|
||||
"widget": DesktopWidgetRegistry.getWidgetDisplayName(root.widgetId)
|
||||
})
|
||||
pointSize: Style.fontSizeL
|
||||
font.weight: Style.fontWeightBold
|
||||
|
||||
@@ -226,6 +226,15 @@ ColumnLayout {
|
||||
text: Math.floor(Settings.data.bar.capsuleOpacity * 100) + "%"
|
||||
}
|
||||
|
||||
NToggle {
|
||||
Layout.fillWidth: true
|
||||
label: I18n.tr("panels.bar.appearance-enable-exclusion-zone-inset-label")
|
||||
description: I18n.tr("panels.bar.appearance-enable-exclusion-zone-inset-description")
|
||||
checked: Settings.data.bar.enableExclusionZoneInset
|
||||
defaultValue: Settings.getDefaultValue("bar.enableExclusionZoneInset")
|
||||
onToggled: checked => Settings.data.bar.enableExclusionZoneInset = checked
|
||||
}
|
||||
|
||||
NToggle {
|
||||
Layout.fillWidth: true
|
||||
visible: CompositorService.isNiri
|
||||
|
||||
@@ -393,7 +393,7 @@ Item {
|
||||
radius: Style.radiusM
|
||||
clip: true
|
||||
|
||||
color: (modelData.connected && modelData.state !== BluetoothDeviceState.Disconnecting) ? Qt.alpha(Color.mPrimary, Math.min(1.15 - Settings.data.ui.panelBackgroundOpacity, 0.75)) : Color.mSurface
|
||||
color: (modelData.connected && modelData.state !== BluetoothDeviceState.Disconnecting) ? Qt.alpha(Color.mPrimary, Math.min(1.15 - Color.panelBackgroundOpacity, 0.75)) : Color.mSurface
|
||||
|
||||
ColumnLayout {
|
||||
id: deviceColumn
|
||||
|
||||
@@ -40,40 +40,53 @@ def theme_exists(theme_name: str) -> bool:
|
||||
return False
|
||||
|
||||
|
||||
GTK_IMPORT = '@import url("noctalia.css");'
|
||||
|
||||
|
||||
def ensure_gtk_css_import(gtk_css: Path, colors_file: Path, label: str) -> bool:
|
||||
"""
|
||||
Append the noctalia.css import to gtk.css if not already present.
|
||||
If gtk.css doesn't exist, create it with the import.
|
||||
Does not overwrite user modifications (similar to niri template).
|
||||
"""
|
||||
if not colors_file.exists():
|
||||
print(f"Error: {label} noctalia.css not found at {colors_file}", file=sys.stderr)
|
||||
return False
|
||||
|
||||
# If gtk.css is a symlink, replace it with a regular file
|
||||
if gtk_css.is_symlink():
|
||||
gtk_css.unlink()
|
||||
|
||||
if gtk_css.exists():
|
||||
content = gtk_css.read_text()
|
||||
# Already has the import (flexible: allow optional whitespace / different quoting)
|
||||
if "noctalia.css" in content and "@import" in content:
|
||||
return True
|
||||
# Append import to the end
|
||||
new_content = content.rstrip()
|
||||
if new_content and not new_content.endswith("\n"):
|
||||
new_content += "\n"
|
||||
new_content += "\n" + GTK_IMPORT + "\n"
|
||||
gtk_css.write_text(new_content)
|
||||
print(f"Appended {label} noctalia.css import to gtk.css")
|
||||
else:
|
||||
gtk_css.write_text(GTK_IMPORT + "\n")
|
||||
print(f"Created {label} gtk.css with noctalia.css import")
|
||||
return True
|
||||
|
||||
|
||||
async def apply_gtk3_colors(config_dir: Path):
|
||||
gtk3_dir = config_dir / "gtk-3.0"
|
||||
colors_file = gtk3_dir / "noctalia.css"
|
||||
gtk_css = gtk3_dir / "gtk.css"
|
||||
|
||||
if not colors_file.exists():
|
||||
print(f"Error: noctalia.css not found at {colors_file}", file=sys.stderr)
|
||||
return False
|
||||
|
||||
if gtk_css.is_symlink():
|
||||
gtk_css.unlink()
|
||||
elif gtk_css.exists():
|
||||
backup_name = f"gtk.css.backup.{int(os.path.getmtime(gtk_css))}"
|
||||
gtk_css.rename(gtk3_dir / backup_name)
|
||||
print(f"Backed up existing gtk.css to {backup_name}")
|
||||
|
||||
gtk_css.symlink_to("noctalia.css")
|
||||
print(f"Created symlink: {gtk_css} -> noctalia.css")
|
||||
return True
|
||||
return ensure_gtk_css_import(gtk_css, colors_file, "GTK3")
|
||||
|
||||
|
||||
async def apply_gtk4_colors(config_dir: Path):
|
||||
gtk4_dir = config_dir / "gtk-4.0"
|
||||
colors_file = gtk4_dir / "noctalia.css"
|
||||
gtk_css = gtk4_dir / "gtk.css"
|
||||
gtk4_import = '@import url("noctalia.css");'
|
||||
|
||||
if not colors_file.exists():
|
||||
print(f"Error: GTK4 noctalia.css not found at {colors_file}", file=sys.stderr)
|
||||
return False
|
||||
|
||||
gtk_css.write_text(gtk4_import)
|
||||
print("Updated GTK4 CSS import")
|
||||
return True
|
||||
return ensure_gtk_css_import(gtk_css, colors_file, "GTK4")
|
||||
|
||||
|
||||
async def refresh_theme():
|
||||
|
||||
@@ -399,6 +399,12 @@ Item {
|
||||
const layoutNameStart = beforeParenthesis.lastIndexOf(',') + 1;
|
||||
const layoutName = ev.substring(layoutNameStart);
|
||||
|
||||
// Ignore bogus "error" layout reported by virtual keyboards (e.g. wtype)
|
||||
if (layoutName.toLowerCase() === "error") {
|
||||
Logger.d("HyprlandService", "Ignoring bogus 'error' layout from activelayout event");
|
||||
return;
|
||||
}
|
||||
|
||||
KeyboardLayoutService.setCurrentLayout(layoutName);
|
||||
Logger.d("HyprlandService", "Keyboard layout switched:", layoutName);
|
||||
} catch (e) {
|
||||
|
||||
@@ -189,7 +189,7 @@ Singleton {
|
||||
// Logger.e("BatteryDebug", "Available Battery count: " + laptopBatteries.length); // can be useful for debugging
|
||||
if (laptopBatteries.length > 1 && device.nativePath) {
|
||||
if (device.nativePath === "DisplayDevice") {
|
||||
return "All batteries (combined)"; // TODO: i18n
|
||||
return I18n.tr("battery.all-batteries");
|
||||
}
|
||||
var match = device.nativePath.match(/(\d+)$/);
|
||||
if (match) {
|
||||
|
||||
Reference in New Issue
Block a user