aboutsummaryrefslogtreecommitdiffstats
path: root/matchbox2/mb-wm-stack.c
diff options
context:
space:
mode:
Diffstat (limited to 'matchbox2/mb-wm-stack.c')
-rw-r--r--matchbox2/mb-wm-stack.c325
1 files changed, 325 insertions, 0 deletions
diff --git a/matchbox2/mb-wm-stack.c b/matchbox2/mb-wm-stack.c
new file mode 100644
index 0000000..f75b228
--- /dev/null
+++ b/matchbox2/mb-wm-stack.c
@@ -0,0 +1,325 @@
+/*
+ * Matchbox Window Manager II - A lightweight window manager not for the
+ * desktop.
+ *
+ * Authored By Matthew Allum <mallum@o-hand.com>
+ *
+ * Copyright (c) 2005 OpenedHand Ltd - http://o-hand.com
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ */
+
+#include "mb-wm.h"
+
+
+static void
+mb_wm_stack_ensure_trans_foreach (MBWindowManagerClient *client, void *data)
+{
+ MBWMList * t = mb_wm_client_get_transients (client);
+
+ mb_wm_stack_move_top (client);
+
+ mb_wm_util_list_foreach
+ (t, (MBWMListForEachCB) mb_wm_stack_ensure_trans_foreach, NULL);
+
+ mb_wm_util_list_free (t);
+}
+
+void
+mb_wm_stack_dump (MBWindowManager *wm)
+{
+#if (MBWM_WANT_DEBUG)
+ MBWindowManagerClient *client;
+ MBWMStackLayerType stacking_layer;
+
+ fprintf(stderr, "\n==== window stack =====\n");
+
+ mb_wm_stack_enumerate_reverse (wm, client)
+ {
+ MBWindowManagerClient *trans_client = client;
+ int i = 0, j = 0;
+ char prefix[128] = {0};
+
+ while ((trans_client = mb_wm_client_get_transient_for(trans_client)))
+ i++;
+
+ if (i)
+ {
+ for (j=0;j<=i*2;j+=2)
+ { prefix[j] = ' '; prefix[j+1] = ' '; }
+
+ strcpy(&prefix[i*2], " +--");
+ }
+
+ stacking_layer = mb_wm_client_get_stacking_layer (client);
+
+ fprintf(stderr, "%s XID: %lx NAME: %s, type %d, layer %d\n",
+ prefix,
+ MB_WM_CLIENT_XWIN(client),
+ client->window->name ? client->window->name : "unknown",
+ MB_WM_CLIENT_CLIENT_TYPE (client),
+ stacking_layer);
+ }
+
+ fprintf(stderr, "======================\n\n");
+#endif
+}
+
+void
+mb_wm_stack_ensure (MBWindowManager *wm)
+{
+ MBWindowManagerClient *client, *seen, *next;
+ int i;
+ MBWMStackLayerType stacking_layer;
+
+ if (wm->stack_bottom == NULL)
+ return;
+
+ /* Ensure the window stack is corrent;
+ * - with respect to client layer types
+ * - transients are stacked within these layers also
+ *
+ * We need to be careful here as we modify stacking list
+ * in place while enumerating it.
+ *
+ * FIXME: This isn't optimal
+ */
+
+ /* bottom -> top on layer types */
+ for (i=1; i<N_MBWMStackLayerTypes; i++)
+ {
+ /* Push each layer type to top, handling transients */
+ client = wm->stack_bottom;
+ seen = NULL;
+
+ while (client != seen && client != NULL)
+ {
+ /* get the next valid client ( ignore transients ) before
+ * modifying the list
+ */
+ next = client->stacked_above;
+
+ while (next && mb_wm_client_get_transient_for (next))
+ next = next->stacked_above;
+
+ stacking_layer = mb_wm_client_get_stacking_layer (client);
+
+ if (stacking_layer == i
+ && mb_wm_client_get_transient_for (client) == NULL)
+ {
+ /* Keep track of the first client modified so we
+ * know when to stop iterating.
+ */
+ if (seen == NULL)
+ seen = client;
+
+ mb_wm_client_stack (client, 0);
+ }
+ client = next;
+ }
+ }
+
+ mb_wm_stack_dump (wm);
+}
+
+void
+mb_wm_stack_insert_above_client (MBWindowManagerClient *client,
+ MBWindowManagerClient *client_below)
+{
+ MBWindowManager *wm = client->wmref;
+
+ MBWM_ASSERT (client != NULL);
+
+ if (client_below == NULL)
+ {
+ /* NULL so nothing below add at bottom */
+ if (wm->stack_bottom)
+ {
+ client->stacked_above = wm->stack_bottom;
+ wm->stack_bottom->stacked_below = client;
+ }
+
+ wm->stack_bottom = client;
+ }
+ else
+ {
+ client->stacked_below = client_below;
+ client->stacked_above = client_below->stacked_above;
+ if (client->stacked_below) client->stacked_below->stacked_above = client;
+ if (client->stacked_above) client->stacked_above->stacked_below = client;
+ }
+
+ if (client_below == wm->stack_top)
+ wm->stack_top = client;
+
+ wm->stack_n_clients++;
+}
+
+
+void
+mb_wm_stack_append_top (MBWindowManagerClient *client)
+{
+ MBWindowManager *wm = client->wmref;
+
+ mb_wm_stack_insert_above_client(client, wm->stack_top);
+}
+
+void
+mb_wm_stack_prepend_bottom (MBWindowManagerClient *client)
+{
+ mb_wm_stack_insert_above_client(client, NULL);
+}
+
+void
+mb_wm_stack_move_client_above_type (MBWindowManagerClient *client,
+ MBWMClientType type_below)
+{
+ MBWindowManager *wm = client->wmref;
+ MBWindowManagerClient *highest_client = NULL;
+
+ highest_client = mb_wm_stack_get_highest_by_type (wm, type_below);
+
+ if (highest_client)
+ mb_wm_stack_move_above_client(client, highest_client);
+}
+
+
+void
+mb_wm_stack_move_above_client (MBWindowManagerClient *client,
+ MBWindowManagerClient *client_below)
+{
+ if (client == client_below) return;
+
+ MBWM_ASSERT (client != NULL);
+ MBWM_ASSERT (client_below != NULL);
+
+ mb_wm_stack_remove(client);
+ mb_wm_stack_insert_above_client(client, client_below);
+}
+
+MBWindowManagerClient*
+mb_wm_stack_get_highest_by_type (MBWindowManager *wm,
+ MBWMClientType type)
+{
+ MBWindowManagerClient *c = NULL;
+
+ mb_wm_stack_enumerate_reverse (wm,c)
+ if (MB_WM_CLIENT_CLIENT_TYPE(c) & type)
+ return c;
+
+ return NULL;
+}
+
+MBWindowManagerClient*
+mb_wm_stack_get_lowest_by_type(MBWindowManager *w, MBWMClientType wanted_type)
+
+{
+ MBWindowManagerClient *c = NULL;
+
+ mb_wm_stack_enumerate(w,c)
+ if (MB_WM_CLIENT_CLIENT_TYPE(c) & wanted_type)
+ return c;
+
+ return NULL;
+}
+
+MBWindowManagerClient *
+mb_wm_stack_cycle_by_type(MBWindowManager *wm, MBWMClientType type,
+ Bool reverse)
+{
+ if (reverse)
+ {
+ MBWindowManagerClient *prev, *highest;
+
+ highest = mb_wm_stack_get_highest_by_type (wm, type);
+
+ if (!highest)
+ return highest;
+
+ prev = highest->stacked_below;
+
+ while (prev && (!(type & MB_WM_CLIENT_CLIENT_TYPE (prev))))
+ {
+ prev = prev->stacked_below;
+ }
+
+ if (prev && highest && prev != highest)
+ {
+ mb_wm_stack_move_above_client (prev, highest);
+ }
+
+ return prev;
+ }
+ else
+ {
+ MBWindowManagerClient *lowest, *highest;
+
+ lowest = mb_wm_stack_get_lowest_by_type (wm, type);
+ highest = mb_wm_stack_get_highest_by_type (wm, type);
+
+ if (lowest && highest && lowest != highest)
+ {
+ mb_wm_stack_move_above_client (lowest, highest);
+ }
+
+ return lowest;
+ }
+}
+
+void
+mb_wm_stack_remove (MBWindowManagerClient *client)
+{
+ MBWindowManager *wm = client->wmref;
+ Bool change = False;
+
+ if (wm->stack_top == wm->stack_bottom)
+ {
+ if (wm->stack_top != client)
+ {
+ MBWM_DBG("Client stack corruption !!!");
+ }
+ else
+ wm->stack_top = wm->stack_bottom = NULL;
+ }
+ else
+ {
+ if (client == wm->stack_top)
+ {
+ wm->stack_top = client->stacked_below;
+ change = True;
+ }
+
+ if (client == wm->stack_bottom)
+ {
+ wm->stack_bottom = client->stacked_above;
+ change = True;
+ }
+
+ if (client->stacked_below != NULL)
+ {
+ client->stacked_below->stacked_above = client->stacked_above;
+ change = True;
+ }
+ if (client->stacked_above != NULL)
+ {
+ client->stacked_above->stacked_below = client->stacked_below;
+ change = True;
+ }
+ }
+
+ client->stacked_above = client->stacked_below = NULL;
+
+ if (change)
+ wm->stack_n_clients--;
+}
+
+