Compare commits

...

24 Commits

Author SHA1 Message Date
Carlos Garnacho
835a97a66c core: Ensure passive key grabs are only set up on X11
We don't strictly need it for wayland compositors, yet there are
paths where we try to trigger those passive grabs there. Just
skip those on the high level code (where "is it x11" decisions
are taken) like we do with passive button grabs.
2019-05-24 19:40:07 +02:00
Carlos Garnacho
9367cd2d66 core: Shuffle wayland checks on passive button grabs
We used to bail out at the very bottom of it, but it seems better to
do that at a higher level so that we don't have to pass "invalid"
X11 data as arguments (e.g. None for windows, etc)
2019-05-24 19:30:34 +02:00
Carlos Garnacho
b1ea768949 wayland: Drop -terminate argument to Xwayland
This argument instructs Xwayland to exit when there are no further
client connections. However we eventually want to handle restarts
ourselves (where, notably, mutter's will be at least the last client
connection).

This behavior could also induce race conditions on startup with clients
that quickly open and close a display, which is a more pressing issue.

Also, add -noreset back (which was also removed in commit 054c25f693 that
added -terminate). We don't want to reset the X server to a pristine state
in that situation either.

https://gitlab.gnome.org/GNOME/mutter/merge_requests/420
2019-05-24 15:30:31 +00:00
Carlos Garnacho
ea9d8a895b wayland: Drop error trap
Code underneath seems to handle errors properly, or be x11-agnostic
entirely, this is apparently here to save a few XSync()s on X11. Just
drop this windowing dependent bit to make things cleaner.

https://gitlab.gnome.org/GNOME/mutter/merge_requests/420
2019-05-24 15:30:31 +00:00
Carlos Garnacho
38432da328 compositor: Drop error trap
Code underneath seems to handle errors properly, and this is apparently
here to save a few XSync()s on X11. Just drop this windowing dependent
bit to make things cleaner.

https://gitlab.gnome.org/GNOME/mutter/merge_requests/420
2019-05-24 15:30:31 +00:00
Carlos Garnacho
430f354cd9 wayland: Split Xwayland initialization in 2 steps
It is now separated into meta_xwayland_start(), which picks an unused
display and sets up the sockets, and meta_xwayland_init_xserver(), which
does the actual exec of Xwayland and MetaX11Display initialization.

This differentiation will be useful when Mutter is able to launch Xwayland
lazily, currently the former calls into the latter.

https://gitlab.gnome.org/GNOME/mutter/merge_requests/420
2019-05-24 15:30:31 +00:00
Carlos Garnacho
1cf4279745 x11: Initialize GdkDisplay together with MetaX11Display
It's no longer a "singleton", since it might be closed and opened again.

https://gitlab.gnome.org/GNOME/mutter/merge_requests/420
2019-05-24 15:30:31 +00:00
Carlos Garnacho
7713006f5b x11: Unmanage X11 windows on MetaX11Display finalization
This used to be relied upon meta_display_close(), but MetaDisplay
and MetaX11Display lifetimes may be unrelated.

https://gitlab.gnome.org/GNOME/mutter/merge_requests/420
2019-05-24 15:30:31 +00:00
Carlos Garnacho
465e13128b core: Add explicit init/shutdown_x11() MetaDisplay calls
The lifetime of MetaX11Display is still tied to MetaDisplay, but these
calls will be useful when it's actually affordable to decouple those.

https://gitlab.gnome.org/GNOME/mutter/merge_requests/420
2019-05-24 15:30:31 +00:00
Carlos Garnacho
86de79cfc5 core: Untangle input focus management
In all places (including src/wayland) we tap into meta_x11_display* focus
API, which then calls meta_display* API. This relation is backwards, so
rework input focus management so it's the other way around.

We now have high-level meta_display_(un)set_input_focus functions, which
perform the backend-independent maintenance, and calls into the X11
functions where relevant. These functions are what callers should use.

https://gitlab.gnome.org/GNOME/mutter/merge_requests/420
2019-05-24 15:30:31 +00:00
Carlos Garnacho
1d77641f0b x11: Separate X11 focus handling into MetaX11Display method
Updating the MetaWindow focus and the X Window focus is interrelated but
independent. Call one after the other in the places we handle window focus
changes.

https://gitlab.gnome.org/GNOME/mutter/merge_requests/420
2019-05-24 15:30:31 +00:00
Carlos Garnacho
2f217109aa core: Relax requirement that MetaWindow shall have icon/mini-icon
We use a GtkIconTheme (thus icon-theme, thus xsettings, thus x11) just to
grab a "missing icon" icon to show in place. Relax this requirement that
surfaces for icon/mini-icon will be set, and just let it have NULL here.

It seems better to have the callers (presumably UI layers) aware of this
and set a proper icon by themselves, but AFAICS there is none in sight,
not even plain mutter seems to use MetaWindow::[mini-]icon. Probably
worth a future cleanup.

https://gitlab.gnome.org/GNOME/mutter/merge_requests/420
2019-05-24 15:30:31 +00:00
Carlos Garnacho
5e0523cc8b x11: Move X11 calls to map/unmap a MetaWindow to MetaWindowX11
Add 2 vmethods so that MetaWindowX11 may handle the X11 calls itself.

https://gitlab.gnome.org/GNOME/mutter/merge_requests/420
2019-05-24 15:30:31 +00:00
Carlos Garnacho
dbe6e01e12 core: Separate checks for pointer barriers availability
If the check happens on --nested (X11 backend) while there is no X11
display we would get a crash. Since the barriers are non-effective on
nested, just take it out into a separate condition.

https://gitlab.gnome.org/GNOME/mutter/merge_requests/420
2019-05-24 15:30:31 +00:00
Carlos Garnacho
103c469cc9 core: Avoid grab transfer shenanigans with non-X11 backend
This explicit ungrab is made to ensure the other X11 display connection
is able to start an active grab immediately on the device without receiving
AlreadyGrabbed.

This is just relevant if there's two X11 display connections to transfer
grabs across, which may just happen on X11 windowing.

https://gitlab.gnome.org/GNOME/mutter/merge_requests/420
2019-05-24 15:30:31 +00:00
Carlos Garnacho
ef074ea510 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
2019-05-24 15:30:31 +00:00
Carlos Garnacho
39bac6eabd core: Turn MetaStack into a GObject
So we can have it emit signals and whatnot. Those are unused, yet.

https://gitlab.gnome.org/GNOME/mutter/merge_requests/420
2019-05-24 15:30:30 +00:00
Carlos Garnacho
0200f4fcd9 x11: Move focus sentinel to MetaX11Display
This focus sentinel is a mechanism to avoid some X11-specific race
conditions in focus-follows-pointer, using X11 mechanisms. Move it to
MetaX11Display altogether.

https://gitlab.gnome.org/GNOME/mutter/merge_requests/420
2019-05-24 15:30:30 +00:00
Jonas Ådahl
439afb3f19 window: Move all attached windows with parent
We'd break the loop for moving attached windows at the first window,
meaning we'd only ever move a single attached dialogs or popup if it was
the first window in the list. This doesn't work out well when there are
multiple popups open, so don't break out of the loop at all until all
windows are potentially moved.

This fixes an issue in gtk4 where one or more non-grabbing popups would
end up unattached if there were more than one and the parent window was
moved.

https://gitlab.gnome.org/GNOME/mutter/merge_requests/592
2019-05-24 15:07:03 +00:00
Carlos Garnacho
b01edc22f3 backends/x11: Do not reload keymap on new keyboard notifications
XkbNewKeyboardNotify informs the client that there is a new keyboard
driving the VCK. It is essentially meant to notify that the keyboard
possibly has a different range of HW keycodes and/or a different
geometry.

But the translation of those keycodes remain the same, and we don't
do range checks or geometry checks (beyond using KEY_GRAVE as "key
under Esc", but that is hardly one). It seems we can avoid the
busywork that is releasing all our passive grabs, reloading the keymap
and regenerating the keycombos and restoring the passive grabs.

Closes: https://gitlab.gnome.org/GNOME/mutter/issues/398
2019-05-24 11:28:07 +02:00
Jonas Ådahl
e8bca5052a ci: Make MALLOC_PERTURB_ less random
The point is to not initialize to some non-zero value to find places
incorrectly relying on blocks being zero initialized. Thus, there is no
reason to have a different random number each time, and by having it the
same, we have slightly more reproducable triggers, would we ever trigger
anything due to this.

https://gitlab.gnome.org/GNOME/mutter/merge_requests/591
2019-05-24 10:57:46 +02:00
Jonas Ådahl
468882ecec ci: Run dconf update before running tests
Otherwise tests will fail due to the following warning:

(mutter-test-runner:3700): dconf-WARNING **: 06:39:42.124: unable to
open file '/etc/dconf/db/local': Failed to open file
“/etc/dconf/db/local”: open() failed: No such file or directory; expect
degraded performance

https://gitlab.gnome.org/GNOME/mutter/merge_requests/591
2019-05-24 09:23:22 +02:00
Florian Müllner
be3c89d823 Bump version to 3.33.2
Update NEWS.
2019-05-22 18:15:34 +00:00
Vasilis Liaskovitis
7719e33e68 wayland/pointer-constraints: Reject invalid lifetime
https://gitlab.gnome.org/GNOME/mutter/issues/425
2019-05-22 15:06:14 +00:00
27 changed files with 1000 additions and 673 deletions

View File

@@ -37,11 +37,12 @@ test-mutter:
GSETTINGS_SCHEMA_DIR: "$CI_PROJECT_DIR/build/data"
MALLOC_CHECK_: "3"
NO_AT_BRIDGE: "1"
MALLOC_PERTURB_: "123"
script:
- dconf update
- mkdir -m 700 $XDG_RUNTIME_DIR
- glib-compile-schemas $GSETTINGS_SCHEMA_DIR
- >
env MALLOC_PERTURB_="$((RANDOM % 256 + 1))"
dbus-run-session -- xvfb-run -s '+iglx -noreset'
meson test -C build --no-rebuild -t 10 --verbose --no-stdsplit --wrap catchsegv
only:

15
NEWS
View File

@@ -1,3 +1,18 @@
3.33.2
======
* Fix rendering lag on Xorg [Daniel; !520, !281]
* Misc. bug fixes and cleanups [Carlos, Marco, Jonas D., Florian, Niels,
Daniel, Benjamin, Jonas Å., Ignacio, Vasilis; #598, !576, !547, !578,
!583, !582, !469, !524, !119, !571, !584, !585, !586, #425]
Contributors:
Jonas Ådahl, Benjamin Berg, Jonas Dreßler, Carlos Garnacho, Niels De Graef,
Vasilis Liaskovitis, Florian Müllner, Ignacio Casal Quinteiro,
Marco Trevisan (Treviño), Daniel van Vugt
Translators:
Daniel Mustieles [es]
3.33.1
======
* Remove unused APIs and outdated driver support

View File

@@ -1,5 +1,5 @@
project('mutter', 'c',
version: '3.33.1',
version: '3.33.2',
meson_version: '>= 0.50.0',
license: 'GPLv2+'
)

View File

@@ -357,7 +357,6 @@ handle_host_xevent (MetaBackend *backend,
{
switch (xkb_ev->any.xkb_type)
{
case XkbNewKeyboardNotify:
case XkbMapNotify:
keymap_changed (backend);
break;

View File

@@ -692,11 +692,8 @@ meta_compositor_add_window (MetaCompositor *compositor,
{
MetaWindowActor *window_actor;
ClutterActor *window_group;
MetaDisplay *display = compositor->display;
GType window_actor_type = G_TYPE_INVALID;
meta_x11_error_trap_push (display->x11_display);
switch (window->client_type)
{
case META_WINDOW_CLIENT_TYPE_X11:
@@ -724,8 +721,6 @@ meta_compositor_add_window (MetaCompositor *compositor,
*/
compositor->windows = g_list_append (compositor->windows, window_actor);
sync_actor_stacking (compositor);
meta_x11_error_trap_pop (display->x11_display);
}
void

View File

@@ -140,14 +140,6 @@ struct _MetaDisplay
*/
guint allow_terminal_deactivation : 1;
/* If true, server->focus_serial refers to us changing the focus; in
* this case, we can ignore focus events that have exactly focus_serial,
* since we take care to make another request immediately afterwards.
* But if focus is being changed by another client, we have to accept
* multiple events with the same serial.
*/
guint focused_by_us : 1;
/*< private-ish >*/
GHashTable *stamps;
GHashTable *wayland_windows;
@@ -203,10 +195,6 @@ struct _MetaDisplay
MetaEdgeResistanceData *grab_edge_resistance_data;
unsigned int grab_last_user_action_was_snap;
/* we use property updates as sentinels for certain window focus events
* to avoid some race conditions on EnterNotify events
*/
int sentinel_counter;
int grab_resize_timeout_id;
MetaKeyBindingManager key_binding_manager;
@@ -363,10 +351,6 @@ gboolean meta_grab_op_is_resizing (MetaGrabOp op);
gboolean meta_grab_op_is_mouse (MetaGrabOp op);
gboolean meta_grab_op_is_keyboard (MetaGrabOp op);
void meta_display_increment_focus_sentinel (MetaDisplay *display);
void meta_display_decrement_focus_sentinel (MetaDisplay *display);
gboolean meta_display_focus_sentinel_clear (MetaDisplay *display);
void meta_display_queue_autoraise_callback (MetaDisplay *display,
MetaWindow *window);
void meta_display_remove_autoraise_callback (MetaDisplay *display);
@@ -379,10 +363,7 @@ gboolean meta_display_modifiers_accelerator_activate (MetaDisplay *display);
void meta_display_sync_wayland_input_focus (MetaDisplay *display);
void meta_display_update_focus_window (MetaDisplay *display,
MetaWindow *window,
Window xwindow,
gulong serial,
gboolean focused_by_us);
MetaWindow *window);
void meta_display_sanity_check_timestamps (MetaDisplay *display,
guint32 timestamp);
@@ -446,4 +427,8 @@ MetaWindow *meta_display_get_window_from_id (MetaDisplay *display,
uint64_t window_id);
uint64_t meta_display_generate_window_id (MetaDisplay *display);
gboolean meta_display_init_x11 (MetaDisplay *display,
GError **error);
void meta_display_shutdown_x11 (MetaDisplay *display);
#endif

View File

@@ -49,6 +49,7 @@
#include "backends/meta-logical-monitor.h"
#include "backends/meta-stage-private.h"
#include "backends/x11/meta-backend-x11.h"
#include "backends/x11/cm/meta-backend-x11-cm.h"
#include "clutter/x11/clutter-x11.h"
#include "core/bell.h"
#include "core/boxes-private.h"
@@ -630,6 +631,39 @@ on_ui_scaling_factor_changed (MetaSettings *settings,
meta_display_reload_cursor (display);
}
gboolean
meta_display_init_x11 (MetaDisplay *display,
GError **error)
{
MetaX11Display *x11_display;
g_assert (display->x11_display == NULL);
x11_display = meta_x11_display_new (display, error);
if (!x11_display)
return FALSE;
display->x11_display = x11_display;
g_signal_emit (display, display_signals[X11_DISPLAY_OPENED], 0);
meta_x11_display_create_guard_window (x11_display);
if (!display->display_opening)
meta_display_manage_all_windows (display);
return TRUE;
}
void
meta_display_shutdown_x11 (MetaDisplay *display)
{
if (!display->x11_display)
return;
g_signal_emit (display, display_signals[X11_DISPLAY_CLOSING], 0);
g_object_run_dispose (G_OBJECT (display->x11_display));
g_clear_object (&display->x11_display);
}
/**
* meta_display_open:
*
@@ -645,7 +679,6 @@ meta_display_open (void)
{
GError *error = NULL;
MetaDisplay *display;
MetaX11Display *x11_display;
int i;
guint32 timestamp;
Window old_active_xwindow = None;
@@ -683,7 +716,6 @@ meta_display_open (void)
}
display->current_time = META_CURRENT_TIME;
display->sentinel_counter = 0;
display->grab_resize_timeout_id = 0;
display->grab_have_keyboard = FALSE;
@@ -730,10 +762,8 @@ meta_display_open (void)
if (meta_should_autostart_x11_display ())
{
x11_display = meta_x11_display_new (display, &error);
g_assert (x11_display != NULL); /* Required, for now */
display->x11_display = x11_display;
g_signal_emit (display, display_signals[X11_DISPLAY_OPENED], 0);
if (!meta_display_init_x11 (display, &error))
g_error ("Failed to start Xwayland: %s", error->message);
timestamp = display->x11_display->timestamp;
}
@@ -779,10 +809,12 @@ meta_display_open (void)
if (old_active_window)
meta_window_focus (old_active_window, timestamp);
else
meta_x11_display_focus_the_no_focus_window (display->x11_display, timestamp);
meta_display_unset_input_focus (display, timestamp);
}
else
{
meta_display_unset_input_focus (display, timestamp);
}
else if (display->x11_display)
meta_x11_display_focus_the_no_focus_window (display->x11_display, timestamp);
meta_idle_monitor_init_dbus ();
@@ -924,7 +956,7 @@ meta_display_close (MetaDisplay *display,
g_clear_object (&display->gesture_tracker);
g_clear_pointer (&display->stack, meta_stack_free);
g_clear_object (&display->stack);
g_clear_pointer (&display->stack_tracker,
meta_stack_tracker_free);
@@ -953,12 +985,7 @@ meta_display_close (MetaDisplay *display,
if (display->compositor)
meta_compositor_destroy (display->compositor);
if (display->x11_display)
{
g_signal_emit (display, display_signals[X11_DISPLAY_CLOSING], 0);
g_object_run_dispose (G_OBJECT (display->x11_display));
g_clear_object (&display->x11_display);
}
meta_display_shutdown_x11 (display);
meta_display_shutdown_keys (display);
@@ -1238,16 +1265,9 @@ meta_display_sync_wayland_input_focus (MetaDisplay *display)
void
meta_display_update_focus_window (MetaDisplay *display,
MetaWindow *window,
Window xwindow,
gulong serial,
gboolean focused_by_us)
MetaWindow *window)
{
display->x11_display->focus_serial = serial;
display->focused_by_us = focused_by_us;
if (display->x11_display->focus_xwindow == xwindow &&
display->focus_window == window)
if (display->focus_window == window)
return;
if (display->focus_window)
@@ -1264,28 +1284,25 @@ meta_display_update_focus_window (MetaDisplay *display,
*/
previous = display->focus_window;
display->focus_window = NULL;
display->x11_display->focus_xwindow = None;
meta_window_set_focused_internal (previous, FALSE);
}
display->focus_window = window;
display->x11_display->focus_xwindow = xwindow;
if (display->focus_window)
{
meta_topic (META_DEBUG_FOCUS, "* Focus --> %s with serial %lu\n",
display->focus_window->desc, serial);
meta_topic (META_DEBUG_FOCUS, "* Focus --> %s\n",
display->focus_window->desc);
meta_window_set_focused_internal (display->focus_window, TRUE);
}
else
meta_topic (META_DEBUG_FOCUS, "* Focus --> NULL with serial %lu\n", serial);
meta_topic (META_DEBUG_FOCUS, "* Focus --> NULL\n");
if (meta_is_wayland_compositor ())
meta_display_sync_wayland_input_focus (display);
g_object_notify (G_OBJECT (display), "focus-window");
meta_x11_display_update_active_window_hint (display->x11_display);
}
gboolean
@@ -1317,6 +1334,51 @@ meta_display_timestamp_too_old (MetaDisplay *display,
return FALSE;
}
void
meta_display_set_input_focus (MetaDisplay *display,
MetaWindow *window,
gboolean focus_frame,
guint32 timestamp)
{
if (meta_display_timestamp_too_old (display, &timestamp))
return;
if (display->x11_display)
{
MetaX11Display *x11_display = display->x11_display;
Window xwindow;
gulong serial;
meta_x11_error_trap_push (x11_display);
if (window)
xwindow = focus_frame ? window->frame->xwindow : window->xwindow;
else
xwindow = x11_display->no_focus_window;
meta_x11_display_set_input_focus (x11_display, xwindow, timestamp);
serial = XNextRequest (x11_display->xdisplay);
meta_x11_display_update_focus_window (x11_display, xwindow, serial, TRUE);
meta_x11_error_trap_pop (display->x11_display);
}
meta_display_update_focus_window (display, window);
display->last_focus_time = timestamp;
if (window == NULL || window != display->autoraise_window)
meta_display_remove_autoraise_callback (display);
}
void
meta_display_unset_input_focus (MetaDisplay *display,
guint32 timestamp)
{
meta_display_set_input_focus (display, NULL, FALSE, timestamp);
}
void
meta_display_register_wayland_window (MetaDisplay *display,
MetaWindow *window)
@@ -1678,14 +1740,17 @@ meta_display_begin_grab_op (MetaDisplay *display,
if (pointer_already_grabbed)
display->grab_have_pointer = TRUE;
/* Since grab operations often happen as a result of implicit
* pointer operations on the display X11 connection, we need
* to ungrab here to ensure that the backend's X11 can take
* the device grab. */
XIUngrabDevice (display->x11_display->xdisplay,
META_VIRTUAL_CORE_POINTER_ID,
timestamp);
XSync (display->x11_display->xdisplay, False);
if (META_IS_BACKEND_X11 (meta_get_backend ()) && display->x11_display)
{
/* Since grab operations often happen as a result of implicit
* pointer operations on the display X11 connection, we need
* to ungrab here to ensure that the backend's X11 can take
* the device grab. */
XIUngrabDevice (display->x11_display->xdisplay,
META_VIRTUAL_CORE_POINTER_ID,
timestamp);
XSync (display->x11_display->xdisplay, False);
}
if (meta_backend_grab_device (backend, META_VIRTUAL_CORE_POINTER_ID, timestamp))
display->grab_have_pointer = TRUE;
@@ -2490,37 +2555,6 @@ prefs_changed_callback (MetaPreference pref,
}
}
void
meta_display_increment_focus_sentinel (MetaDisplay *display)
{
unsigned long data[1];
data[0] = meta_display_get_current_time (display);
XChangeProperty (display->x11_display->xdisplay,
display->x11_display->xroot,
display->x11_display->atom__MUTTER_SENTINEL,
XA_CARDINAL,
32, PropModeReplace, (guchar*) data, 1);
display->sentinel_counter += 1;
}
void
meta_display_decrement_focus_sentinel (MetaDisplay *display)
{
display->sentinel_counter -= 1;
if (display->sentinel_counter < 0)
display->sentinel_counter = 0;
}
gboolean
meta_display_focus_sentinel_clear (MetaDisplay *display)
{
return (display->sentinel_counter == 0);
}
void
meta_display_sanity_check_timestamps (MetaDisplay *display,
guint32 timestamp)
@@ -2626,13 +2660,14 @@ meta_display_supports_extended_barriers (MetaDisplay *display)
return TRUE;
#endif
if (META_IS_BACKEND_X11 (meta_get_backend ()))
if (META_IS_BACKEND_X11_CM (meta_get_backend ()))
{
return (META_X11_DISPLAY_HAS_XINPUT_23 (display->x11_display) &&
!meta_is_wayland_compositor());
if (meta_is_wayland_compositor())
return FALSE;
return META_X11_DISPLAY_HAS_XINPUT_23 (display->x11_display);
}
g_assert_not_reached ();
return FALSE;
}

View File

@@ -1171,9 +1171,6 @@ meta_change_button_grab (MetaKeyBindingManager *keys,
int button,
int modmask)
{
if (meta_is_wayland_compositor ())
return;
MetaBackendX11 *backend = META_BACKEND_X11 (keys->backend);
Display *xdisplay = meta_backend_x11_get_xdisplay (backend);
@@ -1300,12 +1297,8 @@ meta_display_grab_focus_window_button (MetaDisplay *display,
return;
}
/* FIXME If we ignored errors here instead of spewing, we could
* put one big error trap around the loop and avoid a bunch of
* XSync()
*/
meta_change_buttons_grab (keys, window->xwindow, TRUE, TRUE, XIAnyModifier);
if (window->xwindow && !meta_is_wayland_compositor ())
meta_change_buttons_grab (keys, window->xwindow, TRUE, TRUE, XIAnyModifier);
window->have_focus_click_grab = TRUE;
}
@@ -1320,7 +1313,8 @@ meta_display_ungrab_focus_window_button (MetaDisplay *display,
if (!window->have_focus_click_grab)
return;
meta_change_buttons_grab (keys, window->xwindow, FALSE, FALSE, XIAnyModifier);
if (window->xwindow && !meta_is_wayland_compositor ())
meta_change_buttons_grab (keys, window->xwindow, FALSE, FALSE, XIAnyModifier);
window->have_focus_click_grab = FALSE;
}
@@ -1348,7 +1342,8 @@ prefs_changed_callback (MetaPreference pref,
for (l = windows; l; l = l->next)
{
MetaWindow *w = l->data;
meta_display_ungrab_window_buttons (display, w->xwindow);
if (!meta_is_wayland_compositor ())
meta_display_ungrab_window_buttons (display, w->xwindow);
}
update_window_grab_modifiers (keys);
@@ -1356,7 +1351,7 @@ prefs_changed_callback (MetaPreference pref,
for (l = windows; l; l = l->next)
{
MetaWindow *w = l->data;
if (w->type != META_WINDOW_DOCK)
if (!meta_is_wayland_compositor () && w->type != META_WINDOW_DOCK)
meta_display_grab_window_buttons (display, w->xwindow);
}
@@ -1531,6 +1526,8 @@ meta_window_grab_keys (MetaWindow *window)
MetaDisplay *display = window->display;
MetaKeyBindingManager *keys = &display->key_binding_manager;
if (!meta_is_wayland_compositor ())
return;
if (window->all_keys_grabbed)
return;
@@ -1565,7 +1562,7 @@ meta_window_grab_keys (MetaWindow *window)
void
meta_window_ungrab_keys (MetaWindow *window)
{
if (window->keys_grabbed)
if (!meta_is_wayland_compositor () && window->keys_grabbed)
{
MetaDisplay *display = window->display;
MetaKeyBindingManager *keys = &display->key_binding_manager;
@@ -1624,7 +1621,11 @@ meta_display_grab_accelerator (MetaDisplay *display,
return META_KEYBINDING_ACTION_NONE;
}
meta_change_keygrab (keys, display->x11_display->xroot, TRUE, &resolved_combo);
if (!meta_is_wayland_compositor ())
{
meta_change_keygrab (keys, display->x11_display->xroot,
TRUE, &resolved_combo);
}
grab = g_new0 (MetaKeyGrab, 1);
grab->action = next_dynamic_keybinding_action ();
@@ -1670,8 +1671,11 @@ meta_display_ungrab_accelerator (MetaDisplay *display,
{
int i;
meta_change_keygrab (keys, display->x11_display->xroot,
FALSE, &binding->resolved_combo);
if (!meta_is_wayland_compositor ())
{
meta_change_keygrab (keys, display->x11_display->xroot,
FALSE, &binding->resolved_combo);
}
for (i = 0; i < binding->resolved_combo.len; i++)
{
@@ -1749,7 +1753,7 @@ meta_window_grab_all_keys (MetaWindow *window,
guint32 timestamp)
{
Window grabwindow;
gboolean retval;
gboolean retval = TRUE;
if (window->all_keys_grabbed)
return FALSE;
@@ -1765,25 +1769,29 @@ meta_window_grab_all_keys (MetaWindow *window,
window->desc);
meta_window_focus (window, timestamp);
grabwindow = meta_window_x11_get_toplevel_xwindow (window);
meta_topic (META_DEBUG_KEYBINDINGS,
"Grabbing all keys on window %s\n", window->desc);
retval = grab_keyboard (grabwindow, timestamp, XIGrabModeAsync);
if (retval)
if (!meta_is_wayland_compositor ())
{
window->keys_grabbed = FALSE;
window->all_keys_grabbed = TRUE;
window->grab_on_frame = window->frame != NULL;
grabwindow = meta_window_x11_get_toplevel_xwindow (window);
meta_topic (META_DEBUG_KEYBINDINGS,
"Grabbing all keys on window %s\n", window->desc);
retval = grab_keyboard (grabwindow, timestamp, XIGrabModeAsync);
if (retval)
{
window->keys_grabbed = FALSE;
window->all_keys_grabbed = TRUE;
window->grab_on_frame = window->frame != NULL;
}
}
return retval;
}
void
meta_window_ungrab_all_keys (MetaWindow *window, guint32 timestamp)
meta_window_ungrab_all_keys (MetaWindow *window,
guint32 timestamp)
{
if (window->all_keys_grabbed)
if (!meta_is_wayland_compositor () && window->all_keys_grabbed)
{
ungrab_keyboard (timestamp);

View File

@@ -606,22 +606,6 @@ meta_init (void)
meta_fatal ("Can't specify both SM save file and SM client id\n");
meta_main_loop = g_main_loop_new (NULL, FALSE);
/*
* We need to make sure the first client connecting to the X server
* (e.g. Xwayland started from meta_wayland_init() above) is a permanent one,
* so prepare the GDK X11 connection now already. Without doing this, if
* there are any functionality that relies on X11 after here before
* meta_display_open(), the X server will terminate itself when such a client
* disconnects before the permanent GDK client connects.
*/
if (meta_should_autostart_x11_display ())
{
GError *error = NULL;
if (!meta_x11_init_gdk_display (&error))
g_error ("Failed to open X11 display: %s", error->message);
}
}
/**

View File

@@ -29,18 +29,13 @@
#include "core/stack.h"
#include <X11/Xatom.h>
#include "backends/meta-logical-monitor.h"
#include "core/frame.h"
#include "core/meta-workspace-manager-private.h"
#include "core/window-private.h"
#include "meta/group.h"
#include "meta/meta-x11-errors.h"
#include "meta/prefs.h"
#include "meta/workspace.h"
#include "x11/group-private.h"
#include "x11/meta-x11-display-private.h"
#define WINDOW_HAS_TRANSIENT_TYPE(w) \
(w->type == META_WINDOW_DIALOG || \
@@ -52,51 +47,141 @@
#define WINDOW_TRANSIENT_FOR_WHOLE_GROUP(w) \
(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,
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_constrain (MetaStack *stack);
static void stack_do_resort (MetaStack *stack);
static void stack_ensure_sorted (MetaStack *stack);
enum
{
PROP_DISPLAY = 1,
N_PROPS
};
enum
{
CHANGED,
WINDOW_ADDED,
WINDOW_REMOVED,
N_SIGNALS
};
static GParamSpec *pspecs[N_PROPS] = { 0 };
static guint signals[N_SIGNALS] = { 0 };
G_DEFINE_TYPE (MetaStack, meta_stack, G_TYPE_OBJECT)
static void
meta_stack_init (MetaStack *stack)
{
}
static void
meta_stack_finalize (GObject *object)
{
MetaStack *stack = META_STACK (object);
g_list_free (stack->sorted);
G_OBJECT_CLASS (meta_stack_parent_class)->finalize (object);
}
static void
meta_stack_set_property (GObject *object,
guint prop_id,
const GValue *value,
GParamSpec *pspec)
{
MetaStack *stack = META_STACK (object);
switch (prop_id)
{
case PROP_DISPLAY:
stack->display = g_value_get_object (value);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
}
}
static void
meta_stack_get_property (GObject *object,
guint prop_id,
GValue *value,
GParamSpec *pspec)
{
MetaStack *stack = META_STACK (object);
switch (prop_id)
{
case PROP_DISPLAY:
g_value_set_object (value, stack->display);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
}
}
static void
meta_stack_class_init (MetaStackClass *klass)
{
GObjectClass *object_class = G_OBJECT_CLASS (klass);
object_class->set_property = meta_stack_set_property;
object_class->get_property = meta_stack_get_property;
object_class->finalize = meta_stack_finalize;
signals[CHANGED] =
g_signal_new ("changed",
G_TYPE_FROM_CLASS (klass),
G_SIGNAL_RUN_LAST,
0, NULL, NULL, NULL,
G_TYPE_NONE, 0);
signals[WINDOW_ADDED] =
g_signal_new ("window-added",
G_TYPE_FROM_CLASS (klass),
G_SIGNAL_RUN_LAST,
0, NULL, NULL,
g_cclosure_marshal_VOID__OBJECT,
G_TYPE_NONE, 1, META_TYPE_WINDOW);
signals[WINDOW_REMOVED] =
g_signal_new ("window-removed",
G_TYPE_FROM_CLASS (klass),
G_SIGNAL_RUN_LAST,
0, NULL, NULL,
g_cclosure_marshal_VOID__OBJECT,
G_TYPE_NONE, 1, META_TYPE_WINDOW);
pspecs[PROP_DISPLAY] =
g_param_spec_object ("display",
"Display",
"Display",
META_TYPE_DISPLAY,
G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY);
g_object_class_install_properties (object_class, N_PROPS, pspecs);
}
MetaStack *
meta_stack_new (MetaDisplay *display)
{
MetaStack *stack;
stack = g_new (MetaStack, 1);
stack->display = display;
stack->xwindows = g_array_new (FALSE, FALSE, sizeof (Window));
stack->sorted = NULL;
stack->added = NULL;
stack->removed = NULL;
stack->freeze_count = 0;
stack->n_positions = 0;
stack->need_resort = FALSE;
stack->need_relayer = FALSE;
stack->need_constrain = FALSE;
return stack;
return g_object_new (META_TYPE_STACK,
"display", display,
NULL);
}
void
meta_stack_free (MetaStack *stack)
static void
meta_stack_changed (MetaStack *stack)
{
g_array_free (stack->xwindows, TRUE);
/* Bail out if frozen */
if (stack->freeze_count > 0)
return;
g_list_free (stack->sorted);
g_list_free (stack->added);
g_list_free (stack->removed);
g_free (stack);
stack_ensure_sorted (stack);
g_signal_emit (stack, signals[CHANGED], 0);
}
void
@@ -112,7 +197,12 @@ meta_stack_add (MetaStack *stack,
if (meta_window_is_in_stack (window))
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);
window->stack_position = stack->n_positions;
stack->n_positions += 1;
@@ -120,7 +210,7 @@ meta_stack_add (MetaStack *stack,
"Window %s has stack_position initialized to %d\n",
window->desc, window->stack_position);
stack_sync_to_xserver (stack);
meta_stack_changed (stack);
meta_stack_update_window_tile_matches (stack, workspace_manager->active_workspace);
}
@@ -140,25 +230,11 @@ meta_stack_remove (MetaStack *stack,
window->stack_position = -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->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));
}
g_signal_emit (stack, signals[WINDOW_REMOVED], 0, window);
stack_sync_to_xserver (stack);
meta_stack_changed (stack);
meta_stack_update_window_tile_matches (stack, workspace_manager->active_workspace);
}
@@ -169,7 +245,7 @@ meta_stack_update_layer (MetaStack *stack,
MetaWorkspaceManager *workspace_manager = window->display->workspace_manager;
stack->need_relayer = TRUE;
stack_sync_to_xserver (stack);
meta_stack_changed (stack);
meta_stack_update_window_tile_matches (stack, workspace_manager->active_workspace);
}
@@ -180,7 +256,7 @@ meta_stack_update_transient (MetaStack *stack,
MetaWorkspaceManager *workspace_manager = window->display->workspace_manager;
stack->need_constrain = TRUE;
stack_sync_to_xserver (stack);
meta_stack_changed (stack);
meta_stack_update_window_tile_matches (stack, workspace_manager->active_workspace);
}
@@ -210,7 +286,7 @@ meta_stack_raise (MetaStack *stack,
meta_window_set_stack_position_no_sync (window, max_stack_position);
stack_sync_to_xserver (stack);
meta_stack_changed (stack);
meta_stack_update_window_tile_matches (stack, workspace_manager->active_workspace);
}
@@ -239,7 +315,7 @@ meta_stack_lower (MetaStack *stack,
meta_window_set_stack_position_no_sync (window, min_stack_position);
stack_sync_to_xserver (stack);
meta_stack_changed (stack);
meta_stack_update_window_tile_matches (stack, workspace_manager->active_workspace);
}
@@ -255,7 +331,7 @@ meta_stack_thaw (MetaStack *stack)
g_return_if_fail (stack->freeze_count > 0);
stack->freeze_count -= 1;
stack_sync_to_xserver (stack);
meta_stack_changed (stack);
meta_stack_update_window_tile_matches (stack, NULL);
}
@@ -771,99 +847,6 @@ apply_constraints (Constraint **constraints,
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:
*
@@ -981,131 +964,11 @@ stack_do_resort (MetaStack *stack)
static void
stack_ensure_sorted (MetaStack *stack)
{
stack_do_window_deletions (stack);
stack_do_window_additions (stack);
stack_do_relayer (stack);
stack_do_constrain (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*
meta_stack_get_top (MetaStack *stack)
{
@@ -1415,7 +1278,7 @@ meta_stack_set_positions (MetaStack *stack,
meta_topic (META_DEBUG_STACK,
"Reset the stack positions of (nearly) all windows\n");
stack_sync_to_xserver (stack);
meta_stack_changed (stack);
meta_stack_update_window_tile_matches (stack, NULL);
}
@@ -1480,7 +1343,7 @@ meta_window_set_stack_position (MetaWindow *window,
MetaWorkspaceManager *workspace_manager = window->display->workspace_manager;
meta_window_set_stack_position_no_sync (window, position);
stack_sync_to_xserver (window->display->stack);
meta_stack_changed (window->display->stack);
meta_stack_update_window_tile_matches (window->display->stack,
workspace_manager->active_workspace);
}

View File

@@ -51,38 +51,14 @@
*/
struct _MetaStack
{
GObject parent;
/** The MetaDisplay containing this stack. */
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. */
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
* the X server's stack, because it is in the middle of being updated.
@@ -121,6 +97,9 @@ struct _MetaStack
unsigned int need_constrain : 1;
};
#define META_TYPE_STACK (meta_stack_get_type ())
G_DECLARE_FINAL_TYPE (MetaStack, meta_stack, META, STACK, GObject)
/**
* meta_stack_new:
* @display: The MetaDisplay which will be the parent of this stack.
@@ -131,14 +110,6 @@ struct _MetaStack
*/
MetaStack *meta_stack_new (MetaDisplay *display);
/**
* meta_stack_free:
* @stack: The stack to destroy.
*
* Destroys and frees a MetaStack.
*/
void meta_stack_free (MetaStack *stack);
/**
* meta_stack_add:
* @stack: The stack to add it to

View File

@@ -581,6 +581,9 @@ struct _MetaWindowClass
gboolean (*is_stackable) (MetaWindow *window);
gboolean (*can_ping) (MetaWindow *window);
gboolean (*are_updates_frozen) (MetaWindow *window);
void (* map) (MetaWindow *window);
void (* unmap) (MetaWindow *window);
};
/* These differ from window->has_foo_func in that they consider

View File

@@ -809,17 +809,10 @@ sync_client_window_mapped (MetaWindow *window)
window->mapped = should_be_mapped;
meta_x11_error_trap_push (window->display->x11_display);
if (should_be_mapped)
{
XMapWindow (window->display->x11_display->xdisplay, window->xwindow);
}
if (window->mapped)
META_WINDOW_GET_CLASS (window)->map (window);
else
{
XUnmapWindow (window->display->x11_display->xdisplay, window->xwindow);
window->unmaps_pending ++;
}
meta_x11_error_trap_pop (window->display->x11_display);
META_WINDOW_GET_CLASS (window)->unmap (window);
}
static gboolean
@@ -1939,9 +1932,10 @@ idle_calc_showing (gpointer data)
while (tmp != NULL)
{
MetaWindow *window = tmp->data;
MetaDisplay *display = window->display;
if (!window->display->mouse_mode)
meta_display_increment_focus_sentinel (window->display);
if (display->x11_display && !display->mouse_mode)
meta_x11_display_increment_focus_sentinel (display->x11_display);
tmp = tmp->next;
}
@@ -2411,6 +2405,7 @@ meta_window_show (MetaWindow *window)
gboolean needs_stacking_adjustment;
MetaWindow *focus_window;
gboolean notify_demands_attention = FALSE;
MetaDisplay *display = window->display;
meta_topic (META_DEBUG_WINDOW_STATE,
"Showing window %s, shaded: %d iconic: %d placed: %d\n",
@@ -2577,7 +2572,7 @@ meta_window_show (MetaWindow *window)
meta_window_focus (window, timestamp);
}
else
else if (display->x11_display)
{
/* Prevent EnterNotify events in sloppy/mouse focus from
* erroneously focusing the window that had been denied
@@ -2585,7 +2580,7 @@ meta_window_show (MetaWindow *window)
* ideas for a better way to accomplish the same thing, but
* they're more involved so do it this way for now.
*/
meta_display_increment_focus_sentinel (window->display);
meta_x11_display_increment_focus_sentinel (display->x11_display);
}
}
@@ -3812,13 +3807,13 @@ maybe_move_attached_window (MetaWindow *window,
void *data)
{
if (window->hidden)
return FALSE;
return G_SOURCE_CONTINUE;
if (meta_window_is_attached_dialog (window) ||
meta_window_get_placement_rule (window))
meta_window_reposition (window);
return FALSE;
return G_SOURCE_CONTINUE;
}
/**
@@ -5288,7 +5283,8 @@ meta_window_set_focused_internal (MetaWindow *window,
meta_display_ungrab_focus_window_button (window->display, window);
/* Since we ungrab with XIAnyModifier above, all button
grabs go way so we need to re-grab the window buttons. */
meta_display_grab_window_buttons (window->display, window->xwindow);
if (!meta_is_wayland_compositor ())
meta_display_grab_window_buttons (window->display, window->xwindow);
}
g_signal_emit (window, window_signals[FOCUS], 0);
@@ -5378,50 +5374,6 @@ redraw_icon (MetaWindow *window)
meta_frame_queue_draw (window->frame);
}
static cairo_surface_t *
load_default_window_icon (int size)
{
GtkIconTheme *theme = gtk_icon_theme_get_default ();
g_autoptr (GdkPixbuf) pixbuf = NULL;
const char *icon_name;
if (gtk_icon_theme_has_icon (theme, META_DEFAULT_ICON_NAME))
icon_name = META_DEFAULT_ICON_NAME;
else
icon_name = "image-missing";
pixbuf = gtk_icon_theme_load_icon (theme, icon_name, size, 0, NULL);
return gdk_cairo_surface_create_from_pixbuf (pixbuf, 1, NULL);
}
static cairo_surface_t *
get_default_window_icon (void)
{
static cairo_surface_t *default_icon = NULL;
if (default_icon == NULL)
{
default_icon = load_default_window_icon (META_ICON_WIDTH);
g_assert (default_icon);
}
return cairo_surface_reference (default_icon);
}
static cairo_surface_t *
get_default_mini_icon (void)
{
static cairo_surface_t *default_icon = NULL;
if (default_icon == NULL)
{
default_icon = load_default_window_icon (META_MINI_ICON_WIDTH);
g_assert (default_icon);
}
return cairo_surface_reference (default_icon);
}
static void
meta_window_update_icon_now (MetaWindow *window,
gboolean force)
@@ -5438,17 +5390,11 @@ meta_window_update_icon_now (MetaWindow *window,
{
if (window->icon)
cairo_surface_destroy (window->icon);
if (icon)
window->icon = icon;
else
window->icon = get_default_window_icon ();
window->icon = icon;
if (window->mini_icon)
cairo_surface_destroy (window->mini_icon);
if (mini_icon)
window->mini_icon = mini_icon;
else
window->mini_icon = get_default_mini_icon ();
window->mini_icon = mini_icon;
g_object_freeze_notify (G_OBJECT (window));
g_object_notify_by_pspec (G_OBJECT (window), obj_props[PROP_ICON]);
@@ -5457,9 +5403,6 @@ meta_window_update_icon_now (MetaWindow *window,
redraw_icon (window);
}
g_assert (window->icon);
g_assert (window->mini_icon);
}
static gboolean
@@ -8146,8 +8089,7 @@ mouse_mode_focus (MetaWindow *window,
"Unsetting focus from %s due to mouse entering "
"the DESKTOP window\n",
display->focus_window->desc);
meta_x11_display_focus_the_no_focus_window (display->x11_display,
timestamp);
meta_display_unset_input_focus (display, timestamp);
}
}
}

View File

@@ -1308,8 +1308,7 @@ meta_workspace_focus_default_window (MetaWorkspace *workspace,
meta_topic (META_DEBUG_FOCUS,
"Setting focus to no_focus_window, since no valid "
"window to focus found.\n");
meta_x11_display_focus_the_no_focus_window (workspace->display->x11_display,
timestamp);
meta_display_unset_input_focus (workspace->display, timestamp);
}
}
}
@@ -1381,8 +1380,7 @@ focus_ancestor_or_top_window (MetaWorkspace *workspace,
else
{
meta_topic (META_DEBUG_FOCUS, "No MRU window to focus found; focusing no_focus_window.\n");
meta_x11_display_focus_the_no_focus_window (workspace->display->x11_display,
timestamp);
meta_display_unset_input_focus (workspace->display, timestamp);
}
}

View File

@@ -392,6 +392,8 @@ mutter_sources = [
'x11/meta-x11-selection-input-stream-private.h',
'x11/meta-x11-selection-output-stream.c',
'x11/meta-x11-selection-output-stream-private.h',
'x11/meta-x11-stack.c',
'x11/meta-x11-stack-private.h',
'x11/mutter-Xatomtype.h',
'x11/session.c',
'x11/session.h',

View File

@@ -297,4 +297,13 @@ MetaSoundPlayer * meta_display_get_sound_player (MetaDisplay *display);
META_EXPORT
MetaSelection * meta_display_get_selection (MetaDisplay *display);
META_EXPORT
void meta_display_set_input_focus (MetaDisplay *display,
MetaWindow *window,
gboolean focus_frame,
guint32 timestamp);
META_EXPORT
void meta_display_unset_input_focus (MetaDisplay *display,
guint32 timestamp);
#endif

View File

@@ -63,27 +63,4 @@ META_EXPORT
gboolean meta_x11_display_xwindow_is_a_no_focus_window (MetaX11Display *x11_display,
Window xwindow);
/* meta_x11_display_set_input_focus_window is like XSetInputFocus, except
* that (a) it can't detect timestamps later than the current time,
* since Mutter isn't part of the XServer, and thus gives erroneous
* behavior in this circumstance (so don't do it), (b) it uses
* display->last_focus_time since we don't have access to the true
* Xserver one, (c) it makes use of display->user_time since checking
* whether a window should be allowed to be focused should depend
* on user_time events (see bug 167358, comment 15 in particular)
*/
META_EXPORT
void meta_x11_display_set_input_focus_window (MetaX11Display *x11_display,
MetaWindow *window,
gboolean focus_frame,
guint32 timestamp);
/* meta_x11_display_focus_the_no_focus_window is called when the
* designated no_focus_window should be focused, but is otherwise the
* same as meta_display_set_input_focus_window
*/
META_EXPORT
void meta_x11_display_focus_the_no_focus_window (MetaX11Display *x11_display,
guint32 timestamp);
#endif /* META_X11_DISPLAY_H */

View File

@@ -862,6 +862,19 @@ init_pointer_constraint (struct wl_resource *resource,
return;
}
switch (lifetime)
{
case ZWP_POINTER_CONSTRAINTS_V1_LIFETIME_ONESHOT:
case ZWP_POINTER_CONSTRAINTS_V1_LIFETIME_PERSISTENT:
break;
default:
wl_resource_post_error (resource,
WL_DISPLAY_ERROR_INVALID_OBJECT,
"Invalid constraint lifetime");
return;
}
constraint = meta_wayland_pointer_constraint_new (surface, seat,
region,
lifetime,

View File

@@ -48,6 +48,7 @@ typedef struct
char *lock_file;
int abstract_fd;
int unix_fd;
struct wl_display *wayland_display;
struct wl_client *client;
struct wl_resource *xserver_resource;
char *display_name;

View File

@@ -142,10 +142,12 @@ meta_window_wayland_focus (MetaWindow *window,
guint32 timestamp)
{
if (meta_window_is_focusable (window))
meta_x11_display_set_input_focus_window (window->display->x11_display,
window,
FALSE,
timestamp);
{
meta_display_set_input_focus (window->display,
window,
FALSE,
timestamp);
}
}
static void
@@ -611,6 +613,16 @@ meta_window_wayland_are_updates_frozen (MetaWindow *window)
return !wl_window->has_been_shown;
}
static void
meta_window_wayland_map (MetaWindow *window)
{
}
static void
meta_window_wayland_unmap (MetaWindow *window)
{
}
static void
meta_window_wayland_class_init (MetaWindowWaylandClass *klass)
{
@@ -634,6 +646,8 @@ meta_window_wayland_class_init (MetaWindowWaylandClass *klass)
window_class->is_stackable = meta_window_wayland_is_stackable;
window_class->can_ping = meta_window_wayland_can_ping;
window_class->are_updates_frozen = meta_window_wayland_are_updates_frozen;
window_class->map = meta_window_wayland_map;
window_class->unmap = meta_window_wayland_unmap;
}
MetaWindow *
@@ -641,7 +655,6 @@ meta_window_wayland_new (MetaDisplay *display,
MetaWaylandSurface *surface)
{
XWindowAttributes attrs = { 0 };
MetaWindow *window;
/*
* Set attributes used by _meta_window_shared_new, don't bother trying to fake
@@ -656,26 +669,13 @@ meta_window_wayland_new (MetaDisplay *display,
attrs.map_state = IsUnmapped;
attrs.override_redirect = False;
/* XXX: Note: In the Wayland case we currently still trap X errors while
* creating a MetaWindow because we will still be making various redundant
* X requests (passing a window xid of None) until we thoroughly audit all
* the code to make sure it knows about non X based clients...
*/
meta_x11_error_trap_push (display->x11_display); /* Push a trap over all of window
* creation, to reduce XSync() calls
*/
window = _meta_window_shared_new (display,
META_WINDOW_CLIENT_TYPE_WAYLAND,
surface,
None,
WithdrawnState,
META_COMP_EFFECT_CREATE,
&attrs);
meta_x11_error_trap_pop (display->x11_display); /* pop the XSync()-reducing trap */
return window;
return _meta_window_shared_new (display,
META_WINDOW_CLIENT_TYPE_WAYLAND,
surface,
None,
WithdrawnState,
META_COMP_EFFECT_CREATE,
&attrs);
}
static gboolean

View File

@@ -465,32 +465,27 @@ on_displayfd_ready (int fd,
return G_SOURCE_REMOVE;
}
gboolean
meta_xwayland_start (MetaXWaylandManager *manager,
struct wl_display *wl_display)
static gboolean
meta_xwayland_init_xserver (MetaXWaylandManager *manager)
{
int xwayland_client_fd[2];
int displayfd[2];
gboolean started = FALSE;
g_autoptr(GSubprocessLauncher) launcher = NULL;
GSubprocessFlags flags;
GError *error = NULL;
if (!choose_xdisplay (manager))
goto out;
/* We want xwayland to be a wayland client so we make a socketpair to setup a
* wayland protocol connection. */
if (socketpair (AF_UNIX, SOCK_STREAM | SOCK_CLOEXEC, 0, xwayland_client_fd) < 0)
{
g_warning ("xwayland_client_fd socketpair failed\n");
goto out;
return FALSE;
}
if (socketpair (AF_UNIX, SOCK_STREAM | SOCK_CLOEXEC, 0, displayfd) < 0)
{
g_warning ("displayfd socketpair failed\n");
goto out;
return FALSE;
}
/* xwayland, please. */
@@ -511,16 +506,10 @@ meta_xwayland_start (MetaXWaylandManager *manager,
g_subprocess_launcher_setenv (launcher, "WAYLAND_SOCKET", "3", TRUE);
/* Use the -terminate parameter to ensure that Xwayland exits cleanly
* after the last client disconnects. Fortunately that includes the window
* manager so it won't exit prematurely either. This ensures that Xwayland
* won't try to reconnect and crash, leaving uninteresting core dumps. We do
* want core dumps from Xwayland but only if a real bug occurs...
*/
manager->proc = g_subprocess_launcher_spawn (launcher, &error,
XWAYLAND_PATH, manager->display_name,
"-rootless",
"-terminate",
"-noreset",
"-accessx",
"-core",
"-listen", "4",
@@ -530,14 +519,15 @@ meta_xwayland_start (MetaXWaylandManager *manager,
if (!manager->proc)
{
g_error ("Failed to spawn Xwayland: %s", error->message);
goto out;
return FALSE;
}
manager->xserver_died_cancellable = g_cancellable_new ();
g_subprocess_wait_async (manager->proc, manager->xserver_died_cancellable,
xserver_died, NULL);
g_unix_fd_add (displayfd[0], G_IO_IN, on_displayfd_ready, manager);
manager->client = wl_client_create (wl_display, xwayland_client_fd[0]);
manager->client = wl_client_create (manager->wayland_display,
xwayland_client_fd[0]);
/* We need to run a mainloop until we know xwayland has a binding
* for our xserver interface at which point we can assume it's
@@ -545,15 +535,18 @@ meta_xwayland_start (MetaXWaylandManager *manager,
manager->init_loop = g_main_loop_new (NULL, FALSE);
g_main_loop_run (manager->init_loop);
started = TRUE;
return TRUE;
}
out:
if (!started)
{
unlink (manager->lock_file);
g_clear_pointer (&manager->lock_file, g_free);
}
return started;
gboolean
meta_xwayland_start (MetaXWaylandManager *manager,
struct wl_display *wl_display)
{
if (!choose_xdisplay (manager))
return FALSE;
manager->wayland_display = wl_display;
return meta_xwayland_init_xserver (manager);
}
static void

View File

@@ -803,14 +803,15 @@ handle_window_focus_event (MetaX11Display *x11_display,
* multiple focus events with the same serial.
*/
if (x11_display->server_focus_serial > x11_display->focus_serial ||
(!display->focused_by_us &&
(!x11_display->focused_by_us &&
x11_display->server_focus_serial == x11_display->focus_serial))
{
meta_display_update_focus_window (display,
focus_window,
focus_window ? focus_window->xwindow : None,
x11_display->server_focus_serial,
FALSE);
meta_display_update_focus_window (display, focus_window);
meta_x11_display_update_focus_window (x11_display,
focus_window ?
focus_window->xwindow : None,
x11_display->server_focus_serial,
FALSE);
return TRUE;
}
else
@@ -882,7 +883,7 @@ handle_input_xevent (MetaX11Display *x11_display,
enter_event->mode != XINotifyGrab &&
enter_event->mode != XINotifyUngrab &&
enter_event->detail != XINotifyInferior &&
meta_display_focus_sentinel_clear (display))
meta_x11_display_focus_sentinel_clear (x11_display))
{
meta_window_handle_enter (window,
enter_event->time,
@@ -1525,7 +1526,7 @@ handle_other_xevent (MetaX11Display *x11_display,
if (event->xproperty.atom ==
x11_display->atom__MUTTER_SENTINEL)
{
meta_display_decrement_focus_sentinel (display);
meta_x11_display_decrement_focus_sentinel (x11_display);
}
}
}
@@ -1792,7 +1793,7 @@ meta_x11_display_handle_xevent (MetaX11Display *x11_display,
if (META_IS_BACKEND_X11 (backend))
meta_backend_x11_handle_event (META_BACKEND_X11 (backend), event);
if (display->focused_by_us &&
if (x11_display->focused_by_us &&
event->xany.serial > x11_display->focus_serial &&
display->focus_window &&
!window_has_xwindow (display->focus_window, x11_display->server_focus_window))
@@ -1801,10 +1802,11 @@ meta_x11_display_handle_xevent (MetaX11Display *x11_display,
display->focus_window->desc);
meta_display_update_focus_window (display,
meta_x11_display_lookup_x_window (x11_display,
x11_display->server_focus_window),
x11_display->server_focus_window,
x11_display->server_focus_serial,
FALSE);
x11_display->server_focus_window));
meta_x11_display_update_focus_window (x11_display,
x11_display->server_focus_window,
x11_display->server_focus_serial,
FALSE);
}
if (event->xany.window == x11_display->xroot)

View File

@@ -35,6 +35,7 @@
#include "meta/types.h"
#include "meta/meta-x11-display.h"
#include "meta-startup-notification-x11.h"
#include "meta-x11-stack-private.h"
#include "ui/ui.h"
typedef struct _MetaGroupPropHooks MetaGroupPropHooks;
@@ -133,8 +134,21 @@ struct _MetaX11Display
GList *output_streams;
} selection;
/* If true, server->focus_serial refers to us changing the focus; in
* this case, we can ignore focus events that have exactly focus_serial,
* since we take care to make another request immediately afterwards.
* But if focus is being changed by another client, we have to accept
* multiple events with the same serial.
*/
guint focused_by_us : 1;
guint keys_grabbed : 1;
/* we use property updates as sentinels for certain window focus events
* to avoid some race conditions on EnterNotify events
*/
int sentinel_counter;
int composite_event_base;
int composite_error_base;
int composite_major_version;
@@ -162,6 +176,7 @@ struct _MetaX11Display
#define META_X11_DISPLAY_HAS_XINPUT_23(x11_display) ((x11_display)->have_xinput_23)
MetaX11StartupNotification *startup_notification;
MetaX11Stack *x11_stack;
};
MetaX11Display *meta_x11_display_new (MetaDisplay *display, GError **error);
@@ -222,4 +237,16 @@ MetaLogicalMonitor *meta_x11_display_xinerama_index_to_logical_monitor (MetaX11D
void meta_x11_display_update_workspace_layout (MetaX11Display *x11_display);
void meta_x11_display_update_workspace_names (MetaX11Display *x11_display);
void meta_x11_display_increment_focus_sentinel (MetaX11Display *x11_display);
void meta_x11_display_decrement_focus_sentinel (MetaX11Display *x11_display);
gboolean meta_x11_display_focus_sentinel_clear (MetaX11Display *x11_display);
void meta_x11_display_update_focus_window (MetaX11Display *x11_display,
Window xwindow,
gulong serial,
gboolean focused_by_us);
void meta_x11_display_set_input_focus (MetaX11Display *x11_display,
Window xwindow,
guint32 timestamp);
#endif /* META_X11_DISPLAY_PRIVATE_H */

View File

@@ -95,6 +95,27 @@ static void unset_wm_check_hint (MetaX11Display *x11_display);
static void prefs_changed_callback (MetaPreference pref,
void *data);
static void
meta_x11_display_unmanage_windows (MetaX11Display *x11_display)
{
GList *windows, *l;
MetaWindow *window;
if (!x11_display->xids)
return;
windows = g_hash_table_get_values (x11_display->xids);
g_list_foreach (windows, (GFunc) g_object_ref, NULL);
for (l = windows; l; l = l->next)
{
window = l->data;
if (!window->unmanaging)
meta_window_unmanage (window, META_CURRENT_TIME);
}
g_list_free_full (windows, g_object_unref);
}
static void
meta_x11_display_dispose (GObject *object)
{
@@ -107,6 +128,9 @@ meta_x11_display_dispose (GObject *object)
meta_x11_display_ungrab_keys (x11_display);
meta_x11_selection_shutdown (x11_display);
meta_x11_display_unmanage_windows (x11_display);
g_clear_object (&x11_display->x11_stack);
if (x11_display->ui)
{
@@ -1086,6 +1110,9 @@ meta_x11_display_new (MetaDisplay *display, GError **error)
};
Atom atoms[G_N_ELEMENTS(atom_names)];
if (!meta_x11_init_gdk_display (error))
return NULL;
g_assert (prepared_gdk_display);
gdk_display = g_steal_pointer (&prepared_gdk_display);
@@ -1270,6 +1297,7 @@ meta_x11_display_new (MetaDisplay *display, GError **error)
set_desktop_geometry_hint (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;
meta_x11_display_grab_keys (x11_display);
@@ -1819,17 +1847,27 @@ meta_x11_display_update_active_window_hint (MetaX11Display *x11_display)
meta_x11_error_trap_pop (x11_display);
}
static void
request_xserver_input_focus_change (MetaX11Display *x11_display,
MetaWindow *meta_window,
Window xwindow,
guint32 timestamp)
void
meta_x11_display_update_focus_window (MetaX11Display *x11_display,
Window xwindow,
gulong serial,
gboolean focused_by_us)
{
gulong serial;
x11_display->focus_serial = serial;
x11_display->focused_by_us = !!focused_by_us;
if (meta_display_timestamp_too_old (x11_display->display, &timestamp))
if (x11_display->focus_xwindow == xwindow)
return;
x11_display->focus_xwindow = xwindow;
meta_x11_display_update_active_window_hint (x11_display);
}
void
meta_x11_display_set_input_focus (MetaX11Display *x11_display,
Window xwindow,
guint32 timestamp)
{
meta_x11_error_trap_push (x11_display);
/* In order for mutter to know that the focus request succeeded, we track
@@ -1842,8 +1880,6 @@ request_xserver_input_focus_change (MetaX11Display *x11_display,
*/
XGrabServer (x11_display->xdisplay);
serial = XNextRequest (x11_display->xdisplay);
XSetInputFocus (x11_display->xdisplay,
xwindow,
RevertToPointerRoot,
@@ -1857,30 +1893,7 @@ request_xserver_input_focus_change (MetaX11Display *x11_display,
XUngrabServer (x11_display->xdisplay);
XFlush (x11_display->xdisplay);
meta_display_update_focus_window (x11_display->display,
meta_window,
xwindow,
serial,
TRUE);
meta_x11_error_trap_pop (x11_display);
x11_display->display->last_focus_time = timestamp;
if (meta_window == NULL || meta_window != x11_display->display->autoraise_window)
meta_display_remove_autoraise_callback (x11_display->display);
}
void
meta_x11_display_set_input_focus_window (MetaX11Display *x11_display,
MetaWindow *window,
gboolean focus_frame,
guint32 timestamp)
{
request_xserver_input_focus_change (x11_display,
window,
focus_frame ? window->frame->xwindow : window->xwindow,
timestamp);
}
void
@@ -1888,20 +1901,12 @@ meta_x11_display_set_input_focus_xwindow (MetaX11Display *x11_display,
Window window,
guint32 timestamp)
{
request_xserver_input_focus_change (x11_display,
NULL,
window,
timestamp);
}
gulong serial;
void
meta_x11_display_focus_the_no_focus_window (MetaX11Display *x11_display,
guint32 timestamp)
{
request_xserver_input_focus_change (x11_display,
NULL,
x11_display->no_focus_window,
timestamp);
meta_display_unset_input_focus (x11_display->display, timestamp);
serial = XNextRequest (x11_display->xdisplay);
meta_x11_display_set_input_focus (x11_display, window, timestamp);
meta_x11_display_update_focus_window (x11_display, window, serial, TRUE);
}
static MetaX11DisplayLogicalMonitorData *
@@ -2177,3 +2182,34 @@ prefs_changed_callback (MetaPreference pref,
set_workspace_names (x11_display);
}
}
void
meta_x11_display_increment_focus_sentinel (MetaX11Display *x11_display)
{
unsigned long data[1];
data[0] = meta_display_get_current_time (x11_display->display);
XChangeProperty (x11_display->xdisplay,
x11_display->xroot,
x11_display->atom__MUTTER_SENTINEL,
XA_CARDINAL,
32, PropModeReplace, (guchar*) data, 1);
x11_display->sentinel_counter += 1;
}
void
meta_x11_display_decrement_focus_sentinel (MetaX11Display *x11_display)
{
x11_display->sentinel_counter -= 1;
if (x11_display->sentinel_counter < 0)
x11_display->sentinel_counter = 0;
}
gboolean
meta_x11_display_focus_sentinel_clear (MetaX11Display *x11_display)
{
return (x11_display->sentinel_counter == 0);
}

View 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
View 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);
}

View File

@@ -794,10 +794,10 @@ meta_window_x11_focus (MetaWindow *window,
{
meta_topic (META_DEBUG_FOCUS,
"Focusing frame of %s\n", window->desc);
meta_x11_display_set_input_focus_window (window->display->x11_display,
window,
TRUE,
timestamp);
meta_display_set_input_focus (window->display,
window,
TRUE,
timestamp);
}
else
{
@@ -806,10 +806,10 @@ meta_window_x11_focus (MetaWindow *window,
meta_topic (META_DEBUG_FOCUS,
"Setting input focus on %s since input = true\n",
window->desc);
meta_x11_display_set_input_focus_window (window->display->x11_display,
window,
FALSE,
timestamp);
meta_display_set_input_focus (window->display,
window,
FALSE,
timestamp);
}
if (priv->wm_take_focus)
@@ -832,8 +832,7 @@ meta_window_x11_focus (MetaWindow *window,
*/
if (window->display->focus_window != NULL &&
window->display->focus_window->unmanaging)
meta_x11_display_focus_the_no_focus_window (window->display->x11_display,
timestamp);
meta_display_unset_input_focus (window->display, timestamp);
}
request_take_focus (window, timestamp);
@@ -1706,6 +1705,27 @@ meta_window_x11_are_updates_frozen (MetaWindow *window)
return FALSE;
}
static void
meta_window_x11_map (MetaWindow *window)
{
MetaX11Display *x11_display = window->display->x11_display;
meta_x11_error_trap_push (x11_display);
XMapWindow (x11_display->xdisplay, window->xwindow);
meta_x11_error_trap_pop (x11_display);
}
static void
meta_window_x11_unmap (MetaWindow *window)
{
MetaX11Display *x11_display = window->display->x11_display;
meta_x11_error_trap_push (x11_display);
XUnmapWindow (x11_display->xdisplay, window->xwindow);
meta_x11_error_trap_pop (x11_display);
window->unmaps_pending ++;
}
static void
meta_window_x11_class_init (MetaWindowX11Class *klass)
{
@@ -1733,6 +1753,8 @@ meta_window_x11_class_init (MetaWindowX11Class *klass)
window_class->is_stackable = meta_window_x11_is_stackable;
window_class->can_ping = meta_window_x11_can_ping;
window_class->are_updates_frozen = meta_window_x11_are_updates_frozen;
window_class->map = meta_window_x11_map;
window_class->unmap = meta_window_x11_unmap;
}
void