Compare commits

...

59 Commits

Author SHA1 Message Date
Jonas Ådahl
c2e12b3434 x11: Limit touch replay pointer events to when replaying
When a touch sequence was rejected, the emulated pointer events would be
replayed with old timestamps. This caused issues with grabs as they
would be ignored due to being too old. This was mitigated by making sure
device event timestamps never travelled back in time by tampering with
any event that had a timestamp seemingly in the past.

This failed when the most recent timestamp that had been received were
much older than the timestamp of the new event. This could for example
happen when a session was left not interacted with for 40+ days or so;
when interacted with again, as any new timestamp would according to
XSERVER_TIME_IS_BEFORE() still be in the past compared to the "most
recent" one. The effect is that we'd always use the `latest_evtime` for
all new device events without ever updating it.

The end result of this was that passive grabs would become active when
interacted with, but would then newer be released, as the timestamps to
XIAllowEvents() would out of date, resulting in the desktop effectively
freezing, as the Shell would have an active pointer grab.

To avoid the situation where we get stuck with an old `latest_evtime`
timestamp, limit the tampering with device event timestamp to 1) only
pointer events, and 2) only during the replay sequence. The second part
is implemented by sending an asynchronous message via the X server after
rejecting a touch sequence, only potentially tampering with the device
event timestamps until the reply. This should avoid the stuck timestamp
as in those situations, we'll always have a relatively up to date
`latest_evtime` meaning XSERVER_TIME_IS_BEFORE() will not get confused.

https://gitlab.gnome.org/GNOME/mutter/merge_requests/886
2020-04-24 21:30:25 +02:00
Jonas Ådahl
002299fbef display: Move finishing of touch sequence to the backend
We need to manipulate an X11 grab when a touch sequence ends; move that
logic to where it belongs - in the X11 backend.

https://gitlab.gnome.org/GNOME/mutter/merge_requests/886
2020-04-24 21:30:11 +02:00
Jonas Ådahl
f0b7cf4d91 crtc-kms: Ignore 90° rotations
They tend to require special modifiers or won't work at all; ignore
them.
2020-03-06 09:47:41 +01:00
Tim Klocke
ad4dbefbc0 backends: Update inhibited state for the monitor and respect that state
The inhibited state of the monitor was after the initializiation never
updated. meta_idle_monitor_reset_idletime didn't respect the inhibited
state, so it set timeouts if it shouldn't have.

Fixes: https://gitlab.gnome.org/GNOME/mutter/issues/573


(cherry picked from commit 81ee8886ce)
2019-10-10 09:23:44 +00:00
Daniel van Vugt
5a486f5b6b background: Reload when GPU memory is invalidated
Fixes corrupt background wallpaper when resuming from suspend on the
Nvidia driver.

https://gitlab.gnome.org/GNOME/gnome-shell/issues/1084

(cherry picked from commit a5265365dd)

https://gitlab.gnome.org/GNOME/mutter/merge_requests/777
2019-09-06 16:54:45 +08:00
Christian Kirbach
bb5c7b97ba Update German translation (Launchpad bug 1786977) 2019-09-05 23:47:21 +02:00
Marco Trevisan (Treviño)
b7f1588119 metatest: Dispatch the destruction instead of sleeping after it
https://gitlab.gnome.org/GNOME/mutter/merge_requests/669/


(cherry picked from commit ecf7e53206)
2019-07-18 16:40:13 +00:00
Marco Trevisan (Treviño)
88e492cac0 window-x11: Remove double definition of MetaStack
In commit ed03ce53b we introduced a double definition of MetaStack due to a
wrong cherry-pick conflict resolution.

Fix this by removing the invalid duplicated line.

Related to https://gitlab.gnome.org/GNOME/mutter/merge_requests/688
2019-07-18 11:40:16 +02:00
Marco Trevisan (Treviño)
ed03ce53b2 window-x11: Focus a window in the active workspace as take-focus fallback
Starting with commit 2db94e2e we try to focus a fallback default focus window
if no take-focus window candidate gets the input focus when we request it and
we limit the focus candidates to the current window's workspace.

However, if the window is unmanaging, the workspace might be unset, and we could
end up in deferencing a NULL pointer causing a crash.

So, in case the window's workspace is unset, just use the currently active
workspace for the display.

Closes https://gitlab.gnome.org/GNOME/mutter/issues/687

https://gitlab.gnome.org/GNOME/mutter/merge_requests/688

(cherry picked from commit 5ca0ef078d)
2019-07-18 10:41:35 +02:00
Marco Trevisan (Treviño)
ccab0f470d meson: Bump meson requirement to 0.50.0
We've been using configure_file's `install` property for some time now, but this
has been officially supported and works as expected only since meson 0.50, so,
bump version to avoid warnings and ensure the behavior is the one we want.

https://gitlab.gnome.org/GNOME/mutter/issues/668
2019-07-08 15:45:25 +00:00
Marco Trevisan (Treviño)
61691bacc8 window-x11: Use any focusable window as fallback delayed focus window
As per commit f71151a5 we focus an input window if no take-focus-window accepts
it. This might lead to an infinite loop if there are various focusable but
non-input windows in the stack.

When the current focus window is unmanaging and we're trying to focus a
WM_TAKE_FOCUS window, we intent to give the focus to the first focusable input
window in the stack.

However, if an application (such as the Java ones) only uses non-input
WM_TAKE_FOCUS windows, are not requesting these ones to get the focus. This
might lead to a state where no window is focused, or a wrong one is.

So, instead of only focus the first eventually input window available, try to
request to all the take-focus windows that are in the stack between the
destroyed one and the first input one to acquire the input focus.
Use a queue to keep track of those windows, that is passed around stealing
ownership, while we protect for unmanaged queued windows.

Also, reduce the default timeout value, as the previous one might lead to an
excessive long wait.

Added metatests verifying these situations.

Closes: https://gitlab.gnome.org/GNOME/mutter/issues/660
https://gitlab.gnome.org/GNOME/mutter/merge_requests/669

(cherry picked from commit 6d8293a422)
2019-07-08 16:37:25 +02:00
Marco Trevisan (Treviño)
63f3f5d59f tests: Add "accept_take_focus" command
When used it setups an X11 event monitor that replies to WM_TAKE_FOCUS
ClientMessage's with a XSetInputFocus request.

It can only be used by x11 clients on windows that have WM_TAKE_FOCUS atom set
and that does not accept input.

https://gitlab.gnome.org/GNOME/mutter/merge_requests/669


(cherry picked from commit b80250e483)
2019-07-08 14:33:07 +00:00
Marco Trevisan (Treviño)
80869e0737 test-client: Add x11 events GSource handler
When using gtk under X11 some WM related events are always filtered and not
delivered when using the gdk Window filters.

So, add a new one with higher priority than the GTK events one so that we can
pick those events before than Gtk itself.

https://gitlab.gnome.org/GNOME/mutter/merge_requests/669


(cherry picked from commit bd0f1bd338)
2019-07-08 14:32:32 +00:00
Marco Trevisan (Treviño)
763092a4b6 stack: Add a function to get a sorted list of focus candidates
Use a static function if a window can be the default focus window, and use such
function to return a filtered list of the stack.

https://gitlab.gnome.org/GNOME/mutter/merge_requests/669


(cherry picked from commit 2439255f32)
2019-07-08 14:26:01 +00:00
Marco Trevisan (Treviño)
e50cdda4ff window-x11: Accept any focusable window as fallback focus
As per commit f71151a5 we were ignoring WM_TAKE_FOCUS-only windows as focus
targets, however this might end-up in an infinite loop if there are multiple
non-input windows stacked.

So, accept any focusable window as fallback focus target even if it's a
take-focus one (that might not reply to the request).

Added a stacking test to verify this.

Closes: https://gitlab.gnome.org/GNOME/mutter/issues/660
https://gitlab.gnome.org/GNOME/mutter/merge_requests/669

(cherry picked from commit c327b2df95)
2019-07-08 16:23:04 +02:00
Marco Trevisan (Treviño)
c50df14311 window-x11: Don't double-check for unmanaging windows
When looking for the best fallback focus window, we ignore it if it is in the
unmanaging state, but meta_stack_get_default_focus_window() does this is check
for us already.

So, ignore the redundant test.

https://gitlab.gnome.org/GNOME/mutter/merge_requests/669


(cherry picked from commit 9aee47daa9)
2019-07-08 14:16:57 +00:00
Jonas Ådahl
194d93efd8 window-actor: Remove left-over parent field
The commit

commit 60f7ff3a69
Author: Georges Basile Stavracas Neto <georges.stavracas@gmail.com>
Date:   Fri Dec 21 18:12:49 2018 -0200

    window-actor: Turn into a derivable class

made the previous instance struct a instance private struct, but didn't
remove the parent field. Since it's unused, there is no point in keeping
it around, so lets drop it.

https://gitlab.gnome.org/GNOME/mutter/merge_requests/658


(cherry picked from commit 7229a07b6c)
2019-07-04 10:52:09 +00:00
Marco Trevisan (Treviño)
947da2c5d5 surface-actor-x11: Bind the surface actor resources to window actor life
X11 actors need to release the server data (pixmap and damage) before the
display is closed.
During the close phase all the windows are unmanaged and this causes the window
actors to be removed from the compositor, unsetting their actor surface.

However, in case a window is animating the surface might not be destroyed until
the animation is completed and a reference to it kept around by gjs in the shell
case. By the way, per commit 7718e67f all window actors (even the animating
ones) are destroyed before the display is closed, but this is not true for the
child surface, because the parent window will just unref it, leaving it around
if reffed somewhere else. This is fine for wayland surfaces, but not for X11
ones which are bound to server-side pixmaps.

So, connect to the parent MetaWindowActor "destroy" signal, releasing the x11
resources that implies detaching the pixmap (unsetting the texture) and removing
the damages.

Closes: https://gitlab.gnome.org/GNOME/mutter/issues/629
https://gitlab.gnome.org/GNOME/mutter/merge_requests/660


(cherry picked from commit de97b54595)
2019-06-28 17:47:01 +00:00
Marco Trevisan (Treviño)
0a8fbbe5cc surface-actor-x11: Assign X11 Display only if we have resources
free_damage and detach_pixmap functions are called inside dispose and an object
can be disposed multiple times, even when the display is already closed.

So, don't try to deference a possibly null-pointer, assigning the xdisplay too
early, as if the X11 related resources have been unset, the server might not be
open anymore. In fact, we assume that if we have a damage or a pixmap set,
the display is still open.

https://gitlab.gnome.org/GNOME/mutter/merge_requests/660


(cherry picked from commit d7d97f2477)
2019-06-28 17:46:38 +00:00
Marco Trevisan (Treviño)
001076339a window-actor: Set actor as compositor private in window before the surface
In MetaWindowActor creation we're setting the compositor private (i.e. the
window actor itself) of a window before creating the surface actor, and so
passing to the it a window without its compositor side set.

Since the surface actor might use the parent actor, set this before updating
the surface.

https://gitlab.gnome.org/GNOME/mutter/merge_requests/660


(cherry picked from commit 7776941b89)
2019-06-28 17:46:05 +00:00
Marco Trevisan (Treviño)
0d570f2dd3 window-actor: Use vfunc to set the surface actor
As per commit 80e3c1d set_surface_actor has been added, meant to do different
things depending on the backend, like connecting to signals under X11.

However, the vfunc isn't ever used, making the X11 surfaces not to react to
repaint-scheduled signal.

https://gitlab.gnome.org/GNOME/mutter/merge_requests/660


(cherry picked from commit 4061c8384b)
2019-06-28 17:45:13 +00:00
Jonas Ådahl
c5fb1d1975 renderer/native: Discard page flip retries when rebuilding views
Rebuilding views means we don't care to retry page flip attempts for
previous views, especially since connectors may have been disconnected,
making a page flip retry hit an assert a flipped CRTC has connectors
associated with it.

https://gitlab.gnome.org/GNOME/mutter/merge_requests/655
2019-06-26 22:34:21 +02:00
Jonas Ådahl
83ce89ef59 renderer/native: Queue mode reset from new rebuild_views vfunc
Simplify the call site a bit and make the native renderer know it should
queue mode reset itself when views have been rebuilt. This is done
partly due to more things needing to be dealt with after views have been
rebuilt.

https://gitlab.gnome.org/GNOME/mutter/merge_requests/655
2019-06-26 22:34:15 +02:00
Jonas Ådahl
da3195288b renderer/native: Remove left-over function declarations
There are no callers and no definitions of these.

https://gitlab.gnome.org/GNOME/mutter/merge_requests/655
2019-06-26 22:34:00 +02:00
Marco Trevisan (Treviño)
8b986cd065 window: Emit an error and return when trying to activate an unmanaged
If something (i.e. gnome-shell or an extension) tries to activate an unmanaged
window, we should warn about this and avoid to perform further actions as this
could lead to a crash of mutter, since the window has not valid flags (like
workspace) set anymore at this stage.

Fixes https://gitlab.gnome.org/GNOME/mutter/issues/580

https://gitlab.gnome.org/GNOME/mutter/merge_requests/564


(cherry picked from commit a6fc656e91)
2019-06-26 16:42:03 +00:00
Marco Trevisan (Treviño)
5efb11acad window: Warn if try to focus unmanaging windows
https://gitlab.gnome.org/GNOME/mutter/merge_requests/307
(cherry picked from commit e14613e74e)
2019-06-24 15:25:22 +02:00
Marco Trevisan (Treviño)
2db94e2e40 window-x11: Focus the default window with delay while waiting for take-focus
When requesting to a take-focus window to acquire the input, the client may or
may not respond with a SetInputFocus (this doesn't happen for no-input gtk
windows in fact [to be fixed there too]), in such case we were unsetting the
focus while waiting the reply.

In case the client won't respond, we wait for a small delay (set to 250 ms) for
the take-focus window to grab the input focus before setting it to the default
window.

Added a test for this behavior and for the case in which a window takes the
focus meanwhile we're waiting to focus the default window.

https://gitlab.gnome.org/GNOME/mutter/merge_requests/307
(cherry picked from commit f71151a5dd)
2019-06-24 15:25:21 +02:00
Marco Trevisan (Treviño)
866d6780c9 test-runner: Add 'dispatch' command
This will only wait for events to be dispatched and processed by the server
without waiting for client processing.

Reuse the code for the wait command too.

https://gitlab.gnome.org/GNOME/mutter/merge_requests/307
(cherry picked from commit 6022b23923)
2019-06-24 15:01:25 +02:00
Marco Trevisan (Treviño)
9009f8d48f test-runner: Add 'sleep' command
This allows to sleep for a given timeout in milliseconds.

Rename test_case_before_redraw to test_case_loop_quit since it's a generic
function and use it for the timeout too.

https://gitlab.gnome.org/GNOME/mutter/merge_requests/307
(cherry picked from commit d08763c18c)
2019-06-24 15:01:10 +02:00
Marco Trevisan (Treviño)
3d9771b25a tests: Verify focused window in closed-transient tests
Ensure that we have a focused window when closing transient windows with
no-focus or no-take-focus atoms

https://gitlab.gnome.org/GNOME/mutter/merge_requests/307
(cherry picked from commit fcb408ad5d)
2019-06-24 15:00:57 +02:00
Marco Trevisan (Treviño)
1be5a57ade test-runner: Add 'assert_focused' command
This allows to verify which window should have the focus, which might not
be the same as the top of the stack.

It's possible to assert the case where there's no focused window using
"NONE" as parameter.

https://gitlab.gnome.org/GNOME/mutter/merge_requests/307
(cherry picked from commit 51f9e04ef1)
2019-06-24 15:00:46 +02:00
Marco Trevisan (Treviño)
afcea966c0 tests, stacking: Add tests with no-input and no-take-focus windows
When a window with no frame, that doesn't accept focus and that has no
take-focus atom set is destroyed, we ended up in not changing the current_focus
window, causing a crash.

Added test cases that verify this situation.

Related to https://gitlab.gnome.org/GNOME/mutter/issues/308
https://gitlab.gnome.org/GNOME/mutter/merge_requests/307
(cherry picked from commit 2fc7760cee)
2019-06-24 15:00:24 +02:00
Marco Trevisan (Treviño)
9c079a5261 tests: Add 'can_take_focus' command to runner and client
Allow to set/unset WM_TAKE_FOCUS from client window.
This is added by default by gtk, but this might not happen in other toolkits,
so add an ability to (un)set this.

So fetch the protocols with XGetWMProtocols and unset the atom.

test-client now needs to depend on Xlib directly in meson build.

https://gitlab.gnome.org/GNOME/mutter/merge_requests/307
(cherry picked from commit f2d2d473b7)
2019-06-24 14:59:57 +02:00
Marco Trevisan (Treviño)
d56bd28f64 tests: Add 'accept_focus' command to runner and client
Under the hood, calls gtk_window_set_accept_focus in the client

https://gitlab.gnome.org/GNOME/mutter/merge_requests/307
(cherry picked from commit e1f839f48f)
2019-06-24 14:59:43 +02:00
Marco Trevisan (Treviño)
225d18761a workspace: Focus only ancestors that are focusable
When destroying a window that has a parent, we initially try to focus one of
its ancestors. However if no ancestor can be focused, then we should instead
focus the default focus window instead of trying to request focus for a window
that can't get focus anyways.

Fixes https://gitlab.gnome.org/GNOME/mutter/issues/308
(cherry picked from commit eccc791f3b)
2019-06-24 14:59:31 +02:00
Jonas Ådahl
e0922bffea renderer/native: Fix EGLSurface destruction order
Make sure to destroy the EGL surface after releasing held buffers,
otherwise we'll get the following valgrind warnings:

==24016== Invalid read of size 8
==24016==    at 0x1739943F: release_buffer (platform_drm.c:73)
==24016==    by 0x49AC355: meta_drm_buffer_gbm_finalize (meta-drm-buffer-gbm.c:213)
==24016==    by 0x4B75B61: g_object_unref (gobject.c:3346)
==24016==    by 0x49B4B41: free_current_bo (meta-renderer-native.c:991)
==24016==    by 0x49B816F: meta_renderer_native_release_onscreen (meta-renderer-native.c:2971)
==24016==    by 0x5209441: _cogl_onscreen_free (cogl-onscreen.c:167)
==24016==    by 0x5208D81: _cogl_object_onscreen_indirect_free (cogl-onscreen.c:51)
==24016==    by 0x51C8066: _cogl_object_default_unref (cogl-object.c:103)
==24016==    by 0x5207989: _cogl_framebuffer_unref (cogl-framebuffer.c:1814)
==24016==    by 0x51C80B1: cogl_object_unref (cogl-object.c:115)
==24016==    by 0x53673C7: clutter_stage_view_dispose (clutter-stage-view.c:304)
==24016==    by 0x4B75AF2: g_object_unref (gobject.c:3309)
==24016==  Address 0x18e742a8 is 536 bytes inside a block of size 784 free'd
==24016==    at 0x4839A0C: free (vg_replace_malloc.c:540)
==24016==    by 0x17399764: dri2_drm_destroy_surface (platform_drm.c:231)
==24016==    by 0x1738550A: eglDestroySurface (eglapi.c:1145)
==24016==    by 0x5440286: eglDestroySurface (in /home/jonas/Dev/gnome/install/lib/libEGL.so.1.1.0)
==24016==    by 0x49613A5: meta_egl_destroy_surface (meta-egl.c:432)
==24016==    by 0x49B80F9: meta_renderer_native_release_onscreen (meta-renderer-native.c:2954)
==24016==    by 0x5209441: _cogl_onscreen_free (cogl-onscreen.c:167)
==24016==    by 0x5208D81: _cogl_object_onscreen_indirect_free (cogl-onscreen.c:51)
==24016==    by 0x51C8066: _cogl_object_default_unref (cogl-object.c:103)
==24016==    by 0x5207989: _cogl_framebuffer_unref (cogl-framebuffer.c:1814)
==24016==    by 0x51C80B1: cogl_object_unref (cogl-object.c:115)
==24016==    by 0x53673C7: clutter_stage_view_dispose (clutter-stage-view.c:304)
==24016==  Block was alloc'd at
==24016==    at 0x483AB1A: calloc (vg_replace_malloc.c:762)
==24016==    by 0x173997AE: dri2_drm_create_window_surface (platform_drm.c:145)
==24016==    by 0x17388906: _eglCreateWindowSurfaceCommon (eglapi.c:929)
==24016==    by 0x5440197: eglCreateWindowSurface (in /home/jonas/Dev/gnome/install/lib/libEGL.so.1.1.0)
==24016==    by 0x49612FF: meta_egl_create_window_surface (meta-egl.c:396)
==24016==    by 0x49B752E: meta_renderer_native_create_surface_gbm (meta-renderer-native.c:2538)
==24016==    by 0x49B7E6C: meta_onscreen_native_allocate (meta-renderer-native.c:2870)
==24016==    by 0x49B8BCF: meta_renderer_native_create_view (meta-renderer-native.c:3387)
==24016==    by 0x48D274B: meta_renderer_create_view (meta-renderer.c:78)
==24016==    by 0x48D27DE: meta_renderer_rebuild_views (meta-renderer.c:111)
==24016==    by 0x49BB4FB: meta_stage_native_rebuild_views (meta-stage-native.c:142)
==24016==    by 0x49A733C: meta_backend_native_update_screen_size (meta-backend-native.c:517)

https://gitlab.gnome.org/GNOME/mutter/merge_requests/622
(cherry picked from commit d9fb11b043)
2019-06-19 21:49:48 +02:00
Jonas Ådahl
8307c0f7ab renderer/native: Make sure we're not destroying an active EGLSurface
When making a new surface/context pair current, mesa may want to flush
the old context. Make sure we don't try to flush any freed memory by
unmaking a surface/context pair current before freeing it.

Not doing this results in the following valgrind warnings:

==15986== Invalid read of size 8
==15986==    at 0x69A6D80: dri_flush_front_buffer (gbm_dri.c:92)
==15986==    by 0x1750D458: intel_flush_front (brw_context.c:251)
==15986==    by 0x1750D4BB: intel_glFlush (brw_context.c:296)
==15986==    by 0x1739D8DD: dri2_make_current (egl_dri2.c:1461)
==15986==    by 0x17393A3A: eglMakeCurrent (eglapi.c:869)
==15986==    by 0x54381FB: InternalMakeCurrentVendor (in /home/jonas/Dev/gnome/install/lib/libEGL.so.1.1.0)
==15986==    by 0x5438515: eglMakeCurrent (in /home/jonas/Dev/gnome/install/lib/libEGL.so.1.1.0)
==15986==    by 0x522A782: _cogl_winsys_egl_make_current (cogl-winsys-egl.c:303)
==15986==    by 0x49B64C8: meta_renderer_native_create_view (meta-renderer-native.c:3076)
==15986==    by 0x48D26E7: meta_renderer_create_view (meta-renderer.c:78)
==15986==    by 0x48D277A: meta_renderer_rebuild_views (meta-renderer.c:111)
==15986==    by 0x49BF46E: meta_stage_native_rebuild_views (meta-stage-native.c:142)
==15986==  Address 0x1b076600 is 0 bytes inside a block of size 48 free'd
==15986==    at 0x4839A0C: free (vg_replace_malloc.c:540)
==15986==    by 0x49B59F3: meta_renderer_native_release_onscreen (meta-renderer-native.c:2651)
==15986==    by 0x5211441: _cogl_onscreen_free (cogl-onscreen.c:167)
==15986==    by 0x5210D81: _cogl_object_onscreen_indirect_free (cogl-onscreen.c:51)
==15986==    by 0x51D0066: _cogl_object_default_unref (cogl-object.c:103)
==15986==    by 0x520F989: _cogl_framebuffer_unref (cogl-framebuffer.c:1814)
==15986==    by 0x51D00B1: cogl_object_unref (cogl-object.c:115)
==15986==    by 0x536F3C7: clutter_stage_view_dispose (clutter-stage-view.c:304)
==15986==    by 0x4B7DAF2: g_object_unref (gobject.c:3309)
==15986==    by 0x4A9596C: g_list_foreach (glist.c:1013)
==15986==    by 0x4A9599A: g_list_free_full (glist.c:223)
==15986==    by 0x48D2737: meta_renderer_rebuild_views (meta-renderer.c:100)
==15986==  Block was alloc'd at
==15986==    at 0x483AB1A: calloc (vg_replace_malloc.c:762)
==15986==    by 0x69A76B2: gbm_dri_surface_create (gbm_dri.c:1252)
==15986==    by 0x69A6BFE: gbm_surface_create (gbm.c:600)
==15986==    by 0x49B4E29: meta_renderer_native_create_surface_gbm (meta-renderer-native.c:2221)
==15986==    by 0x49B57DB: meta_onscreen_native_allocate (meta-renderer-native.c:2569)
==15986==    by 0x49B6423: meta_renderer_native_create_view (meta-renderer-native.c:3062)
==15986==    by 0x48D26E7: meta_renderer_create_view (meta-renderer.c:78)
==15986==    by 0x48D277A: meta_renderer_rebuild_views (meta-renderer.c:111)
==15986==    by 0x49BF46E: meta_stage_native_rebuild_views (meta-stage-native.c:142)
==15986==    by 0x49A75B5: meta_backend_native_update_screen_size (meta-backend-native.c:520)
==15986==    by 0x48B01BB: meta_backend_sync_screen_size (meta-backend.c:224)
==15986==    by 0x48B09B7: meta_backend_real_post_init (meta-backend.c:501)

https://gitlab.gnome.org/GNOME/mutter/merge_requests/622
(cherry picked from commit 56ddaaa380)
2019-06-19 21:49:48 +02:00
Jonas Ådahl
cded69da61 renderer/native: Use g_set_error() instead of _cogl_set_error()
It's even a GError, so lets use the proper API.

https://gitlab.gnome.org/GNOME/mutter/merge_requests/622
(cherry picked from commit 1efb32d300)
2019-06-19 21:49:48 +02:00
Emil Velikov
a3a97621be renderer/native: add missing eglTerminate in EGLDevice error path
Currently the EGLDevice code gets the display and calls eglInitialize.
As a follow-up it checks the required EGL extensions - technically it
could check the EGL device extensions earlier.

In either case, eglTerminate is missing. Thus the connection to the
display was still bound.

This was highlighted with Mesa commit d6edccee8da ("egl: add
EGL_platform_device support") + amdgpu.

In that case, since the eglTerminate is missing, we end up reusing the
underlying amdgpu_device due to some caching in libdrm_amdgpu. The
latter in itself being a good solution since it allows buffer sharing
across primary and render node of the same device.

Note: we should really get this in branches all the way back to 3.30.

https://gitlab.gnome.org/GNOME/mutter/merge_requests/619

Fixes: 934184e23 ("MetaRendererNative: Add EGLDevice based rendering support")
Cc: Jonas Ådahl <jadahl@gmail.com>
Signed-off-by: Emil Velikov <emil.velikov@collabora.com>


(cherry picked from commit 9213574870)
2019-06-13 16:44:56 +00:00
Marco Trevisan (Treviño)
8b79c83ad5 display: Dispose Stack after Compositor and X11
As per commit 7718e67f, destroying the compositor causes destroying window
actors and this leads to stack changes, but at this point the stack was already
disposed and cleared.

So, clear the stack when any component that could use it (compositor, and X11)
has already been destroyed.
As consequence, also the stamps should be destroyed at later point.

Fixes https://gitlab.gnome.org/GNOME/mutter/issues/623
https://gitlab.gnome.org/GNOME/mutter/merge_requests/605

(cherry-picked from commit e94a0fced9)

https://gitlab.gnome.org/GNOME/mutter/merge_requests/607
2019-06-11 19:12:41 +02:00
Marco Trevisan (Treviño)
2ce4a20c8e headless-start-test: Ignore frame counter warnings
When running in slow or busy machines (hey CI!) or under valgrind headless
tests could fail because of a non fatal warning during initialization.

So define a fatal handler that ignores the frame counter warning.

https://gitlab.gnome.org/GNOME/mutter/merge_requests/581


(cherry picked from commit f869e4d54b)
2019-06-11 17:10:48 +00:00
Marco Trevisan (Treviño)
fb03e198e5 test-runner: Always wait after creating a window
Creating a window could take some time, causing false-positive failures when
running in slower or busy hardware like:

  window 1/2 isn't known to Mutter

So before we proceed in doing any operation on it, wait for the client.
Do this in the test runner instead of repeating the same in every .metatest.

https://gitlab.gnome.org/GNOME/mutter/merge_requests/581


(cherry picked from commit c1059df7f9)
2019-06-11 17:03:54 +00:00
Jonas Ådahl
07c9cd498d wayland/cursor-surface: Update sprite when attaching NULL
Attaching a NULL buffer should hide the cursor sprite. In these cases,
we we'll have neither surface nor buffer damage, so also update when we
just attached a NULL buffer.

Fixes: https://gitlab.gnome.org/GNOME/mutter/issues/630


(cherry picked from commit 36b361617d)
2019-06-07 16:23:57 +00:00
Jonas Ådahl
e716f9d143 wayland/surface: Clear texture when attaching NULL
When 252e64a0ea moved the texture
ownership to MetaWaylandSurface, it failed to handle the case when a
NULL-buffer is attached, leaving the texture reference in place. This
caused issues when the surface should have been hidden (e.g. attaching a
NULL buffer to a cursor surface for hiding the cursor sprite).

Related: https://gitlab.gnome.org/GNOME/mutter/issues/630


(cherry picked from commit 5eac1d696d)
2019-06-07 16:22:05 +00:00
Florian Müllner
13a1624c10 cogl-path: Undeprecate framebuffer functions
It looks like deprecating the functions with explicit framebuffer/pipeline
arguments made it to (cogl) master by mistake:

https://mail.gnome.org/archives/clutter-list/2016-April/msg00008.html

We now use one of them, so this is a good time to undeprecate the lot.

https://gitlab.gnome.org/GNOME/mutter/merge_requests/597
2019-05-28 18:35:04 +02:00
Florian Müllner
30d6e3abe2 clutter-text: Fix selection color drawing
Commit cabcad185 removed the call to cogl_set_source_color4ub() before
cogl_fill_path(), so instead of the previously assigned selection color,
the background is drawn with the last set source.

In order to honour the newly added framebuffer parameter and still apply
the correct color, switch from cogl_fill_path() to the (deprecated!)
cogl_framebuffer_fill_path() method.

https://gitlab.gnome.org/GNOME/mutter/issues/494
2019-05-28 18:34:34 +02:00
Marco Trevisan (Treviño)
18e44bb64c cogl/pipeline: Don't try to access to free'd pointer data
When free'ing a pipeline we destroy the BigState first and then the fragment and
vertex snippets lists using the big state pointer which is now invalid.
This causes a crash  when G_SLICE=always-malloc is set and using MALLOC_CHECK_.

So, invert the operations by free'ing the snippet lists first, and the big state
afterwards.

https://gitlab.gnome.org/GNOME/mutter/merge_requests/581


(cherry picked from commit 7e0d185120)
2019-05-27 22:39:51 +00:00
Marco Trevisan (Treviño)
15803b9558 wayland-seat: Use g_free to cleanup MetaWaylandSeat
MetaWaylandSeat is allocated using g_new0(), and thus we should use g_free() to
destroy it.

https://gitlab.gnome.org/GNOME/mutter/merge_requests/581


(cherry picked from commit 0405786573)
2019-05-27 22:37:45 +00:00
Marco Trevisan (Treviño)
3fdc651179 cursor-renderer-native: Free MetaCursorNativePrivate struct
Fix a small leak in native renderer.

https://gitlab.gnome.org/GNOME/mutter/merge_requests/581


(cherry picked from commit b016ff29f6)
2019-05-27 22:34:47 +00:00
Florian Müllner
189f71f5d1 Bump version to 3.32.2
Update NEWS.
2019-05-14 14:01:28 +00:00
Carlos Garnacho
0a3cddeecf core: Check environment variables before giving to GAppLaunchContext
Depending on the type of session, one or the other might be NULL, which
is not meant to be handled by these functions. Check for both DISPLAY
envvars before setting them on the GAppLaunchContext.

Closes: https://gitlab.gnome.org/GNOME/mutter/issues/586
2019-05-07 16:07:34 +02:00
Jonas Ådahl
ee92e4fe13 idle-monitor: Postpone dispatching of idle timeout if not ready
If we update the ready time while the source is already in the
to-dispatch list, changing the ready time doesn't have any effect, and
the source will still be dispatched. This could cause incorrect idle
watch firing causing the power management plugin in
gnome-settings-daemon to sometimes turn off monitors due to it believing
the user had been idle for some time, while in fact, they just logged
back in.

Fix this by not actually dispatching the idle timeout if the ready time
is in the future when actually dispatching.

https://gitlab.gnome.org/GNOME/mutter/merge_requests/543
2019-05-07 16:01:58 +02:00
Jonas Ådahl
6933ce0976 idle-monitor: Use G_SOURCE_CONTINUE instead of TRUE
Returning TRUE is confusing, as it doesn't carry any relevant meaning.
Use G_SOURCE_CONTINUE to make it clearer that the source is here to
stay.

https://gitlab.gnome.org/GNOME/mutter/merge_requests/543
2019-05-07 16:01:58 +02:00
Carlos Garnacho
f9d6627fe0 backends: Fallback to builtin panel for devices where all heuristics fail
This is 1) relatively likely as not all touchscreens are nice enough to
report a device size that will help us here and 2) Better than nothing if
everything fails anyway, as it will break on multi-monitor and non-default
monitor rotations.

Closes: https://gitlab.gnome.org/GNOME/mutter/issues/581
2019-05-03 23:48:29 +02:00
Marco Trevisan (Treviño)
668c44e66b compositor: Disconnect from stage signals on destruction
From this point there's not any need for the compositor to listen to signals
so we can disconnect from the stage ones we are connected to.

https://gitlab.gnome.org/GNOME/mutter/merge_requests/556


(cherry picked from commit 3ba79961fe)
2019-05-01 05:11:17 +00:00
Marco Trevisan (Treviño)
3495a43810 compositor: Destroy window actors list on destruction
When the compositor is destroyed we should cleanup the list of window actors we
created and destroy them.
Since all the actors are added to the window_group or top_window_group we can
just destroy these containers (together with the feedback_group), and simply
free the windows list.

This is particularly needed under X11 because before we destroy the display, we
might do some cleanups as detaching the surface pixmaps and freeing the damages
and if this happens at later point (for example when triggered by garbage
collector in gnome-shell), we might crash because the x11 dpy reference is
already gone.

Destroying the window actors instead, ensures we avoid any further call to X11
related functions and that we release the actors XServer resources.

Fixes https://gitlab.gnome.org/GNOME/mutter/issues/576


(cherry picked from commit 7718e67f5c)
2019-05-01 05:10:51 +00:00
Olivier Fourdan
9a795d3d0f input-settings: Use 0 initialized struct for kbd a11y
Make sure our keyboard accessibility settings structure is all zero
initialized, to avoid potential padding issues on some platform when
comparing settings.

Reported by Daniel van Vugt on IRC.

https://gitlab.gnome.org/GNOME/mutter/merge_requests/552


(cherry picked from commit eccf7b105c)
2019-04-30 10:57:45 +00:00
Olivier Fourdan
abc3fdcc65 clutter/x11: disable mousekeys with Numlock ON
GNOME documentation on accessibility features states that mousekeys
work only when NumLock is OFF:

  https://help.gnome.org/users/gnome-help/stable/mouse-mousekeys.html

Change the clutter/x11 implementation to match the documentation, i.e.
disable mousekeys when NumLock in ON so that switching NumLock ON
restores the numeric keypad behaviour.

Closes: https://gitlab.gnome.org/GNOME/mutter/issues/530
(cherry picked from commit 251fa024c4)
2019-04-19 16:18:18 +02:00
Olivier Fourdan
4705a31049 clutter/evdev: disable mousekeys with Numlock ON
The clutter/evdev implementation of mousekeys is designed after the
current implementation in X11, and works when the setting is enabled
regardless of the status of NumLock.

The GNOME documentation on accessibility features states however that
mousekeys work only when NumLock is OFF:

  https://help.gnome.org/users/gnome-help/stable/mouse-mousekeys.html

Change the clutter/evdev implementation to match the documentation, i.e.
disable mousekeys when NumLock in ON so that switching NumLock ON
restores the numeric keypad behaviour.

Closes: https://gitlab.gnome.org/GNOME/mutter/issues/530
(cherry picked from commit 471b61bd14)
2019-04-19 16:18:12 +02:00
50 changed files with 1456 additions and 190 deletions

11
NEWS
View File

@@ -1,3 +1,14 @@
3.32.2
======
* Disable mouse keys with Numlock on [Olivier; #530]
* Fix crash when restarting on X11 [Marco; #576]
* Fix mapping of touchscreens that don't report dimensions [Carlos; #581]
* Fix spurious idle signals that prevent session unblank [Jonas; !543]
* Misc. bug fixes and cleanups [Olivier, Marco, Carlos; !552, !557, #586]
Contributors:
Jonas Ådahl, Olivier Fourdan, Carlos Garnacho, Marco Trevisan (Treviño)
3.32.1
======
* Fix fallback app menu on wayland [Florian; #493]

View File

@@ -1975,6 +1975,7 @@ selection_paint (ClutterText *self,
else
{
/* Paint selection background first */
CoglPipeline *color_pipeline = cogl_pipeline_copy (default_color_pipeline);
PangoLayout *layout = clutter_text_get_layout (self);
CoglPath *selection_path = cogl_path_new ();
CoglColor cogl_color = { 0, };
@@ -1987,11 +1988,19 @@ selection_paint (ClutterText *self,
else
color = &priv->text_color;
cogl_color_init_from_4ub (&cogl_color,
color->red,
color->green,
color->blue,
paint_opacity * color->alpha / 255);
cogl_color_premultiply (&cogl_color);
cogl_pipeline_set_color (color_pipeline, &cogl_color);
clutter_text_foreach_selection_rectangle_prescaled (self,
add_selection_rectangle_to_path,
selection_path);
cogl_path_fill (selection_path);
cogl_framebuffer_fill_path (fb, color_pipeline, selection_path);
/* Paint selected text */
cogl_framebuffer_push_path_clip (fb, selection_path);

View File

@@ -855,6 +855,14 @@ emulate_pointer_motion (ClutterInputDeviceEvdev *device,
clutter_virtual_input_device_notify_relative_motion (device->mousekeys_virtual_device,
time_us, dx_motion, dy_motion);
}
static gboolean
is_numlock_active (ClutterInputDeviceEvdev *device)
{
ClutterSeatEvdev *seat = device->seat;
return xkb_state_mod_name_is_active (seat->xkb,
"Mod2",
XKB_STATE_MODS_LOCKED);
}
static void
enable_mousekeys (ClutterInputDeviceEvdev *device)
@@ -1013,6 +1021,10 @@ handle_mousekeys_press (ClutterEvent *event,
if (!(event->key.flags & CLUTTER_EVENT_FLAG_SYNTHETIC))
stop_mousekeys_move (device);
/* Do not handle mousekeys if NumLock is ON */
if (is_numlock_active (device))
return FALSE;
/* Button selection */
switch (event->key.keyval)
{
@@ -1084,6 +1096,10 @@ static gboolean
handle_mousekeys_release (ClutterEvent *event,
ClutterInputDeviceEvdev *device)
{
/* Do not handle mousekeys if NumLock is ON */
if (is_numlock_active (device))
return FALSE;
switch (event->key.keyval)
{
case XKB_KEY_KP_0:

View File

@@ -54,6 +54,7 @@
#include "clutter-main.h"
#include "clutter-private.h"
#include "clutter-settings-private.h"
#include "clutter-xkb-a11y-x11.h"
G_DEFINE_TYPE (ClutterBackendX11, clutter_backend_x11, CLUTTER_TYPE_BACKEND)
@@ -276,6 +277,20 @@ clutter_backend_x11_create_device_manager (ClutterBackendX11 *backend_x11)
_clutter_backend_add_event_translator (backend, translator);
}
static void
on_keymap_state_change (ClutterKeymapX11 *keymap_x11,
gpointer data)
{
ClutterDeviceManager *device_manager = CLUTTER_DEVICE_MANAGER (data);
ClutterKbdA11ySettings kbd_a11y_settings;
/* On keymaps state change, just reapply the current settings, it'll
* take care of enabling/disabling mousekeys based on NumLock state.
*/
clutter_device_manager_get_kbd_a11y_settings (device_manager, &kbd_a11y_settings);
clutter_device_manager_x11_apply_kbd_a11y_settings (device_manager, &kbd_a11y_settings);
}
static void
clutter_backend_x11_create_keymap (ClutterBackendX11 *backend_x11)
{
@@ -292,6 +307,11 @@ clutter_backend_x11_create_keymap (ClutterBackendX11 *backend_x11)
backend = CLUTTER_BACKEND (backend_x11);
translator = CLUTTER_EVENT_TRANSLATOR (backend_x11->keymap);
_clutter_backend_add_event_translator (backend, translator);
g_signal_connect (backend_x11->keymap,
"state-changed",
G_CALLBACK (on_keymap_state_change),
backend->device_manager);
}
}

View File

@@ -241,8 +241,13 @@ clutter_device_manager_x11_apply_kbd_a11y_settings (ClutterDeviceManager *devi
}
/* mouse keys */
if (set_xkb_ctrl (desc, kbd_a11y_settings->controls,
CLUTTER_A11Y_MOUSE_KEYS_ENABLED, XkbMouseKeysMask | XkbMouseKeysAccelMask))
if (clutter_keymap_get_num_lock_state (CLUTTER_KEYMAP (backend_x11->keymap)))
{
/* Disable mousekeys when NumLock is ON */
desc->ctrls->enabled_ctrls &= ~(XkbMouseKeysMask | XkbMouseKeysAccelMask);
}
else if (set_xkb_ctrl (desc, kbd_a11y_settings->controls,
CLUTTER_A11Y_MOUSE_KEYS_ENABLED, XkbMouseKeysMask | XkbMouseKeysAccelMask))
{
gint mk_max_speed;
gint mk_accel_time;

View File

@@ -460,9 +460,7 @@ cogl_path_fill (CoglPath *path);
* use while filling a path.</note>
*
* Stability: unstable
* Deprecated: 1.16: Use cogl_path_fill() instead
*/
COGL_DEPRECATED_FOR (cogl_path_fill)
void
cogl_framebuffer_fill_path (CoglFramebuffer *framebuffer,
CoglPipeline *pipeline,
@@ -492,9 +490,7 @@ cogl_path_stroke (CoglPath *path);
* regardless of the current transformation matrix.
*
* Stability: unstable
* Deprecated: 1.16: Use cogl_path_stroke() instead
*/
COGL_DEPRECATED_FOR (cogl_path_stroke)
void
cogl_framebuffer_stroke_path (CoglFramebuffer *framebuffer,
CoglPipeline *pipeline,
@@ -529,9 +525,7 @@ cogl_framebuffer_push_path_clip (CoglFramebuffer *framebuffer,
*
* Since: 1.8
* Stability: Unstable
* Deprecated: 1.16: Use cogl_framebuffer_push_path_clip() instead
*/
COGL_DEPRECATED_FOR (cogl_framebuffer_push_path_clip)
void
cogl_clip_push_from_path (CoglPath *path);

View File

@@ -1504,7 +1504,6 @@ cogl_framebuffer_push_path_clip (CoglFramebuffer *framebuffer,
COGL_FRAMEBUFFER_STATE_CLIP;
}
/* XXX: deprecated */
void
cogl_clip_push_from_path (CoglPath *path)
{
@@ -1575,7 +1574,6 @@ _cogl_path_build_stroke_attribute_buffer (CoglPath *path)
data->stroke_n_attributes = n_attributes;
}
/* XXX: deprecated */
void
cogl_framebuffer_fill_path (CoglFramebuffer *framebuffer,
CoglPipeline *pipeline,
@@ -1588,7 +1586,6 @@ cogl_framebuffer_fill_path (CoglFramebuffer *framebuffer,
_cogl_path_fill_nodes (path, framebuffer, pipeline, 0 /* flags */);
}
/* XXX: deprecated */
void
cogl_framebuffer_stroke_path (CoglFramebuffer *framebuffer,
CoglPipeline *pipeline,

View File

@@ -455,9 +455,6 @@ _cogl_pipeline_free (CoglPipeline *pipeline)
_cogl_bitmask_destroy (&uniforms_state->changed_mask);
}
if (pipeline->differences & COGL_PIPELINE_STATE_NEEDS_BIG_STATE)
g_slice_free (CoglPipelineBigState, pipeline->big_state);
if (pipeline->differences & COGL_PIPELINE_STATE_LAYERS)
{
g_list_foreach (pipeline->layer_differences,
@@ -471,6 +468,9 @@ _cogl_pipeline_free (CoglPipeline *pipeline)
if (pipeline->differences & COGL_PIPELINE_STATE_FRAGMENT_SNIPPETS)
_cogl_pipeline_snippet_list_free (&pipeline->big_state->fragment_snippets);
if (pipeline->differences & COGL_PIPELINE_STATE_NEEDS_BIG_STATE)
g_slice_free (CoglPipelineBigState, pipeline->big_state);
g_list_free (pipeline->deprecated_get_layers_list);
recursively_free_layer_caches (pipeline);

View File

@@ -1,6 +1,6 @@
project('mutter', 'c',
version: '3.32.1',
meson_version: '>= 0.48.0',
version: '3.32.2',
meson_version: '>= 0.50.0',
license: 'GPLv2+'
)

View File

@@ -13,9 +13,9 @@ msgid ""
msgstr ""
"Project-Id-Version: mutter master\n"
"Report-Msgid-Bugs-To: https://gitlab.gnome.org/GNOME/mutter/issues\n"
"POT-Creation-Date: 2019-02-04 17:52+0000\n"
"PO-Revision-Date: 2019-02-26 20:43+0100\n"
"Last-Translator: Tim Sabsch <tim@sabsch.com>\n"
"POT-Creation-Date: 2019-08-06 00:49+0000\n"
"PO-Revision-Date: 2019-09-05 23:42+0200\n"
"Last-Translator: Christian Kirbach <christian.kirbach@gmail.com>\n"
"Language-Team: Deutsch <gnome-de@gnome.org>\n"
"Language: de\n"
"MIME-Version: 1.0\n"
@@ -152,13 +152,15 @@ msgstr "Zur Arbeitsfläche 4 wechseln"
msgid "Switch to last workspace"
msgstr "Zur letzten Arbeitsfläche wechseln"
# Wechsel der Arbeitsfläche. Es wird nichts verschoben.
#: data/50-mutter-navigation.xml:123
msgid "Move to workspace above"
msgstr "Auf Arbeitsfläche darüber verschieben"
msgstr "Zur Arbeitsfläche darüber wechseln"
# Wechsel der Arbeitsfläche. Es wird nichts verschoben.
#: data/50-mutter-navigation.xml:126
msgid "Move to workspace below"
msgstr "Auf Arbeitsfläche darunter verschieben"
msgstr "Zur Arbeitsfläche darunter wechseln"
#: data/50-mutter-system.xml:6 data/50-mutter-wayland.xml:6
msgid "System"

View File

@@ -49,6 +49,14 @@
#define DEFAULT_XKB_RULES_FILE "evdev"
#define DEFAULT_XKB_MODEL "pc105+inet"
typedef enum
{
META_SEQUENCE_NONE,
META_SEQUENCE_ACCEPTED,
META_SEQUENCE_REJECTED,
META_SEQUENCE_PENDING_END
} MetaSequenceState;
struct _MetaBackendClass
{
GObjectClass parent_class;
@@ -71,6 +79,10 @@ struct _MetaBackendClass
int device_id,
uint32_t timestamp);
void (* finish_touch_sequence) (MetaBackend *backend,
ClutterEventSequence *sequence,
MetaSequenceState state);
void (* warp_pointer) (MetaBackend *backend,
int x,
int y);
@@ -135,6 +147,10 @@ gboolean meta_backend_ungrab_device (MetaBackend *backend,
int device_id,
uint32_t timestamp);
void meta_backend_finish_touch_sequence (MetaBackend *backend,
ClutterEventSequence *sequence,
MetaSequenceState state);
void meta_backend_warp_pointer (MetaBackend *backend,
int x,
int y);

View File

@@ -1007,6 +1007,20 @@ meta_backend_ungrab_device (MetaBackend *backend,
return META_BACKEND_GET_CLASS (backend)->ungrab_device (backend, device_id, timestamp);
}
/**
* meta_backend_finish_touch_sequence: (skip)
*/
void
meta_backend_finish_touch_sequence (MetaBackend *backend,
ClutterEventSequence *sequence,
MetaSequenceState state)
{
if (META_BACKEND_GET_CLASS (backend)->finish_touch_sequence)
META_BACKEND_GET_CLASS (backend)->finish_touch_sequence (backend,
sequence,
state);
}
/**
* meta_backend_warp_pointer: (skip)
*/

View File

@@ -207,6 +207,8 @@ update_inhibited (MetaIdleMonitor *monitor,
if (inhibited == monitor->inhibited)
return;
monitor->inhibited = inhibited;
g_hash_table_foreach (monitor->watches,
update_inhibited_watch,
monitor);
@@ -316,11 +318,18 @@ idle_monitor_dispatch_timeout (GSource *source,
gpointer user_data)
{
MetaIdleMonitorWatch *watch = (MetaIdleMonitorWatch *) user_data;
int64_t now;
int64_t ready_time;
now = g_source_get_time (source);
ready_time = g_source_get_ready_time (source);
if (ready_time > now)
return G_SOURCE_CONTINUE;
_meta_idle_monitor_watch_fire (watch);
g_source_set_ready_time (watch->timeout_source, -1);
return TRUE;
return G_SOURCE_CONTINUE;
}
static GSourceFuncs idle_monitor_source_funcs = {
@@ -508,9 +517,16 @@ meta_idle_monitor_reset_idletime (MetaIdleMonitor *monitor)
}
else
{
g_source_set_ready_time (watch->timeout_source,
monitor->last_event_time +
watch->timeout_msec * 1000);
if (monitor->inhibited)
{
g_source_set_ready_time (watch->timeout_source, -1);
}
else
{
g_source_set_ready_time (watch->timeout_source,
monitor->last_event_time +
watch->timeout_msec * 1000);
}
}
}

View File

@@ -381,7 +381,7 @@ guess_candidates (MetaInputMapper *mapper,
info->candidates[META_MATCH_SIZE] = matched_monitor;
}
if (input->builtin)
if (input->builtin || best == N_OUTPUT_MATCHES)
{
best = MIN (best, META_MATCH_IS_BUILTIN);
find_builtin_output (mapper, &info->candidates[META_MATCH_IS_BUILTIN]);

View File

@@ -1216,7 +1216,7 @@ load_keyboard_a11y_settings (MetaInputSettings *input_settings,
ClutterInputDevice *device)
{
MetaInputSettingsPrivate *priv = meta_input_settings_get_instance_private (input_settings);
ClutterKbdA11ySettings kbd_a11y_settings;
ClutterKbdA11ySettings kbd_a11y_settings = { 0 };
ClutterInputDevice *core_keyboard;
guint i;

View File

@@ -90,6 +90,12 @@ meta_renderer_create_view (MetaRenderer *renderer,
*/
void
meta_renderer_rebuild_views (MetaRenderer *renderer)
{
return META_RENDERER_GET_CLASS (renderer)->rebuild_views (renderer);
}
static void
meta_renderer_real_rebuild_views (MetaRenderer *renderer)
{
MetaRendererPrivate *priv = meta_renderer_get_instance_private (renderer);
MetaBackend *backend = meta_get_backend ();
@@ -181,4 +187,6 @@ meta_renderer_class_init (MetaRendererClass *klass)
GObjectClass *object_class = G_OBJECT_CLASS (klass);
object_class->finalize = meta_renderer_finalize;
klass->rebuild_views = meta_renderer_real_rebuild_views;
}

View File

@@ -43,6 +43,7 @@ struct _MetaRendererClass
CoglRenderer * (* create_cogl_renderer) (MetaRenderer *renderer);
MetaRendererView * (* create_view) (MetaRenderer *renderer,
MetaLogicalMonitor *logical_monitor);
void (* rebuild_views) (MetaRenderer *renderer);
};
CoglRenderer * meta_renderer_create_cogl_renderer (MetaRenderer *renderer);

View File

@@ -368,12 +368,8 @@ parse_transforms (MetaCrtc *crtc,
if (strcmp (prop->enums[i].name, "rotate-0") == 0)
transform = META_MONITOR_TRANSFORM_NORMAL;
else if (strcmp (prop->enums[i].name, "rotate-90") == 0)
transform = META_MONITOR_TRANSFORM_90;
else if (strcmp (prop->enums[i].name, "rotate-180") == 0)
transform = META_MONITOR_TRANSFORM_180;
else if (strcmp (prop->enums[i].name, "rotate-270") == 0)
transform = META_MONITOR_TRANSFORM_270;
if (transform != -1)
{

View File

@@ -823,6 +823,7 @@ static void
cursor_priv_free (MetaCursorNativePrivate *cursor_priv)
{
g_hash_table_destroy (cursor_priv->gpu_states);
g_free (cursor_priv);
}
static MetaCursorNativePrivate *

View File

@@ -258,6 +258,9 @@ cogl_pixel_format_from_drm_format (uint32_t drm_format,
CoglPixelFormat *out_format,
CoglTextureComponents *out_components);
static void
meta_renderer_native_queue_modes_reset (MetaRendererNative *renderer_native);
static MetaBackend *
backend_from_renderer_native (MetaRendererNative *renderer_native)
{
@@ -1277,7 +1280,7 @@ meta_renderer_native_egl_context_created (CoglDisplay *cogl_display,
cogl_display_egl->dummy_surface,
cogl_display_egl->egl_context))
{
_cogl_set_error (error, COGL_WINSYS_ERROR,
g_set_error (error, COGL_WINSYS_ERROR,
COGL_WINSYS_ERROR_CREATE_CONTEXT,
"Failed to make context current");
return FALSE;
@@ -3035,11 +3038,53 @@ meta_onscreen_native_allocate (CoglOnscreen *onscreen,
return TRUE;
}
static void
destroy_egl_surface (CoglOnscreen *onscreen)
{
CoglOnscreenEGL *onscreen_egl = onscreen->winsys;
if (onscreen_egl->egl_surface != EGL_NO_SURFACE)
{
MetaOnscreenNative *onscreen_native = onscreen_egl->platform;
MetaEgl *egl = meta_onscreen_native_get_egl (onscreen_native);
CoglFramebuffer *framebuffer = COGL_FRAMEBUFFER (onscreen);
CoglContext *cogl_context = framebuffer->context;
CoglRenderer *cogl_renderer = cogl_context->display->renderer;
CoglRendererEGL *cogl_renderer_egl = cogl_renderer->winsys;
meta_egl_destroy_surface (egl,
cogl_renderer_egl->edpy,
onscreen_egl->egl_surface,
NULL);
onscreen_egl->egl_surface = EGL_NO_SURFACE;
}
}
static void
discard_onscreen_page_flip_retries (MetaOnscreenNative *onscreen_native)
{
g_list_free_full (onscreen_native->pending_page_flip_retries,
(GDestroyNotify) retry_page_flip_data_free);
onscreen_native->pending_page_flip_retries = NULL;
if (onscreen_native->retry_page_flips_source)
{
MetaBackend *backend =
backend_from_renderer_native (onscreen_native->renderer_native);
meta_backend_thaw_updates (backend);
g_clear_pointer (&onscreen_native->retry_page_flips_source,
g_source_destroy);
}
}
static void
meta_renderer_native_release_onscreen (CoglOnscreen *onscreen)
{
CoglFramebuffer *framebuffer = COGL_FRAMEBUFFER (onscreen);
CoglContext *cogl_context = framebuffer->context;
CoglDisplay *cogl_display = cogl_context_get_display (cogl_context);
CoglDisplayEGL *cogl_display_egl = cogl_display->winsys;
CoglRenderer *cogl_renderer = cogl_context->display->renderer;
CoglRendererEGL *cogl_renderer_egl = cogl_renderer->winsys;
CoglOnscreenEGL *onscreen_egl = onscreen->winsys;
@@ -3052,28 +3097,18 @@ meta_renderer_native_release_onscreen (CoglOnscreen *onscreen)
onscreen_native = onscreen_egl->platform;
g_list_free_full (onscreen_native->pending_page_flip_retries,
(GDestroyNotify) retry_page_flip_data_free);
if (onscreen_native->retry_page_flips_source)
if (onscreen_egl->egl_surface != EGL_NO_SURFACE &&
(cogl_display_egl->current_draw_surface == onscreen_egl->egl_surface ||
cogl_display_egl->current_read_surface == onscreen_egl->egl_surface))
{
MetaBackend *backend =
backend_from_renderer_native (onscreen_native->renderer_native);
meta_backend_thaw_updates (backend);
g_clear_pointer (&onscreen_native->retry_page_flips_source,
g_source_destroy);
if (!_cogl_winsys_egl_make_current (cogl_display,
cogl_display_egl->dummy_surface,
cogl_display_egl->dummy_surface,
cogl_display_egl->egl_context))
g_warning ("Failed to clear current context");
}
if (onscreen_egl->egl_surface != EGL_NO_SURFACE)
{
MetaEgl *egl = meta_onscreen_native_get_egl (onscreen_native);
meta_egl_destroy_surface (egl,
cogl_renderer_egl->edpy,
onscreen_egl->egl_surface,
NULL);
onscreen_egl->egl_surface = EGL_NO_SURFACE;
}
discard_onscreen_page_flip_retries (onscreen_native);
renderer_gpu_data =
meta_renderer_native_get_gpu_data (onscreen_native->renderer_native,
@@ -3087,6 +3122,8 @@ meta_renderer_native_release_onscreen (CoglOnscreen *onscreen)
free_current_bo (onscreen);
destroy_egl_surface (onscreen);
if (onscreen_native->gbm.surface)
{
gbm_surface_destroy (onscreen_native->gbm.surface);
@@ -3097,6 +3134,9 @@ meta_renderer_native_release_onscreen (CoglOnscreen *onscreen)
case META_RENDERER_NATIVE_MODE_EGL_DEVICE:
release_dumb_fb (&onscreen_native->egl.dumb_fb,
onscreen_native->render_gpu);
destroy_egl_surface (onscreen);
if (onscreen_native->egl.stream != EGL_NO_STREAM_KHR)
{
MetaEgl *egl = meta_onscreen_native_get_egl (onscreen_native);
@@ -3157,7 +3197,7 @@ meta_renderer_native_supports_mirroring (MetaRendererNative *renderer_native)
return TRUE;
}
void
static void
meta_renderer_native_queue_modes_reset (MetaRendererNative *renderer_native)
{
MetaRenderer *renderer = META_RENDERER (renderer_native);
@@ -3523,6 +3563,37 @@ meta_renderer_native_create_view (MetaRenderer *renderer,
return view;
}
static void
discard_page_flip_retries (MetaRenderer *renderer)
{
GList *l;
for (l = meta_renderer_get_views (renderer); l; l = l->next)
{
ClutterStageView *stage_view = l->data;
CoglFramebuffer *framebuffer =
clutter_stage_view_get_onscreen (stage_view);
CoglOnscreen *onscreen = COGL_ONSCREEN (framebuffer);
CoglOnscreenEGL *onscreen_egl = onscreen->winsys;
MetaOnscreenNative *onscreen_native = onscreen_egl->platform;
discard_onscreen_page_flip_retries (onscreen_native);
}
}
static void
meta_renderer_native_rebuild_views (MetaRenderer *renderer)
{
MetaRendererClass *parent_renderer_class =
META_RENDERER_CLASS (meta_renderer_native_parent_class);
discard_page_flip_retries (renderer);
parent_renderer_class->rebuild_views (renderer);
meta_renderer_native_queue_modes_reset (META_RENDERER_NATIVE (renderer));
}
void
meta_renderer_native_finish_frame (MetaRendererNative *renderer_native)
{
@@ -4038,6 +4109,7 @@ create_renderer_gpu_data_egl_device (MetaRendererNative *renderer_native,
G_IO_ERROR_FAILED,
"Missing EGL extensions required for EGLDevice renderer: %s",
missing_extensions_str);
meta_egl_terminate (egl, egl_display, NULL);
g_free (missing_extensions_str);
g_free (missing_extensions);
return NULL;
@@ -4320,6 +4392,7 @@ meta_renderer_native_class_init (MetaRendererNativeClass *klass)
renderer_class->create_cogl_renderer = meta_renderer_native_create_cogl_renderer;
renderer_class->create_view = meta_renderer_native_create_view;
renderer_class->rebuild_views = meta_renderer_native_rebuild_views;
obj_props[PROP_MONITOR_MANAGER] =
g_param_spec_object ("monitor-manager",

View File

@@ -53,20 +53,6 @@ struct gbm_device * meta_gbm_device_from_gpu (MetaGpuKms *gpu_kms);
gboolean meta_renderer_native_supports_mirroring (MetaRendererNative *renderer_native);
void meta_renderer_native_queue_modes_reset (MetaRendererNative *renderer_native);
gboolean meta_renderer_native_set_legacy_view_size (MetaRendererNative *renderer_native,
MetaRendererView *view,
int width,
int height,
GError **error);
void meta_renderer_native_set_ignore_crtc (MetaRendererNative *renderer_native,
uint32_t id,
gboolean ignore);
MetaRendererView * meta_renderer_native_create_legacy_view (MetaRendererNative *renderer_native);
void meta_renderer_native_finish_frame (MetaRendererNative *renderer_native);
int64_t meta_renderer_native_get_frame_counter (MetaRendererNative *renderer_native);

View File

@@ -140,7 +140,6 @@ meta_stage_native_rebuild_views (MetaStageNative *stage_native)
ClutterActor *stage = meta_backend_get_stage (backend);
meta_renderer_rebuild_views (renderer);
meta_renderer_native_queue_modes_reset (META_RENDERER_NATIVE (renderer));
clutter_stage_update_resource_scales (CLUTTER_STAGE (stage));
ensure_frame_callbacks (stage_native);
}

View File

@@ -66,6 +66,10 @@ struct _MetaBackendX11Private
XSyncAlarm user_active_alarm;
XSyncCounter counter;
int current_touch_replay_sync_serial;
int pending_touch_replay_sync_serial;
Atom touch_replay_sync_atom;
int xinput_opcode;
int xinput_event_base;
int xinput_error_base;
@@ -174,6 +178,26 @@ meta_backend_x11_translate_device_event (MetaBackendX11 *x11,
backend_x11_class->translate_device_event (x11, device_event);
}
static void
maybe_translate_touch_replay_pointer_event (MetaBackendX11 *x11,
XIDeviceEvent *device_event)
{
MetaBackendX11Private *priv = meta_backend_x11_get_instance_private (x11);
if (!device_event->send_event &&
device_event->time != META_CURRENT_TIME &&
priv->current_touch_replay_sync_serial !=
priv->pending_touch_replay_sync_serial &&
XSERVER_TIME_IS_BEFORE (device_event->time, priv->latest_evtime))
{
/* Emulated pointer events received after XIRejectTouch is received
* on a passive touch grab will contain older timestamps, update those
* so we dont get InvalidTime at grabs.
*/
device_event->time = priv->latest_evtime;
}
}
static void
translate_device_event (MetaBackendX11 *x11,
XIDeviceEvent *device_event)
@@ -183,19 +207,7 @@ translate_device_event (MetaBackendX11 *x11,
meta_backend_x11_translate_device_event (x11, device_event);
if (!device_event->send_event && device_event->time != META_CURRENT_TIME)
{
if (XSERVER_TIME_IS_BEFORE (device_event->time, priv->latest_evtime))
{
/* Emulated pointer events received after XIRejectTouch is received
* on a passive touch grab will contain older timestamps, update those
* so we dont get InvalidTime at grabs.
*/
device_event->time = priv->latest_evtime;
}
/* Update the internal latest evtime, for any possible later use */
priv->latest_evtime = device_event->time;
}
priv->latest_evtime = device_event->time;
}
static void
@@ -260,6 +272,9 @@ maybe_spoof_event_as_stage_event (MetaBackendX11 *x11,
case XI_Motion:
case XI_ButtonPress:
case XI_ButtonRelease:
maybe_translate_touch_replay_pointer_event (x11,
(XIDeviceEvent *) input_event);
/* Intentional fall-through */
case XI_KeyPress:
case XI_KeyRelease:
case XI_TouchBegin:
@@ -327,6 +342,17 @@ handle_host_xevent (MetaBackend *backend,
MetaBackendX11Private *priv = meta_backend_x11_get_instance_private (x11);
gboolean bypass_clutter = FALSE;
switch (event->type)
{
case ClientMessage:
if (event->xclient.window == meta_backend_x11_get_xwindow (x11) &&
event->xclient.message_type == priv->touch_replay_sync_atom)
priv->current_touch_replay_sync_serial = event->xclient.data.l[0];
break;
default:
break;
}
XGetEventData (priv->xdisplay, &event->xcookie);
{
@@ -534,6 +560,10 @@ meta_backend_x11_post_init (MetaBackend *backend)
monitor_manager = meta_backend_get_monitor_manager (backend);
g_signal_connect (monitor_manager, "monitors-changed-internal",
G_CALLBACK (on_monitors_changed), backend);
priv->touch_replay_sync_atom = XInternAtom (priv->xdisplay,
"_MUTTER_TOUCH_SEQUENCE_SYNC",
False);
}
static ClutterBackend *
@@ -591,6 +621,43 @@ meta_backend_x11_ungrab_device (MetaBackend *backend,
return (ret == Success);
}
static void
meta_backend_x11_finish_touch_sequence (MetaBackend *backend,
ClutterEventSequence *sequence,
MetaSequenceState state)
{
MetaBackendX11 *x11 = META_BACKEND_X11 (backend);
MetaBackendX11Private *priv = meta_backend_x11_get_instance_private (x11);
int event_mode;
if (state == META_SEQUENCE_ACCEPTED)
event_mode = XIAcceptTouch;
else if (state == META_SEQUENCE_REJECTED)
event_mode = XIRejectTouch;
else
g_return_if_reached ();
XIAllowTouchEvents (priv->xdisplay,
META_VIRTUAL_CORE_POINTER_ID,
clutter_x11_event_sequence_get_touch_detail (sequence),
DefaultRootWindow (priv->xdisplay), event_mode);
if (state == META_SEQUENCE_REJECTED)
{
XClientMessageEvent ev;
ev = (XClientMessageEvent) {
.type = ClientMessage,
.window = meta_backend_x11_get_xwindow (x11),
.message_type = priv->touch_replay_sync_atom,
.format = 32,
.data.l[0] = ++priv->pending_touch_replay_sync_serial,
};
XSendEvent (priv->xdisplay, meta_backend_x11_get_xwindow (x11),
False, 0, (XEvent *) &ev);
}
}
static void
meta_backend_x11_warp_pointer (MetaBackend *backend,
int x,
@@ -776,6 +843,7 @@ meta_backend_x11_class_init (MetaBackendX11Class *klass)
backend_class->post_init = meta_backend_x11_post_init;
backend_class->grab_device = meta_backend_x11_grab_device;
backend_class->ungrab_device = meta_backend_x11_ungrab_device;
backend_class->finish_touch_sequence = meta_backend_x11_finish_touch_sequence;
backend_class->warp_pointer = meta_backend_x11_warp_pointer;
backend_class->get_current_logical_monitor = meta_backend_x11_get_current_logical_monitor;
backend_class->get_keymap = meta_backend_x11_get_keymap;

View File

@@ -18,6 +18,9 @@ struct _MetaCompositor
guint pre_paint_func_id;
guint post_paint_func_id;
guint stage_presented_id;
guint stage_after_paint_id;
gint64 server_time_query_time;
gint64 server_time_offset;

View File

@@ -92,6 +92,10 @@ on_presented (ClutterStage *stage,
ClutterFrameInfo *frame_info,
MetaCompositor *compositor);
static void
on_top_window_actor_destroyed (MetaWindowActor *window_actor,
MetaCompositor *compositor);
static gboolean
is_modal (MetaDisplay *display)
{
@@ -131,9 +135,31 @@ meta_switch_workspace_completed (MetaCompositor *compositor)
void
meta_compositor_destroy (MetaCompositor *compositor)
{
g_signal_handler_disconnect (compositor->stage,
compositor->stage_after_paint_id);
g_signal_handler_disconnect (compositor->stage,
compositor->stage_presented_id);
compositor->stage_after_paint_id = 0;
compositor->stage_presented_id = 0;
compositor->stage = NULL;
clutter_threads_remove_repaint_func (compositor->pre_paint_func_id);
clutter_threads_remove_repaint_func (compositor->post_paint_func_id);
if (compositor->top_window_actor)
{
g_signal_handlers_disconnect_by_func (compositor->top_window_actor,
on_top_window_actor_destroyed,
compositor);
compositor->top_window_actor = NULL;
}
g_clear_pointer (&compositor->window_group, clutter_actor_destroy);
g_clear_pointer (&compositor->top_window_group, clutter_actor_destroy);
g_clear_pointer (&compositor->feedback_group, clutter_actor_destroy);
g_clear_pointer (&compositor->windows, g_list_free);
if (compositor->have_x11_sync_object)
meta_sync_ring_destroy ();
}
@@ -503,9 +529,10 @@ meta_compositor_manage (MetaCompositor *compositor)
compositor->stage = meta_backend_get_stage (backend);
g_signal_connect (compositor->stage, "presented",
G_CALLBACK (on_presented),
compositor);
compositor->stage_presented_id =
g_signal_connect (compositor->stage, "presented",
G_CALLBACK (on_presented),
compositor);
/* We use connect_after() here to accomodate code in GNOME Shell that,
* when benchmarking drawing performance, connects to ::after-paint
@@ -515,8 +542,9 @@ meta_compositor_manage (MetaCompositor *compositor)
* connections to ::after-paint, connect() vs. connect_after() doesn't
* matter.
*/
g_signal_connect_after (CLUTTER_STAGE (compositor->stage), "after-paint",
G_CALLBACK (after_stage_paint), compositor);
compositor->stage_after_paint_id =
g_signal_connect_after (compositor->stage, "after-paint",
G_CALLBACK (after_stage_paint), compositor);
clutter_stage_set_sync_delay (CLUTTER_STAGE (compositor->stage), META_SYNC_DELAY);

View File

@@ -252,12 +252,11 @@ static void
set_file (MetaBackground *self,
GFile **filep,
MetaBackgroundImage **imagep,
GFile *file)
GFile *file,
gboolean force_reload)
{
if (!file_equal0 (*filep, file))
if (force_reload || !file_equal0 (*filep, file))
{
g_clear_object (filep);
if (*imagep)
{
g_signal_handlers_disconnect_by_func (*imagep,
@@ -267,11 +266,12 @@ set_file (MetaBackground *self,
*imagep = NULL;
}
g_set_object (filep, file);
if (file)
{
MetaBackgroundImageCache *cache = meta_background_image_cache_get_default ();
*filep = g_object_ref (file);
*imagep = meta_background_image_cache_load (cache, file);
g_signal_connect (*imagep, "loaded",
G_CALLBACK (on_background_loaded), self);
@@ -279,6 +279,32 @@ set_file (MetaBackground *self,
}
}
static void
on_gl_video_memory_purged (MetaBackground *self)
{
MetaBackgroundImageCache *cache = meta_background_image_cache_get_default ();
/* The GPU memory that just got invalidated is the texture inside
* self->background_image1,2 and/or its mipmaps. However, to save memory the
* original pixbuf isn't kept in RAM so we can't do a simple re-upload. The
* only copy of the image was the one in texture memory that got invalidated.
* So we need to do a full reload from disk.
*/
if (self->file1)
{
meta_background_image_cache_purge (cache, self->file1);
set_file (self, &self->file1, &self->background_image1, self->file1, TRUE);
}
if (self->file2)
{
meta_background_image_cache_purge (cache, self->file2);
set_file (self, &self->file2, &self->background_image2, self->file2, TRUE);
}
mark_changed (self);
}
static void
meta_background_dispose (GObject *object)
{
@@ -287,8 +313,8 @@ meta_background_dispose (GObject *object)
free_color_texture (self);
free_wallpaper_texture (self);
set_file (self, &self->file1, &self->background_image1, NULL);
set_file (self, &self->file2, &self->background_image2, NULL);
set_file (self, &self->file1, &self->background_image1, NULL, FALSE);
set_file (self, &self->file2, &self->background_image2, NULL, FALSE);
set_display (self, NULL);
@@ -312,7 +338,7 @@ meta_background_constructed (GObject *object)
G_OBJECT_CLASS (meta_background_parent_class)->constructed (object);
g_signal_connect_object (self->display, "gl-video-memory-purged",
G_CALLBACK (mark_changed), object, G_CONNECT_SWAPPED);
G_CALLBACK (on_gl_video_memory_purged), object, G_CONNECT_SWAPPED);
g_signal_connect_object (monitor_manager, "monitors-changed",
G_CALLBACK (on_monitors_changed), self,
@@ -937,8 +963,8 @@ meta_background_set_blend (MetaBackground *self,
g_return_if_fail (META_IS_BACKGROUND (self));
g_return_if_fail (blend_factor >= 0.0 && blend_factor <= 1.0);
set_file (self, &self->file1, &self->background_image1, file1);
set_file (self, &self->file2, &self->background_image2, file2);
set_file (self, &self->file1, &self->background_image1, file1, FALSE);
set_file (self, &self->file2, &self->background_image2, file2, FALSE);
self->blend_factor = blend_factor;
self->style = style;

View File

@@ -32,6 +32,7 @@
#include "cogl/winsys/cogl-texture-pixmap-x11.h"
#include "compositor/meta-cullable.h"
#include "compositor/meta-shaped-texture-private.h"
#include "compositor/meta-window-actor-private.h"
#include "core/window-private.h"
#include "meta/meta-x11-errors.h"
#include "x11/meta-x11-display-private.h"
@@ -71,11 +72,13 @@ static void
free_damage (MetaSurfaceActorX11 *self)
{
MetaDisplay *display = self->display;
Display *xdisplay = meta_x11_display_get_xdisplay (display->x11_display);
Display *xdisplay;
if (self->damage == None)
return;
xdisplay = meta_x11_display_get_xdisplay (display->x11_display);
meta_x11_error_trap_push (display->x11_display);
XDamageDestroy (xdisplay, self->damage);
self->damage = None;
@@ -86,12 +89,14 @@ static void
detach_pixmap (MetaSurfaceActorX11 *self)
{
MetaDisplay *display = self->display;
Display *xdisplay = meta_x11_display_get_xdisplay (display->x11_display);
MetaShapedTexture *stex = meta_surface_actor_get_texture (META_SURFACE_ACTOR (self));
Display *xdisplay;
if (self->pixmap == None)
return;
xdisplay = meta_x11_display_get_xdisplay (display->x11_display);
/* Get rid of all references to the pixmap before freeing it; it's unclear whether
* you are supposed to be able to free a GLXPixmap after freeing the underlying
* pixmap, but it certainly doesn't work with current DRI/Mesa
@@ -343,13 +348,19 @@ meta_surface_actor_x11_is_unredirected (MetaSurfaceActor *actor)
return self->unredirected;
}
static void
release_x11_resources (MetaSurfaceActorX11 *self)
{
detach_pixmap (self);
free_damage (self);
}
static void
meta_surface_actor_x11_dispose (GObject *object)
{
MetaSurfaceActorX11 *self = META_SURFACE_ACTOR_X11 (object);
detach_pixmap (self);
free_damage (self);
release_x11_resources (self);
G_OBJECT_CLASS (meta_surface_actor_x11_parent_class)->dispose (object);
}
@@ -403,8 +414,7 @@ window_decorated_notify (MetaWindow *window,
{
MetaSurfaceActorX11 *self = META_SURFACE_ACTOR_X11 (user_data);
detach_pixmap (self);
free_damage (self);
release_x11_resources (self);
create_damage (self);
}
@@ -441,6 +451,10 @@ meta_surface_actor_x11_new (MetaWindow *window)
g_signal_connect_object (self->window, "notify::decorated",
G_CALLBACK (window_decorated_notify), self, 0);
g_signal_connect_object (meta_window_actor_from_window (window), "destroy",
G_CALLBACK (release_x11_resources), self,
G_CONNECT_SWAPPED);
self->unredirected = FALSE;
sync_unredirected (self);

View File

@@ -52,8 +52,6 @@ typedef enum
typedef struct _MetaWindowActorPrivate
{
ClutterActor parent;
MetaWindow *window;
MetaCompositor *compositor;
@@ -417,7 +415,7 @@ meta_window_actor_update_surface (MetaWindowActor *self)
else
surface_actor = NULL;
set_surface (self, surface_actor);
META_WINDOW_ACTOR_GET_CLASS (self)->set_surface_actor (self, surface_actor);
}
static void
@@ -430,6 +428,9 @@ meta_window_actor_constructed (GObject *object)
priv->compositor = window->display->compositor;
/* Hang our compositor window state off the MetaWindow for fast retrieval */
meta_window_set_compositor_private (window, object);
meta_window_actor_update_surface (self);
meta_window_actor_update_opacity (self);
@@ -446,9 +447,6 @@ meta_window_actor_constructed (GObject *object)
priv->first_frame_state = DRAWING_FIRST_FRAME;
meta_window_actor_sync_actor_geometry (self, priv->window->placed);
/* Hang our compositor window state off the MetaWindow for fast retrieval */
meta_window_set_compositor_private (window, object);
}
static void
@@ -476,7 +474,7 @@ meta_window_actor_dispose (GObject *object)
g_clear_object (&priv->window);
set_surface (self, NULL);
META_WINDOW_ACTOR_GET_CLASS (self)->set_surface_actor (self, NULL);
G_OBJECT_CLASS (meta_window_actor_parent_class)->dispose (object);
}

View File

@@ -42,6 +42,7 @@
#include <X11/extensions/Xdamage.h>
#include <X11/extensions/Xfixes.h>
#include "backends/meta-backend-private.h"
#include "backends/meta-cursor-sprite-xcursor.h"
#include "backends/meta-cursor-tracker-private.h"
#include "backends/meta-idle-monitor-dbus.h"
@@ -598,27 +599,23 @@ gesture_tracker_state_changed (MetaGestureTracker *tracker,
MetaSequenceState state,
MetaDisplay *display)
{
if (meta_is_wayland_compositor ())
switch (state)
{
if (state == META_SEQUENCE_ACCEPTED)
meta_display_cancel_touch (display);
}
else
{
MetaBackendX11 *backend = META_BACKEND_X11 (meta_get_backend ());
int event_mode;
case META_SEQUENCE_NONE:
case META_SEQUENCE_PENDING_END:
return;
case META_SEQUENCE_ACCEPTED:
meta_display_cancel_touch (display);
if (state == META_SEQUENCE_ACCEPTED)
event_mode = XIAcceptTouch;
else if (state == META_SEQUENCE_REJECTED)
event_mode = XIRejectTouch;
else
return;
/* Intentional fall-through */
case META_SEQUENCE_REJECTED:
{
MetaBackend *backend;
XIAllowTouchEvents (meta_backend_x11_get_xdisplay (backend),
META_VIRTUAL_CORE_POINTER_ID,
clutter_x11_event_sequence_get_touch_detail (sequence),
DefaultRootWindow (display->x11_display->xdisplay), event_mode);
backend = meta_get_backend ();
meta_backend_finish_touch_sequence (backend, sequence, state);
break;
}
}
}
@@ -920,10 +917,6 @@ meta_display_close (MetaDisplay *display,
g_clear_object (&display->gesture_tracker);
g_clear_pointer (&display->stack, meta_stack_free);
g_clear_pointer (&display->stack_tracker,
meta_stack_tracker_free);
if (display->focus_timeout_id)
g_source_remove (display->focus_timeout_id);
display->focus_timeout_id = 0;
@@ -940,12 +933,6 @@ meta_display_close (MetaDisplay *display,
/* Stop caring about events */
meta_display_free_events (display);
/* Must be after all calls to meta_window_unmanage() since they
* unregister windows
*/
g_hash_table_destroy (display->wayland_windows);
g_hash_table_destroy (display->stamps);
if (display->compositor)
meta_compositor_destroy (display->compositor);
@@ -956,6 +943,16 @@ meta_display_close (MetaDisplay *display,
g_clear_object (&display->x11_display);
}
/* Must be after all calls to meta_window_unmanage() since they
* unregister windows
*/
g_hash_table_destroy (display->wayland_windows);
g_hash_table_destroy (display->stamps);
g_clear_pointer (&display->stack, meta_stack_free);
g_clear_pointer (&display->stack_tracker,
meta_stack_tracker_free);
meta_display_shutdown_keys (display);
g_clear_object (&display->bell);

View File

@@ -26,6 +26,7 @@
#include <glib-object.h>
#include "backends/meta-backend-private.h"
#include "clutter/clutter.h"
#include "meta/window.h"
@@ -39,14 +40,6 @@
typedef struct _MetaGestureTracker MetaGestureTracker;
typedef struct _MetaGestureTrackerClass MetaGestureTrackerClass;
typedef enum
{
META_SEQUENCE_NONE,
META_SEQUENCE_ACCEPTED,
META_SEQUENCE_REJECTED,
META_SEQUENCE_PENDING_END
} MetaSequenceState;
struct _MetaGestureTracker
{
GObject parent_instance;

View File

@@ -110,13 +110,24 @@ static void
meta_launch_context_constructed (GObject *object)
{
MetaLaunchContext *context = META_LAUNCH_CONTEXT (object);
const char *x11_display, *wayland_display;
G_OBJECT_CLASS (meta_launch_context_parent_class)->constructed (object);
g_app_launch_context_setenv (G_APP_LAUNCH_CONTEXT (context),
"DISPLAY", getenv ("DISPLAY"));
g_app_launch_context_setenv (G_APP_LAUNCH_CONTEXT (context),
"WAYLAND_DISPLAY", getenv ("WAYLAND_DISPLAY"));
x11_display = getenv ("DISPLAY");
wayland_display = getenv ("WAYLAND_DISPLAY");
if (x11_display)
{
g_app_launch_context_setenv (G_APP_LAUNCH_CONTEXT (context),
"DISPLAY", x11_display);
}
if (wayland_display)
{
g_app_launch_context_setenv (G_APP_LAUNCH_CONTEXT (context),
"WAYLAND_DISPLAY", wayland_display);
}
}
static gchar *

View File

@@ -1194,6 +1194,27 @@ window_contains_point (MetaWindow *window,
return POINT_IN_RECT (root_x, root_y, rect);
}
static gboolean
window_can_get_default_focus (MetaWindow *window)
{
if (window->unmaps_pending > 0)
return FALSE;
if (window->unmanaging)
return FALSE;
if (!meta_window_is_focusable (window))
return FALSE;
if (!meta_window_should_be_showing (window))
return FALSE;
if (window->type == META_WINDOW_DOCK)
return FALSE;
return TRUE;
}
static MetaWindow*
get_default_focus_window (MetaStack *stack,
MetaWorkspace *workspace,
@@ -1221,24 +1242,12 @@ get_default_focus_window (MetaStack *stack,
if (window == not_this_one)
continue;
if (window->unmaps_pending > 0)
continue;
if (window->unmanaging)
continue;
if (!meta_window_is_focusable (window))
continue;
if (!meta_window_should_be_showing (window))
if (!window_can_get_default_focus (window))
continue;
if (must_be_at_point && !window_contains_point (window, root_x, root_y))
continue;
if (window->type == META_WINDOW_DOCK)
continue;
return window;
}
@@ -1293,6 +1302,26 @@ meta_stack_list_windows (MetaStack *stack,
return workspace_windows;
}
GList *
meta_stack_get_default_focus_candidates (MetaStack *stack,
MetaWorkspace *workspace)
{
GList *windows = meta_stack_list_windows (stack, workspace);
GList *l;
for (l = windows; l;)
{
GList *next = l->next;
if (!window_can_get_default_focus (l->data))
windows = g_list_delete_link (windows, l);
l = next;
}
return windows;
}
int
meta_stack_windows_cmp (MetaStack *stack,
MetaWindow *window_a,

View File

@@ -337,6 +337,21 @@ MetaWindow* meta_stack_get_default_focus_window_at_point (MetaStack *stack,
int root_x,
int root_y);
/**
* meta_stack_get_default_focus_candidates:
* @stack: The stack to examine.
* @workspace: If not %NULL, only windows on this workspace will be
* returned; otherwise all windows in the stack will be
* returned.
*
* Returns all the focus candidate windows in the stack, in order.
*
* Returns: (transfer container) (element-type Meta.Window):
* A #GList of #MetaWindow, in stacking order, honouring layers.
*/
GList * meta_stack_get_default_focus_candidates (MetaStack *stack,
MetaWorkspace *workspace);
/**
* meta_stack_list_windows:
* @stack: The stack to examine.

View File

@@ -3683,6 +3683,13 @@ meta_window_activate_full (MetaWindow *window,
{
MetaWorkspaceManager *workspace_manager = window->display->workspace_manager;
gboolean allow_workspace_switch;
if (window->unmanaging)
{
g_warning ("Trying to activate unmanaged window '%s'", window->desc);
return;
}
meta_topic (META_DEBUG_FOCUS,
"_NET_ACTIVE_WINDOW message sent for %s at time %u "
"by client type %u.\n",
@@ -8562,6 +8569,8 @@ meta_window_shortcuts_inhibited (MetaWindow *window,
gboolean
meta_window_is_focusable (MetaWindow *window)
{
g_return_val_if_fail (!window->unmanaging, FALSE);
return META_WINDOW_GET_CLASS (window)->is_focusable (window);
}

View File

@@ -85,6 +85,12 @@ typedef struct _MetaWorkspaceLogicalMonitorData
MetaRectangle logical_monitor_work_area;
} MetaWorkspaceLogicalMonitorData;
typedef struct _MetaWorkspaceFocusableAncestorData
{
MetaWorkspace *workspace;
MetaWindow *out_window;
} MetaWorkspaceFocusableAncestorData;
static MetaWorkspaceLogicalMonitorData *
meta_workspace_get_logical_monitor_data (MetaWorkspace *workspace,
MetaLogicalMonitor *logical_monitor)
@@ -1322,13 +1328,20 @@ meta_workspace_focus_default_window (MetaWorkspace *workspace,
}
static gboolean
record_ancestor (MetaWindow *window,
void *data)
find_focusable_ancestor (MetaWindow *window,
gpointer user_data)
{
MetaWindow **result = data;
MetaWorkspaceFocusableAncestorData *data = user_data;
*result = window;
return FALSE; /* quit with the first ancestor we find */
if (!window->unmanaging && meta_window_is_focusable (window) &&
meta_window_located_on_workspace (window, data->workspace) &&
meta_window_showing_on_its_workspace (window))
{
data->out_window = window;
return FALSE;
}
return TRUE;
}
/* Focus ancestor of not_this_one if there is one */
@@ -1350,11 +1363,15 @@ focus_ancestor_or_top_window (MetaWorkspace *workspace,
if (not_this_one)
{
MetaWindow *ancestor;
ancestor = NULL;
meta_window_foreach_ancestor (not_this_one, record_ancestor, &ancestor);
if (ancestor != NULL &&
meta_window_located_on_workspace (ancestor, workspace) &&
meta_window_showing_on_its_workspace (ancestor))
MetaWorkspaceFocusableAncestorData data;
data = (MetaWorkspaceFocusableAncestorData) {
.workspace = workspace,
};
meta_window_foreach_ancestor (not_this_one, find_focusable_ancestor, &data);
ancestor = data.out_window;
if (ancestor)
{
meta_topic (META_DEBUG_FOCUS,
"Focusing %s, ancestor of %s\n",

View File

@@ -32,6 +32,7 @@
#include "wayland/meta-wayland.h"
#define ALL_TRANSFORMS ((1 << (META_MONITOR_TRANSFORM_FLIPPED_270 + 1)) - 1)
#define FRAME_WARNING "Frame has assigned frame counter but no frame drawn time"
static gboolean
run_tests (gpointer data)
@@ -40,6 +41,8 @@ run_tests (gpointer data)
MetaSettings *settings = meta_backend_get_settings (backend);
gboolean ret;
g_test_log_set_fatal_handler (NULL, NULL);
meta_settings_override_experimental_features (settings);
meta_settings_enable_experimental_feature (
@@ -53,6 +56,20 @@ run_tests (gpointer data)
return FALSE;
}
static gboolean
ignore_frame_counter_warning (const gchar *log_domain,
GLogLevelFlags log_level,
const gchar *message,
gpointer user_data)
{
if ((log_level & G_LOG_LEVEL_WARNING) &&
g_strcmp0 (log_domain, "mutter") == 0 &&
g_str_has_suffix (message, FRAME_WARNING))
return FALSE;
return TRUE;
}
static void
meta_test_headless_start (void)
{
@@ -193,6 +210,8 @@ main (int argc, char *argv[])
meta_init ();
meta_register_with_session ();
g_test_log_set_fatal_handler (ignore_frame_counter_warning, NULL);
g_idle_add (run_tests, NULL);
return meta_run ();

View File

@@ -38,6 +38,7 @@ test_client = executable('mutter-test-client',
dependencies: [
gtk3_dep,
gio_unix_dep,
x11_dep,
xext_dep,
],
install: have_installed_tests,
@@ -104,6 +105,13 @@ headless_start_test = executable('mutter-headless-start-test',
stacking_tests = files([
'stacking/basic-x11.metatest',
'stacking/basic-wayland.metatest',
'stacking/closed-transient-no-input-no-take-focus-parent.metatest',
'stacking/closed-transient-no-input-no-take-focus-parents.metatest',
'stacking/closed-transient-no-input-parent.metatest',
'stacking/closed-transient-no-input-parent-delayed-focus-default-cancelled.metatest',
'stacking/closed-transient-no-input-parents.metatest',
'stacking/closed-transient-no-input-parents-queued-default-focus-destroyed.metatest',
'stacking/closed-transient-only-take-focus-parents.metatest',
'stacking/minimized.metatest',
'stacking/mixed-windows.metatest',
'stacking/set-parent.metatest',

View File

@@ -0,0 +1,23 @@
new_client 1 x11
create 1/1
show 1/1
create 1/2 csd
set_parent 1/2 1
can_take_focus 1/2 false
accept_focus 1/2 false
show 1/2
create 1/3 csd
set_parent 1/3 2
show 1/3
wait
assert_focused 1/3
assert_stacking 1/1 1/2 1/3
destroy 1/3
wait
assert_focused 1/1
assert_stacking 1/1 1/2

View File

@@ -0,0 +1,30 @@
new_client 2 x11
create 2/1
show 2/1
wait
new_client 1 x11
create 1/1
accept_focus 1/1 false
can_take_focus 1/1 false
show 1/1
create 1/2 csd
set_parent 1/2 1
can_take_focus 1/2 false
accept_focus 1/2 false
show 1/2
create 1/3 csd
set_parent 1/3 2
show 1/3
wait
assert_focused 1/3
assert_stacking 2/1 1/1 1/2 1/3
destroy 1/3
wait
assert_stacking 1/1 1/2 2/1
assert_focused 2/1

View File

@@ -0,0 +1,36 @@
new_client 2 x11
create 2/1
show 2/1
new_client 1 x11
create 1/1
show 1/1
create 1/2 csd
set_parent 1/2 1
accept_focus 1/2 false
show 1/2
create 1/3 csd
set_parent 1/3 2
show 1/3
wait
assert_focused 1/3
assert_stacking 2/1 1/1 1/2 1/3
destroy 1/3
dispatch
assert_focused none
assert_stacking 2/1 1/1 1/2
activate 2/1
wait
assert_focused 2/1
assert_stacking 1/1 1/2 2/1
sleep 250
assert_focused 2/1
assert_stacking 1/1 1/2 2/1

View File

@@ -0,0 +1,30 @@
new_client 2 x11
create 2/1
show 2/1
new_client 1 x11
create 1/1
show 1/1
create 1/2 csd
set_parent 1/2 1
accept_focus 1/2 false
show 1/2
create 1/3 csd
set_parent 1/3 2
show 1/3
wait
assert_focused 1/3
assert_stacking 2/1 1/1 1/2 1/3
destroy 1/3
dispatch
assert_focused none
assert_stacking 2/1 1/1 1/2
sleep 150
assert_focused 1/1
assert_stacking 2/1 1/1 1/2

View File

@@ -0,0 +1,43 @@
new_client 0 x11
create 0/1
show 0/1
new_client 1 x11
create 1/1
show 1/1
create 1/2 csd
set_parent 1/2 1
accept_focus 1/2 false
show 1/2
create 1/3 csd
set_parent 1/3 2
accept_focus 1/3 false
show 1/3
create 1/4 csd
set_parent 1/4 3
accept_focus 1/4 false
show 1/4
create 1/5 csd
set_parent 1/5 3
show 1/5
wait
assert_focused 1/5
assert_stacking 0/1 1/1 1/2 1/3 1/4 1/5
destroy 1/5
dispatch
assert_focused none
assert_stacking 0/1 1/1 1/2 1/3 1/4
destroy 1/2
dispatch
sleep 450
assert_focused 1/1
assert_stacking 0/1 1/1 1/3 1/4

View File

@@ -0,0 +1,46 @@
new_client 0 x11
create 0/1
show 0/1
new_client 1 x11
create 1/1
show 1/1
create 1/2 csd
set_parent 1/2 1
accept_focus 1/2 false
show 1/2
create 1/3 csd
set_parent 1/3 2
accept_focus 1/3 false
show 1/3
create 1/4 csd
set_parent 1/4 3
accept_focus 1/4 false
show 1/4
create 1/5 csd
set_parent 1/5 3
show 1/5
wait
assert_focused 1/5
assert_stacking 0/1 1/1 1/2 1/3 1/4 1/5
destroy 1/5
dispatch
assert_focused none
assert_stacking 0/1 1/1 1/2 1/3 1/4
sleep 600
assert_focused 1/1
assert_stacking 0/1 1/1 1/2 1/3 1/4
destroy 1/3
wait
assert_focused 1/1
assert_stacking 0/1 1/1 1/2 1/4

View File

@@ -0,0 +1,34 @@
new_client 0 x11
create 0/1
show 0/1
new_client 1 x11
create 1/1
accept_focus 1/1 false
can_take_focus 1/1 true
accept_take_focus 1/1 true
show 1/1
create 1/2 csd
set_parent 1/2 1
accept_focus 1/2 false
can_take_focus 1/2 true
accept_take_focus 1/2 true
show 1/2
create 1/3
set_parent 1/3 2
show 1/3
assert_focused 1/3
assert_stacking 0/1 1/1 1/2 1/3
destroy 1/3
wait
assert_focused 1/2
assert_stacking 0/1 1/1 1/2
sleep 150
assert_focused 1/2
assert_stacking 0/1 1/1 1/2

View File

@@ -31,6 +31,11 @@
const char *client_id = "0";
static gboolean wayland;
GHashTable *windows;
GQuark event_source_quark;
GQuark event_handlers_quark;
GQuark can_take_focus_quark;
typedef void (*XEventHandler) (GtkWidget *window, XEvent *event);
static void read_next_line (GDataInputStream *in);
@@ -57,6 +62,186 @@ lookup_window (const char *window_id)
return window;
}
typedef struct {
GSource base;
GSource **self_ref;
GPollFD event_poll_fd;
Display *xdisplay;
} XClientEventSource;
static gboolean
x_event_source_prepare (GSource *source,
int *timeout)
{
XClientEventSource *x_source = (XClientEventSource *) source;
*timeout = -1;
return XPending (x_source->xdisplay);
}
static gboolean
x_event_source_check (GSource *source)
{
XClientEventSource *x_source = (XClientEventSource *) source;
return XPending (x_source->xdisplay);
}
static gboolean
x_event_source_dispatch (GSource *source,
GSourceFunc callback,
gpointer user_data)
{
XClientEventSource *x_source = (XClientEventSource *) source;
while (XPending (x_source->xdisplay))
{
GHashTableIter iter;
XEvent event;
gpointer value;
XNextEvent (x_source->xdisplay, &event);
g_hash_table_iter_init (&iter, windows);
while (g_hash_table_iter_next (&iter, NULL, &value))
{
GList *l;
GtkWidget *window = value;
GList *handlers =
g_object_get_qdata (G_OBJECT (window), event_handlers_quark);
for (l = handlers; l; l = l->next)
{
XEventHandler handler = l->data;
handler (window, &event);
}
}
}
return TRUE;
}
static void
x_event_source_finalize (GSource *source)
{
XClientEventSource *x_source = (XClientEventSource *) source;
*x_source->self_ref = NULL;
}
static GSourceFuncs x_event_funcs = {
x_event_source_prepare,
x_event_source_check,
x_event_source_dispatch,
x_event_source_finalize,
};
static GSource*
ensure_xsource_handler (GdkDisplay *gdkdisplay)
{
static GSource *source = NULL;
Display *xdisplay = GDK_DISPLAY_XDISPLAY (gdkdisplay);
XClientEventSource *x_source;
if (source)
return g_source_ref (source);
source = g_source_new (&x_event_funcs, sizeof (XClientEventSource));
x_source = (XClientEventSource *) source;
x_source->self_ref = &source;
x_source->xdisplay = xdisplay;
x_source->event_poll_fd.fd = ConnectionNumber (xdisplay);
x_source->event_poll_fd.events = G_IO_IN;
g_source_add_poll (source, &x_source->event_poll_fd);
g_source_set_priority (source, GDK_PRIORITY_EVENTS - 1);
g_source_set_can_recurse (source, TRUE);
g_source_attach (source, NULL);
return source;
}
static gboolean
window_has_x11_event_handler (GtkWidget *window,
XEventHandler handler)
{
GList *handlers =
g_object_get_qdata (G_OBJECT (window), event_handlers_quark);
g_return_val_if_fail (handler, FALSE);
g_return_val_if_fail (!wayland, FALSE);
return g_list_find (handlers, handler) != NULL;
}
static void
unref_and_maybe_destroy_gsource (GSource *source)
{
g_source_unref (source);
if (source->ref_count == 1)
g_source_destroy (source);
}
static void
window_add_x11_event_handler (GtkWidget *window,
XEventHandler handler)
{
GSource *source;
GList *handlers =
g_object_get_qdata (G_OBJECT (window), event_handlers_quark);
g_return_if_fail (!window_has_x11_event_handler (window, handler));
source = ensure_xsource_handler (gtk_widget_get_display (window));
g_object_set_qdata_full (G_OBJECT (window), event_source_quark, source,
(GDestroyNotify) unref_and_maybe_destroy_gsource);
handlers = g_list_append (handlers, handler);
g_object_set_qdata (G_OBJECT (window), event_handlers_quark, handlers);
}
static void
window_remove_x11_event_handler (GtkWidget *window,
XEventHandler handler)
{
GList *handlers =
g_object_get_qdata (G_OBJECT (window), event_handlers_quark);
g_return_if_fail (window_has_x11_event_handler (window, handler));
g_object_set_qdata (G_OBJECT (window), event_source_quark, NULL);
handlers = g_list_remove (handlers, handler);
g_object_set_qdata (G_OBJECT (window), event_handlers_quark, handlers);
}
static void
handle_take_focus (GtkWidget *window,
XEvent *xevent)
{
GdkWindow *gdkwindow = gtk_widget_get_window (window);
GdkDisplay *display = gtk_widget_get_display (window);
Atom wm_protocols =
gdk_x11_get_xatom_by_name_for_display (display, "WM_PROTOCOLS");
Atom wm_take_focus =
gdk_x11_get_xatom_by_name_for_display (display, "WM_TAKE_FOCUS");
if (xevent->xany.type != ClientMessage ||
xevent->xany.window != GDK_WINDOW_XID (gdkwindow))
return;
if (xevent->xclient.message_type == wm_protocols &&
xevent->xclient.data.l[0] == wm_take_focus)
{
XSetInputFocus (xevent->xany.display,
GDK_WINDOW_XID (gdkwindow),
RevertToParent,
xevent->xclient.data.l[1]);
}
}
static void
process_line (const char *line)
{
@@ -125,6 +310,9 @@ process_line (const char *line)
gtk_window_set_title (GTK_WINDOW (window), title);
g_free (title);
g_object_set_qdata (G_OBJECT (window), can_take_focus_quark,
GUINT_TO_POINTER (TRUE));
gtk_widget_realize (window);
if (!wayland)
@@ -196,6 +384,130 @@ process_line (const char *line)
NULL))
g_print ("Fail to export handle for window id %s", argv[2]);
}
else if (strcmp (argv[0], "accept_focus") == 0)
{
if (argc != 3)
{
g_print ("usage: %s <window-id> [true|false]", argv[0]);
goto out;
}
GtkWidget *window = lookup_window (argv[1]);
if (!window)
{
g_print ("unknown window %s", argv[1]);
goto out;
}
if (!wayland &&
window_has_x11_event_handler (window, handle_take_focus))
{
g_print ("Impossible to use %s for windows accepting take focus",
argv[1]);
goto out;
}
gboolean enabled = g_ascii_strcasecmp (argv[2], "true") == 0;
gtk_window_set_accept_focus (GTK_WINDOW (window), enabled);
}
else if (strcmp (argv[0], "can_take_focus") == 0)
{
if (argc != 3)
{
g_print ("usage: %s <window-id> [true|false]", argv[0]);
goto out;
}
GtkWidget *window = lookup_window (argv[1]);
if (!window)
{
g_print ("unknown window %s", argv[1]);
goto out;
}
if (wayland)
{
g_print ("%s not supported under wayland", argv[0]);
goto out;
}
if (window_has_x11_event_handler (window, handle_take_focus))
{
g_print ("Impossible to change %s for windows accepting take focus",
argv[1]);
goto out;
}
GdkDisplay *display = gdk_display_get_default ();
GdkWindow *gdkwindow = gtk_widget_get_window (window);
Display *xdisplay = gdk_x11_display_get_xdisplay (display);
Window xwindow = GDK_WINDOW_XID (gdkwindow);
Atom wm_take_focus = gdk_x11_get_xatom_by_name_for_display (display, "WM_TAKE_FOCUS");
gboolean add = g_ascii_strcasecmp(argv[2], "true") == 0;
Atom *protocols = NULL;
Atom *new_protocols;
int n_protocols = 0;
int i, n = 0;
gdk_display_sync (display);
XGetWMProtocols (xdisplay, xwindow, &protocols, &n_protocols);
new_protocols = g_new0 (Atom, n_protocols + (add ? 1 : 0));
for (i = 0; i < n_protocols; ++i)
{
if (protocols[i] != wm_take_focus)
new_protocols[n++] = protocols[i];
}
if (add)
new_protocols[n++] = wm_take_focus;
XSetWMProtocols (xdisplay, xwindow, new_protocols, n);
g_object_set_qdata (G_OBJECT (window), can_take_focus_quark,
GUINT_TO_POINTER (add));
XFree (new_protocols);
XFree (protocols);
}
else if (strcmp (argv[0], "accept_take_focus") == 0)
{
if (argc != 3)
{
g_print ("usage: %s <window-id> [true|false]", argv[0]);
goto out;
}
GtkWidget *window = lookup_window (argv[1]);
if (!window)
{
g_print ("unknown window %s", argv[1]);
goto out;
}
if (wayland)
{
g_print ("%s not supported under wayland", argv[0]);
goto out;
}
if (gtk_window_get_accept_focus (GTK_WINDOW (window)))
{
g_print ("%s not supported for input windows", argv[0]);
goto out;
}
if (!g_object_get_qdata (G_OBJECT (window), can_take_focus_quark))
{
g_print ("%s not supported for windows with no WM_TAKE_FOCUS set",
argv[0]);
goto out;
}
if (g_ascii_strcasecmp (argv[2], "true") == 0)
window_add_x11_event_handler (window, handle_take_focus);
else
window_remove_x11_event_handler (window, handle_take_focus);
}
else if (strcmp (argv[0], "show") == 0)
{
if (argc != 2)
@@ -460,6 +772,9 @@ main(int argc, char **argv)
windows = g_hash_table_new_full (g_str_hash, g_str_equal,
g_free, NULL);
event_source_quark = g_quark_from_static_string ("event-source");
event_handlers_quark = g_quark_from_static_string ("event-handlers");
can_take_focus_quark = g_quark_from_static_string ("can-take-focus");
GInputStream *raw_in = g_unix_input_stream_new (0, FALSE);
GDataInputStream *in = g_data_input_stream_new (raw_in);

View File

@@ -77,7 +77,7 @@ test_case_new (void)
}
static gboolean
test_case_before_redraw (gpointer data)
test_case_loop_quit (gpointer data)
{
TestCase *test = data;
@@ -86,6 +86,24 @@ test_case_before_redraw (gpointer data)
return FALSE;
}
static gboolean
test_case_dispatch (TestCase *test,
GError **error)
{
/* Wait until we've done any outstanding queued up work.
* Though we add this as BEFORE_REDRAW, the iteration that runs the
* BEFORE_REDRAW idles will proceed on and do the redraw, so we're
* waiting until after *all* frame processing.
*/
meta_later_add (META_LATER_BEFORE_REDRAW,
test_case_loop_quit,
test,
NULL);
g_main_loop_run (test->loop);
return TRUE;
}
static gboolean
test_case_wait (TestCase *test,
GError **error)
@@ -102,16 +120,8 @@ test_case_wait (TestCase *test,
if (!test_client_wait (value, error))
return FALSE;
/* Then wait until we've done any outstanding queued up work.
* Though we add this as BEFORE_REDRAW, the iteration that runs the
* BEFORE_REDRAW idles will proceed on and do the redraw, so we're
* waiting until after *all* frame processing.
*/
meta_later_add (META_LATER_BEFORE_REDRAW,
test_case_before_redraw,
test,
NULL);
g_main_loop_run (test->loop);
/* Then wait until we've done any outstanding queued up work. */
test_case_dispatch (test, error);
/* Then set an XSync counter ourselves and and wait until
* we receive the resulting event - this makes sure that we've
@@ -121,6 +131,17 @@ test_case_wait (TestCase *test,
return TRUE;
}
static gboolean
test_case_sleep (TestCase *test,
guint32 interval,
GError **error)
{
g_timeout_add_full (G_PRIORITY_LOW, interval, test_case_loop_quit, test, NULL);
g_main_loop_run (test->loop);
return TRUE;
}
#define BAD_COMMAND(...) \
G_STMT_START { \
g_set_error (error, \
@@ -237,6 +258,37 @@ test_case_assert_stacking (TestCase *test,
return *error == NULL;
}
static gboolean
test_case_assert_focused (TestCase *test,
const char *expected_window,
GError **error)
{
MetaDisplay *display = meta_get_display ();
if (!display->focus_window)
{
if (g_strcmp0 (expected_window, "none") != 0)
{
g_set_error (error, TEST_RUNNER_ERROR, TEST_RUNNER_ERROR_ASSERTION_FAILED,
"focus: expected='%s', actual='none'", expected_window);
}
}
else
{
const char *focused = display->focus_window->title;
if (g_str_has_prefix (focused, "test/"))
focused += 5;
if (g_strcmp0 (focused, expected_window) != 0)
g_set_error (error, TEST_RUNNER_ERROR, TEST_RUNNER_ERROR_ASSERTION_FAILED,
"focus: expected='%s', actual='%s'",
expected_window, focused);
}
return *error == NULL;
}
static gboolean
test_case_check_xserver_stacking (TestCase *test,
GError **error)
@@ -385,6 +437,9 @@ test_case_do (TestCase *test,
argc == 3 ? argv[2] : NULL,
NULL))
return FALSE;
if (!test_client_wait (client, error))
return FALSE;
}
else if (strcmp (argv[0], "set_parent") == 0 ||
strcmp (argv[0], "set_parent_exported") == 0)
@@ -398,6 +453,63 @@ test_case_do (TestCase *test,
if (!test_case_parse_window_id (test, argv[1], &client, &window_id, error))
return FALSE;
if (!test_client_do (client, error,
argv[0], window_id,
argv[2],
NULL))
return FALSE;
}
else if (strcmp (argv[0], "accept_focus") == 0)
{
if (argc != 3 ||
(g_ascii_strcasecmp (argv[2], "true") != 0 &&
g_ascii_strcasecmp (argv[2], "false") != 0))
BAD_COMMAND("usage: %s <client-id>/<window-id> [true|false]",
argv[0]);
TestClient *client;
const char *window_id;
if (!test_case_parse_window_id (test, argv[1], &client, &window_id, error))
return FALSE;
if (!test_client_do (client, error,
argv[0], window_id,
argv[2],
NULL))
return FALSE;
}
else if (strcmp (argv[0], "can_take_focus") == 0)
{
if (argc != 3 ||
(g_ascii_strcasecmp (argv[2], "true") != 0 &&
g_ascii_strcasecmp (argv[2], "false") != 0))
BAD_COMMAND("usage: %s <client-id>/<window-id> [true|false]",
argv[0]);
TestClient *client;
const char *window_id;
if (!test_case_parse_window_id (test, argv[1], &client, &window_id, error))
return FALSE;
if (!test_client_do (client, error,
argv[0], window_id,
argv[2],
NULL))
return FALSE;
}
else if (strcmp (argv[0], "accept_take_focus") == 0)
{
if (argc != 3 ||
(g_ascii_strcasecmp (argv[2], "true") != 0 &&
g_ascii_strcasecmp (argv[2], "false") != 0))
BAD_COMMAND("usage: %s <client-id>/<window-id> [true|false]",
argv[0]);
TestClient *client;
const char *window_id;
if (!test_case_parse_window_id (test, argv[1], &client, &window_id, error))
return FALSE;
if (!test_client_do (client, error,
argv[0], window_id,
argv[2],
@@ -477,6 +589,28 @@ test_case_do (TestCase *test,
if (!test_case_wait (test, error))
return FALSE;
}
else if (strcmp (argv[0], "dispatch") == 0)
{
if (argc != 1)
BAD_COMMAND("usage: %s", argv[0]);
if (!test_case_dispatch (test, error))
return FALSE;
}
else if (strcmp (argv[0], "sleep") == 0)
{
guint64 interval;
if (argc != 2)
BAD_COMMAND("usage: %s <milliseconds>", argv[0]);
if (!g_ascii_string_to_unsigned (argv[1], 10, 0, G_MAXUINT32,
&interval, error))
return FALSE;
if (!test_case_sleep (test, (guint32) interval, error))
return FALSE;
}
else if (strcmp (argv[0], "assert_stacking") == 0)
{
if (!test_case_assert_stacking (test, argv + 1, argc - 1, error))
@@ -485,6 +619,11 @@ test_case_do (TestCase *test,
if (!test_case_check_xserver_stacking (test, error))
return FALSE;
}
else if (strcmp (argv[0], "assert_focused") == 0)
{
if (!test_case_assert_focused (test, argv[1], error))
return FALSE;
}
else
{
BAD_COMMAND("Unknown command %s", argv[0]);

View File

@@ -170,8 +170,9 @@ meta_wayland_cursor_surface_commit (MetaWaylandSurfaceRole *surface_role,
wl_list_init (&pending->frame_callback_list);
if (pending->newly_attached &&
(!cairo_region_is_empty (pending->surface_damage) ||
!cairo_region_is_empty (pending->buffer_damage)))
((!cairo_region_is_empty (pending->surface_damage) ||
!cairo_region_is_empty (pending->buffer_damage)) ||
!priv->buffer))
update_cursor_sprite_texture (META_WAYLAND_CURSOR_SURFACE (surface_role));
}

View File

@@ -266,7 +266,7 @@ meta_wayland_seat_free (MetaWaylandSeat *seat)
meta_wayland_gtk_text_input_destroy (seat->gtk_text_input);
meta_wayland_text_input_destroy (seat->text_input);
g_slice_free (MetaWaylandSeat, seat);
g_free (seat);
}
static gboolean

View File

@@ -737,6 +737,10 @@ meta_wayland_surface_apply_pending_state (MetaWaylandSurface *surface,
g_clear_pointer (&snippet, cogl_object_unref);
}
}
else
{
cogl_clear_object (&surface->texture);
}
/* If the newly attached buffer is going to be accessed directly without
* making a copy, such as an EGL buffer, mark it as in-use don't release

View File

@@ -50,6 +50,8 @@
#include "x11/window-props.h"
#include "x11/xprops.h"
#define TAKE_FOCUS_FALLBACK_DELAY_MS 150
enum _MetaGtkEdgeConstraints
{
META_GTK_EDGE_CONSTRAINT_TOP_TILED = 1 << 0,
@@ -64,6 +66,11 @@ enum _MetaGtkEdgeConstraints
G_DEFINE_TYPE_WITH_PRIVATE (MetaWindowX11, meta_window_x11, META_TYPE_WINDOW)
static void
meta_window_x11_maybe_focus_delayed (MetaWindow *window,
GQueue *other_focus_candidates,
guint32 timestamp);
static void
meta_window_x11_init (MetaWindowX11 *window_x11)
{
@@ -776,6 +783,158 @@ request_take_focus (MetaWindow *window,
send_icccm_message (window, display->x11_display->atom_WM_TAKE_FOCUS, timestamp);
}
typedef struct
{
MetaWindow *window;
GQueue *pending_focus_candidates;
guint32 timestamp;
guint timeout_id;
gulong unmanaged_id;
gulong focused_changed_id;
} MetaWindowX11DelayedFocusData;
static void
disconnect_pending_focus_window_signals (MetaWindow *window,
GQueue *focus_candidates)
{
g_signal_handlers_disconnect_by_func (window, g_queue_remove,
focus_candidates);
}
static void
meta_window_x11_delayed_focus_data_free (MetaWindowX11DelayedFocusData *data)
{
g_signal_handler_disconnect (data->window, data->unmanaged_id);
g_signal_handler_disconnect (data->window->display, data->focused_changed_id);
if (data->pending_focus_candidates)
{
g_queue_foreach (data->pending_focus_candidates,
(GFunc) disconnect_pending_focus_window_signals,
data->pending_focus_candidates);
g_queue_free (data->pending_focus_candidates);
}
g_clear_handle_id (&data->timeout_id, g_source_remove);
g_free (data);
}
static void
focus_candidates_maybe_take_and_focus_next (GQueue **focus_candidates_ptr,
guint32 timestamp)
{
MetaWindow *focus_window;
GQueue *focus_candidates;
g_assert (*focus_candidates_ptr);
if (g_queue_is_empty (*focus_candidates_ptr))
return;
focus_candidates = g_steal_pointer (focus_candidates_ptr);
focus_window = g_queue_pop_head (focus_candidates);
disconnect_pending_focus_window_signals (focus_window, focus_candidates);
meta_window_x11_maybe_focus_delayed (focus_window, focus_candidates, timestamp);
}
static gboolean
focus_window_delayed_timeout (gpointer user_data)
{
MetaWindowX11DelayedFocusData *data = user_data;
MetaWindow *window = data->window;
guint32 timestamp = data->timestamp;
focus_candidates_maybe_take_and_focus_next (&data->pending_focus_candidates,
timestamp);
data->timeout_id = 0;
meta_window_x11_delayed_focus_data_free (data);
meta_window_focus (window, timestamp);
return G_SOURCE_REMOVE;
}
static void
meta_window_x11_maybe_focus_delayed (MetaWindow *window,
GQueue *other_focus_candidates,
guint32 timestamp)
{
MetaWindowX11DelayedFocusData *data;
data = g_new0 (MetaWindowX11DelayedFocusData, 1);
data->window = window;
data->timestamp = timestamp;
data->pending_focus_candidates = other_focus_candidates;
meta_topic (META_DEBUG_FOCUS,
"Requesting delayed focus to %s\n", window->desc);
data->unmanaged_id =
g_signal_connect_swapped (window, "unmanaged",
G_CALLBACK (meta_window_x11_delayed_focus_data_free),
data);
data->focused_changed_id =
g_signal_connect_swapped (window->display, "notify::focus-window",
G_CALLBACK (meta_window_x11_delayed_focus_data_free),
data);
data->timeout_id = g_timeout_add (TAKE_FOCUS_FALLBACK_DELAY_MS,
focus_window_delayed_timeout, data);
}
static void
maybe_focus_default_window (MetaDisplay *display,
MetaWindow *not_this_one,
guint32 timestamp)
{
MetaWorkspace *workspace;
MetaStack *stack = display->stack;
g_autoptr (GList) focusable_windows = NULL;
g_autoptr (GQueue) focus_candidates = NULL;
GList *l;
if (not_this_one && not_this_one->workspace)
workspace = not_this_one->workspace;
else
workspace = display->workspace_manager->active_workspace;
/* Go through all the focusable windows and try to focus them
* in order, waiting for a delay. The first one that replies to
* the request (in case of take focus windows) changing the display
* focused window, will stop the chained requests.
*/
focusable_windows =
meta_stack_get_default_focus_candidates (stack, workspace);
focus_candidates = g_queue_new ();
for (l = g_list_last (focusable_windows); l; l = l->prev)
{
MetaWindow *focus_window = l->data;
if (focus_window == not_this_one)
continue;
g_queue_push_tail (focus_candidates, focus_window);
g_signal_connect_swapped (focus_window, "unmanaged",
G_CALLBACK (g_queue_remove),
focus_candidates);
if (!META_IS_WINDOW_X11 (focus_window))
break;
if (focus_window->input)
break;
if (focus_window->shaded && focus_window->frame)
break;
}
focus_candidates_maybe_take_and_focus_next (&focus_candidates, timestamp);
}
static void
meta_window_x11_focus (MetaWindow *window,
guint32 timestamp)
@@ -827,13 +986,20 @@ meta_window_x11_focus (MetaWindow *window,
* Normally, we want to just leave the focus undisturbed until
* the window responds to WM_TAKE_FOCUS, but if we're unmanaging
* the current focus window we *need* to move the focus away, so
* we focus the no_focus_window now (and set
* display->focus_window to that) before sending WM_TAKE_FOCUS.
* we focus the no focus window before sending WM_TAKE_FOCUS,
* and eventually the default focus windwo excluding this one,
* if meanwhile we don't get any focus request.
*/
if (window->display->focus_window != NULL &&
window->display->focus_window->unmanaging)
meta_x11_display_focus_the_no_focus_window (window->display->x11_display,
timestamp);
{
MetaX11Display *x11_display = window->display->x11_display;
meta_x11_display_focus_the_no_focus_window (x11_display,
timestamp);
maybe_focus_default_window (window->display, window,
timestamp);
}
}
request_take_focus (window, timestamp);