Handle single_monocle more carefully

Closes #919.
Fixes #730.
This commit is contained in:
Bastien Dejean 2019-01-31 20:29:10 +01:00
parent 644b9e591a
commit 00cf7896a4
11 changed files with 101 additions and 44 deletions

View file

@ -135,32 +135,41 @@ bool find_any_desktop(coordinates_t *ref, coordinates_t *dst, desktop_select_t *
return false;
}
bool set_layout(monitor_t *m, desktop_t *d, layout_t l)
bool set_layout(monitor_t *m, desktop_t *d, layout_t l, bool user)
{
layout_t actual_layout = IS_SINGLE_MONOCLE(d) ? LAYOUT_MONOCLE : l;
bool actual_layout_changed = (d->layout != actual_layout);
if (d->layout == l) {
if ((user && d->user_layout == l) || (!user && d->layout == l)) {
return false;
}
layout_t old_layout = d->layout;
if (user) {
d->user_layout = l;
} else {
d->layout = l;
handle_presel_feedbacks(m, d);
if (!actual_layout_changed) {
return true;
}
arrange(m, d);
if (user && (!single_monocle || tiled_count(d->root, true) > 1)) {
d->layout = l;
}
put_status(SBSC_MASK_DESKTOP_LAYOUT, "desktop_layout 0x%08X 0x%08X %s\n", m->id, d->id, LAYOUT_STR(actual_layout));
if (d->layout != old_layout) {
handle_presel_feedbacks(m, d);
if (user) {
arrange(m, d);
}
put_status(SBSC_MASK_DESKTOP_LAYOUT, "desktop_layout 0x%08X 0x%08X %s\n", m->id, d->id, LAYOUT_STR(d->layout));
if (d == m->desk) {
put_status(SBSC_MASK_REPORT);
}
return true;
} else {
return false;
}
}
void handle_presel_feedbacks(monitor_t *m, desktop_t *d)
@ -255,7 +264,7 @@ desktop_t *make_desktop(const char *name, uint32_t id)
}
d->prev = d->next = NULL;
d->root = d->focus = NULL;
d->layout = LAYOUT_TILED;
d->layout = d->user_layout = LAYOUT_TILED;
d->padding = (padding_t) PADDING;
d->window_gap = window_gap;
d->border_width = border_width;

View file

@ -31,7 +31,7 @@ void focus_desktop(monitor_t *m, desktop_t *d);
bool activate_desktop(monitor_t *m, desktop_t *d);
bool find_closest_desktop(coordinates_t *ref, coordinates_t *dst, cycle_dir_t dir, desktop_select_t *sel);
bool find_any_desktop(coordinates_t *ref, coordinates_t *dst, desktop_select_t *sel);
bool set_layout(monitor_t *m, desktop_t *d, layout_t l);
bool set_layout(monitor_t *m, desktop_t *d, layout_t l, bool user);
void handle_presel_feedbacks(monitor_t *m, desktop_t *d);
bool transfer_desktop(monitor_t *ms, monitor_t *md, desktop_t *d, bool follow);
desktop_t *make_desktop(const char *name, uint32_t id);

View file

@ -41,10 +41,6 @@
#define IS_FULLSCREEN(c) (c->state == STATE_FULLSCREEN)
#define IS_RECEPTACLE(n) (is_leaf(n) && n->client == NULL)
#define IS_SINGLE_MONOCLE(d) (single_monocle && tiled_count(d->root, true) <= 1)
#define IS_MONOCLE(d) (d->layout == LAYOUT_MONOCLE || IS_SINGLE_MONOCLE(d))
#define ACTUAL_LAYOUT(d) (IS_MONOCLE(d) ? LAYOUT_MONOCLE : d->layout)
#define BOOL_STR(A) ((A) ? "true" : "false")
#define ON_OFF_STR(A) ((A) ? "on" : "off")
#define LAYOUT_STR(A) ((A) == LAYOUT_TILED ? "tiled" : "monocle")

View file

@ -745,9 +745,9 @@ void cmd_desktop(char **args, int num, FILE *rsp)
layout_t lyt;
cycle_dir_t cyc;
if (parse_cycle_direction(*args, &cyc)) {
ret = set_layout(trg.monitor, trg.desktop, (trg.desktop->layout + 1) % 2);
ret = set_layout(trg.monitor, trg.desktop, (trg.desktop->layout + 1) % 2, true);
} else if (parse_layout(*args, &lyt)) {
ret = set_layout(trg.monitor, trg.desktop, lyt);
ret = set_layout(trg.monitor, trg.desktop, lyt, true);
} else {
fail(rsp, "desktop %s: Invalid argument: '%s'.\n", *(args - 1), *args);
break;
@ -1637,6 +1637,24 @@ void set_setting(coordinates_t loc, char *name, char *value, FILE *rsp)
fail(rsp, "config: %s: Invalid value: '%s'.\n", name, value);
return;
}
} else if (streq("single_monocle", name)) {
bool b;
if (parse_bool(value, &b)) {
if (b == single_monocle) {
fail(rsp, "");
return;
}
single_monocle = b;
for (monitor_t *m = mon_head; m != NULL; m = m->next) {
for (desktop_t *d = m->desk_head; d != NULL; d = d->next) {
layout_t l = (single_monocle && tiled_count(d->root, true) <= 1) ? LAYOUT_MONOCLE : d->user_layout;
set_layout(m, d, l, false);
}
}
} else {
fail(rsp, "config: %s: Invalid value: '%s'.\n", name, value);
return;
}
} else if (streq("focus_follows_pointer", name)) {
bool b;
if (parse_bool(value, &b)) {
@ -1674,8 +1692,6 @@ void set_setting(coordinates_t loc, char *name, char *value, FILE *rsp)
SET_BOOL(presel_feedback)
SET_BOOL(borderless_monocle)
SET_BOOL(gapless_monocle)
SET_BOOL(single_monocle)
put_status(SBSC_MASK_REPORT);
SET_BOOL(swallow_first_click)
SET_BOOL(pointer_follows_focus)
SET_BOOL(pointer_follows_monitor)

View file

@ -101,6 +101,7 @@ void query_desktop(desktop_t *d, FILE *rsp)
fprintf(rsp, "\"name\":\"%s\",", d->name);
fprintf(rsp, "\"id\":%u,", d->id);
fprintf(rsp, "\"layout\":\"%s\",", LAYOUT_STR(d->layout));
fprintf(rsp, "\"userLayout\":\"%s\",", LAYOUT_STR(d->user_layout));
fprintf(rsp, "\"windowGap\":%i,", d->window_gap);
fprintf(rsp, "\"borderWidth\":%u,", d->border_width);
fprintf(rsp, "\"focusedNodeId\":%u,", d->focus != NULL ? d->focus->id : 0);

View file

@ -314,6 +314,7 @@ desktop_t *restore_desktop(jsmntok_t **t, char *json)
snprintf(d->name, (*t)->end - (*t)->start + 1, "%s", json + (*t)->start);
RESTORE_UINT(id, &d->id)
RESTORE_ANY(layout, &d->layout, parse_layout)
RESTORE_ANY(userLayout, &d->user_layout, parse_layout)
RESTORE_INT(windowGap, &d->window_gap)
RESTORE_UINT(borderWidth, &d->border_width)
} else if (keyeq("focusedNodeId", *t, json)) {

View file

@ -101,7 +101,7 @@ int print_report(FILE *stream)
fprintf(stream, ":%c%s", c, d->name);
}
if (m->desk != NULL) {
fprintf(stream, ":L%c", LAYOUT_CHR(ACTUAL_LAYOUT(m->desk)));
fprintf(stream, ":L%c", LAYOUT_CHR(m->desk->layout));
if (m->desk->focus != NULL) {
node_t *n = m->desk->focus;
if (n->client != NULL) {

View file

@ -46,8 +46,6 @@ void arrange(monitor_t *m, desktop_t *d)
return;
}
layout_t l = ACTUAL_LAYOUT(d);
xcb_rectangle_t rect = m->rectangle;
rect.x += m->padding.left + d->padding.left;
@ -55,24 +53,24 @@ void arrange(monitor_t *m, desktop_t *d)
rect.width -= m->padding.left + d->padding.left + d->padding.right + m->padding.right;
rect.height -= m->padding.top + d->padding.top + d->padding.bottom + m->padding.bottom;
if (l == LAYOUT_MONOCLE) {
if (d->layout == LAYOUT_MONOCLE) {
rect.x += monocle_padding.left;
rect.y += monocle_padding.top;
rect.width -= monocle_padding.left + monocle_padding.right;
rect.height -= monocle_padding.top + monocle_padding.bottom;
}
if (!gapless_monocle || l != LAYOUT_MONOCLE) {
if (!gapless_monocle || d->layout != LAYOUT_MONOCLE) {
rect.x += d->window_gap;
rect.y += d->window_gap;
rect.width -= d->window_gap;
rect.height -= d->window_gap;
}
apply_layout(m, d, d->root, l, rect, rect);
apply_layout(m, d, d->root, rect, rect);
}
void apply_layout(monitor_t *m, desktop_t *d, node_t *n, layout_t l, xcb_rectangle_t rect, xcb_rectangle_t root_rect)
void apply_layout(monitor_t *m, desktop_t *d, node_t *n, xcb_rectangle_t rect, xcb_rectangle_t root_rect)
{
if (n == NULL) {
return;
@ -91,7 +89,7 @@ void apply_layout(monitor_t *m, desktop_t *d, node_t *n, layout_t l, xcb_rectang
}
unsigned int bw;
if ((borderless_monocle && l == LAYOUT_MONOCLE && IS_TILED(n->client))
if ((borderless_monocle && d->layout == LAYOUT_MONOCLE && IS_TILED(n->client))
|| n->client->state == STATE_FULLSCREEN) {
bw = 0;
} else {
@ -103,7 +101,7 @@ void apply_layout(monitor_t *m, desktop_t *d, node_t *n, layout_t l, xcb_rectang
client_state_t s = n->client->state;
/* tiled and pseudo-tiled clients */
if (s == STATE_TILED || s == STATE_PSEUDO_TILED) {
int wg = (gapless_monocle && l == LAYOUT_MONOCLE ? 0 : d->window_gap);
int wg = (gapless_monocle && d->layout == LAYOUT_MONOCLE ? 0 : d->window_gap);
r = rect;
int bleed = wg + 2 * bw;
r.width = (bleed < r.width ? r.width - bleed : 1);
@ -143,7 +141,7 @@ void apply_layout(monitor_t *m, desktop_t *d, node_t *n, layout_t l, xcb_rectang
xcb_rectangle_t first_rect;
xcb_rectangle_t second_rect;
if (l == LAYOUT_MONOCLE || n->first_child->vacant || n->second_child->vacant) {
if (d->layout == LAYOUT_MONOCLE || n->first_child->vacant || n->second_child->vacant) {
first_rect = second_rect = rect;
} else {
unsigned int fence;
@ -176,8 +174,8 @@ void apply_layout(monitor_t *m, desktop_t *d, node_t *n, layout_t l, xcb_rectang
}
}
apply_layout(m, d, n->first_child, l, first_rect, root_rect);
apply_layout(m, d, n->second_child, l, second_rect, root_rect);
apply_layout(m, d, n->first_child, first_rect, root_rect);
apply_layout(m, d, n->second_child, second_rect, root_rect);
}
}
@ -440,7 +438,9 @@ void insert_receptacle(monitor_t *m, desktop_t *d, node_t *n)
node_t *r = make_node(XCB_NONE);
insert_node(m, d, r, n);
put_status(SBSC_MASK_REPORT);
if (single_monocle && d->layout == LAYOUT_MONOCLE && tiled_count(d->root, true) > 1) {
set_layout(m, d, d->user_layout, false);
}
}
bool activate_node(monitor_t *m, desktop_t *d, node_t *n)
@ -1321,6 +1321,10 @@ void remove_node(monitor_t *m, desktop_t *d, node_t *n)
}
free_node(n);
if (single_monocle && d->layout != LAYOUT_MONOCLE && tiled_count(d->root, true) <= 1) {
set_layout(m, d, LAYOUT_MONOCLE, false);
}
ewmh_update_client_list(false);
ewmh_update_client_list(true);
@ -1430,6 +1434,13 @@ bool swap_nodes(monitor_t *m1, desktop_t *d1, node_t *n1, monitor_t *m2, desktop
show_node(d1, n2);
}
if (single_monocle) {
layout_t l1 = tiled_count(d1->root, true) <= 1 ? LAYOUT_MONOCLE : d1->user_layout;
layout_t l2 = tiled_count(d2->root, true) <= 1 ? LAYOUT_MONOCLE : d2->user_layout;
set_layout(m1, d1, l1, false);
set_layout(m2, d2, l2, false);
}
if (n1_held_focus) {
if (d1_was_focused) {
if (follow) {
@ -1526,6 +1537,14 @@ bool transfer_node(monitor_t *ms, desktop_t *ds, node_t *ns, monitor_t *md, desk
draw_border(ns, is_descendant(ns, ds->focus), (ms == mon));
}
} else {
if (single_monocle) {
if (ds->layout != LAYOUT_MONOCLE && tiled_count(ds->root, true) <= 1) {
set_layout(ms, ds, LAYOUT_MONOCLE, false);
}
if (dd->layout == LAYOUT_MONOCLE && tiled_count(dd->root, true) > 1) {
set_layout(md, dd, dd->user_layout, false);
}
}
if (held_focus) {
if (follow) {
if (ds_was_focused) {
@ -1725,6 +1744,8 @@ bool set_state(monitor_t *m, desktop_t *d, node_t *n, client_state_t s)
client_t *c = n->client;
bool was_tiled = IS_TILED(c);
c->last_state = c->state;
c->state = s;
@ -1760,6 +1781,14 @@ bool set_state(monitor_t *m, desktop_t *d, node_t *n, client_state_t s)
put_status(SBSC_MASK_REPORT);
}
if (single_monocle && was_tiled != IS_TILED(c)) {
if (was_tiled && d->layout != LAYOUT_MONOCLE && tiled_count(d->root, true) <= 1) {
set_layout(m, d, LAYOUT_MONOCLE, false);
} else if (!was_tiled && d->layout == LAYOUT_MONOCLE && tiled_count(d->root, true) > 1) {
set_layout(m, d, d->user_layout, false);
}
}
return true;
}
@ -2054,7 +2083,7 @@ xcb_rectangle_t get_rectangle(monitor_t *m, desktop_t *d, node_t *n)
return c->tiled_rectangle;
}
} else {
int wg = (d == NULL ? 0 : (gapless_monocle && IS_MONOCLE(d) ? 0 : d->window_gap));
int wg = (d == NULL ? 0 : (gapless_monocle && d->layout == LAYOUT_MONOCLE ? 0 : d->window_gap));
xcb_rectangle_t rect = n->rectangle;
rect.width -= wg;
rect.height -= wg;

View file

@ -29,7 +29,7 @@
#define MIN_HEIGHT 32
void arrange(monitor_t *m, desktop_t *d);
void apply_layout(monitor_t *m, desktop_t *d, node_t *n, layout_t l, xcb_rectangle_t rect, xcb_rectangle_t root_rect);
void apply_layout(monitor_t *m, desktop_t *d, node_t *n, xcb_rectangle_t rect, xcb_rectangle_t root_rect);
presel_t *make_presel(void);
void set_ratio(node_t *n, double rat);
void presel_dir(monitor_t *m, desktop_t *d, node_t *n, direction_t dir);

View file

@ -268,6 +268,7 @@ struct desktop_t {
char name[SMALEN];
uint32_t id;
layout_t layout;
layout_t user_layout;
node_t *root;
node_t *focus;
desktop_t *prev;

View file

@ -30,6 +30,7 @@
#include "bspwm.h"
#include "ewmh.h"
#include "monitor.h"
#include "desktop.h"
#include "query.h"
#include "rule.h"
#include "settings.h"
@ -165,6 +166,9 @@ bool manage_window(xcb_window_t win, rule_consequence_t *csq, int fd)
f = insert_node(m, d, n, f);
clients_count++;
if (single_monocle && d->layout == LAYOUT_MONOCLE && tiled_count(d->root, true) > 1) {
set_layout(m, d, d->user_layout, false);
}
n->vacant = false;
@ -293,7 +297,7 @@ void draw_presel_feedback(monitor_t *m, desktop_t *d, node_t *n)
initialize_presel_feedback(n);
}
int gap = gapless_monocle && IS_MONOCLE(d) ? 0 : d->window_gap;
int gap = gapless_monocle && d->layout == LAYOUT_MONOCLE ? 0 : d->window_gap;
presel_t *p = n->presel;
xcb_rectangle_t rect = n->rectangle;
rect.x = rect.y = 0;