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
69 changes: 69 additions & 0 deletions src/view.c
Original file line number Diff line number Diff line change
Expand Up @@ -183,12 +183,81 @@ static void area_make_pair(enum window_node_split split, int gap, float ratio, s
}
}

static inline bool window_node_is_leaf(struct window_node *node);

static CGSize window_node_get_min_size(struct window_node *node)
{
CGSize min_size = { 0, 0 };

if (window_node_is_leaf(node)) {
for (int i = 0; i < node->window_count; ++i) {
struct window *window = window_manager_find_window(&g_window_manager, node->window_list[i]);
if (window && window->has_size_constraints) {
min_size.width = max(min_size.width, window->min_size.width);
min_size.height = max(min_size.height, window->min_size.height);
}
}
} else {
CGSize left_min = window_node_get_min_size(node->left);
CGSize right_min = window_node_get_min_size(node->right);
min_size.width = max(left_min.width, right_min.width);
min_size.height = max(left_min.height, right_min.height);
}

return min_size;
}

static void area_make_pair_for_node(struct view *view, struct window_node *node)
{
enum window_node_split split = window_node_get_split(view, node);
float ratio = window_node_get_ratio(node);
int gap = window_node_get_gap(view);

CGSize left_min = window_node_get_min_size(node->left);
CGSize right_min = window_node_get_min_size(node->right);

if (split == SPLIT_Y) {
float available = node->area.w - gap;
float left_needed = left_min.width;
float right_needed = right_min.width;

if (left_needed > 0 && left_needed > available * ratio) {
float new_ratio = left_needed / available;
if (new_ratio <= 0.9f) {
ratio = new_ratio;
debug("adjusted ratio to %.2f for left child min_width %.0f\n", ratio, left_needed);
}
}

if (right_needed > 0 && right_needed > available * (1 - ratio)) {
float new_ratio = 1.0f - (right_needed / available);
if (new_ratio >= 0.1f) {
ratio = new_ratio;
debug("adjusted ratio to %.2f for right child min_width %.0f\n", ratio, right_needed);
}
}
} else {
float available = node->area.h - gap;
float left_needed = left_min.height;
float right_needed = right_min.height;

if (left_needed > 0 && left_needed > available * ratio) {
float new_ratio = left_needed / available;
if (new_ratio <= 0.9f) {
ratio = new_ratio;
debug("adjusted ratio to %.2f for left child min_height %.0f\n", ratio, left_needed);
}
}

if (right_needed > 0 && right_needed > available * (1 - ratio)) {
float new_ratio = 1.0f - (right_needed / available);
if (new_ratio >= 0.1f) {
ratio = new_ratio;
debug("adjusted ratio to %.2f for right child min_height %.0f\n", ratio, right_needed);
}
}
}

area_make_pair(split, gap, ratio, &node->area, &node->left->area, &node->right->area);

node->split = split;
Expand Down
3 changes: 3 additions & 0 deletions src/window.h
Original file line number Diff line number Diff line change
Expand Up @@ -103,6 +103,9 @@ struct window
float opacity;
int layer;
char *scratchpad;
CGSize min_size;
CGSize max_size;
bool has_size_constraints;
};

enum window_flag
Expand Down
101 changes: 101 additions & 0 deletions src/window_manager.c
Original file line number Diff line number Diff line change
Expand Up @@ -352,6 +352,22 @@ void window_manager_resize_window_relative_internal(struct window *window, CGRec

float fw = max(1, frame.size.width + dx * x_mod);
float fh = max(1, frame.size.height + dy * y_mod);

if (window->has_size_constraints) {
if (window->min_size.width > 0 && fw < window->min_size.width) {
fw = window->min_size.width;
}
if (window->min_size.height > 0 && fh < window->min_size.height) {
fh = window->min_size.height;
}
if (window->max_size.width > 0 && fw > window->max_size.width) {
fw = window->max_size.width;
}
if (window->max_size.height > 0 && fh > window->max_size.height) {
fh = window->max_size.height;
}
}

float fx = (direction & HANDLE_LEFT) ? frame.origin.x + frame.size.width - fw : frame.origin.x;
float fy = (direction & HANDLE_TOP) ? frame.origin.y + frame.size.height - fh : frame.origin.y;

Expand Down Expand Up @@ -726,6 +742,52 @@ void window_manager_animate_window(struct window_capture capture)
}
}

static void window_manager_apply_constrained_position(struct window *window, float target_x, float target_y,
float target_w, float target_h, CGRect actual_frame)
{
float new_x = target_x;
float new_y = target_y;

if (actual_frame.size.width < target_w) {
new_x = target_x + (target_w - actual_frame.size.width) / 2.0f;
}
if (actual_frame.size.height < target_h) {
new_y = target_y + (target_h - actual_frame.size.height) / 2.0f;
}

if (actual_frame.size.width > target_w || actual_frame.size.height > target_h) {
uint32_t did = window_display_id(window->id);
CGRect display_bounds = display_bounds_constrained(did, false);

float node_center_x = target_x + target_w / 2.0f;
float node_center_y = target_y + target_h / 2.0f;
float display_center_x = display_bounds.origin.x + display_bounds.size.width / 2.0f;
float display_center_y = display_bounds.origin.y + display_bounds.size.height / 2.0f;

if (actual_frame.size.width > target_w) {
float overflow = actual_frame.size.width - target_w;
if (node_center_x < display_center_x) {
new_x = target_x;
} else {
new_x = target_x - overflow;
}
}

if (actual_frame.size.height > target_h) {
float overflow = actual_frame.size.height - target_h;
if (node_center_y < display_center_y) {
new_y = target_y;
} else {
new_y = target_y - overflow;
}
}
}

if (new_x != target_x || new_y != target_y) {
window_manager_move_window(window, new_x, new_y);
}
}

void window_manager_set_window_frame(struct window *window, float x, float y, float width, float height)
{
//
Expand All @@ -747,6 +809,45 @@ void window_manager_set_window_frame(struct window *window, float x, float y, fl
// NOTE(asmvik): Due to macOS constraints (visible screen-area), we might need to resize the window *after* moving it.
window_manager_resize_window(window, width, height);
});

CGRect actual_frame = window_ax_frame(window);

if (AX_DIFF(actual_frame.size.width, width) || AX_DIFF(actual_frame.size.height, height)) {
bool first_detection = !window->has_size_constraints;
window->has_size_constraints = true;

if (actual_frame.size.width > width) {
window->min_size.width = fmax(window->min_size.width, actual_frame.size.width);
}
if (actual_frame.size.height > height) {
window->min_size.height = fmax(window->min_size.height, actual_frame.size.height);
}
if (actual_frame.size.width < width) {
window->max_size.width = (window->max_size.width == 0)
? actual_frame.size.width
: fmin(window->max_size.width, actual_frame.size.width);
}
if (actual_frame.size.height < height) {
window->max_size.height = (window->max_size.height == 0)
? actual_frame.size.height
: fmin(window->max_size.height, actual_frame.size.height);
}

debug("window %d has constraints: min=%.0fx%.0f max=%.0fx%.0f\n",
window->id,
window->min_size.width, window->min_size.height,
window->max_size.width, window->max_size.height);

window_manager_apply_constrained_position(window, x, y, width, height, actual_frame);

if (first_detection) {
struct view *view = space_manager_find_view(&g_space_manager, space_manager_active_space());
if (view) {
view_update(view);
view_flush(view);
}
}
}
}

void window_manager_set_purify_mode(struct window_manager *wm, enum purify_mode mode)
Expand Down