Skip to content

Commit

Permalink
implement display_sort_order config option
Browse files Browse the repository at this point in the history
none, horizontal, or vertical
  • Loading branch information
http://jneen.net/ committed Jun 9, 2020
1 parent fb70465 commit 4a31138
Show file tree
Hide file tree
Showing 6 changed files with 134 additions and 12 deletions.
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.10
.\" Date: 2020-06-06
.\" Date: 2020-06-08
.\" Manual: Yabai Manual
.\" Source: Yabai
.\" Language: English
.\"
.TH "YABAI" "1" "2020-06-06" "Yabai" "Yabai Manual"
.TH "YABAI" "1" "2020-06-08" "Yabai" "Yabai Manual"
.ie \n(.g .ds Aq \(aq
.el .ds Aq '
.ss \n[.ss] 0
Expand Down Expand Up @@ -150,6 +150,17 @@ When focusing a window, put the mouse at its center.
Automatically focus the window under the mouse.
.RE
.sp
\fBdisplay_sort_order\fP [\fIhorizontal|vertical|none\fP]
.RS 4
Specify how displays are ordered.
.br
\fIhorizontal\fP|\fIvertical\fP: order by the display\(cqs relative position.
.br
\fInone\fP: (default) use the native ordering.
.br
The position of a display is determined by its center point.
.RE
.sp
\fBwindow_placement\fP [\fIfirst_child|second_child\fP]
.RS 4
Specify whether managed windows should become the first or second leaf\-node.
Expand Down
6 changes: 6 additions & 0 deletions doc/yabai.asciidoc
Original file line number Diff line number Diff line change
Expand Up @@ -121,6 +121,12 @@ Global Settings
*focus_follows_mouse* ['autofocus|autoraise|off']::
Automatically focus the window under the mouse.

*display_sort_order* ['horizontal|vertical|none']::
Specify how displays are ordered. +
'horizontal'|'vertical': order by the display's relative position. +
'none': (default) use the native ordering. +
The position of a display is determined by its center point.

*window_placement* ['first_child|second_child']::
Specify whether managed windows should become the first or second leaf-node.

Expand Down
15 changes: 15 additions & 0 deletions src/display.c
Original file line number Diff line number Diff line change
Expand Up @@ -136,6 +136,21 @@ CGRect display_bounds_constrained(uint32_t did)
return frame;
}

static inline float display_frame_center(enum display_sort_order axis, CFStringRef uuid_str) {
CFUUIDRef uuid_ref = CFUUIDCreateFromString(NULL, uuid_str);
uint32_t did = CGDisplayGetDisplayIDFromUUID(uuid_ref);
CGRect frame = CGDisplayBounds(did);

switch(axis) {
case DISPLAY_SORT_HORIZ: return frame.origin.x + (frame.size.width) / 2;
case DISPLAY_SORT_VERT: return frame.origin.y + (frame.size.height) / 2;

// should not get here, but if we do it'll just result in not sorting
// (considering every display to be "equal")
default: return 0.0;
}
}

CGPoint display_center(uint32_t did)
{
CGRect bounds = display_bounds(did);
Expand Down
77 changes: 67 additions & 10 deletions src/display_manager.c
Original file line number Diff line number Diff line change
Expand Up @@ -81,16 +81,73 @@ uint32_t display_manager_point_display_id(CGPoint point)
return result;
}

static inline enum display_sort_order rotate_axis(enum display_sort_order axis) {
switch(axis) {
case DISPLAY_SORT_NONE: return DISPLAY_SORT_NONE;
case DISPLAY_SORT_VERT: return DISPLAY_SORT_HORIZ;
case DISPLAY_SORT_HORIZ: return DISPLAY_SORT_VERT;
}
}

static inline float display_sort_lookup(CGPoint point, enum display_sort_order axis) {
switch(axis) {
case DISPLAY_SORT_NONE: return 0.0;
case DISPLAY_SORT_VERT: return point.y;
case DISPLAY_SORT_HORIZ: return point.x;
}
}

static enum CFComparisonResult coordinate_comparator(const void *a_p, const void *b_p, void *context_p) {
CFStringRef a = (CFStringRef) a_p;
CFStringRef b = (CFStringRef) b_p;
enum display_sort_order axis = *((enum display_sort_order *) context_p);

CFUUIDRef uuid_a = CFUUIDCreateFromString(NULL, a);
CFUUIDRef uuid_b = CFUUIDCreateFromString(NULL, b);

uint32_t did_a = CGDisplayGetDisplayIDFromUUID(uuid_a);
uint32_t did_b = CGDisplayGetDisplayIDFromUUID(uuid_b);

CGPoint center_a = display_center(did_a);
CGPoint center_b = display_center(did_b);

float coord_a, coord_b;

coord_a = display_sort_lookup(center_a, axis);
coord_b = display_sort_lookup(center_b, axis);
if (coord_a < coord_b) return kCFCompareLessThan;
if (coord_a > coord_b) return kCFCompareGreaterThan;

// if equal, fall back to the other axis
axis = rotate_axis(axis);

coord_a = display_sort_lookup(center_a, axis);
coord_b = display_sort_lookup(center_b, axis);
if (coord_a < coord_b) return kCFCompareLessThan;
if (coord_a > coord_b) return kCFCompareGreaterThan;

// the screens share a center point, so don't re-order them at all
return kCFCompareEqualTo;
}

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

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

if (in_range_ie(index, 0, count)) {
result = CFRetain(CFArrayGetValueAtIndex(displays, index));
if (g_display_manager.sort_order == DISPLAY_SORT_NONE) {
result = CFRetain(CFArrayGetValueAtIndex(displays, index));
} else {
// copy the array to a mutable one, then sort it in place
CFRange all = CFRangeMake((long) 0, (long) count);
CFMutableArrayRef mut_displays = CFArrayCreateMutableCopy(NULL, count, displays);
CFArraySortValues(mut_displays, all, &coordinate_comparator, NULL);
result = CFRetain(CFArrayGetValueAtIndex(mut_displays, index));
CFRelease(mut_displays);
}
}

CFRelease(displays);
Expand All @@ -100,16 +157,15 @@ CFStringRef display_manager_arrangement_display_uuid(int arrangement)
uint32_t display_manager_arrangement_display_id(int arrangement)
{
uint32_t result = 0;
CFArrayRef displays = SLSCopyManagedDisplays(g_connection);

int count = CFArrayGetCount(displays);
int index = arrangement - 1;
CFStringRef uuid = display_manager_arrangement_display_uuid(arrangement);
if (!uuid) return result;
CFUUIDRef uuid_ref = CFUUIDCreateFromString(NULL, uuid);
CFRelease(uuid);
if (!uuid_ref) return result;

if (in_range_ie(index, 0, count)) {
result = display_id(CFArrayGetValueAtIndex(displays, index));
}
result = CGDisplayGetDisplayIDFromUUID(uuid_ref);
CFRelease(uuid_ref);

CFRelease(displays);
return result;
}

Expand Down Expand Up @@ -328,6 +384,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->mode = EXTERNAL_BAR_OFF;
dm->sort_order = DISPLAY_SORT_NONE;
dm->top_padding = 0;
dm->bottom_padding = 0;
return CGDisplayRegisterReconfigurationCallback(display_handler, NULL) == kCGErrorSuccess;
Expand Down
16 changes: 16 additions & 0 deletions src/display_manager.h
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,20 @@ extern void CoreDockGetOrientationAndPinning(int *orientation, int *pinning);
#define DOCK_ORIENTATION_LEFT 3
#define DOCK_ORIENTATION_RIGHT 4

enum display_sort_order
{
DISPLAY_SORT_NONE,
DISPLAY_SORT_HORIZ,
DISPLAY_SORT_VERT
};

static const char *display_sort_order_str[] =
{
"none",
"horizontal",
"vertical"
};

enum external_bar_mode
{
EXTERNAL_BAR_OFF,
Expand All @@ -33,6 +47,8 @@ struct display_manager
uint32_t current_display_id;
uint32_t last_display_id;

enum display_sort_order sort_order;

int top_padding;
int bottom_padding;
enum external_bar_mode mode;
Expand Down
17 changes: 17 additions & 0 deletions src/message.c
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ extern bool g_verbose;
#define COMMAND_CONFIG_MFF "mouse_follows_focus"
#define COMMAND_CONFIG_FFM "focus_follows_mouse"
#define COMMAND_CONFIG_WINDOW_PLACEMENT "window_placement"
#define COMMAND_CONFIG_DISPLAY_SORT "display_sort_order"
#define COMMAND_CONFIG_TOPMOST "window_topmost"
#define COMMAND_CONFIG_OPACITY "window_opacity"
#define COMMAND_CONFIG_OPACITY_DURATION "window_opacity_duration"
Expand All @@ -45,6 +46,9 @@ extern bool g_verbose;

#define ARGUMENT_CONFIG_FFM_AUTOFOCUS "autofocus"
#define ARGUMENT_CONFIG_FFM_AUTORAISE "autoraise"
#define ARGUMENT_CONFIG_DISPLAY_SORT_NONE "none"
#define ARGUMENT_CONFIG_DISPLAY_SORT_HORIZ "horizontal"
#define ARGUMENT_CONFIG_DISPLAY_SORT_VERT "vertical"
#define ARGUMENT_CONFIG_WINDOW_PLACEMENT_FST "first_child"
#define ARGUMENT_CONFIG_WINDOW_PLACEMENT_SND "second_child"
#define ARGUMENT_CONFIG_SHADOW_FLT "float"
Expand Down Expand Up @@ -390,6 +394,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_SORT)) {
struct token value = get_token(&message);
if (!token_is_valid(value)) {
fprintf(rsp, "%s\n", display_sort_order_str[g_display_manager.sort_order]);
} else if (token_equals(value, ARGUMENT_CONFIG_DISPLAY_SORT_NONE)) {
g_display_manager.sort_order = DISPLAY_SORT_NONE;
} else if (token_equals(value, ARGUMENT_CONFIG_DISPLAY_SORT_HORIZ)) {
g_display_manager.sort_order = DISPLAY_SORT_HORIZ;
} else if (token_equals(value, ARGUMENT_CONFIG_DISPLAY_SORT_VERT)) {
g_display_manager.sort_order = DISPLAY_SORT_VERT;
} 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_PLACEMENT)) {
struct token value = get_token(&message);
if (!token_is_valid(value)) {
Expand Down

0 comments on commit 4a31138

Please sign in to comment.