-/* Copyright (c) 2012-2014, Bastien Dejean
+/* Copyright (c) 2012, Bastien Dejean
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- *
- * The views and conclusions contained in the software and documentation are those
- * of the authors and should not be interpreted as representing official policies,
- * either expressed or implied, of the FreeBSD Project.
*/
#include <stdlib.h>
#include "bspwm.h"
#include "window.h"
+#include "subscribe.h"
+#include "ewmh.h"
+#include "tree.h"
#include "stack.h"
stacking_list_t *make_stack(node_t *n)
if (a == NULL) {
stack_head = stack_tail = s;
} else {
- if (a->node == n)
+ if (a->node == n) {
+ free(s);
return;
+ }
remove_stack_node(n);
stacking_list_t *b = a->next;
- if (b != NULL)
+ if (b != NULL) {
b->prev = s;
+ }
s->next = b;
s->prev = a;
a->next = s;
- if (stack_tail == a)
+ if (stack_tail == a) {
stack_tail = s;
+ }
}
}
if (a == NULL) {
stack_head = stack_tail = s;
} else {
- if (a->node == n)
+ if (a->node == n) {
+ free(s);
return;
+ }
remove_stack_node(n);
stacking_list_t *b = a->prev;
- if (b != NULL)
+ if (b != NULL) {
b->next = s;
+ }
s->prev = b;
s->next = a;
a->prev = s;
- if (stack_head == a)
+ if (stack_head == a) {
stack_head = s;
+ }
}
}
void remove_stack(stacking_list_t *s)
{
- if (s == NULL)
+ if (s == NULL) {
return;
+ }
stacking_list_t *a = s->prev;
stacking_list_t *b = s->next;
- if (a != NULL)
+ if (a != NULL) {
a->next = b;
- if (b != NULL)
+ }
+ if (b != NULL) {
b->prev = a;
- if (s == stack_head)
+ }
+ if (s == stack_head) {
stack_head = b;
- if (s == stack_tail)
+ }
+ if (s == stack_tail) {
stack_tail = a;
+ }
free(s);
}
void remove_stack_node(node_t *n)
{
- for (stacking_list_t *s = stack_head; s != NULL; s = s->next)
- if (s->node == n) {
- remove_stack(s);
- return;
+ for (node_t *f = first_extrema(n); f != NULL; f = next_leaf(f, n)) {
+ for (stacking_list_t *s = stack_head; s != NULL; s = s->next) {
+ if (s->node == f) {
+ remove_stack(s);
+ break;
+ }
}
+ }
}
-void stack(node_t *n, stack_flavor_t f)
+int stack_level(client_t *c)
{
- PRINTF("stack %X\n", n->client->window);
+ int layer_level = (c->layer == LAYER_NORMAL ? 1 : (c->layer == LAYER_BELOW ? 0 : 2));
+ int state_level = (IS_TILED(c) ? 0 : (IS_FLOATING(c) ? 2 : 1));
+ return 3 * layer_level + state_level;
+}
- if (stack_head == NULL) {
- stack_insert_after(NULL, n);
- } else if (n->client->fullscreen) {
- if (f == STACK_ABOVE) {
- stack_insert_after(stack_tail, n);
- window_raise(n->client->window);
- }
- } else {
- if (f == STACK_ABOVE && n->client->floating && !auto_raise)
- return;
- stacking_list_t *latest_tiled = NULL;
- stacking_list_t *oldest_floating = NULL;
- stacking_list_t *oldest_fullscreen = NULL;
- for (stacking_list_t *s = (f == STACK_ABOVE ? stack_tail : stack_head); s != NULL; s = (f == STACK_ABOVE ? s->prev : s->next)) {
- if (s->node != n) {
- if (s->node->client->fullscreen) {
- if (oldest_fullscreen == NULL)
- oldest_fullscreen = s;
- continue;
- }
- if (s->node->client->floating == n->client->floating) {
- if (f == STACK_ABOVE) {
- stack_insert_after(s, n);
- window_above(n->client->window, s->node->client->window);
- } else {
- stack_insert_before(s, n);
- window_below(n->client->window, s->node->client->window);
- }
- return;
- } else if ((f != STACK_ABOVE || latest_tiled == NULL) && !s->node->client->floating) {
- latest_tiled = s;
- } else if ((f == STACK_ABOVE || oldest_floating == NULL) && s->node->client->floating) {
- oldest_floating = s;
- }
- }
+int stack_cmp(client_t *c1, client_t *c2)
+{
+ return stack_level(c1) - stack_level(c2);
+}
+
+stacking_list_t *limit_above(node_t *n)
+{
+ stacking_list_t *s = stack_head;
+ while (s != NULL && stack_cmp(n->client, s->node->client) >= 0) {
+ s = s->next;
+ }
+ if (s == NULL) {
+ s = stack_tail;
+ }
+ if (s->node == n) {
+ s = s->prev;
+ }
+ return s;
+}
+
+stacking_list_t *limit_below(node_t *n)
+{
+ stacking_list_t *s = stack_tail;
+ while (s != NULL && stack_cmp(n->client, s->node->client) <= 0) {
+ s = s->prev;
+ }
+ if (s == NULL) {
+ s = stack_head;
+ }
+ if (s->node == n) {
+ s = s->next;
+ }
+ return s;
+}
+
+void stack(desktop_t *d, node_t *n, bool focused)
+{
+ for (node_t *f = first_extrema(n); f != NULL; f = next_leaf(f, n)) {
+ if (f->client == NULL || (IS_FLOATING(f->client) && !auto_raise)) {
+ continue;
}
- if (latest_tiled == NULL && oldest_floating == NULL && oldest_fullscreen == NULL)
- return;
- if (n->client->floating) {
- if (latest_tiled != NULL) {
- window_above(n->client->window, latest_tiled->node->client->window);
- stack_insert_after(latest_tiled, n);
- } else if (oldest_fullscreen != NULL) {
- window_below(n->client->window, oldest_fullscreen->node->client->window);
- stack_insert_before(oldest_fullscreen, n);
- }
+
+ if (stack_head == NULL) {
+ stack_insert_after(NULL, f);
} else {
- if (oldest_floating != NULL) {
- window_below(n->client->window, oldest_floating->node->client->window);
- stack_insert_before(oldest_floating, n);
- } else if (oldest_fullscreen != NULL) {
- window_below(n->client->window, oldest_fullscreen->node->client->window);
- stack_insert_before(oldest_fullscreen, n);
+ stacking_list_t *s = (focused ? limit_above(f) : limit_below(f));
+ if (s == NULL) {
+ continue;
+ }
+ int i = stack_cmp(f->client, s->node->client);
+ if (i < 0 || (i == 0 && !focused)) {
+ stack_insert_before(s, f);
+ window_below(f->id, s->node->id);
+ put_status(SBSC_MASK_NODE_STACK, "node_stack 0x%08X below 0x%08X\n", f->id, s->node->id);
+ } else {
+ stack_insert_after(s, f);
+ window_above(f->id, s->node->id);
+ put_status(SBSC_MASK_NODE_STACK, "node_stack 0x%08X above 0x%08X\n", f->id, s->node->id);
}
}
}
+
+ ewmh_update_client_list(true);
+ restack_presel_feedback(d);
+}
+
+void restack_presel_feedback(desktop_t *d)
+{
+ stacking_list_t *s = stack_tail;
+ while (s != NULL && !IS_TILED(s->node->client)) {
+ s = s->prev;
+ }
+ if (s != NULL) {
+ restack_presel_feedback_in(d->root, s->node);
+ }
+}
+
+void restack_presel_feedback_in(node_t *r, node_t *n)
+{
+ if (r == NULL) {
+ return;
+ } else {
+ if (r->presel != NULL) {
+ window_above(r->presel->feedback, n->id);
+ }
+ restack_presel_feedback_in(r->first_child, n);
+ restack_presel_feedback_in(r->second_child, n);
+ }
}