diff --git a/src/action.c b/src/action.c index fa2da2b..fd0066b 100644 --- a/src/action.c +++ b/src/action.c @@ -3,9 +3,28 @@ #include #include +#include "client.h" #include "monitor.h" +#include "types.h" #include "wm.h" +void focus_client_in_same_tag(const user_action_arg_t *arg) { + bool next = arg->b; + tag_t *tag = wm.current_monitor->selected_tag; + + task_in_tag_t *task = nullptr; + if (next) { + task = client_get_next_task_in_tag(wm.client_focused, tag); + } else { + task = client_get_previous_task_in_tag(wm.client_focused, tag); + } + + if (!task) return; + + client_stack_raise(task->client); + client_focus(task->client); +} + void select_tag_of_current_monitor(const user_action_arg_t *arg) { monitor_select_tag(wm.current_monitor, arg->ui); } diff --git a/src/action.h b/src/action.h index 374a30e..8c16804 100644 --- a/src/action.h +++ b/src/action.h @@ -48,6 +48,7 @@ typedef struct keyboard_t { const user_action_arg_t arg; } keyboard_t; +void focus_client_in_same_tag(const user_action_arg_t *arg); void select_tag_of_current_monitor(const user_action_arg_t *arg); void spawn(const user_action_arg_t *arg); void quit(const user_action_arg_t *arg); diff --git a/src/client.c b/src/client.c index 3801f2c..4dd91cd 100644 --- a/src/client.c +++ b/src/client.c @@ -58,6 +58,22 @@ task_in_tag_t *client_get_task_in_tag(client_t *client, tag_t *tag) { return nullptr; } +task_in_tag_t *client_get_next_task_in_tag(client_t *client, tag_t *tag) { + if (!tag->task_list) return nullptr; + + task_in_tag_t *task = tag->task_list; + for (; task && task->client != client; task = task->next); + return task && task->next ? task->next : tag->task_list; +} + +task_in_tag_t *client_get_previous_task_in_tag(client_t *client, tag_t *tag) { + if (!tag->task_list) return nullptr; + + task_in_tag_t *task = tag->task_list; + for (; task && task->next && task->next->client != client; task = task->next); + return task ? task : tag->task_list; +} + static void client_add_to_tag(client_t *client, tag_t *tag) { if (client_get_task_in_tag(client, tag)) return; @@ -191,6 +207,7 @@ void client_manage(xcb_window_t window, monitor_arrange(c->monitor); monitor_draw_bar(c->monitor); + wm_restack_clients(); if (c->tags & c->monitor->selected_tag->mask) client_focus(c); xcb_flush(wm.xcb_conn); @@ -279,6 +296,7 @@ void client_unmanage(client_t *client) { client_wipe(client); + wm_restack_clients(); monitor_deal_focus(m); monitor_arrange(m); monitor_draw_bar(m); @@ -303,6 +321,12 @@ void client_focus(client_t *client) { xwindow_focus(client ? client->window : XCB_WINDOW_NONE); } +void client_stack_raise(client_t *client) { + client_detach_stack(client); + client_attach_stack(client); + wm_restack_clients(); +} + bool client_is_visible(client_t *client) { return client->tags & client->monitor->selected_tag->mask; } diff --git a/src/client.h b/src/client.h index 7c62d99..680a7b8 100644 --- a/src/client.h +++ b/src/client.h @@ -7,6 +7,8 @@ client_t *client_get_by_window(xcb_window_t window); task_in_tag_t *client_get_task_in_tag(client_t *client, tag_t *tag); +task_in_tag_t *client_get_next_task_in_tag(client_t *client, tag_t *tag); +task_in_tag_t *client_get_previous_task_in_tag(client_t *client, tag_t *tag); void client_manage(xcb_window_t window, xcb_get_geometry_reply_t *geometry_reply); char **client_get_task_title(client_t *client); diff --git a/src/default_config.h b/src/default_config.h index 3a52ac4..d16d1e5 100644 --- a/src/default_config.h +++ b/src/default_config.h @@ -36,6 +36,8 @@ static const keyboard_t key_list[] = { {modifier_alt, XK_p, spawn, {.ptr = launcher}}, {modifier_alt, XK_q, quit, {.b = false}}, {modifier_alt, XK_r, quit, {.b = true}}, + {modifier_alt | modifier_shift, XK_j, focus_client_in_same_tag, {.b = true}}, + {modifier_alt | modifier_shift, XK_k, focus_client_in_same_tag, {.b = false}}, }; static const layout_t layout_list[] = { diff --git a/src/wm.c b/src/wm.c index 07b9928..9bd7401 100644 --- a/src/wm.c +++ b/src/wm.c @@ -390,6 +390,25 @@ void wm_quit(void) { } } +void wm_restack_clients(void) { + xcb_window_t sibling_window = XCB_WINDOW_NONE; + for (client_t *c = wm.client_stack_list; c; c = c->stack_next) { + uint16_t mask = XCB_CONFIG_WINDOW_STACK_MODE; + xcb_params_configure_window_t params = {}; + if (sibling_window == XCB_WINDOW_NONE) { + mask = XCB_CONFIG_WINDOW_STACK_MODE; + params.stack_mode = XCB_STACK_MODE_ABOVE; + } else { + mask = XCB_CONFIG_WINDOW_STACK_MODE | XCB_CONFIG_WINDOW_SIBLING; + params.stack_mode = XCB_STACK_MODE_BELOW; + params.sibling = sibling_window; + } + sibling_window = c->window; + xcb_aux_configure_window(wm.xcb_conn, c->window, mask, ¶ms); + } + xcb_flush(wm.xcb_conn); +} + static void debug_show_monitor_list(void) { logger("\n========================== monitors ==========================\n"); for (monitor_t *m = wm.monitor_list; m; m = m->next) { diff --git a/src/wm.h b/src/wm.h index b643a69..cbef2be 100644 --- a/src/wm.h +++ b/src/wm.h @@ -51,3 +51,4 @@ extern wm_t wm; void wm_restart(void); void wm_quit(void); +void wm_restack_clients(void);