Skip to content

Commit

Permalink
koekeishiya#565 re-introduce a more efficient window border system
Browse files Browse the repository at this point in the history
  • Loading branch information
koekeishiya authored and unrevre committed Jun 10, 2020
1 parent b0fbe08 commit 8d79e2a
Show file tree
Hide file tree
Showing 21 changed files with 2,616 additions and 1,893 deletions.
3 changes: 3 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,9 @@ 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
- Re-introduce a more efficient window border system [#565](https://github.com/koekeishiya/yabai/issues/565)

### Changed
- Re-construct application switched and window created events in the correct order when the window is moved through a rule upon creation [#564](https://github.com/koekeishiya/yabai/issues/564)

Expand Down
40 changes: 30 additions & 10 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-10
.\" Manual: Yabai Manual
.\" Source: Yabai
.\" Language: English
.\"
.TH "YABAI" "1" "2020-06-06" "Yabai" "Yabai Manual"
.TH "YABAI" "1" "2020-06-10" "Yabai" "Yabai Manual"
.ie \n(.g .ds Aq \(aq
.el .ds Aq '
.ss \n[.ss] 0
Expand Down Expand Up @@ -160,6 +160,11 @@ Specify whether managed windows should become the first or second leaf\-node.
Make floating windows stay on top.
.RE
.sp
\fBwindow_shadow\fP [\fI<BOOL_SEL>|float\fP]
.RS 4
Draw shadow for windows.
.RE
.sp
\fBwindow_opacity\fP [\fI<BOOL_SEL>\fP]
.RS 4
Enable opacity for windows.
Expand All @@ -170,24 +175,39 @@ Enable opacity for windows.
Duration of transition between active / normal opacity.
.RE
.sp
\fBwindow_shadow\fP [\fI<BOOL_SEL>|float\fP]
\fBactive_window_opacity\fP [\fI<FLOAT_SEL>\fP]
.RS 4
Draw shadow for windows.
Opacity of the focused window.
.RE
.sp
\fBinsert_feedback_color\fP [\fI0xAARRGGBB\fP]
\fBnormal_window_opacity\fP [\fI<FLOAT_SEL>\fP]
.RS 4
Color of the \fBwindow \-\-insert\fP message selection.
Opacity of an unfocused window.
.RE
.sp
\fBactive_window_opacity\fP [\fI<FLOAT_SEL>\fP]
\fBwindow_border\fP [\fI<BOOL_SEL>\fP]
.RS 4
Opacity of the focused window.
Draw border for windows.
.RE
.sp
\fBnormal_window_opacity\fP [\fI<FLOAT_SEL>\fP]
\fBwindow_border_width\fP [\fI<even integer number>\fP]
.RS 4
Opacity of an unfocused window.
Width of window borders. If the given width is an odd number, it will be incremented by 1.
.RE
.sp
\fBactive_window_border_color\fP [\fI0xAARRGGBB\fP]
.RS 4
Color of the border of the focused window.
.RE
.sp
\fBnormal_window_border_color\fP [\fI0xAARRGGBB\fP]
.RS 4
Color of the border of an unfocused window.
.RE
.sp
\fBinsert_feedback_color\fP [\fI0xAARRGGBB\fP]
.RS 4
Color of the \fBwindow \-\-insert\fP message selection.
.RE
.sp
\fBsplit_ratio\fP [\fI<FLOAT_SEL>\fP]
Expand Down
24 changes: 18 additions & 6 deletions doc/yabai.asciidoc
Original file line number Diff line number Diff line change
Expand Up @@ -127,24 +127,36 @@ Global Settings
*window_topmost* ['<BOOL_SEL>']::
Make floating windows stay on top.

*window_shadow* ['<BOOL_SEL>|float']::
Draw shadow for windows.

*window_opacity* ['<BOOL_SEL>']::
Enable opacity for windows.

*window_opacity_duration* ['<floating point number>']::
Duration of transition between active / normal opacity.

*window_shadow* ['<BOOL_SEL>|float']::
Draw shadow for windows.

*insert_feedback_color* ['0xAARRGGBB']::
Color of the *window --insert* message selection.

*active_window_opacity* ['<FLOAT_SEL>']::
Opacity of the focused window.

*normal_window_opacity* ['<FLOAT_SEL>']::
Opacity of an unfocused window.

*window_border* ['<BOOL_SEL>']::
Draw border for windows.

*window_border_width* ['<even integer number>']::
Width of window borders. If the given width is an odd number, it will be incremented by 1.

*active_window_border_color* ['0xAARRGGBB']::
Color of the border of the focused window.

*normal_window_border_color* ['0xAARRGGBB']::
Color of the border of an unfocused window.

*insert_feedback_color* ['0xAARRGGBB']::
Color of the *window --insert* message selection.

*split_ratio* ['<FLOAT_SEL>']::
Default split ratio.

Expand Down
8 changes: 6 additions & 2 deletions examples/yabairc
Original file line number Diff line number Diff line change
Expand Up @@ -5,12 +5,16 @@ yabai -m config mouse_follows_focus off
yabai -m config focus_follows_mouse off
yabai -m config window_placement second_child
yabai -m config window_topmost off
yabai -m config window_shadow on
yabai -m config window_opacity off
yabai -m config window_opacity_duration 0.0
yabai -m config window_shadow on
yabai -m config insert_feedback_color 0xaad75f5f
yabai -m config active_window_opacity 1.0
yabai -m config normal_window_opacity 0.90
yabai -m config window_border off
yabai -m config window_border_width 6
yabai -m config active_window_border_color 0xff775759
yabai -m config normal_window_border_color 0xff555555
yabai -m config insert_feedback_color 0xffd75f5f
yabai -m config split_ratio 0.50
yabai -m config auto_balance off
yabai -m config mouse_modifier fn
Expand Down
16 changes: 2 additions & 14 deletions src/application.c
Original file line number Diff line number Diff line change
Expand Up @@ -143,23 +143,11 @@ bool application_is_hidden(struct application *application)
}
#pragma clang diagnostic pop

struct window **application_window_list(struct application *application, int *window_count)
CFArrayRef application_window_list(struct application *application)
{
CFTypeRef window_list_ref = NULL;
AXUIElementCopyAttributeValue(application->ref, kAXWindowsAttribute, &window_list_ref);
if (!window_list_ref) return NULL;

*window_count = CFArrayGetCount(window_list_ref);
struct window **window_list = malloc((*window_count) * sizeof(struct window *));

for (int i = 0; i < *window_count; ++i) {
AXUIElementRef window_ref = CFArrayGetValueAtIndex(window_list_ref, i);
uint32_t window_id = ax_window_id(window_ref);
window_list[i] = window_id ? window_create(application, CFRetain(window_ref), window_id) : NULL;
}

CFRelease(window_list_ref);
return window_list;
return window_list_ref;
}

struct application *application_create(struct process *process)
Expand Down
2 changes: 1 addition & 1 deletion src/application.h
Original file line number Diff line number Diff line change
Expand Up @@ -79,7 +79,7 @@ bool application_is_frontmost(struct application *application);
bool application_is_hidden(struct application *application);
uint32_t application_main_window(struct application *application);
uint32_t application_focused_window(struct application *application);
struct window **application_window_list(struct application *application, int *window_count);
CFArrayRef application_window_list(struct application *application);
bool application_observe(struct application *application);
void application_unobserve(struct application *application);
struct application *application_create(struct process *process);
Expand Down
108 changes: 108 additions & 0 deletions src/border.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,108 @@
#include "border.h"

extern struct window_manager g_window_manager;

void border_redraw(struct window *window)
{
SLSDisableUpdate(g_connection);
CGContextClearRect(window->border.context, window->border.frame);
CGContextAddPath(window->border.context, window->border.path);
CGContextStrokePath(window->border.context);
CGContextFlush(window->border.context);
SLSReenableUpdate(g_connection);
}

void border_activate(struct window *window)
{
if (!window->border.id) return;

CGContextSetRGBStrokeColor(window->border.context,
g_window_manager.active_border_color.r,
g_window_manager.active_border_color.g,
g_window_manager.active_border_color.b,
g_window_manager.active_border_color.a);
border_redraw(window);
}

void border_deactivate(struct window *window)
{
if (!window->border.id) return;

CGContextSetRGBStrokeColor(window->border.context,
g_window_manager.normal_border_color.r,
g_window_manager.normal_border_color.g,
g_window_manager.normal_border_color.b,
g_window_manager.normal_border_color.a);
border_redraw(window);
}

void border_show(struct window *window)
{
if (window->border.id) SLSOrderWindow(g_connection, window->border.id, 1, window->id);
}

void border_hide(struct window *window)
{
if (window->border.id) SLSOrderWindow(g_connection, window->border.id, 0, window->id);
}

void border_create(struct window *window)
{
if (!g_window_manager.enable_window_border) return;
if (window->border.id) return;

window->border.frame = window_ax_frame(window);
if (window->border.region) CFRelease(window->border.region);
CGSNewRegionWithRect(&window->border.frame, &window->border.region);
window->border.frame.origin.x = 0;
window->border.frame.origin.y = 0;

uint64_t tags[2] = { (1ULL << 31) | kCGSIgnoreForExposeTagBit | kCGSIgnoreForEventsTagBit, 0 };
SLSNewWindow(g_connection, 2, 0, 0, window->border.region, &window->border.id);
SLSSetWindowTags(g_connection, window->border.id, tags, 64);
SLSSetWindowResolution(g_connection, window->border.id, 1.0f);
SLSSetWindowOpacity(g_connection, window->border.id, 0);
SLSSetWindowLevel(g_connection, window->border.id, window_level(window));
window->border.context = SLWindowContextCreate(g_connection, window->border.id, 0);
CGContextSetLineWidth(window->border.context, g_window_manager.border_width);
CGContextSetRGBStrokeColor(window->border.context,
g_window_manager.normal_border_color.r,
g_window_manager.normal_border_color.g,
g_window_manager.normal_border_color.b,
g_window_manager.normal_border_color.a);
window_manager_add_to_window_group(window->border.id, window->id);
}

void border_resize(struct window *window)
{
if (!window->border.id) return;

window->border.frame = window_ax_frame(window);
if (window->border.region) CFRelease(window->border.region);
CGSNewRegionWithRect(&window->border.frame, &window->border.region);
window->border.frame.origin.x = 0;
window->border.frame.origin.y = 0;

if (window->border.path) CGPathRelease(window->border.path);
window->border.path = CGPathCreateMutable();
CGPathAddRoundedRect(window->border.path, NULL, window->border.frame, 0, 0);

SLSDisableUpdate(g_connection);
SLSSetWindowShape(g_connection, window->border.id, 0.0f, 0.0f, window->border.region);
CGContextClearRect(window->border.context, window->border.frame);
CGContextAddPath(window->border.context, window->border.path);
CGContextStrokePath(window->border.context);
CGContextFlush(window->border.context);
SLSReenableUpdate(g_connection);
}

void border_destroy(struct window *window)
{
if (!window->border.id) return;

if (window->border.region) CFRelease(window->border.region);
if (window->border.path) CGPathRelease(window->border.path);
CGContextRelease(window->border.context);
SLSReleaseWindow(g_connection, window->border.id);
memset(&window->border, 0, sizeof(struct border));
}
38 changes: 38 additions & 0 deletions src/border.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
#ifndef BORDER_H
#define BORDER_H

extern CGError SLSDisableUpdate(int cid);
extern CGError SLSReenableUpdate(int cid);
extern CGError SLSNewWindow(int cid, int type, float x, float y, CFTypeRef region, uint32_t *wid);
extern CGError SLSReleaseWindow(int cid, uint32_t wid);
extern CGError SLSSetWindowTags(int cid, uint32_t wid, uint64_t tags[2], int tag_size);
extern CGError SLSSetWindowShape(int cid, uint32_t wid, float x_offset, float y_offset, CFTypeRef shape);
extern CGError SLSSetWindowOpacity(int cid, uint32_t wid, bool isOpaque);
extern CGError SLSOrderWindow(int cid, uint32_t wid, int mode, uint32_t relativeToWID);
extern CGError SLSSetWindowLevel(int cid, uint32_t wid, int level);
extern CGContextRef SLWindowContextCreate(int cid, uint32_t wid, CFDictionaryRef options);
extern CGError CGSNewRegionWithRect(CGRect *rect, CFTypeRef *outRegion);

#define kCGSIgnoreForExposeTagBit (1 << 7)
#define kCGSIgnoreForEventsTagBit (1 << 9)

struct border
{
uint32_t id;
CGContextRef context;
CFTypeRef region;
CGRect frame;
CGMutablePathRef path;
};

struct window;
void border_redraw(struct window *window);
void border_activate(struct window *window);
void border_deactivate(struct window *window);
void border_show(struct window *window);
void border_hide(struct window *window);
void border_create(struct window *window);
void border_resize(struct window *window);
void border_destroy(struct window *window);

#endif
9 changes: 9 additions & 0 deletions src/event.c
Original file line number Diff line number Diff line change
Expand Up @@ -226,6 +226,7 @@ static EVENT_CALLBACK(EVENT_HANDLER_APPLICATION_ACTIVATED)
g_window_manager.focused_window_psn = application->psn;

window_manager_set_window_opacity(&g_window_manager, window, g_window_manager.active_window_opacity);
border_activate(window);

if (g_mouse_state.ffm_window_id != window->id) {
window_manager_center_mouse(&g_window_manager, window);
Expand All @@ -245,11 +246,13 @@ static EVENT_CALLBACK(EVENT_HANDLER_APPLICATION_DEACTIVATED)
struct window *focused_window = window_manager_find_window(&g_window_manager, application_focused_window(application));
if (focused_window) {
window_manager_set_window_opacity(&g_window_manager, focused_window, g_window_manager.normal_window_opacity);
border_deactivate(focused_window);

if (!window_level_is_standard(focused_window) || !window_is_standard(focused_window)) {
struct window *main_window = window_manager_find_window(&g_window_manager, application_main_window(application));
if (main_window && main_window != focused_window) {
window_manager_set_window_opacity(&g_window_manager, main_window, g_window_manager.normal_window_opacity);
border_deactivate(main_window);
}
}
}
Expand Down Expand Up @@ -434,10 +437,12 @@ static EVENT_CALLBACK(EVENT_HANDLER_WINDOW_FOCUSED)
struct window *focused_window = window_manager_find_window(&g_window_manager, g_window_manager.focused_window_id);
if (focused_window && focused_window != window) {
window_manager_set_window_opacity(&g_window_manager, focused_window, g_window_manager.normal_window_opacity);
border_deactivate(focused_window);
}

debug("%s: %s %d\n", __FUNCTION__, window->application->name, window->id);
window_manager_set_window_opacity(&g_window_manager, window, g_window_manager.active_window_opacity);
border_activate(window);

if (window_level_is_standard(window) && window_is_standard(window)) {
if (g_window_manager.focused_window_id != window->id) {
Expand Down Expand Up @@ -531,6 +536,7 @@ static EVENT_CALLBACK(EVENT_HANDLER_WINDOW_RESIZED)
}
}

border_resize(window);
return EVENT_SUCCESS;
}

Expand Down Expand Up @@ -625,6 +631,7 @@ static EVENT_CALLBACK(EVENT_HANDLER_SPACE_CHANGED)
struct window *focused_window = window_manager_focused_window(&g_window_manager);
if (focused_window && window_manager_find_lost_focused_event(&g_window_manager, focused_window->id)) {
window_manager_set_window_opacity(&g_window_manager, focused_window, g_window_manager.active_window_opacity);
border_activate(focused_window);

if (g_mouse_state.ffm_window_id != focused_window->id) {
window_manager_center_mouse(&g_window_manager, focused_window);
Expand Down Expand Up @@ -667,6 +674,7 @@ static EVENT_CALLBACK(EVENT_HANDLER_DISPLAY_CHANGED)
struct window *focused_window = window_manager_focused_window(&g_window_manager);
if (focused_window && window_manager_find_lost_focused_event(&g_window_manager, focused_window->id)) {
window_manager_set_window_opacity(&g_window_manager, focused_window, g_window_manager.active_window_opacity);
border_activate(focused_window);

if (g_mouse_state.ffm_window_id != focused_window->id) {
window_manager_center_mouse(&g_window_manager, focused_window);
Expand Down Expand Up @@ -1193,6 +1201,7 @@ static EVENT_CALLBACK(EVENT_HANDLER_SYSTEM_WOKE)
struct window *focused_window = window_manager_find_window(&g_window_manager, g_window_manager.focused_window_id);
if (focused_window) {
window_manager_set_window_opacity(&g_window_manager, focused_window, g_window_manager.active_window_opacity);
border_activate(focused_window);
window_manager_center_mouse(&g_window_manager, focused_window);
}

Expand Down
Loading

0 comments on commit 8d79e2a

Please sign in to comment.