Skip to content

Commit

Permalink
#379 ability to (de)minimize windows, and report current state throug…
Browse files Browse the repository at this point in the history
…h window queries
  • Loading branch information
koekeishiya committed Apr 20, 2020
1 parent 9153736 commit e6781b5
Show file tree
Hide file tree
Showing 12 changed files with 108 additions and 31 deletions.
2 changes: 2 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,8 @@ All notable changes to this project will be documented in this file.
This project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).

## [Unreleased]
### Added
- New window commands `--minimize` and `--deminimize`. Minimized windows are now reported through window queries and there is a new attribute `minimized` to identify the current state [#379](https://github.com/koekeishiya/yabai/issues/379)

## [2.4.3] - 2020-04-14
### Changed
Expand Down
16 changes: 14 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-03-03
.\" Date: 2020-04-20
.\" Manual: Yabai Manual
.\" Source: Yabai
.\" Language: English
.\"
.TH "YABAI" "1" "2020-03-03" "Yabai" "Yabai Manual"
.TH "YABAI" "1" "2020-04-20" "Yabai" "Yabai Manual"
.ie \n(.g .ds Aq \(aq
.el .ds Aq '
.ss \n[.ss] 0
Expand Down Expand Up @@ -475,6 +475,18 @@ Send the selected window to the given display.
Send the selected window to the given space.
.RE
.sp
\fB\-\-minimize\fP
.RS 4
Minimizes the selected window. Only works on windows that provide a minimize button in its titlebar.
.RE
.sp
\fB\-\-deminimize\fP
.RS 4
Restores the selected window, if it is minimized.
.br
Note that you can also \fI\-\-focus\fP a minimized window to restore it.
.RE
.sp
\fB\-\-close\fP
.RS 4
Closes the selected window. Only works on windows that provide a close button in its titlebar.
Expand Down
7 changes: 7 additions & 0 deletions doc/yabai.asciidoc
Original file line number Diff line number Diff line change
Expand Up @@ -340,6 +340,13 @@ COMMAND
*--space* '<SPACE_SEL>'::
Send the selected window to the given space.

*--minimize*::
Minimizes the selected window. Only works on windows that provide a minimize button in its titlebar.

*--deminimize*::
Restores the selected window, if it is minimized. +
Note that you can also '--focus' a minimized window to restore it.

*--close*::
Closes the selected window. Only works on windows that provide a close button in its titlebar.

Expand Down
2 changes: 1 addition & 1 deletion src/display_manager.c
Original file line number Diff line number Diff line change
Expand Up @@ -246,7 +246,7 @@ void display_manager_focus_display(uint32_t did)
CGPoint point;
AXUIElementRef element_ref;

window_list = space_window_list(display_space_id(did), &window_count);
window_list = space_window_list(display_space_id(did), &window_count, false);
if (!window_list) goto fallback;

for (int i = 0; i < window_count; ++i) {
Expand Down
42 changes: 30 additions & 12 deletions src/message.c
Original file line number Diff line number Diff line change
Expand Up @@ -122,6 +122,8 @@ extern bool g_verbose;
#define COMMAND_WINDOW_MOVE "--move"
#define COMMAND_WINDOW_RESIZE "--resize"
#define COMMAND_WINDOW_RATIO "--ratio"
#define COMMAND_WINDOW_MIN "--minimize"
#define COMMAND_WINDOW_DEMIN "--deminimize"
#define COMMAND_WINDOW_CLOSE "--close"
#define COMMAND_WINDOW_LAYER "--layer"
#define COMMAND_WINDOW_TOGGLE "--toggle"
Expand Down Expand Up @@ -909,7 +911,7 @@ static char *parse_label(FILE *rsp, char **message, enum label_type type)
struct token value = get_token(message);

if ((!token_is_valid(value)) || (value.text[0] >= '0' && value.text[0] <= '9')) {
daemon_fail(rsp, "'%.*s' is not a valid label\n", value.length, value.text);
daemon_fail(rsp, "'%.*s' is not a valid label.\n", value.length, value.text);
return NULL;
}

Expand All @@ -919,7 +921,7 @@ static char *parse_label(FILE *rsp, char **message, enum label_type type)
case LABEL_SPACE: {
for (int i = 0; i < array_count(reserved_space_identifiers); ++i) {
if (token_equals(value, reserved_space_identifiers[i])) {
daemon_fail(rsp, "'%.*s' is a reserved keyword and cannot be used as a label\n", value.length, value.text);
daemon_fail(rsp, "'%.*s' is a reserved keyword and cannot be used as a label.\n", value.length, value.text);
return NULL;
}
}
Expand Down Expand Up @@ -1600,7 +1602,7 @@ static void handle_domain_window(FILE *rsp, struct token domain, char *message)
if (result == WINDOW_OP_ERROR_INVALID_SRC_NODE) {
daemon_fail(rsp, "cannot locate bsp node for the managed window.\n");
} else if (result == WINDOW_OP_ERROR_INVALID_DST_NODE) {
daemon_fail(rsp, "cannot locate a bsp node fence");
daemon_fail(rsp, "cannot locate a bsp node fence.\n");
}
} 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);
Expand All @@ -1614,14 +1616,30 @@ static void handle_domain_window(FILE *rsp, struct token domain, char *message)
if (result == WINDOW_OP_ERROR_INVALID_SRC_VIEW) {
daemon_fail(rsp, "cannot adjust ratio of a non-managed window.\n");
} else if (result == WINDOW_OP_ERROR_INVALID_SRC_NODE) {
daemon_fail(rsp, "cannot adjust ratio of a root node\n");
daemon_fail(rsp, "cannot adjust ratio of a root node.\n");
}
} 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_WINDOW_MIN)) {
enum window_op_error result = window_manager_minimize_window(acting_window);
if (result == WINDOW_OP_ERROR_CANT_MINIMIZE) {
daemon_fail(rsp, "window with id '%d' does not support the minimize operation.\n", acting_window->id);
} else if (result == WINDOW_OP_ERROR_ALREADY_MINIMIZED) {
daemon_fail(rsp, "window with id '%d' is already minimized.\n", acting_window->id);
} else if (result == WINDOW_OP_ERROR_MINIMIZE_FAILED) {
daemon_fail(rsp, "could not minimize window with id '%d'.\n", acting_window->id);
}
} else if (token_equals(command, COMMAND_WINDOW_DEMIN)) {
enum window_op_error result = window_manager_deminimize_window(acting_window);
if (result == WINDOW_OP_ERROR_NOT_MINIMIZED) {
daemon_fail(rsp, "window with id '%d' is not minimized.\n", acting_window->id);
} else if (result == WINDOW_OP_ERROR_DEMINIMIZE_FAILED) {
daemon_fail(rsp, "could not deminimize window with id '%d'.\n", acting_window->id);
}
} else if (token_equals(command, COMMAND_WINDOW_CLOSE)) {
if (!window_manager_close_window(acting_window)) {
daemon_fail(rsp, "could not close window with id '%d'\n", acting_window->id);
daemon_fail(rsp, "could not close window with id '%d'.\n", acting_window->id);
}
} else if (token_equals(command, COMMAND_WINDOW_LAYER)) {
struct token value = get_token(&message);
Expand Down Expand Up @@ -1733,7 +1751,7 @@ static void handle_domain_query(FILE *rsp, struct token domain, char *message)
display_serialize(rsp, window_display_id(acting_window));
fprintf(rsp, "\n");
} else {
daemon_fail(rsp, "could not find window to retrieve display details\n");
daemon_fail(rsp, "could not find window to retrieve display details.\n");
}
}
} else if (token_is_valid(option)) {
Expand All @@ -1749,14 +1767,14 @@ static void handle_domain_query(FILE *rsp, struct token domain, char *message)
if (selector.did_parse || token_is_valid(selector.token)) {
if (selector.did) {
if (!space_manager_query_spaces_for_display(rsp, selector.did)) {
daemon_fail(rsp, "could not retrieve spaces for display\n");
daemon_fail(rsp, "could not retrieve spaces for display.\n");
}
} else {
daemon_fail(rsp, "could not locate the selected display.\n");
}
} else {
if (!space_manager_query_spaces_for_display(rsp, acting_did)) {
daemon_fail(rsp, "could not retrieve spaces for display\n");
daemon_fail(rsp, "could not retrieve spaces for display.\n");
}
}
} else if (token_equals(option, ARGUMENT_QUERY_SPACE)) {
Expand All @@ -1776,7 +1794,7 @@ static void handle_domain_query(FILE *rsp, struct token domain, char *message)
}
} else {
if (!space_manager_query_active_space(rsp)) {
daemon_fail(rsp, "could not retrieve active space\n");
daemon_fail(rsp, "could not retrieve active space.\n");
}
}
} else if (token_equals(option, ARGUMENT_QUERY_WINDOW)) {
Expand All @@ -1792,14 +1810,14 @@ static void handle_domain_query(FILE *rsp, struct token domain, char *message)
if (acting_window) {
space_manager_query_spaces_for_window(rsp, acting_window);
} else {
daemon_fail(rsp, "could not find window to retrieve space details\n");
daemon_fail(rsp, "could not find window to retrieve space details.\n");
}
}
} else if (token_is_valid(option)) {
daemon_fail(rsp, "unknown option '%.*s' given to command '%.*s' for domain '%.*s'\n", option.length, option.text, command.length, command.text, domain.length, domain.text);
} else {
if (!space_manager_query_spaces_for_displays(rsp)) {
daemon_fail(rsp, "could not retrieve spaces for displays\n");
daemon_fail(rsp, "could not retrieve spaces for displays.\n");
}
}
} else if (token_equals(command, COMMAND_QUERY_WINDOWS)) {
Expand Down Expand Up @@ -1843,7 +1861,7 @@ static void handle_domain_query(FILE *rsp, struct token domain, char *message)
window_serialize(rsp, acting_window);
fprintf(rsp, "\n");
} else {
daemon_fail(rsp, "could not retrieve window details\n");
daemon_fail(rsp, "could not retrieve window details.\n");
}
}
} else if (token_is_valid(option)) {
Expand Down
9 changes: 5 additions & 4 deletions src/space.c
Original file line number Diff line number Diff line change
Expand Up @@ -21,14 +21,15 @@ uint32_t space_display_id(uint64_t sid)
return id;
}

uint32_t *space_window_list_for_connection(uint64_t sid, int cid, int *count)
uint32_t *space_window_list_for_connection(uint64_t sid, int cid, int *count, bool include_minimized)
{
uint32_t *window_list = NULL;
uint64_t set_tags = 0;
uint64_t clear_tags = 0;
uint32_t options = include_minimized ? 0x7 : 0x2;

CFArrayRef space_list_ref = cfarray_of_cfnumbers(&sid, sizeof(uint64_t), 1, kCFNumberSInt64Type);
CFArrayRef window_list_ref = SLSCopyWindowsWithOptionsAndTags(g_connection, cid, space_list_ref, 0x2, &set_tags, &clear_tags);
CFArrayRef window_list_ref = SLSCopyWindowsWithOptionsAndTags(g_connection, cid, space_list_ref, options, &set_tags, &clear_tags);
if (!window_list_ref) goto err;

*count = CFArrayGetCount(window_list_ref);
Expand All @@ -48,9 +49,9 @@ uint32_t *space_window_list_for_connection(uint64_t sid, int cid, int *count)
return window_list;
}

uint32_t *space_window_list(uint64_t sid, int *count)
uint32_t *space_window_list(uint64_t sid, int *count, bool include_minimized)
{
return space_window_list_for_connection(sid, 0, count);
return space_window_list_for_connection(sid, 0, count, include_minimized);
}

CFStringRef space_uuid(uint64_t sid)
Expand Down
4 changes: 2 additions & 2 deletions src/space.h
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,8 @@ extern CFArrayRef SLSCopyWindowsWithOptionsAndTags(int cid, uint32_t owner, CFAr

CFStringRef space_display_uuid(uint64_t sid);
uint32_t space_display_id(uint64_t sid);
uint32_t *space_window_list_for_connection(uint64_t sid, int cid, int *count);
uint32_t *space_window_list(uint64_t sid, int *count);
uint32_t *space_window_list_for_connection(uint64_t sid, int cid, int *count, bool include_minimized);
uint32_t *space_window_list(uint64_t sid, int *count, bool include_minimized);
CFStringRef space_uuid(uint64_t sid);
int space_type(uint64_t sid);
bool space_is_user(uint64_t sid);
Expand Down
2 changes: 1 addition & 1 deletion src/view.c
Original file line number Diff line number Diff line change
Expand Up @@ -468,7 +468,7 @@ void view_serialize(FILE *rsp, struct view *view)
uint32_t windows[MAXLEN] = {};

int window_count = 0;
uint32_t *window_list = space_window_list(view->sid, &window_count);
uint32_t *window_list = space_window_list(view->sid, &window_count, true);
if (window_list) {
for (int i = 0; i < window_count; ++i) {
if (window_manager_find_window(&g_window_manager, window_list[i])) {
Expand Down
12 changes: 12 additions & 0 deletions src/window.c
Original file line number Diff line number Diff line change
Expand Up @@ -116,6 +116,7 @@ void window_serialize(FILE *rsp, struct window *window)
int display = display_arrangement(space_display_id(sid));
bool visible = sticky || space_is_visible(sid);
bool is_topmost = window_is_topmost(window);
bool is_minimized = window_is_minimized(window);

CFStringRef cfrole = window_role(window);
if (cfrole) {
Expand Down Expand Up @@ -156,6 +157,7 @@ void window_serialize(FILE *rsp, struct window *window)
"\t\"split\":\"%s\",\n"
"\t\"floating\":%d,\n"
"\t\"sticky\":%d,\n"
"\t\"minimized\":%d,\n"
"\t\"topmost\":%d,\n"
"\t\"border\":%d,\n"
"\t\"shadow\":%d,\n"
Expand All @@ -181,6 +183,7 @@ void window_serialize(FILE *rsp, struct window *window)
split,
window->is_floating,
sticky,
is_minimized,
is_topmost,
window->border.enabled,
window->has_shadow,
Expand Down Expand Up @@ -260,6 +263,15 @@ bool window_can_resize(struct window *window)
return result;
}

bool window_can_minimize(struct window *window)
{
Boolean result;
if (AXUIElementIsAttributeSettable(window->ref, kAXMinimizedAttribute, &result) != kAXErrorSuccess) {
result = 0;
}
return result;
}

bool window_is_undersized(struct window *window)
{
CGRect frame = window_frame(window);
Expand Down
1 change: 1 addition & 0 deletions src/window.h
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,7 @@ CFStringRef window_role(struct window *window);
CFStringRef window_subrole(struct window *window);
bool window_can_move(struct window *window);
bool window_can_resize(struct window *window);
bool window_can_minimize(struct window *window);
bool window_level_is_standard(struct window *window);
bool window_is_undersized(struct window *window);
bool window_is_minimized(struct window *window);
Expand Down
33 changes: 25 additions & 8 deletions src/window_manager.c
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ static TABLE_COMPARE_FUNC(compare_wm)
void window_manager_query_windows_for_space(FILE *rsp, uint64_t sid)
{
int window_count;
uint32_t *window_list = space_window_list(sid, &window_count);
uint32_t *window_list = space_window_list(sid, &window_count, true);
if (!window_list) return;

struct window **window_aggregate_list = NULL;
Expand Down Expand Up @@ -47,7 +47,7 @@ void window_manager_query_windows_for_display(FILE *rsp, uint32_t did)
struct window **window_aggregate_list = NULL;
for (int i = 0; i < space_count; ++i) {
int window_count;
uint32_t *window_list = space_window_list(space_list[i], &window_count);
uint32_t *window_list = space_window_list(space_list[i], &window_count, true);
if (!window_list) continue;

for (int j = 0; j < window_count; ++j) {
Expand Down Expand Up @@ -84,7 +84,7 @@ void window_manager_query_windows_for_displays(FILE *rsp)

for (int j = 0; j < space_count; ++j) {
int window_count;
uint32_t *window_list = space_window_list(space_list[j], &window_count);
uint32_t *window_list = space_window_list(space_list[j], &window_count, true);
if (!window_list) continue;

for (int k = 0; k < window_count; ++k) {
Expand Down Expand Up @@ -550,7 +550,7 @@ void window_manager_set_layer(uint32_t wid, int layer)
static void window_manager_set_layer_for_children(int cid, uint32_t wid, uint64_t sid, int layer)
{
int count;
uint32_t *window_list = space_window_list_for_connection(sid, cid, &count);
uint32_t *window_list = space_window_list_for_connection(sid, cid, &count, false);
if (!window_list) return;

CFArrayRef window_list_ref = cfarray_of_cfnumbers(window_list, sizeof(uint32_t), count, kCFNumberSInt32Type);
Expand Down Expand Up @@ -631,7 +631,7 @@ void window_manager_purify_window(struct window_manager *wm, struct window *wind
static struct window *window_manager_find_window_on_space_by_rank(struct window_manager *wm, uint64_t sid, int rank)
{
int count;
uint32_t *window_list = space_window_list(sid, &count);
uint32_t *window_list = space_window_list(sid, &count, false);
if (!window_list) return NULL;

struct window *result = NULL;
Expand Down Expand Up @@ -716,7 +716,7 @@ struct window *window_manager_find_closest_managed_window_in_direction(struct wi
struct window *window_manager_find_closest_window_in_direction(struct window_manager *wm, struct window *window, int direction)
{
int window_count;
uint32_t *window_list = space_window_list(display_space_id(window_display_id(window)), &window_count);
uint32_t *window_list = space_window_list(display_space_id(window_display_id(window)), &window_count, false);
if (!window_list) return NULL;

struct window *result = window_manager_find_closest_window_for_direction_in_window_list(wm, window, direction, window_list, window_count);
Expand Down Expand Up @@ -1257,6 +1257,23 @@ enum window_op_error window_manager_swap_window(struct space_manager *sm, struct
return WINDOW_OP_ERROR_SUCCESS;
}

enum window_op_error window_manager_minimize_window(struct window *window)
{
if (!window_can_minimize(window)) return WINDOW_OP_ERROR_CANT_MINIMIZE;
if (window->is_minimized) return WINDOW_OP_ERROR_ALREADY_MINIMIZED;

AXError result = AXUIElementSetAttributeValue(window->ref, kAXMinimizedAttribute, kCFBooleanTrue);
return result == kAXErrorSuccess ? WINDOW_OP_ERROR_SUCCESS : WINDOW_OP_ERROR_MINIMIZE_FAILED;
}

enum window_op_error window_manager_deminimize_window(struct window *window)
{
if (!window->is_minimized) return WINDOW_OP_ERROR_NOT_MINIMIZED;

AXError result = AXUIElementSetAttributeValue(window->ref, kAXMinimizedAttribute, kCFBooleanFalse);
return result == kAXErrorSuccess ? WINDOW_OP_ERROR_SUCCESS : WINDOW_OP_ERROR_DEMINIMIZE_FAILED;
}

bool window_manager_close_window(struct window *window)
{
CFTypeRef button = NULL;
Expand Down Expand Up @@ -1514,7 +1531,7 @@ void window_manager_toggle_window_pip(struct space_manager *sm, struct window_ma
void window_manager_validate_windows_on_space(struct space_manager *sm, struct window_manager *wm, uint64_t sid)
{
int window_count;
uint32_t *window_list = space_window_list(sid, &window_count);
uint32_t *window_list = space_window_list(sid, &window_count, false);
if (!window_list) return;

struct view *view = space_manager_find_view(sm, sid);
Expand Down Expand Up @@ -1547,7 +1564,7 @@ void window_manager_validate_windows_on_space(struct space_manager *sm, struct w
void window_manager_check_for_windows_on_space(struct space_manager *sm, struct window_manager *wm, uint64_t sid)
{
int window_count;
uint32_t *window_list = space_window_list(sid, &window_count);
uint32_t *window_list = space_window_list(sid, &window_count, false);
if (!window_list) return;

for (int i = 0; i < window_count; ++i) {
Expand Down
Loading

0 comments on commit e6781b5

Please sign in to comment.