Skip to content
Merged
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
43 changes: 42 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,8 @@
[Secure Vault](#-secure-file--folder-vault) •
[Features](#-core-features) •
[Shortcuts](#-keyboard-shortcuts) •
[Theming](#-theming--customization)
[Theming](#-theming--customization) •
[Compositor & Glass](#-compositor-integration-hyprland-niri--lniri)

---

Expand Down Expand Up @@ -191,6 +192,46 @@ Switch themes inside the app via **Settings (`Ctrl+,`)** or set `theme = "my-the

---

## 🪟 Compositor Integration (Hyprland, Niri & Lniri)

Bubble features native support for Wayland compositor background effects including blur, contrast, and **Lniri's fluidmorphism / liquid-glass shaders** across the entire file manager window (sidebar, navigation toolbar, tabs, and file views).

### Lniri (Liquid Glass & Fluidmorphism)

To enable liquid glass in Lniri, add this window rule to `~/.config/niri/config.kdl`:

```kdl
window-rule {
match app-id="Bubble"
draw-border-with-background false
background-effect {
blur true
xray true
liquid-glass {
liquidity 0.2
refraction-strength 5.0
power-factor 3.5
refraction-power 1
glow-weight 0.1
edge-lighting 0.2
saturation 1.1
vibrancy 0.6
adaptive-dim 0.1
adaptive-boost 0.0
physical-refraction 0.1
lens-distortion 0.1
fringing 0.6
}
}
}
```

> [!TIP]
> - Both `match app-id="Bubble"` and `match app-id="io.github.soyeb_jim285.Bubble"` match automatically. If your environment requires a specific custom Wayland `app-id`, specify `BUBBLE_APP_ID=<your-id> bubble`.
> - Transparency level and container transparency can be toggled and finely adjusted inside Bubble in **Settings (`Ctrl+,`)** under **Appearance**.

---

## Architecture

Bubble is architected into three distinct layers:
Expand Down
3 changes: 2 additions & 1 deletion src/main.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -271,7 +271,8 @@ int main(int argc, char *argv[])
QGuiApplication app(argc, argv);
app.setApplicationName("Bubble");
app.setOrganizationName("bubble");
app.setDesktopFileName("io.github.soyeb_jim285.Bubble");
const QString customAppId = qEnvironmentVariable("BUBBLE_APP_ID");
app.setDesktopFileName(!customAppId.isEmpty() ? customAppId : QStringLiteral("io.github.soyeb_jim285.Bubble"));

// Startup timing: opt-in via BUBBLE_TIMING=1 so normal runs stay quiet.
// Prints milliseconds from QGuiApplication construction at each phase.
Expand Down
20 changes: 10 additions & 10 deletions src/qml/Main.qml
Original file line number Diff line number Diff line change
Expand Up @@ -174,7 +174,7 @@ ApplicationWindow {

// Bridge Bubble theme into Quill theme singleton
Q.Theme.background = Qt.binding(() => Theme.base)
Q.Theme.backgroundAlt = Qt.binding(() => Theme.mantle)
Q.Theme.backgroundAlt = Qt.binding(() => Theme.overlayBackground)
Q.Theme.backgroundDeep = Qt.binding(() => Theme.crust)
Q.Theme.surface0 = Qt.binding(() => Theme.surface)
// surface1/surface2 back Quill components that need an opaque fill
Expand Down Expand Up @@ -1558,7 +1558,7 @@ ApplicationWindow {
anchors.fill: parent
title: "Rename"
padding: 20
color: Theme.mantle
color: Theme.overlayBackground
border.color: Qt.rgba(Theme.text.r, Theme.text.g, Theme.text.b, 0.1)

Q.TextField {
Expand Down Expand Up @@ -1726,7 +1726,7 @@ ApplicationWindow {
anchors.fill: parent
title: "New Folder"
padding: 20
color: Theme.mantle
color: Theme.overlayBackground
border.color: Qt.rgba(Theme.text.r, Theme.text.g, Theme.text.b, 0.1)

Q.TextField {
Expand Down Expand Up @@ -1891,7 +1891,7 @@ ApplicationWindow {
id: fileCard
anchors.fill: parent
title: "New File"
color: Theme.mantle
color: Theme.overlayBackground
border.color: Qt.rgba(Theme.text.r, Theme.text.g, Theme.text.b, 0.1)
padding: 20

Expand Down Expand Up @@ -2244,7 +2244,7 @@ ApplicationWindow {

Rectangle {
anchors.fill: parent
color: Theme.mantle
color: Theme.overlayBackground
radius: Theme.radiusMedium
border.color: Qt.rgba(Theme.text.r, Theme.text.g, Theme.text.b, 0.1)
border.width: 1
Expand Down Expand Up @@ -3897,7 +3897,7 @@ ApplicationWindow {
y: 0
width: 2
height: toolbar.height
color: Theme.mantle
color: Theme.chromeBackground
z: 2
}

Expand Down Expand Up @@ -3974,19 +3974,19 @@ ApplicationWindow {
}
}

// File view (semi-transparent — Hyprland compositor blurs behind this)
// File view (semi-transparent — Hyprland / Niri / Lniri compositor blurs and glass effects behind this)
Rectangle {
id: contentArea
Layout.fillWidth: true
Layout.fillHeight: true
color: Theme.containerColor(Theme.base, 0.65)
color: Theme.contentBackground

// Curved mantle fills for inverse rounded corners
Shape {
z: 1; width: Theme.radiusMedium; height: Theme.radiusMedium
anchors.top: parent.top; anchors.left: parent.left
ShapePath {
fillColor: Theme.mantle; strokeColor: "transparent"
fillColor: Theme.chromeBackground; strokeColor: "transparent"
startX: 0; startY: 0
PathLine { x: Theme.radiusMedium; y: 0 }
PathArc {
Expand All @@ -4001,7 +4001,7 @@ ApplicationWindow {
z: 1; width: Theme.radiusMedium; height: Theme.radiusMedium
anchors.top: parent.top; anchors.right: parent.right
ShapePath {
fillColor: Theme.mantle; strokeColor: "transparent"
fillColor: Theme.chromeBackground; strokeColor: "transparent"
startX: Theme.radiusMedium; startY: 0
PathLine { x: 0; y: 0 }
PathArc {
Expand Down
6 changes: 3 additions & 3 deletions src/qml/components/ContextMenu.qml
Original file line number Diff line number Diff line change
Expand Up @@ -480,7 +480,7 @@ Item {
Rectangle {
anchors.fill: parent
radius: Theme.radiusLarge
color: Theme.crust
color: Theme.popupBackground
border.color: Qt.rgba(Theme.text.r, Theme.text.g, Theme.text.b, 0.08)
border.width: 1
}
Expand Down Expand Up @@ -540,7 +540,7 @@ Item {
visible: root._submenuOpensRight

ShapePath {
fillColor: Theme.crust
fillColor: Theme.popupBackground
strokeColor: Qt.rgba(Theme.text.r, Theme.text.g, Theme.text.b, 0.08)
strokeWidth: 1
joinStyle: ShapePath.MiterJoin
Expand Down Expand Up @@ -587,7 +587,7 @@ Item {
visible: !root._submenuOpensRight

ShapePath {
fillColor: Theme.crust
fillColor: Theme.popupBackground
strokeColor: Qt.rgba(Theme.text.r, Theme.text.g, Theme.text.b, 0.08)
strokeWidth: 1
joinStyle: ShapePath.MiterJoin
Expand Down
2 changes: 1 addition & 1 deletion src/qml/components/FilterPanel.qml
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ Rectangle {
typeFilterChanged(types.join(","))
}

color: Theme.mantle
color: Theme.chromeBackground
implicitHeight: content.implicitHeight + 16

ColumnLayout {
Expand Down
2 changes: 1 addition & 1 deletion src/qml/components/OperationsBar.qml
Original file line number Diff line number Diff line change
Expand Up @@ -71,7 +71,7 @@ Rectangle {

visible: _showBar
implicitHeight: _showBar ? contentCol.implicitHeight + 2 * Theme.spacing : 0
color: Theme.crust
color: Theme.popupBackground

ListModel {
id: transfersModel
Expand Down
2 changes: 1 addition & 1 deletion src/qml/components/QuickPreview.qml
Original file line number Diff line number Diff line change
Expand Up @@ -505,7 +505,7 @@ Item {
scale: 0.88
transformOrigin: Item.Center
radius: Theme.radiusLarge
color: Qt.rgba(Theme.mantle.r, Theme.mantle.g, Theme.mantle.b, 0.98)
color: Theme.overlayBackground
border.width: 1
border.color: Qt.rgba(Theme.text.r, Theme.text.g, Theme.text.b, 0.12)

Expand Down
6 changes: 3 additions & 3 deletions src/qml/components/Sidebar.qml
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ Rectangle {
signal collapseClicked()
signal featureHintRequested(string message)

color: Theme.mantle
color: Theme.chromeBackground
clip: false

Component { id: iconHome; IconHome { size: 18; color: Theme.subtext } }
Expand All @@ -48,7 +48,7 @@ Rectangle {
z: 1; width: Theme.radiusMedium; height: Theme.radiusMedium
anchors.top: parent.top; anchors.left: parent.right
ShapePath {
fillColor: Theme.mantle; strokeColor: "transparent"
fillColor: Theme.chromeBackground; strokeColor: "transparent"
startX: 0; startY: 0
PathLine { x: Theme.radiusMedium; y: 0 }
PathArc {
Expand All @@ -65,7 +65,7 @@ Rectangle {
z: 1; width: Theme.radiusMedium; height: Theme.radiusMedium
anchors.bottom: parent.bottom; anchors.left: parent.right
ShapePath {
fillColor: Theme.mantle; strokeColor: "transparent"
fillColor: Theme.chromeBackground; strokeColor: "transparent"
startX: 0; startY: Theme.radiusMedium
PathLine { x: Theme.radiusMedium; y: Theme.radiusMedium }
PathArc {
Expand Down
6 changes: 3 additions & 3 deletions src/qml/components/StatusBar.qml
Original file line number Diff line number Diff line change
Expand Up @@ -53,15 +53,15 @@ Rectangle {
}

height: 28
color: Theme.mantle
color: Theme.chromeBackground
clip: false

// Inverse rounded corner — top left
Shape {
z: 1; width: Theme.radiusMedium; height: Theme.radiusMedium
anchors.bottom: parent.top; anchors.left: parent.left
ShapePath {
fillColor: Theme.mantle; strokeColor: "transparent"
fillColor: Theme.chromeBackground; strokeColor: "transparent"
startX: 0; startY: Theme.radiusMedium
PathLine { x: Theme.radiusMedium; y: Theme.radiusMedium }
PathArc {
Expand All @@ -78,7 +78,7 @@ Rectangle {
z: 1; width: Theme.radiusMedium; height: Theme.radiusMedium
anchors.bottom: parent.top; anchors.right: parent.right
ShapePath {
fillColor: Theme.mantle; strokeColor: "transparent"
fillColor: Theme.chromeBackground; strokeColor: "transparent"
startX: Theme.radiusMedium; startY: Theme.radiusMedium
PathLine { x: 0; y: Theme.radiusMedium }
PathArc {
Expand Down
2 changes: 1 addition & 1 deletion src/qml/components/Toast.qml
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@ Item {
implicitWidth: Math.max(240, toastRow.implicitWidth + 32)
implicitHeight: toastRow.implicitHeight + 20
radius: Theme.radiusMedium
color: Theme.mantle
color: Theme.overlayBackground

border.width: 2
border.color: toastItem.toastType === "error" ? Theme.error
Expand Down
8 changes: 4 additions & 4 deletions src/qml/components/Toolbar.qml
Original file line number Diff line number Diff line change
Expand Up @@ -94,7 +94,7 @@ Rectangle {
}

implicitHeight: toolbarColumn.implicitHeight
color: Theme.mantle
color: Theme.chromeBackground

DragHandler {
enabled: root.showWindowControls && root.window
Expand Down Expand Up @@ -481,7 +481,7 @@ Rectangle {

Rectangle {
anchors.fill: parent
color: Theme.mantle
color: "transparent"
// Top separator
Rectangle {
anchors.top: parent.top
Expand Down Expand Up @@ -808,7 +808,7 @@ Rectangle {
visible: tabStrip.contentX > 0.5
gradient: Gradient {
orientation: Gradient.Horizontal
GradientStop { position: 0; color: Theme.mantle }
GradientStop { position: 0; color: Theme.chromeBackground }
GradientStop { position: 1; color: "transparent" }
}
}
Expand All @@ -819,7 +819,7 @@ Rectangle {
gradient: Gradient {
orientation: Gradient.Horizontal
GradientStop { position: 0; color: "transparent" }
GradientStop { position: 1; color: Theme.mantle }
GradientStop { position: 1; color: Theme.chromeBackground }
}
}
}
Expand Down
5 changes: 5 additions & 0 deletions src/qml/theme/Theme.qml
Original file line number Diff line number Diff line change
Expand Up @@ -133,4 +133,9 @@ QtObject {
var alpha = 1 - strength * (1 - defaultAlpha)
return Qt.rgba(color.r, color.g, color.b, alpha)
}

readonly property color chromeBackground: containerColor(mantle, 0.75)
readonly property color contentBackground: containerColor(base, 0.65)
readonly property color overlayBackground: containerColor(mantle, 0.88)
readonly property color popupBackground: containerColor(crust, 0.88)
}
4 changes: 2 additions & 2 deletions src/qml/views/FileDetailedView.qml
Original file line number Diff line number Diff line change
Expand Up @@ -551,7 +551,7 @@ FocusScope {
Rectangle {
anchors.fill: parent
radius: Theme.radiusLarge
color: Theme.crust
color: Theme.popupBackground
border.color: Qt.rgba(Theme.text.r, Theme.text.g, Theme.text.b, 0.08)
border.width: 1
}
Expand Down Expand Up @@ -637,7 +637,7 @@ FocusScope {
z: 13
width: root.width
height: root.rowHeight
color: Theme.mantle
color: Theme.chromeBackground
radius: Theme.radiusMedium

// Cover the bottom corners so only the top is rounded
Expand Down
Loading