chore: add alt-tab navigation with update_mru flag and MRU-based taskbar rendering
This commit is contained in:
BIN
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
+1
-1
@@ -18,7 +18,7 @@ void client_unmanage(Client *client);
|
||||
Client *client_find_by_window(Window window);
|
||||
Client *client_find_by_frame(Window frame);
|
||||
|
||||
void client_focus(Client *client);
|
||||
void client_focus(Client *client, bool update_mru);
|
||||
void client_unfocus(Client *client);
|
||||
void client_raise(Client *client);
|
||||
void client_lower(Client *client);
|
||||
|
||||
@@ -171,6 +171,9 @@ typedef struct {
|
||||
|
||||
Client *pending_focus_client;
|
||||
long pending_focus_time;
|
||||
|
||||
bool is_alt_tabbing;
|
||||
Client *alt_tab_client;
|
||||
} DWNState;
|
||||
|
||||
extern DWNState *dwn;
|
||||
|
||||
@@ -50,6 +50,10 @@ void workspace_focus_next(void);
|
||||
void workspace_focus_prev(void);
|
||||
void workspace_focus_master(void);
|
||||
|
||||
void workspace_alt_tab_next(void);
|
||||
void workspace_alt_tab_prev(void);
|
||||
void workspace_end_alt_tab(void);
|
||||
|
||||
void workspace_mru_push(int workspace, Client *client);
|
||||
void workspace_mru_remove(int workspace, Client *client);
|
||||
Client *workspace_mru_get_previous(int workspace, Client *current);
|
||||
|
||||
@@ -111,7 +111,7 @@ static void handle_command(struct mg_connection *c, cJSON *json) {
|
||||
if (cl->workspace != (unsigned int)dwn->current_workspace) {
|
||||
workspace_switch(cl->workspace);
|
||||
}
|
||||
client_focus(cl);
|
||||
client_focus(cl, true);
|
||||
handle_get_status(c);
|
||||
}
|
||||
}
|
||||
|
||||
+13
-7
@@ -232,7 +232,7 @@ Client *client_manage(Window window)
|
||||
client_show(client);
|
||||
|
||||
client_sync_log("client_manage: focusing");
|
||||
client_focus(client);
|
||||
client_focus(client, true);
|
||||
|
||||
client_sync_log("client_manage: DONE");
|
||||
return client;
|
||||
@@ -249,6 +249,10 @@ void client_unmanage(Client *client)
|
||||
|
||||
LOG_DEBUG("Unmanaging window: %lu", client->window);
|
||||
|
||||
if (dwn->alt_tab_client == client) {
|
||||
workspace_end_alt_tab();
|
||||
}
|
||||
|
||||
client_sync_log("client_unmanage: remove from MRU");
|
||||
workspace_mru_remove(client->workspace, client);
|
||||
|
||||
@@ -274,7 +278,7 @@ void client_unmanage(Client *client)
|
||||
if (ws != NULL && ws->focused == NULL) {
|
||||
Client *next = workspace_mru_get_previous(dwn->current_workspace, NULL);
|
||||
if (next != NULL) {
|
||||
client_focus(next);
|
||||
client_focus(next, true);
|
||||
} else {
|
||||
XSetInputFocus(dwn->display, dwn->root, RevertToPointerRoot, CurrentTime);
|
||||
atoms_set_active_window(None);
|
||||
@@ -316,7 +320,7 @@ Client *client_find_by_frame(Window frame)
|
||||
}
|
||||
|
||||
|
||||
void client_focus(Client *client)
|
||||
void client_focus(Client *client, bool update_mru)
|
||||
{
|
||||
client_sync_log("client_focus: START");
|
||||
|
||||
@@ -354,7 +358,9 @@ void client_focus(Client *client)
|
||||
|
||||
if (ws != NULL) {
|
||||
ws->focused = client;
|
||||
workspace_mru_push(client->workspace, client);
|
||||
if (update_mru) {
|
||||
workspace_mru_push(client->workspace, client);
|
||||
}
|
||||
}
|
||||
|
||||
client_sync_log("client_focus: raising");
|
||||
@@ -442,7 +448,7 @@ void client_minimize(Client *client)
|
||||
if (ws != NULL && ws->focused == client) {
|
||||
Client *next = workspace_mru_get_previous(client->workspace, client);
|
||||
if (next != NULL) {
|
||||
client_focus(next);
|
||||
client_focus(next, true);
|
||||
} else {
|
||||
ws->focused = NULL;
|
||||
XSetInputFocus(dwn->display, dwn->root, RevertToPointerRoot, CurrentTime);
|
||||
@@ -459,7 +465,7 @@ void client_restore(Client *client)
|
||||
|
||||
client->flags &= ~CLIENT_MINIMIZED;
|
||||
client_show(client);
|
||||
client_focus(client);
|
||||
client_focus(client, true);
|
||||
}
|
||||
|
||||
|
||||
@@ -848,7 +854,7 @@ void client_set_maximize(Client *client, bool maximized)
|
||||
client_configure(client);
|
||||
decorations_render(client, true);
|
||||
client_raise(client);
|
||||
client_focus(client);
|
||||
client_focus(client, true);
|
||||
} else {
|
||||
client->flags &= ~CLIENT_MAXIMIZED;
|
||||
|
||||
|
||||
+6
-2
@@ -457,6 +457,10 @@ void keys_handle_release(XKeyEvent *ev)
|
||||
super_pressed = false;
|
||||
super_used_in_combo = false;
|
||||
}
|
||||
|
||||
if (keysym == XK_Alt_L || keysym == XK_Alt_R) {
|
||||
workspace_end_alt_tab();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -629,12 +633,12 @@ void key_toggle_minimize(void)
|
||||
|
||||
void key_focus_next(void)
|
||||
{
|
||||
workspace_focus_next();
|
||||
workspace_alt_tab_next();
|
||||
}
|
||||
|
||||
void key_focus_prev(void)
|
||||
{
|
||||
workspace_focus_prev();
|
||||
workspace_alt_tab_prev();
|
||||
}
|
||||
|
||||
void key_workspace_next(void)
|
||||
|
||||
+5
-5
@@ -377,7 +377,7 @@ static void handle_enter_notify(XCrossingEvent *ev)
|
||||
if (c != NULL && c->workspace == (unsigned int)dwn->current_workspace) {
|
||||
int delay = dwn->config->focus_follow_delay_ms;
|
||||
if (delay <= 0) {
|
||||
client_focus(c);
|
||||
client_focus(c, true);
|
||||
} else {
|
||||
dwn->pending_focus_client = c;
|
||||
dwn->pending_focus_time = get_time_ms() + delay;
|
||||
@@ -453,11 +453,11 @@ static void handle_button_press(XButtonEvent *ev)
|
||||
|
||||
if (is_client_window) {
|
||||
XAllowEvents(dwn->display, ReplayPointer, ev->time);
|
||||
client_focus(c);
|
||||
client_focus(c, true);
|
||||
return;
|
||||
}
|
||||
|
||||
client_focus(c);
|
||||
client_focus(c, true);
|
||||
|
||||
if (c->frame != None && ev->window == c->frame) {
|
||||
ButtonType btn = decorations_hit_test_button(c, ev->x, ev->y);
|
||||
@@ -573,7 +573,7 @@ static void handle_client_message(XClientMessageEvent *ev)
|
||||
if (c->workspace != (unsigned int)dwn->current_workspace) {
|
||||
workspace_switch(c->workspace);
|
||||
}
|
||||
client_focus(c);
|
||||
client_focus(c, true);
|
||||
}
|
||||
} else if (ev->message_type == ewmh.NET_CLOSE_WINDOW) {
|
||||
if (c != NULL) {
|
||||
@@ -897,7 +897,7 @@ void dwn_run(void)
|
||||
Workspace *ws = workspace_get_current();
|
||||
if (ws != NULL && ws->focused != dwn->pending_focus_client) {
|
||||
if (dwn->pending_focus_client->workspace == (unsigned int)dwn->current_workspace) {
|
||||
client_focus(dwn->pending_focus_client);
|
||||
client_focus(dwn->pending_focus_client, true);
|
||||
}
|
||||
}
|
||||
dwn->pending_focus_client = NULL;
|
||||
|
||||
+22
-20
@@ -372,10 +372,14 @@ void panel_render_taskbar(Panel *panel, int x, int *width)
|
||||
if (available_width < 0) available_width = 0;
|
||||
int item_count = 0;
|
||||
|
||||
for (Client *c = dwn->client_list; c != NULL; c = c->next) {
|
||||
if (c->workspace == (unsigned int)dwn->current_workspace) {
|
||||
item_count++;
|
||||
}
|
||||
Workspace *ws = workspace_get_current();
|
||||
if (ws == NULL) {
|
||||
*width = 0;
|
||||
return;
|
||||
}
|
||||
|
||||
for (Client *c = ws->mru_head; c != NULL; c = c->mru_next) {
|
||||
item_count++;
|
||||
}
|
||||
|
||||
if (item_count == 0) {
|
||||
@@ -388,14 +392,12 @@ void panel_render_taskbar(Panel *panel, int x, int *width)
|
||||
item_width = TASKBAR_ITEM_WIDTH;
|
||||
}
|
||||
|
||||
Workspace *ws = workspace_get_current();
|
||||
|
||||
for (Client *c = dwn->client_list; c != NULL; c = c->next) {
|
||||
for (Client *c = ws->mru_head; c != NULL; c = c->mru_next) {
|
||||
if (c->workspace != (unsigned int)dwn->current_workspace) {
|
||||
continue;
|
||||
}
|
||||
|
||||
bool focused = (ws != NULL && ws->focused == c);
|
||||
bool focused = (ws->focused == c);
|
||||
bool minimized = client_is_minimized(c);
|
||||
|
||||
unsigned long bg;
|
||||
@@ -554,7 +556,7 @@ void panel_handle_click(Panel *panel, int x, int y, int button)
|
||||
if (ws != NULL && ws->focused == c) {
|
||||
client_minimize(c);
|
||||
} else {
|
||||
client_focus(c);
|
||||
client_focus(c, true);
|
||||
}
|
||||
}
|
||||
} else if (button == 3) {
|
||||
@@ -593,7 +595,11 @@ Client *panel_hit_test_taskbar(Panel *panel, int x, int y)
|
||||
}
|
||||
|
||||
Workspace *ws = workspace_get_current();
|
||||
const char *layout_symbol = layout_get_symbol(ws != NULL ? ws->layout : LAYOUT_TILING);
|
||||
if (ws == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
const char *layout_symbol = layout_get_symbol(ws->layout);
|
||||
int layout_width = panel_text_width(layout_symbol, strlen(layout_symbol));
|
||||
int taskbar_start = PANEL_PADDING + MAX_WORKSPACES * WORKSPACE_WIDTH + WIDGET_SPACING + layout_width + WIDGET_SPACING;
|
||||
if (x < taskbar_start) {
|
||||
@@ -607,10 +613,8 @@ Client *panel_hit_test_taskbar(Panel *panel, int x, int y)
|
||||
if (available_width < 0) available_width = 0;
|
||||
int item_count = 0;
|
||||
|
||||
for (Client *c = dwn->client_list; c != NULL; c = c->next) {
|
||||
if (c->workspace == (unsigned int)dwn->current_workspace) {
|
||||
item_count++;
|
||||
}
|
||||
for (Client *c = ws->mru_head; c != NULL; c = c->mru_next) {
|
||||
item_count++;
|
||||
}
|
||||
|
||||
if (item_count == 0) {
|
||||
@@ -625,13 +629,11 @@ Client *panel_hit_test_taskbar(Panel *panel, int x, int y)
|
||||
int index = (x - taskbar_start) / item_width;
|
||||
int i = 0;
|
||||
|
||||
for (Client *c = dwn->client_list; c != NULL; c = c->next) {
|
||||
if (c->workspace == (unsigned int)dwn->current_workspace) {
|
||||
if (i == index) {
|
||||
return c;
|
||||
}
|
||||
i++;
|
||||
for (Client *c = ws->mru_head; c != NULL; c = c->mru_next) {
|
||||
if (i == index) {
|
||||
return c;
|
||||
}
|
||||
i++;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
|
||||
+89
-5
@@ -95,11 +95,11 @@ void workspace_switch(int index)
|
||||
Workspace *ws = workspace_get(index);
|
||||
if (ws != NULL) {
|
||||
if (ws->focused != NULL) {
|
||||
client_focus(ws->focused);
|
||||
client_focus(ws->focused, true);
|
||||
} else {
|
||||
Client *first = workspace_get_first_client(index);
|
||||
if (first != NULL) {
|
||||
client_focus(first);
|
||||
client_focus(first, true);
|
||||
} else {
|
||||
XSetInputFocus(dwn->display, dwn->root, RevertToPointerRoot, CurrentTime);
|
||||
atoms_set_active_window(None);
|
||||
@@ -409,7 +409,7 @@ void workspace_focus_next(void)
|
||||
}
|
||||
|
||||
if (next != NULL && next != ws->focused) {
|
||||
client_focus(next);
|
||||
client_focus(next, true);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -435,7 +435,7 @@ void workspace_focus_prev(void)
|
||||
}
|
||||
|
||||
if (prev != NULL && prev != ws->focused) {
|
||||
client_focus(prev);
|
||||
client_focus(prev, true);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -443,7 +443,7 @@ void workspace_focus_master(void)
|
||||
{
|
||||
Client *master = workspace_get_first_client(dwn->current_workspace);
|
||||
if (master != NULL) {
|
||||
client_focus(master);
|
||||
client_focus(master, true);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -518,3 +518,87 @@ Client *workspace_mru_get_previous(int workspace, Client *current)
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void workspace_alt_tab_next(void)
|
||||
{
|
||||
if (dwn == NULL) return;
|
||||
|
||||
Workspace *ws = workspace_get_current();
|
||||
if (ws == NULL || ws->mru_head == NULL) return;
|
||||
|
||||
if (!dwn->is_alt_tabbing) {
|
||||
dwn->is_alt_tabbing = true;
|
||||
dwn->alt_tab_client = ws->focused;
|
||||
XGrabKeyboard(dwn->display, dwn->root, True,
|
||||
GrabModeAsync, GrabModeAsync, CurrentTime);
|
||||
}
|
||||
|
||||
Client *current = dwn->alt_tab_client;
|
||||
if (current == NULL) {
|
||||
current = ws->mru_head;
|
||||
}
|
||||
|
||||
if (current != NULL && current->mru_next != NULL) {
|
||||
dwn->alt_tab_client = current->mru_next;
|
||||
} else {
|
||||
dwn->alt_tab_client = ws->mru_head;
|
||||
}
|
||||
|
||||
if (dwn->alt_tab_client != NULL) {
|
||||
client_focus(dwn->alt_tab_client, false);
|
||||
}
|
||||
}
|
||||
|
||||
void workspace_alt_tab_prev(void)
|
||||
{
|
||||
if (dwn == NULL) return;
|
||||
|
||||
Workspace *ws = workspace_get_current();
|
||||
if (ws == NULL || ws->mru_head == NULL) return;
|
||||
|
||||
if (!dwn->is_alt_tabbing) {
|
||||
dwn->is_alt_tabbing = true;
|
||||
dwn->alt_tab_client = ws->focused;
|
||||
XGrabKeyboard(dwn->display, dwn->root, True,
|
||||
GrabModeAsync, GrabModeAsync, CurrentTime);
|
||||
}
|
||||
|
||||
Client *current = dwn->alt_tab_client;
|
||||
|
||||
|
||||
if (current != NULL && current->mru_prev != NULL) {
|
||||
dwn->alt_tab_client = current->mru_prev;
|
||||
} else {
|
||||
dwn->alt_tab_client = ws->mru_tail;
|
||||
}
|
||||
|
||||
if (dwn->alt_tab_client != NULL) {
|
||||
client_focus(dwn->alt_tab_client, false);
|
||||
}
|
||||
}
|
||||
|
||||
void workspace_end_alt_tab(void)
|
||||
{
|
||||
if (dwn == NULL || !dwn->is_alt_tabbing) return;
|
||||
|
||||
dwn->is_alt_tabbing = false;
|
||||
|
||||
if (dwn->alt_tab_client != NULL) {
|
||||
|
||||
workspace_mru_push(dwn->current_workspace, dwn->alt_tab_client);
|
||||
|
||||
/* Redraw panel to show new MRU order */
|
||||
|
||||
panel_render_all();
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
dwn->alt_tab_client = NULL;
|
||||
|
||||
XUngrabKeyboard(dwn->display, CurrentTime);
|
||||
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user