mirror of
https://github.com/scorpion-26/gBar.git
synced 2024-11-21 18:52: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]
|
||||
```
|
||||
*Open microphone flyin, this is equivalent to the audio flyin*
|
||||
```
|
||||
gBar mic [monitor]
|
||||
```
|
||||
*Open bluetooth widget*
|
||||
```
|
||||
gBar bluetooth [monitor]
|
||||
|
@ -68,6 +72,7 @@ Bar:
|
|||
- Time
|
||||
- Bluetooth (BlueZ only)
|
||||
- Audio control
|
||||
- Microphone control
|
||||
- Power control
|
||||
- Shutdown
|
||||
- Restart
|
||||
|
@ -87,6 +92,7 @@ Bluetooth:
|
|||
|
||||
Audio Flyin:
|
||||
- Audio control
|
||||
- Microphone control
|
||||
|
||||
## Configuration for your system
|
||||
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;
|
||||
}
|
||||
|
||||
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 {
|
||||
font-size: 24px;
|
||||
color: #ffb86c;
|
||||
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 {
|
||||
font-size: 16px;
|
||||
color: #1793D1;
|
||||
|
@ -325,32 +378,4 @@
|
|||
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 */
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
// 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 {
|
||||
font-size: 24px;
|
||||
color: $orange;
|
||||
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 {
|
||||
font-size: $textsize;
|
||||
color: $btblue;
|
||||
|
@ -348,34 +411,3 @@ $textsize: 16px;
|
|||
margin: 0px 0px 0px 10px;
|
||||
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)
|
||||
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.
|
||||
AudioRevealer: false
|
||||
|
||||
|
|
|
@ -5,6 +5,8 @@ namespace AudioFlyin
|
|||
{
|
||||
namespace DynCtx
|
||||
{
|
||||
Type type;
|
||||
|
||||
Window* win;
|
||||
Slider* slider;
|
||||
Text* icon;
|
||||
|
@ -19,28 +21,59 @@ namespace AudioFlyin
|
|||
|
||||
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&)
|
||||
{
|
||||
System::AudioInfo info = System::GetAudioInfo();
|
||||
if (sliderVal != info.volume || muted != info.muted)
|
||||
if (type == Type::Speaker)
|
||||
{
|
||||
// Extend timer
|
||||
curCloseTime = msOpen + closeTime;
|
||||
|
||||
sliderVal = info.volume;
|
||||
slider->SetValue(info.volume);
|
||||
|
||||
muted = info.muted;
|
||||
if (info.muted)
|
||||
if (sliderVal != info.sinkVolume || muted != info.sinkMuted)
|
||||
{
|
||||
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->SetHorizontalTransform({100, true, Alignment::Fill});
|
||||
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->SetRange({0, 1, 0.01});
|
||||
DynCtx::slider = slider.get();
|
||||
|
||||
auto icon = Widget::Create<Text>();
|
||||
icon->SetClass("audio-icon");
|
||||
icon->SetText("墳");
|
||||
if (DynCtx::type == Type::Speaker)
|
||||
{
|
||||
icon->SetClass("audio-icon");
|
||||
icon->SetText(" ");
|
||||
}
|
||||
else if (DynCtx::type == Type::Microphone)
|
||||
{
|
||||
icon->SetClass("mic-icon");
|
||||
icon->SetText("");
|
||||
}
|
||||
|
||||
DynCtx::icon = icon.get();
|
||||
|
||||
parent.AddChild(std::move(slider));
|
||||
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::type = type;
|
||||
auto mainWidget = Widget::Create<Box>();
|
||||
mainWidget->SetSpacing({8, false});
|
||||
mainWidget->SetVerticalTransform({16, true, Alignment::Fill});
|
||||
|
|
|
@ -4,5 +4,10 @@
|
|||
|
||||
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
|
||||
|
||||
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;
|
||||
TimerResult UpdateAudio(Slider& slider)
|
||||
Text* micIcon;
|
||||
TimerResult UpdateAudio(Widget&)
|
||||
{
|
||||
System::AudioInfo info = System::GetAudioInfo();
|
||||
slider.SetValue(info.volume);
|
||||
if (info.muted)
|
||||
audioSlider->SetValue(info.sinkVolume);
|
||||
if (info.sinkMuted)
|
||||
{
|
||||
audioIcon->SetText("ﱝ");
|
||||
audioIcon->SetText("");
|
||||
}
|
||||
else
|
||||
{
|
||||
audioIcon->SetText("墳");
|
||||
audioIcon->SetText("");
|
||||
}
|
||||
if (Config::Get().audioInput)
|
||||
{
|
||||
micSlider->SetValue(info.sourceVolume);
|
||||
if (info.sourceMuted)
|
||||
{
|
||||
micIcon->SetText("");
|
||||
}
|
||||
else
|
||||
{
|
||||
micIcon->SetText("");
|
||||
}
|
||||
}
|
||||
return TimerResult::Ok;
|
||||
}
|
||||
|
@ -256,33 +276,59 @@ namespace Bar
|
|||
parent.AddChild(std::move(eventBox));
|
||||
}
|
||||
|
||||
// Handles in and out
|
||||
void WidgetAudio(Widget& parent)
|
||||
{
|
||||
auto widgetAudioSlider = [](Widget& parent)
|
||||
enum class AudioType
|
||||
{
|
||||
Input,
|
||||
Output
|
||||
};
|
||||
auto widgetAudioSlider = [](Widget& parent, AudioType type)
|
||||
{
|
||||
auto slider = Widget::Create<Slider>();
|
||||
slider->SetOrientation(Orientation::Horizontal);
|
||||
slider->SetHorizontalTransform({100, true, Alignment::Fill});
|
||||
slider->SetInverted(true);
|
||||
slider->SetClass("audio-volume");
|
||||
slider->AddTimer<Slider>(DynCtx::UpdateAudio, DynCtx::updateTimeFast);
|
||||
slider->OnValueChange(DynCtx::OnChangeVolume);
|
||||
switch (type)
|
||||
{
|
||||
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->SetScrollSpeed((double)Config::Get().audioScrollSpeed / 100.);
|
||||
|
||||
parent.AddChild(std::move(slider));
|
||||
};
|
||||
|
||||
auto widgetAudioBody = [&widgetAudioSlider](Widget& parent)
|
||||
auto widgetAudioBody = [&widgetAudioSlider](Widget& parent, AudioType type)
|
||||
{
|
||||
auto box = Widget::Create<Box>();
|
||||
box->SetSpacing({8, false});
|
||||
box->SetHorizontalTransform({-1, true, Alignment::Right});
|
||||
{
|
||||
auto icon = Widget::Create<Text>();
|
||||
icon->SetClass("audio-icon");
|
||||
icon->SetText("墳");
|
||||
DynCtx::audioIcon = icon.get();
|
||||
switch (type)
|
||||
{
|
||||
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)
|
||||
{
|
||||
|
@ -296,7 +342,7 @@ namespace Bar
|
|||
slideRevealer->SetRevealed(hovered);
|
||||
});
|
||||
{
|
||||
widgetAudioSlider(*revealer);
|
||||
widgetAudioSlider(*revealer, type);
|
||||
}
|
||||
|
||||
box->AddChild(std::move(revealer));
|
||||
|
@ -304,7 +350,7 @@ namespace Bar
|
|||
else
|
||||
{
|
||||
// Straight forward
|
||||
widgetAudioSlider(*box);
|
||||
widgetAudioSlider(*box, type);
|
||||
}
|
||||
|
||||
box->AddChild(std::move(icon));
|
||||
|
@ -314,16 +360,28 @@ namespace Bar
|
|||
|
||||
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
|
||||
auto eventBox = Widget::Create<EventBox>();
|
||||
widgetAudioBody(*eventBox);
|
||||
widgetAudioBody(*eventBox, AudioType::Output);
|
||||
parent.AddChild(std::move(eventBox));
|
||||
}
|
||||
else
|
||||
{
|
||||
// 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
|
||||
|
|
|
@ -132,6 +132,7 @@ void Config::Load()
|
|||
}
|
||||
|
||||
AddConfigVar("CenterTime", config.centerTime, lineView, foundProperty);
|
||||
AddConfigVar("AudioInput", config.audioInput, lineView, foundProperty);
|
||||
AddConfigVar("AudioRevealer", config.audioRevealer, lineView, foundProperty);
|
||||
AddConfigVar("NetworkWidget", config.networkWidget, lineView, foundProperty);
|
||||
AddConfigVar("WorkspaceScrollOnMonitor", config.workspaceScrollOnMonitor, lineView, foundProperty);
|
||||
|
|
|
@ -16,9 +16,10 @@ public:
|
|||
|
||||
bool centerTime = true;
|
||||
bool audioRevealer = false;
|
||||
bool audioInput = false;
|
||||
bool networkWidget = true;
|
||||
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
|
||||
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 "Common.h"
|
||||
|
||||
#include <cmath>
|
||||
#include <pulse/pulseaudio.h>
|
||||
#include <stdlib.h>
|
||||
#include <algorithm>
|
||||
|
@ -77,20 +78,36 @@ namespace PulseAudio
|
|||
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()
|
||||
{
|
||||
const char* defaultSink = nullptr;
|
||||
struct ServerInfo
|
||||
{
|
||||
const char* defaultSink = nullptr;
|
||||
const char* defaultSource = nullptr;
|
||||
} serverInfo;
|
||||
|
||||
System::AudioInfo info{};
|
||||
// 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)
|
||||
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);
|
||||
pendingOperations.push_back(op);
|
||||
|
||||
|
@ -103,22 +120,43 @@ namespace PulseAudio
|
|||
|
||||
System::AudioInfo* out = (System::AudioInfo*)audioInfo;
|
||||
|
||||
double vol = (double)pa_cvolume_avg(&info->volume) / (double)PA_VOLUME_NORM;
|
||||
out->volume = vol;
|
||||
out->muted = info->mute;
|
||||
|
||||
double vol = PAVolumeToDouble(&info->volume);
|
||||
out->sinkVolume = vol;
|
||||
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);
|
||||
pendingOperations.push_back(op);
|
||||
FlushLoop();
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
inline void SetVolume(double value)
|
||||
inline void SetVolumeSink(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
|
||||
|
@ -127,6 +165,15 @@ namespace PulseAudio
|
|||
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()
|
||||
{
|
||||
pa_mainloop_free(mainLoop);
|
||||
|
|
|
@ -437,9 +437,13 @@ namespace System
|
|||
{
|
||||
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
|
||||
|
|
10
src/System.h
10
src/System.h
|
@ -73,11 +73,15 @@ namespace System
|
|||
|
||||
struct AudioInfo
|
||||
{
|
||||
double volume;
|
||||
bool muted;
|
||||
double sinkVolume;
|
||||
bool sinkMuted;
|
||||
|
||||
double sourceVolume;
|
||||
bool sourceMuted;
|
||||
};
|
||||
AudioInfo GetAudioInfo();
|
||||
void SetVolume(double volume);
|
||||
void SetVolumeSink(double volume);
|
||||
void SetVolumeSource(double volume);
|
||||
|
||||
#ifdef WITH_HYPRLAND
|
||||
enum class WorkspaceStatus
|
||||
|
|
37
src/gBar.cpp
37
src/gBar.cpp
|
@ -13,6 +13,24 @@
|
|||
|
||||
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)
|
||||
{
|
||||
System::Init();
|
||||
|
@ -31,18 +49,11 @@ int main(int argc, char** argv)
|
|||
}
|
||||
else if (strcmp(argv[1], "audio") == 0)
|
||||
{
|
||||
if (access(audioTmpFileOpen, F_OK) != 0)
|
||||
{
|
||||
FILE* audioTempFile = fopen(audioTmpFileOpen, "w");
|
||||
AudioFlyin::Create(window, monitor);
|
||||
fclose(audioTempFile);
|
||||
}
|
||||
else
|
||||
{
|
||||
// Already open, close
|
||||
LOG("Audio already open");
|
||||
exit(0);
|
||||
}
|
||||
OpenAudioFlyin(window, monitor, AudioFlyin::Type::Speaker);
|
||||
}
|
||||
else if (strcmp(argv[1], "mic") == 0)
|
||||
{
|
||||
OpenAudioFlyin(window, monitor, AudioFlyin::Type::Microphone);
|
||||
}
|
||||
#ifdef WITH_BLUEZ
|
||||
else if (strcmp(argv[1], "bluetooth") == 0)
|
||||
|
@ -66,7 +77,7 @@ int main(int argc, char** argv)
|
|||
window.Run(argc, argv);
|
||||
|
||||
System::FreeResources();
|
||||
if (strcmp(argv[1], "audio") == 0)
|
||||
if (flyin)
|
||||
{
|
||||
remove(audioTmpFileOpen);
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue