From 673259897dcf2684bc40f9feca624c8439aefc46 Mon Sep 17 00:00:00 2001 From: Felix Kratz Date: Sun, 9 Oct 2022 16:21:22 +0200 Subject: [PATCH] add volume_change event --- makefile | 4 +-- src/bar_item.c | 6 ++++ src/bar_manager.c | 12 ++++++++ src/bar_manager.h | 1 + src/custom_events.c | 1 + src/custom_events.h | 1 + src/event.c | 6 ++++ src/event.h | 4 +++ src/misc/defines.h | 1 + src/sketchybar.m | 3 ++ src/volume.c | 69 +++++++++++++++++++++++++++++++++++++++++++++ src/volume.h | 5 ++++ 12 files changed, 111 insertions(+), 2 deletions(-) create mode 100644 src/volume.c create mode 100644 src/volume.h diff --git a/makefile b/makefile index b4992f0..ea9a56e 100644 --- a/makefile +++ b/makefile @@ -1,12 +1,12 @@ CFLAGS = -std=c99 -Wall -DNDEBUG -Ofast -ffast-math -fvisibility=hidden -fno-common -LIBS = -framework Carbon -framework Cocoa -F/System/Library/PrivateFrameworks -framework SkyLight +LIBS = -framework Carbon -framework Cocoa -framework CoreAudio -F/System/Library/PrivateFrameworks -framework SkyLight ODIR = bin SRC = src _OBJ = alias.o background.o bar_item.o custom_events.o event.o graph.o \ image.o mouse.o shadow.o text.o message.o mouse.o bar.o window.o \ bar_manager.o display.o event_loop.o group.o mach.o popup.o \ - animation.o workspace.om + animation.o workspace.om volume.o OBJ = $(patsubst %, $(ODIR)/%, $(_OBJ)) .PHONY: all clean arm x86 profile leak universal diff --git a/src/bar_item.c b/src/bar_item.c index b6a6964..9deea83 100644 --- a/src/bar_item.c +++ b/src/bar_item.c @@ -2,6 +2,7 @@ #include "bar_manager.h" #include "event_loop.h" #include "event.h" +#include "volume.h" struct bar_item* bar_item_create() { struct bar_item* bar_item = malloc(sizeof(struct bar_item)); @@ -994,6 +995,11 @@ void bar_item_parse_subscribe_message(struct bar_item* bar_item, char* message, while (event.text && event.length > 0) { uint64_t event_flag = custom_events_get_flag_for_name(&g_bar_manager.custom_events, event.text ); + + if (event_flag & UPDATE_VOLUME_CHANGE) { + begin_receiving_volume_events(); + } + bar_item->update_mask |= event_flag; if (!event_flag) { diff --git a/src/bar_manager.c b/src/bar_manager.c index bccf602..c8ec42a 100644 --- a/src/bar_manager.c +++ b/src/bar_manager.c @@ -733,6 +733,18 @@ void bar_manager_handle_mouse_exited(struct bar_manager* bar_manager, struct bar } } +void bar_manager_handle_volume_change(struct bar_manager* bar_manager, float volume) { + struct env_vars env_vars; + env_vars_init(&env_vars); + char volume_str[16]; + snprintf(volume_str, 16, "%.2f", volume); + env_vars_set(&env_vars, string_copy("INFO"), string_copy(volume_str)); + bar_manager_custom_events_trigger(bar_manager, + COMMAND_SUBSCRIBE_VOLUME_CHANGE, + &env_vars ); + env_vars_destroy(&env_vars); +} + void bar_manager_handle_front_app_switch(struct bar_manager* bar_manager, char* info) { struct env_vars env_vars; env_vars_init(&env_vars); diff --git a/src/bar_manager.h b/src/bar_manager.h index e0dd6b8..eedfccd 100644 --- a/src/bar_manager.h +++ b/src/bar_manager.h @@ -101,6 +101,7 @@ void bar_manager_handle_space_change(struct bar_manager* bar_manager, bool force void bar_manager_handle_display_change(struct bar_manager* bar_manager); void bar_manager_handle_system_woke(struct bar_manager* bar_manager); void bar_manager_handle_system_will_sleep(struct bar_manager* bar_manager); +void bar_manager_handle_volume_change(struct bar_manager* bar_manager, float volume); void bar_manager_custom_events_trigger(struct bar_manager* bar_manager, char* name, struct env_vars* env_vars); void bar_manager_destroy(struct bar_manager* bar_manager); diff --git a/src/custom_events.c b/src/custom_events.c index c76282c..6c943f1 100644 --- a/src/custom_events.c +++ b/src/custom_events.c @@ -29,6 +29,7 @@ void custom_events_init(struct custom_events* custom_events) { custom_events_append(custom_events, string_copy(COMMAND_SUBSCRIBE_SYSTEM_WILL_SLEEP), NULL); custom_events_append(custom_events, string_copy(COMMAND_SUBSCRIBE_MOUSE_ENTERED_GLOBAL), NULL); custom_events_append(custom_events, string_copy(COMMAND_SUBSCRIBE_MOUSE_EXITED_GLOBAL), NULL); + custom_events_append(custom_events, string_copy(COMMAND_SUBSCRIBE_VOLUME_CHANGE), NULL); } void custom_events_append(struct custom_events* custom_events, char* name, char* notification) { diff --git a/src/custom_events.h b/src/custom_events.h index fb4b04f..4940210 100644 --- a/src/custom_events.h +++ b/src/custom_events.h @@ -11,6 +11,7 @@ #define UPDATE_SYSTEM_WILL_SLEEP 1ULL << 7 #define UPDATE_ENTERED_GLOBAL 1ULL << 8 #define UPDATE_EXITED_GLOBAL 1ULL << 9 +#define UPDATE_VOLUME_CHANGE 1ULL << 10 extern void* g_workspace_context; extern void workspace_create_custom_observer(void** context, char* name); diff --git a/src/event.c b/src/event.c index 8db0ede..7511787 100644 --- a/src/event.c +++ b/src/event.c @@ -250,3 +250,9 @@ EVENT_CALLBACK(EVENT_HANDLER_MOUSE_EXITED) { CFRelease(context); return EVENT_SUCCESS; } + +EVENT_CALLBACK(EVENT_HANDLER_VOLUME_CHANGED) { + bar_manager_handle_volume_change(&g_bar_manager, *(float*)context); + free(context); + return EVENT_SUCCESS; +} diff --git a/src/event.h b/src/event.h index 495a3cf..be9c66b 100644 --- a/src/event.h +++ b/src/event.h @@ -29,6 +29,7 @@ EVENT_CALLBACK(EVENT_HANDLER_MACH_MESSAGE); EVENT_CALLBACK(EVENT_HANDLER_MOUSE_UP); EVENT_CALLBACK(EVENT_HANDLER_MOUSE_ENTERED); EVENT_CALLBACK(EVENT_HANDLER_MOUSE_EXITED); +EVENT_CALLBACK(EVENT_HANDLER_VOLUME_CHANGED); EVENT_CALLBACK(EVENT_HANDLER_DISTRIBUTED_NOTIFICATION); #define EVENT_QUEUED 0x0 @@ -59,6 +60,7 @@ enum event_type { MOUSE_UP, MOUSE_ENTERED, MOUSE_EXITED, + VOLUME_CHANGED, DISTRIBUTED_NOTIFICATION, EVENT_TYPE_COUNT @@ -83,6 +85,7 @@ static const char *event_type_str[] = { [MOUSE_UP] = "mouse_up", [MOUSE_ENTERED] = "mouse_entered", [MOUSE_EXITED] = "mouse_exited", + [VOLUME_CHANGED] = "volume_changed", [DISTRIBUTED_NOTIFICATION] = "distributed_notification", [EVENT_TYPE_COUNT] = "event_type_count" @@ -99,6 +102,7 @@ static event_callback *event_handler[] = { [MOUSE_UP] = EVENT_HANDLER_MOUSE_UP, [MOUSE_ENTERED] = EVENT_HANDLER_MOUSE_ENTERED, [MOUSE_EXITED] = EVENT_HANDLER_MOUSE_EXITED, + [VOLUME_CHANGED] = EVENT_HANDLER_VOLUME_CHANGED, [DISTRIBUTED_NOTIFICATION] = EVENT_HANDLER_DISTRIBUTED_NOTIFICATION, [MENU_BAR_HIDDEN_CHANGED] = EVENT_HANDLER_MENU_BAR_HIDDEN_CHANGED, diff --git a/src/misc/defines.h b/src/misc/defines.h index c0fb9ec..b76ffde 100644 --- a/src/misc/defines.h +++ b/src/misc/defines.h @@ -93,6 +93,7 @@ #define COMMAND_SUBSCRIBE_DISPLAY_CHANGE "display_change" #define COMMAND_SUBSCRIBE_SYSTEM_WOKE "system_woke" #define COMMAND_SUBSCRIBE_SYSTEM_WILL_SLEEP "system_will_sleep" +#define COMMAND_SUBSCRIBE_VOLUME_CHANGE "volume_change" #define COMMAND_SUBSCRIBE_MOUSE_ENTERED "mouse.entered" #define COMMAND_SUBSCRIBE_MOUSE_EXITED "mouse.exited" #define COMMAND_SUBSCRIBE_MOUSE_CLICKED "mouse.clicked" diff --git a/src/sketchybar.m b/src/sketchybar.m index f56f6fa..8361d61 100644 --- a/src/sketchybar.m +++ b/src/sketchybar.m @@ -4,6 +4,7 @@ #include "mach.h" #include "mouse.h" #include "message.h" +#include "volume.h" #define LCFILE_PATH_FMT "/tmp/sketchybar_%s.lock" @@ -32,6 +33,7 @@ void *g_workspace_context; char g_config_file[4096]; char g_lock_file[MAXLEN]; bool g_verbose; +bool g_volume_events; static int client_send_message(int argc, char **argv) { if (argc <= 1) { @@ -148,6 +150,7 @@ static inline void init_misc_settings(void) { CGSetLocalEventsSuppressionInterval(0.0f); CGEnableEventStateCombining(false); g_connection = SLSMainConnectionID(); + g_volume_events = false; } #pragma clang diagnostic pop diff --git a/src/volume.c b/src/volume.c new file mode 100644 index 0000000..8250eed --- /dev/null +++ b/src/volume.c @@ -0,0 +1,69 @@ +#include "volume.h" +#include "event.h" + +extern bool g_volume_events; + +static AudioObjectPropertyAddress kVolumePropertyAddress = { + kAudioDevicePropertyVolumeScalar, + kAudioObjectPropertyScopeOutput, + kAudioObjectPropertyElementMain }; + +static AudioObjectPropertyAddress kMutePropertyAddress = { + kAudioDevicePropertyMute, + kAudioObjectPropertyScopeOutput, + kAudioObjectPropertyElementMain }; + +float g_last_volume = 0.f; +static OSStatus handler(AudioObjectID id, uint32_t address_count, const AudioObjectPropertyAddress* addresses, void* context) { + float* volume = malloc(sizeof(float)); + memset(volume, 0, sizeof(float)); + + uint32_t muted = 0; + uint32_t size = sizeof(uint32_t); + + AudioObjectGetPropertyData(id, + &kMutePropertyAddress, + 0, + NULL, + &size, + &muted ); + + size = sizeof(float); + AudioObjectGetPropertyData(id, + &kVolumePropertyAddress, + 0, + NULL, + &size, + volume ); + + if (muted) *volume = 0.f; + if (*volume > g_last_volume + 1e-2 || *volume < g_last_volume - 1e-2) { + g_last_volume = *volume; + struct event *event = event_create(&g_event_loop, + VOLUME_CHANGED, + (void *) volume); + + event_loop_post(&g_event_loop, event); + } + return KERN_SUCCESS; +} + +void begin_receiving_volume_events() { + if (g_volume_events) return; + AudioObjectPropertyAddress output_addr = { + kAudioHardwarePropertyDefaultOutputDevice, + kAudioObjectPropertyScopeGlobal, + kAudioObjectPropertyElementMain }; + + AudioObjectID id = 0; + uint32_t size = sizeof(AudioObjectID); + AudioObjectGetPropertyData(kAudioObjectSystemObject, + &output_addr, + 0, + NULL, + &size, + &id ); + + AudioObjectAddPropertyListener(id, &kMutePropertyAddress, &handler, NULL); + AudioObjectAddPropertyListener(id, &kVolumePropertyAddress, &handler, NULL); +} diff --git a/src/volume.h b/src/volume.h new file mode 100644 index 0000000..d694d6a --- /dev/null +++ b/src/volume.h @@ -0,0 +1,5 @@ +#include "Carbon/Carbon.h" +#include "CoreAudio/CoreAudio.h" +#include + +void begin_receiving_volume_events();