Compare commits
	
		
			19 Commits
		
	
	
		
			3.5.90
			...
			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