Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
40 changes: 40 additions & 0 deletions src/message.c
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,7 @@ extern bool g_verbose;
#define COMMAND_CONFIG_MOUSE_ACTION2 "mouse_action2"
#define COMMAND_CONFIG_MOUSE_DROP_ACTION "mouse_drop_action"
#define COMMAND_CONFIG_EXTERNAL_BAR "external_bar"
#define COMMAND_CONFIG_GRID_COLUMNS "grid_columns"

#define SELECTOR_CONFIG_SPACE "--space"

Expand Down Expand Up @@ -823,6 +824,20 @@ static struct selector parse_space_selector(FILE *rsp, char **message, uint64_t
} else {
daemon_fail(rsp, "could not locate the selected space.\n");
}
} else if (token_equals(result.token, ARGUMENT_COMMON_SEL_NORTH)
|| token_equals(result.token, ARGUMENT_COMMON_SEL_EAST)
|| token_equals(result.token, ARGUMENT_COMMON_SEL_SOUTH)
|| token_equals(result.token, ARGUMENT_COMMON_SEL_WEST)) {
if (acting_sid) {
uint64_t sid = space_manager_grid_space(acting_sid, result.token.text);
if (sid) {
result.sid = sid;
} else {
daemon_fail(rsp, "could not locate the %s space.\n", result.token.text);
}
} else {
daemon_fail(rsp, "could not locate the selected space.\n");
}
} else if (token_equals(result.token, ARGUMENT_COMMON_SEL_FIRST)) {
uint64_t sid = space_manager_first_space();
if (sid) {
Expand Down Expand Up @@ -1679,6 +1694,31 @@ static void handle_domain_config(FILE *rsp, struct token domain, char *message)
} else {
fprintf(rsp, "%s:%d:%d\n", external_bar_mode_str[g_display_manager.mode], g_display_manager.top_padding, g_display_manager.bottom_padding);
}
} else if (token_equals(command, COMMAND_CONFIG_GRID_COLUMNS)) {
struct token value = get_token(&message);
if (!token_is_valid(value)) {
if (NULL != g_space_manager.grid_columns) {
int count = CFArrayGetCount(g_space_manager.grid_columns);
for (int i = 0; i < count; ++i) {
if (i > 0) {
fprintf(rsp, ",");
}
fprintf(rsp, "%d", CFStringGetIntValue(CFArrayGetValueAtIndex(g_space_manager.grid_columns, i)));
}
fprintf(rsp, "\n");
}
} else {
if (NULL != g_space_manager.grid_columns) {
CFRelease(g_space_manager.grid_columns);
}

CFStringRef list = CFStringCreateWithCString(NULL, value.text, kCFStringEncodingUTF8);
CFStringRef separator = CFSTR(",");
// TODO Convert to int list.
g_space_manager.grid_columns = CFStringCreateArrayBySeparatingStrings(NULL, list, separator);
CFRelease(separator);
CFRelease(list);
}
} else {
daemon_fail(rsp, "unknown command '%.*s' for domain '%.*s'\n", command.length, command.text, domain.length, domain.text);
}
Expand Down
61 changes: 61 additions & 0 deletions src/space_manager.c
Original file line number Diff line number Diff line change
Expand Up @@ -608,6 +608,65 @@ uint64_t space_manager_next_space(uint64_t sid)
return n_sid != sid ? n_sid : 0;
}

uint64_t space_manager_grid_space(uint64_t sid, char *direction)
{
uint64_t n_sid = 0;

CFArrayRef display_spaces_ref = SLSCopyManagedDisplaySpaces(g_connection);
int display_spaces_count = CFArrayGetCount(display_spaces_ref);

for (int i = 0; i < display_spaces_count; ++i) {
CFDictionaryRef display_ref = CFArrayGetValueAtIndex(display_spaces_ref, i);
CFArrayRef spaces_ref = CFDictionaryGetValue(display_ref, CFSTR("Spaces"));
uint64_t spaces_count = CFArrayGetCount(spaces_ref);

uint64_t grid_columns = INT_MAX;
if (NULL != g_space_manager.grid_columns
&& i < CFArrayGetCount(g_space_manager.grid_columns)) {
int value = CFStringGetIntValue(CFArrayGetValueAtIndex(g_space_manager.grid_columns, i));
if (value > 0) {
grid_columns = value;
}
}

for (uint64_t j = 0; j < spaces_count; ++j) {
CFDictionaryRef space_ref = CFArrayGetValueAtIndex(spaces_ref, j);
CFNumberRef sid_ref = CFDictionaryGetValue(space_ref, CFSTR("id64"));
CFNumberGetValue(sid_ref, CFNumberGetType(sid_ref), &n_sid);
if (n_sid == sid) {
uint64_t target_space_index = j;
uint64_t focused_column = j%grid_columns;

if (string_equals(direction, ARGUMENT_COMMON_SEL_NORTH)) {
target_space_index -= grid_columns;
} else if (string_equals(direction, ARGUMENT_COMMON_SEL_EAST)) {
if (focused_column < grid_columns - 1) {
target_space_index += 1;
}
} else if (string_equals(direction, ARGUMENT_COMMON_SEL_SOUTH)) {
target_space_index += grid_columns;
} else if (string_equals(direction, ARGUMENT_COMMON_SEL_WEST)) {
if (0 < focused_column) {
target_space_index -= 1;
}
}

if (0 <= target_space_index && target_space_index < spaces_count) {
CFDictionaryRef target_space_ref = CFArrayGetValueAtIndex(spaces_ref, target_space_index);
CFNumberRef target_space_id_ref = CFDictionaryGetValue(target_space_ref, CFSTR("id64"));
CFNumberGetValue(target_space_id_ref, CFNumberGetType(target_space_id_ref), &n_sid);
}

goto out;
}
}
}

out:
CFRelease(display_spaces_ref);
return n_sid != sid ? n_sid : 0;
}

uint64_t space_manager_first_space(void)
{
uint64_t sid = 0;
Expand Down Expand Up @@ -1132,6 +1191,8 @@ void space_manager_begin(struct space_manager *sm)
uint32_t *display_list = display_manager_active_display_list(&display_count);
if (!display_list) return;

sm->grid_columns = NULL;

for (int i = 0; i < display_count; ++i) {
int space_count;
uint64_t *space_list = display_space_list(display_list[i], &space_count);
Expand Down
2 changes: 2 additions & 0 deletions src/space_manager.h
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ struct space_manager
bool window_zoom_persist;
uint32_t auto_balance;
struct space_label *labels;
CFArrayRef grid_columns;
};

enum space_op_error
Expand Down Expand Up @@ -63,6 +64,7 @@ uint64_t space_manager_mission_control_space(int desktop_id);
uint64_t space_manager_cursor_space(void);
uint64_t space_manager_prev_space(uint64_t sid);
uint64_t space_manager_next_space(uint64_t sid);
uint64_t space_manager_grid_space(uint64_t sid, char *direction);
uint64_t space_manager_first_space(void);
uint64_t space_manager_last_space(void);
uint64_t space_manager_active_space(void);
Expand Down
30 changes: 30 additions & 0 deletions wiki/grid-spaces.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
# yabai grid spaces

Grid space navigation (like [TotalSpaces2](https://totalspaces.binaryage.com/)) in
[yabai](https://github.com/koekeishiya/yabai).

## Installation

Install <https://github.com/mikkelricky/yabai/tree/grid-spaces> by running

```shell
brew install --HEAD mikkelricky/formulae/myabai
```

## Configuration

```shell
# Navigate a grid with 3 columns.
yabai --message config grid_columns 3
```

![grid spaces](./images/yabai-grid_columns.svg)

## Usage

```shell
yabai --message space --focus north
yabai --message space --focus east
yabai --message space --focus south
yabai --message space --focus west
```
295 changes: 295 additions & 0 deletions wiki/images/yabai-grid_columns.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.