feat: add maximize window support with MRU focus tracking and demo timing configs
Implement client maximize/unmaximize toggle and state tracking via CLIENT_MAXIMIZED flag, add MRU (most-recently-used) doubly-linked list per workspace for intelligent focus restoration on client unmanage, introduce configurable focus-follow delay (0-1000ms) for sloppy focus mode, and add demo mode timing parameters (step_delay, ai_timeout, window_timeout) with corresponding wait condition enum and configuration parsing in the [demo] section.
This commit is contained in:
BIN
Binary file not shown.
Binary file not shown.
Binary file not shown.
+2
-1
@@ -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:
|
||||
|
||||
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.
@@ -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);
|
||||
|
||||
+9
-1
@@ -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
|
||||
|
||||
+49
-2
@@ -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>
|
||||
|
||||
+90
-1
@@ -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)
|
||||
{
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+580
-198
File diff suppressed because it is too large
Load Diff
+1
-1
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+50
-1
@@ -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) {
|
||||
|
||||
+2
-3
@@ -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;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user