Compare commits
	
		
			19 Commits
		
	
	
		
			3.22.1
			...
			override-r
		
	
	| Author | SHA1 | Date | |
|---|---|---|---|
| 
						 | 
					8a0de6dfd3 | ||
| 
						 | 
					2bf0b2b6de | ||
| 
						 | 
					eed2a2d324 | ||
| 
						 | 
					9828007a02 | ||
| 
						 | 
					1f890672bb | ||
| 
						 | 
					ef966854d5 | ||
| 
						 | 
					7309b6cfe3 | ||
| 
						 | 
					3705a224f0 | ||
| 
						 | 
					2ebedb822d | ||
| 
						 | 
					d6576d9b70 | ||
| 
						 | 
					6516c19ec5 | ||
| 
						 | 
					5518fee61c | ||
| 
						 | 
					ace0521cba | ||
| 
						 | 
					0091a3aab5 | ||
| 
						 | 
					268b92a4ec | ||
| 
						 | 
					29bb4c27e3 | ||
| 
						 | 
					bd3bdc51b9 | ||
| 
						 | 
					0123dab87a | ||
| 
						 | 
					413acc9574 | 
@@ -70,6 +70,8 @@ mutter_SOURCES= 				\
 | 
			
		||||
	core/session.h				\
 | 
			
		||||
	core/stack.c				\
 | 
			
		||||
	core/stack.h				\
 | 
			
		||||
	core/stack-tracker.c			\
 | 
			
		||||
	core/stack-tracker.h			\
 | 
			
		||||
	core/util.c				\
 | 
			
		||||
	include/util.h				\
 | 
			
		||||
	core/window-props.c			\
 | 
			
		||||
 
 | 
			
		||||
@@ -2430,26 +2430,77 @@ clutter_cmp_sync_stack (MetaCompositor *compositor,
 | 
			
		||||
			MetaScreen     *screen,
 | 
			
		||||
			GList	       *stack)
 | 
			
		||||
{
 | 
			
		||||
  GList *tmp;
 | 
			
		||||
  GList *old_stack;
 | 
			
		||||
  MetaCompScreen *info = meta_screen_get_compositor_data (screen);
 | 
			
		||||
 | 
			
		||||
  DEBUG_TRACE ("clutter_cmp_sync_stack\n");
 | 
			
		||||
  /* NB: The first entry in stack, is stacked the highest */
 | 
			
		||||
 | 
			
		||||
  for (tmp = stack; tmp != NULL; tmp = tmp->next)
 | 
			
		||||
  /* This is painful because hidden windows that we are in the process
 | 
			
		||||
   * of animating out of existence. They'll be at the bottom of the
 | 
			
		||||
   * stack of X windows, but we want to leave them in their old position
 | 
			
		||||
   * until the animation effect finishes.
 | 
			
		||||
   */
 | 
			
		||||
 | 
			
		||||
  /* Sources: first window is the highest */
 | 
			
		||||
  stack = g_list_copy (stack); /* The new stack of MetaWindow */
 | 
			
		||||
  old_stack = g_list_reverse (info->windows); /* The old stack of MutterWindow */
 | 
			
		||||
  info->windows = NULL;
 | 
			
		||||
 | 
			
		||||
  while (TRUE)
 | 
			
		||||
    {
 | 
			
		||||
      MetaWindow    *window = tmp->data;
 | 
			
		||||
      MutterWindow  *cw = MUTTER_WINDOW (meta_window_get_compositor_private (window));
 | 
			
		||||
      MutterWindow *old_actor = NULL, *stack_actor = NULL, *actor;
 | 
			
		||||
      MetaWindow *old_window = NULL, *stack_window = NULL, *window;
 | 
			
		||||
 | 
			
		||||
      if (!cw)
 | 
			
		||||
	{
 | 
			
		||||
	  meta_verbose ("Failed to find corresponding MutterWindow "
 | 
			
		||||
			"for window %p\n", window);
 | 
			
		||||
	  continue;
 | 
			
		||||
	}
 | 
			
		||||
      /* Find the remaining top actor in our existing stack */
 | 
			
		||||
      if (old_stack)
 | 
			
		||||
        {
 | 
			
		||||
          old_actor = old_stack->data;
 | 
			
		||||
          old_window = mutter_window_get_meta_window (old_actor);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
      info->windows = g_list_remove (info->windows, (gconstpointer)cw);
 | 
			
		||||
      info->windows = g_list_prepend (info->windows, cw);
 | 
			
		||||
      /* And the remaining top actor in the new stack */
 | 
			
		||||
      while (stack)
 | 
			
		||||
        {
 | 
			
		||||
          stack_window = stack->data;
 | 
			
		||||
          stack_actor = MUTTER_WINDOW (meta_window_get_compositor_private (stack_window));
 | 
			
		||||
          if (!stack_actor)
 | 
			
		||||
            {
 | 
			
		||||
              meta_verbose ("Failed to find corresponding MutterWindow "
 | 
			
		||||
                            "for window %s\n", meta_window_get_description (stack_window));
 | 
			
		||||
              stack = g_list_delete_link (stack, stack);
 | 
			
		||||
            }
 | 
			
		||||
          else
 | 
			
		||||
            break;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
      if (!old_actor && !stack_actor) /* Nothing more to stack */
 | 
			
		||||
        break;
 | 
			
		||||
 | 
			
		||||
      /* We usually prefer the window in the new stack, but if if we
 | 
			
		||||
       * found a hidden window in the process of being animated out
 | 
			
		||||
       * of existence in the old stack we use that instead.
 | 
			
		||||
       */
 | 
			
		||||
      if (old_actor &&
 | 
			
		||||
          (!stack_actor ||
 | 
			
		||||
           (old_window->hidden &&
 | 
			
		||||
            effect_in_progress (old_actor, TRUE))))
 | 
			
		||||
        {
 | 
			
		||||
          actor = old_actor;
 | 
			
		||||
          window = old_window;
 | 
			
		||||
        }
 | 
			
		||||
      else
 | 
			
		||||
        {
 | 
			
		||||
          actor = stack_actor;
 | 
			
		||||
          window = stack_window;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
      /* OK, we know what actor we want next. Add it to our window
 | 
			
		||||
       * list, and remove it from the sources.
 | 
			
		||||
       */
 | 
			
		||||
      info->windows = g_list_prepend (info->windows, actor);
 | 
			
		||||
 | 
			
		||||
      stack = g_list_remove (stack, window);
 | 
			
		||||
      old_stack = g_list_remove (old_stack, actor);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
  sync_actor_stacking (info->windows);
 | 
			
		||||
 
 | 
			
		||||
@@ -52,6 +52,7 @@ typedef struct _MetaStack      MetaStack;
 | 
			
		||||
typedef struct _MetaUISlave    MetaUISlave;
 | 
			
		||||
 | 
			
		||||
typedef struct _MetaGroupPropHooks  MetaGroupPropHooks;
 | 
			
		||||
typedef struct _MetaWindowPropHooks MetaWindowPropHooks;
 | 
			
		||||
 | 
			
		||||
typedef struct MetaEdgeResistanceData MetaEdgeResistanceData;
 | 
			
		||||
 | 
			
		||||
@@ -235,8 +236,9 @@ struct _MetaDisplay
 | 
			
		||||
  MetaWindow *window_with_menu;
 | 
			
		||||
 | 
			
		||||
  /* Managed by window-props.c */
 | 
			
		||||
  gpointer *prop_hooks_table;
 | 
			
		||||
  MetaWindowPropHooks *prop_hooks_table;
 | 
			
		||||
  GHashTable *prop_hooks;
 | 
			
		||||
  int n_prop_hooks;
 | 
			
		||||
 | 
			
		||||
  /* Managed by group-props.c */
 | 
			
		||||
  MetaGroupPropHooks *group_prop_hooks;
 | 
			
		||||
@@ -365,6 +367,7 @@ gboolean    meta_display_xwindow_is_a_no_focus_window (MetaDisplay *display,
 | 
			
		||||
                                                       Window xwindow);
 | 
			
		||||
 | 
			
		||||
GSList*     meta_display_list_windows        (MetaDisplay *display);
 | 
			
		||||
GSList*     meta_display_list_all_windows    (MetaDisplay *display);
 | 
			
		||||
 | 
			
		||||
MetaDisplay* meta_display_for_x_display  (Display     *xdisplay);
 | 
			
		||||
MetaDisplay* meta_get_display            (void);
 | 
			
		||||
 
 | 
			
		||||
@@ -812,13 +812,19 @@ meta_display_open (void)
 | 
			
		||||
  return TRUE;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
typedef struct {
 | 
			
		||||
  GSList *winlist;
 | 
			
		||||
  gboolean include_override_redirect;
 | 
			
		||||
} ListifyClosure;
 | 
			
		||||
 | 
			
		||||
static void
 | 
			
		||||
listify_func (gpointer key, gpointer value, gpointer data)
 | 
			
		||||
{
 | 
			
		||||
  GSList **listp;
 | 
			
		||||
  ListifyClosure *closure = data;
 | 
			
		||||
  MetaWindow *window = value;
 | 
			
		||||
 | 
			
		||||
  listp = data;
 | 
			
		||||
  *listp = g_slist_prepend (*listp, value);
 | 
			
		||||
  if (closure->include_override_redirect || !window->override_redirect)
 | 
			
		||||
    closure->winlist = g_slist_prepend (closure->winlist, window);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static gint
 | 
			
		||||
@@ -832,17 +838,21 @@ ptrcmp (gconstpointer a, gconstpointer b)
 | 
			
		||||
    return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
GSList*
 | 
			
		||||
meta_display_list_windows (MetaDisplay *display)
 | 
			
		||||
static GSList*
 | 
			
		||||
list_windows (MetaDisplay *display,
 | 
			
		||||
              gboolean     include_override_redirect)
 | 
			
		||||
{
 | 
			
		||||
  ListifyClosure closure;
 | 
			
		||||
  GSList *winlist;
 | 
			
		||||
  GSList *tmp;
 | 
			
		||||
  GSList *prev;
 | 
			
		||||
  
 | 
			
		||||
  winlist = NULL;
 | 
			
		||||
 | 
			
		||||
  closure.winlist = NULL;
 | 
			
		||||
  closure.include_override_redirect = include_override_redirect;
 | 
			
		||||
  g_hash_table_foreach (display->window_ids,
 | 
			
		||||
                        listify_func,
 | 
			
		||||
                        &winlist);
 | 
			
		||||
                        &closure);
 | 
			
		||||
  winlist = closure.winlist;
 | 
			
		||||
 | 
			
		||||
  /* Uniquify the list, since both frame windows and plain
 | 
			
		||||
   * windows are in the hash
 | 
			
		||||
@@ -883,6 +893,40 @@ meta_display_list_windows (MetaDisplay *display)
 | 
			
		||||
  return winlist;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * meta_display_list_windows:
 | 
			
		||||
 * @display: a #MetaDisplay
 | 
			
		||||
 *
 | 
			
		||||
 * Lists windows for the display, excluding override-redirect
 | 
			
		||||
 * windows.
 | 
			
		||||
 *
 | 
			
		||||
 * Return value: (transfer container): the list of windows.
 | 
			
		||||
 */
 | 
			
		||||
GSList*
 | 
			
		||||
meta_display_list_windows (MetaDisplay *display)
 | 
			
		||||
{
 | 
			
		||||
  return list_windows (display, FALSE);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * meta_display_list_all_windows:
 | 
			
		||||
 * @display: a #MetaDisplay
 | 
			
		||||
 *
 | 
			
		||||
 * Lists windows for the display, including override-redirect
 | 
			
		||||
 * windows. You usually want to use meta_display_list_windows()
 | 
			
		||||
 * instead, since override-redirect windows are by definition
 | 
			
		||||
 * outside the scope of window management. This function is most
 | 
			
		||||
 * useful if you are interested in how things are displayed on
 | 
			
		||||
 * the screen.
 | 
			
		||||
 *
 | 
			
		||||
 * Return value: (transfer container): the list of windows.
 | 
			
		||||
 */
 | 
			
		||||
GSList*
 | 
			
		||||
meta_display_list_all_windows (MetaDisplay *display)
 | 
			
		||||
{
 | 
			
		||||
  return list_windows (display, TRUE);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void
 | 
			
		||||
meta_display_close (MetaDisplay *display,
 | 
			
		||||
                    guint32      timestamp)
 | 
			
		||||
@@ -2007,9 +2051,27 @@ event_callback (XEvent   *event,
 | 
			
		||||
    case VisibilityNotify:
 | 
			
		||||
      break;
 | 
			
		||||
    case CreateNotify:
 | 
			
		||||
      {
 | 
			
		||||
        MetaScreen *screen;
 | 
			
		||||
 | 
			
		||||
        screen = meta_display_screen_for_root (display,
 | 
			
		||||
                                               event->xcreatewindow.parent);
 | 
			
		||||
        if (screen)
 | 
			
		||||
          meta_stack_tracker_create_event (screen->stack_tracker,
 | 
			
		||||
                                           &event->xcreatewindow);
 | 
			
		||||
      }
 | 
			
		||||
      break;
 | 
			
		||||
      
 | 
			
		||||
    case DestroyNotify:
 | 
			
		||||
      {
 | 
			
		||||
        MetaScreen *screen;
 | 
			
		||||
 | 
			
		||||
        screen = meta_display_screen_for_root (display,
 | 
			
		||||
                                               event->xdestroywindow.event);
 | 
			
		||||
        if (screen)
 | 
			
		||||
          meta_stack_tracker_destroy_event (screen->stack_tracker,
 | 
			
		||||
                                            &event->xdestroywindow);
 | 
			
		||||
      }
 | 
			
		||||
      if (window)
 | 
			
		||||
        {
 | 
			
		||||
          /* FIXME: It sucks that DestroyNotify events don't come with
 | 
			
		||||
@@ -2123,8 +2185,30 @@ event_callback (XEvent   *event,
 | 
			
		||||
        }
 | 
			
		||||
      break;
 | 
			
		||||
    case ReparentNotify:
 | 
			
		||||
      {
 | 
			
		||||
        MetaScreen *screen;
 | 
			
		||||
 | 
			
		||||
        screen = meta_display_screen_for_root (display,
 | 
			
		||||
                                               event->xconfigure.event);
 | 
			
		||||
        if (screen)
 | 
			
		||||
          {
 | 
			
		||||
            if (screen)
 | 
			
		||||
              meta_stack_tracker_reparent_event (screen->stack_tracker,
 | 
			
		||||
                                                 &event->xreparent);
 | 
			
		||||
          }
 | 
			
		||||
      }
 | 
			
		||||
      break;
 | 
			
		||||
    case ConfigureNotify:
 | 
			
		||||
      if (event->xconfigure.event != event->xconfigure.window)
 | 
			
		||||
        {
 | 
			
		||||
          MetaScreen *screen;
 | 
			
		||||
 | 
			
		||||
          screen = meta_display_screen_for_root (display,
 | 
			
		||||
                                                 event->xconfigure.event);
 | 
			
		||||
          if (screen)
 | 
			
		||||
            meta_stack_tracker_configure_event (screen->stack_tracker,
 | 
			
		||||
                                                &event->xconfigure);
 | 
			
		||||
        }
 | 
			
		||||
      if (window && window->override_redirect)
 | 
			
		||||
	meta_window_configure_notify (window, &event->xconfigure);
 | 
			
		||||
      else
 | 
			
		||||
@@ -4824,7 +4908,7 @@ meta_display_unmanage_windows_for_screen (MetaDisplay *display,
 | 
			
		||||
  GSList *tmp;
 | 
			
		||||
  GSList *winlist;
 | 
			
		||||
 | 
			
		||||
  winlist = meta_display_list_windows (display);
 | 
			
		||||
  winlist = meta_display_list_all_windows (display);
 | 
			
		||||
  winlist = g_slist_sort (winlist, meta_display_stack_cmp);
 | 
			
		||||
 | 
			
		||||
  /* Unmanage all windows */
 | 
			
		||||
 
 | 
			
		||||
@@ -48,6 +48,7 @@ meta_window_ensure_frame (MetaWindow *window)
 | 
			
		||||
  MetaFrame *frame;
 | 
			
		||||
  XSetWindowAttributes attrs;
 | 
			
		||||
  Visual *visual;
 | 
			
		||||
  gulong create_serial;
 | 
			
		||||
  
 | 
			
		||||
  if (window->frame)
 | 
			
		||||
    return;
 | 
			
		||||
@@ -105,7 +106,11 @@ meta_window_ensure_frame (MetaWindow *window)
 | 
			
		||||
                                                frame->rect.y,
 | 
			
		||||
						frame->rect.width,
 | 
			
		||||
						frame->rect.height,
 | 
			
		||||
						frame->window->screen->number);
 | 
			
		||||
						frame->window->screen->number,
 | 
			
		||||
                                                &create_serial);
 | 
			
		||||
  meta_stack_tracker_record_add (window->screen->stack_tracker,
 | 
			
		||||
                                 frame->xwindow,
 | 
			
		||||
                                 create_serial);
 | 
			
		||||
 | 
			
		||||
  meta_verbose ("Frame for %s is 0x%lx\n", frame->window->desc, frame->xwindow);
 | 
			
		||||
  attrs.event_mask = EVENT_MASK;
 | 
			
		||||
@@ -141,6 +146,9 @@ meta_window_ensure_frame (MetaWindow *window)
 | 
			
		||||
  window->rect.x = 0;
 | 
			
		||||
  window->rect.y = 0;
 | 
			
		||||
 | 
			
		||||
  meta_stack_tracker_record_remove (window->screen->stack_tracker,
 | 
			
		||||
                                    window->xwindow,
 | 
			
		||||
                                    XNextRequest (window->display->xdisplay));
 | 
			
		||||
  XReparentWindow (window->display->xdisplay,
 | 
			
		||||
                   window->xwindow,
 | 
			
		||||
                   frame->xwindow,
 | 
			
		||||
@@ -199,6 +207,9 @@ meta_window_destroy_frame (MetaWindow *window)
 | 
			
		||||
                  "Incrementing unmaps_pending on %s for reparent back to root\n", window->desc);
 | 
			
		||||
      window->unmaps_pending += 1;
 | 
			
		||||
    }
 | 
			
		||||
  meta_stack_tracker_record_add (window->screen->stack_tracker,
 | 
			
		||||
                                 window->xwindow,
 | 
			
		||||
                                 XNextRequest (window->display->xdisplay));
 | 
			
		||||
  XReparentWindow (window->display->xdisplay,
 | 
			
		||||
                   window->xwindow,
 | 
			
		||||
                   window->screen->xroot,
 | 
			
		||||
 
 | 
			
		||||
@@ -36,6 +36,7 @@
 | 
			
		||||
#include "display-private.h"
 | 
			
		||||
#include "screen.h"
 | 
			
		||||
#include <X11/Xutil.h>
 | 
			
		||||
#include "stack-tracker.h"
 | 
			
		||||
#include "alttabhandler.h"
 | 
			
		||||
#include "ui.h"
 | 
			
		||||
 | 
			
		||||
@@ -94,6 +95,7 @@ struct _MetaScreen
 | 
			
		||||
  GList *workspaces;
 | 
			
		||||
 | 
			
		||||
  MetaStack *stack;
 | 
			
		||||
  MetaStackTracker *stack_tracker;
 | 
			
		||||
 | 
			
		||||
  MetaCursor current_cursor;
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -457,6 +457,10 @@ create_guard_window (Display *xdisplay, MetaScreen *screen)
 | 
			
		||||
		   CopyFromParent, /* visual */
 | 
			
		||||
		   CWEventMask|CWOverrideRedirect|CWBackPixel,
 | 
			
		||||
		   &attributes);
 | 
			
		||||
  meta_stack_tracker_record_add (screen->stack_tracker,
 | 
			
		||||
                                 guard_window,
 | 
			
		||||
                                 XNextRequest(xdisplay) - 1);
 | 
			
		||||
 | 
			
		||||
  XLowerWindow (xdisplay, guard_window);
 | 
			
		||||
  XMapWindow (xdisplay, guard_window);
 | 
			
		||||
  return guard_window;
 | 
			
		||||
@@ -730,6 +734,7 @@ meta_screen_new (MetaDisplay *display,
 | 
			
		||||
  screen->ws_popup = NULL;
 | 
			
		||||
  
 | 
			
		||||
  screen->stack = meta_stack_new (screen);
 | 
			
		||||
  screen->stack_tracker = meta_stack_tracker_new (screen);
 | 
			
		||||
 | 
			
		||||
  meta_prefs_add_listener (prefs_changed_callback, screen);
 | 
			
		||||
 | 
			
		||||
@@ -807,6 +812,7 @@ meta_screen_free (MetaScreen *screen,
 | 
			
		||||
  meta_ui_free (screen->ui);
 | 
			
		||||
 | 
			
		||||
  meta_stack_free (screen->stack);
 | 
			
		||||
  meta_stack_tracker_free (screen->stack_tracker);
 | 
			
		||||
 | 
			
		||||
  meta_error_trap_push_with_return (screen->display);
 | 
			
		||||
  XSelectInput (screen->display->xdisplay, screen->xroot, 0);
 | 
			
		||||
@@ -934,14 +940,13 @@ meta_screen_composite_all_windows (MetaScreen *screen)
 | 
			
		||||
  if (!display->compositor)
 | 
			
		||||
    return;
 | 
			
		||||
 | 
			
		||||
  windows = meta_display_list_windows (display);
 | 
			
		||||
  windows = meta_display_list_all_windows (display);
 | 
			
		||||
  for (tmp = windows; tmp != NULL; tmp = tmp->next)
 | 
			
		||||
    meta_compositor_add_window (display->compositor, tmp->data);
 | 
			
		||||
  g_slist_free (windows);
 | 
			
		||||
  
 | 
			
		||||
  /* trigger a stack_sync_to_server: */
 | 
			
		||||
  meta_stack_freeze (screen->stack);
 | 
			
		||||
  meta_stack_thaw (screen->stack);
 | 
			
		||||
  /* initialize the compositor's view of the stacking order */
 | 
			
		||||
  meta_stack_tracker_sync_stack (screen->stack_tracker);
 | 
			
		||||
#endif
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@@ -1044,6 +1049,15 @@ listify_func (gpointer key, gpointer value, gpointer data)
 | 
			
		||||
  *listp = g_slist_prepend (*listp, value);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * meta_screen_foreach_window:
 | 
			
		||||
 * @screen: a #MetaScreen
 | 
			
		||||
 * @func: function to call for each window
 | 
			
		||||
 * @data: user data to pass to @func
 | 
			
		||||
 *
 | 
			
		||||
 * Calls the specified function for each window on the screen,
 | 
			
		||||
 * ignoring override-redirect windows.
 | 
			
		||||
 */
 | 
			
		||||
void
 | 
			
		||||
meta_screen_foreach_window (MetaScreen *screen,
 | 
			
		||||
                            MetaScreenWindowFunc func,
 | 
			
		||||
@@ -1074,7 +1088,7 @@ meta_screen_foreach_window (MetaScreen *screen,
 | 
			
		||||
        {
 | 
			
		||||
          MetaWindow *window = tmp->data;
 | 
			
		||||
 | 
			
		||||
          if (window->screen == screen)
 | 
			
		||||
          if (window->screen == screen && !window->override_redirect)
 | 
			
		||||
            (* func) (screen, window, data);
 | 
			
		||||
        }
 | 
			
		||||
      
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										728
									
								
								src/core/stack-tracker.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										728
									
								
								src/core/stack-tracker.c
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,728 @@
 | 
			
		||||
/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 * Copyright (C) 2009 Red Hat, Inc.
 | 
			
		||||
 *
 | 
			
		||||
 * 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.
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
#include <config.h>
 | 
			
		||||
 | 
			
		||||
#include <string.h>
 | 
			
		||||
 | 
			
		||||
#include "screen-private.h"
 | 
			
		||||
#include "stack-tracker.h"
 | 
			
		||||
#include "util.h"
 | 
			
		||||
 | 
			
		||||
#include "compositor.h"
 | 
			
		||||
 | 
			
		||||
/* The complexity here comes from resolving two competing factors:
 | 
			
		||||
 *
 | 
			
		||||
 *  - We need to have a view of the stacking order that takes into
 | 
			
		||||
 *    account everything we have done without waiting for events
 | 
			
		||||
 *    back from the X server; we don't want to draw intermediate
 | 
			
		||||
 *    partially-stacked stack states just because we haven't received
 | 
			
		||||
 *    some notification yet.
 | 
			
		||||
 *
 | 
			
		||||
 *  - Only the X server has an accurate view of the complete stacking;
 | 
			
		||||
 *    when we make a request to restack windows, we don't know how
 | 
			
		||||
 *    it will affect override-redirect windows, because at any point
 | 
			
		||||
 *    applications may restack these windows without our involvement.
 | 
			
		||||
 *
 | 
			
		||||
 * The technique we use is that we keep three sets of information:
 | 
			
		||||
 *
 | 
			
		||||
 *  - The stacking order on the server as known from the last
 | 
			
		||||
 *    event we received.
 | 
			
		||||
 *  - A queue of stacking requests that *we* made subsequent to
 | 
			
		||||
 *    that last event.
 | 
			
		||||
 *  - A predicted stacking order, derived from applying the queued
 | 
			
		||||
 *    requests to the last state from the server.
 | 
			
		||||
 *
 | 
			
		||||
 * When we receive a new event: a) we compare the serial in the event to
 | 
			
		||||
 * the serial of the queued requests and remove any that are now
 | 
			
		||||
 * no longer pending b) drop the predicted stacking order to recompute
 | 
			
		||||
 * it at the next opportunity.
 | 
			
		||||
 *
 | 
			
		||||
 * Possible optimizations:
 | 
			
		||||
 *  Keep the stacks as an array + reverse-mapping hash table to avoid
 | 
			
		||||
 *    linear lookups.
 | 
			
		||||
 *  Keep the stacks as a GList + reverse-mapping hash table to avoid
 | 
			
		||||
 *    linear lookups and to make restacking constant-time.
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
typedef union _MetaStackOp MetaStackOp;
 | 
			
		||||
 | 
			
		||||
typedef enum {
 | 
			
		||||
  STACK_OP_ADD,
 | 
			
		||||
  STACK_OP_REMOVE,
 | 
			
		||||
  STACK_OP_RAISE_ABOVE,
 | 
			
		||||
  STACK_OP_LOWER_BELOW
 | 
			
		||||
} MetaStackOpType;
 | 
			
		||||
 | 
			
		||||
/* MetaStackOp represents a "stacking operation" - a change to
 | 
			
		||||
 * apply to a window stack. Depending on the context, it could
 | 
			
		||||
 * either reflect a request we have sent to the server, or a
 | 
			
		||||
 * notification event we received from the X server.
 | 
			
		||||
 */
 | 
			
		||||
union _MetaStackOp
 | 
			
		||||
{
 | 
			
		||||
  struct {
 | 
			
		||||
    MetaStackOpType type;
 | 
			
		||||
    gulong serial;
 | 
			
		||||
  } any;
 | 
			
		||||
  struct {
 | 
			
		||||
    MetaStackOpType type;
 | 
			
		||||
    gulong serial;
 | 
			
		||||
    Window window;
 | 
			
		||||
  } add;
 | 
			
		||||
  struct {
 | 
			
		||||
    MetaStackOpType type;
 | 
			
		||||
    gulong serial;
 | 
			
		||||
    Window window;
 | 
			
		||||
  } remove;
 | 
			
		||||
  struct {
 | 
			
		||||
    MetaStackOpType type;
 | 
			
		||||
    gulong serial;
 | 
			
		||||
    Window window;
 | 
			
		||||
    Window sibling;
 | 
			
		||||
  } raise_above;
 | 
			
		||||
  struct {
 | 
			
		||||
    MetaStackOpType type;
 | 
			
		||||
    gulong serial;
 | 
			
		||||
    Window window;
 | 
			
		||||
    Window sibling;
 | 
			
		||||
  } lower_below;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
struct _MetaStackTracker
 | 
			
		||||
{
 | 
			
		||||
  MetaScreen *screen;
 | 
			
		||||
 | 
			
		||||
  /* This is the last state of the stack as based on events received
 | 
			
		||||
   * from the X server.
 | 
			
		||||
   */
 | 
			
		||||
  GArray *server_stack;
 | 
			
		||||
 | 
			
		||||
  /* This is the serial of the last request we made that was reflected
 | 
			
		||||
   * in server_stack
 | 
			
		||||
   */
 | 
			
		||||
  gulong server_serial;
 | 
			
		||||
 | 
			
		||||
  /* This is a queue of requests we've made to change the stacking order,
 | 
			
		||||
   * where we haven't yet gotten a reply back from the server.
 | 
			
		||||
   */
 | 
			
		||||
  GQueue *queued_requests;
 | 
			
		||||
 | 
			
		||||
  /* This is how we think the stack is, based on server_stack, and
 | 
			
		||||
   * on requests we've made subsequent to server_stack
 | 
			
		||||
   */
 | 
			
		||||
  GArray *predicted_stack;
 | 
			
		||||
 | 
			
		||||
  /* Idle function used to sync the compositor's view of the window
 | 
			
		||||
   * stack up with our best guess before a frame is drawn.
 | 
			
		||||
   */
 | 
			
		||||
  guint sync_stack_idle;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
static void
 | 
			
		||||
meta_stack_op_dump (MetaStackOp *op,
 | 
			
		||||
		    const char  *prefix,
 | 
			
		||||
		    const char  *suffix)
 | 
			
		||||
{
 | 
			
		||||
  switch (op->any.type)
 | 
			
		||||
    {
 | 
			
		||||
    case STACK_OP_ADD:
 | 
			
		||||
      meta_topic (META_DEBUG_STACK, "%sADD(%#lx; %ld)%s",
 | 
			
		||||
		  prefix, op->add.window, op->any.serial, suffix);
 | 
			
		||||
      break;
 | 
			
		||||
    case STACK_OP_REMOVE:
 | 
			
		||||
      meta_topic (META_DEBUG_STACK, "%sREMOVE(%#lx; %ld)%s",
 | 
			
		||||
		  prefix, op->add.window, op->any.serial, suffix);
 | 
			
		||||
      break;
 | 
			
		||||
    case STACK_OP_RAISE_ABOVE:
 | 
			
		||||
      meta_topic (META_DEBUG_STACK, "%sRAISE_ABOVE(%#lx, %#lx; %ld)%s",
 | 
			
		||||
		  prefix,
 | 
			
		||||
                  op->raise_above.window, op->raise_above.sibling,
 | 
			
		||||
                  op->any.serial,
 | 
			
		||||
                  suffix);
 | 
			
		||||
      break;
 | 
			
		||||
    case STACK_OP_LOWER_BELOW:
 | 
			
		||||
      meta_topic (META_DEBUG_STACK, "%sLOWER_BELOW(%#lx, %#lx; %ld)%s",
 | 
			
		||||
		  prefix,
 | 
			
		||||
                  op->lower_below.window, op->lower_below.sibling,
 | 
			
		||||
                  op->any.serial,
 | 
			
		||||
                  suffix);
 | 
			
		||||
      break;
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void
 | 
			
		||||
meta_stack_tracker_dump (MetaStackTracker *tracker)
 | 
			
		||||
{
 | 
			
		||||
  guint i;
 | 
			
		||||
  GList *l;
 | 
			
		||||
 | 
			
		||||
  meta_topic (META_DEBUG_STACK, "MetaStackTracker state (screen=%d)\n", tracker->screen->number);
 | 
			
		||||
  meta_push_no_msg_prefix ();
 | 
			
		||||
  meta_topic (META_DEBUG_STACK, "  server_serial: %ld\n", tracker->server_serial);
 | 
			
		||||
  meta_topic (META_DEBUG_STACK, "  server_stack: ");
 | 
			
		||||
  for (i = 0; i < tracker->server_stack->len; i++)
 | 
			
		||||
    meta_topic (META_DEBUG_STACK, "  %#lx", g_array_index (tracker->server_stack, Window, i));
 | 
			
		||||
  if (tracker->predicted_stack)
 | 
			
		||||
    {
 | 
			
		||||
      meta_topic (META_DEBUG_STACK, "\n  predicted_stack: ");
 | 
			
		||||
      for (i = 0; i < tracker->predicted_stack->len; i++)
 | 
			
		||||
	meta_topic (META_DEBUG_STACK, "  %#lx", g_array_index (tracker->predicted_stack, Window, i));
 | 
			
		||||
    }
 | 
			
		||||
  meta_topic (META_DEBUG_STACK, "\n  queued_requests: [");
 | 
			
		||||
  for (l = tracker->queued_requests->head; l; l = l->next)
 | 
			
		||||
    {
 | 
			
		||||
      MetaStackOp *op = l->data;
 | 
			
		||||
      meta_stack_op_dump (op, "", l->next ? ", " : "");
 | 
			
		||||
    }
 | 
			
		||||
  meta_topic (META_DEBUG_STACK, "]\n");
 | 
			
		||||
  meta_pop_no_msg_prefix ();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void
 | 
			
		||||
meta_stack_op_free (MetaStackOp *op)
 | 
			
		||||
{
 | 
			
		||||
  g_slice_free (MetaStackOp, op);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static int
 | 
			
		||||
find_window (GArray *stack,
 | 
			
		||||
	     Window  window)
 | 
			
		||||
{
 | 
			
		||||
  guint i;
 | 
			
		||||
 | 
			
		||||
  for (i = 0; i < stack->len; i++)
 | 
			
		||||
    if (g_array_index (stack, Window, i) == window)
 | 
			
		||||
      return i;
 | 
			
		||||
 | 
			
		||||
  return -1;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/* Returns TRUE if stack was changed */
 | 
			
		||||
static gboolean
 | 
			
		||||
move_window_above (GArray *stack,
 | 
			
		||||
                   Window  window,
 | 
			
		||||
                   int     old_pos,
 | 
			
		||||
                   int     above_pos)
 | 
			
		||||
{
 | 
			
		||||
  int i;
 | 
			
		||||
 | 
			
		||||
  if (old_pos < above_pos)
 | 
			
		||||
    {
 | 
			
		||||
      for (i = old_pos; i < above_pos; i++)
 | 
			
		||||
	g_array_index (stack, Window, i) = g_array_index (stack, Window, i + 1);
 | 
			
		||||
 | 
			
		||||
      g_array_index (stack, Window, above_pos) = window;
 | 
			
		||||
 | 
			
		||||
      return TRUE;
 | 
			
		||||
    }
 | 
			
		||||
  else if (old_pos > above_pos + 1)
 | 
			
		||||
    {
 | 
			
		||||
      for (i = old_pos; i > above_pos + 1; i--)
 | 
			
		||||
	g_array_index (stack, Window, i) = g_array_index (stack, Window, i - 1);
 | 
			
		||||
 | 
			
		||||
      g_array_index (stack, Window, above_pos + 1) = window;
 | 
			
		||||
 | 
			
		||||
      return TRUE;
 | 
			
		||||
    }
 | 
			
		||||
  else
 | 
			
		||||
    return FALSE;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/* Returns TRUE if stack was changed */
 | 
			
		||||
static gboolean
 | 
			
		||||
meta_stack_op_apply (MetaStackOp *op,
 | 
			
		||||
		     GArray      *stack)
 | 
			
		||||
{
 | 
			
		||||
  switch (op->any.type)
 | 
			
		||||
    {
 | 
			
		||||
    case STACK_OP_ADD:
 | 
			
		||||
      {
 | 
			
		||||
	int old_pos = find_window (stack, op->add.window);
 | 
			
		||||
	if (old_pos >= 0)
 | 
			
		||||
	  {
 | 
			
		||||
	    g_warning ("STACK_OP_ADD: window %#lx already in stack",
 | 
			
		||||
		       op->add.window);
 | 
			
		||||
	    return FALSE;
 | 
			
		||||
	  }
 | 
			
		||||
 | 
			
		||||
	g_array_append_val (stack, op->add.window);
 | 
			
		||||
	return TRUE;
 | 
			
		||||
      }
 | 
			
		||||
    case STACK_OP_REMOVE:
 | 
			
		||||
      {
 | 
			
		||||
	int old_pos = find_window (stack, op->remove.window);
 | 
			
		||||
	if (old_pos < 0)
 | 
			
		||||
	  {
 | 
			
		||||
	    g_warning ("STACK_OP_REMOVE: window %#lx not in stack",
 | 
			
		||||
		       op->remove.window);
 | 
			
		||||
	    return FALSE;
 | 
			
		||||
	  }
 | 
			
		||||
 | 
			
		||||
	g_array_remove_index (stack, old_pos);
 | 
			
		||||
	return TRUE;
 | 
			
		||||
      }
 | 
			
		||||
    case STACK_OP_RAISE_ABOVE:
 | 
			
		||||
      {
 | 
			
		||||
	int old_pos = find_window (stack, op->raise_above.window);
 | 
			
		||||
	int above_pos;
 | 
			
		||||
	if (old_pos < 0)
 | 
			
		||||
	  {
 | 
			
		||||
	    g_warning ("STACK_OP_RAISE_ABOVE: window %#lx not in stack",
 | 
			
		||||
		       op->raise_above.window);
 | 
			
		||||
	    return FALSE;
 | 
			
		||||
	  }
 | 
			
		||||
 | 
			
		||||
	if (op->raise_above.sibling != None)
 | 
			
		||||
	  {
 | 
			
		||||
	    above_pos = find_window (stack, op->raise_above.sibling);
 | 
			
		||||
	    if (above_pos < 0)
 | 
			
		||||
	      {
 | 
			
		||||
		g_warning ("STACK_OP_RAISE_ABOVE: sibling window %#lx not in stack",
 | 
			
		||||
			   op->raise_above.sibling);
 | 
			
		||||
		return FALSE;
 | 
			
		||||
	      }
 | 
			
		||||
	  }
 | 
			
		||||
	else
 | 
			
		||||
	  {
 | 
			
		||||
	    above_pos = -1;
 | 
			
		||||
	  }
 | 
			
		||||
 | 
			
		||||
	return move_window_above (stack, op->raise_above.window, old_pos, above_pos);
 | 
			
		||||
      }
 | 
			
		||||
    case STACK_OP_LOWER_BELOW:
 | 
			
		||||
      {
 | 
			
		||||
	int old_pos = find_window (stack, op->lower_below.window);
 | 
			
		||||
	int above_pos;
 | 
			
		||||
	if (old_pos < 0)
 | 
			
		||||
	  {
 | 
			
		||||
	    g_warning ("STACK_OP_LOWER_BELOW: window %#lx not in stack",
 | 
			
		||||
		       op->lower_below.window);
 | 
			
		||||
	    return FALSE;
 | 
			
		||||
	  }
 | 
			
		||||
 | 
			
		||||
	if (op->lower_below.sibling != None)
 | 
			
		||||
	  {
 | 
			
		||||
	    int below_pos = find_window (stack, op->lower_below.sibling);
 | 
			
		||||
	    if (below_pos < 0)
 | 
			
		||||
	      {
 | 
			
		||||
		g_warning ("STACK_OP_LOWER_BELOW: sibling window %#lx not in stack",
 | 
			
		||||
			   op->lower_below.sibling);
 | 
			
		||||
		return FALSE;
 | 
			
		||||
	      }
 | 
			
		||||
 | 
			
		||||
	    above_pos = below_pos - 1;
 | 
			
		||||
	  }
 | 
			
		||||
	else
 | 
			
		||||
	  {
 | 
			
		||||
	    above_pos = stack->len - 1;
 | 
			
		||||
	  }
 | 
			
		||||
 | 
			
		||||
	return move_window_above (stack, op->lower_below.window, old_pos, above_pos);
 | 
			
		||||
      }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
  g_assert_not_reached ();
 | 
			
		||||
  return FALSE;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static GArray *
 | 
			
		||||
copy_stack (Window *windows,
 | 
			
		||||
	    guint   n_windows)
 | 
			
		||||
{
 | 
			
		||||
  GArray *stack = g_array_new (FALSE, FALSE, sizeof (Window));
 | 
			
		||||
 | 
			
		||||
  g_array_set_size (stack, n_windows);
 | 
			
		||||
  memcpy (stack->data, windows, sizeof (Window) * n_windows);
 | 
			
		||||
 | 
			
		||||
  return stack;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
MetaStackTracker *
 | 
			
		||||
meta_stack_tracker_new (MetaScreen *screen)
 | 
			
		||||
{
 | 
			
		||||
  MetaStackTracker *tracker;
 | 
			
		||||
  Window ignored1, ignored2;
 | 
			
		||||
  Window *children;
 | 
			
		||||
  guint n_children;
 | 
			
		||||
 | 
			
		||||
  tracker = g_new0 (MetaStackTracker, 1);
 | 
			
		||||
  tracker->screen = screen;
 | 
			
		||||
 | 
			
		||||
  tracker->server_serial = XNextRequest (screen->display->xdisplay);
 | 
			
		||||
 | 
			
		||||
  XQueryTree (screen->display->xdisplay,
 | 
			
		||||
              screen->xroot,
 | 
			
		||||
              &ignored1, &ignored2, &children, &n_children);
 | 
			
		||||
  tracker->server_stack = copy_stack (children, n_children);
 | 
			
		||||
  XFree (children);
 | 
			
		||||
 | 
			
		||||
  tracker->queued_requests = g_queue_new ();
 | 
			
		||||
 | 
			
		||||
  return tracker;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void
 | 
			
		||||
meta_stack_tracker_free (MetaStackTracker *tracker)
 | 
			
		||||
{
 | 
			
		||||
  if (tracker->sync_stack_idle)
 | 
			
		||||
    g_source_remove (tracker->sync_stack_idle);
 | 
			
		||||
 | 
			
		||||
  g_array_free (tracker->server_stack, TRUE);
 | 
			
		||||
  if (tracker->predicted_stack)
 | 
			
		||||
    g_array_free (tracker->predicted_stack, TRUE);
 | 
			
		||||
 | 
			
		||||
  g_queue_foreach (tracker->queued_requests, (GFunc)meta_stack_op_free, NULL);
 | 
			
		||||
  g_queue_free (tracker->queued_requests);
 | 
			
		||||
  tracker->queued_requests = NULL;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void
 | 
			
		||||
stack_tracker_queue_request (MetaStackTracker *tracker,
 | 
			
		||||
			     MetaStackOp      *op)
 | 
			
		||||
{
 | 
			
		||||
  meta_stack_op_dump (op, "Queueing: ", "\n");
 | 
			
		||||
  g_queue_push_tail (tracker->queued_requests, op);
 | 
			
		||||
  if (!tracker->predicted_stack ||
 | 
			
		||||
      meta_stack_op_apply (op, tracker->predicted_stack))
 | 
			
		||||
    meta_stack_tracker_queue_sync_stack (tracker);
 | 
			
		||||
 | 
			
		||||
  meta_stack_tracker_dump (tracker);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void
 | 
			
		||||
meta_stack_tracker_record_add (MetaStackTracker *tracker,
 | 
			
		||||
			       Window            window,
 | 
			
		||||
			       gulong            serial)
 | 
			
		||||
{
 | 
			
		||||
  MetaStackOp *op = g_slice_new (MetaStackOp);
 | 
			
		||||
 | 
			
		||||
  op->any.type = STACK_OP_ADD;
 | 
			
		||||
  op->any.serial = serial;
 | 
			
		||||
  op->add.window = window;
 | 
			
		||||
 | 
			
		||||
  stack_tracker_queue_request (tracker, op);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void
 | 
			
		||||
meta_stack_tracker_record_remove (MetaStackTracker *tracker,
 | 
			
		||||
				  Window            window,
 | 
			
		||||
				  gulong            serial)
 | 
			
		||||
{
 | 
			
		||||
  MetaStackOp *op = g_slice_new (MetaStackOp);
 | 
			
		||||
 | 
			
		||||
  op->any.type = STACK_OP_REMOVE;
 | 
			
		||||
  op->any.serial = serial;
 | 
			
		||||
  op->remove.window = window;
 | 
			
		||||
 | 
			
		||||
  stack_tracker_queue_request (tracker, op);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void
 | 
			
		||||
meta_stack_tracker_record_restack_windows (MetaStackTracker *tracker,
 | 
			
		||||
					   Window           *windows,
 | 
			
		||||
					   int               n_windows,
 | 
			
		||||
					   gulong            serial)
 | 
			
		||||
{
 | 
			
		||||
  int i;
 | 
			
		||||
 | 
			
		||||
  /* XRestackWindows() isn't actually a X requests - it's broken down
 | 
			
		||||
   * by XLib into a series of XConfigureWindow(StackMode=below); we
 | 
			
		||||
   * mirror that exactly here.
 | 
			
		||||
   *
 | 
			
		||||
   * Aside: Having a separate StackOp for this would be possible to
 | 
			
		||||
   * get some extra efficiency in memory allocation and in applying
 | 
			
		||||
   * the op, at the expense of a code complexity. Implementation hint
 | 
			
		||||
   * for that - keep op->restack_window.n_complete, and when receiving
 | 
			
		||||
   * events with intermediate serials, set n_complete rather than
 | 
			
		||||
   * removing the op from the queue.
 | 
			
		||||
   */
 | 
			
		||||
  for (i = 0; i < n_windows - 1; i++)
 | 
			
		||||
    meta_stack_tracker_record_lower_below (tracker, windows[i + 1], windows[i],
 | 
			
		||||
					   serial + i);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void
 | 
			
		||||
meta_stack_tracker_record_raise_above (MetaStackTracker *tracker,
 | 
			
		||||
				       Window            window,
 | 
			
		||||
				       Window            sibling,
 | 
			
		||||
				       gulong            serial)
 | 
			
		||||
{
 | 
			
		||||
  MetaStackOp *op = g_slice_new (MetaStackOp);
 | 
			
		||||
 | 
			
		||||
  op->any.type = STACK_OP_RAISE_ABOVE;
 | 
			
		||||
  op->any.serial = serial;
 | 
			
		||||
  op->raise_above.window = window;
 | 
			
		||||
  op->raise_above.sibling = sibling;
 | 
			
		||||
 | 
			
		||||
  stack_tracker_queue_request (tracker, op);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void
 | 
			
		||||
meta_stack_tracker_record_lower_below (MetaStackTracker *tracker,
 | 
			
		||||
				       Window            window,
 | 
			
		||||
				       Window            sibling,
 | 
			
		||||
				       gulong            serial)
 | 
			
		||||
{
 | 
			
		||||
  MetaStackOp *op = g_slice_new (MetaStackOp);
 | 
			
		||||
 | 
			
		||||
  op->any.type = STACK_OP_LOWER_BELOW;
 | 
			
		||||
  op->any.serial = serial;
 | 
			
		||||
  op->lower_below.window = window;
 | 
			
		||||
  op->lower_below.sibling = sibling;
 | 
			
		||||
 | 
			
		||||
  stack_tracker_queue_request (tracker, op);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void
 | 
			
		||||
meta_stack_tracker_record_lower (MetaStackTracker *tracker,
 | 
			
		||||
				 Window            window,
 | 
			
		||||
				 gulong            serial)
 | 
			
		||||
{
 | 
			
		||||
  meta_stack_tracker_record_raise_above (tracker, window, None, serial);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void
 | 
			
		||||
stack_tracker_event_received (MetaStackTracker *tracker,
 | 
			
		||||
			      MetaStackOp      *op)
 | 
			
		||||
{
 | 
			
		||||
  meta_stack_op_dump (op, "Stack op event received: ", "\n");
 | 
			
		||||
 | 
			
		||||
  if (op->any.serial < tracker->server_serial)
 | 
			
		||||
    return;
 | 
			
		||||
 | 
			
		||||
  tracker->server_serial = op->any.serial;
 | 
			
		||||
 | 
			
		||||
  meta_stack_op_apply (op, tracker->server_stack);
 | 
			
		||||
 | 
			
		||||
  while (tracker->queued_requests->head)
 | 
			
		||||
    {
 | 
			
		||||
      MetaStackOp *queued_op = tracker->queued_requests->head->data;
 | 
			
		||||
      if (queued_op->any.serial > op->any.serial)
 | 
			
		||||
	break;
 | 
			
		||||
 | 
			
		||||
      g_queue_pop_head (tracker->queued_requests);
 | 
			
		||||
      meta_stack_op_free (queued_op);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
  if (tracker->predicted_stack)
 | 
			
		||||
    {
 | 
			
		||||
      g_array_free (tracker->predicted_stack, TRUE);
 | 
			
		||||
      tracker->predicted_stack = NULL;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
  meta_stack_tracker_dump (tracker);
 | 
			
		||||
 | 
			
		||||
  meta_stack_tracker_queue_sync_stack (tracker);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void
 | 
			
		||||
meta_stack_tracker_create_event (MetaStackTracker    *tracker,
 | 
			
		||||
				 XCreateWindowEvent  *event)
 | 
			
		||||
{
 | 
			
		||||
  MetaStackOp op;
 | 
			
		||||
 | 
			
		||||
  op.any.type = STACK_OP_ADD;
 | 
			
		||||
  op.any.serial = event->serial;
 | 
			
		||||
  op.add.window = event->window;
 | 
			
		||||
 | 
			
		||||
  stack_tracker_event_received (tracker, &op);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void
 | 
			
		||||
meta_stack_tracker_destroy_event (MetaStackTracker    *tracker,
 | 
			
		||||
				  XDestroyWindowEvent *event)
 | 
			
		||||
{
 | 
			
		||||
  MetaStackOp op;
 | 
			
		||||
 | 
			
		||||
  op.any.type = STACK_OP_REMOVE;
 | 
			
		||||
  op.any.serial = event->serial;
 | 
			
		||||
  op.remove.window = event->window;
 | 
			
		||||
 | 
			
		||||
  stack_tracker_event_received (tracker, &op);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void
 | 
			
		||||
meta_stack_tracker_reparent_event (MetaStackTracker    *tracker,
 | 
			
		||||
				   XReparentEvent      *event)
 | 
			
		||||
{
 | 
			
		||||
  if (event->parent == event->event)
 | 
			
		||||
    {
 | 
			
		||||
      MetaStackOp op;
 | 
			
		||||
 | 
			
		||||
      op.any.type = STACK_OP_ADD;
 | 
			
		||||
      op.any.serial = event->serial;
 | 
			
		||||
      op.add.window = event->window;
 | 
			
		||||
 | 
			
		||||
      stack_tracker_event_received (tracker, &op);
 | 
			
		||||
    }
 | 
			
		||||
  else
 | 
			
		||||
    {
 | 
			
		||||
      MetaStackOp op;
 | 
			
		||||
 | 
			
		||||
      op.any.type = STACK_OP_REMOVE;
 | 
			
		||||
      op.any.serial = event->serial;
 | 
			
		||||
      op.remove.window = event->window;
 | 
			
		||||
 | 
			
		||||
      stack_tracker_event_received (tracker, &op);
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void
 | 
			
		||||
meta_stack_tracker_configure_event (MetaStackTracker    *tracker,
 | 
			
		||||
				    XConfigureEvent     *event)
 | 
			
		||||
{
 | 
			
		||||
  MetaStackOp op;
 | 
			
		||||
 | 
			
		||||
  op.any.type = STACK_OP_RAISE_ABOVE;
 | 
			
		||||
  op.any.serial = event->serial;
 | 
			
		||||
  op.raise_above.window = event->window;
 | 
			
		||||
  op.raise_above.sibling = event->above;
 | 
			
		||||
 | 
			
		||||
  stack_tracker_event_received (tracker, &op);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * meta_stack_tracker_get_stack:
 | 
			
		||||
 * @tracker: a #MetaStackTracker
 | 
			
		||||
 * @windows: location to store list of windows, or %NULL
 | 
			
		||||
 * @n_windows: location to store count of windows, or %NULL
 | 
			
		||||
 *
 | 
			
		||||
 * Returns the most current view we have of the stacking order
 | 
			
		||||
 * of the children of the root window. The returned array contains
 | 
			
		||||
 * everything: InputOnly windows, override-redirect windows,
 | 
			
		||||
 * hidden windows, etc. Some of these will correspond to MetaWindow
 | 
			
		||||
 * objects, others won't.
 | 
			
		||||
 *
 | 
			
		||||
 * Assuming that no other clients have made requests that change
 | 
			
		||||
 * the stacking order since we last received a notification, the
 | 
			
		||||
 * returned list of windows is exactly that you'd get as the
 | 
			
		||||
 * children when calling XQueryTree() on the root window.
 | 
			
		||||
 */
 | 
			
		||||
void
 | 
			
		||||
meta_stack_tracker_get_stack (MetaStackTracker *tracker,
 | 
			
		||||
			      Window          **windows,
 | 
			
		||||
			      int              *n_windows)
 | 
			
		||||
{
 | 
			
		||||
  GArray *stack;
 | 
			
		||||
 | 
			
		||||
  if (tracker->queued_requests->length == 0)
 | 
			
		||||
    {
 | 
			
		||||
      stack = tracker->server_stack;
 | 
			
		||||
    }
 | 
			
		||||
  else
 | 
			
		||||
    {
 | 
			
		||||
      if (tracker->predicted_stack == NULL)
 | 
			
		||||
        {
 | 
			
		||||
          GList *l;
 | 
			
		||||
 | 
			
		||||
          tracker->predicted_stack = copy_stack ((Window *)tracker->server_stack->data,
 | 
			
		||||
                                                 tracker->server_stack->len);
 | 
			
		||||
          for (l = tracker->queued_requests->head; l; l = l->next)
 | 
			
		||||
            {
 | 
			
		||||
              MetaStackOp *op = l->data;
 | 
			
		||||
              meta_stack_op_apply (op, tracker->predicted_stack);
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
      stack = tracker->predicted_stack;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
  if (windows)
 | 
			
		||||
    *windows = (Window *)stack->data;
 | 
			
		||||
  if (n_windows)
 | 
			
		||||
    *n_windows = stack->len;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * meta_stack_tracker_sync_stack:
 | 
			
		||||
 * @tracker: a #MetaStackTracker
 | 
			
		||||
 *
 | 
			
		||||
 * Informs the compositor of the current stacking order of windows,
 | 
			
		||||
 * based on the predicted view maintained by the #MetaStackTracker.
 | 
			
		||||
 */
 | 
			
		||||
void
 | 
			
		||||
meta_stack_tracker_sync_stack (MetaStackTracker *tracker)
 | 
			
		||||
{
 | 
			
		||||
  GList *meta_windows;
 | 
			
		||||
  Window *windows;
 | 
			
		||||
  int n_windows;
 | 
			
		||||
  int i;
 | 
			
		||||
 | 
			
		||||
  if (tracker->sync_stack_idle)
 | 
			
		||||
    {
 | 
			
		||||
      g_source_remove (tracker->sync_stack_idle);
 | 
			
		||||
      tracker->sync_stack_idle = 0;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
  meta_stack_tracker_get_stack (tracker, &windows, &n_windows);
 | 
			
		||||
 | 
			
		||||
  meta_windows = NULL;
 | 
			
		||||
  for (i = 0; i < n_windows; i++)
 | 
			
		||||
    {
 | 
			
		||||
      MetaWindow *meta_window;
 | 
			
		||||
 | 
			
		||||
      meta_window = meta_display_lookup_x_window (tracker->screen->display,
 | 
			
		||||
                                                  windows[i]);
 | 
			
		||||
      if (meta_window)
 | 
			
		||||
        meta_windows = g_list_prepend (meta_windows, meta_window);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
  meta_compositor_sync_stack (tracker->screen->display->compositor,
 | 
			
		||||
			      tracker->screen,
 | 
			
		||||
			      meta_windows);
 | 
			
		||||
  g_list_free (meta_windows);
 | 
			
		||||
 | 
			
		||||
  meta_screen_restacked (tracker->screen);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static gboolean
 | 
			
		||||
stack_tracker_sync_stack_idle (gpointer data)
 | 
			
		||||
{
 | 
			
		||||
  meta_stack_tracker_sync_stack (data);
 | 
			
		||||
 | 
			
		||||
  return FALSE;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * meta_stack_tracker_queue_sync_stack:
 | 
			
		||||
 * @tracker: a #MetaStackTracker
 | 
			
		||||
 *
 | 
			
		||||
 * Queue informing the compositor of the new stacking order before the
 | 
			
		||||
 * next redraw. (See meta_stack_tracker_sync_stack()). This is called
 | 
			
		||||
 * internally when the stack of X windows changes, but also needs be
 | 
			
		||||
 * called directly when we an undecorated window is first shown or
 | 
			
		||||
 * withdrawn since the compositor's stacking order (which contains only
 | 
			
		||||
 * the windows that have a corresponding MetaWindow) will change without
 | 
			
		||||
 * any change to the stacking order of the X windows, if we are creating
 | 
			
		||||
 * or destroying MetaWindows.
 | 
			
		||||
 */
 | 
			
		||||
void
 | 
			
		||||
meta_stack_tracker_queue_sync_stack (MetaStackTracker *tracker)
 | 
			
		||||
{
 | 
			
		||||
  if (tracker->sync_stack_idle == 0)
 | 
			
		||||
    {
 | 
			
		||||
      tracker->sync_stack_idle = g_idle_add_full (META_PRIORITY_BEFORE_REDRAW,
 | 
			
		||||
                                                  stack_tracker_sync_stack_idle,
 | 
			
		||||
                                                  tracker, NULL);
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										89
									
								
								src/core/stack-tracker.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										89
									
								
								src/core/stack-tracker.h
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,89 @@
 | 
			
		||||
/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * \file stack-tracker.h  Track stacking order for compositor
 | 
			
		||||
 *
 | 
			
		||||
 * MetaStackTracker maintains the most accurate view we have at a
 | 
			
		||||
 * given point of time of the ordering of the children of the root
 | 
			
		||||
 * window (including override-redirect windows.) This is used to order
 | 
			
		||||
 * the windows when the compositor draws them.
 | 
			
		||||
 *
 | 
			
		||||
 * By contrast, MetaStack is responsible for keeping track of how we
 | 
			
		||||
 * think that windows *should* be ordered.  For windows we manage
 | 
			
		||||
 * (non-override-redirect windows), the two stacking orders will be
 | 
			
		||||
 * the same.
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 * Copyright (C) 2009 Red Hat, Inc.
 | 
			
		||||
 *
 | 
			
		||||
 * 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_TRACKER_H
 | 
			
		||||
#define META_STACK_TRACKER_H
 | 
			
		||||
 | 
			
		||||
#include "screen.h"
 | 
			
		||||
 | 
			
		||||
typedef struct _MetaStackTracker MetaStackTracker;
 | 
			
		||||
 | 
			
		||||
MetaStackTracker *meta_stack_tracker_new  (MetaScreen       *screen);
 | 
			
		||||
void              meta_stack_tracker_free (MetaStackTracker *tracker);
 | 
			
		||||
 | 
			
		||||
/* These functions are called when we make an X call that changes the
 | 
			
		||||
 * stacking order; this allows MetaStackTracker to predict stacking
 | 
			
		||||
 * order before it receives events back from the X server */
 | 
			
		||||
void meta_stack_tracker_record_add             (MetaStackTracker *tracker,
 | 
			
		||||
						Window            window,
 | 
			
		||||
                                                gulong            serial);
 | 
			
		||||
void meta_stack_tracker_record_remove          (MetaStackTracker *tracker,
 | 
			
		||||
						Window            window,
 | 
			
		||||
                                                gulong            serial);
 | 
			
		||||
void meta_stack_tracker_record_restack_windows (MetaStackTracker *tracker,
 | 
			
		||||
						Window           *windows,
 | 
			
		||||
						int               n_windows,
 | 
			
		||||
                                                gulong            serial);
 | 
			
		||||
void meta_stack_tracker_record_raise_above     (MetaStackTracker *tracker,
 | 
			
		||||
						Window            window,
 | 
			
		||||
						Window            sibling,
 | 
			
		||||
                                                gulong            serial);
 | 
			
		||||
void meta_stack_tracker_record_lower_below    (MetaStackTracker *tracker,
 | 
			
		||||
						Window            window,
 | 
			
		||||
						Window            sibling,
 | 
			
		||||
                                                gulong            serial);
 | 
			
		||||
void meta_stack_tracker_record_lower           (MetaStackTracker *tracker,
 | 
			
		||||
						Window            window,
 | 
			
		||||
                                                gulong            serial);
 | 
			
		||||
 | 
			
		||||
/* These functions are used to update the stack when we get events
 | 
			
		||||
 * reflecting changes to the stacking order */
 | 
			
		||||
void meta_stack_tracker_create_event    (MetaStackTracker    *tracker,
 | 
			
		||||
					 XCreateWindowEvent  *event);
 | 
			
		||||
void meta_stack_tracker_destroy_event   (MetaStackTracker    *tracker,
 | 
			
		||||
					 XDestroyWindowEvent *event);
 | 
			
		||||
void meta_stack_tracker_reparent_event  (MetaStackTracker    *tracker,
 | 
			
		||||
					 XReparentEvent      *event);
 | 
			
		||||
void meta_stack_tracker_configure_event (MetaStackTracker    *tracker,
 | 
			
		||||
					 XConfigureEvent     *event);
 | 
			
		||||
 | 
			
		||||
void meta_stack_tracker_get_stack  (MetaStackTracker  *tracker,
 | 
			
		||||
                                    Window           **windows,
 | 
			
		||||
                                    int               *n_windows);
 | 
			
		||||
 | 
			
		||||
void meta_stack_tracker_sync_stack       (MetaStackTracker *tracker);
 | 
			
		||||
void meta_stack_tracker_queue_sync_stack (MetaStackTracker *tracker);
 | 
			
		||||
 | 
			
		||||
#endif /* META_STACK_TRACKER_H */
 | 
			
		||||
							
								
								
									
										133
									
								
								src/core/stack.c
									
									
									
									
									
								
							
							
						
						
									
										133
									
								
								src/core/stack.c
									
									
									
									
									
								
							@@ -35,10 +35,6 @@
 | 
			
		||||
#include "prefs.h"
 | 
			
		||||
#include "workspace.h"
 | 
			
		||||
 | 
			
		||||
#ifdef HAVE_COMPOSITE_EXTENSIONS
 | 
			
		||||
#include "compositor.h"
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
#include <X11/Xatom.h>
 | 
			
		||||
 | 
			
		||||
#define WINDOW_HAS_TRANSIENT_TYPE(w)                    \
 | 
			
		||||
@@ -964,41 +960,33 @@ stack_ensure_sorted (MetaStack *stack)
 | 
			
		||||
 * This function is used to avoid raising a window above popup
 | 
			
		||||
 * menus and other such things.
 | 
			
		||||
 *
 | 
			
		||||
 * FIXME This is sort of an expensive function, should probably
 | 
			
		||||
 * do something to avoid it. One approach would be to reverse
 | 
			
		||||
 * the stacking algorithm to work by placing each window above
 | 
			
		||||
 * the others, and start by lowering a window to the bottom
 | 
			
		||||
 * (instead of the current way, which works by placing each
 | 
			
		||||
 * window below another and starting with a raise)
 | 
			
		||||
 * The key to the operation of this function is that we are expecting
 | 
			
		||||
 * at most one window to be added at a time. If xwindow is newly added,
 | 
			
		||||
 * then its own stack position will be too high (the frame window
 | 
			
		||||
 * is created at the top of the stack), but if we ignore xwindow,
 | 
			
		||||
 * then the *next* managed window in the stack will be a window that
 | 
			
		||||
 * we've already stacked.
 | 
			
		||||
 *
 | 
			
		||||
 * We could generalize this and remove the assumption that windows
 | 
			
		||||
 * are added one at a time by keeping an explicit ->stacked flag in
 | 
			
		||||
 * MetaWindow.
 | 
			
		||||
 *
 | 
			
		||||
 * An alternate approach would be to reverse the stacking algorithm to
 | 
			
		||||
 * work by placing each window above the others, and start by lowering
 | 
			
		||||
 * a window to the bottom (instead of the current way, which works by
 | 
			
		||||
 * placing each window below another and starting with a raise)
 | 
			
		||||
 */
 | 
			
		||||
static void
 | 
			
		||||
raise_window_relative_to_managed_windows (MetaScreen *screen,
 | 
			
		||||
                                          Window      xwindow)
 | 
			
		||||
{
 | 
			
		||||
 | 
			
		||||
  Window ignored1, ignored2;
 | 
			
		||||
  Window *children;
 | 
			
		||||
  unsigned int n_children;
 | 
			
		||||
  int n_children;
 | 
			
		||||
  int i;
 | 
			
		||||
 | 
			
		||||
  /* Normally XQueryTree() means "must grab server" but here
 | 
			
		||||
   * we don't, since we know we won't manage any new windows
 | 
			
		||||
   * or restack any windows before using the XQueryTree results.
 | 
			
		||||
   */
 | 
			
		||||
  
 | 
			
		||||
  meta_error_trap_push_with_return (screen->display);
 | 
			
		||||
  
 | 
			
		||||
  XQueryTree (screen->display->xdisplay,
 | 
			
		||||
              screen->xroot,
 | 
			
		||||
              &ignored1, &ignored2, &children, &n_children);
 | 
			
		||||
 | 
			
		||||
  if (meta_error_trap_pop_with_return (screen->display, TRUE) != Success)
 | 
			
		||||
    {
 | 
			
		||||
      meta_topic (META_DEBUG_STACK,
 | 
			
		||||
                  "Error querying root children to raise window 0x%lx\n",
 | 
			
		||||
                  xwindow);
 | 
			
		||||
      return;
 | 
			
		||||
    }
 | 
			
		||||
  meta_stack_tracker_get_stack (screen->stack_tracker,
 | 
			
		||||
                                &children, &n_children);
 | 
			
		||||
 | 
			
		||||
  /* Children are in order from bottom to top. We want to
 | 
			
		||||
   * find the topmost managed child, then configure
 | 
			
		||||
@@ -1019,27 +1007,35 @@ raise_window_relative_to_managed_windows (MetaScreen *screen,
 | 
			
		||||
           * to be moved below.
 | 
			
		||||
           */
 | 
			
		||||
        }
 | 
			
		||||
      else if (meta_display_lookup_x_window (screen->display,
 | 
			
		||||
                                             children[i]) != NULL)
 | 
			
		||||
      else
 | 
			
		||||
        {
 | 
			
		||||
          XWindowChanges changes;
 | 
			
		||||
          
 | 
			
		||||
          /* children[i] is the topmost managed child */
 | 
			
		||||
          meta_topic (META_DEBUG_STACK,
 | 
			
		||||
                      "Moving 0x%lx above topmost managed child window 0x%lx\n",
 | 
			
		||||
                      xwindow, children[i]);
 | 
			
		||||
          MetaWindow *other = meta_display_lookup_x_window (screen->display,
 | 
			
		||||
                                                            children[i]);
 | 
			
		||||
          if (other != NULL && !other->override_redirect)
 | 
			
		||||
            {
 | 
			
		||||
              XWindowChanges changes;
 | 
			
		||||
 | 
			
		||||
          changes.sibling = children[i];
 | 
			
		||||
          changes.stack_mode = Above;
 | 
			
		||||
              /* children[i] is the topmost managed child */
 | 
			
		||||
              meta_topic (META_DEBUG_STACK,
 | 
			
		||||
                          "Moving 0x%lx above topmost managed child window 0x%lx\n",
 | 
			
		||||
                          xwindow, children[i]);
 | 
			
		||||
 | 
			
		||||
          meta_error_trap_push (screen->display);
 | 
			
		||||
          XConfigureWindow (screen->display->xdisplay,
 | 
			
		||||
                            xwindow,
 | 
			
		||||
                            CWSibling | CWStackMode,
 | 
			
		||||
                            &changes);
 | 
			
		||||
          meta_error_trap_pop (screen->display, FALSE);
 | 
			
		||||
              changes.sibling = children[i];
 | 
			
		||||
              changes.stack_mode = Above;
 | 
			
		||||
 | 
			
		||||
          break;
 | 
			
		||||
              meta_error_trap_push (screen->display);
 | 
			
		||||
              meta_stack_tracker_record_raise_above (screen->stack_tracker,
 | 
			
		||||
                                                     xwindow,
 | 
			
		||||
                                                     children[i],
 | 
			
		||||
                                                     XNextRequest (screen->display->xdisplay));
 | 
			
		||||
              XConfigureWindow (screen->display->xdisplay,
 | 
			
		||||
                                xwindow,
 | 
			
		||||
                                CWSibling | CWStackMode,
 | 
			
		||||
                                &changes);
 | 
			
		||||
              meta_error_trap_pop (screen->display, FALSE);
 | 
			
		||||
 | 
			
		||||
              break;
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
      --i;
 | 
			
		||||
@@ -1051,13 +1047,13 @@ raise_window_relative_to_managed_windows (MetaScreen *screen,
 | 
			
		||||
       * to be sure we're below any override redirect windows.
 | 
			
		||||
       */
 | 
			
		||||
      meta_error_trap_push (screen->display);
 | 
			
		||||
      meta_stack_tracker_record_lower (screen->stack_tracker,
 | 
			
		||||
                                       xwindow,
 | 
			
		||||
                                       XNextRequest (screen->display->xdisplay));
 | 
			
		||||
      XLowerWindow (screen->display->xdisplay,
 | 
			
		||||
                    xwindow);
 | 
			
		||||
      meta_error_trap_pop (screen->display, FALSE);
 | 
			
		||||
    }
 | 
			
		||||
  
 | 
			
		||||
  if (children)
 | 
			
		||||
    XFree (children);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
@@ -1066,6 +1062,10 @@ raise_window_relative_to_managed_windows (MetaScreen *screen,
 | 
			
		||||
 * or XConfigureWindow on a few particular windows if we do and can figure
 | 
			
		||||
 * out the minimum set of changes.  After that, we set __NET_CLIENT_LIST
 | 
			
		||||
 * and __NET_CLIENT_LIST_STACKING.
 | 
			
		||||
 *
 | 
			
		||||
 * FIXME: Now that we have a good view of the stacking order on the server
 | 
			
		||||
 * with MetaStackTracker it should be possible to do a simpler and better
 | 
			
		||||
 * job of computing the minimal set of stacking requests needed.
 | 
			
		||||
 */
 | 
			
		||||
static void
 | 
			
		||||
stack_sync_to_server (MetaStack *stack)
 | 
			
		||||
@@ -1084,10 +1084,6 @@ stack_sync_to_server (MetaStack *stack)
 | 
			
		||||
 | 
			
		||||
  stack_ensure_sorted (stack);
 | 
			
		||||
 | 
			
		||||
  meta_compositor_sync_stack (stack->screen->display->compositor,
 | 
			
		||||
			      stack->screen,
 | 
			
		||||
			      stack->sorted);
 | 
			
		||||
  
 | 
			
		||||
  /* Create stacked xwindow arrays.
 | 
			
		||||
   * Painfully, "stacked" is in bottom-to-top order for the
 | 
			
		||||
   * _NET hints, and "root_children_stacked" is in top-to-bottom
 | 
			
		||||
@@ -1159,9 +1155,15 @@ stack_sync_to_server (MetaStack *stack)
 | 
			
		||||
      meta_topic (META_DEBUG_STACK, "Don't know last stack state, restacking everything\n");
 | 
			
		||||
 | 
			
		||||
      if (root_children_stacked->len > 0)
 | 
			
		||||
        XRestackWindows (stack->screen->display->xdisplay,
 | 
			
		||||
                         (Window *) root_children_stacked->data,
 | 
			
		||||
                         root_children_stacked->len);
 | 
			
		||||
        {
 | 
			
		||||
          meta_stack_tracker_record_restack_windows (stack->screen->stack_tracker,
 | 
			
		||||
                                                     (Window *) root_children_stacked->data,
 | 
			
		||||
                                                     root_children_stacked->len,
 | 
			
		||||
                                                     XNextRequest (stack->screen->display->xdisplay));
 | 
			
		||||
          XRestackWindows (stack->screen->display->xdisplay,
 | 
			
		||||
                           (Window *) root_children_stacked->data,
 | 
			
		||||
                           root_children_stacked->len);
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
  else if (root_children_stacked->len > 0)
 | 
			
		||||
    {
 | 
			
		||||
@@ -1223,7 +1225,10 @@ stack_sync_to_server (MetaStack *stack)
 | 
			
		||||
 | 
			
		||||
                  meta_topic (META_DEBUG_STACK, "Placing window 0x%lx below 0x%lx\n",
 | 
			
		||||
                              *newp, last_window);
 | 
			
		||||
                  
 | 
			
		||||
 | 
			
		||||
                  meta_stack_tracker_record_lower_below (stack->screen->stack_tracker,
 | 
			
		||||
                                                         *newp, last_window,
 | 
			
		||||
                                                         XNextRequest (stack->screen->display->xdisplay));
 | 
			
		||||
                  XConfigureWindow (stack->screen->display->xdisplay,
 | 
			
		||||
                                    *newp,
 | 
			
		||||
                                    CWSibling | CWStackMode,
 | 
			
		||||
@@ -1246,13 +1251,23 @@ stack_sync_to_server (MetaStack *stack)
 | 
			
		||||
           */
 | 
			
		||||
          if (newp != new_stack)
 | 
			
		||||
            --newp;
 | 
			
		||||
          meta_stack_tracker_record_restack_windows (stack->screen->stack_tracker,
 | 
			
		||||
                                                     (Window *) newp, new_end - newp,
 | 
			
		||||
                                                     XNextRequest (stack->screen->display->xdisplay));
 | 
			
		||||
          XRestackWindows (stack->screen->display->xdisplay,
 | 
			
		||||
                           (Window *) newp, new_end - newp);
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
  /* Push hidden windows to the bottom of the stack under the guard window */
 | 
			
		||||
  meta_stack_tracker_record_lower (stack->screen->stack_tracker,
 | 
			
		||||
                                   stack->screen->guard_window,
 | 
			
		||||
                                   XNextRequest (stack->screen->display->xdisplay));
 | 
			
		||||
  XLowerWindow (stack->screen->display->xdisplay, stack->screen->guard_window);
 | 
			
		||||
  meta_stack_tracker_record_restack_windows (stack->screen->stack_tracker,
 | 
			
		||||
                                             (Window *)all_hidden->data,
 | 
			
		||||
                                             all_hidden->len,
 | 
			
		||||
                                             XNextRequest (stack->screen->display->xdisplay));
 | 
			
		||||
  XRestackWindows (stack->screen->display->xdisplay,
 | 
			
		||||
		   (Window *)all_hidden->data,
 | 
			
		||||
		   all_hidden->len);
 | 
			
		||||
@@ -1286,8 +1301,6 @@ stack_sync_to_server (MetaStack *stack)
 | 
			
		||||
  if (stack->last_root_children_stacked)
 | 
			
		||||
    g_array_free (stack->last_root_children_stacked, TRUE);
 | 
			
		||||
  stack->last_root_children_stacked = root_children_stacked;
 | 
			
		||||
  
 | 
			
		||||
  meta_screen_restacked (stack->screen);
 | 
			
		||||
 | 
			
		||||
  /* That was scary... */
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -56,19 +56,22 @@ typedef void (* ReloadValueFunc) (MetaWindow    *window,
 | 
			
		||||
                                  MetaPropValue *value,
 | 
			
		||||
                                  gboolean       initial);
 | 
			
		||||
 | 
			
		||||
typedef struct MetaWindowPropHooks
 | 
			
		||||
struct _MetaWindowPropHooks
 | 
			
		||||
{
 | 
			
		||||
  Atom property;
 | 
			
		||||
  MetaPropValueType type;
 | 
			
		||||
  ReloadValueFunc reload_func;
 | 
			
		||||
} MetaWindowPropHooks;
 | 
			
		||||
  gboolean load_initially;
 | 
			
		||||
  gboolean include_override_redirect;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
static void init_prop_value            (MetaDisplay   *display,
 | 
			
		||||
                                        Atom           property,
 | 
			
		||||
                                        MetaPropValue *value);
 | 
			
		||||
static void reload_prop_value          (MetaWindow    *window,
 | 
			
		||||
                                        MetaPropValue *value,
 | 
			
		||||
                                        gboolean       initial);
 | 
			
		||||
static void init_prop_value            (MetaWindow          *window,
 | 
			
		||||
                                        MetaWindowPropHooks *hooks,
 | 
			
		||||
                                        MetaPropValue       *value);
 | 
			
		||||
static void reload_prop_value          (MetaWindow          *window,
 | 
			
		||||
                                        MetaWindowPropHooks *hooks,
 | 
			
		||||
                                        MetaPropValue       *value,
 | 
			
		||||
                                        gboolean             initial);
 | 
			
		||||
static MetaWindowPropHooks* find_hooks (MetaDisplay *display,
 | 
			
		||||
                                        Atom         property);
 | 
			
		||||
 | 
			
		||||
@@ -122,7 +125,8 @@ meta_window_reload_properties_from_xwindow (MetaWindow *window,
 | 
			
		||||
  i = 0;
 | 
			
		||||
  while (i < n_properties)
 | 
			
		||||
    {
 | 
			
		||||
      init_prop_value (window->display, properties[i], &values[i]);
 | 
			
		||||
      MetaWindowPropHooks *hooks = find_hooks (window->display, properties[i]);
 | 
			
		||||
      init_prop_value (window, hooks, &values[i]);
 | 
			
		||||
      ++i;
 | 
			
		||||
    }
 | 
			
		||||
  
 | 
			
		||||
@@ -132,7 +136,8 @@ meta_window_reload_properties_from_xwindow (MetaWindow *window,
 | 
			
		||||
  i = 0;
 | 
			
		||||
  while (i < n_properties)
 | 
			
		||||
    {
 | 
			
		||||
      reload_prop_value (window, &values[i], initial);
 | 
			
		||||
      MetaWindowPropHooks *hooks = find_hooks (window->display, properties[i]);
 | 
			
		||||
      reload_prop_value (window, hooks, &values[i], initial);
 | 
			
		||||
      
 | 
			
		||||
      ++i;
 | 
			
		||||
    }
 | 
			
		||||
@@ -142,34 +147,78 @@ meta_window_reload_properties_from_xwindow (MetaWindow *window,
 | 
			
		||||
  g_free (values);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void
 | 
			
		||||
meta_window_load_initial_properties (MetaWindow *window)
 | 
			
		||||
{
 | 
			
		||||
  int i, j;
 | 
			
		||||
  MetaPropValue *values;
 | 
			
		||||
  int n_properties = 0;
 | 
			
		||||
 | 
			
		||||
  values = g_new0 (MetaPropValue, window->display->n_prop_hooks);
 | 
			
		||||
 | 
			
		||||
  j = 0;
 | 
			
		||||
  for (i = 0; i < window->display->n_prop_hooks; i++)
 | 
			
		||||
    {
 | 
			
		||||
      MetaWindowPropHooks *hooks = &window->display->prop_hooks_table[i];
 | 
			
		||||
      if (hooks->load_initially)
 | 
			
		||||
        {
 | 
			
		||||
          init_prop_value (window, hooks, &values[j]);
 | 
			
		||||
          ++j;
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
  n_properties = j;
 | 
			
		||||
 | 
			
		||||
  meta_prop_get_values (window->display, window->xwindow,
 | 
			
		||||
                        values, n_properties);
 | 
			
		||||
 | 
			
		||||
  j = 0;
 | 
			
		||||
  for (i = 0; i < window->display->n_prop_hooks; i++)
 | 
			
		||||
    {
 | 
			
		||||
      MetaWindowPropHooks *hooks = &window->display->prop_hooks_table[i];
 | 
			
		||||
      if (hooks->load_initially)
 | 
			
		||||
        {
 | 
			
		||||
          /* If we didn't actually manage to load anything then we don't need
 | 
			
		||||
           * to call the reload function; this is different from a notification
 | 
			
		||||
           * where disappearance of a previously value is significant.
 | 
			
		||||
           */
 | 
			
		||||
          if (values[j].type != META_PROP_VALUE_INVALID)
 | 
			
		||||
            reload_prop_value (window, hooks, &values[j], TRUE);
 | 
			
		||||
          ++j;
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
  meta_prop_free_values (values, n_properties);
 | 
			
		||||
 | 
			
		||||
  g_free (values);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/* Fill in the MetaPropValue used to get the value of "property" */
 | 
			
		||||
static void
 | 
			
		||||
init_prop_value (MetaDisplay   *display,
 | 
			
		||||
                 Atom           property,
 | 
			
		||||
                 MetaPropValue *value)
 | 
			
		||||
init_prop_value (MetaWindow          *window,
 | 
			
		||||
                 MetaWindowPropHooks *hooks,
 | 
			
		||||
                 MetaPropValue       *value)
 | 
			
		||||
{
 | 
			
		||||
  MetaWindowPropHooks *hooks = find_hooks (display, property);
 | 
			
		||||
 | 
			
		||||
  if (!hooks || hooks->type == META_PROP_VALUE_INVALID)
 | 
			
		||||
  if (!hooks || hooks->type == META_PROP_VALUE_INVALID ||
 | 
			
		||||
      (window->override_redirect && !hooks->include_override_redirect))
 | 
			
		||||
    {
 | 
			
		||||
  value->type = META_PROP_VALUE_INVALID;
 | 
			
		||||
  value->atom = None;
 | 
			
		||||
      value->type = META_PROP_VALUE_INVALID;
 | 
			
		||||
      value->atom = None;
 | 
			
		||||
    }
 | 
			
		||||
  else
 | 
			
		||||
    {
 | 
			
		||||
      value->type = hooks->type;
 | 
			
		||||
      value->atom = property;
 | 
			
		||||
      value->atom = hooks->property;
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void
 | 
			
		||||
reload_prop_value (MetaWindow    *window,
 | 
			
		||||
                   MetaPropValue *value,
 | 
			
		||||
                   gboolean       initial)
 | 
			
		||||
reload_prop_value (MetaWindow          *window,
 | 
			
		||||
                   MetaWindowPropHooks *hooks,
 | 
			
		||||
                   MetaPropValue       *value,
 | 
			
		||||
                   gboolean             initial)
 | 
			
		||||
{
 | 
			
		||||
  MetaWindowPropHooks *hooks = find_hooks (window->display, value->atom);
 | 
			
		||||
  
 | 
			
		||||
  if (hooks && hooks->reload_func != NULL)
 | 
			
		||||
  if (hooks && hooks->reload_func != NULL &&
 | 
			
		||||
      !(window->override_redirect && !hooks->include_override_redirect))
 | 
			
		||||
    (* hooks->reload_func) (window, value, initial);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@@ -1386,7 +1435,8 @@ reload_transient_for (MetaWindow    *window,
 | 
			
		||||
  meta_window_recalc_window_type (window);
 | 
			
		||||
 | 
			
		||||
  /* update stacking constraints */
 | 
			
		||||
  meta_stack_update_transient (window->screen->stack, window);
 | 
			
		||||
  if (!window->override_redirect)
 | 
			
		||||
    meta_stack_update_transient (window->screen->stack, window);
 | 
			
		||||
 | 
			
		||||
  /* possibly change its group. We treat being a window's transient as
 | 
			
		||||
   * equivalent to making it your group leader, to work around shortcomings
 | 
			
		||||
@@ -1397,7 +1447,7 @@ reload_transient_for (MetaWindow    *window,
 | 
			
		||||
      window->xtransient_for != window->xgroup_leader)
 | 
			
		||||
    meta_window_group_leader_changed (window);
 | 
			
		||||
 | 
			
		||||
  if (!window->constructing)
 | 
			
		||||
  if (!window->constructing && !window->override_redirect)
 | 
			
		||||
    meta_window_queue (window, META_QUEUE_MOVE_RESIZE);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@@ -1418,35 +1468,54 @@ reload_transient_for (MetaWindow    *window,
 | 
			
		||||
void
 | 
			
		||||
meta_display_init_window_prop_hooks (MetaDisplay *display)
 | 
			
		||||
{
 | 
			
		||||
  MetaWindowPropHooks hooks[] = {
 | 
			
		||||
    { display->atom_WM_STATE,          META_PROP_VALUE_INVALID,  NULL },
 | 
			
		||||
    { display->atom_WM_CLIENT_MACHINE, META_PROP_VALUE_STRING,   reload_wm_client_machine },
 | 
			
		||||
    { display->atom__NET_WM_PID,       META_PROP_VALUE_CARDINAL, reload_net_wm_pid },
 | 
			
		||||
    { display->atom__NET_WM_USER_TIME, META_PROP_VALUE_CARDINAL, reload_net_wm_user_time },
 | 
			
		||||
    { display->atom__NET_WM_NAME,      META_PROP_VALUE_UTF8,     reload_net_wm_name },
 | 
			
		||||
    { XA_WM_NAME,                      META_PROP_VALUE_TEXT_PROPERTY, reload_wm_name },
 | 
			
		||||
    { display->atom__NET_WM_ICON,      META_PROP_VALUE_INVALID,  reload_net_wm_icon },
 | 
			
		||||
    { display->atom__KWM_WIN_ICON,     META_PROP_VALUE_INVALID,  reload_kwm_win_icon },
 | 
			
		||||
    { display->atom__NET_WM_ICON_NAME, META_PROP_VALUE_UTF8,     reload_net_wm_icon_name },
 | 
			
		||||
    { XA_WM_ICON_NAME,                 META_PROP_VALUE_TEXT_PROPERTY, reload_wm_icon_name },
 | 
			
		||||
    { display->atom__NET_WM_STATE,     META_PROP_VALUE_ATOM_LIST, reload_net_wm_state },
 | 
			
		||||
    { display->atom__MOTIF_WM_HINTS,   META_PROP_VALUE_MOTIF_HINTS, reload_mwm_hints },
 | 
			
		||||
    { display->atom__NET_WM_ICON_GEOMETRY, META_PROP_VALUE_INVALID, NULL },
 | 
			
		||||
    { XA_WM_CLASS,                     META_PROP_VALUE_CLASS_HINT, reload_wm_class },
 | 
			
		||||
    { display->atom_WM_CLIENT_LEADER,  META_PROP_VALUE_INVALID, complain_about_broken_client },
 | 
			
		||||
    { display->atom_SM_CLIENT_ID,      META_PROP_VALUE_INVALID, complain_about_broken_client },
 | 
			
		||||
    { display->atom_WM_WINDOW_ROLE,    META_PROP_VALUE_INVALID, reload_wm_window_role },
 | 
			
		||||
    { display->atom__NET_WM_WINDOW_TYPE, META_PROP_VALUE_INVALID, reload_net_wm_window_type },
 | 
			
		||||
    { display->atom__NET_WM_DESKTOP,   META_PROP_VALUE_CARDINAL, reload_net_wm_desktop },
 | 
			
		||||
    { display->atom__NET_WM_STRUT,         META_PROP_VALUE_INVALID, reload_struts },
 | 
			
		||||
    { display->atom__NET_WM_STRUT_PARTIAL, META_PROP_VALUE_INVALID, reload_struts },
 | 
			
		||||
    { display->atom__NET_STARTUP_ID,  META_PROP_VALUE_UTF8,     reload_net_startup_id },
 | 
			
		||||
    { display->atom__NET_WM_SYNC_REQUEST_COUNTER, META_PROP_VALUE_SYNC_COUNTER, reload_update_counter },
 | 
			
		||||
    { XA_WM_NORMAL_HINTS,              META_PROP_VALUE_SIZE_HINTS, reload_normal_hints },
 | 
			
		||||
    { display->atom_WM_PROTOCOLS,      META_PROP_VALUE_ATOM_LIST, reload_wm_protocols },
 | 
			
		||||
    { XA_WM_HINTS,                     META_PROP_VALUE_WM_HINTS,  reload_wm_hints },
 | 
			
		||||
    { XA_WM_TRANSIENT_FOR,             META_PROP_VALUE_WINDOW,    reload_transient_for },
 | 
			
		||||
    { display->atom__NET_WM_USER_TIME_WINDOW, META_PROP_VALUE_WINDOW, reload_net_wm_user_time_window },
 | 
			
		||||
  /* INIT: load initially
 | 
			
		||||
   * O-R:  fetch for override-redirect windows
 | 
			
		||||
   *
 | 
			
		||||
   * The ordering here is significant for the properties we load
 | 
			
		||||
   * initially: they are roughly ordered in the order we want them to
 | 
			
		||||
   * be gotten. We want to get window name and class first so we can
 | 
			
		||||
   * use them in error messages and such. However, name is modified
 | 
			
		||||
   * depending on wm_client_machine, so push it slightly sooner.
 | 
			
		||||
   *
 | 
			
		||||
   * For override-redirect windows, we pay attention to:
 | 
			
		||||
   *
 | 
			
		||||
   *  - properties that identify the window: useful for debugging
 | 
			
		||||
   *    purposes.
 | 
			
		||||
   *  - WM_TRANSIENT_FOR: could be used to associate menus or other
 | 
			
		||||
   *    override-redirect transients with their parent windows if
 | 
			
		||||
   *    the app sets the property (GTK+ does set this for menus.)
 | 
			
		||||
   *  - NET_WM_WINDOW_TYPE: can be used to do appropriate handling
 | 
			
		||||
   *    for different types of override-redirect windows.
 | 
			
		||||
   */
 | 
			
		||||
  MetaWindowPropHooks hooks[] = {                                                       /* INIT   O-R     */
 | 
			
		||||
    { display->atom_WM_CLIENT_MACHINE, META_PROP_VALUE_STRING,   reload_wm_client_machine, TRUE,  TRUE },
 | 
			
		||||
    { display->atom__NET_WM_NAME,      META_PROP_VALUE_UTF8,     reload_net_wm_name,       TRUE,  TRUE },
 | 
			
		||||
    { XA_WM_CLASS,                     META_PROP_VALUE_CLASS_HINT, reload_wm_class,        TRUE,  TRUE },
 | 
			
		||||
    { display->atom__NET_WM_PID,       META_PROP_VALUE_CARDINAL, reload_net_wm_pid,        TRUE,  TRUE },
 | 
			
		||||
    { XA_WM_NAME,                      META_PROP_VALUE_TEXT_PROPERTY, reload_wm_name,      TRUE,  TRUE },
 | 
			
		||||
    { display->atom__NET_WM_ICON_NAME, META_PROP_VALUE_UTF8,     reload_net_wm_icon_name,  TRUE,  FALSE },
 | 
			
		||||
    { XA_WM_ICON_NAME,                 META_PROP_VALUE_TEXT_PROPERTY, reload_wm_icon_name, TRUE,  FALSE },
 | 
			
		||||
    { display->atom__NET_WM_DESKTOP,   META_PROP_VALUE_CARDINAL, reload_net_wm_desktop,    TRUE,  FALSE },
 | 
			
		||||
    { display->atom__NET_STARTUP_ID,   META_PROP_VALUE_UTF8,     reload_net_startup_id,    TRUE,  FALSE },
 | 
			
		||||
    { display->atom__NET_WM_SYNC_REQUEST_COUNTER, META_PROP_VALUE_SYNC_COUNTER, reload_update_counter, TRUE, FALSE },
 | 
			
		||||
    { XA_WM_NORMAL_HINTS,              META_PROP_VALUE_SIZE_HINTS, reload_normal_hints,    TRUE,  FALSE },
 | 
			
		||||
    { display->atom_WM_PROTOCOLS,      META_PROP_VALUE_ATOM_LIST, reload_wm_protocols,     TRUE,  TRUE },
 | 
			
		||||
    { XA_WM_HINTS,                     META_PROP_VALUE_WM_HINTS,  reload_wm_hints,         TRUE,  FALSE },
 | 
			
		||||
    { display->atom__NET_WM_USER_TIME, META_PROP_VALUE_CARDINAL, reload_net_wm_user_time,  TRUE,  FALSE },
 | 
			
		||||
    { display->atom__NET_WM_STATE,     META_PROP_VALUE_ATOM_LIST, reload_net_wm_state,     TRUE,  FALSE },
 | 
			
		||||
    { display->atom__MOTIF_WM_HINTS,   META_PROP_VALUE_MOTIF_HINTS, reload_mwm_hints,      TRUE,  FALSE },
 | 
			
		||||
    { XA_WM_TRANSIENT_FOR,             META_PROP_VALUE_WINDOW,    reload_transient_for,    TRUE,  TRUE },
 | 
			
		||||
    { display->atom__NET_WM_USER_TIME_WINDOW, META_PROP_VALUE_WINDOW, reload_net_wm_user_time_window, TRUE, FALSE },
 | 
			
		||||
    { display->atom_WM_STATE,          META_PROP_VALUE_INVALID,  NULL,                     FALSE, FALSE },
 | 
			
		||||
    { display->atom__NET_WM_ICON,      META_PROP_VALUE_INVALID,  reload_net_wm_icon,       FALSE, FALSE },
 | 
			
		||||
    { display->atom__KWM_WIN_ICON,     META_PROP_VALUE_INVALID,  reload_kwm_win_icon,      FALSE, FALSE },
 | 
			
		||||
    { display->atom__NET_WM_ICON_GEOMETRY, META_PROP_VALUE_INVALID, NULL,                  FALSE, FALSE },
 | 
			
		||||
    { display->atom_WM_CLIENT_LEADER,  META_PROP_VALUE_INVALID, complain_about_broken_client, FALSE, FALSE },
 | 
			
		||||
    { display->atom_SM_CLIENT_ID,      META_PROP_VALUE_INVALID, complain_about_broken_client, FALSE, FALSE },
 | 
			
		||||
    { display->atom_WM_WINDOW_ROLE,    META_PROP_VALUE_INVALID, reload_wm_window_role,        FALSE, FALSE },
 | 
			
		||||
    { display->atom__NET_WM_WINDOW_TYPE, META_PROP_VALUE_INVALID, reload_net_wm_window_type,  FALSE, TRUE },
 | 
			
		||||
    { display->atom__NET_WM_STRUT,         META_PROP_VALUE_INVALID, reload_struts,            FALSE, FALSE },
 | 
			
		||||
    { display->atom__NET_WM_STRUT_PARTIAL, META_PROP_VALUE_INVALID, reload_struts,            FALSE, FALSE },
 | 
			
		||||
    { 0 },
 | 
			
		||||
  };
 | 
			
		||||
 | 
			
		||||
@@ -1460,6 +1529,9 @@ meta_display_init_window_prop_hooks (MetaDisplay *display)
 | 
			
		||||
 | 
			
		||||
  while (cursor->property)
 | 
			
		||||
    {
 | 
			
		||||
      /* Doing initial loading doesn't make sense if we just want notification */
 | 
			
		||||
      g_assert (!(hooks->load_initially && hooks->type == META_PROP_VALUE_INVALID));
 | 
			
		||||
 | 
			
		||||
      /* Atoms are safe to use with GINT_TO_POINTER because it's safe with
 | 
			
		||||
       * anything 32 bits or less, and atoms are 32 bits with the top three
 | 
			
		||||
       * bits clear.  (Scheifler & Gettys, 2e, p372)
 | 
			
		||||
@@ -1469,6 +1541,7 @@ meta_display_init_window_prop_hooks (MetaDisplay *display)
 | 
			
		||||
                           cursor);
 | 
			
		||||
      cursor++;
 | 
			
		||||
    }
 | 
			
		||||
  display->n_prop_hooks = cursor - table;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void
 | 
			
		||||
 
 | 
			
		||||
@@ -95,6 +95,15 @@ void meta_window_reload_properties_from_xwindow
 | 
			
		||||
                                    int         n_properties,
 | 
			
		||||
                                    gboolean    initial);
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Requests the current values for standard properties for a given
 | 
			
		||||
 * window from the server, and deals with them appropriately.
 | 
			
		||||
 * Does not return them to the caller (they've been dealt with!)
 | 
			
		||||
 *
 | 
			
		||||
 * \param window      The window.
 | 
			
		||||
 */
 | 
			
		||||
void meta_window_load_initial_properties (MetaWindow *window);
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Initialises the hooks used for the reload_propert* functions
 | 
			
		||||
 * on a particular display, and stores a pointer to them in the
 | 
			
		||||
 
 | 
			
		||||
@@ -426,14 +426,10 @@ meta_window_new_with_attrs (MetaDisplay       *display,
 | 
			
		||||
  gulong existing_wm_state;
 | 
			
		||||
  gulong event_mask;
 | 
			
		||||
  MetaMoveResizeFlags flags;
 | 
			
		||||
#define N_INITIAL_PROPS 19
 | 
			
		||||
  Atom initial_props[N_INITIAL_PROPS];
 | 
			
		||||
  int i;
 | 
			
		||||
  gboolean has_shape;
 | 
			
		||||
  MetaScreen *screen;
 | 
			
		||||
 | 
			
		||||
  g_assert (attrs != NULL);
 | 
			
		||||
  g_assert (N_INITIAL_PROPS == (int) G_N_ELEMENTS (initial_props));
 | 
			
		||||
 | 
			
		||||
  meta_verbose ("Attempting to manage 0x%lx\n", xwindow);
 | 
			
		||||
 | 
			
		||||
@@ -682,8 +678,9 @@ meta_window_new_with_attrs (MetaDisplay       *display,
 | 
			
		||||
  window->hidden = 0;
 | 
			
		||||
  /* if already mapped, no need to worry about focus-on-first-time-showing */
 | 
			
		||||
  window->showing_for_first_time = !window->mapped;
 | 
			
		||||
  /* if already mapped we don't want to do the placement thing */
 | 
			
		||||
  window->placed = (window->mapped && !window->hidden);
 | 
			
		||||
  /* if already mapped we don't want to do the placement thing;
 | 
			
		||||
   * override-redirect windows are placed by the app */
 | 
			
		||||
  window->placed = ((window->mapped && !window->hidden) || window->override_redirect);
 | 
			
		||||
  if (window->placed)
 | 
			
		||||
    meta_topic (META_DEBUG_PLACEMENT,
 | 
			
		||||
                "Not placing window 0x%lx since it's already mapped\n",
 | 
			
		||||
@@ -777,39 +774,15 @@ meta_window_new_with_attrs (MetaDisplay       *display,
 | 
			
		||||
  window->xgroup_leader = None;
 | 
			
		||||
  meta_window_compute_group (window);
 | 
			
		||||
 | 
			
		||||
  /* Fill these in the order we want them to be gotten.  we want to
 | 
			
		||||
   * get window name and class first so we can use them in error
 | 
			
		||||
   * messages and such.  However, name is modified depending on
 | 
			
		||||
   * wm_client_machine, so push it slightly sooner.
 | 
			
		||||
   */
 | 
			
		||||
  i = 0;
 | 
			
		||||
  initial_props[i++] = display->atom_WM_CLIENT_MACHINE;
 | 
			
		||||
  initial_props[i++] = display->atom__NET_WM_NAME;
 | 
			
		||||
  initial_props[i++] = XA_WM_CLASS;
 | 
			
		||||
  initial_props[i++] = display->atom__NET_WM_PID;
 | 
			
		||||
  initial_props[i++] = XA_WM_NAME;
 | 
			
		||||
  initial_props[i++] = display->atom__NET_WM_ICON_NAME;
 | 
			
		||||
  initial_props[i++] = XA_WM_ICON_NAME;
 | 
			
		||||
  initial_props[i++] = display->atom__NET_WM_DESKTOP;
 | 
			
		||||
  initial_props[i++] = display->atom__NET_STARTUP_ID;
 | 
			
		||||
  initial_props[i++] = display->atom__NET_WM_SYNC_REQUEST_COUNTER;
 | 
			
		||||
  initial_props[i++] = XA_WM_NORMAL_HINTS;
 | 
			
		||||
  initial_props[i++] = display->atom_WM_PROTOCOLS;
 | 
			
		||||
  initial_props[i++] = XA_WM_HINTS;
 | 
			
		||||
  initial_props[i++] = display->atom__NET_WM_USER_TIME;
 | 
			
		||||
  initial_props[i++] = display->atom__NET_WM_STATE;
 | 
			
		||||
  initial_props[i++] = display->atom__MOTIF_WM_HINTS;
 | 
			
		||||
  initial_props[i++] = XA_WM_TRANSIENT_FOR;
 | 
			
		||||
  initial_props[i++] = display->atom__NET_WM_USER_TIME_WINDOW;
 | 
			
		||||
  initial_props[i++] = display->atom__NET_WM_FULLSCREEN_MONITORS;
 | 
			
		||||
  g_assert (N_INITIAL_PROPS == i);
 | 
			
		||||
 | 
			
		||||
  meta_window_reload_properties (window, initial_props, N_INITIAL_PROPS, TRUE);
 | 
			
		||||
  meta_window_load_initial_properties (window);
 | 
			
		||||
 | 
			
		||||
  if (!window->override_redirect)
 | 
			
		||||
    update_sm_hints (window); /* must come after transient_for */
 | 
			
		||||
    {
 | 
			
		||||
      update_sm_hints (window); /* must come after transient_for */
 | 
			
		||||
 | 
			
		||||
      meta_window_update_role (window);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
  meta_window_update_role (window);
 | 
			
		||||
  meta_window_update_net_wm_type (window);
 | 
			
		||||
 | 
			
		||||
  if (!window->override_redirect)
 | 
			
		||||
@@ -846,7 +819,7 @@ meta_window_new_with_attrs (MetaDisplay       *display,
 | 
			
		||||
   * much we can do...except record the current time so that any children
 | 
			
		||||
   * can use this time as a fallback.
 | 
			
		||||
   */
 | 
			
		||||
  if (!window->net_wm_user_time_set) {
 | 
			
		||||
  if (!window->override_redirect && !window->net_wm_user_time_set) {
 | 
			
		||||
    MetaWindow *parent = NULL;
 | 
			
		||||
    if (window->xtransient_for)
 | 
			
		||||
      parent = meta_display_lookup_x_window (window->display,
 | 
			
		||||
@@ -926,47 +899,55 @@ meta_window_new_with_attrs (MetaDisplay       *display,
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
  if (window->workspace == NULL &&
 | 
			
		||||
      window->xtransient_for != None)
 | 
			
		||||
  /* override-redirect windows are subtly different from other windows
 | 
			
		||||
   * with window->on_all_workspaces == TRUE. Other windows are part of
 | 
			
		||||
   * some workspace (so they can return to that if the flag is turned off),
 | 
			
		||||
   * but appear on other workspaces. override-redirect windows are part
 | 
			
		||||
   * of no workspace.
 | 
			
		||||
   */
 | 
			
		||||
  if (!window->override_redirect)
 | 
			
		||||
    {
 | 
			
		||||
      /* Try putting dialog on parent's workspace */
 | 
			
		||||
      MetaWindow *parent;
 | 
			
		||||
      if (window->workspace == NULL &&
 | 
			
		||||
          window->xtransient_for != None)
 | 
			
		||||
        {
 | 
			
		||||
          /* Try putting dialog on parent's workspace */
 | 
			
		||||
          MetaWindow *parent;
 | 
			
		||||
 | 
			
		||||
      parent = meta_display_lookup_x_window (window->display,
 | 
			
		||||
                                             window->xtransient_for);
 | 
			
		||||
          parent = meta_display_lookup_x_window (window->display,
 | 
			
		||||
                                                 window->xtransient_for);
 | 
			
		||||
 | 
			
		||||
      if (parent && parent->workspace)
 | 
			
		||||
          if (parent && parent->workspace)
 | 
			
		||||
            {
 | 
			
		||||
              meta_topic (META_DEBUG_PLACEMENT,
 | 
			
		||||
                          "Putting window %s on same workspace as parent %s\n",
 | 
			
		||||
                          window->desc, parent->desc);
 | 
			
		||||
 | 
			
		||||
              if (parent->on_all_workspaces)
 | 
			
		||||
                window->on_all_workspaces = TRUE;
 | 
			
		||||
 | 
			
		||||
              /* this will implicitly add to the appropriate MRU lists
 | 
			
		||||
               */
 | 
			
		||||
              meta_workspace_add_window (parent->workspace, window);
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
      if (window->workspace == NULL)
 | 
			
		||||
        {
 | 
			
		||||
          meta_topic (META_DEBUG_PLACEMENT,
 | 
			
		||||
                      "Putting window %s on same workspace as parent %s\n",
 | 
			
		||||
                      window->desc, parent->desc);
 | 
			
		||||
                      "Putting window %s on active workspace\n",
 | 
			
		||||
                      window->desc);
 | 
			
		||||
 | 
			
		||||
          if (parent->on_all_workspaces)
 | 
			
		||||
            window->on_all_workspaces = TRUE;
 | 
			
		||||
          space = window->screen->active_workspace;
 | 
			
		||||
 | 
			
		||||
	  /* this will implicitly add to the appropriate MRU lists
 | 
			
		||||
	   */
 | 
			
		||||
          meta_workspace_add_window (parent->workspace, window);
 | 
			
		||||
          meta_workspace_add_window (space, window);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
      /* for the various on_all_workspaces = TRUE possible above */
 | 
			
		||||
      meta_window_set_current_workspace_hint (window);
 | 
			
		||||
 | 
			
		||||
      meta_window_update_struts (window);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
  if (window->workspace == NULL)
 | 
			
		||||
    {
 | 
			
		||||
      meta_topic (META_DEBUG_PLACEMENT,
 | 
			
		||||
                  "Putting window %s on active workspace\n",
 | 
			
		||||
                  window->desc);
 | 
			
		||||
 | 
			
		||||
      space = window->screen->active_workspace;
 | 
			
		||||
 | 
			
		||||
      meta_workspace_add_window (space, window);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
  /* for the various on_all_workspaces = TRUE possible above */
 | 
			
		||||
  if (!window->override_redirect)
 | 
			
		||||
    meta_window_set_current_workspace_hint (window);
 | 
			
		||||
 | 
			
		||||
  meta_window_update_struts (window);
 | 
			
		||||
 | 
			
		||||
  /* Must add window to stack before doing move/resize, since the
 | 
			
		||||
   * window might have fullscreen size (i.e. should have been
 | 
			
		||||
   * fullscreen'd; acrobat is one such braindead case; it withdraws
 | 
			
		||||
@@ -974,8 +955,11 @@ meta_window_new_with_attrs (MetaDisplay       *display,
 | 
			
		||||
   * and thus constraints may try to auto-fullscreen it which also
 | 
			
		||||
   * means restacking it.
 | 
			
		||||
   */
 | 
			
		||||
  meta_stack_add (window->screen->stack,
 | 
			
		||||
                  window);
 | 
			
		||||
  if (!window->override_redirect)
 | 
			
		||||
    meta_stack_add (window->screen->stack,
 | 
			
		||||
                    window);
 | 
			
		||||
  else
 | 
			
		||||
    window->layer = META_LAYER_OVERRIDE_REDIRECT; /* otherwise set by MetaStack */
 | 
			
		||||
 | 
			
		||||
  /* Put our state back where it should be,
 | 
			
		||||
   * passing TRUE for is_configure_request, ICCCM says
 | 
			
		||||
@@ -983,13 +967,14 @@ meta_window_new_with_attrs (MetaDisplay       *display,
 | 
			
		||||
   */
 | 
			
		||||
  flags =
 | 
			
		||||
    META_IS_CONFIGURE_REQUEST | META_IS_MOVE_ACTION | META_IS_RESIZE_ACTION;
 | 
			
		||||
  meta_window_move_resize_internal (window,
 | 
			
		||||
                                    flags,
 | 
			
		||||
                                    window->size_hints.win_gravity,
 | 
			
		||||
                                    window->size_hints.x,
 | 
			
		||||
                                    window->size_hints.y,
 | 
			
		||||
                                    window->size_hints.width,
 | 
			
		||||
                                    window->size_hints.height);
 | 
			
		||||
  if (!window->override_redirect)
 | 
			
		||||
    meta_window_move_resize_internal (window,
 | 
			
		||||
                                      flags,
 | 
			
		||||
                                      window->size_hints.win_gravity,
 | 
			
		||||
                                      window->size_hints.x,
 | 
			
		||||
                                      window->size_hints.y,
 | 
			
		||||
                                      window->size_hints.width,
 | 
			
		||||
                                      window->size_hints.height);
 | 
			
		||||
 | 
			
		||||
  /* Now try applying saved stuff from the session */
 | 
			
		||||
  {
 | 
			
		||||
@@ -1019,6 +1004,13 @@ meta_window_new_with_attrs (MetaDisplay       *display,
 | 
			
		||||
  /* Sync stack changes */
 | 
			
		||||
  meta_stack_thaw (window->screen->stack);
 | 
			
		||||
 | 
			
		||||
  /* Usually the we'll have queued a stack sync anyways, because we've
 | 
			
		||||
   * added a new frame window or restacked. But if an undecorated
 | 
			
		||||
   * window is mapped, already stacked in the right place, then we
 | 
			
		||||
   * might need to do this explicitly.
 | 
			
		||||
   */
 | 
			
		||||
  meta_stack_tracker_queue_sync_stack (window->screen->stack_tracker);
 | 
			
		||||
 | 
			
		||||
  /* disable show desktop mode unless we're a desktop component */
 | 
			
		||||
  maybe_leave_show_desktop_mode (window);
 | 
			
		||||
 | 
			
		||||
@@ -1039,7 +1031,9 @@ meta_window_new_with_attrs (MetaDisplay       *display,
 | 
			
		||||
   * And we shouldn't unminimize windows if they were initially
 | 
			
		||||
   * iconic.
 | 
			
		||||
   */
 | 
			
		||||
  if (!display->display_opening && !window->initially_iconic)
 | 
			
		||||
  if (!window->override_redirect &&
 | 
			
		||||
      !display->display_opening &&
 | 
			
		||||
      !window->initially_iconic)
 | 
			
		||||
    unminimize_window_and_all_transient_parents (window);
 | 
			
		||||
 | 
			
		||||
  meta_error_trap_pop (display, FALSE); /* pop the XSync()-reducing trap */
 | 
			
		||||
@@ -1320,11 +1314,18 @@ meta_window_unmanage (MetaWindow  *window,
 | 
			
		||||
    }
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
  meta_stack_remove (window->screen->stack, window);
 | 
			
		||||
  if (!window->override_redirect)
 | 
			
		||||
    meta_stack_remove (window->screen->stack, window);
 | 
			
		||||
 | 
			
		||||
  if (window->frame)
 | 
			
		||||
    meta_window_destroy_frame (window);
 | 
			
		||||
 | 
			
		||||
  /* If an undecorated window is being withdrawn, that will change the
 | 
			
		||||
   * stack as presented to the compositing manager, without actually
 | 
			
		||||
   * changing the stacking order of X windows.
 | 
			
		||||
   */
 | 
			
		||||
  meta_stack_tracker_queue_sync_stack (window->screen->stack_tracker);
 | 
			
		||||
 | 
			
		||||
  if (window->withdrawn)
 | 
			
		||||
    {
 | 
			
		||||
      /* We need to clean off the window's state so it
 | 
			
		||||
@@ -1976,6 +1977,9 @@ meta_window_queue (MetaWindow *window, guint queuebits)
 | 
			
		||||
{
 | 
			
		||||
  guint queuenum;
 | 
			
		||||
 | 
			
		||||
  /* Easier to debug by checking here rather than in the idle */
 | 
			
		||||
  g_return_if_fail (!((queuebits & META_QUEUE_MOVE_RESIZE) != 0 && window->override_redirect));
 | 
			
		||||
 | 
			
		||||
  for (queuenum=0; queuenum<NUMBER_OF_QUEUES; queuenum++)
 | 
			
		||||
    {
 | 
			
		||||
      if (queuebits & 1<<queuenum)
 | 
			
		||||
@@ -2377,7 +2381,7 @@ unmap_client_window (MetaWindow *window,
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/* XXX META_EFFECT_*_MAP */
 | 
			
		||||
void
 | 
			
		||||
static void
 | 
			
		||||
meta_window_show (MetaWindow *window)
 | 
			
		||||
{
 | 
			
		||||
  gboolean did_show;
 | 
			
		||||
@@ -2712,6 +2716,8 @@ queue_calc_showing_func (MetaWindow *window,
 | 
			
		||||
void
 | 
			
		||||
meta_window_minimize (MetaWindow  *window)
 | 
			
		||||
{
 | 
			
		||||
  g_return_if_fail (!window->override_redirect);
 | 
			
		||||
 | 
			
		||||
  if (!window->minimized)
 | 
			
		||||
    {
 | 
			
		||||
      window->minimized = TRUE;
 | 
			
		||||
@@ -2739,6 +2745,8 @@ meta_window_minimize (MetaWindow  *window)
 | 
			
		||||
void
 | 
			
		||||
meta_window_unminimize (MetaWindow  *window)
 | 
			
		||||
{
 | 
			
		||||
  g_return_if_fail (!window->override_redirect);
 | 
			
		||||
 | 
			
		||||
  if (window->minimized)
 | 
			
		||||
    {
 | 
			
		||||
      window->minimized = FALSE;
 | 
			
		||||
@@ -2892,8 +2900,11 @@ void
 | 
			
		||||
meta_window_maximize (MetaWindow        *window,
 | 
			
		||||
                      MetaMaximizeFlags  directions)
 | 
			
		||||
{
 | 
			
		||||
  /* At least one of the two directions ought to be set */
 | 
			
		||||
  gboolean maximize_horizontally, maximize_vertically;
 | 
			
		||||
 | 
			
		||||
  g_return_if_fail (!window->override_redirect);
 | 
			
		||||
 | 
			
		||||
  /* At least one of the two directions ought to be set */
 | 
			
		||||
  maximize_horizontally = directions & META_MAXIMIZE_HORIZONTAL;
 | 
			
		||||
  maximize_vertically   = directions & META_MAXIMIZE_VERTICAL;
 | 
			
		||||
  g_assert (maximize_horizontally || maximize_vertically);
 | 
			
		||||
@@ -2987,8 +2998,11 @@ void
 | 
			
		||||
meta_window_unmaximize (MetaWindow        *window,
 | 
			
		||||
                        MetaMaximizeFlags  directions)
 | 
			
		||||
{
 | 
			
		||||
  /* At least one of the two directions ought to be set */
 | 
			
		||||
  gboolean unmaximize_horizontally, unmaximize_vertically;
 | 
			
		||||
 | 
			
		||||
  g_return_if_fail (!window->override_redirect);
 | 
			
		||||
 | 
			
		||||
  /* At least one of the two directions ought to be set */
 | 
			
		||||
  unmaximize_horizontally = directions & META_MAXIMIZE_HORIZONTAL;
 | 
			
		||||
  unmaximize_vertically   = directions & META_MAXIMIZE_VERTICAL;
 | 
			
		||||
  g_assert (unmaximize_horizontally || unmaximize_vertically);
 | 
			
		||||
@@ -3085,6 +3099,8 @@ meta_window_unmaximize (MetaWindow        *window,
 | 
			
		||||
void
 | 
			
		||||
meta_window_make_above (MetaWindow  *window)
 | 
			
		||||
{
 | 
			
		||||
  g_return_if_fail (!window->override_redirect);
 | 
			
		||||
 | 
			
		||||
  window->wm_state_above = TRUE;
 | 
			
		||||
  meta_window_update_layer (window);
 | 
			
		||||
  meta_window_raise (window);
 | 
			
		||||
@@ -3094,6 +3110,8 @@ meta_window_make_above (MetaWindow  *window)
 | 
			
		||||
void
 | 
			
		||||
meta_window_unmake_above (MetaWindow  *window)
 | 
			
		||||
{
 | 
			
		||||
  g_return_if_fail (!window->override_redirect);
 | 
			
		||||
 | 
			
		||||
  window->wm_state_above = FALSE;
 | 
			
		||||
  meta_window_raise (window);
 | 
			
		||||
  meta_window_update_layer (window);
 | 
			
		||||
@@ -3138,6 +3156,8 @@ meta_window_make_fullscreen_internal (MetaWindow  *window)
 | 
			
		||||
void
 | 
			
		||||
meta_window_make_fullscreen (MetaWindow  *window)
 | 
			
		||||
{
 | 
			
		||||
  g_return_if_fail (!window->override_redirect);
 | 
			
		||||
 | 
			
		||||
  if (!window->fullscreen)
 | 
			
		||||
    {
 | 
			
		||||
      meta_window_make_fullscreen_internal (window);
 | 
			
		||||
@@ -3150,6 +3170,8 @@ meta_window_make_fullscreen (MetaWindow  *window)
 | 
			
		||||
void
 | 
			
		||||
meta_window_unmake_fullscreen (MetaWindow  *window)
 | 
			
		||||
{
 | 
			
		||||
  g_return_if_fail (!window->override_redirect);
 | 
			
		||||
 | 
			
		||||
  if (window->fullscreen)
 | 
			
		||||
    {
 | 
			
		||||
      MetaRectangle target_rect;
 | 
			
		||||
@@ -3213,6 +3235,8 @@ void
 | 
			
		||||
meta_window_shade (MetaWindow  *window,
 | 
			
		||||
                   guint32      timestamp)
 | 
			
		||||
{
 | 
			
		||||
  g_return_if_fail (!window->override_redirect);
 | 
			
		||||
 | 
			
		||||
  meta_topic (META_DEBUG_WINDOW_OPS,
 | 
			
		||||
              "Shading %s\n", window->desc);
 | 
			
		||||
  if (!window->shaded)
 | 
			
		||||
@@ -3237,6 +3261,8 @@ void
 | 
			
		||||
meta_window_unshade (MetaWindow  *window,
 | 
			
		||||
                     guint32      timestamp)
 | 
			
		||||
{
 | 
			
		||||
  g_return_if_fail (!window->override_redirect);
 | 
			
		||||
 | 
			
		||||
  meta_topic (META_DEBUG_WINDOW_OPS,
 | 
			
		||||
              "Unshading %s\n", window->desc);
 | 
			
		||||
  if (window->shaded)
 | 
			
		||||
@@ -3358,6 +3384,8 @@ void
 | 
			
		||||
meta_window_activate (MetaWindow     *window,
 | 
			
		||||
                      guint32         timestamp)
 | 
			
		||||
{
 | 
			
		||||
  g_return_if_fail (!window->override_redirect);
 | 
			
		||||
 | 
			
		||||
  /* We're not really a pager, but the behavior we want is the same as if
 | 
			
		||||
   * we were such.  If we change the pager behavior later, we could revisit
 | 
			
		||||
   * this and just add extra flags to window_activate.
 | 
			
		||||
@@ -3370,6 +3398,8 @@ meta_window_activate_with_workspace (MetaWindow     *window,
 | 
			
		||||
                                     guint32         timestamp,
 | 
			
		||||
                                     MetaWorkspace  *workspace)
 | 
			
		||||
{
 | 
			
		||||
  g_return_if_fail (!window->override_redirect);
 | 
			
		||||
 | 
			
		||||
  /* We're not really a pager, but the behavior we want is the same as if
 | 
			
		||||
   * we were such.  If we change the pager behavior later, we could revisit
 | 
			
		||||
   * this and just add extra flags to window_activate.
 | 
			
		||||
@@ -3620,6 +3650,8 @@ meta_window_move_resize_internal (MetaWindow          *window,
 | 
			
		||||
  MetaRectangle new_rect;
 | 
			
		||||
  MetaRectangle old_rect;
 | 
			
		||||
 | 
			
		||||
  g_return_if_fail (!window->override_redirect);
 | 
			
		||||
 | 
			
		||||
  is_configure_request = (flags & META_IS_CONFIGURE_REQUEST) != 0;
 | 
			
		||||
  do_gravity_adjust = (flags & META_DO_GRAVITY_ADJUST) != 0;
 | 
			
		||||
  is_user_action = (flags & META_IS_USER_ACTION) != 0;
 | 
			
		||||
@@ -4020,6 +4052,8 @@ meta_window_resize (MetaWindow  *window,
 | 
			
		||||
  int x, y;
 | 
			
		||||
  MetaMoveResizeFlags flags;
 | 
			
		||||
 | 
			
		||||
  g_return_if_fail (!window->override_redirect);
 | 
			
		||||
 | 
			
		||||
  meta_window_get_position (window, &x, &y);
 | 
			
		||||
 | 
			
		||||
  flags = (user_op ? META_IS_USER_ACTION : 0) | META_IS_RESIZE_ACTION;
 | 
			
		||||
@@ -4035,8 +4069,12 @@ meta_window_move (MetaWindow  *window,
 | 
			
		||||
                  int          root_x_nw,
 | 
			
		||||
                  int          root_y_nw)
 | 
			
		||||
{
 | 
			
		||||
  MetaMoveResizeFlags flags =
 | 
			
		||||
    (user_op ? META_IS_USER_ACTION : 0) | META_IS_MOVE_ACTION;
 | 
			
		||||
  MetaMoveResizeFlags flags;
 | 
			
		||||
 | 
			
		||||
  g_return_if_fail (!window->override_redirect);
 | 
			
		||||
 | 
			
		||||
  flags = (user_op ? META_IS_USER_ACTION : 0) | META_IS_MOVE_ACTION;
 | 
			
		||||
 | 
			
		||||
  meta_window_move_resize_internal (window,
 | 
			
		||||
                                    flags,
 | 
			
		||||
                                    NorthWestGravity,
 | 
			
		||||
@@ -4053,8 +4091,11 @@ meta_window_move_resize (MetaWindow  *window,
 | 
			
		||||
                         int          w,
 | 
			
		||||
                         int          h)
 | 
			
		||||
{
 | 
			
		||||
  MetaMoveResizeFlags flags =
 | 
			
		||||
    (user_op ? META_IS_USER_ACTION : 0) |
 | 
			
		||||
  MetaMoveResizeFlags flags;
 | 
			
		||||
 | 
			
		||||
  g_return_if_fail (!window->override_redirect);
 | 
			
		||||
 | 
			
		||||
  flags = (user_op ? META_IS_USER_ACTION : 0) |
 | 
			
		||||
    META_IS_MOVE_ACTION | META_IS_RESIZE_ACTION;
 | 
			
		||||
  meta_window_move_resize_internal (window,
 | 
			
		||||
                                    flags,
 | 
			
		||||
@@ -4470,6 +4511,8 @@ meta_window_focus (MetaWindow  *window,
 | 
			
		||||
{
 | 
			
		||||
  MetaWindow *modal_transient;
 | 
			
		||||
 | 
			
		||||
  g_return_if_fail (!window->override_redirect);
 | 
			
		||||
 | 
			
		||||
  meta_topic (META_DEBUG_FOCUS,
 | 
			
		||||
              "Setting input focus to window %s, input: %d take_focus: %d\n",
 | 
			
		||||
              window->desc, window->input, window->take_focus);
 | 
			
		||||
@@ -4601,6 +4644,8 @@ void
 | 
			
		||||
meta_window_change_workspace (MetaWindow    *window,
 | 
			
		||||
                              MetaWorkspace *workspace)
 | 
			
		||||
{
 | 
			
		||||
  g_return_if_fail (!window->override_redirect);
 | 
			
		||||
 | 
			
		||||
  meta_window_change_workspace_without_transients (window, workspace);
 | 
			
		||||
 | 
			
		||||
  meta_window_foreach_transient (window, change_workspace_foreach,
 | 
			
		||||
@@ -4698,6 +4743,9 @@ void
 | 
			
		||||
meta_window_stick (MetaWindow  *window)
 | 
			
		||||
{
 | 
			
		||||
  gboolean stick = TRUE;
 | 
			
		||||
 | 
			
		||||
  g_return_if_fail (!window->override_redirect);
 | 
			
		||||
 | 
			
		||||
  window_stick_impl (window);
 | 
			
		||||
  meta_window_foreach_transient (window,
 | 
			
		||||
                                 stick_foreach_func,
 | 
			
		||||
@@ -4708,6 +4756,9 @@ void
 | 
			
		||||
meta_window_unstick (MetaWindow  *window)
 | 
			
		||||
{
 | 
			
		||||
  gboolean stick = FALSE;
 | 
			
		||||
 | 
			
		||||
  g_return_if_fail (!window->override_redirect);
 | 
			
		||||
 | 
			
		||||
  window_unstick_impl (window);
 | 
			
		||||
  meta_window_foreach_transient (window,
 | 
			
		||||
                                 stick_foreach_func,
 | 
			
		||||
@@ -4808,6 +4859,9 @@ void
 | 
			
		||||
meta_window_raise (MetaWindow  *window)
 | 
			
		||||
{
 | 
			
		||||
  MetaWindow *ancestor;
 | 
			
		||||
 | 
			
		||||
  g_return_if_fail (!window->override_redirect);
 | 
			
		||||
 | 
			
		||||
  ancestor = meta_window_find_root_ancestor (window);
 | 
			
		||||
 | 
			
		||||
  meta_topic (META_DEBUG_WINDOW_OPS,
 | 
			
		||||
@@ -4849,6 +4903,8 @@ meta_window_raise (MetaWindow  *window)
 | 
			
		||||
void
 | 
			
		||||
meta_window_lower (MetaWindow  *window)
 | 
			
		||||
{
 | 
			
		||||
  g_return_if_fail (!window->override_redirect);
 | 
			
		||||
 | 
			
		||||
  meta_topic (META_DEBUG_WINDOW_OPS,
 | 
			
		||||
              "Lowering window %s\n", window->desc);
 | 
			
		||||
 | 
			
		||||
@@ -5160,6 +5216,8 @@ meta_window_change_workspace_by_index (MetaWindow *window,
 | 
			
		||||
  MetaWorkspace *workspace;
 | 
			
		||||
  MetaScreen    *screen;
 | 
			
		||||
 | 
			
		||||
  g_return_if_fail (!window->override_redirect);
 | 
			
		||||
 | 
			
		||||
  if (space_index == -1)
 | 
			
		||||
    {
 | 
			
		||||
      meta_window_stick (window);
 | 
			
		||||
@@ -5208,6 +5266,16 @@ meta_window_client_message (MetaWindow *window,
 | 
			
		||||
 | 
			
		||||
  display = window->display;
 | 
			
		||||
 | 
			
		||||
  if (window->override_redirect)
 | 
			
		||||
    {
 | 
			
		||||
      /* Don't warn here: we could warn on any of the messages below,
 | 
			
		||||
       * but we might also receive other client messages that are
 | 
			
		||||
       * part of protocols we don't know anything about. So, silently
 | 
			
		||||
       * ignoring is simplest.
 | 
			
		||||
       */
 | 
			
		||||
      return FALSE;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
  if (event->xclient.message_type ==
 | 
			
		||||
      display->atom__NET_CLOSE_WINDOW)
 | 
			
		||||
    {
 | 
			
		||||
@@ -5888,7 +5956,7 @@ process_property_notify (MetaWindow     *window,
 | 
			
		||||
        xid = window->user_time_window;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
  meta_window_reload_property (window, event->atom, FALSE);
 | 
			
		||||
  meta_window_reload_property_from_xwindow (window, xid, event->atom, FALSE);
 | 
			
		||||
 | 
			
		||||
  return TRUE;
 | 
			
		||||
}
 | 
			
		||||
@@ -5965,6 +6033,8 @@ meta_window_get_icon_geometry (MetaWindow    *window,
 | 
			
		||||
  gulong *geometry = NULL;
 | 
			
		||||
  int nitems;
 | 
			
		||||
 | 
			
		||||
  g_return_val_if_fail (!window->override_redirect, FALSE);
 | 
			
		||||
 | 
			
		||||
  if (meta_prop_get_cardinal_list (window->display,
 | 
			
		||||
                                   window->xwindow,
 | 
			
		||||
                                   window->display->atom__NET_WM_ICON_GEOMETRY,
 | 
			
		||||
@@ -6099,6 +6169,8 @@ meta_window_update_role (MetaWindow *window)
 | 
			
		||||
{
 | 
			
		||||
  char *str;
 | 
			
		||||
 | 
			
		||||
  g_return_if_fail (!window->override_redirect);
 | 
			
		||||
 | 
			
		||||
  if (window->role)
 | 
			
		||||
    g_free (window->role);
 | 
			
		||||
  window->role = NULL;
 | 
			
		||||
@@ -6200,6 +6272,8 @@ meta_window_update_icon_now (MetaWindow *window)
 | 
			
		||||
  GdkPixbuf *icon;
 | 
			
		||||
  GdkPixbuf *mini_icon;
 | 
			
		||||
 | 
			
		||||
  g_return_if_fail (!window->override_redirect);
 | 
			
		||||
 | 
			
		||||
  icon = NULL;
 | 
			
		||||
  mini_icon = NULL;
 | 
			
		||||
 | 
			
		||||
@@ -6308,6 +6382,8 @@ meta_window_update_struts (MetaWindow *window)
 | 
			
		||||
  int nitems;
 | 
			
		||||
  gboolean changed;
 | 
			
		||||
 | 
			
		||||
  g_return_if_fail (!window->override_redirect);
 | 
			
		||||
 | 
			
		||||
  meta_verbose ("Updating struts for %s\n", window->desc);
 | 
			
		||||
 | 
			
		||||
  old_struts = window->struts;
 | 
			
		||||
@@ -7008,6 +7084,8 @@ meta_window_show_menu (MetaWindow *window,
 | 
			
		||||
  int n_workspaces;
 | 
			
		||||
  gboolean ltr;
 | 
			
		||||
 | 
			
		||||
  g_return_if_fail (!window->override_redirect);
 | 
			
		||||
 | 
			
		||||
  if (window->display->window_menu)
 | 
			
		||||
    {
 | 
			
		||||
      meta_ui_window_menu_free (window->display->window_menu);
 | 
			
		||||
@@ -7131,6 +7209,8 @@ meta_window_shove_titlebar_onscreen (MetaWindow *window)
 | 
			
		||||
  int            horiz_amount, vert_amount;
 | 
			
		||||
  int            newx, newy;
 | 
			
		||||
 | 
			
		||||
  g_return_if_fail (!window->override_redirect);
 | 
			
		||||
 | 
			
		||||
  /* If there's no titlebar, don't bother */
 | 
			
		||||
  if (!window->frame)
 | 
			
		||||
    return;
 | 
			
		||||
@@ -8498,6 +8578,8 @@ meta_window_set_user_time (MetaWindow *window,
 | 
			
		||||
   * a future time.
 | 
			
		||||
   */
 | 
			
		||||
 | 
			
		||||
  g_return_if_fail (!window->override_redirect);
 | 
			
		||||
 | 
			
		||||
  /* Only update the time if this timestamp is newer... */
 | 
			
		||||
  if (window->net_wm_user_time_set &&
 | 
			
		||||
      XSERVER_TIME_IS_BEFORE (timestamp, window->net_wm_user_time))
 | 
			
		||||
 
 | 
			
		||||
@@ -620,8 +620,14 @@ meta_workspace_update_window_hints (MetaWorkspace *workspace)
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/* get windows contained on workspace, including workspace->windows
 | 
			
		||||
 * and also sticky windows.
 | 
			
		||||
/**
 | 
			
		||||
 * meta_display_list_windows:
 | 
			
		||||
 * @display: a #MetaDisplay
 | 
			
		||||
 *
 | 
			
		||||
 * Gets windows contained on the workspace, including workspace->windows
 | 
			
		||||
 * and also sticky windows. Override-redirect windows are not included.
 | 
			
		||||
 *
 | 
			
		||||
 * Return value: (transfer container): the list of windows.
 | 
			
		||||
 */
 | 
			
		||||
GList*
 | 
			
		||||
meta_workspace_list_windows (MetaWorkspace *workspace)
 | 
			
		||||
 
 | 
			
		||||
@@ -76,7 +76,8 @@ Window meta_ui_create_frame_window (MetaUI *ui,
 | 
			
		||||
				    gint y,
 | 
			
		||||
				    gint width,
 | 
			
		||||
				    gint height,
 | 
			
		||||
				    gint screen_no);
 | 
			
		||||
				    gint screen_no,
 | 
			
		||||
                                    gulong *create_serial);
 | 
			
		||||
void meta_ui_destroy_frame_window (MetaUI *ui,
 | 
			
		||||
				   Window  xwindow);
 | 
			
		||||
void meta_ui_move_resize_frame (MetaUI *ui,
 | 
			
		||||
 
 | 
			
		||||
@@ -159,7 +159,8 @@ meta_ui_create_frame_window (MetaUI *ui,
 | 
			
		||||
			     gint y,
 | 
			
		||||
			     gint width,
 | 
			
		||||
			     gint height,
 | 
			
		||||
			     gint screen_no)
 | 
			
		||||
			     gint screen_no,
 | 
			
		||||
                             gulong *create_serial)
 | 
			
		||||
{
 | 
			
		||||
  GdkDisplay *display = gdk_x11_lookup_xdisplay (xdisplay);
 | 
			
		||||
  GdkScreen *screen = gdk_display_get_screen (display, screen_no);
 | 
			
		||||
@@ -208,6 +209,12 @@ meta_ui_create_frame_window (MetaUI *ui,
 | 
			
		||||
 | 
			
		||||
  attributes_mask = GDK_WA_X | GDK_WA_Y | GDK_WA_VISUAL | GDK_WA_COLORMAP;
 | 
			
		||||
 | 
			
		||||
  /* We make an assumption that gdk_window_new() is going to call
 | 
			
		||||
   * XCreateWindow as it's first operation; this seems to be true currently
 | 
			
		||||
   * as long as you pass in a colormap.
 | 
			
		||||
   */
 | 
			
		||||
  if (create_serial)
 | 
			
		||||
    *create_serial = XNextRequest (xdisplay);
 | 
			
		||||
  window =
 | 
			
		||||
    gdk_window_new (gdk_screen_get_root_window(screen),
 | 
			
		||||
		    &attrs, attributes_mask);
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user