x11: Add MetaX11Stack object
This object takes care of the X11 representation of the window stack, namely the _NET_CLIENT_LIST and _NET_CLIENT_LIST_STACKING root window properties. This code has been lifted from src/core/stack.c into src/x11 as it's dependent on the X11 display availability. This also leaves MetaStack squeaky clean of x11 specifics. https://gitlab.gnome.org/GNOME/mutter/merge_requests/420
This commit is contained in:
parent
39bac6eabd
commit
ef074ea510
257
src/core/stack.c
257
src/core/stack.c
@ -29,18 +29,13 @@
|
|||||||
|
|
||||||
#include "core/stack.h"
|
#include "core/stack.h"
|
||||||
|
|
||||||
#include <X11/Xatom.h>
|
|
||||||
|
|
||||||
#include "backends/meta-logical-monitor.h"
|
#include "backends/meta-logical-monitor.h"
|
||||||
#include "core/frame.h"
|
#include "core/frame.h"
|
||||||
#include "core/meta-workspace-manager-private.h"
|
#include "core/meta-workspace-manager-private.h"
|
||||||
#include "core/window-private.h"
|
#include "core/window-private.h"
|
||||||
#include "meta/group.h"
|
#include "meta/group.h"
|
||||||
#include "meta/meta-x11-errors.h"
|
|
||||||
#include "meta/prefs.h"
|
#include "meta/prefs.h"
|
||||||
#include "meta/workspace.h"
|
#include "meta/workspace.h"
|
||||||
#include "x11/group-private.h"
|
|
||||||
#include "x11/meta-x11-display-private.h"
|
|
||||||
|
|
||||||
#define WINDOW_HAS_TRANSIENT_TYPE(w) \
|
#define WINDOW_HAS_TRANSIENT_TYPE(w) \
|
||||||
(w->type == META_WINDOW_DIALOG || \
|
(w->type == META_WINDOW_DIALOG || \
|
||||||
@ -52,11 +47,8 @@
|
|||||||
#define WINDOW_TRANSIENT_FOR_WHOLE_GROUP(w) \
|
#define WINDOW_TRANSIENT_FOR_WHOLE_GROUP(w) \
|
||||||
(WINDOW_HAS_TRANSIENT_TYPE (w) && w->transient_for == NULL)
|
(WINDOW_HAS_TRANSIENT_TYPE (w) && w->transient_for == NULL)
|
||||||
|
|
||||||
static void stack_sync_to_xserver (MetaStack *stack);
|
|
||||||
static void meta_window_set_stack_position_no_sync (MetaWindow *window,
|
static void meta_window_set_stack_position_no_sync (MetaWindow *window,
|
||||||
int position);
|
int position);
|
||||||
static void stack_do_window_deletions (MetaStack *stack);
|
|
||||||
static void stack_do_window_additions (MetaStack *stack);
|
|
||||||
static void stack_do_relayer (MetaStack *stack);
|
static void stack_do_relayer (MetaStack *stack);
|
||||||
static void stack_do_constrain (MetaStack *stack);
|
static void stack_do_constrain (MetaStack *stack);
|
||||||
static void stack_do_resort (MetaStack *stack);
|
static void stack_do_resort (MetaStack *stack);
|
||||||
@ -85,7 +77,6 @@ G_DEFINE_TYPE (MetaStack, meta_stack, G_TYPE_OBJECT)
|
|||||||
static void
|
static void
|
||||||
meta_stack_init (MetaStack *stack)
|
meta_stack_init (MetaStack *stack)
|
||||||
{
|
{
|
||||||
stack->xwindows = g_array_new (FALSE, FALSE, sizeof (Window));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
@ -93,11 +84,7 @@ meta_stack_finalize (GObject *object)
|
|||||||
{
|
{
|
||||||
MetaStack *stack = META_STACK (object);
|
MetaStack *stack = META_STACK (object);
|
||||||
|
|
||||||
g_array_free (stack->xwindows, TRUE);
|
|
||||||
|
|
||||||
g_list_free (stack->sorted);
|
g_list_free (stack->sorted);
|
||||||
g_list_free (stack->added);
|
|
||||||
g_list_free (stack->removed);
|
|
||||||
|
|
||||||
G_OBJECT_CLASS (meta_stack_parent_class)->finalize (object);
|
G_OBJECT_CLASS (meta_stack_parent_class)->finalize (object);
|
||||||
}
|
}
|
||||||
@ -210,7 +197,11 @@ meta_stack_add (MetaStack *stack,
|
|||||||
if (meta_window_is_in_stack (window))
|
if (meta_window_is_in_stack (window))
|
||||||
meta_bug ("Window %s had stack position already\n", window->desc);
|
meta_bug ("Window %s had stack position already\n", window->desc);
|
||||||
|
|
||||||
stack->added = g_list_prepend (stack->added, window);
|
stack->sorted = g_list_prepend (stack->sorted, window);
|
||||||
|
stack->need_resort = TRUE; /* may not be needed as we add to top */
|
||||||
|
stack->need_constrain = TRUE;
|
||||||
|
stack->need_relayer = TRUE;
|
||||||
|
|
||||||
g_signal_emit (stack, signals[WINDOW_ADDED], 0, window);
|
g_signal_emit (stack, signals[WINDOW_ADDED], 0, window);
|
||||||
|
|
||||||
window->stack_position = stack->n_positions;
|
window->stack_position = stack->n_positions;
|
||||||
@ -219,7 +210,6 @@ meta_stack_add (MetaStack *stack,
|
|||||||
"Window %s has stack_position initialized to %d\n",
|
"Window %s has stack_position initialized to %d\n",
|
||||||
window->desc, window->stack_position);
|
window->desc, window->stack_position);
|
||||||
|
|
||||||
stack_sync_to_xserver (stack);
|
|
||||||
meta_stack_changed (stack);
|
meta_stack_changed (stack);
|
||||||
meta_stack_update_window_tile_matches (stack, workspace_manager->active_workspace);
|
meta_stack_update_window_tile_matches (stack, workspace_manager->active_workspace);
|
||||||
}
|
}
|
||||||
@ -240,27 +230,10 @@ meta_stack_remove (MetaStack *stack,
|
|||||||
window->stack_position = -1;
|
window->stack_position = -1;
|
||||||
stack->n_positions -= 1;
|
stack->n_positions -= 1;
|
||||||
|
|
||||||
/* We don't know if it's been moved from "added" to "stack" yet */
|
|
||||||
stack->added = g_list_remove (stack->added, window);
|
|
||||||
stack->sorted = g_list_remove (stack->sorted, window);
|
stack->sorted = g_list_remove (stack->sorted, window);
|
||||||
|
|
||||||
g_signal_emit (stack, signals[WINDOW_REMOVED], 0, window);
|
g_signal_emit (stack, signals[WINDOW_REMOVED], 0, window);
|
||||||
|
|
||||||
/* stack->removed is only used to update stack->xwindows */
|
|
||||||
if (window->client_type == META_WINDOW_CLIENT_TYPE_X11)
|
|
||||||
{
|
|
||||||
/* Remember the window ID to remove it from the stack array.
|
|
||||||
* The macro is safe to use: Window is guaranteed to be 32 bits, and
|
|
||||||
* GUINT_TO_POINTER says it only works on 32 bits.
|
|
||||||
*/
|
|
||||||
stack->removed = g_list_prepend (stack->removed,
|
|
||||||
GUINT_TO_POINTER (window->xwindow));
|
|
||||||
if (window->frame)
|
|
||||||
stack->removed = g_list_prepend (stack->removed,
|
|
||||||
GUINT_TO_POINTER (window->frame->xwindow));
|
|
||||||
}
|
|
||||||
|
|
||||||
stack_sync_to_xserver (stack);
|
|
||||||
meta_stack_changed (stack);
|
meta_stack_changed (stack);
|
||||||
meta_stack_update_window_tile_matches (stack, workspace_manager->active_workspace);
|
meta_stack_update_window_tile_matches (stack, workspace_manager->active_workspace);
|
||||||
}
|
}
|
||||||
@ -272,7 +245,6 @@ meta_stack_update_layer (MetaStack *stack,
|
|||||||
MetaWorkspaceManager *workspace_manager = window->display->workspace_manager;
|
MetaWorkspaceManager *workspace_manager = window->display->workspace_manager;
|
||||||
stack->need_relayer = TRUE;
|
stack->need_relayer = TRUE;
|
||||||
|
|
||||||
stack_sync_to_xserver (stack);
|
|
||||||
meta_stack_changed (stack);
|
meta_stack_changed (stack);
|
||||||
meta_stack_update_window_tile_matches (stack, workspace_manager->active_workspace);
|
meta_stack_update_window_tile_matches (stack, workspace_manager->active_workspace);
|
||||||
}
|
}
|
||||||
@ -284,7 +256,6 @@ meta_stack_update_transient (MetaStack *stack,
|
|||||||
MetaWorkspaceManager *workspace_manager = window->display->workspace_manager;
|
MetaWorkspaceManager *workspace_manager = window->display->workspace_manager;
|
||||||
stack->need_constrain = TRUE;
|
stack->need_constrain = TRUE;
|
||||||
|
|
||||||
stack_sync_to_xserver (stack);
|
|
||||||
meta_stack_changed (stack);
|
meta_stack_changed (stack);
|
||||||
meta_stack_update_window_tile_matches (stack, workspace_manager->active_workspace);
|
meta_stack_update_window_tile_matches (stack, workspace_manager->active_workspace);
|
||||||
}
|
}
|
||||||
@ -315,7 +286,6 @@ meta_stack_raise (MetaStack *stack,
|
|||||||
|
|
||||||
meta_window_set_stack_position_no_sync (window, max_stack_position);
|
meta_window_set_stack_position_no_sync (window, max_stack_position);
|
||||||
|
|
||||||
stack_sync_to_xserver (stack);
|
|
||||||
meta_stack_changed (stack);
|
meta_stack_changed (stack);
|
||||||
meta_stack_update_window_tile_matches (stack, workspace_manager->active_workspace);
|
meta_stack_update_window_tile_matches (stack, workspace_manager->active_workspace);
|
||||||
}
|
}
|
||||||
@ -345,7 +315,6 @@ meta_stack_lower (MetaStack *stack,
|
|||||||
|
|
||||||
meta_window_set_stack_position_no_sync (window, min_stack_position);
|
meta_window_set_stack_position_no_sync (window, min_stack_position);
|
||||||
|
|
||||||
stack_sync_to_xserver (stack);
|
|
||||||
meta_stack_changed (stack);
|
meta_stack_changed (stack);
|
||||||
meta_stack_update_window_tile_matches (stack, workspace_manager->active_workspace);
|
meta_stack_update_window_tile_matches (stack, workspace_manager->active_workspace);
|
||||||
}
|
}
|
||||||
@ -362,7 +331,6 @@ meta_stack_thaw (MetaStack *stack)
|
|||||||
g_return_if_fail (stack->freeze_count > 0);
|
g_return_if_fail (stack->freeze_count > 0);
|
||||||
|
|
||||||
stack->freeze_count -= 1;
|
stack->freeze_count -= 1;
|
||||||
stack_sync_to_xserver (stack);
|
|
||||||
meta_stack_changed (stack);
|
meta_stack_changed (stack);
|
||||||
meta_stack_update_window_tile_matches (stack, NULL);
|
meta_stack_update_window_tile_matches (stack, NULL);
|
||||||
}
|
}
|
||||||
@ -879,99 +847,6 @@ apply_constraints (Constraint **constraints,
|
|||||||
g_slist_free (heads);
|
g_slist_free (heads);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* stack_do_window_deletions:
|
|
||||||
*
|
|
||||||
* Go through "deleted" and take the matching windows
|
|
||||||
* out of "windows".
|
|
||||||
*/
|
|
||||||
static void
|
|
||||||
stack_do_window_deletions (MetaStack *stack)
|
|
||||||
{
|
|
||||||
/* Do removals before adds, with paranoid idea that we might re-add
|
|
||||||
* the same window IDs.
|
|
||||||
*/
|
|
||||||
GList *tmp;
|
|
||||||
int i;
|
|
||||||
|
|
||||||
tmp = stack->removed;
|
|
||||||
while (tmp != NULL)
|
|
||||||
{
|
|
||||||
Window xwindow;
|
|
||||||
xwindow = GPOINTER_TO_UINT (tmp->data);
|
|
||||||
|
|
||||||
/* We go from the end figuring removals are more
|
|
||||||
* likely to be recent.
|
|
||||||
*/
|
|
||||||
i = stack->xwindows->len;
|
|
||||||
while (i > 0)
|
|
||||||
{
|
|
||||||
--i;
|
|
||||||
|
|
||||||
/* there's no guarantee we'll actually find windows to
|
|
||||||
* remove, e.g. the same xwindow could have been
|
|
||||||
* added/removed before we ever synced, and we put
|
|
||||||
* both the window->xwindow and window->frame->xwindow
|
|
||||||
* in the removal list.
|
|
||||||
*/
|
|
||||||
if (xwindow == g_array_index (stack->xwindows, Window, i))
|
|
||||||
{
|
|
||||||
g_array_remove_index (stack->xwindows, i);
|
|
||||||
goto next;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
next:
|
|
||||||
tmp = tmp->next;
|
|
||||||
}
|
|
||||||
|
|
||||||
g_list_free (stack->removed);
|
|
||||||
stack->removed = NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void
|
|
||||||
stack_do_window_additions (MetaStack *stack)
|
|
||||||
{
|
|
||||||
GList *tmp;
|
|
||||||
gint n_added;
|
|
||||||
|
|
||||||
n_added = g_list_length (stack->added);
|
|
||||||
if (n_added > 0)
|
|
||||||
{
|
|
||||||
meta_topic (META_DEBUG_STACK,
|
|
||||||
"Adding %d windows to sorted list\n",
|
|
||||||
n_added);
|
|
||||||
|
|
||||||
/* stack->added has the most recent additions at the
|
|
||||||
* front of the list, so we need to reverse it
|
|
||||||
*/
|
|
||||||
stack->added = g_list_reverse (stack->added);
|
|
||||||
|
|
||||||
tmp = stack->added;
|
|
||||||
while (tmp != NULL)
|
|
||||||
{
|
|
||||||
MetaWindow *w;
|
|
||||||
|
|
||||||
w = tmp->data;
|
|
||||||
|
|
||||||
if (w->client_type == META_WINDOW_CLIENT_TYPE_X11)
|
|
||||||
g_array_append_val (stack->xwindows, w->xwindow);
|
|
||||||
|
|
||||||
/* add to the main list */
|
|
||||||
stack->sorted = g_list_prepend (stack->sorted, w);
|
|
||||||
|
|
||||||
tmp = tmp->next;
|
|
||||||
}
|
|
||||||
|
|
||||||
stack->need_resort = TRUE; /* may not be needed as we add to top */
|
|
||||||
stack->need_constrain = TRUE;
|
|
||||||
stack->need_relayer = TRUE;
|
|
||||||
}
|
|
||||||
|
|
||||||
g_list_free (stack->added);
|
|
||||||
stack->added = NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* stack_do_relayer:
|
* stack_do_relayer:
|
||||||
*
|
*
|
||||||
@ -1089,131 +964,11 @@ stack_do_resort (MetaStack *stack)
|
|||||||
static void
|
static void
|
||||||
stack_ensure_sorted (MetaStack *stack)
|
stack_ensure_sorted (MetaStack *stack)
|
||||||
{
|
{
|
||||||
stack_do_window_deletions (stack);
|
|
||||||
stack_do_window_additions (stack);
|
|
||||||
stack_do_relayer (stack);
|
stack_do_relayer (stack);
|
||||||
stack_do_constrain (stack);
|
stack_do_constrain (stack);
|
||||||
stack_do_resort (stack);
|
stack_do_resort (stack);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* stack_sync_to_server:
|
|
||||||
*
|
|
||||||
* Order the windows on the X server to be the same as in our structure.
|
|
||||||
* We do this using XRestackWindows if we don't know the previous order,
|
|
||||||
* 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_xserver (MetaStack *stack)
|
|
||||||
{
|
|
||||||
GArray *x11_stacked;
|
|
||||||
GArray *all_root_children_stacked; /* wayland OR x11 */
|
|
||||||
GList *tmp;
|
|
||||||
GArray *hidden_stack_ids;
|
|
||||||
|
|
||||||
/* Bail out if frozen */
|
|
||||||
if (stack->freeze_count > 0)
|
|
||||||
return;
|
|
||||||
|
|
||||||
meta_topic (META_DEBUG_STACK, "Syncing window stack to server\n");
|
|
||||||
|
|
||||||
stack_ensure_sorted (stack);
|
|
||||||
|
|
||||||
/* Create stacked xwindow arrays, in bottom-to-top order
|
|
||||||
*/
|
|
||||||
x11_stacked = g_array_new (FALSE, FALSE, sizeof (Window));
|
|
||||||
|
|
||||||
all_root_children_stacked = g_array_new (FALSE, FALSE, sizeof (guint64));
|
|
||||||
hidden_stack_ids = g_array_new (FALSE, FALSE, sizeof (guint64));
|
|
||||||
|
|
||||||
meta_topic (META_DEBUG_STACK, "Bottom to top: ");
|
|
||||||
meta_push_no_msg_prefix ();
|
|
||||||
|
|
||||||
for (tmp = g_list_last(stack->sorted); tmp != NULL; tmp = tmp->prev)
|
|
||||||
{
|
|
||||||
MetaWindow *w = tmp->data;
|
|
||||||
guint64 top_level_window;
|
|
||||||
guint64 stack_id;
|
|
||||||
|
|
||||||
if (w->unmanaging)
|
|
||||||
continue;
|
|
||||||
|
|
||||||
meta_topic (META_DEBUG_STACK, "%u:%d - %s ",
|
|
||||||
w->layer, w->stack_position, w->desc);
|
|
||||||
|
|
||||||
if (w->client_type == META_WINDOW_CLIENT_TYPE_X11)
|
|
||||||
g_array_append_val (x11_stacked, w->xwindow);
|
|
||||||
|
|
||||||
if (w->frame)
|
|
||||||
top_level_window = w->frame->xwindow;
|
|
||||||
else
|
|
||||||
top_level_window = w->xwindow;
|
|
||||||
|
|
||||||
if (w->client_type == META_WINDOW_CLIENT_TYPE_X11)
|
|
||||||
stack_id = top_level_window;
|
|
||||||
else
|
|
||||||
stack_id = w->stamp;
|
|
||||||
|
|
||||||
/* We don't restack hidden windows along with the rest, though they are
|
|
||||||
* reflected in the _NET hints. Hidden windows all get pushed below
|
|
||||||
* the screens fullscreen guard_window. */
|
|
||||||
if (w->hidden)
|
|
||||||
{
|
|
||||||
g_array_append_val (hidden_stack_ids, stack_id);
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
g_array_append_val (all_root_children_stacked, stack_id);
|
|
||||||
}
|
|
||||||
|
|
||||||
meta_topic (META_DEBUG_STACK, "\n");
|
|
||||||
meta_pop_no_msg_prefix ();
|
|
||||||
|
|
||||||
/* The screen guard window sits above all hidden windows and acts as
|
|
||||||
* a barrier to input reaching these windows. */
|
|
||||||
guint64 guard_window_id = stack->display->x11_display->guard_window;
|
|
||||||
g_array_append_val (hidden_stack_ids, guard_window_id);
|
|
||||||
|
|
||||||
/* Sync to server */
|
|
||||||
|
|
||||||
meta_topic (META_DEBUG_STACK, "Restacking %u windows\n",
|
|
||||||
all_root_children_stacked->len);
|
|
||||||
|
|
||||||
meta_stack_tracker_restack_managed (stack->display->stack_tracker,
|
|
||||||
(guint64 *)all_root_children_stacked->data,
|
|
||||||
all_root_children_stacked->len);
|
|
||||||
meta_stack_tracker_restack_at_bottom (stack->display->stack_tracker,
|
|
||||||
(guint64 *)hidden_stack_ids->data,
|
|
||||||
hidden_stack_ids->len);
|
|
||||||
|
|
||||||
/* Sync _NET_CLIENT_LIST and _NET_CLIENT_LIST_STACKING */
|
|
||||||
|
|
||||||
XChangeProperty (stack->display->x11_display->xdisplay,
|
|
||||||
stack->display->x11_display->xroot,
|
|
||||||
stack->display->x11_display->atom__NET_CLIENT_LIST,
|
|
||||||
XA_WINDOW,
|
|
||||||
32, PropModeReplace,
|
|
||||||
(unsigned char *)stack->xwindows->data,
|
|
||||||
stack->xwindows->len);
|
|
||||||
XChangeProperty (stack->display->x11_display->xdisplay,
|
|
||||||
stack->display->x11_display->xroot,
|
|
||||||
stack->display->x11_display->atom__NET_CLIENT_LIST_STACKING,
|
|
||||||
XA_WINDOW,
|
|
||||||
32, PropModeReplace,
|
|
||||||
(unsigned char *)x11_stacked->data,
|
|
||||||
x11_stacked->len);
|
|
||||||
|
|
||||||
g_array_free (x11_stacked, TRUE);
|
|
||||||
g_array_free (hidden_stack_ids, TRUE);
|
|
||||||
g_array_free (all_root_children_stacked, TRUE);
|
|
||||||
}
|
|
||||||
|
|
||||||
MetaWindow*
|
MetaWindow*
|
||||||
meta_stack_get_top (MetaStack *stack)
|
meta_stack_get_top (MetaStack *stack)
|
||||||
{
|
{
|
||||||
@ -1523,7 +1278,6 @@ meta_stack_set_positions (MetaStack *stack,
|
|||||||
meta_topic (META_DEBUG_STACK,
|
meta_topic (META_DEBUG_STACK,
|
||||||
"Reset the stack positions of (nearly) all windows\n");
|
"Reset the stack positions of (nearly) all windows\n");
|
||||||
|
|
||||||
stack_sync_to_xserver (stack);
|
|
||||||
meta_stack_changed (stack);
|
meta_stack_changed (stack);
|
||||||
meta_stack_update_window_tile_matches (stack, NULL);
|
meta_stack_update_window_tile_matches (stack, NULL);
|
||||||
}
|
}
|
||||||
@ -1589,7 +1343,6 @@ meta_window_set_stack_position (MetaWindow *window,
|
|||||||
MetaWorkspaceManager *workspace_manager = window->display->workspace_manager;
|
MetaWorkspaceManager *workspace_manager = window->display->workspace_manager;
|
||||||
|
|
||||||
meta_window_set_stack_position_no_sync (window, position);
|
meta_window_set_stack_position_no_sync (window, position);
|
||||||
stack_sync_to_xserver (window->display->stack);
|
|
||||||
meta_stack_changed (window->display->stack);
|
meta_stack_changed (window->display->stack);
|
||||||
meta_stack_update_window_tile_matches (window->display->stack,
|
meta_stack_update_window_tile_matches (window->display->stack,
|
||||||
workspace_manager->active_workspace);
|
workspace_manager->active_workspace);
|
||||||
|
@ -56,35 +56,9 @@ struct _MetaStack
|
|||||||
/** The MetaDisplay containing this stack. */
|
/** The MetaDisplay containing this stack. */
|
||||||
MetaDisplay *display;
|
MetaDisplay *display;
|
||||||
|
|
||||||
/**
|
|
||||||
* A sequence of all the Windows (X handles, not MetaWindows) of the windows
|
|
||||||
* we manage, sorted in order. Suitable to be passed into _NET_CLIENT_LIST.
|
|
||||||
*/
|
|
||||||
GArray *xwindows;
|
|
||||||
|
|
||||||
/** The MetaWindows of the windows we manage, sorted in order. */
|
/** The MetaWindows of the windows we manage, sorted in order. */
|
||||||
GList *sorted;
|
GList *sorted;
|
||||||
|
|
||||||
/**
|
|
||||||
* MetaWindows waiting to be added to the "sorted" and "windows" list, after
|
|
||||||
* being added by meta_stack_add() and before being assimilated by
|
|
||||||
* stack_ensure_sorted().
|
|
||||||
*
|
|
||||||
* The order of the elements in this list is not important; what is important
|
|
||||||
* is the stack_position element of each window.
|
|
||||||
*/
|
|
||||||
GList *added;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Windows (X handles, not MetaWindows) waiting to be removed from the
|
|
||||||
* "windows" list, after being removed by meta_stack_remove() and before
|
|
||||||
* being assimilated by stack_ensure_sorted(). (We already removed them
|
|
||||||
* from the "sorted" list.)
|
|
||||||
*
|
|
||||||
* The order of the elements in this list is not important.
|
|
||||||
*/
|
|
||||||
GList *removed;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* If this is zero, the local stack oughtn't to be brought up to date with
|
* If this is zero, the local stack oughtn't to be brought up to date with
|
||||||
* the X server's stack, because it is in the middle of being updated.
|
* the X server's stack, because it is in the middle of being updated.
|
||||||
|
@ -392,6 +392,8 @@ mutter_sources = [
|
|||||||
'x11/meta-x11-selection-input-stream-private.h',
|
'x11/meta-x11-selection-input-stream-private.h',
|
||||||
'x11/meta-x11-selection-output-stream.c',
|
'x11/meta-x11-selection-output-stream.c',
|
||||||
'x11/meta-x11-selection-output-stream-private.h',
|
'x11/meta-x11-selection-output-stream-private.h',
|
||||||
|
'x11/meta-x11-stack.c',
|
||||||
|
'x11/meta-x11-stack-private.h',
|
||||||
'x11/mutter-Xatomtype.h',
|
'x11/mutter-Xatomtype.h',
|
||||||
'x11/session.c',
|
'x11/session.c',
|
||||||
'x11/session.h',
|
'x11/session.h',
|
||||||
|
@ -35,6 +35,7 @@
|
|||||||
#include "meta/types.h"
|
#include "meta/types.h"
|
||||||
#include "meta/meta-x11-display.h"
|
#include "meta/meta-x11-display.h"
|
||||||
#include "meta-startup-notification-x11.h"
|
#include "meta-startup-notification-x11.h"
|
||||||
|
#include "meta-x11-stack-private.h"
|
||||||
#include "ui/ui.h"
|
#include "ui/ui.h"
|
||||||
|
|
||||||
typedef struct _MetaGroupPropHooks MetaGroupPropHooks;
|
typedef struct _MetaGroupPropHooks MetaGroupPropHooks;
|
||||||
@ -167,6 +168,7 @@ struct _MetaX11Display
|
|||||||
#define META_X11_DISPLAY_HAS_XINPUT_23(x11_display) ((x11_display)->have_xinput_23)
|
#define META_X11_DISPLAY_HAS_XINPUT_23(x11_display) ((x11_display)->have_xinput_23)
|
||||||
|
|
||||||
MetaX11StartupNotification *startup_notification;
|
MetaX11StartupNotification *startup_notification;
|
||||||
|
MetaX11Stack *x11_stack;
|
||||||
};
|
};
|
||||||
|
|
||||||
MetaX11Display *meta_x11_display_new (MetaDisplay *display, GError **error);
|
MetaX11Display *meta_x11_display_new (MetaDisplay *display, GError **error);
|
||||||
|
@ -108,6 +108,8 @@ meta_x11_display_dispose (GObject *object)
|
|||||||
|
|
||||||
meta_x11_selection_shutdown (x11_display);
|
meta_x11_selection_shutdown (x11_display);
|
||||||
|
|
||||||
|
g_clear_object (&x11_display->x11_stack);
|
||||||
|
|
||||||
if (x11_display->ui)
|
if (x11_display->ui)
|
||||||
{
|
{
|
||||||
meta_ui_free (x11_display->ui);
|
meta_ui_free (x11_display->ui);
|
||||||
@ -1270,6 +1272,7 @@ meta_x11_display_new (MetaDisplay *display, GError **error)
|
|||||||
set_desktop_geometry_hint (x11_display);
|
set_desktop_geometry_hint (x11_display);
|
||||||
|
|
||||||
x11_display->ui = meta_ui_new (x11_display);
|
x11_display->ui = meta_ui_new (x11_display);
|
||||||
|
x11_display->x11_stack = meta_x11_stack_new (x11_display);
|
||||||
|
|
||||||
x11_display->keys_grabbed = FALSE;
|
x11_display->keys_grabbed = FALSE;
|
||||||
meta_x11_display_grab_keys (x11_display);
|
meta_x11_display_grab_keys (x11_display);
|
||||||
|
33
src/x11/meta-x11-stack-private.h
Normal file
33
src/x11/meta-x11-stack-private.h
Normal file
@ -0,0 +1,33 @@
|
|||||||
|
/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */
|
||||||
|
/*
|
||||||
|
* Copyright (C) 2019 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, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef META_X11_STACK_H
|
||||||
|
#define META_X11_STACK_H
|
||||||
|
|
||||||
|
#include <glib-object.h>
|
||||||
|
|
||||||
|
#include "meta/types.h"
|
||||||
|
|
||||||
|
#define META_TYPE_X11_STACK (meta_x11_stack_get_type ())
|
||||||
|
G_DECLARE_FINAL_TYPE (MetaX11Stack, meta_x11_stack, META, X11_STACK, GObject)
|
||||||
|
|
||||||
|
typedef struct _MetaX11Stack MetaX11Stack;
|
||||||
|
|
||||||
|
MetaX11Stack * meta_x11_stack_new (MetaX11Display *x11_display);
|
||||||
|
|
||||||
|
#endif /* META_X11_STACK_H */
|
413
src/x11/meta-x11-stack.c
Normal file
413
src/x11/meta-x11-stack.c
Normal file
@ -0,0 +1,413 @@
|
|||||||
|
/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */
|
||||||
|
/*
|
||||||
|
* Copyright (C) 2019 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, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "config.h"
|
||||||
|
|
||||||
|
#include "core/frame.h"
|
||||||
|
#include "core/stack.h"
|
||||||
|
#include "core/window-private.h"
|
||||||
|
#include "x11/meta-x11-display-private.h"
|
||||||
|
#include "x11/meta-x11-stack-private.h"
|
||||||
|
|
||||||
|
struct _MetaX11Stack
|
||||||
|
{
|
||||||
|
GObject parent;
|
||||||
|
MetaX11Display *x11_display;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* A sequence of all the Windows (X handles, not MetaWindows) of the windows
|
||||||
|
* we manage, sorted in order. Suitable to be passed into _NET_CLIENT_LIST.
|
||||||
|
*/
|
||||||
|
GArray *xwindows;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* MetaWindows waiting to be added to the xwindows list, after
|
||||||
|
* being added to the MetaStack.
|
||||||
|
*
|
||||||
|
* The order of the elements in this list is not important; what is important
|
||||||
|
* is the stack_position element of each window.
|
||||||
|
*/
|
||||||
|
GList *added;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Windows (X handles, not MetaWindows) waiting to be removed from the
|
||||||
|
* xwindows list, after being removed from the MetaStack.
|
||||||
|
*
|
||||||
|
* The order of the elements in this list is not important.
|
||||||
|
*/
|
||||||
|
GList *removed;
|
||||||
|
};
|
||||||
|
|
||||||
|
enum
|
||||||
|
{
|
||||||
|
PROP_DISPLAY = 1,
|
||||||
|
N_PROPS
|
||||||
|
};
|
||||||
|
|
||||||
|
static GParamSpec *pspecs[N_PROPS] = { 0 };
|
||||||
|
|
||||||
|
G_DEFINE_TYPE (MetaX11Stack, meta_x11_stack, G_TYPE_OBJECT)
|
||||||
|
|
||||||
|
static void
|
||||||
|
meta_x11_stack_init (MetaX11Stack *x11_stack)
|
||||||
|
{
|
||||||
|
x11_stack->xwindows = g_array_new (FALSE, FALSE, sizeof (Window));
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
meta_x11_stack_set_property (GObject *object,
|
||||||
|
guint prop_id,
|
||||||
|
const GValue *value,
|
||||||
|
GParamSpec *pspec)
|
||||||
|
{
|
||||||
|
MetaX11Stack *x11_stack = META_X11_STACK (object);
|
||||||
|
|
||||||
|
switch (prop_id)
|
||||||
|
{
|
||||||
|
case PROP_DISPLAY:
|
||||||
|
x11_stack->x11_display = g_value_get_object (value);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
meta_x11_stack_get_property (GObject *object,
|
||||||
|
guint prop_id,
|
||||||
|
GValue *value,
|
||||||
|
GParamSpec *pspec)
|
||||||
|
{
|
||||||
|
MetaX11Stack *x11_stack = META_X11_STACK (object);
|
||||||
|
|
||||||
|
switch (prop_id)
|
||||||
|
{
|
||||||
|
case PROP_DISPLAY:
|
||||||
|
g_value_set_object (value, x11_stack->x11_display);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
stack_window_added_cb (MetaStack *stack,
|
||||||
|
MetaWindow *window,
|
||||||
|
MetaX11Stack *x11_stack)
|
||||||
|
{
|
||||||
|
if (window->client_type != META_WINDOW_CLIENT_TYPE_X11)
|
||||||
|
return;
|
||||||
|
|
||||||
|
x11_stack->added = g_list_prepend (x11_stack->added, window);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
stack_window_removed_cb (MetaStack *stack,
|
||||||
|
MetaWindow *window,
|
||||||
|
MetaX11Stack *x11_stack)
|
||||||
|
{
|
||||||
|
if (window->client_type != META_WINDOW_CLIENT_TYPE_X11)
|
||||||
|
return;
|
||||||
|
|
||||||
|
x11_stack->added = g_list_remove (x11_stack->added, window);
|
||||||
|
|
||||||
|
x11_stack->removed = g_list_prepend (x11_stack->removed,
|
||||||
|
GUINT_TO_POINTER (window->xwindow));
|
||||||
|
if (window->frame)
|
||||||
|
{
|
||||||
|
x11_stack->removed = g_list_prepend (x11_stack->removed,
|
||||||
|
GUINT_TO_POINTER (window->frame->xwindow));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* stack_do_window_deletions:
|
||||||
|
*
|
||||||
|
* Go through "deleted" and take the matching windows
|
||||||
|
* out of "windows".
|
||||||
|
*/
|
||||||
|
static void
|
||||||
|
x11_stack_do_window_deletions (MetaX11Stack *x11_stack)
|
||||||
|
{
|
||||||
|
GList *tmp;
|
||||||
|
int i;
|
||||||
|
|
||||||
|
tmp = x11_stack->removed;
|
||||||
|
while (tmp != NULL)
|
||||||
|
{
|
||||||
|
Window xwindow;
|
||||||
|
xwindow = GPOINTER_TO_UINT (tmp->data);
|
||||||
|
|
||||||
|
/* We go from the end figuring removals are more
|
||||||
|
* likely to be recent.
|
||||||
|
*/
|
||||||
|
i = x11_stack->xwindows->len;
|
||||||
|
while (i > 0)
|
||||||
|
{
|
||||||
|
--i;
|
||||||
|
|
||||||
|
/* there's no guarantee we'll actually find windows to
|
||||||
|
* remove, e.g. the same xwindow could have been
|
||||||
|
* added/removed before we ever synced, and we put
|
||||||
|
* both the window->xwindow and window->frame->xwindow
|
||||||
|
* in the removal list.
|
||||||
|
*/
|
||||||
|
if (xwindow == g_array_index (x11_stack->xwindows, Window, i))
|
||||||
|
{
|
||||||
|
g_array_remove_index (x11_stack->xwindows, i);
|
||||||
|
goto next;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
next:
|
||||||
|
tmp = tmp->next;
|
||||||
|
}
|
||||||
|
|
||||||
|
g_clear_pointer (&x11_stack->removed, g_list_free);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
x11_stack_do_window_additions (MetaX11Stack *x11_stack)
|
||||||
|
{
|
||||||
|
GList *tmp;
|
||||||
|
gint n_added;
|
||||||
|
|
||||||
|
n_added = g_list_length (x11_stack->added);
|
||||||
|
if (n_added > 0)
|
||||||
|
{
|
||||||
|
meta_topic (META_DEBUG_STACK,
|
||||||
|
"Adding %d windows to sorted list\n",
|
||||||
|
n_added);
|
||||||
|
|
||||||
|
/* stack->added has the most recent additions at the
|
||||||
|
* front of the list, so we need to reverse it
|
||||||
|
*/
|
||||||
|
x11_stack->added = g_list_reverse (x11_stack->added);
|
||||||
|
|
||||||
|
tmp = x11_stack->added;
|
||||||
|
while (tmp != NULL)
|
||||||
|
{
|
||||||
|
MetaWindow *w;
|
||||||
|
|
||||||
|
w = tmp->data;
|
||||||
|
g_array_append_val (x11_stack->xwindows, w->xwindow);
|
||||||
|
tmp = tmp->next;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
g_clear_pointer (&x11_stack->added, g_list_free);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* x11_stack_sync_to_server:
|
||||||
|
*
|
||||||
|
* Order the windows on the X server to be the same as in our structure.
|
||||||
|
* We do this using XRestackWindows if we don't know the previous order,
|
||||||
|
* 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
|
||||||
|
x11_stack_sync_to_xserver (MetaX11Stack *x11_stack)
|
||||||
|
{
|
||||||
|
MetaX11Display *x11_display = x11_stack->x11_display;
|
||||||
|
MetaStack *stack = x11_display->display->stack;
|
||||||
|
GArray *x11_stacked;
|
||||||
|
GArray *all_root_children_stacked; /* wayland OR x11 */
|
||||||
|
GList *tmp;
|
||||||
|
GArray *hidden_stack_ids;
|
||||||
|
uint64_t guard_window_id;
|
||||||
|
GList *sorted;
|
||||||
|
|
||||||
|
meta_topic (META_DEBUG_STACK, "Syncing window stack to server\n");
|
||||||
|
|
||||||
|
/* Create stacked xwindow arrays, in bottom-to-top order
|
||||||
|
*/
|
||||||
|
x11_stacked = g_array_new (FALSE, FALSE, sizeof (Window));
|
||||||
|
|
||||||
|
all_root_children_stacked = g_array_new (FALSE, FALSE, sizeof (guint64));
|
||||||
|
hidden_stack_ids = g_array_new (FALSE, FALSE, sizeof (guint64));
|
||||||
|
|
||||||
|
meta_topic (META_DEBUG_STACK, "Bottom to top: ");
|
||||||
|
meta_push_no_msg_prefix ();
|
||||||
|
|
||||||
|
sorted = meta_stack_list_windows (stack, NULL);
|
||||||
|
|
||||||
|
for (tmp = sorted; tmp; tmp = tmp->next)
|
||||||
|
{
|
||||||
|
MetaWindow *w = tmp->data;
|
||||||
|
guint64 top_level_window;
|
||||||
|
guint64 stack_id;
|
||||||
|
|
||||||
|
if (w->unmanaging)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
meta_topic (META_DEBUG_STACK, "%u:%d - %s ",
|
||||||
|
w->layer, w->stack_position, w->desc);
|
||||||
|
|
||||||
|
if (w->client_type == META_WINDOW_CLIENT_TYPE_X11)
|
||||||
|
g_array_append_val (x11_stacked, w->xwindow);
|
||||||
|
|
||||||
|
if (w->frame)
|
||||||
|
top_level_window = w->frame->xwindow;
|
||||||
|
else
|
||||||
|
top_level_window = w->xwindow;
|
||||||
|
|
||||||
|
if (w->client_type == META_WINDOW_CLIENT_TYPE_X11)
|
||||||
|
stack_id = top_level_window;
|
||||||
|
else
|
||||||
|
stack_id = w->stamp;
|
||||||
|
|
||||||
|
/* We don't restack hidden windows along with the rest, though they are
|
||||||
|
* reflected in the _NET hints. Hidden windows all get pushed below
|
||||||
|
* the screens fullscreen guard_window. */
|
||||||
|
if (w->hidden)
|
||||||
|
{
|
||||||
|
g_array_append_val (hidden_stack_ids, stack_id);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
g_array_append_val (all_root_children_stacked, stack_id);
|
||||||
|
}
|
||||||
|
|
||||||
|
meta_topic (META_DEBUG_STACK, "\n");
|
||||||
|
meta_pop_no_msg_prefix ();
|
||||||
|
|
||||||
|
/* The screen guard window sits above all hidden windows and acts as
|
||||||
|
* a barrier to input reaching these windows. */
|
||||||
|
guard_window_id = x11_stack->x11_display->guard_window;
|
||||||
|
g_array_append_val (hidden_stack_ids, guard_window_id);
|
||||||
|
|
||||||
|
/* Sync to server */
|
||||||
|
|
||||||
|
meta_topic (META_DEBUG_STACK, "Restacking %u windows\n",
|
||||||
|
all_root_children_stacked->len);
|
||||||
|
|
||||||
|
meta_stack_tracker_restack_managed (x11_display->display->stack_tracker,
|
||||||
|
(guint64 *)all_root_children_stacked->data,
|
||||||
|
all_root_children_stacked->len);
|
||||||
|
meta_stack_tracker_restack_at_bottom (x11_display->display->stack_tracker,
|
||||||
|
(guint64 *)hidden_stack_ids->data,
|
||||||
|
hidden_stack_ids->len);
|
||||||
|
|
||||||
|
/* Sync _NET_CLIENT_LIST and _NET_CLIENT_LIST_STACKING */
|
||||||
|
|
||||||
|
XChangeProperty (x11_stack->x11_display->xdisplay,
|
||||||
|
x11_stack->x11_display->xroot,
|
||||||
|
x11_stack->x11_display->atom__NET_CLIENT_LIST,
|
||||||
|
XA_WINDOW,
|
||||||
|
32, PropModeReplace,
|
||||||
|
(unsigned char *) x11_stack->xwindows->data,
|
||||||
|
x11_stack->xwindows->len);
|
||||||
|
XChangeProperty (x11_stack->x11_display->xdisplay,
|
||||||
|
x11_stack->x11_display->xroot,
|
||||||
|
x11_stack->x11_display->atom__NET_CLIENT_LIST_STACKING,
|
||||||
|
XA_WINDOW,
|
||||||
|
32, PropModeReplace,
|
||||||
|
(unsigned char *) x11_stacked->data,
|
||||||
|
x11_stacked->len);
|
||||||
|
|
||||||
|
g_array_free (x11_stacked, TRUE);
|
||||||
|
g_array_free (hidden_stack_ids, TRUE);
|
||||||
|
g_array_free (all_root_children_stacked, TRUE);
|
||||||
|
g_list_free (sorted);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
stack_changed_cb (MetaX11Stack *x11_stack)
|
||||||
|
{
|
||||||
|
/* Do removals before adds, with paranoid idea that we might re-add
|
||||||
|
* the same window IDs.
|
||||||
|
*/
|
||||||
|
x11_stack_do_window_deletions (x11_stack);
|
||||||
|
x11_stack_do_window_additions (x11_stack);
|
||||||
|
x11_stack_sync_to_xserver (x11_stack);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
meta_x11_stack_constructed (GObject *object)
|
||||||
|
{
|
||||||
|
MetaX11Stack *x11_stack = META_X11_STACK (object);
|
||||||
|
MetaX11Display *x11_display = x11_stack->x11_display;
|
||||||
|
|
||||||
|
G_OBJECT_CLASS (meta_x11_stack_parent_class)->constructed (object);
|
||||||
|
|
||||||
|
g_signal_connect (x11_display->display->stack,
|
||||||
|
"window-added",
|
||||||
|
G_CALLBACK (stack_window_added_cb),
|
||||||
|
x11_stack);
|
||||||
|
g_signal_connect (x11_display->display->stack,
|
||||||
|
"window-removed",
|
||||||
|
G_CALLBACK (stack_window_removed_cb),
|
||||||
|
x11_stack);
|
||||||
|
g_signal_connect_swapped (x11_display->display->stack,
|
||||||
|
"changed",
|
||||||
|
G_CALLBACK (stack_changed_cb),
|
||||||
|
x11_stack);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
meta_x11_stack_finalize (GObject *object)
|
||||||
|
{
|
||||||
|
MetaX11Stack *x11_stack = META_X11_STACK (object);
|
||||||
|
MetaX11Display *x11_display = x11_stack->x11_display;
|
||||||
|
|
||||||
|
if (x11_display->display && x11_display->display->stack)
|
||||||
|
{
|
||||||
|
g_signal_handlers_disconnect_by_data (x11_display->display->stack,
|
||||||
|
x11_stack);
|
||||||
|
}
|
||||||
|
|
||||||
|
g_array_free (x11_stack->xwindows, TRUE);
|
||||||
|
g_list_free (x11_stack->added);
|
||||||
|
g_list_free (x11_stack->removed);
|
||||||
|
|
||||||
|
G_OBJECT_CLASS (meta_x11_stack_parent_class)->finalize (object);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
meta_x11_stack_class_init (MetaX11StackClass *klass)
|
||||||
|
{
|
||||||
|
GObjectClass *object_class = G_OBJECT_CLASS (klass);
|
||||||
|
|
||||||
|
object_class->set_property = meta_x11_stack_set_property;
|
||||||
|
object_class->get_property = meta_x11_stack_get_property;
|
||||||
|
object_class->constructed = meta_x11_stack_constructed;
|
||||||
|
object_class->finalize = meta_x11_stack_finalize;
|
||||||
|
|
||||||
|
pspecs[PROP_DISPLAY] =
|
||||||
|
g_param_spec_object ("display",
|
||||||
|
"Display",
|
||||||
|
"Display",
|
||||||
|
META_TYPE_X11_DISPLAY,
|
||||||
|
G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY);
|
||||||
|
|
||||||
|
g_object_class_install_properties (object_class, N_PROPS, pspecs);
|
||||||
|
}
|
||||||
|
|
||||||
|
MetaX11Stack *
|
||||||
|
meta_x11_stack_new (MetaX11Display *x11_display)
|
||||||
|
{
|
||||||
|
return g_object_new (META_TYPE_X11_STACK,
|
||||||
|
"display", x11_display,
|
||||||
|
NULL);
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user