Compare commits

...

19 Commits

Author SHA1 Message Date
Owen W. Taylor
8a0de6dfd3 Avoid restacking animating hidden actors
Since the stack passed to the compositor now accurately reflects
the X stacking order, we need to treat hidden windows (which are
at the bottom of the X stacking order) specially - when the
compositor stacking order is synced, try to keep animating hidden
actors in their old positions in the stack.

http://bugzilla.gnome.org/show_bug.cgi?id=585984
2009-06-27 09:58:45 -04:00
Owen W. Taylor
2bf0b2b6de Merge branch 'master' into override-redirect-exclusion 2009-06-19 11:42:03 -04:00
Owen W. Taylor
eed2a2d324 Fix shadowing problem breaking MetaStackTracker
A variable shadowing problem introduced in cleanup was causing
queued elements to be removed too early.

http://bugzilla.gnome.org/show_bug.cgi?id=585984
2009-06-17 14:23:57 -04:00
Owen W. Taylor
9828007a02 Merge branch 'master' into override-redirect-exclusion
Conflicts:
	src/core/bell.c
2009-06-17 13:40:42 -04:00
Owen W. Taylor
1f890672bb Use MetaStackTracker to avoid a round-trip XQueryTree()
With MetaStackTracker, it's no longer necessary to XQueryTree to
get a reasonably-up-to-date view of the server stacking order.

Add some comments explaining unclear aspects of
raise_window_relative_to_managed_windows() and with future possible
improvements.

http://bugzilla.gnome.org/show_bug.cgi?id=585984
2009-06-16 09:56:43 -04:00
Owen W. Taylor
ef966854d5 Don't do stacking for override-redirect windows
Don't add override-redirect windows to MetaStack; we shouldn't
be restacking them.

Since we *aren't* stacking the override-redirect windows, we need to
be careful that to ignore them when looking for the top managed
window.

http://bugzilla.gnome.org/show_bug.cgi?id=585984
2009-06-16 09:56:42 -04:00
Owen W. Taylor
7309b6cfe3 Move compositor-stack handling to MetaStackTracker
In order to properly track the stacking order for override-redirect
windows, move meta_compositor_sync_stack() call into MetaStackTracker.
In the new location, we sync the stack as a before-redraw idle function,
rather then using the freeze-thaw facilities of MetaStack. This is
simpler, and also properly compresses multiple stack changes on
notifications received from the X server.

http://bugzilla.gnome.org/show_bug.cgi?id=585984
2009-06-16 09:56:42 -04:00
Owen W. Taylor
3705a224f0 Add better tracking of real stacking order
Wedging override-redirect windows into the constraint code in stack.c
results in Mutter getting confused about the stacking order of
these windows with respect to other windows, and may also in some
cases cause Mutter to restack override-redirect windows.

core/stack-tracker.c core/stack-tracker.h: MetaStackTracker - combine
  events received from the X server with local changes we have made
  to come up with the best possible idea of what the stacking order
  is at any one point in time.

core/screen.c core/screen-private.h: Create a MetaStackTracker for
  the screen.

core/display.c: Feed relevant events to MetaStackTracker

core/frame.c core/screen.c core/stack.c: When we make changes to the
  stacking order or add windows, record those changes immediatley
  in MetaStackTracker so we have the information without waiting
  for a round-trip.

include/ui.h ui/ui.c: meta_ui_create_frame_window add a return value
  for the X request serial used to create the window.

http://bugzilla.gnome.org/show_bug.cgi?id=585984
2009-06-16 09:56:42 -04:00
Owen W. Taylor
2ebedb822d Avoid moving and resizing override-redirect windows
Override-redirect windows should not be moved or resized by the
window manager.

- Mark override-redirect windows as already placed to avoid
  placing them when first shown.
- Don't move-resize newly created override-redirect MetaWindow
- Don't queue a resize on override-redirect windows when reading
  their WM_TRANSIENT_FOR hint.
- Add g_return_if_fail (!window->override_redirect) to catch
  unexpected code paths that might result in override-redirect
  windows being moved or resized.
http://bugzilla.gnome.org/show_bug.cgi?id=582639
2009-06-16 09:56:42 -04:00
Owen W. Taylor
d6576d9b70 Don't add override-redirect windows to workspaces
Normally a window that is "on all workspaces", is also on a particular
workspace (to deal with being unstuck.) This is pointless for
override-redirect windows.

http://bugzilla.gnome.org/show_bug.cgi?id=582639
2009-06-16 09:56:42 -04:00
Owen W. Taylor
6516c19ec5 Ignore client messages sent to override-redirect windows
If someone asks us to close, maximize, etc, an override-redirect
window, just ignore the request.

http://bugzilla.gnome.org/show_bug.cgi?id=582639
2009-06-16 09:56:42 -04:00
Owen W. Taylor
5518fee61c meta_screen_foreach_window(): Skip override-redirect windows
Don't include override-redirect windows when iterating the windows
in the screen. We don't need them for any of the current uses:

 - Queueing redraws and resizes on managed windows
 - Checking which windows should be added to a new workspace

http://bugzilla.gnome.org/show_bug.cgi?id=582639
2009-06-16 09:56:42 -04:00
Owen W. Taylor
ace0521cba meta_display_list_windows: Exclude override-redirect
Don't include override-redirect windows in the list return by
meta_display_list_windows(), since we almost never want to handle
them when considering "all window" for the display. Add a separate
meta_display_list_all_windows() that includes override-redirect
windows.

http://bugzilla.gnome.org/show_bug.cgi?id=582639
2009-06-16 09:56:42 -04:00
Owen W. Taylor
0091a3aab5 Don't read most properties for override-redirect windows
Skipping handling of properties for override redirect windows has
two advantages: first it reduces the amount of work needed to get
an override-redirect window (menu, tooltip, drag icon) onto the
screen. But more importantly, it reduces the number of code-paths
for an override-redirect to get into some code portion where it
isn't expected.

* Integrate the list of properties we load initially with the
  list of property hooks; this avoids having two separate lists
  that we have to keep in sync.

* Add a flag to MetaWindowPropHooks to indicate whether the
  property should be handled for override-redirect windows;
  currently we load a) properties that identify the window -
  useful for debugging purposes b) WM_TRANSIENT_FOR (could be
  used to associate menus with toplevels.)

* For properties that aren't always loaded through window-props.c,
  add !window->override checks to places that trigger loading,
  and add g_return_if_fail(!window->override) to the load
  functions as a double-check.

http://bugzilla.gnome.org/show_bug.cgi?id=582639
2009-06-16 09:56:42 -04:00
Owen W. Taylor
268b92a4ec Add checks against inappropriate changes to override-redirect window
Add g_return_if_fail() to check that window-management functions like
meta_window_maximize() aren't called on override-redirect windows.

This reveals that were were "unminimizing" override-redirect windows
when adding them; avoid doing that.

http://bugzilla.gnome.org/show_bug.cgi?id=582639
2009-06-16 09:56:41 -04:00
Owen W. Taylor
29bb4c27e3 Fix property notifications for certain properties
If a property has a reload function, but the standard property-fetching
mechanism isn't used (hooks->type == META_PROP_VALUE_INVALID), then the
a logic error (introduced in January) caused the hook to never be run.

This meant that changes to struts and icons weren't noticed.

Same as: http://bugzilla.gnome.org/show_bug.cgi?id=572573
The fix here is different in detail from that applied to Metacity, but
similar in spirit.

http://bugzilla.gnome.org/show_bug.cgi?id=585980
2009-06-16 09:56:41 -04:00
Owen W. Taylor
bd3bdc51b9 Load NET_WM_USER_TIME from the right window
On subsequent changes, if there is a NET_WM_USER_TIME_WINDOW, then
read the property from that rather than from the main window.
(Fix an accidental regression: the right Window was being computed
but no longer passed in.)

http://bugzilla.gnome.org/show_bug.cgi?id=585979
2009-06-16 09:56:41 -04:00
Owen W. Taylor
0123dab87a Fix missing static for meta_window_show()
Definition of meta_window_show() was missing static although it
was forward-declared with static.

http://bugzilla.gnome.org/show_bug.cgi?id=585978
2009-06-16 09:56:41 -04:00
Owen W. Taylor
413acc9574 Regularize main loop priorities
If there is a client that is continually redrawing, then
sources that are less-prioritized than CLUTTER_PRIORITY_REDRAW
will never get run. This patch sorts out how all the different
main loop sources fit in CLUTTER_PRIORITY_REDRAW.

common.h: Document all the relevant priorities and how they
  fit in with each other.
ui.h common.h: Move META_PRIORITY_RESIZE to to common.h with
  other priorities.
src/core/window.c src/core/screen.c: Change calc-showing,
  update-icon, and update-work-area idles to be prioritized above
  redraws so they don't get starved.
bell.c: Make the visual bell priority the same as the clutter
  redraw priority.
delete.c: Use a G_PRIORITY_DEFAULT idle when responding to the
  dialog response; we want to handle it as soon as practical.

http://bugzilla.gnome.org/show_bug.cgi?id=568874
2009-06-16 09:56:41 -04:00
16 changed files with 1411 additions and 236 deletions

View File

@ -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 \

View File

@ -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);

View File

@ -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);

View File

@ -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 */

View File

@ -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,

View File

@ -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;

View File

@ -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
View 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
View 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 */

View File

@ -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... */
}

View File

@ -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

View File

@ -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

View File

@ -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))

View File

@ -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)

View File

@ -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,

View File

@ -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);