Skip to content
Open
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
64 changes: 64 additions & 0 deletions somnus/BarWidget.qml
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
import QtQuick
import Quickshell
import qs.Commons
import qs.Services.UI
import qs.Widgets

NIconButton {
id: root

property var pluginApi: null
property ShellScreen screen
property string widgetId: ""
property string section: ""
property int sectionWidgetIndex: -1
property int sectionWidgetsCount: 0

readonly property string iconColorKey: pluginApi?.pluginSettings?.iconColor
|| pluginApi?.manifest?.metadata?.defaultSettings?.iconColor || "primary"

icon: "power"
tooltipText: pluginApi?.tr("widget.tooltip")
tooltipDirection: BarService.getTooltipDirection(screen?.name)
baseSize: Style.getCapsuleHeightForScreen(screen?.name)
applyUiScale: false
customRadius: Style.radiusL

colorBg: Style.capsuleColor
colorFg: Color.resolveColorKey(iconColorKey)
colorBgHover: Color.mHover
colorFgHover: Color.mOnHover
colorBorder: "transparent"
colorBorderHover: "transparent"
border.color: Style.capsuleBorderColor
border.width: Style.capsuleBorderWidth

onClicked: {
Logger.i("Somnus", "Bar button pressed")
pluginApi?.mainInstance?.togglePanel?.(screen)
}

NPopupContextMenu {
id: contextMenu

model: [
{
"label": pluginApi?.tr("menu.settings"),
"action": "settings",
"icon": "settings"
}
]

onTriggered: action => {
contextMenu.close()
PanelService.closeContextMenu(screen)
if (action === "settings") {
BarService.openPluginSettings(screen, pluginApi?.manifest)
}
}
}

onRightClicked: {
PanelService.showContextMenu(contextMenu, root, screen)
}
}
58 changes: 58 additions & 0 deletions somnus/Main.qml
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
import QtQuick
import Quickshell
import Quickshell.Io
import qs.Commons

Item {
id: root

property var pluginApi: null
property bool isOpen: false

IpcHandler {
target: "plugin:somnus"
function toggle() {
var screen = null
try { var screens = Quickshell.screens; if (screens && screens.length > 0) screen = screens[0] }
catch (e) {}
if (!screen && pluginApi?.panelOpenScreen) screen = pluginApi.panelOpenScreen
Logger.i("Somnus", "IPC toggle: screen=" + (screen?.name ?? "null") + ", type=" + typeof screen + ", screens.len=" + (Quickshell.screens?.length ?? -1))
root.togglePanel(screen)
}
}

function togglePanel(screen) {
if (isOpen) closePanel()
else openPanel(screen)
}

function openPanel(screen) {
if (windowLoader.active) return
Logger.i("Somnus", "openPanel called, screen=" + (screen?.name ?? "null") + ", pluginApi=" + (root.pluginApi !== null))
windowLoader.setSource("SomnusWindow.qml", {
"screenRef": screen,
"pluginApi": root.pluginApi
})
windowLoader.active = true
isOpen = true
}

function closePanel() {
windowLoader.active = false
isOpen = false
}

Loader {
id: windowLoader
active: false
asynchronous: false

onLoaded: {
Logger.i("Somnus", "Loader onLoaded fired, item=" + (item !== null) + ", item.width=" + (item?.width ?? -1))
item.closeRequested.connect(root.closePanel)
}
onStatusChanged: {
Logger.i("Somnus", "Loader status=" + status + " (Loaded=" + Loader.Loaded + ")")
}
}
}
75 changes: 75 additions & 0 deletions somnus/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
# Somnus Power Menu

A fullscreen power menu, inspired by wlogout. Provides quick access to all system power actions with a clean, animated interface.

![preview](preview.png)

## Features

- **Two display modes**: Overlay (fullscreen with wallpaper blur and configurable tint) and Panel (centered window with semitransparent background)
- **Six power actions**: Lock, Logout, Suspend, Hibernate, Reboot, Shutdown
- **Smart suspend**: Optionally lock the session before suspending
- **Staggered animations**: Smooth entry animation per button with configurable toggle
- **Hover effects**: Scale and color change with adjustable desaturation
- **Full keyboard navigation**: Arrow keys, number keys (1–6), Enter, Escape
- **Bar widget**: Left-click toggles the menu, right-click opens settings
- **CLI support**: Toggle via `qs ipc call plugin:somnus toggle`
- **Theme-aware**: The bar button and hover colors automatically adapt to your Noctalia theme — whether it's generated from your wallpaper or a manual theme, light or dark mode.

## Configuration

All settings are available through the Noctalia settings panel. Right-click the bar button and select "Settings", or open it from the shell settings menu.

Buttons are arranged in a 3×2 grid. Number keys map to each position:

```
1 → Lock 2 → Logout 3 → Suspend
4 → Hibernate 5 → Reboot 6 → Shutdown
```

| Setting | Default | Description |
|---|---|---|
| `Icon Color` | `primary` | Color of the bar button icon |
| `Lock on Suspend` | `enabled` | Lock session before suspending |
| `Button Width` | `470 px` | Width of each power button |
| `Button Height` | `280 px` | Height of each power button |
| `Button Spacing` | `20 px` | Gap between buttons in the grid |
| `Button Opacity` | `50%` | Background opacity of idle buttons |
| `Hover Color` | `primary` | Background color on hover/focus |
| `Hover Desaturation` | `0%` | Desaturate the hover color (0–85%) |
| `Display Mode` | `Overlay` | Overlay (fullscreen + blur) or Panel (centered) |
| `Overlay Blur` | `75%` | Background blur intensity in overlay mode |
| `Overlay Tint` | `60%` | Dark tint opacity in overlay mode |
| `Panel Tint` | `70%` | Background opacity in panel mode |
| `Animations` | `enabled` | Toggle all entry and hover animations |

## Keyboard Shortcuts

| Key | Action |
|---|---|
| `Arrow keys` | Move focus between buttons |
| `1–6` | Select and execute action by position |
| `Enter / Space` | Execute focused action |
| `Escape / toggle keybind` | Close the menu |

## Keybind

Add to your compositor config:

### Hyprland (Lua)
```lua
hl.bind("SUPER + X", hl.dsp.exec_cmd("qs -c noctalia-shell ipc call plugin:somnus toggle"))
```

### Hyprland (Config)
```conf
bind = SUPER, X, exec, qs -c noctalia-shell ipc call plugin:somnus toggle
```

## License

MIT

## Credits

- **wlogout** — Interface design inspiration (button grid layout and power actions).
Loading