diff --git a/src/Makefile.am b/src/Makefile.am index b4faf06dd..5f3c9f393 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -57,6 +57,8 @@ metacity_SOURCES= \ screen.h \ session.c \ session.h \ + stack.c \ + stack.h \ theme.c \ theme.h \ uislave.c \ diff --git a/src/display.c b/src/display.c index 2cf29e05b..c0b4bf21a 100644 --- a/src/display.c +++ b/src/display.c @@ -116,7 +116,9 @@ meta_display_open (const char *name) "_NET_WM_WINDOW_TYPE_MENU", "_NET_WM_WINDOW_TYPE_DIALOG", "_NET_WM_WINDOW_TYPE_NORMAL", - "_NET_WM_STATE_MODAL" + "_NET_WM_STATE_MODAL", + "_NET_CLIENT_LIST", + "_NET_CLIENT_LIST_STACKING" }; Atom atoms[G_N_ELEMENTS(atom_names)]; @@ -181,6 +183,8 @@ meta_display_open (const char *name) display->atom_net_wm_window_type_dialog = atoms[25]; display->atom_net_wm_window_type_normal = atoms[26]; display->atom_net_wm_state_modal = atoms[27]; + display->atom_net_client_list = atoms[28]; + display->atom_net_client_list_stacking = atoms[29]; screens = NULL; i = 0; diff --git a/src/display.h b/src/display.h index 4421bd2e9..6016b10b7 100644 --- a/src/display.h +++ b/src/display.h @@ -74,6 +74,8 @@ struct _MetaDisplay Atom atom_net_wm_window_type_dialog; Atom atom_net_wm_window_type_normal; Atom atom_net_wm_state_modal; + Atom atom_net_client_list; + Atom atom_net_client_list_stacking; /* This is the actual window from focus events, * not the one we last set diff --git a/src/run-metacity.sh b/src/run-metacity.sh index 798d711e0..24e0489f5 100755 --- a/src/run-metacity.sh +++ b/src/run-metacity.sh @@ -9,7 +9,7 @@ elif test -z "$DEBUG"; then DEBUG=gdb fi -Xnest :1 -scrns $SCREENS -geometry 640x480 & -DISPLAY=:1 xsetroot -solid royalblue3 +Xnest :1 -scrns $SCREENS -geometry 640x480 -bw 15 & +usleep 50000 METACITY_UISLAVE_DIR=./uislave DISPLAY=:1 unst libtool --mode=execute $DEBUG ./metacity killall Xnest diff --git a/src/stack.c b/src/stack.c index bf5a7236e..4999095d9 100644 --- a/src/stack.c +++ b/src/stack.c @@ -20,6 +20,10 @@ */ #include "stack.h" +#include "window.h" +#include "errors.h" + +#include struct _MetaStackOp { @@ -63,6 +67,7 @@ void meta_stack_free (MetaStack *stack) { GList *tmp; + int i; g_array_free (stack->windows, TRUE); @@ -251,6 +256,56 @@ compute_layer (MetaWindow *window) window->layer = META_LAYER_NORMAL; break; } + + meta_verbose ("Window %s on layer %d\n", + window->desc, window->layer); +} + +static gboolean +is_transient_for (MetaWindow *transient, + MetaWindow *parent) +{ + MetaWindow *w; + + w = transient; + while (w != NULL) + { + if (w->xtransient_for == None) + return FALSE; + + w = meta_display_lookup_x_window (w->display, w->xtransient_for); + + if (w == transient) + return FALSE; /* Cycle detected */ + else if (w == parent) + return TRUE; + } + + return FALSE; +} + +static int +window_stack_cmp (MetaWindow *a, + MetaWindow *b) +{ + /* Less than means higher in stacking, i.e. at the + * front of the list. + */ + + if (a->xtransient_for != None && + is_transient_for (a, b)) + { + /* a is higher than b due to transient_for */ + return -1; + } + else if (b->xtransient_for != None && + is_transient_for (b, a)) + { + /* b is higher than a due to transient_for */ + return 1; + } + else + return 0; /* leave things as-is */ } static void @@ -265,11 +320,17 @@ meta_stack_sync_to_server (MetaStack *stack) int n_actually_added; int i, j; int old_size; + GArray *stacked; /* Bail out if frozen */ if (stack->freeze_count > 0) return; + if (stack->pending == NULL) + return; + + meta_verbose ("Syncing window stack to server\n"); + /* Here comes the fun - figure out all the stacking. * We make no pretense of efficiency. * a) replay all the pending operations @@ -304,7 +365,7 @@ meta_stack_sync_to_server (MetaStack *stack) tmp = tmp->next; } - old_size = stack->window->len; + old_size = stack->windows->len; g_array_set_size (stack->windows, old_size + n_actually_added); @@ -447,25 +508,81 @@ meta_stack_sync_to_server (MetaStack *stack) stack->pending = NULL; stack->n_added = 0; - /* Sort the layer lists */ i = 0; while (i < META_LAYER_LAST) { if (needs_sort[i]) { - - + stack->layers[i] = + g_list_sort (stack->layers[i], + (GCompareFunc) window_stack_cmp); } ++i; } /* Create stacked xwindow array */ + stacked = g_array_new (FALSE, FALSE, sizeof (Window)); + i = 0; + while (i < META_LAYER_LAST) + { + if (needs_sort[i]) + { + stack->layers[i] = + g_list_sort (stack->layers[i], + (GCompareFunc) window_stack_cmp); + } + + tmp = stack->layers[i]; + while (tmp != NULL) + { + MetaWindow *w = tmp->data; + + g_array_append_val (stacked, w->xwindow); + + tmp = tmp->next; + } + + ++i; + } + + /* All windows should be in some stacking order */ + if (stacked->len != stack->windows->len) + meta_bug ("%d windows stacked, %d windows exist in stack\n", + stacked->len, stack->windows->len); /* Sync to server */ + + meta_error_trap_push (stack->screen->display); + XRestackWindows (stack->screen->display->xdisplay, + (Window *) stacked->data, + stacked->len); + meta_error_trap_pop (stack->screen->display); + /* on error, a window was destroyed; it should eventually + * get removed from the stacking list when we unmanage it + * and we'll fix stacking at that time. + */ /* Sync _NET_CLIENT_LIST and _NET_CLIENT_LIST_STACKING */ - + + XChangeProperty (stack->screen->display->xdisplay, + stack->screen->xroot, + stack->screen->display->atom_net_client_list, + XA_ATOM, + 32, PropModeReplace, + stack->windows->data, + stack->windows->len); + XChangeProperty (stack->screen->display->xdisplay, + stack->screen->xroot, + stack->screen->display->atom_net_client_list_stacking, + XA_ATOM, + 32, PropModeReplace, + stacked->data, + stacked->len); + + g_array_free (stacked, TRUE); + + /* That was scary... */ } diff --git a/src/stack.h b/src/stack.h new file mode 100644 index 000000000..0f4c7b52d --- /dev/null +++ b/src/stack.h @@ -0,0 +1,92 @@ +/* Metacity Window Stack */ + +/* + * Copyright (C) 2001 Havoc Pennington + * + * 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 of the + * License, 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. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA + * 02111-1307, USA. + */ + +#ifndef META_STACK_H +#define META_STACK_H + +#include "screen.h" + +/* Type of last-queued stacking operation, hung off of MetaWindow + * but an opaque type used only in stack.c + */ +typedef struct _MetaStackOp MetaStackOp; + +/* These MUST be in the order of stacking */ +typedef enum +{ + META_LAYER_DESKTOP = 0, + META_LAYER_BOTTOM = 1, + META_LAYER_NORMAL = 2, + META_LAYER_TOP = 3, + META_LAYER_DOCK = 4, + META_LAYER_LAST = 5 +} MetaStackLayer; + +struct _MetaStack +{ + MetaScreen *screen; + + /* All windows that we manage, in mapping order, + * for _NET_CLIENT_LIST + */ + GArray *windows; + + /* List of MetaWindow* in each layer */ + GList *layers[META_LAYER_LAST]; + + /* List of MetaStackOp, most recent op + * first in list. + */ + GList *pending; + + int freeze_count; + + int n_added; +}; + +MetaStack *meta_stack_new (MetaScreen *screen); +void meta_stack_free (MetaStack *stack); +void meta_stack_add (MetaStack *stack, + MetaWindow *window); +void meta_stack_remove (MetaStack *stack, + MetaWindow *window); +/* re-read layer-related hints */ +void meta_stack_update_layer (MetaStack *stack, + MetaWindow *window); +/* reconsider transient_for */ +void meta_stack_update_transient (MetaStack *stack, + MetaWindow *window); + +/* raise/lower within a layer */ +void meta_stack_raise (MetaStack *stack, + MetaWindow *window); +void meta_stack_lower (MetaStack *stack, + MetaWindow *window); + +/* On thaw, process pending and sync to server */ +void meta_stack_freeze (MetaStack *stack); +void meta_stack_thaw (MetaStack *stack); + +#endif + + + + diff --git a/src/window.c b/src/window.c index 3da2ba06a..4ae30e3a7 100644 --- a/src/window.c +++ b/src/window.c @@ -53,6 +53,7 @@ static int update_net_wm_type (MetaWindow *window); static void recalc_window_type (MetaWindow *window); static int set_wm_state (MetaWindow *window, int state); +static int set_net_wm_state (MetaWindow *window); static void send_configure_notify (MetaWindow *window); static gboolean process_configure_request (MetaWindow *window, int x, diff --git a/src/window.h b/src/window.h index 8c7ed0708..cd44a960a 100644 --- a/src/window.h +++ b/src/window.h @@ -24,6 +24,7 @@ #include "screen.h" #include "util.h" +#include "stack.h" #include typedef enum diff --git a/src/workspace.c b/src/workspace.c index f7e5188c1..8d4415a0c 100644 --- a/src/workspace.c +++ b/src/workspace.c @@ -226,3 +226,6 @@ set_active_space_hint (MetaScreen *screen) 32, PropModeReplace, (guchar*) data, 1); return meta_error_trap_pop (screen->display); } + + +