Skip to content

Commit

Permalink
#550 config to change how yabai should interpret display arrangement …
Browse files Browse the repository at this point in the history
…indices
  • Loading branch information
koekeishiya committed Mar 12, 2024
1 parent 56a8fcd commit e02addf
Show file tree
Hide file tree
Showing 13 changed files with 136 additions and 46 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ This project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.htm
- Added new command `config window_animation_easing ..` to select easing function [#2131](https://github.com/koekeishiya/yabai/issues/2131)
- Added new command `space --equalize .. ` to reset split ratios of all nodes within a space to default value [#2133](https://github.com/koekeishiya/yabai/issues/2133)
- Added new command `space --switch ..` to focus a space (substitute with current focus) regardless of its display [#549](https://github.com/koekeishiya/yabai/issues/549)
- Added new command `config display_arrangement_order ..` to change yabai interprets arrangement indexes used to select displays [#550](https://github.com/koekeishiya/yabai/issues/550)

### Changed
- Preserve relative space ordering when moving spaces to other displays [#2114](https://github.com/koekeishiya/yabai/issues/2114)
Expand Down
15 changes: 13 additions & 2 deletions doc/yabai.1
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,12 @@
.\" Title: yabai
.\" Author: [see the "AUTHOR(S)" section]
.\" Generator: Asciidoctor 2.0.20
.\" Date: 2024-03-11
.\" Date: 2024-03-12
.\" Manual: Yabai Manual
.\" Source: Yabai
.\" Language: English
.\"
.TH "YABAI" "1" "2024-03-11" "Yabai" "Yabai Manual"
.TH "YABAI" "1" "2024-03-12" "Yabai" "Yabai Manual"
.ie \n(.g .ds Aq \(aq
.el .ds Aq '
.ss \n[.ss] 0
Expand Down Expand Up @@ -202,6 +202,17 @@ When focusing a window, put the mouse at its center.
Automatically focus the window under the mouse.
.RE
.sp
\fBdisplay_arrangement_order\fP [\fIdefault|vertical|horizontal\fP]
.RS 4
Specify how displays are ordered (determined by center point).
.br
\fIdefault\fP: Native macOS ordering.
.br
\fIvertical\fP: Order by y\-coordinate (followed by x\-coordinate when equal).
.br
\fIhorizontal\fP: Order by x\-coordinate (followed by y\-coordinate when equal).
.RE
.sp
\fBwindow_origin_display\fP [\fIdefault|focused|cursor\fP]
.RS 4
Specify which display a newly created window should be managed in.
Expand Down
6 changes: 6 additions & 0 deletions doc/yabai.asciidoc
Original file line number Diff line number Diff line change
Expand Up @@ -152,6 +152,12 @@ Global Settings
*focus_follows_mouse* ['autofocus|autoraise|off']::
Automatically focus the window under the mouse.

*display_arrangement_order* ['default|vertical|horizontal']::
Specify how displays are ordered (determined by center point). +
'default': Native macOS ordering. +
'vertical': Order by y-coordinate (followed by x-coordinate when equal). +
'horizontal': Order by x-coordinate (followed by y-coordinate when equal).

*window_origin_display* ['default|focused|cursor']::
Specify which display a newly created window should be managed in. +
'default': The display in which the window is created (standard macOS behaviour). +
Expand Down
1 change: 1 addition & 0 deletions examples/yabairc
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ yabai -m config \
menubar_opacity 1.0 \
mouse_follows_focus off \
focus_follows_mouse off \
display_arrangement_order default \
window_origin_display default \
window_placement second_child \
window_zoom_persist on \
Expand Down
27 changes: 1 addition & 26 deletions src/display.c
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,7 @@ void display_serialize(FILE *rsp, uint32_t did)
"}",
did,
uuid ? uuid : "<unknown>",
display_arrangement(did),
display_manager_display_id_arrangement(did),
frame.origin.x, frame.origin.y, frame.size.width, frame.size.height,
buffer);
}
Expand Down Expand Up @@ -214,28 +214,3 @@ uint64_t *display_space_list(uint32_t did, int *count)
out:
return space_list;
}

int display_arrangement(uint32_t did)
{
int result = 0;

CFStringRef uuid = display_uuid(did);
if (!uuid) goto out;

CFArrayRef displays = SLSCopyManagedDisplays(g_connection);
if (!displays) goto err;

int displays_count = CFArrayGetCount(displays);
for (int i = 0; i < displays_count; ++i) {
if (CFEqual(CFArrayGetValueAtIndex(displays, i), uuid)) {
result = i + 1;
break;
}
}

CFRelease(displays);
err:
CFRelease(uuid);
out:
return result;
}
1 change: 0 additions & 1 deletion src/display.h
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,5 @@ CGPoint display_center(uint32_t did);
uint64_t display_space_id(uint32_t did);
int display_space_count(uint32_t did);
uint64_t *display_space_list(uint32_t did, int *count);
int display_arrangement(uint32_t did);

#endif
83 changes: 73 additions & 10 deletions src/display_manager.c
Original file line number Diff line number Diff line change
Expand Up @@ -80,38 +80,100 @@ uint32_t display_manager_point_display_id(CGPoint point)
return result;
}

CFStringRef display_manager_arrangement_display_uuid(int arrangement)
static CFComparisonResult display_manager_coordinate_comparator(CFTypeRef a, CFTypeRef b, void *context)
{
CFStringRef result = NULL;
enum display_arrangement_order axis = (enum display_arrangement_order)(uintptr_t) context;
if (axis == DISPLAY_ARRANGEMENT_ORDER_DEFAULT) goto out;

uint32_t a_did = display_id(a);
uint32_t b_did = display_id(b);

CGPoint a_center = display_center(a_did);
CGPoint b_center = display_center(b_did);

float a_coord = axis == DISPLAY_ARRANGEMENT_ORDER_Y ? a_center.y : a_center.x;
float b_coord = axis == DISPLAY_ARRANGEMENT_ORDER_Y ? b_center.y : b_center.x;

if (a_coord < b_coord) return kCFCompareLessThan;
if (a_coord > b_coord) return kCFCompareGreaterThan;

a_coord = axis == DISPLAY_ARRANGEMENT_ORDER_Y ? a_center.x : a_center.y;
b_coord = axis == DISPLAY_ARRANGEMENT_ORDER_Y ? b_center.x : b_center.y;

if (a_coord < b_coord) return kCFCompareLessThan;
if (a_coord > b_coord) return kCFCompareGreaterThan;

out:
return kCFCompareEqualTo;
}

int display_manager_display_id_arrangement(uint32_t did)
{
int result = 0;

CFStringRef uuid = display_uuid(did);
if (!uuid) goto out;

CFArrayRef displays = SLSCopyManagedDisplays(g_connection);
if (!displays) goto err;

int count = CFArrayGetCount(displays);
int index = arrangement - 1;
if (!count) goto empty;

if (in_range_ie(index, 0, count)) {
result = CFRetain(CFArrayGetValueAtIndex(displays, index));
if (g_display_manager.order != DISPLAY_ARRANGEMENT_ORDER_DEFAULT) {
CFMutableArrayRef mut_displays = CFArrayCreateMutableCopy(NULL, count, displays);
CFArraySortValues(mut_displays, CFRangeMake(0, count), &display_manager_coordinate_comparator, (void *)(uintptr_t) g_display_manager.order);
CFRelease(displays); displays = mut_displays;
}

for (int i = 0; i < count; ++i) {
if (CFEqual(CFArrayGetValueAtIndex(displays, i), uuid)) {
result = i + 1;
break;
}
}

empty:
CFRelease(displays);
err:
CFRelease(uuid);
out:
return result;
}

uint32_t display_manager_arrangement_display_id(int arrangement)
CFStringRef display_manager_arrangement_display_uuid(int arrangement)
{
uint32_t result = 0;
CFStringRef result = NULL;
CFArrayRef displays = SLSCopyManagedDisplays(g_connection);

int count = CFArrayGetCount(displays);
int index = arrangement - 1;

if (in_range_ie(index, 0, count)) {
result = display_id(CFArrayGetValueAtIndex(displays, index));
if (g_display_manager.order != DISPLAY_ARRANGEMENT_ORDER_DEFAULT) {
CFMutableArrayRef mut_displays = CFArrayCreateMutableCopy(NULL, count, displays);
CFArraySortValues(mut_displays, CFRangeMake(0, count), &display_manager_coordinate_comparator, (void *)(uintptr_t) g_display_manager.order);
CFRelease(displays); displays = mut_displays;
}

result = CFRetain(CFArrayGetValueAtIndex(displays, index));
}

CFRelease(displays);
return result;
}

uint32_t display_manager_arrangement_display_id(int arrangement)
{
CFStringRef uuid = display_manager_arrangement_display_uuid(arrangement);
if (!uuid) return 0;

uint32_t result = display_id(uuid);
CFRelease(uuid);

return result;
}

uint32_t display_manager_cursor_display_id(void)
{
CGPoint cursor;
Expand All @@ -121,15 +183,15 @@ uint32_t display_manager_cursor_display_id(void)

uint32_t display_manager_prev_display_id(uint32_t did)
{
int arrangement = display_arrangement(did);
int arrangement = display_manager_display_id_arrangement(did);
if (arrangement <= 1) return 0;

return display_manager_arrangement_display_id(arrangement - 1);
}

uint32_t display_manager_next_display_id(uint32_t did)
{
int arrangement = display_arrangement(did);
int arrangement = display_manager_display_id_arrangement(did);
if (arrangement >= display_manager_active_display_count()) return 0;

return display_manager_arrangement_display_id(arrangement + 1);
Expand Down Expand Up @@ -350,6 +412,7 @@ bool display_manager_begin(struct display_manager *dm)
{
dm->current_display_id = display_manager_active_display_id();
dm->last_display_id = dm->current_display_id;
dm->order = DISPLAY_ARRANGEMENT_ORDER_DEFAULT;
dm->mode = EXTERNAL_BAR_OFF;
dm->top_padding = 0;
dm->bottom_padding = 0;
Expand Down
17 changes: 17 additions & 0 deletions src/display_manager.h
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,20 @@
#define DOCK_ORIENTATION_LEFT 3
#define DOCK_ORIENTATION_RIGHT 4

enum display_arrangement_order
{
DISPLAY_ARRANGEMENT_ORDER_DEFAULT,
DISPLAY_ARRANGEMENT_ORDER_X,
DISPLAY_ARRANGEMENT_ORDER_Y
};

static const char *display_arrangement_order_str[] =
{
"default",
"horizontal",
"vertical"
};

enum external_bar_mode
{
EXTERNAL_BAR_OFF,
Expand All @@ -26,6 +40,8 @@ struct display_manager

int top_padding;
int bottom_padding;

enum display_arrangement_order order;
enum external_bar_mode mode;
};

Expand All @@ -39,6 +55,7 @@ uint32_t display_manager_dock_display_id(void);
CFStringRef display_manager_point_display_uuid(CGPoint point);
uint32_t display_manager_point_display_id(CGPoint point);
uint32_t display_manager_cursor_display_id(void);
int display_manager_display_id_arrangement(uint32_t did);
CFStringRef display_manager_arrangement_display_uuid(int arrangement);
uint32_t display_manager_arrangement_display_id(int arrangement);
uint32_t display_manager_prev_display_id(uint32_t did);
Expand Down
6 changes: 3 additions & 3 deletions src/event_signal.c
Original file line number Diff line number Diff line change
Expand Up @@ -279,7 +279,7 @@ void event_signal_push(enum signal_type type, void *context)
case SIGNAL_DISPLAY_MOVED:
case SIGNAL_DISPLAY_RESIZED: {
uint32_t did = (uint32_t)(uintptr_t) context;
int index = display_arrangement(did);
int index = display_manager_display_id_arrangement(did);

es->arg_name[0] = ts_alloc_unaligned(arg_size);
es->arg_value[0] = ts_alloc_unaligned(arg_size);
Expand All @@ -304,8 +304,8 @@ void event_signal_push(enum signal_type type, void *context)
uint32_t did = g_display_manager.current_display_id;
uint32_t recent_did = g_display_manager.last_display_id;

int index = display_arrangement(did);
int recent_index = display_arrangement(recent_did);
int index = display_manager_display_id_arrangement(did);
int recent_index = display_manager_display_id_arrangement(recent_did);

es->arg_name[0] = ts_alloc_unaligned(arg_size);
es->arg_value[0] = ts_alloc_unaligned(arg_size);
Expand Down
17 changes: 17 additions & 0 deletions src/message.c
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ extern bool g_verbose;
#define COMMAND_CONFIG_DEBUG_OUTPUT "debug_output"
#define COMMAND_CONFIG_MFF "mouse_follows_focus"
#define COMMAND_CONFIG_FFM "focus_follows_mouse"
#define COMMAND_CONFIG_DISPLAY_ORDER "display_arrangement_order"
#define COMMAND_CONFIG_WINDOW_ORIGIN "window_origin_display"
#define COMMAND_CONFIG_WINDOW_PLACEMENT "window_placement"
#define COMMAND_CONFIG_WINDOW_ZOOM_PERSIST "window_zoom_persist"
Expand Down Expand Up @@ -54,6 +55,9 @@ extern bool g_verbose;

#define ARGUMENT_CONFIG_FFM_AUTOFOCUS "autofocus"
#define ARGUMENT_CONFIG_FFM_AUTORAISE "autoraise"
#define ARGUMENT_CONFIG_DISPLAY_ORDER_DEFAULT "default"
#define ARGUMENT_CONFIG_DISPLAY_ORDER_X "horizontal"
#define ARGUMENT_CONFIG_DISPLAY_ORDER_Y "vertical"
#define ARGUMENT_CONFIG_WINDOW_ORIGIN_DEFAULT "default"
#define ARGUMENT_CONFIG_WINDOW_ORIGIN_FOCUSED "focused"
#define ARGUMENT_CONFIG_WINDOW_ORIGIN_CURSOR "cursor"
Expand Down Expand Up @@ -1079,6 +1083,19 @@ static void handle_domain_config(FILE *rsp, struct token domain, char *message)
} else {
daemon_fail(rsp, "unknown value '%.*s' given to command '%.*s' for domain '%.*s'\n", value.length, value.text, command.length, command.text, domain.length, domain.text);
}
} else if (token_equals(command, COMMAND_CONFIG_DISPLAY_ORDER)) {
struct token value = get_token(&message);
if (!token_is_valid(value)) {
fprintf(rsp, "%s\n", display_arrangement_order_str[g_display_manager.order]);
} else if (token_equals(value, ARGUMENT_CONFIG_DISPLAY_ORDER_DEFAULT)) {
g_display_manager.order = DISPLAY_ARRANGEMENT_ORDER_DEFAULT;
} else if (token_equals(value, ARGUMENT_CONFIG_DISPLAY_ORDER_X)) {
g_display_manager.order = DISPLAY_ARRANGEMENT_ORDER_X;
} else if (token_equals(value, ARGUMENT_CONFIG_DISPLAY_ORDER_Y)) {
g_display_manager.order = DISPLAY_ARRANGEMENT_ORDER_Y;
} else {
daemon_fail(rsp, "unknown value '%.*s' given to command '%.*s' for domain '%.*s'\n", value.length, value.text, command.length, command.text, domain.length, domain.text);
}
} else if (token_equals(command, COMMAND_CONFIG_WINDOW_ORIGIN)) {
struct token value = get_token(&message);
if (!token_is_valid(value)) {
Expand Down
2 changes: 1 addition & 1 deletion src/rule.c
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ void rule_serialize(FILE *rsp, struct rule *rule, int index)
rule->title ? rule->title : "",
rule->role ? rule->role : "",
rule->subrole ? rule->subrole : "",
display_arrangement(rule->effects.did),
display_manager_display_id_arrangement(rule->effects.did),
space_manager_mission_control_index(rule->effects.sid),
json_bool(rule_effects_check_flag(&rule->effects, RULE_FOLLOW_SPACE)),
rule->effects.opacity,
Expand Down
2 changes: 1 addition & 1 deletion src/view.c
Original file line number Diff line number Diff line change
Expand Up @@ -875,7 +875,7 @@ void view_serialize(FILE *rsp, struct view *view)
space_manager_mission_control_index(view->sid),
space_label ? space_label->label : "",
view_type_str[view->layout],
display_arrangement(space_display_id(view->sid)),
display_manager_display_id_arrangement(space_display_id(view->sid)),
buffer,
first_leaf ? first_leaf->window_order[0] : 0,
last_leaf ? last_leaf->window_order[0] : 0,
Expand Down
4 changes: 2 additions & 2 deletions src/window.c
Original file line number Diff line number Diff line change
Expand Up @@ -161,7 +161,7 @@ void window_nonax_serialize(FILE *rsp, uint32_t wid)
bool is_sticky = window_space_count(wid) > 1;

int space = space_manager_mission_control_index(sid);
int display = display_arrangement(space_display_id(sid));
int display = display_manager_display_id_arrangement(space_display_id(sid));
int level = window_level(wid);
int sub_level = window_sub_level(wid);
const char *layer = window_layer(level);
Expand Down Expand Up @@ -249,7 +249,7 @@ void window_serialize(FILE *rsp, struct window *window)
char *escaped_title = ts_string_escape(title);
uint64_t sid = window_space(window->id);
int space = space_manager_mission_control_index(sid);
int display = display_arrangement(space_display_id(sid));
int display = display_manager_display_id_arrangement(space_display_id(sid));
int level = window_level(window->id);
int sub_level = window_sub_level(window->id);
const char *layer = window_layer(level);
Expand Down

0 comments on commit e02addf

Please sign in to comment.