mirror of
https://github.com/scorpion-26/gBar.git
synced 2024-11-22 03:02:49 +00:00
Add Microphone support
This commit adds a new widget for the bar: A Microphone widget. It is disabled by default and can can be enabled with AudioInput: true. Implements a flyin as well. https://github.com/scorpion-26/gBar/issues/5 for the ping
This commit is contained in:
parent
f5adfebfe9
commit
3c8c93d774
14 changed files with 376 additions and 129 deletions
|
@ -44,6 +44,10 @@ gBar bar 0
|
||||||
```
|
```
|
||||||
gBar audio [monitor]
|
gBar audio [monitor]
|
||||||
```
|
```
|
||||||
|
*Open microphone flyin, this is equivalent to the audio flyin*
|
||||||
|
```
|
||||||
|
gBar mic [monitor]
|
||||||
|
```
|
||||||
*Open bluetooth widget*
|
*Open bluetooth widget*
|
||||||
```
|
```
|
||||||
gBar bluetooth [monitor]
|
gBar bluetooth [monitor]
|
||||||
|
@ -68,6 +72,7 @@ Bar:
|
||||||
- Time
|
- Time
|
||||||
- Bluetooth (BlueZ only)
|
- Bluetooth (BlueZ only)
|
||||||
- Audio control
|
- Audio control
|
||||||
|
- Microphone control
|
||||||
- Power control
|
- Power control
|
||||||
- Shutdown
|
- Shutdown
|
||||||
- Restart
|
- Restart
|
||||||
|
@ -87,6 +92,7 @@ Bluetooth:
|
||||||
|
|
||||||
Audio Flyin:
|
Audio Flyin:
|
||||||
- Audio control
|
- Audio control
|
||||||
|
- Microphone control
|
||||||
|
|
||||||
## Configuration for your system
|
## Configuration for your system
|
||||||
Copy the example config (found under data/config) into ~/.config/gBar/config and modify it to your needs.
|
Copy the example config (found under data/config) into ~/.config/gBar/config and modify it to your needs.
|
||||||
|
|
|
@ -42,12 +42,65 @@
|
||||||
margin-right: 6px;
|
margin-right: 6px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
trough {
|
||||||
|
border-radius: 3px;
|
||||||
|
border-width: 1px;
|
||||||
|
border-style: none;
|
||||||
|
background-color: #44475a;
|
||||||
|
margin-top: 2px;
|
||||||
|
min-width: 4px;
|
||||||
|
min-height: 4px;
|
||||||
|
}
|
||||||
|
|
||||||
|
slider {
|
||||||
|
border-radius: 0%;
|
||||||
|
border-width: 1px;
|
||||||
|
border-style: none;
|
||||||
|
margin: -9px -9px -9px -9px;
|
||||||
|
min-width: 16px;
|
||||||
|
min-height: 16px;
|
||||||
|
background-color: transparent;
|
||||||
|
}
|
||||||
|
|
||||||
|
highlight {
|
||||||
|
border-radius: 3px;
|
||||||
|
border-width: 1px;
|
||||||
|
border-style: none;
|
||||||
|
min-height: 6px;
|
||||||
|
}
|
||||||
|
|
||||||
.audio-icon {
|
.audio-icon {
|
||||||
font-size: 24px;
|
font-size: 24px;
|
||||||
color: #ffb86c;
|
color: #ffb86c;
|
||||||
margin-right: 12px;
|
margin-right: 12px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.audio-volume trough {
|
||||||
|
background-color: #44475a;
|
||||||
|
}
|
||||||
|
.audio-volume slider {
|
||||||
|
background-color: transparent;
|
||||||
|
}
|
||||||
|
.audio-volume highlight {
|
||||||
|
background-color: #ffb86c;
|
||||||
|
}
|
||||||
|
|
||||||
|
.mic-icon {
|
||||||
|
font-size: 24px;
|
||||||
|
color: #bd93f9;
|
||||||
|
margin-right: 0px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.mic-volume trough {
|
||||||
|
background-color: #44475a;
|
||||||
|
}
|
||||||
|
.mic-volume slider {
|
||||||
|
background-color: transparent;
|
||||||
|
}
|
||||||
|
.mic-volume highlight {
|
||||||
|
background-color: #bd93f9;
|
||||||
|
}
|
||||||
|
|
||||||
.bt-num {
|
.bt-num {
|
||||||
font-size: 16px;
|
font-size: 16px;
|
||||||
color: #1793D1;
|
color: #1793D1;
|
||||||
|
@ -325,32 +378,4 @@
|
||||||
animation-fill-mode: forwards;
|
animation-fill-mode: forwards;
|
||||||
}
|
}
|
||||||
|
|
||||||
trough {
|
|
||||||
border-radius: 3px;
|
|
||||||
border-width: 1px;
|
|
||||||
border-style: none;
|
|
||||||
background-color: #44475a;
|
|
||||||
margin-top: 2px;
|
|
||||||
min-width: 4px;
|
|
||||||
min-height: 4px;
|
|
||||||
}
|
|
||||||
|
|
||||||
slider {
|
|
||||||
border-radius: 0%;
|
|
||||||
border-width: 1px;
|
|
||||||
border-style: none;
|
|
||||||
margin: -9px -9px -9px -9px;
|
|
||||||
min-width: 16px;
|
|
||||||
min-height: 16px;
|
|
||||||
background-color: transparent;
|
|
||||||
}
|
|
||||||
|
|
||||||
highlight {
|
|
||||||
border-radius: 3px;
|
|
||||||
border-width: 1px;
|
|
||||||
border-style: none;
|
|
||||||
min-height: 6px;
|
|
||||||
background-color: #ffb86c;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*# sourceMappingURL=style.css.map */
|
/*# sourceMappingURL=style.css.map */
|
||||||
|
|
|
@ -1 +1 @@
|
||||||
{"version":3,"sourceRoot":"","sources":["style.scss"],"names":[],"mappings":"AAmBA;EACI;EACA;;;AASJ;EACI,kBA7BC;EA8BD;;;AAGJ;EACI;EACA;;;AAGJ;EACI,WAxBO;;;AA2BX;EACI;EAEA;EAEA,OA5CO;;;AA8CX;EACI;EAGA,OAlDO;;;AAoDX;EACI;EAGA,OAxDO;;;AA2DX;EACI;EAGA,OAzDE;;;AA+DN;EACI;;;AAGJ;EACI;EACA,OAxEK;EAyEL;;;AAGJ;EACI,WApEO;EAqEP,OAvEK;EAwEL;;;AAEJ;EACI;EACA,OA5EK;EA6EL;;;AAEJ;EACI;EACA,OAjFK;EAkFL;;;AAEJ;EACI;EACA,OAtFK;EAuFL;;;AAGJ;EACI,OAhGK;EAiGL,kBAvGO;EAwGP,WA3FO;;;AA6FX;EACI,OArGK;EAsGL;EACA,WAhGO;;;AAmGX;EACI,OA7GK;EA8GL,kBAlHO;;;AAoHX;EACI,OAjHK;EAkHL;EACA,WA1GO;;;AA6GX;EACI,OAnHK;EAoHL,kBA5HO;;;AA8HX;EACI,OAvHK;EAwHL;EACA,WApHO;;;AAuHX;EACI,OAnIG;EAoIH,kBAtIO;;;AAwIX;EACI,OAvIG;EAwIH;EACA,WA9HO;;;AAiIX;EACI,OA5II;EA6IJ,kBAhJO;EAiJP,WApIO;;;AAsIX;EACI,OAjJI;EAkJJ;EACA,WAzIO;;;AA4IX;EACI,OArJG;EAsJH,kBA3JO;EA4JP,WA/IO;;;AAiJX;EACI,OA1JG;EA2JH;EACA,WApJO;;;AAuJX;EACI,OAlKI;EAmKJ;EACA,WA1JO;;;AA8JX;EACI,OA5KO;;;AA+KX;EACI,OA7KI;;;AAgLR;EACI,OA5KK;;;AA+KT;EACI,OApLK;;;AAuLT;EACI,OAtLK;;;AAyLT;EACI,OAzLE;;;AA6LN;EACI,OArMO;;;AAwMX;EACI,OAtMI;;;AAyMR;EACI,OArMK;;;AAwMT;EACI,OA7MK;;;AAgNT;EACI,OA/MK;;;AAkNT;EACI,OAlNE;;;AAqNN;EACI,OA7NO;EA8NP,WAjNO;;;AAmNX;EACI,OAhOO;EAiOP,WArNO;;;AAuNX;EACI,OAnOG;EAoOH,WAzNO;;;AA2NX;EACI,OAjOK;EAkOL,WA7NO;;;AA+NX;EACI,OA1OI;EA2OJ,WAjOO;;;AAqOX;EACI;IACI;;EAEJ;IACI;;;AAGR;EACI;IACI;;EAEJ;IACI;;;AAIR;EACI;IACI,OA7PC;;EA+PL;IACI,OArQA;;;AAwQR;EACI;IACI,OA1QA;;EA4QJ;IACI,OAxQC;;;AA4QT;EACI,kBAvRC;EAwRD;;;AAEJ;EACI;EACA;EACA;EACA;EACA,OAlRK;;;AAoRT;EACI;EACA;;;AAEJ;EAgBI;EACA;EACA;EACA;EACA;EAEA;EACA;EAEA;;AAxBA;EACI;EACA;EACA;EACA;;AAEJ;EACI;EACA;EACA;EACA;;AAEJ;EACI,OA1SF;;;AAwTN;EACI,OAzTE;EA0TF,kBAjUO;EAkUP;EACH;EACA;;;AAED;EAaI,OA3UK;EA4UL,kBApVO;EAqVP;EACA;EACH;EACG;;AAjBA;EACI;EACA;EACA;EACA;;AAEJ;EACI;EACA;EACA;EACA;;;AAWR;EACI;EACA;EACH;EACG,kBAhWO;EAiWP;EACH;EACA;;;AAGD;EAEC;EACG;EACH;EACA;EACA;EACA;EACA;;;AAGD;EACC;EACG;EACH;EACG;EACH,kBAlXQ","file":"style.css"}
|
{"version":3,"sourceRoot":"","sources":["style.scss"],"names":[],"mappings":"AAmBA;EACI;EACA;;;AASJ;EACI,kBA7BC;EA8BD;;;AAGJ;EACI;EACA;;;AAGJ;EACI,WAxBO;;;AA2BX;EACI;EAEA;EAEA,OA5CO;;;AA8CX;EACI;EAGA,OAlDO;;;AAoDX;EACI;EAGA,OAxDO;;;AA2DX;EACI;EAGA,OAzDE;;;AA+DN;EACI;;;AAIJ;EACI;EACA;EACA;EACA,kBA/EO;EAgFP;EACA;EACA;;;AAGJ;EAEI;EACA;EACA;EACA;EACA;EACA;EACA;;;AAGJ;EACI;EACA;EACA;EACA;;;AAGJ;EACI;EACA,OArGK;EAsGL;;;AAIA;EACI,kBA/GG;;AAkHP;EACI;;AAGJ;EACI,kBAnHC;;;AAuHT;EACI;EACA,OAvHK;EAwHL;;;AAIA;EACI,kBAnIG;;AAsIP;EACI;;AAGJ;EACI,kBArIC;;;AAyIT;EACI,WAnIO;EAoIP,OAtIK;EAuIL;;;AAEJ;EACI;EACA,OA3IK;EA4IL;;;AAEJ;EACI;EACA,OAhJK;EAiJL;;;AAEJ;EACI;EACA,OArJK;EAsJL;;;AAGJ;EACI,OA/JK;EAgKL,kBAtKO;EAuKP,WA1JO;;;AA4JX;EACI,OApKK;EAqKL;EACA,WA/JO;;;AAkKX;EACI,OA5KK;EA6KL,kBAjLO;;;AAmLX;EACI,OAhLK;EAiLL;EACA,WAzKO;;;AA4KX;EACI,OAlLK;EAmLL,kBA3LO;;;AA6LX;EACI,OAtLK;EAuLL;EACA,WAnLO;;;AAsLX;EACI,OAlMG;EAmMH,kBArMO;;;AAuMX;EACI,OAtMG;EAuMH;EACA,WA7LO;;;AAgMX;EACI,OA3MI;EA4MJ,kBA/MO;EAgNP,WAnMO;;;AAqMX;EACI,OAhNI;EAiNJ;EACA,WAxMO;;;AA2MX;EACI,OApNG;EAqNH,kBA1NO;EA2NP,WA9MO;;;AAgNX;EACI,OAzNG;EA0NH;EACA,WAnNO;;;AAsNX;EACI,OAjOI;EAkOJ;EACA,WAzNO;;;AA6NX;EACI,OA3OO;;;AA8OX;EACI,OA5OI;;;AA+OR;EACI,OA3OK;;;AA8OT;EACI,OAnPK;;;AAsPT;EACI,OArPK;;;AAwPT;EACI,OAxPE;;;AA4PN;EACI,OApQO;;;AAuQX;EACI,OArQI;;;AAwQR;EACI,OApQK;;;AAuQT;EACI,OA5QK;;;AA+QT;EACI,OA9QK;;;AAiRT;EACI,OAjRE;;;AAoRN;EACI,OA5RO;EA6RP,WAhRO;;;AAkRX;EACI,OA/RO;EAgSP,WApRO;;;AAsRX;EACI,OAlSG;EAmSH,WAxRO;;;AA0RX;EACI,OAhSK;EAiSL,WA5RO;;;AA8RX;EACI,OAzSI;EA0SJ,WAhSO;;;AAoSX;EACI;IACI;;EAEJ;IACI;;;AAGR;EACI;IACI;;EAEJ;IACI;;;AAIR;EACI;IACI,OA5TC;;EA8TL;IACI,OApUA;;;AAuUR;EACI;IACI,OAzUA;;EA2UJ;IACI,OAvUC;;;AA2UT;EACI,kBAtVC;EAuVD;;;AAEJ;EACI;EACA;EACA;EACA;EACA,OAjVK;;;AAmVT;EACI;EACA;;;AAEJ;EAgBI;EACA;EACA;EACA;EACA;EAEA;EACA;EAEA;;AAxBA;EACI;EACA;EACA;EACA;;AAEJ;EACI;EACA;EACA;EACA;;AAEJ;EACI,OAzWF;;;AAuXN;EACI,OAxXE;EAyXF,kBAhYO;EAiYP;EACH;EACA;;;AAED;EAaI,OA1YK;EA2YL,kBAnZO;EAoZP;EACA;EACH;EACG;;AAjBA;EACI;EACA;EACA;EACA;;AAEJ;EACI;EACA;EACA;EACA","file":"style.css"}
|
|
@ -76,12 +76,75 @@ $textsize: 16px;
|
||||||
margin-right: 6px;
|
margin-right: 6px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Common slider settings
|
||||||
|
trough {
|
||||||
|
border-radius: 3px;
|
||||||
|
border-width: 1px;
|
||||||
|
border-style: none;
|
||||||
|
background-color: $inactive;
|
||||||
|
margin-top: 2px;
|
||||||
|
min-width: 4px;
|
||||||
|
min-height: 4px;
|
||||||
|
}
|
||||||
|
|
||||||
|
slider {
|
||||||
|
// Controls the size of the control area (set border-style to solid to see)
|
||||||
|
border-radius: 0%;
|
||||||
|
border-width: 1px;
|
||||||
|
border-style: none;
|
||||||
|
margin: -9px -9px -9px -9px;
|
||||||
|
min-width: 16px;
|
||||||
|
min-height: 16px;
|
||||||
|
background-color: transparent;
|
||||||
|
}
|
||||||
|
|
||||||
|
highlight {
|
||||||
|
border-radius: 3px;
|
||||||
|
border-width: 1px;
|
||||||
|
border-style: none;
|
||||||
|
min-height: 6px;
|
||||||
|
}
|
||||||
|
|
||||||
.audio-icon {
|
.audio-icon {
|
||||||
font-size: 24px;
|
font-size: 24px;
|
||||||
color: $orange;
|
color: $orange;
|
||||||
margin-right: 12px;
|
margin-right: 12px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.audio-volume {
|
||||||
|
trough {
|
||||||
|
background-color: $inactive;
|
||||||
|
}
|
||||||
|
|
||||||
|
slider {
|
||||||
|
background-color: transparent;
|
||||||
|
}
|
||||||
|
|
||||||
|
highlight {
|
||||||
|
background-color: $orange;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.mic-icon {
|
||||||
|
font-size: 24px;
|
||||||
|
color: $purple;
|
||||||
|
margin-right: 0px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.mic-volume {
|
||||||
|
trough {
|
||||||
|
background-color: $inactive;
|
||||||
|
}
|
||||||
|
|
||||||
|
slider {
|
||||||
|
background-color: transparent;
|
||||||
|
}
|
||||||
|
|
||||||
|
highlight {
|
||||||
|
background-color: $purple;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
.bt-num {
|
.bt-num {
|
||||||
font-size: $textsize;
|
font-size: $textsize;
|
||||||
color: $btblue;
|
color: $btblue;
|
||||||
|
@ -348,34 +411,3 @@ $textsize: 16px;
|
||||||
margin: 0px 0px 0px 10px;
|
margin: 0px 0px 0px 10px;
|
||||||
font-size: 18px;
|
font-size: 18px;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Sliders
|
|
||||||
trough {
|
|
||||||
border-radius: 3px;
|
|
||||||
border-width: 1px;
|
|
||||||
border-style: none;
|
|
||||||
background-color: $inactive;
|
|
||||||
margin-top: 2px;
|
|
||||||
min-width: 4px;
|
|
||||||
min-height: 4px;
|
|
||||||
}
|
|
||||||
|
|
||||||
slider {
|
|
||||||
// Controls the size of the control area (set border-style to solid to see)
|
|
||||||
border-radius: 0%;
|
|
||||||
border-width: 1px;
|
|
||||||
border-style: none;
|
|
||||||
margin: -9px -9px -9px -9px;
|
|
||||||
min-width: 16px;
|
|
||||||
min-height: 16px;
|
|
||||||
background-color: transparent;
|
|
||||||
}
|
|
||||||
|
|
||||||
highlight {
|
|
||||||
border-radius: 3px;
|
|
||||||
border-width: 1px;
|
|
||||||
border-style: none;
|
|
||||||
min-height: 6px;
|
|
||||||
background-color: $orange;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
|
@ -38,6 +38,9 @@ WorkspaceScrollInvert: false
|
||||||
# This can cause issues, if there is not enough space on screen (e.g. when opening the text)
|
# This can cause issues, if there is not enough space on screen (e.g. when opening the text)
|
||||||
CenterTime: true
|
CenterTime: true
|
||||||
|
|
||||||
|
# Adds a audio input(aka. microphone) widget
|
||||||
|
AudioInput: false
|
||||||
|
|
||||||
# Sets the audio slider to be on reveal (Just like the sensors) when true. Only affects the bar.
|
# Sets the audio slider to be on reveal (Just like the sensors) when true. Only affects the bar.
|
||||||
AudioRevealer: false
|
AudioRevealer: false
|
||||||
|
|
||||||
|
|
|
@ -5,6 +5,8 @@ namespace AudioFlyin
|
||||||
{
|
{
|
||||||
namespace DynCtx
|
namespace DynCtx
|
||||||
{
|
{
|
||||||
|
Type type;
|
||||||
|
|
||||||
Window* win;
|
Window* win;
|
||||||
Slider* slider;
|
Slider* slider;
|
||||||
Text* icon;
|
Text* icon;
|
||||||
|
@ -19,28 +21,59 @@ namespace AudioFlyin
|
||||||
|
|
||||||
void OnChangeVolume(Slider&, double value)
|
void OnChangeVolume(Slider&, double value)
|
||||||
{
|
{
|
||||||
System::SetVolume(value);
|
if (type == Type::Speaker)
|
||||||
|
{
|
||||||
|
System::SetVolumeSink(value);
|
||||||
|
}
|
||||||
|
else if (type == Type::Microphone)
|
||||||
|
{
|
||||||
|
System::SetVolumeSource(value);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
TimerResult Main(Box&)
|
TimerResult Main(Box&)
|
||||||
{
|
{
|
||||||
System::AudioInfo info = System::GetAudioInfo();
|
System::AudioInfo info = System::GetAudioInfo();
|
||||||
if (sliderVal != info.volume || muted != info.muted)
|
if (type == Type::Speaker)
|
||||||
{
|
{
|
||||||
// Extend timer
|
if (sliderVal != info.sinkVolume || muted != info.sinkMuted)
|
||||||
curCloseTime = msOpen + closeTime;
|
|
||||||
|
|
||||||
sliderVal = info.volume;
|
|
||||||
slider->SetValue(info.volume);
|
|
||||||
|
|
||||||
muted = info.muted;
|
|
||||||
if (info.muted)
|
|
||||||
{
|
{
|
||||||
icon->SetText("ﱝ");
|
// Extend timer
|
||||||
|
curCloseTime = msOpen + closeTime;
|
||||||
|
|
||||||
|
sliderVal = info.sinkVolume;
|
||||||
|
slider->SetValue(info.sinkVolume);
|
||||||
|
|
||||||
|
muted = info.sinkMuted;
|
||||||
|
if (info.sinkMuted)
|
||||||
|
{
|
||||||
|
icon->SetText("ﱝ");
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
icon->SetText("墳");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
else
|
}
|
||||||
|
else if (type == Type::Microphone)
|
||||||
|
{
|
||||||
|
if (sliderVal != info.sourceVolume || muted != info.sourceMuted)
|
||||||
{
|
{
|
||||||
icon->SetText("墳");
|
// Extend timer
|
||||||
|
curCloseTime = msOpen + closeTime;
|
||||||
|
|
||||||
|
sliderVal = info.sourceVolume;
|
||||||
|
slider->SetValue(info.sourceVolume);
|
||||||
|
|
||||||
|
muted = info.sourceMuted;
|
||||||
|
if (info.sourceMuted)
|
||||||
|
{
|
||||||
|
icon->SetText("");
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
icon->SetText("");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -66,23 +99,40 @@ namespace AudioFlyin
|
||||||
slider->SetOrientation(Orientation::Horizontal);
|
slider->SetOrientation(Orientation::Horizontal);
|
||||||
slider->SetHorizontalTransform({100, true, Alignment::Fill});
|
slider->SetHorizontalTransform({100, true, Alignment::Fill});
|
||||||
slider->SetInverted(true);
|
slider->SetInverted(true);
|
||||||
slider->SetClass("audio-volume");
|
if (DynCtx::type == Type::Speaker)
|
||||||
|
{
|
||||||
|
slider->SetClass("audio-volume");
|
||||||
|
}
|
||||||
|
else if (DynCtx::type == Type::Microphone)
|
||||||
|
{
|
||||||
|
slider->SetClass("mic-volume");
|
||||||
|
}
|
||||||
slider->OnValueChange(DynCtx::OnChangeVolume);
|
slider->OnValueChange(DynCtx::OnChangeVolume);
|
||||||
slider->SetRange({0, 1, 0.01});
|
slider->SetRange({0, 1, 0.01});
|
||||||
DynCtx::slider = slider.get();
|
DynCtx::slider = slider.get();
|
||||||
|
|
||||||
auto icon = Widget::Create<Text>();
|
auto icon = Widget::Create<Text>();
|
||||||
icon->SetClass("audio-icon");
|
if (DynCtx::type == Type::Speaker)
|
||||||
icon->SetText("墳");
|
{
|
||||||
|
icon->SetClass("audio-icon");
|
||||||
|
icon->SetText(" ");
|
||||||
|
}
|
||||||
|
else if (DynCtx::type == Type::Microphone)
|
||||||
|
{
|
||||||
|
icon->SetClass("mic-icon");
|
||||||
|
icon->SetText("");
|
||||||
|
}
|
||||||
|
|
||||||
DynCtx::icon = icon.get();
|
DynCtx::icon = icon.get();
|
||||||
|
|
||||||
parent.AddChild(std::move(slider));
|
parent.AddChild(std::move(slider));
|
||||||
parent.AddChild(std::move(icon));
|
parent.AddChild(std::move(icon));
|
||||||
}
|
}
|
||||||
|
|
||||||
void Create(Window& window, int32_t monitor)
|
void Create(Window& window, int32_t monitor, Type type)
|
||||||
{
|
{
|
||||||
DynCtx::win = &window;
|
DynCtx::win = &window;
|
||||||
|
DynCtx::type = type;
|
||||||
auto mainWidget = Widget::Create<Box>();
|
auto mainWidget = Widget::Create<Box>();
|
||||||
mainWidget->SetSpacing({8, false});
|
mainWidget->SetSpacing({8, false});
|
||||||
mainWidget->SetVerticalTransform({16, true, Alignment::Fill});
|
mainWidget->SetVerticalTransform({16, true, Alignment::Fill});
|
||||||
|
|
|
@ -4,5 +4,10 @@
|
||||||
|
|
||||||
namespace AudioFlyin
|
namespace AudioFlyin
|
||||||
{
|
{
|
||||||
void Create(Window& window, int32_t monitor);
|
enum class Type
|
||||||
|
{
|
||||||
|
Speaker,
|
||||||
|
Microphone
|
||||||
|
};
|
||||||
|
void Create(Window& window, int32_t monitor, Type type);
|
||||||
}
|
}
|
||||||
|
|
96
src/Bar.cpp
96
src/Bar.cpp
|
@ -134,23 +134,43 @@ namespace Bar
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
void OnChangeVolume(Slider&, double value)
|
void OnChangeVolumeSink(Slider&, double value)
|
||||||
{
|
{
|
||||||
System::SetVolume(value);
|
System::SetVolumeSink(value);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void OnChangeVolumeSource(Slider&, double value)
|
||||||
|
{
|
||||||
|
System::SetVolumeSource(value);
|
||||||
|
}
|
||||||
|
|
||||||
|
Slider* audioSlider;
|
||||||
|
Slider* micSlider;
|
||||||
Text* audioIcon;
|
Text* audioIcon;
|
||||||
TimerResult UpdateAudio(Slider& slider)
|
Text* micIcon;
|
||||||
|
TimerResult UpdateAudio(Widget&)
|
||||||
{
|
{
|
||||||
System::AudioInfo info = System::GetAudioInfo();
|
System::AudioInfo info = System::GetAudioInfo();
|
||||||
slider.SetValue(info.volume);
|
audioSlider->SetValue(info.sinkVolume);
|
||||||
if (info.muted)
|
if (info.sinkMuted)
|
||||||
{
|
{
|
||||||
audioIcon->SetText("ﱝ");
|
audioIcon->SetText("");
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
audioIcon->SetText("墳");
|
audioIcon->SetText("");
|
||||||
|
}
|
||||||
|
if (Config::Get().audioInput)
|
||||||
|
{
|
||||||
|
micSlider->SetValue(info.sourceVolume);
|
||||||
|
if (info.sourceMuted)
|
||||||
|
{
|
||||||
|
micIcon->SetText("");
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
micIcon->SetText("");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return TimerResult::Ok;
|
return TimerResult::Ok;
|
||||||
}
|
}
|
||||||
|
@ -256,33 +276,59 @@ namespace Bar
|
||||||
parent.AddChild(std::move(eventBox));
|
parent.AddChild(std::move(eventBox));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Handles in and out
|
||||||
void WidgetAudio(Widget& parent)
|
void WidgetAudio(Widget& parent)
|
||||||
{
|
{
|
||||||
auto widgetAudioSlider = [](Widget& parent)
|
enum class AudioType
|
||||||
|
{
|
||||||
|
Input,
|
||||||
|
Output
|
||||||
|
};
|
||||||
|
auto widgetAudioSlider = [](Widget& parent, AudioType type)
|
||||||
{
|
{
|
||||||
auto slider = Widget::Create<Slider>();
|
auto slider = Widget::Create<Slider>();
|
||||||
slider->SetOrientation(Orientation::Horizontal);
|
slider->SetOrientation(Orientation::Horizontal);
|
||||||
slider->SetHorizontalTransform({100, true, Alignment::Fill});
|
slider->SetHorizontalTransform({100, true, Alignment::Fill});
|
||||||
slider->SetInverted(true);
|
slider->SetInverted(true);
|
||||||
slider->SetClass("audio-volume");
|
switch (type)
|
||||||
slider->AddTimer<Slider>(DynCtx::UpdateAudio, DynCtx::updateTimeFast);
|
{
|
||||||
slider->OnValueChange(DynCtx::OnChangeVolume);
|
case AudioType::Input:
|
||||||
|
slider->SetClass("mic-volume");
|
||||||
|
slider->OnValueChange(DynCtx::OnChangeVolumeSource);
|
||||||
|
DynCtx::micSlider = slider.get();
|
||||||
|
break;
|
||||||
|
case AudioType::Output:
|
||||||
|
slider->SetClass("audio-volume");
|
||||||
|
slider->OnValueChange(DynCtx::OnChangeVolumeSink);
|
||||||
|
DynCtx::audioSlider = slider.get();
|
||||||
|
break;
|
||||||
|
}
|
||||||
slider->SetRange({0, 1, 0.01});
|
slider->SetRange({0, 1, 0.01});
|
||||||
slider->SetScrollSpeed((double)Config::Get().audioScrollSpeed / 100.);
|
slider->SetScrollSpeed((double)Config::Get().audioScrollSpeed / 100.);
|
||||||
|
|
||||||
parent.AddChild(std::move(slider));
|
parent.AddChild(std::move(slider));
|
||||||
};
|
};
|
||||||
|
|
||||||
auto widgetAudioBody = [&widgetAudioSlider](Widget& parent)
|
auto widgetAudioBody = [&widgetAudioSlider](Widget& parent, AudioType type)
|
||||||
{
|
{
|
||||||
auto box = Widget::Create<Box>();
|
auto box = Widget::Create<Box>();
|
||||||
box->SetSpacing({8, false});
|
box->SetSpacing({8, false});
|
||||||
box->SetHorizontalTransform({-1, true, Alignment::Right});
|
box->SetHorizontalTransform({-1, true, Alignment::Right});
|
||||||
{
|
{
|
||||||
auto icon = Widget::Create<Text>();
|
auto icon = Widget::Create<Text>();
|
||||||
icon->SetClass("audio-icon");
|
switch (type)
|
||||||
icon->SetText("墳");
|
{
|
||||||
DynCtx::audioIcon = icon.get();
|
case AudioType::Input:
|
||||||
|
icon->SetClass("mic-icon");
|
||||||
|
icon->SetText("");
|
||||||
|
DynCtx::micIcon = icon.get();
|
||||||
|
break;
|
||||||
|
case AudioType::Output:
|
||||||
|
icon->SetClass("audio-icon");
|
||||||
|
icon->SetText(" ");
|
||||||
|
DynCtx::audioIcon = icon.get();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
if (Config::Get().audioRevealer)
|
if (Config::Get().audioRevealer)
|
||||||
{
|
{
|
||||||
|
@ -296,7 +342,7 @@ namespace Bar
|
||||||
slideRevealer->SetRevealed(hovered);
|
slideRevealer->SetRevealed(hovered);
|
||||||
});
|
});
|
||||||
{
|
{
|
||||||
widgetAudioSlider(*revealer);
|
widgetAudioSlider(*revealer, type);
|
||||||
}
|
}
|
||||||
|
|
||||||
box->AddChild(std::move(revealer));
|
box->AddChild(std::move(revealer));
|
||||||
|
@ -304,7 +350,7 @@ namespace Bar
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
// Straight forward
|
// Straight forward
|
||||||
widgetAudioSlider(*box);
|
widgetAudioSlider(*box, type);
|
||||||
}
|
}
|
||||||
|
|
||||||
box->AddChild(std::move(icon));
|
box->AddChild(std::move(icon));
|
||||||
|
@ -314,16 +360,28 @@ namespace Bar
|
||||||
|
|
||||||
if (Config::Get().audioRevealer)
|
if (Config::Get().audioRevealer)
|
||||||
{
|
{
|
||||||
|
// Need an EventBox
|
||||||
|
if (Config::Get().audioInput)
|
||||||
|
{
|
||||||
|
auto eventBox = Widget::Create<EventBox>();
|
||||||
|
widgetAudioBody(*eventBox, AudioType::Input);
|
||||||
|
parent.AddChild(std::move(eventBox));
|
||||||
|
}
|
||||||
// Need an EventBox
|
// Need an EventBox
|
||||||
auto eventBox = Widget::Create<EventBox>();
|
auto eventBox = Widget::Create<EventBox>();
|
||||||
widgetAudioBody(*eventBox);
|
widgetAudioBody(*eventBox, AudioType::Output);
|
||||||
parent.AddChild(std::move(eventBox));
|
parent.AddChild(std::move(eventBox));
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
// Just invoke it.
|
// Just invoke it.
|
||||||
widgetAudioBody(parent);
|
if (Config::Get().audioInput)
|
||||||
|
{
|
||||||
|
widgetAudioBody(parent, AudioType::Input);
|
||||||
|
}
|
||||||
|
widgetAudioBody(parent, AudioType::Output);
|
||||||
}
|
}
|
||||||
|
parent.AddTimer<Widget>(DynCtx::UpdateAudio, DynCtx::updateTimeFast);
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef WITH_BLUEZ
|
#ifdef WITH_BLUEZ
|
||||||
|
|
|
@ -132,6 +132,7 @@ void Config::Load()
|
||||||
}
|
}
|
||||||
|
|
||||||
AddConfigVar("CenterTime", config.centerTime, lineView, foundProperty);
|
AddConfigVar("CenterTime", config.centerTime, lineView, foundProperty);
|
||||||
|
AddConfigVar("AudioInput", config.audioInput, lineView, foundProperty);
|
||||||
AddConfigVar("AudioRevealer", config.audioRevealer, lineView, foundProperty);
|
AddConfigVar("AudioRevealer", config.audioRevealer, lineView, foundProperty);
|
||||||
AddConfigVar("NetworkWidget", config.networkWidget, lineView, foundProperty);
|
AddConfigVar("NetworkWidget", config.networkWidget, lineView, foundProperty);
|
||||||
AddConfigVar("WorkspaceScrollOnMonitor", config.workspaceScrollOnMonitor, lineView, foundProperty);
|
AddConfigVar("WorkspaceScrollOnMonitor", config.workspaceScrollOnMonitor, lineView, foundProperty);
|
||||||
|
|
|
@ -16,9 +16,10 @@ public:
|
||||||
|
|
||||||
bool centerTime = true;
|
bool centerTime = true;
|
||||||
bool audioRevealer = false;
|
bool audioRevealer = false;
|
||||||
|
bool audioInput = false;
|
||||||
bool networkWidget = true;
|
bool networkWidget = true;
|
||||||
bool workspaceScrollOnMonitor = true; // Scroll through workspaces on monitor instead of all
|
bool workspaceScrollOnMonitor = true; // Scroll through workspaces on monitor instead of all
|
||||||
bool workspaceScrollInvert = false; // Up = +1, instead of Up = -1
|
bool workspaceScrollInvert = false; // Up = +1, instead of Up = -1
|
||||||
|
|
||||||
// Controls for color progression of the network widget
|
// Controls for color progression of the network widget
|
||||||
uint32_t minUploadBytes = 0; // Bottom limit of the network widgets upload. Everything below it is considered "under"
|
uint32_t minUploadBytes = 0; // Bottom limit of the network widgets upload. Everything below it is considered "under"
|
||||||
|
|
|
@ -2,6 +2,7 @@
|
||||||
#include "System.h"
|
#include "System.h"
|
||||||
#include "Common.h"
|
#include "Common.h"
|
||||||
|
|
||||||
|
#include <cmath>
|
||||||
#include <pulse/pulseaudio.h>
|
#include <pulse/pulseaudio.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
|
@ -77,20 +78,36 @@ namespace PulseAudio
|
||||||
ASSERT(res >= 0, "pa_context_connect failed!");
|
ASSERT(res >= 0, "pa_context_connect failed!");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
inline double PAVolumeToDouble(const pa_cvolume* volume)
|
||||||
|
{
|
||||||
|
double vol = (double)pa_cvolume_avg(volume) / (double)PA_VOLUME_NORM;
|
||||||
|
// Just round to 1% precision, should be enough
|
||||||
|
constexpr double precision = 0.01;
|
||||||
|
double volRounded = std::round(vol * 1 / precision) * precision;
|
||||||
|
return volRounded;
|
||||||
|
}
|
||||||
|
|
||||||
inline System::AudioInfo GetInfo()
|
inline System::AudioInfo GetInfo()
|
||||||
{
|
{
|
||||||
const char* defaultSink = nullptr;
|
struct ServerInfo
|
||||||
|
{
|
||||||
|
const char* defaultSink = nullptr;
|
||||||
|
const char* defaultSource = nullptr;
|
||||||
|
} serverInfo;
|
||||||
|
|
||||||
System::AudioInfo info{};
|
System::AudioInfo info{};
|
||||||
// 1. Get default sink
|
// 1. Get default sink
|
||||||
auto serverInfo = [](pa_context*, const pa_server_info* info, void* sink)
|
auto getServerInfo = [](pa_context*, const pa_server_info* info, void* out)
|
||||||
{
|
{
|
||||||
if (!info)
|
if (!info)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
*(const char**)sink = info->default_sink_name;
|
ServerInfo* serverInfo = (ServerInfo*)out;
|
||||||
|
serverInfo->defaultSink = info->default_sink_name;
|
||||||
|
serverInfo->defaultSource = info->default_source_name;
|
||||||
};
|
};
|
||||||
|
|
||||||
pa_operation* op = pa_context_get_server_info(context, +serverInfo, &defaultSink);
|
pa_operation* op = pa_context_get_server_info(context, +getServerInfo, &serverInfo);
|
||||||
pa_operation_ref(op);
|
pa_operation_ref(op);
|
||||||
pendingOperations.push_back(op);
|
pendingOperations.push_back(op);
|
||||||
|
|
||||||
|
@ -103,22 +120,43 @@ namespace PulseAudio
|
||||||
|
|
||||||
System::AudioInfo* out = (System::AudioInfo*)audioInfo;
|
System::AudioInfo* out = (System::AudioInfo*)audioInfo;
|
||||||
|
|
||||||
double vol = (double)pa_cvolume_avg(&info->volume) / (double)PA_VOLUME_NORM;
|
double vol = PAVolumeToDouble(&info->volume);
|
||||||
out->volume = vol;
|
out->sinkVolume = vol;
|
||||||
out->muted = info->mute;
|
out->sinkMuted = info->mute;
|
||||||
|
|
||||||
};
|
};
|
||||||
op = pa_context_get_sink_info_by_name(context, defaultSink, +sinkInfo, &info);
|
if (serverInfo.defaultSink)
|
||||||
|
{
|
||||||
|
op = pa_context_get_sink_info_by_name(context, serverInfo.defaultSink, +sinkInfo, &info);
|
||||||
|
pa_operation_ref(op);
|
||||||
|
pendingOperations.push_back(op);
|
||||||
|
|
||||||
pa_operation_ref(op);
|
FlushLoop();
|
||||||
pendingOperations.push_back(op);
|
}
|
||||||
|
|
||||||
FlushLoop();
|
auto sourceInfo = [](pa_context*, const pa_source_info* info, int, void* audioInfo)
|
||||||
|
{
|
||||||
|
if (!info)
|
||||||
|
return;
|
||||||
|
|
||||||
|
System::AudioInfo* out = (System::AudioInfo*)audioInfo;
|
||||||
|
|
||||||
|
double vol = PAVolumeToDouble(&info->volume);
|
||||||
|
out->sourceVolume = vol;
|
||||||
|
out->sourceMuted = info->mute;
|
||||||
|
};
|
||||||
|
if (serverInfo.defaultSource)
|
||||||
|
{
|
||||||
|
op = pa_context_get_source_info_by_name(context, serverInfo.defaultSource, +sourceInfo, &info);
|
||||||
|
pa_operation_ref(op);
|
||||||
|
pendingOperations.push_back(op);
|
||||||
|
|
||||||
|
FlushLoop();
|
||||||
|
}
|
||||||
|
|
||||||
return info;
|
return info;
|
||||||
}
|
}
|
||||||
|
|
||||||
inline void SetVolume(double value)
|
inline void SetVolumeSink(double value)
|
||||||
{
|
{
|
||||||
double valClamped = std::clamp(value, 0., 1.);
|
double valClamped = std::clamp(value, 0., 1.);
|
||||||
// I'm too lazy to implement the c api for this. Since it will only be called when needed and doesn't pipe, it shouldn't be a problem to
|
// I'm too lazy to implement the c api for this. Since it will only be called when needed and doesn't pipe, it shouldn't be a problem to
|
||||||
|
@ -127,6 +165,15 @@ namespace PulseAudio
|
||||||
system(cmd.c_str());
|
system(cmd.c_str());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
inline void SetVolumeSource(double value)
|
||||||
|
{
|
||||||
|
double valClamped = std::clamp(value, 0., 1.);
|
||||||
|
// I'm too lazy to implement the c api for this. Since it will only be called when needed and doesn't pipe, it shouldn't be a problem to
|
||||||
|
// fallback for a command
|
||||||
|
std::string cmd = "pamixer --default-source --set-volume " + std::to_string((uint32_t)(valClamped * 100));
|
||||||
|
system(cmd.c_str());
|
||||||
|
}
|
||||||
|
|
||||||
inline void Shutdown()
|
inline void Shutdown()
|
||||||
{
|
{
|
||||||
pa_mainloop_free(mainLoop);
|
pa_mainloop_free(mainLoop);
|
||||||
|
|
|
@ -437,9 +437,13 @@ namespace System
|
||||||
{
|
{
|
||||||
return PulseAudio::GetInfo();
|
return PulseAudio::GetInfo();
|
||||||
}
|
}
|
||||||
void SetVolume(double volume)
|
void SetVolumeSink(double volume)
|
||||||
{
|
{
|
||||||
PulseAudio::SetVolume(volume);
|
PulseAudio::SetVolumeSink(volume);
|
||||||
|
}
|
||||||
|
void SetVolumeSource(double volume)
|
||||||
|
{
|
||||||
|
PulseAudio::SetVolumeSource(volume);
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef WITH_HYPRLAND
|
#ifdef WITH_HYPRLAND
|
||||||
|
|
10
src/System.h
10
src/System.h
|
@ -73,11 +73,15 @@ namespace System
|
||||||
|
|
||||||
struct AudioInfo
|
struct AudioInfo
|
||||||
{
|
{
|
||||||
double volume;
|
double sinkVolume;
|
||||||
bool muted;
|
bool sinkMuted;
|
||||||
|
|
||||||
|
double sourceVolume;
|
||||||
|
bool sourceMuted;
|
||||||
};
|
};
|
||||||
AudioInfo GetAudioInfo();
|
AudioInfo GetAudioInfo();
|
||||||
void SetVolume(double volume);
|
void SetVolumeSink(double volume);
|
||||||
|
void SetVolumeSource(double volume);
|
||||||
|
|
||||||
#ifdef WITH_HYPRLAND
|
#ifdef WITH_HYPRLAND
|
||||||
enum class WorkspaceStatus
|
enum class WorkspaceStatus
|
||||||
|
|
37
src/gBar.cpp
37
src/gBar.cpp
|
@ -13,6 +13,24 @@
|
||||||
|
|
||||||
const char* audioTmpFileOpen = "/tmp/gBar__audio";
|
const char* audioTmpFileOpen = "/tmp/gBar__audio";
|
||||||
|
|
||||||
|
static bool flyin = false;
|
||||||
|
void OpenAudioFlyin(Window& window, int32_t monitor, AudioFlyin::Type type)
|
||||||
|
{
|
||||||
|
flyin = true;
|
||||||
|
if (access(audioTmpFileOpen, F_OK) != 0)
|
||||||
|
{
|
||||||
|
FILE* audioTempFile = fopen(audioTmpFileOpen, "w");
|
||||||
|
AudioFlyin::Create(window, monitor, type);
|
||||||
|
fclose(audioTempFile);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// Already open, close
|
||||||
|
LOG("Audio flyin already open");
|
||||||
|
exit(0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
int main(int argc, char** argv)
|
int main(int argc, char** argv)
|
||||||
{
|
{
|
||||||
System::Init();
|
System::Init();
|
||||||
|
@ -31,18 +49,11 @@ int main(int argc, char** argv)
|
||||||
}
|
}
|
||||||
else if (strcmp(argv[1], "audio") == 0)
|
else if (strcmp(argv[1], "audio") == 0)
|
||||||
{
|
{
|
||||||
if (access(audioTmpFileOpen, F_OK) != 0)
|
OpenAudioFlyin(window, monitor, AudioFlyin::Type::Speaker);
|
||||||
{
|
}
|
||||||
FILE* audioTempFile = fopen(audioTmpFileOpen, "w");
|
else if (strcmp(argv[1], "mic") == 0)
|
||||||
AudioFlyin::Create(window, monitor);
|
{
|
||||||
fclose(audioTempFile);
|
OpenAudioFlyin(window, monitor, AudioFlyin::Type::Microphone);
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
// Already open, close
|
|
||||||
LOG("Audio already open");
|
|
||||||
exit(0);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
#ifdef WITH_BLUEZ
|
#ifdef WITH_BLUEZ
|
||||||
else if (strcmp(argv[1], "bluetooth") == 0)
|
else if (strcmp(argv[1], "bluetooth") == 0)
|
||||||
|
@ -66,7 +77,7 @@ int main(int argc, char** argv)
|
||||||
window.Run(argc, argv);
|
window.Run(argc, argv);
|
||||||
|
|
||||||
System::FreeResources();
|
System::FreeResources();
|
||||||
if (strcmp(argv[1], "audio") == 0)
|
if (flyin)
|
||||||
{
|
{
|
||||||
remove(audioTmpFileOpen);
|
remove(audioTmpFileOpen);
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue