mirror of
https://github.com/scorpion-26/gBar.git
synced 2024-11-25 04:32:10 +00:00
Process audio slider events asynchronously
This commit avoids piling up events if events are queued quicker, than gBar can handle, causing severe slowdowns. Instead, the requests are handled in a worker thread and excess events are discarded. Fixes: https://github.com/scorpion-26/gBar/issues/86
This commit is contained in:
parent
0f943405d3
commit
6dd1ee6783
2 changed files with 85 additions and 4 deletions
38
src/Bar.cpp
38
src/Bar.cpp
|
@ -288,14 +288,30 @@ namespace Bar
|
||||||
Widget* micSlider;
|
Widget* micSlider;
|
||||||
Button* audioIcon;
|
Button* audioIcon;
|
||||||
Button* micIcon;
|
Button* micIcon;
|
||||||
|
|
||||||
|
static AsyncAtomicContext<double> sinkAsyncContext;
|
||||||
void OnChangeVolumeSink(Slider&, double value)
|
void OnChangeVolumeSink(Slider&, double value)
|
||||||
{
|
{
|
||||||
System::SetVolumeSink(value);
|
// Process async and atomically, so the event handler isn't filled up
|
||||||
|
ExecuteAsyncAtomically(
|
||||||
|
sinkAsyncContext,
|
||||||
|
[](double volume)
|
||||||
|
{
|
||||||
|
System::SetVolumeSink(volume);
|
||||||
|
},
|
||||||
|
value);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static AsyncAtomicContext<double> sourceAsyncContext;
|
||||||
void OnChangeVolumeSource(Slider&, double value)
|
void OnChangeVolumeSource(Slider&, double value)
|
||||||
{
|
{
|
||||||
System::SetVolumeSource(value);
|
ExecuteAsyncAtomically(
|
||||||
|
sourceAsyncContext,
|
||||||
|
[](double volume)
|
||||||
|
{
|
||||||
|
System::SetVolumeSource(volume);
|
||||||
|
},
|
||||||
|
value);
|
||||||
}
|
}
|
||||||
|
|
||||||
// For text
|
// For text
|
||||||
|
@ -304,7 +320,14 @@ namespace Bar
|
||||||
{
|
{
|
||||||
audioVolume += delta;
|
audioVolume += delta;
|
||||||
audioVolume = std::clamp(audioVolume, 0.0, 1.0);
|
audioVolume = std::clamp(audioVolume, 0.0, 1.0);
|
||||||
System::SetVolumeSink(audioVolume);
|
// Process async and atomically, so the event handler isn't filled up
|
||||||
|
ExecuteAsyncAtomically(
|
||||||
|
sinkAsyncContext,
|
||||||
|
[](double volume)
|
||||||
|
{
|
||||||
|
System::SetVolumeSink(volume);
|
||||||
|
},
|
||||||
|
audioVolume);
|
||||||
}
|
}
|
||||||
|
|
||||||
double micVolume = 0;
|
double micVolume = 0;
|
||||||
|
@ -312,7 +335,14 @@ namespace Bar
|
||||||
{
|
{
|
||||||
micVolume += delta;
|
micVolume += delta;
|
||||||
micVolume = std::clamp(micVolume, 0.0, 1.0);
|
micVolume = std::clamp(micVolume, 0.0, 1.0);
|
||||||
System::SetVolumeSource(micVolume);
|
// Process async and atomically, so the event handler isn't filled up
|
||||||
|
ExecuteAsyncAtomically(
|
||||||
|
sourceAsyncContext,
|
||||||
|
[](double volume)
|
||||||
|
{
|
||||||
|
System::SetVolumeSource(volume);
|
||||||
|
},
|
||||||
|
micVolume);
|
||||||
}
|
}
|
||||||
|
|
||||||
void OnToggleSink(Button& button)
|
void OnToggleSink(Button& button)
|
||||||
|
|
51
src/Common.h
51
src/Common.h
|
@ -1,11 +1,15 @@
|
||||||
#pragma once
|
#pragma once
|
||||||
|
#include <atomic>
|
||||||
#include <iostream>
|
#include <iostream>
|
||||||
|
#include <optional>
|
||||||
|
#include <thread>
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
#include <string>
|
#include <string>
|
||||||
#include <unordered_map>
|
#include <unordered_map>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
#include <filesystem>
|
#include <filesystem>
|
||||||
#include <map>
|
#include <map>
|
||||||
|
#include <mutex>
|
||||||
|
|
||||||
#include "Log.h"
|
#include "Log.h"
|
||||||
|
|
||||||
|
@ -186,6 +190,53 @@ inline Process OpenProcess(const std::string& command)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
template<typename Data>
|
||||||
|
struct AsyncAtomicContext
|
||||||
|
{
|
||||||
|
std::atomic<bool> running = false;
|
||||||
|
std::mutex queueLock;
|
||||||
|
std::optional<Data> queue;
|
||||||
|
};
|
||||||
|
|
||||||
|
// Executes the callback function asynchronously, but only one at a time.
|
||||||
|
// Multiple requests at once are stored in a FIFO of size 1.
|
||||||
|
// The context should point to a static reference.
|
||||||
|
template<typename Data, typename Callback>
|
||||||
|
inline void ExecuteAsyncAtomically(AsyncAtomicContext<Data>& context, const Callback& callback, const Data& data)
|
||||||
|
{
|
||||||
|
// Update the queue
|
||||||
|
context.queueLock.lock();
|
||||||
|
context.queue = data;
|
||||||
|
context.queueLock.unlock();
|
||||||
|
|
||||||
|
if (!context.running)
|
||||||
|
{
|
||||||
|
// Launch the thread
|
||||||
|
context.running = true;
|
||||||
|
std::thread(
|
||||||
|
[&, callback]()
|
||||||
|
{
|
||||||
|
while (true)
|
||||||
|
{
|
||||||
|
context.queueLock.lock();
|
||||||
|
if (!context.queue.has_value())
|
||||||
|
{
|
||||||
|
context.queueLock.unlock();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
Data data = std::move(*context.queue);
|
||||||
|
context.queue = {};
|
||||||
|
context.queueLock.unlock();
|
||||||
|
|
||||||
|
// Execute
|
||||||
|
callback(std::move(data));
|
||||||
|
}
|
||||||
|
context.running = false;
|
||||||
|
})
|
||||||
|
.detach();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Plugins
|
// Plugins
|
||||||
#include "Window.h"
|
#include "Window.h"
|
||||||
#define DL_VERSION 1
|
#define DL_VERSION 1
|
||||||
|
|
Loading…
Reference in a new issue