diff --git a/CHANGELOG.md b/CHANGELOG.md index 6be95a7f..70f52d56 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,6 +5,8 @@ All notable changes to this project will be documented in this file. This project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). ## [Unreleased] +### Changed +- Fixed a race condition upon receiving window destroy notifications from macOS because their API is garbage and reports duplicate notifications for the same window [#580](https://github.com/koekeishiya/yabai/issues/580) ## [3.2.0] - 2020-06-14 ### Added diff --git a/src/application.c b/src/application.c index 7380035e..09958ab0 100644 --- a/src/application.c +++ b/src/application.c @@ -10,10 +10,9 @@ static OBSERVER_CALLBACK(application_notification_handler) uint32_t *window_id_ptr = *(uint32_t **) context; if (!window_id_ptr) return; - uint32_t window_id = *window_id_ptr; - while (!__sync_bool_compare_and_swap((uint32_t **) context, window_id_ptr, NULL)); + if (!__sync_bool_compare_and_swap((uint32_t **) context, window_id_ptr, NULL)) return; - event_loop_post(&g_event_loop, WINDOW_DESTROYED, (void *)(uintptr_t) window_id, 0, NULL); + event_loop_post(&g_event_loop, WINDOW_DESTROYED, (void *)(uintptr_t) *window_id_ptr, 0, NULL); } else if (CFEqual(notification, kAXFocusedWindowChangedNotification)) { uint32_t window_id = ax_window_id(element); if (window_id) event_loop_post(&g_event_loop, WINDOW_FOCUSED, (void *)(intptr_t) window_id, 0, NULL); @@ -41,7 +40,7 @@ static OBSERVER_CALLBACK(application_notification_handler) static void application_observe_notification(struct application *application, int notification) { - AXError result = _AXObserverAddNotification(application->observer_ref, application->ref, ax_application_notification[notification], application); + AXError result = AXObserverAddNotification(application->observer_ref, application->ref, ax_application_notification[notification], application); if (result == kAXErrorSuccess || result == kAXErrorNotificationAlreadyRegistered) { application->notification |= 1 << notification; } else { @@ -53,7 +52,7 @@ application_observe_notification(struct application *application, int notificati static void application_unobserve_notification(struct application *application, int notification) { - _AXObserverRemoveNotification(application->observer_ref, application->ref, ax_application_notification[notification]); + AXObserverRemoveNotification(application->observer_ref, application->ref, ax_application_notification[notification]); application->notification &= ~(1 << notification); } diff --git a/src/manifest.m b/src/manifest.m index a73a6aff..f65c0a64 100644 --- a/src/manifest.m +++ b/src/manifest.m @@ -12,7 +12,6 @@ #include #include #include -#include #include #include #include diff --git a/src/misc/helpers.h b/src/misc/helpers.h index 5eacac4f..2601f93b 100644 --- a/src/misc/helpers.h +++ b/src/misc/helpers.h @@ -3,14 +3,6 @@ extern AXError _AXUIElementGetWindow(AXUIElementRef ref, uint32_t *wid); -#define AXOBSERVER_ADD_NOTIFICATION(name) AXError name(AXObserverRef observer, AXUIElementRef application, CFStringRef notification, void *context) -typedef AXOBSERVER_ADD_NOTIFICATION(axobserver_add_notification); -axobserver_add_notification *_AXObserverAddNotification; - -#define AXOBSERVER_REMOVE_NOTIFICATION(name) AXError name(AXObserverRef observer, AXUIElementRef application, CFStringRef notification) -typedef AXOBSERVER_REMOVE_NOTIFICATION(axobserver_remove_notification); -axobserver_remove_notification *_AXObserverRemoveNotification; - static const char *bool_str[] = { "off", "on" }; static const char *layer_str[] = diff --git a/src/window.c b/src/window.c index ec6824e7..29bbd16c 100644 --- a/src/window.c +++ b/src/window.c @@ -8,7 +8,7 @@ extern int g_connection; static void window_observe_notification(struct window *window, int notification) { - AXError result = _AXObserverAddNotification(window->application->observer_ref, window->ref, ax_window_notification[notification], window->id_ptr); + AXError result = AXObserverAddNotification(window->application->observer_ref, window->ref, ax_window_notification[notification], window->id_ptr); if (result == kAXErrorSuccess || result == kAXErrorNotificationAlreadyRegistered) { window->notification |= 1 << notification; } else { @@ -19,7 +19,7 @@ window_observe_notification(struct window *window, int notification) static void window_unobserve_notification(struct window *window, int notification) { - _AXObserverRemoveNotification(window->application->observer_ref, window->ref, ax_window_notification[notification]); + AXObserverRemoveNotification(window->application->observer_ref, window->ref, ax_window_notification[notification]); window->notification &= ~(1 << notification); } diff --git a/src/yabai.c b/src/yabai.c index 6e585091..8512059a 100644 --- a/src/yabai.c +++ b/src/yabai.c @@ -182,26 +182,6 @@ static void exec_config_file(void) } } -static inline void load_axobserver_async(void) -{ - void *handle = dlopen("/System/Library/Frameworks/ApplicationServices.framework/Frameworks/HIServices.framework/Versions/Current/HIServices", RTLD_LAZY); - if (handle) { - _AXObserverAddNotification = dlsym(handle, "AXObserverAddNotificationAsync"); - _AXObserverRemoveNotification = dlsym(handle, "AXObserverRemoveNotificationAsync"); - - if (_AXObserverAddNotification && _AXObserverRemoveNotification) { - debug("%s: loaded AXObserverAddNotificationAsync and AXObserverRemoveNotificationAsync\n", __FUNCTION__); - return; - } - - dlclose(handle); - } - - _AXObserverAddNotification = &AXObserverAddNotification; - _AXObserverRemoveNotification = &AXObserverRemoveNotification; - debug("%s: falling back to AXObserverAddNotification and AXObserverRemoveNotification\n", __FUNCTION__); -} - #pragma clang diagnostic push #pragma clang diagnostic ignored "-Wdeprecated-declarations" static inline void init_misc_settings(void) @@ -291,7 +271,6 @@ int main(int argc, char **argv) error("yabai: could not access accessibility features! abort..\n"); } - load_axobserver_async(); init_misc_settings(); acquire_lockfile();