feat: add maximize window functionality and MRU-based focus management
feat: add focus follow delay configuration feat: add demo mode timing configurations and wait conditions docs: update configuration documentation for new options
This commit is contained in:
parent
d0b1669cb4
commit
395583aea9
BIN
build/ai.o
BIN
build/ai.o
Binary file not shown.
BIN
build/atoms.o
BIN
build/atoms.o
Binary file not shown.
Binary file not shown.
@ -18,7 +18,7 @@ build/client.o: src/client.c include/client.h include/dwn.h \
|
||||
/usr/include/dbus-1.0/dbus/dbus-server.h \
|
||||
/usr/include/dbus-1.0/dbus/dbus-signature.h \
|
||||
/usr/include/dbus-1.0/dbus/dbus-syntax.h \
|
||||
/usr/include/dbus-1.0/dbus/dbus-threads.h
|
||||
/usr/include/dbus-1.0/dbus/dbus-threads.h include/layout.h
|
||||
include/client.h:
|
||||
include/dwn.h:
|
||||
include/atoms.h:
|
||||
@ -45,3 +45,4 @@ include/notifications.h:
|
||||
/usr/include/dbus-1.0/dbus/dbus-signature.h:
|
||||
/usr/include/dbus-1.0/dbus/dbus-syntax.h:
|
||||
/usr/include/dbus-1.0/dbus/dbus-threads.h:
|
||||
include/layout.h:
|
||||
|
||||
BIN
build/client.o
BIN
build/client.o
Binary file not shown.
BIN
build/config.o
BIN
build/config.o
Binary file not shown.
Binary file not shown.
BIN
build/demo.o
BIN
build/demo.o
Binary file not shown.
BIN
build/keys.o
BIN
build/keys.o
Binary file not shown.
BIN
build/layout.o
BIN
build/layout.o
Binary file not shown.
BIN
build/main.o
BIN
build/main.o
Binary file not shown.
BIN
build/news.o
BIN
build/news.o
Binary file not shown.
Binary file not shown.
BIN
build/panel.o
BIN
build/panel.o
Binary file not shown.
BIN
build/systray.o
BIN
build/systray.o
Binary file not shown.
BIN
build/util.o
BIN
build/util.o
Binary file not shown.
Binary file not shown.
@ -35,11 +35,14 @@ void client_update_title(Client *client);
|
||||
void client_update_class(Client *client);
|
||||
void client_set_fullscreen(Client *client, bool fullscreen);
|
||||
void client_toggle_fullscreen(Client *client);
|
||||
void client_set_maximize(Client *client, bool maximized);
|
||||
void client_toggle_maximize(Client *client);
|
||||
void client_set_floating(Client *client, bool floating);
|
||||
void client_toggle_floating(Client *client);
|
||||
|
||||
bool client_is_floating(Client *client);
|
||||
bool client_is_fullscreen(Client *client);
|
||||
bool client_is_maximized(Client *client);
|
||||
bool client_is_minimized(Client *client);
|
||||
bool client_is_dialog(Window window);
|
||||
bool client_is_dock(Window window);
|
||||
|
||||
@ -31,6 +31,7 @@ struct Config {
|
||||
char launcher[128];
|
||||
char file_manager[128];
|
||||
FocusMode focus_mode;
|
||||
int focus_follow_delay_ms;
|
||||
bool show_decorations;
|
||||
|
||||
int border_width;
|
||||
@ -58,6 +59,10 @@ struct Config {
|
||||
bool autostart_enabled;
|
||||
bool autostart_xdg;
|
||||
char autostart_path[512];
|
||||
|
||||
int demo_step_delay_ms;
|
||||
int demo_ai_timeout_ms;
|
||||
int demo_window_timeout_ms;
|
||||
};
|
||||
|
||||
Config *config_create(void);
|
||||
|
||||
@ -23,6 +23,14 @@ typedef enum {
|
||||
DEMO_COMPLETE
|
||||
} DemoPhase;
|
||||
|
||||
typedef enum {
|
||||
DEMO_WAIT_NONE,
|
||||
DEMO_WAIT_TIME,
|
||||
DEMO_WAIT_WINDOW_SPAWN,
|
||||
DEMO_WAIT_AI_RESPONSE,
|
||||
DEMO_WAIT_EXA_RESPONSE
|
||||
} DemoWaitCondition;
|
||||
|
||||
void demo_init(void);
|
||||
void demo_cleanup(void);
|
||||
void demo_start(void);
|
||||
|
||||
@ -58,7 +58,8 @@ typedef enum {
|
||||
CLIENT_FULLSCREEN = (1 << 1),
|
||||
CLIENT_URGENT = (1 << 2),
|
||||
CLIENT_MINIMIZED = (1 << 3),
|
||||
CLIENT_STICKY = (1 << 4)
|
||||
CLIENT_STICKY = (1 << 4),
|
||||
CLIENT_MAXIMIZED = (1 << 5)
|
||||
} ClientFlags;
|
||||
|
||||
typedef struct Client Client;
|
||||
@ -81,6 +82,8 @@ struct Client {
|
||||
char class[64];
|
||||
Client *next;
|
||||
Client *prev;
|
||||
Client *mru_next;
|
||||
Client *mru_prev;
|
||||
};
|
||||
|
||||
struct Monitor {
|
||||
@ -93,6 +96,8 @@ struct Monitor {
|
||||
struct Workspace {
|
||||
Client *clients;
|
||||
Client *focused;
|
||||
Client *mru_head;
|
||||
Client *mru_tail;
|
||||
LayoutType layout;
|
||||
float master_ratio;
|
||||
int master_count;
|
||||
@ -142,6 +147,9 @@ typedef struct {
|
||||
int drag_orig_x, drag_orig_y;
|
||||
int drag_orig_w, drag_orig_h;
|
||||
bool resizing;
|
||||
|
||||
Client *pending_focus_client;
|
||||
long pending_focus_time;
|
||||
} DWNState;
|
||||
|
||||
extern DWNState *dwn;
|
||||
|
||||
@ -50,4 +50,8 @@ void workspace_focus_next(void);
|
||||
void workspace_focus_prev(void);
|
||||
void workspace_focus_master(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);
|
||||
|
||||
#endif
|
||||
|
||||
@ -93,6 +93,11 @@
|
||||
<td><code>click</code></td>
|
||||
<td><code>click</code> or <code>follow</code> (sloppy focus)</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><code>focus_follow_delay</code></td>
|
||||
<td><code>100</code></td>
|
||||
<td>Delay in ms before focus switches in follow mode (0-1000)</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><code>decorations</code></td>
|
||||
<td><code>true</code></td>
|
||||
@ -109,7 +114,8 @@
|
||||
terminal = alacritty
|
||||
launcher = rofi -show run
|
||||
file_manager = nautilus
|
||||
focus_mode = click
|
||||
focus_mode = follow
|
||||
focus_follow_delay = 100
|
||||
decorations = true</code></pre>
|
||||
<h2 id="appearance" style="margin-top: 3rem;">[appearance] - Visual Settings</h2>
|
||||
<p style="color: var(--text-muted); margin-bottom: 1.5rem;">
|
||||
@ -432,6 +438,42 @@ path = ~/.config/dwn/autostart.d</code></pre>
|
||||
<li><code>~/.config/autostart/</code> - User XDG autostart entries</li>
|
||||
<li><code>~/.config/dwn/autostart.d/</code> - DWN-specific symlinks and scripts</li>
|
||||
</ul>
|
||||
<h2 id="demo" style="margin-top: 3rem;">[demo] - Demo Mode</h2>
|
||||
<p style="color: var(--text-muted); margin-bottom: 1.5rem;">
|
||||
Configure demo mode timing. The demo showcases DWN features including live AI and search functionality.
|
||||
</p>
|
||||
<div class="table-wrapper">
|
||||
<table>
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Option</th>
|
||||
<th>Description</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr>
|
||||
<td><code>step_delay</code></td>
|
||||
<td>Time between demo steps in milliseconds (1000-30000, default: 4000)</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><code>ai_timeout</code></td>
|
||||
<td>Timeout for AI/Exa API responses in milliseconds (5000-60000, default: 15000)</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><code>window_timeout</code></td>
|
||||
<td>Timeout for window spawn operations in milliseconds (1000-30000, default: 5000)</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
<div class="code-header">
|
||||
<span>Example</span>
|
||||
<button class="copy-btn" onclick="copyCode(this)">Copy</button>
|
||||
</div>
|
||||
<pre><code>[demo]
|
||||
step_delay = 4000
|
||||
ai_timeout = 15000
|
||||
window_timeout = 5000</code></pre>
|
||||
<h2 style="margin-top: 3rem;">Complete Configuration Example</h2>
|
||||
<div class="code-header">
|
||||
<span>~/.config/dwn/config</span>
|
||||
@ -444,6 +486,7 @@ terminal = alacritty
|
||||
launcher = rofi -show drun
|
||||
file_manager = thunar
|
||||
focus_mode = click
|
||||
focus_follow_delay = 100
|
||||
decorations = true
|
||||
[appearance]
|
||||
border_width = 2
|
||||
@ -478,7 +521,11 @@ model = google/gemini-2.0-flash-exp:free
|
||||
[autostart]
|
||||
enabled = true
|
||||
xdg_autostart = true
|
||||
path = ~/.config/dwn/autostart.d</code></pre>
|
||||
path = ~/.config/dwn/autostart.d
|
||||
[demo]
|
||||
step_delay = 4000
|
||||
ai_timeout = 15000
|
||||
window_timeout = 5000</code></pre>
|
||||
</div>
|
||||
</section>
|
||||
</main>
|
||||
|
||||
91
src/client.c
91
src/client.c
@ -11,6 +11,7 @@
|
||||
#include "workspace.h"
|
||||
#include "decorations.h"
|
||||
#include "notifications.h"
|
||||
#include "layout.h"
|
||||
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
@ -43,6 +44,8 @@ Client *client_create(Window window)
|
||||
client->workspace = dwn->current_workspace;
|
||||
client->next = NULL;
|
||||
client->prev = NULL;
|
||||
client->mru_next = NULL;
|
||||
client->mru_prev = NULL;
|
||||
|
||||
XWindowAttributes wa;
|
||||
int orig_width = 640, orig_height = 480;
|
||||
@ -242,6 +245,9 @@ void client_unmanage(Client *client)
|
||||
|
||||
LOG_DEBUG("Unmanaging window: %lu", client->window);
|
||||
|
||||
client_sync_log("client_unmanage: remove from MRU");
|
||||
workspace_mru_remove(client->workspace, client);
|
||||
|
||||
client_sync_log("client_unmanage: remove from workspace");
|
||||
workspace_remove_client(client->workspace, client);
|
||||
|
||||
@ -258,14 +264,22 @@ void client_unmanage(Client *client)
|
||||
client_destroy(client);
|
||||
|
||||
client_sync_log("client_unmanage: focus next");
|
||||
XGrabServer(dwn->display);
|
||||
|
||||
Workspace *ws = workspace_get_current();
|
||||
if (ws != NULL && ws->focused == NULL) {
|
||||
Client *next = workspace_get_first_client(dwn->current_workspace);
|
||||
Client *next = workspace_mru_get_previous(dwn->current_workspace, NULL);
|
||||
if (next != NULL) {
|
||||
client_focus(next);
|
||||
} else {
|
||||
XSetInputFocus(dwn->display, dwn->root, RevertToPointerRoot, CurrentTime);
|
||||
atoms_set_active_window(None);
|
||||
}
|
||||
}
|
||||
|
||||
XUngrabServer(dwn->display);
|
||||
XSync(dwn->display, False);
|
||||
|
||||
client_sync_log("client_unmanage: DONE");
|
||||
}
|
||||
|
||||
@ -336,6 +350,7 @@ void client_focus(Client *client)
|
||||
|
||||
if (ws != NULL) {
|
||||
ws->focused = client;
|
||||
workspace_mru_push(client->workspace, client);
|
||||
}
|
||||
|
||||
client_sync_log("client_focus: raising");
|
||||
@ -672,6 +687,80 @@ void client_toggle_floating(Client *client)
|
||||
client_set_floating(client, !(client->flags & CLIENT_FLOATING));
|
||||
}
|
||||
|
||||
bool client_is_maximized(Client *client)
|
||||
{
|
||||
return client != NULL && (client->flags & CLIENT_MAXIMIZED);
|
||||
}
|
||||
|
||||
void client_set_maximize(Client *client, bool maximized)
|
||||
{
|
||||
if (client == NULL || dwn == NULL || dwn->display == NULL) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (client->window == None) {
|
||||
return;
|
||||
}
|
||||
|
||||
XWindowAttributes wa;
|
||||
if (!XGetWindowAttributes(dwn->display, client->window, &wa)) {
|
||||
LOG_WARN("client_set_maximize: window %lu no longer exists", client->window);
|
||||
return;
|
||||
}
|
||||
|
||||
if (maximized) {
|
||||
if (!(client->flags & CLIENT_MAXIMIZED)) {
|
||||
client->old_x = client->x;
|
||||
client->old_y = client->y;
|
||||
client->old_width = client->width;
|
||||
client->old_height = client->height;
|
||||
}
|
||||
|
||||
client->flags |= CLIENT_MAXIMIZED;
|
||||
client->flags |= CLIENT_FLOATING;
|
||||
|
||||
atoms_update_wm_state(client->window, ewmh.NET_WM_STATE_MAXIMIZED_VERT, true);
|
||||
atoms_update_wm_state(client->window, ewmh.NET_WM_STATE_MAXIMIZED_HORZ, true);
|
||||
|
||||
int area_x, area_y, area_width, area_height;
|
||||
layout_get_usable_area(&area_x, &area_y, &area_width, &area_height);
|
||||
|
||||
int gap = config_get_gap();
|
||||
int title_height = config_get_title_height();
|
||||
int border = client->border_width;
|
||||
|
||||
client->x = area_x + gap + border;
|
||||
client->y = area_y + gap + title_height + border;
|
||||
client->width = area_width - 2 * gap - 2 * border;
|
||||
client->height = area_height - 2 * gap - title_height - 2 * border;
|
||||
|
||||
client_configure(client);
|
||||
decorations_render(client, true);
|
||||
client_raise(client);
|
||||
} else {
|
||||
client->flags &= ~CLIENT_MAXIMIZED;
|
||||
|
||||
atoms_update_wm_state(client->window, ewmh.NET_WM_STATE_MAXIMIZED_VERT, false);
|
||||
atoms_update_wm_state(client->window, ewmh.NET_WM_STATE_MAXIMIZED_HORZ, false);
|
||||
|
||||
client->x = client->old_x;
|
||||
client->y = client->old_y;
|
||||
client->width = client->old_width;
|
||||
client->height = client->old_height;
|
||||
|
||||
client_configure(client);
|
||||
decorations_render(client, true);
|
||||
}
|
||||
}
|
||||
|
||||
void client_toggle_maximize(Client *client)
|
||||
{
|
||||
if (client == NULL) {
|
||||
return;
|
||||
}
|
||||
client_set_maximize(client, !(client->flags & CLIENT_MAXIMIZED));
|
||||
}
|
||||
|
||||
|
||||
bool client_is_floating(Client *client)
|
||||
{
|
||||
|
||||
19
src/config.c
19
src/config.c
@ -53,6 +53,7 @@ void config_set_defaults(Config *cfg)
|
||||
strncpy(cfg->launcher, "dmenu_run", sizeof(cfg->launcher) - 1);
|
||||
strncpy(cfg->file_manager, "thunar", sizeof(cfg->file_manager) - 1);
|
||||
cfg->focus_mode = FOCUS_CLICK;
|
||||
cfg->focus_follow_delay_ms = 100;
|
||||
cfg->show_decorations = true;
|
||||
|
||||
cfg->border_width = DEFAULT_BORDER_WIDTH;
|
||||
@ -83,6 +84,10 @@ void config_set_defaults(Config *cfg)
|
||||
strncpy(cfg->autostart_path, autostart_path, sizeof(cfg->autostart_path) - 1);
|
||||
dwn_free(autostart_path);
|
||||
}
|
||||
|
||||
cfg->demo_step_delay_ms = 4000;
|
||||
cfg->demo_ai_timeout_ms = 15000;
|
||||
cfg->demo_window_timeout_ms = 5000;
|
||||
}
|
||||
|
||||
|
||||
@ -110,6 +115,9 @@ static void handle_config_entry(const char *section, const char *key,
|
||||
} else {
|
||||
cfg->focus_mode = FOCUS_CLICK;
|
||||
}
|
||||
} else if (strcmp(key, "focus_follow_delay") == 0) {
|
||||
int val = atoi(value);
|
||||
cfg->focus_follow_delay_ms = (val >= 0 && val <= 1000) ? val : 100;
|
||||
} else if (strcmp(key, "decorations") == 0) {
|
||||
cfg->show_decorations = (strcmp(value, "true") == 0 || strcmp(value, "1") == 0);
|
||||
}
|
||||
@ -172,6 +180,17 @@ static void handle_config_entry(const char *section, const char *key,
|
||||
dwn_free(expanded);
|
||||
}
|
||||
}
|
||||
} else if (strcmp(section, "demo") == 0) {
|
||||
if (strcmp(key, "step_delay") == 0) {
|
||||
int val = atoi(value);
|
||||
cfg->demo_step_delay_ms = (val >= 1000 && val <= 30000) ? val : 4000;
|
||||
} else if (strcmp(key, "ai_timeout") == 0) {
|
||||
int val = atoi(value);
|
||||
cfg->demo_ai_timeout_ms = (val >= 5000 && val <= 60000) ? val : 15000;
|
||||
} else if (strcmp(key, "window_timeout") == 0) {
|
||||
int val = atoi(value);
|
||||
cfg->demo_window_timeout_ms = (val >= 1000 && val <= 30000) ? val : 5000;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
778
src/demo.c
778
src/demo.c
File diff suppressed because it is too large
Load Diff
@ -608,7 +608,7 @@ void key_toggle_maximize(void)
|
||||
{
|
||||
Workspace *ws = workspace_get_current();
|
||||
if (ws != NULL && ws->focused != NULL) {
|
||||
client_toggle_fullscreen(ws->focused);
|
||||
client_toggle_maximize(ws->focused);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
51
src/main.c
51
src/main.c
@ -369,7 +369,29 @@ static void handle_enter_notify(XCrossingEvent *ev)
|
||||
}
|
||||
|
||||
if (c != NULL && c->workspace == (unsigned int)dwn->current_workspace) {
|
||||
client_focus(c);
|
||||
int delay = dwn->config->focus_follow_delay_ms;
|
||||
if (delay <= 0) {
|
||||
client_focus(c);
|
||||
} else {
|
||||
dwn->pending_focus_client = c;
|
||||
dwn->pending_focus_time = get_time_ms() + delay;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void handle_leave_notify(XCrossingEvent *ev)
|
||||
{
|
||||
if (ev == NULL || dwn == NULL) {
|
||||
return;
|
||||
}
|
||||
|
||||
Client *c = client_find_by_frame(ev->window);
|
||||
if (c == NULL) {
|
||||
c = client_find_by_window(ev->window);
|
||||
}
|
||||
|
||||
if (c != NULL && dwn->pending_focus_client == c) {
|
||||
dwn->pending_focus_client = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
@ -568,6 +590,17 @@ static void handle_client_message(XClientMessageEvent *ev)
|
||||
client_set_fullscreen(c, set);
|
||||
}
|
||||
}
|
||||
|
||||
if (prop1 == ewmh.NET_WM_STATE_MAXIMIZED_VERT ||
|
||||
prop1 == ewmh.NET_WM_STATE_MAXIMIZED_HORZ ||
|
||||
prop2 == ewmh.NET_WM_STATE_MAXIMIZED_VERT ||
|
||||
prop2 == ewmh.NET_WM_STATE_MAXIMIZED_HORZ) {
|
||||
if (toggle) {
|
||||
client_toggle_maximize(c);
|
||||
} else {
|
||||
client_set_maximize(c, set);
|
||||
}
|
||||
}
|
||||
}
|
||||
} else if (ev->message_type == ewmh.NET_CURRENT_DESKTOP) {
|
||||
int desktop = ev->data.l[0];
|
||||
@ -635,6 +668,9 @@ void dwn_handle_event(XEvent *ev)
|
||||
case EnterNotify:
|
||||
handle_enter_notify(&ev->xcrossing);
|
||||
break;
|
||||
case LeaveNotify:
|
||||
handle_leave_notify(&ev->xcrossing);
|
||||
break;
|
||||
case ButtonPress:
|
||||
handle_button_press(&ev->xbutton);
|
||||
break;
|
||||
@ -840,6 +876,19 @@ void dwn_run(void)
|
||||
|
||||
notifications_update();
|
||||
|
||||
if (dwn->pending_focus_client != NULL) {
|
||||
long now_focus = get_time_ms();
|
||||
if (now_focus >= dwn->pending_focus_time) {
|
||||
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);
|
||||
}
|
||||
}
|
||||
dwn->pending_focus_client = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
long now = get_time_ms();
|
||||
|
||||
if (now - last_news_update >= 16) {
|
||||
|
||||
@ -391,12 +391,11 @@ void panel_render_taskbar(Panel *panel, int x, int *width)
|
||||
XFillRectangle(dpy, panel->buffer, dwn->gc,
|
||||
current_x, 2, item_width - 2, panel->height - 4);
|
||||
|
||||
char title[64];
|
||||
char title[260];
|
||||
if (minimized) {
|
||||
snprintf(title, sizeof(title), "[%s]", c->title);
|
||||
} else {
|
||||
strncpy(title, c->title, sizeof(title) - 1);
|
||||
title[sizeof(title) - 1] = '\0';
|
||||
snprintf(title, sizeof(title), "%s", c->title);
|
||||
}
|
||||
|
||||
int max_text_width = item_width - 8;
|
||||
|
||||
@ -29,6 +29,8 @@ void workspace_init(void)
|
||||
|
||||
ws->clients = NULL;
|
||||
ws->focused = NULL;
|
||||
ws->mru_head = NULL;
|
||||
ws->mru_tail = NULL;
|
||||
ws->layout = (dwn->config != NULL) ?
|
||||
dwn->config->default_layout : LAYOUT_TILING;
|
||||
ws->master_ratio = (dwn->config != NULL) ?
|
||||
@ -444,3 +446,75 @@ void workspace_focus_master(void)
|
||||
client_focus(master);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void workspace_mru_push(int workspace, Client *client)
|
||||
{
|
||||
if (client == NULL || workspace < 0 || workspace >= MAX_WORKSPACES) {
|
||||
return;
|
||||
}
|
||||
|
||||
Workspace *ws = workspace_get(workspace);
|
||||
if (ws == NULL) {
|
||||
return;
|
||||
}
|
||||
|
||||
workspace_mru_remove(workspace, client);
|
||||
|
||||
client->mru_next = ws->mru_head;
|
||||
client->mru_prev = NULL;
|
||||
|
||||
if (ws->mru_head != NULL) {
|
||||
ws->mru_head->mru_prev = client;
|
||||
}
|
||||
ws->mru_head = client;
|
||||
|
||||
if (ws->mru_tail == NULL) {
|
||||
ws->mru_tail = client;
|
||||
}
|
||||
}
|
||||
|
||||
void workspace_mru_remove(int workspace, Client *client)
|
||||
{
|
||||
if (client == NULL || workspace < 0 || workspace >= MAX_WORKSPACES) {
|
||||
return;
|
||||
}
|
||||
|
||||
Workspace *ws = workspace_get(workspace);
|
||||
if (ws == NULL) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (client->mru_prev != NULL) {
|
||||
client->mru_prev->mru_next = client->mru_next;
|
||||
} else if (ws->mru_head == client) {
|
||||
ws->mru_head = client->mru_next;
|
||||
}
|
||||
|
||||
if (client->mru_next != NULL) {
|
||||
client->mru_next->mru_prev = client->mru_prev;
|
||||
} else if (ws->mru_tail == client) {
|
||||
ws->mru_tail = client->mru_prev;
|
||||
}
|
||||
|
||||
client->mru_next = NULL;
|
||||
client->mru_prev = NULL;
|
||||
}
|
||||
|
||||
Client *workspace_mru_get_previous(int workspace, Client *current)
|
||||
{
|
||||
Workspace *ws = workspace_get(workspace);
|
||||
if (ws == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
Client *candidate = ws->mru_head;
|
||||
while (candidate != NULL) {
|
||||
if (candidate != current && !client_is_minimized(candidate)) {
|
||||
return candidate;
|
||||
}
|
||||
candidate = candidate->mru_next;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
Loading…
Reference in New Issue
Block a user