[volume] BREAKING CHANGE - new widget instead of old ones
Having three widgets for volume led to a problem of code duplication - same logic was duplicated three times. However when an issue was discovered and fixed, it was fixed in only one of three widgets. So I decided to create a volume widget from scratch, adding new features, such as selecting input/output, better responsiveness, easily customizable widget ui (bar, text, icon, icon and text, arc). Should close #199, #198, #185, #182, #47, #122, #183.
|
@ -1,112 +0,0 @@
|
||||||
# Volume widget
|
|
||||||
|
|
||||||
Volume widget based on [amixer](https://linux.die.net/man/1/amixer) (is used for controlling the audio volume) and [pacmd](https://linux.die.net/man/1/pacmd) (is used for selecting a sink/source). Also, the widget provides an easy way to customize how it looks, following types are supported out-of-the-box:
|
|
||||||
|
|
||||||
![types](./screenshots/variations.png)
|
|
||||||
|
|
||||||
From left to right: `horizontal_bar`, `vertical_bar`, `icon`, `icon_and_text`, `arc`
|
|
||||||
|
|
||||||
A right-click on the widget opens a popup where you can choose a sink/source:
|
|
||||||
![sink-sources](./screenshots/volume-sink-sources.png)
|
|
||||||
|
|
||||||
### Features
|
|
||||||
|
|
||||||
- switch between sinks/sources by right clicking on the widget;
|
|
||||||
- more responsive than previous versions of volume widget, which were refreshed once a second;
|
|
||||||
- 5 predefined customizable looks;
|
|
||||||
|
|
||||||
## Installation
|
|
||||||
|
|
||||||
Clone the repo under **~/.config/awesome/** and add widget in **rc.lua**:
|
|
||||||
|
|
||||||
```lua
|
|
||||||
local volume_widget = require('awesome-wm-widgets.experiments.volume.volume')
|
|
||||||
...
|
|
||||||
s.mytasklist, -- Middle widget
|
|
||||||
{ -- Right widgets
|
|
||||||
layout = wibox.layout.fixed.horizontal,
|
|
||||||
...
|
|
||||||
-- default
|
|
||||||
volume_widget(),
|
|
||||||
-- customized
|
|
||||||
volume_widget{
|
|
||||||
type = 'arc'
|
|
||||||
},
|
|
||||||
```
|
|
||||||
|
|
||||||
### Shortcuts
|
|
||||||
|
|
||||||
To improve responsiveness of the widget when volume level is changed by a shortcut use corresponding methods of the widget:
|
|
||||||
|
|
||||||
```lua
|
|
||||||
awful.key({ modkey }, "]", function() volume_widget:inc() end),
|
|
||||||
awful.key({ modkey }, "[", function() volume_widget:dec() end),
|
|
||||||
awful.key({ modkey }, "\\", function() volume_widget:toggle() end),
|
|
||||||
```
|
|
||||||
|
|
||||||
## Customization
|
|
||||||
|
|
||||||
It is possible to customize the widget by providing a table with all or some of the following config parameters:
|
|
||||||
|
|
||||||
### Generic parameter
|
|
||||||
|
|
||||||
| Name | Default | Description |
|
|
||||||
|---|---|---|
|
|
||||||
| `type`| `icon_and_text`| Widget type, one of `horizontal_bar`, `vertical_bar`, `icon`, `icon_and_text`, `arc` |
|
|
||||||
|
|
||||||
Depending on the chosen widget type add parameters from the corresponding section below:
|
|
||||||
|
|
||||||
#### `icon` parameters
|
|
||||||
|
|
||||||
| Name | Default | Description |
|
|
||||||
|---|---|---|
|
|
||||||
| `icon_dir`| `./icons`| Path to the folder with icons |
|
|
||||||
|
|
||||||
_Note:_ if you are changing icons, the folder should contain following .svg images:
|
|
||||||
- audio-volume-high-symbolic
|
|
||||||
- audio-volume-medium-symbolic
|
|
||||||
- audio-volume-low-symbolic
|
|
||||||
- audio-volume-muted-symbolic
|
|
||||||
|
|
||||||
#### `icon_and_text` parameters
|
|
||||||
|
|
||||||
| Name | Default | Description |
|
|
||||||
|---|---|---|
|
|
||||||
| `icon_dir`| `./icons`| Path to the folder with icons |
|
|
||||||
| `font` | `beautiful.font` | Font name and size, like `Play 12` |
|
|
||||||
|
|
||||||
#### `arc` parameters
|
|
||||||
|
|
||||||
| Name | Default | Description |
|
|
||||||
|---|---|---|
|
|
||||||
| `thickness` | 2 | Thickness of the arc |
|
|
||||||
| `main_color` | `beautiful.fg_color` | Color of the arc |
|
|
||||||
| `bg_color` | `#ffffff11` | Color of the arc's background |
|
|
||||||
| `mute_color` | `beautiful.fg_urgent` | Color of the arc when mute |
|
|
||||||
| `size` | 18 | Size of the widget |
|
|
||||||
|
|
||||||
#### `horizontal_bar` parameters
|
|
||||||
|
|
||||||
| Name | Default | Description |
|
|
||||||
|---|---|---|
|
|
||||||
| `main_color` | `beautiful.fg_normal` | Color of the bar |
|
|
||||||
| `mute_color` | `beautiful.fg_urgent` | Color of the bar when mute |
|
|
||||||
| `bg_color` | `'#ffffff11'` | Color of the bar's background |
|
|
||||||
| `width` | `50` | The bar width |
|
|
||||||
| `margins` | `10` | Top and bottom margins (if your wibar is 22 px high, bar will be 2 px = 22 - 2*10) |
|
|
||||||
| `shape` | `'bar'` | [gears.shape](https://awesomewm.org/doc/api/libraries/gears.shape.html), could be `octogon`, `hexagon`, `powerline`, etc |
|
|
||||||
| `with_icon` | `true` | Show volume icon|
|
|
||||||
|
|
||||||
_Note:_ I didn't figure out how does the `forced_height` property of progressbar widget work (maybe it doesn't work at all), thus there is a workaround with margins.
|
|
||||||
|
|
||||||
#### `vertical_bar` parameters
|
|
||||||
|
|
||||||
| Name | Default | Description |
|
|
||||||
|---|---|---|
|
|
||||||
| `main_color` | `beautiful.fg_normal` | Color of the bar |
|
|
||||||
| `mute_color` | `beautiful.fg_urgent` | Color of the bar when mute |
|
|
||||||
| `bg_color` | `'#ffffff11'` | Color of the bar's background |
|
|
||||||
| `width` | `10` | The bar width |
|
|
||||||
| `margins` | `20` | Top and bottom margins (if your wibar is 22 px high, bar will be 2 px = 22 - 2*10) |
|
|
||||||
| `shape` | `'bar'` | [gears.shape](https://awesomewm.org/doc/api/libraries/gears.shape.html), could be `octogon`, `hexagon`, `powerline`, etc |
|
|
||||||
| `with_icon` | `true` | Show volume icon|
|
|
|
@ -1,218 +0,0 @@
|
||||||
-------------------------------------------------
|
|
||||||
-- The Ultimate Volume Widget for Awesome Window Manager
|
|
||||||
-- More details could be found here:
|
|
||||||
-- https://github.com/streetturtle/awesome-wm-widgets/tree/master/volume-widget
|
|
||||||
|
|
||||||
-- @author Pavel Makhov
|
|
||||||
-- @copyright 2020 Pavel Makhov
|
|
||||||
-------------------------------------------------
|
|
||||||
|
|
||||||
local awful = require("awful")
|
|
||||||
local wibox = require("wibox")
|
|
||||||
local spawn = require("awful.spawn")
|
|
||||||
local gears = require("gears")
|
|
||||||
local beautiful = require("beautiful")
|
|
||||||
local watch = require("awful.widget.watch")
|
|
||||||
local utils = require("awesome-wm-widgets.experiments.volume.utils")
|
|
||||||
|
|
||||||
|
|
||||||
local LIST_DEVICES_CMD = [[sh -c "pacmd list-sinks; pacmd list-sources"]]
|
|
||||||
local GET_VOLUME_CMD = 'amixer -D pulse sget Master'
|
|
||||||
local INC_VOLUME_CMD = 'amixer -D pulse sset Master 5%+'
|
|
||||||
local DEC_VOLUME_CMD = 'amixer -D pulse sset Master 5%-'
|
|
||||||
local TOG_VOLUME_CMD = 'amixer -D pulse sset Master toggle'
|
|
||||||
|
|
||||||
|
|
||||||
local widget_types = {
|
|
||||||
icon_and_text = require("awesome-wm-widgets.experiments.volume.widgets.icon-and-text-widget"),
|
|
||||||
icon = require("awesome-wm-widgets.experiments.volume.widgets.icon-widget"),
|
|
||||||
arc = require("awesome-wm-widgets.experiments.volume.widgets.arc-widget"),
|
|
||||||
horizontal_bar = require("awesome-wm-widgets.experiments.volume.widgets.horizontal-bar-widget"),
|
|
||||||
vertical_bar = require("awesome-wm-widgets.experiments.volume.widgets.vertical-bar-widget")
|
|
||||||
}
|
|
||||||
local volume = {}
|
|
||||||
|
|
||||||
local rows = { layout = wibox.layout.fixed.vertical }
|
|
||||||
|
|
||||||
local popup = awful.popup{
|
|
||||||
bg = beautiful.bg_normal,
|
|
||||||
ontop = true,
|
|
||||||
visible = false,
|
|
||||||
shape = gears.shape.rounded_rect,
|
|
||||||
border_width = 1,
|
|
||||||
border_color = beautiful.bg_focus,
|
|
||||||
maximum_width = 400,
|
|
||||||
offset = { y = 5 },
|
|
||||||
widget = {}
|
|
||||||
}
|
|
||||||
|
|
||||||
local function build_main_line(device)
|
|
||||||
if device.active_port ~= nil and device.ports[device.active_port] ~= nil then
|
|
||||||
return device.properties.device_description .. ' · ' .. device.ports[device.active_port]
|
|
||||||
else
|
|
||||||
return device.properties.device_description
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
local function build_rows(devices, on_checkbox_click, device_type)
|
|
||||||
local device_rows = { layout = wibox.layout.fixed.vertical }
|
|
||||||
for _, device in pairs(devices) do
|
|
||||||
|
|
||||||
local checkbox = wibox.widget {
|
|
||||||
checked = device.is_default,
|
|
||||||
color = beautiful.bg_normal,
|
|
||||||
paddings = 2,
|
|
||||||
shape = gears.shape.circle,
|
|
||||||
forced_width = 20,
|
|
||||||
forced_height = 20,
|
|
||||||
check_color = beautiful.fg_urgent,
|
|
||||||
widget = wibox.widget.checkbox
|
|
||||||
}
|
|
||||||
|
|
||||||
checkbox:connect_signal("button::press", function()
|
|
||||||
spawn.easy_async(string.format([[sh -c 'pacmd set-default-%s "%s"']], device_type, device.name), function()
|
|
||||||
on_checkbox_click()
|
|
||||||
end)
|
|
||||||
end)
|
|
||||||
|
|
||||||
local row = wibox.widget {
|
|
||||||
{
|
|
||||||
{
|
|
||||||
{
|
|
||||||
checkbox,
|
|
||||||
valign = 'center',
|
|
||||||
layout = wibox.container.place,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
{
|
|
||||||
text = build_main_line(device),
|
|
||||||
align = 'left',
|
|
||||||
widget = wibox.widget.textbox
|
|
||||||
},
|
|
||||||
left = 10,
|
|
||||||
layout = wibox.container.margin
|
|
||||||
},
|
|
||||||
spacing = 8,
|
|
||||||
layout = wibox.layout.align.horizontal
|
|
||||||
},
|
|
||||||
margins = 4,
|
|
||||||
layout = wibox.container.margin
|
|
||||||
},
|
|
||||||
bg = beautiful.bg_normal,
|
|
||||||
widget = wibox.container.background
|
|
||||||
}
|
|
||||||
|
|
||||||
row:connect_signal("mouse::enter", function(c) c:set_bg(beautiful.bg_focus) end)
|
|
||||||
row:connect_signal("mouse::leave", function(c) c:set_bg(beautiful.bg_normal) end)
|
|
||||||
|
|
||||||
local old_cursor, old_wibox
|
|
||||||
row:connect_signal("mouse::enter", function()
|
|
||||||
local wb = mouse.current_wibox
|
|
||||||
old_cursor, old_wibox = wb.cursor, wb
|
|
||||||
wb.cursor = "hand1"
|
|
||||||
end)
|
|
||||||
row:connect_signal("mouse::leave", function()
|
|
||||||
if old_wibox then
|
|
||||||
old_wibox.cursor = old_cursor
|
|
||||||
old_wibox = nil
|
|
||||||
end
|
|
||||||
end)
|
|
||||||
|
|
||||||
row:connect_signal("button::press", function()
|
|
||||||
spawn.easy_async(string.format([[sh -c 'pacmd set-default-%s "%s"']], device_type, device.name), function()
|
|
||||||
on_checkbox_click()
|
|
||||||
end)
|
|
||||||
end)
|
|
||||||
|
|
||||||
table.insert(device_rows, row)
|
|
||||||
end
|
|
||||||
|
|
||||||
return device_rows
|
|
||||||
end
|
|
||||||
|
|
||||||
local function build_header_row(text)
|
|
||||||
return wibox.widget{
|
|
||||||
{
|
|
||||||
markup = "<b>" .. text .. "</b>",
|
|
||||||
align = 'center',
|
|
||||||
widget = wibox.widget.textbox
|
|
||||||
},
|
|
||||||
bg = beautiful.bg_normal,
|
|
||||||
widget = wibox.container.background
|
|
||||||
}
|
|
||||||
end
|
|
||||||
|
|
||||||
local function rebuild_popup()
|
|
||||||
spawn.easy_async(LIST_DEVICES_CMD, function(stdout)
|
|
||||||
|
|
||||||
local sinks, sources = utils.extract_sinks_and_sources(stdout)
|
|
||||||
|
|
||||||
for i = 0, #rows do rows[i]=nil end
|
|
||||||
|
|
||||||
table.insert(rows, build_header_row("SINKS"))
|
|
||||||
table.insert(rows, build_rows(sinks, function() rebuild_popup() end, "sink"))
|
|
||||||
table.insert(rows, build_header_row("SOURCES"))
|
|
||||||
table.insert(rows, build_rows(sources, function() rebuild_popup() end, "source"))
|
|
||||||
|
|
||||||
popup:setup(rows)
|
|
||||||
end)
|
|
||||||
end
|
|
||||||
|
|
||||||
|
|
||||||
local function worker(user_args)
|
|
||||||
|
|
||||||
local args = user_args or {}
|
|
||||||
|
|
||||||
local widget_type = args.widget_type
|
|
||||||
local refresh_rate = args.refresh_rate or 1
|
|
||||||
|
|
||||||
if widget_types[widget_type] == nil then
|
|
||||||
volume.widget = widget_types['icon_and_text'].get_widget(user_args.icon_and_text_args)
|
|
||||||
else
|
|
||||||
volume.widget = widget_types[widget_type].get_widget(args)
|
|
||||||
end
|
|
||||||
|
|
||||||
local function update_graphic(widget, stdout)
|
|
||||||
local mute = string.match(stdout, "%[(o%D%D?)%]") -- \[(o\D\D?)\] - [on] or [off]
|
|
||||||
if mute == 'off' then widget:mute()
|
|
||||||
elseif mute == 'on' then widget:unmute()
|
|
||||||
end
|
|
||||||
local volume_level = string.match(stdout, "(%d?%d?%d)%%") -- (\d?\d?\d)\%)
|
|
||||||
volume_level = string.format("% 3d", volume_level)
|
|
||||||
widget:set_volume_level(volume_level)
|
|
||||||
end
|
|
||||||
|
|
||||||
function volume:inc()
|
|
||||||
spawn.easy_async(INC_VOLUME_CMD, function(stdout) update_graphic(volume.widget, stdout) end)
|
|
||||||
end
|
|
||||||
|
|
||||||
function volume:dec()
|
|
||||||
spawn.easy_async(DEC_VOLUME_CMD, function(stdout) update_graphic(volume.widget, stdout) end)
|
|
||||||
end
|
|
||||||
|
|
||||||
function volume:toggle()
|
|
||||||
spawn.easy_async(TOG_VOLUME_CMD, function(stdout) update_graphic(volume.widget, stdout) end)
|
|
||||||
end
|
|
||||||
|
|
||||||
volume.widget:buttons(
|
|
||||||
awful.util.table.join(
|
|
||||||
awful.button({}, 3, function()
|
|
||||||
if popup.visible then
|
|
||||||
popup.visible = not popup.visible
|
|
||||||
else
|
|
||||||
rebuild_popup()
|
|
||||||
popup:move_next_to(mouse.current_widget_geometry)
|
|
||||||
end
|
|
||||||
end),
|
|
||||||
awful.button({}, 4, function() volume:inc() end),
|
|
||||||
awful.button({}, 5, function() volume:dec() end),
|
|
||||||
awful.button({}, 1, function() volume:toggle() end)
|
|
||||||
)
|
|
||||||
)
|
|
||||||
|
|
||||||
watch(GET_VOLUME_CMD, refresh_rate, update_graphic, volume.widget)
|
|
||||||
|
|
||||||
return volume.widget
|
|
||||||
end
|
|
||||||
|
|
||||||
return setmetatable(volume, { __call = function(_, ...) return worker(...) end })
|
|
|
@ -1,109 +1,112 @@
|
||||||
# Volume widget
|
# Volume widget
|
||||||
|
|
||||||
Simple and easy-to-install widget for Awesome Window Manager which shows the sound level: ![Volume Widget](./vol-widget-1.png)
|
Volume widget based on [amixer](https://linux.die.net/man/1/amixer) (is used for controlling the audio volume) and [pacmd](https://linux.die.net/man/1/pacmd) (is used for selecting a sink/source). Also, the widget provides an easy way to customize how it looks, following types are supported out-of-the-box:
|
||||||
|
|
||||||
Note that widget uses the Arc icon theme, so it should be [installed](https://github.com/horst3180/arc-icon-theme#installation) first under **/usr/share/icons/Arc/** folder.
|
![types](screenshots/variations.png)
|
||||||
|
|
||||||
## Customization
|
From left to right: `horizontal_bar`, `vertical_bar`, `icon`, `icon_and_text`, `arc`
|
||||||
|
|
||||||
It is possible to customize widget by providing a table with all or some of the following config parameters:
|
A right-click on the widget opens a popup where you can choose a sink/source:
|
||||||
|
![sink-sources](screenshots/volume-sink-sources.png)
|
||||||
|
|
||||||
| Name | Default | Description |
|
### Features
|
||||||
|---|---|---|
|
|
||||||
| `volume_audio_controller`| `pulse` | audio device |
|
- switch between sinks/sources by right clicking on the widget;
|
||||||
| `display_notification` | `false` | Display a notification on mouseover and keypress |
|
- more responsive than previous versions of volume widget, which were refreshed once a second;
|
||||||
| `notification_position` | `top_right`| The notification position |
|
- 5 predefined customizable looks;
|
||||||
| `delta` | 5 | The volume +/- percentage |
|
|
||||||
|
|
||||||
## Installation
|
## Installation
|
||||||
|
|
||||||
- clone/copy **volume.lua** file;
|
Clone the repo under **~/.config/awesome/** and add widget in **rc.lua**:
|
||||||
|
|
||||||
- include `volume.lua` and add volume widget to your wibox in rc.lua:
|
|
||||||
|
|
||||||
```lua
|
```lua
|
||||||
local volume_widget = require("awesome-wm-widgets.volume-widget.volume")
|
local volume_widget = require('awesome-wm-widgets.volume-widget.volume')
|
||||||
local volume_widget_widget = volume_widget({display_notification = true})
|
|
||||||
...
|
...
|
||||||
s.mytasklist, -- Middle widget
|
s.mytasklist, -- Middle widget
|
||||||
{ -- Right widgets
|
{ -- Right widgets
|
||||||
...
|
layout = wibox.layout.fixed.horizontal,
|
||||||
volume_widget_widget,
|
...
|
||||||
...
|
-- default
|
||||||
|
volume_widget(),
|
||||||
|
-- customized
|
||||||
|
volume_widget{
|
||||||
|
type = 'arc'
|
||||||
|
},
|
||||||
```
|
```
|
||||||
### Control volume
|
|
||||||
|
|
||||||
To mute/unmute click on the widget. To increase/decrease volume scroll up or down when mouse cursor is over the widget.
|
### Shortcuts
|
||||||
|
|
||||||
If you want to control volume level by keyboard shortcuts add following lines in shortcut section of the **rc.lua**:
|
To improve responsiveness of the widget when volume level is changed by a shortcut use corresponding methods of the widget:
|
||||||
IF you have notification activated, a notification will pop-up on key press
|
|
||||||
|
|
||||||
```lua
|
```lua
|
||||||
-- Key bindings
|
awful.key({ modkey }, "]", function() volume_widget:inc() end),
|
||||||
globalkeys = gears.table.join(
|
awful.key({ modkey }, "[", function() volume_widget:dec() end),
|
||||||
awful.key(
|
awful.key({ modkey }, "\\", function() volume_widget:toggle() end),
|
||||||
{},
|
|
||||||
'XF86AudioRaiseVolume',
|
|
||||||
volume_widget.raise,
|
|
||||||
{description = 'volume up', group = 'hotkeys'}
|
|
||||||
),
|
|
||||||
awful.key(
|
|
||||||
{},
|
|
||||||
'XF86AudioLowerVolume',
|
|
||||||
volume_widget.lower,
|
|
||||||
{description = 'volume down', group = 'hotkeys'}
|
|
||||||
),
|
|
||||||
awful.key(
|
|
||||||
{},
|
|
||||||
'XF86AudioMute',
|
|
||||||
volume_widget.toggle,
|
|
||||||
{description = 'toggle mute', group = 'hotkeys'}
|
|
||||||
),
|
|
||||||
```
|
```
|
||||||
|
|
||||||
### Icons
|
## Customization
|
||||||
|
|
||||||
- _Optional step._ In Arc icon theme the muted audio level icon (![Volume-widget](./audio-volume-muted-symbolic.png)) looks like 0 level icon, which could be a bit misleading.
|
It is possible to customize the widget by providing a table with all or some of the following config parameters:
|
||||||
So I decided to use original muted icon for low audio level, and the same icon, but colored in red for muted audio level. Fortunately icons are in svg format, so you can easily recolor them with `sed`, so it would look like this (![Volume Widget](./audio-volume-muted-symbolic_red.png)):
|
|
||||||
|
|
||||||
```bash
|
### Generic parameter
|
||||||
cd /usr/share/icons/Arc/status/symbolic &&
|
|
||||||
sudo cp audio-volume-muted-symbolic.svg audio-volume-muted-symbolic_red.svg &&
|
|
||||||
sudo sed -i 's/bebebe/ed4737/g' ./audio-volume-muted-symbolic_red.svg
|
|
||||||
```
|
|
||||||
|
|
||||||
### Pulse or ALSA only
|
| Name | Default | Description |
|
||||||
|
|---|---|---|
|
||||||
|
| `type`| `icon_and_text`| Widget type, one of `horizontal_bar`, `vertical_bar`, `icon`, `icon_and_text`, `arc` |
|
||||||
|
|
||||||
Try running this command:
|
Depending on the chosen widget type add parameters from the corresponding section below:
|
||||||
|
|
||||||
```bash
|
#### `icon` parameters
|
||||||
amixer -D pulse sget Master
|
|
||||||
```
|
|
||||||
|
|
||||||
If that prints something like this, then the default setting of 'pulse' is probably fine:
|
| Name | Default | Description |
|
||||||
|
|---|---|---|
|
||||||
|
| `icon_dir`| `./icons`| Path to the folder with icons |
|
||||||
|
|
||||||
```
|
_Note:_ if you are changing icons, the folder should contain following .svg images:
|
||||||
Simple mixer control 'Master',0
|
- audio-volume-high-symbolic
|
||||||
Capabilities: pvolume pvolume-joined pswitch pswitch-joined
|
- audio-volume-medium-symbolic
|
||||||
Playback channels: Mono
|
- audio-volume-low-symbolic
|
||||||
Limits: Playback 0 - 64
|
- audio-volume-muted-symbolic
|
||||||
Mono: Playback 64 [100%] [0.00dB] [on]
|
|
||||||
|
|
||||||
```
|
#### `icon_and_text` parameters
|
||||||
|
|
||||||
If it prints something like this:
|
| Name | Default | Description |
|
||||||
|
|---|---|---|
|
||||||
|
| `icon_dir`| `./icons`| Path to the folder with icons |
|
||||||
|
| `font` | `beautiful.font` | Font name and size, like `Play 12` |
|
||||||
|
|
||||||
```bash
|
#### `arc` parameters
|
||||||
$ amixer -D pulse sget Master
|
|
||||||
ALSA lib pulse.c:243:(pulse_connect) PulseAudio: Unable to connect: Connection refused
|
|
||||||
|
|
||||||
amixer: Mixer attach pulse error: Connection refused
|
| Name | Default | Description |
|
||||||
```
|
|---|---|---|
|
||||||
then set `volume_audio_controller` to `alsa_only` in widget constructor:
|
| `thickness` | 2 | Thickness of the arc |
|
||||||
|
| `main_color` | `beautiful.fg_color` | Color of the arc |
|
||||||
|
| `bg_color` | `#ffffff11` | Color of the arc's background |
|
||||||
|
| `mute_color` | `beautiful.fg_urgent` | Color of the arc when mute |
|
||||||
|
| `size` | 18 | Size of the widget |
|
||||||
|
|
||||||
```lua
|
#### `horizontal_bar` parameters
|
||||||
volume_widget({
|
|
||||||
volume_audio_controller = 'alsa_only'
|
| Name | Default | Description |
|
||||||
})
|
|---|---|---|
|
||||||
```
|
| `main_color` | `beautiful.fg_normal` | Color of the bar |
|
||||||
|
| `mute_color` | `beautiful.fg_urgent` | Color of the bar when mute |
|
||||||
|
| `bg_color` | `'#ffffff11'` | Color of the bar's background |
|
||||||
|
| `width` | `50` | The bar width |
|
||||||
|
| `margins` | `10` | Top and bottom margins (if your wibar is 22 px high, bar will be 2 px = 22 - 2*10) |
|
||||||
|
| `shape` | `'bar'` | [gears.shape](https://awesomewm.org/doc/api/libraries/gears.shape.html), could be `octogon`, `hexagon`, `powerline`, etc |
|
||||||
|
| `with_icon` | `true` | Show volume icon|
|
||||||
|
|
||||||
|
_Note:_ I didn't figure out how does the `forced_height` property of progressbar widget work (maybe it doesn't work at all), thus there is a workaround with margins.
|
||||||
|
|
||||||
|
#### `vertical_bar` parameters
|
||||||
|
|
||||||
|
| Name | Default | Description |
|
||||||
|
|---|---|---|
|
||||||
|
| `main_color` | `beautiful.fg_normal` | Color of the bar |
|
||||||
|
| `mute_color` | `beautiful.fg_urgent` | Color of the bar when mute |
|
||||||
|
| `bg_color` | `'#ffffff11'` | Color of the bar's background |
|
||||||
|
| `width` | `10` | The bar width |
|
||||||
|
| `margins` | `20` | Top and bottom margins (if your wibar is 22 px high, bar will be 2 px = 22 - 2*10) |
|
||||||
|
| `shape` | `'bar'` | [gears.shape](https://awesomewm.org/doc/api/libraries/gears.shape.html), could be `octogon`, `hexagon`, `powerline`, etc |
|
||||||
|
| `with_icon` | `true` | Show volume icon|
|
||||||
|
|
Before Width: | Height: | Size: 435 B |
|
@ -1,88 +0,0 @@
|
||||||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
|
||||||
<svg
|
|
||||||
xmlns:dc="http://purl.org/dc/elements/1.1/"
|
|
||||||
xmlns:cc="http://creativecommons.org/ns#"
|
|
||||||
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
|
|
||||||
xmlns:svg="http://www.w3.org/2000/svg"
|
|
||||||
xmlns="http://www.w3.org/2000/svg"
|
|
||||||
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
|
|
||||||
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
|
|
||||||
width="16"
|
|
||||||
viewBox="0 0 16 16"
|
|
||||||
height="16"
|
|
||||||
id="svg2"
|
|
||||||
version="1.1"
|
|
||||||
inkscape:version="0.91 r13725"
|
|
||||||
sodipodi:docname="audio-volume-muted-symbolic.svg">
|
|
||||||
<metadata
|
|
||||||
id="metadata30">
|
|
||||||
<rdf:RDF>
|
|
||||||
<cc:Work
|
|
||||||
rdf:about="">
|
|
||||||
<dc:format>image/svg+xml</dc:format>
|
|
||||||
<dc:type
|
|
||||||
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
|
|
||||||
<dc:title></dc:title>
|
|
||||||
</cc:Work>
|
|
||||||
</rdf:RDF>
|
|
||||||
</metadata>
|
|
||||||
<sodipodi:namedview
|
|
||||||
pagecolor="#ffffff"
|
|
||||||
bordercolor="#666666"
|
|
||||||
borderopacity="1"
|
|
||||||
objecttolerance="10"
|
|
||||||
gridtolerance="10"
|
|
||||||
guidetolerance="10"
|
|
||||||
inkscape:pageopacity="0"
|
|
||||||
inkscape:pageshadow="2"
|
|
||||||
inkscape:window-width="1215"
|
|
||||||
inkscape:window-height="776"
|
|
||||||
id="namedview28"
|
|
||||||
showgrid="true"
|
|
||||||
inkscape:zoom="38.125"
|
|
||||||
inkscape:cx="3.4229508"
|
|
||||||
inkscape:cy="7.947541"
|
|
||||||
inkscape:window-x="65"
|
|
||||||
inkscape:window-y="24"
|
|
||||||
inkscape:window-maximized="1"
|
|
||||||
inkscape:current-layer="svg2"
|
|
||||||
showguides="true"
|
|
||||||
inkscape:snap-intersection-paths="false"
|
|
||||||
inkscape:object-paths="false">
|
|
||||||
<inkscape:grid
|
|
||||||
type="xygrid"
|
|
||||||
id="grid4158" />
|
|
||||||
</sodipodi:namedview>
|
|
||||||
<defs
|
|
||||||
id="defs4" />
|
|
||||||
<path
|
|
||||||
d="M 6,2 2,6 2,10 6,14 6,9 7,8 6,7 Z"
|
|
||||||
id="path18"
|
|
||||||
inkscape:connector-curvature="0"
|
|
||||||
style="fill:#bebebe"
|
|
||||||
sodipodi:nodetypes="cccccccc" />
|
|
||||||
<path
|
|
||||||
d="M 1.300003,5 C 0.216589,5 0,6.163269 0,7.4 L 0,8.6 C 0,9.836747 0.24312,11 1.300003,11 L 3,11 3,5 Z"
|
|
||||||
id="path20"
|
|
||||||
inkscape:connector-curvature="0"
|
|
||||||
style="fill:#bebebe"
|
|
||||||
sodipodi:nodetypes="ssssccs" />
|
|
||||||
<path
|
|
||||||
style="opacity:0.3;fill:#bebebe;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
|
|
||||||
d="M 13.140638,1 11.726417,2.413582 C 12.808349,3.4955144 13.990412,5.4467621 14,8 c 0,2.551493 -1.192916,4.505751 -2.273583,5.586418 L 13.140638,15 C 14.595711,13.544927 16.019176,11 16,8 16.035061,5 14.595117,2.4544787 13.140638,1 Z"
|
|
||||||
id="path4508"
|
|
||||||
inkscape:connector-curvature="0"
|
|
||||||
sodipodi:nodetypes="ccccccc" />
|
|
||||||
<path
|
|
||||||
style="opacity:0.3;fill:#bebebe;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
|
|
||||||
d="M 11,3.1156678 9.5897193,4.5261118 C 10.372347,5.3087395 11,6.5690611 11,8 11,9.4309388 10.372767,10.690952 9.5897193,11.474 L 11,12.884 C 12.275645,11.608355 13,9.854095 13,8 13,6.1543677 12.273068,4.3887355 11,3.1156678 Z"
|
|
||||||
id="path4529"
|
|
||||||
inkscape:connector-curvature="0"
|
|
||||||
sodipodi:nodetypes="ccccccc" />
|
|
||||||
<path
|
|
||||||
style="opacity:0.3;fill:#bebebe;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
|
|
||||||
d="M 8.629,5 7.2094668,6.4096296 C 8,7.05621 8,7.805653 8,8 8,8.1932576 7.982199,8.9408674 7.209,9.59 L 8.6289063,11 C 9.8466375,9.952694 10,8.5984701 10,8 10,7.400497 9.854476,6.062891 8.629,5 Z"
|
|
||||||
id="path4569"
|
|
||||||
inkscape:connector-curvature="0"
|
|
||||||
sodipodi:nodetypes="ccscccc" />
|
|
||||||
</svg>
|
|
Before Width: | Height: | Size: 3.5 KiB |
|
@ -1,81 +0,0 @@
|
||||||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
|
||||||
<svg
|
|
||||||
xmlns:dc="http://purl.org/dc/elements/1.1/"
|
|
||||||
xmlns:cc="http://creativecommons.org/ns#"
|
|
||||||
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
|
|
||||||
xmlns:svg="http://www.w3.org/2000/svg"
|
|
||||||
xmlns="http://www.w3.org/2000/svg"
|
|
||||||
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
|
|
||||||
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
|
|
||||||
width="16"
|
|
||||||
viewBox="0 0 16 16"
|
|
||||||
height="16"
|
|
||||||
id="svg2"
|
|
||||||
version="1.1"
|
|
||||||
inkscape:version="0.92.2 2405546, 2018-03-11"
|
|
||||||
sodipodi:docname="audio-volume-muted-symbolic-shan.svg">
|
|
||||||
<metadata
|
|
||||||
id="metadata30">
|
|
||||||
<rdf:RDF>
|
|
||||||
<cc:Work
|
|
||||||
rdf:about="">
|
|
||||||
<dc:format>image/svg+xml</dc:format>
|
|
||||||
<dc:type
|
|
||||||
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
|
|
||||||
<dc:title></dc:title>
|
|
||||||
</cc:Work>
|
|
||||||
</rdf:RDF>
|
|
||||||
</metadata>
|
|
||||||
<sodipodi:namedview
|
|
||||||
pagecolor="#ffffff"
|
|
||||||
bordercolor="#666666"
|
|
||||||
borderopacity="1"
|
|
||||||
objecttolerance="10"
|
|
||||||
gridtolerance="10"
|
|
||||||
guidetolerance="10"
|
|
||||||
inkscape:pageopacity="0"
|
|
||||||
inkscape:pageshadow="2"
|
|
||||||
inkscape:window-width="1438"
|
|
||||||
inkscape:window-height="858"
|
|
||||||
id="namedview28"
|
|
||||||
showgrid="true"
|
|
||||||
inkscape:zoom="38.125"
|
|
||||||
inkscape:cx="3.4229508"
|
|
||||||
inkscape:cy="7.947541"
|
|
||||||
inkscape:window-x="0"
|
|
||||||
inkscape:window-y="20"
|
|
||||||
inkscape:window-maximized="1"
|
|
||||||
inkscape:current-layer="svg2"
|
|
||||||
showguides="true"
|
|
||||||
inkscape:snap-intersection-paths="false"
|
|
||||||
inkscape:object-paths="false">
|
|
||||||
<inkscape:grid
|
|
||||||
type="xygrid"
|
|
||||||
id="grid4158" />
|
|
||||||
</sodipodi:namedview>
|
|
||||||
<defs
|
|
||||||
id="defs4" />
|
|
||||||
<path
|
|
||||||
style="opacity:0.3;fill:#bebebe;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
|
|
||||||
d="M 13.140638,1 11.726417,2.413582 C 12.808349,3.4955144 13.990412,5.4467621 14,8 c 0,2.551493 -1.192916,4.505751 -2.273583,5.586418 L 13.140638,15 C 14.595711,13.544927 16.019176,11 16,8 16.035061,5 14.595117,2.4544787 13.140638,1 Z"
|
|
||||||
id="path4508"
|
|
||||||
inkscape:connector-curvature="0"
|
|
||||||
sodipodi:nodetypes="ccccccc" />
|
|
||||||
<path
|
|
||||||
style="opacity:0.3;fill:#bebebe;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
|
|
||||||
d="M 11,3.1156678 9.5897193,4.5261118 C 10.372347,5.3087395 11,6.5690611 11,8 11,9.4309388 10.372767,10.690952 9.5897193,11.474 L 11,12.884 C 12.275645,11.608355 13,9.854095 13,8 13,6.1543677 12.273068,4.3887355 11,3.1156678 Z"
|
|
||||||
id="path4529"
|
|
||||||
inkscape:connector-curvature="0"
|
|
||||||
sodipodi:nodetypes="ccccccc" />
|
|
||||||
<path
|
|
||||||
style="opacity:0.3;fill:#bebebe;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
|
|
||||||
d="M 8.629,5 7.2094668,6.4096296 C 8,7.05621 8,7.805653 8,8 8,8.1932576 7.982199,8.9408674 7.209,9.59 L 8.6289063,11 C 9.8466375,9.952694 10,8.5984701 10,8 10,7.400497 9.854476,6.062891 8.629,5 Z"
|
|
||||||
id="path4569"
|
|
||||||
inkscape:connector-curvature="0"
|
|
||||||
sodipodi:nodetypes="ccscccc" />
|
|
||||||
<path
|
|
||||||
style="opacity:0.3;fill:#bebebe;fill-opacity:1;stroke-width:0.02622951"
|
|
||||||
d="M 4.5036936,12.482983 3.0218135,11.000927 2.1430379,11.000775 C 1.6597113,11.000691 1.1955581,10.989371 1.1115864,10.975618 0.56198086,10.885606 0.24352693,10.462909 0.07812436,9.603862 0.03708101,9.390696 0.03147539,9.196108 0.03147539,7.984533 c 0,-1.217172 0.0054766,-1.405527 0.04717053,-1.622335 0.132109,-0.686963 0.3489491,-1.058742 0.7259726,-1.244702 L 0.97448297,5.033716 1.9849464,5.026316 2.9954098,5.018916 4.4970492,3.518184 5.9986885,2.0174522 V 4.5094289 7.001406 l 0.4983672,0.497849 0.498367,0.497849 -0.4982329,0.498725 -0.498233,0.498725 -0.00669,2.485223 -0.00669,2.485223 z"
|
|
||||||
id="path819"
|
|
||||||
inkscape:connector-curvature="0" />
|
|
||||||
</svg>
|
|
Before Width: | Height: | Size: 3.8 KiB |
Before Width: | Height: | Size: 450 B |
|
@ -1,88 +0,0 @@
|
||||||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
|
||||||
<svg
|
|
||||||
xmlns:dc="http://purl.org/dc/elements/1.1/"
|
|
||||||
xmlns:cc="http://creativecommons.org/ns#"
|
|
||||||
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
|
|
||||||
xmlns:svg="http://www.w3.org/2000/svg"
|
|
||||||
xmlns="http://www.w3.org/2000/svg"
|
|
||||||
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
|
|
||||||
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
|
|
||||||
width="16"
|
|
||||||
viewBox="0 0 16 16"
|
|
||||||
height="16"
|
|
||||||
id="svg2"
|
|
||||||
version="1.1"
|
|
||||||
inkscape:version="0.91 r13725"
|
|
||||||
sodipodi:docname="audio-volume-muted-symbolic.svg">
|
|
||||||
<metadata
|
|
||||||
id="metadata30">
|
|
||||||
<rdf:RDF>
|
|
||||||
<cc:Work
|
|
||||||
rdf:about="">
|
|
||||||
<dc:format>image/svg+xml</dc:format>
|
|
||||||
<dc:type
|
|
||||||
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
|
|
||||||
<dc:title></dc:title>
|
|
||||||
</cc:Work>
|
|
||||||
</rdf:RDF>
|
|
||||||
</metadata>
|
|
||||||
<sodipodi:namedview
|
|
||||||
pagecolor="#ffffff"
|
|
||||||
bordercolor="#666666"
|
|
||||||
borderopacity="1"
|
|
||||||
objecttolerance="10"
|
|
||||||
gridtolerance="10"
|
|
||||||
guidetolerance="10"
|
|
||||||
inkscape:pageopacity="0"
|
|
||||||
inkscape:pageshadow="2"
|
|
||||||
inkscape:window-width="1215"
|
|
||||||
inkscape:window-height="776"
|
|
||||||
id="namedview28"
|
|
||||||
showgrid="true"
|
|
||||||
inkscape:zoom="38.125"
|
|
||||||
inkscape:cx="3.4229508"
|
|
||||||
inkscape:cy="7.947541"
|
|
||||||
inkscape:window-x="65"
|
|
||||||
inkscape:window-y="24"
|
|
||||||
inkscape:window-maximized="1"
|
|
||||||
inkscape:current-layer="svg2"
|
|
||||||
showguides="true"
|
|
||||||
inkscape:snap-intersection-paths="false"
|
|
||||||
inkscape:object-paths="false">
|
|
||||||
<inkscape:grid
|
|
||||||
type="xygrid"
|
|
||||||
id="grid4158" />
|
|
||||||
</sodipodi:namedview>
|
|
||||||
<defs
|
|
||||||
id="defs4" />
|
|
||||||
<path
|
|
||||||
d="M 6,2 2,6 2,10 6,14 6,9 7,8 6,7 Z"
|
|
||||||
id="path18"
|
|
||||||
inkscape:connector-curvature="0"
|
|
||||||
style="fill:#ed4737"
|
|
||||||
sodipodi:nodetypes="cccccccc" />
|
|
||||||
<path
|
|
||||||
d="M 1.300003,5 C 0.216589,5 0,6.163269 0,7.4 L 0,8.6 C 0,9.836747 0.24312,11 1.300003,11 L 3,11 3,5 Z"
|
|
||||||
id="path20"
|
|
||||||
inkscape:connector-curvature="0"
|
|
||||||
style="fill:#ed4737"
|
|
||||||
sodipodi:nodetypes="ssssccs" />
|
|
||||||
<path
|
|
||||||
style="opacity:0.3;fill:#ed4737;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
|
|
||||||
d="M 13.140638,1 11.726417,2.413582 C 12.808349,3.4955144 13.990412,5.4467621 14,8 c 0,2.551493 -1.192916,4.505751 -2.273583,5.586418 L 13.140638,15 C 14.595711,13.544927 16.019176,11 16,8 16.035061,5 14.595117,2.4544787 13.140638,1 Z"
|
|
||||||
id="path4508"
|
|
||||||
inkscape:connector-curvature="0"
|
|
||||||
sodipodi:nodetypes="ccccccc" />
|
|
||||||
<path
|
|
||||||
style="opacity:0.3;fill:#ed4737;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
|
|
||||||
d="M 11,3.1156678 9.5897193,4.5261118 C 10.372347,5.3087395 11,6.5690611 11,8 11,9.4309388 10.372767,10.690952 9.5897193,11.474 L 11,12.884 C 12.275645,11.608355 13,9.854095 13,8 13,6.1543677 12.273068,4.3887355 11,3.1156678 Z"
|
|
||||||
id="path4529"
|
|
||||||
inkscape:connector-curvature="0"
|
|
||||||
sodipodi:nodetypes="ccccccc" />
|
|
||||||
<path
|
|
||||||
style="opacity:0.3;fill:#ed4737;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
|
|
||||||
d="M 8.629,5 7.2094668,6.4096296 C 8,7.05621 8,7.805653 8,8 8,8.1932576 7.982199,8.9408674 7.209,9.59 L 8.6289063,11 C 9.8466375,9.952694 10,8.5984701 10,8 10,7.400497 9.854476,6.062891 8.629,5 Z"
|
|
||||||
id="path4569"
|
|
||||||
inkscape:connector-curvature="0"
|
|
||||||
sodipodi:nodetypes="ccscccc" />
|
|
||||||
</svg>
|
|
Before Width: | Height: | Size: 3.5 KiB |
Before Width: | Height: | Size: 3.4 KiB After Width: | Height: | Size: 3.4 KiB |
Before Width: | Height: | Size: 3.4 KiB After Width: | Height: | Size: 3.4 KiB |
Before Width: | Height: | Size: 3.4 KiB After Width: | Height: | Size: 3.4 KiB |
Before Width: | Height: | Size: 3.5 KiB After Width: | Height: | Size: 3.5 KiB |
Before Width: | Height: | Size: 8.9 KiB After Width: | Height: | Size: 8.9 KiB |
Before Width: | Height: | Size: 72 KiB After Width: | Height: | Size: 72 KiB |
Before Width: | Height: | Size: 824 B |
Before Width: | Height: | Size: 354 B After Width: | Height: | Size: 354 B |
|
@ -1,181 +1,216 @@
|
||||||
-------------------------------------------------
|
-------------------------------------------------
|
||||||
-- Volume Widget for Awesome Window Manager
|
-- The Ultimate Volume Widget for Awesome Window Manager
|
||||||
-- Shows the current volume level
|
|
||||||
-- More details could be found here:
|
-- More details could be found here:
|
||||||
-- https://github.com/streetturtle/awesome-wm-widgets/tree/master/volume-widget
|
-- https://github.com/streetturtle/awesome-wm-widgets/tree/master/volume-widget
|
||||||
|
|
||||||
-- @author Pavel Makhov, Aurélien Lajoie
|
-- @author Pavel Makhov
|
||||||
-- @copyright 2018 Pavel Makhov
|
-- @copyright 2020 Pavel Makhov
|
||||||
-------------------------------------------------
|
-------------------------------------------------
|
||||||
|
|
||||||
|
local awful = require("awful")
|
||||||
local wibox = require("wibox")
|
local wibox = require("wibox")
|
||||||
local spawn = require("awful.spawn")
|
local spawn = require("awful.spawn")
|
||||||
local naughty = require("naughty")
|
local gears = require("gears")
|
||||||
local gfs = require("gears.filesystem")
|
local beautiful = require("beautiful")
|
||||||
local dpi = require('beautiful').xresources.apply_dpi
|
local watch = require("awful.widget.watch")
|
||||||
|
local utils = require("awesome-wm-widgets.volume-widget.utils")
|
||||||
|
|
||||||
local PATH_TO_ICONS = "/usr/share/icons/Arc/status/symbolic/"
|
|
||||||
local volume_icon_name="audio-volume-high-symbolic"
|
|
||||||
local GET_VOLUME_CMD = 'amixer sget Master'
|
|
||||||
|
|
||||||
local volume = {
|
local LIST_DEVICES_CMD = [[sh -c "pacmd list-sinks; pacmd list-sources"]]
|
||||||
device = '',
|
local GET_VOLUME_CMD = 'amixer -D pulse sget Master'
|
||||||
display_notification = false,
|
local INC_VOLUME_CMD = 'amixer -D pulse sset Master 5%+'
|
||||||
display_notification_onClick = true,
|
local DEC_VOLUME_CMD = 'amixer -D pulse sset Master 5%-'
|
||||||
notification = nil,
|
local TOG_VOLUME_CMD = 'amixer -D pulse sset Master toggle'
|
||||||
delta = 5
|
|
||||||
|
|
||||||
|
local widget_types = {
|
||||||
|
icon_and_text = require("awesome-wm-widgets.volume-widget.widgets.icon-and-text-widget"),
|
||||||
|
icon = require("awesome-wm-widgets.volume-widget.widgets.icon-widget"),
|
||||||
|
arc = require("awesome-wm-widgets.volume-widget.widgets.arc-widget"),
|
||||||
|
horizontal_bar = require("awesome-wm-widgets.volume-widget.widgets.horizontal-bar-widget"),
|
||||||
|
vertical_bar = require("awesome-wm-widgets.volume-widget.widgets.vertical-bar-widget")
|
||||||
|
}
|
||||||
|
local volume = {}
|
||||||
|
|
||||||
|
local rows = { layout = wibox.layout.fixed.vertical }
|
||||||
|
|
||||||
|
local popup = awful.popup{
|
||||||
|
bg = beautiful.bg_normal,
|
||||||
|
ontop = true,
|
||||||
|
visible = false,
|
||||||
|
shape = gears.shape.rounded_rect,
|
||||||
|
border_width = 1,
|
||||||
|
border_color = beautiful.bg_focus,
|
||||||
|
maximum_width = 400,
|
||||||
|
offset = { y = 5 },
|
||||||
|
widget = {}
|
||||||
}
|
}
|
||||||
|
|
||||||
function volume:toggle()
|
local function build_main_line(device)
|
||||||
volume:_cmd('amixer ' .. volume.device .. ' sset Master toggle')
|
if device.active_port ~= nil and device.ports[device.active_port] ~= nil then
|
||||||
end
|
return device.properties.device_description .. ' · ' .. device.ports[device.active_port]
|
||||||
|
|
||||||
function volume:raise()
|
|
||||||
volume:_cmd('amixer ' .. volume.device .. ' sset Master ' .. tostring(volume.delta) .. '%+')
|
|
||||||
end
|
|
||||||
function volume:lower()
|
|
||||||
volume:_cmd('amixer ' .. volume.device .. ' sset Master ' .. tostring(volume.delta) .. '%-')
|
|
||||||
end
|
|
||||||
|
|
||||||
--{{{ Icon and notification update
|
|
||||||
|
|
||||||
--------------------------------------------------
|
|
||||||
-- Set the icon and return the message to display
|
|
||||||
-- base on sound level and mute
|
|
||||||
--------------------------------------------------
|
|
||||||
local function parse_output(stdout)
|
|
||||||
local level = string.match(stdout, "(%d?%d?%d)%%")
|
|
||||||
if stdout:find("%[off%]") then
|
|
||||||
volume_icon_name="audio-volume-muted-symbolic_red"
|
|
||||||
return level.."% <span color=\"red\"><b>Mute</b></span>"
|
|
||||||
end
|
|
||||||
level = tonumber(string.format("% 3d", level))
|
|
||||||
|
|
||||||
if (level >= 0 and level < 25) then
|
|
||||||
volume_icon_name="audio-volume-muted-symbolic"
|
|
||||||
elseif (level < 50) then
|
|
||||||
volume_icon_name="audio-volume-low-symbolic"
|
|
||||||
elseif (level < 75) then
|
|
||||||
volume_icon_name="audio-volume-medium-symbolic"
|
|
||||||
else
|
else
|
||||||
volume_icon_name="audio-volume-high-symbolic"
|
return device.properties.device_description
|
||||||
end
|
|
||||||
return level.."%"
|
|
||||||
end
|
|
||||||
|
|
||||||
--------------------------------------------------------
|
|
||||||
--Update the icon and the notification if needed
|
|
||||||
--------------------------------------------------------
|
|
||||||
local function update_graphic(widget, stdout, _, _, _)
|
|
||||||
local txt = parse_output(stdout)
|
|
||||||
widget.image = PATH_TO_ICONS .. volume_icon_name .. ".svg"
|
|
||||||
if (volume.display_notification or volume.display_notification_onClick) then
|
|
||||||
volume.notification.iconbox.image = PATH_TO_ICONS .. volume_icon_name .. ".svg"
|
|
||||||
naughty.replace_text(volume.notification, "Volume", txt)
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
local function notif(msg, keep)
|
local function build_rows(devices, on_checkbox_click, device_type)
|
||||||
if (volume.display_notification or (keep and volume.display_notification_onClick)) then
|
local device_rows = { layout = wibox.layout.fixed.vertical }
|
||||||
naughty.destroy(volume.notification)
|
for _, device in pairs(devices) do
|
||||||
volume.notification= naughty.notify{
|
|
||||||
text = msg,
|
local checkbox = wibox.widget {
|
||||||
icon=PATH_TO_ICONS .. volume_icon_name .. ".svg",
|
checked = device.is_default,
|
||||||
icon_size = dpi(16),
|
color = beautiful.bg_normal,
|
||||||
title = "Volume",
|
paddings = 2,
|
||||||
position = volume.position,
|
shape = gears.shape.circle,
|
||||||
timeout = keep and 0 or 2, hover_timeout = 0.5,
|
forced_width = 20,
|
||||||
width = 200,
|
forced_height = 20,
|
||||||
screen = mouse.screen
|
check_color = beautiful.fg_urgent,
|
||||||
|
widget = wibox.widget.checkbox
|
||||||
}
|
}
|
||||||
|
|
||||||
|
checkbox:connect_signal("button::press", function()
|
||||||
|
spawn.easy_async(string.format([[sh -c 'pacmd set-default-%s "%s"']], device_type, device.name), function()
|
||||||
|
on_checkbox_click()
|
||||||
|
end)
|
||||||
|
end)
|
||||||
|
|
||||||
|
local row = wibox.widget {
|
||||||
|
{
|
||||||
|
{
|
||||||
|
{
|
||||||
|
checkbox,
|
||||||
|
valign = 'center',
|
||||||
|
layout = wibox.container.place,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
{
|
||||||
|
text = build_main_line(device),
|
||||||
|
align = 'left',
|
||||||
|
widget = wibox.widget.textbox
|
||||||
|
},
|
||||||
|
left = 10,
|
||||||
|
layout = wibox.container.margin
|
||||||
|
},
|
||||||
|
spacing = 8,
|
||||||
|
layout = wibox.layout.align.horizontal
|
||||||
|
},
|
||||||
|
margins = 4,
|
||||||
|
layout = wibox.container.margin
|
||||||
|
},
|
||||||
|
bg = beautiful.bg_normal,
|
||||||
|
widget = wibox.container.background
|
||||||
|
}
|
||||||
|
|
||||||
|
row:connect_signal("mouse::enter", function(c) c:set_bg(beautiful.bg_focus) end)
|
||||||
|
row:connect_signal("mouse::leave", function(c) c:set_bg(beautiful.bg_normal) end)
|
||||||
|
|
||||||
|
local old_cursor, old_wibox
|
||||||
|
row:connect_signal("mouse::enter", function()
|
||||||
|
local wb = mouse.current_wibox
|
||||||
|
old_cursor, old_wibox = wb.cursor, wb
|
||||||
|
wb.cursor = "hand1"
|
||||||
|
end)
|
||||||
|
row:connect_signal("mouse::leave", function()
|
||||||
|
if old_wibox then
|
||||||
|
old_wibox.cursor = old_cursor
|
||||||
|
old_wibox = nil
|
||||||
|
end
|
||||||
|
end)
|
||||||
|
|
||||||
|
row:connect_signal("button::press", function()
|
||||||
|
spawn.easy_async(string.format([[sh -c 'pacmd set-default-%s "%s"']], device_type, device.name), function()
|
||||||
|
on_checkbox_click()
|
||||||
|
end)
|
||||||
|
end)
|
||||||
|
|
||||||
|
table.insert(device_rows, row)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
return device_rows
|
||||||
|
end
|
||||||
|
|
||||||
|
local function build_header_row(text)
|
||||||
|
return wibox.widget{
|
||||||
|
{
|
||||||
|
markup = "<b>" .. text .. "</b>",
|
||||||
|
align = 'center',
|
||||||
|
widget = wibox.widget.textbox
|
||||||
|
},
|
||||||
|
bg = beautiful.bg_normal,
|
||||||
|
widget = wibox.container.background
|
||||||
|
}
|
||||||
|
end
|
||||||
|
|
||||||
|
local function rebuild_popup()
|
||||||
|
spawn.easy_async(LIST_DEVICES_CMD, function(stdout)
|
||||||
|
|
||||||
|
local sinks, sources = utils.extract_sinks_and_sources(stdout)
|
||||||
|
|
||||||
|
for i = 0, #rows do rows[i]=nil end
|
||||||
|
|
||||||
|
table.insert(rows, build_header_row("SINKS"))
|
||||||
|
table.insert(rows, build_rows(sinks, function() rebuild_popup() end, "sink"))
|
||||||
|
table.insert(rows, build_header_row("SOURCES"))
|
||||||
|
table.insert(rows, build_rows(sources, function() rebuild_popup() end, "source"))
|
||||||
|
|
||||||
|
popup:setup(rows)
|
||||||
|
end)
|
||||||
end
|
end
|
||||||
|
|
||||||
--}}}
|
|
||||||
|
|
||||||
local function worker(user_args)
|
local function worker(user_args)
|
||||||
--{{{ Args
|
|
||||||
local args = user_args or {}
|
local args = user_args or {}
|
||||||
|
|
||||||
local volume_audio_controller = args.volume_audio_controller or 'pulse'
|
local widget_type = args.widget_type
|
||||||
volume.display_notification = args.display_notification or false
|
local refresh_rate = args.refresh_rate or 1
|
||||||
volume.display_notification_onClick = args.display_notification_onClick or true
|
|
||||||
volume.position = args.notification_position or "top_right"
|
if widget_types[widget_type] == nil then
|
||||||
if volume_audio_controller == 'pulse' then
|
volume.widget = widget_types['icon_and_text'].get_widget(user_args.icon_and_text_args)
|
||||||
volume.device = '-D pulse'
|
else
|
||||||
end
|
volume.widget = widget_types[widget_type].get_widget(args)
|
||||||
volume.delta = args.delta or 5
|
|
||||||
GET_VOLUME_CMD = 'amixer ' .. volume.device.. ' sget Master'
|
|
||||||
--}}}
|
|
||||||
--{{{ Check for icon path
|
|
||||||
if not gfs.dir_readable(PATH_TO_ICONS) then
|
|
||||||
naughty.notify{
|
|
||||||
title = "Volume Widget",
|
|
||||||
text = "Folder with icons doesn't exist: " .. PATH_TO_ICONS,
|
|
||||||
preset = naughty.config.presets.critical
|
|
||||||
}
|
|
||||||
return
|
|
||||||
end
|
|
||||||
--}}}
|
|
||||||
--{{{ Widget creation
|
|
||||||
volume.widget = wibox.widget {
|
|
||||||
{
|
|
||||||
id = "icon",
|
|
||||||
image = PATH_TO_ICONS .. "audio-volume-muted-symbolic.svg",
|
|
||||||
resize = false,
|
|
||||||
widget = wibox.widget.imagebox,
|
|
||||||
},
|
|
||||||
margins = 3,
|
|
||||||
layout = wibox.container.margin,
|
|
||||||
set_image = function(self, path)
|
|
||||||
self.icon.image = path
|
|
||||||
end
|
|
||||||
}
|
|
||||||
--}}}
|
|
||||||
--{{{ Spawn functions
|
|
||||||
function volume:_cmd(cmd)
|
|
||||||
notif("")
|
|
||||||
spawn.easy_async(cmd, function(stdout, stderr, exitreason, exitcode)
|
|
||||||
update_graphic(volume.widget, stdout, stderr, exitreason, exitcode)
|
|
||||||
end)
|
|
||||||
end
|
end
|
||||||
|
|
||||||
local function show()
|
local function update_graphic(widget, stdout)
|
||||||
spawn.easy_async(GET_VOLUME_CMD, function(stdout, _, _, _)
|
local mute = string.match(stdout, "%[(o%D%D?)%]") -- \[(o\D\D?)\] - [on] or [off]
|
||||||
local txt = parse_output(stdout)
|
if mute == 'off' then widget:mute()
|
||||||
notif(txt, true)
|
elseif mute == 'on' then widget:unmute()
|
||||||
end
|
end
|
||||||
)
|
local volume_level = string.match(stdout, "(%d?%d?%d)%%") -- (\d?\d?\d)\%)
|
||||||
|
volume_level = string.format("% 3d", volume_level)
|
||||||
|
widget:set_volume_level(volume_level)
|
||||||
end
|
end
|
||||||
--}}}
|
|
||||||
--{{{ Mouse event
|
|
||||||
--[[ allows control volume level by:
|
|
||||||
- clicking on the widget to mute/unmute
|
|
||||||
- scrolling when cursor is over the widget
|
|
||||||
]]
|
|
||||||
volume.widget:connect_signal("button::press", function(_,_,_,button)
|
|
||||||
if (button == 4) then volume.raise()
|
|
||||||
elseif (button == 5) then volume.lower()
|
|
||||||
elseif (button == 1) then volume.toggle()
|
|
||||||
end
|
|
||||||
end)
|
|
||||||
if volume.display_notification then
|
|
||||||
volume.widget:connect_signal("mouse::enter", function() show() end)
|
|
||||||
volume.widget:connect_signal("mouse::leave", function() naughty.destroy(volume.notification) end)
|
|
||||||
elseif volume.display_notification_onClick then
|
|
||||||
volume.widget:connect_signal("button::press", function(_,_,_,button)
|
|
||||||
if (button == 3) then show() end
|
|
||||||
end)
|
|
||||||
volume.widget:connect_signal("mouse::leave", function() naughty.destroy(volume.notification) end)
|
|
||||||
end
|
|
||||||
--}}}
|
|
||||||
|
|
||||||
--{{{ Set initial icon
|
function volume:inc()
|
||||||
spawn.easy_async(GET_VOLUME_CMD, function(stdout)
|
spawn.easy_async(INC_VOLUME_CMD, function(stdout) update_graphic(volume.widget, stdout) end)
|
||||||
parse_output(stdout)
|
end
|
||||||
volume.widget.image = PATH_TO_ICONS .. volume_icon_name .. ".svg"
|
|
||||||
end)
|
function volume:dec()
|
||||||
--}}}
|
spawn.easy_async(DEC_VOLUME_CMD, function(stdout) update_graphic(volume.widget, stdout) end)
|
||||||
|
end
|
||||||
|
|
||||||
|
function volume:toggle()
|
||||||
|
spawn.easy_async(TOG_VOLUME_CMD, function(stdout) update_graphic(volume.widget, stdout) end)
|
||||||
|
end
|
||||||
|
|
||||||
|
volume.widget:buttons(
|
||||||
|
awful.util.table.join(
|
||||||
|
awful.button({}, 3, function()
|
||||||
|
if popup.visible then
|
||||||
|
popup.visible = not popup.visible
|
||||||
|
else
|
||||||
|
rebuild_popup()
|
||||||
|
popup:move_next_to(mouse.current_widget_geometry)
|
||||||
|
end
|
||||||
|
end),
|
||||||
|
awful.button({}, 4, function() volume:inc() end),
|
||||||
|
awful.button({}, 5, function() volume:dec() end),
|
||||||
|
awful.button({}, 1, function() volume:toggle() end)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
watch(GET_VOLUME_CMD, refresh_rate, update_graphic, volume.widget)
|
||||||
|
|
||||||
return volume.widget
|
return volume.widget
|
||||||
end
|
end
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
local wibox = require("wibox")
|
local wibox = require("wibox")
|
||||||
local beautiful = require('beautiful')
|
local beautiful = require('beautiful')
|
||||||
|
|
||||||
local ICON_DIR = os.getenv("HOME") .. '/.config/awesome/awesome-wm-widgets/experiments/volume/icons/'
|
local ICON_DIR = os.getenv("HOME") .. '/.config/awesome/awesome-wm-widgets/volume-widget/icons/'
|
||||||
|
|
||||||
local widget = {}
|
local widget = {}
|
||||||
|
|
|
@ -2,7 +2,7 @@ local wibox = require("wibox")
|
||||||
local beautiful = require('beautiful')
|
local beautiful = require('beautiful')
|
||||||
local gears = require("gears")
|
local gears = require("gears")
|
||||||
|
|
||||||
local ICON_DIR = os.getenv("HOME") .. '/.config/awesome/awesome-wm-widgets/experiments/volume/icons/'
|
local ICON_DIR = os.getenv("HOME") .. '/.config/awesome/awesome-wm-widgets/volume-widget/icons/'
|
||||||
|
|
||||||
local widget = {}
|
local widget = {}
|
||||||
|
|
|
@ -3,7 +3,7 @@ local beautiful = require('beautiful')
|
||||||
|
|
||||||
local widget = {}
|
local widget = {}
|
||||||
|
|
||||||
local ICON_DIR = os.getenv("HOME") .. '/.config/awesome/awesome-wm-widgets/experiments/volume/icons/'
|
local ICON_DIR = os.getenv("HOME") .. '/.config/awesome/awesome-wm-widgets/volume-widget/icons/'
|
||||||
|
|
||||||
function widget.get_widget(widgets_args)
|
function widget.get_widget(widgets_args)
|
||||||
local args = widgets_args or {}
|
local args = widgets_args or {}
|
|
@ -2,7 +2,7 @@ local wibox = require("wibox")
|
||||||
|
|
||||||
local widget = {}
|
local widget = {}
|
||||||
|
|
||||||
local ICON_DIR = os.getenv("HOME") .. '/.config/awesome/awesome-wm-widgets/experiments/volume/icons/'
|
local ICON_DIR = os.getenv("HOME") .. '/.config/awesome/awesome-wm-widgets/volume-widget/icons/'
|
||||||
|
|
||||||
function widget.get_widget(widgets_args)
|
function widget.get_widget(widgets_args)
|
||||||
local args = widgets_args or {}
|
local args = widgets_args or {}
|
|
@ -2,7 +2,7 @@ local wibox = require("wibox")
|
||||||
local beautiful = require('beautiful')
|
local beautiful = require('beautiful')
|
||||||
local gears = require("gears")
|
local gears = require("gears")
|
||||||
|
|
||||||
local ICON_DIR = os.getenv("HOME") .. '/.config/awesome/awesome-wm-widgets/experiments/volume/icons/'
|
local ICON_DIR = os.getenv("HOME") .. '/.config/awesome/awesome-wm-widgets/volume-widget/icons/'
|
||||||
|
|
||||||
local widget = {}
|
local widget = {}
|
||||||
|
|
|
@ -1,69 +0,0 @@
|
||||||
# Volumearc widget
|
|
||||||
|
|
||||||
Almost the same as [volumebar widget](https://github.com/streetturtle/awesome-wm-widgets/tree/master/volumebar-widget), but using [arcchart](https://awesomewm.org/doc/api/classes/wibox.container.arcchart.html):
|
|
||||||
|
|
||||||
![screenshot](./out.gif)
|
|
||||||
|
|
||||||
Supports
|
|
||||||
- scroll up - increase volume,
|
|
||||||
- scroll down - decrease volume,
|
|
||||||
- left click - mute/unmute.
|
|
||||||
|
|
||||||
## Customization
|
|
||||||
|
|
||||||
It is possible to customize widget by providing a table with all or some of the following config parameters:
|
|
||||||
|
|
||||||
| Name | Default | Description |
|
|
||||||
|---|---|---|
|
|
||||||
| `main_color` | `beautiful.fg_normal` | Color of the arc |
|
|
||||||
| `bg_color` | `#ffffff11` | Color of the arc's background |
|
|
||||||
| `mute_color` | `beautiful.fg_urgent` | Color of the arc when mute |
|
|
||||||
| `path_to_icon` | /usr/share/icons/Arc/status/symbolic/audio-volume-muted-symbolic.svg | Path to the icon |
|
|
||||||
| `thickness` | 2 | The arc thickness |
|
|
||||||
| `height` | `beautiful.fg_normal` | Widget height |
|
|
||||||
| `timeout` | 1 | How often in seconds the widget refreshes |
|
|
||||||
| `get_volume_cmd` | `amixer -D pulse sget Master` | Get current volume level |
|
|
||||||
| `inc_volume_cmd` | `amixer -D pulse sset Master 5%+` | Increase volume level |
|
|
||||||
| `dec_volume_cmd` | `amixer -D pulse sset Master 5%-` | Decrease volume level |
|
|
||||||
| `tog_volume_cmd` | `amixer -D pulse sset Master toggle` | Mute / unmute |
|
|
||||||
| `button_press` | `function(_, _, _, button) <sane default logic> end` | Overwrite the 'button\_press' signal for this widget |
|
|
||||||
|
|
||||||
### Example:
|
|
||||||
|
|
||||||
```lua
|
|
||||||
volumearc_widget({
|
|
||||||
main_color = '#af13f7',
|
|
||||||
mute_color = '#ff0000',
|
|
||||||
thickness = 5,
|
|
||||||
height = 25,
|
|
||||||
button_press = function(_, _, _, button) -- Overwrites the button press behaviour to open pavucontrol when clicked
|
|
||||||
if (button == 1) then awful.spawn('pavucontrol --tab=3', false)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
})
|
|
||||||
```
|
|
||||||
|
|
||||||
The config above results in the following widget:
|
|
||||||
|
|
||||||
![custom](./custom.png)
|
|
||||||
|
|
||||||
## Installation
|
|
||||||
|
|
||||||
1. Clone this repo under **~/.config/awesome/**
|
|
||||||
|
|
||||||
```bash
|
|
||||||
git clone https://github.com/streetturtle/awesome-wm-widgets.git ~/.config/awesome/awesome-wm-widgets
|
|
||||||
```
|
|
||||||
|
|
||||||
1. Require volumearc widget at the beginning of **rc.lua**:
|
|
||||||
|
|
||||||
```lua
|
|
||||||
local volumearc_widget = require("awesome-wm-widgets.volumearc-widget.volumearc")
|
|
||||||
...
|
|
||||||
s.mytasklist, -- Middle widget
|
|
||||||
{ -- Right widgets
|
|
||||||
layout = wibox.layout.fixed.horizontal,
|
|
||||||
...
|
|
||||||
volumearc_widget(),
|
|
||||||
...
|
|
||||||
```
|
|
Before Width: | Height: | Size: 9.2 KiB |
Before Width: | Height: | Size: 7.1 KiB |
|
@ -1,140 +0,0 @@
|
||||||
-------------------------------------------------
|
|
||||||
-- Volume Arc Widget for Awesome Window Manager
|
|
||||||
-- Shows the current volume level
|
|
||||||
-- More details could be found here:
|
|
||||||
-- https://github.com/streetturtle/awesome-wm-widgets/tree/master/volumearc-widget
|
|
||||||
|
|
||||||
-- @author Pavel Makhov
|
|
||||||
-- @copyright 2018 Pavel Makhov
|
|
||||||
-------------------------------------------------
|
|
||||||
|
|
||||||
local awful = require("awful")
|
|
||||||
local beautiful = require("beautiful")
|
|
||||||
local spawn = require("awful.spawn")
|
|
||||||
local watch = require("awful.widget.watch")
|
|
||||||
local wibox = require("wibox")
|
|
||||||
local gears = require("gears")
|
|
||||||
|
|
||||||
local GET_VOLUME_CMD = 'amixer -D pulse sget Master'
|
|
||||||
local INC_VOLUME_CMD = 'amixer -q -D pulse sset Master 5%+'
|
|
||||||
local DEC_VOLUME_CMD = 'amixer -q -D pulse sset Master 5%-'
|
|
||||||
local TOG_VOLUME_CMD = 'amixer -q -D pulse sset Master toggle'
|
|
||||||
|
|
||||||
local PATH_TO_ICON = "/usr/share/icons/Arc/status/symbolic/audio-volume-muted-symbolic.svg"
|
|
||||||
|
|
||||||
local widget = {}
|
|
||||||
|
|
||||||
local popup = awful.popup{
|
|
||||||
ontop = true,
|
|
||||||
visible = false,
|
|
||||||
shape = gears.shape.rounded_rect,
|
|
||||||
border_width = 1,
|
|
||||||
border_color = beautiful.bg_focus,
|
|
||||||
maximum_width = 400,
|
|
||||||
offset = { y = 5 },
|
|
||||||
widget = {}
|
|
||||||
}
|
|
||||||
local rows = {
|
|
||||||
{ widget = wibox.widget.textbox },
|
|
||||||
layout = wibox.layout.fixed.vertical,
|
|
||||||
}
|
|
||||||
local function worker(user_args)
|
|
||||||
|
|
||||||
local args = user_args or {}
|
|
||||||
|
|
||||||
local main_color = args.main_color or beautiful.fg_color
|
|
||||||
local bg_color = args.bg_color or '#ffffff11'
|
|
||||||
local mute_color = args.mute_color or beautiful.fg_urgent
|
|
||||||
local path_to_icon = args.path_to_icon or PATH_TO_ICON
|
|
||||||
local thickness = args.thickness or 2
|
|
||||||
local margins = args.height or 18
|
|
||||||
local timeout = args.timeout or 1
|
|
||||||
|
|
||||||
local get_volume_cmd = args.get_volume_cmd or GET_VOLUME_CMD
|
|
||||||
local inc_volume_cmd = args.inc_volume_cmd or INC_VOLUME_CMD
|
|
||||||
local dec_volume_cmd = args.dec_volume_cmd or DEC_VOLUME_CMD
|
|
||||||
local tog_volume_cmd = args.tog_volume_cmd or TOG_VOLUME_CMD
|
|
||||||
|
|
||||||
local icon = {
|
|
||||||
id = "icon",
|
|
||||||
image = path_to_icon,
|
|
||||||
resize = true,
|
|
||||||
widget = wibox.widget.imagebox,
|
|
||||||
}
|
|
||||||
|
|
||||||
local volumearc = wibox.widget {
|
|
||||||
icon,
|
|
||||||
max_value = 1,
|
|
||||||
thickness = thickness,
|
|
||||||
start_angle = 4.71238898, -- 2pi*3/4
|
|
||||||
forced_height = margins,
|
|
||||||
forced_width = margins,
|
|
||||||
bg = bg_color,
|
|
||||||
paddings = 2,
|
|
||||||
widget = wibox.container.arcchart
|
|
||||||
}
|
|
||||||
|
|
||||||
local update_graphic = function(widget, stdout, _, _, _)
|
|
||||||
local mute = "on"
|
|
||||||
local volume = 0
|
|
||||||
if not (stdout == nil or stdout == '') then
|
|
||||||
mute = string.match(stdout, "%[(o%D%D?)%]") -- \[(o\D\D?)\] - [on] or [off]
|
|
||||||
volume = string.match(tostring(stdout), "(%d?%d?%d)%%") -- (\d?\d?\d)\%)
|
|
||||||
volume = tonumber(string.format("% 3d", volume))
|
|
||||||
end
|
|
||||||
widget.value = volume / 100;
|
|
||||||
widget.colors = mute == 'off'
|
|
||||||
and { mute_color }
|
|
||||||
or { main_color }
|
|
||||||
end
|
|
||||||
|
|
||||||
local button_press = args.button_press or function(_, _, _, button)
|
|
||||||
if (button == 4) then awful.spawn(inc_volume_cmd, false)
|
|
||||||
elseif (button == 5) then awful.spawn(dec_volume_cmd, false)
|
|
||||||
elseif (button == 1) then awful.spawn(tog_volume_cmd, false)
|
|
||||||
end
|
|
||||||
|
|
||||||
spawn.easy_async(get_volume_cmd, function(stdout, stderr, exitreason, exitcode)
|
|
||||||
update_graphic(volumearc, stdout, stderr, exitreason, exitcode)
|
|
||||||
end)
|
|
||||||
end
|
|
||||||
volumearc:connect_signal("button::press", button_press)
|
|
||||||
|
|
||||||
local rebuild_widget = function(stdout)
|
|
||||||
for i = 0, #rows do rows[i]=nil end
|
|
||||||
|
|
||||||
for line in stdout:gmatch("[^\r\n]+") do
|
|
||||||
|
|
||||||
local row = wibox.widget {
|
|
||||||
text = line,
|
|
||||||
widget = wibox.widget.textbox
|
|
||||||
}
|
|
||||||
table.insert(rows, row)
|
|
||||||
end
|
|
||||||
|
|
||||||
popup:setup(rows)
|
|
||||||
end
|
|
||||||
|
|
||||||
volumearc:buttons(
|
|
||||||
awful.util.table.join(
|
|
||||||
awful.button({}, 3, function()
|
|
||||||
if popup.visible then
|
|
||||||
popup.visible = not popup.visible
|
|
||||||
else
|
|
||||||
spawn.easy_async([[bash -c "cat /proc/asound/cards"]], function(stdout, stderr)
|
|
||||||
rebuild_widget(stdout, stderr)
|
|
||||||
popup:move_next_to(mouse.current_widget_geometry)
|
|
||||||
end)
|
|
||||||
end
|
|
||||||
end)
|
|
||||||
)
|
|
||||||
)
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
watch(get_volume_cmd, timeout, update_graphic, volumearc)
|
|
||||||
|
|
||||||
return volumearc
|
|
||||||
end
|
|
||||||
|
|
||||||
return setmetatable(widget, { __call = function(_, ...) return worker(...) end })
|
|
|
@ -1,85 +0,0 @@
|
||||||
# Volumebar widget
|
|
||||||
|
|
||||||
Almost the same as volume widget, but more minimalistic:
|
|
||||||
|
|
||||||
![screenshot](./out.gif)
|
|
||||||
|
|
||||||
Supports
|
|
||||||
- scroll up - increase volume,
|
|
||||||
- scroll down - decrease volume,
|
|
||||||
- left click - mute/unmute.
|
|
||||||
|
|
||||||
## Customization
|
|
||||||
|
|
||||||
It is possible to customize widget by providing a table with all or some of the following config parameters:
|
|
||||||
|
|
||||||
| Name | Default | Description |
|
|
||||||
|---|---|---|
|
|
||||||
| `main_color` | `beautiful.fg_normal` | Color of the bar |
|
|
||||||
| `bg_color` | `#ffffff11` | Color of the bar's background |
|
|
||||||
| `mute_color` | `beautiful.fg_urgent` | Color of the bar when mute |
|
|
||||||
| `width` | 50 | The bar width |
|
|
||||||
| `shape` | `bar` | [gears.shape](https://awesomewm.org/doc/api/libraries/gears.shape.html), could be `octogon`, `hexagon`, `powerline`, etc |
|
|
||||||
| `margins` | `10` | Top and bottom margin (if your wibar is 22 px high, bar will be 2 px (22 - 2*10)) |
|
|
||||||
| `timeout` | 1 | How often in seconds the widget refreshes |
|
|
||||||
| `get_volume_cmd` | `amixer -D pulse sget Master` | Get current volume level |
|
|
||||||
| `inc_volume_cmd` | `amixer -D pulse sset Master 5%+` | Increase volume level |
|
|
||||||
| `dec_volume_cmd` | `amixer -D pulse sset Master 5%-` | Decrease volume level |
|
|
||||||
| `tog_volume_cmd` | `amixer -D pulse sset Master toggle` | Mute / unmute |
|
|
||||||
|
|
||||||
### Example:
|
|
||||||
|
|
||||||
```lua
|
|
||||||
volumebar_widget({
|
|
||||||
main_color = '#af13f7',
|
|
||||||
mute_color = '#ff0000',
|
|
||||||
width = 80,
|
|
||||||
shape = 'rounded_bar',
|
|
||||||
margins = 8
|
|
||||||
})
|
|
||||||
```
|
|
||||||
|
|
||||||
Above config results in following widget:
|
|
||||||
|
|
||||||
![custom](./custom.png)
|
|
||||||
|
|
||||||
|
|
||||||
## Installation
|
|
||||||
|
|
||||||
1. Clone this repo under **~/.config/awesome/**
|
|
||||||
|
|
||||||
```bash
|
|
||||||
git clone https://github.com/streetturtle/awesome-wm-widgets.git ~/.config/awesome/
|
|
||||||
```
|
|
||||||
|
|
||||||
1. Require volumebar widget at the beginning of **rc.lua**:
|
|
||||||
|
|
||||||
```lua
|
|
||||||
local volumebar_widget = require("awesome-wm-widgets.volumebar-widget.volumebar")
|
|
||||||
```
|
|
||||||
|
|
||||||
1. Add widget to the tasklist:
|
|
||||||
|
|
||||||
```lua
|
|
||||||
s.mytasklist, -- Middle widget
|
|
||||||
{ -- Right widgets
|
|
||||||
layout = wibox.layout.fixed.horizontal,
|
|
||||||
...
|
|
||||||
--[[default]]
|
|
||||||
volumebar_widget(),
|
|
||||||
--[[or customized]]
|
|
||||||
volumebar_widget({
|
|
||||||
main_color = '#af13f7',
|
|
||||||
mute_color = '#ff0000',
|
|
||||||
width = 80,
|
|
||||||
shape = 'rounded_bar', -- octogon, hexagon, powerline, etc
|
|
||||||
-- bar's height = wibar's height minus 2x margins
|
|
||||||
margins = 8
|
|
||||||
}),
|
|
||||||
|
|
||||||
...
|
|
||||||
```
|
|
||||||
|
|
||||||
## Troubleshooting
|
|
||||||
|
|
||||||
If the bar is not showing up, try to decrease top or bottom margin - widget uses hardcoded margins for vertical alignment, so if your wibox is too small then bar is simply hidden by the margins.
|
|
Before Width: | Height: | Size: 8.9 KiB |
Before Width: | Height: | Size: 5.8 KiB |
|
@ -1,87 +0,0 @@
|
||||||
-------------------------------------------------
|
|
||||||
-- Volume Bar Widget for Awesome Window Manager
|
|
||||||
-- Shows the current volume level
|
|
||||||
-- More details could be found here:
|
|
||||||
-- https://github.com/streetturtle/awesome-wm-widgets/tree/master/volumebar-widget
|
|
||||||
|
|
||||||
-- @author Pavel Makhov
|
|
||||||
-- @copyright 2018 Pavel Makhov
|
|
||||||
-------------------------------------------------
|
|
||||||
|
|
||||||
local awful = require("awful")
|
|
||||||
local beautiful = require("beautiful")
|
|
||||||
local gears = require("gears")
|
|
||||||
local spawn = require("awful.spawn")
|
|
||||||
local watch = require("awful.widget.watch")
|
|
||||||
local wibox = require("wibox")
|
|
||||||
|
|
||||||
local GET_VOLUME_CMD = 'amixer -D pulse sget Master'
|
|
||||||
local INC_VOLUME_CMD = 'amixer -D pulse sset Master 5%+'
|
|
||||||
local DEC_VOLUME_CMD = 'amixer -D pulse sset Master 5%-'
|
|
||||||
local TOG_VOLUME_CMD = 'amixer -D pulse sset Master toggle'
|
|
||||||
|
|
||||||
local widget = {}
|
|
||||||
|
|
||||||
local function worker(user_args)
|
|
||||||
|
|
||||||
local args = user_args or {}
|
|
||||||
|
|
||||||
local main_color = args.main_color or beautiful.fg_normal
|
|
||||||
local mute_color = args.mute_color or beautiful.fg_urgent
|
|
||||||
local bg_color = args.bg_color or '#ffffff11'
|
|
||||||
local width = args.width or 50
|
|
||||||
local shape = args.shape or 'bar'
|
|
||||||
local margins = args.margins or 10
|
|
||||||
local timeout = args.timeout or 1
|
|
||||||
|
|
||||||
local get_volume_cmd = args.get_volume_cmd or GET_VOLUME_CMD
|
|
||||||
local inc_volume_cmd = args.inc_volume_cmd or INC_VOLUME_CMD
|
|
||||||
local dec_volume_cmd = args.dec_volume_cmd or DEC_VOLUME_CMD
|
|
||||||
local tog_volume_cmd = args.tog_volume_cmd or TOG_VOLUME_CMD
|
|
||||||
|
|
||||||
local volumebar_widget = wibox.widget {
|
|
||||||
max_value = 1,
|
|
||||||
forced_width = width,
|
|
||||||
color = main_color,
|
|
||||||
background_color = bg_color,
|
|
||||||
shape = gears.shape[shape],
|
|
||||||
margins = {
|
|
||||||
top = margins,
|
|
||||||
bottom = margins,
|
|
||||||
},
|
|
||||||
widget = wibox.widget.progressbar
|
|
||||||
}
|
|
||||||
|
|
||||||
local update_graphic = function(_, stdout, _, _, _)
|
|
||||||
local mute = string.match(stdout, "%[(o%D%D?)%]") -- \[(o\D\D?)\] - [on] or [off]
|
|
||||||
local volume = string.match(stdout, "(%d?%d?%d)%%") -- (\d?\d?\d)\%)
|
|
||||||
volume = tonumber(string.format("% 3d", volume))
|
|
||||||
|
|
||||||
widget.value = volume / 100;
|
|
||||||
widget.color = mute == "off"
|
|
||||||
and mute_color
|
|
||||||
or main_color
|
|
||||||
|
|
||||||
end
|
|
||||||
|
|
||||||
volumebar_widget:connect_signal("button::press", function(_, _, _, button)
|
|
||||||
if (button == 4) then
|
|
||||||
awful.spawn(inc_volume_cmd)
|
|
||||||
elseif (button == 5) then
|
|
||||||
awful.spawn(dec_volume_cmd)
|
|
||||||
elseif (button == 1) then
|
|
||||||
awful.spawn(tog_volume_cmd)
|
|
||||||
end
|
|
||||||
|
|
||||||
spawn.easy_async(get_volume_cmd, function(stdout, stderr, exitreason, exitcode)
|
|
||||||
update_graphic(volumebar_widget, stdout, stderr, exitreason, exitcode)
|
|
||||||
end)
|
|
||||||
end)
|
|
||||||
|
|
||||||
watch(get_volume_cmd, timeout, update_graphic, volumebar_widget)
|
|
||||||
|
|
||||||
return volumebar_widget
|
|
||||||
end
|
|
||||||
|
|
||||||
return setmetatable(widget, { __call = function(_, ...) return worker(...) end })
|
|
||||||
|
|