Compare commits
19 Commits
citadel
...
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);
|
||||
|
Loading…
x
Reference in New Issue
Block a user