diff --git a/src/application.c b/src/application.c index 09958ab0..c518aaa4 100644 --- a/src/application.c +++ b/src/application.c @@ -6,34 +6,40 @@ static OBSERVER_CALLBACK(application_notification_handler) { if (CFEqual(notification, kAXCreatedNotification)) { event_loop_post(&g_event_loop, WINDOW_CREATED, (void *) CFRetain(element), 0, NULL); - } else if (CFEqual(notification, kAXUIElementDestroyedNotification)) { - uint32_t *window_id_ptr = *(uint32_t **) context; - if (!window_id_ptr) return; - - 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_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); + event_loop_post(&g_event_loop, WINDOW_FOCUSED, (void *)(intptr_t) ax_window_id(element), 0, NULL); } else if (CFEqual(notification, kAXWindowMovedNotification)) { - uint32_t window_id = ax_window_id(element); - if (window_id) event_loop_post(&g_event_loop, WINDOW_MOVED, (void *)(intptr_t) window_id, 0, NULL); + event_loop_post(&g_event_loop, WINDOW_MOVED, (void *)(intptr_t) ax_window_id(element), 0, NULL); } else if (CFEqual(notification, kAXWindowResizedNotification)) { - uint32_t window_id = ax_window_id(element); - if (window_id) event_loop_post(&g_event_loop, WINDOW_RESIZED, (void *)(intptr_t) window_id, 0, NULL); - } else if (CFEqual(notification, kAXWindowMiniaturizedNotification)) { - uint32_t window_id = **((uint32_t **) context); - event_loop_post(&g_event_loop, WINDOW_MINIMIZED, (void *)(intptr_t) window_id, 0, NULL); - } else if (CFEqual(notification, kAXWindowDeminiaturizedNotification)) { - uint32_t window_id = **((uint32_t **) context); - event_loop_post(&g_event_loop, WINDOW_DEMINIMIZED, (void *)(intptr_t) window_id, 0, NULL); + event_loop_post(&g_event_loop, WINDOW_RESIZED, (void *)(intptr_t) ax_window_id(element), 0, NULL); } else if (CFEqual(notification, kAXTitleChangedNotification)) { - uint32_t window_id = ax_window_id(element); - if (window_id) event_loop_post(&g_event_loop, WINDOW_TITLE_CHANGED, (void *)(intptr_t) window_id, 0, NULL); + event_loop_post(&g_event_loop, WINDOW_TITLE_CHANGED, (void *)(intptr_t) ax_window_id(element), 0, NULL); } else if (CFEqual(notification, kAXMenuOpenedNotification)) { - uint32_t window_id = ax_window_id(element); - if (window_id) event_loop_post(&g_event_loop, MENU_OPENED, (void *)(intptr_t) window_id, 0, NULL); + event_loop_post(&g_event_loop, MENU_OPENED, (void *)(intptr_t) ax_window_id(element), 0, NULL); + } else if (CFEqual(notification, kAXWindowMiniaturizedNotification)) { + event_loop_post(&g_event_loop, WINDOW_MINIMIZED, context, 0, NULL); + } else if (CFEqual(notification, kAXWindowDeminiaturizedNotification)) { + event_loop_post(&g_event_loop, WINDOW_DEMINIMIZED, context, 0, NULL); + } else if (CFEqual(notification, kAXUIElementDestroyedNotification)) { + struct window *window = context; + + // + // NOTE(koekeishiya): Flag events that are already queued, but not yet processed, + // so that they will be ignored; the memory we allocated is still valid and will + // be freed when this event is handled. + // + + if (!__sync_bool_compare_and_swap(&window->id_ptr, &window->id, NULL)) return; + + // + // NOTE(koekeishiya): Usually we avoid running code off the event-loop thread, + // however in this case it is fine, as we are only touching fields that never + // change after the window allocation and creation code. + // + + window_unobserve(window); + + event_loop_post(&g_event_loop, WINDOW_DESTROYED, window, 0, NULL); } } @@ -45,7 +51,7 @@ application_observe_notification(struct application *application, int notificati application->notification |= 1 << notification; } else { if (result == kAXErrorCannotComplete) application->ax_retry = true; - debug("%s: %s failed with error %s\n", __FUNCTION__, ax_application_notification_str[notification], ax_error_str[-result]); + debug("%s: notification %s failed with error %s for %s\n", __FUNCTION__, ax_application_notification_str[notification], ax_error_str[-result], application->name); } } @@ -86,9 +92,9 @@ void application_unobserve(struct application *application) uint32_t application_main_window(struct application *application) { - CFTypeRef window_ref; - bool result = AXUIElementCopyAttributeValue(application->ref, kAXMainWindowAttribute, &window_ref) == kAXErrorSuccess; - if (!result) return 0; + CFTypeRef window_ref = NULL; + AXUIElementCopyAttributeValue(application->ref, kAXMainWindowAttribute, &window_ref); + if (!window_ref) return 0; uint32_t window_id = ax_window_id(window_ref); CFRelease(window_ref); diff --git a/src/event.c b/src/event.c index 93e955ef..b9224cc2 100644 --- a/src/event.c +++ b/src/event.c @@ -149,6 +149,7 @@ static EVENT_CALLBACK(EVENT_HANDLER_APPLICATION_TERMINATED) event_signal_push(SIGNAL_WINDOW_DESTROYED, window); window_manager_remove_window(&g_window_manager, window->id); + window_unobserve(window); window_destroy(window); } @@ -328,13 +329,9 @@ static EVENT_CALLBACK(EVENT_HANDLER_WINDOW_CREATED) static EVENT_CALLBACK(EVENT_HANDLER_WINDOW_DESTROYED) { - uint32_t window_id = (uint32_t)(uintptr_t) context; - struct window *window = window_manager_find_window(&g_window_manager, window_id); - if (!window) return EVENT_FAILURE; - - assert(!*window->id_ptr); + struct window *window = context; debug("%s: %s %d\n", __FUNCTION__, window->application->name, window->id); - window_unobserve(window); + assert(!window->id_ptr); struct view *view = window_manager_find_managed_window(&g_window_manager, window); if (view) { @@ -362,7 +359,7 @@ static EVENT_CALLBACK(EVENT_HANDLER_WINDOW_FOCUSED) return EVENT_FAILURE; } - if (!__sync_bool_compare_and_swap(window->id_ptr, &window->id, &window->id)) { + if (!__sync_bool_compare_and_swap(&window->id_ptr, &window->id, &window->id)) { debug("%s: %d has been marked invalid by the system, ignoring event..\n", __FUNCTION__, window_id); return EVENT_FAILURE; } @@ -395,7 +392,7 @@ static EVENT_CALLBACK(EVENT_HANDLER_WINDOW_MOVED) struct window *window = window_manager_find_window(&g_window_manager, window_id); if (!window) return EVENT_FAILURE; - if (!__sync_bool_compare_and_swap(window->id_ptr, &window->id, &window->id)) { + if (!__sync_bool_compare_and_swap(&window->id_ptr, &window->id, &window->id)) { debug("%s: %d has been marked invalid by the system, ignoring event..\n", __FUNCTION__, window_id); return EVENT_FAILURE; } @@ -417,7 +414,7 @@ static EVENT_CALLBACK(EVENT_HANDLER_WINDOW_RESIZED) struct window *window = window_manager_find_window(&g_window_manager, window_id); if (!window) return EVENT_FAILURE; - if (!__sync_bool_compare_and_swap(window->id_ptr, &window->id, &window->id)) { + if (!__sync_bool_compare_and_swap(&window->id_ptr, &window->id, &window->id)) { debug("%s: %d has been marked invalid by the system, ignoring event..\n", __FUNCTION__, window_id); return EVENT_FAILURE; } @@ -467,12 +464,10 @@ static EVENT_CALLBACK(EVENT_HANDLER_WINDOW_RESIZED) static EVENT_CALLBACK(EVENT_HANDLER_WINDOW_MINIMIZED) { - uint32_t window_id = (uint32_t)(intptr_t) context; - struct window *window = window_manager_find_window(&g_window_manager, window_id); - if (!window) return EVENT_FAILURE; + struct window *window = context; - if (!__sync_bool_compare_and_swap(window->id_ptr, &window->id, &window->id)) { - debug("%s: %d has been marked invalid by the system, ignoring event..\n", __FUNCTION__, window_id); + if (!__sync_bool_compare_and_swap(&window->id_ptr, &window->id, &window->id)) { + debug("%s: %d has been marked invalid by the system, ignoring event..\n", __FUNCTION__, window->id); return EVENT_FAILURE; } @@ -496,13 +491,11 @@ static EVENT_CALLBACK(EVENT_HANDLER_WINDOW_MINIMIZED) static EVENT_CALLBACK(EVENT_HANDLER_WINDOW_DEMINIMIZED) { - uint32_t window_id = (uint32_t)(intptr_t) context; - struct window *window = window_manager_find_window(&g_window_manager, window_id); - if (!window) return EVENT_FAILURE; + struct window *window = context; - if (!__sync_bool_compare_and_swap(window->id_ptr, &window->id, &window->id)) { - debug("%s: %d has been marked invalid by the system, ignoring event..\n", __FUNCTION__, window_id); - window_manager_remove_lost_focused_event(&g_window_manager, window_id); + if (!__sync_bool_compare_and_swap(&window->id_ptr, &window->id, &window->id)) { + debug("%s: %d has been marked invalid by the system, ignoring event..\n", __FUNCTION__, window->id); + window_manager_remove_lost_focused_event(&g_window_manager, window->id); return EVENT_FAILURE; } @@ -535,7 +528,7 @@ static EVENT_CALLBACK(EVENT_HANDLER_WINDOW_TITLE_CHANGED) struct window *window = window_manager_find_window(&g_window_manager, window_id); if (!window) return EVENT_FAILURE; - if (!__sync_bool_compare_and_swap(window->id_ptr, &window->id, &window->id)) { + if (!__sync_bool_compare_and_swap(&window->id_ptr, &window->id, &window->id)) { debug("%s: %d has been marked invalid by the system, ignoring event..\n", __FUNCTION__, window_id); return EVENT_FAILURE; } @@ -681,7 +674,7 @@ static EVENT_CALLBACK(EVENT_HANDLER_MOUSE_UP) if (g_mission_control_active) goto out; if (!g_mouse_state.window) goto out; - if (!__sync_bool_compare_and_swap(g_mouse_state.window->id_ptr, &g_mouse_state.window->id, &g_mouse_state.window->id)) { + if (!__sync_bool_compare_and_swap(&g_mouse_state.window->id_ptr, &g_mouse_state.window->id, &g_mouse_state.window->id)) { debug("%s: %d has been marked invalid by the system, ignoring event..\n", __FUNCTION__, g_mouse_state.window->id); goto err; } @@ -757,7 +750,7 @@ static EVENT_CALLBACK(EVENT_HANDLER_MOUSE_DRAGGED) if (g_mission_control_active) goto out; if (!g_mouse_state.window) goto out; - if (!__sync_bool_compare_and_swap(g_mouse_state.window->id_ptr, &g_mouse_state.window->id, &g_mouse_state.window->id)) { + if (!__sync_bool_compare_and_swap(&g_mouse_state.window->id_ptr, &g_mouse_state.window->id, &g_mouse_state.window->id)) { debug("%s: %d has been marked invalid by the system, ignoring event..\n", __FUNCTION__, g_mouse_state.window->id); g_mouse_state.window = NULL; g_mouse_state.current_action = MOUSE_MODE_NONE; diff --git a/src/window.c b/src/window.c index 8ef484ec..17318877 100644 --- a/src/window.c +++ b/src/window.c @@ -5,10 +5,9 @@ extern int g_normal_window_level; extern int g_floating_window_level; extern int g_connection; -static void -window_observe_notification(struct window *window, int notification) +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); if (result == kAXErrorSuccess || result == kAXErrorNotificationAlreadyRegistered) { window->notification |= 1 << notification; } else { @@ -16,8 +15,7 @@ window_observe_notification(struct window *window, int notification) } } -static void -window_unobserve_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]); window->notification &= ~(1 << notification); @@ -94,6 +92,7 @@ uint64_t *window_space_list(struct window *window, int *count) if (!*count) goto out; space_list = ts_alloc(*count * sizeof(uint64_t)); + for (int i = 0; i < *count; ++i) { CFNumberRef id_ref = CFArrayGetValueAtIndex(space_list_ref, i); CFNumberGetValue(id_ref, CFNumberGetType(id_ref), space_list + i); @@ -118,9 +117,10 @@ void window_serialize(FILE *rsp, struct window *window) int display = display_arrangement(space_display_id(sid)); bool is_topmost = window_is_topmost(window); bool is_minimized = window_is_minimized(window); - bool visible = !is_minimized && (window->is_sticky || space_is_visible(sid)); + bool visible = !is_minimized && !window->application->is_hidden && (window->is_sticky || space_is_visible(sid)); bool border = window->border.id ? 1 : 0; float opacity = window_opacity(window); + bool grabbed = window == g_mouse_state.window; CFStringRef cfrole = window_role(window); if (cfrole) { @@ -150,55 +150,58 @@ void window_serialize(FILE *rsp, struct window *window) "\t\"app\":\"%s\",\n" "\t\"title\":\"%s\",\n" "\t\"frame\":{\n\t\t\"x\":%.4f,\n\t\t\"y\":%.4f,\n\t\t\"w\":%.4f,\n\t\t\"h\":%.4f\n\t},\n" - "\t\"level\":%d,\n" "\t\"role\":\"%s\",\n" "\t\"subrole\":\"%s\",\n" - "\t\"movable\":%d,\n" - "\t\"resizable\":%d,\n" "\t\"display\":%d,\n" "\t\"space\":%d,\n" - "\t\"visible\":%d,\n" - "\t\"focused\":%d,\n" - "\t\"split\":\"%s\",\n" - "\t\"floating\":%d,\n" - "\t\"sticky\":%d,\n" - "\t\"minimized\":%d,\n" - "\t\"topmost\":%d,\n" + "\t\"level\":%d,\n" "\t\"opacity\":%.4f,\n" - "\t\"shadow\":%d,\n" - "\t\"border\":%d,\n" + "\t\"split-type\":\"%s\",\n" "\t\"stack-index\":%d,\n" - "\t\"zoom-parent\":%d,\n" - "\t\"zoom-fullscreen\":%d,\n" - "\t\"native-fullscreen\":%d\n" + "\t\"can-move\":%s,\n" + "\t\"can-resize\":%s,\n" + "\t\"has-focus\":%s,\n" + "\t\"has-shadow\":%s,\n" + "\t\"has-border\":%s,\n" + "\t\"has-parent-zoom\":%s,\n" + "\t\"has-fullscreen-zoom\":%s,\n" + "\t\"is-native-fullscreen\":%s,\n" + "\t\"is-visible\":%s,\n" + "\t\"is-minimized\":%s,\n" + "\t\"is-hidden\":%s,\n" + "\t\"is-floating\":%s,\n" + "\t\"is-sticky\":%s,\n" + "\t\"is-topmost\":%s,\n" + "\t\"is-grabbed\":%s\n" "}", window->id, window->application->pid, window->application->name, escaped_title ? escaped_title : title, - frame.origin.x, frame.origin.y, - frame.size.width, frame.size.height, - window_level(window), + frame.origin.x, frame.origin.y, frame.size.width, frame.size.height, role ? role : "", subrole ? subrole : "", - window_can_move(window), - window_can_resize(window), display, space, - visible, - window->id == g_window_manager.focused_window_id, - split, - window->is_floating, - window->is_sticky, - is_minimized, - is_topmost, + window_level(window), opacity, - window->has_shadow, - border, + split, stack_index, - zoom_parent, - zoom_fullscreen, - window_is_fullscreen(window)); + json_bool(window_can_move(window)), + json_bool(window_can_resize(window)), + json_bool(window->id == g_window_manager.focused_window_id), + json_bool(window->has_shadow), + json_bool(border), + json_bool(zoom_parent), + json_bool(zoom_fullscreen), + json_bool(window_is_fullscreen(window)), + json_bool(visible), + json_bool(window->is_floating), + json_bool(window->is_sticky), + json_bool(is_minimized), + json_bool(window->application->is_hidden), + json_bool(is_topmost), + json_bool(grabbed)); } char *window_title(struct window *window) @@ -231,12 +234,12 @@ CGRect window_ax_frame(struct window *window) AXUIElementCopyAttributeValue(window->ref, kAXPositionAttribute, &position_ref); AXUIElementCopyAttributeValue(window->ref, kAXSizeAttribute, &size_ref); - if (position_ref != NULL) { + if (position_ref) { AXValueGetValue(position_ref, kAXValueTypeCGPoint, &frame.origin); CFRelease(position_ref); } - if (size_ref != NULL) { + if (size_ref) { AXValueGetValue(size_ref, kAXValueTypeCGSize, &frame.size); CFRelease(size_ref); } @@ -303,10 +306,12 @@ bool window_is_fullscreen(struct window *window) { Boolean result = 0; CFTypeRef value; + if (AXUIElementCopyAttributeValue(window->ref, kAXFullscreenAttribute, &value) == kAXErrorSuccess) { result = CFBooleanGetValue(value); CFRelease(value); } + return result; } @@ -454,8 +459,7 @@ struct window *window_create(struct application *application, AXUIElementRef win window->is_minimized = window_is_minimized(window); window->is_fullscreen = window_is_fullscreen(window) || space_is_fullscreen(window_space(window)); window->is_sticky = window_is_sticky(window); - window->id_ptr = malloc(sizeof(uint32_t *)); - *window->id_ptr = &window->id; + window->id_ptr = &window->id; window->has_shadow = true; if (g_window_manager.enable_window_border) border_create(window); @@ -467,6 +471,5 @@ void window_destroy(struct window *window) { border_destroy(window); CFRelease(window->ref); - free(window->id_ptr); free(window); } diff --git a/src/window.h b/src/window.h index 044a3a7f..46a237b5 100644 --- a/src/window.h +++ b/src/window.h @@ -34,7 +34,7 @@ struct window AXUIElementRef ref; int connection; uint32_t id; - uint32_t **volatile id_ptr; + uint32_t *volatile id_ptr; uint8_t notification; bool has_shadow; bool is_fullscreen;