Skip to content

Commit

Permalink
#1247 improved ffm autofocus when SIP is disabled
Browse files Browse the repository at this point in the history
  • Loading branch information
koekeishiya committed Apr 24, 2022
1 parent 157165e commit 7e9b09b
Show file tree
Hide file tree
Showing 8 changed files with 142 additions and 6 deletions.
3 changes: 2 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,8 @@ This project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.htm
### Changed
- The scripting-addition will now also remove the space switch animation when using cmd+tab, clicking on an item in the Dock, and using the numeric macOS mission-control keyboard shortcuts [#1235](https://github.com/koekeishiya/yabai/issues/1235)
- Improved logic used to determine the target window in a given direction [#1220](https://github.com/koekeishiya/yabai/issues/1220)
- Improve behaviour of *focus_follows_mouse autoraise*, preventing a window from being raised if it would occlude some other **floating window**. [#1246](https://github.com/koekeishiya/yabai/issues/1246)
- Improve behaviour of *focus_follows_mouse autoraise*, preventing a window from being raised if it would occlude some other **floating window** [#1246](https://github.com/koekeishiya/yabai/issues/1246)
- Added an improved implementation of *focus_follows_mouse autofocus* that uses the scripting-addition. prior autofocus has been renamed to **autofocus_sip_friendly** [#1247](https://github.com/koekeishiya/yabai/issues/1247)

## [4.0.0] - 2022-03-16
### Added
Expand Down
9 changes: 6 additions & 3 deletions src/event.c
Original file line number Diff line number Diff line change
Expand Up @@ -1007,7 +1007,7 @@ static EVENT_CALLBACK(EVENT_HANDLER_MOUSE_MOVED)
}


if (g_window_manager.ffm_mode == FFM_AUTOFOCUS) {
if (g_window_manager.ffm_mode == FFM_AUTOFOCUS_SIP) {

//
// NOTE(koekeishiya): Look for a window with role AXSheet or AXDrawer
Expand Down Expand Up @@ -1037,9 +1037,12 @@ static EVENT_CALLBACK(EVENT_HANDLER_MOUSE_MOVED)
}

CFRelease(window_list);
window_manager_focus_window_without_raise(&window->application->psn, window->id);
window_manager_focus_window_without_raise_sip_friendly(&window->application->psn, window->id);
g_mouse_state.ffm_window_id = window->id;
} else {
} else if (g_window_manager.ffm_mode == FFM_AUTOFOCUS) {
window_manager_focus_window_without_raise(window->id);
g_mouse_state.ffm_window_id = window->id;
} else if (g_window_manager.ffm_mode == FFM_AUTORAISE) {

//
// NOTE(koekeishiya): If any **floating** window would be fully occluded by
Expand Down
3 changes: 3 additions & 0 deletions src/message.c
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,7 @@ extern bool g_verbose;

#define SELECTOR_CONFIG_SPACE "--space"

#define ARGUMENT_CONFIG_FFM_AUTOFOCUS_SIP "autofocus_sip_friendly"
#define ARGUMENT_CONFIG_FFM_AUTOFOCUS "autofocus"
#define ARGUMENT_CONFIG_FFM_AUTORAISE "autoraise"
#define ARGUMENT_CONFIG_WINDOW_ORIGIN_DEFAULT "default"
Expand Down Expand Up @@ -997,6 +998,8 @@ static void handle_domain_config(FILE *rsp, struct token domain, char *message)
fprintf(rsp, "%s\n", ffm_mode_str[g_window_manager.ffm_mode]);
} else if (token_equals(value, ARGUMENT_COMMON_VAL_OFF)) {
g_window_manager.ffm_mode = FFM_DISABLED;
} else if (token_equals(value, ARGUMENT_CONFIG_FFM_AUTOFOCUS_SIP)) {
g_window_manager.ffm_mode = FFM_AUTOFOCUS_SIP;
} else if (token_equals(value, ARGUMENT_CONFIG_FFM_AUTOFOCUS)) {
g_window_manager.ffm_mode = FFM_AUTOFOCUS;
} else if (token_equals(value, ARGUMENT_CONFIG_FFM_AUTORAISE)) {
Expand Down
113 changes: 113 additions & 0 deletions src/osax/payload.m
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,9 @@
#define kCGSOnAllWorkspacesTagBit (1 << 11)
#define kCGSNoShadowTagBit (1 << 3)

#define CONNECTION_CALLBACK(name) void name(uint32_t type, void *data, size_t data_length, void *context, int cid)
typedef CONNECTION_CALLBACK(connection_callback);

extern int CGSMainConnectionID(void);
extern CGError CGSGetConnectionPSN(int cid, ProcessSerialNumber *psn);
extern CGError CGSSetWindowAlpha(int cid, uint32_t wid, float alpha);
Expand All @@ -59,6 +62,11 @@
extern CFStringRef CGSCopyManagedDisplayForSpace(const int cid, uint64_t spid);
extern void CGSShowSpaces(int cid, CFArrayRef spaces);
extern void CGSHideSpaces(int cid, CFArrayRef spaces);
extern CFArrayRef CGSCopyWindowsWithOptionsAndTags(int cid, uint32_t owner, CFArrayRef spaces, uint32_t options, uint64_t *set_tags, uint64_t *clear_tags);
extern CFArrayRef CGSCopySpacesForWindows(int cid, int selector, CFArrayRef window_list);
extern CGError CGSOrderWindowList(int cid, const uint32_t *window_list, const int *window_order, const uint32_t *window_rel, int window_count);
extern CGError CGSRequestNotificationsForWindows(int cid, uint32_t *window_list, int window_count);
extern CGError CGSRegisterConnectionNotifyProc(int cid, connection_callback *handler, uint32_t event, void *context);

static int _connection;
static id dock_spaces;
Expand Down Expand Up @@ -430,6 +438,45 @@ static Token get_token(const char **message)
return token;
}

static inline CFArrayRef cfarray_of_cfnumbers(void *values, size_t size, int count, CFNumberType type)
{
CFNumberRef temp[count];

for (int i = 0; i < count; ++i) {
temp[i] = CFNumberCreate(NULL, type, ((char *)values) + (size * i));
}

CFArrayRef result = CFArrayCreate(NULL, (const void **)temp, count, &kCFTypeArrayCallBacks);

for (int i = 0; i < count; ++i) {
CFRelease(temp[i]);
}

return result;
}

static uint64_t window_space(uint32_t wid)
{
uint64_t sid = 0;

CFArrayRef window_list_ref = cfarray_of_cfnumbers(&wid, sizeof(uint32_t), 1, kCFNumberSInt32Type);
CFArrayRef space_list_ref = CGSCopySpacesForWindows(_connection, 0x7, window_list_ref);
if (!space_list_ref) goto err;

int count = CFArrayGetCount(space_list_ref);
if (!count) goto free;

CFNumberRef id_ref = CFArrayGetValueAtIndex(space_list_ref, 0);
CFNumberGetValue(id_ref, CFNumberGetType(id_ref), &sid);

free:
CFRelease(space_list_ref);
err:
CFRelease(window_list_ref);

return sid;
}

static inline id get_ivar_value(id instance, const char *name)
{
id result = nil;
Expand Down Expand Up @@ -739,6 +786,69 @@ static void do_window_focus(const char *message)
((focus_window_call) set_front_window_fp)(window_psn, window_id);
}

static volatile bool g_sloppy_focus_spin = false;
static CONNECTION_CALLBACK(connection_handler)
{
g_sloppy_focus_spin = false;
}

static void do_window_sloppy_focus(const char *message)
{
if (set_front_window_fp == 0) return;

int window_connection;
ProcessSerialNumber window_psn;

Token wid_token = get_token(&message);
uint32_t window_id = token_to_uint32t(wid_token);

uint64_t set_tags = 0;
uint64_t clear_tags = 0;
uint32_t options = 0x2;
uint64_t window_sid = window_space(window_id);

CFArrayRef space_list_ref = cfarray_of_cfnumbers(&window_sid, sizeof(uint64_t), 1, kCFNumberSInt64Type);
CFArrayRef window_list_ref = CGSCopyWindowsWithOptionsAndTags(_connection, 0, space_list_ref, options, &set_tags, &clear_tags);
CFRelease(space_list_ref);

if (window_list_ref) {
g_sloppy_focus_spin = true;
CGSRequestNotificationsForWindows(_connection, &window_id, 1);

int window_list_count = CFArrayGetCount(window_list_ref);
int window_count = 0;

uint32_t window_list[window_list_count];
uint32_t window_rel[window_list_count];
int window_order[window_list_count];

for (int i = 0; i < window_list_count && i < 128; ++i) {
uint32_t value = 0;
CFNumberRef id_ref = CFArrayGetValueAtIndex(window_list_ref, i);
CFNumberGetValue(id_ref, CFNumberGetType(id_ref), &value);

if (value != window_id) {
window_list[window_count] = value;
window_rel[window_count] = window_id;
window_order[window_count] = 1;
++window_count;
} else {
break;
}
}

CGSGetWindowOwner(_connection, window_id, &window_connection);
CGSGetConnectionPSN(window_connection, &window_psn);
((focus_window_call) set_front_window_fp)(window_psn, window_id);

for (;;) { if (!g_sloppy_focus_spin) break; }

CGSOrderWindowList(_connection, window_list, window_order, window_rel, window_count);
CGSRequestNotificationsForWindows(_connection, &window_id, 0);
CFRelease(window_list_ref);
}
}

static void do_window_shadow(const char *message)
{
Token wid_token = get_token(&message);
Expand Down Expand Up @@ -806,6 +916,8 @@ static void handle_message(int sockfd, const char *message)
do_window_sticky(message);
} else if (token_equals(token, "window_focus")) {
do_window_focus(message);
} else if (token_equals(token, "window_sloppy_focus")) {
do_window_sloppy_focus(message);
} else if (token_equals(token, "window_shadow")) {
do_window_shadow(message);
}
Expand Down Expand Up @@ -862,6 +974,7 @@ static bool start_daemon(char *socket_path)
}

init_instances();
CGSRegisterConnectionNotifyProc(_connection, connection_handler, 808, NULL);
pthread_create(&daemon_thread, NULL, &handle_connection, NULL);

return true;
Expand Down
1 change: 1 addition & 0 deletions src/sa.h
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ bool scripting_addition_set_layer(uint32_t wid, int layer);
bool scripting_addition_set_sticky(uint32_t wid, bool sticky);
bool scripting_addition_set_shadow(uint32_t wid, bool shadow);
bool scripting_addition_focus_window(uint32_t wid);
bool scripting_addition_sloppy_focus_window(uint32_t wid);
bool scripting_addition_scale_window(uint32_t wid, float x, float y, float w, float h);

extern bool workspace_is_macos_monterey(void);
Expand Down
7 changes: 7 additions & 0 deletions src/sa.m
Original file line number Diff line number Diff line change
Expand Up @@ -630,6 +630,13 @@ bool scripting_addition_focus_window(uint32_t wid)
return scripting_addition_run_command(message);
}

bool scripting_addition_sloppy_focus_window(uint32_t wid)
{
char message[MAXLEN];
snprintf(message, sizeof(message), "window_sloppy_focus %d", wid);
return scripting_addition_run_command(message);
}

bool scripting_addition_scale_window(uint32_t wid, float x, float y, float w, float h)
{
char message[MAXLEN];
Expand Down
7 changes: 6 additions & 1 deletion src/window_manager.c
Original file line number Diff line number Diff line change
Expand Up @@ -842,7 +842,7 @@ static void window_manager_make_key_window(ProcessSerialNumber *window_psn, uint
SLPSPostEventRecordTo(window_psn, bytes2);
}

void window_manager_focus_window_without_raise(ProcessSerialNumber *window_psn, uint32_t window_id)
void window_manager_focus_window_without_raise_sip_friendly(ProcessSerialNumber *window_psn, uint32_t window_id)
{
if (psn_equals(window_psn, &g_window_manager.focused_window_psn)) {
uint8_t bytes1[0xf8] = { [0x04] = 0xf8, [0x08] = 0x0d, [0x8a] = 0x02 };
Expand All @@ -864,6 +864,11 @@ void window_manager_focus_window_without_raise(ProcessSerialNumber *window_psn,
window_manager_make_key_window(window_psn, window_id);
}

void window_manager_focus_window_without_raise(uint32_t window_id)
{
scripting_addition_sloppy_focus_window(window_id);
}

void window_manager_focus_window_with_raise(ProcessSerialNumber *window_psn, uint32_t window_id, AXUIElementRef window_ref)
{
#if 1
Expand Down
5 changes: 4 additions & 1 deletion src/window_manager.h
Original file line number Diff line number Diff line change
Expand Up @@ -40,13 +40,15 @@ static const char *purify_mode_str[] =
enum ffm_mode
{
FFM_DISABLED,
FFM_AUTOFOCUS_SIP,
FFM_AUTOFOCUS,
FFM_AUTORAISE
};

static const char *ffm_mode_str[] =
{
"disabled",
"autofocus_sip_friendly",
"autofocus",
"autoraise"
};
Expand Down Expand Up @@ -125,7 +127,8 @@ struct window *window_manager_find_last_window_in_stack(struct space_manager *sm
struct window *window_manager_find_recent_window_in_stack(struct space_manager *sm, struct window_manager *wm, struct window *window);
struct window *window_manager_find_largest_managed_window(struct space_manager *sm, struct window_manager *wm);
struct window *window_manager_find_smallest_managed_window(struct space_manager *sm, struct window_manager *wm);
void window_manager_focus_window_without_raise(ProcessSerialNumber *window_psn, uint32_t window_id);
void window_manager_focus_window_without_raise_sip_friendly(ProcessSerialNumber *window_psn, uint32_t window_id);
void window_manager_focus_window_without_raise(uint32_t window_id);
void window_manager_focus_window_with_raise(ProcessSerialNumber *window_psn, uint32_t window_id, AXUIElementRef window_ref);
struct window *window_manager_focused_window(struct window_manager *wm);
struct application *window_manager_focused_application(struct window_manager *wm);
Expand Down

0 comments on commit 7e9b09b

Please sign in to comment.