diff --git a/src/event.c b/src/event.c index 7d47b234..c6b77527 100644 --- a/src/event.c +++ b/src/event.c @@ -34,10 +34,10 @@ static void window_did_receive_focus(struct window_manager *wm, struct mouse_sta if (node->window_count <= 1) return; for (int i = 0; i < node->window_count; ++i) { - if (node->window_list[i] != window->id) continue; + if (node->window_order[i] != window->id) continue; - memmove(node->window_list + 1, node->window_list, sizeof(uint32_t) * i); - node->window_list[0] = window->id; + memmove(node->window_order + 1, node->window_order, sizeof(uint32_t) * i); + node->window_order[0] = window->id; break; } diff --git a/src/message.c b/src/message.c index 2e29a97b..e2f58c50 100644 --- a/src/message.c +++ b/src/message.c @@ -188,18 +188,20 @@ extern bool g_verbose; /* ----------------------------------------------------------------------------- */ /* --------------------------------COMMON ARGUMENTS----------------------------- */ -#define ARGUMENT_COMMON_VAL_ON "on" -#define ARGUMENT_COMMON_VAL_OFF "off" -#define ARGUMENT_COMMON_SEL_PREV "prev" -#define ARGUMENT_COMMON_SEL_NEXT "next" -#define ARGUMENT_COMMON_SEL_FIRST "first" -#define ARGUMENT_COMMON_SEL_LAST "last" -#define ARGUMENT_COMMON_SEL_RECENT "recent" -#define ARGUMENT_COMMON_SEL_NORTH "north" -#define ARGUMENT_COMMON_SEL_EAST "east" -#define ARGUMENT_COMMON_SEL_SOUTH "south" -#define ARGUMENT_COMMON_SEL_WEST "west" -#define ARGUMENT_COMMON_SEL_STACK "stack" +#define ARGUMENT_COMMON_VAL_ON "on" +#define ARGUMENT_COMMON_VAL_OFF "off" +#define ARGUMENT_COMMON_SEL_PREV "prev" +#define ARGUMENT_COMMON_SEL_NEXT "next" +#define ARGUMENT_COMMON_SEL_FIRST "first" +#define ARGUMENT_COMMON_SEL_LAST "last" +#define ARGUMENT_COMMON_SEL_RECENT "recent" +#define ARGUMENT_COMMON_SEL_NORTH "north" +#define ARGUMENT_COMMON_SEL_EAST "east" +#define ARGUMENT_COMMON_SEL_SOUTH "south" +#define ARGUMENT_COMMON_SEL_WEST "west" +#define ARGUMENT_COMMON_SEL_STACK "stack" +#define ARGUMENT_COMMON_SEL_STACK_PREV "stack.prev" +#define ARGUMENT_COMMON_SEL_STACK_NEXT "stack.next" /* ----------------------------------------------------------------------------- */ static bool token_equals(struct token token, char *match) @@ -1174,6 +1176,28 @@ static struct selector parse_window_selector(FILE *rsp, char **message, struct w } else { daemon_fail(rsp, "could not locate the most recently focused window.\n"); } + } else if (token_equals(result.token, ARGUMENT_COMMON_SEL_STACK_PREV)) { + if (acting_window) { + struct window *prev_window = window_manager_find_prev_window_in_stack(&g_space_manager, &g_window_manager, acting_window); + if (prev_window) { + result.window = prev_window; + } else { + daemon_fail(rsp, "could not locate the prev stacked window.\n"); + } + } else { + daemon_fail(rsp, "could not locate the selected window.\n"); + } + } else if (token_equals(result.token, ARGUMENT_COMMON_SEL_STACK_NEXT)) { + if (acting_window) { + struct window *next_window = window_manager_find_next_window_in_stack(&g_space_manager, &g_window_manager, acting_window); + if (next_window) { + result.window = next_window; + } else { + daemon_fail(rsp, "could not locate the next stacked window.\n"); + } + } else { + daemon_fail(rsp, "could not locate the selected window.\n"); + } } else if (token_is_valid(result.token)) { int wid = 0; if (token_to_int(result.token, &wid)) { @@ -1520,6 +1544,8 @@ static void handle_domain_window(FILE *rsp, struct token domain, char *message) enum window_op_error result = window_manager_stack_window(&g_space_manager, &g_window_manager, acting_window, selector.window); if (result == WINDOW_OP_ERROR_INVALID_SRC_NODE) { daemon_fail(rsp, "the acting window is not managed.\n"); + } else if (result == WINDOW_OP_ERROR_MAX_STACK) { + daemon_fail(rsp, "cannot stack window, max capacity of %d reached.\n", NODE_MAX_WINDOW_COUNT); } else if (result == WINDOW_OP_ERROR_SAME_WINDOW) { daemon_fail(rsp, "cannot stack a window onto itself.\n"); } diff --git a/src/view.c b/src/view.c index c6f65166..77f84293 100644 --- a/src/view.c +++ b/src/view.c @@ -81,14 +81,14 @@ void insert_feedback_show(struct window_node *node) CGPathAddLineToPoint(outline, NULL, x4, y4); SLSDisableUpdate(g_connection); - SLSOrderWindow(g_connection, node->feedback_window.id, 0, node->window_list[0]); + SLSOrderWindow(g_connection, node->feedback_window.id, 0, node->window_order[0]); SLSSetWindowShape(g_connection, node->feedback_window.id, 0.0f, 0.0f, frame_region); CGContextClearRect(node->feedback_window.context, frame); CGContextFillRect(node->feedback_window.context, fill); CGContextAddPath(node->feedback_window.context, outline); CGContextStrokePath(node->feedback_window.context); CGContextFlush(node->feedback_window.context); - SLSOrderWindow(g_connection, node->feedback_window.id, 1, node->window_list[0]); + SLSOrderWindow(g_connection, node->feedback_window.id, 1, node->window_order[0]); SLSReenableUpdate(g_connection); CGPathRelease(outline); CFRelease(frame_region); @@ -247,13 +247,17 @@ static void window_node_split(struct view *view, struct window_node *node, struc if (window_node_get_child(node) == CHILD_SECOND) { memcpy(left->window_list, node->window_list, sizeof(uint32_t) * node->window_count); + memcpy(left->window_order, node->window_order, sizeof(uint32_t) * node->window_count); left->window_count = node->window_count; right->window_list[0] = window->id; + right->window_order[0] = window->id; right->window_count = 1; } else { memcpy(right->window_list, node->window_list, sizeof(uint32_t) * node->window_count); + memcpy(right->window_order, node->window_order, sizeof(uint32_t) * node->window_count); right->window_count = node->window_count; left->window_list[0] = window->id; + left->window_order[0] = window->id; left->window_count = 1; } @@ -335,6 +339,28 @@ bool window_node_contains_window(struct window_node *node, uint32_t window_id) return false; } +void window_node_swap_window_list(struct window_node *a_node, struct window_node *b_node) +{ + uint32_t tmp_window_list[NODE_MAX_WINDOW_COUNT]; + uint32_t tmp_window_order[NODE_MAX_WINDOW_COUNT]; + uint32_t tmp_window_count; + + memcpy(tmp_window_list, a_node->window_list, sizeof(uint32_t) * a_node->window_count); + memcpy(tmp_window_order, a_node->window_order, sizeof(uint32_t) * a_node->window_count); + tmp_window_count = a_node->window_count; + + memcpy(a_node->window_list, b_node->window_list, sizeof(uint32_t) * b_node->window_count); + memcpy(a_node->window_order, b_node->window_order, sizeof(uint32_t) * b_node->window_count); + a_node->window_count = b_node->window_count; + + memcpy(b_node->window_list, tmp_window_list, sizeof(uint32_t) * tmp_window_count); + memcpy(b_node->window_order, tmp_window_order, sizeof(uint32_t) * tmp_window_count); + b_node->window_count = tmp_window_count; + + a_node->zoom = NULL; + b_node->zoom = NULL; +} + struct window_node *window_node_find_first_leaf(struct window_node *root) { struct window_node *node = root; @@ -521,15 +547,25 @@ void view_remove_window_node(struct view *view, struct window *window) if (!node) return; if (node->window_count > 1) { - for (int i = 0; i < node->window_count; ++i) { - if (node->window_list[i] != window->id) continue; + bool removed_entry = false; + bool removed_order = false; - memmove(node->window_list + i, node->window_list + i + 1, sizeof(uint32_t) * (node->window_count - i - 1)); - --node->window_count; + for (int i = 0; i < node->window_count; ++i) { + if (!removed_entry && node->window_list[i] == window->id) { + memmove(node->window_list + i, node->window_list + i + 1, sizeof(uint32_t) * (node->window_count - i - 1)); + removed_entry = true; + } - break; + if (!removed_order && node->window_order[i] == window->id) { + memmove(node->window_order + i, node->window_order + i + 1, sizeof(uint32_t) * (node->window_count - i - 1)); + removed_order = true; + } } + assert(removed_entry); + assert(removed_order); + --node->window_count; + return; } @@ -550,6 +586,7 @@ void view_remove_window_node(struct view *view, struct window *window) memcpy(parent->window_list, child->window_list, sizeof(uint32_t) * child->window_count); + memcpy(parent->window_order, child->window_order, sizeof(uint32_t) * child->window_count); parent->window_count = child->window_count; parent->left = NULL; @@ -596,7 +633,9 @@ void view_stack_window_node(struct view *view, struct window_node *node, struct window_manager_set_window_frame(window, node->area.x, node->area.y, node->area.w, node->area.h); } - node->window_list[node->window_count++] = window->id; + node->window_list[node->window_count] = window->id; + node->window_order[node->window_count] = window->id; + ++node->window_count; } void view_add_window_node(struct view *view, struct window *window) @@ -604,6 +643,7 @@ void view_add_window_node(struct view *view, struct window *window) if (!window_node_is_occupied(view->root) && window_node_is_leaf(view->root)) { view->root->window_list[0] = window->id; + view->root->window_order[0] = window->id; view->root->window_count = 1; } else { struct window_node *leaf = NULL; @@ -728,8 +768,8 @@ void view_serialize(FILE *rsp, struct view *view) space_is_visible(view->sid), view->sid == g_space_manager.current_space_id, space_is_fullscreen(view->sid), - first_leaf ? first_leaf->window_list[0] : 0, - last_leaf ? last_leaf->window_list[0] : 0); + first_leaf ? first_leaf->window_order[0] : 0, + last_leaf ? last_leaf->window_order[0] : 0); } void view_update(struct view *view) diff --git a/src/view.h b/src/view.h index c4177ec4..15450456 100644 --- a/src/view.h +++ b/src/view.h @@ -51,6 +51,7 @@ struct feedback_window CGContextRef context; }; +#define NODE_MAX_WINDOW_COUNT 32 struct window_node { struct area area; @@ -58,7 +59,8 @@ struct window_node struct window_node *left; struct window_node *right; struct window_node *zoom; - uint32_t window_list[64]; + uint32_t window_list[NODE_MAX_WINDOW_COUNT]; + uint32_t window_order[NODE_MAX_WINDOW_COUNT]; uint32_t window_count; float ratio; enum window_node_split split; @@ -111,6 +113,7 @@ void insert_feedback_destroy(struct window_node *node); void window_node_flush(struct window_node *node); void window_node_update(struct view *view, struct window_node *node); bool window_node_contains_window(struct window_node *node, uint32_t window_id); +void window_node_swap_window_list(struct window_node *a_node, struct window_node *b_node); struct window_node *window_node_find_first_leaf(struct window_node *root); struct window_node *window_node_find_last_leaf(struct window_node *root); struct window_node *window_node_find_prev_leaf(struct window_node *node); diff --git a/src/window_manager.c b/src/window_manager.c index d6ce04f4..63b0616e 100644 --- a/src/window_manager.c +++ b/src/window_manager.c @@ -638,7 +638,7 @@ struct window *window_manager_find_closest_managed_window_in_direction(struct wi struct window_node *closest = view_find_window_node_in_direction(view, node, direction); if (!closest) return NULL; - return window_manager_find_window(wm, closest->window_list[0]); + return window_manager_find_window(wm, closest->window_order[0]); } struct window *window_manager_find_prev_managed_window(struct space_manager *sm, struct window_manager *wm, struct window *window) @@ -652,7 +652,7 @@ struct window *window_manager_find_prev_managed_window(struct space_manager *sm, struct window_node *prev = window_node_find_prev_leaf(node); if (!prev) return NULL; - return window_manager_find_window(wm, prev->window_list[0]); + return window_manager_find_window(wm, prev->window_order[0]); } struct window *window_manager_find_next_managed_window(struct space_manager *sm, struct window_manager *wm, struct window *window) @@ -666,7 +666,7 @@ struct window *window_manager_find_next_managed_window(struct space_manager *sm, struct window_node *next = window_node_find_next_leaf(node); if (!next) return NULL; - return window_manager_find_window(wm, next->window_list[0]); + return window_manager_find_window(wm, next->window_order[0]); } struct window *window_manager_find_first_managed_window(struct space_manager *sm, struct window_manager *wm) @@ -677,7 +677,7 @@ struct window *window_manager_find_first_managed_window(struct space_manager *sm struct window_node *first = window_node_find_first_leaf(view->root); if (!first) return NULL; - return window_manager_find_window(wm, first->window_list[0]); + return window_manager_find_window(wm, first->window_order[0]); } struct window *window_manager_find_last_managed_window(struct space_manager *sm, struct window_manager *wm) @@ -688,7 +688,7 @@ struct window *window_manager_find_last_managed_window(struct space_manager *sm, struct window_node *last = window_node_find_last_leaf(view->root); if (!last) return NULL; - return window_manager_find_window(wm, last->window_list[0]); + return window_manager_find_window(wm, last->window_order[0]); } struct window *window_manager_find_recent_managed_window(struct space_manager *sm, struct window_manager *wm) @@ -702,6 +702,40 @@ struct window *window_manager_find_recent_managed_window(struct space_manager *s return window; } +struct window *window_manager_find_prev_window_in_stack(struct space_manager *sm, struct window_manager *wm, struct window *window) +{ + struct view *view = space_manager_find_view(sm, space_manager_active_space()); + if (!view) return NULL; + + struct window_node *node = view_find_window_node(view, window->id); + if (!node) return NULL; + + for (int i = 1; i < node->window_count; ++i) { + if (node->window_list[i] == window->id) { + return window_manager_find_window(wm, node->window_list[i-1]); + } + } + + return NULL; +} + +struct window *window_manager_find_next_window_in_stack(struct space_manager *sm, struct window_manager *wm, struct window *window) +{ + struct view *view = space_manager_find_view(sm, space_manager_active_space()); + if (!view) return NULL; + + struct window_node *node = view_find_window_node(view, window->id); + if (!node) return NULL; + + for (int i = 0; i < node->window_count - 1; ++i) { + if (node->window_list[i] == window->id) { + return window_manager_find_window(wm, node->window_list[i+1]); + } + } + + return NULL; +} + struct window *window_manager_find_largest_managed_window(struct space_manager *sm, struct window_manager *wm) { struct view *view = space_manager_find_view(sm, space_manager_active_space()); @@ -713,7 +747,7 @@ struct window *window_manager_find_largest_managed_window(struct space_manager * for (struct window_node *node = window_node_find_first_leaf(view->root); node != NULL; node = window_node_find_next_leaf(node)) { uint32_t area = node->area.w * node->area.h; if (area > best_area) { - best_id = node->window_list[0]; + best_id = node->window_order[0]; best_area = area; } } @@ -732,7 +766,7 @@ struct window *window_manager_find_smallest_managed_window(struct space_manager for (struct window_node *node = window_node_find_first_leaf(view->root); node != NULL; node = window_node_find_next_leaf(node)) { uint32_t area = node->area.w * node->area.h; if (area <= best_area) { - best_id = node->window_list[0]; + best_id = node->window_order[0]; best_area = area; } } @@ -1038,7 +1072,7 @@ enum window_op_error window_manager_set_window_insertion(struct space_manager *s } node->insert_dir = direction; - view->insertion_point = node->window_list[0]; + view->insertion_point = node->window_order[0]; insert_feedback_show(node); return WINDOW_OP_ERROR_SUCCESS; @@ -1063,7 +1097,7 @@ enum window_op_error window_manager_stack_window(struct space_manager *sm, struc } struct window_node *a_node = view_find_window_node(a_view, a->id); - assert(a_node); + if (a_node->window_count+1 >= NODE_MAX_WINDOW_COUNT) return WINDOW_OP_ERROR_MAX_STACK; view_stack_window_node(a_view, a_node, b); window_manager_add_managed_window(wm, b, a_view); @@ -1102,20 +1136,7 @@ enum window_op_error window_manager_warp_window(struct space_manager *sm, struct a_view->insertion_point = b->id; } - uint32_t tmp_window_list[64]; - uint32_t tmp_window_count; - - memcpy(tmp_window_list, a_node->window_list, sizeof(uint32_t) * a_node->window_count); - tmp_window_count = a_node->window_count; - - memcpy(a_node->window_list, b_node->window_list, sizeof(uint32_t) * b_node->window_count); - a_node->window_count = b_node->window_count; - - memcpy(b_node->window_list, tmp_window_list, sizeof(uint32_t) * tmp_window_count); - b_node->window_count = tmp_window_count; - - a_node->zoom = NULL; - b_node->zoom = NULL; + window_node_swap_window_list(a_node, b_node); window_node_flush(a_node); window_node_flush(b_node); @@ -1169,20 +1190,7 @@ enum window_op_error window_manager_swap_window(struct space_manager *sm, struct b_view->insertion_point = a->id; } - uint32_t tmp_window_list[64]; - uint32_t tmp_window_count; - - memcpy(tmp_window_list, a_node->window_list, sizeof(uint32_t) * a_node->window_count); - tmp_window_count = a_node->window_count; - - memcpy(a_node->window_list, b_node->window_list, sizeof(uint32_t) * b_node->window_count); - a_node->window_count = b_node->window_count; - - memcpy(b_node->window_list, tmp_window_list, sizeof(uint32_t) * tmp_window_count); - b_node->window_count = tmp_window_count; - - a_node->zoom = NULL; - b_node->zoom = NULL; + window_node_swap_window_list(a_node, b_node); if (a_view->sid != b_view->sid) { for (int i = 0; i < a_node->window_count; ++i) { diff --git a/src/window_manager.h b/src/window_manager.h index b117611d..2307bb64 100644 --- a/src/window_manager.h +++ b/src/window_manager.h @@ -35,6 +35,7 @@ enum window_op_error WINDOW_OP_ERROR_MINIMIZE_FAILED, WINDOW_OP_ERROR_NOT_MINIMIZED, WINDOW_OP_ERROR_DEMINIMIZE_FAILED, + WINDOW_OP_ERROR_MAX_STACK, }; enum purify_mode @@ -117,6 +118,8 @@ struct window *window_manager_find_next_managed_window(struct space_manager *sm, struct window *window_manager_find_first_managed_window(struct space_manager *sm, struct window_manager *wm); struct window *window_manager_find_last_managed_window(struct space_manager *sm, struct window_manager *wm); struct window *window_manager_find_recent_managed_window(struct space_manager *sm, struct window_manager *wm); +struct window *window_manager_find_prev_window_in_stack(struct space_manager *sm, struct window_manager *wm, struct window *window); +struct window *window_manager_find_next_window_in_stack(struct space_manager *sm, struct window_manager *wm, struct window *window); struct window *window_manager_find_largest_managed_window(struct space_manager *sm, struct window_manager *wm); struct window *window_manager_find_smallest_managed_window(struct space_manager *sm, struct window_manager *wm); void window_manager_focus_window_without_raise(ProcessSerialNumber *window_psn, uint32_t window_id);